From 0a228c5670a7326f56ec9f71e1fe7228f3f93156 Mon Sep 17 00:00:00 2001 From: MasatoMakino Date: Sun, 4 Aug 2024 07:40:05 +0000 Subject: [PATCH] deploy: 8347e1a0735eb9a48b5a655f9156e335a2769a58 --- api/classes/BloomEffectComposer.html | 6 +++--- api/classes/ChromaticAberrationShaderPass.html | 4 ++-- api/classes/ColorFilterShaderPass.html | 4 ++-- api/classes/DisplacementMapShaderPass.html | 6 +++--- api/classes/FXAAShaderPass.html | 4 ++-- api/classes/MixShaderPass.html | 4 ++-- api/classes/MonotoneShaderPass.html | 4 ++-- api/classes/PeripheralLightShaderPass.html | 4 ++-- api/classes/PostProcessRenderer.html | 12 ++++++------ api/classes/PostProcessShader.html | 4 ++-- api/classes/PostProcessShaderPass.html | 4 ++-- api/classes/RenderPassOption.html | 4 ++-- api/interfaces/IPostProcessShader.html | 4 ++-- demo/vendor.js | 2 +- 14 files changed, 33 insertions(+), 33 deletions(-) diff --git a/api/classes/BloomEffectComposer.html b/api/classes/BloomEffectComposer.html index 7b4324f..da87ea7 100644 --- a/api/classes/BloomEffectComposer.html +++ b/api/classes/BloomEffectComposer.html @@ -1,6 +1,6 @@ BloomEffectComposer | threejs-postprocess

切り替え可能なUnrealBloomPassを内包したEffectComposer. BloomEffectComposer.BLOOMレイヤーに含まれるオブジェクトのみをBloomさせる.

-

Hierarchy

  • PostProcessEffectComposer
    • BloomEffectComposer

Constructors

Hierarchy

  • PostProcessEffectComposer
    • BloomEffectComposer

Constructors

Properties

Constructors

Properties

bloomPass: UnrealBloomPass
clock: Clock
copyPass: ShaderPass
enabled: boolean = true
onAfterRender?: ((delta?: number) => void)
onBeforeRender?: ((delta?: number) => void)
passes: Pass[]
readBuffer: WebGLRenderTarget<Texture>
renderTarget1: WebGLRenderTarget<Texture>
renderTarget2: WebGLRenderTarget<Texture>
renderToScreen: boolean
renderer: WebGLRenderer
switcher: MaterialSwitcher
writeBuffer: WebGLRenderTarget<Texture>
BLOOM: number = 30
ENTIRE: number = 0

Accessors

Methods

  • Parameters

    • pass: Pass

    Returns void

  • Returns void

  • Parameters

    • pass: Pass
    • index: number

    Returns void

  • Parameters

    • passIndex: number

    Returns boolean

  • Parameters

    • pass: Pass

    Returns void

  • Parameters

    • OptionaldeltaTime: number

    Returns void

  • Parameters

    • OptionalrenderTarget: WebGLRenderTarget<Texture>

    Returns void

  • Parameters

    • pixelRatio: number

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

  • Returns void

+

Constructors

Properties

bloomPass: UnrealBloomPass
clock: Clock
copyPass: ShaderPass
enabled: boolean = true
onAfterRender?: ((delta?: number) => void)
onBeforeRender?: ((delta?: number) => void)
passes: Pass[]
readBuffer: WebGLRenderTarget<Texture>
renderTarget1: WebGLRenderTarget<Texture>
renderTarget2: WebGLRenderTarget<Texture>
renderToScreen: boolean
renderer: WebGLRenderer
switcher: MaterialSwitcher
writeBuffer: WebGLRenderTarget<Texture>
BLOOM: number = 30
ENTIRE: number = 0

Accessors

Methods

  • Parameters

    • pass: Pass

    Returns void

  • Returns void

  • Parameters

    • pass: Pass
    • index: number

    Returns void

  • Parameters

    • passIndex: number

    Returns boolean

  • Parameters

    • pass: Pass

    Returns void

  • Parameters

    • OptionaldeltaTime: number

    Returns void

  • Parameters

    • OptionalrenderTarget: WebGLRenderTarget<Texture>

    Returns void

  • Parameters

    • pixelRatio: number

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

  • Returns void

diff --git a/api/classes/ChromaticAberrationShaderPass.html b/api/classes/ChromaticAberrationShaderPass.html index 4547dda..311a85e 100644 --- a/api/classes/ChromaticAberrationShaderPass.html +++ b/api/classes/ChromaticAberrationShaderPass.html @@ -1,7 +1,7 @@ ChromaticAberrationShaderPass | threejs-postprocess

Class ChromaticAberrationShaderPass

ポストプロセス用のShaderPass。 EffectComposerにPassとして追加することで、任意のポストエフェクトを実現する。

コンストラクターでPostProcessShaderを受け取り、そのシェーダーのuniformを操作する。

-

Hierarchy (view full)

Constructors

Hierarchy (view full)

Constructors

Properties

clear enabled fsQuad @@ -18,4 +18,4 @@

Methods

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

+

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

diff --git a/api/classes/ColorFilterShaderPass.html b/api/classes/ColorFilterShaderPass.html index e85ace7..edeab8a 100644 --- a/api/classes/ColorFilterShaderPass.html +++ b/api/classes/ColorFilterShaderPass.html @@ -2,7 +2,7 @@

例 ) multiS = 0.0, addB = 1.0にすると白に飽和する。 multiB = 0.0, もしくはaddB = -1.0 でブラックアウト。

-

Hierarchy (view full)

Constructors

Hierarchy (view full)

Constructors

Properties

clear enabled fsQuad @@ -21,4 +21,4 @@

Methods

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

+

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

diff --git a/api/classes/DisplacementMapShaderPass.html b/api/classes/DisplacementMapShaderPass.html index 0282326..eaaded8 100644 --- a/api/classes/DisplacementMapShaderPass.html +++ b/api/classes/DisplacementMapShaderPass.html @@ -1,5 +1,5 @@ DisplacementMapShaderPass | threejs-postprocess

Class DisplacementMapShaderPass

DisplacementMapによって画面を歪ませるShaderPass

-

Hierarchy (view full)

Constructors

Hierarchy (view full)

Constructors

Properties

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
mapSizeH: number
mapSizeW: number
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
rendererSizeH: number
rendererSizeW: number
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • DisplacementMapを読み込む。 +

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
mapSizeH: number
mapSizeW: number
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
rendererSizeH: number
rendererSizeW: number
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

+

Parameters

Returns void

diff --git a/api/classes/FXAAShaderPass.html b/api/classes/FXAAShaderPass.html index 6b892d4..0fa0754 100644 --- a/api/classes/FXAAShaderPass.html +++ b/api/classes/FXAAShaderPass.html @@ -1,5 +1,5 @@ FXAAShaderPass | threejs-postprocess

FXAAShaderを組み込み済みのShaderPass

-

Hierarchy (view full)

Constructors

Hierarchy (view full)

Constructors

Properties

clear enabled fsQuad @@ -14,4 +14,4 @@ render setSize

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

+

Returns FXAAShaderPass

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

diff --git a/api/classes/MixShaderPass.html b/api/classes/MixShaderPass.html index 60ea64d..e58f75e 100644 --- a/api/classes/MixShaderPass.html +++ b/api/classes/MixShaderPass.html @@ -1,5 +1,5 @@ MixShaderPass | threejs-postprocess

他のエフェクトコンポーザーの描画結果を受け取り、自身のレンダリング結果に乗算するShaderPass

-

Hierarchy (view full)

Constructors

Hierarchy (view full)

Constructors

Properties

clear enabled fsQuad @@ -14,4 +14,4 @@

Methods

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

+

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

diff --git a/api/classes/MonotoneShaderPass.html b/api/classes/MonotoneShaderPass.html index 6e5e7a8..0948e67 100644 --- a/api/classes/MonotoneShaderPass.html +++ b/api/classes/MonotoneShaderPass.html @@ -1,4 +1,4 @@ -MonotoneShaderPass | threejs-postprocess

Hierarchy (view full)

Constructors

constructor +MonotoneShaderPass | threejs-postprocess

Hierarchy (view full)

Constructors

Properties

clear enabled fsQuad @@ -14,4 +14,4 @@

Methods

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

+

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

diff --git a/api/classes/PeripheralLightShaderPass.html b/api/classes/PeripheralLightShaderPass.html index 83d2293..24552f3 100644 --- a/api/classes/PeripheralLightShaderPass.html +++ b/api/classes/PeripheralLightShaderPass.html @@ -1,5 +1,5 @@ PeripheralLightShaderPass | threejs-postprocess

Class PeripheralLightShaderPass

周辺光量の減光を表現するフィルタ。

-

Hierarchy (view full)

Constructors

Hierarchy (view full)

Constructors

Properties

clear enabled fsQuad @@ -17,4 +17,4 @@

Methods

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

+

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

diff --git a/api/classes/PostProcessRenderer.html b/api/classes/PostProcessRenderer.html index 15af31e..0588321 100644 --- a/api/classes/PostProcessRenderer.html +++ b/api/classes/PostProcessRenderer.html @@ -1,5 +1,5 @@ PostProcessRenderer | threejs-postprocess

複数のエフェクトコンポーザーと、WebGLRendererを管理し、連続してポストエフェクト処理を行うためのクラス。

-

Constructors

Constructors

Properties

Constructors

Properties

camera: PerspectiveCamera
renderer: WebGLRenderer
scene: Scene

Accessors

Methods

  • シェーダーパスを挟んだEffectComposerを生成、登録する。

    +

Constructors

Properties

camera: PerspectiveCamera
renderer: WebGLRenderer
scene: Scene

Accessors

Methods

  • シェーダーパスを挟んだEffectComposerを生成、登録する。

    Parameters

    • passes: Pass[]
    • OptionalrenderPass: RenderPass

      レンダリングパス。省略した場合は、sceneとcameraを利用して自動生成する。複数のコンポーザーで同じレンダリングパスを共有する場合は、この引数にインスタンスを渡す。

      -

    Returns PostProcessEffectComposer

+

Returns PostProcessEffectComposer

diff --git a/api/classes/PostProcessShader.html b/api/classes/PostProcessShader.html index aa1a202..da383ff 100644 --- a/api/classes/PostProcessShader.html +++ b/api/classes/PostProcessShader.html @@ -3,9 +3,9 @@

このクラスのインスタンスをShaderPassに渡すことで、任意のシェーダーエフェクトコンポーザーになる。 参照関係はPostProcessEffectComposer → PostProcessShaderPass → PostProcessShader

型としては、ShaderPassのコンストラクター第一引数に渡すオブジェクトに相当する。

-

Implements

Constructors

Implements

Constructors

Properties

fragmentShader: string
uniforms: {
    [uniform: string]: IUniform;
}
vertexShader: string = ...

Methods

+

Constructors

Properties

fragmentShader: string
uniforms: {
    [uniform: string]: IUniform;
}
vertexShader: string = ...

Methods

diff --git a/api/classes/PostProcessShaderPass.html b/api/classes/PostProcessShaderPass.html index 75a093b..f63bb90 100644 --- a/api/classes/PostProcessShaderPass.html +++ b/api/classes/PostProcessShaderPass.html @@ -1,7 +1,7 @@ PostProcessShaderPass | threejs-postprocess

Class PostProcessShaderPass

ポストプロセス用のShaderPass。 EffectComposerにPassとして追加することで、任意のポストエフェクトを実現する。

コンストラクターでPostProcessShaderを受け取り、そのシェーダーのuniformを操作する。

-

Hierarchy (view full)

Constructors

Hierarchy (view full)

Constructors

Properties

clear enabled fsQuad @@ -15,4 +15,4 @@

Methods

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

+

Constructors

Properties

clear: boolean
enabled: boolean
fsQuad: FullScreenQuad
isPass: boolean
material: ShaderMaterial
needsSwap: boolean
renderToScreen: boolean
textureID: string
uniforms: {
    [uniform: string]: IUniform;
}

Accessors

Methods

  • Returns void

  • Parameters

    • renderer: WebGLRenderer
    • writeBuffer: WebGLRenderTarget<Texture>
    • readBuffer: WebGLRenderTarget<Texture>
    • deltaTime: number
    • maskActive: boolean

    Returns void

  • Parameters

    • width: number
    • height: number

    Returns void

diff --git a/api/classes/RenderPassOption.html b/api/classes/RenderPassOption.html index 5efcf0d..98a8126 100644 --- a/api/classes/RenderPassOption.html +++ b/api/classes/RenderPassOption.html @@ -2,9 +2,9 @@

sceneとcameraのセット、もしくはrenderPassインスタンスを代入する必要がある。 sceneとcameraのセットの場合 : RenderPassインスタンスを生成する。 renderPassインスタンスの場合 : そのままrenderPassインスタンスを利用する。

-

Constructors

Constructors

Properties

Methods

Constructors

Properties

camera?: Camera
renderPass?: RenderPass
scene?: Scene

Methods

+

Constructors

Properties

camera?: Camera
renderPass?: RenderPass
scene?: Scene

Methods

diff --git a/api/interfaces/IPostProcessShader.html b/api/interfaces/IPostProcessShader.html index c02a666..3612d0c 100644 --- a/api/interfaces/IPostProcessShader.html +++ b/api/interfaces/IPostProcessShader.html @@ -1,4 +1,4 @@ -IPostProcessShader | threejs-postprocess

Interface IPostProcessShader

interface IPostProcessShader {
    fragmentShader: string;
    uniforms: {
        [uniform: string]: IUniform;
    };
    vertexShader: string;
}

Implemented by

Properties

fragmentShader +IPostProcessShader | threejs-postprocess

Interface IPostProcessShader

interface IPostProcessShader {
    fragmentShader: string;
    uniforms: {
        [uniform: string]: IUniform;
    };
    vertexShader: string;
}

Implemented by

Properties

fragmentShader: string
uniforms: {
    [uniform: string]: IUniform;
}
vertexShader: string
+

Properties

fragmentShader: string
uniforms: {
    [uniform: string]: IUniform;
}
vertexShader: string
diff --git a/demo/vendor.js b/demo/vendor.js index a1abfda..39f4ec8 100644 --- a/demo/vendor.js +++ b/demo/vendor.js @@ -1 +1 @@ -"use strict";(self.webpackChunkthreejs_postprocess=self.webpackChunkthreejs_postprocess||[]).push([[121],{418:module=>{eval("\n\nvar has = Object.prototype.hasOwnProperty\n , prefix = '~';\n\n/**\n * Constructor to create a storage for our `EE` objects.\n * An `Events` instance is a plain object whose properties are event names.\n *\n * @constructor\n * @private\n */\nfunction Events() {}\n\n//\n// We try to not inherit from `Object.prototype`. In some engines creating an\n// instance in this way is faster than calling `Object.create(null)` directly.\n// If `Object.create(null)` is not supported we prefix the event names with a\n// character to make sure that the built-in object properties are not\n// overridden or used as an attack vector.\n//\nif (Object.create) {\n Events.prototype = Object.create(null);\n\n //\n // This hack is needed because the `__proto__` property is still inherited in\n // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.\n //\n if (!new Events().__proto__) prefix = false;\n}\n\n/**\n * Representation of a single event listener.\n *\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} [once=false] Specify if the listener is a one-time listener.\n * @constructor\n * @private\n */\nfunction EE(fn, context, once) {\n this.fn = fn;\n this.context = context;\n this.once = once || false;\n}\n\n/**\n * Add a listener for a given event.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} once Specify if the listener is a one-time listener.\n * @returns {EventEmitter}\n * @private\n */\nfunction addListener(emitter, event, fn, context, once) {\n if (typeof fn !== 'function') {\n throw new TypeError('The listener must be a function');\n }\n\n var listener = new EE(fn, context || emitter, once)\n , evt = prefix ? prefix + event : event;\n\n if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;\n else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);\n else emitter._events[evt] = [emitter._events[evt], listener];\n\n return emitter;\n}\n\n/**\n * Clear event by name.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} evt The Event name.\n * @private\n */\nfunction clearEvent(emitter, evt) {\n if (--emitter._eventsCount === 0) emitter._events = new Events();\n else delete emitter._events[evt];\n}\n\n/**\n * Minimal `EventEmitter` interface that is molded against the Node.js\n * `EventEmitter` interface.\n *\n * @constructor\n * @public\n */\nfunction EventEmitter() {\n this._events = new Events();\n this._eventsCount = 0;\n}\n\n/**\n * Return an array listing the events for which the emitter has registered\n * listeners.\n *\n * @returns {Array}\n * @public\n */\nEventEmitter.prototype.eventNames = function eventNames() {\n var names = []\n , events\n , name;\n\n if (this._eventsCount === 0) return names;\n\n for (name in (events = this._events)) {\n if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);\n }\n\n if (Object.getOwnPropertySymbols) {\n return names.concat(Object.getOwnPropertySymbols(events));\n }\n\n return names;\n};\n\n/**\n * Return the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Array} The registered listeners.\n * @public\n */\nEventEmitter.prototype.listeners = function listeners(event) {\n var evt = prefix ? prefix + event : event\n , handlers = this._events[evt];\n\n if (!handlers) return [];\n if (handlers.fn) return [handlers.fn];\n\n for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {\n ee[i] = handlers[i].fn;\n }\n\n return ee;\n};\n\n/**\n * Return the number of listeners listening to a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Number} The number of listeners.\n * @public\n */\nEventEmitter.prototype.listenerCount = function listenerCount(event) {\n var evt = prefix ? prefix + event : event\n , listeners = this._events[evt];\n\n if (!listeners) return 0;\n if (listeners.fn) return 1;\n return listeners.length;\n};\n\n/**\n * Calls each of the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Boolean} `true` if the event had listeners, else `false`.\n * @public\n */\nEventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return false;\n\n var listeners = this._events[evt]\n , len = arguments.length\n , args\n , i;\n\n if (listeners.fn) {\n if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);\n\n switch (len) {\n case 1: return listeners.fn.call(listeners.context), true;\n case 2: return listeners.fn.call(listeners.context, a1), true;\n case 3: return listeners.fn.call(listeners.context, a1, a2), true;\n case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;\n case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;\n case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;\n }\n\n for (i = 1, args = new Array(len -1); i < len; i++) {\n args[i - 1] = arguments[i];\n }\n\n listeners.fn.apply(listeners.context, args);\n } else {\n var length = listeners.length\n , j;\n\n for (i = 0; i < length; i++) {\n if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);\n\n switch (len) {\n case 1: listeners[i].fn.call(listeners[i].context); break;\n case 2: listeners[i].fn.call(listeners[i].context, a1); break;\n case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;\n case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;\n default:\n if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {\n args[j - 1] = arguments[j];\n }\n\n listeners[i].fn.apply(listeners[i].context, args);\n }\n }\n }\n\n return true;\n};\n\n/**\n * Add a listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.on = function on(event, fn, context) {\n return addListener(this, event, fn, context, false);\n};\n\n/**\n * Add a one-time listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.once = function once(event, fn, context) {\n return addListener(this, event, fn, context, true);\n};\n\n/**\n * Remove the listeners of a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn Only remove the listeners that match this function.\n * @param {*} context Only remove the listeners that have this context.\n * @param {Boolean} once Only remove one-time listeners.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return this;\n if (!fn) {\n clearEvent(this, evt);\n return this;\n }\n\n var listeners = this._events[evt];\n\n if (listeners.fn) {\n if (\n listeners.fn === fn &&\n (!once || listeners.once) &&\n (!context || listeners.context === context)\n ) {\n clearEvent(this, evt);\n }\n } else {\n for (var i = 0, events = [], length = listeners.length; i < length; i++) {\n if (\n listeners[i].fn !== fn ||\n (once && !listeners[i].once) ||\n (context && listeners[i].context !== context)\n ) {\n events.push(listeners[i]);\n }\n }\n\n //\n // Reset the array, or remove it completely if we have no more listeners.\n //\n if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;\n else clearEvent(this, evt);\n }\n\n return this;\n};\n\n/**\n * Remove all listeners, or those of the specified event.\n *\n * @param {(String|Symbol)} [event] The event name.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {\n var evt;\n\n if (event) {\n evt = prefix ? prefix + event : event;\n if (this._events[evt]) clearEvent(this, evt);\n } else {\n this._events = new Events();\n this._eventsCount = 0;\n }\n\n return this;\n};\n\n//\n// Alias methods names because people roll like that.\n//\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\nEventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n//\n// Expose the prefix.\n//\nEventEmitter.prefixed = prefix;\n\n//\n// Allow `EventEmitter` to be imported as module namespace.\n//\nEventEmitter.EventEmitter = EventEmitter;\n\n//\n// Expose the module.\n//\nif (true) {\n module.exports = EventEmitter;\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNDE4LmpzIiwibWFwcGluZ3MiOiJBQUFhOztBQUViO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsVUFBVTtBQUNyQixXQUFXLEdBQUc7QUFDZCxXQUFXLFNBQVM7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGNBQWM7QUFDekIsV0FBVyxpQkFBaUI7QUFDNUIsV0FBVyxVQUFVO0FBQ3JCLFdBQVcsR0FBRztBQUNkLFdBQVcsU0FBUztBQUNwQixhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxjQUFjO0FBQ3pCLFdBQVcsaUJBQWlCO0FBQzVCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUIsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSwwREFBMEQsT0FBTztBQUNqRTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUIsYUFBYSxTQUFTO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSwwQ0FBMEMsU0FBUztBQUNuRDtBQUNBOztBQUVBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUEsZ0JBQWdCLFlBQVk7QUFDNUI7O0FBRUE7QUFDQSw0REFBNEQ7QUFDNUQsZ0VBQWdFO0FBQ2hFLG9FQUFvRTtBQUNwRSx3RUFBd0U7QUFDeEU7QUFDQSwyREFBMkQsU0FBUztBQUNwRTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUIsV0FBVyxVQUFVO0FBQ3JCLFdBQVcsR0FBRztBQUNkLGFBQWEsY0FBYztBQUMzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsaUJBQWlCO0FBQzVCLFdBQVcsVUFBVTtBQUNyQixXQUFXLEdBQUc7QUFDZCxhQUFhLGNBQWM7QUFDM0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGlCQUFpQjtBQUM1QixXQUFXLFVBQVU7QUFDckIsV0FBVyxHQUFHO0FBQ2QsV0FBVyxTQUFTO0FBQ3BCLGFBQWEsY0FBYztBQUMzQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osNERBQTRELFlBQVk7QUFDeEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGlCQUFpQjtBQUM1QixhQUFhLGNBQWM7QUFDM0I7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSSxJQUE2QjtBQUNqQztBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy9ldmVudGVtaXR0ZXIzL2luZGV4LmpzPzcwMmUiXSwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaGFzID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eVxuICAsIHByZWZpeCA9ICd+JztcblxuLyoqXG4gKiBDb25zdHJ1Y3RvciB0byBjcmVhdGUgYSBzdG9yYWdlIGZvciBvdXIgYEVFYCBvYmplY3RzLlxuICogQW4gYEV2ZW50c2AgaW5zdGFuY2UgaXMgYSBwbGFpbiBvYmplY3Qgd2hvc2UgcHJvcGVydGllcyBhcmUgZXZlbnQgbmFtZXMuXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBFdmVudHMoKSB7fVxuXG4vL1xuLy8gV2UgdHJ5IHRvIG5vdCBpbmhlcml0IGZyb20gYE9iamVjdC5wcm90b3R5cGVgLiBJbiBzb21lIGVuZ2luZXMgY3JlYXRpbmcgYW5cbi8vIGluc3RhbmNlIGluIHRoaXMgd2F5IGlzIGZhc3RlciB0aGFuIGNhbGxpbmcgYE9iamVjdC5jcmVhdGUobnVsbClgIGRpcmVjdGx5LlxuLy8gSWYgYE9iamVjdC5jcmVhdGUobnVsbClgIGlzIG5vdCBzdXBwb3J0ZWQgd2UgcHJlZml4IHRoZSBldmVudCBuYW1lcyB3aXRoIGFcbi8vIGNoYXJhY3RlciB0byBtYWtlIHN1cmUgdGhhdCB0aGUgYnVpbHQtaW4gb2JqZWN0IHByb3BlcnRpZXMgYXJlIG5vdFxuLy8gb3ZlcnJpZGRlbiBvciB1c2VkIGFzIGFuIGF0dGFjayB2ZWN0b3IuXG4vL1xuaWYgKE9iamVjdC5jcmVhdGUpIHtcbiAgRXZlbnRzLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG5cbiAgLy9cbiAgLy8gVGhpcyBoYWNrIGlzIG5lZWRlZCBiZWNhdXNlIHRoZSBgX19wcm90b19fYCBwcm9wZXJ0eSBpcyBzdGlsbCBpbmhlcml0ZWQgaW5cbiAgLy8gc29tZSBvbGQgYnJvd3NlcnMgbGlrZSBBbmRyb2lkIDQsIGlQaG9uZSA1LjEsIE9wZXJhIDExIGFuZCBTYWZhcmkgNS5cbiAgLy9cbiAgaWYgKCFuZXcgRXZlbnRzKCkuX19wcm90b19fKSBwcmVmaXggPSBmYWxzZTtcbn1cblxuLyoqXG4gKiBSZXByZXNlbnRhdGlvbiBvZiBhIHNpbmdsZSBldmVudCBsaXN0ZW5lci5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBUaGUgbGlzdGVuZXIgZnVuY3Rpb24uXG4gKiBAcGFyYW0geyp9IGNvbnRleHQgVGhlIGNvbnRleHQgdG8gaW52b2tlIHRoZSBsaXN0ZW5lciB3aXRoLlxuICogQHBhcmFtIHtCb29sZWFufSBbb25jZT1mYWxzZV0gU3BlY2lmeSBpZiB0aGUgbGlzdGVuZXIgaXMgYSBvbmUtdGltZSBsaXN0ZW5lci5cbiAqIEBjb25zdHJ1Y3RvclxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gRUUoZm4sIGNvbnRleHQsIG9uY2UpIHtcbiAgdGhpcy5mbiA9IGZuO1xuICB0aGlzLmNvbnRleHQgPSBjb250ZXh0O1xuICB0aGlzLm9uY2UgPSBvbmNlIHx8IGZhbHNlO1xufVxuXG4vKipcbiAqIEFkZCBhIGxpc3RlbmVyIGZvciBhIGdpdmVuIGV2ZW50LlxuICpcbiAqIEBwYXJhbSB7RXZlbnRFbWl0dGVyfSBlbWl0dGVyIFJlZmVyZW5jZSB0byB0aGUgYEV2ZW50RW1pdHRlcmAgaW5zdGFuY2UuXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZlbnQgVGhlIGV2ZW50IG5hbWUuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBUaGUgbGlzdGVuZXIgZnVuY3Rpb24uXG4gKiBAcGFyYW0geyp9IGNvbnRleHQgVGhlIGNvbnRleHQgdG8gaW52b2tlIHRoZSBsaXN0ZW5lciB3aXRoLlxuICogQHBhcmFtIHtCb29sZWFufSBvbmNlIFNwZWNpZnkgaWYgdGhlIGxpc3RlbmVyIGlzIGEgb25lLXRpbWUgbGlzdGVuZXIuXG4gKiBAcmV0dXJucyB7RXZlbnRFbWl0dGVyfVxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gYWRkTGlzdGVuZXIoZW1pdHRlciwgZXZlbnQsIGZuLCBjb250ZXh0LCBvbmNlKSB7XG4gIGlmICh0eXBlb2YgZm4gIT09ICdmdW5jdGlvbicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdUaGUgbGlzdGVuZXIgbXVzdCBiZSBhIGZ1bmN0aW9uJyk7XG4gIH1cblxuICB2YXIgbGlzdGVuZXIgPSBuZXcgRUUoZm4sIGNvbnRleHQgfHwgZW1pdHRlciwgb25jZSlcbiAgICAsIGV2dCA9IHByZWZpeCA/IHByZWZpeCArIGV2ZW50IDogZXZlbnQ7XG5cbiAgaWYgKCFlbWl0dGVyLl9ldmVudHNbZXZ0XSkgZW1pdHRlci5fZXZlbnRzW2V2dF0gPSBsaXN0ZW5lciwgZW1pdHRlci5fZXZlbnRzQ291bnQrKztcbiAgZWxzZSBpZiAoIWVtaXR0ZXIuX2V2ZW50c1tldnRdLmZuKSBlbWl0dGVyLl9ldmVudHNbZXZ0XS5wdXNoKGxpc3RlbmVyKTtcbiAgZWxzZSBlbWl0dGVyLl9ldmVudHNbZXZ0XSA9IFtlbWl0dGVyLl9ldmVudHNbZXZ0XSwgbGlzdGVuZXJdO1xuXG4gIHJldHVybiBlbWl0dGVyO1xufVxuXG4vKipcbiAqIENsZWFyIGV2ZW50IGJ5IG5hbWUuXG4gKlxuICogQHBhcmFtIHtFdmVudEVtaXR0ZXJ9IGVtaXR0ZXIgUmVmZXJlbmNlIHRvIHRoZSBgRXZlbnRFbWl0dGVyYCBpbnN0YW5jZS5cbiAqIEBwYXJhbSB7KFN0cmluZ3xTeW1ib2wpfSBldnQgVGhlIEV2ZW50IG5hbWUuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBjbGVhckV2ZW50KGVtaXR0ZXIsIGV2dCkge1xuICBpZiAoLS1lbWl0dGVyLl9ldmVudHNDb3VudCA9PT0gMCkgZW1pdHRlci5fZXZlbnRzID0gbmV3IEV2ZW50cygpO1xuICBlbHNlIGRlbGV0ZSBlbWl0dGVyLl9ldmVudHNbZXZ0XTtcbn1cblxuLyoqXG4gKiBNaW5pbWFsIGBFdmVudEVtaXR0ZXJgIGludGVyZmFjZSB0aGF0IGlzIG1vbGRlZCBhZ2FpbnN0IHRoZSBOb2RlLmpzXG4gKiBgRXZlbnRFbWl0dGVyYCBpbnRlcmZhY2UuXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAcHVibGljXG4gKi9cbmZ1bmN0aW9uIEV2ZW50RW1pdHRlcigpIHtcbiAgdGhpcy5fZXZlbnRzID0gbmV3IEV2ZW50cygpO1xuICB0aGlzLl9ldmVudHNDb3VudCA9IDA7XG59XG5cbi8qKlxuICogUmV0dXJuIGFuIGFycmF5IGxpc3RpbmcgdGhlIGV2ZW50cyBmb3Igd2hpY2ggdGhlIGVtaXR0ZXIgaGFzIHJlZ2lzdGVyZWRcbiAqIGxpc3RlbmVycy5cbiAqXG4gKiBAcmV0dXJucyB7QXJyYXl9XG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuZXZlbnROYW1lcyA9IGZ1bmN0aW9uIGV2ZW50TmFtZXMoKSB7XG4gIHZhciBuYW1lcyA9IFtdXG4gICAgLCBldmVudHNcbiAgICAsIG5hbWU7XG5cbiAgaWYgKHRoaXMuX2V2ZW50c0NvdW50ID09PSAwKSByZXR1cm4gbmFtZXM7XG5cbiAgZm9yIChuYW1lIGluIChldmVudHMgPSB0aGlzLl9ldmVudHMpKSB7XG4gICAgaWYgKGhhcy5jYWxsKGV2ZW50cywgbmFtZSkpIG5hbWVzLnB1c2gocHJlZml4ID8gbmFtZS5zbGljZSgxKSA6IG5hbWUpO1xuICB9XG5cbiAgaWYgKE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMpIHtcbiAgICByZXR1cm4gbmFtZXMuY29uY2F0KE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMoZXZlbnRzKSk7XG4gIH1cblxuICByZXR1cm4gbmFtZXM7XG59O1xuXG4vKipcbiAqIFJldHVybiB0aGUgbGlzdGVuZXJzIHJlZ2lzdGVyZWQgZm9yIGEgZ2l2ZW4gZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHJldHVybnMge0FycmF5fSBUaGUgcmVnaXN0ZXJlZCBsaXN0ZW5lcnMuXG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUubGlzdGVuZXJzID0gZnVuY3Rpb24gbGlzdGVuZXJzKGV2ZW50KSB7XG4gIHZhciBldnQgPSBwcmVmaXggPyBwcmVmaXggKyBldmVudCA6IGV2ZW50XG4gICAgLCBoYW5kbGVycyA9IHRoaXMuX2V2ZW50c1tldnRdO1xuXG4gIGlmICghaGFuZGxlcnMpIHJldHVybiBbXTtcbiAgaWYgKGhhbmRsZXJzLmZuKSByZXR1cm4gW2hhbmRsZXJzLmZuXTtcblxuICBmb3IgKHZhciBpID0gMCwgbCA9IGhhbmRsZXJzLmxlbmd0aCwgZWUgPSBuZXcgQXJyYXkobCk7IGkgPCBsOyBpKyspIHtcbiAgICBlZVtpXSA9IGhhbmRsZXJzW2ldLmZuO1xuICB9XG5cbiAgcmV0dXJuIGVlO1xufTtcblxuLyoqXG4gKiBSZXR1cm4gdGhlIG51bWJlciBvZiBsaXN0ZW5lcnMgbGlzdGVuaW5nIHRvIGEgZ2l2ZW4gZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHJldHVybnMge051bWJlcn0gVGhlIG51bWJlciBvZiBsaXN0ZW5lcnMuXG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUubGlzdGVuZXJDb3VudCA9IGZ1bmN0aW9uIGxpc3RlbmVyQ291bnQoZXZlbnQpIHtcbiAgdmFyIGV2dCA9IHByZWZpeCA/IHByZWZpeCArIGV2ZW50IDogZXZlbnRcbiAgICAsIGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50c1tldnRdO1xuXG4gIGlmICghbGlzdGVuZXJzKSByZXR1cm4gMDtcbiAgaWYgKGxpc3RlbmVycy5mbikgcmV0dXJuIDE7XG4gIHJldHVybiBsaXN0ZW5lcnMubGVuZ3RoO1xufTtcblxuLyoqXG4gKiBDYWxscyBlYWNoIG9mIHRoZSBsaXN0ZW5lcnMgcmVnaXN0ZXJlZCBmb3IgYSBnaXZlbiBldmVudC5cbiAqXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZlbnQgVGhlIGV2ZW50IG5hbWUuXG4gKiBAcmV0dXJucyB7Qm9vbGVhbn0gYHRydWVgIGlmIHRoZSBldmVudCBoYWQgbGlzdGVuZXJzLCBlbHNlIGBmYWxzZWAuXG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuZW1pdCA9IGZ1bmN0aW9uIGVtaXQoZXZlbnQsIGExLCBhMiwgYTMsIGE0LCBhNSkge1xuICB2YXIgZXZ0ID0gcHJlZml4ID8gcHJlZml4ICsgZXZlbnQgOiBldmVudDtcblxuICBpZiAoIXRoaXMuX2V2ZW50c1tldnRdKSByZXR1cm4gZmFsc2U7XG5cbiAgdmFyIGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50c1tldnRdXG4gICAgLCBsZW4gPSBhcmd1bWVudHMubGVuZ3RoXG4gICAgLCBhcmdzXG4gICAgLCBpO1xuXG4gIGlmIChsaXN0ZW5lcnMuZm4pIHtcbiAgICBpZiAobGlzdGVuZXJzLm9uY2UpIHRoaXMucmVtb3ZlTGlzdGVuZXIoZXZlbnQsIGxpc3RlbmVycy5mbiwgdW5kZWZpbmVkLCB0cnVlKTtcblxuICAgIHN3aXRjaCAobGVuKSB7XG4gICAgICBjYXNlIDE6IHJldHVybiBsaXN0ZW5lcnMuZm4uY2FsbChsaXN0ZW5lcnMuY29udGV4dCksIHRydWU7XG4gICAgICBjYXNlIDI6IHJldHVybiBsaXN0ZW5lcnMuZm4uY2FsbChsaXN0ZW5lcnMuY29udGV4dCwgYTEpLCB0cnVlO1xuICAgICAgY2FzZSAzOiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQsIGExLCBhMiksIHRydWU7XG4gICAgICBjYXNlIDQ6IHJldHVybiBsaXN0ZW5lcnMuZm4uY2FsbChsaXN0ZW5lcnMuY29udGV4dCwgYTEsIGEyLCBhMyksIHRydWU7XG4gICAgICBjYXNlIDU6IHJldHVybiBsaXN0ZW5lcnMuZm4uY2FsbChsaXN0ZW5lcnMuY29udGV4dCwgYTEsIGEyLCBhMywgYTQpLCB0cnVlO1xuICAgICAgY2FzZSA2OiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQsIGExLCBhMiwgYTMsIGE0LCBhNSksIHRydWU7XG4gICAgfVxuXG4gICAgZm9yIChpID0gMSwgYXJncyA9IG5ldyBBcnJheShsZW4gLTEpOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIGFyZ3NbaSAtIDFdID0gYXJndW1lbnRzW2ldO1xuICAgIH1cblxuICAgIGxpc3RlbmVycy5mbi5hcHBseShsaXN0ZW5lcnMuY29udGV4dCwgYXJncyk7XG4gIH0gZWxzZSB7XG4gICAgdmFyIGxlbmd0aCA9IGxpc3RlbmVycy5sZW5ndGhcbiAgICAgICwgajtcblxuICAgIGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGxpc3RlbmVyc1tpXS5vbmNlKSB0aGlzLnJlbW92ZUxpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcnNbaV0uZm4sIHVuZGVmaW5lZCwgdHJ1ZSk7XG5cbiAgICAgIHN3aXRjaCAobGVuKSB7XG4gICAgICAgIGNhc2UgMTogbGlzdGVuZXJzW2ldLmZuLmNhbGwobGlzdGVuZXJzW2ldLmNvbnRleHQpOyBicmVhaztcbiAgICAgICAgY2FzZSAyOiBsaXN0ZW5lcnNbaV0uZm4uY2FsbChsaXN0ZW5lcnNbaV0uY29udGV4dCwgYTEpOyBicmVhaztcbiAgICAgICAgY2FzZSAzOiBsaXN0ZW5lcnNbaV0uZm4uY2FsbChsaXN0ZW5lcnNbaV0uY29udGV4dCwgYTEsIGEyKTsgYnJlYWs7XG4gICAgICAgIGNhc2UgNDogbGlzdGVuZXJzW2ldLmZuLmNhbGwobGlzdGVuZXJzW2ldLmNvbnRleHQsIGExLCBhMiwgYTMpOyBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICBpZiAoIWFyZ3MpIGZvciAoaiA9IDEsIGFyZ3MgPSBuZXcgQXJyYXkobGVuIC0xKTsgaiA8IGxlbjsgaisrKSB7XG4gICAgICAgICAgICBhcmdzW2ogLSAxXSA9IGFyZ3VtZW50c1tqXTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBsaXN0ZW5lcnNbaV0uZm4uYXBwbHkobGlzdGVuZXJzW2ldLmNvbnRleHQsIGFyZ3MpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuLyoqXG4gKiBBZGQgYSBsaXN0ZW5lciBmb3IgYSBnaXZlbiBldmVudC5cbiAqXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZlbnQgVGhlIGV2ZW50IG5hbWUuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBUaGUgbGlzdGVuZXIgZnVuY3Rpb24uXG4gKiBAcGFyYW0geyp9IFtjb250ZXh0PXRoaXNdIFRoZSBjb250ZXh0IHRvIGludm9rZSB0aGUgbGlzdGVuZXIgd2l0aC5cbiAqIEByZXR1cm5zIHtFdmVudEVtaXR0ZXJ9IGB0aGlzYC5cbiAqIEBwdWJsaWNcbiAqL1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbiA9IGZ1bmN0aW9uIG9uKGV2ZW50LCBmbiwgY29udGV4dCkge1xuICByZXR1cm4gYWRkTGlzdGVuZXIodGhpcywgZXZlbnQsIGZuLCBjb250ZXh0LCBmYWxzZSk7XG59O1xuXG4vKipcbiAqIEFkZCBhIG9uZS10aW1lIGxpc3RlbmVyIGZvciBhIGdpdmVuIGV2ZW50LlxuICpcbiAqIEBwYXJhbSB7KFN0cmluZ3xTeW1ib2wpfSBldmVudCBUaGUgZXZlbnQgbmFtZS5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIFRoZSBsaXN0ZW5lciBmdW5jdGlvbi5cbiAqIEBwYXJhbSB7Kn0gW2NvbnRleHQ9dGhpc10gVGhlIGNvbnRleHQgdG8gaW52b2tlIHRoZSBsaXN0ZW5lciB3aXRoLlxuICogQHJldHVybnMge0V2ZW50RW1pdHRlcn0gYHRoaXNgLlxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLm9uY2UgPSBmdW5jdGlvbiBvbmNlKGV2ZW50LCBmbiwgY29udGV4dCkge1xuICByZXR1cm4gYWRkTGlzdGVuZXIodGhpcywgZXZlbnQsIGZuLCBjb250ZXh0LCB0cnVlKTtcbn07XG5cbi8qKlxuICogUmVtb3ZlIHRoZSBsaXN0ZW5lcnMgb2YgYSBnaXZlbiBldmVudC5cbiAqXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZlbnQgVGhlIGV2ZW50IG5hbWUuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBPbmx5IHJlbW92ZSB0aGUgbGlzdGVuZXJzIHRoYXQgbWF0Y2ggdGhpcyBmdW5jdGlvbi5cbiAqIEBwYXJhbSB7Kn0gY29udGV4dCBPbmx5IHJlbW92ZSB0aGUgbGlzdGVuZXJzIHRoYXQgaGF2ZSB0aGlzIGNvbnRleHQuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9uY2UgT25seSByZW1vdmUgb25lLXRpbWUgbGlzdGVuZXJzLlxuICogQHJldHVybnMge0V2ZW50RW1pdHRlcn0gYHRoaXNgLlxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnJlbW92ZUxpc3RlbmVyID0gZnVuY3Rpb24gcmVtb3ZlTGlzdGVuZXIoZXZlbnQsIGZuLCBjb250ZXh0LCBvbmNlKSB7XG4gIHZhciBldnQgPSBwcmVmaXggPyBwcmVmaXggKyBldmVudCA6IGV2ZW50O1xuXG4gIGlmICghdGhpcy5fZXZlbnRzW2V2dF0pIHJldHVybiB0aGlzO1xuICBpZiAoIWZuKSB7XG4gICAgY2xlYXJFdmVudCh0aGlzLCBldnQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgdmFyIGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50c1tldnRdO1xuXG4gIGlmIChsaXN0ZW5lcnMuZm4pIHtcbiAgICBpZiAoXG4gICAgICBsaXN0ZW5lcnMuZm4gPT09IGZuICYmXG4gICAgICAoIW9uY2UgfHwgbGlzdGVuZXJzLm9uY2UpICYmXG4gICAgICAoIWNvbnRleHQgfHwgbGlzdGVuZXJzLmNvbnRleHQgPT09IGNvbnRleHQpXG4gICAgKSB7XG4gICAgICBjbGVhckV2ZW50KHRoaXMsIGV2dCk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGZvciAodmFyIGkgPSAwLCBldmVudHMgPSBbXSwgbGVuZ3RoID0gbGlzdGVuZXJzLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoXG4gICAgICAgIGxpc3RlbmVyc1tpXS5mbiAhPT0gZm4gfHxcbiAgICAgICAgKG9uY2UgJiYgIWxpc3RlbmVyc1tpXS5vbmNlKSB8fFxuICAgICAgICAoY29udGV4dCAmJiBsaXN0ZW5lcnNbaV0uY29udGV4dCAhPT0gY29udGV4dClcbiAgICAgICkge1xuICAgICAgICBldmVudHMucHVzaChsaXN0ZW5lcnNbaV0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vXG4gICAgLy8gUmVzZXQgdGhlIGFycmF5LCBvciByZW1vdmUgaXQgY29tcGxldGVseSBpZiB3ZSBoYXZlIG5vIG1vcmUgbGlzdGVuZXJzLlxuICAgIC8vXG4gICAgaWYgKGV2ZW50cy5sZW5ndGgpIHRoaXMuX2V2ZW50c1tldnRdID0gZXZlbnRzLmxlbmd0aCA9PT0gMSA/IGV2ZW50c1swXSA6IGV2ZW50cztcbiAgICBlbHNlIGNsZWFyRXZlbnQodGhpcywgZXZ0KTtcbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKiBSZW1vdmUgYWxsIGxpc3RlbmVycywgb3IgdGhvc2Ugb2YgdGhlIHNwZWNpZmllZCBldmVudC5cbiAqXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gW2V2ZW50XSBUaGUgZXZlbnQgbmFtZS5cbiAqIEByZXR1cm5zIHtFdmVudEVtaXR0ZXJ9IGB0aGlzYC5cbiAqIEBwdWJsaWNcbiAqL1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBmdW5jdGlvbiByZW1vdmVBbGxMaXN0ZW5lcnMoZXZlbnQpIHtcbiAgdmFyIGV2dDtcblxuICBpZiAoZXZlbnQpIHtcbiAgICBldnQgPSBwcmVmaXggPyBwcmVmaXggKyBldmVudCA6IGV2ZW50O1xuICAgIGlmICh0aGlzLl9ldmVudHNbZXZ0XSkgY2xlYXJFdmVudCh0aGlzLCBldnQpO1xuICB9IGVsc2Uge1xuICAgIHRoaXMuX2V2ZW50cyA9IG5ldyBFdmVudHMoKTtcbiAgICB0aGlzLl9ldmVudHNDb3VudCA9IDA7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbi8vXG4vLyBBbGlhcyBtZXRob2RzIG5hbWVzIGJlY2F1c2UgcGVvcGxlIHJvbGwgbGlrZSB0aGF0LlxuLy9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub2ZmID0gRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVMaXN0ZW5lcjtcbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXIgPSBFdmVudEVtaXR0ZXIucHJvdG90eXBlLm9uO1xuXG4vL1xuLy8gRXhwb3NlIHRoZSBwcmVmaXguXG4vL1xuRXZlbnRFbWl0dGVyLnByZWZpeGVkID0gcHJlZml4O1xuXG4vL1xuLy8gQWxsb3cgYEV2ZW50RW1pdHRlcmAgdG8gYmUgaW1wb3J0ZWQgYXMgbW9kdWxlIG5hbWVzcGFjZS5cbi8vXG5FdmVudEVtaXR0ZXIuRXZlbnRFbWl0dGVyID0gRXZlbnRFbWl0dGVyO1xuXG4vL1xuLy8gRXhwb3NlIHRoZSBtb2R1bGUuXG4vL1xuaWYgKCd1bmRlZmluZWQnICE9PSB0eXBlb2YgbW9kdWxlKSB7XG4gIG1vZHVsZS5leHBvcnRzID0gRXZlbnRFbWl0dGVyO1xufVxuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///418\n")},993:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval('\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n w: () => (/* reexport */ RAFTicker),\n J: () => (/* reexport */ RAFTickerEventContext)\n});\n\n// EXTERNAL MODULE: ./node_modules/eventemitter3/index.js\nvar eventemitter3 = __webpack_require__(418);\n;// CONCATENATED MODULE: ./node_modules/eventemitter3/index.mjs\n\n\n\n/* harmony default export */ const node_modules_eventemitter3 = ((/* unused pure expression or super */ null && (EventEmitter)));\n\n;// CONCATENATED MODULE: ./node_modules/@masatomakino/raf-ticker/esm/RAFTickerEvent.js\nclass RAFTickerEventContext {\n constructor(timestamp, delta) {\n this.timestamp = timestamp;\n this.delta = delta;\n }\n}\n\n;// CONCATENATED MODULE: ./node_modules/@masatomakino/raf-ticker/esm/RAFTicker.js\nvar _a;\n\n\nclass RAFTicker {\n static initialize() {\n if (this._dispatcher == null) {\n this._dispatcher = new eventemitter3();\n }\n this.start();\n }\n static reset() {\n this._dispatcher.removeAllListeners();\n this.stop();\n this.start();\n }\n static start() {\n if (!_a._id) {\n this._lastUpdateTimestamp = undefined;\n _a.onTick(performance.now());\n }\n }\n static stop() {\n cancelAnimationFrame(_a._id);\n this._id = undefined;\n this._lastUpdateTimestamp = undefined;\n }\n static addListener(type, listener) {\n this._dispatcher.on(type, listener);\n }\n /**\n *\n * @param type\n * @param listener\n */\n static hasListener(type, listener) {\n const listeners = this._dispatcher.listeners(type);\n return listeners.includes(listener);\n }\n /**\n * Removes the specified listener\n *\n * @param type\n * @param listener\n */\n static removeListener(type, listener) {\n this._dispatcher.removeListener(type, listener);\n }\n /**\n * イベントを発効する。\n * この関数はアプリケーションから利用することはなく、主に単体テストのために使用する。\n *\n * @param type\n * @param event\n */\n static emit(type, event) {\n this._dispatcher.emit(type, event);\n }\n static emitTickEvent(timestamp) {\n if (_a._lastUpdateTimestamp == null) {\n _a._lastUpdateTimestamp = timestamp;\n }\n const delta = timestamp - _a._lastUpdateTimestamp;\n this._dispatcher.emit("onBeforeTick", new RAFTickerEventContext(timestamp, delta));\n this._dispatcher.emit("tick", new RAFTickerEventContext(timestamp, delta));\n this._dispatcher.emit("onAfterTick", new RAFTickerEventContext(timestamp, delta));\n _a._lastUpdateTimestamp = timestamp;\n }\n}\n_a = RAFTicker;\n/**\n * Alias for addListener\n *\n * @param type\n * @param listener\n */\nRAFTicker.on = _a.addListener;\n/**\n * Alias for removeListener\n *\n * @param type\n * @param listener\n */\nRAFTicker.off = _a.removeListener;\nRAFTicker.onTick = (timestamp) => {\n _a.emitTickEvent(timestamp);\n _a._id = requestAnimationFrame(_a.onTick);\n};\nRAFTicker.initialize();\n\n;// CONCATENATED MODULE: ./node_modules/@masatomakino/raf-ticker/esm/index.js\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiOTkzLmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUFBcUM7O0FBRWQ7QUFDdkIsaUVBQWUsNERBQVk7OztBQ0hwQjtBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0xBO0FBQzZDO0FBQ2U7QUFDckQ7QUFDUDtBQUNBO0FBQ0EsbUNBQW1DLGFBQVk7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrREFBa0QscUJBQXFCO0FBQ3ZFLDBDQUEwQyxxQkFBcUI7QUFDL0QsaURBQWlELHFCQUFxQjtBQUN0RTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUN2RitCO0FBQ0siLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL2V2ZW50ZW1pdHRlcjMvaW5kZXgubWpzP2U2Y2MiLCJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy9AbWFzYXRvbWFraW5vL3JhZi10aWNrZXIvZXNtL1JBRlRpY2tlckV2ZW50LmpzPzk1YTciLCJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy9AbWFzYXRvbWFraW5vL3JhZi10aWNrZXIvZXNtL1JBRlRpY2tlci5qcz9iOTg4Iiwid2VicGFjazovL3RocmVlanMtcG9zdHByb2Nlc3MvLi9ub2RlX21vZHVsZXMvQG1hc2F0b21ha2luby9yYWYtdGlja2VyL2VzbS9pbmRleC5qcz9mYmNkIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBFdmVudEVtaXR0ZXIgZnJvbSAnLi9pbmRleC5qcydcblxuZXhwb3J0IHsgRXZlbnRFbWl0dGVyIH1cbmV4cG9ydCBkZWZhdWx0IEV2ZW50RW1pdHRlclxuIiwiZXhwb3J0IGNsYXNzIFJBRlRpY2tlckV2ZW50Q29udGV4dCB7XG4gICAgY29uc3RydWN0b3IodGltZXN0YW1wLCBkZWx0YSkge1xuICAgICAgICB0aGlzLnRpbWVzdGFtcCA9IHRpbWVzdGFtcDtcbiAgICAgICAgdGhpcy5kZWx0YSA9IGRlbHRhO1xuICAgIH1cbn1cbiIsInZhciBfYTtcbmltcG9ydCB7IEV2ZW50RW1pdHRlciB9IGZyb20gXCJldmVudGVtaXR0ZXIzXCI7XG5pbXBvcnQgeyBSQUZUaWNrZXJFdmVudENvbnRleHQgfSBmcm9tIFwiLi9SQUZUaWNrZXJFdmVudC5qc1wiO1xuZXhwb3J0IGNsYXNzIFJBRlRpY2tlciB7XG4gICAgc3RhdGljIGluaXRpYWxpemUoKSB7XG4gICAgICAgIGlmICh0aGlzLl9kaXNwYXRjaGVyID09IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMuX2Rpc3BhdGNoZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zdGFydCgpO1xuICAgIH1cbiAgICBzdGF0aWMgcmVzZXQoKSB7XG4gICAgICAgIHRoaXMuX2Rpc3BhdGNoZXIucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgIHRoaXMuc3RvcCgpO1xuICAgICAgICB0aGlzLnN0YXJ0KCk7XG4gICAgfVxuICAgIHN0YXRpYyBzdGFydCgpIHtcbiAgICAgICAgaWYgKCFfYS5faWQpIHtcbiAgICAgICAgICAgIHRoaXMuX2xhc3RVcGRhdGVUaW1lc3RhbXAgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICBfYS5vblRpY2socGVyZm9ybWFuY2Uubm93KCkpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHN0YXRpYyBzdG9wKCkge1xuICAgICAgICBjYW5jZWxBbmltYXRpb25GcmFtZShfYS5faWQpO1xuICAgICAgICB0aGlzLl9pZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpcy5fbGFzdFVwZGF0ZVRpbWVzdGFtcCA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgc3RhdGljIGFkZExpc3RlbmVyKHR5cGUsIGxpc3RlbmVyKSB7XG4gICAgICAgIHRoaXMuX2Rpc3BhdGNoZXIub24odHlwZSwgbGlzdGVuZXIpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB0eXBlXG4gICAgICogQHBhcmFtIGxpc3RlbmVyXG4gICAgICovXG4gICAgc3RhdGljIGhhc0xpc3RlbmVyKHR5cGUsIGxpc3RlbmVyKSB7XG4gICAgICAgIGNvbnN0IGxpc3RlbmVycyA9IHRoaXMuX2Rpc3BhdGNoZXIubGlzdGVuZXJzKHR5cGUpO1xuICAgICAgICByZXR1cm4gbGlzdGVuZXJzLmluY2x1ZGVzKGxpc3RlbmVyKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyB0aGUgc3BlY2lmaWVkIGxpc3RlbmVyXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdHlwZVxuICAgICAqIEBwYXJhbSBsaXN0ZW5lclxuICAgICAqL1xuICAgIHN0YXRpYyByZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcikge1xuICAgICAgICB0aGlzLl9kaXNwYXRjaGVyLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGxpc3RlbmVyKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICog44Kk44OZ44Oz44OI44KS55m65Yq544GZ44KL44CCXG4gICAgICog44GT44Gu6Zai5pWw44Gv44Ki44OX44Oq44Kx44O844K344On44Oz44GL44KJ5Yip55So44GZ44KL44GT44Go44Gv44Gq44GP44CB5Li744Gr5Y2Y5L2T44OG44K544OI44Gu44Gf44KB44Gr5L2/55So44GZ44KL44CCXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdHlwZVxuICAgICAqIEBwYXJhbSBldmVudFxuICAgICAqL1xuICAgIHN0YXRpYyBlbWl0KHR5cGUsIGV2ZW50KSB7XG4gICAgICAgIHRoaXMuX2Rpc3BhdGNoZXIuZW1pdCh0eXBlLCBldmVudCk7XG4gICAgfVxuICAgIHN0YXRpYyBlbWl0VGlja0V2ZW50KHRpbWVzdGFtcCkge1xuICAgICAgICBpZiAoX2EuX2xhc3RVcGRhdGVUaW1lc3RhbXAgPT0gbnVsbCkge1xuICAgICAgICAgICAgX2EuX2xhc3RVcGRhdGVUaW1lc3RhbXAgPSB0aW1lc3RhbXA7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZGVsdGEgPSB0aW1lc3RhbXAgLSBfYS5fbGFzdFVwZGF0ZVRpbWVzdGFtcDtcbiAgICAgICAgdGhpcy5fZGlzcGF0Y2hlci5lbWl0KFwib25CZWZvcmVUaWNrXCIsIG5ldyBSQUZUaWNrZXJFdmVudENvbnRleHQodGltZXN0YW1wLCBkZWx0YSkpO1xuICAgICAgICB0aGlzLl9kaXNwYXRjaGVyLmVtaXQoXCJ0aWNrXCIsIG5ldyBSQUZUaWNrZXJFdmVudENvbnRleHQodGltZXN0YW1wLCBkZWx0YSkpO1xuICAgICAgICB0aGlzLl9kaXNwYXRjaGVyLmVtaXQoXCJvbkFmdGVyVGlja1wiLCBuZXcgUkFGVGlja2VyRXZlbnRDb250ZXh0KHRpbWVzdGFtcCwgZGVsdGEpKTtcbiAgICAgICAgX2EuX2xhc3RVcGRhdGVUaW1lc3RhbXAgPSB0aW1lc3RhbXA7XG4gICAgfVxufVxuX2EgPSBSQUZUaWNrZXI7XG4vKipcbiAqIEFsaWFzIGZvciBhZGRMaXN0ZW5lclxuICpcbiAqIEBwYXJhbSB0eXBlXG4gKiBAcGFyYW0gbGlzdGVuZXJcbiAqL1xuUkFGVGlja2VyLm9uID0gX2EuYWRkTGlzdGVuZXI7XG4vKipcbiAqIEFsaWFzIGZvciByZW1vdmVMaXN0ZW5lclxuICpcbiAqIEBwYXJhbSB0eXBlXG4gKiBAcGFyYW0gbGlzdGVuZXJcbiAqL1xuUkFGVGlja2VyLm9mZiA9IF9hLnJlbW92ZUxpc3RlbmVyO1xuUkFGVGlja2VyLm9uVGljayA9ICh0aW1lc3RhbXApID0+IHtcbiAgICBfYS5lbWl0VGlja0V2ZW50KHRpbWVzdGFtcCk7XG4gICAgX2EuX2lkID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKF9hLm9uVGljayk7XG59O1xuUkFGVGlja2VyLmluaXRpYWxpemUoKTtcbiIsImV4cG9ydCAqIGZyb20gXCIuL1JBRlRpY2tlci5qc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vUkFGVGlja2VyRXZlbnQuanNcIjtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///993\n')},638:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Ay: () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* unused harmony exports BooleanController, ColorController, Controller, FunctionController, GUI, NumberController, OptionController, StringController */\n/**\n * lil-gui\n * https://lil-gui.georgealways.com\n * @version 0.19.2\n * @author George Michael Brower\n * @license MIT\n */\n\n/**\n * Base class for all controllers.\n */\nclass Controller {\n\n\tconstructor( parent, object, property, className, elementType = 'div' ) {\n\n\t\t/**\n\t\t * The GUI that contains this controller.\n\t\t * @type {GUI}\n\t\t */\n\t\tthis.parent = parent;\n\n\t\t/**\n\t\t * The object this controller will modify.\n\t\t * @type {object}\n\t\t */\n\t\tthis.object = object;\n\n\t\t/**\n\t\t * The name of the property to control.\n\t\t * @type {string}\n\t\t */\n\t\tthis.property = property;\n\n\t\t/**\n\t\t * Used to determine if the controller is disabled.\n\t\t * Use `controller.disable( true|false )` to modify this value.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._disabled = false;\n\n\t\t/**\n\t\t * Used to determine if the Controller is hidden.\n\t\t * Use `controller.show()` or `controller.hide()` to change this.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._hidden = false;\n\n\t\t/**\n\t\t * The value of `object[ property ]` when the controller was created.\n\t\t * @type {any}\n\t\t */\n\t\tthis.initialValue = this.getValue();\n\n\t\t/**\n\t\t * The outermost container DOM element for this controller.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.domElement = document.createElement( elementType );\n\t\tthis.domElement.classList.add( 'controller' );\n\t\tthis.domElement.classList.add( className );\n\n\t\t/**\n\t\t * The DOM element that contains the controller's name.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$name = document.createElement( 'div' );\n\t\tthis.$name.classList.add( 'name' );\n\n\t\tController.nextNameID = Controller.nextNameID || 0;\n\t\tthis.$name.id = `lil-gui-name-${++Controller.nextNameID}`;\n\n\t\t/**\n\t\t * The DOM element that contains the controller's \"widget\" (which differs by controller type).\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$widget = document.createElement( 'div' );\n\t\tthis.$widget.classList.add( 'widget' );\n\n\t\t/**\n\t\t * The DOM element that receives the disabled attribute when using disable().\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$disable = this.$widget;\n\n\t\tthis.domElement.appendChild( this.$name );\n\t\tthis.domElement.appendChild( this.$widget );\n\n\t\t// Don't fire global key events while typing in a controller\n\t\tthis.domElement.addEventListener( 'keydown', e => e.stopPropagation() );\n\t\tthis.domElement.addEventListener( 'keyup', e => e.stopPropagation() );\n\n\t\tthis.parent.children.push( this );\n\t\tthis.parent.controllers.push( this );\n\n\t\tthis.parent.$children.appendChild( this.domElement );\n\n\t\tthis._listenCallback = this._listenCallback.bind( this );\n\n\t\tthis.name( property );\n\n\t}\n\n\t/**\n\t * Sets the name of the controller and its label in the GUI.\n\t * @param {string} name\n\t * @returns {this}\n\t */\n\tname( name ) {\n\t\t/**\n\t\t * The controller's name. Use `controller.name( 'Name' )` to modify this value.\n\t\t * @type {string}\n\t\t */\n\t\tthis._name = name;\n\t\tthis.$name.textContent = name;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Pass a function to be called whenever the value is modified by this controller.\n\t * The function receives the new value as its first parameter. The value of `this` will be the\n\t * controller.\n\t *\n\t * For function controllers, the `onChange` callback will be fired on click, after the function\n\t * executes.\n\t * @param {Function} callback\n\t * @returns {this}\n\t * @example\n\t * const controller = gui.add( object, 'property' );\n\t *\n\t * controller.onChange( function( v ) {\n\t * \tconsole.log( 'The value is now ' + v );\n\t * \tconsole.assert( this === controller );\n\t * } );\n\t */\n\tonChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onChange` events. Don't modify this value directly.\n\t\t * Use the `controller.onChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onChange = callback;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Calls the onChange methods of this controller and its parent GUI.\n\t * @protected\n\t */\n\t_callOnChange() {\n\n\t\tthis.parent._callOnChange( this );\n\n\t\tif ( this._onChange !== undefined ) {\n\t\t\tthis._onChange.call( this, this.getValue() );\n\t\t}\n\n\t\tthis._changed = true;\n\n\t}\n\n\t/**\n\t * Pass a function to be called after this controller has been modified and loses focus.\n\t * @param {Function} callback\n\t * @returns {this}\n\t * @example\n\t * const controller = gui.add( object, 'property' );\n\t *\n\t * controller.onFinishChange( function( v ) {\n\t * \tconsole.log( 'Changes complete: ' + v );\n\t * \tconsole.assert( this === controller );\n\t * } );\n\t */\n\tonFinishChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onFinishChange` events. Don't modify this value\n\t\t * directly. Use the `controller.onFinishChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onFinishChange = callback;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Should be called by Controller when its widgets lose focus.\n\t * @protected\n\t */\n\t_callOnFinishChange() {\n\n\t\tif ( this._changed ) {\n\n\t\t\tthis.parent._callOnFinishChange( this );\n\n\t\t\tif ( this._onFinishChange !== undefined ) {\n\t\t\t\tthis._onFinishChange.call( this, this.getValue() );\n\t\t\t}\n\n\t\t}\n\n\t\tthis._changed = false;\n\n\t}\n\n\t/**\n\t * Sets the controller back to its initial value.\n\t * @returns {this}\n\t */\n\treset() {\n\t\tthis.setValue( this.initialValue );\n\t\tthis._callOnFinishChange();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Enables this controller.\n\t * @param {boolean} enabled\n\t * @returns {this}\n\t * @example\n\t * controller.enable();\n\t * controller.enable( false ); // disable\n\t * controller.enable( controller._disabled ); // toggle\n\t */\n\tenable( enabled = true ) {\n\t\treturn this.disable( !enabled );\n\t}\n\n\t/**\n\t * Disables this controller.\n\t * @param {boolean} disabled\n\t * @returns {this}\n\t * @example\n\t * controller.disable();\n\t * controller.disable( false ); // enable\n\t * controller.disable( !controller._disabled ); // toggle\n\t */\n\tdisable( disabled = true ) {\n\n\t\tif ( disabled === this._disabled ) return this;\n\n\t\tthis._disabled = disabled;\n\n\t\tthis.domElement.classList.toggle( 'disabled', disabled );\n\t\tthis.$disable.toggleAttribute( 'disabled', disabled );\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Shows the Controller after it's been hidden.\n\t * @param {boolean} show\n\t * @returns {this}\n\t * @example\n\t * controller.show();\n\t * controller.show( false ); // hide\n\t * controller.show( controller._hidden ); // toggle\n\t */\n\tshow( show = true ) {\n\n\t\tthis._hidden = !show;\n\n\t\tthis.domElement.style.display = this._hidden ? 'none' : '';\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Hides the Controller.\n\t * @returns {this}\n\t */\n\thide() {\n\t\treturn this.show( false );\n\t}\n\n\t/**\n\t * Changes this controller into a dropdown of options.\n\t *\n\t * Calling this method on an option controller will simply update the options. However, if this\n\t * controller was not already an option controller, old references to this controller are\n\t * destroyed, and a new controller is added to the end of the GUI.\n\t * @example\n\t * // safe usage\n\t *\n\t * gui.add( obj, 'prop1' ).options( [ 'a', 'b', 'c' ] );\n\t * gui.add( obj, 'prop2' ).options( { Big: 10, Small: 1 } );\n\t * gui.add( obj, 'prop3' );\n\t *\n\t * // danger\n\t *\n\t * const ctrl1 = gui.add( obj, 'prop1' );\n\t * gui.add( obj, 'prop2' );\n\t *\n\t * // calling options out of order adds a new controller to the end...\n\t * const ctrl2 = ctrl1.options( [ 'a', 'b', 'c' ] );\n\t *\n\t * // ...and ctrl1 now references a controller that doesn't exist\n\t * assert( ctrl2 !== ctrl1 )\n\t * @param {object|Array} options\n\t * @returns {Controller}\n\t */\n\toptions( options ) {\n\t\tconst controller = this.parent.add( this.object, this.property, options );\n\t\tcontroller.name( this._name );\n\t\tthis.destroy();\n\t\treturn controller;\n\t}\n\n\t/**\n\t * Sets the minimum value. Only works on number controllers.\n\t * @param {number} min\n\t * @returns {this}\n\t */\n\tmin( min ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the maximum value. Only works on number controllers.\n\t * @param {number} max\n\t * @returns {this}\n\t */\n\tmax( max ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Values set by this controller will be rounded to multiples of `step`. Only works on number\n\t * controllers.\n\t * @param {number} step\n\t * @returns {this}\n\t */\n\tstep( step ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Rounds the displayed value to a fixed number of decimals, without affecting the actual value\n\t * like `step()`. Only works on number controllers.\n\t * @example\n\t * gui.add( object, 'property' ).listen().decimals( 4 );\n\t * @param {number} decimals\n\t * @returns {this}\n\t */\n\tdecimals( decimals ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Calls `updateDisplay()` every animation frame. Pass `false` to stop listening.\n\t * @param {boolean} listen\n\t * @returns {this}\n\t */\n\tlisten( listen = true ) {\n\n\t\t/**\n\t\t * Used to determine if the controller is currently listening. Don't modify this value\n\t\t * directly. Use the `controller.listen( true|false )` method instead.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._listening = listen;\n\n\t\tif ( this._listenCallbackID !== undefined ) {\n\t\t\tcancelAnimationFrame( this._listenCallbackID );\n\t\t\tthis._listenCallbackID = undefined;\n\t\t}\n\n\t\tif ( this._listening ) {\n\t\t\tthis._listenCallback();\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t_listenCallback() {\n\n\t\tthis._listenCallbackID = requestAnimationFrame( this._listenCallback );\n\n\t\t// To prevent framerate loss, make sure the value has changed before updating the display.\n\t\t// Note: save() is used here instead of getValue() only because of ColorController. The !== operator\n\t\t// won't work for color objects or arrays, but ColorController.save() always returns a string.\n\n\t\tconst curValue = this.save();\n\n\t\tif ( curValue !== this._listenPrevValue ) {\n\t\t\tthis.updateDisplay();\n\t\t}\n\n\t\tthis._listenPrevValue = curValue;\n\n\t}\n\n\t/**\n\t * Returns `object[ property ]`.\n\t * @returns {any}\n\t */\n\tgetValue() {\n\t\treturn this.object[ this.property ];\n\t}\n\n\t/**\n\t * Sets the value of `object[ property ]`, invokes any `onChange` handlers and updates the display.\n\t * @param {any} value\n\t * @returns {this}\n\t */\n\tsetValue( value ) {\n\n\t\tif ( this.getValue() !== value ) {\n\n\t\t\tthis.object[ this.property ] = value;\n\t\t\tthis._callOnChange();\n\t\t\tthis.updateDisplay();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Updates the display to keep it in sync with the current value. Useful for updating your\n\t * controllers when their values have been modified outside of the GUI.\n\t * @returns {this}\n\t */\n\tupdateDisplay() {\n\t\treturn this;\n\t}\n\n\tload( value ) {\n\t\tthis.setValue( value );\n\t\tthis._callOnFinishChange();\n\t\treturn this;\n\t}\n\n\tsave() {\n\t\treturn this.getValue();\n\t}\n\n\t/**\n\t * Destroys this controller and removes it from the parent GUI.\n\t */\n\tdestroy() {\n\t\tthis.listen( false );\n\t\tthis.parent.children.splice( this.parent.children.indexOf( this ), 1 );\n\t\tthis.parent.controllers.splice( this.parent.controllers.indexOf( this ), 1 );\n\t\tthis.parent.$children.removeChild( this.domElement );\n\t}\n\n}\n\nclass BooleanController extends Controller {\n\n\tconstructor( parent, object, property ) {\n\n\t\tsuper( parent, object, property, 'boolean', 'label' );\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'checkbox' );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$widget.appendChild( this.$input );\n\n\t\tthis.$input.addEventListener( 'change', () => {\n\t\t\tthis.setValue( this.$input.checked );\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$disable = this.$input;\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\tupdateDisplay() {\n\t\tthis.$input.checked = this.getValue();\n\t\treturn this;\n\t}\n\n}\n\nfunction normalizeColorString( string ) {\n\n\tlet match, result;\n\n\tif ( match = string.match( /(#|0x)?([a-f0-9]{6})/i ) ) {\n\n\t\tresult = match[ 2 ];\n\n\t} else if ( match = string.match( /rgb\\(\\s*(\\d*)\\s*,\\s*(\\d*)\\s*,\\s*(\\d*)\\s*\\)/ ) ) {\n\n\t\tresult = parseInt( match[ 1 ] ).toString( 16 ).padStart( 2, 0 )\n\t\t\t+ parseInt( match[ 2 ] ).toString( 16 ).padStart( 2, 0 )\n\t\t\t+ parseInt( match[ 3 ] ).toString( 16 ).padStart( 2, 0 );\n\n\t} else if ( match = string.match( /^#?([a-f0-9])([a-f0-9])([a-f0-9])$/i ) ) {\n\n\t\tresult = match[ 1 ] + match[ 1 ] + match[ 2 ] + match[ 2 ] + match[ 3 ] + match[ 3 ];\n\n\t}\n\n\tif ( result ) {\n\t\treturn '#' + result;\n\t}\n\n\treturn false;\n\n}\n\nconst STRING = {\n\tisPrimitive: true,\n\tmatch: v => typeof v === 'string',\n\tfromHexString: normalizeColorString,\n\ttoHexString: normalizeColorString\n};\n\nconst INT = {\n\tisPrimitive: true,\n\tmatch: v => typeof v === 'number',\n\tfromHexString: string => parseInt( string.substring( 1 ), 16 ),\n\ttoHexString: value => '#' + value.toString( 16 ).padStart( 6, 0 )\n};\n\nconst ARRAY = {\n\tisPrimitive: false,\n\n\t// The arrow function is here to appease tree shakers like esbuild or webpack.\n\t// See https://esbuild.github.io/api/#tree-shaking\n\tmatch: v => Array.isArray( v ),\n\n\tfromHexString( string, target, rgbScale = 1 ) {\n\n\t\tconst int = INT.fromHexString( string );\n\n\t\ttarget[ 0 ] = ( int >> 16 & 255 ) / 255 * rgbScale;\n\t\ttarget[ 1 ] = ( int >> 8 & 255 ) / 255 * rgbScale;\n\t\ttarget[ 2 ] = ( int & 255 ) / 255 * rgbScale;\n\n\t},\n\ttoHexString( [ r, g, b ], rgbScale = 1 ) {\n\n\t\trgbScale = 255 / rgbScale;\n\n\t\tconst int = ( r * rgbScale ) << 16 ^\n\t\t\t( g * rgbScale ) << 8 ^\n\t\t\t( b * rgbScale ) << 0;\n\n\t\treturn INT.toHexString( int );\n\n\t}\n};\n\nconst OBJECT = {\n\tisPrimitive: false,\n\tmatch: v => Object( v ) === v,\n\tfromHexString( string, target, rgbScale = 1 ) {\n\n\t\tconst int = INT.fromHexString( string );\n\n\t\ttarget.r = ( int >> 16 & 255 ) / 255 * rgbScale;\n\t\ttarget.g = ( int >> 8 & 255 ) / 255 * rgbScale;\n\t\ttarget.b = ( int & 255 ) / 255 * rgbScale;\n\n\t},\n\ttoHexString( { r, g, b }, rgbScale = 1 ) {\n\n\t\trgbScale = 255 / rgbScale;\n\n\t\tconst int = ( r * rgbScale ) << 16 ^\n\t\t\t( g * rgbScale ) << 8 ^\n\t\t\t( b * rgbScale ) << 0;\n\n\t\treturn INT.toHexString( int );\n\n\t}\n};\n\nconst FORMATS = [ STRING, INT, ARRAY, OBJECT ];\n\nfunction getColorFormat( value ) {\n\treturn FORMATS.find( format => format.match( value ) );\n}\n\nclass ColorController extends Controller {\n\n\tconstructor( parent, object, property, rgbScale ) {\n\n\t\tsuper( parent, object, property, 'color' );\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'color' );\n\t\tthis.$input.setAttribute( 'tabindex', -1 );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$text = document.createElement( 'input' );\n\t\tthis.$text.setAttribute( 'type', 'text' );\n\t\tthis.$text.setAttribute( 'spellcheck', 'false' );\n\t\tthis.$text.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$display = document.createElement( 'div' );\n\t\tthis.$display.classList.add( 'display' );\n\n\t\tthis.$display.appendChild( this.$input );\n\t\tthis.$widget.appendChild( this.$display );\n\t\tthis.$widget.appendChild( this.$text );\n\n\t\tthis._format = getColorFormat( this.initialValue );\n\t\tthis._rgbScale = rgbScale;\n\n\t\tthis._initialValueHexString = this.save();\n\t\tthis._textFocused = false;\n\n\t\tthis.$input.addEventListener( 'input', () => {\n\t\t\tthis._setValueFromHexString( this.$input.value );\n\t\t} );\n\n\t\tthis.$input.addEventListener( 'blur', () => {\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$text.addEventListener( 'input', () => {\n\t\t\tconst tryParse = normalizeColorString( this.$text.value );\n\t\t\tif ( tryParse ) {\n\t\t\t\tthis._setValueFromHexString( tryParse );\n\t\t\t}\n\t\t} );\n\n\t\tthis.$text.addEventListener( 'focus', () => {\n\t\t\tthis._textFocused = true;\n\t\t\tthis.$text.select();\n\t\t} );\n\n\t\tthis.$text.addEventListener( 'blur', () => {\n\t\t\tthis._textFocused = false;\n\t\t\tthis.updateDisplay();\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$disable = this.$text;\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\treset() {\n\t\tthis._setValueFromHexString( this._initialValueHexString );\n\t\treturn this;\n\t}\n\n\t_setValueFromHexString( value ) {\n\n\t\tif ( this._format.isPrimitive ) {\n\n\t\t\tconst newValue = this._format.fromHexString( value );\n\t\t\tthis.setValue( newValue );\n\n\t\t} else {\n\n\t\t\tthis._format.fromHexString( value, this.getValue(), this._rgbScale );\n\t\t\tthis._callOnChange();\n\t\t\tthis.updateDisplay();\n\n\t\t}\n\n\t}\n\n\tsave() {\n\t\treturn this._format.toHexString( this.getValue(), this._rgbScale );\n\t}\n\n\tload( value ) {\n\t\tthis._setValueFromHexString( value );\n\t\tthis._callOnFinishChange();\n\t\treturn this;\n\t}\n\n\tupdateDisplay() {\n\t\tthis.$input.value = this._format.toHexString( this.getValue(), this._rgbScale );\n\t\tif ( !this._textFocused ) {\n\t\t\tthis.$text.value = this.$input.value.substring( 1 );\n\t\t}\n\t\tthis.$display.style.backgroundColor = this.$input.value;\n\t\treturn this;\n\t}\n\n}\n\nclass FunctionController extends Controller {\n\n\tconstructor( parent, object, property ) {\n\n\t\tsuper( parent, object, property, 'function' );\n\n\t\t// Buttons are the only case where widget contains name\n\t\tthis.$button = document.createElement( 'button' );\n\t\tthis.$button.appendChild( this.$name );\n\t\tthis.$widget.appendChild( this.$button );\n\n\t\tthis.$button.addEventListener( 'click', e => {\n\t\t\te.preventDefault();\n\t\t\tthis.getValue().call( this.object );\n\t\t\tthis._callOnChange();\n\t\t} );\n\n\t\t// enables :active pseudo class on mobile\n\t\tthis.$button.addEventListener( 'touchstart', () => {}, { passive: true } );\n\n\t\tthis.$disable = this.$button;\n\n\t}\n\n}\n\nclass NumberController extends Controller {\n\n\tconstructor( parent, object, property, min, max, step ) {\n\n\t\tsuper( parent, object, property, 'number' );\n\n\t\tthis._initInput();\n\n\t\tthis.min( min );\n\t\tthis.max( max );\n\n\t\tconst stepExplicit = step !== undefined;\n\t\tthis.step( stepExplicit ? step : this._getImplicitStep(), stepExplicit );\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\tdecimals( decimals ) {\n\t\tthis._decimals = decimals;\n\t\tthis.updateDisplay();\n\t\treturn this;\n\t}\n\n\tmin( min ) {\n\t\tthis._min = min;\n\t\tthis._onUpdateMinMax();\n\t\treturn this;\n\t}\n\n\tmax( max ) {\n\t\tthis._max = max;\n\t\tthis._onUpdateMinMax();\n\t\treturn this;\n\t}\n\n\tstep( step, explicit = true ) {\n\t\tthis._step = step;\n\t\tthis._stepExplicit = explicit;\n\t\treturn this;\n\t}\n\n\tupdateDisplay() {\n\n\t\tconst value = this.getValue();\n\n\t\tif ( this._hasSlider ) {\n\n\t\t\tlet percent = ( value - this._min ) / ( this._max - this._min );\n\t\t\tpercent = Math.max( 0, Math.min( percent, 1 ) );\n\n\t\t\tthis.$fill.style.width = percent * 100 + '%';\n\n\t\t}\n\n\t\tif ( !this._inputFocused ) {\n\t\t\tthis.$input.value = this._decimals === undefined ? value : value.toFixed( this._decimals );\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t_initInput() {\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'text' );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\t// On touch devices only, use input[type=number] to force a numeric keyboard.\n\t\t// Ideally we could use one input type everywhere, but [type=number] has quirks\n\t\t// on desktop, and [inputmode=decimal] has quirks on iOS.\n\t\t// See https://github.com/georgealways/lil-gui/pull/16\n\n\t\tconst isTouch = window.matchMedia( '(pointer: coarse)' ).matches;\n\n\t\tif ( isTouch ) {\n\t\t\tthis.$input.setAttribute( 'type', 'number' );\n\t\t\tthis.$input.setAttribute( 'step', 'any' );\n\t\t}\n\n\t\tthis.$widget.appendChild( this.$input );\n\n\t\tthis.$disable = this.$input;\n\n\t\tconst onInput = () => {\n\n\t\t\tlet value = parseFloat( this.$input.value );\n\n\t\t\tif ( isNaN( value ) ) return;\n\n\t\t\tif ( this._stepExplicit ) {\n\t\t\t\tvalue = this._snap( value );\n\t\t\t}\n\n\t\t\tthis.setValue( this._clamp( value ) );\n\n\t\t};\n\n\t\t// Keys & mouse wheel\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst increment = delta => {\n\n\t\t\tconst value = parseFloat( this.$input.value );\n\n\t\t\tif ( isNaN( value ) ) return;\n\n\t\t\tthis._snapClampSetValue( value + delta );\n\n\t\t\t// Force the input to updateDisplay when it's focused\n\t\t\tthis.$input.value = this.getValue();\n\n\t\t};\n\n\t\tconst onKeyDown = e => {\n\t\t\t// Using `e.key` instead of `e.code` also catches NumpadEnter\n\t\t\tif ( e.key === 'Enter' ) {\n\t\t\t\tthis.$input.blur();\n\t\t\t}\n\t\t\tif ( e.code === 'ArrowUp' ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tincrement( this._step * this._arrowKeyMultiplier( e ) );\n\t\t\t}\n\t\t\tif ( e.code === 'ArrowDown' ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tincrement( this._step * this._arrowKeyMultiplier( e ) * -1 );\n\t\t\t}\n\t\t};\n\n\t\tconst onWheel = e => {\n\t\t\tif ( this._inputFocused ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tincrement( this._step * this._normalizeMouseWheel( e ) );\n\t\t\t}\n\t\t};\n\n\t\t// Vertical drag\n\t\t// ---------------------------------------------------------------------\n\n\t\tlet testingForVerticalDrag = false,\n\t\t\tinitClientX,\n\t\t\tinitClientY,\n\t\t\tprevClientY,\n\t\t\tinitValue,\n\t\t\tdragDelta;\n\n\t\t// Once the mouse is dragged more than DRAG_THRESH px on any axis, we decide\n\t\t// on the user's intent: horizontal means highlight, vertical means drag.\n\t\tconst DRAG_THRESH = 5;\n\n\t\tconst onMouseDown = e => {\n\n\t\t\tinitClientX = e.clientX;\n\t\t\tinitClientY = prevClientY = e.clientY;\n\t\t\ttestingForVerticalDrag = true;\n\n\t\t\tinitValue = this.getValue();\n\t\t\tdragDelta = 0;\n\n\t\t\twindow.addEventListener( 'mousemove', onMouseMove );\n\t\t\twindow.addEventListener( 'mouseup', onMouseUp );\n\n\t\t};\n\n\t\tconst onMouseMove = e => {\n\n\t\t\tif ( testingForVerticalDrag ) {\n\n\t\t\t\tconst dx = e.clientX - initClientX;\n\t\t\t\tconst dy = e.clientY - initClientY;\n\n\t\t\t\tif ( Math.abs( dy ) > DRAG_THRESH ) {\n\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tthis.$input.blur();\n\t\t\t\t\ttestingForVerticalDrag = false;\n\t\t\t\t\tthis._setDraggingStyle( true, 'vertical' );\n\n\t\t\t\t} else if ( Math.abs( dx ) > DRAG_THRESH ) {\n\n\t\t\t\t\tonMouseUp();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// This isn't an else so that the first move counts towards dragDelta\n\t\t\tif ( !testingForVerticalDrag ) {\n\n\t\t\t\tconst dy = e.clientY - prevClientY;\n\n\t\t\t\tdragDelta -= dy * this._step * this._arrowKeyMultiplier( e );\n\n\t\t\t\t// Clamp dragDelta so we don't have 'dead space' after dragging past bounds.\n\t\t\t\t// We're okay with the fact that bounds can be undefined here.\n\t\t\t\tif ( initValue + dragDelta > this._max ) {\n\t\t\t\t\tdragDelta = this._max - initValue;\n\t\t\t\t} else if ( initValue + dragDelta < this._min ) {\n\t\t\t\t\tdragDelta = this._min - initValue;\n\t\t\t\t}\n\n\t\t\t\tthis._snapClampSetValue( initValue + dragDelta );\n\n\t\t\t}\n\n\t\t\tprevClientY = e.clientY;\n\n\t\t};\n\n\t\tconst onMouseUp = () => {\n\t\t\tthis._setDraggingStyle( false, 'vertical' );\n\t\t\tthis._callOnFinishChange();\n\t\t\twindow.removeEventListener( 'mousemove', onMouseMove );\n\t\t\twindow.removeEventListener( 'mouseup', onMouseUp );\n\t\t};\n\n\t\t// Focus state & onFinishChange\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst onFocus = () => {\n\t\t\tthis._inputFocused = true;\n\t\t};\n\n\t\tconst onBlur = () => {\n\t\t\tthis._inputFocused = false;\n\t\t\tthis.updateDisplay();\n\t\t\tthis._callOnFinishChange();\n\t\t};\n\n\t\tthis.$input.addEventListener( 'input', onInput );\n\t\tthis.$input.addEventListener( 'keydown', onKeyDown );\n\t\tthis.$input.addEventListener( 'wheel', onWheel, { passive: false } );\n\t\tthis.$input.addEventListener( 'mousedown', onMouseDown );\n\t\tthis.$input.addEventListener( 'focus', onFocus );\n\t\tthis.$input.addEventListener( 'blur', onBlur );\n\n\t}\n\n\t_initSlider() {\n\n\t\tthis._hasSlider = true;\n\n\t\t// Build DOM\n\t\t// ---------------------------------------------------------------------\n\n\t\tthis.$slider = document.createElement( 'div' );\n\t\tthis.$slider.classList.add( 'slider' );\n\n\t\tthis.$fill = document.createElement( 'div' );\n\t\tthis.$fill.classList.add( 'fill' );\n\n\t\tthis.$slider.appendChild( this.$fill );\n\t\tthis.$widget.insertBefore( this.$slider, this.$input );\n\n\t\tthis.domElement.classList.add( 'hasSlider' );\n\n\t\t// Map clientX to value\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst map = ( v, a, b, c, d ) => {\n\t\t\treturn ( v - a ) / ( b - a ) * ( d - c ) + c;\n\t\t};\n\n\t\tconst setValueFromX = clientX => {\n\t\t\tconst rect = this.$slider.getBoundingClientRect();\n\t\t\tlet value = map( clientX, rect.left, rect.right, this._min, this._max );\n\t\t\tthis._snapClampSetValue( value );\n\t\t};\n\n\t\t// Mouse drag\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst mouseDown = e => {\n\t\t\tthis._setDraggingStyle( true );\n\t\t\tsetValueFromX( e.clientX );\n\t\t\twindow.addEventListener( 'mousemove', mouseMove );\n\t\t\twindow.addEventListener( 'mouseup', mouseUp );\n\t\t};\n\n\t\tconst mouseMove = e => {\n\t\t\tsetValueFromX( e.clientX );\n\t\t};\n\n\t\tconst mouseUp = () => {\n\t\t\tthis._callOnFinishChange();\n\t\t\tthis._setDraggingStyle( false );\n\t\t\twindow.removeEventListener( 'mousemove', mouseMove );\n\t\t\twindow.removeEventListener( 'mouseup', mouseUp );\n\t\t};\n\n\t\t// Touch drag\n\t\t// ---------------------------------------------------------------------\n\n\t\tlet testingForScroll = false, prevClientX, prevClientY;\n\n\t\tconst beginTouchDrag = e => {\n\t\t\te.preventDefault();\n\t\t\tthis._setDraggingStyle( true );\n\t\t\tsetValueFromX( e.touches[ 0 ].clientX );\n\t\t\ttestingForScroll = false;\n\t\t};\n\n\t\tconst onTouchStart = e => {\n\n\t\t\tif ( e.touches.length > 1 ) return;\n\n\t\t\t// If we're in a scrollable container, we should wait for the first\n\t\t\t// touchmove to see if the user is trying to slide or scroll.\n\t\t\tif ( this._hasScrollBar ) {\n\n\t\t\t\tprevClientX = e.touches[ 0 ].clientX;\n\t\t\t\tprevClientY = e.touches[ 0 ].clientY;\n\t\t\t\ttestingForScroll = true;\n\n\t\t\t} else {\n\n\t\t\t\t// Otherwise, we can set the value straight away on touchstart.\n\t\t\t\tbeginTouchDrag( e );\n\n\t\t\t}\n\n\t\t\twindow.addEventListener( 'touchmove', onTouchMove, { passive: false } );\n\t\t\twindow.addEventListener( 'touchend', onTouchEnd );\n\n\t\t};\n\n\t\tconst onTouchMove = e => {\n\n\t\t\tif ( testingForScroll ) {\n\n\t\t\t\tconst dx = e.touches[ 0 ].clientX - prevClientX;\n\t\t\t\tconst dy = e.touches[ 0 ].clientY - prevClientY;\n\n\t\t\t\tif ( Math.abs( dx ) > Math.abs( dy ) ) {\n\n\t\t\t\t\t// We moved horizontally, set the value and stop checking.\n\t\t\t\t\tbeginTouchDrag( e );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// This was, in fact, an attempt to scroll. Abort.\n\t\t\t\t\twindow.removeEventListener( 'touchmove', onTouchMove );\n\t\t\t\t\twindow.removeEventListener( 'touchend', onTouchEnd );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\te.preventDefault();\n\t\t\t\tsetValueFromX( e.touches[ 0 ].clientX );\n\n\t\t\t}\n\n\t\t};\n\n\t\tconst onTouchEnd = () => {\n\t\t\tthis._callOnFinishChange();\n\t\t\tthis._setDraggingStyle( false );\n\t\t\twindow.removeEventListener( 'touchmove', onTouchMove );\n\t\t\twindow.removeEventListener( 'touchend', onTouchEnd );\n\t\t};\n\n\t\t// Mouse wheel\n\t\t// ---------------------------------------------------------------------\n\n\t\t// We have to use a debounced function to call onFinishChange because\n\t\t// there's no way to tell when the user is \"done\" mouse-wheeling.\n\t\tconst callOnFinishChange = this._callOnFinishChange.bind( this );\n\t\tconst WHEEL_DEBOUNCE_TIME = 400;\n\t\tlet wheelFinishChangeTimeout;\n\n\t\tconst onWheel = e => {\n\n\t\t\t// ignore vertical wheels if there's a scrollbar\n\t\t\tconst isVertical = Math.abs( e.deltaX ) < Math.abs( e.deltaY );\n\t\t\tif ( isVertical && this._hasScrollBar ) return;\n\n\t\t\te.preventDefault();\n\n\t\t\t// set value\n\t\t\tconst delta = this._normalizeMouseWheel( e ) * this._step;\n\t\t\tthis._snapClampSetValue( this.getValue() + delta );\n\n\t\t\t// force the input to updateDisplay when it's focused\n\t\t\tthis.$input.value = this.getValue();\n\n\t\t\t// debounce onFinishChange\n\t\t\tclearTimeout( wheelFinishChangeTimeout );\n\t\t\twheelFinishChangeTimeout = setTimeout( callOnFinishChange, WHEEL_DEBOUNCE_TIME );\n\n\t\t};\n\n\t\tthis.$slider.addEventListener( 'mousedown', mouseDown );\n\t\tthis.$slider.addEventListener( 'touchstart', onTouchStart, { passive: false } );\n\t\tthis.$slider.addEventListener( 'wheel', onWheel, { passive: false } );\n\n\t}\n\n\t_setDraggingStyle( active, axis = 'horizontal' ) {\n\t\tif ( this.$slider ) {\n\t\t\tthis.$slider.classList.toggle( 'active', active );\n\t\t}\n\t\tdocument.body.classList.toggle( 'lil-gui-dragging', active );\n\t\tdocument.body.classList.toggle( `lil-gui-${axis}`, active );\n\t}\n\n\t_getImplicitStep() {\n\n\t\tif ( this._hasMin && this._hasMax ) {\n\t\t\treturn ( this._max - this._min ) / 1000;\n\t\t}\n\n\t\treturn 0.1;\n\n\t}\n\n\t_onUpdateMinMax() {\n\n\t\tif ( !this._hasSlider && this._hasMin && this._hasMax ) {\n\n\t\t\t// If this is the first time we're hearing about min and max\n\t\t\t// and we haven't explicitly stated what our step is, let's\n\t\t\t// update that too.\n\t\t\tif ( !this._stepExplicit ) {\n\t\t\t\tthis.step( this._getImplicitStep(), false );\n\t\t\t}\n\n\t\t\tthis._initSlider();\n\t\t\tthis.updateDisplay();\n\n\t\t}\n\n\t}\n\n\t_normalizeMouseWheel( e ) {\n\n\t\tlet { deltaX, deltaY } = e;\n\n\t\t// Safari and Chrome report weird non-integral values for a notched wheel,\n\t\t// but still expose actual lines scrolled via wheelDelta. Notched wheels\n\t\t// should behave the same way as arrow keys.\n\t\tif ( Math.floor( e.deltaY ) !== e.deltaY && e.wheelDelta ) {\n\t\t\tdeltaX = 0;\n\t\t\tdeltaY = -e.wheelDelta / 120;\n\t\t\tdeltaY *= this._stepExplicit ? 1 : 10;\n\t\t}\n\n\t\tconst wheel = deltaX + -deltaY;\n\n\t\treturn wheel;\n\n\t}\n\n\t_arrowKeyMultiplier( e ) {\n\n\t\tlet mult = this._stepExplicit ? 1 : 10;\n\n\t\tif ( e.shiftKey ) {\n\t\t\tmult *= 10;\n\t\t} else if ( e.altKey ) {\n\t\t\tmult /= 10;\n\t\t}\n\n\t\treturn mult;\n\n\t}\n\n\t_snap( value ) {\n\n\t\t// This would be the logical way to do things, but floating point errors.\n\t\t// return Math.round( value / this._step ) * this._step;\n\n\t\t// Using inverse step solves a lot of them, but not all\n\t\t// const inverseStep = 1 / this._step;\n\t\t// return Math.round( value * inverseStep ) / inverseStep;\n\n\t\t// Not happy about this, but haven't seen it break.\n\t\tconst r = Math.round( value / this._step ) * this._step;\n\t\treturn parseFloat( r.toPrecision( 15 ) );\n\n\t}\n\n\t_clamp( value ) {\n\t\t// either condition is false if min or max is undefined\n\t\tif ( value < this._min ) value = this._min;\n\t\tif ( value > this._max ) value = this._max;\n\t\treturn value;\n\t}\n\n\t_snapClampSetValue( value ) {\n\t\tthis.setValue( this._clamp( this._snap( value ) ) );\n\t}\n\n\tget _hasScrollBar() {\n\t\tconst root = this.parent.root.$children;\n\t\treturn root.scrollHeight > root.clientHeight;\n\t}\n\n\tget _hasMin() {\n\t\treturn this._min !== undefined;\n\t}\n\n\tget _hasMax() {\n\t\treturn this._max !== undefined;\n\t}\n\n}\n\nclass OptionController extends Controller {\n\n\tconstructor( parent, object, property, options ) {\n\n\t\tsuper( parent, object, property, 'option' );\n\n\t\tthis.$select = document.createElement( 'select' );\n\t\tthis.$select.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$display = document.createElement( 'div' );\n\t\tthis.$display.classList.add( 'display' );\n\n\t\tthis.$select.addEventListener( 'change', () => {\n\t\t\tthis.setValue( this._values[ this.$select.selectedIndex ] );\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$select.addEventListener( 'focus', () => {\n\t\t\tthis.$display.classList.add( 'focus' );\n\t\t} );\n\n\t\tthis.$select.addEventListener( 'blur', () => {\n\t\t\tthis.$display.classList.remove( 'focus' );\n\t\t} );\n\n\t\tthis.$widget.appendChild( this.$select );\n\t\tthis.$widget.appendChild( this.$display );\n\n\t\tthis.$disable = this.$select;\n\n\t\tthis.options( options );\n\n\t}\n\n\toptions( options ) {\n\n\t\tthis._values = Array.isArray( options ) ? options : Object.values( options );\n\t\tthis._names = Array.isArray( options ) ? options : Object.keys( options );\n\n\t\tthis.$select.replaceChildren();\n\n\t\tthis._names.forEach( name => {\n\t\t\tconst $option = document.createElement( 'option' );\n\t\t\t$option.textContent = name;\n\t\t\tthis.$select.appendChild( $option );\n\t\t} );\n\n\t\tthis.updateDisplay();\n\n\t\treturn this;\n\n\t}\n\n\tupdateDisplay() {\n\t\tconst value = this.getValue();\n\t\tconst index = this._values.indexOf( value );\n\t\tthis.$select.selectedIndex = index;\n\t\tthis.$display.textContent = index === -1 ? value : this._names[ index ];\n\t\treturn this;\n\t}\n\n}\n\nclass StringController extends Controller {\n\n\tconstructor( parent, object, property ) {\n\n\t\tsuper( parent, object, property, 'string' );\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'text' );\n\t\tthis.$input.setAttribute( 'spellcheck', 'false' );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$input.addEventListener( 'input', () => {\n\t\t\tthis.setValue( this.$input.value );\n\t\t} );\n\n\t\tthis.$input.addEventListener( 'keydown', e => {\n\t\t\tif ( e.code === 'Enter' ) {\n\t\t\t\tthis.$input.blur();\n\t\t\t}\n\t\t} );\n\n\t\tthis.$input.addEventListener( 'blur', () => {\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$widget.appendChild( this.$input );\n\n\t\tthis.$disable = this.$input;\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\tupdateDisplay() {\n\t\tthis.$input.value = this.getValue();\n\t\treturn this;\n\t}\n\n}\n\nconst stylesheet = `.lil-gui {\n font-family: var(--font-family);\n font-size: var(--font-size);\n line-height: 1;\n font-weight: normal;\n font-style: normal;\n text-align: left;\n color: var(--text-color);\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n --background-color: #1f1f1f;\n --text-color: #ebebeb;\n --title-background-color: #111111;\n --title-text-color: #ebebeb;\n --widget-color: #424242;\n --hover-color: #4f4f4f;\n --focus-color: #595959;\n --number-color: #2cc9ff;\n --string-color: #a2db3c;\n --font-size: 11px;\n --input-font-size: 11px;\n --font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Arial, sans-serif;\n --font-family-mono: Menlo, Monaco, Consolas, \"Droid Sans Mono\", monospace;\n --padding: 4px;\n --spacing: 4px;\n --widget-height: 20px;\n --title-height: calc(var(--widget-height) + var(--spacing) * 1.25);\n --name-width: 45%;\n --slider-knob-width: 2px;\n --slider-input-width: 27%;\n --color-input-width: 27%;\n --slider-input-min-width: 45px;\n --color-input-min-width: 45px;\n --folder-indent: 7px;\n --widget-padding: 0 0 0 3px;\n --widget-border-radius: 2px;\n --checkbox-size: calc(0.75 * var(--widget-height));\n --scrollbar-width: 5px;\n}\n.lil-gui, .lil-gui * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n.lil-gui.root {\n width: var(--width, 245px);\n display: flex;\n flex-direction: column;\n background: var(--background-color);\n}\n.lil-gui.root > .title {\n background: var(--title-background-color);\n color: var(--title-text-color);\n}\n.lil-gui.root > .children {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.lil-gui.root > .children::-webkit-scrollbar {\n width: var(--scrollbar-width);\n height: var(--scrollbar-width);\n background: var(--background-color);\n}\n.lil-gui.root > .children::-webkit-scrollbar-thumb {\n border-radius: var(--scrollbar-width);\n background: var(--focus-color);\n}\n@media (pointer: coarse) {\n .lil-gui.allow-touch-styles, .lil-gui.allow-touch-styles .lil-gui {\n --widget-height: 28px;\n --padding: 6px;\n --spacing: 6px;\n --font-size: 13px;\n --input-font-size: 16px;\n --folder-indent: 10px;\n --scrollbar-width: 7px;\n --slider-input-min-width: 50px;\n --color-input-min-width: 65px;\n }\n}\n.lil-gui.force-touch-styles, .lil-gui.force-touch-styles .lil-gui {\n --widget-height: 28px;\n --padding: 6px;\n --spacing: 6px;\n --font-size: 13px;\n --input-font-size: 16px;\n --folder-indent: 10px;\n --scrollbar-width: 7px;\n --slider-input-min-width: 50px;\n --color-input-min-width: 65px;\n}\n.lil-gui.autoPlace {\n max-height: 100%;\n position: fixed;\n top: 0;\n right: 15px;\n z-index: 1001;\n}\n\n.lil-gui .controller {\n display: flex;\n align-items: center;\n padding: 0 var(--padding);\n margin: var(--spacing) 0;\n}\n.lil-gui .controller.disabled {\n opacity: 0.5;\n}\n.lil-gui .controller.disabled, .lil-gui .controller.disabled * {\n pointer-events: none !important;\n}\n.lil-gui .controller > .name {\n min-width: var(--name-width);\n flex-shrink: 0;\n white-space: pre;\n padding-right: var(--spacing);\n line-height: var(--widget-height);\n}\n.lil-gui .controller .widget {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-height: var(--widget-height);\n}\n.lil-gui .controller.string input {\n color: var(--string-color);\n}\n.lil-gui .controller.boolean {\n cursor: pointer;\n}\n.lil-gui .controller.color .display {\n width: 100%;\n height: var(--widget-height);\n border-radius: var(--widget-border-radius);\n position: relative;\n}\n@media (hover: hover) {\n .lil-gui .controller.color .display:hover:before {\n content: \" \";\n display: block;\n position: absolute;\n border-radius: var(--widget-border-radius);\n border: 1px solid #fff9;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n}\n.lil-gui .controller.color input[type=color] {\n opacity: 0;\n width: 100%;\n height: 100%;\n cursor: pointer;\n}\n.lil-gui .controller.color input[type=text] {\n margin-left: var(--spacing);\n font-family: var(--font-family-mono);\n min-width: var(--color-input-min-width);\n width: var(--color-input-width);\n flex-shrink: 0;\n}\n.lil-gui .controller.option select {\n opacity: 0;\n position: absolute;\n width: 100%;\n max-width: 100%;\n}\n.lil-gui .controller.option .display {\n position: relative;\n pointer-events: none;\n border-radius: var(--widget-border-radius);\n height: var(--widget-height);\n line-height: var(--widget-height);\n max-width: 100%;\n overflow: hidden;\n word-break: break-all;\n padding-left: 0.55em;\n padding-right: 1.75em;\n background: var(--widget-color);\n}\n@media (hover: hover) {\n .lil-gui .controller.option .display.focus {\n background: var(--focus-color);\n }\n}\n.lil-gui .controller.option .display.active {\n background: var(--focus-color);\n}\n.lil-gui .controller.option .display:after {\n font-family: \"lil-gui\";\n content: \"↕\";\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n padding-right: 0.375em;\n}\n.lil-gui .controller.option .widget,\n.lil-gui .controller.option select {\n cursor: pointer;\n}\n@media (hover: hover) {\n .lil-gui .controller.option .widget:hover .display {\n background: var(--hover-color);\n }\n}\n.lil-gui .controller.number input {\n color: var(--number-color);\n}\n.lil-gui .controller.number.hasSlider input {\n margin-left: var(--spacing);\n width: var(--slider-input-width);\n min-width: var(--slider-input-min-width);\n flex-shrink: 0;\n}\n.lil-gui .controller.number .slider {\n width: 100%;\n height: var(--widget-height);\n background: var(--widget-color);\n border-radius: var(--widget-border-radius);\n padding-right: var(--slider-knob-width);\n overflow: hidden;\n cursor: ew-resize;\n touch-action: pan-y;\n}\n@media (hover: hover) {\n .lil-gui .controller.number .slider:hover {\n background: var(--hover-color);\n }\n}\n.lil-gui .controller.number .slider.active {\n background: var(--focus-color);\n}\n.lil-gui .controller.number .slider.active .fill {\n opacity: 0.95;\n}\n.lil-gui .controller.number .fill {\n height: 100%;\n border-right: var(--slider-knob-width) solid var(--number-color);\n box-sizing: content-box;\n}\n\n.lil-gui-dragging .lil-gui {\n --hover-color: var(--widget-color);\n}\n.lil-gui-dragging * {\n cursor: ew-resize !important;\n}\n\n.lil-gui-dragging.lil-gui-vertical * {\n cursor: ns-resize !important;\n}\n\n.lil-gui .title {\n height: var(--title-height);\n line-height: calc(var(--title-height) - 4px);\n font-weight: 600;\n padding: 0 var(--padding);\n -webkit-tap-highlight-color: transparent;\n cursor: pointer;\n outline: none;\n text-decoration-skip: objects;\n}\n.lil-gui .title:before {\n font-family: \"lil-gui\";\n content: \"▾\";\n padding-right: 2px;\n display: inline-block;\n}\n.lil-gui .title:active {\n background: var(--title-background-color);\n opacity: 0.75;\n}\n@media (hover: hover) {\n body:not(.lil-gui-dragging) .lil-gui .title:hover {\n background: var(--title-background-color);\n opacity: 0.85;\n }\n .lil-gui .title:focus {\n text-decoration: underline var(--focus-color);\n }\n}\n.lil-gui.root > .title:focus {\n text-decoration: none !important;\n}\n.lil-gui.closed > .title:before {\n content: \"▸\";\n}\n.lil-gui.closed > .children {\n transform: translateY(-7px);\n opacity: 0;\n}\n.lil-gui.closed:not(.transition) > .children {\n display: none;\n}\n.lil-gui.transition > .children {\n transition-duration: 300ms;\n transition-property: height, opacity, transform;\n transition-timing-function: cubic-bezier(0.2, 0.6, 0.35, 1);\n overflow: hidden;\n pointer-events: none;\n}\n.lil-gui .children:empty:before {\n content: \"Empty\";\n padding: 0 var(--padding);\n margin: var(--spacing) 0;\n display: block;\n height: var(--widget-height);\n font-style: italic;\n line-height: var(--widget-height);\n opacity: 0.5;\n}\n.lil-gui.root > .children > .lil-gui > .title {\n border: 0 solid var(--widget-color);\n border-width: 1px 0;\n transition: border-color 300ms;\n}\n.lil-gui.root > .children > .lil-gui.closed > .title {\n border-bottom-color: transparent;\n}\n.lil-gui + .controller {\n border-top: 1px solid var(--widget-color);\n margin-top: 0;\n padding-top: var(--spacing);\n}\n.lil-gui .lil-gui .lil-gui > .title {\n border: none;\n}\n.lil-gui .lil-gui .lil-gui > .children {\n border: none;\n margin-left: var(--folder-indent);\n border-left: 2px solid var(--widget-color);\n}\n.lil-gui .lil-gui .controller {\n border: none;\n}\n\n.lil-gui label, .lil-gui input, .lil-gui button {\n -webkit-tap-highlight-color: transparent;\n}\n.lil-gui input {\n border: 0;\n outline: none;\n font-family: var(--font-family);\n font-size: var(--input-font-size);\n border-radius: var(--widget-border-radius);\n height: var(--widget-height);\n background: var(--widget-color);\n color: var(--text-color);\n width: 100%;\n}\n@media (hover: hover) {\n .lil-gui input:hover {\n background: var(--hover-color);\n }\n .lil-gui input:active {\n background: var(--focus-color);\n }\n}\n.lil-gui input:disabled {\n opacity: 1;\n}\n.lil-gui input[type=text],\n.lil-gui input[type=number] {\n padding: var(--widget-padding);\n -moz-appearance: textfield;\n}\n.lil-gui input[type=text]:focus,\n.lil-gui input[type=number]:focus {\n background: var(--focus-color);\n}\n.lil-gui input[type=checkbox] {\n appearance: none;\n width: var(--checkbox-size);\n height: var(--checkbox-size);\n border-radius: var(--widget-border-radius);\n text-align: center;\n cursor: pointer;\n}\n.lil-gui input[type=checkbox]:checked:before {\n font-family: \"lil-gui\";\n content: \"✓\";\n font-size: var(--checkbox-size);\n line-height: var(--checkbox-size);\n}\n@media (hover: hover) {\n .lil-gui input[type=checkbox]:focus {\n box-shadow: inset 0 0 0 1px var(--focus-color);\n }\n}\n.lil-gui button {\n outline: none;\n cursor: pointer;\n font-family: var(--font-family);\n font-size: var(--font-size);\n color: var(--text-color);\n width: 100%;\n height: var(--widget-height);\n text-transform: none;\n background: var(--widget-color);\n border-radius: var(--widget-border-radius);\n border: none;\n}\n@media (hover: hover) {\n .lil-gui button:hover {\n background: var(--hover-color);\n }\n .lil-gui button:focus {\n box-shadow: inset 0 0 0 1px var(--focus-color);\n }\n}\n.lil-gui button:active {\n background: var(--focus-color);\n}\n\n@font-face {\n font-family: \"lil-gui\";\n src: url(\"data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAUsAAsAAAAACJwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAAH4AAADAImwmYE9TLzIAAAGIAAAAPwAAAGBKqH5SY21hcAAAAcgAAAD0AAACrukyyJBnbHlmAAACvAAAAF8AAACEIZpWH2hlYWQAAAMcAAAAJwAAADZfcj2zaGhlYQAAA0QAAAAYAAAAJAC5AHhobXR4AAADXAAAABAAAABMAZAAAGxvY2EAAANsAAAAFAAAACgCEgIybWF4cAAAA4AAAAAeAAAAIAEfABJuYW1lAAADoAAAASIAAAIK9SUU/XBvc3QAAATEAAAAZgAAAJCTcMc2eJxVjbEOgjAURU+hFRBK1dGRL+ALnAiToyMLEzFpnPz/eAshwSa97517c/MwwJmeB9kwPl+0cf5+uGPZXsqPu4nvZabcSZldZ6kfyWnomFY/eScKqZNWupKJO6kXN3K9uCVoL7iInPr1X5baXs3tjuMqCtzEuagm/AAlzQgPAAB4nGNgYRBlnMDAysDAYM/gBiT5oLQBAwuDJAMDEwMrMwNWEJDmmsJwgCFeXZghBcjlZMgFCzOiKOIFAB71Bb8AeJy1kjFuwkAQRZ+DwRAwBtNQRUGKQ8OdKCAWUhAgKLhIuAsVSpWz5Bbkj3dEgYiUIszqWdpZe+Z7/wB1oCYmIoboiwiLT2WjKl/jscrHfGg/pKdMkyklC5Zs2LEfHYpjcRoPzme9MWWmk3dWbK9ObkWkikOetJ554fWyoEsmdSlt+uR0pCJR34b6t/TVg1SY3sYvdf8vuiKrpyaDXDISiegp17p7579Gp3p++y7HPAiY9pmTibljrr85qSidtlg4+l25GLCaS8e6rRxNBmsnERunKbaOObRz7N72ju5vdAjYpBXHgJylOAVsMseDAPEP8LYoUHicY2BiAAEfhiAGJgZWBgZ7RnFRdnVJELCQlBSRlATJMoLV2DK4glSYs6ubq5vbKrJLSbGrgEmovDuDJVhe3VzcXFwNLCOILB/C4IuQ1xTn5FPilBTj5FPmBAB4WwoqAHicY2BkYGAA4sk1sR/j+W2+MnAzpDBgAyEMQUCSg4EJxAEAwUgFHgB4nGNgZGBgSGFggJMhDIwMqEAYAByHATJ4nGNgAIIUNEwmAABl3AGReJxjYAACIQYlBiMGJ3wQAEcQBEV4nGNgZGBgEGZgY2BiAAEQyQWEDAz/wXwGAAsPATIAAHicXdBNSsNAHAXwl35iA0UQXYnMShfS9GPZA7T7LgIu03SSpkwzYTIt1BN4Ak/gKTyAeCxfw39jZkjymzcvAwmAW/wgwHUEGDb36+jQQ3GXGot79L24jxCP4gHzF/EIr4jEIe7wxhOC3g2TMYy4Q7+Lu/SHuEd/ivt4wJd4wPxbPEKMX3GI5+DJFGaSn4qNzk8mcbKSR6xdXdhSzaOZJGtdapd4vVPbi6rP+cL7TGXOHtXKll4bY1Xl7EGnPtp7Xy2n00zyKLVHfkHBa4IcJ2oD3cgggWvt/V/FbDrUlEUJhTn/0azVWbNTNr0Ens8de1tceK9xZmfB1CPjOmPH4kitmvOubcNpmVTN3oFJyjzCvnmrwhJTzqzVj9jiSX911FjeAAB4nG3HMRKCMBBA0f0giiKi4DU8k0V2GWbIZDOh4PoWWvq6J5V8If9NVNQcaDhyouXMhY4rPTcG7jwYmXhKq8Wz+p762aNaeYXom2n3m2dLTVgsrCgFJ7OTmIkYbwIbC6vIB7WmFfAAAA==\") format(\"woff\");\n}`;\n\nfunction _injectStyles( cssContent ) {\n\tconst injected = document.createElement( 'style' );\n\tinjected.innerHTML = cssContent;\n\tconst before = document.querySelector( 'head link[rel=stylesheet], head style' );\n\tif ( before ) {\n\t\tdocument.head.insertBefore( injected, before );\n\t} else {\n\t\tdocument.head.appendChild( injected );\n\t}\n}\n\nlet stylesInjected = false;\n\nclass GUI {\n\n\t/**\n\t * Creates a panel that holds controllers.\n\t * @example\n\t * new GUI();\n\t * new GUI( { container: document.getElementById( 'custom' ) } );\n\t *\n\t * @param {object} [options]\n\t * @param {boolean} [options.autoPlace=true]\n\t * Adds the GUI to `document.body` and fixes it to the top right of the page.\n\t *\n\t * @param {HTMLElement} [options.container]\n\t * Adds the GUI to this DOM element. Overrides `autoPlace`.\n\t *\n\t * @param {number} [options.width=245]\n\t * Width of the GUI in pixels, usually set when name labels become too long. Note that you can make\n\t * name labels wider in CSS with `.lil‑gui { ‑‑name‑width: 55% }`.\n\t *\n\t * @param {string} [options.title=Controls]\n\t * Name to display in the title bar.\n\t *\n\t * @param {boolean} [options.closeFolders=false]\n\t * Pass `true` to close all folders in this GUI by default.\n\t *\n\t * @param {boolean} [options.injectStyles=true]\n\t * Injects the default stylesheet into the page if this is the first GUI.\n\t * Pass `false` to use your own stylesheet.\n\t *\n\t * @param {number} [options.touchStyles=true]\n\t * Makes controllers larger on touch devices. Pass `false` to disable touch styles.\n\t *\n\t * @param {GUI} [options.parent]\n\t * Adds this GUI as a child in another GUI. Usually this is done for you by `addFolder()`.\n\t *\n\t */\n\tconstructor( {\n\t\tparent,\n\t\tautoPlace = parent === undefined,\n\t\tcontainer,\n\t\twidth,\n\t\ttitle = 'Controls',\n\t\tcloseFolders = false,\n\t\tinjectStyles = true,\n\t\ttouchStyles = true\n\t} = {} ) {\n\n\t\t/**\n\t\t * The GUI containing this folder, or `undefined` if this is the root GUI.\n\t\t * @type {GUI}\n\t\t */\n\t\tthis.parent = parent;\n\n\t\t/**\n\t\t * The top level GUI containing this folder, or `this` if this is the root GUI.\n\t\t * @type {GUI}\n\t\t */\n\t\tthis.root = parent ? parent.root : this;\n\n\t\t/**\n\t\t * The list of controllers and folders contained by this GUI.\n\t\t * @type {Array}\n\t\t */\n\t\tthis.children = [];\n\n\t\t/**\n\t\t * The list of controllers contained by this GUI.\n\t\t * @type {Array}\n\t\t */\n\t\tthis.controllers = [];\n\n\t\t/**\n\t\t * The list of folders contained by this GUI.\n\t\t * @type {Array}\n\t\t */\n\t\tthis.folders = [];\n\n\t\t/**\n\t\t * Used to determine if the GUI is closed. Use `gui.open()` or `gui.close()` to change this.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._closed = false;\n\n\t\t/**\n\t\t * Used to determine if the GUI is hidden. Use `gui.show()` or `gui.hide()` to change this.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._hidden = false;\n\n\t\t/**\n\t\t * The outermost container element.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.domElement = document.createElement( 'div' );\n\t\tthis.domElement.classList.add( 'lil-gui' );\n\n\t\t/**\n\t\t * The DOM element that contains the title.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$title = document.createElement( 'div' );\n\t\tthis.$title.classList.add( 'title' );\n\t\tthis.$title.setAttribute( 'role', 'button' );\n\t\tthis.$title.setAttribute( 'aria-expanded', true );\n\t\tthis.$title.setAttribute( 'tabindex', 0 );\n\n\t\tthis.$title.addEventListener( 'click', () => this.openAnimated( this._closed ) );\n\t\tthis.$title.addEventListener( 'keydown', e => {\n\t\t\tif ( e.code === 'Enter' || e.code === 'Space' ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis.$title.click();\n\t\t\t}\n\t\t} );\n\n\t\t// enables :active pseudo class on mobile\n\t\tthis.$title.addEventListener( 'touchstart', () => {}, { passive: true } );\n\n\t\t/**\n\t\t * The DOM element that contains children.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$children = document.createElement( 'div' );\n\t\tthis.$children.classList.add( 'children' );\n\n\t\tthis.domElement.appendChild( this.$title );\n\t\tthis.domElement.appendChild( this.$children );\n\n\t\tthis.title( title );\n\n\t\tif ( this.parent ) {\n\n\t\t\tthis.parent.children.push( this );\n\t\t\tthis.parent.folders.push( this );\n\n\t\t\tthis.parent.$children.appendChild( this.domElement );\n\n\t\t\t// Stop the constructor early, everything onward only applies to root GUI's\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.domElement.classList.add( 'root' );\n\n\t\tif ( touchStyles ) {\n\t\t\tthis.domElement.classList.add( 'allow-touch-styles' );\n\t\t}\n\n\t\t// Inject stylesheet if we haven't done that yet\n\t\tif ( !stylesInjected && injectStyles ) {\n\t\t\t_injectStyles( stylesheet );\n\t\t\tstylesInjected = true;\n\t\t}\n\n\t\tif ( container ) {\n\n\t\t\tcontainer.appendChild( this.domElement );\n\n\t\t} else if ( autoPlace ) {\n\n\t\t\tthis.domElement.classList.add( 'autoPlace' );\n\t\t\tdocument.body.appendChild( this.domElement );\n\n\t\t}\n\n\t\tif ( width ) {\n\t\t\tthis.domElement.style.setProperty( '--width', width + 'px' );\n\t\t}\n\n\t\tthis._closeFolders = closeFolders;\n\n\t}\n\n\t/**\n\t * Adds a controller to the GUI, inferring controller type using the `typeof` operator.\n\t * @example\n\t * gui.add( object, 'property' );\n\t * gui.add( object, 'number', 0, 100, 1 );\n\t * gui.add( object, 'options', [ 1, 2, 3 ] );\n\t *\n\t * @param {object} object The object the controller will modify.\n\t * @param {string} property Name of the property to control.\n\t * @param {number|object|Array} [$1] Minimum value for number controllers, or the set of\n\t * selectable values for a dropdown.\n\t * @param {number} [max] Maximum value for number controllers.\n\t * @param {number} [step] Step value for number controllers.\n\t * @returns {Controller}\n\t */\n\tadd( object, property, $1, max, step ) {\n\n\t\tif ( Object( $1 ) === $1 ) {\n\n\t\t\treturn new OptionController( this, object, property, $1 );\n\n\t\t}\n\n\t\tconst initialValue = object[ property ];\n\n\t\tswitch ( typeof initialValue ) {\n\n\t\t\tcase 'number':\n\n\t\t\t\treturn new NumberController( this, object, property, $1, max, step );\n\n\t\t\tcase 'boolean':\n\n\t\t\t\treturn new BooleanController( this, object, property );\n\n\t\t\tcase 'string':\n\n\t\t\t\treturn new StringController( this, object, property );\n\n\t\t\tcase 'function':\n\n\t\t\t\treturn new FunctionController( this, object, property );\n\n\t\t}\n\n\t\tconsole.error( `gui.add failed\n\tproperty:`, property, `\n\tobject:`, object, `\n\tvalue:`, initialValue );\n\n\t}\n\n\t/**\n\t * Adds a color controller to the GUI.\n\t * @example\n\t * params = {\n\t * \tcssColor: '#ff00ff',\n\t * \trgbColor: { r: 0, g: 0.2, b: 0.4 },\n\t * \tcustomRange: [ 0, 127, 255 ],\n\t * };\n\t *\n\t * gui.addColor( params, 'cssColor' );\n\t * gui.addColor( params, 'rgbColor' );\n\t * gui.addColor( params, 'customRange', 255 );\n\t *\n\t * @param {object} object The object the controller will modify.\n\t * @param {string} property Name of the property to control.\n\t * @param {number} rgbScale Maximum value for a color channel when using an RGB color. You may\n\t * need to set this to 255 if your colors are too bright.\n\t * @returns {Controller}\n\t */\n\taddColor( object, property, rgbScale = 1 ) {\n\t\treturn new ColorController( this, object, property, rgbScale );\n\t}\n\n\t/**\n\t * Adds a folder to the GUI, which is just another GUI. This method returns\n\t * the nested GUI so you can add controllers to it.\n\t * @example\n\t * const folder = gui.addFolder( 'Position' );\n\t * folder.add( position, 'x' );\n\t * folder.add( position, 'y' );\n\t * folder.add( position, 'z' );\n\t *\n\t * @param {string} title Name to display in the folder's title bar.\n\t * @returns {GUI}\n\t */\n\taddFolder( title ) {\n\t\tconst folder = new GUI( { parent: this, title } );\n\t\tif ( this.root._closeFolders ) folder.close();\n\t\treturn folder;\n\t}\n\n\t/**\n\t * Recalls values that were saved with `gui.save()`.\n\t * @param {object} obj\n\t * @param {boolean} recursive Pass false to exclude folders descending from this GUI.\n\t * @returns {this}\n\t */\n\tload( obj, recursive = true ) {\n\n\t\tif ( obj.controllers ) {\n\n\t\t\tthis.controllers.forEach( c => {\n\n\t\t\t\tif ( c instanceof FunctionController ) return;\n\n\t\t\t\tif ( c._name in obj.controllers ) {\n\t\t\t\t\tc.load( obj.controllers[ c._name ] );\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t}\n\n\t\tif ( recursive && obj.folders ) {\n\n\t\t\tthis.folders.forEach( f => {\n\n\t\t\t\tif ( f._title in obj.folders ) {\n\t\t\t\t\tf.load( obj.folders[ f._title ] );\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Returns an object mapping controller names to values. The object can be passed to `gui.load()` to\n\t * recall these values.\n\t * @example\n\t * {\n\t * \tcontrollers: {\n\t * \t\tprop1: 1,\n\t * \t\tprop2: 'value',\n\t * \t\t...\n\t * \t},\n\t * \tfolders: {\n\t * \t\tfolderName1: { controllers, folders },\n\t * \t\tfolderName2: { controllers, folders }\n\t * \t\t...\n\t * \t}\n\t * }\n\t *\n\t * @param {boolean} recursive Pass false to exclude folders descending from this GUI.\n\t * @returns {object}\n\t */\n\tsave( recursive = true ) {\n\n\t\tconst obj = {\n\t\t\tcontrollers: {},\n\t\t\tfolders: {}\n\t\t};\n\n\t\tthis.controllers.forEach( c => {\n\n\t\t\tif ( c instanceof FunctionController ) return;\n\n\t\t\tif ( c._name in obj.controllers ) {\n\t\t\t\tthrow new Error( `Cannot save GUI with duplicate property \"${c._name}\"` );\n\t\t\t}\n\n\t\t\tobj.controllers[ c._name ] = c.save();\n\n\t\t} );\n\n\t\tif ( recursive ) {\n\n\t\t\tthis.folders.forEach( f => {\n\n\t\t\t\tif ( f._title in obj.folders ) {\n\t\t\t\t\tthrow new Error( `Cannot save GUI with duplicate folder \"${f._title}\"` );\n\t\t\t\t}\n\n\t\t\t\tobj.folders[ f._title ] = f.save();\n\n\t\t\t} );\n\n\t\t}\n\n\t\treturn obj;\n\n\t}\n\n\t/**\n\t * Opens a GUI or folder. GUI and folders are open by default.\n\t * @param {boolean} open Pass false to close.\n\t * @returns {this}\n\t * @example\n\t * gui.open(); // open\n\t * gui.open( false ); // close\n\t * gui.open( gui._closed ); // toggle\n\t */\n\topen( open = true ) {\n\n\t\tthis._setClosed( !open );\n\n\t\tthis.$title.setAttribute( 'aria-expanded', !this._closed );\n\t\tthis.domElement.classList.toggle( 'closed', this._closed );\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Closes the GUI.\n\t * @returns {this}\n\t */\n\tclose() {\n\t\treturn this.open( false );\n\t}\n\n\t_setClosed( closed ) {\n\t\tif ( this._closed === closed ) return;\n\t\tthis._closed = closed;\n\t\tthis._callOnOpenClose( this );\n\t}\n\n\t/**\n\t * Shows the GUI after it's been hidden.\n\t * @param {boolean} show\n\t * @returns {this}\n\t * @example\n\t * gui.show();\n\t * gui.show( false ); // hide\n\t * gui.show( gui._hidden ); // toggle\n\t */\n\tshow( show = true ) {\n\n\t\tthis._hidden = !show;\n\n\t\tthis.domElement.style.display = this._hidden ? 'none' : '';\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Hides the GUI.\n\t * @returns {this}\n\t */\n\thide() {\n\t\treturn this.show( false );\n\t}\n\n\topenAnimated( open = true ) {\n\n\t\t// set state immediately\n\t\tthis._setClosed( !open );\n\n\t\tthis.$title.setAttribute( 'aria-expanded', !this._closed );\n\n\t\t// wait for next frame to measure $children\n\t\trequestAnimationFrame( () => {\n\n\t\t\t// explicitly set initial height for transition\n\t\t\tconst initialHeight = this.$children.clientHeight;\n\t\t\tthis.$children.style.height = initialHeight + 'px';\n\n\t\t\tthis.domElement.classList.add( 'transition' );\n\n\t\t\tconst onTransitionEnd = e => {\n\t\t\t\tif ( e.target !== this.$children ) return;\n\t\t\t\tthis.$children.style.height = '';\n\t\t\t\tthis.domElement.classList.remove( 'transition' );\n\t\t\t\tthis.$children.removeEventListener( 'transitionend', onTransitionEnd );\n\t\t\t};\n\n\t\t\tthis.$children.addEventListener( 'transitionend', onTransitionEnd );\n\n\t\t\t// todo: this is wrong if children's scrollHeight makes for a gui taller than maxHeight\n\t\t\tconst targetHeight = !open ? 0 : this.$children.scrollHeight;\n\n\t\t\tthis.domElement.classList.toggle( 'closed', !open );\n\n\t\t\trequestAnimationFrame( () => {\n\t\t\t\tthis.$children.style.height = targetHeight + 'px';\n\t\t\t} );\n\n\t\t} );\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Change the title of this GUI.\n\t * @param {string} title\n\t * @returns {this}\n\t */\n\ttitle( title ) {\n\t\t/**\n\t\t * Current title of the GUI. Use `gui.title( 'Title' )` to modify this value.\n\t\t * @type {string}\n\t\t */\n\t\tthis._title = title;\n\t\tthis.$title.textContent = title;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Resets all controllers to their initial values.\n\t * @param {boolean} recursive Pass false to exclude folders descending from this GUI.\n\t * @returns {this}\n\t */\n\treset( recursive = true ) {\n\t\tconst controllers = recursive ? this.controllersRecursive() : this.controllers;\n\t\tcontrollers.forEach( c => c.reset() );\n\t\treturn this;\n\t}\n\n\t/**\n\t * Pass a function to be called whenever a controller in this GUI changes.\n\t * @param {function({object:object, property:string, value:any, controller:Controller})} callback\n\t * @returns {this}\n\t * @example\n\t * gui.onChange( event => {\n\t * \tevent.object // object that was modified\n\t * \tevent.property // string, name of property\n\t * \tevent.value // new value of controller\n\t * \tevent.controller // controller that was modified\n\t * } );\n\t */\n\tonChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onChange` events. Don't modify this value\n\t\t * directly. Use the `gui.onChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onChange = callback;\n\t\treturn this;\n\t}\n\n\t_callOnChange( controller ) {\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._callOnChange( controller );\n\t\t}\n\n\t\tif ( this._onChange !== undefined ) {\n\t\t\tthis._onChange.call( this, {\n\t\t\t\tobject: controller.object,\n\t\t\t\tproperty: controller.property,\n\t\t\t\tvalue: controller.getValue(),\n\t\t\t\tcontroller\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Pass a function to be called whenever a controller in this GUI has finished changing.\n\t * @param {function({object:object, property:string, value:any, controller:Controller})} callback\n\t * @returns {this}\n\t * @example\n\t * gui.onFinishChange( event => {\n\t * \tevent.object // object that was modified\n\t * \tevent.property // string, name of property\n\t * \tevent.value // new value of controller\n\t * \tevent.controller // controller that was modified\n\t * } );\n\t */\n\tonFinishChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onFinishChange` events. Don't modify this value\n\t\t * directly. Use the `gui.onFinishChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onFinishChange = callback;\n\t\treturn this;\n\t}\n\n\t_callOnFinishChange( controller ) {\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._callOnFinishChange( controller );\n\t\t}\n\n\t\tif ( this._onFinishChange !== undefined ) {\n\t\t\tthis._onFinishChange.call( this, {\n\t\t\t\tobject: controller.object,\n\t\t\t\tproperty: controller.property,\n\t\t\t\tvalue: controller.getValue(),\n\t\t\t\tcontroller\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Pass a function to be called when this GUI or its descendants are opened or closed.\n\t * @param {function(GUI)} callback\n\t * @returns {this}\n\t * @example\n\t * gui.onOpenClose( changedGUI => {\n\t * \tconsole.log( changedGUI._closed );\n\t * } );\n\t */\n\tonOpenClose( callback ) {\n\t\tthis._onOpenClose = callback;\n\t\treturn this;\n\t}\n\n\t_callOnOpenClose( changedGUI ) {\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._callOnOpenClose( changedGUI );\n\t\t}\n\n\t\tif ( this._onOpenClose !== undefined ) {\n\t\t\tthis._onOpenClose.call( this, changedGUI );\n\t\t}\n\t}\n\n\t/**\n\t * Destroys all DOM elements and event listeners associated with this GUI.\n\t */\n\tdestroy() {\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent.children.splice( this.parent.children.indexOf( this ), 1 );\n\t\t\tthis.parent.folders.splice( this.parent.folders.indexOf( this ), 1 );\n\t\t}\n\n\t\tif ( this.domElement.parentElement ) {\n\t\t\tthis.domElement.parentElement.removeChild( this.domElement );\n\t\t}\n\n\t\tArray.from( this.children ).forEach( c => c.destroy() );\n\n\t}\n\n\t/**\n\t * Returns an array of controllers contained by this GUI and its descendents.\n\t * @returns {Controller[]}\n\t */\n\tcontrollersRecursive() {\n\t\tlet controllers = Array.from( this.controllers );\n\t\tthis.folders.forEach( f => {\n\t\t\tcontrollers = controllers.concat( f.controllersRecursive() );\n\t\t} );\n\t\treturn controllers;\n\t}\n\n\t/**\n\t * Returns an array of folders contained by this GUI and its descendents.\n\t * @returns {GUI[]}\n\t */\n\tfoldersRecursive() {\n\t\tlet folders = Array.from( this.folders );\n\t\tthis.folders.forEach( f => {\n\t\t\tfolders = folders.concat( f.foldersRecursive() );\n\t\t} );\n\t\treturn folders;\n\t}\n\n}\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (GUI);\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNjM4LmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGtDQUFrQyx3QkFBd0I7O0FBRTFEO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFVBQVU7QUFDdEIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFVBQVU7QUFDdEIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckIsY0FBYztBQUNkO0FBQ0E7QUFDQSxnQ0FBZ0M7QUFDaEMsK0NBQStDO0FBQy9DO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckIsY0FBYztBQUNkO0FBQ0E7QUFDQSxpQ0FBaUM7QUFDakMsaURBQWlEO0FBQ2pEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCLGNBQWM7QUFDZDtBQUNBO0FBQ0EsOEJBQThCO0FBQzlCLDJDQUEyQztBQUMzQztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsb0JBQW9CO0FBQzNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksY0FBYztBQUMxQixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVksUUFBUTtBQUNwQixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVksUUFBUTtBQUNwQixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCLGNBQWM7QUFDZDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVksS0FBSztBQUNqQixjQUFjO0FBQ2Q7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw4Q0FBOEMsRUFBRTs7QUFFaEQ7O0FBRUEsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsRUFBRTtBQUNGOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFO0FBQ0YsZ0JBQWdCLFNBQVM7O0FBRXpCOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBLHVEQUF1RCxJQUFJLGdCQUFnQjs7QUFFM0U7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esb0RBQW9ELGlCQUFpQjtBQUNyRTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUEsd0RBQXdELGlCQUFpQjtBQUN6RTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLCtEQUErRCxpQkFBaUI7QUFDaEYscURBQXFELGlCQUFpQjs7QUFFdEU7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZDQUE2QyxLQUFLO0FBQ2xEOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxRQUFRLGlCQUFpQjs7QUFFekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0EsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSx1Q0FBdUMsY0FBYztBQUNyRCxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLGlEQUFpRDtBQUNoRTtBQUNBLFlBQVksUUFBUTtBQUNwQixZQUFZLFNBQVM7QUFDckI7QUFDQTtBQUNBLFlBQVksYUFBYTtBQUN6QjtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCO0FBQ0EsOENBQThDLG1CQUFtQjtBQUNqRTtBQUNBLFlBQVksUUFBUTtBQUNwQjtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckI7QUFDQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCO0FBQ0E7QUFDQSxZQUFZLEtBQUs7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRyxLQUFLOztBQUVSO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0Esc0RBQXNELElBQUksZ0JBQWdCOztBQUUxRTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCLFlBQVksUUFBUTtBQUNwQixZQUFZLHFCQUFxQjtBQUNqQztBQUNBLFlBQVksUUFBUTtBQUNwQixZQUFZLFFBQVE7QUFDcEIsY0FBYztBQUNkO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixzQkFBc0I7QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsWUFBWSxRQUFRO0FBQ3BCLFlBQVksUUFBUTtBQUNwQjtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsY0FBYztBQUNkO0FBQ0E7QUFDQSw0QkFBNEIsc0JBQXNCO0FBQ2xEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCLFlBQVksU0FBUztBQUNyQixjQUFjO0FBQ2Q7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQSxxQkFBcUIsc0JBQXNCO0FBQzNDLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksU0FBUztBQUNyQixjQUFjO0FBQ2Q7QUFDQTs7QUFFQTtBQUNBLGtCQUFrQjtBQUNsQjtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsaUVBQWlFLFFBQVE7QUFDekU7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBLGdFQUFnRSxTQUFTO0FBQ3pFOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLFlBQVksU0FBUztBQUNyQixjQUFjO0FBQ2Q7QUFDQSxnQkFBZ0I7QUFDaEIsdUJBQXVCO0FBQ3ZCLDZCQUE2QjtBQUM3QjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckIsY0FBYztBQUNkO0FBQ0E7QUFDQSx1QkFBdUI7QUFDdkIsNkJBQTZCO0FBQzdCO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLFlBQVksUUFBUTtBQUNwQixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVksVUFBVSxpRUFBaUUsR0FBRztBQUMxRixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFVBQVUsaUVBQWlFLEdBQUc7QUFDMUYsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxlQUFlO0FBQzNCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7O0FBRUEsaUVBQWUsR0FBRyxFQUFDO0FBQ3NIIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy9saWwtZ3VpL2Rpc3QvbGlsLWd1aS5lc20uanM/YWZiMyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGxpbC1ndWlcbiAqIGh0dHBzOi8vbGlsLWd1aS5nZW9yZ2VhbHdheXMuY29tXG4gKiBAdmVyc2lvbiAwLjE5LjJcbiAqIEBhdXRob3IgR2VvcmdlIE1pY2hhZWwgQnJvd2VyXG4gKiBAbGljZW5zZSBNSVRcbiAqL1xuXG4vKipcbiAqIEJhc2UgY2xhc3MgZm9yIGFsbCBjb250cm9sbGVycy5cbiAqL1xuY2xhc3MgQ29udHJvbGxlciB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSwgY2xhc3NOYW1lLCBlbGVtZW50VHlwZSA9ICdkaXYnICkge1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIEdVSSB0aGF0IGNvbnRhaW5zIHRoaXMgY29udHJvbGxlci5cblx0XHQgKiBAdHlwZSB7R1VJfVxuXHRcdCAqL1xuXHRcdHRoaXMucGFyZW50ID0gcGFyZW50O1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIG9iamVjdCB0aGlzIGNvbnRyb2xsZXIgd2lsbCBtb2RpZnkuXG5cdFx0ICogQHR5cGUge29iamVjdH1cblx0XHQgKi9cblx0XHR0aGlzLm9iamVjdCA9IG9iamVjdDtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBuYW1lIG9mIHRoZSBwcm9wZXJ0eSB0byBjb250cm9sLlxuXHRcdCAqIEB0eXBlIHtzdHJpbmd9XG5cdFx0ICovXG5cdFx0dGhpcy5wcm9wZXJ0eSA9IHByb3BlcnR5O1xuXG5cdFx0LyoqXG5cdFx0ICogVXNlZCB0byBkZXRlcm1pbmUgaWYgdGhlIGNvbnRyb2xsZXIgaXMgZGlzYWJsZWQuXG5cdFx0ICogVXNlIGBjb250cm9sbGVyLmRpc2FibGUoIHRydWV8ZmFsc2UgKWAgdG8gbW9kaWZ5IHRoaXMgdmFsdWUuXG5cdFx0ICogQHR5cGUge2Jvb2xlYW59XG5cdFx0ICovXG5cdFx0dGhpcy5fZGlzYWJsZWQgPSBmYWxzZTtcblxuXHRcdC8qKlxuXHRcdCAqIFVzZWQgdG8gZGV0ZXJtaW5lIGlmIHRoZSBDb250cm9sbGVyIGlzIGhpZGRlbi5cblx0XHQgKiBVc2UgYGNvbnRyb2xsZXIuc2hvdygpYCBvciBgY29udHJvbGxlci5oaWRlKClgIHRvIGNoYW5nZSB0aGlzLlxuXHRcdCAqIEB0eXBlIHtib29sZWFufVxuXHRcdCAqL1xuXHRcdHRoaXMuX2hpZGRlbiA9IGZhbHNlO1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIHZhbHVlIG9mIGBvYmplY3RbIHByb3BlcnR5IF1gIHdoZW4gdGhlIGNvbnRyb2xsZXIgd2FzIGNyZWF0ZWQuXG5cdFx0ICogQHR5cGUge2FueX1cblx0XHQgKi9cblx0XHR0aGlzLmluaXRpYWxWYWx1ZSA9IHRoaXMuZ2V0VmFsdWUoKTtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBvdXRlcm1vc3QgY29udGFpbmVyIERPTSBlbGVtZW50IGZvciB0aGlzIGNvbnRyb2xsZXIuXG5cdFx0ICogQHR5cGUge0hUTUxFbGVtZW50fVxuXHRcdCAqL1xuXHRcdHRoaXMuZG9tRWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIGVsZW1lbnRUeXBlICk7XG5cdFx0dGhpcy5kb21FbGVtZW50LmNsYXNzTGlzdC5hZGQoICdjb250cm9sbGVyJyApO1xuXHRcdHRoaXMuZG9tRWxlbWVudC5jbGFzc0xpc3QuYWRkKCBjbGFzc05hbWUgKTtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBET00gZWxlbWVudCB0aGF0IGNvbnRhaW5zIHRoZSBjb250cm9sbGVyJ3MgbmFtZS5cblx0XHQgKiBAdHlwZSB7SFRNTEVsZW1lbnR9XG5cdFx0ICovXG5cdFx0dGhpcy4kbmFtZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdkaXYnICk7XG5cdFx0dGhpcy4kbmFtZS5jbGFzc0xpc3QuYWRkKCAnbmFtZScgKTtcblxuXHRcdENvbnRyb2xsZXIubmV4dE5hbWVJRCA9IENvbnRyb2xsZXIubmV4dE5hbWVJRCB8fCAwO1xuXHRcdHRoaXMuJG5hbWUuaWQgPSBgbGlsLWd1aS1uYW1lLSR7KytDb250cm9sbGVyLm5leHROYW1lSUR9YDtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBET00gZWxlbWVudCB0aGF0IGNvbnRhaW5zIHRoZSBjb250cm9sbGVyJ3MgXCJ3aWRnZXRcIiAod2hpY2ggZGlmZmVycyBieSBjb250cm9sbGVyIHR5cGUpLlxuXHRcdCAqIEB0eXBlIHtIVE1MRWxlbWVudH1cblx0XHQgKi9cblx0XHR0aGlzLiR3aWRnZXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnZGl2JyApO1xuXHRcdHRoaXMuJHdpZGdldC5jbGFzc0xpc3QuYWRkKCAnd2lkZ2V0JyApO1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIERPTSBlbGVtZW50IHRoYXQgcmVjZWl2ZXMgdGhlIGRpc2FibGVkIGF0dHJpYnV0ZSB3aGVuIHVzaW5nIGRpc2FibGUoKS5cblx0XHQgKiBAdHlwZSB7SFRNTEVsZW1lbnR9XG5cdFx0ICovXG5cdFx0dGhpcy4kZGlzYWJsZSA9IHRoaXMuJHdpZGdldDtcblxuXHRcdHRoaXMuZG9tRWxlbWVudC5hcHBlbmRDaGlsZCggdGhpcy4kbmFtZSApO1xuXHRcdHRoaXMuZG9tRWxlbWVudC5hcHBlbmRDaGlsZCggdGhpcy4kd2lkZ2V0ICk7XG5cblx0XHQvLyBEb24ndCBmaXJlIGdsb2JhbCBrZXkgZXZlbnRzIHdoaWxlIHR5cGluZyBpbiBhIGNvbnRyb2xsZXJcblx0XHR0aGlzLmRvbUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCBlID0+IGUuc3RvcFByb3BhZ2F0aW9uKCkgKTtcblx0XHR0aGlzLmRvbUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ2tleXVwJywgZSA9PiBlLnN0b3BQcm9wYWdhdGlvbigpICk7XG5cblx0XHR0aGlzLnBhcmVudC5jaGlsZHJlbi5wdXNoKCB0aGlzICk7XG5cdFx0dGhpcy5wYXJlbnQuY29udHJvbGxlcnMucHVzaCggdGhpcyApO1xuXG5cdFx0dGhpcy5wYXJlbnQuJGNoaWxkcmVuLmFwcGVuZENoaWxkKCB0aGlzLmRvbUVsZW1lbnQgKTtcblxuXHRcdHRoaXMuX2xpc3RlbkNhbGxiYWNrID0gdGhpcy5fbGlzdGVuQ2FsbGJhY2suYmluZCggdGhpcyApO1xuXG5cdFx0dGhpcy5uYW1lKCBwcm9wZXJ0eSApO1xuXG5cdH1cblxuXHQvKipcblx0ICogU2V0cyB0aGUgbmFtZSBvZiB0aGUgY29udHJvbGxlciBhbmQgaXRzIGxhYmVsIGluIHRoZSBHVUkuXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKi9cblx0bmFtZSggbmFtZSApIHtcblx0XHQvKipcblx0XHQgKiBUaGUgY29udHJvbGxlcidzIG5hbWUuIFVzZSBgY29udHJvbGxlci5uYW1lKCAnTmFtZScgKWAgdG8gbW9kaWZ5IHRoaXMgdmFsdWUuXG5cdFx0ICogQHR5cGUge3N0cmluZ31cblx0XHQgKi9cblx0XHR0aGlzLl9uYW1lID0gbmFtZTtcblx0XHR0aGlzLiRuYW1lLnRleHRDb250ZW50ID0gbmFtZTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBQYXNzIGEgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW5ldmVyIHRoZSB2YWx1ZSBpcyBtb2RpZmllZCBieSB0aGlzIGNvbnRyb2xsZXIuXG5cdCAqIFRoZSBmdW5jdGlvbiByZWNlaXZlcyB0aGUgbmV3IHZhbHVlIGFzIGl0cyBmaXJzdCBwYXJhbWV0ZXIuIFRoZSB2YWx1ZSBvZiBgdGhpc2Agd2lsbCBiZSB0aGVcblx0ICogY29udHJvbGxlci5cblx0ICpcblx0ICogRm9yIGZ1bmN0aW9uIGNvbnRyb2xsZXJzLCB0aGUgYG9uQ2hhbmdlYCBjYWxsYmFjayB3aWxsIGJlIGZpcmVkIG9uIGNsaWNrLCBhZnRlciB0aGUgZnVuY3Rpb25cblx0ICogZXhlY3V0ZXMuXG5cdCAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKiBAZXhhbXBsZVxuXHQgKiBjb25zdCBjb250cm9sbGVyID0gZ3VpLmFkZCggb2JqZWN0LCAncHJvcGVydHknICk7XG5cdCAqXG5cdCAqIGNvbnRyb2xsZXIub25DaGFuZ2UoIGZ1bmN0aW9uKCB2ICkge1xuXHQgKiBcdGNvbnNvbGUubG9nKCAnVGhlIHZhbHVlIGlzIG5vdyAnICsgdiApO1xuXHQgKiBcdGNvbnNvbGUuYXNzZXJ0KCB0aGlzID09PSBjb250cm9sbGVyICk7XG5cdCAqIH0gKTtcblx0ICovXG5cdG9uQ2hhbmdlKCBjYWxsYmFjayApIHtcblx0XHQvKipcblx0XHQgKiBVc2VkIHRvIGFjY2VzcyB0aGUgZnVuY3Rpb24gYm91bmQgdG8gYG9uQ2hhbmdlYCBldmVudHMuIERvbid0IG1vZGlmeSB0aGlzIHZhbHVlIGRpcmVjdGx5LlxuXHRcdCAqIFVzZSB0aGUgYGNvbnRyb2xsZXIub25DaGFuZ2UoIGNhbGxiYWNrIClgIG1ldGhvZCBpbnN0ZWFkLlxuXHRcdCAqIEB0eXBlIHtGdW5jdGlvbn1cblx0XHQgKi9cblx0XHR0aGlzLl9vbkNoYW5nZSA9IGNhbGxiYWNrO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIENhbGxzIHRoZSBvbkNoYW5nZSBtZXRob2RzIG9mIHRoaXMgY29udHJvbGxlciBhbmQgaXRzIHBhcmVudCBHVUkuXG5cdCAqIEBwcm90ZWN0ZWRcblx0ICovXG5cdF9jYWxsT25DaGFuZ2UoKSB7XG5cblx0XHR0aGlzLnBhcmVudC5fY2FsbE9uQ2hhbmdlKCB0aGlzICk7XG5cblx0XHRpZiAoIHRoaXMuX29uQ2hhbmdlICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHR0aGlzLl9vbkNoYW5nZS5jYWxsKCB0aGlzLCB0aGlzLmdldFZhbHVlKCkgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9jaGFuZ2VkID0gdHJ1ZTtcblxuXHR9XG5cblx0LyoqXG5cdCAqIFBhc3MgYSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgYWZ0ZXIgdGhpcyBjb250cm9sbGVyIGhhcyBiZWVuIG1vZGlmaWVkIGFuZCBsb3NlcyBmb2N1cy5cblx0ICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqIEBleGFtcGxlXG5cdCAqIGNvbnN0IGNvbnRyb2xsZXIgPSBndWkuYWRkKCBvYmplY3QsICdwcm9wZXJ0eScgKTtcblx0ICpcblx0ICogY29udHJvbGxlci5vbkZpbmlzaENoYW5nZSggZnVuY3Rpb24oIHYgKSB7XG5cdCAqIFx0Y29uc29sZS5sb2coICdDaGFuZ2VzIGNvbXBsZXRlOiAnICsgdiApO1xuXHQgKiBcdGNvbnNvbGUuYXNzZXJ0KCB0aGlzID09PSBjb250cm9sbGVyICk7XG5cdCAqIH0gKTtcblx0ICovXG5cdG9uRmluaXNoQ2hhbmdlKCBjYWxsYmFjayApIHtcblx0XHQvKipcblx0XHQgKiBVc2VkIHRvIGFjY2VzcyB0aGUgZnVuY3Rpb24gYm91bmQgdG8gYG9uRmluaXNoQ2hhbmdlYCBldmVudHMuIERvbid0IG1vZGlmeSB0aGlzIHZhbHVlXG5cdFx0ICogZGlyZWN0bHkuIFVzZSB0aGUgYGNvbnRyb2xsZXIub25GaW5pc2hDaGFuZ2UoIGNhbGxiYWNrIClgIG1ldGhvZCBpbnN0ZWFkLlxuXHRcdCAqIEB0eXBlIHtGdW5jdGlvbn1cblx0XHQgKi9cblx0XHR0aGlzLl9vbkZpbmlzaENoYW5nZSA9IGNhbGxiYWNrO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNob3VsZCBiZSBjYWxsZWQgYnkgQ29udHJvbGxlciB3aGVuIGl0cyB3aWRnZXRzIGxvc2UgZm9jdXMuXG5cdCAqIEBwcm90ZWN0ZWRcblx0ICovXG5cdF9jYWxsT25GaW5pc2hDaGFuZ2UoKSB7XG5cblx0XHRpZiAoIHRoaXMuX2NoYW5nZWQgKSB7XG5cblx0XHRcdHRoaXMucGFyZW50Ll9jYWxsT25GaW5pc2hDaGFuZ2UoIHRoaXMgKTtcblxuXHRcdFx0aWYgKCB0aGlzLl9vbkZpbmlzaENoYW5nZSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHR0aGlzLl9vbkZpbmlzaENoYW5nZS5jYWxsKCB0aGlzLCB0aGlzLmdldFZhbHVlKCkgKTtcblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHRoaXMuX2NoYW5nZWQgPSBmYWxzZTtcblxuXHR9XG5cblx0LyoqXG5cdCAqIFNldHMgdGhlIGNvbnRyb2xsZXIgYmFjayB0byBpdHMgaW5pdGlhbCB2YWx1ZS5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRyZXNldCgpIHtcblx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLmluaXRpYWxWYWx1ZSApO1xuXHRcdHRoaXMuX2NhbGxPbkZpbmlzaENoYW5nZSgpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIEVuYWJsZXMgdGhpcyBjb250cm9sbGVyLlxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IGVuYWJsZWRcblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqIEBleGFtcGxlXG5cdCAqIGNvbnRyb2xsZXIuZW5hYmxlKCk7XG5cdCAqIGNvbnRyb2xsZXIuZW5hYmxlKCBmYWxzZSApOyAvLyBkaXNhYmxlXG5cdCAqIGNvbnRyb2xsZXIuZW5hYmxlKCBjb250cm9sbGVyLl9kaXNhYmxlZCApOyAvLyB0b2dnbGVcblx0ICovXG5cdGVuYWJsZSggZW5hYmxlZCA9IHRydWUgKSB7XG5cdFx0cmV0dXJuIHRoaXMuZGlzYWJsZSggIWVuYWJsZWQgKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBEaXNhYmxlcyB0aGlzIGNvbnRyb2xsZXIuXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gZGlzYWJsZWRcblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqIEBleGFtcGxlXG5cdCAqIGNvbnRyb2xsZXIuZGlzYWJsZSgpO1xuXHQgKiBjb250cm9sbGVyLmRpc2FibGUoIGZhbHNlICk7IC8vIGVuYWJsZVxuXHQgKiBjb250cm9sbGVyLmRpc2FibGUoICFjb250cm9sbGVyLl9kaXNhYmxlZCApOyAvLyB0b2dnbGVcblx0ICovXG5cdGRpc2FibGUoIGRpc2FibGVkID0gdHJ1ZSApIHtcblxuXHRcdGlmICggZGlzYWJsZWQgPT09IHRoaXMuX2Rpc2FibGVkICkgcmV0dXJuIHRoaXM7XG5cblx0XHR0aGlzLl9kaXNhYmxlZCA9IGRpc2FibGVkO1xuXG5cdFx0dGhpcy5kb21FbGVtZW50LmNsYXNzTGlzdC50b2dnbGUoICdkaXNhYmxlZCcsIGRpc2FibGVkICk7XG5cdFx0dGhpcy4kZGlzYWJsZS50b2dnbGVBdHRyaWJ1dGUoICdkaXNhYmxlZCcsIGRpc2FibGVkICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0LyoqXG5cdCAqIFNob3dzIHRoZSBDb250cm9sbGVyIGFmdGVyIGl0J3MgYmVlbiBoaWRkZW4uXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvd1xuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICogQGV4YW1wbGVcblx0ICogY29udHJvbGxlci5zaG93KCk7XG5cdCAqIGNvbnRyb2xsZXIuc2hvdyggZmFsc2UgKTsgLy8gaGlkZVxuXHQgKiBjb250cm9sbGVyLnNob3coIGNvbnRyb2xsZXIuX2hpZGRlbiApOyAvLyB0b2dnbGVcblx0ICovXG5cdHNob3coIHNob3cgPSB0cnVlICkge1xuXG5cdFx0dGhpcy5faGlkZGVuID0gIXNob3c7XG5cblx0XHR0aGlzLmRvbUVsZW1lbnQuc3R5bGUuZGlzcGxheSA9IHRoaXMuX2hpZGRlbiA/ICdub25lJyA6ICcnO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBIaWRlcyB0aGUgQ29udHJvbGxlci5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRoaWRlKCkge1xuXHRcdHJldHVybiB0aGlzLnNob3coIGZhbHNlICk7XG5cdH1cblxuXHQvKipcblx0ICogQ2hhbmdlcyB0aGlzIGNvbnRyb2xsZXIgaW50byBhIGRyb3Bkb3duIG9mIG9wdGlvbnMuXG5cdCAqXG5cdCAqIENhbGxpbmcgdGhpcyBtZXRob2Qgb24gYW4gb3B0aW9uIGNvbnRyb2xsZXIgd2lsbCBzaW1wbHkgdXBkYXRlIHRoZSBvcHRpb25zLiBIb3dldmVyLCBpZiB0aGlzXG5cdCAqIGNvbnRyb2xsZXIgd2FzIG5vdCBhbHJlYWR5IGFuIG9wdGlvbiBjb250cm9sbGVyLCBvbGQgcmVmZXJlbmNlcyB0byB0aGlzIGNvbnRyb2xsZXIgYXJlXG5cdCAqIGRlc3Ryb3llZCwgYW5kIGEgbmV3IGNvbnRyb2xsZXIgaXMgYWRkZWQgdG8gdGhlIGVuZCBvZiB0aGUgR1VJLlxuXHQgKiBAZXhhbXBsZVxuXHQgKiAvLyBzYWZlIHVzYWdlXG5cdCAqXG5cdCAqIGd1aS5hZGQoIG9iaiwgJ3Byb3AxJyApLm9wdGlvbnMoIFsgJ2EnLCAnYicsICdjJyBdICk7XG5cdCAqIGd1aS5hZGQoIG9iaiwgJ3Byb3AyJyApLm9wdGlvbnMoIHsgQmlnOiAxMCwgU21hbGw6IDEgfSApO1xuXHQgKiBndWkuYWRkKCBvYmosICdwcm9wMycgKTtcblx0ICpcblx0ICogLy8gZGFuZ2VyXG5cdCAqXG5cdCAqIGNvbnN0IGN0cmwxID0gZ3VpLmFkZCggb2JqLCAncHJvcDEnICk7XG5cdCAqIGd1aS5hZGQoIG9iaiwgJ3Byb3AyJyApO1xuXHQgKlxuXHQgKiAvLyBjYWxsaW5nIG9wdGlvbnMgb3V0IG9mIG9yZGVyIGFkZHMgYSBuZXcgY29udHJvbGxlciB0byB0aGUgZW5kLi4uXG5cdCAqIGNvbnN0IGN0cmwyID0gY3RybDEub3B0aW9ucyggWyAnYScsICdiJywgJ2MnIF0gKTtcblx0ICpcblx0ICogLy8gLi4uYW5kIGN0cmwxIG5vdyByZWZlcmVuY2VzIGEgY29udHJvbGxlciB0aGF0IGRvZXNuJ3QgZXhpc3Rcblx0ICogYXNzZXJ0KCBjdHJsMiAhPT0gY3RybDEgKVxuXHQgKiBAcGFyYW0ge29iamVjdHxBcnJheX0gb3B0aW9uc1xuXHQgKiBAcmV0dXJucyB7Q29udHJvbGxlcn1cblx0ICovXG5cdG9wdGlvbnMoIG9wdGlvbnMgKSB7XG5cdFx0Y29uc3QgY29udHJvbGxlciA9IHRoaXMucGFyZW50LmFkZCggdGhpcy5vYmplY3QsIHRoaXMucHJvcGVydHksIG9wdGlvbnMgKTtcblx0XHRjb250cm9sbGVyLm5hbWUoIHRoaXMuX25hbWUgKTtcblx0XHR0aGlzLmRlc3Ryb3koKTtcblx0XHRyZXR1cm4gY29udHJvbGxlcjtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXRzIHRoZSBtaW5pbXVtIHZhbHVlLiBPbmx5IHdvcmtzIG9uIG51bWJlciBjb250cm9sbGVycy5cblx0ICogQHBhcmFtIHtudW1iZXJ9IG1pblxuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICovXG5cdG1pbiggbWluICkge1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldHMgdGhlIG1heGltdW0gdmFsdWUuIE9ubHkgd29ya3Mgb24gbnVtYmVyIGNvbnRyb2xsZXJzLlxuXHQgKiBAcGFyYW0ge251bWJlcn0gbWF4XG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKi9cblx0bWF4KCBtYXggKSB7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogVmFsdWVzIHNldCBieSB0aGlzIGNvbnRyb2xsZXIgd2lsbCBiZSByb3VuZGVkIHRvIG11bHRpcGxlcyBvZiBgc3RlcGAuIE9ubHkgd29ya3Mgb24gbnVtYmVyXG5cdCAqIGNvbnRyb2xsZXJzLlxuXHQgKiBAcGFyYW0ge251bWJlcn0gc3RlcFxuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICovXG5cdHN0ZXAoIHN0ZXAgKSB7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogUm91bmRzIHRoZSBkaXNwbGF5ZWQgdmFsdWUgdG8gYSBmaXhlZCBudW1iZXIgb2YgZGVjaW1hbHMsIHdpdGhvdXQgYWZmZWN0aW5nIHRoZSBhY3R1YWwgdmFsdWVcblx0ICogbGlrZSBgc3RlcCgpYC4gT25seSB3b3JrcyBvbiBudW1iZXIgY29udHJvbGxlcnMuXG5cdCAqIEBleGFtcGxlXG5cdCAqIGd1aS5hZGQoIG9iamVjdCwgJ3Byb3BlcnR5JyApLmxpc3RlbigpLmRlY2ltYWxzKCA0ICk7XG5cdCAqIEBwYXJhbSB7bnVtYmVyfSBkZWNpbWFsc1xuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICovXG5cdGRlY2ltYWxzKCBkZWNpbWFscyApIHtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBDYWxscyBgdXBkYXRlRGlzcGxheSgpYCBldmVyeSBhbmltYXRpb24gZnJhbWUuIFBhc3MgYGZhbHNlYCB0byBzdG9wIGxpc3RlbmluZy5cblx0ICogQHBhcmFtIHtib29sZWFufSBsaXN0ZW5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRsaXN0ZW4oIGxpc3RlbiA9IHRydWUgKSB7XG5cblx0XHQvKipcblx0XHQgKiBVc2VkIHRvIGRldGVybWluZSBpZiB0aGUgY29udHJvbGxlciBpcyBjdXJyZW50bHkgbGlzdGVuaW5nLiBEb24ndCBtb2RpZnkgdGhpcyB2YWx1ZVxuXHRcdCAqIGRpcmVjdGx5LiBVc2UgdGhlIGBjb250cm9sbGVyLmxpc3RlbiggdHJ1ZXxmYWxzZSApYCBtZXRob2QgaW5zdGVhZC5cblx0XHQgKiBAdHlwZSB7Ym9vbGVhbn1cblx0XHQgKi9cblx0XHR0aGlzLl9saXN0ZW5pbmcgPSBsaXN0ZW47XG5cblx0XHRpZiAoIHRoaXMuX2xpc3RlbkNhbGxiYWNrSUQgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdGNhbmNlbEFuaW1hdGlvbkZyYW1lKCB0aGlzLl9saXN0ZW5DYWxsYmFja0lEICk7XG5cdFx0XHR0aGlzLl9saXN0ZW5DYWxsYmFja0lEID0gdW5kZWZpbmVkO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fbGlzdGVuaW5nICkge1xuXHRcdFx0dGhpcy5fbGlzdGVuQ2FsbGJhY2soKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0X2xpc3RlbkNhbGxiYWNrKCkge1xuXG5cdFx0dGhpcy5fbGlzdGVuQ2FsbGJhY2tJRCA9IHJlcXVlc3RBbmltYXRpb25GcmFtZSggdGhpcy5fbGlzdGVuQ2FsbGJhY2sgKTtcblxuXHRcdC8vIFRvIHByZXZlbnQgZnJhbWVyYXRlIGxvc3MsIG1ha2Ugc3VyZSB0aGUgdmFsdWUgaGFzIGNoYW5nZWQgYmVmb3JlIHVwZGF0aW5nIHRoZSBkaXNwbGF5LlxuXHRcdC8vIE5vdGU6IHNhdmUoKSBpcyB1c2VkIGhlcmUgaW5zdGVhZCBvZiBnZXRWYWx1ZSgpIG9ubHkgYmVjYXVzZSBvZiBDb2xvckNvbnRyb2xsZXIuIFRoZSAhPT0gb3BlcmF0b3Jcblx0XHQvLyB3b24ndCB3b3JrIGZvciBjb2xvciBvYmplY3RzIG9yIGFycmF5cywgYnV0IENvbG9yQ29udHJvbGxlci5zYXZlKCkgYWx3YXlzIHJldHVybnMgYSBzdHJpbmcuXG5cblx0XHRjb25zdCBjdXJWYWx1ZSA9IHRoaXMuc2F2ZSgpO1xuXG5cdFx0aWYgKCBjdXJWYWx1ZSAhPT0gdGhpcy5fbGlzdGVuUHJldlZhbHVlICkge1xuXHRcdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fbGlzdGVuUHJldlZhbHVlID0gY3VyVmFsdWU7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBSZXR1cm5zIGBvYmplY3RbIHByb3BlcnR5IF1gLlxuXHQgKiBAcmV0dXJucyB7YW55fVxuXHQgKi9cblx0Z2V0VmFsdWUoKSB7XG5cdFx0cmV0dXJuIHRoaXMub2JqZWN0WyB0aGlzLnByb3BlcnR5IF07XG5cdH1cblxuXHQvKipcblx0ICogU2V0cyB0aGUgdmFsdWUgb2YgYG9iamVjdFsgcHJvcGVydHkgXWAsIGludm9rZXMgYW55IGBvbkNoYW5nZWAgaGFuZGxlcnMgYW5kIHVwZGF0ZXMgdGhlIGRpc3BsYXkuXG5cdCAqIEBwYXJhbSB7YW55fSB2YWx1ZVxuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICovXG5cdHNldFZhbHVlKCB2YWx1ZSApIHtcblxuXHRcdGlmICggdGhpcy5nZXRWYWx1ZSgpICE9PSB2YWx1ZSApIHtcblxuXHRcdFx0dGhpcy5vYmplY3RbIHRoaXMucHJvcGVydHkgXSA9IHZhbHVlO1xuXHRcdFx0dGhpcy5fY2FsbE9uQ2hhbmdlKCk7XG5cdFx0XHR0aGlzLnVwZGF0ZURpc3BsYXkoKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvKipcblx0ICogVXBkYXRlcyB0aGUgZGlzcGxheSB0byBrZWVwIGl0IGluIHN5bmMgd2l0aCB0aGUgY3VycmVudCB2YWx1ZS4gVXNlZnVsIGZvciB1cGRhdGluZyB5b3VyXG5cdCAqIGNvbnRyb2xsZXJzIHdoZW4gdGhlaXIgdmFsdWVzIGhhdmUgYmVlbiBtb2RpZmllZCBvdXRzaWRlIG9mIHRoZSBHVUkuXG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKi9cblx0dXBkYXRlRGlzcGxheSgpIHtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdGxvYWQoIHZhbHVlICkge1xuXHRcdHRoaXMuc2V0VmFsdWUoIHZhbHVlICk7XG5cdFx0dGhpcy5fY2FsbE9uRmluaXNoQ2hhbmdlKCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRzYXZlKCkge1xuXHRcdHJldHVybiB0aGlzLmdldFZhbHVlKCk7XG5cdH1cblxuXHQvKipcblx0ICogRGVzdHJveXMgdGhpcyBjb250cm9sbGVyIGFuZCByZW1vdmVzIGl0IGZyb20gdGhlIHBhcmVudCBHVUkuXG5cdCAqL1xuXHRkZXN0cm95KCkge1xuXHRcdHRoaXMubGlzdGVuKCBmYWxzZSApO1xuXHRcdHRoaXMucGFyZW50LmNoaWxkcmVuLnNwbGljZSggdGhpcy5wYXJlbnQuY2hpbGRyZW4uaW5kZXhPZiggdGhpcyApLCAxICk7XG5cdFx0dGhpcy5wYXJlbnQuY29udHJvbGxlcnMuc3BsaWNlKCB0aGlzLnBhcmVudC5jb250cm9sbGVycy5pbmRleE9mKCB0aGlzICksIDEgKTtcblx0XHR0aGlzLnBhcmVudC4kY2hpbGRyZW4ucmVtb3ZlQ2hpbGQoIHRoaXMuZG9tRWxlbWVudCApO1xuXHR9XG5cbn1cblxuY2xhc3MgQm9vbGVhbkNvbnRyb2xsZXIgZXh0ZW5kcyBDb250cm9sbGVyIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyZW50LCBvYmplY3QsIHByb3BlcnR5ICkge1xuXG5cdFx0c3VwZXIoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSwgJ2Jvb2xlYW4nLCAnbGFiZWwnICk7XG5cblx0XHR0aGlzLiRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdpbnB1dCcgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICd0eXBlJywgJ2NoZWNrYm94JyApO1xuXHRcdHRoaXMuJGlucHV0LnNldEF0dHJpYnV0ZSggJ2FyaWEtbGFiZWxsZWRieScsIHRoaXMuJG5hbWUuaWQgKTtcblxuXHRcdHRoaXMuJHdpZGdldC5hcHBlbmRDaGlsZCggdGhpcy4kaW5wdXQgKTtcblxuXHRcdHRoaXMuJGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoICdjaGFuZ2UnLCAoKSA9PiB7XG5cdFx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLiRpbnB1dC5jaGVja2VkICk7XG5cdFx0XHR0aGlzLl9jYWxsT25GaW5pc2hDaGFuZ2UoKTtcblx0XHR9ICk7XG5cblx0XHR0aGlzLiRkaXNhYmxlID0gdGhpcy4kaW5wdXQ7XG5cblx0XHR0aGlzLnVwZGF0ZURpc3BsYXkoKTtcblxuXHR9XG5cblx0dXBkYXRlRGlzcGxheSgpIHtcblx0XHR0aGlzLiRpbnB1dC5jaGVja2VkID0gdGhpcy5nZXRWYWx1ZSgpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplQ29sb3JTdHJpbmcoIHN0cmluZyApIHtcblxuXHRsZXQgbWF0Y2gsIHJlc3VsdDtcblxuXHRpZiAoIG1hdGNoID0gc3RyaW5nLm1hdGNoKCAvKCN8MHgpPyhbYS1mMC05XXs2fSkvaSApICkge1xuXG5cdFx0cmVzdWx0ID0gbWF0Y2hbIDIgXTtcblxuXHR9IGVsc2UgaWYgKCBtYXRjaCA9IHN0cmluZy5tYXRjaCggL3JnYlxcKFxccyooXFxkKilcXHMqLFxccyooXFxkKilcXHMqLFxccyooXFxkKilcXHMqXFwpLyApICkge1xuXG5cdFx0cmVzdWx0ID0gcGFyc2VJbnQoIG1hdGNoWyAxIF0gKS50b1N0cmluZyggMTYgKS5wYWRTdGFydCggMiwgMCApXG5cdFx0XHQrIHBhcnNlSW50KCBtYXRjaFsgMiBdICkudG9TdHJpbmcoIDE2ICkucGFkU3RhcnQoIDIsIDAgKVxuXHRcdFx0KyBwYXJzZUludCggbWF0Y2hbIDMgXSApLnRvU3RyaW5nKCAxNiApLnBhZFN0YXJ0KCAyLCAwICk7XG5cblx0fSBlbHNlIGlmICggbWF0Y2ggPSBzdHJpbmcubWF0Y2goIC9eIz8oW2EtZjAtOV0pKFthLWYwLTldKShbYS1mMC05XSkkL2kgKSApIHtcblxuXHRcdHJlc3VsdCA9IG1hdGNoWyAxIF0gKyBtYXRjaFsgMSBdICsgbWF0Y2hbIDIgXSArIG1hdGNoWyAyIF0gKyBtYXRjaFsgMyBdICsgbWF0Y2hbIDMgXTtcblxuXHR9XG5cblx0aWYgKCByZXN1bHQgKSB7XG5cdFx0cmV0dXJuICcjJyArIHJlc3VsdDtcblx0fVxuXG5cdHJldHVybiBmYWxzZTtcblxufVxuXG5jb25zdCBTVFJJTkcgPSB7XG5cdGlzUHJpbWl0aXZlOiB0cnVlLFxuXHRtYXRjaDogdiA9PiB0eXBlb2YgdiA9PT0gJ3N0cmluZycsXG5cdGZyb21IZXhTdHJpbmc6IG5vcm1hbGl6ZUNvbG9yU3RyaW5nLFxuXHR0b0hleFN0cmluZzogbm9ybWFsaXplQ29sb3JTdHJpbmdcbn07XG5cbmNvbnN0IElOVCA9IHtcblx0aXNQcmltaXRpdmU6IHRydWUsXG5cdG1hdGNoOiB2ID0+IHR5cGVvZiB2ID09PSAnbnVtYmVyJyxcblx0ZnJvbUhleFN0cmluZzogc3RyaW5nID0+IHBhcnNlSW50KCBzdHJpbmcuc3Vic3RyaW5nKCAxICksIDE2ICksXG5cdHRvSGV4U3RyaW5nOiB2YWx1ZSA9PiAnIycgKyB2YWx1ZS50b1N0cmluZyggMTYgKS5wYWRTdGFydCggNiwgMCApXG59O1xuXG5jb25zdCBBUlJBWSA9IHtcblx0aXNQcmltaXRpdmU6IGZhbHNlLFxuXG5cdC8vIFRoZSBhcnJvdyBmdW5jdGlvbiBpcyBoZXJlIHRvIGFwcGVhc2UgdHJlZSBzaGFrZXJzIGxpa2UgZXNidWlsZCBvciB3ZWJwYWNrLlxuXHQvLyBTZWUgaHR0cHM6Ly9lc2J1aWxkLmdpdGh1Yi5pby9hcGkvI3RyZWUtc2hha2luZ1xuXHRtYXRjaDogdiA9PiBBcnJheS5pc0FycmF5KCB2ICksXG5cblx0ZnJvbUhleFN0cmluZyggc3RyaW5nLCB0YXJnZXQsIHJnYlNjYWxlID0gMSApIHtcblxuXHRcdGNvbnN0IGludCA9IElOVC5mcm9tSGV4U3RyaW5nKCBzdHJpbmcgKTtcblxuXHRcdHRhcmdldFsgMCBdID0gKCBpbnQgPj4gMTYgJiAyNTUgKSAvIDI1NSAqIHJnYlNjYWxlO1xuXHRcdHRhcmdldFsgMSBdID0gKCBpbnQgPj4gOCAmIDI1NSApIC8gMjU1ICogcmdiU2NhbGU7XG5cdFx0dGFyZ2V0WyAyIF0gPSAoIGludCAmIDI1NSApIC8gMjU1ICogcmdiU2NhbGU7XG5cblx0fSxcblx0dG9IZXhTdHJpbmcoIFsgciwgZywgYiBdLCByZ2JTY2FsZSA9IDEgKSB7XG5cblx0XHRyZ2JTY2FsZSA9IDI1NSAvIHJnYlNjYWxlO1xuXG5cdFx0Y29uc3QgaW50ID0gKCByICogcmdiU2NhbGUgKSA8PCAxNiBeXG5cdFx0XHQoIGcgKiByZ2JTY2FsZSApIDw8IDggXlxuXHRcdFx0KCBiICogcmdiU2NhbGUgKSA8PCAwO1xuXG5cdFx0cmV0dXJuIElOVC50b0hleFN0cmluZyggaW50ICk7XG5cblx0fVxufTtcblxuY29uc3QgT0JKRUNUID0ge1xuXHRpc1ByaW1pdGl2ZTogZmFsc2UsXG5cdG1hdGNoOiB2ID0+IE9iamVjdCggdiApID09PSB2LFxuXHRmcm9tSGV4U3RyaW5nKCBzdHJpbmcsIHRhcmdldCwgcmdiU2NhbGUgPSAxICkge1xuXG5cdFx0Y29uc3QgaW50ID0gSU5ULmZyb21IZXhTdHJpbmcoIHN0cmluZyApO1xuXG5cdFx0dGFyZ2V0LnIgPSAoIGludCA+PiAxNiAmIDI1NSApIC8gMjU1ICogcmdiU2NhbGU7XG5cdFx0dGFyZ2V0LmcgPSAoIGludCA+PiA4ICYgMjU1ICkgLyAyNTUgKiByZ2JTY2FsZTtcblx0XHR0YXJnZXQuYiA9ICggaW50ICYgMjU1ICkgLyAyNTUgKiByZ2JTY2FsZTtcblxuXHR9LFxuXHR0b0hleFN0cmluZyggeyByLCBnLCBiIH0sIHJnYlNjYWxlID0gMSApIHtcblxuXHRcdHJnYlNjYWxlID0gMjU1IC8gcmdiU2NhbGU7XG5cblx0XHRjb25zdCBpbnQgPSAoIHIgKiByZ2JTY2FsZSApIDw8IDE2IF5cblx0XHRcdCggZyAqIHJnYlNjYWxlICkgPDwgOCBeXG5cdFx0XHQoIGIgKiByZ2JTY2FsZSApIDw8IDA7XG5cblx0XHRyZXR1cm4gSU5ULnRvSGV4U3RyaW5nKCBpbnQgKTtcblxuXHR9XG59O1xuXG5jb25zdCBGT1JNQVRTID0gWyBTVFJJTkcsIElOVCwgQVJSQVksIE9CSkVDVCBdO1xuXG5mdW5jdGlvbiBnZXRDb2xvckZvcm1hdCggdmFsdWUgKSB7XG5cdHJldHVybiBGT1JNQVRTLmZpbmQoIGZvcm1hdCA9PiBmb3JtYXQubWF0Y2goIHZhbHVlICkgKTtcbn1cblxuY2xhc3MgQ29sb3JDb250cm9sbGVyIGV4dGVuZHMgQ29udHJvbGxlciB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSwgcmdiU2NhbGUgKSB7XG5cblx0XHRzdXBlciggcGFyZW50LCBvYmplY3QsIHByb3BlcnR5LCAnY29sb3InICk7XG5cblx0XHR0aGlzLiRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdpbnB1dCcgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICd0eXBlJywgJ2NvbG9yJyApO1xuXHRcdHRoaXMuJGlucHV0LnNldEF0dHJpYnV0ZSggJ3RhYmluZGV4JywgLTEgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICdhcmlhLWxhYmVsbGVkYnknLCB0aGlzLiRuYW1lLmlkICk7XG5cblx0XHR0aGlzLiR0ZXh0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggJ2lucHV0JyApO1xuXHRcdHRoaXMuJHRleHQuc2V0QXR0cmlidXRlKCAndHlwZScsICd0ZXh0JyApO1xuXHRcdHRoaXMuJHRleHQuc2V0QXR0cmlidXRlKCAnc3BlbGxjaGVjaycsICdmYWxzZScgKTtcblx0XHR0aGlzLiR0ZXh0LnNldEF0dHJpYnV0ZSggJ2FyaWEtbGFiZWxsZWRieScsIHRoaXMuJG5hbWUuaWQgKTtcblxuXHRcdHRoaXMuJGRpc3BsYXkgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnZGl2JyApO1xuXHRcdHRoaXMuJGRpc3BsYXkuY2xhc3NMaXN0LmFkZCggJ2Rpc3BsYXknICk7XG5cblx0XHR0aGlzLiRkaXNwbGF5LmFwcGVuZENoaWxkKCB0aGlzLiRpbnB1dCApO1xuXHRcdHRoaXMuJHdpZGdldC5hcHBlbmRDaGlsZCggdGhpcy4kZGlzcGxheSApO1xuXHRcdHRoaXMuJHdpZGdldC5hcHBlbmRDaGlsZCggdGhpcy4kdGV4dCApO1xuXG5cdFx0dGhpcy5fZm9ybWF0ID0gZ2V0Q29sb3JGb3JtYXQoIHRoaXMuaW5pdGlhbFZhbHVlICk7XG5cdFx0dGhpcy5fcmdiU2NhbGUgPSByZ2JTY2FsZTtcblxuXHRcdHRoaXMuX2luaXRpYWxWYWx1ZUhleFN0cmluZyA9IHRoaXMuc2F2ZSgpO1xuXHRcdHRoaXMuX3RleHRGb2N1c2VkID0gZmFsc2U7XG5cblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnaW5wdXQnLCAoKSA9PiB7XG5cdFx0XHR0aGlzLl9zZXRWYWx1ZUZyb21IZXhTdHJpbmcoIHRoaXMuJGlucHV0LnZhbHVlICk7XG5cdFx0fSApO1xuXG5cdFx0dGhpcy4kaW5wdXQuYWRkRXZlbnRMaXN0ZW5lciggJ2JsdXInLCAoKSA9PiB7XG5cdFx0XHR0aGlzLl9jYWxsT25GaW5pc2hDaGFuZ2UoKTtcblx0XHR9ICk7XG5cblx0XHR0aGlzLiR0ZXh0LmFkZEV2ZW50TGlzdGVuZXIoICdpbnB1dCcsICgpID0+IHtcblx0XHRcdGNvbnN0IHRyeVBhcnNlID0gbm9ybWFsaXplQ29sb3JTdHJpbmcoIHRoaXMuJHRleHQudmFsdWUgKTtcblx0XHRcdGlmICggdHJ5UGFyc2UgKSB7XG5cdFx0XHRcdHRoaXMuX3NldFZhbHVlRnJvbUhleFN0cmluZyggdHJ5UGFyc2UgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHR0aGlzLiR0ZXh0LmFkZEV2ZW50TGlzdGVuZXIoICdmb2N1cycsICgpID0+IHtcblx0XHRcdHRoaXMuX3RleHRGb2N1c2VkID0gdHJ1ZTtcblx0XHRcdHRoaXMuJHRleHQuc2VsZWN0KCk7XG5cdFx0fSApO1xuXG5cdFx0dGhpcy4kdGV4dC5hZGRFdmVudExpc3RlbmVyKCAnYmx1cicsICgpID0+IHtcblx0XHRcdHRoaXMuX3RleHRGb2N1c2VkID0gZmFsc2U7XG5cdFx0XHR0aGlzLnVwZGF0ZURpc3BsYXkoKTtcblx0XHRcdHRoaXMuX2NhbGxPbkZpbmlzaENoYW5nZSgpO1xuXHRcdH0gKTtcblxuXHRcdHRoaXMuJGRpc2FibGUgPSB0aGlzLiR0ZXh0O1xuXG5cdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cblx0fVxuXG5cdHJlc2V0KCkge1xuXHRcdHRoaXMuX3NldFZhbHVlRnJvbUhleFN0cmluZyggdGhpcy5faW5pdGlhbFZhbHVlSGV4U3RyaW5nICk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRfc2V0VmFsdWVGcm9tSGV4U3RyaW5nKCB2YWx1ZSApIHtcblxuXHRcdGlmICggdGhpcy5fZm9ybWF0LmlzUHJpbWl0aXZlICkge1xuXG5cdFx0XHRjb25zdCBuZXdWYWx1ZSA9IHRoaXMuX2Zvcm1hdC5mcm9tSGV4U3RyaW5nKCB2YWx1ZSApO1xuXHRcdFx0dGhpcy5zZXRWYWx1ZSggbmV3VmFsdWUgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuX2Zvcm1hdC5mcm9tSGV4U3RyaW5nKCB2YWx1ZSwgdGhpcy5nZXRWYWx1ZSgpLCB0aGlzLl9yZ2JTY2FsZSApO1xuXHRcdFx0dGhpcy5fY2FsbE9uQ2hhbmdlKCk7XG5cdFx0XHR0aGlzLnVwZGF0ZURpc3BsYXkoKTtcblxuXHRcdH1cblxuXHR9XG5cblx0c2F2ZSgpIHtcblx0XHRyZXR1cm4gdGhpcy5fZm9ybWF0LnRvSGV4U3RyaW5nKCB0aGlzLmdldFZhbHVlKCksIHRoaXMuX3JnYlNjYWxlICk7XG5cdH1cblxuXHRsb2FkKCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zZXRWYWx1ZUZyb21IZXhTdHJpbmcoIHZhbHVlICk7XG5cdFx0dGhpcy5fY2FsbE9uRmluaXNoQ2hhbmdlKCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHR1cGRhdGVEaXNwbGF5KCkge1xuXHRcdHRoaXMuJGlucHV0LnZhbHVlID0gdGhpcy5fZm9ybWF0LnRvSGV4U3RyaW5nKCB0aGlzLmdldFZhbHVlKCksIHRoaXMuX3JnYlNjYWxlICk7XG5cdFx0aWYgKCAhdGhpcy5fdGV4dEZvY3VzZWQgKSB7XG5cdFx0XHR0aGlzLiR0ZXh0LnZhbHVlID0gdGhpcy4kaW5wdXQudmFsdWUuc3Vic3RyaW5nKCAxICk7XG5cdFx0fVxuXHRcdHRoaXMuJGRpc3BsYXkuc3R5bGUuYmFja2dyb3VuZENvbG9yID0gdGhpcy4kaW5wdXQudmFsdWU7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxufVxuXG5jbGFzcyBGdW5jdGlvbkNvbnRyb2xsZXIgZXh0ZW5kcyBDb250cm9sbGVyIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyZW50LCBvYmplY3QsIHByb3BlcnR5ICkge1xuXG5cdFx0c3VwZXIoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSwgJ2Z1bmN0aW9uJyApO1xuXG5cdFx0Ly8gQnV0dG9ucyBhcmUgdGhlIG9ubHkgY2FzZSB3aGVyZSB3aWRnZXQgY29udGFpbnMgbmFtZVxuXHRcdHRoaXMuJGJ1dHRvbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdidXR0b24nICk7XG5cdFx0dGhpcy4kYnV0dG9uLmFwcGVuZENoaWxkKCB0aGlzLiRuYW1lICk7XG5cdFx0dGhpcy4kd2lkZ2V0LmFwcGVuZENoaWxkKCB0aGlzLiRidXR0b24gKTtcblxuXHRcdHRoaXMuJGJ1dHRvbi5hZGRFdmVudExpc3RlbmVyKCAnY2xpY2snLCBlID0+IHtcblx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdHRoaXMuZ2V0VmFsdWUoKS5jYWxsKCB0aGlzLm9iamVjdCApO1xuXHRcdFx0dGhpcy5fY2FsbE9uQ2hhbmdlKCk7XG5cdFx0fSApO1xuXG5cdFx0Ly8gZW5hYmxlcyA6YWN0aXZlIHBzZXVkbyBjbGFzcyBvbiBtb2JpbGVcblx0XHR0aGlzLiRidXR0b24uYWRkRXZlbnRMaXN0ZW5lciggJ3RvdWNoc3RhcnQnLCAoKSA9PiB7fSwgeyBwYXNzaXZlOiB0cnVlIH0gKTtcblxuXHRcdHRoaXMuJGRpc2FibGUgPSB0aGlzLiRidXR0b247XG5cblx0fVxuXG59XG5cbmNsYXNzIE51bWJlckNvbnRyb2xsZXIgZXh0ZW5kcyBDb250cm9sbGVyIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyZW50LCBvYmplY3QsIHByb3BlcnR5LCBtaW4sIG1heCwgc3RlcCApIHtcblxuXHRcdHN1cGVyKCBwYXJlbnQsIG9iamVjdCwgcHJvcGVydHksICdudW1iZXInICk7XG5cblx0XHR0aGlzLl9pbml0SW5wdXQoKTtcblxuXHRcdHRoaXMubWluKCBtaW4gKTtcblx0XHR0aGlzLm1heCggbWF4ICk7XG5cblx0XHRjb25zdCBzdGVwRXhwbGljaXQgPSBzdGVwICE9PSB1bmRlZmluZWQ7XG5cdFx0dGhpcy5zdGVwKCBzdGVwRXhwbGljaXQgPyBzdGVwIDogdGhpcy5fZ2V0SW1wbGljaXRTdGVwKCksIHN0ZXBFeHBsaWNpdCApO1xuXG5cdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cblx0fVxuXG5cdGRlY2ltYWxzKCBkZWNpbWFscyApIHtcblx0XHR0aGlzLl9kZWNpbWFscyA9IGRlY2ltYWxzO1xuXHRcdHRoaXMudXBkYXRlRGlzcGxheSgpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0bWluKCBtaW4gKSB7XG5cdFx0dGhpcy5fbWluID0gbWluO1xuXHRcdHRoaXMuX29uVXBkYXRlTWluTWF4KCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRtYXgoIG1heCApIHtcblx0XHR0aGlzLl9tYXggPSBtYXg7XG5cdFx0dGhpcy5fb25VcGRhdGVNaW5NYXgoKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdHN0ZXAoIHN0ZXAsIGV4cGxpY2l0ID0gdHJ1ZSApIHtcblx0XHR0aGlzLl9zdGVwID0gc3RlcDtcblx0XHR0aGlzLl9zdGVwRXhwbGljaXQgPSBleHBsaWNpdDtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdHVwZGF0ZURpc3BsYXkoKSB7XG5cblx0XHRjb25zdCB2YWx1ZSA9IHRoaXMuZ2V0VmFsdWUoKTtcblxuXHRcdGlmICggdGhpcy5faGFzU2xpZGVyICkge1xuXG5cdFx0XHRsZXQgcGVyY2VudCA9ICggdmFsdWUgLSB0aGlzLl9taW4gKSAvICggdGhpcy5fbWF4IC0gdGhpcy5fbWluICk7XG5cdFx0XHRwZXJjZW50ID0gTWF0aC5tYXgoIDAsIE1hdGgubWluKCBwZXJjZW50LCAxICkgKTtcblxuXHRcdFx0dGhpcy4kZmlsbC5zdHlsZS53aWR0aCA9IHBlcmNlbnQgKiAxMDAgKyAnJSc7XG5cblx0XHR9XG5cblx0XHRpZiAoICF0aGlzLl9pbnB1dEZvY3VzZWQgKSB7XG5cdFx0XHR0aGlzLiRpbnB1dC52YWx1ZSA9IHRoaXMuX2RlY2ltYWxzID09PSB1bmRlZmluZWQgPyB2YWx1ZSA6IHZhbHVlLnRvRml4ZWQoIHRoaXMuX2RlY2ltYWxzICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdF9pbml0SW5wdXQoKSB7XG5cblx0XHR0aGlzLiRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdpbnB1dCcgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICd0eXBlJywgJ3RleHQnICk7XG5cdFx0dGhpcy4kaW5wdXQuc2V0QXR0cmlidXRlKCAnYXJpYS1sYWJlbGxlZGJ5JywgdGhpcy4kbmFtZS5pZCApO1xuXG5cdFx0Ly8gT24gdG91Y2ggZGV2aWNlcyBvbmx5LCB1c2UgaW5wdXRbdHlwZT1udW1iZXJdIHRvIGZvcmNlIGEgbnVtZXJpYyBrZXlib2FyZC5cblx0XHQvLyBJZGVhbGx5IHdlIGNvdWxkIHVzZSBvbmUgaW5wdXQgdHlwZSBldmVyeXdoZXJlLCBidXQgW3R5cGU9bnVtYmVyXSBoYXMgcXVpcmtzXG5cdFx0Ly8gb24gZGVza3RvcCwgYW5kIFtpbnB1dG1vZGU9ZGVjaW1hbF0gaGFzIHF1aXJrcyBvbiBpT1MuXG5cdFx0Ly8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9nZW9yZ2VhbHdheXMvbGlsLWd1aS9wdWxsLzE2XG5cblx0XHRjb25zdCBpc1RvdWNoID0gd2luZG93Lm1hdGNoTWVkaWEoICcocG9pbnRlcjogY29hcnNlKScgKS5tYXRjaGVzO1xuXG5cdFx0aWYgKCBpc1RvdWNoICkge1xuXHRcdFx0dGhpcy4kaW5wdXQuc2V0QXR0cmlidXRlKCAndHlwZScsICdudW1iZXInICk7XG5cdFx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICdzdGVwJywgJ2FueScgKTtcblx0XHR9XG5cblx0XHR0aGlzLiR3aWRnZXQuYXBwZW5kQ2hpbGQoIHRoaXMuJGlucHV0ICk7XG5cblx0XHR0aGlzLiRkaXNhYmxlID0gdGhpcy4kaW5wdXQ7XG5cblx0XHRjb25zdCBvbklucHV0ID0gKCkgPT4ge1xuXG5cdFx0XHRsZXQgdmFsdWUgPSBwYXJzZUZsb2F0KCB0aGlzLiRpbnB1dC52YWx1ZSApO1xuXG5cdFx0XHRpZiAoIGlzTmFOKCB2YWx1ZSApICkgcmV0dXJuO1xuXG5cdFx0XHRpZiAoIHRoaXMuX3N0ZXBFeHBsaWNpdCApIHtcblx0XHRcdFx0dmFsdWUgPSB0aGlzLl9zbmFwKCB2YWx1ZSApO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLl9jbGFtcCggdmFsdWUgKSApO1xuXG5cdFx0fTtcblxuXHRcdC8vIEtleXMgJiBtb3VzZSB3aGVlbFxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0Y29uc3QgaW5jcmVtZW50ID0gZGVsdGEgPT4ge1xuXG5cdFx0XHRjb25zdCB2YWx1ZSA9IHBhcnNlRmxvYXQoIHRoaXMuJGlucHV0LnZhbHVlICk7XG5cblx0XHRcdGlmICggaXNOYU4oIHZhbHVlICkgKSByZXR1cm47XG5cblx0XHRcdHRoaXMuX3NuYXBDbGFtcFNldFZhbHVlKCB2YWx1ZSArIGRlbHRhICk7XG5cblx0XHRcdC8vIEZvcmNlIHRoZSBpbnB1dCB0byB1cGRhdGVEaXNwbGF5IHdoZW4gaXQncyBmb2N1c2VkXG5cdFx0XHR0aGlzLiRpbnB1dC52YWx1ZSA9IHRoaXMuZ2V0VmFsdWUoKTtcblxuXHRcdH07XG5cblx0XHRjb25zdCBvbktleURvd24gPSBlID0+IHtcblx0XHRcdC8vIFVzaW5nIGBlLmtleWAgaW5zdGVhZCBvZiBgZS5jb2RlYCBhbHNvIGNhdGNoZXMgTnVtcGFkRW50ZXJcblx0XHRcdGlmICggZS5rZXkgPT09ICdFbnRlcicgKSB7XG5cdFx0XHRcdHRoaXMuJGlucHV0LmJsdXIoKTtcblx0XHRcdH1cblx0XHRcdGlmICggZS5jb2RlID09PSAnQXJyb3dVcCcgKSB7XG5cdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0aW5jcmVtZW50KCB0aGlzLl9zdGVwICogdGhpcy5fYXJyb3dLZXlNdWx0aXBsaWVyKCBlICkgKTtcblx0XHRcdH1cblx0XHRcdGlmICggZS5jb2RlID09PSAnQXJyb3dEb3duJyApIHtcblx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRpbmNyZW1lbnQoIHRoaXMuX3N0ZXAgKiB0aGlzLl9hcnJvd0tleU11bHRpcGxpZXIoIGUgKSAqIC0xICk7XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdGNvbnN0IG9uV2hlZWwgPSBlID0+IHtcblx0XHRcdGlmICggdGhpcy5faW5wdXRGb2N1c2VkICkge1xuXHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdGluY3JlbWVudCggdGhpcy5fc3RlcCAqIHRoaXMuX25vcm1hbGl6ZU1vdXNlV2hlZWwoIGUgKSApO1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHQvLyBWZXJ0aWNhbCBkcmFnXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0XHRsZXQgdGVzdGluZ0ZvclZlcnRpY2FsRHJhZyA9IGZhbHNlLFxuXHRcdFx0aW5pdENsaWVudFgsXG5cdFx0XHRpbml0Q2xpZW50WSxcblx0XHRcdHByZXZDbGllbnRZLFxuXHRcdFx0aW5pdFZhbHVlLFxuXHRcdFx0ZHJhZ0RlbHRhO1xuXG5cdFx0Ly8gT25jZSB0aGUgbW91c2UgaXMgZHJhZ2dlZCBtb3JlIHRoYW4gRFJBR19USFJFU0ggcHggb24gYW55IGF4aXMsIHdlIGRlY2lkZVxuXHRcdC8vIG9uIHRoZSB1c2VyJ3MgaW50ZW50OiBob3Jpem9udGFsIG1lYW5zIGhpZ2hsaWdodCwgdmVydGljYWwgbWVhbnMgZHJhZy5cblx0XHRjb25zdCBEUkFHX1RIUkVTSCA9IDU7XG5cblx0XHRjb25zdCBvbk1vdXNlRG93biA9IGUgPT4ge1xuXG5cdFx0XHRpbml0Q2xpZW50WCA9IGUuY2xpZW50WDtcblx0XHRcdGluaXRDbGllbnRZID0gcHJldkNsaWVudFkgPSBlLmNsaWVudFk7XG5cdFx0XHR0ZXN0aW5nRm9yVmVydGljYWxEcmFnID0gdHJ1ZTtcblxuXHRcdFx0aW5pdFZhbHVlID0gdGhpcy5nZXRWYWx1ZSgpO1xuXHRcdFx0ZHJhZ0RlbHRhID0gMDtcblxuXHRcdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoICdtb3VzZW1vdmUnLCBvbk1vdXNlTW92ZSApO1xuXHRcdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoICdtb3VzZXVwJywgb25Nb3VzZVVwICk7XG5cblx0XHR9O1xuXG5cdFx0Y29uc3Qgb25Nb3VzZU1vdmUgPSBlID0+IHtcblxuXHRcdFx0aWYgKCB0ZXN0aW5nRm9yVmVydGljYWxEcmFnICkge1xuXG5cdFx0XHRcdGNvbnN0IGR4ID0gZS5jbGllbnRYIC0gaW5pdENsaWVudFg7XG5cdFx0XHRcdGNvbnN0IGR5ID0gZS5jbGllbnRZIC0gaW5pdENsaWVudFk7XG5cblx0XHRcdFx0aWYgKCBNYXRoLmFicyggZHkgKSA+IERSQUdfVEhSRVNIICkge1xuXG5cdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdHRoaXMuJGlucHV0LmJsdXIoKTtcblx0XHRcdFx0XHR0ZXN0aW5nRm9yVmVydGljYWxEcmFnID0gZmFsc2U7XG5cdFx0XHRcdFx0dGhpcy5fc2V0RHJhZ2dpbmdTdHlsZSggdHJ1ZSwgJ3ZlcnRpY2FsJyApO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIE1hdGguYWJzKCBkeCApID4gRFJBR19USFJFU0ggKSB7XG5cblx0XHRcdFx0XHRvbk1vdXNlVXAoKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gVGhpcyBpc24ndCBhbiBlbHNlIHNvIHRoYXQgdGhlIGZpcnN0IG1vdmUgY291bnRzIHRvd2FyZHMgZHJhZ0RlbHRhXG5cdFx0XHRpZiAoICF0ZXN0aW5nRm9yVmVydGljYWxEcmFnICkge1xuXG5cdFx0XHRcdGNvbnN0IGR5ID0gZS5jbGllbnRZIC0gcHJldkNsaWVudFk7XG5cblx0XHRcdFx0ZHJhZ0RlbHRhIC09IGR5ICogdGhpcy5fc3RlcCAqIHRoaXMuX2Fycm93S2V5TXVsdGlwbGllciggZSApO1xuXG5cdFx0XHRcdC8vIENsYW1wIGRyYWdEZWx0YSBzbyB3ZSBkb24ndCBoYXZlICdkZWFkIHNwYWNlJyBhZnRlciBkcmFnZ2luZyBwYXN0IGJvdW5kcy5cblx0XHRcdFx0Ly8gV2UncmUgb2theSB3aXRoIHRoZSBmYWN0IHRoYXQgYm91bmRzIGNhbiBiZSB1bmRlZmluZWQgaGVyZS5cblx0XHRcdFx0aWYgKCBpbml0VmFsdWUgKyBkcmFnRGVsdGEgPiB0aGlzLl9tYXggKSB7XG5cdFx0XHRcdFx0ZHJhZ0RlbHRhID0gdGhpcy5fbWF4IC0gaW5pdFZhbHVlO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCBpbml0VmFsdWUgKyBkcmFnRGVsdGEgPCB0aGlzLl9taW4gKSB7XG5cdFx0XHRcdFx0ZHJhZ0RlbHRhID0gdGhpcy5fbWluIC0gaW5pdFZhbHVlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0dGhpcy5fc25hcENsYW1wU2V0VmFsdWUoIGluaXRWYWx1ZSArIGRyYWdEZWx0YSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHByZXZDbGllbnRZID0gZS5jbGllbnRZO1xuXG5cdFx0fTtcblxuXHRcdGNvbnN0IG9uTW91c2VVcCA9ICgpID0+IHtcblx0XHRcdHRoaXMuX3NldERyYWdnaW5nU3R5bGUoIGZhbHNlLCAndmVydGljYWwnICk7XG5cdFx0XHR0aGlzLl9jYWxsT25GaW5pc2hDaGFuZ2UoKTtcblx0XHRcdHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCAnbW91c2Vtb3ZlJywgb25Nb3VzZU1vdmUgKTtcblx0XHRcdHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCAnbW91c2V1cCcsIG9uTW91c2VVcCApO1xuXHRcdH07XG5cblx0XHQvLyBGb2N1cyBzdGF0ZSAmIG9uRmluaXNoQ2hhbmdlXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0XHRjb25zdCBvbkZvY3VzID0gKCkgPT4ge1xuXHRcdFx0dGhpcy5faW5wdXRGb2N1c2VkID0gdHJ1ZTtcblx0XHR9O1xuXG5cdFx0Y29uc3Qgb25CbHVyID0gKCkgPT4ge1xuXHRcdFx0dGhpcy5faW5wdXRGb2N1c2VkID0gZmFsc2U7XG5cdFx0XHR0aGlzLnVwZGF0ZURpc3BsYXkoKTtcblx0XHRcdHRoaXMuX2NhbGxPbkZpbmlzaENoYW5nZSgpO1xuXHRcdH07XG5cblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnaW5wdXQnLCBvbklucHV0ICk7XG5cdFx0dGhpcy4kaW5wdXQuYWRkRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCBvbktleURvd24gKTtcblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnd2hlZWwnLCBvbldoZWVsLCB7IHBhc3NpdmU6IGZhbHNlIH0gKTtcblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnbW91c2Vkb3duJywgb25Nb3VzZURvd24gKTtcblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnZm9jdXMnLCBvbkZvY3VzICk7XG5cdFx0dGhpcy4kaW5wdXQuYWRkRXZlbnRMaXN0ZW5lciggJ2JsdXInLCBvbkJsdXIgKTtcblxuXHR9XG5cblx0X2luaXRTbGlkZXIoKSB7XG5cblx0XHR0aGlzLl9oYXNTbGlkZXIgPSB0cnVlO1xuXG5cdFx0Ly8gQnVpbGQgRE9NXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0XHR0aGlzLiRzbGlkZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnZGl2JyApO1xuXHRcdHRoaXMuJHNsaWRlci5jbGFzc0xpc3QuYWRkKCAnc2xpZGVyJyApO1xuXG5cdFx0dGhpcy4kZmlsbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdkaXYnICk7XG5cdFx0dGhpcy4kZmlsbC5jbGFzc0xpc3QuYWRkKCAnZmlsbCcgKTtcblxuXHRcdHRoaXMuJHNsaWRlci5hcHBlbmRDaGlsZCggdGhpcy4kZmlsbCApO1xuXHRcdHRoaXMuJHdpZGdldC5pbnNlcnRCZWZvcmUoIHRoaXMuJHNsaWRlciwgdGhpcy4kaW5wdXQgKTtcblxuXHRcdHRoaXMuZG9tRWxlbWVudC5jbGFzc0xpc3QuYWRkKCAnaGFzU2xpZGVyJyApO1xuXG5cdFx0Ly8gTWFwIGNsaWVudFggdG8gdmFsdWVcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRcdGNvbnN0IG1hcCA9ICggdiwgYSwgYiwgYywgZCApID0+IHtcblx0XHRcdHJldHVybiAoIHYgLSBhICkgLyAoIGIgLSBhICkgKiAoIGQgLSBjICkgKyBjO1xuXHRcdH07XG5cblx0XHRjb25zdCBzZXRWYWx1ZUZyb21YID0gY2xpZW50WCA9PiB7XG5cdFx0XHRjb25zdCByZWN0ID0gdGhpcy4kc2xpZGVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXHRcdFx0bGV0IHZhbHVlID0gbWFwKCBjbGllbnRYLCByZWN0LmxlZnQsIHJlY3QucmlnaHQsIHRoaXMuX21pbiwgdGhpcy5fbWF4ICk7XG5cdFx0XHR0aGlzLl9zbmFwQ2xhbXBTZXRWYWx1ZSggdmFsdWUgKTtcblx0XHR9O1xuXG5cdFx0Ly8gTW91c2UgZHJhZ1xuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0Y29uc3QgbW91c2VEb3duID0gZSA9PiB7XG5cdFx0XHR0aGlzLl9zZXREcmFnZ2luZ1N0eWxlKCB0cnVlICk7XG5cdFx0XHRzZXRWYWx1ZUZyb21YKCBlLmNsaWVudFggKTtcblx0XHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCAnbW91c2Vtb3ZlJywgbW91c2VNb3ZlICk7XG5cdFx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lciggJ21vdXNldXAnLCBtb3VzZVVwICk7XG5cdFx0fTtcblxuXHRcdGNvbnN0IG1vdXNlTW92ZSA9IGUgPT4ge1xuXHRcdFx0c2V0VmFsdWVGcm9tWCggZS5jbGllbnRYICk7XG5cdFx0fTtcblxuXHRcdGNvbnN0IG1vdXNlVXAgPSAoKSA9PiB7XG5cdFx0XHR0aGlzLl9jYWxsT25GaW5pc2hDaGFuZ2UoKTtcblx0XHRcdHRoaXMuX3NldERyYWdnaW5nU3R5bGUoIGZhbHNlICk7XG5cdFx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ21vdXNlbW92ZScsIG1vdXNlTW92ZSApO1xuXHRcdFx0d2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoICdtb3VzZXVwJywgbW91c2VVcCApO1xuXHRcdH07XG5cblx0XHQvLyBUb3VjaCBkcmFnXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0XHRsZXQgdGVzdGluZ0ZvclNjcm9sbCA9IGZhbHNlLCBwcmV2Q2xpZW50WCwgcHJldkNsaWVudFk7XG5cblx0XHRjb25zdCBiZWdpblRvdWNoRHJhZyA9IGUgPT4ge1xuXHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0dGhpcy5fc2V0RHJhZ2dpbmdTdHlsZSggdHJ1ZSApO1xuXHRcdFx0c2V0VmFsdWVGcm9tWCggZS50b3VjaGVzWyAwIF0uY2xpZW50WCApO1xuXHRcdFx0dGVzdGluZ0ZvclNjcm9sbCA9IGZhbHNlO1xuXHRcdH07XG5cblx0XHRjb25zdCBvblRvdWNoU3RhcnQgPSBlID0+IHtcblxuXHRcdFx0aWYgKCBlLnRvdWNoZXMubGVuZ3RoID4gMSApIHJldHVybjtcblxuXHRcdFx0Ly8gSWYgd2UncmUgaW4gYSBzY3JvbGxhYmxlIGNvbnRhaW5lciwgd2Ugc2hvdWxkIHdhaXQgZm9yIHRoZSBmaXJzdFxuXHRcdFx0Ly8gdG91Y2htb3ZlIHRvIHNlZSBpZiB0aGUgdXNlciBpcyB0cnlpbmcgdG8gc2xpZGUgb3Igc2Nyb2xsLlxuXHRcdFx0aWYgKCB0aGlzLl9oYXNTY3JvbGxCYXIgKSB7XG5cblx0XHRcdFx0cHJldkNsaWVudFggPSBlLnRvdWNoZXNbIDAgXS5jbGllbnRYO1xuXHRcdFx0XHRwcmV2Q2xpZW50WSA9IGUudG91Y2hlc1sgMCBdLmNsaWVudFk7XG5cdFx0XHRcdHRlc3RpbmdGb3JTY3JvbGwgPSB0cnVlO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIE90aGVyd2lzZSwgd2UgY2FuIHNldCB0aGUgdmFsdWUgc3RyYWlnaHQgYXdheSBvbiB0b3VjaHN0YXJ0LlxuXHRcdFx0XHRiZWdpblRvdWNoRHJhZyggZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCAndG91Y2htb3ZlJywgb25Ub3VjaE1vdmUsIHsgcGFzc2l2ZTogZmFsc2UgfSApO1xuXHRcdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoICd0b3VjaGVuZCcsIG9uVG91Y2hFbmQgKTtcblxuXHRcdH07XG5cblx0XHRjb25zdCBvblRvdWNoTW92ZSA9IGUgPT4ge1xuXG5cdFx0XHRpZiAoIHRlc3RpbmdGb3JTY3JvbGwgKSB7XG5cblx0XHRcdFx0Y29uc3QgZHggPSBlLnRvdWNoZXNbIDAgXS5jbGllbnRYIC0gcHJldkNsaWVudFg7XG5cdFx0XHRcdGNvbnN0IGR5ID0gZS50b3VjaGVzWyAwIF0uY2xpZW50WSAtIHByZXZDbGllbnRZO1xuXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIGR4ICkgPiBNYXRoLmFicyggZHkgKSApIHtcblxuXHRcdFx0XHRcdC8vIFdlIG1vdmVkIGhvcml6b250YWxseSwgc2V0IHRoZSB2YWx1ZSBhbmQgc3RvcCBjaGVja2luZy5cblx0XHRcdFx0XHRiZWdpblRvdWNoRHJhZyggZSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBUaGlzIHdhcywgaW4gZmFjdCwgYW4gYXR0ZW1wdCB0byBzY3JvbGwuIEFib3J0LlxuXHRcdFx0XHRcdHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCAndG91Y2htb3ZlJywgb25Ub3VjaE1vdmUgKTtcblx0XHRcdFx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3RvdWNoZW5kJywgb25Ub3VjaEVuZCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdHNldFZhbHVlRnJvbVgoIGUudG91Y2hlc1sgMCBdLmNsaWVudFggKTtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdGNvbnN0IG9uVG91Y2hFbmQgPSAoKSA9PiB7XG5cdFx0XHR0aGlzLl9jYWxsT25GaW5pc2hDaGFuZ2UoKTtcblx0XHRcdHRoaXMuX3NldERyYWdnaW5nU3R5bGUoIGZhbHNlICk7XG5cdFx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3RvdWNobW92ZScsIG9uVG91Y2hNb3ZlICk7XG5cdFx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3RvdWNoZW5kJywgb25Ub3VjaEVuZCApO1xuXHRcdH07XG5cblx0XHQvLyBNb3VzZSB3aGVlbFxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0Ly8gV2UgaGF2ZSB0byB1c2UgYSBkZWJvdW5jZWQgZnVuY3Rpb24gdG8gY2FsbCBvbkZpbmlzaENoYW5nZSBiZWNhdXNlXG5cdFx0Ly8gdGhlcmUncyBubyB3YXkgdG8gdGVsbCB3aGVuIHRoZSB1c2VyIGlzIFwiZG9uZVwiIG1vdXNlLXdoZWVsaW5nLlxuXHRcdGNvbnN0IGNhbGxPbkZpbmlzaENoYW5nZSA9IHRoaXMuX2NhbGxPbkZpbmlzaENoYW5nZS5iaW5kKCB0aGlzICk7XG5cdFx0Y29uc3QgV0hFRUxfREVCT1VOQ0VfVElNRSA9IDQwMDtcblx0XHRsZXQgd2hlZWxGaW5pc2hDaGFuZ2VUaW1lb3V0O1xuXG5cdFx0Y29uc3Qgb25XaGVlbCA9IGUgPT4ge1xuXG5cdFx0XHQvLyBpZ25vcmUgdmVydGljYWwgd2hlZWxzIGlmIHRoZXJlJ3MgYSBzY3JvbGxiYXJcblx0XHRcdGNvbnN0IGlzVmVydGljYWwgPSBNYXRoLmFicyggZS5kZWx0YVggKSA8IE1hdGguYWJzKCBlLmRlbHRhWSApO1xuXHRcdFx0aWYgKCBpc1ZlcnRpY2FsICYmIHRoaXMuX2hhc1Njcm9sbEJhciApIHJldHVybjtcblxuXHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHQvLyBzZXQgdmFsdWVcblx0XHRcdGNvbnN0IGRlbHRhID0gdGhpcy5fbm9ybWFsaXplTW91c2VXaGVlbCggZSApICogdGhpcy5fc3RlcDtcblx0XHRcdHRoaXMuX3NuYXBDbGFtcFNldFZhbHVlKCB0aGlzLmdldFZhbHVlKCkgKyBkZWx0YSApO1xuXG5cdFx0XHQvLyBmb3JjZSB0aGUgaW5wdXQgdG8gdXBkYXRlRGlzcGxheSB3aGVuIGl0J3MgZm9jdXNlZFxuXHRcdFx0dGhpcy4kaW5wdXQudmFsdWUgPSB0aGlzLmdldFZhbHVlKCk7XG5cblx0XHRcdC8vIGRlYm91bmNlIG9uRmluaXNoQ2hhbmdlXG5cdFx0XHRjbGVhclRpbWVvdXQoIHdoZWVsRmluaXNoQ2hhbmdlVGltZW91dCApO1xuXHRcdFx0d2hlZWxGaW5pc2hDaGFuZ2VUaW1lb3V0ID0gc2V0VGltZW91dCggY2FsbE9uRmluaXNoQ2hhbmdlLCBXSEVFTF9ERUJPVU5DRV9USU1FICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy4kc2xpZGVyLmFkZEV2ZW50TGlzdGVuZXIoICdtb3VzZWRvd24nLCBtb3VzZURvd24gKTtcblx0XHR0aGlzLiRzbGlkZXIuYWRkRXZlbnRMaXN0ZW5lciggJ3RvdWNoc3RhcnQnLCBvblRvdWNoU3RhcnQsIHsgcGFzc2l2ZTogZmFsc2UgfSApO1xuXHRcdHRoaXMuJHNsaWRlci5hZGRFdmVudExpc3RlbmVyKCAnd2hlZWwnLCBvbldoZWVsLCB7IHBhc3NpdmU6IGZhbHNlIH0gKTtcblxuXHR9XG5cblx0X3NldERyYWdnaW5nU3R5bGUoIGFjdGl2ZSwgYXhpcyA9ICdob3Jpem9udGFsJyApIHtcblx0XHRpZiAoIHRoaXMuJHNsaWRlciApIHtcblx0XHRcdHRoaXMuJHNsaWRlci5jbGFzc0xpc3QudG9nZ2xlKCAnYWN0aXZlJywgYWN0aXZlICk7XG5cdFx0fVxuXHRcdGRvY3VtZW50LmJvZHkuY2xhc3NMaXN0LnRvZ2dsZSggJ2xpbC1ndWktZHJhZ2dpbmcnLCBhY3RpdmUgKTtcblx0XHRkb2N1bWVudC5ib2R5LmNsYXNzTGlzdC50b2dnbGUoIGBsaWwtZ3VpLSR7YXhpc31gLCBhY3RpdmUgKTtcblx0fVxuXG5cdF9nZXRJbXBsaWNpdFN0ZXAoKSB7XG5cblx0XHRpZiAoIHRoaXMuX2hhc01pbiAmJiB0aGlzLl9oYXNNYXggKSB7XG5cdFx0XHRyZXR1cm4gKCB0aGlzLl9tYXggLSB0aGlzLl9taW4gKSAvIDEwMDA7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIDAuMTtcblxuXHR9XG5cblx0X29uVXBkYXRlTWluTWF4KCkge1xuXG5cdFx0aWYgKCAhdGhpcy5faGFzU2xpZGVyICYmIHRoaXMuX2hhc01pbiAmJiB0aGlzLl9oYXNNYXggKSB7XG5cblx0XHRcdC8vIElmIHRoaXMgaXMgdGhlIGZpcnN0IHRpbWUgd2UncmUgaGVhcmluZyBhYm91dCBtaW4gYW5kIG1heFxuXHRcdFx0Ly8gYW5kIHdlIGhhdmVuJ3QgZXhwbGljaXRseSBzdGF0ZWQgd2hhdCBvdXIgc3RlcCBpcywgbGV0J3Ncblx0XHRcdC8vIHVwZGF0ZSB0aGF0IHRvby5cblx0XHRcdGlmICggIXRoaXMuX3N0ZXBFeHBsaWNpdCApIHtcblx0XHRcdFx0dGhpcy5zdGVwKCB0aGlzLl9nZXRJbXBsaWNpdFN0ZXAoKSwgZmFsc2UgKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5faW5pdFNsaWRlcigpO1xuXHRcdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cblx0XHR9XG5cblx0fVxuXG5cdF9ub3JtYWxpemVNb3VzZVdoZWVsKCBlICkge1xuXG5cdFx0bGV0IHsgZGVsdGFYLCBkZWx0YVkgfSA9IGU7XG5cblx0XHQvLyBTYWZhcmkgYW5kIENocm9tZSByZXBvcnQgd2VpcmQgbm9uLWludGVncmFsIHZhbHVlcyBmb3IgYSBub3RjaGVkIHdoZWVsLFxuXHRcdC8vIGJ1dCBzdGlsbCBleHBvc2UgYWN0dWFsIGxpbmVzIHNjcm9sbGVkIHZpYSB3aGVlbERlbHRhLiBOb3RjaGVkIHdoZWVsc1xuXHRcdC8vIHNob3VsZCBiZWhhdmUgdGhlIHNhbWUgd2F5IGFzIGFycm93IGtleXMuXG5cdFx0aWYgKCBNYXRoLmZsb29yKCBlLmRlbHRhWSApICE9PSBlLmRlbHRhWSAmJiBlLndoZWVsRGVsdGEgKSB7XG5cdFx0XHRkZWx0YVggPSAwO1xuXHRcdFx0ZGVsdGFZID0gLWUud2hlZWxEZWx0YSAvIDEyMDtcblx0XHRcdGRlbHRhWSAqPSB0aGlzLl9zdGVwRXhwbGljaXQgPyAxIDogMTA7XG5cdFx0fVxuXG5cdFx0Y29uc3Qgd2hlZWwgPSBkZWx0YVggKyAtZGVsdGFZO1xuXG5cdFx0cmV0dXJuIHdoZWVsO1xuXG5cdH1cblxuXHRfYXJyb3dLZXlNdWx0aXBsaWVyKCBlICkge1xuXG5cdFx0bGV0IG11bHQgPSB0aGlzLl9zdGVwRXhwbGljaXQgPyAxIDogMTA7XG5cblx0XHRpZiAoIGUuc2hpZnRLZXkgKSB7XG5cdFx0XHRtdWx0ICo9IDEwO1xuXHRcdH0gZWxzZSBpZiAoIGUuYWx0S2V5ICkge1xuXHRcdFx0bXVsdCAvPSAxMDtcblx0XHR9XG5cblx0XHRyZXR1cm4gbXVsdDtcblxuXHR9XG5cblx0X3NuYXAoIHZhbHVlICkge1xuXG5cdFx0Ly8gVGhpcyB3b3VsZCBiZSB0aGUgbG9naWNhbCB3YXkgdG8gZG8gdGhpbmdzLCBidXQgZmxvYXRpbmcgcG9pbnQgZXJyb3JzLlxuXHRcdC8vIHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAvIHRoaXMuX3N0ZXAgKSAqIHRoaXMuX3N0ZXA7XG5cblx0XHQvLyBVc2luZyBpbnZlcnNlIHN0ZXAgc29sdmVzIGEgbG90IG9mIHRoZW0sIGJ1dCBub3QgYWxsXG5cdFx0Ly8gY29uc3QgaW52ZXJzZVN0ZXAgPSAxIC8gdGhpcy5fc3RlcDtcblx0XHQvLyByZXR1cm4gTWF0aC5yb3VuZCggdmFsdWUgKiBpbnZlcnNlU3RlcCApIC8gaW52ZXJzZVN0ZXA7XG5cblx0XHQvLyBOb3QgaGFwcHkgYWJvdXQgdGhpcywgYnV0IGhhdmVuJ3Qgc2VlbiBpdCBicmVhay5cblx0XHRjb25zdCByID0gTWF0aC5yb3VuZCggdmFsdWUgLyB0aGlzLl9zdGVwICkgKiB0aGlzLl9zdGVwO1xuXHRcdHJldHVybiBwYXJzZUZsb2F0KCByLnRvUHJlY2lzaW9uKCAxNSApICk7XG5cblx0fVxuXG5cdF9jbGFtcCggdmFsdWUgKSB7XG5cdFx0Ly8gZWl0aGVyIGNvbmRpdGlvbiBpcyBmYWxzZSBpZiBtaW4gb3IgbWF4IGlzIHVuZGVmaW5lZFxuXHRcdGlmICggdmFsdWUgPCB0aGlzLl9taW4gKSB2YWx1ZSA9IHRoaXMuX21pbjtcblx0XHRpZiAoIHZhbHVlID4gdGhpcy5fbWF4ICkgdmFsdWUgPSB0aGlzLl9tYXg7XG5cdFx0cmV0dXJuIHZhbHVlO1xuXHR9XG5cblx0X3NuYXBDbGFtcFNldFZhbHVlKCB2YWx1ZSApIHtcblx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLl9jbGFtcCggdGhpcy5fc25hcCggdmFsdWUgKSApICk7XG5cdH1cblxuXHRnZXQgX2hhc1Njcm9sbEJhcigpIHtcblx0XHRjb25zdCByb290ID0gdGhpcy5wYXJlbnQucm9vdC4kY2hpbGRyZW47XG5cdFx0cmV0dXJuIHJvb3Quc2Nyb2xsSGVpZ2h0ID4gcm9vdC5jbGllbnRIZWlnaHQ7XG5cdH1cblxuXHRnZXQgX2hhc01pbigpIHtcblx0XHRyZXR1cm4gdGhpcy5fbWluICE9PSB1bmRlZmluZWQ7XG5cdH1cblxuXHRnZXQgX2hhc01heCgpIHtcblx0XHRyZXR1cm4gdGhpcy5fbWF4ICE9PSB1bmRlZmluZWQ7XG5cdH1cblxufVxuXG5jbGFzcyBPcHRpb25Db250cm9sbGVyIGV4dGVuZHMgQ29udHJvbGxlciB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSwgb3B0aW9ucyApIHtcblxuXHRcdHN1cGVyKCBwYXJlbnQsIG9iamVjdCwgcHJvcGVydHksICdvcHRpb24nICk7XG5cblx0XHR0aGlzLiRzZWxlY3QgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnc2VsZWN0JyApO1xuXHRcdHRoaXMuJHNlbGVjdC5zZXRBdHRyaWJ1dGUoICdhcmlhLWxhYmVsbGVkYnknLCB0aGlzLiRuYW1lLmlkICk7XG5cblx0XHR0aGlzLiRkaXNwbGF5ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggJ2RpdicgKTtcblx0XHR0aGlzLiRkaXNwbGF5LmNsYXNzTGlzdC5hZGQoICdkaXNwbGF5JyApO1xuXG5cdFx0dGhpcy4kc2VsZWN0LmFkZEV2ZW50TGlzdGVuZXIoICdjaGFuZ2UnLCAoKSA9PiB7XG5cdFx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLl92YWx1ZXNbIHRoaXMuJHNlbGVjdC5zZWxlY3RlZEluZGV4IF0gKTtcblx0XHRcdHRoaXMuX2NhbGxPbkZpbmlzaENoYW5nZSgpO1xuXHRcdH0gKTtcblxuXHRcdHRoaXMuJHNlbGVjdC5hZGRFdmVudExpc3RlbmVyKCAnZm9jdXMnLCAoKSA9PiB7XG5cdFx0XHR0aGlzLiRkaXNwbGF5LmNsYXNzTGlzdC5hZGQoICdmb2N1cycgKTtcblx0XHR9ICk7XG5cblx0XHR0aGlzLiRzZWxlY3QuYWRkRXZlbnRMaXN0ZW5lciggJ2JsdXInLCAoKSA9PiB7XG5cdFx0XHR0aGlzLiRkaXNwbGF5LmNsYXNzTGlzdC5yZW1vdmUoICdmb2N1cycgKTtcblx0XHR9ICk7XG5cblx0XHR0aGlzLiR3aWRnZXQuYXBwZW5kQ2hpbGQoIHRoaXMuJHNlbGVjdCApO1xuXHRcdHRoaXMuJHdpZGdldC5hcHBlbmRDaGlsZCggdGhpcy4kZGlzcGxheSApO1xuXG5cdFx0dGhpcy4kZGlzYWJsZSA9IHRoaXMuJHNlbGVjdDtcblxuXHRcdHRoaXMub3B0aW9ucyggb3B0aW9ucyApO1xuXG5cdH1cblxuXHRvcHRpb25zKCBvcHRpb25zICkge1xuXG5cdFx0dGhpcy5fdmFsdWVzID0gQXJyYXkuaXNBcnJheSggb3B0aW9ucyApID8gb3B0aW9ucyA6IE9iamVjdC52YWx1ZXMoIG9wdGlvbnMgKTtcblx0XHR0aGlzLl9uYW1lcyA9IEFycmF5LmlzQXJyYXkoIG9wdGlvbnMgKSA/IG9wdGlvbnMgOiBPYmplY3Qua2V5cyggb3B0aW9ucyApO1xuXG5cdFx0dGhpcy4kc2VsZWN0LnJlcGxhY2VDaGlsZHJlbigpO1xuXG5cdFx0dGhpcy5fbmFtZXMuZm9yRWFjaCggbmFtZSA9PiB7XG5cdFx0XHRjb25zdCAkb3B0aW9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggJ29wdGlvbicgKTtcblx0XHRcdCRvcHRpb24udGV4dENvbnRlbnQgPSBuYW1lO1xuXHRcdFx0dGhpcy4kc2VsZWN0LmFwcGVuZENoaWxkKCAkb3B0aW9uICk7XG5cdFx0fSApO1xuXG5cdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dXBkYXRlRGlzcGxheSgpIHtcblx0XHRjb25zdCB2YWx1ZSA9IHRoaXMuZ2V0VmFsdWUoKTtcblx0XHRjb25zdCBpbmRleCA9IHRoaXMuX3ZhbHVlcy5pbmRleE9mKCB2YWx1ZSApO1xuXHRcdHRoaXMuJHNlbGVjdC5zZWxlY3RlZEluZGV4ID0gaW5kZXg7XG5cdFx0dGhpcy4kZGlzcGxheS50ZXh0Q29udGVudCA9IGluZGV4ID09PSAtMSA/IHZhbHVlIDogdGhpcy5fbmFtZXNbIGluZGV4IF07XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxufVxuXG5jbGFzcyBTdHJpbmdDb250cm9sbGVyIGV4dGVuZHMgQ29udHJvbGxlciB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSApIHtcblxuXHRcdHN1cGVyKCBwYXJlbnQsIG9iamVjdCwgcHJvcGVydHksICdzdHJpbmcnICk7XG5cblx0XHR0aGlzLiRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdpbnB1dCcgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICd0eXBlJywgJ3RleHQnICk7XG5cdFx0dGhpcy4kaW5wdXQuc2V0QXR0cmlidXRlKCAnc3BlbGxjaGVjaycsICdmYWxzZScgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICdhcmlhLWxhYmVsbGVkYnknLCB0aGlzLiRuYW1lLmlkICk7XG5cblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnaW5wdXQnLCAoKSA9PiB7XG5cdFx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLiRpbnB1dC52YWx1ZSApO1xuXHRcdH0gKTtcblxuXHRcdHRoaXMuJGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoICdrZXlkb3duJywgZSA9PiB7XG5cdFx0XHRpZiAoIGUuY29kZSA9PT0gJ0VudGVyJyApIHtcblx0XHRcdFx0dGhpcy4kaW5wdXQuYmx1cigpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHRoaXMuJGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoICdibHVyJywgKCkgPT4ge1xuXHRcdFx0dGhpcy5fY2FsbE9uRmluaXNoQ2hhbmdlKCk7XG5cdFx0fSApO1xuXG5cdFx0dGhpcy4kd2lkZ2V0LmFwcGVuZENoaWxkKCB0aGlzLiRpbnB1dCApO1xuXG5cdFx0dGhpcy4kZGlzYWJsZSA9IHRoaXMuJGlucHV0O1xuXG5cdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cblx0fVxuXG5cdHVwZGF0ZURpc3BsYXkoKSB7XG5cdFx0dGhpcy4kaW5wdXQudmFsdWUgPSB0aGlzLmdldFZhbHVlKCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxufVxuXG5jb25zdCBzdHlsZXNoZWV0ID0gYC5saWwtZ3VpIHtcbiAgZm9udC1mYW1pbHk6IHZhcigtLWZvbnQtZmFtaWx5KTtcbiAgZm9udC1zaXplOiB2YXIoLS1mb250LXNpemUpO1xuICBsaW5lLWhlaWdodDogMTtcbiAgZm9udC13ZWlnaHQ6IG5vcm1hbDtcbiAgZm9udC1zdHlsZTogbm9ybWFsO1xuICB0ZXh0LWFsaWduOiBsZWZ0O1xuICBjb2xvcjogdmFyKC0tdGV4dC1jb2xvcik7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuICAtd2Via2l0LXVzZXItc2VsZWN0OiBub25lO1xuICB0b3VjaC1hY3Rpb246IG1hbmlwdWxhdGlvbjtcbiAgLS1iYWNrZ3JvdW5kLWNvbG9yOiAjMWYxZjFmO1xuICAtLXRleHQtY29sb3I6ICNlYmViZWI7XG4gIC0tdGl0bGUtYmFja2dyb3VuZC1jb2xvcjogIzExMTExMTtcbiAgLS10aXRsZS10ZXh0LWNvbG9yOiAjZWJlYmViO1xuICAtLXdpZGdldC1jb2xvcjogIzQyNDI0MjtcbiAgLS1ob3Zlci1jb2xvcjogIzRmNGY0ZjtcbiAgLS1mb2N1cy1jb2xvcjogIzU5NTk1OTtcbiAgLS1udW1iZXItY29sb3I6ICMyY2M5ZmY7XG4gIC0tc3RyaW5nLWNvbG9yOiAjYTJkYjNjO1xuICAtLWZvbnQtc2l6ZTogMTFweDtcbiAgLS1pbnB1dC1mb250LXNpemU6IDExcHg7XG4gIC0tZm9udC1mYW1pbHk6IC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgXCJTZWdvZSBVSVwiLCBSb2JvdG8sIEFyaWFsLCBzYW5zLXNlcmlmO1xuICAtLWZvbnQtZmFtaWx5LW1vbm86IE1lbmxvLCBNb25hY28sIENvbnNvbGFzLCBcIkRyb2lkIFNhbnMgTW9ub1wiLCBtb25vc3BhY2U7XG4gIC0tcGFkZGluZzogNHB4O1xuICAtLXNwYWNpbmc6IDRweDtcbiAgLS13aWRnZXQtaGVpZ2h0OiAyMHB4O1xuICAtLXRpdGxlLWhlaWdodDogY2FsYyh2YXIoLS13aWRnZXQtaGVpZ2h0KSArIHZhcigtLXNwYWNpbmcpICogMS4yNSk7XG4gIC0tbmFtZS13aWR0aDogNDUlO1xuICAtLXNsaWRlci1rbm9iLXdpZHRoOiAycHg7XG4gIC0tc2xpZGVyLWlucHV0LXdpZHRoOiAyNyU7XG4gIC0tY29sb3ItaW5wdXQtd2lkdGg6IDI3JTtcbiAgLS1zbGlkZXItaW5wdXQtbWluLXdpZHRoOiA0NXB4O1xuICAtLWNvbG9yLWlucHV0LW1pbi13aWR0aDogNDVweDtcbiAgLS1mb2xkZXItaW5kZW50OiA3cHg7XG4gIC0td2lkZ2V0LXBhZGRpbmc6IDAgMCAwIDNweDtcbiAgLS13aWRnZXQtYm9yZGVyLXJhZGl1czogMnB4O1xuICAtLWNoZWNrYm94LXNpemU6IGNhbGMoMC43NSAqIHZhcigtLXdpZGdldC1oZWlnaHQpKTtcbiAgLS1zY3JvbGxiYXItd2lkdGg6IDVweDtcbn1cbi5saWwtZ3VpLCAubGlsLWd1aSAqIHtcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgbWFyZ2luOiAwO1xuICBwYWRkaW5nOiAwO1xufVxuLmxpbC1ndWkucm9vdCB7XG4gIHdpZHRoOiB2YXIoLS13aWR0aCwgMjQ1cHgpO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBiYWNrZ3JvdW5kOiB2YXIoLS1iYWNrZ3JvdW5kLWNvbG9yKTtcbn1cbi5saWwtZ3VpLnJvb3QgPiAudGl0bGUge1xuICBiYWNrZ3JvdW5kOiB2YXIoLS10aXRsZS1iYWNrZ3JvdW5kLWNvbG9yKTtcbiAgY29sb3I6IHZhcigtLXRpdGxlLXRleHQtY29sb3IpO1xufVxuLmxpbC1ndWkucm9vdCA+IC5jaGlsZHJlbiB7XG4gIG92ZXJmbG93LXg6IGhpZGRlbjtcbiAgb3ZlcmZsb3cteTogYXV0bztcbn1cbi5saWwtZ3VpLnJvb3QgPiAuY2hpbGRyZW46Oi13ZWJraXQtc2Nyb2xsYmFyIHtcbiAgd2lkdGg6IHZhcigtLXNjcm9sbGJhci13aWR0aCk7XG4gIGhlaWdodDogdmFyKC0tc2Nyb2xsYmFyLXdpZHRoKTtcbiAgYmFja2dyb3VuZDogdmFyKC0tYmFja2dyb3VuZC1jb2xvcik7XG59XG4ubGlsLWd1aS5yb290ID4gLmNoaWxkcmVuOjotd2Via2l0LXNjcm9sbGJhci10aHVtYiB7XG4gIGJvcmRlci1yYWRpdXM6IHZhcigtLXNjcm9sbGJhci13aWR0aCk7XG4gIGJhY2tncm91bmQ6IHZhcigtLWZvY3VzLWNvbG9yKTtcbn1cbkBtZWRpYSAocG9pbnRlcjogY29hcnNlKSB7XG4gIC5saWwtZ3VpLmFsbG93LXRvdWNoLXN0eWxlcywgLmxpbC1ndWkuYWxsb3ctdG91Y2gtc3R5bGVzIC5saWwtZ3VpIHtcbiAgICAtLXdpZGdldC1oZWlnaHQ6IDI4cHg7XG4gICAgLS1wYWRkaW5nOiA2cHg7XG4gICAgLS1zcGFjaW5nOiA2cHg7XG4gICAgLS1mb250LXNpemU6IDEzcHg7XG4gICAgLS1pbnB1dC1mb250LXNpemU6IDE2cHg7XG4gICAgLS1mb2xkZXItaW5kZW50OiAxMHB4O1xuICAgIC0tc2Nyb2xsYmFyLXdpZHRoOiA3cHg7XG4gICAgLS1zbGlkZXItaW5wdXQtbWluLXdpZHRoOiA1MHB4O1xuICAgIC0tY29sb3ItaW5wdXQtbWluLXdpZHRoOiA2NXB4O1xuICB9XG59XG4ubGlsLWd1aS5mb3JjZS10b3VjaC1zdHlsZXMsIC5saWwtZ3VpLmZvcmNlLXRvdWNoLXN0eWxlcyAubGlsLWd1aSB7XG4gIC0td2lkZ2V0LWhlaWdodDogMjhweDtcbiAgLS1wYWRkaW5nOiA2cHg7XG4gIC0tc3BhY2luZzogNnB4O1xuICAtLWZvbnQtc2l6ZTogMTNweDtcbiAgLS1pbnB1dC1mb250LXNpemU6IDE2cHg7XG4gIC0tZm9sZGVyLWluZGVudDogMTBweDtcbiAgLS1zY3JvbGxiYXItd2lkdGg6IDdweDtcbiAgLS1zbGlkZXItaW5wdXQtbWluLXdpZHRoOiA1MHB4O1xuICAtLWNvbG9yLWlucHV0LW1pbi13aWR0aDogNjVweDtcbn1cbi5saWwtZ3VpLmF1dG9QbGFjZSB7XG4gIG1heC1oZWlnaHQ6IDEwMCU7XG4gIHBvc2l0aW9uOiBmaXhlZDtcbiAgdG9wOiAwO1xuICByaWdodDogMTVweDtcbiAgei1pbmRleDogMTAwMTtcbn1cblxuLmxpbC1ndWkgLmNvbnRyb2xsZXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBwYWRkaW5nOiAwIHZhcigtLXBhZGRpbmcpO1xuICBtYXJnaW46IHZhcigtLXNwYWNpbmcpIDA7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5kaXNhYmxlZCB7XG4gIG9wYWNpdHk6IDAuNTtcbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyLmRpc2FibGVkLCAubGlsLWd1aSAuY29udHJvbGxlci5kaXNhYmxlZCAqIHtcbiAgcG9pbnRlci1ldmVudHM6IG5vbmUgIWltcG9ydGFudDtcbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyID4gLm5hbWUge1xuICBtaW4td2lkdGg6IHZhcigtLW5hbWUtd2lkdGgpO1xuICBmbGV4LXNocmluazogMDtcbiAgd2hpdGUtc3BhY2U6IHByZTtcbiAgcGFkZGluZy1yaWdodDogdmFyKC0tc3BhY2luZyk7XG4gIGxpbmUtaGVpZ2h0OiB2YXIoLS13aWRnZXQtaGVpZ2h0KTtcbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyIC53aWRnZXQge1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIHdpZHRoOiAxMDAlO1xuICBtaW4taGVpZ2h0OiB2YXIoLS13aWRnZXQtaGVpZ2h0KTtcbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyLnN0cmluZyBpbnB1dCB7XG4gIGNvbG9yOiB2YXIoLS1zdHJpbmctY29sb3IpO1xufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIuYm9vbGVhbiB7XG4gIGN1cnNvcjogcG9pbnRlcjtcbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyLmNvbG9yIC5kaXNwbGF5IHtcbiAgd2lkdGg6IDEwMCU7XG4gIGhlaWdodDogdmFyKC0td2lkZ2V0LWhlaWdodCk7XG4gIGJvcmRlci1yYWRpdXM6IHZhcigtLXdpZGdldC1ib3JkZXItcmFkaXVzKTtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xufVxuQG1lZGlhIChob3ZlcjogaG92ZXIpIHtcbiAgLmxpbC1ndWkgLmNvbnRyb2xsZXIuY29sb3IgLmRpc3BsYXk6aG92ZXI6YmVmb3JlIHtcbiAgICBjb250ZW50OiBcIiBcIjtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgYm9yZGVyLXJhZGl1czogdmFyKC0td2lkZ2V0LWJvcmRlci1yYWRpdXMpO1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNmZmY5O1xuICAgIHRvcDogMDtcbiAgICByaWdodDogMDtcbiAgICBib3R0b206IDA7XG4gICAgbGVmdDogMDtcbiAgfVxufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIuY29sb3IgaW5wdXRbdHlwZT1jb2xvcl0ge1xuICBvcGFjaXR5OiAwO1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBjdXJzb3I6IHBvaW50ZXI7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5jb2xvciBpbnB1dFt0eXBlPXRleHRdIHtcbiAgbWFyZ2luLWxlZnQ6IHZhcigtLXNwYWNpbmcpO1xuICBmb250LWZhbWlseTogdmFyKC0tZm9udC1mYW1pbHktbW9ubyk7XG4gIG1pbi13aWR0aDogdmFyKC0tY29sb3ItaW5wdXQtbWluLXdpZHRoKTtcbiAgd2lkdGg6IHZhcigtLWNvbG9yLWlucHV0LXdpZHRoKTtcbiAgZmxleC1zaHJpbms6IDA7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5vcHRpb24gc2VsZWN0IHtcbiAgb3BhY2l0eTogMDtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB3aWR0aDogMTAwJTtcbiAgbWF4LXdpZHRoOiAxMDAlO1xufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIub3B0aW9uIC5kaXNwbGF5IHtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbiAgYm9yZGVyLXJhZGl1czogdmFyKC0td2lkZ2V0LWJvcmRlci1yYWRpdXMpO1xuICBoZWlnaHQ6IHZhcigtLXdpZGdldC1oZWlnaHQpO1xuICBsaW5lLWhlaWdodDogdmFyKC0td2lkZ2V0LWhlaWdodCk7XG4gIG1heC13aWR0aDogMTAwJTtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgd29yZC1icmVhazogYnJlYWstYWxsO1xuICBwYWRkaW5nLWxlZnQ6IDAuNTVlbTtcbiAgcGFkZGluZy1yaWdodDogMS43NWVtO1xuICBiYWNrZ3JvdW5kOiB2YXIoLS13aWRnZXQtY29sb3IpO1xufVxuQG1lZGlhIChob3ZlcjogaG92ZXIpIHtcbiAgLmxpbC1ndWkgLmNvbnRyb2xsZXIub3B0aW9uIC5kaXNwbGF5LmZvY3VzIHtcbiAgICBiYWNrZ3JvdW5kOiB2YXIoLS1mb2N1cy1jb2xvcik7XG4gIH1cbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyLm9wdGlvbiAuZGlzcGxheS5hY3RpdmUge1xuICBiYWNrZ3JvdW5kOiB2YXIoLS1mb2N1cy1jb2xvcik7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5vcHRpb24gLmRpc3BsYXk6YWZ0ZXIge1xuICBmb250LWZhbWlseTogXCJsaWwtZ3VpXCI7XG4gIGNvbnRlbnQ6IFwi4oaVXCI7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgdG9wOiAwO1xuICByaWdodDogMDtcbiAgYm90dG9tOiAwO1xuICBwYWRkaW5nLXJpZ2h0OiAwLjM3NWVtO1xufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIub3B0aW9uIC53aWRnZXQsXG4ubGlsLWd1aSAuY29udHJvbGxlci5vcHRpb24gc2VsZWN0IHtcbiAgY3Vyc29yOiBwb2ludGVyO1xufVxuQG1lZGlhIChob3ZlcjogaG92ZXIpIHtcbiAgLmxpbC1ndWkgLmNvbnRyb2xsZXIub3B0aW9uIC53aWRnZXQ6aG92ZXIgLmRpc3BsYXkge1xuICAgIGJhY2tncm91bmQ6IHZhcigtLWhvdmVyLWNvbG9yKTtcbiAgfVxufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIubnVtYmVyIGlucHV0IHtcbiAgY29sb3I6IHZhcigtLW51bWJlci1jb2xvcik7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5udW1iZXIuaGFzU2xpZGVyIGlucHV0IHtcbiAgbWFyZ2luLWxlZnQ6IHZhcigtLXNwYWNpbmcpO1xuICB3aWR0aDogdmFyKC0tc2xpZGVyLWlucHV0LXdpZHRoKTtcbiAgbWluLXdpZHRoOiB2YXIoLS1zbGlkZXItaW5wdXQtbWluLXdpZHRoKTtcbiAgZmxleC1zaHJpbms6IDA7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5udW1iZXIgLnNsaWRlciB7XG4gIHdpZHRoOiAxMDAlO1xuICBoZWlnaHQ6IHZhcigtLXdpZGdldC1oZWlnaHQpO1xuICBiYWNrZ3JvdW5kOiB2YXIoLS13aWRnZXQtY29sb3IpO1xuICBib3JkZXItcmFkaXVzOiB2YXIoLS13aWRnZXQtYm9yZGVyLXJhZGl1cyk7XG4gIHBhZGRpbmctcmlnaHQ6IHZhcigtLXNsaWRlci1rbm9iLXdpZHRoKTtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgY3Vyc29yOiBldy1yZXNpemU7XG4gIHRvdWNoLWFjdGlvbjogcGFuLXk7XG59XG5AbWVkaWEgKGhvdmVyOiBob3Zlcikge1xuICAubGlsLWd1aSAuY29udHJvbGxlci5udW1iZXIgLnNsaWRlcjpob3ZlciB7XG4gICAgYmFja2dyb3VuZDogdmFyKC0taG92ZXItY29sb3IpO1xuICB9XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5udW1iZXIgLnNsaWRlci5hY3RpdmUge1xuICBiYWNrZ3JvdW5kOiB2YXIoLS1mb2N1cy1jb2xvcik7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5udW1iZXIgLnNsaWRlci5hY3RpdmUgLmZpbGwge1xuICBvcGFjaXR5OiAwLjk1O1xufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIubnVtYmVyIC5maWxsIHtcbiAgaGVpZ2h0OiAxMDAlO1xuICBib3JkZXItcmlnaHQ6IHZhcigtLXNsaWRlci1rbm9iLXdpZHRoKSBzb2xpZCB2YXIoLS1udW1iZXItY29sb3IpO1xuICBib3gtc2l6aW5nOiBjb250ZW50LWJveDtcbn1cblxuLmxpbC1ndWktZHJhZ2dpbmcgLmxpbC1ndWkge1xuICAtLWhvdmVyLWNvbG9yOiB2YXIoLS13aWRnZXQtY29sb3IpO1xufVxuLmxpbC1ndWktZHJhZ2dpbmcgKiB7XG4gIGN1cnNvcjogZXctcmVzaXplICFpbXBvcnRhbnQ7XG59XG5cbi5saWwtZ3VpLWRyYWdnaW5nLmxpbC1ndWktdmVydGljYWwgKiB7XG4gIGN1cnNvcjogbnMtcmVzaXplICFpbXBvcnRhbnQ7XG59XG5cbi5saWwtZ3VpIC50aXRsZSB7XG4gIGhlaWdodDogdmFyKC0tdGl0bGUtaGVpZ2h0KTtcbiAgbGluZS1oZWlnaHQ6IGNhbGModmFyKC0tdGl0bGUtaGVpZ2h0KSAtIDRweCk7XG4gIGZvbnQtd2VpZ2h0OiA2MDA7XG4gIHBhZGRpbmc6IDAgdmFyKC0tcGFkZGluZyk7XG4gIC13ZWJraXQtdGFwLWhpZ2hsaWdodC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gIGN1cnNvcjogcG9pbnRlcjtcbiAgb3V0bGluZTogbm9uZTtcbiAgdGV4dC1kZWNvcmF0aW9uLXNraXA6IG9iamVjdHM7XG59XG4ubGlsLWd1aSAudGl0bGU6YmVmb3JlIHtcbiAgZm9udC1mYW1pbHk6IFwibGlsLWd1aVwiO1xuICBjb250ZW50OiBcIuKWvlwiO1xuICBwYWRkaW5nLXJpZ2h0OiAycHg7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbn1cbi5saWwtZ3VpIC50aXRsZTphY3RpdmUge1xuICBiYWNrZ3JvdW5kOiB2YXIoLS10aXRsZS1iYWNrZ3JvdW5kLWNvbG9yKTtcbiAgb3BhY2l0eTogMC43NTtcbn1cbkBtZWRpYSAoaG92ZXI6IGhvdmVyKSB7XG4gIGJvZHk6bm90KC5saWwtZ3VpLWRyYWdnaW5nKSAubGlsLWd1aSAudGl0bGU6aG92ZXIge1xuICAgIGJhY2tncm91bmQ6IHZhcigtLXRpdGxlLWJhY2tncm91bmQtY29sb3IpO1xuICAgIG9wYWNpdHk6IDAuODU7XG4gIH1cbiAgLmxpbC1ndWkgLnRpdGxlOmZvY3VzIHtcbiAgICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZSB2YXIoLS1mb2N1cy1jb2xvcik7XG4gIH1cbn1cbi5saWwtZ3VpLnJvb3QgPiAudGl0bGU6Zm9jdXMge1xuICB0ZXh0LWRlY29yYXRpb246IG5vbmUgIWltcG9ydGFudDtcbn1cbi5saWwtZ3VpLmNsb3NlZCA+IC50aXRsZTpiZWZvcmUge1xuICBjb250ZW50OiBcIuKWuFwiO1xufVxuLmxpbC1ndWkuY2xvc2VkID4gLmNoaWxkcmVuIHtcbiAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKC03cHgpO1xuICBvcGFjaXR5OiAwO1xufVxuLmxpbC1ndWkuY2xvc2VkOm5vdCgudHJhbnNpdGlvbikgPiAuY2hpbGRyZW4ge1xuICBkaXNwbGF5OiBub25lO1xufVxuLmxpbC1ndWkudHJhbnNpdGlvbiA+IC5jaGlsZHJlbiB7XG4gIHRyYW5zaXRpb24tZHVyYXRpb246IDMwMG1zO1xuICB0cmFuc2l0aW9uLXByb3BlcnR5OiBoZWlnaHQsIG9wYWNpdHksIHRyYW5zZm9ybTtcbiAgdHJhbnNpdGlvbi10aW1pbmctZnVuY3Rpb246IGN1YmljLWJlemllcigwLjIsIDAuNiwgMC4zNSwgMSk7XG4gIG92ZXJmbG93OiBoaWRkZW47XG4gIHBvaW50ZXItZXZlbnRzOiBub25lO1xufVxuLmxpbC1ndWkgLmNoaWxkcmVuOmVtcHR5OmJlZm9yZSB7XG4gIGNvbnRlbnQ6IFwiRW1wdHlcIjtcbiAgcGFkZGluZzogMCB2YXIoLS1wYWRkaW5nKTtcbiAgbWFyZ2luOiB2YXIoLS1zcGFjaW5nKSAwO1xuICBkaXNwbGF5OiBibG9jaztcbiAgaGVpZ2h0OiB2YXIoLS13aWRnZXQtaGVpZ2h0KTtcbiAgZm9udC1zdHlsZTogaXRhbGljO1xuICBsaW5lLWhlaWdodDogdmFyKC0td2lkZ2V0LWhlaWdodCk7XG4gIG9wYWNpdHk6IDAuNTtcbn1cbi5saWwtZ3VpLnJvb3QgPiAuY2hpbGRyZW4gPiAubGlsLWd1aSA+IC50aXRsZSB7XG4gIGJvcmRlcjogMCBzb2xpZCB2YXIoLS13aWRnZXQtY29sb3IpO1xuICBib3JkZXItd2lkdGg6IDFweCAwO1xuICB0cmFuc2l0aW9uOiBib3JkZXItY29sb3IgMzAwbXM7XG59XG4ubGlsLWd1aS5yb290ID4gLmNoaWxkcmVuID4gLmxpbC1ndWkuY2xvc2VkID4gLnRpdGxlIHtcbiAgYm9yZGVyLWJvdHRvbS1jb2xvcjogdHJhbnNwYXJlbnQ7XG59XG4ubGlsLWd1aSArIC5jb250cm9sbGVyIHtcbiAgYm9yZGVyLXRvcDogMXB4IHNvbGlkIHZhcigtLXdpZGdldC1jb2xvcik7XG4gIG1hcmdpbi10b3A6IDA7XG4gIHBhZGRpbmctdG9wOiB2YXIoLS1zcGFjaW5nKTtcbn1cbi5saWwtZ3VpIC5saWwtZ3VpIC5saWwtZ3VpID4gLnRpdGxlIHtcbiAgYm9yZGVyOiBub25lO1xufVxuLmxpbC1ndWkgLmxpbC1ndWkgLmxpbC1ndWkgPiAuY2hpbGRyZW4ge1xuICBib3JkZXI6IG5vbmU7XG4gIG1hcmdpbi1sZWZ0OiB2YXIoLS1mb2xkZXItaW5kZW50KTtcbiAgYm9yZGVyLWxlZnQ6IDJweCBzb2xpZCB2YXIoLS13aWRnZXQtY29sb3IpO1xufVxuLmxpbC1ndWkgLmxpbC1ndWkgLmNvbnRyb2xsZXIge1xuICBib3JkZXI6IG5vbmU7XG59XG5cbi5saWwtZ3VpIGxhYmVsLCAubGlsLWd1aSBpbnB1dCwgLmxpbC1ndWkgYnV0dG9uIHtcbiAgLXdlYmtpdC10YXAtaGlnaGxpZ2h0LWNvbG9yOiB0cmFuc3BhcmVudDtcbn1cbi5saWwtZ3VpIGlucHV0IHtcbiAgYm9yZGVyOiAwO1xuICBvdXRsaW5lOiBub25lO1xuICBmb250LWZhbWlseTogdmFyKC0tZm9udC1mYW1pbHkpO1xuICBmb250LXNpemU6IHZhcigtLWlucHV0LWZvbnQtc2l6ZSk7XG4gIGJvcmRlci1yYWRpdXM6IHZhcigtLXdpZGdldC1ib3JkZXItcmFkaXVzKTtcbiAgaGVpZ2h0OiB2YXIoLS13aWRnZXQtaGVpZ2h0KTtcbiAgYmFja2dyb3VuZDogdmFyKC0td2lkZ2V0LWNvbG9yKTtcbiAgY29sb3I6IHZhcigtLXRleHQtY29sb3IpO1xuICB3aWR0aDogMTAwJTtcbn1cbkBtZWRpYSAoaG92ZXI6IGhvdmVyKSB7XG4gIC5saWwtZ3VpIGlucHV0OmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kOiB2YXIoLS1ob3Zlci1jb2xvcik7XG4gIH1cbiAgLmxpbC1ndWkgaW5wdXQ6YWN0aXZlIHtcbiAgICBiYWNrZ3JvdW5kOiB2YXIoLS1mb2N1cy1jb2xvcik7XG4gIH1cbn1cbi5saWwtZ3VpIGlucHV0OmRpc2FibGVkIHtcbiAgb3BhY2l0eTogMTtcbn1cbi5saWwtZ3VpIGlucHV0W3R5cGU9dGV4dF0sXG4ubGlsLWd1aSBpbnB1dFt0eXBlPW51bWJlcl0ge1xuICBwYWRkaW5nOiB2YXIoLS13aWRnZXQtcGFkZGluZyk7XG4gIC1tb3otYXBwZWFyYW5jZTogdGV4dGZpZWxkO1xufVxuLmxpbC1ndWkgaW5wdXRbdHlwZT10ZXh0XTpmb2N1cyxcbi5saWwtZ3VpIGlucHV0W3R5cGU9bnVtYmVyXTpmb2N1cyB7XG4gIGJhY2tncm91bmQ6IHZhcigtLWZvY3VzLWNvbG9yKTtcbn1cbi5saWwtZ3VpIGlucHV0W3R5cGU9Y2hlY2tib3hdIHtcbiAgYXBwZWFyYW5jZTogbm9uZTtcbiAgd2lkdGg6IHZhcigtLWNoZWNrYm94LXNpemUpO1xuICBoZWlnaHQ6IHZhcigtLWNoZWNrYm94LXNpemUpO1xuICBib3JkZXItcmFkaXVzOiB2YXIoLS13aWRnZXQtYm9yZGVyLXJhZGl1cyk7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgY3Vyc29yOiBwb2ludGVyO1xufVxuLmxpbC1ndWkgaW5wdXRbdHlwZT1jaGVja2JveF06Y2hlY2tlZDpiZWZvcmUge1xuICBmb250LWZhbWlseTogXCJsaWwtZ3VpXCI7XG4gIGNvbnRlbnQ6IFwi4pyTXCI7XG4gIGZvbnQtc2l6ZTogdmFyKC0tY2hlY2tib3gtc2l6ZSk7XG4gIGxpbmUtaGVpZ2h0OiB2YXIoLS1jaGVja2JveC1zaXplKTtcbn1cbkBtZWRpYSAoaG92ZXI6IGhvdmVyKSB7XG4gIC5saWwtZ3VpIGlucHV0W3R5cGU9Y2hlY2tib3hdOmZvY3VzIHtcbiAgICBib3gtc2hhZG93OiBpbnNldCAwIDAgMCAxcHggdmFyKC0tZm9jdXMtY29sb3IpO1xuICB9XG59XG4ubGlsLWd1aSBidXR0b24ge1xuICBvdXRsaW5lOiBub25lO1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIGZvbnQtZmFtaWx5OiB2YXIoLS1mb250LWZhbWlseSk7XG4gIGZvbnQtc2l6ZTogdmFyKC0tZm9udC1zaXplKTtcbiAgY29sb3I6IHZhcigtLXRleHQtY29sb3IpO1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiB2YXIoLS13aWRnZXQtaGVpZ2h0KTtcbiAgdGV4dC10cmFuc2Zvcm06IG5vbmU7XG4gIGJhY2tncm91bmQ6IHZhcigtLXdpZGdldC1jb2xvcik7XG4gIGJvcmRlci1yYWRpdXM6IHZhcigtLXdpZGdldC1ib3JkZXItcmFkaXVzKTtcbiAgYm9yZGVyOiBub25lO1xufVxuQG1lZGlhIChob3ZlcjogaG92ZXIpIHtcbiAgLmxpbC1ndWkgYnV0dG9uOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kOiB2YXIoLS1ob3Zlci1jb2xvcik7XG4gIH1cbiAgLmxpbC1ndWkgYnV0dG9uOmZvY3VzIHtcbiAgICBib3gtc2hhZG93OiBpbnNldCAwIDAgMCAxcHggdmFyKC0tZm9jdXMtY29sb3IpO1xuICB9XG59XG4ubGlsLWd1aSBidXR0b246YWN0aXZlIHtcbiAgYmFja2dyb3VuZDogdmFyKC0tZm9jdXMtY29sb3IpO1xufVxuXG5AZm9udC1mYWNlIHtcbiAgZm9udC1mYW1pbHk6IFwibGlsLWd1aVwiO1xuICBzcmM6IHVybChcImRhdGE6YXBwbGljYXRpb24vZm9udC13b2ZmO2NoYXJzZXQ9dXRmLTg7YmFzZTY0LGQwOUdSZ0FCQUFBQUFBVXNBQXNBQUFBQUNKd0FBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCSFUxVkNBQUFCQ0FBQUFINEFBQURBSW13bVlFOVRMeklBQUFHSUFBQUFQd0FBQUdCS3FINVNZMjFoY0FBQUFjZ0FBQUQwQUFBQ3J1a3l5SkJuYkhsbUFBQUN2QUFBQUY4QUFBQ0VJWnBXSDJobFlXUUFBQU1jQUFBQUp3QUFBRFpmY2oyemFHaGxZUUFBQTBRQUFBQVlBQUFBSkFDNUFIaG9iWFI0QUFBRFhBQUFBQkFBQUFCTUFaQUFBR3h2WTJFQUFBTnNBQUFBRkFBQUFDZ0NFZ0l5YldGNGNBQUFBNEFBQUFBZUFBQUFJQUVmQUJKdVlXMWxBQUFEb0FBQUFTSUFBQUlLOVNVVS9YQnZjM1FBQUFURUFBQUFaZ0FBQUpDVGNNYzJlSnhWamJFT2dqQVVSVStoRlJCSzFkR1JMK0FMbkFpVG95TUxFekZwblB6L2VBc2h3U2E5NzUxN2MvTXd3Sm1lQjlrd1BsKzBjZjUrdUdQWlhzcVB1NG52WmFiY1NabGRaNmtmeVdub21GWS9lU2NLcVpOV3VwS0pPNmtYTjNLOXVDVm9MN2lJblByMVg1YmFYczN0anVNcUN0ekV1YWdtL0FBbHpRZ1BBQUI0bkdOZ1lSQmxuTURBeXNEQVlNL2dCaVQ1b0xRQkF3dURKQU1ERXdNck13TldFSkRtbXNKd2dDRmVYWmdoQmNqbFpNZ0ZDek9pS09JRkFCNzFCYjhBZUp5MWtqRnV3a0FRUlorRHdSQXdCdE5RUlVHS1E4T2RLQ0FXVWhBZ0tMaEl1QXNWU3BXejVCYmtqM2RFZ1lpVUlzenFXZHBaZStaNy93QjFvQ1ltSW9ib2l3aUxUMldqS2wvanNjckhmR2cvcEtkTWt5a2xDNVpzMkxFZkhZcGpjUm9Qem1lOU1XV21rM2RXYks5T2JrV2tpa09ldEo1NTRmV3lvRXNtZFNsdCt1UjBwQ0pSMzRiNnQvVFZnMVNZM3NZdmRmOHZ1aUtycHlhRFhESVNpZWdwMTdwNzU3OUdwM3ArK3k3SFBBaVk5cG1UaWJsanJyODVxU2lkdGxnNCtsMjVHTENhUzhlNnJSeE5CbXNuRVJ1bktiYU9PYlJ6N043Mmp1NXZkQWpZcEJYSGdKeWxPQVZzTXNlREFQRVA4TFlvVUhpY1kyQmlBQUVmaGlBR0pnWldCZ1o3Um5GUmRuVkpFTENRbEJTUmxBVEpNb0xWMkRLNGdsU1lzNnVicTV2YktySkxTYkdyZ0Vtb3ZEdURKVmhlM1Z6Y1hGd05MQ09JTEIvQzRJdVExeFRuNUZQaWxCVGo1RlBtQkFCNFd3b3FBSGljWTJCa1lHQUE0c2sxc1IvaitXMitNbkF6cERCZ0F5RU1RVUNTZzRFSnhBRUF3VWdGSGdCNG5HTmdaR0JnU0dGZ2dKTWhESXdNcUVBWUFCeUhBVEo0bkdOZ0FJSVVORXdtQUFCbDNBR1JlSnhqWUFBQ0lRWWxCaU1HSjN3UUFFY1FCRVY0bkdOZ1pHQmdFR1pnWTJCaUFBRVF5UVdFREF6L3dYd0dBQXNQQVRJQUFIaWNYZEJOU3NOQUhBWHdsMzVpQTBVUVhZbk1TaGZTOUdQWkE3VDdMZ0l1MDNTU3Brd3pZVEl0MUJONEFrL2dLVHlBZUN4ZnczOWpaa2p5bXpjdkF3bUFXL3dnd0hVRUdEYjM2K2pRUTNHWEdvdDc5TDI0anhDUDRnSHpGL0VJcjRqRUllN3d4aE9DM2cyVE1ZeTRRNytMdS9TSHVFZC9pdnQ0d0pkNHdQeGJQRUtNWDNHSTUrREpGR2FTbjRxTnprOG1jYktTUjZ4ZFhkaFN6YU9aSkd0ZGFwZDR2VlBiaTZyUCtjTDdUR1hPSHRYS2xsNGJZMVhsN0VHblB0cDdYeTJuMDB6eUtMVkhma0hCYTRJY0oyb0QzY2dnZ1d2dC9WL0ZiRHJVbEVVSmhUbi8wYXpWV2JOVE5yMEVuczhkZTF0Y2VLOXhabWZCMUNQak9tUEg0a2l0bXZPdWJjTnBtVlROM29GSnlqekN2bm1yd2hKVHpxelZqOWppU1g5MTFGamVBQUI0bkczSE1SS0NNQkJBMGYwZ2lpS2k0RFU4azBWMkdXYklaRE9oNFBvV1d2cTZKNVY4SWY5TlZOUWNhRGh5b3VYTWhZNHJQVGNHN2p3WW1YaEtxOFd6K3A3NjJhTmFlWVhvbTJuM20yZExUVmdzckNnRko3T1RtSWtZYndJYkM2dklCN1dtRmZBQUFBPT1cIikgZm9ybWF0KFwid29mZlwiKTtcbn1gO1xuXG5mdW5jdGlvbiBfaW5qZWN0U3R5bGVzKCBjc3NDb250ZW50ICkge1xuXHRjb25zdCBpbmplY3RlZCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdzdHlsZScgKTtcblx0aW5qZWN0ZWQuaW5uZXJIVE1MID0gY3NzQ29udGVudDtcblx0Y29uc3QgYmVmb3JlID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvciggJ2hlYWQgbGlua1tyZWw9c3R5bGVzaGVldF0sIGhlYWQgc3R5bGUnICk7XG5cdGlmICggYmVmb3JlICkge1xuXHRcdGRvY3VtZW50LmhlYWQuaW5zZXJ0QmVmb3JlKCBpbmplY3RlZCwgYmVmb3JlICk7XG5cdH0gZWxzZSB7XG5cdFx0ZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZCggaW5qZWN0ZWQgKTtcblx0fVxufVxuXG5sZXQgc3R5bGVzSW5qZWN0ZWQgPSBmYWxzZTtcblxuY2xhc3MgR1VJIHtcblxuXHQvKipcblx0ICogQ3JlYXRlcyBhIHBhbmVsIHRoYXQgaG9sZHMgY29udHJvbGxlcnMuXG5cdCAqIEBleGFtcGxlXG5cdCAqIG5ldyBHVUkoKTtcblx0ICogbmV3IEdVSSggeyBjb250YWluZXI6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnY3VzdG9tJyApIH0gKTtcblx0ICpcblx0ICogQHBhcmFtIHtvYmplY3R9IFtvcHRpb25zXVxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmF1dG9QbGFjZT10cnVlXVxuXHQgKiBBZGRzIHRoZSBHVUkgdG8gYGRvY3VtZW50LmJvZHlgIGFuZCBmaXhlcyBpdCB0byB0aGUgdG9wIHJpZ2h0IG9mIHRoZSBwYWdlLlxuXHQgKlxuXHQgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBbb3B0aW9ucy5jb250YWluZXJdXG5cdCAqIEFkZHMgdGhlIEdVSSB0byB0aGlzIERPTSBlbGVtZW50LiBPdmVycmlkZXMgYGF1dG9QbGFjZWAuXG5cdCAqXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy53aWR0aD0yNDVdXG5cdCAqIFdpZHRoIG9mIHRoZSBHVUkgaW4gcGl4ZWxzLCB1c3VhbGx5IHNldCB3aGVuIG5hbWUgbGFiZWxzIGJlY29tZSB0b28gbG9uZy4gTm90ZSB0aGF0IHlvdSBjYW4gbWFrZVxuXHQgKiBuYW1lIGxhYmVscyB3aWRlciBpbiBDU1Mgd2l0aCBgLmxpbOKAkWd1aSB7IOKAkeKAkW5hbWXigJF3aWR0aDogNTUlIH1gLlxuXHQgKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gW29wdGlvbnMudGl0bGU9Q29udHJvbHNdXG5cdCAqIE5hbWUgdG8gZGlzcGxheSBpbiB0aGUgdGl0bGUgYmFyLlxuXHQgKlxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmNsb3NlRm9sZGVycz1mYWxzZV1cblx0ICogUGFzcyBgdHJ1ZWAgdG8gY2xvc2UgYWxsIGZvbGRlcnMgaW4gdGhpcyBHVUkgYnkgZGVmYXVsdC5cblx0ICpcblx0ICogQHBhcmFtIHtib29sZWFufSBbb3B0aW9ucy5pbmplY3RTdHlsZXM9dHJ1ZV1cblx0ICogSW5qZWN0cyB0aGUgZGVmYXVsdCBzdHlsZXNoZWV0IGludG8gdGhlIHBhZ2UgaWYgdGhpcyBpcyB0aGUgZmlyc3QgR1VJLlxuXHQgKiBQYXNzIGBmYWxzZWAgdG8gdXNlIHlvdXIgb3duIHN0eWxlc2hlZXQuXG5cdCAqXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy50b3VjaFN0eWxlcz10cnVlXVxuXHQgKiBNYWtlcyBjb250cm9sbGVycyBsYXJnZXIgb24gdG91Y2ggZGV2aWNlcy4gUGFzcyBgZmFsc2VgIHRvIGRpc2FibGUgdG91Y2ggc3R5bGVzLlxuXHQgKlxuXHQgKiBAcGFyYW0ge0dVSX0gW29wdGlvbnMucGFyZW50XVxuXHQgKiBBZGRzIHRoaXMgR1VJIGFzIGEgY2hpbGQgaW4gYW5vdGhlciBHVUkuIFVzdWFsbHkgdGhpcyBpcyBkb25lIGZvciB5b3UgYnkgYGFkZEZvbGRlcigpYC5cblx0ICpcblx0ICovXG5cdGNvbnN0cnVjdG9yKCB7XG5cdFx0cGFyZW50LFxuXHRcdGF1dG9QbGFjZSA9IHBhcmVudCA9PT0gdW5kZWZpbmVkLFxuXHRcdGNvbnRhaW5lcixcblx0XHR3aWR0aCxcblx0XHR0aXRsZSA9ICdDb250cm9scycsXG5cdFx0Y2xvc2VGb2xkZXJzID0gZmFsc2UsXG5cdFx0aW5qZWN0U3R5bGVzID0gdHJ1ZSxcblx0XHR0b3VjaFN0eWxlcyA9IHRydWVcblx0fSA9IHt9ICkge1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIEdVSSBjb250YWluaW5nIHRoaXMgZm9sZGVyLCBvciBgdW5kZWZpbmVkYCBpZiB0aGlzIGlzIHRoZSByb290IEdVSS5cblx0XHQgKiBAdHlwZSB7R1VJfVxuXHRcdCAqL1xuXHRcdHRoaXMucGFyZW50ID0gcGFyZW50O1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIHRvcCBsZXZlbCBHVUkgY29udGFpbmluZyB0aGlzIGZvbGRlciwgb3IgYHRoaXNgIGlmIHRoaXMgaXMgdGhlIHJvb3QgR1VJLlxuXHRcdCAqIEB0eXBlIHtHVUl9XG5cdFx0ICovXG5cdFx0dGhpcy5yb290ID0gcGFyZW50ID8gcGFyZW50LnJvb3QgOiB0aGlzO1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIGxpc3Qgb2YgY29udHJvbGxlcnMgYW5kIGZvbGRlcnMgY29udGFpbmVkIGJ5IHRoaXMgR1VJLlxuXHRcdCAqIEB0eXBlIHtBcnJheTxHVUl8Q29udHJvbGxlcj59XG5cdFx0ICovXG5cdFx0dGhpcy5jaGlsZHJlbiA9IFtdO1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIGxpc3Qgb2YgY29udHJvbGxlcnMgY29udGFpbmVkIGJ5IHRoaXMgR1VJLlxuXHRcdCAqIEB0eXBlIHtBcnJheTxDb250cm9sbGVyPn1cblx0XHQgKi9cblx0XHR0aGlzLmNvbnRyb2xsZXJzID0gW107XG5cblx0XHQvKipcblx0XHQgKiBUaGUgbGlzdCBvZiBmb2xkZXJzIGNvbnRhaW5lZCBieSB0aGlzIEdVSS5cblx0XHQgKiBAdHlwZSB7QXJyYXk8R1VJPn1cblx0XHQgKi9cblx0XHR0aGlzLmZvbGRlcnMgPSBbXTtcblxuXHRcdC8qKlxuXHRcdCAqIFVzZWQgdG8gZGV0ZXJtaW5lIGlmIHRoZSBHVUkgaXMgY2xvc2VkLiBVc2UgYGd1aS5vcGVuKClgIG9yIGBndWkuY2xvc2UoKWAgdG8gY2hhbmdlIHRoaXMuXG5cdFx0ICogQHR5cGUge2Jvb2xlYW59XG5cdFx0ICovXG5cdFx0dGhpcy5fY2xvc2VkID0gZmFsc2U7XG5cblx0XHQvKipcblx0XHQgKiBVc2VkIHRvIGRldGVybWluZSBpZiB0aGUgR1VJIGlzIGhpZGRlbi4gVXNlIGBndWkuc2hvdygpYCBvciBgZ3VpLmhpZGUoKWAgdG8gY2hhbmdlIHRoaXMuXG5cdFx0ICogQHR5cGUge2Jvb2xlYW59XG5cdFx0ICovXG5cdFx0dGhpcy5faGlkZGVuID0gZmFsc2U7XG5cblx0XHQvKipcblx0XHQgKiBUaGUgb3V0ZXJtb3N0IGNvbnRhaW5lciBlbGVtZW50LlxuXHRcdCAqIEB0eXBlIHtIVE1MRWxlbWVudH1cblx0XHQgKi9cblx0XHR0aGlzLmRvbUVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnZGl2JyApO1xuXHRcdHRoaXMuZG9tRWxlbWVudC5jbGFzc0xpc3QuYWRkKCAnbGlsLWd1aScgKTtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBET00gZWxlbWVudCB0aGF0IGNvbnRhaW5zIHRoZSB0aXRsZS5cblx0XHQgKiBAdHlwZSB7SFRNTEVsZW1lbnR9XG5cdFx0ICovXG5cdFx0dGhpcy4kdGl0bGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnZGl2JyApO1xuXHRcdHRoaXMuJHRpdGxlLmNsYXNzTGlzdC5hZGQoICd0aXRsZScgKTtcblx0XHR0aGlzLiR0aXRsZS5zZXRBdHRyaWJ1dGUoICdyb2xlJywgJ2J1dHRvbicgKTtcblx0XHR0aGlzLiR0aXRsZS5zZXRBdHRyaWJ1dGUoICdhcmlhLWV4cGFuZGVkJywgdHJ1ZSApO1xuXHRcdHRoaXMuJHRpdGxlLnNldEF0dHJpYnV0ZSggJ3RhYmluZGV4JywgMCApO1xuXG5cdFx0dGhpcy4kdGl0bGUuYWRkRXZlbnRMaXN0ZW5lciggJ2NsaWNrJywgKCkgPT4gdGhpcy5vcGVuQW5pbWF0ZWQoIHRoaXMuX2Nsb3NlZCApICk7XG5cdFx0dGhpcy4kdGl0bGUuYWRkRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCBlID0+IHtcblx0XHRcdGlmICggZS5jb2RlID09PSAnRW50ZXInIHx8IGUuY29kZSA9PT0gJ1NwYWNlJyApIHtcblx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHR0aGlzLiR0aXRsZS5jbGljaygpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdC8vIGVuYWJsZXMgOmFjdGl2ZSBwc2V1ZG8gY2xhc3Mgb24gbW9iaWxlXG5cdFx0dGhpcy4kdGl0bGUuYWRkRXZlbnRMaXN0ZW5lciggJ3RvdWNoc3RhcnQnLCAoKSA9PiB7fSwgeyBwYXNzaXZlOiB0cnVlIH0gKTtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBET00gZWxlbWVudCB0aGF0IGNvbnRhaW5zIGNoaWxkcmVuLlxuXHRcdCAqIEB0eXBlIHtIVE1MRWxlbWVudH1cblx0XHQgKi9cblx0XHR0aGlzLiRjaGlsZHJlbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdkaXYnICk7XG5cdFx0dGhpcy4kY2hpbGRyZW4uY2xhc3NMaXN0LmFkZCggJ2NoaWxkcmVuJyApO1xuXG5cdFx0dGhpcy5kb21FbGVtZW50LmFwcGVuZENoaWxkKCB0aGlzLiR0aXRsZSApO1xuXHRcdHRoaXMuZG9tRWxlbWVudC5hcHBlbmRDaGlsZCggdGhpcy4kY2hpbGRyZW4gKTtcblxuXHRcdHRoaXMudGl0bGUoIHRpdGxlICk7XG5cblx0XHRpZiAoIHRoaXMucGFyZW50ICkge1xuXG5cdFx0XHR0aGlzLnBhcmVudC5jaGlsZHJlbi5wdXNoKCB0aGlzICk7XG5cdFx0XHR0aGlzLnBhcmVudC5mb2xkZXJzLnB1c2goIHRoaXMgKTtcblxuXHRcdFx0dGhpcy5wYXJlbnQuJGNoaWxkcmVuLmFwcGVuZENoaWxkKCB0aGlzLmRvbUVsZW1lbnQgKTtcblxuXHRcdFx0Ly8gU3RvcCB0aGUgY29uc3RydWN0b3IgZWFybHksIGV2ZXJ5dGhpbmcgb253YXJkIG9ubHkgYXBwbGllcyB0byByb290IEdVSSdzXG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHR0aGlzLmRvbUVsZW1lbnQuY2xhc3NMaXN0LmFkZCggJ3Jvb3QnICk7XG5cblx0XHRpZiAoIHRvdWNoU3R5bGVzICkge1xuXHRcdFx0dGhpcy5kb21FbGVtZW50LmNsYXNzTGlzdC5hZGQoICdhbGxvdy10b3VjaC1zdHlsZXMnICk7XG5cdFx0fVxuXG5cdFx0Ly8gSW5qZWN0IHN0eWxlc2hlZXQgaWYgd2UgaGF2ZW4ndCBkb25lIHRoYXQgeWV0XG5cdFx0aWYgKCAhc3R5bGVzSW5qZWN0ZWQgJiYgaW5qZWN0U3R5bGVzICkge1xuXHRcdFx0X2luamVjdFN0eWxlcyggc3R5bGVzaGVldCApO1xuXHRcdFx0c3R5bGVzSW5qZWN0ZWQgPSB0cnVlO1xuXHRcdH1cblxuXHRcdGlmICggY29udGFpbmVyICkge1xuXG5cdFx0XHRjb250YWluZXIuYXBwZW5kQ2hpbGQoIHRoaXMuZG9tRWxlbWVudCApO1xuXG5cdFx0fSBlbHNlIGlmICggYXV0b1BsYWNlICkge1xuXG5cdFx0XHR0aGlzLmRvbUVsZW1lbnQuY2xhc3NMaXN0LmFkZCggJ2F1dG9QbGFjZScgKTtcblx0XHRcdGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoIHRoaXMuZG9tRWxlbWVudCApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB3aWR0aCApIHtcblx0XHRcdHRoaXMuZG9tRWxlbWVudC5zdHlsZS5zZXRQcm9wZXJ0eSggJy0td2lkdGgnLCB3aWR0aCArICdweCcgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9jbG9zZUZvbGRlcnMgPSBjbG9zZUZvbGRlcnM7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBBZGRzIGEgY29udHJvbGxlciB0byB0aGUgR1VJLCBpbmZlcnJpbmcgY29udHJvbGxlciB0eXBlIHVzaW5nIHRoZSBgdHlwZW9mYCBvcGVyYXRvci5cblx0ICogQGV4YW1wbGVcblx0ICogZ3VpLmFkZCggb2JqZWN0LCAncHJvcGVydHknICk7XG5cdCAqIGd1aS5hZGQoIG9iamVjdCwgJ251bWJlcicsIDAsIDEwMCwgMSApO1xuXHQgKiBndWkuYWRkKCBvYmplY3QsICdvcHRpb25zJywgWyAxLCAyLCAzIF0gKTtcblx0ICpcblx0ICogQHBhcmFtIHtvYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRoZSBjb250cm9sbGVyIHdpbGwgbW9kaWZ5LlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgTmFtZSBvZiB0aGUgcHJvcGVydHkgdG8gY29udHJvbC5cblx0ICogQHBhcmFtIHtudW1iZXJ8b2JqZWN0fEFycmF5fSBbJDFdIE1pbmltdW0gdmFsdWUgZm9yIG51bWJlciBjb250cm9sbGVycywgb3IgdGhlIHNldCBvZlxuXHQgKiBzZWxlY3RhYmxlIHZhbHVlcyBmb3IgYSBkcm9wZG93bi5cblx0ICogQHBhcmFtIHtudW1iZXJ9IFttYXhdIE1heGltdW0gdmFsdWUgZm9yIG51bWJlciBjb250cm9sbGVycy5cblx0ICogQHBhcmFtIHtudW1iZXJ9IFtzdGVwXSBTdGVwIHZhbHVlIGZvciBudW1iZXIgY29udHJvbGxlcnMuXG5cdCAqIEByZXR1cm5zIHtDb250cm9sbGVyfVxuXHQgKi9cblx0YWRkKCBvYmplY3QsIHByb3BlcnR5LCAkMSwgbWF4LCBzdGVwICkge1xuXG5cdFx0aWYgKCBPYmplY3QoICQxICkgPT09ICQxICkge1xuXG5cdFx0XHRyZXR1cm4gbmV3IE9wdGlvbkNvbnRyb2xsZXIoIHRoaXMsIG9iamVjdCwgcHJvcGVydHksICQxICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBpbml0aWFsVmFsdWUgPSBvYmplY3RbIHByb3BlcnR5IF07XG5cblx0XHRzd2l0Y2ggKCB0eXBlb2YgaW5pdGlhbFZhbHVlICkge1xuXG5cdFx0XHRjYXNlICdudW1iZXInOlxuXG5cdFx0XHRcdHJldHVybiBuZXcgTnVtYmVyQ29udHJvbGxlciggdGhpcywgb2JqZWN0LCBwcm9wZXJ0eSwgJDEsIG1heCwgc3RlcCApO1xuXG5cdFx0XHRjYXNlICdib29sZWFuJzpcblxuXHRcdFx0XHRyZXR1cm4gbmV3IEJvb2xlYW5Db250cm9sbGVyKCB0aGlzLCBvYmplY3QsIHByb3BlcnR5ICk7XG5cblx0XHRcdGNhc2UgJ3N0cmluZyc6XG5cblx0XHRcdFx0cmV0dXJuIG5ldyBTdHJpbmdDb250cm9sbGVyKCB0aGlzLCBvYmplY3QsIHByb3BlcnR5ICk7XG5cblx0XHRcdGNhc2UgJ2Z1bmN0aW9uJzpcblxuXHRcdFx0XHRyZXR1cm4gbmV3IEZ1bmN0aW9uQ29udHJvbGxlciggdGhpcywgb2JqZWN0LCBwcm9wZXJ0eSApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc29sZS5lcnJvciggYGd1aS5hZGQgZmFpbGVkXG5cdHByb3BlcnR5OmAsIHByb3BlcnR5LCBgXG5cdG9iamVjdDpgLCBvYmplY3QsIGBcblx0dmFsdWU6YCwgaW5pdGlhbFZhbHVlICk7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBBZGRzIGEgY29sb3IgY29udHJvbGxlciB0byB0aGUgR1VJLlxuXHQgKiBAZXhhbXBsZVxuXHQgKiBwYXJhbXMgPSB7XG5cdCAqIFx0Y3NzQ29sb3I6ICcjZmYwMGZmJyxcblx0ICogXHRyZ2JDb2xvcjogeyByOiAwLCBnOiAwLjIsIGI6IDAuNCB9LFxuXHQgKiBcdGN1c3RvbVJhbmdlOiBbIDAsIDEyNywgMjU1IF0sXG5cdCAqIH07XG5cdCAqXG5cdCAqIGd1aS5hZGRDb2xvciggcGFyYW1zLCAnY3NzQ29sb3InICk7XG5cdCAqIGd1aS5hZGRDb2xvciggcGFyYW1zLCAncmdiQ29sb3InICk7XG5cdCAqIGd1aS5hZGRDb2xvciggcGFyYW1zLCAnY3VzdG9tUmFuZ2UnLCAyNTUgKTtcblx0ICpcblx0ICogQHBhcmFtIHtvYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRoZSBjb250cm9sbGVyIHdpbGwgbW9kaWZ5LlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgTmFtZSBvZiB0aGUgcHJvcGVydHkgdG8gY29udHJvbC5cblx0ICogQHBhcmFtIHtudW1iZXJ9IHJnYlNjYWxlIE1heGltdW0gdmFsdWUgZm9yIGEgY29sb3IgY2hhbm5lbCB3aGVuIHVzaW5nIGFuIFJHQiBjb2xvci4gWW91IG1heVxuXHQgKiBuZWVkIHRvIHNldCB0aGlzIHRvIDI1NSBpZiB5b3VyIGNvbG9ycyBhcmUgdG9vIGJyaWdodC5cblx0ICogQHJldHVybnMge0NvbnRyb2xsZXJ9XG5cdCAqL1xuXHRhZGRDb2xvciggb2JqZWN0LCBwcm9wZXJ0eSwgcmdiU2NhbGUgPSAxICkge1xuXHRcdHJldHVybiBuZXcgQ29sb3JDb250cm9sbGVyKCB0aGlzLCBvYmplY3QsIHByb3BlcnR5LCByZ2JTY2FsZSApO1xuXHR9XG5cblx0LyoqXG5cdCAqIEFkZHMgYSBmb2xkZXIgdG8gdGhlIEdVSSwgd2hpY2ggaXMganVzdCBhbm90aGVyIEdVSS4gVGhpcyBtZXRob2QgcmV0dXJuc1xuXHQgKiB0aGUgbmVzdGVkIEdVSSBzbyB5b3UgY2FuIGFkZCBjb250cm9sbGVycyB0byBpdC5cblx0ICogQGV4YW1wbGVcblx0ICogY29uc3QgZm9sZGVyID0gZ3VpLmFkZEZvbGRlciggJ1Bvc2l0aW9uJyApO1xuXHQgKiBmb2xkZXIuYWRkKCBwb3NpdGlvbiwgJ3gnICk7XG5cdCAqIGZvbGRlci5hZGQoIHBvc2l0aW9uLCAneScgKTtcblx0ICogZm9sZGVyLmFkZCggcG9zaXRpb24sICd6JyApO1xuXHQgKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gdGl0bGUgTmFtZSB0byBkaXNwbGF5IGluIHRoZSBmb2xkZXIncyB0aXRsZSBiYXIuXG5cdCAqIEByZXR1cm5zIHtHVUl9XG5cdCAqL1xuXHRhZGRGb2xkZXIoIHRpdGxlICkge1xuXHRcdGNvbnN0IGZvbGRlciA9IG5ldyBHVUkoIHsgcGFyZW50OiB0aGlzLCB0aXRsZSB9ICk7XG5cdFx0aWYgKCB0aGlzLnJvb3QuX2Nsb3NlRm9sZGVycyApIGZvbGRlci5jbG9zZSgpO1xuXHRcdHJldHVybiBmb2xkZXI7XG5cdH1cblxuXHQvKipcblx0ICogUmVjYWxscyB2YWx1ZXMgdGhhdCB3ZXJlIHNhdmVkIHdpdGggYGd1aS5zYXZlKClgLlxuXHQgKiBAcGFyYW0ge29iamVjdH0gb2JqXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gcmVjdXJzaXZlIFBhc3MgZmFsc2UgdG8gZXhjbHVkZSBmb2xkZXJzIGRlc2NlbmRpbmcgZnJvbSB0aGlzIEdVSS5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRsb2FkKCBvYmosIHJlY3Vyc2l2ZSA9IHRydWUgKSB7XG5cblx0XHRpZiAoIG9iai5jb250cm9sbGVycyApIHtcblxuXHRcdFx0dGhpcy5jb250cm9sbGVycy5mb3JFYWNoKCBjID0+IHtcblxuXHRcdFx0XHRpZiAoIGMgaW5zdGFuY2VvZiBGdW5jdGlvbkNvbnRyb2xsZXIgKSByZXR1cm47XG5cblx0XHRcdFx0aWYgKCBjLl9uYW1lIGluIG9iai5jb250cm9sbGVycyApIHtcblx0XHRcdFx0XHRjLmxvYWQoIG9iai5jb250cm9sbGVyc1sgYy5fbmFtZSBdICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0fSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCByZWN1cnNpdmUgJiYgb2JqLmZvbGRlcnMgKSB7XG5cblx0XHRcdHRoaXMuZm9sZGVycy5mb3JFYWNoKCBmID0+IHtcblxuXHRcdFx0XHRpZiAoIGYuX3RpdGxlIGluIG9iai5mb2xkZXJzICkge1xuXHRcdFx0XHRcdGYubG9hZCggb2JqLmZvbGRlcnNbIGYuX3RpdGxlIF0gKTtcblx0XHRcdFx0fVxuXG5cdFx0XHR9ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybnMgYW4gb2JqZWN0IG1hcHBpbmcgY29udHJvbGxlciBuYW1lcyB0byB2YWx1ZXMuIFRoZSBvYmplY3QgY2FuIGJlIHBhc3NlZCB0byBgZ3VpLmxvYWQoKWAgdG9cblx0ICogcmVjYWxsIHRoZXNlIHZhbHVlcy5cblx0ICogQGV4YW1wbGVcblx0ICoge1xuXHQgKiBcdGNvbnRyb2xsZXJzOiB7XG5cdCAqIFx0XHRwcm9wMTogMSxcblx0ICogXHRcdHByb3AyOiAndmFsdWUnLFxuXHQgKiBcdFx0Li4uXG5cdCAqIFx0fSxcblx0ICogXHRmb2xkZXJzOiB7XG5cdCAqIFx0XHRmb2xkZXJOYW1lMTogeyBjb250cm9sbGVycywgZm9sZGVycyB9LFxuXHQgKiBcdFx0Zm9sZGVyTmFtZTI6IHsgY29udHJvbGxlcnMsIGZvbGRlcnMgfVxuXHQgKiBcdFx0Li4uXG5cdCAqIFx0fVxuXHQgKiB9XG5cdCAqXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gcmVjdXJzaXZlIFBhc3MgZmFsc2UgdG8gZXhjbHVkZSBmb2xkZXJzIGRlc2NlbmRpbmcgZnJvbSB0aGlzIEdVSS5cblx0ICogQHJldHVybnMge29iamVjdH1cblx0ICovXG5cdHNhdmUoIHJlY3Vyc2l2ZSA9IHRydWUgKSB7XG5cblx0XHRjb25zdCBvYmogPSB7XG5cdFx0XHRjb250cm9sbGVyczoge30sXG5cdFx0XHRmb2xkZXJzOiB7fVxuXHRcdH07XG5cblx0XHR0aGlzLmNvbnRyb2xsZXJzLmZvckVhY2goIGMgPT4ge1xuXG5cdFx0XHRpZiAoIGMgaW5zdGFuY2VvZiBGdW5jdGlvbkNvbnRyb2xsZXIgKSByZXR1cm47XG5cblx0XHRcdGlmICggYy5fbmFtZSBpbiBvYmouY29udHJvbGxlcnMgKSB7XG5cdFx0XHRcdHRocm93IG5ldyBFcnJvciggYENhbm5vdCBzYXZlIEdVSSB3aXRoIGR1cGxpY2F0ZSBwcm9wZXJ0eSBcIiR7Yy5fbmFtZX1cImAgKTtcblx0XHRcdH1cblxuXHRcdFx0b2JqLmNvbnRyb2xsZXJzWyBjLl9uYW1lIF0gPSBjLnNhdmUoKTtcblxuXHRcdH0gKTtcblxuXHRcdGlmICggcmVjdXJzaXZlICkge1xuXG5cdFx0XHR0aGlzLmZvbGRlcnMuZm9yRWFjaCggZiA9PiB7XG5cblx0XHRcdFx0aWYgKCBmLl90aXRsZSBpbiBvYmouZm9sZGVycyApIHtcblx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoIGBDYW5ub3Qgc2F2ZSBHVUkgd2l0aCBkdXBsaWNhdGUgZm9sZGVyIFwiJHtmLl90aXRsZX1cImAgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdG9iai5mb2xkZXJzWyBmLl90aXRsZSBdID0gZi5zYXZlKCk7XG5cblx0XHRcdH0gKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBvYmo7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBPcGVucyBhIEdVSSBvciBmb2xkZXIuIEdVSSBhbmQgZm9sZGVycyBhcmUgb3BlbiBieSBkZWZhdWx0LlxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IG9wZW4gUGFzcyBmYWxzZSB0byBjbG9zZS5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqIEBleGFtcGxlXG5cdCAqIGd1aS5vcGVuKCk7IC8vIG9wZW5cblx0ICogZ3VpLm9wZW4oIGZhbHNlICk7IC8vIGNsb3NlXG5cdCAqIGd1aS5vcGVuKCBndWkuX2Nsb3NlZCApOyAvLyB0b2dnbGVcblx0ICovXG5cdG9wZW4oIG9wZW4gPSB0cnVlICkge1xuXG5cdFx0dGhpcy5fc2V0Q2xvc2VkKCAhb3BlbiApO1xuXG5cdFx0dGhpcy4kdGl0bGUuc2V0QXR0cmlidXRlKCAnYXJpYS1leHBhbmRlZCcsICF0aGlzLl9jbG9zZWQgKTtcblx0XHR0aGlzLmRvbUVsZW1lbnQuY2xhc3NMaXN0LnRvZ2dsZSggJ2Nsb3NlZCcsIHRoaXMuX2Nsb3NlZCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBDbG9zZXMgdGhlIEdVSS5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRjbG9zZSgpIHtcblx0XHRyZXR1cm4gdGhpcy5vcGVuKCBmYWxzZSApO1xuXHR9XG5cblx0X3NldENsb3NlZCggY2xvc2VkICkge1xuXHRcdGlmICggdGhpcy5fY2xvc2VkID09PSBjbG9zZWQgKSByZXR1cm47XG5cdFx0dGhpcy5fY2xvc2VkID0gY2xvc2VkO1xuXHRcdHRoaXMuX2NhbGxPbk9wZW5DbG9zZSggdGhpcyApO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNob3dzIHRoZSBHVUkgYWZ0ZXIgaXQncyBiZWVuIGhpZGRlbi5cblx0ICogQHBhcmFtIHtib29sZWFufSBzaG93XG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKiBAZXhhbXBsZVxuXHQgKiBndWkuc2hvdygpO1xuXHQgKiBndWkuc2hvdyggZmFsc2UgKTsgLy8gaGlkZVxuXHQgKiBndWkuc2hvdyggZ3VpLl9oaWRkZW4gKTsgLy8gdG9nZ2xlXG5cdCAqL1xuXHRzaG93KCBzaG93ID0gdHJ1ZSApIHtcblxuXHRcdHRoaXMuX2hpZGRlbiA9ICFzaG93O1xuXG5cdFx0dGhpcy5kb21FbGVtZW50LnN0eWxlLmRpc3BsYXkgPSB0aGlzLl9oaWRkZW4gPyAnbm9uZScgOiAnJztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvKipcblx0ICogSGlkZXMgdGhlIEdVSS5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRoaWRlKCkge1xuXHRcdHJldHVybiB0aGlzLnNob3coIGZhbHNlICk7XG5cdH1cblxuXHRvcGVuQW5pbWF0ZWQoIG9wZW4gPSB0cnVlICkge1xuXG5cdFx0Ly8gc2V0IHN0YXRlIGltbWVkaWF0ZWx5XG5cdFx0dGhpcy5fc2V0Q2xvc2VkKCAhb3BlbiApO1xuXG5cdFx0dGhpcy4kdGl0bGUuc2V0QXR0cmlidXRlKCAnYXJpYS1leHBhbmRlZCcsICF0aGlzLl9jbG9zZWQgKTtcblxuXHRcdC8vIHdhaXQgZm9yIG5leHQgZnJhbWUgdG8gbWVhc3VyZSAkY2hpbGRyZW5cblx0XHRyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoICgpID0+IHtcblxuXHRcdFx0Ly8gZXhwbGljaXRseSBzZXQgaW5pdGlhbCBoZWlnaHQgZm9yIHRyYW5zaXRpb25cblx0XHRcdGNvbnN0IGluaXRpYWxIZWlnaHQgPSB0aGlzLiRjaGlsZHJlbi5jbGllbnRIZWlnaHQ7XG5cdFx0XHR0aGlzLiRjaGlsZHJlbi5zdHlsZS5oZWlnaHQgPSBpbml0aWFsSGVpZ2h0ICsgJ3B4JztcblxuXHRcdFx0dGhpcy5kb21FbGVtZW50LmNsYXNzTGlzdC5hZGQoICd0cmFuc2l0aW9uJyApO1xuXG5cdFx0XHRjb25zdCBvblRyYW5zaXRpb25FbmQgPSBlID0+IHtcblx0XHRcdFx0aWYgKCBlLnRhcmdldCAhPT0gdGhpcy4kY2hpbGRyZW4gKSByZXR1cm47XG5cdFx0XHRcdHRoaXMuJGNoaWxkcmVuLnN0eWxlLmhlaWdodCA9ICcnO1xuXHRcdFx0XHR0aGlzLmRvbUVsZW1lbnQuY2xhc3NMaXN0LnJlbW92ZSggJ3RyYW5zaXRpb24nICk7XG5cdFx0XHRcdHRoaXMuJGNoaWxkcmVuLnJlbW92ZUV2ZW50TGlzdGVuZXIoICd0cmFuc2l0aW9uZW5kJywgb25UcmFuc2l0aW9uRW5kICk7XG5cdFx0XHR9O1xuXG5cdFx0XHR0aGlzLiRjaGlsZHJlbi5hZGRFdmVudExpc3RlbmVyKCAndHJhbnNpdGlvbmVuZCcsIG9uVHJhbnNpdGlvbkVuZCApO1xuXG5cdFx0XHQvLyB0b2RvOiB0aGlzIGlzIHdyb25nIGlmIGNoaWxkcmVuJ3Mgc2Nyb2xsSGVpZ2h0IG1ha2VzIGZvciBhIGd1aSB0YWxsZXIgdGhhbiBtYXhIZWlnaHRcblx0XHRcdGNvbnN0IHRhcmdldEhlaWdodCA9ICFvcGVuID8gMCA6IHRoaXMuJGNoaWxkcmVuLnNjcm9sbEhlaWdodDtcblxuXHRcdFx0dGhpcy5kb21FbGVtZW50LmNsYXNzTGlzdC50b2dnbGUoICdjbG9zZWQnLCAhb3BlbiApO1xuXG5cdFx0XHRyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoICgpID0+IHtcblx0XHRcdFx0dGhpcy4kY2hpbGRyZW4uc3R5bGUuaGVpZ2h0ID0gdGFyZ2V0SGVpZ2h0ICsgJ3B4Jztcblx0XHRcdH0gKTtcblxuXHRcdH0gKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvKipcblx0ICogQ2hhbmdlIHRoZSB0aXRsZSBvZiB0aGlzIEdVSS5cblx0ICogQHBhcmFtIHtzdHJpbmd9IHRpdGxlXG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKi9cblx0dGl0bGUoIHRpdGxlICkge1xuXHRcdC8qKlxuXHRcdCAqIEN1cnJlbnQgdGl0bGUgb2YgdGhlIEdVSS4gVXNlIGBndWkudGl0bGUoICdUaXRsZScgKWAgdG8gbW9kaWZ5IHRoaXMgdmFsdWUuXG5cdFx0ICogQHR5cGUge3N0cmluZ31cblx0XHQgKi9cblx0XHR0aGlzLl90aXRsZSA9IHRpdGxlO1xuXHRcdHRoaXMuJHRpdGxlLnRleHRDb250ZW50ID0gdGl0bGU7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogUmVzZXRzIGFsbCBjb250cm9sbGVycyB0byB0aGVpciBpbml0aWFsIHZhbHVlcy5cblx0ICogQHBhcmFtIHtib29sZWFufSByZWN1cnNpdmUgUGFzcyBmYWxzZSB0byBleGNsdWRlIGZvbGRlcnMgZGVzY2VuZGluZyBmcm9tIHRoaXMgR1VJLlxuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICovXG5cdHJlc2V0KCByZWN1cnNpdmUgPSB0cnVlICkge1xuXHRcdGNvbnN0IGNvbnRyb2xsZXJzID0gcmVjdXJzaXZlID8gdGhpcy5jb250cm9sbGVyc1JlY3Vyc2l2ZSgpIDogdGhpcy5jb250cm9sbGVycztcblx0XHRjb250cm9sbGVycy5mb3JFYWNoKCBjID0+IGMucmVzZXQoKSApO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFBhc3MgYSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgd2hlbmV2ZXIgYSBjb250cm9sbGVyIGluIHRoaXMgR1VJIGNoYW5nZXMuXG5cdCAqIEBwYXJhbSB7ZnVuY3Rpb24oe29iamVjdDpvYmplY3QsIHByb3BlcnR5OnN0cmluZywgdmFsdWU6YW55LCBjb250cm9sbGVyOkNvbnRyb2xsZXJ9KX0gY2FsbGJhY2tcblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqIEBleGFtcGxlXG5cdCAqIGd1aS5vbkNoYW5nZSggZXZlbnQgPT4ge1xuXHQgKiBcdGV2ZW50Lm9iamVjdCAgICAgLy8gb2JqZWN0IHRoYXQgd2FzIG1vZGlmaWVkXG5cdCAqIFx0ZXZlbnQucHJvcGVydHkgICAvLyBzdHJpbmcsIG5hbWUgb2YgcHJvcGVydHlcblx0ICogXHRldmVudC52YWx1ZSAgICAgIC8vIG5ldyB2YWx1ZSBvZiBjb250cm9sbGVyXG5cdCAqIFx0ZXZlbnQuY29udHJvbGxlciAvLyBjb250cm9sbGVyIHRoYXQgd2FzIG1vZGlmaWVkXG5cdCAqIH0gKTtcblx0ICovXG5cdG9uQ2hhbmdlKCBjYWxsYmFjayApIHtcblx0XHQvKipcblx0XHQgKiBVc2VkIHRvIGFjY2VzcyB0aGUgZnVuY3Rpb24gYm91bmQgdG8gYG9uQ2hhbmdlYCBldmVudHMuIERvbid0IG1vZGlmeSB0aGlzIHZhbHVlXG5cdFx0ICogZGlyZWN0bHkuIFVzZSB0aGUgYGd1aS5vbkNoYW5nZSggY2FsbGJhY2sgKWAgbWV0aG9kIGluc3RlYWQuXG5cdFx0ICogQHR5cGUge0Z1bmN0aW9ufVxuXHRcdCAqL1xuXHRcdHRoaXMuX29uQ2hhbmdlID0gY2FsbGJhY2s7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRfY2FsbE9uQ2hhbmdlKCBjb250cm9sbGVyICkge1xuXG5cdFx0aWYgKCB0aGlzLnBhcmVudCApIHtcblx0XHRcdHRoaXMucGFyZW50Ll9jYWxsT25DaGFuZ2UoIGNvbnRyb2xsZXIgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX29uQ2hhbmdlICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHR0aGlzLl9vbkNoYW5nZS5jYWxsKCB0aGlzLCB7XG5cdFx0XHRcdG9iamVjdDogY29udHJvbGxlci5vYmplY3QsXG5cdFx0XHRcdHByb3BlcnR5OiBjb250cm9sbGVyLnByb3BlcnR5LFxuXHRcdFx0XHR2YWx1ZTogY29udHJvbGxlci5nZXRWYWx1ZSgpLFxuXHRcdFx0XHRjb250cm9sbGVyXG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFBhc3MgYSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgd2hlbmV2ZXIgYSBjb250cm9sbGVyIGluIHRoaXMgR1VJIGhhcyBmaW5pc2hlZCBjaGFuZ2luZy5cblx0ICogQHBhcmFtIHtmdW5jdGlvbih7b2JqZWN0Om9iamVjdCwgcHJvcGVydHk6c3RyaW5nLCB2YWx1ZTphbnksIGNvbnRyb2xsZXI6Q29udHJvbGxlcn0pfSBjYWxsYmFja1xuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICogQGV4YW1wbGVcblx0ICogZ3VpLm9uRmluaXNoQ2hhbmdlKCBldmVudCA9PiB7XG5cdCAqIFx0ZXZlbnQub2JqZWN0ICAgICAvLyBvYmplY3QgdGhhdCB3YXMgbW9kaWZpZWRcblx0ICogXHRldmVudC5wcm9wZXJ0eSAgIC8vIHN0cmluZywgbmFtZSBvZiBwcm9wZXJ0eVxuXHQgKiBcdGV2ZW50LnZhbHVlICAgICAgLy8gbmV3IHZhbHVlIG9mIGNvbnRyb2xsZXJcblx0ICogXHRldmVudC5jb250cm9sbGVyIC8vIGNvbnRyb2xsZXIgdGhhdCB3YXMgbW9kaWZpZWRcblx0ICogfSApO1xuXHQgKi9cblx0b25GaW5pc2hDaGFuZ2UoIGNhbGxiYWNrICkge1xuXHRcdC8qKlxuXHRcdCAqIFVzZWQgdG8gYWNjZXNzIHRoZSBmdW5jdGlvbiBib3VuZCB0byBgb25GaW5pc2hDaGFuZ2VgIGV2ZW50cy4gRG9uJ3QgbW9kaWZ5IHRoaXMgdmFsdWVcblx0XHQgKiBkaXJlY3RseS4gVXNlIHRoZSBgZ3VpLm9uRmluaXNoQ2hhbmdlKCBjYWxsYmFjayApYCBtZXRob2QgaW5zdGVhZC5cblx0XHQgKiBAdHlwZSB7RnVuY3Rpb259XG5cdFx0ICovXG5cdFx0dGhpcy5fb25GaW5pc2hDaGFuZ2UgPSBjYWxsYmFjaztcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdF9jYWxsT25GaW5pc2hDaGFuZ2UoIGNvbnRyb2xsZXIgKSB7XG5cblx0XHRpZiAoIHRoaXMucGFyZW50ICkge1xuXHRcdFx0dGhpcy5wYXJlbnQuX2NhbGxPbkZpbmlzaENoYW5nZSggY29udHJvbGxlciApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fb25GaW5pc2hDaGFuZ2UgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuX29uRmluaXNoQ2hhbmdlLmNhbGwoIHRoaXMsIHtcblx0XHRcdFx0b2JqZWN0OiBjb250cm9sbGVyLm9iamVjdCxcblx0XHRcdFx0cHJvcGVydHk6IGNvbnRyb2xsZXIucHJvcGVydHksXG5cdFx0XHRcdHZhbHVlOiBjb250cm9sbGVyLmdldFZhbHVlKCksXG5cdFx0XHRcdGNvbnRyb2xsZXJcblx0XHRcdH0gKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogUGFzcyBhIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB3aGVuIHRoaXMgR1VJIG9yIGl0cyBkZXNjZW5kYW50cyBhcmUgb3BlbmVkIG9yIGNsb3NlZC5cblx0ICogQHBhcmFtIHtmdW5jdGlvbihHVUkpfSBjYWxsYmFja1xuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICogQGV4YW1wbGVcblx0ICogZ3VpLm9uT3BlbkNsb3NlKCBjaGFuZ2VkR1VJID0+IHtcblx0ICogXHRjb25zb2xlLmxvZyggY2hhbmdlZEdVSS5fY2xvc2VkICk7XG5cdCAqIH0gKTtcblx0ICovXG5cdG9uT3BlbkNsb3NlKCBjYWxsYmFjayApIHtcblx0XHR0aGlzLl9vbk9wZW5DbG9zZSA9IGNhbGxiYWNrO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0X2NhbGxPbk9wZW5DbG9zZSggY2hhbmdlZEdVSSApIHtcblx0XHRpZiAoIHRoaXMucGFyZW50ICkge1xuXHRcdFx0dGhpcy5wYXJlbnQuX2NhbGxPbk9wZW5DbG9zZSggY2hhbmdlZEdVSSApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fb25PcGVuQ2xvc2UgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuX29uT3BlbkNsb3NlLmNhbGwoIHRoaXMsIGNoYW5nZWRHVUkgKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogRGVzdHJveXMgYWxsIERPTSBlbGVtZW50cyBhbmQgZXZlbnQgbGlzdGVuZXJzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEdVSS5cblx0ICovXG5cdGRlc3Ryb3koKSB7XG5cblx0XHRpZiAoIHRoaXMucGFyZW50ICkge1xuXHRcdFx0dGhpcy5wYXJlbnQuY2hpbGRyZW4uc3BsaWNlKCB0aGlzLnBhcmVudC5jaGlsZHJlbi5pbmRleE9mKCB0aGlzICksIDEgKTtcblx0XHRcdHRoaXMucGFyZW50LmZvbGRlcnMuc3BsaWNlKCB0aGlzLnBhcmVudC5mb2xkZXJzLmluZGV4T2YoIHRoaXMgKSwgMSApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5kb21FbGVtZW50LnBhcmVudEVsZW1lbnQgKSB7XG5cdFx0XHR0aGlzLmRvbUVsZW1lbnQucGFyZW50RWxlbWVudC5yZW1vdmVDaGlsZCggdGhpcy5kb21FbGVtZW50ICk7XG5cdFx0fVxuXG5cdFx0QXJyYXkuZnJvbSggdGhpcy5jaGlsZHJlbiApLmZvckVhY2goIGMgPT4gYy5kZXN0cm95KCkgKTtcblxuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybnMgYW4gYXJyYXkgb2YgY29udHJvbGxlcnMgY29udGFpbmVkIGJ5IHRoaXMgR1VJIGFuZCBpdHMgZGVzY2VuZGVudHMuXG5cdCAqIEByZXR1cm5zIHtDb250cm9sbGVyW119XG5cdCAqL1xuXHRjb250cm9sbGVyc1JlY3Vyc2l2ZSgpIHtcblx0XHRsZXQgY29udHJvbGxlcnMgPSBBcnJheS5mcm9tKCB0aGlzLmNvbnRyb2xsZXJzICk7XG5cdFx0dGhpcy5mb2xkZXJzLmZvckVhY2goIGYgPT4ge1xuXHRcdFx0Y29udHJvbGxlcnMgPSBjb250cm9sbGVycy5jb25jYXQoIGYuY29udHJvbGxlcnNSZWN1cnNpdmUoKSApO1xuXHRcdH0gKTtcblx0XHRyZXR1cm4gY29udHJvbGxlcnM7XG5cdH1cblxuXHQvKipcblx0ICogUmV0dXJucyBhbiBhcnJheSBvZiBmb2xkZXJzIGNvbnRhaW5lZCBieSB0aGlzIEdVSSBhbmQgaXRzIGRlc2NlbmRlbnRzLlxuXHQgKiBAcmV0dXJucyB7R1VJW119XG5cdCAqL1xuXHRmb2xkZXJzUmVjdXJzaXZlKCkge1xuXHRcdGxldCBmb2xkZXJzID0gQXJyYXkuZnJvbSggdGhpcy5mb2xkZXJzICk7XG5cdFx0dGhpcy5mb2xkZXJzLmZvckVhY2goIGYgPT4ge1xuXHRcdFx0Zm9sZGVycyA9IGZvbGRlcnMuY29uY2F0KCBmLmZvbGRlcnNSZWN1cnNpdmUoKSApO1xuXHRcdH0gKTtcblx0XHRyZXR1cm4gZm9sZGVycztcblx0fVxuXG59XG5cbmV4cG9ydCBkZWZhdWx0IEdVSTtcbmV4cG9ydCB7IEJvb2xlYW5Db250cm9sbGVyLCBDb2xvckNvbnRyb2xsZXIsIENvbnRyb2xsZXIsIEZ1bmN0aW9uQ29udHJvbGxlciwgR1VJLCBOdW1iZXJDb250cm9sbGVyLCBPcHRpb25Db250cm9sbGVyLCBTdHJpbmdDb250cm9sbGVyIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///638\n")},753:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ $p8: () => (/* binding */ AmbientLight),\n/* harmony export */ BKk: () => (/* binding */ ShaderMaterial),\n/* harmony export */ D$Q: () => (/* binding */ RawShaderMaterial),\n/* harmony export */ EZo: () => (/* binding */ AdditiveBlending),\n/* harmony export */ F1l: () => (/* binding */ PointLightHelper),\n/* harmony export */ FV: () => (/* binding */ ACESFilmicToneMapping),\n/* harmony export */ G_z: () => (/* binding */ MeshLambertMaterial),\n/* harmony export */ Gu$: () => (/* binding */ SphereGeometry),\n/* harmony export */ HiM: () => (/* binding */ PointLight),\n/* harmony export */ I9Y: () => (/* binding */ Vector2),\n/* harmony export */ IzY: () => (/* binding */ AxesHelper),\n/* harmony export */ JeP: () => (/* binding */ WebGLRenderer),\n/* harmony export */ KLL: () => (/* binding */ SRGBTransfer),\n/* harmony export */ LAk: () => (/* binding */ AgXToneMapping),\n/* harmony export */ LlO: () => (/* binding */ UniformsUtils),\n/* harmony export */ LoY: () => (/* binding */ BufferGeometry),\n/* harmony export */ Mjd: () => (/* binding */ ReinhardToneMapping),\n/* harmony export */ PTz: () => (/* binding */ Quaternion),\n/* harmony export */ Pq0: () => (/* binding */ Vector3),\n/* harmony export */ Q1f: () => (/* binding */ Color),\n/* harmony export */ Qev: () => (/* binding */ EventDispatcher),\n/* harmony export */ RlV: () => (/* binding */ Ray),\n/* harmony export */ Tap: () => (/* binding */ TextureLoader),\n/* harmony export */ V9B: () => (/* binding */ MeshBasicMaterial),\n/* harmony export */ XIg: () => (/* binding */ NoBlending),\n/* harmony export */ YHV: () => (/* binding */ Spherical),\n/* harmony export */ Z58: () => (/* binding */ Scene),\n/* harmony export */ Zcv: () => (/* binding */ Plane),\n/* harmony export */ aJ8: () => (/* binding */ NeutralToneMapping),\n/* harmony export */ cj9: () => (/* binding */ MathUtils),\n/* harmony export */ eaF: () => (/* binding */ Mesh),\n/* harmony export */ gPd: () => (/* binding */ Texture),\n/* harmony export */ hxR: () => (/* binding */ NearestFilter),\n/* harmony export */ ix0: () => (/* binding */ HalfFloatType),\n/* harmony export */ jUj: () => (/* binding */ Fog),\n/* harmony export */ k6q: () => (/* binding */ LinearFilter),\n/* harmony export */ kBv: () => (/* binding */ MOUSE),\n/* harmony export */ kyO: () => (/* binding */ LinearToneMapping),\n/* harmony export */ nNL: () => (/* binding */ CineonToneMapping),\n/* harmony export */ nWS: () => (/* binding */ WebGLRenderTarget),\n/* harmony export */ ppV: () => (/* binding */ ColorManagement),\n/* harmony export */ qUd: () => (/* binding */ OrthographicCamera),\n/* harmony export */ qtW: () => (/* binding */ Float32BufferAttribute),\n/* harmony export */ ubm: () => (/* binding */ PerspectiveCamera),\n/* harmony export */ wtR: () => (/* binding */ TOUCH),\n/* harmony export */ zD7: () => (/* binding */ Clock),\n/* harmony export */ zgK: () => (/* binding */ Layers)\n/* harmony export */ });\n/* unused harmony exports AddEquation, AddOperation, AdditiveAnimationBlendMode, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, BackSide, BasicDepthPacking, BasicShadowMap, BatchedMesh, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, BufferAttribute, BufferGeometryLoader, ByteType, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, ClampToEdgeWrapping, ColorKeyframeTrack, 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, ExtrudeGeometry, FileLoader, Float16BufferAttribute, FloatType, FogExp2, FramebufferTexture, FrontSide, Frustum, GLBufferAttribute, GLSL1, GLSL3, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, 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, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearDisplayP3ColorSpace, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearTransfer, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, Material, MaterialLoader, Matrix3, Matrix4, MaxEquation, MeshDepthMaterial, MeshDistanceMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeverCompare, NeverDepth, NeverStencilFunc, NoColorSpace, NoToneMapping, NormalAnimationBlendMode, NormalBlending, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, P3Primaries, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, Path, PlaneGeometry, PlaneHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, 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, RGBFormat, RGBIntegerFormat, 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, Raycaster, Rec709Primaries, RectAreaLight, RedFormat, RedIntegerFormat, RenderTarget, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RingGeometry, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, ShaderChunk, ShaderLib, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TangentSpaceNormalMap, TetrahedronGeometry, TextureUtils, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, UniformsLib, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VSMShadowMap, Vector4, VectorKeyframeTrack, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLMultipleRenderTargets, WebGLUtils, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, createCanvasElement */\n/**\n * @license\n * Copyright 2010-2024 Three.js Authors\n * SPDX-License-Identifier: MIT\n */\nconst REVISION = '166';\n\nconst MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };\nconst TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };\nconst CullFaceNone = 0;\nconst CullFaceBack = 1;\nconst CullFaceFront = 2;\nconst CullFaceFrontBack = 3;\nconst BasicShadowMap = 0;\nconst PCFShadowMap = 1;\nconst PCFSoftShadowMap = 2;\nconst VSMShadowMap = 3;\nconst FrontSide = 0;\nconst BackSide = 1;\nconst DoubleSide = 2;\nconst NoBlending = 0;\nconst NormalBlending = 1;\nconst AdditiveBlending = 2;\nconst SubtractiveBlending = 3;\nconst MultiplyBlending = 4;\nconst CustomBlending = 5;\nconst AddEquation = 100;\nconst SubtractEquation = 101;\nconst ReverseSubtractEquation = 102;\nconst MinEquation = 103;\nconst MaxEquation = 104;\nconst ZeroFactor = 200;\nconst OneFactor = 201;\nconst SrcColorFactor = 202;\nconst OneMinusSrcColorFactor = 203;\nconst SrcAlphaFactor = 204;\nconst OneMinusSrcAlphaFactor = 205;\nconst DstAlphaFactor = 206;\nconst OneMinusDstAlphaFactor = 207;\nconst DstColorFactor = 208;\nconst OneMinusDstColorFactor = 209;\nconst SrcAlphaSaturateFactor = 210;\nconst ConstantColorFactor = 211;\nconst OneMinusConstantColorFactor = 212;\nconst ConstantAlphaFactor = 213;\nconst OneMinusConstantAlphaFactor = 214;\nconst NeverDepth = 0;\nconst AlwaysDepth = 1;\nconst LessDepth = 2;\nconst LessEqualDepth = 3;\nconst EqualDepth = 4;\nconst GreaterEqualDepth = 5;\nconst GreaterDepth = 6;\nconst NotEqualDepth = 7;\nconst MultiplyOperation = 0;\nconst MixOperation = 1;\nconst AddOperation = 2;\nconst NoToneMapping = 0;\nconst LinearToneMapping = 1;\nconst ReinhardToneMapping = 2;\nconst CineonToneMapping = 3;\nconst ACESFilmicToneMapping = 4;\nconst CustomToneMapping = 5;\nconst AgXToneMapping = 6;\nconst NeutralToneMapping = 7;\nconst AttachedBindMode = 'attached';\nconst DetachedBindMode = 'detached';\n\nconst UVMapping = 300;\nconst CubeReflectionMapping = 301;\nconst CubeRefractionMapping = 302;\nconst EquirectangularReflectionMapping = 303;\nconst EquirectangularRefractionMapping = 304;\nconst CubeUVReflectionMapping = 306;\nconst RepeatWrapping = 1000;\nconst ClampToEdgeWrapping = 1001;\nconst MirroredRepeatWrapping = 1002;\nconst NearestFilter = 1003;\nconst NearestMipmapNearestFilter = 1004;\nconst NearestMipMapNearestFilter = 1004;\nconst NearestMipmapLinearFilter = 1005;\nconst NearestMipMapLinearFilter = 1005;\nconst LinearFilter = 1006;\nconst LinearMipmapNearestFilter = 1007;\nconst LinearMipMapNearestFilter = 1007;\nconst LinearMipmapLinearFilter = 1008;\nconst LinearMipMapLinearFilter = 1008;\nconst UnsignedByteType = 1009;\nconst ByteType = 1010;\nconst ShortType = 1011;\nconst UnsignedShortType = 1012;\nconst IntType = 1013;\nconst UnsignedIntType = 1014;\nconst FloatType = 1015;\nconst HalfFloatType = 1016;\nconst UnsignedShort4444Type = 1017;\nconst UnsignedShort5551Type = 1018;\nconst UnsignedInt248Type = 1020;\nconst UnsignedInt5999Type = 35902;\nconst AlphaFormat = 1021;\nconst RGBFormat = 1022;\nconst RGBAFormat = 1023;\nconst LuminanceFormat = 1024;\nconst LuminanceAlphaFormat = 1025;\nconst DepthFormat = 1026;\nconst DepthStencilFormat = 1027;\nconst RedFormat = 1028;\nconst RedIntegerFormat = 1029;\nconst RGFormat = 1030;\nconst RGIntegerFormat = 1031;\nconst RGBIntegerFormat = 1032;\nconst RGBAIntegerFormat = 1033;\n\nconst RGB_S3TC_DXT1_Format = 33776;\nconst RGBA_S3TC_DXT1_Format = 33777;\nconst RGBA_S3TC_DXT3_Format = 33778;\nconst RGBA_S3TC_DXT5_Format = 33779;\nconst RGB_PVRTC_4BPPV1_Format = 35840;\nconst RGB_PVRTC_2BPPV1_Format = 35841;\nconst RGBA_PVRTC_4BPPV1_Format = 35842;\nconst RGBA_PVRTC_2BPPV1_Format = 35843;\nconst RGB_ETC1_Format = 36196;\nconst RGB_ETC2_Format = 37492;\nconst RGBA_ETC2_EAC_Format = 37496;\nconst RGBA_ASTC_4x4_Format = 37808;\nconst RGBA_ASTC_5x4_Format = 37809;\nconst RGBA_ASTC_5x5_Format = 37810;\nconst RGBA_ASTC_6x5_Format = 37811;\nconst RGBA_ASTC_6x6_Format = 37812;\nconst RGBA_ASTC_8x5_Format = 37813;\nconst RGBA_ASTC_8x6_Format = 37814;\nconst RGBA_ASTC_8x8_Format = 37815;\nconst RGBA_ASTC_10x5_Format = 37816;\nconst RGBA_ASTC_10x6_Format = 37817;\nconst RGBA_ASTC_10x8_Format = 37818;\nconst RGBA_ASTC_10x10_Format = 37819;\nconst RGBA_ASTC_12x10_Format = 37820;\nconst RGBA_ASTC_12x12_Format = 37821;\nconst RGBA_BPTC_Format = 36492;\nconst RGB_BPTC_SIGNED_Format = 36494;\nconst RGB_BPTC_UNSIGNED_Format = 36495;\nconst RED_RGTC1_Format = 36283;\nconst SIGNED_RED_RGTC1_Format = 36284;\nconst RED_GREEN_RGTC2_Format = 36285;\nconst SIGNED_RED_GREEN_RGTC2_Format = 36286;\nconst LoopOnce = 2200;\nconst LoopRepeat = 2201;\nconst LoopPingPong = 2202;\nconst InterpolateDiscrete = 2300;\nconst InterpolateLinear = 2301;\nconst InterpolateSmooth = 2302;\nconst ZeroCurvatureEnding = 2400;\nconst ZeroSlopeEnding = 2401;\nconst WrapAroundEnding = 2402;\nconst NormalAnimationBlendMode = 2500;\nconst AdditiveAnimationBlendMode = 2501;\nconst TrianglesDrawMode = 0;\nconst TriangleStripDrawMode = 1;\nconst TriangleFanDrawMode = 2;\nconst BasicDepthPacking = 3200;\nconst RGBADepthPacking = 3201;\nconst TangentSpaceNormalMap = 0;\nconst ObjectSpaceNormalMap = 1;\n\n// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available.\nconst NoColorSpace = '';\nconst SRGBColorSpace = 'srgb';\nconst LinearSRGBColorSpace = 'srgb-linear';\nconst DisplayP3ColorSpace = 'display-p3';\nconst LinearDisplayP3ColorSpace = 'display-p3-linear';\n\nconst LinearTransfer = 'linear';\nconst SRGBTransfer = 'srgb';\n\nconst Rec709Primaries = 'rec709';\nconst P3Primaries = 'p3';\n\nconst ZeroStencilOp = 0;\nconst KeepStencilOp = 7680;\nconst ReplaceStencilOp = 7681;\nconst IncrementStencilOp = 7682;\nconst DecrementStencilOp = 7683;\nconst IncrementWrapStencilOp = 34055;\nconst DecrementWrapStencilOp = 34056;\nconst InvertStencilOp = 5386;\n\nconst NeverStencilFunc = 512;\nconst LessStencilFunc = 513;\nconst EqualStencilFunc = 514;\nconst LessEqualStencilFunc = 515;\nconst GreaterStencilFunc = 516;\nconst NotEqualStencilFunc = 517;\nconst GreaterEqualStencilFunc = 518;\nconst AlwaysStencilFunc = 519;\n\nconst NeverCompare = 512;\nconst LessCompare = 513;\nconst EqualCompare = 514;\nconst LessEqualCompare = 515;\nconst GreaterCompare = 516;\nconst NotEqualCompare = 517;\nconst GreaterEqualCompare = 518;\nconst AlwaysCompare = 519;\n\nconst StaticDrawUsage = 35044;\nconst DynamicDrawUsage = 35048;\nconst StreamDrawUsage = 35040;\nconst StaticReadUsage = 35045;\nconst DynamicReadUsage = 35049;\nconst StreamReadUsage = 35041;\nconst StaticCopyUsage = 35046;\nconst DynamicCopyUsage = 35050;\nconst StreamCopyUsage = 35042;\n\nconst GLSL1 = '100';\nconst GLSL3 = '300 es';\n\nconst WebGLCoordinateSystem = 2000;\nconst WebGPUCoordinateSystem = 2001;\n\n/**\n * https://github.com/mrdoob/eventdispatcher.js/\n */\n\nclass EventDispatcher {\n\n\taddEventListener( type, listener ) {\n\n\t\tif ( this._listeners === undefined ) this._listeners = {};\n\n\t\tconst listeners = this._listeners;\n\n\t\tif ( listeners[ type ] === undefined ) {\n\n\t\t\tlisteners[ type ] = [];\n\n\t\t}\n\n\t\tif ( listeners[ type ].indexOf( listener ) === - 1 ) {\n\n\t\t\tlisteners[ type ].push( listener );\n\n\t\t}\n\n\t}\n\n\thasEventListener( type, listener ) {\n\n\t\tif ( this._listeners === undefined ) return false;\n\n\t\tconst listeners = this._listeners;\n\n\t\treturn listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;\n\n\t}\n\n\tremoveEventListener( type, listener ) {\n\n\t\tif ( this._listeners === undefined ) return;\n\n\t\tconst listeners = this._listeners;\n\t\tconst listenerArray = listeners[ type ];\n\n\t\tif ( listenerArray !== undefined ) {\n\n\t\t\tconst index = listenerArray.indexOf( listener );\n\n\t\t\tif ( index !== - 1 ) {\n\n\t\t\t\tlistenerArray.splice( index, 1 );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tdispatchEvent( event ) {\n\n\t\tif ( this._listeners === undefined ) return;\n\n\t\tconst listeners = this._listeners;\n\t\tconst listenerArray = listeners[ event.type ];\n\n\t\tif ( listenerArray !== undefined ) {\n\n\t\t\tevent.target = this;\n\n\t\t\t// Make a copy, in case listeners are removed while iterating.\n\t\t\tconst array = listenerArray.slice( 0 );\n\n\t\t\tfor ( let i = 0, l = array.length; i < l; i ++ ) {\n\n\t\t\t\tarray[ i ].call( this, event );\n\n\t\t\t}\n\n\t\t\tevent.target = null;\n\n\t\t}\n\n\t}\n\n}\n\nconst _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' ];\n\nlet _seed = 1234567;\n\n\nconst DEG2RAD = Math.PI / 180;\nconst RAD2DEG = 180 / Math.PI;\n\n// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136\nfunction generateUUID() {\n\n\tconst d0 = Math.random() * 0xffffffff | 0;\n\tconst d1 = Math.random() * 0xffffffff | 0;\n\tconst d2 = Math.random() * 0xffffffff | 0;\n\tconst d3 = Math.random() * 0xffffffff | 0;\n\tconst uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +\n\t\t\t_lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +\n\t\t\t_lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +\n\t\t\t_lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];\n\n\t// .toLowerCase() here flattens concatenated strings to save heap memory space.\n\treturn uuid.toLowerCase();\n\n}\n\nfunction clamp( value, min, max ) {\n\n\treturn Math.max( min, Math.min( max, value ) );\n\n}\n\n// compute euclidean modulo of m % n\n// https://en.wikipedia.org/wiki/Modulo_operation\nfunction euclideanModulo( n, m ) {\n\n\treturn ( ( n % m ) + m ) % m;\n\n}\n\n// Linear mapping from range to range \nfunction mapLinear( x, a1, a2, b1, b2 ) {\n\n\treturn b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );\n\n}\n\n// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/\nfunction inverseLerp( x, y, value ) {\n\n\tif ( x !== y ) {\n\n\t\treturn ( value - x ) / ( y - x );\n\n\t} else {\n\n\t\treturn 0;\n\n\t}\n\n}\n\n// https://en.wikipedia.org/wiki/Linear_interpolation\nfunction lerp( x, y, t ) {\n\n\treturn ( 1 - t ) * x + t * y;\n\n}\n\n// http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/\nfunction damp( x, y, lambda, dt ) {\n\n\treturn lerp( x, y, 1 - Math.exp( - lambda * dt ) );\n\n}\n\n// https://www.desmos.com/calculator/vcsjnyz7x4\nfunction pingpong( x, length = 1 ) {\n\n\treturn length - Math.abs( euclideanModulo( x, length * 2 ) - length );\n\n}\n\n// http://en.wikipedia.org/wiki/Smoothstep\nfunction smoothstep( x, min, max ) {\n\n\tif ( x <= min ) return 0;\n\tif ( x >= max ) return 1;\n\n\tx = ( x - min ) / ( max - min );\n\n\treturn x * x * ( 3 - 2 * x );\n\n}\n\nfunction smootherstep( x, min, max ) {\n\n\tif ( x <= min ) return 0;\n\tif ( x >= max ) return 1;\n\n\tx = ( x - min ) / ( max - min );\n\n\treturn x * x * x * ( x * ( x * 6 - 15 ) + 10 );\n\n}\n\n// Random integer from interval\nfunction randInt( low, high ) {\n\n\treturn low + Math.floor( Math.random() * ( high - low + 1 ) );\n\n}\n\n// Random float from interval\nfunction randFloat( low, high ) {\n\n\treturn low + Math.random() * ( high - low );\n\n}\n\n// Random float from <-range/2, range/2> interval\nfunction randFloatSpread( range ) {\n\n\treturn range * ( 0.5 - Math.random() );\n\n}\n\n// Deterministic pseudo-random float in the interval [ 0, 1 ]\nfunction seededRandom( s ) {\n\n\tif ( s !== undefined ) _seed = s;\n\n\t// Mulberry32 generator\n\n\tlet t = _seed += 0x6D2B79F5;\n\n\tt = Math.imul( t ^ t >>> 15, t | 1 );\n\n\tt ^= t + Math.imul( t ^ t >>> 7, t | 61 );\n\n\treturn ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296;\n\n}\n\nfunction degToRad( degrees ) {\n\n\treturn degrees * DEG2RAD;\n\n}\n\nfunction radToDeg( radians ) {\n\n\treturn radians * RAD2DEG;\n\n}\n\nfunction isPowerOfTwo( value ) {\n\n\treturn ( value & ( value - 1 ) ) === 0 && value !== 0;\n\n}\n\nfunction ceilPowerOfTwo( value ) {\n\n\treturn Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );\n\n}\n\nfunction floorPowerOfTwo( value ) {\n\n\treturn Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );\n\n}\n\nfunction setQuaternionFromProperEuler( q, a, b, c, order ) {\n\n\t// Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles\n\n\t// rotations are applied to the axes in the order specified by 'order'\n\t// rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'\n\t// angles are in radians\n\n\tconst cos = Math.cos;\n\tconst sin = Math.sin;\n\n\tconst c2 = cos( b / 2 );\n\tconst s2 = sin( b / 2 );\n\n\tconst c13 = cos( ( a + c ) / 2 );\n\tconst s13 = sin( ( a + c ) / 2 );\n\n\tconst c1_3 = cos( ( a - c ) / 2 );\n\tconst s1_3 = sin( ( a - c ) / 2 );\n\n\tconst c3_1 = cos( ( c - a ) / 2 );\n\tconst s3_1 = sin( ( c - a ) / 2 );\n\n\tswitch ( order ) {\n\n\t\tcase 'XYX':\n\t\t\tq.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );\n\t\t\tbreak;\n\n\t\tcase 'YZY':\n\t\t\tq.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );\n\t\t\tbreak;\n\n\t\tcase 'ZXZ':\n\t\t\tq.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );\n\t\t\tbreak;\n\n\t\tcase 'XZX':\n\t\t\tq.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );\n\t\t\tbreak;\n\n\t\tcase 'YXY':\n\t\t\tq.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );\n\t\t\tbreak;\n\n\t\tcase 'ZYZ':\n\t\t\tq.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tconsole.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );\n\n\t}\n\n}\n\nfunction denormalize( value, array ) {\n\n\tswitch ( array.constructor ) {\n\n\t\tcase Float32Array:\n\n\t\t\treturn value;\n\n\t\tcase Uint32Array:\n\n\t\t\treturn value / 4294967295.0;\n\n\t\tcase Uint16Array:\n\n\t\t\treturn value / 65535.0;\n\n\t\tcase Uint8Array:\n\n\t\t\treturn value / 255.0;\n\n\t\tcase Int32Array:\n\n\t\t\treturn Math.max( value / 2147483647.0, - 1.0 );\n\n\t\tcase Int16Array:\n\n\t\t\treturn Math.max( value / 32767.0, - 1.0 );\n\n\t\tcase Int8Array:\n\n\t\t\treturn Math.max( value / 127.0, - 1.0 );\n\n\t\tdefault:\n\n\t\t\tthrow new Error( 'Invalid component type.' );\n\n\t}\n\n}\n\nfunction normalize( value, array ) {\n\n\tswitch ( array.constructor ) {\n\n\t\tcase Float32Array:\n\n\t\t\treturn value;\n\n\t\tcase Uint32Array:\n\n\t\t\treturn Math.round( value * 4294967295.0 );\n\n\t\tcase Uint16Array:\n\n\t\t\treturn Math.round( value * 65535.0 );\n\n\t\tcase Uint8Array:\n\n\t\t\treturn Math.round( value * 255.0 );\n\n\t\tcase Int32Array:\n\n\t\t\treturn Math.round( value * 2147483647.0 );\n\n\t\tcase Int16Array:\n\n\t\t\treturn Math.round( value * 32767.0 );\n\n\t\tcase Int8Array:\n\n\t\t\treturn Math.round( value * 127.0 );\n\n\t\tdefault:\n\n\t\t\tthrow new Error( 'Invalid component type.' );\n\n\t}\n\n}\n\nconst MathUtils = {\n\tDEG2RAD: DEG2RAD,\n\tRAD2DEG: RAD2DEG,\n\tgenerateUUID: generateUUID,\n\tclamp: clamp,\n\teuclideanModulo: euclideanModulo,\n\tmapLinear: mapLinear,\n\tinverseLerp: inverseLerp,\n\tlerp: lerp,\n\tdamp: damp,\n\tpingpong: pingpong,\n\tsmoothstep: smoothstep,\n\tsmootherstep: smootherstep,\n\trandInt: randInt,\n\trandFloat: randFloat,\n\trandFloatSpread: randFloatSpread,\n\tseededRandom: seededRandom,\n\tdegToRad: degToRad,\n\tradToDeg: radToDeg,\n\tisPowerOfTwo: isPowerOfTwo,\n\tceilPowerOfTwo: ceilPowerOfTwo,\n\tfloorPowerOfTwo: floorPowerOfTwo,\n\tsetQuaternionFromProperEuler: setQuaternionFromProperEuler,\n\tnormalize: normalize,\n\tdenormalize: denormalize\n};\n\nclass Vector2 {\n\n\tconstructor( x = 0, y = 0 ) {\n\n\t\tVector2.prototype.isVector2 = true;\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\n\t}\n\n\tget width() {\n\n\t\treturn this.x;\n\n\t}\n\n\tset width( value ) {\n\n\t\tthis.x = value;\n\n\t}\n\n\tget height() {\n\n\t\treturn this.y;\n\n\t}\n\n\tset height( value ) {\n\n\t\tthis.y = value;\n\n\t}\n\n\tset( x, y ) {\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetScalar( scalar ) {\n\n\t\tthis.x = scalar;\n\t\tthis.y = scalar;\n\n\t\treturn this;\n\n\t}\n\n\tsetX( x ) {\n\n\t\tthis.x = x;\n\n\t\treturn this;\n\n\t}\n\n\tsetY( y ) {\n\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetComponent( index, value ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: this.x = value; break;\n\t\t\tcase 1: this.y = value; break;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetComponent( index ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: return this.x;\n\t\t\tcase 1: return this.y;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.x, this.y );\n\n\t}\n\n\tcopy( v ) {\n\n\t\tthis.x = v.x;\n\t\tthis.y = v.y;\n\n\t\treturn this;\n\n\t}\n\n\tadd( v ) {\n\n\t\tthis.x += v.x;\n\t\tthis.y += v.y;\n\n\t\treturn this;\n\n\t}\n\n\taddScalar( s ) {\n\n\t\tthis.x += s;\n\t\tthis.y += s;\n\n\t\treturn this;\n\n\t}\n\n\taddVectors( a, b ) {\n\n\t\tthis.x = a.x + b.x;\n\t\tthis.y = a.y + b.y;\n\n\t\treturn this;\n\n\t}\n\n\taddScaledVector( v, s ) {\n\n\t\tthis.x += v.x * s;\n\t\tthis.y += v.y * s;\n\n\t\treturn this;\n\n\t}\n\n\tsub( v ) {\n\n\t\tthis.x -= v.x;\n\t\tthis.y -= v.y;\n\n\t\treturn this;\n\n\t}\n\n\tsubScalar( s ) {\n\n\t\tthis.x -= s;\n\t\tthis.y -= s;\n\n\t\treturn this;\n\n\t}\n\n\tsubVectors( a, b ) {\n\n\t\tthis.x = a.x - b.x;\n\t\tthis.y = a.y - b.y;\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( v ) {\n\n\t\tthis.x *= v.x;\n\t\tthis.y *= v.y;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( scalar ) {\n\n\t\tthis.x *= scalar;\n\t\tthis.y *= scalar;\n\n\t\treturn this;\n\n\t}\n\n\tdivide( v ) {\n\n\t\tthis.x /= v.x;\n\t\tthis.y /= v.y;\n\n\t\treturn this;\n\n\t}\n\n\tdivideScalar( scalar ) {\n\n\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t}\n\n\tapplyMatrix3( m ) {\n\n\t\tconst x = this.x, y = this.y;\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];\n\t\tthis.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];\n\n\t\treturn this;\n\n\t}\n\n\tmin( v ) {\n\n\t\tthis.x = Math.min( this.x, v.x );\n\t\tthis.y = Math.min( this.y, v.y );\n\n\t\treturn this;\n\n\t}\n\n\tmax( v ) {\n\n\t\tthis.x = Math.max( this.x, v.x );\n\t\tthis.y = Math.max( this.y, v.y );\n\n\t\treturn this;\n\n\t}\n\n\tclamp( min, max ) {\n\n\t\t// assumes min < max, componentwise\n\n\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampScalar( minVal, maxVal ) {\n\n\t\tthis.x = Math.max( minVal, Math.min( maxVal, this.x ) );\n\t\tthis.y = Math.max( minVal, Math.min( maxVal, this.y ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampLength( min, max ) {\n\n\t\tconst length = this.length();\n\n\t\treturn this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );\n\n\t}\n\n\tfloor() {\n\n\t\tthis.x = Math.floor( this.x );\n\t\tthis.y = Math.floor( this.y );\n\n\t\treturn this;\n\n\t}\n\n\tceil() {\n\n\t\tthis.x = Math.ceil( this.x );\n\t\tthis.y = Math.ceil( this.y );\n\n\t\treturn this;\n\n\t}\n\n\tround() {\n\n\t\tthis.x = Math.round( this.x );\n\t\tthis.y = Math.round( this.y );\n\n\t\treturn this;\n\n\t}\n\n\troundToZero() {\n\n\t\tthis.x = Math.trunc( this.x );\n\t\tthis.y = Math.trunc( this.y );\n\n\t\treturn this;\n\n\t}\n\n\tnegate() {\n\n\t\tthis.x = - this.x;\n\t\tthis.y = - this.y;\n\n\t\treturn this;\n\n\t}\n\n\tdot( v ) {\n\n\t\treturn this.x * v.x + this.y * v.y;\n\n\t}\n\n\tcross( v ) {\n\n\t\treturn this.x * v.y - this.y * v.x;\n\n\t}\n\n\tlengthSq() {\n\n\t\treturn this.x * this.x + this.y * this.y;\n\n\t}\n\n\tlength() {\n\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y );\n\n\t}\n\n\tmanhattanLength() {\n\n\t\treturn Math.abs( this.x ) + Math.abs( this.y );\n\n\t}\n\n\tnormalize() {\n\n\t\treturn this.divideScalar( this.length() || 1 );\n\n\t}\n\n\tangle() {\n\n\t\t// computes the angle in radians with respect to the positive x-axis\n\n\t\tconst angle = Math.atan2( - this.y, - this.x ) + Math.PI;\n\n\t\treturn angle;\n\n\t}\n\n\tangleTo( v ) {\n\n\t\tconst denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );\n\n\t\tif ( denominator === 0 ) return Math.PI / 2;\n\n\t\tconst theta = this.dot( v ) / denominator;\n\n\t\t// clamp, to handle numerical problems\n\n\t\treturn Math.acos( clamp( theta, - 1, 1 ) );\n\n\t}\n\n\tdistanceTo( v ) {\n\n\t\treturn Math.sqrt( this.distanceToSquared( v ) );\n\n\t}\n\n\tdistanceToSquared( v ) {\n\n\t\tconst dx = this.x - v.x, dy = this.y - v.y;\n\t\treturn dx * dx + dy * dy;\n\n\t}\n\n\tmanhattanDistanceTo( v ) {\n\n\t\treturn Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );\n\n\t}\n\n\tsetLength( length ) {\n\n\t\treturn this.normalize().multiplyScalar( length );\n\n\t}\n\n\tlerp( v, alpha ) {\n\n\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\tthis.y += ( v.y - this.y ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tlerpVectors( v1, v2, alpha ) {\n\n\t\tthis.x = v1.x + ( v2.x - v1.x ) * alpha;\n\t\tthis.y = v1.y + ( v2.y - v1.y ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tequals( v ) {\n\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tthis.x = array[ offset ];\n\t\tthis.y = array[ offset + 1 ];\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this.x;\n\t\tarray[ offset + 1 ] = this.y;\n\n\t\treturn array;\n\n\t}\n\n\tfromBufferAttribute( attribute, index ) {\n\n\t\tthis.x = attribute.getX( index );\n\t\tthis.y = attribute.getY( index );\n\n\t\treturn this;\n\n\t}\n\n\trotateAround( center, angle ) {\n\n\t\tconst c = Math.cos( angle ), s = Math.sin( angle );\n\n\t\tconst x = this.x - center.x;\n\t\tconst y = this.y - center.y;\n\n\t\tthis.x = x * c - y * s + center.x;\n\t\tthis.y = x * s + y * c + center.y;\n\n\t\treturn this;\n\n\t}\n\n\trandom() {\n\n\t\tthis.x = Math.random();\n\t\tthis.y = Math.random();\n\n\t\treturn this;\n\n\t}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this.x;\n\t\tyield this.y;\n\n\t}\n\n}\n\nclass Matrix3 {\n\n\tconstructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {\n\n\t\tMatrix3.prototype.isMatrix3 = true;\n\n\t\tthis.elements = [\n\n\t\t\t1, 0, 0,\n\t\t\t0, 1, 0,\n\t\t\t0, 0, 1\n\n\t\t];\n\n\t\tif ( n11 !== undefined ) {\n\n\t\t\tthis.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 );\n\n\t\t}\n\n\t}\n\n\tset( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {\n\n\t\tconst te = this.elements;\n\n\t\tte[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;\n\t\tte[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;\n\t\tte[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;\n\n\t\treturn this;\n\n\t}\n\n\tidentity() {\n\n\t\tthis.set(\n\n\t\t\t1, 0, 0,\n\t\t\t0, 1, 0,\n\t\t\t0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tcopy( m ) {\n\n\t\tconst te = this.elements;\n\t\tconst me = m.elements;\n\n\t\tte[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];\n\t\tte[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];\n\t\tte[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];\n\n\t\treturn this;\n\n\t}\n\n\textractBasis( xAxis, yAxis, zAxis ) {\n\n\t\txAxis.setFromMatrix3Column( this, 0 );\n\t\tyAxis.setFromMatrix3Column( this, 1 );\n\t\tzAxis.setFromMatrix3Column( this, 2 );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrix4( m ) {\n\n\t\tconst me = m.elements;\n\n\t\tthis.set(\n\n\t\t\tme[ 0 ], me[ 4 ], me[ 8 ],\n\t\t\tme[ 1 ], me[ 5 ], me[ 9 ],\n\t\t\tme[ 2 ], me[ 6 ], me[ 10 ]\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( m ) {\n\n\t\treturn this.multiplyMatrices( this, m );\n\n\t}\n\n\tpremultiply( m ) {\n\n\t\treturn this.multiplyMatrices( m, this );\n\n\t}\n\n\tmultiplyMatrices( a, b ) {\n\n\t\tconst ae = a.elements;\n\t\tconst be = b.elements;\n\t\tconst te = this.elements;\n\n\t\tconst a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];\n\t\tconst a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];\n\t\tconst a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];\n\n\t\tconst b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];\n\t\tconst b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];\n\t\tconst b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];\n\n\t\tte[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;\n\t\tte[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;\n\t\tte[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;\n\n\t\tte[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;\n\t\tte[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;\n\t\tte[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;\n\n\t\tte[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;\n\t\tte[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;\n\t\tte[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( s ) {\n\n\t\tconst te = this.elements;\n\n\t\tte[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;\n\t\tte[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;\n\t\tte[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;\n\n\t\treturn this;\n\n\t}\n\n\tdeterminant() {\n\n\t\tconst te = this.elements;\n\n\t\tconst a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],\n\t\t\td = te[ 3 ], e = te[ 4 ], f = te[ 5 ],\n\t\t\tg = te[ 6 ], h = te[ 7 ], i = te[ 8 ];\n\n\t\treturn a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;\n\n\t}\n\n\tinvert() {\n\n\t\tconst te = this.elements,\n\n\t\t\tn11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],\n\t\t\tn12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ],\n\t\t\tn13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ],\n\n\t\t\tt11 = n33 * n22 - n32 * n23,\n\t\t\tt12 = n32 * n13 - n33 * n12,\n\t\t\tt13 = n23 * n12 - n22 * n13,\n\n\t\t\tdet = n11 * t11 + n21 * t12 + n31 * t13;\n\n\t\tif ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );\n\n\t\tconst detInv = 1 / det;\n\n\t\tte[ 0 ] = t11 * detInv;\n\t\tte[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;\n\t\tte[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;\n\n\t\tte[ 3 ] = t12 * detInv;\n\t\tte[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;\n\t\tte[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;\n\n\t\tte[ 6 ] = t13 * detInv;\n\t\tte[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;\n\t\tte[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;\n\n\t\treturn this;\n\n\t}\n\n\ttranspose() {\n\n\t\tlet tmp;\n\t\tconst m = this.elements;\n\n\t\ttmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;\n\t\ttmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;\n\t\ttmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;\n\n\t\treturn this;\n\n\t}\n\n\tgetNormalMatrix( matrix4 ) {\n\n\t\treturn this.setFromMatrix4( matrix4 ).invert().transpose();\n\n\t}\n\n\ttransposeIntoArray( r ) {\n\n\t\tconst m = this.elements;\n\n\t\tr[ 0 ] = m[ 0 ];\n\t\tr[ 1 ] = m[ 3 ];\n\t\tr[ 2 ] = m[ 6 ];\n\t\tr[ 3 ] = m[ 1 ];\n\t\tr[ 4 ] = m[ 4 ];\n\t\tr[ 5 ] = m[ 7 ];\n\t\tr[ 6 ] = m[ 2 ];\n\t\tr[ 7 ] = m[ 5 ];\n\t\tr[ 8 ] = m[ 8 ];\n\n\t\treturn this;\n\n\t}\n\n\tsetUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {\n\n\t\tconst c = Math.cos( rotation );\n\t\tconst s = Math.sin( rotation );\n\n\t\tthis.set(\n\t\t\tsx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,\n\t\t\t- sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,\n\t\t\t0, 0, 1\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\t//\n\n\tscale( sx, sy ) {\n\n\t\tthis.premultiply( _m3.makeScale( sx, sy ) );\n\n\t\treturn this;\n\n\t}\n\n\trotate( theta ) {\n\n\t\tthis.premultiply( _m3.makeRotation( - theta ) );\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( tx, ty ) {\n\n\t\tthis.premultiply( _m3.makeTranslation( tx, ty ) );\n\n\t\treturn this;\n\n\t}\n\n\t// for 2D Transforms\n\n\tmakeTranslation( x, y ) {\n\n\t\tif ( x.isVector2 ) {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0, x.x,\n\t\t\t\t0, 1, x.y,\n\t\t\t\t0, 0, 1\n\n\t\t\t);\n\n\t\t} else {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0, x,\n\t\t\t\t0, 1, y,\n\t\t\t\t0, 0, 1\n\n\t\t\t);\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotation( theta ) {\n\n\t\t// counterclockwise\n\n\t\tconst c = Math.cos( theta );\n\t\tconst s = Math.sin( theta );\n\n\t\tthis.set(\n\n\t\t\tc, - s, 0,\n\t\t\ts, c, 0,\n\t\t\t0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeScale( x, y ) {\n\n\t\tthis.set(\n\n\t\t\tx, 0, 0,\n\t\t\t0, y, 0,\n\t\t\t0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\t//\n\n\tequals( matrix ) {\n\n\t\tconst te = this.elements;\n\t\tconst me = matrix.elements;\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tif ( te[ i ] !== me[ i ] ) return false;\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.elements[ i ] = array[ i + offset ];\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tconst te = this.elements;\n\n\t\tarray[ offset ] = te[ 0 ];\n\t\tarray[ offset + 1 ] = te[ 1 ];\n\t\tarray[ offset + 2 ] = te[ 2 ];\n\n\t\tarray[ offset + 3 ] = te[ 3 ];\n\t\tarray[ offset + 4 ] = te[ 4 ];\n\t\tarray[ offset + 5 ] = te[ 5 ];\n\n\t\tarray[ offset + 6 ] = te[ 6 ];\n\t\tarray[ offset + 7 ] = te[ 7 ];\n\t\tarray[ offset + 8 ] = te[ 8 ];\n\n\t\treturn array;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().fromArray( this.elements );\n\n\t}\n\n}\n\nconst _m3 = /*@__PURE__*/ new Matrix3();\n\nfunction arrayNeedsUint32( array ) {\n\n\t// assumes larger values usually on last\n\n\tfor ( let i = array.length - 1; i >= 0; -- i ) {\n\n\t\tif ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565\n\n\t}\n\n\treturn false;\n\n}\n\nconst TYPED_ARRAYS = {\n\tInt8Array: Int8Array,\n\tUint8Array: Uint8Array,\n\tUint8ClampedArray: Uint8ClampedArray,\n\tInt16Array: Int16Array,\n\tUint16Array: Uint16Array,\n\tInt32Array: Int32Array,\n\tUint32Array: Uint32Array,\n\tFloat32Array: Float32Array,\n\tFloat64Array: Float64Array\n};\n\nfunction getTypedArray( type, buffer ) {\n\n\treturn new TYPED_ARRAYS[ type ]( buffer );\n\n}\n\nfunction createElementNS( name ) {\n\n\treturn document.createElementNS( 'http://www.w3.org/1999/xhtml', name );\n\n}\n\nfunction createCanvasElement() {\n\n\tconst canvas = createElementNS( 'canvas' );\n\tcanvas.style.display = 'block';\n\treturn canvas;\n\n}\n\nconst _cache = {};\n\nfunction warnOnce( message ) {\n\n\tif ( message in _cache ) return;\n\n\t_cache[ message ] = true;\n\n\tconsole.warn( message );\n\n}\n\nfunction probeAsync( gl, sync, interval ) {\n\n\treturn new Promise( function ( resolve, reject ) {\n\n\t\tfunction probe() {\n\n\t\t\tswitch ( gl.clientWaitSync( sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0 ) ) {\n\n\t\t\t\tcase gl.WAIT_FAILED:\n\t\t\t\t\treject();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase gl.TIMEOUT_EXPIRED:\n\t\t\t\t\tsetTimeout( probe, interval );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tresolve();\n\n\t\t\t}\n\n\t\t}\n\n\t\tsetTimeout( probe, interval );\n\n\t} );\n\n}\n\n/**\n * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping\n * or clipping. Based on W3C specifications for sRGB and Display P3,\n * and ICC specifications for the D50 connection space. Values in/out\n * are _linear_ sRGB and _linear_ Display P3.\n *\n * Note that both sRGB and Display P3 use the sRGB transfer functions.\n *\n * Reference:\n * - http://www.russellcottrell.com/photo/matrixCalculator.htm\n */\n\nconst LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set(\n\t0.8224621, 0.177538, 0.0,\n\t0.0331941, 0.9668058, 0.0,\n\t0.0170827, 0.0723974, 0.9105199,\n);\n\nconst LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set(\n\t1.2249401, - 0.2249404, 0.0,\n\t- 0.0420569, 1.0420571, 0.0,\n\t- 0.0196376, - 0.0786361, 1.0982735\n);\n\n/**\n * Defines supported color spaces by transfer function and primaries,\n * and provides conversions to/from the Linear-sRGB reference space.\n */\nconst COLOR_SPACES = {\n\t[ LinearSRGBColorSpace ]: {\n\t\ttransfer: LinearTransfer,\n\t\tprimaries: Rec709Primaries,\n\t\ttoReference: ( color ) => color,\n\t\tfromReference: ( color ) => color,\n\t},\n\t[ SRGBColorSpace ]: {\n\t\ttransfer: SRGBTransfer,\n\t\tprimaries: Rec709Primaries,\n\t\ttoReference: ( color ) => color.convertSRGBToLinear(),\n\t\tfromReference: ( color ) => color.convertLinearToSRGB(),\n\t},\n\t[ LinearDisplayP3ColorSpace ]: {\n\t\ttransfer: LinearTransfer,\n\t\tprimaries: P3Primaries,\n\t\ttoReference: ( color ) => color.applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ),\n\t\tfromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ),\n\t},\n\t[ DisplayP3ColorSpace ]: {\n\t\ttransfer: SRGBTransfer,\n\t\tprimaries: P3Primaries,\n\t\ttoReference: ( color ) => color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ),\n\t\tfromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB(),\n\t},\n};\n\nconst SUPPORTED_WORKING_COLOR_SPACES = new Set( [ LinearSRGBColorSpace, LinearDisplayP3ColorSpace ] );\n\nconst ColorManagement = {\n\n\tenabled: true,\n\n\t_workingColorSpace: LinearSRGBColorSpace,\n\n\tget workingColorSpace() {\n\n\t\treturn this._workingColorSpace;\n\n\t},\n\n\tset workingColorSpace( colorSpace ) {\n\n\t\tif ( ! SUPPORTED_WORKING_COLOR_SPACES.has( colorSpace ) ) {\n\n\t\t\tthrow new Error( `Unsupported working color space, \"${ colorSpace }\".` );\n\n\t\t}\n\n\t\tthis._workingColorSpace = colorSpace;\n\n\t},\n\n\tconvert: function ( color, sourceColorSpace, targetColorSpace ) {\n\n\t\tif ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) {\n\n\t\t\treturn color;\n\n\t\t}\n\n\t\tconst sourceToReference = COLOR_SPACES[ sourceColorSpace ].toReference;\n\t\tconst targetFromReference = COLOR_SPACES[ targetColorSpace ].fromReference;\n\n\t\treturn targetFromReference( sourceToReference( color ) );\n\n\t},\n\n\tfromWorkingColorSpace: function ( color, targetColorSpace ) {\n\n\t\treturn this.convert( color, this._workingColorSpace, targetColorSpace );\n\n\t},\n\n\ttoWorkingColorSpace: function ( color, sourceColorSpace ) {\n\n\t\treturn this.convert( color, sourceColorSpace, this._workingColorSpace );\n\n\t},\n\n\tgetPrimaries: function ( colorSpace ) {\n\n\t\treturn COLOR_SPACES[ colorSpace ].primaries;\n\n\t},\n\n\tgetTransfer: function ( colorSpace ) {\n\n\t\tif ( colorSpace === NoColorSpace ) return LinearTransfer;\n\n\t\treturn COLOR_SPACES[ colorSpace ].transfer;\n\n\t},\n\n};\n\n\nfunction SRGBToLinear( c ) {\n\n\treturn ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );\n\n}\n\nfunction LinearToSRGB( c ) {\n\n\treturn ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;\n\n}\n\nlet _canvas;\n\nclass ImageUtils {\n\n\tstatic getDataURL( image ) {\n\n\t\tif ( /^data:/i.test( image.src ) ) {\n\n\t\t\treturn image.src;\n\n\t\t}\n\n\t\tif ( typeof HTMLCanvasElement === 'undefined' ) {\n\n\t\t\treturn image.src;\n\n\t\t}\n\n\t\tlet canvas;\n\n\t\tif ( image instanceof HTMLCanvasElement ) {\n\n\t\t\tcanvas = image;\n\n\t\t} else {\n\n\t\t\tif ( _canvas === undefined ) _canvas = createElementNS( 'canvas' );\n\n\t\t\t_canvas.width = image.width;\n\t\t\t_canvas.height = image.height;\n\n\t\t\tconst context = _canvas.getContext( '2d' );\n\n\t\t\tif ( image instanceof ImageData ) {\n\n\t\t\t\tcontext.putImageData( image, 0, 0 );\n\n\t\t\t} else {\n\n\t\t\t\tcontext.drawImage( image, 0, 0, image.width, image.height );\n\n\t\t\t}\n\n\t\t\tcanvas = _canvas;\n\n\t\t}\n\n\t\tif ( canvas.width > 2048 || canvas.height > 2048 ) {\n\n\t\t\tconsole.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image );\n\n\t\t\treturn canvas.toDataURL( 'image/jpeg', 0.6 );\n\n\t\t} else {\n\n\t\t\treturn canvas.toDataURL( 'image/png' );\n\n\t\t}\n\n\t}\n\n\tstatic sRGBToLinear( image ) {\n\n\t\tif ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||\n\t\t\t( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||\n\t\t\t( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {\n\n\t\t\tconst canvas = createElementNS( 'canvas' );\n\n\t\t\tcanvas.width = image.width;\n\t\t\tcanvas.height = image.height;\n\n\t\t\tconst context = canvas.getContext( '2d' );\n\t\t\tcontext.drawImage( image, 0, 0, image.width, image.height );\n\n\t\t\tconst imageData = context.getImageData( 0, 0, image.width, image.height );\n\t\t\tconst data = imageData.data;\n\n\t\t\tfor ( let i = 0; i < data.length; i ++ ) {\n\n\t\t\t\tdata[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255;\n\n\t\t\t}\n\n\t\t\tcontext.putImageData( imageData, 0, 0 );\n\n\t\t\treturn canvas;\n\n\t\t} else if ( image.data ) {\n\n\t\t\tconst data = image.data.slice( 0 );\n\n\t\t\tfor ( let i = 0; i < data.length; i ++ ) {\n\n\t\t\t\tif ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) {\n\n\t\t\t\t\tdata[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// assuming float\n\n\t\t\t\t\tdata[ i ] = SRGBToLinear( data[ i ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tdata: data,\n\t\t\t\twidth: image.width,\n\t\t\t\theight: image.height\n\t\t\t};\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' );\n\t\t\treturn image;\n\n\t\t}\n\n\t}\n\n}\n\nlet _sourceId = 0;\n\nclass Source {\n\n\tconstructor( data = null ) {\n\n\t\tthis.isSource = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _sourceId ++ } );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.data = data;\n\t\tthis.dataReady = true;\n\n\t\tthis.version = 0;\n\n\t}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst isRootObject = ( meta === undefined || typeof meta === 'string' );\n\n\t\tif ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) {\n\n\t\t\treturn meta.images[ this.uuid ];\n\n\t\t}\n\n\t\tconst output = {\n\t\t\tuuid: this.uuid,\n\t\t\turl: ''\n\t\t};\n\n\t\tconst data = this.data;\n\n\t\tif ( data !== null ) {\n\n\t\t\tlet url;\n\n\t\t\tif ( Array.isArray( data ) ) {\n\n\t\t\t\t// cube texture\n\n\t\t\t\turl = [];\n\n\t\t\t\tfor ( let i = 0, l = data.length; i < l; i ++ ) {\n\n\t\t\t\t\tif ( data[ i ].isDataTexture ) {\n\n\t\t\t\t\t\turl.push( serializeImage( data[ i ].image ) );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\turl.push( serializeImage( data[ i ] ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// texture\n\n\t\t\t\turl = serializeImage( data );\n\n\t\t\t}\n\n\t\t\toutput.url = url;\n\n\t\t}\n\n\t\tif ( ! isRootObject ) {\n\n\t\t\tmeta.images[ this.uuid ] = output;\n\n\t\t}\n\n\t\treturn output;\n\n\t}\n\n}\n\nfunction serializeImage( image ) {\n\n\tif ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||\n\t\t( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||\n\t\t( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {\n\n\t\t// default images\n\n\t\treturn ImageUtils.getDataURL( image );\n\n\t} else {\n\n\t\tif ( image.data ) {\n\n\t\t\t// images of DataTexture\n\n\t\t\treturn {\n\t\t\t\tdata: Array.from( image.data ),\n\t\t\t\twidth: image.width,\n\t\t\t\theight: image.height,\n\t\t\t\ttype: image.data.constructor.name\n\t\t\t};\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.Texture: Unable to serialize Texture.' );\n\t\t\treturn {};\n\n\t\t}\n\n\t}\n\n}\n\nlet _textureId = 0;\n\nclass Texture extends EventDispatcher {\n\n\tconstructor( 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 ) {\n\n\t\tsuper();\n\n\t\tthis.isTexture = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _textureId ++ } );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.name = '';\n\n\t\tthis.source = new Source( image );\n\t\tthis.mipmaps = [];\n\n\t\tthis.mapping = mapping;\n\t\tthis.channel = 0;\n\n\t\tthis.wrapS = wrapS;\n\t\tthis.wrapT = wrapT;\n\n\t\tthis.magFilter = magFilter;\n\t\tthis.minFilter = minFilter;\n\n\t\tthis.anisotropy = anisotropy;\n\n\t\tthis.format = format;\n\t\tthis.internalFormat = null;\n\t\tthis.type = type;\n\n\t\tthis.offset = new Vector2( 0, 0 );\n\t\tthis.repeat = new Vector2( 1, 1 );\n\t\tthis.center = new Vector2( 0, 0 );\n\t\tthis.rotation = 0;\n\n\t\tthis.matrixAutoUpdate = true;\n\t\tthis.matrix = new Matrix3();\n\n\t\tthis.generateMipmaps = true;\n\t\tthis.premultiplyAlpha = false;\n\t\tthis.flipY = true;\n\t\tthis.unpackAlignment = 4;\t// valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)\n\n\t\tthis.colorSpace = colorSpace;\n\n\t\tthis.userData = {};\n\n\t\tthis.version = 0;\n\t\tthis.onUpdate = null;\n\n\t\tthis.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not\n\t\tthis.pmremVersion = 0; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures)\n\n\t}\n\n\tget image() {\n\n\t\treturn this.source.data;\n\n\t}\n\n\tset image( value = null ) {\n\n\t\tthis.source.data = value;\n\n\t}\n\n\tupdateMatrix() {\n\n\t\tthis.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.name = source.name;\n\n\t\tthis.source = source.source;\n\t\tthis.mipmaps = source.mipmaps.slice( 0 );\n\n\t\tthis.mapping = source.mapping;\n\t\tthis.channel = source.channel;\n\n\t\tthis.wrapS = source.wrapS;\n\t\tthis.wrapT = source.wrapT;\n\n\t\tthis.magFilter = source.magFilter;\n\t\tthis.minFilter = source.minFilter;\n\n\t\tthis.anisotropy = source.anisotropy;\n\n\t\tthis.format = source.format;\n\t\tthis.internalFormat = source.internalFormat;\n\t\tthis.type = source.type;\n\n\t\tthis.offset.copy( source.offset );\n\t\tthis.repeat.copy( source.repeat );\n\t\tthis.center.copy( source.center );\n\t\tthis.rotation = source.rotation;\n\n\t\tthis.matrixAutoUpdate = source.matrixAutoUpdate;\n\t\tthis.matrix.copy( source.matrix );\n\n\t\tthis.generateMipmaps = source.generateMipmaps;\n\t\tthis.premultiplyAlpha = source.premultiplyAlpha;\n\t\tthis.flipY = source.flipY;\n\t\tthis.unpackAlignment = source.unpackAlignment;\n\t\tthis.colorSpace = source.colorSpace;\n\n\t\tthis.userData = JSON.parse( JSON.stringify( source.userData ) );\n\n\t\tthis.needsUpdate = true;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst isRootObject = ( meta === undefined || typeof meta === 'string' );\n\n\t\tif ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {\n\n\t\t\treturn meta.textures[ this.uuid ];\n\n\t\t}\n\n\t\tconst output = {\n\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'Texture',\n\t\t\t\tgenerator: 'Texture.toJSON'\n\t\t\t},\n\n\t\t\tuuid: this.uuid,\n\t\t\tname: this.name,\n\n\t\t\timage: this.source.toJSON( meta ).uuid,\n\n\t\t\tmapping: this.mapping,\n\t\t\tchannel: this.channel,\n\n\t\t\trepeat: [ this.repeat.x, this.repeat.y ],\n\t\t\toffset: [ this.offset.x, this.offset.y ],\n\t\t\tcenter: [ this.center.x, this.center.y ],\n\t\t\trotation: this.rotation,\n\n\t\t\twrap: [ this.wrapS, this.wrapT ],\n\n\t\t\tformat: this.format,\n\t\t\tinternalFormat: this.internalFormat,\n\t\t\ttype: this.type,\n\t\t\tcolorSpace: this.colorSpace,\n\n\t\t\tminFilter: this.minFilter,\n\t\t\tmagFilter: this.magFilter,\n\t\t\tanisotropy: this.anisotropy,\n\n\t\t\tflipY: this.flipY,\n\n\t\t\tgenerateMipmaps: this.generateMipmaps,\n\t\t\tpremultiplyAlpha: this.premultiplyAlpha,\n\t\t\tunpackAlignment: this.unpackAlignment\n\n\t\t};\n\n\t\tif ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData;\n\n\t\tif ( ! isRootObject ) {\n\n\t\t\tmeta.textures[ this.uuid ] = output;\n\n\t\t}\n\n\t\treturn output;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n\ttransformUv( uv ) {\n\n\t\tif ( this.mapping !== UVMapping ) return uv;\n\n\t\tuv.applyMatrix3( this.matrix );\n\n\t\tif ( uv.x < 0 || uv.x > 1 ) {\n\n\t\t\tswitch ( this.wrapS ) {\n\n\t\t\t\tcase RepeatWrapping:\n\n\t\t\t\t\tuv.x = uv.x - Math.floor( uv.x );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ClampToEdgeWrapping:\n\n\t\t\t\t\tuv.x = uv.x < 0 ? 0 : 1;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MirroredRepeatWrapping:\n\n\t\t\t\t\tif ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {\n\n\t\t\t\t\t\tuv.x = Math.ceil( uv.x ) - uv.x;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tuv.x = uv.x - Math.floor( uv.x );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( uv.y < 0 || uv.y > 1 ) {\n\n\t\t\tswitch ( this.wrapT ) {\n\n\t\t\t\tcase RepeatWrapping:\n\n\t\t\t\t\tuv.y = uv.y - Math.floor( uv.y );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ClampToEdgeWrapping:\n\n\t\t\t\t\tuv.y = uv.y < 0 ? 0 : 1;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MirroredRepeatWrapping:\n\n\t\t\t\t\tif ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {\n\n\t\t\t\t\t\tuv.y = Math.ceil( uv.y ) - uv.y;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tuv.y = uv.y - Math.floor( uv.y );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.flipY ) {\n\n\t\t\tuv.y = 1 - uv.y;\n\n\t\t}\n\n\t\treturn uv;\n\n\t}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) {\n\n\t\t\tthis.version ++;\n\t\t\tthis.source.needsUpdate = true;\n\n\t\t}\n\n\t}\n\n\tset needsPMREMUpdate( value ) {\n\n\t\tif ( value === true ) {\n\n\t\t\tthis.pmremVersion ++;\n\n\t\t}\n\n\t}\n\n}\n\nTexture.DEFAULT_IMAGE = null;\nTexture.DEFAULT_MAPPING = UVMapping;\nTexture.DEFAULT_ANISOTROPY = 1;\n\nclass Vector4 {\n\n\tconstructor( x = 0, y = 0, z = 0, w = 1 ) {\n\n\t\tVector4.prototype.isVector4 = true;\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.z = z;\n\t\tthis.w = w;\n\n\t}\n\n\tget width() {\n\n\t\treturn this.z;\n\n\t}\n\n\tset width( value ) {\n\n\t\tthis.z = value;\n\n\t}\n\n\tget height() {\n\n\t\treturn this.w;\n\n\t}\n\n\tset height( value ) {\n\n\t\tthis.w = value;\n\n\t}\n\n\tset( x, y, z, w ) {\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.z = z;\n\t\tthis.w = w;\n\n\t\treturn this;\n\n\t}\n\n\tsetScalar( scalar ) {\n\n\t\tthis.x = scalar;\n\t\tthis.y = scalar;\n\t\tthis.z = scalar;\n\t\tthis.w = scalar;\n\n\t\treturn this;\n\n\t}\n\n\tsetX( x ) {\n\n\t\tthis.x = x;\n\n\t\treturn this;\n\n\t}\n\n\tsetY( y ) {\n\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetZ( z ) {\n\n\t\tthis.z = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetW( w ) {\n\n\t\tthis.w = w;\n\n\t\treturn this;\n\n\t}\n\n\tsetComponent( index, value ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: this.x = value; break;\n\t\t\tcase 1: this.y = value; break;\n\t\t\tcase 2: this.z = value; break;\n\t\t\tcase 3: this.w = value; break;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetComponent( index ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: return this.x;\n\t\t\tcase 1: return this.y;\n\t\t\tcase 2: return this.z;\n\t\t\tcase 3: return this.w;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.x, this.y, this.z, this.w );\n\n\t}\n\n\tcopy( v ) {\n\n\t\tthis.x = v.x;\n\t\tthis.y = v.y;\n\t\tthis.z = v.z;\n\t\tthis.w = ( v.w !== undefined ) ? v.w : 1;\n\n\t\treturn this;\n\n\t}\n\n\tadd( v ) {\n\n\t\tthis.x += v.x;\n\t\tthis.y += v.y;\n\t\tthis.z += v.z;\n\t\tthis.w += v.w;\n\n\t\treturn this;\n\n\t}\n\n\taddScalar( s ) {\n\n\t\tthis.x += s;\n\t\tthis.y += s;\n\t\tthis.z += s;\n\t\tthis.w += s;\n\n\t\treturn this;\n\n\t}\n\n\taddVectors( a, b ) {\n\n\t\tthis.x = a.x + b.x;\n\t\tthis.y = a.y + b.y;\n\t\tthis.z = a.z + b.z;\n\t\tthis.w = a.w + b.w;\n\n\t\treturn this;\n\n\t}\n\n\taddScaledVector( v, s ) {\n\n\t\tthis.x += v.x * s;\n\t\tthis.y += v.y * s;\n\t\tthis.z += v.z * s;\n\t\tthis.w += v.w * s;\n\n\t\treturn this;\n\n\t}\n\n\tsub( v ) {\n\n\t\tthis.x -= v.x;\n\t\tthis.y -= v.y;\n\t\tthis.z -= v.z;\n\t\tthis.w -= v.w;\n\n\t\treturn this;\n\n\t}\n\n\tsubScalar( s ) {\n\n\t\tthis.x -= s;\n\t\tthis.y -= s;\n\t\tthis.z -= s;\n\t\tthis.w -= s;\n\n\t\treturn this;\n\n\t}\n\n\tsubVectors( a, b ) {\n\n\t\tthis.x = a.x - b.x;\n\t\tthis.y = a.y - b.y;\n\t\tthis.z = a.z - b.z;\n\t\tthis.w = a.w - b.w;\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( v ) {\n\n\t\tthis.x *= v.x;\n\t\tthis.y *= v.y;\n\t\tthis.z *= v.z;\n\t\tthis.w *= v.w;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( scalar ) {\n\n\t\tthis.x *= scalar;\n\t\tthis.y *= scalar;\n\t\tthis.z *= scalar;\n\t\tthis.w *= scalar;\n\n\t\treturn this;\n\n\t}\n\n\tapplyMatrix4( m ) {\n\n\t\tconst x = this.x, y = this.y, z = this.z, w = this.w;\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;\n\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;\n\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;\n\t\tthis.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;\n\n\t\treturn this;\n\n\t}\n\n\tdivideScalar( scalar ) {\n\n\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t}\n\n\tsetAxisAngleFromQuaternion( q ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm\n\n\t\t// q is assumed to be normalized\n\n\t\tthis.w = 2 * Math.acos( q.w );\n\n\t\tconst s = Math.sqrt( 1 - q.w * q.w );\n\n\t\tif ( s < 0.0001 ) {\n\n\t\t\tthis.x = 1;\n\t\t\tthis.y = 0;\n\t\t\tthis.z = 0;\n\n\t\t} else {\n\n\t\t\tthis.x = q.x / s;\n\t\t\tthis.y = q.y / s;\n\t\t\tthis.z = q.z / s;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetAxisAngleFromRotationMatrix( m ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tlet angle, x, y, z; // variables for result\n\t\tconst epsilon = 0.01,\t\t// margin to allow for rounding errors\n\t\t\tepsilon2 = 0.1,\t\t// margin to distinguish between 0 and 180 degrees\n\n\t\t\tte = m.elements,\n\n\t\t\tm11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],\n\t\t\tm21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],\n\t\t\tm31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];\n\n\t\tif ( ( Math.abs( m12 - m21 ) < epsilon ) &&\n\t\t ( Math.abs( m13 - m31 ) < epsilon ) &&\n\t\t ( Math.abs( m23 - m32 ) < epsilon ) ) {\n\n\t\t\t// singularity found\n\t\t\t// first check for identity matrix which must have +1 for all terms\n\t\t\t// in leading diagonal and zero in other terms\n\n\t\t\tif ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&\n\t\t\t ( Math.abs( m13 + m31 ) < epsilon2 ) &&\n\t\t\t ( Math.abs( m23 + m32 ) < epsilon2 ) &&\n\t\t\t ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {\n\n\t\t\t\t// this singularity is identity matrix so angle = 0\n\n\t\t\t\tthis.set( 1, 0, 0, 0 );\n\n\t\t\t\treturn this; // zero angle, arbitrary axis\n\n\t\t\t}\n\n\t\t\t// otherwise this singularity is angle = 180\n\n\t\t\tangle = Math.PI;\n\n\t\t\tconst xx = ( m11 + 1 ) / 2;\n\t\t\tconst yy = ( m22 + 1 ) / 2;\n\t\t\tconst zz = ( m33 + 1 ) / 2;\n\t\t\tconst xy = ( m12 + m21 ) / 4;\n\t\t\tconst xz = ( m13 + m31 ) / 4;\n\t\t\tconst yz = ( m23 + m32 ) / 4;\n\n\t\t\tif ( ( xx > yy ) && ( xx > zz ) ) {\n\n\t\t\t\t// m11 is the largest diagonal term\n\n\t\t\t\tif ( xx < epsilon ) {\n\n\t\t\t\t\tx = 0;\n\t\t\t\t\ty = 0.707106781;\n\t\t\t\t\tz = 0.707106781;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tx = Math.sqrt( xx );\n\t\t\t\t\ty = xy / x;\n\t\t\t\t\tz = xz / x;\n\n\t\t\t\t}\n\n\t\t\t} else if ( yy > zz ) {\n\n\t\t\t\t// m22 is the largest diagonal term\n\n\t\t\t\tif ( yy < epsilon ) {\n\n\t\t\t\t\tx = 0.707106781;\n\t\t\t\t\ty = 0;\n\t\t\t\t\tz = 0.707106781;\n\n\t\t\t\t} else {\n\n\t\t\t\t\ty = Math.sqrt( yy );\n\t\t\t\t\tx = xy / y;\n\t\t\t\t\tz = yz / y;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// m33 is the largest diagonal term so base result on this\n\n\t\t\t\tif ( zz < epsilon ) {\n\n\t\t\t\t\tx = 0.707106781;\n\t\t\t\t\ty = 0.707106781;\n\t\t\t\t\tz = 0;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tz = Math.sqrt( zz );\n\t\t\t\t\tx = xz / z;\n\t\t\t\t\ty = yz / z;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.set( x, y, z, angle );\n\n\t\t\treturn this; // return 180 deg rotation\n\n\t\t}\n\n\t\t// as we have reached here there are no singularities so we can handle normally\n\n\t\tlet s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +\n\t\t\t( m13 - m31 ) * ( m13 - m31 ) +\n\t\t\t( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize\n\n\t\tif ( Math.abs( s ) < 0.001 ) s = 1;\n\n\t\t// prevent divide by zero, should not happen if matrix is orthogonal and should be\n\t\t// caught by singularity test above, but I've left it in just in case\n\n\t\tthis.x = ( m32 - m23 ) / s;\n\t\tthis.y = ( m13 - m31 ) / s;\n\t\tthis.z = ( m21 - m12 ) / s;\n\t\tthis.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrixPosition( m ) {\n\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 12 ];\n\t\tthis.y = e[ 13 ];\n\t\tthis.z = e[ 14 ];\n\t\tthis.w = e[ 15 ];\n\n\t\treturn this;\n\n\t}\n\n\tmin( v ) {\n\n\t\tthis.x = Math.min( this.x, v.x );\n\t\tthis.y = Math.min( this.y, v.y );\n\t\tthis.z = Math.min( this.z, v.z );\n\t\tthis.w = Math.min( this.w, v.w );\n\n\t\treturn this;\n\n\t}\n\n\tmax( v ) {\n\n\t\tthis.x = Math.max( this.x, v.x );\n\t\tthis.y = Math.max( this.y, v.y );\n\t\tthis.z = Math.max( this.z, v.z );\n\t\tthis.w = Math.max( this.w, v.w );\n\n\t\treturn this;\n\n\t}\n\n\tclamp( min, max ) {\n\n\t\t// assumes min < max, componentwise\n\n\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\t\tthis.z = Math.max( min.z, Math.min( max.z, this.z ) );\n\t\tthis.w = Math.max( min.w, Math.min( max.w, this.w ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampScalar( minVal, maxVal ) {\n\n\t\tthis.x = Math.max( minVal, Math.min( maxVal, this.x ) );\n\t\tthis.y = Math.max( minVal, Math.min( maxVal, this.y ) );\n\t\tthis.z = Math.max( minVal, Math.min( maxVal, this.z ) );\n\t\tthis.w = Math.max( minVal, Math.min( maxVal, this.w ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampLength( min, max ) {\n\n\t\tconst length = this.length();\n\n\t\treturn this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );\n\n\t}\n\n\tfloor() {\n\n\t\tthis.x = Math.floor( this.x );\n\t\tthis.y = Math.floor( this.y );\n\t\tthis.z = Math.floor( this.z );\n\t\tthis.w = Math.floor( this.w );\n\n\t\treturn this;\n\n\t}\n\n\tceil() {\n\n\t\tthis.x = Math.ceil( this.x );\n\t\tthis.y = Math.ceil( this.y );\n\t\tthis.z = Math.ceil( this.z );\n\t\tthis.w = Math.ceil( this.w );\n\n\t\treturn this;\n\n\t}\n\n\tround() {\n\n\t\tthis.x = Math.round( this.x );\n\t\tthis.y = Math.round( this.y );\n\t\tthis.z = Math.round( this.z );\n\t\tthis.w = Math.round( this.w );\n\n\t\treturn this;\n\n\t}\n\n\troundToZero() {\n\n\t\tthis.x = Math.trunc( this.x );\n\t\tthis.y = Math.trunc( this.y );\n\t\tthis.z = Math.trunc( this.z );\n\t\tthis.w = Math.trunc( this.w );\n\n\t\treturn this;\n\n\t}\n\n\tnegate() {\n\n\t\tthis.x = - this.x;\n\t\tthis.y = - this.y;\n\t\tthis.z = - this.z;\n\t\tthis.w = - this.w;\n\n\t\treturn this;\n\n\t}\n\n\tdot( v ) {\n\n\t\treturn this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;\n\n\t}\n\n\tlengthSq() {\n\n\t\treturn this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;\n\n\t}\n\n\tlength() {\n\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );\n\n\t}\n\n\tmanhattanLength() {\n\n\t\treturn Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );\n\n\t}\n\n\tnormalize() {\n\n\t\treturn this.divideScalar( this.length() || 1 );\n\n\t}\n\n\tsetLength( length ) {\n\n\t\treturn this.normalize().multiplyScalar( length );\n\n\t}\n\n\tlerp( v, alpha ) {\n\n\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\tthis.y += ( v.y - this.y ) * alpha;\n\t\tthis.z += ( v.z - this.z ) * alpha;\n\t\tthis.w += ( v.w - this.w ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tlerpVectors( v1, v2, alpha ) {\n\n\t\tthis.x = v1.x + ( v2.x - v1.x ) * alpha;\n\t\tthis.y = v1.y + ( v2.y - v1.y ) * alpha;\n\t\tthis.z = v1.z + ( v2.z - v1.z ) * alpha;\n\t\tthis.w = v1.w + ( v2.w - v1.w ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tequals( v ) {\n\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tthis.x = array[ offset ];\n\t\tthis.y = array[ offset + 1 ];\n\t\tthis.z = array[ offset + 2 ];\n\t\tthis.w = array[ offset + 3 ];\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this.x;\n\t\tarray[ offset + 1 ] = this.y;\n\t\tarray[ offset + 2 ] = this.z;\n\t\tarray[ offset + 3 ] = this.w;\n\n\t\treturn array;\n\n\t}\n\n\tfromBufferAttribute( attribute, index ) {\n\n\t\tthis.x = attribute.getX( index );\n\t\tthis.y = attribute.getY( index );\n\t\tthis.z = attribute.getZ( index );\n\t\tthis.w = attribute.getW( index );\n\n\t\treturn this;\n\n\t}\n\n\trandom() {\n\n\t\tthis.x = Math.random();\n\t\tthis.y = Math.random();\n\t\tthis.z = Math.random();\n\t\tthis.w = Math.random();\n\n\t\treturn this;\n\n\t}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this.x;\n\t\tyield this.y;\n\t\tyield this.z;\n\t\tyield this.w;\n\n\t}\n\n}\n\n/*\n In options, we can specify:\n * Texture parameters for an auto-generated target texture\n * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers\n*/\nclass RenderTarget extends EventDispatcher {\n\n\tconstructor( width = 1, height = 1, options = {} ) {\n\n\t\tsuper();\n\n\t\tthis.isRenderTarget = true;\n\n\t\tthis.width = width;\n\t\tthis.height = height;\n\t\tthis.depth = 1;\n\n\t\tthis.scissor = new Vector4( 0, 0, width, height );\n\t\tthis.scissorTest = false;\n\n\t\tthis.viewport = new Vector4( 0, 0, width, height );\n\n\t\tconst image = { width: width, height: height, depth: 1 };\n\n\t\toptions = Object.assign( {\n\t\t\tgenerateMipmaps: false,\n\t\t\tinternalFormat: null,\n\t\t\tminFilter: LinearFilter,\n\t\t\tdepthBuffer: true,\n\t\t\tstencilBuffer: false,\n\t\t\tresolveDepthBuffer: true,\n\t\t\tresolveStencilBuffer: true,\n\t\t\tdepthTexture: null,\n\t\t\tsamples: 0,\n\t\t\tcount: 1\n\t\t}, options );\n\n\t\tconst texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace );\n\n\t\ttexture.flipY = false;\n\t\ttexture.generateMipmaps = options.generateMipmaps;\n\t\ttexture.internalFormat = options.internalFormat;\n\n\t\tthis.textures = [];\n\n\t\tconst count = options.count;\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tthis.textures[ i ] = texture.clone();\n\t\t\tthis.textures[ i ].isRenderTargetTexture = true;\n\n\t\t}\n\n\t\tthis.depthBuffer = options.depthBuffer;\n\t\tthis.stencilBuffer = options.stencilBuffer;\n\n\t\tthis.resolveDepthBuffer = options.resolveDepthBuffer;\n\t\tthis.resolveStencilBuffer = options.resolveStencilBuffer;\n\n\t\tthis.depthTexture = options.depthTexture;\n\n\t\tthis.samples = options.samples;\n\n\t}\n\n\tget texture() {\n\n\t\treturn this.textures[ 0 ];\n\n\t}\n\n\tset texture( value ) {\n\n\t\tthis.textures[ 0 ] = value;\n\n\t}\n\n\tsetSize( width, height, depth = 1 ) {\n\n\t\tif ( this.width !== width || this.height !== height || this.depth !== depth ) {\n\n\t\t\tthis.width = width;\n\t\t\tthis.height = height;\n\t\t\tthis.depth = depth;\n\n\t\t\tfor ( let i = 0, il = this.textures.length; i < il; i ++ ) {\n\n\t\t\t\tthis.textures[ i ].image.width = width;\n\t\t\t\tthis.textures[ i ].image.height = height;\n\t\t\t\tthis.textures[ i ].image.depth = depth;\n\n\t\t\t}\n\n\t\t\tthis.dispose();\n\n\t\t}\n\n\t\tthis.viewport.set( 0, 0, width, height );\n\t\tthis.scissor.set( 0, 0, width, height );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.width = source.width;\n\t\tthis.height = source.height;\n\t\tthis.depth = source.depth;\n\n\t\tthis.scissor.copy( source.scissor );\n\t\tthis.scissorTest = source.scissorTest;\n\n\t\tthis.viewport.copy( source.viewport );\n\n\t\tthis.textures.length = 0;\n\n\t\tfor ( let i = 0, il = source.textures.length; i < il; i ++ ) {\n\n\t\t\tthis.textures[ i ] = source.textures[ i ].clone();\n\t\t\tthis.textures[ i ].isRenderTargetTexture = true;\n\n\t\t}\n\n\t\t// ensure image object is not shared, see #20328\n\n\t\tconst image = Object.assign( {}, source.texture.image );\n\t\tthis.texture.source = new Source( image );\n\n\t\tthis.depthBuffer = source.depthBuffer;\n\t\tthis.stencilBuffer = source.stencilBuffer;\n\n\t\tthis.resolveDepthBuffer = source.resolveDepthBuffer;\n\t\tthis.resolveStencilBuffer = source.resolveStencilBuffer;\n\n\t\tif ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone();\n\n\t\tthis.samples = source.samples;\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n}\n\nclass WebGLRenderTarget extends RenderTarget {\n\n\tconstructor( width = 1, height = 1, options = {} ) {\n\n\t\tsuper( width, height, options );\n\n\t\tthis.isWebGLRenderTarget = true;\n\n\t}\n\n}\n\nclass DataArrayTexture extends Texture {\n\n\tconstructor( data = null, width = 1, height = 1, depth = 1 ) {\n\n\t\tsuper( null );\n\n\t\tthis.isDataArrayTexture = true;\n\n\t\tthis.image = { data, width, height, depth };\n\n\t\tthis.magFilter = NearestFilter;\n\t\tthis.minFilter = NearestFilter;\n\n\t\tthis.wrapR = ClampToEdgeWrapping;\n\n\t\tthis.generateMipmaps = false;\n\t\tthis.flipY = false;\n\t\tthis.unpackAlignment = 1;\n\n\t\tthis.layerUpdates = new Set();\n\n\t}\n\n\taddLayerUpdate( layerIndex ) {\n\n\t\tthis.layerUpdates.add( layerIndex );\n\n\t}\n\n\tclearLayerUpdates() {\n\n\t\tthis.layerUpdates.clear();\n\n\t}\n\n}\n\nclass WebGLArrayRenderTarget extends WebGLRenderTarget {\n\n\tconstructor( width = 1, height = 1, depth = 1, options = {} ) {\n\n\t\tsuper( width, height, options );\n\n\t\tthis.isWebGLArrayRenderTarget = true;\n\n\t\tthis.depth = depth;\n\n\t\tthis.texture = new DataArrayTexture( null, width, height, depth );\n\n\t\tthis.texture.isRenderTargetTexture = true;\n\n\t}\n\n}\n\nclass Data3DTexture extends Texture {\n\n\tconstructor( data = null, width = 1, height = 1, depth = 1 ) {\n\n\t\t// We're going to add .setXXX() methods for setting properties later.\n\t\t// Users can still set in DataTexture3D directly.\n\t\t//\n\t\t//\tconst texture = new THREE.DataTexture3D( data, width, height, depth );\n\t\t// \ttexture.anisotropy = 16;\n\t\t//\n\t\t// See #14839\n\n\t\tsuper( null );\n\n\t\tthis.isData3DTexture = true;\n\n\t\tthis.image = { data, width, height, depth };\n\n\t\tthis.magFilter = NearestFilter;\n\t\tthis.minFilter = NearestFilter;\n\n\t\tthis.wrapR = ClampToEdgeWrapping;\n\n\t\tthis.generateMipmaps = false;\n\t\tthis.flipY = false;\n\t\tthis.unpackAlignment = 1;\n\n\t}\n\n}\n\nclass WebGL3DRenderTarget extends WebGLRenderTarget {\n\n\tconstructor( width = 1, height = 1, depth = 1, options = {} ) {\n\n\t\tsuper( width, height, options );\n\n\t\tthis.isWebGL3DRenderTarget = true;\n\n\t\tthis.depth = depth;\n\n\t\tthis.texture = new Data3DTexture( null, width, height, depth );\n\n\t\tthis.texture.isRenderTargetTexture = true;\n\n\t}\n\n}\n\nclass Quaternion {\n\n\tconstructor( x = 0, y = 0, z = 0, w = 1 ) {\n\n\t\tthis.isQuaternion = true;\n\n\t\tthis._x = x;\n\t\tthis._y = y;\n\t\tthis._z = z;\n\t\tthis._w = w;\n\n\t}\n\n\tstatic slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {\n\n\t\t// fuzz-free, array-based Quaternion SLERP operation\n\n\t\tlet x0 = src0[ srcOffset0 + 0 ],\n\t\t\ty0 = src0[ srcOffset0 + 1 ],\n\t\t\tz0 = src0[ srcOffset0 + 2 ],\n\t\t\tw0 = src0[ srcOffset0 + 3 ];\n\n\t\tconst x1 = src1[ srcOffset1 + 0 ],\n\t\t\ty1 = src1[ srcOffset1 + 1 ],\n\t\t\tz1 = src1[ srcOffset1 + 2 ],\n\t\t\tw1 = src1[ srcOffset1 + 3 ];\n\n\t\tif ( t === 0 ) {\n\n\t\t\tdst[ dstOffset + 0 ] = x0;\n\t\t\tdst[ dstOffset + 1 ] = y0;\n\t\t\tdst[ dstOffset + 2 ] = z0;\n\t\t\tdst[ dstOffset + 3 ] = w0;\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( t === 1 ) {\n\n\t\t\tdst[ dstOffset + 0 ] = x1;\n\t\t\tdst[ dstOffset + 1 ] = y1;\n\t\t\tdst[ dstOffset + 2 ] = z1;\n\t\t\tdst[ dstOffset + 3 ] = w1;\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {\n\n\t\t\tlet s = 1 - t;\n\t\t\tconst cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,\n\t\t\t\tdir = ( cos >= 0 ? 1 : - 1 ),\n\t\t\t\tsqrSin = 1 - cos * cos;\n\n\t\t\t// Skip the Slerp for tiny steps to avoid numeric problems:\n\t\t\tif ( sqrSin > Number.EPSILON ) {\n\n\t\t\t\tconst sin = Math.sqrt( sqrSin ),\n\t\t\t\t\tlen = Math.atan2( sin, cos * dir );\n\n\t\t\t\ts = Math.sin( s * len ) / sin;\n\t\t\t\tt = Math.sin( t * len ) / sin;\n\n\t\t\t}\n\n\t\t\tconst tDir = t * dir;\n\n\t\t\tx0 = x0 * s + x1 * tDir;\n\t\t\ty0 = y0 * s + y1 * tDir;\n\t\t\tz0 = z0 * s + z1 * tDir;\n\t\t\tw0 = w0 * s + w1 * tDir;\n\n\t\t\t// Normalize in case we just did a lerp:\n\t\t\tif ( s === 1 - t ) {\n\n\t\t\t\tconst f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );\n\n\t\t\t\tx0 *= f;\n\t\t\t\ty0 *= f;\n\t\t\t\tz0 *= f;\n\t\t\t\tw0 *= f;\n\n\t\t\t}\n\n\t\t}\n\n\t\tdst[ dstOffset ] = x0;\n\t\tdst[ dstOffset + 1 ] = y0;\n\t\tdst[ dstOffset + 2 ] = z0;\n\t\tdst[ dstOffset + 3 ] = w0;\n\n\t}\n\n\tstatic multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) {\n\n\t\tconst x0 = src0[ srcOffset0 ];\n\t\tconst y0 = src0[ srcOffset0 + 1 ];\n\t\tconst z0 = src0[ srcOffset0 + 2 ];\n\t\tconst w0 = src0[ srcOffset0 + 3 ];\n\n\t\tconst x1 = src1[ srcOffset1 ];\n\t\tconst y1 = src1[ srcOffset1 + 1 ];\n\t\tconst z1 = src1[ srcOffset1 + 2 ];\n\t\tconst w1 = src1[ srcOffset1 + 3 ];\n\n\t\tdst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;\n\t\tdst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;\n\t\tdst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;\n\t\tdst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;\n\n\t\treturn dst;\n\n\t}\n\n\tget x() {\n\n\t\treturn this._x;\n\n\t}\n\n\tset x( value ) {\n\n\t\tthis._x = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget y() {\n\n\t\treturn this._y;\n\n\t}\n\n\tset y( value ) {\n\n\t\tthis._y = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget z() {\n\n\t\treturn this._z;\n\n\t}\n\n\tset z( value ) {\n\n\t\tthis._z = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget w() {\n\n\t\treturn this._w;\n\n\t}\n\n\tset w( value ) {\n\n\t\tthis._w = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tset( x, y, z, w ) {\n\n\t\tthis._x = x;\n\t\tthis._y = y;\n\t\tthis._z = z;\n\t\tthis._w = w;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this._x, this._y, this._z, this._w );\n\n\t}\n\n\tcopy( quaternion ) {\n\n\t\tthis._x = quaternion.x;\n\t\tthis._y = quaternion.y;\n\t\tthis._z = quaternion.z;\n\t\tthis._w = quaternion.w;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromEuler( euler, update = true ) {\n\n\t\tconst x = euler._x, y = euler._y, z = euler._z, order = euler._order;\n\n\t\t// http://www.mathworks.com/matlabcentral/fileexchange/\n\t\t// \t20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/\n\t\t//\tcontent/SpinCalc.m\n\n\t\tconst cos = Math.cos;\n\t\tconst sin = Math.sin;\n\n\t\tconst c1 = cos( x / 2 );\n\t\tconst c2 = cos( y / 2 );\n\t\tconst c3 = cos( z / 2 );\n\n\t\tconst s1 = sin( x / 2 );\n\t\tconst s2 = sin( y / 2 );\n\t\tconst s3 = sin( z / 2 );\n\n\t\tswitch ( order ) {\n\n\t\t\tcase 'XYZ':\n\t\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tcase 'YXZ':\n\t\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tcase 'ZXY':\n\t\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tcase 'ZYX':\n\t\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tcase 'YZX':\n\t\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tcase 'XZY':\n\t\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tconsole.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order );\n\n\t\t}\n\n\t\tif ( update === true ) this._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromAxisAngle( axis, angle ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm\n\n\t\t// assumes axis is normalized\n\n\t\tconst halfAngle = angle / 2, s = Math.sin( halfAngle );\n\n\t\tthis._x = axis.x * s;\n\t\tthis._y = axis.y * s;\n\t\tthis._z = axis.z * s;\n\t\tthis._w = Math.cos( halfAngle );\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromRotationMatrix( m ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tconst te = m.elements,\n\n\t\t\tm11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],\n\t\t\tm21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],\n\t\t\tm31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],\n\n\t\t\ttrace = m11 + m22 + m33;\n\n\t\tif ( trace > 0 ) {\n\n\t\t\tconst s = 0.5 / Math.sqrt( trace + 1.0 );\n\n\t\t\tthis._w = 0.25 / s;\n\t\t\tthis._x = ( m32 - m23 ) * s;\n\t\t\tthis._y = ( m13 - m31 ) * s;\n\t\t\tthis._z = ( m21 - m12 ) * s;\n\n\t\t} else if ( m11 > m22 && m11 > m33 ) {\n\n\t\t\tconst s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );\n\n\t\t\tthis._w = ( m32 - m23 ) / s;\n\t\t\tthis._x = 0.25 * s;\n\t\t\tthis._y = ( m12 + m21 ) / s;\n\t\t\tthis._z = ( m13 + m31 ) / s;\n\n\t\t} else if ( m22 > m33 ) {\n\n\t\t\tconst s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );\n\n\t\t\tthis._w = ( m13 - m31 ) / s;\n\t\t\tthis._x = ( m12 + m21 ) / s;\n\t\t\tthis._y = 0.25 * s;\n\t\t\tthis._z = ( m23 + m32 ) / s;\n\n\t\t} else {\n\n\t\t\tconst s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );\n\n\t\t\tthis._w = ( m21 - m12 ) / s;\n\t\t\tthis._x = ( m13 + m31 ) / s;\n\t\t\tthis._y = ( m23 + m32 ) / s;\n\t\t\tthis._z = 0.25 * s;\n\n\t\t}\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromUnitVectors( vFrom, vTo ) {\n\n\t\t// assumes direction vectors vFrom and vTo are normalized\n\n\t\tlet r = vFrom.dot( vTo ) + 1;\n\n\t\tif ( r < Number.EPSILON ) {\n\n\t\t\t// vFrom and vTo point in opposite directions\n\n\t\t\tr = 0;\n\n\t\t\tif ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {\n\n\t\t\t\tthis._x = - vFrom.y;\n\t\t\t\tthis._y = vFrom.x;\n\t\t\t\tthis._z = 0;\n\t\t\t\tthis._w = r;\n\n\t\t\t} else {\n\n\t\t\t\tthis._x = 0;\n\t\t\t\tthis._y = - vFrom.z;\n\t\t\t\tthis._z = vFrom.y;\n\t\t\t\tthis._w = r;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3\n\n\t\t\tthis._x = vFrom.y * vTo.z - vFrom.z * vTo.y;\n\t\t\tthis._y = vFrom.z * vTo.x - vFrom.x * vTo.z;\n\t\t\tthis._z = vFrom.x * vTo.y - vFrom.y * vTo.x;\n\t\t\tthis._w = r;\n\n\t\t}\n\n\t\treturn this.normalize();\n\n\t}\n\n\tangleTo( q ) {\n\n\t\treturn 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) );\n\n\t}\n\n\trotateTowards( q, step ) {\n\n\t\tconst angle = this.angleTo( q );\n\n\t\tif ( angle === 0 ) return this;\n\n\t\tconst t = Math.min( 1, step / angle );\n\n\t\tthis.slerp( q, t );\n\n\t\treturn this;\n\n\t}\n\n\tidentity() {\n\n\t\treturn this.set( 0, 0, 0, 1 );\n\n\t}\n\n\tinvert() {\n\n\t\t// quaternion is assumed to have unit length\n\n\t\treturn this.conjugate();\n\n\t}\n\n\tconjugate() {\n\n\t\tthis._x *= - 1;\n\t\tthis._y *= - 1;\n\t\tthis._z *= - 1;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tdot( v ) {\n\n\t\treturn this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;\n\n\t}\n\n\tlengthSq() {\n\n\t\treturn this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;\n\n\t}\n\n\tlength() {\n\n\t\treturn Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );\n\n\t}\n\n\tnormalize() {\n\n\t\tlet l = this.length();\n\n\t\tif ( l === 0 ) {\n\n\t\t\tthis._x = 0;\n\t\t\tthis._y = 0;\n\t\t\tthis._z = 0;\n\t\t\tthis._w = 1;\n\n\t\t} else {\n\n\t\t\tl = 1 / l;\n\n\t\t\tthis._x = this._x * l;\n\t\t\tthis._y = this._y * l;\n\t\t\tthis._z = this._z * l;\n\t\t\tthis._w = this._w * l;\n\n\t\t}\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( q ) {\n\n\t\treturn this.multiplyQuaternions( this, q );\n\n\t}\n\n\tpremultiply( q ) {\n\n\t\treturn this.multiplyQuaternions( q, this );\n\n\t}\n\n\tmultiplyQuaternions( a, b ) {\n\n\t\t// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm\n\n\t\tconst qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;\n\t\tconst qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;\n\n\t\tthis._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;\n\t\tthis._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;\n\t\tthis._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;\n\t\tthis._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tslerp( qb, t ) {\n\n\t\tif ( t === 0 ) return this;\n\t\tif ( t === 1 ) return this.copy( qb );\n\n\t\tconst x = this._x, y = this._y, z = this._z, w = this._w;\n\n\t\t// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/\n\n\t\tlet cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;\n\n\t\tif ( cosHalfTheta < 0 ) {\n\n\t\t\tthis._w = - qb._w;\n\t\t\tthis._x = - qb._x;\n\t\t\tthis._y = - qb._y;\n\t\t\tthis._z = - qb._z;\n\n\t\t\tcosHalfTheta = - cosHalfTheta;\n\n\t\t} else {\n\n\t\t\tthis.copy( qb );\n\n\t\t}\n\n\t\tif ( cosHalfTheta >= 1.0 ) {\n\n\t\t\tthis._w = w;\n\t\t\tthis._x = x;\n\t\t\tthis._y = y;\n\t\t\tthis._z = z;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tconst sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;\n\n\t\tif ( sqrSinHalfTheta <= Number.EPSILON ) {\n\n\t\t\tconst s = 1 - t;\n\t\t\tthis._w = s * w + t * this._w;\n\t\t\tthis._x = s * x + t * this._x;\n\t\t\tthis._y = s * y + t * this._y;\n\t\t\tthis._z = s * z + t * this._z;\n\n\t\t\tthis.normalize(); // normalize calls _onChangeCallback()\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tconst sinHalfTheta = Math.sqrt( sqrSinHalfTheta );\n\t\tconst halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );\n\t\tconst ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,\n\t\t\tratioB = Math.sin( t * halfTheta ) / sinHalfTheta;\n\n\t\tthis._w = ( w * ratioA + this._w * ratioB );\n\t\tthis._x = ( x * ratioA + this._x * ratioB );\n\t\tthis._y = ( y * ratioA + this._y * ratioB );\n\t\tthis._z = ( z * ratioA + this._z * ratioB );\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tslerpQuaternions( qa, qb, t ) {\n\n\t\treturn this.copy( qa ).slerp( qb, t );\n\n\t}\n\n\trandom() {\n\n\t\t// sets this quaternion to a uniform random unit quaternnion\n\n\t\t// Ken Shoemake\n\t\t// Uniform random rotations\n\t\t// D. Kirk, editor, Graphics Gems III, pages 124-132. Academic Press, New York, 1992.\n\n\t\tconst theta1 = 2 * Math.PI * Math.random();\n\t\tconst theta2 = 2 * Math.PI * Math.random();\n\n\t\tconst x0 = Math.random();\n\t\tconst r1 = Math.sqrt( 1 - x0 );\n\t\tconst r2 = Math.sqrt( x0 );\n\n\t\treturn this.set(\n\t\t\tr1 * Math.sin( theta1 ),\n\t\t\tr1 * Math.cos( theta1 ),\n\t\t\tr2 * Math.sin( theta2 ),\n\t\t\tr2 * Math.cos( theta2 ),\n\t\t);\n\n\t}\n\n\tequals( quaternion ) {\n\n\t\treturn ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tthis._x = array[ offset ];\n\t\tthis._y = array[ offset + 1 ];\n\t\tthis._z = array[ offset + 2 ];\n\t\tthis._w = array[ offset + 3 ];\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this._x;\n\t\tarray[ offset + 1 ] = this._y;\n\t\tarray[ offset + 2 ] = this._z;\n\t\tarray[ offset + 3 ] = this._w;\n\n\t\treturn array;\n\n\t}\n\n\tfromBufferAttribute( attribute, index ) {\n\n\t\tthis._x = attribute.getX( index );\n\t\tthis._y = attribute.getY( index );\n\t\tthis._z = attribute.getZ( index );\n\t\tthis._w = attribute.getW( index );\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\treturn this.toArray();\n\n\t}\n\n\t_onChange( callback ) {\n\n\t\tthis._onChangeCallback = callback;\n\n\t\treturn this;\n\n\t}\n\n\t_onChangeCallback() {}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this._x;\n\t\tyield this._y;\n\t\tyield this._z;\n\t\tyield this._w;\n\n\t}\n\n}\n\nclass Vector3 {\n\n\tconstructor( x = 0, y = 0, z = 0 ) {\n\n\t\tVector3.prototype.isVector3 = true;\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.z = z;\n\n\t}\n\n\tset( x, y, z ) {\n\n\t\tif ( z === undefined ) z = this.z; // sprite.scale.set(x,y)\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.z = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetScalar( scalar ) {\n\n\t\tthis.x = scalar;\n\t\tthis.y = scalar;\n\t\tthis.z = scalar;\n\n\t\treturn this;\n\n\t}\n\n\tsetX( x ) {\n\n\t\tthis.x = x;\n\n\t\treturn this;\n\n\t}\n\n\tsetY( y ) {\n\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetZ( z ) {\n\n\t\tthis.z = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetComponent( index, value ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: this.x = value; break;\n\t\t\tcase 1: this.y = value; break;\n\t\t\tcase 2: this.z = value; break;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetComponent( index ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: return this.x;\n\t\t\tcase 1: return this.y;\n\t\t\tcase 2: return this.z;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.x, this.y, this.z );\n\n\t}\n\n\tcopy( v ) {\n\n\t\tthis.x = v.x;\n\t\tthis.y = v.y;\n\t\tthis.z = v.z;\n\n\t\treturn this;\n\n\t}\n\n\tadd( v ) {\n\n\t\tthis.x += v.x;\n\t\tthis.y += v.y;\n\t\tthis.z += v.z;\n\n\t\treturn this;\n\n\t}\n\n\taddScalar( s ) {\n\n\t\tthis.x += s;\n\t\tthis.y += s;\n\t\tthis.z += s;\n\n\t\treturn this;\n\n\t}\n\n\taddVectors( a, b ) {\n\n\t\tthis.x = a.x + b.x;\n\t\tthis.y = a.y + b.y;\n\t\tthis.z = a.z + b.z;\n\n\t\treturn this;\n\n\t}\n\n\taddScaledVector( v, s ) {\n\n\t\tthis.x += v.x * s;\n\t\tthis.y += v.y * s;\n\t\tthis.z += v.z * s;\n\n\t\treturn this;\n\n\t}\n\n\tsub( v ) {\n\n\t\tthis.x -= v.x;\n\t\tthis.y -= v.y;\n\t\tthis.z -= v.z;\n\n\t\treturn this;\n\n\t}\n\n\tsubScalar( s ) {\n\n\t\tthis.x -= s;\n\t\tthis.y -= s;\n\t\tthis.z -= s;\n\n\t\treturn this;\n\n\t}\n\n\tsubVectors( a, b ) {\n\n\t\tthis.x = a.x - b.x;\n\t\tthis.y = a.y - b.y;\n\t\tthis.z = a.z - b.z;\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( v ) {\n\n\t\tthis.x *= v.x;\n\t\tthis.y *= v.y;\n\t\tthis.z *= v.z;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( scalar ) {\n\n\t\tthis.x *= scalar;\n\t\tthis.y *= scalar;\n\t\tthis.z *= scalar;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyVectors( a, b ) {\n\n\t\tthis.x = a.x * b.x;\n\t\tthis.y = a.y * b.y;\n\t\tthis.z = a.z * b.z;\n\n\t\treturn this;\n\n\t}\n\n\tapplyEuler( euler ) {\n\n\t\treturn this.applyQuaternion( _quaternion$4.setFromEuler( euler ) );\n\n\t}\n\n\tapplyAxisAngle( axis, angle ) {\n\n\t\treturn this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) );\n\n\t}\n\n\tapplyMatrix3( m ) {\n\n\t\tconst x = this.x, y = this.y, z = this.z;\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;\n\t\tthis.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;\n\t\tthis.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;\n\n\t\treturn this;\n\n\t}\n\n\tapplyNormalMatrix( m ) {\n\n\t\treturn this.applyMatrix3( m ).normalize();\n\n\t}\n\n\tapplyMatrix4( m ) {\n\n\t\tconst x = this.x, y = this.y, z = this.z;\n\t\tconst e = m.elements;\n\n\t\tconst w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );\n\n\t\tthis.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;\n\t\tthis.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;\n\t\tthis.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;\n\n\t\treturn this;\n\n\t}\n\n\tapplyQuaternion( q ) {\n\n\t\t// quaternion q is assumed to have unit length\n\n\t\tconst vx = this.x, vy = this.y, vz = this.z;\n\t\tconst qx = q.x, qy = q.y, qz = q.z, qw = q.w;\n\n\t\t// t = 2 * cross( q.xyz, v );\n\t\tconst tx = 2 * ( qy * vz - qz * vy );\n\t\tconst ty = 2 * ( qz * vx - qx * vz );\n\t\tconst tz = 2 * ( qx * vy - qy * vx );\n\n\t\t// v + q.w * t + cross( q.xyz, t );\n\t\tthis.x = vx + qw * tx + qy * tz - qz * ty;\n\t\tthis.y = vy + qw * ty + qz * tx - qx * tz;\n\t\tthis.z = vz + qw * tz + qx * ty - qy * tx;\n\n\t\treturn this;\n\n\t}\n\n\tproject( camera ) {\n\n\t\treturn this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );\n\n\t}\n\n\tunproject( camera ) {\n\n\t\treturn this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld );\n\n\t}\n\n\ttransformDirection( m ) {\n\n\t\t// input: THREE.Matrix4 affine matrix\n\t\t// vector interpreted as a direction\n\n\t\tconst x = this.x, y = this.y, z = this.z;\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;\n\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;\n\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;\n\n\t\treturn this.normalize();\n\n\t}\n\n\tdivide( v ) {\n\n\t\tthis.x /= v.x;\n\t\tthis.y /= v.y;\n\t\tthis.z /= v.z;\n\n\t\treturn this;\n\n\t}\n\n\tdivideScalar( scalar ) {\n\n\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t}\n\n\tmin( v ) {\n\n\t\tthis.x = Math.min( this.x, v.x );\n\t\tthis.y = Math.min( this.y, v.y );\n\t\tthis.z = Math.min( this.z, v.z );\n\n\t\treturn this;\n\n\t}\n\n\tmax( v ) {\n\n\t\tthis.x = Math.max( this.x, v.x );\n\t\tthis.y = Math.max( this.y, v.y );\n\t\tthis.z = Math.max( this.z, v.z );\n\n\t\treturn this;\n\n\t}\n\n\tclamp( min, max ) {\n\n\t\t// assumes min < max, componentwise\n\n\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\t\tthis.z = Math.max( min.z, Math.min( max.z, this.z ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampScalar( minVal, maxVal ) {\n\n\t\tthis.x = Math.max( minVal, Math.min( maxVal, this.x ) );\n\t\tthis.y = Math.max( minVal, Math.min( maxVal, this.y ) );\n\t\tthis.z = Math.max( minVal, Math.min( maxVal, this.z ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampLength( min, max ) {\n\n\t\tconst length = this.length();\n\n\t\treturn this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );\n\n\t}\n\n\tfloor() {\n\n\t\tthis.x = Math.floor( this.x );\n\t\tthis.y = Math.floor( this.y );\n\t\tthis.z = Math.floor( this.z );\n\n\t\treturn this;\n\n\t}\n\n\tceil() {\n\n\t\tthis.x = Math.ceil( this.x );\n\t\tthis.y = Math.ceil( this.y );\n\t\tthis.z = Math.ceil( this.z );\n\n\t\treturn this;\n\n\t}\n\n\tround() {\n\n\t\tthis.x = Math.round( this.x );\n\t\tthis.y = Math.round( this.y );\n\t\tthis.z = Math.round( this.z );\n\n\t\treturn this;\n\n\t}\n\n\troundToZero() {\n\n\t\tthis.x = Math.trunc( this.x );\n\t\tthis.y = Math.trunc( this.y );\n\t\tthis.z = Math.trunc( this.z );\n\n\t\treturn this;\n\n\t}\n\n\tnegate() {\n\n\t\tthis.x = - this.x;\n\t\tthis.y = - this.y;\n\t\tthis.z = - this.z;\n\n\t\treturn this;\n\n\t}\n\n\tdot( v ) {\n\n\t\treturn this.x * v.x + this.y * v.y + this.z * v.z;\n\n\t}\n\n\t// TODO lengthSquared?\n\n\tlengthSq() {\n\n\t\treturn this.x * this.x + this.y * this.y + this.z * this.z;\n\n\t}\n\n\tlength() {\n\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );\n\n\t}\n\n\tmanhattanLength() {\n\n\t\treturn Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );\n\n\t}\n\n\tnormalize() {\n\n\t\treturn this.divideScalar( this.length() || 1 );\n\n\t}\n\n\tsetLength( length ) {\n\n\t\treturn this.normalize().multiplyScalar( length );\n\n\t}\n\n\tlerp( v, alpha ) {\n\n\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\tthis.y += ( v.y - this.y ) * alpha;\n\t\tthis.z += ( v.z - this.z ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tlerpVectors( v1, v2, alpha ) {\n\n\t\tthis.x = v1.x + ( v2.x - v1.x ) * alpha;\n\t\tthis.y = v1.y + ( v2.y - v1.y ) * alpha;\n\t\tthis.z = v1.z + ( v2.z - v1.z ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tcross( v ) {\n\n\t\treturn this.crossVectors( this, v );\n\n\t}\n\n\tcrossVectors( a, b ) {\n\n\t\tconst ax = a.x, ay = a.y, az = a.z;\n\t\tconst bx = b.x, by = b.y, bz = b.z;\n\n\t\tthis.x = ay * bz - az * by;\n\t\tthis.y = az * bx - ax * bz;\n\t\tthis.z = ax * by - ay * bx;\n\n\t\treturn this;\n\n\t}\n\n\tprojectOnVector( v ) {\n\n\t\tconst denominator = v.lengthSq();\n\n\t\tif ( denominator === 0 ) return this.set( 0, 0, 0 );\n\n\t\tconst scalar = v.dot( this ) / denominator;\n\n\t\treturn this.copy( v ).multiplyScalar( scalar );\n\n\t}\n\n\tprojectOnPlane( planeNormal ) {\n\n\t\t_vector$c.copy( this ).projectOnVector( planeNormal );\n\n\t\treturn this.sub( _vector$c );\n\n\t}\n\n\treflect( normal ) {\n\n\t\t// reflect incident vector off plane orthogonal to normal\n\t\t// normal is assumed to have unit length\n\n\t\treturn this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );\n\n\t}\n\n\tangleTo( v ) {\n\n\t\tconst denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );\n\n\t\tif ( denominator === 0 ) return Math.PI / 2;\n\n\t\tconst theta = this.dot( v ) / denominator;\n\n\t\t// clamp, to handle numerical problems\n\n\t\treturn Math.acos( clamp( theta, - 1, 1 ) );\n\n\t}\n\n\tdistanceTo( v ) {\n\n\t\treturn Math.sqrt( this.distanceToSquared( v ) );\n\n\t}\n\n\tdistanceToSquared( v ) {\n\n\t\tconst dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;\n\n\t\treturn dx * dx + dy * dy + dz * dz;\n\n\t}\n\n\tmanhattanDistanceTo( v ) {\n\n\t\treturn Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );\n\n\t}\n\n\tsetFromSpherical( s ) {\n\n\t\treturn this.setFromSphericalCoords( s.radius, s.phi, s.theta );\n\n\t}\n\n\tsetFromSphericalCoords( radius, phi, theta ) {\n\n\t\tconst sinPhiRadius = Math.sin( phi ) * radius;\n\n\t\tthis.x = sinPhiRadius * Math.sin( theta );\n\t\tthis.y = Math.cos( phi ) * radius;\n\t\tthis.z = sinPhiRadius * Math.cos( theta );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromCylindrical( c ) {\n\n\t\treturn this.setFromCylindricalCoords( c.radius, c.theta, c.y );\n\n\t}\n\n\tsetFromCylindricalCoords( radius, theta, y ) {\n\n\t\tthis.x = radius * Math.sin( theta );\n\t\tthis.y = y;\n\t\tthis.z = radius * Math.cos( theta );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrixPosition( m ) {\n\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 12 ];\n\t\tthis.y = e[ 13 ];\n\t\tthis.z = e[ 14 ];\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrixScale( m ) {\n\n\t\tconst sx = this.setFromMatrixColumn( m, 0 ).length();\n\t\tconst sy = this.setFromMatrixColumn( m, 1 ).length();\n\t\tconst sz = this.setFromMatrixColumn( m, 2 ).length();\n\n\t\tthis.x = sx;\n\t\tthis.y = sy;\n\t\tthis.z = sz;\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrixColumn( m, index ) {\n\n\t\treturn this.fromArray( m.elements, index * 4 );\n\n\t}\n\n\tsetFromMatrix3Column( m, index ) {\n\n\t\treturn this.fromArray( m.elements, index * 3 );\n\n\t}\n\n\tsetFromEuler( e ) {\n\n\t\tthis.x = e._x;\n\t\tthis.y = e._y;\n\t\tthis.z = e._z;\n\n\t\treturn this;\n\n\t}\n\n\tsetFromColor( c ) {\n\n\t\tthis.x = c.r;\n\t\tthis.y = c.g;\n\t\tthis.z = c.b;\n\n\t\treturn this;\n\n\t}\n\n\tequals( v ) {\n\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tthis.x = array[ offset ];\n\t\tthis.y = array[ offset + 1 ];\n\t\tthis.z = array[ offset + 2 ];\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this.x;\n\t\tarray[ offset + 1 ] = this.y;\n\t\tarray[ offset + 2 ] = this.z;\n\n\t\treturn array;\n\n\t}\n\n\tfromBufferAttribute( attribute, index ) {\n\n\t\tthis.x = attribute.getX( index );\n\t\tthis.y = attribute.getY( index );\n\t\tthis.z = attribute.getZ( index );\n\n\t\treturn this;\n\n\t}\n\n\trandom() {\n\n\t\tthis.x = Math.random();\n\t\tthis.y = Math.random();\n\t\tthis.z = Math.random();\n\n\t\treturn this;\n\n\t}\n\n\trandomDirection() {\n\n\t\t// https://mathworld.wolfram.com/SpherePointPicking.html\n\n\t\tconst theta = Math.random() * Math.PI * 2;\n\t\tconst u = Math.random() * 2 - 1;\n\t\tconst c = Math.sqrt( 1 - u * u );\n\n\t\tthis.x = c * Math.cos( theta );\n\t\tthis.y = u;\n\t\tthis.z = c * Math.sin( theta );\n\n\t\treturn this;\n\n\t}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this.x;\n\t\tyield this.y;\n\t\tyield this.z;\n\n\t}\n\n}\n\nconst _vector$c = /*@__PURE__*/ new Vector3();\nconst _quaternion$4 = /*@__PURE__*/ new Quaternion();\n\nclass Box3 {\n\n\tconstructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) {\n\n\t\tthis.isBox3 = true;\n\n\t\tthis.min = min;\n\t\tthis.max = max;\n\n\t}\n\n\tset( min, max ) {\n\n\t\tthis.min.copy( min );\n\t\tthis.max.copy( max );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromArray( array ) {\n\n\t\tthis.makeEmpty();\n\n\t\tfor ( let i = 0, il = array.length; i < il; i += 3 ) {\n\n\t\t\tthis.expandByPoint( _vector$b.fromArray( array, i ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetFromBufferAttribute( attribute ) {\n\n\t\tthis.makeEmpty();\n\n\t\tfor ( let i = 0, il = attribute.count; i < il; i ++ ) {\n\n\t\t\tthis.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetFromPoints( points ) {\n\n\t\tthis.makeEmpty();\n\n\t\tfor ( let i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\tthis.expandByPoint( points[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetFromCenterAndSize( center, size ) {\n\n\t\tconst halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 );\n\n\t\tthis.min.copy( center ).sub( halfSize );\n\t\tthis.max.copy( center ).add( halfSize );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromObject( object, precise = false ) {\n\n\t\tthis.makeEmpty();\n\n\t\treturn this.expandByObject( object, precise );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( box ) {\n\n\t\tthis.min.copy( box.min );\n\t\tthis.max.copy( box.max );\n\n\t\treturn this;\n\n\t}\n\n\tmakeEmpty() {\n\n\t\tthis.min.x = this.min.y = this.min.z = + Infinity;\n\t\tthis.max.x = this.max.y = this.max.z = - Infinity;\n\n\t\treturn this;\n\n\t}\n\n\tisEmpty() {\n\n\t\t// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes\n\n\t\treturn ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );\n\n\t}\n\n\tgetCenter( target ) {\n\n\t\treturn this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );\n\n\t}\n\n\tgetSize( target ) {\n\n\t\treturn this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );\n\n\t}\n\n\texpandByPoint( point ) {\n\n\t\tthis.min.min( point );\n\t\tthis.max.max( point );\n\n\t\treturn this;\n\n\t}\n\n\texpandByVector( vector ) {\n\n\t\tthis.min.sub( vector );\n\t\tthis.max.add( vector );\n\n\t\treturn this;\n\n\t}\n\n\texpandByScalar( scalar ) {\n\n\t\tthis.min.addScalar( - scalar );\n\t\tthis.max.addScalar( scalar );\n\n\t\treturn this;\n\n\t}\n\n\texpandByObject( object, precise = false ) {\n\n\t\t// Computes the world-axis-aligned bounding box of an object (including its children),\n\t\t// accounting for both the object's, and children's, world transforms\n\n\t\tobject.updateWorldMatrix( false, false );\n\n\t\tconst geometry = object.geometry;\n\n\t\tif ( geometry !== undefined ) {\n\n\t\t\tconst positionAttribute = geometry.getAttribute( 'position' );\n\n\t\t\t// precise AABB computation based on vertex data requires at least a position attribute.\n\t\t\t// instancing isn't supported so far and uses the normal (conservative) code path.\n\n\t\t\tif ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) {\n\n\t\t\t\tfor ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {\n\n\t\t\t\t\tif ( object.isMesh === true ) {\n\n\t\t\t\t\t\tobject.getVertexPosition( i, _vector$b );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t_vector$b.fromBufferAttribute( positionAttribute, i );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t_vector$b.applyMatrix4( object.matrixWorld );\n\t\t\t\t\tthis.expandByPoint( _vector$b );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( object.boundingBox !== undefined ) {\n\n\t\t\t\t\t// object-level bounding box\n\n\t\t\t\t\tif ( object.boundingBox === null ) {\n\n\t\t\t\t\t\tobject.computeBoundingBox();\n\n\t\t\t\t\t}\n\n\t\t\t\t\t_box$4.copy( object.boundingBox );\n\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// geometry-level bounding box\n\n\t\t\t\t\tif ( geometry.boundingBox === null ) {\n\n\t\t\t\t\t\tgeometry.computeBoundingBox();\n\n\t\t\t\t\t}\n\n\t\t\t\t\t_box$4.copy( geometry.boundingBox );\n\n\t\t\t\t}\n\n\t\t\t\t_box$4.applyMatrix4( object.matrixWorld );\n\n\t\t\t\tthis.union( _box$4 );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst children = object.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tthis.expandByObject( children[ i ], precise );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tcontainsPoint( point ) {\n\n\t\treturn point.x < this.min.x || point.x > this.max.x ||\n\t\t\tpoint.y < this.min.y || point.y > this.max.y ||\n\t\t\tpoint.z < this.min.z || point.z > this.max.z ? false : true;\n\n\t}\n\n\tcontainsBox( box ) {\n\n\t\treturn this.min.x <= box.min.x && box.max.x <= this.max.x &&\n\t\t\tthis.min.y <= box.min.y && box.max.y <= this.max.y &&\n\t\t\tthis.min.z <= box.min.z && box.max.z <= this.max.z;\n\n\t}\n\n\tgetParameter( point, target ) {\n\n\t\t// This can potentially have a divide by zero if the box\n\t\t// has a size dimension of 0.\n\n\t\treturn target.set(\n\t\t\t( point.x - this.min.x ) / ( this.max.x - this.min.x ),\n\t\t\t( point.y - this.min.y ) / ( this.max.y - this.min.y ),\n\t\t\t( point.z - this.min.z ) / ( this.max.z - this.min.z )\n\t\t);\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\t// using 6 splitting planes to rule out intersections.\n\t\treturn box.max.x < this.min.x || box.min.x > this.max.x ||\n\t\t\tbox.max.y < this.min.y || box.min.y > this.max.y ||\n\t\t\tbox.max.z < this.min.z || box.min.z > this.max.z ? false : true;\n\n\t}\n\n\tintersectsSphere( sphere ) {\n\n\t\t// Find the point on the AABB closest to the sphere center.\n\t\tthis.clampPoint( sphere.center, _vector$b );\n\n\t\t// If that point is inside the sphere, the AABB and sphere intersect.\n\t\treturn _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );\n\n\t}\n\n\tintersectsPlane( plane ) {\n\n\t\t// We compute the minimum and maximum dot product values. If those values\n\t\t// are on the same side (back or front) of the plane, then there is no intersection.\n\n\t\tlet min, max;\n\n\t\tif ( plane.normal.x > 0 ) {\n\n\t\t\tmin = plane.normal.x * this.min.x;\n\t\t\tmax = plane.normal.x * this.max.x;\n\n\t\t} else {\n\n\t\t\tmin = plane.normal.x * this.max.x;\n\t\t\tmax = plane.normal.x * this.min.x;\n\n\t\t}\n\n\t\tif ( plane.normal.y > 0 ) {\n\n\t\t\tmin += plane.normal.y * this.min.y;\n\t\t\tmax += plane.normal.y * this.max.y;\n\n\t\t} else {\n\n\t\t\tmin += plane.normal.y * this.max.y;\n\t\t\tmax += plane.normal.y * this.min.y;\n\n\t\t}\n\n\t\tif ( plane.normal.z > 0 ) {\n\n\t\t\tmin += plane.normal.z * this.min.z;\n\t\t\tmax += plane.normal.z * this.max.z;\n\n\t\t} else {\n\n\t\t\tmin += plane.normal.z * this.max.z;\n\t\t\tmax += plane.normal.z * this.min.z;\n\n\t\t}\n\n\t\treturn ( min <= - plane.constant && max >= - plane.constant );\n\n\t}\n\n\tintersectsTriangle( triangle ) {\n\n\t\tif ( this.isEmpty() ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\t// compute box center and extents\n\t\tthis.getCenter( _center );\n\t\t_extents.subVectors( this.max, _center );\n\n\t\t// translate triangle to aabb origin\n\t\t_v0$2.subVectors( triangle.a, _center );\n\t\t_v1$7.subVectors( triangle.b, _center );\n\t\t_v2$4.subVectors( triangle.c, _center );\n\n\t\t// compute edge vectors for triangle\n\t\t_f0.subVectors( _v1$7, _v0$2 );\n\t\t_f1.subVectors( _v2$4, _v1$7 );\n\t\t_f2.subVectors( _v0$2, _v2$4 );\n\n\t\t// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb\n\t\t// 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\n\t\t// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)\n\t\tlet axes = [\n\t\t\t0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,\n\t\t\t_f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,\n\t\t\t- _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0\n\t\t];\n\t\tif ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\t// test 3 face normals from the aabb\n\t\taxes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];\n\t\tif ( ! satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents ) ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\t// finally testing the face normal of the triangle\n\t\t// use already existing triangle edge vectors here\n\t\t_triangleNormal.crossVectors( _f0, _f1 );\n\t\taxes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];\n\n\t\treturn satForAxes( axes, _v0$2, _v1$7, _v2$4, _extents );\n\n\t}\n\n\tclampPoint( point, target ) {\n\n\t\treturn target.copy( point ).clamp( this.min, this.max );\n\n\t}\n\n\tdistanceToPoint( point ) {\n\n\t\treturn this.clampPoint( point, _vector$b ).distanceTo( point );\n\n\t}\n\n\tgetBoundingSphere( target ) {\n\n\t\tif ( this.isEmpty() ) {\n\n\t\t\ttarget.makeEmpty();\n\n\t\t} else {\n\n\t\t\tthis.getCenter( target.center );\n\n\t\t\ttarget.radius = this.getSize( _vector$b ).length() * 0.5;\n\n\t\t}\n\n\t\treturn target;\n\n\t}\n\n\tintersect( box ) {\n\n\t\tthis.min.max( box.min );\n\t\tthis.max.min( box.max );\n\n\t\t// 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.\n\t\tif ( this.isEmpty() ) this.makeEmpty();\n\n\t\treturn this;\n\n\t}\n\n\tunion( box ) {\n\n\t\tthis.min.min( box.min );\n\t\tthis.max.max( box.max );\n\n\t\treturn this;\n\n\t}\n\n\tapplyMatrix4( matrix ) {\n\n\t\t// transform of empty box is an empty box.\n\t\tif ( this.isEmpty() ) return this;\n\n\t\t// NOTE: I am using a binary pattern to specify all 2^3 combinations below\n\t\t_points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000\n\t\t_points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001\n\t\t_points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010\n\t\t_points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011\n\t\t_points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100\n\t\t_points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101\n\t\t_points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110\n\t\t_points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111\n\n\t\tthis.setFromPoints( _points );\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( offset ) {\n\n\t\tthis.min.add( offset );\n\t\tthis.max.add( offset );\n\n\t\treturn this;\n\n\t}\n\n\tequals( box ) {\n\n\t\treturn box.min.equals( this.min ) && box.max.equals( this.max );\n\n\t}\n\n}\n\nconst _points = [\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3()\n];\n\nconst _vector$b = /*@__PURE__*/ new Vector3();\n\nconst _box$4 = /*@__PURE__*/ new Box3();\n\n// triangle centered vertices\n\nconst _v0$2 = /*@__PURE__*/ new Vector3();\nconst _v1$7 = /*@__PURE__*/ new Vector3();\nconst _v2$4 = /*@__PURE__*/ new Vector3();\n\n// triangle edge vectors\n\nconst _f0 = /*@__PURE__*/ new Vector3();\nconst _f1 = /*@__PURE__*/ new Vector3();\nconst _f2 = /*@__PURE__*/ new Vector3();\n\nconst _center = /*@__PURE__*/ new Vector3();\nconst _extents = /*@__PURE__*/ new Vector3();\nconst _triangleNormal = /*@__PURE__*/ new Vector3();\nconst _testAxis = /*@__PURE__*/ new Vector3();\n\nfunction satForAxes( axes, v0, v1, v2, extents ) {\n\n\tfor ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) {\n\n\t\t_testAxis.fromArray( axes, i );\n\t\t// project the aabb onto the separating axis\n\t\tconst r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );\n\t\t// project all 3 vertices of the triangle onto the separating axis\n\t\tconst p0 = v0.dot( _testAxis );\n\t\tconst p1 = v1.dot( _testAxis );\n\t\tconst p2 = v2.dot( _testAxis );\n\t\t// actual test, basically see if either of the most extreme of the triangle points intersects r\n\t\tif ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {\n\n\t\t\t// points of the projected triangle are outside the projected half-length of the aabb\n\t\t\t// the axis is separating and we can exit\n\t\t\treturn false;\n\n\t\t}\n\n\t}\n\n\treturn true;\n\n}\n\nconst _box$3 = /*@__PURE__*/ new Box3();\nconst _v1$6 = /*@__PURE__*/ new Vector3();\nconst _v2$3 = /*@__PURE__*/ new Vector3();\n\nclass Sphere {\n\n\tconstructor( center = new Vector3(), radius = - 1 ) {\n\n\t\tthis.isSphere = true;\n\n\t\tthis.center = center;\n\t\tthis.radius = radius;\n\n\t}\n\n\tset( center, radius ) {\n\n\t\tthis.center.copy( center );\n\t\tthis.radius = radius;\n\n\t\treturn this;\n\n\t}\n\n\tsetFromPoints( points, optionalCenter ) {\n\n\t\tconst center = this.center;\n\n\t\tif ( optionalCenter !== undefined ) {\n\n\t\t\tcenter.copy( optionalCenter );\n\n\t\t} else {\n\n\t\t\t_box$3.setFromPoints( points ).getCenter( center );\n\n\t\t}\n\n\t\tlet maxRadiusSq = 0;\n\n\t\tfor ( let i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );\n\n\t\t}\n\n\t\tthis.radius = Math.sqrt( maxRadiusSq );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( sphere ) {\n\n\t\tthis.center.copy( sphere.center );\n\t\tthis.radius = sphere.radius;\n\n\t\treturn this;\n\n\t}\n\n\tisEmpty() {\n\n\t\treturn ( this.radius < 0 );\n\n\t}\n\n\tmakeEmpty() {\n\n\t\tthis.center.set( 0, 0, 0 );\n\t\tthis.radius = - 1;\n\n\t\treturn this;\n\n\t}\n\n\tcontainsPoint( point ) {\n\n\t\treturn ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );\n\n\t}\n\n\tdistanceToPoint( point ) {\n\n\t\treturn ( point.distanceTo( this.center ) - this.radius );\n\n\t}\n\n\tintersectsSphere( sphere ) {\n\n\t\tconst radiusSum = this.radius + sphere.radius;\n\n\t\treturn sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\treturn box.intersectsSphere( this );\n\n\t}\n\n\tintersectsPlane( plane ) {\n\n\t\treturn Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;\n\n\t}\n\n\tclampPoint( point, target ) {\n\n\t\tconst deltaLengthSq = this.center.distanceToSquared( point );\n\n\t\ttarget.copy( point );\n\n\t\tif ( deltaLengthSq > ( this.radius * this.radius ) ) {\n\n\t\t\ttarget.sub( this.center ).normalize();\n\t\t\ttarget.multiplyScalar( this.radius ).add( this.center );\n\n\t\t}\n\n\t\treturn target;\n\n\t}\n\n\tgetBoundingBox( target ) {\n\n\t\tif ( this.isEmpty() ) {\n\n\t\t\t// Empty sphere produces empty bounding box\n\t\t\ttarget.makeEmpty();\n\t\t\treturn target;\n\n\t\t}\n\n\t\ttarget.set( this.center, this.center );\n\t\ttarget.expandByScalar( this.radius );\n\n\t\treturn target;\n\n\t}\n\n\tapplyMatrix4( matrix ) {\n\n\t\tthis.center.applyMatrix4( matrix );\n\t\tthis.radius = this.radius * matrix.getMaxScaleOnAxis();\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( offset ) {\n\n\t\tthis.center.add( offset );\n\n\t\treturn this;\n\n\t}\n\n\texpandByPoint( point ) {\n\n\t\tif ( this.isEmpty() ) {\n\n\t\t\tthis.center.copy( point );\n\n\t\t\tthis.radius = 0;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\t_v1$6.subVectors( point, this.center );\n\n\t\tconst lengthSq = _v1$6.lengthSq();\n\n\t\tif ( lengthSq > ( this.radius * this.radius ) ) {\n\n\t\t\t// calculate the minimal sphere\n\n\t\t\tconst length = Math.sqrt( lengthSq );\n\n\t\t\tconst delta = ( length - this.radius ) * 0.5;\n\n\t\t\tthis.center.addScaledVector( _v1$6, delta / length );\n\n\t\t\tthis.radius += delta;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tunion( sphere ) {\n\n\t\tif ( sphere.isEmpty() ) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( this.isEmpty() ) {\n\n\t\t\tthis.copy( sphere );\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( this.center.equals( sphere.center ) === true ) {\n\n\t\t\t this.radius = Math.max( this.radius, sphere.radius );\n\n\t\t} else {\n\n\t\t\t_v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius );\n\n\t\t\tthis.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) );\n\n\t\t\tthis.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tequals( sphere ) {\n\n\t\treturn sphere.center.equals( this.center ) && ( sphere.radius === this.radius );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nconst _vector$a = /*@__PURE__*/ new Vector3();\nconst _segCenter = /*@__PURE__*/ new Vector3();\nconst _segDir = /*@__PURE__*/ new Vector3();\nconst _diff = /*@__PURE__*/ new Vector3();\n\nconst _edge1 = /*@__PURE__*/ new Vector3();\nconst _edge2 = /*@__PURE__*/ new Vector3();\nconst _normal$1 = /*@__PURE__*/ new Vector3();\n\nclass Ray {\n\n\tconstructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) {\n\n\t\tthis.origin = origin;\n\t\tthis.direction = direction;\n\n\t}\n\n\tset( origin, direction ) {\n\n\t\tthis.origin.copy( origin );\n\t\tthis.direction.copy( direction );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( ray ) {\n\n\t\tthis.origin.copy( ray.origin );\n\t\tthis.direction.copy( ray.direction );\n\n\t\treturn this;\n\n\t}\n\n\tat( t, target ) {\n\n\t\treturn target.copy( this.origin ).addScaledVector( this.direction, t );\n\n\t}\n\n\tlookAt( v ) {\n\n\t\tthis.direction.copy( v ).sub( this.origin ).normalize();\n\n\t\treturn this;\n\n\t}\n\n\trecast( t ) {\n\n\t\tthis.origin.copy( this.at( t, _vector$a ) );\n\n\t\treturn this;\n\n\t}\n\n\tclosestPointToPoint( point, target ) {\n\n\t\ttarget.subVectors( point, this.origin );\n\n\t\tconst directionDistance = target.dot( this.direction );\n\n\t\tif ( directionDistance < 0 ) {\n\n\t\t\treturn target.copy( this.origin );\n\n\t\t}\n\n\t\treturn target.copy( this.origin ).addScaledVector( this.direction, directionDistance );\n\n\t}\n\n\tdistanceToPoint( point ) {\n\n\t\treturn Math.sqrt( this.distanceSqToPoint( point ) );\n\n\t}\n\n\tdistanceSqToPoint( point ) {\n\n\t\tconst directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction );\n\n\t\t// point behind the ray\n\n\t\tif ( directionDistance < 0 ) {\n\n\t\t\treturn this.origin.distanceToSquared( point );\n\n\t\t}\n\n\t\t_vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance );\n\n\t\treturn _vector$a.distanceToSquared( point );\n\n\t}\n\n\tdistanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {\n\n\t\t// from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h\n\t\t// It returns the min distance between the ray and the segment\n\t\t// defined by v0 and v1\n\t\t// It can also set two optional targets :\n\t\t// - The closest point on the ray\n\t\t// - The closest point on the segment\n\n\t\t_segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );\n\t\t_segDir.copy( v1 ).sub( v0 ).normalize();\n\t\t_diff.copy( this.origin ).sub( _segCenter );\n\n\t\tconst segExtent = v0.distanceTo( v1 ) * 0.5;\n\t\tconst a01 = - this.direction.dot( _segDir );\n\t\tconst b0 = _diff.dot( this.direction );\n\t\tconst b1 = - _diff.dot( _segDir );\n\t\tconst c = _diff.lengthSq();\n\t\tconst det = Math.abs( 1 - a01 * a01 );\n\t\tlet s0, s1, sqrDist, extDet;\n\n\t\tif ( det > 0 ) {\n\n\t\t\t// The ray and segment are not parallel.\n\n\t\t\ts0 = a01 * b1 - b0;\n\t\t\ts1 = a01 * b0 - b1;\n\t\t\textDet = segExtent * det;\n\n\t\t\tif ( s0 >= 0 ) {\n\n\t\t\t\tif ( s1 >= - extDet ) {\n\n\t\t\t\t\tif ( s1 <= extDet ) {\n\n\t\t\t\t\t\t// region 0\n\t\t\t\t\t\t// Minimum at interior points of ray and segment.\n\n\t\t\t\t\t\tconst invDet = 1 / det;\n\t\t\t\t\t\ts0 *= invDet;\n\t\t\t\t\t\ts1 *= invDet;\n\t\t\t\t\t\tsqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// region 1\n\n\t\t\t\t\t\ts1 = segExtent;\n\t\t\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// region 5\n\n\t\t\t\t\ts1 = - segExtent;\n\t\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( s1 <= - extDet ) {\n\n\t\t\t\t\t// region 4\n\n\t\t\t\t\ts0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );\n\t\t\t\t\ts1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t} else if ( s1 <= extDet ) {\n\n\t\t\t\t\t// region 3\n\n\t\t\t\t\ts0 = 0;\n\t\t\t\t\ts1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\tsqrDist = s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// region 2\n\n\t\t\t\t\ts0 = Math.max( 0, - ( a01 * segExtent + b0 ) );\n\t\t\t\t\ts1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// Ray and segment are parallel.\n\n\t\t\ts1 = ( a01 > 0 ) ? - segExtent : segExtent;\n\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t}\n\n\t\tif ( optionalPointOnRay ) {\n\n\t\t\toptionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 );\n\n\t\t}\n\n\t\tif ( optionalPointOnSegment ) {\n\n\t\t\toptionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 );\n\n\t\t}\n\n\t\treturn sqrDist;\n\n\t}\n\n\tintersectSphere( sphere, target ) {\n\n\t\t_vector$a.subVectors( sphere.center, this.origin );\n\t\tconst tca = _vector$a.dot( this.direction );\n\t\tconst d2 = _vector$a.dot( _vector$a ) - tca * tca;\n\t\tconst radius2 = sphere.radius * sphere.radius;\n\n\t\tif ( d2 > radius2 ) return null;\n\n\t\tconst thc = Math.sqrt( radius2 - d2 );\n\n\t\t// t0 = first intersect point - entrance on front of sphere\n\t\tconst t0 = tca - thc;\n\n\t\t// t1 = second intersect point - exit point on back of sphere\n\t\tconst t1 = tca + thc;\n\n\t\t// test to see if t1 is behind the ray - if so, return null\n\t\tif ( t1 < 0 ) return null;\n\n\t\t// test to see if t0 is behind the ray:\n\t\t// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,\n\t\t// in order to always return an intersect point that is in front of the ray.\n\t\tif ( t0 < 0 ) return this.at( t1, target );\n\n\t\t// else t0 is in front of the ray, so return the first collision point scaled by t0\n\t\treturn this.at( t0, target );\n\n\t}\n\n\tintersectsSphere( sphere ) {\n\n\t\treturn this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );\n\n\t}\n\n\tdistanceToPlane( plane ) {\n\n\t\tconst denominator = plane.normal.dot( this.direction );\n\n\t\tif ( denominator === 0 ) {\n\n\t\t\t// line is coplanar, return origin\n\t\t\tif ( plane.distanceToPoint( this.origin ) === 0 ) {\n\n\t\t\t\treturn 0;\n\n\t\t\t}\n\n\t\t\t// Null is preferable to undefined since undefined means.... it is undefined\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;\n\n\t\t// Return if the ray never intersects the plane\n\n\t\treturn t >= 0 ? t : null;\n\n\t}\n\n\tintersectPlane( plane, target ) {\n\n\t\tconst t = this.distanceToPlane( plane );\n\n\t\tif ( t === null ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\treturn this.at( t, target );\n\n\t}\n\n\tintersectsPlane( plane ) {\n\n\t\t// check if the ray lies on the plane first\n\n\t\tconst distToPoint = plane.distanceToPoint( this.origin );\n\n\t\tif ( distToPoint === 0 ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\tconst denominator = plane.normal.dot( this.direction );\n\n\t\tif ( denominator * distToPoint < 0 ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\t// ray origin is behind the plane (and is pointing behind it)\n\n\t\treturn false;\n\n\t}\n\n\tintersectBox( box, target ) {\n\n\t\tlet tmin, tmax, tymin, tymax, tzmin, tzmax;\n\n\t\tconst invdirx = 1 / this.direction.x,\n\t\t\tinvdiry = 1 / this.direction.y,\n\t\t\tinvdirz = 1 / this.direction.z;\n\n\t\tconst origin = this.origin;\n\n\t\tif ( invdirx >= 0 ) {\n\n\t\t\ttmin = ( box.min.x - origin.x ) * invdirx;\n\t\t\ttmax = ( box.max.x - origin.x ) * invdirx;\n\n\t\t} else {\n\n\t\t\ttmin = ( box.max.x - origin.x ) * invdirx;\n\t\t\ttmax = ( box.min.x - origin.x ) * invdirx;\n\n\t\t}\n\n\t\tif ( invdiry >= 0 ) {\n\n\t\t\ttymin = ( box.min.y - origin.y ) * invdiry;\n\t\t\ttymax = ( box.max.y - origin.y ) * invdiry;\n\n\t\t} else {\n\n\t\t\ttymin = ( box.max.y - origin.y ) * invdiry;\n\t\t\ttymax = ( box.min.y - origin.y ) * invdiry;\n\n\t\t}\n\n\t\tif ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;\n\n\t\tif ( tymin > tmin || isNaN( tmin ) ) tmin = tymin;\n\n\t\tif ( tymax < tmax || isNaN( tmax ) ) tmax = tymax;\n\n\t\tif ( invdirz >= 0 ) {\n\n\t\t\ttzmin = ( box.min.z - origin.z ) * invdirz;\n\t\t\ttzmax = ( box.max.z - origin.z ) * invdirz;\n\n\t\t} else {\n\n\t\t\ttzmin = ( box.max.z - origin.z ) * invdirz;\n\t\t\ttzmax = ( box.min.z - origin.z ) * invdirz;\n\n\t\t}\n\n\t\tif ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;\n\n\t\tif ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;\n\n\t\tif ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;\n\n\t\t//return point closest to the ray (positive side)\n\n\t\tif ( tmax < 0 ) return null;\n\n\t\treturn this.at( tmin >= 0 ? tmin : tmax, target );\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\treturn this.intersectBox( box, _vector$a ) !== null;\n\n\t}\n\n\tintersectTriangle( a, b, c, backfaceCulling, target ) {\n\n\t\t// Compute the offset origin, edges, and normal.\n\n\t\t// from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h\n\n\t\t_edge1.subVectors( b, a );\n\t\t_edge2.subVectors( c, a );\n\t\t_normal$1.crossVectors( _edge1, _edge2 );\n\n\t\t// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,\n\t\t// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by\n\t\t// |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))\n\t\t// |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))\n\t\t// |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)\n\t\tlet DdN = this.direction.dot( _normal$1 );\n\t\tlet sign;\n\n\t\tif ( DdN > 0 ) {\n\n\t\t\tif ( backfaceCulling ) return null;\n\t\t\tsign = 1;\n\n\t\t} else if ( DdN < 0 ) {\n\n\t\t\tsign = - 1;\n\t\t\tDdN = - DdN;\n\n\t\t} else {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t_diff.subVectors( this.origin, a );\n\t\tconst DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );\n\n\t\t// b1 < 0, no intersection\n\t\tif ( DdQxE2 < 0 ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );\n\n\t\t// b2 < 0, no intersection\n\t\tif ( DdE1xQ < 0 ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// b1+b2 > 1, no intersection\n\t\tif ( DdQxE2 + DdE1xQ > DdN ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// Line intersects triangle, check if ray does.\n\t\tconst QdN = - sign * _diff.dot( _normal$1 );\n\n\t\t// t < 0, no intersection\n\t\tif ( QdN < 0 ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// Ray intersects triangle.\n\t\treturn this.at( QdN / DdN, target );\n\n\t}\n\n\tapplyMatrix4( matrix4 ) {\n\n\t\tthis.origin.applyMatrix4( matrix4 );\n\t\tthis.direction.transformDirection( matrix4 );\n\n\t\treturn this;\n\n\t}\n\n\tequals( ray ) {\n\n\t\treturn ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nclass Matrix4 {\n\n\tconstructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {\n\n\t\tMatrix4.prototype.isMatrix4 = true;\n\n\t\tthis.elements = [\n\n\t\t\t1, 0, 0, 0,\n\t\t\t0, 1, 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t];\n\n\t\tif ( n11 !== undefined ) {\n\n\t\t\tthis.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 );\n\n\t\t}\n\n\t}\n\n\tset( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {\n\n\t\tconst te = this.elements;\n\n\t\tte[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;\n\t\tte[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;\n\t\tte[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;\n\t\tte[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;\n\n\t\treturn this;\n\n\t}\n\n\tidentity() {\n\n\t\tthis.set(\n\n\t\t\t1, 0, 0, 0,\n\t\t\t0, 1, 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new Matrix4().fromArray( this.elements );\n\n\t}\n\n\tcopy( m ) {\n\n\t\tconst te = this.elements;\n\t\tconst me = m.elements;\n\n\t\tte[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];\n\t\tte[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];\n\t\tte[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];\n\t\tte[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];\n\n\t\treturn this;\n\n\t}\n\n\tcopyPosition( m ) {\n\n\t\tconst te = this.elements, me = m.elements;\n\n\t\tte[ 12 ] = me[ 12 ];\n\t\tte[ 13 ] = me[ 13 ];\n\t\tte[ 14 ] = me[ 14 ];\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrix3( m ) {\n\n\t\tconst me = m.elements;\n\n\t\tthis.set(\n\n\t\t\tme[ 0 ], me[ 3 ], me[ 6 ], 0,\n\t\t\tme[ 1 ], me[ 4 ], me[ 7 ], 0,\n\t\t\tme[ 2 ], me[ 5 ], me[ 8 ], 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\textractBasis( xAxis, yAxis, zAxis ) {\n\n\t\txAxis.setFromMatrixColumn( this, 0 );\n\t\tyAxis.setFromMatrixColumn( this, 1 );\n\t\tzAxis.setFromMatrixColumn( this, 2 );\n\n\t\treturn this;\n\n\t}\n\n\tmakeBasis( xAxis, yAxis, zAxis ) {\n\n\t\tthis.set(\n\t\t\txAxis.x, yAxis.x, zAxis.x, 0,\n\t\t\txAxis.y, yAxis.y, zAxis.y, 0,\n\t\t\txAxis.z, yAxis.z, zAxis.z, 0,\n\t\t\t0, 0, 0, 1\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\textractRotation( m ) {\n\n\t\t// this method does not support reflection matrices\n\n\t\tconst te = this.elements;\n\t\tconst me = m.elements;\n\n\t\tconst scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length();\n\t\tconst scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length();\n\t\tconst scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length();\n\n\t\tte[ 0 ] = me[ 0 ] * scaleX;\n\t\tte[ 1 ] = me[ 1 ] * scaleX;\n\t\tte[ 2 ] = me[ 2 ] * scaleX;\n\t\tte[ 3 ] = 0;\n\n\t\tte[ 4 ] = me[ 4 ] * scaleY;\n\t\tte[ 5 ] = me[ 5 ] * scaleY;\n\t\tte[ 6 ] = me[ 6 ] * scaleY;\n\t\tte[ 7 ] = 0;\n\n\t\tte[ 8 ] = me[ 8 ] * scaleZ;\n\t\tte[ 9 ] = me[ 9 ] * scaleZ;\n\t\tte[ 10 ] = me[ 10 ] * scaleZ;\n\t\tte[ 11 ] = 0;\n\n\t\tte[ 12 ] = 0;\n\t\tte[ 13 ] = 0;\n\t\tte[ 14 ] = 0;\n\t\tte[ 15 ] = 1;\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationFromEuler( euler ) {\n\n\t\tconst te = this.elements;\n\n\t\tconst x = euler.x, y = euler.y, z = euler.z;\n\t\tconst a = Math.cos( x ), b = Math.sin( x );\n\t\tconst c = Math.cos( y ), d = Math.sin( y );\n\t\tconst e = Math.cos( z ), f = Math.sin( z );\n\n\t\tif ( euler.order === 'XYZ' ) {\n\n\t\t\tconst ae = a * e, af = a * f, be = b * e, bf = b * f;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = - c * f;\n\t\t\tte[ 8 ] = d;\n\n\t\t\tte[ 1 ] = af + be * d;\n\t\t\tte[ 5 ] = ae - bf * d;\n\t\t\tte[ 9 ] = - b * c;\n\n\t\t\tte[ 2 ] = bf - ae * d;\n\t\t\tte[ 6 ] = be + af * d;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'YXZ' ) {\n\n\t\t\tconst ce = c * e, cf = c * f, de = d * e, df = d * f;\n\n\t\t\tte[ 0 ] = ce + df * b;\n\t\t\tte[ 4 ] = de * b - cf;\n\t\t\tte[ 8 ] = a * d;\n\n\t\t\tte[ 1 ] = a * f;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = - b;\n\n\t\t\tte[ 2 ] = cf * b - de;\n\t\t\tte[ 6 ] = df + ce * b;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'ZXY' ) {\n\n\t\t\tconst ce = c * e, cf = c * f, de = d * e, df = d * f;\n\n\t\t\tte[ 0 ] = ce - df * b;\n\t\t\tte[ 4 ] = - a * f;\n\t\t\tte[ 8 ] = de + cf * b;\n\n\t\t\tte[ 1 ] = cf + de * b;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = df - ce * b;\n\n\t\t\tte[ 2 ] = - a * d;\n\t\t\tte[ 6 ] = b;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'ZYX' ) {\n\n\t\t\tconst ae = a * e, af = a * f, be = b * e, bf = b * f;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = be * d - af;\n\t\t\tte[ 8 ] = ae * d + bf;\n\n\t\t\tte[ 1 ] = c * f;\n\t\t\tte[ 5 ] = bf * d + ae;\n\t\t\tte[ 9 ] = af * d - be;\n\n\t\t\tte[ 2 ] = - d;\n\t\t\tte[ 6 ] = b * c;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'YZX' ) {\n\n\t\t\tconst ac = a * c, ad = a * d, bc = b * c, bd = b * d;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = bd - ac * f;\n\t\t\tte[ 8 ] = bc * f + ad;\n\n\t\t\tte[ 1 ] = f;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = - b * e;\n\n\t\t\tte[ 2 ] = - d * e;\n\t\t\tte[ 6 ] = ad * f + bc;\n\t\t\tte[ 10 ] = ac - bd * f;\n\n\t\t} else if ( euler.order === 'XZY' ) {\n\n\t\t\tconst ac = a * c, ad = a * d, bc = b * c, bd = b * d;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = - f;\n\t\t\tte[ 8 ] = d * e;\n\n\t\t\tte[ 1 ] = ac * f + bd;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = ad * f - bc;\n\n\t\t\tte[ 2 ] = bc * f - ad;\n\t\t\tte[ 6 ] = b * e;\n\t\t\tte[ 10 ] = bd * f + ac;\n\n\t\t}\n\n\t\t// bottom row\n\t\tte[ 3 ] = 0;\n\t\tte[ 7 ] = 0;\n\t\tte[ 11 ] = 0;\n\n\t\t// last column\n\t\tte[ 12 ] = 0;\n\t\tte[ 13 ] = 0;\n\t\tte[ 14 ] = 0;\n\t\tte[ 15 ] = 1;\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationFromQuaternion( q ) {\n\n\t\treturn this.compose( _zero, q, _one );\n\n\t}\n\n\tlookAt( eye, target, up ) {\n\n\t\tconst te = this.elements;\n\n\t\t_z.subVectors( eye, target );\n\n\t\tif ( _z.lengthSq() === 0 ) {\n\n\t\t\t// eye and target are in the same position\n\n\t\t\t_z.z = 1;\n\n\t\t}\n\n\t\t_z.normalize();\n\t\t_x.crossVectors( up, _z );\n\n\t\tif ( _x.lengthSq() === 0 ) {\n\n\t\t\t// up and z are parallel\n\n\t\t\tif ( Math.abs( up.z ) === 1 ) {\n\n\t\t\t\t_z.x += 0.0001;\n\n\t\t\t} else {\n\n\t\t\t\t_z.z += 0.0001;\n\n\t\t\t}\n\n\t\t\t_z.normalize();\n\t\t\t_x.crossVectors( up, _z );\n\n\t\t}\n\n\t\t_x.normalize();\n\t\t_y.crossVectors( _z, _x );\n\n\t\tte[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x;\n\t\tte[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y;\n\t\tte[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z;\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( m ) {\n\n\t\treturn this.multiplyMatrices( this, m );\n\n\t}\n\n\tpremultiply( m ) {\n\n\t\treturn this.multiplyMatrices( m, this );\n\n\t}\n\n\tmultiplyMatrices( a, b ) {\n\n\t\tconst ae = a.elements;\n\t\tconst be = b.elements;\n\t\tconst te = this.elements;\n\n\t\tconst a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];\n\t\tconst a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];\n\t\tconst a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];\n\t\tconst a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];\n\n\t\tconst b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];\n\t\tconst b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];\n\t\tconst b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];\n\t\tconst b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];\n\n\t\tte[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;\n\t\tte[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;\n\t\tte[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;\n\t\tte[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;\n\n\t\tte[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;\n\t\tte[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;\n\t\tte[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;\n\t\tte[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;\n\n\t\tte[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;\n\t\tte[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;\n\t\tte[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;\n\t\tte[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;\n\n\t\tte[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;\n\t\tte[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;\n\t\tte[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;\n\t\tte[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( s ) {\n\n\t\tconst te = this.elements;\n\n\t\tte[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;\n\t\tte[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;\n\t\tte[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;\n\t\tte[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;\n\n\t\treturn this;\n\n\t}\n\n\tdeterminant() {\n\n\t\tconst te = this.elements;\n\n\t\tconst n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];\n\t\tconst n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];\n\t\tconst n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];\n\t\tconst n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];\n\n\t\t//TODO: make this more efficient\n\t\t//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )\n\n\t\treturn (\n\t\t\tn41 * (\n\t\t\t\t+ n14 * n23 * n32\n\t\t\t\t - n13 * n24 * n32\n\t\t\t\t - n14 * n22 * n33\n\t\t\t\t + n12 * n24 * n33\n\t\t\t\t + n13 * n22 * n34\n\t\t\t\t - n12 * n23 * n34\n\t\t\t) +\n\t\t\tn42 * (\n\t\t\t\t+ n11 * n23 * n34\n\t\t\t\t - n11 * n24 * n33\n\t\t\t\t + n14 * n21 * n33\n\t\t\t\t - n13 * n21 * n34\n\t\t\t\t + n13 * n24 * n31\n\t\t\t\t - n14 * n23 * n31\n\t\t\t) +\n\t\t\tn43 * (\n\t\t\t\t+ n11 * n24 * n32\n\t\t\t\t - n11 * n22 * n34\n\t\t\t\t - n14 * n21 * n32\n\t\t\t\t + n12 * n21 * n34\n\t\t\t\t + n14 * n22 * n31\n\t\t\t\t - n12 * n24 * n31\n\t\t\t) +\n\t\t\tn44 * (\n\t\t\t\t- n13 * n22 * n31\n\t\t\t\t - n11 * n23 * n32\n\t\t\t\t + n11 * n22 * n33\n\t\t\t\t + n13 * n21 * n32\n\t\t\t\t - n12 * n21 * n33\n\t\t\t\t + n12 * n23 * n31\n\t\t\t)\n\n\t\t);\n\n\t}\n\n\ttranspose() {\n\n\t\tconst te = this.elements;\n\t\tlet tmp;\n\n\t\ttmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;\n\t\ttmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;\n\t\ttmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;\n\n\t\ttmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;\n\t\ttmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;\n\t\ttmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;\n\n\t\treturn this;\n\n\t}\n\n\tsetPosition( x, y, z ) {\n\n\t\tconst te = this.elements;\n\n\t\tif ( x.isVector3 ) {\n\n\t\t\tte[ 12 ] = x.x;\n\t\t\tte[ 13 ] = x.y;\n\t\t\tte[ 14 ] = x.z;\n\n\t\t} else {\n\n\t\t\tte[ 12 ] = x;\n\t\t\tte[ 13 ] = y;\n\t\t\tte[ 14 ] = z;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tinvert() {\n\n\t\t// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm\n\t\tconst te = this.elements,\n\n\t\t\tn11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ],\n\t\t\tn12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ],\n\t\t\tn13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ],\n\t\t\tn14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ],\n\n\t\t\tt11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,\n\t\t\tt12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,\n\t\t\tt13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,\n\t\t\tt14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;\n\n\t\tconst det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;\n\n\t\tif ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );\n\n\t\tconst detInv = 1 / det;\n\n\t\tte[ 0 ] = t11 * detInv;\n\t\tte[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;\n\t\tte[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;\n\t\tte[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;\n\n\t\tte[ 4 ] = t12 * detInv;\n\t\tte[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;\n\t\tte[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;\n\t\tte[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;\n\n\t\tte[ 8 ] = t13 * detInv;\n\t\tte[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;\n\t\tte[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;\n\t\tte[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;\n\n\t\tte[ 12 ] = t14 * detInv;\n\t\tte[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;\n\t\tte[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;\n\t\tte[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;\n\n\t\treturn this;\n\n\t}\n\n\tscale( v ) {\n\n\t\tconst te = this.elements;\n\t\tconst x = v.x, y = v.y, z = v.z;\n\n\t\tte[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;\n\t\tte[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;\n\t\tte[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;\n\t\tte[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;\n\n\t\treturn this;\n\n\t}\n\n\tgetMaxScaleOnAxis() {\n\n\t\tconst te = this.elements;\n\n\t\tconst scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];\n\t\tconst scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];\n\t\tconst scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];\n\n\t\treturn Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );\n\n\t}\n\n\tmakeTranslation( x, y, z ) {\n\n\t\tif ( x.isVector3 ) {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0, 0, x.x,\n\t\t\t\t0, 1, 0, x.y,\n\t\t\t\t0, 0, 1, x.z,\n\t\t\t\t0, 0, 0, 1\n\n\t\t\t);\n\n\t\t} else {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0, 0, x,\n\t\t\t\t0, 1, 0, y,\n\t\t\t\t0, 0, 1, z,\n\t\t\t\t0, 0, 0, 1\n\n\t\t\t);\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationX( theta ) {\n\n\t\tconst c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\tthis.set(\n\n\t\t\t1, 0, 0, 0,\n\t\t\t0, c, - s, 0,\n\t\t\t0, s, c, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationY( theta ) {\n\n\t\tconst c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\tthis.set(\n\n\t\t\t c, 0, s, 0,\n\t\t\t 0, 1, 0, 0,\n\t\t\t- s, 0, c, 0,\n\t\t\t 0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationZ( theta ) {\n\n\t\tconst c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\tthis.set(\n\n\t\t\tc, - s, 0, 0,\n\t\t\ts, c, 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationAxis( axis, angle ) {\n\n\t\t// Based on http://www.gamedev.net/reference/articles/article1199.asp\n\n\t\tconst c = Math.cos( angle );\n\t\tconst s = Math.sin( angle );\n\t\tconst t = 1 - c;\n\t\tconst x = axis.x, y = axis.y, z = axis.z;\n\t\tconst tx = t * x, ty = t * y;\n\n\t\tthis.set(\n\n\t\t\ttx * x + c, tx * y - s * z, tx * z + s * y, 0,\n\t\t\ttx * y + s * z, ty * y + c, ty * z - s * x, 0,\n\t\t\ttx * z - s * y, ty * z + s * x, t * z * z + c, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeScale( x, y, z ) {\n\n\t\tthis.set(\n\n\t\t\tx, 0, 0, 0,\n\t\t\t0, y, 0, 0,\n\t\t\t0, 0, z, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeShear( xy, xz, yx, yz, zx, zy ) {\n\n\t\tthis.set(\n\n\t\t\t1, yx, zx, 0,\n\t\t\txy, 1, zy, 0,\n\t\t\txz, yz, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tcompose( position, quaternion, scale ) {\n\n\t\tconst te = this.elements;\n\n\t\tconst x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;\n\t\tconst x2 = x + x,\ty2 = y + y, z2 = z + z;\n\t\tconst xx = x * x2, xy = x * y2, xz = x * z2;\n\t\tconst yy = y * y2, yz = y * z2, zz = z * z2;\n\t\tconst wx = w * x2, wy = w * y2, wz = w * z2;\n\n\t\tconst sx = scale.x, sy = scale.y, sz = scale.z;\n\n\t\tte[ 0 ] = ( 1 - ( yy + zz ) ) * sx;\n\t\tte[ 1 ] = ( xy + wz ) * sx;\n\t\tte[ 2 ] = ( xz - wy ) * sx;\n\t\tte[ 3 ] = 0;\n\n\t\tte[ 4 ] = ( xy - wz ) * sy;\n\t\tte[ 5 ] = ( 1 - ( xx + zz ) ) * sy;\n\t\tte[ 6 ] = ( yz + wx ) * sy;\n\t\tte[ 7 ] = 0;\n\n\t\tte[ 8 ] = ( xz + wy ) * sz;\n\t\tte[ 9 ] = ( yz - wx ) * sz;\n\t\tte[ 10 ] = ( 1 - ( xx + yy ) ) * sz;\n\t\tte[ 11 ] = 0;\n\n\t\tte[ 12 ] = position.x;\n\t\tte[ 13 ] = position.y;\n\t\tte[ 14 ] = position.z;\n\t\tte[ 15 ] = 1;\n\n\t\treturn this;\n\n\t}\n\n\tdecompose( position, quaternion, scale ) {\n\n\t\tconst te = this.elements;\n\n\t\tlet sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();\n\t\tconst sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();\n\t\tconst sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();\n\n\t\t// if determine is negative, we need to invert one scale\n\t\tconst det = this.determinant();\n\t\tif ( det < 0 ) sx = - sx;\n\n\t\tposition.x = te[ 12 ];\n\t\tposition.y = te[ 13 ];\n\t\tposition.z = te[ 14 ];\n\n\t\t// scale the rotation part\n\t\t_m1$4.copy( this );\n\n\t\tconst invSX = 1 / sx;\n\t\tconst invSY = 1 / sy;\n\t\tconst invSZ = 1 / sz;\n\n\t\t_m1$4.elements[ 0 ] *= invSX;\n\t\t_m1$4.elements[ 1 ] *= invSX;\n\t\t_m1$4.elements[ 2 ] *= invSX;\n\n\t\t_m1$4.elements[ 4 ] *= invSY;\n\t\t_m1$4.elements[ 5 ] *= invSY;\n\t\t_m1$4.elements[ 6 ] *= invSY;\n\n\t\t_m1$4.elements[ 8 ] *= invSZ;\n\t\t_m1$4.elements[ 9 ] *= invSZ;\n\t\t_m1$4.elements[ 10 ] *= invSZ;\n\n\t\tquaternion.setFromRotationMatrix( _m1$4 );\n\n\t\tscale.x = sx;\n\t\tscale.y = sy;\n\t\tscale.z = sz;\n\n\t\treturn this;\n\n\t}\n\n\tmakePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) {\n\n\t\tconst te = this.elements;\n\t\tconst x = 2 * near / ( right - left );\n\t\tconst y = 2 * near / ( top - bottom );\n\n\t\tconst a = ( right + left ) / ( right - left );\n\t\tconst b = ( top + bottom ) / ( top - bottom );\n\n\t\tlet c, d;\n\n\t\tif ( coordinateSystem === WebGLCoordinateSystem ) {\n\n\t\t\tc = - ( far + near ) / ( far - near );\n\t\t\td = ( - 2 * far * near ) / ( far - near );\n\n\t\t} else if ( coordinateSystem === WebGPUCoordinateSystem ) {\n\n\t\t\tc = - far / ( far - near );\n\t\t\td = ( - far * near ) / ( far - near );\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem );\n\n\t\t}\n\n\t\tte[ 0 ] = x;\tte[ 4 ] = 0;\tte[ 8 ] = a; \tte[ 12 ] = 0;\n\t\tte[ 1 ] = 0;\tte[ 5 ] = y;\tte[ 9 ] = b; \tte[ 13 ] = 0;\n\t\tte[ 2 ] = 0;\tte[ 6 ] = 0;\tte[ 10 ] = c; \tte[ 14 ] = d;\n\t\tte[ 3 ] = 0;\tte[ 7 ] = 0;\tte[ 11 ] = - 1;\tte[ 15 ] = 0;\n\n\t\treturn this;\n\n\t}\n\n\tmakeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) {\n\n\t\tconst te = this.elements;\n\t\tconst w = 1.0 / ( right - left );\n\t\tconst h = 1.0 / ( top - bottom );\n\t\tconst p = 1.0 / ( far - near );\n\n\t\tconst x = ( right + left ) * w;\n\t\tconst y = ( top + bottom ) * h;\n\n\t\tlet z, zInv;\n\n\t\tif ( coordinateSystem === WebGLCoordinateSystem ) {\n\n\t\t\tz = ( far + near ) * p;\n\t\t\tzInv = - 2 * p;\n\n\t\t} else if ( coordinateSystem === WebGPUCoordinateSystem ) {\n\n\t\t\tz = near * p;\n\t\t\tzInv = - 1 * p;\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem );\n\n\t\t}\n\n\t\tte[ 0 ] = 2 * w;\tte[ 4 ] = 0;\t\tte[ 8 ] = 0; \t\tte[ 12 ] = - x;\n\t\tte[ 1 ] = 0; \t\tte[ 5 ] = 2 * h;\tte[ 9 ] = 0; \t\tte[ 13 ] = - y;\n\t\tte[ 2 ] = 0; \t\tte[ 6 ] = 0;\t\tte[ 10 ] = zInv;\tte[ 14 ] = - z;\n\t\tte[ 3 ] = 0; \t\tte[ 7 ] = 0;\t\tte[ 11 ] = 0;\t\tte[ 15 ] = 1;\n\n\t\treturn this;\n\n\t}\n\n\tequals( matrix ) {\n\n\t\tconst te = this.elements;\n\t\tconst me = matrix.elements;\n\n\t\tfor ( let i = 0; i < 16; i ++ ) {\n\n\t\t\tif ( te[ i ] !== me[ i ] ) return false;\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tfor ( let i = 0; i < 16; i ++ ) {\n\n\t\t\tthis.elements[ i ] = array[ i + offset ];\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tconst te = this.elements;\n\n\t\tarray[ offset ] = te[ 0 ];\n\t\tarray[ offset + 1 ] = te[ 1 ];\n\t\tarray[ offset + 2 ] = te[ 2 ];\n\t\tarray[ offset + 3 ] = te[ 3 ];\n\n\t\tarray[ offset + 4 ] = te[ 4 ];\n\t\tarray[ offset + 5 ] = te[ 5 ];\n\t\tarray[ offset + 6 ] = te[ 6 ];\n\t\tarray[ offset + 7 ] = te[ 7 ];\n\n\t\tarray[ offset + 8 ] = te[ 8 ];\n\t\tarray[ offset + 9 ] = te[ 9 ];\n\t\tarray[ offset + 10 ] = te[ 10 ];\n\t\tarray[ offset + 11 ] = te[ 11 ];\n\n\t\tarray[ offset + 12 ] = te[ 12 ];\n\t\tarray[ offset + 13 ] = te[ 13 ];\n\t\tarray[ offset + 14 ] = te[ 14 ];\n\t\tarray[ offset + 15 ] = te[ 15 ];\n\n\t\treturn array;\n\n\t}\n\n}\n\nconst _v1$5 = /*@__PURE__*/ new Vector3();\nconst _m1$4 = /*@__PURE__*/ new Matrix4();\nconst _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 );\nconst _one = /*@__PURE__*/ new Vector3( 1, 1, 1 );\nconst _x = /*@__PURE__*/ new Vector3();\nconst _y = /*@__PURE__*/ new Vector3();\nconst _z = /*@__PURE__*/ new Vector3();\n\nconst _matrix$2 = /*@__PURE__*/ new Matrix4();\nconst _quaternion$3 = /*@__PURE__*/ new Quaternion();\n\nclass Euler {\n\n\tconstructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) {\n\n\t\tthis.isEuler = true;\n\n\t\tthis._x = x;\n\t\tthis._y = y;\n\t\tthis._z = z;\n\t\tthis._order = order;\n\n\t}\n\n\tget x() {\n\n\t\treturn this._x;\n\n\t}\n\n\tset x( value ) {\n\n\t\tthis._x = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget y() {\n\n\t\treturn this._y;\n\n\t}\n\n\tset y( value ) {\n\n\t\tthis._y = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget z() {\n\n\t\treturn this._z;\n\n\t}\n\n\tset z( value ) {\n\n\t\tthis._z = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget order() {\n\n\t\treturn this._order;\n\n\t}\n\n\tset order( value ) {\n\n\t\tthis._order = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tset( x, y, z, order = this._order ) {\n\n\t\tthis._x = x;\n\t\tthis._y = y;\n\t\tthis._z = z;\n\t\tthis._order = order;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this._x, this._y, this._z, this._order );\n\n\t}\n\n\tcopy( euler ) {\n\n\t\tthis._x = euler._x;\n\t\tthis._y = euler._y;\n\t\tthis._z = euler._z;\n\t\tthis._order = euler._order;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromRotationMatrix( m, order = this._order, update = true ) {\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tconst te = m.elements;\n\t\tconst m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];\n\t\tconst m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];\n\t\tconst m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];\n\n\t\tswitch ( order ) {\n\n\t\t\tcase 'XYZ':\n\n\t\t\t\tthis._y = Math.asin( clamp( m13, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m13 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( - m23, m33 );\n\t\t\t\t\tthis._z = Math.atan2( - m12, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = Math.atan2( m32, m22 );\n\t\t\t\t\tthis._z = 0;\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'YXZ':\n\n\t\t\t\tthis._x = Math.asin( - clamp( m23, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m23 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._y = Math.atan2( m13, m33 );\n\t\t\t\t\tthis._z = Math.atan2( m21, m22 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._y = Math.atan2( - m31, m11 );\n\t\t\t\t\tthis._z = 0;\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'ZXY':\n\n\t\t\t\tthis._x = Math.asin( clamp( m32, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m32 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._y = Math.atan2( - m31, m33 );\n\t\t\t\t\tthis._z = Math.atan2( - m12, m22 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._y = 0;\n\t\t\t\t\tthis._z = Math.atan2( m21, m11 );\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'ZYX':\n\n\t\t\t\tthis._y = Math.asin( - clamp( m31, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m31 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( m32, m33 );\n\t\t\t\t\tthis._z = Math.atan2( m21, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = 0;\n\t\t\t\t\tthis._z = Math.atan2( - m12, m22 );\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'YZX':\n\n\t\t\t\tthis._z = Math.asin( clamp( m21, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m21 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( - m23, m22 );\n\t\t\t\t\tthis._y = Math.atan2( - m31, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = 0;\n\t\t\t\t\tthis._y = Math.atan2( m13, m33 );\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'XZY':\n\n\t\t\t\tthis._z = Math.asin( - clamp( m12, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m12 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( m32, m22 );\n\t\t\t\t\tthis._y = Math.atan2( m13, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = Math.atan2( - m23, m33 );\n\t\t\t\t\tthis._y = 0;\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\n\t\t\t\tconsole.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order );\n\n\t\t}\n\n\t\tthis._order = order;\n\n\t\tif ( update === true ) this._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromQuaternion( q, order, update ) {\n\n\t\t_matrix$2.makeRotationFromQuaternion( q );\n\n\t\treturn this.setFromRotationMatrix( _matrix$2, order, update );\n\n\t}\n\n\tsetFromVector3( v, order = this._order ) {\n\n\t\treturn this.set( v.x, v.y, v.z, order );\n\n\t}\n\n\treorder( newOrder ) {\n\n\t\t// WARNING: this discards revolution information -bhouston\n\n\t\t_quaternion$3.setFromEuler( this );\n\n\t\treturn this.setFromQuaternion( _quaternion$3, newOrder );\n\n\t}\n\n\tequals( euler ) {\n\n\t\treturn ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );\n\n\t}\n\n\tfromArray( array ) {\n\n\t\tthis._x = array[ 0 ];\n\t\tthis._y = array[ 1 ];\n\t\tthis._z = array[ 2 ];\n\t\tif ( array[ 3 ] !== undefined ) this._order = array[ 3 ];\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this._x;\n\t\tarray[ offset + 1 ] = this._y;\n\t\tarray[ offset + 2 ] = this._z;\n\t\tarray[ offset + 3 ] = this._order;\n\n\t\treturn array;\n\n\t}\n\n\t_onChange( callback ) {\n\n\t\tthis._onChangeCallback = callback;\n\n\t\treturn this;\n\n\t}\n\n\t_onChangeCallback() {}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this._x;\n\t\tyield this._y;\n\t\tyield this._z;\n\t\tyield this._order;\n\n\t}\n\n}\n\nEuler.DEFAULT_ORDER = 'XYZ';\n\nclass Layers {\n\n\tconstructor() {\n\n\t\tthis.mask = 1 | 0;\n\n\t}\n\n\tset( channel ) {\n\n\t\tthis.mask = ( 1 << channel | 0 ) >>> 0;\n\n\t}\n\n\tenable( channel ) {\n\n\t\tthis.mask |= 1 << channel | 0;\n\n\t}\n\n\tenableAll() {\n\n\t\tthis.mask = 0xffffffff | 0;\n\n\t}\n\n\ttoggle( channel ) {\n\n\t\tthis.mask ^= 1 << channel | 0;\n\n\t}\n\n\tdisable( channel ) {\n\n\t\tthis.mask &= ~ ( 1 << channel | 0 );\n\n\t}\n\n\tdisableAll() {\n\n\t\tthis.mask = 0;\n\n\t}\n\n\ttest( layers ) {\n\n\t\treturn ( this.mask & layers.mask ) !== 0;\n\n\t}\n\n\tisEnabled( channel ) {\n\n\t\treturn ( this.mask & ( 1 << channel | 0 ) ) !== 0;\n\n\t}\n\n}\n\nlet _object3DId = 0;\n\nconst _v1$4 = /*@__PURE__*/ new Vector3();\nconst _q1 = /*@__PURE__*/ new Quaternion();\nconst _m1$3 = /*@__PURE__*/ new Matrix4();\nconst _target = /*@__PURE__*/ new Vector3();\n\nconst _position$3 = /*@__PURE__*/ new Vector3();\nconst _scale$2 = /*@__PURE__*/ new Vector3();\nconst _quaternion$2 = /*@__PURE__*/ new Quaternion();\n\nconst _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 );\nconst _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 );\nconst _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 );\n\nconst _addedEvent = { type: 'added' };\nconst _removedEvent = { type: 'removed' };\n\nconst _childaddedEvent = { type: 'childadded', child: null };\nconst _childremovedEvent = { type: 'childremoved', child: null };\n\nclass Object3D extends EventDispatcher {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isObject3D = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _object3DId ++ } );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.name = '';\n\t\tthis.type = 'Object3D';\n\n\t\tthis.parent = null;\n\t\tthis.children = [];\n\n\t\tthis.up = Object3D.DEFAULT_UP.clone();\n\n\t\tconst position = new Vector3();\n\t\tconst rotation = new Euler();\n\t\tconst quaternion = new Quaternion();\n\t\tconst scale = new Vector3( 1, 1, 1 );\n\n\t\tfunction onRotationChange() {\n\n\t\t\tquaternion.setFromEuler( rotation, false );\n\n\t\t}\n\n\t\tfunction onQuaternionChange() {\n\n\t\t\trotation.setFromQuaternion( quaternion, undefined, false );\n\n\t\t}\n\n\t\trotation._onChange( onRotationChange );\n\t\tquaternion._onChange( onQuaternionChange );\n\n\t\tObject.defineProperties( this, {\n\t\t\tposition: {\n\t\t\t\tconfigurable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: position\n\t\t\t},\n\t\t\trotation: {\n\t\t\t\tconfigurable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: rotation\n\t\t\t},\n\t\t\tquaternion: {\n\t\t\t\tconfigurable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: quaternion\n\t\t\t},\n\t\t\tscale: {\n\t\t\t\tconfigurable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: scale\n\t\t\t},\n\t\t\tmodelViewMatrix: {\n\t\t\t\tvalue: new Matrix4()\n\t\t\t},\n\t\t\tnormalMatrix: {\n\t\t\t\tvalue: new Matrix3()\n\t\t\t}\n\t\t} );\n\n\t\tthis.matrix = new Matrix4();\n\t\tthis.matrixWorld = new Matrix4();\n\n\t\tthis.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE;\n\n\t\tthis.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer\n\t\tthis.matrixWorldNeedsUpdate = false;\n\n\t\tthis.layers = new Layers();\n\t\tthis.visible = true;\n\n\t\tthis.castShadow = false;\n\t\tthis.receiveShadow = false;\n\n\t\tthis.frustumCulled = true;\n\t\tthis.renderOrder = 0;\n\n\t\tthis.animations = [];\n\n\t\tthis.userData = {};\n\n\t}\n\n\tonBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}\n\n\tonAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}\n\n\tonBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {}\n\n\tonAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {}\n\n\tapplyMatrix4( matrix ) {\n\n\t\tif ( this.matrixAutoUpdate ) this.updateMatrix();\n\n\t\tthis.matrix.premultiply( matrix );\n\n\t\tthis.matrix.decompose( this.position, this.quaternion, this.scale );\n\n\t}\n\n\tapplyQuaternion( q ) {\n\n\t\tthis.quaternion.premultiply( q );\n\n\t\treturn this;\n\n\t}\n\n\tsetRotationFromAxisAngle( axis, angle ) {\n\n\t\t// assumes axis is normalized\n\n\t\tthis.quaternion.setFromAxisAngle( axis, angle );\n\n\t}\n\n\tsetRotationFromEuler( euler ) {\n\n\t\tthis.quaternion.setFromEuler( euler, true );\n\n\t}\n\n\tsetRotationFromMatrix( m ) {\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tthis.quaternion.setFromRotationMatrix( m );\n\n\t}\n\n\tsetRotationFromQuaternion( q ) {\n\n\t\t// assumes q is normalized\n\n\t\tthis.quaternion.copy( q );\n\n\t}\n\n\trotateOnAxis( axis, angle ) {\n\n\t\t// rotate object on axis in object space\n\t\t// axis is assumed to be normalized\n\n\t\t_q1.setFromAxisAngle( axis, angle );\n\n\t\tthis.quaternion.multiply( _q1 );\n\n\t\treturn this;\n\n\t}\n\n\trotateOnWorldAxis( axis, angle ) {\n\n\t\t// rotate object on axis in world space\n\t\t// axis is assumed to be normalized\n\t\t// method assumes no rotated parent\n\n\t\t_q1.setFromAxisAngle( axis, angle );\n\n\t\tthis.quaternion.premultiply( _q1 );\n\n\t\treturn this;\n\n\t}\n\n\trotateX( angle ) {\n\n\t\treturn this.rotateOnAxis( _xAxis, angle );\n\n\t}\n\n\trotateY( angle ) {\n\n\t\treturn this.rotateOnAxis( _yAxis, angle );\n\n\t}\n\n\trotateZ( angle ) {\n\n\t\treturn this.rotateOnAxis( _zAxis, angle );\n\n\t}\n\n\ttranslateOnAxis( axis, distance ) {\n\n\t\t// translate object by distance along axis in object space\n\t\t// axis is assumed to be normalized\n\n\t\t_v1$4.copy( axis ).applyQuaternion( this.quaternion );\n\n\t\tthis.position.add( _v1$4.multiplyScalar( distance ) );\n\n\t\treturn this;\n\n\t}\n\n\ttranslateX( distance ) {\n\n\t\treturn this.translateOnAxis( _xAxis, distance );\n\n\t}\n\n\ttranslateY( distance ) {\n\n\t\treturn this.translateOnAxis( _yAxis, distance );\n\n\t}\n\n\ttranslateZ( distance ) {\n\n\t\treturn this.translateOnAxis( _zAxis, distance );\n\n\t}\n\n\tlocalToWorld( vector ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\treturn vector.applyMatrix4( this.matrixWorld );\n\n\t}\n\n\tworldToLocal( vector ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\treturn vector.applyMatrix4( _m1$3.copy( this.matrixWorld ).invert() );\n\n\t}\n\n\tlookAt( x, y, z ) {\n\n\t\t// This method does not support objects having non-uniformly-scaled parent(s)\n\n\t\tif ( x.isVector3 ) {\n\n\t\t\t_target.copy( x );\n\n\t\t} else {\n\n\t\t\t_target.set( x, y, z );\n\n\t\t}\n\n\t\tconst parent = this.parent;\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\t_position$3.setFromMatrixPosition( this.matrixWorld );\n\n\t\tif ( this.isCamera || this.isLight ) {\n\n\t\t\t_m1$3.lookAt( _position$3, _target, this.up );\n\n\t\t} else {\n\n\t\t\t_m1$3.lookAt( _target, _position$3, this.up );\n\n\t\t}\n\n\t\tthis.quaternion.setFromRotationMatrix( _m1$3 );\n\n\t\tif ( parent ) {\n\n\t\t\t_m1$3.extractRotation( parent.matrixWorld );\n\t\t\t_q1.setFromRotationMatrix( _m1$3 );\n\t\t\tthis.quaternion.premultiply( _q1.invert() );\n\n\t\t}\n\n\t}\n\n\tadd( object ) {\n\n\t\tif ( arguments.length > 1 ) {\n\n\t\t\tfor ( let i = 0; i < arguments.length; i ++ ) {\n\n\t\t\t\tthis.add( arguments[ i ] );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( object === this ) {\n\n\t\t\tconsole.error( 'THREE.Object3D.add: object can\\'t be added as a child of itself.', object );\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( object && object.isObject3D ) {\n\n\t\t\tobject.removeFromParent();\n\t\t\tobject.parent = this;\n\t\t\tthis.children.push( object );\n\n\t\t\tobject.dispatchEvent( _addedEvent );\n\n\t\t\t_childaddedEvent.child = object;\n\t\t\tthis.dispatchEvent( _childaddedEvent );\n\t\t\t_childaddedEvent.child = null;\n\n\t\t} else {\n\n\t\t\tconsole.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tremove( object ) {\n\n\t\tif ( arguments.length > 1 ) {\n\n\t\t\tfor ( let i = 0; i < arguments.length; i ++ ) {\n\n\t\t\t\tthis.remove( arguments[ i ] );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tconst index = this.children.indexOf( object );\n\n\t\tif ( index !== - 1 ) {\n\n\t\t\tobject.parent = null;\n\t\t\tthis.children.splice( index, 1 );\n\n\t\t\tobject.dispatchEvent( _removedEvent );\n\n\t\t\t_childremovedEvent.child = object;\n\t\t\tthis.dispatchEvent( _childremovedEvent );\n\t\t\t_childremovedEvent.child = null;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tremoveFromParent() {\n\n\t\tconst parent = this.parent;\n\n\t\tif ( parent !== null ) {\n\n\t\t\tparent.remove( this );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclear() {\n\n\t\treturn this.remove( ... this.children );\n\n\t}\n\n\tattach( object ) {\n\n\t\t// adds object as a child of this, while maintaining the object's world transform\n\n\t\t// Note: This method does not support scene graphs having non-uniformly-scaled nodes(s)\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\t_m1$3.copy( this.matrixWorld ).invert();\n\n\t\tif ( object.parent !== null ) {\n\n\t\t\tobject.parent.updateWorldMatrix( true, false );\n\n\t\t\t_m1$3.multiply( object.parent.matrixWorld );\n\n\t\t}\n\n\t\tobject.applyMatrix4( _m1$3 );\n\n\t\tobject.removeFromParent();\n\t\tobject.parent = this;\n\t\tthis.children.push( object );\n\n\t\tobject.updateWorldMatrix( false, true );\n\n\t\tobject.dispatchEvent( _addedEvent );\n\n\t\t_childaddedEvent.child = object;\n\t\tthis.dispatchEvent( _childaddedEvent );\n\t\t_childaddedEvent.child = null;\n\n\t\treturn this;\n\n\t}\n\n\tgetObjectById( id ) {\n\n\t\treturn this.getObjectByProperty( 'id', id );\n\n\t}\n\n\tgetObjectByName( name ) {\n\n\t\treturn this.getObjectByProperty( 'name', name );\n\n\t}\n\n\tgetObjectByProperty( name, value ) {\n\n\t\tif ( this[ name ] === value ) return this;\n\n\t\tfor ( let i = 0, l = this.children.length; i < l; i ++ ) {\n\n\t\t\tconst child = this.children[ i ];\n\t\t\tconst object = child.getObjectByProperty( name, value );\n\n\t\t\tif ( object !== undefined ) {\n\n\t\t\t\treturn object;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn undefined;\n\n\t}\n\n\tgetObjectsByProperty( name, value, result = [] ) {\n\n\t\tif ( this[ name ] === value ) result.push( this );\n\n\t\tconst children = this.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tchildren[ i ].getObjectsByProperty( name, value, result );\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\tgetWorldPosition( target ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\treturn target.setFromMatrixPosition( this.matrixWorld );\n\n\t}\n\n\tgetWorldQuaternion( target ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\tthis.matrixWorld.decompose( _position$3, target, _scale$2 );\n\n\t\treturn target;\n\n\t}\n\n\tgetWorldScale( target ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\tthis.matrixWorld.decompose( _position$3, _quaternion$2, target );\n\n\t\treturn target;\n\n\t}\n\n\tgetWorldDirection( target ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\tconst e = this.matrixWorld.elements;\n\n\t\treturn target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();\n\n\t}\n\n\traycast( /* raycaster, intersects */ ) {}\n\n\ttraverse( callback ) {\n\n\t\tcallback( this );\n\n\t\tconst children = this.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tchildren[ i ].traverse( callback );\n\n\t\t}\n\n\t}\n\n\ttraverseVisible( callback ) {\n\n\t\tif ( this.visible === false ) return;\n\n\t\tcallback( this );\n\n\t\tconst children = this.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tchildren[ i ].traverseVisible( callback );\n\n\t\t}\n\n\t}\n\n\ttraverseAncestors( callback ) {\n\n\t\tconst parent = this.parent;\n\n\t\tif ( parent !== null ) {\n\n\t\t\tcallback( parent );\n\n\t\t\tparent.traverseAncestors( callback );\n\n\t\t}\n\n\t}\n\n\tupdateMatrix() {\n\n\t\tthis.matrix.compose( this.position, this.quaternion, this.scale );\n\n\t\tthis.matrixWorldNeedsUpdate = true;\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tif ( this.matrixAutoUpdate ) this.updateMatrix();\n\n\t\tif ( this.matrixWorldNeedsUpdate || force ) {\n\n\t\t\tif ( this.matrixWorldAutoUpdate === true ) {\n\n\t\t\t\tif ( this.parent === null ) {\n\n\t\t\t\t\tthis.matrixWorld.copy( this.matrix );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.matrixWorldNeedsUpdate = false;\n\n\t\t\tforce = true;\n\n\t\t}\n\n\t\t// make sure descendants are updated if required\n\n\t\tconst children = this.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tconst child = children[ i ];\n\n\t\t\tchild.updateMatrixWorld( force );\n\n\t\t}\n\n\t}\n\n\tupdateWorldMatrix( updateParents, updateChildren ) {\n\n\t\tconst parent = this.parent;\n\n\t\tif ( updateParents === true && parent !== null ) {\n\n\t\t\tparent.updateWorldMatrix( true, false );\n\n\t\t}\n\n\t\tif ( this.matrixAutoUpdate ) this.updateMatrix();\n\n\t\tif ( this.matrixWorldAutoUpdate === true ) {\n\n\t\t\tif ( this.parent === null ) {\n\n\t\t\t\tthis.matrixWorld.copy( this.matrix );\n\n\t\t\t} else {\n\n\t\t\t\tthis.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// make sure descendants are updated\n\n\t\tif ( updateChildren === true ) {\n\n\t\t\tconst children = this.children;\n\n\t\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = children[ i ];\n\n\t\t\t\tchild.updateWorldMatrix( false, true );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\t// meta is a string when called from JSON.stringify\n\t\tconst isRootObject = ( meta === undefined || typeof meta === 'string' );\n\n\t\tconst output = {};\n\n\t\t// meta is a hash used to collect geometries, materials.\n\t\t// not providing it implies that this is the root object\n\t\t// being serialized.\n\t\tif ( isRootObject ) {\n\n\t\t\t// initialize meta obj\n\t\t\tmeta = {\n\t\t\t\tgeometries: {},\n\t\t\t\tmaterials: {},\n\t\t\t\ttextures: {},\n\t\t\t\timages: {},\n\t\t\t\tshapes: {},\n\t\t\t\tskeletons: {},\n\t\t\t\tanimations: {},\n\t\t\t\tnodes: {}\n\t\t\t};\n\n\t\t\toutput.metadata = {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'Object',\n\t\t\t\tgenerator: 'Object3D.toJSON'\n\t\t\t};\n\n\t\t}\n\n\t\t// standard Object3D serialization\n\n\t\tconst object = {};\n\n\t\tobject.uuid = this.uuid;\n\t\tobject.type = this.type;\n\n\t\tif ( this.name !== '' ) object.name = this.name;\n\t\tif ( this.castShadow === true ) object.castShadow = true;\n\t\tif ( this.receiveShadow === true ) object.receiveShadow = true;\n\t\tif ( this.visible === false ) object.visible = false;\n\t\tif ( this.frustumCulled === false ) object.frustumCulled = false;\n\t\tif ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;\n\t\tif ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData;\n\n\t\tobject.layers = this.layers.mask;\n\t\tobject.matrix = this.matrix.toArray();\n\t\tobject.up = this.up.toArray();\n\n\t\tif ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;\n\n\t\t// object specific properties\n\n\t\tif ( this.isInstancedMesh ) {\n\n\t\t\tobject.type = 'InstancedMesh';\n\t\t\tobject.count = this.count;\n\t\t\tobject.instanceMatrix = this.instanceMatrix.toJSON();\n\t\t\tif ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON();\n\n\t\t}\n\n\t\tif ( this.isBatchedMesh ) {\n\n\t\t\tobject.type = 'BatchedMesh';\n\t\t\tobject.perObjectFrustumCulled = this.perObjectFrustumCulled;\n\t\t\tobject.sortObjects = this.sortObjects;\n\n\t\t\tobject.drawRanges = this._drawRanges;\n\t\t\tobject.reservedRanges = this._reservedRanges;\n\n\t\t\tobject.visibility = this._visibility;\n\t\t\tobject.active = this._active;\n\t\t\tobject.bounds = this._bounds.map( bound => ( {\n\t\t\t\tboxInitialized: bound.boxInitialized,\n\t\t\t\tboxMin: bound.box.min.toArray(),\n\t\t\t\tboxMax: bound.box.max.toArray(),\n\n\t\t\t\tsphereInitialized: bound.sphereInitialized,\n\t\t\t\tsphereRadius: bound.sphere.radius,\n\t\t\t\tsphereCenter: bound.sphere.center.toArray()\n\t\t\t} ) );\n\n\t\t\tobject.maxInstanceCount = this._maxInstanceCount;\n\t\t\tobject.maxVertexCount = this._maxVertexCount;\n\t\t\tobject.maxIndexCount = this._maxIndexCount;\n\n\t\t\tobject.geometryInitialized = this._geometryInitialized;\n\t\t\tobject.geometryCount = this._geometryCount;\n\n\t\t\tobject.matricesTexture = this._matricesTexture.toJSON( meta );\n\n\t\t\tif ( this._colorsTexture !== null ) object.colorsTexture = this._colorsTexture.toJSON( meta );\n\n\t\t\tif ( this.boundingSphere !== null ) {\n\n\t\t\t\tobject.boundingSphere = {\n\t\t\t\t\tcenter: object.boundingSphere.center.toArray(),\n\t\t\t\t\tradius: object.boundingSphere.radius\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\tif ( this.boundingBox !== null ) {\n\n\t\t\t\tobject.boundingBox = {\n\t\t\t\t\tmin: object.boundingBox.min.toArray(),\n\t\t\t\t\tmax: object.boundingBox.max.toArray()\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tfunction serialize( library, element ) {\n\n\t\t\tif ( library[ element.uuid ] === undefined ) {\n\n\t\t\t\tlibrary[ element.uuid ] = element.toJSON( meta );\n\n\t\t\t}\n\n\t\t\treturn element.uuid;\n\n\t\t}\n\n\t\tif ( this.isScene ) {\n\n\t\t\tif ( this.background ) {\n\n\t\t\t\tif ( this.background.isColor ) {\n\n\t\t\t\t\tobject.background = this.background.toJSON();\n\n\t\t\t\t} else if ( this.background.isTexture ) {\n\n\t\t\t\t\tobject.background = this.background.toJSON( meta ).uuid;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) {\n\n\t\t\t\tobject.environment = this.environment.toJSON( meta ).uuid;\n\n\t\t\t}\n\n\t\t} else if ( this.isMesh || this.isLine || this.isPoints ) {\n\n\t\t\tobject.geometry = serialize( meta.geometries, this.geometry );\n\n\t\t\tconst parameters = this.geometry.parameters;\n\n\t\t\tif ( parameters !== undefined && parameters.shapes !== undefined ) {\n\n\t\t\t\tconst shapes = parameters.shapes;\n\n\t\t\t\tif ( Array.isArray( shapes ) ) {\n\n\t\t\t\t\tfor ( let i = 0, l = shapes.length; i < l; i ++ ) {\n\n\t\t\t\t\t\tconst shape = shapes[ i ];\n\n\t\t\t\t\t\tserialize( meta.shapes, shape );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tserialize( meta.shapes, shapes );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.isSkinnedMesh ) {\n\n\t\t\tobject.bindMode = this.bindMode;\n\t\t\tobject.bindMatrix = this.bindMatrix.toArray();\n\n\t\t\tif ( this.skeleton !== undefined ) {\n\n\t\t\t\tserialize( meta.skeletons, this.skeleton );\n\n\t\t\t\tobject.skeleton = this.skeleton.uuid;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.material !== undefined ) {\n\n\t\t\tif ( Array.isArray( this.material ) ) {\n\n\t\t\t\tconst uuids = [];\n\n\t\t\t\tfor ( let i = 0, l = this.material.length; i < l; i ++ ) {\n\n\t\t\t\t\tuuids.push( serialize( meta.materials, this.material[ i ] ) );\n\n\t\t\t\t}\n\n\t\t\t\tobject.material = uuids;\n\n\t\t\t} else {\n\n\t\t\t\tobject.material = serialize( meta.materials, this.material );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tif ( this.children.length > 0 ) {\n\n\t\t\tobject.children = [];\n\n\t\t\tfor ( let i = 0; i < this.children.length; i ++ ) {\n\n\t\t\t\tobject.children.push( this.children[ i ].toJSON( meta ).object );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tif ( this.animations.length > 0 ) {\n\n\t\t\tobject.animations = [];\n\n\t\t\tfor ( let i = 0; i < this.animations.length; i ++ ) {\n\n\t\t\t\tconst animation = this.animations[ i ];\n\n\t\t\t\tobject.animations.push( serialize( meta.animations, animation ) );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( isRootObject ) {\n\n\t\t\tconst geometries = extractFromCache( meta.geometries );\n\t\t\tconst materials = extractFromCache( meta.materials );\n\t\t\tconst textures = extractFromCache( meta.textures );\n\t\t\tconst images = extractFromCache( meta.images );\n\t\t\tconst shapes = extractFromCache( meta.shapes );\n\t\t\tconst skeletons = extractFromCache( meta.skeletons );\n\t\t\tconst animations = extractFromCache( meta.animations );\n\t\t\tconst nodes = extractFromCache( meta.nodes );\n\n\t\t\tif ( geometries.length > 0 ) output.geometries = geometries;\n\t\t\tif ( materials.length > 0 ) output.materials = materials;\n\t\t\tif ( textures.length > 0 ) output.textures = textures;\n\t\t\tif ( images.length > 0 ) output.images = images;\n\t\t\tif ( shapes.length > 0 ) output.shapes = shapes;\n\t\t\tif ( skeletons.length > 0 ) output.skeletons = skeletons;\n\t\t\tif ( animations.length > 0 ) output.animations = animations;\n\t\t\tif ( nodes.length > 0 ) output.nodes = nodes;\n\n\t\t}\n\n\t\toutput.object = object;\n\n\t\treturn output;\n\n\t\t// extract data from the cache hash\n\t\t// remove metadata on each item\n\t\t// and return as array\n\t\tfunction extractFromCache( cache ) {\n\n\t\t\tconst values = [];\n\t\t\tfor ( const key in cache ) {\n\n\t\t\t\tconst data = cache[ key ];\n\t\t\t\tdelete data.metadata;\n\t\t\t\tvalues.push( data );\n\n\t\t\t}\n\n\t\t\treturn values;\n\n\t\t}\n\n\t}\n\n\tclone( recursive ) {\n\n\t\treturn new this.constructor().copy( this, recursive );\n\n\t}\n\n\tcopy( source, recursive = true ) {\n\n\t\tthis.name = source.name;\n\n\t\tthis.up.copy( source.up );\n\n\t\tthis.position.copy( source.position );\n\t\tthis.rotation.order = source.rotation.order;\n\t\tthis.quaternion.copy( source.quaternion );\n\t\tthis.scale.copy( source.scale );\n\n\t\tthis.matrix.copy( source.matrix );\n\t\tthis.matrixWorld.copy( source.matrixWorld );\n\n\t\tthis.matrixAutoUpdate = source.matrixAutoUpdate;\n\n\t\tthis.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;\n\t\tthis.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;\n\n\t\tthis.layers.mask = source.layers.mask;\n\t\tthis.visible = source.visible;\n\n\t\tthis.castShadow = source.castShadow;\n\t\tthis.receiveShadow = source.receiveShadow;\n\n\t\tthis.frustumCulled = source.frustumCulled;\n\t\tthis.renderOrder = source.renderOrder;\n\n\t\tthis.animations = source.animations.slice();\n\n\t\tthis.userData = JSON.parse( JSON.stringify( source.userData ) );\n\n\t\tif ( recursive === true ) {\n\n\t\t\tfor ( let i = 0; i < source.children.length; i ++ ) {\n\n\t\t\t\tconst child = source.children[ i ];\n\t\t\t\tthis.add( child.clone() );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\nObject3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 );\nObject3D.DEFAULT_MATRIX_AUTO_UPDATE = true;\nObject3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true;\n\nconst _v0$1 = /*@__PURE__*/ new Vector3();\nconst _v1$3 = /*@__PURE__*/ new Vector3();\nconst _v2$2 = /*@__PURE__*/ new Vector3();\nconst _v3$2 = /*@__PURE__*/ new Vector3();\n\nconst _vab = /*@__PURE__*/ new Vector3();\nconst _vac = /*@__PURE__*/ new Vector3();\nconst _vbc = /*@__PURE__*/ new Vector3();\nconst _vap = /*@__PURE__*/ new Vector3();\nconst _vbp = /*@__PURE__*/ new Vector3();\nconst _vcp = /*@__PURE__*/ new Vector3();\n\nclass Triangle {\n\n\tconstructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) {\n\n\t\tthis.a = a;\n\t\tthis.b = b;\n\t\tthis.c = c;\n\n\t}\n\n\tstatic getNormal( a, b, c, target ) {\n\n\t\ttarget.subVectors( c, b );\n\t\t_v0$1.subVectors( a, b );\n\t\ttarget.cross( _v0$1 );\n\n\t\tconst targetLengthSq = target.lengthSq();\n\t\tif ( targetLengthSq > 0 ) {\n\n\t\t\treturn target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );\n\n\t\t}\n\n\t\treturn target.set( 0, 0, 0 );\n\n\t}\n\n\t// static/instance method to calculate barycentric coordinates\n\t// based on: http://www.blackpawn.com/texts/pointinpoly/default.html\n\tstatic getBarycoord( point, a, b, c, target ) {\n\n\t\t_v0$1.subVectors( c, a );\n\t\t_v1$3.subVectors( b, a );\n\t\t_v2$2.subVectors( point, a );\n\n\t\tconst dot00 = _v0$1.dot( _v0$1 );\n\t\tconst dot01 = _v0$1.dot( _v1$3 );\n\t\tconst dot02 = _v0$1.dot( _v2$2 );\n\t\tconst dot11 = _v1$3.dot( _v1$3 );\n\t\tconst dot12 = _v1$3.dot( _v2$2 );\n\n\t\tconst denom = ( dot00 * dot11 - dot01 * dot01 );\n\n\t\t// collinear or singular triangle\n\t\tif ( denom === 0 ) {\n\n\t\t\ttarget.set( 0, 0, 0 );\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst invDenom = 1 / denom;\n\t\tconst u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;\n\t\tconst v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;\n\n\t\t// barycentric coordinates must always sum to 1\n\t\treturn target.set( 1 - u - v, v, u );\n\n\t}\n\n\tstatic containsPoint( point, a, b, c ) {\n\n\t\t// if the triangle is degenerate then we can't contain a point\n\t\tif ( this.getBarycoord( point, a, b, c, _v3$2 ) === null ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\treturn ( _v3$2.x >= 0 ) && ( _v3$2.y >= 0 ) && ( ( _v3$2.x + _v3$2.y ) <= 1 );\n\n\t}\n\n\tstatic getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) {\n\n\t\tif ( this.getBarycoord( point, p1, p2, p3, _v3$2 ) === null ) {\n\n\t\t\ttarget.x = 0;\n\t\t\ttarget.y = 0;\n\t\t\tif ( 'z' in target ) target.z = 0;\n\t\t\tif ( 'w' in target ) target.w = 0;\n\t\t\treturn null;\n\n\t\t}\n\n\t\ttarget.setScalar( 0 );\n\t\ttarget.addScaledVector( v1, _v3$2.x );\n\t\ttarget.addScaledVector( v2, _v3$2.y );\n\t\ttarget.addScaledVector( v3, _v3$2.z );\n\n\t\treturn target;\n\n\t}\n\n\tstatic isFrontFacing( a, b, c, direction ) {\n\n\t\t_v0$1.subVectors( c, b );\n\t\t_v1$3.subVectors( a, b );\n\n\t\t// strictly front facing\n\t\treturn ( _v0$1.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false;\n\n\t}\n\n\tset( a, b, c ) {\n\n\t\tthis.a.copy( a );\n\t\tthis.b.copy( b );\n\t\tthis.c.copy( c );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromPointsAndIndices( points, i0, i1, i2 ) {\n\n\t\tthis.a.copy( points[ i0 ] );\n\t\tthis.b.copy( points[ i1 ] );\n\t\tthis.c.copy( points[ i2 ] );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromAttributeAndIndices( attribute, i0, i1, i2 ) {\n\n\t\tthis.a.fromBufferAttribute( attribute, i0 );\n\t\tthis.b.fromBufferAttribute( attribute, i1 );\n\t\tthis.c.fromBufferAttribute( attribute, i2 );\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( triangle ) {\n\n\t\tthis.a.copy( triangle.a );\n\t\tthis.b.copy( triangle.b );\n\t\tthis.c.copy( triangle.c );\n\n\t\treturn this;\n\n\t}\n\n\tgetArea() {\n\n\t\t_v0$1.subVectors( this.c, this.b );\n\t\t_v1$3.subVectors( this.a, this.b );\n\n\t\treturn _v0$1.cross( _v1$3 ).length() * 0.5;\n\n\t}\n\n\tgetMidpoint( target ) {\n\n\t\treturn target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );\n\n\t}\n\n\tgetNormal( target ) {\n\n\t\treturn Triangle.getNormal( this.a, this.b, this.c, target );\n\n\t}\n\n\tgetPlane( target ) {\n\n\t\treturn target.setFromCoplanarPoints( this.a, this.b, this.c );\n\n\t}\n\n\tgetBarycoord( point, target ) {\n\n\t\treturn Triangle.getBarycoord( point, this.a, this.b, this.c, target );\n\n\t}\n\n\tgetInterpolation( point, v1, v2, v3, target ) {\n\n\t\treturn Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target );\n\n\t}\n\n\tcontainsPoint( point ) {\n\n\t\treturn Triangle.containsPoint( point, this.a, this.b, this.c );\n\n\t}\n\n\tisFrontFacing( direction ) {\n\n\t\treturn Triangle.isFrontFacing( this.a, this.b, this.c, direction );\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\treturn box.intersectsTriangle( this );\n\n\t}\n\n\tclosestPointToPoint( p, target ) {\n\n\t\tconst a = this.a, b = this.b, c = this.c;\n\t\tlet v, w;\n\n\t\t// algorithm thanks to Real-Time Collision Detection by Christer Ericson,\n\t\t// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,\n\t\t// under the accompanying license; see chapter 5.1.5 for detailed explanation.\n\t\t// basically, we're distinguishing which of the voronoi regions of the triangle\n\t\t// the point lies in with the minimum amount of redundant computation.\n\n\t\t_vab.subVectors( b, a );\n\t\t_vac.subVectors( c, a );\n\t\t_vap.subVectors( p, a );\n\t\tconst d1 = _vab.dot( _vap );\n\t\tconst d2 = _vac.dot( _vap );\n\t\tif ( d1 <= 0 && d2 <= 0 ) {\n\n\t\t\t// vertex region of A; barycentric coords (1, 0, 0)\n\t\t\treturn target.copy( a );\n\n\t\t}\n\n\t\t_vbp.subVectors( p, b );\n\t\tconst d3 = _vab.dot( _vbp );\n\t\tconst d4 = _vac.dot( _vbp );\n\t\tif ( d3 >= 0 && d4 <= d3 ) {\n\n\t\t\t// vertex region of B; barycentric coords (0, 1, 0)\n\t\t\treturn target.copy( b );\n\n\t\t}\n\n\t\tconst vc = d1 * d4 - d3 * d2;\n\t\tif ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {\n\n\t\t\tv = d1 / ( d1 - d3 );\n\t\t\t// edge region of AB; barycentric coords (1-v, v, 0)\n\t\t\treturn target.copy( a ).addScaledVector( _vab, v );\n\n\t\t}\n\n\t\t_vcp.subVectors( p, c );\n\t\tconst d5 = _vab.dot( _vcp );\n\t\tconst d6 = _vac.dot( _vcp );\n\t\tif ( d6 >= 0 && d5 <= d6 ) {\n\n\t\t\t// vertex region of C; barycentric coords (0, 0, 1)\n\t\t\treturn target.copy( c );\n\n\t\t}\n\n\t\tconst vb = d5 * d2 - d1 * d6;\n\t\tif ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {\n\n\t\t\tw = d2 / ( d2 - d6 );\n\t\t\t// edge region of AC; barycentric coords (1-w, 0, w)\n\t\t\treturn target.copy( a ).addScaledVector( _vac, w );\n\n\t\t}\n\n\t\tconst va = d3 * d6 - d5 * d4;\n\t\tif ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {\n\n\t\t\t_vbc.subVectors( c, b );\n\t\t\tw = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );\n\t\t\t// edge region of BC; barycentric coords (0, 1-w, w)\n\t\t\treturn target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC\n\n\t\t}\n\n\t\t// face region\n\t\tconst denom = 1 / ( va + vb + vc );\n\t\t// u = va * denom\n\t\tv = vb * denom;\n\t\tw = vc * denom;\n\n\t\treturn target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );\n\n\t}\n\n\tequals( triangle ) {\n\n\t\treturn triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );\n\n\t}\n\n}\n\nconst _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,\n\t'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,\n\t'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,\n\t'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,\n\t'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,\n\t'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,\n\t'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,\n\t'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,\n\t'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,\n\t'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,\n\t'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,\n\t'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,\n\t'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,\n\t'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,\n\t'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,\n\t'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,\n\t'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,\n\t'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,\n\t'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,\n\t'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,\n\t'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,\n\t'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,\n\t'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,\n\t'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };\n\nconst _hslA = { h: 0, s: 0, l: 0 };\nconst _hslB = { h: 0, s: 0, l: 0 };\n\nfunction hue2rgb( p, q, t ) {\n\n\tif ( t < 0 ) t += 1;\n\tif ( t > 1 ) t -= 1;\n\tif ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;\n\tif ( t < 1 / 2 ) return q;\n\tif ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );\n\treturn p;\n\n}\n\nclass Color {\n\n\tconstructor( r, g, b ) {\n\n\t\tthis.isColor = true;\n\n\t\tthis.r = 1;\n\t\tthis.g = 1;\n\t\tthis.b = 1;\n\n\t\treturn this.set( r, g, b );\n\n\t}\n\n\tset( r, g, b ) {\n\n\t\tif ( g === undefined && b === undefined ) {\n\n\t\t\t// r is THREE.Color, hex or string\n\n\t\t\tconst value = r;\n\n\t\t\tif ( value && value.isColor ) {\n\n\t\t\t\tthis.copy( value );\n\n\t\t\t} else if ( typeof value === 'number' ) {\n\n\t\t\t\tthis.setHex( value );\n\n\t\t\t} else if ( typeof value === 'string' ) {\n\n\t\t\t\tthis.setStyle( value );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tthis.setRGB( r, g, b );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetScalar( scalar ) {\n\n\t\tthis.r = scalar;\n\t\tthis.g = scalar;\n\t\tthis.b = scalar;\n\n\t\treturn this;\n\n\t}\n\n\tsetHex( hex, colorSpace = SRGBColorSpace ) {\n\n\t\thex = Math.floor( hex );\n\n\t\tthis.r = ( hex >> 16 & 255 ) / 255;\n\t\tthis.g = ( hex >> 8 & 255 ) / 255;\n\t\tthis.b = ( hex & 255 ) / 255;\n\n\t\tColorManagement.toWorkingColorSpace( this, colorSpace );\n\n\t\treturn this;\n\n\t}\n\n\tsetRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) {\n\n\t\tthis.r = r;\n\t\tthis.g = g;\n\t\tthis.b = b;\n\n\t\tColorManagement.toWorkingColorSpace( this, colorSpace );\n\n\t\treturn this;\n\n\t}\n\n\tsetHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) {\n\n\t\t// h,s,l ranges are in 0.0 - 1.0\n\t\th = euclideanModulo( h, 1 );\n\t\ts = clamp( s, 0, 1 );\n\t\tl = clamp( l, 0, 1 );\n\n\t\tif ( s === 0 ) {\n\n\t\t\tthis.r = this.g = this.b = l;\n\n\t\t} else {\n\n\t\t\tconst p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );\n\t\t\tconst q = ( 2 * l ) - p;\n\n\t\t\tthis.r = hue2rgb( q, p, h + 1 / 3 );\n\t\t\tthis.g = hue2rgb( q, p, h );\n\t\t\tthis.b = hue2rgb( q, p, h - 1 / 3 );\n\n\t\t}\n\n\t\tColorManagement.toWorkingColorSpace( this, colorSpace );\n\n\t\treturn this;\n\n\t}\n\n\tsetStyle( style, colorSpace = SRGBColorSpace ) {\n\n\t\tfunction handleAlpha( string ) {\n\n\t\t\tif ( string === undefined ) return;\n\n\t\t\tif ( parseFloat( string ) < 1 ) {\n\n\t\t\t\tconsole.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );\n\n\t\t\t}\n\n\t\t}\n\n\n\t\tlet m;\n\n\t\tif ( m = /^(\\w+)\\(([^\\)]*)\\)/.exec( style ) ) {\n\n\t\t\t// rgb / hsl\n\n\t\t\tlet color;\n\t\t\tconst name = m[ 1 ];\n\t\t\tconst components = m[ 2 ];\n\n\t\t\tswitch ( name ) {\n\n\t\t\t\tcase 'rgb':\n\t\t\t\tcase 'rgba':\n\n\t\t\t\t\tif ( color = /^\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(?:,\\s*(\\d*\\.?\\d+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t// rgb(255,0,0) rgba(255,0,0,0.5)\n\n\t\t\t\t\t\thandleAlpha( color[ 4 ] );\n\n\t\t\t\t\t\treturn this.setRGB(\n\t\t\t\t\t\t\tMath.min( 255, parseInt( color[ 1 ], 10 ) ) / 255,\n\t\t\t\t\t\t\tMath.min( 255, parseInt( color[ 2 ], 10 ) ) / 255,\n\t\t\t\t\t\t\tMath.min( 255, parseInt( color[ 3 ], 10 ) ) / 255,\n\t\t\t\t\t\t\tcolorSpace\n\t\t\t\t\t\t);\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( color = /^\\s*(\\d+)\\%\\s*,\\s*(\\d+)\\%\\s*,\\s*(\\d+)\\%\\s*(?:,\\s*(\\d*\\.?\\d+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)\n\n\t\t\t\t\t\thandleAlpha( color[ 4 ] );\n\n\t\t\t\t\t\treturn this.setRGB(\n\t\t\t\t\t\t\tMath.min( 100, parseInt( color[ 1 ], 10 ) ) / 100,\n\t\t\t\t\t\t\tMath.min( 100, parseInt( color[ 2 ], 10 ) ) / 100,\n\t\t\t\t\t\t\tMath.min( 100, parseInt( color[ 3 ], 10 ) ) / 100,\n\t\t\t\t\t\t\tcolorSpace\n\t\t\t\t\t\t);\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'hsl':\n\t\t\t\tcase 'hsla':\n\n\t\t\t\t\tif ( color = /^\\s*(\\d*\\.?\\d+)\\s*,\\s*(\\d*\\.?\\d+)\\%\\s*,\\s*(\\d*\\.?\\d+)\\%\\s*(?:,\\s*(\\d*\\.?\\d+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t// hsl(120,50%,50%) hsla(120,50%,50%,0.5)\n\n\t\t\t\t\t\thandleAlpha( color[ 4 ] );\n\n\t\t\t\t\t\treturn this.setHSL(\n\t\t\t\t\t\t\tparseFloat( color[ 1 ] ) / 360,\n\t\t\t\t\t\t\tparseFloat( color[ 2 ] ) / 100,\n\t\t\t\t\t\t\tparseFloat( color[ 3 ] ) / 100,\n\t\t\t\t\t\t\tcolorSpace\n\t\t\t\t\t\t);\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tconsole.warn( 'THREE.Color: Unknown color model ' + style );\n\n\t\t\t}\n\n\t\t} else if ( m = /^\\#([A-Fa-f\\d]+)$/.exec( style ) ) {\n\n\t\t\t// hex color\n\n\t\t\tconst hex = m[ 1 ];\n\t\t\tconst size = hex.length;\n\n\t\t\tif ( size === 3 ) {\n\n\t\t\t\t// #ff0\n\t\t\t\treturn this.setRGB(\n\t\t\t\t\tparseInt( hex.charAt( 0 ), 16 ) / 15,\n\t\t\t\t\tparseInt( hex.charAt( 1 ), 16 ) / 15,\n\t\t\t\t\tparseInt( hex.charAt( 2 ), 16 ) / 15,\n\t\t\t\t\tcolorSpace\n\t\t\t\t);\n\n\t\t\t} else if ( size === 6 ) {\n\n\t\t\t\t// #ff0000\n\t\t\t\treturn this.setHex( parseInt( hex, 16 ), colorSpace );\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'THREE.Color: Invalid hex color ' + style );\n\n\t\t\t}\n\n\t\t} else if ( style && style.length > 0 ) {\n\n\t\t\treturn this.setColorName( style, colorSpace );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetColorName( style, colorSpace = SRGBColorSpace ) {\n\n\t\t// color keywords\n\t\tconst hex = _colorKeywords[ style.toLowerCase() ];\n\n\t\tif ( hex !== undefined ) {\n\n\t\t\t// red\n\t\t\tthis.setHex( hex, colorSpace );\n\n\t\t} else {\n\n\t\t\t// unknown color\n\t\t\tconsole.warn( 'THREE.Color: Unknown color ' + style );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.r, this.g, this.b );\n\n\t}\n\n\tcopy( color ) {\n\n\t\tthis.r = color.r;\n\t\tthis.g = color.g;\n\t\tthis.b = color.b;\n\n\t\treturn this;\n\n\t}\n\n\tcopySRGBToLinear( color ) {\n\n\t\tthis.r = SRGBToLinear( color.r );\n\t\tthis.g = SRGBToLinear( color.g );\n\t\tthis.b = SRGBToLinear( color.b );\n\n\t\treturn this;\n\n\t}\n\n\tcopyLinearToSRGB( color ) {\n\n\t\tthis.r = LinearToSRGB( color.r );\n\t\tthis.g = LinearToSRGB( color.g );\n\t\tthis.b = LinearToSRGB( color.b );\n\n\t\treturn this;\n\n\t}\n\n\tconvertSRGBToLinear() {\n\n\t\tthis.copySRGBToLinear( this );\n\n\t\treturn this;\n\n\t}\n\n\tconvertLinearToSRGB() {\n\n\t\tthis.copyLinearToSRGB( this );\n\n\t\treturn this;\n\n\t}\n\n\tgetHex( colorSpace = SRGBColorSpace ) {\n\n\t\tColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );\n\n\t\treturn 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 ) );\n\n\t}\n\n\tgetHexString( colorSpace = SRGBColorSpace ) {\n\n\t\treturn ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 );\n\n\t}\n\n\tgetHSL( target, colorSpace = ColorManagement.workingColorSpace ) {\n\n\t\t// h,s,l ranges are in 0.0 - 1.0\n\n\t\tColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );\n\n\t\tconst r = _color.r, g = _color.g, b = _color.b;\n\n\t\tconst max = Math.max( r, g, b );\n\t\tconst min = Math.min( r, g, b );\n\n\t\tlet hue, saturation;\n\t\tconst lightness = ( min + max ) / 2.0;\n\n\t\tif ( min === max ) {\n\n\t\t\thue = 0;\n\t\t\tsaturation = 0;\n\n\t\t} else {\n\n\t\t\tconst delta = max - min;\n\n\t\t\tsaturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );\n\n\t\t\tswitch ( max ) {\n\n\t\t\t\tcase r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;\n\t\t\t\tcase g: hue = ( b - r ) / delta + 2; break;\n\t\t\t\tcase b: hue = ( r - g ) / delta + 4; break;\n\n\t\t\t}\n\n\t\t\thue /= 6;\n\n\t\t}\n\n\t\ttarget.h = hue;\n\t\ttarget.s = saturation;\n\t\ttarget.l = lightness;\n\n\t\treturn target;\n\n\t}\n\n\tgetRGB( target, colorSpace = ColorManagement.workingColorSpace ) {\n\n\t\tColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );\n\n\t\ttarget.r = _color.r;\n\t\ttarget.g = _color.g;\n\t\ttarget.b = _color.b;\n\n\t\treturn target;\n\n\t}\n\n\tgetStyle( colorSpace = SRGBColorSpace ) {\n\n\t\tColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );\n\n\t\tconst r = _color.r, g = _color.g, b = _color.b;\n\n\t\tif ( colorSpace !== SRGBColorSpace ) {\n\n\t\t\t// Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/).\n\t\t\treturn `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`;\n\n\t\t}\n\n\t\treturn `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`;\n\n\t}\n\n\toffsetHSL( h, s, l ) {\n\n\t\tthis.getHSL( _hslA );\n\n\t\treturn this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l );\n\n\t}\n\n\tadd( color ) {\n\n\t\tthis.r += color.r;\n\t\tthis.g += color.g;\n\t\tthis.b += color.b;\n\n\t\treturn this;\n\n\t}\n\n\taddColors( color1, color2 ) {\n\n\t\tthis.r = color1.r + color2.r;\n\t\tthis.g = color1.g + color2.g;\n\t\tthis.b = color1.b + color2.b;\n\n\t\treturn this;\n\n\t}\n\n\taddScalar( s ) {\n\n\t\tthis.r += s;\n\t\tthis.g += s;\n\t\tthis.b += s;\n\n\t\treturn this;\n\n\t}\n\n\tsub( color ) {\n\n\t\tthis.r = Math.max( 0, this.r - color.r );\n\t\tthis.g = Math.max( 0, this.g - color.g );\n\t\tthis.b = Math.max( 0, this.b - color.b );\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( color ) {\n\n\t\tthis.r *= color.r;\n\t\tthis.g *= color.g;\n\t\tthis.b *= color.b;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( s ) {\n\n\t\tthis.r *= s;\n\t\tthis.g *= s;\n\t\tthis.b *= s;\n\n\t\treturn this;\n\n\t}\n\n\tlerp( color, alpha ) {\n\n\t\tthis.r += ( color.r - this.r ) * alpha;\n\t\tthis.g += ( color.g - this.g ) * alpha;\n\t\tthis.b += ( color.b - this.b ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tlerpColors( color1, color2, alpha ) {\n\n\t\tthis.r = color1.r + ( color2.r - color1.r ) * alpha;\n\t\tthis.g = color1.g + ( color2.g - color1.g ) * alpha;\n\t\tthis.b = color1.b + ( color2.b - color1.b ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tlerpHSL( color, alpha ) {\n\n\t\tthis.getHSL( _hslA );\n\t\tcolor.getHSL( _hslB );\n\n\t\tconst h = lerp( _hslA.h, _hslB.h, alpha );\n\t\tconst s = lerp( _hslA.s, _hslB.s, alpha );\n\t\tconst l = lerp( _hslA.l, _hslB.l, alpha );\n\n\t\tthis.setHSL( h, s, l );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromVector3( v ) {\n\n\t\tthis.r = v.x;\n\t\tthis.g = v.y;\n\t\tthis.b = v.z;\n\n\t\treturn this;\n\n\t}\n\n\tapplyMatrix3( m ) {\n\n\t\tconst r = this.r, g = this.g, b = this.b;\n\t\tconst e = m.elements;\n\n\t\tthis.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b;\n\t\tthis.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b;\n\t\tthis.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b;\n\n\t\treturn this;\n\n\t}\n\n\tequals( c ) {\n\n\t\treturn ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tthis.r = array[ offset ];\n\t\tthis.g = array[ offset + 1 ];\n\t\tthis.b = array[ offset + 2 ];\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this.r;\n\t\tarray[ offset + 1 ] = this.g;\n\t\tarray[ offset + 2 ] = this.b;\n\n\t\treturn array;\n\n\t}\n\n\tfromBufferAttribute( attribute, index ) {\n\n\t\tthis.r = attribute.getX( index );\n\t\tthis.g = attribute.getY( index );\n\t\tthis.b = attribute.getZ( index );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\treturn this.getHex();\n\n\t}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this.r;\n\t\tyield this.g;\n\t\tyield this.b;\n\n\t}\n\n}\n\nconst _color = /*@__PURE__*/ new Color();\n\nColor.NAMES = _colorKeywords;\n\nlet _materialId = 0;\n\nclass Material extends EventDispatcher {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isMaterial = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _materialId ++ } );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.name = '';\n\t\tthis.type = 'Material';\n\n\t\tthis.blending = NormalBlending;\n\t\tthis.side = FrontSide;\n\t\tthis.vertexColors = false;\n\n\t\tthis.opacity = 1;\n\t\tthis.transparent = false;\n\t\tthis.alphaHash = false;\n\n\t\tthis.blendSrc = SrcAlphaFactor;\n\t\tthis.blendDst = OneMinusSrcAlphaFactor;\n\t\tthis.blendEquation = AddEquation;\n\t\tthis.blendSrcAlpha = null;\n\t\tthis.blendDstAlpha = null;\n\t\tthis.blendEquationAlpha = null;\n\t\tthis.blendColor = new Color( 0, 0, 0 );\n\t\tthis.blendAlpha = 0;\n\n\t\tthis.depthFunc = LessEqualDepth;\n\t\tthis.depthTest = true;\n\t\tthis.depthWrite = true;\n\n\t\tthis.stencilWriteMask = 0xff;\n\t\tthis.stencilFunc = AlwaysStencilFunc;\n\t\tthis.stencilRef = 0;\n\t\tthis.stencilFuncMask = 0xff;\n\t\tthis.stencilFail = KeepStencilOp;\n\t\tthis.stencilZFail = KeepStencilOp;\n\t\tthis.stencilZPass = KeepStencilOp;\n\t\tthis.stencilWrite = false;\n\n\t\tthis.clippingPlanes = null;\n\t\tthis.clipIntersection = false;\n\t\tthis.clipShadows = false;\n\n\t\tthis.shadowSide = null;\n\n\t\tthis.colorWrite = true;\n\n\t\tthis.precision = null; // override the renderer's default precision for this material\n\n\t\tthis.polygonOffset = false;\n\t\tthis.polygonOffsetFactor = 0;\n\t\tthis.polygonOffsetUnits = 0;\n\n\t\tthis.dithering = false;\n\n\t\tthis.alphaToCoverage = false;\n\t\tthis.premultipliedAlpha = false;\n\t\tthis.forceSinglePass = false;\n\n\t\tthis.visible = true;\n\n\t\tthis.toneMapped = true;\n\n\t\tthis.userData = {};\n\n\t\tthis.version = 0;\n\n\t\tthis._alphaTest = 0;\n\n\t}\n\n\tget alphaTest() {\n\n\t\treturn this._alphaTest;\n\n\t}\n\n\tset alphaTest( value ) {\n\n\t\tif ( this._alphaTest > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._alphaTest = value;\n\n\t}\n\n\tonBeforeCompile( /* shaderobject, renderer */ ) {}\n\n\tcustomProgramCacheKey() {\n\n\t\treturn this.onBeforeCompile.toString();\n\n\t}\n\n\tsetValues( values ) {\n\n\t\tif ( values === undefined ) return;\n\n\t\tfor ( const key in values ) {\n\n\t\t\tconst newValue = values[ key ];\n\n\t\t\tif ( newValue === undefined ) {\n\n\t\t\t\tconsole.warn( `THREE.Material: parameter '${ key }' has value of undefined.` );\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tconst currentValue = this[ key ];\n\n\t\t\tif ( currentValue === undefined ) {\n\n\t\t\t\tconsole.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` );\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tif ( currentValue && currentValue.isColor ) {\n\n\t\t\t\tcurrentValue.set( newValue );\n\n\t\t\t} else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {\n\n\t\t\t\tcurrentValue.copy( newValue );\n\n\t\t\t} else {\n\n\t\t\t\tthis[ key ] = newValue;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst isRootObject = ( meta === undefined || typeof meta === 'string' );\n\n\t\tif ( isRootObject ) {\n\n\t\t\tmeta = {\n\t\t\t\ttextures: {},\n\t\t\t\timages: {}\n\t\t\t};\n\n\t\t}\n\n\t\tconst data = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'Material',\n\t\t\t\tgenerator: 'Material.toJSON'\n\t\t\t}\n\t\t};\n\n\t\t// standard Material serialization\n\t\tdata.uuid = this.uuid;\n\t\tdata.type = this.type;\n\n\t\tif ( this.name !== '' ) data.name = this.name;\n\n\t\tif ( this.color && this.color.isColor ) data.color = this.color.getHex();\n\n\t\tif ( this.roughness !== undefined ) data.roughness = this.roughness;\n\t\tif ( this.metalness !== undefined ) data.metalness = this.metalness;\n\n\t\tif ( this.sheen !== undefined ) data.sheen = this.sheen;\n\t\tif ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex();\n\t\tif ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness;\n\t\tif ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();\n\t\tif ( this.emissiveIntensity !== undefined && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;\n\n\t\tif ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();\n\t\tif ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity;\n\t\tif ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex();\n\t\tif ( this.shininess !== undefined ) data.shininess = this.shininess;\n\t\tif ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;\n\t\tif ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;\n\n\t\tif ( this.clearcoatMap && this.clearcoatMap.isTexture ) {\n\n\t\t\tdata.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {\n\n\t\t\tdata.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {\n\n\t\t\tdata.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;\n\t\t\tdata.clearcoatNormalScale = this.clearcoatNormalScale.toArray();\n\n\t\t}\n\n\t\tif ( this.dispersion !== undefined ) data.dispersion = this.dispersion;\n\n\t\tif ( this.iridescence !== undefined ) data.iridescence = this.iridescence;\n\t\tif ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR;\n\t\tif ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange;\n\n\t\tif ( this.iridescenceMap && this.iridescenceMap.isTexture ) {\n\n\t\t\tdata.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) {\n\n\t\t\tdata.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy;\n\t\tif ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation;\n\n\t\tif ( this.anisotropyMap && this.anisotropyMap.isTexture ) {\n\n\t\t\tdata.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;\n\t\tif ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;\n\t\tif ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;\n\n\t\tif ( this.lightMap && this.lightMap.isTexture ) {\n\n\t\t\tdata.lightMap = this.lightMap.toJSON( meta ).uuid;\n\t\t\tdata.lightMapIntensity = this.lightMapIntensity;\n\n\t\t}\n\n\t\tif ( this.aoMap && this.aoMap.isTexture ) {\n\n\t\t\tdata.aoMap = this.aoMap.toJSON( meta ).uuid;\n\t\t\tdata.aoMapIntensity = this.aoMapIntensity;\n\n\t\t}\n\n\t\tif ( this.bumpMap && this.bumpMap.isTexture ) {\n\n\t\t\tdata.bumpMap = this.bumpMap.toJSON( meta ).uuid;\n\t\t\tdata.bumpScale = this.bumpScale;\n\n\t\t}\n\n\t\tif ( this.normalMap && this.normalMap.isTexture ) {\n\n\t\t\tdata.normalMap = this.normalMap.toJSON( meta ).uuid;\n\t\t\tdata.normalMapType = this.normalMapType;\n\t\t\tdata.normalScale = this.normalScale.toArray();\n\n\t\t}\n\n\t\tif ( this.displacementMap && this.displacementMap.isTexture ) {\n\n\t\t\tdata.displacementMap = this.displacementMap.toJSON( meta ).uuid;\n\t\t\tdata.displacementScale = this.displacementScale;\n\t\t\tdata.displacementBias = this.displacementBias;\n\n\t\t}\n\n\t\tif ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;\n\t\tif ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;\n\n\t\tif ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;\n\t\tif ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;\n\t\tif ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid;\n\t\tif ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid;\n\n\t\tif ( this.envMap && this.envMap.isTexture ) {\n\n\t\t\tdata.envMap = this.envMap.toJSON( meta ).uuid;\n\n\t\t\tif ( this.combine !== undefined ) data.combine = this.combine;\n\n\t\t}\n\n\t\tif ( this.envMapRotation !== undefined ) data.envMapRotation = this.envMapRotation.toArray();\n\t\tif ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;\n\t\tif ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity;\n\t\tif ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio;\n\n\t\tif ( this.gradientMap && this.gradientMap.isTexture ) {\n\n\t\t\tdata.gradientMap = this.gradientMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.transmission !== undefined ) data.transmission = this.transmission;\n\t\tif ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid;\n\t\tif ( this.thickness !== undefined ) data.thickness = this.thickness;\n\t\tif ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid;\n\t\tif ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance;\n\t\tif ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex();\n\n\t\tif ( this.size !== undefined ) data.size = this.size;\n\t\tif ( this.shadowSide !== null ) data.shadowSide = this.shadowSide;\n\t\tif ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;\n\n\t\tif ( this.blending !== NormalBlending ) data.blending = this.blending;\n\t\tif ( this.side !== FrontSide ) data.side = this.side;\n\t\tif ( this.vertexColors === true ) data.vertexColors = true;\n\n\t\tif ( this.opacity < 1 ) data.opacity = this.opacity;\n\t\tif ( this.transparent === true ) data.transparent = true;\n\n\t\tif ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc;\n\t\tif ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst;\n\t\tif ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation;\n\t\tif ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha;\n\t\tif ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha;\n\t\tif ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha;\n\t\tif ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex();\n\t\tif ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha;\n\n\t\tif ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc;\n\t\tif ( this.depthTest === false ) data.depthTest = this.depthTest;\n\t\tif ( this.depthWrite === false ) data.depthWrite = this.depthWrite;\n\t\tif ( this.colorWrite === false ) data.colorWrite = this.colorWrite;\n\n\t\tif ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask;\n\t\tif ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc;\n\t\tif ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef;\n\t\tif ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask;\n\t\tif ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail;\n\t\tif ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail;\n\t\tif ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass;\n\t\tif ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite;\n\n\t\t// rotation (SpriteMaterial)\n\t\tif ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation;\n\n\t\tif ( this.polygonOffset === true ) data.polygonOffset = true;\n\t\tif ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;\n\t\tif ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;\n\n\t\tif ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth;\n\t\tif ( this.dashSize !== undefined ) data.dashSize = this.dashSize;\n\t\tif ( this.gapSize !== undefined ) data.gapSize = this.gapSize;\n\t\tif ( this.scale !== undefined ) data.scale = this.scale;\n\n\t\tif ( this.dithering === true ) data.dithering = true;\n\n\t\tif ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;\n\t\tif ( this.alphaHash === true ) data.alphaHash = true;\n\t\tif ( this.alphaToCoverage === true ) data.alphaToCoverage = true;\n\t\tif ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true;\n\t\tif ( this.forceSinglePass === true ) data.forceSinglePass = true;\n\n\t\tif ( this.wireframe === true ) data.wireframe = true;\n\t\tif ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;\n\t\tif ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;\n\t\tif ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;\n\n\t\tif ( this.flatShading === true ) data.flatShading = true;\n\n\t\tif ( this.visible === false ) data.visible = false;\n\n\t\tif ( this.toneMapped === false ) data.toneMapped = false;\n\n\t\tif ( this.fog === false ) data.fog = false;\n\n\t\tif ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;\n\n\t\t// TODO: Copied from Object3D.toJSON\n\n\t\tfunction extractFromCache( cache ) {\n\n\t\t\tconst values = [];\n\n\t\t\tfor ( const key in cache ) {\n\n\t\t\t\tconst data = cache[ key ];\n\t\t\t\tdelete data.metadata;\n\t\t\t\tvalues.push( data );\n\n\t\t\t}\n\n\t\t\treturn values;\n\n\t\t}\n\n\t\tif ( isRootObject ) {\n\n\t\t\tconst textures = extractFromCache( meta.textures );\n\t\t\tconst images = extractFromCache( meta.images );\n\n\t\t\tif ( textures.length > 0 ) data.textures = textures;\n\t\t\tif ( images.length > 0 ) data.images = images;\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.name = source.name;\n\n\t\tthis.blending = source.blending;\n\t\tthis.side = source.side;\n\t\tthis.vertexColors = source.vertexColors;\n\n\t\tthis.opacity = source.opacity;\n\t\tthis.transparent = source.transparent;\n\n\t\tthis.blendSrc = source.blendSrc;\n\t\tthis.blendDst = source.blendDst;\n\t\tthis.blendEquation = source.blendEquation;\n\t\tthis.blendSrcAlpha = source.blendSrcAlpha;\n\t\tthis.blendDstAlpha = source.blendDstAlpha;\n\t\tthis.blendEquationAlpha = source.blendEquationAlpha;\n\t\tthis.blendColor.copy( source.blendColor );\n\t\tthis.blendAlpha = source.blendAlpha;\n\n\t\tthis.depthFunc = source.depthFunc;\n\t\tthis.depthTest = source.depthTest;\n\t\tthis.depthWrite = source.depthWrite;\n\n\t\tthis.stencilWriteMask = source.stencilWriteMask;\n\t\tthis.stencilFunc = source.stencilFunc;\n\t\tthis.stencilRef = source.stencilRef;\n\t\tthis.stencilFuncMask = source.stencilFuncMask;\n\t\tthis.stencilFail = source.stencilFail;\n\t\tthis.stencilZFail = source.stencilZFail;\n\t\tthis.stencilZPass = source.stencilZPass;\n\t\tthis.stencilWrite = source.stencilWrite;\n\n\t\tconst srcPlanes = source.clippingPlanes;\n\t\tlet dstPlanes = null;\n\n\t\tif ( srcPlanes !== null ) {\n\n\t\t\tconst n = srcPlanes.length;\n\t\t\tdstPlanes = new Array( n );\n\n\t\t\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\t\t\tdstPlanes[ i ] = srcPlanes[ i ].clone();\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.clippingPlanes = dstPlanes;\n\t\tthis.clipIntersection = source.clipIntersection;\n\t\tthis.clipShadows = source.clipShadows;\n\n\t\tthis.shadowSide = source.shadowSide;\n\n\t\tthis.colorWrite = source.colorWrite;\n\n\t\tthis.precision = source.precision;\n\n\t\tthis.polygonOffset = source.polygonOffset;\n\t\tthis.polygonOffsetFactor = source.polygonOffsetFactor;\n\t\tthis.polygonOffsetUnits = source.polygonOffsetUnits;\n\n\t\tthis.dithering = source.dithering;\n\n\t\tthis.alphaTest = source.alphaTest;\n\t\tthis.alphaHash = source.alphaHash;\n\t\tthis.alphaToCoverage = source.alphaToCoverage;\n\t\tthis.premultipliedAlpha = source.premultipliedAlpha;\n\t\tthis.forceSinglePass = source.forceSinglePass;\n\n\t\tthis.visible = source.visible;\n\n\t\tthis.toneMapped = source.toneMapped;\n\n\t\tthis.userData = JSON.parse( JSON.stringify( source.userData ) );\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t}\n\n\tonBuild( /* shaderobject, renderer */ ) {\n\n\t\tconsole.warn( 'Material: onBuild() has been removed.' ); // @deprecated, r166\n\n\t}\n\n\tonBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {\n\n\t\tconsole.warn( 'Material: onBeforeRender() has been removed.' ); // @deprecated, r166\n\n\t}\n\n\n}\n\nclass MeshBasicMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshBasicMaterial = true;\n\n\t\tthis.type = 'MeshBasicMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // emissive\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.specularMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.envMapRotation = new Euler();\n\t\tthis.combine = MultiplyOperation;\n\t\tthis.reflectivity = 1;\n\t\tthis.refractionRatio = 0.98;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.specularMap = source.specularMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.envMapRotation.copy( source.envMapRotation );\n\t\tthis.combine = source.combine;\n\t\tthis.reflectivity = source.reflectivity;\n\t\tthis.refractionRatio = source.refractionRatio;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\n// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf\n\nconst _tables = /*@__PURE__*/ _generateTables();\n\nfunction _generateTables() {\n\n\t// float32 to float16 helpers\n\n\tconst buffer = new ArrayBuffer( 4 );\n\tconst floatView = new Float32Array( buffer );\n\tconst uint32View = new Uint32Array( buffer );\n\n\tconst baseTable = new Uint32Array( 512 );\n\tconst shiftTable = new Uint32Array( 512 );\n\n\tfor ( let i = 0; i < 256; ++ i ) {\n\n\t\tconst e = i - 127;\n\n\t\t// very small number (0, -0)\n\n\t\tif ( e < - 27 ) {\n\n\t\t\tbaseTable[ i ] = 0x0000;\n\t\t\tbaseTable[ i | 0x100 ] = 0x8000;\n\t\t\tshiftTable[ i ] = 24;\n\t\t\tshiftTable[ i | 0x100 ] = 24;\n\n\t\t\t// small number (denorm)\n\n\t\t} else if ( e < - 14 ) {\n\n\t\t\tbaseTable[ i ] = 0x0400 >> ( - e - 14 );\n\t\t\tbaseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000;\n\t\t\tshiftTable[ i ] = - e - 1;\n\t\t\tshiftTable[ i | 0x100 ] = - e - 1;\n\n\t\t\t// normal number\n\n\t\t} else if ( e <= 15 ) {\n\n\t\t\tbaseTable[ i ] = ( e + 15 ) << 10;\n\t\t\tbaseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000;\n\t\t\tshiftTable[ i ] = 13;\n\t\t\tshiftTable[ i | 0x100 ] = 13;\n\n\t\t\t// large number (Infinity, -Infinity)\n\n\t\t} else if ( e < 128 ) {\n\n\t\t\tbaseTable[ i ] = 0x7c00;\n\t\t\tbaseTable[ i | 0x100 ] = 0xfc00;\n\t\t\tshiftTable[ i ] = 24;\n\t\t\tshiftTable[ i | 0x100 ] = 24;\n\n\t\t\t// stay (NaN, Infinity, -Infinity)\n\n\t\t} else {\n\n\t\t\tbaseTable[ i ] = 0x7c00;\n\t\t\tbaseTable[ i | 0x100 ] = 0xfc00;\n\t\t\tshiftTable[ i ] = 13;\n\t\t\tshiftTable[ i | 0x100 ] = 13;\n\n\t\t}\n\n\t}\n\n\t// float16 to float32 helpers\n\n\tconst mantissaTable = new Uint32Array( 2048 );\n\tconst exponentTable = new Uint32Array( 64 );\n\tconst offsetTable = new Uint32Array( 64 );\n\n\tfor ( let i = 1; i < 1024; ++ i ) {\n\n\t\tlet m = i << 13; // zero pad mantissa bits\n\t\tlet e = 0; // zero exponent\n\n\t\t// normalized\n\t\twhile ( ( m & 0x00800000 ) === 0 ) {\n\n\t\t\tm <<= 1;\n\t\t\te -= 0x00800000; // decrement exponent\n\n\t\t}\n\n\t\tm &= ~ 0x00800000; // clear leading 1 bit\n\t\te += 0x38800000; // adjust bias\n\n\t\tmantissaTable[ i ] = m | e;\n\n\t}\n\n\tfor ( let i = 1024; i < 2048; ++ i ) {\n\n\t\tmantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 );\n\n\t}\n\n\tfor ( let i = 1; i < 31; ++ i ) {\n\n\t\texponentTable[ i ] = i << 23;\n\n\t}\n\n\texponentTable[ 31 ] = 0x47800000;\n\texponentTable[ 32 ] = 0x80000000;\n\n\tfor ( let i = 33; i < 63; ++ i ) {\n\n\t\texponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 );\n\n\t}\n\n\texponentTable[ 63 ] = 0xc7800000;\n\n\tfor ( let i = 1; i < 64; ++ i ) {\n\n\t\tif ( i !== 32 ) {\n\n\t\t\toffsetTable[ i ] = 1024;\n\n\t\t}\n\n\t}\n\n\treturn {\n\t\tfloatView: floatView,\n\t\tuint32View: uint32View,\n\t\tbaseTable: baseTable,\n\t\tshiftTable: shiftTable,\n\t\tmantissaTable: mantissaTable,\n\t\texponentTable: exponentTable,\n\t\toffsetTable: offsetTable\n\t};\n\n}\n\n// float32 to float16\n\nfunction toHalfFloat( val ) {\n\n\tif ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' );\n\n\tval = clamp( val, - 65504, 65504 );\n\n\t_tables.floatView[ 0 ] = val;\n\tconst f = _tables.uint32View[ 0 ];\n\tconst e = ( f >> 23 ) & 0x1ff;\n\treturn _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] );\n\n}\n\n// float16 to float32\n\nfunction fromHalfFloat( val ) {\n\n\tconst m = val >> 10;\n\t_tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ];\n\treturn _tables.floatView[ 0 ];\n\n}\n\nconst DataUtils = {\n\ttoHalfFloat: toHalfFloat,\n\tfromHalfFloat: fromHalfFloat,\n};\n\nconst _vector$9 = /*@__PURE__*/ new Vector3();\nconst _vector2$1 = /*@__PURE__*/ new Vector2();\n\nclass BufferAttribute {\n\n\tconstructor( array, itemSize, normalized = false ) {\n\n\t\tif ( Array.isArray( array ) ) {\n\n\t\t\tthrow new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );\n\n\t\t}\n\n\t\tthis.isBufferAttribute = true;\n\n\t\tthis.name = '';\n\n\t\tthis.array = array;\n\t\tthis.itemSize = itemSize;\n\t\tthis.count = array !== undefined ? array.length / itemSize : 0;\n\t\tthis.normalized = normalized;\n\n\t\tthis.usage = StaticDrawUsage;\n\t\tthis._updateRange = { offset: 0, count: - 1 };\n\t\tthis.updateRanges = [];\n\t\tthis.gpuType = FloatType;\n\n\t\tthis.version = 0;\n\n\t}\n\n\tonUploadCallback() {}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t}\n\n\tget updateRange() {\n\n\t\twarnOnce( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159\n\t\treturn this._updateRange;\n\n\t}\n\n\tsetUsage( value ) {\n\n\t\tthis.usage = value;\n\n\t\treturn this;\n\n\t}\n\n\taddUpdateRange( start, count ) {\n\n\t\tthis.updateRanges.push( { start, count } );\n\n\t}\n\n\tclearUpdateRanges() {\n\n\t\tthis.updateRanges.length = 0;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.name = source.name;\n\t\tthis.array = new source.array.constructor( source.array );\n\t\tthis.itemSize = source.itemSize;\n\t\tthis.count = source.count;\n\t\tthis.normalized = source.normalized;\n\n\t\tthis.usage = source.usage;\n\t\tthis.gpuType = source.gpuType;\n\n\t\treturn this;\n\n\t}\n\n\tcopyAt( index1, attribute, index2 ) {\n\n\t\tindex1 *= this.itemSize;\n\t\tindex2 *= attribute.itemSize;\n\n\t\tfor ( let i = 0, l = this.itemSize; i < l; i ++ ) {\n\n\t\t\tthis.array[ index1 + i ] = attribute.array[ index2 + i ];\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tcopyArray( array ) {\n\n\t\tthis.array.set( array );\n\n\t\treturn this;\n\n\t}\n\n\tapplyMatrix3( m ) {\n\n\t\tif ( this.itemSize === 2 ) {\n\n\t\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t\t_vector2$1.fromBufferAttribute( this, i );\n\t\t\t\t_vector2$1.applyMatrix3( m );\n\n\t\t\t\tthis.setXY( i, _vector2$1.x, _vector2$1.y );\n\n\t\t\t}\n\n\t\t} else if ( this.itemSize === 3 ) {\n\n\t\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t\t_vector$9.fromBufferAttribute( this, i );\n\t\t\t\t_vector$9.applyMatrix3( m );\n\n\t\t\t\tthis.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tapplyMatrix4( m ) {\n\n\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t_vector$9.fromBufferAttribute( this, i );\n\n\t\t\t_vector$9.applyMatrix4( m );\n\n\t\t\tthis.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tapplyNormalMatrix( m ) {\n\n\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t_vector$9.fromBufferAttribute( this, i );\n\n\t\t\t_vector$9.applyNormalMatrix( m );\n\n\t\t\tthis.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttransformDirection( m ) {\n\n\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t_vector$9.fromBufferAttribute( this, i );\n\n\t\t\t_vector$9.transformDirection( m );\n\n\t\t\tthis.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tset( value, offset = 0 ) {\n\n\t\t// Matching BufferAttribute constructor, do not normalize the array.\n\t\tthis.array.set( value, offset );\n\n\t\treturn this;\n\n\t}\n\n\tgetComponent( index, component ) {\n\n\t\tlet value = this.array[ index * this.itemSize + component ];\n\n\t\tif ( this.normalized ) value = denormalize( value, this.array );\n\n\t\treturn value;\n\n\t}\n\n\tsetComponent( index, component, value ) {\n\n\t\tif ( this.normalized ) value = normalize( value, this.array );\n\n\t\tthis.array[ index * this.itemSize + component ] = value;\n\n\t\treturn this;\n\n\t}\n\n\tgetX( index ) {\n\n\t\tlet x = this.array[ index * this.itemSize ];\n\n\t\tif ( this.normalized ) x = denormalize( x, this.array );\n\n\t\treturn x;\n\n\t}\n\n\tsetX( index, x ) {\n\n\t\tif ( this.normalized ) x = normalize( x, this.array );\n\n\t\tthis.array[ index * this.itemSize ] = x;\n\n\t\treturn this;\n\n\t}\n\n\tgetY( index ) {\n\n\t\tlet y = this.array[ index * this.itemSize + 1 ];\n\n\t\tif ( this.normalized ) y = denormalize( y, this.array );\n\n\t\treturn y;\n\n\t}\n\n\tsetY( index, y ) {\n\n\t\tif ( this.normalized ) y = normalize( y, this.array );\n\n\t\tthis.array[ index * this.itemSize + 1 ] = y;\n\n\t\treturn this;\n\n\t}\n\n\tgetZ( index ) {\n\n\t\tlet z = this.array[ index * this.itemSize + 2 ];\n\n\t\tif ( this.normalized ) z = denormalize( z, this.array );\n\n\t\treturn z;\n\n\t}\n\n\tsetZ( index, z ) {\n\n\t\tif ( this.normalized ) z = normalize( z, this.array );\n\n\t\tthis.array[ index * this.itemSize + 2 ] = z;\n\n\t\treturn this;\n\n\t}\n\n\tgetW( index ) {\n\n\t\tlet w = this.array[ index * this.itemSize + 3 ];\n\n\t\tif ( this.normalized ) w = denormalize( w, this.array );\n\n\t\treturn w;\n\n\t}\n\n\tsetW( index, w ) {\n\n\t\tif ( this.normalized ) w = normalize( w, this.array );\n\n\t\tthis.array[ index * this.itemSize + 3 ] = w;\n\n\t\treturn this;\n\n\t}\n\n\tsetXY( index, x, y ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = x;\n\t\tthis.array[ index + 1 ] = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZ( index, x, y, z ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = x;\n\t\tthis.array[ index + 1 ] = y;\n\t\tthis.array[ index + 2 ] = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZW( index, x, y, z, w ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\t\t\tw = normalize( w, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = x;\n\t\tthis.array[ index + 1 ] = y;\n\t\tthis.array[ index + 2 ] = z;\n\t\tthis.array[ index + 3 ] = w;\n\n\t\treturn this;\n\n\t}\n\n\tonUpload( callback ) {\n\n\t\tthis.onUploadCallback = callback;\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.array, this.itemSize ).copy( this );\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = {\n\t\t\titemSize: this.itemSize,\n\t\t\ttype: this.array.constructor.name,\n\t\t\tarray: Array.from( this.array ),\n\t\t\tnormalized: this.normalized\n\t\t};\n\n\t\tif ( this.name !== '' ) data.name = this.name;\n\t\tif ( this.usage !== StaticDrawUsage ) data.usage = this.usage;\n\n\t\treturn data;\n\n\t}\n\n}\n\n//\n\nclass Int8BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Int8Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Uint8BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Uint8Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Uint8ClampedBufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Uint8ClampedArray( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Int16BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Int16Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Uint16BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Uint16Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Int32BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Int32Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Uint32BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Uint32Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Float16BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Uint16Array( array ), itemSize, normalized );\n\n\t\tthis.isFloat16BufferAttribute = true;\n\n\t}\n\n\tgetX( index ) {\n\n\t\tlet x = fromHalfFloat( this.array[ index * this.itemSize ] );\n\n\t\tif ( this.normalized ) x = denormalize( x, this.array );\n\n\t\treturn x;\n\n\t}\n\n\tsetX( index, x ) {\n\n\t\tif ( this.normalized ) x = normalize( x, this.array );\n\n\t\tthis.array[ index * this.itemSize ] = toHalfFloat( x );\n\n\t\treturn this;\n\n\t}\n\n\tgetY( index ) {\n\n\t\tlet y = fromHalfFloat( this.array[ index * this.itemSize + 1 ] );\n\n\t\tif ( this.normalized ) y = denormalize( y, this.array );\n\n\t\treturn y;\n\n\t}\n\n\tsetY( index, y ) {\n\n\t\tif ( this.normalized ) y = normalize( y, this.array );\n\n\t\tthis.array[ index * this.itemSize + 1 ] = toHalfFloat( y );\n\n\t\treturn this;\n\n\t}\n\n\tgetZ( index ) {\n\n\t\tlet z = fromHalfFloat( this.array[ index * this.itemSize + 2 ] );\n\n\t\tif ( this.normalized ) z = denormalize( z, this.array );\n\n\t\treturn z;\n\n\t}\n\n\tsetZ( index, z ) {\n\n\t\tif ( this.normalized ) z = normalize( z, this.array );\n\n\t\tthis.array[ index * this.itemSize + 2 ] = toHalfFloat( z );\n\n\t\treturn this;\n\n\t}\n\n\tgetW( index ) {\n\n\t\tlet w = fromHalfFloat( this.array[ index * this.itemSize + 3 ] );\n\n\t\tif ( this.normalized ) w = denormalize( w, this.array );\n\n\t\treturn w;\n\n\t}\n\n\tsetW( index, w ) {\n\n\t\tif ( this.normalized ) w = normalize( w, this.array );\n\n\t\tthis.array[ index * this.itemSize + 3 ] = toHalfFloat( w );\n\n\t\treturn this;\n\n\t}\n\n\tsetXY( index, x, y ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = toHalfFloat( x );\n\t\tthis.array[ index + 1 ] = toHalfFloat( y );\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZ( index, x, y, z ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = toHalfFloat( x );\n\t\tthis.array[ index + 1 ] = toHalfFloat( y );\n\t\tthis.array[ index + 2 ] = toHalfFloat( z );\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZW( index, x, y, z, w ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\t\t\tw = normalize( w, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = toHalfFloat( x );\n\t\tthis.array[ index + 1 ] = toHalfFloat( y );\n\t\tthis.array[ index + 2 ] = toHalfFloat( z );\n\t\tthis.array[ index + 3 ] = toHalfFloat( w );\n\n\t\treturn this;\n\n\t}\n\n}\n\n\nclass Float32BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Float32Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nlet _id$2 = 0;\n\nconst _m1$2 = /*@__PURE__*/ new Matrix4();\nconst _obj = /*@__PURE__*/ new Object3D();\nconst _offset = /*@__PURE__*/ new Vector3();\nconst _box$2 = /*@__PURE__*/ new Box3();\nconst _boxMorphTargets = /*@__PURE__*/ new Box3();\nconst _vector$8 = /*@__PURE__*/ new Vector3();\n\nclass BufferGeometry extends EventDispatcher {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isBufferGeometry = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _id$2 ++ } );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.name = '';\n\t\tthis.type = 'BufferGeometry';\n\n\t\tthis.index = null;\n\t\tthis.attributes = {};\n\n\t\tthis.morphAttributes = {};\n\t\tthis.morphTargetsRelative = false;\n\n\t\tthis.groups = [];\n\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t\tthis.drawRange = { start: 0, count: Infinity };\n\n\t\tthis.userData = {};\n\n\t}\n\n\tgetIndex() {\n\n\t\treturn this.index;\n\n\t}\n\n\tsetIndex( index ) {\n\n\t\tif ( Array.isArray( index ) ) {\n\n\t\t\tthis.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );\n\n\t\t} else {\n\n\t\t\tthis.index = index;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetAttribute( name ) {\n\n\t\treturn this.attributes[ name ];\n\n\t}\n\n\tsetAttribute( name, attribute ) {\n\n\t\tthis.attributes[ name ] = attribute;\n\n\t\treturn this;\n\n\t}\n\n\tdeleteAttribute( name ) {\n\n\t\tdelete this.attributes[ name ];\n\n\t\treturn this;\n\n\t}\n\n\thasAttribute( name ) {\n\n\t\treturn this.attributes[ name ] !== undefined;\n\n\t}\n\n\taddGroup( start, count, materialIndex = 0 ) {\n\n\t\tthis.groups.push( {\n\n\t\t\tstart: start,\n\t\t\tcount: count,\n\t\t\tmaterialIndex: materialIndex\n\n\t\t} );\n\n\t}\n\n\tclearGroups() {\n\n\t\tthis.groups = [];\n\n\t}\n\n\tsetDrawRange( start, count ) {\n\n\t\tthis.drawRange.start = start;\n\t\tthis.drawRange.count = count;\n\n\t}\n\n\tapplyMatrix4( matrix ) {\n\n\t\tconst position = this.attributes.position;\n\n\t\tif ( position !== undefined ) {\n\n\t\t\tposition.applyMatrix4( matrix );\n\n\t\t\tposition.needsUpdate = true;\n\n\t\t}\n\n\t\tconst normal = this.attributes.normal;\n\n\t\tif ( normal !== undefined ) {\n\n\t\t\tconst normalMatrix = new Matrix3().getNormalMatrix( matrix );\n\n\t\t\tnormal.applyNormalMatrix( normalMatrix );\n\n\t\t\tnormal.needsUpdate = true;\n\n\t\t}\n\n\t\tconst tangent = this.attributes.tangent;\n\n\t\tif ( tangent !== undefined ) {\n\n\t\t\ttangent.transformDirection( matrix );\n\n\t\t\ttangent.needsUpdate = true;\n\n\t\t}\n\n\t\tif ( this.boundingBox !== null ) {\n\n\t\t\tthis.computeBoundingBox();\n\n\t\t}\n\n\t\tif ( this.boundingSphere !== null ) {\n\n\t\t\tthis.computeBoundingSphere();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tapplyQuaternion( q ) {\n\n\t\t_m1$2.makeRotationFromQuaternion( q );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\trotateX( angle ) {\n\n\t\t// rotate geometry around world x-axis\n\n\t\t_m1$2.makeRotationX( angle );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\trotateY( angle ) {\n\n\t\t// rotate geometry around world y-axis\n\n\t\t_m1$2.makeRotationY( angle );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\trotateZ( angle ) {\n\n\t\t// rotate geometry around world z-axis\n\n\t\t_m1$2.makeRotationZ( angle );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( x, y, z ) {\n\n\t\t// translate geometry\n\n\t\t_m1$2.makeTranslation( x, y, z );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\tscale( x, y, z ) {\n\n\t\t// scale geometry\n\n\t\t_m1$2.makeScale( x, y, z );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\tlookAt( vector ) {\n\n\t\t_obj.lookAt( vector );\n\n\t\t_obj.updateMatrix();\n\n\t\tthis.applyMatrix4( _obj.matrix );\n\n\t\treturn this;\n\n\t}\n\n\tcenter() {\n\n\t\tthis.computeBoundingBox();\n\n\t\tthis.boundingBox.getCenter( _offset ).negate();\n\n\t\tthis.translate( _offset.x, _offset.y, _offset.z );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromPoints( points ) {\n\n\t\tconst position = [];\n\n\t\tfor ( let i = 0, l = points.length; i < l; i ++ ) {\n\n\t\t\tconst point = points[ i ];\n\t\t\tposition.push( point.x, point.y, point.z || 0 );\n\n\t\t}\n\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );\n\n\t\treturn this;\n\n\t}\n\n\tcomputeBoundingBox() {\n\n\t\tif ( this.boundingBox === null ) {\n\n\t\t\tthis.boundingBox = new Box3();\n\n\t\t}\n\n\t\tconst position = this.attributes.position;\n\t\tconst morphAttributesPosition = this.morphAttributes.position;\n\n\t\tif ( position && position.isGLBufferAttribute ) {\n\n\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.', this );\n\n\t\t\tthis.boundingBox.set(\n\t\t\t\tnew Vector3( - Infinity, - Infinity, - Infinity ),\n\t\t\t\tnew Vector3( + Infinity, + Infinity, + Infinity )\n\t\t\t);\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( position !== undefined ) {\n\n\t\t\tthis.boundingBox.setFromBufferAttribute( position );\n\n\t\t\t// process morph attributes if present\n\n\t\t\tif ( morphAttributesPosition ) {\n\n\t\t\t\tfor ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst morphAttribute = morphAttributesPosition[ i ];\n\t\t\t\t\t_box$2.setFromBufferAttribute( morphAttribute );\n\n\t\t\t\t\tif ( this.morphTargetsRelative ) {\n\n\t\t\t\t\t\t_vector$8.addVectors( this.boundingBox.min, _box$2.min );\n\t\t\t\t\t\tthis.boundingBox.expandByPoint( _vector$8 );\n\n\t\t\t\t\t\t_vector$8.addVectors( this.boundingBox.max, _box$2.max );\n\t\t\t\t\t\tthis.boundingBox.expandByPoint( _vector$8 );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tthis.boundingBox.expandByPoint( _box$2.min );\n\t\t\t\t\t\tthis.boundingBox.expandByPoint( _box$2.max );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tthis.boundingBox.makeEmpty();\n\n\t\t}\n\n\t\tif ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {\n\n\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The \"position\" attribute is likely to have NaN values.', this );\n\n\t\t}\n\n\t}\n\n\tcomputeBoundingSphere() {\n\n\t\tif ( this.boundingSphere === null ) {\n\n\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\tconst position = this.attributes.position;\n\t\tconst morphAttributesPosition = this.morphAttributes.position;\n\n\t\tif ( position && position.isGLBufferAttribute ) {\n\n\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere.', this );\n\n\t\t\tthis.boundingSphere.set( new Vector3(), Infinity );\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( position ) {\n\n\t\t\t// first, find the center of the bounding sphere\n\n\t\t\tconst center = this.boundingSphere.center;\n\n\t\t\t_box$2.setFromBufferAttribute( position );\n\n\t\t\t// process morph attributes if present\n\n\t\t\tif ( morphAttributesPosition ) {\n\n\t\t\t\tfor ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst morphAttribute = morphAttributesPosition[ i ];\n\t\t\t\t\t_boxMorphTargets.setFromBufferAttribute( morphAttribute );\n\n\t\t\t\t\tif ( this.morphTargetsRelative ) {\n\n\t\t\t\t\t\t_vector$8.addVectors( _box$2.min, _boxMorphTargets.min );\n\t\t\t\t\t\t_box$2.expandByPoint( _vector$8 );\n\n\t\t\t\t\t\t_vector$8.addVectors( _box$2.max, _boxMorphTargets.max );\n\t\t\t\t\t\t_box$2.expandByPoint( _vector$8 );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t_box$2.expandByPoint( _boxMorphTargets.min );\n\t\t\t\t\t\t_box$2.expandByPoint( _boxMorphTargets.max );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_box$2.getCenter( center );\n\n\t\t\t// second, try to find a boundingSphere with a radius smaller than the\n\t\t\t// boundingSphere of the boundingBox: sqrt(3) smaller in the best case\n\n\t\t\tlet maxRadiusSq = 0;\n\n\t\t\tfor ( let i = 0, il = position.count; i < il; i ++ ) {\n\n\t\t\t\t_vector$8.fromBufferAttribute( position, i );\n\n\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );\n\n\t\t\t}\n\n\t\t\t// process morph attributes if present\n\n\t\t\tif ( morphAttributesPosition ) {\n\n\t\t\t\tfor ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst morphAttribute = morphAttributesPosition[ i ];\n\t\t\t\t\tconst morphTargetsRelative = this.morphTargetsRelative;\n\n\t\t\t\t\tfor ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {\n\n\t\t\t\t\t\t_vector$8.fromBufferAttribute( morphAttribute, j );\n\n\t\t\t\t\t\tif ( morphTargetsRelative ) {\n\n\t\t\t\t\t\t\t_offset.fromBufferAttribute( position, j );\n\t\t\t\t\t\t\t_vector$8.add( _offset );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.boundingSphere.radius = Math.sqrt( maxRadiusSq );\n\n\t\t\tif ( isNaN( this.boundingSphere.radius ) ) {\n\n\t\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The \"position\" attribute is likely to have NaN values.', this );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcomputeTangents() {\n\n\t\tconst index = this.index;\n\t\tconst attributes = this.attributes;\n\n\t\t// based on http://www.terathon.com/code/tangent.html\n\t\t// (per vertex tangents)\n\n\t\tif ( index === null ||\n\t\t\t attributes.position === undefined ||\n\t\t\t attributes.normal === undefined ||\n\t\t\t attributes.uv === undefined ) {\n\n\t\t\tconsole.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst positionAttribute = attributes.position;\n\t\tconst normalAttribute = attributes.normal;\n\t\tconst uvAttribute = attributes.uv;\n\n\t\tif ( this.hasAttribute( 'tangent' ) === false ) {\n\n\t\t\tthis.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * positionAttribute.count ), 4 ) );\n\n\t\t}\n\n\t\tconst tangentAttribute = this.getAttribute( 'tangent' );\n\n\t\tconst tan1 = [], tan2 = [];\n\n\t\tfor ( let i = 0; i < positionAttribute.count; i ++ ) {\n\n\t\t\ttan1[ i ] = new Vector3();\n\t\t\ttan2[ i ] = new Vector3();\n\n\t\t}\n\n\t\tconst vA = new Vector3(),\n\t\t\tvB = new Vector3(),\n\t\t\tvC = new Vector3(),\n\n\t\t\tuvA = new Vector2(),\n\t\t\tuvB = new Vector2(),\n\t\t\tuvC = new Vector2(),\n\n\t\t\tsdir = new Vector3(),\n\t\t\ttdir = new Vector3();\n\n\t\tfunction handleTriangle( a, b, c ) {\n\n\t\t\tvA.fromBufferAttribute( positionAttribute, a );\n\t\t\tvB.fromBufferAttribute( positionAttribute, b );\n\t\t\tvC.fromBufferAttribute( positionAttribute, c );\n\n\t\t\tuvA.fromBufferAttribute( uvAttribute, a );\n\t\t\tuvB.fromBufferAttribute( uvAttribute, b );\n\t\t\tuvC.fromBufferAttribute( uvAttribute, c );\n\n\t\t\tvB.sub( vA );\n\t\t\tvC.sub( vA );\n\n\t\t\tuvB.sub( uvA );\n\t\t\tuvC.sub( uvA );\n\n\t\t\tconst r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y );\n\n\t\t\t// silently ignore degenerate uv triangles having coincident or colinear vertices\n\n\t\t\tif ( ! isFinite( r ) ) return;\n\n\t\t\tsdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r );\n\t\t\ttdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r );\n\n\t\t\ttan1[ a ].add( sdir );\n\t\t\ttan1[ b ].add( sdir );\n\t\t\ttan1[ c ].add( sdir );\n\n\t\t\ttan2[ a ].add( tdir );\n\t\t\ttan2[ b ].add( tdir );\n\t\t\ttan2[ c ].add( tdir );\n\n\t\t}\n\n\t\tlet groups = this.groups;\n\n\t\tif ( groups.length === 0 ) {\n\n\t\t\tgroups = [ {\n\t\t\t\tstart: 0,\n\t\t\t\tcount: index.count\n\t\t\t} ];\n\n\t\t}\n\n\t\tfor ( let i = 0, il = groups.length; i < il; ++ i ) {\n\n\t\t\tconst group = groups[ i ];\n\n\t\t\tconst start = group.start;\n\t\t\tconst count = group.count;\n\n\t\t\tfor ( let j = start, jl = start + count; j < jl; j += 3 ) {\n\n\t\t\t\thandleTriangle(\n\t\t\t\t\tindex.getX( j + 0 ),\n\t\t\t\t\tindex.getX( j + 1 ),\n\t\t\t\t\tindex.getX( j + 2 )\n\t\t\t\t);\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst tmp = new Vector3(), tmp2 = new Vector3();\n\t\tconst n = new Vector3(), n2 = new Vector3();\n\n\t\tfunction handleVertex( v ) {\n\n\t\t\tn.fromBufferAttribute( normalAttribute, v );\n\t\t\tn2.copy( n );\n\n\t\t\tconst t = tan1[ v ];\n\n\t\t\t// Gram-Schmidt orthogonalize\n\n\t\t\ttmp.copy( t );\n\t\t\ttmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();\n\n\t\t\t// Calculate handedness\n\n\t\t\ttmp2.crossVectors( n2, t );\n\t\t\tconst test = tmp2.dot( tan2[ v ] );\n\t\t\tconst w = ( test < 0.0 ) ? - 1.0 : 1.0;\n\n\t\t\ttangentAttribute.setXYZW( v, tmp.x, tmp.y, tmp.z, w );\n\n\t\t}\n\n\t\tfor ( let i = 0, il = groups.length; i < il; ++ i ) {\n\n\t\t\tconst group = groups[ i ];\n\n\t\t\tconst start = group.start;\n\t\t\tconst count = group.count;\n\n\t\t\tfor ( let j = start, jl = start + count; j < jl; j += 3 ) {\n\n\t\t\t\thandleVertex( index.getX( j + 0 ) );\n\t\t\t\thandleVertex( index.getX( j + 1 ) );\n\t\t\t\thandleVertex( index.getX( j + 2 ) );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcomputeVertexNormals() {\n\n\t\tconst index = this.index;\n\t\tconst positionAttribute = this.getAttribute( 'position' );\n\n\t\tif ( positionAttribute !== undefined ) {\n\n\t\t\tlet normalAttribute = this.getAttribute( 'normal' );\n\n\t\t\tif ( normalAttribute === undefined ) {\n\n\t\t\t\tnormalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 );\n\t\t\t\tthis.setAttribute( 'normal', normalAttribute );\n\n\t\t\t} else {\n\n\t\t\t\t// reset existing normals to zero\n\n\t\t\t\tfor ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {\n\n\t\t\t\t\tnormalAttribute.setXYZ( i, 0, 0, 0 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst pA = new Vector3(), pB = new Vector3(), pC = new Vector3();\n\t\t\tconst nA = new Vector3(), nB = new Vector3(), nC = new Vector3();\n\t\t\tconst cb = new Vector3(), ab = new Vector3();\n\n\t\t\t// indexed elements\n\n\t\t\tif ( index ) {\n\n\t\t\t\tfor ( let i = 0, il = index.count; i < il; i += 3 ) {\n\n\t\t\t\t\tconst vA = index.getX( i + 0 );\n\t\t\t\t\tconst vB = index.getX( i + 1 );\n\t\t\t\t\tconst vC = index.getX( i + 2 );\n\n\t\t\t\t\tpA.fromBufferAttribute( positionAttribute, vA );\n\t\t\t\t\tpB.fromBufferAttribute( positionAttribute, vB );\n\t\t\t\t\tpC.fromBufferAttribute( positionAttribute, vC );\n\n\t\t\t\t\tcb.subVectors( pC, pB );\n\t\t\t\t\tab.subVectors( pA, pB );\n\t\t\t\t\tcb.cross( ab );\n\n\t\t\t\t\tnA.fromBufferAttribute( normalAttribute, vA );\n\t\t\t\t\tnB.fromBufferAttribute( normalAttribute, vB );\n\t\t\t\t\tnC.fromBufferAttribute( normalAttribute, vC );\n\n\t\t\t\t\tnA.add( cb );\n\t\t\t\t\tnB.add( cb );\n\t\t\t\t\tnC.add( cb );\n\n\t\t\t\t\tnormalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );\n\t\t\t\t\tnormalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );\n\t\t\t\t\tnormalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// non-indexed elements (unconnected triangle soup)\n\n\t\t\t\tfor ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {\n\n\t\t\t\t\tpA.fromBufferAttribute( positionAttribute, i + 0 );\n\t\t\t\t\tpB.fromBufferAttribute( positionAttribute, i + 1 );\n\t\t\t\t\tpC.fromBufferAttribute( positionAttribute, i + 2 );\n\n\t\t\t\t\tcb.subVectors( pC, pB );\n\t\t\t\t\tab.subVectors( pA, pB );\n\t\t\t\t\tcb.cross( ab );\n\n\t\t\t\t\tnormalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );\n\t\t\t\t\tnormalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );\n\t\t\t\t\tnormalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.normalizeNormals();\n\n\t\t\tnormalAttribute.needsUpdate = true;\n\n\t\t}\n\n\t}\n\n\tnormalizeNormals() {\n\n\t\tconst normals = this.attributes.normal;\n\n\t\tfor ( let i = 0, il = normals.count; i < il; i ++ ) {\n\n\t\t\t_vector$8.fromBufferAttribute( normals, i );\n\n\t\t\t_vector$8.normalize();\n\n\t\t\tnormals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z );\n\n\t\t}\n\n\t}\n\n\ttoNonIndexed() {\n\n\t\tfunction convertBufferAttribute( attribute, indices ) {\n\n\t\t\tconst array = attribute.array;\n\t\t\tconst itemSize = attribute.itemSize;\n\t\t\tconst normalized = attribute.normalized;\n\n\t\t\tconst array2 = new array.constructor( indices.length * itemSize );\n\n\t\t\tlet index = 0, index2 = 0;\n\n\t\t\tfor ( let i = 0, l = indices.length; i < l; i ++ ) {\n\n\t\t\t\tif ( attribute.isInterleavedBufferAttribute ) {\n\n\t\t\t\t\tindex = indices[ i ] * attribute.data.stride + attribute.offset;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tindex = indices[ i ] * itemSize;\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let j = 0; j < itemSize; j ++ ) {\n\n\t\t\t\t\tarray2[ index2 ++ ] = array[ index ++ ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn new BufferAttribute( array2, itemSize, normalized );\n\n\t\t}\n\n\t\t//\n\n\t\tif ( this.index === null ) {\n\n\t\t\tconsole.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' );\n\t\t\treturn this;\n\n\t\t}\n\n\t\tconst geometry2 = new BufferGeometry();\n\n\t\tconst indices = this.index.array;\n\t\tconst attributes = this.attributes;\n\n\t\t// attributes\n\n\t\tfor ( const name in attributes ) {\n\n\t\t\tconst attribute = attributes[ name ];\n\n\t\t\tconst newAttribute = convertBufferAttribute( attribute, indices );\n\n\t\t\tgeometry2.setAttribute( name, newAttribute );\n\n\t\t}\n\n\t\t// morph attributes\n\n\t\tconst morphAttributes = this.morphAttributes;\n\n\t\tfor ( const name in morphAttributes ) {\n\n\t\t\tconst morphArray = [];\n\t\t\tconst morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes\n\n\t\t\tfor ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {\n\n\t\t\t\tconst attribute = morphAttribute[ i ];\n\n\t\t\t\tconst newAttribute = convertBufferAttribute( attribute, indices );\n\n\t\t\t\tmorphArray.push( newAttribute );\n\n\t\t\t}\n\n\t\t\tgeometry2.morphAttributes[ name ] = morphArray;\n\n\t\t}\n\n\t\tgeometry2.morphTargetsRelative = this.morphTargetsRelative;\n\n\t\t// groups\n\n\t\tconst groups = this.groups;\n\n\t\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\tconst group = groups[ i ];\n\t\t\tgeometry2.addGroup( group.start, group.count, group.materialIndex );\n\n\t\t}\n\n\t\treturn geometry2;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'BufferGeometry',\n\t\t\t\tgenerator: 'BufferGeometry.toJSON'\n\t\t\t}\n\t\t};\n\n\t\t// standard BufferGeometry serialization\n\n\t\tdata.uuid = this.uuid;\n\t\tdata.type = this.type;\n\t\tif ( this.name !== '' ) data.name = this.name;\n\t\tif ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;\n\n\t\tif ( this.parameters !== undefined ) {\n\n\t\t\tconst parameters = this.parameters;\n\n\t\t\tfor ( const key in parameters ) {\n\n\t\t\t\tif ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\t// for simplicity the code assumes attributes are not shared across geometries, see #15811\n\n\t\tdata.data = { attributes: {} };\n\n\t\tconst index = this.index;\n\n\t\tif ( index !== null ) {\n\n\t\t\tdata.data.index = {\n\t\t\t\ttype: index.array.constructor.name,\n\t\t\t\tarray: Array.prototype.slice.call( index.array )\n\t\t\t};\n\n\t\t}\n\n\t\tconst attributes = this.attributes;\n\n\t\tfor ( const key in attributes ) {\n\n\t\t\tconst attribute = attributes[ key ];\n\n\t\t\tdata.data.attributes[ key ] = attribute.toJSON( data.data );\n\n\t\t}\n\n\t\tconst morphAttributes = {};\n\t\tlet hasMorphAttributes = false;\n\n\t\tfor ( const key in this.morphAttributes ) {\n\n\t\t\tconst attributeArray = this.morphAttributes[ key ];\n\n\t\t\tconst array = [];\n\n\t\t\tfor ( let i = 0, il = attributeArray.length; i < il; i ++ ) {\n\n\t\t\t\tconst attribute = attributeArray[ i ];\n\n\t\t\t\tarray.push( attribute.toJSON( data.data ) );\n\n\t\t\t}\n\n\t\t\tif ( array.length > 0 ) {\n\n\t\t\t\tmorphAttributes[ key ] = array;\n\n\t\t\t\thasMorphAttributes = true;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( hasMorphAttributes ) {\n\n\t\t\tdata.data.morphAttributes = morphAttributes;\n\t\t\tdata.data.morphTargetsRelative = this.morphTargetsRelative;\n\n\t\t}\n\n\t\tconst groups = this.groups;\n\n\t\tif ( groups.length > 0 ) {\n\n\t\t\tdata.data.groups = JSON.parse( JSON.stringify( groups ) );\n\n\t\t}\n\n\t\tconst boundingSphere = this.boundingSphere;\n\n\t\tif ( boundingSphere !== null ) {\n\n\t\t\tdata.data.boundingSphere = {\n\t\t\t\tcenter: boundingSphere.center.toArray(),\n\t\t\t\tradius: boundingSphere.radius\n\t\t\t};\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( source ) {\n\n\t\t// reset\n\n\t\tthis.index = null;\n\t\tthis.attributes = {};\n\t\tthis.morphAttributes = {};\n\t\tthis.groups = [];\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t\t// used for storing cloned, shared data\n\n\t\tconst data = {};\n\n\t\t// name\n\n\t\tthis.name = source.name;\n\n\t\t// index\n\n\t\tconst index = source.index;\n\n\t\tif ( index !== null ) {\n\n\t\t\tthis.setIndex( index.clone( data ) );\n\n\t\t}\n\n\t\t// attributes\n\n\t\tconst attributes = source.attributes;\n\n\t\tfor ( const name in attributes ) {\n\n\t\t\tconst attribute = attributes[ name ];\n\t\t\tthis.setAttribute( name, attribute.clone( data ) );\n\n\t\t}\n\n\t\t// morph attributes\n\n\t\tconst morphAttributes = source.morphAttributes;\n\n\t\tfor ( const name in morphAttributes ) {\n\n\t\t\tconst array = [];\n\t\t\tconst morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes\n\n\t\t\tfor ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {\n\n\t\t\t\tarray.push( morphAttribute[ i ].clone( data ) );\n\n\t\t\t}\n\n\t\t\tthis.morphAttributes[ name ] = array;\n\n\t\t}\n\n\t\tthis.morphTargetsRelative = source.morphTargetsRelative;\n\n\t\t// groups\n\n\t\tconst groups = source.groups;\n\n\t\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\tconst group = groups[ i ];\n\t\t\tthis.addGroup( group.start, group.count, group.materialIndex );\n\n\t\t}\n\n\t\t// bounding box\n\n\t\tconst boundingBox = source.boundingBox;\n\n\t\tif ( boundingBox !== null ) {\n\n\t\t\tthis.boundingBox = boundingBox.clone();\n\n\t\t}\n\n\t\t// bounding sphere\n\n\t\tconst boundingSphere = source.boundingSphere;\n\n\t\tif ( boundingSphere !== null ) {\n\n\t\t\tthis.boundingSphere = boundingSphere.clone();\n\n\t\t}\n\n\t\t// draw range\n\n\t\tthis.drawRange.start = source.drawRange.start;\n\t\tthis.drawRange.count = source.drawRange.count;\n\n\t\t// user data\n\n\t\tthis.userData = source.userData;\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n}\n\nconst _inverseMatrix$3 = /*@__PURE__*/ new Matrix4();\nconst _ray$3 = /*@__PURE__*/ new Ray();\nconst _sphere$6 = /*@__PURE__*/ new Sphere();\nconst _sphereHitAt = /*@__PURE__*/ new Vector3();\n\nconst _vA$1 = /*@__PURE__*/ new Vector3();\nconst _vB$1 = /*@__PURE__*/ new Vector3();\nconst _vC$1 = /*@__PURE__*/ new Vector3();\n\nconst _tempA = /*@__PURE__*/ new Vector3();\nconst _morphA = /*@__PURE__*/ new Vector3();\n\nconst _uvA$1 = /*@__PURE__*/ new Vector2();\nconst _uvB$1 = /*@__PURE__*/ new Vector2();\nconst _uvC$1 = /*@__PURE__*/ new Vector2();\n\nconst _normalA = /*@__PURE__*/ new Vector3();\nconst _normalB = /*@__PURE__*/ new Vector3();\nconst _normalC = /*@__PURE__*/ new Vector3();\n\nconst _intersectionPoint = /*@__PURE__*/ new Vector3();\nconst _intersectionPointWorld = /*@__PURE__*/ new Vector3();\n\nclass Mesh extends Object3D {\n\n\tconstructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) {\n\n\t\tsuper();\n\n\t\tthis.isMesh = true;\n\n\t\tthis.type = 'Mesh';\n\n\t\tthis.geometry = geometry;\n\t\tthis.material = material;\n\n\t\tthis.updateMorphTargets();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tif ( source.morphTargetInfluences !== undefined ) {\n\n\t\t\tthis.morphTargetInfluences = source.morphTargetInfluences.slice();\n\n\t\t}\n\n\t\tif ( source.morphTargetDictionary !== undefined ) {\n\n\t\t\tthis.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );\n\n\t\t}\n\n\t\tthis.material = Array.isArray( source.material ) ? source.material.slice() : source.material;\n\t\tthis.geometry = source.geometry;\n\n\t\treturn this;\n\n\t}\n\n\tupdateMorphTargets() {\n\n\t\tconst geometry = this.geometry;\n\n\t\tconst morphAttributes = geometry.morphAttributes;\n\t\tconst keys = Object.keys( morphAttributes );\n\n\t\tif ( keys.length > 0 ) {\n\n\t\t\tconst morphAttribute = morphAttributes[ keys[ 0 ] ];\n\n\t\t\tif ( morphAttribute !== undefined ) {\n\n\t\t\t\tthis.morphTargetInfluences = [];\n\t\t\t\tthis.morphTargetDictionary = {};\n\n\t\t\t\tfor ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {\n\n\t\t\t\t\tconst name = morphAttribute[ m ].name || String( m );\n\n\t\t\t\t\tthis.morphTargetInfluences.push( 0 );\n\t\t\t\t\tthis.morphTargetDictionary[ name ] = m;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tgetVertexPosition( index, target ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst position = geometry.attributes.position;\n\t\tconst morphPosition = geometry.morphAttributes.position;\n\t\tconst morphTargetsRelative = geometry.morphTargetsRelative;\n\n\t\ttarget.fromBufferAttribute( position, index );\n\n\t\tconst morphInfluences = this.morphTargetInfluences;\n\n\t\tif ( morphPosition && morphInfluences ) {\n\n\t\t\t_morphA.set( 0, 0, 0 );\n\n\t\t\tfor ( let i = 0, il = morphPosition.length; i < il; i ++ ) {\n\n\t\t\t\tconst influence = morphInfluences[ i ];\n\t\t\t\tconst morphAttribute = morphPosition[ i ];\n\n\t\t\t\tif ( influence === 0 ) continue;\n\n\t\t\t\t_tempA.fromBufferAttribute( morphAttribute, index );\n\n\t\t\t\tif ( morphTargetsRelative ) {\n\n\t\t\t\t\t_morphA.addScaledVector( _tempA, influence );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_morphA.addScaledVector( _tempA.sub( target ), influence );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\ttarget.add( _morphA );\n\n\t\t}\n\n\t\treturn target;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst material = this.material;\n\t\tconst matrixWorld = this.matrixWorld;\n\n\t\tif ( material === undefined ) return;\n\n\t\t// test with bounding sphere in world space\n\n\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t_sphere$6.copy( geometry.boundingSphere );\n\t\t_sphere$6.applyMatrix4( matrixWorld );\n\n\t\t// check distance from ray origin to bounding sphere\n\n\t\t_ray$3.copy( raycaster.ray ).recast( raycaster.near );\n\n\t\tif ( _sphere$6.containsPoint( _ray$3.origin ) === false ) {\n\n\t\t\tif ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return;\n\n\t\t\tif ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return;\n\n\t\t}\n\n\t\t// convert ray to local space of mesh\n\n\t\t_inverseMatrix$3.copy( matrixWorld ).invert();\n\t\t_ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 );\n\n\t\t// test with bounding box in local space\n\n\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\tif ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return;\n\n\t\t}\n\n\t\t// test for intersections with geometry\n\n\t\tthis._computeIntersections( raycaster, intersects, _ray$3 );\n\n\t}\n\n\t_computeIntersections( raycaster, intersects, rayLocalSpace ) {\n\n\t\tlet intersection;\n\n\t\tconst geometry = this.geometry;\n\t\tconst material = this.material;\n\n\t\tconst index = geometry.index;\n\t\tconst position = geometry.attributes.position;\n\t\tconst uv = geometry.attributes.uv;\n\t\tconst uv1 = geometry.attributes.uv1;\n\t\tconst normal = geometry.attributes.normal;\n\t\tconst groups = geometry.groups;\n\t\tconst drawRange = geometry.drawRange;\n\n\t\tif ( index !== null ) {\n\n\t\t\t// indexed buffer geometry\n\n\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\tfor ( let i = 0, il = groups.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst group = groups[ i ];\n\t\t\t\t\tconst groupMaterial = material[ group.materialIndex ];\n\n\t\t\t\t\tconst start = Math.max( group.start, drawRange.start );\n\t\t\t\t\tconst end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );\n\n\t\t\t\t\tfor ( let j = start, jl = end; j < jl; j += 3 ) {\n\n\t\t\t\t\t\tconst a = index.getX( j );\n\t\t\t\t\t\tconst b = index.getX( j + 1 );\n\t\t\t\t\t\tconst c = index.getX( j + 2 );\n\n\t\t\t\t\t\tintersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );\n\n\t\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\t\tintersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics\n\t\t\t\t\t\t\tintersection.face.materialIndex = group.materialIndex;\n\t\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\t\tconst end = Math.min( index.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\t\tfor ( let i = start, il = end; i < il; i += 3 ) {\n\n\t\t\t\t\tconst a = index.getX( i );\n\t\t\t\t\tconst b = index.getX( i + 1 );\n\t\t\t\t\tconst c = index.getX( i + 2 );\n\n\t\t\t\t\tintersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );\n\n\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\tintersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics\n\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else if ( position !== undefined ) {\n\n\t\t\t// non-indexed buffer geometry\n\n\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\tfor ( let i = 0, il = groups.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst group = groups[ i ];\n\t\t\t\t\tconst groupMaterial = material[ group.materialIndex ];\n\n\t\t\t\t\tconst start = Math.max( group.start, drawRange.start );\n\t\t\t\t\tconst end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );\n\n\t\t\t\t\tfor ( let j = start, jl = end; j < jl; j += 3 ) {\n\n\t\t\t\t\t\tconst a = j;\n\t\t\t\t\t\tconst b = j + 1;\n\t\t\t\t\t\tconst c = j + 2;\n\n\t\t\t\t\t\tintersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );\n\n\t\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\t\tintersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics\n\t\t\t\t\t\t\tintersection.face.materialIndex = group.materialIndex;\n\t\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\t\tconst end = Math.min( position.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\t\tfor ( let i = start, il = end; i < il; i += 3 ) {\n\n\t\t\t\t\tconst a = i;\n\t\t\t\t\tconst b = i + 1;\n\t\t\t\t\tconst c = i + 2;\n\n\t\t\t\t\tintersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );\n\n\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\tintersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics\n\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nfunction checkIntersection$1( object, material, raycaster, ray, pA, pB, pC, point ) {\n\n\tlet intersect;\n\n\tif ( material.side === BackSide ) {\n\n\t\tintersect = ray.intersectTriangle( pC, pB, pA, true, point );\n\n\t} else {\n\n\t\tintersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point );\n\n\t}\n\n\tif ( intersect === null ) return null;\n\n\t_intersectionPointWorld.copy( point );\n\t_intersectionPointWorld.applyMatrix4( object.matrixWorld );\n\n\tconst distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );\n\n\tif ( distance < raycaster.near || distance > raycaster.far ) return null;\n\n\treturn {\n\t\tdistance: distance,\n\t\tpoint: _intersectionPointWorld.clone(),\n\t\tobject: object\n\t};\n\n}\n\nfunction checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) {\n\n\tobject.getVertexPosition( a, _vA$1 );\n\tobject.getVertexPosition( b, _vB$1 );\n\tobject.getVertexPosition( c, _vC$1 );\n\n\tconst intersection = checkIntersection$1( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint );\n\n\tif ( intersection ) {\n\n\t\tif ( uv ) {\n\n\t\t\t_uvA$1.fromBufferAttribute( uv, a );\n\t\t\t_uvB$1.fromBufferAttribute( uv, b );\n\t\t\t_uvC$1.fromBufferAttribute( uv, c );\n\n\t\t\tintersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );\n\n\t\t}\n\n\t\tif ( uv1 ) {\n\n\t\t\t_uvA$1.fromBufferAttribute( uv1, a );\n\t\t\t_uvB$1.fromBufferAttribute( uv1, b );\n\t\t\t_uvC$1.fromBufferAttribute( uv1, c );\n\n\t\t\tintersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );\n\n\t\t}\n\n\t\tif ( normal ) {\n\n\t\t\t_normalA.fromBufferAttribute( normal, a );\n\t\t\t_normalB.fromBufferAttribute( normal, b );\n\t\t\t_normalC.fromBufferAttribute( normal, c );\n\n\t\t\tintersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() );\n\n\t\t\tif ( intersection.normal.dot( ray.direction ) > 0 ) {\n\n\t\t\t\tintersection.normal.multiplyScalar( - 1 );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst face = {\n\t\t\ta: a,\n\t\t\tb: b,\n\t\t\tc: c,\n\t\t\tnormal: new Vector3(),\n\t\t\tmaterialIndex: 0\n\t\t};\n\n\t\tTriangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal );\n\n\t\tintersection.face = face;\n\n\t}\n\n\treturn intersection;\n\n}\n\nclass BoxGeometry extends BufferGeometry {\n\n\tconstructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'BoxGeometry';\n\n\t\tthis.parameters = {\n\t\t\twidth: width,\n\t\t\theight: height,\n\t\t\tdepth: depth,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\tdepthSegments: depthSegments\n\t\t};\n\n\t\tconst scope = this;\n\n\t\t// segments\n\n\t\twidthSegments = Math.floor( widthSegments );\n\t\theightSegments = Math.floor( heightSegments );\n\t\tdepthSegments = Math.floor( depthSegments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tlet numberOfVertices = 0;\n\t\tlet groupStart = 0;\n\n\t\t// build each side of the box geometry\n\n\t\tbuildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px\n\t\tbuildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx\n\t\tbuildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py\n\t\tbuildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny\n\t\tbuildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz\n\t\tbuildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\tfunction buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {\n\n\t\t\tconst segmentWidth = width / gridX;\n\t\t\tconst segmentHeight = height / gridY;\n\n\t\t\tconst widthHalf = width / 2;\n\t\t\tconst heightHalf = height / 2;\n\t\t\tconst depthHalf = depth / 2;\n\n\t\t\tconst gridX1 = gridX + 1;\n\t\t\tconst gridY1 = gridY + 1;\n\n\t\t\tlet vertexCounter = 0;\n\t\t\tlet groupCount = 0;\n\n\t\t\tconst vector = new Vector3();\n\n\t\t\t// generate vertices, normals and uvs\n\n\t\t\tfor ( let iy = 0; iy < gridY1; iy ++ ) {\n\n\t\t\t\tconst y = iy * segmentHeight - heightHalf;\n\n\t\t\t\tfor ( let ix = 0; ix < gridX1; ix ++ ) {\n\n\t\t\t\t\tconst x = ix * segmentWidth - widthHalf;\n\n\t\t\t\t\t// set values to correct vector component\n\n\t\t\t\t\tvector[ u ] = x * udir;\n\t\t\t\t\tvector[ v ] = y * vdir;\n\t\t\t\t\tvector[ w ] = depthHalf;\n\n\t\t\t\t\t// now apply vector to vertex buffer\n\n\t\t\t\t\tvertices.push( vector.x, vector.y, vector.z );\n\n\t\t\t\t\t// set values to correct vector component\n\n\t\t\t\t\tvector[ u ] = 0;\n\t\t\t\t\tvector[ v ] = 0;\n\t\t\t\t\tvector[ w ] = depth > 0 ? 1 : - 1;\n\n\t\t\t\t\t// now apply vector to normal buffer\n\n\t\t\t\t\tnormals.push( vector.x, vector.y, vector.z );\n\n\t\t\t\t\t// uvs\n\n\t\t\t\t\tuvs.push( ix / gridX );\n\t\t\t\t\tuvs.push( 1 - ( iy / gridY ) );\n\n\t\t\t\t\t// counters\n\n\t\t\t\t\tvertexCounter += 1;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// indices\n\n\t\t\t// 1. you need three indices to draw a single face\n\t\t\t// 2. a single segment consists of two faces\n\t\t\t// 3. so we need to generate six (2*3) indices per segment\n\n\t\t\tfor ( let iy = 0; iy < gridY; iy ++ ) {\n\n\t\t\t\tfor ( let ix = 0; ix < gridX; ix ++ ) {\n\n\t\t\t\t\tconst a = numberOfVertices + ix + gridX1 * iy;\n\t\t\t\t\tconst b = numberOfVertices + ix + gridX1 * ( iy + 1 );\n\t\t\t\t\tconst c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );\n\t\t\t\t\tconst d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;\n\n\t\t\t\t\t// faces\n\n\t\t\t\t\tindices.push( a, b, d );\n\t\t\t\t\tindices.push( b, c, d );\n\n\t\t\t\t\t// increase counter\n\n\t\t\t\t\tgroupCount += 6;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\t\tscope.addGroup( groupStart, groupCount, materialIndex );\n\n\t\t\t// calculate new start value for groups\n\n\t\t\tgroupStart += groupCount;\n\n\t\t\t// update total number of vertices\n\n\t\t\tnumberOfVertices += vertexCounter;\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments );\n\n\t}\n\n}\n\n/**\n * Uniform Utilities\n */\n\nfunction cloneUniforms( src ) {\n\n\tconst dst = {};\n\n\tfor ( const u in src ) {\n\n\t\tdst[ u ] = {};\n\n\t\tfor ( const p in src[ u ] ) {\n\n\t\t\tconst property = src[ u ][ p ];\n\n\t\t\tif ( property && ( property.isColor ||\n\t\t\t\tproperty.isMatrix3 || property.isMatrix4 ||\n\t\t\t\tproperty.isVector2 || property.isVector3 || property.isVector4 ||\n\t\t\t\tproperty.isTexture || property.isQuaternion ) ) {\n\n\t\t\t\tif ( property.isRenderTargetTexture ) {\n\n\t\t\t\t\tconsole.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' );\n\t\t\t\t\tdst[ u ][ p ] = null;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tdst[ u ][ p ] = property.clone();\n\n\t\t\t\t}\n\n\t\t\t} else if ( Array.isArray( property ) ) {\n\n\t\t\t\tdst[ u ][ p ] = property.slice();\n\n\t\t\t} else {\n\n\t\t\t\tdst[ u ][ p ] = property;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn dst;\n\n}\n\nfunction mergeUniforms( uniforms ) {\n\n\tconst merged = {};\n\n\tfor ( let u = 0; u < uniforms.length; u ++ ) {\n\n\t\tconst tmp = cloneUniforms( uniforms[ u ] );\n\n\t\tfor ( const p in tmp ) {\n\n\t\t\tmerged[ p ] = tmp[ p ];\n\n\t\t}\n\n\t}\n\n\treturn merged;\n\n}\n\nfunction cloneUniformsGroups( src ) {\n\n\tconst dst = [];\n\n\tfor ( let u = 0; u < src.length; u ++ ) {\n\n\t\tdst.push( src[ u ].clone() );\n\n\t}\n\n\treturn dst;\n\n}\n\nfunction getUnlitUniformColorSpace( renderer ) {\n\n\tconst currentRenderTarget = renderer.getRenderTarget();\n\n\tif ( currentRenderTarget === null ) {\n\n\t\t// https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398\n\t\treturn renderer.outputColorSpace;\n\n\t}\n\n\t// https://github.com/mrdoob/three.js/issues/27868\n\tif ( currentRenderTarget.isXRRenderTarget === true ) {\n\n\t\treturn currentRenderTarget.texture.colorSpace;\n\n\t}\n\n\treturn ColorManagement.workingColorSpace;\n\n}\n\n// Legacy\n\nconst UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms };\n\nvar default_vertex = \"void main() {\\n\\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\\n}\";\n\nvar default_fragment = \"void main() {\\n\\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\\n}\";\n\nclass ShaderMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isShaderMaterial = true;\n\n\t\tthis.type = 'ShaderMaterial';\n\n\t\tthis.defines = {};\n\t\tthis.uniforms = {};\n\t\tthis.uniformsGroups = [];\n\n\t\tthis.vertexShader = default_vertex;\n\t\tthis.fragmentShader = default_fragment;\n\n\t\tthis.linewidth = 1;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\n\t\tthis.fog = false; // set to use scene fog\n\t\tthis.lights = false; // set to use scene lights\n\t\tthis.clipping = false; // set to use user-defined clipping planes\n\n\t\tthis.forceSinglePass = true;\n\n\t\tthis.extensions = {\n\t\t\tclipCullDistance: false, // set to use vertex shader clipping\n\t\t\tmultiDraw: false // set to use vertex shader multi_draw / enable gl_DrawID\n\t\t};\n\n\t\t// When rendered geometry doesn't include these attributes but the material does,\n\t\t// use these default values in WebGL. This avoids errors when buffer data is missing.\n\t\tthis.defaultAttributeValues = {\n\t\t\t'color': [ 1, 1, 1 ],\n\t\t\t'uv': [ 0, 0 ],\n\t\t\t'uv1': [ 0, 0 ]\n\t\t};\n\n\t\tthis.index0AttributeName = undefined;\n\t\tthis.uniformsNeedUpdate = false;\n\n\t\tthis.glslVersion = null;\n\n\t\tif ( parameters !== undefined ) {\n\n\t\t\tthis.setValues( parameters );\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.fragmentShader = source.fragmentShader;\n\t\tthis.vertexShader = source.vertexShader;\n\n\t\tthis.uniforms = cloneUniforms( source.uniforms );\n\t\tthis.uniformsGroups = cloneUniformsGroups( source.uniformsGroups );\n\n\t\tthis.defines = Object.assign( {}, source.defines );\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\t\tthis.fog = source.fog;\n\t\tthis.lights = source.lights;\n\t\tthis.clipping = source.clipping;\n\n\t\tthis.extensions = Object.assign( {}, source.extensions );\n\n\t\tthis.glslVersion = source.glslVersion;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.glslVersion = this.glslVersion;\n\t\tdata.uniforms = {};\n\n\t\tfor ( const name in this.uniforms ) {\n\n\t\t\tconst uniform = this.uniforms[ name ];\n\t\t\tconst value = uniform.value;\n\n\t\t\tif ( value && value.isTexture ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 't',\n\t\t\t\t\tvalue: value.toJSON( meta ).uuid\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isColor ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'c',\n\t\t\t\t\tvalue: value.getHex()\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isVector2 ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'v2',\n\t\t\t\t\tvalue: value.toArray()\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isVector3 ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'v3',\n\t\t\t\t\tvalue: value.toArray()\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isVector4 ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'v4',\n\t\t\t\t\tvalue: value.toArray()\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isMatrix3 ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'm3',\n\t\t\t\t\tvalue: value.toArray()\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isMatrix4 ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'm4',\n\t\t\t\t\tvalue: value.toArray()\n\t\t\t\t};\n\n\t\t\t} else {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\tvalue: value\n\t\t\t\t};\n\n\t\t\t\t// note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;\n\n\t\tdata.vertexShader = this.vertexShader;\n\t\tdata.fragmentShader = this.fragmentShader;\n\n\t\tdata.lights = this.lights;\n\t\tdata.clipping = this.clipping;\n\n\t\tconst extensions = {};\n\n\t\tfor ( const key in this.extensions ) {\n\n\t\t\tif ( this.extensions[ key ] === true ) extensions[ key ] = true;\n\n\t\t}\n\n\t\tif ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass Camera extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isCamera = true;\n\n\t\tthis.type = 'Camera';\n\n\t\tthis.matrixWorldInverse = new Matrix4();\n\n\t\tthis.projectionMatrix = new Matrix4();\n\t\tthis.projectionMatrixInverse = new Matrix4();\n\n\t\tthis.coordinateSystem = WebGLCoordinateSystem;\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.matrixWorldInverse.copy( source.matrixWorldInverse );\n\n\t\tthis.projectionMatrix.copy( source.projectionMatrix );\n\t\tthis.projectionMatrixInverse.copy( source.projectionMatrixInverse );\n\n\t\tthis.coordinateSystem = source.coordinateSystem;\n\n\t\treturn this;\n\n\t}\n\n\tgetWorldDirection( target ) {\n\n\t\treturn super.getWorldDirection( target ).negate();\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t\tthis.matrixWorldInverse.copy( this.matrixWorld ).invert();\n\n\t}\n\n\tupdateWorldMatrix( updateParents, updateChildren ) {\n\n\t\tsuper.updateWorldMatrix( updateParents, updateChildren );\n\n\t\tthis.matrixWorldInverse.copy( this.matrixWorld ).invert();\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nconst _v3$1 = /*@__PURE__*/ new Vector3();\nconst _minTarget = /*@__PURE__*/ new Vector2();\nconst _maxTarget = /*@__PURE__*/ new Vector2();\n\n\nclass PerspectiveCamera extends Camera {\n\n\tconstructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) {\n\n\t\tsuper();\n\n\t\tthis.isPerspectiveCamera = true;\n\n\t\tthis.type = 'PerspectiveCamera';\n\n\t\tthis.fov = fov;\n\t\tthis.zoom = 1;\n\n\t\tthis.near = near;\n\t\tthis.far = far;\n\t\tthis.focus = 10;\n\n\t\tthis.aspect = aspect;\n\t\tthis.view = null;\n\n\t\tthis.filmGauge = 35;\t// width of the film (default in millimeters)\n\t\tthis.filmOffset = 0;\t// horizontal film offset (same unit as gauge)\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.fov = source.fov;\n\t\tthis.zoom = source.zoom;\n\n\t\tthis.near = source.near;\n\t\tthis.far = source.far;\n\t\tthis.focus = source.focus;\n\n\t\tthis.aspect = source.aspect;\n\t\tthis.view = source.view === null ? null : Object.assign( {}, source.view );\n\n\t\tthis.filmGauge = source.filmGauge;\n\t\tthis.filmOffset = source.filmOffset;\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Sets the FOV by focal length in respect to the current .filmGauge.\n\t *\n\t * The default film gauge is 35, so that the focal length can be specified for\n\t * a 35mm (full frame) camera.\n\t *\n\t * Values for focal length and film gauge must have the same unit.\n\t */\n\tsetFocalLength( focalLength ) {\n\n\t\t/** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */\n\t\tconst vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;\n\n\t\tthis.fov = RAD2DEG * 2 * Math.atan( vExtentSlope );\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\t/**\n\t * Calculates the focal length from the current .fov and .filmGauge.\n\t */\n\tgetFocalLength() {\n\n\t\tconst vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov );\n\n\t\treturn 0.5 * this.getFilmHeight() / vExtentSlope;\n\n\t}\n\n\tgetEffectiveFOV() {\n\n\t\treturn RAD2DEG * 2 * Math.atan(\n\t\t\tMath.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom );\n\n\t}\n\n\tgetFilmWidth() {\n\n\t\t// film not completely covered in portrait format (aspect < 1)\n\t\treturn this.filmGauge * Math.min( this.aspect, 1 );\n\n\t}\n\n\tgetFilmHeight() {\n\n\t\t// film not completely covered in landscape format (aspect > 1)\n\t\treturn this.filmGauge / Math.max( this.aspect, 1 );\n\n\t}\n\n\t/**\n\t * Computes the 2D bounds of the camera's viewable rectangle at a given distance along the viewing direction.\n\t * Sets minTarget and maxTarget to the coordinates of the lower-left and upper-right corners of the view rectangle.\n\t */\n\tgetViewBounds( distance, minTarget, maxTarget ) {\n\n\t\t_v3$1.set( - 1, - 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse );\n\n\t\tminTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z );\n\n\t\t_v3$1.set( 1, 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse );\n\n\t\tmaxTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z );\n\n\t}\n\n\t/**\n\t * Computes the width and height of the camera's viewable rectangle at a given distance along the viewing direction.\n\t * Copies the result into the target Vector2, where x is width and y is height.\n\t */\n\tgetViewSize( distance, target ) {\n\n\t\tthis.getViewBounds( distance, _minTarget, _maxTarget );\n\n\t\treturn target.subVectors( _maxTarget, _minTarget );\n\n\t}\n\n\t/**\n\t * Sets an offset in a larger frustum. This is useful for multi-window or\n\t * multi-monitor/multi-machine setups.\n\t *\n\t * For example, if you have 3x2 monitors and each monitor is 1920x1080 and\n\t * the monitors are in grid like this\n\t *\n\t * +---+---+---+\n\t * | A | B | C |\n\t * +---+---+---+\n\t * | D | E | F |\n\t * +---+---+---+\n\t *\n\t * then for each monitor you would call it like this\n\t *\n\t * const w = 1920;\n\t * const h = 1080;\n\t * const fullWidth = w * 3;\n\t * const fullHeight = h * 2;\n\t *\n\t * --A--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );\n\t * --B--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );\n\t * --C--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );\n\t * --D--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );\n\t * --E--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );\n\t * --F--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );\n\t *\n\t * Note there is no reason monitors have to be the same size or in a grid.\n\t */\n\tsetViewOffset( fullWidth, fullHeight, x, y, width, height ) {\n\n\t\tthis.aspect = fullWidth / fullHeight;\n\n\t\tif ( this.view === null ) {\n\n\t\t\tthis.view = {\n\t\t\t\tenabled: true,\n\t\t\t\tfullWidth: 1,\n\t\t\t\tfullHeight: 1,\n\t\t\t\toffsetX: 0,\n\t\t\t\toffsetY: 0,\n\t\t\t\twidth: 1,\n\t\t\t\theight: 1\n\t\t\t};\n\n\t\t}\n\n\t\tthis.view.enabled = true;\n\t\tthis.view.fullWidth = fullWidth;\n\t\tthis.view.fullHeight = fullHeight;\n\t\tthis.view.offsetX = x;\n\t\tthis.view.offsetY = y;\n\t\tthis.view.width = width;\n\t\tthis.view.height = height;\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tclearViewOffset() {\n\n\t\tif ( this.view !== null ) {\n\n\t\t\tthis.view.enabled = false;\n\n\t\t}\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tupdateProjectionMatrix() {\n\n\t\tconst near = this.near;\n\t\tlet top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom;\n\t\tlet height = 2 * top;\n\t\tlet width = this.aspect * height;\n\t\tlet left = - 0.5 * width;\n\t\tconst view = this.view;\n\n\t\tif ( this.view !== null && this.view.enabled ) {\n\n\t\t\tconst fullWidth = view.fullWidth,\n\t\t\t\tfullHeight = view.fullHeight;\n\n\t\t\tleft += view.offsetX * width / fullWidth;\n\t\t\ttop -= view.offsetY * height / fullHeight;\n\t\t\twidth *= view.width / fullWidth;\n\t\t\theight *= view.height / fullHeight;\n\n\t\t}\n\n\t\tconst skew = this.filmOffset;\n\t\tif ( skew !== 0 ) left += near * skew / this.getFilmWidth();\n\n\t\tthis.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem );\n\n\t\tthis.projectionMatrixInverse.copy( this.projectionMatrix ).invert();\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.object.fov = this.fov;\n\t\tdata.object.zoom = this.zoom;\n\n\t\tdata.object.near = this.near;\n\t\tdata.object.far = this.far;\n\t\tdata.object.focus = this.focus;\n\n\t\tdata.object.aspect = this.aspect;\n\n\t\tif ( this.view !== null ) data.object.view = Object.assign( {}, this.view );\n\n\t\tdata.object.filmGauge = this.filmGauge;\n\t\tdata.object.filmOffset = this.filmOffset;\n\n\t\treturn data;\n\n\t}\n\n}\n\nconst fov = - 90; // negative fov is not an error\nconst aspect = 1;\n\nclass CubeCamera extends Object3D {\n\n\tconstructor( near, far, renderTarget ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'CubeCamera';\n\n\t\tthis.renderTarget = renderTarget;\n\t\tthis.coordinateSystem = null;\n\t\tthis.activeMipmapLevel = 0;\n\n\t\tconst cameraPX = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraPX.layers = this.layers;\n\t\tthis.add( cameraPX );\n\n\t\tconst cameraNX = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraNX.layers = this.layers;\n\t\tthis.add( cameraNX );\n\n\t\tconst cameraPY = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraPY.layers = this.layers;\n\t\tthis.add( cameraPY );\n\n\t\tconst cameraNY = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraNY.layers = this.layers;\n\t\tthis.add( cameraNY );\n\n\t\tconst cameraPZ = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraPZ.layers = this.layers;\n\t\tthis.add( cameraPZ );\n\n\t\tconst cameraNZ = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraNZ.layers = this.layers;\n\t\tthis.add( cameraNZ );\n\n\t}\n\n\tupdateCoordinateSystem() {\n\n\t\tconst coordinateSystem = this.coordinateSystem;\n\n\t\tconst cameras = this.children.concat();\n\n\t\tconst [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras;\n\n\t\tfor ( const camera of cameras ) this.remove( camera );\n\n\t\tif ( coordinateSystem === WebGLCoordinateSystem ) {\n\n\t\t\tcameraPX.up.set( 0, 1, 0 );\n\t\t\tcameraPX.lookAt( 1, 0, 0 );\n\n\t\t\tcameraNX.up.set( 0, 1, 0 );\n\t\t\tcameraNX.lookAt( - 1, 0, 0 );\n\n\t\t\tcameraPY.up.set( 0, 0, - 1 );\n\t\t\tcameraPY.lookAt( 0, 1, 0 );\n\n\t\t\tcameraNY.up.set( 0, 0, 1 );\n\t\t\tcameraNY.lookAt( 0, - 1, 0 );\n\n\t\t\tcameraPZ.up.set( 0, 1, 0 );\n\t\t\tcameraPZ.lookAt( 0, 0, 1 );\n\n\t\t\tcameraNZ.up.set( 0, 1, 0 );\n\t\t\tcameraNZ.lookAt( 0, 0, - 1 );\n\n\t\t} else if ( coordinateSystem === WebGPUCoordinateSystem ) {\n\n\t\t\tcameraPX.up.set( 0, - 1, 0 );\n\t\t\tcameraPX.lookAt( - 1, 0, 0 );\n\n\t\t\tcameraNX.up.set( 0, - 1, 0 );\n\t\t\tcameraNX.lookAt( 1, 0, 0 );\n\n\t\t\tcameraPY.up.set( 0, 0, 1 );\n\t\t\tcameraPY.lookAt( 0, 1, 0 );\n\n\t\t\tcameraNY.up.set( 0, 0, - 1 );\n\t\t\tcameraNY.lookAt( 0, - 1, 0 );\n\n\t\t\tcameraPZ.up.set( 0, - 1, 0 );\n\t\t\tcameraPZ.lookAt( 0, 0, 1 );\n\n\t\t\tcameraNZ.up.set( 0, - 1, 0 );\n\t\t\tcameraNZ.lookAt( 0, 0, - 1 );\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem );\n\n\t\t}\n\n\t\tfor ( const camera of cameras ) {\n\n\t\t\tthis.add( camera );\n\n\t\t\tcamera.updateMatrixWorld();\n\n\t\t}\n\n\t}\n\n\tupdate( renderer, scene ) {\n\n\t\tif ( this.parent === null ) this.updateMatrixWorld();\n\n\t\tconst { renderTarget, activeMipmapLevel } = this;\n\n\t\tif ( this.coordinateSystem !== renderer.coordinateSystem ) {\n\n\t\t\tthis.coordinateSystem = renderer.coordinateSystem;\n\n\t\t\tthis.updateCoordinateSystem();\n\n\t\t}\n\n\t\tconst [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children;\n\n\t\tconst currentRenderTarget = renderer.getRenderTarget();\n\t\tconst currentActiveCubeFace = renderer.getActiveCubeFace();\n\t\tconst currentActiveMipmapLevel = renderer.getActiveMipmapLevel();\n\n\t\tconst currentXrEnabled = renderer.xr.enabled;\n\n\t\trenderer.xr.enabled = false;\n\n\t\tconst generateMipmaps = renderTarget.texture.generateMipmaps;\n\n\t\trenderTarget.texture.generateMipmaps = false;\n\n\t\trenderer.setRenderTarget( renderTarget, 0, activeMipmapLevel );\n\t\trenderer.render( scene, cameraPX );\n\n\t\trenderer.setRenderTarget( renderTarget, 1, activeMipmapLevel );\n\t\trenderer.render( scene, cameraNX );\n\n\t\trenderer.setRenderTarget( renderTarget, 2, activeMipmapLevel );\n\t\trenderer.render( scene, cameraPY );\n\n\t\trenderer.setRenderTarget( renderTarget, 3, activeMipmapLevel );\n\t\trenderer.render( scene, cameraNY );\n\n\t\trenderer.setRenderTarget( renderTarget, 4, activeMipmapLevel );\n\t\trenderer.render( scene, cameraPZ );\n\n\t\t// mipmaps are generated during the last call of render()\n\t\t// at this point, all sides of the cube render target are defined\n\n\t\trenderTarget.texture.generateMipmaps = generateMipmaps;\n\n\t\trenderer.setRenderTarget( renderTarget, 5, activeMipmapLevel );\n\t\trenderer.render( scene, cameraNZ );\n\n\t\trenderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel );\n\n\t\trenderer.xr.enabled = currentXrEnabled;\n\n\t\trenderTarget.texture.needsPMREMUpdate = true;\n\n\t}\n\n}\n\nclass CubeTexture extends Texture {\n\n\tconstructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) {\n\n\t\timages = images !== undefined ? images : [];\n\t\tmapping = mapping !== undefined ? mapping : CubeReflectionMapping;\n\n\t\tsuper( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );\n\n\t\tthis.isCubeTexture = true;\n\n\t\tthis.flipY = false;\n\n\t}\n\n\tget images() {\n\n\t\treturn this.image;\n\n\t}\n\n\tset images( value ) {\n\n\t\tthis.image = value;\n\n\t}\n\n}\n\nclass WebGLCubeRenderTarget extends WebGLRenderTarget {\n\n\tconstructor( size = 1, options = {} ) {\n\n\t\tsuper( size, size, options );\n\n\t\tthis.isWebGLCubeRenderTarget = true;\n\n\t\tconst image = { width: size, height: size, depth: 1 };\n\t\tconst images = [ image, image, image, image, image, image ];\n\n\t\tthis.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace );\n\n\t\t// By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)\n\t\t// in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,\n\t\t// in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.\n\n\t\t// three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped\n\t\t// and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture\n\t\t// as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures).\n\n\t\tthis.texture.isRenderTargetTexture = true;\n\n\t\tthis.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;\n\t\tthis.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;\n\n\t}\n\n\tfromEquirectangularTexture( renderer, texture ) {\n\n\t\tthis.texture.type = texture.type;\n\t\tthis.texture.colorSpace = texture.colorSpace;\n\n\t\tthis.texture.generateMipmaps = texture.generateMipmaps;\n\t\tthis.texture.minFilter = texture.minFilter;\n\t\tthis.texture.magFilter = texture.magFilter;\n\n\t\tconst shader = {\n\n\t\t\tuniforms: {\n\t\t\t\ttEquirect: { value: null },\n\t\t\t},\n\n\t\t\tvertexShader: /* glsl */`\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`,\n\n\t\t\tfragmentShader: /* glsl */`\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`\n\t\t};\n\n\t\tconst geometry = new BoxGeometry( 5, 5, 5 );\n\n\t\tconst material = new ShaderMaterial( {\n\n\t\t\tname: 'CubemapFromEquirect',\n\n\t\t\tuniforms: cloneUniforms( shader.uniforms ),\n\t\t\tvertexShader: shader.vertexShader,\n\t\t\tfragmentShader: shader.fragmentShader,\n\t\t\tside: BackSide,\n\t\t\tblending: NoBlending\n\n\t\t} );\n\n\t\tmaterial.uniforms.tEquirect.value = texture;\n\n\t\tconst mesh = new Mesh( geometry, material );\n\n\t\tconst currentMinFilter = texture.minFilter;\n\n\t\t// Avoid blurred poles\n\t\tif ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;\n\n\t\tconst camera = new CubeCamera( 1, 10, this );\n\t\tcamera.update( renderer, mesh );\n\n\t\ttexture.minFilter = currentMinFilter;\n\n\t\tmesh.geometry.dispose();\n\t\tmesh.material.dispose();\n\n\t\treturn this;\n\n\t}\n\n\tclear( renderer, color, depth, stencil ) {\n\n\t\tconst currentRenderTarget = renderer.getRenderTarget();\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\trenderer.setRenderTarget( this, i );\n\n\t\t\trenderer.clear( color, depth, stencil );\n\n\t\t}\n\n\t\trenderer.setRenderTarget( currentRenderTarget );\n\n\t}\n\n}\n\nconst _vector1 = /*@__PURE__*/ new Vector3();\nconst _vector2 = /*@__PURE__*/ new Vector3();\nconst _normalMatrix = /*@__PURE__*/ new Matrix3();\n\nclass Plane {\n\n\tconstructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) {\n\n\t\tthis.isPlane = true;\n\n\t\t// normal is assumed to be normalized\n\n\t\tthis.normal = normal;\n\t\tthis.constant = constant;\n\n\t}\n\n\tset( normal, constant ) {\n\n\t\tthis.normal.copy( normal );\n\t\tthis.constant = constant;\n\n\t\treturn this;\n\n\t}\n\n\tsetComponents( x, y, z, w ) {\n\n\t\tthis.normal.set( x, y, z );\n\t\tthis.constant = w;\n\n\t\treturn this;\n\n\t}\n\n\tsetFromNormalAndCoplanarPoint( normal, point ) {\n\n\t\tthis.normal.copy( normal );\n\t\tthis.constant = - point.dot( this.normal );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromCoplanarPoints( a, b, c ) {\n\n\t\tconst normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize();\n\n\t\t// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?\n\n\t\tthis.setFromNormalAndCoplanarPoint( normal, a );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( plane ) {\n\n\t\tthis.normal.copy( plane.normal );\n\t\tthis.constant = plane.constant;\n\n\t\treturn this;\n\n\t}\n\n\tnormalize() {\n\n\t\t// Note: will lead to a divide by zero if the plane is invalid.\n\n\t\tconst inverseNormalLength = 1.0 / this.normal.length();\n\t\tthis.normal.multiplyScalar( inverseNormalLength );\n\t\tthis.constant *= inverseNormalLength;\n\n\t\treturn this;\n\n\t}\n\n\tnegate() {\n\n\t\tthis.constant *= - 1;\n\t\tthis.normal.negate();\n\n\t\treturn this;\n\n\t}\n\n\tdistanceToPoint( point ) {\n\n\t\treturn this.normal.dot( point ) + this.constant;\n\n\t}\n\n\tdistanceToSphere( sphere ) {\n\n\t\treturn this.distanceToPoint( sphere.center ) - sphere.radius;\n\n\t}\n\n\tprojectPoint( point, target ) {\n\n\t\treturn target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) );\n\n\t}\n\n\tintersectLine( line, target ) {\n\n\t\tconst direction = line.delta( _vector1 );\n\n\t\tconst denominator = this.normal.dot( direction );\n\n\t\tif ( denominator === 0 ) {\n\n\t\t\t// line is coplanar, return origin\n\t\t\tif ( this.distanceToPoint( line.start ) === 0 ) {\n\n\t\t\t\treturn target.copy( line.start );\n\n\t\t\t}\n\n\t\t\t// Unsure if this is the correct method to handle this case.\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;\n\n\t\tif ( t < 0 || t > 1 ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\treturn target.copy( line.start ).addScaledVector( direction, t );\n\n\t}\n\n\tintersectsLine( line ) {\n\n\t\t// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.\n\n\t\tconst startSign = this.distanceToPoint( line.start );\n\t\tconst endSign = this.distanceToPoint( line.end );\n\n\t\treturn ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\treturn box.intersectsPlane( this );\n\n\t}\n\n\tintersectsSphere( sphere ) {\n\n\t\treturn sphere.intersectsPlane( this );\n\n\t}\n\n\tcoplanarPoint( target ) {\n\n\t\treturn target.copy( this.normal ).multiplyScalar( - this.constant );\n\n\t}\n\n\tapplyMatrix4( matrix, optionalNormalMatrix ) {\n\n\t\tconst normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix );\n\n\t\tconst referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix );\n\n\t\tconst normal = this.normal.applyMatrix3( normalMatrix ).normalize();\n\n\t\tthis.constant = - referencePoint.dot( normal );\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( offset ) {\n\n\t\tthis.constant -= offset.dot( this.normal );\n\n\t\treturn this;\n\n\t}\n\n\tequals( plane ) {\n\n\t\treturn plane.normal.equals( this.normal ) && ( plane.constant === this.constant );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nconst _sphere$5 = /*@__PURE__*/ new Sphere();\nconst _vector$7 = /*@__PURE__*/ new Vector3();\n\nclass Frustum {\n\n\tconstructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) {\n\n\t\tthis.planes = [ p0, p1, p2, p3, p4, p5 ];\n\n\t}\n\n\tset( p0, p1, p2, p3, p4, p5 ) {\n\n\t\tconst planes = this.planes;\n\n\t\tplanes[ 0 ].copy( p0 );\n\t\tplanes[ 1 ].copy( p1 );\n\t\tplanes[ 2 ].copy( p2 );\n\t\tplanes[ 3 ].copy( p3 );\n\t\tplanes[ 4 ].copy( p4 );\n\t\tplanes[ 5 ].copy( p5 );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( frustum ) {\n\n\t\tconst planes = this.planes;\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\tplanes[ i ].copy( frustum.planes[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) {\n\n\t\tconst planes = this.planes;\n\t\tconst me = m.elements;\n\t\tconst me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];\n\t\tconst me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];\n\t\tconst me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];\n\t\tconst me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];\n\n\t\tplanes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();\n\t\tplanes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();\n\t\tplanes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();\n\t\tplanes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();\n\t\tplanes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();\n\n\t\tif ( coordinateSystem === WebGLCoordinateSystem ) {\n\n\t\t\tplanes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();\n\n\t\t} else if ( coordinateSystem === WebGPUCoordinateSystem ) {\n\n\t\t\tplanes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize();\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tintersectsObject( object ) {\n\n\t\tif ( object.boundingSphere !== undefined ) {\n\n\t\t\tif ( object.boundingSphere === null ) object.computeBoundingSphere();\n\n\t\t\t_sphere$5.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld );\n\n\t\t} else {\n\n\t\t\tconst geometry = object.geometry;\n\n\t\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t\t_sphere$5.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );\n\n\t\t}\n\n\t\treturn this.intersectsSphere( _sphere$5 );\n\n\t}\n\n\tintersectsSprite( sprite ) {\n\n\t\t_sphere$5.center.set( 0, 0, 0 );\n\t\t_sphere$5.radius = 0.7071067811865476;\n\t\t_sphere$5.applyMatrix4( sprite.matrixWorld );\n\n\t\treturn this.intersectsSphere( _sphere$5 );\n\n\t}\n\n\tintersectsSphere( sphere ) {\n\n\t\tconst planes = this.planes;\n\t\tconst center = sphere.center;\n\t\tconst negRadius = - sphere.radius;\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\tconst distance = planes[ i ].distanceToPoint( center );\n\n\t\t\tif ( distance < negRadius ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\tconst planes = this.planes;\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\tconst plane = planes[ i ];\n\n\t\t\t// corner at max distance\n\n\t\t\t_vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x;\n\t\t\t_vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y;\n\t\t\t_vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z;\n\n\t\t\tif ( plane.distanceToPoint( _vector$7 ) < 0 ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tcontainsPoint( point ) {\n\n\t\tconst planes = this.planes;\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\tif ( planes[ i ].distanceToPoint( point ) < 0 ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nfunction WebGLAnimation() {\n\n\tlet context = null;\n\tlet isAnimating = false;\n\tlet animationLoop = null;\n\tlet requestId = null;\n\n\tfunction onAnimationFrame( time, frame ) {\n\n\t\tanimationLoop( time, frame );\n\n\t\trequestId = context.requestAnimationFrame( onAnimationFrame );\n\n\t}\n\n\treturn {\n\n\t\tstart: function () {\n\n\t\t\tif ( isAnimating === true ) return;\n\t\t\tif ( animationLoop === null ) return;\n\n\t\t\trequestId = context.requestAnimationFrame( onAnimationFrame );\n\n\t\t\tisAnimating = true;\n\n\t\t},\n\n\t\tstop: function () {\n\n\t\t\tcontext.cancelAnimationFrame( requestId );\n\n\t\t\tisAnimating = false;\n\n\t\t},\n\n\t\tsetAnimationLoop: function ( callback ) {\n\n\t\t\tanimationLoop = callback;\n\n\t\t},\n\n\t\tsetContext: function ( value ) {\n\n\t\t\tcontext = value;\n\n\t\t}\n\n\t};\n\n}\n\nfunction WebGLAttributes( gl ) {\n\n\tconst buffers = new WeakMap();\n\n\tfunction createBuffer( attribute, bufferType ) {\n\n\t\tconst array = attribute.array;\n\t\tconst usage = attribute.usage;\n\t\tconst size = array.byteLength;\n\n\t\tconst buffer = gl.createBuffer();\n\n\t\tgl.bindBuffer( bufferType, buffer );\n\t\tgl.bufferData( bufferType, array, usage );\n\n\t\tattribute.onUploadCallback();\n\n\t\tlet type;\n\n\t\tif ( array instanceof Float32Array ) {\n\n\t\t\ttype = gl.FLOAT;\n\n\t\t} else if ( array instanceof Uint16Array ) {\n\n\t\t\tif ( attribute.isFloat16BufferAttribute ) {\n\n\t\t\t\ttype = gl.HALF_FLOAT;\n\n\t\t\t} else {\n\n\t\t\t\ttype = gl.UNSIGNED_SHORT;\n\n\t\t\t}\n\n\t\t} else if ( array instanceof Int16Array ) {\n\n\t\t\ttype = gl.SHORT;\n\n\t\t} else if ( array instanceof Uint32Array ) {\n\n\t\t\ttype = gl.UNSIGNED_INT;\n\n\t\t} else if ( array instanceof Int32Array ) {\n\n\t\t\ttype = gl.INT;\n\n\t\t} else if ( array instanceof Int8Array ) {\n\n\t\t\ttype = gl.BYTE;\n\n\t\t} else if ( array instanceof Uint8Array ) {\n\n\t\t\ttype = gl.UNSIGNED_BYTE;\n\n\t\t} else if ( array instanceof Uint8ClampedArray ) {\n\n\t\t\ttype = gl.UNSIGNED_BYTE;\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array );\n\n\t\t}\n\n\t\treturn {\n\t\t\tbuffer: buffer,\n\t\t\ttype: type,\n\t\t\tbytesPerElement: array.BYTES_PER_ELEMENT,\n\t\t\tversion: attribute.version,\n\t\t\tsize: size\n\t\t};\n\n\t}\n\n\tfunction updateBuffer( buffer, attribute, bufferType ) {\n\n\t\tconst array = attribute.array;\n\t\tconst updateRange = attribute._updateRange; // @deprecated, r159\n\t\tconst updateRanges = attribute.updateRanges;\n\n\t\tgl.bindBuffer( bufferType, buffer );\n\n\t\tif ( updateRange.count === - 1 && updateRanges.length === 0 ) {\n\n\t\t\t// Not using update ranges\n\t\t\tgl.bufferSubData( bufferType, 0, array );\n\n\t\t}\n\n\t\tif ( updateRanges.length !== 0 ) {\n\n\t\t\tfor ( let i = 0, l = updateRanges.length; i < l; i ++ ) {\n\n\t\t\t\tconst range = updateRanges[ i ];\n\n\t\t\t\tgl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,\n\t\t\t\t\tarray, range.start, range.count );\n\n\t\t\t}\n\n\t\t\tattribute.clearUpdateRanges();\n\n\t\t}\n\n\t\t// @deprecated, r159\n\t\tif ( updateRange.count !== - 1 ) {\n\n\t\t\tgl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,\n\t\t\t\tarray, updateRange.offset, updateRange.count );\n\n\t\t\tupdateRange.count = - 1; // reset range\n\n\t\t}\n\n\t\tattribute.onUploadCallback();\n\n\t}\n\n\t//\n\n\tfunction get( attribute ) {\n\n\t\tif ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;\n\n\t\treturn buffers.get( attribute );\n\n\t}\n\n\tfunction remove( attribute ) {\n\n\t\tif ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;\n\n\t\tconst data = buffers.get( attribute );\n\n\t\tif ( data ) {\n\n\t\t\tgl.deleteBuffer( data.buffer );\n\n\t\t\tbuffers.delete( attribute );\n\n\t\t}\n\n\t}\n\n\tfunction update( attribute, bufferType ) {\n\n\t\tif ( attribute.isGLBufferAttribute ) {\n\n\t\t\tconst cached = buffers.get( attribute );\n\n\t\t\tif ( ! cached || cached.version < attribute.version ) {\n\n\t\t\t\tbuffers.set( attribute, {\n\t\t\t\t\tbuffer: attribute.buffer,\n\t\t\t\t\ttype: attribute.type,\n\t\t\t\t\tbytesPerElement: attribute.elementSize,\n\t\t\t\t\tversion: attribute.version\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;\n\n\t\tconst data = buffers.get( attribute );\n\n\t\tif ( data === undefined ) {\n\n\t\t\tbuffers.set( attribute, createBuffer( attribute, bufferType ) );\n\n\t\t} else if ( data.version < attribute.version ) {\n\n\t\t\tif ( data.size !== attribute.array.byteLength ) {\n\n\t\t\t\tthrow 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.' );\n\n\t\t\t}\n\n\t\t\tupdateBuffer( data.buffer, attribute, bufferType );\n\n\t\t\tdata.version = attribute.version;\n\n\t\t}\n\n\t}\n\n\treturn {\n\n\t\tget: get,\n\t\tremove: remove,\n\t\tupdate: update\n\n\t};\n\n}\n\nclass PlaneGeometry extends BufferGeometry {\n\n\tconstructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'PlaneGeometry';\n\n\t\tthis.parameters = {\n\t\t\twidth: width,\n\t\t\theight: height,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments\n\t\t};\n\n\t\tconst width_half = width / 2;\n\t\tconst height_half = height / 2;\n\n\t\tconst gridX = Math.floor( widthSegments );\n\t\tconst gridY = Math.floor( heightSegments );\n\n\t\tconst gridX1 = gridX + 1;\n\t\tconst gridY1 = gridY + 1;\n\n\t\tconst segment_width = width / gridX;\n\t\tconst segment_height = height / gridY;\n\n\t\t//\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\tfor ( let iy = 0; iy < gridY1; iy ++ ) {\n\n\t\t\tconst y = iy * segment_height - height_half;\n\n\t\t\tfor ( let ix = 0; ix < gridX1; ix ++ ) {\n\n\t\t\t\tconst x = ix * segment_width - width_half;\n\n\t\t\t\tvertices.push( x, - y, 0 );\n\n\t\t\t\tnormals.push( 0, 0, 1 );\n\n\t\t\t\tuvs.push( ix / gridX );\n\t\t\t\tuvs.push( 1 - ( iy / gridY ) );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( let iy = 0; iy < gridY; iy ++ ) {\n\n\t\t\tfor ( let ix = 0; ix < gridX; ix ++ ) {\n\n\t\t\t\tconst a = ix + gridX1 * iy;\n\t\t\t\tconst b = ix + gridX1 * ( iy + 1 );\n\t\t\t\tconst c = ( ix + 1 ) + gridX1 * ( iy + 1 );\n\t\t\t\tconst d = ( ix + 1 ) + gridX1 * iy;\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments );\n\n\t}\n\n}\n\nvar alphahash_fragment = \"#ifdef USE_ALPHAHASH\\n\\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\\n#endif\";\n\nvar 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\";\n\nvar alphamap_fragment = \"#ifdef USE_ALPHAMAP\\n\\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\\n#endif\";\n\nvar alphamap_pars_fragment = \"#ifdef USE_ALPHAMAP\\n\\tuniform sampler2D alphaMap;\\n#endif\";\n\nvar 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\";\n\nvar alphatest_pars_fragment = \"#ifdef USE_ALPHATEST\\n\\tuniform float alphaTest;\\n#endif\";\n\nvar 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\";\n\nvar aomap_pars_fragment = \"#ifdef USE_AOMAP\\n\\tuniform sampler2D aoMap;\\n\\tuniform float aoMapIntensity;\\n#endif\";\n\nvar batching_pars_vertex = \"#ifdef USE_BATCHING\\n\\t#if ! defined( GL_ANGLE_multi_draw )\\n\\t#define gl_DrawID _gl_DrawID\\n\\tuniform int _gl_DrawID;\\n\\t#endif\\n\\tuniform highp sampler2D batchingTexture;\\n\\tuniform highp usampler2D batchingIdTexture;\\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\\tfloat getIndirectIndex( const in int i ) {\\n\\t\\tint size = textureSize( batchingIdTexture, 0 ).x;\\n\\t\\tint x = i % size;\\n\\t\\tint y = i / size;\\n\\t\\treturn float( texelFetch( batchingIdTexture, ivec2( x, y ), 0 ).r );\\n\\t}\\n#endif\\n#ifdef USE_BATCHING_COLOR\\n\\tuniform sampler2D batchingColorTexture;\\n\\tvec3 getBatchingColor( const in float i ) {\\n\\t\\tint size = textureSize( batchingColorTexture, 0 ).x;\\n\\t\\tint j = int( i );\\n\\t\\tint x = j % size;\\n\\t\\tint y = j / size;\\n\\t\\treturn texelFetch( batchingColorTexture, ivec2( x, y ), 0 ).rgb;\\n\\t}\\n#endif\";\n\nvar batching_vertex = \"#ifdef USE_BATCHING\\n\\tmat4 batchingMatrix = getBatchingMatrix( getIndirectIndex( gl_DrawID ) );\\n#endif\";\n\nvar begin_vertex = \"vec3 transformed = vec3( position );\\n#ifdef USE_ALPHAHASH\\n\\tvPosition = vec3( position );\\n#endif\";\n\nvar beginnormal_vertex = \"vec3 objectNormal = vec3( normal );\\n#ifdef USE_TANGENT\\n\\tvec3 objectTangent = vec3( tangent.xyz );\\n#endif\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar clipping_planes_pars_fragment = \"#if NUM_CLIPPING_PLANES > 0\\n\\tvarying vec3 vClipPosition;\\n\\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\\n#endif\";\n\nvar clipping_planes_pars_vertex = \"#if NUM_CLIPPING_PLANES > 0\\n\\tvarying vec3 vClipPosition;\\n#endif\";\n\nvar clipping_planes_vertex = \"#if NUM_CLIPPING_PLANES > 0\\n\\tvClipPosition = - mvPosition.xyz;\\n#endif\";\n\nvar color_fragment = \"#if defined( USE_COLOR_ALPHA )\\n\\tdiffuseColor *= vColor;\\n#elif defined( USE_COLOR )\\n\\tdiffuseColor.rgb *= vColor;\\n#endif\";\n\nvar color_pars_fragment = \"#if defined( USE_COLOR_ALPHA )\\n\\tvarying vec4 vColor;\\n#elif defined( USE_COLOR )\\n\\tvarying vec3 vColor;\\n#endif\";\n\nvar color_pars_vertex = \"#if defined( USE_COLOR_ALPHA )\\n\\tvarying vec4 vColor;\\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )\\n\\tvarying vec3 vColor;\\n#endif\";\n\nvar color_vertex = \"#if defined( USE_COLOR_ALPHA )\\n\\tvColor = vec4( 1.0 );\\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_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\\n#ifdef USE_BATCHING_COLOR\\n\\tvec3 batchingColor = getBatchingColor( getIndirectIndex( gl_DrawID ) );\\n\\tvColor.xyz *= batchingColor.xyz;\\n#endif\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar displacementmap_pars_vertex = \"#ifdef USE_DISPLACEMENTMAP\\n\\tuniform sampler2D displacementMap;\\n\\tuniform float displacementScale;\\n\\tuniform float displacementBias;\\n#endif\";\n\nvar displacementmap_vertex = \"#ifdef USE_DISPLACEMENTMAP\\n\\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\\n#endif\";\n\nvar emissivemap_fragment = \"#ifdef USE_EMISSIVEMAP\\n\\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\\n\\ttotalEmissiveRadiance *= emissiveColor.rgb;\\n#endif\";\n\nvar emissivemap_pars_fragment = \"#ifdef USE_EMISSIVEMAP\\n\\tuniform sampler2D emissiveMap;\\n#endif\";\n\nvar colorspace_fragment = \"gl_FragColor = linearToOutputTexel( gl_FragColor );\";\n\nvar 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}\";\n\nvar 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, envMapRotation * 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\";\n\nvar envmap_common_pars_fragment = \"#ifdef USE_ENVMAP\\n\\tuniform float envMapIntensity;\\n\\tuniform float flipEnvMap;\\n\\tuniform mat3 envMapRotation;\\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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar fog_vertex = \"#ifdef USE_FOG\\n\\tvFogDepth = - mvPosition.z;\\n#endif\";\n\nvar fog_pars_vertex = \"#ifdef USE_FOG\\n\\tvarying float vFogDepth;\\n#endif\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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}\";\n\nvar lightmap_pars_fragment = \"#ifdef USE_LIGHTMAP\\n\\tuniform sampler2D lightMap;\\n\\tuniform float lightMapIntensity;\\n#endif\";\n\nvar lights_lambert_fragment = \"LambertMaterial material;\\nmaterial.diffuseColor = diffuseColor.rgb;\\nmaterial.specularStrength = specularStrength;\";\n\nvar 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\";\n\nvar 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\\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\\n\\tif ( cutoffDistance > 0.0 ) {\\n\\t\\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\\n\\t}\\n\\treturn distanceFalloff;\\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\";\n\nvar 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, envMapRotation * 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, envMapRotation * 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\";\n\nvar lights_toon_fragment = \"ToonMaterial material;\\nmaterial.diffuseColor = diffuseColor.rgb;\";\n\nvar 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\";\n\nvar lights_phong_fragment = \"BlinnPhongMaterial material;\\nmaterial.diffuseColor = diffuseColor.rgb;\\nmaterial.specularColor = specular;\\nmaterial.specularShininess = shininess;\\nmaterial.specularStrength = specularStrength;\";\n\nvar 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\";\n\nvar 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_DISPERSION\\n\\tmaterial.dispersion = dispersion;\\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\";\n\nvar lights_physical_pars_fragment = \"struct PhysicalMaterial {\\n\\tvec3 diffuseColor;\\n\\tfloat roughness;\\n\\tvec3 specularColor;\\n\\tfloat specularF90;\\n\\tfloat dispersion;\\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}\";\n\nvar 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.shadowIntensity, 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.shadowIntensity, 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.shadowIntensity, 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar logdepthbuf_fragment = \"#if defined( USE_LOGDEPTHBUF )\\n\\tgl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\\n#endif\";\n\nvar logdepthbuf_pars_fragment = \"#if defined( USE_LOGDEPTHBUF )\\n\\tuniform float logDepthBufFC;\\n\\tvarying float vFragDepth;\\n\\tvarying float vIsPerspective;\\n#endif\";\n\nvar logdepthbuf_pars_vertex = \"#ifdef USE_LOGDEPTHBUF\\n\\tvarying float vFragDepth;\\n\\tvarying float vIsPerspective;\\n#endif\";\n\nvar logdepthbuf_vertex = \"#ifdef USE_LOGDEPTHBUF\\n\\tvFragDepth = 1.0 + gl_Position.w;\\n\\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\\n#endif\";\n\nvar 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\";\n\nvar map_pars_fragment = \"#ifdef USE_MAP\\n\\tuniform sampler2D map;\\n#endif\";\n\nvar 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\";\n\nvar 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\";\n\nvar metalnessmap_fragment = \"float metalnessFactor = metalness;\\n#ifdef USE_METALNESSMAP\\n\\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\\n\\tmetalnessFactor *= texelMetalness.b;\\n#endif\";\n\nvar metalnessmap_pars_fragment = \"#ifdef USE_METALNESSMAP\\n\\tuniform sampler2D metalnessMap;\\n#endif\";\n\nvar morphinstance_vertex = \"#ifdef USE_INSTANCING_MORPH\\n\\tfloat morphTargetInfluences[ MORPHTARGETS_COUNT ];\\n\\tfloat morphTargetBaseInfluence = texelFetch( morphTexture, ivec2( 0, gl_InstanceID ), 0 ).r;\\n\\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\\n\\t\\tmorphTargetInfluences[i] = texelFetch( morphTexture, ivec2( i + 1, gl_InstanceID ), 0 ).r;\\n\\t}\\n#endif\";\n\nvar morphcolor_vertex = \"#if defined( USE_MORPHCOLORS )\\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\";\n\nvar morphnormal_vertex = \"#ifdef USE_MORPHNORMALS\\n\\tobjectNormal *= morphTargetBaseInfluence;\\n\\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\\n\\t\\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\\n\\t}\\n#endif\";\n\nvar morphtarget_pars_vertex = \"#ifdef USE_MORPHTARGETS\\n\\t#ifndef USE_INSTANCING_MORPH\\n\\t\\tuniform float morphTargetBaseInfluence;\\n\\t\\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\\n\\t#endif\\n\\tuniform sampler2DArray morphTargetsTexture;\\n\\tuniform ivec2 morphTargetsTextureSize;\\n\\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\\n\\t\\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\\n\\t\\tint y = texelIndex / morphTargetsTextureSize.x;\\n\\t\\tint x = texelIndex - y * morphTargetsTextureSize.x;\\n\\t\\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\\n\\t\\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\\n\\t}\\n#endif\";\n\nvar morphtarget_vertex = \"#ifdef USE_MORPHTARGETS\\n\\ttransformed *= morphTargetBaseInfluence;\\n\\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\\n\\t\\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\\n\\t}\\n#endif\";\n\nvar 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;\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar clearcoat_normal_fragment_begin = \"#ifdef USE_CLEARCOAT\\n\\tvec3 clearcoatNormal = nonPerturbedNormal;\\n#endif\";\n\nvar 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\";\n\nvar 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\";\n\nvar iridescence_pars_fragment = \"#ifdef USE_IRIDESCENCEMAP\\n\\tuniform sampler2D iridescenceMap;\\n#endif\\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\\n\\tuniform sampler2D iridescenceThicknessMap;\\n#endif\";\n\nvar 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 );\";\n\nvar 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}\";\n\nvar premultiplied_alpha_fragment = \"#ifdef PREMULTIPLIED_ALPHA\\n\\tgl_FragColor.rgb *= gl_FragColor.a;\\n#endif\";\n\nvar 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;\";\n\nvar dithering_fragment = \"#ifdef DITHERING\\n\\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\\n#endif\";\n\nvar 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\";\n\nvar roughnessmap_fragment = \"float roughnessFactor = roughness;\\n#ifdef USE_ROUGHNESSMAP\\n\\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\\n\\troughnessFactor *= texelRoughness.g;\\n#endif\";\n\nvar roughnessmap_pars_fragment = \"#ifdef USE_ROUGHNESSMAP\\n\\tuniform sampler2D roughnessMap;\\n#endif\";\n\nvar 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 shadowIntensity;\\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 shadowIntensity;\\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 shadowIntensity;\\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 shadowIntensity, 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 mix( 1.0, shadow, shadowIntensity );\\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 shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\\n\\t\\tfloat shadow = 1.0;\\n\\t\\tvec3 lightToPosition = shadowCoord.xyz;\\n\\t\\t\\n\\t\\tfloat lightToPositionLength = length( lightToPosition );\\n\\t\\tif ( lightToPositionLength - shadowCameraFar <= 0.0 && lightToPositionLength - shadowCameraNear >= 0.0 ) {\\n\\t\\t\\tfloat dp = ( lightToPositionLength - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\\t\\t\\tdp += shadowBias;\\n\\t\\t\\tvec3 bd3D = normalize( lightToPosition );\\n\\t\\t\\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\\n\\t\\t\\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\\n\\t\\t\\t\\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\\n\\t\\t\\t\\tshadow = (\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\\n\\t\\t\\t\\t) * ( 1.0 / 9.0 );\\n\\t\\t\\t#else\\n\\t\\t\\t\\tshadow = texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\\n\\t\\t\\t#endif\\n\\t\\t}\\n\\t\\treturn mix( 1.0, shadow, shadowIntensity );\\n\\t}\\n#endif\";\n\nvar 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 shadowIntensity;\\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 shadowIntensity;\\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 shadowIntensity;\\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\";\n\nvar 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\";\n\nvar 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.shadowIntensity, 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.shadowIntensity, 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.shadowIntensity, 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}\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar specularmap_pars_fragment = \"#ifdef USE_SPECULARMAP\\n\\tuniform sampler2D specularMap;\\n#endif\";\n\nvar tonemapping_fragment = \"#if defined( TONE_MAPPING )\\n\\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\\n#endif\";\n\nvar 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 NeutralToneMapping( vec3 color ) {\\n\\tconst float StartCompression = 0.8 - 0.04;\\n\\tconst float Desaturation = 0.15;\\n\\tcolor *= toneMappingExposure;\\n\\tfloat x = min( color.r, min( color.g, color.b ) );\\n\\tfloat offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\\n\\tcolor -= offset;\\n\\tfloat peak = max( color.r, max( color.g, color.b ) );\\n\\tif ( peak < StartCompression ) return color;\\n\\tfloat d = 1. - StartCompression;\\n\\tfloat newPeak = 1. - d * d / ( peak + d - StartCompression );\\n\\tcolor *= newPeak / peak;\\n\\tfloat g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. );\\n\\treturn mix( color, vec3( newPeak ), g );\\n}\\nvec3 CustomToneMapping( vec3 color ) { return color; }\";\n\nvar 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.dispersion, 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\";\n\nvar 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 dispersion, const in float ior, const in float thickness,\\n\\t\\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\\n\\t\\tvec4 transmittedLight;\\n\\t\\tvec3 transmittance;\\n\\t\\t#ifdef USE_DISPERSION\\n\\t\\t\\tfloat halfSpread = ( ior - 1.0 ) * 0.025 * dispersion;\\n\\t\\t\\tvec3 iors = vec3( ior - halfSpread, ior, ior + halfSpread );\\n\\t\\t\\tfor ( int i = 0; i < 3; i ++ ) {\\n\\t\\t\\t\\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, iors[ i ], modelMatrix );\\n\\t\\t\\t\\tvec3 refractedRayExit = position + transmissionRay;\\n\\t\\t\\n\\t\\t\\t\\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\\n\\t\\t\\t\\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\\n\\t\\t\\t\\trefractionCoords += 1.0;\\n\\t\\t\\t\\trefractionCoords /= 2.0;\\n\\t\\t\\n\\t\\t\\t\\tvec4 transmissionSample = getTransmissionSample( refractionCoords, roughness, iors[ i ] );\\n\\t\\t\\t\\ttransmittedLight[ i ] = transmissionSample[ i ];\\n\\t\\t\\t\\ttransmittedLight.a += transmissionSample.a;\\n\\t\\t\\t\\ttransmittance[ i ] = diffuseColor[ i ] * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance )[ i ];\\n\\t\\t\\t}\\n\\t\\t\\ttransmittedLight.a /= 3.0;\\n\\t\\t\\n\\t\\t#else\\n\\t\\t\\n\\t\\t\\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\\n\\t\\t\\tvec3 refractedRayExit = position + transmissionRay;\\n\\t\\t\\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\\n\\t\\t\\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\\n\\t\\t\\trefractionCoords += 1.0;\\n\\t\\t\\trefractionCoords /= 2.0;\\n\\t\\t\\ttransmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\\n\\t\\t\\ttransmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\\n\\t\\t\\n\\t\\t#endif\\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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nconst 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}\";\n\nconst 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}\";\n\nconst 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}\";\n\nconst 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;\\nuniform mat3 backgroundRotation;\\nvarying vec3 vWorldDirection;\\n#include \\nvoid main() {\\n\\t#ifdef ENVMAP_TYPE_CUBE\\n\\t\\tvec4 texColor = textureCube( envMap, backgroundRotation * vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\\n\\t#elif defined( ENVMAP_TYPE_CUBE_UV )\\n\\t\\tvec4 texColor = textureCubeUV( envMap, backgroundRotation * 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}\";\n\nconst 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}\";\n\nconst 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}\";\n\nconst 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#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}\";\n\nconst 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}\";\n\nconst 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#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}\";\n\nconst 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}\";\n\nconst vertex$c = \"varying vec3 vWorldDirection;\\n#include \\nvoid main() {\\n\\tvWorldDirection = transformDirection( position, modelMatrix );\\n\\t#include \\n\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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#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}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n\\tvViewPosition = - mvPosition.xyz;\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n\\tvViewPosition = - mvPosition.xyz;\\n}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\\n\\tvViewPosition = - mvPosition.xyz;\\n#endif\\n}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n\\tvViewPosition = - mvPosition.xyz;\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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\\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}\";\n\nconst 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_DISPERSION\\n\\tuniform float dispersion;\\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}\";\n\nconst 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\\t#include \\n\\tvViewPosition = - mvPosition.xyz;\\n\\t#include \\n\\t#include \\n\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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\\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}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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}\";\n\nconst 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}\";\n\nconst ShaderChunk = {\n\talphahash_fragment: alphahash_fragment,\n\talphahash_pars_fragment: alphahash_pars_fragment,\n\talphamap_fragment: alphamap_fragment,\n\talphamap_pars_fragment: alphamap_pars_fragment,\n\talphatest_fragment: alphatest_fragment,\n\talphatest_pars_fragment: alphatest_pars_fragment,\n\taomap_fragment: aomap_fragment,\n\taomap_pars_fragment: aomap_pars_fragment,\n\tbatching_pars_vertex: batching_pars_vertex,\n\tbatching_vertex: batching_vertex,\n\tbegin_vertex: begin_vertex,\n\tbeginnormal_vertex: beginnormal_vertex,\n\tbsdfs: bsdfs,\n\tiridescence_fragment: iridescence_fragment,\n\tbumpmap_pars_fragment: bumpmap_pars_fragment,\n\tclipping_planes_fragment: clipping_planes_fragment,\n\tclipping_planes_pars_fragment: clipping_planes_pars_fragment,\n\tclipping_planes_pars_vertex: clipping_planes_pars_vertex,\n\tclipping_planes_vertex: clipping_planes_vertex,\n\tcolor_fragment: color_fragment,\n\tcolor_pars_fragment: color_pars_fragment,\n\tcolor_pars_vertex: color_pars_vertex,\n\tcolor_vertex: color_vertex,\n\tcommon: common,\n\tcube_uv_reflection_fragment: cube_uv_reflection_fragment,\n\tdefaultnormal_vertex: defaultnormal_vertex,\n\tdisplacementmap_pars_vertex: displacementmap_pars_vertex,\n\tdisplacementmap_vertex: displacementmap_vertex,\n\temissivemap_fragment: emissivemap_fragment,\n\temissivemap_pars_fragment: emissivemap_pars_fragment,\n\tcolorspace_fragment: colorspace_fragment,\n\tcolorspace_pars_fragment: colorspace_pars_fragment,\n\tenvmap_fragment: envmap_fragment,\n\tenvmap_common_pars_fragment: envmap_common_pars_fragment,\n\tenvmap_pars_fragment: envmap_pars_fragment,\n\tenvmap_pars_vertex: envmap_pars_vertex,\n\tenvmap_physical_pars_fragment: envmap_physical_pars_fragment,\n\tenvmap_vertex: envmap_vertex,\n\tfog_vertex: fog_vertex,\n\tfog_pars_vertex: fog_pars_vertex,\n\tfog_fragment: fog_fragment,\n\tfog_pars_fragment: fog_pars_fragment,\n\tgradientmap_pars_fragment: gradientmap_pars_fragment,\n\tlightmap_pars_fragment: lightmap_pars_fragment,\n\tlights_lambert_fragment: lights_lambert_fragment,\n\tlights_lambert_pars_fragment: lights_lambert_pars_fragment,\n\tlights_pars_begin: lights_pars_begin,\n\tlights_toon_fragment: lights_toon_fragment,\n\tlights_toon_pars_fragment: lights_toon_pars_fragment,\n\tlights_phong_fragment: lights_phong_fragment,\n\tlights_phong_pars_fragment: lights_phong_pars_fragment,\n\tlights_physical_fragment: lights_physical_fragment,\n\tlights_physical_pars_fragment: lights_physical_pars_fragment,\n\tlights_fragment_begin: lights_fragment_begin,\n\tlights_fragment_maps: lights_fragment_maps,\n\tlights_fragment_end: lights_fragment_end,\n\tlogdepthbuf_fragment: logdepthbuf_fragment,\n\tlogdepthbuf_pars_fragment: logdepthbuf_pars_fragment,\n\tlogdepthbuf_pars_vertex: logdepthbuf_pars_vertex,\n\tlogdepthbuf_vertex: logdepthbuf_vertex,\n\tmap_fragment: map_fragment,\n\tmap_pars_fragment: map_pars_fragment,\n\tmap_particle_fragment: map_particle_fragment,\n\tmap_particle_pars_fragment: map_particle_pars_fragment,\n\tmetalnessmap_fragment: metalnessmap_fragment,\n\tmetalnessmap_pars_fragment: metalnessmap_pars_fragment,\n\tmorphinstance_vertex: morphinstance_vertex,\n\tmorphcolor_vertex: morphcolor_vertex,\n\tmorphnormal_vertex: morphnormal_vertex,\n\tmorphtarget_pars_vertex: morphtarget_pars_vertex,\n\tmorphtarget_vertex: morphtarget_vertex,\n\tnormal_fragment_begin: normal_fragment_begin,\n\tnormal_fragment_maps: normal_fragment_maps,\n\tnormal_pars_fragment: normal_pars_fragment,\n\tnormal_pars_vertex: normal_pars_vertex,\n\tnormal_vertex: normal_vertex,\n\tnormalmap_pars_fragment: normalmap_pars_fragment,\n\tclearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,\n\tclearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,\n\tclearcoat_pars_fragment: clearcoat_pars_fragment,\n\tiridescence_pars_fragment: iridescence_pars_fragment,\n\topaque_fragment: opaque_fragment,\n\tpacking: packing,\n\tpremultiplied_alpha_fragment: premultiplied_alpha_fragment,\n\tproject_vertex: project_vertex,\n\tdithering_fragment: dithering_fragment,\n\tdithering_pars_fragment: dithering_pars_fragment,\n\troughnessmap_fragment: roughnessmap_fragment,\n\troughnessmap_pars_fragment: roughnessmap_pars_fragment,\n\tshadowmap_pars_fragment: shadowmap_pars_fragment,\n\tshadowmap_pars_vertex: shadowmap_pars_vertex,\n\tshadowmap_vertex: shadowmap_vertex,\n\tshadowmask_pars_fragment: shadowmask_pars_fragment,\n\tskinbase_vertex: skinbase_vertex,\n\tskinning_pars_vertex: skinning_pars_vertex,\n\tskinning_vertex: skinning_vertex,\n\tskinnormal_vertex: skinnormal_vertex,\n\tspecularmap_fragment: specularmap_fragment,\n\tspecularmap_pars_fragment: specularmap_pars_fragment,\n\ttonemapping_fragment: tonemapping_fragment,\n\ttonemapping_pars_fragment: tonemapping_pars_fragment,\n\ttransmission_fragment: transmission_fragment,\n\ttransmission_pars_fragment: transmission_pars_fragment,\n\tuv_pars_fragment: uv_pars_fragment,\n\tuv_pars_vertex: uv_pars_vertex,\n\tuv_vertex: uv_vertex,\n\tworldpos_vertex: worldpos_vertex,\n\n\tbackground_vert: vertex$h,\n\tbackground_frag: fragment$h,\n\tbackgroundCube_vert: vertex$g,\n\tbackgroundCube_frag: fragment$g,\n\tcube_vert: vertex$f,\n\tcube_frag: fragment$f,\n\tdepth_vert: vertex$e,\n\tdepth_frag: fragment$e,\n\tdistanceRGBA_vert: vertex$d,\n\tdistanceRGBA_frag: fragment$d,\n\tequirect_vert: vertex$c,\n\tequirect_frag: fragment$c,\n\tlinedashed_vert: vertex$b,\n\tlinedashed_frag: fragment$b,\n\tmeshbasic_vert: vertex$a,\n\tmeshbasic_frag: fragment$a,\n\tmeshlambert_vert: vertex$9,\n\tmeshlambert_frag: fragment$9,\n\tmeshmatcap_vert: vertex$8,\n\tmeshmatcap_frag: fragment$8,\n\tmeshnormal_vert: vertex$7,\n\tmeshnormal_frag: fragment$7,\n\tmeshphong_vert: vertex$6,\n\tmeshphong_frag: fragment$6,\n\tmeshphysical_vert: vertex$5,\n\tmeshphysical_frag: fragment$5,\n\tmeshtoon_vert: vertex$4,\n\tmeshtoon_frag: fragment$4,\n\tpoints_vert: vertex$3,\n\tpoints_frag: fragment$3,\n\tshadow_vert: vertex$2,\n\tshadow_frag: fragment$2,\n\tsprite_vert: vertex$1,\n\tsprite_frag: fragment$1\n};\n\n/**\n * Uniforms library for shared webgl shaders\n */\n\nconst UniformsLib = {\n\n\tcommon: {\n\n\t\tdiffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },\n\t\topacity: { value: 1.0 },\n\n\t\tmap: { value: null },\n\t\tmapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\n\t\talphaMap: { value: null },\n\t\talphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\n\t\talphaTest: { value: 0 }\n\n\t},\n\n\tspecularmap: {\n\n\t\tspecularMap: { value: null },\n\t\tspecularMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tenvmap: {\n\n\t\tenvMap: { value: null },\n\t\tenvMapRotation: { value: /*@__PURE__*/ new Matrix3() },\n\t\tflipEnvMap: { value: - 1 },\n\t\treflectivity: { value: 1.0 }, // basic, lambert, phong\n\t\tior: { value: 1.5 }, // physical\n\t\trefractionRatio: { value: 0.98 }, // basic, lambert, phong\n\n\t},\n\n\taomap: {\n\n\t\taoMap: { value: null },\n\t\taoMapIntensity: { value: 1 },\n\t\taoMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tlightmap: {\n\n\t\tlightMap: { value: null },\n\t\tlightMapIntensity: { value: 1 },\n\t\tlightMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tbumpmap: {\n\n\t\tbumpMap: { value: null },\n\t\tbumpMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\tbumpScale: { value: 1 }\n\n\t},\n\n\tnormalmap: {\n\n\t\tnormalMap: { value: null },\n\t\tnormalMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\tnormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }\n\n\t},\n\n\tdisplacementmap: {\n\n\t\tdisplacementMap: { value: null },\n\t\tdisplacementMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\tdisplacementScale: { value: 1 },\n\t\tdisplacementBias: { value: 0 }\n\n\t},\n\n\temissivemap: {\n\n\t\temissiveMap: { value: null },\n\t\temissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tmetalnessmap: {\n\n\t\tmetalnessMap: { value: null },\n\t\tmetalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\troughnessmap: {\n\n\t\troughnessMap: { value: null },\n\t\troughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tgradientmap: {\n\n\t\tgradientMap: { value: null }\n\n\t},\n\n\tfog: {\n\n\t\tfogDensity: { value: 0.00025 },\n\t\tfogNear: { value: 1 },\n\t\tfogFar: { value: 2000 },\n\t\tfogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) }\n\n\t},\n\n\tlights: {\n\n\t\tambientLightColor: { value: [] },\n\n\t\tlightProbe: { value: [] },\n\n\t\tdirectionalLights: { value: [], properties: {\n\t\t\tdirection: {},\n\t\t\tcolor: {}\n\t\t} },\n\n\t\tdirectionalLightShadows: { value: [], properties: {\n\t\t\tshadowIntensity: 1,\n\t\t\tshadowBias: {},\n\t\t\tshadowNormalBias: {},\n\t\t\tshadowRadius: {},\n\t\t\tshadowMapSize: {}\n\t\t} },\n\n\t\tdirectionalShadowMap: { value: [] },\n\t\tdirectionalShadowMatrix: { value: [] },\n\n\t\tspotLights: { value: [], properties: {\n\t\t\tcolor: {},\n\t\t\tposition: {},\n\t\t\tdirection: {},\n\t\t\tdistance: {},\n\t\t\tconeCos: {},\n\t\t\tpenumbraCos: {},\n\t\t\tdecay: {}\n\t\t} },\n\n\t\tspotLightShadows: { value: [], properties: {\n\t\t\tshadowIntensity: 1,\n\t\t\tshadowBias: {},\n\t\t\tshadowNormalBias: {},\n\t\t\tshadowRadius: {},\n\t\t\tshadowMapSize: {}\n\t\t} },\n\n\t\tspotLightMap: { value: [] },\n\t\tspotShadowMap: { value: [] },\n\t\tspotLightMatrix: { value: [] },\n\n\t\tpointLights: { value: [], properties: {\n\t\t\tcolor: {},\n\t\t\tposition: {},\n\t\t\tdecay: {},\n\t\t\tdistance: {}\n\t\t} },\n\n\t\tpointLightShadows: { value: [], properties: {\n\t\t\tshadowIntensity: 1,\n\t\t\tshadowBias: {},\n\t\t\tshadowNormalBias: {},\n\t\t\tshadowRadius: {},\n\t\t\tshadowMapSize: {},\n\t\t\tshadowCameraNear: {},\n\t\t\tshadowCameraFar: {}\n\t\t} },\n\n\t\tpointShadowMap: { value: [] },\n\t\tpointShadowMatrix: { value: [] },\n\n\t\themisphereLights: { value: [], properties: {\n\t\t\tdirection: {},\n\t\t\tskyColor: {},\n\t\t\tgroundColor: {}\n\t\t} },\n\n\t\t// TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src\n\t\trectAreaLights: { value: [], properties: {\n\t\t\tcolor: {},\n\t\t\tposition: {},\n\t\t\twidth: {},\n\t\t\theight: {}\n\t\t} },\n\n\t\tltc_1: { value: null },\n\t\tltc_2: { value: null }\n\n\t},\n\n\tpoints: {\n\n\t\tdiffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },\n\t\topacity: { value: 1.0 },\n\t\tsize: { value: 1.0 },\n\t\tscale: { value: 1.0 },\n\t\tmap: { value: null },\n\t\talphaMap: { value: null },\n\t\talphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\talphaTest: { value: 0 },\n\t\tuvTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tsprite: {\n\n\t\tdiffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },\n\t\topacity: { value: 1.0 },\n\t\tcenter: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) },\n\t\trotation: { value: 0.0 },\n\t\tmap: { value: null },\n\t\tmapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\talphaMap: { value: null },\n\t\talphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\talphaTest: { value: 0 }\n\n\t}\n\n};\n\nconst ShaderLib = {\n\n\tbasic: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.specularmap,\n\t\t\tUniformsLib.envmap,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.fog\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshbasic_vert,\n\t\tfragmentShader: ShaderChunk.meshbasic_frag\n\n\t},\n\n\tlambert: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.specularmap,\n\t\t\tUniformsLib.envmap,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.emissivemap,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.fog,\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\temissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshlambert_vert,\n\t\tfragmentShader: ShaderChunk.meshlambert_frag\n\n\t},\n\n\tphong: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.specularmap,\n\t\t\tUniformsLib.envmap,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.emissivemap,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.fog,\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\temissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },\n\t\t\t\tspecular: { value: /*@__PURE__*/ new Color( 0x111111 ) },\n\t\t\t\tshininess: { value: 30 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshphong_vert,\n\t\tfragmentShader: ShaderChunk.meshphong_frag\n\n\t},\n\n\tstandard: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.envmap,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.emissivemap,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.roughnessmap,\n\t\t\tUniformsLib.metalnessmap,\n\t\t\tUniformsLib.fog,\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\temissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },\n\t\t\t\troughness: { value: 1.0 },\n\t\t\t\tmetalness: { value: 0.0 },\n\t\t\t\tenvMapIntensity: { value: 1 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshphysical_vert,\n\t\tfragmentShader: ShaderChunk.meshphysical_frag\n\n\t},\n\n\ttoon: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.emissivemap,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.gradientmap,\n\t\t\tUniformsLib.fog,\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\temissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshtoon_vert,\n\t\tfragmentShader: ShaderChunk.meshtoon_frag\n\n\t},\n\n\tmatcap: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.fog,\n\t\t\t{\n\t\t\t\tmatcap: { value: null }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshmatcap_vert,\n\t\tfragmentShader: ShaderChunk.meshmatcap_frag\n\n\t},\n\n\tpoints: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.points,\n\t\t\tUniformsLib.fog\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.points_vert,\n\t\tfragmentShader: ShaderChunk.points_frag\n\n\t},\n\n\tdashed: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.fog,\n\t\t\t{\n\t\t\t\tscale: { value: 1 },\n\t\t\t\tdashSize: { value: 1 },\n\t\t\t\ttotalSize: { value: 2 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.linedashed_vert,\n\t\tfragmentShader: ShaderChunk.linedashed_frag\n\n\t},\n\n\tdepth: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.displacementmap\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.depth_vert,\n\t\tfragmentShader: ShaderChunk.depth_frag\n\n\t},\n\n\tnormal: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\t{\n\t\t\t\topacity: { value: 1.0 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshnormal_vert,\n\t\tfragmentShader: ShaderChunk.meshnormal_frag\n\n\t},\n\n\tsprite: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.sprite,\n\t\t\tUniformsLib.fog\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.sprite_vert,\n\t\tfragmentShader: ShaderChunk.sprite_frag\n\n\t},\n\n\tbackground: {\n\n\t\tuniforms: {\n\t\t\tuvTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tt2D: { value: null },\n\t\t\tbackgroundIntensity: { value: 1 }\n\t\t},\n\n\t\tvertexShader: ShaderChunk.background_vert,\n\t\tfragmentShader: ShaderChunk.background_frag\n\n\t},\n\n\tbackgroundCube: {\n\n\t\tuniforms: {\n\t\t\tenvMap: { value: null },\n\t\t\tflipEnvMap: { value: - 1 },\n\t\t\tbackgroundBlurriness: { value: 0 },\n\t\t\tbackgroundIntensity: { value: 1 },\n\t\t\tbackgroundRotation: { value: /*@__PURE__*/ new Matrix3() }\n\t\t},\n\n\t\tvertexShader: ShaderChunk.backgroundCube_vert,\n\t\tfragmentShader: ShaderChunk.backgroundCube_frag\n\n\t},\n\n\tcube: {\n\n\t\tuniforms: {\n\t\t\ttCube: { value: null },\n\t\t\ttFlip: { value: - 1 },\n\t\t\topacity: { value: 1.0 }\n\t\t},\n\n\t\tvertexShader: ShaderChunk.cube_vert,\n\t\tfragmentShader: ShaderChunk.cube_frag\n\n\t},\n\n\tequirect: {\n\n\t\tuniforms: {\n\t\t\ttEquirect: { value: null },\n\t\t},\n\n\t\tvertexShader: ShaderChunk.equirect_vert,\n\t\tfragmentShader: ShaderChunk.equirect_frag\n\n\t},\n\n\tdistanceRGBA: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.displacementmap,\n\t\t\t{\n\t\t\t\treferencePosition: { value: /*@__PURE__*/ new Vector3() },\n\t\t\t\tnearDistance: { value: 1 },\n\t\t\t\tfarDistance: { value: 1000 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.distanceRGBA_vert,\n\t\tfragmentShader: ShaderChunk.distanceRGBA_frag\n\n\t},\n\n\tshadow: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.lights,\n\t\t\tUniformsLib.fog,\n\t\t\t{\n\t\t\t\tcolor: { value: /*@__PURE__*/ new Color( 0x00000 ) },\n\t\t\t\topacity: { value: 1.0 }\n\t\t\t},\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.shadow_vert,\n\t\tfragmentShader: ShaderChunk.shadow_frag\n\n\t}\n\n};\n\nShaderLib.physical = {\n\n\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\tShaderLib.standard.uniforms,\n\t\t{\n\t\t\tclearcoat: { value: 0 },\n\t\t\tclearcoatMap: { value: null },\n\t\t\tclearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tclearcoatNormalMap: { value: null },\n\t\t\tclearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tclearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) },\n\t\t\tclearcoatRoughness: { value: 0 },\n\t\t\tclearcoatRoughnessMap: { value: null },\n\t\t\tclearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tdispersion: { value: 0 },\n\t\t\tiridescence: { value: 0 },\n\t\t\tiridescenceMap: { value: null },\n\t\t\tiridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tiridescenceIOR: { value: 1.3 },\n\t\t\tiridescenceThicknessMinimum: { value: 100 },\n\t\t\tiridescenceThicknessMaximum: { value: 400 },\n\t\t\tiridescenceThicknessMap: { value: null },\n\t\t\tiridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tsheen: { value: 0 },\n\t\t\tsheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },\n\t\t\tsheenColorMap: { value: null },\n\t\t\tsheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tsheenRoughness: { value: 1 },\n\t\t\tsheenRoughnessMap: { value: null },\n\t\t\tsheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\ttransmission: { value: 0 },\n\t\t\ttransmissionMap: { value: null },\n\t\t\ttransmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\ttransmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() },\n\t\t\ttransmissionSamplerMap: { value: null },\n\t\t\tthickness: { value: 0 },\n\t\t\tthicknessMap: { value: null },\n\t\t\tthicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tattenuationDistance: { value: 0 },\n\t\t\tattenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },\n\t\t\tspecularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) },\n\t\t\tspecularColorMap: { value: null },\n\t\t\tspecularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tspecularIntensity: { value: 1 },\n\t\t\tspecularIntensityMap: { value: null },\n\t\t\tspecularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tanisotropyVector: { value: /*@__PURE__*/ new Vector2() },\n\t\t\tanisotropyMap: { value: null },\n\t\t\tanisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t}\n\t] ),\n\n\tvertexShader: ShaderChunk.meshphysical_vert,\n\tfragmentShader: ShaderChunk.meshphysical_frag\n\n};\n\nconst _rgb = { r: 0, b: 0, g: 0 };\nconst _e1$1 = /*@__PURE__*/ new Euler();\nconst _m1$1 = /*@__PURE__*/ new Matrix4();\n\nfunction WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, premultipliedAlpha ) {\n\n\tconst clearColor = new Color( 0x000000 );\n\tlet clearAlpha = alpha === true ? 0 : 1;\n\n\tlet planeMesh;\n\tlet boxMesh;\n\n\tlet currentBackground = null;\n\tlet currentBackgroundVersion = 0;\n\tlet currentTonemapping = null;\n\n\tfunction getBackground( scene ) {\n\n\t\tlet background = scene.isScene === true ? scene.background : null;\n\n\t\tif ( background && background.isTexture ) {\n\n\t\t\tconst usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background\n\t\t\tbackground = ( usePMREM ? cubeuvmaps : cubemaps ).get( background );\n\n\t\t}\n\n\t\treturn background;\n\n\t}\n\n\tfunction render( scene ) {\n\n\t\tlet forceClear = false;\n\t\tconst background = getBackground( scene );\n\n\t\tif ( background === null ) {\n\n\t\t\tsetClear( clearColor, clearAlpha );\n\n\t\t} else if ( background && background.isColor ) {\n\n\t\t\tsetClear( background, 1 );\n\t\t\tforceClear = true;\n\n\t\t}\n\n\t\tconst environmentBlendMode = renderer.xr.getEnvironmentBlendMode();\n\n\t\tif ( environmentBlendMode === 'additive' ) {\n\n\t\t\tstate.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );\n\n\t\t} else if ( environmentBlendMode === 'alpha-blend' ) {\n\n\t\t\tstate.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );\n\n\t\t}\n\n\t\tif ( renderer.autoClear || forceClear ) {\n\n\t\t\t// buffers might not be writable which is required to ensure a correct clear\n\n\t\t\tstate.buffers.depth.setTest( true );\n\t\t\tstate.buffers.depth.setMask( true );\n\t\t\tstate.buffers.color.setMask( true );\n\n\t\t\trenderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );\n\n\t\t}\n\n\t}\n\n\tfunction addToRenderList( renderList, scene ) {\n\n\t\tconst background = getBackground( scene );\n\n\t\tif ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) {\n\n\t\t\tif ( boxMesh === undefined ) {\n\n\t\t\t\tboxMesh = new Mesh(\n\t\t\t\t\tnew BoxGeometry( 1, 1, 1 ),\n\t\t\t\t\tnew ShaderMaterial( {\n\t\t\t\t\t\tname: 'BackgroundCubeMaterial',\n\t\t\t\t\t\tuniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ),\n\t\t\t\t\t\tvertexShader: ShaderLib.backgroundCube.vertexShader,\n\t\t\t\t\t\tfragmentShader: ShaderLib.backgroundCube.fragmentShader,\n\t\t\t\t\t\tside: BackSide,\n\t\t\t\t\t\tdepthTest: false,\n\t\t\t\t\t\tdepthWrite: false,\n\t\t\t\t\t\tfog: false\n\t\t\t\t\t} )\n\t\t\t\t);\n\n\t\t\t\tboxMesh.geometry.deleteAttribute( 'normal' );\n\t\t\t\tboxMesh.geometry.deleteAttribute( 'uv' );\n\n\t\t\t\tboxMesh.onBeforeRender = function ( renderer, scene, camera ) {\n\n\t\t\t\t\tthis.matrixWorld.copyPosition( camera.matrixWorld );\n\n\t\t\t\t};\n\n\t\t\t\t// add \"envMap\" material property so the renderer can evaluate it like for built-in materials\n\t\t\t\tObject.defineProperty( boxMesh.material, 'envMap', {\n\n\t\t\t\t\tget: function () {\n\n\t\t\t\t\t\treturn this.uniforms.envMap.value;\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t\tobjects.update( boxMesh );\n\n\t\t\t}\n\n\t\t\t_e1$1.copy( scene.backgroundRotation );\n\n\t\t\t// accommodate left-handed frame\n\t\t\t_e1$1.x *= - 1; _e1$1.y *= - 1; _e1$1.z *= - 1;\n\n\t\t\tif ( background.isCubeTexture && background.isRenderTargetTexture === false ) {\n\n\t\t\t\t// environment maps which are not cube render targets or PMREMs follow a different convention\n\t\t\t\t_e1$1.y *= - 1;\n\t\t\t\t_e1$1.z *= - 1;\n\n\t\t\t}\n\n\t\t\tboxMesh.material.uniforms.envMap.value = background;\n\t\t\tboxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1;\n\t\t\tboxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness;\n\t\t\tboxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;\n\t\t\tboxMesh.material.uniforms.backgroundRotation.value.setFromMatrix4( _m1$1.makeRotationFromEuler( _e1$1 ) );\n\t\t\tboxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;\n\n\t\t\tif ( currentBackground !== background ||\n\t\t\t\tcurrentBackgroundVersion !== background.version ||\n\t\t\t\tcurrentTonemapping !== renderer.toneMapping ) {\n\n\t\t\t\tboxMesh.material.needsUpdate = true;\n\n\t\t\t\tcurrentBackground = background;\n\t\t\t\tcurrentBackgroundVersion = background.version;\n\t\t\t\tcurrentTonemapping = renderer.toneMapping;\n\n\t\t\t}\n\n\t\t\tboxMesh.layers.enableAll();\n\n\t\t\t// push to the pre-sorted opaque render list\n\t\t\trenderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );\n\n\t\t} else if ( background && background.isTexture ) {\n\n\t\t\tif ( planeMesh === undefined ) {\n\n\t\t\t\tplaneMesh = new Mesh(\n\t\t\t\t\tnew PlaneGeometry( 2, 2 ),\n\t\t\t\t\tnew ShaderMaterial( {\n\t\t\t\t\t\tname: 'BackgroundMaterial',\n\t\t\t\t\t\tuniforms: cloneUniforms( ShaderLib.background.uniforms ),\n\t\t\t\t\t\tvertexShader: ShaderLib.background.vertexShader,\n\t\t\t\t\t\tfragmentShader: ShaderLib.background.fragmentShader,\n\t\t\t\t\t\tside: FrontSide,\n\t\t\t\t\t\tdepthTest: false,\n\t\t\t\t\t\tdepthWrite: false,\n\t\t\t\t\t\tfog: false\n\t\t\t\t\t} )\n\t\t\t\t);\n\n\t\t\t\tplaneMesh.geometry.deleteAttribute( 'normal' );\n\n\t\t\t\t// add \"map\" material property so the renderer can evaluate it like for built-in materials\n\t\t\t\tObject.defineProperty( planeMesh.material, 'map', {\n\n\t\t\t\t\tget: function () {\n\n\t\t\t\t\t\treturn this.uniforms.t2D.value;\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t\tobjects.update( planeMesh );\n\n\t\t\t}\n\n\t\t\tplaneMesh.material.uniforms.t2D.value = background;\n\t\t\tplaneMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;\n\t\t\tplaneMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;\n\n\t\t\tif ( background.matrixAutoUpdate === true ) {\n\n\t\t\t\tbackground.updateMatrix();\n\n\t\t\t}\n\n\t\t\tplaneMesh.material.uniforms.uvTransform.value.copy( background.matrix );\n\n\t\t\tif ( currentBackground !== background ||\n\t\t\t\tcurrentBackgroundVersion !== background.version ||\n\t\t\t\tcurrentTonemapping !== renderer.toneMapping ) {\n\n\t\t\t\tplaneMesh.material.needsUpdate = true;\n\n\t\t\t\tcurrentBackground = background;\n\t\t\t\tcurrentBackgroundVersion = background.version;\n\t\t\t\tcurrentTonemapping = renderer.toneMapping;\n\n\t\t\t}\n\n\t\t\tplaneMesh.layers.enableAll();\n\n\t\t\t// push to the pre-sorted opaque render list\n\t\t\trenderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );\n\n\t\t}\n\n\t}\n\n\tfunction setClear( color, alpha ) {\n\n\t\tcolor.getRGB( _rgb, getUnlitUniformColorSpace( renderer ) );\n\n\t\tstate.buffers.color.setClear( _rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha );\n\n\t}\n\n\treturn {\n\n\t\tgetClearColor: function () {\n\n\t\t\treturn clearColor;\n\n\t\t},\n\t\tsetClearColor: function ( color, alpha = 1 ) {\n\n\t\t\tclearColor.set( color );\n\t\t\tclearAlpha = alpha;\n\t\t\tsetClear( clearColor, clearAlpha );\n\n\t\t},\n\t\tgetClearAlpha: function () {\n\n\t\t\treturn clearAlpha;\n\n\t\t},\n\t\tsetClearAlpha: function ( alpha ) {\n\n\t\t\tclearAlpha = alpha;\n\t\t\tsetClear( clearColor, clearAlpha );\n\n\t\t},\n\t\trender: render,\n\t\taddToRenderList: addToRenderList\n\n\t};\n\n}\n\nfunction WebGLBindingStates( gl, attributes ) {\n\n\tconst maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );\n\n\tconst bindingStates = {};\n\n\tconst defaultState = createBindingState( null );\n\tlet currentState = defaultState;\n\tlet forceUpdate = false;\n\n\tfunction setup( object, material, program, geometry, index ) {\n\n\t\tlet updateBuffers = false;\n\n\t\tconst state = getBindingState( geometry, program, material );\n\n\t\tif ( currentState !== state ) {\n\n\t\t\tcurrentState = state;\n\t\t\tbindVertexArrayObject( currentState.object );\n\n\t\t}\n\n\t\tupdateBuffers = needsUpdate( object, geometry, program, index );\n\n\t\tif ( updateBuffers ) saveCache( object, geometry, program, index );\n\n\t\tif ( index !== null ) {\n\n\t\t\tattributes.update( index, gl.ELEMENT_ARRAY_BUFFER );\n\n\t\t}\n\n\t\tif ( updateBuffers || forceUpdate ) {\n\n\t\t\tforceUpdate = false;\n\n\t\t\tsetupVertexAttributes( object, material, program, geometry );\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction createVertexArrayObject() {\n\n\t\treturn gl.createVertexArray();\n\n\t}\n\n\tfunction bindVertexArrayObject( vao ) {\n\n\t\treturn gl.bindVertexArray( vao );\n\n\t}\n\n\tfunction deleteVertexArrayObject( vao ) {\n\n\t\treturn gl.deleteVertexArray( vao );\n\n\t}\n\n\tfunction getBindingState( geometry, program, material ) {\n\n\t\tconst wireframe = ( material.wireframe === true );\n\n\t\tlet programMap = bindingStates[ geometry.id ];\n\n\t\tif ( programMap === undefined ) {\n\n\t\t\tprogramMap = {};\n\t\t\tbindingStates[ geometry.id ] = programMap;\n\n\t\t}\n\n\t\tlet stateMap = programMap[ program.id ];\n\n\t\tif ( stateMap === undefined ) {\n\n\t\t\tstateMap = {};\n\t\t\tprogramMap[ program.id ] = stateMap;\n\n\t\t}\n\n\t\tlet state = stateMap[ wireframe ];\n\n\t\tif ( state === undefined ) {\n\n\t\t\tstate = createBindingState( createVertexArrayObject() );\n\t\t\tstateMap[ wireframe ] = state;\n\n\t\t}\n\n\t\treturn state;\n\n\t}\n\n\tfunction createBindingState( vao ) {\n\n\t\tconst newAttributes = [];\n\t\tconst enabledAttributes = [];\n\t\tconst attributeDivisors = [];\n\n\t\tfor ( let i = 0; i < maxVertexAttributes; i ++ ) {\n\n\t\t\tnewAttributes[ i ] = 0;\n\t\t\tenabledAttributes[ i ] = 0;\n\t\t\tattributeDivisors[ i ] = 0;\n\n\t\t}\n\n\t\treturn {\n\n\t\t\t// for backward compatibility on non-VAO support browser\n\t\t\tgeometry: null,\n\t\t\tprogram: null,\n\t\t\twireframe: false,\n\n\t\t\tnewAttributes: newAttributes,\n\t\t\tenabledAttributes: enabledAttributes,\n\t\t\tattributeDivisors: attributeDivisors,\n\t\t\tobject: vao,\n\t\t\tattributes: {},\n\t\t\tindex: null\n\n\t\t};\n\n\t}\n\n\tfunction needsUpdate( object, geometry, program, index ) {\n\n\t\tconst cachedAttributes = currentState.attributes;\n\t\tconst geometryAttributes = geometry.attributes;\n\n\t\tlet attributesNum = 0;\n\n\t\tconst programAttributes = program.getAttributes();\n\n\t\tfor ( const name in programAttributes ) {\n\n\t\t\tconst programAttribute = programAttributes[ name ];\n\n\t\t\tif ( programAttribute.location >= 0 ) {\n\n\t\t\t\tconst cachedAttribute = cachedAttributes[ name ];\n\t\t\t\tlet geometryAttribute = geometryAttributes[ name ];\n\n\t\t\t\tif ( geometryAttribute === undefined ) {\n\n\t\t\t\t\tif ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;\n\t\t\t\t\tif ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;\n\n\t\t\t\t}\n\n\t\t\t\tif ( cachedAttribute === undefined ) return true;\n\n\t\t\t\tif ( cachedAttribute.attribute !== geometryAttribute ) return true;\n\n\t\t\t\tif ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true;\n\n\t\t\t\tattributesNum ++;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( currentState.attributesNum !== attributesNum ) return true;\n\n\t\tif ( currentState.index !== index ) return true;\n\n\t\treturn false;\n\n\t}\n\n\tfunction saveCache( object, geometry, program, index ) {\n\n\t\tconst cache = {};\n\t\tconst attributes = geometry.attributes;\n\t\tlet attributesNum = 0;\n\n\t\tconst programAttributes = program.getAttributes();\n\n\t\tfor ( const name in programAttributes ) {\n\n\t\t\tconst programAttribute = programAttributes[ name ];\n\n\t\t\tif ( programAttribute.location >= 0 ) {\n\n\t\t\t\tlet attribute = attributes[ name ];\n\n\t\t\t\tif ( attribute === undefined ) {\n\n\t\t\t\t\tif ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix;\n\t\t\t\t\tif ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor;\n\n\t\t\t\t}\n\n\t\t\t\tconst data = {};\n\t\t\t\tdata.attribute = attribute;\n\n\t\t\t\tif ( attribute && attribute.data ) {\n\n\t\t\t\t\tdata.data = attribute.data;\n\n\t\t\t\t}\n\n\t\t\t\tcache[ name ] = data;\n\n\t\t\t\tattributesNum ++;\n\n\t\t\t}\n\n\t\t}\n\n\t\tcurrentState.attributes = cache;\n\t\tcurrentState.attributesNum = attributesNum;\n\n\t\tcurrentState.index = index;\n\n\t}\n\n\tfunction initAttributes() {\n\n\t\tconst newAttributes = currentState.newAttributes;\n\n\t\tfor ( let i = 0, il = newAttributes.length; i < il; i ++ ) {\n\n\t\t\tnewAttributes[ i ] = 0;\n\n\t\t}\n\n\t}\n\n\tfunction enableAttribute( attribute ) {\n\n\t\tenableAttributeAndDivisor( attribute, 0 );\n\n\t}\n\n\tfunction enableAttributeAndDivisor( attribute, meshPerAttribute ) {\n\n\t\tconst newAttributes = currentState.newAttributes;\n\t\tconst enabledAttributes = currentState.enabledAttributes;\n\t\tconst attributeDivisors = currentState.attributeDivisors;\n\n\t\tnewAttributes[ attribute ] = 1;\n\n\t\tif ( enabledAttributes[ attribute ] === 0 ) {\n\n\t\t\tgl.enableVertexAttribArray( attribute );\n\t\t\tenabledAttributes[ attribute ] = 1;\n\n\t\t}\n\n\t\tif ( attributeDivisors[ attribute ] !== meshPerAttribute ) {\n\n\t\t\tgl.vertexAttribDivisor( attribute, meshPerAttribute );\n\t\t\tattributeDivisors[ attribute ] = meshPerAttribute;\n\n\t\t}\n\n\t}\n\n\tfunction disableUnusedAttributes() {\n\n\t\tconst newAttributes = currentState.newAttributes;\n\t\tconst enabledAttributes = currentState.enabledAttributes;\n\n\t\tfor ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {\n\n\t\t\tif ( enabledAttributes[ i ] !== newAttributes[ i ] ) {\n\n\t\t\t\tgl.disableVertexAttribArray( i );\n\t\t\t\tenabledAttributes[ i ] = 0;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) {\n\n\t\tif ( integer === true ) {\n\n\t\t\tgl.vertexAttribIPointer( index, size, type, stride, offset );\n\n\t\t} else {\n\n\t\t\tgl.vertexAttribPointer( index, size, type, normalized, stride, offset );\n\n\t\t}\n\n\t}\n\n\tfunction setupVertexAttributes( object, material, program, geometry ) {\n\n\t\tinitAttributes();\n\n\t\tconst geometryAttributes = geometry.attributes;\n\n\t\tconst programAttributes = program.getAttributes();\n\n\t\tconst materialDefaultAttributeValues = material.defaultAttributeValues;\n\n\t\tfor ( const name in programAttributes ) {\n\n\t\t\tconst programAttribute = programAttributes[ name ];\n\n\t\t\tif ( programAttribute.location >= 0 ) {\n\n\t\t\t\tlet geometryAttribute = geometryAttributes[ name ];\n\n\t\t\t\tif ( geometryAttribute === undefined ) {\n\n\t\t\t\t\tif ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;\n\t\t\t\t\tif ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;\n\n\t\t\t\t}\n\n\t\t\t\tif ( geometryAttribute !== undefined ) {\n\n\t\t\t\t\tconst normalized = geometryAttribute.normalized;\n\t\t\t\t\tconst size = geometryAttribute.itemSize;\n\n\t\t\t\t\tconst attribute = attributes.get( geometryAttribute );\n\n\t\t\t\t\t// TODO Attribute may not be available on context restore\n\n\t\t\t\t\tif ( attribute === undefined ) continue;\n\n\t\t\t\t\tconst buffer = attribute.buffer;\n\t\t\t\t\tconst type = attribute.type;\n\t\t\t\t\tconst bytesPerElement = attribute.bytesPerElement;\n\n\t\t\t\t\t// check for integer attributes\n\n\t\t\t\t\tconst integer = ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType );\n\n\t\t\t\t\tif ( geometryAttribute.isInterleavedBufferAttribute ) {\n\n\t\t\t\t\t\tconst data = geometryAttribute.data;\n\t\t\t\t\t\tconst stride = data.stride;\n\t\t\t\t\t\tconst offset = geometryAttribute.offset;\n\n\t\t\t\t\t\tif ( data.isInstancedInterleavedBuffer ) {\n\n\t\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\t\tenableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {\n\n\t\t\t\t\t\t\t\tgeometry._maxInstanceCount = data.meshPerAttribute * data.count;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\t\tenableAttribute( programAttribute.location + i );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgl.bindBuffer( gl.ARRAY_BUFFER, buffer );\n\n\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\tvertexAttribPointer(\n\t\t\t\t\t\t\t\tprogramAttribute.location + i,\n\t\t\t\t\t\t\t\tsize / programAttribute.locationSize,\n\t\t\t\t\t\t\t\ttype,\n\t\t\t\t\t\t\t\tnormalized,\n\t\t\t\t\t\t\t\tstride * bytesPerElement,\n\t\t\t\t\t\t\t\t( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement,\n\t\t\t\t\t\t\t\tinteger\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( geometryAttribute.isInstancedBufferAttribute ) {\n\n\t\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\t\tenableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {\n\n\t\t\t\t\t\t\t\tgeometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\t\tenableAttribute( programAttribute.location + i );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgl.bindBuffer( gl.ARRAY_BUFFER, buffer );\n\n\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\tvertexAttribPointer(\n\t\t\t\t\t\t\t\tprogramAttribute.location + i,\n\t\t\t\t\t\t\t\tsize / programAttribute.locationSize,\n\t\t\t\t\t\t\t\ttype,\n\t\t\t\t\t\t\t\tnormalized,\n\t\t\t\t\t\t\t\tsize * bytesPerElement,\n\t\t\t\t\t\t\t\t( size / programAttribute.locationSize ) * i * bytesPerElement,\n\t\t\t\t\t\t\t\tinteger\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( materialDefaultAttributeValues !== undefined ) {\n\n\t\t\t\t\tconst value = materialDefaultAttributeValues[ name ];\n\n\t\t\t\t\tif ( value !== undefined ) {\n\n\t\t\t\t\t\tswitch ( value.length ) {\n\n\t\t\t\t\t\t\tcase 2:\n\t\t\t\t\t\t\t\tgl.vertexAttrib2fv( programAttribute.location, value );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 3:\n\t\t\t\t\t\t\t\tgl.vertexAttrib3fv( programAttribute.location, value );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 4:\n\t\t\t\t\t\t\t\tgl.vertexAttrib4fv( programAttribute.location, value );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tgl.vertexAttrib1fv( programAttribute.location, value );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tdisableUnusedAttributes();\n\n\t}\n\n\tfunction dispose() {\n\n\t\treset();\n\n\t\tfor ( const geometryId in bindingStates ) {\n\n\t\t\tconst programMap = bindingStates[ geometryId ];\n\n\t\t\tfor ( const programId in programMap ) {\n\n\t\t\t\tconst stateMap = programMap[ programId ];\n\n\t\t\t\tfor ( const wireframe in stateMap ) {\n\n\t\t\t\t\tdeleteVertexArrayObject( stateMap[ wireframe ].object );\n\n\t\t\t\t\tdelete stateMap[ wireframe ];\n\n\t\t\t\t}\n\n\t\t\t\tdelete programMap[ programId ];\n\n\t\t\t}\n\n\t\t\tdelete bindingStates[ geometryId ];\n\n\t\t}\n\n\t}\n\n\tfunction releaseStatesOfGeometry( geometry ) {\n\n\t\tif ( bindingStates[ geometry.id ] === undefined ) return;\n\n\t\tconst programMap = bindingStates[ geometry.id ];\n\n\t\tfor ( const programId in programMap ) {\n\n\t\t\tconst stateMap = programMap[ programId ];\n\n\t\t\tfor ( const wireframe in stateMap ) {\n\n\t\t\t\tdeleteVertexArrayObject( stateMap[ wireframe ].object );\n\n\t\t\t\tdelete stateMap[ wireframe ];\n\n\t\t\t}\n\n\t\t\tdelete programMap[ programId ];\n\n\t\t}\n\n\t\tdelete bindingStates[ geometry.id ];\n\n\t}\n\n\tfunction releaseStatesOfProgram( program ) {\n\n\t\tfor ( const geometryId in bindingStates ) {\n\n\t\t\tconst programMap = bindingStates[ geometryId ];\n\n\t\t\tif ( programMap[ program.id ] === undefined ) continue;\n\n\t\t\tconst stateMap = programMap[ program.id ];\n\n\t\t\tfor ( const wireframe in stateMap ) {\n\n\t\t\t\tdeleteVertexArrayObject( stateMap[ wireframe ].object );\n\n\t\t\t\tdelete stateMap[ wireframe ];\n\n\t\t\t}\n\n\t\t\tdelete programMap[ program.id ];\n\n\t\t}\n\n\t}\n\n\tfunction reset() {\n\n\t\tresetDefaultState();\n\t\tforceUpdate = true;\n\n\t\tif ( currentState === defaultState ) return;\n\n\t\tcurrentState = defaultState;\n\t\tbindVertexArrayObject( currentState.object );\n\n\t}\n\n\t// for backward-compatibility\n\n\tfunction resetDefaultState() {\n\n\t\tdefaultState.geometry = null;\n\t\tdefaultState.program = null;\n\t\tdefaultState.wireframe = false;\n\n\t}\n\n\treturn {\n\n\t\tsetup: setup,\n\t\treset: reset,\n\t\tresetDefaultState: resetDefaultState,\n\t\tdispose: dispose,\n\t\treleaseStatesOfGeometry: releaseStatesOfGeometry,\n\t\treleaseStatesOfProgram: releaseStatesOfProgram,\n\n\t\tinitAttributes: initAttributes,\n\t\tenableAttribute: enableAttribute,\n\t\tdisableUnusedAttributes: disableUnusedAttributes\n\n\t};\n\n}\n\nfunction WebGLBufferRenderer( gl, extensions, info ) {\n\n\tlet mode;\n\n\tfunction setMode( value ) {\n\n\t\tmode = value;\n\n\t}\n\n\tfunction render( start, count ) {\n\n\t\tgl.drawArrays( mode, start, count );\n\n\t\tinfo.update( count, mode, 1 );\n\n\t}\n\n\tfunction renderInstances( start, count, primcount ) {\n\n\t\tif ( primcount === 0 ) return;\n\n\t\tgl.drawArraysInstanced( mode, start, count, primcount );\n\n\t\tinfo.update( count, mode, primcount );\n\n\t}\n\n\tfunction renderMultiDraw( starts, counts, drawCount ) {\n\n\t\tif ( drawCount === 0 ) return;\n\n\t\tconst extension = extensions.get( 'WEBGL_multi_draw' );\n\t\textension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount );\n\n\t\tlet elementCount = 0;\n\t\tfor ( let i = 0; i < drawCount; i ++ ) {\n\n\t\t\telementCount += counts[ i ];\n\n\t\t}\n\n\t\tinfo.update( elementCount, mode, 1 );\n\n\t}\n\n\tfunction renderMultiDrawInstances( starts, counts, drawCount, primcount ) {\n\n\t\tif ( drawCount === 0 ) return;\n\n\t\tconst extension = extensions.get( 'WEBGL_multi_draw' );\n\n\t\tif ( extension === null ) {\n\n\t\t\tfor ( let i = 0; i < starts.length; i ++ ) {\n\n\t\t\t\trenderInstances( starts[ i ], counts[ i ], primcount[ i ] );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\textension.multiDrawArraysInstancedWEBGL( mode, starts, 0, counts, 0, primcount, 0, drawCount );\n\n\t\t\tlet elementCount = 0;\n\t\t\tfor ( let i = 0; i < drawCount; i ++ ) {\n\n\t\t\t\telementCount += counts[ i ];\n\n\t\t\t}\n\n\t\t\tfor ( let i = 0; i < primcount.length; i ++ ) {\n\n\t\t\t\tinfo.update( elementCount, mode, primcount[ i ] );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t//\n\n\tthis.setMode = setMode;\n\tthis.render = render;\n\tthis.renderInstances = renderInstances;\n\tthis.renderMultiDraw = renderMultiDraw;\n\tthis.renderMultiDrawInstances = renderMultiDrawInstances;\n\n}\n\nfunction WebGLCapabilities( gl, extensions, parameters, utils ) {\n\n\tlet maxAnisotropy;\n\n\tfunction getMaxAnisotropy() {\n\n\t\tif ( maxAnisotropy !== undefined ) return maxAnisotropy;\n\n\t\tif ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {\n\n\t\t\tconst extension = extensions.get( 'EXT_texture_filter_anisotropic' );\n\n\t\t\tmaxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );\n\n\t\t} else {\n\n\t\t\tmaxAnisotropy = 0;\n\n\t\t}\n\n\t\treturn maxAnisotropy;\n\n\t}\n\n\tfunction textureFormatReadable( textureFormat ) {\n\n\t\tif ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tfunction textureTypeReadable( textureType ) {\n\n\t\tconst halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || extensions.has( 'EXT_color_buffer_float' ) );\n\n\t\tif ( textureType !== UnsignedByteType && utils.convert( textureType ) !== gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)\n\t\t\ttextureType !== FloatType && ! halfFloatSupportedByExt ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tfunction getMaxPrecision( precision ) {\n\n\t\tif ( precision === 'highp' ) {\n\n\t\t\tif ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&\n\t\t\t\tgl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {\n\n\t\t\t\treturn 'highp';\n\n\t\t\t}\n\n\t\t\tprecision = 'mediump';\n\n\t\t}\n\n\t\tif ( precision === 'mediump' ) {\n\n\t\t\tif ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&\n\t\t\t\tgl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {\n\n\t\t\t\treturn 'mediump';\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn 'lowp';\n\n\t}\n\n\tlet precision = parameters.precision !== undefined ? parameters.precision : 'highp';\n\tconst maxPrecision = getMaxPrecision( precision );\n\n\tif ( maxPrecision !== precision ) {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );\n\t\tprecision = maxPrecision;\n\n\t}\n\n\tconst logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;\n\n\tconst maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );\n\tconst maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );\n\tconst maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );\n\tconst maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE );\n\n\tconst maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );\n\tconst maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );\n\tconst maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );\n\tconst maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );\n\n\tconst vertexTextures = maxVertexTextures > 0;\n\n\tconst maxSamples = gl.getParameter( gl.MAX_SAMPLES );\n\n\treturn {\n\n\t\tisWebGL2: true, // keeping this for backwards compatibility\n\n\t\tgetMaxAnisotropy: getMaxAnisotropy,\n\t\tgetMaxPrecision: getMaxPrecision,\n\n\t\ttextureFormatReadable: textureFormatReadable,\n\t\ttextureTypeReadable: textureTypeReadable,\n\n\t\tprecision: precision,\n\t\tlogarithmicDepthBuffer: logarithmicDepthBuffer,\n\n\t\tmaxTextures: maxTextures,\n\t\tmaxVertexTextures: maxVertexTextures,\n\t\tmaxTextureSize: maxTextureSize,\n\t\tmaxCubemapSize: maxCubemapSize,\n\n\t\tmaxAttributes: maxAttributes,\n\t\tmaxVertexUniforms: maxVertexUniforms,\n\t\tmaxVaryings: maxVaryings,\n\t\tmaxFragmentUniforms: maxFragmentUniforms,\n\n\t\tvertexTextures: vertexTextures,\n\n\t\tmaxSamples: maxSamples\n\n\t};\n\n}\n\nfunction WebGLClipping( properties ) {\n\n\tconst scope = this;\n\n\tlet globalState = null,\n\t\tnumGlobalPlanes = 0,\n\t\tlocalClippingEnabled = false,\n\t\trenderingShadows = false;\n\n\tconst plane = new Plane(),\n\t\tviewNormalMatrix = new Matrix3(),\n\n\t\tuniform = { value: null, needsUpdate: false };\n\n\tthis.uniform = uniform;\n\tthis.numPlanes = 0;\n\tthis.numIntersection = 0;\n\n\tthis.init = function ( planes, enableLocalClipping ) {\n\n\t\tconst enabled =\n\t\t\tplanes.length !== 0 ||\n\t\t\tenableLocalClipping ||\n\t\t\t// enable state of previous frame - the clipping code has to\n\t\t\t// run another frame in order to reset the state:\n\t\t\tnumGlobalPlanes !== 0 ||\n\t\t\tlocalClippingEnabled;\n\n\t\tlocalClippingEnabled = enableLocalClipping;\n\n\t\tnumGlobalPlanes = planes.length;\n\n\t\treturn enabled;\n\n\t};\n\n\tthis.beginShadows = function () {\n\n\t\trenderingShadows = true;\n\t\tprojectPlanes( null );\n\n\t};\n\n\tthis.endShadows = function () {\n\n\t\trenderingShadows = false;\n\n\t};\n\n\tthis.setGlobalState = function ( planes, camera ) {\n\n\t\tglobalState = projectPlanes( planes, camera, 0 );\n\n\t};\n\n\tthis.setState = function ( material, camera, useCache ) {\n\n\t\tconst planes = material.clippingPlanes,\n\t\t\tclipIntersection = material.clipIntersection,\n\t\t\tclipShadows = material.clipShadows;\n\n\t\tconst materialProperties = properties.get( material );\n\n\t\tif ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {\n\n\t\t\t// there's no local clipping\n\n\t\t\tif ( renderingShadows ) {\n\n\t\t\t\t// there's no global clipping\n\n\t\t\t\tprojectPlanes( null );\n\n\t\t\t} else {\n\n\t\t\t\tresetGlobalState();\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconst nGlobal = renderingShadows ? 0 : numGlobalPlanes,\n\t\t\t\tlGlobal = nGlobal * 4;\n\n\t\t\tlet dstArray = materialProperties.clippingState || null;\n\n\t\t\tuniform.value = dstArray; // ensure unique state\n\n\t\t\tdstArray = projectPlanes( planes, camera, lGlobal, useCache );\n\n\t\t\tfor ( let i = 0; i !== lGlobal; ++ i ) {\n\n\t\t\t\tdstArray[ i ] = globalState[ i ];\n\n\t\t\t}\n\n\t\t\tmaterialProperties.clippingState = dstArray;\n\t\t\tthis.numIntersection = clipIntersection ? this.numPlanes : 0;\n\t\t\tthis.numPlanes += nGlobal;\n\n\t\t}\n\n\n\t};\n\n\tfunction resetGlobalState() {\n\n\t\tif ( uniform.value !== globalState ) {\n\n\t\t\tuniform.value = globalState;\n\t\t\tuniform.needsUpdate = numGlobalPlanes > 0;\n\n\t\t}\n\n\t\tscope.numPlanes = numGlobalPlanes;\n\t\tscope.numIntersection = 0;\n\n\t}\n\n\tfunction projectPlanes( planes, camera, dstOffset, skipTransform ) {\n\n\t\tconst nPlanes = planes !== null ? planes.length : 0;\n\t\tlet dstArray = null;\n\n\t\tif ( nPlanes !== 0 ) {\n\n\t\t\tdstArray = uniform.value;\n\n\t\t\tif ( skipTransform !== true || dstArray === null ) {\n\n\t\t\t\tconst flatSize = dstOffset + nPlanes * 4,\n\t\t\t\t\tviewMatrix = camera.matrixWorldInverse;\n\n\t\t\t\tviewNormalMatrix.getNormalMatrix( viewMatrix );\n\n\t\t\t\tif ( dstArray === null || dstArray.length < flatSize ) {\n\n\t\t\t\t\tdstArray = new Float32Array( flatSize );\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {\n\n\t\t\t\t\tplane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );\n\n\t\t\t\t\tplane.normal.toArray( dstArray, i4 );\n\t\t\t\t\tdstArray[ i4 + 3 ] = plane.constant;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tuniform.value = dstArray;\n\t\t\tuniform.needsUpdate = true;\n\n\t\t}\n\n\t\tscope.numPlanes = nPlanes;\n\t\tscope.numIntersection = 0;\n\n\t\treturn dstArray;\n\n\t}\n\n}\n\nfunction WebGLCubeMaps( renderer ) {\n\n\tlet cubemaps = new WeakMap();\n\n\tfunction mapTextureMapping( texture, mapping ) {\n\n\t\tif ( mapping === EquirectangularReflectionMapping ) {\n\n\t\t\ttexture.mapping = CubeReflectionMapping;\n\n\t\t} else if ( mapping === EquirectangularRefractionMapping ) {\n\n\t\t\ttexture.mapping = CubeRefractionMapping;\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n\tfunction get( texture ) {\n\n\t\tif ( texture && texture.isTexture ) {\n\n\t\t\tconst mapping = texture.mapping;\n\n\t\t\tif ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) {\n\n\t\t\t\tif ( cubemaps.has( texture ) ) {\n\n\t\t\t\t\tconst cubemap = cubemaps.get( texture ).texture;\n\t\t\t\t\treturn mapTextureMapping( cubemap, texture.mapping );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconst image = texture.image;\n\n\t\t\t\t\tif ( image && image.height > 0 ) {\n\n\t\t\t\t\t\tconst renderTarget = new WebGLCubeRenderTarget( image.height );\n\t\t\t\t\t\trenderTarget.fromEquirectangularTexture( renderer, texture );\n\t\t\t\t\t\tcubemaps.set( texture, renderTarget );\n\n\t\t\t\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\n\n\t\t\t\t\t\treturn mapTextureMapping( renderTarget.texture, texture.mapping );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// image not yet ready. try the conversion next frame\n\n\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n\tfunction onTextureDispose( event ) {\n\n\t\tconst texture = event.target;\n\n\t\ttexture.removeEventListener( 'dispose', onTextureDispose );\n\n\t\tconst cubemap = cubemaps.get( texture );\n\n\t\tif ( cubemap !== undefined ) {\n\n\t\t\tcubemaps.delete( texture );\n\t\t\tcubemap.dispose();\n\n\t\t}\n\n\t}\n\n\tfunction dispose() {\n\n\t\tcubemaps = new WeakMap();\n\n\t}\n\n\treturn {\n\t\tget: get,\n\t\tdispose: dispose\n\t};\n\n}\n\nclass OrthographicCamera extends Camera {\n\n\tconstructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) {\n\n\t\tsuper();\n\n\t\tthis.isOrthographicCamera = true;\n\n\t\tthis.type = 'OrthographicCamera';\n\n\t\tthis.zoom = 1;\n\t\tthis.view = null;\n\n\t\tthis.left = left;\n\t\tthis.right = right;\n\t\tthis.top = top;\n\t\tthis.bottom = bottom;\n\n\t\tthis.near = near;\n\t\tthis.far = far;\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.left = source.left;\n\t\tthis.right = source.right;\n\t\tthis.top = source.top;\n\t\tthis.bottom = source.bottom;\n\t\tthis.near = source.near;\n\t\tthis.far = source.far;\n\n\t\tthis.zoom = source.zoom;\n\t\tthis.view = source.view === null ? null : Object.assign( {}, source.view );\n\n\t\treturn this;\n\n\t}\n\n\tsetViewOffset( fullWidth, fullHeight, x, y, width, height ) {\n\n\t\tif ( this.view === null ) {\n\n\t\t\tthis.view = {\n\t\t\t\tenabled: true,\n\t\t\t\tfullWidth: 1,\n\t\t\t\tfullHeight: 1,\n\t\t\t\toffsetX: 0,\n\t\t\t\toffsetY: 0,\n\t\t\t\twidth: 1,\n\t\t\t\theight: 1\n\t\t\t};\n\n\t\t}\n\n\t\tthis.view.enabled = true;\n\t\tthis.view.fullWidth = fullWidth;\n\t\tthis.view.fullHeight = fullHeight;\n\t\tthis.view.offsetX = x;\n\t\tthis.view.offsetY = y;\n\t\tthis.view.width = width;\n\t\tthis.view.height = height;\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tclearViewOffset() {\n\n\t\tif ( this.view !== null ) {\n\n\t\t\tthis.view.enabled = false;\n\n\t\t}\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tupdateProjectionMatrix() {\n\n\t\tconst dx = ( this.right - this.left ) / ( 2 * this.zoom );\n\t\tconst dy = ( this.top - this.bottom ) / ( 2 * this.zoom );\n\t\tconst cx = ( this.right + this.left ) / 2;\n\t\tconst cy = ( this.top + this.bottom ) / 2;\n\n\t\tlet left = cx - dx;\n\t\tlet right = cx + dx;\n\t\tlet top = cy + dy;\n\t\tlet bottom = cy - dy;\n\n\t\tif ( this.view !== null && this.view.enabled ) {\n\n\t\t\tconst scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom;\n\t\t\tconst scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom;\n\n\t\t\tleft += scaleW * this.view.offsetX;\n\t\t\tright = left + scaleW * this.view.width;\n\t\t\ttop -= scaleH * this.view.offsetY;\n\t\t\tbottom = top - scaleH * this.view.height;\n\n\t\t}\n\n\t\tthis.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem );\n\n\t\tthis.projectionMatrixInverse.copy( this.projectionMatrix ).invert();\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.object.zoom = this.zoom;\n\t\tdata.object.left = this.left;\n\t\tdata.object.right = this.right;\n\t\tdata.object.top = this.top;\n\t\tdata.object.bottom = this.bottom;\n\t\tdata.object.near = this.near;\n\t\tdata.object.far = this.far;\n\n\t\tif ( this.view !== null ) data.object.view = Object.assign( {}, this.view );\n\n\t\treturn data;\n\n\t}\n\n}\n\nconst LOD_MIN = 4;\n\n// The standard deviations (radians) associated with the extra mips. These are\n// chosen to approximate a Trowbridge-Reitz distribution function times the\n// geometric shadowing function. These sigma values squared must match the\n// variance #defines in cube_uv_reflection_fragment.glsl.js.\nconst EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];\n\n// The maximum length of the blur for loop. Smaller sigmas will use fewer\n// samples and exit early, but not recompile the shader.\nconst MAX_SAMPLES = 20;\n\nconst _flatCamera = /*@__PURE__*/ new OrthographicCamera();\nconst _clearColor = /*@__PURE__*/ new Color();\nlet _oldTarget = null;\nlet _oldActiveCubeFace = 0;\nlet _oldActiveMipmapLevel = 0;\nlet _oldXrEnabled = false;\n\n// Golden Ratio\nconst PHI = ( 1 + Math.sqrt( 5 ) ) / 2;\nconst INV_PHI = 1 / PHI;\n\n// Vertices of a dodecahedron (except the opposites, which represent the\n// same axis), used as axis directions evenly spread on a sphere.\nconst _axisDirections = [\n\t/*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ),\n\t/*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ),\n\t/*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ),\n\t/*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ),\n\t/*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ),\n\t/*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ),\n\t/*@__PURE__*/ new Vector3( - 1, 1, - 1 ),\n\t/*@__PURE__*/ new Vector3( 1, 1, - 1 ),\n\t/*@__PURE__*/ new Vector3( - 1, 1, 1 ),\n\t/*@__PURE__*/ new Vector3( 1, 1, 1 ) ];\n\n/**\n * This class generates a Prefiltered, Mipmapped Radiance Environment Map\n * (PMREM) from a cubeMap environment texture. This allows different levels of\n * blur to be quickly accessed based on material roughness. It is packed into a\n * special CubeUV format that allows us to perform custom interpolation so that\n * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap\n * chain, it only goes down to the LOD_MIN level (above), and then creates extra\n * even more filtered 'mips' at the same LOD_MIN resolution, associated with\n * higher roughness levels. In this way we maintain resolution to smoothly\n * interpolate diffuse lighting while limiting sampling computation.\n *\n * Paper: Fast, Accurate Image-Based Lighting\n * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view\n*/\n\nclass PMREMGenerator {\n\n\tconstructor( renderer ) {\n\n\t\tthis._renderer = renderer;\n\t\tthis._pingPongRenderTarget = null;\n\n\t\tthis._lodMax = 0;\n\t\tthis._cubeSize = 0;\n\t\tthis._lodPlanes = [];\n\t\tthis._sizeLods = [];\n\t\tthis._sigmas = [];\n\n\t\tthis._blurMaterial = null;\n\t\tthis._cubemapMaterial = null;\n\t\tthis._equirectMaterial = null;\n\n\t\tthis._compileMaterial( this._blurMaterial );\n\n\t}\n\n\t/**\n\t * Generates a PMREM from a supplied Scene, which can be faster than using an\n\t * image if networking bandwidth is low. Optional sigma specifies a blur radius\n\t * in radians to be applied to the scene before PMREM generation. Optional near\n\t * and far planes ensure the scene is rendered in its entirety (the cubeCamera\n\t * is placed at the origin).\n\t */\n\tfromScene( scene, sigma = 0, near = 0.1, far = 100 ) {\n\n\t\t_oldTarget = this._renderer.getRenderTarget();\n\t\t_oldActiveCubeFace = this._renderer.getActiveCubeFace();\n\t\t_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();\n\t\t_oldXrEnabled = this._renderer.xr.enabled;\n\n\t\tthis._renderer.xr.enabled = false;\n\n\t\tthis._setSize( 256 );\n\n\t\tconst cubeUVRenderTarget = this._allocateTargets();\n\t\tcubeUVRenderTarget.depthBuffer = true;\n\n\t\tthis._sceneToCubeUV( scene, near, far, cubeUVRenderTarget );\n\n\t\tif ( sigma > 0 ) {\n\n\t\t\tthis._blur( cubeUVRenderTarget, 0, 0, sigma );\n\n\t\t}\n\n\t\tthis._applyPMREM( cubeUVRenderTarget );\n\t\tthis._cleanup( cubeUVRenderTarget );\n\n\t\treturn cubeUVRenderTarget;\n\n\t}\n\n\t/**\n\t * Generates a PMREM from an equirectangular texture, which can be either LDR\n\t * or HDR. The ideal input image size is 1k (1024 x 512),\n\t * as this matches best with the 256 x 256 cubemap output.\n\t * The smallest supported equirectangular image size is 64 x 32.\n\t */\n\tfromEquirectangular( equirectangular, renderTarget = null ) {\n\n\t\treturn this._fromTexture( equirectangular, renderTarget );\n\n\t}\n\n\t/**\n\t * Generates a PMREM from an cubemap texture, which can be either LDR\n\t * or HDR. The ideal input cube size is 256 x 256,\n\t * as this matches best with the 256 x 256 cubemap output.\n\t * The smallest supported cube size is 16 x 16.\n\t */\n\tfromCubemap( cubemap, renderTarget = null ) {\n\n\t\treturn this._fromTexture( cubemap, renderTarget );\n\n\t}\n\n\t/**\n\t * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during\n\t * your texture's network fetch for increased concurrency.\n\t */\n\tcompileCubemapShader() {\n\n\t\tif ( this._cubemapMaterial === null ) {\n\n\t\t\tthis._cubemapMaterial = _getCubemapMaterial();\n\t\t\tthis._compileMaterial( this._cubemapMaterial );\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during\n\t * your texture's network fetch for increased concurrency.\n\t */\n\tcompileEquirectangularShader() {\n\n\t\tif ( this._equirectMaterial === null ) {\n\n\t\t\tthis._equirectMaterial = _getEquirectMaterial();\n\t\t\tthis._compileMaterial( this._equirectMaterial );\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,\n\t * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on\n\t * one of them will cause any others to also become unusable.\n\t */\n\tdispose() {\n\n\t\tthis._dispose();\n\n\t\tif ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose();\n\t\tif ( this._equirectMaterial !== null ) this._equirectMaterial.dispose();\n\n\t}\n\n\t// private interface\n\n\t_setSize( cubeSize ) {\n\n\t\tthis._lodMax = Math.floor( Math.log2( cubeSize ) );\n\t\tthis._cubeSize = Math.pow( 2, this._lodMax );\n\n\t}\n\n\t_dispose() {\n\n\t\tif ( this._blurMaterial !== null ) this._blurMaterial.dispose();\n\n\t\tif ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose();\n\n\t\tfor ( let i = 0; i < this._lodPlanes.length; i ++ ) {\n\n\t\t\tthis._lodPlanes[ i ].dispose();\n\n\t\t}\n\n\t}\n\n\t_cleanup( outputTarget ) {\n\n\t\tthis._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel );\n\t\tthis._renderer.xr.enabled = _oldXrEnabled;\n\n\t\toutputTarget.scissorTest = false;\n\t\t_setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );\n\n\t}\n\n\t_fromTexture( texture, renderTarget ) {\n\n\t\tif ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) {\n\n\t\t\tthis._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) );\n\n\t\t} else { // Equirectangular\n\n\t\t\tthis._setSize( texture.image.width / 4 );\n\n\t\t}\n\n\t\t_oldTarget = this._renderer.getRenderTarget();\n\t\t_oldActiveCubeFace = this._renderer.getActiveCubeFace();\n\t\t_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();\n\t\t_oldXrEnabled = this._renderer.xr.enabled;\n\n\t\tthis._renderer.xr.enabled = false;\n\n\t\tconst cubeUVRenderTarget = renderTarget || this._allocateTargets();\n\t\tthis._textureToCubeUV( texture, cubeUVRenderTarget );\n\t\tthis._applyPMREM( cubeUVRenderTarget );\n\t\tthis._cleanup( cubeUVRenderTarget );\n\n\t\treturn cubeUVRenderTarget;\n\n\t}\n\n\t_allocateTargets() {\n\n\t\tconst width = 3 * Math.max( this._cubeSize, 16 * 7 );\n\t\tconst height = 4 * this._cubeSize;\n\n\t\tconst params = {\n\t\t\tmagFilter: LinearFilter,\n\t\t\tminFilter: LinearFilter,\n\t\t\tgenerateMipmaps: false,\n\t\t\ttype: HalfFloatType,\n\t\t\tformat: RGBAFormat,\n\t\t\tcolorSpace: LinearSRGBColorSpace,\n\t\t\tdepthBuffer: false\n\t\t};\n\n\t\tconst cubeUVRenderTarget = _createRenderTarget( width, height, params );\n\n\t\tif ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) {\n\n\t\t\tif ( this._pingPongRenderTarget !== null ) {\n\n\t\t\t\tthis._dispose();\n\n\t\t\t}\n\n\t\t\tthis._pingPongRenderTarget = _createRenderTarget( width, height, params );\n\n\t\t\tconst { _lodMax } = this;\n\t\t\t( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) );\n\n\t\t\tthis._blurMaterial = _getBlurShader( _lodMax, width, height );\n\n\t\t}\n\n\t\treturn cubeUVRenderTarget;\n\n\t}\n\n\t_compileMaterial( material ) {\n\n\t\tconst tmpMesh = new Mesh( this._lodPlanes[ 0 ], material );\n\t\tthis._renderer.compile( tmpMesh, _flatCamera );\n\n\t}\n\n\t_sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) {\n\n\t\tconst fov = 90;\n\t\tconst aspect = 1;\n\t\tconst cubeCamera = new PerspectiveCamera( fov, aspect, near, far );\n\t\tconst upSign = [ 1, - 1, 1, 1, 1, 1 ];\n\t\tconst forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ];\n\t\tconst renderer = this._renderer;\n\n\t\tconst originalAutoClear = renderer.autoClear;\n\t\tconst toneMapping = renderer.toneMapping;\n\t\trenderer.getClearColor( _clearColor );\n\n\t\trenderer.toneMapping = NoToneMapping;\n\t\trenderer.autoClear = false;\n\n\t\tconst backgroundMaterial = new MeshBasicMaterial( {\n\t\t\tname: 'PMREM.Background',\n\t\t\tside: BackSide,\n\t\t\tdepthWrite: false,\n\t\t\tdepthTest: false,\n\t\t} );\n\n\t\tconst backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );\n\n\t\tlet useSolidColor = false;\n\t\tconst background = scene.background;\n\n\t\tif ( background ) {\n\n\t\t\tif ( background.isColor ) {\n\n\t\t\t\tbackgroundMaterial.color.copy( background );\n\t\t\t\tscene.background = null;\n\t\t\t\tuseSolidColor = true;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tbackgroundMaterial.color.copy( _clearColor );\n\t\t\tuseSolidColor = true;\n\n\t\t}\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\tconst col = i % 3;\n\n\t\t\tif ( col === 0 ) {\n\n\t\t\t\tcubeCamera.up.set( 0, upSign[ i ], 0 );\n\t\t\t\tcubeCamera.lookAt( forwardSign[ i ], 0, 0 );\n\n\t\t\t} else if ( col === 1 ) {\n\n\t\t\t\tcubeCamera.up.set( 0, 0, upSign[ i ] );\n\t\t\t\tcubeCamera.lookAt( 0, forwardSign[ i ], 0 );\n\n\t\t\t} else {\n\n\t\t\t\tcubeCamera.up.set( 0, upSign[ i ], 0 );\n\t\t\t\tcubeCamera.lookAt( 0, 0, forwardSign[ i ] );\n\n\t\t\t}\n\n\t\t\tconst size = this._cubeSize;\n\n\t\t\t_setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size );\n\n\t\t\trenderer.setRenderTarget( cubeUVRenderTarget );\n\n\t\t\tif ( useSolidColor ) {\n\n\t\t\t\trenderer.render( backgroundBox, cubeCamera );\n\n\t\t\t}\n\n\t\t\trenderer.render( scene, cubeCamera );\n\n\t\t}\n\n\t\tbackgroundBox.geometry.dispose();\n\t\tbackgroundBox.material.dispose();\n\n\t\trenderer.toneMapping = toneMapping;\n\t\trenderer.autoClear = originalAutoClear;\n\t\tscene.background = background;\n\n\t}\n\n\t_textureToCubeUV( texture, cubeUVRenderTarget ) {\n\n\t\tconst renderer = this._renderer;\n\n\t\tconst isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping );\n\n\t\tif ( isCubeTexture ) {\n\n\t\t\tif ( this._cubemapMaterial === null ) {\n\n\t\t\t\tthis._cubemapMaterial = _getCubemapMaterial();\n\n\t\t\t}\n\n\t\t\tthis._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1;\n\n\t\t} else {\n\n\t\t\tif ( this._equirectMaterial === null ) {\n\n\t\t\t\tthis._equirectMaterial = _getEquirectMaterial();\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial;\n\t\tconst mesh = new Mesh( this._lodPlanes[ 0 ], material );\n\n\t\tconst uniforms = material.uniforms;\n\n\t\tuniforms[ 'envMap' ].value = texture;\n\n\t\tconst size = this._cubeSize;\n\n\t\t_setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );\n\n\t\trenderer.setRenderTarget( cubeUVRenderTarget );\n\t\trenderer.render( mesh, _flatCamera );\n\n\t}\n\n\t_applyPMREM( cubeUVRenderTarget ) {\n\n\t\tconst renderer = this._renderer;\n\t\tconst autoClear = renderer.autoClear;\n\t\trenderer.autoClear = false;\n\t\tconst n = this._lodPlanes.length;\n\n\t\tfor ( let i = 1; i < n; i ++ ) {\n\n\t\t\tconst sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] );\n\n\t\t\tconst poleAxis = _axisDirections[ ( n - i - 1 ) % _axisDirections.length ];\n\n\t\t\tthis._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );\n\n\t\t}\n\n\t\trenderer.autoClear = autoClear;\n\n\t}\n\n\t/**\n\t * This is a two-pass Gaussian blur for a cubemap. Normally this is done\n\t * vertically and horizontally, but this breaks down on a cube. Here we apply\n\t * the blur latitudinally (around the poles), and then longitudinally (towards\n\t * the poles) to approximate the orthogonally-separable blur. It is least\n\t * accurate at the poles, but still does a decent job.\n\t */\n\t_blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {\n\n\t\tconst pingPongRenderTarget = this._pingPongRenderTarget;\n\n\t\tthis._halfBlur(\n\t\t\tcubeUVRenderTarget,\n\t\t\tpingPongRenderTarget,\n\t\t\tlodIn,\n\t\t\tlodOut,\n\t\t\tsigma,\n\t\t\t'latitudinal',\n\t\t\tpoleAxis );\n\n\t\tthis._halfBlur(\n\t\t\tpingPongRenderTarget,\n\t\t\tcubeUVRenderTarget,\n\t\t\tlodOut,\n\t\t\tlodOut,\n\t\t\tsigma,\n\t\t\t'longitudinal',\n\t\t\tpoleAxis );\n\n\t}\n\n\t_halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {\n\n\t\tconst renderer = this._renderer;\n\t\tconst blurMaterial = this._blurMaterial;\n\n\t\tif ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {\n\n\t\t\tconsole.error(\n\t\t\t\t'blur direction must be either latitudinal or longitudinal!' );\n\n\t\t}\n\n\t\t// Number of standard deviations at which to cut off the discrete approximation.\n\t\tconst STANDARD_DEVIATIONS = 3;\n\n\t\tconst blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial );\n\t\tconst blurUniforms = blurMaterial.uniforms;\n\n\t\tconst pixels = this._sizeLods[ lodIn ] - 1;\n\t\tconst radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );\n\t\tconst sigmaPixels = sigmaRadians / radiansPerPixel;\n\t\tconst samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;\n\n\t\tif ( samples > MAX_SAMPLES ) {\n\n\t\t\tconsole.warn( `sigmaRadians, ${\n\t\t\t\tsigmaRadians}, is too large and will clip, as it requested ${\n\t\t\t\tsamples} samples when the maximum is set to ${MAX_SAMPLES}` );\n\n\t\t}\n\n\t\tconst weights = [];\n\t\tlet sum = 0;\n\n\t\tfor ( let i = 0; i < MAX_SAMPLES; ++ i ) {\n\n\t\t\tconst x = i / sigmaPixels;\n\t\t\tconst weight = Math.exp( - x * x / 2 );\n\t\t\tweights.push( weight );\n\n\t\t\tif ( i === 0 ) {\n\n\t\t\t\tsum += weight;\n\n\t\t\t} else if ( i < samples ) {\n\n\t\t\t\tsum += 2 * weight;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( let i = 0; i < weights.length; i ++ ) {\n\n\t\t\tweights[ i ] = weights[ i ] / sum;\n\n\t\t}\n\n\t\tblurUniforms[ 'envMap' ].value = targetIn.texture;\n\t\tblurUniforms[ 'samples' ].value = samples;\n\t\tblurUniforms[ 'weights' ].value = weights;\n\t\tblurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';\n\n\t\tif ( poleAxis ) {\n\n\t\t\tblurUniforms[ 'poleAxis' ].value = poleAxis;\n\n\t\t}\n\n\t\tconst { _lodMax } = this;\n\t\tblurUniforms[ 'dTheta' ].value = radiansPerPixel;\n\t\tblurUniforms[ 'mipInt' ].value = _lodMax - lodIn;\n\n\t\tconst outputSize = this._sizeLods[ lodOut ];\n\t\tconst x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 );\n\t\tconst y = 4 * ( this._cubeSize - outputSize );\n\n\t\t_setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );\n\t\trenderer.setRenderTarget( targetOut );\n\t\trenderer.render( blurMesh, _flatCamera );\n\n\t}\n\n}\n\n\n\nfunction _createPlanes( lodMax ) {\n\n\tconst lodPlanes = [];\n\tconst sizeLods = [];\n\tconst sigmas = [];\n\n\tlet lod = lodMax;\n\n\tconst totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;\n\n\tfor ( let i = 0; i < totalLods; i ++ ) {\n\n\t\tconst sizeLod = Math.pow( 2, lod );\n\t\tsizeLods.push( sizeLod );\n\t\tlet sigma = 1.0 / sizeLod;\n\n\t\tif ( i > lodMax - LOD_MIN ) {\n\n\t\t\tsigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ];\n\n\t\t} else if ( i === 0 ) {\n\n\t\t\tsigma = 0;\n\n\t\t}\n\n\t\tsigmas.push( sigma );\n\n\t\tconst texelSize = 1.0 / ( sizeLod - 2 );\n\t\tconst min = - texelSize;\n\t\tconst max = 1 + texelSize;\n\t\tconst uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];\n\n\t\tconst cubeFaces = 6;\n\t\tconst vertices = 6;\n\t\tconst positionSize = 3;\n\t\tconst uvSize = 2;\n\t\tconst faceIndexSize = 1;\n\n\t\tconst position = new Float32Array( positionSize * vertices * cubeFaces );\n\t\tconst uv = new Float32Array( uvSize * vertices * cubeFaces );\n\t\tconst faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces );\n\n\t\tfor ( let face = 0; face < cubeFaces; face ++ ) {\n\n\t\t\tconst x = ( face % 3 ) * 2 / 3 - 1;\n\t\t\tconst y = face > 2 ? 0 : - 1;\n\t\t\tconst coordinates = [\n\t\t\t\tx, y, 0,\n\t\t\t\tx + 2 / 3, y, 0,\n\t\t\t\tx + 2 / 3, y + 1, 0,\n\t\t\t\tx, y, 0,\n\t\t\t\tx + 2 / 3, y + 1, 0,\n\t\t\t\tx, y + 1, 0\n\t\t\t];\n\t\t\tposition.set( coordinates, positionSize * vertices * face );\n\t\t\tuv.set( uv1, uvSize * vertices * face );\n\t\t\tconst fill = [ face, face, face, face, face, face ];\n\t\t\tfaceIndex.set( fill, faceIndexSize * vertices * face );\n\n\t\t}\n\n\t\tconst planes = new BufferGeometry();\n\t\tplanes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );\n\t\tplanes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );\n\t\tplanes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );\n\t\tlodPlanes.push( planes );\n\n\t\tif ( lod > LOD_MIN ) {\n\n\t\t\tlod --;\n\n\t\t}\n\n\t}\n\n\treturn { lodPlanes, sizeLods, sigmas };\n\n}\n\nfunction _createRenderTarget( width, height, params ) {\n\n\tconst cubeUVRenderTarget = new WebGLRenderTarget( width, height, params );\n\tcubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;\n\tcubeUVRenderTarget.texture.name = 'PMREM.cubeUv';\n\tcubeUVRenderTarget.scissorTest = true;\n\treturn cubeUVRenderTarget;\n\n}\n\nfunction _setViewport( target, x, y, width, height ) {\n\n\ttarget.viewport.set( x, y, width, height );\n\ttarget.scissor.set( x, y, width, height );\n\n}\n\nfunction _getBlurShader( lodMax, width, height ) {\n\n\tconst weights = new Float32Array( MAX_SAMPLES );\n\tconst poleAxis = new Vector3( 0, 1, 0 );\n\tconst shaderMaterial = new ShaderMaterial( {\n\n\t\tname: 'SphericalGaussianBlur',\n\n\t\tdefines: {\n\t\t\t'n': MAX_SAMPLES,\n\t\t\t'CUBEUV_TEXEL_WIDTH': 1.0 / width,\n\t\t\t'CUBEUV_TEXEL_HEIGHT': 1.0 / height,\n\t\t\t'CUBEUV_MAX_MIP': `${lodMax}.0`,\n\t\t},\n\n\t\tuniforms: {\n\t\t\t'envMap': { value: null },\n\t\t\t'samples': { value: 1 },\n\t\t\t'weights': { value: weights },\n\t\t\t'latitudinal': { value: false },\n\t\t\t'dTheta': { value: 0 },\n\t\t\t'mipInt': { value: 0 },\n\t\t\t'poleAxis': { value: poleAxis }\n\t\t},\n\n\t\tvertexShader: _getCommonVertexShader(),\n\n\t\tfragmentShader: /* glsl */`\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`,\n\n\t\tblending: NoBlending,\n\t\tdepthTest: false,\n\t\tdepthWrite: false\n\n\t} );\n\n\treturn shaderMaterial;\n\n}\n\nfunction _getEquirectMaterial() {\n\n\treturn new ShaderMaterial( {\n\n\t\tname: 'EquirectangularToCubeUV',\n\n\t\tuniforms: {\n\t\t\t'envMap': { value: null }\n\t\t},\n\n\t\tvertexShader: _getCommonVertexShader(),\n\n\t\tfragmentShader: /* glsl */`\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`,\n\n\t\tblending: NoBlending,\n\t\tdepthTest: false,\n\t\tdepthWrite: false\n\n\t} );\n\n}\n\nfunction _getCubemapMaterial() {\n\n\treturn new ShaderMaterial( {\n\n\t\tname: 'CubemapToCubeUV',\n\n\t\tuniforms: {\n\t\t\t'envMap': { value: null },\n\t\t\t'flipEnvMap': { value: - 1 }\n\t\t},\n\n\t\tvertexShader: _getCommonVertexShader(),\n\n\t\tfragmentShader: /* glsl */`\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`,\n\n\t\tblending: NoBlending,\n\t\tdepthTest: false,\n\t\tdepthWrite: false\n\n\t} );\n\n}\n\nfunction _getCommonVertexShader() {\n\n\treturn /* glsl */`\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`;\n\n}\n\nfunction WebGLCubeUVMaps( renderer ) {\n\n\tlet cubeUVmaps = new WeakMap();\n\n\tlet pmremGenerator = null;\n\n\tfunction get( texture ) {\n\n\t\tif ( texture && texture.isTexture ) {\n\n\t\t\tconst mapping = texture.mapping;\n\n\t\t\tconst isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping );\n\t\t\tconst isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping );\n\n\t\t\t// equirect/cube map to cubeUV conversion\n\n\t\t\tif ( isEquirectMap || isCubeMap ) {\n\n\t\t\t\tlet renderTarget = cubeUVmaps.get( texture );\n\n\t\t\t\tconst currentPMREMVersion = renderTarget !== undefined ? renderTarget.texture.pmremVersion : 0;\n\n\t\t\t\tif ( texture.isRenderTargetTexture && texture.pmremVersion !== currentPMREMVersion ) {\n\n\t\t\t\t\tif ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );\n\n\t\t\t\t\trenderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget );\n\t\t\t\t\trenderTarget.texture.pmremVersion = texture.pmremVersion;\n\n\t\t\t\t\tcubeUVmaps.set( texture, renderTarget );\n\n\t\t\t\t\treturn renderTarget.texture;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( renderTarget !== undefined ) {\n\n\t\t\t\t\t\treturn renderTarget.texture;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconst image = texture.image;\n\n\t\t\t\t\t\tif ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) {\n\n\t\t\t\t\t\t\tif ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );\n\n\t\t\t\t\t\t\trenderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture );\n\t\t\t\t\t\t\trenderTarget.texture.pmremVersion = texture.pmremVersion;\n\n\t\t\t\t\t\t\tcubeUVmaps.set( texture, renderTarget );\n\n\t\t\t\t\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\n\n\t\t\t\t\t\t\treturn renderTarget.texture;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// image not yet ready. try the conversion next frame\n\n\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n\tfunction isCubeTextureComplete( image ) {\n\n\t\tlet count = 0;\n\t\tconst length = 6;\n\n\t\tfor ( let i = 0; i < length; i ++ ) {\n\n\t\t\tif ( image[ i ] !== undefined ) count ++;\n\n\t\t}\n\n\t\treturn count === length;\n\n\n\t}\n\n\tfunction onTextureDispose( event ) {\n\n\t\tconst texture = event.target;\n\n\t\ttexture.removeEventListener( 'dispose', onTextureDispose );\n\n\t\tconst cubemapUV = cubeUVmaps.get( texture );\n\n\t\tif ( cubemapUV !== undefined ) {\n\n\t\t\tcubeUVmaps.delete( texture );\n\t\t\tcubemapUV.dispose();\n\n\t\t}\n\n\t}\n\n\tfunction dispose() {\n\n\t\tcubeUVmaps = new WeakMap();\n\n\t\tif ( pmremGenerator !== null ) {\n\n\t\t\tpmremGenerator.dispose();\n\t\t\tpmremGenerator = null;\n\n\t\t}\n\n\t}\n\n\treturn {\n\t\tget: get,\n\t\tdispose: dispose\n\t};\n\n}\n\nfunction WebGLExtensions( gl ) {\n\n\tconst extensions = {};\n\n\tfunction getExtension( name ) {\n\n\t\tif ( extensions[ name ] !== undefined ) {\n\n\t\t\treturn extensions[ name ];\n\n\t\t}\n\n\t\tlet extension;\n\n\t\tswitch ( name ) {\n\n\t\t\tcase 'WEBGL_depth_texture':\n\t\t\t\textension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );\n\t\t\t\tbreak;\n\n\t\t\tcase 'EXT_texture_filter_anisotropic':\n\t\t\t\textension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );\n\t\t\t\tbreak;\n\n\t\t\tcase 'WEBGL_compressed_texture_s3tc':\n\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );\n\t\t\t\tbreak;\n\n\t\t\tcase 'WEBGL_compressed_texture_pvrtc':\n\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\textension = gl.getExtension( name );\n\n\t\t}\n\n\t\textensions[ name ] = extension;\n\n\t\treturn extension;\n\n\t}\n\n\treturn {\n\n\t\thas: function ( name ) {\n\n\t\t\treturn getExtension( name ) !== null;\n\n\t\t},\n\n\t\tinit: function () {\n\n\t\t\tgetExtension( 'EXT_color_buffer_float' );\n\t\t\tgetExtension( 'WEBGL_clip_cull_distance' );\n\t\t\tgetExtension( 'OES_texture_float_linear' );\n\t\t\tgetExtension( 'EXT_color_buffer_half_float' );\n\t\t\tgetExtension( 'WEBGL_multisampled_render_to_texture' );\n\t\t\tgetExtension( 'WEBGL_render_shared_exponent' );\n\n\t\t},\n\n\t\tget: function ( name ) {\n\n\t\t\tconst extension = getExtension( name );\n\n\t\t\tif ( extension === null ) {\n\n\t\t\t\twarnOnce( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );\n\n\t\t\t}\n\n\t\t\treturn extension;\n\n\t\t}\n\n\t};\n\n}\n\nfunction WebGLGeometries( gl, attributes, info, bindingStates ) {\n\n\tconst geometries = {};\n\tconst wireframeAttributes = new WeakMap();\n\n\tfunction onGeometryDispose( event ) {\n\n\t\tconst geometry = event.target;\n\n\t\tif ( geometry.index !== null ) {\n\n\t\t\tattributes.remove( geometry.index );\n\n\t\t}\n\n\t\tfor ( const name in geometry.attributes ) {\n\n\t\t\tattributes.remove( geometry.attributes[ name ] );\n\n\t\t}\n\n\t\tfor ( const name in geometry.morphAttributes ) {\n\n\t\t\tconst array = geometry.morphAttributes[ name ];\n\n\t\t\tfor ( let i = 0, l = array.length; i < l; i ++ ) {\n\n\t\t\t\tattributes.remove( array[ i ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tgeometry.removeEventListener( 'dispose', onGeometryDispose );\n\n\t\tdelete geometries[ geometry.id ];\n\n\t\tconst attribute = wireframeAttributes.get( geometry );\n\n\t\tif ( attribute ) {\n\n\t\t\tattributes.remove( attribute );\n\t\t\twireframeAttributes.delete( geometry );\n\n\t\t}\n\n\t\tbindingStates.releaseStatesOfGeometry( geometry );\n\n\t\tif ( geometry.isInstancedBufferGeometry === true ) {\n\n\t\t\tdelete geometry._maxInstanceCount;\n\n\t\t}\n\n\t\t//\n\n\t\tinfo.memory.geometries --;\n\n\t}\n\n\tfunction get( object, geometry ) {\n\n\t\tif ( geometries[ geometry.id ] === true ) return geometry;\n\n\t\tgeometry.addEventListener( 'dispose', onGeometryDispose );\n\n\t\tgeometries[ geometry.id ] = true;\n\n\t\tinfo.memory.geometries ++;\n\n\t\treturn geometry;\n\n\t}\n\n\tfunction update( geometry ) {\n\n\t\tconst geometryAttributes = geometry.attributes;\n\n\t\t// Updating index buffer in VAO now. See WebGLBindingStates.\n\n\t\tfor ( const name in geometryAttributes ) {\n\n\t\t\tattributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );\n\n\t\t}\n\n\t\t// morph targets\n\n\t\tconst morphAttributes = geometry.morphAttributes;\n\n\t\tfor ( const name in morphAttributes ) {\n\n\t\t\tconst array = morphAttributes[ name ];\n\n\t\t\tfor ( let i = 0, l = array.length; i < l; i ++ ) {\n\n\t\t\t\tattributes.update( array[ i ], gl.ARRAY_BUFFER );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction updateWireframeAttribute( geometry ) {\n\n\t\tconst indices = [];\n\n\t\tconst geometryIndex = geometry.index;\n\t\tconst geometryPosition = geometry.attributes.position;\n\t\tlet version = 0;\n\n\t\tif ( geometryIndex !== null ) {\n\n\t\t\tconst array = geometryIndex.array;\n\t\t\tversion = geometryIndex.version;\n\n\t\t\tfor ( let i = 0, l = array.length; i < l; i += 3 ) {\n\n\t\t\t\tconst a = array[ i + 0 ];\n\t\t\t\tconst b = array[ i + 1 ];\n\t\t\t\tconst c = array[ i + 2 ];\n\n\t\t\t\tindices.push( a, b, b, c, c, a );\n\n\t\t\t}\n\n\t\t} else if ( geometryPosition !== undefined ) {\n\n\t\t\tconst array = geometryPosition.array;\n\t\t\tversion = geometryPosition.version;\n\n\t\t\tfor ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {\n\n\t\t\t\tconst a = i + 0;\n\t\t\t\tconst b = i + 1;\n\t\t\t\tconst c = i + 2;\n\n\t\t\t\tindices.push( a, b, b, c, c, a );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );\n\t\tattribute.version = version;\n\n\t\t// Updating index buffer in VAO now. See WebGLBindingStates\n\n\t\t//\n\n\t\tconst previousAttribute = wireframeAttributes.get( geometry );\n\n\t\tif ( previousAttribute ) attributes.remove( previousAttribute );\n\n\t\t//\n\n\t\twireframeAttributes.set( geometry, attribute );\n\n\t}\n\n\tfunction getWireframeAttribute( geometry ) {\n\n\t\tconst currentAttribute = wireframeAttributes.get( geometry );\n\n\t\tif ( currentAttribute ) {\n\n\t\t\tconst geometryIndex = geometry.index;\n\n\t\t\tif ( geometryIndex !== null ) {\n\n\t\t\t\t// if the attribute is obsolete, create a new one\n\n\t\t\t\tif ( currentAttribute.version < geometryIndex.version ) {\n\n\t\t\t\t\tupdateWireframeAttribute( geometry );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tupdateWireframeAttribute( geometry );\n\n\t\t}\n\n\t\treturn wireframeAttributes.get( geometry );\n\n\t}\n\n\treturn {\n\n\t\tget: get,\n\t\tupdate: update,\n\n\t\tgetWireframeAttribute: getWireframeAttribute\n\n\t};\n\n}\n\nfunction WebGLIndexedBufferRenderer( gl, extensions, info ) {\n\n\tlet mode;\n\n\tfunction setMode( value ) {\n\n\t\tmode = value;\n\n\t}\n\n\tlet type, bytesPerElement;\n\n\tfunction setIndex( value ) {\n\n\t\ttype = value.type;\n\t\tbytesPerElement = value.bytesPerElement;\n\n\t}\n\n\tfunction render( start, count ) {\n\n\t\tgl.drawElements( mode, count, type, start * bytesPerElement );\n\n\t\tinfo.update( count, mode, 1 );\n\n\t}\n\n\tfunction renderInstances( start, count, primcount ) {\n\n\t\tif ( primcount === 0 ) return;\n\n\t\tgl.drawElementsInstanced( mode, count, type, start * bytesPerElement, primcount );\n\n\t\tinfo.update( count, mode, primcount );\n\n\t}\n\n\tfunction renderMultiDraw( starts, counts, drawCount ) {\n\n\t\tif ( drawCount === 0 ) return;\n\n\t\tconst extension = extensions.get( 'WEBGL_multi_draw' );\n\t\textension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount );\n\n\t\tlet elementCount = 0;\n\t\tfor ( let i = 0; i < drawCount; i ++ ) {\n\n\t\t\telementCount += counts[ i ];\n\n\t\t}\n\n\t\tinfo.update( elementCount, mode, 1 );\n\n\n\t}\n\n\tfunction renderMultiDrawInstances( starts, counts, drawCount, primcount ) {\n\n\t\tif ( drawCount === 0 ) return;\n\n\t\tconst extension = extensions.get( 'WEBGL_multi_draw' );\n\n\t\tif ( extension === null ) {\n\n\t\t\tfor ( let i = 0; i < starts.length; i ++ ) {\n\n\t\t\t\trenderInstances( starts[ i ] / bytesPerElement, counts[ i ], primcount[ i ] );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\textension.multiDrawElementsInstancedWEBGL( mode, counts, 0, type, starts, 0, primcount, 0, drawCount );\n\n\t\t\tlet elementCount = 0;\n\t\t\tfor ( let i = 0; i < drawCount; i ++ ) {\n\n\t\t\t\telementCount += counts[ i ];\n\n\t\t\t}\n\n\t\t\tfor ( let i = 0; i < primcount.length; i ++ ) {\n\n\t\t\t\tinfo.update( elementCount, mode, primcount[ i ] );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t//\n\n\tthis.setMode = setMode;\n\tthis.setIndex = setIndex;\n\tthis.render = render;\n\tthis.renderInstances = renderInstances;\n\tthis.renderMultiDraw = renderMultiDraw;\n\tthis.renderMultiDrawInstances = renderMultiDrawInstances;\n\n}\n\nfunction WebGLInfo( gl ) {\n\n\tconst memory = {\n\t\tgeometries: 0,\n\t\ttextures: 0\n\t};\n\n\tconst render = {\n\t\tframe: 0,\n\t\tcalls: 0,\n\t\ttriangles: 0,\n\t\tpoints: 0,\n\t\tlines: 0\n\t};\n\n\tfunction update( count, mode, instanceCount ) {\n\n\t\trender.calls ++;\n\n\t\tswitch ( mode ) {\n\n\t\t\tcase gl.TRIANGLES:\n\t\t\t\trender.triangles += instanceCount * ( count / 3 );\n\t\t\t\tbreak;\n\n\t\t\tcase gl.LINES:\n\t\t\t\trender.lines += instanceCount * ( count / 2 );\n\t\t\t\tbreak;\n\n\t\t\tcase gl.LINE_STRIP:\n\t\t\t\trender.lines += instanceCount * ( count - 1 );\n\t\t\t\tbreak;\n\n\t\t\tcase gl.LINE_LOOP:\n\t\t\t\trender.lines += instanceCount * count;\n\t\t\t\tbreak;\n\n\t\t\tcase gl.POINTS:\n\t\t\t\trender.points += instanceCount * count;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tconsole.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\tfunction reset() {\n\n\t\trender.calls = 0;\n\t\trender.triangles = 0;\n\t\trender.points = 0;\n\t\trender.lines = 0;\n\n\t}\n\n\treturn {\n\t\tmemory: memory,\n\t\trender: render,\n\t\tprograms: null,\n\t\tautoReset: true,\n\t\treset: reset,\n\t\tupdate: update\n\t};\n\n}\n\nfunction WebGLMorphtargets( gl, capabilities, textures ) {\n\n\tconst morphTextures = new WeakMap();\n\tconst morph = new Vector4();\n\n\tfunction update( object, geometry, program ) {\n\n\t\tconst objectInfluences = object.morphTargetInfluences;\n\n\t\t// the following encodes morph targets into an array of data textures. Each layer represents a single morph target.\n\n\t\tconst morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;\n\t\tconst morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;\n\n\t\tlet entry = morphTextures.get( geometry );\n\n\t\tif ( entry === undefined || entry.count !== morphTargetsCount ) {\n\n\t\t\tif ( entry !== undefined ) entry.texture.dispose();\n\n\t\t\tconst hasMorphPosition = geometry.morphAttributes.position !== undefined;\n\t\t\tconst hasMorphNormals = geometry.morphAttributes.normal !== undefined;\n\t\t\tconst hasMorphColors = geometry.morphAttributes.color !== undefined;\n\n\t\t\tconst morphTargets = geometry.morphAttributes.position || [];\n\t\t\tconst morphNormals = geometry.morphAttributes.normal || [];\n\t\t\tconst morphColors = geometry.morphAttributes.color || [];\n\n\t\t\tlet vertexDataCount = 0;\n\n\t\t\tif ( hasMorphPosition === true ) vertexDataCount = 1;\n\t\t\tif ( hasMorphNormals === true ) vertexDataCount = 2;\n\t\t\tif ( hasMorphColors === true ) vertexDataCount = 3;\n\n\t\t\tlet width = geometry.attributes.position.count * vertexDataCount;\n\t\t\tlet height = 1;\n\n\t\t\tif ( width > capabilities.maxTextureSize ) {\n\n\t\t\t\theight = Math.ceil( width / capabilities.maxTextureSize );\n\t\t\t\twidth = capabilities.maxTextureSize;\n\n\t\t\t}\n\n\t\t\tconst buffer = new Float32Array( width * height * 4 * morphTargetsCount );\n\n\t\t\tconst texture = new DataArrayTexture( buffer, width, height, morphTargetsCount );\n\t\t\ttexture.type = FloatType;\n\t\t\ttexture.needsUpdate = true;\n\n\t\t\t// fill buffer\n\n\t\t\tconst vertexDataStride = vertexDataCount * 4;\n\n\t\t\tfor ( let i = 0; i < morphTargetsCount; i ++ ) {\n\n\t\t\t\tconst morphTarget = morphTargets[ i ];\n\t\t\t\tconst morphNormal = morphNormals[ i ];\n\t\t\t\tconst morphColor = morphColors[ i ];\n\n\t\t\t\tconst offset = width * height * 4 * i;\n\n\t\t\t\tfor ( let j = 0; j < morphTarget.count; j ++ ) {\n\n\t\t\t\t\tconst stride = j * vertexDataStride;\n\n\t\t\t\t\tif ( hasMorphPosition === true ) {\n\n\t\t\t\t\t\tmorph.fromBufferAttribute( morphTarget, j );\n\n\t\t\t\t\t\tbuffer[ offset + stride + 0 ] = morph.x;\n\t\t\t\t\t\tbuffer[ offset + stride + 1 ] = morph.y;\n\t\t\t\t\t\tbuffer[ offset + stride + 2 ] = morph.z;\n\t\t\t\t\t\tbuffer[ offset + stride + 3 ] = 0;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( hasMorphNormals === true ) {\n\n\t\t\t\t\t\tmorph.fromBufferAttribute( morphNormal, j );\n\n\t\t\t\t\t\tbuffer[ offset + stride + 4 ] = morph.x;\n\t\t\t\t\t\tbuffer[ offset + stride + 5 ] = morph.y;\n\t\t\t\t\t\tbuffer[ offset + stride + 6 ] = morph.z;\n\t\t\t\t\t\tbuffer[ offset + stride + 7 ] = 0;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( hasMorphColors === true ) {\n\n\t\t\t\t\t\tmorph.fromBufferAttribute( morphColor, j );\n\n\t\t\t\t\t\tbuffer[ offset + stride + 8 ] = morph.x;\n\t\t\t\t\t\tbuffer[ offset + stride + 9 ] = morph.y;\n\t\t\t\t\t\tbuffer[ offset + stride + 10 ] = morph.z;\n\t\t\t\t\t\tbuffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tentry = {\n\t\t\t\tcount: morphTargetsCount,\n\t\t\t\ttexture: texture,\n\t\t\t\tsize: new Vector2( width, height )\n\t\t\t};\n\n\t\t\tmorphTextures.set( geometry, entry );\n\n\t\t\tfunction disposeTexture() {\n\n\t\t\t\ttexture.dispose();\n\n\t\t\t\tmorphTextures.delete( geometry );\n\n\t\t\t\tgeometry.removeEventListener( 'dispose', disposeTexture );\n\n\t\t\t}\n\n\t\t\tgeometry.addEventListener( 'dispose', disposeTexture );\n\n\t\t}\n\n\t\t//\n\t\tif ( object.isInstancedMesh === true && object.morphTexture !== null ) {\n\n\t\t\tprogram.getUniforms().setValue( gl, 'morphTexture', object.morphTexture, textures );\n\n\t\t} else {\n\n\t\t\tlet morphInfluencesSum = 0;\n\n\t\t\tfor ( let i = 0; i < objectInfluences.length; i ++ ) {\n\n\t\t\t\tmorphInfluencesSum += objectInfluences[ i ];\n\n\t\t\t}\n\n\t\t\tconst morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;\n\n\n\t\t\tprogram.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );\n\t\t\tprogram.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences );\n\n\t\t}\n\n\t\tprogram.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures );\n\t\tprogram.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size );\n\n\t}\n\n\treturn {\n\n\t\tupdate: update\n\n\t};\n\n}\n\nfunction WebGLObjects( gl, geometries, attributes, info ) {\n\n\tlet updateMap = new WeakMap();\n\n\tfunction update( object ) {\n\n\t\tconst frame = info.render.frame;\n\n\t\tconst geometry = object.geometry;\n\t\tconst buffergeometry = geometries.get( object, geometry );\n\n\t\t// Update once per frame\n\n\t\tif ( updateMap.get( buffergeometry ) !== frame ) {\n\n\t\t\tgeometries.update( buffergeometry );\n\n\t\t\tupdateMap.set( buffergeometry, frame );\n\n\t\t}\n\n\t\tif ( object.isInstancedMesh ) {\n\n\t\t\tif ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) {\n\n\t\t\t\tobject.addEventListener( 'dispose', onInstancedMeshDispose );\n\n\t\t\t}\n\n\t\t\tif ( updateMap.get( object ) !== frame ) {\n\n\t\t\t\tattributes.update( object.instanceMatrix, gl.ARRAY_BUFFER );\n\n\t\t\t\tif ( object.instanceColor !== null ) {\n\n\t\t\t\t\tattributes.update( object.instanceColor, gl.ARRAY_BUFFER );\n\n\t\t\t\t}\n\n\t\t\t\tupdateMap.set( object, frame );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( object.isSkinnedMesh ) {\n\n\t\t\tconst skeleton = object.skeleton;\n\n\t\t\tif ( updateMap.get( skeleton ) !== frame ) {\n\n\t\t\t\tskeleton.update();\n\n\t\t\t\tupdateMap.set( skeleton, frame );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn buffergeometry;\n\n\t}\n\n\tfunction dispose() {\n\n\t\tupdateMap = new WeakMap();\n\n\t}\n\n\tfunction onInstancedMeshDispose( event ) {\n\n\t\tconst instancedMesh = event.target;\n\n\t\tinstancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );\n\n\t\tattributes.remove( instancedMesh.instanceMatrix );\n\n\t\tif ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );\n\n\t}\n\n\treturn {\n\n\t\tupdate: update,\n\t\tdispose: dispose\n\n\t};\n\n}\n\nclass DepthTexture extends Texture {\n\n\tconstructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format = DepthFormat ) {\n\n\t\tif ( format !== DepthFormat && format !== DepthStencilFormat ) {\n\n\t\t\tthrow new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );\n\n\t\t}\n\n\t\tif ( type === undefined && format === DepthFormat ) type = UnsignedIntType;\n\t\tif ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;\n\n\t\tsuper( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\t\tthis.isDepthTexture = true;\n\n\t\tthis.image = { width: width, height: height };\n\n\t\tthis.magFilter = magFilter !== undefined ? magFilter : NearestFilter;\n\t\tthis.minFilter = minFilter !== undefined ? minFilter : NearestFilter;\n\n\t\tthis.flipY = false;\n\t\tthis.generateMipmaps = false;\n\n\t\tthis.compareFunction = null;\n\n\t}\n\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.compareFunction = source.compareFunction;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tif ( this.compareFunction !== null ) data.compareFunction = this.compareFunction;\n\n\t\treturn data;\n\n\t}\n\n}\n\n/**\n * Uniforms of a program.\n * Those form a tree structure with a special top-level container for the root,\n * which you get by calling 'new WebGLUniforms( gl, program )'.\n *\n *\n * Properties of inner nodes including the top-level container:\n *\n * .seq - array of nested uniforms\n * .map - nested uniforms by name\n *\n *\n * Methods of all nodes except the top-level container:\n *\n * .setValue( gl, value, [textures] )\n *\n * \t\tuploads a uniform value(s)\n * \tthe 'textures' parameter is needed for sampler uniforms\n *\n *\n * Static methods of the top-level container (textures factorizations):\n *\n * .upload( gl, seq, values, textures )\n *\n * \t\tsets uniforms in 'seq' to 'values[id].value'\n *\n * .seqWithValue( seq, values ) : filteredSeq\n *\n * \t\tfilters 'seq' entries with corresponding entry in values\n *\n *\n * Methods of the top-level container (textures factorizations):\n *\n * .setValue( gl, name, value, textures )\n *\n * \t\tsets uniform with name 'name' to 'value'\n *\n * .setOptional( gl, obj, prop )\n *\n * \t\tlike .set for an optional property of the object\n *\n */\n\n\nconst emptyTexture = /*@__PURE__*/ new Texture();\n\nconst emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 );\n\nconst emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture();\nconst empty3dTexture = /*@__PURE__*/ new Data3DTexture();\nconst emptyCubeTexture = /*@__PURE__*/ new CubeTexture();\n\n// --- Utilities ---\n\n// Array Caches (provide typed arrays for temporary by size)\n\nconst arrayCacheF32 = [];\nconst arrayCacheI32 = [];\n\n// Float32Array caches used for uploading Matrix uniforms\n\nconst mat4array = new Float32Array( 16 );\nconst mat3array = new Float32Array( 9 );\nconst mat2array = new Float32Array( 4 );\n\n// Flattening for arrays of vectors and matrices\n\nfunction flatten( array, nBlocks, blockSize ) {\n\n\tconst firstElem = array[ 0 ];\n\n\tif ( firstElem <= 0 || firstElem > 0 ) return array;\n\t// unoptimized: ! isNaN( firstElem )\n\t// see http://jacksondunstan.com/articles/983\n\n\tconst n = nBlocks * blockSize;\n\tlet r = arrayCacheF32[ n ];\n\n\tif ( r === undefined ) {\n\n\t\tr = new Float32Array( n );\n\t\tarrayCacheF32[ n ] = r;\n\n\t}\n\n\tif ( nBlocks !== 0 ) {\n\n\t\tfirstElem.toArray( r, 0 );\n\n\t\tfor ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {\n\n\t\t\toffset += blockSize;\n\t\t\tarray[ i ].toArray( r, offset );\n\n\t\t}\n\n\t}\n\n\treturn r;\n\n}\n\nfunction arraysEqual( a, b ) {\n\n\tif ( a.length !== b.length ) return false;\n\n\tfor ( let i = 0, l = a.length; i < l; i ++ ) {\n\n\t\tif ( a[ i ] !== b[ i ] ) return false;\n\n\t}\n\n\treturn true;\n\n}\n\nfunction copyArray( a, b ) {\n\n\tfor ( let i = 0, l = b.length; i < l; i ++ ) {\n\n\t\ta[ i ] = b[ i ];\n\n\t}\n\n}\n\n// Texture unit allocation\n\nfunction allocTexUnits( textures, n ) {\n\n\tlet r = arrayCacheI32[ n ];\n\n\tif ( r === undefined ) {\n\n\t\tr = new Int32Array( n );\n\t\tarrayCacheI32[ n ] = r;\n\n\t}\n\n\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\tr[ i ] = textures.allocateTextureUnit();\n\n\t}\n\n\treturn r;\n\n}\n\n// --- Setters ---\n\n// Note: Defining these methods externally, because they come in a bunch\n// and this way their names minify.\n\n// Single scalar\n\nfunction setValueV1f( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( cache[ 0 ] === v ) return;\n\n\tgl.uniform1f( this.addr, v );\n\n\tcache[ 0 ] = v;\n\n}\n\n// Single float vector (from flat array or THREE.VectorN)\n\nfunction setValueV2f( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {\n\n\t\t\tgl.uniform2f( this.addr, v.x, v.y );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform2fv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV3f( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {\n\n\t\t\tgl.uniform3f( this.addr, v.x, v.y, v.z );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\n\t\t}\n\n\t} else if ( v.r !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {\n\n\t\t\tgl.uniform3f( this.addr, v.r, v.g, v.b );\n\n\t\t\tcache[ 0 ] = v.r;\n\t\t\tcache[ 1 ] = v.g;\n\t\t\tcache[ 2 ] = v.b;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform3fv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV4f( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {\n\n\t\t\tgl.uniform4f( this.addr, v.x, v.y, v.z, v.w );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\t\t\tcache[ 3 ] = v.w;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform4fv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\n// Single matrix (from flat array or THREE.MatrixN)\n\nfunction setValueM2( gl, v ) {\n\n\tconst cache = this.cache;\n\tconst elements = v.elements;\n\n\tif ( elements === undefined ) {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniformMatrix2fv( this.addr, false, v );\n\n\t\tcopyArray( cache, v );\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, elements ) ) return;\n\n\t\tmat2array.set( elements );\n\n\t\tgl.uniformMatrix2fv( this.addr, false, mat2array );\n\n\t\tcopyArray( cache, elements );\n\n\t}\n\n}\n\nfunction setValueM3( gl, v ) {\n\n\tconst cache = this.cache;\n\tconst elements = v.elements;\n\n\tif ( elements === undefined ) {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniformMatrix3fv( this.addr, false, v );\n\n\t\tcopyArray( cache, v );\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, elements ) ) return;\n\n\t\tmat3array.set( elements );\n\n\t\tgl.uniformMatrix3fv( this.addr, false, mat3array );\n\n\t\tcopyArray( cache, elements );\n\n\t}\n\n}\n\nfunction setValueM4( gl, v ) {\n\n\tconst cache = this.cache;\n\tconst elements = v.elements;\n\n\tif ( elements === undefined ) {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniformMatrix4fv( this.addr, false, v );\n\n\t\tcopyArray( cache, v );\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, elements ) ) return;\n\n\t\tmat4array.set( elements );\n\n\t\tgl.uniformMatrix4fv( this.addr, false, mat4array );\n\n\t\tcopyArray( cache, elements );\n\n\t}\n\n}\n\n// Single integer / boolean\n\nfunction setValueV1i( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( cache[ 0 ] === v ) return;\n\n\tgl.uniform1i( this.addr, v );\n\n\tcache[ 0 ] = v;\n\n}\n\n// Single integer / boolean vector (from flat array or THREE.VectorN)\n\nfunction setValueV2i( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {\n\n\t\t\tgl.uniform2i( this.addr, v.x, v.y );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform2iv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV3i( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {\n\n\t\t\tgl.uniform3i( this.addr, v.x, v.y, v.z );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform3iv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV4i( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {\n\n\t\t\tgl.uniform4i( this.addr, v.x, v.y, v.z, v.w );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\t\t\tcache[ 3 ] = v.w;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform4iv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\n// Single unsigned integer\n\nfunction setValueV1ui( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( cache[ 0 ] === v ) return;\n\n\tgl.uniform1ui( this.addr, v );\n\n\tcache[ 0 ] = v;\n\n}\n\n// Single unsigned integer vector (from flat array or THREE.VectorN)\n\nfunction setValueV2ui( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {\n\n\t\t\tgl.uniform2ui( this.addr, v.x, v.y );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform2uiv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV3ui( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {\n\n\t\t\tgl.uniform3ui( this.addr, v.x, v.y, v.z );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform3uiv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV4ui( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {\n\n\t\t\tgl.uniform4ui( this.addr, v.x, v.y, v.z, v.w );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\t\t\tcache[ 3 ] = v.w;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform4uiv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\n\n// Single texture (2D / Cube)\n\nfunction setValueT1( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\tconst unit = textures.allocateTextureUnit();\n\n\tif ( cache[ 0 ] !== unit ) {\n\n\t\tgl.uniform1i( this.addr, unit );\n\t\tcache[ 0 ] = unit;\n\n\t}\n\n\tlet emptyTexture2D;\n\n\tif ( this.type === gl.SAMPLER_2D_SHADOW ) {\n\n\t\temptyShadowTexture.compareFunction = LessEqualCompare; // #28670\n\t\temptyTexture2D = emptyShadowTexture;\n\n\t} else {\n\n\t\temptyTexture2D = emptyTexture;\n\n\t}\n\n\ttextures.setTexture2D( v || emptyTexture2D, unit );\n\n}\n\nfunction setValueT3D1( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\tconst unit = textures.allocateTextureUnit();\n\n\tif ( cache[ 0 ] !== unit ) {\n\n\t\tgl.uniform1i( this.addr, unit );\n\t\tcache[ 0 ] = unit;\n\n\t}\n\n\ttextures.setTexture3D( v || empty3dTexture, unit );\n\n}\n\nfunction setValueT6( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\tconst unit = textures.allocateTextureUnit();\n\n\tif ( cache[ 0 ] !== unit ) {\n\n\t\tgl.uniform1i( this.addr, unit );\n\t\tcache[ 0 ] = unit;\n\n\t}\n\n\ttextures.setTextureCube( v || emptyCubeTexture, unit );\n\n}\n\nfunction setValueT2DArray1( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\tconst unit = textures.allocateTextureUnit();\n\n\tif ( cache[ 0 ] !== unit ) {\n\n\t\tgl.uniform1i( this.addr, unit );\n\t\tcache[ 0 ] = unit;\n\n\t}\n\n\ttextures.setTexture2DArray( v || emptyArrayTexture, unit );\n\n}\n\n// Helper to pick the right setter for the singular case\n\nfunction getSingularSetter( type ) {\n\n\tswitch ( type ) {\n\n\t\tcase 0x1406: return setValueV1f; // FLOAT\n\t\tcase 0x8b50: return setValueV2f; // _VEC2\n\t\tcase 0x8b51: return setValueV3f; // _VEC3\n\t\tcase 0x8b52: return setValueV4f; // _VEC4\n\n\t\tcase 0x8b5a: return setValueM2; // _MAT2\n\t\tcase 0x8b5b: return setValueM3; // _MAT3\n\t\tcase 0x8b5c: return setValueM4; // _MAT4\n\n\t\tcase 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL\n\t\tcase 0x8b53: case 0x8b57: return setValueV2i; // _VEC2\n\t\tcase 0x8b54: case 0x8b58: return setValueV3i; // _VEC3\n\t\tcase 0x8b55: case 0x8b59: return setValueV4i; // _VEC4\n\n\t\tcase 0x1405: return setValueV1ui; // UINT\n\t\tcase 0x8dc6: return setValueV2ui; // _VEC2\n\t\tcase 0x8dc7: return setValueV3ui; // _VEC3\n\t\tcase 0x8dc8: return setValueV4ui; // _VEC4\n\n\t\tcase 0x8b5e: // SAMPLER_2D\n\t\tcase 0x8d66: // SAMPLER_EXTERNAL_OES\n\t\tcase 0x8dca: // INT_SAMPLER_2D\n\t\tcase 0x8dd2: // UNSIGNED_INT_SAMPLER_2D\n\t\tcase 0x8b62: // SAMPLER_2D_SHADOW\n\t\t\treturn setValueT1;\n\n\t\tcase 0x8b5f: // SAMPLER_3D\n\t\tcase 0x8dcb: // INT_SAMPLER_3D\n\t\tcase 0x8dd3: // UNSIGNED_INT_SAMPLER_3D\n\t\t\treturn setValueT3D1;\n\n\t\tcase 0x8b60: // SAMPLER_CUBE\n\t\tcase 0x8dcc: // INT_SAMPLER_CUBE\n\t\tcase 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE\n\t\tcase 0x8dc5: // SAMPLER_CUBE_SHADOW\n\t\t\treturn setValueT6;\n\n\t\tcase 0x8dc1: // SAMPLER_2D_ARRAY\n\t\tcase 0x8dcf: // INT_SAMPLER_2D_ARRAY\n\t\tcase 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY\n\t\tcase 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW\n\t\t\treturn setValueT2DArray1;\n\n\t}\n\n}\n\n\n// Array of scalars\n\nfunction setValueV1fArray( gl, v ) {\n\n\tgl.uniform1fv( this.addr, v );\n\n}\n\n// Array of vectors (from flat array or array of THREE.VectorN)\n\nfunction setValueV2fArray( gl, v ) {\n\n\tconst data = flatten( v, this.size, 2 );\n\n\tgl.uniform2fv( this.addr, data );\n\n}\n\nfunction setValueV3fArray( gl, v ) {\n\n\tconst data = flatten( v, this.size, 3 );\n\n\tgl.uniform3fv( this.addr, data );\n\n}\n\nfunction setValueV4fArray( gl, v ) {\n\n\tconst data = flatten( v, this.size, 4 );\n\n\tgl.uniform4fv( this.addr, data );\n\n}\n\n// Array of matrices (from flat array or array of THREE.MatrixN)\n\nfunction setValueM2Array( gl, v ) {\n\n\tconst data = flatten( v, this.size, 4 );\n\n\tgl.uniformMatrix2fv( this.addr, false, data );\n\n}\n\nfunction setValueM3Array( gl, v ) {\n\n\tconst data = flatten( v, this.size, 9 );\n\n\tgl.uniformMatrix3fv( this.addr, false, data );\n\n}\n\nfunction setValueM4Array( gl, v ) {\n\n\tconst data = flatten( v, this.size, 16 );\n\n\tgl.uniformMatrix4fv( this.addr, false, data );\n\n}\n\n// Array of integer / boolean\n\nfunction setValueV1iArray( gl, v ) {\n\n\tgl.uniform1iv( this.addr, v );\n\n}\n\n// Array of integer / boolean vectors (from flat array)\n\nfunction setValueV2iArray( gl, v ) {\n\n\tgl.uniform2iv( this.addr, v );\n\n}\n\nfunction setValueV3iArray( gl, v ) {\n\n\tgl.uniform3iv( this.addr, v );\n\n}\n\nfunction setValueV4iArray( gl, v ) {\n\n\tgl.uniform4iv( this.addr, v );\n\n}\n\n// Array of unsigned integer\n\nfunction setValueV1uiArray( gl, v ) {\n\n\tgl.uniform1uiv( this.addr, v );\n\n}\n\n// Array of unsigned integer vectors (from flat array)\n\nfunction setValueV2uiArray( gl, v ) {\n\n\tgl.uniform2uiv( this.addr, v );\n\n}\n\nfunction setValueV3uiArray( gl, v ) {\n\n\tgl.uniform3uiv( this.addr, v );\n\n}\n\nfunction setValueV4uiArray( gl, v ) {\n\n\tgl.uniform4uiv( this.addr, v );\n\n}\n\n\n// Array of textures (2D / 3D / Cube / 2DArray)\n\nfunction setValueT1Array( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\n\tconst n = v.length;\n\n\tconst units = allocTexUnits( textures, n );\n\n\tif ( ! arraysEqual( cache, units ) ) {\n\n\t\tgl.uniform1iv( this.addr, units );\n\n\t\tcopyArray( cache, units );\n\n\t}\n\n\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\ttextures.setTexture2D( v[ i ] || emptyTexture, units[ i ] );\n\n\t}\n\n}\n\nfunction setValueT3DArray( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\n\tconst n = v.length;\n\n\tconst units = allocTexUnits( textures, n );\n\n\tif ( ! arraysEqual( cache, units ) ) {\n\n\t\tgl.uniform1iv( this.addr, units );\n\n\t\tcopyArray( cache, units );\n\n\t}\n\n\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\ttextures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] );\n\n\t}\n\n}\n\nfunction setValueT6Array( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\n\tconst n = v.length;\n\n\tconst units = allocTexUnits( textures, n );\n\n\tif ( ! arraysEqual( cache, units ) ) {\n\n\t\tgl.uniform1iv( this.addr, units );\n\n\t\tcopyArray( cache, units );\n\n\t}\n\n\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\ttextures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );\n\n\t}\n\n}\n\nfunction setValueT2DArrayArray( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\n\tconst n = v.length;\n\n\tconst units = allocTexUnits( textures, n );\n\n\tif ( ! arraysEqual( cache, units ) ) {\n\n\t\tgl.uniform1iv( this.addr, units );\n\n\t\tcopyArray( cache, units );\n\n\t}\n\n\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\ttextures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] );\n\n\t}\n\n}\n\n\n// Helper to pick the right setter for a pure (bottom-level) array\n\nfunction getPureArraySetter( type ) {\n\n\tswitch ( type ) {\n\n\t\tcase 0x1406: return setValueV1fArray; // FLOAT\n\t\tcase 0x8b50: return setValueV2fArray; // _VEC2\n\t\tcase 0x8b51: return setValueV3fArray; // _VEC3\n\t\tcase 0x8b52: return setValueV4fArray; // _VEC4\n\n\t\tcase 0x8b5a: return setValueM2Array; // _MAT2\n\t\tcase 0x8b5b: return setValueM3Array; // _MAT3\n\t\tcase 0x8b5c: return setValueM4Array; // _MAT4\n\n\t\tcase 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL\n\t\tcase 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2\n\t\tcase 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3\n\t\tcase 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4\n\n\t\tcase 0x1405: return setValueV1uiArray; // UINT\n\t\tcase 0x8dc6: return setValueV2uiArray; // _VEC2\n\t\tcase 0x8dc7: return setValueV3uiArray; // _VEC3\n\t\tcase 0x8dc8: return setValueV4uiArray; // _VEC4\n\n\t\tcase 0x8b5e: // SAMPLER_2D\n\t\tcase 0x8d66: // SAMPLER_EXTERNAL_OES\n\t\tcase 0x8dca: // INT_SAMPLER_2D\n\t\tcase 0x8dd2: // UNSIGNED_INT_SAMPLER_2D\n\t\tcase 0x8b62: // SAMPLER_2D_SHADOW\n\t\t\treturn setValueT1Array;\n\n\t\tcase 0x8b5f: // SAMPLER_3D\n\t\tcase 0x8dcb: // INT_SAMPLER_3D\n\t\tcase 0x8dd3: // UNSIGNED_INT_SAMPLER_3D\n\t\t\treturn setValueT3DArray;\n\n\t\tcase 0x8b60: // SAMPLER_CUBE\n\t\tcase 0x8dcc: // INT_SAMPLER_CUBE\n\t\tcase 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE\n\t\tcase 0x8dc5: // SAMPLER_CUBE_SHADOW\n\t\t\treturn setValueT6Array;\n\n\t\tcase 0x8dc1: // SAMPLER_2D_ARRAY\n\t\tcase 0x8dcf: // INT_SAMPLER_2D_ARRAY\n\t\tcase 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY\n\t\tcase 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW\n\t\t\treturn setValueT2DArrayArray;\n\n\t}\n\n}\n\n// --- Uniform Classes ---\n\nclass SingleUniform {\n\n\tconstructor( id, activeInfo, addr ) {\n\n\t\tthis.id = id;\n\t\tthis.addr = addr;\n\t\tthis.cache = [];\n\t\tthis.type = activeInfo.type;\n\t\tthis.setValue = getSingularSetter( activeInfo.type );\n\n\t\t// this.path = activeInfo.name; // DEBUG\n\n\t}\n\n}\n\nclass PureArrayUniform {\n\n\tconstructor( id, activeInfo, addr ) {\n\n\t\tthis.id = id;\n\t\tthis.addr = addr;\n\t\tthis.cache = [];\n\t\tthis.type = activeInfo.type;\n\t\tthis.size = activeInfo.size;\n\t\tthis.setValue = getPureArraySetter( activeInfo.type );\n\n\t\t// this.path = activeInfo.name; // DEBUG\n\n\t}\n\n}\n\nclass StructuredUniform {\n\n\tconstructor( id ) {\n\n\t\tthis.id = id;\n\n\t\tthis.seq = [];\n\t\tthis.map = {};\n\n\t}\n\n\tsetValue( gl, value, textures ) {\n\n\t\tconst seq = this.seq;\n\n\t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\t\tconst u = seq[ i ];\n\t\t\tu.setValue( gl, value[ u.id ], textures );\n\n\t\t}\n\n\t}\n\n}\n\n// --- Top-level ---\n\n// Parser - builds up the property tree from the path strings\n\nconst RePathPart = /(\\w+)(\\])?(\\[|\\.)?/g;\n\n// extracts\n// \t- the identifier (member name or array index)\n// - followed by an optional right bracket (found when array index)\n// - followed by an optional left bracket or dot (type of subscript)\n//\n// Note: These portions can be read in a non-overlapping fashion and\n// allow straightforward parsing of the hierarchy that WebGL encodes\n// in the uniform names.\n\nfunction addUniform( container, uniformObject ) {\n\n\tcontainer.seq.push( uniformObject );\n\tcontainer.map[ uniformObject.id ] = uniformObject;\n\n}\n\nfunction parseUniform( activeInfo, addr, container ) {\n\n\tconst path = activeInfo.name,\n\t\tpathLength = path.length;\n\n\t// reset RegExp object, because of the early exit of a previous run\n\tRePathPart.lastIndex = 0;\n\n\twhile ( true ) {\n\n\t\tconst match = RePathPart.exec( path ),\n\t\t\tmatchEnd = RePathPart.lastIndex;\n\n\t\tlet id = match[ 1 ];\n\t\tconst idIsIndex = match[ 2 ] === ']',\n\t\t\tsubscript = match[ 3 ];\n\n\t\tif ( idIsIndex ) id = id | 0; // convert to integer\n\n\t\tif ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {\n\n\t\t\t// bare name or \"pure\" bottom-level array \"[0]\" suffix\n\n\t\t\taddUniform( container, subscript === undefined ?\n\t\t\t\tnew SingleUniform( id, activeInfo, addr ) :\n\t\t\t\tnew PureArrayUniform( id, activeInfo, addr ) );\n\n\t\t\tbreak;\n\n\t\t} else {\n\n\t\t\t// step into inner node / create it in case it doesn't exist\n\n\t\t\tconst map = container.map;\n\t\t\tlet next = map[ id ];\n\n\t\t\tif ( next === undefined ) {\n\n\t\t\t\tnext = new StructuredUniform( id );\n\t\t\t\taddUniform( container, next );\n\n\t\t\t}\n\n\t\t\tcontainer = next;\n\n\t\t}\n\n\t}\n\n}\n\n// Root Container\n\nclass WebGLUniforms {\n\n\tconstructor( gl, program ) {\n\n\t\tthis.seq = [];\n\t\tthis.map = {};\n\n\t\tconst n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );\n\n\t\tfor ( let i = 0; i < n; ++ i ) {\n\n\t\t\tconst info = gl.getActiveUniform( program, i ),\n\t\t\t\taddr = gl.getUniformLocation( program, info.name );\n\n\t\t\tparseUniform( info, addr, this );\n\n\t\t}\n\n\t}\n\n\tsetValue( gl, name, value, textures ) {\n\n\t\tconst u = this.map[ name ];\n\n\t\tif ( u !== undefined ) u.setValue( gl, value, textures );\n\n\t}\n\n\tsetOptional( gl, object, name ) {\n\n\t\tconst v = object[ name ];\n\n\t\tif ( v !== undefined ) this.setValue( gl, name, v );\n\n\t}\n\n\tstatic upload( gl, seq, values, textures ) {\n\n\t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\t\tconst u = seq[ i ],\n\t\t\t\tv = values[ u.id ];\n\n\t\t\tif ( v.needsUpdate !== false ) {\n\n\t\t\t\t// note: always updating when .needsUpdate is undefined\n\t\t\t\tu.setValue( gl, v.value, textures );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic seqWithValue( seq, values ) {\n\n\t\tconst r = [];\n\n\t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\t\tconst u = seq[ i ];\n\t\t\tif ( u.id in values ) r.push( u );\n\n\t\t}\n\n\t\treturn r;\n\n\t}\n\n}\n\nfunction WebGLShader( gl, type, string ) {\n\n\tconst shader = gl.createShader( type );\n\n\tgl.shaderSource( shader, string );\n\tgl.compileShader( shader );\n\n\treturn shader;\n\n}\n\n// From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/\nconst COMPLETION_STATUS_KHR = 0x91B1;\n\nlet programIdCount = 0;\n\nfunction handleSource( string, errorLine ) {\n\n\tconst lines = string.split( '\\n' );\n\tconst lines2 = [];\n\n\tconst from = Math.max( errorLine - 6, 0 );\n\tconst to = Math.min( errorLine + 6, lines.length );\n\n\tfor ( let i = from; i < to; i ++ ) {\n\n\t\tconst line = i + 1;\n\t\tlines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` );\n\n\t}\n\n\treturn lines2.join( '\\n' );\n\n}\n\nfunction getEncodingComponents( colorSpace ) {\n\n\tconst workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );\n\tconst encodingPrimaries = ColorManagement.getPrimaries( colorSpace );\n\n\tlet gamutMapping;\n\n\tif ( workingPrimaries === encodingPrimaries ) {\n\n\t\tgamutMapping = '';\n\n\t} else if ( workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries ) {\n\n\t\tgamutMapping = 'LinearDisplayP3ToLinearSRGB';\n\n\t} else if ( workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries ) {\n\n\t\tgamutMapping = 'LinearSRGBToLinearDisplayP3';\n\n\t}\n\n\tswitch ( colorSpace ) {\n\n\t\tcase LinearSRGBColorSpace:\n\t\tcase LinearDisplayP3ColorSpace:\n\t\t\treturn [ gamutMapping, 'LinearTransferOETF' ];\n\n\t\tcase SRGBColorSpace:\n\t\tcase DisplayP3ColorSpace:\n\t\t\treturn [ gamutMapping, 'sRGBTransferOETF' ];\n\n\t\tdefault:\n\t\t\tconsole.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace );\n\t\t\treturn [ gamutMapping, 'LinearTransferOETF' ];\n\n\t}\n\n}\n\nfunction getShaderErrors( gl, shader, type ) {\n\n\tconst status = gl.getShaderParameter( shader, gl.COMPILE_STATUS );\n\tconst errors = gl.getShaderInfoLog( shader ).trim();\n\n\tif ( status && errors === '' ) return '';\n\n\tconst errorMatches = /ERROR: 0:(\\d+)/.exec( errors );\n\tif ( errorMatches ) {\n\n\t\t// --enable-privileged-webgl-extension\n\t\t// console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );\n\n\t\tconst errorLine = parseInt( errorMatches[ 1 ] );\n\t\treturn type.toUpperCase() + '\\n\\n' + errors + '\\n\\n' + handleSource( gl.getShaderSource( shader ), errorLine );\n\n\t} else {\n\n\t\treturn errors;\n\n\t}\n\n}\n\nfunction getTexelEncodingFunction( functionName, colorSpace ) {\n\n\tconst components = getEncodingComponents( colorSpace );\n\treturn `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`;\n\n}\n\nfunction getToneMappingFunction( functionName, toneMapping ) {\n\n\tlet toneMappingName;\n\n\tswitch ( toneMapping ) {\n\n\t\tcase LinearToneMapping:\n\t\t\ttoneMappingName = 'Linear';\n\t\t\tbreak;\n\n\t\tcase ReinhardToneMapping:\n\t\t\ttoneMappingName = 'Reinhard';\n\t\t\tbreak;\n\n\t\tcase CineonToneMapping:\n\t\t\ttoneMappingName = 'OptimizedCineon';\n\t\t\tbreak;\n\n\t\tcase ACESFilmicToneMapping:\n\t\t\ttoneMappingName = 'ACESFilmic';\n\t\t\tbreak;\n\n\t\tcase AgXToneMapping:\n\t\t\ttoneMappingName = 'AgX';\n\t\t\tbreak;\n\n\t\tcase NeutralToneMapping:\n\t\t\ttoneMappingName = 'Neutral';\n\t\t\tbreak;\n\n\t\tcase CustomToneMapping:\n\t\t\ttoneMappingName = 'Custom';\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tconsole.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );\n\t\t\ttoneMappingName = 'Linear';\n\n\t}\n\n\treturn 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';\n\n}\n\nfunction generateVertexExtensions( parameters ) {\n\n\tconst chunks = [\n\t\tparameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '',\n\t\tparameters.extensionMultiDraw ? '#extension GL_ANGLE_multi_draw : require' : '',\n\t];\n\n\treturn chunks.filter( filterEmptyLine ).join( '\\n' );\n\n}\n\nfunction generateDefines( defines ) {\n\n\tconst chunks = [];\n\n\tfor ( const name in defines ) {\n\n\t\tconst value = defines[ name ];\n\n\t\tif ( value === false ) continue;\n\n\t\tchunks.push( '#define ' + name + ' ' + value );\n\n\t}\n\n\treturn chunks.join( '\\n' );\n\n}\n\nfunction fetchAttributeLocations( gl, program ) {\n\n\tconst attributes = {};\n\n\tconst n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );\n\n\tfor ( let i = 0; i < n; i ++ ) {\n\n\t\tconst info = gl.getActiveAttrib( program, i );\n\t\tconst name = info.name;\n\n\t\tlet locationSize = 1;\n\t\tif ( info.type === gl.FLOAT_MAT2 ) locationSize = 2;\n\t\tif ( info.type === gl.FLOAT_MAT3 ) locationSize = 3;\n\t\tif ( info.type === gl.FLOAT_MAT4 ) locationSize = 4;\n\n\t\t// console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );\n\n\t\tattributes[ name ] = {\n\t\t\ttype: info.type,\n\t\t\tlocation: gl.getAttribLocation( program, name ),\n\t\t\tlocationSize: locationSize\n\t\t};\n\n\t}\n\n\treturn attributes;\n\n}\n\nfunction filterEmptyLine( string ) {\n\n\treturn string !== '';\n\n}\n\nfunction replaceLightNums( string, parameters ) {\n\n\tconst numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps;\n\n\treturn string\n\t\t.replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )\n\t\t.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )\n\t\t.replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps )\n\t\t.replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords )\n\t\t.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )\n\t\t.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )\n\t\t.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )\n\t\t.replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )\n\t\t.replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps )\n\t\t.replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )\n\t\t.replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );\n\n}\n\nfunction replaceClippingPlaneNums( string, parameters ) {\n\n\treturn string\n\t\t.replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )\n\t\t.replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );\n\n}\n\n// Resolve Includes\n\nconst includePattern = /^[ \\t]*#include +<([\\w\\d./]+)>/gm;\n\nfunction resolveIncludes( string ) {\n\n\treturn string.replace( includePattern, includeReplacer );\n\n}\n\nconst shaderChunkMap = new Map();\n\nfunction includeReplacer( match, include ) {\n\n\tlet string = ShaderChunk[ include ];\n\n\tif ( string === undefined ) {\n\n\t\tconst newInclude = shaderChunkMap.get( include );\n\n\t\tif ( newInclude !== undefined ) {\n\n\t\t\tstring = ShaderChunk[ newInclude ];\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: Shader chunk \"%s\" has been deprecated. Use \"%s\" instead.', include, newInclude );\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'Can not resolve #include <' + include + '>' );\n\n\t\t}\n\n\t}\n\n\treturn resolveIncludes( string );\n\n}\n\n// Unroll Loops\n\nconst 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;\n\nfunction unrollLoops( string ) {\n\n\treturn string.replace( unrollLoopPattern, loopReplacer );\n\n}\n\nfunction loopReplacer( match, start, end, snippet ) {\n\n\tlet string = '';\n\n\tfor ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {\n\n\t\tstring += snippet\n\t\t\t.replace( /\\[\\s*i\\s*\\]/g, '[ ' + i + ' ]' )\n\t\t\t.replace( /UNROLLED_LOOP_INDEX/g, i );\n\n\t}\n\n\treturn string;\n\n}\n\n//\n\nfunction generatePrecision( parameters ) {\n\n\tlet precisionstring = `precision ${parameters.precision} float;\n\tprecision ${parameters.precision} int;\n\tprecision ${parameters.precision} sampler2D;\n\tprecision ${parameters.precision} samplerCube;\n\tprecision ${parameters.precision} sampler3D;\n\tprecision ${parameters.precision} sampler2DArray;\n\tprecision ${parameters.precision} sampler2DShadow;\n\tprecision ${parameters.precision} samplerCubeShadow;\n\tprecision ${parameters.precision} sampler2DArrayShadow;\n\tprecision ${parameters.precision} isampler2D;\n\tprecision ${parameters.precision} isampler3D;\n\tprecision ${parameters.precision} isamplerCube;\n\tprecision ${parameters.precision} isampler2DArray;\n\tprecision ${parameters.precision} usampler2D;\n\tprecision ${parameters.precision} usampler3D;\n\tprecision ${parameters.precision} usamplerCube;\n\tprecision ${parameters.precision} usampler2DArray;\n\t`;\n\n\tif ( parameters.precision === 'highp' ) {\n\n\t\tprecisionstring += '\\n#define HIGH_PRECISION';\n\n\t} else if ( parameters.precision === 'mediump' ) {\n\n\t\tprecisionstring += '\\n#define MEDIUM_PRECISION';\n\n\t} else if ( parameters.precision === 'lowp' ) {\n\n\t\tprecisionstring += '\\n#define LOW_PRECISION';\n\n\t}\n\n\treturn precisionstring;\n\n}\n\nfunction generateShadowMapTypeDefine( parameters ) {\n\n\tlet shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';\n\n\tif ( parameters.shadowMapType === PCFShadowMap ) {\n\n\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';\n\n\t} else if ( parameters.shadowMapType === PCFSoftShadowMap ) {\n\n\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';\n\n\t} else if ( parameters.shadowMapType === VSMShadowMap ) {\n\n\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';\n\n\t}\n\n\treturn shadowMapTypeDefine;\n\n}\n\nfunction generateEnvMapTypeDefine( parameters ) {\n\n\tlet envMapTypeDefine = 'ENVMAP_TYPE_CUBE';\n\n\tif ( parameters.envMap ) {\n\n\t\tswitch ( parameters.envMapMode ) {\n\n\t\t\tcase CubeReflectionMapping:\n\t\t\tcase CubeRefractionMapping:\n\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_CUBE';\n\t\t\t\tbreak;\n\n\t\t\tcase CubeUVReflectionMapping:\n\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\treturn envMapTypeDefine;\n\n}\n\nfunction generateEnvMapModeDefine( parameters ) {\n\n\tlet envMapModeDefine = 'ENVMAP_MODE_REFLECTION';\n\n\tif ( parameters.envMap ) {\n\n\t\tswitch ( parameters.envMapMode ) {\n\n\t\t\tcase CubeRefractionMapping:\n\n\t\t\t\tenvMapModeDefine = 'ENVMAP_MODE_REFRACTION';\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\treturn envMapModeDefine;\n\n}\n\nfunction generateEnvMapBlendingDefine( parameters ) {\n\n\tlet envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';\n\n\tif ( parameters.envMap ) {\n\n\t\tswitch ( parameters.combine ) {\n\n\t\t\tcase MultiplyOperation:\n\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';\n\t\t\t\tbreak;\n\n\t\t\tcase MixOperation:\n\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_MIX';\n\t\t\t\tbreak;\n\n\t\t\tcase AddOperation:\n\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_ADD';\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\treturn envMapBlendingDefine;\n\n}\n\nfunction generateCubeUVSize( parameters ) {\n\n\tconst imageHeight = parameters.envMapCubeUVHeight;\n\n\tif ( imageHeight === null ) return null;\n\n\tconst maxMip = Math.log2( imageHeight ) - 2;\n\n\tconst texelHeight = 1.0 / imageHeight;\n\n\tconst texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );\n\n\treturn { texelWidth, texelHeight, maxMip };\n\n}\n\nfunction WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {\n\n\t// TODO Send this event to Three.js DevTools\n\t// console.log( 'WebGLProgram', cacheKey );\n\n\tconst gl = renderer.getContext();\n\n\tconst defines = parameters.defines;\n\n\tlet vertexShader = parameters.vertexShader;\n\tlet fragmentShader = parameters.fragmentShader;\n\n\tconst shadowMapTypeDefine = generateShadowMapTypeDefine( parameters );\n\tconst envMapTypeDefine = generateEnvMapTypeDefine( parameters );\n\tconst envMapModeDefine = generateEnvMapModeDefine( parameters );\n\tconst envMapBlendingDefine = generateEnvMapBlendingDefine( parameters );\n\tconst envMapCubeUVSize = generateCubeUVSize( parameters );\n\n\tconst customVertexExtensions = generateVertexExtensions( parameters );\n\n\tconst customDefines = generateDefines( defines );\n\n\tconst program = gl.createProgram();\n\n\tlet prefixVertex, prefixFragment;\n\tlet versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\\n' : '';\n\n\tif ( parameters.isRawShaderMaterial ) {\n\n\t\tprefixVertex = [\n\n\t\t\t'#define SHADER_TYPE ' + parameters.shaderType,\n\t\t\t'#define SHADER_NAME ' + parameters.shaderName,\n\n\t\t\tcustomDefines\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\tif ( prefixVertex.length > 0 ) {\n\n\t\t\tprefixVertex += '\\n';\n\n\t\t}\n\n\t\tprefixFragment = [\n\n\t\t\t'#define SHADER_TYPE ' + parameters.shaderType,\n\t\t\t'#define SHADER_NAME ' + parameters.shaderName,\n\n\t\t\tcustomDefines\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\tif ( prefixFragment.length > 0 ) {\n\n\t\t\tprefixFragment += '\\n';\n\n\t\t}\n\n\t} else {\n\n\t\tprefixVertex = [\n\n\t\t\tgeneratePrecision( parameters ),\n\n\t\t\t'#define SHADER_TYPE ' + parameters.shaderType,\n\t\t\t'#define SHADER_NAME ' + parameters.shaderName,\n\n\t\t\tcustomDefines,\n\n\t\t\tparameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '',\n\t\t\tparameters.batching ? '#define USE_BATCHING' : '',\n\t\t\tparameters.batchingColor ? '#define USE_BATCHING_COLOR' : '',\n\t\t\tparameters.instancing ? '#define USE_INSTANCING' : '',\n\t\t\tparameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',\n\t\t\tparameters.instancingMorph ? '#define USE_INSTANCING_MORPH' : '',\n\n\t\t\tparameters.useFog && parameters.fog ? '#define USE_FOG' : '',\n\t\t\tparameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',\n\n\t\t\tparameters.map ? '#define USE_MAP' : '',\n\t\t\tparameters.envMap ? '#define USE_ENVMAP' : '',\n\t\t\tparameters.envMap ? '#define ' + envMapModeDefine : '',\n\t\t\tparameters.lightMap ? '#define USE_LIGHTMAP' : '',\n\t\t\tparameters.aoMap ? '#define USE_AOMAP' : '',\n\t\t\tparameters.bumpMap ? '#define USE_BUMPMAP' : '',\n\t\t\tparameters.normalMap ? '#define USE_NORMALMAP' : '',\n\t\t\tparameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',\n\t\t\tparameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',\n\t\t\tparameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '',\n\t\t\tparameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',\n\n\t\t\tparameters.anisotropy ? '#define USE_ANISOTROPY' : '',\n\t\t\tparameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',\n\n\t\t\tparameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',\n\t\t\tparameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',\n\t\t\tparameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',\n\n\t\t\tparameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',\n\t\t\tparameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',\n\n\t\t\tparameters.specularMap ? '#define USE_SPECULARMAP' : '',\n\t\t\tparameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',\n\t\t\tparameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',\n\n\t\t\tparameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',\n\t\t\tparameters.metalnessMap ? '#define USE_METALNESSMAP' : '',\n\t\t\tparameters.alphaMap ? '#define USE_ALPHAMAP' : '',\n\t\t\tparameters.alphaHash ? '#define USE_ALPHAHASH' : '',\n\n\t\t\tparameters.transmission ? '#define USE_TRANSMISSION' : '',\n\t\t\tparameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',\n\t\t\tparameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',\n\n\t\t\tparameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',\n\t\t\tparameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',\n\n\t\t\t//\n\n\t\t\tparameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '',\n\t\t\tparameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '',\n\t\t\tparameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '',\n\t\t\tparameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '',\n\t\t\tparameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '',\n\t\t\tparameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '',\n\t\t\tparameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '',\n\t\t\tparameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '',\n\n\t\t\tparameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '',\n\t\t\tparameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '',\n\n\t\t\tparameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '',\n\n\t\t\tparameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '',\n\t\t\tparameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '',\n\t\t\tparameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '',\n\n\t\t\tparameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '',\n\t\t\tparameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '',\n\n\t\t\tparameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '',\n\t\t\tparameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '',\n\n\t\t\tparameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '',\n\t\t\tparameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '',\n\t\t\tparameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '',\n\n\t\t\tparameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '',\n\t\t\tparameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '',\n\n\t\t\t//\n\n\t\t\tparameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',\n\t\t\tparameters.vertexColors ? '#define USE_COLOR' : '',\n\t\t\tparameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',\n\t\t\tparameters.vertexUv1s ? '#define USE_UV1' : '',\n\t\t\tparameters.vertexUv2s ? '#define USE_UV2' : '',\n\t\t\tparameters.vertexUv3s ? '#define USE_UV3' : '',\n\n\t\t\tparameters.pointsUvs ? '#define USE_POINTS_UV' : '',\n\n\t\t\tparameters.flatShading ? '#define FLAT_SHADED' : '',\n\n\t\t\tparameters.skinning ? '#define USE_SKINNING' : '',\n\n\t\t\tparameters.morphTargets ? '#define USE_MORPHTARGETS' : '',\n\t\t\tparameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',\n\t\t\t( parameters.morphColors ) ? '#define USE_MORPHCOLORS' : '',\n\t\t\t( parameters.morphTargetsCount > 0 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '',\n\t\t\t( parameters.morphTargetsCount > 0 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',\n\t\t\tparameters.doubleSided ? '#define DOUBLE_SIDED' : '',\n\t\t\tparameters.flipSided ? '#define FLIP_SIDED' : '',\n\n\t\t\tparameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',\n\t\t\tparameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',\n\n\t\t\tparameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',\n\n\t\t\tparameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',\n\n\t\t\tparameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',\n\n\t\t\t'uniform mat4 modelMatrix;',\n\t\t\t'uniform mat4 modelViewMatrix;',\n\t\t\t'uniform mat4 projectionMatrix;',\n\t\t\t'uniform mat4 viewMatrix;',\n\t\t\t'uniform mat3 normalMatrix;',\n\t\t\t'uniform vec3 cameraPosition;',\n\t\t\t'uniform bool isOrthographic;',\n\n\t\t\t'#ifdef USE_INSTANCING',\n\n\t\t\t'\tattribute mat4 instanceMatrix;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_INSTANCING_COLOR',\n\n\t\t\t'\tattribute vec3 instanceColor;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_INSTANCING_MORPH',\n\n\t\t\t'\tuniform sampler2D morphTexture;',\n\n\t\t\t'#endif',\n\n\t\t\t'attribute vec3 position;',\n\t\t\t'attribute vec3 normal;',\n\t\t\t'attribute vec2 uv;',\n\n\t\t\t'#ifdef USE_UV1',\n\n\t\t\t'\tattribute vec2 uv1;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_UV2',\n\n\t\t\t'\tattribute vec2 uv2;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_UV3',\n\n\t\t\t'\tattribute vec2 uv3;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_TANGENT',\n\n\t\t\t'\tattribute vec4 tangent;',\n\n\t\t\t'#endif',\n\n\t\t\t'#if defined( USE_COLOR_ALPHA )',\n\n\t\t\t'\tattribute vec4 color;',\n\n\t\t\t'#elif defined( USE_COLOR )',\n\n\t\t\t'\tattribute vec3 color;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_SKINNING',\n\n\t\t\t'\tattribute vec4 skinIndex;',\n\t\t\t'\tattribute vec4 skinWeight;',\n\n\t\t\t'#endif',\n\n\t\t\t'\\n'\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\tprefixFragment = [\n\n\t\t\tgeneratePrecision( parameters ),\n\n\t\t\t'#define SHADER_TYPE ' + parameters.shaderType,\n\t\t\t'#define SHADER_NAME ' + parameters.shaderName,\n\n\t\t\tcustomDefines,\n\n\t\t\tparameters.useFog && parameters.fog ? '#define USE_FOG' : '',\n\t\t\tparameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',\n\n\t\t\tparameters.alphaToCoverage ? '#define ALPHA_TO_COVERAGE' : '',\n\t\t\tparameters.map ? '#define USE_MAP' : '',\n\t\t\tparameters.matcap ? '#define USE_MATCAP' : '',\n\t\t\tparameters.envMap ? '#define USE_ENVMAP' : '',\n\t\t\tparameters.envMap ? '#define ' + envMapTypeDefine : '',\n\t\t\tparameters.envMap ? '#define ' + envMapModeDefine : '',\n\t\t\tparameters.envMap ? '#define ' + envMapBlendingDefine : '',\n\t\t\tenvMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '',\n\t\t\tenvMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '',\n\t\t\tenvMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '',\n\t\t\tparameters.lightMap ? '#define USE_LIGHTMAP' : '',\n\t\t\tparameters.aoMap ? '#define USE_AOMAP' : '',\n\t\t\tparameters.bumpMap ? '#define USE_BUMPMAP' : '',\n\t\t\tparameters.normalMap ? '#define USE_NORMALMAP' : '',\n\t\t\tparameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',\n\t\t\tparameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',\n\t\t\tparameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',\n\n\t\t\tparameters.anisotropy ? '#define USE_ANISOTROPY' : '',\n\t\t\tparameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',\n\n\t\t\tparameters.clearcoat ? '#define USE_CLEARCOAT' : '',\n\t\t\tparameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',\n\t\t\tparameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',\n\t\t\tparameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',\n\n\t\t\tparameters.dispersion ? '#define USE_DISPERSION' : '',\n\n\t\t\tparameters.iridescence ? '#define USE_IRIDESCENCE' : '',\n\t\t\tparameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',\n\t\t\tparameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',\n\n\t\t\tparameters.specularMap ? '#define USE_SPECULARMAP' : '',\n\t\t\tparameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',\n\t\t\tparameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',\n\n\t\t\tparameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',\n\t\t\tparameters.metalnessMap ? '#define USE_METALNESSMAP' : '',\n\n\t\t\tparameters.alphaMap ? '#define USE_ALPHAMAP' : '',\n\t\t\tparameters.alphaTest ? '#define USE_ALPHATEST' : '',\n\t\t\tparameters.alphaHash ? '#define USE_ALPHAHASH' : '',\n\n\t\t\tparameters.sheen ? '#define USE_SHEEN' : '',\n\t\t\tparameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',\n\t\t\tparameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',\n\n\t\t\tparameters.transmission ? '#define USE_TRANSMISSION' : '',\n\t\t\tparameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',\n\t\t\tparameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',\n\n\t\t\tparameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',\n\t\t\tparameters.vertexColors || parameters.instancingColor || parameters.batchingColor ? '#define USE_COLOR' : '',\n\t\t\tparameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',\n\t\t\tparameters.vertexUv1s ? '#define USE_UV1' : '',\n\t\t\tparameters.vertexUv2s ? '#define USE_UV2' : '',\n\t\t\tparameters.vertexUv3s ? '#define USE_UV3' : '',\n\n\t\t\tparameters.pointsUvs ? '#define USE_POINTS_UV' : '',\n\n\t\t\tparameters.gradientMap ? '#define USE_GRADIENTMAP' : '',\n\n\t\t\tparameters.flatShading ? '#define FLAT_SHADED' : '',\n\n\t\t\tparameters.doubleSided ? '#define DOUBLE_SIDED' : '',\n\t\t\tparameters.flipSided ? '#define FLIP_SIDED' : '',\n\n\t\t\tparameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',\n\t\t\tparameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',\n\n\t\t\tparameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',\n\n\t\t\tparameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',\n\n\t\t\tparameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',\n\n\t\t\tparameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',\n\n\t\t\t'uniform mat4 viewMatrix;',\n\t\t\t'uniform vec3 cameraPosition;',\n\t\t\t'uniform bool isOrthographic;',\n\n\t\t\t( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',\n\t\t\t( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below\n\t\t\t( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',\n\n\t\t\tparameters.dithering ? '#define DITHERING' : '',\n\t\t\tparameters.opaque ? '#define OPAQUE' : '',\n\n\t\t\tShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below\n\t\t\tgetTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ),\n\n\t\t\tparameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',\n\n\t\t\t'\\n'\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t}\n\n\tvertexShader = resolveIncludes( vertexShader );\n\tvertexShader = replaceLightNums( vertexShader, parameters );\n\tvertexShader = replaceClippingPlaneNums( vertexShader, parameters );\n\n\tfragmentShader = resolveIncludes( fragmentShader );\n\tfragmentShader = replaceLightNums( fragmentShader, parameters );\n\tfragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );\n\n\tvertexShader = unrollLoops( vertexShader );\n\tfragmentShader = unrollLoops( fragmentShader );\n\n\tif ( parameters.isRawShaderMaterial !== true ) {\n\n\t\t// GLSL 3.0 conversion for built-in materials and ShaderMaterial\n\n\t\tversionString = '#version 300 es\\n';\n\n\t\tprefixVertex = [\n\t\t\tcustomVertexExtensions,\n\t\t\t'#define attribute in',\n\t\t\t'#define varying out',\n\t\t\t'#define texture2D texture'\n\t\t].join( '\\n' ) + '\\n' + prefixVertex;\n\n\t\tprefixFragment = [\n\t\t\t'#define varying in',\n\t\t\t( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;',\n\t\t\t( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',\n\t\t\t'#define gl_FragDepthEXT gl_FragDepth',\n\t\t\t'#define texture2D texture',\n\t\t\t'#define textureCube texture',\n\t\t\t'#define texture2DProj textureProj',\n\t\t\t'#define texture2DLodEXT textureLod',\n\t\t\t'#define texture2DProjLodEXT textureProjLod',\n\t\t\t'#define textureCubeLodEXT textureLod',\n\t\t\t'#define texture2DGradEXT textureGrad',\n\t\t\t'#define texture2DProjGradEXT textureProjGrad',\n\t\t\t'#define textureCubeGradEXT textureGrad'\n\t\t].join( '\\n' ) + '\\n' + prefixFragment;\n\n\t}\n\n\tconst vertexGlsl = versionString + prefixVertex + vertexShader;\n\tconst fragmentGlsl = versionString + prefixFragment + fragmentShader;\n\n\t// console.log( '*VERTEX*', vertexGlsl );\n\t// console.log( '*FRAGMENT*', fragmentGlsl );\n\n\tconst glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );\n\tconst glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );\n\n\tgl.attachShader( program, glVertexShader );\n\tgl.attachShader( program, glFragmentShader );\n\n\t// Force a particular attribute to index 0.\n\n\tif ( parameters.index0AttributeName !== undefined ) {\n\n\t\tgl.bindAttribLocation( program, 0, parameters.index0AttributeName );\n\n\t} else if ( parameters.morphTargets === true ) {\n\n\t\t// programs with morphTargets displace position out of attribute 0\n\t\tgl.bindAttribLocation( program, 0, 'position' );\n\n\t}\n\n\tgl.linkProgram( program );\n\n\tfunction onFirstUse( self ) {\n\n\t\t// check for link errors\n\t\tif ( renderer.debug.checkShaderErrors ) {\n\n\t\t\tconst programLog = gl.getProgramInfoLog( program ).trim();\n\t\t\tconst vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();\n\t\t\tconst fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();\n\n\t\t\tlet runnable = true;\n\t\t\tlet haveDiagnostics = true;\n\n\t\t\tif ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {\n\n\t\t\t\trunnable = false;\n\n\t\t\t\tif ( typeof renderer.debug.onShaderError === 'function' ) {\n\n\t\t\t\t\trenderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// default error reporting\n\n\t\t\t\t\tconst vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );\n\t\t\t\t\tconst fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );\n\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' +\n\t\t\t\t\t\t'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\\n\\n' +\n\t\t\t\t\t\t'Material Name: ' + self.name + '\\n' +\n\t\t\t\t\t\t'Material Type: ' + self.type + '\\n\\n' +\n\t\t\t\t\t\t'Program Info Log: ' + programLog + '\\n' +\n\t\t\t\t\t\tvertexErrors + '\\n' +\n\t\t\t\t\t\tfragmentErrors\n\t\t\t\t\t);\n\n\t\t\t\t}\n\n\t\t\t} else if ( programLog !== '' ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLProgram: Program Info Log:', programLog );\n\n\t\t\t} else if ( vertexLog === '' || fragmentLog === '' ) {\n\n\t\t\t\thaveDiagnostics = false;\n\n\t\t\t}\n\n\t\t\tif ( haveDiagnostics ) {\n\n\t\t\t\tself.diagnostics = {\n\n\t\t\t\t\trunnable: runnable,\n\n\t\t\t\t\tprogramLog: programLog,\n\n\t\t\t\t\tvertexShader: {\n\n\t\t\t\t\t\tlog: vertexLog,\n\t\t\t\t\t\tprefix: prefixVertex\n\n\t\t\t\t\t},\n\n\t\t\t\t\tfragmentShader: {\n\n\t\t\t\t\t\tlog: fragmentLog,\n\t\t\t\t\t\tprefix: prefixFragment\n\n\t\t\t\t\t}\n\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Clean up\n\n\t\t// Crashes in iOS9 and iOS10. #18402\n\t\t// gl.detachShader( program, glVertexShader );\n\t\t// gl.detachShader( program, glFragmentShader );\n\n\t\tgl.deleteShader( glVertexShader );\n\t\tgl.deleteShader( glFragmentShader );\n\n\t\tcachedUniforms = new WebGLUniforms( gl, program );\n\t\tcachedAttributes = fetchAttributeLocations( gl, program );\n\n\t}\n\n\t// set up caching for uniform locations\n\n\tlet cachedUniforms;\n\n\tthis.getUniforms = function () {\n\n\t\tif ( cachedUniforms === undefined ) {\n\n\t\t\t// Populates cachedUniforms and cachedAttributes\n\t\t\tonFirstUse( this );\n\n\t\t}\n\n\t\treturn cachedUniforms;\n\n\t};\n\n\t// set up caching for attribute locations\n\n\tlet cachedAttributes;\n\n\tthis.getAttributes = function () {\n\n\t\tif ( cachedAttributes === undefined ) {\n\n\t\t\t// Populates cachedAttributes and cachedUniforms\n\t\t\tonFirstUse( this );\n\n\t\t}\n\n\t\treturn cachedAttributes;\n\n\t};\n\n\t// indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported,\n\t// flag the program as ready immediately. It may cause a stall when it's first used.\n\n\tlet programReady = ( parameters.rendererExtensionParallelShaderCompile === false );\n\n\tthis.isReady = function () {\n\n\t\tif ( programReady === false ) {\n\n\t\t\tprogramReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR );\n\n\t\t}\n\n\t\treturn programReady;\n\n\t};\n\n\t// free resource\n\n\tthis.destroy = function () {\n\n\t\tbindingStates.releaseStatesOfProgram( this );\n\n\t\tgl.deleteProgram( program );\n\t\tthis.program = undefined;\n\n\t};\n\n\t//\n\n\tthis.type = parameters.shaderType;\n\tthis.name = parameters.shaderName;\n\tthis.id = programIdCount ++;\n\tthis.cacheKey = cacheKey;\n\tthis.usedTimes = 1;\n\tthis.program = program;\n\tthis.vertexShader = glVertexShader;\n\tthis.fragmentShader = glFragmentShader;\n\n\treturn this;\n\n}\n\nlet _id$1 = 0;\n\nclass WebGLShaderCache {\n\n\tconstructor() {\n\n\t\tthis.shaderCache = new Map();\n\t\tthis.materialCache = new Map();\n\n\t}\n\n\tupdate( material ) {\n\n\t\tconst vertexShader = material.vertexShader;\n\t\tconst fragmentShader = material.fragmentShader;\n\n\t\tconst vertexShaderStage = this._getShaderStage( vertexShader );\n\t\tconst fragmentShaderStage = this._getShaderStage( fragmentShader );\n\n\t\tconst materialShaders = this._getShaderCacheForMaterial( material );\n\n\t\tif ( materialShaders.has( vertexShaderStage ) === false ) {\n\n\t\t\tmaterialShaders.add( vertexShaderStage );\n\t\t\tvertexShaderStage.usedTimes ++;\n\n\t\t}\n\n\t\tif ( materialShaders.has( fragmentShaderStage ) === false ) {\n\n\t\t\tmaterialShaders.add( fragmentShaderStage );\n\t\t\tfragmentShaderStage.usedTimes ++;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tremove( material ) {\n\n\t\tconst materialShaders = this.materialCache.get( material );\n\n\t\tfor ( const shaderStage of materialShaders ) {\n\n\t\t\tshaderStage.usedTimes --;\n\n\t\t\tif ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code );\n\n\t\t}\n\n\t\tthis.materialCache.delete( material );\n\n\t\treturn this;\n\n\t}\n\n\tgetVertexShaderID( material ) {\n\n\t\treturn this._getShaderStage( material.vertexShader ).id;\n\n\t}\n\n\tgetFragmentShaderID( material ) {\n\n\t\treturn this._getShaderStage( material.fragmentShader ).id;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.shaderCache.clear();\n\t\tthis.materialCache.clear();\n\n\t}\n\n\t_getShaderCacheForMaterial( material ) {\n\n\t\tconst cache = this.materialCache;\n\t\tlet set = cache.get( material );\n\n\t\tif ( set === undefined ) {\n\n\t\t\tset = new Set();\n\t\t\tcache.set( material, set );\n\n\t\t}\n\n\t\treturn set;\n\n\t}\n\n\t_getShaderStage( code ) {\n\n\t\tconst cache = this.shaderCache;\n\t\tlet stage = cache.get( code );\n\n\t\tif ( stage === undefined ) {\n\n\t\t\tstage = new WebGLShaderStage( code );\n\t\t\tcache.set( code, stage );\n\n\t\t}\n\n\t\treturn stage;\n\n\t}\n\n}\n\nclass WebGLShaderStage {\n\n\tconstructor( code ) {\n\n\t\tthis.id = _id$1 ++;\n\n\t\tthis.code = code;\n\t\tthis.usedTimes = 0;\n\n\t}\n\n}\n\nfunction WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) {\n\n\tconst _programLayers = new Layers();\n\tconst _customShaders = new WebGLShaderCache();\n\tconst _activeChannels = new Set();\n\tconst programs = [];\n\n\tconst logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;\n\tconst SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures;\n\n\tlet precision = capabilities.precision;\n\n\tconst shaderIDs = {\n\t\tMeshDepthMaterial: 'depth',\n\t\tMeshDistanceMaterial: 'distanceRGBA',\n\t\tMeshNormalMaterial: 'normal',\n\t\tMeshBasicMaterial: 'basic',\n\t\tMeshLambertMaterial: 'lambert',\n\t\tMeshPhongMaterial: 'phong',\n\t\tMeshToonMaterial: 'toon',\n\t\tMeshStandardMaterial: 'physical',\n\t\tMeshPhysicalMaterial: 'physical',\n\t\tMeshMatcapMaterial: 'matcap',\n\t\tLineBasicMaterial: 'basic',\n\t\tLineDashedMaterial: 'dashed',\n\t\tPointsMaterial: 'points',\n\t\tShadowMaterial: 'shadow',\n\t\tSpriteMaterial: 'sprite'\n\t};\n\n\tfunction getChannel( value ) {\n\n\t\t_activeChannels.add( value );\n\n\t\tif ( value === 0 ) return 'uv';\n\n\t\treturn `uv${ value }`;\n\n\t}\n\n\tfunction getParameters( material, lights, shadows, scene, object ) {\n\n\t\tconst fog = scene.fog;\n\t\tconst geometry = object.geometry;\n\t\tconst environment = material.isMeshStandardMaterial ? scene.environment : null;\n\n\t\tconst envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );\n\t\tconst envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null;\n\n\t\tconst shaderID = shaderIDs[ material.type ];\n\n\t\t// heuristics to create shader parameters according to lights in the scene\n\t\t// (not to blow over maxLights budget)\n\n\t\tif ( material.precision !== null ) {\n\n\t\t\tprecision = capabilities.getMaxPrecision( material.precision );\n\n\t\t\tif ( precision !== material.precision ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tconst morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;\n\t\tconst morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;\n\n\t\tlet morphTextureStride = 0;\n\n\t\tif ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1;\n\t\tif ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2;\n\t\tif ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3;\n\n\t\t//\n\n\t\tlet vertexShader, fragmentShader;\n\t\tlet customVertexShaderID, customFragmentShaderID;\n\n\t\tif ( shaderID ) {\n\n\t\t\tconst shader = ShaderLib[ shaderID ];\n\n\t\t\tvertexShader = shader.vertexShader;\n\t\t\tfragmentShader = shader.fragmentShader;\n\n\t\t} else {\n\n\t\t\tvertexShader = material.vertexShader;\n\t\t\tfragmentShader = material.fragmentShader;\n\n\t\t\t_customShaders.update( material );\n\n\t\t\tcustomVertexShaderID = _customShaders.getVertexShaderID( material );\n\t\t\tcustomFragmentShaderID = _customShaders.getFragmentShaderID( material );\n\n\t\t}\n\n\t\tconst currentRenderTarget = renderer.getRenderTarget();\n\n\t\tconst IS_INSTANCEDMESH = object.isInstancedMesh === true;\n\t\tconst IS_BATCHEDMESH = object.isBatchedMesh === true;\n\n\t\tconst HAS_MAP = !! material.map;\n\t\tconst HAS_MATCAP = !! material.matcap;\n\t\tconst HAS_ENVMAP = !! envMap;\n\t\tconst HAS_AOMAP = !! material.aoMap;\n\t\tconst HAS_LIGHTMAP = !! material.lightMap;\n\t\tconst HAS_BUMPMAP = !! material.bumpMap;\n\t\tconst HAS_NORMALMAP = !! material.normalMap;\n\t\tconst HAS_DISPLACEMENTMAP = !! material.displacementMap;\n\t\tconst HAS_EMISSIVEMAP = !! material.emissiveMap;\n\n\t\tconst HAS_METALNESSMAP = !! material.metalnessMap;\n\t\tconst HAS_ROUGHNESSMAP = !! material.roughnessMap;\n\n\t\tconst HAS_ANISOTROPY = material.anisotropy > 0;\n\t\tconst HAS_CLEARCOAT = material.clearcoat > 0;\n\t\tconst HAS_DISPERSION = material.dispersion > 0;\n\t\tconst HAS_IRIDESCENCE = material.iridescence > 0;\n\t\tconst HAS_SHEEN = material.sheen > 0;\n\t\tconst HAS_TRANSMISSION = material.transmission > 0;\n\n\t\tconst HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap;\n\n\t\tconst HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap;\n\t\tconst HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap;\n\t\tconst HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap;\n\n\t\tconst HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap;\n\t\tconst HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap;\n\n\t\tconst HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap;\n\t\tconst HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap;\n\n\t\tconst HAS_SPECULARMAP = !! material.specularMap;\n\t\tconst HAS_SPECULAR_COLORMAP = !! material.specularColorMap;\n\t\tconst HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap;\n\n\t\tconst HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap;\n\t\tconst HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap;\n\n\t\tconst HAS_GRADIENTMAP = !! material.gradientMap;\n\n\t\tconst HAS_ALPHAMAP = !! material.alphaMap;\n\n\t\tconst HAS_ALPHATEST = material.alphaTest > 0;\n\n\t\tconst HAS_ALPHAHASH = !! material.alphaHash;\n\n\t\tconst HAS_EXTENSIONS = !! material.extensions;\n\n\t\tlet toneMapping = NoToneMapping;\n\n\t\tif ( material.toneMapped ) {\n\n\t\t\tif ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) {\n\n\t\t\t\ttoneMapping = renderer.toneMapping;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst parameters = {\n\n\t\t\tshaderID: shaderID,\n\t\t\tshaderType: material.type,\n\t\t\tshaderName: material.name,\n\n\t\t\tvertexShader: vertexShader,\n\t\t\tfragmentShader: fragmentShader,\n\t\t\tdefines: material.defines,\n\n\t\t\tcustomVertexShaderID: customVertexShaderID,\n\t\t\tcustomFragmentShaderID: customFragmentShaderID,\n\n\t\t\tisRawShaderMaterial: material.isRawShaderMaterial === true,\n\t\t\tglslVersion: material.glslVersion,\n\n\t\t\tprecision: precision,\n\n\t\t\tbatching: IS_BATCHEDMESH,\n\t\t\tbatchingColor: IS_BATCHEDMESH && object._colorsTexture !== null,\n\t\t\tinstancing: IS_INSTANCEDMESH,\n\t\t\tinstancingColor: IS_INSTANCEDMESH && object.instanceColor !== null,\n\t\t\tinstancingMorph: IS_INSTANCEDMESH && object.morphTexture !== null,\n\n\t\t\tsupportsVertexTextures: SUPPORTS_VERTEX_TEXTURES,\n\t\t\toutputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ),\n\t\t\talphaToCoverage: !! material.alphaToCoverage,\n\n\t\t\tmap: HAS_MAP,\n\t\t\tmatcap: HAS_MATCAP,\n\t\t\tenvMap: HAS_ENVMAP,\n\t\t\tenvMapMode: HAS_ENVMAP && envMap.mapping,\n\t\t\tenvMapCubeUVHeight: envMapCubeUVHeight,\n\t\t\taoMap: HAS_AOMAP,\n\t\t\tlightMap: HAS_LIGHTMAP,\n\t\t\tbumpMap: HAS_BUMPMAP,\n\t\t\tnormalMap: HAS_NORMALMAP,\n\t\t\tdisplacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP,\n\t\t\temissiveMap: HAS_EMISSIVEMAP,\n\n\t\t\tnormalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap,\n\t\t\tnormalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap,\n\n\t\t\tmetalnessMap: HAS_METALNESSMAP,\n\t\t\troughnessMap: HAS_ROUGHNESSMAP,\n\n\t\t\tanisotropy: HAS_ANISOTROPY,\n\t\t\tanisotropyMap: HAS_ANISOTROPYMAP,\n\n\t\t\tclearcoat: HAS_CLEARCOAT,\n\t\t\tclearcoatMap: HAS_CLEARCOATMAP,\n\t\t\tclearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP,\n\t\t\tclearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP,\n\n\t\t\tdispersion: HAS_DISPERSION,\n\n\t\t\tiridescence: HAS_IRIDESCENCE,\n\t\t\tiridescenceMap: HAS_IRIDESCENCEMAP,\n\t\t\tiridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP,\n\n\t\t\tsheen: HAS_SHEEN,\n\t\t\tsheenColorMap: HAS_SHEEN_COLORMAP,\n\t\t\tsheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP,\n\n\t\t\tspecularMap: HAS_SPECULARMAP,\n\t\t\tspecularColorMap: HAS_SPECULAR_COLORMAP,\n\t\t\tspecularIntensityMap: HAS_SPECULAR_INTENSITYMAP,\n\n\t\t\ttransmission: HAS_TRANSMISSION,\n\t\t\ttransmissionMap: HAS_TRANSMISSIONMAP,\n\t\t\tthicknessMap: HAS_THICKNESSMAP,\n\n\t\t\tgradientMap: HAS_GRADIENTMAP,\n\n\t\t\topaque: material.transparent === false && material.blending === NormalBlending && material.alphaToCoverage === false,\n\n\t\t\talphaMap: HAS_ALPHAMAP,\n\t\t\talphaTest: HAS_ALPHATEST,\n\t\t\talphaHash: HAS_ALPHAHASH,\n\n\t\t\tcombine: material.combine,\n\n\t\t\t//\n\n\t\t\tmapUv: HAS_MAP && getChannel( material.map.channel ),\n\t\t\taoMapUv: HAS_AOMAP && getChannel( material.aoMap.channel ),\n\t\t\tlightMapUv: HAS_LIGHTMAP && getChannel( material.lightMap.channel ),\n\t\t\tbumpMapUv: HAS_BUMPMAP && getChannel( material.bumpMap.channel ),\n\t\t\tnormalMapUv: HAS_NORMALMAP && getChannel( material.normalMap.channel ),\n\t\t\tdisplacementMapUv: HAS_DISPLACEMENTMAP && getChannel( material.displacementMap.channel ),\n\t\t\temissiveMapUv: HAS_EMISSIVEMAP && getChannel( material.emissiveMap.channel ),\n\n\t\t\tmetalnessMapUv: HAS_METALNESSMAP && getChannel( material.metalnessMap.channel ),\n\t\t\troughnessMapUv: HAS_ROUGHNESSMAP && getChannel( material.roughnessMap.channel ),\n\n\t\t\tanisotropyMapUv: HAS_ANISOTROPYMAP && getChannel( material.anisotropyMap.channel ),\n\n\t\t\tclearcoatMapUv: HAS_CLEARCOATMAP && getChannel( material.clearcoatMap.channel ),\n\t\t\tclearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel( material.clearcoatNormalMap.channel ),\n\t\t\tclearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel( material.clearcoatRoughnessMap.channel ),\n\n\t\t\tiridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel( material.iridescenceMap.channel ),\n\t\t\tiridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel( material.iridescenceThicknessMap.channel ),\n\n\t\t\tsheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel( material.sheenColorMap.channel ),\n\t\t\tsheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel( material.sheenRoughnessMap.channel ),\n\n\t\t\tspecularMapUv: HAS_SPECULARMAP && getChannel( material.specularMap.channel ),\n\t\t\tspecularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel( material.specularColorMap.channel ),\n\t\t\tspecularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel( material.specularIntensityMap.channel ),\n\n\t\t\ttransmissionMapUv: HAS_TRANSMISSIONMAP && getChannel( material.transmissionMap.channel ),\n\t\t\tthicknessMapUv: HAS_THICKNESSMAP && getChannel( material.thicknessMap.channel ),\n\n\t\t\talphaMapUv: HAS_ALPHAMAP && getChannel( material.alphaMap.channel ),\n\n\t\t\t//\n\n\t\t\tvertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ),\n\t\t\tvertexColors: material.vertexColors,\n\t\t\tvertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4,\n\n\t\t\tpointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ),\n\n\t\t\tfog: !! fog,\n\t\t\tuseFog: material.fog === true,\n\t\t\tfogExp2: ( !! fog && fog.isFogExp2 ),\n\n\t\t\tflatShading: material.flatShading === true,\n\n\t\t\tsizeAttenuation: material.sizeAttenuation === true,\n\t\t\tlogarithmicDepthBuffer: logarithmicDepthBuffer,\n\n\t\t\tskinning: object.isSkinnedMesh === true,\n\n\t\t\tmorphTargets: geometry.morphAttributes.position !== undefined,\n\t\t\tmorphNormals: geometry.morphAttributes.normal !== undefined,\n\t\t\tmorphColors: geometry.morphAttributes.color !== undefined,\n\t\t\tmorphTargetsCount: morphTargetsCount,\n\t\t\tmorphTextureStride: morphTextureStride,\n\n\t\t\tnumDirLights: lights.directional.length,\n\t\t\tnumPointLights: lights.point.length,\n\t\t\tnumSpotLights: lights.spot.length,\n\t\t\tnumSpotLightMaps: lights.spotLightMap.length,\n\t\t\tnumRectAreaLights: lights.rectArea.length,\n\t\t\tnumHemiLights: lights.hemi.length,\n\n\t\t\tnumDirLightShadows: lights.directionalShadowMap.length,\n\t\t\tnumPointLightShadows: lights.pointShadowMap.length,\n\t\t\tnumSpotLightShadows: lights.spotShadowMap.length,\n\t\t\tnumSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps,\n\n\t\t\tnumLightProbes: lights.numLightProbes,\n\n\t\t\tnumClippingPlanes: clipping.numPlanes,\n\t\t\tnumClipIntersection: clipping.numIntersection,\n\n\t\t\tdithering: material.dithering,\n\n\t\t\tshadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,\n\t\t\tshadowMapType: renderer.shadowMap.type,\n\n\t\t\ttoneMapping: toneMapping,\n\n\t\t\tdecodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ),\n\n\t\t\tpremultipliedAlpha: material.premultipliedAlpha,\n\n\t\t\tdoubleSided: material.side === DoubleSide,\n\t\t\tflipSided: material.side === BackSide,\n\n\t\t\tuseDepthPacking: material.depthPacking >= 0,\n\t\t\tdepthPacking: material.depthPacking || 0,\n\n\t\t\tindex0AttributeName: material.index0AttributeName,\n\n\t\t\textensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance === true && extensions.has( 'WEBGL_clip_cull_distance' ),\n\t\t\textensionMultiDraw: ( HAS_EXTENSIONS && material.extensions.multiDraw === true || IS_BATCHEDMESH ) && extensions.has( 'WEBGL_multi_draw' ),\n\n\t\t\trendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ),\n\n\t\t\tcustomProgramCacheKey: material.customProgramCacheKey()\n\n\t\t};\n\n\t\t// the usage of getChannel() determines the active texture channels for this shader\n\n\t\tparameters.vertexUv1s = _activeChannels.has( 1 );\n\t\tparameters.vertexUv2s = _activeChannels.has( 2 );\n\t\tparameters.vertexUv3s = _activeChannels.has( 3 );\n\n\t\t_activeChannels.clear();\n\n\t\treturn parameters;\n\n\t}\n\n\tfunction getProgramCacheKey( parameters ) {\n\n\t\tconst array = [];\n\n\t\tif ( parameters.shaderID ) {\n\n\t\t\tarray.push( parameters.shaderID );\n\n\t\t} else {\n\n\t\t\tarray.push( parameters.customVertexShaderID );\n\t\t\tarray.push( parameters.customFragmentShaderID );\n\n\t\t}\n\n\t\tif ( parameters.defines !== undefined ) {\n\n\t\t\tfor ( const name in parameters.defines ) {\n\n\t\t\t\tarray.push( name );\n\t\t\t\tarray.push( parameters.defines[ name ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( parameters.isRawShaderMaterial === false ) {\n\n\t\t\tgetProgramCacheKeyParameters( array, parameters );\n\t\t\tgetProgramCacheKeyBooleans( array, parameters );\n\t\t\tarray.push( renderer.outputColorSpace );\n\n\t\t}\n\n\t\tarray.push( parameters.customProgramCacheKey );\n\n\t\treturn array.join();\n\n\t}\n\n\tfunction getProgramCacheKeyParameters( array, parameters ) {\n\n\t\tarray.push( parameters.precision );\n\t\tarray.push( parameters.outputColorSpace );\n\t\tarray.push( parameters.envMapMode );\n\t\tarray.push( parameters.envMapCubeUVHeight );\n\t\tarray.push( parameters.mapUv );\n\t\tarray.push( parameters.alphaMapUv );\n\t\tarray.push( parameters.lightMapUv );\n\t\tarray.push( parameters.aoMapUv );\n\t\tarray.push( parameters.bumpMapUv );\n\t\tarray.push( parameters.normalMapUv );\n\t\tarray.push( parameters.displacementMapUv );\n\t\tarray.push( parameters.emissiveMapUv );\n\t\tarray.push( parameters.metalnessMapUv );\n\t\tarray.push( parameters.roughnessMapUv );\n\t\tarray.push( parameters.anisotropyMapUv );\n\t\tarray.push( parameters.clearcoatMapUv );\n\t\tarray.push( parameters.clearcoatNormalMapUv );\n\t\tarray.push( parameters.clearcoatRoughnessMapUv );\n\t\tarray.push( parameters.iridescenceMapUv );\n\t\tarray.push( parameters.iridescenceThicknessMapUv );\n\t\tarray.push( parameters.sheenColorMapUv );\n\t\tarray.push( parameters.sheenRoughnessMapUv );\n\t\tarray.push( parameters.specularMapUv );\n\t\tarray.push( parameters.specularColorMapUv );\n\t\tarray.push( parameters.specularIntensityMapUv );\n\t\tarray.push( parameters.transmissionMapUv );\n\t\tarray.push( parameters.thicknessMapUv );\n\t\tarray.push( parameters.combine );\n\t\tarray.push( parameters.fogExp2 );\n\t\tarray.push( parameters.sizeAttenuation );\n\t\tarray.push( parameters.morphTargetsCount );\n\t\tarray.push( parameters.morphAttributeCount );\n\t\tarray.push( parameters.numDirLights );\n\t\tarray.push( parameters.numPointLights );\n\t\tarray.push( parameters.numSpotLights );\n\t\tarray.push( parameters.numSpotLightMaps );\n\t\tarray.push( parameters.numHemiLights );\n\t\tarray.push( parameters.numRectAreaLights );\n\t\tarray.push( parameters.numDirLightShadows );\n\t\tarray.push( parameters.numPointLightShadows );\n\t\tarray.push( parameters.numSpotLightShadows );\n\t\tarray.push( parameters.numSpotLightShadowsWithMaps );\n\t\tarray.push( parameters.numLightProbes );\n\t\tarray.push( parameters.shadowMapType );\n\t\tarray.push( parameters.toneMapping );\n\t\tarray.push( parameters.numClippingPlanes );\n\t\tarray.push( parameters.numClipIntersection );\n\t\tarray.push( parameters.depthPacking );\n\n\t}\n\n\tfunction getProgramCacheKeyBooleans( array, parameters ) {\n\n\t\t_programLayers.disableAll();\n\n\t\tif ( parameters.supportsVertexTextures )\n\t\t\t_programLayers.enable( 0 );\n\t\tif ( parameters.instancing )\n\t\t\t_programLayers.enable( 1 );\n\t\tif ( parameters.instancingColor )\n\t\t\t_programLayers.enable( 2 );\n\t\tif ( parameters.instancingMorph )\n\t\t\t_programLayers.enable( 3 );\n\t\tif ( parameters.matcap )\n\t\t\t_programLayers.enable( 4 );\n\t\tif ( parameters.envMap )\n\t\t\t_programLayers.enable( 5 );\n\t\tif ( parameters.normalMapObjectSpace )\n\t\t\t_programLayers.enable( 6 );\n\t\tif ( parameters.normalMapTangentSpace )\n\t\t\t_programLayers.enable( 7 );\n\t\tif ( parameters.clearcoat )\n\t\t\t_programLayers.enable( 8 );\n\t\tif ( parameters.iridescence )\n\t\t\t_programLayers.enable( 9 );\n\t\tif ( parameters.alphaTest )\n\t\t\t_programLayers.enable( 10 );\n\t\tif ( parameters.vertexColors )\n\t\t\t_programLayers.enable( 11 );\n\t\tif ( parameters.vertexAlphas )\n\t\t\t_programLayers.enable( 12 );\n\t\tif ( parameters.vertexUv1s )\n\t\t\t_programLayers.enable( 13 );\n\t\tif ( parameters.vertexUv2s )\n\t\t\t_programLayers.enable( 14 );\n\t\tif ( parameters.vertexUv3s )\n\t\t\t_programLayers.enable( 15 );\n\t\tif ( parameters.vertexTangents )\n\t\t\t_programLayers.enable( 16 );\n\t\tif ( parameters.anisotropy )\n\t\t\t_programLayers.enable( 17 );\n\t\tif ( parameters.alphaHash )\n\t\t\t_programLayers.enable( 18 );\n\t\tif ( parameters.batching )\n\t\t\t_programLayers.enable( 19 );\n\t\tif ( parameters.dispersion )\n\t\t\t_programLayers.enable( 20 );\n\t\tif ( parameters.batchingColor )\n\t\t\t_programLayers.enable( 21 );\n\n\t\tarray.push( _programLayers.mask );\n\t\t_programLayers.disableAll();\n\n\t\tif ( parameters.fog )\n\t\t\t_programLayers.enable( 0 );\n\t\tif ( parameters.useFog )\n\t\t\t_programLayers.enable( 1 );\n\t\tif ( parameters.flatShading )\n\t\t\t_programLayers.enable( 2 );\n\t\tif ( parameters.logarithmicDepthBuffer )\n\t\t\t_programLayers.enable( 3 );\n\t\tif ( parameters.skinning )\n\t\t\t_programLayers.enable( 4 );\n\t\tif ( parameters.morphTargets )\n\t\t\t_programLayers.enable( 5 );\n\t\tif ( parameters.morphNormals )\n\t\t\t_programLayers.enable( 6 );\n\t\tif ( parameters.morphColors )\n\t\t\t_programLayers.enable( 7 );\n\t\tif ( parameters.premultipliedAlpha )\n\t\t\t_programLayers.enable( 8 );\n\t\tif ( parameters.shadowMapEnabled )\n\t\t\t_programLayers.enable( 9 );\n\t\tif ( parameters.doubleSided )\n\t\t\t_programLayers.enable( 10 );\n\t\tif ( parameters.flipSided )\n\t\t\t_programLayers.enable( 11 );\n\t\tif ( parameters.useDepthPacking )\n\t\t\t_programLayers.enable( 12 );\n\t\tif ( parameters.dithering )\n\t\t\t_programLayers.enable( 13 );\n\t\tif ( parameters.transmission )\n\t\t\t_programLayers.enable( 14 );\n\t\tif ( parameters.sheen )\n\t\t\t_programLayers.enable( 15 );\n\t\tif ( parameters.opaque )\n\t\t\t_programLayers.enable( 16 );\n\t\tif ( parameters.pointsUvs )\n\t\t\t_programLayers.enable( 17 );\n\t\tif ( parameters.decodeVideoTexture )\n\t\t\t_programLayers.enable( 18 );\n\t\tif ( parameters.alphaToCoverage )\n\t\t\t_programLayers.enable( 19 );\n\n\t\tarray.push( _programLayers.mask );\n\n\t}\n\n\tfunction getUniforms( material ) {\n\n\t\tconst shaderID = shaderIDs[ material.type ];\n\t\tlet uniforms;\n\n\t\tif ( shaderID ) {\n\n\t\t\tconst shader = ShaderLib[ shaderID ];\n\t\t\tuniforms = UniformsUtils.clone( shader.uniforms );\n\n\t\t} else {\n\n\t\t\tuniforms = material.uniforms;\n\n\t\t}\n\n\t\treturn uniforms;\n\n\t}\n\n\tfunction acquireProgram( parameters, cacheKey ) {\n\n\t\tlet program;\n\n\t\t// Check if code has been already compiled\n\t\tfor ( let p = 0, pl = programs.length; p < pl; p ++ ) {\n\n\t\t\tconst preexistingProgram = programs[ p ];\n\n\t\t\tif ( preexistingProgram.cacheKey === cacheKey ) {\n\n\t\t\t\tprogram = preexistingProgram;\n\t\t\t\t++ program.usedTimes;\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( program === undefined ) {\n\n\t\t\tprogram = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );\n\t\t\tprograms.push( program );\n\n\t\t}\n\n\t\treturn program;\n\n\t}\n\n\tfunction releaseProgram( program ) {\n\n\t\tif ( -- program.usedTimes === 0 ) {\n\n\t\t\t// Remove from unordered set\n\t\t\tconst i = programs.indexOf( program );\n\t\t\tprograms[ i ] = programs[ programs.length - 1 ];\n\t\t\tprograms.pop();\n\n\t\t\t// Free WebGL resources\n\t\t\tprogram.destroy();\n\n\t\t}\n\n\t}\n\n\tfunction releaseShaderCache( material ) {\n\n\t\t_customShaders.remove( material );\n\n\t}\n\n\tfunction dispose() {\n\n\t\t_customShaders.dispose();\n\n\t}\n\n\treturn {\n\t\tgetParameters: getParameters,\n\t\tgetProgramCacheKey: getProgramCacheKey,\n\t\tgetUniforms: getUniforms,\n\t\tacquireProgram: acquireProgram,\n\t\treleaseProgram: releaseProgram,\n\t\treleaseShaderCache: releaseShaderCache,\n\t\t// Exposed for resource monitoring & error feedback via renderer.info:\n\t\tprograms: programs,\n\t\tdispose: dispose\n\t};\n\n}\n\nfunction WebGLProperties() {\n\n\tlet properties = new WeakMap();\n\n\tfunction get( object ) {\n\n\t\tlet map = properties.get( object );\n\n\t\tif ( map === undefined ) {\n\n\t\t\tmap = {};\n\t\t\tproperties.set( object, map );\n\n\t\t}\n\n\t\treturn map;\n\n\t}\n\n\tfunction remove( object ) {\n\n\t\tproperties.delete( object );\n\n\t}\n\n\tfunction update( object, key, value ) {\n\n\t\tproperties.get( object )[ key ] = value;\n\n\t}\n\n\tfunction dispose() {\n\n\t\tproperties = new WeakMap();\n\n\t}\n\n\treturn {\n\t\tget: get,\n\t\tremove: remove,\n\t\tupdate: update,\n\t\tdispose: dispose\n\t};\n\n}\n\nfunction painterSortStable( a, b ) {\n\n\tif ( a.groupOrder !== b.groupOrder ) {\n\n\t\treturn a.groupOrder - b.groupOrder;\n\n\t} else if ( a.renderOrder !== b.renderOrder ) {\n\n\t\treturn a.renderOrder - b.renderOrder;\n\n\t} else if ( a.material.id !== b.material.id ) {\n\n\t\treturn a.material.id - b.material.id;\n\n\t} else if ( a.z !== b.z ) {\n\n\t\treturn a.z - b.z;\n\n\t} else {\n\n\t\treturn a.id - b.id;\n\n\t}\n\n}\n\nfunction reversePainterSortStable( a, b ) {\n\n\tif ( a.groupOrder !== b.groupOrder ) {\n\n\t\treturn a.groupOrder - b.groupOrder;\n\n\t} else if ( a.renderOrder !== b.renderOrder ) {\n\n\t\treturn a.renderOrder - b.renderOrder;\n\n\t} else if ( a.z !== b.z ) {\n\n\t\treturn b.z - a.z;\n\n\t} else {\n\n\t\treturn a.id - b.id;\n\n\t}\n\n}\n\n\nfunction WebGLRenderList() {\n\n\tconst renderItems = [];\n\tlet renderItemsIndex = 0;\n\n\tconst opaque = [];\n\tconst transmissive = [];\n\tconst transparent = [];\n\n\tfunction init() {\n\n\t\trenderItemsIndex = 0;\n\n\t\topaque.length = 0;\n\t\ttransmissive.length = 0;\n\t\ttransparent.length = 0;\n\n\t}\n\n\tfunction getNextRenderItem( object, geometry, material, groupOrder, z, group ) {\n\n\t\tlet renderItem = renderItems[ renderItemsIndex ];\n\n\t\tif ( renderItem === undefined ) {\n\n\t\t\trenderItem = {\n\t\t\t\tid: object.id,\n\t\t\t\tobject: object,\n\t\t\t\tgeometry: geometry,\n\t\t\t\tmaterial: material,\n\t\t\t\tgroupOrder: groupOrder,\n\t\t\t\trenderOrder: object.renderOrder,\n\t\t\t\tz: z,\n\t\t\t\tgroup: group\n\t\t\t};\n\n\t\t\trenderItems[ renderItemsIndex ] = renderItem;\n\n\t\t} else {\n\n\t\t\trenderItem.id = object.id;\n\t\t\trenderItem.object = object;\n\t\t\trenderItem.geometry = geometry;\n\t\t\trenderItem.material = material;\n\t\t\trenderItem.groupOrder = groupOrder;\n\t\t\trenderItem.renderOrder = object.renderOrder;\n\t\t\trenderItem.z = z;\n\t\t\trenderItem.group = group;\n\n\t\t}\n\n\t\trenderItemsIndex ++;\n\n\t\treturn renderItem;\n\n\t}\n\n\tfunction push( object, geometry, material, groupOrder, z, group ) {\n\n\t\tconst renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );\n\n\t\tif ( material.transmission > 0.0 ) {\n\n\t\t\ttransmissive.push( renderItem );\n\n\t\t} else if ( material.transparent === true ) {\n\n\t\t\ttransparent.push( renderItem );\n\n\t\t} else {\n\n\t\t\topaque.push( renderItem );\n\n\t\t}\n\n\t}\n\n\tfunction unshift( object, geometry, material, groupOrder, z, group ) {\n\n\t\tconst renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );\n\n\t\tif ( material.transmission > 0.0 ) {\n\n\t\t\ttransmissive.unshift( renderItem );\n\n\t\t} else if ( material.transparent === true ) {\n\n\t\t\ttransparent.unshift( renderItem );\n\n\t\t} else {\n\n\t\t\topaque.unshift( renderItem );\n\n\t\t}\n\n\t}\n\n\tfunction sort( customOpaqueSort, customTransparentSort ) {\n\n\t\tif ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );\n\t\tif ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable );\n\t\tif ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );\n\n\t}\n\n\tfunction finish() {\n\n\t\t// Clear references from inactive renderItems in the list\n\n\t\tfor ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {\n\n\t\t\tconst renderItem = renderItems[ i ];\n\n\t\t\tif ( renderItem.id === null ) break;\n\n\t\t\trenderItem.id = null;\n\t\t\trenderItem.object = null;\n\t\t\trenderItem.geometry = null;\n\t\t\trenderItem.material = null;\n\t\t\trenderItem.group = null;\n\n\t\t}\n\n\t}\n\n\treturn {\n\n\t\topaque: opaque,\n\t\ttransmissive: transmissive,\n\t\ttransparent: transparent,\n\n\t\tinit: init,\n\t\tpush: push,\n\t\tunshift: unshift,\n\t\tfinish: finish,\n\n\t\tsort: sort\n\t};\n\n}\n\nfunction WebGLRenderLists() {\n\n\tlet lists = new WeakMap();\n\n\tfunction get( scene, renderCallDepth ) {\n\n\t\tconst listArray = lists.get( scene );\n\t\tlet list;\n\n\t\tif ( listArray === undefined ) {\n\n\t\t\tlist = new WebGLRenderList();\n\t\t\tlists.set( scene, [ list ] );\n\n\t\t} else {\n\n\t\t\tif ( renderCallDepth >= listArray.length ) {\n\n\t\t\t\tlist = new WebGLRenderList();\n\t\t\t\tlistArray.push( list );\n\n\t\t\t} else {\n\n\t\t\t\tlist = listArray[ renderCallDepth ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn list;\n\n\t}\n\n\tfunction dispose() {\n\n\t\tlists = new WeakMap();\n\n\t}\n\n\treturn {\n\t\tget: get,\n\t\tdispose: dispose\n\t};\n\n}\n\nfunction UniformsCache() {\n\n\tconst lights = {};\n\n\treturn {\n\n\t\tget: function ( light ) {\n\n\t\t\tif ( lights[ light.id ] !== undefined ) {\n\n\t\t\t\treturn lights[ light.id ];\n\n\t\t\t}\n\n\t\t\tlet uniforms;\n\n\t\t\tswitch ( light.type ) {\n\n\t\t\t\tcase 'DirectionalLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\tcolor: new Color()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'SpotLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\tdistance: 0,\n\t\t\t\t\t\tconeCos: 0,\n\t\t\t\t\t\tpenumbraCos: 0,\n\t\t\t\t\t\tdecay: 0\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'PointLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\tdistance: 0,\n\t\t\t\t\t\tdecay: 0\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'HemisphereLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\tskyColor: new Color(),\n\t\t\t\t\t\tgroundColor: new Color()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'RectAreaLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\thalfWidth: new Vector3(),\n\t\t\t\t\t\thalfHeight: new Vector3()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tlights[ light.id ] = uniforms;\n\n\t\t\treturn uniforms;\n\n\t\t}\n\n\t};\n\n}\n\nfunction ShadowUniformsCache() {\n\n\tconst lights = {};\n\n\treturn {\n\n\t\tget: function ( light ) {\n\n\t\t\tif ( lights[ light.id ] !== undefined ) {\n\n\t\t\t\treturn lights[ light.id ];\n\n\t\t\t}\n\n\t\t\tlet uniforms;\n\n\t\t\tswitch ( light.type ) {\n\n\t\t\t\tcase 'DirectionalLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tshadowIntensity: 1,\n\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\tshadowNormalBias: 0,\n\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\tshadowMapSize: new Vector2()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'SpotLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tshadowIntensity: 1,\n\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\tshadowNormalBias: 0,\n\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\tshadowMapSize: new Vector2()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'PointLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tshadowIntensity: 1,\n\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\tshadowNormalBias: 0,\n\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\tshadowMapSize: new Vector2(),\n\t\t\t\t\t\tshadowCameraNear: 1,\n\t\t\t\t\t\tshadowCameraFar: 1000\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\t// TODO (abelnation): set RectAreaLight shadow uniforms\n\n\t\t\t}\n\n\t\t\tlights[ light.id ] = uniforms;\n\n\t\t\treturn uniforms;\n\n\t\t}\n\n\t};\n\n}\n\n\n\nlet nextVersion = 0;\n\nfunction shadowCastingAndTexturingLightsFirst( lightA, lightB ) {\n\n\treturn ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 );\n\n}\n\nfunction WebGLLights( extensions ) {\n\n\tconst cache = new UniformsCache();\n\n\tconst shadowCache = ShadowUniformsCache();\n\n\tconst state = {\n\n\t\tversion: 0,\n\n\t\thash: {\n\t\t\tdirectionalLength: - 1,\n\t\t\tpointLength: - 1,\n\t\t\tspotLength: - 1,\n\t\t\trectAreaLength: - 1,\n\t\t\themiLength: - 1,\n\n\t\t\tnumDirectionalShadows: - 1,\n\t\t\tnumPointShadows: - 1,\n\t\t\tnumSpotShadows: - 1,\n\t\t\tnumSpotMaps: - 1,\n\n\t\t\tnumLightProbes: - 1\n\t\t},\n\n\t\tambient: [ 0, 0, 0 ],\n\t\tprobe: [],\n\t\tdirectional: [],\n\t\tdirectionalShadow: [],\n\t\tdirectionalShadowMap: [],\n\t\tdirectionalShadowMatrix: [],\n\t\tspot: [],\n\t\tspotLightMap: [],\n\t\tspotShadow: [],\n\t\tspotShadowMap: [],\n\t\tspotLightMatrix: [],\n\t\trectArea: [],\n\t\trectAreaLTC1: null,\n\t\trectAreaLTC2: null,\n\t\tpoint: [],\n\t\tpointShadow: [],\n\t\tpointShadowMap: [],\n\t\tpointShadowMatrix: [],\n\t\themi: [],\n\t\tnumSpotLightShadowsWithMaps: 0,\n\t\tnumLightProbes: 0\n\n\t};\n\n\tfor ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );\n\n\tconst vector3 = new Vector3();\n\tconst matrix4 = new Matrix4();\n\tconst matrix42 = new Matrix4();\n\n\tfunction setup( lights ) {\n\n\t\tlet r = 0, g = 0, b = 0;\n\n\t\tfor ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );\n\n\t\tlet directionalLength = 0;\n\t\tlet pointLength = 0;\n\t\tlet spotLength = 0;\n\t\tlet rectAreaLength = 0;\n\t\tlet hemiLength = 0;\n\n\t\tlet numDirectionalShadows = 0;\n\t\tlet numPointShadows = 0;\n\t\tlet numSpotShadows = 0;\n\t\tlet numSpotMaps = 0;\n\t\tlet numSpotShadowsWithMaps = 0;\n\n\t\tlet numLightProbes = 0;\n\n\t\t// ordering : [shadow casting + map texturing, map texturing, shadow casting, none ]\n\t\tlights.sort( shadowCastingAndTexturingLightsFirst );\n\n\t\tfor ( let i = 0, l = lights.length; i < l; i ++ ) {\n\n\t\t\tconst light = lights[ i ];\n\n\t\t\tconst color = light.color;\n\t\t\tconst intensity = light.intensity;\n\t\t\tconst distance = light.distance;\n\n\t\t\tconst shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;\n\n\t\t\tif ( light.isAmbientLight ) {\n\n\t\t\t\tr += color.r * intensity;\n\t\t\t\tg += color.g * intensity;\n\t\t\t\tb += color.b * intensity;\n\n\t\t\t} else if ( light.isLightProbe ) {\n\n\t\t\t\tfor ( let j = 0; j < 9; j ++ ) {\n\n\t\t\t\t\tstate.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );\n\n\t\t\t\t}\n\n\t\t\t\tnumLightProbes ++;\n\n\t\t\t} else if ( light.isDirectionalLight ) {\n\n\t\t\t\tconst uniforms = cache.get( light );\n\n\t\t\t\tuniforms.color.copy( light.color ).multiplyScalar( light.intensity );\n\n\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\tconst shadow = light.shadow;\n\n\t\t\t\t\tconst shadowUniforms = shadowCache.get( light );\n\n\t\t\t\t\tshadowUniforms.shadowIntensity = shadow.intensity;\n\t\t\t\t\tshadowUniforms.shadowBias = shadow.bias;\n\t\t\t\t\tshadowUniforms.shadowNormalBias = shadow.normalBias;\n\t\t\t\t\tshadowUniforms.shadowRadius = shadow.radius;\n\t\t\t\t\tshadowUniforms.shadowMapSize = shadow.mapSize;\n\n\t\t\t\t\tstate.directionalShadow[ directionalLength ] = shadowUniforms;\n\t\t\t\t\tstate.directionalShadowMap[ directionalLength ] = shadowMap;\n\t\t\t\t\tstate.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;\n\n\t\t\t\t\tnumDirectionalShadows ++;\n\n\t\t\t\t}\n\n\t\t\t\tstate.directional[ directionalLength ] = uniforms;\n\n\t\t\t\tdirectionalLength ++;\n\n\t\t\t} else if ( light.isSpotLight ) {\n\n\t\t\t\tconst uniforms = cache.get( light );\n\n\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\n\t\t\t\tuniforms.color.copy( color ).multiplyScalar( intensity );\n\t\t\t\tuniforms.distance = distance;\n\n\t\t\t\tuniforms.coneCos = Math.cos( light.angle );\n\t\t\t\tuniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );\n\t\t\t\tuniforms.decay = light.decay;\n\n\t\t\t\tstate.spot[ spotLength ] = uniforms;\n\n\t\t\t\tconst shadow = light.shadow;\n\n\t\t\t\tif ( light.map ) {\n\n\t\t\t\t\tstate.spotLightMap[ numSpotMaps ] = light.map;\n\t\t\t\t\tnumSpotMaps ++;\n\n\t\t\t\t\t// make sure the lightMatrix is up to date\n\t\t\t\t\t// TODO : do it if required only\n\t\t\t\t\tshadow.updateMatrices( light );\n\n\t\t\t\t\tif ( light.castShadow ) numSpotShadowsWithMaps ++;\n\n\t\t\t\t}\n\n\t\t\t\tstate.spotLightMatrix[ spotLength ] = shadow.matrix;\n\n\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\tconst shadowUniforms = shadowCache.get( light );\n\n\t\t\t\t\tshadowUniforms.shadowIntensity = shadow.intensity;\n\t\t\t\t\tshadowUniforms.shadowBias = shadow.bias;\n\t\t\t\t\tshadowUniforms.shadowNormalBias = shadow.normalBias;\n\t\t\t\t\tshadowUniforms.shadowRadius = shadow.radius;\n\t\t\t\t\tshadowUniforms.shadowMapSize = shadow.mapSize;\n\n\t\t\t\t\tstate.spotShadow[ spotLength ] = shadowUniforms;\n\t\t\t\t\tstate.spotShadowMap[ spotLength ] = shadowMap;\n\n\t\t\t\t\tnumSpotShadows ++;\n\n\t\t\t\t}\n\n\t\t\t\tspotLength ++;\n\n\t\t\t} else if ( light.isRectAreaLight ) {\n\n\t\t\t\tconst uniforms = cache.get( light );\n\n\t\t\t\tuniforms.color.copy( color ).multiplyScalar( intensity );\n\n\t\t\t\tuniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );\n\t\t\t\tuniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );\n\n\t\t\t\tstate.rectArea[ rectAreaLength ] = uniforms;\n\n\t\t\t\trectAreaLength ++;\n\n\t\t\t} else if ( light.isPointLight ) {\n\n\t\t\t\tconst uniforms = cache.get( light );\n\n\t\t\t\tuniforms.color.copy( light.color ).multiplyScalar( light.intensity );\n\t\t\t\tuniforms.distance = light.distance;\n\t\t\t\tuniforms.decay = light.decay;\n\n\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\tconst shadow = light.shadow;\n\n\t\t\t\t\tconst shadowUniforms = shadowCache.get( light );\n\n\t\t\t\t\tshadowUniforms.shadowIntensity = shadow.intensity;\n\t\t\t\t\tshadowUniforms.shadowBias = shadow.bias;\n\t\t\t\t\tshadowUniforms.shadowNormalBias = shadow.normalBias;\n\t\t\t\t\tshadowUniforms.shadowRadius = shadow.radius;\n\t\t\t\t\tshadowUniforms.shadowMapSize = shadow.mapSize;\n\t\t\t\t\tshadowUniforms.shadowCameraNear = shadow.camera.near;\n\t\t\t\t\tshadowUniforms.shadowCameraFar = shadow.camera.far;\n\n\t\t\t\t\tstate.pointShadow[ pointLength ] = shadowUniforms;\n\t\t\t\t\tstate.pointShadowMap[ pointLength ] = shadowMap;\n\t\t\t\t\tstate.pointShadowMatrix[ pointLength ] = light.shadow.matrix;\n\n\t\t\t\t\tnumPointShadows ++;\n\n\t\t\t\t}\n\n\t\t\t\tstate.point[ pointLength ] = uniforms;\n\n\t\t\t\tpointLength ++;\n\n\t\t\t} else if ( light.isHemisphereLight ) {\n\n\t\t\t\tconst uniforms = cache.get( light );\n\n\t\t\t\tuniforms.skyColor.copy( light.color ).multiplyScalar( intensity );\n\t\t\t\tuniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );\n\n\t\t\t\tstate.hemi[ hemiLength ] = uniforms;\n\n\t\t\t\themiLength ++;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( rectAreaLength > 0 ) {\n\n\t\t\tif ( extensions.has( 'OES_texture_float_linear' ) === true ) {\n\n\t\t\t\tstate.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;\n\t\t\t\tstate.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;\n\n\t\t\t} else {\n\n\t\t\t\tstate.rectAreaLTC1 = UniformsLib.LTC_HALF_1;\n\t\t\t\tstate.rectAreaLTC2 = UniformsLib.LTC_HALF_2;\n\n\t\t\t}\n\n\t\t}\n\n\t\tstate.ambient[ 0 ] = r;\n\t\tstate.ambient[ 1 ] = g;\n\t\tstate.ambient[ 2 ] = b;\n\n\t\tconst hash = state.hash;\n\n\t\tif ( hash.directionalLength !== directionalLength ||\n\t\t\thash.pointLength !== pointLength ||\n\t\t\thash.spotLength !== spotLength ||\n\t\t\thash.rectAreaLength !== rectAreaLength ||\n\t\t\thash.hemiLength !== hemiLength ||\n\t\t\thash.numDirectionalShadows !== numDirectionalShadows ||\n\t\t\thash.numPointShadows !== numPointShadows ||\n\t\t\thash.numSpotShadows !== numSpotShadows ||\n\t\t\thash.numSpotMaps !== numSpotMaps ||\n\t\t\thash.numLightProbes !== numLightProbes ) {\n\n\t\t\tstate.directional.length = directionalLength;\n\t\t\tstate.spot.length = spotLength;\n\t\t\tstate.rectArea.length = rectAreaLength;\n\t\t\tstate.point.length = pointLength;\n\t\t\tstate.hemi.length = hemiLength;\n\n\t\t\tstate.directionalShadow.length = numDirectionalShadows;\n\t\t\tstate.directionalShadowMap.length = numDirectionalShadows;\n\t\t\tstate.pointShadow.length = numPointShadows;\n\t\t\tstate.pointShadowMap.length = numPointShadows;\n\t\t\tstate.spotShadow.length = numSpotShadows;\n\t\t\tstate.spotShadowMap.length = numSpotShadows;\n\t\t\tstate.directionalShadowMatrix.length = numDirectionalShadows;\n\t\t\tstate.pointShadowMatrix.length = numPointShadows;\n\t\t\tstate.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps;\n\t\t\tstate.spotLightMap.length = numSpotMaps;\n\t\t\tstate.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps;\n\t\t\tstate.numLightProbes = numLightProbes;\n\n\t\t\thash.directionalLength = directionalLength;\n\t\t\thash.pointLength = pointLength;\n\t\t\thash.spotLength = spotLength;\n\t\t\thash.rectAreaLength = rectAreaLength;\n\t\t\thash.hemiLength = hemiLength;\n\n\t\t\thash.numDirectionalShadows = numDirectionalShadows;\n\t\t\thash.numPointShadows = numPointShadows;\n\t\t\thash.numSpotShadows = numSpotShadows;\n\t\t\thash.numSpotMaps = numSpotMaps;\n\n\t\t\thash.numLightProbes = numLightProbes;\n\n\t\t\tstate.version = nextVersion ++;\n\n\t\t}\n\n\t}\n\n\tfunction setupView( lights, camera ) {\n\n\t\tlet directionalLength = 0;\n\t\tlet pointLength = 0;\n\t\tlet spotLength = 0;\n\t\tlet rectAreaLength = 0;\n\t\tlet hemiLength = 0;\n\n\t\tconst viewMatrix = camera.matrixWorldInverse;\n\n\t\tfor ( let i = 0, l = lights.length; i < l; i ++ ) {\n\n\t\t\tconst light = lights[ i ];\n\n\t\t\tif ( light.isDirectionalLight ) {\n\n\t\t\t\tconst uniforms = state.directional[ directionalLength ];\n\n\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tvector3.setFromMatrixPosition( light.target.matrixWorld );\n\t\t\t\tuniforms.direction.sub( vector3 );\n\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\n\t\t\t\tdirectionalLength ++;\n\n\t\t\t} else if ( light.isSpotLight ) {\n\n\t\t\t\tconst uniforms = state.spot[ spotLength ];\n\n\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tvector3.setFromMatrixPosition( light.target.matrixWorld );\n\t\t\t\tuniforms.direction.sub( vector3 );\n\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\n\t\t\t\tspotLength ++;\n\n\t\t\t} else if ( light.isRectAreaLight ) {\n\n\t\t\t\tconst uniforms = state.rectArea[ rectAreaLength ];\n\n\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\t// extract local rotation of light to derive width/height half vectors\n\t\t\t\tmatrix42.identity();\n\t\t\t\tmatrix4.copy( light.matrixWorld );\n\t\t\t\tmatrix4.premultiply( viewMatrix );\n\t\t\t\tmatrix42.extractRotation( matrix4 );\n\n\t\t\t\tuniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );\n\t\t\t\tuniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );\n\n\t\t\t\tuniforms.halfWidth.applyMatrix4( matrix42 );\n\t\t\t\tuniforms.halfHeight.applyMatrix4( matrix42 );\n\n\t\t\t\trectAreaLength ++;\n\n\t\t\t} else if ( light.isPointLight ) {\n\n\t\t\t\tconst uniforms = state.point[ pointLength ];\n\n\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\tpointLength ++;\n\n\t\t\t} else if ( light.isHemisphereLight ) {\n\n\t\t\t\tconst uniforms = state.hemi[ hemiLength ];\n\n\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\n\t\t\t\themiLength ++;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn {\n\t\tsetup: setup,\n\t\tsetupView: setupView,\n\t\tstate: state\n\t};\n\n}\n\nfunction WebGLRenderState( extensions ) {\n\n\tconst lights = new WebGLLights( extensions );\n\n\tconst lightsArray = [];\n\tconst shadowsArray = [];\n\n\tfunction init( camera ) {\n\n\t\tstate.camera = camera;\n\n\t\tlightsArray.length = 0;\n\t\tshadowsArray.length = 0;\n\n\t}\n\n\tfunction pushLight( light ) {\n\n\t\tlightsArray.push( light );\n\n\t}\n\n\tfunction pushShadow( shadowLight ) {\n\n\t\tshadowsArray.push( shadowLight );\n\n\t}\n\n\tfunction setupLights() {\n\n\t\tlights.setup( lightsArray );\n\n\t}\n\n\tfunction setupLightsView( camera ) {\n\n\t\tlights.setupView( lightsArray, camera );\n\n\t}\n\n\tconst state = {\n\t\tlightsArray: lightsArray,\n\t\tshadowsArray: shadowsArray,\n\n\t\tcamera: null,\n\n\t\tlights: lights,\n\n\t\ttransmissionRenderTarget: {}\n\t};\n\n\treturn {\n\t\tinit: init,\n\t\tstate: state,\n\t\tsetupLights: setupLights,\n\t\tsetupLightsView: setupLightsView,\n\n\t\tpushLight: pushLight,\n\t\tpushShadow: pushShadow\n\t};\n\n}\n\nfunction WebGLRenderStates( extensions ) {\n\n\tlet renderStates = new WeakMap();\n\n\tfunction get( scene, renderCallDepth = 0 ) {\n\n\t\tconst renderStateArray = renderStates.get( scene );\n\t\tlet renderState;\n\n\t\tif ( renderStateArray === undefined ) {\n\n\t\t\trenderState = new WebGLRenderState( extensions );\n\t\t\trenderStates.set( scene, [ renderState ] );\n\n\t\t} else {\n\n\t\t\tif ( renderCallDepth >= renderStateArray.length ) {\n\n\t\t\t\trenderState = new WebGLRenderState( extensions );\n\t\t\t\trenderStateArray.push( renderState );\n\n\t\t\t} else {\n\n\t\t\t\trenderState = renderStateArray[ renderCallDepth ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn renderState;\n\n\t}\n\n\tfunction dispose() {\n\n\t\trenderStates = new WeakMap();\n\n\t}\n\n\treturn {\n\t\tget: get,\n\t\tdispose: dispose\n\t};\n\n}\n\nclass MeshDepthMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshDepthMaterial = true;\n\n\t\tthis.type = 'MeshDepthMaterial';\n\n\t\tthis.depthPacking = BasicDepthPacking;\n\n\t\tthis.map = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.depthPacking = source.depthPacking;\n\n\t\tthis.map = source.map;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshDistanceMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshDistanceMaterial = true;\n\n\t\tthis.type = 'MeshDistanceMaterial';\n\n\t\tthis.map = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.map = source.map;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst vertex = \"void main() {\\n\\tgl_Position = vec4( position, 1.0 );\\n}\";\n\nconst 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}\";\n\nfunction WebGLShadowMap( renderer, objects, capabilities ) {\n\n\tlet _frustum = new Frustum();\n\n\tconst _shadowMapSize = new Vector2(),\n\t\t_viewportSize = new Vector2(),\n\n\t\t_viewport = new Vector4(),\n\n\t\t_depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ),\n\t\t_distanceMaterial = new MeshDistanceMaterial(),\n\n\t\t_materialCache = {},\n\n\t\t_maxTextureSize = capabilities.maxTextureSize;\n\n\tconst shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide };\n\n\tconst shadowMaterialVertical = new ShaderMaterial( {\n\t\tdefines: {\n\t\t\tVSM_SAMPLES: 8\n\t\t},\n\t\tuniforms: {\n\t\t\tshadow_pass: { value: null },\n\t\t\tresolution: { value: new Vector2() },\n\t\t\tradius: { value: 4.0 }\n\t\t},\n\n\t\tvertexShader: vertex,\n\t\tfragmentShader: fragment\n\n\t} );\n\n\tconst shadowMaterialHorizontal = shadowMaterialVertical.clone();\n\tshadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1;\n\n\tconst fullScreenTri = new BufferGeometry();\n\tfullScreenTri.setAttribute(\n\t\t'position',\n\t\tnew BufferAttribute(\n\t\t\tnew Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ),\n\t\t\t3\n\t\t)\n\t);\n\n\tconst fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical );\n\n\tconst scope = this;\n\n\tthis.enabled = false;\n\n\tthis.autoUpdate = true;\n\tthis.needsUpdate = false;\n\n\tthis.type = PCFShadowMap;\n\tlet _previousType = this.type;\n\n\tthis.render = function ( lights, scene, camera ) {\n\n\t\tif ( scope.enabled === false ) return;\n\t\tif ( scope.autoUpdate === false && scope.needsUpdate === false ) return;\n\n\t\tif ( lights.length === 0 ) return;\n\n\t\tconst currentRenderTarget = renderer.getRenderTarget();\n\t\tconst activeCubeFace = renderer.getActiveCubeFace();\n\t\tconst activeMipmapLevel = renderer.getActiveMipmapLevel();\n\n\t\tconst _state = renderer.state;\n\n\t\t// Set GL state for depth map.\n\t\t_state.setBlending( NoBlending );\n\t\t_state.buffers.color.setClear( 1, 1, 1, 1 );\n\t\t_state.buffers.depth.setTest( true );\n\t\t_state.setScissorTest( false );\n\n\t\t// check for shadow map type changes\n\n\t\tconst toVSM = ( _previousType !== VSMShadowMap && this.type === VSMShadowMap );\n\t\tconst fromVSM = ( _previousType === VSMShadowMap && this.type !== VSMShadowMap );\n\n\t\t// render depth map\n\n\t\tfor ( let i = 0, il = lights.length; i < il; i ++ ) {\n\n\t\t\tconst light = lights[ i ];\n\t\t\tconst shadow = light.shadow;\n\n\t\t\tif ( shadow === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tif ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue;\n\n\t\t\t_shadowMapSize.copy( shadow.mapSize );\n\n\t\t\tconst shadowFrameExtents = shadow.getFrameExtents();\n\n\t\t\t_shadowMapSize.multiply( shadowFrameExtents );\n\n\t\t\t_viewportSize.copy( shadow.mapSize );\n\n\t\t\tif ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) {\n\n\t\t\t\tif ( _shadowMapSize.x > _maxTextureSize ) {\n\n\t\t\t\t\t_viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x );\n\t\t\t\t\t_shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x;\n\t\t\t\t\tshadow.mapSize.x = _viewportSize.x;\n\n\t\t\t\t}\n\n\t\t\t\tif ( _shadowMapSize.y > _maxTextureSize ) {\n\n\t\t\t\t\t_viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y );\n\t\t\t\t\t_shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y;\n\t\t\t\t\tshadow.mapSize.y = _viewportSize.y;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( shadow.map === null || toVSM === true || fromVSM === true ) {\n\n\t\t\t\tconst pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {};\n\n\t\t\t\tif ( shadow.map !== null ) {\n\n\t\t\t\t\tshadow.map.dispose();\n\n\t\t\t\t}\n\n\t\t\t\tshadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );\n\t\t\t\tshadow.map.texture.name = light.name + '.shadowMap';\n\n\t\t\t\tshadow.camera.updateProjectionMatrix();\n\n\t\t\t}\n\n\t\t\trenderer.setRenderTarget( shadow.map );\n\t\t\trenderer.clear();\n\n\t\t\tconst viewportCount = shadow.getViewportCount();\n\n\t\t\tfor ( let vp = 0; vp < viewportCount; vp ++ ) {\n\n\t\t\t\tconst viewport = shadow.getViewport( vp );\n\n\t\t\t\t_viewport.set(\n\t\t\t\t\t_viewportSize.x * viewport.x,\n\t\t\t\t\t_viewportSize.y * viewport.y,\n\t\t\t\t\t_viewportSize.x * viewport.z,\n\t\t\t\t\t_viewportSize.y * viewport.w\n\t\t\t\t);\n\n\t\t\t\t_state.viewport( _viewport );\n\n\t\t\t\tshadow.updateMatrices( light, vp );\n\n\t\t\t\t_frustum = shadow.getFrustum();\n\n\t\t\t\trenderObject( scene, camera, shadow.camera, light, this.type );\n\n\t\t\t}\n\n\t\t\t// do blur pass for VSM\n\n\t\t\tif ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) {\n\n\t\t\t\tVSMPass( shadow, camera );\n\n\t\t\t}\n\n\t\t\tshadow.needsUpdate = false;\n\n\t\t}\n\n\t\t_previousType = this.type;\n\n\t\tscope.needsUpdate = false;\n\n\t\trenderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel );\n\n\t};\n\n\tfunction VSMPass( shadow, camera ) {\n\n\t\tconst geometry = objects.update( fullScreenMesh );\n\n\t\tif ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) {\n\n\t\t\tshadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples;\n\t\t\tshadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples;\n\n\t\t\tshadowMaterialVertical.needsUpdate = true;\n\t\t\tshadowMaterialHorizontal.needsUpdate = true;\n\n\t\t}\n\n\t\tif ( shadow.mapPass === null ) {\n\n\t\t\tshadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y );\n\n\t\t}\n\n\t\t// vertical pass\n\n\t\tshadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;\n\t\tshadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;\n\t\tshadowMaterialVertical.uniforms.radius.value = shadow.radius;\n\t\trenderer.setRenderTarget( shadow.mapPass );\n\t\trenderer.clear();\n\t\trenderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );\n\n\t\t// horizontal pass\n\n\t\tshadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;\n\t\tshadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;\n\t\tshadowMaterialHorizontal.uniforms.radius.value = shadow.radius;\n\t\trenderer.setRenderTarget( shadow.map );\n\t\trenderer.clear();\n\t\trenderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null );\n\n\t}\n\n\tfunction getDepthMaterial( object, material, light, type ) {\n\n\t\tlet result = null;\n\n\t\tconst customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial;\n\n\t\tif ( customMaterial !== undefined ) {\n\n\t\t\tresult = customMaterial;\n\n\t\t} else {\n\n\t\t\tresult = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial;\n\n\t\t\tif ( ( renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) ||\n\t\t\t\t( material.displacementMap && material.displacementScale !== 0 ) ||\n\t\t\t\t( material.alphaMap && material.alphaTest > 0 ) ||\n\t\t\t\t( material.map && material.alphaTest > 0 ) ) {\n\n\t\t\t\t// in this case we need a unique material instance reflecting the\n\t\t\t\t// appropriate state\n\n\t\t\t\tconst keyA = result.uuid, keyB = material.uuid;\n\n\t\t\t\tlet materialsForVariant = _materialCache[ keyA ];\n\n\t\t\t\tif ( materialsForVariant === undefined ) {\n\n\t\t\t\t\tmaterialsForVariant = {};\n\t\t\t\t\t_materialCache[ keyA ] = materialsForVariant;\n\n\t\t\t\t}\n\n\t\t\t\tlet cachedMaterial = materialsForVariant[ keyB ];\n\n\t\t\t\tif ( cachedMaterial === undefined ) {\n\n\t\t\t\t\tcachedMaterial = result.clone();\n\t\t\t\t\tmaterialsForVariant[ keyB ] = cachedMaterial;\n\t\t\t\t\tmaterial.addEventListener( 'dispose', onMaterialDispose );\n\n\t\t\t\t}\n\n\t\t\t\tresult = cachedMaterial;\n\n\t\t\t}\n\n\t\t}\n\n\t\tresult.visible = material.visible;\n\t\tresult.wireframe = material.wireframe;\n\n\t\tif ( type === VSMShadowMap ) {\n\n\t\t\tresult.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;\n\n\t\t} else {\n\n\t\t\tresult.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];\n\n\t\t}\n\n\t\tresult.alphaMap = material.alphaMap;\n\t\tresult.alphaTest = material.alphaTest;\n\t\tresult.map = material.map;\n\n\t\tresult.clipShadows = material.clipShadows;\n\t\tresult.clippingPlanes = material.clippingPlanes;\n\t\tresult.clipIntersection = material.clipIntersection;\n\n\t\tresult.displacementMap = material.displacementMap;\n\t\tresult.displacementScale = material.displacementScale;\n\t\tresult.displacementBias = material.displacementBias;\n\n\t\tresult.wireframeLinewidth = material.wireframeLinewidth;\n\t\tresult.linewidth = material.linewidth;\n\n\t\tif ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {\n\n\t\t\tconst materialProperties = renderer.properties.get( result );\n\t\t\tmaterialProperties.light = light;\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\tfunction renderObject( object, camera, shadowCamera, light, type ) {\n\n\t\tif ( object.visible === false ) return;\n\n\t\tconst visible = object.layers.test( camera.layers );\n\n\t\tif ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {\n\n\t\t\tif ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {\n\n\t\t\t\tobject.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );\n\n\t\t\t\tconst geometry = objects.update( object );\n\t\t\t\tconst material = object.material;\n\n\t\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\t\tconst groups = geometry.groups;\n\n\t\t\t\t\tfor ( let k = 0, kl = groups.length; k < kl; k ++ ) {\n\n\t\t\t\t\t\tconst group = groups[ k ];\n\t\t\t\t\t\tconst groupMaterial = material[ group.materialIndex ];\n\n\t\t\t\t\t\tif ( groupMaterial && groupMaterial.visible ) {\n\n\t\t\t\t\t\t\tconst depthMaterial = getDepthMaterial( object, groupMaterial, light, type );\n\n\t\t\t\t\t\t\tobject.onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, group );\n\n\t\t\t\t\t\t\trenderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );\n\n\t\t\t\t\t\t\tobject.onAfterShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, group );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( material.visible ) {\n\n\t\t\t\t\tconst depthMaterial = getDepthMaterial( object, material, light, type );\n\n\t\t\t\t\tobject.onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, null );\n\n\t\t\t\t\trenderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );\n\n\t\t\t\t\tobject.onAfterShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, null );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst children = object.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\trenderObject( children[ i ], camera, shadowCamera, light, type );\n\n\t\t}\n\n\t}\n\n\tfunction onMaterialDispose( event ) {\n\n\t\tconst material = event.target;\n\n\t\tmaterial.removeEventListener( 'dispose', onMaterialDispose );\n\n\t\t// make sure to remove the unique distance/depth materials used for shadow map rendering\n\n\t\tfor ( const id in _materialCache ) {\n\n\t\t\tconst cache = _materialCache[ id ];\n\n\t\t\tconst uuid = event.target.uuid;\n\n\t\t\tif ( uuid in cache ) {\n\n\t\t\t\tconst shadowMaterial = cache[ uuid ];\n\t\t\t\tshadowMaterial.dispose();\n\t\t\t\tdelete cache[ uuid ];\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nfunction WebGLState( gl ) {\n\n\tfunction ColorBuffer() {\n\n\t\tlet locked = false;\n\n\t\tconst color = new Vector4();\n\t\tlet currentColorMask = null;\n\t\tconst currentColorClear = new Vector4( 0, 0, 0, 0 );\n\n\t\treturn {\n\n\t\t\tsetMask: function ( colorMask ) {\n\n\t\t\t\tif ( currentColorMask !== colorMask && ! locked ) {\n\n\t\t\t\t\tgl.colorMask( colorMask, colorMask, colorMask, colorMask );\n\t\t\t\t\tcurrentColorMask = colorMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\tlocked = lock;\n\n\t\t\t},\n\n\t\t\tsetClear: function ( r, g, b, a, premultipliedAlpha ) {\n\n\t\t\t\tif ( premultipliedAlpha === true ) {\n\n\t\t\t\t\tr *= a; g *= a; b *= a;\n\n\t\t\t\t}\n\n\t\t\t\tcolor.set( r, g, b, a );\n\n\t\t\t\tif ( currentColorClear.equals( color ) === false ) {\n\n\t\t\t\t\tgl.clearColor( r, g, b, a );\n\t\t\t\t\tcurrentColorClear.copy( color );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\treset: function () {\n\n\t\t\t\tlocked = false;\n\n\t\t\t\tcurrentColorMask = null;\n\t\t\t\tcurrentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\tfunction DepthBuffer() {\n\n\t\tlet locked = false;\n\n\t\tlet currentDepthMask = null;\n\t\tlet currentDepthFunc = null;\n\t\tlet currentDepthClear = null;\n\n\t\treturn {\n\n\t\t\tsetTest: function ( depthTest ) {\n\n\t\t\t\tif ( depthTest ) {\n\n\t\t\t\t\tenable( gl.DEPTH_TEST );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tdisable( gl.DEPTH_TEST );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetMask: function ( depthMask ) {\n\n\t\t\t\tif ( currentDepthMask !== depthMask && ! locked ) {\n\n\t\t\t\t\tgl.depthMask( depthMask );\n\t\t\t\t\tcurrentDepthMask = depthMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetFunc: function ( depthFunc ) {\n\n\t\t\t\tif ( currentDepthFunc !== depthFunc ) {\n\n\t\t\t\t\tswitch ( depthFunc ) {\n\n\t\t\t\t\t\tcase NeverDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.NEVER );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase AlwaysDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.ALWAYS );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase LessDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.LESS );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase LessEqualDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.LEQUAL );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase EqualDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.EQUAL );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase GreaterEqualDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.GEQUAL );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase GreaterDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.GREATER );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase NotEqualDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.NOTEQUAL );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.LEQUAL );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tcurrentDepthFunc = depthFunc;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\tlocked = lock;\n\n\t\t\t},\n\n\t\t\tsetClear: function ( depth ) {\n\n\t\t\t\tif ( currentDepthClear !== depth ) {\n\n\t\t\t\t\tgl.clearDepth( depth );\n\t\t\t\t\tcurrentDepthClear = depth;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\treset: function () {\n\n\t\t\t\tlocked = false;\n\n\t\t\t\tcurrentDepthMask = null;\n\t\t\t\tcurrentDepthFunc = null;\n\t\t\t\tcurrentDepthClear = null;\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\tfunction StencilBuffer() {\n\n\t\tlet locked = false;\n\n\t\tlet currentStencilMask = null;\n\t\tlet currentStencilFunc = null;\n\t\tlet currentStencilRef = null;\n\t\tlet currentStencilFuncMask = null;\n\t\tlet currentStencilFail = null;\n\t\tlet currentStencilZFail = null;\n\t\tlet currentStencilZPass = null;\n\t\tlet currentStencilClear = null;\n\n\t\treturn {\n\n\t\t\tsetTest: function ( stencilTest ) {\n\n\t\t\t\tif ( ! locked ) {\n\n\t\t\t\t\tif ( stencilTest ) {\n\n\t\t\t\t\t\tenable( gl.STENCIL_TEST );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tdisable( gl.STENCIL_TEST );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetMask: function ( stencilMask ) {\n\n\t\t\t\tif ( currentStencilMask !== stencilMask && ! locked ) {\n\n\t\t\t\t\tgl.stencilMask( stencilMask );\n\t\t\t\t\tcurrentStencilMask = stencilMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetFunc: function ( stencilFunc, stencilRef, stencilMask ) {\n\n\t\t\t\tif ( currentStencilFunc !== stencilFunc ||\n\t\t\t\t currentStencilRef !== stencilRef ||\n\t\t\t\t currentStencilFuncMask !== stencilMask ) {\n\n\t\t\t\t\tgl.stencilFunc( stencilFunc, stencilRef, stencilMask );\n\n\t\t\t\t\tcurrentStencilFunc = stencilFunc;\n\t\t\t\t\tcurrentStencilRef = stencilRef;\n\t\t\t\t\tcurrentStencilFuncMask = stencilMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetOp: function ( stencilFail, stencilZFail, stencilZPass ) {\n\n\t\t\t\tif ( currentStencilFail !== stencilFail ||\n\t\t\t\t currentStencilZFail !== stencilZFail ||\n\t\t\t\t currentStencilZPass !== stencilZPass ) {\n\n\t\t\t\t\tgl.stencilOp( stencilFail, stencilZFail, stencilZPass );\n\n\t\t\t\t\tcurrentStencilFail = stencilFail;\n\t\t\t\t\tcurrentStencilZFail = stencilZFail;\n\t\t\t\t\tcurrentStencilZPass = stencilZPass;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\tlocked = lock;\n\n\t\t\t},\n\n\t\t\tsetClear: function ( stencil ) {\n\n\t\t\t\tif ( currentStencilClear !== stencil ) {\n\n\t\t\t\t\tgl.clearStencil( stencil );\n\t\t\t\t\tcurrentStencilClear = stencil;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\treset: function () {\n\n\t\t\t\tlocked = false;\n\n\t\t\t\tcurrentStencilMask = null;\n\t\t\t\tcurrentStencilFunc = null;\n\t\t\t\tcurrentStencilRef = null;\n\t\t\t\tcurrentStencilFuncMask = null;\n\t\t\t\tcurrentStencilFail = null;\n\t\t\t\tcurrentStencilZFail = null;\n\t\t\t\tcurrentStencilZPass = null;\n\t\t\t\tcurrentStencilClear = null;\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\t//\n\n\tconst colorBuffer = new ColorBuffer();\n\tconst depthBuffer = new DepthBuffer();\n\tconst stencilBuffer = new StencilBuffer();\n\n\tconst uboBindings = new WeakMap();\n\tconst uboProgramMap = new WeakMap();\n\n\tlet enabledCapabilities = {};\n\n\tlet currentBoundFramebuffers = {};\n\tlet currentDrawbuffers = new WeakMap();\n\tlet defaultDrawbuffers = [];\n\n\tlet currentProgram = null;\n\n\tlet currentBlendingEnabled = false;\n\tlet currentBlending = null;\n\tlet currentBlendEquation = null;\n\tlet currentBlendSrc = null;\n\tlet currentBlendDst = null;\n\tlet currentBlendEquationAlpha = null;\n\tlet currentBlendSrcAlpha = null;\n\tlet currentBlendDstAlpha = null;\n\tlet currentBlendColor = new Color( 0, 0, 0 );\n\tlet currentBlendAlpha = 0;\n\tlet currentPremultipledAlpha = false;\n\n\tlet currentFlipSided = null;\n\tlet currentCullFace = null;\n\n\tlet currentLineWidth = null;\n\n\tlet currentPolygonOffsetFactor = null;\n\tlet currentPolygonOffsetUnits = null;\n\n\tconst maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );\n\n\tlet lineWidthAvailable = false;\n\tlet version = 0;\n\tconst glVersion = gl.getParameter( gl.VERSION );\n\n\tif ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {\n\n\t\tversion = parseFloat( /^WebGL (\\d)/.exec( glVersion )[ 1 ] );\n\t\tlineWidthAvailable = ( version >= 1.0 );\n\n\t} else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {\n\n\t\tversion = parseFloat( /^OpenGL ES (\\d)/.exec( glVersion )[ 1 ] );\n\t\tlineWidthAvailable = ( version >= 2.0 );\n\n\t}\n\n\tlet currentTextureSlot = null;\n\tlet currentBoundTextures = {};\n\n\tconst scissorParam = gl.getParameter( gl.SCISSOR_BOX );\n\tconst viewportParam = gl.getParameter( gl.VIEWPORT );\n\n\tconst currentScissor = new Vector4().fromArray( scissorParam );\n\tconst currentViewport = new Vector4().fromArray( viewportParam );\n\n\tfunction createTexture( type, target, count, dimensions ) {\n\n\t\tconst data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.\n\t\tconst texture = gl.createTexture();\n\n\t\tgl.bindTexture( type, texture );\n\t\tgl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\t\tgl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tif ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) {\n\n\t\t\t\tgl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );\n\n\t\t\t} else {\n\n\t\t\t\tgl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n\tconst emptyTextures = {};\n\temptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );\n\temptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );\n\temptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 );\n\temptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 );\n\n\t// init\n\n\tcolorBuffer.setClear( 0, 0, 0, 1 );\n\tdepthBuffer.setClear( 1 );\n\tstencilBuffer.setClear( 0 );\n\n\tenable( gl.DEPTH_TEST );\n\tdepthBuffer.setFunc( LessEqualDepth );\n\n\tsetFlipSided( false );\n\tsetCullFace( CullFaceBack );\n\tenable( gl.CULL_FACE );\n\n\tsetBlending( NoBlending );\n\n\t//\n\n\tfunction enable( id ) {\n\n\t\tif ( enabledCapabilities[ id ] !== true ) {\n\n\t\t\tgl.enable( id );\n\t\t\tenabledCapabilities[ id ] = true;\n\n\t\t}\n\n\t}\n\n\tfunction disable( id ) {\n\n\t\tif ( enabledCapabilities[ id ] !== false ) {\n\n\t\t\tgl.disable( id );\n\t\t\tenabledCapabilities[ id ] = false;\n\n\t\t}\n\n\t}\n\n\tfunction bindFramebuffer( target, framebuffer ) {\n\n\t\tif ( currentBoundFramebuffers[ target ] !== framebuffer ) {\n\n\t\t\tgl.bindFramebuffer( target, framebuffer );\n\n\t\t\tcurrentBoundFramebuffers[ target ] = framebuffer;\n\n\t\t\t// gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER\n\n\t\t\tif ( target === gl.DRAW_FRAMEBUFFER ) {\n\n\t\t\t\tcurrentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer;\n\n\t\t\t}\n\n\t\t\tif ( target === gl.FRAMEBUFFER ) {\n\n\t\t\t\tcurrentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer;\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\treturn false;\n\n\t}\n\n\tfunction drawBuffers( renderTarget, framebuffer ) {\n\n\t\tlet drawBuffers = defaultDrawbuffers;\n\n\t\tlet needsUpdate = false;\n\n\t\tif ( renderTarget ) {\n\n\t\t\tdrawBuffers = currentDrawbuffers.get( framebuffer );\n\n\t\t\tif ( drawBuffers === undefined ) {\n\n\t\t\t\tdrawBuffers = [];\n\t\t\t\tcurrentDrawbuffers.set( framebuffer, drawBuffers );\n\n\t\t\t}\n\n\t\t\tconst textures = renderTarget.textures;\n\n\t\t\tif ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {\n\n\t\t\t\tfor ( let i = 0, il = textures.length; i < il; i ++ ) {\n\n\t\t\t\t\tdrawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i;\n\n\t\t\t\t}\n\n\t\t\t\tdrawBuffers.length = textures.length;\n\n\t\t\t\tneedsUpdate = true;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif ( drawBuffers[ 0 ] !== gl.BACK ) {\n\n\t\t\t\tdrawBuffers[ 0 ] = gl.BACK;\n\n\t\t\t\tneedsUpdate = true;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( needsUpdate ) {\n\n\t\t\tgl.drawBuffers( drawBuffers );\n\n\t\t}\n\n\t}\n\n\tfunction useProgram( program ) {\n\n\t\tif ( currentProgram !== program ) {\n\n\t\t\tgl.useProgram( program );\n\n\t\t\tcurrentProgram = program;\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\treturn false;\n\n\t}\n\n\tconst equationToGL = {\n\t\t[ AddEquation ]: gl.FUNC_ADD,\n\t\t[ SubtractEquation ]: gl.FUNC_SUBTRACT,\n\t\t[ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT\n\t};\n\n\tequationToGL[ MinEquation ] = gl.MIN;\n\tequationToGL[ MaxEquation ] = gl.MAX;\n\n\tconst factorToGL = {\n\t\t[ ZeroFactor ]: gl.ZERO,\n\t\t[ OneFactor ]: gl.ONE,\n\t\t[ SrcColorFactor ]: gl.SRC_COLOR,\n\t\t[ SrcAlphaFactor ]: gl.SRC_ALPHA,\n\t\t[ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE,\n\t\t[ DstColorFactor ]: gl.DST_COLOR,\n\t\t[ DstAlphaFactor ]: gl.DST_ALPHA,\n\t\t[ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR,\n\t\t[ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA,\n\t\t[ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR,\n\t\t[ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA,\n\t\t[ ConstantColorFactor ]: gl.CONSTANT_COLOR,\n\t\t[ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR,\n\t\t[ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA,\n\t\t[ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA\n\t};\n\n\tfunction setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) {\n\n\t\tif ( blending === NoBlending ) {\n\n\t\t\tif ( currentBlendingEnabled === true ) {\n\n\t\t\t\tdisable( gl.BLEND );\n\t\t\t\tcurrentBlendingEnabled = false;\n\n\t\t\t}\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( currentBlendingEnabled === false ) {\n\n\t\t\tenable( gl.BLEND );\n\t\t\tcurrentBlendingEnabled = true;\n\n\t\t}\n\n\t\tif ( blending !== CustomBlending ) {\n\n\t\t\tif ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {\n\n\t\t\t\tif ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {\n\n\t\t\t\t\tgl.blendEquation( gl.FUNC_ADD );\n\n\t\t\t\t\tcurrentBlendEquation = AddEquation;\n\t\t\t\t\tcurrentBlendEquationAlpha = AddEquation;\n\n\t\t\t\t}\n\n\t\t\t\tif ( premultipliedAlpha ) {\n\n\t\t\t\t\tswitch ( blending ) {\n\n\t\t\t\t\t\tcase NormalBlending:\n\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase AdditiveBlending:\n\t\t\t\t\t\t\tgl.blendFunc( gl.ONE, gl.ONE );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase SubtractiveBlending:\n\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase MultiplyBlending:\n\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tconsole.error( 'THREE.WebGLState: Invalid blending: ', blending );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tswitch ( blending ) {\n\n\t\t\t\t\t\tcase NormalBlending:\n\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase AdditiveBlending:\n\t\t\t\t\t\t\tgl.blendFunc( gl.SRC_ALPHA, gl.ONE );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase SubtractiveBlending:\n\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase MultiplyBlending:\n\t\t\t\t\t\t\tgl.blendFunc( gl.ZERO, gl.SRC_COLOR );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tconsole.error( 'THREE.WebGLState: Invalid blending: ', blending );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tcurrentBlendSrc = null;\n\t\t\t\tcurrentBlendDst = null;\n\t\t\t\tcurrentBlendSrcAlpha = null;\n\t\t\t\tcurrentBlendDstAlpha = null;\n\t\t\t\tcurrentBlendColor.set( 0, 0, 0 );\n\t\t\t\tcurrentBlendAlpha = 0;\n\n\t\t\t\tcurrentBlending = blending;\n\t\t\t\tcurrentPremultipledAlpha = premultipliedAlpha;\n\n\t\t\t}\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t// custom blending\n\n\t\tblendEquationAlpha = blendEquationAlpha || blendEquation;\n\t\tblendSrcAlpha = blendSrcAlpha || blendSrc;\n\t\tblendDstAlpha = blendDstAlpha || blendDst;\n\n\t\tif ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {\n\n\t\t\tgl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );\n\n\t\t\tcurrentBlendEquation = blendEquation;\n\t\t\tcurrentBlendEquationAlpha = blendEquationAlpha;\n\n\t\t}\n\n\t\tif ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {\n\n\t\t\tgl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );\n\n\t\t\tcurrentBlendSrc = blendSrc;\n\t\t\tcurrentBlendDst = blendDst;\n\t\t\tcurrentBlendSrcAlpha = blendSrcAlpha;\n\t\t\tcurrentBlendDstAlpha = blendDstAlpha;\n\n\t\t}\n\n\t\tif ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) {\n\n\t\t\tgl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha );\n\n\t\t\tcurrentBlendColor.copy( blendColor );\n\t\t\tcurrentBlendAlpha = blendAlpha;\n\n\t\t}\n\n\t\tcurrentBlending = blending;\n\t\tcurrentPremultipledAlpha = false;\n\n\t}\n\n\tfunction setMaterial( material, frontFaceCW ) {\n\n\t\tmaterial.side === DoubleSide\n\t\t\t? disable( gl.CULL_FACE )\n\t\t\t: enable( gl.CULL_FACE );\n\n\t\tlet flipSided = ( material.side === BackSide );\n\t\tif ( frontFaceCW ) flipSided = ! flipSided;\n\n\t\tsetFlipSided( flipSided );\n\n\t\t( material.blending === NormalBlending && material.transparent === false )\n\t\t\t? setBlending( NoBlending )\n\t\t\t: setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );\n\n\t\tdepthBuffer.setFunc( material.depthFunc );\n\t\tdepthBuffer.setTest( material.depthTest );\n\t\tdepthBuffer.setMask( material.depthWrite );\n\t\tcolorBuffer.setMask( material.colorWrite );\n\n\t\tconst stencilWrite = material.stencilWrite;\n\t\tstencilBuffer.setTest( stencilWrite );\n\t\tif ( stencilWrite ) {\n\n\t\t\tstencilBuffer.setMask( material.stencilWriteMask );\n\t\t\tstencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );\n\t\t\tstencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );\n\n\t\t}\n\n\t\tsetPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );\n\n\t\tmaterial.alphaToCoverage === true\n\t\t\t? enable( gl.SAMPLE_ALPHA_TO_COVERAGE )\n\t\t\t: disable( gl.SAMPLE_ALPHA_TO_COVERAGE );\n\n\t}\n\n\t//\n\n\tfunction setFlipSided( flipSided ) {\n\n\t\tif ( currentFlipSided !== flipSided ) {\n\n\t\t\tif ( flipSided ) {\n\n\t\t\t\tgl.frontFace( gl.CW );\n\n\t\t\t} else {\n\n\t\t\t\tgl.frontFace( gl.CCW );\n\n\t\t\t}\n\n\t\t\tcurrentFlipSided = flipSided;\n\n\t\t}\n\n\t}\n\n\tfunction setCullFace( cullFace ) {\n\n\t\tif ( cullFace !== CullFaceNone ) {\n\n\t\t\tenable( gl.CULL_FACE );\n\n\t\t\tif ( cullFace !== currentCullFace ) {\n\n\t\t\t\tif ( cullFace === CullFaceBack ) {\n\n\t\t\t\t\tgl.cullFace( gl.BACK );\n\n\t\t\t\t} else if ( cullFace === CullFaceFront ) {\n\n\t\t\t\t\tgl.cullFace( gl.FRONT );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tgl.cullFace( gl.FRONT_AND_BACK );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tdisable( gl.CULL_FACE );\n\n\t\t}\n\n\t\tcurrentCullFace = cullFace;\n\n\t}\n\n\tfunction setLineWidth( width ) {\n\n\t\tif ( width !== currentLineWidth ) {\n\n\t\t\tif ( lineWidthAvailable ) gl.lineWidth( width );\n\n\t\t\tcurrentLineWidth = width;\n\n\t\t}\n\n\t}\n\n\tfunction setPolygonOffset( polygonOffset, factor, units ) {\n\n\t\tif ( polygonOffset ) {\n\n\t\t\tenable( gl.POLYGON_OFFSET_FILL );\n\n\t\t\tif ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {\n\n\t\t\t\tgl.polygonOffset( factor, units );\n\n\t\t\t\tcurrentPolygonOffsetFactor = factor;\n\t\t\t\tcurrentPolygonOffsetUnits = units;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tdisable( gl.POLYGON_OFFSET_FILL );\n\n\t\t}\n\n\t}\n\n\tfunction setScissorTest( scissorTest ) {\n\n\t\tif ( scissorTest ) {\n\n\t\t\tenable( gl.SCISSOR_TEST );\n\n\t\t} else {\n\n\t\t\tdisable( gl.SCISSOR_TEST );\n\n\t\t}\n\n\t}\n\n\t// texture\n\n\tfunction activeTexture( webglSlot ) {\n\n\t\tif ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;\n\n\t\tif ( currentTextureSlot !== webglSlot ) {\n\n\t\t\tgl.activeTexture( webglSlot );\n\t\t\tcurrentTextureSlot = webglSlot;\n\n\t\t}\n\n\t}\n\n\tfunction bindTexture( webglType, webglTexture, webglSlot ) {\n\n\t\tif ( webglSlot === undefined ) {\n\n\t\t\tif ( currentTextureSlot === null ) {\n\n\t\t\t\twebglSlot = gl.TEXTURE0 + maxTextures - 1;\n\n\t\t\t} else {\n\n\t\t\t\twebglSlot = currentTextureSlot;\n\n\t\t\t}\n\n\t\t}\n\n\t\tlet boundTexture = currentBoundTextures[ webglSlot ];\n\n\t\tif ( boundTexture === undefined ) {\n\n\t\t\tboundTexture = { type: undefined, texture: undefined };\n\t\t\tcurrentBoundTextures[ webglSlot ] = boundTexture;\n\n\t\t}\n\n\t\tif ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {\n\n\t\t\tif ( currentTextureSlot !== webglSlot ) {\n\n\t\t\t\tgl.activeTexture( webglSlot );\n\t\t\t\tcurrentTextureSlot = webglSlot;\n\n\t\t\t}\n\n\t\t\tgl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );\n\n\t\t\tboundTexture.type = webglType;\n\t\t\tboundTexture.texture = webglTexture;\n\n\t\t}\n\n\t}\n\n\tfunction unbindTexture() {\n\n\t\tconst boundTexture = currentBoundTextures[ currentTextureSlot ];\n\n\t\tif ( boundTexture !== undefined && boundTexture.type !== undefined ) {\n\n\t\t\tgl.bindTexture( boundTexture.type, null );\n\n\t\t\tboundTexture.type = undefined;\n\t\t\tboundTexture.texture = undefined;\n\n\t\t}\n\n\t}\n\n\tfunction compressedTexImage2D() {\n\n\t\ttry {\n\n\t\t\tgl.compressedTexImage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction compressedTexImage3D() {\n\n\t\ttry {\n\n\t\t\tgl.compressedTexImage3D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texSubImage2D() {\n\n\t\ttry {\n\n\t\t\tgl.texSubImage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texSubImage3D() {\n\n\t\ttry {\n\n\t\t\tgl.texSubImage3D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction compressedTexSubImage2D() {\n\n\t\ttry {\n\n\t\t\tgl.compressedTexSubImage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction compressedTexSubImage3D() {\n\n\t\ttry {\n\n\t\t\tgl.compressedTexSubImage3D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texStorage2D() {\n\n\t\ttry {\n\n\t\t\tgl.texStorage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texStorage3D() {\n\n\t\ttry {\n\n\t\t\tgl.texStorage3D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texImage2D() {\n\n\t\ttry {\n\n\t\t\tgl.texImage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texImage3D() {\n\n\t\ttry {\n\n\t\t\tgl.texImage3D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\t//\n\n\tfunction scissor( scissor ) {\n\n\t\tif ( currentScissor.equals( scissor ) === false ) {\n\n\t\t\tgl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );\n\t\t\tcurrentScissor.copy( scissor );\n\n\t\t}\n\n\t}\n\n\tfunction viewport( viewport ) {\n\n\t\tif ( currentViewport.equals( viewport ) === false ) {\n\n\t\t\tgl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );\n\t\t\tcurrentViewport.copy( viewport );\n\n\t\t}\n\n\t}\n\n\tfunction updateUBOMapping( uniformsGroup, program ) {\n\n\t\tlet mapping = uboProgramMap.get( program );\n\n\t\tif ( mapping === undefined ) {\n\n\t\t\tmapping = new WeakMap();\n\n\t\t\tuboProgramMap.set( program, mapping );\n\n\t\t}\n\n\t\tlet blockIndex = mapping.get( uniformsGroup );\n\n\t\tif ( blockIndex === undefined ) {\n\n\t\t\tblockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name );\n\n\t\t\tmapping.set( uniformsGroup, blockIndex );\n\n\t\t}\n\n\t}\n\n\tfunction uniformBlockBinding( uniformsGroup, program ) {\n\n\t\tconst mapping = uboProgramMap.get( program );\n\t\tconst blockIndex = mapping.get( uniformsGroup );\n\n\t\tif ( uboBindings.get( program ) !== blockIndex ) {\n\n\t\t\t// bind shader specific block index to global block point\n\t\t\tgl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex );\n\n\t\t\tuboBindings.set( program, blockIndex );\n\n\t\t}\n\n\t}\n\n\t//\n\n\tfunction reset() {\n\n\t\t// reset state\n\n\t\tgl.disable( gl.BLEND );\n\t\tgl.disable( gl.CULL_FACE );\n\t\tgl.disable( gl.DEPTH_TEST );\n\t\tgl.disable( gl.POLYGON_OFFSET_FILL );\n\t\tgl.disable( gl.SCISSOR_TEST );\n\t\tgl.disable( gl.STENCIL_TEST );\n\t\tgl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );\n\n\t\tgl.blendEquation( gl.FUNC_ADD );\n\t\tgl.blendFunc( gl.ONE, gl.ZERO );\n\t\tgl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO );\n\t\tgl.blendColor( 0, 0, 0, 0 );\n\n\t\tgl.colorMask( true, true, true, true );\n\t\tgl.clearColor( 0, 0, 0, 0 );\n\n\t\tgl.depthMask( true );\n\t\tgl.depthFunc( gl.LESS );\n\t\tgl.clearDepth( 1 );\n\n\t\tgl.stencilMask( 0xffffffff );\n\t\tgl.stencilFunc( gl.ALWAYS, 0, 0xffffffff );\n\t\tgl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP );\n\t\tgl.clearStencil( 0 );\n\n\t\tgl.cullFace( gl.BACK );\n\t\tgl.frontFace( gl.CCW );\n\n\t\tgl.polygonOffset( 0, 0 );\n\n\t\tgl.activeTexture( gl.TEXTURE0 );\n\n\t\tgl.bindFramebuffer( gl.FRAMEBUFFER, null );\n\t\tgl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );\n\t\tgl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );\n\n\t\tgl.useProgram( null );\n\n\t\tgl.lineWidth( 1 );\n\n\t\tgl.scissor( 0, 0, gl.canvas.width, gl.canvas.height );\n\t\tgl.viewport( 0, 0, gl.canvas.width, gl.canvas.height );\n\n\t\t// reset internals\n\n\t\tenabledCapabilities = {};\n\n\t\tcurrentTextureSlot = null;\n\t\tcurrentBoundTextures = {};\n\n\t\tcurrentBoundFramebuffers = {};\n\t\tcurrentDrawbuffers = new WeakMap();\n\t\tdefaultDrawbuffers = [];\n\n\t\tcurrentProgram = null;\n\n\t\tcurrentBlendingEnabled = false;\n\t\tcurrentBlending = null;\n\t\tcurrentBlendEquation = null;\n\t\tcurrentBlendSrc = null;\n\t\tcurrentBlendDst = null;\n\t\tcurrentBlendEquationAlpha = null;\n\t\tcurrentBlendSrcAlpha = null;\n\t\tcurrentBlendDstAlpha = null;\n\t\tcurrentBlendColor = new Color( 0, 0, 0 );\n\t\tcurrentBlendAlpha = 0;\n\t\tcurrentPremultipledAlpha = false;\n\n\t\tcurrentFlipSided = null;\n\t\tcurrentCullFace = null;\n\n\t\tcurrentLineWidth = null;\n\n\t\tcurrentPolygonOffsetFactor = null;\n\t\tcurrentPolygonOffsetUnits = null;\n\n\t\tcurrentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height );\n\t\tcurrentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height );\n\n\t\tcolorBuffer.reset();\n\t\tdepthBuffer.reset();\n\t\tstencilBuffer.reset();\n\n\t}\n\n\treturn {\n\n\t\tbuffers: {\n\t\t\tcolor: colorBuffer,\n\t\t\tdepth: depthBuffer,\n\t\t\tstencil: stencilBuffer\n\t\t},\n\n\t\tenable: enable,\n\t\tdisable: disable,\n\n\t\tbindFramebuffer: bindFramebuffer,\n\t\tdrawBuffers: drawBuffers,\n\n\t\tuseProgram: useProgram,\n\n\t\tsetBlending: setBlending,\n\t\tsetMaterial: setMaterial,\n\n\t\tsetFlipSided: setFlipSided,\n\t\tsetCullFace: setCullFace,\n\n\t\tsetLineWidth: setLineWidth,\n\t\tsetPolygonOffset: setPolygonOffset,\n\n\t\tsetScissorTest: setScissorTest,\n\n\t\tactiveTexture: activeTexture,\n\t\tbindTexture: bindTexture,\n\t\tunbindTexture: unbindTexture,\n\t\tcompressedTexImage2D: compressedTexImage2D,\n\t\tcompressedTexImage3D: compressedTexImage3D,\n\t\ttexImage2D: texImage2D,\n\t\ttexImage3D: texImage3D,\n\n\t\tupdateUBOMapping: updateUBOMapping,\n\t\tuniformBlockBinding: uniformBlockBinding,\n\n\t\ttexStorage2D: texStorage2D,\n\t\ttexStorage3D: texStorage3D,\n\t\ttexSubImage2D: texSubImage2D,\n\t\ttexSubImage3D: texSubImage3D,\n\t\tcompressedTexSubImage2D: compressedTexSubImage2D,\n\t\tcompressedTexSubImage3D: compressedTexSubImage3D,\n\n\t\tscissor: scissor,\n\t\tviewport: viewport,\n\n\t\treset: reset\n\n\t};\n\n}\n\nfunction contain( texture, aspect ) {\n\n\tconst imageAspect = ( texture.image && texture.image.width ) ? texture.image.width / texture.image.height : 1;\n\n\tif ( imageAspect > aspect ) {\n\n\t\ttexture.repeat.x = 1;\n\t\ttexture.repeat.y = imageAspect / aspect;\n\n\t\ttexture.offset.x = 0;\n\t\ttexture.offset.y = ( 1 - texture.repeat.y ) / 2;\n\n\t} else {\n\n\t\ttexture.repeat.x = aspect / imageAspect;\n\t\ttexture.repeat.y = 1;\n\n\t\ttexture.offset.x = ( 1 - texture.repeat.x ) / 2;\n\t\ttexture.offset.y = 0;\n\n\t}\n\n\treturn texture;\n\n}\n\nfunction cover( texture, aspect ) {\n\n\tconst imageAspect = ( texture.image && texture.image.width ) ? texture.image.width / texture.image.height : 1;\n\n\tif ( imageAspect > aspect ) {\n\n\t\ttexture.repeat.x = aspect / imageAspect;\n\t\ttexture.repeat.y = 1;\n\n\t\ttexture.offset.x = ( 1 - texture.repeat.x ) / 2;\n\t\ttexture.offset.y = 0;\n\n\t} else {\n\n\t\ttexture.repeat.x = 1;\n\t\ttexture.repeat.y = imageAspect / aspect;\n\n\t\ttexture.offset.x = 0;\n\t\ttexture.offset.y = ( 1 - texture.repeat.y ) / 2;\n\n\t}\n\n\treturn texture;\n\n}\n\nfunction fill( texture ) {\n\n\ttexture.repeat.x = 1;\n\ttexture.repeat.y = 1;\n\n\ttexture.offset.x = 0;\n\ttexture.offset.y = 0;\n\n\treturn texture;\n\n}\n\n\n\n/**\n * Given the width, height, format, and type of a texture. Determines how many\n * bytes must be used to represent the texture.\n */\nfunction getByteLength( width, height, format, type ) {\n\n\tconst typeByteLength = getTextureTypeByteLength( type );\n\n\tswitch ( format ) {\n\n\t\t// https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml\n\t\tcase AlphaFormat:\n\t\t\treturn width * height;\n\t\tcase LuminanceFormat:\n\t\t\treturn width * height;\n\t\tcase LuminanceAlphaFormat:\n\t\t\treturn width * height * 2;\n\t\tcase RedFormat:\n\t\t\treturn ( ( width * height ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RedIntegerFormat:\n\t\t\treturn ( ( width * height ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RGFormat:\n\t\t\treturn ( ( width * height * 2 ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RGIntegerFormat:\n\t\t\treturn ( ( width * height * 2 ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RGBFormat:\n\t\t\treturn ( ( width * height * 3 ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RGBAFormat:\n\t\t\treturn ( ( width * height * 4 ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RGBAIntegerFormat:\n\t\t\treturn ( ( width * height * 4 ) / typeByteLength.components ) * typeByteLength.byteLength;\n\n\t\t// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_s3tc_srgb/\n\t\tcase RGB_S3TC_DXT1_Format:\n\t\tcase RGBA_S3TC_DXT1_Format:\n\t\t\treturn Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 8;\n\t\tcase RGBA_S3TC_DXT3_Format:\n\t\tcase RGBA_S3TC_DXT5_Format:\n\t\t\treturn Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16;\n\n\t\t// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_pvrtc/\n\t\tcase RGB_PVRTC_2BPPV1_Format:\n\t\tcase RGBA_PVRTC_2BPPV1_Format:\n\t\t\treturn ( Math.max( width, 16 ) * Math.max( height, 8 ) ) / 4;\n\t\tcase RGB_PVRTC_4BPPV1_Format:\n\t\tcase RGBA_PVRTC_4BPPV1_Format:\n\t\t\treturn ( Math.max( width, 8 ) * Math.max( height, 8 ) ) / 2;\n\n\t\t// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_etc/\n\t\tcase RGB_ETC1_Format:\n\t\tcase RGB_ETC2_Format:\n\t\t\treturn Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 8;\n\t\tcase RGBA_ETC2_EAC_Format:\n\t\t\treturn Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16;\n\n\t\t// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_astc/\n\t\tcase RGBA_ASTC_4x4_Format:\n\t\t\treturn Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16;\n\t\tcase RGBA_ASTC_5x4_Format:\n\t\t\treturn Math.floor( ( width + 4 ) / 5 ) * Math.floor( ( height + 3 ) / 4 ) * 16;\n\t\tcase RGBA_ASTC_5x5_Format:\n\t\t\treturn Math.floor( ( width + 4 ) / 5 ) * Math.floor( ( height + 4 ) / 5 ) * 16;\n\t\tcase RGBA_ASTC_6x5_Format:\n\t\t\treturn Math.floor( ( width + 5 ) / 6 ) * Math.floor( ( height + 4 ) / 5 ) * 16;\n\t\tcase RGBA_ASTC_6x6_Format:\n\t\t\treturn Math.floor( ( width + 5 ) / 6 ) * Math.floor( ( height + 5 ) / 6 ) * 16;\n\t\tcase RGBA_ASTC_8x5_Format:\n\t\t\treturn Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 4 ) / 5 ) * 16;\n\t\tcase RGBA_ASTC_8x6_Format:\n\t\t\treturn Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 5 ) / 6 ) * 16;\n\t\tcase RGBA_ASTC_8x8_Format:\n\t\t\treturn Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 7 ) / 8 ) * 16;\n\t\tcase RGBA_ASTC_10x5_Format:\n\t\t\treturn Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 4 ) / 5 ) * 16;\n\t\tcase RGBA_ASTC_10x6_Format:\n\t\t\treturn Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 5 ) / 6 ) * 16;\n\t\tcase RGBA_ASTC_10x8_Format:\n\t\t\treturn Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 7 ) / 8 ) * 16;\n\t\tcase RGBA_ASTC_10x10_Format:\n\t\t\treturn Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 9 ) / 10 ) * 16;\n\t\tcase RGBA_ASTC_12x10_Format:\n\t\t\treturn Math.floor( ( width + 11 ) / 12 ) * Math.floor( ( height + 9 ) / 10 ) * 16;\n\t\tcase RGBA_ASTC_12x12_Format:\n\t\t\treturn Math.floor( ( width + 11 ) / 12 ) * Math.floor( ( height + 11 ) / 12 ) * 16;\n\n\t\t// https://registry.khronos.org/webgl/extensions/EXT_texture_compression_bptc/\n\t\tcase RGBA_BPTC_Format:\n\t\tcase RGB_BPTC_SIGNED_Format:\n\t\tcase RGB_BPTC_UNSIGNED_Format:\n\t\t\treturn Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 16;\n\n\t\t// https://registry.khronos.org/webgl/extensions/EXT_texture_compression_rgtc/\n\t\tcase RED_RGTC1_Format:\n\t\tcase SIGNED_RED_RGTC1_Format:\n\t\t\treturn Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 8;\n\t\tcase RED_GREEN_RGTC2_Format:\n\t\tcase SIGNED_RED_GREEN_RGTC2_Format:\n\t\t\treturn Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 16;\n\n\t}\n\n\tthrow new Error(\n\t\t`Unable to determine texture byte length for ${format} format.`,\n\t);\n\n}\n\nfunction getTextureTypeByteLength( type ) {\n\n\tswitch ( type ) {\n\n\t\tcase UnsignedByteType:\n\t\tcase ByteType:\n\t\t\treturn { byteLength: 1, components: 1 };\n\t\tcase UnsignedShortType:\n\t\tcase ShortType:\n\t\tcase HalfFloatType:\n\t\t\treturn { byteLength: 2, components: 1 };\n\t\tcase UnsignedShort4444Type:\n\t\tcase UnsignedShort5551Type:\n\t\t\treturn { byteLength: 2, components: 4 };\n\t\tcase UnsignedIntType:\n\t\tcase IntType:\n\t\tcase FloatType:\n\t\t\treturn { byteLength: 4, components: 1 };\n\t\tcase UnsignedInt5999Type:\n\t\t\treturn { byteLength: 4, components: 3 };\n\n\t}\n\n\tthrow new Error( `Unknown texture type ${type}.` );\n\n}\n\nconst TextureUtils = {\n\tcontain,\n\tcover,\n\tfill,\n\tgetByteLength\n};\n\nfunction WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {\n\n\tconst multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null;\n\tconst supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent );\n\n\tconst _imageDimensions = new Vector2();\n\tconst _videoTextures = new WeakMap();\n\tlet _canvas;\n\n\tconst _sources = new WeakMap(); // maps WebglTexture objects to instances of Source\n\n\t// cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,\n\t// also OffscreenCanvas.getContext(\"webgl\"), but not OffscreenCanvas.getContext(\"2d\")!\n\t// Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).\n\n\tlet useOffscreenCanvas = false;\n\n\ttry {\n\n\t\tuseOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'\n\t\t\t// eslint-disable-next-line compat/compat\n\t\t\t&& ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null;\n\n\t} catch ( err ) {\n\n\t\t// Ignore any errors\n\n\t}\n\n\tfunction createCanvas( width, height ) {\n\n\t\t// Use OffscreenCanvas when available. Specially needed in web workers\n\n\t\treturn useOffscreenCanvas ?\n\t\t\t// eslint-disable-next-line compat/compat\n\t\t\tnew OffscreenCanvas( width, height ) : createElementNS( 'canvas' );\n\n\t}\n\n\tfunction resizeImage( image, needsNewCanvas, maxSize ) {\n\n\t\tlet scale = 1;\n\n\t\tconst dimensions = getDimensions( image );\n\n\t\t// handle case if texture exceeds max size\n\n\t\tif ( dimensions.width > maxSize || dimensions.height > maxSize ) {\n\n\t\t\tscale = maxSize / Math.max( dimensions.width, dimensions.height );\n\n\t\t}\n\n\t\t// only perform resize if necessary\n\n\t\tif ( scale < 1 ) {\n\n\t\t\t// only perform resize for certain image types\n\n\t\t\tif ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||\n\t\t\t\t( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||\n\t\t\t\t( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ||\n\t\t\t\t( typeof VideoFrame !== 'undefined' && image instanceof VideoFrame ) ) {\n\n\t\t\t\tconst width = Math.floor( scale * dimensions.width );\n\t\t\t\tconst height = Math.floor( scale * dimensions.height );\n\n\t\t\t\tif ( _canvas === undefined ) _canvas = createCanvas( width, height );\n\n\t\t\t\t// cube textures can't reuse the same canvas\n\n\t\t\t\tconst canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;\n\n\t\t\t\tcanvas.width = width;\n\t\t\t\tcanvas.height = height;\n\n\t\t\t\tconst context = canvas.getContext( '2d' );\n\t\t\t\tcontext.drawImage( image, 0, 0, width, height );\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + dimensions.width + 'x' + dimensions.height + ') to (' + width + 'x' + height + ').' );\n\n\t\t\t\treturn canvas;\n\n\t\t\t} else {\n\n\t\t\t\tif ( 'data' in image ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + dimensions.width + 'x' + dimensions.height + ').' );\n\n\t\t\t\t}\n\n\t\t\t\treturn image;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn image;\n\n\t}\n\n\tfunction textureNeedsGenerateMipmaps( texture ) {\n\n\t\treturn texture.generateMipmaps && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;\n\n\t}\n\n\tfunction generateMipmap( target ) {\n\n\t\t_gl.generateMipmap( target );\n\n\t}\n\n\tfunction getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) {\n\n\t\tif ( internalFormatName !== null ) {\n\n\t\t\tif ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \\'' + internalFormatName + '\\'' );\n\n\t\t}\n\n\t\tlet internalFormat = glFormat;\n\n\t\tif ( glFormat === _gl.RED ) {\n\n\t\t\tif ( glType === _gl.FLOAT ) internalFormat = _gl.R32F;\n\t\t\tif ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F;\n\t\t\tif ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8;\n\n\t\t}\n\n\t\tif ( glFormat === _gl.RED_INTEGER ) {\n\n\t\t\tif ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI;\n\t\t\tif ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI;\n\t\t\tif ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI;\n\t\t\tif ( glType === _gl.BYTE ) internalFormat = _gl.R8I;\n\t\t\tif ( glType === _gl.SHORT ) internalFormat = _gl.R16I;\n\t\t\tif ( glType === _gl.INT ) internalFormat = _gl.R32I;\n\n\t\t}\n\n\t\tif ( glFormat === _gl.RG ) {\n\n\t\t\tif ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F;\n\t\t\tif ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F;\n\t\t\tif ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8;\n\n\t\t}\n\n\t\tif ( glFormat === _gl.RG_INTEGER ) {\n\n\t\t\tif ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8UI;\n\t\t\tif ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RG16UI;\n\t\t\tif ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RG32UI;\n\t\t\tif ( glType === _gl.BYTE ) internalFormat = _gl.RG8I;\n\t\t\tif ( glType === _gl.SHORT ) internalFormat = _gl.RG16I;\n\t\t\tif ( glType === _gl.INT ) internalFormat = _gl.RG32I;\n\n\t\t}\n\n\t\tif ( glFormat === _gl.RGB ) {\n\n\t\t\tif ( glType === _gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = _gl.RGB9_E5;\n\n\t\t}\n\n\t\tif ( glFormat === _gl.RGBA ) {\n\n\t\t\tconst transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace );\n\n\t\t\tif ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F;\n\t\t\tif ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F;\n\t\t\tif ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8;\n\t\t\tif ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4;\n\t\t\tif ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1;\n\n\t\t}\n\n\t\tif ( internalFormat === _gl.R16F || internalFormat === _gl.R32F ||\n\t\t\tinternalFormat === _gl.RG16F || internalFormat === _gl.RG32F ||\n\t\t\tinternalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) {\n\n\t\t\textensions.get( 'EXT_color_buffer_float' );\n\n\t\t}\n\n\t\treturn internalFormat;\n\n\t}\n\n\tfunction getInternalDepthFormat( useStencil, depthType ) {\n\n\t\tlet glInternalFormat;\n\t\tif ( useStencil ) {\n\n\t\t\tif ( depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH24_STENCIL8;\n\n\t\t\t} else if ( depthType === FloatType ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH32F_STENCIL8;\n\n\t\t\t} else if ( depthType === UnsignedShortType ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH24_STENCIL8;\n\t\t\t\tconsole.warn( 'DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.' );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif ( depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH_COMPONENT24;\n\n\t\t\t} else if ( depthType === FloatType ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH_COMPONENT32F;\n\n\t\t\t} else if ( depthType === UnsignedShortType ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH_COMPONENT16;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn glInternalFormat;\n\n\t}\n\n\tfunction getMipLevels( texture, image ) {\n\n\t\tif ( textureNeedsGenerateMipmaps( texture ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) {\n\n\t\t\treturn Math.log2( Math.max( image.width, image.height ) ) + 1;\n\n\t\t} else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) {\n\n\t\t\t// user-defined mipmaps\n\n\t\t\treturn texture.mipmaps.length;\n\n\t\t} else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) {\n\n\t\t\treturn image.mipmaps.length;\n\n\t\t} else {\n\n\t\t\t// texture without mipmaps (only base level)\n\n\t\t\treturn 1;\n\n\t\t}\n\n\t}\n\n\t//\n\n\tfunction onTextureDispose( event ) {\n\n\t\tconst texture = event.target;\n\n\t\ttexture.removeEventListener( 'dispose', onTextureDispose );\n\n\t\tdeallocateTexture( texture );\n\n\t\tif ( texture.isVideoTexture ) {\n\n\t\t\t_videoTextures.delete( texture );\n\n\t\t}\n\n\t}\n\n\tfunction onRenderTargetDispose( event ) {\n\n\t\tconst renderTarget = event.target;\n\n\t\trenderTarget.removeEventListener( 'dispose', onRenderTargetDispose );\n\n\t\tdeallocateRenderTarget( renderTarget );\n\n\t}\n\n\t//\n\n\tfunction deallocateTexture( texture ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\n\t\tif ( textureProperties.__webglInit === undefined ) return;\n\n\t\t// check if it's necessary to remove the WebGLTexture object\n\n\t\tconst source = texture.source;\n\t\tconst webglTextures = _sources.get( source );\n\n\t\tif ( webglTextures ) {\n\n\t\t\tconst webglTexture = webglTextures[ textureProperties.__cacheKey ];\n\t\t\twebglTexture.usedTimes --;\n\n\t\t\t// the WebGLTexture object is not used anymore, remove it\n\n\t\t\tif ( webglTexture.usedTimes === 0 ) {\n\n\t\t\t\tdeleteTexture( texture );\n\n\t\t\t}\n\n\t\t\t// remove the weak map entry if no WebGLTexture uses the source anymore\n\n\t\t\tif ( Object.keys( webglTextures ).length === 0 ) {\n\n\t\t\t\t_sources.delete( source );\n\n\t\t\t}\n\n\t\t}\n\n\t\tproperties.remove( texture );\n\n\t}\n\n\tfunction deleteTexture( texture ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\t\t_gl.deleteTexture( textureProperties.__webglTexture );\n\n\t\tconst source = texture.source;\n\t\tconst webglTextures = _sources.get( source );\n\t\tdelete webglTextures[ textureProperties.__cacheKey ];\n\n\t\tinfo.memory.textures --;\n\n\t}\n\n\tfunction deallocateRenderTarget( renderTarget ) {\n\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\n\t\tif ( renderTarget.depthTexture ) {\n\n\t\t\trenderTarget.depthTexture.dispose();\n\n\t\t}\n\n\t\tif ( renderTarget.isWebGLCubeRenderTarget ) {\n\n\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\tif ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) {\n\n\t\t\t\t\tfor ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );\n\n\t\t\t\t}\n\n\t\t\t\tif ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) {\n\n\t\t\t\tfor ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] );\n\n\t\t\t} else {\n\n\t\t\t\t_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );\n\n\t\t\t}\n\n\t\t\tif ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );\n\t\t\tif ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );\n\n\t\t\tif ( renderTargetProperties.__webglColorRenderbuffer ) {\n\n\t\t\t\tfor ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) {\n\n\t\t\t\t\tif ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );\n\n\t\t}\n\n\t\tconst textures = renderTarget.textures;\n\n\t\tfor ( let i = 0, il = textures.length; i < il; i ++ ) {\n\n\t\t\tconst attachmentProperties = properties.get( textures[ i ] );\n\n\t\t\tif ( attachmentProperties.__webglTexture ) {\n\n\t\t\t\t_gl.deleteTexture( attachmentProperties.__webglTexture );\n\n\t\t\t\tinfo.memory.textures --;\n\n\t\t\t}\n\n\t\t\tproperties.remove( textures[ i ] );\n\n\t\t}\n\n\t\tproperties.remove( renderTarget );\n\n\t}\n\n\t//\n\n\tlet textureUnits = 0;\n\n\tfunction resetTextureUnits() {\n\n\t\ttextureUnits = 0;\n\n\t}\n\n\tfunction allocateTextureUnit() {\n\n\t\tconst textureUnit = textureUnits;\n\n\t\tif ( textureUnit >= capabilities.maxTextures ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );\n\n\t\t}\n\n\t\ttextureUnits += 1;\n\n\t\treturn textureUnit;\n\n\t}\n\n\tfunction getTextureCacheKey( texture ) {\n\n\t\tconst array = [];\n\n\t\tarray.push( texture.wrapS );\n\t\tarray.push( texture.wrapT );\n\t\tarray.push( texture.wrapR || 0 );\n\t\tarray.push( texture.magFilter );\n\t\tarray.push( texture.minFilter );\n\t\tarray.push( texture.anisotropy );\n\t\tarray.push( texture.internalFormat );\n\t\tarray.push( texture.format );\n\t\tarray.push( texture.type );\n\t\tarray.push( texture.generateMipmaps );\n\t\tarray.push( texture.premultiplyAlpha );\n\t\tarray.push( texture.flipY );\n\t\tarray.push( texture.unpackAlignment );\n\t\tarray.push( texture.colorSpace );\n\n\t\treturn array.join();\n\n\t}\n\n\t//\n\n\tfunction setTexture2D( texture, slot ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\n\t\tif ( texture.isVideoTexture ) updateVideoTexture( texture );\n\n\t\tif ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\tconst image = texture.image;\n\n\t\t\tif ( image === null ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' );\n\n\t\t\t} else if ( image.complete === false ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );\n\n\t\t\t} else {\n\n\t\t\t\tuploadTexture( textureProperties, texture, slot );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t}\n\n\t\tstate.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t}\n\n\tfunction setTexture2DArray( texture, slot ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\n\t\tif ( texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\tuploadTexture( textureProperties, texture, slot );\n\t\t\treturn;\n\n\t\t}\n\n\t\tstate.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t}\n\n\tfunction setTexture3D( texture, slot ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\n\t\tif ( texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\tuploadTexture( textureProperties, texture, slot );\n\t\t\treturn;\n\n\t\t}\n\n\t\tstate.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t}\n\n\tfunction setTextureCube( texture, slot ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\n\t\tif ( texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\tuploadCubeTexture( textureProperties, texture, slot );\n\t\t\treturn;\n\n\t\t}\n\n\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t}\n\n\tconst wrappingToGL = {\n\t\t[ RepeatWrapping ]: _gl.REPEAT,\n\t\t[ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE,\n\t\t[ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT\n\t};\n\n\tconst filterToGL = {\n\t\t[ NearestFilter ]: _gl.NEAREST,\n\t\t[ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST,\n\t\t[ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR,\n\n\t\t[ LinearFilter ]: _gl.LINEAR,\n\t\t[ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST,\n\t\t[ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR\n\t};\n\n\tconst compareToGL = {\n\t\t[ NeverCompare ]: _gl.NEVER,\n\t\t[ AlwaysCompare ]: _gl.ALWAYS,\n\t\t[ LessCompare ]: _gl.LESS,\n\t\t[ LessEqualCompare ]: _gl.LEQUAL,\n\t\t[ EqualCompare ]: _gl.EQUAL,\n\t\t[ GreaterEqualCompare ]: _gl.GEQUAL,\n\t\t[ GreaterCompare ]: _gl.GREATER,\n\t\t[ NotEqualCompare ]: _gl.NOTEQUAL\n\t};\n\n\tfunction setTextureParameters( textureType, texture ) {\n\n\t\tif ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false &&\n\t\t\t( texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter ||\n\t\t\ttexture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter ) ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device.' );\n\n\t\t}\n\n\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] );\n\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] );\n\n\t\tif ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {\n\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] );\n\n\t\t}\n\n\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] );\n\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] );\n\n\t\tif ( texture.compareFunction ) {\n\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_MODE, _gl.COMPARE_REF_TO_TEXTURE );\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] );\n\n\t\t}\n\n\t\tif ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {\n\n\t\t\tif ( texture.magFilter === NearestFilter ) return;\n\t\t\tif ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return;\n\t\t\tif ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension\n\n\t\t\tif ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {\n\n\t\t\t\tconst extension = extensions.get( 'EXT_texture_filter_anisotropic' );\n\t\t\t\t_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );\n\t\t\t\tproperties.get( texture ).__currentAnisotropy = texture.anisotropy;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction initTexture( textureProperties, texture ) {\n\n\t\tlet forceUpload = false;\n\n\t\tif ( textureProperties.__webglInit === undefined ) {\n\n\t\t\ttextureProperties.__webglInit = true;\n\n\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\n\n\t\t}\n\n\t\t// create Source <-> WebGLTextures mapping if necessary\n\n\t\tconst source = texture.source;\n\t\tlet webglTextures = _sources.get( source );\n\n\t\tif ( webglTextures === undefined ) {\n\n\t\t\twebglTextures = {};\n\t\t\t_sources.set( source, webglTextures );\n\n\t\t}\n\n\t\t// check if there is already a WebGLTexture object for the given texture parameters\n\n\t\tconst textureCacheKey = getTextureCacheKey( texture );\n\n\t\tif ( textureCacheKey !== textureProperties.__cacheKey ) {\n\n\t\t\t// if not, create a new instance of WebGLTexture\n\n\t\t\tif ( webglTextures[ textureCacheKey ] === undefined ) {\n\n\t\t\t\t// create new entry\n\n\t\t\t\twebglTextures[ textureCacheKey ] = {\n\t\t\t\t\ttexture: _gl.createTexture(),\n\t\t\t\t\tusedTimes: 0\n\t\t\t\t};\n\n\t\t\t\tinfo.memory.textures ++;\n\n\t\t\t\t// when a new instance of WebGLTexture was created, a texture upload is required\n\t\t\t\t// even if the image contents are identical\n\n\t\t\t\tforceUpload = true;\n\n\t\t\t}\n\n\t\t\twebglTextures[ textureCacheKey ].usedTimes ++;\n\n\t\t\t// every time the texture cache key changes, it's necessary to check if an instance of\n\t\t\t// WebGLTexture can be deleted in order to avoid a memory leak.\n\n\t\t\tconst webglTexture = webglTextures[ textureProperties.__cacheKey ];\n\n\t\t\tif ( webglTexture !== undefined ) {\n\n\t\t\t\twebglTextures[ textureProperties.__cacheKey ].usedTimes --;\n\n\t\t\t\tif ( webglTexture.usedTimes === 0 ) {\n\n\t\t\t\t\tdeleteTexture( texture );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// store references to cache key and WebGLTexture object\n\n\t\t\ttextureProperties.__cacheKey = textureCacheKey;\n\t\t\ttextureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture;\n\n\t\t}\n\n\t\treturn forceUpload;\n\n\t}\n\n\tfunction uploadTexture( textureProperties, texture, slot ) {\n\n\t\tlet textureType = _gl.TEXTURE_2D;\n\n\t\tif ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY;\n\t\tif ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D;\n\n\t\tconst forceUpload = initTexture( textureProperties, texture );\n\t\tconst source = texture.source;\n\n\t\tstate.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t\tconst sourceProperties = properties.get( source );\n\n\t\tif ( source.version !== sourceProperties.__version || forceUpload === true ) {\n\n\t\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\n\t\t\tconst workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );\n\t\t\tconst texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );\n\t\t\tconst unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );\n\n\t\t\tlet image = resizeImage( texture.image, false, capabilities.maxTextureSize );\n\t\t\timage = verifyColorSpace( texture, image );\n\n\t\t\tconst glFormat = utils.convert( texture.format, texture.colorSpace );\n\n\t\t\tconst glType = utils.convert( texture.type );\n\t\t\tlet glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture );\n\n\t\t\tsetTextureParameters( textureType, texture );\n\n\t\t\tlet mipmap;\n\t\t\tconst mipmaps = texture.mipmaps;\n\n\t\t\tconst useTexStorage = ( texture.isVideoTexture !== true );\n\t\t\tconst allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );\n\t\t\tconst dataReady = source.dataReady;\n\t\t\tconst levels = getMipLevels( texture, image );\n\n\t\t\tif ( texture.isDepthTexture ) {\n\n\t\t\t\tglInternalFormat = getInternalDepthFormat( texture.format === DepthStencilFormat, texture.type );\n\n\t\t\t\t//\n\n\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( texture.isDataTexture ) {\n\n\t\t\t\t// use manually created mipmaps if available\n\t\t\t\t// if there are no manual mipmaps\n\t\t\t\t// set 0 level mipmap and then use GL to generate other mipmap levels\n\n\t\t\t\tif ( mipmaps.length > 0 ) {\n\n\t\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( let i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tmipmap = mipmaps[ i ];\n\n\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture.generateMipmaps = false;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( texture.isCompressedTexture ) {\n\n\t\t\t\tif ( texture.isCompressedArrayTexture ) {\n\n\t\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\t\tstate.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( let i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tmipmap = mipmaps[ i ];\n\n\t\t\t\t\t\tif ( texture.format !== RGBAFormat ) {\n\n\t\t\t\t\t\t\tif ( glFormat !== null ) {\n\n\t\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\t\tif ( texture.layerUpdates.size > 0 ) {\n\n\t\t\t\t\t\t\t\t\t\t\tconst layerByteLength = getByteLength( mipmap.width, mipmap.height, texture.format, texture.type );\n\n\t\t\t\t\t\t\t\t\t\t\tfor ( const layerIndex of texture.layerUpdates ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst layerData = mipmap.data.subarray(\n\t\t\t\t\t\t\t\t\t\t\t\t\tlayerIndex * layerByteLength / mipmap.data.BYTES_PER_ELEMENT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t( layerIndex + 1 ) * layerByteLength / mipmap.data.BYTES_PER_ELEMENT\n\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\tstate.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, layerIndex, mipmap.width, mipmap.height, 1, glFormat, layerData, 0, 0 );\n\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\ttexture.clearLayerUpdates();\n\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\tstate.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 );\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\tstate.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\tstate.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( let i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tmipmap = mipmaps[ i ];\n\n\t\t\t\t\t\tif ( texture.format !== RGBAFormat ) {\n\n\t\t\t\t\t\t\tif ( glFormat !== null ) {\n\n\t\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\t\tstate.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\tstate.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( texture.isDataArrayTexture ) {\n\n\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\t\tstate.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\tif ( texture.layerUpdates.size > 0 ) {\n\n\t\t\t\t\t\t\tconst layerByteLength = getByteLength( image.width, image.height, texture.format, texture.type );\n\n\t\t\t\t\t\t\tfor ( const layerIndex of texture.layerUpdates ) {\n\n\t\t\t\t\t\t\t\tconst layerData = image.data.subarray(\n\t\t\t\t\t\t\t\t\tlayerIndex * layerByteLength / image.data.BYTES_PER_ELEMENT,\n\t\t\t\t\t\t\t\t\t( layerIndex + 1 ) * layerByteLength / image.data.BYTES_PER_ELEMENT\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tstate.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, layerIndex, image.width, image.height, 1, glFormat, glType, layerData );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttexture.clearLayerUpdates();\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tstate.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );\n\n\t\t\t\t}\n\n\t\t\t} else if ( texture.isData3DTexture ) {\n\n\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\t\tstate.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\tstate.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tstate.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );\n\n\t\t\t\t}\n\n\t\t\t} else if ( texture.isFramebufferTexture ) {\n\n\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tlet width = image.width, height = image.height;\n\n\t\t\t\t\t\tfor ( let i = 0; i < levels; i ++ ) {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null );\n\n\t\t\t\t\t\t\twidth >>= 1;\n\t\t\t\t\t\t\theight >>= 1;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// regular Texture (image, video, canvas)\n\n\t\t\t\t// use manually created mipmaps if available\n\t\t\t\t// if there are no manual mipmaps\n\t\t\t\t// set 0 level mipmap and then use GL to generate other mipmap levels\n\n\t\t\t\tif ( mipmaps.length > 0 ) {\n\n\t\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\t\tconst dimensions = getDimensions( mipmaps[ 0 ] );\n\n\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( let i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tmipmap = mipmaps[ i ];\n\n\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture.generateMipmaps = false;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\t\t\tconst dimensions = getDimensions( image );\n\n\t\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture ) ) {\n\n\t\t\t\tgenerateMipmap( textureType );\n\n\t\t\t}\n\n\t\t\tsourceProperties.__version = source.version;\n\n\t\t\tif ( texture.onUpdate ) texture.onUpdate( texture );\n\n\t\t}\n\n\t\ttextureProperties.__version = texture.version;\n\n\t}\n\n\tfunction uploadCubeTexture( textureProperties, texture, slot ) {\n\n\t\tif ( texture.image.length !== 6 ) return;\n\n\t\tconst forceUpload = initTexture( textureProperties, texture );\n\t\tconst source = texture.source;\n\n\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t\tconst sourceProperties = properties.get( source );\n\n\t\tif ( source.version !== sourceProperties.__version || forceUpload === true ) {\n\n\t\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\n\t\t\tconst workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );\n\t\t\tconst texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );\n\t\t\tconst unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );\n\n\t\t\tconst isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture );\n\t\t\tconst isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );\n\n\t\t\tconst cubeImage = [];\n\n\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\tif ( ! isCompressed && ! isDataTexture ) {\n\n\t\t\t\t\tcubeImage[ i ] = resizeImage( texture.image[ i ], true, capabilities.maxCubemapSize );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tcubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];\n\n\t\t\t\t}\n\n\t\t\t\tcubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] );\n\n\t\t\t}\n\n\t\t\tconst image = cubeImage[ 0 ],\n\t\t\t\tglFormat = utils.convert( texture.format, texture.colorSpace ),\n\t\t\t\tglType = utils.convert( texture.type ),\n\t\t\t\tglInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );\n\n\t\t\tconst useTexStorage = ( texture.isVideoTexture !== true );\n\t\t\tconst allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );\n\t\t\tconst dataReady = source.dataReady;\n\t\t\tlet levels = getMipLevels( texture, image );\n\n\t\t\tsetTextureParameters( _gl.TEXTURE_CUBE_MAP, texture );\n\n\t\t\tlet mipmaps;\n\n\t\t\tif ( isCompressed ) {\n\n\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height );\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\tmipmaps = cubeImage[ i ].mipmaps;\n\n\t\t\t\t\tfor ( let j = 0; j < mipmaps.length; j ++ ) {\n\n\t\t\t\t\t\tconst mipmap = mipmaps[ j ];\n\n\t\t\t\t\t\tif ( texture.format !== RGBAFormat ) {\n\n\t\t\t\t\t\t\tif ( glFormat !== null ) {\n\n\t\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\t\tstate.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\tstate.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tmipmaps = texture.mipmaps;\n\n\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\t// TODO: Uniformly handle mipmap definitions\n\t\t\t\t\t// Normal textures and compressed cube textures define base level + mips with their mipmap array\n\t\t\t\t\t// Uncompressed cube textures use their mipmap array only for mips (no base level)\n\n\t\t\t\t\tif ( mipmaps.length > 0 ) levels ++;\n\n\t\t\t\t\tconst dimensions = getDimensions( cubeImage[ 0 ] );\n\n\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, dimensions.width, dimensions.height );\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\tif ( isDataTexture ) {\n\n\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor ( let j = 0; j < mipmaps.length; j ++ ) {\n\n\t\t\t\t\t\t\tconst mipmap = mipmaps[ j ];\n\t\t\t\t\t\t\tconst mipmapImage = mipmap.image[ i ].image;\n\n\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor ( let j = 0; j < mipmaps.length; j ++ ) {\n\n\t\t\t\t\t\t\tconst mipmap = mipmaps[ j ];\n\n\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture ) ) {\n\n\t\t\t\t// We assume images for cube map have the same size.\n\t\t\t\tgenerateMipmap( _gl.TEXTURE_CUBE_MAP );\n\n\t\t\t}\n\n\t\t\tsourceProperties.__version = source.version;\n\n\t\t\tif ( texture.onUpdate ) texture.onUpdate( texture );\n\n\t\t}\n\n\t\ttextureProperties.__version = texture.version;\n\n\t}\n\n\t// Render targets\n\n\t// Setup storage for target texture and bind it to correct framebuffer\n\tfunction setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) {\n\n\t\tconst glFormat = utils.convert( texture.format, texture.colorSpace );\n\t\tconst glType = utils.convert( texture.type );\n\t\tconst glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\n\t\tif ( ! renderTargetProperties.__hasExternalTextures ) {\n\n\t\t\tconst width = Math.max( 1, renderTarget.width >> level );\n\t\t\tconst height = Math.max( 1, renderTarget.height >> level );\n\n\t\t\tif ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) {\n\n\t\t\t\tstate.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null );\n\n\t\t\t} else {\n\n\t\t\t\tstate.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null );\n\n\t\t\t}\n\n\t\t}\n\n\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\tif ( useMultisampledRTT( renderTarget ) ) {\n\n\t\t\tmultisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) );\n\n\t\t} else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753\n\n\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level );\n\n\t\t}\n\n\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\n\t}\n\n\t// Setup storage for internal depth/stencil buffers and bind to correct framebuffer\n\tfunction setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {\n\n\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );\n\n\t\tif ( renderTarget.depthBuffer ) {\n\n\t\t\t// retrieve the depth attachment types\n\t\t\tconst depthTexture = renderTarget.depthTexture;\n\t\t\tconst depthType = depthTexture && depthTexture.isDepthTexture ? depthTexture.type : null;\n\t\t\tconst glInternalFormat = getInternalDepthFormat( renderTarget.stencilBuffer, depthType );\n\t\t\tconst glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;\n\n\t\t\t// set up the attachment\n\t\t\tconst samples = getRenderTargetSamples( renderTarget );\n\t\t\tconst isUseMultisampledRTT = useMultisampledRTT( renderTarget );\n\t\t\tif ( isUseMultisampledRTT ) {\n\n\t\t\t\tmultisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t} else if ( isMultisample ) {\n\n\t\t\t\t_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t} else {\n\n\t\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t}\n\n\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer );\n\n\t\t} else {\n\n\t\t\tconst textures = renderTarget.textures;\n\n\t\t\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\t\t\tconst texture = textures[ i ];\n\n\t\t\t\tconst glFormat = utils.convert( texture.format, texture.colorSpace );\n\t\t\t\tconst glType = utils.convert( texture.type );\n\t\t\t\tconst glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );\n\t\t\t\tconst samples = getRenderTargetSamples( renderTarget );\n\n\t\t\t\tif ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {\n\n\t\t\t\t\t_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t\t} else if ( useMultisampledRTT( renderTarget ) ) {\n\n\t\t\t\t\tmultisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );\n\n\t}\n\n\t// Setup resources for a Depth Texture for a FBO (needs an extension)\n\tfunction setupDepthTexture( framebuffer, renderTarget ) {\n\n\t\tconst isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );\n\t\tif ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );\n\n\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\tif ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {\n\n\t\t\tthrow new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );\n\n\t\t}\n\n\t\t// upload an empty depth texture with framebuffer size\n\t\tif ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||\n\t\t\t\trenderTarget.depthTexture.image.width !== renderTarget.width ||\n\t\t\t\trenderTarget.depthTexture.image.height !== renderTarget.height ) {\n\n\t\t\trenderTarget.depthTexture.image.width = renderTarget.width;\n\t\t\trenderTarget.depthTexture.image.height = renderTarget.height;\n\t\t\trenderTarget.depthTexture.needsUpdate = true;\n\n\t\t}\n\n\t\tsetTexture2D( renderTarget.depthTexture, 0 );\n\n\t\tconst webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;\n\t\tconst samples = getRenderTargetSamples( renderTarget );\n\n\t\tif ( renderTarget.depthTexture.format === DepthFormat ) {\n\n\t\t\tif ( useMultisampledRTT( renderTarget ) ) {\n\n\t\t\t\tmultisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );\n\n\t\t\t} else {\n\n\t\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );\n\n\t\t\t}\n\n\t\t} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {\n\n\t\t\tif ( useMultisampledRTT( renderTarget ) ) {\n\n\t\t\t\tmultisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );\n\n\t\t\t} else {\n\n\t\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'Unknown depthTexture format' );\n\n\t\t}\n\n\t}\n\n\t// Setup GL resources for a non-texture depth buffer\n\tfunction setupDepthRenderbuffer( renderTarget ) {\n\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\t\tconst isCube = ( renderTarget.isWebGLCubeRenderTarget === true );\n\n\t\tif ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) {\n\n\t\t\tif ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );\n\n\t\t\tsetupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );\n\n\t\t} else {\n\n\t\t\tif ( isCube ) {\n\n\t\t\t\trenderTargetProperties.__webglDepthbuffer = [];\n\n\t\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );\n\t\t\t\t\trenderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();\n\t\t\t\t\tsetupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );\n\t\t\t\trenderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();\n\t\t\t\tsetupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );\n\n\t\t\t}\n\n\t\t}\n\n\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\n\t}\n\n\t// rebind framebuffer with external textures\n\tfunction rebindTextures( renderTarget, colorTexture, depthTexture ) {\n\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\n\t\tif ( colorTexture !== undefined ) {\n\n\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 );\n\n\t\t}\n\n\t\tif ( depthTexture !== undefined ) {\n\n\t\t\tsetupDepthRenderbuffer( renderTarget );\n\n\t\t}\n\n\t}\n\n\t// Set up GL resources for the render target\n\tfunction setupRenderTarget( renderTarget ) {\n\n\t\tconst texture = renderTarget.texture;\n\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\t\tconst textureProperties = properties.get( texture );\n\n\t\trenderTarget.addEventListener( 'dispose', onRenderTargetDispose );\n\n\t\tconst textures = renderTarget.textures;\n\n\t\tconst isCube = ( renderTarget.isWebGLCubeRenderTarget === true );\n\t\tconst isMultipleRenderTargets = ( textures.length > 1 );\n\n\t\tif ( ! isMultipleRenderTargets ) {\n\n\t\t\tif ( textureProperties.__webglTexture === undefined ) {\n\n\t\t\t\ttextureProperties.__webglTexture = _gl.createTexture();\n\n\t\t\t}\n\n\t\t\ttextureProperties.__version = texture.version;\n\t\t\tinfo.memory.textures ++;\n\n\t\t}\n\n\t\t// Setup framebuffer\n\n\t\tif ( isCube ) {\n\n\t\t\trenderTargetProperties.__webglFramebuffer = [];\n\n\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\tif ( texture.mipmaps && texture.mipmaps.length > 0 ) {\n\n\t\t\t\t\trenderTargetProperties.__webglFramebuffer[ i ] = [];\n\n\t\t\t\t\tfor ( let level = 0; level < texture.mipmaps.length; level ++ ) {\n\n\t\t\t\t\t\trenderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer();\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\trenderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif ( texture.mipmaps && texture.mipmaps.length > 0 ) {\n\n\t\t\t\trenderTargetProperties.__webglFramebuffer = [];\n\n\t\t\t\tfor ( let level = 0; level < texture.mipmaps.length; level ++ ) {\n\n\t\t\t\t\trenderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer();\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\trenderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();\n\n\t\t\t}\n\n\t\t\tif ( isMultipleRenderTargets ) {\n\n\t\t\t\tfor ( let i = 0, il = textures.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst attachmentProperties = properties.get( textures[ i ] );\n\n\t\t\t\t\tif ( attachmentProperties.__webglTexture === undefined ) {\n\n\t\t\t\t\t\tattachmentProperties.__webglTexture = _gl.createTexture();\n\n\t\t\t\t\t\tinfo.memory.textures ++;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( ( renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {\n\n\t\t\t\trenderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();\n\t\t\t\trenderTargetProperties.__webglColorRenderbuffer = [];\n\n\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );\n\n\t\t\t\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\t\t\t\tconst texture = textures[ i ];\n\t\t\t\t\trenderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer();\n\n\t\t\t\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );\n\n\t\t\t\t\tconst glFormat = utils.convert( texture.format, texture.colorSpace );\n\t\t\t\t\tconst glType = utils.convert( texture.type );\n\t\t\t\t\tconst glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true );\n\t\t\t\t\tconst samples = getRenderTargetSamples( renderTarget );\n\t\t\t\t\t_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );\n\n\t\t\t\t}\n\n\t\t\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );\n\n\t\t\t\tif ( renderTarget.depthBuffer ) {\n\n\t\t\t\t\trenderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();\n\t\t\t\t\tsetupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );\n\n\t\t\t\t}\n\n\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Setup color buffer\n\n\t\tif ( isCube ) {\n\n\t\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );\n\t\t\tsetTextureParameters( _gl.TEXTURE_CUBE_MAP, texture );\n\n\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\tif ( texture.mipmaps && texture.mipmaps.length > 0 ) {\n\n\t\t\t\t\tfor ( let level = 0; level < texture.mipmaps.length; level ++ ) {\n\n\t\t\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ][ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture ) ) {\n\n\t\t\t\tgenerateMipmap( _gl.TEXTURE_CUBE_MAP );\n\n\t\t\t}\n\n\t\t\tstate.unbindTexture();\n\n\t\t} else if ( isMultipleRenderTargets ) {\n\n\t\t\tfor ( let i = 0, il = textures.length; i < il; i ++ ) {\n\n\t\t\t\tconst attachment = textures[ i ];\n\t\t\t\tconst attachmentProperties = properties.get( attachment );\n\n\t\t\t\tstate.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture );\n\t\t\t\tsetTextureParameters( _gl.TEXTURE_2D, attachment );\n\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 );\n\n\t\t\t\tif ( textureNeedsGenerateMipmaps( attachment ) ) {\n\n\t\t\t\t\tgenerateMipmap( _gl.TEXTURE_2D );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tstate.unbindTexture();\n\n\t\t} else {\n\n\t\t\tlet glTextureType = _gl.TEXTURE_2D;\n\n\t\t\tif ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) {\n\n\t\t\t\tglTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY;\n\n\t\t\t}\n\n\t\t\tstate.bindTexture( glTextureType, textureProperties.__webglTexture );\n\t\t\tsetTextureParameters( glTextureType, texture );\n\n\t\t\tif ( texture.mipmaps && texture.mipmaps.length > 0 ) {\n\n\t\t\t\tfor ( let level = 0; level < texture.mipmaps.length; level ++ ) {\n\n\t\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 );\n\n\t\t\t}\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture ) ) {\n\n\t\t\t\tgenerateMipmap( glTextureType );\n\n\t\t\t}\n\n\t\t\tstate.unbindTexture();\n\n\t\t}\n\n\t\t// Setup depth and stencil buffers\n\n\t\tif ( renderTarget.depthBuffer ) {\n\n\t\t\tsetupDepthRenderbuffer( renderTarget );\n\n\t\t}\n\n\t}\n\n\tfunction updateRenderTargetMipmap( renderTarget ) {\n\n\t\tconst textures = renderTarget.textures;\n\n\t\tfor ( let i = 0, il = textures.length; i < il; i ++ ) {\n\n\t\t\tconst texture = textures[ i ];\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture ) ) {\n\n\t\t\t\tconst target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;\n\t\t\t\tconst webglTexture = properties.get( texture ).__webglTexture;\n\n\t\t\t\tstate.bindTexture( target, webglTexture );\n\t\t\t\tgenerateMipmap( target );\n\t\t\t\tstate.unbindTexture();\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tconst invalidationArrayRead = [];\n\tconst invalidationArrayDraw = [];\n\n\tfunction updateMultisampleRenderTarget( renderTarget ) {\n\n\t\tif ( renderTarget.samples > 0 ) {\n\n\t\t\tif ( useMultisampledRTT( renderTarget ) === false ) {\n\n\t\t\t\tconst textures = renderTarget.textures;\n\t\t\t\tconst width = renderTarget.width;\n\t\t\t\tconst height = renderTarget.height;\n\t\t\t\tlet mask = _gl.COLOR_BUFFER_BIT;\n\t\t\t\tconst depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;\n\t\t\t\tconst renderTargetProperties = properties.get( renderTarget );\n\t\t\t\tconst isMultipleRenderTargets = ( textures.length > 1 );\n\n\t\t\t\t// If MRT we need to remove FBO attachments\n\t\t\t\tif ( isMultipleRenderTargets ) {\n\n\t\t\t\t\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );\n\t\t\t\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null );\n\n\t\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );\n\t\t\t\t\t\t_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tstate.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );\n\t\t\t\tstate.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );\n\n\t\t\t\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\t\t\t\tif ( renderTarget.resolveDepthBuffer ) {\n\n\t\t\t\t\t\tif ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT;\n\n\t\t\t\t\t\t// resolving stencil is slow with a D3D backend. disable it for all transmission render targets (see #27799)\n\n\t\t\t\t\t\tif ( renderTarget.stencilBuffer && renderTarget.resolveStencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( isMultipleRenderTargets ) {\n\n\t\t\t\t\t\t_gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );\n\n\t\t\t\t\t\tconst webglTexture = properties.get( textures[ i ] ).__webglTexture;\n\t\t\t\t\t\t_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t_gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST );\n\n\t\t\t\t\tif ( supportsInvalidateFramebuffer === true ) {\n\n\t\t\t\t\t\tinvalidationArrayRead.length = 0;\n\t\t\t\t\t\tinvalidationArrayDraw.length = 0;\n\n\t\t\t\t\t\tinvalidationArrayRead.push( _gl.COLOR_ATTACHMENT0 + i );\n\n\t\t\t\t\t\tif ( renderTarget.depthBuffer && renderTarget.resolveDepthBuffer === false ) {\n\n\t\t\t\t\t\t\tinvalidationArrayRead.push( depthStyle );\n\t\t\t\t\t\t\tinvalidationArrayDraw.push( depthStyle );\n\n\t\t\t\t\t\t\t_gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, invalidationArrayDraw );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t_gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArrayRead );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tstate.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );\n\t\t\t\tstate.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null );\n\n\t\t\t\t// If MRT since pre-blit we removed the FBO we need to reconstruct the attachments\n\t\t\t\tif ( isMultipleRenderTargets ) {\n\n\t\t\t\t\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );\n\t\t\t\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );\n\n\t\t\t\t\t\tconst webglTexture = properties.get( textures[ i ] ).__webglTexture;\n\n\t\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );\n\t\t\t\t\t\t_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tstate.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );\n\n\t\t\t} else {\n\n\t\t\t\tif ( renderTarget.depthBuffer && renderTarget.resolveDepthBuffer === false && supportsInvalidateFramebuffer ) {\n\n\t\t\t\t\tconst depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;\n\n\t\t\t\t\t_gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction getRenderTargetSamples( renderTarget ) {\n\n\t\treturn Math.min( capabilities.maxSamples, renderTarget.samples );\n\n\t}\n\n\tfunction useMultisampledRTT( renderTarget ) {\n\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\n\t\treturn renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false;\n\n\t}\n\n\tfunction updateVideoTexture( texture ) {\n\n\t\tconst frame = info.render.frame;\n\n\t\t// Check the last frame we updated the VideoTexture\n\n\t\tif ( _videoTextures.get( texture ) !== frame ) {\n\n\t\t\t_videoTextures.set( texture, frame );\n\t\t\ttexture.update();\n\n\t\t}\n\n\t}\n\n\tfunction verifyColorSpace( texture, image ) {\n\n\t\tconst colorSpace = texture.colorSpace;\n\t\tconst format = texture.format;\n\t\tconst type = texture.type;\n\n\t\tif ( texture.isCompressedTexture === true || texture.isVideoTexture === true ) return image;\n\n\t\tif ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) {\n\n\t\t\t// sRGB\n\n\t\t\tif ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) {\n\n\t\t\t\t// in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format\n\n\t\t\t\tif ( format !== RGBAFormat || type !== UnsignedByteType ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tconsole.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn image;\n\n\t}\n\n\tfunction getDimensions( image ) {\n\n\t\tif ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) {\n\n\t\t\t// if intrinsic data are not available, fallback to width/height\n\n\t\t\t_imageDimensions.width = image.naturalWidth || image.width;\n\t\t\t_imageDimensions.height = image.naturalHeight || image.height;\n\n\t\t} else if ( typeof VideoFrame !== 'undefined' && image instanceof VideoFrame ) {\n\n\t\t\t_imageDimensions.width = image.displayWidth;\n\t\t\t_imageDimensions.height = image.displayHeight;\n\n\t\t} else {\n\n\t\t\t_imageDimensions.width = image.width;\n\t\t\t_imageDimensions.height = image.height;\n\n\t\t}\n\n\t\treturn _imageDimensions;\n\n\t}\n\n\t//\n\n\tthis.allocateTextureUnit = allocateTextureUnit;\n\tthis.resetTextureUnits = resetTextureUnits;\n\n\tthis.setTexture2D = setTexture2D;\n\tthis.setTexture2DArray = setTexture2DArray;\n\tthis.setTexture3D = setTexture3D;\n\tthis.setTextureCube = setTextureCube;\n\tthis.rebindTextures = rebindTextures;\n\tthis.setupRenderTarget = setupRenderTarget;\n\tthis.updateRenderTargetMipmap = updateRenderTargetMipmap;\n\tthis.updateMultisampleRenderTarget = updateMultisampleRenderTarget;\n\tthis.setupDepthRenderbuffer = setupDepthRenderbuffer;\n\tthis.setupFrameBufferTexture = setupFrameBufferTexture;\n\tthis.useMultisampledRTT = useMultisampledRTT;\n\n}\n\nfunction WebGLUtils( gl, extensions ) {\n\n\tfunction convert( p, colorSpace = NoColorSpace ) {\n\n\t\tlet extension;\n\n\t\tconst transfer = ColorManagement.getTransfer( colorSpace );\n\n\t\tif ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;\n\t\tif ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;\n\t\tif ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;\n\t\tif ( p === UnsignedInt5999Type ) return gl.UNSIGNED_INT_5_9_9_9_REV;\n\n\t\tif ( p === ByteType ) return gl.BYTE;\n\t\tif ( p === ShortType ) return gl.SHORT;\n\t\tif ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT;\n\t\tif ( p === IntType ) return gl.INT;\n\t\tif ( p === UnsignedIntType ) return gl.UNSIGNED_INT;\n\t\tif ( p === FloatType ) return gl.FLOAT;\n\t\tif ( p === HalfFloatType ) return gl.HALF_FLOAT;\n\n\t\tif ( p === AlphaFormat ) return gl.ALPHA;\n\t\tif ( p === RGBFormat ) return gl.RGB;\n\t\tif ( p === RGBAFormat ) return gl.RGBA;\n\t\tif ( p === LuminanceFormat ) return gl.LUMINANCE;\n\t\tif ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA;\n\t\tif ( p === DepthFormat ) return gl.DEPTH_COMPONENT;\n\t\tif ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;\n\n\t\t// WebGL2 formats.\n\n\t\tif ( p === RedFormat ) return gl.RED;\n\t\tif ( p === RedIntegerFormat ) return gl.RED_INTEGER;\n\t\tif ( p === RGFormat ) return gl.RG;\n\t\tif ( p === RGIntegerFormat ) return gl.RG_INTEGER;\n\t\tif ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER;\n\n\t\t// S3TC\n\n\t\tif ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {\n\n\t\t\tif ( transfer === SRGBTransfer ) {\n\n\t\t\t\textension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' );\n\n\t\t\t\tif ( extension !== null ) {\n\n\t\t\t\t\tif ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\textension = extensions.get( 'WEBGL_compressed_texture_s3tc' );\n\n\t\t\t\tif ( extension !== null ) {\n\n\t\t\t\t\tif ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// PVRTC\n\n\t\tif ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {\n\n\t\t\textension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;\n\t\t\t\tif ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;\n\t\t\t\tif ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;\n\t\t\t\tif ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;\n\n\t\t\t} else {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// ETC\n\n\t\tif ( p === RGB_ETC1_Format || p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {\n\n\t\t\textension = extensions.get( 'WEBGL_compressed_texture_etc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGB_ETC1_Format || p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2;\n\t\t\t\tif ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC;\n\n\t\t\t} else {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// ASTC\n\n\t\tif ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||\n\t\t\tp === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||\n\t\t\tp === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||\n\t\t\tp === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||\n\t\t\tp === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) {\n\n\t\t\textension = extensions.get( 'WEBGL_compressed_texture_astc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR;\n\n\t\t\t} else {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// BPTC\n\n\t\tif ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) {\n\n\t\t\textension = extensions.get( 'EXT_texture_compression_bptc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;\n\t\t\t\tif ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;\n\t\t\t\tif ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT;\n\n\t\t\t} else {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// RGTC\n\n\t\tif ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) {\n\n\t\t\textension = extensions.get( 'EXT_texture_compression_rgtc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT;\n\t\t\t\tif ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT;\n\t\t\t\tif ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT;\n\t\t\t\tif ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;\n\n\t\t\t} else {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tif ( p === UnsignedInt248Type ) return gl.UNSIGNED_INT_24_8;\n\n\t\t// if \"p\" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats)\n\n\t\treturn ( gl[ p ] !== undefined ) ? gl[ p ] : null;\n\n\t}\n\n\treturn { convert: convert };\n\n}\n\nclass ArrayCamera extends PerspectiveCamera {\n\n\tconstructor( array = [] ) {\n\n\t\tsuper();\n\n\t\tthis.isArrayCamera = true;\n\n\t\tthis.cameras = array;\n\n\t}\n\n}\n\nclass Group extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isGroup = true;\n\n\t\tthis.type = 'Group';\n\n\t}\n\n}\n\nconst _moveEvent = { type: 'move' };\n\nclass WebXRController {\n\n\tconstructor() {\n\n\t\tthis._targetRay = null;\n\t\tthis._grip = null;\n\t\tthis._hand = null;\n\n\t}\n\n\tgetHandSpace() {\n\n\t\tif ( this._hand === null ) {\n\n\t\t\tthis._hand = new Group();\n\t\t\tthis._hand.matrixAutoUpdate = false;\n\t\t\tthis._hand.visible = false;\n\n\t\t\tthis._hand.joints = {};\n\t\t\tthis._hand.inputState = { pinching: false };\n\n\t\t}\n\n\t\treturn this._hand;\n\n\t}\n\n\tgetTargetRaySpace() {\n\n\t\tif ( this._targetRay === null ) {\n\n\t\t\tthis._targetRay = new Group();\n\t\t\tthis._targetRay.matrixAutoUpdate = false;\n\t\t\tthis._targetRay.visible = false;\n\t\t\tthis._targetRay.hasLinearVelocity = false;\n\t\t\tthis._targetRay.linearVelocity = new Vector3();\n\t\t\tthis._targetRay.hasAngularVelocity = false;\n\t\t\tthis._targetRay.angularVelocity = new Vector3();\n\n\t\t}\n\n\t\treturn this._targetRay;\n\n\t}\n\n\tgetGripSpace() {\n\n\t\tif ( this._grip === null ) {\n\n\t\t\tthis._grip = new Group();\n\t\t\tthis._grip.matrixAutoUpdate = false;\n\t\t\tthis._grip.visible = false;\n\t\t\tthis._grip.hasLinearVelocity = false;\n\t\t\tthis._grip.linearVelocity = new Vector3();\n\t\t\tthis._grip.hasAngularVelocity = false;\n\t\t\tthis._grip.angularVelocity = new Vector3();\n\n\t\t}\n\n\t\treturn this._grip;\n\n\t}\n\n\tdispatchEvent( event ) {\n\n\t\tif ( this._targetRay !== null ) {\n\n\t\t\tthis._targetRay.dispatchEvent( event );\n\n\t\t}\n\n\t\tif ( this._grip !== null ) {\n\n\t\t\tthis._grip.dispatchEvent( event );\n\n\t\t}\n\n\t\tif ( this._hand !== null ) {\n\n\t\t\tthis._hand.dispatchEvent( event );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tconnect( inputSource ) {\n\n\t\tif ( inputSource && inputSource.hand ) {\n\n\t\t\tconst hand = this._hand;\n\n\t\t\tif ( hand ) {\n\n\t\t\t\tfor ( const inputjoint of inputSource.hand.values() ) {\n\n\t\t\t\t\t// Initialize hand with joints when connected\n\t\t\t\t\tthis._getHandJoint( hand, inputjoint );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.dispatchEvent( { type: 'connected', data: inputSource } );\n\n\t\treturn this;\n\n\t}\n\n\tdisconnect( inputSource ) {\n\n\t\tthis.dispatchEvent( { type: 'disconnected', data: inputSource } );\n\n\t\tif ( this._targetRay !== null ) {\n\n\t\t\tthis._targetRay.visible = false;\n\n\t\t}\n\n\t\tif ( this._grip !== null ) {\n\n\t\t\tthis._grip.visible = false;\n\n\t\t}\n\n\t\tif ( this._hand !== null ) {\n\n\t\t\tthis._hand.visible = false;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tupdate( inputSource, frame, referenceSpace ) {\n\n\t\tlet inputPose = null;\n\t\tlet gripPose = null;\n\t\tlet handPose = null;\n\n\t\tconst targetRay = this._targetRay;\n\t\tconst grip = this._grip;\n\t\tconst hand = this._hand;\n\n\t\tif ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) {\n\n\t\t\tif ( hand && inputSource.hand ) {\n\n\t\t\t\thandPose = true;\n\n\t\t\t\tfor ( const inputjoint of inputSource.hand.values() ) {\n\n\t\t\t\t\t// Update the joints groups with the XRJoint poses\n\t\t\t\t\tconst jointPose = frame.getJointPose( inputjoint, referenceSpace );\n\n\t\t\t\t\t// The transform of this joint will be updated with the joint pose on each frame\n\t\t\t\t\tconst joint = this._getHandJoint( hand, inputjoint );\n\n\t\t\t\t\tif ( jointPose !== null ) {\n\n\t\t\t\t\t\tjoint.matrix.fromArray( jointPose.transform.matrix );\n\t\t\t\t\t\tjoint.matrix.decompose( joint.position, joint.rotation, joint.scale );\n\t\t\t\t\t\tjoint.matrixWorldNeedsUpdate = true;\n\t\t\t\t\t\tjoint.jointRadius = jointPose.radius;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tjoint.visible = jointPose !== null;\n\n\t\t\t\t}\n\n\t\t\t\t// Custom events\n\n\t\t\t\t// Check pinchz\n\t\t\t\tconst indexTip = hand.joints[ 'index-finger-tip' ];\n\t\t\t\tconst thumbTip = hand.joints[ 'thumb-tip' ];\n\t\t\t\tconst distance = indexTip.position.distanceTo( thumbTip.position );\n\n\t\t\t\tconst distanceToPinch = 0.02;\n\t\t\t\tconst threshold = 0.005;\n\n\t\t\t\tif ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {\n\n\t\t\t\t\thand.inputState.pinching = false;\n\t\t\t\t\tthis.dispatchEvent( {\n\t\t\t\t\t\ttype: 'pinchend',\n\t\t\t\t\t\thandedness: inputSource.handedness,\n\t\t\t\t\t\ttarget: this\n\t\t\t\t\t} );\n\n\t\t\t\t} else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {\n\n\t\t\t\t\thand.inputState.pinching = true;\n\t\t\t\t\tthis.dispatchEvent( {\n\t\t\t\t\t\ttype: 'pinchstart',\n\t\t\t\t\t\thandedness: inputSource.handedness,\n\t\t\t\t\t\ttarget: this\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( grip !== null && inputSource.gripSpace ) {\n\n\t\t\t\t\tgripPose = frame.getPose( inputSource.gripSpace, referenceSpace );\n\n\t\t\t\t\tif ( gripPose !== null ) {\n\n\t\t\t\t\t\tgrip.matrix.fromArray( gripPose.transform.matrix );\n\t\t\t\t\t\tgrip.matrix.decompose( grip.position, grip.rotation, grip.scale );\n\t\t\t\t\t\tgrip.matrixWorldNeedsUpdate = true;\n\n\t\t\t\t\t\tif ( gripPose.linearVelocity ) {\n\n\t\t\t\t\t\t\tgrip.hasLinearVelocity = true;\n\t\t\t\t\t\t\tgrip.linearVelocity.copy( gripPose.linearVelocity );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tgrip.hasLinearVelocity = false;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( gripPose.angularVelocity ) {\n\n\t\t\t\t\t\t\tgrip.hasAngularVelocity = true;\n\t\t\t\t\t\t\tgrip.angularVelocity.copy( gripPose.angularVelocity );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tgrip.hasAngularVelocity = false;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( targetRay !== null ) {\n\n\t\t\t\tinputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );\n\n\t\t\t\t// Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it\n\t\t\t\tif ( inputPose === null && gripPose !== null ) {\n\n\t\t\t\t\tinputPose = gripPose;\n\n\t\t\t\t}\n\n\t\t\t\tif ( inputPose !== null ) {\n\n\t\t\t\t\ttargetRay.matrix.fromArray( inputPose.transform.matrix );\n\t\t\t\t\ttargetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale );\n\t\t\t\t\ttargetRay.matrixWorldNeedsUpdate = true;\n\n\t\t\t\t\tif ( inputPose.linearVelocity ) {\n\n\t\t\t\t\t\ttargetRay.hasLinearVelocity = true;\n\t\t\t\t\t\ttargetRay.linearVelocity.copy( inputPose.linearVelocity );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ttargetRay.hasLinearVelocity = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( inputPose.angularVelocity ) {\n\n\t\t\t\t\t\ttargetRay.hasAngularVelocity = true;\n\t\t\t\t\t\ttargetRay.angularVelocity.copy( inputPose.angularVelocity );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ttargetRay.hasAngularVelocity = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.dispatchEvent( _moveEvent );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t}\n\n\t\tif ( targetRay !== null ) {\n\n\t\t\ttargetRay.visible = ( inputPose !== null );\n\n\t\t}\n\n\t\tif ( grip !== null ) {\n\n\t\t\tgrip.visible = ( gripPose !== null );\n\n\t\t}\n\n\t\tif ( hand !== null ) {\n\n\t\t\thand.visible = ( handPose !== null );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// private method\n\n\t_getHandJoint( hand, inputjoint ) {\n\n\t\tif ( hand.joints[ inputjoint.jointName ] === undefined ) {\n\n\t\t\tconst joint = new Group();\n\t\t\tjoint.matrixAutoUpdate = false;\n\t\t\tjoint.visible = false;\n\t\t\thand.joints[ inputjoint.jointName ] = joint;\n\n\t\t\thand.add( joint );\n\n\t\t}\n\n\t\treturn hand.joints[ inputjoint.jointName ];\n\n\t}\n\n}\n\nconst _occlusion_vertex = `\nvoid main() {\n\n\tgl_Position = vec4( position, 1.0 );\n\n}`;\n\nconst _occlusion_fragment = `\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_FragDepth = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r;\n\n\t} else {\n\n\t\tgl_FragDepth = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r;\n\n\t}\n\n}`;\n\nclass WebXRDepthSensing {\n\n\tconstructor() {\n\n\t\tthis.texture = null;\n\t\tthis.mesh = null;\n\n\t\tthis.depthNear = 0;\n\t\tthis.depthFar = 0;\n\n\t}\n\n\tinit( renderer, depthData, renderState ) {\n\n\t\tif ( this.texture === null ) {\n\n\t\t\tconst texture = new Texture();\n\n\t\t\tconst texProps = renderer.properties.get( texture );\n\t\t\ttexProps.__webglTexture = depthData.texture;\n\n\t\t\tif ( ( depthData.depthNear != renderState.depthNear ) || ( depthData.depthFar != renderState.depthFar ) ) {\n\n\t\t\t\tthis.depthNear = depthData.depthNear;\n\t\t\t\tthis.depthFar = depthData.depthFar;\n\n\t\t\t}\n\n\t\t\tthis.texture = texture;\n\n\t\t}\n\n\t}\n\n\tgetMesh( cameraXR ) {\n\n\t\tif ( this.texture !== null ) {\n\n\t\t\tif ( this.mesh === null ) {\n\n\t\t\t\tconst viewport = cameraXR.cameras[ 0 ].viewport;\n\t\t\t\tconst material = new ShaderMaterial( {\n\t\t\t\t\tvertexShader: _occlusion_vertex,\n\t\t\t\t\tfragmentShader: _occlusion_fragment,\n\t\t\t\t\tuniforms: {\n\t\t\t\t\t\tdepthColor: { value: this.texture },\n\t\t\t\t\t\tdepthWidth: { value: viewport.z },\n\t\t\t\t\t\tdepthHeight: { value: viewport.w }\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\tthis.mesh = new Mesh( new PlaneGeometry( 20, 20 ), material );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this.mesh;\n\n\t}\n\n\treset() {\n\n\t\tthis.texture = null;\n\t\tthis.mesh = null;\n\n\t}\n\n\tgetDepthTexture() {\n\n\t\treturn this.texture;\n\n\t}\n\n}\n\nclass WebXRManager extends EventDispatcher {\n\n\tconstructor( renderer, gl ) {\n\n\t\tsuper();\n\n\t\tconst scope = this;\n\n\t\tlet session = null;\n\n\t\tlet framebufferScaleFactor = 1.0;\n\n\t\tlet referenceSpace = null;\n\t\tlet referenceSpaceType = 'local-floor';\n\t\t// Set default foveation to maximum.\n\t\tlet foveation = 1.0;\n\t\tlet customReferenceSpace = null;\n\n\t\tlet pose = null;\n\t\tlet glBinding = null;\n\t\tlet glProjLayer = null;\n\t\tlet glBaseLayer = null;\n\t\tlet xrFrame = null;\n\n\t\tconst depthSensing = new WebXRDepthSensing();\n\t\tconst attributes = gl.getContextAttributes();\n\n\t\tlet initialRenderTarget = null;\n\t\tlet newRenderTarget = null;\n\n\t\tconst controllers = [];\n\t\tconst controllerInputSources = [];\n\n\t\tconst currentSize = new Vector2();\n\t\tlet currentPixelRatio = null;\n\n\t\t//\n\n\t\tconst cameraL = new PerspectiveCamera();\n\t\tcameraL.layers.enable( 1 );\n\t\tcameraL.viewport = new Vector4();\n\n\t\tconst cameraR = new PerspectiveCamera();\n\t\tcameraR.layers.enable( 2 );\n\t\tcameraR.viewport = new Vector4();\n\n\t\tconst cameras = [ cameraL, cameraR ];\n\n\t\tconst cameraXR = new ArrayCamera();\n\t\tcameraXR.layers.enable( 1 );\n\t\tcameraXR.layers.enable( 2 );\n\n\t\tlet _currentDepthNear = null;\n\t\tlet _currentDepthFar = null;\n\n\t\t//\n\n\t\tthis.cameraAutoUpdate = true;\n\t\tthis.enabled = false;\n\n\t\tthis.isPresenting = false;\n\n\t\tthis.getController = function ( index ) {\n\n\t\t\tlet controller = controllers[ index ];\n\n\t\t\tif ( controller === undefined ) {\n\n\t\t\t\tcontroller = new WebXRController();\n\t\t\t\tcontrollers[ index ] = controller;\n\n\t\t\t}\n\n\t\t\treturn controller.getTargetRaySpace();\n\n\t\t};\n\n\t\tthis.getControllerGrip = function ( index ) {\n\n\t\t\tlet controller = controllers[ index ];\n\n\t\t\tif ( controller === undefined ) {\n\n\t\t\t\tcontroller = new WebXRController();\n\t\t\t\tcontrollers[ index ] = controller;\n\n\t\t\t}\n\n\t\t\treturn controller.getGripSpace();\n\n\t\t};\n\n\t\tthis.getHand = function ( index ) {\n\n\t\t\tlet controller = controllers[ index ];\n\n\t\t\tif ( controller === undefined ) {\n\n\t\t\t\tcontroller = new WebXRController();\n\t\t\t\tcontrollers[ index ] = controller;\n\n\t\t\t}\n\n\t\t\treturn controller.getHandSpace();\n\n\t\t};\n\n\t\t//\n\n\t\tfunction onSessionEvent( event ) {\n\n\t\t\tconst controllerIndex = controllerInputSources.indexOf( event.inputSource );\n\n\t\t\tif ( controllerIndex === - 1 ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tconst controller = controllers[ controllerIndex ];\n\n\t\t\tif ( controller !== undefined ) {\n\n\t\t\t\tcontroller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace );\n\t\t\t\tcontroller.dispatchEvent( { type: event.type, data: event.inputSource } );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onSessionEnd() {\n\n\t\t\tsession.removeEventListener( 'select', onSessionEvent );\n\t\t\tsession.removeEventListener( 'selectstart', onSessionEvent );\n\t\t\tsession.removeEventListener( 'selectend', onSessionEvent );\n\t\t\tsession.removeEventListener( 'squeeze', onSessionEvent );\n\t\t\tsession.removeEventListener( 'squeezestart', onSessionEvent );\n\t\t\tsession.removeEventListener( 'squeezeend', onSessionEvent );\n\t\t\tsession.removeEventListener( 'end', onSessionEnd );\n\t\t\tsession.removeEventListener( 'inputsourceschange', onInputSourcesChange );\n\n\t\t\tfor ( let i = 0; i < controllers.length; i ++ ) {\n\n\t\t\t\tconst inputSource = controllerInputSources[ i ];\n\n\t\t\t\tif ( inputSource === null ) continue;\n\n\t\t\t\tcontrollerInputSources[ i ] = null;\n\n\t\t\t\tcontrollers[ i ].disconnect( inputSource );\n\n\t\t\t}\n\n\t\t\t_currentDepthNear = null;\n\t\t\t_currentDepthFar = null;\n\n\t\t\tdepthSensing.reset();\n\n\t\t\t// restore framebuffer/rendering state\n\n\t\t\trenderer.setRenderTarget( initialRenderTarget );\n\n\t\t\tglBaseLayer = null;\n\t\t\tglProjLayer = null;\n\t\t\tglBinding = null;\n\t\t\tsession = null;\n\t\t\tnewRenderTarget = null;\n\n\t\t\t//\n\n\t\t\tanimation.stop();\n\n\t\t\tscope.isPresenting = false;\n\n\t\t\trenderer.setPixelRatio( currentPixelRatio );\n\t\t\trenderer.setSize( currentSize.width, currentSize.height, false );\n\n\t\t\tscope.dispatchEvent( { type: 'sessionend' } );\n\n\t\t}\n\n\t\tthis.setFramebufferScaleFactor = function ( value ) {\n\n\t\t\tframebufferScaleFactor = value;\n\n\t\t\tif ( scope.isPresenting === true ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.setReferenceSpaceType = function ( value ) {\n\n\t\t\treferenceSpaceType = value;\n\n\t\t\tif ( scope.isPresenting === true ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.getReferenceSpace = function () {\n\n\t\t\treturn customReferenceSpace || referenceSpace;\n\n\t\t};\n\n\t\tthis.setReferenceSpace = function ( space ) {\n\n\t\t\tcustomReferenceSpace = space;\n\n\t\t};\n\n\t\tthis.getBaseLayer = function () {\n\n\t\t\treturn glProjLayer !== null ? glProjLayer : glBaseLayer;\n\n\t\t};\n\n\t\tthis.getBinding = function () {\n\n\t\t\treturn glBinding;\n\n\t\t};\n\n\t\tthis.getFrame = function () {\n\n\t\t\treturn xrFrame;\n\n\t\t};\n\n\t\tthis.getSession = function () {\n\n\t\t\treturn session;\n\n\t\t};\n\n\t\tthis.setSession = async function ( value ) {\n\n\t\t\tsession = value;\n\n\t\t\tif ( session !== null ) {\n\n\t\t\t\tinitialRenderTarget = renderer.getRenderTarget();\n\n\t\t\t\tsession.addEventListener( 'select', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'selectstart', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'selectend', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'squeeze', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'squeezestart', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'squeezeend', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'end', onSessionEnd );\n\t\t\t\tsession.addEventListener( 'inputsourceschange', onInputSourcesChange );\n\n\t\t\t\tif ( attributes.xrCompatible !== true ) {\n\n\t\t\t\t\tawait gl.makeXRCompatible();\n\n\t\t\t\t}\n\n\t\t\t\tcurrentPixelRatio = renderer.getPixelRatio();\n\t\t\t\trenderer.getSize( currentSize );\n\n\t\t\t\tif ( session.renderState.layers === undefined ) {\n\n\t\t\t\t\tconst layerInit = {\n\t\t\t\t\t\tantialias: attributes.antialias,\n\t\t\t\t\t\talpha: true,\n\t\t\t\t\t\tdepth: attributes.depth,\n\t\t\t\t\t\tstencil: attributes.stencil,\n\t\t\t\t\t\tframebufferScaleFactor: framebufferScaleFactor\n\t\t\t\t\t};\n\n\t\t\t\t\tglBaseLayer = new XRWebGLLayer( session, gl, layerInit );\n\n\t\t\t\t\tsession.updateRenderState( { baseLayer: glBaseLayer } );\n\n\t\t\t\t\trenderer.setPixelRatio( 1 );\n\t\t\t\t\trenderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false );\n\n\t\t\t\t\tnewRenderTarget = new WebGLRenderTarget(\n\t\t\t\t\t\tglBaseLayer.framebufferWidth,\n\t\t\t\t\t\tglBaseLayer.framebufferHeight,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tformat: RGBAFormat,\n\t\t\t\t\t\t\ttype: UnsignedByteType,\n\t\t\t\t\t\t\tcolorSpace: renderer.outputColorSpace,\n\t\t\t\t\t\t\tstencilBuffer: attributes.stencil\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\n\t\t\t\t} else {\n\n\t\t\t\t\tlet depthFormat = null;\n\t\t\t\t\tlet depthType = null;\n\t\t\t\t\tlet glDepthFormat = null;\n\n\t\t\t\t\tif ( attributes.depth ) {\n\n\t\t\t\t\t\tglDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24;\n\t\t\t\t\t\tdepthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat;\n\t\t\t\t\t\tdepthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst projectionlayerInit = {\n\t\t\t\t\t\tcolorFormat: gl.RGBA8,\n\t\t\t\t\t\tdepthFormat: glDepthFormat,\n\t\t\t\t\t\tscaleFactor: framebufferScaleFactor\n\t\t\t\t\t};\n\n\t\t\t\t\tglBinding = new XRWebGLBinding( session, gl );\n\n\t\t\t\t\tglProjLayer = glBinding.createProjectionLayer( projectionlayerInit );\n\n\t\t\t\t\tsession.updateRenderState( { layers: [ glProjLayer ] } );\n\n\t\t\t\t\trenderer.setPixelRatio( 1 );\n\t\t\t\t\trenderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false );\n\n\t\t\t\t\tnewRenderTarget = new WebGLRenderTarget(\n\t\t\t\t\t\tglProjLayer.textureWidth,\n\t\t\t\t\t\tglProjLayer.textureHeight,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tformat: RGBAFormat,\n\t\t\t\t\t\t\ttype: UnsignedByteType,\n\t\t\t\t\t\t\tdepthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ),\n\t\t\t\t\t\t\tstencilBuffer: attributes.stencil,\n\t\t\t\t\t\t\tcolorSpace: renderer.outputColorSpace,\n\t\t\t\t\t\t\tsamples: attributes.antialias ? 4 : 0,\n\t\t\t\t\t\t\tresolveDepthBuffer: ( glProjLayer.ignoreDepthValues === false )\n\t\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t\tnewRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278\n\n\t\t\t\tthis.setFoveation( foveation );\n\n\t\t\t\tcustomReferenceSpace = null;\n\t\t\t\treferenceSpace = await session.requestReferenceSpace( referenceSpaceType );\n\n\t\t\t\tanimation.setContext( session );\n\t\t\t\tanimation.start();\n\n\t\t\t\tscope.isPresenting = true;\n\n\t\t\t\tscope.dispatchEvent( { type: 'sessionstart' } );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.getEnvironmentBlendMode = function () {\n\n\t\t\tif ( session !== null ) {\n\n\t\t\t\treturn session.environmentBlendMode;\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.getDepthTexture = function () {\n\n\t\t\treturn depthSensing.getDepthTexture();\n\n\t\t};\n\n\t\tfunction onInputSourcesChange( event ) {\n\n\t\t\t// Notify disconnected\n\n\t\t\tfor ( let i = 0; i < event.removed.length; i ++ ) {\n\n\t\t\t\tconst inputSource = event.removed[ i ];\n\t\t\t\tconst index = controllerInputSources.indexOf( inputSource );\n\n\t\t\t\tif ( index >= 0 ) {\n\n\t\t\t\t\tcontrollerInputSources[ index ] = null;\n\t\t\t\t\tcontrollers[ index ].disconnect( inputSource );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// Notify connected\n\n\t\t\tfor ( let i = 0; i < event.added.length; i ++ ) {\n\n\t\t\t\tconst inputSource = event.added[ i ];\n\n\t\t\t\tlet controllerIndex = controllerInputSources.indexOf( inputSource );\n\n\t\t\t\tif ( controllerIndex === - 1 ) {\n\n\t\t\t\t\t// Assign input source a controller that currently has no input source\n\n\t\t\t\t\tfor ( let i = 0; i < controllers.length; i ++ ) {\n\n\t\t\t\t\t\tif ( i >= controllerInputSources.length ) {\n\n\t\t\t\t\t\t\tcontrollerInputSources.push( inputSource );\n\t\t\t\t\t\t\tcontrollerIndex = i;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t} else if ( controllerInputSources[ i ] === null ) {\n\n\t\t\t\t\t\t\tcontrollerInputSources[ i ] = inputSource;\n\t\t\t\t\t\t\tcontrollerIndex = i;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// If all controllers do currently receive input we ignore new ones\n\n\t\t\t\t\tif ( controllerIndex === - 1 ) break;\n\n\t\t\t\t}\n\n\t\t\t\tconst controller = controllers[ controllerIndex ];\n\n\t\t\t\tif ( controller ) {\n\n\t\t\t\t\tcontroller.connect( inputSource );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tconst cameraLPos = new Vector3();\n\t\tconst cameraRPos = new Vector3();\n\n\t\t/**\n\t\t * Assumes 2 cameras that are parallel and share an X-axis, and that\n\t\t * the cameras' projection and world matrices have already been set.\n\t\t * And that near and far planes are identical for both cameras.\n\t\t * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765\n\t\t */\n\t\tfunction setProjectionFromUnion( camera, cameraL, cameraR ) {\n\n\t\t\tcameraLPos.setFromMatrixPosition( cameraL.matrixWorld );\n\t\t\tcameraRPos.setFromMatrixPosition( cameraR.matrixWorld );\n\n\t\t\tconst ipd = cameraLPos.distanceTo( cameraRPos );\n\n\t\t\tconst projL = cameraL.projectionMatrix.elements;\n\t\t\tconst projR = cameraR.projectionMatrix.elements;\n\n\t\t\t// VR systems will have identical far and near planes, and\n\t\t\t// most likely identical top and bottom frustum extents.\n\t\t\t// Use the left camera for these values.\n\t\t\tconst near = projL[ 14 ] / ( projL[ 10 ] - 1 );\n\t\t\tconst far = projL[ 14 ] / ( projL[ 10 ] + 1 );\n\t\t\tconst topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];\n\t\t\tconst bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];\n\n\t\t\tconst leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];\n\t\t\tconst rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];\n\t\t\tconst left = near * leftFov;\n\t\t\tconst right = near * rightFov;\n\n\t\t\t// Calculate the new camera's position offset from the\n\t\t\t// left camera. xOffset should be roughly half `ipd`.\n\t\t\tconst zOffset = ipd / ( - leftFov + rightFov );\n\t\t\tconst xOffset = zOffset * - leftFov;\n\n\t\t\t// TODO: Better way to apply this offset?\n\t\t\tcameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );\n\t\t\tcamera.translateX( xOffset );\n\t\t\tcamera.translateZ( zOffset );\n\t\t\tcamera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );\n\t\t\tcamera.matrixWorldInverse.copy( camera.matrixWorld ).invert();\n\n\t\t\t// Find the union of the frustum values of the cameras and scale\n\t\t\t// the values so that the near plane's position does not change in world space,\n\t\t\t// although must now be relative to the new union camera.\n\t\t\tconst near2 = near + zOffset;\n\t\t\tconst far2 = far + zOffset;\n\t\t\tconst left2 = left - xOffset;\n\t\t\tconst right2 = right + ( ipd - xOffset );\n\t\t\tconst top2 = topFov * far / far2 * near2;\n\t\t\tconst bottom2 = bottomFov * far / far2 * near2;\n\n\t\t\tcamera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );\n\t\t\tcamera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();\n\n\t\t}\n\n\t\tfunction updateCamera( camera, parent ) {\n\n\t\t\tif ( parent === null ) {\n\n\t\t\t\tcamera.matrixWorld.copy( camera.matrix );\n\n\t\t\t} else {\n\n\t\t\t\tcamera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );\n\n\t\t\t}\n\n\t\t\tcamera.matrixWorldInverse.copy( camera.matrixWorld ).invert();\n\n\t\t}\n\n\t\tthis.updateCamera = function ( camera ) {\n\n\t\t\tif ( session === null ) return;\n\n\t\t\tif ( depthSensing.texture !== null ) {\n\n\t\t\t\tcamera.near = depthSensing.depthNear;\n\t\t\t\tcamera.far = depthSensing.depthFar;\n\n\t\t\t}\n\n\t\t\tcameraXR.near = cameraR.near = cameraL.near = camera.near;\n\t\t\tcameraXR.far = cameraR.far = cameraL.far = camera.far;\n\n\t\t\tif ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) {\n\n\t\t\t\t// Note that the new renderState won't apply until the next frame. See #18320\n\n\t\t\t\tsession.updateRenderState( {\n\t\t\t\t\tdepthNear: cameraXR.near,\n\t\t\t\t\tdepthFar: cameraXR.far\n\t\t\t\t} );\n\n\t\t\t\t_currentDepthNear = cameraXR.near;\n\t\t\t\t_currentDepthFar = cameraXR.far;\n\n\t\t\t\tcameraL.near = _currentDepthNear;\n\t\t\t\tcameraL.far = _currentDepthFar;\n\t\t\t\tcameraR.near = _currentDepthNear;\n\t\t\t\tcameraR.far = _currentDepthFar;\n\n\t\t\t\tcameraL.updateProjectionMatrix();\n\t\t\t\tcameraR.updateProjectionMatrix();\n\t\t\t\tcamera.updateProjectionMatrix();\n\n\t\t\t}\n\n\t\t\tconst parent = camera.parent;\n\t\t\tconst cameras = cameraXR.cameras;\n\n\t\t\tupdateCamera( cameraXR, parent );\n\n\t\t\tfor ( let i = 0; i < cameras.length; i ++ ) {\n\n\t\t\t\tupdateCamera( cameras[ i ], parent );\n\n\t\t\t}\n\n\t\t\t// update projection matrix for proper view frustum culling\n\n\t\t\tif ( cameras.length === 2 ) {\n\n\t\t\t\tsetProjectionFromUnion( cameraXR, cameraL, cameraR );\n\n\t\t\t} else {\n\n\t\t\t\t// assume single camera setup (AR)\n\n\t\t\t\tcameraXR.projectionMatrix.copy( cameraL.projectionMatrix );\n\n\t\t\t}\n\n\t\t\t// update user camera and its children\n\n\t\t\tupdateUserCamera( camera, cameraXR, parent );\n\n\t\t};\n\n\t\tfunction updateUserCamera( camera, cameraXR, parent ) {\n\n\t\t\tif ( parent === null ) {\n\n\t\t\t\tcamera.matrix.copy( cameraXR.matrixWorld );\n\n\t\t\t} else {\n\n\t\t\t\tcamera.matrix.copy( parent.matrixWorld );\n\t\t\t\tcamera.matrix.invert();\n\t\t\t\tcamera.matrix.multiply( cameraXR.matrixWorld );\n\n\t\t\t}\n\n\t\t\tcamera.matrix.decompose( camera.position, camera.quaternion, camera.scale );\n\t\t\tcamera.updateMatrixWorld( true );\n\n\t\t\tcamera.projectionMatrix.copy( cameraXR.projectionMatrix );\n\t\t\tcamera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse );\n\n\t\t\tif ( camera.isPerspectiveCamera ) {\n\n\t\t\t\tcamera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] );\n\t\t\t\tcamera.zoom = 1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.getCamera = function () {\n\n\t\t\treturn cameraXR;\n\n\t\t};\n\n\t\tthis.getFoveation = function () {\n\n\t\t\tif ( glProjLayer === null && glBaseLayer === null ) {\n\n\t\t\t\treturn undefined;\n\n\t\t\t}\n\n\t\t\treturn foveation;\n\n\t\t};\n\n\t\tthis.setFoveation = function ( value ) {\n\n\t\t\t// 0 = no foveation = full resolution\n\t\t\t// 1 = maximum foveation = the edges render at lower resolution\n\n\t\t\tfoveation = value;\n\n\t\t\tif ( glProjLayer !== null ) {\n\n\t\t\t\tglProjLayer.fixedFoveation = value;\n\n\t\t\t}\n\n\t\t\tif ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) {\n\n\t\t\t\tglBaseLayer.fixedFoveation = value;\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.hasDepthSensing = function () {\n\n\t\t\treturn depthSensing.texture !== null;\n\n\t\t};\n\n\t\tthis.getDepthSensingMesh = function () {\n\n\t\t\treturn depthSensing.getMesh( cameraXR );\n\n\t\t};\n\n\t\t// Animation Loop\n\n\t\tlet onAnimationFrameCallback = null;\n\n\t\tfunction onAnimationFrame( time, frame ) {\n\n\t\t\tpose = frame.getViewerPose( customReferenceSpace || referenceSpace );\n\t\t\txrFrame = frame;\n\n\t\t\tif ( pose !== null ) {\n\n\t\t\t\tconst views = pose.views;\n\n\t\t\t\tif ( glBaseLayer !== null ) {\n\n\t\t\t\t\trenderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer );\n\t\t\t\t\trenderer.setRenderTarget( newRenderTarget );\n\n\t\t\t\t}\n\n\t\t\t\tlet cameraXRNeedsUpdate = false;\n\n\t\t\t\t// check if it's necessary to rebuild cameraXR's camera list\n\n\t\t\t\tif ( views.length !== cameraXR.cameras.length ) {\n\n\t\t\t\t\tcameraXR.cameras.length = 0;\n\t\t\t\t\tcameraXRNeedsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let i = 0; i < views.length; i ++ ) {\n\n\t\t\t\t\tconst view = views[ i ];\n\n\t\t\t\t\tlet viewport = null;\n\n\t\t\t\t\tif ( glBaseLayer !== null ) {\n\n\t\t\t\t\t\tviewport = glBaseLayer.getViewport( view );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconst glSubImage = glBinding.getViewSubImage( glProjLayer, view );\n\t\t\t\t\t\tviewport = glSubImage.viewport;\n\n\t\t\t\t\t\t// For side-by-side projection, we only produce a single texture for both eyes.\n\t\t\t\t\t\tif ( i === 0 ) {\n\n\t\t\t\t\t\t\trenderer.setRenderTargetTextures(\n\t\t\t\t\t\t\t\tnewRenderTarget,\n\t\t\t\t\t\t\t\tglSubImage.colorTexture,\n\t\t\t\t\t\t\t\tglProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture );\n\n\t\t\t\t\t\t\trenderer.setRenderTarget( newRenderTarget );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet camera = cameras[ i ];\n\n\t\t\t\t\tif ( camera === undefined ) {\n\n\t\t\t\t\t\tcamera = new PerspectiveCamera();\n\t\t\t\t\t\tcamera.layers.enable( i );\n\t\t\t\t\t\tcamera.viewport = new Vector4();\n\t\t\t\t\t\tcameras[ i ] = camera;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tcamera.matrix.fromArray( view.transform.matrix );\n\t\t\t\t\tcamera.matrix.decompose( camera.position, camera.quaternion, camera.scale );\n\t\t\t\t\tcamera.projectionMatrix.fromArray( view.projectionMatrix );\n\t\t\t\t\tcamera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();\n\t\t\t\t\tcamera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );\n\n\t\t\t\t\tif ( i === 0 ) {\n\n\t\t\t\t\t\tcameraXR.matrix.copy( camera.matrix );\n\t\t\t\t\t\tcameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( cameraXRNeedsUpdate === true ) {\n\n\t\t\t\t\t\tcameraXR.cameras.push( camera );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t//\n\n\t\t\t\tconst enabledFeatures = session.enabledFeatures;\n\n\t\t\t\tif ( enabledFeatures && enabledFeatures.includes( 'depth-sensing' ) ) {\n\n\t\t\t\t\tconst depthData = glBinding.getDepthInformation( views[ 0 ] );\n\n\t\t\t\t\tif ( depthData && depthData.isValid && depthData.texture ) {\n\n\t\t\t\t\t\tdepthSensing.init( renderer, depthData, session.renderState );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tfor ( let i = 0; i < controllers.length; i ++ ) {\n\n\t\t\t\tconst inputSource = controllerInputSources[ i ];\n\t\t\t\tconst controller = controllers[ i ];\n\n\t\t\t\tif ( inputSource !== null && controller !== undefined ) {\n\n\t\t\t\t\tcontroller.update( inputSource, frame, customReferenceSpace || referenceSpace );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );\n\n\t\t\tif ( frame.detectedPlanes ) {\n\n\t\t\t\tscope.dispatchEvent( { type: 'planesdetected', data: frame } );\n\n\t\t\t}\n\n\t\t\txrFrame = null;\n\n\t\t}\n\n\t\tconst animation = new WebGLAnimation();\n\n\t\tanimation.setAnimationLoop( onAnimationFrame );\n\n\t\tthis.setAnimationLoop = function ( callback ) {\n\n\t\t\tonAnimationFrameCallback = callback;\n\n\t\t};\n\n\t\tthis.dispose = function () {};\n\n\t}\n\n}\n\nconst _e1 = /*@__PURE__*/ new Euler();\nconst _m1 = /*@__PURE__*/ new Matrix4();\n\nfunction WebGLMaterials( renderer, properties ) {\n\n\tfunction refreshTransformUniform( map, uniform ) {\n\n\t\tif ( map.matrixAutoUpdate === true ) {\n\n\t\t\tmap.updateMatrix();\n\n\t\t}\n\n\t\tuniform.value.copy( map.matrix );\n\n\t}\n\n\tfunction refreshFogUniforms( uniforms, fog ) {\n\n\t\tfog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) );\n\n\t\tif ( fog.isFog ) {\n\n\t\t\tuniforms.fogNear.value = fog.near;\n\t\t\tuniforms.fogFar.value = fog.far;\n\n\t\t} else if ( fog.isFogExp2 ) {\n\n\t\t\tuniforms.fogDensity.value = fog.density;\n\n\t\t}\n\n\t}\n\n\tfunction refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) {\n\n\t\tif ( material.isMeshBasicMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\n\t\t} else if ( material.isMeshLambertMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\n\t\t} else if ( material.isMeshToonMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\t\t\trefreshUniformsToon( uniforms, material );\n\n\t\t} else if ( material.isMeshPhongMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\t\t\trefreshUniformsPhong( uniforms, material );\n\n\t\t} else if ( material.isMeshStandardMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\t\t\trefreshUniformsStandard( uniforms, material );\n\n\t\t\tif ( material.isMeshPhysicalMaterial ) {\n\n\t\t\t\trefreshUniformsPhysical( uniforms, material, transmissionRenderTarget );\n\n\t\t\t}\n\n\t\t} else if ( material.isMeshMatcapMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\t\t\trefreshUniformsMatcap( uniforms, material );\n\n\t\t} else if ( material.isMeshDepthMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\n\t\t} else if ( material.isMeshDistanceMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\t\t\trefreshUniformsDistance( uniforms, material );\n\n\t\t} else if ( material.isMeshNormalMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\n\t\t} else if ( material.isLineBasicMaterial ) {\n\n\t\t\trefreshUniformsLine( uniforms, material );\n\n\t\t\tif ( material.isLineDashedMaterial ) {\n\n\t\t\t\trefreshUniformsDash( uniforms, material );\n\n\t\t\t}\n\n\t\t} else if ( material.isPointsMaterial ) {\n\n\t\t\trefreshUniformsPoints( uniforms, material, pixelRatio, height );\n\n\t\t} else if ( material.isSpriteMaterial ) {\n\n\t\t\trefreshUniformsSprites( uniforms, material );\n\n\t\t} else if ( material.isShadowMaterial ) {\n\n\t\t\tuniforms.color.value.copy( material.color );\n\t\t\tuniforms.opacity.value = material.opacity;\n\n\t\t} else if ( material.isShaderMaterial ) {\n\n\t\t\tmaterial.uniformsNeedUpdate = false; // #15581\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsCommon( uniforms, material ) {\n\n\t\tuniforms.opacity.value = material.opacity;\n\n\t\tif ( material.color ) {\n\n\t\t\tuniforms.diffuse.value.copy( material.color );\n\n\t\t}\n\n\t\tif ( material.emissive ) {\n\n\t\t\tuniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );\n\n\t\t}\n\n\t\tif ( material.map ) {\n\n\t\t\tuniforms.map.value = material.map;\n\n\t\t\trefreshTransformUniform( material.map, uniforms.mapTransform );\n\n\t\t}\n\n\t\tif ( material.alphaMap ) {\n\n\t\t\tuniforms.alphaMap.value = material.alphaMap;\n\n\t\t\trefreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );\n\n\t\t}\n\n\t\tif ( material.bumpMap ) {\n\n\t\t\tuniforms.bumpMap.value = material.bumpMap;\n\n\t\t\trefreshTransformUniform( material.bumpMap, uniforms.bumpMapTransform );\n\n\t\t\tuniforms.bumpScale.value = material.bumpScale;\n\n\t\t\tif ( material.side === BackSide ) {\n\n\t\t\t\tuniforms.bumpScale.value *= - 1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.normalMap ) {\n\n\t\t\tuniforms.normalMap.value = material.normalMap;\n\n\t\t\trefreshTransformUniform( material.normalMap, uniforms.normalMapTransform );\n\n\t\t\tuniforms.normalScale.value.copy( material.normalScale );\n\n\t\t\tif ( material.side === BackSide ) {\n\n\t\t\t\tuniforms.normalScale.value.negate();\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.displacementMap ) {\n\n\t\t\tuniforms.displacementMap.value = material.displacementMap;\n\n\t\t\trefreshTransformUniform( material.displacementMap, uniforms.displacementMapTransform );\n\n\t\t\tuniforms.displacementScale.value = material.displacementScale;\n\t\t\tuniforms.displacementBias.value = material.displacementBias;\n\n\t\t}\n\n\t\tif ( material.emissiveMap ) {\n\n\t\t\tuniforms.emissiveMap.value = material.emissiveMap;\n\n\t\t\trefreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform );\n\n\t\t}\n\n\t\tif ( material.specularMap ) {\n\n\t\t\tuniforms.specularMap.value = material.specularMap;\n\n\t\t\trefreshTransformUniform( material.specularMap, uniforms.specularMapTransform );\n\n\t\t}\n\n\t\tif ( material.alphaTest > 0 ) {\n\n\t\t\tuniforms.alphaTest.value = material.alphaTest;\n\n\t\t}\n\n\t\tconst materialProperties = properties.get( material );\n\n\t\tconst envMap = materialProperties.envMap;\n\t\tconst envMapRotation = materialProperties.envMapRotation;\n\n\t\tif ( envMap ) {\n\n\t\t\tuniforms.envMap.value = envMap;\n\n\t\t\t_e1.copy( envMapRotation );\n\n\t\t\t// accommodate left-handed frame\n\t\t\t_e1.x *= - 1; _e1.y *= - 1; _e1.z *= - 1;\n\n\t\t\tif ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) {\n\n\t\t\t\t// environment maps which are not cube render targets or PMREMs follow a different convention\n\t\t\t\t_e1.y *= - 1;\n\t\t\t\t_e1.z *= - 1;\n\n\t\t\t}\n\n\t\t\tuniforms.envMapRotation.value.setFromMatrix4( _m1.makeRotationFromEuler( _e1 ) );\n\n\t\t\tuniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;\n\n\t\t\tuniforms.reflectivity.value = material.reflectivity;\n\t\t\tuniforms.ior.value = material.ior;\n\t\t\tuniforms.refractionRatio.value = material.refractionRatio;\n\n\t\t}\n\n\t\tif ( material.lightMap ) {\n\n\t\t\tuniforms.lightMap.value = material.lightMap;\n\t\t\tuniforms.lightMapIntensity.value = material.lightMapIntensity;\n\n\t\t\trefreshTransformUniform( material.lightMap, uniforms.lightMapTransform );\n\n\t\t}\n\n\t\tif ( material.aoMap ) {\n\n\t\t\tuniforms.aoMap.value = material.aoMap;\n\t\t\tuniforms.aoMapIntensity.value = material.aoMapIntensity;\n\n\t\t\trefreshTransformUniform( material.aoMap, uniforms.aoMapTransform );\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsLine( uniforms, material ) {\n\n\t\tuniforms.diffuse.value.copy( material.color );\n\t\tuniforms.opacity.value = material.opacity;\n\n\t\tif ( material.map ) {\n\n\t\t\tuniforms.map.value = material.map;\n\n\t\t\trefreshTransformUniform( material.map, uniforms.mapTransform );\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsDash( uniforms, material ) {\n\n\t\tuniforms.dashSize.value = material.dashSize;\n\t\tuniforms.totalSize.value = material.dashSize + material.gapSize;\n\t\tuniforms.scale.value = material.scale;\n\n\t}\n\n\tfunction refreshUniformsPoints( uniforms, material, pixelRatio, height ) {\n\n\t\tuniforms.diffuse.value.copy( material.color );\n\t\tuniforms.opacity.value = material.opacity;\n\t\tuniforms.size.value = material.size * pixelRatio;\n\t\tuniforms.scale.value = height * 0.5;\n\n\t\tif ( material.map ) {\n\n\t\t\tuniforms.map.value = material.map;\n\n\t\t\trefreshTransformUniform( material.map, uniforms.uvTransform );\n\n\t\t}\n\n\t\tif ( material.alphaMap ) {\n\n\t\t\tuniforms.alphaMap.value = material.alphaMap;\n\n\t\t\trefreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );\n\n\t\t}\n\n\t\tif ( material.alphaTest > 0 ) {\n\n\t\t\tuniforms.alphaTest.value = material.alphaTest;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsSprites( uniforms, material ) {\n\n\t\tuniforms.diffuse.value.copy( material.color );\n\t\tuniforms.opacity.value = material.opacity;\n\t\tuniforms.rotation.value = material.rotation;\n\n\t\tif ( material.map ) {\n\n\t\t\tuniforms.map.value = material.map;\n\n\t\t\trefreshTransformUniform( material.map, uniforms.mapTransform );\n\n\t\t}\n\n\t\tif ( material.alphaMap ) {\n\n\t\t\tuniforms.alphaMap.value = material.alphaMap;\n\n\t\t\trefreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );\n\n\t\t}\n\n\t\tif ( material.alphaTest > 0 ) {\n\n\t\t\tuniforms.alphaTest.value = material.alphaTest;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsPhong( uniforms, material ) {\n\n\t\tuniforms.specular.value.copy( material.specular );\n\t\tuniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )\n\n\t}\n\n\tfunction refreshUniformsToon( uniforms, material ) {\n\n\t\tif ( material.gradientMap ) {\n\n\t\t\tuniforms.gradientMap.value = material.gradientMap;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsStandard( uniforms, material ) {\n\n\t\tuniforms.metalness.value = material.metalness;\n\n\t\tif ( material.metalnessMap ) {\n\n\t\t\tuniforms.metalnessMap.value = material.metalnessMap;\n\n\t\t\trefreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform );\n\n\t\t}\n\n\t\tuniforms.roughness.value = material.roughness;\n\n\t\tif ( material.roughnessMap ) {\n\n\t\t\tuniforms.roughnessMap.value = material.roughnessMap;\n\n\t\t\trefreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform );\n\n\t\t}\n\n\t\tif ( material.envMap ) {\n\n\t\t\t//uniforms.envMap.value = material.envMap; // part of uniforms common\n\n\t\t\tuniforms.envMapIntensity.value = material.envMapIntensity;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) {\n\n\t\tuniforms.ior.value = material.ior; // also part of uniforms common\n\n\t\tif ( material.sheen > 0 ) {\n\n\t\t\tuniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen );\n\n\t\t\tuniforms.sheenRoughness.value = material.sheenRoughness;\n\n\t\t\tif ( material.sheenColorMap ) {\n\n\t\t\t\tuniforms.sheenColorMap.value = material.sheenColorMap;\n\n\t\t\t\trefreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform );\n\n\t\t\t}\n\n\t\t\tif ( material.sheenRoughnessMap ) {\n\n\t\t\t\tuniforms.sheenRoughnessMap.value = material.sheenRoughnessMap;\n\n\t\t\t\trefreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.clearcoat > 0 ) {\n\n\t\t\tuniforms.clearcoat.value = material.clearcoat;\n\t\t\tuniforms.clearcoatRoughness.value = material.clearcoatRoughness;\n\n\t\t\tif ( material.clearcoatMap ) {\n\n\t\t\t\tuniforms.clearcoatMap.value = material.clearcoatMap;\n\n\t\t\t\trefreshTransformUniform( material.clearcoatMap, uniforms.clearcoatMapTransform );\n\n\t\t\t}\n\n\t\t\tif ( material.clearcoatRoughnessMap ) {\n\n\t\t\t\tuniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;\n\n\t\t\t\trefreshTransformUniform( material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform );\n\n\t\t\t}\n\n\t\t\tif ( material.clearcoatNormalMap ) {\n\n\t\t\t\tuniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;\n\n\t\t\t\trefreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform );\n\n\t\t\t\tuniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );\n\n\t\t\t\tif ( material.side === BackSide ) {\n\n\t\t\t\t\tuniforms.clearcoatNormalScale.value.negate();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.dispersion > 0 ) {\n\n\t\t\tuniforms.dispersion.value = material.dispersion;\n\n\t\t}\n\n\t\tif ( material.iridescence > 0 ) {\n\n\t\t\tuniforms.iridescence.value = material.iridescence;\n\t\t\tuniforms.iridescenceIOR.value = material.iridescenceIOR;\n\t\t\tuniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ];\n\t\t\tuniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ];\n\n\t\t\tif ( material.iridescenceMap ) {\n\n\t\t\t\tuniforms.iridescenceMap.value = material.iridescenceMap;\n\n\t\t\t\trefreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform );\n\n\t\t\t}\n\n\t\t\tif ( material.iridescenceThicknessMap ) {\n\n\t\t\t\tuniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap;\n\n\t\t\t\trefreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.transmission > 0 ) {\n\n\t\t\tuniforms.transmission.value = material.transmission;\n\t\t\tuniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture;\n\t\t\tuniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height );\n\n\t\t\tif ( material.transmissionMap ) {\n\n\t\t\t\tuniforms.transmissionMap.value = material.transmissionMap;\n\n\t\t\t\trefreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform );\n\n\t\t\t}\n\n\t\t\tuniforms.thickness.value = material.thickness;\n\n\t\t\tif ( material.thicknessMap ) {\n\n\t\t\t\tuniforms.thicknessMap.value = material.thicknessMap;\n\n\t\t\t\trefreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform );\n\n\t\t\t}\n\n\t\t\tuniforms.attenuationDistance.value = material.attenuationDistance;\n\t\t\tuniforms.attenuationColor.value.copy( material.attenuationColor );\n\n\t\t}\n\n\t\tif ( material.anisotropy > 0 ) {\n\n\t\t\tuniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) );\n\n\t\t\tif ( material.anisotropyMap ) {\n\n\t\t\t\tuniforms.anisotropyMap.value = material.anisotropyMap;\n\n\t\t\t\trefreshTransformUniform( material.anisotropyMap, uniforms.anisotropyMapTransform );\n\n\t\t\t}\n\n\t\t}\n\n\t\tuniforms.specularIntensity.value = material.specularIntensity;\n\t\tuniforms.specularColor.value.copy( material.specularColor );\n\n\t\tif ( material.specularColorMap ) {\n\n\t\t\tuniforms.specularColorMap.value = material.specularColorMap;\n\n\t\t\trefreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform );\n\n\t\t}\n\n\t\tif ( material.specularIntensityMap ) {\n\n\t\t\tuniforms.specularIntensityMap.value = material.specularIntensityMap;\n\n\t\t\trefreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform );\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsMatcap( uniforms, material ) {\n\n\t\tif ( material.matcap ) {\n\n\t\t\tuniforms.matcap.value = material.matcap;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsDistance( uniforms, material ) {\n\n\t\tconst light = properties.get( material ).light;\n\n\t\tuniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld );\n\t\tuniforms.nearDistance.value = light.shadow.camera.near;\n\t\tuniforms.farDistance.value = light.shadow.camera.far;\n\n\t}\n\n\treturn {\n\t\trefreshFogUniforms: refreshFogUniforms,\n\t\trefreshMaterialUniforms: refreshMaterialUniforms\n\t};\n\n}\n\nfunction WebGLUniformsGroups( gl, info, capabilities, state ) {\n\n\tlet buffers = {};\n\tlet updateList = {};\n\tlet allocatedBindingPoints = [];\n\n\tconst maxBindingPoints = gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ); // binding points are global whereas block indices are per shader program\n\n\tfunction bind( uniformsGroup, program ) {\n\n\t\tconst webglProgram = program.program;\n\t\tstate.uniformBlockBinding( uniformsGroup, webglProgram );\n\n\t}\n\n\tfunction update( uniformsGroup, program ) {\n\n\t\tlet buffer = buffers[ uniformsGroup.id ];\n\n\t\tif ( buffer === undefined ) {\n\n\t\t\tprepareUniformsGroup( uniformsGroup );\n\n\t\t\tbuffer = createBuffer( uniformsGroup );\n\t\t\tbuffers[ uniformsGroup.id ] = buffer;\n\n\t\t\tuniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose );\n\n\t\t}\n\n\t\t// ensure to update the binding points/block indices mapping for this program\n\n\t\tconst webglProgram = program.program;\n\t\tstate.updateUBOMapping( uniformsGroup, webglProgram );\n\n\t\t// update UBO once per frame\n\n\t\tconst frame = info.render.frame;\n\n\t\tif ( updateList[ uniformsGroup.id ] !== frame ) {\n\n\t\t\tupdateBufferData( uniformsGroup );\n\n\t\t\tupdateList[ uniformsGroup.id ] = frame;\n\n\t\t}\n\n\t}\n\n\tfunction createBuffer( uniformsGroup ) {\n\n\t\t// the setup of an UBO is independent of a particular shader program but global\n\n\t\tconst bindingPointIndex = allocateBindingPointIndex();\n\t\tuniformsGroup.__bindingPointIndex = bindingPointIndex;\n\n\t\tconst buffer = gl.createBuffer();\n\t\tconst size = uniformsGroup.__size;\n\t\tconst usage = uniformsGroup.usage;\n\n\t\tgl.bindBuffer( gl.UNIFORM_BUFFER, buffer );\n\t\tgl.bufferData( gl.UNIFORM_BUFFER, size, usage );\n\t\tgl.bindBuffer( gl.UNIFORM_BUFFER, null );\n\t\tgl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer );\n\n\t\treturn buffer;\n\n\t}\n\n\tfunction allocateBindingPointIndex() {\n\n\t\tfor ( let i = 0; i < maxBindingPoints; i ++ ) {\n\n\t\t\tif ( allocatedBindingPoints.indexOf( i ) === - 1 ) {\n\n\t\t\t\tallocatedBindingPoints.push( i );\n\t\t\t\treturn i;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconsole.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' );\n\n\t\treturn 0;\n\n\t}\n\n\tfunction updateBufferData( uniformsGroup ) {\n\n\t\tconst buffer = buffers[ uniformsGroup.id ];\n\t\tconst uniforms = uniformsGroup.uniforms;\n\t\tconst cache = uniformsGroup.__cache;\n\n\t\tgl.bindBuffer( gl.UNIFORM_BUFFER, buffer );\n\n\t\tfor ( let i = 0, il = uniforms.length; i < il; i ++ ) {\n\n\t\t\tconst uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];\n\n\t\t\tfor ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {\n\n\t\t\t\tconst uniform = uniformArray[ j ];\n\n\t\t\t\tif ( hasUniformChanged( uniform, i, j, cache ) === true ) {\n\n\t\t\t\t\tconst offset = uniform.__offset;\n\n\t\t\t\t\tconst values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];\n\n\t\t\t\t\tlet arrayOffset = 0;\n\n\t\t\t\t\tfor ( let k = 0; k < values.length; k ++ ) {\n\n\t\t\t\t\t\tconst value = values[ k ];\n\n\t\t\t\t\t\tconst info = getUniformSize( value );\n\n\t\t\t\t\t\t// TODO add integer and struct support\n\t\t\t\t\t\tif ( typeof value === 'number' || typeof value === 'boolean' ) {\n\n\t\t\t\t\t\t\tuniform.__data[ 0 ] = value;\n\t\t\t\t\t\t\tgl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data );\n\n\t\t\t\t\t\t} else if ( value.isMatrix3 ) {\n\n\t\t\t\t\t\t\t// manually converting 3x3 to 3x4\n\n\t\t\t\t\t\t\tuniform.__data[ 0 ] = value.elements[ 0 ];\n\t\t\t\t\t\t\tuniform.__data[ 1 ] = value.elements[ 1 ];\n\t\t\t\t\t\t\tuniform.__data[ 2 ] = value.elements[ 2 ];\n\t\t\t\t\t\t\tuniform.__data[ 3 ] = 0;\n\t\t\t\t\t\t\tuniform.__data[ 4 ] = value.elements[ 3 ];\n\t\t\t\t\t\t\tuniform.__data[ 5 ] = value.elements[ 4 ];\n\t\t\t\t\t\t\tuniform.__data[ 6 ] = value.elements[ 5 ];\n\t\t\t\t\t\t\tuniform.__data[ 7 ] = 0;\n\t\t\t\t\t\t\tuniform.__data[ 8 ] = value.elements[ 6 ];\n\t\t\t\t\t\t\tuniform.__data[ 9 ] = value.elements[ 7 ];\n\t\t\t\t\t\t\tuniform.__data[ 10 ] = value.elements[ 8 ];\n\t\t\t\t\t\t\tuniform.__data[ 11 ] = 0;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tvalue.toArray( uniform.__data, arrayOffset );\n\n\t\t\t\t\t\t\tarrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tgl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tgl.bindBuffer( gl.UNIFORM_BUFFER, null );\n\n\t}\n\n\tfunction hasUniformChanged( uniform, index, indexArray, cache ) {\n\n\t\tconst value = uniform.value;\n\t\tconst indexString = index + '_' + indexArray;\n\n\t\tif ( cache[ indexString ] === undefined ) {\n\n\t\t\t// cache entry does not exist so far\n\n\t\t\tif ( typeof value === 'number' || typeof value === 'boolean' ) {\n\n\t\t\t\tcache[ indexString ] = value;\n\n\t\t\t} else {\n\n\t\t\t\tcache[ indexString ] = value.clone();\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t} else {\n\n\t\t\tconst cachedObject = cache[ indexString ];\n\n\t\t\t// compare current value with cached entry\n\n\t\t\tif ( typeof value === 'number' || typeof value === 'boolean' ) {\n\n\t\t\t\tif ( cachedObject !== value ) {\n\n\t\t\t\t\tcache[ indexString ] = value;\n\t\t\t\t\treturn true;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( cachedObject.equals( value ) === false ) {\n\n\t\t\t\t\tcachedObject.copy( value );\n\t\t\t\t\treturn true;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn false;\n\n\t}\n\n\tfunction prepareUniformsGroup( uniformsGroup ) {\n\n\t\t// determine total buffer size according to the STD140 layout\n\t\t// Hint: STD140 is the only supported layout in WebGL 2\n\n\t\tconst uniforms = uniformsGroup.uniforms;\n\n\t\tlet offset = 0; // global buffer offset in bytes\n\t\tconst chunkSize = 16; // size of a chunk in bytes\n\n\t\tfor ( let i = 0, l = uniforms.length; i < l; i ++ ) {\n\n\t\t\tconst uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];\n\n\t\t\tfor ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {\n\n\t\t\t\tconst uniform = uniformArray[ j ];\n\n\t\t\t\tconst values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];\n\n\t\t\t\tfor ( let k = 0, kl = values.length; k < kl; k ++ ) {\n\n\t\t\t\t\tconst value = values[ k ];\n\n\t\t\t\t\tconst info = getUniformSize( value );\n\n\t\t\t\t\t// Calculate the chunk offset\n\t\t\t\t\tconst chunkOffsetUniform = offset % chunkSize;\n\n\t\t\t\t\t// Check for chunk overflow\n\t\t\t\t\tif ( chunkOffsetUniform !== 0 && ( chunkSize - chunkOffsetUniform ) < info.boundary ) {\n\n\t\t\t\t\t\t// Add padding and adjust offset\n\t\t\t\t\t\toffset += ( chunkSize - chunkOffsetUniform );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// the following two properties will be used for partial buffer updates\n\n\t\t\t\t\tuniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT );\n\t\t\t\t\tuniform.__offset = offset;\n\n\n\t\t\t\t\t// Update the global offset\n\t\t\t\t\toffset += info.storage;\n\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// ensure correct final padding\n\n\t\tconst chunkOffset = offset % chunkSize;\n\n\t\tif ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset );\n\n\t\t//\n\n\t\tuniformsGroup.__size = offset;\n\t\tuniformsGroup.__cache = {};\n\n\t\treturn this;\n\n\t}\n\n\tfunction getUniformSize( value ) {\n\n\t\tconst info = {\n\t\t\tboundary: 0, // bytes\n\t\t\tstorage: 0 // bytes\n\t\t};\n\n\t\t// determine sizes according to STD140\n\n\t\tif ( typeof value === 'number' || typeof value === 'boolean' ) {\n\n\t\t\t// float/int/bool\n\n\t\t\tinfo.boundary = 4;\n\t\t\tinfo.storage = 4;\n\n\t\t} else if ( value.isVector2 ) {\n\n\t\t\t// vec2\n\n\t\t\tinfo.boundary = 8;\n\t\t\tinfo.storage = 8;\n\n\t\t} else if ( value.isVector3 || value.isColor ) {\n\n\t\t\t// vec3\n\n\t\t\tinfo.boundary = 16;\n\t\t\tinfo.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes\n\n\t\t} else if ( value.isVector4 ) {\n\n\t\t\t// vec4\n\n\t\t\tinfo.boundary = 16;\n\t\t\tinfo.storage = 16;\n\n\t\t} else if ( value.isMatrix3 ) {\n\n\t\t\t// mat3 (in STD140 a 3x3 matrix is represented as 3x4)\n\n\t\t\tinfo.boundary = 48;\n\t\t\tinfo.storage = 48;\n\n\t\t} else if ( value.isMatrix4 ) {\n\n\t\t\t// mat4\n\n\t\t\tinfo.boundary = 64;\n\t\t\tinfo.storage = 64;\n\n\t\t} else if ( value.isTexture ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' );\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value );\n\n\t\t}\n\n\t\treturn info;\n\n\t}\n\n\tfunction onUniformsGroupsDispose( event ) {\n\n\t\tconst uniformsGroup = event.target;\n\n\t\tuniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose );\n\n\t\tconst index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex );\n\t\tallocatedBindingPoints.splice( index, 1 );\n\n\t\tgl.deleteBuffer( buffers[ uniformsGroup.id ] );\n\n\t\tdelete buffers[ uniformsGroup.id ];\n\t\tdelete updateList[ uniformsGroup.id ];\n\n\t}\n\n\tfunction dispose() {\n\n\t\tfor ( const id in buffers ) {\n\n\t\t\tgl.deleteBuffer( buffers[ id ] );\n\n\t\t}\n\n\t\tallocatedBindingPoints = [];\n\t\tbuffers = {};\n\t\tupdateList = {};\n\n\t}\n\n\treturn {\n\n\t\tbind: bind,\n\t\tupdate: update,\n\n\t\tdispose: dispose\n\n\t};\n\n}\n\nclass WebGLRenderer {\n\n\tconstructor( parameters = {} ) {\n\n\t\tconst {\n\t\t\tcanvas = createCanvasElement(),\n\t\t\tcontext = null,\n\t\t\tdepth = true,\n\t\t\tstencil = false,\n\t\t\talpha = false,\n\t\t\tantialias = false,\n\t\t\tpremultipliedAlpha = true,\n\t\t\tpreserveDrawingBuffer = false,\n\t\t\tpowerPreference = 'default',\n\t\t\tfailIfMajorPerformanceCaveat = false,\n\t\t} = parameters;\n\n\t\tthis.isWebGLRenderer = true;\n\n\t\tlet _alpha;\n\n\t\tif ( context !== null ) {\n\n\t\t\tif ( typeof WebGLRenderingContext !== 'undefined' && context instanceof WebGLRenderingContext ) {\n\n\t\t\t\tthrow new Error( 'THREE.WebGLRenderer: WebGL 1 is not supported since r163.' );\n\n\t\t\t}\n\n\t\t\t_alpha = context.getContextAttributes().alpha;\n\n\t\t} else {\n\n\t\t\t_alpha = alpha;\n\n\t\t}\n\n\t\tconst uintClearColor = new Uint32Array( 4 );\n\t\tconst intClearColor = new Int32Array( 4 );\n\n\t\tlet currentRenderList = null;\n\t\tlet currentRenderState = null;\n\n\t\t// render() can be called from within a callback triggered by another render.\n\t\t// We track this so that the nested render call gets its list and state isolated from the parent render call.\n\n\t\tconst renderListStack = [];\n\t\tconst renderStateStack = [];\n\n\t\t// public properties\n\n\t\tthis.domElement = canvas;\n\n\t\t// Debug configuration container\n\t\tthis.debug = {\n\n\t\t\t/**\n\t\t\t * Enables error checking and reporting when shader programs are being compiled\n\t\t\t * @type {boolean}\n\t\t\t */\n\t\t\tcheckShaderErrors: true,\n\t\t\t/**\n\t\t\t * Callback for custom error reporting.\n\t\t\t * @type {?Function}\n\t\t\t */\n\t\t\tonShaderError: null\n\t\t};\n\n\t\t// clearing\n\n\t\tthis.autoClear = true;\n\t\tthis.autoClearColor = true;\n\t\tthis.autoClearDepth = true;\n\t\tthis.autoClearStencil = true;\n\n\t\t// scene graph\n\n\t\tthis.sortObjects = true;\n\n\t\t// user-defined clipping\n\n\t\tthis.clippingPlanes = [];\n\t\tthis.localClippingEnabled = false;\n\n\t\t// physically based shading\n\n\t\tthis._outputColorSpace = SRGBColorSpace;\n\n\t\t// tone mapping\n\n\t\tthis.toneMapping = NoToneMapping;\n\t\tthis.toneMappingExposure = 1.0;\n\n\t\t// internal properties\n\n\t\tconst _this = this;\n\n\t\tlet _isContextLost = false;\n\n\t\t// internal state cache\n\n\t\tlet _currentActiveCubeFace = 0;\n\t\tlet _currentActiveMipmapLevel = 0;\n\t\tlet _currentRenderTarget = null;\n\t\tlet _currentMaterialId = - 1;\n\n\t\tlet _currentCamera = null;\n\n\t\tconst _currentViewport = new Vector4();\n\t\tconst _currentScissor = new Vector4();\n\t\tlet _currentScissorTest = null;\n\n\t\tconst _currentClearColor = new Color( 0x000000 );\n\t\tlet _currentClearAlpha = 0;\n\n\t\t//\n\n\t\tlet _width = canvas.width;\n\t\tlet _height = canvas.height;\n\n\t\tlet _pixelRatio = 1;\n\t\tlet _opaqueSort = null;\n\t\tlet _transparentSort = null;\n\n\t\tconst _viewport = new Vector4( 0, 0, _width, _height );\n\t\tconst _scissor = new Vector4( 0, 0, _width, _height );\n\t\tlet _scissorTest = false;\n\n\t\t// frustum\n\n\t\tconst _frustum = new Frustum();\n\n\t\t// clipping\n\n\t\tlet _clippingEnabled = false;\n\t\tlet _localClippingEnabled = false;\n\n\t\t// camera matrices cache\n\n\t\tconst _projScreenMatrix = new Matrix4();\n\n\t\tconst _vector3 = new Vector3();\n\n\t\tconst _vector4 = new Vector4();\n\n\t\tconst _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };\n\n\t\tlet _renderBackground = false;\n\n\t\tfunction getTargetPixelRatio() {\n\n\t\t\treturn _currentRenderTarget === null ? _pixelRatio : 1;\n\n\t\t}\n\n\t\t// initialize\n\n\t\tlet _gl = context;\n\n\t\tfunction getContext( contextName, contextAttributes ) {\n\n\t\t\treturn canvas.getContext( contextName, contextAttributes );\n\n\t\t}\n\n\t\ttry {\n\n\t\t\tconst contextAttributes = {\n\t\t\t\talpha: true,\n\t\t\t\tdepth,\n\t\t\t\tstencil,\n\t\t\t\tantialias,\n\t\t\t\tpremultipliedAlpha,\n\t\t\t\tpreserveDrawingBuffer,\n\t\t\t\tpowerPreference,\n\t\t\t\tfailIfMajorPerformanceCaveat,\n\t\t\t};\n\n\t\t\t// OffscreenCanvas does not have setAttribute, see #22811\n\t\t\tif ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` );\n\n\t\t\t// event listeners must be registered before WebGL context is created, see #12753\n\t\t\tcanvas.addEventListener( 'webglcontextlost', onContextLost, false );\n\t\t\tcanvas.addEventListener( 'webglcontextrestored', onContextRestore, false );\n\t\t\tcanvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false );\n\n\t\t\tif ( _gl === null ) {\n\n\t\t\t\tconst contextName = 'webgl2';\n\n\t\t\t\t_gl = getContext( contextName, contextAttributes );\n\n\t\t\t\tif ( _gl === null ) {\n\n\t\t\t\t\tif ( getContext( contextName ) ) {\n\n\t\t\t\t\t\tthrow new Error( 'Error creating WebGL context with your selected attributes.' );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tthrow new Error( 'Error creating WebGL context.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLRenderer: ' + error.message );\n\t\t\tthrow error;\n\n\t\t}\n\n\t\tlet extensions, capabilities, state, info;\n\t\tlet properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects;\n\t\tlet programCache, materials, renderLists, renderStates, clipping, shadowMap;\n\n\t\tlet background, morphtargets, bufferRenderer, indexedBufferRenderer;\n\n\t\tlet utils, bindingStates, uniformsGroups;\n\n\t\tfunction initGLContext() {\n\n\t\t\textensions = new WebGLExtensions( _gl );\n\t\t\textensions.init();\n\n\t\t\tutils = new WebGLUtils( _gl, extensions );\n\n\t\t\tcapabilities = new WebGLCapabilities( _gl, extensions, parameters, utils );\n\n\t\t\tstate = new WebGLState( _gl );\n\n\t\t\tinfo = new WebGLInfo( _gl );\n\t\t\tproperties = new WebGLProperties();\n\t\t\ttextures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );\n\t\t\tcubemaps = new WebGLCubeMaps( _this );\n\t\t\tcubeuvmaps = new WebGLCubeUVMaps( _this );\n\t\t\tattributes = new WebGLAttributes( _gl );\n\t\t\tbindingStates = new WebGLBindingStates( _gl, attributes );\n\t\t\tgeometries = new WebGLGeometries( _gl, attributes, info, bindingStates );\n\t\t\tobjects = new WebGLObjects( _gl, geometries, attributes, info );\n\t\t\tmorphtargets = new WebGLMorphtargets( _gl, capabilities, textures );\n\t\t\tclipping = new WebGLClipping( properties );\n\t\t\tprogramCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping );\n\t\t\tmaterials = new WebGLMaterials( _this, properties );\n\t\t\trenderLists = new WebGLRenderLists();\n\t\t\trenderStates = new WebGLRenderStates( extensions );\n\t\t\tbackground = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha );\n\t\t\tshadowMap = new WebGLShadowMap( _this, objects, capabilities );\n\t\t\tuniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state );\n\n\t\t\tbufferRenderer = new WebGLBufferRenderer( _gl, extensions, info );\n\t\t\tindexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info );\n\n\t\t\tinfo.programs = programCache.programs;\n\n\t\t\t_this.capabilities = capabilities;\n\t\t\t_this.extensions = extensions;\n\t\t\t_this.properties = properties;\n\t\t\t_this.renderLists = renderLists;\n\t\t\t_this.shadowMap = shadowMap;\n\t\t\t_this.state = state;\n\t\t\t_this.info = info;\n\n\t\t}\n\n\t\tinitGLContext();\n\n\t\t// xr\n\n\t\tconst xr = new WebXRManager( _this, _gl );\n\n\t\tthis.xr = xr;\n\n\t\t// API\n\n\t\tthis.getContext = function () {\n\n\t\t\treturn _gl;\n\n\t\t};\n\n\t\tthis.getContextAttributes = function () {\n\n\t\t\treturn _gl.getContextAttributes();\n\n\t\t};\n\n\t\tthis.forceContextLoss = function () {\n\n\t\t\tconst extension = extensions.get( 'WEBGL_lose_context' );\n\t\t\tif ( extension ) extension.loseContext();\n\n\t\t};\n\n\t\tthis.forceContextRestore = function () {\n\n\t\t\tconst extension = extensions.get( 'WEBGL_lose_context' );\n\t\t\tif ( extension ) extension.restoreContext();\n\n\t\t};\n\n\t\tthis.getPixelRatio = function () {\n\n\t\t\treturn _pixelRatio;\n\n\t\t};\n\n\t\tthis.setPixelRatio = function ( value ) {\n\n\t\t\tif ( value === undefined ) return;\n\n\t\t\t_pixelRatio = value;\n\n\t\t\tthis.setSize( _width, _height, false );\n\n\t\t};\n\n\t\tthis.getSize = function ( target ) {\n\n\t\t\treturn target.set( _width, _height );\n\n\t\t};\n\n\t\tthis.setSize = function ( width, height, updateStyle = true ) {\n\n\t\t\tif ( xr.isPresenting ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Can\\'t change size while VR device is presenting.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\t_width = width;\n\t\t\t_height = height;\n\n\t\t\tcanvas.width = Math.floor( width * _pixelRatio );\n\t\t\tcanvas.height = Math.floor( height * _pixelRatio );\n\n\t\t\tif ( updateStyle === true ) {\n\n\t\t\t\tcanvas.style.width = width + 'px';\n\t\t\t\tcanvas.style.height = height + 'px';\n\n\t\t\t}\n\n\t\t\tthis.setViewport( 0, 0, width, height );\n\n\t\t};\n\n\t\tthis.getDrawingBufferSize = function ( target ) {\n\n\t\t\treturn target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();\n\n\t\t};\n\n\t\tthis.setDrawingBufferSize = function ( width, height, pixelRatio ) {\n\n\t\t\t_width = width;\n\t\t\t_height = height;\n\n\t\t\t_pixelRatio = pixelRatio;\n\n\t\t\tcanvas.width = Math.floor( width * pixelRatio );\n\t\t\tcanvas.height = Math.floor( height * pixelRatio );\n\n\t\t\tthis.setViewport( 0, 0, width, height );\n\n\t\t};\n\n\t\tthis.getCurrentViewport = function ( target ) {\n\n\t\t\treturn target.copy( _currentViewport );\n\n\t\t};\n\n\t\tthis.getViewport = function ( target ) {\n\n\t\t\treturn target.copy( _viewport );\n\n\t\t};\n\n\t\tthis.setViewport = function ( x, y, width, height ) {\n\n\t\t\tif ( x.isVector4 ) {\n\n\t\t\t\t_viewport.set( x.x, x.y, x.z, x.w );\n\n\t\t\t} else {\n\n\t\t\t\t_viewport.set( x, y, width, height );\n\n\t\t\t}\n\n\t\t\tstate.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).round() );\n\n\t\t};\n\n\t\tthis.getScissor = function ( target ) {\n\n\t\t\treturn target.copy( _scissor );\n\n\t\t};\n\n\t\tthis.setScissor = function ( x, y, width, height ) {\n\n\t\t\tif ( x.isVector4 ) {\n\n\t\t\t\t_scissor.set( x.x, x.y, x.z, x.w );\n\n\t\t\t} else {\n\n\t\t\t\t_scissor.set( x, y, width, height );\n\n\t\t\t}\n\n\t\t\tstate.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).round() );\n\n\t\t};\n\n\t\tthis.getScissorTest = function () {\n\n\t\t\treturn _scissorTest;\n\n\t\t};\n\n\t\tthis.setScissorTest = function ( boolean ) {\n\n\t\t\tstate.setScissorTest( _scissorTest = boolean );\n\n\t\t};\n\n\t\tthis.setOpaqueSort = function ( method ) {\n\n\t\t\t_opaqueSort = method;\n\n\t\t};\n\n\t\tthis.setTransparentSort = function ( method ) {\n\n\t\t\t_transparentSort = method;\n\n\t\t};\n\n\t\t// Clearing\n\n\t\tthis.getClearColor = function ( target ) {\n\n\t\t\treturn target.copy( background.getClearColor() );\n\n\t\t};\n\n\t\tthis.setClearColor = function () {\n\n\t\t\tbackground.setClearColor.apply( background, arguments );\n\n\t\t};\n\n\t\tthis.getClearAlpha = function () {\n\n\t\t\treturn background.getClearAlpha();\n\n\t\t};\n\n\t\tthis.setClearAlpha = function () {\n\n\t\t\tbackground.setClearAlpha.apply( background, arguments );\n\n\t\t};\n\n\t\tthis.clear = function ( color = true, depth = true, stencil = true ) {\n\n\t\t\tlet bits = 0;\n\n\t\t\tif ( color ) {\n\n\t\t\t\t// check if we're trying to clear an integer target\n\t\t\t\tlet isIntegerFormat = false;\n\t\t\t\tif ( _currentRenderTarget !== null ) {\n\n\t\t\t\t\tconst targetFormat = _currentRenderTarget.texture.format;\n\t\t\t\t\tisIntegerFormat = targetFormat === RGBAIntegerFormat ||\n\t\t\t\t\t\ttargetFormat === RGIntegerFormat ||\n\t\t\t\t\t\ttargetFormat === RedIntegerFormat;\n\n\t\t\t\t}\n\n\t\t\t\t// use the appropriate clear functions to clear the target if it's a signed\n\t\t\t\t// or unsigned integer target\n\t\t\t\tif ( isIntegerFormat ) {\n\n\t\t\t\t\tconst targetType = _currentRenderTarget.texture.type;\n\t\t\t\t\tconst isUnsignedType = targetType === UnsignedByteType ||\n\t\t\t\t\t\ttargetType === UnsignedIntType ||\n\t\t\t\t\t\ttargetType === UnsignedShortType ||\n\t\t\t\t\t\ttargetType === UnsignedInt248Type ||\n\t\t\t\t\t\ttargetType === UnsignedShort4444Type ||\n\t\t\t\t\t\ttargetType === UnsignedShort5551Type;\n\n\t\t\t\t\tconst clearColor = background.getClearColor();\n\t\t\t\t\tconst a = background.getClearAlpha();\n\t\t\t\t\tconst r = clearColor.r;\n\t\t\t\t\tconst g = clearColor.g;\n\t\t\t\t\tconst b = clearColor.b;\n\n\t\t\t\t\tif ( isUnsignedType ) {\n\n\t\t\t\t\t\tuintClearColor[ 0 ] = r;\n\t\t\t\t\t\tuintClearColor[ 1 ] = g;\n\t\t\t\t\t\tuintClearColor[ 2 ] = b;\n\t\t\t\t\t\tuintClearColor[ 3 ] = a;\n\t\t\t\t\t\t_gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tintClearColor[ 0 ] = r;\n\t\t\t\t\t\tintClearColor[ 1 ] = g;\n\t\t\t\t\t\tintClearColor[ 2 ] = b;\n\t\t\t\t\t\tintClearColor[ 3 ] = a;\n\t\t\t\t\t\t_gl.clearBufferiv( _gl.COLOR, 0, intClearColor );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tbits |= _gl.COLOR_BUFFER_BIT;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( depth ) bits |= _gl.DEPTH_BUFFER_BIT;\n\t\t\tif ( stencil ) {\n\n\t\t\t\tbits |= _gl.STENCIL_BUFFER_BIT;\n\t\t\t\tthis.state.buffers.stencil.setMask( 0xffffffff );\n\n\t\t\t}\n\n\t\t\t_gl.clear( bits );\n\n\t\t};\n\n\t\tthis.clearColor = function () {\n\n\t\t\tthis.clear( true, false, false );\n\n\t\t};\n\n\t\tthis.clearDepth = function () {\n\n\t\t\tthis.clear( false, true, false );\n\n\t\t};\n\n\t\tthis.clearStencil = function () {\n\n\t\t\tthis.clear( false, false, true );\n\n\t\t};\n\n\t\t//\n\n\t\tthis.dispose = function () {\n\n\t\t\tcanvas.removeEventListener( 'webglcontextlost', onContextLost, false );\n\t\t\tcanvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );\n\t\t\tcanvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false );\n\n\t\t\trenderLists.dispose();\n\t\t\trenderStates.dispose();\n\t\t\tproperties.dispose();\n\t\t\tcubemaps.dispose();\n\t\t\tcubeuvmaps.dispose();\n\t\t\tobjects.dispose();\n\t\t\tbindingStates.dispose();\n\t\t\tuniformsGroups.dispose();\n\t\t\tprogramCache.dispose();\n\n\t\t\txr.dispose();\n\n\t\t\txr.removeEventListener( 'sessionstart', onXRSessionStart );\n\t\t\txr.removeEventListener( 'sessionend', onXRSessionEnd );\n\n\t\t\tanimation.stop();\n\n\t\t};\n\n\t\t// Events\n\n\t\tfunction onContextLost( event ) {\n\n\t\t\tevent.preventDefault();\n\n\t\t\tconsole.log( 'THREE.WebGLRenderer: Context Lost.' );\n\n\t\t\t_isContextLost = true;\n\n\t\t}\n\n\t\tfunction onContextRestore( /* event */ ) {\n\n\t\t\tconsole.log( 'THREE.WebGLRenderer: Context Restored.' );\n\n\t\t\t_isContextLost = false;\n\n\t\t\tconst infoAutoReset = info.autoReset;\n\t\t\tconst shadowMapEnabled = shadowMap.enabled;\n\t\t\tconst shadowMapAutoUpdate = shadowMap.autoUpdate;\n\t\t\tconst shadowMapNeedsUpdate = shadowMap.needsUpdate;\n\t\t\tconst shadowMapType = shadowMap.type;\n\n\t\t\tinitGLContext();\n\n\t\t\tinfo.autoReset = infoAutoReset;\n\t\t\tshadowMap.enabled = shadowMapEnabled;\n\t\t\tshadowMap.autoUpdate = shadowMapAutoUpdate;\n\t\t\tshadowMap.needsUpdate = shadowMapNeedsUpdate;\n\t\t\tshadowMap.type = shadowMapType;\n\n\t\t}\n\n\t\tfunction onContextCreationError( event ) {\n\n\t\t\tconsole.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage );\n\n\t\t}\n\n\t\tfunction onMaterialDispose( event ) {\n\n\t\t\tconst material = event.target;\n\n\t\t\tmaterial.removeEventListener( 'dispose', onMaterialDispose );\n\n\t\t\tdeallocateMaterial( material );\n\n\t\t}\n\n\t\t// Buffer deallocation\n\n\t\tfunction deallocateMaterial( material ) {\n\n\t\t\treleaseMaterialProgramReferences( material );\n\n\t\t\tproperties.remove( material );\n\n\t\t}\n\n\n\t\tfunction releaseMaterialProgramReferences( material ) {\n\n\t\t\tconst programs = properties.get( material ).programs;\n\n\t\t\tif ( programs !== undefined ) {\n\n\t\t\t\tprograms.forEach( function ( program ) {\n\n\t\t\t\t\tprogramCache.releaseProgram( program );\n\n\t\t\t\t} );\n\n\t\t\t\tif ( material.isShaderMaterial ) {\n\n\t\t\t\t\tprogramCache.releaseShaderCache( material );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Buffer rendering\n\n\t\tthis.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {\n\n\t\t\tif ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)\n\n\t\t\tconst frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );\n\n\t\t\tconst program = setProgram( camera, scene, geometry, material, object );\n\n\t\t\tstate.setMaterial( material, frontFaceCW );\n\n\t\t\t//\n\n\t\t\tlet index = geometry.index;\n\t\t\tlet rangeFactor = 1;\n\n\t\t\tif ( material.wireframe === true ) {\n\n\t\t\t\tindex = geometries.getWireframeAttribute( geometry );\n\n\t\t\t\tif ( index === undefined ) return;\n\n\t\t\t\trangeFactor = 2;\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tconst drawRange = geometry.drawRange;\n\t\t\tconst position = geometry.attributes.position;\n\n\t\t\tlet drawStart = drawRange.start * rangeFactor;\n\t\t\tlet drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor;\n\n\t\t\tif ( group !== null ) {\n\n\t\t\t\tdrawStart = Math.max( drawStart, group.start * rangeFactor );\n\t\t\t\tdrawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor );\n\n\t\t\t}\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tdrawStart = Math.max( drawStart, 0 );\n\t\t\t\tdrawEnd = Math.min( drawEnd, index.count );\n\n\t\t\t} else if ( position !== undefined && position !== null ) {\n\n\t\t\t\tdrawStart = Math.max( drawStart, 0 );\n\t\t\t\tdrawEnd = Math.min( drawEnd, position.count );\n\n\t\t\t}\n\n\t\t\tconst drawCount = drawEnd - drawStart;\n\n\t\t\tif ( drawCount < 0 || drawCount === Infinity ) return;\n\n\t\t\t//\n\n\t\t\tbindingStates.setup( object, material, program, geometry, index );\n\n\t\t\tlet attribute;\n\t\t\tlet renderer = bufferRenderer;\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tattribute = attributes.get( index );\n\n\t\t\t\trenderer = indexedBufferRenderer;\n\t\t\t\trenderer.setIndex( attribute );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( object.isMesh ) {\n\n\t\t\t\tif ( material.wireframe === true ) {\n\n\t\t\t\t\tstate.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );\n\t\t\t\t\trenderer.setMode( _gl.LINES );\n\n\t\t\t\t} else {\n\n\t\t\t\t\trenderer.setMode( _gl.TRIANGLES );\n\n\t\t\t\t}\n\n\t\t\t} else if ( object.isLine ) {\n\n\t\t\t\tlet lineWidth = material.linewidth;\n\n\t\t\t\tif ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material\n\n\t\t\t\tstate.setLineWidth( lineWidth * getTargetPixelRatio() );\n\n\t\t\t\tif ( object.isLineSegments ) {\n\n\t\t\t\t\trenderer.setMode( _gl.LINES );\n\n\t\t\t\t} else if ( object.isLineLoop ) {\n\n\t\t\t\t\trenderer.setMode( _gl.LINE_LOOP );\n\n\t\t\t\t} else {\n\n\t\t\t\t\trenderer.setMode( _gl.LINE_STRIP );\n\n\t\t\t\t}\n\n\t\t\t} else if ( object.isPoints ) {\n\n\t\t\t\trenderer.setMode( _gl.POINTS );\n\n\t\t\t} else if ( object.isSprite ) {\n\n\t\t\t\trenderer.setMode( _gl.TRIANGLES );\n\n\t\t\t}\n\n\t\t\tif ( object.isBatchedMesh ) {\n\n\t\t\t\tif ( object._multiDrawInstances !== null ) {\n\n\t\t\t\t\trenderer.renderMultiDrawInstances( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount, object._multiDrawInstances );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( ! extensions.get( 'WEBGL_multi_draw' ) ) {\n\n\t\t\t\t\t\tconst starts = object._multiDrawStarts;\n\t\t\t\t\t\tconst counts = object._multiDrawCounts;\n\t\t\t\t\t\tconst drawCount = object._multiDrawCount;\n\t\t\t\t\t\tconst bytesPerElement = index ? attributes.get( index ).bytesPerElement : 1;\n\t\t\t\t\t\tconst uniforms = properties.get( material ).currentProgram.getUniforms();\n\t\t\t\t\t\tfor ( let i = 0; i < drawCount; i ++ ) {\n\n\t\t\t\t\t\t\tuniforms.setValue( _gl, '_gl_DrawID', i );\n\t\t\t\t\t\t\trenderer.render( starts[ i ] / bytesPerElement, counts[ i ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\trenderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( object.isInstancedMesh ) {\n\n\t\t\t\trenderer.renderInstances( drawStart, drawCount, object.count );\n\n\t\t\t} else if ( geometry.isInstancedBufferGeometry ) {\n\n\t\t\t\tconst maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity;\n\t\t\t\tconst instanceCount = Math.min( geometry.instanceCount, maxInstanceCount );\n\n\t\t\t\trenderer.renderInstances( drawStart, drawCount, instanceCount );\n\n\t\t\t} else {\n\n\t\t\t\trenderer.render( drawStart, drawCount );\n\n\t\t\t}\n\n\t\t};\n\n\t\t// Compile\n\n\t\tfunction prepareMaterial( material, scene, object ) {\n\n\t\t\tif ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {\n\n\t\t\t\tmaterial.side = BackSide;\n\t\t\t\tmaterial.needsUpdate = true;\n\t\t\t\tgetProgram( material, scene, object );\n\n\t\t\t\tmaterial.side = FrontSide;\n\t\t\t\tmaterial.needsUpdate = true;\n\t\t\t\tgetProgram( material, scene, object );\n\n\t\t\t\tmaterial.side = DoubleSide;\n\n\t\t\t} else {\n\n\t\t\t\tgetProgram( material, scene, object );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.compile = function ( scene, camera, targetScene = null ) {\n\n\t\t\tif ( targetScene === null ) targetScene = scene;\n\n\t\t\tcurrentRenderState = renderStates.get( targetScene );\n\t\t\tcurrentRenderState.init( camera );\n\n\t\t\trenderStateStack.push( currentRenderState );\n\n\t\t\t// gather lights from both the target scene and the new object that will be added to the scene.\n\n\t\t\ttargetScene.traverseVisible( function ( object ) {\n\n\t\t\t\tif ( object.isLight && object.layers.test( camera.layers ) ) {\n\n\t\t\t\t\tcurrentRenderState.pushLight( object );\n\n\t\t\t\t\tif ( object.castShadow ) {\n\n\t\t\t\t\t\tcurrentRenderState.pushShadow( object );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\tif ( scene !== targetScene ) {\n\n\t\t\t\tscene.traverseVisible( function ( object ) {\n\n\t\t\t\t\tif ( object.isLight && object.layers.test( camera.layers ) ) {\n\n\t\t\t\t\t\tcurrentRenderState.pushLight( object );\n\n\t\t\t\t\t\tif ( object.castShadow ) {\n\n\t\t\t\t\t\t\tcurrentRenderState.pushShadow( object );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\tcurrentRenderState.setupLights();\n\n\t\t\t// Only initialize materials in the new scene, not the targetScene.\n\n\t\t\tconst materials = new Set();\n\n\t\t\tscene.traverse( function ( object ) {\n\n\t\t\t\tconst material = object.material;\n\n\t\t\t\tif ( material ) {\n\n\t\t\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\t\t\tfor ( let i = 0; i < material.length; i ++ ) {\n\n\t\t\t\t\t\t\tconst material2 = material[ i ];\n\n\t\t\t\t\t\t\tprepareMaterial( material2, targetScene, object );\n\t\t\t\t\t\t\tmaterials.add( material2 );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tprepareMaterial( material, targetScene, object );\n\t\t\t\t\t\tmaterials.add( material );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\trenderStateStack.pop();\n\t\t\tcurrentRenderState = null;\n\n\t\t\treturn materials;\n\n\t\t};\n\n\t\t// compileAsync\n\n\t\tthis.compileAsync = function ( scene, camera, targetScene = null ) {\n\n\t\t\tconst materials = this.compile( scene, camera, targetScene );\n\n\t\t\t// Wait for all the materials in the new object to indicate that they're\n\t\t\t// ready to be used before resolving the promise.\n\n\t\t\treturn new Promise( ( resolve ) => {\n\n\t\t\t\tfunction checkMaterialsReady() {\n\n\t\t\t\t\tmaterials.forEach( function ( material ) {\n\n\t\t\t\t\t\tconst materialProperties = properties.get( material );\n\t\t\t\t\t\tconst program = materialProperties.currentProgram;\n\n\t\t\t\t\t\tif ( program.isReady() ) {\n\n\t\t\t\t\t\t\t// remove any programs that report they're ready to use from the list\n\t\t\t\t\t\t\tmaterials.delete( material );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} );\n\n\t\t\t\t\t// once the list of compiling materials is empty, call the callback\n\n\t\t\t\t\tif ( materials.size === 0 ) {\n\n\t\t\t\t\t\tresolve( scene );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// if some materials are still not ready, wait a bit and check again\n\n\t\t\t\t\tsetTimeout( checkMaterialsReady, 10 );\n\n\t\t\t\t}\n\n\t\t\t\tif ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) {\n\n\t\t\t\t\t// If we can check the compilation status of the materials without\n\t\t\t\t\t// blocking then do so right away.\n\n\t\t\t\t\tcheckMaterialsReady();\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// Otherwise start by waiting a bit to give the materials we just\n\t\t\t\t\t// initialized a chance to finish.\n\n\t\t\t\t\tsetTimeout( checkMaterialsReady, 10 );\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t};\n\n\t\t// Animation Loop\n\n\t\tlet onAnimationFrameCallback = null;\n\n\t\tfunction onAnimationFrame( time ) {\n\n\t\t\tif ( onAnimationFrameCallback ) onAnimationFrameCallback( time );\n\n\t\t}\n\n\t\tfunction onXRSessionStart() {\n\n\t\t\tanimation.stop();\n\n\t\t}\n\n\t\tfunction onXRSessionEnd() {\n\n\t\t\tanimation.start();\n\n\t\t}\n\n\t\tconst animation = new WebGLAnimation();\n\t\tanimation.setAnimationLoop( onAnimationFrame );\n\n\t\tif ( typeof self !== 'undefined' ) animation.setContext( self );\n\n\t\tthis.setAnimationLoop = function ( callback ) {\n\n\t\t\tonAnimationFrameCallback = callback;\n\t\t\txr.setAnimationLoop( callback );\n\n\t\t\t( callback === null ) ? animation.stop() : animation.start();\n\n\t\t};\n\n\t\txr.addEventListener( 'sessionstart', onXRSessionStart );\n\t\txr.addEventListener( 'sessionend', onXRSessionEnd );\n\n\t\t// Rendering\n\n\t\tthis.render = function ( scene, camera ) {\n\n\t\t\tif ( camera !== undefined && camera.isCamera !== true ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( _isContextLost === true ) return;\n\n\t\t\t// update scene graph\n\n\t\t\tif ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();\n\n\t\t\t// update camera matrices and frustum\n\n\t\t\tif ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();\n\n\t\t\tif ( xr.enabled === true && xr.isPresenting === true ) {\n\n\t\t\t\tif ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera );\n\n\t\t\t\tcamera = xr.getCamera(); // use XR camera for rendering\n\n\t\t\t}\n\n\t\t\t//\n\t\t\tif ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget );\n\n\t\t\tcurrentRenderState = renderStates.get( scene, renderStateStack.length );\n\t\t\tcurrentRenderState.init( camera );\n\n\t\t\trenderStateStack.push( currentRenderState );\n\n\t\t\t_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );\n\t\t\t_frustum.setFromProjectionMatrix( _projScreenMatrix );\n\n\t\t\t_localClippingEnabled = this.localClippingEnabled;\n\t\t\t_clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled );\n\n\t\t\tcurrentRenderList = renderLists.get( scene, renderListStack.length );\n\t\t\tcurrentRenderList.init();\n\n\t\t\trenderListStack.push( currentRenderList );\n\n\t\t\tif ( xr.enabled === true && xr.isPresenting === true ) {\n\n\t\t\t\tconst depthSensingMesh = _this.xr.getDepthSensingMesh();\n\n\t\t\t\tif ( depthSensingMesh !== null ) {\n\n\t\t\t\t\tprojectObject( depthSensingMesh, camera, - Infinity, _this.sortObjects );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tprojectObject( scene, camera, 0, _this.sortObjects );\n\n\t\t\tcurrentRenderList.finish();\n\n\t\t\tif ( _this.sortObjects === true ) {\n\n\t\t\t\tcurrentRenderList.sort( _opaqueSort, _transparentSort );\n\n\t\t\t}\n\n\t\t\t_renderBackground = xr.enabled === false || xr.isPresenting === false || xr.hasDepthSensing() === false;\n\t\t\tif ( _renderBackground ) {\n\n\t\t\t\tbackground.addToRenderList( currentRenderList, scene );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tthis.info.render.frame ++;\n\n\t\t\tif ( _clippingEnabled === true ) clipping.beginShadows();\n\n\t\t\tconst shadowsArray = currentRenderState.state.shadowsArray;\n\n\t\t\tshadowMap.render( shadowsArray, scene, camera );\n\n\t\t\tif ( _clippingEnabled === true ) clipping.endShadows();\n\n\t\t\t//\n\n\t\t\tif ( this.info.autoReset === true ) this.info.reset();\n\n\t\t\t// render scene\n\n\t\t\tconst opaqueObjects = currentRenderList.opaque;\n\t\t\tconst transmissiveObjects = currentRenderList.transmissive;\n\n\t\t\tcurrentRenderState.setupLights();\n\n\t\t\tif ( camera.isArrayCamera ) {\n\n\t\t\t\tconst cameras = camera.cameras;\n\n\t\t\t\tif ( transmissiveObjects.length > 0 ) {\n\n\t\t\t\t\tfor ( let i = 0, l = cameras.length; i < l; i ++ ) {\n\n\t\t\t\t\t\tconst camera2 = cameras[ i ];\n\n\t\t\t\t\t\trenderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( _renderBackground ) background.render( scene );\n\n\t\t\t\tfor ( let i = 0, l = cameras.length; i < l; i ++ ) {\n\n\t\t\t\t\tconst camera2 = cameras[ i ];\n\n\t\t\t\t\trenderScene( currentRenderList, scene, camera2, camera2.viewport );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera );\n\n\t\t\t\tif ( _renderBackground ) background.render( scene );\n\n\t\t\t\trenderScene( currentRenderList, scene, camera );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( _currentRenderTarget !== null ) {\n\n\t\t\t\t// resolve multisample renderbuffers to a single-sample texture if necessary\n\n\t\t\t\ttextures.updateMultisampleRenderTarget( _currentRenderTarget );\n\n\t\t\t\t// Generate mipmap if we're using any kind of mipmap filtering\n\n\t\t\t\ttextures.updateRenderTargetMipmap( _currentRenderTarget );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );\n\n\t\t\t// _gl.finish();\n\n\t\t\tbindingStates.resetDefaultState();\n\t\t\t_currentMaterialId = - 1;\n\t\t\t_currentCamera = null;\n\n\t\t\trenderStateStack.pop();\n\n\t\t\tif ( renderStateStack.length > 0 ) {\n\n\t\t\t\tcurrentRenderState = renderStateStack[ renderStateStack.length - 1 ];\n\n\t\t\t\tif ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, currentRenderState.state.camera );\n\n\t\t\t} else {\n\n\t\t\t\tcurrentRenderState = null;\n\n\t\t\t}\n\n\t\t\trenderListStack.pop();\n\n\t\t\tif ( renderListStack.length > 0 ) {\n\n\t\t\t\tcurrentRenderList = renderListStack[ renderListStack.length - 1 ];\n\n\t\t\t} else {\n\n\t\t\t\tcurrentRenderList = null;\n\n\t\t\t}\n\n\t\t};\n\n\t\tfunction projectObject( object, camera, groupOrder, sortObjects ) {\n\n\t\t\tif ( object.visible === false ) return;\n\n\t\t\tconst visible = object.layers.test( camera.layers );\n\n\t\t\tif ( visible ) {\n\n\t\t\t\tif ( object.isGroup ) {\n\n\t\t\t\t\tgroupOrder = object.renderOrder;\n\n\t\t\t\t} else if ( object.isLOD ) {\n\n\t\t\t\t\tif ( object.autoUpdate === true ) object.update( camera );\n\n\t\t\t\t} else if ( object.isLight ) {\n\n\t\t\t\t\tcurrentRenderState.pushLight( object );\n\n\t\t\t\t\tif ( object.castShadow ) {\n\n\t\t\t\t\t\tcurrentRenderState.pushShadow( object );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( object.isSprite ) {\n\n\t\t\t\t\tif ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {\n\n\t\t\t\t\t\tif ( sortObjects ) {\n\n\t\t\t\t\t\t\t_vector4.setFromMatrixPosition( object.matrixWorld )\n\t\t\t\t\t\t\t\t.applyMatrix4( _projScreenMatrix );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst geometry = objects.update( object );\n\t\t\t\t\t\tconst material = object.material;\n\n\t\t\t\t\t\tif ( material.visible ) {\n\n\t\t\t\t\t\t\tcurrentRenderList.push( object, geometry, material, groupOrder, _vector4.z, null );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( object.isMesh || object.isLine || object.isPoints ) {\n\n\t\t\t\t\tif ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {\n\n\t\t\t\t\t\tconst geometry = objects.update( object );\n\t\t\t\t\t\tconst material = object.material;\n\n\t\t\t\t\t\tif ( sortObjects ) {\n\n\t\t\t\t\t\t\tif ( object.boundingSphere !== undefined ) {\n\n\t\t\t\t\t\t\t\tif ( object.boundingSphere === null ) object.computeBoundingSphere();\n\t\t\t\t\t\t\t\t_vector4.copy( object.boundingSphere.center );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\t\t\t\t\t\t\t\t_vector4.copy( geometry.boundingSphere.center );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t_vector4\n\t\t\t\t\t\t\t\t.applyMatrix4( object.matrixWorld )\n\t\t\t\t\t\t\t\t.applyMatrix4( _projScreenMatrix );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\t\t\t\tconst groups = geometry.groups;\n\n\t\t\t\t\t\t\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\t\t\t\t\t\tconst group = groups[ i ];\n\t\t\t\t\t\t\t\tconst groupMaterial = material[ group.materialIndex ];\n\n\t\t\t\t\t\t\t\tif ( groupMaterial && groupMaterial.visible ) {\n\n\t\t\t\t\t\t\t\t\tcurrentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector4.z, group );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else if ( material.visible ) {\n\n\t\t\t\t\t\t\tcurrentRenderList.push( object, geometry, material, groupOrder, _vector4.z, null );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst children = object.children;\n\n\t\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\t\tprojectObject( children[ i ], camera, groupOrder, sortObjects );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction renderScene( currentRenderList, scene, camera, viewport ) {\n\n\t\t\tconst opaqueObjects = currentRenderList.opaque;\n\t\t\tconst transmissiveObjects = currentRenderList.transmissive;\n\t\t\tconst transparentObjects = currentRenderList.transparent;\n\n\t\t\tcurrentRenderState.setupLightsView( camera );\n\n\t\t\tif ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );\n\n\t\t\tif ( viewport ) state.viewport( _currentViewport.copy( viewport ) );\n\n\t\t\tif ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );\n\t\t\tif ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera );\n\t\t\tif ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );\n\n\t\t\t// Ensure depth buffer writing is enabled so it can be cleared on next render\n\n\t\t\tstate.buffers.depth.setTest( true );\n\t\t\tstate.buffers.depth.setMask( true );\n\t\t\tstate.buffers.color.setMask( true );\n\n\t\t\tstate.setPolygonOffset( false );\n\n\t\t}\n\n\t\tfunction renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) {\n\n\t\t\tconst overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;\n\n\t\t\tif ( overrideMaterial !== null ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( currentRenderState.state.transmissionRenderTarget[ camera.id ] === undefined ) {\n\n\t\t\t\tcurrentRenderState.state.transmissionRenderTarget[ camera.id ] = new WebGLRenderTarget( 1, 1, {\n\t\t\t\t\tgenerateMipmaps: true,\n\t\t\t\t\ttype: ( extensions.has( 'EXT_color_buffer_half_float' ) || extensions.has( 'EXT_color_buffer_float' ) ) ? HalfFloatType : UnsignedByteType,\n\t\t\t\t\tminFilter: LinearMipmapLinearFilter,\n\t\t\t\t\tsamples: 4,\n\t\t\t\t\tstencilBuffer: stencil,\n\t\t\t\t\tresolveDepthBuffer: false,\n\t\t\t\t\tresolveStencilBuffer: false,\n\t\t\t\t\tcolorSpace: ColorManagement.workingColorSpace,\n\t\t\t\t} );\n\n\t\t\t\t// debug\n\n\t\t\t\t/*\n\t\t\t\tconst geometry = new PlaneGeometry();\n\t\t\t\tconst material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } );\n\n\t\t\t\tconst mesh = new Mesh( geometry, material );\n\t\t\t\tscene.add( mesh );\n\t\t\t\t*/\n\n\t\t\t}\n\n\t\t\tconst transmissionRenderTarget = currentRenderState.state.transmissionRenderTarget[ camera.id ];\n\n\t\t\tconst activeViewport = camera.viewport || _currentViewport;\n\t\t\ttransmissionRenderTarget.setSize( activeViewport.z, activeViewport.w );\n\n\t\t\t//\n\n\t\t\tconst currentRenderTarget = _this.getRenderTarget();\n\t\t\t_this.setRenderTarget( transmissionRenderTarget );\n\n\t\t\t_this.getClearColor( _currentClearColor );\n\t\t\t_currentClearAlpha = _this.getClearAlpha();\n\t\t\tif ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 );\n\n\t\t\tif ( _renderBackground ) {\n\n\t\t\t\tbackground.render( scene );\n\n\t\t\t} else {\n\n\t\t\t\t_this.clear();\n\n\t\t\t}\n\n\t\t\t// Turn off the features which can affect the frag color for opaque objects pass.\n\t\t\t// Otherwise they are applied twice in opaque objects pass and transmission objects pass.\n\t\t\tconst currentToneMapping = _this.toneMapping;\n\t\t\t_this.toneMapping = NoToneMapping;\n\n\t\t\t// Remove viewport from camera to avoid nested render calls resetting viewport to it (e.g Reflector).\n\t\t\t// Transmission render pass requires viewport to match the transmissionRenderTarget.\n\t\t\tconst currentCameraViewport = camera.viewport;\n\t\t\tif ( camera.viewport !== undefined ) camera.viewport = undefined;\n\n\t\t\tcurrentRenderState.setupLightsView( camera );\n\n\t\t\tif ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );\n\n\t\t\trenderObjects( opaqueObjects, scene, camera );\n\n\t\t\ttextures.updateMultisampleRenderTarget( transmissionRenderTarget );\n\t\t\ttextures.updateRenderTargetMipmap( transmissionRenderTarget );\n\n\t\t\tif ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === false ) { // see #28131\n\n\t\t\t\tlet renderTargetNeedsUpdate = false;\n\n\t\t\t\tfor ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) {\n\n\t\t\t\t\tconst renderItem = transmissiveObjects[ i ];\n\n\t\t\t\t\tconst object = renderItem.object;\n\t\t\t\t\tconst geometry = renderItem.geometry;\n\t\t\t\t\tconst material = renderItem.material;\n\t\t\t\t\tconst group = renderItem.group;\n\n\t\t\t\t\tif ( material.side === DoubleSide && object.layers.test( camera.layers ) ) {\n\n\t\t\t\t\t\tconst currentSide = material.side;\n\n\t\t\t\t\t\tmaterial.side = BackSide;\n\t\t\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t\t\t\trenderObject( object, scene, camera, geometry, material, group );\n\n\t\t\t\t\t\tmaterial.side = currentSide;\n\t\t\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t\t\t\trenderTargetNeedsUpdate = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( renderTargetNeedsUpdate === true ) {\n\n\t\t\t\t\ttextures.updateMultisampleRenderTarget( transmissionRenderTarget );\n\t\t\t\t\ttextures.updateRenderTargetMipmap( transmissionRenderTarget );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_this.setRenderTarget( currentRenderTarget );\n\n\t\t\t_this.setClearColor( _currentClearColor, _currentClearAlpha );\n\n\t\t\tif ( currentCameraViewport !== undefined ) camera.viewport = currentCameraViewport;\n\n\t\t\t_this.toneMapping = currentToneMapping;\n\n\t\t}\n\n\t\tfunction renderObjects( renderList, scene, camera ) {\n\n\t\t\tconst overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;\n\n\t\t\tfor ( let i = 0, l = renderList.length; i < l; i ++ ) {\n\n\t\t\t\tconst renderItem = renderList[ i ];\n\n\t\t\t\tconst object = renderItem.object;\n\t\t\t\tconst geometry = renderItem.geometry;\n\t\t\t\tconst material = overrideMaterial === null ? renderItem.material : overrideMaterial;\n\t\t\t\tconst group = renderItem.group;\n\n\t\t\t\tif ( object.layers.test( camera.layers ) ) {\n\n\t\t\t\t\trenderObject( object, scene, camera, geometry, material, group );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction renderObject( object, scene, camera, geometry, material, group ) {\n\n\t\t\tobject.onBeforeRender( _this, scene, camera, geometry, material, group );\n\n\t\t\tobject.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );\n\t\t\tobject.normalMatrix.getNormalMatrix( object.modelViewMatrix );\n\n\t\t\tif ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {\n\n\t\t\t\tmaterial.side = BackSide;\n\t\t\t\tmaterial.needsUpdate = true;\n\t\t\t\t_this.renderBufferDirect( camera, scene, geometry, material, object, group );\n\n\t\t\t\tmaterial.side = FrontSide;\n\t\t\t\tmaterial.needsUpdate = true;\n\t\t\t\t_this.renderBufferDirect( camera, scene, geometry, material, object, group );\n\n\t\t\t\tmaterial.side = DoubleSide;\n\n\t\t\t} else {\n\n\t\t\t\t_this.renderBufferDirect( camera, scene, geometry, material, object, group );\n\n\t\t\t}\n\n\t\t\tobject.onAfterRender( _this, scene, camera, geometry, material, group );\n\n\t\t}\n\n\t\tfunction getProgram( material, scene, object ) {\n\n\t\t\tif ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...\n\n\t\t\tconst materialProperties = properties.get( material );\n\n\t\t\tconst lights = currentRenderState.state.lights;\n\t\t\tconst shadowsArray = currentRenderState.state.shadowsArray;\n\n\t\t\tconst lightsStateVersion = lights.state.version;\n\n\t\t\tconst parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );\n\t\t\tconst programCacheKey = programCache.getProgramCacheKey( parameters );\n\n\t\t\tlet programs = materialProperties.programs;\n\n\t\t\t// always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change\n\n\t\t\tmaterialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;\n\t\t\tmaterialProperties.fog = scene.fog;\n\t\t\tmaterialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment );\n\t\t\tmaterialProperties.envMapRotation = ( materialProperties.environment !== null && material.envMap === null ) ? scene.environmentRotation : material.envMapRotation;\n\n\t\t\tif ( programs === undefined ) {\n\n\t\t\t\t// new material\n\n\t\t\t\tmaterial.addEventListener( 'dispose', onMaterialDispose );\n\n\t\t\t\tprograms = new Map();\n\t\t\t\tmaterialProperties.programs = programs;\n\n\t\t\t}\n\n\t\t\tlet program = programs.get( programCacheKey );\n\n\t\t\tif ( program !== undefined ) {\n\n\t\t\t\t// early out if program and light state is identical\n\n\t\t\t\tif ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) {\n\n\t\t\t\t\tupdateCommonMaterialProperties( material, parameters );\n\n\t\t\t\t\treturn program;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tparameters.uniforms = programCache.getUniforms( material );\n\n\t\t\t\tmaterial.onBeforeCompile( parameters, _this );\n\n\t\t\t\tprogram = programCache.acquireProgram( parameters, programCacheKey );\n\t\t\t\tprograms.set( programCacheKey, program );\n\n\t\t\t\tmaterialProperties.uniforms = parameters.uniforms;\n\n\t\t\t}\n\n\t\t\tconst uniforms = materialProperties.uniforms;\n\n\t\t\tif ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) {\n\n\t\t\t\tuniforms.clippingPlanes = clipping.uniform;\n\n\t\t\t}\n\n\t\t\tupdateCommonMaterialProperties( material, parameters );\n\n\t\t\t// store the light setup it was created for\n\n\t\t\tmaterialProperties.needsLights = materialNeedsLights( material );\n\t\t\tmaterialProperties.lightsStateVersion = lightsStateVersion;\n\n\t\t\tif ( materialProperties.needsLights ) {\n\n\t\t\t\t// wire up the material to this renderer's lighting state\n\n\t\t\t\tuniforms.ambientLightColor.value = lights.state.ambient;\n\t\t\t\tuniforms.lightProbe.value = lights.state.probe;\n\t\t\t\tuniforms.directionalLights.value = lights.state.directional;\n\t\t\t\tuniforms.directionalLightShadows.value = lights.state.directionalShadow;\n\t\t\t\tuniforms.spotLights.value = lights.state.spot;\n\t\t\t\tuniforms.spotLightShadows.value = lights.state.spotShadow;\n\t\t\t\tuniforms.rectAreaLights.value = lights.state.rectArea;\n\t\t\t\tuniforms.ltc_1.value = lights.state.rectAreaLTC1;\n\t\t\t\tuniforms.ltc_2.value = lights.state.rectAreaLTC2;\n\t\t\t\tuniforms.pointLights.value = lights.state.point;\n\t\t\t\tuniforms.pointLightShadows.value = lights.state.pointShadow;\n\t\t\t\tuniforms.hemisphereLights.value = lights.state.hemi;\n\n\t\t\t\tuniforms.directionalShadowMap.value = lights.state.directionalShadowMap;\n\t\t\t\tuniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;\n\t\t\t\tuniforms.spotShadowMap.value = lights.state.spotShadowMap;\n\t\t\t\tuniforms.spotLightMatrix.value = lights.state.spotLightMatrix;\n\t\t\t\tuniforms.spotLightMap.value = lights.state.spotLightMap;\n\t\t\t\tuniforms.pointShadowMap.value = lights.state.pointShadowMap;\n\t\t\t\tuniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;\n\t\t\t\t// TODO (abelnation): add area lights shadow info to uniforms\n\n\t\t\t}\n\n\t\t\tmaterialProperties.currentProgram = program;\n\t\t\tmaterialProperties.uniformsList = null;\n\n\t\t\treturn program;\n\n\t\t}\n\n\t\tfunction getUniformList( materialProperties ) {\n\n\t\t\tif ( materialProperties.uniformsList === null ) {\n\n\t\t\t\tconst progUniforms = materialProperties.currentProgram.getUniforms();\n\t\t\t\tmaterialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms );\n\n\t\t\t}\n\n\t\t\treturn materialProperties.uniformsList;\n\n\t\t}\n\n\t\tfunction updateCommonMaterialProperties( material, parameters ) {\n\n\t\t\tconst materialProperties = properties.get( material );\n\n\t\t\tmaterialProperties.outputColorSpace = parameters.outputColorSpace;\n\t\t\tmaterialProperties.batching = parameters.batching;\n\t\t\tmaterialProperties.batchingColor = parameters.batchingColor;\n\t\t\tmaterialProperties.instancing = parameters.instancing;\n\t\t\tmaterialProperties.instancingColor = parameters.instancingColor;\n\t\t\tmaterialProperties.instancingMorph = parameters.instancingMorph;\n\t\t\tmaterialProperties.skinning = parameters.skinning;\n\t\t\tmaterialProperties.morphTargets = parameters.morphTargets;\n\t\t\tmaterialProperties.morphNormals = parameters.morphNormals;\n\t\t\tmaterialProperties.morphColors = parameters.morphColors;\n\t\t\tmaterialProperties.morphTargetsCount = parameters.morphTargetsCount;\n\t\t\tmaterialProperties.numClippingPlanes = parameters.numClippingPlanes;\n\t\t\tmaterialProperties.numIntersection = parameters.numClipIntersection;\n\t\t\tmaterialProperties.vertexAlphas = parameters.vertexAlphas;\n\t\t\tmaterialProperties.vertexTangents = parameters.vertexTangents;\n\t\t\tmaterialProperties.toneMapping = parameters.toneMapping;\n\n\t\t}\n\n\t\tfunction setProgram( camera, scene, geometry, material, object ) {\n\n\t\t\tif ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...\n\n\t\t\ttextures.resetTextureUnits();\n\n\t\t\tconst fog = scene.fog;\n\t\t\tconst environment = material.isMeshStandardMaterial ? scene.environment : null;\n\t\t\tconst colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace );\n\t\t\tconst envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );\n\t\t\tconst vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4;\n\t\t\tconst vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 );\n\t\t\tconst morphTargets = !! geometry.morphAttributes.position;\n\t\t\tconst morphNormals = !! geometry.morphAttributes.normal;\n\t\t\tconst morphColors = !! geometry.morphAttributes.color;\n\n\t\t\tlet toneMapping = NoToneMapping;\n\n\t\t\tif ( material.toneMapped ) {\n\n\t\t\t\tif ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) {\n\n\t\t\t\t\ttoneMapping = _this.toneMapping;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;\n\t\t\tconst morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;\n\n\t\t\tconst materialProperties = properties.get( material );\n\t\t\tconst lights = currentRenderState.state.lights;\n\n\t\t\tif ( _clippingEnabled === true ) {\n\n\t\t\t\tif ( _localClippingEnabled === true || camera !== _currentCamera ) {\n\n\t\t\t\t\tconst useCache =\n\t\t\t\t\t\tcamera === _currentCamera &&\n\t\t\t\t\t\tmaterial.id === _currentMaterialId;\n\n\t\t\t\t\t// we might want to call this function with some ClippingGroup\n\t\t\t\t\t// object instead of the material, once it becomes feasible\n\t\t\t\t\t// (#8465, #8379)\n\t\t\t\t\tclipping.setState( material, camera, useCache );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tlet needsProgramChange = false;\n\n\t\t\tif ( material.version === materialProperties.__version ) {\n\n\t\t\t\tif ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.outputColorSpace !== colorSpace ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isBatchedMesh && materialProperties.batching === false ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( ! object.isBatchedMesh && materialProperties.batching === true ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isBatchedMesh && materialProperties.batchingColor === true && object.colorTexture === null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isBatchedMesh && materialProperties.batchingColor === false && object.colorTexture !== null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isInstancedMesh && materialProperties.instancing === false ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isSkinnedMesh && materialProperties.skinning === false ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isInstancedMesh && materialProperties.instancingMorph === true && object.morphTexture === null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isInstancedMesh && materialProperties.instancingMorph === false && object.morphTexture !== null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.envMap !== envMap ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( material.fog === true && materialProperties.fog !== fog ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.numClippingPlanes !== undefined &&\n\t\t\t\t\t( materialProperties.numClippingPlanes !== clipping.numPlanes ||\n\t\t\t\t\tmaterialProperties.numIntersection !== clipping.numIntersection ) ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.vertexAlphas !== vertexAlphas ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.vertexTangents !== vertexTangents ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.morphTargets !== morphTargets ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.morphNormals !== morphNormals ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.morphColors !== morphColors ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.toneMapping !== toneMapping ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.morphTargetsCount !== morphTargetsCount ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tneedsProgramChange = true;\n\t\t\t\tmaterialProperties.__version = material.version;\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tlet program = materialProperties.currentProgram;\n\n\t\t\tif ( needsProgramChange === true ) {\n\n\t\t\t\tprogram = getProgram( material, scene, object );\n\n\t\t\t}\n\n\t\t\tlet refreshProgram = false;\n\t\t\tlet refreshMaterial = false;\n\t\t\tlet refreshLights = false;\n\n\t\t\tconst p_uniforms = program.getUniforms(),\n\t\t\t\tm_uniforms = materialProperties.uniforms;\n\n\t\t\tif ( state.useProgram( program.program ) ) {\n\n\t\t\t\trefreshProgram = true;\n\t\t\t\trefreshMaterial = true;\n\t\t\t\trefreshLights = true;\n\n\t\t\t}\n\n\t\t\tif ( material.id !== _currentMaterialId ) {\n\n\t\t\t\t_currentMaterialId = material.id;\n\n\t\t\t\trefreshMaterial = true;\n\n\t\t\t}\n\n\t\t\tif ( refreshProgram || _currentCamera !== camera ) {\n\n\t\t\t\t// common camera uniforms\n\n\t\t\t\tp_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );\n\t\t\t\tp_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );\n\n\t\t\t\tconst uCamPos = p_uniforms.map.cameraPosition;\n\n\t\t\t\tif ( uCamPos !== undefined ) {\n\n\t\t\t\t\tuCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( capabilities.logarithmicDepthBuffer ) {\n\n\t\t\t\t\tp_uniforms.setValue( _gl, 'logDepthBufFC',\n\t\t\t\t\t\t2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );\n\n\t\t\t\t}\n\n\t\t\t\t// consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067\n\n\t\t\t\tif ( material.isMeshPhongMaterial ||\n\t\t\t\t\tmaterial.isMeshToonMaterial ||\n\t\t\t\t\tmaterial.isMeshLambertMaterial ||\n\t\t\t\t\tmaterial.isMeshBasicMaterial ||\n\t\t\t\t\tmaterial.isMeshStandardMaterial ||\n\t\t\t\t\tmaterial.isShaderMaterial ) {\n\n\t\t\t\t\tp_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );\n\n\t\t\t\t}\n\n\t\t\t\tif ( _currentCamera !== camera ) {\n\n\t\t\t\t\t_currentCamera = camera;\n\n\t\t\t\t\t// lighting uniforms depend on the camera so enforce an update\n\t\t\t\t\t// now, in case this material supports lights - or later, when\n\t\t\t\t\t// the next material that does gets activated:\n\n\t\t\t\t\trefreshMaterial = true;\t\t// set to true on material change\n\t\t\t\t\trefreshLights = true;\t\t// remains set until update done\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// skinning and morph target uniforms must be set even if material didn't change\n\t\t\t// auto-setting of texture unit for bone and morph texture must go before other textures\n\t\t\t// otherwise textures used for skinning and morphing can take over texture units reserved for other material textures\n\n\t\t\tif ( object.isSkinnedMesh ) {\n\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'bindMatrix' );\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );\n\n\t\t\t\tconst skeleton = object.skeleton;\n\n\t\t\t\tif ( skeleton ) {\n\n\t\t\t\t\tif ( skeleton.boneTexture === null ) skeleton.computeBoneTexture();\n\n\t\t\t\t\tp_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( object.isBatchedMesh ) {\n\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'batchingTexture' );\n\t\t\t\tp_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures );\n\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'batchingIdTexture' );\n\t\t\t\tp_uniforms.setValue( _gl, 'batchingIdTexture', object._indirectTexture, textures );\n\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'batchingColorTexture' );\n\t\t\t\tif ( object._colorsTexture !== null ) {\n\n\t\t\t\t\tp_uniforms.setValue( _gl, 'batchingColorTexture', object._colorsTexture, textures );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst morphAttributes = geometry.morphAttributes;\n\n\t\t\tif ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined ) ) {\n\n\t\t\t\tmorphtargets.update( object, geometry, program );\n\n\t\t\t}\n\n\t\t\tif ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {\n\n\t\t\t\tmaterialProperties.receiveShadow = object.receiveShadow;\n\t\t\t\tp_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );\n\n\t\t\t}\n\n\t\t\t// https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512\n\n\t\t\tif ( material.isMeshGouraudMaterial && material.envMap !== null ) {\n\n\t\t\t\tm_uniforms.envMap.value = envMap;\n\n\t\t\t\tm_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;\n\n\t\t\t}\n\n\t\t\tif ( material.isMeshStandardMaterial && material.envMap === null && scene.environment !== null ) {\n\n\t\t\t\tm_uniforms.envMapIntensity.value = scene.environmentIntensity;\n\n\t\t\t}\n\n\t\t\tif ( refreshMaterial ) {\n\n\t\t\t\tp_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );\n\n\t\t\t\tif ( materialProperties.needsLights ) {\n\n\t\t\t\t\t// the current material requires lighting info\n\n\t\t\t\t\t// note: all lighting uniforms are always set correctly\n\t\t\t\t\t// they simply reference the renderer's state for their\n\t\t\t\t\t// values\n\t\t\t\t\t//\n\t\t\t\t\t// use the current material's .needsUpdate flags to set\n\t\t\t\t\t// the GL state when required\n\n\t\t\t\t\tmarkUniformsLightsNeedsUpdate( m_uniforms, refreshLights );\n\n\t\t\t\t}\n\n\t\t\t\t// refresh uniforms common to several materials\n\n\t\t\t\tif ( fog && material.fog === true ) {\n\n\t\t\t\t\tmaterials.refreshFogUniforms( m_uniforms, fog );\n\n\t\t\t\t}\n\n\t\t\t\tmaterials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, currentRenderState.state.transmissionRenderTarget[ camera.id ] );\n\n\t\t\t\tWebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );\n\n\t\t\t}\n\n\t\t\tif ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {\n\n\t\t\t\tWebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );\n\t\t\t\tmaterial.uniformsNeedUpdate = false;\n\n\t\t\t}\n\n\t\t\tif ( material.isSpriteMaterial ) {\n\n\t\t\t\tp_uniforms.setValue( _gl, 'center', object.center );\n\n\t\t\t}\n\n\t\t\t// common matrices\n\n\t\t\tp_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );\n\t\t\tp_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );\n\t\t\tp_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );\n\n\t\t\t// UBOs\n\n\t\t\tif ( material.isShaderMaterial || material.isRawShaderMaterial ) {\n\n\t\t\t\tconst groups = material.uniformsGroups;\n\n\t\t\t\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\t\t\tconst group = groups[ i ];\n\n\t\t\t\t\tuniformsGroups.update( group, program );\n\t\t\t\t\tuniformsGroups.bind( group, program );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn program;\n\n\t\t}\n\n\t\t// If uniforms are marked as clean, they don't need to be loaded to the GPU.\n\n\t\tfunction markUniformsLightsNeedsUpdate( uniforms, value ) {\n\n\t\t\tuniforms.ambientLightColor.needsUpdate = value;\n\t\t\tuniforms.lightProbe.needsUpdate = value;\n\n\t\t\tuniforms.directionalLights.needsUpdate = value;\n\t\t\tuniforms.directionalLightShadows.needsUpdate = value;\n\t\t\tuniforms.pointLights.needsUpdate = value;\n\t\t\tuniforms.pointLightShadows.needsUpdate = value;\n\t\t\tuniforms.spotLights.needsUpdate = value;\n\t\t\tuniforms.spotLightShadows.needsUpdate = value;\n\t\t\tuniforms.rectAreaLights.needsUpdate = value;\n\t\t\tuniforms.hemisphereLights.needsUpdate = value;\n\n\t\t}\n\n\t\tfunction materialNeedsLights( material ) {\n\n\t\t\treturn material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||\n\t\t\t\tmaterial.isMeshStandardMaterial || material.isShadowMaterial ||\n\t\t\t\t( material.isShaderMaterial && material.lights === true );\n\n\t\t}\n\n\t\tthis.getActiveCubeFace = function () {\n\n\t\t\treturn _currentActiveCubeFace;\n\n\t\t};\n\n\t\tthis.getActiveMipmapLevel = function () {\n\n\t\t\treturn _currentActiveMipmapLevel;\n\n\t\t};\n\n\t\tthis.getRenderTarget = function () {\n\n\t\t\treturn _currentRenderTarget;\n\n\t\t};\n\n\t\tthis.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) {\n\n\t\t\tproperties.get( renderTarget.texture ).__webglTexture = colorTexture;\n\t\t\tproperties.get( renderTarget.depthTexture ).__webglTexture = depthTexture;\n\n\t\t\tconst renderTargetProperties = properties.get( renderTarget );\n\t\t\trenderTargetProperties.__hasExternalTextures = true;\n\n\t\t\trenderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined;\n\n\t\t\tif ( ! renderTargetProperties.__autoAllocateDepthBuffer ) {\n\n\t\t\t\t// The multisample_render_to_texture extension doesn't work properly if there\n\t\t\t\t// are midframe flushes and an external depth buffer. Disable use of the extension.\n\t\t\t\tif ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' );\n\t\t\t\t\trenderTargetProperties.__useRenderToTexture = false;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) {\n\n\t\t\tconst renderTargetProperties = properties.get( renderTarget );\n\t\t\trenderTargetProperties.__webglFramebuffer = defaultFramebuffer;\n\t\t\trenderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined;\n\n\t\t};\n\n\t\tthis.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {\n\n\t\t\t_currentRenderTarget = renderTarget;\n\t\t\t_currentActiveCubeFace = activeCubeFace;\n\t\t\t_currentActiveMipmapLevel = activeMipmapLevel;\n\n\t\t\tlet useDefaultFramebuffer = true;\n\t\t\tlet framebuffer = null;\n\t\t\tlet isCube = false;\n\t\t\tlet isRenderTarget3D = false;\n\n\t\t\tif ( renderTarget ) {\n\n\t\t\t\tconst renderTargetProperties = properties.get( renderTarget );\n\n\t\t\t\tif ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) {\n\n\t\t\t\t\t// We need to make sure to rebind the framebuffer.\n\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\t\t\t\t\tuseDefaultFramebuffer = false;\n\n\t\t\t\t} else if ( renderTargetProperties.__webglFramebuffer === undefined ) {\n\n\t\t\t\t\ttextures.setupRenderTarget( renderTarget );\n\n\t\t\t\t} else if ( renderTargetProperties.__hasExternalTextures ) {\n\n\t\t\t\t\t// Color and depth texture must be rebound in order for the swapchain to update.\n\t\t\t\t\ttextures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture );\n\n\t\t\t\t}\n\n\t\t\t\tconst texture = renderTarget.texture;\n\n\t\t\t\tif ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {\n\n\t\t\t\t\tisRenderTarget3D = true;\n\n\t\t\t\t}\n\n\t\t\t\tconst __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;\n\n\t\t\t\tif ( renderTarget.isWebGLCubeRenderTarget ) {\n\n\t\t\t\t\tif ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) {\n\n\t\t\t\t\t\tframebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ];\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tframebuffer = __webglFramebuffer[ activeCubeFace ];\n\n\t\t\t\t\t}\n\n\t\t\t\t\tisCube = true;\n\n\t\t\t\t} else if ( ( renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) {\n\n\t\t\t\t\tframebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( Array.isArray( __webglFramebuffer ) ) {\n\n\t\t\t\t\t\tframebuffer = __webglFramebuffer[ activeMipmapLevel ];\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tframebuffer = __webglFramebuffer;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t_currentViewport.copy( renderTarget.viewport );\n\t\t\t\t_currentScissor.copy( renderTarget.scissor );\n\t\t\t\t_currentScissorTest = renderTarget.scissorTest;\n\n\t\t\t} else {\n\n\t\t\t\t_currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();\n\t\t\t\t_currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();\n\t\t\t\t_currentScissorTest = _scissorTest;\n\n\t\t\t}\n\n\t\t\tconst framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\tif ( framebufferBound && useDefaultFramebuffer ) {\n\n\t\t\t\tstate.drawBuffers( renderTarget, framebuffer );\n\n\t\t\t}\n\n\t\t\tstate.viewport( _currentViewport );\n\t\t\tstate.scissor( _currentScissor );\n\t\t\tstate.setScissorTest( _currentScissorTest );\n\n\t\t\tif ( isCube ) {\n\n\t\t\t\tconst textureProperties = properties.get( renderTarget.texture );\n\t\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );\n\n\t\t\t} else if ( isRenderTarget3D ) {\n\n\t\t\t\tconst textureProperties = properties.get( renderTarget.texture );\n\t\t\t\tconst layer = activeCubeFace || 0;\n\t\t\t\t_gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer );\n\n\t\t\t}\n\n\t\t\t_currentMaterialId = - 1; // reset current material to ensure correct uniform bindings\n\n\t\t};\n\n\t\tthis.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {\n\n\t\t\tif ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tlet framebuffer = properties.get( renderTarget ).__webglFramebuffer;\n\n\t\t\tif ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {\n\n\t\t\t\tframebuffer = framebuffer[ activeCubeFaceIndex ];\n\n\t\t\t}\n\n\t\t\tif ( framebuffer ) {\n\n\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\t\ttry {\n\n\t\t\t\t\tconst texture = renderTarget.texture;\n\t\t\t\t\tconst textureFormat = texture.format;\n\t\t\t\t\tconst textureType = texture.type;\n\n\t\t\t\t\tif ( ! capabilities.textureFormatReadable( textureFormat ) ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! capabilities.textureTypeReadable( textureType ) ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)\n\n\t\t\t\t\tif ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {\n\n\t\t\t\t\t\t_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );\n\n\t\t\t\t\t}\n\n\t\t\t\t} finally {\n\n\t\t\t\t\t// restore framebuffer of current render target if necessary\n\n\t\t\t\t\tconst framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;\n\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.readRenderTargetPixelsAsync = async function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {\n\n\t\t\tif ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {\n\n\t\t\t\tthrow new Error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );\n\n\t\t\t}\n\n\t\t\tlet framebuffer = properties.get( renderTarget ).__webglFramebuffer;\n\t\t\tif ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {\n\n\t\t\t\tframebuffer = framebuffer[ activeCubeFaceIndex ];\n\n\t\t\t}\n\n\t\t\tif ( framebuffer ) {\n\n\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\t\ttry {\n\n\t\t\t\t\tconst texture = renderTarget.texture;\n\t\t\t\t\tconst textureFormat = texture.format;\n\t\t\t\t\tconst textureType = texture.type;\n\n\t\t\t\t\tif ( ! capabilities.textureFormatReadable( textureFormat ) ) {\n\n\t\t\t\t\t\tthrow new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! capabilities.textureTypeReadable( textureType ) ) {\n\n\t\t\t\t\t\tthrow new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)\n\t\t\t\t\tif ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {\n\n\t\t\t\t\t\tconst glBuffer = _gl.createBuffer();\n\t\t\t\t\t\t_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );\n\t\t\t\t\t\t_gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );\n\t\t\t\t\t\t_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );\n\t\t\t\t\t\t_gl.flush();\n\n\t\t\t\t\t\t// check if the commands have finished every 8 ms\n\t\t\t\t\t\tconst sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );\n\t\t\t\t\t\tawait probeAsync( _gl, sync, 4 );\n\n\t\t\t\t\t\ttry {\n\n\t\t\t\t\t\t\t_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );\n\t\t\t\t\t\t\t_gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer );\n\n\t\t\t\t\t\t} finally {\n\n\t\t\t\t\t\t\t_gl.deleteBuffer( glBuffer );\n\t\t\t\t\t\t\t_gl.deleteSync( sync );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn buffer;\n\n\t\t\t\t\t}\n\n\t\t\t\t} finally {\n\n\t\t\t\t\t// restore framebuffer of current render target if necessary\n\n\t\t\t\t\tconst framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;\n\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.copyFramebufferToTexture = function ( texture, position = null, level = 0 ) {\n\n\t\t\t// support previous signature with position first\n\t\t\tif ( texture.isTexture !== true ) {\n\n\t\t\t\t// @deprecated, r165\n\t\t\t\tconsole.warn( 'WebGLRenderer: copyFramebufferToTexture function signature has changed.' );\n\n\t\t\t\tposition = arguments[ 0 ] || null;\n\t\t\t\ttexture = arguments[ 1 ];\n\n\t\t\t}\n\n\t\t\tconst levelScale = Math.pow( 2, - level );\n\t\t\tconst width = Math.floor( texture.image.width * levelScale );\n\t\t\tconst height = Math.floor( texture.image.height * levelScale );\n\n\t\t\tconst x = position !== null ? position.x : 0;\n\t\t\tconst y = position !== null ? position.y : 0;\n\n\t\t\ttextures.setTexture2D( texture, 0 );\n\n\t\t\t_gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, x, y, width, height );\n\n\t\t\tstate.unbindTexture();\n\n\t\t};\n\n\t\tthis.copyTextureToTexture = function ( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {\n\n\t\t\t// support previous signature with dstPosition first\n\t\t\tif ( srcTexture.isTexture !== true ) {\n\n\t\t\t\t// @deprecated, r165\n\t\t\t\tconsole.warn( 'WebGLRenderer: copyTextureToTexture function signature has changed.' );\n\n\t\t\t\tdstPosition = arguments[ 0 ] || null;\n\t\t\t\tsrcTexture = arguments[ 1 ];\n\t\t\t\tdstTexture = arguments[ 2 ];\n\t\t\t\tlevel = arguments[ 3 ] || 0;\n\t\t\t\tsrcRegion = null;\n\n\t\t\t}\n\n\t\t\tlet width, height, minX, minY;\n\t\t\tlet dstX, dstY;\n\t\t\tif ( srcRegion !== null ) {\n\n\t\t\t\twidth = srcRegion.max.x - srcRegion.min.x;\n\t\t\t\theight = srcRegion.max.y - srcRegion.min.y;\n\t\t\t\tminX = srcRegion.min.x;\n\t\t\t\tminY = srcRegion.min.y;\n\n\t\t\t} else {\n\n\t\t\t\twidth = srcTexture.image.width;\n\t\t\t\theight = srcTexture.image.height;\n\t\t\t\tminX = 0;\n\t\t\t\tminY = 0;\n\n\t\t\t}\n\n\t\t\tif ( dstPosition !== null ) {\n\n\t\t\t\tdstX = dstPosition.x;\n\t\t\t\tdstY = dstPosition.y;\n\n\t\t\t} else {\n\n\t\t\t\tdstX = 0;\n\t\t\t\tdstY = 0;\n\n\t\t\t}\n\n\t\t\tconst glFormat = utils.convert( dstTexture.format );\n\t\t\tconst glType = utils.convert( dstTexture.type );\n\n\t\t\ttextures.setTexture2D( dstTexture, 0 );\n\n\t\t\t// As another texture upload may have changed pixelStorei\n\t\t\t// parameters, make sure they are correct for the dstTexture\n\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );\n\n\t\t\tconst currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );\n\t\t\tconst currentUnpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );\n\t\t\tconst currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );\n\t\t\tconst currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );\n\t\t\tconst currentUnpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );\n\n\t\t\tconst image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, minX );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY );\n\n\t\t\tif ( srcTexture.isDataTexture ) {\n\n\t\t\t\t_gl.texSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image.data );\n\n\t\t\t} else {\n\n\t\t\t\tif ( srcTexture.isCompressedTexture ) {\n\n\t\t\t\t\t_gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, image.width, image.height, glFormat, image.data );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_gl.texSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages );\n\n\t\t\t// Generate mipmaps only when copying level 0\n\t\t\tif ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D );\n\n\t\t\tstate.unbindTexture();\n\n\t\t};\n\n\t\tthis.copyTextureToTexture3D = function ( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {\n\n\t\t\t// support previous signature with source box first\n\t\t\tif ( srcTexture.isTexture !== true ) {\n\n\t\t\t\t// @deprecated, r165\n\t\t\t\tconsole.warn( 'WebGLRenderer: copyTextureToTexture3D function signature has changed.' );\n\n\t\t\t\tsrcRegion = arguments[ 0 ] || null;\n\t\t\t\tdstPosition = arguments[ 1 ] || null;\n\t\t\t\tsrcTexture = arguments[ 2 ];\n\t\t\t\tdstTexture = arguments[ 3 ];\n\t\t\t\tlevel = arguments[ 4 ] || 0;\n\n\t\t\t}\n\n\t\t\tlet width, height, depth, minX, minY, minZ;\n\t\t\tlet dstX, dstY, dstZ;\n\t\t\tconst image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;\n\t\t\tif ( srcRegion !== null ) {\n\n\t\t\t\twidth = srcRegion.max.x - srcRegion.min.x;\n\t\t\t\theight = srcRegion.max.y - srcRegion.min.y;\n\t\t\t\tdepth = srcRegion.max.z - srcRegion.min.z;\n\t\t\t\tminX = srcRegion.min.x;\n\t\t\t\tminY = srcRegion.min.y;\n\t\t\t\tminZ = srcRegion.min.z;\n\n\t\t\t} else {\n\n\t\t\t\twidth = image.width;\n\t\t\t\theight = image.height;\n\t\t\t\tdepth = image.depth;\n\t\t\t\tminX = 0;\n\t\t\t\tminY = 0;\n\t\t\t\tminZ = 0;\n\n\t\t\t}\n\n\t\t\tif ( dstPosition !== null ) {\n\n\t\t\t\tdstX = dstPosition.x;\n\t\t\t\tdstY = dstPosition.y;\n\t\t\t\tdstZ = dstPosition.z;\n\n\t\t\t} else {\n\n\t\t\t\tdstX = 0;\n\t\t\t\tdstY = 0;\n\t\t\t\tdstZ = 0;\n\n\t\t\t}\n\n\t\t\tconst glFormat = utils.convert( dstTexture.format );\n\t\t\tconst glType = utils.convert( dstTexture.type );\n\t\t\tlet glTarget;\n\n\t\t\tif ( dstTexture.isData3DTexture ) {\n\n\t\t\t\ttextures.setTexture3D( dstTexture, 0 );\n\t\t\t\tglTarget = _gl.TEXTURE_3D;\n\n\t\t\t} else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) {\n\n\t\t\t\ttextures.setTexture2DArray( dstTexture, 0 );\n\t\t\t\tglTarget = _gl.TEXTURE_2D_ARRAY;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );\n\n\t\t\tconst currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );\n\t\t\tconst currentUnpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );\n\t\t\tconst currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );\n\t\t\tconst currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );\n\t\t\tconst currentUnpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, minX );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, minZ );\n\n\t\t\tif ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) {\n\n\t\t\t\t_gl.texSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image.data );\n\n\t\t\t} else {\n\n\t\t\t\tif ( dstTexture.isCompressedArrayTexture ) {\n\n\t\t\t\t\t_gl.compressedTexSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, image.data );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_gl.texSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages );\n\n\t\t\t// Generate mipmaps only when copying level 0\n\t\t\tif ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget );\n\n\t\t\tstate.unbindTexture();\n\n\t\t};\n\n\t\tthis.initRenderTarget = function ( target ) {\n\n\t\t\tif ( properties.get( target ).__webglFramebuffer === undefined ) {\n\n\t\t\t\ttextures.setupRenderTarget( target );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.initTexture = function ( texture ) {\n\n\t\t\tif ( texture.isCubeTexture ) {\n\n\t\t\t\ttextures.setTextureCube( texture, 0 );\n\n\t\t\t} else if ( texture.isData3DTexture ) {\n\n\t\t\t\ttextures.setTexture3D( texture, 0 );\n\n\t\t\t} else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {\n\n\t\t\t\ttextures.setTexture2DArray( texture, 0 );\n\n\t\t\t} else {\n\n\t\t\t\ttextures.setTexture2D( texture, 0 );\n\n\t\t\t}\n\n\t\t\tstate.unbindTexture();\n\n\t\t};\n\n\t\tthis.resetState = function () {\n\n\t\t\t_currentActiveCubeFace = 0;\n\t\t\t_currentActiveMipmapLevel = 0;\n\t\t\t_currentRenderTarget = null;\n\n\t\t\tstate.reset();\n\t\t\tbindingStates.reset();\n\n\t\t};\n\n\t\tif ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {\n\n\t\t\t__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );\n\n\t\t}\n\n\t}\n\n\tget coordinateSystem() {\n\n\t\treturn WebGLCoordinateSystem;\n\n\t}\n\n\tget outputColorSpace() {\n\n\t\treturn this._outputColorSpace;\n\n\t}\n\n\tset outputColorSpace( colorSpace ) {\n\n\t\tthis._outputColorSpace = colorSpace;\n\n\t\tconst gl = this.getContext();\n\t\tgl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb';\n\t\tgl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb';\n\n\t}\n\n}\n\nclass FogExp2 {\n\n\tconstructor( color, density = 0.00025 ) {\n\n\t\tthis.isFogExp2 = true;\n\n\t\tthis.name = '';\n\n\t\tthis.color = new Color( color );\n\t\tthis.density = density;\n\n\t}\n\n\tclone() {\n\n\t\treturn new FogExp2( this.color, this.density );\n\n\t}\n\n\ttoJSON( /* meta */ ) {\n\n\t\treturn {\n\t\t\ttype: 'FogExp2',\n\t\t\tname: this.name,\n\t\t\tcolor: this.color.getHex(),\n\t\t\tdensity: this.density\n\t\t};\n\n\t}\n\n}\n\nclass Fog {\n\n\tconstructor( color, near = 1, far = 1000 ) {\n\n\t\tthis.isFog = true;\n\n\t\tthis.name = '';\n\n\t\tthis.color = new Color( color );\n\n\t\tthis.near = near;\n\t\tthis.far = far;\n\n\t}\n\n\tclone() {\n\n\t\treturn new Fog( this.color, this.near, this.far );\n\n\t}\n\n\ttoJSON( /* meta */ ) {\n\n\t\treturn {\n\t\t\ttype: 'Fog',\n\t\t\tname: this.name,\n\t\t\tcolor: this.color.getHex(),\n\t\t\tnear: this.near,\n\t\t\tfar: this.far\n\t\t};\n\n\t}\n\n}\n\nclass Scene extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isScene = true;\n\n\t\tthis.type = 'Scene';\n\n\t\tthis.background = null;\n\t\tthis.environment = null;\n\t\tthis.fog = null;\n\n\t\tthis.backgroundBlurriness = 0;\n\t\tthis.backgroundIntensity = 1;\n\t\tthis.backgroundRotation = new Euler();\n\n\t\tthis.environmentIntensity = 1;\n\t\tthis.environmentRotation = new Euler();\n\n\t\tthis.overrideMaterial = null;\n\n\t\tif ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {\n\n\t\t\t__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );\n\n\t\t}\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tif ( source.background !== null ) this.background = source.background.clone();\n\t\tif ( source.environment !== null ) this.environment = source.environment.clone();\n\t\tif ( source.fog !== null ) this.fog = source.fog.clone();\n\n\t\tthis.backgroundBlurriness = source.backgroundBlurriness;\n\t\tthis.backgroundIntensity = source.backgroundIntensity;\n\t\tthis.backgroundRotation.copy( source.backgroundRotation );\n\n\t\tthis.environmentIntensity = source.environmentIntensity;\n\t\tthis.environmentRotation.copy( source.environmentRotation );\n\n\t\tif ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();\n\n\t\tthis.matrixAutoUpdate = source.matrixAutoUpdate;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tif ( this.fog !== null ) data.object.fog = this.fog.toJSON();\n\n\t\tif ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness;\n\t\tif ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity;\n\t\tdata.object.backgroundRotation = this.backgroundRotation.toArray();\n\n\t\tif ( this.environmentIntensity !== 1 ) data.object.environmentIntensity = this.environmentIntensity;\n\t\tdata.object.environmentRotation = this.environmentRotation.toArray();\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass InterleavedBuffer {\n\n\tconstructor( array, stride ) {\n\n\t\tthis.isInterleavedBuffer = true;\n\n\t\tthis.array = array;\n\t\tthis.stride = stride;\n\t\tthis.count = array !== undefined ? array.length / stride : 0;\n\n\t\tthis.usage = StaticDrawUsage;\n\t\tthis._updateRange = { offset: 0, count: - 1 };\n\t\tthis.updateRanges = [];\n\n\t\tthis.version = 0;\n\n\t\tthis.uuid = generateUUID();\n\n\t}\n\n\tonUploadCallback() {}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t}\n\n\tget updateRange() {\n\n\t\twarnOnce( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159\n\t\treturn this._updateRange;\n\n\t}\n\n\tsetUsage( value ) {\n\n\t\tthis.usage = value;\n\n\t\treturn this;\n\n\t}\n\n\taddUpdateRange( start, count ) {\n\n\t\tthis.updateRanges.push( { start, count } );\n\n\t}\n\n\tclearUpdateRanges() {\n\n\t\tthis.updateRanges.length = 0;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.array = new source.array.constructor( source.array );\n\t\tthis.count = source.count;\n\t\tthis.stride = source.stride;\n\t\tthis.usage = source.usage;\n\n\t\treturn this;\n\n\t}\n\n\tcopyAt( index1, attribute, index2 ) {\n\n\t\tindex1 *= this.stride;\n\t\tindex2 *= attribute.stride;\n\n\t\tfor ( let i = 0, l = this.stride; i < l; i ++ ) {\n\n\t\t\tthis.array[ index1 + i ] = attribute.array[ index2 + i ];\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tset( value, offset = 0 ) {\n\n\t\tthis.array.set( value, offset );\n\n\t\treturn this;\n\n\t}\n\n\tclone( data ) {\n\n\t\tif ( data.arrayBuffers === undefined ) {\n\n\t\t\tdata.arrayBuffers = {};\n\n\t\t}\n\n\t\tif ( this.array.buffer._uuid === undefined ) {\n\n\t\t\tthis.array.buffer._uuid = generateUUID();\n\n\t\t}\n\n\t\tif ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {\n\n\t\t\tdata.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer;\n\n\t\t}\n\n\t\tconst array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] );\n\n\t\tconst ib = new this.constructor( array, this.stride );\n\t\tib.setUsage( this.usage );\n\n\t\treturn ib;\n\n\t}\n\n\tonUpload( callback ) {\n\n\t\tthis.onUploadCallback = callback;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( data ) {\n\n\t\tif ( data.arrayBuffers === undefined ) {\n\n\t\t\tdata.arrayBuffers = {};\n\n\t\t}\n\n\t\t// generate UUID for array buffer if necessary\n\n\t\tif ( this.array.buffer._uuid === undefined ) {\n\n\t\t\tthis.array.buffer._uuid = generateUUID();\n\n\t\t}\n\n\t\tif ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {\n\n\t\t\tdata.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) );\n\n\t\t}\n\n\t\t//\n\n\t\treturn {\n\t\t\tuuid: this.uuid,\n\t\t\tbuffer: this.array.buffer._uuid,\n\t\t\ttype: this.array.constructor.name,\n\t\t\tstride: this.stride\n\t\t};\n\n\t}\n\n}\n\nconst _vector$6 = /*@__PURE__*/ new Vector3();\n\nclass InterleavedBufferAttribute {\n\n\tconstructor( interleavedBuffer, itemSize, offset, normalized = false ) {\n\n\t\tthis.isInterleavedBufferAttribute = true;\n\n\t\tthis.name = '';\n\n\t\tthis.data = interleavedBuffer;\n\t\tthis.itemSize = itemSize;\n\t\tthis.offset = offset;\n\n\t\tthis.normalized = normalized;\n\n\t}\n\n\tget count() {\n\n\t\treturn this.data.count;\n\n\t}\n\n\tget array() {\n\n\t\treturn this.data.array;\n\n\t}\n\n\tset needsUpdate( value ) {\n\n\t\tthis.data.needsUpdate = value;\n\n\t}\n\n\tapplyMatrix4( m ) {\n\n\t\tfor ( let i = 0, l = this.data.count; i < l; i ++ ) {\n\n\t\t\t_vector$6.fromBufferAttribute( this, i );\n\n\t\t\t_vector$6.applyMatrix4( m );\n\n\t\t\tthis.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tapplyNormalMatrix( m ) {\n\n\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t_vector$6.fromBufferAttribute( this, i );\n\n\t\t\t_vector$6.applyNormalMatrix( m );\n\n\t\t\tthis.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttransformDirection( m ) {\n\n\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t_vector$6.fromBufferAttribute( this, i );\n\n\t\t\t_vector$6.transformDirection( m );\n\n\t\t\tthis.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetComponent( index, component ) {\n\n\t\tlet value = this.array[ index * this.data.stride + this.offset + component ];\n\n\t\tif ( this.normalized ) value = denormalize( value, this.array );\n\n\t\treturn value;\n\n\t}\n\n\tsetComponent( index, component, value ) {\n\n\t\tif ( this.normalized ) value = normalize( value, this.array );\n\n\t\tthis.data.array[ index * this.data.stride + this.offset + component ] = value;\n\n\t\treturn this;\n\n\t}\n\n\tsetX( index, x ) {\n\n\t\tif ( this.normalized ) x = normalize( x, this.array );\n\n\t\tthis.data.array[ index * this.data.stride + this.offset ] = x;\n\n\t\treturn this;\n\n\t}\n\n\tsetY( index, y ) {\n\n\t\tif ( this.normalized ) y = normalize( y, this.array );\n\n\t\tthis.data.array[ index * this.data.stride + this.offset + 1 ] = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetZ( index, z ) {\n\n\t\tif ( this.normalized ) z = normalize( z, this.array );\n\n\t\tthis.data.array[ index * this.data.stride + this.offset + 2 ] = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetW( index, w ) {\n\n\t\tif ( this.normalized ) w = normalize( w, this.array );\n\n\t\tthis.data.array[ index * this.data.stride + this.offset + 3 ] = w;\n\n\t\treturn this;\n\n\t}\n\n\tgetX( index ) {\n\n\t\tlet x = this.data.array[ index * this.data.stride + this.offset ];\n\n\t\tif ( this.normalized ) x = denormalize( x, this.array );\n\n\t\treturn x;\n\n\t}\n\n\tgetY( index ) {\n\n\t\tlet y = this.data.array[ index * this.data.stride + this.offset + 1 ];\n\n\t\tif ( this.normalized ) y = denormalize( y, this.array );\n\n\t\treturn y;\n\n\t}\n\n\tgetZ( index ) {\n\n\t\tlet z = this.data.array[ index * this.data.stride + this.offset + 2 ];\n\n\t\tif ( this.normalized ) z = denormalize( z, this.array );\n\n\t\treturn z;\n\n\t}\n\n\tgetW( index ) {\n\n\t\tlet w = this.data.array[ index * this.data.stride + this.offset + 3 ];\n\n\t\tif ( this.normalized ) w = denormalize( w, this.array );\n\n\t\treturn w;\n\n\t}\n\n\tsetXY( index, x, y ) {\n\n\t\tindex = index * this.data.stride + this.offset;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\n\t\t}\n\n\t\tthis.data.array[ index + 0 ] = x;\n\t\tthis.data.array[ index + 1 ] = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZ( index, x, y, z ) {\n\n\t\tindex = index * this.data.stride + this.offset;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\n\t\t}\n\n\t\tthis.data.array[ index + 0 ] = x;\n\t\tthis.data.array[ index + 1 ] = y;\n\t\tthis.data.array[ index + 2 ] = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZW( index, x, y, z, w ) {\n\n\t\tindex = index * this.data.stride + this.offset;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\t\t\tw = normalize( w, this.array );\n\n\t\t}\n\n\t\tthis.data.array[ index + 0 ] = x;\n\t\tthis.data.array[ index + 1 ] = y;\n\t\tthis.data.array[ index + 2 ] = z;\n\t\tthis.data.array[ index + 3 ] = w;\n\n\t\treturn this;\n\n\t}\n\n\tclone( data ) {\n\n\t\tif ( data === undefined ) {\n\n\t\t\tconsole.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' );\n\n\t\t\tconst array = [];\n\n\t\t\tfor ( let i = 0; i < this.count; i ++ ) {\n\n\t\t\t\tconst index = i * this.data.stride + this.offset;\n\n\t\t\t\tfor ( let j = 0; j < this.itemSize; j ++ ) {\n\n\t\t\t\t\tarray.push( this.data.array[ index + j ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );\n\n\t\t} else {\n\n\t\t\tif ( data.interleavedBuffers === undefined ) {\n\n\t\t\t\tdata.interleavedBuffers = {};\n\n\t\t\t}\n\n\t\t\tif ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {\n\n\t\t\t\tdata.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );\n\n\t\t\t}\n\n\t\t\treturn new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );\n\n\t\t}\n\n\t}\n\n\ttoJSON( data ) {\n\n\t\tif ( data === undefined ) {\n\n\t\t\tconsole.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' );\n\n\t\t\tconst array = [];\n\n\t\t\tfor ( let i = 0; i < this.count; i ++ ) {\n\n\t\t\t\tconst index = i * this.data.stride + this.offset;\n\n\t\t\t\tfor ( let j = 0; j < this.itemSize; j ++ ) {\n\n\t\t\t\t\tarray.push( this.data.array[ index + j ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// de-interleave data and save it as an ordinary buffer attribute for now\n\n\t\t\treturn {\n\t\t\t\titemSize: this.itemSize,\n\t\t\t\ttype: this.array.constructor.name,\n\t\t\t\tarray: array,\n\t\t\t\tnormalized: this.normalized\n\t\t\t};\n\n\t\t} else {\n\n\t\t\t// save as true interleaved attribute\n\n\t\t\tif ( data.interleavedBuffers === undefined ) {\n\n\t\t\t\tdata.interleavedBuffers = {};\n\n\t\t\t}\n\n\t\t\tif ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {\n\n\t\t\t\tdata.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );\n\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tisInterleavedBufferAttribute: true,\n\t\t\t\titemSize: this.itemSize,\n\t\t\t\tdata: this.data.uuid,\n\t\t\t\toffset: this.offset,\n\t\t\t\tnormalized: this.normalized\n\t\t\t};\n\n\t\t}\n\n\t}\n\n}\n\nclass SpriteMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isSpriteMaterial = true;\n\n\t\tthis.type = 'SpriteMaterial';\n\n\t\tthis.color = new Color( 0xffffff );\n\n\t\tthis.map = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.rotation = 0;\n\n\t\tthis.sizeAttenuation = true;\n\n\t\tthis.transparent = true;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.rotation = source.rotation;\n\n\t\tthis.sizeAttenuation = source.sizeAttenuation;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nlet _geometry;\n\nconst _intersectPoint = /*@__PURE__*/ new Vector3();\nconst _worldScale = /*@__PURE__*/ new Vector3();\nconst _mvPosition = /*@__PURE__*/ new Vector3();\n\nconst _alignedPosition = /*@__PURE__*/ new Vector2();\nconst _rotatedPosition = /*@__PURE__*/ new Vector2();\nconst _viewWorldMatrix = /*@__PURE__*/ new Matrix4();\n\nconst _vA = /*@__PURE__*/ new Vector3();\nconst _vB = /*@__PURE__*/ new Vector3();\nconst _vC = /*@__PURE__*/ new Vector3();\n\nconst _uvA = /*@__PURE__*/ new Vector2();\nconst _uvB = /*@__PURE__*/ new Vector2();\nconst _uvC = /*@__PURE__*/ new Vector2();\n\nclass Sprite extends Object3D {\n\n\tconstructor( material = new SpriteMaterial() ) {\n\n\t\tsuper();\n\n\t\tthis.isSprite = true;\n\n\t\tthis.type = 'Sprite';\n\n\t\tif ( _geometry === undefined ) {\n\n\t\t\t_geometry = new BufferGeometry();\n\n\t\t\tconst float32Array = new Float32Array( [\n\t\t\t\t- 0.5, - 0.5, 0, 0, 0,\n\t\t\t\t0.5, - 0.5, 0, 1, 0,\n\t\t\t\t0.5, 0.5, 0, 1, 1,\n\t\t\t\t- 0.5, 0.5, 0, 0, 1\n\t\t\t] );\n\n\t\t\tconst interleavedBuffer = new InterleavedBuffer( float32Array, 5 );\n\n\t\t\t_geometry.setIndex( [ 0, 1, 2,\t0, 2, 3 ] );\n\t\t\t_geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );\n\t\t\t_geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );\n\n\t\t}\n\n\t\tthis.geometry = _geometry;\n\t\tthis.material = material;\n\n\t\tthis.center = new Vector2( 0.5, 0.5 );\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tif ( raycaster.camera === null ) {\n\n\t\t\tconsole.error( 'THREE.Sprite: \"Raycaster.camera\" needs to be set in order to raycast against sprites.' );\n\n\t\t}\n\n\t\t_worldScale.setFromMatrixScale( this.matrixWorld );\n\n\t\t_viewWorldMatrix.copy( raycaster.camera.matrixWorld );\n\t\tthis.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld );\n\n\t\t_mvPosition.setFromMatrixPosition( this.modelViewMatrix );\n\n\t\tif ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {\n\n\t\t\t_worldScale.multiplyScalar( - _mvPosition.z );\n\n\t\t}\n\n\t\tconst rotation = this.material.rotation;\n\t\tlet sin, cos;\n\n\t\tif ( rotation !== 0 ) {\n\n\t\t\tcos = Math.cos( rotation );\n\t\t\tsin = Math.sin( rotation );\n\n\t\t}\n\n\t\tconst center = this.center;\n\n\t\ttransformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );\n\t\ttransformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );\n\t\ttransformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );\n\n\t\t_uvA.set( 0, 0 );\n\t\t_uvB.set( 1, 0 );\n\t\t_uvC.set( 1, 1 );\n\n\t\t// check first triangle\n\t\tlet intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint );\n\n\t\tif ( intersect === null ) {\n\n\t\t\t// check second triangle\n\t\t\ttransformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );\n\t\t\t_uvB.set( 0, 1 );\n\n\t\t\tintersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint );\n\t\t\tif ( intersect === null ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst distance = raycaster.ray.origin.distanceTo( _intersectPoint );\n\n\t\tif ( distance < raycaster.near || distance > raycaster.far ) return;\n\n\t\tintersects.push( {\n\n\t\t\tdistance: distance,\n\t\t\tpoint: _intersectPoint.clone(),\n\t\t\tuv: Triangle.getInterpolation( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ),\n\t\t\tface: null,\n\t\t\tobject: this\n\n\t\t} );\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tif ( source.center !== undefined ) this.center.copy( source.center );\n\n\t\tthis.material = source.material;\n\n\t\treturn this;\n\n\t}\n\n}\n\nfunction transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) {\n\n\t// compute position in camera space\n\t_alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );\n\n\t// to check if rotation is not zero\n\tif ( sin !== undefined ) {\n\n\t\t_rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y );\n\t\t_rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y );\n\n\t} else {\n\n\t\t_rotatedPosition.copy( _alignedPosition );\n\n\t}\n\n\n\tvertexPosition.copy( mvPosition );\n\tvertexPosition.x += _rotatedPosition.x;\n\tvertexPosition.y += _rotatedPosition.y;\n\n\t// transform to world space\n\tvertexPosition.applyMatrix4( _viewWorldMatrix );\n\n}\n\nconst _v1$2 = /*@__PURE__*/ new Vector3();\nconst _v2$1 = /*@__PURE__*/ new Vector3();\n\nclass LOD extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis._currentLevel = 0;\n\n\t\tthis.type = 'LOD';\n\n\t\tObject.defineProperties( this, {\n\t\t\tlevels: {\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: []\n\t\t\t},\n\t\t\tisLOD: {\n\t\t\t\tvalue: true,\n\t\t\t}\n\t\t} );\n\n\t\tthis.autoUpdate = true;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source, false );\n\n\t\tconst levels = source.levels;\n\n\t\tfor ( let i = 0, l = levels.length; i < l; i ++ ) {\n\n\t\t\tconst level = levels[ i ];\n\n\t\t\tthis.addLevel( level.object.clone(), level.distance, level.hysteresis );\n\n\t\t}\n\n\t\tthis.autoUpdate = source.autoUpdate;\n\n\t\treturn this;\n\n\t}\n\n\taddLevel( object, distance = 0, hysteresis = 0 ) {\n\n\t\tdistance = Math.abs( distance );\n\n\t\tconst levels = this.levels;\n\n\t\tlet l;\n\n\t\tfor ( l = 0; l < levels.length; l ++ ) {\n\n\t\t\tif ( distance < levels[ l ].distance ) {\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tlevels.splice( l, 0, { distance: distance, hysteresis: hysteresis, object: object } );\n\n\t\tthis.add( object );\n\n\t\treturn this;\n\n\t}\n\n\tgetCurrentLevel() {\n\n\t\treturn this._currentLevel;\n\n\t}\n\n\n\n\tgetObjectForDistance( distance ) {\n\n\t\tconst levels = this.levels;\n\n\t\tif ( levels.length > 0 ) {\n\n\t\t\tlet i, l;\n\n\t\t\tfor ( i = 1, l = levels.length; i < l; i ++ ) {\n\n\t\t\t\tlet levelDistance = levels[ i ].distance;\n\n\t\t\t\tif ( levels[ i ].object.visible ) {\n\n\t\t\t\t\tlevelDistance -= levelDistance * levels[ i ].hysteresis;\n\n\t\t\t\t}\n\n\t\t\t\tif ( distance < levelDistance ) {\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn levels[ i - 1 ].object;\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst levels = this.levels;\n\n\t\tif ( levels.length > 0 ) {\n\n\t\t\t_v1$2.setFromMatrixPosition( this.matrixWorld );\n\n\t\t\tconst distance = raycaster.ray.origin.distanceTo( _v1$2 );\n\n\t\t\tthis.getObjectForDistance( distance ).raycast( raycaster, intersects );\n\n\t\t}\n\n\t}\n\n\tupdate( camera ) {\n\n\t\tconst levels = this.levels;\n\n\t\tif ( levels.length > 1 ) {\n\n\t\t\t_v1$2.setFromMatrixPosition( camera.matrixWorld );\n\t\t\t_v2$1.setFromMatrixPosition( this.matrixWorld );\n\n\t\t\tconst distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom;\n\n\t\t\tlevels[ 0 ].object.visible = true;\n\n\t\t\tlet i, l;\n\n\t\t\tfor ( i = 1, l = levels.length; i < l; i ++ ) {\n\n\t\t\t\tlet levelDistance = levels[ i ].distance;\n\n\t\t\t\tif ( levels[ i ].object.visible ) {\n\n\t\t\t\t\tlevelDistance -= levelDistance * levels[ i ].hysteresis;\n\n\t\t\t\t}\n\n\t\t\t\tif ( distance >= levelDistance ) {\n\n\t\t\t\t\tlevels[ i - 1 ].object.visible = false;\n\t\t\t\t\tlevels[ i ].object.visible = true;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis._currentLevel = i - 1;\n\n\t\t\tfor ( ; i < l; i ++ ) {\n\n\t\t\t\tlevels[ i ].object.visible = false;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tif ( this.autoUpdate === false ) data.object.autoUpdate = false;\n\n\t\tdata.object.levels = [];\n\n\t\tconst levels = this.levels;\n\n\t\tfor ( let i = 0, l = levels.length; i < l; i ++ ) {\n\n\t\t\tconst level = levels[ i ];\n\n\t\t\tdata.object.levels.push( {\n\t\t\t\tobject: level.object.uuid,\n\t\t\t\tdistance: level.distance,\n\t\t\t\thysteresis: level.hysteresis\n\t\t\t} );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n}\n\nconst _basePosition = /*@__PURE__*/ new Vector3();\n\nconst _skinIndex = /*@__PURE__*/ new Vector4();\nconst _skinWeight = /*@__PURE__*/ new Vector4();\n\nconst _vector3 = /*@__PURE__*/ new Vector3();\nconst _matrix4 = /*@__PURE__*/ new Matrix4();\nconst _vertex = /*@__PURE__*/ new Vector3();\n\nconst _sphere$4 = /*@__PURE__*/ new Sphere();\nconst _inverseMatrix$2 = /*@__PURE__*/ new Matrix4();\nconst _ray$2 = /*@__PURE__*/ new Ray();\n\nclass SkinnedMesh extends Mesh {\n\n\tconstructor( geometry, material ) {\n\n\t\tsuper( geometry, material );\n\n\t\tthis.isSkinnedMesh = true;\n\n\t\tthis.type = 'SkinnedMesh';\n\n\t\tthis.bindMode = AttachedBindMode;\n\t\tthis.bindMatrix = new Matrix4();\n\t\tthis.bindMatrixInverse = new Matrix4();\n\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t}\n\n\tcomputeBoundingBox() {\n\n\t\tconst geometry = this.geometry;\n\n\t\tif ( this.boundingBox === null ) {\n\n\t\t\tthis.boundingBox = new Box3();\n\n\t\t}\n\n\t\tthis.boundingBox.makeEmpty();\n\n\t\tconst positionAttribute = geometry.getAttribute( 'position' );\n\n\t\tfor ( let i = 0; i < positionAttribute.count; i ++ ) {\n\n\t\t\tthis.getVertexPosition( i, _vertex );\n\t\t\tthis.boundingBox.expandByPoint( _vertex );\n\n\t\t}\n\n\t}\n\n\tcomputeBoundingSphere() {\n\n\t\tconst geometry = this.geometry;\n\n\t\tif ( this.boundingSphere === null ) {\n\n\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\tthis.boundingSphere.makeEmpty();\n\n\t\tconst positionAttribute = geometry.getAttribute( 'position' );\n\n\t\tfor ( let i = 0; i < positionAttribute.count; i ++ ) {\n\n\t\t\tthis.getVertexPosition( i, _vertex );\n\t\t\tthis.boundingSphere.expandByPoint( _vertex );\n\n\t\t}\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.bindMode = source.bindMode;\n\t\tthis.bindMatrix.copy( source.bindMatrix );\n\t\tthis.bindMatrixInverse.copy( source.bindMatrixInverse );\n\n\t\tthis.skeleton = source.skeleton;\n\n\t\tif ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone();\n\t\tif ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone();\n\n\t\treturn this;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst material = this.material;\n\t\tconst matrixWorld = this.matrixWorld;\n\n\t\tif ( material === undefined ) return;\n\n\t\t// test with bounding sphere in world space\n\n\t\tif ( this.boundingSphere === null ) this.computeBoundingSphere();\n\n\t\t_sphere$4.copy( this.boundingSphere );\n\t\t_sphere$4.applyMatrix4( matrixWorld );\n\n\t\tif ( raycaster.ray.intersectsSphere( _sphere$4 ) === false ) return;\n\n\t\t// convert ray to local space of skinned mesh\n\n\t\t_inverseMatrix$2.copy( matrixWorld ).invert();\n\t\t_ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 );\n\n\t\t// test with bounding box in local space\n\n\t\tif ( this.boundingBox !== null ) {\n\n\t\t\tif ( _ray$2.intersectsBox( this.boundingBox ) === false ) return;\n\n\t\t}\n\n\t\t// test for intersections with geometry\n\n\t\tthis._computeIntersections( raycaster, intersects, _ray$2 );\n\n\t}\n\n\tgetVertexPosition( index, target ) {\n\n\t\tsuper.getVertexPosition( index, target );\n\n\t\tthis.applyBoneTransform( index, target );\n\n\t\treturn target;\n\n\t}\n\n\tbind( skeleton, bindMatrix ) {\n\n\t\tthis.skeleton = skeleton;\n\n\t\tif ( bindMatrix === undefined ) {\n\n\t\t\tthis.updateMatrixWorld( true );\n\n\t\t\tthis.skeleton.calculateInverses();\n\n\t\t\tbindMatrix = this.matrixWorld;\n\n\t\t}\n\n\t\tthis.bindMatrix.copy( bindMatrix );\n\t\tthis.bindMatrixInverse.copy( bindMatrix ).invert();\n\n\t}\n\n\tpose() {\n\n\t\tthis.skeleton.pose();\n\n\t}\n\n\tnormalizeSkinWeights() {\n\n\t\tconst vector = new Vector4();\n\n\t\tconst skinWeight = this.geometry.attributes.skinWeight;\n\n\t\tfor ( let i = 0, l = skinWeight.count; i < l; i ++ ) {\n\n\t\t\tvector.fromBufferAttribute( skinWeight, i );\n\n\t\t\tconst scale = 1.0 / vector.manhattanLength();\n\n\t\t\tif ( scale !== Infinity ) {\n\n\t\t\t\tvector.multiplyScalar( scale );\n\n\t\t\t} else {\n\n\t\t\t\tvector.set( 1, 0, 0, 0 ); // do something reasonable\n\n\t\t\t}\n\n\t\t\tskinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w );\n\n\t\t}\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t\tif ( this.bindMode === AttachedBindMode ) {\n\n\t\t\tthis.bindMatrixInverse.copy( this.matrixWorld ).invert();\n\n\t\t} else if ( this.bindMode === DetachedBindMode ) {\n\n\t\t\tthis.bindMatrixInverse.copy( this.bindMatrix ).invert();\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );\n\n\t\t}\n\n\t}\n\n\tapplyBoneTransform( index, vector ) {\n\n\t\tconst skeleton = this.skeleton;\n\t\tconst geometry = this.geometry;\n\n\t\t_skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );\n\t\t_skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );\n\n\t\t_basePosition.copy( vector ).applyMatrix4( this.bindMatrix );\n\n\t\tvector.set( 0, 0, 0 );\n\n\t\tfor ( let i = 0; i < 4; i ++ ) {\n\n\t\t\tconst weight = _skinWeight.getComponent( i );\n\n\t\t\tif ( weight !== 0 ) {\n\n\t\t\t\tconst boneIndex = _skinIndex.getComponent( i );\n\n\t\t\t\t_matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );\n\n\t\t\t\tvector.addScaledVector( _vector3.copy( _basePosition ).applyMatrix4( _matrix4 ), weight );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn vector.applyMatrix4( this.bindMatrixInverse );\n\n\t}\n\n}\n\nclass Bone extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isBone = true;\n\n\t\tthis.type = 'Bone';\n\n\t}\n\n}\n\nclass DataTexture extends Texture {\n\n\tconstructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace ) {\n\n\t\tsuper( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );\n\n\t\tthis.isDataTexture = true;\n\n\t\tthis.image = { data: data, width: width, height: height };\n\n\t\tthis.generateMipmaps = false;\n\t\tthis.flipY = false;\n\t\tthis.unpackAlignment = 1;\n\n\t}\n\n}\n\nconst _offsetMatrix = /*@__PURE__*/ new Matrix4();\nconst _identityMatrix$1 = /*@__PURE__*/ new Matrix4();\n\nclass Skeleton {\n\n\tconstructor( bones = [], boneInverses = [] ) {\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.bones = bones.slice( 0 );\n\t\tthis.boneInverses = boneInverses;\n\t\tthis.boneMatrices = null;\n\n\t\tthis.boneTexture = null;\n\n\t\tthis.init();\n\n\t}\n\n\tinit() {\n\n\t\tconst bones = this.bones;\n\t\tconst boneInverses = this.boneInverses;\n\n\t\tthis.boneMatrices = new Float32Array( bones.length * 16 );\n\n\t\t// calculate inverse bone matrices if necessary\n\n\t\tif ( boneInverses.length === 0 ) {\n\n\t\t\tthis.calculateInverses();\n\n\t\t} else {\n\n\t\t\t// handle special case\n\n\t\t\tif ( bones.length !== boneInverses.length ) {\n\n\t\t\t\tconsole.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' );\n\n\t\t\t\tthis.boneInverses = [];\n\n\t\t\t\tfor ( let i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\t\t\tthis.boneInverses.push( new Matrix4() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcalculateInverses() {\n\n\t\tthis.boneInverses.length = 0;\n\n\t\tfor ( let i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\tconst inverse = new Matrix4();\n\n\t\t\tif ( this.bones[ i ] ) {\n\n\t\t\t\tinverse.copy( this.bones[ i ].matrixWorld ).invert();\n\n\t\t\t}\n\n\t\t\tthis.boneInverses.push( inverse );\n\n\t\t}\n\n\t}\n\n\tpose() {\n\n\t\t// recover the bind-time world matrices\n\n\t\tfor ( let i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\tconst bone = this.bones[ i ];\n\n\t\t\tif ( bone ) {\n\n\t\t\t\tbone.matrixWorld.copy( this.boneInverses[ i ] ).invert();\n\n\t\t\t}\n\n\t\t}\n\n\t\t// compute the local matrices, positions, rotations and scales\n\n\t\tfor ( let i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\tconst bone = this.bones[ i ];\n\n\t\t\tif ( bone ) {\n\n\t\t\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\t\t\tbone.matrix.copy( bone.parent.matrixWorld ).invert();\n\t\t\t\t\tbone.matrix.multiply( bone.matrixWorld );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tbone.matrix.copy( bone.matrixWorld );\n\n\t\t\t\t}\n\n\t\t\t\tbone.matrix.decompose( bone.position, bone.quaternion, bone.scale );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tupdate() {\n\n\t\tconst bones = this.bones;\n\t\tconst boneInverses = this.boneInverses;\n\t\tconst boneMatrices = this.boneMatrices;\n\t\tconst boneTexture = this.boneTexture;\n\n\t\t// flatten bone matrices to array\n\n\t\tfor ( let i = 0, il = bones.length; i < il; i ++ ) {\n\n\t\t\t// compute the offset between the current and the original transform\n\n\t\t\tconst matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix$1;\n\n\t\t\t_offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );\n\t\t\t_offsetMatrix.toArray( boneMatrices, i * 16 );\n\n\t\t}\n\n\t\tif ( boneTexture !== null ) {\n\n\t\t\tboneTexture.needsUpdate = true;\n\n\t\t}\n\n\t}\n\n\tclone() {\n\n\t\treturn new Skeleton( this.bones, this.boneInverses );\n\n\t}\n\n\tcomputeBoneTexture() {\n\n\t\t// layout (1 matrix = 4 pixels)\n\t\t// RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)\n\t\t// with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8)\n\t\t// 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16)\n\t\t// 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32)\n\t\t// 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)\n\n\t\tlet size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix\n\t\tsize = Math.ceil( size / 4 ) * 4;\n\t\tsize = Math.max( size, 4 );\n\n\t\tconst boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel\n\t\tboneMatrices.set( this.boneMatrices ); // copy current values\n\n\t\tconst boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );\n\t\tboneTexture.needsUpdate = true;\n\n\t\tthis.boneMatrices = boneMatrices;\n\t\tthis.boneTexture = boneTexture;\n\n\t\treturn this;\n\n\t}\n\n\tgetBoneByName( name ) {\n\n\t\tfor ( let i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\tconst bone = this.bones[ i ];\n\n\t\t\tif ( bone.name === name ) {\n\n\t\t\t\treturn bone;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn undefined;\n\n\t}\n\n\tdispose( ) {\n\n\t\tif ( this.boneTexture !== null ) {\n\n\t\t\tthis.boneTexture.dispose();\n\n\t\t\tthis.boneTexture = null;\n\n\t\t}\n\n\t}\n\n\tfromJSON( json, bones ) {\n\n\t\tthis.uuid = json.uuid;\n\n\t\tfor ( let i = 0, l = json.bones.length; i < l; i ++ ) {\n\n\t\t\tconst uuid = json.bones[ i ];\n\t\t\tlet bone = bones[ uuid ];\n\n\t\t\tif ( bone === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Skeleton: No bone found with UUID:', uuid );\n\t\t\t\tbone = new Bone();\n\n\t\t\t}\n\n\t\t\tthis.bones.push( bone );\n\t\t\tthis.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) );\n\n\t\t}\n\n\t\tthis.init();\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'Skeleton',\n\t\t\t\tgenerator: 'Skeleton.toJSON'\n\t\t\t},\n\t\t\tbones: [],\n\t\t\tboneInverses: []\n\t\t};\n\n\t\tdata.uuid = this.uuid;\n\n\t\tconst bones = this.bones;\n\t\tconst boneInverses = this.boneInverses;\n\n\t\tfor ( let i = 0, l = bones.length; i < l; i ++ ) {\n\n\t\t\tconst bone = bones[ i ];\n\t\t\tdata.bones.push( bone.uuid );\n\n\t\t\tconst boneInverse = boneInverses[ i ];\n\t\t\tdata.boneInverses.push( boneInverse.toArray() );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass InstancedBufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized, meshPerAttribute = 1 ) {\n\n\t\tsuper( array, itemSize, normalized );\n\n\t\tthis.isInstancedBufferAttribute = true;\n\n\t\tthis.meshPerAttribute = meshPerAttribute;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.meshPerAttribute = source.meshPerAttribute;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.meshPerAttribute = this.meshPerAttribute;\n\n\t\tdata.isInstancedBufferAttribute = true;\n\n\t\treturn data;\n\n\t}\n\n}\n\nconst _instanceLocalMatrix = /*@__PURE__*/ new Matrix4();\nconst _instanceWorldMatrix = /*@__PURE__*/ new Matrix4();\n\nconst _instanceIntersects = [];\n\nconst _box3 = /*@__PURE__*/ new Box3();\nconst _identity = /*@__PURE__*/ new Matrix4();\nconst _mesh$1 = /*@__PURE__*/ new Mesh();\nconst _sphere$3 = /*@__PURE__*/ new Sphere();\n\nclass InstancedMesh extends Mesh {\n\n\tconstructor( geometry, material, count ) {\n\n\t\tsuper( geometry, material );\n\n\t\tthis.isInstancedMesh = true;\n\n\t\tthis.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 );\n\t\tthis.instanceColor = null;\n\t\tthis.morphTexture = null;\n\n\t\tthis.count = count;\n\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tthis.setMatrixAt( i, _identity );\n\n\t\t}\n\n\t}\n\n\tcomputeBoundingBox() {\n\n\t\tconst geometry = this.geometry;\n\t\tconst count = this.count;\n\n\t\tif ( this.boundingBox === null ) {\n\n\t\t\tthis.boundingBox = new Box3();\n\n\t\t}\n\n\t\tif ( geometry.boundingBox === null ) {\n\n\t\t\tgeometry.computeBoundingBox();\n\n\t\t}\n\n\t\tthis.boundingBox.makeEmpty();\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tthis.getMatrixAt( i, _instanceLocalMatrix );\n\n\t\t\t_box3.copy( geometry.boundingBox ).applyMatrix4( _instanceLocalMatrix );\n\n\t\t\tthis.boundingBox.union( _box3 );\n\n\t\t}\n\n\t}\n\n\tcomputeBoundingSphere() {\n\n\t\tconst geometry = this.geometry;\n\t\tconst count = this.count;\n\n\t\tif ( this.boundingSphere === null ) {\n\n\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\tif ( geometry.boundingSphere === null ) {\n\n\t\t\tgeometry.computeBoundingSphere();\n\n\t\t}\n\n\t\tthis.boundingSphere.makeEmpty();\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tthis.getMatrixAt( i, _instanceLocalMatrix );\n\n\t\t\t_sphere$3.copy( geometry.boundingSphere ).applyMatrix4( _instanceLocalMatrix );\n\n\t\t\tthis.boundingSphere.union( _sphere$3 );\n\n\t\t}\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.instanceMatrix.copy( source.instanceMatrix );\n\n\t\tif ( source.morphTexture !== null ) this.morphTexture = source.morphTexture.clone();\n\t\tif ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone();\n\n\t\tthis.count = source.count;\n\n\t\tif ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone();\n\t\tif ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone();\n\n\t\treturn this;\n\n\t}\n\n\tgetColorAt( index, color ) {\n\n\t\tcolor.fromArray( this.instanceColor.array, index * 3 );\n\n\t}\n\n\tgetMatrixAt( index, matrix ) {\n\n\t\tmatrix.fromArray( this.instanceMatrix.array, index * 16 );\n\n\t}\n\n\tgetMorphAt( index, object ) {\n\n\t\tconst objectInfluences = object.morphTargetInfluences;\n\n\t\tconst array = this.morphTexture.source.data.data;\n\n\t\tconst len = objectInfluences.length + 1; // All influences + the baseInfluenceSum\n\n\t\tconst dataIndex = index * len + 1; // Skip the baseInfluenceSum at the beginning\n\n\t\tfor ( let i = 0; i < objectInfluences.length; i ++ ) {\n\n\t\t\tobjectInfluences[ i ] = array[ dataIndex + i ];\n\n\t\t}\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst matrixWorld = this.matrixWorld;\n\t\tconst raycastTimes = this.count;\n\n\t\t_mesh$1.geometry = this.geometry;\n\t\t_mesh$1.material = this.material;\n\n\t\tif ( _mesh$1.material === undefined ) return;\n\n\t\t// test with bounding sphere first\n\n\t\tif ( this.boundingSphere === null ) this.computeBoundingSphere();\n\n\t\t_sphere$3.copy( this.boundingSphere );\n\t\t_sphere$3.applyMatrix4( matrixWorld );\n\n\t\tif ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return;\n\n\t\t// now test each instance\n\n\t\tfor ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) {\n\n\t\t\t// calculate the world matrix for each instance\n\n\t\t\tthis.getMatrixAt( instanceId, _instanceLocalMatrix );\n\n\t\t\t_instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix );\n\n\t\t\t// the mesh represents this single instance\n\n\t\t\t_mesh$1.matrixWorld = _instanceWorldMatrix;\n\n\t\t\t_mesh$1.raycast( raycaster, _instanceIntersects );\n\n\t\t\t// process the result of raycast\n\n\t\t\tfor ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) {\n\n\t\t\t\tconst intersect = _instanceIntersects[ i ];\n\t\t\t\tintersect.instanceId = instanceId;\n\t\t\t\tintersect.object = this;\n\t\t\t\tintersects.push( intersect );\n\n\t\t\t}\n\n\t\t\t_instanceIntersects.length = 0;\n\n\t\t}\n\n\t}\n\n\tsetColorAt( index, color ) {\n\n\t\tif ( this.instanceColor === null ) {\n\n\t\t\tthis.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ), 3 );\n\n\t\t}\n\n\t\tcolor.toArray( this.instanceColor.array, index * 3 );\n\n\t}\n\n\tsetMatrixAt( index, matrix ) {\n\n\t\tmatrix.toArray( this.instanceMatrix.array, index * 16 );\n\n\t}\n\n\tsetMorphAt( index, object ) {\n\n\t\tconst objectInfluences = object.morphTargetInfluences;\n\n\t\tconst len = objectInfluences.length + 1; // morphBaseInfluence + all influences\n\n\t\tif ( this.morphTexture === null ) {\n\n\t\t\tthis.morphTexture = new DataTexture( new Float32Array( len * this.count ), len, this.count, RedFormat, FloatType );\n\n\t\t}\n\n\t\tconst array = this.morphTexture.source.data.data;\n\n\t\tlet morphInfluencesSum = 0;\n\n\t\tfor ( let i = 0; i < objectInfluences.length; i ++ ) {\n\n\t\t\tmorphInfluencesSum += objectInfluences[ i ];\n\n\t\t}\n\n\t\tconst morphBaseInfluence = this.geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;\n\n\t\tconst dataIndex = len * index;\n\n\t\tarray[ dataIndex ] = morphBaseInfluence;\n\n\t\tarray.set( objectInfluences, dataIndex + 1 );\n\n\t}\n\n\tupdateMorphTargets() {\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t\tif ( this.morphTexture !== null ) {\n\n\t\t\tthis.morphTexture.dispose();\n\t\t\tthis.morphTexture = null;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\nfunction sortOpaque( a, b ) {\n\n\treturn a.z - b.z;\n\n}\n\nfunction sortTransparent( a, b ) {\n\n\treturn b.z - a.z;\n\n}\n\nclass MultiDrawRenderList {\n\n\tconstructor() {\n\n\t\tthis.index = 0;\n\t\tthis.pool = [];\n\t\tthis.list = [];\n\n\t}\n\n\tpush( drawRange, z, index ) {\n\n\t\tconst pool = this.pool;\n\t\tconst list = this.list;\n\t\tif ( this.index >= pool.length ) {\n\n\t\t\tpool.push( {\n\n\t\t\t\tstart: - 1,\n\t\t\t\tcount: - 1,\n\t\t\t\tz: - 1,\n\t\t\t\tindex: - 1,\n\n\t\t\t} );\n\n\t\t}\n\n\t\tconst item = pool[ this.index ];\n\t\tlist.push( item );\n\t\tthis.index ++;\n\n\t\titem.start = drawRange.start;\n\t\titem.count = drawRange.count;\n\t\titem.z = z;\n\t\titem.index = index;\n\n\t}\n\n\treset() {\n\n\t\tthis.list.length = 0;\n\t\tthis.index = 0;\n\n\t}\n\n}\n\nconst _matrix$1 = /*@__PURE__*/ new Matrix4();\nconst _invMatrixWorld = /*@__PURE__*/ new Matrix4();\nconst _identityMatrix = /*@__PURE__*/ new Matrix4();\nconst _whiteColor = /*@__PURE__*/ new Color( 1, 1, 1 );\nconst _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4();\nconst _frustum = /*@__PURE__*/ new Frustum();\nconst _box$1 = /*@__PURE__*/ new Box3();\nconst _sphere$2 = /*@__PURE__*/ new Sphere();\nconst _vector$5 = /*@__PURE__*/ new Vector3();\nconst _forward = /*@__PURE__*/ new Vector3();\nconst _temp = /*@__PURE__*/ new Vector3();\nconst _renderList = /*@__PURE__*/ new MultiDrawRenderList();\nconst _mesh = /*@__PURE__*/ new Mesh();\nconst _batchIntersects = [];\n\n// @TODO: SkinnedMesh support?\n// @TODO: geometry.groups support?\n// @TODO: geometry.drawRange support?\n// @TODO: geometry.morphAttributes support?\n// @TODO: Support uniform parameter per geometry\n// @TODO: Add an \"optimize\" function to pack geometry and remove data gaps\n\n// copies data from attribute \"src\" into \"target\" starting at \"targetOffset\"\nfunction copyAttributeData( src, target, targetOffset = 0 ) {\n\n\tconst itemSize = target.itemSize;\n\tif ( src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor ) {\n\n\t\t// use the component getters and setters if the array data cannot\n\t\t// be copied directly\n\t\tconst vertexCount = src.count;\n\t\tfor ( let i = 0; i < vertexCount; i ++ ) {\n\n\t\t\tfor ( let c = 0; c < itemSize; c ++ ) {\n\n\t\t\t\ttarget.setComponent( i + targetOffset, c, src.getComponent( i, c ) );\n\n\t\t\t}\n\n\t\t}\n\n\t} else {\n\n\t\t// faster copy approach using typed array set function\n\t\ttarget.array.set( src.array, targetOffset * itemSize );\n\n\t}\n\n\ttarget.needsUpdate = true;\n\n}\n\nclass BatchedMesh extends Mesh {\n\n\tget maxInstanceCount() {\n\n\t\treturn this._maxInstanceCount;\n\n\t}\n\n\tconstructor( maxInstanceCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) {\n\n\t\tsuper( new BufferGeometry(), material );\n\n\t\tthis.isBatchedMesh = true;\n\t\tthis.perObjectFrustumCulled = true;\n\t\tthis.sortObjects = true;\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\t\tthis.customSort = null;\n\n\t\t// stores visible, active, and geometry id per object\n\t\tthis._drawInfo = [];\n\n\t\t// geometry information\n\t\tthis._drawRanges = [];\n\t\tthis._reservedRanges = [];\n\t\tthis._bounds = [];\n\n\t\tthis._maxInstanceCount = maxInstanceCount;\n\t\tthis._maxVertexCount = maxVertexCount;\n\t\tthis._maxIndexCount = maxIndexCount;\n\n\t\tthis._geometryInitialized = false;\n\t\tthis._geometryCount = 0;\n\t\tthis._multiDrawCounts = new Int32Array( maxInstanceCount );\n\t\tthis._multiDrawStarts = new Int32Array( maxInstanceCount );\n\t\tthis._multiDrawCount = 0;\n\t\tthis._multiDrawInstances = null;\n\t\tthis._visibilityChanged = true;\n\n\t\t// Local matrix per geometry by using data texture\n\t\tthis._matricesTexture = null;\n\t\tthis._indirectTexture = null;\n\t\tthis._colorsTexture = null;\n\n\t\tthis._initMatricesTexture();\n\t\tthis._initIndirectTexture();\n\n\t}\n\n\t_initMatricesTexture() {\n\n\t\t// layout (1 matrix = 4 pixels)\n\t\t// RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)\n\t\t// with 8x8 pixel texture max 16 matrices * 4 pixels = (8 * 8)\n\t\t// 16x16 pixel texture max 64 matrices * 4 pixels = (16 * 16)\n\t\t// 32x32 pixel texture max 256 matrices * 4 pixels = (32 * 32)\n\t\t// 64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64)\n\n\t\tlet size = Math.sqrt( this._maxInstanceCount * 4 ); // 4 pixels needed for 1 matrix\n\t\tsize = Math.ceil( size / 4 ) * 4;\n\t\tsize = Math.max( size, 4 );\n\n\t\tconst matricesArray = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel\n\t\tconst matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType );\n\n\t\tthis._matricesTexture = matricesTexture;\n\n\t}\n\n\t_initIndirectTexture() {\n\n\t\tlet size = Math.sqrt( this._maxInstanceCount );\n\t\tsize = Math.ceil( size );\n\n\t\tconst indirectArray = new Uint32Array( size * size );\n\t\tconst indirectTexture = new DataTexture( indirectArray, size, size, RedIntegerFormat, UnsignedIntType );\n\n\t\tthis._indirectTexture = indirectTexture;\n\n\t}\n\n\t_initColorsTexture() {\n\n\t\tlet size = Math.sqrt( this._maxIndexCount );\n\t\tsize = Math.ceil( size );\n\n\t\t// 4 floats per RGBA pixel initialized to white\n\t\tconst colorsArray = new Float32Array( size * size * 4 ).fill( 1 );\n\t\tconst colorsTexture = new DataTexture( colorsArray, size, size, RGBAFormat, FloatType );\n\t\tcolorsTexture.colorSpace = ColorManagement.workingColorSpace;\n\n\t\tthis._colorsTexture = colorsTexture;\n\n\t}\n\n\t_initializeGeometry( reference ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst maxVertexCount = this._maxVertexCount;\n\t\tconst maxIndexCount = this._maxIndexCount;\n\t\tif ( this._geometryInitialized === false ) {\n\n\t\t\tfor ( const attributeName in reference.attributes ) {\n\n\t\t\t\tconst srcAttribute = reference.getAttribute( attributeName );\n\t\t\t\tconst { array, itemSize, normalized } = srcAttribute;\n\n\t\t\t\tconst dstArray = new array.constructor( maxVertexCount * itemSize );\n\t\t\t\tconst dstAttribute = new BufferAttribute( dstArray, itemSize, normalized );\n\n\t\t\t\tgeometry.setAttribute( attributeName, dstAttribute );\n\n\t\t\t}\n\n\t\t\tif ( reference.getIndex() !== null ) {\n\n\t\t\t\t// Reserve last u16 index for primitive restart.\n\t\t\t\tconst indexArray = maxVertexCount > 65535\n\t\t\t\t\t? new Uint32Array( maxIndexCount )\n\t\t\t\t\t: new Uint16Array( maxIndexCount );\n\n\t\t\t\tgeometry.setIndex( new BufferAttribute( indexArray, 1 ) );\n\n\t\t\t}\n\n\t\t\tthis._geometryInitialized = true;\n\n\t\t}\n\n\t}\n\n\t// Make sure the geometry is compatible with the existing combined geometry attributes\n\t_validateGeometry( geometry ) {\n\n\t\t// check to ensure the geometries are using consistent attributes and indices\n\t\tconst batchGeometry = this.geometry;\n\t\tif ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) {\n\n\t\t\tthrow new Error( 'BatchedMesh: All geometries must consistently have \"index\".' );\n\n\t\t}\n\n\t\tfor ( const attributeName in batchGeometry.attributes ) {\n\n\t\t\tif ( ! geometry.hasAttribute( attributeName ) ) {\n\n\t\t\t\tthrow new Error( `BatchedMesh: Added geometry missing \"${ attributeName }\". All geometries must have consistent attributes.` );\n\n\t\t\t}\n\n\t\t\tconst srcAttribute = geometry.getAttribute( attributeName );\n\t\t\tconst dstAttribute = batchGeometry.getAttribute( attributeName );\n\t\t\tif ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) {\n\n\t\t\t\tthrow new Error( 'BatchedMesh: All attributes must have a consistent itemSize and normalized value.' );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tsetCustomSort( func ) {\n\n\t\tthis.customSort = func;\n\t\treturn this;\n\n\t}\n\n\tcomputeBoundingBox() {\n\n\t\tif ( this.boundingBox === null ) {\n\n\t\t\tthis.boundingBox = new Box3();\n\n\t\t}\n\n\t\tconst geometryCount = this._geometryCount;\n\t\tconst boundingBox = this.boundingBox;\n\t\tconst drawInfo = this._drawInfo;\n\n\t\tboundingBox.makeEmpty();\n\t\tfor ( let i = 0; i < geometryCount; i ++ ) {\n\n\t\t\tif ( drawInfo[ i ].active === false ) continue;\n\n\t\t\tconst geometryId = drawInfo[ i ].geometryIndex;\n\t\t\tthis.getMatrixAt( i, _matrix$1 );\n\t\t\tthis.getBoundingBoxAt( geometryId, _box$1 ).applyMatrix4( _matrix$1 );\n\t\t\tboundingBox.union( _box$1 );\n\n\t\t}\n\n\t}\n\n\tcomputeBoundingSphere() {\n\n\t\tif ( this.boundingSphere === null ) {\n\n\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\tconst boundingSphere = this.boundingSphere;\n\t\tconst drawInfo = this._drawInfo;\n\n\t\tboundingSphere.makeEmpty();\n\t\tfor ( let i = 0, l = drawInfo.length; i < l; i ++ ) {\n\n\t\t\tif ( drawInfo[ i ].active === false ) continue;\n\n\t\t\tconst geometryId = drawInfo[ i ].geometryIndex;\n\t\t\tthis.getMatrixAt( i, _matrix$1 );\n\t\t\tthis.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 );\n\t\t\tboundingSphere.union( _sphere$2 );\n\n\t\t}\n\n\t}\n\n\taddInstance( geometryId ) {\n\n\t\t// ensure we're not over geometry\n\t\tif ( this._drawInfo.length >= this._maxInstanceCount ) {\n\n\t\t\tthrow new Error( 'BatchedMesh: Maximum item count reached.' );\n\n\t\t}\n\n\t\tthis._drawInfo.push( {\n\n\t\t\tvisible: true,\n\t\t\tactive: true,\n\t\t\tgeometryIndex: geometryId,\n\n\t\t} );\n\n\t\t// initialize the matrix\n\t\tconst drawId = this._drawInfo.length - 1;\n\t\tconst matricesTexture = this._matricesTexture;\n\t\tconst matricesArray = matricesTexture.image.data;\n\t\t_identityMatrix.toArray( matricesArray, drawId * 16 );\n\t\tmatricesTexture.needsUpdate = true;\n\n\t\tconst colorsTexture = this._colorsTexture;\n\t\tif ( colorsTexture ) {\n\n\t\t\t_whiteColor.toArray( colorsTexture.image.data, drawId * 4 );\n\t\t\tcolorsTexture.needsUpdate = true;\n\n\t\t}\n\n\t\treturn drawId;\n\n\t}\n\n\taddGeometry( geometry, vertexCount = - 1, indexCount = - 1 ) {\n\n\t\tthis._initializeGeometry( geometry );\n\n\t\tthis._validateGeometry( geometry );\n\n\t\t// ensure we're not over geometry\n\t\tif ( this._drawInfo.length >= this._maxInstanceCount ) {\n\n\t\t\tthrow new Error( 'BatchedMesh: Maximum item count reached.' );\n\n\t\t}\n\n\t\t// get the necessary range fo the geometry\n\t\tconst reservedRange = {\n\t\t\tvertexStart: - 1,\n\t\t\tvertexCount: - 1,\n\t\t\tindexStart: - 1,\n\t\t\tindexCount: - 1,\n\t\t};\n\n\t\tlet lastRange = null;\n\t\tconst reservedRanges = this._reservedRanges;\n\t\tconst drawRanges = this._drawRanges;\n\t\tconst bounds = this._bounds;\n\t\tif ( this._geometryCount !== 0 ) {\n\n\t\t\tlastRange = reservedRanges[ reservedRanges.length - 1 ];\n\n\t\t}\n\n\t\tif ( vertexCount === - 1 ) {\n\n\t\t\treservedRange.vertexCount = geometry.getAttribute( 'position' ).count;\n\n\t\t} else {\n\n\t\t\treservedRange.vertexCount = vertexCount;\n\n\t\t}\n\n\t\tif ( lastRange === null ) {\n\n\t\t\treservedRange.vertexStart = 0;\n\n\t\t} else {\n\n\t\t\treservedRange.vertexStart = lastRange.vertexStart + lastRange.vertexCount;\n\n\t\t}\n\n\t\tconst index = geometry.getIndex();\n\t\tconst hasIndex = index !== null;\n\t\tif ( hasIndex ) {\n\n\t\t\tif ( indexCount\t=== - 1 ) {\n\n\t\t\t\treservedRange.indexCount = index.count;\n\n\t\t\t} else {\n\n\t\t\t\treservedRange.indexCount = indexCount;\n\n\t\t\t}\n\n\t\t\tif ( lastRange === null ) {\n\n\t\t\t\treservedRange.indexStart = 0;\n\n\t\t\t} else {\n\n\t\t\t\treservedRange.indexStart = lastRange.indexStart + lastRange.indexCount;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif (\n\t\t\treservedRange.indexStart !== - 1 &&\n\t\t\treservedRange.indexStart + reservedRange.indexCount > this._maxIndexCount ||\n\t\t\treservedRange.vertexStart + reservedRange.vertexCount > this._maxVertexCount\n\t\t) {\n\n\t\t\tthrow new Error( 'BatchedMesh: Reserved space request exceeds the maximum buffer size.' );\n\n\t\t}\n\n\t\t// update id\n\t\tconst geometryId = this._geometryCount;\n\t\tthis._geometryCount ++;\n\n\t\t// add the reserved range and draw range objects\n\t\treservedRanges.push( reservedRange );\n\t\tdrawRanges.push( {\n\t\t\tstart: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart,\n\t\t\tcount: - 1\n\t\t} );\n\t\tbounds.push( {\n\t\t\tboxInitialized: false,\n\t\t\tbox: new Box3(),\n\n\t\t\tsphereInitialized: false,\n\t\t\tsphere: new Sphere()\n\t\t} );\n\n\t\t// update the geometry\n\t\tthis.setGeometryAt( geometryId, geometry );\n\n\t\treturn geometryId;\n\n\t}\n\n\tsetGeometryAt( geometryId, geometry ) {\n\n\t\tif ( geometryId >= this._geometryCount ) {\n\n\t\t\tthrow new Error( 'BatchedMesh: Maximum geometry count reached.' );\n\n\t\t}\n\n\t\tthis._validateGeometry( geometry );\n\n\t\tconst batchGeometry = this.geometry;\n\t\tconst hasIndex = batchGeometry.getIndex() !== null;\n\t\tconst dstIndex = batchGeometry.getIndex();\n\t\tconst srcIndex = geometry.getIndex();\n\t\tconst reservedRange = this._reservedRanges[ geometryId ];\n\t\tif (\n\t\t\thasIndex &&\n\t\t\tsrcIndex.count > reservedRange.indexCount ||\n\t\t\tgeometry.attributes.position.count > reservedRange.vertexCount\n\t\t) {\n\n\t\t\tthrow new Error( 'BatchedMesh: Reserved space not large enough for provided geometry.' );\n\n\t\t}\n\n\t\t// copy geometry over\n\t\tconst vertexStart = reservedRange.vertexStart;\n\t\tconst vertexCount = reservedRange.vertexCount;\n\t\tfor ( const attributeName in batchGeometry.attributes ) {\n\n\t\t\t// copy attribute data\n\t\t\tconst srcAttribute = geometry.getAttribute( attributeName );\n\t\t\tconst dstAttribute = batchGeometry.getAttribute( attributeName );\n\t\t\tcopyAttributeData( srcAttribute, dstAttribute, vertexStart );\n\n\t\t\t// fill the rest in with zeroes\n\t\t\tconst itemSize = srcAttribute.itemSize;\n\t\t\tfor ( let i = srcAttribute.count, l = vertexCount; i < l; i ++ ) {\n\n\t\t\t\tconst index = vertexStart + i;\n\t\t\t\tfor ( let c = 0; c < itemSize; c ++ ) {\n\n\t\t\t\t\tdstAttribute.setComponent( index, c, 0 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tdstAttribute.needsUpdate = true;\n\t\t\tdstAttribute.addUpdateRange( vertexStart * itemSize, vertexCount * itemSize );\n\n\t\t}\n\n\t\t// copy index\n\t\tif ( hasIndex ) {\n\n\t\t\tconst indexStart = reservedRange.indexStart;\n\n\t\t\t// copy index data over\n\t\t\tfor ( let i = 0; i < srcIndex.count; i ++ ) {\n\n\t\t\t\tdstIndex.setX( indexStart + i, vertexStart + srcIndex.getX( i ) );\n\n\t\t\t}\n\n\t\t\t// fill the rest in with zeroes\n\t\t\tfor ( let i = srcIndex.count, l = reservedRange.indexCount; i < l; i ++ ) {\n\n\t\t\t\tdstIndex.setX( indexStart + i, vertexStart );\n\n\t\t\t}\n\n\t\t\tdstIndex.needsUpdate = true;\n\t\t\tdstIndex.addUpdateRange( indexStart, reservedRange.indexCount );\n\n\t\t}\n\n\t\t// store the bounding boxes\n\t\tconst bound = this._bounds[ geometryId ];\n\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\tbound.box.copy( geometry.boundingBox );\n\t\t\tbound.boxInitialized = true;\n\n\t\t} else {\n\n\t\t\tbound.boxInitialized = false;\n\n\t\t}\n\n\t\tif ( geometry.boundingSphere !== null ) {\n\n\t\t\tbound.sphere.copy( geometry.boundingSphere );\n\t\t\tbound.sphereInitialized = true;\n\n\t\t} else {\n\n\t\t\tbound.sphereInitialized = false;\n\n\t\t}\n\n\t\t// set drawRange count\n\t\tconst drawRange = this._drawRanges[ geometryId ];\n\t\tconst posAttr = geometry.getAttribute( 'position' );\n\t\tdrawRange.count = hasIndex ? srcIndex.count : posAttr.count;\n\t\tthis._visibilityChanged = true;\n\n\t\treturn geometryId;\n\n\t}\n\n\t/*\n\tdeleteGeometry( geometryId ) {\n\n\t\t// TODO: delete geometry and associated instances\n\n\t}\n\t*/\n\n\t/*\n\tdeleteInstance( instanceId ) {\n\n\t\t// Note: User needs to call optimize() afterward to pack the data.\n\n\t\tconst drawInfo = this._drawInfo;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tdrawInfo[ instanceId ].active = false;\n\t\tthis._visibilityChanged = true;\n\n\t\treturn this;\n\n\t}\n\t*/\n\n\t// get bounding box and compute it if it doesn't exist\n\tgetBoundingBoxAt( geometryId, target ) {\n\n\t\tif ( geometryId >= this._geometryCount ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// compute bounding box\n\t\tconst bound = this._bounds[ geometryId ];\n\t\tconst box = bound.box;\n\t\tconst geometry = this.geometry;\n\t\tif ( bound.boxInitialized === false ) {\n\n\t\t\tbox.makeEmpty();\n\n\t\t\tconst index = geometry.index;\n\t\t\tconst position = geometry.attributes.position;\n\t\t\tconst drawRange = this._drawRanges[ geometryId ];\n\t\t\tfor ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {\n\n\t\t\t\tlet iv = i;\n\t\t\t\tif ( index ) {\n\n\t\t\t\t\tiv = index.getX( iv );\n\n\t\t\t\t}\n\n\t\t\t\tbox.expandByPoint( _vector$5.fromBufferAttribute( position, iv ) );\n\n\t\t\t}\n\n\t\t\tbound.boxInitialized = true;\n\n\t\t}\n\n\t\ttarget.copy( box );\n\t\treturn target;\n\n\t}\n\n\t// get bounding sphere and compute it if it doesn't exist\n\tgetBoundingSphereAt( geometryId, target ) {\n\n\t\tif ( geometryId >= this._geometryCount ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// compute bounding sphere\n\t\tconst bound = this._bounds[ geometryId ];\n\t\tconst sphere = bound.sphere;\n\t\tconst geometry = this.geometry;\n\t\tif ( bound.sphereInitialized === false ) {\n\n\t\t\tsphere.makeEmpty();\n\n\t\t\tthis.getBoundingBoxAt( geometryId, _box$1 );\n\t\t\t_box$1.getCenter( sphere.center );\n\n\t\t\tconst index = geometry.index;\n\t\t\tconst position = geometry.attributes.position;\n\t\t\tconst drawRange = this._drawRanges[ geometryId ];\n\n\t\t\tlet maxRadiusSq = 0;\n\t\t\tfor ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {\n\n\t\t\t\tlet iv = i;\n\t\t\t\tif ( index ) {\n\n\t\t\t\t\tiv = index.getX( iv );\n\n\t\t\t\t}\n\n\t\t\t\t_vector$5.fromBufferAttribute( position, iv );\n\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, sphere.center.distanceToSquared( _vector$5 ) );\n\n\t\t\t}\n\n\t\t\tsphere.radius = Math.sqrt( maxRadiusSq );\n\t\t\tbound.sphereInitialized = true;\n\n\t\t}\n\n\t\ttarget.copy( sphere );\n\t\treturn target;\n\n\t}\n\n\tsetMatrixAt( instanceId, matrix ) {\n\n\t\t// @TODO: Map geometryId to index of the arrays because\n\t\t// optimize() can make geometryId mismatch the index\n\n\t\tconst drawInfo = this._drawInfo;\n\t\tconst matricesTexture = this._matricesTexture;\n\t\tconst matricesArray = this._matricesTexture.image.data;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tmatrix.toArray( matricesArray, instanceId * 16 );\n\t\tmatricesTexture.needsUpdate = true;\n\n\t\treturn this;\n\n\t}\n\n\tgetMatrixAt( instanceId, matrix ) {\n\n\t\tconst drawInfo = this._drawInfo;\n\t\tconst matricesArray = this._matricesTexture.image.data;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\treturn matrix.fromArray( matricesArray, instanceId * 16 );\n\n\t}\n\n\tsetColorAt( instanceId, color ) {\n\n\t\tif ( this._colorsTexture === null ) {\n\n\t\t\tthis._initColorsTexture();\n\n\t\t}\n\n\t\t// @TODO: Map id to index of the arrays because\n\t\t// optimize() can make id mismatch the index\n\n\t\tconst colorsTexture = this._colorsTexture;\n\t\tconst colorsArray = this._colorsTexture.image.data;\n\t\tconst drawInfo = this._drawInfo;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tcolor.toArray( colorsArray, instanceId * 4 );\n\t\tcolorsTexture.needsUpdate = true;\n\n\t\treturn this;\n\n\t}\n\n\tgetColorAt( instanceId, color ) {\n\n\t\tconst colorsArray = this._colorsTexture.image.data;\n\t\tconst drawInfo = this._drawInfo;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\treturn color.fromArray( colorsArray, instanceId * 4 );\n\n\t}\n\n\tsetVisibleAt( instanceId, value ) {\n\n\t\t// if the geometry is out of range, not active, or visibility state\n\t\t// does not change then return early\n\t\tconst drawInfo = this._drawInfo;\n\t\tif (\n\t\t\tinstanceId >= drawInfo.length ||\n\t\t\tdrawInfo[ instanceId ].active === false ||\n\t\t\tdrawInfo[ instanceId ].visible === value\n\t\t) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tdrawInfo[ instanceId ].visible = value;\n\t\tthis._visibilityChanged = true;\n\n\t\treturn this;\n\n\t}\n\n\tgetVisibleAt( instanceId ) {\n\n\t\t// return early if the geometry is out of range or not active\n\t\tconst drawInfo = this._drawInfo;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\treturn drawInfo[ instanceId ].visible;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst drawInfo = this._drawInfo;\n\t\tconst drawRanges = this._drawRanges;\n\t\tconst matrixWorld = this.matrixWorld;\n\t\tconst batchGeometry = this.geometry;\n\n\t\t// iterate over each geometry\n\t\t_mesh.material = this.material;\n\t\t_mesh.geometry.index = batchGeometry.index;\n\t\t_mesh.geometry.attributes = batchGeometry.attributes;\n\t\tif ( _mesh.geometry.boundingBox === null ) {\n\n\t\t\t_mesh.geometry.boundingBox = new Box3();\n\n\t\t}\n\n\t\tif ( _mesh.geometry.boundingSphere === null ) {\n\n\t\t\t_mesh.geometry.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\tfor ( let i = 0, l = drawInfo.length; i < l; i ++ ) {\n\n\t\t\tif ( ! drawInfo[ i ].visible || ! drawInfo[ i ].active ) {\n\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tconst geometryId = drawInfo[ i ].geometryIndex;\n\t\t\tconst drawRange = drawRanges[ geometryId ];\n\t\t\t_mesh.geometry.setDrawRange( drawRange.start, drawRange.count );\n\n\t\t\t// ge the intersects\n\t\t\tthis.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld );\n\t\t\tthis.getBoundingBoxAt( geometryId, _mesh.geometry.boundingBox );\n\t\t\tthis.getBoundingSphereAt( geometryId, _mesh.geometry.boundingSphere );\n\t\t\t_mesh.raycast( raycaster, _batchIntersects );\n\n\t\t\t// add batch id to the intersects\n\t\t\tfor ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) {\n\n\t\t\t\tconst intersect = _batchIntersects[ j ];\n\t\t\t\tintersect.object = this;\n\t\t\t\tintersect.batchId = i;\n\t\t\t\tintersects.push( intersect );\n\n\t\t\t}\n\n\t\t\t_batchIntersects.length = 0;\n\n\t\t}\n\n\t\t_mesh.material = null;\n\t\t_mesh.geometry.index = null;\n\t\t_mesh.geometry.attributes = {};\n\t\t_mesh.geometry.setDrawRange( 0, Infinity );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.geometry = source.geometry.clone();\n\t\tthis.perObjectFrustumCulled = source.perObjectFrustumCulled;\n\t\tthis.sortObjects = source.sortObjects;\n\t\tthis.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null;\n\t\tthis.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null;\n\n\t\tthis._drawRanges = source._drawRanges.map( range => ( { ...range } ) );\n\t\tthis._reservedRanges = source._reservedRanges.map( range => ( { ...range } ) );\n\n\t\tthis._drawInfo = source._drawInfo.map( inf => ( { ...inf } ) );\n\t\tthis._bounds = source._bounds.map( bound => ( {\n\t\t\tboxInitialized: bound.boxInitialized,\n\t\t\tbox: bound.box.clone(),\n\n\t\t\tsphereInitialized: bound.sphereInitialized,\n\t\t\tsphere: bound.sphere.clone()\n\t\t} ) );\n\n\t\tthis._maxInstanceCount = source._maxInstanceCount;\n\t\tthis._maxVertexCount = source._maxVertexCount;\n\t\tthis._maxIndexCount = source._maxIndexCount;\n\n\t\tthis._geometryInitialized = source._geometryInitialized;\n\t\tthis._geometryCount = source._geometryCount;\n\t\tthis._multiDrawCounts = source._multiDrawCounts.slice();\n\t\tthis._multiDrawStarts = source._multiDrawStarts.slice();\n\n\t\tthis._matricesTexture = source._matricesTexture.clone();\n\t\tthis._matricesTexture.image.data = this._matricesTexture.image.slice();\n\n\t\tif ( this._colorsTexture !== null ) {\n\n\t\t\tthis._colorsTexture = source._colorsTexture.clone();\n\t\t\tthis._colorsTexture.image.data = this._colorsTexture.image.slice();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\t// Assuming the geometry is not shared with other meshes\n\t\tthis.geometry.dispose();\n\n\t\tthis._matricesTexture.dispose();\n\t\tthis._matricesTexture = null;\n\n\t\tthis._indirectTexture.dispose();\n\t\tthis._indirectTexture = null;\n\n\t\tif ( this._colorsTexture !== null ) {\n\n\t\t\tthis._colorsTexture.dispose();\n\t\t\tthis._colorsTexture = null;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tonBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) {\n\n\t\t// if visibility has not changed and frustum culling and object sorting is not required\n\t\t// then skip iterating over all items\n\t\tif ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && ! this.sortObjects ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t// the indexed version of the multi draw function requires specifying the start\n\t\t// offset in bytes.\n\t\tconst index = geometry.getIndex();\n\t\tconst bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT;\n\n\t\tconst drawInfo = this._drawInfo;\n\t\tconst multiDrawStarts = this._multiDrawStarts;\n\t\tconst multiDrawCounts = this._multiDrawCounts;\n\t\tconst drawRanges = this._drawRanges;\n\t\tconst perObjectFrustumCulled = this.perObjectFrustumCulled;\n\t\tconst indirectTexture = this._indirectTexture;\n\t\tconst indirectArray = indirectTexture.image.data;\n\n\t\t// prepare the frustum in the local frame\n\t\tif ( perObjectFrustumCulled ) {\n\n\t\t\t_projScreenMatrix$2\n\t\t\t\t.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse )\n\t\t\t\t.multiply( this.matrixWorld );\n\t\t\t_frustum.setFromProjectionMatrix(\n\t\t\t\t_projScreenMatrix$2,\n\t\t\t\trenderer.coordinateSystem\n\t\t\t);\n\n\t\t}\n\n\t\tlet count = 0;\n\t\tif ( this.sortObjects ) {\n\n\t\t\t// get the camera position in the local frame\n\t\t\t_invMatrixWorld.copy( this.matrixWorld ).invert();\n\t\t\t_vector$5.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _invMatrixWorld );\n\t\t\t_forward.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ).transformDirection( _invMatrixWorld );\n\n\t\t\tfor ( let i = 0, l = drawInfo.length; i < l; i ++ ) {\n\n\t\t\t\tif ( drawInfo[ i ].visible && drawInfo[ i ].active ) {\n\n\t\t\t\t\tconst geometryId = drawInfo[ i ].geometryIndex;\n\n\t\t\t\t\t// get the bounds in world space\n\t\t\t\t\tthis.getMatrixAt( i, _matrix$1 );\n\t\t\t\t\tthis.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 );\n\n\t\t\t\t\t// determine whether the batched geometry is within the frustum\n\t\t\t\t\tlet culled = false;\n\t\t\t\t\tif ( perObjectFrustumCulled ) {\n\n\t\t\t\t\t\tculled = ! _frustum.intersectsSphere( _sphere$2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! culled ) {\n\n\t\t\t\t\t\t// get the distance from camera used for sorting\n\t\t\t\t\t\tconst z = _temp.subVectors( _sphere$2.center, _vector$5 ).dot( _forward );\n\t\t\t\t\t\t_renderList.push( drawRanges[ geometryId ], z, i );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// Sort the draw ranges and prep for rendering\n\t\t\tconst list = _renderList.list;\n\t\t\tconst customSort = this.customSort;\n\t\t\tif ( customSort === null ) {\n\n\t\t\t\tlist.sort( material.transparent ? sortTransparent : sortOpaque );\n\n\t\t\t} else {\n\n\t\t\t\tcustomSort.call( this, list, camera );\n\n\t\t\t}\n\n\t\t\tfor ( let i = 0, l = list.length; i < l; i ++ ) {\n\n\t\t\t\tconst item = list[ i ];\n\t\t\t\tmultiDrawStarts[ count ] = item.start * bytesPerElement;\n\t\t\t\tmultiDrawCounts[ count ] = item.count;\n\t\t\t\tindirectArray[ count ] = item.index;\n\t\t\t\tcount ++;\n\n\t\t\t}\n\n\t\t\t_renderList.reset();\n\n\t\t} else {\n\n\t\t\tfor ( let i = 0, l = drawInfo.length; i < l; i ++ ) {\n\n\t\t\t\tif ( drawInfo[ i ].visible && drawInfo[ i ].active ) {\n\n\t\t\t\t\tconst geometryId = drawInfo[ i ].geometryIndex;\n\n\t\t\t\t\t// determine whether the batched geometry is within the frustum\n\t\t\t\t\tlet culled = false;\n\t\t\t\t\tif ( perObjectFrustumCulled ) {\n\n\t\t\t\t\t\t// get the bounds in world space\n\t\t\t\t\t\tthis.getMatrixAt( i, _matrix$1 );\n\t\t\t\t\t\tthis.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 );\n\t\t\t\t\t\tculled = ! _frustum.intersectsSphere( _sphere$2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! culled ) {\n\n\t\t\t\t\t\tconst range = drawRanges[ geometryId ];\n\t\t\t\t\t\tmultiDrawStarts[ count ] = range.start * bytesPerElement;\n\t\t\t\t\t\tmultiDrawCounts[ count ] = range.count;\n\t\t\t\t\t\tindirectArray[ count ] = i;\n\t\t\t\t\t\tcount ++;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tindirectTexture.needsUpdate = true;\n\t\tthis._multiDrawCount = count;\n\t\tthis._visibilityChanged = false;\n\n\t}\n\n\tonBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */ ) {\n\n\t\tthis.onBeforeRender( renderer, null, shadowCamera, geometry, depthMaterial );\n\n\t}\n\n}\n\nclass LineBasicMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isLineBasicMaterial = true;\n\n\t\tthis.type = 'LineBasicMaterial';\n\n\t\tthis.color = new Color( 0xffffff );\n\n\t\tthis.map = null;\n\n\t\tthis.linewidth = 1;\n\t\tthis.linecap = 'round';\n\t\tthis.linejoin = 'round';\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.linewidth = source.linewidth;\n\t\tthis.linecap = source.linecap;\n\t\tthis.linejoin = source.linejoin;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _vStart = /*@__PURE__*/ new Vector3();\nconst _vEnd = /*@__PURE__*/ new Vector3();\n\nconst _inverseMatrix$1 = /*@__PURE__*/ new Matrix4();\nconst _ray$1 = /*@__PURE__*/ new Ray();\nconst _sphere$1 = /*@__PURE__*/ new Sphere();\n\nconst _intersectPointOnRay = /*@__PURE__*/ new Vector3();\nconst _intersectPointOnSegment = /*@__PURE__*/ new Vector3();\n\nclass Line extends Object3D {\n\n\tconstructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) {\n\n\t\tsuper();\n\n\t\tthis.isLine = true;\n\n\t\tthis.type = 'Line';\n\n\t\tthis.geometry = geometry;\n\t\tthis.material = material;\n\n\t\tthis.updateMorphTargets();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.material = Array.isArray( source.material ) ? source.material.slice() : source.material;\n\t\tthis.geometry = source.geometry;\n\n\t\treturn this;\n\n\t}\n\n\tcomputeLineDistances() {\n\n\t\tconst geometry = this.geometry;\n\n\t\t// we assume non-indexed geometry\n\n\t\tif ( geometry.index === null ) {\n\n\t\t\tconst positionAttribute = geometry.attributes.position;\n\t\t\tconst lineDistances = [ 0 ];\n\n\t\t\tfor ( let i = 1, l = positionAttribute.count; i < l; i ++ ) {\n\n\t\t\t\t_vStart.fromBufferAttribute( positionAttribute, i - 1 );\n\t\t\t\t_vEnd.fromBufferAttribute( positionAttribute, i );\n\n\t\t\t\tlineDistances[ i ] = lineDistances[ i - 1 ];\n\t\t\t\tlineDistances[ i ] += _vStart.distanceTo( _vEnd );\n\n\t\t\t}\n\n\t\t\tgeometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst matrixWorld = this.matrixWorld;\n\t\tconst threshold = raycaster.params.Line.threshold;\n\t\tconst drawRange = geometry.drawRange;\n\n\t\t// Checking boundingSphere distance to ray\n\n\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t_sphere$1.copy( geometry.boundingSphere );\n\t\t_sphere$1.applyMatrix4( matrixWorld );\n\t\t_sphere$1.radius += threshold;\n\n\t\tif ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return;\n\n\t\t//\n\n\t\t_inverseMatrix$1.copy( matrixWorld ).invert();\n\t\t_ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 );\n\n\t\tconst localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );\n\t\tconst localThresholdSq = localThreshold * localThreshold;\n\n\t\tconst step = this.isLineSegments ? 2 : 1;\n\n\t\tconst index = geometry.index;\n\t\tconst attributes = geometry.attributes;\n\t\tconst positionAttribute = attributes.position;\n\n\t\tif ( index !== null ) {\n\n\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\tconst end = Math.min( index.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\tfor ( let i = start, l = end - 1; i < l; i += step ) {\n\n\t\t\t\tconst a = index.getX( i );\n\t\t\t\tconst b = index.getX( i + 1 );\n\n\t\t\t\tconst intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b );\n\n\t\t\t\tif ( intersect ) {\n\n\t\t\t\t\tintersects.push( intersect );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.isLineLoop ) {\n\n\t\t\t\tconst a = index.getX( end - 1 );\n\t\t\t\tconst b = index.getX( start );\n\n\t\t\t\tconst intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b );\n\n\t\t\t\tif ( intersect ) {\n\n\t\t\t\t\tintersects.push( intersect );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\tconst end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\tfor ( let i = start, l = end - 1; i < l; i += step ) {\n\n\t\t\t\tconst intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, i, i + 1 );\n\n\t\t\t\tif ( intersect ) {\n\n\t\t\t\t\tintersects.push( intersect );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.isLineLoop ) {\n\n\t\t\t\tconst intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, end - 1, start );\n\n\t\t\t\tif ( intersect ) {\n\n\t\t\t\t\tintersects.push( intersect );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tupdateMorphTargets() {\n\n\t\tconst geometry = this.geometry;\n\n\t\tconst morphAttributes = geometry.morphAttributes;\n\t\tconst keys = Object.keys( morphAttributes );\n\n\t\tif ( keys.length > 0 ) {\n\n\t\t\tconst morphAttribute = morphAttributes[ keys[ 0 ] ];\n\n\t\t\tif ( morphAttribute !== undefined ) {\n\n\t\t\t\tthis.morphTargetInfluences = [];\n\t\t\t\tthis.morphTargetDictionary = {};\n\n\t\t\t\tfor ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {\n\n\t\t\t\t\tconst name = morphAttribute[ m ].name || String( m );\n\n\t\t\t\t\tthis.morphTargetInfluences.push( 0 );\n\t\t\t\t\tthis.morphTargetDictionary[ name ] = m;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nfunction checkIntersection( object, raycaster, ray, thresholdSq, a, b ) {\n\n\tconst positionAttribute = object.geometry.attributes.position;\n\n\t_vStart.fromBufferAttribute( positionAttribute, a );\n\t_vEnd.fromBufferAttribute( positionAttribute, b );\n\n\tconst distSq = ray.distanceSqToSegment( _vStart, _vEnd, _intersectPointOnRay, _intersectPointOnSegment );\n\n\tif ( distSq > thresholdSq ) return;\n\n\t_intersectPointOnRay.applyMatrix4( object.matrixWorld ); // Move back to world space for distance calculation\n\n\tconst distance = raycaster.ray.origin.distanceTo( _intersectPointOnRay );\n\n\tif ( distance < raycaster.near || distance > raycaster.far ) return;\n\n\treturn {\n\n\t\tdistance: distance,\n\t\t// What do we want? intersection point on the ray or on the segment??\n\t\t// point: raycaster.ray.at( distance ),\n\t\tpoint: _intersectPointOnSegment.clone().applyMatrix4( object.matrixWorld ),\n\t\tindex: a,\n\t\tface: null,\n\t\tfaceIndex: null,\n\t\tobject: object\n\n\t};\n\n}\n\nconst _start = /*@__PURE__*/ new Vector3();\nconst _end = /*@__PURE__*/ new Vector3();\n\nclass LineSegments extends Line {\n\n\tconstructor( geometry, material ) {\n\n\t\tsuper( geometry, material );\n\n\t\tthis.isLineSegments = true;\n\n\t\tthis.type = 'LineSegments';\n\n\t}\n\n\tcomputeLineDistances() {\n\n\t\tconst geometry = this.geometry;\n\n\t\t// we assume non-indexed geometry\n\n\t\tif ( geometry.index === null ) {\n\n\t\t\tconst positionAttribute = geometry.attributes.position;\n\t\t\tconst lineDistances = [];\n\n\t\t\tfor ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {\n\n\t\t\t\t_start.fromBufferAttribute( positionAttribute, i );\n\t\t\t\t_end.fromBufferAttribute( positionAttribute, i + 1 );\n\n\t\t\t\tlineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];\n\t\t\t\tlineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end );\n\n\t\t\t}\n\n\t\t\tgeometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass LineLoop extends Line {\n\n\tconstructor( geometry, material ) {\n\n\t\tsuper( geometry, material );\n\n\t\tthis.isLineLoop = true;\n\n\t\tthis.type = 'LineLoop';\n\n\t}\n\n}\n\nclass PointsMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isPointsMaterial = true;\n\n\t\tthis.type = 'PointsMaterial';\n\n\t\tthis.color = new Color( 0xffffff );\n\n\t\tthis.map = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.size = 1;\n\t\tthis.sizeAttenuation = true;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.size = source.size;\n\t\tthis.sizeAttenuation = source.sizeAttenuation;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _inverseMatrix = /*@__PURE__*/ new Matrix4();\nconst _ray = /*@__PURE__*/ new Ray();\nconst _sphere = /*@__PURE__*/ new Sphere();\nconst _position$2 = /*@__PURE__*/ new Vector3();\n\nclass Points extends Object3D {\n\n\tconstructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) {\n\n\t\tsuper();\n\n\t\tthis.isPoints = true;\n\n\t\tthis.type = 'Points';\n\n\t\tthis.geometry = geometry;\n\t\tthis.material = material;\n\n\t\tthis.updateMorphTargets();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.material = Array.isArray( source.material ) ? source.material.slice() : source.material;\n\t\tthis.geometry = source.geometry;\n\n\t\treturn this;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst matrixWorld = this.matrixWorld;\n\t\tconst threshold = raycaster.params.Points.threshold;\n\t\tconst drawRange = geometry.drawRange;\n\n\t\t// Checking boundingSphere distance to ray\n\n\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t_sphere.copy( geometry.boundingSphere );\n\t\t_sphere.applyMatrix4( matrixWorld );\n\t\t_sphere.radius += threshold;\n\n\t\tif ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;\n\n\t\t//\n\n\t\t_inverseMatrix.copy( matrixWorld ).invert();\n\t\t_ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );\n\n\t\tconst localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );\n\t\tconst localThresholdSq = localThreshold * localThreshold;\n\n\t\tconst index = geometry.index;\n\t\tconst attributes = geometry.attributes;\n\t\tconst positionAttribute = attributes.position;\n\n\t\tif ( index !== null ) {\n\n\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\tconst end = Math.min( index.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\tfor ( let i = start, il = end; i < il; i ++ ) {\n\n\t\t\t\tconst a = index.getX( i );\n\n\t\t\t\t_position$2.fromBufferAttribute( positionAttribute, a );\n\n\t\t\t\ttestPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\tconst end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\tfor ( let i = start, l = end; i < l; i ++ ) {\n\n\t\t\t\t_position$2.fromBufferAttribute( positionAttribute, i );\n\n\t\t\t\ttestPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tupdateMorphTargets() {\n\n\t\tconst geometry = this.geometry;\n\n\t\tconst morphAttributes = geometry.morphAttributes;\n\t\tconst keys = Object.keys( morphAttributes );\n\n\t\tif ( keys.length > 0 ) {\n\n\t\t\tconst morphAttribute = morphAttributes[ keys[ 0 ] ];\n\n\t\t\tif ( morphAttribute !== undefined ) {\n\n\t\t\t\tthis.morphTargetInfluences = [];\n\t\t\t\tthis.morphTargetDictionary = {};\n\n\t\t\t\tfor ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {\n\n\t\t\t\t\tconst name = morphAttribute[ m ].name || String( m );\n\n\t\t\t\t\tthis.morphTargetInfluences.push( 0 );\n\t\t\t\t\tthis.morphTargetDictionary[ name ] = m;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nfunction testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {\n\n\tconst rayPointDistanceSq = _ray.distanceSqToPoint( point );\n\n\tif ( rayPointDistanceSq < localThresholdSq ) {\n\n\t\tconst intersectPoint = new Vector3();\n\n\t\t_ray.closestPointToPoint( point, intersectPoint );\n\t\tintersectPoint.applyMatrix4( matrixWorld );\n\n\t\tconst distance = raycaster.ray.origin.distanceTo( intersectPoint );\n\n\t\tif ( distance < raycaster.near || distance > raycaster.far ) return;\n\n\t\tintersects.push( {\n\n\t\t\tdistance: distance,\n\t\t\tdistanceToRay: Math.sqrt( rayPointDistanceSq ),\n\t\t\tpoint: intersectPoint,\n\t\t\tindex: index,\n\t\t\tface: null,\n\t\t\tobject: object\n\n\t\t} );\n\n\t}\n\n}\n\nclass VideoTexture extends Texture {\n\n\tconstructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {\n\n\t\tsuper( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\t\tthis.isVideoTexture = true;\n\n\t\tthis.minFilter = minFilter !== undefined ? minFilter : LinearFilter;\n\t\tthis.magFilter = magFilter !== undefined ? magFilter : LinearFilter;\n\n\t\tthis.generateMipmaps = false;\n\n\t\tconst scope = this;\n\n\t\tfunction updateVideo() {\n\n\t\t\tscope.needsUpdate = true;\n\t\t\tvideo.requestVideoFrameCallback( updateVideo );\n\n\t\t}\n\n\t\tif ( 'requestVideoFrameCallback' in video ) {\n\n\t\t\tvideo.requestVideoFrameCallback( updateVideo );\n\n\t\t}\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.image ).copy( this );\n\n\t}\n\n\tupdate() {\n\n\t\tconst video = this.image;\n\t\tconst hasVideoFrameCallback = 'requestVideoFrameCallback' in video;\n\n\t\tif ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) {\n\n\t\t\tthis.needsUpdate = true;\n\n\t\t}\n\n\t}\n\n}\n\nclass FramebufferTexture extends Texture {\n\n\tconstructor( width, height ) {\n\n\t\tsuper( { width, height } );\n\n\t\tthis.isFramebufferTexture = true;\n\n\t\tthis.magFilter = NearestFilter;\n\t\tthis.minFilter = NearestFilter;\n\n\t\tthis.generateMipmaps = false;\n\n\t\tthis.needsUpdate = true;\n\n\t}\n\n}\n\nclass CompressedTexture extends Texture {\n\n\tconstructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, colorSpace ) {\n\n\t\tsuper( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );\n\n\t\tthis.isCompressedTexture = true;\n\n\t\tthis.image = { width: width, height: height };\n\t\tthis.mipmaps = mipmaps;\n\n\t\t// no flipping for cube textures\n\t\t// (also flipping doesn't work for compressed textures )\n\n\t\tthis.flipY = false;\n\n\t\t// can't generate mipmaps for compressed textures\n\t\t// mips must be embedded in DDS files\n\n\t\tthis.generateMipmaps = false;\n\n\t}\n\n}\n\nclass CompressedArrayTexture extends CompressedTexture {\n\n\tconstructor( mipmaps, width, height, depth, format, type ) {\n\n\t\tsuper( mipmaps, width, height, format, type );\n\n\t\tthis.isCompressedArrayTexture = true;\n\t\tthis.image.depth = depth;\n\t\tthis.wrapR = ClampToEdgeWrapping;\n\n\t\tthis.layerUpdates = new Set();\n\n\t}\n\n\taddLayerUpdate( layerIndex ) {\n\n\t\tthis.layerUpdates.add( layerIndex );\n\n\t}\n\n\tclearLayerUpdates() {\n\n\t\tthis.layerUpdates.clear();\n\n\t}\n\n}\n\nclass CompressedCubeTexture extends CompressedTexture {\n\n\tconstructor( images, format, type ) {\n\n\t\tsuper( undefined, images[ 0 ].width, images[ 0 ].height, format, type, CubeReflectionMapping );\n\n\t\tthis.isCompressedCubeTexture = true;\n\t\tthis.isCubeTexture = true;\n\n\t\tthis.image = images;\n\n\t}\n\n}\n\nclass CanvasTexture extends Texture {\n\n\tconstructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {\n\n\t\tsuper( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\t\tthis.isCanvasTexture = true;\n\n\t\tthis.needsUpdate = true;\n\n\t}\n\n}\n\n/**\n * Extensible curve object.\n *\n * Some common of curve methods:\n * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )\n * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )\n * .getPoints(), .getSpacedPoints()\n * .getLength()\n * .updateArcLengths()\n *\n * This following curves inherit from THREE.Curve:\n *\n * -- 2D curves --\n * THREE.ArcCurve\n * THREE.CubicBezierCurve\n * THREE.EllipseCurve\n * THREE.LineCurve\n * THREE.QuadraticBezierCurve\n * THREE.SplineCurve\n *\n * -- 3D curves --\n * THREE.CatmullRomCurve3\n * THREE.CubicBezierCurve3\n * THREE.LineCurve3\n * THREE.QuadraticBezierCurve3\n *\n * A series of curves can be represented as a THREE.CurvePath.\n *\n **/\n\nclass Curve {\n\n\tconstructor() {\n\n\t\tthis.type = 'Curve';\n\n\t\tthis.arcLengthDivisions = 200;\n\n\t}\n\n\t// Virtual base class method to overwrite and implement in subclasses\n\t//\t- t [0 .. 1]\n\n\tgetPoint( /* t, optionalTarget */ ) {\n\n\t\tconsole.warn( 'THREE.Curve: .getPoint() not implemented.' );\n\t\treturn null;\n\n\t}\n\n\t// Get point at relative position in curve according to arc length\n\t// - u [0 .. 1]\n\n\tgetPointAt( u, optionalTarget ) {\n\n\t\tconst t = this.getUtoTmapping( u );\n\t\treturn this.getPoint( t, optionalTarget );\n\n\t}\n\n\t// Get sequence of points using getPoint( t )\n\n\tgetPoints( divisions = 5 ) {\n\n\t\tconst points = [];\n\n\t\tfor ( let d = 0; d <= divisions; d ++ ) {\n\n\t\t\tpoints.push( this.getPoint( d / divisions ) );\n\n\t\t}\n\n\t\treturn points;\n\n\t}\n\n\t// Get sequence of points using getPointAt( u )\n\n\tgetSpacedPoints( divisions = 5 ) {\n\n\t\tconst points = [];\n\n\t\tfor ( let d = 0; d <= divisions; d ++ ) {\n\n\t\t\tpoints.push( this.getPointAt( d / divisions ) );\n\n\t\t}\n\n\t\treturn points;\n\n\t}\n\n\t// Get total curve arc length\n\n\tgetLength() {\n\n\t\tconst lengths = this.getLengths();\n\t\treturn lengths[ lengths.length - 1 ];\n\n\t}\n\n\t// Get list of cumulative segment lengths\n\n\tgetLengths( divisions = this.arcLengthDivisions ) {\n\n\t\tif ( this.cacheArcLengths &&\n\t\t\t( this.cacheArcLengths.length === divisions + 1 ) &&\n\t\t\t! this.needsUpdate ) {\n\n\t\t\treturn this.cacheArcLengths;\n\n\t\t}\n\n\t\tthis.needsUpdate = false;\n\n\t\tconst cache = [];\n\t\tlet current, last = this.getPoint( 0 );\n\t\tlet sum = 0;\n\n\t\tcache.push( 0 );\n\n\t\tfor ( let p = 1; p <= divisions; p ++ ) {\n\n\t\t\tcurrent = this.getPoint( p / divisions );\n\t\t\tsum += current.distanceTo( last );\n\t\t\tcache.push( sum );\n\t\t\tlast = current;\n\n\t\t}\n\n\t\tthis.cacheArcLengths = cache;\n\n\t\treturn cache; // { sums: cache, sum: sum }; Sum is in the last element.\n\n\t}\n\n\tupdateArcLengths() {\n\n\t\tthis.needsUpdate = true;\n\t\tthis.getLengths();\n\n\t}\n\n\t// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant\n\n\tgetUtoTmapping( u, distance ) {\n\n\t\tconst arcLengths = this.getLengths();\n\n\t\tlet i = 0;\n\t\tconst il = arcLengths.length;\n\n\t\tlet targetArcLength; // The targeted u distance value to get\n\n\t\tif ( distance ) {\n\n\t\t\ttargetArcLength = distance;\n\n\t\t} else {\n\n\t\t\ttargetArcLength = u * arcLengths[ il - 1 ];\n\n\t\t}\n\n\t\t// binary search for the index with largest value smaller than target u distance\n\n\t\tlet low = 0, high = il - 1, comparison;\n\n\t\twhile ( low <= high ) {\n\n\t\t\ti = 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\n\n\t\t\tcomparison = arcLengths[ i ] - targetArcLength;\n\n\t\t\tif ( comparison < 0 ) {\n\n\t\t\t\tlow = i + 1;\n\n\t\t\t} else if ( comparison > 0 ) {\n\n\t\t\t\thigh = i - 1;\n\n\t\t\t} else {\n\n\t\t\t\thigh = i;\n\t\t\t\tbreak;\n\n\t\t\t\t// DONE\n\n\t\t\t}\n\n\t\t}\n\n\t\ti = high;\n\n\t\tif ( arcLengths[ i ] === targetArcLength ) {\n\n\t\t\treturn i / ( il - 1 );\n\n\t\t}\n\n\t\t// we could get finer grain at lengths, or use simple interpolation between two points\n\n\t\tconst lengthBefore = arcLengths[ i ];\n\t\tconst lengthAfter = arcLengths[ i + 1 ];\n\n\t\tconst segmentLength = lengthAfter - lengthBefore;\n\n\t\t// determine where we are between the 'before' and 'after' points\n\n\t\tconst segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;\n\n\t\t// add that fractional amount to t\n\n\t\tconst t = ( i + segmentFraction ) / ( il - 1 );\n\n\t\treturn t;\n\n\t}\n\n\t// Returns a unit vector tangent at t\n\t// In case any sub curve does not implement its tangent derivation,\n\t// 2 points a small delta apart will be used to find its gradient\n\t// which seems to give a reasonable approximation\n\n\tgetTangent( t, optionalTarget ) {\n\n\t\tconst delta = 0.0001;\n\t\tlet t1 = t - delta;\n\t\tlet t2 = t + delta;\n\n\t\t// Capping in case of danger\n\n\t\tif ( t1 < 0 ) t1 = 0;\n\t\tif ( t2 > 1 ) t2 = 1;\n\n\t\tconst pt1 = this.getPoint( t1 );\n\t\tconst pt2 = this.getPoint( t2 );\n\n\t\tconst tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() );\n\n\t\ttangent.copy( pt2 ).sub( pt1 ).normalize();\n\n\t\treturn tangent;\n\n\t}\n\n\tgetTangentAt( u, optionalTarget ) {\n\n\t\tconst t = this.getUtoTmapping( u );\n\t\treturn this.getTangent( t, optionalTarget );\n\n\t}\n\n\tcomputeFrenetFrames( segments, closed ) {\n\n\t\t// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf\n\n\t\tconst normal = new Vector3();\n\n\t\tconst tangents = [];\n\t\tconst normals = [];\n\t\tconst binormals = [];\n\n\t\tconst vec = new Vector3();\n\t\tconst mat = new Matrix4();\n\n\t\t// compute the tangent vectors for each segment on the curve\n\n\t\tfor ( let i = 0; i <= segments; i ++ ) {\n\n\t\t\tconst u = i / segments;\n\n\t\t\ttangents[ i ] = this.getTangentAt( u, new Vector3() );\n\n\t\t}\n\n\t\t// select an initial normal vector perpendicular to the first tangent vector,\n\t\t// and in the direction of the minimum tangent xyz component\n\n\t\tnormals[ 0 ] = new Vector3();\n\t\tbinormals[ 0 ] = new Vector3();\n\t\tlet min = Number.MAX_VALUE;\n\t\tconst tx = Math.abs( tangents[ 0 ].x );\n\t\tconst ty = Math.abs( tangents[ 0 ].y );\n\t\tconst tz = Math.abs( tangents[ 0 ].z );\n\n\t\tif ( tx <= min ) {\n\n\t\t\tmin = tx;\n\t\t\tnormal.set( 1, 0, 0 );\n\n\t\t}\n\n\t\tif ( ty <= min ) {\n\n\t\t\tmin = ty;\n\t\t\tnormal.set( 0, 1, 0 );\n\n\t\t}\n\n\t\tif ( tz <= min ) {\n\n\t\t\tnormal.set( 0, 0, 1 );\n\n\t\t}\n\n\t\tvec.crossVectors( tangents[ 0 ], normal ).normalize();\n\n\t\tnormals[ 0 ].crossVectors( tangents[ 0 ], vec );\n\t\tbinormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );\n\n\n\t\t// compute the slowly-varying normal and binormal vectors for each segment on the curve\n\n\t\tfor ( let i = 1; i <= segments; i ++ ) {\n\n\t\t\tnormals[ i ] = normals[ i - 1 ].clone();\n\n\t\t\tbinormals[ i ] = binormals[ i - 1 ].clone();\n\n\t\t\tvec.crossVectors( tangents[ i - 1 ], tangents[ i ] );\n\n\t\t\tif ( vec.length() > Number.EPSILON ) {\n\n\t\t\t\tvec.normalize();\n\n\t\t\t\tconst theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors\n\n\t\t\t\tnormals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );\n\n\t\t\t}\n\n\t\t\tbinormals[ i ].crossVectors( tangents[ i ], normals[ i ] );\n\n\t\t}\n\n\t\t// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same\n\n\t\tif ( closed === true ) {\n\n\t\t\tlet theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );\n\t\t\ttheta /= segments;\n\n\t\t\tif ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {\n\n\t\t\t\ttheta = - theta;\n\n\t\t\t}\n\n\t\t\tfor ( let i = 1; i <= segments; i ++ ) {\n\n\t\t\t\t// twist a little...\n\t\t\t\tnormals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );\n\t\t\t\tbinormals[ i ].crossVectors( tangents[ i ], normals[ i ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn {\n\t\t\ttangents: tangents,\n\t\t\tnormals: normals,\n\t\t\tbinormals: binormals\n\t\t};\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.arcLengthDivisions = source.arcLengthDivisions;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'Curve',\n\t\t\t\tgenerator: 'Curve.toJSON'\n\t\t\t}\n\t\t};\n\n\t\tdata.arcLengthDivisions = this.arcLengthDivisions;\n\t\tdata.type = this.type;\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tthis.arcLengthDivisions = json.arcLengthDivisions;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass EllipseCurve extends Curve {\n\n\tconstructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) {\n\n\t\tsuper();\n\n\t\tthis.isEllipseCurve = true;\n\n\t\tthis.type = 'EllipseCurve';\n\n\t\tthis.aX = aX;\n\t\tthis.aY = aY;\n\n\t\tthis.xRadius = xRadius;\n\t\tthis.yRadius = yRadius;\n\n\t\tthis.aStartAngle = aStartAngle;\n\t\tthis.aEndAngle = aEndAngle;\n\n\t\tthis.aClockwise = aClockwise;\n\n\t\tthis.aRotation = aRotation;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector2() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst twoPi = Math.PI * 2;\n\t\tlet deltaAngle = this.aEndAngle - this.aStartAngle;\n\t\tconst samePoints = Math.abs( deltaAngle ) < Number.EPSILON;\n\n\t\t// ensures that deltaAngle is 0 .. 2 PI\n\t\twhile ( deltaAngle < 0 ) deltaAngle += twoPi;\n\t\twhile ( deltaAngle > twoPi ) deltaAngle -= twoPi;\n\n\t\tif ( deltaAngle < Number.EPSILON ) {\n\n\t\t\tif ( samePoints ) {\n\n\t\t\t\tdeltaAngle = 0;\n\n\t\t\t} else {\n\n\t\t\t\tdeltaAngle = twoPi;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.aClockwise === true && ! samePoints ) {\n\n\t\t\tif ( deltaAngle === twoPi ) {\n\n\t\t\t\tdeltaAngle = - twoPi;\n\n\t\t\t} else {\n\n\t\t\t\tdeltaAngle = deltaAngle - twoPi;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst angle = this.aStartAngle + t * deltaAngle;\n\t\tlet x = this.aX + this.xRadius * Math.cos( angle );\n\t\tlet y = this.aY + this.yRadius * Math.sin( angle );\n\n\t\tif ( this.aRotation !== 0 ) {\n\n\t\t\tconst cos = Math.cos( this.aRotation );\n\t\t\tconst sin = Math.sin( this.aRotation );\n\n\t\t\tconst tx = x - this.aX;\n\t\t\tconst ty = y - this.aY;\n\n\t\t\t// Rotate the point about the center of the ellipse.\n\t\t\tx = tx * cos - ty * sin + this.aX;\n\t\t\ty = tx * sin + ty * cos + this.aY;\n\n\t\t}\n\n\t\treturn point.set( x, y );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.aX = source.aX;\n\t\tthis.aY = source.aY;\n\n\t\tthis.xRadius = source.xRadius;\n\t\tthis.yRadius = source.yRadius;\n\n\t\tthis.aStartAngle = source.aStartAngle;\n\t\tthis.aEndAngle = source.aEndAngle;\n\n\t\tthis.aClockwise = source.aClockwise;\n\n\t\tthis.aRotation = source.aRotation;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.aX = this.aX;\n\t\tdata.aY = this.aY;\n\n\t\tdata.xRadius = this.xRadius;\n\t\tdata.yRadius = this.yRadius;\n\n\t\tdata.aStartAngle = this.aStartAngle;\n\t\tdata.aEndAngle = this.aEndAngle;\n\n\t\tdata.aClockwise = this.aClockwise;\n\n\t\tdata.aRotation = this.aRotation;\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.aX = json.aX;\n\t\tthis.aY = json.aY;\n\n\t\tthis.xRadius = json.xRadius;\n\t\tthis.yRadius = json.yRadius;\n\n\t\tthis.aStartAngle = json.aStartAngle;\n\t\tthis.aEndAngle = json.aEndAngle;\n\n\t\tthis.aClockwise = json.aClockwise;\n\n\t\tthis.aRotation = json.aRotation;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass ArcCurve extends EllipseCurve {\n\n\tconstructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\t\tsuper( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );\n\n\t\tthis.isArcCurve = true;\n\n\t\tthis.type = 'ArcCurve';\n\n\t}\n\n}\n\n/**\n * Centripetal CatmullRom Curve - which is useful for avoiding\n * cusps and self-intersections in non-uniform catmull rom curves.\n * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf\n *\n * curve.type accepts centripetal(default), chordal and catmullrom\n * curve.tension is used for catmullrom which defaults to 0.5\n */\n\n\n/*\nBased on an optimized c++ solution in\n - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/\n - http://ideone.com/NoEbVM\n\nThis CubicPoly class could be used for reusing some variables and calculations,\nbut for three.js curve use, it could be possible inlined and flatten into a single function call\nwhich can be placed in CurveUtils.\n*/\n\nfunction CubicPoly() {\n\n\tlet c0 = 0, c1 = 0, c2 = 0, c3 = 0;\n\n\t/*\n\t * Compute coefficients for a cubic polynomial\n\t * p(s) = c0 + c1*s + c2*s^2 + c3*s^3\n\t * such that\n\t * p(0) = x0, p(1) = x1\n\t * and\n\t * p'(0) = t0, p'(1) = t1.\n\t */\n\tfunction init( x0, x1, t0, t1 ) {\n\n\t\tc0 = x0;\n\t\tc1 = t0;\n\t\tc2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;\n\t\tc3 = 2 * x0 - 2 * x1 + t0 + t1;\n\n\t}\n\n\treturn {\n\n\t\tinitCatmullRom: function ( x0, x1, x2, x3, tension ) {\n\n\t\t\tinit( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );\n\n\t\t},\n\n\t\tinitNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {\n\n\t\t\t// compute tangents when parameterized in [t1,t2]\n\t\t\tlet t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;\n\t\t\tlet t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;\n\n\t\t\t// rescale tangents for parametrization in [0,1]\n\t\t\tt1 *= dt1;\n\t\t\tt2 *= dt1;\n\n\t\t\tinit( x1, x2, t1, t2 );\n\n\t\t},\n\n\t\tcalc: function ( t ) {\n\n\t\t\tconst t2 = t * t;\n\t\t\tconst t3 = t2 * t;\n\t\t\treturn c0 + c1 * t + c2 * t2 + c3 * t3;\n\n\t\t}\n\n\t};\n\n}\n\n//\n\nconst tmp = /*@__PURE__*/ new Vector3();\nconst px = /*@__PURE__*/ new CubicPoly();\nconst py = /*@__PURE__*/ new CubicPoly();\nconst pz = /*@__PURE__*/ new CubicPoly();\n\nclass CatmullRomCurve3 extends Curve {\n\n\tconstructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {\n\n\t\tsuper();\n\n\t\tthis.isCatmullRomCurve3 = true;\n\n\t\tthis.type = 'CatmullRomCurve3';\n\n\t\tthis.points = points;\n\t\tthis.closed = closed;\n\t\tthis.curveType = curveType;\n\t\tthis.tension = tension;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector3() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst points = this.points;\n\t\tconst l = points.length;\n\n\t\tconst p = ( l - ( this.closed ? 0 : 1 ) ) * t;\n\t\tlet intPoint = Math.floor( p );\n\t\tlet weight = p - intPoint;\n\n\t\tif ( this.closed ) {\n\n\t\t\tintPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;\n\n\t\t} else if ( weight === 0 && intPoint === l - 1 ) {\n\n\t\t\tintPoint = l - 2;\n\t\t\tweight = 1;\n\n\t\t}\n\n\t\tlet p0, p3; // 4 points (p1 & p2 defined below)\n\n\t\tif ( this.closed || intPoint > 0 ) {\n\n\t\t\tp0 = points[ ( intPoint - 1 ) % l ];\n\n\t\t} else {\n\n\t\t\t// extrapolate first point\n\t\t\ttmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );\n\t\t\tp0 = tmp;\n\n\t\t}\n\n\t\tconst p1 = points[ intPoint % l ];\n\t\tconst p2 = points[ ( intPoint + 1 ) % l ];\n\n\t\tif ( this.closed || intPoint + 2 < l ) {\n\n\t\t\tp3 = points[ ( intPoint + 2 ) % l ];\n\n\t\t} else {\n\n\t\t\t// extrapolate last point\n\t\t\ttmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );\n\t\t\tp3 = tmp;\n\n\t\t}\n\n\t\tif ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {\n\n\t\t\t// init Centripetal / Chordal Catmull-Rom\n\t\t\tconst pow = this.curveType === 'chordal' ? 0.5 : 0.25;\n\t\t\tlet dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );\n\t\t\tlet dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );\n\t\t\tlet dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );\n\n\t\t\t// safety check for repeated points\n\t\t\tif ( dt1 < 1e-4 ) dt1 = 1.0;\n\t\t\tif ( dt0 < 1e-4 ) dt0 = dt1;\n\t\t\tif ( dt2 < 1e-4 ) dt2 = dt1;\n\n\t\t\tpx.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );\n\t\t\tpy.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );\n\t\t\tpz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );\n\n\t\t} else if ( this.curveType === 'catmullrom' ) {\n\n\t\t\tpx.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );\n\t\t\tpy.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );\n\t\t\tpz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );\n\n\t\t}\n\n\t\tpoint.set(\n\t\t\tpx.calc( weight ),\n\t\t\tpy.calc( weight ),\n\t\t\tpz.calc( weight )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.points = [];\n\n\t\tfor ( let i = 0, l = source.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = source.points[ i ];\n\n\t\t\tthis.points.push( point.clone() );\n\n\t\t}\n\n\t\tthis.closed = source.closed;\n\t\tthis.curveType = source.curveType;\n\t\tthis.tension = source.tension;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.points = [];\n\n\t\tfor ( let i = 0, l = this.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = this.points[ i ];\n\t\t\tdata.points.push( point.toArray() );\n\n\t\t}\n\n\t\tdata.closed = this.closed;\n\t\tdata.curveType = this.curveType;\n\t\tdata.tension = this.tension;\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.points = [];\n\n\t\tfor ( let i = 0, l = json.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = json.points[ i ];\n\t\t\tthis.points.push( new Vector3().fromArray( point ) );\n\n\t\t}\n\n\t\tthis.closed = json.closed;\n\t\tthis.curveType = json.curveType;\n\t\tthis.tension = json.tension;\n\n\t\treturn this;\n\n\t}\n\n}\n\n/**\n * Bezier Curves formulas obtained from\n * https://en.wikipedia.org/wiki/B%C3%A9zier_curve\n */\n\nfunction CatmullRom( t, p0, p1, p2, p3 ) {\n\n\tconst v0 = ( p2 - p0 ) * 0.5;\n\tconst v1 = ( p3 - p1 ) * 0.5;\n\tconst t2 = t * t;\n\tconst t3 = t * t2;\n\treturn ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;\n\n}\n\n//\n\nfunction QuadraticBezierP0( t, p ) {\n\n\tconst k = 1 - t;\n\treturn k * k * p;\n\n}\n\nfunction QuadraticBezierP1( t, p ) {\n\n\treturn 2 * ( 1 - t ) * t * p;\n\n}\n\nfunction QuadraticBezierP2( t, p ) {\n\n\treturn t * t * p;\n\n}\n\nfunction QuadraticBezier( t, p0, p1, p2 ) {\n\n\treturn QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +\n\t\tQuadraticBezierP2( t, p2 );\n\n}\n\n//\n\nfunction CubicBezierP0( t, p ) {\n\n\tconst k = 1 - t;\n\treturn k * k * k * p;\n\n}\n\nfunction CubicBezierP1( t, p ) {\n\n\tconst k = 1 - t;\n\treturn 3 * k * k * t * p;\n\n}\n\nfunction CubicBezierP2( t, p ) {\n\n\treturn 3 * ( 1 - t ) * t * t * p;\n\n}\n\nfunction CubicBezierP3( t, p ) {\n\n\treturn t * t * t * p;\n\n}\n\nfunction CubicBezier( t, p0, p1, p2, p3 ) {\n\n\treturn CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +\n\t\tCubicBezierP3( t, p3 );\n\n}\n\nclass CubicBezierCurve extends Curve {\n\n\tconstructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) {\n\n\t\tsuper();\n\n\t\tthis.isCubicBezierCurve = true;\n\n\t\tthis.type = 'CubicBezierCurve';\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\t\tthis.v3 = v3;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector2() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;\n\n\t\tpoint.set(\n\t\t\tCubicBezier( t, v0.x, v1.x, v2.x, v3.x ),\n\t\t\tCubicBezier( t, v0.y, v1.y, v2.y, v3.y )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v0.copy( source.v0 );\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\t\tthis.v3.copy( source.v3 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v0 = this.v0.toArray();\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\t\tdata.v3 = this.v3.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v0.fromArray( json.v0 );\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\t\tthis.v3.fromArray( json.v3 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass CubicBezierCurve3 extends Curve {\n\n\tconstructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {\n\n\t\tsuper();\n\n\t\tthis.isCubicBezierCurve3 = true;\n\n\t\tthis.type = 'CubicBezierCurve3';\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\t\tthis.v3 = v3;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector3() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;\n\n\t\tpoint.set(\n\t\t\tCubicBezier( t, v0.x, v1.x, v2.x, v3.x ),\n\t\t\tCubicBezier( t, v0.y, v1.y, v2.y, v3.y ),\n\t\t\tCubicBezier( t, v0.z, v1.z, v2.z, v3.z )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v0.copy( source.v0 );\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\t\tthis.v3.copy( source.v3 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v0 = this.v0.toArray();\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\t\tdata.v3 = this.v3.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v0.fromArray( json.v0 );\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\t\tthis.v3.fromArray( json.v3 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass LineCurve extends Curve {\n\n\tconstructor( v1 = new Vector2(), v2 = new Vector2() ) {\n\n\t\tsuper();\n\n\t\tthis.isLineCurve = true;\n\n\t\tthis.type = 'LineCurve';\n\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector2() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tif ( t === 1 ) {\n\n\t\t\tpoint.copy( this.v2 );\n\n\t\t} else {\n\n\t\t\tpoint.copy( this.v2 ).sub( this.v1 );\n\t\t\tpoint.multiplyScalar( t ).add( this.v1 );\n\n\t\t}\n\n\t\treturn point;\n\n\t}\n\n\t// Line curve is linear, so we can overwrite default getPointAt\n\tgetPointAt( u, optionalTarget ) {\n\n\t\treturn this.getPoint( u, optionalTarget );\n\n\t}\n\n\tgetTangent( t, optionalTarget = new Vector2() ) {\n\n\t\treturn optionalTarget.subVectors( this.v2, this.v1 ).normalize();\n\n\t}\n\n\tgetTangentAt( u, optionalTarget ) {\n\n\t\treturn this.getTangent( u, optionalTarget );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass LineCurve3 extends Curve {\n\n\tconstructor( v1 = new Vector3(), v2 = new Vector3() ) {\n\n\t\tsuper();\n\n\t\tthis.isLineCurve3 = true;\n\n\t\tthis.type = 'LineCurve3';\n\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector3() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tif ( t === 1 ) {\n\n\t\t\tpoint.copy( this.v2 );\n\n\t\t} else {\n\n\t\t\tpoint.copy( this.v2 ).sub( this.v1 );\n\t\t\tpoint.multiplyScalar( t ).add( this.v1 );\n\n\t\t}\n\n\t\treturn point;\n\n\t}\n\n\t// Line curve is linear, so we can overwrite default getPointAt\n\tgetPointAt( u, optionalTarget ) {\n\n\t\treturn this.getPoint( u, optionalTarget );\n\n\t}\n\n\tgetTangent( t, optionalTarget = new Vector3() ) {\n\n\t\treturn optionalTarget.subVectors( this.v2, this.v1 ).normalize();\n\n\t}\n\n\tgetTangentAt( u, optionalTarget ) {\n\n\t\treturn this.getTangent( u, optionalTarget );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass QuadraticBezierCurve extends Curve {\n\n\tconstructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) {\n\n\t\tsuper();\n\n\t\tthis.isQuadraticBezierCurve = true;\n\n\t\tthis.type = 'QuadraticBezierCurve';\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector2() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst v0 = this.v0, v1 = this.v1, v2 = this.v2;\n\n\t\tpoint.set(\n\t\t\tQuadraticBezier( t, v0.x, v1.x, v2.x ),\n\t\t\tQuadraticBezier( t, v0.y, v1.y, v2.y )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v0.copy( source.v0 );\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v0 = this.v0.toArray();\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v0.fromArray( json.v0 );\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass QuadraticBezierCurve3 extends Curve {\n\n\tconstructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {\n\n\t\tsuper();\n\n\t\tthis.isQuadraticBezierCurve3 = true;\n\n\t\tthis.type = 'QuadraticBezierCurve3';\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector3() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst v0 = this.v0, v1 = this.v1, v2 = this.v2;\n\n\t\tpoint.set(\n\t\t\tQuadraticBezier( t, v0.x, v1.x, v2.x ),\n\t\t\tQuadraticBezier( t, v0.y, v1.y, v2.y ),\n\t\t\tQuadraticBezier( t, v0.z, v1.z, v2.z )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v0.copy( source.v0 );\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v0 = this.v0.toArray();\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v0.fromArray( json.v0 );\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass SplineCurve extends Curve {\n\n\tconstructor( points = [] ) {\n\n\t\tsuper();\n\n\t\tthis.isSplineCurve = true;\n\n\t\tthis.type = 'SplineCurve';\n\n\t\tthis.points = points;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector2() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst points = this.points;\n\t\tconst p = ( points.length - 1 ) * t;\n\n\t\tconst intPoint = Math.floor( p );\n\t\tconst weight = p - intPoint;\n\n\t\tconst p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];\n\t\tconst p1 = points[ intPoint ];\n\t\tconst p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];\n\t\tconst p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];\n\n\t\tpoint.set(\n\t\t\tCatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),\n\t\t\tCatmullRom( weight, p0.y, p1.y, p2.y, p3.y )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.points = [];\n\n\t\tfor ( let i = 0, l = source.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = source.points[ i ];\n\n\t\t\tthis.points.push( point.clone() );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.points = [];\n\n\t\tfor ( let i = 0, l = this.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = this.points[ i ];\n\t\t\tdata.points.push( point.toArray() );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.points = [];\n\n\t\tfor ( let i = 0, l = json.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = json.points[ i ];\n\t\t\tthis.points.push( new Vector2().fromArray( point ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\nvar Curves = /*#__PURE__*/Object.freeze({\n\t__proto__: null,\n\tArcCurve: ArcCurve,\n\tCatmullRomCurve3: CatmullRomCurve3,\n\tCubicBezierCurve: CubicBezierCurve,\n\tCubicBezierCurve3: CubicBezierCurve3,\n\tEllipseCurve: EllipseCurve,\n\tLineCurve: LineCurve,\n\tLineCurve3: LineCurve3,\n\tQuadraticBezierCurve: QuadraticBezierCurve,\n\tQuadraticBezierCurve3: QuadraticBezierCurve3,\n\tSplineCurve: SplineCurve\n});\n\n/**************************************************************\n *\tCurved Path - a curve path is simply a array of connected\n * curves, but retains the api of a curve\n **************************************************************/\n\nclass CurvePath extends Curve {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.type = 'CurvePath';\n\n\t\tthis.curves = [];\n\t\tthis.autoClose = false; // Automatically closes the path\n\n\t}\n\n\tadd( curve ) {\n\n\t\tthis.curves.push( curve );\n\n\t}\n\n\tclosePath() {\n\n\t\t// Add a line curve if start and end of lines are not connected\n\t\tconst startPoint = this.curves[ 0 ].getPoint( 0 );\n\t\tconst endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );\n\n\t\tif ( ! startPoint.equals( endPoint ) ) {\n\n\t\t\tconst lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3';\n\t\t\tthis.curves.push( new Curves[ lineType ]( endPoint, startPoint ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// To get accurate point with reference to\n\t// entire path distance at time t,\n\t// following has to be done:\n\n\t// 1. Length of each sub path have to be known\n\t// 2. Locate and identify type of curve\n\t// 3. Get t for the curve\n\t// 4. Return curve.getPointAt(t')\n\n\tgetPoint( t, optionalTarget ) {\n\n\t\tconst d = t * this.getLength();\n\t\tconst curveLengths = this.getCurveLengths();\n\t\tlet i = 0;\n\n\t\t// To think about boundaries points.\n\n\t\twhile ( i < curveLengths.length ) {\n\n\t\t\tif ( curveLengths[ i ] >= d ) {\n\n\t\t\t\tconst diff = curveLengths[ i ] - d;\n\t\t\t\tconst curve = this.curves[ i ];\n\n\t\t\t\tconst segmentLength = curve.getLength();\n\t\t\t\tconst u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;\n\n\t\t\t\treturn curve.getPointAt( u, optionalTarget );\n\n\t\t\t}\n\n\t\t\ti ++;\n\n\t\t}\n\n\t\treturn null;\n\n\t\t// loop where sum != 0, sum > d , sum+1 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {\n\n\t\t\tpoints.push( points[ 0 ] );\n\n\t\t}\n\n\t\treturn points;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.curves = [];\n\n\t\tfor ( let i = 0, l = source.curves.length; i < l; i ++ ) {\n\n\t\t\tconst curve = source.curves[ i ];\n\n\t\t\tthis.curves.push( curve.clone() );\n\n\t\t}\n\n\t\tthis.autoClose = source.autoClose;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.autoClose = this.autoClose;\n\t\tdata.curves = [];\n\n\t\tfor ( let i = 0, l = this.curves.length; i < l; i ++ ) {\n\n\t\t\tconst curve = this.curves[ i ];\n\t\t\tdata.curves.push( curve.toJSON() );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.autoClose = json.autoClose;\n\t\tthis.curves = [];\n\n\t\tfor ( let i = 0, l = json.curves.length; i < l; i ++ ) {\n\n\t\t\tconst curve = json.curves[ i ];\n\t\t\tthis.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass Path extends CurvePath {\n\n\tconstructor( points ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'Path';\n\n\t\tthis.currentPoint = new Vector2();\n\n\t\tif ( points ) {\n\n\t\t\tthis.setFromPoints( points );\n\n\t\t}\n\n\t}\n\n\tsetFromPoints( points ) {\n\n\t\tthis.moveTo( points[ 0 ].x, points[ 0 ].y );\n\n\t\tfor ( let i = 1, l = points.length; i < l; i ++ ) {\n\n\t\t\tthis.lineTo( points[ i ].x, points[ i ].y );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tmoveTo( x, y ) {\n\n\t\tthis.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?\n\n\t\treturn this;\n\n\t}\n\n\tlineTo( x, y ) {\n\n\t\tconst curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.set( x, y );\n\n\t\treturn this;\n\n\t}\n\n\tquadraticCurveTo( aCPx, aCPy, aX, aY ) {\n\n\t\tconst curve = new QuadraticBezierCurve(\n\t\t\tthis.currentPoint.clone(),\n\t\t\tnew Vector2( aCPx, aCPy ),\n\t\t\tnew Vector2( aX, aY )\n\t\t);\n\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.set( aX, aY );\n\n\t\treturn this;\n\n\t}\n\n\tbezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {\n\n\t\tconst curve = new CubicBezierCurve(\n\t\t\tthis.currentPoint.clone(),\n\t\t\tnew Vector2( aCP1x, aCP1y ),\n\t\t\tnew Vector2( aCP2x, aCP2y ),\n\t\t\tnew Vector2( aX, aY )\n\t\t);\n\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.set( aX, aY );\n\n\t\treturn this;\n\n\t}\n\n\tsplineThru( pts /*Array of Vector*/ ) {\n\n\t\tconst npts = [ this.currentPoint.clone() ].concat( pts );\n\n\t\tconst curve = new SplineCurve( npts );\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.copy( pts[ pts.length - 1 ] );\n\n\t\treturn this;\n\n\t}\n\n\tarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\t\tconst x0 = this.currentPoint.x;\n\t\tconst y0 = this.currentPoint.y;\n\n\t\tthis.absarc( aX + x0, aY + y0, aRadius,\n\t\t\taStartAngle, aEndAngle, aClockwise );\n\n\t\treturn this;\n\n\t}\n\n\tabsarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\t\tthis.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );\n\n\t\treturn this;\n\n\t}\n\n\tellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {\n\n\t\tconst x0 = this.currentPoint.x;\n\t\tconst y0 = this.currentPoint.y;\n\n\t\tthis.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );\n\n\t\treturn this;\n\n\t}\n\n\tabsellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {\n\n\t\tconst curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );\n\n\t\tif ( this.curves.length > 0 ) {\n\n\t\t\t// if a previous curve is present, attempt to join\n\t\t\tconst firstPoint = curve.getPoint( 0 );\n\n\t\t\tif ( ! firstPoint.equals( this.currentPoint ) ) {\n\n\t\t\t\tthis.lineTo( firstPoint.x, firstPoint.y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.curves.push( curve );\n\n\t\tconst lastPoint = curve.getPoint( 1 );\n\t\tthis.currentPoint.copy( lastPoint );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.currentPoint.copy( source.currentPoint );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.currentPoint = this.currentPoint.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.currentPoint.fromArray( json.currentPoint );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass LatheGeometry extends BufferGeometry {\n\n\tconstructor( points = [ new Vector2( 0, - 0.5 ), new Vector2( 0.5, 0 ), new Vector2( 0, 0.5 ) ], segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'LatheGeometry';\n\n\t\tthis.parameters = {\n\t\t\tpoints: points,\n\t\t\tsegments: segments,\n\t\t\tphiStart: phiStart,\n\t\t\tphiLength: phiLength\n\t\t};\n\n\t\tsegments = Math.floor( segments );\n\n\t\t// clamp phiLength so it's in range of [ 0, 2PI ]\n\n\t\tphiLength = clamp( phiLength, 0, Math.PI * 2 );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst uvs = [];\n\t\tconst initNormals = [];\n\t\tconst normals = [];\n\n\t\t// helper variables\n\n\t\tconst inverseSegments = 1.0 / segments;\n\t\tconst vertex = new Vector3();\n\t\tconst uv = new Vector2();\n\t\tconst normal = new Vector3();\n\t\tconst curNormal = new Vector3();\n\t\tconst prevNormal = new Vector3();\n\t\tlet dx = 0;\n\t\tlet dy = 0;\n\n\t\t// pre-compute normals for initial \"meridian\"\n\n\t\tfor ( let j = 0; j <= ( points.length - 1 ); j ++ ) {\n\n\t\t\tswitch ( j ) {\n\n\t\t\t\tcase 0:\t\t\t\t// special handling for 1st vertex on path\n\n\t\t\t\t\tdx = points[ j + 1 ].x - points[ j ].x;\n\t\t\t\t\tdy = points[ j + 1 ].y - points[ j ].y;\n\n\t\t\t\t\tnormal.x = dy * 1.0;\n\t\t\t\t\tnormal.y = - dx;\n\t\t\t\t\tnormal.z = dy * 0.0;\n\n\t\t\t\t\tprevNormal.copy( normal );\n\n\t\t\t\t\tnormal.normalize();\n\n\t\t\t\t\tinitNormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ( points.length - 1 ):\t// special handling for last Vertex on path\n\n\t\t\t\t\tinitNormals.push( prevNormal.x, prevNormal.y, prevNormal.z );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\t\t\t// default handling for all vertices in between\n\n\t\t\t\t\tdx = points[ j + 1 ].x - points[ j ].x;\n\t\t\t\t\tdy = points[ j + 1 ].y - points[ j ].y;\n\n\t\t\t\t\tnormal.x = dy * 1.0;\n\t\t\t\t\tnormal.y = - dx;\n\t\t\t\t\tnormal.z = dy * 0.0;\n\n\t\t\t\t\tcurNormal.copy( normal );\n\n\t\t\t\t\tnormal.x += prevNormal.x;\n\t\t\t\t\tnormal.y += prevNormal.y;\n\t\t\t\t\tnormal.z += prevNormal.z;\n\n\t\t\t\t\tnormal.normalize();\n\n\t\t\t\t\tinitNormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t\tprevNormal.copy( curNormal );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate vertices, uvs and normals\n\n\t\tfor ( let i = 0; i <= segments; i ++ ) {\n\n\t\t\tconst phi = phiStart + i * inverseSegments * phiLength;\n\n\t\t\tconst sin = Math.sin( phi );\n\t\t\tconst cos = Math.cos( phi );\n\n\t\t\tfor ( let j = 0; j <= ( points.length - 1 ); j ++ ) {\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = points[ j ].x * sin;\n\t\t\t\tvertex.y = points[ j ].y;\n\t\t\t\tvertex.z = points[ j ].x * cos;\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuv.x = i / segments;\n\t\t\t\tuv.y = j / ( points.length - 1 );\n\n\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t\t// normal\n\n\t\t\t\tconst x = initNormals[ 3 * j + 0 ] * sin;\n\t\t\t\tconst y = initNormals[ 3 * j + 1 ];\n\t\t\t\tconst z = initNormals[ 3 * j + 0 ] * cos;\n\n\t\t\t\tnormals.push( x, y, z );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( let i = 0; i < segments; i ++ ) {\n\n\t\t\tfor ( let j = 0; j < ( points.length - 1 ); j ++ ) {\n\n\t\t\t\tconst base = j + i * points.length;\n\n\t\t\t\tconst a = base;\n\t\t\t\tconst b = base + points.length;\n\t\t\t\tconst c = base + points.length + 1;\n\t\t\t\tconst d = base + 1;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( c, d, b );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength );\n\n\t}\n\n}\n\nclass CapsuleGeometry extends LatheGeometry {\n\n\tconstructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8 ) {\n\n\t\tconst path = new Path();\n\t\tpath.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 );\n\t\tpath.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 );\n\n\t\tsuper( path.getPoints( capSegments ), radialSegments );\n\n\t\tthis.type = 'CapsuleGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tlength: length,\n\t\t\tcapSegments: capSegments,\n\t\t\tradialSegments: radialSegments,\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments );\n\n\t}\n\n}\n\nclass CircleGeometry extends BufferGeometry {\n\n\tconstructor( radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'CircleGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tsegments: segments,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tsegments = Math.max( 3, segments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tconst vertex = new Vector3();\n\t\tconst uv = new Vector2();\n\n\t\t// center point\n\n\t\tvertices.push( 0, 0, 0 );\n\t\tnormals.push( 0, 0, 1 );\n\t\tuvs.push( 0.5, 0.5 );\n\n\t\tfor ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {\n\n\t\t\tconst segment = thetaStart + s / segments * thetaLength;\n\n\t\t\t// vertex\n\n\t\t\tvertex.x = radius * Math.cos( segment );\n\t\t\tvertex.y = radius * Math.sin( segment );\n\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t// normal\n\n\t\t\tnormals.push( 0, 0, 1 );\n\n\t\t\t// uvs\n\n\t\t\tuv.x = ( vertices[ i ] / radius + 1 ) / 2;\n\t\t\tuv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;\n\n\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( let i = 1; i <= segments; i ++ ) {\n\n\t\t\tindices.push( i, i + 1, 0 );\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength );\n\n\t}\n\n}\n\nclass CylinderGeometry extends BufferGeometry {\n\n\tconstructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'CylinderGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradiusTop: radiusTop,\n\t\t\tradiusBottom: radiusBottom,\n\t\t\theight: height,\n\t\t\tradialSegments: radialSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\topenEnded: openEnded,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tconst scope = this;\n\n\t\tradialSegments = Math.floor( radialSegments );\n\t\theightSegments = Math.floor( heightSegments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tlet index = 0;\n\t\tconst indexArray = [];\n\t\tconst halfHeight = height / 2;\n\t\tlet groupStart = 0;\n\n\t\t// generate geometry\n\n\t\tgenerateTorso();\n\n\t\tif ( openEnded === false ) {\n\n\t\t\tif ( radiusTop > 0 ) generateCap( true );\n\t\t\tif ( radiusBottom > 0 ) generateCap( false );\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\tfunction generateTorso() {\n\n\t\t\tconst normal = new Vector3();\n\t\t\tconst vertex = new Vector3();\n\n\t\t\tlet groupCount = 0;\n\n\t\t\t// this will be used to calculate the normal\n\t\t\tconst slope = ( radiusBottom - radiusTop ) / height;\n\n\t\t\t// generate vertices, normals and uvs\n\n\t\t\tfor ( let y = 0; y <= heightSegments; y ++ ) {\n\n\t\t\t\tconst indexRow = [];\n\n\t\t\t\tconst v = y / heightSegments;\n\n\t\t\t\t// calculate the radius of the current row\n\n\t\t\t\tconst radius = v * ( radiusBottom - radiusTop ) + radiusTop;\n\n\t\t\t\tfor ( let x = 0; x <= radialSegments; x ++ ) {\n\n\t\t\t\t\tconst u = x / radialSegments;\n\n\t\t\t\t\tconst theta = u * thetaLength + thetaStart;\n\n\t\t\t\t\tconst sinTheta = Math.sin( theta );\n\t\t\t\t\tconst cosTheta = Math.cos( theta );\n\n\t\t\t\t\t// vertex\n\n\t\t\t\t\tvertex.x = radius * sinTheta;\n\t\t\t\t\tvertex.y = - v * height + halfHeight;\n\t\t\t\t\tvertex.z = radius * cosTheta;\n\t\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t\t// normal\n\n\t\t\t\t\tnormal.set( sinTheta, slope, cosTheta ).normalize();\n\t\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t\t// uv\n\n\t\t\t\t\tuvs.push( u, 1 - v );\n\n\t\t\t\t\t// save index of vertex in respective row\n\n\t\t\t\t\tindexRow.push( index ++ );\n\n\t\t\t\t}\n\n\t\t\t\t// now save vertices of the row in our index array\n\n\t\t\t\tindexArray.push( indexRow );\n\n\t\t\t}\n\n\t\t\t// generate indices\n\n\t\t\tfor ( let x = 0; x < radialSegments; x ++ ) {\n\n\t\t\t\tfor ( let y = 0; y < heightSegments; y ++ ) {\n\n\t\t\t\t\t// we use the index array to access the correct indices\n\n\t\t\t\t\tconst a = indexArray[ y ][ x ];\n\t\t\t\t\tconst b = indexArray[ y + 1 ][ x ];\n\t\t\t\t\tconst c = indexArray[ y + 1 ][ x + 1 ];\n\t\t\t\t\tconst d = indexArray[ y ][ x + 1 ];\n\n\t\t\t\t\t// faces\n\n\t\t\t\t\tindices.push( a, b, d );\n\t\t\t\t\tindices.push( b, c, d );\n\n\t\t\t\t\t// update group counter\n\n\t\t\t\t\tgroupCount += 6;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\t\tscope.addGroup( groupStart, groupCount, 0 );\n\n\t\t\t// calculate new start value for groups\n\n\t\t\tgroupStart += groupCount;\n\n\t\t}\n\n\t\tfunction generateCap( top ) {\n\n\t\t\t// save the index of the first center vertex\n\t\t\tconst centerIndexStart = index;\n\n\t\t\tconst uv = new Vector2();\n\t\t\tconst vertex = new Vector3();\n\n\t\t\tlet groupCount = 0;\n\n\t\t\tconst radius = ( top === true ) ? radiusTop : radiusBottom;\n\t\t\tconst sign = ( top === true ) ? 1 : - 1;\n\n\t\t\t// first we generate the center vertex data of the cap.\n\t\t\t// because the geometry needs one set of uvs per face,\n\t\t\t// we must generate a center vertex per face/segment\n\n\t\t\tfor ( let x = 1; x <= radialSegments; x ++ ) {\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertices.push( 0, halfHeight * sign, 0 );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormals.push( 0, sign, 0 );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( 0.5, 0.5 );\n\n\t\t\t\t// increase index\n\n\t\t\t\tindex ++;\n\n\t\t\t}\n\n\t\t\t// save the index of the last center vertex\n\t\t\tconst centerIndexEnd = index;\n\n\t\t\t// now we generate the surrounding vertices, normals and uvs\n\n\t\t\tfor ( let x = 0; x <= radialSegments; x ++ ) {\n\n\t\t\t\tconst u = x / radialSegments;\n\t\t\t\tconst theta = u * thetaLength + thetaStart;\n\n\t\t\t\tconst cosTheta = Math.cos( theta );\n\t\t\t\tconst sinTheta = Math.sin( theta );\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = radius * sinTheta;\n\t\t\t\tvertex.y = halfHeight * sign;\n\t\t\t\tvertex.z = radius * cosTheta;\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormals.push( 0, sign, 0 );\n\n\t\t\t\t// uv\n\n\t\t\t\tuv.x = ( cosTheta * 0.5 ) + 0.5;\n\t\t\t\tuv.y = ( sinTheta * 0.5 * sign ) + 0.5;\n\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t\t// increase index\n\n\t\t\t\tindex ++;\n\n\t\t\t}\n\n\t\t\t// generate indices\n\n\t\t\tfor ( let x = 0; x < radialSegments; x ++ ) {\n\n\t\t\t\tconst c = centerIndexStart + x;\n\t\t\t\tconst i = centerIndexEnd + x;\n\n\t\t\t\tif ( top === true ) {\n\n\t\t\t\t\t// face top\n\n\t\t\t\t\tindices.push( i, i + 1, c );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// face bottom\n\n\t\t\t\t\tindices.push( i + 1, i, c );\n\n\t\t\t\t}\n\n\t\t\t\tgroupCount += 3;\n\n\t\t\t}\n\n\t\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\t\tscope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );\n\n\t\t\t// calculate new start value for groups\n\n\t\t\tgroupStart += groupCount;\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );\n\n\t}\n\n}\n\nclass ConeGeometry extends CylinderGeometry {\n\n\tconstructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {\n\n\t\tsuper( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );\n\n\t\tthis.type = 'ConeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\theight: height,\n\t\t\tradialSegments: radialSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\topenEnded: openEnded,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );\n\n\t}\n\n}\n\nclass PolyhedronGeometry extends BufferGeometry {\n\n\tconstructor( vertices = [], indices = [], radius = 1, detail = 0 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'PolyhedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tvertices: vertices,\n\t\t\tindices: indices,\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t\t// default buffer data\n\n\t\tconst vertexBuffer = [];\n\t\tconst uvBuffer = [];\n\n\t\t// the subdivision creates the vertex buffer data\n\n\t\tsubdivide( detail );\n\n\t\t// all vertices should lie on a conceptual sphere with a given radius\n\n\t\tapplyRadius( radius );\n\n\t\t// finally, create the uv data\n\n\t\tgenerateUVs();\n\n\t\t// build non-indexed geometry\n\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );\n\n\t\tif ( detail === 0 ) {\n\n\t\t\tthis.computeVertexNormals(); // flat normals\n\n\t\t} else {\n\n\t\t\tthis.normalizeNormals(); // smooth normals\n\n\t\t}\n\n\t\t// helper functions\n\n\t\tfunction subdivide( detail ) {\n\n\t\t\tconst a = new Vector3();\n\t\t\tconst b = new Vector3();\n\t\t\tconst c = new Vector3();\n\n\t\t\t// iterate over all faces and apply a subdivision with the given detail value\n\n\t\t\tfor ( let i = 0; i < indices.length; i += 3 ) {\n\n\t\t\t\t// get the vertices of the face\n\n\t\t\t\tgetVertexByIndex( indices[ i + 0 ], a );\n\t\t\t\tgetVertexByIndex( indices[ i + 1 ], b );\n\t\t\t\tgetVertexByIndex( indices[ i + 2 ], c );\n\n\t\t\t\t// perform subdivision\n\n\t\t\t\tsubdivideFace( a, b, c, detail );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction subdivideFace( a, b, c, detail ) {\n\n\t\t\tconst cols = detail + 1;\n\n\t\t\t// we use this multidimensional array as a data structure for creating the subdivision\n\n\t\t\tconst v = [];\n\n\t\t\t// construct all of the vertices for this subdivision\n\n\t\t\tfor ( let i = 0; i <= cols; i ++ ) {\n\n\t\t\t\tv[ i ] = [];\n\n\t\t\t\tconst aj = a.clone().lerp( c, i / cols );\n\t\t\t\tconst bj = b.clone().lerp( c, i / cols );\n\n\t\t\t\tconst rows = cols - i;\n\n\t\t\t\tfor ( let j = 0; j <= rows; j ++ ) {\n\n\t\t\t\t\tif ( j === 0 && i === cols ) {\n\n\t\t\t\t\t\tv[ i ][ j ] = aj;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tv[ i ][ j ] = aj.clone().lerp( bj, j / rows );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// construct all of the faces\n\n\t\t\tfor ( let i = 0; i < cols; i ++ ) {\n\n\t\t\t\tfor ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {\n\n\t\t\t\t\tconst k = Math.floor( j / 2 );\n\n\t\t\t\t\tif ( j % 2 === 0 ) {\n\n\t\t\t\t\t\tpushVertex( v[ i ][ k + 1 ] );\n\t\t\t\t\t\tpushVertex( v[ i + 1 ][ k ] );\n\t\t\t\t\t\tpushVertex( v[ i ][ k ] );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpushVertex( v[ i ][ k + 1 ] );\n\t\t\t\t\t\tpushVertex( v[ i + 1 ][ k + 1 ] );\n\t\t\t\t\t\tpushVertex( v[ i + 1 ][ k ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction applyRadius( radius ) {\n\n\t\t\tconst vertex = new Vector3();\n\n\t\t\t// iterate over the entire buffer and apply the radius to each vertex\n\n\t\t\tfor ( let i = 0; i < vertexBuffer.length; i += 3 ) {\n\n\t\t\t\tvertex.x = vertexBuffer[ i + 0 ];\n\t\t\t\tvertex.y = vertexBuffer[ i + 1 ];\n\t\t\t\tvertex.z = vertexBuffer[ i + 2 ];\n\n\t\t\t\tvertex.normalize().multiplyScalar( radius );\n\n\t\t\t\tvertexBuffer[ i + 0 ] = vertex.x;\n\t\t\t\tvertexBuffer[ i + 1 ] = vertex.y;\n\t\t\t\tvertexBuffer[ i + 2 ] = vertex.z;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction generateUVs() {\n\n\t\t\tconst vertex = new Vector3();\n\n\t\t\tfor ( let i = 0; i < vertexBuffer.length; i += 3 ) {\n\n\t\t\t\tvertex.x = vertexBuffer[ i + 0 ];\n\t\t\t\tvertex.y = vertexBuffer[ i + 1 ];\n\t\t\t\tvertex.z = vertexBuffer[ i + 2 ];\n\n\t\t\t\tconst u = azimuth( vertex ) / 2 / Math.PI + 0.5;\n\t\t\t\tconst v = inclination( vertex ) / Math.PI + 0.5;\n\t\t\t\tuvBuffer.push( u, 1 - v );\n\n\t\t\t}\n\n\t\t\tcorrectUVs();\n\n\t\t\tcorrectSeam();\n\n\t\t}\n\n\t\tfunction correctSeam() {\n\n\t\t\t// handle case when face straddles the seam, see #3269\n\n\t\t\tfor ( let i = 0; i < uvBuffer.length; i += 6 ) {\n\n\t\t\t\t// uv data of a single face\n\n\t\t\t\tconst x0 = uvBuffer[ i + 0 ];\n\t\t\t\tconst x1 = uvBuffer[ i + 2 ];\n\t\t\t\tconst x2 = uvBuffer[ i + 4 ];\n\n\t\t\t\tconst max = Math.max( x0, x1, x2 );\n\t\t\t\tconst min = Math.min( x0, x1, x2 );\n\n\t\t\t\t// 0.9 is somewhat arbitrary\n\n\t\t\t\tif ( max > 0.9 && min < 0.1 ) {\n\n\t\t\t\t\tif ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;\n\t\t\t\t\tif ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;\n\t\t\t\t\tif ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction pushVertex( vertex ) {\n\n\t\t\tvertexBuffer.push( vertex.x, vertex.y, vertex.z );\n\n\t\t}\n\n\t\tfunction getVertexByIndex( index, vertex ) {\n\n\t\t\tconst stride = index * 3;\n\n\t\t\tvertex.x = vertices[ stride + 0 ];\n\t\t\tvertex.y = vertices[ stride + 1 ];\n\t\t\tvertex.z = vertices[ stride + 2 ];\n\n\t\t}\n\n\t\tfunction correctUVs() {\n\n\t\t\tconst a = new Vector3();\n\t\t\tconst b = new Vector3();\n\t\t\tconst c = new Vector3();\n\n\t\t\tconst centroid = new Vector3();\n\n\t\t\tconst uvA = new Vector2();\n\t\t\tconst uvB = new Vector2();\n\t\t\tconst uvC = new Vector2();\n\n\t\t\tfor ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {\n\n\t\t\t\ta.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );\n\t\t\t\tb.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );\n\t\t\t\tc.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );\n\n\t\t\t\tuvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );\n\t\t\t\tuvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );\n\t\t\t\tuvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );\n\n\t\t\t\tcentroid.copy( a ).add( b ).add( c ).divideScalar( 3 );\n\n\t\t\t\tconst azi = azimuth( centroid );\n\n\t\t\t\tcorrectUV( uvA, j + 0, a, azi );\n\t\t\t\tcorrectUV( uvB, j + 2, b, azi );\n\t\t\t\tcorrectUV( uvC, j + 4, c, azi );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction correctUV( uv, stride, vector, azimuth ) {\n\n\t\t\tif ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {\n\n\t\t\t\tuvBuffer[ stride ] = uv.x - 1;\n\n\t\t\t}\n\n\t\t\tif ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {\n\n\t\t\t\tuvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Angle around the Y axis, counter-clockwise when looking from above.\n\n\t\tfunction azimuth( vector ) {\n\n\t\t\treturn Math.atan2( vector.z, - vector.x );\n\n\t\t}\n\n\n\t\t// Angle above the XZ plane.\n\n\t\tfunction inclination( vector ) {\n\n\t\t\treturn Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details );\n\n\t}\n\n}\n\nclass DodecahedronGeometry extends PolyhedronGeometry {\n\n\tconstructor( radius = 1, detail = 0 ) {\n\n\t\tconst t = ( 1 + Math.sqrt( 5 ) ) / 2;\n\t\tconst r = 1 / t;\n\n\t\tconst vertices = [\n\n\t\t\t// (±1, ±1, ±1)\n\t\t\t- 1, - 1, - 1,\t- 1, - 1, 1,\n\t\t\t- 1, 1, - 1, - 1, 1, 1,\n\t\t\t1, - 1, - 1, 1, - 1, 1,\n\t\t\t1, 1, - 1, 1, 1, 1,\n\n\t\t\t// (0, ±1/φ, ±φ)\n\t\t\t0, - r, - t, 0, - r, t,\n\t\t\t0, r, - t, 0, r, t,\n\n\t\t\t// (±1/φ, ±φ, 0)\n\t\t\t- r, - t, 0, - r, t, 0,\n\t\t\tr, - t, 0, r, t, 0,\n\n\t\t\t// (±φ, 0, ±1/φ)\n\t\t\t- t, 0, - r, t, 0, - r,\n\t\t\t- t, 0, r, t, 0, r\n\t\t];\n\n\t\tconst indices = [\n\t\t\t3, 11, 7, \t3, 7, 15, \t3, 15, 13,\n\t\t\t7, 19, 17, \t7, 17, 6, \t7, 6, 15,\n\t\t\t17, 4, 8, \t17, 8, 10, \t17, 10, 6,\n\t\t\t8, 0, 16, \t8, 16, 2, \t8, 2, 10,\n\t\t\t0, 12, 1, \t0, 1, 18, \t0, 18, 16,\n\t\t\t6, 10, 2, \t6, 2, 13, \t6, 13, 15,\n\t\t\t2, 16, 18, \t2, 18, 3, \t2, 3, 13,\n\t\t\t18, 1, 9, \t18, 9, 11, \t18, 11, 3,\n\t\t\t4, 14, 12, \t4, 12, 0, \t4, 0, 8,\n\t\t\t11, 9, 5, \t11, 5, 19, \t11, 19, 7,\n\t\t\t19, 5, 14, \t19, 14, 4, \t19, 4, 17,\n\t\t\t1, 12, 14, \t1, 14, 5, \t1, 5, 9\n\t\t];\n\n\t\tsuper( vertices, indices, radius, detail );\n\n\t\tthis.type = 'DodecahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new DodecahedronGeometry( data.radius, data.detail );\n\n\t}\n\n}\n\nconst _v0 = /*@__PURE__*/ new Vector3();\nconst _v1$1 = /*@__PURE__*/ new Vector3();\nconst _normal = /*@__PURE__*/ new Vector3();\nconst _triangle = /*@__PURE__*/ new Triangle();\n\nclass EdgesGeometry extends BufferGeometry {\n\n\tconstructor( geometry = null, thresholdAngle = 1 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'EdgesGeometry';\n\n\t\tthis.parameters = {\n\t\t\tgeometry: geometry,\n\t\t\tthresholdAngle: thresholdAngle\n\t\t};\n\n\t\tif ( geometry !== null ) {\n\n\t\t\tconst precisionPoints = 4;\n\t\t\tconst precision = Math.pow( 10, precisionPoints );\n\t\t\tconst thresholdDot = Math.cos( DEG2RAD * thresholdAngle );\n\n\t\t\tconst indexAttr = geometry.getIndex();\n\t\t\tconst positionAttr = geometry.getAttribute( 'position' );\n\t\t\tconst indexCount = indexAttr ? indexAttr.count : positionAttr.count;\n\n\t\t\tconst indexArr = [ 0, 0, 0 ];\n\t\t\tconst vertKeys = [ 'a', 'b', 'c' ];\n\t\t\tconst hashes = new Array( 3 );\n\n\t\t\tconst edgeData = {};\n\t\t\tconst vertices = [];\n\t\t\tfor ( let i = 0; i < indexCount; i += 3 ) {\n\n\t\t\t\tif ( indexAttr ) {\n\n\t\t\t\t\tindexArr[ 0 ] = indexAttr.getX( i );\n\t\t\t\t\tindexArr[ 1 ] = indexAttr.getX( i + 1 );\n\t\t\t\t\tindexArr[ 2 ] = indexAttr.getX( i + 2 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tindexArr[ 0 ] = i;\n\t\t\t\t\tindexArr[ 1 ] = i + 1;\n\t\t\t\t\tindexArr[ 2 ] = i + 2;\n\n\t\t\t\t}\n\n\t\t\t\tconst { a, b, c } = _triangle;\n\t\t\t\ta.fromBufferAttribute( positionAttr, indexArr[ 0 ] );\n\t\t\t\tb.fromBufferAttribute( positionAttr, indexArr[ 1 ] );\n\t\t\t\tc.fromBufferAttribute( positionAttr, indexArr[ 2 ] );\n\t\t\t\t_triangle.getNormal( _normal );\n\n\t\t\t\t// create hashes for the edge from the vertices\n\t\t\t\thashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`;\n\t\t\t\thashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`;\n\t\t\t\thashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`;\n\n\t\t\t\t// skip degenerate triangles\n\t\t\t\tif ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) {\n\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\t// iterate over every edge\n\t\t\t\tfor ( let j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t// get the first and next vertex making up the edge\n\t\t\t\t\tconst jNext = ( j + 1 ) % 3;\n\t\t\t\t\tconst vecHash0 = hashes[ j ];\n\t\t\t\t\tconst vecHash1 = hashes[ jNext ];\n\t\t\t\t\tconst v0 = _triangle[ vertKeys[ j ] ];\n\t\t\t\t\tconst v1 = _triangle[ vertKeys[ jNext ] ];\n\n\t\t\t\t\tconst hash = `${ vecHash0 }_${ vecHash1 }`;\n\t\t\t\t\tconst reverseHash = `${ vecHash1 }_${ vecHash0 }`;\n\n\t\t\t\t\tif ( reverseHash in edgeData && edgeData[ reverseHash ] ) {\n\n\t\t\t\t\t\t// if we found a sibling edge add it into the vertex array if\n\t\t\t\t\t\t// it meets the angle threshold and delete the edge from the map.\n\t\t\t\t\t\tif ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) {\n\n\t\t\t\t\t\t\tvertices.push( v0.x, v0.y, v0.z );\n\t\t\t\t\t\t\tvertices.push( v1.x, v1.y, v1.z );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tedgeData[ reverseHash ] = null;\n\n\t\t\t\t\t} else if ( ! ( hash in edgeData ) ) {\n\n\t\t\t\t\t\t// if we've already got an edge here then skip adding a new one\n\t\t\t\t\t\tedgeData[ hash ] = {\n\n\t\t\t\t\t\t\tindex0: indexArr[ j ],\n\t\t\t\t\t\t\tindex1: indexArr[ jNext ],\n\t\t\t\t\t\t\tnormal: _normal.clone(),\n\n\t\t\t\t\t\t};\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// iterate over all remaining, unmatched edges and add them to the vertex array\n\t\t\tfor ( const key in edgeData ) {\n\n\t\t\t\tif ( edgeData[ key ] ) {\n\n\t\t\t\t\tconst { index0, index1 } = edgeData[ key ];\n\t\t\t\t\t_v0.fromBufferAttribute( positionAttr, index0 );\n\t\t\t\t\t_v1$1.fromBufferAttribute( positionAttr, index1 );\n\n\t\t\t\t\tvertices.push( _v0.x, _v0.y, _v0.z );\n\t\t\t\t\tvertices.push( _v1$1.x, _v1$1.y, _v1$1.z );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass Shape extends Path {\n\n\tconstructor( points ) {\n\n\t\tsuper( points );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.type = 'Shape';\n\n\t\tthis.holes = [];\n\n\t}\n\n\tgetPointsHoles( divisions ) {\n\n\t\tconst holesPts = [];\n\n\t\tfor ( let i = 0, l = this.holes.length; i < l; i ++ ) {\n\n\t\t\tholesPts[ i ] = this.holes[ i ].getPoints( divisions );\n\n\t\t}\n\n\t\treturn holesPts;\n\n\t}\n\n\t// get points of shape and holes (keypoints based on segments parameter)\n\n\textractPoints( divisions ) {\n\n\t\treturn {\n\n\t\t\tshape: this.getPoints( divisions ),\n\t\t\tholes: this.getPointsHoles( divisions )\n\n\t\t};\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.holes = [];\n\n\t\tfor ( let i = 0, l = source.holes.length; i < l; i ++ ) {\n\n\t\t\tconst hole = source.holes[ i ];\n\n\t\t\tthis.holes.push( hole.clone() );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.uuid = this.uuid;\n\t\tdata.holes = [];\n\n\t\tfor ( let i = 0, l = this.holes.length; i < l; i ++ ) {\n\n\t\t\tconst hole = this.holes[ i ];\n\t\t\tdata.holes.push( hole.toJSON() );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.uuid = json.uuid;\n\t\tthis.holes = [];\n\n\t\tfor ( let i = 0, l = json.holes.length; i < l; i ++ ) {\n\n\t\t\tconst hole = json.holes[ i ];\n\t\t\tthis.holes.push( new Path().fromJSON( hole ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\n/**\n * Port from https://github.com/mapbox/earcut (v2.2.4)\n */\n\nconst Earcut = {\n\n\ttriangulate: function ( data, holeIndices, dim = 2 ) {\n\n\t\tconst hasHoles = holeIndices && holeIndices.length;\n\t\tconst outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;\n\t\tlet outerNode = linkedList( data, 0, outerLen, dim, true );\n\t\tconst triangles = [];\n\n\t\tif ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;\n\n\t\tlet minX, minY, maxX, maxY, x, y, invSize;\n\n\t\tif ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim );\n\n\t\t// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox\n\t\tif ( data.length > 80 * dim ) {\n\n\t\t\tminX = maxX = data[ 0 ];\n\t\t\tminY = maxY = data[ 1 ];\n\n\t\t\tfor ( let i = dim; i < outerLen; i += dim ) {\n\n\t\t\t\tx = data[ i ];\n\t\t\t\ty = data[ i + 1 ];\n\t\t\t\tif ( x < minX ) minX = x;\n\t\t\t\tif ( y < minY ) minY = y;\n\t\t\t\tif ( x > maxX ) maxX = x;\n\t\t\t\tif ( y > maxY ) maxY = y;\n\n\t\t\t}\n\n\t\t\t// minX, minY and invSize are later used to transform coords into integers for z-order calculation\n\t\t\tinvSize = Math.max( maxX - minX, maxY - minY );\n\t\t\tinvSize = invSize !== 0 ? 32767 / invSize : 0;\n\n\t\t}\n\n\t\tearcutLinked( outerNode, triangles, dim, minX, minY, invSize, 0 );\n\n\t\treturn triangles;\n\n\t}\n\n};\n\n// create a circular doubly linked list from polygon points in the specified winding order\nfunction linkedList( data, start, end, dim, clockwise ) {\n\n\tlet i, last;\n\n\tif ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) {\n\n\t\tfor ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );\n\n\t} else {\n\n\t\tfor ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );\n\n\t}\n\n\tif ( last && equals( last, last.next ) ) {\n\n\t\tremoveNode( last );\n\t\tlast = last.next;\n\n\t}\n\n\treturn last;\n\n}\n\n// eliminate colinear or duplicate points\nfunction filterPoints( start, end ) {\n\n\tif ( ! start ) return start;\n\tif ( ! end ) end = start;\n\n\tlet p = start,\n\t\tagain;\n\tdo {\n\n\t\tagain = false;\n\n\t\tif ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) {\n\n\t\t\tremoveNode( p );\n\t\t\tp = end = p.prev;\n\t\t\tif ( p === p.next ) break;\n\t\t\tagain = true;\n\n\t\t} else {\n\n\t\t\tp = p.next;\n\n\t\t}\n\n\t} while ( again || p !== end );\n\n\treturn end;\n\n}\n\n// main ear slicing loop which triangulates a polygon (given as a linked list)\nfunction earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {\n\n\tif ( ! ear ) return;\n\n\t// interlink polygon nodes in z-order\n\tif ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize );\n\n\tlet stop = ear,\n\t\tprev, next;\n\n\t// iterate through ears, slicing them one by one\n\twhile ( ear.prev !== ear.next ) {\n\n\t\tprev = ear.prev;\n\t\tnext = ear.next;\n\n\t\tif ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) {\n\n\t\t\t// cut off the triangle\n\t\t\ttriangles.push( prev.i / dim | 0 );\n\t\t\ttriangles.push( ear.i / dim | 0 );\n\t\t\ttriangles.push( next.i / dim | 0 );\n\n\t\t\tremoveNode( ear );\n\n\t\t\t// skipping the next vertex leads to less sliver triangles\n\t\t\tear = next.next;\n\t\t\tstop = next.next;\n\n\t\t\tcontinue;\n\n\t\t}\n\n\t\tear = next;\n\n\t\t// if we looped through the whole remaining polygon and can't find any more ears\n\t\tif ( ear === stop ) {\n\n\t\t\t// try filtering points and slicing again\n\t\t\tif ( ! pass ) {\n\n\t\t\t\tearcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 );\n\n\t\t\t\t// if this didn't work, try curing all small self-intersections locally\n\n\t\t\t} else if ( pass === 1 ) {\n\n\t\t\t\tear = cureLocalIntersections( filterPoints( ear ), triangles, dim );\n\t\t\t\tearcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );\n\n\t\t\t\t// as a last resort, try splitting the remaining polygon into two\n\n\t\t\t} else if ( pass === 2 ) {\n\n\t\t\t\tsplitEarcut( ear, triangles, dim, minX, minY, invSize );\n\n\t\t\t}\n\n\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n}\n\n// check whether a polygon node forms a valid ear with adjacent nodes\nfunction isEar( ear ) {\n\n\tconst a = ear.prev,\n\t\tb = ear,\n\t\tc = ear.next;\n\n\tif ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear\n\n\t// now make sure we don't have other points inside the potential ear\n\tconst ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;\n\n\t// triangle bbox; min & max are calculated like this for speed\n\tconst x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),\n\t\ty0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),\n\t\tx1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),\n\t\ty1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );\n\n\tlet p = c.next;\n\twhile ( p !== a ) {\n\n\t\tif ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) &&\n\t\t\tarea( p.prev, p, p.next ) >= 0 ) return false;\n\t\tp = p.next;\n\n\t}\n\n\treturn true;\n\n}\n\nfunction isEarHashed( ear, minX, minY, invSize ) {\n\n\tconst a = ear.prev,\n\t\tb = ear,\n\t\tc = ear.next;\n\n\tif ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear\n\n\tconst ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;\n\n\t// triangle bbox; min & max are calculated like this for speed\n\tconst x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),\n\t\ty0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),\n\t\tx1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),\n\t\ty1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );\n\n\t// z-order range for the current triangle bbox;\n\tconst minZ = zOrder( x0, y0, minX, minY, invSize ),\n\t\tmaxZ = zOrder( x1, y1, minX, minY, invSize );\n\n\tlet p = ear.prevZ,\n\t\tn = ear.nextZ;\n\n\t// look for points inside the triangle in both directions\n\twhile ( p && p.z >= minZ && n && n.z <= maxZ ) {\n\n\t\tif ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;\n\t\tp = p.prevZ;\n\n\t\tif ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;\n\t\tn = n.nextZ;\n\n\t}\n\n\t// look for remaining points in decreasing z-order\n\twhile ( p && p.z >= minZ ) {\n\n\t\tif ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;\n\t\tp = p.prevZ;\n\n\t}\n\n\t// look for remaining points in increasing z-order\n\twhile ( n && n.z <= maxZ ) {\n\n\t\tif ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;\n\t\tn = n.nextZ;\n\n\t}\n\n\treturn true;\n\n}\n\n// go through all polygon nodes and cure small local self-intersections\nfunction cureLocalIntersections( start, triangles, dim ) {\n\n\tlet p = start;\n\tdo {\n\n\t\tconst a = p.prev,\n\t\t\tb = p.next.next;\n\n\t\tif ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {\n\n\t\t\ttriangles.push( a.i / dim | 0 );\n\t\t\ttriangles.push( p.i / dim | 0 );\n\t\t\ttriangles.push( b.i / dim | 0 );\n\n\t\t\t// remove two nodes involved\n\t\t\tremoveNode( p );\n\t\t\tremoveNode( p.next );\n\n\t\t\tp = start = b;\n\n\t\t}\n\n\t\tp = p.next;\n\n\t} while ( p !== start );\n\n\treturn filterPoints( p );\n\n}\n\n// try splitting polygon into two and triangulate them independently\nfunction splitEarcut( start, triangles, dim, minX, minY, invSize ) {\n\n\t// look for a valid diagonal that divides the polygon into two\n\tlet a = start;\n\tdo {\n\n\t\tlet b = a.next.next;\n\t\twhile ( b !== a.prev ) {\n\n\t\t\tif ( a.i !== b.i && isValidDiagonal( a, b ) ) {\n\n\t\t\t\t// split the polygon in two by the diagonal\n\t\t\t\tlet c = splitPolygon( a, b );\n\n\t\t\t\t// filter colinear points around the cuts\n\t\t\t\ta = filterPoints( a, a.next );\n\t\t\t\tc = filterPoints( c, c.next );\n\n\t\t\t\t// run earcut on each half\n\t\t\t\tearcutLinked( a, triangles, dim, minX, minY, invSize, 0 );\n\t\t\t\tearcutLinked( c, triangles, dim, minX, minY, invSize, 0 );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tb = b.next;\n\n\t\t}\n\n\t\ta = a.next;\n\n\t} while ( a !== start );\n\n}\n\n// link every hole into the outer loop, producing a single-ring polygon without holes\nfunction eliminateHoles( data, holeIndices, outerNode, dim ) {\n\n\tconst queue = [];\n\tlet i, len, start, end, list;\n\n\tfor ( i = 0, len = holeIndices.length; i < len; i ++ ) {\n\n\t\tstart = holeIndices[ i ] * dim;\n\t\tend = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;\n\t\tlist = linkedList( data, start, end, dim, false );\n\t\tif ( list === list.next ) list.steiner = true;\n\t\tqueue.push( getLeftmost( list ) );\n\n\t}\n\n\tqueue.sort( compareX );\n\n\t// process holes from left to right\n\tfor ( i = 0; i < queue.length; i ++ ) {\n\n\t\touterNode = eliminateHole( queue[ i ], outerNode );\n\n\t}\n\n\treturn outerNode;\n\n}\n\nfunction compareX( a, b ) {\n\n\treturn a.x - b.x;\n\n}\n\n// find a bridge between vertices that connects hole with an outer ring and link it\nfunction eliminateHole( hole, outerNode ) {\n\n\tconst bridge = findHoleBridge( hole, outerNode );\n\tif ( ! bridge ) {\n\n\t\treturn outerNode;\n\n\t}\n\n\tconst bridgeReverse = splitPolygon( bridge, hole );\n\n\t// filter collinear points around the cuts\n\tfilterPoints( bridgeReverse, bridgeReverse.next );\n\treturn filterPoints( bridge, bridge.next );\n\n}\n\n// David Eberly's algorithm for finding a bridge between hole and outer polygon\nfunction findHoleBridge( hole, outerNode ) {\n\n\tlet p = outerNode,\n\t\tqx = - Infinity,\n\t\tm;\n\n\tconst hx = hole.x, hy = hole.y;\n\n\t// find a segment intersected by a ray from the hole's leftmost point to the left;\n\t// segment's endpoint with lesser x will be potential connection point\n\tdo {\n\n\t\tif ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {\n\n\t\t\tconst x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );\n\t\t\tif ( x <= hx && x > qx ) {\n\n\t\t\t\tqx = x;\n\t\t\t\tm = p.x < p.next.x ? p : p.next;\n\t\t\t\tif ( x === hx ) return m; // hole touches outer segment; pick leftmost endpoint\n\n\t\t\t}\n\n\t\t}\n\n\t\tp = p.next;\n\n\t} while ( p !== outerNode );\n\n\tif ( ! m ) return null;\n\n\t// look for points inside the triangle of hole point, segment intersection and endpoint;\n\t// if there are no points found, we have a valid connection;\n\t// otherwise choose the point of the minimum angle with the ray as connection point\n\n\tconst stop = m,\n\t\tmx = m.x,\n\t\tmy = m.y;\n\tlet tanMin = Infinity, tan;\n\n\tp = m;\n\n\tdo {\n\n\t\tif ( hx >= p.x && p.x >= mx && hx !== p.x &&\n\t\t\t\tpointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {\n\n\t\t\ttan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential\n\n\t\t\tif ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) {\n\n\t\t\t\tm = p;\n\t\t\t\ttanMin = tan;\n\n\t\t\t}\n\n\t\t}\n\n\t\tp = p.next;\n\n\t} while ( p !== stop );\n\n\treturn m;\n\n}\n\n// whether sector in vertex m contains sector in vertex p in the same coordinates\nfunction sectorContainsSector( m, p ) {\n\n\treturn area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;\n\n}\n\n// interlink polygon nodes in z-order\nfunction indexCurve( start, minX, minY, invSize ) {\n\n\tlet p = start;\n\tdo {\n\n\t\tif ( p.z === 0 ) p.z = zOrder( p.x, p.y, minX, minY, invSize );\n\t\tp.prevZ = p.prev;\n\t\tp.nextZ = p.next;\n\t\tp = p.next;\n\n\t} while ( p !== start );\n\n\tp.prevZ.nextZ = null;\n\tp.prevZ = null;\n\n\tsortLinked( p );\n\n}\n\n// Simon Tatham's linked list merge sort algorithm\n// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html\nfunction sortLinked( list ) {\n\n\tlet i, p, q, e, tail, numMerges, pSize, qSize,\n\t\tinSize = 1;\n\n\tdo {\n\n\t\tp = list;\n\t\tlist = null;\n\t\ttail = null;\n\t\tnumMerges = 0;\n\n\t\twhile ( p ) {\n\n\t\t\tnumMerges ++;\n\t\t\tq = p;\n\t\t\tpSize = 0;\n\t\t\tfor ( i = 0; i < inSize; i ++ ) {\n\n\t\t\t\tpSize ++;\n\t\t\t\tq = q.nextZ;\n\t\t\t\tif ( ! q ) break;\n\n\t\t\t}\n\n\t\t\tqSize = inSize;\n\n\t\t\twhile ( pSize > 0 || ( qSize > 0 && q ) ) {\n\n\t\t\t\tif ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {\n\n\t\t\t\t\te = p;\n\t\t\t\t\tp = p.nextZ;\n\t\t\t\t\tpSize --;\n\n\t\t\t\t} else {\n\n\t\t\t\t\te = q;\n\t\t\t\t\tq = q.nextZ;\n\t\t\t\t\tqSize --;\n\n\t\t\t\t}\n\n\t\t\t\tif ( tail ) tail.nextZ = e;\n\t\t\t\telse list = e;\n\n\t\t\t\te.prevZ = tail;\n\t\t\t\ttail = e;\n\n\t\t\t}\n\n\t\t\tp = q;\n\n\t\t}\n\n\t\ttail.nextZ = null;\n\t\tinSize *= 2;\n\n\t} while ( numMerges > 1 );\n\n\treturn list;\n\n}\n\n// z-order of a point given coords and inverse of the longer side of data bbox\nfunction zOrder( x, y, minX, minY, invSize ) {\n\n\t// coords are transformed into non-negative 15-bit integer range\n\tx = ( x - minX ) * invSize | 0;\n\ty = ( y - minY ) * invSize | 0;\n\n\tx = ( x | ( x << 8 ) ) & 0x00FF00FF;\n\tx = ( x | ( x << 4 ) ) & 0x0F0F0F0F;\n\tx = ( x | ( x << 2 ) ) & 0x33333333;\n\tx = ( x | ( x << 1 ) ) & 0x55555555;\n\n\ty = ( y | ( y << 8 ) ) & 0x00FF00FF;\n\ty = ( y | ( y << 4 ) ) & 0x0F0F0F0F;\n\ty = ( y | ( y << 2 ) ) & 0x33333333;\n\ty = ( y | ( y << 1 ) ) & 0x55555555;\n\n\treturn x | ( y << 1 );\n\n}\n\n// find the leftmost node of a polygon ring\nfunction getLeftmost( start ) {\n\n\tlet p = start,\n\t\tleftmost = start;\n\tdo {\n\n\t\tif ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;\n\t\tp = p.next;\n\n\t} while ( p !== start );\n\n\treturn leftmost;\n\n}\n\n// check if a point lies within a convex triangle\nfunction pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {\n\n\treturn ( cx - px ) * ( ay - py ) >= ( ax - px ) * ( cy - py ) &&\n ( ax - px ) * ( by - py ) >= ( bx - px ) * ( ay - py ) &&\n ( bx - px ) * ( cy - py ) >= ( cx - px ) * ( by - py );\n\n}\n\n// check if a diagonal between two polygon nodes is valid (lies in polygon interior)\nfunction isValidDiagonal( a, b ) {\n\n\treturn a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges\n ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible\n ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors\n equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case\n\n}\n\n// signed area of a triangle\nfunction area( p, q, r ) {\n\n\treturn ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );\n\n}\n\n// check if two points are equal\nfunction equals( p1, p2 ) {\n\n\treturn p1.x === p2.x && p1.y === p2.y;\n\n}\n\n// check if two segments intersect\nfunction intersects( p1, q1, p2, q2 ) {\n\n\tconst o1 = sign( area( p1, q1, p2 ) );\n\tconst o2 = sign( area( p1, q1, q2 ) );\n\tconst o3 = sign( area( p2, q2, p1 ) );\n\tconst o4 = sign( area( p2, q2, q1 ) );\n\n\tif ( o1 !== o2 && o3 !== o4 ) return true; // general case\n\n\tif ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1\n\tif ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1\n\tif ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2\n\tif ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2\n\n\treturn false;\n\n}\n\n// for collinear points p, q, r, check if point q lies on segment pr\nfunction onSegment( p, q, r ) {\n\n\treturn 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 );\n\n}\n\nfunction sign( num ) {\n\n\treturn num > 0 ? 1 : num < 0 ? - 1 : 0;\n\n}\n\n// check if a polygon diagonal intersects any polygon segments\nfunction intersectsPolygon( a, b ) {\n\n\tlet p = a;\n\tdo {\n\n\t\tif ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&\n\t\t\tintersects( p, p.next, a, b ) ) return true;\n\t\tp = p.next;\n\n\t} while ( p !== a );\n\n\treturn false;\n\n}\n\n// check if a polygon diagonal is locally inside the polygon\nfunction locallyInside( a, b ) {\n\n\treturn area( a.prev, a, a.next ) < 0 ?\n\t\tarea( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 :\n\t\tarea( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0;\n\n}\n\n// check if the middle point of a polygon diagonal is inside the polygon\nfunction middleInside( a, b ) {\n\n\tlet p = a,\n\t\tinside = false;\n\tconst px = ( a.x + b.x ) / 2,\n\t\tpy = ( a.y + b.y ) / 2;\n\tdo {\n\n\t\tif ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&\n\t\t\t( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )\n\t\t\tinside = ! inside;\n\t\tp = p.next;\n\n\t} while ( p !== a );\n\n\treturn inside;\n\n}\n\n// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;\n// if one belongs to the outer ring and another to a hole, it merges it into a single ring\nfunction splitPolygon( a, b ) {\n\n\tconst a2 = new Node( a.i, a.x, a.y ),\n\t\tb2 = new Node( b.i, b.x, b.y ),\n\t\tan = a.next,\n\t\tbp = b.prev;\n\n\ta.next = b;\n\tb.prev = a;\n\n\ta2.next = an;\n\tan.prev = a2;\n\n\tb2.next = a2;\n\ta2.prev = b2;\n\n\tbp.next = b2;\n\tb2.prev = bp;\n\n\treturn b2;\n\n}\n\n// create a node and optionally link it with previous one (in a circular doubly linked list)\nfunction insertNode( i, x, y, last ) {\n\n\tconst p = new Node( i, x, y );\n\n\tif ( ! last ) {\n\n\t\tp.prev = p;\n\t\tp.next = p;\n\n\t} else {\n\n\t\tp.next = last.next;\n\t\tp.prev = last;\n\t\tlast.next.prev = p;\n\t\tlast.next = p;\n\n\t}\n\n\treturn p;\n\n}\n\nfunction removeNode( p ) {\n\n\tp.next.prev = p.prev;\n\tp.prev.next = p.next;\n\n\tif ( p.prevZ ) p.prevZ.nextZ = p.nextZ;\n\tif ( p.nextZ ) p.nextZ.prevZ = p.prevZ;\n\n}\n\nfunction Node( i, x, y ) {\n\n\t// vertex index in coordinates array\n\tthis.i = i;\n\n\t// vertex coordinates\n\tthis.x = x;\n\tthis.y = y;\n\n\t// previous and next vertex nodes in a polygon ring\n\tthis.prev = null;\n\tthis.next = null;\n\n\t// z-order curve value\n\tthis.z = 0;\n\n\t// previous and next nodes in z-order\n\tthis.prevZ = null;\n\tthis.nextZ = null;\n\n\t// indicates whether this is a steiner point\n\tthis.steiner = false;\n\n}\n\nfunction signedArea( data, start, end, dim ) {\n\n\tlet sum = 0;\n\tfor ( let i = start, j = end - dim; i < end; i += dim ) {\n\n\t\tsum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );\n\t\tj = i;\n\n\t}\n\n\treturn sum;\n\n}\n\nclass ShapeUtils {\n\n\t// calculate area of the contour polygon\n\n\tstatic area( contour ) {\n\n\t\tconst n = contour.length;\n\t\tlet a = 0.0;\n\n\t\tfor ( let p = n - 1, q = 0; q < n; p = q ++ ) {\n\n\t\t\ta += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;\n\n\t\t}\n\n\t\treturn a * 0.5;\n\n\t}\n\n\tstatic isClockWise( pts ) {\n\n\t\treturn ShapeUtils.area( pts ) < 0;\n\n\t}\n\n\tstatic triangulateShape( contour, holes ) {\n\n\t\tconst vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]\n\t\tconst holeIndices = []; // array of hole indices\n\t\tconst faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]\n\n\t\tremoveDupEndPts( contour );\n\t\taddContour( vertices, contour );\n\n\t\t//\n\n\t\tlet holeIndex = contour.length;\n\n\t\tholes.forEach( removeDupEndPts );\n\n\t\tfor ( let i = 0; i < holes.length; i ++ ) {\n\n\t\t\tholeIndices.push( holeIndex );\n\t\t\tholeIndex += holes[ i ].length;\n\t\t\taddContour( vertices, holes[ i ] );\n\n\t\t}\n\n\t\t//\n\n\t\tconst triangles = Earcut.triangulate( vertices, holeIndices );\n\n\t\t//\n\n\t\tfor ( let i = 0; i < triangles.length; i += 3 ) {\n\n\t\t\tfaces.push( triangles.slice( i, i + 3 ) );\n\n\t\t}\n\n\t\treturn faces;\n\n\t}\n\n}\n\nfunction removeDupEndPts( points ) {\n\n\tconst l = points.length;\n\n\tif ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {\n\n\t\tpoints.pop();\n\n\t}\n\n}\n\nfunction addContour( vertices, contour ) {\n\n\tfor ( let i = 0; i < contour.length; i ++ ) {\n\n\t\tvertices.push( contour[ i ].x );\n\t\tvertices.push( contour[ i ].y );\n\n\t}\n\n}\n\n/**\n * Creates extruded geometry from a path shape.\n *\n * parameters = {\n *\n * curveSegments: , // number of points on the curves\n * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too\n * depth: , // Depth to extrude the shape\n *\n * bevelEnabled: , // turn on bevel\n * bevelThickness: , // how deep into the original shape bevel goes\n * bevelSize: , // how far from shape outline (including bevelOffset) is bevel\n * bevelOffset: , // how far from shape outline does bevel start\n * bevelSegments: , // number of bevel layers\n *\n * extrudePath: // curve to extrude shape along\n *\n * UVGenerator: // object that provides UV generator functions\n *\n * }\n */\n\n\nclass ExtrudeGeometry extends BufferGeometry {\n\n\tconstructor( 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 = {} ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'ExtrudeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tshapes: shapes,\n\t\t\toptions: options\n\t\t};\n\n\t\tshapes = Array.isArray( shapes ) ? shapes : [ shapes ];\n\n\t\tconst scope = this;\n\n\t\tconst verticesArray = [];\n\t\tconst uvArray = [];\n\n\t\tfor ( let i = 0, l = shapes.length; i < l; i ++ ) {\n\n\t\t\tconst shape = shapes[ i ];\n\t\t\taddShape( shape );\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );\n\n\t\tthis.computeVertexNormals();\n\n\t\t// functions\n\n\t\tfunction addShape( shape ) {\n\n\t\t\tconst placeholder = [];\n\n\t\t\t// options\n\n\t\t\tconst curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;\n\t\t\tconst steps = options.steps !== undefined ? options.steps : 1;\n\t\t\tconst depth = options.depth !== undefined ? options.depth : 1;\n\n\t\t\tlet bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;\n\t\t\tlet bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2;\n\t\t\tlet bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1;\n\t\t\tlet bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0;\n\t\t\tlet bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;\n\n\t\t\tconst extrudePath = options.extrudePath;\n\n\t\t\tconst uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;\n\n\t\t\t//\n\n\t\t\tlet extrudePts, extrudeByPath = false;\n\t\t\tlet splineTube, binormal, normal, position2;\n\n\t\t\tif ( extrudePath ) {\n\n\t\t\t\textrudePts = extrudePath.getSpacedPoints( steps );\n\n\t\t\t\textrudeByPath = true;\n\t\t\t\tbevelEnabled = false; // bevels not supported for path extrusion\n\n\t\t\t\t// SETUP TNB variables\n\n\t\t\t\t// TODO1 - have a .isClosed in spline?\n\n\t\t\t\tsplineTube = extrudePath.computeFrenetFrames( steps, false );\n\n\t\t\t\t// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);\n\n\t\t\t\tbinormal = new Vector3();\n\t\t\t\tnormal = new Vector3();\n\t\t\t\tposition2 = new Vector3();\n\n\t\t\t}\n\n\t\t\t// Safeguards if bevels are not enabled\n\n\t\t\tif ( ! bevelEnabled ) {\n\n\t\t\t\tbevelSegments = 0;\n\t\t\t\tbevelThickness = 0;\n\t\t\t\tbevelSize = 0;\n\t\t\t\tbevelOffset = 0;\n\n\t\t\t}\n\n\t\t\t// Variables initialization\n\n\t\t\tconst shapePoints = shape.extractPoints( curveSegments );\n\n\t\t\tlet vertices = shapePoints.shape;\n\t\t\tconst holes = shapePoints.holes;\n\n\t\t\tconst reverse = ! ShapeUtils.isClockWise( vertices );\n\n\t\t\tif ( reverse ) {\n\n\t\t\t\tvertices = vertices.reverse();\n\n\t\t\t\t// Maybe we should also check if holes are in the opposite direction, just to be safe ...\n\n\t\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\t\tconst ahole = holes[ h ];\n\n\t\t\t\t\tif ( ShapeUtils.isClockWise( ahole ) ) {\n\n\t\t\t\t\t\tholes[ h ] = ahole.reverse();\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t\tconst faces = ShapeUtils.triangulateShape( vertices, holes );\n\n\t\t\t/* Vertices */\n\n\t\t\tconst contour = vertices; // vertices has all points but contour has only points of circumference\n\n\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\tconst ahole = holes[ h ];\n\n\t\t\t\tvertices = vertices.concat( ahole );\n\n\t\t\t}\n\n\n\t\t\tfunction scalePt2( pt, vec, size ) {\n\n\t\t\t\tif ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' );\n\n\t\t\t\treturn pt.clone().addScaledVector( vec, size );\n\n\t\t\t}\n\n\t\t\tconst vlen = vertices.length, flen = faces.length;\n\n\n\t\t\t// Find directions for point movement\n\n\n\t\t\tfunction getBevelVec( inPt, inPrev, inNext ) {\n\n\t\t\t\t// computes for inPt the corresponding point inPt' on a new contour\n\t\t\t\t// shifted by 1 unit (length of normalized vector) to the left\n\t\t\t\t// if we walk along contour clockwise, this new contour is outside the old one\n\t\t\t\t//\n\t\t\t\t// inPt' is the intersection of the two lines parallel to the two\n\t\t\t\t// adjacent edges of inPt at a distance of 1 unit on the left side.\n\n\t\t\t\tlet v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt\n\n\t\t\t\t// good reading for geometry algorithms (here: line-line intersection)\n\t\t\t\t// http://geomalgorithms.com/a05-_intersect-1.html\n\n\t\t\t\tconst v_prev_x = inPt.x - inPrev.x,\n\t\t\t\t\tv_prev_y = inPt.y - inPrev.y;\n\t\t\t\tconst v_next_x = inNext.x - inPt.x,\n\t\t\t\t\tv_next_y = inNext.y - inPt.y;\n\n\t\t\t\tconst v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );\n\n\t\t\t\t// check for collinear edges\n\t\t\t\tconst collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );\n\n\t\t\t\tif ( Math.abs( collinear0 ) > Number.EPSILON ) {\n\n\t\t\t\t\t// not collinear\n\n\t\t\t\t\t// length of vectors for normalizing\n\n\t\t\t\t\tconst v_prev_len = Math.sqrt( v_prev_lensq );\n\t\t\t\t\tconst v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );\n\n\t\t\t\t\t// shift adjacent points by unit vectors to the left\n\n\t\t\t\t\tconst ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );\n\t\t\t\t\tconst ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );\n\n\t\t\t\t\tconst ptNextShift_x = ( inNext.x - v_next_y / v_next_len );\n\t\t\t\t\tconst ptNextShift_y = ( inNext.y + v_next_x / v_next_len );\n\n\t\t\t\t\t// scaling factor for v_prev to intersection point\n\n\t\t\t\t\tconst sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -\n\t\t\t\t\t\t\t( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /\n\t\t\t\t\t\t( v_prev_x * v_next_y - v_prev_y * v_next_x );\n\n\t\t\t\t\t// vector from inPt to intersection point\n\n\t\t\t\t\tv_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );\n\t\t\t\t\tv_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );\n\n\t\t\t\t\t// Don't normalize!, otherwise sharp corners become ugly\n\t\t\t\t\t// but prevent crazy spikes\n\t\t\t\t\tconst v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );\n\t\t\t\t\tif ( v_trans_lensq <= 2 ) {\n\n\t\t\t\t\t\treturn new Vector2( v_trans_x, v_trans_y );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tshrink_by = Math.sqrt( v_trans_lensq / 2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// handle special case of collinear edges\n\n\t\t\t\t\tlet direction_eq = false; // assumes: opposite\n\n\t\t\t\t\tif ( v_prev_x > Number.EPSILON ) {\n\n\t\t\t\t\t\tif ( v_next_x > Number.EPSILON ) {\n\n\t\t\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( v_prev_x < - Number.EPSILON ) {\n\n\t\t\t\t\t\t\tif ( v_next_x < - Number.EPSILON ) {\n\n\t\t\t\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tif ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {\n\n\t\t\t\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( direction_eq ) {\n\n\t\t\t\t\t\t// console.log(\"Warning: lines are a straight sequence\");\n\t\t\t\t\t\tv_trans_x = - v_prev_y;\n\t\t\t\t\t\tv_trans_y = v_prev_x;\n\t\t\t\t\t\tshrink_by = Math.sqrt( v_prev_lensq );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// console.log(\"Warning: lines are a straight spike\");\n\t\t\t\t\t\tv_trans_x = v_prev_x;\n\t\t\t\t\t\tv_trans_y = v_prev_y;\n\t\t\t\t\t\tshrink_by = Math.sqrt( v_prev_lensq / 2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );\n\n\t\t\t}\n\n\n\t\t\tconst contourMovements = [];\n\n\t\t\tfor ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {\n\n\t\t\t\tif ( j === il ) j = 0;\n\t\t\t\tif ( k === il ) k = 0;\n\n\t\t\t\t// (j)---(i)---(k)\n\t\t\t\t// console.log('i,j,k', i, j , k)\n\n\t\t\t\tcontourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );\n\n\t\t\t}\n\n\t\t\tconst holesMovements = [];\n\t\t\tlet oneHoleMovements, verticesMovements = contourMovements.concat();\n\n\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\tconst ahole = holes[ h ];\n\n\t\t\t\toneHoleMovements = [];\n\n\t\t\t\tfor ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {\n\n\t\t\t\t\tif ( j === il ) j = 0;\n\t\t\t\t\tif ( k === il ) k = 0;\n\n\t\t\t\t\t// (j)---(i)---(k)\n\t\t\t\t\toneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );\n\n\t\t\t\t}\n\n\t\t\t\tholesMovements.push( oneHoleMovements );\n\t\t\t\tverticesMovements = verticesMovements.concat( oneHoleMovements );\n\n\t\t\t}\n\n\n\t\t\t// Loop bevelSegments, 1 for the front, 1 for the back\n\n\t\t\tfor ( let b = 0; b < bevelSegments; b ++ ) {\n\n\t\t\t\t//for ( b = bevelSegments; b > 0; b -- ) {\n\n\t\t\t\tconst t = b / bevelSegments;\n\t\t\t\tconst z = bevelThickness * Math.cos( t * Math.PI / 2 );\n\t\t\t\tconst bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;\n\n\t\t\t\t// contract shape\n\n\t\t\t\tfor ( let i = 0, il = contour.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst vert = scalePt2( contour[ i ], contourMovements[ i ], bs );\n\n\t\t\t\t\tv( vert.x, vert.y, - z );\n\n\t\t\t\t}\n\n\t\t\t\t// expand holes\n\n\t\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\t\tconst ahole = holes[ h ];\n\t\t\t\t\toneHoleMovements = holesMovements[ h ];\n\n\t\t\t\t\tfor ( let i = 0, il = ahole.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tconst vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );\n\n\t\t\t\t\t\tv( vert.x, vert.y, - z );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst bs = bevelSize + bevelOffset;\n\n\t\t\t// Back facing vertices\n\n\t\t\tfor ( let i = 0; i < vlen; i ++ ) {\n\n\t\t\t\tconst vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];\n\n\t\t\t\tif ( ! extrudeByPath ) {\n\n\t\t\t\t\tv( vert.x, vert.y, 0 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );\n\n\t\t\t\t\tnormal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );\n\t\t\t\t\tbinormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );\n\n\t\t\t\t\tposition2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );\n\n\t\t\t\t\tv( position2.x, position2.y, position2.z );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// Add stepped vertices...\n\t\t\t// Including front facing vertices\n\n\t\t\tfor ( let s = 1; s <= steps; s ++ ) {\n\n\t\t\t\tfor ( let i = 0; i < vlen; i ++ ) {\n\n\t\t\t\t\tconst vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];\n\n\t\t\t\t\tif ( ! extrudeByPath ) {\n\n\t\t\t\t\t\tv( vert.x, vert.y, depth / steps * s );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );\n\n\t\t\t\t\t\tnormal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );\n\t\t\t\t\t\tbinormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );\n\n\t\t\t\t\t\tposition2.copy( extrudePts[ s ] ).add( normal ).add( binormal );\n\n\t\t\t\t\t\tv( position2.x, position2.y, position2.z );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t\t// Add bevel segments planes\n\n\t\t\t//for ( b = 1; b <= bevelSegments; b ++ ) {\n\t\t\tfor ( let b = bevelSegments - 1; b >= 0; b -- ) {\n\n\t\t\t\tconst t = b / bevelSegments;\n\t\t\t\tconst z = bevelThickness * Math.cos( t * Math.PI / 2 );\n\t\t\t\tconst bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;\n\n\t\t\t\t// contract shape\n\n\t\t\t\tfor ( let i = 0, il = contour.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst vert = scalePt2( contour[ i ], contourMovements[ i ], bs );\n\t\t\t\t\tv( vert.x, vert.y, depth + z );\n\n\t\t\t\t}\n\n\t\t\t\t// expand holes\n\n\t\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\t\tconst ahole = holes[ h ];\n\t\t\t\t\toneHoleMovements = holesMovements[ h ];\n\n\t\t\t\t\tfor ( let i = 0, il = ahole.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tconst vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );\n\n\t\t\t\t\t\tif ( ! extrudeByPath ) {\n\n\t\t\t\t\t\t\tv( vert.x, vert.y, depth + z );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tv( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t/* Faces */\n\n\t\t\t// Top and bottom faces\n\n\t\t\tbuildLidFaces();\n\n\t\t\t// Sides faces\n\n\t\t\tbuildSideFaces();\n\n\n\t\t\t///// Internal functions\n\n\t\t\tfunction buildLidFaces() {\n\n\t\t\t\tconst start = verticesArray.length / 3;\n\n\t\t\t\tif ( bevelEnabled ) {\n\n\t\t\t\t\tlet layer = 0; // steps + 1\n\t\t\t\t\tlet offset = vlen * layer;\n\n\t\t\t\t\t// Bottom faces\n\n\t\t\t\t\tfor ( let i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\t\tconst face = faces[ i ];\n\t\t\t\t\t\tf3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlayer = steps + bevelSegments * 2;\n\t\t\t\t\toffset = vlen * layer;\n\n\t\t\t\t\t// Top faces\n\n\t\t\t\t\tfor ( let i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\t\tconst face = faces[ i ];\n\t\t\t\t\t\tf3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// Bottom faces\n\n\t\t\t\t\tfor ( let i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\t\tconst face = faces[ i ];\n\t\t\t\t\t\tf3( face[ 2 ], face[ 1 ], face[ 0 ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// Top faces\n\n\t\t\t\t\tfor ( let i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\t\tconst face = faces[ i ];\n\t\t\t\t\t\tf3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tscope.addGroup( start, verticesArray.length / 3 - start, 0 );\n\n\t\t\t}\n\n\t\t\t// Create faces for the z-sides of the shape\n\n\t\t\tfunction buildSideFaces() {\n\n\t\t\t\tconst start = verticesArray.length / 3;\n\t\t\t\tlet layeroffset = 0;\n\t\t\t\tsidewalls( contour, layeroffset );\n\t\t\t\tlayeroffset += contour.length;\n\n\t\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\t\tconst ahole = holes[ h ];\n\t\t\t\t\tsidewalls( ahole, layeroffset );\n\n\t\t\t\t\t//, true\n\t\t\t\t\tlayeroffset += ahole.length;\n\n\t\t\t\t}\n\n\n\t\t\t\tscope.addGroup( start, verticesArray.length / 3 - start, 1 );\n\n\n\t\t\t}\n\n\t\t\tfunction sidewalls( contour, layeroffset ) {\n\n\t\t\t\tlet i = contour.length;\n\n\t\t\t\twhile ( -- i >= 0 ) {\n\n\t\t\t\t\tconst j = i;\n\t\t\t\t\tlet k = i - 1;\n\t\t\t\t\tif ( k < 0 ) k = contour.length - 1;\n\n\t\t\t\t\t//console.log('b', i,j, i-1, k,vertices.length);\n\n\t\t\t\t\tfor ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) {\n\n\t\t\t\t\t\tconst slen1 = vlen * s;\n\t\t\t\t\t\tconst slen2 = vlen * ( s + 1 );\n\n\t\t\t\t\t\tconst a = layeroffset + j + slen1,\n\t\t\t\t\t\t\tb = layeroffset + k + slen1,\n\t\t\t\t\t\t\tc = layeroffset + k + slen2,\n\t\t\t\t\t\t\td = layeroffset + j + slen2;\n\n\t\t\t\t\t\tf4( a, b, c, d );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfunction v( x, y, z ) {\n\n\t\t\t\tplaceholder.push( x );\n\t\t\t\tplaceholder.push( y );\n\t\t\t\tplaceholder.push( z );\n\n\t\t\t}\n\n\n\t\t\tfunction f3( a, b, c ) {\n\n\t\t\t\taddVertex( a );\n\t\t\t\taddVertex( b );\n\t\t\t\taddVertex( c );\n\n\t\t\t\tconst nextIndex = verticesArray.length / 3;\n\t\t\t\tconst uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );\n\n\t\t\t\taddUV( uvs[ 0 ] );\n\t\t\t\taddUV( uvs[ 1 ] );\n\t\t\t\taddUV( uvs[ 2 ] );\n\n\t\t\t}\n\n\t\t\tfunction f4( a, b, c, d ) {\n\n\t\t\t\taddVertex( a );\n\t\t\t\taddVertex( b );\n\t\t\t\taddVertex( d );\n\n\t\t\t\taddVertex( b );\n\t\t\t\taddVertex( c );\n\t\t\t\taddVertex( d );\n\n\n\t\t\t\tconst nextIndex = verticesArray.length / 3;\n\t\t\t\tconst uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );\n\n\t\t\t\taddUV( uvs[ 0 ] );\n\t\t\t\taddUV( uvs[ 1 ] );\n\t\t\t\taddUV( uvs[ 3 ] );\n\n\t\t\t\taddUV( uvs[ 1 ] );\n\t\t\t\taddUV( uvs[ 2 ] );\n\t\t\t\taddUV( uvs[ 3 ] );\n\n\t\t\t}\n\n\t\t\tfunction addVertex( index ) {\n\n\t\t\t\tverticesArray.push( placeholder[ index * 3 + 0 ] );\n\t\t\t\tverticesArray.push( placeholder[ index * 3 + 1 ] );\n\t\t\t\tverticesArray.push( placeholder[ index * 3 + 2 ] );\n\n\t\t\t}\n\n\n\t\t\tfunction addUV( vector2 ) {\n\n\t\t\t\tuvArray.push( vector2.x );\n\t\t\t\tuvArray.push( vector2.y );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tconst shapes = this.parameters.shapes;\n\t\tconst options = this.parameters.options;\n\n\t\treturn toJSON$1( shapes, options, data );\n\n\t}\n\n\tstatic fromJSON( data, shapes ) {\n\n\t\tconst geometryShapes = [];\n\n\t\tfor ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {\n\n\t\t\tconst shape = shapes[ data.shapes[ j ] ];\n\n\t\t\tgeometryShapes.push( shape );\n\n\t\t}\n\n\t\tconst extrudePath = data.options.extrudePath;\n\n\t\tif ( extrudePath !== undefined ) {\n\n\t\t\tdata.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath );\n\n\t\t}\n\n\t\treturn new ExtrudeGeometry( geometryShapes, data.options );\n\n\t}\n\n}\n\nconst WorldUVGenerator = {\n\n\tgenerateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {\n\n\t\tconst a_x = vertices[ indexA * 3 ];\n\t\tconst a_y = vertices[ indexA * 3 + 1 ];\n\t\tconst b_x = vertices[ indexB * 3 ];\n\t\tconst b_y = vertices[ indexB * 3 + 1 ];\n\t\tconst c_x = vertices[ indexC * 3 ];\n\t\tconst c_y = vertices[ indexC * 3 + 1 ];\n\n\t\treturn [\n\t\t\tnew Vector2( a_x, a_y ),\n\t\t\tnew Vector2( b_x, b_y ),\n\t\t\tnew Vector2( c_x, c_y )\n\t\t];\n\n\t},\n\n\tgenerateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {\n\n\t\tconst a_x = vertices[ indexA * 3 ];\n\t\tconst a_y = vertices[ indexA * 3 + 1 ];\n\t\tconst a_z = vertices[ indexA * 3 + 2 ];\n\t\tconst b_x = vertices[ indexB * 3 ];\n\t\tconst b_y = vertices[ indexB * 3 + 1 ];\n\t\tconst b_z = vertices[ indexB * 3 + 2 ];\n\t\tconst c_x = vertices[ indexC * 3 ];\n\t\tconst c_y = vertices[ indexC * 3 + 1 ];\n\t\tconst c_z = vertices[ indexC * 3 + 2 ];\n\t\tconst d_x = vertices[ indexD * 3 ];\n\t\tconst d_y = vertices[ indexD * 3 + 1 ];\n\t\tconst d_z = vertices[ indexD * 3 + 2 ];\n\n\t\tif ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) {\n\n\t\t\treturn [\n\t\t\t\tnew Vector2( a_x, 1 - a_z ),\n\t\t\t\tnew Vector2( b_x, 1 - b_z ),\n\t\t\t\tnew Vector2( c_x, 1 - c_z ),\n\t\t\t\tnew Vector2( d_x, 1 - d_z )\n\t\t\t];\n\n\t\t} else {\n\n\t\t\treturn [\n\t\t\t\tnew Vector2( a_y, 1 - a_z ),\n\t\t\t\tnew Vector2( b_y, 1 - b_z ),\n\t\t\t\tnew Vector2( c_y, 1 - c_z ),\n\t\t\t\tnew Vector2( d_y, 1 - d_z )\n\t\t\t];\n\n\t\t}\n\n\t}\n\n};\n\nfunction toJSON$1( shapes, options, data ) {\n\n\tdata.shapes = [];\n\n\tif ( Array.isArray( shapes ) ) {\n\n\t\tfor ( let i = 0, l = shapes.length; i < l; i ++ ) {\n\n\t\t\tconst shape = shapes[ i ];\n\n\t\t\tdata.shapes.push( shape.uuid );\n\n\t\t}\n\n\t} else {\n\n\t\tdata.shapes.push( shapes.uuid );\n\n\t}\n\n\tdata.options = Object.assign( {}, options );\n\n\tif ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();\n\n\treturn data;\n\n}\n\nclass IcosahedronGeometry extends PolyhedronGeometry {\n\n\tconstructor( radius = 1, detail = 0 ) {\n\n\t\tconst t = ( 1 + Math.sqrt( 5 ) ) / 2;\n\n\t\tconst vertices = [\n\t\t\t- 1, t, 0, \t1, t, 0, \t- 1, - t, 0, \t1, - t, 0,\n\t\t\t0, - 1, t, \t0, 1, t,\t0, - 1, - t, \t0, 1, - t,\n\t\t\tt, 0, - 1, \tt, 0, 1, \t- t, 0, - 1, \t- t, 0, 1\n\t\t];\n\n\t\tconst indices = [\n\t\t\t0, 11, 5, \t0, 5, 1, \t0, 1, 7, \t0, 7, 10, \t0, 10, 11,\n\t\t\t1, 5, 9, \t5, 11, 4,\t11, 10, 2,\t10, 7, 6,\t7, 1, 8,\n\t\t\t3, 9, 4, \t3, 4, 2,\t3, 2, 6,\t3, 6, 8,\t3, 8, 9,\n\t\t\t4, 9, 5, \t2, 4, 11,\t6, 2, 10,\t8, 6, 7,\t9, 8, 1\n\t\t];\n\n\t\tsuper( vertices, indices, radius, detail );\n\n\t\tthis.type = 'IcosahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new IcosahedronGeometry( data.radius, data.detail );\n\n\t}\n\n}\n\nclass OctahedronGeometry extends PolyhedronGeometry {\n\n\tconstructor( radius = 1, detail = 0 ) {\n\n\t\tconst vertices = [\n\t\t\t1, 0, 0, \t- 1, 0, 0,\t0, 1, 0,\n\t\t\t0, - 1, 0, \t0, 0, 1,\t0, 0, - 1\n\t\t];\n\n\t\tconst indices = [\n\t\t\t0, 2, 4,\t0, 4, 3,\t0, 3, 5,\n\t\t\t0, 5, 2,\t1, 2, 5,\t1, 5, 3,\n\t\t\t1, 3, 4,\t1, 4, 2\n\t\t];\n\n\t\tsuper( vertices, indices, radius, detail );\n\n\t\tthis.type = 'OctahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new OctahedronGeometry( data.radius, data.detail );\n\n\t}\n\n}\n\nclass RingGeometry extends BufferGeometry {\n\n\tconstructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'RingGeometry';\n\n\t\tthis.parameters = {\n\t\t\tinnerRadius: innerRadius,\n\t\t\touterRadius: outerRadius,\n\t\t\tthetaSegments: thetaSegments,\n\t\t\tphiSegments: phiSegments,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tthetaSegments = Math.max( 3, thetaSegments );\n\t\tphiSegments = Math.max( 1, phiSegments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// some helper variables\n\n\t\tlet radius = innerRadius;\n\t\tconst radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );\n\t\tconst vertex = new Vector3();\n\t\tconst uv = new Vector2();\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( let j = 0; j <= phiSegments; j ++ ) {\n\n\t\t\tfor ( let i = 0; i <= thetaSegments; i ++ ) {\n\n\t\t\t\t// values are generate from the inside of the ring to the outside\n\n\t\t\t\tconst segment = thetaStart + i / thetaSegments * thetaLength;\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = radius * Math.cos( segment );\n\t\t\t\tvertex.y = radius * Math.sin( segment );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormals.push( 0, 0, 1 );\n\n\t\t\t\t// uv\n\n\t\t\t\tuv.x = ( vertex.x / outerRadius + 1 ) / 2;\n\t\t\t\tuv.y = ( vertex.y / outerRadius + 1 ) / 2;\n\n\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t}\n\n\t\t\t// increase the radius for next row of vertices\n\n\t\t\tradius += radiusStep;\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( let j = 0; j < phiSegments; j ++ ) {\n\n\t\t\tconst thetaSegmentLevel = j * ( thetaSegments + 1 );\n\n\t\t\tfor ( let i = 0; i < thetaSegments; i ++ ) {\n\n\t\t\t\tconst segment = i + thetaSegmentLevel;\n\n\t\t\t\tconst a = segment;\n\t\t\t\tconst b = segment + thetaSegments + 1;\n\t\t\t\tconst c = segment + thetaSegments + 2;\n\t\t\t\tconst d = segment + 1;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength );\n\n\t}\n\n}\n\nclass ShapeGeometry extends BufferGeometry {\n\n\tconstructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'ShapeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tshapes: shapes,\n\t\t\tcurveSegments: curveSegments\n\t\t};\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tlet groupStart = 0;\n\t\tlet groupCount = 0;\n\n\t\t// allow single and array values for \"shapes\" parameter\n\n\t\tif ( Array.isArray( shapes ) === false ) {\n\n\t\t\taddShape( shapes );\n\n\t\t} else {\n\n\t\t\tfor ( let i = 0; i < shapes.length; i ++ ) {\n\n\t\t\t\taddShape( shapes[ i ] );\n\n\t\t\t\tthis.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support\n\n\t\t\t\tgroupStart += groupCount;\n\t\t\t\tgroupCount = 0;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\n\t\t// helper functions\n\n\t\tfunction addShape( shape ) {\n\n\t\t\tconst indexOffset = vertices.length / 3;\n\t\t\tconst points = shape.extractPoints( curveSegments );\n\n\t\t\tlet shapeVertices = points.shape;\n\t\t\tconst shapeHoles = points.holes;\n\n\t\t\t// check direction of vertices\n\n\t\t\tif ( ShapeUtils.isClockWise( shapeVertices ) === false ) {\n\n\t\t\t\tshapeVertices = shapeVertices.reverse();\n\n\t\t\t}\n\n\t\t\tfor ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {\n\n\t\t\t\tconst shapeHole = shapeHoles[ i ];\n\n\t\t\t\tif ( ShapeUtils.isClockWise( shapeHole ) === true ) {\n\n\t\t\t\t\tshapeHoles[ i ] = shapeHole.reverse();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );\n\n\t\t\t// join vertices of inner and outer paths to a single array\n\n\t\t\tfor ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {\n\n\t\t\t\tconst shapeHole = shapeHoles[ i ];\n\t\t\t\tshapeVertices = shapeVertices.concat( shapeHole );\n\n\t\t\t}\n\n\t\t\t// vertices, normals, uvs\n\n\t\t\tfor ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {\n\n\t\t\t\tconst vertex = shapeVertices[ i ];\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, 0 );\n\t\t\t\tnormals.push( 0, 0, 1 );\n\t\t\t\tuvs.push( vertex.x, vertex.y ); // world uvs\n\n\t\t\t}\n\n\t\t\t// indices\n\n\t\t\tfor ( let i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\t\tconst face = faces[ i ];\n\n\t\t\t\tconst a = face[ 0 ] + indexOffset;\n\t\t\t\tconst b = face[ 1 ] + indexOffset;\n\t\t\t\tconst c = face[ 2 ] + indexOffset;\n\n\t\t\t\tindices.push( a, b, c );\n\t\t\t\tgroupCount += 3;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tconst shapes = this.parameters.shapes;\n\n\t\treturn toJSON( shapes, data );\n\n\t}\n\n\tstatic fromJSON( data, shapes ) {\n\n\t\tconst geometryShapes = [];\n\n\t\tfor ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {\n\n\t\t\tconst shape = shapes[ data.shapes[ j ] ];\n\n\t\t\tgeometryShapes.push( shape );\n\n\t\t}\n\n\t\treturn new ShapeGeometry( geometryShapes, data.curveSegments );\n\n\t}\n\n}\n\nfunction toJSON( shapes, data ) {\n\n\tdata.shapes = [];\n\n\tif ( Array.isArray( shapes ) ) {\n\n\t\tfor ( let i = 0, l = shapes.length; i < l; i ++ ) {\n\n\t\t\tconst shape = shapes[ i ];\n\n\t\t\tdata.shapes.push( shape.uuid );\n\n\t\t}\n\n\t} else {\n\n\t\tdata.shapes.push( shapes.uuid );\n\n\t}\n\n\treturn data;\n\n}\n\nclass SphereGeometry extends BufferGeometry {\n\n\tconstructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'SphereGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\tphiStart: phiStart,\n\t\t\tphiLength: phiLength,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\twidthSegments = Math.max( 3, Math.floor( widthSegments ) );\n\t\theightSegments = Math.max( 2, Math.floor( heightSegments ) );\n\n\t\tconst thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );\n\n\t\tlet index = 0;\n\t\tconst grid = [];\n\n\t\tconst vertex = new Vector3();\n\t\tconst normal = new Vector3();\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( let iy = 0; iy <= heightSegments; iy ++ ) {\n\n\t\t\tconst verticesRow = [];\n\n\t\t\tconst v = iy / heightSegments;\n\n\t\t\t// special case for the poles\n\n\t\t\tlet uOffset = 0;\n\n\t\t\tif ( iy === 0 && thetaStart === 0 ) {\n\n\t\t\t\tuOffset = 0.5 / widthSegments;\n\n\t\t\t} else if ( iy === heightSegments && thetaEnd === Math.PI ) {\n\n\t\t\t\tuOffset = - 0.5 / widthSegments;\n\n\t\t\t}\n\n\t\t\tfor ( let ix = 0; ix <= widthSegments; ix ++ ) {\n\n\t\t\t\tconst u = ix / widthSegments;\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );\n\t\t\t\tvertex.y = radius * Math.cos( thetaStart + v * thetaLength );\n\t\t\t\tvertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormal.copy( vertex ).normalize();\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( u + uOffset, 1 - v );\n\n\t\t\t\tverticesRow.push( index ++ );\n\n\t\t\t}\n\n\t\t\tgrid.push( verticesRow );\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( let iy = 0; iy < heightSegments; iy ++ ) {\n\n\t\t\tfor ( let ix = 0; ix < widthSegments; ix ++ ) {\n\n\t\t\t\tconst a = grid[ iy ][ ix + 1 ];\n\t\t\t\tconst b = grid[ iy ][ ix ];\n\t\t\t\tconst c = grid[ iy + 1 ][ ix ];\n\t\t\t\tconst d = grid[ iy + 1 ][ ix + 1 ];\n\n\t\t\t\tif ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );\n\t\t\t\tif ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength );\n\n\t}\n\n}\n\nclass TetrahedronGeometry extends PolyhedronGeometry {\n\n\tconstructor( radius = 1, detail = 0 ) {\n\n\t\tconst vertices = [\n\t\t\t1, 1, 1, \t- 1, - 1, 1, \t- 1, 1, - 1, \t1, - 1, - 1\n\t\t];\n\n\t\tconst indices = [\n\t\t\t2, 1, 0, \t0, 3, 2,\t1, 3, 0,\t2, 3, 1\n\t\t];\n\n\t\tsuper( vertices, indices, radius, detail );\n\n\t\tthis.type = 'TetrahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new TetrahedronGeometry( data.radius, data.detail );\n\n\t}\n\n}\n\nclass TorusGeometry extends BufferGeometry {\n\n\tconstructor( radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'TorusGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\ttube: tube,\n\t\t\tradialSegments: radialSegments,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tarc: arc\n\t\t};\n\n\t\tradialSegments = Math.floor( radialSegments );\n\t\ttubularSegments = Math.floor( tubularSegments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tconst center = new Vector3();\n\t\tconst vertex = new Vector3();\n\t\tconst normal = new Vector3();\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( let j = 0; j <= radialSegments; j ++ ) {\n\n\t\t\tfor ( let i = 0; i <= tubularSegments; i ++ ) {\n\n\t\t\t\tconst u = i / tubularSegments * arc;\n\t\t\t\tconst v = j / radialSegments * Math.PI * 2;\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );\n\t\t\t\tvertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );\n\t\t\t\tvertex.z = tube * Math.sin( v );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tcenter.x = radius * Math.cos( u );\n\t\t\t\tcenter.y = radius * Math.sin( u );\n\t\t\t\tnormal.subVectors( vertex, center ).normalize();\n\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( i / tubularSegments );\n\t\t\t\tuvs.push( j / radialSegments );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate indices\n\n\t\tfor ( let j = 1; j <= radialSegments; j ++ ) {\n\n\t\t\tfor ( let i = 1; i <= tubularSegments; i ++ ) {\n\n\t\t\t\t// indices\n\n\t\t\t\tconst a = ( tubularSegments + 1 ) * j + i - 1;\n\t\t\t\tconst b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;\n\t\t\t\tconst c = ( tubularSegments + 1 ) * ( j - 1 ) + i;\n\t\t\t\tconst d = ( tubularSegments + 1 ) * j + i;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc );\n\n\t}\n\n}\n\nclass TorusKnotGeometry extends BufferGeometry {\n\n\tconstructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'TorusKnotGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\ttube: tube,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tradialSegments: radialSegments,\n\t\t\tp: p,\n\t\t\tq: q\n\t\t};\n\n\t\ttubularSegments = Math.floor( tubularSegments );\n\t\tradialSegments = Math.floor( radialSegments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tconst vertex = new Vector3();\n\t\tconst normal = new Vector3();\n\n\t\tconst P1 = new Vector3();\n\t\tconst P2 = new Vector3();\n\n\t\tconst B = new Vector3();\n\t\tconst T = new Vector3();\n\t\tconst N = new Vector3();\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( let i = 0; i <= tubularSegments; ++ i ) {\n\n\t\t\t// the radian \"u\" is used to calculate the position on the torus curve of the current tubular segment\n\n\t\t\tconst u = i / tubularSegments * p * Math.PI * 2;\n\n\t\t\t// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.\n\t\t\t// these points are used to create a special \"coordinate space\", which is necessary to calculate the correct vertex positions\n\n\t\t\tcalculatePositionOnCurve( u, p, q, radius, P1 );\n\t\t\tcalculatePositionOnCurve( u + 0.01, p, q, radius, P2 );\n\n\t\t\t// calculate orthonormal basis\n\n\t\t\tT.subVectors( P2, P1 );\n\t\t\tN.addVectors( P2, P1 );\n\t\t\tB.crossVectors( T, N );\n\t\t\tN.crossVectors( B, T );\n\n\t\t\t// normalize B, N. T can be ignored, we don't use it\n\n\t\t\tB.normalize();\n\t\t\tN.normalize();\n\n\t\t\tfor ( let j = 0; j <= radialSegments; ++ j ) {\n\n\t\t\t\t// now calculate the vertices. they are nothing more than an extrusion of the torus curve.\n\t\t\t\t// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.\n\n\t\t\t\tconst v = j / radialSegments * Math.PI * 2;\n\t\t\t\tconst cx = - tube * Math.cos( v );\n\t\t\t\tconst cy = tube * Math.sin( v );\n\n\t\t\t\t// now calculate the final vertex position.\n\t\t\t\t// first we orient the extrusion with our basis vectors, then we add it to the current position on the curve\n\n\t\t\t\tvertex.x = P1.x + ( cx * N.x + cy * B.x );\n\t\t\t\tvertex.y = P1.y + ( cx * N.y + cy * B.y );\n\t\t\t\tvertex.z = P1.z + ( cx * N.z + cy * B.z );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)\n\n\t\t\t\tnormal.subVectors( vertex, P1 ).normalize();\n\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( i / tubularSegments );\n\t\t\t\tuvs.push( j / radialSegments );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate indices\n\n\t\tfor ( let j = 1; j <= tubularSegments; j ++ ) {\n\n\t\t\tfor ( let i = 1; i <= radialSegments; i ++ ) {\n\n\t\t\t\t// indices\n\n\t\t\t\tconst a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );\n\t\t\t\tconst b = ( radialSegments + 1 ) * j + ( i - 1 );\n\t\t\t\tconst c = ( radialSegments + 1 ) * j + i;\n\t\t\t\tconst d = ( radialSegments + 1 ) * ( j - 1 ) + i;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\t// this function calculates the current position on the torus curve\n\n\t\tfunction calculatePositionOnCurve( u, p, q, radius, position ) {\n\n\t\t\tconst cu = Math.cos( u );\n\t\t\tconst su = Math.sin( u );\n\t\t\tconst quOverP = q / p * u;\n\t\t\tconst cs = Math.cos( quOverP );\n\n\t\t\tposition.x = radius * ( 2 + cs ) * 0.5 * cu;\n\t\t\tposition.y = radius * ( 2 + cs ) * su * 0.5;\n\t\t\tposition.z = radius * Math.sin( quOverP ) * 0.5;\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q );\n\n\t}\n\n}\n\nclass TubeGeometry extends BufferGeometry {\n\n\tconstructor( 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 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'TubeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tpath: path,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tradius: radius,\n\t\t\tradialSegments: radialSegments,\n\t\t\tclosed: closed\n\t\t};\n\n\t\tconst frames = path.computeFrenetFrames( tubularSegments, closed );\n\n\t\t// expose internals\n\n\t\tthis.tangents = frames.tangents;\n\t\tthis.normals = frames.normals;\n\t\tthis.binormals = frames.binormals;\n\n\t\t// helper variables\n\n\t\tconst vertex = new Vector3();\n\t\tconst normal = new Vector3();\n\t\tconst uv = new Vector2();\n\t\tlet P = new Vector3();\n\n\t\t// buffer\n\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\t\tconst indices = [];\n\n\t\t// create buffer data\n\n\t\tgenerateBufferData();\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\t// functions\n\n\t\tfunction generateBufferData() {\n\n\t\t\tfor ( let i = 0; i < tubularSegments; i ++ ) {\n\n\t\t\t\tgenerateSegment( i );\n\n\t\t\t}\n\n\t\t\t// if the geometry is not closed, generate the last row of vertices and normals\n\t\t\t// at the regular position on the given path\n\t\t\t//\n\t\t\t// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)\n\n\t\t\tgenerateSegment( ( closed === false ) ? tubularSegments : 0 );\n\n\t\t\t// uvs are generated in a separate function.\n\t\t\t// this makes it easy compute correct values for closed geometries\n\n\t\t\tgenerateUVs();\n\n\t\t\t// finally create faces\n\n\t\t\tgenerateIndices();\n\n\t\t}\n\n\t\tfunction generateSegment( i ) {\n\n\t\t\t// we use getPointAt to sample evenly distributed points from the given path\n\n\t\t\tP = path.getPointAt( i / tubularSegments, P );\n\n\t\t\t// retrieve corresponding normal and binormal\n\n\t\t\tconst N = frames.normals[ i ];\n\t\t\tconst B = frames.binormals[ i ];\n\n\t\t\t// generate normals and vertices for the current segment\n\n\t\t\tfor ( let j = 0; j <= radialSegments; j ++ ) {\n\n\t\t\t\tconst v = j / radialSegments * Math.PI * 2;\n\n\t\t\t\tconst sin = Math.sin( v );\n\t\t\t\tconst cos = - Math.cos( v );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormal.x = ( cos * N.x + sin * B.x );\n\t\t\t\tnormal.y = ( cos * N.y + sin * B.y );\n\t\t\t\tnormal.z = ( cos * N.z + sin * B.z );\n\t\t\t\tnormal.normalize();\n\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = P.x + radius * normal.x;\n\t\t\t\tvertex.y = P.y + radius * normal.y;\n\t\t\t\tvertex.z = P.z + radius * normal.z;\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction generateIndices() {\n\n\t\t\tfor ( let j = 1; j <= tubularSegments; j ++ ) {\n\n\t\t\t\tfor ( let i = 1; i <= radialSegments; i ++ ) {\n\n\t\t\t\t\tconst a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );\n\t\t\t\t\tconst b = ( radialSegments + 1 ) * j + ( i - 1 );\n\t\t\t\t\tconst c = ( radialSegments + 1 ) * j + i;\n\t\t\t\t\tconst d = ( radialSegments + 1 ) * ( j - 1 ) + i;\n\n\t\t\t\t\t// faces\n\n\t\t\t\t\tindices.push( a, b, d );\n\t\t\t\t\tindices.push( b, c, d );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction generateUVs() {\n\n\t\t\tfor ( let i = 0; i <= tubularSegments; i ++ ) {\n\n\t\t\t\tfor ( let j = 0; j <= radialSegments; j ++ ) {\n\n\t\t\t\t\tuv.x = i / tubularSegments;\n\t\t\t\t\tuv.y = j / radialSegments;\n\n\t\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.path = this.parameters.path.toJSON();\n\n\t\treturn data;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\t// This only works for built-in curves (e.g. CatmullRomCurve3).\n\t\t// User defined curves or instances of CurvePath will not be deserialized.\n\t\treturn new TubeGeometry(\n\t\t\tnew Curves[ data.path.type ]().fromJSON( data.path ),\n\t\t\tdata.tubularSegments,\n\t\t\tdata.radius,\n\t\t\tdata.radialSegments,\n\t\t\tdata.closed\n\t\t);\n\n\t}\n\n}\n\nclass WireframeGeometry extends BufferGeometry {\n\n\tconstructor( geometry = null ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'WireframeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tgeometry: geometry\n\t\t};\n\n\t\tif ( geometry !== null ) {\n\n\t\t\t// buffer\n\n\t\t\tconst vertices = [];\n\t\t\tconst edges = new Set();\n\n\t\t\t// helper variables\n\n\t\t\tconst start = new Vector3();\n\t\t\tconst end = new Vector3();\n\n\t\t\tif ( geometry.index !== null ) {\n\n\t\t\t\t// indexed BufferGeometry\n\n\t\t\t\tconst position = geometry.attributes.position;\n\t\t\t\tconst indices = geometry.index;\n\t\t\t\tlet groups = geometry.groups;\n\n\t\t\t\tif ( groups.length === 0 ) {\n\n\t\t\t\t\tgroups = [ { start: 0, count: indices.count, materialIndex: 0 } ];\n\n\t\t\t\t}\n\n\t\t\t\t// create a data structure that contains all edges without duplicates\n\n\t\t\t\tfor ( let o = 0, ol = groups.length; o < ol; ++ o ) {\n\n\t\t\t\t\tconst group = groups[ o ];\n\n\t\t\t\t\tconst groupStart = group.start;\n\t\t\t\t\tconst groupCount = group.count;\n\n\t\t\t\t\tfor ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) {\n\n\t\t\t\t\t\tfor ( let j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t\t\tconst index1 = indices.getX( i + j );\n\t\t\t\t\t\t\tconst index2 = indices.getX( i + ( j + 1 ) % 3 );\n\n\t\t\t\t\t\t\tstart.fromBufferAttribute( position, index1 );\n\t\t\t\t\t\t\tend.fromBufferAttribute( position, index2 );\n\n\t\t\t\t\t\t\tif ( isUniqueEdge( start, end, edges ) === true ) {\n\n\t\t\t\t\t\t\t\tvertices.push( start.x, start.y, start.z );\n\t\t\t\t\t\t\t\tvertices.push( end.x, end.y, end.z );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// non-indexed BufferGeometry\n\n\t\t\t\tconst position = geometry.attributes.position;\n\n\t\t\t\tfor ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) {\n\n\t\t\t\t\tfor ( let j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t\t// three edges per triangle, an edge is represented as (index1, index2)\n\t\t\t\t\t\t// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)\n\n\t\t\t\t\t\tconst index1 = 3 * i + j;\n\t\t\t\t\t\tconst index2 = 3 * i + ( ( j + 1 ) % 3 );\n\n\t\t\t\t\t\tstart.fromBufferAttribute( position, index1 );\n\t\t\t\t\t\tend.fromBufferAttribute( position, index2 );\n\n\t\t\t\t\t\tif ( isUniqueEdge( start, end, edges ) === true ) {\n\n\t\t\t\t\t\t\tvertices.push( start.x, start.y, start.z );\n\t\t\t\t\t\t\tvertices.push( end.x, end.y, end.z );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// build geometry\n\n\t\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n}\n\nfunction isUniqueEdge( start, end, edges ) {\n\n\tconst hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`;\n\tconst hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge\n\n\tif ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) {\n\n\t\treturn false;\n\n\t} else {\n\n\t\tedges.add( hash1 );\n\t\tedges.add( hash2 );\n\t\treturn true;\n\n\t}\n\n}\n\nvar Geometries = /*#__PURE__*/Object.freeze({\n\t__proto__: null,\n\tBoxGeometry: BoxGeometry,\n\tCapsuleGeometry: CapsuleGeometry,\n\tCircleGeometry: CircleGeometry,\n\tConeGeometry: ConeGeometry,\n\tCylinderGeometry: CylinderGeometry,\n\tDodecahedronGeometry: DodecahedronGeometry,\n\tEdgesGeometry: EdgesGeometry,\n\tExtrudeGeometry: ExtrudeGeometry,\n\tIcosahedronGeometry: IcosahedronGeometry,\n\tLatheGeometry: LatheGeometry,\n\tOctahedronGeometry: OctahedronGeometry,\n\tPlaneGeometry: PlaneGeometry,\n\tPolyhedronGeometry: PolyhedronGeometry,\n\tRingGeometry: RingGeometry,\n\tShapeGeometry: ShapeGeometry,\n\tSphereGeometry: SphereGeometry,\n\tTetrahedronGeometry: TetrahedronGeometry,\n\tTorusGeometry: TorusGeometry,\n\tTorusKnotGeometry: TorusKnotGeometry,\n\tTubeGeometry: TubeGeometry,\n\tWireframeGeometry: WireframeGeometry\n});\n\nclass ShadowMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isShadowMaterial = true;\n\n\t\tthis.type = 'ShadowMaterial';\n\n\t\tthis.color = new Color( 0x000000 );\n\t\tthis.transparent = true;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass RawShaderMaterial extends ShaderMaterial {\n\n\tconstructor( parameters ) {\n\n\t\tsuper( parameters );\n\n\t\tthis.isRawShaderMaterial = true;\n\n\t\tthis.type = 'RawShaderMaterial';\n\n\t}\n\n}\n\nclass MeshStandardMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshStandardMaterial = true;\n\n\t\tthis.defines = { 'STANDARD': '' };\n\n\t\tthis.type = 'MeshStandardMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // diffuse\n\t\tthis.roughness = 1.0;\n\t\tthis.metalness = 0.0;\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.emissive = new Color( 0x000000 );\n\t\tthis.emissiveIntensity = 1.0;\n\t\tthis.emissiveMap = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.roughnessMap = null;\n\n\t\tthis.metalnessMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.envMapRotation = new Euler();\n\t\tthis.envMapIntensity = 1.0;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.flatShading = false;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.defines = { 'STANDARD': '' };\n\n\t\tthis.color.copy( source.color );\n\t\tthis.roughness = source.roughness;\n\t\tthis.metalness = source.metalness;\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.emissive.copy( source.emissive );\n\t\tthis.emissiveMap = source.emissiveMap;\n\t\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.roughnessMap = source.roughnessMap;\n\n\t\tthis.metalnessMap = source.metalnessMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.envMapRotation.copy( source.envMapRotation );\n\t\tthis.envMapIntensity = source.envMapIntensity;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.flatShading = source.flatShading;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshPhysicalMaterial extends MeshStandardMaterial {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshPhysicalMaterial = true;\n\n\t\tthis.defines = {\n\n\t\t\t'STANDARD': '',\n\t\t\t'PHYSICAL': ''\n\n\t\t};\n\n\t\tthis.type = 'MeshPhysicalMaterial';\n\n\t\tthis.anisotropyRotation = 0;\n\t\tthis.anisotropyMap = null;\n\n\t\tthis.clearcoatMap = null;\n\t\tthis.clearcoatRoughness = 0.0;\n\t\tthis.clearcoatRoughnessMap = null;\n\t\tthis.clearcoatNormalScale = new Vector2( 1, 1 );\n\t\tthis.clearcoatNormalMap = null;\n\n\t\tthis.ior = 1.5;\n\n\t\tObject.defineProperty( this, 'reflectivity', {\n\t\t\tget: function () {\n\n\t\t\t\treturn ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) );\n\n\t\t\t},\n\t\t\tset: function ( reflectivity ) {\n\n\t\t\t\tthis.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity );\n\n\t\t\t}\n\t\t} );\n\n\t\tthis.iridescenceMap = null;\n\t\tthis.iridescenceIOR = 1.3;\n\t\tthis.iridescenceThicknessRange = [ 100, 400 ];\n\t\tthis.iridescenceThicknessMap = null;\n\n\t\tthis.sheenColor = new Color( 0x000000 );\n\t\tthis.sheenColorMap = null;\n\t\tthis.sheenRoughness = 1.0;\n\t\tthis.sheenRoughnessMap = null;\n\n\t\tthis.transmissionMap = null;\n\n\t\tthis.thickness = 0;\n\t\tthis.thicknessMap = null;\n\t\tthis.attenuationDistance = Infinity;\n\t\tthis.attenuationColor = new Color( 1, 1, 1 );\n\n\t\tthis.specularIntensity = 1.0;\n\t\tthis.specularIntensityMap = null;\n\t\tthis.specularColor = new Color( 1, 1, 1 );\n\t\tthis.specularColorMap = null;\n\n\t\tthis._anisotropy = 0;\n\t\tthis._clearcoat = 0;\n\t\tthis._dispersion = 0;\n\t\tthis._iridescence = 0;\n\t\tthis._sheen = 0.0;\n\t\tthis._transmission = 0;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tget anisotropy() {\n\n\t\treturn this._anisotropy;\n\n\t}\n\n\tset anisotropy( value ) {\n\n\t\tif ( this._anisotropy > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._anisotropy = value;\n\n\t}\n\n\tget clearcoat() {\n\n\t\treturn this._clearcoat;\n\n\t}\n\n\tset clearcoat( value ) {\n\n\t\tif ( this._clearcoat > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._clearcoat = value;\n\n\t}\n\n\tget iridescence() {\n\n\t\treturn this._iridescence;\n\n\t}\n\n\tset iridescence( value ) {\n\n\t\tif ( this._iridescence > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._iridescence = value;\n\n\t}\n\n\tget dispersion() {\n\n\t\treturn this._dispersion;\n\n\t}\n\n\tset dispersion( value ) {\n\n\t\tif ( this._dispersion > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._dispersion = value;\n\n\t}\n\n\tget sheen() {\n\n\t\treturn this._sheen;\n\n\t}\n\n\tset sheen( value ) {\n\n\t\tif ( this._sheen > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._sheen = value;\n\n\t}\n\n\tget transmission() {\n\n\t\treturn this._transmission;\n\n\t}\n\n\tset transmission( value ) {\n\n\t\tif ( this._transmission > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._transmission = value;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.defines = {\n\n\t\t\t'STANDARD': '',\n\t\t\t'PHYSICAL': ''\n\n\t\t};\n\n\t\tthis.anisotropy = source.anisotropy;\n\t\tthis.anisotropyRotation = source.anisotropyRotation;\n\t\tthis.anisotropyMap = source.anisotropyMap;\n\n\t\tthis.clearcoat = source.clearcoat;\n\t\tthis.clearcoatMap = source.clearcoatMap;\n\t\tthis.clearcoatRoughness = source.clearcoatRoughness;\n\t\tthis.clearcoatRoughnessMap = source.clearcoatRoughnessMap;\n\t\tthis.clearcoatNormalMap = source.clearcoatNormalMap;\n\t\tthis.clearcoatNormalScale.copy( source.clearcoatNormalScale );\n\n\t\tthis.dispersion = source.dispersion;\n\t\tthis.ior = source.ior;\n\n\t\tthis.iridescence = source.iridescence;\n\t\tthis.iridescenceMap = source.iridescenceMap;\n\t\tthis.iridescenceIOR = source.iridescenceIOR;\n\t\tthis.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ];\n\t\tthis.iridescenceThicknessMap = source.iridescenceThicknessMap;\n\n\t\tthis.sheen = source.sheen;\n\t\tthis.sheenColor.copy( source.sheenColor );\n\t\tthis.sheenColorMap = source.sheenColorMap;\n\t\tthis.sheenRoughness = source.sheenRoughness;\n\t\tthis.sheenRoughnessMap = source.sheenRoughnessMap;\n\n\t\tthis.transmission = source.transmission;\n\t\tthis.transmissionMap = source.transmissionMap;\n\n\t\tthis.thickness = source.thickness;\n\t\tthis.thicknessMap = source.thicknessMap;\n\t\tthis.attenuationDistance = source.attenuationDistance;\n\t\tthis.attenuationColor.copy( source.attenuationColor );\n\n\t\tthis.specularIntensity = source.specularIntensity;\n\t\tthis.specularIntensityMap = source.specularIntensityMap;\n\t\tthis.specularColor.copy( source.specularColor );\n\t\tthis.specularColorMap = source.specularColorMap;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshPhongMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshPhongMaterial = true;\n\n\t\tthis.type = 'MeshPhongMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // diffuse\n\t\tthis.specular = new Color( 0x111111 );\n\t\tthis.shininess = 30;\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.emissive = new Color( 0x000000 );\n\t\tthis.emissiveIntensity = 1.0;\n\t\tthis.emissiveMap = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.specularMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.envMapRotation = new Euler();\n\t\tthis.combine = MultiplyOperation;\n\t\tthis.reflectivity = 1;\n\t\tthis.refractionRatio = 0.98;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.flatShading = false;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\t\tthis.specular.copy( source.specular );\n\t\tthis.shininess = source.shininess;\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.emissive.copy( source.emissive );\n\t\tthis.emissiveMap = source.emissiveMap;\n\t\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.specularMap = source.specularMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.envMapRotation.copy( source.envMapRotation );\n\t\tthis.combine = source.combine;\n\t\tthis.reflectivity = source.reflectivity;\n\t\tthis.refractionRatio = source.refractionRatio;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.flatShading = source.flatShading;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshToonMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshToonMaterial = true;\n\n\t\tthis.defines = { 'TOON': '' };\n\n\t\tthis.type = 'MeshToonMaterial';\n\n\t\tthis.color = new Color( 0xffffff );\n\n\t\tthis.map = null;\n\t\tthis.gradientMap = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.emissive = new Color( 0x000000 );\n\t\tthis.emissiveIntensity = 1.0;\n\t\tthis.emissiveMap = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\t\tthis.gradientMap = source.gradientMap;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.emissive.copy( source.emissive );\n\t\tthis.emissiveMap = source.emissiveMap;\n\t\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshNormalMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshNormalMaterial = true;\n\n\t\tthis.type = 'MeshNormalMaterial';\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\n\t\tthis.flatShading = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\t\tthis.flatShading = source.flatShading;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshLambertMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshLambertMaterial = true;\n\n\t\tthis.type = 'MeshLambertMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // diffuse\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.emissive = new Color( 0x000000 );\n\t\tthis.emissiveIntensity = 1.0;\n\t\tthis.emissiveMap = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.specularMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.envMapRotation = new Euler();\n\t\tthis.combine = MultiplyOperation;\n\t\tthis.reflectivity = 1;\n\t\tthis.refractionRatio = 0.98;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.flatShading = false;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.emissive.copy( source.emissive );\n\t\tthis.emissiveMap = source.emissiveMap;\n\t\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.specularMap = source.specularMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.envMapRotation.copy( source.envMapRotation );\n\t\tthis.combine = source.combine;\n\t\tthis.reflectivity = source.reflectivity;\n\t\tthis.refractionRatio = source.refractionRatio;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.flatShading = source.flatShading;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshMatcapMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshMatcapMaterial = true;\n\n\t\tthis.defines = { 'MATCAP': '' };\n\n\t\tthis.type = 'MeshMatcapMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // diffuse\n\n\t\tthis.matcap = null;\n\n\t\tthis.map = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.flatShading = false;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.defines = { 'MATCAP': '' };\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.matcap = source.matcap;\n\n\t\tthis.map = source.map;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.flatShading = source.flatShading;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass LineDashedMaterial extends LineBasicMaterial {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isLineDashedMaterial = true;\n\n\t\tthis.type = 'LineDashedMaterial';\n\n\t\tthis.scale = 1;\n\t\tthis.dashSize = 3;\n\t\tthis.gapSize = 1;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.scale = source.scale;\n\t\tthis.dashSize = source.dashSize;\n\t\tthis.gapSize = source.gapSize;\n\n\t\treturn this;\n\n\t}\n\n}\n\n// converts an array to a specific type\nfunction convertArray( array, type, forceClone ) {\n\n\tif ( ! array || // let 'undefined' and 'null' pass\n\t\t! forceClone && array.constructor === type ) return array;\n\n\tif ( typeof type.BYTES_PER_ELEMENT === 'number' ) {\n\n\t\treturn new type( array ); // create typed array\n\n\t}\n\n\treturn Array.prototype.slice.call( array ); // create Array\n\n}\n\nfunction isTypedArray( object ) {\n\n\treturn ArrayBuffer.isView( object ) &&\n\t\t! ( object instanceof DataView );\n\n}\n\n// returns an array by which times and values can be sorted\nfunction getKeyframeOrder( times ) {\n\n\tfunction compareTime( i, j ) {\n\n\t\treturn times[ i ] - times[ j ];\n\n\t}\n\n\tconst n = times.length;\n\tconst result = new Array( n );\n\tfor ( let i = 0; i !== n; ++ i ) result[ i ] = i;\n\n\tresult.sort( compareTime );\n\n\treturn result;\n\n}\n\n// uses the array previously returned by 'getKeyframeOrder' to sort data\nfunction sortedArray( values, stride, order ) {\n\n\tconst nValues = values.length;\n\tconst result = new values.constructor( nValues );\n\n\tfor ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {\n\n\t\tconst srcOffset = order[ i ] * stride;\n\n\t\tfor ( let j = 0; j !== stride; ++ j ) {\n\n\t\t\tresult[ dstOffset ++ ] = values[ srcOffset + j ];\n\n\t\t}\n\n\t}\n\n\treturn result;\n\n}\n\n// function for parsing AOS keyframe formats\nfunction flattenJSON( jsonKeys, times, values, valuePropertyName ) {\n\n\tlet i = 1, key = jsonKeys[ 0 ];\n\n\twhile ( key !== undefined && key[ valuePropertyName ] === undefined ) {\n\n\t\tkey = jsonKeys[ i ++ ];\n\n\t}\n\n\tif ( key === undefined ) return; // no data\n\n\tlet value = key[ valuePropertyName ];\n\tif ( value === undefined ) return; // no data\n\n\tif ( Array.isArray( value ) ) {\n\n\t\tdo {\n\n\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\tif ( value !== undefined ) {\n\n\t\t\t\ttimes.push( key.time );\n\t\t\t\tvalues.push.apply( values, value ); // push all elements\n\n\t\t\t}\n\n\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t} while ( key !== undefined );\n\n\t} else if ( value.toArray !== undefined ) {\n\n\t\t// ...assume THREE.Math-ish\n\n\t\tdo {\n\n\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\tif ( value !== undefined ) {\n\n\t\t\t\ttimes.push( key.time );\n\t\t\t\tvalue.toArray( values, values.length );\n\n\t\t\t}\n\n\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t} while ( key !== undefined );\n\n\t} else {\n\n\t\t// otherwise push as-is\n\n\t\tdo {\n\n\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\tif ( value !== undefined ) {\n\n\t\t\t\ttimes.push( key.time );\n\t\t\t\tvalues.push( value );\n\n\t\t\t}\n\n\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t} while ( key !== undefined );\n\n\t}\n\n}\n\nfunction subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) {\n\n\tconst clip = sourceClip.clone();\n\n\tclip.name = name;\n\n\tconst tracks = [];\n\n\tfor ( let i = 0; i < clip.tracks.length; ++ i ) {\n\n\t\tconst track = clip.tracks[ i ];\n\t\tconst valueSize = track.getValueSize();\n\n\t\tconst times = [];\n\t\tconst values = [];\n\n\t\tfor ( let j = 0; j < track.times.length; ++ j ) {\n\n\t\t\tconst frame = track.times[ j ] * fps;\n\n\t\t\tif ( frame < startFrame || frame >= endFrame ) continue;\n\n\t\t\ttimes.push( track.times[ j ] );\n\n\t\t\tfor ( let k = 0; k < valueSize; ++ k ) {\n\n\t\t\t\tvalues.push( track.values[ j * valueSize + k ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( times.length === 0 ) continue;\n\n\t\ttrack.times = convertArray( times, track.times.constructor );\n\t\ttrack.values = convertArray( values, track.values.constructor );\n\n\t\ttracks.push( track );\n\n\t}\n\n\tclip.tracks = tracks;\n\n\t// find minimum .times value across all tracks in the trimmed clip\n\n\tlet minStartTime = Infinity;\n\n\tfor ( let i = 0; i < clip.tracks.length; ++ i ) {\n\n\t\tif ( minStartTime > clip.tracks[ i ].times[ 0 ] ) {\n\n\t\t\tminStartTime = clip.tracks[ i ].times[ 0 ];\n\n\t\t}\n\n\t}\n\n\t// shift all tracks such that clip begins at t=0\n\n\tfor ( let i = 0; i < clip.tracks.length; ++ i ) {\n\n\t\tclip.tracks[ i ].shift( - 1 * minStartTime );\n\n\t}\n\n\tclip.resetDuration();\n\n\treturn clip;\n\n}\n\nfunction makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) {\n\n\tif ( fps <= 0 ) fps = 30;\n\n\tconst numTracks = referenceClip.tracks.length;\n\tconst referenceTime = referenceFrame / fps;\n\n\t// Make each track's values relative to the values at the reference frame\n\tfor ( let i = 0; i < numTracks; ++ i ) {\n\n\t\tconst referenceTrack = referenceClip.tracks[ i ];\n\t\tconst referenceTrackType = referenceTrack.ValueTypeName;\n\n\t\t// Skip this track if it's non-numeric\n\t\tif ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue;\n\n\t\t// Find the track in the target clip whose name and type matches the reference track\n\t\tconst targetTrack = targetClip.tracks.find( function ( track ) {\n\n\t\t\treturn track.name === referenceTrack.name\n\t\t\t\t&& track.ValueTypeName === referenceTrackType;\n\n\t\t} );\n\n\t\tif ( targetTrack === undefined ) continue;\n\n\t\tlet referenceOffset = 0;\n\t\tconst referenceValueSize = referenceTrack.getValueSize();\n\n\t\tif ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {\n\n\t\t\treferenceOffset = referenceValueSize / 3;\n\n\t\t}\n\n\t\tlet targetOffset = 0;\n\t\tconst targetValueSize = targetTrack.getValueSize();\n\n\t\tif ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {\n\n\t\t\ttargetOffset = targetValueSize / 3;\n\n\t\t}\n\n\t\tconst lastIndex = referenceTrack.times.length - 1;\n\t\tlet referenceValue;\n\n\t\t// Find the value to subtract out of the track\n\t\tif ( referenceTime <= referenceTrack.times[ 0 ] ) {\n\n\t\t\t// Reference frame is earlier than the first keyframe, so just use the first keyframe\n\t\t\tconst startIndex = referenceOffset;\n\t\t\tconst endIndex = referenceValueSize - referenceOffset;\n\t\t\treferenceValue = referenceTrack.values.slice( startIndex, endIndex );\n\n\t\t} else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) {\n\n\t\t\t// Reference frame is after the last keyframe, so just use the last keyframe\n\t\t\tconst startIndex = lastIndex * referenceValueSize + referenceOffset;\n\t\t\tconst endIndex = startIndex + referenceValueSize - referenceOffset;\n\t\t\treferenceValue = referenceTrack.values.slice( startIndex, endIndex );\n\n\t\t} else {\n\n\t\t\t// Interpolate to the reference value\n\t\t\tconst interpolant = referenceTrack.createInterpolant();\n\t\t\tconst startIndex = referenceOffset;\n\t\t\tconst endIndex = referenceValueSize - referenceOffset;\n\t\t\tinterpolant.evaluate( referenceTime );\n\t\t\treferenceValue = interpolant.resultBuffer.slice( startIndex, endIndex );\n\n\t\t}\n\n\t\t// Conjugate the quaternion\n\t\tif ( referenceTrackType === 'quaternion' ) {\n\n\t\t\tconst referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate();\n\t\t\treferenceQuat.toArray( referenceValue );\n\n\t\t}\n\n\t\t// Subtract the reference value from all of the track values\n\n\t\tconst numTimes = targetTrack.times.length;\n\t\tfor ( let j = 0; j < numTimes; ++ j ) {\n\n\t\t\tconst valueStart = j * targetValueSize + targetOffset;\n\n\t\t\tif ( referenceTrackType === 'quaternion' ) {\n\n\t\t\t\t// Multiply the conjugate for quaternion track types\n\t\t\t\tQuaternion.multiplyQuaternionsFlat(\n\t\t\t\t\ttargetTrack.values,\n\t\t\t\t\tvalueStart,\n\t\t\t\t\treferenceValue,\n\t\t\t\t\t0,\n\t\t\t\t\ttargetTrack.values,\n\t\t\t\t\tvalueStart\n\t\t\t\t);\n\n\t\t\t} else {\n\n\t\t\t\tconst valueEnd = targetValueSize - targetOffset * 2;\n\n\t\t\t\t// Subtract each value for all other numeric track types\n\t\t\t\tfor ( let k = 0; k < valueEnd; ++ k ) {\n\n\t\t\t\t\ttargetTrack.values[ valueStart + k ] -= referenceValue[ k ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\ttargetClip.blendMode = AdditiveAnimationBlendMode;\n\n\treturn targetClip;\n\n}\n\nconst AnimationUtils = {\n\tconvertArray: convertArray,\n\tisTypedArray: isTypedArray,\n\tgetKeyframeOrder: getKeyframeOrder,\n\tsortedArray: sortedArray,\n\tflattenJSON: flattenJSON,\n\tsubclip: subclip,\n\tmakeClipAdditive: makeClipAdditive\n};\n\n/**\n * Abstract base class of interpolants over parametric samples.\n *\n * The parameter domain is one dimensional, typically the time or a path\n * along a curve defined by the data.\n *\n * The sample values can have any dimensionality and derived classes may\n * apply special interpretations to the data.\n *\n * This class provides the interval seek in a Template Method, deferring\n * the actual interpolation to derived classes.\n *\n * Time complexity is O(1) for linear access crossing at most two points\n * and O(log N) for random access, where N is the number of positions.\n *\n * References:\n *\n * \t\thttp://www.oodesign.com/template-method-pattern.html\n *\n */\n\nclass Interpolant {\n\n\tconstructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tthis.parameterPositions = parameterPositions;\n\t\tthis._cachedIndex = 0;\n\n\t\tthis.resultBuffer = resultBuffer !== undefined ?\n\t\t\tresultBuffer : new sampleValues.constructor( sampleSize );\n\t\tthis.sampleValues = sampleValues;\n\t\tthis.valueSize = sampleSize;\n\n\t\tthis.settings = null;\n\t\tthis.DefaultSettings_ = {};\n\n\t}\n\n\tevaluate( t ) {\n\n\t\tconst pp = this.parameterPositions;\n\t\tlet i1 = this._cachedIndex,\n\t\t\tt1 = pp[ i1 ],\n\t\t\tt0 = pp[ i1 - 1 ];\n\n\t\tvalidate_interval: {\n\n\t\t\tseek: {\n\n\t\t\t\tlet right;\n\n\t\t\t\tlinear_scan: {\n\n\t\t\t\t\t//- See http://jsperf.com/comparison-to-undefined/3\n\t\t\t\t\t//- slower code:\n\t\t\t\t\t//-\n\t\t\t\t\t//- \t\t\t\tif ( t >= t1 || t1 === undefined ) {\n\t\t\t\t\tforward_scan: if ( ! ( t < t1 ) ) {\n\n\t\t\t\t\t\tfor ( let giveUpAt = i1 + 2; ; ) {\n\n\t\t\t\t\t\t\tif ( t1 === undefined ) {\n\n\t\t\t\t\t\t\t\tif ( t < t0 ) break forward_scan;\n\n\t\t\t\t\t\t\t\t// after end\n\n\t\t\t\t\t\t\t\ti1 = pp.length;\n\t\t\t\t\t\t\t\tthis._cachedIndex = i1;\n\t\t\t\t\t\t\t\treturn this.copySampleValue_( i1 - 1 );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( i1 === giveUpAt ) break; // this loop\n\n\t\t\t\t\t\t\tt0 = t1;\n\t\t\t\t\t\t\tt1 = pp[ ++ i1 ];\n\n\t\t\t\t\t\t\tif ( t < t1 ) {\n\n\t\t\t\t\t\t\t\t// we have arrived at the sought interval\n\t\t\t\t\t\t\t\tbreak seek;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// prepare binary search on the right side of the index\n\t\t\t\t\t\tright = pp.length;\n\t\t\t\t\t\tbreak linear_scan;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t//- slower code:\n\t\t\t\t\t//-\t\t\t\t\tif ( t < t0 || t0 === undefined ) {\n\t\t\t\t\tif ( ! ( t >= t0 ) ) {\n\n\t\t\t\t\t\t// looping?\n\n\t\t\t\t\t\tconst t1global = pp[ 1 ];\n\n\t\t\t\t\t\tif ( t < t1global ) {\n\n\t\t\t\t\t\t\ti1 = 2; // + 1, using the scan for the details\n\t\t\t\t\t\t\tt0 = t1global;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// linear reverse scan\n\n\t\t\t\t\t\tfor ( let giveUpAt = i1 - 2; ; ) {\n\n\t\t\t\t\t\t\tif ( t0 === undefined ) {\n\n\t\t\t\t\t\t\t\t// before start\n\n\t\t\t\t\t\t\t\tthis._cachedIndex = 0;\n\t\t\t\t\t\t\t\treturn this.copySampleValue_( 0 );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( i1 === giveUpAt ) break; // this loop\n\n\t\t\t\t\t\t\tt1 = t0;\n\t\t\t\t\t\t\tt0 = pp[ -- i1 - 1 ];\n\n\t\t\t\t\t\t\tif ( t >= t0 ) {\n\n\t\t\t\t\t\t\t\t// we have arrived at the sought interval\n\t\t\t\t\t\t\t\tbreak seek;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// prepare binary search on the left side of the index\n\t\t\t\t\t\tright = i1;\n\t\t\t\t\t\ti1 = 0;\n\t\t\t\t\t\tbreak linear_scan;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// the interval is valid\n\n\t\t\t\t\tbreak validate_interval;\n\n\t\t\t\t} // linear scan\n\n\t\t\t\t// binary search\n\n\t\t\t\twhile ( i1 < right ) {\n\n\t\t\t\t\tconst mid = ( i1 + right ) >>> 1;\n\n\t\t\t\t\tif ( t < pp[ mid ] ) {\n\n\t\t\t\t\t\tright = mid;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ti1 = mid + 1;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tt1 = pp[ i1 ];\n\t\t\t\tt0 = pp[ i1 - 1 ];\n\n\t\t\t\t// check boundary cases, again\n\n\t\t\t\tif ( t0 === undefined ) {\n\n\t\t\t\t\tthis._cachedIndex = 0;\n\t\t\t\t\treturn this.copySampleValue_( 0 );\n\n\t\t\t\t}\n\n\t\t\t\tif ( t1 === undefined ) {\n\n\t\t\t\t\ti1 = pp.length;\n\t\t\t\t\tthis._cachedIndex = i1;\n\t\t\t\t\treturn this.copySampleValue_( i1 - 1 );\n\n\t\t\t\t}\n\n\t\t\t} // seek\n\n\t\t\tthis._cachedIndex = i1;\n\n\t\t\tthis.intervalChanged_( i1, t0, t1 );\n\n\t\t} // validate_interval\n\n\t\treturn this.interpolate_( i1, t0, t, t1 );\n\n\t}\n\n\tgetSettings_() {\n\n\t\treturn this.settings || this.DefaultSettings_;\n\n\t}\n\n\tcopySampleValue_( index ) {\n\n\t\t// copies a sample value to the result buffer\n\n\t\tconst result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\t\t\toffset = index * stride;\n\n\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\tresult[ i ] = values[ offset + i ];\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\t// Template methods for derived classes:\n\n\tinterpolate_( /* i1, t0, t, t1 */ ) {\n\n\t\tthrow new Error( 'call to abstract method' );\n\t\t// implementations shall return this.resultBuffer\n\n\t}\n\n\tintervalChanged_( /* i1, t0, t1 */ ) {\n\n\t\t// empty\n\n\t}\n\n}\n\n/**\n * Fast and simple cubic spline interpolant.\n *\n * It was derived from a Hermitian construction setting the first derivative\n * at each sample position to the linear slope between neighboring positions\n * over their parameter interval.\n */\n\nclass CubicInterpolant extends Interpolant {\n\n\tconstructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tsuper( parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t\tthis._weightPrev = - 0;\n\t\tthis._offsetPrev = - 0;\n\t\tthis._weightNext = - 0;\n\t\tthis._offsetNext = - 0;\n\n\t\tthis.DefaultSettings_ = {\n\n\t\t\tendingStart: ZeroCurvatureEnding,\n\t\t\tendingEnd: ZeroCurvatureEnding\n\n\t\t};\n\n\t}\n\n\tintervalChanged_( i1, t0, t1 ) {\n\n\t\tconst pp = this.parameterPositions;\n\t\tlet iPrev = i1 - 2,\n\t\t\tiNext = i1 + 1,\n\n\t\t\ttPrev = pp[ iPrev ],\n\t\t\ttNext = pp[ iNext ];\n\n\t\tif ( tPrev === undefined ) {\n\n\t\t\tswitch ( this.getSettings_().endingStart ) {\n\n\t\t\t\tcase ZeroSlopeEnding:\n\n\t\t\t\t\t// f'(t0) = 0\n\t\t\t\t\tiPrev = i1;\n\t\t\t\t\ttPrev = 2 * t0 - t1;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase WrapAroundEnding:\n\n\t\t\t\t\t// use the other end of the curve\n\t\t\t\t\tiPrev = pp.length - 2;\n\t\t\t\t\ttPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault: // ZeroCurvatureEnding\n\n\t\t\t\t\t// f''(t0) = 0 a.k.a. Natural Spline\n\t\t\t\t\tiPrev = i1;\n\t\t\t\t\ttPrev = t1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( tNext === undefined ) {\n\n\t\t\tswitch ( this.getSettings_().endingEnd ) {\n\n\t\t\t\tcase ZeroSlopeEnding:\n\n\t\t\t\t\t// f'(tN) = 0\n\t\t\t\t\tiNext = i1;\n\t\t\t\t\ttNext = 2 * t1 - t0;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase WrapAroundEnding:\n\n\t\t\t\t\t// use the other end of the curve\n\t\t\t\t\tiNext = 1;\n\t\t\t\t\ttNext = t1 + pp[ 1 ] - pp[ 0 ];\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault: // ZeroCurvatureEnding\n\n\t\t\t\t\t// f''(tN) = 0, a.k.a. Natural Spline\n\t\t\t\t\tiNext = i1 - 1;\n\t\t\t\t\ttNext = t0;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst halfDt = ( t1 - t0 ) * 0.5,\n\t\t\tstride = this.valueSize;\n\n\t\tthis._weightPrev = halfDt / ( t0 - tPrev );\n\t\tthis._weightNext = halfDt / ( tNext - t1 );\n\t\tthis._offsetPrev = iPrev * stride;\n\t\tthis._offsetNext = iNext * stride;\n\n\t}\n\n\tinterpolate_( i1, t0, t, t1 ) {\n\n\t\tconst result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\n\t\t\to1 = i1 * stride,\t\to0 = o1 - stride,\n\t\t\toP = this._offsetPrev, \toN = this._offsetNext,\n\t\t\twP = this._weightPrev,\twN = this._weightNext,\n\n\t\t\tp = ( t - t0 ) / ( t1 - t0 ),\n\t\t\tpp = p * p,\n\t\t\tppp = pp * p;\n\n\t\t// evaluate polynomials\n\n\t\tconst sP = - wP * ppp + 2 * wP * pp - wP * p;\n\t\tconst s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;\n\t\tconst s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;\n\t\tconst sN = wN * ppp - wN * pp;\n\n\t\t// combine data linearly\n\n\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\tresult[ i ] =\n\t\t\t\t\tsP * values[ oP + i ] +\n\t\t\t\t\ts0 * values[ o0 + i ] +\n\t\t\t\t\ts1 * values[ o1 + i ] +\n\t\t\t\t\tsN * values[ oN + i ];\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n}\n\nclass LinearInterpolant extends Interpolant {\n\n\tconstructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tsuper( parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t}\n\n\tinterpolate_( i1, t0, t, t1 ) {\n\n\t\tconst result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\n\t\t\toffset1 = i1 * stride,\n\t\t\toffset0 = offset1 - stride,\n\n\t\t\tweight1 = ( t - t0 ) / ( t1 - t0 ),\n\t\t\tweight0 = 1 - weight1;\n\n\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\tresult[ i ] =\n\t\t\t\t\tvalues[ offset0 + i ] * weight0 +\n\t\t\t\t\tvalues[ offset1 + i ] * weight1;\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n}\n\n/**\n *\n * Interpolant that evaluates to the sample value at the position preceding\n * the parameter.\n */\n\nclass DiscreteInterpolant extends Interpolant {\n\n\tconstructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tsuper( parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t}\n\n\tinterpolate_( i1 /*, t0, t, t1 */ ) {\n\n\t\treturn this.copySampleValue_( i1 - 1 );\n\n\t}\n\n}\n\nclass KeyframeTrack {\n\n\tconstructor( name, times, values, interpolation ) {\n\n\t\tif ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' );\n\t\tif ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name );\n\n\t\tthis.name = name;\n\n\t\tthis.times = convertArray( times, this.TimeBufferType );\n\t\tthis.values = convertArray( values, this.ValueBufferType );\n\n\t\tthis.setInterpolation( interpolation || this.DefaultInterpolation );\n\n\t}\n\n\t// Serialization (in static context, because of constructor invocation\n\t// and automatic invocation of .toJSON):\n\n\tstatic toJSON( track ) {\n\n\t\tconst trackType = track.constructor;\n\n\t\tlet json;\n\n\t\t// derived classes can define a static toJSON method\n\t\tif ( trackType.toJSON !== this.toJSON ) {\n\n\t\t\tjson = trackType.toJSON( track );\n\n\t\t} else {\n\n\t\t\t// by default, we assume the data can be serialized as-is\n\t\t\tjson = {\n\n\t\t\t\t'name': track.name,\n\t\t\t\t'times': convertArray( track.times, Array ),\n\t\t\t\t'values': convertArray( track.values, Array )\n\n\t\t\t};\n\n\t\t\tconst interpolation = track.getInterpolation();\n\n\t\t\tif ( interpolation !== track.DefaultInterpolation ) {\n\n\t\t\t\tjson.interpolation = interpolation;\n\n\t\t\t}\n\n\t\t}\n\n\t\tjson.type = track.ValueTypeName; // mandatory\n\n\t\treturn json;\n\n\t}\n\n\tInterpolantFactoryMethodDiscrete( result ) {\n\n\t\treturn new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );\n\n\t}\n\n\tInterpolantFactoryMethodLinear( result ) {\n\n\t\treturn new LinearInterpolant( this.times, this.values, this.getValueSize(), result );\n\n\t}\n\n\tInterpolantFactoryMethodSmooth( result ) {\n\n\t\treturn new CubicInterpolant( this.times, this.values, this.getValueSize(), result );\n\n\t}\n\n\tsetInterpolation( interpolation ) {\n\n\t\tlet factoryMethod;\n\n\t\tswitch ( interpolation ) {\n\n\t\t\tcase InterpolateDiscrete:\n\n\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodDiscrete;\n\n\t\t\t\tbreak;\n\n\t\t\tcase InterpolateLinear:\n\n\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodLinear;\n\n\t\t\t\tbreak;\n\n\t\t\tcase InterpolateSmooth:\n\n\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodSmooth;\n\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\tif ( factoryMethod === undefined ) {\n\n\t\t\tconst message = 'unsupported interpolation for ' +\n\t\t\t\tthis.ValueTypeName + ' keyframe track named ' + this.name;\n\n\t\t\tif ( this.createInterpolant === undefined ) {\n\n\t\t\t\t// fall back to default, unless the default itself is messed up\n\t\t\t\tif ( interpolation !== this.DefaultInterpolation ) {\n\n\t\t\t\t\tthis.setInterpolation( this.DefaultInterpolation );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthrow new Error( message ); // fatal, in this case\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconsole.warn( 'THREE.KeyframeTrack:', message );\n\t\t\treturn this;\n\n\t\t}\n\n\t\tthis.createInterpolant = factoryMethod;\n\n\t\treturn this;\n\n\t}\n\n\tgetInterpolation() {\n\n\t\tswitch ( this.createInterpolant ) {\n\n\t\t\tcase this.InterpolantFactoryMethodDiscrete:\n\n\t\t\t\treturn InterpolateDiscrete;\n\n\t\t\tcase this.InterpolantFactoryMethodLinear:\n\n\t\t\t\treturn InterpolateLinear;\n\n\t\t\tcase this.InterpolantFactoryMethodSmooth:\n\n\t\t\t\treturn InterpolateSmooth;\n\n\t\t}\n\n\t}\n\n\tgetValueSize() {\n\n\t\treturn this.values.length / this.times.length;\n\n\t}\n\n\t// move all keyframes either forwards or backwards in time\n\tshift( timeOffset ) {\n\n\t\tif ( timeOffset !== 0.0 ) {\n\n\t\t\tconst times = this.times;\n\n\t\t\tfor ( let i = 0, n = times.length; i !== n; ++ i ) {\n\n\t\t\t\ttimes[ i ] += timeOffset;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// scale all keyframe times by a factor (useful for frame <-> seconds conversions)\n\tscale( timeScale ) {\n\n\t\tif ( timeScale !== 1.0 ) {\n\n\t\t\tconst times = this.times;\n\n\t\t\tfor ( let i = 0, n = times.length; i !== n; ++ i ) {\n\n\t\t\t\ttimes[ i ] *= timeScale;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// removes keyframes before and after animation without changing any values within the range [startTime, endTime].\n\t// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values\n\ttrim( startTime, endTime ) {\n\n\t\tconst times = this.times,\n\t\t\tnKeys = times.length;\n\n\t\tlet from = 0,\n\t\t\tto = nKeys - 1;\n\n\t\twhile ( from !== nKeys && times[ from ] < startTime ) {\n\n\t\t\t++ from;\n\n\t\t}\n\n\t\twhile ( to !== - 1 && times[ to ] > endTime ) {\n\n\t\t\t-- to;\n\n\t\t}\n\n\t\t++ to; // inclusive -> exclusive bound\n\n\t\tif ( from !== 0 || to !== nKeys ) {\n\n\t\t\t// empty tracks are forbidden, so keep at least one keyframe\n\t\t\tif ( from >= to ) {\n\n\t\t\t\tto = Math.max( to, 1 );\n\t\t\t\tfrom = to - 1;\n\n\t\t\t}\n\n\t\t\tconst stride = this.getValueSize();\n\t\t\tthis.times = times.slice( from, to );\n\t\t\tthis.values = this.values.slice( from * stride, to * stride );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable\n\tvalidate() {\n\n\t\tlet valid = true;\n\n\t\tconst valueSize = this.getValueSize();\n\t\tif ( valueSize - Math.floor( valueSize ) !== 0 ) {\n\n\t\t\tconsole.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );\n\t\t\tvalid = false;\n\n\t\t}\n\n\t\tconst times = this.times,\n\t\t\tvalues = this.values,\n\n\t\t\tnKeys = times.length;\n\n\t\tif ( nKeys === 0 ) {\n\n\t\t\tconsole.error( 'THREE.KeyframeTrack: Track is empty.', this );\n\t\t\tvalid = false;\n\n\t\t}\n\n\t\tlet prevTime = null;\n\n\t\tfor ( let i = 0; i !== nKeys; i ++ ) {\n\n\t\t\tconst currTime = times[ i ];\n\n\t\t\tif ( typeof currTime === 'number' && isNaN( currTime ) ) {\n\n\t\t\t\tconsole.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );\n\t\t\t\tvalid = false;\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( prevTime !== null && prevTime > currTime ) {\n\n\t\t\t\tconsole.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );\n\t\t\t\tvalid = false;\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tprevTime = currTime;\n\n\t\t}\n\n\t\tif ( values !== undefined ) {\n\n\t\t\tif ( isTypedArray( values ) ) {\n\n\t\t\t\tfor ( let i = 0, n = values.length; i !== n; ++ i ) {\n\n\t\t\t\t\tconst value = values[ i ];\n\n\t\t\t\t\tif ( isNaN( value ) ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );\n\t\t\t\t\t\tvalid = false;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn valid;\n\n\t}\n\n\t// removes equivalent sequential keys as common in morph target sequences\n\t// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --\x3e (0,0,1,1,0,0)\n\toptimize() {\n\n\t\t// times or values may be shared with other tracks, so overwriting is unsafe\n\t\tconst times = this.times.slice(),\n\t\t\tvalues = this.values.slice(),\n\t\t\tstride = this.getValueSize(),\n\n\t\t\tsmoothInterpolation = this.getInterpolation() === InterpolateSmooth,\n\n\t\t\tlastIndex = times.length - 1;\n\n\t\tlet writeIndex = 1;\n\n\t\tfor ( let i = 1; i < lastIndex; ++ i ) {\n\n\t\t\tlet keep = false;\n\n\t\t\tconst time = times[ i ];\n\t\t\tconst timeNext = times[ i + 1 ];\n\n\t\t\t// remove adjacent keyframes scheduled at the same time\n\n\t\t\tif ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) {\n\n\t\t\t\tif ( ! smoothInterpolation ) {\n\n\t\t\t\t\t// remove unnecessary keyframes same as their neighbors\n\n\t\t\t\t\tconst offset = i * stride,\n\t\t\t\t\t\toffsetP = offset - stride,\n\t\t\t\t\t\toffsetN = offset + stride;\n\n\t\t\t\t\tfor ( let j = 0; j !== stride; ++ j ) {\n\n\t\t\t\t\t\tconst value = values[ offset + j ];\n\n\t\t\t\t\t\tif ( value !== values[ offsetP + j ] ||\n\t\t\t\t\t\t\tvalue !== values[ offsetN + j ] ) {\n\n\t\t\t\t\t\t\tkeep = true;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tkeep = true;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// in-place compaction\n\n\t\t\tif ( keep ) {\n\n\t\t\t\tif ( i !== writeIndex ) {\n\n\t\t\t\t\ttimes[ writeIndex ] = times[ i ];\n\n\t\t\t\t\tconst readOffset = i * stride,\n\t\t\t\t\t\twriteOffset = writeIndex * stride;\n\n\t\t\t\t\tfor ( let j = 0; j !== stride; ++ j ) {\n\n\t\t\t\t\t\tvalues[ writeOffset + j ] = values[ readOffset + j ];\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t++ writeIndex;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// flush last keyframe (compaction looks ahead)\n\n\t\tif ( lastIndex > 0 ) {\n\n\t\t\ttimes[ writeIndex ] = times[ lastIndex ];\n\n\t\t\tfor ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {\n\n\t\t\t\tvalues[ writeOffset + j ] = values[ readOffset + j ];\n\n\t\t\t}\n\n\t\t\t++ writeIndex;\n\n\t\t}\n\n\t\tif ( writeIndex !== times.length ) {\n\n\t\t\tthis.times = times.slice( 0, writeIndex );\n\t\t\tthis.values = values.slice( 0, writeIndex * stride );\n\n\t\t} else {\n\n\t\t\tthis.times = times;\n\t\t\tthis.values = values;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\tconst times = this.times.slice();\n\t\tconst values = this.values.slice();\n\n\t\tconst TypedKeyframeTrack = this.constructor;\n\t\tconst track = new TypedKeyframeTrack( this.name, times, values );\n\n\t\t// Interpolant argument to constructor is not saved, so copy the factory method directly.\n\t\ttrack.createInterpolant = this.createInterpolant;\n\n\t\treturn track;\n\n\t}\n\n}\n\nKeyframeTrack.prototype.TimeBufferType = Float32Array;\nKeyframeTrack.prototype.ValueBufferType = Float32Array;\nKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;\n\n/**\n * A Track of Boolean keyframe values.\n */\nclass BooleanKeyframeTrack extends KeyframeTrack {\n\n\t// No interpolation parameter because only InterpolateDiscrete is valid.\n\tconstructor( name, times, values ) {\n\n\t\tsuper( name, times, values );\n\n\t}\n\n}\n\nBooleanKeyframeTrack.prototype.ValueTypeName = 'bool';\nBooleanKeyframeTrack.prototype.ValueBufferType = Array;\nBooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;\nBooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;\nBooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;\n\n/**\n * A Track of keyframe values that represent color.\n */\nclass ColorKeyframeTrack extends KeyframeTrack {}\n\nColorKeyframeTrack.prototype.ValueTypeName = 'color';\n\n/**\n * A Track of numeric keyframe values.\n */\nclass NumberKeyframeTrack extends KeyframeTrack {}\n\nNumberKeyframeTrack.prototype.ValueTypeName = 'number';\n\n/**\n * Spherical linear unit quaternion interpolant.\n */\n\nclass QuaternionLinearInterpolant extends Interpolant {\n\n\tconstructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tsuper( parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t}\n\n\tinterpolate_( i1, t0, t, t1 ) {\n\n\t\tconst result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\n\t\t\talpha = ( t - t0 ) / ( t1 - t0 );\n\n\t\tlet offset = i1 * stride;\n\n\t\tfor ( let end = offset + stride; offset !== end; offset += 4 ) {\n\n\t\t\tQuaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n}\n\n/**\n * A Track of quaternion keyframe values.\n */\nclass QuaternionKeyframeTrack extends KeyframeTrack {\n\n\tInterpolantFactoryMethodLinear( result ) {\n\n\t\treturn new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );\n\n\t}\n\n}\n\nQuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion';\n// ValueBufferType is inherited\n// DefaultInterpolation is inherited;\nQuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;\n\n/**\n * A Track that interpolates Strings\n */\nclass StringKeyframeTrack extends KeyframeTrack {\n\n\t// No interpolation parameter because only InterpolateDiscrete is valid.\n\tconstructor( name, times, values ) {\n\n\t\tsuper( name, times, values );\n\n\t}\n\n}\n\nStringKeyframeTrack.prototype.ValueTypeName = 'string';\nStringKeyframeTrack.prototype.ValueBufferType = Array;\nStringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;\nStringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;\nStringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;\n\n/**\n * A Track of vectored keyframe values.\n */\nclass VectorKeyframeTrack extends KeyframeTrack {}\n\nVectorKeyframeTrack.prototype.ValueTypeName = 'vector';\n\nclass AnimationClip {\n\n\tconstructor( name = '', duration = - 1, tracks = [], blendMode = NormalAnimationBlendMode ) {\n\n\t\tthis.name = name;\n\t\tthis.tracks = tracks;\n\t\tthis.duration = duration;\n\t\tthis.blendMode = blendMode;\n\n\t\tthis.uuid = generateUUID();\n\n\t\t// this means it should figure out its duration by scanning the tracks\n\t\tif ( this.duration < 0 ) {\n\n\t\t\tthis.resetDuration();\n\n\t\t}\n\n\t}\n\n\n\tstatic parse( json ) {\n\n\t\tconst tracks = [],\n\t\t\tjsonTracks = json.tracks,\n\t\t\tframeTime = 1.0 / ( json.fps || 1.0 );\n\n\t\tfor ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) {\n\n\t\t\ttracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) );\n\n\t\t}\n\n\t\tconst clip = new this( json.name, json.duration, tracks, json.blendMode );\n\t\tclip.uuid = json.uuid;\n\n\t\treturn clip;\n\n\t}\n\n\tstatic toJSON( clip ) {\n\n\t\tconst tracks = [],\n\t\t\tclipTracks = clip.tracks;\n\n\t\tconst json = {\n\n\t\t\t'name': clip.name,\n\t\t\t'duration': clip.duration,\n\t\t\t'tracks': tracks,\n\t\t\t'uuid': clip.uuid,\n\t\t\t'blendMode': clip.blendMode\n\n\t\t};\n\n\t\tfor ( let i = 0, n = clipTracks.length; i !== n; ++ i ) {\n\n\t\t\ttracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );\n\n\t\t}\n\n\t\treturn json;\n\n\t}\n\n\tstatic CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) {\n\n\t\tconst numMorphTargets = morphTargetSequence.length;\n\t\tconst tracks = [];\n\n\t\tfor ( let i = 0; i < numMorphTargets; i ++ ) {\n\n\t\t\tlet times = [];\n\t\t\tlet values = [];\n\n\t\t\ttimes.push(\n\t\t\t\t( i + numMorphTargets - 1 ) % numMorphTargets,\n\t\t\t\ti,\n\t\t\t\t( i + 1 ) % numMorphTargets );\n\n\t\t\tvalues.push( 0, 1, 0 );\n\n\t\t\tconst order = getKeyframeOrder( times );\n\t\t\ttimes = sortedArray( times, 1, order );\n\t\t\tvalues = sortedArray( values, 1, order );\n\n\t\t\t// if there is a key at the first frame, duplicate it as the\n\t\t\t// last frame as well for perfect loop.\n\t\t\tif ( ! noLoop && times[ 0 ] === 0 ) {\n\n\t\t\t\ttimes.push( numMorphTargets );\n\t\t\t\tvalues.push( values[ 0 ] );\n\n\t\t\t}\n\n\t\t\ttracks.push(\n\t\t\t\tnew NumberKeyframeTrack(\n\t\t\t\t\t'.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',\n\t\t\t\t\ttimes, values\n\t\t\t\t).scale( 1.0 / fps ) );\n\n\t\t}\n\n\t\treturn new this( name, - 1, tracks );\n\n\t}\n\n\tstatic findByName( objectOrClipArray, name ) {\n\n\t\tlet clipArray = objectOrClipArray;\n\n\t\tif ( ! Array.isArray( objectOrClipArray ) ) {\n\n\t\t\tconst o = objectOrClipArray;\n\t\t\tclipArray = o.geometry && o.geometry.animations || o.animations;\n\n\t\t}\n\n\t\tfor ( let i = 0; i < clipArray.length; i ++ ) {\n\n\t\t\tif ( clipArray[ i ].name === name ) {\n\n\t\t\t\treturn clipArray[ i ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n\tstatic CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) {\n\n\t\tconst animationToMorphTargets = {};\n\n\t\t// tested with https://regex101.com/ on trick sequences\n\t\t// such flamingo_flyA_003, flamingo_run1_003, crdeath0059\n\t\tconst pattern = /^([\\w-]*?)([\\d]+)$/;\n\n\t\t// sort morph target names into animation groups based\n\t\t// patterns like Walk_001, Walk_002, Run_001, Run_002\n\t\tfor ( let i = 0, il = morphTargets.length; i < il; i ++ ) {\n\n\t\t\tconst morphTarget = morphTargets[ i ];\n\t\t\tconst parts = morphTarget.name.match( pattern );\n\n\t\t\tif ( parts && parts.length > 1 ) {\n\n\t\t\t\tconst name = parts[ 1 ];\n\n\t\t\t\tlet animationMorphTargets = animationToMorphTargets[ name ];\n\n\t\t\t\tif ( ! animationMorphTargets ) {\n\n\t\t\t\t\tanimationToMorphTargets[ name ] = animationMorphTargets = [];\n\n\t\t\t\t}\n\n\t\t\t\tanimationMorphTargets.push( morphTarget );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst clips = [];\n\n\t\tfor ( const name in animationToMorphTargets ) {\n\n\t\t\tclips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );\n\n\t\t}\n\n\t\treturn clips;\n\n\t}\n\n\t// parse the animation.hierarchy format\n\tstatic parseAnimation( animation, bones ) {\n\n\t\tif ( ! animation ) {\n\n\t\t\tconsole.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {\n\n\t\t\t// only return track if there are actually keys.\n\t\t\tif ( animationKeys.length !== 0 ) {\n\n\t\t\t\tconst times = [];\n\t\t\t\tconst values = [];\n\n\t\t\t\tflattenJSON( animationKeys, times, values, propertyName );\n\n\t\t\t\t// empty keys are filtered out, so check again\n\t\t\t\tif ( times.length !== 0 ) {\n\n\t\t\t\t\tdestTracks.push( new trackType( trackName, times, values ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tconst tracks = [];\n\n\t\tconst clipName = animation.name || 'default';\n\t\tconst fps = animation.fps || 30;\n\t\tconst blendMode = animation.blendMode;\n\n\t\t// automatic length determination in AnimationClip.\n\t\tlet duration = animation.length || - 1;\n\n\t\tconst hierarchyTracks = animation.hierarchy || [];\n\n\t\tfor ( let h = 0; h < hierarchyTracks.length; h ++ ) {\n\n\t\t\tconst animationKeys = hierarchyTracks[ h ].keys;\n\n\t\t\t// skip empty tracks\n\t\t\tif ( ! animationKeys || animationKeys.length === 0 ) continue;\n\n\t\t\t// process morph targets\n\t\t\tif ( animationKeys[ 0 ].morphTargets ) {\n\n\t\t\t\t// figure out all morph targets used in this track\n\t\t\t\tconst morphTargetNames = {};\n\n\t\t\t\tlet k;\n\n\t\t\t\tfor ( k = 0; k < animationKeys.length; k ++ ) {\n\n\t\t\t\t\tif ( animationKeys[ k ].morphTargets ) {\n\n\t\t\t\t\t\tfor ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {\n\n\t\t\t\t\t\t\tmorphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// create a track for each morph target with all zero\n\t\t\t\t// morphTargetInfluences except for the keys in which\n\t\t\t\t// the morphTarget is named.\n\t\t\t\tfor ( const morphTargetName in morphTargetNames ) {\n\n\t\t\t\t\tconst times = [];\n\t\t\t\t\tconst values = [];\n\n\t\t\t\t\tfor ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {\n\n\t\t\t\t\t\tconst animationKey = animationKeys[ k ];\n\n\t\t\t\t\t\ttimes.push( animationKey.time );\n\t\t\t\t\t\tvalues.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );\n\n\t\t\t\t}\n\n\t\t\t\tduration = morphTargetNames.length * fps;\n\n\t\t\t} else {\n\n\t\t\t\t// ...assume skeletal animation\n\n\t\t\t\tconst boneName = '.bones[' + bones[ h ].name + ']';\n\n\t\t\t\taddNonemptyTrack(\n\t\t\t\t\tVectorKeyframeTrack, boneName + '.position',\n\t\t\t\t\tanimationKeys, 'pos', tracks );\n\n\t\t\t\taddNonemptyTrack(\n\t\t\t\t\tQuaternionKeyframeTrack, boneName + '.quaternion',\n\t\t\t\t\tanimationKeys, 'rot', tracks );\n\n\t\t\t\taddNonemptyTrack(\n\t\t\t\t\tVectorKeyframeTrack, boneName + '.scale',\n\t\t\t\t\tanimationKeys, 'scl', tracks );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( tracks.length === 0 ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst clip = new this( clipName, duration, tracks, blendMode );\n\n\t\treturn clip;\n\n\t}\n\n\tresetDuration() {\n\n\t\tconst tracks = this.tracks;\n\t\tlet duration = 0;\n\n\t\tfor ( let i = 0, n = tracks.length; i !== n; ++ i ) {\n\n\t\t\tconst track = this.tracks[ i ];\n\n\t\t\tduration = Math.max( duration, track.times[ track.times.length - 1 ] );\n\n\t\t}\n\n\t\tthis.duration = duration;\n\n\t\treturn this;\n\n\t}\n\n\ttrim() {\n\n\t\tfor ( let i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\tthis.tracks[ i ].trim( 0, this.duration );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tvalidate() {\n\n\t\tlet valid = true;\n\n\t\tfor ( let i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\tvalid = valid && this.tracks[ i ].validate();\n\n\t\t}\n\n\t\treturn valid;\n\n\t}\n\n\toptimize() {\n\n\t\tfor ( let i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\tthis.tracks[ i ].optimize();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\tconst tracks = [];\n\n\t\tfor ( let i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\ttracks.push( this.tracks[ i ].clone() );\n\n\t\t}\n\n\t\treturn new this.constructor( this.name, this.duration, tracks, this.blendMode );\n\n\t}\n\n\ttoJSON() {\n\n\t\treturn this.constructor.toJSON( this );\n\n\t}\n\n}\n\nfunction getTrackTypeForValueTypeName( typeName ) {\n\n\tswitch ( typeName.toLowerCase() ) {\n\n\t\tcase 'scalar':\n\t\tcase 'double':\n\t\tcase 'float':\n\t\tcase 'number':\n\t\tcase 'integer':\n\n\t\t\treturn NumberKeyframeTrack;\n\n\t\tcase 'vector':\n\t\tcase 'vector2':\n\t\tcase 'vector3':\n\t\tcase 'vector4':\n\n\t\t\treturn VectorKeyframeTrack;\n\n\t\tcase 'color':\n\n\t\t\treturn ColorKeyframeTrack;\n\n\t\tcase 'quaternion':\n\n\t\t\treturn QuaternionKeyframeTrack;\n\n\t\tcase 'bool':\n\t\tcase 'boolean':\n\n\t\t\treturn BooleanKeyframeTrack;\n\n\t\tcase 'string':\n\n\t\t\treturn StringKeyframeTrack;\n\n\t}\n\n\tthrow new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );\n\n}\n\nfunction parseKeyframeTrack( json ) {\n\n\tif ( json.type === undefined ) {\n\n\t\tthrow new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );\n\n\t}\n\n\tconst trackType = getTrackTypeForValueTypeName( json.type );\n\n\tif ( json.times === undefined ) {\n\n\t\tconst times = [], values = [];\n\n\t\tflattenJSON( json.keys, times, values, 'value' );\n\n\t\tjson.times = times;\n\t\tjson.values = values;\n\n\t}\n\n\t// derived classes can define a static parse method\n\tif ( trackType.parse !== undefined ) {\n\n\t\treturn trackType.parse( json );\n\n\t} else {\n\n\t\t// by default, we assume a constructor compatible with the base\n\t\treturn new trackType( json.name, json.times, json.values, json.interpolation );\n\n\t}\n\n}\n\nconst Cache = {\n\n\tenabled: false,\n\n\tfiles: {},\n\n\tadd: function ( key, file ) {\n\n\t\tif ( this.enabled === false ) return;\n\n\t\t// console.log( 'THREE.Cache', 'Adding key:', key );\n\n\t\tthis.files[ key ] = file;\n\n\t},\n\n\tget: function ( key ) {\n\n\t\tif ( this.enabled === false ) return;\n\n\t\t// console.log( 'THREE.Cache', 'Checking key:', key );\n\n\t\treturn this.files[ key ];\n\n\t},\n\n\tremove: function ( key ) {\n\n\t\tdelete this.files[ key ];\n\n\t},\n\n\tclear: function () {\n\n\t\tthis.files = {};\n\n\t}\n\n};\n\nclass LoadingManager {\n\n\tconstructor( onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tlet isLoading = false;\n\t\tlet itemsLoaded = 0;\n\t\tlet itemsTotal = 0;\n\t\tlet urlModifier = undefined;\n\t\tconst handlers = [];\n\n\t\t// Refer to #5689 for the reason why we don't set .onStart\n\t\t// in the constructor\n\n\t\tthis.onStart = undefined;\n\t\tthis.onLoad = onLoad;\n\t\tthis.onProgress = onProgress;\n\t\tthis.onError = onError;\n\n\t\tthis.itemStart = function ( url ) {\n\n\t\t\titemsTotal ++;\n\n\t\t\tif ( isLoading === false ) {\n\n\t\t\t\tif ( scope.onStart !== undefined ) {\n\n\t\t\t\t\tscope.onStart( url, itemsLoaded, itemsTotal );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tisLoading = true;\n\n\t\t};\n\n\t\tthis.itemEnd = function ( url ) {\n\n\t\t\titemsLoaded ++;\n\n\t\t\tif ( scope.onProgress !== undefined ) {\n\n\t\t\t\tscope.onProgress( url, itemsLoaded, itemsTotal );\n\n\t\t\t}\n\n\t\t\tif ( itemsLoaded === itemsTotal ) {\n\n\t\t\t\tisLoading = false;\n\n\t\t\t\tif ( scope.onLoad !== undefined ) {\n\n\t\t\t\t\tscope.onLoad();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.itemError = function ( url ) {\n\n\t\t\tif ( scope.onError !== undefined ) {\n\n\t\t\t\tscope.onError( url );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.resolveURL = function ( url ) {\n\n\t\t\tif ( urlModifier ) {\n\n\t\t\t\treturn urlModifier( url );\n\n\t\t\t}\n\n\t\t\treturn url;\n\n\t\t};\n\n\t\tthis.setURLModifier = function ( transform ) {\n\n\t\t\turlModifier = transform;\n\n\t\t\treturn this;\n\n\t\t};\n\n\t\tthis.addHandler = function ( regex, loader ) {\n\n\t\t\thandlers.push( regex, loader );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t\tthis.removeHandler = function ( regex ) {\n\n\t\t\tconst index = handlers.indexOf( regex );\n\n\t\t\tif ( index !== - 1 ) {\n\n\t\t\t\thandlers.splice( index, 2 );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t};\n\n\t\tthis.getHandler = function ( file ) {\n\n\t\t\tfor ( let i = 0, l = handlers.length; i < l; i += 2 ) {\n\n\t\t\t\tconst regex = handlers[ i ];\n\t\t\t\tconst loader = handlers[ i + 1 ];\n\n\t\t\t\tif ( regex.global ) regex.lastIndex = 0; // see #17920\n\n\t\t\t\tif ( regex.test( file ) ) {\n\n\t\t\t\t\treturn loader;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn null;\n\n\t\t};\n\n\t}\n\n}\n\nconst DefaultLoadingManager = /*@__PURE__*/ new LoadingManager();\n\nclass Loader {\n\n\tconstructor( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t\tthis.crossOrigin = 'anonymous';\n\t\tthis.withCredentials = false;\n\t\tthis.path = '';\n\t\tthis.resourcePath = '';\n\t\tthis.requestHeader = {};\n\n\t}\n\n\tload( /* url, onLoad, onProgress, onError */ ) {}\n\n\tloadAsync( url, onProgress ) {\n\n\t\tconst scope = this;\n\n\t\treturn new Promise( function ( resolve, reject ) {\n\n\t\t\tscope.load( url, resolve, onProgress, reject );\n\n\t\t} );\n\n\t}\n\n\tparse( /* data */ ) {}\n\n\tsetCrossOrigin( crossOrigin ) {\n\n\t\tthis.crossOrigin = crossOrigin;\n\t\treturn this;\n\n\t}\n\n\tsetWithCredentials( value ) {\n\n\t\tthis.withCredentials = value;\n\t\treturn this;\n\n\t}\n\n\tsetPath( path ) {\n\n\t\tthis.path = path;\n\t\treturn this;\n\n\t}\n\n\tsetResourcePath( resourcePath ) {\n\n\t\tthis.resourcePath = resourcePath;\n\t\treturn this;\n\n\t}\n\n\tsetRequestHeader( requestHeader ) {\n\n\t\tthis.requestHeader = requestHeader;\n\t\treturn this;\n\n\t}\n\n}\n\nLoader.DEFAULT_MATERIAL_NAME = '__DEFAULT';\n\nconst loading = {};\n\nclass HttpError extends Error {\n\n\tconstructor( message, response ) {\n\n\t\tsuper( message );\n\t\tthis.response = response;\n\n\t}\n\n}\n\nclass FileLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tif ( url === undefined ) url = '';\n\n\t\tif ( this.path !== undefined ) url = this.path + url;\n\n\t\turl = this.manager.resolveURL( url );\n\n\t\tconst cached = Cache.get( url );\n\n\t\tif ( cached !== undefined ) {\n\n\t\t\tthis.manager.itemStart( url );\n\n\t\t\tsetTimeout( () => {\n\n\t\t\t\tif ( onLoad ) onLoad( cached );\n\n\t\t\t\tthis.manager.itemEnd( url );\n\n\t\t\t}, 0 );\n\n\t\t\treturn cached;\n\n\t\t}\n\n\t\t// Check if request is duplicate\n\n\t\tif ( loading[ url ] !== undefined ) {\n\n\t\t\tloading[ url ].push( {\n\n\t\t\t\tonLoad: onLoad,\n\t\t\t\tonProgress: onProgress,\n\t\t\t\tonError: onError\n\n\t\t\t} );\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t// Initialise array for duplicate requests\n\t\tloading[ url ] = [];\n\n\t\tloading[ url ].push( {\n\t\t\tonLoad: onLoad,\n\t\t\tonProgress: onProgress,\n\t\t\tonError: onError,\n\t\t} );\n\n\t\t// create request\n\t\tconst req = new Request( url, {\n\t\t\theaders: new Headers( this.requestHeader ),\n\t\t\tcredentials: this.withCredentials ? 'include' : 'same-origin',\n\t\t\t// An abort controller could be added within a future PR\n\t\t} );\n\n\t\t// record states ( avoid data race )\n\t\tconst mimeType = this.mimeType;\n\t\tconst responseType = this.responseType;\n\n\t\t// start the fetch\n\t\tfetch( req )\n\t\t\t.then( response => {\n\n\t\t\t\tif ( response.status === 200 || response.status === 0 ) {\n\n\t\t\t\t\t// Some browsers return HTTP Status 0 when using non-http protocol\n\t\t\t\t\t// e.g. 'file://' or 'data://'. Handle as success.\n\n\t\t\t\t\tif ( response.status === 0 ) {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.FileLoader: HTTP Status 0 received.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// Workaround: Checking if response.body === undefined for Alipay browser #23548\n\n\t\t\t\t\tif ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) {\n\n\t\t\t\t\t\treturn response;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst callbacks = loading[ url ];\n\t\t\t\t\tconst reader = response.body.getReader();\n\n\t\t\t\t\t// Nginx needs X-File-Size check\n\t\t\t\t\t// https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content\n\t\t\t\t\tconst contentLength = response.headers.get( 'X-File-Size' ) || response.headers.get( 'Content-Length' );\n\t\t\t\t\tconst total = contentLength ? parseInt( contentLength ) : 0;\n\t\t\t\t\tconst lengthComputable = total !== 0;\n\t\t\t\t\tlet loaded = 0;\n\n\t\t\t\t\t// periodically read data into the new stream tracking while download progress\n\t\t\t\t\tconst stream = new ReadableStream( {\n\t\t\t\t\t\tstart( controller ) {\n\n\t\t\t\t\t\t\treadData();\n\n\t\t\t\t\t\t\tfunction readData() {\n\n\t\t\t\t\t\t\t\treader.read().then( ( { done, value } ) => {\n\n\t\t\t\t\t\t\t\t\tif ( done ) {\n\n\t\t\t\t\t\t\t\t\t\tcontroller.close();\n\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\tloaded += value.byteLength;\n\n\t\t\t\t\t\t\t\t\t\tconst event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } );\n\t\t\t\t\t\t\t\t\t\tfor ( let i = 0, il = callbacks.length; i < il; i ++ ) {\n\n\t\t\t\t\t\t\t\t\t\t\tconst callback = callbacks[ i ];\n\t\t\t\t\t\t\t\t\t\t\tif ( callback.onProgress ) callback.onProgress( event );\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tcontroller.enqueue( value );\n\t\t\t\t\t\t\t\t\t\treadData();\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t}, ( e ) => {\n\n\t\t\t\t\t\t\t\t\tcontroller.error( e );\n\n\t\t\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} );\n\n\t\t\t\t\treturn new Response( stream );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthrow new HttpError( `fetch for \"${response.url}\" responded with ${response.status}: ${response.statusText}`, response );\n\n\t\t\t\t}\n\n\t\t\t} )\n\t\t\t.then( response => {\n\n\t\t\t\tswitch ( responseType ) {\n\n\t\t\t\t\tcase 'arraybuffer':\n\n\t\t\t\t\t\treturn response.arrayBuffer();\n\n\t\t\t\t\tcase 'blob':\n\n\t\t\t\t\t\treturn response.blob();\n\n\t\t\t\t\tcase 'document':\n\n\t\t\t\t\t\treturn response.text()\n\t\t\t\t\t\t\t.then( text => {\n\n\t\t\t\t\t\t\t\tconst parser = new DOMParser();\n\t\t\t\t\t\t\t\treturn parser.parseFromString( text, mimeType );\n\n\t\t\t\t\t\t\t} );\n\n\t\t\t\t\tcase 'json':\n\n\t\t\t\t\t\treturn response.json();\n\n\t\t\t\t\tdefault:\n\n\t\t\t\t\t\tif ( mimeType === undefined ) {\n\n\t\t\t\t\t\t\treturn response.text();\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// sniff encoding\n\t\t\t\t\t\t\tconst re = /charset=\"?([^;\"\\s]*)\"?/i;\n\t\t\t\t\t\t\tconst exec = re.exec( mimeType );\n\t\t\t\t\t\t\tconst label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined;\n\t\t\t\t\t\t\tconst decoder = new TextDecoder( label );\n\t\t\t\t\t\t\treturn response.arrayBuffer().then( ab => decoder.decode( ab ) );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} )\n\t\t\t.then( data => {\n\n\t\t\t\t// Add to cache only on HTTP success, so that we do not cache\n\t\t\t\t// error response bodies as proper responses to requests.\n\t\t\t\tCache.add( url, data );\n\n\t\t\t\tconst callbacks = loading[ url ];\n\t\t\t\tdelete loading[ url ];\n\n\t\t\t\tfor ( let i = 0, il = callbacks.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst callback = callbacks[ i ];\n\t\t\t\t\tif ( callback.onLoad ) callback.onLoad( data );\n\n\t\t\t\t}\n\n\t\t\t} )\n\t\t\t.catch( err => {\n\n\t\t\t\t// Abort errors and other errors are handled the same\n\n\t\t\t\tconst callbacks = loading[ url ];\n\n\t\t\t\tif ( callbacks === undefined ) {\n\n\t\t\t\t\t// When onLoad was called and url was deleted in `loading`\n\t\t\t\t\tthis.manager.itemError( url );\n\t\t\t\t\tthrow err;\n\n\t\t\t\t}\n\n\t\t\t\tdelete loading[ url ];\n\n\t\t\t\tfor ( let i = 0, il = callbacks.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst callback = callbacks[ i ];\n\t\t\t\t\tif ( callback.onError ) callback.onError( err );\n\n\t\t\t\t}\n\n\t\t\t\tthis.manager.itemError( url );\n\n\t\t\t} )\n\t\t\t.finally( () => {\n\n\t\t\t\tthis.manager.itemEnd( url );\n\n\t\t\t} );\n\n\t\tthis.manager.itemStart( url );\n\n\t}\n\n\tsetResponseType( value ) {\n\n\t\tthis.responseType = value;\n\t\treturn this;\n\n\t}\n\n\tsetMimeType( value ) {\n\n\t\tthis.mimeType = value;\n\t\treturn this;\n\n\t}\n\n}\n\nclass AnimationLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setPath( this.path );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setWithCredentials( this.withCredentials );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\ttry {\n\n\t\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\n\n\t\t\t} catch ( e ) {\n\n\t\t\t\tif ( onError ) {\n\n\t\t\t\t\tonError( e );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( e );\n\n\t\t\t\t}\n\n\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t}\n\n\tparse( json ) {\n\n\t\tconst animations = [];\n\n\t\tfor ( let i = 0; i < json.length; i ++ ) {\n\n\t\t\tconst clip = AnimationClip.parse( json[ i ] );\n\n\t\t\tanimations.push( clip );\n\n\t\t}\n\n\t\treturn animations;\n\n\t}\n\n}\n\n/**\n * Abstract Base class to block based textures loader (dds, pvr, ...)\n *\n * Sub classes have to implement the parse() method which will be used in load().\n */\n\nclass CompressedTextureLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst images = [];\n\n\t\tconst texture = new CompressedTexture();\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setPath( this.path );\n\t\tloader.setResponseType( 'arraybuffer' );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setWithCredentials( scope.withCredentials );\n\n\t\tlet loaded = 0;\n\n\t\tfunction loadTexture( i ) {\n\n\t\t\tloader.load( url[ i ], function ( buffer ) {\n\n\t\t\t\tconst texDatas = scope.parse( buffer, true );\n\n\t\t\t\timages[ i ] = {\n\t\t\t\t\twidth: texDatas.width,\n\t\t\t\t\theight: texDatas.height,\n\t\t\t\t\tformat: texDatas.format,\n\t\t\t\t\tmipmaps: texDatas.mipmaps\n\t\t\t\t};\n\n\t\t\t\tloaded += 1;\n\n\t\t\t\tif ( loaded === 6 ) {\n\n\t\t\t\t\tif ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter;\n\n\t\t\t\t\ttexture.image = images;\n\t\t\t\t\ttexture.format = texDatas.format;\n\t\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t\t}\n\n\t\t\t}, onProgress, onError );\n\n\t\t}\n\n\t\tif ( Array.isArray( url ) ) {\n\n\t\t\tfor ( let i = 0, il = url.length; i < il; ++ i ) {\n\n\t\t\t\tloadTexture( i );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// compressed cubemap texture stored in a single DDS file\n\n\t\t\tloader.load( url, function ( buffer ) {\n\n\t\t\t\tconst texDatas = scope.parse( buffer, true );\n\n\t\t\t\tif ( texDatas.isCubemap ) {\n\n\t\t\t\t\tconst faces = texDatas.mipmaps.length / texDatas.mipmapCount;\n\n\t\t\t\t\tfor ( let f = 0; f < faces; f ++ ) {\n\n\t\t\t\t\t\timages[ f ] = { mipmaps: [] };\n\n\t\t\t\t\t\tfor ( let i = 0; i < texDatas.mipmapCount; i ++ ) {\n\n\t\t\t\t\t\t\timages[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );\n\t\t\t\t\t\t\timages[ f ].format = texDatas.format;\n\t\t\t\t\t\t\timages[ f ].width = texDatas.width;\n\t\t\t\t\t\t\timages[ f ].height = texDatas.height;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture.image = images;\n\n\t\t\t\t} else {\n\n\t\t\t\t\ttexture.image.width = texDatas.width;\n\t\t\t\t\ttexture.image.height = texDatas.height;\n\t\t\t\t\ttexture.mipmaps = texDatas.mipmaps;\n\n\t\t\t\t}\n\n\t\t\t\tif ( texDatas.mipmapCount === 1 ) {\n\n\t\t\t\t\ttexture.minFilter = LinearFilter;\n\n\t\t\t\t}\n\n\t\t\t\ttexture.format = texDatas.format;\n\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t}, onProgress, onError );\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n}\n\nclass ImageLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tif ( this.path !== undefined ) url = this.path + url;\n\n\t\turl = this.manager.resolveURL( url );\n\n\t\tconst scope = this;\n\n\t\tconst cached = Cache.get( url );\n\n\t\tif ( cached !== undefined ) {\n\n\t\t\tscope.manager.itemStart( url );\n\n\t\t\tsetTimeout( function () {\n\n\t\t\t\tif ( onLoad ) onLoad( cached );\n\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t}, 0 );\n\n\t\t\treturn cached;\n\n\t\t}\n\n\t\tconst image = createElementNS( 'img' );\n\n\t\tfunction onImageLoad() {\n\n\t\t\tremoveEventListeners();\n\n\t\t\tCache.add( url, this );\n\n\t\t\tif ( onLoad ) onLoad( this );\n\n\t\t\tscope.manager.itemEnd( url );\n\n\t\t}\n\n\t\tfunction onImageError( event ) {\n\n\t\t\tremoveEventListeners();\n\n\t\t\tif ( onError ) onError( event );\n\n\t\t\tscope.manager.itemError( url );\n\t\t\tscope.manager.itemEnd( url );\n\n\t\t}\n\n\t\tfunction removeEventListeners() {\n\n\t\t\timage.removeEventListener( 'load', onImageLoad, false );\n\t\t\timage.removeEventListener( 'error', onImageError, false );\n\n\t\t}\n\n\t\timage.addEventListener( 'load', onImageLoad, false );\n\t\timage.addEventListener( 'error', onImageError, false );\n\n\t\tif ( url.slice( 0, 5 ) !== 'data:' ) {\n\n\t\t\tif ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;\n\n\t\t}\n\n\t\tscope.manager.itemStart( url );\n\n\t\timage.src = url;\n\n\t\treturn image;\n\n\t}\n\n}\n\nclass CubeTextureLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( urls, onLoad, onProgress, onError ) {\n\n\t\tconst texture = new CubeTexture();\n\t\ttexture.colorSpace = SRGBColorSpace;\n\n\t\tconst loader = new ImageLoader( this.manager );\n\t\tloader.setCrossOrigin( this.crossOrigin );\n\t\tloader.setPath( this.path );\n\n\t\tlet loaded = 0;\n\n\t\tfunction loadTexture( i ) {\n\n\t\t\tloader.load( urls[ i ], function ( image ) {\n\n\t\t\t\ttexture.images[ i ] = image;\n\n\t\t\t\tloaded ++;\n\n\t\t\t\tif ( loaded === 6 ) {\n\n\t\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t\t}\n\n\t\t\t}, undefined, onError );\n\n\t\t}\n\n\t\tfor ( let i = 0; i < urls.length; ++ i ) {\n\n\t\t\tloadTexture( i );\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n}\n\n/**\n * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)\n *\n * Sub classes have to implement the parse() method which will be used in load().\n */\n\nclass DataTextureLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst texture = new DataTexture();\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setResponseType( 'arraybuffer' );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setPath( this.path );\n\t\tloader.setWithCredentials( scope.withCredentials );\n\t\tloader.load( url, function ( buffer ) {\n\n\t\t\tlet texData;\n\n\t\t\ttry {\n\n\t\t\t\ttexData = scope.parse( buffer );\n\n\t\t\t} catch ( error ) {\n\n\t\t\t\tif ( onError !== undefined ) {\n\n\t\t\t\t\tonError( error );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( error );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( texData.image !== undefined ) {\n\n\t\t\t\ttexture.image = texData.image;\n\n\t\t\t} else if ( texData.data !== undefined ) {\n\n\t\t\t\ttexture.image.width = texData.width;\n\t\t\t\ttexture.image.height = texData.height;\n\t\t\t\ttexture.image.data = texData.data;\n\n\t\t\t}\n\n\t\t\ttexture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping;\n\t\t\ttexture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping;\n\n\t\t\ttexture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter;\n\t\t\ttexture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter;\n\n\t\t\ttexture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1;\n\n\t\t\tif ( texData.colorSpace !== undefined ) {\n\n\t\t\t\ttexture.colorSpace = texData.colorSpace;\n\n\t\t\t}\n\n\t\t\tif ( texData.flipY !== undefined ) {\n\n\t\t\t\ttexture.flipY = texData.flipY;\n\n\t\t\t}\n\n\t\t\tif ( texData.format !== undefined ) {\n\n\t\t\t\ttexture.format = texData.format;\n\n\t\t\t}\n\n\t\t\tif ( texData.type !== undefined ) {\n\n\t\t\t\ttexture.type = texData.type;\n\n\t\t\t}\n\n\t\t\tif ( texData.mipmaps !== undefined ) {\n\n\t\t\t\ttexture.mipmaps = texData.mipmaps;\n\t\t\t\ttexture.minFilter = LinearMipmapLinearFilter; // presumably...\n\n\t\t\t}\n\n\t\t\tif ( texData.mipmapCount === 1 ) {\n\n\t\t\t\ttexture.minFilter = LinearFilter;\n\n\t\t\t}\n\n\t\t\tif ( texData.generateMipmaps !== undefined ) {\n\n\t\t\t\ttexture.generateMipmaps = texData.generateMipmaps;\n\n\t\t\t}\n\n\t\t\ttexture.needsUpdate = true;\n\n\t\t\tif ( onLoad ) onLoad( texture, texData );\n\n\t\t}, onProgress, onError );\n\n\n\t\treturn texture;\n\n\t}\n\n}\n\nclass TextureLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst texture = new Texture();\n\n\t\tconst loader = new ImageLoader( this.manager );\n\t\tloader.setCrossOrigin( this.crossOrigin );\n\t\tloader.setPath( this.path );\n\n\t\tloader.load( url, function ( image ) {\n\n\t\t\ttexture.image = image;\n\t\t\ttexture.needsUpdate = true;\n\n\t\t\tif ( onLoad !== undefined ) {\n\n\t\t\t\tonLoad( texture );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t\treturn texture;\n\n\t}\n\n}\n\nclass Light extends Object3D {\n\n\tconstructor( color, intensity = 1 ) {\n\n\t\tsuper();\n\n\t\tthis.isLight = true;\n\n\t\tthis.type = 'Light';\n\n\t\tthis.color = new Color( color );\n\t\tthis.intensity = intensity;\n\n\t}\n\n\tdispose() {\n\n\t\t// Empty here in base class; some subclasses override.\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.color.copy( source.color );\n\t\tthis.intensity = source.intensity;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.object.color = this.color.getHex();\n\t\tdata.object.intensity = this.intensity;\n\n\t\tif ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();\n\n\t\tif ( this.distance !== undefined ) data.object.distance = this.distance;\n\t\tif ( this.angle !== undefined ) data.object.angle = this.angle;\n\t\tif ( this.decay !== undefined ) data.object.decay = this.decay;\n\t\tif ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;\n\n\t\tif ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();\n\t\tif ( this.target !== undefined ) data.object.target = this.target.uuid;\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass HemisphereLight extends Light {\n\n\tconstructor( skyColor, groundColor, intensity ) {\n\n\t\tsuper( skyColor, intensity );\n\n\t\tthis.isHemisphereLight = true;\n\n\t\tthis.type = 'HemisphereLight';\n\n\t\tthis.position.copy( Object3D.DEFAULT_UP );\n\t\tthis.updateMatrix();\n\n\t\tthis.groundColor = new Color( groundColor );\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.groundColor.copy( source.groundColor );\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4();\nconst _lightPositionWorld$1 = /*@__PURE__*/ new Vector3();\nconst _lookTarget$1 = /*@__PURE__*/ new Vector3();\n\nclass LightShadow {\n\n\tconstructor( camera ) {\n\n\t\tthis.camera = camera;\n\n\t\tthis.intensity = 1;\n\n\t\tthis.bias = 0;\n\t\tthis.normalBias = 0;\n\t\tthis.radius = 1;\n\t\tthis.blurSamples = 8;\n\n\t\tthis.mapSize = new Vector2( 512, 512 );\n\n\t\tthis.map = null;\n\t\tthis.mapPass = null;\n\t\tthis.matrix = new Matrix4();\n\n\t\tthis.autoUpdate = true;\n\t\tthis.needsUpdate = false;\n\n\t\tthis._frustum = new Frustum();\n\t\tthis._frameExtents = new Vector2( 1, 1 );\n\n\t\tthis._viewportCount = 1;\n\n\t\tthis._viewports = [\n\n\t\t\tnew Vector4( 0, 0, 1, 1 )\n\n\t\t];\n\n\t}\n\n\tgetViewportCount() {\n\n\t\treturn this._viewportCount;\n\n\t}\n\n\tgetFrustum() {\n\n\t\treturn this._frustum;\n\n\t}\n\n\tupdateMatrices( light ) {\n\n\t\tconst shadowCamera = this.camera;\n\t\tconst shadowMatrix = this.matrix;\n\n\t\t_lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld );\n\t\tshadowCamera.position.copy( _lightPositionWorld$1 );\n\n\t\t_lookTarget$1.setFromMatrixPosition( light.target.matrixWorld );\n\t\tshadowCamera.lookAt( _lookTarget$1 );\n\t\tshadowCamera.updateMatrixWorld();\n\n\t\t_projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );\n\t\tthis._frustum.setFromProjectionMatrix( _projScreenMatrix$1 );\n\n\t\tshadowMatrix.set(\n\t\t\t0.5, 0.0, 0.0, 0.5,\n\t\t\t0.0, 0.5, 0.0, 0.5,\n\t\t\t0.0, 0.0, 0.5, 0.5,\n\t\t\t0.0, 0.0, 0.0, 1.0\n\t\t);\n\n\t\tshadowMatrix.multiply( _projScreenMatrix$1 );\n\n\t}\n\n\tgetViewport( viewportIndex ) {\n\n\t\treturn this._viewports[ viewportIndex ];\n\n\t}\n\n\tgetFrameExtents() {\n\n\t\treturn this._frameExtents;\n\n\t}\n\n\tdispose() {\n\n\t\tif ( this.map ) {\n\n\t\t\tthis.map.dispose();\n\n\t\t}\n\n\t\tif ( this.mapPass ) {\n\n\t\t\tthis.mapPass.dispose();\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.camera = source.camera.clone();\n\n\t\tthis.intensity = source.intensity;\n\n\t\tthis.bias = source.bias;\n\t\tthis.radius = source.radius;\n\n\t\tthis.mapSize.copy( source.mapSize );\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst object = {};\n\n\t\tif ( this.intensity !== 1 ) object.intensity = this.intensity;\n\t\tif ( this.bias !== 0 ) object.bias = this.bias;\n\t\tif ( this.normalBias !== 0 ) object.normalBias = this.normalBias;\n\t\tif ( this.radius !== 1 ) object.radius = this.radius;\n\t\tif ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();\n\n\t\tobject.camera = this.camera.toJSON( false ).object;\n\t\tdelete object.camera.matrix;\n\n\t\treturn object;\n\n\t}\n\n}\n\nclass SpotLightShadow extends LightShadow {\n\n\tconstructor() {\n\n\t\tsuper( new PerspectiveCamera( 50, 1, 0.5, 500 ) );\n\n\t\tthis.isSpotLightShadow = true;\n\n\t\tthis.focus = 1;\n\n\t}\n\n\tupdateMatrices( light ) {\n\n\t\tconst camera = this.camera;\n\n\t\tconst fov = RAD2DEG * 2 * light.angle * this.focus;\n\t\tconst aspect = this.mapSize.width / this.mapSize.height;\n\t\tconst far = light.distance || camera.far;\n\n\t\tif ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {\n\n\t\t\tcamera.fov = fov;\n\t\t\tcamera.aspect = aspect;\n\t\t\tcamera.far = far;\n\t\t\tcamera.updateProjectionMatrix();\n\n\t\t}\n\n\t\tsuper.updateMatrices( light );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.focus = source.focus;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass SpotLight extends Light {\n\n\tconstructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) {\n\n\t\tsuper( color, intensity );\n\n\t\tthis.isSpotLight = true;\n\n\t\tthis.type = 'SpotLight';\n\n\t\tthis.position.copy( Object3D.DEFAULT_UP );\n\t\tthis.updateMatrix();\n\n\t\tthis.target = new Object3D();\n\n\t\tthis.distance = distance;\n\t\tthis.angle = angle;\n\t\tthis.penumbra = penumbra;\n\t\tthis.decay = decay;\n\n\t\tthis.map = null;\n\n\t\tthis.shadow = new SpotLightShadow();\n\n\t}\n\n\tget power() {\n\n\t\t// compute the light's luminous power (in lumens) from its intensity (in candela)\n\t\t// by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd)\n\t\treturn this.intensity * Math.PI;\n\n\t}\n\n\tset power( power ) {\n\n\t\t// set the light's intensity (in candela) from the desired luminous power (in lumens)\n\t\tthis.intensity = power / Math.PI;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.shadow.dispose();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.distance = source.distance;\n\t\tthis.angle = source.angle;\n\t\tthis.penumbra = source.penumbra;\n\t\tthis.decay = source.decay;\n\n\t\tthis.target = source.target.clone();\n\n\t\tthis.shadow = source.shadow.clone();\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _projScreenMatrix = /*@__PURE__*/ new Matrix4();\nconst _lightPositionWorld = /*@__PURE__*/ new Vector3();\nconst _lookTarget = /*@__PURE__*/ new Vector3();\n\nclass PointLightShadow extends LightShadow {\n\n\tconstructor() {\n\n\t\tsuper( new PerspectiveCamera( 90, 1, 0.5, 500 ) );\n\n\t\tthis.isPointLightShadow = true;\n\n\t\tthis._frameExtents = new Vector2( 4, 2 );\n\n\t\tthis._viewportCount = 6;\n\n\t\tthis._viewports = [\n\t\t\t// These viewports map a cube-map onto a 2D texture with the\n\t\t\t// following orientation:\n\t\t\t//\n\t\t\t// xzXZ\n\t\t\t// y Y\n\t\t\t//\n\t\t\t// X - Positive x direction\n\t\t\t// x - Negative x direction\n\t\t\t// Y - Positive y direction\n\t\t\t// y - Negative y direction\n\t\t\t// Z - Positive z direction\n\t\t\t// z - Negative z direction\n\n\t\t\t// positive X\n\t\t\tnew Vector4( 2, 1, 1, 1 ),\n\t\t\t// negative X\n\t\t\tnew Vector4( 0, 1, 1, 1 ),\n\t\t\t// positive Z\n\t\t\tnew Vector4( 3, 1, 1, 1 ),\n\t\t\t// negative Z\n\t\t\tnew Vector4( 1, 1, 1, 1 ),\n\t\t\t// positive Y\n\t\t\tnew Vector4( 3, 0, 1, 1 ),\n\t\t\t// negative Y\n\t\t\tnew Vector4( 1, 0, 1, 1 )\n\t\t];\n\n\t\tthis._cubeDirections = [\n\t\t\tnew Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),\n\t\t\tnew Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )\n\t\t];\n\n\t\tthis._cubeUps = [\n\t\t\tnew Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),\n\t\t\tnew Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),\tnew Vector3( 0, 0, - 1 )\n\t\t];\n\n\t}\n\n\tupdateMatrices( light, viewportIndex = 0 ) {\n\n\t\tconst camera = this.camera;\n\t\tconst shadowMatrix = this.matrix;\n\n\t\tconst far = light.distance || camera.far;\n\n\t\tif ( far !== camera.far ) {\n\n\t\t\tcamera.far = far;\n\t\t\tcamera.updateProjectionMatrix();\n\n\t\t}\n\n\t\t_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );\n\t\tcamera.position.copy( _lightPositionWorld );\n\n\t\t_lookTarget.copy( camera.position );\n\t\t_lookTarget.add( this._cubeDirections[ viewportIndex ] );\n\t\tcamera.up.copy( this._cubeUps[ viewportIndex ] );\n\t\tcamera.lookAt( _lookTarget );\n\t\tcamera.updateMatrixWorld();\n\n\t\tshadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );\n\n\t\t_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );\n\t\tthis._frustum.setFromProjectionMatrix( _projScreenMatrix );\n\n\t}\n\n}\n\nclass PointLight extends Light {\n\n\tconstructor( color, intensity, distance = 0, decay = 2 ) {\n\n\t\tsuper( color, intensity );\n\n\t\tthis.isPointLight = true;\n\n\t\tthis.type = 'PointLight';\n\n\t\tthis.distance = distance;\n\t\tthis.decay = decay;\n\n\t\tthis.shadow = new PointLightShadow();\n\n\t}\n\n\tget power() {\n\n\t\t// compute the light's luminous power (in lumens) from its intensity (in candela)\n\t\t// for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd)\n\t\treturn this.intensity * 4 * Math.PI;\n\n\t}\n\n\tset power( power ) {\n\n\t\t// set the light's intensity (in candela) from the desired luminous power (in lumens)\n\t\tthis.intensity = power / ( 4 * Math.PI );\n\n\t}\n\n\tdispose() {\n\n\t\tthis.shadow.dispose();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.distance = source.distance;\n\t\tthis.decay = source.decay;\n\n\t\tthis.shadow = source.shadow.clone();\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass DirectionalLightShadow extends LightShadow {\n\n\tconstructor() {\n\n\t\tsuper( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );\n\n\t\tthis.isDirectionalLightShadow = true;\n\n\t}\n\n}\n\nclass DirectionalLight extends Light {\n\n\tconstructor( color, intensity ) {\n\n\t\tsuper( color, intensity );\n\n\t\tthis.isDirectionalLight = true;\n\n\t\tthis.type = 'DirectionalLight';\n\n\t\tthis.position.copy( Object3D.DEFAULT_UP );\n\t\tthis.updateMatrix();\n\n\t\tthis.target = new Object3D();\n\n\t\tthis.shadow = new DirectionalLightShadow();\n\n\t}\n\n\tdispose() {\n\n\t\tthis.shadow.dispose();\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.target = source.target.clone();\n\t\tthis.shadow = source.shadow.clone();\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass AmbientLight extends Light {\n\n\tconstructor( color, intensity ) {\n\n\t\tsuper( color, intensity );\n\n\t\tthis.isAmbientLight = true;\n\n\t\tthis.type = 'AmbientLight';\n\n\t}\n\n}\n\nclass RectAreaLight extends Light {\n\n\tconstructor( color, intensity, width = 10, height = 10 ) {\n\n\t\tsuper( color, intensity );\n\n\t\tthis.isRectAreaLight = true;\n\n\t\tthis.type = 'RectAreaLight';\n\n\t\tthis.width = width;\n\t\tthis.height = height;\n\n\t}\n\n\tget power() {\n\n\t\t// compute the light's luminous power (in lumens) from its intensity (in nits)\n\t\treturn this.intensity * this.width * this.height * Math.PI;\n\n\t}\n\n\tset power( power ) {\n\n\t\t// set the light's intensity (in nits) from the desired luminous power (in lumens)\n\t\tthis.intensity = power / ( this.width * this.height * Math.PI );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.width = source.width;\n\t\tthis.height = source.height;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.object.width = this.width;\n\t\tdata.object.height = this.height;\n\n\t\treturn data;\n\n\t}\n\n}\n\n/**\n * Primary reference:\n * https://graphics.stanford.edu/papers/envmap/envmap.pdf\n *\n * Secondary reference:\n * https://www.ppsloan.org/publications/StupidSH36.pdf\n */\n\n// 3-band SH defined by 9 coefficients\n\nclass SphericalHarmonics3 {\n\n\tconstructor() {\n\n\t\tthis.isSphericalHarmonics3 = true;\n\n\t\tthis.coefficients = [];\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients.push( new Vector3() );\n\n\t\t}\n\n\t}\n\n\tset( coefficients ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].copy( coefficients[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tzero() {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].set( 0, 0, 0 );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// get the radiance in the direction of the normal\n\t// target is a Vector3\n\tgetAt( normal, target ) {\n\n\t\t// normal is assumed to be unit length\n\n\t\tconst x = normal.x, y = normal.y, z = normal.z;\n\n\t\tconst coeff = this.coefficients;\n\n\t\t// band 0\n\t\ttarget.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 );\n\n\t\t// band 1\n\t\ttarget.addScaledVector( coeff[ 1 ], 0.488603 * y );\n\t\ttarget.addScaledVector( coeff[ 2 ], 0.488603 * z );\n\t\ttarget.addScaledVector( coeff[ 3 ], 0.488603 * x );\n\n\t\t// band 2\n\t\ttarget.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) );\n\t\ttarget.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) );\n\t\ttarget.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) );\n\t\ttarget.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) );\n\t\ttarget.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) );\n\n\t\treturn target;\n\n\t}\n\n\t// get the irradiance (radiance convolved with cosine lobe) in the direction of the normal\n\t// target is a Vector3\n\t// https://graphics.stanford.edu/papers/envmap/envmap.pdf\n\tgetIrradianceAt( normal, target ) {\n\n\t\t// normal is assumed to be unit length\n\n\t\tconst x = normal.x, y = normal.y, z = normal.z;\n\n\t\tconst coeff = this.coefficients;\n\n\t\t// band 0\n\t\ttarget.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095\n\n\t\t// band 1\n\t\ttarget.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603\n\t\ttarget.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z );\n\t\ttarget.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x );\n\n\t\t// band 2\n\t\ttarget.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548\n\t\ttarget.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z );\n\t\ttarget.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3\n\t\ttarget.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z );\n\t\ttarget.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274\n\n\t\treturn target;\n\n\t}\n\n\tadd( sh ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].add( sh.coefficients[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\taddScaledSH( sh, s ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tscale( s ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].multiplyScalar( s );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tlerp( sh, alpha ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].lerp( sh.coefficients[ i ], alpha );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tequals( sh ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tif ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tcopy( sh ) {\n\n\t\treturn this.set( sh.coefficients );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tconst coefficients = this.coefficients;\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tcoefficients[ i ].fromArray( array, offset + ( i * 3 ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tconst coefficients = this.coefficients;\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tcoefficients[ i ].toArray( array, offset + ( i * 3 ) );\n\n\t\t}\n\n\t\treturn array;\n\n\t}\n\n\t// evaluate the basis functions\n\t// shBasis is an Array[ 9 ]\n\tstatic getBasisAt( normal, shBasis ) {\n\n\t\t// normal is assumed to be unit length\n\n\t\tconst x = normal.x, y = normal.y, z = normal.z;\n\n\t\t// band 0\n\t\tshBasis[ 0 ] = 0.282095;\n\n\t\t// band 1\n\t\tshBasis[ 1 ] = 0.488603 * y;\n\t\tshBasis[ 2 ] = 0.488603 * z;\n\t\tshBasis[ 3 ] = 0.488603 * x;\n\n\t\t// band 2\n\t\tshBasis[ 4 ] = 1.092548 * x * y;\n\t\tshBasis[ 5 ] = 1.092548 * y * z;\n\t\tshBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 );\n\t\tshBasis[ 7 ] = 1.092548 * x * z;\n\t\tshBasis[ 8 ] = 0.546274 * ( x * x - y * y );\n\n\t}\n\n}\n\nclass LightProbe extends Light {\n\n\tconstructor( sh = new SphericalHarmonics3(), intensity = 1 ) {\n\n\t\tsuper( undefined, intensity );\n\n\t\tthis.isLightProbe = true;\n\n\t\tthis.sh = sh;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.sh.copy( source.sh );\n\n\t\treturn this;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tthis.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON();\n\t\tthis.sh.fromArray( json.sh );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.object.sh = this.sh.toArray();\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass MaterialLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\t\tthis.textures = {};\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst loader = new FileLoader( scope.manager );\n\t\tloader.setPath( scope.path );\n\t\tloader.setRequestHeader( scope.requestHeader );\n\t\tloader.setWithCredentials( scope.withCredentials );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\ttry {\n\n\t\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\n\n\t\t\t} catch ( e ) {\n\n\t\t\t\tif ( onError ) {\n\n\t\t\t\t\tonError( e );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( e );\n\n\t\t\t\t}\n\n\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t}\n\n\tparse( json ) {\n\n\t\tconst textures = this.textures;\n\n\t\tfunction getTexture( name ) {\n\n\t\t\tif ( textures[ name ] === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.MaterialLoader: Undefined texture', name );\n\n\t\t\t}\n\n\t\t\treturn textures[ name ];\n\n\t\t}\n\n\t\tconst material = MaterialLoader.createMaterialFromType( json.type );\n\n\t\tif ( json.uuid !== undefined ) material.uuid = json.uuid;\n\t\tif ( json.name !== undefined ) material.name = json.name;\n\t\tif ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color );\n\t\tif ( json.roughness !== undefined ) material.roughness = json.roughness;\n\t\tif ( json.metalness !== undefined ) material.metalness = json.metalness;\n\t\tif ( json.sheen !== undefined ) material.sheen = json.sheen;\n\t\tif ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor );\n\t\tif ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness;\n\t\tif ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive );\n\t\tif ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular );\n\t\tif ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity;\n\t\tif ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor );\n\t\tif ( json.shininess !== undefined ) material.shininess = json.shininess;\n\t\tif ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat;\n\t\tif ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness;\n\t\tif ( json.dispersion !== undefined ) material.dispersion = json.dispersion;\n\t\tif ( json.iridescence !== undefined ) material.iridescence = json.iridescence;\n\t\tif ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR;\n\t\tif ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange;\n\t\tif ( json.transmission !== undefined ) material.transmission = json.transmission;\n\t\tif ( json.thickness !== undefined ) material.thickness = json.thickness;\n\t\tif ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance;\n\t\tif ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor );\n\t\tif ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy;\n\t\tif ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation;\n\t\tif ( json.fog !== undefined ) material.fog = json.fog;\n\t\tif ( json.flatShading !== undefined ) material.flatShading = json.flatShading;\n\t\tif ( json.blending !== undefined ) material.blending = json.blending;\n\t\tif ( json.combine !== undefined ) material.combine = json.combine;\n\t\tif ( json.side !== undefined ) material.side = json.side;\n\t\tif ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide;\n\t\tif ( json.opacity !== undefined ) material.opacity = json.opacity;\n\t\tif ( json.transparent !== undefined ) material.transparent = json.transparent;\n\t\tif ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;\n\t\tif ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash;\n\t\tif ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc;\n\t\tif ( json.depthTest !== undefined ) material.depthTest = json.depthTest;\n\t\tif ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;\n\t\tif ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;\n\t\tif ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc;\n\t\tif ( json.blendDst !== undefined ) material.blendDst = json.blendDst;\n\t\tif ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation;\n\t\tif ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha;\n\t\tif ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha;\n\t\tif ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha;\n\t\tif ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor );\n\t\tif ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha;\n\t\tif ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask;\n\t\tif ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc;\n\t\tif ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef;\n\t\tif ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask;\n\t\tif ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail;\n\t\tif ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail;\n\t\tif ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass;\n\t\tif ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite;\n\n\t\tif ( json.wireframe !== undefined ) material.wireframe = json.wireframe;\n\t\tif ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;\n\t\tif ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;\n\t\tif ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;\n\n\t\tif ( json.rotation !== undefined ) material.rotation = json.rotation;\n\n\t\tif ( json.linewidth !== undefined ) material.linewidth = json.linewidth;\n\t\tif ( json.dashSize !== undefined ) material.dashSize = json.dashSize;\n\t\tif ( json.gapSize !== undefined ) material.gapSize = json.gapSize;\n\t\tif ( json.scale !== undefined ) material.scale = json.scale;\n\n\t\tif ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset;\n\t\tif ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor;\n\t\tif ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits;\n\n\t\tif ( json.dithering !== undefined ) material.dithering = json.dithering;\n\n\t\tif ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage;\n\t\tif ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha;\n\t\tif ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass;\n\n\t\tif ( json.visible !== undefined ) material.visible = json.visible;\n\n\t\tif ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped;\n\n\t\tif ( json.userData !== undefined ) material.userData = json.userData;\n\n\t\tif ( json.vertexColors !== undefined ) {\n\n\t\t\tif ( typeof json.vertexColors === 'number' ) {\n\n\t\t\t\tmaterial.vertexColors = ( json.vertexColors > 0 ) ? true : false;\n\n\t\t\t} else {\n\n\t\t\t\tmaterial.vertexColors = json.vertexColors;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Shader Material\n\n\t\tif ( json.uniforms !== undefined ) {\n\n\t\t\tfor ( const name in json.uniforms ) {\n\n\t\t\t\tconst uniform = json.uniforms[ name ];\n\n\t\t\t\tmaterial.uniforms[ name ] = {};\n\n\t\t\t\tswitch ( uniform.type ) {\n\n\t\t\t\t\tcase 't':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = getTexture( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'c':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Color().setHex( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'v2':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Vector2().fromArray( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'v3':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Vector3().fromArray( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'v4':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Vector4().fromArray( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'm3':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Matrix3().fromArray( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'm4':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Matrix4().fromArray( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = uniform.value;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( json.defines !== undefined ) material.defines = json.defines;\n\t\tif ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;\n\t\tif ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;\n\t\tif ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion;\n\n\t\tif ( json.extensions !== undefined ) {\n\n\t\t\tfor ( const key in json.extensions ) {\n\n\t\t\t\tmaterial.extensions[ key ] = json.extensions[ key ];\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( json.lights !== undefined ) material.lights = json.lights;\n\t\tif ( json.clipping !== undefined ) material.clipping = json.clipping;\n\n\t\t// for PointsMaterial\n\n\t\tif ( json.size !== undefined ) material.size = json.size;\n\t\tif ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;\n\n\t\t// maps\n\n\t\tif ( json.map !== undefined ) material.map = getTexture( json.map );\n\t\tif ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap );\n\n\t\tif ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap );\n\n\t\tif ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );\n\t\tif ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;\n\n\t\tif ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );\n\t\tif ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType;\n\t\tif ( json.normalScale !== undefined ) {\n\n\t\t\tlet normalScale = json.normalScale;\n\n\t\t\tif ( Array.isArray( normalScale ) === false ) {\n\n\t\t\t\t// Blender exporter used to export a scalar. See #7459\n\n\t\t\t\tnormalScale = [ normalScale, normalScale ];\n\n\t\t\t}\n\n\t\t\tmaterial.normalScale = new Vector2().fromArray( normalScale );\n\n\t\t}\n\n\t\tif ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );\n\t\tif ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;\n\t\tif ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;\n\n\t\tif ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );\n\t\tif ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );\n\n\t\tif ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );\n\t\tif ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;\n\n\t\tif ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );\n\t\tif ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap );\n\t\tif ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap );\n\n\t\tif ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );\n\t\tif ( json.envMapRotation !== undefined ) material.envMapRotation.fromArray( json.envMapRotation );\n\t\tif ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity;\n\n\t\tif ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;\n\t\tif ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio;\n\n\t\tif ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );\n\t\tif ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;\n\n\t\tif ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );\n\t\tif ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;\n\n\t\tif ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );\n\n\t\tif ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap );\n\t\tif ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap );\n\t\tif ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap );\n\t\tif ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale );\n\n\t\tif ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap );\n\t\tif ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap );\n\n\t\tif ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap );\n\t\tif ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap );\n\n\t\tif ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap );\n\n\t\tif ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap );\n\t\tif ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap );\n\n\t\treturn material;\n\n\t}\n\n\tsetTextures( value ) {\n\n\t\tthis.textures = value;\n\t\treturn this;\n\n\t}\n\n\tstatic createMaterialFromType( type ) {\n\n\t\tconst materialLib = {\n\t\t\tShadowMaterial,\n\t\t\tSpriteMaterial,\n\t\t\tRawShaderMaterial,\n\t\t\tShaderMaterial,\n\t\t\tPointsMaterial,\n\t\t\tMeshPhysicalMaterial,\n\t\t\tMeshStandardMaterial,\n\t\t\tMeshPhongMaterial,\n\t\t\tMeshToonMaterial,\n\t\t\tMeshNormalMaterial,\n\t\t\tMeshLambertMaterial,\n\t\t\tMeshDepthMaterial,\n\t\t\tMeshDistanceMaterial,\n\t\t\tMeshBasicMaterial,\n\t\t\tMeshMatcapMaterial,\n\t\t\tLineDashedMaterial,\n\t\t\tLineBasicMaterial,\n\t\t\tMaterial\n\t\t};\n\n\t\treturn new materialLib[ type ]();\n\n\t}\n\n}\n\nclass LoaderUtils {\n\n\tstatic decodeText( array ) { // @deprecated, r165\n\n\t\tconsole.warn( 'THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead.' );\n\n\t\tif ( typeof TextDecoder !== 'undefined' ) {\n\n\t\t\treturn new TextDecoder().decode( array );\n\n\t\t}\n\n\t\t// Avoid the String.fromCharCode.apply(null, array) shortcut, which\n\t\t// throws a \"maximum call stack size exceeded\" error for large arrays.\n\n\t\tlet s = '';\n\n\t\tfor ( let i = 0, il = array.length; i < il; i ++ ) {\n\n\t\t\t// Implicitly assumes little-endian.\n\t\t\ts += String.fromCharCode( array[ i ] );\n\n\t\t}\n\n\t\ttry {\n\n\t\t\t// merges multi-byte utf-8 characters.\n\n\t\t\treturn decodeURIComponent( escape( s ) );\n\n\t\t} catch ( e ) { // see #16358\n\n\t\t\treturn s;\n\n\t\t}\n\n\t}\n\n\tstatic extractUrlBase( url ) {\n\n\t\tconst index = url.lastIndexOf( '/' );\n\n\t\tif ( index === - 1 ) return './';\n\n\t\treturn url.slice( 0, index + 1 );\n\n\t}\n\n\tstatic resolveURL( url, path ) {\n\n\t\t// Invalid URL\n\t\tif ( typeof url !== 'string' || url === '' ) return '';\n\n\t\t// Host Relative URL\n\t\tif ( /^https?:\\/\\//i.test( path ) && /^\\//.test( url ) ) {\n\n\t\t\tpath = path.replace( /(^https?:\\/\\/[^\\/]+).*/i, '$1' );\n\n\t\t}\n\n\t\t// Absolute URL http://,https://,//\n\t\tif ( /^(https?:)?\\/\\//i.test( url ) ) return url;\n\n\t\t// Data URI\n\t\tif ( /^data:.*,.*$/i.test( url ) ) return url;\n\n\t\t// Blob URL\n\t\tif ( /^blob:.*$/i.test( url ) ) return url;\n\n\t\t// Relative URL\n\t\treturn path + url;\n\n\t}\n\n}\n\nclass InstancedBufferGeometry extends BufferGeometry {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isInstancedBufferGeometry = true;\n\n\t\tthis.type = 'InstancedBufferGeometry';\n\t\tthis.instanceCount = Infinity;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.instanceCount = source.instanceCount;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.instanceCount = this.instanceCount;\n\n\t\tdata.isInstancedBufferGeometry = true;\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass BufferGeometryLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst loader = new FileLoader( scope.manager );\n\t\tloader.setPath( scope.path );\n\t\tloader.setRequestHeader( scope.requestHeader );\n\t\tloader.setWithCredentials( scope.withCredentials );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\ttry {\n\n\t\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\n\n\t\t\t} catch ( e ) {\n\n\t\t\t\tif ( onError ) {\n\n\t\t\t\t\tonError( e );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( e );\n\n\t\t\t\t}\n\n\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t}\n\n\tparse( json ) {\n\n\t\tconst interleavedBufferMap = {};\n\t\tconst arrayBufferMap = {};\n\n\t\tfunction getInterleavedBuffer( json, uuid ) {\n\n\t\t\tif ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ];\n\n\t\t\tconst interleavedBuffers = json.interleavedBuffers;\n\t\t\tconst interleavedBuffer = interleavedBuffers[ uuid ];\n\n\t\t\tconst buffer = getArrayBuffer( json, interleavedBuffer.buffer );\n\n\t\t\tconst array = getTypedArray( interleavedBuffer.type, buffer );\n\t\t\tconst ib = new InterleavedBuffer( array, interleavedBuffer.stride );\n\t\t\tib.uuid = interleavedBuffer.uuid;\n\n\t\t\tinterleavedBufferMap[ uuid ] = ib;\n\n\t\t\treturn ib;\n\n\t\t}\n\n\t\tfunction getArrayBuffer( json, uuid ) {\n\n\t\t\tif ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ];\n\n\t\t\tconst arrayBuffers = json.arrayBuffers;\n\t\t\tconst arrayBuffer = arrayBuffers[ uuid ];\n\n\t\t\tconst ab = new Uint32Array( arrayBuffer ).buffer;\n\n\t\t\tarrayBufferMap[ uuid ] = ab;\n\n\t\t\treturn ab;\n\n\t\t}\n\n\t\tconst geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry();\n\n\t\tconst index = json.data.index;\n\n\t\tif ( index !== undefined ) {\n\n\t\t\tconst typedArray = getTypedArray( index.type, index.array );\n\t\t\tgeometry.setIndex( new BufferAttribute( typedArray, 1 ) );\n\n\t\t}\n\n\t\tconst attributes = json.data.attributes;\n\n\t\tfor ( const key in attributes ) {\n\n\t\t\tconst attribute = attributes[ key ];\n\t\t\tlet bufferAttribute;\n\n\t\t\tif ( attribute.isInterleavedBufferAttribute ) {\n\n\t\t\t\tconst interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );\n\t\t\t\tbufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );\n\n\t\t\t} else {\n\n\t\t\t\tconst typedArray = getTypedArray( attribute.type, attribute.array );\n\t\t\t\tconst bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute;\n\t\t\t\tbufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized );\n\n\t\t\t}\n\n\t\t\tif ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;\n\t\t\tif ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage );\n\n\t\t\tgeometry.setAttribute( key, bufferAttribute );\n\n\t\t}\n\n\t\tconst morphAttributes = json.data.morphAttributes;\n\n\t\tif ( morphAttributes ) {\n\n\t\t\tfor ( const key in morphAttributes ) {\n\n\t\t\t\tconst attributeArray = morphAttributes[ key ];\n\n\t\t\t\tconst array = [];\n\n\t\t\t\tfor ( let i = 0, il = attributeArray.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst attribute = attributeArray[ i ];\n\t\t\t\t\tlet bufferAttribute;\n\n\t\t\t\t\tif ( attribute.isInterleavedBufferAttribute ) {\n\n\t\t\t\t\t\tconst interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );\n\t\t\t\t\t\tbufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconst typedArray = getTypedArray( attribute.type, attribute.array );\n\t\t\t\t\t\tbufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;\n\t\t\t\t\tarray.push( bufferAttribute );\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.morphAttributes[ key ] = array;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst morphTargetsRelative = json.data.morphTargetsRelative;\n\n\t\tif ( morphTargetsRelative ) {\n\n\t\t\tgeometry.morphTargetsRelative = true;\n\n\t\t}\n\n\t\tconst groups = json.data.groups || json.data.drawcalls || json.data.offsets;\n\n\t\tif ( groups !== undefined ) {\n\n\t\t\tfor ( let i = 0, n = groups.length; i !== n; ++ i ) {\n\n\t\t\t\tconst group = groups[ i ];\n\n\t\t\t\tgeometry.addGroup( group.start, group.count, group.materialIndex );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst boundingSphere = json.data.boundingSphere;\n\n\t\tif ( boundingSphere !== undefined ) {\n\n\t\t\tconst center = new Vector3();\n\n\t\t\tif ( boundingSphere.center !== undefined ) {\n\n\t\t\t\tcenter.fromArray( boundingSphere.center );\n\n\t\t\t}\n\n\t\t\tgeometry.boundingSphere = new Sphere( center, boundingSphere.radius );\n\n\t\t}\n\n\t\tif ( json.name ) geometry.name = json.name;\n\t\tif ( json.userData ) geometry.userData = json.userData;\n\n\t\treturn geometry;\n\n\t}\n\n}\n\nclass ObjectLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;\n\t\tthis.resourcePath = this.resourcePath || path;\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setPath( this.path );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setWithCredentials( this.withCredentials );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\tlet json = null;\n\n\t\t\ttry {\n\n\t\t\t\tjson = JSON.parse( text );\n\n\t\t\t} catch ( error ) {\n\n\t\t\t\tif ( onError !== undefined ) onError( error );\n\n\t\t\t\tconsole.error( 'THREE:ObjectLoader: Can\\'t parse ' + url + '.', error.message );\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tconst metadata = json.metadata;\n\n\t\t\tif ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {\n\n\t\t\t\tif ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\\'t load ' + url ) );\n\n\t\t\t\tconsole.error( 'THREE.ObjectLoader: Can\\'t load ' + url );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tscope.parse( json, onLoad );\n\n\t\t}, onProgress, onError );\n\n\t}\n\n\tasync loadAsync( url, onProgress ) {\n\n\t\tconst scope = this;\n\n\t\tconst path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;\n\t\tthis.resourcePath = this.resourcePath || path;\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setPath( this.path );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setWithCredentials( this.withCredentials );\n\n\t\tconst text = await loader.loadAsync( url, onProgress );\n\n\t\tconst json = JSON.parse( text );\n\n\t\tconst metadata = json.metadata;\n\n\t\tif ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {\n\n\t\t\tthrow new Error( 'THREE.ObjectLoader: Can\\'t load ' + url );\n\n\t\t}\n\n\t\treturn await scope.parseAsync( json );\n\n\t}\n\n\tparse( json, onLoad ) {\n\n\t\tconst animations = this.parseAnimations( json.animations );\n\t\tconst shapes = this.parseShapes( json.shapes );\n\t\tconst geometries = this.parseGeometries( json.geometries, shapes );\n\n\t\tconst images = this.parseImages( json.images, function () {\n\n\t\t\tif ( onLoad !== undefined ) onLoad( object );\n\n\t\t} );\n\n\t\tconst textures = this.parseTextures( json.textures, images );\n\t\tconst materials = this.parseMaterials( json.materials, textures );\n\n\t\tconst object = this.parseObject( json.object, geometries, materials, textures, animations );\n\t\tconst skeletons = this.parseSkeletons( json.skeletons, object );\n\n\t\tthis.bindSkeletons( object, skeletons );\n\t\tthis.bindLightTargets( object );\n\n\t\t//\n\n\t\tif ( onLoad !== undefined ) {\n\n\t\t\tlet hasImages = false;\n\n\t\t\tfor ( const uuid in images ) {\n\n\t\t\t\tif ( images[ uuid ].data instanceof HTMLImageElement ) {\n\n\t\t\t\t\thasImages = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( hasImages === false ) onLoad( object );\n\n\t\t}\n\n\t\treturn object;\n\n\t}\n\n\tasync parseAsync( json ) {\n\n\t\tconst animations = this.parseAnimations( json.animations );\n\t\tconst shapes = this.parseShapes( json.shapes );\n\t\tconst geometries = this.parseGeometries( json.geometries, shapes );\n\n\t\tconst images = await this.parseImagesAsync( json.images );\n\n\t\tconst textures = this.parseTextures( json.textures, images );\n\t\tconst materials = this.parseMaterials( json.materials, textures );\n\n\t\tconst object = this.parseObject( json.object, geometries, materials, textures, animations );\n\t\tconst skeletons = this.parseSkeletons( json.skeletons, object );\n\n\t\tthis.bindSkeletons( object, skeletons );\n\n\t\treturn object;\n\n\t}\n\n\tparseShapes( json ) {\n\n\t\tconst shapes = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tfor ( let i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tconst shape = new Shape().fromJSON( json[ i ] );\n\n\t\t\t\tshapes[ shape.uuid ] = shape;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn shapes;\n\n\t}\n\n\tparseSkeletons( json, object ) {\n\n\t\tconst skeletons = {};\n\t\tconst bones = {};\n\n\t\t// generate bone lookup table\n\n\t\tobject.traverse( function ( child ) {\n\n\t\t\tif ( child.isBone ) bones[ child.uuid ] = child;\n\n\t\t} );\n\n\t\t// create skeletons\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tfor ( let i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tconst skeleton = new Skeleton().fromJSON( json[ i ], bones );\n\n\t\t\t\tskeletons[ skeleton.uuid ] = skeleton;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn skeletons;\n\n\t}\n\n\tparseGeometries( json, shapes ) {\n\n\t\tconst geometries = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tconst bufferGeometryLoader = new BufferGeometryLoader();\n\n\t\t\tfor ( let i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tlet geometry;\n\t\t\t\tconst data = json[ i ];\n\n\t\t\t\tswitch ( data.type ) {\n\n\t\t\t\t\tcase 'BufferGeometry':\n\t\t\t\t\tcase 'InstancedBufferGeometry':\n\n\t\t\t\t\t\tgeometry = bufferGeometryLoader.parse( data );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\n\t\t\t\t\t\tif ( data.type in Geometries ) {\n\n\t\t\t\t\t\t\tgeometry = Geometries[ data.type ].fromJSON( data, shapes );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tconsole.warn( `THREE.ObjectLoader: Unsupported geometry type \"${ data.type }\"` );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.uuid = data.uuid;\n\n\t\t\t\tif ( data.name !== undefined ) geometry.name = data.name;\n\t\t\t\tif ( data.userData !== undefined ) geometry.userData = data.userData;\n\n\t\t\t\tgeometries[ data.uuid ] = geometry;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn geometries;\n\n\t}\n\n\tparseMaterials( json, textures ) {\n\n\t\tconst cache = {}; // MultiMaterial\n\t\tconst materials = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tconst loader = new MaterialLoader();\n\t\t\tloader.setTextures( textures );\n\n\t\t\tfor ( let i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tconst data = json[ i ];\n\n\t\t\t\tif ( cache[ data.uuid ] === undefined ) {\n\n\t\t\t\t\tcache[ data.uuid ] = loader.parse( data );\n\n\t\t\t\t}\n\n\t\t\t\tmaterials[ data.uuid ] = cache[ data.uuid ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn materials;\n\n\t}\n\n\tparseAnimations( json ) {\n\n\t\tconst animations = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tfor ( let i = 0; i < json.length; i ++ ) {\n\n\t\t\t\tconst data = json[ i ];\n\n\t\t\t\tconst clip = AnimationClip.parse( data );\n\n\t\t\t\tanimations[ clip.uuid ] = clip;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn animations;\n\n\t}\n\n\tparseImages( json, onLoad ) {\n\n\t\tconst scope = this;\n\t\tconst images = {};\n\n\t\tlet loader;\n\n\t\tfunction loadImage( url ) {\n\n\t\t\tscope.manager.itemStart( url );\n\n\t\t\treturn loader.load( url, function () {\n\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t}, undefined, function () {\n\n\t\t\t\tscope.manager.itemError( url );\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t} );\n\n\t\t}\n\n\t\tfunction deserializeImage( image ) {\n\n\t\t\tif ( typeof image === 'string' ) {\n\n\t\t\t\tconst url = image;\n\n\t\t\t\tconst path = /^(\\/\\/)|([a-z]+:(\\/\\/)?)/i.test( url ) ? url : scope.resourcePath + url;\n\n\t\t\t\treturn loadImage( path );\n\n\t\t\t} else {\n\n\t\t\t\tif ( image.data ) {\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdata: getTypedArray( image.type, image.data ),\n\t\t\t\t\t\twidth: image.width,\n\t\t\t\t\t\theight: image.height\n\t\t\t\t\t};\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( json !== undefined && json.length > 0 ) {\n\n\t\t\tconst manager = new LoadingManager( onLoad );\n\n\t\t\tloader = new ImageLoader( manager );\n\t\t\tloader.setCrossOrigin( this.crossOrigin );\n\n\t\t\tfor ( let i = 0, il = json.length; i < il; i ++ ) {\n\n\t\t\t\tconst image = json[ i ];\n\t\t\t\tconst url = image.url;\n\n\t\t\t\tif ( Array.isArray( url ) ) {\n\n\t\t\t\t\t// load array of images e.g CubeTexture\n\n\t\t\t\t\tconst imageArray = [];\n\n\t\t\t\t\tfor ( let j = 0, jl = url.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tconst currentUrl = url[ j ];\n\n\t\t\t\t\t\tconst deserializedImage = deserializeImage( currentUrl );\n\n\t\t\t\t\t\tif ( deserializedImage !== null ) {\n\n\t\t\t\t\t\t\tif ( deserializedImage instanceof HTMLImageElement ) {\n\n\t\t\t\t\t\t\t\timageArray.push( deserializedImage );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// special case: handle array of data textures for cube textures\n\n\t\t\t\t\t\t\t\timageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\timages[ image.uuid ] = new Source( imageArray );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// load single image\n\n\t\t\t\t\tconst deserializedImage = deserializeImage( image.url );\n\t\t\t\t\timages[ image.uuid ] = new Source( deserializedImage );\n\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn images;\n\n\t}\n\n\tasync parseImagesAsync( json ) {\n\n\t\tconst scope = this;\n\t\tconst images = {};\n\n\t\tlet loader;\n\n\t\tasync function deserializeImage( image ) {\n\n\t\t\tif ( typeof image === 'string' ) {\n\n\t\t\t\tconst url = image;\n\n\t\t\t\tconst path = /^(\\/\\/)|([a-z]+:(\\/\\/)?)/i.test( url ) ? url : scope.resourcePath + url;\n\n\t\t\t\treturn await loader.loadAsync( path );\n\n\t\t\t} else {\n\n\t\t\t\tif ( image.data ) {\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdata: getTypedArray( image.type, image.data ),\n\t\t\t\t\t\twidth: image.width,\n\t\t\t\t\t\theight: image.height\n\t\t\t\t\t};\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( json !== undefined && json.length > 0 ) {\n\n\t\t\tloader = new ImageLoader( this.manager );\n\t\t\tloader.setCrossOrigin( this.crossOrigin );\n\n\t\t\tfor ( let i = 0, il = json.length; i < il; i ++ ) {\n\n\t\t\t\tconst image = json[ i ];\n\t\t\t\tconst url = image.url;\n\n\t\t\t\tif ( Array.isArray( url ) ) {\n\n\t\t\t\t\t// load array of images e.g CubeTexture\n\n\t\t\t\t\tconst imageArray = [];\n\n\t\t\t\t\tfor ( let j = 0, jl = url.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tconst currentUrl = url[ j ];\n\n\t\t\t\t\t\tconst deserializedImage = await deserializeImage( currentUrl );\n\n\t\t\t\t\t\tif ( deserializedImage !== null ) {\n\n\t\t\t\t\t\t\tif ( deserializedImage instanceof HTMLImageElement ) {\n\n\t\t\t\t\t\t\t\timageArray.push( deserializedImage );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// special case: handle array of data textures for cube textures\n\n\t\t\t\t\t\t\t\timageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\timages[ image.uuid ] = new Source( imageArray );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// load single image\n\n\t\t\t\t\tconst deserializedImage = await deserializeImage( image.url );\n\t\t\t\t\timages[ image.uuid ] = new Source( deserializedImage );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn images;\n\n\t}\n\n\tparseTextures( json, images ) {\n\n\t\tfunction parseConstant( value, type ) {\n\n\t\t\tif ( typeof value === 'number' ) return value;\n\n\t\t\tconsole.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );\n\n\t\t\treturn type[ value ];\n\n\t\t}\n\n\t\tconst textures = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tfor ( let i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tconst data = json[ i ];\n\n\t\t\t\tif ( data.image === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: No \"image\" specified for', data.uuid );\n\n\t\t\t\t}\n\n\t\t\t\tif ( images[ data.image ] === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined image', data.image );\n\n\t\t\t\t}\n\n\t\t\t\tconst source = images[ data.image ];\n\t\t\t\tconst image = source.data;\n\n\t\t\t\tlet texture;\n\n\t\t\t\tif ( Array.isArray( image ) ) {\n\n\t\t\t\t\ttexture = new CubeTexture();\n\n\t\t\t\t\tif ( image.length === 6 ) texture.needsUpdate = true;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( image && image.data ) {\n\n\t\t\t\t\t\ttexture = new DataTexture();\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ttexture = new Texture();\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( image ) texture.needsUpdate = true; // textures can have undefined image data\n\n\t\t\t\t}\n\n\t\t\t\ttexture.source = source;\n\n\t\t\t\ttexture.uuid = data.uuid;\n\n\t\t\t\tif ( data.name !== undefined ) texture.name = data.name;\n\n\t\t\t\tif ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );\n\t\t\t\tif ( data.channel !== undefined ) texture.channel = data.channel;\n\n\t\t\t\tif ( data.offset !== undefined ) texture.offset.fromArray( data.offset );\n\t\t\t\tif ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );\n\t\t\t\tif ( data.center !== undefined ) texture.center.fromArray( data.center );\n\t\t\t\tif ( data.rotation !== undefined ) texture.rotation = data.rotation;\n\n\t\t\t\tif ( data.wrap !== undefined ) {\n\n\t\t\t\t\ttexture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );\n\t\t\t\t\ttexture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.format !== undefined ) texture.format = data.format;\n\t\t\t\tif ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat;\n\t\t\t\tif ( data.type !== undefined ) texture.type = data.type;\n\t\t\t\tif ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace;\n\n\t\t\t\tif ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER );\n\t\t\t\tif ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );\n\t\t\t\tif ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;\n\n\t\t\t\tif ( data.flipY !== undefined ) texture.flipY = data.flipY;\n\n\t\t\t\tif ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps;\n\t\t\t\tif ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha;\n\t\t\t\tif ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment;\n\t\t\t\tif ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction;\n\n\t\t\t\tif ( data.userData !== undefined ) texture.userData = data.userData;\n\n\t\t\t\ttextures[ data.uuid ] = texture;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn textures;\n\n\t}\n\n\tparseObject( data, geometries, materials, textures, animations ) {\n\n\t\tlet object;\n\n\t\tfunction getGeometry( name ) {\n\n\t\t\tif ( geometries[ name ] === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined geometry', name );\n\n\t\t\t}\n\n\t\t\treturn geometries[ name ];\n\n\t\t}\n\n\t\tfunction getMaterial( name ) {\n\n\t\t\tif ( name === undefined ) return undefined;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\n\t\t\t\tconst array = [];\n\n\t\t\t\tfor ( let i = 0, l = name.length; i < l; i ++ ) {\n\n\t\t\t\t\tconst uuid = name[ i ];\n\n\t\t\t\t\tif ( materials[ uuid ] === undefined ) {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined material', uuid );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tarray.push( materials[ uuid ] );\n\n\t\t\t\t}\n\n\t\t\t\treturn array;\n\n\t\t\t}\n\n\t\t\tif ( materials[ name ] === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined material', name );\n\n\t\t\t}\n\n\t\t\treturn materials[ name ];\n\n\t\t}\n\n\t\tfunction getTexture( uuid ) {\n\n\t\t\tif ( textures[ uuid ] === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined texture', uuid );\n\n\t\t\t}\n\n\t\t\treturn textures[ uuid ];\n\n\t\t}\n\n\t\tlet geometry, material;\n\n\t\tswitch ( data.type ) {\n\n\t\t\tcase 'Scene':\n\n\t\t\t\tobject = new Scene();\n\n\t\t\t\tif ( data.background !== undefined ) {\n\n\t\t\t\t\tif ( Number.isInteger( data.background ) ) {\n\n\t\t\t\t\t\tobject.background = new Color( data.background );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tobject.background = getTexture( data.background );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.environment !== undefined ) {\n\n\t\t\t\t\tobject.environment = getTexture( data.environment );\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.fog !== undefined ) {\n\n\t\t\t\t\tif ( data.fog.type === 'Fog' ) {\n\n\t\t\t\t\t\tobject.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );\n\n\t\t\t\t\t} else if ( data.fog.type === 'FogExp2' ) {\n\n\t\t\t\t\t\tobject.fog = new FogExp2( data.fog.color, data.fog.density );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( data.fog.name !== '' ) {\n\n\t\t\t\t\t\tobject.fog.name = data.fog.name;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness;\n\t\t\t\tif ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity;\n\t\t\t\tif ( data.backgroundRotation !== undefined ) object.backgroundRotation.fromArray( data.backgroundRotation );\n\n\t\t\t\tif ( data.environmentIntensity !== undefined ) object.environmentIntensity = data.environmentIntensity;\n\t\t\t\tif ( data.environmentRotation !== undefined ) object.environmentRotation.fromArray( data.environmentRotation );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'PerspectiveCamera':\n\n\t\t\t\tobject = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );\n\n\t\t\t\tif ( data.focus !== undefined ) object.focus = data.focus;\n\t\t\t\tif ( data.zoom !== undefined ) object.zoom = data.zoom;\n\t\t\t\tif ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;\n\t\t\t\tif ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;\n\t\t\t\tif ( data.view !== undefined ) object.view = Object.assign( {}, data.view );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'OrthographicCamera':\n\n\t\t\t\tobject = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );\n\n\t\t\t\tif ( data.zoom !== undefined ) object.zoom = data.zoom;\n\t\t\t\tif ( data.view !== undefined ) object.view = Object.assign( {}, data.view );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'AmbientLight':\n\n\t\t\t\tobject = new AmbientLight( data.color, data.intensity );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'DirectionalLight':\n\n\t\t\t\tobject = new DirectionalLight( data.color, data.intensity );\n\t\t\t\tobject.target = data.target || '';\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'PointLight':\n\n\t\t\t\tobject = new PointLight( data.color, data.intensity, data.distance, data.decay );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'RectAreaLight':\n\n\t\t\t\tobject = new RectAreaLight( data.color, data.intensity, data.width, data.height );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'SpotLight':\n\n\t\t\t\tobject = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );\n\t\t\t\tobject.target = data.target || '';\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'HemisphereLight':\n\n\t\t\t\tobject = new HemisphereLight( data.color, data.groundColor, data.intensity );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'LightProbe':\n\n\t\t\t\tobject = new LightProbe().fromJSON( data );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'SkinnedMesh':\n\n\t\t\t\tgeometry = getGeometry( data.geometry );\n\t\t\t \tmaterial = getMaterial( data.material );\n\n\t\t\t\tobject = new SkinnedMesh( geometry, material );\n\n\t\t\t\tif ( data.bindMode !== undefined ) object.bindMode = data.bindMode;\n\t\t\t\tif ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix );\n\t\t\t\tif ( data.skeleton !== undefined ) object.skeleton = data.skeleton;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'Mesh':\n\n\t\t\t\tgeometry = getGeometry( data.geometry );\n\t\t\t\tmaterial = getMaterial( data.material );\n\n\t\t\t\tobject = new Mesh( geometry, material );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'InstancedMesh':\n\n\t\t\t\tgeometry = getGeometry( data.geometry );\n\t\t\t\tmaterial = getMaterial( data.material );\n\t\t\t\tconst count = data.count;\n\t\t\t\tconst instanceMatrix = data.instanceMatrix;\n\t\t\t\tconst instanceColor = data.instanceColor;\n\n\t\t\t\tobject = new InstancedMesh( geometry, material, count );\n\t\t\t\tobject.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 );\n\t\t\t\tif ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'BatchedMesh':\n\n\t\t\t\tgeometry = getGeometry( data.geometry );\n\t\t\t\tmaterial = getMaterial( data.material );\n\n\t\t\t\tobject = new BatchedMesh( data.maxInstanceCount, data.maxVertexCount, data.maxIndexCount, material );\n\t\t\t\tobject.geometry = geometry;\n\t\t\t\tobject.perObjectFrustumCulled = data.perObjectFrustumCulled;\n\t\t\t\tobject.sortObjects = data.sortObjects;\n\n\t\t\t\tobject._drawRanges = data.drawRanges;\n\t\t\t\tobject._reservedRanges = data.reservedRanges;\n\n\t\t\t\tobject._visibility = data.visibility;\n\t\t\t\tobject._active = data.active;\n\t\t\t\tobject._bounds = data.bounds.map( bound => {\n\n\t\t\t\t\tconst box = new Box3();\n\t\t\t\t\tbox.min.fromArray( bound.boxMin );\n\t\t\t\t\tbox.max.fromArray( bound.boxMax );\n\n\t\t\t\t\tconst sphere = new Sphere();\n\t\t\t\t\tsphere.radius = bound.sphereRadius;\n\t\t\t\t\tsphere.center.fromArray( bound.sphereCenter );\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tboxInitialized: bound.boxInitialized,\n\t\t\t\t\t\tbox: box,\n\n\t\t\t\t\t\tsphereInitialized: bound.sphereInitialized,\n\t\t\t\t\t\tsphere: sphere\n\t\t\t\t\t};\n\n\t\t\t\t} );\n\n\t\t\t\tobject._maxInstanceCount = data.maxInstanceCount;\n\t\t\t\tobject._maxVertexCount = data.maxVertexCount;\n\t\t\t\tobject._maxIndexCount = data.maxIndexCount;\n\n\t\t\t\tobject._geometryInitialized = data.geometryInitialized;\n\t\t\t\tobject._geometryCount = data.geometryCount;\n\n\t\t\t\tobject._matricesTexture = getTexture( data.matricesTexture.uuid );\n\t\t\t\tif ( data.colorsTexture !== undefined ) object._colorsTexture = getTexture( data.colorsTexture.uuid );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'LOD':\n\n\t\t\t\tobject = new LOD();\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'Line':\n\n\t\t\t\tobject = new Line( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'LineLoop':\n\n\t\t\t\tobject = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'LineSegments':\n\n\t\t\t\tobject = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'PointCloud':\n\t\t\tcase 'Points':\n\n\t\t\t\tobject = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'Sprite':\n\n\t\t\t\tobject = new Sprite( getMaterial( data.material ) );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'Group':\n\n\t\t\t\tobject = new Group();\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'Bone':\n\n\t\t\t\tobject = new Bone();\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\n\t\t\t\tobject = new Object3D();\n\n\t\t}\n\n\t\tobject.uuid = data.uuid;\n\n\t\tif ( data.name !== undefined ) object.name = data.name;\n\n\t\tif ( data.matrix !== undefined ) {\n\n\t\t\tobject.matrix.fromArray( data.matrix );\n\n\t\t\tif ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate;\n\t\t\tif ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale );\n\n\t\t} else {\n\n\t\t\tif ( data.position !== undefined ) object.position.fromArray( data.position );\n\t\t\tif ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );\n\t\t\tif ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );\n\t\t\tif ( data.scale !== undefined ) object.scale.fromArray( data.scale );\n\n\t\t}\n\n\t\tif ( data.up !== undefined ) object.up.fromArray( data.up );\n\n\t\tif ( data.castShadow !== undefined ) object.castShadow = data.castShadow;\n\t\tif ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;\n\n\t\tif ( data.shadow ) {\n\n\t\t\tif ( data.shadow.intensity !== undefined ) object.shadow.intensity = data.shadow.intensity;\n\t\t\tif ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;\n\t\t\tif ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias;\n\t\t\tif ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;\n\t\t\tif ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );\n\t\t\tif ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );\n\n\t\t}\n\n\t\tif ( data.visible !== undefined ) object.visible = data.visible;\n\t\tif ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled;\n\t\tif ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder;\n\t\tif ( data.userData !== undefined ) object.userData = data.userData;\n\t\tif ( data.layers !== undefined ) object.layers.mask = data.layers;\n\n\t\tif ( data.children !== undefined ) {\n\n\t\t\tconst children = data.children;\n\n\t\t\tfor ( let i = 0; i < children.length; i ++ ) {\n\n\t\t\t\tobject.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( data.animations !== undefined ) {\n\n\t\t\tconst objectAnimations = data.animations;\n\n\t\t\tfor ( let i = 0; i < objectAnimations.length; i ++ ) {\n\n\t\t\t\tconst uuid = objectAnimations[ i ];\n\n\t\t\t\tobject.animations.push( animations[ uuid ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( data.type === 'LOD' ) {\n\n\t\t\tif ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate;\n\n\t\t\tconst levels = data.levels;\n\n\t\t\tfor ( let l = 0; l < levels.length; l ++ ) {\n\n\t\t\t\tconst level = levels[ l ];\n\t\t\t\tconst child = object.getObjectByProperty( 'uuid', level.object );\n\n\t\t\t\tif ( child !== undefined ) {\n\n\t\t\t\t\tobject.addLevel( child, level.distance, level.hysteresis );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn object;\n\n\t}\n\n\tbindSkeletons( object, skeletons ) {\n\n\t\tif ( Object.keys( skeletons ).length === 0 ) return;\n\n\t\tobject.traverse( function ( child ) {\n\n\t\t\tif ( child.isSkinnedMesh === true && child.skeleton !== undefined ) {\n\n\t\t\t\tconst skeleton = skeletons[ child.skeleton ];\n\n\t\t\t\tif ( skeleton === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tchild.bind( skeleton, child.bindMatrix );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} );\n\n\t}\n\n\tbindLightTargets( object ) {\n\n\t\tobject.traverse( function ( child ) {\n\n\t\t\tif ( child.isDirectionalLight || child.isSpotLight ) {\n\n\t\t\t\tconst uuid = child.target;\n\n\t\t\t\tconst target = object.getObjectByProperty( 'uuid', uuid );\n\n\t\t\t\tif ( target !== undefined ) {\n\n\t\t\t\t\tchild.target = target;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tchild.target = new Object3D();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} );\n\n\t}\n\n}\n\nconst TEXTURE_MAPPING = {\n\tUVMapping: UVMapping,\n\tCubeReflectionMapping: CubeReflectionMapping,\n\tCubeRefractionMapping: CubeRefractionMapping,\n\tEquirectangularReflectionMapping: EquirectangularReflectionMapping,\n\tEquirectangularRefractionMapping: EquirectangularRefractionMapping,\n\tCubeUVReflectionMapping: CubeUVReflectionMapping\n};\n\nconst TEXTURE_WRAPPING = {\n\tRepeatWrapping: RepeatWrapping,\n\tClampToEdgeWrapping: ClampToEdgeWrapping,\n\tMirroredRepeatWrapping: MirroredRepeatWrapping\n};\n\nconst TEXTURE_FILTER = {\n\tNearestFilter: NearestFilter,\n\tNearestMipmapNearestFilter: NearestMipmapNearestFilter,\n\tNearestMipmapLinearFilter: NearestMipmapLinearFilter,\n\tLinearFilter: LinearFilter,\n\tLinearMipmapNearestFilter: LinearMipmapNearestFilter,\n\tLinearMipmapLinearFilter: LinearMipmapLinearFilter\n};\n\nclass ImageBitmapLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t\tthis.isImageBitmapLoader = true;\n\n\t\tif ( typeof createImageBitmap === 'undefined' ) {\n\n\t\t\tconsole.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' );\n\n\t\t}\n\n\t\tif ( typeof fetch === 'undefined' ) {\n\n\t\t\tconsole.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' );\n\n\t\t}\n\n\t\tthis.options = { premultiplyAlpha: 'none' };\n\n\t}\n\n\tsetOptions( options ) {\n\n\t\tthis.options = options;\n\n\t\treturn this;\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tif ( url === undefined ) url = '';\n\n\t\tif ( this.path !== undefined ) url = this.path + url;\n\n\t\turl = this.manager.resolveURL( url );\n\n\t\tconst scope = this;\n\n\t\tconst cached = Cache.get( url );\n\n\t\tif ( cached !== undefined ) {\n\n\t\t\tscope.manager.itemStart( url );\n\n\t\t\t// If cached is a promise, wait for it to resolve\n\t\t\tif ( cached.then ) {\n\n\t\t\t\tcached.then( imageBitmap => {\n\n\t\t\t\t\tif ( onLoad ) onLoad( imageBitmap );\n\n\t\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t\t} ).catch( e => {\n\n\t\t\t\t\tif ( onError ) onError( e );\n\n\t\t\t\t} );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\t// If cached is not a promise (i.e., it's already an imageBitmap)\n\t\t\tsetTimeout( function () {\n\n\t\t\t\tif ( onLoad ) onLoad( cached );\n\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t}, 0 );\n\n\t\t\treturn cached;\n\n\t\t}\n\n\t\tconst fetchOptions = {};\n\t\tfetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include';\n\t\tfetchOptions.headers = this.requestHeader;\n\n\t\tconst promise = fetch( url, fetchOptions ).then( function ( res ) {\n\n\t\t\treturn res.blob();\n\n\t\t} ).then( function ( blob ) {\n\n\t\t\treturn createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) );\n\n\t\t} ).then( function ( imageBitmap ) {\n\n\t\t\tCache.add( url, imageBitmap );\n\n\t\t\tif ( onLoad ) onLoad( imageBitmap );\n\n\t\t\tscope.manager.itemEnd( url );\n\n\t\t\treturn imageBitmap;\n\n\t\t} ).catch( function ( e ) {\n\n\t\t\tif ( onError ) onError( e );\n\n\t\t\tCache.remove( url );\n\n\t\t\tscope.manager.itemError( url );\n\t\t\tscope.manager.itemEnd( url );\n\n\t\t} );\n\n\t\tCache.add( url, promise );\n\t\tscope.manager.itemStart( url );\n\n\t}\n\n}\n\nlet _context;\n\nclass AudioContext {\n\n\tstatic getContext() {\n\n\t\tif ( _context === undefined ) {\n\n\t\t\t_context = new ( window.AudioContext || window.webkitAudioContext )();\n\n\t\t}\n\n\t\treturn _context;\n\n\t}\n\n\tstatic setContext( value ) {\n\n\t\t_context = value;\n\n\t}\n\n}\n\nclass AudioLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setResponseType( 'arraybuffer' );\n\t\tloader.setPath( this.path );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setWithCredentials( this.withCredentials );\n\t\tloader.load( url, function ( buffer ) {\n\n\t\t\ttry {\n\n\t\t\t\t// Create a copy of the buffer. The `decodeAudioData` method\n\t\t\t\t// detaches the buffer when complete, preventing reuse.\n\t\t\t\tconst bufferCopy = buffer.slice( 0 );\n\n\t\t\t\tconst context = AudioContext.getContext();\n\t\t\t\tcontext.decodeAudioData( bufferCopy, function ( audioBuffer ) {\n\n\t\t\t\t\tonLoad( audioBuffer );\n\n\t\t\t\t} ).catch( handleError );\n\n\t\t\t} catch ( e ) {\n\n\t\t\t\thandleError( e );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t\tfunction handleError( e ) {\n\n\t\t\tif ( onError ) {\n\n\t\t\t\tonError( e );\n\n\t\t\t} else {\n\n\t\t\t\tconsole.error( e );\n\n\t\t\t}\n\n\t\t\tscope.manager.itemError( url );\n\n\t\t}\n\n\t}\n\n}\n\nconst _eyeRight = /*@__PURE__*/ new Matrix4();\nconst _eyeLeft = /*@__PURE__*/ new Matrix4();\nconst _projectionMatrix = /*@__PURE__*/ new Matrix4();\n\nclass StereoCamera {\n\n\tconstructor() {\n\n\t\tthis.type = 'StereoCamera';\n\n\t\tthis.aspect = 1;\n\n\t\tthis.eyeSep = 0.064;\n\n\t\tthis.cameraL = new PerspectiveCamera();\n\t\tthis.cameraL.layers.enable( 1 );\n\t\tthis.cameraL.matrixAutoUpdate = false;\n\n\t\tthis.cameraR = new PerspectiveCamera();\n\t\tthis.cameraR.layers.enable( 2 );\n\t\tthis.cameraR.matrixAutoUpdate = false;\n\n\t\tthis._cache = {\n\t\t\tfocus: null,\n\t\t\tfov: null,\n\t\t\taspect: null,\n\t\t\tnear: null,\n\t\t\tfar: null,\n\t\t\tzoom: null,\n\t\t\teyeSep: null\n\t\t};\n\n\t}\n\n\tupdate( camera ) {\n\n\t\tconst cache = this._cache;\n\n\t\tconst needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov ||\n\t\t\tcache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near ||\n\t\t\tcache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep;\n\n\t\tif ( needsUpdate ) {\n\n\t\t\tcache.focus = camera.focus;\n\t\t\tcache.fov = camera.fov;\n\t\t\tcache.aspect = camera.aspect * this.aspect;\n\t\t\tcache.near = camera.near;\n\t\t\tcache.far = camera.far;\n\t\t\tcache.zoom = camera.zoom;\n\t\t\tcache.eyeSep = this.eyeSep;\n\n\t\t\t// Off-axis stereoscopic effect based on\n\t\t\t// http://paulbourke.net/stereographics/stereorender/\n\n\t\t\t_projectionMatrix.copy( camera.projectionMatrix );\n\t\t\tconst eyeSepHalf = cache.eyeSep / 2;\n\t\t\tconst eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus;\n\t\t\tconst ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom;\n\t\t\tlet xmin, xmax;\n\n\t\t\t// translate xOffset\n\n\t\t\t_eyeLeft.elements[ 12 ] = - eyeSepHalf;\n\t\t\t_eyeRight.elements[ 12 ] = eyeSepHalf;\n\n\t\t\t// for left eye\n\n\t\t\txmin = - ymax * cache.aspect + eyeSepOnProjection;\n\t\t\txmax = ymax * cache.aspect + eyeSepOnProjection;\n\n\t\t\t_projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );\n\t\t\t_projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );\n\n\t\t\tthis.cameraL.projectionMatrix.copy( _projectionMatrix );\n\n\t\t\t// for right eye\n\n\t\t\txmin = - ymax * cache.aspect - eyeSepOnProjection;\n\t\t\txmax = ymax * cache.aspect - eyeSepOnProjection;\n\n\t\t\t_projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );\n\t\t\t_projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );\n\n\t\t\tthis.cameraR.projectionMatrix.copy( _projectionMatrix );\n\n\t\t}\n\n\t\tthis.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft );\n\t\tthis.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight );\n\n\t}\n\n}\n\nclass Clock {\n\n\tconstructor( autoStart = true ) {\n\n\t\tthis.autoStart = autoStart;\n\n\t\tthis.startTime = 0;\n\t\tthis.oldTime = 0;\n\t\tthis.elapsedTime = 0;\n\n\t\tthis.running = false;\n\n\t}\n\n\tstart() {\n\n\t\tthis.startTime = now();\n\n\t\tthis.oldTime = this.startTime;\n\t\tthis.elapsedTime = 0;\n\t\tthis.running = true;\n\n\t}\n\n\tstop() {\n\n\t\tthis.getElapsedTime();\n\t\tthis.running = false;\n\t\tthis.autoStart = false;\n\n\t}\n\n\tgetElapsedTime() {\n\n\t\tthis.getDelta();\n\t\treturn this.elapsedTime;\n\n\t}\n\n\tgetDelta() {\n\n\t\tlet diff = 0;\n\n\t\tif ( this.autoStart && ! this.running ) {\n\n\t\t\tthis.start();\n\t\t\treturn 0;\n\n\t\t}\n\n\t\tif ( this.running ) {\n\n\t\t\tconst newTime = now();\n\n\t\t\tdiff = ( newTime - this.oldTime ) / 1000;\n\t\t\tthis.oldTime = newTime;\n\n\t\t\tthis.elapsedTime += diff;\n\n\t\t}\n\n\t\treturn diff;\n\n\t}\n\n}\n\nfunction now() {\n\n\treturn ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732\n\n}\n\nconst _position$1 = /*@__PURE__*/ new Vector3();\nconst _quaternion$1 = /*@__PURE__*/ new Quaternion();\nconst _scale$1 = /*@__PURE__*/ new Vector3();\nconst _orientation$1 = /*@__PURE__*/ new Vector3();\n\nclass AudioListener extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.type = 'AudioListener';\n\n\t\tthis.context = AudioContext.getContext();\n\n\t\tthis.gain = this.context.createGain();\n\t\tthis.gain.connect( this.context.destination );\n\n\t\tthis.filter = null;\n\n\t\tthis.timeDelta = 0;\n\n\t\t// private\n\n\t\tthis._clock = new Clock();\n\n\t}\n\n\tgetInput() {\n\n\t\treturn this.gain;\n\n\t}\n\n\tremoveFilter() {\n\n\t\tif ( this.filter !== null ) {\n\n\t\t\tthis.gain.disconnect( this.filter );\n\t\t\tthis.filter.disconnect( this.context.destination );\n\t\t\tthis.gain.connect( this.context.destination );\n\t\t\tthis.filter = null;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetFilter() {\n\n\t\treturn this.filter;\n\n\t}\n\n\tsetFilter( value ) {\n\n\t\tif ( this.filter !== null ) {\n\n\t\t\tthis.gain.disconnect( this.filter );\n\t\t\tthis.filter.disconnect( this.context.destination );\n\n\t\t} else {\n\n\t\t\tthis.gain.disconnect( this.context.destination );\n\n\t\t}\n\n\t\tthis.filter = value;\n\t\tthis.gain.connect( this.filter );\n\t\tthis.filter.connect( this.context.destination );\n\n\t\treturn this;\n\n\t}\n\n\tgetMasterVolume() {\n\n\t\treturn this.gain.gain.value;\n\n\t}\n\n\tsetMasterVolume( value ) {\n\n\t\tthis.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );\n\n\t\treturn this;\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t\tconst listener = this.context.listener;\n\t\tconst up = this.up;\n\n\t\tthis.timeDelta = this._clock.getDelta();\n\n\t\tthis.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 );\n\n\t\t_orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 );\n\n\t\tif ( listener.positionX ) {\n\n\t\t\t// code path for Chrome (see #14393)\n\n\t\t\tconst endTime = this.context.currentTime + this.timeDelta;\n\n\t\t\tlistener.positionX.linearRampToValueAtTime( _position$1.x, endTime );\n\t\t\tlistener.positionY.linearRampToValueAtTime( _position$1.y, endTime );\n\t\t\tlistener.positionZ.linearRampToValueAtTime( _position$1.z, endTime );\n\t\t\tlistener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime );\n\t\t\tlistener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime );\n\t\t\tlistener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime );\n\t\t\tlistener.upX.linearRampToValueAtTime( up.x, endTime );\n\t\t\tlistener.upY.linearRampToValueAtTime( up.y, endTime );\n\t\t\tlistener.upZ.linearRampToValueAtTime( up.z, endTime );\n\n\t\t} else {\n\n\t\t\tlistener.setPosition( _position$1.x, _position$1.y, _position$1.z );\n\t\t\tlistener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z );\n\n\t\t}\n\n\t}\n\n}\n\nclass Audio extends Object3D {\n\n\tconstructor( listener ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'Audio';\n\n\t\tthis.listener = listener;\n\t\tthis.context = listener.context;\n\n\t\tthis.gain = this.context.createGain();\n\t\tthis.gain.connect( listener.getInput() );\n\n\t\tthis.autoplay = false;\n\n\t\tthis.buffer = null;\n\t\tthis.detune = 0;\n\t\tthis.loop = false;\n\t\tthis.loopStart = 0;\n\t\tthis.loopEnd = 0;\n\t\tthis.offset = 0;\n\t\tthis.duration = undefined;\n\t\tthis.playbackRate = 1;\n\t\tthis.isPlaying = false;\n\t\tthis.hasPlaybackControl = true;\n\t\tthis.source = null;\n\t\tthis.sourceType = 'empty';\n\n\t\tthis._startedAt = 0;\n\t\tthis._progress = 0;\n\t\tthis._connected = false;\n\n\t\tthis.filters = [];\n\n\t}\n\n\tgetOutput() {\n\n\t\treturn this.gain;\n\n\t}\n\n\tsetNodeSource( audioNode ) {\n\n\t\tthis.hasPlaybackControl = false;\n\t\tthis.sourceType = 'audioNode';\n\t\tthis.source = audioNode;\n\t\tthis.connect();\n\n\t\treturn this;\n\n\t}\n\n\tsetMediaElementSource( mediaElement ) {\n\n\t\tthis.hasPlaybackControl = false;\n\t\tthis.sourceType = 'mediaNode';\n\t\tthis.source = this.context.createMediaElementSource( mediaElement );\n\t\tthis.connect();\n\n\t\treturn this;\n\n\t}\n\n\tsetMediaStreamSource( mediaStream ) {\n\n\t\tthis.hasPlaybackControl = false;\n\t\tthis.sourceType = 'mediaStreamNode';\n\t\tthis.source = this.context.createMediaStreamSource( mediaStream );\n\t\tthis.connect();\n\n\t\treturn this;\n\n\t}\n\n\tsetBuffer( audioBuffer ) {\n\n\t\tthis.buffer = audioBuffer;\n\t\tthis.sourceType = 'buffer';\n\n\t\tif ( this.autoplay ) this.play();\n\n\t\treturn this;\n\n\t}\n\n\tplay( delay = 0 ) {\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: Audio is already playing.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis._startedAt = this.context.currentTime + delay;\n\n\t\tconst source = this.context.createBufferSource();\n\t\tsource.buffer = this.buffer;\n\t\tsource.loop = this.loop;\n\t\tsource.loopStart = this.loopStart;\n\t\tsource.loopEnd = this.loopEnd;\n\t\tsource.onended = this.onEnded.bind( this );\n\t\tsource.start( this._startedAt, this._progress + this.offset, this.duration );\n\n\t\tthis.isPlaying = true;\n\n\t\tthis.source = source;\n\n\t\tthis.setDetune( this.detune );\n\t\tthis.setPlaybackRate( this.playbackRate );\n\n\t\treturn this.connect();\n\n\t}\n\n\tpause() {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\t// update current progress\n\n\t\t\tthis._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate;\n\n\t\t\tif ( this.loop === true ) {\n\n\t\t\t\t// ensure _progress does not exceed duration with looped audios\n\n\t\t\t\tthis._progress = this._progress % ( this.duration || this.buffer.duration );\n\n\t\t\t}\n\n\t\t\tthis.source.stop();\n\t\t\tthis.source.onended = null;\n\n\t\t\tthis.isPlaying = false;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tstop() {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis._progress = 0;\n\n\t\tif ( this.source !== null ) {\n\n\t\t\tthis.source.stop();\n\t\t\tthis.source.onended = null;\n\n\t\t}\n\n\t\tthis.isPlaying = false;\n\n\t\treturn this;\n\n\t}\n\n\tconnect() {\n\n\t\tif ( this.filters.length > 0 ) {\n\n\t\t\tthis.source.connect( this.filters[ 0 ] );\n\n\t\t\tfor ( let i = 1, l = this.filters.length; i < l; i ++ ) {\n\n\t\t\t\tthis.filters[ i - 1 ].connect( this.filters[ i ] );\n\n\t\t\t}\n\n\t\t\tthis.filters[ this.filters.length - 1 ].connect( this.getOutput() );\n\n\t\t} else {\n\n\t\t\tthis.source.connect( this.getOutput() );\n\n\t\t}\n\n\t\tthis._connected = true;\n\n\t\treturn this;\n\n\t}\n\n\tdisconnect() {\n\n\t\tif ( this._connected === false ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( this.filters.length > 0 ) {\n\n\t\t\tthis.source.disconnect( this.filters[ 0 ] );\n\n\t\t\tfor ( let i = 1, l = this.filters.length; i < l; i ++ ) {\n\n\t\t\t\tthis.filters[ i - 1 ].disconnect( this.filters[ i ] );\n\n\t\t\t}\n\n\t\t\tthis.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );\n\n\t\t} else {\n\n\t\t\tthis.source.disconnect( this.getOutput() );\n\n\t\t}\n\n\t\tthis._connected = false;\n\n\t\treturn this;\n\n\t}\n\n\tgetFilters() {\n\n\t\treturn this.filters;\n\n\t}\n\n\tsetFilters( value ) {\n\n\t\tif ( ! value ) value = [];\n\n\t\tif ( this._connected === true ) {\n\n\t\t\tthis.disconnect();\n\t\t\tthis.filters = value.slice();\n\t\t\tthis.connect();\n\n\t\t} else {\n\n\t\t\tthis.filters = value.slice();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetDetune( value ) {\n\n\t\tthis.detune = value;\n\n\t\tif ( this.isPlaying === true && this.source.detune !== undefined ) {\n\n\t\t\tthis.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetDetune() {\n\n\t\treturn this.detune;\n\n\t}\n\n\tgetFilter() {\n\n\t\treturn this.getFilters()[ 0 ];\n\n\t}\n\n\tsetFilter( filter ) {\n\n\t\treturn this.setFilters( filter ? [ filter ] : [] );\n\n\t}\n\n\tsetPlaybackRate( value ) {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.playbackRate = value;\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\tthis.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetPlaybackRate() {\n\n\t\treturn this.playbackRate;\n\n\t}\n\n\tonEnded() {\n\n\t\tthis.isPlaying = false;\n\n\t}\n\n\tgetLoop() {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn false;\n\n\t\t}\n\n\t\treturn this.loop;\n\n\t}\n\n\tsetLoop( value ) {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.loop = value;\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\tthis.source.loop = this.loop;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetLoopStart( value ) {\n\n\t\tthis.loopStart = value;\n\n\t\treturn this;\n\n\t}\n\n\tsetLoopEnd( value ) {\n\n\t\tthis.loopEnd = value;\n\n\t\treturn this;\n\n\t}\n\n\tgetVolume() {\n\n\t\treturn this.gain.gain.value;\n\n\t}\n\n\tsetVolume( value ) {\n\n\t\tthis.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _position = /*@__PURE__*/ new Vector3();\nconst _quaternion = /*@__PURE__*/ new Quaternion();\nconst _scale = /*@__PURE__*/ new Vector3();\nconst _orientation = /*@__PURE__*/ new Vector3();\n\nclass PositionalAudio extends Audio {\n\n\tconstructor( listener ) {\n\n\t\tsuper( listener );\n\n\t\tthis.panner = this.context.createPanner();\n\t\tthis.panner.panningModel = 'HRTF';\n\t\tthis.panner.connect( this.gain );\n\n\t}\n\n\tconnect() {\n\n\t\tsuper.connect();\n\n\t\tthis.panner.connect( this.gain );\n\n\t}\n\n\tdisconnect() {\n\n\t\tsuper.disconnect();\n\n\t\tthis.panner.disconnect( this.gain );\n\n\t}\n\n\tgetOutput() {\n\n\t\treturn this.panner;\n\n\t}\n\n\tgetRefDistance() {\n\n\t\treturn this.panner.refDistance;\n\n\t}\n\n\tsetRefDistance( value ) {\n\n\t\tthis.panner.refDistance = value;\n\n\t\treturn this;\n\n\t}\n\n\tgetRolloffFactor() {\n\n\t\treturn this.panner.rolloffFactor;\n\n\t}\n\n\tsetRolloffFactor( value ) {\n\n\t\tthis.panner.rolloffFactor = value;\n\n\t\treturn this;\n\n\t}\n\n\tgetDistanceModel() {\n\n\t\treturn this.panner.distanceModel;\n\n\t}\n\n\tsetDistanceModel( value ) {\n\n\t\tthis.panner.distanceModel = value;\n\n\t\treturn this;\n\n\t}\n\n\tgetMaxDistance() {\n\n\t\treturn this.panner.maxDistance;\n\n\t}\n\n\tsetMaxDistance( value ) {\n\n\t\tthis.panner.maxDistance = value;\n\n\t\treturn this;\n\n\t}\n\n\tsetDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) {\n\n\t\tthis.panner.coneInnerAngle = coneInnerAngle;\n\t\tthis.panner.coneOuterAngle = coneOuterAngle;\n\t\tthis.panner.coneOuterGain = coneOuterGain;\n\n\t\treturn this;\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t\tif ( this.hasPlaybackControl === true && this.isPlaying === false ) return;\n\n\t\tthis.matrixWorld.decompose( _position, _quaternion, _scale );\n\n\t\t_orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion );\n\n\t\tconst panner = this.panner;\n\n\t\tif ( panner.positionX ) {\n\n\t\t\t// code path for Chrome and Firefox (see #14393)\n\n\t\t\tconst endTime = this.context.currentTime + this.listener.timeDelta;\n\n\t\t\tpanner.positionX.linearRampToValueAtTime( _position.x, endTime );\n\t\t\tpanner.positionY.linearRampToValueAtTime( _position.y, endTime );\n\t\t\tpanner.positionZ.linearRampToValueAtTime( _position.z, endTime );\n\t\t\tpanner.orientationX.linearRampToValueAtTime( _orientation.x, endTime );\n\t\t\tpanner.orientationY.linearRampToValueAtTime( _orientation.y, endTime );\n\t\t\tpanner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime );\n\n\t\t} else {\n\n\t\t\tpanner.setPosition( _position.x, _position.y, _position.z );\n\t\t\tpanner.setOrientation( _orientation.x, _orientation.y, _orientation.z );\n\n\t\t}\n\n\t}\n\n}\n\nclass AudioAnalyser {\n\n\tconstructor( audio, fftSize = 2048 ) {\n\n\t\tthis.analyser = audio.context.createAnalyser();\n\t\tthis.analyser.fftSize = fftSize;\n\n\t\tthis.data = new Uint8Array( this.analyser.frequencyBinCount );\n\n\t\taudio.getOutput().connect( this.analyser );\n\n\t}\n\n\n\tgetFrequencyData() {\n\n\t\tthis.analyser.getByteFrequencyData( this.data );\n\n\t\treturn this.data;\n\n\t}\n\n\tgetAverageFrequency() {\n\n\t\tlet value = 0;\n\t\tconst data = this.getFrequencyData();\n\n\t\tfor ( let i = 0; i < data.length; i ++ ) {\n\n\t\t\tvalue += data[ i ];\n\n\t\t}\n\n\t\treturn value / data.length;\n\n\t}\n\n}\n\nclass PropertyMixer {\n\n\tconstructor( binding, typeName, valueSize ) {\n\n\t\tthis.binding = binding;\n\t\tthis.valueSize = valueSize;\n\n\t\tlet mixFunction,\n\t\t\tmixFunctionAdditive,\n\t\t\tsetIdentity;\n\n\t\t// buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ]\n\t\t//\n\t\t// interpolators can use .buffer as their .result\n\t\t// the data then goes to 'incoming'\n\t\t//\n\t\t// 'accu0' and 'accu1' are used frame-interleaved for\n\t\t// the cumulative result and are compared to detect\n\t\t// changes\n\t\t//\n\t\t// 'orig' stores the original state of the property\n\t\t//\n\t\t// 'add' is used for additive cumulative results\n\t\t//\n\t\t// 'work' is optional and is only present for quaternion types. It is used\n\t\t// to store intermediate quaternion multiplication results\n\n\t\tswitch ( typeName ) {\n\n\t\t\tcase 'quaternion':\n\t\t\t\tmixFunction = this._slerp;\n\t\t\t\tmixFunctionAdditive = this._slerpAdditive;\n\t\t\t\tsetIdentity = this._setAdditiveIdentityQuaternion;\n\n\t\t\t\tthis.buffer = new Float64Array( valueSize * 6 );\n\t\t\t\tthis._workIndex = 5;\n\t\t\t\tbreak;\n\n\t\t\tcase 'string':\n\t\t\tcase 'bool':\n\t\t\t\tmixFunction = this._select;\n\n\t\t\t\t// Use the regular mix function and for additive on these types,\n\t\t\t\t// additive is not relevant for non-numeric types\n\t\t\t\tmixFunctionAdditive = this._select;\n\n\t\t\t\tsetIdentity = this._setAdditiveIdentityOther;\n\n\t\t\t\tthis.buffer = new Array( valueSize * 5 );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tmixFunction = this._lerp;\n\t\t\t\tmixFunctionAdditive = this._lerpAdditive;\n\t\t\t\tsetIdentity = this._setAdditiveIdentityNumeric;\n\n\t\t\t\tthis.buffer = new Float64Array( valueSize * 5 );\n\n\t\t}\n\n\t\tthis._mixBufferRegion = mixFunction;\n\t\tthis._mixBufferRegionAdditive = mixFunctionAdditive;\n\t\tthis._setIdentity = setIdentity;\n\t\tthis._origIndex = 3;\n\t\tthis._addIndex = 4;\n\n\t\tthis.cumulativeWeight = 0;\n\t\tthis.cumulativeWeightAdditive = 0;\n\n\t\tthis.useCount = 0;\n\t\tthis.referenceCount = 0;\n\n\t}\n\n\t// accumulate data in the 'incoming' region into 'accu'\n\taccumulate( accuIndex, weight ) {\n\n\t\t// note: happily accumulating nothing when weight = 0, the caller knows\n\t\t// the weight and shouldn't have made the call in the first place\n\n\t\tconst buffer = this.buffer,\n\t\t\tstride = this.valueSize,\n\t\t\toffset = accuIndex * stride + stride;\n\n\t\tlet currentWeight = this.cumulativeWeight;\n\n\t\tif ( currentWeight === 0 ) {\n\n\t\t\t// accuN := incoming * weight\n\n\t\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\t\tbuffer[ offset + i ] = buffer[ i ];\n\n\t\t\t}\n\n\t\t\tcurrentWeight = weight;\n\n\t\t} else {\n\n\t\t\t// accuN := accuN + incoming * weight\n\n\t\t\tcurrentWeight += weight;\n\t\t\tconst mix = weight / currentWeight;\n\t\t\tthis._mixBufferRegion( buffer, offset, 0, mix, stride );\n\n\t\t}\n\n\t\tthis.cumulativeWeight = currentWeight;\n\n\t}\n\n\t// accumulate data in the 'incoming' region into 'add'\n\taccumulateAdditive( weight ) {\n\n\t\tconst buffer = this.buffer,\n\t\t\tstride = this.valueSize,\n\t\t\toffset = stride * this._addIndex;\n\n\t\tif ( this.cumulativeWeightAdditive === 0 ) {\n\n\t\t\t// add = identity\n\n\t\t\tthis._setIdentity();\n\n\t\t}\n\n\t\t// add := add + incoming * weight\n\n\t\tthis._mixBufferRegionAdditive( buffer, offset, 0, weight, stride );\n\t\tthis.cumulativeWeightAdditive += weight;\n\n\t}\n\n\t// apply the state of 'accu' to the binding when accus differ\n\tapply( accuIndex ) {\n\n\t\tconst stride = this.valueSize,\n\t\t\tbuffer = this.buffer,\n\t\t\toffset = accuIndex * stride + stride,\n\n\t\t\tweight = this.cumulativeWeight,\n\t\t\tweightAdditive = this.cumulativeWeightAdditive,\n\n\t\t\tbinding = this.binding;\n\n\t\tthis.cumulativeWeight = 0;\n\t\tthis.cumulativeWeightAdditive = 0;\n\n\t\tif ( weight < 1 ) {\n\n\t\t\t// accuN := accuN + original * ( 1 - cumulativeWeight )\n\n\t\t\tconst originalValueOffset = stride * this._origIndex;\n\n\t\t\tthis._mixBufferRegion(\n\t\t\t\tbuffer, offset, originalValueOffset, 1 - weight, stride );\n\n\t\t}\n\n\t\tif ( weightAdditive > 0 ) {\n\n\t\t\t// accuN := accuN + additive accuN\n\n\t\t\tthis._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride );\n\n\t\t}\n\n\t\tfor ( let i = stride, e = stride + stride; i !== e; ++ i ) {\n\n\t\t\tif ( buffer[ i ] !== buffer[ i + stride ] ) {\n\n\t\t\t\t// value has changed -> update scene graph\n\n\t\t\t\tbinding.setValue( buffer, offset );\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// remember the state of the bound property and copy it to both accus\n\tsaveOriginalState() {\n\n\t\tconst binding = this.binding;\n\n\t\tconst buffer = this.buffer,\n\t\t\tstride = this.valueSize,\n\n\t\t\toriginalValueOffset = stride * this._origIndex;\n\n\t\tbinding.getValue( buffer, originalValueOffset );\n\n\t\t// accu[0..1] := orig -- initially detect changes against the original\n\t\tfor ( let i = stride, e = originalValueOffset; i !== e; ++ i ) {\n\n\t\t\tbuffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];\n\n\t\t}\n\n\t\t// Add to identity for additive\n\t\tthis._setIdentity();\n\n\t\tthis.cumulativeWeight = 0;\n\t\tthis.cumulativeWeightAdditive = 0;\n\n\t}\n\n\t// apply the state previously taken via 'saveOriginalState' to the binding\n\trestoreOriginalState() {\n\n\t\tconst originalValueOffset = this.valueSize * 3;\n\t\tthis.binding.setValue( this.buffer, originalValueOffset );\n\n\t}\n\n\t_setAdditiveIdentityNumeric() {\n\n\t\tconst startIndex = this._addIndex * this.valueSize;\n\t\tconst endIndex = startIndex + this.valueSize;\n\n\t\tfor ( let i = startIndex; i < endIndex; i ++ ) {\n\n\t\t\tthis.buffer[ i ] = 0;\n\n\t\t}\n\n\t}\n\n\t_setAdditiveIdentityQuaternion() {\n\n\t\tthis._setAdditiveIdentityNumeric();\n\t\tthis.buffer[ this._addIndex * this.valueSize + 3 ] = 1;\n\n\t}\n\n\t_setAdditiveIdentityOther() {\n\n\t\tconst startIndex = this._origIndex * this.valueSize;\n\t\tconst targetIndex = this._addIndex * this.valueSize;\n\n\t\tfor ( let i = 0; i < this.valueSize; i ++ ) {\n\n\t\t\tthis.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ];\n\n\t\t}\n\n\t}\n\n\n\t// mix functions\n\n\t_select( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\tif ( t >= 0.5 ) {\n\n\t\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\t\tbuffer[ dstOffset + i ] = buffer[ srcOffset + i ];\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_slerp( buffer, dstOffset, srcOffset, t ) {\n\n\t\tQuaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );\n\n\t}\n\n\t_slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\tconst workOffset = this._workIndex * stride;\n\n\t\t// Store result in intermediate buffer offset\n\t\tQuaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset );\n\n\t\t// Slerp to the intermediate result\n\t\tQuaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t );\n\n\t}\n\n\t_lerp( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\tconst s = 1 - t;\n\n\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\tconst j = dstOffset + i;\n\n\t\t\tbuffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;\n\n\t\t}\n\n\t}\n\n\t_lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\tconst j = dstOffset + i;\n\n\t\t\tbuffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t;\n\n\t\t}\n\n\t}\n\n}\n\n// Characters [].:/ are reserved for track binding syntax.\nconst _RESERVED_CHARS_RE = '\\\\[\\\\]\\\\.:\\\\/';\nconst _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' );\n\n// Attempts to allow node names from any language. ES5's `\\w` regexp matches\n// only latin characters, and the unicode \\p{L} is not yet supported. So\n// instead, we exclude reserved characters and match everything else.\nconst _wordChar = '[^' + _RESERVED_CHARS_RE + ']';\nconst _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\\\.', '' ) + ']';\n\n// Parent directories, delimited by '/' or ':'. Currently unused, but must\n// be matched to parse the rest of the track name.\nconst _directoryRe = /*@__PURE__*/ /((?:WC+[\\/:])*)/.source.replace( 'WC', _wordChar );\n\n// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.\nconst _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );\n\n// Object on target node, and accessor. May not contain reserved\n// characters. Accessor may contain any character except closing bracket.\nconst _objectRe = /*@__PURE__*/ /(?:\\.(WC+)(?:\\[(.+)\\])?)?/.source.replace( 'WC', _wordChar );\n\n// Property and accessor. May not contain reserved characters. Accessor may\n// contain any non-bracket characters.\nconst _propertyRe = /*@__PURE__*/ /\\.(WC+)(?:\\[(.+)\\])?/.source.replace( 'WC', _wordChar );\n\nconst _trackRe = new RegExp( ''\n\t+ '^'\n\t+ _directoryRe\n\t+ _nodeRe\n\t+ _objectRe\n\t+ _propertyRe\n\t+ '$'\n);\n\nconst _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ];\n\nclass Composite {\n\n\tconstructor( targetGroup, path, optionalParsedPath ) {\n\n\t\tconst parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );\n\n\t\tthis._targetGroup = targetGroup;\n\t\tthis._bindings = targetGroup.subscribe_( path, parsedPath );\n\n\t}\n\n\tgetValue( array, offset ) {\n\n\t\tthis.bind(); // bind all binding\n\n\t\tconst firstValidIndex = this._targetGroup.nCachedObjects_,\n\t\t\tbinding = this._bindings[ firstValidIndex ];\n\n\t\t// and only call .getValue on the first\n\t\tif ( binding !== undefined ) binding.getValue( array, offset );\n\n\t}\n\n\tsetValue( array, offset ) {\n\n\t\tconst bindings = this._bindings;\n\n\t\tfor ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\tbindings[ i ].setValue( array, offset );\n\n\t\t}\n\n\t}\n\n\tbind() {\n\n\t\tconst bindings = this._bindings;\n\n\t\tfor ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\tbindings[ i ].bind();\n\n\t\t}\n\n\t}\n\n\tunbind() {\n\n\t\tconst bindings = this._bindings;\n\n\t\tfor ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\tbindings[ i ].unbind();\n\n\t\t}\n\n\t}\n\n}\n\n// Note: This class uses a State pattern on a per-method basis:\n// 'bind' sets 'this.getValue' / 'setValue' and shadows the\n// prototype version of these methods with one that represents\n// the bound state. When the property is not found, the methods\n// become no-ops.\nclass PropertyBinding {\n\n\tconstructor( rootNode, path, parsedPath ) {\n\n\t\tthis.path = path;\n\t\tthis.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );\n\n\t\tthis.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName );\n\n\t\tthis.rootNode = rootNode;\n\n\t\t// initial state of these methods that calls 'bind'\n\t\tthis.getValue = this._getValue_unbound;\n\t\tthis.setValue = this._setValue_unbound;\n\n\t}\n\n\n\tstatic create( root, path, parsedPath ) {\n\n\t\tif ( ! ( root && root.isAnimationObjectGroup ) ) {\n\n\t\t\treturn new PropertyBinding( root, path, parsedPath );\n\n\t\t} else {\n\n\t\t\treturn new PropertyBinding.Composite( root, path, parsedPath );\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Replaces spaces with underscores and removes unsupported characters from\n\t * node names, to ensure compatibility with parseTrackName().\n\t *\n\t * @param {string} name Node name to be sanitized.\n\t * @return {string}\n\t */\n\tstatic sanitizeNodeName( name ) {\n\n\t\treturn name.replace( /\\s/g, '_' ).replace( _reservedRe, '' );\n\n\t}\n\n\tstatic parseTrackName( trackName ) {\n\n\t\tconst matches = _trackRe.exec( trackName );\n\n\t\tif ( matches === null ) {\n\n\t\t\tthrow new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );\n\n\t\t}\n\n\t\tconst results = {\n\t\t\t// directoryName: matches[ 1 ], // (tschw) currently unused\n\t\t\tnodeName: matches[ 2 ],\n\t\t\tobjectName: matches[ 3 ],\n\t\t\tobjectIndex: matches[ 4 ],\n\t\t\tpropertyName: matches[ 5 ], // required\n\t\t\tpropertyIndex: matches[ 6 ]\n\t\t};\n\n\t\tconst lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );\n\n\t\tif ( lastDot !== undefined && lastDot !== - 1 ) {\n\n\t\t\tconst objectName = results.nodeName.substring( lastDot + 1 );\n\n\t\t\t// Object names must be checked against an allowlist. Otherwise, there\n\t\t\t// is no way to parse 'foo.bar.baz': 'baz' must be a property, but\n\t\t\t// 'bar' could be the objectName, or part of a nodeName (which can\n\t\t\t// include '.' characters).\n\t\t\tif ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) {\n\n\t\t\t\tresults.nodeName = results.nodeName.substring( 0, lastDot );\n\t\t\t\tresults.objectName = objectName;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( results.propertyName === null || results.propertyName.length === 0 ) {\n\n\t\t\tthrow new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );\n\n\t\t}\n\n\t\treturn results;\n\n\t}\n\n\tstatic findNode( root, nodeName ) {\n\n\t\tif ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {\n\n\t\t\treturn root;\n\n\t\t}\n\n\t\t// search into skeleton bones.\n\t\tif ( root.skeleton ) {\n\n\t\t\tconst bone = root.skeleton.getBoneByName( nodeName );\n\n\t\t\tif ( bone !== undefined ) {\n\n\t\t\t\treturn bone;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// search into node subtree.\n\t\tif ( root.children ) {\n\n\t\t\tconst searchNodeSubtree = function ( children ) {\n\n\t\t\t\tfor ( let i = 0; i < children.length; i ++ ) {\n\n\t\t\t\t\tconst childNode = children[ i ];\n\n\t\t\t\t\tif ( childNode.name === nodeName || childNode.uuid === nodeName ) {\n\n\t\t\t\t\t\treturn childNode;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst result = searchNodeSubtree( childNode.children );\n\n\t\t\t\t\tif ( result ) return result;\n\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\n\t\t\t};\n\n\t\t\tconst subTreeNode = searchNodeSubtree( root.children );\n\n\t\t\tif ( subTreeNode ) {\n\n\t\t\t\treturn subTreeNode;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n\t// these are used to \"bind\" a nonexistent property\n\t_getValue_unavailable() {}\n\t_setValue_unavailable() {}\n\n\t// Getters\n\n\t_getValue_direct( buffer, offset ) {\n\n\t\tbuffer[ offset ] = this.targetObject[ this.propertyName ];\n\n\t}\n\n\t_getValue_array( buffer, offset ) {\n\n\t\tconst source = this.resolvedProperty;\n\n\t\tfor ( let i = 0, n = source.length; i !== n; ++ i ) {\n\n\t\t\tbuffer[ offset ++ ] = source[ i ];\n\n\t\t}\n\n\t}\n\n\t_getValue_arrayElement( buffer, offset ) {\n\n\t\tbuffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];\n\n\t}\n\n\t_getValue_toArray( buffer, offset ) {\n\n\t\tthis.resolvedProperty.toArray( buffer, offset );\n\n\t}\n\n\t// Direct\n\n\t_setValue_direct( buffer, offset ) {\n\n\t\tthis.targetObject[ this.propertyName ] = buffer[ offset ];\n\n\t}\n\n\t_setValue_direct_setNeedsUpdate( buffer, offset ) {\n\n\t\tthis.targetObject[ this.propertyName ] = buffer[ offset ];\n\t\tthis.targetObject.needsUpdate = true;\n\n\t}\n\n\t_setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\tthis.targetObject[ this.propertyName ] = buffer[ offset ];\n\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t}\n\n\t// EntireArray\n\n\t_setValue_array( buffer, offset ) {\n\n\t\tconst dest = this.resolvedProperty;\n\n\t\tfor ( let i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t}\n\n\t}\n\n\t_setValue_array_setNeedsUpdate( buffer, offset ) {\n\n\t\tconst dest = this.resolvedProperty;\n\n\t\tfor ( let i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t}\n\n\t\tthis.targetObject.needsUpdate = true;\n\n\t}\n\n\t_setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\tconst dest = this.resolvedProperty;\n\n\t\tfor ( let i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t}\n\n\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t}\n\n\t// ArrayElement\n\n\t_setValue_arrayElement( buffer, offset ) {\n\n\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\n\t}\n\n\t_setValue_arrayElement_setNeedsUpdate( buffer, offset ) {\n\n\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\t\tthis.targetObject.needsUpdate = true;\n\n\t}\n\n\t_setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t}\n\n\t// HasToFromArray\n\n\t_setValue_fromArray( buffer, offset ) {\n\n\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\n\t}\n\n\t_setValue_fromArray_setNeedsUpdate( buffer, offset ) {\n\n\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\t\tthis.targetObject.needsUpdate = true;\n\n\t}\n\n\t_setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t}\n\n\t_getValue_unbound( targetArray, offset ) {\n\n\t\tthis.bind();\n\t\tthis.getValue( targetArray, offset );\n\n\t}\n\n\t_setValue_unbound( sourceArray, offset ) {\n\n\t\tthis.bind();\n\t\tthis.setValue( sourceArray, offset );\n\n\t}\n\n\t// create getter / setter pair for a property in the scene graph\n\tbind() {\n\n\t\tlet targetObject = this.node;\n\t\tconst parsedPath = this.parsedPath;\n\n\t\tconst objectName = parsedPath.objectName;\n\t\tconst propertyName = parsedPath.propertyName;\n\t\tlet propertyIndex = parsedPath.propertyIndex;\n\n\t\tif ( ! targetObject ) {\n\n\t\t\ttargetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName );\n\n\t\t\tthis.node = targetObject;\n\n\t\t}\n\n\t\t// set fail state so we can just 'return' on error\n\t\tthis.getValue = this._getValue_unavailable;\n\t\tthis.setValue = this._setValue_unavailable;\n\n\t\t// ensure there is a value node\n\t\tif ( ! targetObject ) {\n\n\t\t\tconsole.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( objectName ) {\n\n\t\t\tlet objectIndex = parsedPath.objectIndex;\n\n\t\t\t// special cases were we need to reach deeper into the hierarchy to get the face materials....\n\t\t\tswitch ( objectName ) {\n\n\t\t\t\tcase 'materials':\n\n\t\t\t\t\tif ( ! targetObject.material ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! targetObject.material.materials ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttargetObject = targetObject.material.materials;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'bones':\n\n\t\t\t\t\tif ( ! targetObject.skeleton ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// potential future optimization: skip this if propertyIndex is already an integer\n\t\t\t\t\t// and convert the integer string to a true integer.\n\n\t\t\t\t\ttargetObject = targetObject.skeleton.bones;\n\n\t\t\t\t\t// support resolving morphTarget names into indices.\n\t\t\t\t\tfor ( let i = 0; i < targetObject.length; i ++ ) {\n\n\t\t\t\t\t\tif ( targetObject[ i ].name === objectIndex ) {\n\n\t\t\t\t\t\t\tobjectIndex = i;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'map':\n\n\t\t\t\t\tif ( 'map' in targetObject ) {\n\n\t\t\t\t\t\ttargetObject = targetObject.map;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! targetObject.material ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! targetObject.material.map ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttargetObject = targetObject.material.map;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tif ( targetObject[ objectName ] === undefined ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttargetObject = targetObject[ objectName ];\n\n\t\t\t}\n\n\n\t\t\tif ( objectIndex !== undefined ) {\n\n\t\t\t\tif ( targetObject[ objectIndex ] === undefined ) {\n\n\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\ttargetObject = targetObject[ objectIndex ];\n\n\t\t\t}\n\n\t\t}\n\n\t\t// resolve property\n\t\tconst nodeProperty = targetObject[ propertyName ];\n\n\t\tif ( nodeProperty === undefined ) {\n\n\t\t\tconst nodeName = parsedPath.nodeName;\n\n\t\t\tconsole.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +\n\t\t\t\t'.' + propertyName + ' but it wasn\\'t found.', targetObject );\n\t\t\treturn;\n\n\t\t}\n\n\t\t// determine versioning scheme\n\t\tlet versioning = this.Versioning.None;\n\n\t\tthis.targetObject = targetObject;\n\n\t\tif ( targetObject.needsUpdate !== undefined ) { // material\n\n\t\t\tversioning = this.Versioning.NeedsUpdate;\n\n\t\t} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform\n\n\t\t\tversioning = this.Versioning.MatrixWorldNeedsUpdate;\n\n\t\t}\n\n\t\t// determine how the property gets bound\n\t\tlet bindingType = this.BindingType.Direct;\n\n\t\tif ( propertyIndex !== undefined ) {\n\n\t\t\t// access a sub element of the property array (only primitives are supported right now)\n\n\t\t\tif ( propertyName === 'morphTargetInfluences' ) {\n\n\t\t\t\t// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.\n\n\t\t\t\t// support resolving morphTarget names into indices.\n\t\t\t\tif ( ! targetObject.geometry ) {\n\n\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tif ( ! targetObject.geometry.morphAttributes ) {\n\n\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tif ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) {\n\n\t\t\t\t\tpropertyIndex = targetObject.morphTargetDictionary[ propertyIndex ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tbindingType = this.BindingType.ArrayElement;\n\n\t\t\tthis.resolvedProperty = nodeProperty;\n\t\t\tthis.propertyIndex = propertyIndex;\n\n\t\t} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {\n\n\t\t\t// must use copy for Object3D.Euler/Quaternion\n\n\t\t\tbindingType = this.BindingType.HasFromToArray;\n\n\t\t\tthis.resolvedProperty = nodeProperty;\n\n\t\t} else if ( Array.isArray( nodeProperty ) ) {\n\n\t\t\tbindingType = this.BindingType.EntireArray;\n\n\t\t\tthis.resolvedProperty = nodeProperty;\n\n\t\t} else {\n\n\t\t\tthis.propertyName = propertyName;\n\n\t\t}\n\n\t\t// select getter / setter\n\t\tthis.getValue = this.GetterByBindingType[ bindingType ];\n\t\tthis.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];\n\n\t}\n\n\tunbind() {\n\n\t\tthis.node = null;\n\n\t\t// back to the prototype version of getValue / setValue\n\t\t// note: avoiding to mutate the shape of 'this' via 'delete'\n\t\tthis.getValue = this._getValue_unbound;\n\t\tthis.setValue = this._setValue_unbound;\n\n\t}\n\n}\n\nPropertyBinding.Composite = Composite;\n\nPropertyBinding.prototype.BindingType = {\n\tDirect: 0,\n\tEntireArray: 1,\n\tArrayElement: 2,\n\tHasFromToArray: 3\n};\n\nPropertyBinding.prototype.Versioning = {\n\tNone: 0,\n\tNeedsUpdate: 1,\n\tMatrixWorldNeedsUpdate: 2\n};\n\nPropertyBinding.prototype.GetterByBindingType = [\n\n\tPropertyBinding.prototype._getValue_direct,\n\tPropertyBinding.prototype._getValue_array,\n\tPropertyBinding.prototype._getValue_arrayElement,\n\tPropertyBinding.prototype._getValue_toArray,\n\n];\n\nPropertyBinding.prototype.SetterByBindingTypeAndVersioning = [\n\n\t[\n\t\t// Direct\n\t\tPropertyBinding.prototype._setValue_direct,\n\t\tPropertyBinding.prototype._setValue_direct_setNeedsUpdate,\n\t\tPropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate,\n\n\t], [\n\n\t\t// EntireArray\n\n\t\tPropertyBinding.prototype._setValue_array,\n\t\tPropertyBinding.prototype._setValue_array_setNeedsUpdate,\n\t\tPropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate,\n\n\t], [\n\n\t\t// ArrayElement\n\t\tPropertyBinding.prototype._setValue_arrayElement,\n\t\tPropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate,\n\t\tPropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate,\n\n\t], [\n\n\t\t// HasToFromArray\n\t\tPropertyBinding.prototype._setValue_fromArray,\n\t\tPropertyBinding.prototype._setValue_fromArray_setNeedsUpdate,\n\t\tPropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate,\n\n\t]\n\n];\n\n/**\n *\n * A group of objects that receives a shared animation state.\n *\n * Usage:\n *\n * - Add objects you would otherwise pass as 'root' to the\n * constructor or the .clipAction method of AnimationMixer.\n *\n * - Instead pass this object as 'root'.\n *\n * - You can also add and remove objects later when the mixer\n * is running.\n *\n * Note:\n *\n * Objects of this class appear as one object to the mixer,\n * so cache control of the individual objects must be done\n * on the group.\n *\n * Limitation:\n *\n * - The animated properties must be compatible among the\n * all objects in the group.\n *\n * - A single property can either be controlled through a\n * target group or directly, but not both.\n */\n\nclass AnimationObjectGroup {\n\n\tconstructor() {\n\n\t\tthis.isAnimationObjectGroup = true;\n\n\t\tthis.uuid = generateUUID();\n\n\t\t// cached objects followed by the active ones\n\t\tthis._objects = Array.prototype.slice.call( arguments );\n\n\t\tthis.nCachedObjects_ = 0; // threshold\n\t\t// note: read by PropertyBinding.Composite\n\n\t\tconst indices = {};\n\t\tthis._indicesByUUID = indices; // for bookkeeping\n\n\t\tfor ( let i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tindices[ arguments[ i ].uuid ] = i;\n\n\t\t}\n\n\t\tthis._paths = []; // inside: string\n\t\tthis._parsedPaths = []; // inside: { we don't care, here }\n\t\tthis._bindings = []; // inside: Array< PropertyBinding >\n\t\tthis._bindingsIndicesByPath = {}; // inside: indices in these arrays\n\n\t\tconst scope = this;\n\n\t\tthis.stats = {\n\n\t\t\tobjects: {\n\t\t\t\tget total() {\n\n\t\t\t\t\treturn scope._objects.length;\n\n\t\t\t\t},\n\t\t\t\tget inUse() {\n\n\t\t\t\t\treturn this.total - scope.nCachedObjects_;\n\n\t\t\t\t}\n\t\t\t},\n\t\t\tget bindingsPerObject() {\n\n\t\t\t\treturn scope._bindings.length;\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\tadd() {\n\n\t\tconst objects = this._objects,\n\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\tpaths = this._paths,\n\t\t\tparsedPaths = this._parsedPaths,\n\t\t\tbindings = this._bindings,\n\t\t\tnBindings = bindings.length;\n\n\t\tlet knownObject = undefined,\n\t\t\tnObjects = objects.length,\n\t\t\tnCachedObjects = this.nCachedObjects_;\n\n\t\tfor ( let i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tconst object = arguments[ i ],\n\t\t\t\tuuid = object.uuid;\n\t\t\tlet index = indicesByUUID[ uuid ];\n\n\t\t\tif ( index === undefined ) {\n\n\t\t\t\t// unknown object -> add it to the ACTIVE region\n\n\t\t\t\tindex = nObjects ++;\n\t\t\t\tindicesByUUID[ uuid ] = index;\n\t\t\t\tobjects.push( object );\n\n\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\tfor ( let j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\tbindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );\n\n\t\t\t\t}\n\n\t\t\t} else if ( index < nCachedObjects ) {\n\n\t\t\t\tknownObject = objects[ index ];\n\n\t\t\t\t// move existing object to the ACTIVE region\n\n\t\t\t\tconst firstActiveIndex = -- nCachedObjects,\n\t\t\t\t\tlastCachedObject = objects[ firstActiveIndex ];\n\n\t\t\t\tindicesByUUID[ lastCachedObject.uuid ] = index;\n\t\t\t\tobjects[ index ] = lastCachedObject;\n\n\t\t\t\tindicesByUUID[ uuid ] = firstActiveIndex;\n\t\t\t\tobjects[ firstActiveIndex ] = object;\n\n\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\tfor ( let j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\tconst bindingsForPath = bindings[ j ],\n\t\t\t\t\t\tlastCached = bindingsForPath[ firstActiveIndex ];\n\n\t\t\t\t\tlet binding = bindingsForPath[ index ];\n\n\t\t\t\t\tbindingsForPath[ index ] = lastCached;\n\n\t\t\t\t\tif ( binding === undefined ) {\n\n\t\t\t\t\t\t// since we do not bother to create new bindings\n\t\t\t\t\t\t// for objects that are cached, the binding may\n\t\t\t\t\t\t// or may not exist\n\n\t\t\t\t\t\tbinding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbindingsForPath[ firstActiveIndex ] = binding;\n\n\t\t\t\t}\n\n\t\t\t} else if ( objects[ index ] !== knownObject ) {\n\n\t\t\t\tconsole.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +\n\t\t\t\t\t'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );\n\n\t\t\t} // else the object is already where we want it to be\n\n\t\t} // for arguments\n\n\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t}\n\n\tremove() {\n\n\t\tconst objects = this._objects,\n\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\tbindings = this._bindings,\n\t\t\tnBindings = bindings.length;\n\n\t\tlet nCachedObjects = this.nCachedObjects_;\n\n\t\tfor ( let i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tconst object = arguments[ i ],\n\t\t\t\tuuid = object.uuid,\n\t\t\t\tindex = indicesByUUID[ uuid ];\n\n\t\t\tif ( index !== undefined && index >= nCachedObjects ) {\n\n\t\t\t\t// move existing object into the CACHED region\n\n\t\t\t\tconst lastCachedIndex = nCachedObjects ++,\n\t\t\t\t\tfirstActiveObject = objects[ lastCachedIndex ];\n\n\t\t\t\tindicesByUUID[ firstActiveObject.uuid ] = index;\n\t\t\t\tobjects[ index ] = firstActiveObject;\n\n\t\t\t\tindicesByUUID[ uuid ] = lastCachedIndex;\n\t\t\t\tobjects[ lastCachedIndex ] = object;\n\n\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\tfor ( let j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\tconst bindingsForPath = bindings[ j ],\n\t\t\t\t\t\tfirstActive = bindingsForPath[ lastCachedIndex ],\n\t\t\t\t\t\tbinding = bindingsForPath[ index ];\n\n\t\t\t\t\tbindingsForPath[ index ] = firstActive;\n\t\t\t\t\tbindingsForPath[ lastCachedIndex ] = binding;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} // for arguments\n\n\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t}\n\n\t// remove & forget\n\tuncache() {\n\n\t\tconst objects = this._objects,\n\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\tbindings = this._bindings,\n\t\t\tnBindings = bindings.length;\n\n\t\tlet nCachedObjects = this.nCachedObjects_,\n\t\t\tnObjects = objects.length;\n\n\t\tfor ( let i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tconst object = arguments[ i ],\n\t\t\t\tuuid = object.uuid,\n\t\t\t\tindex = indicesByUUID[ uuid ];\n\n\t\t\tif ( index !== undefined ) {\n\n\t\t\t\tdelete indicesByUUID[ uuid ];\n\n\t\t\t\tif ( index < nCachedObjects ) {\n\n\t\t\t\t\t// object is cached, shrink the CACHED region\n\n\t\t\t\t\tconst firstActiveIndex = -- nCachedObjects,\n\t\t\t\t\t\tlastCachedObject = objects[ firstActiveIndex ],\n\t\t\t\t\t\tlastIndex = -- nObjects,\n\t\t\t\t\t\tlastObject = objects[ lastIndex ];\n\n\t\t\t\t\t// last cached object takes this object's place\n\t\t\t\t\tindicesByUUID[ lastCachedObject.uuid ] = index;\n\t\t\t\t\tobjects[ index ] = lastCachedObject;\n\n\t\t\t\t\t// last object goes to the activated slot and pop\n\t\t\t\t\tindicesByUUID[ lastObject.uuid ] = firstActiveIndex;\n\t\t\t\t\tobjects[ firstActiveIndex ] = lastObject;\n\t\t\t\t\tobjects.pop();\n\n\t\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\t\tfor ( let j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\t\tconst bindingsForPath = bindings[ j ],\n\t\t\t\t\t\t\tlastCached = bindingsForPath[ firstActiveIndex ],\n\t\t\t\t\t\t\tlast = bindingsForPath[ lastIndex ];\n\n\t\t\t\t\t\tbindingsForPath[ index ] = lastCached;\n\t\t\t\t\t\tbindingsForPath[ firstActiveIndex ] = last;\n\t\t\t\t\t\tbindingsForPath.pop();\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// object is active, just swap with the last and pop\n\n\t\t\t\t\tconst lastIndex = -- nObjects,\n\t\t\t\t\t\tlastObject = objects[ lastIndex ];\n\n\t\t\t\t\tif ( lastIndex > 0 ) {\n\n\t\t\t\t\t\tindicesByUUID[ lastObject.uuid ] = index;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tobjects[ index ] = lastObject;\n\t\t\t\t\tobjects.pop();\n\n\t\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\t\tfor ( let j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\t\tconst bindingsForPath = bindings[ j ];\n\n\t\t\t\t\t\tbindingsForPath[ index ] = bindingsForPath[ lastIndex ];\n\t\t\t\t\t\tbindingsForPath.pop();\n\n\t\t\t\t\t}\n\n\t\t\t\t} // cached or active\n\n\t\t\t} // if object is known\n\n\t\t} // for arguments\n\n\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t}\n\n\t// Internal interface used by befriended PropertyBinding.Composite:\n\n\tsubscribe_( path, parsedPath ) {\n\n\t\t// returns an array of bindings for the given path that is changed\n\t\t// according to the contained objects in the group\n\n\t\tconst indicesByPath = this._bindingsIndicesByPath;\n\t\tlet index = indicesByPath[ path ];\n\t\tconst bindings = this._bindings;\n\n\t\tif ( index !== undefined ) return bindings[ index ];\n\n\t\tconst paths = this._paths,\n\t\t\tparsedPaths = this._parsedPaths,\n\t\t\tobjects = this._objects,\n\t\t\tnObjects = objects.length,\n\t\t\tnCachedObjects = this.nCachedObjects_,\n\t\t\tbindingsForPath = new Array( nObjects );\n\n\t\tindex = bindings.length;\n\n\t\tindicesByPath[ path ] = index;\n\n\t\tpaths.push( path );\n\t\tparsedPaths.push( parsedPath );\n\t\tbindings.push( bindingsForPath );\n\n\t\tfor ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {\n\n\t\t\tconst object = objects[ i ];\n\t\t\tbindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );\n\n\t\t}\n\n\t\treturn bindingsForPath;\n\n\t}\n\n\tunsubscribe_( path ) {\n\n\t\t// tells the group to forget about a property path and no longer\n\t\t// update the array previously obtained with 'subscribe_'\n\n\t\tconst indicesByPath = this._bindingsIndicesByPath,\n\t\t\tindex = indicesByPath[ path ];\n\n\t\tif ( index !== undefined ) {\n\n\t\t\tconst paths = this._paths,\n\t\t\t\tparsedPaths = this._parsedPaths,\n\t\t\t\tbindings = this._bindings,\n\t\t\t\tlastBindingsIndex = bindings.length - 1,\n\t\t\t\tlastBindings = bindings[ lastBindingsIndex ],\n\t\t\t\tlastBindingsPath = path[ lastBindingsIndex ];\n\n\t\t\tindicesByPath[ lastBindingsPath ] = index;\n\n\t\t\tbindings[ index ] = lastBindings;\n\t\t\tbindings.pop();\n\n\t\t\tparsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];\n\t\t\tparsedPaths.pop();\n\n\t\t\tpaths[ index ] = paths[ lastBindingsIndex ];\n\t\t\tpaths.pop();\n\n\t\t}\n\n\t}\n\n}\n\nclass AnimationAction {\n\n\tconstructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) {\n\n\t\tthis._mixer = mixer;\n\t\tthis._clip = clip;\n\t\tthis._localRoot = localRoot;\n\t\tthis.blendMode = blendMode;\n\n\t\tconst tracks = clip.tracks,\n\t\t\tnTracks = tracks.length,\n\t\t\tinterpolants = new Array( nTracks );\n\n\t\tconst interpolantSettings = {\n\t\t\tendingStart: ZeroCurvatureEnding,\n\t\t\tendingEnd: ZeroCurvatureEnding\n\t\t};\n\n\t\tfor ( let i = 0; i !== nTracks; ++ i ) {\n\n\t\t\tconst interpolant = tracks[ i ].createInterpolant( null );\n\t\t\tinterpolants[ i ] = interpolant;\n\t\t\tinterpolant.settings = interpolantSettings;\n\n\t\t}\n\n\t\tthis._interpolantSettings = interpolantSettings;\n\n\t\tthis._interpolants = interpolants; // bound by the mixer\n\n\t\t// inside: PropertyMixer (managed by the mixer)\n\t\tthis._propertyBindings = new Array( nTracks );\n\n\t\tthis._cacheIndex = null; // for the memory manager\n\t\tthis._byClipCacheIndex = null; // for the memory manager\n\n\t\tthis._timeScaleInterpolant = null;\n\t\tthis._weightInterpolant = null;\n\n\t\tthis.loop = LoopRepeat;\n\t\tthis._loopCount = - 1;\n\n\t\t// global mixer time when the action is to be started\n\t\t// it's set back to 'null' upon start of the action\n\t\tthis._startTime = null;\n\n\t\t// scaled local time of the action\n\t\t// gets clamped or wrapped to 0..clip.duration according to loop\n\t\tthis.time = 0;\n\n\t\tthis.timeScale = 1;\n\t\tthis._effectiveTimeScale = 1;\n\n\t\tthis.weight = 1;\n\t\tthis._effectiveWeight = 1;\n\n\t\tthis.repetitions = Infinity; // no. of repetitions when looping\n\n\t\tthis.paused = false; // true -> zero effective time scale\n\t\tthis.enabled = true; // false -> zero effective weight\n\n\t\tthis.clampWhenFinished = false;// keep feeding the last frame?\n\n\t\tthis.zeroSlopeAtStart = true;// for smooth interpolation w/o separate\n\t\tthis.zeroSlopeAtEnd = true;// clips for start, loop and end\n\n\t}\n\n\t// State & Scheduling\n\n\tplay() {\n\n\t\tthis._mixer._activateAction( this );\n\n\t\treturn this;\n\n\t}\n\n\tstop() {\n\n\t\tthis._mixer._deactivateAction( this );\n\n\t\treturn this.reset();\n\n\t}\n\n\treset() {\n\n\t\tthis.paused = false;\n\t\tthis.enabled = true;\n\n\t\tthis.time = 0; // restart clip\n\t\tthis._loopCount = - 1;// forget previous loops\n\t\tthis._startTime = null;// forget scheduling\n\n\t\treturn this.stopFading().stopWarping();\n\n\t}\n\n\tisRunning() {\n\n\t\treturn this.enabled && ! this.paused && this.timeScale !== 0 &&\n\t\t\tthis._startTime === null && this._mixer._isActiveAction( this );\n\n\t}\n\n\t// return true when play has been called\n\tisScheduled() {\n\n\t\treturn this._mixer._isActiveAction( this );\n\n\t}\n\n\tstartAt( time ) {\n\n\t\tthis._startTime = time;\n\n\t\treturn this;\n\n\t}\n\n\tsetLoop( mode, repetitions ) {\n\n\t\tthis.loop = mode;\n\t\tthis.repetitions = repetitions;\n\n\t\treturn this;\n\n\t}\n\n\t// Weight\n\n\t// set the weight stopping any scheduled fading\n\t// although .enabled = false yields an effective weight of zero, this\n\t// method does *not* change .enabled, because it would be confusing\n\tsetEffectiveWeight( weight ) {\n\n\t\tthis.weight = weight;\n\n\t\t// note: same logic as when updated at runtime\n\t\tthis._effectiveWeight = this.enabled ? weight : 0;\n\n\t\treturn this.stopFading();\n\n\t}\n\n\t// return the weight considering fading and .enabled\n\tgetEffectiveWeight() {\n\n\t\treturn this._effectiveWeight;\n\n\t}\n\n\tfadeIn( duration ) {\n\n\t\treturn this._scheduleFading( duration, 0, 1 );\n\n\t}\n\n\tfadeOut( duration ) {\n\n\t\treturn this._scheduleFading( duration, 1, 0 );\n\n\t}\n\n\tcrossFadeFrom( fadeOutAction, duration, warp ) {\n\n\t\tfadeOutAction.fadeOut( duration );\n\t\tthis.fadeIn( duration );\n\n\t\tif ( warp ) {\n\n\t\t\tconst fadeInDuration = this._clip.duration,\n\t\t\t\tfadeOutDuration = fadeOutAction._clip.duration,\n\n\t\t\t\tstartEndRatio = fadeOutDuration / fadeInDuration,\n\t\t\t\tendStartRatio = fadeInDuration / fadeOutDuration;\n\n\t\t\tfadeOutAction.warp( 1.0, startEndRatio, duration );\n\t\t\tthis.warp( endStartRatio, 1.0, duration );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tcrossFadeTo( fadeInAction, duration, warp ) {\n\n\t\treturn fadeInAction.crossFadeFrom( this, duration, warp );\n\n\t}\n\n\tstopFading() {\n\n\t\tconst weightInterpolant = this._weightInterpolant;\n\n\t\tif ( weightInterpolant !== null ) {\n\n\t\t\tthis._weightInterpolant = null;\n\t\t\tthis._mixer._takeBackControlInterpolant( weightInterpolant );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// Time Scale Control\n\n\t// set the time scale stopping any scheduled warping\n\t// although .paused = true yields an effective time scale of zero, this\n\t// method does *not* change .paused, because it would be confusing\n\tsetEffectiveTimeScale( timeScale ) {\n\n\t\tthis.timeScale = timeScale;\n\t\tthis._effectiveTimeScale = this.paused ? 0 : timeScale;\n\n\t\treturn this.stopWarping();\n\n\t}\n\n\t// return the time scale considering warping and .paused\n\tgetEffectiveTimeScale() {\n\n\t\treturn this._effectiveTimeScale;\n\n\t}\n\n\tsetDuration( duration ) {\n\n\t\tthis.timeScale = this._clip.duration / duration;\n\n\t\treturn this.stopWarping();\n\n\t}\n\n\tsyncWith( action ) {\n\n\t\tthis.time = action.time;\n\t\tthis.timeScale = action.timeScale;\n\n\t\treturn this.stopWarping();\n\n\t}\n\n\thalt( duration ) {\n\n\t\treturn this.warp( this._effectiveTimeScale, 0, duration );\n\n\t}\n\n\twarp( startTimeScale, endTimeScale, duration ) {\n\n\t\tconst mixer = this._mixer,\n\t\t\tnow = mixer.time,\n\t\t\ttimeScale = this.timeScale;\n\n\t\tlet interpolant = this._timeScaleInterpolant;\n\n\t\tif ( interpolant === null ) {\n\n\t\t\tinterpolant = mixer._lendControlInterpolant();\n\t\t\tthis._timeScaleInterpolant = interpolant;\n\n\t\t}\n\n\t\tconst times = interpolant.parameterPositions,\n\t\t\tvalues = interpolant.sampleValues;\n\n\t\ttimes[ 0 ] = now;\n\t\ttimes[ 1 ] = now + duration;\n\n\t\tvalues[ 0 ] = startTimeScale / timeScale;\n\t\tvalues[ 1 ] = endTimeScale / timeScale;\n\n\t\treturn this;\n\n\t}\n\n\tstopWarping() {\n\n\t\tconst timeScaleInterpolant = this._timeScaleInterpolant;\n\n\t\tif ( timeScaleInterpolant !== null ) {\n\n\t\t\tthis._timeScaleInterpolant = null;\n\t\t\tthis._mixer._takeBackControlInterpolant( timeScaleInterpolant );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// Object Accessors\n\n\tgetMixer() {\n\n\t\treturn this._mixer;\n\n\t}\n\n\tgetClip() {\n\n\t\treturn this._clip;\n\n\t}\n\n\tgetRoot() {\n\n\t\treturn this._localRoot || this._mixer._root;\n\n\t}\n\n\t// Interna\n\n\t_update( time, deltaTime, timeDirection, accuIndex ) {\n\n\t\t// called by the mixer\n\n\t\tif ( ! this.enabled ) {\n\n\t\t\t// call ._updateWeight() to update ._effectiveWeight\n\n\t\t\tthis._updateWeight( time );\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst startTime = this._startTime;\n\n\t\tif ( startTime !== null ) {\n\n\t\t\t// check for scheduled start of action\n\n\t\t\tconst timeRunning = ( time - startTime ) * timeDirection;\n\t\t\tif ( timeRunning < 0 || timeDirection === 0 ) {\n\n\t\t\t\tdeltaTime = 0;\n\n\t\t\t} else {\n\n\n\t\t\t\tthis._startTime = null; // unschedule\n\t\t\t\tdeltaTime = timeDirection * timeRunning;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// apply time scale and advance time\n\n\t\tdeltaTime *= this._updateTimeScale( time );\n\t\tconst clipTime = this._updateTime( deltaTime );\n\n\t\t// note: _updateTime may disable the action resulting in\n\t\t// an effective weight of 0\n\n\t\tconst weight = this._updateWeight( time );\n\n\t\tif ( weight > 0 ) {\n\n\t\t\tconst interpolants = this._interpolants;\n\t\t\tconst propertyMixers = this._propertyBindings;\n\n\t\t\tswitch ( this.blendMode ) {\n\n\t\t\t\tcase AdditiveAnimationBlendMode:\n\n\t\t\t\t\tfor ( let j = 0, m = interpolants.length; j !== m; ++ j ) {\n\n\t\t\t\t\t\tinterpolants[ j ].evaluate( clipTime );\n\t\t\t\t\t\tpropertyMixers[ j ].accumulateAdditive( weight );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase NormalAnimationBlendMode:\n\t\t\t\tdefault:\n\n\t\t\t\t\tfor ( let j = 0, m = interpolants.length; j !== m; ++ j ) {\n\n\t\t\t\t\t\tinterpolants[ j ].evaluate( clipTime );\n\t\t\t\t\t\tpropertyMixers[ j ].accumulate( accuIndex, weight );\n\n\t\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_updateWeight( time ) {\n\n\t\tlet weight = 0;\n\n\t\tif ( this.enabled ) {\n\n\t\t\tweight = this.weight;\n\t\t\tconst interpolant = this._weightInterpolant;\n\n\t\t\tif ( interpolant !== null ) {\n\n\t\t\t\tconst interpolantValue = interpolant.evaluate( time )[ 0 ];\n\n\t\t\t\tweight *= interpolantValue;\n\n\t\t\t\tif ( time > interpolant.parameterPositions[ 1 ] ) {\n\n\t\t\t\t\tthis.stopFading();\n\n\t\t\t\t\tif ( interpolantValue === 0 ) {\n\n\t\t\t\t\t\t// faded out, disable\n\t\t\t\t\t\tthis.enabled = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis._effectiveWeight = weight;\n\t\treturn weight;\n\n\t}\n\n\t_updateTimeScale( time ) {\n\n\t\tlet timeScale = 0;\n\n\t\tif ( ! this.paused ) {\n\n\t\t\ttimeScale = this.timeScale;\n\n\t\t\tconst interpolant = this._timeScaleInterpolant;\n\n\t\t\tif ( interpolant !== null ) {\n\n\t\t\t\tconst interpolantValue = interpolant.evaluate( time )[ 0 ];\n\n\t\t\t\ttimeScale *= interpolantValue;\n\n\t\t\t\tif ( time > interpolant.parameterPositions[ 1 ] ) {\n\n\t\t\t\t\tthis.stopWarping();\n\n\t\t\t\t\tif ( timeScale === 0 ) {\n\n\t\t\t\t\t\t// motion has halted, pause\n\t\t\t\t\t\tthis.paused = true;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// warp done - apply final time scale\n\t\t\t\t\t\tthis.timeScale = timeScale;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis._effectiveTimeScale = timeScale;\n\t\treturn timeScale;\n\n\t}\n\n\t_updateTime( deltaTime ) {\n\n\t\tconst duration = this._clip.duration;\n\t\tconst loop = this.loop;\n\n\t\tlet time = this.time + deltaTime;\n\t\tlet loopCount = this._loopCount;\n\n\t\tconst pingPong = ( loop === LoopPingPong );\n\n\t\tif ( deltaTime === 0 ) {\n\n\t\t\tif ( loopCount === - 1 ) return time;\n\n\t\t\treturn ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time;\n\n\t\t}\n\n\t\tif ( loop === LoopOnce ) {\n\n\t\t\tif ( loopCount === - 1 ) {\n\n\t\t\t\t// just started\n\n\t\t\t\tthis._loopCount = 0;\n\t\t\t\tthis._setEndings( true, true, false );\n\n\t\t\t}\n\n\t\t\thandle_stop: {\n\n\t\t\t\tif ( time >= duration ) {\n\n\t\t\t\t\ttime = duration;\n\n\t\t\t\t} else if ( time < 0 ) {\n\n\t\t\t\t\ttime = 0;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis.time = time;\n\n\t\t\t\t\tbreak handle_stop;\n\n\t\t\t\t}\n\n\t\t\t\tif ( this.clampWhenFinished ) this.paused = true;\n\t\t\t\telse this.enabled = false;\n\n\t\t\t\tthis.time = time;\n\n\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\ttype: 'finished', action: this,\n\t\t\t\t\tdirection: deltaTime < 0 ? - 1 : 1\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t} else { // repetitive Repeat or PingPong\n\n\t\t\tif ( loopCount === - 1 ) {\n\n\t\t\t\t// just started\n\n\t\t\t\tif ( deltaTime >= 0 ) {\n\n\t\t\t\t\tloopCount = 0;\n\n\t\t\t\t\tthis._setEndings( true, this.repetitions === 0, pingPong );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// when looping in reverse direction, the initial\n\t\t\t\t\t// transition through zero counts as a repetition,\n\t\t\t\t\t// so leave loopCount at -1\n\n\t\t\t\t\tthis._setEndings( this.repetitions === 0, true, pingPong );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( time >= duration || time < 0 ) {\n\n\t\t\t\t// wrap around\n\n\t\t\t\tconst loopDelta = Math.floor( time / duration ); // signed\n\t\t\t\ttime -= duration * loopDelta;\n\n\t\t\t\tloopCount += Math.abs( loopDelta );\n\n\t\t\t\tconst pending = this.repetitions - loopCount;\n\n\t\t\t\tif ( pending <= 0 ) {\n\n\t\t\t\t\t// have to stop (switch state, clamp time, fire event)\n\n\t\t\t\t\tif ( this.clampWhenFinished ) this.paused = true;\n\t\t\t\t\telse this.enabled = false;\n\n\t\t\t\t\ttime = deltaTime > 0 ? duration : 0;\n\n\t\t\t\t\tthis.time = time;\n\n\t\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\t\ttype: 'finished', action: this,\n\t\t\t\t\t\tdirection: deltaTime > 0 ? 1 : - 1\n\t\t\t\t\t} );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// keep running\n\n\t\t\t\t\tif ( pending === 1 ) {\n\n\t\t\t\t\t\t// entering the last round\n\n\t\t\t\t\t\tconst atStart = deltaTime < 0;\n\t\t\t\t\t\tthis._setEndings( atStart, ! atStart, pingPong );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tthis._setEndings( false, false, pingPong );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._loopCount = loopCount;\n\n\t\t\t\t\tthis.time = time;\n\n\t\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\t\ttype: 'loop', action: this, loopDelta: loopDelta\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tthis.time = time;\n\n\t\t\t}\n\n\t\t\tif ( pingPong && ( loopCount & 1 ) === 1 ) {\n\n\t\t\t\t// invert time for the \"pong round\"\n\n\t\t\t\treturn duration - time;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn time;\n\n\t}\n\n\t_setEndings( atStart, atEnd, pingPong ) {\n\n\t\tconst settings = this._interpolantSettings;\n\n\t\tif ( pingPong ) {\n\n\t\t\tsettings.endingStart = ZeroSlopeEnding;\n\t\t\tsettings.endingEnd = ZeroSlopeEnding;\n\n\t\t} else {\n\n\t\t\t// assuming for LoopOnce atStart == atEnd == true\n\n\t\t\tif ( atStart ) {\n\n\t\t\t\tsettings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;\n\n\t\t\t} else {\n\n\t\t\t\tsettings.endingStart = WrapAroundEnding;\n\n\t\t\t}\n\n\t\t\tif ( atEnd ) {\n\n\t\t\t\tsettings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;\n\n\t\t\t} else {\n\n\t\t\t\tsettings.endingEnd \t = WrapAroundEnding;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_scheduleFading( duration, weightNow, weightThen ) {\n\n\t\tconst mixer = this._mixer, now = mixer.time;\n\t\tlet interpolant = this._weightInterpolant;\n\n\t\tif ( interpolant === null ) {\n\n\t\t\tinterpolant = mixer._lendControlInterpolant();\n\t\t\tthis._weightInterpolant = interpolant;\n\n\t\t}\n\n\t\tconst times = interpolant.parameterPositions,\n\t\t\tvalues = interpolant.sampleValues;\n\n\t\ttimes[ 0 ] = now;\n\t\tvalues[ 0 ] = weightNow;\n\t\ttimes[ 1 ] = now + duration;\n\t\tvalues[ 1 ] = weightThen;\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _controlInterpolantsResultBuffer = new Float32Array( 1 );\n\n\nclass AnimationMixer extends EventDispatcher {\n\n\tconstructor( root ) {\n\n\t\tsuper();\n\n\t\tthis._root = root;\n\t\tthis._initMemoryManager();\n\t\tthis._accuIndex = 0;\n\t\tthis.time = 0;\n\t\tthis.timeScale = 1.0;\n\n\t}\n\n\t_bindAction( action, prototypeAction ) {\n\n\t\tconst root = action._localRoot || this._root,\n\t\t\ttracks = action._clip.tracks,\n\t\t\tnTracks = tracks.length,\n\t\t\tbindings = action._propertyBindings,\n\t\t\tinterpolants = action._interpolants,\n\t\t\trootUuid = root.uuid,\n\t\t\tbindingsByRoot = this._bindingsByRootAndName;\n\n\t\tlet bindingsByName = bindingsByRoot[ rootUuid ];\n\n\t\tif ( bindingsByName === undefined ) {\n\n\t\t\tbindingsByName = {};\n\t\t\tbindingsByRoot[ rootUuid ] = bindingsByName;\n\n\t\t}\n\n\t\tfor ( let i = 0; i !== nTracks; ++ i ) {\n\n\t\t\tconst track = tracks[ i ],\n\t\t\t\ttrackName = track.name;\n\n\t\t\tlet binding = bindingsByName[ trackName ];\n\n\t\t\tif ( binding !== undefined ) {\n\n\t\t\t\t++ binding.referenceCount;\n\t\t\t\tbindings[ i ] = binding;\n\n\t\t\t} else {\n\n\t\t\t\tbinding = bindings[ i ];\n\n\t\t\t\tif ( binding !== undefined ) {\n\n\t\t\t\t\t// existing binding, make sure the cache knows\n\n\t\t\t\t\tif ( binding._cacheIndex === null ) {\n\n\t\t\t\t\t\t++ binding.referenceCount;\n\t\t\t\t\t\tthis._addInactiveBinding( binding, rootUuid, trackName );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\tconst path = prototypeAction && prototypeAction.\n\t\t\t\t\t_propertyBindings[ i ].binding.parsedPath;\n\n\t\t\t\tbinding = new PropertyMixer(\n\t\t\t\t\tPropertyBinding.create( root, trackName, path ),\n\t\t\t\t\ttrack.ValueTypeName, track.getValueSize() );\n\n\t\t\t\t++ binding.referenceCount;\n\t\t\t\tthis._addInactiveBinding( binding, rootUuid, trackName );\n\n\t\t\t\tbindings[ i ] = binding;\n\n\t\t\t}\n\n\t\t\tinterpolants[ i ].resultBuffer = binding.buffer;\n\n\t\t}\n\n\t}\n\n\t_activateAction( action ) {\n\n\t\tif ( ! this._isActiveAction( action ) ) {\n\n\t\t\tif ( action._cacheIndex === null ) {\n\n\t\t\t\t// this action has been forgotten by the cache, but the user\n\t\t\t\t// appears to be still using it -> rebind\n\n\t\t\t\tconst rootUuid = ( action._localRoot || this._root ).uuid,\n\t\t\t\t\tclipUuid = action._clip.uuid,\n\t\t\t\t\tactionsForClip = this._actionsByClip[ clipUuid ];\n\n\t\t\t\tthis._bindAction( action,\n\t\t\t\t\tactionsForClip && actionsForClip.knownActions[ 0 ] );\n\n\t\t\t\tthis._addInactiveAction( action, clipUuid, rootUuid );\n\n\t\t\t}\n\n\t\t\tconst bindings = action._propertyBindings;\n\n\t\t\t// increment reference counts / sort out state\n\t\t\tfor ( let i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\tconst binding = bindings[ i ];\n\n\t\t\t\tif ( binding.useCount ++ === 0 ) {\n\n\t\t\t\t\tthis._lendBinding( binding );\n\t\t\t\t\tbinding.saveOriginalState();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis._lendAction( action );\n\n\t\t}\n\n\t}\n\n\t_deactivateAction( action ) {\n\n\t\tif ( this._isActiveAction( action ) ) {\n\n\t\t\tconst bindings = action._propertyBindings;\n\n\t\t\t// decrement reference counts / sort out state\n\t\t\tfor ( let i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\tconst binding = bindings[ i ];\n\n\t\t\t\tif ( -- binding.useCount === 0 ) {\n\n\t\t\t\t\tbinding.restoreOriginalState();\n\t\t\t\t\tthis._takeBackBinding( binding );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis._takeBackAction( action );\n\n\t\t}\n\n\t}\n\n\t// Memory manager\n\n\t_initMemoryManager() {\n\n\t\tthis._actions = []; // 'nActiveActions' followed by inactive ones\n\t\tthis._nActiveActions = 0;\n\n\t\tthis._actionsByClip = {};\n\t\t// inside:\n\t\t// {\n\t\t// \tknownActions: Array< AnimationAction > - used as prototypes\n\t\t// \tactionByRoot: AnimationAction - lookup\n\t\t// }\n\n\n\t\tthis._bindings = []; // 'nActiveBindings' followed by inactive ones\n\t\tthis._nActiveBindings = 0;\n\n\t\tthis._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >\n\n\n\t\tthis._controlInterpolants = []; // same game as above\n\t\tthis._nActiveControlInterpolants = 0;\n\n\t\tconst scope = this;\n\n\t\tthis.stats = {\n\n\t\t\tactions: {\n\t\t\t\tget total() {\n\n\t\t\t\t\treturn scope._actions.length;\n\n\t\t\t\t},\n\t\t\t\tget inUse() {\n\n\t\t\t\t\treturn scope._nActiveActions;\n\n\t\t\t\t}\n\t\t\t},\n\t\t\tbindings: {\n\t\t\t\tget total() {\n\n\t\t\t\t\treturn scope._bindings.length;\n\n\t\t\t\t},\n\t\t\t\tget inUse() {\n\n\t\t\t\t\treturn scope._nActiveBindings;\n\n\t\t\t\t}\n\t\t\t},\n\t\t\tcontrolInterpolants: {\n\t\t\t\tget total() {\n\n\t\t\t\t\treturn scope._controlInterpolants.length;\n\n\t\t\t\t},\n\t\t\t\tget inUse() {\n\n\t\t\t\t\treturn scope._nActiveControlInterpolants;\n\n\t\t\t\t}\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\t// Memory management for AnimationAction objects\n\n\t_isActiveAction( action ) {\n\n\t\tconst index = action._cacheIndex;\n\t\treturn index !== null && index < this._nActiveActions;\n\n\t}\n\n\t_addInactiveAction( action, clipUuid, rootUuid ) {\n\n\t\tconst actions = this._actions,\n\t\t\tactionsByClip = this._actionsByClip;\n\n\t\tlet actionsForClip = actionsByClip[ clipUuid ];\n\n\t\tif ( actionsForClip === undefined ) {\n\n\t\t\tactionsForClip = {\n\n\t\t\t\tknownActions: [ action ],\n\t\t\t\tactionByRoot: {}\n\n\t\t\t};\n\n\t\t\taction._byClipCacheIndex = 0;\n\n\t\t\tactionsByClip[ clipUuid ] = actionsForClip;\n\n\t\t} else {\n\n\t\t\tconst knownActions = actionsForClip.knownActions;\n\n\t\t\taction._byClipCacheIndex = knownActions.length;\n\t\t\tknownActions.push( action );\n\n\t\t}\n\n\t\taction._cacheIndex = actions.length;\n\t\tactions.push( action );\n\n\t\tactionsForClip.actionByRoot[ rootUuid ] = action;\n\n\t}\n\n\t_removeInactiveAction( action ) {\n\n\t\tconst actions = this._actions,\n\t\t\tlastInactiveAction = actions[ actions.length - 1 ],\n\t\t\tcacheIndex = action._cacheIndex;\n\n\t\tlastInactiveAction._cacheIndex = cacheIndex;\n\t\tactions[ cacheIndex ] = lastInactiveAction;\n\t\tactions.pop();\n\n\t\taction._cacheIndex = null;\n\n\n\t\tconst clipUuid = action._clip.uuid,\n\t\t\tactionsByClip = this._actionsByClip,\n\t\t\tactionsForClip = actionsByClip[ clipUuid ],\n\t\t\tknownActionsForClip = actionsForClip.knownActions,\n\n\t\t\tlastKnownAction =\n\t\t\t\tknownActionsForClip[ knownActionsForClip.length - 1 ],\n\n\t\t\tbyClipCacheIndex = action._byClipCacheIndex;\n\n\t\tlastKnownAction._byClipCacheIndex = byClipCacheIndex;\n\t\tknownActionsForClip[ byClipCacheIndex ] = lastKnownAction;\n\t\tknownActionsForClip.pop();\n\n\t\taction._byClipCacheIndex = null;\n\n\n\t\tconst actionByRoot = actionsForClip.actionByRoot,\n\t\t\trootUuid = ( action._localRoot || this._root ).uuid;\n\n\t\tdelete actionByRoot[ rootUuid ];\n\n\t\tif ( knownActionsForClip.length === 0 ) {\n\n\t\t\tdelete actionsByClip[ clipUuid ];\n\n\t\t}\n\n\t\tthis._removeInactiveBindingsForAction( action );\n\n\t}\n\n\t_removeInactiveBindingsForAction( action ) {\n\n\t\tconst bindings = action._propertyBindings;\n\n\t\tfor ( let i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\tconst binding = bindings[ i ];\n\n\t\t\tif ( -- binding.referenceCount === 0 ) {\n\n\t\t\t\tthis._removeInactiveBinding( binding );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_lendAction( action ) {\n\n\t\t// [ active actions | inactive actions ]\n\t\t// [ active actions >| inactive actions ]\n\t\t// s a\n\t\t// <-swap->\n\t\t// a s\n\n\t\tconst actions = this._actions,\n\t\t\tprevIndex = action._cacheIndex,\n\n\t\t\tlastActiveIndex = this._nActiveActions ++,\n\n\t\t\tfirstInactiveAction = actions[ lastActiveIndex ];\n\n\t\taction._cacheIndex = lastActiveIndex;\n\t\tactions[ lastActiveIndex ] = action;\n\n\t\tfirstInactiveAction._cacheIndex = prevIndex;\n\t\tactions[ prevIndex ] = firstInactiveAction;\n\n\t}\n\n\t_takeBackAction( action ) {\n\n\t\t// [ active actions | inactive actions ]\n\t\t// [ active actions |< inactive actions ]\n\t\t// a s\n\t\t// <-swap->\n\t\t// s a\n\n\t\tconst actions = this._actions,\n\t\t\tprevIndex = action._cacheIndex,\n\n\t\t\tfirstInactiveIndex = -- this._nActiveActions,\n\n\t\t\tlastActiveAction = actions[ firstInactiveIndex ];\n\n\t\taction._cacheIndex = firstInactiveIndex;\n\t\tactions[ firstInactiveIndex ] = action;\n\n\t\tlastActiveAction._cacheIndex = prevIndex;\n\t\tactions[ prevIndex ] = lastActiveAction;\n\n\t}\n\n\t// Memory management for PropertyMixer objects\n\n\t_addInactiveBinding( binding, rootUuid, trackName ) {\n\n\t\tconst bindingsByRoot = this._bindingsByRootAndName,\n\t\t\tbindings = this._bindings;\n\n\t\tlet bindingByName = bindingsByRoot[ rootUuid ];\n\n\t\tif ( bindingByName === undefined ) {\n\n\t\t\tbindingByName = {};\n\t\t\tbindingsByRoot[ rootUuid ] = bindingByName;\n\n\t\t}\n\n\t\tbindingByName[ trackName ] = binding;\n\n\t\tbinding._cacheIndex = bindings.length;\n\t\tbindings.push( binding );\n\n\t}\n\n\t_removeInactiveBinding( binding ) {\n\n\t\tconst bindings = this._bindings,\n\t\t\tpropBinding = binding.binding,\n\t\t\trootUuid = propBinding.rootNode.uuid,\n\t\t\ttrackName = propBinding.path,\n\t\t\tbindingsByRoot = this._bindingsByRootAndName,\n\t\t\tbindingByName = bindingsByRoot[ rootUuid ],\n\n\t\t\tlastInactiveBinding = bindings[ bindings.length - 1 ],\n\t\t\tcacheIndex = binding._cacheIndex;\n\n\t\tlastInactiveBinding._cacheIndex = cacheIndex;\n\t\tbindings[ cacheIndex ] = lastInactiveBinding;\n\t\tbindings.pop();\n\n\t\tdelete bindingByName[ trackName ];\n\n\t\tif ( Object.keys( bindingByName ).length === 0 ) {\n\n\t\t\tdelete bindingsByRoot[ rootUuid ];\n\n\t\t}\n\n\t}\n\n\t_lendBinding( binding ) {\n\n\t\tconst bindings = this._bindings,\n\t\t\tprevIndex = binding._cacheIndex,\n\n\t\t\tlastActiveIndex = this._nActiveBindings ++,\n\n\t\t\tfirstInactiveBinding = bindings[ lastActiveIndex ];\n\n\t\tbinding._cacheIndex = lastActiveIndex;\n\t\tbindings[ lastActiveIndex ] = binding;\n\n\t\tfirstInactiveBinding._cacheIndex = prevIndex;\n\t\tbindings[ prevIndex ] = firstInactiveBinding;\n\n\t}\n\n\t_takeBackBinding( binding ) {\n\n\t\tconst bindings = this._bindings,\n\t\t\tprevIndex = binding._cacheIndex,\n\n\t\t\tfirstInactiveIndex = -- this._nActiveBindings,\n\n\t\t\tlastActiveBinding = bindings[ firstInactiveIndex ];\n\n\t\tbinding._cacheIndex = firstInactiveIndex;\n\t\tbindings[ firstInactiveIndex ] = binding;\n\n\t\tlastActiveBinding._cacheIndex = prevIndex;\n\t\tbindings[ prevIndex ] = lastActiveBinding;\n\n\t}\n\n\n\t// Memory management of Interpolants for weight and time scale\n\n\t_lendControlInterpolant() {\n\n\t\tconst interpolants = this._controlInterpolants,\n\t\t\tlastActiveIndex = this._nActiveControlInterpolants ++;\n\n\t\tlet interpolant = interpolants[ lastActiveIndex ];\n\n\t\tif ( interpolant === undefined ) {\n\n\t\t\tinterpolant = new LinearInterpolant(\n\t\t\t\tnew Float32Array( 2 ), new Float32Array( 2 ),\n\t\t\t\t1, _controlInterpolantsResultBuffer );\n\n\t\t\tinterpolant.__cacheIndex = lastActiveIndex;\n\t\t\tinterpolants[ lastActiveIndex ] = interpolant;\n\n\t\t}\n\n\t\treturn interpolant;\n\n\t}\n\n\t_takeBackControlInterpolant( interpolant ) {\n\n\t\tconst interpolants = this._controlInterpolants,\n\t\t\tprevIndex = interpolant.__cacheIndex,\n\n\t\t\tfirstInactiveIndex = -- this._nActiveControlInterpolants,\n\n\t\t\tlastActiveInterpolant = interpolants[ firstInactiveIndex ];\n\n\t\tinterpolant.__cacheIndex = firstInactiveIndex;\n\t\tinterpolants[ firstInactiveIndex ] = interpolant;\n\n\t\tlastActiveInterpolant.__cacheIndex = prevIndex;\n\t\tinterpolants[ prevIndex ] = lastActiveInterpolant;\n\n\t}\n\n\t// return an action for a clip optionally using a custom root target\n\t// object (this method allocates a lot of dynamic memory in case a\n\t// previously unknown clip/root combination is specified)\n\tclipAction( clip, optionalRoot, blendMode ) {\n\n\t\tconst root = optionalRoot || this._root,\n\t\t\trootUuid = root.uuid;\n\n\t\tlet clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip;\n\n\t\tconst clipUuid = clipObject !== null ? clipObject.uuid : clip;\n\n\t\tconst actionsForClip = this._actionsByClip[ clipUuid ];\n\t\tlet prototypeAction = null;\n\n\t\tif ( blendMode === undefined ) {\n\n\t\t\tif ( clipObject !== null ) {\n\n\t\t\t\tblendMode = clipObject.blendMode;\n\n\t\t\t} else {\n\n\t\t\t\tblendMode = NormalAnimationBlendMode;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\tconst existingAction = actionsForClip.actionByRoot[ rootUuid ];\n\n\t\t\tif ( existingAction !== undefined && existingAction.blendMode === blendMode ) {\n\n\t\t\t\treturn existingAction;\n\n\t\t\t}\n\n\t\t\t// we know the clip, so we don't have to parse all\n\t\t\t// the bindings again but can just copy\n\t\t\tprototypeAction = actionsForClip.knownActions[ 0 ];\n\n\t\t\t// also, take the clip from the prototype action\n\t\t\tif ( clipObject === null )\n\t\t\t\tclipObject = prototypeAction._clip;\n\n\t\t}\n\n\t\t// clip must be known when specified via string\n\t\tif ( clipObject === null ) return null;\n\n\t\t// allocate all resources required to run it\n\t\tconst newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode );\n\n\t\tthis._bindAction( newAction, prototypeAction );\n\n\t\t// and make the action known to the memory manager\n\t\tthis._addInactiveAction( newAction, clipUuid, rootUuid );\n\n\t\treturn newAction;\n\n\t}\n\n\t// get an existing action\n\texistingAction( clip, optionalRoot ) {\n\n\t\tconst root = optionalRoot || this._root,\n\t\t\trootUuid = root.uuid,\n\n\t\t\tclipObject = typeof clip === 'string' ?\n\t\t\t\tAnimationClip.findByName( root, clip ) : clip,\n\n\t\t\tclipUuid = clipObject ? clipObject.uuid : clip,\n\n\t\t\tactionsForClip = this._actionsByClip[ clipUuid ];\n\n\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\treturn actionsForClip.actionByRoot[ rootUuid ] || null;\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n\t// deactivates all previously scheduled actions\n\tstopAllAction() {\n\n\t\tconst actions = this._actions,\n\t\t\tnActions = this._nActiveActions;\n\n\t\tfor ( let i = nActions - 1; i >= 0; -- i ) {\n\n\t\t\tactions[ i ].stop();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// advance the time and update apply the animation\n\tupdate( deltaTime ) {\n\n\t\tdeltaTime *= this.timeScale;\n\n\t\tconst actions = this._actions,\n\t\t\tnActions = this._nActiveActions,\n\n\t\t\ttime = this.time += deltaTime,\n\t\t\ttimeDirection = Math.sign( deltaTime ),\n\n\t\t\taccuIndex = this._accuIndex ^= 1;\n\n\t\t// run active actions\n\n\t\tfor ( let i = 0; i !== nActions; ++ i ) {\n\n\t\t\tconst action = actions[ i ];\n\n\t\t\taction._update( time, deltaTime, timeDirection, accuIndex );\n\n\t\t}\n\n\t\t// update scene graph\n\n\t\tconst bindings = this._bindings,\n\t\t\tnBindings = this._nActiveBindings;\n\n\t\tfor ( let i = 0; i !== nBindings; ++ i ) {\n\n\t\t\tbindings[ i ].apply( accuIndex );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// Allows you to seek to a specific time in an animation.\n\tsetTime( timeInSeconds ) {\n\n\t\tthis.time = 0; // Zero out time attribute for AnimationMixer object;\n\t\tfor ( let i = 0; i < this._actions.length; i ++ ) {\n\n\t\t\tthis._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects.\n\n\t\t}\n\n\t\treturn this.update( timeInSeconds ); // Update used to set exact time. Returns \"this\" AnimationMixer object.\n\n\t}\n\n\t// return this mixer's root target object\n\tgetRoot() {\n\n\t\treturn this._root;\n\n\t}\n\n\t// free all resources specific to a particular clip\n\tuncacheClip( clip ) {\n\n\t\tconst actions = this._actions,\n\t\t\tclipUuid = clip.uuid,\n\t\t\tactionsByClip = this._actionsByClip,\n\t\t\tactionsForClip = actionsByClip[ clipUuid ];\n\n\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\t// note: just calling _removeInactiveAction would mess up the\n\t\t\t// iteration state and also require updating the state we can\n\t\t\t// just throw away\n\n\t\t\tconst actionsToRemove = actionsForClip.knownActions;\n\n\t\t\tfor ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) {\n\n\t\t\t\tconst action = actionsToRemove[ i ];\n\n\t\t\t\tthis._deactivateAction( action );\n\n\t\t\t\tconst cacheIndex = action._cacheIndex,\n\t\t\t\t\tlastInactiveAction = actions[ actions.length - 1 ];\n\n\t\t\t\taction._cacheIndex = null;\n\t\t\t\taction._byClipCacheIndex = null;\n\n\t\t\t\tlastInactiveAction._cacheIndex = cacheIndex;\n\t\t\t\tactions[ cacheIndex ] = lastInactiveAction;\n\t\t\t\tactions.pop();\n\n\t\t\t\tthis._removeInactiveBindingsForAction( action );\n\n\t\t\t}\n\n\t\t\tdelete actionsByClip[ clipUuid ];\n\n\t\t}\n\n\t}\n\n\t// free all resources specific to a particular root target object\n\tuncacheRoot( root ) {\n\n\t\tconst rootUuid = root.uuid,\n\t\t\tactionsByClip = this._actionsByClip;\n\n\t\tfor ( const clipUuid in actionsByClip ) {\n\n\t\t\tconst actionByRoot = actionsByClip[ clipUuid ].actionByRoot,\n\t\t\t\taction = actionByRoot[ rootUuid ];\n\n\t\t\tif ( action !== undefined ) {\n\n\t\t\t\tthis._deactivateAction( action );\n\t\t\t\tthis._removeInactiveAction( action );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst bindingsByRoot = this._bindingsByRootAndName,\n\t\t\tbindingByName = bindingsByRoot[ rootUuid ];\n\n\t\tif ( bindingByName !== undefined ) {\n\n\t\t\tfor ( const trackName in bindingByName ) {\n\n\t\t\t\tconst binding = bindingByName[ trackName ];\n\t\t\t\tbinding.restoreOriginalState();\n\t\t\t\tthis._removeInactiveBinding( binding );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// remove a targeted clip from the cache\n\tuncacheAction( clip, optionalRoot ) {\n\n\t\tconst action = this.existingAction( clip, optionalRoot );\n\n\t\tif ( action !== null ) {\n\n\t\t\tthis._deactivateAction( action );\n\t\t\tthis._removeInactiveAction( action );\n\n\t\t}\n\n\t}\n\n}\n\nclass Uniform {\n\n\tconstructor( value ) {\n\n\t\tthis.value = value;\n\n\t}\n\n\tclone() {\n\n\t\treturn new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );\n\n\t}\n\n}\n\nlet _id = 0;\n\nclass UniformsGroup extends EventDispatcher {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isUniformsGroup = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _id ++ } );\n\n\t\tthis.name = '';\n\n\t\tthis.usage = StaticDrawUsage;\n\t\tthis.uniforms = [];\n\n\t}\n\n\tadd( uniform ) {\n\n\t\tthis.uniforms.push( uniform );\n\n\t\treturn this;\n\n\t}\n\n\tremove( uniform ) {\n\n\t\tconst index = this.uniforms.indexOf( uniform );\n\n\t\tif ( index !== - 1 ) this.uniforms.splice( index, 1 );\n\n\t\treturn this;\n\n\t}\n\n\tsetName( name ) {\n\n\t\tthis.name = name;\n\n\t\treturn this;\n\n\t}\n\n\tsetUsage( value ) {\n\n\t\tthis.usage = value;\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.name = source.name;\n\t\tthis.usage = source.usage;\n\n\t\tconst uniformsSource = source.uniforms;\n\n\t\tthis.uniforms.length = 0;\n\n\t\tfor ( let i = 0, l = uniformsSource.length; i < l; i ++ ) {\n\n\t\t\tconst uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ];\n\n\t\t\tfor ( let j = 0; j < uniforms.length; j ++ ) {\n\n\t\t\t\tthis.uniforms.push( uniforms[ j ].clone() );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nclass InstancedInterleavedBuffer extends InterleavedBuffer {\n\n\tconstructor( array, stride, meshPerAttribute = 1 ) {\n\n\t\tsuper( array, stride );\n\n\t\tthis.isInstancedInterleavedBuffer = true;\n\n\t\tthis.meshPerAttribute = meshPerAttribute;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.meshPerAttribute = source.meshPerAttribute;\n\n\t\treturn this;\n\n\t}\n\n\tclone( data ) {\n\n\t\tconst ib = super.clone( data );\n\n\t\tib.meshPerAttribute = this.meshPerAttribute;\n\n\t\treturn ib;\n\n\t}\n\n\ttoJSON( data ) {\n\n\t\tconst json = super.toJSON( data );\n\n\t\tjson.isInstancedInterleavedBuffer = true;\n\t\tjson.meshPerAttribute = this.meshPerAttribute;\n\n\t\treturn json;\n\n\t}\n\n}\n\nclass GLBufferAttribute {\n\n\tconstructor( buffer, type, itemSize, elementSize, count ) {\n\n\t\tthis.isGLBufferAttribute = true;\n\n\t\tthis.name = '';\n\n\t\tthis.buffer = buffer;\n\t\tthis.type = type;\n\t\tthis.itemSize = itemSize;\n\t\tthis.elementSize = elementSize;\n\t\tthis.count = count;\n\n\t\tthis.version = 0;\n\n\t}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t}\n\n\tsetBuffer( buffer ) {\n\n\t\tthis.buffer = buffer;\n\n\t\treturn this;\n\n\t}\n\n\tsetType( type, elementSize ) {\n\n\t\tthis.type = type;\n\t\tthis.elementSize = elementSize;\n\n\t\treturn this;\n\n\t}\n\n\tsetItemSize( itemSize ) {\n\n\t\tthis.itemSize = itemSize;\n\n\t\treturn this;\n\n\t}\n\n\tsetCount( count ) {\n\n\t\tthis.count = count;\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _matrix = /*@__PURE__*/ new Matrix4();\n\nclass Raycaster {\n\n\tconstructor( origin, direction, near = 0, far = Infinity ) {\n\n\t\tthis.ray = new Ray( origin, direction );\n\t\t// direction is assumed to be normalized (for accurate distance calculations)\n\n\t\tthis.near = near;\n\t\tthis.far = far;\n\t\tthis.camera = null;\n\t\tthis.layers = new Layers();\n\n\t\tthis.params = {\n\t\t\tMesh: {},\n\t\t\tLine: { threshold: 1 },\n\t\t\tLOD: {},\n\t\t\tPoints: { threshold: 1 },\n\t\t\tSprite: {}\n\t\t};\n\n\t}\n\n\tset( origin, direction ) {\n\n\t\t// direction is assumed to be normalized (for accurate distance calculations)\n\n\t\tthis.ray.set( origin, direction );\n\n\t}\n\n\tsetFromCamera( coords, camera ) {\n\n\t\tif ( camera.isPerspectiveCamera ) {\n\n\t\t\tthis.ray.origin.setFromMatrixPosition( camera.matrixWorld );\n\t\t\tthis.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();\n\t\t\tthis.camera = camera;\n\n\t\t} else if ( camera.isOrthographicCamera ) {\n\n\t\t\tthis.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera\n\t\t\tthis.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );\n\t\t\tthis.camera = camera;\n\n\t\t} else {\n\n\t\t\tconsole.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type );\n\n\t\t}\n\n\t}\n\n\tsetFromXRController( controller ) {\n\n\t\t_matrix.identity().extractRotation( controller.matrixWorld );\n\n\t\tthis.ray.origin.setFromMatrixPosition( controller.matrixWorld );\n\t\tthis.ray.direction.set( 0, 0, - 1 ).applyMatrix4( _matrix );\n\n\t\treturn this;\n\n\t}\n\n\tintersectObject( object, recursive = true, intersects = [] ) {\n\n\t\tintersect( object, this, intersects, recursive );\n\n\t\tintersects.sort( ascSort );\n\n\t\treturn intersects;\n\n\t}\n\n\tintersectObjects( objects, recursive = true, intersects = [] ) {\n\n\t\tfor ( let i = 0, l = objects.length; i < l; i ++ ) {\n\n\t\t\tintersect( objects[ i ], this, intersects, recursive );\n\n\t\t}\n\n\t\tintersects.sort( ascSort );\n\n\t\treturn intersects;\n\n\t}\n\n}\n\nfunction ascSort( a, b ) {\n\n\treturn a.distance - b.distance;\n\n}\n\nfunction intersect( object, raycaster, intersects, recursive ) {\n\n\tlet propagate = true;\n\n\tif ( object.layers.test( raycaster.layers ) ) {\n\n\t\tconst result = object.raycast( raycaster, intersects );\n\n\t\tif ( result === false ) propagate = false;\n\n\t}\n\n\tif ( propagate === true && recursive === true ) {\n\n\t\tconst children = object.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tintersect( children[ i ], raycaster, intersects, true );\n\n\t\t}\n\n\t}\n\n}\n\n/**\n * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system\n *\n * phi (the polar angle) is measured from the positive y-axis. The positive y-axis is up.\n * theta (the azimuthal angle) is measured from the positive z-axis.\n */\nclass Spherical {\n\n\tconstructor( radius = 1, phi = 0, theta = 0 ) {\n\n\t\tthis.radius = radius;\n\t\tthis.phi = phi; // polar angle\n\t\tthis.theta = theta; // azimuthal angle\n\n\t\treturn this;\n\n\t}\n\n\tset( radius, phi, theta ) {\n\n\t\tthis.radius = radius;\n\t\tthis.phi = phi;\n\t\tthis.theta = theta;\n\n\t\treturn this;\n\n\t}\n\n\tcopy( other ) {\n\n\t\tthis.radius = other.radius;\n\t\tthis.phi = other.phi;\n\t\tthis.theta = other.theta;\n\n\t\treturn this;\n\n\t}\n\n\t// restrict phi to be between EPS and PI-EPS\n\tmakeSafe() {\n\n\t\tconst EPS = 0.000001;\n\t\tthis.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromVector3( v ) {\n\n\t\treturn this.setFromCartesianCoords( v.x, v.y, v.z );\n\n\t}\n\n\tsetFromCartesianCoords( x, y, z ) {\n\n\t\tthis.radius = Math.sqrt( x * x + y * y + z * z );\n\n\t\tif ( this.radius === 0 ) {\n\n\t\t\tthis.theta = 0;\n\t\t\tthis.phi = 0;\n\n\t\t} else {\n\n\t\t\tthis.theta = Math.atan2( x, z );\n\t\t\tthis.phi = Math.acos( clamp( y / this.radius, - 1, 1 ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\n/**\n * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system\n */\n\nclass Cylindrical {\n\n\tconstructor( radius = 1, theta = 0, y = 0 ) {\n\n\t\tthis.radius = radius; // distance from the origin to a point in the x-z plane\n\t\tthis.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis\n\t\tthis.y = y; // height above the x-z plane\n\n\t\treturn this;\n\n\t}\n\n\tset( radius, theta, y ) {\n\n\t\tthis.radius = radius;\n\t\tthis.theta = theta;\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tcopy( other ) {\n\n\t\tthis.radius = other.radius;\n\t\tthis.theta = other.theta;\n\t\tthis.y = other.y;\n\n\t\treturn this;\n\n\t}\n\n\tsetFromVector3( v ) {\n\n\t\treturn this.setFromCartesianCoords( v.x, v.y, v.z );\n\n\t}\n\n\tsetFromCartesianCoords( x, y, z ) {\n\n\t\tthis.radius = Math.sqrt( x * x + z * z );\n\t\tthis.theta = Math.atan2( x, z );\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nconst _vector$4 = /*@__PURE__*/ new Vector2();\n\nclass Box2 {\n\n\tconstructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) {\n\n\t\tthis.isBox2 = true;\n\n\t\tthis.min = min;\n\t\tthis.max = max;\n\n\t}\n\n\tset( min, max ) {\n\n\t\tthis.min.copy( min );\n\t\tthis.max.copy( max );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromPoints( points ) {\n\n\t\tthis.makeEmpty();\n\n\t\tfor ( let i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\tthis.expandByPoint( points[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetFromCenterAndSize( center, size ) {\n\n\t\tconst halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 );\n\t\tthis.min.copy( center ).sub( halfSize );\n\t\tthis.max.copy( center ).add( halfSize );\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( box ) {\n\n\t\tthis.min.copy( box.min );\n\t\tthis.max.copy( box.max );\n\n\t\treturn this;\n\n\t}\n\n\tmakeEmpty() {\n\n\t\tthis.min.x = this.min.y = + Infinity;\n\t\tthis.max.x = this.max.y = - Infinity;\n\n\t\treturn this;\n\n\t}\n\n\tisEmpty() {\n\n\t\t// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes\n\n\t\treturn ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );\n\n\t}\n\n\tgetCenter( target ) {\n\n\t\treturn this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );\n\n\t}\n\n\tgetSize( target ) {\n\n\t\treturn this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min );\n\n\t}\n\n\texpandByPoint( point ) {\n\n\t\tthis.min.min( point );\n\t\tthis.max.max( point );\n\n\t\treturn this;\n\n\t}\n\n\texpandByVector( vector ) {\n\n\t\tthis.min.sub( vector );\n\t\tthis.max.add( vector );\n\n\t\treturn this;\n\n\t}\n\n\texpandByScalar( scalar ) {\n\n\t\tthis.min.addScalar( - scalar );\n\t\tthis.max.addScalar( scalar );\n\n\t\treturn this;\n\n\t}\n\n\tcontainsPoint( point ) {\n\n\t\treturn point.x < this.min.x || point.x > this.max.x ||\n\t\t\tpoint.y < this.min.y || point.y > this.max.y ? false : true;\n\n\t}\n\n\tcontainsBox( box ) {\n\n\t\treturn this.min.x <= box.min.x && box.max.x <= this.max.x &&\n\t\t\tthis.min.y <= box.min.y && box.max.y <= this.max.y;\n\n\t}\n\n\tgetParameter( point, target ) {\n\n\t\t// This can potentially have a divide by zero if the box\n\t\t// has a size dimension of 0.\n\n\t\treturn target.set(\n\t\t\t( point.x - this.min.x ) / ( this.max.x - this.min.x ),\n\t\t\t( point.y - this.min.y ) / ( this.max.y - this.min.y )\n\t\t);\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\t// using 4 splitting planes to rule out intersections\n\n\t\treturn box.max.x < this.min.x || box.min.x > this.max.x ||\n\t\t\tbox.max.y < this.min.y || box.min.y > this.max.y ? false : true;\n\n\t}\n\n\tclampPoint( point, target ) {\n\n\t\treturn target.copy( point ).clamp( this.min, this.max );\n\n\t}\n\n\tdistanceToPoint( point ) {\n\n\t\treturn this.clampPoint( point, _vector$4 ).distanceTo( point );\n\n\t}\n\n\tintersect( box ) {\n\n\t\tthis.min.max( box.min );\n\t\tthis.max.min( box.max );\n\n\t\tif ( this.isEmpty() ) this.makeEmpty();\n\n\t\treturn this;\n\n\t}\n\n\tunion( box ) {\n\n\t\tthis.min.min( box.min );\n\t\tthis.max.max( box.max );\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( offset ) {\n\n\t\tthis.min.add( offset );\n\t\tthis.max.add( offset );\n\n\t\treturn this;\n\n\t}\n\n\tequals( box ) {\n\n\t\treturn box.min.equals( this.min ) && box.max.equals( this.max );\n\n\t}\n\n}\n\nconst _startP = /*@__PURE__*/ new Vector3();\nconst _startEnd = /*@__PURE__*/ new Vector3();\n\nclass Line3 {\n\n\tconstructor( start = new Vector3(), end = new Vector3() ) {\n\n\t\tthis.start = start;\n\t\tthis.end = end;\n\n\t}\n\n\tset( start, end ) {\n\n\t\tthis.start.copy( start );\n\t\tthis.end.copy( end );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( line ) {\n\n\t\tthis.start.copy( line.start );\n\t\tthis.end.copy( line.end );\n\n\t\treturn this;\n\n\t}\n\n\tgetCenter( target ) {\n\n\t\treturn target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );\n\n\t}\n\n\tdelta( target ) {\n\n\t\treturn target.subVectors( this.end, this.start );\n\n\t}\n\n\tdistanceSq() {\n\n\t\treturn this.start.distanceToSquared( this.end );\n\n\t}\n\n\tdistance() {\n\n\t\treturn this.start.distanceTo( this.end );\n\n\t}\n\n\tat( t, target ) {\n\n\t\treturn this.delta( target ).multiplyScalar( t ).add( this.start );\n\n\t}\n\n\tclosestPointToPointParameter( point, clampToLine ) {\n\n\t\t_startP.subVectors( point, this.start );\n\t\t_startEnd.subVectors( this.end, this.start );\n\n\t\tconst startEnd2 = _startEnd.dot( _startEnd );\n\t\tconst startEnd_startP = _startEnd.dot( _startP );\n\n\t\tlet t = startEnd_startP / startEnd2;\n\n\t\tif ( clampToLine ) {\n\n\t\t\tt = clamp( t, 0, 1 );\n\n\t\t}\n\n\t\treturn t;\n\n\t}\n\n\tclosestPointToPoint( point, clampToLine, target ) {\n\n\t\tconst t = this.closestPointToPointParameter( point, clampToLine );\n\n\t\treturn this.delta( target ).multiplyScalar( t ).add( this.start );\n\n\t}\n\n\tapplyMatrix4( matrix ) {\n\n\t\tthis.start.applyMatrix4( matrix );\n\t\tthis.end.applyMatrix4( matrix );\n\n\t\treturn this;\n\n\t}\n\n\tequals( line ) {\n\n\t\treturn line.start.equals( this.start ) && line.end.equals( this.end );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nconst _vector$3 = /*@__PURE__*/ new Vector3();\n\nclass SpotLightHelper extends Object3D {\n\n\tconstructor( light, color ) {\n\n\t\tsuper();\n\n\t\tthis.light = light;\n\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.color = color;\n\n\t\tthis.type = 'SpotLightHelper';\n\n\t\tconst geometry = new BufferGeometry();\n\n\t\tconst positions = [\n\t\t\t0, 0, 0, \t0, 0, 1,\n\t\t\t0, 0, 0, \t1, 0, 1,\n\t\t\t0, 0, 0,\t- 1, 0, 1,\n\t\t\t0, 0, 0, \t0, 1, 1,\n\t\t\t0, 0, 0, \t0, - 1, 1\n\t\t];\n\n\t\tfor ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {\n\n\t\t\tconst p1 = ( i / l ) * Math.PI * 2;\n\t\t\tconst p2 = ( j / l ) * Math.PI * 2;\n\n\t\t\tpositions.push(\n\t\t\t\tMath.cos( p1 ), Math.sin( p1 ), 1,\n\t\t\t\tMath.cos( p2 ), Math.sin( p2 ), 1\n\t\t\t);\n\n\t\t}\n\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { fog: false, toneMapped: false } );\n\n\t\tthis.cone = new LineSegments( geometry, material );\n\t\tthis.add( this.cone );\n\n\t\tthis.update();\n\n\t}\n\n\tdispose() {\n\n\t\tthis.cone.geometry.dispose();\n\t\tthis.cone.material.dispose();\n\n\t}\n\n\tupdate() {\n\n\t\tthis.light.updateWorldMatrix( true, false );\n\t\tthis.light.target.updateWorldMatrix( true, false );\n\n\t\t// update the local matrix based on the parent and light target transforms\n\t\tif ( this.parent ) {\n\n\t\t\tthis.parent.updateWorldMatrix( true );\n\n\t\t\tthis.matrix\n\t\t\t\t.copy( this.parent.matrixWorld )\n\t\t\t\t.invert()\n\t\t\t\t.multiply( this.light.matrixWorld );\n\n\t\t} else {\n\n\t\t\tthis.matrix.copy( this.light.matrixWorld );\n\n\t\t}\n\n\t\tthis.matrixWorld.copy( this.light.matrixWorld );\n\n\t\tconst coneLength = this.light.distance ? this.light.distance : 1000;\n\t\tconst coneWidth = coneLength * Math.tan( this.light.angle );\n\n\t\tthis.cone.scale.set( coneWidth, coneWidth, coneLength );\n\n\t\t_vector$3.setFromMatrixPosition( this.light.target.matrixWorld );\n\n\t\tthis.cone.lookAt( _vector$3 );\n\n\t\tif ( this.color !== undefined ) {\n\n\t\t\tthis.cone.material.color.set( this.color );\n\n\t\t} else {\n\n\t\t\tthis.cone.material.color.copy( this.light.color );\n\n\t\t}\n\n\t}\n\n}\n\nconst _vector$2 = /*@__PURE__*/ new Vector3();\nconst _boneMatrix = /*@__PURE__*/ new Matrix4();\nconst _matrixWorldInv = /*@__PURE__*/ new Matrix4();\n\n\nclass SkeletonHelper extends LineSegments {\n\n\tconstructor( object ) {\n\n\t\tconst bones = getBoneList( object );\n\n\t\tconst geometry = new BufferGeometry();\n\n\t\tconst vertices = [];\n\t\tconst colors = [];\n\n\t\tconst color1 = new Color( 0, 0, 1 );\n\t\tconst color2 = new Color( 0, 1, 0 );\n\n\t\tfor ( let i = 0; i < bones.length; i ++ ) {\n\n\t\t\tconst bone = bones[ i ];\n\n\t\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\t\tvertices.push( 0, 0, 0 );\n\t\t\t\tvertices.push( 0, 0, 0 );\n\t\t\t\tcolors.push( color1.r, color1.g, color1.b );\n\t\t\t\tcolors.push( color2.r, color2.g, color2.b );\n\n\t\t\t}\n\n\t\t}\n\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.isSkeletonHelper = true;\n\n\t\tthis.type = 'SkeletonHelper';\n\n\t\tthis.root = object;\n\t\tthis.bones = bones;\n\n\t\tthis.matrix = object.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tconst bones = this.bones;\n\n\t\tconst geometry = this.geometry;\n\t\tconst position = geometry.getAttribute( 'position' );\n\n\t\t_matrixWorldInv.copy( this.root.matrixWorld ).invert();\n\n\t\tfor ( let i = 0, j = 0; i < bones.length; i ++ ) {\n\n\t\t\tconst bone = bones[ i ];\n\n\t\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\t\t_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld );\n\t\t\t\t_vector$2.setFromMatrixPosition( _boneMatrix );\n\t\t\t\tposition.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z );\n\n\t\t\t\t_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld );\n\t\t\t\t_vector$2.setFromMatrixPosition( _boneMatrix );\n\t\t\t\tposition.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z );\n\n\t\t\t\tj += 2;\n\n\t\t\t}\n\n\t\t}\n\n\t\tgeometry.getAttribute( 'position' ).needsUpdate = true;\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\n\nfunction getBoneList( object ) {\n\n\tconst boneList = [];\n\n\tif ( object.isBone === true ) {\n\n\t\tboneList.push( object );\n\n\t}\n\n\tfor ( let i = 0; i < object.children.length; i ++ ) {\n\n\t\tboneList.push.apply( boneList, getBoneList( object.children[ i ] ) );\n\n\t}\n\n\treturn boneList;\n\n}\n\nclass PointLightHelper extends Mesh {\n\n\tconstructor( light, sphereSize, color ) {\n\n\t\tconst geometry = new SphereGeometry( sphereSize, 4, 2 );\n\t\tconst material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.light = light;\n\n\t\tthis.color = color;\n\n\t\tthis.type = 'PointLightHelper';\n\n\t\tthis.matrix = this.light.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.update();\n\n\n\t\t/*\n\t// TODO: delete this comment?\n\tconst distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );\n\tconst distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );\n\n\tthis.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );\n\tthis.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );\n\n\tconst d = light.distance;\n\n\tif ( d === 0.0 ) {\n\n\t\tthis.lightDistance.visible = false;\n\n\t} else {\n\n\t\tthis.lightDistance.scale.set( d, d, d );\n\n\t}\n\n\tthis.add( this.lightDistance );\n\t*/\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n\tupdate() {\n\n\t\tthis.light.updateWorldMatrix( true, false );\n\n\t\tif ( this.color !== undefined ) {\n\n\t\t\tthis.material.color.set( this.color );\n\n\t\t} else {\n\n\t\t\tthis.material.color.copy( this.light.color );\n\n\t\t}\n\n\t\t/*\n\t\tconst d = this.light.distance;\n\n\t\tif ( d === 0.0 ) {\n\n\t\t\tthis.lightDistance.visible = false;\n\n\t\t} else {\n\n\t\t\tthis.lightDistance.visible = true;\n\t\t\tthis.lightDistance.scale.set( d, d, d );\n\n\t\t}\n\t\t*/\n\n\t}\n\n}\n\nconst _vector$1 = /*@__PURE__*/ new Vector3();\nconst _color1 = /*@__PURE__*/ new Color();\nconst _color2 = /*@__PURE__*/ new Color();\n\nclass HemisphereLightHelper extends Object3D {\n\n\tconstructor( light, size, color ) {\n\n\t\tsuper();\n\n\t\tthis.light = light;\n\n\t\tthis.matrix = light.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.color = color;\n\n\t\tthis.type = 'HemisphereLightHelper';\n\n\t\tconst geometry = new OctahedronGeometry( size );\n\t\tgeometry.rotateY( Math.PI * 0.5 );\n\n\t\tthis.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );\n\t\tif ( this.color === undefined ) this.material.vertexColors = true;\n\n\t\tconst position = geometry.getAttribute( 'position' );\n\t\tconst colors = new Float32Array( position.count * 3 );\n\n\t\tgeometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );\n\n\t\tthis.add( new Mesh( geometry, this.material ) );\n\n\t\tthis.update();\n\n\t}\n\n\tdispose() {\n\n\t\tthis.children[ 0 ].geometry.dispose();\n\t\tthis.children[ 0 ].material.dispose();\n\n\t}\n\n\tupdate() {\n\n\t\tconst mesh = this.children[ 0 ];\n\n\t\tif ( this.color !== undefined ) {\n\n\t\t\tthis.material.color.set( this.color );\n\n\t\t} else {\n\n\t\t\tconst colors = mesh.geometry.getAttribute( 'color' );\n\n\t\t\t_color1.copy( this.light.color );\n\t\t\t_color2.copy( this.light.groundColor );\n\n\t\t\tfor ( let i = 0, l = colors.count; i < l; i ++ ) {\n\n\t\t\t\tconst color = ( i < ( l / 2 ) ) ? _color1 : _color2;\n\n\t\t\t\tcolors.setXYZ( i, color.r, color.g, color.b );\n\n\t\t\t}\n\n\t\t\tcolors.needsUpdate = true;\n\n\t\t}\n\n\t\tthis.light.updateWorldMatrix( true, false );\n\n\t\tmesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() );\n\n\t}\n\n}\n\nclass GridHelper extends LineSegments {\n\n\tconstructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) {\n\n\t\tcolor1 = new Color( color1 );\n\t\tcolor2 = new Color( color2 );\n\n\t\tconst center = divisions / 2;\n\t\tconst step = size / divisions;\n\t\tconst halfSize = size / 2;\n\n\t\tconst vertices = [], colors = [];\n\n\t\tfor ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {\n\n\t\t\tvertices.push( - halfSize, 0, k, halfSize, 0, k );\n\t\t\tvertices.push( k, 0, - halfSize, k, 0, halfSize );\n\n\t\t\tconst color = i === center ? color1 : color2;\n\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\n\t\t}\n\n\t\tconst geometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.type = 'GridHelper';\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\nclass PolarGridHelper extends LineSegments {\n\n\tconstructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) {\n\n\t\tcolor1 = new Color( color1 );\n\t\tcolor2 = new Color( color2 );\n\n\t\tconst vertices = [];\n\t\tconst colors = [];\n\n\t\t// create the sectors\n\n\t\tif ( sectors > 1 ) {\n\n\t\t\tfor ( let i = 0; i < sectors; i ++ ) {\n\n\t\t\t\tconst v = ( i / sectors ) * ( Math.PI * 2 );\n\n\t\t\t\tconst x = Math.sin( v ) * radius;\n\t\t\t\tconst z = Math.cos( v ) * radius;\n\n\t\t\t\tvertices.push( 0, 0, 0 );\n\t\t\t\tvertices.push( x, 0, z );\n\n\t\t\t\tconst color = ( i & 1 ) ? color1 : color2;\n\n\t\t\t\tcolors.push( color.r, color.g, color.b );\n\t\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// create the rings\n\n\t\tfor ( let i = 0; i < rings; i ++ ) {\n\n\t\t\tconst color = ( i & 1 ) ? color1 : color2;\n\n\t\t\tconst r = radius - ( radius / rings * i );\n\n\t\t\tfor ( let j = 0; j < divisions; j ++ ) {\n\n\t\t\t\t// first vertex\n\n\t\t\t\tlet v = ( j / divisions ) * ( Math.PI * 2 );\n\n\t\t\t\tlet x = Math.sin( v ) * r;\n\t\t\t\tlet z = Math.cos( v ) * r;\n\n\t\t\t\tvertices.push( x, 0, z );\n\t\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t\t\t// second vertex\n\n\t\t\t\tv = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );\n\n\t\t\t\tx = Math.sin( v ) * r;\n\t\t\t\tz = Math.cos( v ) * r;\n\n\t\t\t\tvertices.push( x, 0, z );\n\t\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst geometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.type = 'PolarGridHelper';\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\nconst _v1 = /*@__PURE__*/ new Vector3();\nconst _v2 = /*@__PURE__*/ new Vector3();\nconst _v3 = /*@__PURE__*/ new Vector3();\n\nclass DirectionalLightHelper extends Object3D {\n\n\tconstructor( light, size, color ) {\n\n\t\tsuper();\n\n\t\tthis.light = light;\n\n\t\tthis.matrix = light.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.color = color;\n\n\t\tthis.type = 'DirectionalLightHelper';\n\n\t\tif ( size === undefined ) size = 1;\n\n\t\tlet geometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( [\n\t\t\t- size, size, 0,\n\t\t\tsize, size, 0,\n\t\t\tsize, - size, 0,\n\t\t\t- size, - size, 0,\n\t\t\t- size, size, 0\n\t\t], 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { fog: false, toneMapped: false } );\n\n\t\tthis.lightPlane = new Line( geometry, material );\n\t\tthis.add( this.lightPlane );\n\n\t\tgeometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );\n\n\t\tthis.targetLine = new Line( geometry, material );\n\t\tthis.add( this.targetLine );\n\n\t\tthis.update();\n\n\t}\n\n\tdispose() {\n\n\t\tthis.lightPlane.geometry.dispose();\n\t\tthis.lightPlane.material.dispose();\n\t\tthis.targetLine.geometry.dispose();\n\t\tthis.targetLine.material.dispose();\n\n\t}\n\n\tupdate() {\n\n\t\tthis.light.updateWorldMatrix( true, false );\n\t\tthis.light.target.updateWorldMatrix( true, false );\n\n\t\t_v1.setFromMatrixPosition( this.light.matrixWorld );\n\t\t_v2.setFromMatrixPosition( this.light.target.matrixWorld );\n\t\t_v3.subVectors( _v2, _v1 );\n\n\t\tthis.lightPlane.lookAt( _v2 );\n\n\t\tif ( this.color !== undefined ) {\n\n\t\t\tthis.lightPlane.material.color.set( this.color );\n\t\t\tthis.targetLine.material.color.set( this.color );\n\n\t\t} else {\n\n\t\t\tthis.lightPlane.material.color.copy( this.light.color );\n\t\t\tthis.targetLine.material.color.copy( this.light.color );\n\n\t\t}\n\n\t\tthis.targetLine.lookAt( _v2 );\n\t\tthis.targetLine.scale.z = _v3.length();\n\n\t}\n\n}\n\nconst _vector = /*@__PURE__*/ new Vector3();\nconst _camera = /*@__PURE__*/ new Camera();\n\n/**\n *\t- shows frustum, line of sight and up of the camera\n *\t- suitable for fast updates\n * \t- based on frustum visualization in lightgl.js shadowmap example\n *\t\thttps://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html\n */\n\nclass CameraHelper extends LineSegments {\n\n\tconstructor( camera ) {\n\n\t\tconst geometry = new BufferGeometry();\n\t\tconst material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } );\n\n\t\tconst vertices = [];\n\t\tconst colors = [];\n\n\t\tconst pointMap = {};\n\n\t\t// near\n\n\t\taddLine( 'n1', 'n2' );\n\t\taddLine( 'n2', 'n4' );\n\t\taddLine( 'n4', 'n3' );\n\t\taddLine( 'n3', 'n1' );\n\n\t\t// far\n\n\t\taddLine( 'f1', 'f2' );\n\t\taddLine( 'f2', 'f4' );\n\t\taddLine( 'f4', 'f3' );\n\t\taddLine( 'f3', 'f1' );\n\n\t\t// sides\n\n\t\taddLine( 'n1', 'f1' );\n\t\taddLine( 'n2', 'f2' );\n\t\taddLine( 'n3', 'f3' );\n\t\taddLine( 'n4', 'f4' );\n\n\t\t// cone\n\n\t\taddLine( 'p', 'n1' );\n\t\taddLine( 'p', 'n2' );\n\t\taddLine( 'p', 'n3' );\n\t\taddLine( 'p', 'n4' );\n\n\t\t// up\n\n\t\taddLine( 'u1', 'u2' );\n\t\taddLine( 'u2', 'u3' );\n\t\taddLine( 'u3', 'u1' );\n\n\t\t// target\n\n\t\taddLine( 'c', 't' );\n\t\taddLine( 'p', 'c' );\n\n\t\t// cross\n\n\t\taddLine( 'cn1', 'cn2' );\n\t\taddLine( 'cn3', 'cn4' );\n\n\t\taddLine( 'cf1', 'cf2' );\n\t\taddLine( 'cf3', 'cf4' );\n\n\t\tfunction addLine( a, b ) {\n\n\t\t\taddPoint( a );\n\t\t\taddPoint( b );\n\n\t\t}\n\n\t\tfunction addPoint( id ) {\n\n\t\t\tvertices.push( 0, 0, 0 );\n\t\t\tcolors.push( 0, 0, 0 );\n\n\t\t\tif ( pointMap[ id ] === undefined ) {\n\n\t\t\t\tpointMap[ id ] = [];\n\n\t\t\t}\n\n\t\t\tpointMap[ id ].push( ( vertices.length / 3 ) - 1 );\n\n\t\t}\n\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.type = 'CameraHelper';\n\n\t\tthis.camera = camera;\n\t\tif ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();\n\n\t\tthis.matrix = camera.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.pointMap = pointMap;\n\n\t\tthis.update();\n\n\t\t// colors\n\n\t\tconst colorFrustum = new Color( 0xffaa00 );\n\t\tconst colorCone = new Color( 0xff0000 );\n\t\tconst colorUp = new Color( 0x00aaff );\n\t\tconst colorTarget = new Color( 0xffffff );\n\t\tconst colorCross = new Color( 0x333333 );\n\n\t\tthis.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross );\n\n\t}\n\n\tsetColors( frustum, cone, up, target, cross ) {\n\n\t\tconst geometry = this.geometry;\n\n\t\tconst colorAttribute = geometry.getAttribute( 'color' );\n\n\t\t// near\n\n\t\tcolorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2\n\t\tcolorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4\n\t\tcolorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3\n\t\tcolorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1\n\n\t\t// far\n\n\t\tcolorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2\n\t\tcolorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4\n\t\tcolorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3\n\t\tcolorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1\n\n\t\t// sides\n\n\t\tcolorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1\n\t\tcolorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2\n\t\tcolorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3\n\t\tcolorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4\n\n\t\t// cone\n\n\t\tcolorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1\n\t\tcolorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2\n\t\tcolorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3\n\t\tcolorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4\n\n\t\t// up\n\n\t\tcolorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2\n\t\tcolorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3\n\t\tcolorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1\n\n\t\t// target\n\n\t\tcolorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t\n\t\tcolorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c\n\n\t\t// cross\n\n\t\tcolorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2\n\t\tcolorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4\n\n\t\tcolorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2\n\t\tcolorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4\n\n\t\tcolorAttribute.needsUpdate = true;\n\n\t}\n\n\tupdate() {\n\n\t\tconst geometry = this.geometry;\n\t\tconst pointMap = this.pointMap;\n\n\t\tconst w = 1, h = 1;\n\n\t\t// we need just camera projection matrix inverse\n\t\t// world matrix must be identity\n\n\t\t_camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse );\n\n\t\t// center / target\n\n\t\tsetPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 );\n\t\tsetPoint( 't', pointMap, geometry, _camera, 0, 0, 1 );\n\n\t\t// near\n\n\t\tsetPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 );\n\t\tsetPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 );\n\t\tsetPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 );\n\t\tsetPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 );\n\n\t\t// far\n\n\t\tsetPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 );\n\t\tsetPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 );\n\t\tsetPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 );\n\t\tsetPoint( 'f4', pointMap, geometry, _camera, w, h, 1 );\n\n\t\t// up\n\n\t\tsetPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 );\n\t\tsetPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 );\n\t\tsetPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 );\n\n\t\t// cross\n\n\t\tsetPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 );\n\t\tsetPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 );\n\t\tsetPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 );\n\t\tsetPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 );\n\n\t\tsetPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 );\n\t\tsetPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 );\n\t\tsetPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 );\n\t\tsetPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 );\n\n\t\tgeometry.getAttribute( 'position' ).needsUpdate = true;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\n\nfunction setPoint( point, pointMap, geometry, camera, x, y, z ) {\n\n\t_vector.set( x, y, z ).unproject( camera );\n\n\tconst points = pointMap[ point ];\n\n\tif ( points !== undefined ) {\n\n\t\tconst position = geometry.getAttribute( 'position' );\n\n\t\tfor ( let i = 0, l = points.length; i < l; i ++ ) {\n\n\t\t\tposition.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z );\n\n\t\t}\n\n\t}\n\n}\n\nconst _box = /*@__PURE__*/ new Box3();\n\nclass BoxHelper extends LineSegments {\n\n\tconstructor( object, color = 0xffff00 ) {\n\n\t\tconst 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 ] );\n\t\tconst positions = new Float32Array( 8 * 3 );\n\n\t\tconst geometry = new BufferGeometry();\n\t\tgeometry.setIndex( new BufferAttribute( indices, 1 ) );\n\t\tgeometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );\n\n\t\tsuper( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );\n\n\t\tthis.object = object;\n\t\tthis.type = 'BoxHelper';\n\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.update();\n\n\t}\n\n\tupdate( object ) {\n\n\t\tif ( object !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );\n\n\t\t}\n\n\t\tif ( this.object !== undefined ) {\n\n\t\t\t_box.setFromObject( this.object );\n\n\t\t}\n\n\t\tif ( _box.isEmpty() ) return;\n\n\t\tconst min = _box.min;\n\t\tconst max = _box.max;\n\n\t\t/*\n\t\t\t5____4\n\t\t1/___0/|\n\t\t| 6__|_7\n\t\t2/___3/\n\n\t\t0: max.x, max.y, max.z\n\t\t1: min.x, max.y, max.z\n\t\t2: min.x, min.y, max.z\n\t\t3: max.x, min.y, max.z\n\t\t4: max.x, max.y, min.z\n\t\t5: min.x, max.y, min.z\n\t\t6: min.x, min.y, min.z\n\t\t7: max.x, min.y, min.z\n\t\t*/\n\n\t\tconst position = this.geometry.attributes.position;\n\t\tconst array = position.array;\n\n\t\tarray[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;\n\t\tarray[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;\n\t\tarray[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;\n\t\tarray[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;\n\t\tarray[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;\n\t\tarray[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;\n\t\tarray[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;\n\t\tarray[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;\n\n\t\tposition.needsUpdate = true;\n\n\t\tthis.geometry.computeBoundingSphere();\n\n\t}\n\n\tsetFromObject( object ) {\n\n\t\tthis.object = object;\n\t\tthis.update();\n\n\t\treturn this;\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.object = source.object;\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\nclass Box3Helper extends LineSegments {\n\n\tconstructor( box, color = 0xffff00 ) {\n\n\t\tconst 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 ] );\n\n\t\tconst 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 ];\n\n\t\tconst geometry = new BufferGeometry();\n\n\t\tgeometry.setIndex( new BufferAttribute( indices, 1 ) );\n\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );\n\n\t\tsuper( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );\n\n\t\tthis.box = box;\n\n\t\tthis.type = 'Box3Helper';\n\n\t\tthis.geometry.computeBoundingSphere();\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tconst box = this.box;\n\n\t\tif ( box.isEmpty() ) return;\n\n\t\tbox.getCenter( this.position );\n\n\t\tbox.getSize( this.scale );\n\n\t\tthis.scale.multiplyScalar( 0.5 );\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\nclass PlaneHelper extends Line {\n\n\tconstructor( plane, size = 1, hex = 0xffff00 ) {\n\n\t\tconst color = hex;\n\n\t\tconst 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 ];\n\n\t\tconst geometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );\n\t\tgeometry.computeBoundingSphere();\n\n\t\tsuper( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );\n\n\t\tthis.type = 'PlaneHelper';\n\n\t\tthis.plane = plane;\n\n\t\tthis.size = size;\n\n\t\tconst positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ];\n\n\t\tconst geometry2 = new BufferGeometry();\n\t\tgeometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );\n\t\tgeometry2.computeBoundingSphere();\n\n\t\tthis.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) );\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tthis.position.set( 0, 0, 0 );\n\n\t\tthis.scale.set( 0.5 * this.size, 0.5 * this.size, 1 );\n\n\t\tthis.lookAt( this.plane.normal );\n\n\t\tthis.translateZ( - this.plane.constant );\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\t\tthis.children[ 0 ].geometry.dispose();\n\t\tthis.children[ 0 ].material.dispose();\n\n\t}\n\n}\n\nconst _axis = /*@__PURE__*/ new Vector3();\nlet _lineGeometry, _coneGeometry;\n\nclass ArrowHelper extends Object3D {\n\n\t// dir is assumed to be normalized\n\n\tconstructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'ArrowHelper';\n\n\t\tif ( _lineGeometry === undefined ) {\n\n\t\t\t_lineGeometry = new BufferGeometry();\n\t\t\t_lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );\n\n\t\t\t_coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 );\n\t\t\t_coneGeometry.translate( 0, - 0.5, 0 );\n\n\t\t}\n\n\t\tthis.position.copy( origin );\n\n\t\tthis.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );\n\t\tthis.line.matrixAutoUpdate = false;\n\t\tthis.add( this.line );\n\n\t\tthis.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) );\n\t\tthis.cone.matrixAutoUpdate = false;\n\t\tthis.add( this.cone );\n\n\t\tthis.setDirection( dir );\n\t\tthis.setLength( length, headLength, headWidth );\n\n\t}\n\n\tsetDirection( dir ) {\n\n\t\t// dir is assumed to be normalized\n\n\t\tif ( dir.y > 0.99999 ) {\n\n\t\t\tthis.quaternion.set( 0, 0, 0, 1 );\n\n\t\t} else if ( dir.y < - 0.99999 ) {\n\n\t\t\tthis.quaternion.set( 1, 0, 0, 0 );\n\n\t\t} else {\n\n\t\t\t_axis.set( dir.z, 0, - dir.x ).normalize();\n\n\t\t\tconst radians = Math.acos( dir.y );\n\n\t\t\tthis.quaternion.setFromAxisAngle( _axis, radians );\n\n\t\t}\n\n\t}\n\n\tsetLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) {\n\n\t\tthis.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458\n\t\tthis.line.updateMatrix();\n\n\t\tthis.cone.scale.set( headWidth, headLength, headWidth );\n\t\tthis.cone.position.y = length;\n\t\tthis.cone.updateMatrix();\n\n\t}\n\n\tsetColor( color ) {\n\n\t\tthis.line.material.color.set( color );\n\t\tthis.cone.material.color.set( color );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source, false );\n\n\t\tthis.line.copy( source.line );\n\t\tthis.cone.copy( source.cone );\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.line.geometry.dispose();\n\t\tthis.line.material.dispose();\n\t\tthis.cone.geometry.dispose();\n\t\tthis.cone.material.dispose();\n\n\t}\n\n}\n\nclass AxesHelper extends LineSegments {\n\n\tconstructor( size = 1 ) {\n\n\t\tconst vertices = [\n\t\t\t0, 0, 0,\tsize, 0, 0,\n\t\t\t0, 0, 0,\t0, size, 0,\n\t\t\t0, 0, 0,\t0, 0, size\n\t\t];\n\n\t\tconst colors = [\n\t\t\t1, 0, 0,\t1, 0.6, 0,\n\t\t\t0, 1, 0,\t0.6, 1, 0,\n\t\t\t0, 0, 1,\t0, 0.6, 1\n\t\t];\n\n\t\tconst geometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.type = 'AxesHelper';\n\n\t}\n\n\tsetColors( xAxisColor, yAxisColor, zAxisColor ) {\n\n\t\tconst color = new Color();\n\t\tconst array = this.geometry.attributes.color.array;\n\n\t\tcolor.set( xAxisColor );\n\t\tcolor.toArray( array, 0 );\n\t\tcolor.toArray( array, 3 );\n\n\t\tcolor.set( yAxisColor );\n\t\tcolor.toArray( array, 6 );\n\t\tcolor.toArray( array, 9 );\n\n\t\tcolor.set( zAxisColor );\n\t\tcolor.toArray( array, 12 );\n\t\tcolor.toArray( array, 15 );\n\n\t\tthis.geometry.attributes.color.needsUpdate = true;\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\nclass ShapePath {\n\n\tconstructor() {\n\n\t\tthis.type = 'ShapePath';\n\n\t\tthis.color = new Color();\n\n\t\tthis.subPaths = [];\n\t\tthis.currentPath = null;\n\n\t}\n\n\tmoveTo( x, y ) {\n\n\t\tthis.currentPath = new Path();\n\t\tthis.subPaths.push( this.currentPath );\n\t\tthis.currentPath.moveTo( x, y );\n\n\t\treturn this;\n\n\t}\n\n\tlineTo( x, y ) {\n\n\t\tthis.currentPath.lineTo( x, y );\n\n\t\treturn this;\n\n\t}\n\n\tquadraticCurveTo( aCPx, aCPy, aX, aY ) {\n\n\t\tthis.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );\n\n\t\treturn this;\n\n\t}\n\n\tbezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {\n\n\t\tthis.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );\n\n\t\treturn this;\n\n\t}\n\n\tsplineThru( pts ) {\n\n\t\tthis.currentPath.splineThru( pts );\n\n\t\treturn this;\n\n\t}\n\n\ttoShapes( isCCW ) {\n\n\t\tfunction toShapesNoHoles( inSubpaths ) {\n\n\t\t\tconst shapes = [];\n\n\t\t\tfor ( let i = 0, l = inSubpaths.length; i < l; i ++ ) {\n\n\t\t\t\tconst tmpPath = inSubpaths[ i ];\n\n\t\t\t\tconst tmpShape = new Shape();\n\t\t\t\ttmpShape.curves = tmpPath.curves;\n\n\t\t\t\tshapes.push( tmpShape );\n\n\t\t\t}\n\n\t\t\treturn shapes;\n\n\t\t}\n\n\t\tfunction isPointInsidePolygon( inPt, inPolygon ) {\n\n\t\t\tconst polyLen = inPolygon.length;\n\n\t\t\t// inPt on polygon contour => immediate success or\n\t\t\t// toggling of inside/outside at every single! intersection point of an edge\n\t\t\t// with the horizontal line through inPt, left of inPt\n\t\t\t// not counting lowerY endpoints of edges and whole edges on that line\n\t\t\tlet inside = false;\n\t\t\tfor ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {\n\n\t\t\t\tlet edgeLowPt = inPolygon[ p ];\n\t\t\t\tlet edgeHighPt = inPolygon[ q ];\n\n\t\t\t\tlet edgeDx = edgeHighPt.x - edgeLowPt.x;\n\t\t\t\tlet edgeDy = edgeHighPt.y - edgeLowPt.y;\n\n\t\t\t\tif ( Math.abs( edgeDy ) > Number.EPSILON ) {\n\n\t\t\t\t\t// not parallel\n\t\t\t\t\tif ( edgeDy < 0 ) {\n\n\t\t\t\t\t\tedgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;\n\t\t\t\t\t\tedgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) \t\tcontinue;\n\n\t\t\t\t\tif ( inPt.y === edgeLowPt.y ) {\n\n\t\t\t\t\t\tif ( inPt.x === edgeLowPt.x )\t\treturn\ttrue;\t\t// inPt is on contour ?\n\t\t\t\t\t\t// continue;\t\t\t\t// no intersection or edgeLowPt => doesn't count !!!\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconst perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );\n\t\t\t\t\t\tif ( perpEdge === 0 )\t\t\t\treturn\ttrue;\t\t// inPt is on contour ?\n\t\t\t\t\t\tif ( perpEdge < 0 ) \t\t\t\tcontinue;\n\t\t\t\t\t\tinside = ! inside;\t\t// true intersection left of inPt\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// parallel or collinear\n\t\t\t\t\tif ( inPt.y !== edgeLowPt.y ) \t\tcontinue;\t\t\t// parallel\n\t\t\t\t\t// edge lies on the same horizontal line as inPt\n\t\t\t\t\tif ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||\n\t\t\t\t\t\t ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )\t\treturn\ttrue;\t// inPt: Point on contour !\n\t\t\t\t\t// continue;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn\tinside;\n\n\t\t}\n\n\t\tconst isClockWise = ShapeUtils.isClockWise;\n\n\t\tconst subPaths = this.subPaths;\n\t\tif ( subPaths.length === 0 ) return [];\n\n\t\tlet solid, tmpPath, tmpShape;\n\t\tconst shapes = [];\n\n\t\tif ( subPaths.length === 1 ) {\n\n\t\t\ttmpPath = subPaths[ 0 ];\n\t\t\ttmpShape = new Shape();\n\t\t\ttmpShape.curves = tmpPath.curves;\n\t\t\tshapes.push( tmpShape );\n\t\t\treturn shapes;\n\n\t\t}\n\n\t\tlet holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );\n\t\tholesFirst = isCCW ? ! holesFirst : holesFirst;\n\n\t\t// console.log(\"Holes first\", holesFirst);\n\n\t\tconst betterShapeHoles = [];\n\t\tconst newShapes = [];\n\t\tlet newShapeHoles = [];\n\t\tlet mainIdx = 0;\n\t\tlet tmpPoints;\n\n\t\tnewShapes[ mainIdx ] = undefined;\n\t\tnewShapeHoles[ mainIdx ] = [];\n\n\t\tfor ( let i = 0, l = subPaths.length; i < l; i ++ ) {\n\n\t\t\ttmpPath = subPaths[ i ];\n\t\t\ttmpPoints = tmpPath.getPoints();\n\t\t\tsolid = isClockWise( tmpPoints );\n\t\t\tsolid = isCCW ? ! solid : solid;\n\n\t\t\tif ( solid ) {\n\n\t\t\t\tif ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) )\tmainIdx ++;\n\n\t\t\t\tnewShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };\n\t\t\t\tnewShapes[ mainIdx ].s.curves = tmpPath.curves;\n\n\t\t\t\tif ( holesFirst )\tmainIdx ++;\n\t\t\t\tnewShapeHoles[ mainIdx ] = [];\n\n\t\t\t\t//console.log('cw', i);\n\n\t\t\t} else {\n\n\t\t\t\tnewShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );\n\n\t\t\t\t//console.log('ccw', i);\n\n\t\t\t}\n\n\t\t}\n\n\t\t// only Holes? -> probably all Shapes with wrong orientation\n\t\tif ( ! newShapes[ 0 ] )\treturn\ttoShapesNoHoles( subPaths );\n\n\n\t\tif ( newShapes.length > 1 ) {\n\n\t\t\tlet ambiguous = false;\n\t\t\tlet toChange = 0;\n\n\t\t\tfor ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {\n\n\t\t\t\tbetterShapeHoles[ sIdx ] = [];\n\n\t\t\t}\n\n\t\t\tfor ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {\n\n\t\t\t\tconst sho = newShapeHoles[ sIdx ];\n\n\t\t\t\tfor ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) {\n\n\t\t\t\t\tconst ho = sho[ hIdx ];\n\t\t\t\t\tlet hole_unassigned = true;\n\n\t\t\t\t\tfor ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {\n\n\t\t\t\t\t\tif ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {\n\n\t\t\t\t\t\t\tif ( sIdx !== s2Idx )\ttoChange ++;\n\n\t\t\t\t\t\t\tif ( hole_unassigned ) {\n\n\t\t\t\t\t\t\t\thole_unassigned = false;\n\t\t\t\t\t\t\t\tbetterShapeHoles[ s2Idx ].push( ho );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tambiguous = true;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( hole_unassigned ) {\n\n\t\t\t\t\t\tbetterShapeHoles[ sIdx ].push( ho );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( toChange > 0 && ambiguous === false ) {\n\n\t\t\t\tnewShapeHoles = betterShapeHoles;\n\n\t\t\t}\n\n\t\t}\n\n\t\tlet tmpHoles;\n\n\t\tfor ( let i = 0, il = newShapes.length; i < il; i ++ ) {\n\n\t\t\ttmpShape = newShapes[ i ].s;\n\t\t\tshapes.push( tmpShape );\n\t\t\ttmpHoles = newShapeHoles[ i ];\n\n\t\t\tfor ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) {\n\n\t\t\t\ttmpShape.holes.push( tmpHoles[ j ].h );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//console.log(\"shape\", shapes);\n\n\t\treturn shapes;\n\n\t}\n\n}\n\nclass WebGLMultipleRenderTargets extends WebGLRenderTarget { // @deprecated, r162\n\n\tconstructor( width = 1, height = 1, count = 1, options = {} ) {\n\n\t\tconsole.warn( 'THREE.WebGLMultipleRenderTargets has been deprecated and will be removed in r172. Use THREE.WebGLRenderTarget and set the \"count\" parameter to enable MRT.' );\n\n\t\tsuper( width, height, { ...options, count } );\n\n\t\tthis.isWebGLMultipleRenderTargets = true;\n\n\t}\n\n\tget texture() {\n\n\t\treturn this.textures;\n\n\t}\n\n}\n\nif ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {\n\n\t__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {\n\t\trevision: REVISION,\n\t} } ) );\n\n}\n\nif ( typeof window !== 'undefined' ) {\n\n\tif ( window.__THREE__ ) {\n\n\t\tconsole.warn( 'WARNING: Multiple instances of Three.js being imported.' );\n\n\t} else {\n\n\t\twindow.__THREE__ = REVISION;\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNzUzLmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdCQUFnQjtBQUNoQixnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJCQUEyQjtBQUMzQiwyQkFBMkI7QUFDM0I7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsaUJBQWlCLGVBQWU7QUFDaEMsaUJBQWlCLGVBQWU7QUFDaEMsaUJBQWlCLGVBQWU7O0FBRWhDOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHFCQUFxQixtQkFBbUI7QUFDeEMscUJBQXFCLG1CQUFtQjtBQUN4QyxxQkFBcUIsbUJBQW1COztBQUV4Qzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGdCQUFnQixjQUFjO0FBQzlCLGdCQUFnQixjQUFjO0FBQzlCLGdCQUFnQixjQUFjOztBQUU5Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLGdCQUFnQixpQkFBaUI7QUFDakMsZ0JBQWdCLGlCQUFpQjtBQUNqQyxnQkFBZ0IsaUJBQWlCOztBQUVqQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLE9BQU87O0FBRTFCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGlDQUFpQyxRQUFROztBQUV6QywwQ0FBMEM7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUEsMERBQTBELFlBQVk7O0FBRXRFOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLG9CQUFvQixpQkFBaUI7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsb0JBQW9CLGlCQUFpQjs7QUFFckM7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx1Q0FBdUMsc0JBQXNCOztBQUU3RDs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3Qzs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx1Q0FBdUMsdUJBQXVCOztBQUU5RDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDRCQUE0Qjs7QUFFNUI7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxzQ0FBc0M7QUFDdEMseUJBQXlCOztBQUV6Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdCQUF3QixrQkFBa0I7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJCQUEyQjtBQUMzQiwyQkFBMkI7QUFDM0IsMkJBQTJCO0FBQzNCLDJCQUEyQjtBQUMzQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNCQUFzQjtBQUN0QjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLGlCQUFpQjs7QUFFakI7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxnQkFBZ0I7O0FBRWhCOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxvQ0FBb0M7O0FBRXBDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGtEQUFrRDs7QUFFbEQ7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsa0JBQWtCOztBQUVsQjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxtQkFBbUIsV0FBVzs7QUFFOUI7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLCtDQUErQyxRQUFROztBQUV2RDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxnREFBZ0QsUUFBUTs7QUFFeEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxpQ0FBaUM7QUFDakM7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdCQUF3QixrQkFBa0I7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBLGtEQUFrRDs7QUFFbEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsaUJBQWlCOztBQUVqQjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw2REFBNkQ7O0FBRTdEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLGlCQUFpQjs7QUFFakI7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNkRBQTZEOztBQUU3RDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKLGtDQUFrQzs7QUFFbEM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxxQkFBcUI7O0FBRXJCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQkFBMkI7QUFDM0IsMkJBQTJCO0FBQzNCLDJCQUEyQjtBQUMzQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLFFBQVE7O0FBRTlDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHlDQUF5QyxRQUFROztBQUVqRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx1Q0FBdUMsUUFBUTs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLGtEQUFrRCxPQUFPOztBQUV6RDs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0EsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsT0FBTzs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsaUZBQWlGO0FBQ2pGLGlGQUFpRjtBQUNqRixpRkFBaUY7QUFDakYsaUZBQWlGO0FBQ2pGLGlGQUFpRjtBQUNqRixpRkFBaUY7QUFDakYsaUZBQWlGO0FBQ2pGLGlGQUFpRjs7QUFFakY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLHVDQUF1QyxRQUFROztBQUUvQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQSx1Q0FBdUMsUUFBUTs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGlCQUFpQixlQUFlLGVBQWU7QUFDL0MsaUJBQWlCLGVBQWUsZUFBZTtBQUMvQyxpQkFBaUIsZUFBZSxnQkFBZ0I7QUFDaEQsaUJBQWlCLGVBQWUsZ0JBQWdCOztBQUVoRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHFCQUFxQixtQkFBbUIsbUJBQW1CO0FBQzNELHFCQUFxQixtQkFBbUIsbUJBQW1CO0FBQzNELHFCQUFxQixtQkFBbUIscUJBQXFCO0FBQzdELHVCQUF1QixxQkFBcUIscUJBQXFCOztBQUVqRTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLGtCQUFrQixnQkFBZ0I7QUFDbEMsa0JBQWtCLGdCQUFnQjtBQUNsQyxrQkFBa0IsZ0JBQWdCOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsZ0JBQWdCLGNBQWMsY0FBYztBQUM1QyxnQkFBZ0IsY0FBYyxjQUFjO0FBQzVDLGdCQUFnQixjQUFjLGVBQWU7QUFDN0MsZ0JBQWdCLGNBQWMsZUFBZTs7QUFFN0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxpQkFBaUIsbUJBQW1CO0FBQ3BDLGlCQUFpQixtQkFBbUI7QUFDcEMsaUJBQWlCLG1CQUFtQjs7QUFFcEMsaUJBQWlCLG9CQUFvQjtBQUNyQyxpQkFBaUIsb0JBQW9CO0FBQ3JDLGtCQUFrQixxQkFBcUI7O0FBRXZDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsZ0JBQWdCLGNBQWM7QUFDOUIsZ0JBQWdCLGNBQWM7QUFDOUIsZ0JBQWdCLGNBQWM7QUFDOUIsZ0JBQWdCLGNBQWM7O0FBRTlCOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQSxlQUFlLGFBQWEsY0FBYztBQUMxQyxlQUFlLGFBQWEsY0FBYztBQUMxQyxlQUFlLGFBQWEsZUFBZTtBQUMzQyxlQUFlLGFBQWEsZ0JBQWdCOztBQUU1Qzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEsbUJBQW1CLGNBQWMsZUFBZTtBQUNoRCxpQkFBaUIsaUJBQWlCLGVBQWU7QUFDakQsaUJBQWlCLGNBQWMsaUJBQWlCO0FBQ2hELGlCQUFpQixjQUFjLGVBQWU7O0FBRTlDOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsbUJBQW1CLFFBQVE7O0FBRTNCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixRQUFROztBQUUzQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxzQkFBc0I7QUFDdEIsd0JBQXdCOztBQUV4QiwyQkFBMkI7QUFDM0IsNkJBQTZCOztBQUU3Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx1Q0FBdUMsd0JBQXdCOztBQUUvRDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBLDBFQUEwRTtBQUMxRTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHNCQUFzQjs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHNCQUFzQjs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw2Q0FBNkMsT0FBTzs7QUFFcEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsT0FBTzs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0NBQXdDLE9BQU87O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdDQUF3QyxPQUFPOztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdDQUF3QyxPQUFPOztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHlDQUF5QyxPQUFPOztBQUVoRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxrQkFBa0I7QUFDbEIsaUJBQWlCO0FBQ2pCLGdCQUFnQjtBQUNoQixjQUFjO0FBQ2QsY0FBYztBQUNkLGlCQUFpQjtBQUNqQixrQkFBa0I7QUFDbEI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx5Q0FBeUMsT0FBTzs7QUFFaEQ7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLCtDQUErQyxPQUFPOztBQUV0RDs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQiwwQkFBMEI7O0FBRTlDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQiw0QkFBNEI7O0FBRWhEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLDRCQUE0Qjs7QUFFaEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EscUNBQXFDO0FBQ3JDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDBCQUEwQjtBQUMxQjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSwwQkFBMEI7QUFDMUI7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLHlCQUF5QjtBQUN6Qjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSwwQkFBMEI7QUFDMUI7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLHlCQUF5QjtBQUN6Qjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSx5QkFBeUI7QUFDekIsdURBQXVEOztBQUV2RDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHlCQUF5QjtBQUN6QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdCQUFnQjtBQUNoQixnQkFBZ0I7O0FBRWhCOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUEseURBQXlEO0FBQ3pELHlDQUF5QztBQUN6Qyx5Q0FBeUM7O0FBRXpDOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxvQkFBb0IsYUFBYSxHQUFHLGlCQUFpQixHQUFHLGlCQUFpQixHQUFHLGdCQUFnQjs7QUFFNUY7O0FBRUEsaUJBQWlCLHVCQUF1QixJQUFJLHVCQUF1QixJQUFJLHVCQUF1Qjs7QUFFOUY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1Qyx3QkFBd0I7O0FBRS9EOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSx5QkFBeUI7O0FBRXpCO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsaURBQWlELEtBQUs7QUFDdEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUNBQXVDLEtBQUssZ0NBQWdDLFdBQVc7QUFDdkY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsZ0JBQWdCO0FBQ2hCO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0IsU0FBUzs7QUFFN0I7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdCQUF3QixrQkFBa0I7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJEQUEyRDs7QUFFM0Q7O0FBRUE7O0FBRUEsa0VBQWtFOztBQUVsRTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDOztBQUV0Qzs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxrQkFBa0IsU0FBUzs7QUFFM0I7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsa0JBQWtCLFVBQVU7O0FBRTVCLG1CQUFtQjtBQUNuQixhQUFhOztBQUViO0FBQ0E7O0FBRUE7QUFDQSxvQkFBb0I7O0FBRXBCOztBQUVBLHFCQUFxQjtBQUNyQixtQkFBbUI7O0FBRW5COztBQUVBOztBQUVBLHFCQUFxQixVQUFVOztBQUUvQjs7QUFFQTs7QUFFQSxrQkFBa0IsUUFBUTs7QUFFMUI7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUIsUUFBUTs7QUFFM0I7O0FBRUE7O0FBRUE7O0FBRUEsa0JBQWtCLFFBQVE7O0FBRTFCOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHdCQUF3QjtBQUN4QjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLCtIQUErSDtBQUMvSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw0QkFBNEIsZUFBZTs7QUFFM0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9DQUFvQyxPQUFPOztBQUUzQztBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUosb0NBQW9DLE9BQU87O0FBRTNDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUNBQW1DLE9BQU87O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQyxPQUFPOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQ0FBbUMsT0FBTzs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1QyxrQkFBa0I7O0FBRXpEOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEscUJBQXFCOztBQUVyQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwwREFBMEQsUUFBUTs7QUFFbEU7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsT0FBTzs7QUFFUDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwwREFBMEQsUUFBUTs7QUFFbEU7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsT0FBTzs7QUFFUDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEseUNBQXlDLFFBQVE7O0FBRWpEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDBEQUEwRCxRQUFROztBQUVsRTtBQUNBOztBQUVBLGlEQUFpRCxRQUFROztBQUV6RDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsNkJBQTZCOztBQUVoRDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDs7QUFFQSx1Q0FBdUMsUUFBUTs7QUFFL0M7O0FBRUE7QUFDQTs7QUFFQSw0Q0FBNEMsUUFBUTs7QUFFcEQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsdUNBQXVDLFFBQVE7O0FBRS9DOztBQUVBO0FBQ0E7O0FBRUEsNENBQTRDLFFBQVE7O0FBRXBEO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxpREFBaUQsUUFBUTs7QUFFekQ7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1QyxRQUFROztBQUUvQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLG1EQUFtRCxRQUFROztBQUUzRDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx1Q0FBdUMsUUFBUTs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLHdDQUF3QyxPQUFPOztBQUUvQzs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBLHFCQUFxQixjQUFjOztBQUVuQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxtREFBbUQ7O0FBRW5ELGdEQUFnRCxRQUFROztBQUV4RDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0MsT0FBTzs7QUFFN0M7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxnQkFBZ0I7O0FBRWhCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsZ0RBQWdELFFBQVE7O0FBRXhEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxtREFBbUQ7O0FBRW5ELCtDQUErQyxPQUFPOztBQUV0RDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0MsT0FBTzs7QUFFN0M7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdCQUF3QixrQkFBa0I7O0FBRTFDOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGlEQUFpRDs7QUFFakQ7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsaURBQWlELFFBQVE7O0FBRXpEOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsK0NBQStDLFFBQVE7O0FBRXZEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseUNBQXlDLFFBQVE7O0FBRWpEO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxvQ0FBb0MsUUFBUTs7QUFFNUM7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLHFEQUFxRDtBQUNyRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQSxtQ0FBbUMsUUFBUTs7QUFFM0M7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLG9EQUFvRDtBQUNwRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLHlDQUF5QyxRQUFROztBQUVqRDtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsb0NBQW9DLFFBQVE7O0FBRTVDO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxxREFBcUQ7QUFDckQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUEsbUNBQW1DLFFBQVE7O0FBRTNDO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxvREFBb0Q7QUFDcEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsaUdBQWlHO0FBQ2pHLGlHQUFpRztBQUNqRyw0RkFBNEY7QUFDNUYsZ0dBQWdHO0FBQ2hHLCtGQUErRjtBQUMvRixtR0FBbUc7O0FBRW5HOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxxQkFBcUIsYUFBYTs7QUFFbEM7O0FBRUEsc0JBQXNCLGFBQWE7O0FBRW5DOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEscUJBQXFCLFlBQVk7O0FBRWpDLHNCQUFzQixZQUFZOztBQUVsQztBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsa0JBQWtCLHFCQUFxQjs7QUFFdkM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsa0JBQWtCLGdCQUFnQjs7QUFFbEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdCQUF3Qjs7QUFFeEIsbUNBQW1DLDZFQUE2RSxHQUFHOztBQUVuSCxxQ0FBcUMsOENBQThDLEdBQUc7O0FBRXRGOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsb0JBQW9CO0FBQ3BCLHVCQUF1QjtBQUN2Qix5QkFBeUI7O0FBRXpCOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLGtDQUFrQzs7QUFFbEM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsdUJBQXVCO0FBQ3ZCLHVCQUF1Qjs7QUFFdkI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw2REFBNkQ7O0FBRTdEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLFdBQVcseUVBQXlFO0FBQ3BGOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxnRUFBZ0U7O0FBRWhFO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsa0JBQWtCO0FBQ2xCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsVUFBVSxrQ0FBa0M7O0FBRTVDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQSxrQkFBa0I7QUFDbEI7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsaUJBQWlCLGFBQWE7QUFDOUIsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLE9BQU87O0FBRTFCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLDhDQUE4QztBQUM5Qzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLDZDQUE2QyxPQUFPOztBQUVwRDs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSw0QkFBNEI7O0FBRTVCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG9CQUFvQixhQUFhOztBQUVqQzs7QUFFQSxxQkFBcUIsYUFBYTs7QUFFbEM7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsWUFBWTs7QUFFaEMscUJBQXFCLFlBQVk7O0FBRWpDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxSEFBcUg7O0FBRXJILDJGQUEyRixnQ0FBZ0MsdUhBQXVILEtBQUssZ0NBQWdDLDJEQUEyRCxLQUFLLGtEQUFrRCxnSEFBZ0gsNkRBQTZELHNIQUFzSCwySUFBMkksbURBQW1ELHNFQUFzRSxvREFBb0QsdUxBQXVMLHdHQUF3Ryw4Q0FBOEMsS0FBSzs7QUFFdHpDLHVHQUF1Rzs7QUFFdkcsZ0ZBQWdGOztBQUVoRiw2S0FBNksseUNBQXlDLHVEQUF1RDs7QUFFN1EsK0VBQStFOztBQUUvRSxtSUFBbUksdURBQXVELHFGQUFxRix1RkFBdUYscUlBQXFJLGlIQUFpSDs7QUFFNWxCLHVFQUF1RSxpQ0FBaUM7O0FBRXhHLGtKQUFrSixzREFBc0QsK0NBQStDLGdEQUFnRCxxREFBcUQsMkJBQTJCLHVCQUF1Qix1QkFBdUIsZ0VBQWdFLG9FQUFvRSxvRUFBb0Usb0VBQW9FLG9DQUFvQyxLQUFLLDhDQUE4Qyx1REFBdUQsdUJBQXVCLHVCQUF1QiwwRUFBMEUsS0FBSyw4RUFBOEUsK0NBQStDLDBEQUEwRCx1QkFBdUIsdUJBQXVCLHVCQUF1QixzRUFBc0UsS0FBSzs7QUFFbndDLHVIQUF1SDs7QUFFdkgsd0RBQXdELHVEQUF1RDs7QUFFL0csNkRBQTZELGlFQUFpRTs7QUFFOUgsNkNBQTZDLGdCQUFnQixHQUFHLHdFQUF3RSwrRUFBK0UsR0FBRyxzSkFBc0osbURBQW1ELHFEQUFxRCxzREFBc0Qsb0RBQW9ELHVDQUF1QywrQ0FBK0MseUJBQXlCLElBQUk7O0FBRXJyQixzTkFBc04seUNBQXlDLHFDQUFxQyxpRUFBaUUsS0FBSyxrRUFBa0UseUdBQXlHLEtBQUssb0VBQW9FLHdGQUF3RixLQUFLLG1EQUFtRCw0Q0FBNEMsNERBQTRELDREQUE0RCw0REFBNEQsMEdBQTBHLHlJQUF5SSx1QkFBdUIscUNBQXFDLGlCQUFpQixLQUFLLGlIQUFpSCxhQUFhLGlHQUFpRyw0RkFBNEYsNENBQTRDLGdDQUFnQywyQkFBMkIsT0FBTyw0Q0FBNEMsNkRBQTZELGtEQUFrRCw2QkFBNkIsd0JBQXdCLG9EQUFvRCwrQkFBK0IsbUVBQW1FLHVEQUF1RCxpREFBaUQsK0JBQStCLDJEQUEyRCwyREFBMkQsMkRBQTJELHVFQUF1RSx1Q0FBdUMsbURBQW1ELCtCQUErQiw0REFBNEQseUJBQXlCLGFBQWEsMEJBQTBCLHVCQUF1QixRQUFRLFFBQVEsbUJBQW1CLDhFQUE4RSxxQkFBcUIsT0FBTyxtQ0FBbUMsS0FBSzs7QUFFbDJGLDZFQUE2RSw0QkFBNEIsc0JBQXNCLHNDQUFzQyxzQ0FBc0MsaUVBQWlFLCtFQUErRSwrRUFBK0UsOEJBQThCLEtBQUssNkZBQTZGLHVEQUF1RCx1REFBdUQsMEJBQTBCLHFDQUFxQyxxQ0FBcUMsc0RBQXNELGtFQUFrRSwwREFBMEQsS0FBSzs7QUFFbjdCLDBFQUEwRSwwRUFBMEUsOEJBQThCLHNEQUFzRCwyQkFBMkIsUUFBUSxvQ0FBb0Msc0VBQXNFLDJEQUEyRCwyRkFBMkYsMENBQTBDLE9BQU8sdUhBQXVILDhFQUE4RSx5QkFBeUIsUUFBUSxzQ0FBc0Msd0VBQXdFLDZEQUE2RCx3R0FBd0csU0FBUyw2RUFBNkUsZ0RBQWdELDJDQUEyQywrREFBK0QsMkJBQTJCLFFBQVEsb0NBQW9DLGlFQUFpRSxPQUFPLDhHQUE4Ryw4RUFBOEUseUJBQXlCLFFBQVEsc0NBQXNDLDZFQUE2RSxTQUFTLDhEQUE4RDs7QUFFMzBELCtGQUErRix1REFBdUQ7O0FBRXRKLDZGQUE2Rjs7QUFFN0YsOEZBQThGOztBQUU5RiwrRUFBK0UsMkRBQTJEOztBQUUxSSxpRkFBaUYsb0RBQW9EOztBQUVySSwrRUFBK0Usd0hBQXdIOztBQUV2TSwyRUFBMkUseUhBQXlILDhDQUE4Qyx5RUFBeUUsOEdBQThHLG9DQUFvQzs7QUFFN2Msd1hBQXdYLGFBQWEsaUNBQWlDLGFBQWEsbUNBQW1DLGVBQWUsbUNBQW1DLGdCQUFnQixlQUFlLGtDQUFrQyxxQ0FBcUMscUNBQXFDLHFDQUFxQyx3Q0FBd0MsOERBQThELG1FQUFtRSxrQ0FBa0MsR0FBRyxpRUFBaUUscUJBQXFCLGdEQUFnRCw0Q0FBNEMsdURBQXVELEtBQUssZ0NBQWdDLGVBQWUsbUJBQW1CLGlCQUFpQixJQUFJLHlCQUF5Qix1QkFBdUIsd0JBQXdCLHlCQUF5QiwwQkFBMEIsSUFBSSxpREFBaUQsa0VBQWtFLDBEQUEwRCxHQUFHLGlFQUFpRSwwREFBMEQsR0FBRyx5Q0FBeUMsYUFBYSxvREFBb0Qsb0RBQW9ELG9EQUFvRCxlQUFlLEdBQUcsd0NBQXdDLGlFQUFpRSwrQkFBK0IsR0FBRyxzQ0FBc0MsZ0NBQWdDLEdBQUcsa0NBQWtDLDBEQUEwRCx1RUFBdUUsd0JBQXdCLEdBQUcsbURBQW1ELHdDQUF3QyxHQUFHLGdGQUFnRixvRUFBb0Usc0RBQXNELEdBQUcsa0ZBQWtGLG9FQUFvRSxzREFBc0QsSUFBSTs7QUFFenVGLHVLQUF1SywyQ0FBMkMseUJBQXlCLDhDQUE4Qyw2RkFBNkYsMkRBQTJELFFBQVEsTUFBTSw2RkFBNkYsMkRBQTJELE9BQU8sa0JBQWtCLEtBQUssOENBQThDLGNBQWMsMEJBQTBCLG1FQUFtRSxRQUFRLHlCQUF5Qix1RUFBdUUsUUFBUSx5QkFBeUIscUVBQXFFLFFBQVEseUJBQXlCLHFFQUFxRSxRQUFRLHlCQUF5QixxRUFBcUUsUUFBUSxNQUFNLG1FQUFtRSxPQUFPLGdDQUFnQyxLQUFLLDJFQUEyRSx3Q0FBd0MsZ0VBQWdFLGlEQUFpRCxzQ0FBc0MsMEVBQTBFLHlCQUF5Qix5QkFBeUIsb0JBQW9CLE9BQU8sOEJBQThCLG1EQUFtRCwwREFBMEQsaUNBQWlDLGtDQUFrQyx5R0FBeUcsc0RBQXNELGlCQUFpQiw4U0FBOFMsc0JBQXNCLHFDQUFxQyw0R0FBNEcsUUFBUSxvQ0FBb0MsNEdBQTRHLFFBQVEsb0NBQW9DLDRHQUE0RyxRQUFRLG9DQUFvQyw0R0FBNEcsUUFBUSxNQUFNLCtDQUErQyxLQUFLLGlCQUFpQixLQUFLLDZFQUE2RSxrRkFBa0YsZ0NBQWdDLGtDQUFrQyxnRUFBZ0UsMEJBQTBCLG1DQUFtQyxRQUFRLE1BQU0sd0VBQXdFLHdEQUF3RCxPQUFPLEtBQUs7O0FBRWpqSCxrRUFBa0UsZ0VBQWdFLGtFQUFrRSwyR0FBMkcsK0NBQStDLHlFQUF5RSw4RUFBOEUsMkdBQTJHLCtDQUErQyx5RUFBeUUseUVBQXlFLCtEQUErRCwrR0FBK0cscUVBQXFFOztBQUVwaEMsbUdBQW1HLG9DQUFvQyxtQ0FBbUM7O0FBRTFLLHFNQUFxTTs7QUFFck0sb0hBQW9ILCtDQUErQzs7QUFFbksseUZBQXlGOztBQUV6Riw4RUFBOEU7O0FBRTlFLCtNQUErTSx3TEFBd0wscURBQXFELHlFQUF5RSxHQUFHLHFEQUFxRCx5RUFBeUUsR0FBRyw0Q0FBNEMsaUJBQWlCLEdBQUcsMENBQTBDLHVLQUF1SyxHQUFHLHdDQUF3QyxpQkFBaUIsR0FBRyxzQ0FBc0MscUNBQXFDLEdBQUc7O0FBRXZpQyx1RkFBdUYsNkJBQTZCLG1IQUFtSCxRQUFRLE1BQU0sb0VBQW9FLE9BQU8seUVBQXlFLGtHQUFrRywyRkFBMkYsc0RBQXNELG9KQUFvSiwyQ0FBMkMsdUpBQXVKLGtJQUFrSSw4R0FBOEc7O0FBRWxzQyxzRkFBc0YsNkJBQTZCLGdDQUFnQyw0REFBNEQsd0NBQXdDOztBQUV2UCw0RUFBNEUsaU1BQWlNLG9DQUFvQyxxQ0FBcUM7O0FBRXRWLGtQQUFrUCxxQ0FBcUMsb0NBQW9DOztBQUUzVCxzR0FBc0csbUNBQW1DLDZCQUE2QixxSEFBcUgsUUFBUSxNQUFNLHlFQUF5RSxPQUFPLG9GQUFvRiw2RkFBNkYsc0ZBQXNGOztBQUVob0IsK0RBQStEOztBQUUvRCxpRUFBaUU7O0FBRWpFLDRJQUE0SSwwRUFBMEUsOEVBQThFOztBQUVwUyxpRUFBaUUsNEJBQTRCLGtEQUFrRCxxQ0FBcUMsMkJBQTJCOztBQUUvTSx5RkFBeUYsMEVBQTBFLGdEQUFnRCxnREFBZ0QsaUZBQWlGLCtDQUErQyw0RkFBNEYsYUFBYTs7QUFFNWUsZ0ZBQWdGLG9DQUFvQzs7QUFFcEgsd0RBQXdELDJDQUEyQywrQ0FBK0M7O0FBRWxKLCtEQUErRCwwQkFBMEIsc0JBQXNCLDJCQUEyQixJQUFJLDRRQUE0USwyRUFBMkUsZ0RBQWdELHVGQUF1RixHQUFHLDJRQUEyUSx5RkFBeUYsR0FBRzs7QUFFdDlCLG9EQUFvRCxpQ0FBaUMsa0VBQWtFLGlGQUFpRixtREFBbUQsaURBQWlELHVEQUF1RCx1REFBdUQsdURBQXVELDJEQUEyRCwyREFBMkQsb0VBQW9FLDJEQUEyRCxpRUFBaUUsa0JBQWtCLEdBQUcsdUZBQXVGLHVFQUF1RSxtRUFBbUUsc0JBQXNCLEdBQUcscUVBQXFFLHdDQUF3QyxzQkFBc0IsR0FBRyw2SEFBNkgsbUZBQW1GLGlDQUFpQywwRkFBMEYsS0FBSywyQkFBMkIsR0FBRyxvSEFBb0gsaUVBQWlFLEdBQUcscURBQXFELHFCQUFxQixpQkFBaUIsTUFBTSxpRUFBaUUseUdBQXlHLDJDQUEyQyxtREFBbUQsMkJBQTJCLEtBQUsseURBQXlELG9CQUFvQixpQkFBaUIscUJBQXFCLGtCQUFrQixNQUFNLHVEQUF1RCx1SEFBdUgsNERBQTRELDZDQUE2Qyw4Q0FBOEMscUNBQXFDLG9HQUFvRyxxREFBcUQsS0FBSyx1REFBdUQsb0JBQW9CLHFCQUFxQixpQkFBaUIscUJBQXFCLGtCQUFrQixvQkFBb0Isd0JBQXdCLE1BQU0sb0RBQW9ELG9IQUFvSCwyREFBMkQsNkNBQTZDLG1FQUFtRSx1R0FBdUcsb0NBQW9DLGdEQUFnRCx3REFBd0Qsb0dBQW9HLHVEQUF1RCxRQUFRLE1BQU0sa0NBQWtDLDhCQUE4QixPQUFPLEtBQUssZ0VBQWdFLGlCQUFpQixvQkFBb0IscUJBQXFCLHNCQUFzQixNQUFNLDRCQUE0QiwwQkFBMEIsaUVBQWlFLDZEQUE2RCxxQkFBcUIsb0JBQW9CLHVCQUF1QixNQUFNLGdFQUFnRSxtR0FBbUcsdURBQXVELGtEQUFrRCw0RkFBNEYsd0JBQXdCLEtBQUs7O0FBRXhoSix5R0FBeUcsMkdBQTJHLHNGQUFzRixzREFBc0Qsc0NBQXNDLGlCQUFpQixrR0FBa0csdUZBQXVGLGtGQUFrRix5RUFBeUUsMkZBQTJGLGlEQUFpRCxzQ0FBc0MsaUJBQWlCLDJMQUEyTCwwRkFBMEYsbUVBQW1FLHNIQUFzSCxrRUFBa0UsMENBQTBDLHFCQUFxQjs7QUFFNy9DLGtEQUFrRCwyQ0FBMkM7O0FBRTdGLDREQUE0RCx1QkFBdUIsc0JBQXNCLElBQUksc1FBQXNRLHlHQUF5Ryx1RkFBdUYsR0FBRyxxUUFBcVEseUZBQXlGLEdBQUc7O0FBRXY1Qix5REFBeUQsMkNBQTJDLG9DQUFvQyx5Q0FBeUMsK0NBQStDOztBQUVoTyw2REFBNkQsNkJBQTZCLHNCQUFzQix1QkFBdUIsNEJBQTRCLDJCQUEyQixJQUFJLGtSQUFrUiwyRUFBMkUsZ0RBQWdELHVGQUF1Riw0TUFBNE0sR0FBRyxpUkFBaVIseUZBQXlGLEdBQUc7O0FBRWx1QywwREFBMEQsdUVBQXVFLHlGQUF5Riw4REFBOEQsc0RBQXNELHdDQUF3QyxzREFBc0QsbUNBQW1DLCtFQUErRSwrQ0FBK0Msd0hBQXdILGtKQUFrSiw4RkFBOEYsbURBQW1ELDZDQUE2QyxpQ0FBaUMsNk1BQTZNLDJGQUEyRiwrQkFBK0IsaUVBQWlFLHFEQUFxRCx3Q0FBd0MsZ0NBQWdDLG9HQUFvRyxtSkFBbUosa0VBQWtFLDJFQUEyRSxxREFBcUQsMEVBQTBFLG9FQUFvRSx1RUFBdUUsNkNBQTZDLDRHQUE0RyxzUEFBc1AsMkVBQTJFLHlFQUF5RSwyR0FBMkcsMkVBQTJFLHlIQUF5SCx5TEFBeUwsOEVBQThFLGlIQUFpSCxtREFBbUQsMERBQTBELHNDQUFzQyxxQ0FBcUMsTUFBTSxNQUFNLHlDQUF5Qyw0REFBNEQsS0FBSywwRkFBMEYsK0VBQStFLCtFQUErRTs7QUFFejdILDhEQUE4RCxzQkFBc0Isb0JBQW9CLHVCQUF1QixzQkFBc0IscUJBQXFCLDhDQUE4QywrQkFBK0IsdUJBQXVCLHlCQUF5Qiw0REFBNEQsMkJBQTJCLGlDQUFpQyw4QkFBOEIseUJBQXlCLG9EQUFvRCwyQkFBMkIsd0NBQXdDLDhEQUE4RCw4QkFBOEIsc0JBQXNCLGdDQUFnQyw0QkFBNEIsMERBQTBELG1CQUFtQix1QkFBdUIsdUJBQXVCLGNBQWMsNkNBQTZDLCtDQUErQyx5Q0FBeUMsMENBQTBDLG1GQUFtRiwrQ0FBK0MsdUJBQXVCLG1EQUFtRCxxREFBcUQsR0FBRyxtR0FBbUcsNkJBQTZCLGlFQUFpRSxpRUFBaUUseUNBQXlDLEdBQUcsNkRBQTZELDZCQUE2QixxREFBcUQsOENBQThDLEdBQUcsd1BBQXdQLGlGQUFpRixpRkFBaUYsa0NBQWtDLHlCQUF5QixLQUFLLCtJQUErSSxpQ0FBaUMsd0VBQXdFLG1DQUFtQyx5QkFBeUIsOENBQThDLEtBQUsscUtBQXFLLHFDQUFxQyx3Q0FBd0Msb0RBQW9ELHNDQUFzQyxxREFBcUQsd0RBQXdELHVEQUF1RCx1REFBdUQsd0RBQXdELDJDQUEyQyw2REFBNkQsc0NBQXNDLDJCQUEyQixLQUFLLG9JQUFvSSxxQ0FBcUMscUNBQXFDLHlDQUF5QyxvQ0FBb0MsbURBQW1ELHNEQUFzRCxxREFBcUQscURBQXFELHNEQUFzRCx5Q0FBeUMsZ0dBQWdHLDZGQUE2Rix5REFBeUQseURBQXlELDBEQUEwRCx5REFBeUQseURBQXlELHNIQUFzSCxpRkFBaUYsc0VBQXNFLHNDQUFzQyxtQ0FBbUMsR0FBRyw2RUFBNkUsZ0NBQWdDLDBEQUEwRCwwQ0FBMEMsMENBQTBDLHFEQUFxRCxtQ0FBbUMsY0FBYyxHQUFHLHdEQUF3RCwwQkFBMEIscURBQXFELEdBQUcsdUVBQXVFLDRCQUE0Qix1QkFBdUIsNERBQTRELGdEQUFnRCxvQkFBb0IsK0ZBQStGLDRDQUE0QyxHQUFHLDZIQUE2SCxnREFBZ0QsZ0RBQWdELHVDQUF1QywyRUFBMkUsZ0JBQWdCLDBDQUEwQywwQkFBMEIseURBQXlELHFCQUFxQixnREFBZ0QsZ0RBQWdELGdEQUFnRCxnREFBZ0QsMkNBQTJDLDJDQUEyQywyQ0FBMkMsMkNBQTJDLHdDQUF3Qyw2RUFBNkUsNkVBQTZFLDZFQUE2RSw2RUFBNkUsbUVBQW1FLDBCQUEwQixHQUFHLDZFQUE2RSxvQ0FBb0MsaUNBQWlDLGdDQUFnQyxnREFBZ0QsNEVBQTRFLEdBQUcsK0NBQStDLHlFQUF5RSxHQUFHLDBJQUEwSSxtREFBbUQsc0RBQXNELHFEQUFxRCxxREFBcUQsaURBQWlELHdDQUF3QyxrQ0FBa0MsR0FBRyx1R0FBdUcscURBQXFELHFDQUFxQywrR0FBK0csMkdBQTJHLDhGQUE4RiwwQ0FBMEMsR0FBRywyRkFBMkYscURBQXFELDBEQUEwRCxvREFBb0QsaUNBQWlDLHNFQUFzRSxrREFBa0QsZUFBZSxHQUFHLDBKQUEwSix1REFBdUQsdURBQXVELEdBQUcsZ1RBQWdULDJOQUEyTiwrREFBK0QsMkZBQTJGLHVDQUF1Qyw2REFBNkQsOEJBQThCLDBCQUEwQiw2Q0FBNkMsa0RBQWtELDRCQUE0Qiw4QkFBOEIsR0FBRyx5VEFBeVQsbUNBQW1DLHFDQUFxQyx1Q0FBdUMsNkNBQTZDLCtDQUErQyxpREFBaUQsNENBQTRDLDJDQUEyQywyQkFBMkIsMERBQTBELHdEQUF3RCwwREFBMEQsMERBQTBELHFEQUFxRCx1Q0FBdUMsdUNBQXVDLHdIQUF3SCx5R0FBeUcsMEhBQTBILDhJQUE4SSxLQUFLLHNSQUFzUiwyRUFBMkUsZ0RBQWdELGdIQUFnSCxzREFBc0QsZ0pBQWdKLDJMQUEyTCx5SUFBeUksdUZBQXVGLEdBQUcsNlFBQTZRLHlGQUF5RixHQUFHLHNVQUFzVSxxTkFBcU4seUtBQXlLLGtEQUFrRCx1Q0FBdUMsK0RBQStELDZQQUE2UCw4S0FBOEssd0VBQXdFLDJIQUEySCxtRUFBbUUsa0ZBQWtGLHlFQUF5RSxHQUFHLHFWQUFxVixrSEFBa0gsR0FBRzs7QUFFbGdlLHVFQUF1RSwrQkFBK0IsMkZBQTJGLDZDQUE2QyxvRUFBb0UsOEZBQThGLGlEQUFpRCxpQ0FBaUMsTUFBTSxNQUFNLDhEQUE4RCxLQUFLLHVDQUF1QyxtSkFBbUoseUZBQXlGLEtBQUssb0NBQW9DLGdGQUFnRixxR0FBcUcsNERBQTRELHNCQUFzQixRQUFRLG9DQUFvQyxxRUFBcUUsdUlBQXVJLDZVQUE2VSxpSkFBaUosS0FBSyxnSEFBZ0gsbUJBQW1CLHdCQUF3Qix3QkFBd0Isa0dBQWtHLDREQUE0RCxxQkFBcUIsUUFBUSxrQ0FBa0MsbUVBQW1FLDRmQUE0Zix5RkFBeUYseUZBQXlGLG1HQUFtRyxpTEFBaUwsNFBBQTRQLGlKQUFpSixLQUFLLDZIQUE2SCwrR0FBK0csNERBQTRELG9CQUFvQixRQUFRLGdEQUFnRCwrREFBK0QsaUpBQWlKLHVTQUF1UyxpSkFBaUosS0FBSyxzSUFBc0ksa0RBQWtELDBCQUEwQixRQUFRLDBDQUEwQyxnSkFBZ0osS0FBSywyR0FBMkcscUVBQXFFLDZHQUE2RywrRkFBK0YscUJBQXFCLFFBQVEsNEZBQTRGLE9BQU8sbUhBQW1ILHlDQUF5Qzs7QUFFeHFMLGtKQUFrSixzRUFBc0UsdUNBQXVDLDBKQUEwSixxUEFBcVAsaUdBQWlHLHFKQUFxSjs7QUFFcDRCLHVNQUF1TSx3TkFBd047O0FBRS9aLCtKQUErSjs7QUFFL0osK0ZBQStGLDZCQUE2QixpQ0FBaUM7O0FBRTdKLGtGQUFrRixpQ0FBaUM7O0FBRW5ILHFGQUFxRixzRUFBc0U7O0FBRTNKLDBGQUEwRiw4UkFBOFIsc0RBQXNEOztBQUU5YSxpRUFBaUU7O0FBRWpFLGtJQUFrSSxnR0FBZ0csMkVBQTJFLCtFQUErRTs7QUFFNVgsbUZBQW1GLDJGQUEyRiw0REFBNEQsNERBQTREOztBQUV0UywrREFBK0QsOEZBQThGLHdDQUF3Qzs7QUFFck0sNEZBQTRGOztBQUU1Riw2R0FBNkcsZ0dBQWdHLHFCQUFxQix3QkFBd0IsUUFBUSxpR0FBaUcsS0FBSzs7QUFFeFcsOEZBQThGLHFCQUFxQix3QkFBd0IsUUFBUSwwSkFBMEosMEpBQTBKLGlCQUFpQjs7QUFFeGQsOEZBQThGLHFCQUFxQix3QkFBd0IsUUFBUSw4SEFBOEgsS0FBSzs7QUFFdFIsbUlBQW1JLGdFQUFnRSx5REFBeUQsMENBQTBDLG1HQUFtRywwRUFBMEUscURBQXFELHlEQUF5RCxzREFBc0QsMkRBQTJELEtBQUs7O0FBRXZyQiw2RkFBNkYscUJBQXFCLHdCQUF3QixRQUFRLDZIQUE2SCxLQUFLOztBQUVwUixnRkFBZ0YseURBQXlELHFDQUFxQyxpREFBaUQsOENBQThDLHFEQUFxRCxzT0FBc08sOE9BQThPLG1HQUFtRyw4QkFBOEIseUpBQXlKLDZGQUE2RixvR0FBb0csK0JBQStCLHFEQUFxRDs7QUFFcjBDLDhIQUE4SCw2Q0FBNkMsdUVBQXVFLDBEQUEwRCxrSEFBa0gsMkJBQTJCLHFDQUFxQyxtSEFBbUg7O0FBRWpsQix3RUFBd0Usa0RBQWtELDhCQUE4Qjs7QUFFeEosc0VBQXNFLGtEQUFrRCw4QkFBOEI7O0FBRXRKLHFGQUFxRix1RUFBdUUsdUVBQXVFOztBQUVuTyxtRkFBbUYsNkJBQTZCLHdFQUF3RSw0TkFBNE4sb0NBQW9DLG9DQUFvQywrQkFBK0IsK0JBQStCLHlCQUF5QixtQ0FBbUMsbUNBQW1DLCtDQUErQywrQ0FBK0Msa0RBQWtELDhEQUE4RCw2Q0FBNkMsS0FBSzs7QUFFejNCLHlHQUF5Rzs7QUFFekcsb0tBQW9LLDZDQUE2Qyx3REFBd0Q7O0FBRXpRLHlGQUF5RixpRkFBaUYsc0NBQXNDLHVGQUF1Rjs7QUFFdlMsK0ZBQStGLDJGQUEyRjs7QUFFMUwsMkRBQTJELGdGQUFnRiwrREFBK0Q7O0FBRTFNLDZEQUE2RCwyQ0FBMkMsR0FBRywrQ0FBK0MsK0JBQStCLEdBQUcsd0NBQXdDLDBDQUEwQyx5RUFBeUUsdUVBQXVFLHNDQUFzQyw0Q0FBNEMsaURBQWlELGlDQUFpQyx5QkFBeUIsR0FBRyw4Q0FBOEMsbUNBQW1DLEdBQUcsMENBQTBDLG1DQUFtQyxHQUFHLGtEQUFrRCx1REFBdUQsR0FBRyxrQ0FBa0MsMEVBQTBFLGtFQUFrRSxHQUFHLG9DQUFvQyxnRUFBZ0UsR0FBRyxtR0FBbUcsNkNBQTZDLEdBQUcsbUdBQW1HLHlDQUF5QyxHQUFHLGtHQUFrRyxtRUFBbUUsR0FBRyxrR0FBa0csNkRBQTZELEdBQUc7O0FBRWx2RCxxR0FBcUc7O0FBRXJHLGlFQUFpRSxrRUFBa0UsNEVBQTRFLG9EQUFvRCw4Q0FBOEM7O0FBRWpULCtGQUErRjs7QUFFL0YsaUZBQWlGLG9EQUFvRCxnRkFBZ0YsK0ZBQStGLHNDQUFzQyxLQUFLOztBQUUvViwrREFBK0QsOEZBQThGLHdDQUF3Qzs7QUFFck0sNEZBQTRGOztBQUU1RixzSEFBc0gsK0ZBQStGLHFJQUFxSSxvRUFBb0UscUNBQXFDLDhCQUE4Qix5QkFBeUIsK0JBQStCLDJCQUEyQiwyQkFBMkIsUUFBUSxzRkFBc0YsNEdBQTRHLDhCQUE4Qiw4QkFBOEIseUJBQXlCLCtCQUErQiwyQkFBMkIsMkJBQTJCLFFBQVEseUVBQXlFLCtHQUErRyxnRUFBZ0UsK0JBQStCLDhCQUE4Qix5QkFBeUIsK0JBQStCLDJCQUEyQiwyQkFBMkIsK0JBQStCLDhCQUE4QixRQUFRLDRFQUE0RSxrRkFBa0YsMkVBQTJFLEtBQUssNkRBQTZELDBEQUEwRCxLQUFLLGdFQUFnRSw0QkFBNEIsOERBQThELDJEQUEyRCxnQ0FBZ0MsbURBQW1ELHlFQUF5RSxrRkFBa0YsZ0dBQWdHLDhFQUE4RSxPQUFPLHVCQUF1QixLQUFLLCtJQUErSSx5QkFBeUIsdUNBQXVDLGtDQUFrQyxvSEFBb0gsMkRBQTJELDBCQUEwQiw0RkFBNEYsaURBQWlELGlEQUFpRCxpREFBaUQsaURBQWlELDhCQUE4Qiw4QkFBOEIsOEJBQThCLDhCQUE4QixtaURBQW1pRCxtR0FBbUcsK0JBQStCLCtCQUErQixpQ0FBaUMsbURBQW1ELDRCQUE0QixvK0NBQW8rQyxnSEFBZ0gseUZBQXlGLG1CQUFtQixpREFBaUQsS0FBSywrQ0FBK0MsMkJBQTJCLHFFQUFxRSwwQkFBMEIsb0RBQW9ELHlCQUF5Qiw0Q0FBNEMsMkNBQTJDLGtDQUFrQyx1REFBdUQsUUFBUSxpQ0FBaUMsa0NBQWtDLDZDQUE2QyxRQUFRLGlDQUFpQyxrQ0FBa0MsMkNBQTJDLHFDQUFxQyxPQUFPLGdFQUFnRSxLQUFLLG1NQUFtTSx5QkFBeUIsNkNBQTZDLG9FQUFvRSxnSEFBZ0gseUdBQXlHLHVCQUF1QixpREFBaUQsNEVBQTRFLG9MQUFvTCxvMUJBQW8xQixpR0FBaUcscUJBQXFCLGlEQUFpRCxLQUFLOztBQUVoNlMsb0hBQW9ILDBEQUEwRCxtSUFBbUksb0VBQW9FLHFDQUFxQyw4QkFBOEIseUJBQXlCLCtCQUErQiwyQkFBMkIsMkJBQTJCLFFBQVEsc0ZBQXNGLDBFQUEwRSw4QkFBOEIseUJBQXlCLCtCQUErQiwyQkFBMkIsMkJBQTJCLFFBQVEseUVBQXlFLDZHQUE2RyxnRUFBZ0UsK0JBQStCLDhCQUE4Qix5QkFBeUIsK0JBQStCLDJCQUEyQiwyQkFBMkIsK0JBQStCLDhCQUE4QixRQUFRLDRFQUE0RTs7QUFFcDVDLGlQQUFpUCw2QkFBNkIsNkhBQTZILDJCQUEyQixRQUFRLDJIQUEySCwwRkFBMEYsT0FBTyxnSUFBZ0ksNkJBQTZCLFFBQVEscUhBQXFILDhFQUE4RSxPQUFPLGdJQUFnSSwyQkFBMkIsUUFBUSwwQ0FBMEMsb0xBQW9MLG9GQUFvRixLQUFLOztBQUVuOUMsdURBQXVELHVCQUF1QixxR0FBcUcsa0RBQWtELDJCQUEyQixRQUFRLHNEQUFzRCx5T0FBeU8sS0FBSyxxR0FBcUcsa0RBQWtELDRCQUE0QixRQUFRLHdDQUF3Qyw4TEFBOEwsS0FBSyx3R0FBd0csa0RBQWtELDZCQUE2QixRQUFRLDBDQUEwQyxtUUFBbVEsS0FBSyxpRUFBaUUsR0FBRzs7QUFFdmdELDJGQUEyRixpREFBaUQsaURBQWlELGlEQUFpRDs7QUFFOU8sMkVBQTJFLG1DQUFtQyx3Q0FBd0MsNENBQTRDLGlEQUFpRCwyQkFBMkIsdUJBQXVCLHVCQUF1Qiw0REFBNEQsZ0VBQWdFLGdFQUFnRSxnRUFBZ0Usb0NBQW9DLEtBQUs7O0FBRWptQixzR0FBc0csK0JBQStCLG9EQUFvRCxvREFBb0Qsb0RBQW9ELG9EQUFvRCxzREFBc0Q7O0FBRTNZLDhFQUE4RSwwQ0FBMEMsMENBQTBDLDBDQUEwQywwQ0FBMEMsNkRBQTZELHNFQUFzRSxnR0FBZ0c7O0FBRXpkLG1EQUFtRCwwRkFBMEYsdUNBQXVDLGtDQUFrQzs7QUFFdE4seUZBQXlGOztBQUV6Riw4R0FBOEc7O0FBRTlHLHlJQUF5SSx3Q0FBd0MsbURBQW1ELEdBQUcsMENBQTBDLGlDQUFpQyx1REFBdUQsR0FBRyxpREFBaUQsaUNBQWlDLDhDQUE4Qyw0R0FBNEcsR0FBRywrQkFBK0IsaURBQWlELHlEQUF5RCxpQkFBaUIsR0FBRyw0Q0FBNEMsOEpBQThKLHdLQUF3Syx1Q0FBdUMsaUNBQWlDLGtDQUFrQyxrQ0FBa0MsNkJBQTZCLEdBQUcsMEtBQTBLLDhKQUE4SiwyQ0FBMkMsb0JBQW9CLHNCQUFzQiw4SUFBOEksR0FBRyxxQ0FBcUMsOFBBQThQLHdSQUF3UixzQ0FBc0Msa0NBQWtDLGlDQUFpQyxrREFBa0QsbUNBQW1DLGdDQUFnQyx3QkFBd0IsMkRBQTJELHFDQUFxQyw4Q0FBOEMsb0NBQW9DLDBEQUEwRCxrREFBa0QscUNBQXFDLGlCQUFpQixHQUFHLHlDQUF5Qyw4Q0FBOEMsb0NBQW9DLGlDQUFpQyxzREFBc0Qsc0RBQXNELG9CQUFvQix5REFBeUQsZ0RBQWdELG9DQUFvQyxpRUFBaUUsNEJBQTRCLG1FQUFtRSw0Q0FBNEMsR0FBRyx5Q0FBeUMsZUFBZTs7QUFFNW5ILDZGQUE2RixxQ0FBcUMsbUNBQW1DLHVEQUF1RCxpREFBaUQsZ0hBQWdILDhHQUE4Ryx3Q0FBd0MsK0NBQStDLDZEQUE2RCw4VEFBOFQseUdBQXlHLCtFQUErRTs7QUFFcm5DLHdGQUF3Riw0QkFBNEIsc0NBQXNDLGtDQUFrQyxzRUFBc0UsMEVBQTBFLG1EQUFtRCw2Q0FBNkMsNkJBQTZCLGtDQUFrQyxnQ0FBZ0MseUJBQXlCLHVFQUF1RSxLQUFLLHlCQUF5QixrRUFBa0UsS0FBSyx3QkFBd0IsNkVBQTZFLEtBQUsseUJBQXlCLDJDQUEyQyxLQUFLLHlCQUF5QiwrQkFBK0IsS0FBSyx5QkFBeUIsK0JBQStCLEtBQUsseUJBQXlCLHFEQUFxRCxLQUFLLHlCQUF5QixtREFBbUQsS0FBSyx1RUFBdUUsbUNBQW1DLDZCQUE2Qiw2QkFBNkIsOEJBQThCLDhCQUE4Qiw4QkFBOEIsOEJBQThCLDhCQUE4Qiw4QkFBOEIsMEVBQTBFLDBFQUEwRSwwRUFBMEUsMEVBQTBFLGtNQUFrTSxLQUFLLGtFQUFrRSxpRUFBaUUsdUVBQXVFLHdDQUF3Qyx3Q0FBd0MseUZBQXlGLHdGQUF3RixtREFBbUQsS0FBSyxnSkFBZ0osd0VBQXdFLHNCQUFzQiw0REFBNEQsNERBQTRELDREQUE0RCxvRUFBb0UsS0FBSywrRUFBK0UsNERBQTRELEtBQUsseUdBQXlHLDRGQUE0Rix5RUFBeUUsS0FBSyx1SUFBdUksMkNBQTJDLDJCQUEyQixRQUFRLE1BQU0scUZBQXFGLG9GQUFvRiwyQkFBMkIsT0FBTyxLQUFLLHViQUF1Yiw0QkFBNEIseUJBQXlCLHlGQUF5RixvRUFBb0UseUJBQXlCLE9BQU8sUUFBUSxxR0FBcUcsNkRBQTZELHNGQUFzRix1REFBdUQsa0NBQWtDLGtDQUFrQywwR0FBMEcsMERBQTBELHFEQUFxRCw4SUFBOEksU0FBUyxrQ0FBa0Msb0hBQW9ILDJEQUEyRCw4RUFBOEUscURBQXFELGdDQUFnQyxnQ0FBZ0MscUZBQXFGLDZIQUE2SCxvRkFBb0YsOEVBQThFLGdHQUFnRyw2R0FBNkcsS0FBSzs7QUFFbHBNLCtGQUErRixnREFBZ0QsMERBQTBELDBEQUEwRCxvREFBb0Qsd0RBQXdELDREQUE0RCxnRUFBZ0Usa0VBQWtFLGtFQUFrRSxvRUFBb0Usa0VBQWtFLCtFQUErRSxxRkFBcUYsc0VBQXNFLHlGQUF5RixxRUFBcUUsNkVBQTZFLGdFQUFnRSwyRUFBMkUsbUZBQW1GLDhFQUE4RSxvQ0FBb0Msd0VBQXdFLGlDQUFpQzs7QUFFbm9ELDZGQUE2RixzREFBc0Qsd0JBQXdCLGdFQUFnRSw2QkFBNkIsZ0VBQWdFLDZCQUE2QiwwREFBMEQsMEJBQTBCLDhEQUE4RCw0QkFBNEIsa0VBQWtFLDhCQUE4Qiw4RUFBOEUsb0NBQW9DLHNFQUFzRSxnQ0FBZ0Msd0VBQXdFLGlDQUFpQyx3RUFBd0UsaUNBQWlDLDBFQUEwRSxrQ0FBa0Msd0VBQXdFLGlDQUFpQyxxRkFBcUYsdUNBQXVDLDJGQUEyRiwwQ0FBMEMsMkVBQTJFLGtDQUFrQyxtRkFBbUYsc0NBQXNDLDRFQUE0RSxtQ0FBbUMsK0ZBQStGLDRDQUE0QyxzRUFBc0UsZ0NBQWdDLGlGQUFpRixxQ0FBcUMseUZBQXlGLHlDQUF5Qyw4RUFBOEUsb0NBQW9DLHdFQUF3RSxpQ0FBaUM7O0FBRTVnRiw4RkFBOEYsNkVBQTZFLGlHQUFpRyxpR0FBaUcscUZBQXFGLDZGQUE2RixxR0FBcUcsNkhBQTZILDZHQUE2RyxpSEFBaUgsaUhBQWlILHFIQUFxSCxpSEFBaUgsMklBQTJJLHVKQUF1Six5SEFBeUgsK0pBQStKLHVIQUF1SCx1SUFBdUksNkdBQTZHLG1JQUFtSSxtSkFBbUosNkhBQTZILGlIQUFpSDs7QUFFL3RGLG1OQUFtTiw0RUFBNEUsd0ZBQXdGLDBEQUEwRDs7QUFFamIsbUNBQW1DLDJCQUEyQixlQUFlLDZDQUE2QyxnREFBZ0QsR0FBRzs7QUFFN0ssMENBQTBDLG9DQUFvQyxtQkFBbUIsZUFBZSwwQ0FBMEMsdU9BQXVPLGtEQUFrRCw0QkFBNEIsd0VBQXdFOztBQUV2aEIsK0NBQStDLGtDQUFrQyxrRUFBa0UsMEZBQTBGLEdBQUc7O0FBRWhQLDBFQUEwRSxtRUFBbUUsbUNBQW1DLHFDQUFxQyxvQ0FBb0Msa0NBQWtDLCtCQUErQix1REFBdUQsd0pBQXdKLGtKQUFrSiwwREFBMEQsa0RBQWtELDRCQUE0Qix3RUFBd0U7O0FBRTMyQiwrQ0FBK0Msa0NBQWtDLGtFQUFrRSwwRkFBMEYsR0FBRzs7QUFFaFAsOENBQThDLHNCQUFzQix3QkFBd0IsK0JBQStCLGVBQWUsZ0dBQWdHLDRCQUE0Qiw4QkFBOEIsd0VBQXdFOztBQUU1Vyx3VEFBd1QsZUFBZSwrZ0JBQStnQixHQUFHOztBQUV6MUIsdUVBQXVFLHFVQUFxVSxlQUFlLG9DQUFvQyxtR0FBbUcsdVBBQXVQLDRGQUE0RixrRkFBa0YsYUFBYTs7QUFFcDlCLGdFQUFnRSxtUEFBbVAsNmdCQUE2Z0IsR0FBRzs7QUFFbjBCLHFFQUFxRSw2QkFBNkIsNEJBQTRCLDhCQUE4Qix1UUFBdVEsb0NBQW9DLGtPQUFrTyxvRUFBb0UsNEJBQTRCLDJDQUEyQyxHQUFHOztBQUV2ekIsK0NBQStDLGtDQUFrQyxrRUFBa0UsMkRBQTJEOztBQUU5TSxnREFBZ0QsK0JBQStCLGtDQUFrQyxrREFBa0QsNENBQTRDLG9EQUFvRCx3RUFBd0U7O0FBRTNVLHNDQUFzQywrQkFBK0IsOEJBQThCLHVPQUF1Tyx5Q0FBeUMsaVRBQWlUOztBQUVwcUIseUNBQXlDLHdCQUF3Qix5QkFBeUIsMEJBQTBCLDhCQUE4QiwyT0FBMk8saURBQWlELDhGQUE4RixjQUFjLEtBQUsscUNBQXFDLGdJQUFnSSw0S0FBNEs7O0FBRWgzQix3VkFBd1Ysd3BCQUF3cEI7O0FBRWgvQix5Q0FBeUMsd0JBQXdCLDhDQUE4QyxvakJBQW9qQixpREFBaUQsZ1hBQWdYLHFGQUFxRiw4RkFBOEYsNkRBQTZELDhGQUE4Rix3REFBd0QsMk9BQTJPOztBQUVyckQsOERBQThELGliQUFpYiwwbEJBQTBsQixxSEFBcUg7O0FBRTlyQywwREFBMEQsd0JBQXdCLHdCQUF3QiwwMEJBQTAwQixpREFBaUQsZ0pBQWdKLDBDQUEwQyxxbUJBQXFtQiwyT0FBMk87O0FBRS8rRCw2REFBNkQsZ1hBQWdYLG1uQkFBbW5CLEdBQUc7O0FBRW5pQyx5REFBeUQsd0JBQXdCLDJCQUEyQiw2QkFBNkIsaWVBQWllLGlEQUFpRCx5VkFBeVYsOERBQThELGlDQUFpQyx1RUFBdUUsc0VBQXNFLDZFQUE2RSxzRUFBc0UsNk1BQTZNOztBQUVoa0QsOEpBQThKLDhUQUE4VCw4bkJBQThuQixXQUFXOztBQUVybUMsMERBQTBELDhIQUE4SCwrUEFBK1AsdURBQXVELHNOQUFzTiw0Q0FBNEMsYUFBYTs7QUFFN3ZCLDREQUE0RCxpYkFBaWIsMGxCQUEwbEIscUhBQXFIOztBQUU1ckMsd0RBQXdELHdCQUF3Qix3QkFBd0IsMEJBQTBCLHdCQUF3Qix3MEJBQXcwQixpREFBaUQsZ0pBQWdKLDBDQUEwQyxxcUJBQXFxQiwyT0FBMk87O0FBRTdsRSwrREFBK0QseURBQXlELDBaQUEwWiwwbEJBQTBsQixzSkFBc0osV0FBVzs7QUFFN3dDLDJIQUEySCx3QkFBd0IsMEJBQTBCLDBCQUEwQix3QkFBd0Isa0NBQWtDLGlFQUFpRSwrQkFBK0IseUVBQXlFLDJGQUEyRixvRUFBb0UscUNBQXFDLDREQUE0RCw4REFBOEQsaUNBQWlDLDhDQUE4Qyw4Q0FBOEMsc0RBQXNELGlDQUFpQyxtRUFBbUUscUZBQXFGLDJFQUEyRSxrRUFBa0UsK0NBQStDLG9pQ0FBb2lDLGlEQUFpRCxnSkFBZ0osMENBQTBDLDZzQkFBNnNCLHlGQUF5RixrSEFBa0gsNEZBQTRGLG9HQUFvRyxvSEFBb0gsbUZBQW1GLHdKQUF3Six1TkFBdU47O0FBRTdxSSwyREFBMkQsa1pBQWtaLDBsQkFBMGxCLHlGQUF5Rjs7QUFFaG9DLHVEQUF1RCx3QkFBd0Isd0JBQXdCLDh2QkFBOHZCLGlEQUFpRCxnSkFBZ0osMENBQTBDLCtqQkFBK2pCLDZNQUE2TTs7QUFFNTFELHFDQUFxQyxzQkFBc0Isd09BQXdPLDZCQUE2Qix1QkFBdUIsdUVBQXVFLHlOQUF5TixpR0FBaUcsc0VBQXNFLDBJQUEwSTs7QUFFeDZCLHlDQUF5Qyx3QkFBd0IsK1JBQStSLGlEQUFpRCw0RUFBNEUsMk1BQTJNLDRLQUE0Szs7QUFFcDFCLDBQQUEwUCxxZEFBcWQ7O0FBRS9zQix1Q0FBdUMsd0JBQXdCLG1QQUFtUCx5R0FBeUcsbUdBQW1HOztBQUU5Zix5Q0FBeUMsc0JBQXNCLHFLQUFxSywyRkFBMkYsZUFBZSwyRkFBMkYsMkZBQTJGLGtHQUFrRyxtREFBbUQsd0ZBQXdGLHlCQUF5QixrR0FBa0csa0dBQWtHLHFDQUFxQyxnREFBZ0Qsa0dBQWtHOztBQUVyb0MseUNBQXlDLHdCQUF3QixzVEFBc1QsaURBQWlELDRFQUE0RSxxTUFBcU0saUlBQWlJOztBQUUxekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLGFBQWEsNENBQTRDO0FBQ3pELGFBQWEsWUFBWTs7QUFFekIsU0FBUyxhQUFhO0FBQ3RCLGtCQUFrQixvQ0FBb0M7O0FBRXRELGNBQWMsYUFBYTtBQUMzQix1QkFBdUIsb0NBQW9DOztBQUUzRCxlQUFlOztBQUVmLEVBQUU7O0FBRUY7O0FBRUEsaUJBQWlCLGFBQWE7QUFDOUIsMEJBQTBCOztBQUUxQixFQUFFOztBQUVGOztBQUVBLFlBQVksYUFBYTtBQUN6QixvQkFBb0Isb0NBQW9DO0FBQ3hELGdCQUFnQixZQUFZO0FBQzVCLGtCQUFrQixZQUFZO0FBQzlCLFNBQVMsWUFBWTtBQUNyQixxQkFBcUIsYUFBYTs7QUFFbEMsRUFBRTs7QUFFRjs7QUFFQSxXQUFXLGFBQWE7QUFDeEIsb0JBQW9CLFVBQVU7QUFDOUIsb0JBQW9COztBQUVwQixFQUFFOztBQUVGOztBQUVBLGNBQWMsYUFBYTtBQUMzQix1QkFBdUIsVUFBVTtBQUNqQyx1QkFBdUI7O0FBRXZCLEVBQUU7O0FBRUY7O0FBRUEsYUFBYSxhQUFhO0FBQzFCLHNCQUFzQixvQ0FBb0M7QUFDMUQsZUFBZTs7QUFFZixFQUFFOztBQUVGOztBQUVBLGVBQWUsYUFBYTtBQUM1Qix3QkFBd0Isb0NBQW9DO0FBQzVELGlCQUFpQjs7QUFFakIsRUFBRTs7QUFFRjs7QUFFQSxxQkFBcUIsYUFBYTtBQUNsQyw4QkFBOEIsb0NBQW9DO0FBQ2xFLHVCQUF1QixVQUFVO0FBQ2pDLHNCQUFzQjs7QUFFdEIsRUFBRTs7QUFFRjs7QUFFQSxpQkFBaUIsYUFBYTtBQUM5QiwwQkFBMEI7O0FBRTFCLEVBQUU7O0FBRUY7O0FBRUEsa0JBQWtCLGFBQWE7QUFDL0IsMkJBQTJCOztBQUUzQixFQUFFOztBQUVGOztBQUVBLGtCQUFrQixhQUFhO0FBQy9CLDJCQUEyQjs7QUFFM0IsRUFBRTs7QUFFRjs7QUFFQSxpQkFBaUI7O0FBRWpCLEVBQUU7O0FBRUY7O0FBRUEsZ0JBQWdCLGdCQUFnQjtBQUNoQyxhQUFhLFVBQVU7QUFDdkIsWUFBWSxhQUFhO0FBQ3pCLGNBQWM7O0FBRWQsRUFBRTs7QUFFRjs7QUFFQSx1QkFBdUIsV0FBVzs7QUFFbEMsZ0JBQWdCLFdBQVc7O0FBRTNCLHVCQUF1QjtBQUN2QixnQkFBZ0I7QUFDaEI7QUFDQSxLQUFLOztBQUVMLDZCQUE2QjtBQUM3QjtBQUNBLGlCQUFpQjtBQUNqQix1QkFBdUI7QUFDdkIsbUJBQW1CO0FBQ25CO0FBQ0EsS0FBSzs7QUFFTCwwQkFBMEIsV0FBVztBQUNyQyw2QkFBNkIsV0FBVzs7QUFFeEMsZ0JBQWdCO0FBQ2hCLFlBQVk7QUFDWixlQUFlO0FBQ2YsZ0JBQWdCO0FBQ2hCLGVBQWU7QUFDZixjQUFjO0FBQ2Qsa0JBQWtCO0FBQ2xCO0FBQ0EsS0FBSzs7QUFFTCxzQkFBc0I7QUFDdEI7QUFDQSxpQkFBaUI7QUFDakIsdUJBQXVCO0FBQ3ZCLG1CQUFtQjtBQUNuQjtBQUNBLEtBQUs7O0FBRUwsa0JBQWtCLFdBQVc7QUFDN0IsbUJBQW1CLFdBQVc7QUFDOUIscUJBQXFCLFdBQVc7O0FBRWhDLGlCQUFpQjtBQUNqQixZQUFZO0FBQ1osZUFBZTtBQUNmLFlBQVk7QUFDWjtBQUNBLEtBQUs7O0FBRUwsdUJBQXVCO0FBQ3ZCO0FBQ0EsaUJBQWlCO0FBQ2pCLHVCQUF1QjtBQUN2QixtQkFBbUI7QUFDbkIsb0JBQW9CO0FBQ3BCLHVCQUF1QjtBQUN2QjtBQUNBLEtBQUs7O0FBRUwsb0JBQW9CLFdBQVc7QUFDL0IsdUJBQXVCLFdBQVc7O0FBRWxDLHNCQUFzQjtBQUN0QixnQkFBZ0I7QUFDaEIsZUFBZTtBQUNmO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLG9CQUFvQjtBQUNwQixZQUFZO0FBQ1osZUFBZTtBQUNmLFlBQVk7QUFDWjtBQUNBLEtBQUs7O0FBRUwsV0FBVyxhQUFhO0FBQ3hCLFdBQVc7O0FBRVgsRUFBRTs7QUFFRjs7QUFFQSxhQUFhLDRDQUE0QztBQUN6RCxhQUFhLFlBQVk7QUFDekIsVUFBVSxZQUFZO0FBQ3RCLFdBQVcsWUFBWTtBQUN2QixTQUFTLGFBQWE7QUFDdEIsY0FBYyxhQUFhO0FBQzNCLHVCQUF1QixvQ0FBb0M7QUFDM0QsZUFBZSxVQUFVO0FBQ3pCLGlCQUFpQjs7QUFFakIsRUFBRTs7QUFFRjs7QUFFQSxhQUFhLDRDQUE0QztBQUN6RCxhQUFhLFlBQVk7QUFDekIsWUFBWSw4Q0FBOEM7QUFDMUQsY0FBYyxZQUFZO0FBQzFCLFNBQVMsYUFBYTtBQUN0QixrQkFBa0Isb0NBQW9DO0FBQ3RELGNBQWMsYUFBYTtBQUMzQix1QkFBdUIsb0NBQW9DO0FBQzNELGVBQWU7O0FBRWY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsNENBQTRDO0FBQzVELGdCQUFnQiw0Q0FBNEM7QUFDNUQsaUJBQWlCO0FBQ2pCO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsNENBQTRDO0FBQzVELGlCQUFpQixZQUFZO0FBQzdCLGlCQUFpQixZQUFZO0FBQzdCLHVCQUF1QjtBQUN2QjtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxVQUFVO0FBQ3ZCLGdCQUFnQixVQUFVO0FBQzFCLGlCQUFpQjtBQUNqQjtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZTtBQUNmO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBLGtCQUFrQixvQ0FBb0M7QUFDdEQsVUFBVSxhQUFhO0FBQ3ZCLDBCQUEwQjtBQUMxQixHQUFHOztBQUVIO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBLGFBQWEsYUFBYTtBQUMxQixpQkFBaUIsWUFBWTtBQUM3QiwyQkFBMkIsVUFBVTtBQUNyQywwQkFBMEIsVUFBVTtBQUNwQyx5QkFBeUI7QUFDekIsR0FBRzs7QUFFSDtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQSxZQUFZLGFBQWE7QUFDekIsWUFBWSxZQUFZO0FBQ3hCLGNBQWM7QUFDZCxHQUFHOztBQUVIO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBLGdCQUFnQixhQUFhO0FBQzdCLEdBQUc7O0FBRUg7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLG9DQUFvQztBQUM3RCxvQkFBb0IsVUFBVTtBQUM5QixtQkFBbUI7QUFDbkI7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLDJDQUEyQztBQUN4RCxlQUFlO0FBQ2YsSUFBSTtBQUNKOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLFVBQVU7QUFDMUIsbUJBQW1CLGFBQWE7QUFDaEMsNEJBQTRCLG9DQUFvQztBQUNoRSx5QkFBeUIsYUFBYTtBQUN0QyxrQ0FBa0Msb0NBQW9DO0FBQ3RFLDJCQUEyQiwwQ0FBMEM7QUFDckUseUJBQXlCLFVBQVU7QUFDbkMsNEJBQTRCLGFBQWE7QUFDekMscUNBQXFDLG9DQUFvQztBQUN6RSxpQkFBaUIsVUFBVTtBQUMzQixrQkFBa0IsVUFBVTtBQUM1QixxQkFBcUIsYUFBYTtBQUNsQyw4QkFBOEIsb0NBQW9DO0FBQ2xFLHFCQUFxQixZQUFZO0FBQ2pDLGtDQUFrQyxZQUFZO0FBQzlDLGtDQUFrQyxZQUFZO0FBQzlDLDhCQUE4QixhQUFhO0FBQzNDLHVDQUF1QyxvQ0FBb0M7QUFDM0UsWUFBWSxVQUFVO0FBQ3RCLGlCQUFpQiw0Q0FBNEM7QUFDN0Qsb0JBQW9CLGFBQWE7QUFDakMsNkJBQTZCLG9DQUFvQztBQUNqRSxxQkFBcUIsVUFBVTtBQUMvQix3QkFBd0IsYUFBYTtBQUNyQyxpQ0FBaUMsb0NBQW9DO0FBQ3JFLG1CQUFtQixVQUFVO0FBQzdCLHNCQUFzQixhQUFhO0FBQ25DLCtCQUErQixvQ0FBb0M7QUFDbkUsOEJBQThCLG9DQUFvQztBQUNsRSw2QkFBNkIsYUFBYTtBQUMxQyxnQkFBZ0IsVUFBVTtBQUMxQixtQkFBbUIsYUFBYTtBQUNoQyw0QkFBNEIsb0NBQW9DO0FBQ2hFLDBCQUEwQixVQUFVO0FBQ3BDLHVCQUF1Qiw0Q0FBNEM7QUFDbkUsb0JBQW9CLDJDQUEyQztBQUMvRCx1QkFBdUIsYUFBYTtBQUNwQyxnQ0FBZ0Msb0NBQW9DO0FBQ3BFLHdCQUF3QixVQUFVO0FBQ2xDLDJCQUEyQixhQUFhO0FBQ3hDLG9DQUFvQyxvQ0FBb0M7QUFDeEUsdUJBQXVCLG9DQUFvQztBQUMzRCxvQkFBb0IsYUFBYTtBQUNqQyw2QkFBNkIsb0NBQW9DO0FBQ2pFO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxlQUFlO0FBQ2Y7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9EQUFvRDtBQUNwRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsbUJBQW1CLGdCQUFnQjs7QUFFbkM7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsR0FBRztBQUNIOztBQUVBOztBQUVBLEdBQUc7QUFDSDs7QUFFQTtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxtQkFBbUIseUJBQXlCOztBQUU1QztBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDhDQUE4QyxRQUFROztBQUV0RDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsa0RBQWtELFFBQVE7O0FBRTFEOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSx3QkFBd0IsbUNBQW1DOztBQUUzRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxRQUFROztBQUVSLHdCQUF3QixtQ0FBbUM7O0FBRTNEOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVCQUF1QixtQ0FBbUM7O0FBRTFEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBLHdCQUF3QixtQ0FBbUM7O0FBRTNEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFFBQVE7O0FBRVIsd0JBQXdCLG1DQUFtQzs7QUFFM0Q7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUJBQXVCLG1DQUFtQzs7QUFFMUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLG1CQUFtQixlQUFlOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsbUJBQW1COztBQUV2Qzs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0Esb0JBQW9CLGVBQWU7O0FBRW5DOztBQUVBOztBQUVBLG9CQUFvQixzQkFBc0I7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxjQUFjOztBQUVkO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQSw2QkFBNkI7O0FBRTdCOztBQUVBLG9CQUFvQixlQUFlOztBQUVuQzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDLGVBQWU7O0FBRXBEOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDZEQUE2RDs7QUFFN0Q7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsZ0VBQWdFOztBQUVoRTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLDRCQUE0Qjs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUksT0FBTzs7QUFFWDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxXQUFXLFVBQVU7QUFDckIsT0FBTyw2RUFBNkU7O0FBRXBGOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsaUJBQWlCO0FBQ2pCLGFBQWEscUNBQXFDLFlBQVk7O0FBRTlEOztBQUVBO0FBQ0E7O0FBRUEsbUJBQW1CLGlCQUFpQjs7QUFFcEM7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLG9CQUFvQjs7QUFFdkM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsVUFBVSxVQUFVO0FBQ3BCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7OztBQUlBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsZUFBZTs7QUFFakM7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsc0JBQXNCLGtCQUFrQjs7QUFFeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFVBQVU7O0FBRVY7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QixPQUFPO0FBQy9CLEdBQUc7O0FBRUg7QUFDQSxlQUFlLGFBQWE7QUFDNUIsZ0JBQWdCLFVBQVU7QUFDMUIsZ0JBQWdCLGdCQUFnQjtBQUNoQyxvQkFBb0IsY0FBYztBQUNsQyxlQUFlLFVBQVU7QUFDekIsZUFBZSxVQUFVO0FBQ3pCLGlCQUFpQjtBQUNqQixHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEscUJBQXFCLE9BQU87O0FBRTVCOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsZUFBZTtBQUNmLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxlQUFlLGFBQWE7QUFDNUIsbUJBQW1CO0FBQ25CLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsMkJBQTJCO0FBQzNCOztBQUVBOztBQUVBOztBQUVBOztBQUVBLCtCQUErQjs7QUFFL0IsS0FBSzs7QUFFTDtBQUNBLDBCQUEwQjs7QUFFMUIsS0FBSzs7QUFFTCx5QkFBeUI7O0FBRXpCLEtBQUs7O0FBRUw7QUFDQSwwQkFBMEI7O0FBRTFCLEtBQUs7O0FBRUw7QUFDQSwwQkFBMEI7O0FBRTFCLEtBQUs7O0FBRUwseUJBQXlCOztBQUV6Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUIsWUFBWTs7QUFFL0I7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3QztBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBLGtEQUFrRCxPQUFPOztBQUV6RDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxtQkFBbUIsZUFBZTs7QUFFbEM7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixtQkFBbUI7O0FBRXZDOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQSxvQkFBb0IsZUFBZTs7QUFFbkM7O0FBRUE7O0FBRUEsb0JBQW9CLHNCQUFzQjs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHVCQUF1Qjs7QUFFM0M7QUFDQTtBQUNBOztBQUVBOztBQUVBLHFCQUFxQix1QkFBdUI7O0FBRTVDOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLG9CQUFvQiw2QkFBNkI7O0FBRWpEOztBQUVBOztBQUVBOzs7QUFHQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsaUJBQWlCOztBQUVqQjtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsK0JBQStCLGVBQWU7O0FBRTlDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsZ0NBQWdDLE9BQU87O0FBRXZDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGdDQUFnQyxPQUFPOztBQUV2Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLGtCQUFrQixTQUFTOztBQUUzQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseURBQXlEO0FBQ3pEOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUNBQW1DO0FBQ25DLG1DQUFtQztBQUNuQyxtQ0FBbUM7QUFDbkMsbUNBQW1DOztBQUVuQyxrQ0FBa0M7QUFDbEMsa0NBQWtDO0FBQ2xDLGtDQUFrQzs7QUFFbEMsZ0RBQWdEO0FBQ2hELGdEQUFnRDtBQUNoRCxnREFBZ0Q7QUFDaEQsZ0RBQWdEOztBQUVoRCxvQ0FBb0M7QUFDcEMsb0NBQW9DO0FBQ3BDLG9DQUFvQztBQUNwQyxvQ0FBb0M7O0FBRXBDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsU0FBUzs7QUFFM0I7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsa0JBQWtCLFNBQVM7O0FBRTNCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGtCQUFrQixTQUFTOztBQUUzQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsU0FBUzs7QUFFM0I7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBLHdDQUF3QztBQUN4Qyx3Q0FBd0M7QUFDeEMsd0NBQXdDO0FBQ3hDLHdDQUF3Qzs7QUFFeEMsdUNBQXVDO0FBQ3ZDLHVDQUF1QztBQUN2Qyx1Q0FBdUM7O0FBRXZDLHFEQUFxRDtBQUNyRCxxREFBcUQ7QUFDckQscURBQXFEO0FBQ3JELHFEQUFxRDs7QUFFckQseUNBQXlDO0FBQ3pDLHlDQUF5QztBQUN6Qyx5Q0FBeUM7QUFDekMseUNBQXlDOztBQUV6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsa0NBQWtDOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsa0NBQWtDOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQyxTQUFTOztBQUU1QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsZ0NBQWdDOztBQUVoQzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQ0FBbUMsU0FBUzs7QUFFNUM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQyxTQUFTOztBQUU1QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEscUJBQXFCLFFBQVE7O0FBRTdCO0FBQ0Esa0JBQWtCLGdDQUFnQyxFQUFFLEtBQUssSUFBSSxXQUFXOztBQUV4RTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxnQkFBZ0IsYUFBYSxpQkFBaUIsU0FBUyxnQkFBZ0IsSUFBSSxnQkFBZ0IsY0FBYzs7QUFFekc7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxtREFBbUQscURBQXFEOztBQUV4Rzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsT0FBTzs7QUFFekI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHlGQUF5RixvQkFBb0Isb0JBQW9CLFdBQVc7O0FBRTVJOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGtDQUFrQyxxQkFBcUI7O0FBRXZEO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQ0FBb0Msc0JBQXNCO0FBQzFELGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsVUFBVTs7QUFFVjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw2QkFBNkI7QUFDN0IsaUNBQWlDO0FBQ2pDLGtDQUFrQztBQUNsQyw0QkFBNEI7QUFDNUIsOEJBQThCO0FBQzlCLGdDQUFnQztBQUNoQyxnQ0FBZ0M7O0FBRWhDOztBQUVBLG1DQUFtQzs7QUFFbkM7O0FBRUE7O0FBRUEsa0NBQWtDOztBQUVsQzs7QUFFQTs7QUFFQSxvQ0FBb0M7O0FBRXBDOztBQUVBLDRCQUE0QjtBQUM1QiwwQkFBMEI7QUFDMUIsc0JBQXNCOztBQUV0Qjs7QUFFQSx3QkFBd0I7O0FBRXhCOztBQUVBOztBQUVBLHdCQUF3Qjs7QUFFeEI7O0FBRUE7O0FBRUEsd0JBQXdCOztBQUV4Qjs7QUFFQTs7QUFFQSw0QkFBNEI7O0FBRTVCOztBQUVBOztBQUVBLDBCQUEwQjs7QUFFMUI7O0FBRUEsMEJBQTBCOztBQUUxQjs7QUFFQTs7QUFFQSw4QkFBOEI7QUFDOUIsK0JBQStCOztBQUUvQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDRCQUE0QjtBQUM1QixnQ0FBZ0M7QUFDaEMsZ0NBQWdDOztBQUVoQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGlHQUFpRztBQUNqRztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGVBQWUsT0FBTzs7QUFFdEI7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EseUNBQXlDLFFBQVE7O0FBRWpEOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQSxHQUFHOztBQUVIOztBQUVBLEdBQUc7O0FBRUg7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBLEdBQUc7O0FBRUg7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7O0FBR0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyREFBMkQsUUFBUTs7QUFFbkU7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7OztBQUlBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLGtCQUFrQixPQUFPOztBQUV6QjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLE9BQU87O0FBRTFCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3Qzs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUwscUJBQXFCLE9BQU87O0FBRTVCOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxzQ0FBc0MsT0FBTzs7QUFFN0M7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDZCQUE2Qix3Q0FBd0MsR0FBRzs7QUFFeEUsZ0RBQWdELDBCQUEwQix1QkFBdUIsbUNBQW1DLCtDQUErQyxxQkFBcUIsNkJBQTZCLG9FQUFvRSxpREFBaUQseUJBQXlCLGFBQWEsUUFBUSw4Q0FBOEMseUtBQXlLLCtCQUErQiwwRkFBMEYsa0pBQWtKLHNCQUFzQixzQ0FBc0MsaUJBQWlCLDBCQUEwQiwwQ0FBMEMsdURBQXVELDREQUE0RCxHQUFHOztBQUVqbkM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSw0Q0FBNEMsaUNBQWlDO0FBQzdFOztBQUVBLHFCQUFxQjs7QUFFckI7O0FBRUEsc0JBQXNCOztBQUV0QjtBQUNBO0FBQ0E7QUFDQSxHQUFHO0FBQ0g7QUFDQSxrQkFBa0IsYUFBYTtBQUMvQixpQkFBaUIsc0JBQXNCO0FBQ3ZDLGFBQWE7QUFDYixHQUFHOztBQUVIO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSx1Q0FBdUMsUUFBUTs7QUFFL0M7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0RBQW9ELHFEQUFxRDs7QUFFekc7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLHFCQUFxQixvQkFBb0I7O0FBRXpDOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLDBDQUEwQyxRQUFROztBQUVsRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0NBQXdDLE9BQU87O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEsYUFBYSxRQUFROztBQUVyQjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQSwyQ0FBMkM7O0FBRTNDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsb0NBQW9DO0FBQ3BDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxtQkFBbUIsV0FBVzs7QUFFOUI7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQ0FBMkMsUUFBUTs7QUFFbkQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQjtBQUNwQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7Ozs7QUFJQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsaURBQWlELFFBQVE7QUFDekQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQSxZQUFZOztBQUVaOztBQUVBLDBDQUEwQyxLQUFLOztBQUUvQzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsaUNBQWlDOztBQUVqQztBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixPQUFPOztBQUUzQjs7QUFFQSwwQkFBMEIsK0RBQStEOztBQUV6RixNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEseUJBQXlCLDBEQUEwRDs7QUFFbkYsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLHFCQUFxQiw0REFBNEQ7O0FBRWpGOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHlDQUF5QyxRQUFROztBQUVqRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSx1R0FBdUc7O0FBRXZHOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxRQUFROztBQUVuRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxRQUFROztBQUVSOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxRQUFROztBQUVuRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLFlBQVk7O0FBRVo7O0FBRUE7O0FBRUE7O0FBRUEsVUFBVTs7QUFFVjs7QUFFQTs7QUFFQSxTQUFTOztBQUVUOztBQUVBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsU0FBUzs7QUFFVDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxRQUFROztBQUVuRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxVQUFVOztBQUVWOztBQUVBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUE7O0FBRUEsUUFBUTs7QUFFUjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxTQUFTOztBQUVUOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxRQUFROztBQUVSOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQSx1QkFBdUIsWUFBWTs7QUFFbkM7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQ0FBMkMsUUFBUTs7QUFFbkQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsUUFBUTs7QUFFUjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxvQkFBb0IsT0FBTzs7QUFFM0I7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQkFBcUIsT0FBTzs7QUFFNUI7O0FBRUEsc0JBQXNCLG9CQUFvQjs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsVUFBVTs7QUFFVjs7QUFFQTs7QUFFQSxTQUFTOztBQUVUOztBQUVBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsU0FBUzs7QUFFVDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQkFBcUIsT0FBTzs7QUFFNUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsUUFBUTs7QUFFUjs7QUFFQTs7QUFFQSx1QkFBdUIsb0JBQW9COztBQUUzQztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxRQUFROztBQUVSOztBQUVBOztBQUVBLHVCQUF1QixvQkFBb0I7O0FBRTNDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJLDJKQUEySjs7QUFFL0o7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLG9CQUFvQixxQkFBcUI7O0FBRXpDOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQSxxQkFBcUIsT0FBTzs7QUFFNUI7QUFDQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsT0FBTzs7QUFFM0I7O0FBRUE7O0FBRUEsMEJBQTBCLGdDQUFnQzs7QUFFMUQ7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLHlCQUF5QixnQ0FBZ0M7O0FBRXpEOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLFFBQVE7O0FBRW5EOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEscUJBQXFCLHFCQUFxQjs7QUFFMUM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0IsT0FBTzs7QUFFM0I7O0FBRUEsMEJBQTBCLGdDQUFnQzs7QUFFMUQ7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKLDBDQUEwQyxRQUFROztBQUVsRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEseUJBQXlCLGdDQUFnQzs7QUFFekQ7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx5Q0FBeUMsUUFBUTs7QUFFakQ7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLHNCQUFzQixxQkFBcUI7O0FBRTNDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHFCQUFxQixxQkFBcUI7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxzQkFBc0IscUJBQXFCOztBQUUzQztBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFVBQVU7O0FBRVY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUJBQXFCOztBQUVyQjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsNkJBQTZCOztBQUU3Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdCQUF3Qix1Q0FBdUM7O0FBRS9EOztBQUVBOztBQUVBOztBQUVBLHdCQUF3QiwwQ0FBMEM7O0FBRWxFOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVAsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxRQUFROztBQUVSOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsQ0FBQzs7QUFFRDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBLENBQUM7O0FBRUQ7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esb0JBQW9CLHFCQUFxQjtBQUN6QyxvQkFBb0IsbUJBQW1CO0FBQ3ZDLHFCQUFxQjtBQUNyQjtBQUNBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxnQ0FBZ0MsNENBQTRDOztBQUU1RTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG9CQUFvQix3QkFBd0I7O0FBRTVDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLDBCQUEwQixxQkFBcUI7O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxrQ0FBa0MseUJBQXlCOztBQUUzRDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLGtDQUFrQywwQkFBMEI7O0FBRTVEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFFBQVE7O0FBRVI7O0FBRUEsNkNBQTZDOztBQUU3Qzs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsMkJBQTJCLHVCQUF1Qjs7QUFFbEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLDBCQUEwQjs7QUFFOUM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQix3QkFBd0I7O0FBRTVDOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNCQUFzQix3QkFBd0I7O0FBRTlDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxRQUFROztBQUVSO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTs7QUFFTjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLG9CQUFvQixvQkFBb0I7O0FBRXhDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxxQkFBcUIsa0JBQWtCOztBQUV2Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHdCQUF3Qjs7QUFFNUM7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQkFBMkIsc0NBQXNDOztBQUVqRTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQSxJQUFJOztBQUVKLHdDQUF3Qzs7QUFFeEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsaUJBQWlCLGNBQWM7O0FBRS9COztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLG1FQUFtRTs7QUFFbkU7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsOENBQThDOztBQUU5Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDZFQUE2RTs7QUFFN0U7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLHNCQUFzQjs7QUFFekM7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEseUNBQXlDLFFBQVE7O0FBRWpEOztBQUVBLDhDQUE4QyxRQUFROztBQUV0RDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQkFBc0IsbUJBQW1COztBQUV6Qzs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsUUFBUTs7QUFFUjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsUUFBUTs7QUFFUjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLGtCQUFrQjtBQUNsQix3QkFBd0I7O0FBRXhCLHdDQUF3QyxPQUFPOztBQUUvQzs7QUFFQSw4Q0FBOEMsUUFBUTs7QUFFdEQ7O0FBRUE7O0FBRUEseUNBQXlDLFFBQVE7O0FBRWpEOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7OztBQUdBO0FBQ0E7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBLHNCQUFzQjs7QUFFdEIsSUFBSTs7QUFFSjs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw4QkFBOEI7O0FBRTlCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhO0FBQ2I7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3QkFBd0I7O0FBRXhCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esb0ZBQW9GLFNBQVM7O0FBRTdGO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsOENBQThDOztBQUU5Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxrREFBa0Q7O0FBRWxEOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsdUJBQXVCLGVBQWU7O0FBRXRDO0FBQ0E7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx1QkFBdUIscUJBQXFCOztBQUU1Qzs7QUFFQTtBQUNBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjtBQUNBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw2QkFBNkI7O0FBRTdCOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMENBQTBDLE9BQU87O0FBRWpEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHlDQUF5QyxPQUFPOztBQUVoRDs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLFNBQVM7O0FBRVQ7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLE9BQU87O0FBRWxEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsUUFBUTs7QUFFUjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx5Q0FBeUMsT0FBTzs7QUFFaEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTs7QUFFTjs7QUFFQTtBQUNBO0FBQ0EsOENBQThDLHlDQUF5Qzs7QUFFdkY7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLCtFQUErRTs7QUFFL0U7O0FBRUEscURBQXFELE9BQU87O0FBRTVEOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxPQUFPOztBQUVsRDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzREFBc0Q7O0FBRXREOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxzREFBc0Q7O0FBRXREOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07QUFDTjtBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSw4QkFBOEI7QUFDOUIsNEJBQTRCOztBQUU1Qjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsT0FBTzs7QUFFL0M7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSw2QkFBNkI7O0FBRTdCOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLFFBQVE7O0FBRVI7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLG1FQUFtRSxlQUFlOztBQUVsRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsbUVBQW1FLGVBQWU7O0FBRWxGOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx3QkFBd0I7QUFDeEI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsaUlBQWlJO0FBQ2pJOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDRCQUE0QixlQUFlOztBQUUzQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLG9DQUFvQyxPQUFPOztBQUUzQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0NBQXdDLE9BQU87O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQyxPQUFPOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQ0FBbUMsT0FBTzs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLGdCQUFnQjs7QUFFcEM7O0FBRUEscUJBQXFCLG1CQUFtQjs7QUFFeEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsZ0JBQWdCOztBQUVwQzs7QUFFQSxxQkFBcUIsbUJBQW1COztBQUV4Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7O0FBR0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxlQUFlLG1CQUFtQjs7QUFFbEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseUJBQXlCLDZEQUE2RDs7QUFFdEY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7Ozs7QUFJQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQ0FBbUMsT0FBTzs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQ0FBbUMsT0FBTzs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFdBQVcsT0FBTzs7QUFFbEI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLDZCQUE2Qjs7QUFFaEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsNkJBQTZCOztBQUVoRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseUNBQXlDLE9BQU87O0FBRWhEOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUwsOEJBQThCOztBQUU5Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxpQkFBaUI7O0FBRWpCO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNkNBQTZDLFFBQVE7O0FBRXJEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxRQUFROztBQUVuRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQ0FBMkMsUUFBUTs7QUFFbkQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLFFBQVE7O0FBRW5EOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxzQ0FBc0MsUUFBUTs7QUFFOUM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsaURBQWlEO0FBQ2pEO0FBQ0E7O0FBRUEsNERBQTREO0FBQzVELHlDQUF5Qzs7QUFFekM7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxRQUFROztBQUVuRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwwQ0FBMEMsT0FBTzs7QUFFakQ7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxxQ0FBcUMsT0FBTzs7QUFFNUM7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsbUJBQW1CLFdBQVc7O0FBRTlCOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLFdBQVc7O0FBRTlCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLFdBQVc7O0FBRTlCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQ0FBMkM7O0FBRTNDLHFDQUFxQzs7QUFFckMsbUJBQW1CLDZCQUE2Qjs7QUFFaEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsNEJBQTRCLDJCQUEyQjs7QUFFdkQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0RBQW9ELE9BQU87O0FBRTNEO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQzs7QUFFM0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLDZCQUE2Qjs7QUFFaEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0JBQXdCLGtCQUFrQjs7QUFFMUM7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQixpQkFBaUI7O0FBRXBDLG9CQUFvQixjQUFjOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHNEQUFzRDtBQUN0RDtBQUNBOztBQUVBLDZEQUE2RDtBQUM3RDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLFlBQVksOEJBQThCOztBQUUxQztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDhEQUE4RCxlQUFlOztBQUU3RTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxtQkFBbUIsbUJBQW1COztBQUV0Qzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0Esd0NBQXdDLE9BQU87O0FBRS9DOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esc0RBQXNELE9BQU87O0FBRTdEO0FBQ0EscUJBQXFCLGNBQWM7O0FBRW5DOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLG9CQUFvQixvQkFBb0I7O0FBRXhDOztBQUVBOztBQUVBO0FBQ0EsK0RBQStELE9BQU87O0FBRXRFOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EseUVBQXlFLE9BQU87O0FBRWhGO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSx5RUFBeUUsT0FBTzs7QUFFaEY7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdDQUF3QyxPQUFPOztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGlEQUFpRCxPQUFPOztBQUV4RDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDBEQUEwRCxXQUFXO0FBQ3JFLGtFQUFrRSxXQUFXOztBQUU3RSxvREFBb0QsU0FBUztBQUM3RDtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEseUNBQXlDLE9BQU87O0FBRWhEOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUEscUNBQXFDLE9BQU87O0FBRTVDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSix5Q0FBeUMsT0FBTzs7QUFFaEQ7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsaURBQWlELE9BQU87O0FBRXhEO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEscUNBQXFDLE9BQU87O0FBRTVDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUEscUNBQXFDLE9BQU87O0FBRTVDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxpREFBaUQsUUFBUTs7QUFFekQ7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLDBEQUEwRDs7QUFFMUQ7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsaURBQWlELE9BQU87O0FBRXhEO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxrQ0FBa0MsUUFBUTs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBLGlDQUFpQyxPQUFPOztBQUV4Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsaURBQWlELFFBQVE7O0FBRXpEOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxXQUFXLGdCQUFnQjs7QUFFM0I7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxpQkFBaUI7QUFDakI7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsZ0JBQWdCOztBQUVuQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsZ0JBQWdCOztBQUVuQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsbUJBQW1CLGdCQUFnQjs7QUFFbkM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsZ0JBQWdCLEtBQUsseUJBQXlCOztBQUU5Qzs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsdUJBQXVCOztBQUV2Qjs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLCtDQUErQzs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsbUJBQW1CLGVBQWU7O0FBRWxDOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOzs7QUFHQTs7QUFFQSxtQkFBbUIsZUFBZTs7QUFFbEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0ZBQXdGOztBQUV4Rjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixlQUFlOztBQUVuQztBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBLGNBQWM7O0FBRWQ7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDZDQUE2QyxPQUFPOztBQUVwRDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLE9BQU87O0FBRWxEO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxPQUFPOztBQUVsRDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDZDQUE2QyxPQUFPOztBQUVwRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQ0FBMkMsT0FBTzs7QUFFbEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQ0FBMkMsT0FBTzs7QUFFbEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsMEJBQTBCOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSwyQ0FBMkMsT0FBTzs7QUFFbEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsZ0JBQWdCOztBQUVuQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHlDQUF5QyxtQkFBbUI7O0FBRTVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsb0JBQW9CLGdCQUFnQjs7QUFFcEM7O0FBRUEsa0RBQWtEOztBQUVsRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDZDQUE2QyxPQUFPOztBQUVwRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLDJDQUEyQyxPQUFPOztBQUVsRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsMkNBQTJDLE9BQU87O0FBRWxEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGlDQUFpQzs7QUFFakM7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLG1CQUFtQiw0QkFBNEI7O0FBRS9DOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsZUFBZTs7QUFFbEM7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0IsNEJBQTRCOztBQUVoRDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGNBQWM7O0FBRWpDLG9CQUFvQiwyQkFBMkI7O0FBRS9DOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSwwQkFBMEIsZUFBZTs7QUFFekM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixlQUFlOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsb0JBQW9CLHFCQUFxQjs7QUFFekM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUJBQXFCLHFCQUFxQjs7QUFFMUM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixvQkFBb0I7O0FBRXhDLHFCQUFxQixvQkFBb0I7O0FBRXpDOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLG9CQUFvQixxQkFBcUI7O0FBRXpDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsb0JBQW9CLHFCQUFxQjs7QUFFekM7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0Isb0JBQW9COztBQUV4QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLGdDQUFnQzs7QUFFaEMsSUFBSTs7QUFFSiw0QkFBNEI7O0FBRTVCOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxvQkFBb0Isb0JBQW9COztBQUV4Qzs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLFdBQVc7O0FBRS9COztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEscUJBQXFCLFdBQVc7O0FBRWhDOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLFVBQVU7O0FBRTlCLHFCQUFxQiwwQkFBMEI7O0FBRS9DOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxPQUFPOztBQUVQO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IseUJBQXlCOztBQUU3QztBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQix5QkFBeUI7O0FBRTdDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHFCQUFxQjs7QUFFekM7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDJCQUEyQix5QkFBeUI7O0FBRXBEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLG9CQUFvQixnQkFBZ0I7O0FBRXBDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxZQUFZLFVBQVU7QUFDdEI7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxzQkFBc0IsK0JBQStCLElBQUksK0JBQStCLElBQUksK0JBQStCO0FBQzNILHNCQUFzQiwrQkFBK0IsSUFBSSwrQkFBK0IsSUFBSSwrQkFBK0I7QUFDM0gsc0JBQXNCLCtCQUErQixJQUFJLCtCQUErQixJQUFJLCtCQUErQjs7QUFFM0g7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLHFCQUFxQixPQUFPOztBQUU1QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsc0JBQXNCLFVBQVUsSUFBSSxVQUFVO0FBQzlDLDZCQUE2QixVQUFVLElBQUksVUFBVTs7QUFFckQ7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLGFBQWEsaUJBQWlCO0FBQzlCO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDBDQUEwQyxPQUFPOztBQUVqRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDRDQUE0QyxPQUFPOztBQUVuRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLDBDQUEwQyxPQUFPOztBQUVqRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsMENBQTBDLE9BQU87O0FBRWpEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHlFQUF5RTtBQUN6RTs7QUFFQTtBQUNBOztBQUVBLHNCQUFzQixjQUFjOztBQUVwQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLFNBQVM7O0FBRTVCLEdBQUc7O0FBRUgsdUJBQXVCLFlBQVk7O0FBRW5DOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsMkNBQTJDOztBQUUzQztBQUNBOztBQUVBLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSwyQ0FBMkM7O0FBRTNDOztBQUVBLG1CQUFtQjtBQUNuQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsd0NBQXdDLFNBQVM7O0FBRWpEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxjQUFjLGtCQUFrQjs7QUFFaEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsOEJBQThCLCtCQUErQjs7QUFFN0Q7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSw4Q0FBOEM7O0FBRTlDOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLFlBQVk7O0FBRTVCO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxnR0FBZ0c7O0FBRWhHOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDRDQUE0Qzs7QUFFNUMseURBQXlEO0FBQ3pELHlEQUF5RDtBQUN6RCx5REFBeUQ7QUFDekQseURBQXlEOztBQUV6RDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQSw0Q0FBNEM7QUFDNUM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxHQUFHOztBQUVIO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLHFDQUFxQyxTQUFTOztBQUU5QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsOEJBQThCLE9BQU87O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVCQUF1QjtBQUN2QiwwQkFBMEI7QUFDMUIsb0JBQW9COztBQUVwQjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixrQkFBa0I7O0FBRXJDO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsc0JBQXNCOztBQUV6Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0Isb0JBQW9COztBQUV0QztBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7O0FBRUEsaUtBQWlLOztBQUVqSzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3QztBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLDBCQUEwQjs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0NBQXdDLFFBQVE7O0FBRWhEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQSw2QkFBNkI7O0FBRTdCLHVDQUF1QyxRQUFROztBQUUvQzs7QUFFQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7OztBQUdBOzs7QUFHQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEseUNBQXlDOztBQUV6QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBLCtCQUErQjs7QUFFL0I7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxRQUFROztBQUVSOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBLGdFQUFnRSxRQUFROztBQUV4RTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSx1Q0FBdUMsUUFBUTs7QUFFL0M7O0FBRUE7O0FBRUEsK0RBQStELFFBQVE7O0FBRXZFO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOzs7QUFHQTs7QUFFQSxvQkFBb0IsbUJBQW1COztBQUV2QywrQkFBK0IsT0FBTzs7QUFFdEM7QUFDQTtBQUNBOztBQUVBOztBQUVBLDBDQUEwQyxRQUFROztBQUVsRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsUUFBUTs7QUFFaEQ7QUFDQTs7QUFFQSx5Q0FBeUMsUUFBUTs7QUFFakQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLFVBQVU7O0FBRTlCOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLG9CQUFvQixZQUFZOztBQUVoQyxxQkFBcUIsVUFBVTs7QUFFL0I7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQSxrQkFBa0Isb0JBQW9CO0FBQ3RDLG9DQUFvQyxRQUFROztBQUU1QztBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsMENBQTBDLFFBQVE7O0FBRWxEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsd0NBQXdDLFFBQVE7O0FBRWhEO0FBQ0E7O0FBRUEseUNBQXlDLFFBQVE7O0FBRWpEOztBQUVBOztBQUVBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQjtBQUNwQjs7QUFFQTs7QUFFQSxzQkFBc0IsVUFBVTs7QUFFaEM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLHNCQUFzQixVQUFVOztBQUVoQztBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUEsc0JBQXNCLFVBQVU7O0FBRWhDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsc0JBQXNCLFVBQVU7O0FBRWhDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsd0NBQXdDLFFBQVE7O0FBRWhEO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7O0FBR0E7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSwwREFBMEQsUUFBUTs7QUFFbEU7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7OztBQUdBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOzs7QUFHQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw0Q0FBNEMsUUFBUTs7QUFFcEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3Qzs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBLGlDQUFpQzs7QUFFakM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsbUJBQW1CLGtCQUFrQjs7QUFFckMsb0JBQW9CLG9CQUFvQjs7QUFFeEM7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixpQkFBaUI7O0FBRXBDOztBQUVBLG9CQUFvQixtQkFBbUI7O0FBRXZDOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUosb0JBQW9CLG1CQUFtQjs7QUFFdkM7O0FBRUEsZ0RBQWdEOztBQUVoRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLE9BQU87O0FBRWxEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxPQUFPOztBQUVsRDtBQUNBOztBQUVBOztBQUVBOztBQUVBLDhDQUE4QyxPQUFPOztBQUVyRDs7QUFFQTtBQUNBO0FBQ0Esb0NBQW9DOztBQUVwQzs7QUFFQTs7QUFFQSxzQ0FBc0MsT0FBTzs7QUFFN0M7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw0Q0FBNEMsUUFBUTs7QUFFcEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLG9CQUFvQixzQkFBc0I7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUEscUJBQXFCLHFCQUFxQjs7QUFFMUM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHFCQUFxQjs7QUFFekMscUJBQXFCLG9CQUFvQjs7QUFFekM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsbUJBQW1CLHFCQUFxQjs7QUFFeEMsb0JBQW9CLHNCQUFzQjs7QUFFMUM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLHFCQUFxQjs7QUFFeEMsb0JBQW9CLHNCQUFzQjs7QUFFMUM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLG1CQUFtQixzQkFBc0I7O0FBRXpDOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLG9CQUFvQixxQkFBcUI7O0FBRXpDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLHNCQUFzQjs7QUFFekMsb0JBQW9CLHFCQUFxQjs7QUFFekM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHFCQUFxQjs7QUFFekM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLG9CQUFvQixxQkFBcUI7O0FBRXpDOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixzQkFBc0I7O0FBRTFDLHFCQUFxQixxQkFBcUI7O0FBRTFDO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHNCQUFzQjs7QUFFMUMscUJBQXFCLHFCQUFxQjs7QUFFMUM7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxrQkFBa0IsbURBQW1EOztBQUVyRTs7QUFFQTs7QUFFQSx5Q0FBeUMsUUFBUTs7QUFFakQ7O0FBRUE7QUFDQTs7QUFFQSxnRUFBZ0UsT0FBTzs7QUFFdkUsdUJBQXVCLE9BQU87O0FBRTlCO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUEsaURBQWlELE9BQU87O0FBRXhELHNCQUFzQixPQUFPOztBQUU3QjtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsa0JBQWtCLFFBQVEsR0FBRyxRQUFRLEdBQUcsUUFBUSxHQUFHLE1BQU0sR0FBRyxNQUFNLEdBQUcsTUFBTTtBQUMzRSxrQkFBa0IsTUFBTSxHQUFHLE1BQU0sR0FBRyxNQUFNLEdBQUcsUUFBUSxHQUFHLFFBQVEsR0FBRyxRQUFRLEdBQUc7O0FBRTlFOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxDQUFDOztBQUVEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1COztBQUVuQjs7QUFFQSxzQ0FBc0M7QUFDdEM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1COztBQUVuQjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTtBQUNKOztBQUVBOztBQUVBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDO0FBQ3RDO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUI7O0FBRW5COztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0M7O0FBRXRDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUI7O0FBRW5COztBQUVBLHNDQUFzQzs7QUFFdEM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQSxtQkFBbUI7O0FBRW5COztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSw0QkFBNEI7O0FBRTVCOztBQUVBLDZDQUE2Qzs7QUFFN0M7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxrQkFBa0IsU0FBUzs7QUFFM0I7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLGlDQUFpQyx1QkFBdUI7O0FBRXhEOztBQUVBLG1CQUFtQixjQUFjOztBQUVqQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGtDQUFrQzs7QUFFbEM7QUFDQSxvQ0FBb0M7O0FBRXBDOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0Esd0NBQXdDOztBQUV4Qzs7QUFFQTs7QUFFQSxJQUFJOztBQUVKLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGtCQUFrQix3QkFBd0I7O0FBRTFDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUIsd0JBQXdCOztBQUUzQzs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsZUFBZTs7QUFFbkM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0Isd0JBQXdCOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0Isd0JBQXdCOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0Esa0JBQWtCLGVBQWU7O0FBRWpDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsbUJBQW1CLGNBQWM7O0FBRWpDOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0EscUJBQXFCLGNBQWM7O0FBRW5DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsZUFBZTtBQUNmOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsbUJBQW1CLGNBQWM7O0FBRWpDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLG1CQUFtQixjQUFjOztBQUVqQztBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsbUJBQW1CLGNBQWM7O0FBRWpDO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQ0FBbUM7O0FBRW5DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOLGlDQUFpQzs7QUFFakM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyxTQUFTOztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyxTQUFTOztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGFBQWE7O0FBRWhDOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0NBQXdDLFNBQVM7O0FBRWpEOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGVBQWU7O0FBRWxDOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLHNCQUFzQixjQUFjOztBQUVwQzs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHNCQUFzQixjQUFjOztBQUVwQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3RkFBd0YsY0FBYzs7QUFFdEc7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQyxnQkFBZ0I7O0FBRW5EOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsMENBQTBDLFNBQVM7O0FBRW5EOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLDBDQUEwQyxTQUFTOztBQUVuRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLG1CQUFtQixxQkFBcUI7O0FBRXhDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxtQkFBbUIsc0JBQXNCOztBQUV6Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLDZDQUE2QyxRQUFROztBQUVyRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxtQkFBbUIsNEJBQTRCOztBQUUvQzs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxpQkFBaUIsMEJBQTBCOztBQUUzQzs7QUFFQSx1QkFBdUIsNENBQTRDOztBQUVuRTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLHNCQUFzQiw4Q0FBOEM7O0FBRXBFOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHNDQUFzQyxTQUFTOztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsd0JBQXdCOztBQUUzQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsd0JBQXdCOztBQUUzQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsd0JBQXdCOztBQUUzQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsd0JBQXdCOztBQUUzQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxVQUFVOztBQUVWOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx5Q0FBeUMsT0FBTzs7QUFFaEQ7QUFDQTs7QUFFQSw2Q0FBNkM7O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsZ0NBQWdDLGNBQWM7O0FBRTlDOztBQUVBOztBQUVBLFdBQVc7O0FBRVg7O0FBRUEseURBQXlELGtDQUFrQztBQUMzRixrREFBa0QsUUFBUTs7QUFFMUQ7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUEsVUFBVTs7QUFFVjs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBLE1BQU07O0FBRU4sd0NBQXdDLGFBQWEsbUJBQW1CLGdCQUFnQixJQUFJLG9CQUFvQjs7QUFFaEg7O0FBRUEsS0FBSztBQUNMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxTQUFTOztBQUVUOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFFBQVE7O0FBRVI7QUFDQSxpQ0FBaUM7QUFDakM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSztBQUNMOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLDRDQUE0QyxRQUFROztBQUVwRDtBQUNBOztBQUVBOztBQUVBLEtBQUs7QUFDTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsNENBQTRDLFFBQVE7O0FBRXBEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSztBQUNMOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGlCQUFpQjs7QUFFcEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQSxxQ0FBcUMsUUFBUTs7QUFFN0M7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQkFBc0IsV0FBVzs7QUFFakMsc0JBQXNCOztBQUV0Qix1QkFBdUIsMEJBQTBCOztBQUVqRDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLG1CQUFtQixpQkFBaUI7O0FBRXBDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLGtEQUFrRDs7QUFFbEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7O0FBR0g7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLCtCQUErQjs7QUFFL0I7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLE9BQU87O0FBRTFCOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0Esd0RBQXdEOztBQUV4RDtBQUNBLDREQUE0RDtBQUM1RDtBQUNBOztBQUVBO0FBQ0EsZ0VBQWdFO0FBQ2hFO0FBQ0EscUVBQXFFO0FBQ3JFO0FBQ0Esc0VBQXNFOztBQUV0RTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLE9BQU87O0FBRTFCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLE9BQU87O0FBRTFCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQztBQUNuQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsOEJBQThCOztBQUU5Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLHNDQUFzQyxRQUFROztBQUU5QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUksY0FBYzs7QUFFbEI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGlEQUFpRCxRQUFROztBQUV6RDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsT0FBTzs7QUFFUDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUNBQXVDLFNBQVM7O0FBRWhEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQyxPQUFPOztBQUU1Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEscUNBQXFDLE9BQU87O0FBRTVDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQyxPQUFPOztBQUU1QztBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxRQUFROztBQUVSLHdFQUF3RSxXQUFXOztBQUVuRjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQjtBQUNwQjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHFDQUFxQyxPQUFPOztBQUU1Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsaUJBQWlCOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsc0NBQXNDLFFBQVE7O0FBRTlDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUNBQXVDLFFBQVE7O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTtBQUNBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsc0NBQXNDLFFBQVE7O0FBRTlDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUNBQXVDLFFBQVE7O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQyxPQUFPOztBQUU1Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQSw4Q0FBOEM7O0FBRTlDOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGtFQUFrRTs7QUFFbEU7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxrRUFBa0U7O0FBRWxFOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixxQkFBcUI7O0FBRXpDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQiw2QkFBNkI7O0FBRWpEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixtQkFBbUI7O0FBRXZDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUI7O0FBRW5COztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNO0FBQ047O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKLG1FQUFtRSwrQkFBK0I7O0FBRWxHLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTixLQUFLOztBQUVMOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyRUFBMkU7O0FBRTNFOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDZDQUE2QyxPQUFPOztBQUVwRDs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDZDQUE2QyxPQUFPOztBQUVwRDs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLG1CQUFtQixpQkFBaUI7O0FBRXBDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLGNBQWM7O0FBRWxDOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNkNBQTZDLFNBQVM7O0FBRXREOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsaURBQWlELFNBQVM7O0FBRTFEOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSw0QkFBNEIsY0FBYzs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLG1CQUFtQixvQkFBb0I7O0FBRXZDOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsY0FBYzs7QUFFbEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixjQUFjOztBQUVqQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsY0FBYzs7QUFFakM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0EsNkNBQTZDLEdBQUc7QUFDaEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLGVBQWU7O0FBRWY7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdFQUF3RSxTQUFTOztBQUVqRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3RUFBd0UsU0FBUzs7QUFFakY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0VBQXdFLFNBQVM7O0FBRWpGOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksUUFBUTtBQUNwQixhQUFhO0FBQ2I7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEscUJBQXFCLHFCQUFxQjs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyxTQUFTOztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0NBQW9DLFNBQVM7O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9DQUFvQyxTQUFTOztBQUU3Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQ0FBb0MsU0FBUzs7QUFFN0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLHNCQUFzQix5QkFBeUI7O0FBRS9DOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsa0RBQWtEOztBQUVsRDs7QUFFQSxJQUFJLGdFQUFnRTs7QUFFcEU7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLDRCQUE0QjtBQUM1Qjs7QUFFQTtBQUNBLGlDQUFpQzs7QUFFakMseUNBQXlDLFNBQVM7O0FBRWxEOztBQUVBOztBQUVBLG9CQUFvQjtBQUNwQiwwQkFBMEIsYUFBYTtBQUN2Qyx1QkFBdUI7QUFDdkIsb0NBQW9DOztBQUVwQzs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7QUFDTDs7QUFFQTs7QUFFQTtBQUNBLElBQUk7QUFDSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLHlDQUF5QyxTQUFTOztBQUVsRDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLG9DQUFvQyxTQUFTOztBQUU3Qzs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLG9DQUFvQyxTQUFTOztBQUU3QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTCxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLHlDQUF5QyxTQUFTOztBQUVsRDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsb0NBQW9DLFNBQVM7O0FBRTdDO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLHlDQUF5QyxTQUFTOztBQUVsRDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLHFDQUFxQyxTQUFTOztBQUU5QztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLHFDQUFxQyxTQUFTOztBQUU5Qzs7QUFFQTtBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU4sS0FBSzs7QUFFTCxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsb0RBQW9ELFNBQVM7O0FBRTdEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsbUJBQW1CLGVBQWU7O0FBRWxDO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDO0FBQ0E7O0FBRUEsMkJBQTJCO0FBQzNCLGlDQUFpQzs7QUFFakM7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLCtCQUErQjs7QUFFL0IsdUJBQXVCO0FBQ3ZCLHVCQUF1Qjs7QUFFdkIsaUNBQWlDOztBQUVqQywrQkFBK0I7QUFDL0IsNkJBQTZCOztBQUU3Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLGlCQUFpQjtBQUNqQix3QkFBd0I7QUFDeEIseUJBQXlCOztBQUV6Qjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7OztBQUdMLDRCQUE0QjtBQUM1Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSwrQ0FBK0MsU0FBUzs7QUFFeEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLCtDQUErQyxTQUFTOztBQUV4RDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsT0FBTzs7QUFFUDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsTUFBTTs7QUFFTjs7QUFFQSxJQUFJLE9BQU87O0FBRVg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscURBQXFEO0FBQ3JEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUCxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUDs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxtQkFBbUIsZUFBZTs7QUFFbEM7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSx5Q0FBeUMsU0FBUzs7QUFFbEQ7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLHlDQUF5QyxTQUFTOztBQUVsRDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNCQUFzQjtBQUN0Qjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQUdBLHVCQUF1QjtBQUN2Qjs7QUFFQSxvQ0FBb0M7OztBQUdwQyxrQ0FBa0M7QUFDbEM7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTs7QUFFQSxLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7QUFDQSxJQUFJO0FBQ0o7QUFDQTs7QUFFQTs7QUFFQSxLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOzs7QUFHQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7O0FBR0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsU0FBUzs7QUFFakQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSw4QkFBOEIsUUFBUTs7QUFFdEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGdCQUFnQjs7QUFFbkM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUIsaUJBQWlCOztBQUVwQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLGlCQUFpQjtBQUNqQixtQkFBbUIsMEJBQTBCOztBQUU3QyxnQ0FBZ0M7O0FBRWhDOztBQUVBLHVDQUF1Qzs7QUFFdkM7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxnREFBZ0QsU0FBUzs7QUFFekQ7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx1Q0FBdUMsZ0JBQWdCOztBQUV2RDs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdCQUF3QixrQkFBa0I7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsOENBQThDLE9BQU87O0FBRXJEOztBQUVBLG9CQUFvQixxQkFBcUI7O0FBRXpDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSxXQUFXO0FBQ1gsV0FBVyxjQUFjO0FBQ3pCLFVBQVU7QUFDVixhQUFhLGNBQWM7QUFDM0I7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSiwrSEFBK0g7QUFDL0g7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUNBQXVDLE9BQU87O0FBRTlDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdDQUF3QyxPQUFPOztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLGtCQUFrQjtBQUNsQixzQkFBc0I7O0FBRXRCOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSx3QkFBd0I7QUFDeEIsc0JBQXNCO0FBQ3RCLGNBQWM7O0FBRWQ7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1QyxRQUFROztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxrQ0FBa0MsT0FBTzs7QUFFekM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSw0Q0FBNEMsZ0NBQWdDOztBQUU1RTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLG1CQUFtQixrQkFBa0I7O0FBRXJDOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsNENBQTRDLGdHQUFnRzs7QUFFNUk7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsMEJBQTBCLGtCQUFrQjs7QUFFNUM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsNEJBQTRCOztBQUU5Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLDRDQUE0QyxpREFBaUQ7O0FBRTdGOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7OztBQUdBO0FBQ0E7QUFDQTtBQUNBLHlEQUF5RCxnRkFBZ0Y7O0FBRXpJO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsMkNBQTJDLGlEQUFpRDtBQUM1Rjs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSwwQ0FBMEMsZ0JBQWdCOztBQUUxRDtBQUNBOztBQUVBOztBQUVBLCtCQUErQjtBQUMvQiwrQkFBK0I7QUFDL0IsK0JBQStCO0FBQy9CLCtCQUErQjs7QUFFL0I7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDRDQUE0Qyx3Q0FBd0M7O0FBRXBGOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixhQUFhOztBQUVqQzs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsV0FBVzs7QUFFOUI7O0FBRUE7O0FBRUEsb0JBQW9CLGVBQWU7O0FBRW5DOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDRDQUE0Qyx3Q0FBd0M7O0FBRXBGOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSw0Q0FBNEMsZ0NBQWdDOztBQUU1RTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsNENBQTRDLHlEQUF5RDs7QUFFckc7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsK0RBQStELDZEQUE2RDtBQUM1SCwrREFBK0QsNkRBQTZEO0FBQzVILCtEQUErRCw2REFBNkQ7QUFDNUgsK0RBQStELDZEQUE2RDs7QUFFNUg7O0FBRUEsK0RBQStELDZEQUE2RDtBQUM1SCxnRUFBZ0UsOERBQThEO0FBQzlILGdFQUFnRSw4REFBOEQ7QUFDOUgsZ0VBQWdFLDhEQUE4RDs7QUFFOUg7O0FBRUEsZ0VBQWdFLDhEQUE4RDtBQUM5SCxnRUFBZ0UsOERBQThEO0FBQzlILGdFQUFnRSw4REFBOEQ7QUFDOUgsZ0VBQWdFLDhEQUE4RDs7QUFFOUg7O0FBRUEsdURBQXVELHFEQUFxRDtBQUM1Ryx1REFBdUQscURBQXFEO0FBQzVHLHVEQUF1RCxxREFBcUQ7QUFDNUcsdURBQXVELHFEQUFxRDs7QUFFNUc7O0FBRUEsaURBQWlELCtDQUErQztBQUNoRyxpREFBaUQsK0NBQStDO0FBQ2hHLGlEQUFpRCwrQ0FBK0M7O0FBRWhHOztBQUVBLDZEQUE2RCwyREFBMkQ7QUFDeEgsMERBQTBELHdEQUF3RDs7QUFFbEg7O0FBRUEsMERBQTBELHdEQUF3RDtBQUNsSCwwREFBMEQsd0RBQXdEOztBQUVsSCwwREFBMEQsd0RBQXdEO0FBQ2xILDBEQUEwRCx3REFBd0Q7O0FBRWxIOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0MsT0FBTzs7QUFFN0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsNENBQTRDLGtDQUFrQzs7QUFFOUU7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsc0JBQXNCLG9CQUFvQjtBQUMxQyxzQkFBc0Isb0JBQW9CO0FBQzFDLHNCQUFzQixvQkFBb0I7QUFDMUMsc0JBQXNCLHFCQUFxQjtBQUMzQyx1QkFBdUIscUJBQXFCO0FBQzVDLHVCQUF1QixxQkFBcUI7QUFDNUMsdUJBQXVCLHFCQUFxQjtBQUM1Qyx1QkFBdUIscUJBQXFCOztBQUU1Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNENBQTRDLGtDQUFrQzs7QUFFOUU7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsNENBQTRDLGtDQUFrQzs7QUFFOUU7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDBEQUEwRCxzRkFBc0Y7O0FBRWhKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLGdFQUFnRSxrQ0FBa0M7QUFDbEc7QUFDQTs7QUFFQSxnRUFBZ0Usa0NBQWtDO0FBQ2xHO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0VBQXdFO0FBQ3hFOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSw0Q0FBNEMsd0NBQXdDOztBQUVwRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLE9BQU87O0FBRWxEOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHFDQUFxQyxhQUFhOztBQUVsRDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxrQ0FBa0M7QUFDbEMsbUNBQW1DOztBQUVuQzs7QUFFQTs7QUFFQTs7QUFFQSxtREFBbUQ7QUFDbkQsc0JBQXNCOztBQUV0QixPQUFPOztBQUVQO0FBQ0EsNkNBQTZDO0FBQzdDO0FBQ0EsMEJBQTBCOztBQUUxQjs7QUFFQSxNQUFNOztBQUVOO0FBQ0EsaURBQWlEO0FBQ2pEO0FBQ0E7QUFDQSxtRkFBbUY7QUFDbkY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsd0NBQXdDLE9BQU87O0FBRS9DO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLDZCQUE2QjtBQUM3Qjs7QUFFQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUwscUNBQXFDLGdDQUFnQzs7QUFFckU7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7O0FBR0E7O0FBRUE7QUFDQTs7QUFFQSxnREFBZ0QsYUFBYTs7QUFFN0Q7O0FBRUE7O0FBRUEsZ0RBQWdELGFBQWE7O0FBRTdEOztBQUVBLHdCQUF3QixtQkFBbUI7O0FBRTNDO0FBQ0E7O0FBRUEsMEJBQTBCLDBCQUEwQjs7QUFFcEQ7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxTQUFTOztBQUVUOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDBDQUEwQyxRQUFROztBQUVsRDtBQUNBO0FBQ0E7O0FBRUEsMENBQTBDLFFBQVE7O0FBRWxEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDZEQUE2RDs7QUFFN0QsNkRBQTZEOztBQUU3RDs7QUFFQSwwQkFBMEIsb0JBQW9COztBQUU5Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrRUFBa0U7QUFDbEU7QUFDQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRXM2TiIsInNvdXJjZXMiOlsid2VicGFjazovL3RocmVlanMtcG9zdHByb2Nlc3MvLi9ub2RlX21vZHVsZXMvdGhyZWUvYnVpbGQvdGhyZWUubW9kdWxlLmpzPzlhOTAiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBAbGljZW5zZVxuICogQ29weXJpZ2h0IDIwMTAtMjAyNCBUaHJlZS5qcyBBdXRob3JzXG4gKiBTUERYLUxpY2Vuc2UtSWRlbnRpZmllcjogTUlUXG4gKi9cbmNvbnN0IFJFVklTSU9OID0gJzE2Nic7XG5cbmNvbnN0IE1PVVNFID0geyBMRUZUOiAwLCBNSURETEU6IDEsIFJJR0hUOiAyLCBST1RBVEU6IDAsIERPTExZOiAxLCBQQU46IDIgfTtcbmNvbnN0IFRPVUNIID0geyBST1RBVEU6IDAsIFBBTjogMSwgRE9MTFlfUEFOOiAyLCBET0xMWV9ST1RBVEU6IDMgfTtcbmNvbnN0IEN1bGxGYWNlTm9uZSA9IDA7XG5jb25zdCBDdWxsRmFjZUJhY2sgPSAxO1xuY29uc3QgQ3VsbEZhY2VGcm9udCA9IDI7XG5jb25zdCBDdWxsRmFjZUZyb250QmFjayA9IDM7XG5jb25zdCBCYXNpY1NoYWRvd01hcCA9IDA7XG5jb25zdCBQQ0ZTaGFkb3dNYXAgPSAxO1xuY29uc3QgUENGU29mdFNoYWRvd01hcCA9IDI7XG5jb25zdCBWU01TaGFkb3dNYXAgPSAzO1xuY29uc3QgRnJvbnRTaWRlID0gMDtcbmNvbnN0IEJhY2tTaWRlID0gMTtcbmNvbnN0IERvdWJsZVNpZGUgPSAyO1xuY29uc3QgTm9CbGVuZGluZyA9IDA7XG5jb25zdCBOb3JtYWxCbGVuZGluZyA9IDE7XG5jb25zdCBBZGRpdGl2ZUJsZW5kaW5nID0gMjtcbmNvbnN0IFN1YnRyYWN0aXZlQmxlbmRpbmcgPSAzO1xuY29uc3QgTXVsdGlwbHlCbGVuZGluZyA9IDQ7XG5jb25zdCBDdXN0b21CbGVuZGluZyA9IDU7XG5jb25zdCBBZGRFcXVhdGlvbiA9IDEwMDtcbmNvbnN0IFN1YnRyYWN0RXF1YXRpb24gPSAxMDE7XG5jb25zdCBSZXZlcnNlU3VidHJhY3RFcXVhdGlvbiA9IDEwMjtcbmNvbnN0IE1pbkVxdWF0aW9uID0gMTAzO1xuY29uc3QgTWF4RXF1YXRpb24gPSAxMDQ7XG5jb25zdCBaZXJvRmFjdG9yID0gMjAwO1xuY29uc3QgT25lRmFjdG9yID0gMjAxO1xuY29uc3QgU3JjQ29sb3JGYWN0b3IgPSAyMDI7XG5jb25zdCBPbmVNaW51c1NyY0NvbG9yRmFjdG9yID0gMjAzO1xuY29uc3QgU3JjQWxwaGFGYWN0b3IgPSAyMDQ7XG5jb25zdCBPbmVNaW51c1NyY0FscGhhRmFjdG9yID0gMjA1O1xuY29uc3QgRHN0QWxwaGFGYWN0b3IgPSAyMDY7XG5jb25zdCBPbmVNaW51c0RzdEFscGhhRmFjdG9yID0gMjA3O1xuY29uc3QgRHN0Q29sb3JGYWN0b3IgPSAyMDg7XG5jb25zdCBPbmVNaW51c0RzdENvbG9yRmFjdG9yID0gMjA5O1xuY29uc3QgU3JjQWxwaGFTYXR1cmF0ZUZhY3RvciA9IDIxMDtcbmNvbnN0IENvbnN0YW50Q29sb3JGYWN0b3IgPSAyMTE7XG5jb25zdCBPbmVNaW51c0NvbnN0YW50Q29sb3JGYWN0b3IgPSAyMTI7XG5jb25zdCBDb25zdGFudEFscGhhRmFjdG9yID0gMjEzO1xuY29uc3QgT25lTWludXNDb25zdGFudEFscGhhRmFjdG9yID0gMjE0O1xuY29uc3QgTmV2ZXJEZXB0aCA9IDA7XG5jb25zdCBBbHdheXNEZXB0aCA9IDE7XG5jb25zdCBMZXNzRGVwdGggPSAyO1xuY29uc3QgTGVzc0VxdWFsRGVwdGggPSAzO1xuY29uc3QgRXF1YWxEZXB0aCA9IDQ7XG5jb25zdCBHcmVhdGVyRXF1YWxEZXB0aCA9IDU7XG5jb25zdCBHcmVhdGVyRGVwdGggPSA2O1xuY29uc3QgTm90RXF1YWxEZXB0aCA9IDc7XG5jb25zdCBNdWx0aXBseU9wZXJhdGlvbiA9IDA7XG5jb25zdCBNaXhPcGVyYXRpb24gPSAxO1xuY29uc3QgQWRkT3BlcmF0aW9uID0gMjtcbmNvbnN0IE5vVG9uZU1hcHBpbmcgPSAwO1xuY29uc3QgTGluZWFyVG9uZU1hcHBpbmcgPSAxO1xuY29uc3QgUmVpbmhhcmRUb25lTWFwcGluZyA9IDI7XG5jb25zdCBDaW5lb25Ub25lTWFwcGluZyA9IDM7XG5jb25zdCBBQ0VTRmlsbWljVG9uZU1hcHBpbmcgPSA0O1xuY29uc3QgQ3VzdG9tVG9uZU1hcHBpbmcgPSA1O1xuY29uc3QgQWdYVG9uZU1hcHBpbmcgPSA2O1xuY29uc3QgTmV1dHJhbFRvbmVNYXBwaW5nID0gNztcbmNvbnN0IEF0dGFjaGVkQmluZE1vZGUgPSAnYXR0YWNoZWQnO1xuY29uc3QgRGV0YWNoZWRCaW5kTW9kZSA9ICdkZXRhY2hlZCc7XG5cbmNvbnN0IFVWTWFwcGluZyA9IDMwMDtcbmNvbnN0IEN1YmVSZWZsZWN0aW9uTWFwcGluZyA9IDMwMTtcbmNvbnN0IEN1YmVSZWZyYWN0aW9uTWFwcGluZyA9IDMwMjtcbmNvbnN0IEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nID0gMzAzO1xuY29uc3QgRXF1aXJlY3Rhbmd1bGFyUmVmcmFjdGlvbk1hcHBpbmcgPSAzMDQ7XG5jb25zdCBDdWJlVVZSZWZsZWN0aW9uTWFwcGluZyA9IDMwNjtcbmNvbnN0IFJlcGVhdFdyYXBwaW5nID0gMTAwMDtcbmNvbnN0IENsYW1wVG9FZGdlV3JhcHBpbmcgPSAxMDAxO1xuY29uc3QgTWlycm9yZWRSZXBlYXRXcmFwcGluZyA9IDEwMDI7XG5jb25zdCBOZWFyZXN0RmlsdGVyID0gMTAwMztcbmNvbnN0IE5lYXJlc3RNaXBtYXBOZWFyZXN0RmlsdGVyID0gMTAwNDtcbmNvbnN0IE5lYXJlc3RNaXBNYXBOZWFyZXN0RmlsdGVyID0gMTAwNDtcbmNvbnN0IE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXIgPSAxMDA1O1xuY29uc3QgTmVhcmVzdE1pcE1hcExpbmVhckZpbHRlciA9IDEwMDU7XG5jb25zdCBMaW5lYXJGaWx0ZXIgPSAxMDA2O1xuY29uc3QgTGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlciA9IDEwMDc7XG5jb25zdCBMaW5lYXJNaXBNYXBOZWFyZXN0RmlsdGVyID0gMTAwNztcbmNvbnN0IExpbmVhck1pcG1hcExpbmVhckZpbHRlciA9IDEwMDg7XG5jb25zdCBMaW5lYXJNaXBNYXBMaW5lYXJGaWx0ZXIgPSAxMDA4O1xuY29uc3QgVW5zaWduZWRCeXRlVHlwZSA9IDEwMDk7XG5jb25zdCBCeXRlVHlwZSA9IDEwMTA7XG5jb25zdCBTaG9ydFR5cGUgPSAxMDExO1xuY29uc3QgVW5zaWduZWRTaG9ydFR5cGUgPSAxMDEyO1xuY29uc3QgSW50VHlwZSA9IDEwMTM7XG5jb25zdCBVbnNpZ25lZEludFR5cGUgPSAxMDE0O1xuY29uc3QgRmxvYXRUeXBlID0gMTAxNTtcbmNvbnN0IEhhbGZGbG9hdFR5cGUgPSAxMDE2O1xuY29uc3QgVW5zaWduZWRTaG9ydDQ0NDRUeXBlID0gMTAxNztcbmNvbnN0IFVuc2lnbmVkU2hvcnQ1NTUxVHlwZSA9IDEwMTg7XG5jb25zdCBVbnNpZ25lZEludDI0OFR5cGUgPSAxMDIwO1xuY29uc3QgVW5zaWduZWRJbnQ1OTk5VHlwZSA9IDM1OTAyO1xuY29uc3QgQWxwaGFGb3JtYXQgPSAxMDIxO1xuY29uc3QgUkdCRm9ybWF0ID0gMTAyMjtcbmNvbnN0IFJHQkFGb3JtYXQgPSAxMDIzO1xuY29uc3QgTHVtaW5hbmNlRm9ybWF0ID0gMTAyNDtcbmNvbnN0IEx1bWluYW5jZUFscGhhRm9ybWF0ID0gMTAyNTtcbmNvbnN0IERlcHRoRm9ybWF0ID0gMTAyNjtcbmNvbnN0IERlcHRoU3RlbmNpbEZvcm1hdCA9IDEwMjc7XG5jb25zdCBSZWRGb3JtYXQgPSAxMDI4O1xuY29uc3QgUmVkSW50ZWdlckZvcm1hdCA9IDEwMjk7XG5jb25zdCBSR0Zvcm1hdCA9IDEwMzA7XG5jb25zdCBSR0ludGVnZXJGb3JtYXQgPSAxMDMxO1xuY29uc3QgUkdCSW50ZWdlckZvcm1hdCA9IDEwMzI7XG5jb25zdCBSR0JBSW50ZWdlckZvcm1hdCA9IDEwMzM7XG5cbmNvbnN0IFJHQl9TM1RDX0RYVDFfRm9ybWF0ID0gMzM3NzY7XG5jb25zdCBSR0JBX1MzVENfRFhUMV9Gb3JtYXQgPSAzMzc3NztcbmNvbnN0IFJHQkFfUzNUQ19EWFQzX0Zvcm1hdCA9IDMzNzc4O1xuY29uc3QgUkdCQV9TM1RDX0RYVDVfRm9ybWF0ID0gMzM3Nzk7XG5jb25zdCBSR0JfUFZSVENfNEJQUFYxX0Zvcm1hdCA9IDM1ODQwO1xuY29uc3QgUkdCX1BWUlRDXzJCUFBWMV9Gb3JtYXQgPSAzNTg0MTtcbmNvbnN0IFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCA9IDM1ODQyO1xuY29uc3QgUkdCQV9QVlJUQ18yQlBQVjFfRm9ybWF0ID0gMzU4NDM7XG5jb25zdCBSR0JfRVRDMV9Gb3JtYXQgPSAzNjE5NjtcbmNvbnN0IFJHQl9FVEMyX0Zvcm1hdCA9IDM3NDkyO1xuY29uc3QgUkdCQV9FVEMyX0VBQ19Gb3JtYXQgPSAzNzQ5NjtcbmNvbnN0IFJHQkFfQVNUQ180eDRfRm9ybWF0ID0gMzc4MDg7XG5jb25zdCBSR0JBX0FTVENfNXg0X0Zvcm1hdCA9IDM3ODA5O1xuY29uc3QgUkdCQV9BU1RDXzV4NV9Gb3JtYXQgPSAzNzgxMDtcbmNvbnN0IFJHQkFfQVNUQ182eDVfRm9ybWF0ID0gMzc4MTE7XG5jb25zdCBSR0JBX0FTVENfNng2X0Zvcm1hdCA9IDM3ODEyO1xuY29uc3QgUkdCQV9BU1RDXzh4NV9Gb3JtYXQgPSAzNzgxMztcbmNvbnN0IFJHQkFfQVNUQ184eDZfRm9ybWF0ID0gMzc4MTQ7XG5jb25zdCBSR0JBX0FTVENfOHg4X0Zvcm1hdCA9IDM3ODE1O1xuY29uc3QgUkdCQV9BU1RDXzEweDVfRm9ybWF0ID0gMzc4MTY7XG5jb25zdCBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQgPSAzNzgxNztcbmNvbnN0IFJHQkFfQVNUQ18xMHg4X0Zvcm1hdCA9IDM3ODE4O1xuY29uc3QgUkdCQV9BU1RDXzEweDEwX0Zvcm1hdCA9IDM3ODE5O1xuY29uc3QgUkdCQV9BU1RDXzEyeDEwX0Zvcm1hdCA9IDM3ODIwO1xuY29uc3QgUkdCQV9BU1RDXzEyeDEyX0Zvcm1hdCA9IDM3ODIxO1xuY29uc3QgUkdCQV9CUFRDX0Zvcm1hdCA9IDM2NDkyO1xuY29uc3QgUkdCX0JQVENfU0lHTkVEX0Zvcm1hdCA9IDM2NDk0O1xuY29uc3QgUkdCX0JQVENfVU5TSUdORURfRm9ybWF0ID0gMzY0OTU7XG5jb25zdCBSRURfUkdUQzFfRm9ybWF0ID0gMzYyODM7XG5jb25zdCBTSUdORURfUkVEX1JHVEMxX0Zvcm1hdCA9IDM2Mjg0O1xuY29uc3QgUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCA9IDM2Mjg1O1xuY29uc3QgU0lHTkVEX1JFRF9HUkVFTl9SR1RDMl9Gb3JtYXQgPSAzNjI4NjtcbmNvbnN0IExvb3BPbmNlID0gMjIwMDtcbmNvbnN0IExvb3BSZXBlYXQgPSAyMjAxO1xuY29uc3QgTG9vcFBpbmdQb25nID0gMjIwMjtcbmNvbnN0IEludGVycG9sYXRlRGlzY3JldGUgPSAyMzAwO1xuY29uc3QgSW50ZXJwb2xhdGVMaW5lYXIgPSAyMzAxO1xuY29uc3QgSW50ZXJwb2xhdGVTbW9vdGggPSAyMzAyO1xuY29uc3QgWmVyb0N1cnZhdHVyZUVuZGluZyA9IDI0MDA7XG5jb25zdCBaZXJvU2xvcGVFbmRpbmcgPSAyNDAxO1xuY29uc3QgV3JhcEFyb3VuZEVuZGluZyA9IDI0MDI7XG5jb25zdCBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGUgPSAyNTAwO1xuY29uc3QgQWRkaXRpdmVBbmltYXRpb25CbGVuZE1vZGUgPSAyNTAxO1xuY29uc3QgVHJpYW5nbGVzRHJhd01vZGUgPSAwO1xuY29uc3QgVHJpYW5nbGVTdHJpcERyYXdNb2RlID0gMTtcbmNvbnN0IFRyaWFuZ2xlRmFuRHJhd01vZGUgPSAyO1xuY29uc3QgQmFzaWNEZXB0aFBhY2tpbmcgPSAzMjAwO1xuY29uc3QgUkdCQURlcHRoUGFja2luZyA9IDMyMDE7XG5jb25zdCBUYW5nZW50U3BhY2VOb3JtYWxNYXAgPSAwO1xuY29uc3QgT2JqZWN0U3BhY2VOb3JtYWxNYXAgPSAxO1xuXG4vLyBDb2xvciBzcGFjZSBzdHJpbmcgaWRlbnRpZmllcnMsIG1hdGNoaW5nIENTUyBDb2xvciBNb2R1bGUgTGV2ZWwgNCBhbmQgV2ViR1BVIG5hbWVzIHdoZXJlIGF2YWlsYWJsZS5cbmNvbnN0IE5vQ29sb3JTcGFjZSA9ICcnO1xuY29uc3QgU1JHQkNvbG9yU3BhY2UgPSAnc3JnYic7XG5jb25zdCBMaW5lYXJTUkdCQ29sb3JTcGFjZSA9ICdzcmdiLWxpbmVhcic7XG5jb25zdCBEaXNwbGF5UDNDb2xvclNwYWNlID0gJ2Rpc3BsYXktcDMnO1xuY29uc3QgTGluZWFyRGlzcGxheVAzQ29sb3JTcGFjZSA9ICdkaXNwbGF5LXAzLWxpbmVhcic7XG5cbmNvbnN0IExpbmVhclRyYW5zZmVyID0gJ2xpbmVhcic7XG5jb25zdCBTUkdCVHJhbnNmZXIgPSAnc3JnYic7XG5cbmNvbnN0IFJlYzcwOVByaW1hcmllcyA9ICdyZWM3MDknO1xuY29uc3QgUDNQcmltYXJpZXMgPSAncDMnO1xuXG5jb25zdCBaZXJvU3RlbmNpbE9wID0gMDtcbmNvbnN0IEtlZXBTdGVuY2lsT3AgPSA3NjgwO1xuY29uc3QgUmVwbGFjZVN0ZW5jaWxPcCA9IDc2ODE7XG5jb25zdCBJbmNyZW1lbnRTdGVuY2lsT3AgPSA3NjgyO1xuY29uc3QgRGVjcmVtZW50U3RlbmNpbE9wID0gNzY4MztcbmNvbnN0IEluY3JlbWVudFdyYXBTdGVuY2lsT3AgPSAzNDA1NTtcbmNvbnN0IERlY3JlbWVudFdyYXBTdGVuY2lsT3AgPSAzNDA1NjtcbmNvbnN0IEludmVydFN0ZW5jaWxPcCA9IDUzODY7XG5cbmNvbnN0IE5ldmVyU3RlbmNpbEZ1bmMgPSA1MTI7XG5jb25zdCBMZXNzU3RlbmNpbEZ1bmMgPSA1MTM7XG5jb25zdCBFcXVhbFN0ZW5jaWxGdW5jID0gNTE0O1xuY29uc3QgTGVzc0VxdWFsU3RlbmNpbEZ1bmMgPSA1MTU7XG5jb25zdCBHcmVhdGVyU3RlbmNpbEZ1bmMgPSA1MTY7XG5jb25zdCBOb3RFcXVhbFN0ZW5jaWxGdW5jID0gNTE3O1xuY29uc3QgR3JlYXRlckVxdWFsU3RlbmNpbEZ1bmMgPSA1MTg7XG5jb25zdCBBbHdheXNTdGVuY2lsRnVuYyA9IDUxOTtcblxuY29uc3QgTmV2ZXJDb21wYXJlID0gNTEyO1xuY29uc3QgTGVzc0NvbXBhcmUgPSA1MTM7XG5jb25zdCBFcXVhbENvbXBhcmUgPSA1MTQ7XG5jb25zdCBMZXNzRXF1YWxDb21wYXJlID0gNTE1O1xuY29uc3QgR3JlYXRlckNvbXBhcmUgPSA1MTY7XG5jb25zdCBOb3RFcXVhbENvbXBhcmUgPSA1MTc7XG5jb25zdCBHcmVhdGVyRXF1YWxDb21wYXJlID0gNTE4O1xuY29uc3QgQWx3YXlzQ29tcGFyZSA9IDUxOTtcblxuY29uc3QgU3RhdGljRHJhd1VzYWdlID0gMzUwNDQ7XG5jb25zdCBEeW5hbWljRHJhd1VzYWdlID0gMzUwNDg7XG5jb25zdCBTdHJlYW1EcmF3VXNhZ2UgPSAzNTA0MDtcbmNvbnN0IFN0YXRpY1JlYWRVc2FnZSA9IDM1MDQ1O1xuY29uc3QgRHluYW1pY1JlYWRVc2FnZSA9IDM1MDQ5O1xuY29uc3QgU3RyZWFtUmVhZFVzYWdlID0gMzUwNDE7XG5jb25zdCBTdGF0aWNDb3B5VXNhZ2UgPSAzNTA0NjtcbmNvbnN0IER5bmFtaWNDb3B5VXNhZ2UgPSAzNTA1MDtcbmNvbnN0IFN0cmVhbUNvcHlVc2FnZSA9IDM1MDQyO1xuXG5jb25zdCBHTFNMMSA9ICcxMDAnO1xuY29uc3QgR0xTTDMgPSAnMzAwIGVzJztcblxuY29uc3QgV2ViR0xDb29yZGluYXRlU3lzdGVtID0gMjAwMDtcbmNvbnN0IFdlYkdQVUNvb3JkaW5hdGVTeXN0ZW0gPSAyMDAxO1xuXG4vKipcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvZXZlbnRkaXNwYXRjaGVyLmpzL1xuICovXG5cbmNsYXNzIEV2ZW50RGlzcGF0Y2hlciB7XG5cblx0YWRkRXZlbnRMaXN0ZW5lciggdHlwZSwgbGlzdGVuZXIgKSB7XG5cblx0XHRpZiAoIHRoaXMuX2xpc3RlbmVycyA9PT0gdW5kZWZpbmVkICkgdGhpcy5fbGlzdGVuZXJzID0ge307XG5cblx0XHRjb25zdCBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnM7XG5cblx0XHRpZiAoIGxpc3RlbmVyc1sgdHlwZSBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGxpc3RlbmVyc1sgdHlwZSBdID0gW107XG5cblx0XHR9XG5cblx0XHRpZiAoIGxpc3RlbmVyc1sgdHlwZSBdLmluZGV4T2YoIGxpc3RlbmVyICkgPT09IC0gMSApIHtcblxuXHRcdFx0bGlzdGVuZXJzWyB0eXBlIF0ucHVzaCggbGlzdGVuZXIgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0aGFzRXZlbnRMaXN0ZW5lciggdHlwZSwgbGlzdGVuZXIgKSB7XG5cblx0XHRpZiAoIHRoaXMuX2xpc3RlbmVycyA9PT0gdW5kZWZpbmVkICkgcmV0dXJuIGZhbHNlO1xuXG5cdFx0Y29uc3QgbGlzdGVuZXJzID0gdGhpcy5fbGlzdGVuZXJzO1xuXG5cdFx0cmV0dXJuIGxpc3RlbmVyc1sgdHlwZSBdICE9PSB1bmRlZmluZWQgJiYgbGlzdGVuZXJzWyB0eXBlIF0uaW5kZXhPZiggbGlzdGVuZXIgKSAhPT0gLSAxO1xuXG5cdH1cblxuXHRyZW1vdmVFdmVudExpc3RlbmVyKCB0eXBlLCBsaXN0ZW5lciApIHtcblxuXHRcdGlmICggdGhpcy5fbGlzdGVuZXJzID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHRjb25zdCBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnM7XG5cdFx0Y29uc3QgbGlzdGVuZXJBcnJheSA9IGxpc3RlbmVyc1sgdHlwZSBdO1xuXG5cdFx0aWYgKCBsaXN0ZW5lckFycmF5ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IGluZGV4ID0gbGlzdGVuZXJBcnJheS5pbmRleE9mKCBsaXN0ZW5lciApO1xuXG5cdFx0XHRpZiAoIGluZGV4ICE9PSAtIDEgKSB7XG5cblx0XHRcdFx0bGlzdGVuZXJBcnJheS5zcGxpY2UoIGluZGV4LCAxICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0ZGlzcGF0Y2hFdmVudCggZXZlbnQgKSB7XG5cblx0XHRpZiAoIHRoaXMuX2xpc3RlbmVycyA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xuXG5cdFx0Y29uc3QgbGlzdGVuZXJzID0gdGhpcy5fbGlzdGVuZXJzO1xuXHRcdGNvbnN0IGxpc3RlbmVyQXJyYXkgPSBsaXN0ZW5lcnNbIGV2ZW50LnR5cGUgXTtcblxuXHRcdGlmICggbGlzdGVuZXJBcnJheSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRldmVudC50YXJnZXQgPSB0aGlzO1xuXG5cdFx0XHQvLyBNYWtlIGEgY29weSwgaW4gY2FzZSBsaXN0ZW5lcnMgYXJlIHJlbW92ZWQgd2hpbGUgaXRlcmF0aW5nLlxuXHRcdFx0Y29uc3QgYXJyYXkgPSBsaXN0ZW5lckFycmF5LnNsaWNlKCAwICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGFycmF5Lmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0YXJyYXlbIGkgXS5jYWxsKCB0aGlzLCBldmVudCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGV2ZW50LnRhcmdldCA9IG51bGw7XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbmNvbnN0IF9sdXQgPSBbICcwMCcsICcwMScsICcwMicsICcwMycsICcwNCcsICcwNScsICcwNicsICcwNycsICcwOCcsICcwOScsICcwYScsICcwYicsICcwYycsICcwZCcsICcwZScsICcwZicsICcxMCcsICcxMScsICcxMicsICcxMycsICcxNCcsICcxNScsICcxNicsICcxNycsICcxOCcsICcxOScsICcxYScsICcxYicsICcxYycsICcxZCcsICcxZScsICcxZicsICcyMCcsICcyMScsICcyMicsICcyMycsICcyNCcsICcyNScsICcyNicsICcyNycsICcyOCcsICcyOScsICcyYScsICcyYicsICcyYycsICcyZCcsICcyZScsICcyZicsICczMCcsICczMScsICczMicsICczMycsICczNCcsICczNScsICczNicsICczNycsICczOCcsICczOScsICczYScsICczYicsICczYycsICczZCcsICczZScsICczZicsICc0MCcsICc0MScsICc0MicsICc0MycsICc0NCcsICc0NScsICc0NicsICc0NycsICc0OCcsICc0OScsICc0YScsICc0YicsICc0YycsICc0ZCcsICc0ZScsICc0ZicsICc1MCcsICc1MScsICc1MicsICc1MycsICc1NCcsICc1NScsICc1NicsICc1NycsICc1OCcsICc1OScsICc1YScsICc1YicsICc1YycsICc1ZCcsICc1ZScsICc1ZicsICc2MCcsICc2MScsICc2MicsICc2MycsICc2NCcsICc2NScsICc2NicsICc2NycsICc2OCcsICc2OScsICc2YScsICc2YicsICc2YycsICc2ZCcsICc2ZScsICc2ZicsICc3MCcsICc3MScsICc3MicsICc3MycsICc3NCcsICc3NScsICc3NicsICc3NycsICc3OCcsICc3OScsICc3YScsICc3YicsICc3YycsICc3ZCcsICc3ZScsICc3ZicsICc4MCcsICc4MScsICc4MicsICc4MycsICc4NCcsICc4NScsICc4NicsICc4NycsICc4OCcsICc4OScsICc4YScsICc4YicsICc4YycsICc4ZCcsICc4ZScsICc4ZicsICc5MCcsICc5MScsICc5MicsICc5MycsICc5NCcsICc5NScsICc5NicsICc5NycsICc5OCcsICc5OScsICc5YScsICc5YicsICc5YycsICc5ZCcsICc5ZScsICc5ZicsICdhMCcsICdhMScsICdhMicsICdhMycsICdhNCcsICdhNScsICdhNicsICdhNycsICdhOCcsICdhOScsICdhYScsICdhYicsICdhYycsICdhZCcsICdhZScsICdhZicsICdiMCcsICdiMScsICdiMicsICdiMycsICdiNCcsICdiNScsICdiNicsICdiNycsICdiOCcsICdiOScsICdiYScsICdiYicsICdiYycsICdiZCcsICdiZScsICdiZicsICdjMCcsICdjMScsICdjMicsICdjMycsICdjNCcsICdjNScsICdjNicsICdjNycsICdjOCcsICdjOScsICdjYScsICdjYicsICdjYycsICdjZCcsICdjZScsICdjZicsICdkMCcsICdkMScsICdkMicsICdkMycsICdkNCcsICdkNScsICdkNicsICdkNycsICdkOCcsICdkOScsICdkYScsICdkYicsICdkYycsICdkZCcsICdkZScsICdkZicsICdlMCcsICdlMScsICdlMicsICdlMycsICdlNCcsICdlNScsICdlNicsICdlNycsICdlOCcsICdlOScsICdlYScsICdlYicsICdlYycsICdlZCcsICdlZScsICdlZicsICdmMCcsICdmMScsICdmMicsICdmMycsICdmNCcsICdmNScsICdmNicsICdmNycsICdmOCcsICdmOScsICdmYScsICdmYicsICdmYycsICdmZCcsICdmZScsICdmZicgXTtcblxubGV0IF9zZWVkID0gMTIzNDU2NztcblxuXG5jb25zdCBERUcyUkFEID0gTWF0aC5QSSAvIDE4MDtcbmNvbnN0IFJBRDJERUcgPSAxODAgLyBNYXRoLlBJO1xuXG4vLyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzEwNTAzNC9ob3ctdG8tY3JlYXRlLWEtZ3VpZC11dWlkLWluLWphdmFzY3JpcHQvMjE5NjMxMzYjMjE5NjMxMzZcbmZ1bmN0aW9uIGdlbmVyYXRlVVVJRCgpIHtcblxuXHRjb25zdCBkMCA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcblx0Y29uc3QgZDEgPSBNYXRoLnJhbmRvbSgpICogMHhmZmZmZmZmZiB8IDA7XG5cdGNvbnN0IGQyID0gTWF0aC5yYW5kb20oKSAqIDB4ZmZmZmZmZmYgfCAwO1xuXHRjb25zdCBkMyA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcblx0Y29uc3QgdXVpZCA9IF9sdXRbIGQwICYgMHhmZiBdICsgX2x1dFsgZDAgPj4gOCAmIDB4ZmYgXSArIF9sdXRbIGQwID4+IDE2ICYgMHhmZiBdICsgX2x1dFsgZDAgPj4gMjQgJiAweGZmIF0gKyAnLScgK1xuXHRcdFx0X2x1dFsgZDEgJiAweGZmIF0gKyBfbHV0WyBkMSA+PiA4ICYgMHhmZiBdICsgJy0nICsgX2x1dFsgZDEgPj4gMTYgJiAweDBmIHwgMHg0MCBdICsgX2x1dFsgZDEgPj4gMjQgJiAweGZmIF0gKyAnLScgK1xuXHRcdFx0X2x1dFsgZDIgJiAweDNmIHwgMHg4MCBdICsgX2x1dFsgZDIgPj4gOCAmIDB4ZmYgXSArICctJyArIF9sdXRbIGQyID4+IDE2ICYgMHhmZiBdICsgX2x1dFsgZDIgPj4gMjQgJiAweGZmIF0gK1xuXHRcdFx0X2x1dFsgZDMgJiAweGZmIF0gKyBfbHV0WyBkMyA+PiA4ICYgMHhmZiBdICsgX2x1dFsgZDMgPj4gMTYgJiAweGZmIF0gKyBfbHV0WyBkMyA+PiAyNCAmIDB4ZmYgXTtcblxuXHQvLyAudG9Mb3dlckNhc2UoKSBoZXJlIGZsYXR0ZW5zIGNvbmNhdGVuYXRlZCBzdHJpbmdzIHRvIHNhdmUgaGVhcCBtZW1vcnkgc3BhY2UuXG5cdHJldHVybiB1dWlkLnRvTG93ZXJDYXNlKCk7XG5cbn1cblxuZnVuY3Rpb24gY2xhbXAoIHZhbHVlLCBtaW4sIG1heCApIHtcblxuXHRyZXR1cm4gTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgdmFsdWUgKSApO1xuXG59XG5cbi8vIGNvbXB1dGUgZXVjbGlkZWFuIG1vZHVsbyBvZiBtICUgblxuLy8gaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTW9kdWxvX29wZXJhdGlvblxuZnVuY3Rpb24gZXVjbGlkZWFuTW9kdWxvKCBuLCBtICkge1xuXG5cdHJldHVybiAoICggbiAlIG0gKSArIG0gKSAlIG07XG5cbn1cblxuLy8gTGluZWFyIG1hcHBpbmcgZnJvbSByYW5nZSA8YTEsIGEyPiB0byByYW5nZSA8YjEsIGIyPlxuZnVuY3Rpb24gbWFwTGluZWFyKCB4LCBhMSwgYTIsIGIxLCBiMiApIHtcblxuXHRyZXR1cm4gYjEgKyAoIHggLSBhMSApICogKCBiMiAtIGIxICkgLyAoIGEyIC0gYTEgKTtcblxufVxuXG4vLyBodHRwczovL3d3dy5nYW1lZGV2Lm5ldC90dXRvcmlhbHMvcHJvZ3JhbW1pbmcvZ2VuZXJhbC1hbmQtZ2FtZXBsYXktcHJvZ3JhbW1pbmcvaW52ZXJzZS1sZXJwLWEtc3VwZXItdXNlZnVsLXlldC1vZnRlbi1vdmVybG9va2VkLWZ1bmN0aW9uLXI1MjMwL1xuZnVuY3Rpb24gaW52ZXJzZUxlcnAoIHgsIHksIHZhbHVlICkge1xuXG5cdGlmICggeCAhPT0geSApIHtcblxuXHRcdHJldHVybiAoIHZhbHVlIC0geCApIC8gKCB5IC0geCApO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRyZXR1cm4gMDtcblxuXHR9XG5cbn1cblxuLy8gaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGluZWFyX2ludGVycG9sYXRpb25cbmZ1bmN0aW9uIGxlcnAoIHgsIHksIHQgKSB7XG5cblx0cmV0dXJuICggMSAtIHQgKSAqIHggKyB0ICogeTtcblxufVxuXG4vLyBodHRwOi8vd3d3LnJvcnlkcmlzY29sbC5jb20vMjAxNi8wMy8wNy9mcmFtZS1yYXRlLWluZGVwZW5kZW50LWRhbXBpbmctdXNpbmctbGVycC9cbmZ1bmN0aW9uIGRhbXAoIHgsIHksIGxhbWJkYSwgZHQgKSB7XG5cblx0cmV0dXJuIGxlcnAoIHgsIHksIDEgLSBNYXRoLmV4cCggLSBsYW1iZGEgKiBkdCApICk7XG5cbn1cblxuLy8gaHR0cHM6Ly93d3cuZGVzbW9zLmNvbS9jYWxjdWxhdG9yL3Zjc2pueXo3eDRcbmZ1bmN0aW9uIHBpbmdwb25nKCB4LCBsZW5ndGggPSAxICkge1xuXG5cdHJldHVybiBsZW5ndGggLSBNYXRoLmFicyggZXVjbGlkZWFuTW9kdWxvKCB4LCBsZW5ndGggKiAyICkgLSBsZW5ndGggKTtcblxufVxuXG4vLyBodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1Ntb290aHN0ZXBcbmZ1bmN0aW9uIHNtb290aHN0ZXAoIHgsIG1pbiwgbWF4ICkge1xuXG5cdGlmICggeCA8PSBtaW4gKSByZXR1cm4gMDtcblx0aWYgKCB4ID49IG1heCApIHJldHVybiAxO1xuXG5cdHggPSAoIHggLSBtaW4gKSAvICggbWF4IC0gbWluICk7XG5cblx0cmV0dXJuIHggKiB4ICogKCAzIC0gMiAqIHggKTtcblxufVxuXG5mdW5jdGlvbiBzbW9vdGhlcnN0ZXAoIHgsIG1pbiwgbWF4ICkge1xuXG5cdGlmICggeCA8PSBtaW4gKSByZXR1cm4gMDtcblx0aWYgKCB4ID49IG1heCApIHJldHVybiAxO1xuXG5cdHggPSAoIHggLSBtaW4gKSAvICggbWF4IC0gbWluICk7XG5cblx0cmV0dXJuIHggKiB4ICogeCAqICggeCAqICggeCAqIDYgLSAxNSApICsgMTAgKTtcblxufVxuXG4vLyBSYW5kb20gaW50ZWdlciBmcm9tIDxsb3csIGhpZ2g+IGludGVydmFsXG5mdW5jdGlvbiByYW5kSW50KCBsb3csIGhpZ2ggKSB7XG5cblx0cmV0dXJuIGxvdyArIE1hdGguZmxvb3IoIE1hdGgucmFuZG9tKCkgKiAoIGhpZ2ggLSBsb3cgKyAxICkgKTtcblxufVxuXG4vLyBSYW5kb20gZmxvYXQgZnJvbSA8bG93LCBoaWdoPiBpbnRlcnZhbFxuZnVuY3Rpb24gcmFuZEZsb2F0KCBsb3csIGhpZ2ggKSB7XG5cblx0cmV0dXJuIGxvdyArIE1hdGgucmFuZG9tKCkgKiAoIGhpZ2ggLSBsb3cgKTtcblxufVxuXG4vLyBSYW5kb20gZmxvYXQgZnJvbSA8LXJhbmdlLzIsIHJhbmdlLzI+IGludGVydmFsXG5mdW5jdGlvbiByYW5kRmxvYXRTcHJlYWQoIHJhbmdlICkge1xuXG5cdHJldHVybiByYW5nZSAqICggMC41IC0gTWF0aC5yYW5kb20oKSApO1xuXG59XG5cbi8vIERldGVybWluaXN0aWMgcHNldWRvLXJhbmRvbSBmbG9hdCBpbiB0aGUgaW50ZXJ2YWwgWyAwLCAxIF1cbmZ1bmN0aW9uIHNlZWRlZFJhbmRvbSggcyApIHtcblxuXHRpZiAoIHMgIT09IHVuZGVmaW5lZCApIF9zZWVkID0gcztcblxuXHQvLyBNdWxiZXJyeTMyIGdlbmVyYXRvclxuXG5cdGxldCB0ID0gX3NlZWQgKz0gMHg2RDJCNzlGNTtcblxuXHR0ID0gTWF0aC5pbXVsKCB0IF4gdCA+Pj4gMTUsIHQgfCAxICk7XG5cblx0dCBePSB0ICsgTWF0aC5pbXVsKCB0IF4gdCA+Pj4gNywgdCB8IDYxICk7XG5cblx0cmV0dXJuICggKCB0IF4gdCA+Pj4gMTQgKSA+Pj4gMCApIC8gNDI5NDk2NzI5NjtcblxufVxuXG5mdW5jdGlvbiBkZWdUb1JhZCggZGVncmVlcyApIHtcblxuXHRyZXR1cm4gZGVncmVlcyAqIERFRzJSQUQ7XG5cbn1cblxuZnVuY3Rpb24gcmFkVG9EZWcoIHJhZGlhbnMgKSB7XG5cblx0cmV0dXJuIHJhZGlhbnMgKiBSQUQyREVHO1xuXG59XG5cbmZ1bmN0aW9uIGlzUG93ZXJPZlR3byggdmFsdWUgKSB7XG5cblx0cmV0dXJuICggdmFsdWUgJiAoIHZhbHVlIC0gMSApICkgPT09IDAgJiYgdmFsdWUgIT09IDA7XG5cbn1cblxuZnVuY3Rpb24gY2VpbFBvd2VyT2ZUd28oIHZhbHVlICkge1xuXG5cdHJldHVybiBNYXRoLnBvdyggMiwgTWF0aC5jZWlsKCBNYXRoLmxvZyggdmFsdWUgKSAvIE1hdGguTE4yICkgKTtcblxufVxuXG5mdW5jdGlvbiBmbG9vclBvd2VyT2ZUd28oIHZhbHVlICkge1xuXG5cdHJldHVybiBNYXRoLnBvdyggMiwgTWF0aC5mbG9vciggTWF0aC5sb2coIHZhbHVlICkgLyBNYXRoLkxOMiApICk7XG5cbn1cblxuZnVuY3Rpb24gc2V0UXVhdGVybmlvbkZyb21Qcm9wZXJFdWxlciggcSwgYSwgYiwgYywgb3JkZXIgKSB7XG5cblx0Ly8gSW50cmluc2ljIFByb3BlciBFdWxlciBBbmdsZXMgLSBzZWUgaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRXVsZXJfYW5nbGVzXG5cblx0Ly8gcm90YXRpb25zIGFyZSBhcHBsaWVkIHRvIHRoZSBheGVzIGluIHRoZSBvcmRlciBzcGVjaWZpZWQgYnkgJ29yZGVyJ1xuXHQvLyByb3RhdGlvbiBieSBhbmdsZSAnYScgaXMgYXBwbGllZCBmaXJzdCwgdGhlbiBieSBhbmdsZSAnYicsIHRoZW4gYnkgYW5nbGUgJ2MnXG5cdC8vIGFuZ2xlcyBhcmUgaW4gcmFkaWFuc1xuXG5cdGNvbnN0IGNvcyA9IE1hdGguY29zO1xuXHRjb25zdCBzaW4gPSBNYXRoLnNpbjtcblxuXHRjb25zdCBjMiA9IGNvcyggYiAvIDIgKTtcblx0Y29uc3QgczIgPSBzaW4oIGIgLyAyICk7XG5cblx0Y29uc3QgYzEzID0gY29zKCAoIGEgKyBjICkgLyAyICk7XG5cdGNvbnN0IHMxMyA9IHNpbiggKCBhICsgYyApIC8gMiApO1xuXG5cdGNvbnN0IGMxXzMgPSBjb3MoICggYSAtIGMgKSAvIDIgKTtcblx0Y29uc3QgczFfMyA9IHNpbiggKCBhIC0gYyApIC8gMiApO1xuXG5cdGNvbnN0IGMzXzEgPSBjb3MoICggYyAtIGEgKSAvIDIgKTtcblx0Y29uc3QgczNfMSA9IHNpbiggKCBjIC0gYSApIC8gMiApO1xuXG5cdHN3aXRjaCAoIG9yZGVyICkge1xuXG5cdFx0Y2FzZSAnWFlYJzpcblx0XHRcdHEuc2V0KCBjMiAqIHMxMywgczIgKiBjMV8zLCBzMiAqIHMxXzMsIGMyICogYzEzICk7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgJ1laWSc6XG5cdFx0XHRxLnNldCggczIgKiBzMV8zLCBjMiAqIHMxMywgczIgKiBjMV8zLCBjMiAqIGMxMyApO1xuXHRcdFx0YnJlYWs7XG5cblx0XHRjYXNlICdaWFonOlxuXHRcdFx0cS5zZXQoIHMyICogYzFfMywgczIgKiBzMV8zLCBjMiAqIHMxMywgYzIgKiBjMTMgKTtcblx0XHRcdGJyZWFrO1xuXG5cdFx0Y2FzZSAnWFpYJzpcblx0XHRcdHEuc2V0KCBjMiAqIHMxMywgczIgKiBzM18xLCBzMiAqIGMzXzEsIGMyICogYzEzICk7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgJ1lYWSc6XG5cdFx0XHRxLnNldCggczIgKiBjM18xLCBjMiAqIHMxMywgczIgKiBzM18xLCBjMiAqIGMxMyApO1xuXHRcdFx0YnJlYWs7XG5cblx0XHRjYXNlICdaWVonOlxuXHRcdFx0cS5zZXQoIHMyICogczNfMSwgczIgKiBjM18xLCBjMiAqIHMxMywgYzIgKiBjMTMgKTtcblx0XHRcdGJyZWFrO1xuXG5cdFx0ZGVmYXVsdDpcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLk1hdGhVdGlsczogLnNldFF1YXRlcm5pb25Gcm9tUHJvcGVyRXVsZXIoKSBlbmNvdW50ZXJlZCBhbiB1bmtub3duIG9yZGVyOiAnICsgb3JkZXIgKTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gZGVub3JtYWxpemUoIHZhbHVlLCBhcnJheSApIHtcblxuXHRzd2l0Y2ggKCBhcnJheS5jb25zdHJ1Y3RvciApIHtcblxuXHRcdGNhc2UgRmxvYXQzMkFycmF5OlxuXG5cdFx0XHRyZXR1cm4gdmFsdWU7XG5cblx0XHRjYXNlIFVpbnQzMkFycmF5OlxuXG5cdFx0XHRyZXR1cm4gdmFsdWUgLyA0Mjk0OTY3Mjk1LjA7XG5cblx0XHRjYXNlIFVpbnQxNkFycmF5OlxuXG5cdFx0XHRyZXR1cm4gdmFsdWUgLyA2NTUzNS4wO1xuXG5cdFx0Y2FzZSBVaW50OEFycmF5OlxuXG5cdFx0XHRyZXR1cm4gdmFsdWUgLyAyNTUuMDtcblxuXHRcdGNhc2UgSW50MzJBcnJheTpcblxuXHRcdFx0cmV0dXJuIE1hdGgubWF4KCB2YWx1ZSAvIDIxNDc0ODM2NDcuMCwgLSAxLjAgKTtcblxuXHRcdGNhc2UgSW50MTZBcnJheTpcblxuXHRcdFx0cmV0dXJuIE1hdGgubWF4KCB2YWx1ZSAvIDMyNzY3LjAsIC0gMS4wICk7XG5cblx0XHRjYXNlIEludDhBcnJheTpcblxuXHRcdFx0cmV0dXJuIE1hdGgubWF4KCB2YWx1ZSAvIDEyNy4wLCAtIDEuMCApO1xuXG5cdFx0ZGVmYXVsdDpcblxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnSW52YWxpZCBjb21wb25lbnQgdHlwZS4nICk7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZSggdmFsdWUsIGFycmF5ICkge1xuXG5cdHN3aXRjaCAoIGFycmF5LmNvbnN0cnVjdG9yICkge1xuXG5cdFx0Y2FzZSBGbG9hdDMyQXJyYXk6XG5cblx0XHRcdHJldHVybiB2YWx1ZTtcblxuXHRcdGNhc2UgVWludDMyQXJyYXk6XG5cblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDQyOTQ5NjcyOTUuMCApO1xuXG5cdFx0Y2FzZSBVaW50MTZBcnJheTpcblxuXHRcdFx0cmV0dXJuIE1hdGgucm91bmQoIHZhbHVlICogNjU1MzUuMCApO1xuXG5cdFx0Y2FzZSBVaW50OEFycmF5OlxuXG5cdFx0XHRyZXR1cm4gTWF0aC5yb3VuZCggdmFsdWUgKiAyNTUuMCApO1xuXG5cdFx0Y2FzZSBJbnQzMkFycmF5OlxuXG5cdFx0XHRyZXR1cm4gTWF0aC5yb3VuZCggdmFsdWUgKiAyMTQ3NDgzNjQ3LjAgKTtcblxuXHRcdGNhc2UgSW50MTZBcnJheTpcblxuXHRcdFx0cmV0dXJuIE1hdGgucm91bmQoIHZhbHVlICogMzI3NjcuMCApO1xuXG5cdFx0Y2FzZSBJbnQ4QXJyYXk6XG5cblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDEyNy4wICk7XG5cblx0XHRkZWZhdWx0OlxuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdJbnZhbGlkIGNvbXBvbmVudCB0eXBlLicgKTtcblxuXHR9XG5cbn1cblxuY29uc3QgTWF0aFV0aWxzID0ge1xuXHRERUcyUkFEOiBERUcyUkFELFxuXHRSQUQyREVHOiBSQUQyREVHLFxuXHRnZW5lcmF0ZVVVSUQ6IGdlbmVyYXRlVVVJRCxcblx0Y2xhbXA6IGNsYW1wLFxuXHRldWNsaWRlYW5Nb2R1bG86IGV1Y2xpZGVhbk1vZHVsbyxcblx0bWFwTGluZWFyOiBtYXBMaW5lYXIsXG5cdGludmVyc2VMZXJwOiBpbnZlcnNlTGVycCxcblx0bGVycDogbGVycCxcblx0ZGFtcDogZGFtcCxcblx0cGluZ3Bvbmc6IHBpbmdwb25nLFxuXHRzbW9vdGhzdGVwOiBzbW9vdGhzdGVwLFxuXHRzbW9vdGhlcnN0ZXA6IHNtb290aGVyc3RlcCxcblx0cmFuZEludDogcmFuZEludCxcblx0cmFuZEZsb2F0OiByYW5kRmxvYXQsXG5cdHJhbmRGbG9hdFNwcmVhZDogcmFuZEZsb2F0U3ByZWFkLFxuXHRzZWVkZWRSYW5kb206IHNlZWRlZFJhbmRvbSxcblx0ZGVnVG9SYWQ6IGRlZ1RvUmFkLFxuXHRyYWRUb0RlZzogcmFkVG9EZWcsXG5cdGlzUG93ZXJPZlR3bzogaXNQb3dlck9mVHdvLFxuXHRjZWlsUG93ZXJPZlR3bzogY2VpbFBvd2VyT2ZUd28sXG5cdGZsb29yUG93ZXJPZlR3bzogZmxvb3JQb3dlck9mVHdvLFxuXHRzZXRRdWF0ZXJuaW9uRnJvbVByb3BlckV1bGVyOiBzZXRRdWF0ZXJuaW9uRnJvbVByb3BlckV1bGVyLFxuXHRub3JtYWxpemU6IG5vcm1hbGl6ZSxcblx0ZGVub3JtYWxpemU6IGRlbm9ybWFsaXplXG59O1xuXG5jbGFzcyBWZWN0b3IyIHtcblxuXHRjb25zdHJ1Y3RvciggeCA9IDAsIHkgPSAwICkge1xuXG5cdFx0VmVjdG9yMi5wcm90b3R5cGUuaXNWZWN0b3IyID0gdHJ1ZTtcblxuXHRcdHRoaXMueCA9IHg7XG5cdFx0dGhpcy55ID0geTtcblxuXHR9XG5cblx0Z2V0IHdpZHRoKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMueDtcblxuXHR9XG5cblx0c2V0IHdpZHRoKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMueCA9IHZhbHVlO1xuXG5cdH1cblxuXHRnZXQgaGVpZ2h0KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMueTtcblxuXHR9XG5cblx0c2V0IGhlaWdodCggdmFsdWUgKSB7XG5cblx0XHR0aGlzLnkgPSB2YWx1ZTtcblxuXHR9XG5cblx0c2V0KCB4LCB5ICkge1xuXG5cdFx0dGhpcy54ID0geDtcblx0XHR0aGlzLnkgPSB5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFNjYWxhciggc2NhbGFyICkge1xuXG5cdFx0dGhpcy54ID0gc2NhbGFyO1xuXHRcdHRoaXMueSA9IHNjYWxhcjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRYKCB4ICkge1xuXG5cdFx0dGhpcy54ID0geDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRZKCB5ICkge1xuXG5cdFx0dGhpcy55ID0geTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRDb21wb25lbnQoIGluZGV4LCB2YWx1ZSApIHtcblxuXHRcdHN3aXRjaCAoIGluZGV4ICkge1xuXG5cdFx0XHRjYXNlIDA6IHRoaXMueCA9IHZhbHVlOyBicmVhaztcblx0XHRcdGNhc2UgMTogdGhpcy55ID0gdmFsdWU7IGJyZWFrO1xuXHRcdFx0ZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKCAnaW5kZXggaXMgb3V0IG9mIHJhbmdlOiAnICsgaW5kZXggKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRDb21wb25lbnQoIGluZGV4ICkge1xuXG5cdFx0c3dpdGNoICggaW5kZXggKSB7XG5cblx0XHRcdGNhc2UgMDogcmV0dXJuIHRoaXMueDtcblx0XHRcdGNhc2UgMTogcmV0dXJuIHRoaXMueTtcblx0XHRcdGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvciggJ2luZGV4IGlzIG91dCBvZiByYW5nZTogJyArIGluZGV4ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCB0aGlzLngsIHRoaXMueSApO1xuXG5cdH1cblxuXHRjb3B5KCB2ICkge1xuXG5cdFx0dGhpcy54ID0gdi54O1xuXHRcdHRoaXMueSA9IHYueTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhZGQoIHYgKSB7XG5cblx0XHR0aGlzLnggKz0gdi54O1xuXHRcdHRoaXMueSArPSB2Lnk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkU2NhbGFyKCBzICkge1xuXG5cdFx0dGhpcy54ICs9IHM7XG5cdFx0dGhpcy55ICs9IHM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkVmVjdG9ycyggYSwgYiApIHtcblxuXHRcdHRoaXMueCA9IGEueCArIGIueDtcblx0XHR0aGlzLnkgPSBhLnkgKyBiLnk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkU2NhbGVkVmVjdG9yKCB2LCBzICkge1xuXG5cdFx0dGhpcy54ICs9IHYueCAqIHM7XG5cdFx0dGhpcy55ICs9IHYueSAqIHM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3ViKCB2ICkge1xuXG5cdFx0dGhpcy54IC09IHYueDtcblx0XHR0aGlzLnkgLT0gdi55O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN1YlNjYWxhciggcyApIHtcblxuXHRcdHRoaXMueCAtPSBzO1xuXHRcdHRoaXMueSAtPSBzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN1YlZlY3RvcnMoIGEsIGIgKSB7XG5cblx0XHR0aGlzLnggPSBhLnggLSBiLng7XG5cdFx0dGhpcy55ID0gYS55IC0gYi55O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5KCB2ICkge1xuXG5cdFx0dGhpcy54ICo9IHYueDtcblx0XHR0aGlzLnkgKj0gdi55O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5U2NhbGFyKCBzY2FsYXIgKSB7XG5cblx0XHR0aGlzLnggKj0gc2NhbGFyO1xuXHRcdHRoaXMueSAqPSBzY2FsYXI7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGl2aWRlKCB2ICkge1xuXG5cdFx0dGhpcy54IC89IHYueDtcblx0XHR0aGlzLnkgLz0gdi55O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRpdmlkZVNjYWxhciggc2NhbGFyICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubXVsdGlwbHlTY2FsYXIoIDEgLyBzY2FsYXIgKTtcblxuXHR9XG5cblx0YXBwbHlNYXRyaXgzKCBtICkge1xuXG5cdFx0Y29uc3QgeCA9IHRoaXMueCwgeSA9IHRoaXMueTtcblx0XHRjb25zdCBlID0gbS5lbGVtZW50cztcblxuXHRcdHRoaXMueCA9IGVbIDAgXSAqIHggKyBlWyAzIF0gKiB5ICsgZVsgNiBdO1xuXHRcdHRoaXMueSA9IGVbIDEgXSAqIHggKyBlWyA0IF0gKiB5ICsgZVsgNyBdO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1pbiggdiApIHtcblxuXHRcdHRoaXMueCA9IE1hdGgubWluKCB0aGlzLngsIHYueCApO1xuXHRcdHRoaXMueSA9IE1hdGgubWluKCB0aGlzLnksIHYueSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1heCggdiApIHtcblxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCB0aGlzLngsIHYueCApO1xuXHRcdHRoaXMueSA9IE1hdGgubWF4KCB0aGlzLnksIHYueSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsYW1wKCBtaW4sIG1heCApIHtcblxuXHRcdC8vIGFzc3VtZXMgbWluIDwgbWF4LCBjb21wb25lbnR3aXNlXG5cblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluLngsIE1hdGgubWluKCBtYXgueCwgdGhpcy54ICkgKTtcblx0XHR0aGlzLnkgPSBNYXRoLm1heCggbWluLnksIE1hdGgubWluKCBtYXgueSwgdGhpcy55ICkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbGFtcFNjYWxhciggbWluVmFsLCBtYXhWYWwgKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnggKSApO1xuXHRcdHRoaXMueSA9IE1hdGgubWF4KCBtaW5WYWwsIE1hdGgubWluKCBtYXhWYWwsIHRoaXMueSApICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xhbXBMZW5ndGgoIG1pbiwgbWF4ICkge1xuXG5cdFx0Y29uc3QgbGVuZ3RoID0gdGhpcy5sZW5ndGgoKTtcblxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggbGVuZ3RoIHx8IDEgKS5tdWx0aXBseVNjYWxhciggTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgbGVuZ3RoICkgKSApO1xuXG5cdH1cblxuXHRmbG9vcigpIHtcblxuXHRcdHRoaXMueCA9IE1hdGguZmxvb3IoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGguZmxvb3IoIHRoaXMueSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNlaWwoKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLmNlaWwoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGguY2VpbCggdGhpcy55ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cm91bmQoKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLnJvdW5kKCB0aGlzLnggKTtcblx0XHR0aGlzLnkgPSBNYXRoLnJvdW5kKCB0aGlzLnkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyb3VuZFRvWmVybygpIHtcblxuXHRcdHRoaXMueCA9IE1hdGgudHJ1bmMoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGgudHJ1bmMoIHRoaXMueSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG5lZ2F0ZSgpIHtcblxuXHRcdHRoaXMueCA9IC0gdGhpcy54O1xuXHRcdHRoaXMueSA9IC0gdGhpcy55O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRvdCggdiApIHtcblxuXHRcdHJldHVybiB0aGlzLnggKiB2LnggKyB0aGlzLnkgKiB2Lnk7XG5cblx0fVxuXG5cdGNyb3NzKCB2ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMueCAqIHYueSAtIHRoaXMueSAqIHYueDtcblxuXHR9XG5cblx0bGVuZ3RoU3EoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy54ICogdGhpcy54ICsgdGhpcy55ICogdGhpcy55O1xuXG5cdH1cblxuXHRsZW5ndGgoKSB7XG5cblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCB0aGlzLnggKiB0aGlzLnggKyB0aGlzLnkgKiB0aGlzLnkgKTtcblxuXHR9XG5cblx0bWFuaGF0dGFuTGVuZ3RoKCkge1xuXG5cdFx0cmV0dXJuIE1hdGguYWJzKCB0aGlzLnggKSArIE1hdGguYWJzKCB0aGlzLnkgKTtcblxuXHR9XG5cblx0bm9ybWFsaXplKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZGl2aWRlU2NhbGFyKCB0aGlzLmxlbmd0aCgpIHx8IDEgKTtcblxuXHR9XG5cblx0YW5nbGUoKSB7XG5cblx0XHQvLyBjb21wdXRlcyB0aGUgYW5nbGUgaW4gcmFkaWFucyB3aXRoIHJlc3BlY3QgdG8gdGhlIHBvc2l0aXZlIHgtYXhpc1xuXG5cdFx0Y29uc3QgYW5nbGUgPSBNYXRoLmF0YW4yKCAtIHRoaXMueSwgLSB0aGlzLnggKSArIE1hdGguUEk7XG5cblx0XHRyZXR1cm4gYW5nbGU7XG5cblx0fVxuXG5cdGFuZ2xlVG8oIHYgKSB7XG5cblx0XHRjb25zdCBkZW5vbWluYXRvciA9IE1hdGguc3FydCggdGhpcy5sZW5ndGhTcSgpICogdi5sZW5ndGhTcSgpICk7XG5cblx0XHRpZiAoIGRlbm9taW5hdG9yID09PSAwICkgcmV0dXJuIE1hdGguUEkgLyAyO1xuXG5cdFx0Y29uc3QgdGhldGEgPSB0aGlzLmRvdCggdiApIC8gZGVub21pbmF0b3I7XG5cblx0XHQvLyBjbGFtcCwgdG8gaGFuZGxlIG51bWVyaWNhbCBwcm9ibGVtc1xuXG5cdFx0cmV0dXJuIE1hdGguYWNvcyggY2xhbXAoIHRoZXRhLCAtIDEsIDEgKSApO1xuXG5cdH1cblxuXHRkaXN0YW5jZVRvKCB2ICkge1xuXG5cdFx0cmV0dXJuIE1hdGguc3FydCggdGhpcy5kaXN0YW5jZVRvU3F1YXJlZCggdiApICk7XG5cblx0fVxuXG5cdGRpc3RhbmNlVG9TcXVhcmVkKCB2ICkge1xuXG5cdFx0Y29uc3QgZHggPSB0aGlzLnggLSB2LngsIGR5ID0gdGhpcy55IC0gdi55O1xuXHRcdHJldHVybiBkeCAqIGR4ICsgZHkgKiBkeTtcblxuXHR9XG5cblx0bWFuaGF0dGFuRGlzdGFuY2VUbyggdiApIHtcblxuXHRcdHJldHVybiBNYXRoLmFicyggdGhpcy54IC0gdi54ICkgKyBNYXRoLmFicyggdGhpcy55IC0gdi55ICk7XG5cblx0fVxuXG5cdHNldExlbmd0aCggbGVuZ3RoICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubm9ybWFsaXplKCkubXVsdGlwbHlTY2FsYXIoIGxlbmd0aCApO1xuXG5cdH1cblxuXHRsZXJwKCB2LCBhbHBoYSApIHtcblxuXHRcdHRoaXMueCArPSAoIHYueCAtIHRoaXMueCApICogYWxwaGE7XG5cdFx0dGhpcy55ICs9ICggdi55IC0gdGhpcy55ICkgKiBhbHBoYTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRsZXJwVmVjdG9ycyggdjEsIHYyLCBhbHBoYSApIHtcblxuXHRcdHRoaXMueCA9IHYxLnggKyAoIHYyLnggLSB2MS54ICkgKiBhbHBoYTtcblx0XHR0aGlzLnkgPSB2MS55ICsgKCB2Mi55IC0gdjEueSApICogYWxwaGE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXF1YWxzKCB2ICkge1xuXG5cdFx0cmV0dXJuICggKCB2LnggPT09IHRoaXMueCApICYmICggdi55ID09PSB0aGlzLnkgKSApO1xuXG5cdH1cblxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xuXG5cdFx0dGhpcy54ID0gYXJyYXlbIG9mZnNldCBdO1xuXHRcdHRoaXMueSA9IGFycmF5WyBvZmZzZXQgKyAxIF07XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdGFycmF5WyBvZmZzZXQgXSA9IHRoaXMueDtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy55O1xuXG5cdFx0cmV0dXJuIGFycmF5O1xuXG5cdH1cblxuXHRmcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGluZGV4ICkge1xuXG5cdFx0dGhpcy54ID0gYXR0cmlidXRlLmdldFgoIGluZGV4ICk7XG5cdFx0dGhpcy55ID0gYXR0cmlidXRlLmdldFkoIGluZGV4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cm90YXRlQXJvdW5kKCBjZW50ZXIsIGFuZ2xlICkge1xuXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCBhbmdsZSApLCBzID0gTWF0aC5zaW4oIGFuZ2xlICk7XG5cblx0XHRjb25zdCB4ID0gdGhpcy54IC0gY2VudGVyLng7XG5cdFx0Y29uc3QgeSA9IHRoaXMueSAtIGNlbnRlci55O1xuXG5cdFx0dGhpcy54ID0geCAqIGMgLSB5ICogcyArIGNlbnRlci54O1xuXHRcdHRoaXMueSA9IHggKiBzICsgeSAqIGMgKyBjZW50ZXIueTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyYW5kb20oKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLnJhbmRvbSgpO1xuXHRcdHRoaXMueSA9IE1hdGgucmFuZG9tKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0KlsgU3ltYm9sLml0ZXJhdG9yIF0oKSB7XG5cblx0XHR5aWVsZCB0aGlzLng7XG5cdFx0eWllbGQgdGhpcy55O1xuXG5cdH1cblxufVxuXG5jbGFzcyBNYXRyaXgzIHtcblxuXHRjb25zdHJ1Y3RvciggbjExLCBuMTIsIG4xMywgbjIxLCBuMjIsIG4yMywgbjMxLCBuMzIsIG4zMyApIHtcblxuXHRcdE1hdHJpeDMucHJvdG90eXBlLmlzTWF0cml4MyA9IHRydWU7XG5cblx0XHR0aGlzLmVsZW1lbnRzID0gW1xuXG5cdFx0XHQxLCAwLCAwLFxuXHRcdFx0MCwgMSwgMCxcblx0XHRcdDAsIDAsIDFcblxuXHRcdF07XG5cblx0XHRpZiAoIG4xMSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLnNldCggbjExLCBuMTIsIG4xMywgbjIxLCBuMjIsIG4yMywgbjMxLCBuMzIsIG4zMyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRzZXQoIG4xMSwgbjEyLCBuMTMsIG4yMSwgbjIyLCBuMjMsIG4zMSwgbjMyLCBuMzMgKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cblx0XHR0ZVsgMCBdID0gbjExOyB0ZVsgMSBdID0gbjIxOyB0ZVsgMiBdID0gbjMxO1xuXHRcdHRlWyAzIF0gPSBuMTI7IHRlWyA0IF0gPSBuMjI7IHRlWyA1IF0gPSBuMzI7XG5cdFx0dGVbIDYgXSA9IG4xMzsgdGVbIDcgXSA9IG4yMzsgdGVbIDggXSA9IG4zMztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRpZGVudGl0eSgpIHtcblxuXHRcdHRoaXMuc2V0KFxuXG5cdFx0XHQxLCAwLCAwLFxuXHRcdFx0MCwgMSwgMCxcblx0XHRcdDAsIDAsIDFcblxuXHRcdCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weSggbSApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblx0XHRjb25zdCBtZSA9IG0uZWxlbWVudHM7XG5cblx0XHR0ZVsgMCBdID0gbWVbIDAgXTsgdGVbIDEgXSA9IG1lWyAxIF07IHRlWyAyIF0gPSBtZVsgMiBdO1xuXHRcdHRlWyAzIF0gPSBtZVsgMyBdOyB0ZVsgNCBdID0gbWVbIDQgXTsgdGVbIDUgXSA9IG1lWyA1IF07XG5cdFx0dGVbIDYgXSA9IG1lWyA2IF07IHRlWyA3IF0gPSBtZVsgNyBdOyB0ZVsgOCBdID0gbWVbIDggXTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRleHRyYWN0QmFzaXMoIHhBeGlzLCB5QXhpcywgekF4aXMgKSB7XG5cblx0XHR4QXhpcy5zZXRGcm9tTWF0cml4M0NvbHVtbiggdGhpcywgMCApO1xuXHRcdHlBeGlzLnNldEZyb21NYXRyaXgzQ29sdW1uKCB0aGlzLCAxICk7XG5cdFx0ekF4aXMuc2V0RnJvbU1hdHJpeDNDb2x1bW4oIHRoaXMsIDIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tTWF0cml4NCggbSApIHtcblxuXHRcdGNvbnN0IG1lID0gbS5lbGVtZW50cztcblxuXHRcdHRoaXMuc2V0KFxuXG5cdFx0XHRtZVsgMCBdLCBtZVsgNCBdLCBtZVsgOCBdLFxuXHRcdFx0bWVbIDEgXSwgbWVbIDUgXSwgbWVbIDkgXSxcblx0XHRcdG1lWyAyIF0sIG1lWyA2IF0sIG1lWyAxMCBdXG5cblx0XHQpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5KCBtICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubXVsdGlwbHlNYXRyaWNlcyggdGhpcywgbSApO1xuXG5cdH1cblxuXHRwcmVtdWx0aXBseSggbSApIHtcblxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5TWF0cmljZXMoIG0sIHRoaXMgKTtcblxuXHR9XG5cblx0bXVsdGlwbHlNYXRyaWNlcyggYSwgYiApIHtcblxuXHRcdGNvbnN0IGFlID0gYS5lbGVtZW50cztcblx0XHRjb25zdCBiZSA9IGIuZWxlbWVudHM7XG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0Y29uc3QgYTExID0gYWVbIDAgXSwgYTEyID0gYWVbIDMgXSwgYTEzID0gYWVbIDYgXTtcblx0XHRjb25zdCBhMjEgPSBhZVsgMSBdLCBhMjIgPSBhZVsgNCBdLCBhMjMgPSBhZVsgNyBdO1xuXHRcdGNvbnN0IGEzMSA9IGFlWyAyIF0sIGEzMiA9IGFlWyA1IF0sIGEzMyA9IGFlWyA4IF07XG5cblx0XHRjb25zdCBiMTEgPSBiZVsgMCBdLCBiMTIgPSBiZVsgMyBdLCBiMTMgPSBiZVsgNiBdO1xuXHRcdGNvbnN0IGIyMSA9IGJlWyAxIF0sIGIyMiA9IGJlWyA0IF0sIGIyMyA9IGJlWyA3IF07XG5cdFx0Y29uc3QgYjMxID0gYmVbIDIgXSwgYjMyID0gYmVbIDUgXSwgYjMzID0gYmVbIDggXTtcblxuXHRcdHRlWyAwIF0gPSBhMTEgKiBiMTEgKyBhMTIgKiBiMjEgKyBhMTMgKiBiMzE7XG5cdFx0dGVbIDMgXSA9IGExMSAqIGIxMiArIGExMiAqIGIyMiArIGExMyAqIGIzMjtcblx0XHR0ZVsgNiBdID0gYTExICogYjEzICsgYTEyICogYjIzICsgYTEzICogYjMzO1xuXG5cdFx0dGVbIDEgXSA9IGEyMSAqIGIxMSArIGEyMiAqIGIyMSArIGEyMyAqIGIzMTtcblx0XHR0ZVsgNCBdID0gYTIxICogYjEyICsgYTIyICogYjIyICsgYTIzICogYjMyO1xuXHRcdHRlWyA3IF0gPSBhMjEgKiBiMTMgKyBhMjIgKiBiMjMgKyBhMjMgKiBiMzM7XG5cblx0XHR0ZVsgMiBdID0gYTMxICogYjExICsgYTMyICogYjIxICsgYTMzICogYjMxO1xuXHRcdHRlWyA1IF0gPSBhMzEgKiBiMTIgKyBhMzIgKiBiMjIgKyBhMzMgKiBiMzI7XG5cdFx0dGVbIDggXSA9IGEzMSAqIGIxMyArIGEzMiAqIGIyMyArIGEzMyAqIGIzMztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtdWx0aXBseVNjYWxhciggcyApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdHRlWyAwIF0gKj0gczsgdGVbIDMgXSAqPSBzOyB0ZVsgNiBdICo9IHM7XG5cdFx0dGVbIDEgXSAqPSBzOyB0ZVsgNCBdICo9IHM7IHRlWyA3IF0gKj0gcztcblx0XHR0ZVsgMiBdICo9IHM7IHRlWyA1IF0gKj0gczsgdGVbIDggXSAqPSBzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRldGVybWluYW50KCkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0Y29uc3QgYSA9IHRlWyAwIF0sIGIgPSB0ZVsgMSBdLCBjID0gdGVbIDIgXSxcblx0XHRcdGQgPSB0ZVsgMyBdLCBlID0gdGVbIDQgXSwgZiA9IHRlWyA1IF0sXG5cdFx0XHRnID0gdGVbIDYgXSwgaCA9IHRlWyA3IF0sIGkgPSB0ZVsgOCBdO1xuXG5cdFx0cmV0dXJuIGEgKiBlICogaSAtIGEgKiBmICogaCAtIGIgKiBkICogaSArIGIgKiBmICogZyArIGMgKiBkICogaCAtIGMgKiBlICogZztcblxuXHR9XG5cblx0aW52ZXJ0KCkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzLFxuXG5cdFx0XHRuMTEgPSB0ZVsgMCBdLCBuMjEgPSB0ZVsgMSBdLCBuMzEgPSB0ZVsgMiBdLFxuXHRcdFx0bjEyID0gdGVbIDMgXSwgbjIyID0gdGVbIDQgXSwgbjMyID0gdGVbIDUgXSxcblx0XHRcdG4xMyA9IHRlWyA2IF0sIG4yMyA9IHRlWyA3IF0sIG4zMyA9IHRlWyA4IF0sXG5cblx0XHRcdHQxMSA9IG4zMyAqIG4yMiAtIG4zMiAqIG4yMyxcblx0XHRcdHQxMiA9IG4zMiAqIG4xMyAtIG4zMyAqIG4xMixcblx0XHRcdHQxMyA9IG4yMyAqIG4xMiAtIG4yMiAqIG4xMyxcblxuXHRcdFx0ZGV0ID0gbjExICogdDExICsgbjIxICogdDEyICsgbjMxICogdDEzO1xuXG5cdFx0aWYgKCBkZXQgPT09IDAgKSByZXR1cm4gdGhpcy5zZXQoIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAgKTtcblxuXHRcdGNvbnN0IGRldEludiA9IDEgLyBkZXQ7XG5cblx0XHR0ZVsgMCBdID0gdDExICogZGV0SW52O1xuXHRcdHRlWyAxIF0gPSAoIG4zMSAqIG4yMyAtIG4zMyAqIG4yMSApICogZGV0SW52O1xuXHRcdHRlWyAyIF0gPSAoIG4zMiAqIG4yMSAtIG4zMSAqIG4yMiApICogZGV0SW52O1xuXG5cdFx0dGVbIDMgXSA9IHQxMiAqIGRldEludjtcblx0XHR0ZVsgNCBdID0gKCBuMzMgKiBuMTEgLSBuMzEgKiBuMTMgKSAqIGRldEludjtcblx0XHR0ZVsgNSBdID0gKCBuMzEgKiBuMTIgLSBuMzIgKiBuMTEgKSAqIGRldEludjtcblxuXHRcdHRlWyA2IF0gPSB0MTMgKiBkZXRJbnY7XG5cdFx0dGVbIDcgXSA9ICggbjIxICogbjEzIC0gbjIzICogbjExICkgKiBkZXRJbnY7XG5cdFx0dGVbIDggXSA9ICggbjIyICogbjExIC0gbjIxICogbjEyICkgKiBkZXRJbnY7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJhbnNwb3NlKCkge1xuXG5cdFx0bGV0IHRtcDtcblx0XHRjb25zdCBtID0gdGhpcy5lbGVtZW50cztcblxuXHRcdHRtcCA9IG1bIDEgXTsgbVsgMSBdID0gbVsgMyBdOyBtWyAzIF0gPSB0bXA7XG5cdFx0dG1wID0gbVsgMiBdOyBtWyAyIF0gPSBtWyA2IF07IG1bIDYgXSA9IHRtcDtcblx0XHR0bXAgPSBtWyA1IF07IG1bIDUgXSA9IG1bIDcgXTsgbVsgNyBdID0gdG1wO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldE5vcm1hbE1hdHJpeCggbWF0cml4NCApIHtcblxuXHRcdHJldHVybiB0aGlzLnNldEZyb21NYXRyaXg0KCBtYXRyaXg0ICkuaW52ZXJ0KCkudHJhbnNwb3NlKCk7XG5cblx0fVxuXG5cdHRyYW5zcG9zZUludG9BcnJheSggciApIHtcblxuXHRcdGNvbnN0IG0gPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0clsgMCBdID0gbVsgMCBdO1xuXHRcdHJbIDEgXSA9IG1bIDMgXTtcblx0XHRyWyAyIF0gPSBtWyA2IF07XG5cdFx0clsgMyBdID0gbVsgMSBdO1xuXHRcdHJbIDQgXSA9IG1bIDQgXTtcblx0XHRyWyA1IF0gPSBtWyA3IF07XG5cdFx0clsgNiBdID0gbVsgMiBdO1xuXHRcdHJbIDcgXSA9IG1bIDUgXTtcblx0XHRyWyA4IF0gPSBtWyA4IF07XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0VXZUcmFuc2Zvcm0oIHR4LCB0eSwgc3gsIHN5LCByb3RhdGlvbiwgY3gsIGN5ICkge1xuXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCByb3RhdGlvbiApO1xuXHRcdGNvbnN0IHMgPSBNYXRoLnNpbiggcm90YXRpb24gKTtcblxuXHRcdHRoaXMuc2V0KFxuXHRcdFx0c3ggKiBjLCBzeCAqIHMsIC0gc3ggKiAoIGMgKiBjeCArIHMgKiBjeSApICsgY3ggKyB0eCxcblx0XHRcdC0gc3kgKiBzLCBzeSAqIGMsIC0gc3kgKiAoIC0gcyAqIGN4ICsgYyAqIGN5ICkgKyBjeSArIHR5LFxuXHRcdFx0MCwgMCwgMVxuXHRcdCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Ly9cblxuXHRzY2FsZSggc3gsIHN5ICkge1xuXG5cdFx0dGhpcy5wcmVtdWx0aXBseSggX20zLm1ha2VTY2FsZSggc3gsIHN5ICkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyb3RhdGUoIHRoZXRhICkge1xuXG5cdFx0dGhpcy5wcmVtdWx0aXBseSggX20zLm1ha2VSb3RhdGlvbiggLSB0aGV0YSApICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJhbnNsYXRlKCB0eCwgdHkgKSB7XG5cblx0XHR0aGlzLnByZW11bHRpcGx5KCBfbTMubWFrZVRyYW5zbGF0aW9uKCB0eCwgdHkgKSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIGZvciAyRCBUcmFuc2Zvcm1zXG5cblx0bWFrZVRyYW5zbGF0aW9uKCB4LCB5ICkge1xuXG5cdFx0aWYgKCB4LmlzVmVjdG9yMiApIHtcblxuXHRcdFx0dGhpcy5zZXQoXG5cblx0XHRcdFx0MSwgMCwgeC54LFxuXHRcdFx0XHQwLCAxLCB4LnksXG5cdFx0XHRcdDAsIDAsIDFcblxuXHRcdFx0KTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuc2V0KFxuXG5cdFx0XHRcdDEsIDAsIHgsXG5cdFx0XHRcdDAsIDEsIHksXG5cdFx0XHRcdDAsIDAsIDFcblxuXHRcdFx0KTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlUm90YXRpb24oIHRoZXRhICkge1xuXG5cdFx0Ly8gY291bnRlcmNsb2Nrd2lzZVxuXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCB0aGV0YSApO1xuXHRcdGNvbnN0IHMgPSBNYXRoLnNpbiggdGhldGEgKTtcblxuXHRcdHRoaXMuc2V0KFxuXG5cdFx0XHRjLCAtIHMsIDAsXG5cdFx0XHRzLCBjLCAwLFxuXHRcdFx0MCwgMCwgMVxuXG5cdFx0KTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlU2NhbGUoIHgsIHkgKSB7XG5cblx0XHR0aGlzLnNldChcblxuXHRcdFx0eCwgMCwgMCxcblx0XHRcdDAsIHksIDAsXG5cdFx0XHQwLCAwLCAxXG5cblx0XHQpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vXG5cblx0ZXF1YWxzKCBtYXRyaXggKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cdFx0Y29uc3QgbWUgPSBtYXRyaXguZWxlbWVudHM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xuXG5cdFx0XHRpZiAoIHRlWyBpIF0gIT09IG1lWyBpIF0gKSByZXR1cm4gZmFsc2U7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9XG5cblx0ZnJvbUFycmF5KCBhcnJheSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuZWxlbWVudHNbIGkgXSA9IGFycmF5WyBpICsgb2Zmc2V0IF07XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdGFycmF5WyBvZmZzZXQgXSA9IHRlWyAwIF07XG5cdFx0YXJyYXlbIG9mZnNldCArIDEgXSA9IHRlWyAxIF07XG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRlWyAyIF07XG5cblx0XHRhcnJheVsgb2Zmc2V0ICsgMyBdID0gdGVbIDMgXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgNCBdID0gdGVbIDQgXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgNSBdID0gdGVbIDUgXTtcblxuXHRcdGFycmF5WyBvZmZzZXQgKyA2IF0gPSB0ZVsgNiBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyA3IF0gPSB0ZVsgNyBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyA4IF0gPSB0ZVsgOCBdO1xuXG5cdFx0cmV0dXJuIGFycmF5O1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmZyb21BcnJheSggdGhpcy5lbGVtZW50cyApO1xuXG5cdH1cblxufVxuXG5jb25zdCBfbTMgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCk7XG5cbmZ1bmN0aW9uIGFycmF5TmVlZHNVaW50MzIoIGFycmF5ICkge1xuXG5cdC8vIGFzc3VtZXMgbGFyZ2VyIHZhbHVlcyB1c3VhbGx5IG9uIGxhc3RcblxuXHRmb3IgKCBsZXQgaSA9IGFycmF5Lmxlbmd0aCAtIDE7IGkgPj0gMDsgLS0gaSApIHtcblxuXHRcdGlmICggYXJyYXlbIGkgXSA+PSA2NTUzNSApIHJldHVybiB0cnVlOyAvLyBhY2NvdW50IGZvciBQUklNSVRJVkVfUkVTVEFSVF9GSVhFRF9JTkRFWCwgIzI0NTY1XG5cblx0fVxuXG5cdHJldHVybiBmYWxzZTtcblxufVxuXG5jb25zdCBUWVBFRF9BUlJBWVMgPSB7XG5cdEludDhBcnJheTogSW50OEFycmF5LFxuXHRVaW50OEFycmF5OiBVaW50OEFycmF5LFxuXHRVaW50OENsYW1wZWRBcnJheTogVWludDhDbGFtcGVkQXJyYXksXG5cdEludDE2QXJyYXk6IEludDE2QXJyYXksXG5cdFVpbnQxNkFycmF5OiBVaW50MTZBcnJheSxcblx0SW50MzJBcnJheTogSW50MzJBcnJheSxcblx0VWludDMyQXJyYXk6IFVpbnQzMkFycmF5LFxuXHRGbG9hdDMyQXJyYXk6IEZsb2F0MzJBcnJheSxcblx0RmxvYXQ2NEFycmF5OiBGbG9hdDY0QXJyYXlcbn07XG5cbmZ1bmN0aW9uIGdldFR5cGVkQXJyYXkoIHR5cGUsIGJ1ZmZlciApIHtcblxuXHRyZXR1cm4gbmV3IFRZUEVEX0FSUkFZU1sgdHlwZSBdKCBidWZmZXIgKTtcblxufVxuXG5mdW5jdGlvbiBjcmVhdGVFbGVtZW50TlMoIG5hbWUgKSB7XG5cblx0cmV0dXJuIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyggJ2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwnLCBuYW1lICk7XG5cbn1cblxuZnVuY3Rpb24gY3JlYXRlQ2FudmFzRWxlbWVudCgpIHtcblxuXHRjb25zdCBjYW52YXMgPSBjcmVhdGVFbGVtZW50TlMoICdjYW52YXMnICk7XG5cdGNhbnZhcy5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblx0cmV0dXJuIGNhbnZhcztcblxufVxuXG5jb25zdCBfY2FjaGUgPSB7fTtcblxuZnVuY3Rpb24gd2Fybk9uY2UoIG1lc3NhZ2UgKSB7XG5cblx0aWYgKCBtZXNzYWdlIGluIF9jYWNoZSApIHJldHVybjtcblxuXHRfY2FjaGVbIG1lc3NhZ2UgXSA9IHRydWU7XG5cblx0Y29uc29sZS53YXJuKCBtZXNzYWdlICk7XG5cbn1cblxuZnVuY3Rpb24gcHJvYmVBc3luYyggZ2wsIHN5bmMsIGludGVydmFsICkge1xuXG5cdHJldHVybiBuZXcgUHJvbWlzZSggZnVuY3Rpb24gKCByZXNvbHZlLCByZWplY3QgKSB7XG5cblx0XHRmdW5jdGlvbiBwcm9iZSgpIHtcblxuXHRcdFx0c3dpdGNoICggZ2wuY2xpZW50V2FpdFN5bmMoIHN5bmMsIGdsLlNZTkNfRkxVU0hfQ09NTUFORFNfQklULCAwICkgKSB7XG5cblx0XHRcdFx0Y2FzZSBnbC5XQUlUX0ZBSUxFRDpcblx0XHRcdFx0XHRyZWplY3QoKTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlIGdsLlRJTUVPVVRfRVhQSVJFRDpcblx0XHRcdFx0XHRzZXRUaW1lb3V0KCBwcm9iZSwgaW50ZXJ2YWwgKTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdHJlc29sdmUoKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0c2V0VGltZW91dCggcHJvYmUsIGludGVydmFsICk7XG5cblx0fSApO1xuXG59XG5cbi8qKlxuICogTWF0cmljZXMgY29udmVydGluZyBQMyA8LT4gUmVjLiA3MDkgcHJpbWFyaWVzLCB3aXRob3V0IGdhbXV0IG1hcHBpbmdcbiAqIG9yIGNsaXBwaW5nLiBCYXNlZCBvbiBXM0Mgc3BlY2lmaWNhdGlvbnMgZm9yIHNSR0IgYW5kIERpc3BsYXkgUDMsXG4gKiBhbmQgSUNDIHNwZWNpZmljYXRpb25zIGZvciB0aGUgRDUwIGNvbm5lY3Rpb24gc3BhY2UuIFZhbHVlcyBpbi9vdXRcbiAqIGFyZSBfbGluZWFyXyBzUkdCIGFuZCBfbGluZWFyXyBEaXNwbGF5IFAzLlxuICpcbiAqIE5vdGUgdGhhdCBib3RoIHNSR0IgYW5kIERpc3BsYXkgUDMgdXNlIHRoZSBzUkdCIHRyYW5zZmVyIGZ1bmN0aW9ucy5cbiAqXG4gKiBSZWZlcmVuY2U6XG4gKiAtIGh0dHA6Ly93d3cucnVzc2VsbGNvdHRyZWxsLmNvbS9waG90by9tYXRyaXhDYWxjdWxhdG9yLmh0bVxuICovXG5cbmNvbnN0IExJTkVBUl9TUkdCX1RPX0xJTkVBUl9ESVNQTEFZX1AzID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpLnNldChcblx0MC44MjI0NjIxLCAwLjE3NzUzOCwgMC4wLFxuXHQwLjAzMzE5NDEsIDAuOTY2ODA1OCwgMC4wLFxuXHQwLjAxNzA4MjcsIDAuMDcyMzk3NCwgMC45MTA1MTk5LFxuKTtcblxuY29uc3QgTElORUFSX0RJU1BMQVlfUDNfVE9fTElORUFSX1NSR0IgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkuc2V0KFxuXHQxLjIyNDk0MDEsIC0gMC4yMjQ5NDA0LCAwLjAsXG5cdC0gMC4wNDIwNTY5LCAxLjA0MjA1NzEsIDAuMCxcblx0LSAwLjAxOTYzNzYsIC0gMC4wNzg2MzYxLCAxLjA5ODI3MzVcbik7XG5cbi8qKlxuICogRGVmaW5lcyBzdXBwb3J0ZWQgY29sb3Igc3BhY2VzIGJ5IHRyYW5zZmVyIGZ1bmN0aW9uIGFuZCBwcmltYXJpZXMsXG4gKiBhbmQgcHJvdmlkZXMgY29udmVyc2lvbnMgdG8vZnJvbSB0aGUgTGluZWFyLXNSR0IgcmVmZXJlbmNlIHNwYWNlLlxuICovXG5jb25zdCBDT0xPUl9TUEFDRVMgPSB7XG5cdFsgTGluZWFyU1JHQkNvbG9yU3BhY2UgXToge1xuXHRcdHRyYW5zZmVyOiBMaW5lYXJUcmFuc2Zlcixcblx0XHRwcmltYXJpZXM6IFJlYzcwOVByaW1hcmllcyxcblx0XHR0b1JlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLFxuXHRcdGZyb21SZWZlcmVuY2U6ICggY29sb3IgKSA9PiBjb2xvcixcblx0fSxcblx0WyBTUkdCQ29sb3JTcGFjZSBdOiB7XG5cdFx0dHJhbnNmZXI6IFNSR0JUcmFuc2Zlcixcblx0XHRwcmltYXJpZXM6IFJlYzcwOVByaW1hcmllcyxcblx0XHR0b1JlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLmNvbnZlcnRTUkdCVG9MaW5lYXIoKSxcblx0XHRmcm9tUmVmZXJlbmNlOiAoIGNvbG9yICkgPT4gY29sb3IuY29udmVydExpbmVhclRvU1JHQigpLFxuXHR9LFxuXHRbIExpbmVhckRpc3BsYXlQM0NvbG9yU3BhY2UgXToge1xuXHRcdHRyYW5zZmVyOiBMaW5lYXJUcmFuc2Zlcixcblx0XHRwcmltYXJpZXM6IFAzUHJpbWFyaWVzLFxuXHRcdHRvUmVmZXJlbmNlOiAoIGNvbG9yICkgPT4gY29sb3IuYXBwbHlNYXRyaXgzKCBMSU5FQVJfRElTUExBWV9QM19UT19MSU5FQVJfU1JHQiApLFxuXHRcdGZyb21SZWZlcmVuY2U6ICggY29sb3IgKSA9PiBjb2xvci5hcHBseU1hdHJpeDMoIExJTkVBUl9TUkdCX1RPX0xJTkVBUl9ESVNQTEFZX1AzICksXG5cdH0sXG5cdFsgRGlzcGxheVAzQ29sb3JTcGFjZSBdOiB7XG5cdFx0dHJhbnNmZXI6IFNSR0JUcmFuc2Zlcixcblx0XHRwcmltYXJpZXM6IFAzUHJpbWFyaWVzLFxuXHRcdHRvUmVmZXJlbmNlOiAoIGNvbG9yICkgPT4gY29sb3IuY29udmVydFNSR0JUb0xpbmVhcigpLmFwcGx5TWF0cml4MyggTElORUFSX0RJU1BMQVlfUDNfVE9fTElORUFSX1NSR0IgKSxcblx0XHRmcm9tUmVmZXJlbmNlOiAoIGNvbG9yICkgPT4gY29sb3IuYXBwbHlNYXRyaXgzKCBMSU5FQVJfU1JHQl9UT19MSU5FQVJfRElTUExBWV9QMyApLmNvbnZlcnRMaW5lYXJUb1NSR0IoKSxcblx0fSxcbn07XG5cbmNvbnN0IFNVUFBPUlRFRF9XT1JLSU5HX0NPTE9SX1NQQUNFUyA9IG5ldyBTZXQoIFsgTGluZWFyU1JHQkNvbG9yU3BhY2UsIExpbmVhckRpc3BsYXlQM0NvbG9yU3BhY2UgXSApO1xuXG5jb25zdCBDb2xvck1hbmFnZW1lbnQgPSB7XG5cblx0ZW5hYmxlZDogdHJ1ZSxcblxuXHRfd29ya2luZ0NvbG9yU3BhY2U6IExpbmVhclNSR0JDb2xvclNwYWNlLFxuXG5cdGdldCB3b3JraW5nQ29sb3JTcGFjZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLl93b3JraW5nQ29sb3JTcGFjZTtcblxuXHR9LFxuXG5cdHNldCB3b3JraW5nQ29sb3JTcGFjZSggY29sb3JTcGFjZSApIHtcblxuXHRcdGlmICggISBTVVBQT1JURURfV09SS0lOR19DT0xPUl9TUEFDRVMuaGFzKCBjb2xvclNwYWNlICkgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggYFVuc3VwcG9ydGVkIHdvcmtpbmcgY29sb3Igc3BhY2UsIFwiJHsgY29sb3JTcGFjZSB9XCIuYCApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5fd29ya2luZ0NvbG9yU3BhY2UgPSBjb2xvclNwYWNlO1xuXG5cdH0sXG5cblx0Y29udmVydDogZnVuY3Rpb24gKCBjb2xvciwgc291cmNlQ29sb3JTcGFjZSwgdGFyZ2V0Q29sb3JTcGFjZSApIHtcblxuXHRcdGlmICggdGhpcy5lbmFibGVkID09PSBmYWxzZSB8fCBzb3VyY2VDb2xvclNwYWNlID09PSB0YXJnZXRDb2xvclNwYWNlIHx8ICEgc291cmNlQ29sb3JTcGFjZSB8fCAhIHRhcmdldENvbG9yU3BhY2UgKSB7XG5cblx0XHRcdHJldHVybiBjb2xvcjtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHNvdXJjZVRvUmVmZXJlbmNlID0gQ09MT1JfU1BBQ0VTWyBzb3VyY2VDb2xvclNwYWNlIF0udG9SZWZlcmVuY2U7XG5cdFx0Y29uc3QgdGFyZ2V0RnJvbVJlZmVyZW5jZSA9IENPTE9SX1NQQUNFU1sgdGFyZ2V0Q29sb3JTcGFjZSBdLmZyb21SZWZlcmVuY2U7XG5cblx0XHRyZXR1cm4gdGFyZ2V0RnJvbVJlZmVyZW5jZSggc291cmNlVG9SZWZlcmVuY2UoIGNvbG9yICkgKTtcblxuXHR9LFxuXG5cdGZyb21Xb3JraW5nQ29sb3JTcGFjZTogZnVuY3Rpb24gKCBjb2xvciwgdGFyZ2V0Q29sb3JTcGFjZSApIHtcblxuXHRcdHJldHVybiB0aGlzLmNvbnZlcnQoIGNvbG9yLCB0aGlzLl93b3JraW5nQ29sb3JTcGFjZSwgdGFyZ2V0Q29sb3JTcGFjZSApO1xuXG5cdH0sXG5cblx0dG9Xb3JraW5nQ29sb3JTcGFjZTogZnVuY3Rpb24gKCBjb2xvciwgc291cmNlQ29sb3JTcGFjZSApIHtcblxuXHRcdHJldHVybiB0aGlzLmNvbnZlcnQoIGNvbG9yLCBzb3VyY2VDb2xvclNwYWNlLCB0aGlzLl93b3JraW5nQ29sb3JTcGFjZSApO1xuXG5cdH0sXG5cblx0Z2V0UHJpbWFyaWVzOiBmdW5jdGlvbiAoIGNvbG9yU3BhY2UgKSB7XG5cblx0XHRyZXR1cm4gQ09MT1JfU1BBQ0VTWyBjb2xvclNwYWNlIF0ucHJpbWFyaWVzO1xuXG5cdH0sXG5cblx0Z2V0VHJhbnNmZXI6IGZ1bmN0aW9uICggY29sb3JTcGFjZSApIHtcblxuXHRcdGlmICggY29sb3JTcGFjZSA9PT0gTm9Db2xvclNwYWNlICkgcmV0dXJuIExpbmVhclRyYW5zZmVyO1xuXG5cdFx0cmV0dXJuIENPTE9SX1NQQUNFU1sgY29sb3JTcGFjZSBdLnRyYW5zZmVyO1xuXG5cdH0sXG5cbn07XG5cblxuZnVuY3Rpb24gU1JHQlRvTGluZWFyKCBjICkge1xuXG5cdHJldHVybiAoIGMgPCAwLjA0MDQ1ICkgPyBjICogMC4wNzczOTkzODA4IDogTWF0aC5wb3coIGMgKiAwLjk0Nzg2NzI5ODYgKyAwLjA1MjEzMjcwMTQsIDIuNCApO1xuXG59XG5cbmZ1bmN0aW9uIExpbmVhclRvU1JHQiggYyApIHtcblxuXHRyZXR1cm4gKCBjIDwgMC4wMDMxMzA4ICkgPyBjICogMTIuOTIgOiAxLjA1NSAqICggTWF0aC5wb3coIGMsIDAuNDE2NjYgKSApIC0gMC4wNTU7XG5cbn1cblxubGV0IF9jYW52YXM7XG5cbmNsYXNzIEltYWdlVXRpbHMge1xuXG5cdHN0YXRpYyBnZXREYXRhVVJMKCBpbWFnZSApIHtcblxuXHRcdGlmICggL15kYXRhOi9pLnRlc3QoIGltYWdlLnNyYyApICkge1xuXG5cdFx0XHRyZXR1cm4gaW1hZ2Uuc3JjO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0eXBlb2YgSFRNTENhbnZhc0VsZW1lbnQgPT09ICd1bmRlZmluZWQnICkge1xuXG5cdFx0XHRyZXR1cm4gaW1hZ2Uuc3JjO1xuXG5cdFx0fVxuXG5cdFx0bGV0IGNhbnZhcztcblxuXHRcdGlmICggaW1hZ2UgaW5zdGFuY2VvZiBIVE1MQ2FudmFzRWxlbWVudCApIHtcblxuXHRcdFx0Y2FudmFzID0gaW1hZ2U7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIF9jYW52YXMgPT09IHVuZGVmaW5lZCApIF9jYW52YXMgPSBjcmVhdGVFbGVtZW50TlMoICdjYW52YXMnICk7XG5cblx0XHRcdF9jYW52YXMud2lkdGggPSBpbWFnZS53aWR0aDtcblx0XHRcdF9jYW52YXMuaGVpZ2h0ID0gaW1hZ2UuaGVpZ2h0O1xuXG5cdFx0XHRjb25zdCBjb250ZXh0ID0gX2NhbnZhcy5nZXRDb250ZXh0KCAnMmQnICk7XG5cblx0XHRcdGlmICggaW1hZ2UgaW5zdGFuY2VvZiBJbWFnZURhdGEgKSB7XG5cblx0XHRcdFx0Y29udGV4dC5wdXRJbWFnZURhdGEoIGltYWdlLCAwLCAwICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Y29udGV4dC5kcmF3SW1hZ2UoIGltYWdlLCAwLCAwLCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Y2FudmFzID0gX2NhbnZhcztcblxuXHRcdH1cblxuXHRcdGlmICggY2FudmFzLndpZHRoID4gMjA0OCB8fCBjYW52YXMuaGVpZ2h0ID4gMjA0OCApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuSW1hZ2VVdGlscy5nZXREYXRhVVJMOiBJbWFnZSBjb252ZXJ0ZWQgdG8ganBnIGZvciBwZXJmb3JtYW5jZSByZWFzb25zJywgaW1hZ2UgKTtcblxuXHRcdFx0cmV0dXJuIGNhbnZhcy50b0RhdGFVUkwoICdpbWFnZS9qcGVnJywgMC42ICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRyZXR1cm4gY2FudmFzLnRvRGF0YVVSTCggJ2ltYWdlL3BuZycgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0c3RhdGljIHNSR0JUb0xpbmVhciggaW1hZ2UgKSB7XG5cblx0XHRpZiAoICggdHlwZW9mIEhUTUxJbWFnZUVsZW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGltYWdlIGluc3RhbmNlb2YgSFRNTEltYWdlRWxlbWVudCApIHx8XG5cdFx0XHQoIHR5cGVvZiBIVE1MQ2FudmFzRWxlbWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBIVE1MQ2FudmFzRWxlbWVudCApIHx8XG5cdFx0XHQoIHR5cGVvZiBJbWFnZUJpdG1hcCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBJbWFnZUJpdG1hcCApICkge1xuXG5cdFx0XHRjb25zdCBjYW52YXMgPSBjcmVhdGVFbGVtZW50TlMoICdjYW52YXMnICk7XG5cblx0XHRcdGNhbnZhcy53aWR0aCA9IGltYWdlLndpZHRoO1xuXHRcdFx0Y2FudmFzLmhlaWdodCA9IGltYWdlLmhlaWdodDtcblxuXHRcdFx0Y29uc3QgY29udGV4dCA9IGNhbnZhcy5nZXRDb250ZXh0KCAnMmQnICk7XG5cdFx0XHRjb250ZXh0LmRyYXdJbWFnZSggaW1hZ2UsIDAsIDAsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcblxuXHRcdFx0Y29uc3QgaW1hZ2VEYXRhID0gY29udGV4dC5nZXRJbWFnZURhdGEoIDAsIDAsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcblx0XHRcdGNvbnN0IGRhdGEgPSBpbWFnZURhdGEuZGF0YTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZGF0YS5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0ZGF0YVsgaSBdID0gU1JHQlRvTGluZWFyKCBkYXRhWyBpIF0gLyAyNTUgKSAqIDI1NTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb250ZXh0LnB1dEltYWdlRGF0YSggaW1hZ2VEYXRhLCAwLCAwICk7XG5cblx0XHRcdHJldHVybiBjYW52YXM7XG5cblx0XHR9IGVsc2UgaWYgKCBpbWFnZS5kYXRhICkge1xuXG5cdFx0XHRjb25zdCBkYXRhID0gaW1hZ2UuZGF0YS5zbGljZSggMCApO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRpZiAoIGRhdGEgaW5zdGFuY2VvZiBVaW50OEFycmF5IHx8IGRhdGEgaW5zdGFuY2VvZiBVaW50OENsYW1wZWRBcnJheSApIHtcblxuXHRcdFx0XHRcdGRhdGFbIGkgXSA9IE1hdGguZmxvb3IoIFNSR0JUb0xpbmVhciggZGF0YVsgaSBdIC8gMjU1ICkgKiAyNTUgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ly8gYXNzdW1pbmcgZmxvYXRcblxuXHRcdFx0XHRcdGRhdGFbIGkgXSA9IFNSR0JUb0xpbmVhciggZGF0YVsgaSBdICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdGRhdGE6IGRhdGEsXG5cdFx0XHRcdHdpZHRoOiBpbWFnZS53aWR0aCxcblx0XHRcdFx0aGVpZ2h0OiBpbWFnZS5oZWlnaHRcblx0XHRcdH07XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5JbWFnZVV0aWxzLnNSR0JUb0xpbmVhcigpOiBVbnN1cHBvcnRlZCBpbWFnZSB0eXBlLiBObyBjb2xvciBzcGFjZSBjb252ZXJzaW9uIGFwcGxpZWQuJyApO1xuXHRcdFx0cmV0dXJuIGltYWdlO1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5sZXQgX3NvdXJjZUlkID0gMDtcblxuY2xhc3MgU291cmNlIHtcblxuXHRjb25zdHJ1Y3RvciggZGF0YSA9IG51bGwgKSB7XG5cblx0XHR0aGlzLmlzU291cmNlID0gdHJ1ZTtcblxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggdGhpcywgJ2lkJywgeyB2YWx1ZTogX3NvdXJjZUlkICsrIH0gKTtcblxuXHRcdHRoaXMudXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0dGhpcy5kYXRhID0gZGF0YTtcblx0XHR0aGlzLmRhdGFSZWFkeSA9IHRydWU7XG5cblx0XHR0aGlzLnZlcnNpb24gPSAwO1xuXG5cdH1cblxuXHRzZXQgbmVlZHNVcGRhdGUoIHZhbHVlICkge1xuXG5cdFx0aWYgKCB2YWx1ZSA9PT0gdHJ1ZSApIHRoaXMudmVyc2lvbiArKztcblxuXHR9XG5cblx0dG9KU09OKCBtZXRhICkge1xuXG5cdFx0Y29uc3QgaXNSb290T2JqZWN0ID0gKCBtZXRhID09PSB1bmRlZmluZWQgfHwgdHlwZW9mIG1ldGEgPT09ICdzdHJpbmcnICk7XG5cblx0XHRpZiAoICEgaXNSb290T2JqZWN0ICYmIG1ldGEuaW1hZ2VzWyB0aGlzLnV1aWQgXSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRyZXR1cm4gbWV0YS5pbWFnZXNbIHRoaXMudXVpZCBdO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3Qgb3V0cHV0ID0ge1xuXHRcdFx0dXVpZDogdGhpcy51dWlkLFxuXHRcdFx0dXJsOiAnJ1xuXHRcdH07XG5cblx0XHRjb25zdCBkYXRhID0gdGhpcy5kYXRhO1xuXG5cdFx0aWYgKCBkYXRhICE9PSBudWxsICkge1xuXG5cdFx0XHRsZXQgdXJsO1xuXG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIGRhdGEgKSApIHtcblxuXHRcdFx0XHQvLyBjdWJlIHRleHR1cmVcblxuXHRcdFx0XHR1cmwgPSBbXTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBkYXRhLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRpZiAoIGRhdGFbIGkgXS5pc0RhdGFUZXh0dXJlICkge1xuXG5cdFx0XHRcdFx0XHR1cmwucHVzaCggc2VyaWFsaXplSW1hZ2UoIGRhdGFbIGkgXS5pbWFnZSApICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHR1cmwucHVzaCggc2VyaWFsaXplSW1hZ2UoIGRhdGFbIGkgXSApICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIHRleHR1cmVcblxuXHRcdFx0XHR1cmwgPSBzZXJpYWxpemVJbWFnZSggZGF0YSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdG91dHB1dC51cmwgPSB1cmw7XG5cblx0XHR9XG5cblx0XHRpZiAoICEgaXNSb290T2JqZWN0ICkge1xuXG5cdFx0XHRtZXRhLmltYWdlc1sgdGhpcy51dWlkIF0gPSBvdXRwdXQ7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gb3V0cHV0O1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzZXJpYWxpemVJbWFnZSggaW1hZ2UgKSB7XG5cblx0aWYgKCAoIHR5cGVvZiBIVE1MSW1hZ2VFbGVtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEhUTUxJbWFnZUVsZW1lbnQgKSB8fFxuXHRcdCggdHlwZW9mIEhUTUxDYW52YXNFbGVtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50ICkgfHxcblx0XHQoIHR5cGVvZiBJbWFnZUJpdG1hcCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBJbWFnZUJpdG1hcCApICkge1xuXG5cdFx0Ly8gZGVmYXVsdCBpbWFnZXNcblxuXHRcdHJldHVybiBJbWFnZVV0aWxzLmdldERhdGFVUkwoIGltYWdlICk7XG5cblx0fSBlbHNlIHtcblxuXHRcdGlmICggaW1hZ2UuZGF0YSApIHtcblxuXHRcdFx0Ly8gaW1hZ2VzIG9mIERhdGFUZXh0dXJlXG5cblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdGRhdGE6IEFycmF5LmZyb20oIGltYWdlLmRhdGEgKSxcblx0XHRcdFx0d2lkdGg6IGltYWdlLndpZHRoLFxuXHRcdFx0XHRoZWlnaHQ6IGltYWdlLmhlaWdodCxcblx0XHRcdFx0dHlwZTogaW1hZ2UuZGF0YS5jb25zdHJ1Y3Rvci5uYW1lXG5cdFx0XHR9O1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuVGV4dHVyZTogVW5hYmxlIHRvIHNlcmlhbGl6ZSBUZXh0dXJlLicgKTtcblx0XHRcdHJldHVybiB7fTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxubGV0IF90ZXh0dXJlSWQgPSAwO1xuXG5jbGFzcyBUZXh0dXJlIGV4dGVuZHMgRXZlbnREaXNwYXRjaGVyIHtcblxuXHRjb25zdHJ1Y3RvciggaW1hZ2UgPSBUZXh0dXJlLkRFRkFVTFRfSU1BR0UsIG1hcHBpbmcgPSBUZXh0dXJlLkRFRkFVTFRfTUFQUElORywgd3JhcFMgPSBDbGFtcFRvRWRnZVdyYXBwaW5nLCB3cmFwVCA9IENsYW1wVG9FZGdlV3JhcHBpbmcsIG1hZ0ZpbHRlciA9IExpbmVhckZpbHRlciwgbWluRmlsdGVyID0gTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyLCBmb3JtYXQgPSBSR0JBRm9ybWF0LCB0eXBlID0gVW5zaWduZWRCeXRlVHlwZSwgYW5pc290cm9weSA9IFRleHR1cmUuREVGQVVMVF9BTklTT1RST1BZLCBjb2xvclNwYWNlID0gTm9Db2xvclNwYWNlICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNUZXh0dXJlID0gdHJ1ZTtcblxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggdGhpcywgJ2lkJywgeyB2YWx1ZTogX3RleHR1cmVJZCArKyB9ICk7XG5cblx0XHR0aGlzLnV1aWQgPSBnZW5lcmF0ZVVVSUQoKTtcblxuXHRcdHRoaXMubmFtZSA9ICcnO1xuXG5cdFx0dGhpcy5zb3VyY2UgPSBuZXcgU291cmNlKCBpbWFnZSApO1xuXHRcdHRoaXMubWlwbWFwcyA9IFtdO1xuXG5cdFx0dGhpcy5tYXBwaW5nID0gbWFwcGluZztcblx0XHR0aGlzLmNoYW5uZWwgPSAwO1xuXG5cdFx0dGhpcy53cmFwUyA9IHdyYXBTO1xuXHRcdHRoaXMud3JhcFQgPSB3cmFwVDtcblxuXHRcdHRoaXMubWFnRmlsdGVyID0gbWFnRmlsdGVyO1xuXHRcdHRoaXMubWluRmlsdGVyID0gbWluRmlsdGVyO1xuXG5cdFx0dGhpcy5hbmlzb3Ryb3B5ID0gYW5pc290cm9weTtcblxuXHRcdHRoaXMuZm9ybWF0ID0gZm9ybWF0O1xuXHRcdHRoaXMuaW50ZXJuYWxGb3JtYXQgPSBudWxsO1xuXHRcdHRoaXMudHlwZSA9IHR5cGU7XG5cblx0XHR0aGlzLm9mZnNldCA9IG5ldyBWZWN0b3IyKCAwLCAwICk7XG5cdFx0dGhpcy5yZXBlYXQgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xuXHRcdHRoaXMuY2VudGVyID0gbmV3IFZlY3RvcjIoIDAsIDAgKTtcblx0XHR0aGlzLnJvdGF0aW9uID0gMDtcblxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IHRydWU7XG5cdFx0dGhpcy5tYXRyaXggPSBuZXcgTWF0cml4MygpO1xuXG5cdFx0dGhpcy5nZW5lcmF0ZU1pcG1hcHMgPSB0cnVlO1xuXHRcdHRoaXMucHJlbXVsdGlwbHlBbHBoYSA9IGZhbHNlO1xuXHRcdHRoaXMuZmxpcFkgPSB0cnVlO1xuXHRcdHRoaXMudW5wYWNrQWxpZ25tZW50ID0gNDtcdC8vIHZhbGlkIHZhbHVlczogMSwgMiwgNCwgOCAoc2VlIGh0dHA6Ly93d3cua2hyb25vcy5vcmcvb3BlbmdsZXMvc2RrL2RvY3MvbWFuL3hodG1sL2dsUGl4ZWxTdG9yZWkueG1sKVxuXG5cdFx0dGhpcy5jb2xvclNwYWNlID0gY29sb3JTcGFjZTtcblxuXHRcdHRoaXMudXNlckRhdGEgPSB7fTtcblxuXHRcdHRoaXMudmVyc2lvbiA9IDA7XG5cdFx0dGhpcy5vblVwZGF0ZSA9IG51bGw7XG5cblx0XHR0aGlzLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9IGZhbHNlOyAvLyBpbmRpY2F0ZXMgd2hldGhlciBhIHRleHR1cmUgYmVsb25ncyB0byBhIHJlbmRlciB0YXJnZXQgb3Igbm90XG5cdFx0dGhpcy5wbXJlbVZlcnNpb24gPSAwOyAvLyBpbmRpY2F0ZXMgd2hldGhlciB0aGlzIHRleHR1cmUgc2hvdWxkIGJlIHByb2Nlc3NlZCBieSBQTVJFTUdlbmVyYXRvciBvciBub3QgKG9ubHkgcmVsZXZhbnQgZm9yIHJlbmRlciB0YXJnZXQgdGV4dHVyZXMpXG5cblx0fVxuXG5cdGdldCBpbWFnZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLnNvdXJjZS5kYXRhO1xuXG5cdH1cblxuXHRzZXQgaW1hZ2UoIHZhbHVlID0gbnVsbCApIHtcblxuXHRcdHRoaXMuc291cmNlLmRhdGEgPSB2YWx1ZTtcblxuXHR9XG5cblx0dXBkYXRlTWF0cml4KCkge1xuXG5cdFx0dGhpcy5tYXRyaXguc2V0VXZUcmFuc2Zvcm0oIHRoaXMub2Zmc2V0LngsIHRoaXMub2Zmc2V0LnksIHRoaXMucmVwZWF0LngsIHRoaXMucmVwZWF0LnksIHRoaXMucm90YXRpb24sIHRoaXMuY2VudGVyLngsIHRoaXMuY2VudGVyLnkgKTtcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHRoaXMubmFtZSA9IHNvdXJjZS5uYW1lO1xuXG5cdFx0dGhpcy5zb3VyY2UgPSBzb3VyY2Uuc291cmNlO1xuXHRcdHRoaXMubWlwbWFwcyA9IHNvdXJjZS5taXBtYXBzLnNsaWNlKCAwICk7XG5cblx0XHR0aGlzLm1hcHBpbmcgPSBzb3VyY2UubWFwcGluZztcblx0XHR0aGlzLmNoYW5uZWwgPSBzb3VyY2UuY2hhbm5lbDtcblxuXHRcdHRoaXMud3JhcFMgPSBzb3VyY2Uud3JhcFM7XG5cdFx0dGhpcy53cmFwVCA9IHNvdXJjZS53cmFwVDtcblxuXHRcdHRoaXMubWFnRmlsdGVyID0gc291cmNlLm1hZ0ZpbHRlcjtcblx0XHR0aGlzLm1pbkZpbHRlciA9IHNvdXJjZS5taW5GaWx0ZXI7XG5cblx0XHR0aGlzLmFuaXNvdHJvcHkgPSBzb3VyY2UuYW5pc290cm9weTtcblxuXHRcdHRoaXMuZm9ybWF0ID0gc291cmNlLmZvcm1hdDtcblx0XHR0aGlzLmludGVybmFsRm9ybWF0ID0gc291cmNlLmludGVybmFsRm9ybWF0O1xuXHRcdHRoaXMudHlwZSA9IHNvdXJjZS50eXBlO1xuXG5cdFx0dGhpcy5vZmZzZXQuY29weSggc291cmNlLm9mZnNldCApO1xuXHRcdHRoaXMucmVwZWF0LmNvcHkoIHNvdXJjZS5yZXBlYXQgKTtcblx0XHR0aGlzLmNlbnRlci5jb3B5KCBzb3VyY2UuY2VudGVyICk7XG5cdFx0dGhpcy5yb3RhdGlvbiA9IHNvdXJjZS5yb3RhdGlvbjtcblxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IHNvdXJjZS5tYXRyaXhBdXRvVXBkYXRlO1xuXHRcdHRoaXMubWF0cml4LmNvcHkoIHNvdXJjZS5tYXRyaXggKTtcblxuXHRcdHRoaXMuZ2VuZXJhdGVNaXBtYXBzID0gc291cmNlLmdlbmVyYXRlTWlwbWFwcztcblx0XHR0aGlzLnByZW11bHRpcGx5QWxwaGEgPSBzb3VyY2UucHJlbXVsdGlwbHlBbHBoYTtcblx0XHR0aGlzLmZsaXBZID0gc291cmNlLmZsaXBZO1xuXHRcdHRoaXMudW5wYWNrQWxpZ25tZW50ID0gc291cmNlLnVucGFja0FsaWdubWVudDtcblx0XHR0aGlzLmNvbG9yU3BhY2UgPSBzb3VyY2UuY29sb3JTcGFjZTtcblxuXHRcdHRoaXMudXNlckRhdGEgPSBKU09OLnBhcnNlKCBKU09OLnN0cmluZ2lmeSggc291cmNlLnVzZXJEYXRhICkgKTtcblxuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTiggbWV0YSApIHtcblxuXHRcdGNvbnN0IGlzUm9vdE9iamVjdCA9ICggbWV0YSA9PT0gdW5kZWZpbmVkIHx8IHR5cGVvZiBtZXRhID09PSAnc3RyaW5nJyApO1xuXG5cdFx0aWYgKCAhIGlzUm9vdE9iamVjdCAmJiBtZXRhLnRleHR1cmVzWyB0aGlzLnV1aWQgXSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRyZXR1cm4gbWV0YS50ZXh0dXJlc1sgdGhpcy51dWlkIF07XG5cblx0XHR9XG5cblx0XHRjb25zdCBvdXRwdXQgPSB7XG5cblx0XHRcdG1ldGFkYXRhOiB7XG5cdFx0XHRcdHZlcnNpb246IDQuNixcblx0XHRcdFx0dHlwZTogJ1RleHR1cmUnLFxuXHRcdFx0XHRnZW5lcmF0b3I6ICdUZXh0dXJlLnRvSlNPTidcblx0XHRcdH0sXG5cblx0XHRcdHV1aWQ6IHRoaXMudXVpZCxcblx0XHRcdG5hbWU6IHRoaXMubmFtZSxcblxuXHRcdFx0aW1hZ2U6IHRoaXMuc291cmNlLnRvSlNPTiggbWV0YSApLnV1aWQsXG5cblx0XHRcdG1hcHBpbmc6IHRoaXMubWFwcGluZyxcblx0XHRcdGNoYW5uZWw6IHRoaXMuY2hhbm5lbCxcblxuXHRcdFx0cmVwZWF0OiBbIHRoaXMucmVwZWF0LngsIHRoaXMucmVwZWF0LnkgXSxcblx0XHRcdG9mZnNldDogWyB0aGlzLm9mZnNldC54LCB0aGlzLm9mZnNldC55IF0sXG5cdFx0XHRjZW50ZXI6IFsgdGhpcy5jZW50ZXIueCwgdGhpcy5jZW50ZXIueSBdLFxuXHRcdFx0cm90YXRpb246IHRoaXMucm90YXRpb24sXG5cblx0XHRcdHdyYXA6IFsgdGhpcy53cmFwUywgdGhpcy53cmFwVCBdLFxuXG5cdFx0XHRmb3JtYXQ6IHRoaXMuZm9ybWF0LFxuXHRcdFx0aW50ZXJuYWxGb3JtYXQ6IHRoaXMuaW50ZXJuYWxGb3JtYXQsXG5cdFx0XHR0eXBlOiB0aGlzLnR5cGUsXG5cdFx0XHRjb2xvclNwYWNlOiB0aGlzLmNvbG9yU3BhY2UsXG5cblx0XHRcdG1pbkZpbHRlcjogdGhpcy5taW5GaWx0ZXIsXG5cdFx0XHRtYWdGaWx0ZXI6IHRoaXMubWFnRmlsdGVyLFxuXHRcdFx0YW5pc290cm9weTogdGhpcy5hbmlzb3Ryb3B5LFxuXG5cdFx0XHRmbGlwWTogdGhpcy5mbGlwWSxcblxuXHRcdFx0Z2VuZXJhdGVNaXBtYXBzOiB0aGlzLmdlbmVyYXRlTWlwbWFwcyxcblx0XHRcdHByZW11bHRpcGx5QWxwaGE6IHRoaXMucHJlbXVsdGlwbHlBbHBoYSxcblx0XHRcdHVucGFja0FsaWdubWVudDogdGhpcy51bnBhY2tBbGlnbm1lbnRcblxuXHRcdH07XG5cblx0XHRpZiAoIE9iamVjdC5rZXlzKCB0aGlzLnVzZXJEYXRhICkubGVuZ3RoID4gMCApIG91dHB1dC51c2VyRGF0YSA9IHRoaXMudXNlckRhdGE7XG5cblx0XHRpZiAoICEgaXNSb290T2JqZWN0ICkge1xuXG5cdFx0XHRtZXRhLnRleHR1cmVzWyB0aGlzLnV1aWQgXSA9IG91dHB1dDtcblxuXHRcdH1cblxuXHRcdHJldHVybiBvdXRwdXQ7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogJ2Rpc3Bvc2UnIH0gKTtcblxuXHR9XG5cblx0dHJhbnNmb3JtVXYoIHV2ICkge1xuXG5cdFx0aWYgKCB0aGlzLm1hcHBpbmcgIT09IFVWTWFwcGluZyApIHJldHVybiB1djtcblxuXHRcdHV2LmFwcGx5TWF0cml4MyggdGhpcy5tYXRyaXggKTtcblxuXHRcdGlmICggdXYueCA8IDAgfHwgdXYueCA+IDEgKSB7XG5cblx0XHRcdHN3aXRjaCAoIHRoaXMud3JhcFMgKSB7XG5cblx0XHRcdFx0Y2FzZSBSZXBlYXRXcmFwcGluZzpcblxuXHRcdFx0XHRcdHV2LnggPSB1di54IC0gTWF0aC5mbG9vciggdXYueCApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgQ2xhbXBUb0VkZ2VXcmFwcGluZzpcblxuXHRcdFx0XHRcdHV2LnggPSB1di54IDwgMCA/IDAgOiAxO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgTWlycm9yZWRSZXBlYXRXcmFwcGluZzpcblxuXHRcdFx0XHRcdGlmICggTWF0aC5hYnMoIE1hdGguZmxvb3IoIHV2LnggKSAlIDIgKSA9PT0gMSApIHtcblxuXHRcdFx0XHRcdFx0dXYueCA9IE1hdGguY2VpbCggdXYueCApIC0gdXYueDtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHV2LnggPSB1di54IC0gTWF0aC5mbG9vciggdXYueCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggdXYueSA8IDAgfHwgdXYueSA+IDEgKSB7XG5cblx0XHRcdHN3aXRjaCAoIHRoaXMud3JhcFQgKSB7XG5cblx0XHRcdFx0Y2FzZSBSZXBlYXRXcmFwcGluZzpcblxuXHRcdFx0XHRcdHV2LnkgPSB1di55IC0gTWF0aC5mbG9vciggdXYueSApO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgQ2xhbXBUb0VkZ2VXcmFwcGluZzpcblxuXHRcdFx0XHRcdHV2LnkgPSB1di55IDwgMCA/IDAgOiAxO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgTWlycm9yZWRSZXBlYXRXcmFwcGluZzpcblxuXHRcdFx0XHRcdGlmICggTWF0aC5hYnMoIE1hdGguZmxvb3IoIHV2LnkgKSAlIDIgKSA9PT0gMSApIHtcblxuXHRcdFx0XHRcdFx0dXYueSA9IE1hdGguY2VpbCggdXYueSApIC0gdXYueTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHV2LnkgPSB1di55IC0gTWF0aC5mbG9vciggdXYueSApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5mbGlwWSApIHtcblxuXHRcdFx0dXYueSA9IDEgLSB1di55O1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHV2O1xuXG5cdH1cblxuXHRzZXQgbmVlZHNVcGRhdGUoIHZhbHVlICkge1xuXG5cdFx0aWYgKCB2YWx1ZSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xuXHRcdFx0dGhpcy5zb3VyY2UubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRzZXQgbmVlZHNQTVJFTVVwZGF0ZSggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHZhbHVlID09PSB0cnVlICkge1xuXG5cdFx0XHR0aGlzLnBtcmVtVmVyc2lvbiArKztcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuVGV4dHVyZS5ERUZBVUxUX0lNQUdFID0gbnVsbDtcblRleHR1cmUuREVGQVVMVF9NQVBQSU5HID0gVVZNYXBwaW5nO1xuVGV4dHVyZS5ERUZBVUxUX0FOSVNPVFJPUFkgPSAxO1xuXG5jbGFzcyBWZWN0b3I0IHtcblxuXHRjb25zdHJ1Y3RvciggeCA9IDAsIHkgPSAwLCB6ID0gMCwgdyA9IDEgKSB7XG5cblx0XHRWZWN0b3I0LnByb3RvdHlwZS5pc1ZlY3RvcjQgPSB0cnVlO1xuXG5cdFx0dGhpcy54ID0geDtcblx0XHR0aGlzLnkgPSB5O1xuXHRcdHRoaXMueiA9IHo7XG5cdFx0dGhpcy53ID0gdztcblxuXHR9XG5cblx0Z2V0IHdpZHRoKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuejtcblxuXHR9XG5cblx0c2V0IHdpZHRoKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMueiA9IHZhbHVlO1xuXG5cdH1cblxuXHRnZXQgaGVpZ2h0KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMudztcblxuXHR9XG5cblx0c2V0IGhlaWdodCggdmFsdWUgKSB7XG5cblx0XHR0aGlzLncgPSB2YWx1ZTtcblxuXHR9XG5cblx0c2V0KCB4LCB5LCB6LCB3ICkge1xuXG5cdFx0dGhpcy54ID0geDtcblx0XHR0aGlzLnkgPSB5O1xuXHRcdHRoaXMueiA9IHo7XG5cdFx0dGhpcy53ID0gdztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRTY2FsYXIoIHNjYWxhciApIHtcblxuXHRcdHRoaXMueCA9IHNjYWxhcjtcblx0XHR0aGlzLnkgPSBzY2FsYXI7XG5cdFx0dGhpcy56ID0gc2NhbGFyO1xuXHRcdHRoaXMudyA9IHNjYWxhcjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRYKCB4ICkge1xuXG5cdFx0dGhpcy54ID0geDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRZKCB5ICkge1xuXG5cdFx0dGhpcy55ID0geTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRaKCB6ICkge1xuXG5cdFx0dGhpcy56ID0gejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRXKCB3ICkge1xuXG5cdFx0dGhpcy53ID0gdztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRDb21wb25lbnQoIGluZGV4LCB2YWx1ZSApIHtcblxuXHRcdHN3aXRjaCAoIGluZGV4ICkge1xuXG5cdFx0XHRjYXNlIDA6IHRoaXMueCA9IHZhbHVlOyBicmVhaztcblx0XHRcdGNhc2UgMTogdGhpcy55ID0gdmFsdWU7IGJyZWFrO1xuXHRcdFx0Y2FzZSAyOiB0aGlzLnogPSB2YWx1ZTsgYnJlYWs7XG5cdFx0XHRjYXNlIDM6IHRoaXMudyA9IHZhbHVlOyBicmVhaztcblx0XHRcdGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvciggJ2luZGV4IGlzIG91dCBvZiByYW5nZTogJyArIGluZGV4ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0Q29tcG9uZW50KCBpbmRleCApIHtcblxuXHRcdHN3aXRjaCAoIGluZGV4ICkge1xuXG5cdFx0XHRjYXNlIDA6IHJldHVybiB0aGlzLng7XG5cdFx0XHRjYXNlIDE6IHJldHVybiB0aGlzLnk7XG5cdFx0XHRjYXNlIDI6IHJldHVybiB0aGlzLno7XG5cdFx0XHRjYXNlIDM6IHJldHVybiB0aGlzLnc7XG5cdFx0XHRkZWZhdWx0OiB0aHJvdyBuZXcgRXJyb3IoICdpbmRleCBpcyBvdXQgb2YgcmFuZ2U6ICcgKyBpbmRleCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy54LCB0aGlzLnksIHRoaXMueiwgdGhpcy53ICk7XG5cblx0fVxuXG5cdGNvcHkoIHYgKSB7XG5cblx0XHR0aGlzLnggPSB2Lng7XG5cdFx0dGhpcy55ID0gdi55O1xuXHRcdHRoaXMueiA9IHYuejtcblx0XHR0aGlzLncgPSAoIHYudyAhPT0gdW5kZWZpbmVkICkgPyB2LncgOiAxO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFkZCggdiApIHtcblxuXHRcdHRoaXMueCArPSB2Lng7XG5cdFx0dGhpcy55ICs9IHYueTtcblx0XHR0aGlzLnogKz0gdi56O1xuXHRcdHRoaXMudyArPSB2Lnc7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkU2NhbGFyKCBzICkge1xuXG5cdFx0dGhpcy54ICs9IHM7XG5cdFx0dGhpcy55ICs9IHM7XG5cdFx0dGhpcy56ICs9IHM7XG5cdFx0dGhpcy53ICs9IHM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkVmVjdG9ycyggYSwgYiApIHtcblxuXHRcdHRoaXMueCA9IGEueCArIGIueDtcblx0XHR0aGlzLnkgPSBhLnkgKyBiLnk7XG5cdFx0dGhpcy56ID0gYS56ICsgYi56O1xuXHRcdHRoaXMudyA9IGEudyArIGIudztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhZGRTY2FsZWRWZWN0b3IoIHYsIHMgKSB7XG5cblx0XHR0aGlzLnggKz0gdi54ICogcztcblx0XHR0aGlzLnkgKz0gdi55ICogcztcblx0XHR0aGlzLnogKz0gdi56ICogcztcblx0XHR0aGlzLncgKz0gdi53ICogcztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdWIoIHYgKSB7XG5cblx0XHR0aGlzLnggLT0gdi54O1xuXHRcdHRoaXMueSAtPSB2Lnk7XG5cdFx0dGhpcy56IC09IHYuejtcblx0XHR0aGlzLncgLT0gdi53O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN1YlNjYWxhciggcyApIHtcblxuXHRcdHRoaXMueCAtPSBzO1xuXHRcdHRoaXMueSAtPSBzO1xuXHRcdHRoaXMueiAtPSBzO1xuXHRcdHRoaXMudyAtPSBzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN1YlZlY3RvcnMoIGEsIGIgKSB7XG5cblx0XHR0aGlzLnggPSBhLnggLSBiLng7XG5cdFx0dGhpcy55ID0gYS55IC0gYi55O1xuXHRcdHRoaXMueiA9IGEueiAtIGIuejtcblx0XHR0aGlzLncgPSBhLncgLSBiLnc7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bXVsdGlwbHkoIHYgKSB7XG5cblx0XHR0aGlzLnggKj0gdi54O1xuXHRcdHRoaXMueSAqPSB2Lnk7XG5cdFx0dGhpcy56ICo9IHYuejtcblx0XHR0aGlzLncgKj0gdi53O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5U2NhbGFyKCBzY2FsYXIgKSB7XG5cblx0XHR0aGlzLnggKj0gc2NhbGFyO1xuXHRcdHRoaXMueSAqPSBzY2FsYXI7XG5cdFx0dGhpcy56ICo9IHNjYWxhcjtcblx0XHR0aGlzLncgKj0gc2NhbGFyO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFwcGx5TWF0cml4NCggbSApIHtcblxuXHRcdGNvbnN0IHggPSB0aGlzLngsIHkgPSB0aGlzLnksIHogPSB0aGlzLnosIHcgPSB0aGlzLnc7XG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XG5cblx0XHR0aGlzLnggPSBlWyAwIF0gKiB4ICsgZVsgNCBdICogeSArIGVbIDggXSAqIHogKyBlWyAxMiBdICogdztcblx0XHR0aGlzLnkgPSBlWyAxIF0gKiB4ICsgZVsgNSBdICogeSArIGVbIDkgXSAqIHogKyBlWyAxMyBdICogdztcblx0XHR0aGlzLnogPSBlWyAyIF0gKiB4ICsgZVsgNiBdICogeSArIGVbIDEwIF0gKiB6ICsgZVsgMTQgXSAqIHc7XG5cdFx0dGhpcy53ID0gZVsgMyBdICogeCArIGVbIDcgXSAqIHkgKyBlWyAxMSBdICogeiArIGVbIDE1IF0gKiB3O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRpdmlkZVNjYWxhciggc2NhbGFyICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubXVsdGlwbHlTY2FsYXIoIDEgLyBzY2FsYXIgKTtcblxuXHR9XG5cblx0c2V0QXhpc0FuZ2xlRnJvbVF1YXRlcm5pb24oIHEgKSB7XG5cblx0XHQvLyBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9nZW9tZXRyeS9yb3RhdGlvbnMvY29udmVyc2lvbnMvcXVhdGVybmlvblRvQW5nbGUvaW5kZXguaHRtXG5cblx0XHQvLyBxIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxuXG5cdFx0dGhpcy53ID0gMiAqIE1hdGguYWNvcyggcS53ICk7XG5cblx0XHRjb25zdCBzID0gTWF0aC5zcXJ0KCAxIC0gcS53ICogcS53ICk7XG5cblx0XHRpZiAoIHMgPCAwLjAwMDEgKSB7XG5cblx0XHRcdHRoaXMueCA9IDE7XG5cdFx0XHR0aGlzLnkgPSAwO1xuXHRcdFx0dGhpcy56ID0gMDtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMueCA9IHEueCAvIHM7XG5cdFx0XHR0aGlzLnkgPSBxLnkgLyBzO1xuXHRcdFx0dGhpcy56ID0gcS56IC8gcztcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRBeGlzQW5nbGVGcm9tUm90YXRpb25NYXRyaXgoIG0gKSB7XG5cblx0XHQvLyBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9nZW9tZXRyeS9yb3RhdGlvbnMvY29udmVyc2lvbnMvbWF0cml4VG9BbmdsZS9pbmRleC5odG1cblxuXHRcdC8vIGFzc3VtZXMgdGhlIHVwcGVyIDN4MyBvZiBtIGlzIGEgcHVyZSByb3RhdGlvbiBtYXRyaXggKGkuZSwgdW5zY2FsZWQpXG5cblx0XHRsZXQgYW5nbGUsIHgsIHksIHo7IC8vIHZhcmlhYmxlcyBmb3IgcmVzdWx0XG5cdFx0Y29uc3QgZXBzaWxvbiA9IDAuMDEsXHRcdC8vIG1hcmdpbiB0byBhbGxvdyBmb3Igcm91bmRpbmcgZXJyb3JzXG5cdFx0XHRlcHNpbG9uMiA9IDAuMSxcdFx0Ly8gbWFyZ2luIHRvIGRpc3Rpbmd1aXNoIGJldHdlZW4gMCBhbmQgMTgwIGRlZ3JlZXNcblxuXHRcdFx0dGUgPSBtLmVsZW1lbnRzLFxuXG5cdFx0XHRtMTEgPSB0ZVsgMCBdLCBtMTIgPSB0ZVsgNCBdLCBtMTMgPSB0ZVsgOCBdLFxuXHRcdFx0bTIxID0gdGVbIDEgXSwgbTIyID0gdGVbIDUgXSwgbTIzID0gdGVbIDkgXSxcblx0XHRcdG0zMSA9IHRlWyAyIF0sIG0zMiA9IHRlWyA2IF0sIG0zMyA9IHRlWyAxMCBdO1xuXG5cdFx0aWYgKCAoIE1hdGguYWJzKCBtMTIgLSBtMjEgKSA8IGVwc2lsb24gKSAmJlxuXHRcdCAgICAgKCBNYXRoLmFicyggbTEzIC0gbTMxICkgPCBlcHNpbG9uICkgJiZcblx0XHQgICAgICggTWF0aC5hYnMoIG0yMyAtIG0zMiApIDwgZXBzaWxvbiApICkge1xuXG5cdFx0XHQvLyBzaW5ndWxhcml0eSBmb3VuZFxuXHRcdFx0Ly8gZmlyc3QgY2hlY2sgZm9yIGlkZW50aXR5IG1hdHJpeCB3aGljaCBtdXN0IGhhdmUgKzEgZm9yIGFsbCB0ZXJtc1xuXHRcdFx0Ly8gaW4gbGVhZGluZyBkaWFnb25hbCBhbmQgemVybyBpbiBvdGhlciB0ZXJtc1xuXG5cdFx0XHRpZiAoICggTWF0aC5hYnMoIG0xMiArIG0yMSApIDwgZXBzaWxvbjIgKSAmJlxuXHRcdFx0ICAgICAoIE1hdGguYWJzKCBtMTMgKyBtMzEgKSA8IGVwc2lsb24yICkgJiZcblx0XHRcdCAgICAgKCBNYXRoLmFicyggbTIzICsgbTMyICkgPCBlcHNpbG9uMiApICYmXG5cdFx0XHQgICAgICggTWF0aC5hYnMoIG0xMSArIG0yMiArIG0zMyAtIDMgKSA8IGVwc2lsb24yICkgKSB7XG5cblx0XHRcdFx0Ly8gdGhpcyBzaW5ndWxhcml0eSBpcyBpZGVudGl0eSBtYXRyaXggc28gYW5nbGUgPSAwXG5cblx0XHRcdFx0dGhpcy5zZXQoIDEsIDAsIDAsIDAgKTtcblxuXHRcdFx0XHRyZXR1cm4gdGhpczsgLy8gemVybyBhbmdsZSwgYXJiaXRyYXJ5IGF4aXNcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBvdGhlcndpc2UgdGhpcyBzaW5ndWxhcml0eSBpcyBhbmdsZSA9IDE4MFxuXG5cdFx0XHRhbmdsZSA9IE1hdGguUEk7XG5cblx0XHRcdGNvbnN0IHh4ID0gKCBtMTEgKyAxICkgLyAyO1xuXHRcdFx0Y29uc3QgeXkgPSAoIG0yMiArIDEgKSAvIDI7XG5cdFx0XHRjb25zdCB6eiA9ICggbTMzICsgMSApIC8gMjtcblx0XHRcdGNvbnN0IHh5ID0gKCBtMTIgKyBtMjEgKSAvIDQ7XG5cdFx0XHRjb25zdCB4eiA9ICggbTEzICsgbTMxICkgLyA0O1xuXHRcdFx0Y29uc3QgeXogPSAoIG0yMyArIG0zMiApIC8gNDtcblxuXHRcdFx0aWYgKCAoIHh4ID4geXkgKSAmJiAoIHh4ID4genogKSApIHtcblxuXHRcdFx0XHQvLyBtMTEgaXMgdGhlIGxhcmdlc3QgZGlhZ29uYWwgdGVybVxuXG5cdFx0XHRcdGlmICggeHggPCBlcHNpbG9uICkge1xuXG5cdFx0XHRcdFx0eCA9IDA7XG5cdFx0XHRcdFx0eSA9IDAuNzA3MTA2NzgxO1xuXHRcdFx0XHRcdHogPSAwLjcwNzEwNjc4MTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0eCA9IE1hdGguc3FydCggeHggKTtcblx0XHRcdFx0XHR5ID0geHkgLyB4O1xuXHRcdFx0XHRcdHogPSB4eiAvIHg7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2UgaWYgKCB5eSA+IHp6ICkge1xuXG5cdFx0XHRcdC8vIG0yMiBpcyB0aGUgbGFyZ2VzdCBkaWFnb25hbCB0ZXJtXG5cblx0XHRcdFx0aWYgKCB5eSA8IGVwc2lsb24gKSB7XG5cblx0XHRcdFx0XHR4ID0gMC43MDcxMDY3ODE7XG5cdFx0XHRcdFx0eSA9IDA7XG5cdFx0XHRcdFx0eiA9IDAuNzA3MTA2NzgxO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHR5ID0gTWF0aC5zcXJ0KCB5eSApO1xuXHRcdFx0XHRcdHggPSB4eSAvIHk7XG5cdFx0XHRcdFx0eiA9IHl6IC8geTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gbTMzIGlzIHRoZSBsYXJnZXN0IGRpYWdvbmFsIHRlcm0gc28gYmFzZSByZXN1bHQgb24gdGhpc1xuXG5cdFx0XHRcdGlmICggenogPCBlcHNpbG9uICkge1xuXG5cdFx0XHRcdFx0eCA9IDAuNzA3MTA2NzgxO1xuXHRcdFx0XHRcdHkgPSAwLjcwNzEwNjc4MTtcblx0XHRcdFx0XHR6ID0gMDtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0eiA9IE1hdGguc3FydCggenogKTtcblx0XHRcdFx0XHR4ID0geHogLyB6O1xuXHRcdFx0XHRcdHkgPSB5eiAvIHo7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuc2V0KCB4LCB5LCB6LCBhbmdsZSApO1xuXG5cdFx0XHRyZXR1cm4gdGhpczsgLy8gcmV0dXJuIDE4MCBkZWcgcm90YXRpb25cblxuXHRcdH1cblxuXHRcdC8vIGFzIHdlIGhhdmUgcmVhY2hlZCBoZXJlIHRoZXJlIGFyZSBubyBzaW5ndWxhcml0aWVzIHNvIHdlIGNhbiBoYW5kbGUgbm9ybWFsbHlcblxuXHRcdGxldCBzID0gTWF0aC5zcXJ0KCAoIG0zMiAtIG0yMyApICogKCBtMzIgLSBtMjMgKSArXG5cdFx0XHQoIG0xMyAtIG0zMSApICogKCBtMTMgLSBtMzEgKSArXG5cdFx0XHQoIG0yMSAtIG0xMiApICogKCBtMjEgLSBtMTIgKSApOyAvLyB1c2VkIHRvIG5vcm1hbGl6ZVxuXG5cdFx0aWYgKCBNYXRoLmFicyggcyApIDwgMC4wMDEgKSBzID0gMTtcblxuXHRcdC8vIHByZXZlbnQgZGl2aWRlIGJ5IHplcm8sIHNob3VsZCBub3QgaGFwcGVuIGlmIG1hdHJpeCBpcyBvcnRob2dvbmFsIGFuZCBzaG91bGQgYmVcblx0XHQvLyBjYXVnaHQgYnkgc2luZ3VsYXJpdHkgdGVzdCBhYm92ZSwgYnV0IEkndmUgbGVmdCBpdCBpbiBqdXN0IGluIGNhc2VcblxuXHRcdHRoaXMueCA9ICggbTMyIC0gbTIzICkgLyBzO1xuXHRcdHRoaXMueSA9ICggbTEzIC0gbTMxICkgLyBzO1xuXHRcdHRoaXMueiA9ICggbTIxIC0gbTEyICkgLyBzO1xuXHRcdHRoaXMudyA9IE1hdGguYWNvcyggKCBtMTEgKyBtMjIgKyBtMzMgLSAxICkgLyAyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBtICkge1xuXG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XG5cblx0XHR0aGlzLnggPSBlWyAxMiBdO1xuXHRcdHRoaXMueSA9IGVbIDEzIF07XG5cdFx0dGhpcy56ID0gZVsgMTQgXTtcblx0XHR0aGlzLncgPSBlWyAxNSBdO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1pbiggdiApIHtcblxuXHRcdHRoaXMueCA9IE1hdGgubWluKCB0aGlzLngsIHYueCApO1xuXHRcdHRoaXMueSA9IE1hdGgubWluKCB0aGlzLnksIHYueSApO1xuXHRcdHRoaXMueiA9IE1hdGgubWluKCB0aGlzLnosIHYueiApO1xuXHRcdHRoaXMudyA9IE1hdGgubWluKCB0aGlzLncsIHYudyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1heCggdiApIHtcblxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCB0aGlzLngsIHYueCApO1xuXHRcdHRoaXMueSA9IE1hdGgubWF4KCB0aGlzLnksIHYueSApO1xuXHRcdHRoaXMueiA9IE1hdGgubWF4KCB0aGlzLnosIHYueiApO1xuXHRcdHRoaXMudyA9IE1hdGgubWF4KCB0aGlzLncsIHYudyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsYW1wKCBtaW4sIG1heCApIHtcblxuXHRcdC8vIGFzc3VtZXMgbWluIDwgbWF4LCBjb21wb25lbnR3aXNlXG5cblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluLngsIE1hdGgubWluKCBtYXgueCwgdGhpcy54ICkgKTtcblx0XHR0aGlzLnkgPSBNYXRoLm1heCggbWluLnksIE1hdGgubWluKCBtYXgueSwgdGhpcy55ICkgKTtcblx0XHR0aGlzLnogPSBNYXRoLm1heCggbWluLnosIE1hdGgubWluKCBtYXgueiwgdGhpcy56ICkgKTtcblx0XHR0aGlzLncgPSBNYXRoLm1heCggbWluLncsIE1hdGgubWluKCBtYXgudywgdGhpcy53ICkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbGFtcFNjYWxhciggbWluVmFsLCBtYXhWYWwgKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnggKSApO1xuXHRcdHRoaXMueSA9IE1hdGgubWF4KCBtaW5WYWwsIE1hdGgubWluKCBtYXhWYWwsIHRoaXMueSApICk7XG5cdFx0dGhpcy56ID0gTWF0aC5tYXgoIG1pblZhbCwgTWF0aC5taW4oIG1heFZhbCwgdGhpcy56ICkgKTtcblx0XHR0aGlzLncgPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLncgKSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsYW1wTGVuZ3RoKCBtaW4sIG1heCApIHtcblxuXHRcdGNvbnN0IGxlbmd0aCA9IHRoaXMubGVuZ3RoKCk7XG5cblx0XHRyZXR1cm4gdGhpcy5kaXZpZGVTY2FsYXIoIGxlbmd0aCB8fCAxICkubXVsdGlwbHlTY2FsYXIoIE1hdGgubWF4KCBtaW4sIE1hdGgubWluKCBtYXgsIGxlbmd0aCApICkgKTtcblxuXHR9XG5cblx0Zmxvb3IoKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLmZsb29yKCB0aGlzLnggKTtcblx0XHR0aGlzLnkgPSBNYXRoLmZsb29yKCB0aGlzLnkgKTtcblx0XHR0aGlzLnogPSBNYXRoLmZsb29yKCB0aGlzLnogKTtcblx0XHR0aGlzLncgPSBNYXRoLmZsb29yKCB0aGlzLncgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjZWlsKCkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC5jZWlsKCB0aGlzLnggKTtcblx0XHR0aGlzLnkgPSBNYXRoLmNlaWwoIHRoaXMueSApO1xuXHRcdHRoaXMueiA9IE1hdGguY2VpbCggdGhpcy56ICk7XG5cdFx0dGhpcy53ID0gTWF0aC5jZWlsKCB0aGlzLncgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyb3VuZCgpIHtcblxuXHRcdHRoaXMueCA9IE1hdGgucm91bmQoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGgucm91bmQoIHRoaXMueSApO1xuXHRcdHRoaXMueiA9IE1hdGgucm91bmQoIHRoaXMueiApO1xuXHRcdHRoaXMudyA9IE1hdGgucm91bmQoIHRoaXMudyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJvdW5kVG9aZXJvKCkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC50cnVuYyggdGhpcy54ICk7XG5cdFx0dGhpcy55ID0gTWF0aC50cnVuYyggdGhpcy55ICk7XG5cdFx0dGhpcy56ID0gTWF0aC50cnVuYyggdGhpcy56ICk7XG5cdFx0dGhpcy53ID0gTWF0aC50cnVuYyggdGhpcy53ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bmVnYXRlKCkge1xuXG5cdFx0dGhpcy54ID0gLSB0aGlzLng7XG5cdFx0dGhpcy55ID0gLSB0aGlzLnk7XG5cdFx0dGhpcy56ID0gLSB0aGlzLno7XG5cdFx0dGhpcy53ID0gLSB0aGlzLnc7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZG90KCB2ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMueCAqIHYueCArIHRoaXMueSAqIHYueSArIHRoaXMueiAqIHYueiArIHRoaXMudyAqIHYudztcblxuXHR9XG5cblx0bGVuZ3RoU3EoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy54ICogdGhpcy54ICsgdGhpcy55ICogdGhpcy55ICsgdGhpcy56ICogdGhpcy56ICsgdGhpcy53ICogdGhpcy53O1xuXG5cdH1cblxuXHRsZW5ndGgoKSB7XG5cblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCB0aGlzLnggKiB0aGlzLnggKyB0aGlzLnkgKiB0aGlzLnkgKyB0aGlzLnogKiB0aGlzLnogKyB0aGlzLncgKiB0aGlzLncgKTtcblxuXHR9XG5cblx0bWFuaGF0dGFuTGVuZ3RoKCkge1xuXG5cdFx0cmV0dXJuIE1hdGguYWJzKCB0aGlzLnggKSArIE1hdGguYWJzKCB0aGlzLnkgKSArIE1hdGguYWJzKCB0aGlzLnogKSArIE1hdGguYWJzKCB0aGlzLncgKTtcblxuXHR9XG5cblx0bm9ybWFsaXplKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZGl2aWRlU2NhbGFyKCB0aGlzLmxlbmd0aCgpIHx8IDEgKTtcblxuXHR9XG5cblx0c2V0TGVuZ3RoKCBsZW5ndGggKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5ub3JtYWxpemUoKS5tdWx0aXBseVNjYWxhciggbGVuZ3RoICk7XG5cblx0fVxuXG5cdGxlcnAoIHYsIGFscGhhICkge1xuXG5cdFx0dGhpcy54ICs9ICggdi54IC0gdGhpcy54ICkgKiBhbHBoYTtcblx0XHR0aGlzLnkgKz0gKCB2LnkgLSB0aGlzLnkgKSAqIGFscGhhO1xuXHRcdHRoaXMueiArPSAoIHYueiAtIHRoaXMueiApICogYWxwaGE7XG5cdFx0dGhpcy53ICs9ICggdi53IC0gdGhpcy53ICkgKiBhbHBoYTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRsZXJwVmVjdG9ycyggdjEsIHYyLCBhbHBoYSApIHtcblxuXHRcdHRoaXMueCA9IHYxLnggKyAoIHYyLnggLSB2MS54ICkgKiBhbHBoYTtcblx0XHR0aGlzLnkgPSB2MS55ICsgKCB2Mi55IC0gdjEueSApICogYWxwaGE7XG5cdFx0dGhpcy56ID0gdjEueiArICggdjIueiAtIHYxLnogKSAqIGFscGhhO1xuXHRcdHRoaXMudyA9IHYxLncgKyAoIHYyLncgLSB2MS53ICkgKiBhbHBoYTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRlcXVhbHMoIHYgKSB7XG5cblx0XHRyZXR1cm4gKCAoIHYueCA9PT0gdGhpcy54ICkgJiYgKCB2LnkgPT09IHRoaXMueSApICYmICggdi56ID09PSB0aGlzLnogKSAmJiAoIHYudyA9PT0gdGhpcy53ICkgKTtcblxuXHR9XG5cblx0ZnJvbUFycmF5KCBhcnJheSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdHRoaXMueCA9IGFycmF5WyBvZmZzZXQgXTtcblx0XHR0aGlzLnkgPSBhcnJheVsgb2Zmc2V0ICsgMSBdO1xuXHRcdHRoaXMueiA9IGFycmF5WyBvZmZzZXQgKyAyIF07XG5cdFx0dGhpcy53ID0gYXJyYXlbIG9mZnNldCArIDMgXTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0FycmF5KCBhcnJheSA9IFtdLCBvZmZzZXQgPSAwICkge1xuXG5cdFx0YXJyYXlbIG9mZnNldCBdID0gdGhpcy54O1xuXHRcdGFycmF5WyBvZmZzZXQgKyAxIF0gPSB0aGlzLnk7XG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRoaXMuejtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMyBdID0gdGhpcy53O1xuXG5cdFx0cmV0dXJuIGFycmF5O1xuXG5cdH1cblxuXHRmcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGluZGV4ICkge1xuXG5cdFx0dGhpcy54ID0gYXR0cmlidXRlLmdldFgoIGluZGV4ICk7XG5cdFx0dGhpcy55ID0gYXR0cmlidXRlLmdldFkoIGluZGV4ICk7XG5cdFx0dGhpcy56ID0gYXR0cmlidXRlLmdldFooIGluZGV4ICk7XG5cdFx0dGhpcy53ID0gYXR0cmlidXRlLmdldFcoIGluZGV4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cmFuZG9tKCkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC5yYW5kb20oKTtcblx0XHR0aGlzLnkgPSBNYXRoLnJhbmRvbSgpO1xuXHRcdHRoaXMueiA9IE1hdGgucmFuZG9tKCk7XG5cdFx0dGhpcy53ID0gTWF0aC5yYW5kb20oKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQqWyBTeW1ib2wuaXRlcmF0b3IgXSgpIHtcblxuXHRcdHlpZWxkIHRoaXMueDtcblx0XHR5aWVsZCB0aGlzLnk7XG5cdFx0eWllbGQgdGhpcy56O1xuXHRcdHlpZWxkIHRoaXMudztcblxuXHR9XG5cbn1cblxuLypcbiBJbiBvcHRpb25zLCB3ZSBjYW4gc3BlY2lmeTpcbiAqIFRleHR1cmUgcGFyYW1ldGVycyBmb3IgYW4gYXV0by1nZW5lcmF0ZWQgdGFyZ2V0IHRleHR1cmVcbiAqIGRlcHRoQnVmZmVyL3N0ZW5jaWxCdWZmZXI6IEJvb2xlYW5zIHRvIGluZGljYXRlIGlmIHdlIHNob3VsZCBnZW5lcmF0ZSB0aGVzZSBidWZmZXJzXG4qL1xuY2xhc3MgUmVuZGVyVGFyZ2V0IGV4dGVuZHMgRXZlbnREaXNwYXRjaGVyIHtcblxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBvcHRpb25zID0ge30gKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc1JlbmRlclRhcmdldCA9IHRydWU7XG5cblx0XHR0aGlzLndpZHRoID0gd2lkdGg7XG5cdFx0dGhpcy5oZWlnaHQgPSBoZWlnaHQ7XG5cdFx0dGhpcy5kZXB0aCA9IDE7XG5cblx0XHR0aGlzLnNjaXNzb3IgPSBuZXcgVmVjdG9yNCggMCwgMCwgd2lkdGgsIGhlaWdodCApO1xuXHRcdHRoaXMuc2Npc3NvclRlc3QgPSBmYWxzZTtcblxuXHRcdHRoaXMudmlld3BvcnQgPSBuZXcgVmVjdG9yNCggMCwgMCwgd2lkdGgsIGhlaWdodCApO1xuXG5cdFx0Y29uc3QgaW1hZ2UgPSB7IHdpZHRoOiB3aWR0aCwgaGVpZ2h0OiBoZWlnaHQsIGRlcHRoOiAxIH07XG5cblx0XHRvcHRpb25zID0gT2JqZWN0LmFzc2lnbigge1xuXHRcdFx0Z2VuZXJhdGVNaXBtYXBzOiBmYWxzZSxcblx0XHRcdGludGVybmFsRm9ybWF0OiBudWxsLFxuXHRcdFx0bWluRmlsdGVyOiBMaW5lYXJGaWx0ZXIsXG5cdFx0XHRkZXB0aEJ1ZmZlcjogdHJ1ZSxcblx0XHRcdHN0ZW5jaWxCdWZmZXI6IGZhbHNlLFxuXHRcdFx0cmVzb2x2ZURlcHRoQnVmZmVyOiB0cnVlLFxuXHRcdFx0cmVzb2x2ZVN0ZW5jaWxCdWZmZXI6IHRydWUsXG5cdFx0XHRkZXB0aFRleHR1cmU6IG51bGwsXG5cdFx0XHRzYW1wbGVzOiAwLFxuXHRcdFx0Y291bnQ6IDFcblx0XHR9LCBvcHRpb25zICk7XG5cblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IFRleHR1cmUoIGltYWdlLCBvcHRpb25zLm1hcHBpbmcsIG9wdGlvbnMud3JhcFMsIG9wdGlvbnMud3JhcFQsIG9wdGlvbnMubWFnRmlsdGVyLCBvcHRpb25zLm1pbkZpbHRlciwgb3B0aW9ucy5mb3JtYXQsIG9wdGlvbnMudHlwZSwgb3B0aW9ucy5hbmlzb3Ryb3B5LCBvcHRpb25zLmNvbG9yU3BhY2UgKTtcblxuXHRcdHRleHR1cmUuZmxpcFkgPSBmYWxzZTtcblx0XHR0ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IG9wdGlvbnMuZ2VuZXJhdGVNaXBtYXBzO1xuXHRcdHRleHR1cmUuaW50ZXJuYWxGb3JtYXQgPSBvcHRpb25zLmludGVybmFsRm9ybWF0O1xuXG5cdFx0dGhpcy50ZXh0dXJlcyA9IFtdO1xuXG5cdFx0Y29uc3QgY291bnQgPSBvcHRpb25zLmNvdW50O1xuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvdW50OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLnRleHR1cmVzWyBpIF0gPSB0ZXh0dXJlLmNsb25lKCk7XG5cdFx0XHR0aGlzLnRleHR1cmVzWyBpIF0uaXNSZW5kZXJUYXJnZXRUZXh0dXJlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdHRoaXMuZGVwdGhCdWZmZXIgPSBvcHRpb25zLmRlcHRoQnVmZmVyO1xuXHRcdHRoaXMuc3RlbmNpbEJ1ZmZlciA9IG9wdGlvbnMuc3RlbmNpbEJ1ZmZlcjtcblxuXHRcdHRoaXMucmVzb2x2ZURlcHRoQnVmZmVyID0gb3B0aW9ucy5yZXNvbHZlRGVwdGhCdWZmZXI7XG5cdFx0dGhpcy5yZXNvbHZlU3RlbmNpbEJ1ZmZlciA9IG9wdGlvbnMucmVzb2x2ZVN0ZW5jaWxCdWZmZXI7XG5cblx0XHR0aGlzLmRlcHRoVGV4dHVyZSA9IG9wdGlvbnMuZGVwdGhUZXh0dXJlO1xuXG5cdFx0dGhpcy5zYW1wbGVzID0gb3B0aW9ucy5zYW1wbGVzO1xuXG5cdH1cblxuXHRnZXQgdGV4dHVyZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLnRleHR1cmVzWyAwIF07XG5cblx0fVxuXG5cdHNldCB0ZXh0dXJlKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMudGV4dHVyZXNbIDAgXSA9IHZhbHVlO1xuXG5cdH1cblxuXHRzZXRTaXplKCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCA9IDEgKSB7XG5cblx0XHRpZiAoIHRoaXMud2lkdGggIT09IHdpZHRoIHx8IHRoaXMuaGVpZ2h0ICE9PSBoZWlnaHQgfHwgdGhpcy5kZXB0aCAhPT0gZGVwdGggKSB7XG5cblx0XHRcdHRoaXMud2lkdGggPSB3aWR0aDtcblx0XHRcdHRoaXMuaGVpZ2h0ID0gaGVpZ2h0O1xuXHRcdFx0dGhpcy5kZXB0aCA9IGRlcHRoO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdGhpcy50ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHR0aGlzLnRleHR1cmVzWyBpIF0uaW1hZ2Uud2lkdGggPSB3aWR0aDtcblx0XHRcdFx0dGhpcy50ZXh0dXJlc1sgaSBdLmltYWdlLmhlaWdodCA9IGhlaWdodDtcblx0XHRcdFx0dGhpcy50ZXh0dXJlc1sgaSBdLmltYWdlLmRlcHRoID0gZGVwdGg7XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5kaXNwb3NlKCk7XG5cblx0XHR9XG5cblx0XHR0aGlzLnZpZXdwb3J0LnNldCggMCwgMCwgd2lkdGgsIGhlaWdodCApO1xuXHRcdHRoaXMuc2Npc3Nvci5zZXQoIDAsIDAsIHdpZHRoLCBoZWlnaHQgKTtcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHRoaXMud2lkdGggPSBzb3VyY2Uud2lkdGg7XG5cdFx0dGhpcy5oZWlnaHQgPSBzb3VyY2UuaGVpZ2h0O1xuXHRcdHRoaXMuZGVwdGggPSBzb3VyY2UuZGVwdGg7XG5cblx0XHR0aGlzLnNjaXNzb3IuY29weSggc291cmNlLnNjaXNzb3IgKTtcblx0XHR0aGlzLnNjaXNzb3JUZXN0ID0gc291cmNlLnNjaXNzb3JUZXN0O1xuXG5cdFx0dGhpcy52aWV3cG9ydC5jb3B5KCBzb3VyY2Uudmlld3BvcnQgKTtcblxuXHRcdHRoaXMudGV4dHVyZXMubGVuZ3RoID0gMDtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBzb3VyY2UudGV4dHVyZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMudGV4dHVyZXNbIGkgXSA9IHNvdXJjZS50ZXh0dXJlc1sgaSBdLmNsb25lKCk7XG5cdFx0XHR0aGlzLnRleHR1cmVzWyBpIF0uaXNSZW5kZXJUYXJnZXRUZXh0dXJlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdC8vIGVuc3VyZSBpbWFnZSBvYmplY3QgaXMgbm90IHNoYXJlZCwgc2VlICMyMDMyOFxuXG5cdFx0Y29uc3QgaW1hZ2UgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnRleHR1cmUuaW1hZ2UgKTtcblx0XHR0aGlzLnRleHR1cmUuc291cmNlID0gbmV3IFNvdXJjZSggaW1hZ2UgKTtcblxuXHRcdHRoaXMuZGVwdGhCdWZmZXIgPSBzb3VyY2UuZGVwdGhCdWZmZXI7XG5cdFx0dGhpcy5zdGVuY2lsQnVmZmVyID0gc291cmNlLnN0ZW5jaWxCdWZmZXI7XG5cblx0XHR0aGlzLnJlc29sdmVEZXB0aEJ1ZmZlciA9IHNvdXJjZS5yZXNvbHZlRGVwdGhCdWZmZXI7XG5cdFx0dGhpcy5yZXNvbHZlU3RlbmNpbEJ1ZmZlciA9IHNvdXJjZS5yZXNvbHZlU3RlbmNpbEJ1ZmZlcjtcblxuXHRcdGlmICggc291cmNlLmRlcHRoVGV4dHVyZSAhPT0gbnVsbCApIHRoaXMuZGVwdGhUZXh0dXJlID0gc291cmNlLmRlcHRoVGV4dHVyZS5jbG9uZSgpO1xuXG5cdFx0dGhpcy5zYW1wbGVzID0gc291cmNlLnNhbXBsZXM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzcG9zZScgfSApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBXZWJHTFJlbmRlclRhcmdldCBleHRlbmRzIFJlbmRlclRhcmdldCB7XG5cblx0Y29uc3RydWN0b3IoIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgb3B0aW9ucyA9IHt9ICkge1xuXG5cdFx0c3VwZXIoIHdpZHRoLCBoZWlnaHQsIG9wdGlvbnMgKTtcblxuXHRcdHRoaXMuaXNXZWJHTFJlbmRlclRhcmdldCA9IHRydWU7XG5cblx0fVxuXG59XG5cbmNsYXNzIERhdGFBcnJheVRleHR1cmUgZXh0ZW5kcyBUZXh0dXJlIHtcblxuXHRjb25zdHJ1Y3RvciggZGF0YSA9IG51bGwsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgZGVwdGggPSAxICkge1xuXG5cdFx0c3VwZXIoIG51bGwgKTtcblxuXHRcdHRoaXMuaXNEYXRhQXJyYXlUZXh0dXJlID0gdHJ1ZTtcblxuXHRcdHRoaXMuaW1hZ2UgPSB7IGRhdGEsIHdpZHRoLCBoZWlnaHQsIGRlcHRoIH07XG5cblx0XHR0aGlzLm1hZ0ZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XG5cdFx0dGhpcy5taW5GaWx0ZXIgPSBOZWFyZXN0RmlsdGVyO1xuXG5cdFx0dGhpcy53cmFwUiA9IENsYW1wVG9FZGdlV3JhcHBpbmc7XG5cblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXHRcdHRoaXMuZmxpcFkgPSBmYWxzZTtcblx0XHR0aGlzLnVucGFja0FsaWdubWVudCA9IDE7XG5cblx0XHR0aGlzLmxheWVyVXBkYXRlcyA9IG5ldyBTZXQoKTtcblxuXHR9XG5cblx0YWRkTGF5ZXJVcGRhdGUoIGxheWVySW5kZXggKSB7XG5cblx0XHR0aGlzLmxheWVyVXBkYXRlcy5hZGQoIGxheWVySW5kZXggKTtcblxuXHR9XG5cblx0Y2xlYXJMYXllclVwZGF0ZXMoKSB7XG5cblx0XHR0aGlzLmxheWVyVXBkYXRlcy5jbGVhcigpO1xuXG5cdH1cblxufVxuXG5jbGFzcyBXZWJHTEFycmF5UmVuZGVyVGFyZ2V0IGV4dGVuZHMgV2ViR0xSZW5kZXJUYXJnZXQge1xuXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCA9IDEsIGhlaWdodCA9IDEsIGRlcHRoID0gMSwgb3B0aW9ucyA9IHt9ICkge1xuXG5cdFx0c3VwZXIoIHdpZHRoLCBoZWlnaHQsIG9wdGlvbnMgKTtcblxuXHRcdHRoaXMuaXNXZWJHTEFycmF5UmVuZGVyVGFyZ2V0ID0gdHJ1ZTtcblxuXHRcdHRoaXMuZGVwdGggPSBkZXB0aDtcblxuXHRcdHRoaXMudGV4dHVyZSA9IG5ldyBEYXRhQXJyYXlUZXh0dXJlKCBudWxsLCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCApO1xuXG5cdFx0dGhpcy50ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9IHRydWU7XG5cblx0fVxuXG59XG5cbmNsYXNzIERhdGEzRFRleHR1cmUgZXh0ZW5kcyBUZXh0dXJlIHtcblxuXHRjb25zdHJ1Y3RvciggZGF0YSA9IG51bGwsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgZGVwdGggPSAxICkge1xuXG5cdFx0Ly8gV2UncmUgZ29pbmcgdG8gYWRkIC5zZXRYWFgoKSBtZXRob2RzIGZvciBzZXR0aW5nIHByb3BlcnRpZXMgbGF0ZXIuXG5cdFx0Ly8gVXNlcnMgY2FuIHN0aWxsIHNldCBpbiBEYXRhVGV4dHVyZTNEIGRpcmVjdGx5LlxuXHRcdC8vXG5cdFx0Ly9cdGNvbnN0IHRleHR1cmUgPSBuZXcgVEhSRUUuRGF0YVRleHR1cmUzRCggZGF0YSwgd2lkdGgsIGhlaWdodCwgZGVwdGggKTtcblx0XHQvLyBcdHRleHR1cmUuYW5pc290cm9weSA9IDE2O1xuXHRcdC8vXG5cdFx0Ly8gU2VlICMxNDgzOVxuXG5cdFx0c3VwZXIoIG51bGwgKTtcblxuXHRcdHRoaXMuaXNEYXRhM0RUZXh0dXJlID0gdHJ1ZTtcblxuXHRcdHRoaXMuaW1hZ2UgPSB7IGRhdGEsIHdpZHRoLCBoZWlnaHQsIGRlcHRoIH07XG5cblx0XHR0aGlzLm1hZ0ZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XG5cdFx0dGhpcy5taW5GaWx0ZXIgPSBOZWFyZXN0RmlsdGVyO1xuXG5cdFx0dGhpcy53cmFwUiA9IENsYW1wVG9FZGdlV3JhcHBpbmc7XG5cblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXHRcdHRoaXMuZmxpcFkgPSBmYWxzZTtcblx0XHR0aGlzLnVucGFja0FsaWdubWVudCA9IDE7XG5cblx0fVxuXG59XG5cbmNsYXNzIFdlYkdMM0RSZW5kZXJUYXJnZXQgZXh0ZW5kcyBXZWJHTFJlbmRlclRhcmdldCB7XG5cblx0Y29uc3RydWN0b3IoIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgZGVwdGggPSAxLCBvcHRpb25zID0ge30gKSB7XG5cblx0XHRzdXBlciggd2lkdGgsIGhlaWdodCwgb3B0aW9ucyApO1xuXG5cdFx0dGhpcy5pc1dlYkdMM0RSZW5kZXJUYXJnZXQgPSB0cnVlO1xuXG5cdFx0dGhpcy5kZXB0aCA9IGRlcHRoO1xuXG5cdFx0dGhpcy50ZXh0dXJlID0gbmV3IERhdGEzRFRleHR1cmUoIG51bGwsIHdpZHRoLCBoZWlnaHQsIGRlcHRoICk7XG5cblx0XHR0aGlzLnRleHR1cmUuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID0gdHJ1ZTtcblxuXHR9XG5cbn1cblxuY2xhc3MgUXVhdGVybmlvbiB7XG5cblx0Y29uc3RydWN0b3IoIHggPSAwLCB5ID0gMCwgeiA9IDAsIHcgPSAxICkge1xuXG5cdFx0dGhpcy5pc1F1YXRlcm5pb24gPSB0cnVlO1xuXG5cdFx0dGhpcy5feCA9IHg7XG5cdFx0dGhpcy5feSA9IHk7XG5cdFx0dGhpcy5feiA9IHo7XG5cdFx0dGhpcy5fdyA9IHc7XG5cblx0fVxuXG5cdHN0YXRpYyBzbGVycEZsYXQoIGRzdCwgZHN0T2Zmc2V0LCBzcmMwLCBzcmNPZmZzZXQwLCBzcmMxLCBzcmNPZmZzZXQxLCB0ICkge1xuXG5cdFx0Ly8gZnV6ei1mcmVlLCBhcnJheS1iYXNlZCBRdWF0ZXJuaW9uIFNMRVJQIG9wZXJhdGlvblxuXG5cdFx0bGV0IHgwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDAgXSxcblx0XHRcdHkwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDEgXSxcblx0XHRcdHowID0gc3JjMFsgc3JjT2Zmc2V0MCArIDIgXSxcblx0XHRcdHcwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDMgXTtcblxuXHRcdGNvbnN0IHgxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDAgXSxcblx0XHRcdHkxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDEgXSxcblx0XHRcdHoxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDIgXSxcblx0XHRcdHcxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDMgXTtcblxuXHRcdGlmICggdCA9PT0gMCApIHtcblxuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAwIF0gPSB4MDtcblx0XHRcdGRzdFsgZHN0T2Zmc2V0ICsgMSBdID0geTA7XG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDIgXSA9IHowO1xuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAzIF0gPSB3MDtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdGlmICggdCA9PT0gMSApIHtcblxuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAwIF0gPSB4MTtcblx0XHRcdGRzdFsgZHN0T2Zmc2V0ICsgMSBdID0geTE7XG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDIgXSA9IHoxO1xuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAzIF0gPSB3MTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdGlmICggdzAgIT09IHcxIHx8IHgwICE9PSB4MSB8fCB5MCAhPT0geTEgfHwgejAgIT09IHoxICkge1xuXG5cdFx0XHRsZXQgcyA9IDEgLSB0O1xuXHRcdFx0Y29uc3QgY29zID0geDAgKiB4MSArIHkwICogeTEgKyB6MCAqIHoxICsgdzAgKiB3MSxcblx0XHRcdFx0ZGlyID0gKCBjb3MgPj0gMCA/IDEgOiAtIDEgKSxcblx0XHRcdFx0c3FyU2luID0gMSAtIGNvcyAqIGNvcztcblxuXHRcdFx0Ly8gU2tpcCB0aGUgU2xlcnAgZm9yIHRpbnkgc3RlcHMgdG8gYXZvaWQgbnVtZXJpYyBwcm9ibGVtczpcblx0XHRcdGlmICggc3FyU2luID4gTnVtYmVyLkVQU0lMT04gKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2luID0gTWF0aC5zcXJ0KCBzcXJTaW4gKSxcblx0XHRcdFx0XHRsZW4gPSBNYXRoLmF0YW4yKCBzaW4sIGNvcyAqIGRpciApO1xuXG5cdFx0XHRcdHMgPSBNYXRoLnNpbiggcyAqIGxlbiApIC8gc2luO1xuXHRcdFx0XHR0ID0gTWF0aC5zaW4oIHQgKiBsZW4gKSAvIHNpbjtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCB0RGlyID0gdCAqIGRpcjtcblxuXHRcdFx0eDAgPSB4MCAqIHMgKyB4MSAqIHREaXI7XG5cdFx0XHR5MCA9IHkwICogcyArIHkxICogdERpcjtcblx0XHRcdHowID0gejAgKiBzICsgejEgKiB0RGlyO1xuXHRcdFx0dzAgPSB3MCAqIHMgKyB3MSAqIHREaXI7XG5cblx0XHRcdC8vIE5vcm1hbGl6ZSBpbiBjYXNlIHdlIGp1c3QgZGlkIGEgbGVycDpcblx0XHRcdGlmICggcyA9PT0gMSAtIHQgKSB7XG5cblx0XHRcdFx0Y29uc3QgZiA9IDEgLyBNYXRoLnNxcnQoIHgwICogeDAgKyB5MCAqIHkwICsgejAgKiB6MCArIHcwICogdzAgKTtcblxuXHRcdFx0XHR4MCAqPSBmO1xuXHRcdFx0XHR5MCAqPSBmO1xuXHRcdFx0XHR6MCAqPSBmO1xuXHRcdFx0XHR3MCAqPSBmO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRkc3RbIGRzdE9mZnNldCBdID0geDA7XG5cdFx0ZHN0WyBkc3RPZmZzZXQgKyAxIF0gPSB5MDtcblx0XHRkc3RbIGRzdE9mZnNldCArIDIgXSA9IHowO1xuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMyBdID0gdzA7XG5cblx0fVxuXG5cdHN0YXRpYyBtdWx0aXBseVF1YXRlcm5pb25zRmxhdCggZHN0LCBkc3RPZmZzZXQsIHNyYzAsIHNyY09mZnNldDAsIHNyYzEsIHNyY09mZnNldDEgKSB7XG5cblx0XHRjb25zdCB4MCA9IHNyYzBbIHNyY09mZnNldDAgXTtcblx0XHRjb25zdCB5MCA9IHNyYzBbIHNyY09mZnNldDAgKyAxIF07XG5cdFx0Y29uc3QgejAgPSBzcmMwWyBzcmNPZmZzZXQwICsgMiBdO1xuXHRcdGNvbnN0IHcwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDMgXTtcblxuXHRcdGNvbnN0IHgxID0gc3JjMVsgc3JjT2Zmc2V0MSBdO1xuXHRcdGNvbnN0IHkxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDEgXTtcblx0XHRjb25zdCB6MSA9IHNyYzFbIHNyY09mZnNldDEgKyAyIF07XG5cdFx0Y29uc3QgdzEgPSBzcmMxWyBzcmNPZmZzZXQxICsgMyBdO1xuXG5cdFx0ZHN0WyBkc3RPZmZzZXQgXSA9IHgwICogdzEgKyB3MCAqIHgxICsgeTAgKiB6MSAtIHowICogeTE7XG5cdFx0ZHN0WyBkc3RPZmZzZXQgKyAxIF0gPSB5MCAqIHcxICsgdzAgKiB5MSArIHowICogeDEgLSB4MCAqIHoxO1xuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMiBdID0gejAgKiB3MSArIHcwICogejEgKyB4MCAqIHkxIC0geTAgKiB4MTtcblx0XHRkc3RbIGRzdE9mZnNldCArIDMgXSA9IHcwICogdzEgLSB4MCAqIHgxIC0geTAgKiB5MSAtIHowICogejE7XG5cblx0XHRyZXR1cm4gZHN0O1xuXG5cdH1cblxuXHRnZXQgeCgpIHtcblxuXHRcdHJldHVybiB0aGlzLl94O1xuXG5cdH1cblxuXHRzZXQgeCggdmFsdWUgKSB7XG5cblx0XHR0aGlzLl94ID0gdmFsdWU7XG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdH1cblxuXHRnZXQgeSgpIHtcblxuXHRcdHJldHVybiB0aGlzLl95O1xuXG5cdH1cblxuXHRzZXQgeSggdmFsdWUgKSB7XG5cblx0XHR0aGlzLl95ID0gdmFsdWU7XG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdH1cblxuXHRnZXQgeigpIHtcblxuXHRcdHJldHVybiB0aGlzLl96O1xuXG5cdH1cblxuXHRzZXQgeiggdmFsdWUgKSB7XG5cblx0XHR0aGlzLl96ID0gdmFsdWU7XG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdH1cblxuXHRnZXQgdygpIHtcblxuXHRcdHJldHVybiB0aGlzLl93O1xuXG5cdH1cblxuXHRzZXQgdyggdmFsdWUgKSB7XG5cblx0XHR0aGlzLl93ID0gdmFsdWU7XG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdH1cblxuXHRzZXQoIHgsIHksIHosIHcgKSB7XG5cblx0XHR0aGlzLl94ID0geDtcblx0XHR0aGlzLl95ID0geTtcblx0XHR0aGlzLl96ID0gejtcblx0XHR0aGlzLl93ID0gdztcblxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy5feCwgdGhpcy5feSwgdGhpcy5feiwgdGhpcy5fdyApO1xuXG5cdH1cblxuXHRjb3B5KCBxdWF0ZXJuaW9uICkge1xuXG5cdFx0dGhpcy5feCA9IHF1YXRlcm5pb24ueDtcblx0XHR0aGlzLl95ID0gcXVhdGVybmlvbi55O1xuXHRcdHRoaXMuX3ogPSBxdWF0ZXJuaW9uLno7XG5cdFx0dGhpcy5fdyA9IHF1YXRlcm5pb24udztcblxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tRXVsZXIoIGV1bGVyLCB1cGRhdGUgPSB0cnVlICkge1xuXG5cdFx0Y29uc3QgeCA9IGV1bGVyLl94LCB5ID0gZXVsZXIuX3ksIHogPSBldWxlci5feiwgb3JkZXIgPSBldWxlci5fb3JkZXI7XG5cblx0XHQvLyBodHRwOi8vd3d3Lm1hdGh3b3Jrcy5jb20vbWF0bGFiY2VudHJhbC9maWxlZXhjaGFuZ2UvXG5cdFx0Ly8gXHQyMDY5Ni1mdW5jdGlvbi10by1jb252ZXJ0LWJldHdlZW4tZGNtLWV1bGVyLWFuZ2xlcy1xdWF0ZXJuaW9ucy1hbmQtZXVsZXItdmVjdG9ycy9cblx0XHQvL1x0Y29udGVudC9TcGluQ2FsYy5tXG5cblx0XHRjb25zdCBjb3MgPSBNYXRoLmNvcztcblx0XHRjb25zdCBzaW4gPSBNYXRoLnNpbjtcblxuXHRcdGNvbnN0IGMxID0gY29zKCB4IC8gMiApO1xuXHRcdGNvbnN0IGMyID0gY29zKCB5IC8gMiApO1xuXHRcdGNvbnN0IGMzID0gY29zKCB6IC8gMiApO1xuXG5cdFx0Y29uc3QgczEgPSBzaW4oIHggLyAyICk7XG5cdFx0Y29uc3QgczIgPSBzaW4oIHkgLyAyICk7XG5cdFx0Y29uc3QgczMgPSBzaW4oIHogLyAyICk7XG5cblx0XHRzd2l0Y2ggKCBvcmRlciApIHtcblxuXHRcdFx0Y2FzZSAnWFlaJzpcblx0XHRcdFx0dGhpcy5feCA9IHMxICogYzIgKiBjMyArIGMxICogczIgKiBzMztcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyAtIHMxICogYzIgKiBzMztcblx0XHRcdFx0dGhpcy5feiA9IGMxICogYzIgKiBzMyArIHMxICogczIgKiBjMztcblx0XHRcdFx0dGhpcy5fdyA9IGMxICogYzIgKiBjMyAtIHMxICogczIgKiBzMztcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1lYWic6XG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgKyBjMSAqIHMyICogczM7XG5cdFx0XHRcdHRoaXMuX3kgPSBjMSAqIHMyICogYzMgLSBzMSAqIGMyICogczM7XG5cdFx0XHRcdHRoaXMuX3ogPSBjMSAqIGMyICogczMgLSBzMSAqIHMyICogYzM7XG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgKyBzMSAqIHMyICogczM7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdaWFknOlxuXHRcdFx0XHR0aGlzLl94ID0gczEgKiBjMiAqIGMzIC0gYzEgKiBzMiAqIHMzO1xuXHRcdFx0XHR0aGlzLl95ID0gYzEgKiBzMiAqIGMzICsgczEgKiBjMiAqIHMzO1xuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzICsgczEgKiBzMiAqIGMzO1xuXHRcdFx0XHR0aGlzLl93ID0gYzEgKiBjMiAqIGMzIC0gczEgKiBzMiAqIHMzO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnWllYJzpcblx0XHRcdFx0dGhpcy5feCA9IHMxICogYzIgKiBjMyAtIGMxICogczIgKiBzMztcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyArIHMxICogYzIgKiBzMztcblx0XHRcdFx0dGhpcy5feiA9IGMxICogYzIgKiBzMyAtIHMxICogczIgKiBjMztcblx0XHRcdFx0dGhpcy5fdyA9IGMxICogYzIgKiBjMyArIHMxICogczIgKiBzMztcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1laWCc6XG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgKyBjMSAqIHMyICogczM7XG5cdFx0XHRcdHRoaXMuX3kgPSBjMSAqIHMyICogYzMgKyBzMSAqIGMyICogczM7XG5cdFx0XHRcdHRoaXMuX3ogPSBjMSAqIGMyICogczMgLSBzMSAqIHMyICogYzM7XG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgLSBzMSAqIHMyICogczM7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdYWlknOlxuXHRcdFx0XHR0aGlzLl94ID0gczEgKiBjMiAqIGMzIC0gYzEgKiBzMiAqIHMzO1xuXHRcdFx0XHR0aGlzLl95ID0gYzEgKiBzMiAqIGMzIC0gczEgKiBjMiAqIHMzO1xuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzICsgczEgKiBzMiAqIGMzO1xuXHRcdFx0XHR0aGlzLl93ID0gYzEgKiBjMiAqIGMzICsgczEgKiBzMiAqIHMzO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuUXVhdGVybmlvbjogLnNldEZyb21FdWxlcigpIGVuY291bnRlcmVkIGFuIHVua25vd24gb3JkZXI6ICcgKyBvcmRlciApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB1cGRhdGUgPT09IHRydWUgKSB0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbUF4aXNBbmdsZSggYXhpcywgYW5nbGUgKSB7XG5cblx0XHQvLyBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9nZW9tZXRyeS9yb3RhdGlvbnMvY29udmVyc2lvbnMvYW5nbGVUb1F1YXRlcm5pb24vaW5kZXguaHRtXG5cblx0XHQvLyBhc3N1bWVzIGF4aXMgaXMgbm9ybWFsaXplZFxuXG5cdFx0Y29uc3QgaGFsZkFuZ2xlID0gYW5nbGUgLyAyLCBzID0gTWF0aC5zaW4oIGhhbGZBbmdsZSApO1xuXG5cdFx0dGhpcy5feCA9IGF4aXMueCAqIHM7XG5cdFx0dGhpcy5feSA9IGF4aXMueSAqIHM7XG5cdFx0dGhpcy5feiA9IGF4aXMueiAqIHM7XG5cdFx0dGhpcy5fdyA9IE1hdGguY29zKCBoYWxmQW5nbGUgKTtcblxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tUm90YXRpb25NYXRyaXgoIG0gKSB7XG5cblx0XHQvLyBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9nZW9tZXRyeS9yb3RhdGlvbnMvY29udmVyc2lvbnMvbWF0cml4VG9RdWF0ZXJuaW9uL2luZGV4Lmh0bVxuXG5cdFx0Ly8gYXNzdW1lcyB0aGUgdXBwZXIgM3gzIG9mIG0gaXMgYSBwdXJlIHJvdGF0aW9uIG1hdHJpeCAoaS5lLCB1bnNjYWxlZClcblxuXHRcdGNvbnN0IHRlID0gbS5lbGVtZW50cyxcblxuXHRcdFx0bTExID0gdGVbIDAgXSwgbTEyID0gdGVbIDQgXSwgbTEzID0gdGVbIDggXSxcblx0XHRcdG0yMSA9IHRlWyAxIF0sIG0yMiA9IHRlWyA1IF0sIG0yMyA9IHRlWyA5IF0sXG5cdFx0XHRtMzEgPSB0ZVsgMiBdLCBtMzIgPSB0ZVsgNiBdLCBtMzMgPSB0ZVsgMTAgXSxcblxuXHRcdFx0dHJhY2UgPSBtMTEgKyBtMjIgKyBtMzM7XG5cblx0XHRpZiAoIHRyYWNlID4gMCApIHtcblxuXHRcdFx0Y29uc3QgcyA9IDAuNSAvIE1hdGguc3FydCggdHJhY2UgKyAxLjAgKTtcblxuXHRcdFx0dGhpcy5fdyA9IDAuMjUgLyBzO1xuXHRcdFx0dGhpcy5feCA9ICggbTMyIC0gbTIzICkgKiBzO1xuXHRcdFx0dGhpcy5feSA9ICggbTEzIC0gbTMxICkgKiBzO1xuXHRcdFx0dGhpcy5feiA9ICggbTIxIC0gbTEyICkgKiBzO1xuXG5cdFx0fSBlbHNlIGlmICggbTExID4gbTIyICYmIG0xMSA+IG0zMyApIHtcblxuXHRcdFx0Y29uc3QgcyA9IDIuMCAqIE1hdGguc3FydCggMS4wICsgbTExIC0gbTIyIC0gbTMzICk7XG5cblx0XHRcdHRoaXMuX3cgPSAoIG0zMiAtIG0yMyApIC8gcztcblx0XHRcdHRoaXMuX3ggPSAwLjI1ICogcztcblx0XHRcdHRoaXMuX3kgPSAoIG0xMiArIG0yMSApIC8gcztcblx0XHRcdHRoaXMuX3ogPSAoIG0xMyArIG0zMSApIC8gcztcblxuXHRcdH0gZWxzZSBpZiAoIG0yMiA+IG0zMyApIHtcblxuXHRcdFx0Y29uc3QgcyA9IDIuMCAqIE1hdGguc3FydCggMS4wICsgbTIyIC0gbTExIC0gbTMzICk7XG5cblx0XHRcdHRoaXMuX3cgPSAoIG0xMyAtIG0zMSApIC8gcztcblx0XHRcdHRoaXMuX3ggPSAoIG0xMiArIG0yMSApIC8gcztcblx0XHRcdHRoaXMuX3kgPSAwLjI1ICogcztcblx0XHRcdHRoaXMuX3ogPSAoIG0yMyArIG0zMiApIC8gcztcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGNvbnN0IHMgPSAyLjAgKiBNYXRoLnNxcnQoIDEuMCArIG0zMyAtIG0xMSAtIG0yMiApO1xuXG5cdFx0XHR0aGlzLl93ID0gKCBtMjEgLSBtMTIgKSAvIHM7XG5cdFx0XHR0aGlzLl94ID0gKCBtMTMgKyBtMzEgKSAvIHM7XG5cdFx0XHR0aGlzLl95ID0gKCBtMjMgKyBtMzIgKSAvIHM7XG5cdFx0XHR0aGlzLl96ID0gMC4yNSAqIHM7XG5cblx0XHR9XG5cblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbVVuaXRWZWN0b3JzKCB2RnJvbSwgdlRvICkge1xuXG5cdFx0Ly8gYXNzdW1lcyBkaXJlY3Rpb24gdmVjdG9ycyB2RnJvbSBhbmQgdlRvIGFyZSBub3JtYWxpemVkXG5cblx0XHRsZXQgciA9IHZGcm9tLmRvdCggdlRvICkgKyAxO1xuXG5cdFx0aWYgKCByIDwgTnVtYmVyLkVQU0lMT04gKSB7XG5cblx0XHRcdC8vIHZGcm9tIGFuZCB2VG8gcG9pbnQgaW4gb3Bwb3NpdGUgZGlyZWN0aW9uc1xuXG5cdFx0XHRyID0gMDtcblxuXHRcdFx0aWYgKCBNYXRoLmFicyggdkZyb20ueCApID4gTWF0aC5hYnMoIHZGcm9tLnogKSApIHtcblxuXHRcdFx0XHR0aGlzLl94ID0gLSB2RnJvbS55O1xuXHRcdFx0XHR0aGlzLl95ID0gdkZyb20ueDtcblx0XHRcdFx0dGhpcy5feiA9IDA7XG5cdFx0XHRcdHRoaXMuX3cgPSByO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHRoaXMuX3ggPSAwO1xuXHRcdFx0XHR0aGlzLl95ID0gLSB2RnJvbS56O1xuXHRcdFx0XHR0aGlzLl96ID0gdkZyb20ueTtcblx0XHRcdFx0dGhpcy5fdyA9IHI7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIGNyb3NzVmVjdG9ycyggdkZyb20sIHZUbyApOyAvLyBpbmxpbmVkIHRvIGF2b2lkIGN5Y2xpYyBkZXBlbmRlbmN5IG9uIFZlY3RvcjNcblxuXHRcdFx0dGhpcy5feCA9IHZGcm9tLnkgKiB2VG8ueiAtIHZGcm9tLnogKiB2VG8ueTtcblx0XHRcdHRoaXMuX3kgPSB2RnJvbS56ICogdlRvLnggLSB2RnJvbS54ICogdlRvLno7XG5cdFx0XHR0aGlzLl96ID0gdkZyb20ueCAqIHZUby55IC0gdkZyb20ueSAqIHZUby54O1xuXHRcdFx0dGhpcy5fdyA9IHI7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5ub3JtYWxpemUoKTtcblxuXHR9XG5cblx0YW5nbGVUbyggcSApIHtcblxuXHRcdHJldHVybiAyICogTWF0aC5hY29zKCBNYXRoLmFicyggY2xhbXAoIHRoaXMuZG90KCBxICksIC0gMSwgMSApICkgKTtcblxuXHR9XG5cblx0cm90YXRlVG93YXJkcyggcSwgc3RlcCApIHtcblxuXHRcdGNvbnN0IGFuZ2xlID0gdGhpcy5hbmdsZVRvKCBxICk7XG5cblx0XHRpZiAoIGFuZ2xlID09PSAwICkgcmV0dXJuIHRoaXM7XG5cblx0XHRjb25zdCB0ID0gTWF0aC5taW4oIDEsIHN0ZXAgLyBhbmdsZSApO1xuXG5cdFx0dGhpcy5zbGVycCggcSwgdCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGlkZW50aXR5KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuc2V0KCAwLCAwLCAwLCAxICk7XG5cblx0fVxuXG5cdGludmVydCgpIHtcblxuXHRcdC8vIHF1YXRlcm5pb24gaXMgYXNzdW1lZCB0byBoYXZlIHVuaXQgbGVuZ3RoXG5cblx0XHRyZXR1cm4gdGhpcy5jb25qdWdhdGUoKTtcblxuXHR9XG5cblx0Y29uanVnYXRlKCkge1xuXG5cdFx0dGhpcy5feCAqPSAtIDE7XG5cdFx0dGhpcy5feSAqPSAtIDE7XG5cdFx0dGhpcy5feiAqPSAtIDE7XG5cblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZG90KCB2ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3ggKiB2Ll94ICsgdGhpcy5feSAqIHYuX3kgKyB0aGlzLl96ICogdi5feiArIHRoaXMuX3cgKiB2Ll93O1xuXG5cdH1cblxuXHRsZW5ndGhTcSgpIHtcblxuXHRcdHJldHVybiB0aGlzLl94ICogdGhpcy5feCArIHRoaXMuX3kgKiB0aGlzLl95ICsgdGhpcy5feiAqIHRoaXMuX3ogKyB0aGlzLl93ICogdGhpcy5fdztcblxuXHR9XG5cblx0bGVuZ3RoKCkge1xuXG5cdFx0cmV0dXJuIE1hdGguc3FydCggdGhpcy5feCAqIHRoaXMuX3ggKyB0aGlzLl95ICogdGhpcy5feSArIHRoaXMuX3ogKiB0aGlzLl96ICsgdGhpcy5fdyAqIHRoaXMuX3cgKTtcblxuXHR9XG5cblx0bm9ybWFsaXplKCkge1xuXG5cdFx0bGV0IGwgPSB0aGlzLmxlbmd0aCgpO1xuXG5cdFx0aWYgKCBsID09PSAwICkge1xuXG5cdFx0XHR0aGlzLl94ID0gMDtcblx0XHRcdHRoaXMuX3kgPSAwO1xuXHRcdFx0dGhpcy5feiA9IDA7XG5cdFx0XHR0aGlzLl93ID0gMTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGwgPSAxIC8gbDtcblxuXHRcdFx0dGhpcy5feCA9IHRoaXMuX3ggKiBsO1xuXHRcdFx0dGhpcy5feSA9IHRoaXMuX3kgKiBsO1xuXHRcdFx0dGhpcy5feiA9IHRoaXMuX3ogKiBsO1xuXHRcdFx0dGhpcy5fdyA9IHRoaXMuX3cgKiBsO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5KCBxICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubXVsdGlwbHlRdWF0ZXJuaW9ucyggdGhpcywgcSApO1xuXG5cdH1cblxuXHRwcmVtdWx0aXBseSggcSApIHtcblxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5UXVhdGVybmlvbnMoIHEsIHRoaXMgKTtcblxuXHR9XG5cblx0bXVsdGlwbHlRdWF0ZXJuaW9ucyggYSwgYiApIHtcblxuXHRcdC8vIGZyb20gaHR0cDovL3d3dy5ldWNsaWRlYW5zcGFjZS5jb20vbWF0aHMvYWxnZWJyYS9yZWFsTm9ybWVkQWxnZWJyYS9xdWF0ZXJuaW9ucy9jb2RlL2luZGV4Lmh0bVxuXG5cdFx0Y29uc3QgcWF4ID0gYS5feCwgcWF5ID0gYS5feSwgcWF6ID0gYS5feiwgcWF3ID0gYS5fdztcblx0XHRjb25zdCBxYnggPSBiLl94LCBxYnkgPSBiLl95LCBxYnogPSBiLl96LCBxYncgPSBiLl93O1xuXG5cdFx0dGhpcy5feCA9IHFheCAqIHFidyArIHFhdyAqIHFieCArIHFheSAqIHFieiAtIHFheiAqIHFieTtcblx0XHR0aGlzLl95ID0gcWF5ICogcWJ3ICsgcWF3ICogcWJ5ICsgcWF6ICogcWJ4IC0gcWF4ICogcWJ6O1xuXHRcdHRoaXMuX3ogPSBxYXogKiBxYncgKyBxYXcgKiBxYnogKyBxYXggKiBxYnkgLSBxYXkgKiBxYng7XG5cdFx0dGhpcy5fdyA9IHFhdyAqIHFidyAtIHFheCAqIHFieCAtIHFheSAqIHFieSAtIHFheiAqIHFiejtcblxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzbGVycCggcWIsIHQgKSB7XG5cblx0XHRpZiAoIHQgPT09IDAgKSByZXR1cm4gdGhpcztcblx0XHRpZiAoIHQgPT09IDEgKSByZXR1cm4gdGhpcy5jb3B5KCBxYiApO1xuXG5cdFx0Y29uc3QgeCA9IHRoaXMuX3gsIHkgPSB0aGlzLl95LCB6ID0gdGhpcy5feiwgdyA9IHRoaXMuX3c7XG5cblx0XHQvLyBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9hbGdlYnJhL3JlYWxOb3JtZWRBbGdlYnJhL3F1YXRlcm5pb25zL3NsZXJwL1xuXG5cdFx0bGV0IGNvc0hhbGZUaGV0YSA9IHcgKiBxYi5fdyArIHggKiBxYi5feCArIHkgKiBxYi5feSArIHogKiBxYi5fejtcblxuXHRcdGlmICggY29zSGFsZlRoZXRhIDwgMCApIHtcblxuXHRcdFx0dGhpcy5fdyA9IC0gcWIuX3c7XG5cdFx0XHR0aGlzLl94ID0gLSBxYi5feDtcblx0XHRcdHRoaXMuX3kgPSAtIHFiLl95O1xuXHRcdFx0dGhpcy5feiA9IC0gcWIuX3o7XG5cblx0XHRcdGNvc0hhbGZUaGV0YSA9IC0gY29zSGFsZlRoZXRhO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhpcy5jb3B5KCBxYiApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBjb3NIYWxmVGhldGEgPj0gMS4wICkge1xuXG5cdFx0XHR0aGlzLl93ID0gdztcblx0XHRcdHRoaXMuX3ggPSB4O1xuXHRcdFx0dGhpcy5feSA9IHk7XG5cdFx0XHR0aGlzLl96ID0gejtcblxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHR9XG5cblx0XHRjb25zdCBzcXJTaW5IYWxmVGhldGEgPSAxLjAgLSBjb3NIYWxmVGhldGEgKiBjb3NIYWxmVGhldGE7XG5cblx0XHRpZiAoIHNxclNpbkhhbGZUaGV0YSA8PSBOdW1iZXIuRVBTSUxPTiApIHtcblxuXHRcdFx0Y29uc3QgcyA9IDEgLSB0O1xuXHRcdFx0dGhpcy5fdyA9IHMgKiB3ICsgdCAqIHRoaXMuX3c7XG5cdFx0XHR0aGlzLl94ID0gcyAqIHggKyB0ICogdGhpcy5feDtcblx0XHRcdHRoaXMuX3kgPSBzICogeSArIHQgKiB0aGlzLl95O1xuXHRcdFx0dGhpcy5feiA9IHMgKiB6ICsgdCAqIHRoaXMuX3o7XG5cblx0XHRcdHRoaXMubm9ybWFsaXplKCk7IC8vIG5vcm1hbGl6ZSBjYWxscyBfb25DaGFuZ2VDYWxsYmFjaygpXG5cblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3Qgc2luSGFsZlRoZXRhID0gTWF0aC5zcXJ0KCBzcXJTaW5IYWxmVGhldGEgKTtcblx0XHRjb25zdCBoYWxmVGhldGEgPSBNYXRoLmF0YW4yKCBzaW5IYWxmVGhldGEsIGNvc0hhbGZUaGV0YSApO1xuXHRcdGNvbnN0IHJhdGlvQSA9IE1hdGguc2luKCAoIDEgLSB0ICkgKiBoYWxmVGhldGEgKSAvIHNpbkhhbGZUaGV0YSxcblx0XHRcdHJhdGlvQiA9IE1hdGguc2luKCB0ICogaGFsZlRoZXRhICkgLyBzaW5IYWxmVGhldGE7XG5cblx0XHR0aGlzLl93ID0gKCB3ICogcmF0aW9BICsgdGhpcy5fdyAqIHJhdGlvQiApO1xuXHRcdHRoaXMuX3ggPSAoIHggKiByYXRpb0EgKyB0aGlzLl94ICogcmF0aW9CICk7XG5cdFx0dGhpcy5feSA9ICggeSAqIHJhdGlvQSArIHRoaXMuX3kgKiByYXRpb0IgKTtcblx0XHR0aGlzLl96ID0gKCB6ICogcmF0aW9BICsgdGhpcy5feiAqIHJhdGlvQiApO1xuXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNsZXJwUXVhdGVybmlvbnMoIHFhLCBxYiwgdCApIHtcblxuXHRcdHJldHVybiB0aGlzLmNvcHkoIHFhICkuc2xlcnAoIHFiLCB0ICk7XG5cblx0fVxuXG5cdHJhbmRvbSgpIHtcblxuXHRcdC8vIHNldHMgdGhpcyBxdWF0ZXJuaW9uIHRvIGEgdW5pZm9ybSByYW5kb20gdW5pdCBxdWF0ZXJubmlvblxuXG5cdFx0Ly8gS2VuIFNob2VtYWtlXG5cdFx0Ly8gVW5pZm9ybSByYW5kb20gcm90YXRpb25zXG5cdFx0Ly8gRC4gS2lyaywgZWRpdG9yLCBHcmFwaGljcyBHZW1zIElJSSwgcGFnZXMgMTI0LTEzMi4gQWNhZGVtaWMgUHJlc3MsIE5ldyBZb3JrLCAxOTkyLlxuXG5cdFx0Y29uc3QgdGhldGExID0gMiAqIE1hdGguUEkgKiBNYXRoLnJhbmRvbSgpO1xuXHRcdGNvbnN0IHRoZXRhMiA9IDIgKiBNYXRoLlBJICogTWF0aC5yYW5kb20oKTtcblxuXHRcdGNvbnN0IHgwID0gTWF0aC5yYW5kb20oKTtcblx0XHRjb25zdCByMSA9IE1hdGguc3FydCggMSAtIHgwICk7XG5cdFx0Y29uc3QgcjIgPSBNYXRoLnNxcnQoIHgwICk7XG5cblx0XHRyZXR1cm4gdGhpcy5zZXQoXG5cdFx0XHRyMSAqIE1hdGguc2luKCB0aGV0YTEgKSxcblx0XHRcdHIxICogTWF0aC5jb3MoIHRoZXRhMSApLFxuXHRcdFx0cjIgKiBNYXRoLnNpbiggdGhldGEyICksXG5cdFx0XHRyMiAqIE1hdGguY29zKCB0aGV0YTIgKSxcblx0XHQpO1xuXG5cdH1cblxuXHRlcXVhbHMoIHF1YXRlcm5pb24gKSB7XG5cblx0XHRyZXR1cm4gKCBxdWF0ZXJuaW9uLl94ID09PSB0aGlzLl94ICkgJiYgKCBxdWF0ZXJuaW9uLl95ID09PSB0aGlzLl95ICkgJiYgKCBxdWF0ZXJuaW9uLl96ID09PSB0aGlzLl96ICkgJiYgKCBxdWF0ZXJuaW9uLl93ID09PSB0aGlzLl93ICk7XG5cblx0fVxuXG5cdGZyb21BcnJheSggYXJyYXksIG9mZnNldCA9IDAgKSB7XG5cblx0XHR0aGlzLl94ID0gYXJyYXlbIG9mZnNldCBdO1xuXHRcdHRoaXMuX3kgPSBhcnJheVsgb2Zmc2V0ICsgMSBdO1xuXHRcdHRoaXMuX3ogPSBhcnJheVsgb2Zmc2V0ICsgMiBdO1xuXHRcdHRoaXMuX3cgPSBhcnJheVsgb2Zmc2V0ICsgMyBdO1xuXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvQXJyYXkoIGFycmF5ID0gW10sIG9mZnNldCA9IDAgKSB7XG5cblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLl94O1xuXHRcdGFycmF5WyBvZmZzZXQgKyAxIF0gPSB0aGlzLl95O1xuXHRcdGFycmF5WyBvZmZzZXQgKyAyIF0gPSB0aGlzLl96O1xuXHRcdGFycmF5WyBvZmZzZXQgKyAzIF0gPSB0aGlzLl93O1xuXG5cdFx0cmV0dXJuIGFycmF5O1xuXG5cdH1cblxuXHRmcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGluZGV4ICkge1xuXG5cdFx0dGhpcy5feCA9IGF0dHJpYnV0ZS5nZXRYKCBpbmRleCApO1xuXHRcdHRoaXMuX3kgPSBhdHRyaWJ1dGUuZ2V0WSggaW5kZXggKTtcblx0XHR0aGlzLl96ID0gYXR0cmlidXRlLmdldFooIGluZGV4ICk7XG5cdFx0dGhpcy5fdyA9IGF0dHJpYnV0ZS5nZXRXKCBpbmRleCApO1xuXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdHJldHVybiB0aGlzLnRvQXJyYXkoKTtcblxuXHR9XG5cblx0X29uQ2hhbmdlKCBjYWxsYmFjayApIHtcblxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2sgPSBjYWxsYmFjaztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRfb25DaGFuZ2VDYWxsYmFjaygpIHt9XG5cblx0KlsgU3ltYm9sLml0ZXJhdG9yIF0oKSB7XG5cblx0XHR5aWVsZCB0aGlzLl94O1xuXHRcdHlpZWxkIHRoaXMuX3k7XG5cdFx0eWllbGQgdGhpcy5fejtcblx0XHR5aWVsZCB0aGlzLl93O1xuXG5cdH1cblxufVxuXG5jbGFzcyBWZWN0b3IzIHtcblxuXHRjb25zdHJ1Y3RvciggeCA9IDAsIHkgPSAwLCB6ID0gMCApIHtcblxuXHRcdFZlY3RvcjMucHJvdG90eXBlLmlzVmVjdG9yMyA9IHRydWU7XG5cblx0XHR0aGlzLnggPSB4O1xuXHRcdHRoaXMueSA9IHk7XG5cdFx0dGhpcy56ID0gejtcblxuXHR9XG5cblx0c2V0KCB4LCB5LCB6ICkge1xuXG5cdFx0aWYgKCB6ID09PSB1bmRlZmluZWQgKSB6ID0gdGhpcy56OyAvLyBzcHJpdGUuc2NhbGUuc2V0KHgseSlcblxuXHRcdHRoaXMueCA9IHg7XG5cdFx0dGhpcy55ID0geTtcblx0XHR0aGlzLnogPSB6O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFNjYWxhciggc2NhbGFyICkge1xuXG5cdFx0dGhpcy54ID0gc2NhbGFyO1xuXHRcdHRoaXMueSA9IHNjYWxhcjtcblx0XHR0aGlzLnogPSBzY2FsYXI7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0WCggeCApIHtcblxuXHRcdHRoaXMueCA9IHg7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0WSggeSApIHtcblxuXHRcdHRoaXMueSA9IHk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0WiggeiApIHtcblxuXHRcdHRoaXMueiA9IHo7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0Q29tcG9uZW50KCBpbmRleCwgdmFsdWUgKSB7XG5cblx0XHRzd2l0Y2ggKCBpbmRleCApIHtcblxuXHRcdFx0Y2FzZSAwOiB0aGlzLnggPSB2YWx1ZTsgYnJlYWs7XG5cdFx0XHRjYXNlIDE6IHRoaXMueSA9IHZhbHVlOyBicmVhaztcblx0XHRcdGNhc2UgMjogdGhpcy56ID0gdmFsdWU7IGJyZWFrO1xuXHRcdFx0ZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKCAnaW5kZXggaXMgb3V0IG9mIHJhbmdlOiAnICsgaW5kZXggKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRDb21wb25lbnQoIGluZGV4ICkge1xuXG5cdFx0c3dpdGNoICggaW5kZXggKSB7XG5cblx0XHRcdGNhc2UgMDogcmV0dXJuIHRoaXMueDtcblx0XHRcdGNhc2UgMTogcmV0dXJuIHRoaXMueTtcblx0XHRcdGNhc2UgMjogcmV0dXJuIHRoaXMuejtcblx0XHRcdGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvciggJ2luZGV4IGlzIG91dCBvZiByYW5nZTogJyArIGluZGV4ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCB0aGlzLngsIHRoaXMueSwgdGhpcy56ICk7XG5cblx0fVxuXG5cdGNvcHkoIHYgKSB7XG5cblx0XHR0aGlzLnggPSB2Lng7XG5cdFx0dGhpcy55ID0gdi55O1xuXHRcdHRoaXMueiA9IHYuejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhZGQoIHYgKSB7XG5cblx0XHR0aGlzLnggKz0gdi54O1xuXHRcdHRoaXMueSArPSB2Lnk7XG5cdFx0dGhpcy56ICs9IHYuejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhZGRTY2FsYXIoIHMgKSB7XG5cblx0XHR0aGlzLnggKz0gcztcblx0XHR0aGlzLnkgKz0gcztcblx0XHR0aGlzLnogKz0gcztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhZGRWZWN0b3JzKCBhLCBiICkge1xuXG5cdFx0dGhpcy54ID0gYS54ICsgYi54O1xuXHRcdHRoaXMueSA9IGEueSArIGIueTtcblx0XHR0aGlzLnogPSBhLnogKyBiLno7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkU2NhbGVkVmVjdG9yKCB2LCBzICkge1xuXG5cdFx0dGhpcy54ICs9IHYueCAqIHM7XG5cdFx0dGhpcy55ICs9IHYueSAqIHM7XG5cdFx0dGhpcy56ICs9IHYueiAqIHM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3ViKCB2ICkge1xuXG5cdFx0dGhpcy54IC09IHYueDtcblx0XHR0aGlzLnkgLT0gdi55O1xuXHRcdHRoaXMueiAtPSB2Lno7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3ViU2NhbGFyKCBzICkge1xuXG5cdFx0dGhpcy54IC09IHM7XG5cdFx0dGhpcy55IC09IHM7XG5cdFx0dGhpcy56IC09IHM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3ViVmVjdG9ycyggYSwgYiApIHtcblxuXHRcdHRoaXMueCA9IGEueCAtIGIueDtcblx0XHR0aGlzLnkgPSBhLnkgLSBiLnk7XG5cdFx0dGhpcy56ID0gYS56IC0gYi56O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5KCB2ICkge1xuXG5cdFx0dGhpcy54ICo9IHYueDtcblx0XHR0aGlzLnkgKj0gdi55O1xuXHRcdHRoaXMueiAqPSB2Lno7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bXVsdGlwbHlTY2FsYXIoIHNjYWxhciApIHtcblxuXHRcdHRoaXMueCAqPSBzY2FsYXI7XG5cdFx0dGhpcy55ICo9IHNjYWxhcjtcblx0XHR0aGlzLnogKj0gc2NhbGFyO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5VmVjdG9ycyggYSwgYiApIHtcblxuXHRcdHRoaXMueCA9IGEueCAqIGIueDtcblx0XHR0aGlzLnkgPSBhLnkgKiBiLnk7XG5cdFx0dGhpcy56ID0gYS56ICogYi56O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFwcGx5RXVsZXIoIGV1bGVyICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuYXBwbHlRdWF0ZXJuaW9uKCBfcXVhdGVybmlvbiQ0LnNldEZyb21FdWxlciggZXVsZXIgKSApO1xuXG5cdH1cblxuXHRhcHBseUF4aXNBbmdsZSggYXhpcywgYW5nbGUgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5hcHBseVF1YXRlcm5pb24oIF9xdWF0ZXJuaW9uJDQuc2V0RnJvbUF4aXNBbmdsZSggYXhpcywgYW5nbGUgKSApO1xuXG5cdH1cblxuXHRhcHBseU1hdHJpeDMoIG0gKSB7XG5cblx0XHRjb25zdCB4ID0gdGhpcy54LCB5ID0gdGhpcy55LCB6ID0gdGhpcy56O1xuXHRcdGNvbnN0IGUgPSBtLmVsZW1lbnRzO1xuXG5cdFx0dGhpcy54ID0gZVsgMCBdICogeCArIGVbIDMgXSAqIHkgKyBlWyA2IF0gKiB6O1xuXHRcdHRoaXMueSA9IGVbIDEgXSAqIHggKyBlWyA0IF0gKiB5ICsgZVsgNyBdICogejtcblx0XHR0aGlzLnogPSBlWyAyIF0gKiB4ICsgZVsgNSBdICogeSArIGVbIDggXSAqIHo7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXBwbHlOb3JtYWxNYXRyaXgoIG0gKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5hcHBseU1hdHJpeDMoIG0gKS5ub3JtYWxpemUoKTtcblxuXHR9XG5cblx0YXBwbHlNYXRyaXg0KCBtICkge1xuXG5cdFx0Y29uc3QgeCA9IHRoaXMueCwgeSA9IHRoaXMueSwgeiA9IHRoaXMuejtcblx0XHRjb25zdCBlID0gbS5lbGVtZW50cztcblxuXHRcdGNvbnN0IHcgPSAxIC8gKCBlWyAzIF0gKiB4ICsgZVsgNyBdICogeSArIGVbIDExIF0gKiB6ICsgZVsgMTUgXSApO1xuXG5cdFx0dGhpcy54ID0gKCBlWyAwIF0gKiB4ICsgZVsgNCBdICogeSArIGVbIDggXSAqIHogKyBlWyAxMiBdICkgKiB3O1xuXHRcdHRoaXMueSA9ICggZVsgMSBdICogeCArIGVbIDUgXSAqIHkgKyBlWyA5IF0gKiB6ICsgZVsgMTMgXSApICogdztcblx0XHR0aGlzLnogPSAoIGVbIDIgXSAqIHggKyBlWyA2IF0gKiB5ICsgZVsgMTAgXSAqIHogKyBlWyAxNCBdICkgKiB3O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFwcGx5UXVhdGVybmlvbiggcSApIHtcblxuXHRcdC8vIHF1YXRlcm5pb24gcSBpcyBhc3N1bWVkIHRvIGhhdmUgdW5pdCBsZW5ndGhcblxuXHRcdGNvbnN0IHZ4ID0gdGhpcy54LCB2eSA9IHRoaXMueSwgdnogPSB0aGlzLno7XG5cdFx0Y29uc3QgcXggPSBxLngsIHF5ID0gcS55LCBxeiA9IHEueiwgcXcgPSBxLnc7XG5cblx0XHQvLyB0ID0gMiAqIGNyb3NzKCBxLnh5eiwgdiApO1xuXHRcdGNvbnN0IHR4ID0gMiAqICggcXkgKiB2eiAtIHF6ICogdnkgKTtcblx0XHRjb25zdCB0eSA9IDIgKiAoIHF6ICogdnggLSBxeCAqIHZ6ICk7XG5cdFx0Y29uc3QgdHogPSAyICogKCBxeCAqIHZ5IC0gcXkgKiB2eCApO1xuXG5cdFx0Ly8gdiArIHEudyAqIHQgKyBjcm9zcyggcS54eXosIHQgKTtcblx0XHR0aGlzLnggPSB2eCArIHF3ICogdHggKyBxeSAqIHR6IC0gcXogKiB0eTtcblx0XHR0aGlzLnkgPSB2eSArIHF3ICogdHkgKyBxeiAqIHR4IC0gcXggKiB0ejtcblx0XHR0aGlzLnogPSB2eiArIHF3ICogdHogKyBxeCAqIHR5IC0gcXkgKiB0eDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRwcm9qZWN0KCBjYW1lcmEgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5hcHBseU1hdHJpeDQoIGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UgKS5hcHBseU1hdHJpeDQoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4ICk7XG5cblx0fVxuXG5cdHVucHJvamVjdCggY2FtZXJhICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuYXBwbHlNYXRyaXg0KCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKS5hcHBseU1hdHJpeDQoIGNhbWVyYS5tYXRyaXhXb3JsZCApO1xuXG5cdH1cblxuXHR0cmFuc2Zvcm1EaXJlY3Rpb24oIG0gKSB7XG5cblx0XHQvLyBpbnB1dDogVEhSRUUuTWF0cml4NCBhZmZpbmUgbWF0cml4XG5cdFx0Ly8gdmVjdG9yIGludGVycHJldGVkIGFzIGEgZGlyZWN0aW9uXG5cblx0XHRjb25zdCB4ID0gdGhpcy54LCB5ID0gdGhpcy55LCB6ID0gdGhpcy56O1xuXHRcdGNvbnN0IGUgPSBtLmVsZW1lbnRzO1xuXG5cdFx0dGhpcy54ID0gZVsgMCBdICogeCArIGVbIDQgXSAqIHkgKyBlWyA4IF0gKiB6O1xuXHRcdHRoaXMueSA9IGVbIDEgXSAqIHggKyBlWyA1IF0gKiB5ICsgZVsgOSBdICogejtcblx0XHR0aGlzLnogPSBlWyAyIF0gKiB4ICsgZVsgNiBdICogeSArIGVbIDEwIF0gKiB6O1xuXG5cdFx0cmV0dXJuIHRoaXMubm9ybWFsaXplKCk7XG5cblx0fVxuXG5cdGRpdmlkZSggdiApIHtcblxuXHRcdHRoaXMueCAvPSB2Lng7XG5cdFx0dGhpcy55IC89IHYueTtcblx0XHR0aGlzLnogLz0gdi56O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRpdmlkZVNjYWxhciggc2NhbGFyICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubXVsdGlwbHlTY2FsYXIoIDEgLyBzY2FsYXIgKTtcblxuXHR9XG5cblx0bWluKCB2ICkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC5taW4oIHRoaXMueCwgdi54ICk7XG5cdFx0dGhpcy55ID0gTWF0aC5taW4oIHRoaXMueSwgdi55ICk7XG5cdFx0dGhpcy56ID0gTWF0aC5taW4oIHRoaXMueiwgdi56ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bWF4KCB2ICkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC5tYXgoIHRoaXMueCwgdi54ICk7XG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIHRoaXMueSwgdi55ICk7XG5cdFx0dGhpcy56ID0gTWF0aC5tYXgoIHRoaXMueiwgdi56ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xhbXAoIG1pbiwgbWF4ICkge1xuXG5cdFx0Ly8gYXNzdW1lcyBtaW4gPCBtYXgsIGNvbXBvbmVudHdpc2VcblxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCBtaW4ueCwgTWF0aC5taW4oIG1heC54LCB0aGlzLnggKSApO1xuXHRcdHRoaXMueSA9IE1hdGgubWF4KCBtaW4ueSwgTWF0aC5taW4oIG1heC55LCB0aGlzLnkgKSApO1xuXHRcdHRoaXMueiA9IE1hdGgubWF4KCBtaW4ueiwgTWF0aC5taW4oIG1heC56LCB0aGlzLnogKSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsYW1wU2NhbGFyKCBtaW5WYWwsIG1heFZhbCApIHtcblxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCBtaW5WYWwsIE1hdGgubWluKCBtYXhWYWwsIHRoaXMueCApICk7XG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIG1pblZhbCwgTWF0aC5taW4oIG1heFZhbCwgdGhpcy55ICkgKTtcblx0XHR0aGlzLnogPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnogKSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsYW1wTGVuZ3RoKCBtaW4sIG1heCApIHtcblxuXHRcdGNvbnN0IGxlbmd0aCA9IHRoaXMubGVuZ3RoKCk7XG5cblx0XHRyZXR1cm4gdGhpcy5kaXZpZGVTY2FsYXIoIGxlbmd0aCB8fCAxICkubXVsdGlwbHlTY2FsYXIoIE1hdGgubWF4KCBtaW4sIE1hdGgubWluKCBtYXgsIGxlbmd0aCApICkgKTtcblxuXHR9XG5cblx0Zmxvb3IoKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLmZsb29yKCB0aGlzLnggKTtcblx0XHR0aGlzLnkgPSBNYXRoLmZsb29yKCB0aGlzLnkgKTtcblx0XHR0aGlzLnogPSBNYXRoLmZsb29yKCB0aGlzLnogKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjZWlsKCkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC5jZWlsKCB0aGlzLnggKTtcblx0XHR0aGlzLnkgPSBNYXRoLmNlaWwoIHRoaXMueSApO1xuXHRcdHRoaXMueiA9IE1hdGguY2VpbCggdGhpcy56ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cm91bmQoKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLnJvdW5kKCB0aGlzLnggKTtcblx0XHR0aGlzLnkgPSBNYXRoLnJvdW5kKCB0aGlzLnkgKTtcblx0XHR0aGlzLnogPSBNYXRoLnJvdW5kKCB0aGlzLnogKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyb3VuZFRvWmVybygpIHtcblxuXHRcdHRoaXMueCA9IE1hdGgudHJ1bmMoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGgudHJ1bmMoIHRoaXMueSApO1xuXHRcdHRoaXMueiA9IE1hdGgudHJ1bmMoIHRoaXMueiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG5lZ2F0ZSgpIHtcblxuXHRcdHRoaXMueCA9IC0gdGhpcy54O1xuXHRcdHRoaXMueSA9IC0gdGhpcy55O1xuXHRcdHRoaXMueiA9IC0gdGhpcy56O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRvdCggdiApIHtcblxuXHRcdHJldHVybiB0aGlzLnggKiB2LnggKyB0aGlzLnkgKiB2LnkgKyB0aGlzLnogKiB2Lno7XG5cblx0fVxuXG5cdC8vIFRPRE8gbGVuZ3RoU3F1YXJlZD9cblxuXHRsZW5ndGhTcSgpIHtcblxuXHRcdHJldHVybiB0aGlzLnggKiB0aGlzLnggKyB0aGlzLnkgKiB0aGlzLnkgKyB0aGlzLnogKiB0aGlzLno7XG5cblx0fVxuXG5cdGxlbmd0aCgpIHtcblxuXHRcdHJldHVybiBNYXRoLnNxcnQoIHRoaXMueCAqIHRoaXMueCArIHRoaXMueSAqIHRoaXMueSArIHRoaXMueiAqIHRoaXMueiApO1xuXG5cdH1cblxuXHRtYW5oYXR0YW5MZW5ndGgoKSB7XG5cblx0XHRyZXR1cm4gTWF0aC5hYnMoIHRoaXMueCApICsgTWF0aC5hYnMoIHRoaXMueSApICsgTWF0aC5hYnMoIHRoaXMueiApO1xuXG5cdH1cblxuXHRub3JtYWxpemUoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5kaXZpZGVTY2FsYXIoIHRoaXMubGVuZ3RoKCkgfHwgMSApO1xuXG5cdH1cblxuXHRzZXRMZW5ndGgoIGxlbmd0aCApIHtcblxuXHRcdHJldHVybiB0aGlzLm5vcm1hbGl6ZSgpLm11bHRpcGx5U2NhbGFyKCBsZW5ndGggKTtcblxuXHR9XG5cblx0bGVycCggdiwgYWxwaGEgKSB7XG5cblx0XHR0aGlzLnggKz0gKCB2LnggLSB0aGlzLnggKSAqIGFscGhhO1xuXHRcdHRoaXMueSArPSAoIHYueSAtIHRoaXMueSApICogYWxwaGE7XG5cdFx0dGhpcy56ICs9ICggdi56IC0gdGhpcy56ICkgKiBhbHBoYTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRsZXJwVmVjdG9ycyggdjEsIHYyLCBhbHBoYSApIHtcblxuXHRcdHRoaXMueCA9IHYxLnggKyAoIHYyLnggLSB2MS54ICkgKiBhbHBoYTtcblx0XHR0aGlzLnkgPSB2MS55ICsgKCB2Mi55IC0gdjEueSApICogYWxwaGE7XG5cdFx0dGhpcy56ID0gdjEueiArICggdjIueiAtIHYxLnogKSAqIGFscGhhO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNyb3NzKCB2ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuY3Jvc3NWZWN0b3JzKCB0aGlzLCB2ICk7XG5cblx0fVxuXG5cdGNyb3NzVmVjdG9ycyggYSwgYiApIHtcblxuXHRcdGNvbnN0IGF4ID0gYS54LCBheSA9IGEueSwgYXogPSBhLno7XG5cdFx0Y29uc3QgYnggPSBiLngsIGJ5ID0gYi55LCBieiA9IGIuejtcblxuXHRcdHRoaXMueCA9IGF5ICogYnogLSBheiAqIGJ5O1xuXHRcdHRoaXMueSA9IGF6ICogYnggLSBheCAqIGJ6O1xuXHRcdHRoaXMueiA9IGF4ICogYnkgLSBheSAqIGJ4O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHByb2plY3RPblZlY3RvciggdiApIHtcblxuXHRcdGNvbnN0IGRlbm9taW5hdG9yID0gdi5sZW5ndGhTcSgpO1xuXG5cdFx0aWYgKCBkZW5vbWluYXRvciA9PT0gMCApIHJldHVybiB0aGlzLnNldCggMCwgMCwgMCApO1xuXG5cdFx0Y29uc3Qgc2NhbGFyID0gdi5kb3QoIHRoaXMgKSAvIGRlbm9taW5hdG9yO1xuXG5cdFx0cmV0dXJuIHRoaXMuY29weSggdiApLm11bHRpcGx5U2NhbGFyKCBzY2FsYXIgKTtcblxuXHR9XG5cblx0cHJvamVjdE9uUGxhbmUoIHBsYW5lTm9ybWFsICkge1xuXG5cdFx0X3ZlY3RvciRjLmNvcHkoIHRoaXMgKS5wcm9qZWN0T25WZWN0b3IoIHBsYW5lTm9ybWFsICk7XG5cblx0XHRyZXR1cm4gdGhpcy5zdWIoIF92ZWN0b3IkYyApO1xuXG5cdH1cblxuXHRyZWZsZWN0KCBub3JtYWwgKSB7XG5cblx0XHQvLyByZWZsZWN0IGluY2lkZW50IHZlY3RvciBvZmYgcGxhbmUgb3J0aG9nb25hbCB0byBub3JtYWxcblx0XHQvLyBub3JtYWwgaXMgYXNzdW1lZCB0byBoYXZlIHVuaXQgbGVuZ3RoXG5cblx0XHRyZXR1cm4gdGhpcy5zdWIoIF92ZWN0b3IkYy5jb3B5KCBub3JtYWwgKS5tdWx0aXBseVNjYWxhciggMiAqIHRoaXMuZG90KCBub3JtYWwgKSApICk7XG5cblx0fVxuXG5cdGFuZ2xlVG8oIHYgKSB7XG5cblx0XHRjb25zdCBkZW5vbWluYXRvciA9IE1hdGguc3FydCggdGhpcy5sZW5ndGhTcSgpICogdi5sZW5ndGhTcSgpICk7XG5cblx0XHRpZiAoIGRlbm9taW5hdG9yID09PSAwICkgcmV0dXJuIE1hdGguUEkgLyAyO1xuXG5cdFx0Y29uc3QgdGhldGEgPSB0aGlzLmRvdCggdiApIC8gZGVub21pbmF0b3I7XG5cblx0XHQvLyBjbGFtcCwgdG8gaGFuZGxlIG51bWVyaWNhbCBwcm9ibGVtc1xuXG5cdFx0cmV0dXJuIE1hdGguYWNvcyggY2xhbXAoIHRoZXRhLCAtIDEsIDEgKSApO1xuXG5cdH1cblxuXHRkaXN0YW5jZVRvKCB2ICkge1xuXG5cdFx0cmV0dXJuIE1hdGguc3FydCggdGhpcy5kaXN0YW5jZVRvU3F1YXJlZCggdiApICk7XG5cblx0fVxuXG5cdGRpc3RhbmNlVG9TcXVhcmVkKCB2ICkge1xuXG5cdFx0Y29uc3QgZHggPSB0aGlzLnggLSB2LngsIGR5ID0gdGhpcy55IC0gdi55LCBkeiA9IHRoaXMueiAtIHYuejtcblxuXHRcdHJldHVybiBkeCAqIGR4ICsgZHkgKiBkeSArIGR6ICogZHo7XG5cblx0fVxuXG5cdG1hbmhhdHRhbkRpc3RhbmNlVG8oIHYgKSB7XG5cblx0XHRyZXR1cm4gTWF0aC5hYnMoIHRoaXMueCAtIHYueCApICsgTWF0aC5hYnMoIHRoaXMueSAtIHYueSApICsgTWF0aC5hYnMoIHRoaXMueiAtIHYueiApO1xuXG5cdH1cblxuXHRzZXRGcm9tU3BoZXJpY2FsKCBzICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuc2V0RnJvbVNwaGVyaWNhbENvb3Jkcyggcy5yYWRpdXMsIHMucGhpLCBzLnRoZXRhICk7XG5cblx0fVxuXG5cdHNldEZyb21TcGhlcmljYWxDb29yZHMoIHJhZGl1cywgcGhpLCB0aGV0YSApIHtcblxuXHRcdGNvbnN0IHNpblBoaVJhZGl1cyA9IE1hdGguc2luKCBwaGkgKSAqIHJhZGl1cztcblxuXHRcdHRoaXMueCA9IHNpblBoaVJhZGl1cyAqIE1hdGguc2luKCB0aGV0YSApO1xuXHRcdHRoaXMueSA9IE1hdGguY29zKCBwaGkgKSAqIHJhZGl1cztcblx0XHR0aGlzLnogPSBzaW5QaGlSYWRpdXMgKiBNYXRoLmNvcyggdGhldGEgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tQ3lsaW5kcmljYWwoIGMgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5zZXRGcm9tQ3lsaW5kcmljYWxDb29yZHMoIGMucmFkaXVzLCBjLnRoZXRhLCBjLnkgKTtcblxuXHR9XG5cblx0c2V0RnJvbUN5bGluZHJpY2FsQ29vcmRzKCByYWRpdXMsIHRoZXRhLCB5ICkge1xuXG5cdFx0dGhpcy54ID0gcmFkaXVzICogTWF0aC5zaW4oIHRoZXRhICk7XG5cdFx0dGhpcy55ID0geTtcblx0XHR0aGlzLnogPSByYWRpdXMgKiBNYXRoLmNvcyggdGhldGEgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tTWF0cml4UG9zaXRpb24oIG0gKSB7XG5cblx0XHRjb25zdCBlID0gbS5lbGVtZW50cztcblxuXHRcdHRoaXMueCA9IGVbIDEyIF07XG5cdFx0dGhpcy55ID0gZVsgMTMgXTtcblx0XHR0aGlzLnogPSBlWyAxNCBdO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21NYXRyaXhTY2FsZSggbSApIHtcblxuXHRcdGNvbnN0IHN4ID0gdGhpcy5zZXRGcm9tTWF0cml4Q29sdW1uKCBtLCAwICkubGVuZ3RoKCk7XG5cdFx0Y29uc3Qgc3kgPSB0aGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIG0sIDEgKS5sZW5ndGgoKTtcblx0XHRjb25zdCBzeiA9IHRoaXMuc2V0RnJvbU1hdHJpeENvbHVtbiggbSwgMiApLmxlbmd0aCgpO1xuXG5cdFx0dGhpcy54ID0gc3g7XG5cdFx0dGhpcy55ID0gc3k7XG5cdFx0dGhpcy56ID0gc3o7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbU1hdHJpeENvbHVtbiggbSwgaW5kZXggKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5mcm9tQXJyYXkoIG0uZWxlbWVudHMsIGluZGV4ICogNCApO1xuXG5cdH1cblxuXHRzZXRGcm9tTWF0cml4M0NvbHVtbiggbSwgaW5kZXggKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5mcm9tQXJyYXkoIG0uZWxlbWVudHMsIGluZGV4ICogMyApO1xuXG5cdH1cblxuXHRzZXRGcm9tRXVsZXIoIGUgKSB7XG5cblx0XHR0aGlzLnggPSBlLl94O1xuXHRcdHRoaXMueSA9IGUuX3k7XG5cdFx0dGhpcy56ID0gZS5fejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tQ29sb3IoIGMgKSB7XG5cblx0XHR0aGlzLnggPSBjLnI7XG5cdFx0dGhpcy55ID0gYy5nO1xuXHRcdHRoaXMueiA9IGMuYjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRlcXVhbHMoIHYgKSB7XG5cblx0XHRyZXR1cm4gKCAoIHYueCA9PT0gdGhpcy54ICkgJiYgKCB2LnkgPT09IHRoaXMueSApICYmICggdi56ID09PSB0aGlzLnogKSApO1xuXG5cdH1cblxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xuXG5cdFx0dGhpcy54ID0gYXJyYXlbIG9mZnNldCBdO1xuXHRcdHRoaXMueSA9IGFycmF5WyBvZmZzZXQgKyAxIF07XG5cdFx0dGhpcy56ID0gYXJyYXlbIG9mZnNldCArIDIgXTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0FycmF5KCBhcnJheSA9IFtdLCBvZmZzZXQgPSAwICkge1xuXG5cdFx0YXJyYXlbIG9mZnNldCBdID0gdGhpcy54O1xuXHRcdGFycmF5WyBvZmZzZXQgKyAxIF0gPSB0aGlzLnk7XG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRoaXMuejtcblxuXHRcdHJldHVybiBhcnJheTtcblxuXHR9XG5cblx0ZnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpbmRleCApIHtcblxuXHRcdHRoaXMueCA9IGF0dHJpYnV0ZS5nZXRYKCBpbmRleCApO1xuXHRcdHRoaXMueSA9IGF0dHJpYnV0ZS5nZXRZKCBpbmRleCApO1xuXHRcdHRoaXMueiA9IGF0dHJpYnV0ZS5nZXRaKCBpbmRleCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJhbmRvbSgpIHtcblxuXHRcdHRoaXMueCA9IE1hdGgucmFuZG9tKCk7XG5cdFx0dGhpcy55ID0gTWF0aC5yYW5kb20oKTtcblx0XHR0aGlzLnogPSBNYXRoLnJhbmRvbSgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJhbmRvbURpcmVjdGlvbigpIHtcblxuXHRcdC8vIGh0dHBzOi8vbWF0aHdvcmxkLndvbGZyYW0uY29tL1NwaGVyZVBvaW50UGlja2luZy5odG1sXG5cblx0XHRjb25zdCB0aGV0YSA9IE1hdGgucmFuZG9tKCkgKiBNYXRoLlBJICogMjtcblx0XHRjb25zdCB1ID0gTWF0aC5yYW5kb20oKSAqIDIgLSAxO1xuXHRcdGNvbnN0IGMgPSBNYXRoLnNxcnQoIDEgLSB1ICogdSApO1xuXG5cdFx0dGhpcy54ID0gYyAqIE1hdGguY29zKCB0aGV0YSApO1xuXHRcdHRoaXMueSA9IHU7XG5cdFx0dGhpcy56ID0gYyAqIE1hdGguc2luKCB0aGV0YSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdCpbIFN5bWJvbC5pdGVyYXRvciBdKCkge1xuXG5cdFx0eWllbGQgdGhpcy54O1xuXHRcdHlpZWxkIHRoaXMueTtcblx0XHR5aWVsZCB0aGlzLno7XG5cblx0fVxuXG59XG5cbmNvbnN0IF92ZWN0b3IkYyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9xdWF0ZXJuaW9uJDQgPSAvKkBfX1BVUkVfXyovIG5ldyBRdWF0ZXJuaW9uKCk7XG5cbmNsYXNzIEJveDMge1xuXG5cdGNvbnN0cnVjdG9yKCBtaW4gPSBuZXcgVmVjdG9yMyggKyBJbmZpbml0eSwgKyBJbmZpbml0eSwgKyBJbmZpbml0eSApLCBtYXggPSBuZXcgVmVjdG9yMyggLSBJbmZpbml0eSwgLSBJbmZpbml0eSwgLSBJbmZpbml0eSApICkge1xuXG5cdFx0dGhpcy5pc0JveDMgPSB0cnVlO1xuXG5cdFx0dGhpcy5taW4gPSBtaW47XG5cdFx0dGhpcy5tYXggPSBtYXg7XG5cblx0fVxuXG5cdHNldCggbWluLCBtYXggKSB7XG5cblx0XHR0aGlzLm1pbi5jb3B5KCBtaW4gKTtcblx0XHR0aGlzLm1heC5jb3B5KCBtYXggKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tQXJyYXkoIGFycmF5ICkge1xuXG5cdFx0dGhpcy5tYWtlRW1wdHkoKTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBhcnJheS5sZW5ndGg7IGkgPCBpbDsgaSArPSAzICkge1xuXG5cdFx0XHR0aGlzLmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IkYi5mcm9tQXJyYXkoIGFycmF5LCBpICkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUgKSB7XG5cblx0XHR0aGlzLm1ha2VFbXB0eSgpO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGF0dHJpYnV0ZS5jb3VudDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IkYi5mcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGkgKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21Qb2ludHMoIHBvaW50cyApIHtcblxuXHRcdHRoaXMubWFrZUVtcHR5KCk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gcG9pbnRzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmV4cGFuZEJ5UG9pbnQoIHBvaW50c1sgaSBdICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbUNlbnRlckFuZFNpemUoIGNlbnRlciwgc2l6ZSApIHtcblxuXHRcdGNvbnN0IGhhbGZTaXplID0gX3ZlY3RvciRiLmNvcHkoIHNpemUgKS5tdWx0aXBseVNjYWxhciggMC41ICk7XG5cblx0XHR0aGlzLm1pbi5jb3B5KCBjZW50ZXIgKS5zdWIoIGhhbGZTaXplICk7XG5cdFx0dGhpcy5tYXguY29weSggY2VudGVyICkuYWRkKCBoYWxmU2l6ZSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21PYmplY3QoIG9iamVjdCwgcHJlY2lzZSA9IGZhbHNlICkge1xuXG5cdFx0dGhpcy5tYWtlRW1wdHkoKTtcblxuXHRcdHJldHVybiB0aGlzLmV4cGFuZEJ5T2JqZWN0KCBvYmplY3QsIHByZWNpc2UgKTtcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG5cdGNvcHkoIGJveCApIHtcblxuXHRcdHRoaXMubWluLmNvcHkoIGJveC5taW4gKTtcblx0XHR0aGlzLm1heC5jb3B5KCBib3gubWF4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bWFrZUVtcHR5KCkge1xuXG5cdFx0dGhpcy5taW4ueCA9IHRoaXMubWluLnkgPSB0aGlzLm1pbi56ID0gKyBJbmZpbml0eTtcblx0XHR0aGlzLm1heC54ID0gdGhpcy5tYXgueSA9IHRoaXMubWF4LnogPSAtIEluZmluaXR5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGlzRW1wdHkoKSB7XG5cblx0XHQvLyB0aGlzIGlzIGEgbW9yZSByb2J1c3QgY2hlY2sgZm9yIGVtcHR5IHRoYW4gKCB2b2x1bWUgPD0gMCApIGJlY2F1c2Ugdm9sdW1lIGNhbiBnZXQgcG9zaXRpdmUgd2l0aCB0d28gbmVnYXRpdmUgYXhlc1xuXG5cdFx0cmV0dXJuICggdGhpcy5tYXgueCA8IHRoaXMubWluLnggKSB8fCAoIHRoaXMubWF4LnkgPCB0aGlzLm1pbi55ICkgfHwgKCB0aGlzLm1heC56IDwgdGhpcy5taW4ueiApO1xuXG5cdH1cblxuXHRnZXRDZW50ZXIoIHRhcmdldCApIHtcblxuXHRcdHJldHVybiB0aGlzLmlzRW1wdHkoKSA/IHRhcmdldC5zZXQoIDAsIDAsIDAgKSA6IHRhcmdldC5hZGRWZWN0b3JzKCB0aGlzLm1pbiwgdGhpcy5tYXggKS5tdWx0aXBseVNjYWxhciggMC41ICk7XG5cblx0fVxuXG5cdGdldFNpemUoIHRhcmdldCApIHtcblxuXHRcdHJldHVybiB0aGlzLmlzRW1wdHkoKSA/IHRhcmdldC5zZXQoIDAsIDAsIDAgKSA6IHRhcmdldC5zdWJWZWN0b3JzKCB0aGlzLm1heCwgdGhpcy5taW4gKTtcblxuXHR9XG5cblx0ZXhwYW5kQnlQb2ludCggcG9pbnQgKSB7XG5cblx0XHR0aGlzLm1pbi5taW4oIHBvaW50ICk7XG5cdFx0dGhpcy5tYXgubWF4KCBwb2ludCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGV4cGFuZEJ5VmVjdG9yKCB2ZWN0b3IgKSB7XG5cblx0XHR0aGlzLm1pbi5zdWIoIHZlY3RvciApO1xuXHRcdHRoaXMubWF4LmFkZCggdmVjdG9yICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXhwYW5kQnlTY2FsYXIoIHNjYWxhciApIHtcblxuXHRcdHRoaXMubWluLmFkZFNjYWxhciggLSBzY2FsYXIgKTtcblx0XHR0aGlzLm1heC5hZGRTY2FsYXIoIHNjYWxhciApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGV4cGFuZEJ5T2JqZWN0KCBvYmplY3QsIHByZWNpc2UgPSBmYWxzZSApIHtcblxuXHRcdC8vIENvbXB1dGVzIHRoZSB3b3JsZC1heGlzLWFsaWduZWQgYm91bmRpbmcgYm94IG9mIGFuIG9iamVjdCAoaW5jbHVkaW5nIGl0cyBjaGlsZHJlbiksXG5cdFx0Ly8gYWNjb3VudGluZyBmb3IgYm90aCB0aGUgb2JqZWN0J3MsIGFuZCBjaGlsZHJlbidzLCB3b3JsZCB0cmFuc2Zvcm1zXG5cblx0XHRvYmplY3QudXBkYXRlV29ybGRNYXRyaXgoIGZhbHNlLCBmYWxzZSApO1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBvYmplY3QuZ2VvbWV0cnk7XG5cblx0XHRpZiAoIGdlb21ldHJ5ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XG5cblx0XHRcdC8vIHByZWNpc2UgQUFCQiBjb21wdXRhdGlvbiBiYXNlZCBvbiB2ZXJ0ZXggZGF0YSByZXF1aXJlcyBhdCBsZWFzdCBhIHBvc2l0aW9uIGF0dHJpYnV0ZS5cblx0XHRcdC8vIGluc3RhbmNpbmcgaXNuJ3Qgc3VwcG9ydGVkIHNvIGZhciBhbmQgdXNlcyB0aGUgbm9ybWFsIChjb25zZXJ2YXRpdmUpIGNvZGUgcGF0aC5cblxuXHRcdFx0aWYgKCBwcmVjaXNlID09PSB0cnVlICYmIHBvc2l0aW9uQXR0cmlidXRlICE9PSB1bmRlZmluZWQgJiYgb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCAhPT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRpZiAoIG9iamVjdC5pc01lc2ggPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRcdG9iamVjdC5nZXRWZXJ0ZXhQb3NpdGlvbiggaSwgX3ZlY3RvciRiICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRfdmVjdG9yJGIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdF92ZWN0b3IkYi5hcHBseU1hdHJpeDQoIG9iamVjdC5tYXRyaXhXb3JsZCApO1xuXHRcdFx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggX3ZlY3RvciRiICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGlmICggb2JqZWN0LmJvdW5kaW5nQm94ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHQvLyBvYmplY3QtbGV2ZWwgYm91bmRpbmcgYm94XG5cblx0XHRcdFx0XHRpZiAoIG9iamVjdC5ib3VuZGluZ0JveCA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdFx0b2JqZWN0LmNvbXB1dGVCb3VuZGluZ0JveCgpO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0X2JveCQ0LmNvcHkoIG9iamVjdC5ib3VuZGluZ0JveCApO1xuXG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdC8vIGdlb21ldHJ5LWxldmVsIGJvdW5kaW5nIGJveFxuXG5cdFx0XHRcdFx0aWYgKCBnZW9tZXRyeS5ib3VuZGluZ0JveCA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdFx0Z2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nQm94KCk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRfYm94JDQuY29weSggZ2VvbWV0cnkuYm91bmRpbmdCb3ggKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0X2JveCQ0LmFwcGx5TWF0cml4NCggb2JqZWN0Lm1hdHJpeFdvcmxkICk7XG5cblx0XHRcdFx0dGhpcy51bmlvbiggX2JveCQ0ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IGNoaWxkcmVuID0gb2JqZWN0LmNoaWxkcmVuO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5leHBhbmRCeU9iamVjdCggY2hpbGRyZW5bIGkgXSwgcHJlY2lzZSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvbnRhaW5zUG9pbnQoIHBvaW50ICkge1xuXG5cdFx0cmV0dXJuIHBvaW50LnggPCB0aGlzLm1pbi54IHx8IHBvaW50LnggPiB0aGlzLm1heC54IHx8XG5cdFx0XHRwb2ludC55IDwgdGhpcy5taW4ueSB8fCBwb2ludC55ID4gdGhpcy5tYXgueSB8fFxuXHRcdFx0cG9pbnQueiA8IHRoaXMubWluLnogfHwgcG9pbnQueiA+IHRoaXMubWF4LnogPyBmYWxzZSA6IHRydWU7XG5cblx0fVxuXG5cdGNvbnRhaW5zQm94KCBib3ggKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5taW4ueCA8PSBib3gubWluLnggJiYgYm94Lm1heC54IDw9IHRoaXMubWF4LnggJiZcblx0XHRcdHRoaXMubWluLnkgPD0gYm94Lm1pbi55ICYmIGJveC5tYXgueSA8PSB0aGlzLm1heC55ICYmXG5cdFx0XHR0aGlzLm1pbi56IDw9IGJveC5taW4ueiAmJiBib3gubWF4LnogPD0gdGhpcy5tYXguejtcblxuXHR9XG5cblx0Z2V0UGFyYW1ldGVyKCBwb2ludCwgdGFyZ2V0ICkge1xuXG5cdFx0Ly8gVGhpcyBjYW4gcG90ZW50aWFsbHkgaGF2ZSBhIGRpdmlkZSBieSB6ZXJvIGlmIHRoZSBib3hcblx0XHQvLyBoYXMgYSBzaXplIGRpbWVuc2lvbiBvZiAwLlxuXG5cdFx0cmV0dXJuIHRhcmdldC5zZXQoXG5cdFx0XHQoIHBvaW50LnggLSB0aGlzLm1pbi54ICkgLyAoIHRoaXMubWF4LnggLSB0aGlzLm1pbi54ICksXG5cdFx0XHQoIHBvaW50LnkgLSB0aGlzLm1pbi55ICkgLyAoIHRoaXMubWF4LnkgLSB0aGlzLm1pbi55ICksXG5cdFx0XHQoIHBvaW50LnogLSB0aGlzLm1pbi56ICkgLyAoIHRoaXMubWF4LnogLSB0aGlzLm1pbi56IClcblx0XHQpO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzQm94KCBib3ggKSB7XG5cblx0XHQvLyB1c2luZyA2IHNwbGl0dGluZyBwbGFuZXMgdG8gcnVsZSBvdXQgaW50ZXJzZWN0aW9ucy5cblx0XHRyZXR1cm4gYm94Lm1heC54IDwgdGhpcy5taW4ueCB8fCBib3gubWluLnggPiB0aGlzLm1heC54IHx8XG5cdFx0XHRib3gubWF4LnkgPCB0aGlzLm1pbi55IHx8IGJveC5taW4ueSA+IHRoaXMubWF4LnkgfHxcblx0XHRcdGJveC5tYXgueiA8IHRoaXMubWluLnogfHwgYm94Lm1pbi56ID4gdGhpcy5tYXgueiA/IGZhbHNlIDogdHJ1ZTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c1NwaGVyZSggc3BoZXJlICkge1xuXG5cdFx0Ly8gRmluZCB0aGUgcG9pbnQgb24gdGhlIEFBQkIgY2xvc2VzdCB0byB0aGUgc3BoZXJlIGNlbnRlci5cblx0XHR0aGlzLmNsYW1wUG9pbnQoIHNwaGVyZS5jZW50ZXIsIF92ZWN0b3IkYiApO1xuXG5cdFx0Ly8gSWYgdGhhdCBwb2ludCBpcyBpbnNpZGUgdGhlIHNwaGVyZSwgdGhlIEFBQkIgYW5kIHNwaGVyZSBpbnRlcnNlY3QuXG5cdFx0cmV0dXJuIF92ZWN0b3IkYi5kaXN0YW5jZVRvU3F1YXJlZCggc3BoZXJlLmNlbnRlciApIDw9ICggc3BoZXJlLnJhZGl1cyAqIHNwaGVyZS5yYWRpdXMgKTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c1BsYW5lKCBwbGFuZSApIHtcblxuXHRcdC8vIFdlIGNvbXB1dGUgdGhlIG1pbmltdW0gYW5kIG1heGltdW0gZG90IHByb2R1Y3QgdmFsdWVzLiBJZiB0aG9zZSB2YWx1ZXNcblx0XHQvLyBhcmUgb24gdGhlIHNhbWUgc2lkZSAoYmFjayBvciBmcm9udCkgb2YgdGhlIHBsYW5lLCB0aGVuIHRoZXJlIGlzIG5vIGludGVyc2VjdGlvbi5cblxuXHRcdGxldCBtaW4sIG1heDtcblxuXHRcdGlmICggcGxhbmUubm9ybWFsLnggPiAwICkge1xuXG5cdFx0XHRtaW4gPSBwbGFuZS5ub3JtYWwueCAqIHRoaXMubWluLng7XG5cdFx0XHRtYXggPSBwbGFuZS5ub3JtYWwueCAqIHRoaXMubWF4Lng7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRtaW4gPSBwbGFuZS5ub3JtYWwueCAqIHRoaXMubWF4Lng7XG5cdFx0XHRtYXggPSBwbGFuZS5ub3JtYWwueCAqIHRoaXMubWluLng7XG5cblx0XHR9XG5cblx0XHRpZiAoIHBsYW5lLm5vcm1hbC55ID4gMCApIHtcblxuXHRcdFx0bWluICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5taW4ueTtcblx0XHRcdG1heCArPSBwbGFuZS5ub3JtYWwueSAqIHRoaXMubWF4Lnk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRtaW4gKz0gcGxhbmUubm9ybWFsLnkgKiB0aGlzLm1heC55O1xuXHRcdFx0bWF4ICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5taW4ueTtcblxuXHRcdH1cblxuXHRcdGlmICggcGxhbmUubm9ybWFsLnogPiAwICkge1xuXG5cdFx0XHRtaW4gKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1pbi56O1xuXHRcdFx0bWF4ICs9IHBsYW5lLm5vcm1hbC56ICogdGhpcy5tYXguejtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdG1pbiArPSBwbGFuZS5ub3JtYWwueiAqIHRoaXMubWF4Lno7XG5cdFx0XHRtYXggKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1pbi56O1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuICggbWluIDw9IC0gcGxhbmUuY29uc3RhbnQgJiYgbWF4ID49IC0gcGxhbmUuY29uc3RhbnQgKTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c1RyaWFuZ2xlKCB0cmlhbmdsZSApIHtcblxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB7XG5cblx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdH1cblxuXHRcdC8vIGNvbXB1dGUgYm94IGNlbnRlciBhbmQgZXh0ZW50c1xuXHRcdHRoaXMuZ2V0Q2VudGVyKCBfY2VudGVyICk7XG5cdFx0X2V4dGVudHMuc3ViVmVjdG9ycyggdGhpcy5tYXgsIF9jZW50ZXIgKTtcblxuXHRcdC8vIHRyYW5zbGF0ZSB0cmlhbmdsZSB0byBhYWJiIG9yaWdpblxuXHRcdF92MCQyLnN1YlZlY3RvcnMoIHRyaWFuZ2xlLmEsIF9jZW50ZXIgKTtcblx0XHRfdjEkNy5zdWJWZWN0b3JzKCB0cmlhbmdsZS5iLCBfY2VudGVyICk7XG5cdFx0X3YyJDQuc3ViVmVjdG9ycyggdHJpYW5nbGUuYywgX2NlbnRlciApO1xuXG5cdFx0Ly8gY29tcHV0ZSBlZGdlIHZlY3RvcnMgZm9yIHRyaWFuZ2xlXG5cdFx0X2YwLnN1YlZlY3RvcnMoIF92MSQ3LCBfdjAkMiApO1xuXHRcdF9mMS5zdWJWZWN0b3JzKCBfdjIkNCwgX3YxJDcgKTtcblx0XHRfZjIuc3ViVmVjdG9ycyggX3YwJDIsIF92MiQ0ICk7XG5cblx0XHQvLyB0ZXN0IGFnYWluc3QgYXhlcyB0aGF0IGFyZSBnaXZlbiBieSBjcm9zcyBwcm9kdWN0IGNvbWJpbmF0aW9ucyBvZiB0aGUgZWRnZXMgb2YgdGhlIHRyaWFuZ2xlIGFuZCB0aGUgZWRnZXMgb2YgdGhlIGFhYmJcblx0XHQvLyBtYWtlIGFuIGF4aXMgdGVzdGluZyBvZiBlYWNoIG9mIHRoZSAzIHNpZGVzIG9mIHRoZSBhYWJiIGFnYWluc3QgZWFjaCBvZiB0aGUgMyBzaWRlcyBvZiB0aGUgdHJpYW5nbGUgPSA5IGF4aXMgb2Ygc2VwYXJhdGlvblxuXHRcdC8vIGF4aXNfaWogPSB1X2kgeCBmX2ogKHUwLCB1MSwgdTIgPSBmYWNlIG5vcm1hbHMgb2YgYWFiYiA9IHgseSx6IGF4ZXMgdmVjdG9ycyBzaW5jZSBhYWJiIGlzIGF4aXMgYWxpZ25lZClcblx0XHRsZXQgYXhlcyA9IFtcblx0XHRcdDAsIC0gX2YwLnosIF9mMC55LCAwLCAtIF9mMS56LCBfZjEueSwgMCwgLSBfZjIueiwgX2YyLnksXG5cdFx0XHRfZjAueiwgMCwgLSBfZjAueCwgX2YxLnosIDAsIC0gX2YxLngsIF9mMi56LCAwLCAtIF9mMi54LFxuXHRcdFx0LSBfZjAueSwgX2YwLngsIDAsIC0gX2YxLnksIF9mMS54LCAwLCAtIF9mMi55LCBfZjIueCwgMFxuXHRcdF07XG5cdFx0aWYgKCAhIHNhdEZvckF4ZXMoIGF4ZXMsIF92MCQyLCBfdjEkNywgX3YyJDQsIF9leHRlbnRzICkgKSB7XG5cblx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdH1cblxuXHRcdC8vIHRlc3QgMyBmYWNlIG5vcm1hbHMgZnJvbSB0aGUgYWFiYlxuXHRcdGF4ZXMgPSBbIDEsIDAsIDAsIDAsIDEsIDAsIDAsIDAsIDEgXTtcblx0XHRpZiAoICEgc2F0Rm9yQXhlcyggYXhlcywgX3YwJDIsIF92MSQ3LCBfdjIkNCwgX2V4dGVudHMgKSApIHtcblxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0Ly8gZmluYWxseSB0ZXN0aW5nIHRoZSBmYWNlIG5vcm1hbCBvZiB0aGUgdHJpYW5nbGVcblx0XHQvLyB1c2UgYWxyZWFkeSBleGlzdGluZyB0cmlhbmdsZSBlZGdlIHZlY3RvcnMgaGVyZVxuXHRcdF90cmlhbmdsZU5vcm1hbC5jcm9zc1ZlY3RvcnMoIF9mMCwgX2YxICk7XG5cdFx0YXhlcyA9IFsgX3RyaWFuZ2xlTm9ybWFsLngsIF90cmlhbmdsZU5vcm1hbC55LCBfdHJpYW5nbGVOb3JtYWwueiBdO1xuXG5cdFx0cmV0dXJuIHNhdEZvckF4ZXMoIGF4ZXMsIF92MCQyLCBfdjEkNywgX3YyJDQsIF9leHRlbnRzICk7XG5cblx0fVxuXG5cdGNsYW1wUG9pbnQoIHBvaW50LCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHBvaW50ICkuY2xhbXAoIHRoaXMubWluLCB0aGlzLm1heCApO1xuXG5cdH1cblxuXHRkaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuY2xhbXBQb2ludCggcG9pbnQsIF92ZWN0b3IkYiApLmRpc3RhbmNlVG8oIHBvaW50ICk7XG5cblx0fVxuXG5cdGdldEJvdW5kaW5nU3BoZXJlKCB0YXJnZXQgKSB7XG5cblx0XHRpZiAoIHRoaXMuaXNFbXB0eSgpICkge1xuXG5cdFx0XHR0YXJnZXQubWFrZUVtcHR5KCk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLmdldENlbnRlciggdGFyZ2V0LmNlbnRlciApO1xuXG5cdFx0XHR0YXJnZXQucmFkaXVzID0gdGhpcy5nZXRTaXplKCBfdmVjdG9yJGIgKS5sZW5ndGgoKSAqIDAuNTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0YXJnZXQ7XG5cblx0fVxuXG5cdGludGVyc2VjdCggYm94ICkge1xuXG5cdFx0dGhpcy5taW4ubWF4KCBib3gubWluICk7XG5cdFx0dGhpcy5tYXgubWluKCBib3gubWF4ICk7XG5cblx0XHQvLyBlbnN1cmUgdGhhdCBpZiB0aGVyZSBpcyBubyBvdmVybGFwLCB0aGUgcmVzdWx0IGlzIGZ1bGx5IGVtcHR5LCBub3Qgc2xpZ2h0bHkgZW1wdHkgd2l0aCBub24taW5mLytpbmYgdmFsdWVzIHRoYXQgd2lsbCBjYXVzZSBzdWJzZXF1ZW5jZSBpbnRlcnNlY3RzIHRvIGVycm9uZW91c2x5IHJldHVybiB2YWxpZCB2YWx1ZXMuXG5cdFx0aWYgKCB0aGlzLmlzRW1wdHkoKSApIHRoaXMubWFrZUVtcHR5KCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dW5pb24oIGJveCApIHtcblxuXHRcdHRoaXMubWluLm1pbiggYm94Lm1pbiApO1xuXHRcdHRoaXMubWF4Lm1heCggYm94Lm1heCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFwcGx5TWF0cml4NCggbWF0cml4ICkge1xuXG5cdFx0Ly8gdHJhbnNmb3JtIG9mIGVtcHR5IGJveCBpcyBhbiBlbXB0eSBib3guXG5cdFx0aWYgKCB0aGlzLmlzRW1wdHkoKSApIHJldHVybiB0aGlzO1xuXG5cdFx0Ly8gTk9URTogSSBhbSB1c2luZyBhIGJpbmFyeSBwYXR0ZXJuIHRvIHNwZWNpZnkgYWxsIDJeMyBjb21iaW5hdGlvbnMgYmVsb3dcblx0XHRfcG9pbnRzWyAwIF0uc2V0KCB0aGlzLm1pbi54LCB0aGlzLm1pbi55LCB0aGlzLm1pbi56ICkuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTsgLy8gMDAwXG5cdFx0X3BvaW50c1sgMSBdLnNldCggdGhpcy5taW4ueCwgdGhpcy5taW4ueSwgdGhpcy5tYXgueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDAwMVxuXHRcdF9wb2ludHNbIDIgXS5zZXQoIHRoaXMubWluLngsIHRoaXMubWF4LnksIHRoaXMubWluLnogKS5hcHBseU1hdHJpeDQoIG1hdHJpeCApOyAvLyAwMTBcblx0XHRfcG9pbnRzWyAzIF0uc2V0KCB0aGlzLm1pbi54LCB0aGlzLm1heC55LCB0aGlzLm1heC56ICkuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTsgLy8gMDExXG5cdFx0X3BvaW50c1sgNCBdLnNldCggdGhpcy5tYXgueCwgdGhpcy5taW4ueSwgdGhpcy5taW4ueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDEwMFxuXHRcdF9wb2ludHNbIDUgXS5zZXQoIHRoaXMubWF4LngsIHRoaXMubWluLnksIHRoaXMubWF4LnogKS5hcHBseU1hdHJpeDQoIG1hdHJpeCApOyAvLyAxMDFcblx0XHRfcG9pbnRzWyA2IF0uc2V0KCB0aGlzLm1heC54LCB0aGlzLm1heC55LCB0aGlzLm1pbi56ICkuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTsgLy8gMTEwXG5cdFx0X3BvaW50c1sgNyBdLnNldCggdGhpcy5tYXgueCwgdGhpcy5tYXgueSwgdGhpcy5tYXgueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDExMVxuXG5cdFx0dGhpcy5zZXRGcm9tUG9pbnRzKCBfcG9pbnRzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJhbnNsYXRlKCBvZmZzZXQgKSB7XG5cblx0XHR0aGlzLm1pbi5hZGQoIG9mZnNldCApO1xuXHRcdHRoaXMubWF4LmFkZCggb2Zmc2V0ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXF1YWxzKCBib3ggKSB7XG5cblx0XHRyZXR1cm4gYm94Lm1pbi5lcXVhbHMoIHRoaXMubWluICkgJiYgYm94Lm1heC5lcXVhbHMoIHRoaXMubWF4ICk7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9wb2ludHMgPSBbXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKSxcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpLFxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCksXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKSxcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpLFxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCksXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKSxcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpXG5dO1xuXG5jb25zdCBfdmVjdG9yJGIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNvbnN0IF9ib3gkNCA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcblxuLy8gdHJpYW5nbGUgY2VudGVyZWQgdmVydGljZXNcblxuY29uc3QgX3YwJDIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdjEkNyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92MiQ0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG4vLyB0cmlhbmdsZSBlZGdlIHZlY3RvcnNcblxuY29uc3QgX2YwID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2YxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2YyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jb25zdCBfY2VudGVyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2V4dGVudHMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdHJpYW5nbGVOb3JtYWwgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdGVzdEF4aXMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmZ1bmN0aW9uIHNhdEZvckF4ZXMoIGF4ZXMsIHYwLCB2MSwgdjIsIGV4dGVudHMgKSB7XG5cblx0Zm9yICggbGV0IGkgPSAwLCBqID0gYXhlcy5sZW5ndGggLSAzOyBpIDw9IGo7IGkgKz0gMyApIHtcblxuXHRcdF90ZXN0QXhpcy5mcm9tQXJyYXkoIGF4ZXMsIGkgKTtcblx0XHQvLyBwcm9qZWN0IHRoZSBhYWJiIG9udG8gdGhlIHNlcGFyYXRpbmcgYXhpc1xuXHRcdGNvbnN0IHIgPSBleHRlbnRzLnggKiBNYXRoLmFicyggX3Rlc3RBeGlzLnggKSArIGV4dGVudHMueSAqIE1hdGguYWJzKCBfdGVzdEF4aXMueSApICsgZXh0ZW50cy56ICogTWF0aC5hYnMoIF90ZXN0QXhpcy56ICk7XG5cdFx0Ly8gcHJvamVjdCBhbGwgMyB2ZXJ0aWNlcyBvZiB0aGUgdHJpYW5nbGUgb250byB0aGUgc2VwYXJhdGluZyBheGlzXG5cdFx0Y29uc3QgcDAgPSB2MC5kb3QoIF90ZXN0QXhpcyApO1xuXHRcdGNvbnN0IHAxID0gdjEuZG90KCBfdGVzdEF4aXMgKTtcblx0XHRjb25zdCBwMiA9IHYyLmRvdCggX3Rlc3RBeGlzICk7XG5cdFx0Ly8gYWN0dWFsIHRlc3QsIGJhc2ljYWxseSBzZWUgaWYgZWl0aGVyIG9mIHRoZSBtb3N0IGV4dHJlbWUgb2YgdGhlIHRyaWFuZ2xlIHBvaW50cyBpbnRlcnNlY3RzIHJcblx0XHRpZiAoIE1hdGgubWF4KCAtIE1hdGgubWF4KCBwMCwgcDEsIHAyICksIE1hdGgubWluKCBwMCwgcDEsIHAyICkgKSA+IHIgKSB7XG5cblx0XHRcdC8vIHBvaW50cyBvZiB0aGUgcHJvamVjdGVkIHRyaWFuZ2xlIGFyZSBvdXRzaWRlIHRoZSBwcm9qZWN0ZWQgaGFsZi1sZW5ndGggb2YgdGhlIGFhYmJcblx0XHRcdC8vIHRoZSBheGlzIGlzIHNlcGFyYXRpbmcgYW5kIHdlIGNhbiBleGl0XG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cblx0XHR9XG5cblx0fVxuXG5cdHJldHVybiB0cnVlO1xuXG59XG5cbmNvbnN0IF9ib3gkMyA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcbmNvbnN0IF92MSQ2ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3YyJDMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNsYXNzIFNwaGVyZSB7XG5cblx0Y29uc3RydWN0b3IoIGNlbnRlciA9IG5ldyBWZWN0b3IzKCksIHJhZGl1cyA9IC0gMSApIHtcblxuXHRcdHRoaXMuaXNTcGhlcmUgPSB0cnVlO1xuXG5cdFx0dGhpcy5jZW50ZXIgPSBjZW50ZXI7XG5cdFx0dGhpcy5yYWRpdXMgPSByYWRpdXM7XG5cblx0fVxuXG5cdHNldCggY2VudGVyLCByYWRpdXMgKSB7XG5cblx0XHR0aGlzLmNlbnRlci5jb3B5KCBjZW50ZXIgKTtcblx0XHR0aGlzLnJhZGl1cyA9IHJhZGl1cztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tUG9pbnRzKCBwb2ludHMsIG9wdGlvbmFsQ2VudGVyICkge1xuXG5cdFx0Y29uc3QgY2VudGVyID0gdGhpcy5jZW50ZXI7XG5cblx0XHRpZiAoIG9wdGlvbmFsQ2VudGVyICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNlbnRlci5jb3B5KCBvcHRpb25hbENlbnRlciApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0X2JveCQzLnNldEZyb21Qb2ludHMoIHBvaW50cyApLmdldENlbnRlciggY2VudGVyICk7XG5cblx0XHR9XG5cblx0XHRsZXQgbWF4UmFkaXVzU3EgPSAwO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHBvaW50cy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0bWF4UmFkaXVzU3EgPSBNYXRoLm1heCggbWF4UmFkaXVzU3EsIGNlbnRlci5kaXN0YW5jZVRvU3F1YXJlZCggcG9pbnRzWyBpIF0gKSApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5yYWRpdXMgPSBNYXRoLnNxcnQoIG1heFJhZGl1c1NxICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weSggc3BoZXJlICkge1xuXG5cdFx0dGhpcy5jZW50ZXIuY29weSggc3BoZXJlLmNlbnRlciApO1xuXHRcdHRoaXMucmFkaXVzID0gc3BoZXJlLnJhZGl1cztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRpc0VtcHR5KCkge1xuXG5cdFx0cmV0dXJuICggdGhpcy5yYWRpdXMgPCAwICk7XG5cblx0fVxuXG5cdG1ha2VFbXB0eSgpIHtcblxuXHRcdHRoaXMuY2VudGVyLnNldCggMCwgMCwgMCApO1xuXHRcdHRoaXMucmFkaXVzID0gLSAxO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvbnRhaW5zUG9pbnQoIHBvaW50ICkge1xuXG5cdFx0cmV0dXJuICggcG9pbnQuZGlzdGFuY2VUb1NxdWFyZWQoIHRoaXMuY2VudGVyICkgPD0gKCB0aGlzLnJhZGl1cyAqIHRoaXMucmFkaXVzICkgKTtcblxuXHR9XG5cblx0ZGlzdGFuY2VUb1BvaW50KCBwb2ludCApIHtcblxuXHRcdHJldHVybiAoIHBvaW50LmRpc3RhbmNlVG8oIHRoaXMuY2VudGVyICkgLSB0aGlzLnJhZGl1cyApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzU3BoZXJlKCBzcGhlcmUgKSB7XG5cblx0XHRjb25zdCByYWRpdXNTdW0gPSB0aGlzLnJhZGl1cyArIHNwaGVyZS5yYWRpdXM7XG5cblx0XHRyZXR1cm4gc3BoZXJlLmNlbnRlci5kaXN0YW5jZVRvU3F1YXJlZCggdGhpcy5jZW50ZXIgKSA8PSAoIHJhZGl1c1N1bSAqIHJhZGl1c1N1bSApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzQm94KCBib3ggKSB7XG5cblx0XHRyZXR1cm4gYm94LmludGVyc2VjdHNTcGhlcmUoIHRoaXMgKTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c1BsYW5lKCBwbGFuZSApIHtcblxuXHRcdHJldHVybiBNYXRoLmFicyggcGxhbmUuZGlzdGFuY2VUb1BvaW50KCB0aGlzLmNlbnRlciApICkgPD0gdGhpcy5yYWRpdXM7XG5cblx0fVxuXG5cdGNsYW1wUG9pbnQoIHBvaW50LCB0YXJnZXQgKSB7XG5cblx0XHRjb25zdCBkZWx0YUxlbmd0aFNxID0gdGhpcy5jZW50ZXIuZGlzdGFuY2VUb1NxdWFyZWQoIHBvaW50ICk7XG5cblx0XHR0YXJnZXQuY29weSggcG9pbnQgKTtcblxuXHRcdGlmICggZGVsdGFMZW5ndGhTcSA+ICggdGhpcy5yYWRpdXMgKiB0aGlzLnJhZGl1cyApICkge1xuXG5cdFx0XHR0YXJnZXQuc3ViKCB0aGlzLmNlbnRlciApLm5vcm1hbGl6ZSgpO1xuXHRcdFx0dGFyZ2V0Lm11bHRpcGx5U2NhbGFyKCB0aGlzLnJhZGl1cyApLmFkZCggdGhpcy5jZW50ZXIgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0YXJnZXQ7XG5cblx0fVxuXG5cdGdldEJvdW5kaW5nQm94KCB0YXJnZXQgKSB7XG5cblx0XHRpZiAoIHRoaXMuaXNFbXB0eSgpICkge1xuXG5cdFx0XHQvLyBFbXB0eSBzcGhlcmUgcHJvZHVjZXMgZW1wdHkgYm91bmRpbmcgYm94XG5cdFx0XHR0YXJnZXQubWFrZUVtcHR5KCk7XG5cdFx0XHRyZXR1cm4gdGFyZ2V0O1xuXG5cdFx0fVxuXG5cdFx0dGFyZ2V0LnNldCggdGhpcy5jZW50ZXIsIHRoaXMuY2VudGVyICk7XG5cdFx0dGFyZ2V0LmV4cGFuZEJ5U2NhbGFyKCB0aGlzLnJhZGl1cyApO1xuXG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0YXBwbHlNYXRyaXg0KCBtYXRyaXggKSB7XG5cblx0XHR0aGlzLmNlbnRlci5hcHBseU1hdHJpeDQoIG1hdHJpeCApO1xuXHRcdHRoaXMucmFkaXVzID0gdGhpcy5yYWRpdXMgKiBtYXRyaXguZ2V0TWF4U2NhbGVPbkF4aXMoKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0cmFuc2xhdGUoIG9mZnNldCApIHtcblxuXHRcdHRoaXMuY2VudGVyLmFkZCggb2Zmc2V0ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXhwYW5kQnlQb2ludCggcG9pbnQgKSB7XG5cblx0XHRpZiAoIHRoaXMuaXNFbXB0eSgpICkge1xuXG5cdFx0XHR0aGlzLmNlbnRlci5jb3B5KCBwb2ludCApO1xuXG5cdFx0XHR0aGlzLnJhZGl1cyA9IDA7XG5cblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fVxuXG5cdFx0X3YxJDYuc3ViVmVjdG9ycyggcG9pbnQsIHRoaXMuY2VudGVyICk7XG5cblx0XHRjb25zdCBsZW5ndGhTcSA9IF92MSQ2Lmxlbmd0aFNxKCk7XG5cblx0XHRpZiAoIGxlbmd0aFNxID4gKCB0aGlzLnJhZGl1cyAqIHRoaXMucmFkaXVzICkgKSB7XG5cblx0XHRcdC8vIGNhbGN1bGF0ZSB0aGUgbWluaW1hbCBzcGhlcmVcblxuXHRcdFx0Y29uc3QgbGVuZ3RoID0gTWF0aC5zcXJ0KCBsZW5ndGhTcSApO1xuXG5cdFx0XHRjb25zdCBkZWx0YSA9ICggbGVuZ3RoIC0gdGhpcy5yYWRpdXMgKSAqIDAuNTtcblxuXHRcdFx0dGhpcy5jZW50ZXIuYWRkU2NhbGVkVmVjdG9yKCBfdjEkNiwgZGVsdGEgLyBsZW5ndGggKTtcblxuXHRcdFx0dGhpcy5yYWRpdXMgKz0gZGVsdGE7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dW5pb24oIHNwaGVyZSApIHtcblxuXHRcdGlmICggc3BoZXJlLmlzRW1wdHkoKSApIHtcblxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuaXNFbXB0eSgpICkge1xuXG5cdFx0XHR0aGlzLmNvcHkoIHNwaGVyZSApO1xuXG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5jZW50ZXIuZXF1YWxzKCBzcGhlcmUuY2VudGVyICkgPT09IHRydWUgKSB7XG5cblx0XHRcdCB0aGlzLnJhZGl1cyA9IE1hdGgubWF4KCB0aGlzLnJhZGl1cywgc3BoZXJlLnJhZGl1cyApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0X3YyJDMuc3ViVmVjdG9ycyggc3BoZXJlLmNlbnRlciwgdGhpcy5jZW50ZXIgKS5zZXRMZW5ndGgoIHNwaGVyZS5yYWRpdXMgKTtcblxuXHRcdFx0dGhpcy5leHBhbmRCeVBvaW50KCBfdjEkNi5jb3B5KCBzcGhlcmUuY2VudGVyICkuYWRkKCBfdjIkMyApICk7XG5cblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggX3YxJDYuY29weSggc3BoZXJlLmNlbnRlciApLnN1YiggX3YyJDMgKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGVxdWFscyggc3BoZXJlICkge1xuXG5cdFx0cmV0dXJuIHNwaGVyZS5jZW50ZXIuZXF1YWxzKCB0aGlzLmNlbnRlciApICYmICggc3BoZXJlLnJhZGl1cyA9PT0gdGhpcy5yYWRpdXMgKTtcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG59XG5cbmNvbnN0IF92ZWN0b3IkYSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9zZWdDZW50ZXIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfc2VnRGlyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2RpZmYgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNvbnN0IF9lZGdlMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9lZGdlMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9ub3JtYWwkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgUmF5IHtcblxuXHRjb25zdHJ1Y3Rvciggb3JpZ2luID0gbmV3IFZlY3RvcjMoKSwgZGlyZWN0aW9uID0gbmV3IFZlY3RvcjMoIDAsIDAsIC0gMSApICkge1xuXG5cdFx0dGhpcy5vcmlnaW4gPSBvcmlnaW47XG5cdFx0dGhpcy5kaXJlY3Rpb24gPSBkaXJlY3Rpb247XG5cblx0fVxuXG5cdHNldCggb3JpZ2luLCBkaXJlY3Rpb24gKSB7XG5cblx0XHR0aGlzLm9yaWdpbi5jb3B5KCBvcmlnaW4gKTtcblx0XHR0aGlzLmRpcmVjdGlvbi5jb3B5KCBkaXJlY3Rpb24gKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb3B5KCByYXkgKSB7XG5cblx0XHR0aGlzLm9yaWdpbi5jb3B5KCByYXkub3JpZ2luICk7XG5cdFx0dGhpcy5kaXJlY3Rpb24uY29weSggcmF5LmRpcmVjdGlvbiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGF0KCB0LCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHRoaXMub3JpZ2luICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLmRpcmVjdGlvbiwgdCApO1xuXG5cdH1cblxuXHRsb29rQXQoIHYgKSB7XG5cblx0XHR0aGlzLmRpcmVjdGlvbi5jb3B5KCB2ICkuc3ViKCB0aGlzLm9yaWdpbiApLm5vcm1hbGl6ZSgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJlY2FzdCggdCApIHtcblxuXHRcdHRoaXMub3JpZ2luLmNvcHkoIHRoaXMuYXQoIHQsIF92ZWN0b3IkYSApICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xvc2VzdFBvaW50VG9Qb2ludCggcG9pbnQsIHRhcmdldCApIHtcblxuXHRcdHRhcmdldC5zdWJWZWN0b3JzKCBwb2ludCwgdGhpcy5vcmlnaW4gKTtcblxuXHRcdGNvbnN0IGRpcmVjdGlvbkRpc3RhbmNlID0gdGFyZ2V0LmRvdCggdGhpcy5kaXJlY3Rpb24gKTtcblxuXHRcdGlmICggZGlyZWN0aW9uRGlzdGFuY2UgPCAwICkge1xuXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHRoaXMub3JpZ2luICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHRoaXMub3JpZ2luICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLmRpcmVjdGlvbiwgZGlyZWN0aW9uRGlzdGFuY2UgKTtcblxuXHR9XG5cblx0ZGlzdGFuY2VUb1BvaW50KCBwb2ludCApIHtcblxuXHRcdHJldHVybiBNYXRoLnNxcnQoIHRoaXMuZGlzdGFuY2VTcVRvUG9pbnQoIHBvaW50ICkgKTtcblxuXHR9XG5cblx0ZGlzdGFuY2VTcVRvUG9pbnQoIHBvaW50ICkge1xuXG5cdFx0Y29uc3QgZGlyZWN0aW9uRGlzdGFuY2UgPSBfdmVjdG9yJGEuc3ViVmVjdG9ycyggcG9pbnQsIHRoaXMub3JpZ2luICkuZG90KCB0aGlzLmRpcmVjdGlvbiApO1xuXG5cdFx0Ly8gcG9pbnQgYmVoaW5kIHRoZSByYXlcblxuXHRcdGlmICggZGlyZWN0aW9uRGlzdGFuY2UgPCAwICkge1xuXG5cdFx0XHRyZXR1cm4gdGhpcy5vcmlnaW4uZGlzdGFuY2VUb1NxdWFyZWQoIHBvaW50ICk7XG5cblx0XHR9XG5cblx0XHRfdmVjdG9yJGEuY29weSggdGhpcy5vcmlnaW4gKS5hZGRTY2FsZWRWZWN0b3IoIHRoaXMuZGlyZWN0aW9uLCBkaXJlY3Rpb25EaXN0YW5jZSApO1xuXG5cdFx0cmV0dXJuIF92ZWN0b3IkYS5kaXN0YW5jZVRvU3F1YXJlZCggcG9pbnQgKTtcblxuXHR9XG5cblx0ZGlzdGFuY2VTcVRvU2VnbWVudCggdjAsIHYxLCBvcHRpb25hbFBvaW50T25SYXksIG9wdGlvbmFsUG9pbnRPblNlZ21lbnQgKSB7XG5cblx0XHQvLyBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9wbWpvbmlhay9HZW9tZXRyaWNUb29scy9ibG9iL21hc3Rlci9HVEVuZ2luZS9JbmNsdWRlL01hdGhlbWF0aWNzL0d0ZURpc3RSYXlTZWdtZW50Lmhcblx0XHQvLyBJdCByZXR1cm5zIHRoZSBtaW4gZGlzdGFuY2UgYmV0d2VlbiB0aGUgcmF5IGFuZCB0aGUgc2VnbWVudFxuXHRcdC8vIGRlZmluZWQgYnkgdjAgYW5kIHYxXG5cdFx0Ly8gSXQgY2FuIGFsc28gc2V0IHR3byBvcHRpb25hbCB0YXJnZXRzIDpcblx0XHQvLyAtIFRoZSBjbG9zZXN0IHBvaW50IG9uIHRoZSByYXlcblx0XHQvLyAtIFRoZSBjbG9zZXN0IHBvaW50IG9uIHRoZSBzZWdtZW50XG5cblx0XHRfc2VnQ2VudGVyLmNvcHkoIHYwICkuYWRkKCB2MSApLm11bHRpcGx5U2NhbGFyKCAwLjUgKTtcblx0XHRfc2VnRGlyLmNvcHkoIHYxICkuc3ViKCB2MCApLm5vcm1hbGl6ZSgpO1xuXHRcdF9kaWZmLmNvcHkoIHRoaXMub3JpZ2luICkuc3ViKCBfc2VnQ2VudGVyICk7XG5cblx0XHRjb25zdCBzZWdFeHRlbnQgPSB2MC5kaXN0YW5jZVRvKCB2MSApICogMC41O1xuXHRcdGNvbnN0IGEwMSA9IC0gdGhpcy5kaXJlY3Rpb24uZG90KCBfc2VnRGlyICk7XG5cdFx0Y29uc3QgYjAgPSBfZGlmZi5kb3QoIHRoaXMuZGlyZWN0aW9uICk7XG5cdFx0Y29uc3QgYjEgPSAtIF9kaWZmLmRvdCggX3NlZ0RpciApO1xuXHRcdGNvbnN0IGMgPSBfZGlmZi5sZW5ndGhTcSgpO1xuXHRcdGNvbnN0IGRldCA9IE1hdGguYWJzKCAxIC0gYTAxICogYTAxICk7XG5cdFx0bGV0IHMwLCBzMSwgc3FyRGlzdCwgZXh0RGV0O1xuXG5cdFx0aWYgKCBkZXQgPiAwICkge1xuXG5cdFx0XHQvLyBUaGUgcmF5IGFuZCBzZWdtZW50IGFyZSBub3QgcGFyYWxsZWwuXG5cblx0XHRcdHMwID0gYTAxICogYjEgLSBiMDtcblx0XHRcdHMxID0gYTAxICogYjAgLSBiMTtcblx0XHRcdGV4dERldCA9IHNlZ0V4dGVudCAqIGRldDtcblxuXHRcdFx0aWYgKCBzMCA+PSAwICkge1xuXG5cdFx0XHRcdGlmICggczEgPj0gLSBleHREZXQgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHMxIDw9IGV4dERldCApIHtcblxuXHRcdFx0XHRcdFx0Ly8gcmVnaW9uIDBcblx0XHRcdFx0XHRcdC8vIE1pbmltdW0gYXQgaW50ZXJpb3IgcG9pbnRzIG9mIHJheSBhbmQgc2VnbWVudC5cblxuXHRcdFx0XHRcdFx0Y29uc3QgaW52RGV0ID0gMSAvIGRldDtcblx0XHRcdFx0XHRcdHMwICo9IGludkRldDtcblx0XHRcdFx0XHRcdHMxICo9IGludkRldDtcblx0XHRcdFx0XHRcdHNxckRpc3QgPSBzMCAqICggczAgKyBhMDEgKiBzMSArIDIgKiBiMCApICsgczEgKiAoIGEwMSAqIHMwICsgczEgKyAyICogYjEgKSArIGM7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHQvLyByZWdpb24gMVxuXG5cdFx0XHRcdFx0XHRzMSA9IHNlZ0V4dGVudDtcblx0XHRcdFx0XHRcdHMwID0gTWF0aC5tYXgoIDAsIC0gKCBhMDEgKiBzMSArIGIwICkgKTtcblx0XHRcdFx0XHRcdHNxckRpc3QgPSAtIHMwICogczAgKyBzMSAqICggczEgKyAyICogYjEgKSArIGM7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdC8vIHJlZ2lvbiA1XG5cblx0XHRcdFx0XHRzMSA9IC0gc2VnRXh0ZW50O1xuXHRcdFx0XHRcdHMwID0gTWF0aC5tYXgoIDAsIC0gKCBhMDEgKiBzMSArIGIwICkgKTtcblx0XHRcdFx0XHRzcXJEaXN0ID0gLSBzMCAqIHMwICsgczEgKiAoIHMxICsgMiAqIGIxICkgKyBjO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRpZiAoIHMxIDw9IC0gZXh0RGV0ICkge1xuXG5cdFx0XHRcdFx0Ly8gcmVnaW9uIDRcblxuXHRcdFx0XHRcdHMwID0gTWF0aC5tYXgoIDAsIC0gKCAtIGEwMSAqIHNlZ0V4dGVudCArIGIwICkgKTtcblx0XHRcdFx0XHRzMSA9ICggczAgPiAwICkgPyAtIHNlZ0V4dGVudCA6IE1hdGgubWluKCBNYXRoLm1heCggLSBzZWdFeHRlbnQsIC0gYjEgKSwgc2VnRXh0ZW50ICk7XG5cdFx0XHRcdFx0c3FyRGlzdCA9IC0gczAgKiBzMCArIHMxICogKCBzMSArIDIgKiBiMSApICsgYztcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBzMSA8PSBleHREZXQgKSB7XG5cblx0XHRcdFx0XHQvLyByZWdpb24gM1xuXG5cdFx0XHRcdFx0czAgPSAwO1xuXHRcdFx0XHRcdHMxID0gTWF0aC5taW4oIE1hdGgubWF4KCAtIHNlZ0V4dGVudCwgLSBiMSApLCBzZWdFeHRlbnQgKTtcblx0XHRcdFx0XHRzcXJEaXN0ID0gczEgKiAoIHMxICsgMiAqIGIxICkgKyBjO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyByZWdpb24gMlxuXG5cdFx0XHRcdFx0czAgPSBNYXRoLm1heCggMCwgLSAoIGEwMSAqIHNlZ0V4dGVudCArIGIwICkgKTtcblx0XHRcdFx0XHRzMSA9ICggczAgPiAwICkgPyBzZWdFeHRlbnQgOiBNYXRoLm1pbiggTWF0aC5tYXgoIC0gc2VnRXh0ZW50LCAtIGIxICksIHNlZ0V4dGVudCApO1xuXHRcdFx0XHRcdHNxckRpc3QgPSAtIHMwICogczAgKyBzMSAqICggczEgKyAyICogYjEgKSArIGM7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBSYXkgYW5kIHNlZ21lbnQgYXJlIHBhcmFsbGVsLlxuXG5cdFx0XHRzMSA9ICggYTAxID4gMCApID8gLSBzZWdFeHRlbnQgOiBzZWdFeHRlbnQ7XG5cdFx0XHRzMCA9IE1hdGgubWF4KCAwLCAtICggYTAxICogczEgKyBiMCApICk7XG5cdFx0XHRzcXJEaXN0ID0gLSBzMCAqIHMwICsgczEgKiAoIHMxICsgMiAqIGIxICkgKyBjO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBvcHRpb25hbFBvaW50T25SYXkgKSB7XG5cblx0XHRcdG9wdGlvbmFsUG9pbnRPblJheS5jb3B5KCB0aGlzLm9yaWdpbiApLmFkZFNjYWxlZFZlY3RvciggdGhpcy5kaXJlY3Rpb24sIHMwICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG9wdGlvbmFsUG9pbnRPblNlZ21lbnQgKSB7XG5cblx0XHRcdG9wdGlvbmFsUG9pbnRPblNlZ21lbnQuY29weSggX3NlZ0NlbnRlciApLmFkZFNjYWxlZFZlY3RvciggX3NlZ0RpciwgczEgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBzcXJEaXN0O1xuXG5cdH1cblxuXHRpbnRlcnNlY3RTcGhlcmUoIHNwaGVyZSwgdGFyZ2V0ICkge1xuXG5cdFx0X3ZlY3RvciRhLnN1YlZlY3RvcnMoIHNwaGVyZS5jZW50ZXIsIHRoaXMub3JpZ2luICk7XG5cdFx0Y29uc3QgdGNhID0gX3ZlY3RvciRhLmRvdCggdGhpcy5kaXJlY3Rpb24gKTtcblx0XHRjb25zdCBkMiA9IF92ZWN0b3IkYS5kb3QoIF92ZWN0b3IkYSApIC0gdGNhICogdGNhO1xuXHRcdGNvbnN0IHJhZGl1czIgPSBzcGhlcmUucmFkaXVzICogc3BoZXJlLnJhZGl1cztcblxuXHRcdGlmICggZDIgPiByYWRpdXMyICkgcmV0dXJuIG51bGw7XG5cblx0XHRjb25zdCB0aGMgPSBNYXRoLnNxcnQoIHJhZGl1czIgLSBkMiApO1xuXG5cdFx0Ly8gdDAgPSBmaXJzdCBpbnRlcnNlY3QgcG9pbnQgLSBlbnRyYW5jZSBvbiBmcm9udCBvZiBzcGhlcmVcblx0XHRjb25zdCB0MCA9IHRjYSAtIHRoYztcblxuXHRcdC8vIHQxID0gc2Vjb25kIGludGVyc2VjdCBwb2ludCAtIGV4aXQgcG9pbnQgb24gYmFjayBvZiBzcGhlcmVcblx0XHRjb25zdCB0MSA9IHRjYSArIHRoYztcblxuXHRcdC8vIHRlc3QgdG8gc2VlIGlmIHQxIGlzIGJlaGluZCB0aGUgcmF5IC0gaWYgc28sIHJldHVybiBudWxsXG5cdFx0aWYgKCB0MSA8IDAgKSByZXR1cm4gbnVsbDtcblxuXHRcdC8vIHRlc3QgdG8gc2VlIGlmIHQwIGlzIGJlaGluZCB0aGUgcmF5OlxuXHRcdC8vIGlmIGl0IGlzLCB0aGUgcmF5IGlzIGluc2lkZSB0aGUgc3BoZXJlLCBzbyByZXR1cm4gdGhlIHNlY29uZCBleGl0IHBvaW50IHNjYWxlZCBieSB0MSxcblx0XHQvLyBpbiBvcmRlciB0byBhbHdheXMgcmV0dXJuIGFuIGludGVyc2VjdCBwb2ludCB0aGF0IGlzIGluIGZyb250IG9mIHRoZSByYXkuXG5cdFx0aWYgKCB0MCA8IDAgKSByZXR1cm4gdGhpcy5hdCggdDEsIHRhcmdldCApO1xuXG5cdFx0Ly8gZWxzZSB0MCBpcyBpbiBmcm9udCBvZiB0aGUgcmF5LCBzbyByZXR1cm4gdGhlIGZpcnN0IGNvbGxpc2lvbiBwb2ludCBzY2FsZWQgYnkgdDBcblx0XHRyZXR1cm4gdGhpcy5hdCggdDAsIHRhcmdldCApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzU3BoZXJlKCBzcGhlcmUgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5kaXN0YW5jZVNxVG9Qb2ludCggc3BoZXJlLmNlbnRlciApIDw9ICggc3BoZXJlLnJhZGl1cyAqIHNwaGVyZS5yYWRpdXMgKTtcblxuXHR9XG5cblx0ZGlzdGFuY2VUb1BsYW5lKCBwbGFuZSApIHtcblxuXHRcdGNvbnN0IGRlbm9taW5hdG9yID0gcGxhbmUubm9ybWFsLmRvdCggdGhpcy5kaXJlY3Rpb24gKTtcblxuXHRcdGlmICggZGVub21pbmF0b3IgPT09IDAgKSB7XG5cblx0XHRcdC8vIGxpbmUgaXMgY29wbGFuYXIsIHJldHVybiBvcmlnaW5cblx0XHRcdGlmICggcGxhbmUuZGlzdGFuY2VUb1BvaW50KCB0aGlzLm9yaWdpbiApID09PSAwICkge1xuXG5cdFx0XHRcdHJldHVybiAwO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIE51bGwgaXMgcHJlZmVyYWJsZSB0byB1bmRlZmluZWQgc2luY2UgdW5kZWZpbmVkIG1lYW5zLi4uLiBpdCBpcyB1bmRlZmluZWRcblxuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9XG5cblx0XHRjb25zdCB0ID0gLSAoIHRoaXMub3JpZ2luLmRvdCggcGxhbmUubm9ybWFsICkgKyBwbGFuZS5jb25zdGFudCApIC8gZGVub21pbmF0b3I7XG5cblx0XHQvLyBSZXR1cm4gaWYgdGhlIHJheSBuZXZlciBpbnRlcnNlY3RzIHRoZSBwbGFuZVxuXG5cdFx0cmV0dXJuIHQgPj0gMCA/IHQgOiBudWxsO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RQbGFuZSggcGxhbmUsIHRhcmdldCApIHtcblxuXHRcdGNvbnN0IHQgPSB0aGlzLmRpc3RhbmNlVG9QbGFuZSggcGxhbmUgKTtcblxuXHRcdGlmICggdCA9PT0gbnVsbCApIHtcblxuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcy5hdCggdCwgdGFyZ2V0ICk7XG5cblx0fVxuXG5cdGludGVyc2VjdHNQbGFuZSggcGxhbmUgKSB7XG5cblx0XHQvLyBjaGVjayBpZiB0aGUgcmF5IGxpZXMgb24gdGhlIHBsYW5lIGZpcnN0XG5cblx0XHRjb25zdCBkaXN0VG9Qb2ludCA9IHBsYW5lLmRpc3RhbmNlVG9Qb2ludCggdGhpcy5vcmlnaW4gKTtcblxuXHRcdGlmICggZGlzdFRvUG9pbnQgPT09IDAgKSB7XG5cblx0XHRcdHJldHVybiB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgZGVub21pbmF0b3IgPSBwbGFuZS5ub3JtYWwuZG90KCB0aGlzLmRpcmVjdGlvbiApO1xuXG5cdFx0aWYgKCBkZW5vbWluYXRvciAqIGRpc3RUb1BvaW50IDwgMCApIHtcblxuXHRcdFx0cmV0dXJuIHRydWU7XG5cblx0XHR9XG5cblx0XHQvLyByYXkgb3JpZ2luIGlzIGJlaGluZCB0aGUgcGxhbmUgKGFuZCBpcyBwb2ludGluZyBiZWhpbmQgaXQpXG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cblx0fVxuXG5cdGludGVyc2VjdEJveCggYm94LCB0YXJnZXQgKSB7XG5cblx0XHRsZXQgdG1pbiwgdG1heCwgdHltaW4sIHR5bWF4LCB0em1pbiwgdHptYXg7XG5cblx0XHRjb25zdCBpbnZkaXJ4ID0gMSAvIHRoaXMuZGlyZWN0aW9uLngsXG5cdFx0XHRpbnZkaXJ5ID0gMSAvIHRoaXMuZGlyZWN0aW9uLnksXG5cdFx0XHRpbnZkaXJ6ID0gMSAvIHRoaXMuZGlyZWN0aW9uLno7XG5cblx0XHRjb25zdCBvcmlnaW4gPSB0aGlzLm9yaWdpbjtcblxuXHRcdGlmICggaW52ZGlyeCA+PSAwICkge1xuXG5cdFx0XHR0bWluID0gKCBib3gubWluLnggLSBvcmlnaW4ueCApICogaW52ZGlyeDtcblx0XHRcdHRtYXggPSAoIGJveC5tYXgueCAtIG9yaWdpbi54ICkgKiBpbnZkaXJ4O1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dG1pbiA9ICggYm94Lm1heC54IC0gb3JpZ2luLnggKSAqIGludmRpcng7XG5cdFx0XHR0bWF4ID0gKCBib3gubWluLnggLSBvcmlnaW4ueCApICogaW52ZGlyeDtcblxuXHRcdH1cblxuXHRcdGlmICggaW52ZGlyeSA+PSAwICkge1xuXG5cdFx0XHR0eW1pbiA9ICggYm94Lm1pbi55IC0gb3JpZ2luLnkgKSAqIGludmRpcnk7XG5cdFx0XHR0eW1heCA9ICggYm94Lm1heC55IC0gb3JpZ2luLnkgKSAqIGludmRpcnk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0eW1pbiA9ICggYm94Lm1heC55IC0gb3JpZ2luLnkgKSAqIGludmRpcnk7XG5cdFx0XHR0eW1heCA9ICggYm94Lm1pbi55IC0gb3JpZ2luLnkgKSAqIGludmRpcnk7XG5cblx0XHR9XG5cblx0XHRpZiAoICggdG1pbiA+IHR5bWF4ICkgfHwgKCB0eW1pbiA+IHRtYXggKSApIHJldHVybiBudWxsO1xuXG5cdFx0aWYgKCB0eW1pbiA+IHRtaW4gfHwgaXNOYU4oIHRtaW4gKSApIHRtaW4gPSB0eW1pbjtcblxuXHRcdGlmICggdHltYXggPCB0bWF4IHx8IGlzTmFOKCB0bWF4ICkgKSB0bWF4ID0gdHltYXg7XG5cblx0XHRpZiAoIGludmRpcnogPj0gMCApIHtcblxuXHRcdFx0dHptaW4gPSAoIGJveC5taW4ueiAtIG9yaWdpbi56ICkgKiBpbnZkaXJ6O1xuXHRcdFx0dHptYXggPSAoIGJveC5tYXgueiAtIG9yaWdpbi56ICkgKiBpbnZkaXJ6O1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dHptaW4gPSAoIGJveC5tYXgueiAtIG9yaWdpbi56ICkgKiBpbnZkaXJ6O1xuXHRcdFx0dHptYXggPSAoIGJveC5taW4ueiAtIG9yaWdpbi56ICkgKiBpbnZkaXJ6O1xuXG5cdFx0fVxuXG5cdFx0aWYgKCAoIHRtaW4gPiB0em1heCApIHx8ICggdHptaW4gPiB0bWF4ICkgKSByZXR1cm4gbnVsbDtcblxuXHRcdGlmICggdHptaW4gPiB0bWluIHx8IHRtaW4gIT09IHRtaW4gKSB0bWluID0gdHptaW47XG5cblx0XHRpZiAoIHR6bWF4IDwgdG1heCB8fCB0bWF4ICE9PSB0bWF4ICkgdG1heCA9IHR6bWF4O1xuXG5cdFx0Ly9yZXR1cm4gcG9pbnQgY2xvc2VzdCB0byB0aGUgcmF5IChwb3NpdGl2ZSBzaWRlKVxuXG5cdFx0aWYgKCB0bWF4IDwgMCApIHJldHVybiBudWxsO1xuXG5cdFx0cmV0dXJuIHRoaXMuYXQoIHRtaW4gPj0gMCA/IHRtaW4gOiB0bWF4LCB0YXJnZXQgKTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c0JveCggYm94ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuaW50ZXJzZWN0Qm94KCBib3gsIF92ZWN0b3IkYSApICE9PSBudWxsO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RUcmlhbmdsZSggYSwgYiwgYywgYmFja2ZhY2VDdWxsaW5nLCB0YXJnZXQgKSB7XG5cblx0XHQvLyBDb21wdXRlIHRoZSBvZmZzZXQgb3JpZ2luLCBlZGdlcywgYW5kIG5vcm1hbC5cblxuXHRcdC8vIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL3Btam9uaWFrL0dlb21ldHJpY1Rvb2xzL2Jsb2IvbWFzdGVyL0dURW5naW5lL0luY2x1ZGUvTWF0aGVtYXRpY3MvR3RlSW50clJheTNUcmlhbmdsZTMuaFxuXG5cdFx0X2VkZ2UxLnN1YlZlY3RvcnMoIGIsIGEgKTtcblx0XHRfZWRnZTIuc3ViVmVjdG9ycyggYywgYSApO1xuXHRcdF9ub3JtYWwkMS5jcm9zc1ZlY3RvcnMoIF9lZGdlMSwgX2VkZ2UyICk7XG5cblx0XHQvLyBTb2x2ZSBRICsgdCpEID0gYjEqRTEgKyBiMipFMiAoUSA9IGtEaWZmLCBEID0gcmF5IGRpcmVjdGlvbixcblx0XHQvLyBFMSA9IGtFZGdlMSwgRTIgPSBrRWRnZTIsIE4gPSBDcm9zcyhFMSxFMikpIGJ5XG5cdFx0Ly8gICB8RG90KEQsTil8KmIxID0gc2lnbihEb3QoRCxOKSkqRG90KEQsQ3Jvc3MoUSxFMikpXG5cdFx0Ly8gICB8RG90KEQsTil8KmIyID0gc2lnbihEb3QoRCxOKSkqRG90KEQsQ3Jvc3MoRTEsUSkpXG5cdFx0Ly8gICB8RG90KEQsTil8KnQgPSAtc2lnbihEb3QoRCxOKSkqRG90KFEsTilcblx0XHRsZXQgRGROID0gdGhpcy5kaXJlY3Rpb24uZG90KCBfbm9ybWFsJDEgKTtcblx0XHRsZXQgc2lnbjtcblxuXHRcdGlmICggRGROID4gMCApIHtcblxuXHRcdFx0aWYgKCBiYWNrZmFjZUN1bGxpbmcgKSByZXR1cm4gbnVsbDtcblx0XHRcdHNpZ24gPSAxO1xuXG5cdFx0fSBlbHNlIGlmICggRGROIDwgMCApIHtcblxuXHRcdFx0c2lnbiA9IC0gMTtcblx0XHRcdERkTiA9IC0gRGROO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9XG5cblx0XHRfZGlmZi5zdWJWZWN0b3JzKCB0aGlzLm9yaWdpbiwgYSApO1xuXHRcdGNvbnN0IERkUXhFMiA9IHNpZ24gKiB0aGlzLmRpcmVjdGlvbi5kb3QoIF9lZGdlMi5jcm9zc1ZlY3RvcnMoIF9kaWZmLCBfZWRnZTIgKSApO1xuXG5cdFx0Ly8gYjEgPCAwLCBubyBpbnRlcnNlY3Rpb25cblx0XHRpZiAoIERkUXhFMiA8IDAgKSB7XG5cblx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgRGRFMXhRID0gc2lnbiAqIHRoaXMuZGlyZWN0aW9uLmRvdCggX2VkZ2UxLmNyb3NzKCBfZGlmZiApICk7XG5cblx0XHQvLyBiMiA8IDAsIG5vIGludGVyc2VjdGlvblxuXHRcdGlmICggRGRFMXhRIDwgMCApIHtcblxuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9XG5cblx0XHQvLyBiMStiMiA+IDEsIG5vIGludGVyc2VjdGlvblxuXHRcdGlmICggRGRReEUyICsgRGRFMXhRID4gRGROICkge1xuXG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdC8vIExpbmUgaW50ZXJzZWN0cyB0cmlhbmdsZSwgY2hlY2sgaWYgcmF5IGRvZXMuXG5cdFx0Y29uc3QgUWROID0gLSBzaWduICogX2RpZmYuZG90KCBfbm9ybWFsJDEgKTtcblxuXHRcdC8vIHQgPCAwLCBubyBpbnRlcnNlY3Rpb25cblx0XHRpZiAoIFFkTiA8IDAgKSB7XG5cblx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0fVxuXG5cdFx0Ly8gUmF5IGludGVyc2VjdHMgdHJpYW5nbGUuXG5cdFx0cmV0dXJuIHRoaXMuYXQoIFFkTiAvIERkTiwgdGFyZ2V0ICk7XG5cblx0fVxuXG5cdGFwcGx5TWF0cml4NCggbWF0cml4NCApIHtcblxuXHRcdHRoaXMub3JpZ2luLmFwcGx5TWF0cml4NCggbWF0cml4NCApO1xuXHRcdHRoaXMuZGlyZWN0aW9uLnRyYW5zZm9ybURpcmVjdGlvbiggbWF0cml4NCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGVxdWFscyggcmF5ICkge1xuXG5cdFx0cmV0dXJuIHJheS5vcmlnaW4uZXF1YWxzKCB0aGlzLm9yaWdpbiApICYmIHJheS5kaXJlY3Rpb24uZXF1YWxzKCB0aGlzLmRpcmVjdGlvbiApO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgTWF0cml4NCB7XG5cblx0Y29uc3RydWN0b3IoIG4xMSwgbjEyLCBuMTMsIG4xNCwgbjIxLCBuMjIsIG4yMywgbjI0LCBuMzEsIG4zMiwgbjMzLCBuMzQsIG40MSwgbjQyLCBuNDMsIG40NCApIHtcblxuXHRcdE1hdHJpeDQucHJvdG90eXBlLmlzTWF0cml4NCA9IHRydWU7XG5cblx0XHR0aGlzLmVsZW1lbnRzID0gW1xuXG5cdFx0XHQxLCAwLCAwLCAwLFxuXHRcdFx0MCwgMSwgMCwgMCxcblx0XHRcdDAsIDAsIDEsIDAsXG5cdFx0XHQwLCAwLCAwLCAxXG5cblx0XHRdO1xuXG5cdFx0aWYgKCBuMTEgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGhpcy5zZXQoIG4xMSwgbjEyLCBuMTMsIG4xNCwgbjIxLCBuMjIsIG4yMywgbjI0LCBuMzEsIG4zMiwgbjMzLCBuMzQsIG40MSwgbjQyLCBuNDMsIG40NCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRzZXQoIG4xMSwgbjEyLCBuMTMsIG4xNCwgbjIxLCBuMjIsIG4yMywgbjI0LCBuMzEsIG4zMiwgbjMzLCBuMzQsIG40MSwgbjQyLCBuNDMsIG40NCApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdHRlWyAwIF0gPSBuMTE7IHRlWyA0IF0gPSBuMTI7IHRlWyA4IF0gPSBuMTM7IHRlWyAxMiBdID0gbjE0O1xuXHRcdHRlWyAxIF0gPSBuMjE7IHRlWyA1IF0gPSBuMjI7IHRlWyA5IF0gPSBuMjM7IHRlWyAxMyBdID0gbjI0O1xuXHRcdHRlWyAyIF0gPSBuMzE7IHRlWyA2IF0gPSBuMzI7IHRlWyAxMCBdID0gbjMzOyB0ZVsgMTQgXSA9IG4zNDtcblx0XHR0ZVsgMyBdID0gbjQxOyB0ZVsgNyBdID0gbjQyOyB0ZVsgMTEgXSA9IG40MzsgdGVbIDE1IF0gPSBuNDQ7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0aWRlbnRpdHkoKSB7XG5cblx0XHR0aGlzLnNldChcblxuXHRcdFx0MSwgMCwgMCwgMCxcblx0XHRcdDAsIDEsIDAsIDAsXG5cdFx0XHQwLCAwLCAxLCAwLFxuXHRcdFx0MCwgMCwgMCwgMVxuXG5cdFx0KTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgTWF0cml4NCgpLmZyb21BcnJheSggdGhpcy5lbGVtZW50cyApO1xuXG5cdH1cblxuXHRjb3B5KCBtICkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXHRcdGNvbnN0IG1lID0gbS5lbGVtZW50cztcblxuXHRcdHRlWyAwIF0gPSBtZVsgMCBdOyB0ZVsgMSBdID0gbWVbIDEgXTsgdGVbIDIgXSA9IG1lWyAyIF07IHRlWyAzIF0gPSBtZVsgMyBdO1xuXHRcdHRlWyA0IF0gPSBtZVsgNCBdOyB0ZVsgNSBdID0gbWVbIDUgXTsgdGVbIDYgXSA9IG1lWyA2IF07IHRlWyA3IF0gPSBtZVsgNyBdO1xuXHRcdHRlWyA4IF0gPSBtZVsgOCBdOyB0ZVsgOSBdID0gbWVbIDkgXTsgdGVbIDEwIF0gPSBtZVsgMTAgXTsgdGVbIDExIF0gPSBtZVsgMTEgXTtcblx0XHR0ZVsgMTIgXSA9IG1lWyAxMiBdOyB0ZVsgMTMgXSA9IG1lWyAxMyBdOyB0ZVsgMTQgXSA9IG1lWyAxNCBdOyB0ZVsgMTUgXSA9IG1lWyAxNSBdO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvcHlQb3NpdGlvbiggbSApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cywgbWUgPSBtLmVsZW1lbnRzO1xuXG5cdFx0dGVbIDEyIF0gPSBtZVsgMTIgXTtcblx0XHR0ZVsgMTMgXSA9IG1lWyAxMyBdO1xuXHRcdHRlWyAxNCBdID0gbWVbIDE0IF07XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbU1hdHJpeDMoIG0gKSB7XG5cblx0XHRjb25zdCBtZSA9IG0uZWxlbWVudHM7XG5cblx0XHR0aGlzLnNldChcblxuXHRcdFx0bWVbIDAgXSwgbWVbIDMgXSwgbWVbIDYgXSwgMCxcblx0XHRcdG1lWyAxIF0sIG1lWyA0IF0sIG1lWyA3IF0sIDAsXG5cdFx0XHRtZVsgMiBdLCBtZVsgNSBdLCBtZVsgOCBdLCAwLFxuXHRcdFx0MCwgMCwgMCwgMVxuXG5cdFx0KTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRleHRyYWN0QmFzaXMoIHhBeGlzLCB5QXhpcywgekF4aXMgKSB7XG5cblx0XHR4QXhpcy5zZXRGcm9tTWF0cml4Q29sdW1uKCB0aGlzLCAwICk7XG5cdFx0eUF4aXMuc2V0RnJvbU1hdHJpeENvbHVtbiggdGhpcywgMSApO1xuXHRcdHpBeGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIHRoaXMsIDIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlQmFzaXMoIHhBeGlzLCB5QXhpcywgekF4aXMgKSB7XG5cblx0XHR0aGlzLnNldChcblx0XHRcdHhBeGlzLngsIHlBeGlzLngsIHpBeGlzLngsIDAsXG5cdFx0XHR4QXhpcy55LCB5QXhpcy55LCB6QXhpcy55LCAwLFxuXHRcdFx0eEF4aXMueiwgeUF4aXMueiwgekF4aXMueiwgMCxcblx0XHRcdDAsIDAsIDAsIDFcblx0XHQpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGV4dHJhY3RSb3RhdGlvbiggbSApIHtcblxuXHRcdC8vIHRoaXMgbWV0aG9kIGRvZXMgbm90IHN1cHBvcnQgcmVmbGVjdGlvbiBtYXRyaWNlc1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXHRcdGNvbnN0IG1lID0gbS5lbGVtZW50cztcblxuXHRcdGNvbnN0IHNjYWxlWCA9IDEgLyBfdjEkNS5zZXRGcm9tTWF0cml4Q29sdW1uKCBtLCAwICkubGVuZ3RoKCk7XG5cdFx0Y29uc3Qgc2NhbGVZID0gMSAvIF92MSQ1LnNldEZyb21NYXRyaXhDb2x1bW4oIG0sIDEgKS5sZW5ndGgoKTtcblx0XHRjb25zdCBzY2FsZVogPSAxIC8gX3YxJDUuc2V0RnJvbU1hdHJpeENvbHVtbiggbSwgMiApLmxlbmd0aCgpO1xuXG5cdFx0dGVbIDAgXSA9IG1lWyAwIF0gKiBzY2FsZVg7XG5cdFx0dGVbIDEgXSA9IG1lWyAxIF0gKiBzY2FsZVg7XG5cdFx0dGVbIDIgXSA9IG1lWyAyIF0gKiBzY2FsZVg7XG5cdFx0dGVbIDMgXSA9IDA7XG5cblx0XHR0ZVsgNCBdID0gbWVbIDQgXSAqIHNjYWxlWTtcblx0XHR0ZVsgNSBdID0gbWVbIDUgXSAqIHNjYWxlWTtcblx0XHR0ZVsgNiBdID0gbWVbIDYgXSAqIHNjYWxlWTtcblx0XHR0ZVsgNyBdID0gMDtcblxuXHRcdHRlWyA4IF0gPSBtZVsgOCBdICogc2NhbGVaO1xuXHRcdHRlWyA5IF0gPSBtZVsgOSBdICogc2NhbGVaO1xuXHRcdHRlWyAxMCBdID0gbWVbIDEwIF0gKiBzY2FsZVo7XG5cdFx0dGVbIDExIF0gPSAwO1xuXG5cdFx0dGVbIDEyIF0gPSAwO1xuXHRcdHRlWyAxMyBdID0gMDtcblx0XHR0ZVsgMTQgXSA9IDA7XG5cdFx0dGVbIDE1IF0gPSAxO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1ha2VSb3RhdGlvbkZyb21FdWxlciggZXVsZXIgKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cblx0XHRjb25zdCB4ID0gZXVsZXIueCwgeSA9IGV1bGVyLnksIHogPSBldWxlci56O1xuXHRcdGNvbnN0IGEgPSBNYXRoLmNvcyggeCApLCBiID0gTWF0aC5zaW4oIHggKTtcblx0XHRjb25zdCBjID0gTWF0aC5jb3MoIHkgKSwgZCA9IE1hdGguc2luKCB5ICk7XG5cdFx0Y29uc3QgZSA9IE1hdGguY29zKCB6ICksIGYgPSBNYXRoLnNpbiggeiApO1xuXG5cdFx0aWYgKCBldWxlci5vcmRlciA9PT0gJ1hZWicgKSB7XG5cblx0XHRcdGNvbnN0IGFlID0gYSAqIGUsIGFmID0gYSAqIGYsIGJlID0gYiAqIGUsIGJmID0gYiAqIGY7XG5cblx0XHRcdHRlWyAwIF0gPSBjICogZTtcblx0XHRcdHRlWyA0IF0gPSAtIGMgKiBmO1xuXHRcdFx0dGVbIDggXSA9IGQ7XG5cblx0XHRcdHRlWyAxIF0gPSBhZiArIGJlICogZDtcblx0XHRcdHRlWyA1IF0gPSBhZSAtIGJmICogZDtcblx0XHRcdHRlWyA5IF0gPSAtIGIgKiBjO1xuXG5cdFx0XHR0ZVsgMiBdID0gYmYgLSBhZSAqIGQ7XG5cdFx0XHR0ZVsgNiBdID0gYmUgKyBhZiAqIGQ7XG5cdFx0XHR0ZVsgMTAgXSA9IGEgKiBjO1xuXG5cdFx0fSBlbHNlIGlmICggZXVsZXIub3JkZXIgPT09ICdZWFonICkge1xuXG5cdFx0XHRjb25zdCBjZSA9IGMgKiBlLCBjZiA9IGMgKiBmLCBkZSA9IGQgKiBlLCBkZiA9IGQgKiBmO1xuXG5cdFx0XHR0ZVsgMCBdID0gY2UgKyBkZiAqIGI7XG5cdFx0XHR0ZVsgNCBdID0gZGUgKiBiIC0gY2Y7XG5cdFx0XHR0ZVsgOCBdID0gYSAqIGQ7XG5cblx0XHRcdHRlWyAxIF0gPSBhICogZjtcblx0XHRcdHRlWyA1IF0gPSBhICogZTtcblx0XHRcdHRlWyA5IF0gPSAtIGI7XG5cblx0XHRcdHRlWyAyIF0gPSBjZiAqIGIgLSBkZTtcblx0XHRcdHRlWyA2IF0gPSBkZiArIGNlICogYjtcblx0XHRcdHRlWyAxMCBdID0gYSAqIGM7XG5cblx0XHR9IGVsc2UgaWYgKCBldWxlci5vcmRlciA9PT0gJ1pYWScgKSB7XG5cblx0XHRcdGNvbnN0IGNlID0gYyAqIGUsIGNmID0gYyAqIGYsIGRlID0gZCAqIGUsIGRmID0gZCAqIGY7XG5cblx0XHRcdHRlWyAwIF0gPSBjZSAtIGRmICogYjtcblx0XHRcdHRlWyA0IF0gPSAtIGEgKiBmO1xuXHRcdFx0dGVbIDggXSA9IGRlICsgY2YgKiBiO1xuXG5cdFx0XHR0ZVsgMSBdID0gY2YgKyBkZSAqIGI7XG5cdFx0XHR0ZVsgNSBdID0gYSAqIGU7XG5cdFx0XHR0ZVsgOSBdID0gZGYgLSBjZSAqIGI7XG5cblx0XHRcdHRlWyAyIF0gPSAtIGEgKiBkO1xuXHRcdFx0dGVbIDYgXSA9IGI7XG5cdFx0XHR0ZVsgMTAgXSA9IGEgKiBjO1xuXG5cdFx0fSBlbHNlIGlmICggZXVsZXIub3JkZXIgPT09ICdaWVgnICkge1xuXG5cdFx0XHRjb25zdCBhZSA9IGEgKiBlLCBhZiA9IGEgKiBmLCBiZSA9IGIgKiBlLCBiZiA9IGIgKiBmO1xuXG5cdFx0XHR0ZVsgMCBdID0gYyAqIGU7XG5cdFx0XHR0ZVsgNCBdID0gYmUgKiBkIC0gYWY7XG5cdFx0XHR0ZVsgOCBdID0gYWUgKiBkICsgYmY7XG5cblx0XHRcdHRlWyAxIF0gPSBjICogZjtcblx0XHRcdHRlWyA1IF0gPSBiZiAqIGQgKyBhZTtcblx0XHRcdHRlWyA5IF0gPSBhZiAqIGQgLSBiZTtcblxuXHRcdFx0dGVbIDIgXSA9IC0gZDtcblx0XHRcdHRlWyA2IF0gPSBiICogYztcblx0XHRcdHRlWyAxMCBdID0gYSAqIGM7XG5cblx0XHR9IGVsc2UgaWYgKCBldWxlci5vcmRlciA9PT0gJ1laWCcgKSB7XG5cblx0XHRcdGNvbnN0IGFjID0gYSAqIGMsIGFkID0gYSAqIGQsIGJjID0gYiAqIGMsIGJkID0gYiAqIGQ7XG5cblx0XHRcdHRlWyAwIF0gPSBjICogZTtcblx0XHRcdHRlWyA0IF0gPSBiZCAtIGFjICogZjtcblx0XHRcdHRlWyA4IF0gPSBiYyAqIGYgKyBhZDtcblxuXHRcdFx0dGVbIDEgXSA9IGY7XG5cdFx0XHR0ZVsgNSBdID0gYSAqIGU7XG5cdFx0XHR0ZVsgOSBdID0gLSBiICogZTtcblxuXHRcdFx0dGVbIDIgXSA9IC0gZCAqIGU7XG5cdFx0XHR0ZVsgNiBdID0gYWQgKiBmICsgYmM7XG5cdFx0XHR0ZVsgMTAgXSA9IGFjIC0gYmQgKiBmO1xuXG5cdFx0fSBlbHNlIGlmICggZXVsZXIub3JkZXIgPT09ICdYWlknICkge1xuXG5cdFx0XHRjb25zdCBhYyA9IGEgKiBjLCBhZCA9IGEgKiBkLCBiYyA9IGIgKiBjLCBiZCA9IGIgKiBkO1xuXG5cdFx0XHR0ZVsgMCBdID0gYyAqIGU7XG5cdFx0XHR0ZVsgNCBdID0gLSBmO1xuXHRcdFx0dGVbIDggXSA9IGQgKiBlO1xuXG5cdFx0XHR0ZVsgMSBdID0gYWMgKiBmICsgYmQ7XG5cdFx0XHR0ZVsgNSBdID0gYSAqIGU7XG5cdFx0XHR0ZVsgOSBdID0gYWQgKiBmIC0gYmM7XG5cblx0XHRcdHRlWyAyIF0gPSBiYyAqIGYgLSBhZDtcblx0XHRcdHRlWyA2IF0gPSBiICogZTtcblx0XHRcdHRlWyAxMCBdID0gYmQgKiBmICsgYWM7XG5cblx0XHR9XG5cblx0XHQvLyBib3R0b20gcm93XG5cdFx0dGVbIDMgXSA9IDA7XG5cdFx0dGVbIDcgXSA9IDA7XG5cdFx0dGVbIDExIF0gPSAwO1xuXG5cdFx0Ly8gbGFzdCBjb2x1bW5cblx0XHR0ZVsgMTIgXSA9IDA7XG5cdFx0dGVbIDEzIF0gPSAwO1xuXHRcdHRlWyAxNCBdID0gMDtcblx0XHR0ZVsgMTUgXSA9IDE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bWFrZVJvdGF0aW9uRnJvbVF1YXRlcm5pb24oIHEgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5jb21wb3NlKCBfemVybywgcSwgX29uZSApO1xuXG5cdH1cblxuXHRsb29rQXQoIGV5ZSwgdGFyZ2V0LCB1cCApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdF96LnN1YlZlY3RvcnMoIGV5ZSwgdGFyZ2V0ICk7XG5cblx0XHRpZiAoIF96Lmxlbmd0aFNxKCkgPT09IDAgKSB7XG5cblx0XHRcdC8vIGV5ZSBhbmQgdGFyZ2V0IGFyZSBpbiB0aGUgc2FtZSBwb3NpdGlvblxuXG5cdFx0XHRfei56ID0gMTtcblxuXHRcdH1cblxuXHRcdF96Lm5vcm1hbGl6ZSgpO1xuXHRcdF94LmNyb3NzVmVjdG9ycyggdXAsIF96ICk7XG5cblx0XHRpZiAoIF94Lmxlbmd0aFNxKCkgPT09IDAgKSB7XG5cblx0XHRcdC8vIHVwIGFuZCB6IGFyZSBwYXJhbGxlbFxuXG5cdFx0XHRpZiAoIE1hdGguYWJzKCB1cC56ICkgPT09IDEgKSB7XG5cblx0XHRcdFx0X3oueCArPSAwLjAwMDE7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0X3oueiArPSAwLjAwMDE7XG5cblx0XHRcdH1cblxuXHRcdFx0X3oubm9ybWFsaXplKCk7XG5cdFx0XHRfeC5jcm9zc1ZlY3RvcnMoIHVwLCBfeiApO1xuXG5cdFx0fVxuXG5cdFx0X3gubm9ybWFsaXplKCk7XG5cdFx0X3kuY3Jvc3NWZWN0b3JzKCBfeiwgX3ggKTtcblxuXHRcdHRlWyAwIF0gPSBfeC54OyB0ZVsgNCBdID0gX3kueDsgdGVbIDggXSA9IF96Lng7XG5cdFx0dGVbIDEgXSA9IF94Lnk7IHRlWyA1IF0gPSBfeS55OyB0ZVsgOSBdID0gX3oueTtcblx0XHR0ZVsgMiBdID0gX3guejsgdGVbIDYgXSA9IF95Lno7IHRlWyAxMCBdID0gX3ouejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtdWx0aXBseSggbSApIHtcblxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5TWF0cmljZXMoIHRoaXMsIG0gKTtcblxuXHR9XG5cblx0cHJlbXVsdGlwbHkoIG0gKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseU1hdHJpY2VzKCBtLCB0aGlzICk7XG5cblx0fVxuXG5cdG11bHRpcGx5TWF0cmljZXMoIGEsIGIgKSB7XG5cblx0XHRjb25zdCBhZSA9IGEuZWxlbWVudHM7XG5cdFx0Y29uc3QgYmUgPSBiLmVsZW1lbnRzO1xuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdGNvbnN0IGExMSA9IGFlWyAwIF0sIGExMiA9IGFlWyA0IF0sIGExMyA9IGFlWyA4IF0sIGExNCA9IGFlWyAxMiBdO1xuXHRcdGNvbnN0IGEyMSA9IGFlWyAxIF0sIGEyMiA9IGFlWyA1IF0sIGEyMyA9IGFlWyA5IF0sIGEyNCA9IGFlWyAxMyBdO1xuXHRcdGNvbnN0IGEzMSA9IGFlWyAyIF0sIGEzMiA9IGFlWyA2IF0sIGEzMyA9IGFlWyAxMCBdLCBhMzQgPSBhZVsgMTQgXTtcblx0XHRjb25zdCBhNDEgPSBhZVsgMyBdLCBhNDIgPSBhZVsgNyBdLCBhNDMgPSBhZVsgMTEgXSwgYTQ0ID0gYWVbIDE1IF07XG5cblx0XHRjb25zdCBiMTEgPSBiZVsgMCBdLCBiMTIgPSBiZVsgNCBdLCBiMTMgPSBiZVsgOCBdLCBiMTQgPSBiZVsgMTIgXTtcblx0XHRjb25zdCBiMjEgPSBiZVsgMSBdLCBiMjIgPSBiZVsgNSBdLCBiMjMgPSBiZVsgOSBdLCBiMjQgPSBiZVsgMTMgXTtcblx0XHRjb25zdCBiMzEgPSBiZVsgMiBdLCBiMzIgPSBiZVsgNiBdLCBiMzMgPSBiZVsgMTAgXSwgYjM0ID0gYmVbIDE0IF07XG5cdFx0Y29uc3QgYjQxID0gYmVbIDMgXSwgYjQyID0gYmVbIDcgXSwgYjQzID0gYmVbIDExIF0sIGI0NCA9IGJlWyAxNSBdO1xuXG5cdFx0dGVbIDAgXSA9IGExMSAqIGIxMSArIGExMiAqIGIyMSArIGExMyAqIGIzMSArIGExNCAqIGI0MTtcblx0XHR0ZVsgNCBdID0gYTExICogYjEyICsgYTEyICogYjIyICsgYTEzICogYjMyICsgYTE0ICogYjQyO1xuXHRcdHRlWyA4IF0gPSBhMTEgKiBiMTMgKyBhMTIgKiBiMjMgKyBhMTMgKiBiMzMgKyBhMTQgKiBiNDM7XG5cdFx0dGVbIDEyIF0gPSBhMTEgKiBiMTQgKyBhMTIgKiBiMjQgKyBhMTMgKiBiMzQgKyBhMTQgKiBiNDQ7XG5cblx0XHR0ZVsgMSBdID0gYTIxICogYjExICsgYTIyICogYjIxICsgYTIzICogYjMxICsgYTI0ICogYjQxO1xuXHRcdHRlWyA1IF0gPSBhMjEgKiBiMTIgKyBhMjIgKiBiMjIgKyBhMjMgKiBiMzIgKyBhMjQgKiBiNDI7XG5cdFx0dGVbIDkgXSA9IGEyMSAqIGIxMyArIGEyMiAqIGIyMyArIGEyMyAqIGIzMyArIGEyNCAqIGI0Mztcblx0XHR0ZVsgMTMgXSA9IGEyMSAqIGIxNCArIGEyMiAqIGIyNCArIGEyMyAqIGIzNCArIGEyNCAqIGI0NDtcblxuXHRcdHRlWyAyIF0gPSBhMzEgKiBiMTEgKyBhMzIgKiBiMjEgKyBhMzMgKiBiMzEgKyBhMzQgKiBiNDE7XG5cdFx0dGVbIDYgXSA9IGEzMSAqIGIxMiArIGEzMiAqIGIyMiArIGEzMyAqIGIzMiArIGEzNCAqIGI0Mjtcblx0XHR0ZVsgMTAgXSA9IGEzMSAqIGIxMyArIGEzMiAqIGIyMyArIGEzMyAqIGIzMyArIGEzNCAqIGI0Mztcblx0XHR0ZVsgMTQgXSA9IGEzMSAqIGIxNCArIGEzMiAqIGIyNCArIGEzMyAqIGIzNCArIGEzNCAqIGI0NDtcblxuXHRcdHRlWyAzIF0gPSBhNDEgKiBiMTEgKyBhNDIgKiBiMjEgKyBhNDMgKiBiMzEgKyBhNDQgKiBiNDE7XG5cdFx0dGVbIDcgXSA9IGE0MSAqIGIxMiArIGE0MiAqIGIyMiArIGE0MyAqIGIzMiArIGE0NCAqIGI0Mjtcblx0XHR0ZVsgMTEgXSA9IGE0MSAqIGIxMyArIGE0MiAqIGIyMyArIGE0MyAqIGIzMyArIGE0NCAqIGI0Mztcblx0XHR0ZVsgMTUgXSA9IGE0MSAqIGIxNCArIGE0MiAqIGIyNCArIGE0MyAqIGIzNCArIGE0NCAqIGI0NDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtdWx0aXBseVNjYWxhciggcyApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdHRlWyAwIF0gKj0gczsgdGVbIDQgXSAqPSBzOyB0ZVsgOCBdICo9IHM7IHRlWyAxMiBdICo9IHM7XG5cdFx0dGVbIDEgXSAqPSBzOyB0ZVsgNSBdICo9IHM7IHRlWyA5IF0gKj0gczsgdGVbIDEzIF0gKj0gcztcblx0XHR0ZVsgMiBdICo9IHM7IHRlWyA2IF0gKj0gczsgdGVbIDEwIF0gKj0gczsgdGVbIDE0IF0gKj0gcztcblx0XHR0ZVsgMyBdICo9IHM7IHRlWyA3IF0gKj0gczsgdGVbIDExIF0gKj0gczsgdGVbIDE1IF0gKj0gcztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkZXRlcm1pbmFudCgpIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdGNvbnN0IG4xMSA9IHRlWyAwIF0sIG4xMiA9IHRlWyA0IF0sIG4xMyA9IHRlWyA4IF0sIG4xNCA9IHRlWyAxMiBdO1xuXHRcdGNvbnN0IG4yMSA9IHRlWyAxIF0sIG4yMiA9IHRlWyA1IF0sIG4yMyA9IHRlWyA5IF0sIG4yNCA9IHRlWyAxMyBdO1xuXHRcdGNvbnN0IG4zMSA9IHRlWyAyIF0sIG4zMiA9IHRlWyA2IF0sIG4zMyA9IHRlWyAxMCBdLCBuMzQgPSB0ZVsgMTQgXTtcblx0XHRjb25zdCBuNDEgPSB0ZVsgMyBdLCBuNDIgPSB0ZVsgNyBdLCBuNDMgPSB0ZVsgMTEgXSwgbjQ0ID0gdGVbIDE1IF07XG5cblx0XHQvL1RPRE86IG1ha2UgdGhpcyBtb3JlIGVmZmljaWVudFxuXHRcdC8vKCBiYXNlZCBvbiBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9hbGdlYnJhL21hdHJpeC9mdW5jdGlvbnMvaW52ZXJzZS9mb3VyRC9pbmRleC5odG0gKVxuXG5cdFx0cmV0dXJuIChcblx0XHRcdG40MSAqIChcblx0XHRcdFx0KyBuMTQgKiBuMjMgKiBuMzJcblx0XHRcdFx0IC0gbjEzICogbjI0ICogbjMyXG5cdFx0XHRcdCAtIG4xNCAqIG4yMiAqIG4zM1xuXHRcdFx0XHQgKyBuMTIgKiBuMjQgKiBuMzNcblx0XHRcdFx0ICsgbjEzICogbjIyICogbjM0XG5cdFx0XHRcdCAtIG4xMiAqIG4yMyAqIG4zNFxuXHRcdFx0KSArXG5cdFx0XHRuNDIgKiAoXG5cdFx0XHRcdCsgbjExICogbjIzICogbjM0XG5cdFx0XHRcdCAtIG4xMSAqIG4yNCAqIG4zM1xuXHRcdFx0XHQgKyBuMTQgKiBuMjEgKiBuMzNcblx0XHRcdFx0IC0gbjEzICogbjIxICogbjM0XG5cdFx0XHRcdCArIG4xMyAqIG4yNCAqIG4zMVxuXHRcdFx0XHQgLSBuMTQgKiBuMjMgKiBuMzFcblx0XHRcdCkgK1xuXHRcdFx0bjQzICogKFxuXHRcdFx0XHQrIG4xMSAqIG4yNCAqIG4zMlxuXHRcdFx0XHQgLSBuMTEgKiBuMjIgKiBuMzRcblx0XHRcdFx0IC0gbjE0ICogbjIxICogbjMyXG5cdFx0XHRcdCArIG4xMiAqIG4yMSAqIG4zNFxuXHRcdFx0XHQgKyBuMTQgKiBuMjIgKiBuMzFcblx0XHRcdFx0IC0gbjEyICogbjI0ICogbjMxXG5cdFx0XHQpICtcblx0XHRcdG40NCAqIChcblx0XHRcdFx0LSBuMTMgKiBuMjIgKiBuMzFcblx0XHRcdFx0IC0gbjExICogbjIzICogbjMyXG5cdFx0XHRcdCArIG4xMSAqIG4yMiAqIG4zM1xuXHRcdFx0XHQgKyBuMTMgKiBuMjEgKiBuMzJcblx0XHRcdFx0IC0gbjEyICogbjIxICogbjMzXG5cdFx0XHRcdCArIG4xMiAqIG4yMyAqIG4zMVxuXHRcdFx0KVxuXG5cdFx0KTtcblxuXHR9XG5cblx0dHJhbnNwb3NlKCkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXHRcdGxldCB0bXA7XG5cblx0XHR0bXAgPSB0ZVsgMSBdOyB0ZVsgMSBdID0gdGVbIDQgXTsgdGVbIDQgXSA9IHRtcDtcblx0XHR0bXAgPSB0ZVsgMiBdOyB0ZVsgMiBdID0gdGVbIDggXTsgdGVbIDggXSA9IHRtcDtcblx0XHR0bXAgPSB0ZVsgNiBdOyB0ZVsgNiBdID0gdGVbIDkgXTsgdGVbIDkgXSA9IHRtcDtcblxuXHRcdHRtcCA9IHRlWyAzIF07IHRlWyAzIF0gPSB0ZVsgMTIgXTsgdGVbIDEyIF0gPSB0bXA7XG5cdFx0dG1wID0gdGVbIDcgXTsgdGVbIDcgXSA9IHRlWyAxMyBdOyB0ZVsgMTMgXSA9IHRtcDtcblx0XHR0bXAgPSB0ZVsgMTEgXTsgdGVbIDExIF0gPSB0ZVsgMTQgXTsgdGVbIDE0IF0gPSB0bXA7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0UG9zaXRpb24oIHgsIHksIHogKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cblx0XHRpZiAoIHguaXNWZWN0b3IzICkge1xuXG5cdFx0XHR0ZVsgMTIgXSA9IHgueDtcblx0XHRcdHRlWyAxMyBdID0geC55O1xuXHRcdFx0dGVbIDE0IF0gPSB4Lno7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0ZVsgMTIgXSA9IHg7XG5cdFx0XHR0ZVsgMTMgXSA9IHk7XG5cdFx0XHR0ZVsgMTQgXSA9IHo7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0aW52ZXJ0KCkge1xuXG5cdFx0Ly8gYmFzZWQgb24gaHR0cDovL3d3dy5ldWNsaWRlYW5zcGFjZS5jb20vbWF0aHMvYWxnZWJyYS9tYXRyaXgvZnVuY3Rpb25zL2ludmVyc2UvZm91ckQvaW5kZXguaHRtXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzLFxuXG5cdFx0XHRuMTEgPSB0ZVsgMCBdLCBuMjEgPSB0ZVsgMSBdLCBuMzEgPSB0ZVsgMiBdLCBuNDEgPSB0ZVsgMyBdLFxuXHRcdFx0bjEyID0gdGVbIDQgXSwgbjIyID0gdGVbIDUgXSwgbjMyID0gdGVbIDYgXSwgbjQyID0gdGVbIDcgXSxcblx0XHRcdG4xMyA9IHRlWyA4IF0sIG4yMyA9IHRlWyA5IF0sIG4zMyA9IHRlWyAxMCBdLCBuNDMgPSB0ZVsgMTEgXSxcblx0XHRcdG4xNCA9IHRlWyAxMiBdLCBuMjQgPSB0ZVsgMTMgXSwgbjM0ID0gdGVbIDE0IF0sIG40NCA9IHRlWyAxNSBdLFxuXG5cdFx0XHR0MTEgPSBuMjMgKiBuMzQgKiBuNDIgLSBuMjQgKiBuMzMgKiBuNDIgKyBuMjQgKiBuMzIgKiBuNDMgLSBuMjIgKiBuMzQgKiBuNDMgLSBuMjMgKiBuMzIgKiBuNDQgKyBuMjIgKiBuMzMgKiBuNDQsXG5cdFx0XHR0MTIgPSBuMTQgKiBuMzMgKiBuNDIgLSBuMTMgKiBuMzQgKiBuNDIgLSBuMTQgKiBuMzIgKiBuNDMgKyBuMTIgKiBuMzQgKiBuNDMgKyBuMTMgKiBuMzIgKiBuNDQgLSBuMTIgKiBuMzMgKiBuNDQsXG5cdFx0XHR0MTMgPSBuMTMgKiBuMjQgKiBuNDIgLSBuMTQgKiBuMjMgKiBuNDIgKyBuMTQgKiBuMjIgKiBuNDMgLSBuMTIgKiBuMjQgKiBuNDMgLSBuMTMgKiBuMjIgKiBuNDQgKyBuMTIgKiBuMjMgKiBuNDQsXG5cdFx0XHR0MTQgPSBuMTQgKiBuMjMgKiBuMzIgLSBuMTMgKiBuMjQgKiBuMzIgLSBuMTQgKiBuMjIgKiBuMzMgKyBuMTIgKiBuMjQgKiBuMzMgKyBuMTMgKiBuMjIgKiBuMzQgLSBuMTIgKiBuMjMgKiBuMzQ7XG5cblx0XHRjb25zdCBkZXQgPSBuMTEgKiB0MTEgKyBuMjEgKiB0MTIgKyBuMzEgKiB0MTMgKyBuNDEgKiB0MTQ7XG5cblx0XHRpZiAoIGRldCA9PT0gMCApIHJldHVybiB0aGlzLnNldCggMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCwgMCApO1xuXG5cdFx0Y29uc3QgZGV0SW52ID0gMSAvIGRldDtcblxuXHRcdHRlWyAwIF0gPSB0MTEgKiBkZXRJbnY7XG5cdFx0dGVbIDEgXSA9ICggbjI0ICogbjMzICogbjQxIC0gbjIzICogbjM0ICogbjQxIC0gbjI0ICogbjMxICogbjQzICsgbjIxICogbjM0ICogbjQzICsgbjIzICogbjMxICogbjQ0IC0gbjIxICogbjMzICogbjQ0ICkgKiBkZXRJbnY7XG5cdFx0dGVbIDIgXSA9ICggbjIyICogbjM0ICogbjQxIC0gbjI0ICogbjMyICogbjQxICsgbjI0ICogbjMxICogbjQyIC0gbjIxICogbjM0ICogbjQyIC0gbjIyICogbjMxICogbjQ0ICsgbjIxICogbjMyICogbjQ0ICkgKiBkZXRJbnY7XG5cdFx0dGVbIDMgXSA9ICggbjIzICogbjMyICogbjQxIC0gbjIyICogbjMzICogbjQxIC0gbjIzICogbjMxICogbjQyICsgbjIxICogbjMzICogbjQyICsgbjIyICogbjMxICogbjQzIC0gbjIxICogbjMyICogbjQzICkgKiBkZXRJbnY7XG5cblx0XHR0ZVsgNCBdID0gdDEyICogZGV0SW52O1xuXHRcdHRlWyA1IF0gPSAoIG4xMyAqIG4zNCAqIG40MSAtIG4xNCAqIG4zMyAqIG40MSArIG4xNCAqIG4zMSAqIG40MyAtIG4xMSAqIG4zNCAqIG40MyAtIG4xMyAqIG4zMSAqIG40NCArIG4xMSAqIG4zMyAqIG40NCApICogZGV0SW52O1xuXHRcdHRlWyA2IF0gPSAoIG4xNCAqIG4zMiAqIG40MSAtIG4xMiAqIG4zNCAqIG40MSAtIG4xNCAqIG4zMSAqIG40MiArIG4xMSAqIG4zNCAqIG40MiArIG4xMiAqIG4zMSAqIG40NCAtIG4xMSAqIG4zMiAqIG40NCApICogZGV0SW52O1xuXHRcdHRlWyA3IF0gPSAoIG4xMiAqIG4zMyAqIG40MSAtIG4xMyAqIG4zMiAqIG40MSArIG4xMyAqIG4zMSAqIG40MiAtIG4xMSAqIG4zMyAqIG40MiAtIG4xMiAqIG4zMSAqIG40MyArIG4xMSAqIG4zMiAqIG40MyApICogZGV0SW52O1xuXG5cdFx0dGVbIDggXSA9IHQxMyAqIGRldEludjtcblx0XHR0ZVsgOSBdID0gKCBuMTQgKiBuMjMgKiBuNDEgLSBuMTMgKiBuMjQgKiBuNDEgLSBuMTQgKiBuMjEgKiBuNDMgKyBuMTEgKiBuMjQgKiBuNDMgKyBuMTMgKiBuMjEgKiBuNDQgLSBuMTEgKiBuMjMgKiBuNDQgKSAqIGRldEludjtcblx0XHR0ZVsgMTAgXSA9ICggbjEyICogbjI0ICogbjQxIC0gbjE0ICogbjIyICogbjQxICsgbjE0ICogbjIxICogbjQyIC0gbjExICogbjI0ICogbjQyIC0gbjEyICogbjIxICogbjQ0ICsgbjExICogbjIyICogbjQ0ICkgKiBkZXRJbnY7XG5cdFx0dGVbIDExIF0gPSAoIG4xMyAqIG4yMiAqIG40MSAtIG4xMiAqIG4yMyAqIG40MSAtIG4xMyAqIG4yMSAqIG40MiArIG4xMSAqIG4yMyAqIG40MiArIG4xMiAqIG4yMSAqIG40MyAtIG4xMSAqIG4yMiAqIG40MyApICogZGV0SW52O1xuXG5cdFx0dGVbIDEyIF0gPSB0MTQgKiBkZXRJbnY7XG5cdFx0dGVbIDEzIF0gPSAoIG4xMyAqIG4yNCAqIG4zMSAtIG4xNCAqIG4yMyAqIG4zMSArIG4xNCAqIG4yMSAqIG4zMyAtIG4xMSAqIG4yNCAqIG4zMyAtIG4xMyAqIG4yMSAqIG4zNCArIG4xMSAqIG4yMyAqIG4zNCApICogZGV0SW52O1xuXHRcdHRlWyAxNCBdID0gKCBuMTQgKiBuMjIgKiBuMzEgLSBuMTIgKiBuMjQgKiBuMzEgLSBuMTQgKiBuMjEgKiBuMzIgKyBuMTEgKiBuMjQgKiBuMzIgKyBuMTIgKiBuMjEgKiBuMzQgLSBuMTEgKiBuMjIgKiBuMzQgKSAqIGRldEludjtcblx0XHR0ZVsgMTUgXSA9ICggbjEyICogbjIzICogbjMxIC0gbjEzICogbjIyICogbjMxICsgbjEzICogbjIxICogbjMyIC0gbjExICogbjIzICogbjMyIC0gbjEyICogbjIxICogbjMzICsgbjExICogbjIyICogbjMzICkgKiBkZXRJbnY7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2NhbGUoIHYgKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cdFx0Y29uc3QgeCA9IHYueCwgeSA9IHYueSwgeiA9IHYuejtcblxuXHRcdHRlWyAwIF0gKj0geDsgdGVbIDQgXSAqPSB5OyB0ZVsgOCBdICo9IHo7XG5cdFx0dGVbIDEgXSAqPSB4OyB0ZVsgNSBdICo9IHk7IHRlWyA5IF0gKj0gejtcblx0XHR0ZVsgMiBdICo9IHg7IHRlWyA2IF0gKj0geTsgdGVbIDEwIF0gKj0gejtcblx0XHR0ZVsgMyBdICo9IHg7IHRlWyA3IF0gKj0geTsgdGVbIDExIF0gKj0gejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRNYXhTY2FsZU9uQXhpcygpIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdGNvbnN0IHNjYWxlWFNxID0gdGVbIDAgXSAqIHRlWyAwIF0gKyB0ZVsgMSBdICogdGVbIDEgXSArIHRlWyAyIF0gKiB0ZVsgMiBdO1xuXHRcdGNvbnN0IHNjYWxlWVNxID0gdGVbIDQgXSAqIHRlWyA0IF0gKyB0ZVsgNSBdICogdGVbIDUgXSArIHRlWyA2IF0gKiB0ZVsgNiBdO1xuXHRcdGNvbnN0IHNjYWxlWlNxID0gdGVbIDggXSAqIHRlWyA4IF0gKyB0ZVsgOSBdICogdGVbIDkgXSArIHRlWyAxMCBdICogdGVbIDEwIF07XG5cblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCBNYXRoLm1heCggc2NhbGVYU3EsIHNjYWxlWVNxLCBzY2FsZVpTcSApICk7XG5cblx0fVxuXG5cdG1ha2VUcmFuc2xhdGlvbiggeCwgeSwgeiApIHtcblxuXHRcdGlmICggeC5pc1ZlY3RvcjMgKSB7XG5cblx0XHRcdHRoaXMuc2V0KFxuXG5cdFx0XHRcdDEsIDAsIDAsIHgueCxcblx0XHRcdFx0MCwgMSwgMCwgeC55LFxuXHRcdFx0XHQwLCAwLCAxLCB4LnosXG5cdFx0XHRcdDAsIDAsIDAsIDFcblxuXHRcdFx0KTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuc2V0KFxuXG5cdFx0XHRcdDEsIDAsIDAsIHgsXG5cdFx0XHRcdDAsIDEsIDAsIHksXG5cdFx0XHRcdDAsIDAsIDEsIHosXG5cdFx0XHRcdDAsIDAsIDAsIDFcblxuXHRcdFx0KTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlUm90YXRpb25YKCB0aGV0YSApIHtcblxuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggdGhldGEgKSwgcyA9IE1hdGguc2luKCB0aGV0YSApO1xuXG5cdFx0dGhpcy5zZXQoXG5cblx0XHRcdDEsIDAsIDAsIDAsXG5cdFx0XHQwLCBjLCAtIHMsIDAsXG5cdFx0XHQwLCBzLCBjLCAwLFxuXHRcdFx0MCwgMCwgMCwgMVxuXG5cdFx0KTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlUm90YXRpb25ZKCB0aGV0YSApIHtcblxuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggdGhldGEgKSwgcyA9IE1hdGguc2luKCB0aGV0YSApO1xuXG5cdFx0dGhpcy5zZXQoXG5cblx0XHRcdCBjLCAwLCBzLCAwLFxuXHRcdFx0IDAsIDEsIDAsIDAsXG5cdFx0XHQtIHMsIDAsIGMsIDAsXG5cdFx0XHQgMCwgMCwgMCwgMVxuXG5cdFx0KTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlUm90YXRpb25aKCB0aGV0YSApIHtcblxuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggdGhldGEgKSwgcyA9IE1hdGguc2luKCB0aGV0YSApO1xuXG5cdFx0dGhpcy5zZXQoXG5cblx0XHRcdGMsIC0gcywgMCwgMCxcblx0XHRcdHMsIGMsIDAsIDAsXG5cdFx0XHQwLCAwLCAxLCAwLFxuXHRcdFx0MCwgMCwgMCwgMVxuXG5cdFx0KTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlUm90YXRpb25BeGlzKCBheGlzLCBhbmdsZSApIHtcblxuXHRcdC8vIEJhc2VkIG9uIGh0dHA6Ly93d3cuZ2FtZWRldi5uZXQvcmVmZXJlbmNlL2FydGljbGVzL2FydGljbGUxMTk5LmFzcFxuXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCBhbmdsZSApO1xuXHRcdGNvbnN0IHMgPSBNYXRoLnNpbiggYW5nbGUgKTtcblx0XHRjb25zdCB0ID0gMSAtIGM7XG5cdFx0Y29uc3QgeCA9IGF4aXMueCwgeSA9IGF4aXMueSwgeiA9IGF4aXMuejtcblx0XHRjb25zdCB0eCA9IHQgKiB4LCB0eSA9IHQgKiB5O1xuXG5cdFx0dGhpcy5zZXQoXG5cblx0XHRcdHR4ICogeCArIGMsIHR4ICogeSAtIHMgKiB6LCB0eCAqIHogKyBzICogeSwgMCxcblx0XHRcdHR4ICogeSArIHMgKiB6LCB0eSAqIHkgKyBjLCB0eSAqIHogLSBzICogeCwgMCxcblx0XHRcdHR4ICogeiAtIHMgKiB5LCB0eSAqIHogKyBzICogeCwgdCAqIHogKiB6ICsgYywgMCxcblx0XHRcdDAsIDAsIDAsIDFcblxuXHRcdCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bWFrZVNjYWxlKCB4LCB5LCB6ICkge1xuXG5cdFx0dGhpcy5zZXQoXG5cblx0XHRcdHgsIDAsIDAsIDAsXG5cdFx0XHQwLCB5LCAwLCAwLFxuXHRcdFx0MCwgMCwgeiwgMCxcblx0XHRcdDAsIDAsIDAsIDFcblxuXHRcdCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bWFrZVNoZWFyKCB4eSwgeHosIHl4LCB5eiwgengsIHp5ICkge1xuXG5cdFx0dGhpcy5zZXQoXG5cblx0XHRcdDEsIHl4LCB6eCwgMCxcblx0XHRcdHh5LCAxLCB6eSwgMCxcblx0XHRcdHh6LCB5eiwgMSwgMCxcblx0XHRcdDAsIDAsIDAsIDFcblxuXHRcdCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29tcG9zZSggcG9zaXRpb24sIHF1YXRlcm5pb24sIHNjYWxlICkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0Y29uc3QgeCA9IHF1YXRlcm5pb24uX3gsIHkgPSBxdWF0ZXJuaW9uLl95LCB6ID0gcXVhdGVybmlvbi5feiwgdyA9IHF1YXRlcm5pb24uX3c7XG5cdFx0Y29uc3QgeDIgPSB4ICsgeCxcdHkyID0geSArIHksIHoyID0geiArIHo7XG5cdFx0Y29uc3QgeHggPSB4ICogeDIsIHh5ID0geCAqIHkyLCB4eiA9IHggKiB6Mjtcblx0XHRjb25zdCB5eSA9IHkgKiB5MiwgeXogPSB5ICogejIsIHp6ID0geiAqIHoyO1xuXHRcdGNvbnN0IHd4ID0gdyAqIHgyLCB3eSA9IHcgKiB5Miwgd3ogPSB3ICogejI7XG5cblx0XHRjb25zdCBzeCA9IHNjYWxlLngsIHN5ID0gc2NhbGUueSwgc3ogPSBzY2FsZS56O1xuXG5cdFx0dGVbIDAgXSA9ICggMSAtICggeXkgKyB6eiApICkgKiBzeDtcblx0XHR0ZVsgMSBdID0gKCB4eSArIHd6ICkgKiBzeDtcblx0XHR0ZVsgMiBdID0gKCB4eiAtIHd5ICkgKiBzeDtcblx0XHR0ZVsgMyBdID0gMDtcblxuXHRcdHRlWyA0IF0gPSAoIHh5IC0gd3ogKSAqIHN5O1xuXHRcdHRlWyA1IF0gPSAoIDEgLSAoIHh4ICsgenogKSApICogc3k7XG5cdFx0dGVbIDYgXSA9ICggeXogKyB3eCApICogc3k7XG5cdFx0dGVbIDcgXSA9IDA7XG5cblx0XHR0ZVsgOCBdID0gKCB4eiArIHd5ICkgKiBzejtcblx0XHR0ZVsgOSBdID0gKCB5eiAtIHd4ICkgKiBzejtcblx0XHR0ZVsgMTAgXSA9ICggMSAtICggeHggKyB5eSApICkgKiBzejtcblx0XHR0ZVsgMTEgXSA9IDA7XG5cblx0XHR0ZVsgMTIgXSA9IHBvc2l0aW9uLng7XG5cdFx0dGVbIDEzIF0gPSBwb3NpdGlvbi55O1xuXHRcdHRlWyAxNCBdID0gcG9zaXRpb24uejtcblx0XHR0ZVsgMTUgXSA9IDE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGVjb21wb3NlKCBwb3NpdGlvbiwgcXVhdGVybmlvbiwgc2NhbGUgKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cblx0XHRsZXQgc3ggPSBfdjEkNS5zZXQoIHRlWyAwIF0sIHRlWyAxIF0sIHRlWyAyIF0gKS5sZW5ndGgoKTtcblx0XHRjb25zdCBzeSA9IF92MSQ1LnNldCggdGVbIDQgXSwgdGVbIDUgXSwgdGVbIDYgXSApLmxlbmd0aCgpO1xuXHRcdGNvbnN0IHN6ID0gX3YxJDUuc2V0KCB0ZVsgOCBdLCB0ZVsgOSBdLCB0ZVsgMTAgXSApLmxlbmd0aCgpO1xuXG5cdFx0Ly8gaWYgZGV0ZXJtaW5lIGlzIG5lZ2F0aXZlLCB3ZSBuZWVkIHRvIGludmVydCBvbmUgc2NhbGVcblx0XHRjb25zdCBkZXQgPSB0aGlzLmRldGVybWluYW50KCk7XG5cdFx0aWYgKCBkZXQgPCAwICkgc3ggPSAtIHN4O1xuXG5cdFx0cG9zaXRpb24ueCA9IHRlWyAxMiBdO1xuXHRcdHBvc2l0aW9uLnkgPSB0ZVsgMTMgXTtcblx0XHRwb3NpdGlvbi56ID0gdGVbIDE0IF07XG5cblx0XHQvLyBzY2FsZSB0aGUgcm90YXRpb24gcGFydFxuXHRcdF9tMSQ0LmNvcHkoIHRoaXMgKTtcblxuXHRcdGNvbnN0IGludlNYID0gMSAvIHN4O1xuXHRcdGNvbnN0IGludlNZID0gMSAvIHN5O1xuXHRcdGNvbnN0IGludlNaID0gMSAvIHN6O1xuXG5cdFx0X20xJDQuZWxlbWVudHNbIDAgXSAqPSBpbnZTWDtcblx0XHRfbTEkNC5lbGVtZW50c1sgMSBdICo9IGludlNYO1xuXHRcdF9tMSQ0LmVsZW1lbnRzWyAyIF0gKj0gaW52U1g7XG5cblx0XHRfbTEkNC5lbGVtZW50c1sgNCBdICo9IGludlNZO1xuXHRcdF9tMSQ0LmVsZW1lbnRzWyA1IF0gKj0gaW52U1k7XG5cdFx0X20xJDQuZWxlbWVudHNbIDYgXSAqPSBpbnZTWTtcblxuXHRcdF9tMSQ0LmVsZW1lbnRzWyA4IF0gKj0gaW52U1o7XG5cdFx0X20xJDQuZWxlbWVudHNbIDkgXSAqPSBpbnZTWjtcblx0XHRfbTEkNC5lbGVtZW50c1sgMTAgXSAqPSBpbnZTWjtcblxuXHRcdHF1YXRlcm5pb24uc2V0RnJvbVJvdGF0aW9uTWF0cml4KCBfbTEkNCApO1xuXG5cdFx0c2NhbGUueCA9IHN4O1xuXHRcdHNjYWxlLnkgPSBzeTtcblx0XHRzY2FsZS56ID0gc3o7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bWFrZVBlcnNwZWN0aXZlKCBsZWZ0LCByaWdodCwgdG9wLCBib3R0b20sIG5lYXIsIGZhciwgY29vcmRpbmF0ZVN5c3RlbSA9IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblx0XHRjb25zdCB4ID0gMiAqIG5lYXIgLyAoIHJpZ2h0IC0gbGVmdCApO1xuXHRcdGNvbnN0IHkgPSAyICogbmVhciAvICggdG9wIC0gYm90dG9tICk7XG5cblx0XHRjb25zdCBhID0gKCByaWdodCArIGxlZnQgKSAvICggcmlnaHQgLSBsZWZ0ICk7XG5cdFx0Y29uc3QgYiA9ICggdG9wICsgYm90dG9tICkgLyAoIHRvcCAtIGJvdHRvbSApO1xuXG5cdFx0bGV0IGMsIGQ7XG5cblx0XHRpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdFx0YyA9IC0gKCBmYXIgKyBuZWFyICkgLyAoIGZhciAtIG5lYXIgKTtcblx0XHRcdGQgPSAoIC0gMiAqIGZhciAqIG5lYXIgKSAvICggZmFyIC0gbmVhciApO1xuXG5cdFx0fSBlbHNlIGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR1BVQ29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdFx0YyA9IC0gZmFyIC8gKCBmYXIgLSBuZWFyICk7XG5cdFx0XHRkID0gKCAtIGZhciAqIG5lYXIgKSAvICggZmFyIC0gbmVhciApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuTWF0cml4NC5tYWtlUGVyc3BlY3RpdmUoKTogSW52YWxpZCBjb29yZGluYXRlIHN5c3RlbTogJyArIGNvb3JkaW5hdGVTeXN0ZW0gKTtcblxuXHRcdH1cblxuXHRcdHRlWyAwIF0gPSB4O1x0dGVbIDQgXSA9IDA7XHR0ZVsgOCBdID0gYTsgXHR0ZVsgMTIgXSA9IDA7XG5cdFx0dGVbIDEgXSA9IDA7XHR0ZVsgNSBdID0geTtcdHRlWyA5IF0gPSBiOyBcdHRlWyAxMyBdID0gMDtcblx0XHR0ZVsgMiBdID0gMDtcdHRlWyA2IF0gPSAwO1x0dGVbIDEwIF0gPSBjOyBcdHRlWyAxNCBdID0gZDtcblx0XHR0ZVsgMyBdID0gMDtcdHRlWyA3IF0gPSAwO1x0dGVbIDExIF0gPSAtIDE7XHR0ZVsgMTUgXSA9IDA7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bWFrZU9ydGhvZ3JhcGhpYyggbGVmdCwgcmlnaHQsIHRvcCwgYm90dG9tLCBuZWFyLCBmYXIsIGNvb3JkaW5hdGVTeXN0ZW0gPSBXZWJHTENvb3JkaW5hdGVTeXN0ZW0gKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cdFx0Y29uc3QgdyA9IDEuMCAvICggcmlnaHQgLSBsZWZ0ICk7XG5cdFx0Y29uc3QgaCA9IDEuMCAvICggdG9wIC0gYm90dG9tICk7XG5cdFx0Y29uc3QgcCA9IDEuMCAvICggZmFyIC0gbmVhciApO1xuXG5cdFx0Y29uc3QgeCA9ICggcmlnaHQgKyBsZWZ0ICkgKiB3O1xuXHRcdGNvbnN0IHkgPSAoIHRvcCArIGJvdHRvbSApICogaDtcblxuXHRcdGxldCB6LCB6SW52O1xuXG5cdFx0aWYgKCBjb29yZGluYXRlU3lzdGVtID09PSBXZWJHTENvb3JkaW5hdGVTeXN0ZW0gKSB7XG5cblx0XHRcdHogPSAoIGZhciArIG5lYXIgKSAqIHA7XG5cdFx0XHR6SW52ID0gLSAyICogcDtcblxuXHRcdH0gZWxzZSBpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdQVUNvb3JkaW5hdGVTeXN0ZW0gKSB7XG5cblx0XHRcdHogPSBuZWFyICogcDtcblx0XHRcdHpJbnYgPSAtIDEgKiBwO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuTWF0cml4NC5tYWtlT3J0aG9ncmFwaGljKCk6IEludmFsaWQgY29vcmRpbmF0ZSBzeXN0ZW06ICcgKyBjb29yZGluYXRlU3lzdGVtICk7XG5cblx0XHR9XG5cblx0XHR0ZVsgMCBdID0gMiAqIHc7XHR0ZVsgNCBdID0gMDtcdFx0dGVbIDggXSA9IDA7IFx0XHR0ZVsgMTIgXSA9IC0geDtcblx0XHR0ZVsgMSBdID0gMDsgXHRcdHRlWyA1IF0gPSAyICogaDtcdHRlWyA5IF0gPSAwOyBcdFx0dGVbIDEzIF0gPSAtIHk7XG5cdFx0dGVbIDIgXSA9IDA7IFx0XHR0ZVsgNiBdID0gMDtcdFx0dGVbIDEwIF0gPSB6SW52O1x0dGVbIDE0IF0gPSAtIHo7XG5cdFx0dGVbIDMgXSA9IDA7IFx0XHR0ZVsgNyBdID0gMDtcdFx0dGVbIDExIF0gPSAwO1x0XHR0ZVsgMTUgXSA9IDE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXF1YWxzKCBtYXRyaXggKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cdFx0Y29uc3QgbWUgPSBtYXRyaXguZWxlbWVudHM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCAxNjsgaSArKyApIHtcblxuXHRcdFx0aWYgKCB0ZVsgaSBdICE9PSBtZVsgaSBdICkgcmV0dXJuIGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fVxuXG5cdGZyb21BcnJheSggYXJyYXksIG9mZnNldCA9IDAgKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCAxNjsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5lbGVtZW50c1sgaSBdID0gYXJyYXlbIGkgKyBvZmZzZXQgXTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0FycmF5KCBhcnJheSA9IFtdLCBvZmZzZXQgPSAwICkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0YXJyYXlbIG9mZnNldCBdID0gdGVbIDAgXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGVbIDEgXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMiBdID0gdGVbIDIgXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMyBdID0gdGVbIDMgXTtcblxuXHRcdGFycmF5WyBvZmZzZXQgKyA0IF0gPSB0ZVsgNCBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyA1IF0gPSB0ZVsgNSBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyA2IF0gPSB0ZVsgNiBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyA3IF0gPSB0ZVsgNyBdO1xuXG5cdFx0YXJyYXlbIG9mZnNldCArIDggXSA9IHRlWyA4IF07XG5cdFx0YXJyYXlbIG9mZnNldCArIDkgXSA9IHRlWyA5IF07XG5cdFx0YXJyYXlbIG9mZnNldCArIDEwIF0gPSB0ZVsgMTAgXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMTEgXSA9IHRlWyAxMSBdO1xuXG5cdFx0YXJyYXlbIG9mZnNldCArIDEyIF0gPSB0ZVsgMTIgXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMTMgXSA9IHRlWyAxMyBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyAxNCBdID0gdGVbIDE0IF07XG5cdFx0YXJyYXlbIG9mZnNldCArIDE1IF0gPSB0ZVsgMTUgXTtcblxuXHRcdHJldHVybiBhcnJheTtcblxuXHR9XG5cbn1cblxuY29uc3QgX3YxJDUgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfbTEkNCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF96ZXJvID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgMCwgMCApO1xuY29uc3QgX29uZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDEsIDEsIDEgKTtcbmNvbnN0IF94ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3kgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfeiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY29uc3QgX21hdHJpeCQyID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX3F1YXRlcm5pb24kMyA9IC8qQF9fUFVSRV9fKi8gbmV3IFF1YXRlcm5pb24oKTtcblxuY2xhc3MgRXVsZXIge1xuXG5cdGNvbnN0cnVjdG9yKCB4ID0gMCwgeSA9IDAsIHogPSAwLCBvcmRlciA9IEV1bGVyLkRFRkFVTFRfT1JERVIgKSB7XG5cblx0XHR0aGlzLmlzRXVsZXIgPSB0cnVlO1xuXG5cdFx0dGhpcy5feCA9IHg7XG5cdFx0dGhpcy5feSA9IHk7XG5cdFx0dGhpcy5feiA9IHo7XG5cdFx0dGhpcy5fb3JkZXIgPSBvcmRlcjtcblxuXHR9XG5cblx0Z2V0IHgoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5feDtcblxuXHR9XG5cblx0c2V0IHgoIHZhbHVlICkge1xuXG5cdFx0dGhpcy5feCA9IHZhbHVlO1xuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHR9XG5cblx0Z2V0IHkoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5feTtcblxuXHR9XG5cblx0c2V0IHkoIHZhbHVlICkge1xuXG5cdFx0dGhpcy5feSA9IHZhbHVlO1xuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHR9XG5cblx0Z2V0IHooKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fejtcblxuXHR9XG5cblx0c2V0IHooIHZhbHVlICkge1xuXG5cdFx0dGhpcy5feiA9IHZhbHVlO1xuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHR9XG5cblx0Z2V0IG9yZGVyKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX29yZGVyO1xuXG5cdH1cblxuXHRzZXQgb3JkZXIoIHZhbHVlICkge1xuXG5cdFx0dGhpcy5fb3JkZXIgPSB2YWx1ZTtcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0fVxuXG5cdHNldCggeCwgeSwgeiwgb3JkZXIgPSB0aGlzLl9vcmRlciApIHtcblxuXHRcdHRoaXMuX3ggPSB4O1xuXHRcdHRoaXMuX3kgPSB5O1xuXHRcdHRoaXMuX3ogPSB6O1xuXHRcdHRoaXMuX29yZGVyID0gb3JkZXI7XG5cblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMuX3gsIHRoaXMuX3ksIHRoaXMuX3osIHRoaXMuX29yZGVyICk7XG5cblx0fVxuXG5cdGNvcHkoIGV1bGVyICkge1xuXG5cdFx0dGhpcy5feCA9IGV1bGVyLl94O1xuXHRcdHRoaXMuX3kgPSBldWxlci5feTtcblx0XHR0aGlzLl96ID0gZXVsZXIuX3o7XG5cdFx0dGhpcy5fb3JkZXIgPSBldWxlci5fb3JkZXI7XG5cblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbVJvdGF0aW9uTWF0cml4KCBtLCBvcmRlciA9IHRoaXMuX29yZGVyLCB1cGRhdGUgPSB0cnVlICkge1xuXG5cdFx0Ly8gYXNzdW1lcyB0aGUgdXBwZXIgM3gzIG9mIG0gaXMgYSBwdXJlIHJvdGF0aW9uIG1hdHJpeCAoaS5lLCB1bnNjYWxlZClcblxuXHRcdGNvbnN0IHRlID0gbS5lbGVtZW50cztcblx0XHRjb25zdCBtMTEgPSB0ZVsgMCBdLCBtMTIgPSB0ZVsgNCBdLCBtMTMgPSB0ZVsgOCBdO1xuXHRcdGNvbnN0IG0yMSA9IHRlWyAxIF0sIG0yMiA9IHRlWyA1IF0sIG0yMyA9IHRlWyA5IF07XG5cdFx0Y29uc3QgbTMxID0gdGVbIDIgXSwgbTMyID0gdGVbIDYgXSwgbTMzID0gdGVbIDEwIF07XG5cblx0XHRzd2l0Y2ggKCBvcmRlciApIHtcblxuXHRcdFx0Y2FzZSAnWFlaJzpcblxuXHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hc2luKCBjbGFtcCggbTEzLCAtIDEsIDEgKSApO1xuXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIG0xMyApIDwgMC45OTk5OTk5ICkge1xuXG5cdFx0XHRcdFx0dGhpcy5feCA9IE1hdGguYXRhbjIoIC0gbTIzLCBtMzMgKTtcblx0XHRcdFx0XHR0aGlzLl96ID0gTWF0aC5hdGFuMiggLSBtMTIsIG0xMSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHR0aGlzLl94ID0gTWF0aC5hdGFuMiggbTMyLCBtMjIgKTtcblx0XHRcdFx0XHR0aGlzLl96ID0gMDtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1lYWic6XG5cblx0XHRcdFx0dGhpcy5feCA9IE1hdGguYXNpbiggLSBjbGFtcCggbTIzLCAtIDEsIDEgKSApO1xuXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIG0yMyApIDwgMC45OTk5OTk5ICkge1xuXG5cdFx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXRhbjIoIG0xMywgbTMzICk7XG5cdFx0XHRcdFx0dGhpcy5feiA9IE1hdGguYXRhbjIoIG0yMSwgbTIyICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHRoaXMuX3kgPSBNYXRoLmF0YW4yKCAtIG0zMSwgbTExICk7XG5cdFx0XHRcdFx0dGhpcy5feiA9IDA7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdaWFknOlxuXG5cdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmFzaW4oIGNsYW1wKCBtMzIsIC0gMSwgMSApICk7XG5cblx0XHRcdFx0aWYgKCBNYXRoLmFicyggbTMyICkgPCAwLjk5OTk5OTkgKSB7XG5cblx0XHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hdGFuMiggLSBtMzEsIG0zMyApO1xuXHRcdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmF0YW4yKCAtIG0xMiwgbTIyICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHRoaXMuX3kgPSAwO1xuXHRcdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmF0YW4yKCBtMjEsIG0xMSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnWllYJzpcblxuXHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hc2luKCAtIGNsYW1wKCBtMzEsIC0gMSwgMSApICk7XG5cblx0XHRcdFx0aWYgKCBNYXRoLmFicyggbTMxICkgPCAwLjk5OTk5OTkgKSB7XG5cblx0XHRcdFx0XHR0aGlzLl94ID0gTWF0aC5hdGFuMiggbTMyLCBtMzMgKTtcblx0XHRcdFx0XHR0aGlzLl96ID0gTWF0aC5hdGFuMiggbTIxLCBtMTEgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0dGhpcy5feCA9IDA7XG5cdFx0XHRcdFx0dGhpcy5feiA9IE1hdGguYXRhbjIoIC0gbTEyLCBtMjIgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1laWCc6XG5cblx0XHRcdFx0dGhpcy5feiA9IE1hdGguYXNpbiggY2xhbXAoIG0yMSwgLSAxLCAxICkgKTtcblxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBtMjEgKSA8IDAuOTk5OTk5OSApIHtcblxuXHRcdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmF0YW4yKCAtIG0yMywgbTIyICk7XG5cdFx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXRhbjIoIC0gbTMxLCBtMTEgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0dGhpcy5feCA9IDA7XG5cdFx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXRhbjIoIG0xMywgbTMzICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdYWlknOlxuXG5cdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmFzaW4oIC0gY2xhbXAoIG0xMiwgLSAxLCAxICkgKTtcblxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBtMTIgKSA8IDAuOTk5OTk5OSApIHtcblxuXHRcdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmF0YW4yKCBtMzIsIG0yMiApO1xuXHRcdFx0XHRcdHRoaXMuX3kgPSBNYXRoLmF0YW4yKCBtMTMsIG0xMSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHR0aGlzLl94ID0gTWF0aC5hdGFuMiggLSBtMjMsIG0zMyApO1xuXHRcdFx0XHRcdHRoaXMuX3kgPSAwO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0ZGVmYXVsdDpcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5FdWxlcjogLnNldEZyb21Sb3RhdGlvbk1hdHJpeCgpIGVuY291bnRlcmVkIGFuIHVua25vd24gb3JkZXI6ICcgKyBvcmRlciApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5fb3JkZXIgPSBvcmRlcjtcblxuXHRcdGlmICggdXBkYXRlID09PSB0cnVlICkgdGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21RdWF0ZXJuaW9uKCBxLCBvcmRlciwgdXBkYXRlICkge1xuXG5cdFx0X21hdHJpeCQyLm1ha2VSb3RhdGlvbkZyb21RdWF0ZXJuaW9uKCBxICk7XG5cblx0XHRyZXR1cm4gdGhpcy5zZXRGcm9tUm90YXRpb25NYXRyaXgoIF9tYXRyaXgkMiwgb3JkZXIsIHVwZGF0ZSApO1xuXG5cdH1cblxuXHRzZXRGcm9tVmVjdG9yMyggdiwgb3JkZXIgPSB0aGlzLl9vcmRlciApIHtcblxuXHRcdHJldHVybiB0aGlzLnNldCggdi54LCB2LnksIHYueiwgb3JkZXIgKTtcblxuXHR9XG5cblx0cmVvcmRlciggbmV3T3JkZXIgKSB7XG5cblx0XHQvLyBXQVJOSU5HOiB0aGlzIGRpc2NhcmRzIHJldm9sdXRpb24gaW5mb3JtYXRpb24gLWJob3VzdG9uXG5cblx0XHRfcXVhdGVybmlvbiQzLnNldEZyb21FdWxlciggdGhpcyApO1xuXG5cdFx0cmV0dXJuIHRoaXMuc2V0RnJvbVF1YXRlcm5pb24oIF9xdWF0ZXJuaW9uJDMsIG5ld09yZGVyICk7XG5cblx0fVxuXG5cdGVxdWFscyggZXVsZXIgKSB7XG5cblx0XHRyZXR1cm4gKCBldWxlci5feCA9PT0gdGhpcy5feCApICYmICggZXVsZXIuX3kgPT09IHRoaXMuX3kgKSAmJiAoIGV1bGVyLl96ID09PSB0aGlzLl96ICkgJiYgKCBldWxlci5fb3JkZXIgPT09IHRoaXMuX29yZGVyICk7XG5cblx0fVxuXG5cdGZyb21BcnJheSggYXJyYXkgKSB7XG5cblx0XHR0aGlzLl94ID0gYXJyYXlbIDAgXTtcblx0XHR0aGlzLl95ID0gYXJyYXlbIDEgXTtcblx0XHR0aGlzLl96ID0gYXJyYXlbIDIgXTtcblx0XHRpZiAoIGFycmF5WyAzIF0gIT09IHVuZGVmaW5lZCApIHRoaXMuX29yZGVyID0gYXJyYXlbIDMgXTtcblxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0FycmF5KCBhcnJheSA9IFtdLCBvZmZzZXQgPSAwICkge1xuXG5cdFx0YXJyYXlbIG9mZnNldCBdID0gdGhpcy5feDtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy5feTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMiBdID0gdGhpcy5fejtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMyBdID0gdGhpcy5fb3JkZXI7XG5cblx0XHRyZXR1cm4gYXJyYXk7XG5cblx0fVxuXG5cdF9vbkNoYW5nZSggY2FsbGJhY2sgKSB7XG5cblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrID0gY2FsbGJhY2s7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0X29uQ2hhbmdlQ2FsbGJhY2soKSB7fVxuXG5cdCpbIFN5bWJvbC5pdGVyYXRvciBdKCkge1xuXG5cdFx0eWllbGQgdGhpcy5feDtcblx0XHR5aWVsZCB0aGlzLl95O1xuXHRcdHlpZWxkIHRoaXMuX3o7XG5cdFx0eWllbGQgdGhpcy5fb3JkZXI7XG5cblx0fVxuXG59XG5cbkV1bGVyLkRFRkFVTFRfT1JERVIgPSAnWFlaJztcblxuY2xhc3MgTGF5ZXJzIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHRoaXMubWFzayA9IDEgfCAwO1xuXG5cdH1cblxuXHRzZXQoIGNoYW5uZWwgKSB7XG5cblx0XHR0aGlzLm1hc2sgPSAoIDEgPDwgY2hhbm5lbCB8IDAgKSA+Pj4gMDtcblxuXHR9XG5cblx0ZW5hYmxlKCBjaGFubmVsICkge1xuXG5cdFx0dGhpcy5tYXNrIHw9IDEgPDwgY2hhbm5lbCB8IDA7XG5cblx0fVxuXG5cdGVuYWJsZUFsbCgpIHtcblxuXHRcdHRoaXMubWFzayA9IDB4ZmZmZmZmZmYgfCAwO1xuXG5cdH1cblxuXHR0b2dnbGUoIGNoYW5uZWwgKSB7XG5cblx0XHR0aGlzLm1hc2sgXj0gMSA8PCBjaGFubmVsIHwgMDtcblxuXHR9XG5cblx0ZGlzYWJsZSggY2hhbm5lbCApIHtcblxuXHRcdHRoaXMubWFzayAmPSB+ICggMSA8PCBjaGFubmVsIHwgMCApO1xuXG5cdH1cblxuXHRkaXNhYmxlQWxsKCkge1xuXG5cdFx0dGhpcy5tYXNrID0gMDtcblxuXHR9XG5cblx0dGVzdCggbGF5ZXJzICkge1xuXG5cdFx0cmV0dXJuICggdGhpcy5tYXNrICYgbGF5ZXJzLm1hc2sgKSAhPT0gMDtcblxuXHR9XG5cblx0aXNFbmFibGVkKCBjaGFubmVsICkge1xuXG5cdFx0cmV0dXJuICggdGhpcy5tYXNrICYgKCAxIDw8IGNoYW5uZWwgfCAwICkgKSAhPT0gMDtcblxuXHR9XG5cbn1cblxubGV0IF9vYmplY3QzRElkID0gMDtcblxuY29uc3QgX3YxJDQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfcTEgPSAvKkBfX1BVUkVfXyovIG5ldyBRdWF0ZXJuaW9uKCk7XG5jb25zdCBfbTEkMyA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF90YXJnZXQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNvbnN0IF9wb3NpdGlvbiQzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3NjYWxlJDIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfcXVhdGVybmlvbiQyID0gLypAX19QVVJFX18qLyBuZXcgUXVhdGVybmlvbigpO1xuXG5jb25zdCBfeEF4aXMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAxLCAwLCAwICk7XG5jb25zdCBfeUF4aXMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAwLCAxLCAwICk7XG5jb25zdCBfekF4aXMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAwLCAwLCAxICk7XG5cbmNvbnN0IF9hZGRlZEV2ZW50ID0geyB0eXBlOiAnYWRkZWQnIH07XG5jb25zdCBfcmVtb3ZlZEV2ZW50ID0geyB0eXBlOiAncmVtb3ZlZCcgfTtcblxuY29uc3QgX2NoaWxkYWRkZWRFdmVudCA9IHsgdHlwZTogJ2NoaWxkYWRkZWQnLCBjaGlsZDogbnVsbCB9O1xuY29uc3QgX2NoaWxkcmVtb3ZlZEV2ZW50ID0geyB0eXBlOiAnY2hpbGRyZW1vdmVkJywgY2hpbGQ6IG51bGwgfTtcblxuY2xhc3MgT2JqZWN0M0QgZXh0ZW5kcyBFdmVudERpc3BhdGNoZXIge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNPYmplY3QzRCA9IHRydWU7XG5cblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoIHRoaXMsICdpZCcsIHsgdmFsdWU6IF9vYmplY3QzRElkICsrIH0gKTtcblxuXHRcdHRoaXMudXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0dGhpcy5uYW1lID0gJyc7XG5cdFx0dGhpcy50eXBlID0gJ09iamVjdDNEJztcblxuXHRcdHRoaXMucGFyZW50ID0gbnVsbDtcblx0XHR0aGlzLmNoaWxkcmVuID0gW107XG5cblx0XHR0aGlzLnVwID0gT2JqZWN0M0QuREVGQVVMVF9VUC5jbG9uZSgpO1xuXG5cdFx0Y29uc3QgcG9zaXRpb24gPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IHJvdGF0aW9uID0gbmV3IEV1bGVyKCk7XG5cdFx0Y29uc3QgcXVhdGVybmlvbiA9IG5ldyBRdWF0ZXJuaW9uKCk7XG5cdFx0Y29uc3Qgc2NhbGUgPSBuZXcgVmVjdG9yMyggMSwgMSwgMSApO1xuXG5cdFx0ZnVuY3Rpb24gb25Sb3RhdGlvbkNoYW5nZSgpIHtcblxuXHRcdFx0cXVhdGVybmlvbi5zZXRGcm9tRXVsZXIoIHJvdGF0aW9uLCBmYWxzZSApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gb25RdWF0ZXJuaW9uQ2hhbmdlKCkge1xuXG5cdFx0XHRyb3RhdGlvbi5zZXRGcm9tUXVhdGVybmlvbiggcXVhdGVybmlvbiwgdW5kZWZpbmVkLCBmYWxzZSApO1xuXG5cdFx0fVxuXG5cdFx0cm90YXRpb24uX29uQ2hhbmdlKCBvblJvdGF0aW9uQ2hhbmdlICk7XG5cdFx0cXVhdGVybmlvbi5fb25DaGFuZ2UoIG9uUXVhdGVybmlvbkNoYW5nZSApO1xuXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnRpZXMoIHRoaXMsIHtcblx0XHRcdHBvc2l0aW9uOiB7XG5cdFx0XHRcdGNvbmZpZ3VyYWJsZTogdHJ1ZSxcblx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcblx0XHRcdFx0dmFsdWU6IHBvc2l0aW9uXG5cdFx0XHR9LFxuXHRcdFx0cm90YXRpb246IHtcblx0XHRcdFx0Y29uZmlndXJhYmxlOiB0cnVlLFxuXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuXHRcdFx0XHR2YWx1ZTogcm90YXRpb25cblx0XHRcdH0sXG5cdFx0XHRxdWF0ZXJuaW9uOiB7XG5cdFx0XHRcdGNvbmZpZ3VyYWJsZTogdHJ1ZSxcblx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcblx0XHRcdFx0dmFsdWU6IHF1YXRlcm5pb25cblx0XHRcdH0sXG5cdFx0XHRzY2FsZToge1xuXHRcdFx0XHRjb25maWd1cmFibGU6IHRydWUsXG5cdFx0XHRcdGVudW1lcmFibGU6IHRydWUsXG5cdFx0XHRcdHZhbHVlOiBzY2FsZVxuXHRcdFx0fSxcblx0XHRcdG1vZGVsVmlld01hdHJpeDoge1xuXHRcdFx0XHR2YWx1ZTogbmV3IE1hdHJpeDQoKVxuXHRcdFx0fSxcblx0XHRcdG5vcm1hbE1hdHJpeDoge1xuXHRcdFx0XHR2YWx1ZTogbmV3IE1hdHJpeDMoKVxuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHRoaXMubWF0cml4ID0gbmV3IE1hdHJpeDQoKTtcblx0XHR0aGlzLm1hdHJpeFdvcmxkID0gbmV3IE1hdHJpeDQoKTtcblxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IE9iamVjdDNELkRFRkFVTFRfTUFUUklYX0FVVE9fVVBEQVRFO1xuXG5cdFx0dGhpcy5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPSBPYmplY3QzRC5ERUZBVUxUX01BVFJJWF9XT1JMRF9BVVRPX1VQREFURTsgLy8gY2hlY2tlZCBieSB0aGUgcmVuZGVyZXJcblx0XHR0aGlzLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSBmYWxzZTtcblxuXHRcdHRoaXMubGF5ZXJzID0gbmV3IExheWVycygpO1xuXHRcdHRoaXMudmlzaWJsZSA9IHRydWU7XG5cblx0XHR0aGlzLmNhc3RTaGFkb3cgPSBmYWxzZTtcblx0XHR0aGlzLnJlY2VpdmVTaGFkb3cgPSBmYWxzZTtcblxuXHRcdHRoaXMuZnJ1c3R1bUN1bGxlZCA9IHRydWU7XG5cdFx0dGhpcy5yZW5kZXJPcmRlciA9IDA7XG5cblx0XHR0aGlzLmFuaW1hdGlvbnMgPSBbXTtcblxuXHRcdHRoaXMudXNlckRhdGEgPSB7fTtcblxuXHR9XG5cblx0b25CZWZvcmVTaGFkb3coIC8qIHJlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgZ3JvdXAgKi8gKSB7fVxuXG5cdG9uQWZ0ZXJTaGFkb3coIC8qIHJlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgZ3JvdXAgKi8gKSB7fVxuXG5cdG9uQmVmb3JlUmVuZGVyKCAvKiByZW5kZXJlciwgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCAqLyApIHt9XG5cblx0b25BZnRlclJlbmRlciggLyogcmVuZGVyZXIsIHNjZW5lLCBjYW1lcmEsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXAgKi8gKSB7fVxuXG5cdGFwcGx5TWF0cml4NCggbWF0cml4ICkge1xuXG5cdFx0aWYgKCB0aGlzLm1hdHJpeEF1dG9VcGRhdGUgKSB0aGlzLnVwZGF0ZU1hdHJpeCgpO1xuXG5cdFx0dGhpcy5tYXRyaXgucHJlbXVsdGlwbHkoIG1hdHJpeCApO1xuXG5cdFx0dGhpcy5tYXRyaXguZGVjb21wb3NlKCB0aGlzLnBvc2l0aW9uLCB0aGlzLnF1YXRlcm5pb24sIHRoaXMuc2NhbGUgKTtcblxuXHR9XG5cblx0YXBwbHlRdWF0ZXJuaW9uKCBxICkge1xuXG5cdFx0dGhpcy5xdWF0ZXJuaW9uLnByZW11bHRpcGx5KCBxICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0Um90YXRpb25Gcm9tQXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApIHtcblxuXHRcdC8vIGFzc3VtZXMgYXhpcyBpcyBub3JtYWxpemVkXG5cblx0XHR0aGlzLnF1YXRlcm5pb24uc2V0RnJvbUF4aXNBbmdsZSggYXhpcywgYW5nbGUgKTtcblxuXHR9XG5cblx0c2V0Um90YXRpb25Gcm9tRXVsZXIoIGV1bGVyICkge1xuXG5cdFx0dGhpcy5xdWF0ZXJuaW9uLnNldEZyb21FdWxlciggZXVsZXIsIHRydWUgKTtcblxuXHR9XG5cblx0c2V0Um90YXRpb25Gcm9tTWF0cml4KCBtICkge1xuXG5cdFx0Ly8gYXNzdW1lcyB0aGUgdXBwZXIgM3gzIG9mIG0gaXMgYSBwdXJlIHJvdGF0aW9uIG1hdHJpeCAoaS5lLCB1bnNjYWxlZClcblxuXHRcdHRoaXMucXVhdGVybmlvbi5zZXRGcm9tUm90YXRpb25NYXRyaXgoIG0gKTtcblxuXHR9XG5cblx0c2V0Um90YXRpb25Gcm9tUXVhdGVybmlvbiggcSApIHtcblxuXHRcdC8vIGFzc3VtZXMgcSBpcyBub3JtYWxpemVkXG5cblx0XHR0aGlzLnF1YXRlcm5pb24uY29weSggcSApO1xuXG5cdH1cblxuXHRyb3RhdGVPbkF4aXMoIGF4aXMsIGFuZ2xlICkge1xuXG5cdFx0Ly8gcm90YXRlIG9iamVjdCBvbiBheGlzIGluIG9iamVjdCBzcGFjZVxuXHRcdC8vIGF4aXMgaXMgYXNzdW1lZCB0byBiZSBub3JtYWxpemVkXG5cblx0XHRfcTEuc2V0RnJvbUF4aXNBbmdsZSggYXhpcywgYW5nbGUgKTtcblxuXHRcdHRoaXMucXVhdGVybmlvbi5tdWx0aXBseSggX3ExICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cm90YXRlT25Xb3JsZEF4aXMoIGF4aXMsIGFuZ2xlICkge1xuXG5cdFx0Ly8gcm90YXRlIG9iamVjdCBvbiBheGlzIGluIHdvcmxkIHNwYWNlXG5cdFx0Ly8gYXhpcyBpcyBhc3N1bWVkIHRvIGJlIG5vcm1hbGl6ZWRcblx0XHQvLyBtZXRob2QgYXNzdW1lcyBubyByb3RhdGVkIHBhcmVudFxuXG5cdFx0X3ExLnNldEZyb21BeGlzQW5nbGUoIGF4aXMsIGFuZ2xlICk7XG5cblx0XHR0aGlzLnF1YXRlcm5pb24ucHJlbXVsdGlwbHkoIF9xMSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJvdGF0ZVgoIGFuZ2xlICkge1xuXG5cdFx0cmV0dXJuIHRoaXMucm90YXRlT25BeGlzKCBfeEF4aXMsIGFuZ2xlICk7XG5cblx0fVxuXG5cdHJvdGF0ZVkoIGFuZ2xlICkge1xuXG5cdFx0cmV0dXJuIHRoaXMucm90YXRlT25BeGlzKCBfeUF4aXMsIGFuZ2xlICk7XG5cblx0fVxuXG5cdHJvdGF0ZVooIGFuZ2xlICkge1xuXG5cdFx0cmV0dXJuIHRoaXMucm90YXRlT25BeGlzKCBfekF4aXMsIGFuZ2xlICk7XG5cblx0fVxuXG5cdHRyYW5zbGF0ZU9uQXhpcyggYXhpcywgZGlzdGFuY2UgKSB7XG5cblx0XHQvLyB0cmFuc2xhdGUgb2JqZWN0IGJ5IGRpc3RhbmNlIGFsb25nIGF4aXMgaW4gb2JqZWN0IHNwYWNlXG5cdFx0Ly8gYXhpcyBpcyBhc3N1bWVkIHRvIGJlIG5vcm1hbGl6ZWRcblxuXHRcdF92MSQ0LmNvcHkoIGF4aXMgKS5hcHBseVF1YXRlcm5pb24oIHRoaXMucXVhdGVybmlvbiApO1xuXG5cdFx0dGhpcy5wb3NpdGlvbi5hZGQoIF92MSQ0Lm11bHRpcGx5U2NhbGFyKCBkaXN0YW5jZSApICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJhbnNsYXRlWCggZGlzdGFuY2UgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy50cmFuc2xhdGVPbkF4aXMoIF94QXhpcywgZGlzdGFuY2UgKTtcblxuXHR9XG5cblx0dHJhbnNsYXRlWSggZGlzdGFuY2UgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy50cmFuc2xhdGVPbkF4aXMoIF95QXhpcywgZGlzdGFuY2UgKTtcblxuXHR9XG5cblx0dHJhbnNsYXRlWiggZGlzdGFuY2UgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy50cmFuc2xhdGVPbkF4aXMoIF96QXhpcywgZGlzdGFuY2UgKTtcblxuXHR9XG5cblx0bG9jYWxUb1dvcmxkKCB2ZWN0b3IgKSB7XG5cblx0XHR0aGlzLnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xuXG5cdFx0cmV0dXJuIHZlY3Rvci5hcHBseU1hdHJpeDQoIHRoaXMubWF0cml4V29ybGQgKTtcblxuXHR9XG5cblx0d29ybGRUb0xvY2FsKCB2ZWN0b3IgKSB7XG5cblx0XHR0aGlzLnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xuXG5cdFx0cmV0dXJuIHZlY3Rvci5hcHBseU1hdHJpeDQoIF9tMSQzLmNvcHkoIHRoaXMubWF0cml4V29ybGQgKS5pbnZlcnQoKSApO1xuXG5cdH1cblxuXHRsb29rQXQoIHgsIHksIHogKSB7XG5cblx0XHQvLyBUaGlzIG1ldGhvZCBkb2VzIG5vdCBzdXBwb3J0IG9iamVjdHMgaGF2aW5nIG5vbi11bmlmb3JtbHktc2NhbGVkIHBhcmVudChzKVxuXG5cdFx0aWYgKCB4LmlzVmVjdG9yMyApIHtcblxuXHRcdFx0X3RhcmdldC5jb3B5KCB4ICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRfdGFyZ2V0LnNldCggeCwgeSwgeiApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgcGFyZW50ID0gdGhpcy5wYXJlbnQ7XG5cblx0XHR0aGlzLnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xuXG5cdFx0X3Bvc2l0aW9uJDMuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1hdHJpeFdvcmxkICk7XG5cblx0XHRpZiAoIHRoaXMuaXNDYW1lcmEgfHwgdGhpcy5pc0xpZ2h0ICkge1xuXG5cdFx0XHRfbTEkMy5sb29rQXQoIF9wb3NpdGlvbiQzLCBfdGFyZ2V0LCB0aGlzLnVwICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRfbTEkMy5sb29rQXQoIF90YXJnZXQsIF9wb3NpdGlvbiQzLCB0aGlzLnVwICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLnF1YXRlcm5pb24uc2V0RnJvbVJvdGF0aW9uTWF0cml4KCBfbTEkMyApO1xuXG5cdFx0aWYgKCBwYXJlbnQgKSB7XG5cblx0XHRcdF9tMSQzLmV4dHJhY3RSb3RhdGlvbiggcGFyZW50Lm1hdHJpeFdvcmxkICk7XG5cdFx0XHRfcTEuc2V0RnJvbVJvdGF0aW9uTWF0cml4KCBfbTEkMyApO1xuXHRcdFx0dGhpcy5xdWF0ZXJuaW9uLnByZW11bHRpcGx5KCBfcTEuaW52ZXJ0KCkgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0YWRkKCBvYmplY3QgKSB7XG5cblx0XHRpZiAoIGFyZ3VtZW50cy5sZW5ndGggPiAxICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBhcmd1bWVudHMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdHRoaXMuYWRkKCBhcmd1bWVudHNbIGkgXSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBvYmplY3QgPT09IHRoaXMgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5PYmplY3QzRC5hZGQ6IG9iamVjdCBjYW5cXCd0IGJlIGFkZGVkIGFzIGEgY2hpbGQgb2YgaXRzZWxmLicsIG9iamVjdCApO1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHR9XG5cblx0XHRpZiAoIG9iamVjdCAmJiBvYmplY3QuaXNPYmplY3QzRCApIHtcblxuXHRcdFx0b2JqZWN0LnJlbW92ZUZyb21QYXJlbnQoKTtcblx0XHRcdG9iamVjdC5wYXJlbnQgPSB0aGlzO1xuXHRcdFx0dGhpcy5jaGlsZHJlbi5wdXNoKCBvYmplY3QgKTtcblxuXHRcdFx0b2JqZWN0LmRpc3BhdGNoRXZlbnQoIF9hZGRlZEV2ZW50ICk7XG5cblx0XHRcdF9jaGlsZGFkZGVkRXZlbnQuY2hpbGQgPSBvYmplY3Q7XG5cdFx0XHR0aGlzLmRpc3BhdGNoRXZlbnQoIF9jaGlsZGFkZGVkRXZlbnQgKTtcblx0XHRcdF9jaGlsZGFkZGVkRXZlbnQuY2hpbGQgPSBudWxsO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLk9iamVjdDNELmFkZDogb2JqZWN0IG5vdCBhbiBpbnN0YW5jZSBvZiBUSFJFRS5PYmplY3QzRC4nLCBvYmplY3QgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyZW1vdmUoIG9iamVjdCApIHtcblxuXHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCA+IDEgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0dGhpcy5yZW1vdmUoIGFyZ3VtZW50c1sgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHR9XG5cblx0XHRjb25zdCBpbmRleCA9IHRoaXMuY2hpbGRyZW4uaW5kZXhPZiggb2JqZWN0ICk7XG5cblx0XHRpZiAoIGluZGV4ICE9PSAtIDEgKSB7XG5cblx0XHRcdG9iamVjdC5wYXJlbnQgPSBudWxsO1xuXHRcdFx0dGhpcy5jaGlsZHJlbi5zcGxpY2UoIGluZGV4LCAxICk7XG5cblx0XHRcdG9iamVjdC5kaXNwYXRjaEV2ZW50KCBfcmVtb3ZlZEV2ZW50ICk7XG5cblx0XHRcdF9jaGlsZHJlbW92ZWRFdmVudC5jaGlsZCA9IG9iamVjdDtcblx0XHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggX2NoaWxkcmVtb3ZlZEV2ZW50ICk7XG5cdFx0XHRfY2hpbGRyZW1vdmVkRXZlbnQuY2hpbGQgPSBudWxsO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJlbW92ZUZyb21QYXJlbnQoKSB7XG5cblx0XHRjb25zdCBwYXJlbnQgPSB0aGlzLnBhcmVudDtcblxuXHRcdGlmICggcGFyZW50ICE9PSBudWxsICkge1xuXG5cdFx0XHRwYXJlbnQucmVtb3ZlKCB0aGlzICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xlYXIoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5yZW1vdmUoIC4uLiB0aGlzLmNoaWxkcmVuICk7XG5cblx0fVxuXG5cdGF0dGFjaCggb2JqZWN0ICkge1xuXG5cdFx0Ly8gYWRkcyBvYmplY3QgYXMgYSBjaGlsZCBvZiB0aGlzLCB3aGlsZSBtYWludGFpbmluZyB0aGUgb2JqZWN0J3Mgd29ybGQgdHJhbnNmb3JtXG5cblx0XHQvLyBOb3RlOiBUaGlzIG1ldGhvZCBkb2VzIG5vdCBzdXBwb3J0IHNjZW5lIGdyYXBocyBoYXZpbmcgbm9uLXVuaWZvcm1seS1zY2FsZWQgbm9kZXMocylcblxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XG5cblx0XHRfbTEkMy5jb3B5KCB0aGlzLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cblx0XHRpZiAoIG9iamVjdC5wYXJlbnQgIT09IG51bGwgKSB7XG5cblx0XHRcdG9iamVjdC5wYXJlbnQudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XG5cblx0XHRcdF9tMSQzLm11bHRpcGx5KCBvYmplY3QucGFyZW50Lm1hdHJpeFdvcmxkICk7XG5cblx0XHR9XG5cblx0XHRvYmplY3QuYXBwbHlNYXRyaXg0KCBfbTEkMyApO1xuXG5cdFx0b2JqZWN0LnJlbW92ZUZyb21QYXJlbnQoKTtcblx0XHRvYmplY3QucGFyZW50ID0gdGhpcztcblx0XHR0aGlzLmNoaWxkcmVuLnB1c2goIG9iamVjdCApO1xuXG5cdFx0b2JqZWN0LnVwZGF0ZVdvcmxkTWF0cml4KCBmYWxzZSwgdHJ1ZSApO1xuXG5cdFx0b2JqZWN0LmRpc3BhdGNoRXZlbnQoIF9hZGRlZEV2ZW50ICk7XG5cblx0XHRfY2hpbGRhZGRlZEV2ZW50LmNoaWxkID0gb2JqZWN0O1xuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggX2NoaWxkYWRkZWRFdmVudCApO1xuXHRcdF9jaGlsZGFkZGVkRXZlbnQuY2hpbGQgPSBudWxsO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldE9iamVjdEJ5SWQoIGlkICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZ2V0T2JqZWN0QnlQcm9wZXJ0eSggJ2lkJywgaWQgKTtcblxuXHR9XG5cblx0Z2V0T2JqZWN0QnlOYW1lKCBuYW1lICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZ2V0T2JqZWN0QnlQcm9wZXJ0eSggJ25hbWUnLCBuYW1lICk7XG5cblx0fVxuXG5cdGdldE9iamVjdEJ5UHJvcGVydHkoIG5hbWUsIHZhbHVlICkge1xuXG5cdFx0aWYgKCB0aGlzWyBuYW1lIF0gPT09IHZhbHVlICkgcmV0dXJuIHRoaXM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGNoaWxkID0gdGhpcy5jaGlsZHJlblsgaSBdO1xuXHRcdFx0Y29uc3Qgb2JqZWN0ID0gY2hpbGQuZ2V0T2JqZWN0QnlQcm9wZXJ0eSggbmFtZSwgdmFsdWUgKTtcblxuXHRcdFx0aWYgKCBvYmplY3QgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRyZXR1cm4gb2JqZWN0O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdW5kZWZpbmVkO1xuXG5cdH1cblxuXHRnZXRPYmplY3RzQnlQcm9wZXJ0eSggbmFtZSwgdmFsdWUsIHJlc3VsdCA9IFtdICkge1xuXG5cdFx0aWYgKCB0aGlzWyBuYW1lIF0gPT09IHZhbHVlICkgcmVzdWx0LnB1c2goIHRoaXMgKTtcblxuXHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNoaWxkcmVuWyBpIF0uZ2V0T2JqZWN0c0J5UHJvcGVydHkoIG5hbWUsIHZhbHVlLCByZXN1bHQgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiByZXN1bHQ7XG5cblx0fVxuXG5cdGdldFdvcmxkUG9zaXRpb24oIHRhcmdldCApIHtcblxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LnNldEZyb21NYXRyaXhQb3NpdGlvbiggdGhpcy5tYXRyaXhXb3JsZCApO1xuXG5cdH1cblxuXHRnZXRXb3JsZFF1YXRlcm5pb24oIHRhcmdldCApIHtcblxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XG5cblx0XHR0aGlzLm1hdHJpeFdvcmxkLmRlY29tcG9zZSggX3Bvc2l0aW9uJDMsIHRhcmdldCwgX3NjYWxlJDIgKTtcblxuXHRcdHJldHVybiB0YXJnZXQ7XG5cblx0fVxuXG5cdGdldFdvcmxkU2NhbGUoIHRhcmdldCApIHtcblxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XG5cblx0XHR0aGlzLm1hdHJpeFdvcmxkLmRlY29tcG9zZSggX3Bvc2l0aW9uJDMsIF9xdWF0ZXJuaW9uJDIsIHRhcmdldCApO1xuXG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0Z2V0V29ybGREaXJlY3Rpb24oIHRhcmdldCApIHtcblxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XG5cblx0XHRjb25zdCBlID0gdGhpcy5tYXRyaXhXb3JsZC5lbGVtZW50cztcblxuXHRcdHJldHVybiB0YXJnZXQuc2V0KCBlWyA4IF0sIGVbIDkgXSwgZVsgMTAgXSApLm5vcm1hbGl6ZSgpO1xuXG5cdH1cblxuXHRyYXljYXN0KCAvKiByYXljYXN0ZXIsIGludGVyc2VjdHMgKi8gKSB7fVxuXG5cdHRyYXZlcnNlKCBjYWxsYmFjayApIHtcblxuXHRcdGNhbGxiYWNrKCB0aGlzICk7XG5cblx0XHRjb25zdCBjaGlsZHJlbiA9IHRoaXMuY2hpbGRyZW47XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjaGlsZHJlblsgaSBdLnRyYXZlcnNlKCBjYWxsYmFjayApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHR0cmF2ZXJzZVZpc2libGUoIGNhbGxiYWNrICkge1xuXG5cdFx0aWYgKCB0aGlzLnZpc2libGUgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0Y2FsbGJhY2soIHRoaXMgKTtcblxuXHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNoaWxkcmVuWyBpIF0udHJhdmVyc2VWaXNpYmxlKCBjYWxsYmFjayApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHR0cmF2ZXJzZUFuY2VzdG9ycyggY2FsbGJhY2sgKSB7XG5cblx0XHRjb25zdCBwYXJlbnQgPSB0aGlzLnBhcmVudDtcblxuXHRcdGlmICggcGFyZW50ICE9PSBudWxsICkge1xuXG5cdFx0XHRjYWxsYmFjayggcGFyZW50ICk7XG5cblx0XHRcdHBhcmVudC50cmF2ZXJzZUFuY2VzdG9ycyggY2FsbGJhY2sgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0dXBkYXRlTWF0cml4KCkge1xuXG5cdFx0dGhpcy5tYXRyaXguY29tcG9zZSggdGhpcy5wb3NpdGlvbiwgdGhpcy5xdWF0ZXJuaW9uLCB0aGlzLnNjYWxlICk7XG5cblx0XHR0aGlzLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XG5cblx0XHRpZiAoIHRoaXMubWF0cml4QXV0b1VwZGF0ZSApIHRoaXMudXBkYXRlTWF0cml4KCk7XG5cblx0XHRpZiAoIHRoaXMubWF0cml4V29ybGROZWVkc1VwZGF0ZSB8fCBmb3JjZSApIHtcblxuXHRcdFx0aWYgKCB0aGlzLm1hdHJpeFdvcmxkQXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRpZiAoIHRoaXMucGFyZW50ID09PSBudWxsICkge1xuXG5cdFx0XHRcdFx0dGhpcy5tYXRyaXhXb3JsZC5jb3B5KCB0aGlzLm1hdHJpeCApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHR0aGlzLm1hdHJpeFdvcmxkLm11bHRpcGx5TWF0cmljZXMoIHRoaXMucGFyZW50Lm1hdHJpeFdvcmxkLCB0aGlzLm1hdHJpeCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSBmYWxzZTtcblxuXHRcdFx0Zm9yY2UgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0Ly8gbWFrZSBzdXJlIGRlc2NlbmRhbnRzIGFyZSB1cGRhdGVkIGlmIHJlcXVpcmVkXG5cblx0XHRjb25zdCBjaGlsZHJlbiA9IHRoaXMuY2hpbGRyZW47XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBjaGlsZCA9IGNoaWxkcmVuWyBpIF07XG5cblx0XHRcdGNoaWxkLnVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHR1cGRhdGVXb3JsZE1hdHJpeCggdXBkYXRlUGFyZW50cywgdXBkYXRlQ2hpbGRyZW4gKSB7XG5cblx0XHRjb25zdCBwYXJlbnQgPSB0aGlzLnBhcmVudDtcblxuXHRcdGlmICggdXBkYXRlUGFyZW50cyA9PT0gdHJ1ZSAmJiBwYXJlbnQgIT09IG51bGwgKSB7XG5cblx0XHRcdHBhcmVudC51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5tYXRyaXhBdXRvVXBkYXRlICkgdGhpcy51cGRhdGVNYXRyaXgoKTtcblxuXHRcdGlmICggdGhpcy5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPT09IHRydWUgKSB7XG5cblx0XHRcdGlmICggdGhpcy5wYXJlbnQgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0dGhpcy5tYXRyaXhXb3JsZC5jb3B5KCB0aGlzLm1hdHJpeCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHRoaXMubWF0cml4V29ybGQubXVsdGlwbHlNYXRyaWNlcyggdGhpcy5wYXJlbnQubWF0cml4V29ybGQsIHRoaXMubWF0cml4ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIG1ha2Ugc3VyZSBkZXNjZW5kYW50cyBhcmUgdXBkYXRlZFxuXG5cdFx0aWYgKCB1cGRhdGVDaGlsZHJlbiA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0Y29uc3QgY2hpbGRyZW4gPSB0aGlzLmNoaWxkcmVuO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGNoaWxkID0gY2hpbGRyZW5bIGkgXTtcblxuXHRcdFx0XHRjaGlsZC51cGRhdGVXb3JsZE1hdHJpeCggZmFsc2UsIHRydWUgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHR0b0pTT04oIG1ldGEgKSB7XG5cblx0XHQvLyBtZXRhIGlzIGEgc3RyaW5nIHdoZW4gY2FsbGVkIGZyb20gSlNPTi5zdHJpbmdpZnlcblx0XHRjb25zdCBpc1Jvb3RPYmplY3QgPSAoIG1ldGEgPT09IHVuZGVmaW5lZCB8fCB0eXBlb2YgbWV0YSA9PT0gJ3N0cmluZycgKTtcblxuXHRcdGNvbnN0IG91dHB1dCA9IHt9O1xuXG5cdFx0Ly8gbWV0YSBpcyBhIGhhc2ggdXNlZCB0byBjb2xsZWN0IGdlb21ldHJpZXMsIG1hdGVyaWFscy5cblx0XHQvLyBub3QgcHJvdmlkaW5nIGl0IGltcGxpZXMgdGhhdCB0aGlzIGlzIHRoZSByb290IG9iamVjdFxuXHRcdC8vIGJlaW5nIHNlcmlhbGl6ZWQuXG5cdFx0aWYgKCBpc1Jvb3RPYmplY3QgKSB7XG5cblx0XHRcdC8vIGluaXRpYWxpemUgbWV0YSBvYmpcblx0XHRcdG1ldGEgPSB7XG5cdFx0XHRcdGdlb21ldHJpZXM6IHt9LFxuXHRcdFx0XHRtYXRlcmlhbHM6IHt9LFxuXHRcdFx0XHR0ZXh0dXJlczoge30sXG5cdFx0XHRcdGltYWdlczoge30sXG5cdFx0XHRcdHNoYXBlczoge30sXG5cdFx0XHRcdHNrZWxldG9uczoge30sXG5cdFx0XHRcdGFuaW1hdGlvbnM6IHt9LFxuXHRcdFx0XHRub2Rlczoge31cblx0XHRcdH07XG5cblx0XHRcdG91dHB1dC5tZXRhZGF0YSA9IHtcblx0XHRcdFx0dmVyc2lvbjogNC42LFxuXHRcdFx0XHR0eXBlOiAnT2JqZWN0Jyxcblx0XHRcdFx0Z2VuZXJhdG9yOiAnT2JqZWN0M0QudG9KU09OJ1xuXHRcdFx0fTtcblxuXHRcdH1cblxuXHRcdC8vIHN0YW5kYXJkIE9iamVjdDNEIHNlcmlhbGl6YXRpb25cblxuXHRcdGNvbnN0IG9iamVjdCA9IHt9O1xuXG5cdFx0b2JqZWN0LnV1aWQgPSB0aGlzLnV1aWQ7XG5cdFx0b2JqZWN0LnR5cGUgPSB0aGlzLnR5cGU7XG5cblx0XHRpZiAoIHRoaXMubmFtZSAhPT0gJycgKSBvYmplY3QubmFtZSA9IHRoaXMubmFtZTtcblx0XHRpZiAoIHRoaXMuY2FzdFNoYWRvdyA9PT0gdHJ1ZSApIG9iamVjdC5jYXN0U2hhZG93ID0gdHJ1ZTtcblx0XHRpZiAoIHRoaXMucmVjZWl2ZVNoYWRvdyA9PT0gdHJ1ZSApIG9iamVjdC5yZWNlaXZlU2hhZG93ID0gdHJ1ZTtcblx0XHRpZiAoIHRoaXMudmlzaWJsZSA9PT0gZmFsc2UgKSBvYmplY3QudmlzaWJsZSA9IGZhbHNlO1xuXHRcdGlmICggdGhpcy5mcnVzdHVtQ3VsbGVkID09PSBmYWxzZSApIG9iamVjdC5mcnVzdHVtQ3VsbGVkID0gZmFsc2U7XG5cdFx0aWYgKCB0aGlzLnJlbmRlck9yZGVyICE9PSAwICkgb2JqZWN0LnJlbmRlck9yZGVyID0gdGhpcy5yZW5kZXJPcmRlcjtcblx0XHRpZiAoIE9iamVjdC5rZXlzKCB0aGlzLnVzZXJEYXRhICkubGVuZ3RoID4gMCApIG9iamVjdC51c2VyRGF0YSA9IHRoaXMudXNlckRhdGE7XG5cblx0XHRvYmplY3QubGF5ZXJzID0gdGhpcy5sYXllcnMubWFzaztcblx0XHRvYmplY3QubWF0cml4ID0gdGhpcy5tYXRyaXgudG9BcnJheSgpO1xuXHRcdG9iamVjdC51cCA9IHRoaXMudXAudG9BcnJheSgpO1xuXG5cdFx0aWYgKCB0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPT09IGZhbHNlICkgb2JqZWN0Lm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblxuXHRcdC8vIG9iamVjdCBzcGVjaWZpYyBwcm9wZXJ0aWVzXG5cblx0XHRpZiAoIHRoaXMuaXNJbnN0YW5jZWRNZXNoICkge1xuXG5cdFx0XHRvYmplY3QudHlwZSA9ICdJbnN0YW5jZWRNZXNoJztcblx0XHRcdG9iamVjdC5jb3VudCA9IHRoaXMuY291bnQ7XG5cdFx0XHRvYmplY3QuaW5zdGFuY2VNYXRyaXggPSB0aGlzLmluc3RhbmNlTWF0cml4LnRvSlNPTigpO1xuXHRcdFx0aWYgKCB0aGlzLmluc3RhbmNlQ29sb3IgIT09IG51bGwgKSBvYmplY3QuaW5zdGFuY2VDb2xvciA9IHRoaXMuaW5zdGFuY2VDb2xvci50b0pTT04oKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5pc0JhdGNoZWRNZXNoICkge1xuXG5cdFx0XHRvYmplY3QudHlwZSA9ICdCYXRjaGVkTWVzaCc7XG5cdFx0XHRvYmplY3QucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCA9IHRoaXMucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZDtcblx0XHRcdG9iamVjdC5zb3J0T2JqZWN0cyA9IHRoaXMuc29ydE9iamVjdHM7XG5cblx0XHRcdG9iamVjdC5kcmF3UmFuZ2VzID0gdGhpcy5fZHJhd1Jhbmdlcztcblx0XHRcdG9iamVjdC5yZXNlcnZlZFJhbmdlcyA9IHRoaXMuX3Jlc2VydmVkUmFuZ2VzO1xuXG5cdFx0XHRvYmplY3QudmlzaWJpbGl0eSA9IHRoaXMuX3Zpc2liaWxpdHk7XG5cdFx0XHRvYmplY3QuYWN0aXZlID0gdGhpcy5fYWN0aXZlO1xuXHRcdFx0b2JqZWN0LmJvdW5kcyA9IHRoaXMuX2JvdW5kcy5tYXAoIGJvdW5kID0+ICgge1xuXHRcdFx0XHRib3hJbml0aWFsaXplZDogYm91bmQuYm94SW5pdGlhbGl6ZWQsXG5cdFx0XHRcdGJveE1pbjogYm91bmQuYm94Lm1pbi50b0FycmF5KCksXG5cdFx0XHRcdGJveE1heDogYm91bmQuYm94Lm1heC50b0FycmF5KCksXG5cblx0XHRcdFx0c3BoZXJlSW5pdGlhbGl6ZWQ6IGJvdW5kLnNwaGVyZUluaXRpYWxpemVkLFxuXHRcdFx0XHRzcGhlcmVSYWRpdXM6IGJvdW5kLnNwaGVyZS5yYWRpdXMsXG5cdFx0XHRcdHNwaGVyZUNlbnRlcjogYm91bmQuc3BoZXJlLmNlbnRlci50b0FycmF5KClcblx0XHRcdH0gKSApO1xuXG5cdFx0XHRvYmplY3QubWF4SW5zdGFuY2VDb3VudCA9IHRoaXMuX21heEluc3RhbmNlQ291bnQ7XG5cdFx0XHRvYmplY3QubWF4VmVydGV4Q291bnQgPSB0aGlzLl9tYXhWZXJ0ZXhDb3VudDtcblx0XHRcdG9iamVjdC5tYXhJbmRleENvdW50ID0gdGhpcy5fbWF4SW5kZXhDb3VudDtcblxuXHRcdFx0b2JqZWN0Lmdlb21ldHJ5SW5pdGlhbGl6ZWQgPSB0aGlzLl9nZW9tZXRyeUluaXRpYWxpemVkO1xuXHRcdFx0b2JqZWN0Lmdlb21ldHJ5Q291bnQgPSB0aGlzLl9nZW9tZXRyeUNvdW50O1xuXG5cdFx0XHRvYmplY3QubWF0cmljZXNUZXh0dXJlID0gdGhpcy5fbWF0cmljZXNUZXh0dXJlLnRvSlNPTiggbWV0YSApO1xuXG5cdFx0XHRpZiAoIHRoaXMuX2NvbG9yc1RleHR1cmUgIT09IG51bGwgKSBvYmplY3QuY29sb3JzVGV4dHVyZSA9IHRoaXMuX2NvbG9yc1RleHR1cmUudG9KU09OKCBtZXRhICk7XG5cblx0XHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRvYmplY3QuYm91bmRpbmdTcGhlcmUgPSB7XG5cdFx0XHRcdFx0Y2VudGVyOiBvYmplY3QuYm91bmRpbmdTcGhlcmUuY2VudGVyLnRvQXJyYXkoKSxcblx0XHRcdFx0XHRyYWRpdXM6IG9iamVjdC5ib3VuZGluZ1NwaGVyZS5yYWRpdXNcblx0XHRcdFx0fTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRoaXMuYm91bmRpbmdCb3ggIT09IG51bGwgKSB7XG5cblx0XHRcdFx0b2JqZWN0LmJvdW5kaW5nQm94ID0ge1xuXHRcdFx0XHRcdG1pbjogb2JqZWN0LmJvdW5kaW5nQm94Lm1pbi50b0FycmF5KCksXG5cdFx0XHRcdFx0bWF4OiBvYmplY3QuYm91bmRpbmdCb3gubWF4LnRvQXJyYXkoKVxuXHRcdFx0XHR9O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvL1xuXG5cdFx0ZnVuY3Rpb24gc2VyaWFsaXplKCBsaWJyYXJ5LCBlbGVtZW50ICkge1xuXG5cdFx0XHRpZiAoIGxpYnJhcnlbIGVsZW1lbnQudXVpZCBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0bGlicmFyeVsgZWxlbWVudC51dWlkIF0gPSBlbGVtZW50LnRvSlNPTiggbWV0YSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBlbGVtZW50LnV1aWQ7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuaXNTY2VuZSApIHtcblxuXHRcdFx0aWYgKCB0aGlzLmJhY2tncm91bmQgKSB7XG5cblx0XHRcdFx0aWYgKCB0aGlzLmJhY2tncm91bmQuaXNDb2xvciApIHtcblxuXHRcdFx0XHRcdG9iamVjdC5iYWNrZ3JvdW5kID0gdGhpcy5iYWNrZ3JvdW5kLnRvSlNPTigpO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHRoaXMuYmFja2dyb3VuZC5pc1RleHR1cmUgKSB7XG5cblx0XHRcdFx0XHRvYmplY3QuYmFja2dyb3VuZCA9IHRoaXMuYmFja2dyb3VuZC50b0pTT04oIG1ldGEgKS51dWlkO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRoaXMuZW52aXJvbm1lbnQgJiYgdGhpcy5lbnZpcm9ubWVudC5pc1RleHR1cmUgJiYgdGhpcy5lbnZpcm9ubWVudC5pc1JlbmRlclRhcmdldFRleHR1cmUgIT09IHRydWUgKSB7XG5cblx0XHRcdFx0b2JqZWN0LmVudmlyb25tZW50ID0gdGhpcy5lbnZpcm9ubWVudC50b0pTT04oIG1ldGEgKS51dWlkO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2UgaWYgKCB0aGlzLmlzTWVzaCB8fCB0aGlzLmlzTGluZSB8fCB0aGlzLmlzUG9pbnRzICkge1xuXG5cdFx0XHRvYmplY3QuZ2VvbWV0cnkgPSBzZXJpYWxpemUoIG1ldGEuZ2VvbWV0cmllcywgdGhpcy5nZW9tZXRyeSApO1xuXG5cdFx0XHRjb25zdCBwYXJhbWV0ZXJzID0gdGhpcy5nZW9tZXRyeS5wYXJhbWV0ZXJzO1xuXG5cdFx0XHRpZiAoIHBhcmFtZXRlcnMgIT09IHVuZGVmaW5lZCAmJiBwYXJhbWV0ZXJzLnNoYXBlcyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGNvbnN0IHNoYXBlcyA9IHBhcmFtZXRlcnMuc2hhcGVzO1xuXG5cdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggc2hhcGVzICkgKSB7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzaGFwZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3Qgc2hhcGUgPSBzaGFwZXNbIGkgXTtcblxuXHRcdFx0XHRcdFx0c2VyaWFsaXplKCBtZXRhLnNoYXBlcywgc2hhcGUgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0c2VyaWFsaXplKCBtZXRhLnNoYXBlcywgc2hhcGVzICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuaXNTa2lubmVkTWVzaCApIHtcblxuXHRcdFx0b2JqZWN0LmJpbmRNb2RlID0gdGhpcy5iaW5kTW9kZTtcblx0XHRcdG9iamVjdC5iaW5kTWF0cml4ID0gdGhpcy5iaW5kTWF0cml4LnRvQXJyYXkoKTtcblxuXHRcdFx0aWYgKCB0aGlzLnNrZWxldG9uICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0c2VyaWFsaXplKCBtZXRhLnNrZWxldG9ucywgdGhpcy5za2VsZXRvbiApO1xuXG5cdFx0XHRcdG9iamVjdC5za2VsZXRvbiA9IHRoaXMuc2tlbGV0b24udXVpZDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm1hdGVyaWFsICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggdGhpcy5tYXRlcmlhbCApICkge1xuXG5cdFx0XHRcdGNvbnN0IHV1aWRzID0gW107XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5tYXRlcmlhbC5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0dXVpZHMucHVzaCggc2VyaWFsaXplKCBtZXRhLm1hdGVyaWFscywgdGhpcy5tYXRlcmlhbFsgaSBdICkgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0b2JqZWN0Lm1hdGVyaWFsID0gdXVpZHM7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0b2JqZWN0Lm1hdGVyaWFsID0gc2VyaWFsaXplKCBtZXRhLm1hdGVyaWFscywgdGhpcy5tYXRlcmlhbCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvL1xuXG5cdFx0aWYgKCB0aGlzLmNoaWxkcmVuLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdG9iamVjdC5jaGlsZHJlbiA9IFtdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLmNoaWxkcmVuLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRvYmplY3QuY2hpbGRyZW4ucHVzaCggdGhpcy5jaGlsZHJlblsgaSBdLnRvSlNPTiggbWV0YSApLm9iamVjdCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvL1xuXG5cdFx0aWYgKCB0aGlzLmFuaW1hdGlvbnMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0b2JqZWN0LmFuaW1hdGlvbnMgPSBbXTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy5hbmltYXRpb25zLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBhbmltYXRpb24gPSB0aGlzLmFuaW1hdGlvbnNbIGkgXTtcblxuXHRcdFx0XHRvYmplY3QuYW5pbWF0aW9ucy5wdXNoKCBzZXJpYWxpemUoIG1ldGEuYW5pbWF0aW9ucywgYW5pbWF0aW9uICkgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBpc1Jvb3RPYmplY3QgKSB7XG5cblx0XHRcdGNvbnN0IGdlb21ldHJpZXMgPSBleHRyYWN0RnJvbUNhY2hlKCBtZXRhLmdlb21ldHJpZXMgKTtcblx0XHRcdGNvbnN0IG1hdGVyaWFscyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEubWF0ZXJpYWxzICk7XG5cdFx0XHRjb25zdCB0ZXh0dXJlcyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEudGV4dHVyZXMgKTtcblx0XHRcdGNvbnN0IGltYWdlcyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEuaW1hZ2VzICk7XG5cdFx0XHRjb25zdCBzaGFwZXMgPSBleHRyYWN0RnJvbUNhY2hlKCBtZXRhLnNoYXBlcyApO1xuXHRcdFx0Y29uc3Qgc2tlbGV0b25zID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS5za2VsZXRvbnMgKTtcblx0XHRcdGNvbnN0IGFuaW1hdGlvbnMgPSBleHRyYWN0RnJvbUNhY2hlKCBtZXRhLmFuaW1hdGlvbnMgKTtcblx0XHRcdGNvbnN0IG5vZGVzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS5ub2RlcyApO1xuXG5cdFx0XHRpZiAoIGdlb21ldHJpZXMubGVuZ3RoID4gMCApIG91dHB1dC5nZW9tZXRyaWVzID0gZ2VvbWV0cmllcztcblx0XHRcdGlmICggbWF0ZXJpYWxzLmxlbmd0aCA+IDAgKSBvdXRwdXQubWF0ZXJpYWxzID0gbWF0ZXJpYWxzO1xuXHRcdFx0aWYgKCB0ZXh0dXJlcy5sZW5ndGggPiAwICkgb3V0cHV0LnRleHR1cmVzID0gdGV4dHVyZXM7XG5cdFx0XHRpZiAoIGltYWdlcy5sZW5ndGggPiAwICkgb3V0cHV0LmltYWdlcyA9IGltYWdlcztcblx0XHRcdGlmICggc2hhcGVzLmxlbmd0aCA+IDAgKSBvdXRwdXQuc2hhcGVzID0gc2hhcGVzO1xuXHRcdFx0aWYgKCBza2VsZXRvbnMubGVuZ3RoID4gMCApIG91dHB1dC5za2VsZXRvbnMgPSBza2VsZXRvbnM7XG5cdFx0XHRpZiAoIGFuaW1hdGlvbnMubGVuZ3RoID4gMCApIG91dHB1dC5hbmltYXRpb25zID0gYW5pbWF0aW9ucztcblx0XHRcdGlmICggbm9kZXMubGVuZ3RoID4gMCApIG91dHB1dC5ub2RlcyA9IG5vZGVzO1xuXG5cdFx0fVxuXG5cdFx0b3V0cHV0Lm9iamVjdCA9IG9iamVjdDtcblxuXHRcdHJldHVybiBvdXRwdXQ7XG5cblx0XHQvLyBleHRyYWN0IGRhdGEgZnJvbSB0aGUgY2FjaGUgaGFzaFxuXHRcdC8vIHJlbW92ZSBtZXRhZGF0YSBvbiBlYWNoIGl0ZW1cblx0XHQvLyBhbmQgcmV0dXJuIGFzIGFycmF5XG5cdFx0ZnVuY3Rpb24gZXh0cmFjdEZyb21DYWNoZSggY2FjaGUgKSB7XG5cblx0XHRcdGNvbnN0IHZhbHVlcyA9IFtdO1xuXHRcdFx0Zm9yICggY29uc3Qga2V5IGluIGNhY2hlICkge1xuXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBjYWNoZVsga2V5IF07XG5cdFx0XHRcdGRlbGV0ZSBkYXRhLm1ldGFkYXRhO1xuXHRcdFx0XHR2YWx1ZXMucHVzaCggZGF0YSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB2YWx1ZXM7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNsb25lKCByZWN1cnNpdmUgKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzLCByZWN1cnNpdmUgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgPSB0cnVlICkge1xuXG5cdFx0dGhpcy5uYW1lID0gc291cmNlLm5hbWU7XG5cblx0XHR0aGlzLnVwLmNvcHkoIHNvdXJjZS51cCApO1xuXG5cdFx0dGhpcy5wb3NpdGlvbi5jb3B5KCBzb3VyY2UucG9zaXRpb24gKTtcblx0XHR0aGlzLnJvdGF0aW9uLm9yZGVyID0gc291cmNlLnJvdGF0aW9uLm9yZGVyO1xuXHRcdHRoaXMucXVhdGVybmlvbi5jb3B5KCBzb3VyY2UucXVhdGVybmlvbiApO1xuXHRcdHRoaXMuc2NhbGUuY29weSggc291cmNlLnNjYWxlICk7XG5cblx0XHR0aGlzLm1hdHJpeC5jb3B5KCBzb3VyY2UubWF0cml4ICk7XG5cdFx0dGhpcy5tYXRyaXhXb3JsZC5jb3B5KCBzb3VyY2UubWF0cml4V29ybGQgKTtcblxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IHNvdXJjZS5tYXRyaXhBdXRvVXBkYXRlO1xuXG5cdFx0dGhpcy5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPSBzb3VyY2UubWF0cml4V29ybGRBdXRvVXBkYXRlO1xuXHRcdHRoaXMubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHNvdXJjZS5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlO1xuXG5cdFx0dGhpcy5sYXllcnMubWFzayA9IHNvdXJjZS5sYXllcnMubWFzaztcblx0XHR0aGlzLnZpc2libGUgPSBzb3VyY2UudmlzaWJsZTtcblxuXHRcdHRoaXMuY2FzdFNoYWRvdyA9IHNvdXJjZS5jYXN0U2hhZG93O1xuXHRcdHRoaXMucmVjZWl2ZVNoYWRvdyA9IHNvdXJjZS5yZWNlaXZlU2hhZG93O1xuXG5cdFx0dGhpcy5mcnVzdHVtQ3VsbGVkID0gc291cmNlLmZydXN0dW1DdWxsZWQ7XG5cdFx0dGhpcy5yZW5kZXJPcmRlciA9IHNvdXJjZS5yZW5kZXJPcmRlcjtcblxuXHRcdHRoaXMuYW5pbWF0aW9ucyA9IHNvdXJjZS5hbmltYXRpb25zLnNsaWNlKCk7XG5cblx0XHR0aGlzLnVzZXJEYXRhID0gSlNPTi5wYXJzZSggSlNPTi5zdHJpbmdpZnkoIHNvdXJjZS51c2VyRGF0YSApICk7XG5cblx0XHRpZiAoIHJlY3Vyc2l2ZSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgc291cmNlLmNoaWxkcmVuLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBjaGlsZCA9IHNvdXJjZS5jaGlsZHJlblsgaSBdO1xuXHRcdFx0XHR0aGlzLmFkZCggY2hpbGQuY2xvbmUoKSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuT2JqZWN0M0QuREVGQVVMVF9VUCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDAsIDEsIDAgKTtcbk9iamVjdDNELkRFRkFVTFRfTUFUUklYX0FVVE9fVVBEQVRFID0gdHJ1ZTtcbk9iamVjdDNELkRFRkFVTFRfTUFUUklYX1dPUkxEX0FVVE9fVVBEQVRFID0gdHJ1ZTtcblxuY29uc3QgX3YwJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdjEkMyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92MiQyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3YzJDIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNvbnN0IF92YWIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdmFjID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3ZiYyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92YXAgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdmJwID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3ZjcCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgVHJpYW5nbGUge1xuXG5cdGNvbnN0cnVjdG9yKCBhID0gbmV3IFZlY3RvcjMoKSwgYiA9IG5ldyBWZWN0b3IzKCksIGMgPSBuZXcgVmVjdG9yMygpICkge1xuXG5cdFx0dGhpcy5hID0gYTtcblx0XHR0aGlzLmIgPSBiO1xuXHRcdHRoaXMuYyA9IGM7XG5cblx0fVxuXG5cdHN0YXRpYyBnZXROb3JtYWwoIGEsIGIsIGMsIHRhcmdldCApIHtcblxuXHRcdHRhcmdldC5zdWJWZWN0b3JzKCBjLCBiICk7XG5cdFx0X3YwJDEuc3ViVmVjdG9ycyggYSwgYiApO1xuXHRcdHRhcmdldC5jcm9zcyggX3YwJDEgKTtcblxuXHRcdGNvbnN0IHRhcmdldExlbmd0aFNxID0gdGFyZ2V0Lmxlbmd0aFNxKCk7XG5cdFx0aWYgKCB0YXJnZXRMZW5ndGhTcSA+IDAgKSB7XG5cblx0XHRcdHJldHVybiB0YXJnZXQubXVsdGlwbHlTY2FsYXIoIDEgLyBNYXRoLnNxcnQoIHRhcmdldExlbmd0aFNxICkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0YXJnZXQuc2V0KCAwLCAwLCAwICk7XG5cblx0fVxuXG5cdC8vIHN0YXRpYy9pbnN0YW5jZSBtZXRob2QgdG8gY2FsY3VsYXRlIGJhcnljZW50cmljIGNvb3JkaW5hdGVzXG5cdC8vIGJhc2VkIG9uOiBodHRwOi8vd3d3LmJsYWNrcGF3bi5jb20vdGV4dHMvcG9pbnRpbnBvbHkvZGVmYXVsdC5odG1sXG5cdHN0YXRpYyBnZXRCYXJ5Y29vcmQoIHBvaW50LCBhLCBiLCBjLCB0YXJnZXQgKSB7XG5cblx0XHRfdjAkMS5zdWJWZWN0b3JzKCBjLCBhICk7XG5cdFx0X3YxJDMuc3ViVmVjdG9ycyggYiwgYSApO1xuXHRcdF92MiQyLnN1YlZlY3RvcnMoIHBvaW50LCBhICk7XG5cblx0XHRjb25zdCBkb3QwMCA9IF92MCQxLmRvdCggX3YwJDEgKTtcblx0XHRjb25zdCBkb3QwMSA9IF92MCQxLmRvdCggX3YxJDMgKTtcblx0XHRjb25zdCBkb3QwMiA9IF92MCQxLmRvdCggX3YyJDIgKTtcblx0XHRjb25zdCBkb3QxMSA9IF92MSQzLmRvdCggX3YxJDMgKTtcblx0XHRjb25zdCBkb3QxMiA9IF92MSQzLmRvdCggX3YyJDIgKTtcblxuXHRcdGNvbnN0IGRlbm9tID0gKCBkb3QwMCAqIGRvdDExIC0gZG90MDEgKiBkb3QwMSApO1xuXG5cdFx0Ly8gY29sbGluZWFyIG9yIHNpbmd1bGFyIHRyaWFuZ2xlXG5cdFx0aWYgKCBkZW5vbSA9PT0gMCApIHtcblxuXHRcdFx0dGFyZ2V0LnNldCggMCwgMCwgMCApO1xuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9XG5cblx0XHRjb25zdCBpbnZEZW5vbSA9IDEgLyBkZW5vbTtcblx0XHRjb25zdCB1ID0gKCBkb3QxMSAqIGRvdDAyIC0gZG90MDEgKiBkb3QxMiApICogaW52RGVub207XG5cdFx0Y29uc3QgdiA9ICggZG90MDAgKiBkb3QxMiAtIGRvdDAxICogZG90MDIgKSAqIGludkRlbm9tO1xuXG5cdFx0Ly8gYmFyeWNlbnRyaWMgY29vcmRpbmF0ZXMgbXVzdCBhbHdheXMgc3VtIHRvIDFcblx0XHRyZXR1cm4gdGFyZ2V0LnNldCggMSAtIHUgLSB2LCB2LCB1ICk7XG5cblx0fVxuXG5cdHN0YXRpYyBjb250YWluc1BvaW50KCBwb2ludCwgYSwgYiwgYyApIHtcblxuXHRcdC8vIGlmIHRoZSB0cmlhbmdsZSBpcyBkZWdlbmVyYXRlIHRoZW4gd2UgY2FuJ3QgY29udGFpbiBhIHBvaW50XG5cdFx0aWYgKCB0aGlzLmdldEJhcnljb29yZCggcG9pbnQsIGEsIGIsIGMsIF92MyQyICkgPT09IG51bGwgKSB7XG5cblx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdH1cblxuXHRcdHJldHVybiAoIF92MyQyLnggPj0gMCApICYmICggX3YzJDIueSA+PSAwICkgJiYgKCAoIF92MyQyLnggKyBfdjMkMi55ICkgPD0gMSApO1xuXG5cdH1cblxuXHRzdGF0aWMgZ2V0SW50ZXJwb2xhdGlvbiggcG9pbnQsIHAxLCBwMiwgcDMsIHYxLCB2MiwgdjMsIHRhcmdldCApIHtcblxuXHRcdGlmICggdGhpcy5nZXRCYXJ5Y29vcmQoIHBvaW50LCBwMSwgcDIsIHAzLCBfdjMkMiApID09PSBudWxsICkge1xuXG5cdFx0XHR0YXJnZXQueCA9IDA7XG5cdFx0XHR0YXJnZXQueSA9IDA7XG5cdFx0XHRpZiAoICd6JyBpbiB0YXJnZXQgKSB0YXJnZXQueiA9IDA7XG5cdFx0XHRpZiAoICd3JyBpbiB0YXJnZXQgKSB0YXJnZXQudyA9IDA7XG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdHRhcmdldC5zZXRTY2FsYXIoIDAgKTtcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCB2MSwgX3YzJDIueCApO1xuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIHYyLCBfdjMkMi55ICk7XG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggdjMsIF92MyQyLnogKTtcblxuXHRcdHJldHVybiB0YXJnZXQ7XG5cblx0fVxuXG5cdHN0YXRpYyBpc0Zyb250RmFjaW5nKCBhLCBiLCBjLCBkaXJlY3Rpb24gKSB7XG5cblx0XHRfdjAkMS5zdWJWZWN0b3JzKCBjLCBiICk7XG5cdFx0X3YxJDMuc3ViVmVjdG9ycyggYSwgYiApO1xuXG5cdFx0Ly8gc3RyaWN0bHkgZnJvbnQgZmFjaW5nXG5cdFx0cmV0dXJuICggX3YwJDEuY3Jvc3MoIF92MSQzICkuZG90KCBkaXJlY3Rpb24gKSA8IDAgKSA/IHRydWUgOiBmYWxzZTtcblxuXHR9XG5cblx0c2V0KCBhLCBiLCBjICkge1xuXG5cdFx0dGhpcy5hLmNvcHkoIGEgKTtcblx0XHR0aGlzLmIuY29weSggYiApO1xuXHRcdHRoaXMuYy5jb3B5KCBjICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbVBvaW50c0FuZEluZGljZXMoIHBvaW50cywgaTAsIGkxLCBpMiApIHtcblxuXHRcdHRoaXMuYS5jb3B5KCBwb2ludHNbIGkwIF0gKTtcblx0XHR0aGlzLmIuY29weSggcG9pbnRzWyBpMSBdICk7XG5cdFx0dGhpcy5jLmNvcHkoIHBvaW50c1sgaTIgXSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21BdHRyaWJ1dGVBbmRJbmRpY2VzKCBhdHRyaWJ1dGUsIGkwLCBpMSwgaTIgKSB7XG5cblx0XHR0aGlzLmEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpMCApO1xuXHRcdHRoaXMuYi5mcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGkxICk7XG5cdFx0dGhpcy5jLmZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaTIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcblxuXHR9XG5cblx0Y29weSggdHJpYW5nbGUgKSB7XG5cblx0XHR0aGlzLmEuY29weSggdHJpYW5nbGUuYSApO1xuXHRcdHRoaXMuYi5jb3B5KCB0cmlhbmdsZS5iICk7XG5cdFx0dGhpcy5jLmNvcHkoIHRyaWFuZ2xlLmMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRBcmVhKCkge1xuXG5cdFx0X3YwJDEuc3ViVmVjdG9ycyggdGhpcy5jLCB0aGlzLmIgKTtcblx0XHRfdjEkMy5zdWJWZWN0b3JzKCB0aGlzLmEsIHRoaXMuYiApO1xuXG5cdFx0cmV0dXJuIF92MCQxLmNyb3NzKCBfdjEkMyApLmxlbmd0aCgpICogMC41O1xuXG5cdH1cblxuXHRnZXRNaWRwb2ludCggdGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIHRhcmdldC5hZGRWZWN0b3JzKCB0aGlzLmEsIHRoaXMuYiApLmFkZCggdGhpcy5jICkubXVsdGlwbHlTY2FsYXIoIDEgLyAzICk7XG5cblx0fVxuXG5cdGdldE5vcm1hbCggdGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIFRyaWFuZ2xlLmdldE5vcm1hbCggdGhpcy5hLCB0aGlzLmIsIHRoaXMuYywgdGFyZ2V0ICk7XG5cblx0fVxuXG5cdGdldFBsYW5lKCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LnNldEZyb21Db3BsYW5hclBvaW50cyggdGhpcy5hLCB0aGlzLmIsIHRoaXMuYyApO1xuXG5cdH1cblxuXHRnZXRCYXJ5Y29vcmQoIHBvaW50LCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gVHJpYW5nbGUuZ2V0QmFyeWNvb3JkKCBwb2ludCwgdGhpcy5hLCB0aGlzLmIsIHRoaXMuYywgdGFyZ2V0ICk7XG5cblx0fVxuXG5cdGdldEludGVycG9sYXRpb24oIHBvaW50LCB2MSwgdjIsIHYzLCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gVHJpYW5nbGUuZ2V0SW50ZXJwb2xhdGlvbiggcG9pbnQsIHRoaXMuYSwgdGhpcy5iLCB0aGlzLmMsIHYxLCB2MiwgdjMsIHRhcmdldCApO1xuXG5cdH1cblxuXHRjb250YWluc1BvaW50KCBwb2ludCApIHtcblxuXHRcdHJldHVybiBUcmlhbmdsZS5jb250YWluc1BvaW50KCBwb2ludCwgdGhpcy5hLCB0aGlzLmIsIHRoaXMuYyApO1xuXG5cdH1cblxuXHRpc0Zyb250RmFjaW5nKCBkaXJlY3Rpb24gKSB7XG5cblx0XHRyZXR1cm4gVHJpYW5nbGUuaXNGcm9udEZhY2luZyggdGhpcy5hLCB0aGlzLmIsIHRoaXMuYywgZGlyZWN0aW9uICk7XG5cblx0fVxuXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcblxuXHRcdHJldHVybiBib3guaW50ZXJzZWN0c1RyaWFuZ2xlKCB0aGlzICk7XG5cblx0fVxuXG5cdGNsb3Nlc3RQb2ludFRvUG9pbnQoIHAsIHRhcmdldCApIHtcblxuXHRcdGNvbnN0IGEgPSB0aGlzLmEsIGIgPSB0aGlzLmIsIGMgPSB0aGlzLmM7XG5cdFx0bGV0IHYsIHc7XG5cblx0XHQvLyBhbGdvcml0aG0gdGhhbmtzIHRvIFJlYWwtVGltZSBDb2xsaXNpb24gRGV0ZWN0aW9uIGJ5IENocmlzdGVyIEVyaWNzb24sXG5cdFx0Ly8gcHVibGlzaGVkIGJ5IE1vcmdhbiBLYXVmbWFubiBQdWJsaXNoZXJzLCAoYykgMjAwNSBFbHNldmllciBJbmMuLFxuXHRcdC8vIHVuZGVyIHRoZSBhY2NvbXBhbnlpbmcgbGljZW5zZTsgc2VlIGNoYXB0ZXIgNS4xLjUgZm9yIGRldGFpbGVkIGV4cGxhbmF0aW9uLlxuXHRcdC8vIGJhc2ljYWxseSwgd2UncmUgZGlzdGluZ3Vpc2hpbmcgd2hpY2ggb2YgdGhlIHZvcm9ub2kgcmVnaW9ucyBvZiB0aGUgdHJpYW5nbGVcblx0XHQvLyB0aGUgcG9pbnQgbGllcyBpbiB3aXRoIHRoZSBtaW5pbXVtIGFtb3VudCBvZiByZWR1bmRhbnQgY29tcHV0YXRpb24uXG5cblx0XHRfdmFiLnN1YlZlY3RvcnMoIGIsIGEgKTtcblx0XHRfdmFjLnN1YlZlY3RvcnMoIGMsIGEgKTtcblx0XHRfdmFwLnN1YlZlY3RvcnMoIHAsIGEgKTtcblx0XHRjb25zdCBkMSA9IF92YWIuZG90KCBfdmFwICk7XG5cdFx0Y29uc3QgZDIgPSBfdmFjLmRvdCggX3ZhcCApO1xuXHRcdGlmICggZDEgPD0gMCAmJiBkMiA8PSAwICkge1xuXG5cdFx0XHQvLyB2ZXJ0ZXggcmVnaW9uIG9mIEE7IGJhcnljZW50cmljIGNvb3JkcyAoMSwgMCwgMClcblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggYSApO1xuXG5cdFx0fVxuXG5cdFx0X3ZicC5zdWJWZWN0b3JzKCBwLCBiICk7XG5cdFx0Y29uc3QgZDMgPSBfdmFiLmRvdCggX3ZicCApO1xuXHRcdGNvbnN0IGQ0ID0gX3ZhYy5kb3QoIF92YnAgKTtcblx0XHRpZiAoIGQzID49IDAgJiYgZDQgPD0gZDMgKSB7XG5cblx0XHRcdC8vIHZlcnRleCByZWdpb24gb2YgQjsgYmFyeWNlbnRyaWMgY29vcmRzICgwLCAxLCAwKVxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBiICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCB2YyA9IGQxICogZDQgLSBkMyAqIGQyO1xuXHRcdGlmICggdmMgPD0gMCAmJiBkMSA+PSAwICYmIGQzIDw9IDAgKSB7XG5cblx0XHRcdHYgPSBkMSAvICggZDEgLSBkMyApO1xuXHRcdFx0Ly8gZWRnZSByZWdpb24gb2YgQUI7IGJhcnljZW50cmljIGNvb3JkcyAoMS12LCB2LCAwKVxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBhICkuYWRkU2NhbGVkVmVjdG9yKCBfdmFiLCB2ICk7XG5cblx0XHR9XG5cblx0XHRfdmNwLnN1YlZlY3RvcnMoIHAsIGMgKTtcblx0XHRjb25zdCBkNSA9IF92YWIuZG90KCBfdmNwICk7XG5cdFx0Y29uc3QgZDYgPSBfdmFjLmRvdCggX3ZjcCApO1xuXHRcdGlmICggZDYgPj0gMCAmJiBkNSA8PSBkNiApIHtcblxuXHRcdFx0Ly8gdmVydGV4IHJlZ2lvbiBvZiBDOyBiYXJ5Y2VudHJpYyBjb29yZHMgKDAsIDAsIDEpXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGMgKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHZiID0gZDUgKiBkMiAtIGQxICogZDY7XG5cdFx0aWYgKCB2YiA8PSAwICYmIGQyID49IDAgJiYgZDYgPD0gMCApIHtcblxuXHRcdFx0dyA9IGQyIC8gKCBkMiAtIGQ2ICk7XG5cdFx0XHQvLyBlZGdlIHJlZ2lvbiBvZiBBQzsgYmFyeWNlbnRyaWMgY29vcmRzICgxLXcsIDAsIHcpXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGEgKS5hZGRTY2FsZWRWZWN0b3IoIF92YWMsIHcgKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHZhID0gZDMgKiBkNiAtIGQ1ICogZDQ7XG5cdFx0aWYgKCB2YSA8PSAwICYmICggZDQgLSBkMyApID49IDAgJiYgKCBkNSAtIGQ2ICkgPj0gMCApIHtcblxuXHRcdFx0X3ZiYy5zdWJWZWN0b3JzKCBjLCBiICk7XG5cdFx0XHR3ID0gKCBkNCAtIGQzICkgLyAoICggZDQgLSBkMyApICsgKCBkNSAtIGQ2ICkgKTtcblx0XHRcdC8vIGVkZ2UgcmVnaW9uIG9mIEJDOyBiYXJ5Y2VudHJpYyBjb29yZHMgKDAsIDEtdywgdylcblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggYiApLmFkZFNjYWxlZFZlY3RvciggX3ZiYywgdyApOyAvLyBlZGdlIHJlZ2lvbiBvZiBCQ1xuXG5cdFx0fVxuXG5cdFx0Ly8gZmFjZSByZWdpb25cblx0XHRjb25zdCBkZW5vbSA9IDEgLyAoIHZhICsgdmIgKyB2YyApO1xuXHRcdC8vIHUgPSB2YSAqIGRlbm9tXG5cdFx0diA9IHZiICogZGVub207XG5cdFx0dyA9IHZjICogZGVub207XG5cblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGEgKS5hZGRTY2FsZWRWZWN0b3IoIF92YWIsIHYgKS5hZGRTY2FsZWRWZWN0b3IoIF92YWMsIHcgKTtcblxuXHR9XG5cblx0ZXF1YWxzKCB0cmlhbmdsZSApIHtcblxuXHRcdHJldHVybiB0cmlhbmdsZS5hLmVxdWFscyggdGhpcy5hICkgJiYgdHJpYW5nbGUuYi5lcXVhbHMoIHRoaXMuYiApICYmIHRyaWFuZ2xlLmMuZXF1YWxzKCB0aGlzLmMgKTtcblxuXHR9XG5cbn1cblxuY29uc3QgX2NvbG9yS2V5d29yZHMgPSB7ICdhbGljZWJsdWUnOiAweEYwRjhGRiwgJ2FudGlxdWV3aGl0ZSc6IDB4RkFFQkQ3LCAnYXF1YSc6IDB4MDBGRkZGLCAnYXF1YW1hcmluZSc6IDB4N0ZGRkQ0LCAnYXp1cmUnOiAweEYwRkZGRixcblx0J2JlaWdlJzogMHhGNUY1REMsICdiaXNxdWUnOiAweEZGRTRDNCwgJ2JsYWNrJzogMHgwMDAwMDAsICdibGFuY2hlZGFsbW9uZCc6IDB4RkZFQkNELCAnYmx1ZSc6IDB4MDAwMEZGLCAnYmx1ZXZpb2xldCc6IDB4OEEyQkUyLFxuXHQnYnJvd24nOiAweEE1MkEyQSwgJ2J1cmx5d29vZCc6IDB4REVCODg3LCAnY2FkZXRibHVlJzogMHg1RjlFQTAsICdjaGFydHJldXNlJzogMHg3RkZGMDAsICdjaG9jb2xhdGUnOiAweEQyNjkxRSwgJ2NvcmFsJzogMHhGRjdGNTAsXG5cdCdjb3JuZmxvd2VyYmx1ZSc6IDB4NjQ5NUVELCAnY29ybnNpbGsnOiAweEZGRjhEQywgJ2NyaW1zb24nOiAweERDMTQzQywgJ2N5YW4nOiAweDAwRkZGRiwgJ2RhcmtibHVlJzogMHgwMDAwOEIsICdkYXJrY3lhbic6IDB4MDA4QjhCLFxuXHQnZGFya2dvbGRlbnJvZCc6IDB4Qjg4NjBCLCAnZGFya2dyYXknOiAweEE5QTlBOSwgJ2RhcmtncmVlbic6IDB4MDA2NDAwLCAnZGFya2dyZXknOiAweEE5QTlBOSwgJ2RhcmtraGFraSc6IDB4QkRCNzZCLCAnZGFya21hZ2VudGEnOiAweDhCMDA4Qixcblx0J2RhcmtvbGl2ZWdyZWVuJzogMHg1NTZCMkYsICdkYXJrb3JhbmdlJzogMHhGRjhDMDAsICdkYXJrb3JjaGlkJzogMHg5OTMyQ0MsICdkYXJrcmVkJzogMHg4QjAwMDAsICdkYXJrc2FsbW9uJzogMHhFOTk2N0EsICdkYXJrc2VhZ3JlZW4nOiAweDhGQkM4Rixcblx0J2RhcmtzbGF0ZWJsdWUnOiAweDQ4M0Q4QiwgJ2RhcmtzbGF0ZWdyYXknOiAweDJGNEY0RiwgJ2RhcmtzbGF0ZWdyZXknOiAweDJGNEY0RiwgJ2Rhcmt0dXJxdW9pc2UnOiAweDAwQ0VEMSwgJ2Rhcmt2aW9sZXQnOiAweDk0MDBEMyxcblx0J2RlZXBwaW5rJzogMHhGRjE0OTMsICdkZWVwc2t5Ymx1ZSc6IDB4MDBCRkZGLCAnZGltZ3JheSc6IDB4Njk2OTY5LCAnZGltZ3JleSc6IDB4Njk2OTY5LCAnZG9kZ2VyYmx1ZSc6IDB4MUU5MEZGLCAnZmlyZWJyaWNrJzogMHhCMjIyMjIsXG5cdCdmbG9yYWx3aGl0ZSc6IDB4RkZGQUYwLCAnZm9yZXN0Z3JlZW4nOiAweDIyOEIyMiwgJ2Z1Y2hzaWEnOiAweEZGMDBGRiwgJ2dhaW5zYm9ybyc6IDB4RENEQ0RDLCAnZ2hvc3R3aGl0ZSc6IDB4RjhGOEZGLCAnZ29sZCc6IDB4RkZENzAwLFxuXHQnZ29sZGVucm9kJzogMHhEQUE1MjAsICdncmF5JzogMHg4MDgwODAsICdncmVlbic6IDB4MDA4MDAwLCAnZ3JlZW55ZWxsb3cnOiAweEFERkYyRiwgJ2dyZXknOiAweDgwODA4MCwgJ2hvbmV5ZGV3JzogMHhGMEZGRjAsICdob3RwaW5rJzogMHhGRjY5QjQsXG5cdCdpbmRpYW5yZWQnOiAweENENUM1QywgJ2luZGlnbyc6IDB4NEIwMDgyLCAnaXZvcnknOiAweEZGRkZGMCwgJ2toYWtpJzogMHhGMEU2OEMsICdsYXZlbmRlcic6IDB4RTZFNkZBLCAnbGF2ZW5kZXJibHVzaCc6IDB4RkZGMEY1LCAnbGF3bmdyZWVuJzogMHg3Q0ZDMDAsXG5cdCdsZW1vbmNoaWZmb24nOiAweEZGRkFDRCwgJ2xpZ2h0Ymx1ZSc6IDB4QUREOEU2LCAnbGlnaHRjb3JhbCc6IDB4RjA4MDgwLCAnbGlnaHRjeWFuJzogMHhFMEZGRkYsICdsaWdodGdvbGRlbnJvZHllbGxvdyc6IDB4RkFGQUQyLCAnbGlnaHRncmF5JzogMHhEM0QzRDMsXG5cdCdsaWdodGdyZWVuJzogMHg5MEVFOTAsICdsaWdodGdyZXknOiAweEQzRDNEMywgJ2xpZ2h0cGluayc6IDB4RkZCNkMxLCAnbGlnaHRzYWxtb24nOiAweEZGQTA3QSwgJ2xpZ2h0c2VhZ3JlZW4nOiAweDIwQjJBQSwgJ2xpZ2h0c2t5Ymx1ZSc6IDB4ODdDRUZBLFxuXHQnbGlnaHRzbGF0ZWdyYXknOiAweDc3ODg5OSwgJ2xpZ2h0c2xhdGVncmV5JzogMHg3Nzg4OTksICdsaWdodHN0ZWVsYmx1ZSc6IDB4QjBDNERFLCAnbGlnaHR5ZWxsb3cnOiAweEZGRkZFMCwgJ2xpbWUnOiAweDAwRkYwMCwgJ2xpbWVncmVlbic6IDB4MzJDRDMyLFxuXHQnbGluZW4nOiAweEZBRjBFNiwgJ21hZ2VudGEnOiAweEZGMDBGRiwgJ21hcm9vbic6IDB4ODAwMDAwLCAnbWVkaXVtYXF1YW1hcmluZSc6IDB4NjZDREFBLCAnbWVkaXVtYmx1ZSc6IDB4MDAwMENELCAnbWVkaXVtb3JjaGlkJzogMHhCQTU1RDMsXG5cdCdtZWRpdW1wdXJwbGUnOiAweDkzNzBEQiwgJ21lZGl1bXNlYWdyZWVuJzogMHgzQ0IzNzEsICdtZWRpdW1zbGF0ZWJsdWUnOiAweDdCNjhFRSwgJ21lZGl1bXNwcmluZ2dyZWVuJzogMHgwMEZBOUEsICdtZWRpdW10dXJxdW9pc2UnOiAweDQ4RDFDQyxcblx0J21lZGl1bXZpb2xldHJlZCc6IDB4QzcxNTg1LCAnbWlkbmlnaHRibHVlJzogMHgxOTE5NzAsICdtaW50Y3JlYW0nOiAweEY1RkZGQSwgJ21pc3R5cm9zZSc6IDB4RkZFNEUxLCAnbW9jY2FzaW4nOiAweEZGRTRCNSwgJ25hdmFqb3doaXRlJzogMHhGRkRFQUQsXG5cdCduYXZ5JzogMHgwMDAwODAsICdvbGRsYWNlJzogMHhGREY1RTYsICdvbGl2ZSc6IDB4ODA4MDAwLCAnb2xpdmVkcmFiJzogMHg2QjhFMjMsICdvcmFuZ2UnOiAweEZGQTUwMCwgJ29yYW5nZXJlZCc6IDB4RkY0NTAwLCAnb3JjaGlkJzogMHhEQTcwRDYsXG5cdCdwYWxlZ29sZGVucm9kJzogMHhFRUU4QUEsICdwYWxlZ3JlZW4nOiAweDk4RkI5OCwgJ3BhbGV0dXJxdW9pc2UnOiAweEFGRUVFRSwgJ3BhbGV2aW9sZXRyZWQnOiAweERCNzA5MywgJ3BhcGF5YXdoaXAnOiAweEZGRUZENSwgJ3BlYWNocHVmZic6IDB4RkZEQUI5LFxuXHQncGVydSc6IDB4Q0Q4NTNGLCAncGluayc6IDB4RkZDMENCLCAncGx1bSc6IDB4RERBMERELCAncG93ZGVyYmx1ZSc6IDB4QjBFMEU2LCAncHVycGxlJzogMHg4MDAwODAsICdyZWJlY2NhcHVycGxlJzogMHg2NjMzOTksICdyZWQnOiAweEZGMDAwMCwgJ3Jvc3licm93bic6IDB4QkM4RjhGLFxuXHQncm95YWxibHVlJzogMHg0MTY5RTEsICdzYWRkbGVicm93bic6IDB4OEI0NTEzLCAnc2FsbW9uJzogMHhGQTgwNzIsICdzYW5keWJyb3duJzogMHhGNEE0NjAsICdzZWFncmVlbic6IDB4MkU4QjU3LCAnc2Vhc2hlbGwnOiAweEZGRjVFRSxcblx0J3NpZW5uYSc6IDB4QTA1MjJELCAnc2lsdmVyJzogMHhDMEMwQzAsICdza3libHVlJzogMHg4N0NFRUIsICdzbGF0ZWJsdWUnOiAweDZBNUFDRCwgJ3NsYXRlZ3JheSc6IDB4NzA4MDkwLCAnc2xhdGVncmV5JzogMHg3MDgwOTAsICdzbm93JzogMHhGRkZBRkEsXG5cdCdzcHJpbmdncmVlbic6IDB4MDBGRjdGLCAnc3RlZWxibHVlJzogMHg0NjgyQjQsICd0YW4nOiAweEQyQjQ4QywgJ3RlYWwnOiAweDAwODA4MCwgJ3RoaXN0bGUnOiAweEQ4QkZEOCwgJ3RvbWF0byc6IDB4RkY2MzQ3LCAndHVycXVvaXNlJzogMHg0MEUwRDAsXG5cdCd2aW9sZXQnOiAweEVFODJFRSwgJ3doZWF0JzogMHhGNURFQjMsICd3aGl0ZSc6IDB4RkZGRkZGLCAnd2hpdGVzbW9rZSc6IDB4RjVGNUY1LCAneWVsbG93JzogMHhGRkZGMDAsICd5ZWxsb3dncmVlbic6IDB4OUFDRDMyIH07XG5cbmNvbnN0IF9oc2xBID0geyBoOiAwLCBzOiAwLCBsOiAwIH07XG5jb25zdCBfaHNsQiA9IHsgaDogMCwgczogMCwgbDogMCB9O1xuXG5mdW5jdGlvbiBodWUycmdiKCBwLCBxLCB0ICkge1xuXG5cdGlmICggdCA8IDAgKSB0ICs9IDE7XG5cdGlmICggdCA+IDEgKSB0IC09IDE7XG5cdGlmICggdCA8IDEgLyA2ICkgcmV0dXJuIHAgKyAoIHEgLSBwICkgKiA2ICogdDtcblx0aWYgKCB0IDwgMSAvIDIgKSByZXR1cm4gcTtcblx0aWYgKCB0IDwgMiAvIDMgKSByZXR1cm4gcCArICggcSAtIHAgKSAqIDYgKiAoIDIgLyAzIC0gdCApO1xuXHRyZXR1cm4gcDtcblxufVxuXG5jbGFzcyBDb2xvciB7XG5cblx0Y29uc3RydWN0b3IoIHIsIGcsIGIgKSB7XG5cblx0XHR0aGlzLmlzQ29sb3IgPSB0cnVlO1xuXG5cdFx0dGhpcy5yID0gMTtcblx0XHR0aGlzLmcgPSAxO1xuXHRcdHRoaXMuYiA9IDE7XG5cblx0XHRyZXR1cm4gdGhpcy5zZXQoIHIsIGcsIGIgKTtcblxuXHR9XG5cblx0c2V0KCByLCBnLCBiICkge1xuXG5cdFx0aWYgKCBnID09PSB1bmRlZmluZWQgJiYgYiA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHQvLyByIGlzIFRIUkVFLkNvbG9yLCBoZXggb3Igc3RyaW5nXG5cblx0XHRcdGNvbnN0IHZhbHVlID0gcjtcblxuXHRcdFx0aWYgKCB2YWx1ZSAmJiB2YWx1ZS5pc0NvbG9yICkge1xuXG5cdFx0XHRcdHRoaXMuY29weSggdmFsdWUgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggdHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyApIHtcblxuXHRcdFx0XHR0aGlzLnNldEhleCggdmFsdWUgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggdHlwZW9mIHZhbHVlID09PSAnc3RyaW5nJyApIHtcblxuXHRcdFx0XHR0aGlzLnNldFN0eWxlKCB2YWx1ZSApO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLnNldFJHQiggciwgZywgYiApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFNjYWxhciggc2NhbGFyICkge1xuXG5cdFx0dGhpcy5yID0gc2NhbGFyO1xuXHRcdHRoaXMuZyA9IHNjYWxhcjtcblx0XHR0aGlzLmIgPSBzY2FsYXI7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0SGV4KCBoZXgsIGNvbG9yU3BhY2UgPSBTUkdCQ29sb3JTcGFjZSApIHtcblxuXHRcdGhleCA9IE1hdGguZmxvb3IoIGhleCApO1xuXG5cdFx0dGhpcy5yID0gKCBoZXggPj4gMTYgJiAyNTUgKSAvIDI1NTtcblx0XHR0aGlzLmcgPSAoIGhleCA+PiA4ICYgMjU1ICkgLyAyNTU7XG5cdFx0dGhpcy5iID0gKCBoZXggJiAyNTUgKSAvIDI1NTtcblxuXHRcdENvbG9yTWFuYWdlbWVudC50b1dvcmtpbmdDb2xvclNwYWNlKCB0aGlzLCBjb2xvclNwYWNlICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0UkdCKCByLCBnLCBiLCBjb2xvclNwYWNlID0gQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlICkge1xuXG5cdFx0dGhpcy5yID0gcjtcblx0XHR0aGlzLmcgPSBnO1xuXHRcdHRoaXMuYiA9IGI7XG5cblx0XHRDb2xvck1hbmFnZW1lbnQudG9Xb3JraW5nQ29sb3JTcGFjZSggdGhpcywgY29sb3JTcGFjZSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEhTTCggaCwgcywgbCwgY29sb3JTcGFjZSA9IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSApIHtcblxuXHRcdC8vIGgscyxsIHJhbmdlcyBhcmUgaW4gMC4wIC0gMS4wXG5cdFx0aCA9IGV1Y2xpZGVhbk1vZHVsbyggaCwgMSApO1xuXHRcdHMgPSBjbGFtcCggcywgMCwgMSApO1xuXHRcdGwgPSBjbGFtcCggbCwgMCwgMSApO1xuXG5cdFx0aWYgKCBzID09PSAwICkge1xuXG5cdFx0XHR0aGlzLnIgPSB0aGlzLmcgPSB0aGlzLmIgPSBsO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc3QgcCA9IGwgPD0gMC41ID8gbCAqICggMSArIHMgKSA6IGwgKyBzIC0gKCBsICogcyApO1xuXHRcdFx0Y29uc3QgcSA9ICggMiAqIGwgKSAtIHA7XG5cblx0XHRcdHRoaXMuciA9IGh1ZTJyZ2IoIHEsIHAsIGggKyAxIC8gMyApO1xuXHRcdFx0dGhpcy5nID0gaHVlMnJnYiggcSwgcCwgaCApO1xuXHRcdFx0dGhpcy5iID0gaHVlMnJnYiggcSwgcCwgaCAtIDEgLyAzICk7XG5cblx0XHR9XG5cblx0XHRDb2xvck1hbmFnZW1lbnQudG9Xb3JraW5nQ29sb3JTcGFjZSggdGhpcywgY29sb3JTcGFjZSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFN0eWxlKCBzdHlsZSwgY29sb3JTcGFjZSA9IFNSR0JDb2xvclNwYWNlICkge1xuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlQWxwaGEoIHN0cmluZyApIHtcblxuXHRcdFx0aWYgKCBzdHJpbmcgPT09IHVuZGVmaW5lZCApIHJldHVybjtcblxuXHRcdFx0aWYgKCBwYXJzZUZsb2F0KCBzdHJpbmcgKSA8IDEgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQ29sb3I6IEFscGhhIGNvbXBvbmVudCBvZiAnICsgc3R5bGUgKyAnIHdpbGwgYmUgaWdub3JlZC4nICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXG5cdFx0bGV0IG07XG5cblx0XHRpZiAoIG0gPSAvXihcXHcrKVxcKChbXlxcKV0qKVxcKS8uZXhlYyggc3R5bGUgKSApIHtcblxuXHRcdFx0Ly8gcmdiIC8gaHNsXG5cblx0XHRcdGxldCBjb2xvcjtcblx0XHRcdGNvbnN0IG5hbWUgPSBtWyAxIF07XG5cdFx0XHRjb25zdCBjb21wb25lbnRzID0gbVsgMiBdO1xuXG5cdFx0XHRzd2l0Y2ggKCBuYW1lICkge1xuXG5cdFx0XHRcdGNhc2UgJ3JnYic6XG5cdFx0XHRcdGNhc2UgJ3JnYmEnOlxuXG5cdFx0XHRcdFx0aWYgKCBjb2xvciA9IC9eXFxzKihcXGQrKVxccyosXFxzKihcXGQrKVxccyosXFxzKihcXGQrKVxccyooPzosXFxzKihcXGQqXFwuP1xcZCspXFxzKik/JC8uZXhlYyggY29tcG9uZW50cyApICkge1xuXG5cdFx0XHRcdFx0XHQvLyByZ2IoMjU1LDAsMCkgcmdiYSgyNTUsMCwwLDAuNSlcblxuXHRcdFx0XHRcdFx0aGFuZGxlQWxwaGEoIGNvbG9yWyA0IF0gKTtcblxuXHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMuc2V0UkdCKFxuXHRcdFx0XHRcdFx0XHRNYXRoLm1pbiggMjU1LCBwYXJzZUludCggY29sb3JbIDEgXSwgMTAgKSApIC8gMjU1LFxuXHRcdFx0XHRcdFx0XHRNYXRoLm1pbiggMjU1LCBwYXJzZUludCggY29sb3JbIDIgXSwgMTAgKSApIC8gMjU1LFxuXHRcdFx0XHRcdFx0XHRNYXRoLm1pbiggMjU1LCBwYXJzZUludCggY29sb3JbIDMgXSwgMTAgKSApIC8gMjU1LFxuXHRcdFx0XHRcdFx0XHRjb2xvclNwYWNlXG5cdFx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCBjb2xvciA9IC9eXFxzKihcXGQrKVxcJVxccyosXFxzKihcXGQrKVxcJVxccyosXFxzKihcXGQrKVxcJVxccyooPzosXFxzKihcXGQqXFwuP1xcZCspXFxzKik/JC8uZXhlYyggY29tcG9uZW50cyApICkge1xuXG5cdFx0XHRcdFx0XHQvLyByZ2IoMTAwJSwwJSwwJSkgcmdiYSgxMDAlLDAlLDAlLDAuNSlcblxuXHRcdFx0XHRcdFx0aGFuZGxlQWxwaGEoIGNvbG9yWyA0IF0gKTtcblxuXHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMuc2V0UkdCKFxuXHRcdFx0XHRcdFx0XHRNYXRoLm1pbiggMTAwLCBwYXJzZUludCggY29sb3JbIDEgXSwgMTAgKSApIC8gMTAwLFxuXHRcdFx0XHRcdFx0XHRNYXRoLm1pbiggMTAwLCBwYXJzZUludCggY29sb3JbIDIgXSwgMTAgKSApIC8gMTAwLFxuXHRcdFx0XHRcdFx0XHRNYXRoLm1pbiggMTAwLCBwYXJzZUludCggY29sb3JbIDMgXSwgMTAgKSApIC8gMTAwLFxuXHRcdFx0XHRcdFx0XHRjb2xvclNwYWNlXG5cdFx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAnaHNsJzpcblx0XHRcdFx0Y2FzZSAnaHNsYSc6XG5cblx0XHRcdFx0XHRpZiAoIGNvbG9yID0gL15cXHMqKFxcZCpcXC4/XFxkKylcXHMqLFxccyooXFxkKlxcLj9cXGQrKVxcJVxccyosXFxzKihcXGQqXFwuP1xcZCspXFwlXFxzKig/OixcXHMqKFxcZCpcXC4/XFxkKylcXHMqKT8kLy5leGVjKCBjb21wb25lbnRzICkgKSB7XG5cblx0XHRcdFx0XHRcdC8vIGhzbCgxMjAsNTAlLDUwJSkgaHNsYSgxMjAsNTAlLDUwJSwwLjUpXG5cblx0XHRcdFx0XHRcdGhhbmRsZUFscGhhKCBjb2xvclsgNCBdICk7XG5cblx0XHRcdFx0XHRcdHJldHVybiB0aGlzLnNldEhTTChcblx0XHRcdFx0XHRcdFx0cGFyc2VGbG9hdCggY29sb3JbIDEgXSApIC8gMzYwLFxuXHRcdFx0XHRcdFx0XHRwYXJzZUZsb2F0KCBjb2xvclsgMiBdICkgLyAxMDAsXG5cdFx0XHRcdFx0XHRcdHBhcnNlRmxvYXQoIGNvbG9yWyAzIF0gKSAvIDEwMCxcblx0XHRcdFx0XHRcdFx0Y29sb3JTcGFjZVxuXHRcdFx0XHRcdFx0KTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5Db2xvcjogVW5rbm93biBjb2xvciBtb2RlbCAnICsgc3R5bGUgKTtcblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIGlmICggbSA9IC9eXFwjKFtBLUZhLWZcXGRdKykkLy5leGVjKCBzdHlsZSApICkge1xuXG5cdFx0XHQvLyBoZXggY29sb3JcblxuXHRcdFx0Y29uc3QgaGV4ID0gbVsgMSBdO1xuXHRcdFx0Y29uc3Qgc2l6ZSA9IGhleC5sZW5ndGg7XG5cblx0XHRcdGlmICggc2l6ZSA9PT0gMyApIHtcblxuXHRcdFx0XHQvLyAjZmYwXG5cdFx0XHRcdHJldHVybiB0aGlzLnNldFJHQihcblx0XHRcdFx0XHRwYXJzZUludCggaGV4LmNoYXJBdCggMCApLCAxNiApIC8gMTUsXG5cdFx0XHRcdFx0cGFyc2VJbnQoIGhleC5jaGFyQXQoIDEgKSwgMTYgKSAvIDE1LFxuXHRcdFx0XHRcdHBhcnNlSW50KCBoZXguY2hhckF0KCAyICksIDE2ICkgLyAxNSxcblx0XHRcdFx0XHRjb2xvclNwYWNlXG5cdFx0XHRcdCk7XG5cblx0XHRcdH0gZWxzZSBpZiAoIHNpemUgPT09IDYgKSB7XG5cblx0XHRcdFx0Ly8gI2ZmMDAwMFxuXHRcdFx0XHRyZXR1cm4gdGhpcy5zZXRIZXgoIHBhcnNlSW50KCBoZXgsIDE2ICksIGNvbG9yU3BhY2UgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5Db2xvcjogSW52YWxpZCBoZXggY29sb3IgJyArIHN0eWxlICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSBpZiAoIHN0eWxlICYmIHN0eWxlLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdHJldHVybiB0aGlzLnNldENvbG9yTmFtZSggc3R5bGUsIGNvbG9yU3BhY2UgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRDb2xvck5hbWUoIHN0eWxlLCBjb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2UgKSB7XG5cblx0XHQvLyBjb2xvciBrZXl3b3Jkc1xuXHRcdGNvbnN0IGhleCA9IF9jb2xvcktleXdvcmRzWyBzdHlsZS50b0xvd2VyQ2FzZSgpIF07XG5cblx0XHRpZiAoIGhleCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHQvLyByZWRcblx0XHRcdHRoaXMuc2V0SGV4KCBoZXgsIGNvbG9yU3BhY2UgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIHVua25vd24gY29sb3Jcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkNvbG9yOiBVbmtub3duIGNvbG9yICcgKyBzdHlsZSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCB0aGlzLnIsIHRoaXMuZywgdGhpcy5iICk7XG5cblx0fVxuXG5cdGNvcHkoIGNvbG9yICkge1xuXG5cdFx0dGhpcy5yID0gY29sb3Iucjtcblx0XHR0aGlzLmcgPSBjb2xvci5nO1xuXHRcdHRoaXMuYiA9IGNvbG9yLmI7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weVNSR0JUb0xpbmVhciggY29sb3IgKSB7XG5cblx0XHR0aGlzLnIgPSBTUkdCVG9MaW5lYXIoIGNvbG9yLnIgKTtcblx0XHR0aGlzLmcgPSBTUkdCVG9MaW5lYXIoIGNvbG9yLmcgKTtcblx0XHR0aGlzLmIgPSBTUkdCVG9MaW5lYXIoIGNvbG9yLmIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb3B5TGluZWFyVG9TUkdCKCBjb2xvciApIHtcblxuXHRcdHRoaXMuciA9IExpbmVhclRvU1JHQiggY29sb3IuciApO1xuXHRcdHRoaXMuZyA9IExpbmVhclRvU1JHQiggY29sb3IuZyApO1xuXHRcdHRoaXMuYiA9IExpbmVhclRvU1JHQiggY29sb3IuYiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvbnZlcnRTUkdCVG9MaW5lYXIoKSB7XG5cblx0XHR0aGlzLmNvcHlTUkdCVG9MaW5lYXIoIHRoaXMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb252ZXJ0TGluZWFyVG9TUkdCKCkge1xuXG5cdFx0dGhpcy5jb3B5TGluZWFyVG9TUkdCKCB0aGlzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0SGV4KCBjb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2UgKSB7XG5cblx0XHRDb2xvck1hbmFnZW1lbnQuZnJvbVdvcmtpbmdDb2xvclNwYWNlKCBfY29sb3IuY29weSggdGhpcyApLCBjb2xvclNwYWNlICk7XG5cblx0XHRyZXR1cm4gTWF0aC5yb3VuZCggY2xhbXAoIF9jb2xvci5yICogMjU1LCAwLCAyNTUgKSApICogNjU1MzYgKyBNYXRoLnJvdW5kKCBjbGFtcCggX2NvbG9yLmcgKiAyNTUsIDAsIDI1NSApICkgKiAyNTYgKyBNYXRoLnJvdW5kKCBjbGFtcCggX2NvbG9yLmIgKiAyNTUsIDAsIDI1NSApICk7XG5cblx0fVxuXG5cdGdldEhleFN0cmluZyggY29sb3JTcGFjZSA9IFNSR0JDb2xvclNwYWNlICkge1xuXG5cdFx0cmV0dXJuICggJzAwMDAwMCcgKyB0aGlzLmdldEhleCggY29sb3JTcGFjZSApLnRvU3RyaW5nKCAxNiApICkuc2xpY2UoIC0gNiApO1xuXG5cdH1cblxuXHRnZXRIU0woIHRhcmdldCwgY29sb3JTcGFjZSA9IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSApIHtcblxuXHRcdC8vIGgscyxsIHJhbmdlcyBhcmUgaW4gMC4wIC0gMS4wXG5cblx0XHRDb2xvck1hbmFnZW1lbnQuZnJvbVdvcmtpbmdDb2xvclNwYWNlKCBfY29sb3IuY29weSggdGhpcyApLCBjb2xvclNwYWNlICk7XG5cblx0XHRjb25zdCByID0gX2NvbG9yLnIsIGcgPSBfY29sb3IuZywgYiA9IF9jb2xvci5iO1xuXG5cdFx0Y29uc3QgbWF4ID0gTWF0aC5tYXgoIHIsIGcsIGIgKTtcblx0XHRjb25zdCBtaW4gPSBNYXRoLm1pbiggciwgZywgYiApO1xuXG5cdFx0bGV0IGh1ZSwgc2F0dXJhdGlvbjtcblx0XHRjb25zdCBsaWdodG5lc3MgPSAoIG1pbiArIG1heCApIC8gMi4wO1xuXG5cdFx0aWYgKCBtaW4gPT09IG1heCApIHtcblxuXHRcdFx0aHVlID0gMDtcblx0XHRcdHNhdHVyYXRpb24gPSAwO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc3QgZGVsdGEgPSBtYXggLSBtaW47XG5cblx0XHRcdHNhdHVyYXRpb24gPSBsaWdodG5lc3MgPD0gMC41ID8gZGVsdGEgLyAoIG1heCArIG1pbiApIDogZGVsdGEgLyAoIDIgLSBtYXggLSBtaW4gKTtcblxuXHRcdFx0c3dpdGNoICggbWF4ICkge1xuXG5cdFx0XHRcdGNhc2UgcjogaHVlID0gKCBnIC0gYiApIC8gZGVsdGEgKyAoIGcgPCBiID8gNiA6IDAgKTsgYnJlYWs7XG5cdFx0XHRcdGNhc2UgZzogaHVlID0gKCBiIC0gciApIC8gZGVsdGEgKyAyOyBicmVhaztcblx0XHRcdFx0Y2FzZSBiOiBodWUgPSAoIHIgLSBnICkgLyBkZWx0YSArIDQ7IGJyZWFrO1xuXG5cdFx0XHR9XG5cblx0XHRcdGh1ZSAvPSA2O1xuXG5cdFx0fVxuXG5cdFx0dGFyZ2V0LmggPSBodWU7XG5cdFx0dGFyZ2V0LnMgPSBzYXR1cmF0aW9uO1xuXHRcdHRhcmdldC5sID0gbGlnaHRuZXNzO1xuXG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0Z2V0UkdCKCB0YXJnZXQsIGNvbG9yU3BhY2UgPSBDb2xvck1hbmFnZW1lbnQud29ya2luZ0NvbG9yU3BhY2UgKSB7XG5cblx0XHRDb2xvck1hbmFnZW1lbnQuZnJvbVdvcmtpbmdDb2xvclNwYWNlKCBfY29sb3IuY29weSggdGhpcyApLCBjb2xvclNwYWNlICk7XG5cblx0XHR0YXJnZXQuciA9IF9jb2xvci5yO1xuXHRcdHRhcmdldC5nID0gX2NvbG9yLmc7XG5cdFx0dGFyZ2V0LmIgPSBfY29sb3IuYjtcblxuXHRcdHJldHVybiB0YXJnZXQ7XG5cblx0fVxuXG5cdGdldFN0eWxlKCBjb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2UgKSB7XG5cblx0XHRDb2xvck1hbmFnZW1lbnQuZnJvbVdvcmtpbmdDb2xvclNwYWNlKCBfY29sb3IuY29weSggdGhpcyApLCBjb2xvclNwYWNlICk7XG5cblx0XHRjb25zdCByID0gX2NvbG9yLnIsIGcgPSBfY29sb3IuZywgYiA9IF9jb2xvci5iO1xuXG5cdFx0aWYgKCBjb2xvclNwYWNlICE9PSBTUkdCQ29sb3JTcGFjZSApIHtcblxuXHRcdFx0Ly8gUmVxdWlyZXMgQ1NTIENvbG9yIE1vZHVsZSBMZXZlbCA0IChodHRwczovL3d3dy53My5vcmcvVFIvY3NzLWNvbG9yLTQvKS5cblx0XHRcdHJldHVybiBgY29sb3IoJHsgY29sb3JTcGFjZSB9ICR7IHIudG9GaXhlZCggMyApIH0gJHsgZy50b0ZpeGVkKCAzICkgfSAkeyBiLnRvRml4ZWQoIDMgKSB9KWA7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gYHJnYigkeyBNYXRoLnJvdW5kKCByICogMjU1ICkgfSwkeyBNYXRoLnJvdW5kKCBnICogMjU1ICkgfSwkeyBNYXRoLnJvdW5kKCBiICogMjU1ICkgfSlgO1xuXG5cdH1cblxuXHRvZmZzZXRIU0woIGgsIHMsIGwgKSB7XG5cblx0XHR0aGlzLmdldEhTTCggX2hzbEEgKTtcblxuXHRcdHJldHVybiB0aGlzLnNldEhTTCggX2hzbEEuaCArIGgsIF9oc2xBLnMgKyBzLCBfaHNsQS5sICsgbCApO1xuXG5cdH1cblxuXHRhZGQoIGNvbG9yICkge1xuXG5cdFx0dGhpcy5yICs9IGNvbG9yLnI7XG5cdFx0dGhpcy5nICs9IGNvbG9yLmc7XG5cdFx0dGhpcy5iICs9IGNvbG9yLmI7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkQ29sb3JzKCBjb2xvcjEsIGNvbG9yMiApIHtcblxuXHRcdHRoaXMuciA9IGNvbG9yMS5yICsgY29sb3IyLnI7XG5cdFx0dGhpcy5nID0gY29sb3IxLmcgKyBjb2xvcjIuZztcblx0XHR0aGlzLmIgPSBjb2xvcjEuYiArIGNvbG9yMi5iO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFkZFNjYWxhciggcyApIHtcblxuXHRcdHRoaXMuciArPSBzO1xuXHRcdHRoaXMuZyArPSBzO1xuXHRcdHRoaXMuYiArPSBzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN1YiggY29sb3IgKSB7XG5cblx0XHR0aGlzLnIgPSBNYXRoLm1heCggMCwgdGhpcy5yIC0gY29sb3IuciApO1xuXHRcdHRoaXMuZyA9IE1hdGgubWF4KCAwLCB0aGlzLmcgLSBjb2xvci5nICk7XG5cdFx0dGhpcy5iID0gTWF0aC5tYXgoIDAsIHRoaXMuYiAtIGNvbG9yLmIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtdWx0aXBseSggY29sb3IgKSB7XG5cblx0XHR0aGlzLnIgKj0gY29sb3Iucjtcblx0XHR0aGlzLmcgKj0gY29sb3IuZztcblx0XHR0aGlzLmIgKj0gY29sb3IuYjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtdWx0aXBseVNjYWxhciggcyApIHtcblxuXHRcdHRoaXMuciAqPSBzO1xuXHRcdHRoaXMuZyAqPSBzO1xuXHRcdHRoaXMuYiAqPSBzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGxlcnAoIGNvbG9yLCBhbHBoYSApIHtcblxuXHRcdHRoaXMuciArPSAoIGNvbG9yLnIgLSB0aGlzLnIgKSAqIGFscGhhO1xuXHRcdHRoaXMuZyArPSAoIGNvbG9yLmcgLSB0aGlzLmcgKSAqIGFscGhhO1xuXHRcdHRoaXMuYiArPSAoIGNvbG9yLmIgLSB0aGlzLmIgKSAqIGFscGhhO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGxlcnBDb2xvcnMoIGNvbG9yMSwgY29sb3IyLCBhbHBoYSApIHtcblxuXHRcdHRoaXMuciA9IGNvbG9yMS5yICsgKCBjb2xvcjIuciAtIGNvbG9yMS5yICkgKiBhbHBoYTtcblx0XHR0aGlzLmcgPSBjb2xvcjEuZyArICggY29sb3IyLmcgLSBjb2xvcjEuZyApICogYWxwaGE7XG5cdFx0dGhpcy5iID0gY29sb3IxLmIgKyAoIGNvbG9yMi5iIC0gY29sb3IxLmIgKSAqIGFscGhhO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGxlcnBIU0woIGNvbG9yLCBhbHBoYSApIHtcblxuXHRcdHRoaXMuZ2V0SFNMKCBfaHNsQSApO1xuXHRcdGNvbG9yLmdldEhTTCggX2hzbEIgKTtcblxuXHRcdGNvbnN0IGggPSBsZXJwKCBfaHNsQS5oLCBfaHNsQi5oLCBhbHBoYSApO1xuXHRcdGNvbnN0IHMgPSBsZXJwKCBfaHNsQS5zLCBfaHNsQi5zLCBhbHBoYSApO1xuXHRcdGNvbnN0IGwgPSBsZXJwKCBfaHNsQS5sLCBfaHNsQi5sLCBhbHBoYSApO1xuXG5cdFx0dGhpcy5zZXRIU0woIGgsIHMsIGwgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tVmVjdG9yMyggdiApIHtcblxuXHRcdHRoaXMuciA9IHYueDtcblx0XHR0aGlzLmcgPSB2Lnk7XG5cdFx0dGhpcy5iID0gdi56O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFwcGx5TWF0cml4MyggbSApIHtcblxuXHRcdGNvbnN0IHIgPSB0aGlzLnIsIGcgPSB0aGlzLmcsIGIgPSB0aGlzLmI7XG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XG5cblx0XHR0aGlzLnIgPSBlWyAwIF0gKiByICsgZVsgMyBdICogZyArIGVbIDYgXSAqIGI7XG5cdFx0dGhpcy5nID0gZVsgMSBdICogciArIGVbIDQgXSAqIGcgKyBlWyA3IF0gKiBiO1xuXHRcdHRoaXMuYiA9IGVbIDIgXSAqIHIgKyBlWyA1IF0gKiBnICsgZVsgOCBdICogYjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRlcXVhbHMoIGMgKSB7XG5cblx0XHRyZXR1cm4gKCBjLnIgPT09IHRoaXMuciApICYmICggYy5nID09PSB0aGlzLmcgKSAmJiAoIGMuYiA9PT0gdGhpcy5iICk7XG5cblx0fVxuXG5cdGZyb21BcnJheSggYXJyYXksIG9mZnNldCA9IDAgKSB7XG5cblx0XHR0aGlzLnIgPSBhcnJheVsgb2Zmc2V0IF07XG5cdFx0dGhpcy5nID0gYXJyYXlbIG9mZnNldCArIDEgXTtcblx0XHR0aGlzLmIgPSBhcnJheVsgb2Zmc2V0ICsgMiBdO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvQXJyYXkoIGFycmF5ID0gW10sIG9mZnNldCA9IDAgKSB7XG5cblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLnI7XG5cdFx0YXJyYXlbIG9mZnNldCArIDEgXSA9IHRoaXMuZztcblx0XHRhcnJheVsgb2Zmc2V0ICsgMiBdID0gdGhpcy5iO1xuXG5cdFx0cmV0dXJuIGFycmF5O1xuXG5cdH1cblxuXHRmcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGluZGV4ICkge1xuXG5cdFx0dGhpcy5yID0gYXR0cmlidXRlLmdldFgoIGluZGV4ICk7XG5cdFx0dGhpcy5nID0gYXR0cmlidXRlLmdldFkoIGluZGV4ICk7XG5cdFx0dGhpcy5iID0gYXR0cmlidXRlLmdldFooIGluZGV4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZ2V0SGV4KCk7XG5cblx0fVxuXG5cdCpbIFN5bWJvbC5pdGVyYXRvciBdKCkge1xuXG5cdFx0eWllbGQgdGhpcy5yO1xuXHRcdHlpZWxkIHRoaXMuZztcblx0XHR5aWVsZCB0aGlzLmI7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9jb2xvciA9IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCk7XG5cbkNvbG9yLk5BTUVTID0gX2NvbG9yS2V5d29yZHM7XG5cbmxldCBfbWF0ZXJpYWxJZCA9IDA7XG5cbmNsYXNzIE1hdGVyaWFsIGV4dGVuZHMgRXZlbnREaXNwYXRjaGVyIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfbWF0ZXJpYWxJZCArKyB9ICk7XG5cblx0XHR0aGlzLnV1aWQgPSBnZW5lcmF0ZVVVSUQoKTtcblxuXHRcdHRoaXMubmFtZSA9ICcnO1xuXHRcdHRoaXMudHlwZSA9ICdNYXRlcmlhbCc7XG5cblx0XHR0aGlzLmJsZW5kaW5nID0gTm9ybWFsQmxlbmRpbmc7XG5cdFx0dGhpcy5zaWRlID0gRnJvbnRTaWRlO1xuXHRcdHRoaXMudmVydGV4Q29sb3JzID0gZmFsc2U7XG5cblx0XHR0aGlzLm9wYWNpdHkgPSAxO1xuXHRcdHRoaXMudHJhbnNwYXJlbnQgPSBmYWxzZTtcblx0XHR0aGlzLmFscGhhSGFzaCA9IGZhbHNlO1xuXG5cdFx0dGhpcy5ibGVuZFNyYyA9IFNyY0FscGhhRmFjdG9yO1xuXHRcdHRoaXMuYmxlbmREc3QgPSBPbmVNaW51c1NyY0FscGhhRmFjdG9yO1xuXHRcdHRoaXMuYmxlbmRFcXVhdGlvbiA9IEFkZEVxdWF0aW9uO1xuXHRcdHRoaXMuYmxlbmRTcmNBbHBoYSA9IG51bGw7XG5cdFx0dGhpcy5ibGVuZERzdEFscGhhID0gbnVsbDtcblx0XHR0aGlzLmJsZW5kRXF1YXRpb25BbHBoYSA9IG51bGw7XG5cdFx0dGhpcy5ibGVuZENvbG9yID0gbmV3IENvbG9yKCAwLCAwLCAwICk7XG5cdFx0dGhpcy5ibGVuZEFscGhhID0gMDtcblxuXHRcdHRoaXMuZGVwdGhGdW5jID0gTGVzc0VxdWFsRGVwdGg7XG5cdFx0dGhpcy5kZXB0aFRlc3QgPSB0cnVlO1xuXHRcdHRoaXMuZGVwdGhXcml0ZSA9IHRydWU7XG5cblx0XHR0aGlzLnN0ZW5jaWxXcml0ZU1hc2sgPSAweGZmO1xuXHRcdHRoaXMuc3RlbmNpbEZ1bmMgPSBBbHdheXNTdGVuY2lsRnVuYztcblx0XHR0aGlzLnN0ZW5jaWxSZWYgPSAwO1xuXHRcdHRoaXMuc3RlbmNpbEZ1bmNNYXNrID0gMHhmZjtcblx0XHR0aGlzLnN0ZW5jaWxGYWlsID0gS2VlcFN0ZW5jaWxPcDtcblx0XHR0aGlzLnN0ZW5jaWxaRmFpbCA9IEtlZXBTdGVuY2lsT3A7XG5cdFx0dGhpcy5zdGVuY2lsWlBhc3MgPSBLZWVwU3RlbmNpbE9wO1xuXHRcdHRoaXMuc3RlbmNpbFdyaXRlID0gZmFsc2U7XG5cblx0XHR0aGlzLmNsaXBwaW5nUGxhbmVzID0gbnVsbDtcblx0XHR0aGlzLmNsaXBJbnRlcnNlY3Rpb24gPSBmYWxzZTtcblx0XHR0aGlzLmNsaXBTaGFkb3dzID0gZmFsc2U7XG5cblx0XHR0aGlzLnNoYWRvd1NpZGUgPSBudWxsO1xuXG5cdFx0dGhpcy5jb2xvcldyaXRlID0gdHJ1ZTtcblxuXHRcdHRoaXMucHJlY2lzaW9uID0gbnVsbDsgLy8gb3ZlcnJpZGUgdGhlIHJlbmRlcmVyJ3MgZGVmYXVsdCBwcmVjaXNpb24gZm9yIHRoaXMgbWF0ZXJpYWxcblxuXHRcdHRoaXMucG9seWdvbk9mZnNldCA9IGZhbHNlO1xuXHRcdHRoaXMucG9seWdvbk9mZnNldEZhY3RvciA9IDA7XG5cdFx0dGhpcy5wb2x5Z29uT2Zmc2V0VW5pdHMgPSAwO1xuXG5cdFx0dGhpcy5kaXRoZXJpbmcgPSBmYWxzZTtcblxuXHRcdHRoaXMuYWxwaGFUb0NvdmVyYWdlID0gZmFsc2U7XG5cdFx0dGhpcy5wcmVtdWx0aXBsaWVkQWxwaGEgPSBmYWxzZTtcblx0XHR0aGlzLmZvcmNlU2luZ2xlUGFzcyA9IGZhbHNlO1xuXG5cdFx0dGhpcy52aXNpYmxlID0gdHJ1ZTtcblxuXHRcdHRoaXMudG9uZU1hcHBlZCA9IHRydWU7XG5cblx0XHR0aGlzLnVzZXJEYXRhID0ge307XG5cblx0XHR0aGlzLnZlcnNpb24gPSAwO1xuXG5cdFx0dGhpcy5fYWxwaGFUZXN0ID0gMDtcblxuXHR9XG5cblx0Z2V0IGFscGhhVGVzdCgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9hbHBoYVRlc3Q7XG5cblx0fVxuXG5cdHNldCBhbHBoYVRlc3QoIHZhbHVlICkge1xuXG5cdFx0aWYgKCB0aGlzLl9hbHBoYVRlc3QgPiAwICE9PSB2YWx1ZSA+IDAgKSB7XG5cblx0XHRcdHRoaXMudmVyc2lvbiArKztcblxuXHRcdH1cblxuXHRcdHRoaXMuX2FscGhhVGVzdCA9IHZhbHVlO1xuXG5cdH1cblxuXHRvbkJlZm9yZUNvbXBpbGUoIC8qIHNoYWRlcm9iamVjdCwgcmVuZGVyZXIgKi8gKSB7fVxuXG5cdGN1c3RvbVByb2dyYW1DYWNoZUtleSgpIHtcblxuXHRcdHJldHVybiB0aGlzLm9uQmVmb3JlQ29tcGlsZS50b1N0cmluZygpO1xuXG5cdH1cblxuXHRzZXRWYWx1ZXMoIHZhbHVlcyApIHtcblxuXHRcdGlmICggdmFsdWVzID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHRmb3IgKCBjb25zdCBrZXkgaW4gdmFsdWVzICkge1xuXG5cdFx0XHRjb25zdCBuZXdWYWx1ZSA9IHZhbHVlc1sga2V5IF07XG5cblx0XHRcdGlmICggbmV3VmFsdWUgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oIGBUSFJFRS5NYXRlcmlhbDogcGFyYW1ldGVyICckeyBrZXkgfScgaGFzIHZhbHVlIG9mIHVuZGVmaW5lZC5gICk7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGN1cnJlbnRWYWx1ZSA9IHRoaXNbIGtleSBdO1xuXG5cdFx0XHRpZiAoIGN1cnJlbnRWYWx1ZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggYFRIUkVFLk1hdGVyaWFsOiAnJHsga2V5IH0nIGlzIG5vdCBhIHByb3BlcnR5IG9mIFRIUkVFLiR7IHRoaXMudHlwZSB9LmAgKTtcblx0XHRcdFx0Y29udGludWU7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBjdXJyZW50VmFsdWUgJiYgY3VycmVudFZhbHVlLmlzQ29sb3IgKSB7XG5cblx0XHRcdFx0Y3VycmVudFZhbHVlLnNldCggbmV3VmFsdWUgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggKCBjdXJyZW50VmFsdWUgJiYgY3VycmVudFZhbHVlLmlzVmVjdG9yMyApICYmICggbmV3VmFsdWUgJiYgbmV3VmFsdWUuaXNWZWN0b3IzICkgKSB7XG5cblx0XHRcdFx0Y3VycmVudFZhbHVlLmNvcHkoIG5ld1ZhbHVlICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0dGhpc1sga2V5IF0gPSBuZXdWYWx1ZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHR0b0pTT04oIG1ldGEgKSB7XG5cblx0XHRjb25zdCBpc1Jvb3RPYmplY3QgPSAoIG1ldGEgPT09IHVuZGVmaW5lZCB8fCB0eXBlb2YgbWV0YSA9PT0gJ3N0cmluZycgKTtcblxuXHRcdGlmICggaXNSb290T2JqZWN0ICkge1xuXG5cdFx0XHRtZXRhID0ge1xuXHRcdFx0XHR0ZXh0dXJlczoge30sXG5cdFx0XHRcdGltYWdlczoge31cblx0XHRcdH07XG5cblx0XHR9XG5cblx0XHRjb25zdCBkYXRhID0ge1xuXHRcdFx0bWV0YWRhdGE6IHtcblx0XHRcdFx0dmVyc2lvbjogNC42LFxuXHRcdFx0XHR0eXBlOiAnTWF0ZXJpYWwnLFxuXHRcdFx0XHRnZW5lcmF0b3I6ICdNYXRlcmlhbC50b0pTT04nXG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdC8vIHN0YW5kYXJkIE1hdGVyaWFsIHNlcmlhbGl6YXRpb25cblx0XHRkYXRhLnV1aWQgPSB0aGlzLnV1aWQ7XG5cdFx0ZGF0YS50eXBlID0gdGhpcy50eXBlO1xuXG5cdFx0aWYgKCB0aGlzLm5hbWUgIT09ICcnICkgZGF0YS5uYW1lID0gdGhpcy5uYW1lO1xuXG5cdFx0aWYgKCB0aGlzLmNvbG9yICYmIHRoaXMuY29sb3IuaXNDb2xvciApIGRhdGEuY29sb3IgPSB0aGlzLmNvbG9yLmdldEhleCgpO1xuXG5cdFx0aWYgKCB0aGlzLnJvdWdobmVzcyAhPT0gdW5kZWZpbmVkICkgZGF0YS5yb3VnaG5lc3MgPSB0aGlzLnJvdWdobmVzcztcblx0XHRpZiAoIHRoaXMubWV0YWxuZXNzICE9PSB1bmRlZmluZWQgKSBkYXRhLm1ldGFsbmVzcyA9IHRoaXMubWV0YWxuZXNzO1xuXG5cdFx0aWYgKCB0aGlzLnNoZWVuICE9PSB1bmRlZmluZWQgKSBkYXRhLnNoZWVuID0gdGhpcy5zaGVlbjtcblx0XHRpZiAoIHRoaXMuc2hlZW5Db2xvciAmJiB0aGlzLnNoZWVuQ29sb3IuaXNDb2xvciApIGRhdGEuc2hlZW5Db2xvciA9IHRoaXMuc2hlZW5Db2xvci5nZXRIZXgoKTtcblx0XHRpZiAoIHRoaXMuc2hlZW5Sb3VnaG5lc3MgIT09IHVuZGVmaW5lZCApIGRhdGEuc2hlZW5Sb3VnaG5lc3MgPSB0aGlzLnNoZWVuUm91Z2huZXNzO1xuXHRcdGlmICggdGhpcy5lbWlzc2l2ZSAmJiB0aGlzLmVtaXNzaXZlLmlzQ29sb3IgKSBkYXRhLmVtaXNzaXZlID0gdGhpcy5lbWlzc2l2ZS5nZXRIZXgoKTtcblx0XHRpZiAoIHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmVtaXNzaXZlSW50ZW5zaXR5ICE9PSAxICkgZGF0YS5lbWlzc2l2ZUludGVuc2l0eSA9IHRoaXMuZW1pc3NpdmVJbnRlbnNpdHk7XG5cblx0XHRpZiAoIHRoaXMuc3BlY3VsYXIgJiYgdGhpcy5zcGVjdWxhci5pc0NvbG9yICkgZGF0YS5zcGVjdWxhciA9IHRoaXMuc3BlY3VsYXIuZ2V0SGV4KCk7XG5cdFx0aWYgKCB0aGlzLnNwZWN1bGFySW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBkYXRhLnNwZWN1bGFySW50ZW5zaXR5ID0gdGhpcy5zcGVjdWxhckludGVuc2l0eTtcblx0XHRpZiAoIHRoaXMuc3BlY3VsYXJDb2xvciAmJiB0aGlzLnNwZWN1bGFyQ29sb3IuaXNDb2xvciApIGRhdGEuc3BlY3VsYXJDb2xvciA9IHRoaXMuc3BlY3VsYXJDb2xvci5nZXRIZXgoKTtcblx0XHRpZiAoIHRoaXMuc2hpbmluZXNzICE9PSB1bmRlZmluZWQgKSBkYXRhLnNoaW5pbmVzcyA9IHRoaXMuc2hpbmluZXNzO1xuXHRcdGlmICggdGhpcy5jbGVhcmNvYXQgIT09IHVuZGVmaW5lZCApIGRhdGEuY2xlYXJjb2F0ID0gdGhpcy5jbGVhcmNvYXQ7XG5cdFx0aWYgKCB0aGlzLmNsZWFyY29hdFJvdWdobmVzcyAhPT0gdW5kZWZpbmVkICkgZGF0YS5jbGVhcmNvYXRSb3VnaG5lc3MgPSB0aGlzLmNsZWFyY29hdFJvdWdobmVzcztcblxuXHRcdGlmICggdGhpcy5jbGVhcmNvYXRNYXAgJiYgdGhpcy5jbGVhcmNvYXRNYXAuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRkYXRhLmNsZWFyY29hdE1hcCA9IHRoaXMuY2xlYXJjb2F0TWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwICYmIHRoaXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0ZGF0YS5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgPSB0aGlzLmNsZWFyY29hdFJvdWdobmVzc01hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmNsZWFyY29hdE5vcm1hbE1hcCAmJiB0aGlzLmNsZWFyY29hdE5vcm1hbE1hcC5pc1RleHR1cmUgKSB7XG5cblx0XHRcdGRhdGEuY2xlYXJjb2F0Tm9ybWFsTWFwID0gdGhpcy5jbGVhcmNvYXROb3JtYWxNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblx0XHRcdGRhdGEuY2xlYXJjb2F0Tm9ybWFsU2NhbGUgPSB0aGlzLmNsZWFyY29hdE5vcm1hbFNjYWxlLnRvQXJyYXkoKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5kaXNwZXJzaW9uICE9PSB1bmRlZmluZWQgKSBkYXRhLmRpc3BlcnNpb24gPSB0aGlzLmRpc3BlcnNpb247XG5cblx0XHRpZiAoIHRoaXMuaXJpZGVzY2VuY2UgIT09IHVuZGVmaW5lZCApIGRhdGEuaXJpZGVzY2VuY2UgPSB0aGlzLmlyaWRlc2NlbmNlO1xuXHRcdGlmICggdGhpcy5pcmlkZXNjZW5jZUlPUiAhPT0gdW5kZWZpbmVkICkgZGF0YS5pcmlkZXNjZW5jZUlPUiA9IHRoaXMuaXJpZGVzY2VuY2VJT1I7XG5cdFx0aWYgKCB0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzUmFuZ2UgIT09IHVuZGVmaW5lZCApIGRhdGEuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZSA9IHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZTtcblxuXHRcdGlmICggdGhpcy5pcmlkZXNjZW5jZU1hcCAmJiB0aGlzLmlyaWRlc2NlbmNlTWFwLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0ZGF0YS5pcmlkZXNjZW5jZU1hcCA9IHRoaXMuaXJpZGVzY2VuY2VNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcCAmJiB0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0ZGF0YS5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcCA9IHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5hbmlzb3Ryb3B5ICE9PSB1bmRlZmluZWQgKSBkYXRhLmFuaXNvdHJvcHkgPSB0aGlzLmFuaXNvdHJvcHk7XG5cdFx0aWYgKCB0aGlzLmFuaXNvdHJvcHlSb3RhdGlvbiAhPT0gdW5kZWZpbmVkICkgZGF0YS5hbmlzb3Ryb3B5Um90YXRpb24gPSB0aGlzLmFuaXNvdHJvcHlSb3RhdGlvbjtcblxuXHRcdGlmICggdGhpcy5hbmlzb3Ryb3B5TWFwICYmIHRoaXMuYW5pc290cm9weU1hcC5pc1RleHR1cmUgKSB7XG5cblx0XHRcdGRhdGEuYW5pc290cm9weU1hcCA9IHRoaXMuYW5pc290cm9weU1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm1hcCAmJiB0aGlzLm1hcC5pc1RleHR1cmUgKSBkYXRhLm1hcCA9IHRoaXMubWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cdFx0aWYgKCB0aGlzLm1hdGNhcCAmJiB0aGlzLm1hdGNhcC5pc1RleHR1cmUgKSBkYXRhLm1hdGNhcCA9IHRoaXMubWF0Y2FwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cdFx0aWYgKCB0aGlzLmFscGhhTWFwICYmIHRoaXMuYWxwaGFNYXAuaXNUZXh0dXJlICkgZGF0YS5hbHBoYU1hcCA9IHRoaXMuYWxwaGFNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblxuXHRcdGlmICggdGhpcy5saWdodE1hcCAmJiB0aGlzLmxpZ2h0TWFwLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0ZGF0YS5saWdodE1hcCA9IHRoaXMubGlnaHRNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblx0XHRcdGRhdGEubGlnaHRNYXBJbnRlbnNpdHkgPSB0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5O1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmFvTWFwICYmIHRoaXMuYW9NYXAuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRkYXRhLmFvTWFwID0gdGhpcy5hb01hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXHRcdFx0ZGF0YS5hb01hcEludGVuc2l0eSA9IHRoaXMuYW9NYXBJbnRlbnNpdHk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuYnVtcE1hcCAmJiB0aGlzLmJ1bXBNYXAuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRkYXRhLmJ1bXBNYXAgPSB0aGlzLmJ1bXBNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblx0XHRcdGRhdGEuYnVtcFNjYWxlID0gdGhpcy5idW1wU2NhbGU7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsTWFwICYmIHRoaXMubm9ybWFsTWFwLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0ZGF0YS5ub3JtYWxNYXAgPSB0aGlzLm5vcm1hbE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXHRcdFx0ZGF0YS5ub3JtYWxNYXBUeXBlID0gdGhpcy5ub3JtYWxNYXBUeXBlO1xuXHRcdFx0ZGF0YS5ub3JtYWxTY2FsZSA9IHRoaXMubm9ybWFsU2NhbGUudG9BcnJheSgpO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmRpc3BsYWNlbWVudE1hcCAmJiB0aGlzLmRpc3BsYWNlbWVudE1hcC5pc1RleHR1cmUgKSB7XG5cblx0XHRcdGRhdGEuZGlzcGxhY2VtZW50TWFwID0gdGhpcy5kaXNwbGFjZW1lbnRNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblx0XHRcdGRhdGEuZGlzcGxhY2VtZW50U2NhbGUgPSB0aGlzLmRpc3BsYWNlbWVudFNjYWxlO1xuXHRcdFx0ZGF0YS5kaXNwbGFjZW1lbnRCaWFzID0gdGhpcy5kaXNwbGFjZW1lbnRCaWFzO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLnJvdWdobmVzc01hcCAmJiB0aGlzLnJvdWdobmVzc01hcC5pc1RleHR1cmUgKSBkYXRhLnJvdWdobmVzc01hcCA9IHRoaXMucm91Z2huZXNzTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cdFx0aWYgKCB0aGlzLm1ldGFsbmVzc01hcCAmJiB0aGlzLm1ldGFsbmVzc01hcC5pc1RleHR1cmUgKSBkYXRhLm1ldGFsbmVzc01hcCA9IHRoaXMubWV0YWxuZXNzTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cblx0XHRpZiAoIHRoaXMuZW1pc3NpdmVNYXAgJiYgdGhpcy5lbWlzc2l2ZU1hcC5pc1RleHR1cmUgKSBkYXRhLmVtaXNzaXZlTWFwID0gdGhpcy5lbWlzc2l2ZU1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXHRcdGlmICggdGhpcy5zcGVjdWxhck1hcCAmJiB0aGlzLnNwZWN1bGFyTWFwLmlzVGV4dHVyZSApIGRhdGEuc3BlY3VsYXJNYXAgPSB0aGlzLnNwZWN1bGFyTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cdFx0aWYgKCB0aGlzLnNwZWN1bGFySW50ZW5zaXR5TWFwICYmIHRoaXMuc3BlY3VsYXJJbnRlbnNpdHlNYXAuaXNUZXh0dXJlICkgZGF0YS5zcGVjdWxhckludGVuc2l0eU1hcCA9IHRoaXMuc3BlY3VsYXJJbnRlbnNpdHlNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblx0XHRpZiAoIHRoaXMuc3BlY3VsYXJDb2xvck1hcCAmJiB0aGlzLnNwZWN1bGFyQ29sb3JNYXAuaXNUZXh0dXJlICkgZGF0YS5zcGVjdWxhckNvbG9yTWFwID0gdGhpcy5zcGVjdWxhckNvbG9yTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cblx0XHRpZiAoIHRoaXMuZW52TWFwICYmIHRoaXMuZW52TWFwLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0ZGF0YS5lbnZNYXAgPSB0aGlzLmVudk1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXG5cdFx0XHRpZiAoIHRoaXMuY29tYmluZSAhPT0gdW5kZWZpbmVkICkgZGF0YS5jb21iaW5lID0gdGhpcy5jb21iaW5lO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmVudk1hcFJvdGF0aW9uICE9PSB1bmRlZmluZWQgKSBkYXRhLmVudk1hcFJvdGF0aW9uID0gdGhpcy5lbnZNYXBSb3RhdGlvbi50b0FycmF5KCk7XG5cdFx0aWYgKCB0aGlzLmVudk1hcEludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgZGF0YS5lbnZNYXBJbnRlbnNpdHkgPSB0aGlzLmVudk1hcEludGVuc2l0eTtcblx0XHRpZiAoIHRoaXMucmVmbGVjdGl2aXR5ICE9PSB1bmRlZmluZWQgKSBkYXRhLnJlZmxlY3Rpdml0eSA9IHRoaXMucmVmbGVjdGl2aXR5O1xuXHRcdGlmICggdGhpcy5yZWZyYWN0aW9uUmF0aW8gIT09IHVuZGVmaW5lZCApIGRhdGEucmVmcmFjdGlvblJhdGlvID0gdGhpcy5yZWZyYWN0aW9uUmF0aW87XG5cblx0XHRpZiAoIHRoaXMuZ3JhZGllbnRNYXAgJiYgdGhpcy5ncmFkaWVudE1hcC5pc1RleHR1cmUgKSB7XG5cblx0XHRcdGRhdGEuZ3JhZGllbnRNYXAgPSB0aGlzLmdyYWRpZW50TWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMudHJhbnNtaXNzaW9uICE9PSB1bmRlZmluZWQgKSBkYXRhLnRyYW5zbWlzc2lvbiA9IHRoaXMudHJhbnNtaXNzaW9uO1xuXHRcdGlmICggdGhpcy50cmFuc21pc3Npb25NYXAgJiYgdGhpcy50cmFuc21pc3Npb25NYXAuaXNUZXh0dXJlICkgZGF0YS50cmFuc21pc3Npb25NYXAgPSB0aGlzLnRyYW5zbWlzc2lvbk1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXHRcdGlmICggdGhpcy50aGlja25lc3MgIT09IHVuZGVmaW5lZCApIGRhdGEudGhpY2tuZXNzID0gdGhpcy50aGlja25lc3M7XG5cdFx0aWYgKCB0aGlzLnRoaWNrbmVzc01hcCAmJiB0aGlzLnRoaWNrbmVzc01hcC5pc1RleHR1cmUgKSBkYXRhLnRoaWNrbmVzc01hcCA9IHRoaXMudGhpY2tuZXNzTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cdFx0aWYgKCB0aGlzLmF0dGVudWF0aW9uRGlzdGFuY2UgIT09IHVuZGVmaW5lZCAmJiB0aGlzLmF0dGVudWF0aW9uRGlzdGFuY2UgIT09IEluZmluaXR5ICkgZGF0YS5hdHRlbnVhdGlvbkRpc3RhbmNlID0gdGhpcy5hdHRlbnVhdGlvbkRpc3RhbmNlO1xuXHRcdGlmICggdGhpcy5hdHRlbnVhdGlvbkNvbG9yICE9PSB1bmRlZmluZWQgKSBkYXRhLmF0dGVudWF0aW9uQ29sb3IgPSB0aGlzLmF0dGVudWF0aW9uQ29sb3IuZ2V0SGV4KCk7XG5cblx0XHRpZiAoIHRoaXMuc2l6ZSAhPT0gdW5kZWZpbmVkICkgZGF0YS5zaXplID0gdGhpcy5zaXplO1xuXHRcdGlmICggdGhpcy5zaGFkb3dTaWRlICE9PSBudWxsICkgZGF0YS5zaGFkb3dTaWRlID0gdGhpcy5zaGFkb3dTaWRlO1xuXHRcdGlmICggdGhpcy5zaXplQXR0ZW51YXRpb24gIT09IHVuZGVmaW5lZCApIGRhdGEuc2l6ZUF0dGVudWF0aW9uID0gdGhpcy5zaXplQXR0ZW51YXRpb247XG5cblx0XHRpZiAoIHRoaXMuYmxlbmRpbmcgIT09IE5vcm1hbEJsZW5kaW5nICkgZGF0YS5ibGVuZGluZyA9IHRoaXMuYmxlbmRpbmc7XG5cdFx0aWYgKCB0aGlzLnNpZGUgIT09IEZyb250U2lkZSApIGRhdGEuc2lkZSA9IHRoaXMuc2lkZTtcblx0XHRpZiAoIHRoaXMudmVydGV4Q29sb3JzID09PSB0cnVlICkgZGF0YS52ZXJ0ZXhDb2xvcnMgPSB0cnVlO1xuXG5cdFx0aWYgKCB0aGlzLm9wYWNpdHkgPCAxICkgZGF0YS5vcGFjaXR5ID0gdGhpcy5vcGFjaXR5O1xuXHRcdGlmICggdGhpcy50cmFuc3BhcmVudCA9PT0gdHJ1ZSApIGRhdGEudHJhbnNwYXJlbnQgPSB0cnVlO1xuXG5cdFx0aWYgKCB0aGlzLmJsZW5kU3JjICE9PSBTcmNBbHBoYUZhY3RvciApIGRhdGEuYmxlbmRTcmMgPSB0aGlzLmJsZW5kU3JjO1xuXHRcdGlmICggdGhpcy5ibGVuZERzdCAhPT0gT25lTWludXNTcmNBbHBoYUZhY3RvciApIGRhdGEuYmxlbmREc3QgPSB0aGlzLmJsZW5kRHN0O1xuXHRcdGlmICggdGhpcy5ibGVuZEVxdWF0aW9uICE9PSBBZGRFcXVhdGlvbiApIGRhdGEuYmxlbmRFcXVhdGlvbiA9IHRoaXMuYmxlbmRFcXVhdGlvbjtcblx0XHRpZiAoIHRoaXMuYmxlbmRTcmNBbHBoYSAhPT0gbnVsbCApIGRhdGEuYmxlbmRTcmNBbHBoYSA9IHRoaXMuYmxlbmRTcmNBbHBoYTtcblx0XHRpZiAoIHRoaXMuYmxlbmREc3RBbHBoYSAhPT0gbnVsbCApIGRhdGEuYmxlbmREc3RBbHBoYSA9IHRoaXMuYmxlbmREc3RBbHBoYTtcblx0XHRpZiAoIHRoaXMuYmxlbmRFcXVhdGlvbkFscGhhICE9PSBudWxsICkgZGF0YS5ibGVuZEVxdWF0aW9uQWxwaGEgPSB0aGlzLmJsZW5kRXF1YXRpb25BbHBoYTtcblx0XHRpZiAoIHRoaXMuYmxlbmRDb2xvciAmJiB0aGlzLmJsZW5kQ29sb3IuaXNDb2xvciApIGRhdGEuYmxlbmRDb2xvciA9IHRoaXMuYmxlbmRDb2xvci5nZXRIZXgoKTtcblx0XHRpZiAoIHRoaXMuYmxlbmRBbHBoYSAhPT0gMCApIGRhdGEuYmxlbmRBbHBoYSA9IHRoaXMuYmxlbmRBbHBoYTtcblxuXHRcdGlmICggdGhpcy5kZXB0aEZ1bmMgIT09IExlc3NFcXVhbERlcHRoICkgZGF0YS5kZXB0aEZ1bmMgPSB0aGlzLmRlcHRoRnVuYztcblx0XHRpZiAoIHRoaXMuZGVwdGhUZXN0ID09PSBmYWxzZSApIGRhdGEuZGVwdGhUZXN0ID0gdGhpcy5kZXB0aFRlc3Q7XG5cdFx0aWYgKCB0aGlzLmRlcHRoV3JpdGUgPT09IGZhbHNlICkgZGF0YS5kZXB0aFdyaXRlID0gdGhpcy5kZXB0aFdyaXRlO1xuXHRcdGlmICggdGhpcy5jb2xvcldyaXRlID09PSBmYWxzZSApIGRhdGEuY29sb3JXcml0ZSA9IHRoaXMuY29sb3JXcml0ZTtcblxuXHRcdGlmICggdGhpcy5zdGVuY2lsV3JpdGVNYXNrICE9PSAweGZmICkgZGF0YS5zdGVuY2lsV3JpdGVNYXNrID0gdGhpcy5zdGVuY2lsV3JpdGVNYXNrO1xuXHRcdGlmICggdGhpcy5zdGVuY2lsRnVuYyAhPT0gQWx3YXlzU3RlbmNpbEZ1bmMgKSBkYXRhLnN0ZW5jaWxGdW5jID0gdGhpcy5zdGVuY2lsRnVuYztcblx0XHRpZiAoIHRoaXMuc3RlbmNpbFJlZiAhPT0gMCApIGRhdGEuc3RlbmNpbFJlZiA9IHRoaXMuc3RlbmNpbFJlZjtcblx0XHRpZiAoIHRoaXMuc3RlbmNpbEZ1bmNNYXNrICE9PSAweGZmICkgZGF0YS5zdGVuY2lsRnVuY01hc2sgPSB0aGlzLnN0ZW5jaWxGdW5jTWFzaztcblx0XHRpZiAoIHRoaXMuc3RlbmNpbEZhaWwgIT09IEtlZXBTdGVuY2lsT3AgKSBkYXRhLnN0ZW5jaWxGYWlsID0gdGhpcy5zdGVuY2lsRmFpbDtcblx0XHRpZiAoIHRoaXMuc3RlbmNpbFpGYWlsICE9PSBLZWVwU3RlbmNpbE9wICkgZGF0YS5zdGVuY2lsWkZhaWwgPSB0aGlzLnN0ZW5jaWxaRmFpbDtcblx0XHRpZiAoIHRoaXMuc3RlbmNpbFpQYXNzICE9PSBLZWVwU3RlbmNpbE9wICkgZGF0YS5zdGVuY2lsWlBhc3MgPSB0aGlzLnN0ZW5jaWxaUGFzcztcblx0XHRpZiAoIHRoaXMuc3RlbmNpbFdyaXRlID09PSB0cnVlICkgZGF0YS5zdGVuY2lsV3JpdGUgPSB0aGlzLnN0ZW5jaWxXcml0ZTtcblxuXHRcdC8vIHJvdGF0aW9uIChTcHJpdGVNYXRlcmlhbClcblx0XHRpZiAoIHRoaXMucm90YXRpb24gIT09IHVuZGVmaW5lZCAmJiB0aGlzLnJvdGF0aW9uICE9PSAwICkgZGF0YS5yb3RhdGlvbiA9IHRoaXMucm90YXRpb247XG5cblx0XHRpZiAoIHRoaXMucG9seWdvbk9mZnNldCA9PT0gdHJ1ZSApIGRhdGEucG9seWdvbk9mZnNldCA9IHRydWU7XG5cdFx0aWYgKCB0aGlzLnBvbHlnb25PZmZzZXRGYWN0b3IgIT09IDAgKSBkYXRhLnBvbHlnb25PZmZzZXRGYWN0b3IgPSB0aGlzLnBvbHlnb25PZmZzZXRGYWN0b3I7XG5cdFx0aWYgKCB0aGlzLnBvbHlnb25PZmZzZXRVbml0cyAhPT0gMCApIGRhdGEucG9seWdvbk9mZnNldFVuaXRzID0gdGhpcy5wb2x5Z29uT2Zmc2V0VW5pdHM7XG5cblx0XHRpZiAoIHRoaXMubGluZXdpZHRoICE9PSB1bmRlZmluZWQgJiYgdGhpcy5saW5ld2lkdGggIT09IDEgKSBkYXRhLmxpbmV3aWR0aCA9IHRoaXMubGluZXdpZHRoO1xuXHRcdGlmICggdGhpcy5kYXNoU2l6ZSAhPT0gdW5kZWZpbmVkICkgZGF0YS5kYXNoU2l6ZSA9IHRoaXMuZGFzaFNpemU7XG5cdFx0aWYgKCB0aGlzLmdhcFNpemUgIT09IHVuZGVmaW5lZCApIGRhdGEuZ2FwU2l6ZSA9IHRoaXMuZ2FwU2l6ZTtcblx0XHRpZiAoIHRoaXMuc2NhbGUgIT09IHVuZGVmaW5lZCApIGRhdGEuc2NhbGUgPSB0aGlzLnNjYWxlO1xuXG5cdFx0aWYgKCB0aGlzLmRpdGhlcmluZyA9PT0gdHJ1ZSApIGRhdGEuZGl0aGVyaW5nID0gdHJ1ZTtcblxuXHRcdGlmICggdGhpcy5hbHBoYVRlc3QgPiAwICkgZGF0YS5hbHBoYVRlc3QgPSB0aGlzLmFscGhhVGVzdDtcblx0XHRpZiAoIHRoaXMuYWxwaGFIYXNoID09PSB0cnVlICkgZGF0YS5hbHBoYUhhc2ggPSB0cnVlO1xuXHRcdGlmICggdGhpcy5hbHBoYVRvQ292ZXJhZ2UgPT09IHRydWUgKSBkYXRhLmFscGhhVG9Db3ZlcmFnZSA9IHRydWU7XG5cdFx0aWYgKCB0aGlzLnByZW11bHRpcGxpZWRBbHBoYSA9PT0gdHJ1ZSApIGRhdGEucHJlbXVsdGlwbGllZEFscGhhID0gdHJ1ZTtcblx0XHRpZiAoIHRoaXMuZm9yY2VTaW5nbGVQYXNzID09PSB0cnVlICkgZGF0YS5mb3JjZVNpbmdsZVBhc3MgPSB0cnVlO1xuXG5cdFx0aWYgKCB0aGlzLndpcmVmcmFtZSA9PT0gdHJ1ZSApIGRhdGEud2lyZWZyYW1lID0gdHJ1ZTtcblx0XHRpZiAoIHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID4gMSApIGRhdGEud2lyZWZyYW1lTGluZXdpZHRoID0gdGhpcy53aXJlZnJhbWVMaW5ld2lkdGg7XG5cdFx0aWYgKCB0aGlzLndpcmVmcmFtZUxpbmVjYXAgIT09ICdyb3VuZCcgKSBkYXRhLndpcmVmcmFtZUxpbmVjYXAgPSB0aGlzLndpcmVmcmFtZUxpbmVjYXA7XG5cdFx0aWYgKCB0aGlzLndpcmVmcmFtZUxpbmVqb2luICE9PSAncm91bmQnICkgZGF0YS53aXJlZnJhbWVMaW5lam9pbiA9IHRoaXMud2lyZWZyYW1lTGluZWpvaW47XG5cblx0XHRpZiAoIHRoaXMuZmxhdFNoYWRpbmcgPT09IHRydWUgKSBkYXRhLmZsYXRTaGFkaW5nID0gdHJ1ZTtcblxuXHRcdGlmICggdGhpcy52aXNpYmxlID09PSBmYWxzZSApIGRhdGEudmlzaWJsZSA9IGZhbHNlO1xuXG5cdFx0aWYgKCB0aGlzLnRvbmVNYXBwZWQgPT09IGZhbHNlICkgZGF0YS50b25lTWFwcGVkID0gZmFsc2U7XG5cblx0XHRpZiAoIHRoaXMuZm9nID09PSBmYWxzZSApIGRhdGEuZm9nID0gZmFsc2U7XG5cblx0XHRpZiAoIE9iamVjdC5rZXlzKCB0aGlzLnVzZXJEYXRhICkubGVuZ3RoID4gMCApIGRhdGEudXNlckRhdGEgPSB0aGlzLnVzZXJEYXRhO1xuXG5cdFx0Ly8gVE9ETzogQ29waWVkIGZyb20gT2JqZWN0M0QudG9KU09OXG5cblx0XHRmdW5jdGlvbiBleHRyYWN0RnJvbUNhY2hlKCBjYWNoZSApIHtcblxuXHRcdFx0Y29uc3QgdmFsdWVzID0gW107XG5cblx0XHRcdGZvciAoIGNvbnN0IGtleSBpbiBjYWNoZSApIHtcblxuXHRcdFx0XHRjb25zdCBkYXRhID0gY2FjaGVbIGtleSBdO1xuXHRcdFx0XHRkZWxldGUgZGF0YS5tZXRhZGF0YTtcblx0XHRcdFx0dmFsdWVzLnB1c2goIGRhdGEgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gdmFsdWVzO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBpc1Jvb3RPYmplY3QgKSB7XG5cblx0XHRcdGNvbnN0IHRleHR1cmVzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS50ZXh0dXJlcyApO1xuXHRcdFx0Y29uc3QgaW1hZ2VzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS5pbWFnZXMgKTtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlcy5sZW5ndGggPiAwICkgZGF0YS50ZXh0dXJlcyA9IHRleHR1cmVzO1xuXHRcdFx0aWYgKCBpbWFnZXMubGVuZ3RoID4gMCApIGRhdGEuaW1hZ2VzID0gaW1hZ2VzO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHR0aGlzLm5hbWUgPSBzb3VyY2UubmFtZTtcblxuXHRcdHRoaXMuYmxlbmRpbmcgPSBzb3VyY2UuYmxlbmRpbmc7XG5cdFx0dGhpcy5zaWRlID0gc291cmNlLnNpZGU7XG5cdFx0dGhpcy52ZXJ0ZXhDb2xvcnMgPSBzb3VyY2UudmVydGV4Q29sb3JzO1xuXG5cdFx0dGhpcy5vcGFjaXR5ID0gc291cmNlLm9wYWNpdHk7XG5cdFx0dGhpcy50cmFuc3BhcmVudCA9IHNvdXJjZS50cmFuc3BhcmVudDtcblxuXHRcdHRoaXMuYmxlbmRTcmMgPSBzb3VyY2UuYmxlbmRTcmM7XG5cdFx0dGhpcy5ibGVuZERzdCA9IHNvdXJjZS5ibGVuZERzdDtcblx0XHR0aGlzLmJsZW5kRXF1YXRpb24gPSBzb3VyY2UuYmxlbmRFcXVhdGlvbjtcblx0XHR0aGlzLmJsZW5kU3JjQWxwaGEgPSBzb3VyY2UuYmxlbmRTcmNBbHBoYTtcblx0XHR0aGlzLmJsZW5kRHN0QWxwaGEgPSBzb3VyY2UuYmxlbmREc3RBbHBoYTtcblx0XHR0aGlzLmJsZW5kRXF1YXRpb25BbHBoYSA9IHNvdXJjZS5ibGVuZEVxdWF0aW9uQWxwaGE7XG5cdFx0dGhpcy5ibGVuZENvbG9yLmNvcHkoIHNvdXJjZS5ibGVuZENvbG9yICk7XG5cdFx0dGhpcy5ibGVuZEFscGhhID0gc291cmNlLmJsZW5kQWxwaGE7XG5cblx0XHR0aGlzLmRlcHRoRnVuYyA9IHNvdXJjZS5kZXB0aEZ1bmM7XG5cdFx0dGhpcy5kZXB0aFRlc3QgPSBzb3VyY2UuZGVwdGhUZXN0O1xuXHRcdHRoaXMuZGVwdGhXcml0ZSA9IHNvdXJjZS5kZXB0aFdyaXRlO1xuXG5cdFx0dGhpcy5zdGVuY2lsV3JpdGVNYXNrID0gc291cmNlLnN0ZW5jaWxXcml0ZU1hc2s7XG5cdFx0dGhpcy5zdGVuY2lsRnVuYyA9IHNvdXJjZS5zdGVuY2lsRnVuYztcblx0XHR0aGlzLnN0ZW5jaWxSZWYgPSBzb3VyY2Uuc3RlbmNpbFJlZjtcblx0XHR0aGlzLnN0ZW5jaWxGdW5jTWFzayA9IHNvdXJjZS5zdGVuY2lsRnVuY01hc2s7XG5cdFx0dGhpcy5zdGVuY2lsRmFpbCA9IHNvdXJjZS5zdGVuY2lsRmFpbDtcblx0XHR0aGlzLnN0ZW5jaWxaRmFpbCA9IHNvdXJjZS5zdGVuY2lsWkZhaWw7XG5cdFx0dGhpcy5zdGVuY2lsWlBhc3MgPSBzb3VyY2Uuc3RlbmNpbFpQYXNzO1xuXHRcdHRoaXMuc3RlbmNpbFdyaXRlID0gc291cmNlLnN0ZW5jaWxXcml0ZTtcblxuXHRcdGNvbnN0IHNyY1BsYW5lcyA9IHNvdXJjZS5jbGlwcGluZ1BsYW5lcztcblx0XHRsZXQgZHN0UGxhbmVzID0gbnVsbDtcblxuXHRcdGlmICggc3JjUGxhbmVzICE9PSBudWxsICkge1xuXG5cdFx0XHRjb25zdCBuID0gc3JjUGxhbmVzLmxlbmd0aDtcblx0XHRcdGRzdFBsYW5lcyA9IG5ldyBBcnJheSggbiApO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdFx0ZHN0UGxhbmVzWyBpIF0gPSBzcmNQbGFuZXNbIGkgXS5jbG9uZSgpO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHR0aGlzLmNsaXBwaW5nUGxhbmVzID0gZHN0UGxhbmVzO1xuXHRcdHRoaXMuY2xpcEludGVyc2VjdGlvbiA9IHNvdXJjZS5jbGlwSW50ZXJzZWN0aW9uO1xuXHRcdHRoaXMuY2xpcFNoYWRvd3MgPSBzb3VyY2UuY2xpcFNoYWRvd3M7XG5cblx0XHR0aGlzLnNoYWRvd1NpZGUgPSBzb3VyY2Uuc2hhZG93U2lkZTtcblxuXHRcdHRoaXMuY29sb3JXcml0ZSA9IHNvdXJjZS5jb2xvcldyaXRlO1xuXG5cdFx0dGhpcy5wcmVjaXNpb24gPSBzb3VyY2UucHJlY2lzaW9uO1xuXG5cdFx0dGhpcy5wb2x5Z29uT2Zmc2V0ID0gc291cmNlLnBvbHlnb25PZmZzZXQ7XG5cdFx0dGhpcy5wb2x5Z29uT2Zmc2V0RmFjdG9yID0gc291cmNlLnBvbHlnb25PZmZzZXRGYWN0b3I7XG5cdFx0dGhpcy5wb2x5Z29uT2Zmc2V0VW5pdHMgPSBzb3VyY2UucG9seWdvbk9mZnNldFVuaXRzO1xuXG5cdFx0dGhpcy5kaXRoZXJpbmcgPSBzb3VyY2UuZGl0aGVyaW5nO1xuXG5cdFx0dGhpcy5hbHBoYVRlc3QgPSBzb3VyY2UuYWxwaGFUZXN0O1xuXHRcdHRoaXMuYWxwaGFIYXNoID0gc291cmNlLmFscGhhSGFzaDtcblx0XHR0aGlzLmFscGhhVG9Db3ZlcmFnZSA9IHNvdXJjZS5hbHBoYVRvQ292ZXJhZ2U7XG5cdFx0dGhpcy5wcmVtdWx0aXBsaWVkQWxwaGEgPSBzb3VyY2UucHJlbXVsdGlwbGllZEFscGhhO1xuXHRcdHRoaXMuZm9yY2VTaW5nbGVQYXNzID0gc291cmNlLmZvcmNlU2luZ2xlUGFzcztcblxuXHRcdHRoaXMudmlzaWJsZSA9IHNvdXJjZS52aXNpYmxlO1xuXG5cdFx0dGhpcy50b25lTWFwcGVkID0gc291cmNlLnRvbmVNYXBwZWQ7XG5cblx0XHR0aGlzLnVzZXJEYXRhID0gSlNPTi5wYXJzZSggSlNPTi5zdHJpbmdpZnkoIHNvdXJjZS51c2VyRGF0YSApICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzcG9zZScgfSApO1xuXG5cdH1cblxuXHRzZXQgbmVlZHNVcGRhdGUoIHZhbHVlICkge1xuXG5cdFx0aWYgKCB2YWx1ZSA9PT0gdHJ1ZSApIHRoaXMudmVyc2lvbiArKztcblxuXHR9XG5cblx0b25CdWlsZCggLyogc2hhZGVyb2JqZWN0LCByZW5kZXJlciAqLyApIHtcblxuXHRcdGNvbnNvbGUud2FybiggJ01hdGVyaWFsOiBvbkJ1aWxkKCkgaGFzIGJlZW4gcmVtb3ZlZC4nICk7IC8vIEBkZXByZWNhdGVkLCByMTY2XG5cblx0fVxuXG5cdG9uQmVmb3JlUmVuZGVyKCAvKiByZW5kZXJlciwgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG9iamVjdCwgZ3JvdXAgKi8gKSB7XG5cblx0XHRjb25zb2xlLndhcm4oICdNYXRlcmlhbDogb25CZWZvcmVSZW5kZXIoKSBoYXMgYmVlbiByZW1vdmVkLicgKTsgLy8gQGRlcHJlY2F0ZWQsIHIxNjZcblxuXHR9XG5cblxufVxuXG5jbGFzcyBNZXNoQmFzaWNNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTWVzaEJhc2ljTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ01lc2hCYXNpY01hdGVyaWFsJztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7IC8vIGVtaXNzaXZlXG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmxpZ2h0TWFwID0gbnVsbDtcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gMS4wO1xuXG5cdFx0dGhpcy5hb01hcCA9IG51bGw7XG5cdFx0dGhpcy5hb01hcEludGVuc2l0eSA9IDEuMDtcblxuXHRcdHRoaXMuc3BlY3VsYXJNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5hbHBoYU1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmVudk1hcCA9IG51bGw7XG5cdFx0dGhpcy5lbnZNYXBSb3RhdGlvbiA9IG5ldyBFdWxlcigpO1xuXHRcdHRoaXMuY29tYmluZSA9IE11bHRpcGx5T3BlcmF0aW9uO1xuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gMTtcblx0XHR0aGlzLnJlZnJhY3Rpb25SYXRpbyA9IDAuOTg7XG5cblx0XHR0aGlzLndpcmVmcmFtZSA9IGZhbHNlO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gMTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSAncm91bmQnO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSAncm91bmQnO1xuXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xuXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLmNvbG9yLmNvcHkoIHNvdXJjZS5jb2xvciApO1xuXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xuXG5cdFx0dGhpcy5saWdodE1hcCA9IHNvdXJjZS5saWdodE1hcDtcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gc291cmNlLmxpZ2h0TWFwSW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5hb01hcCA9IHNvdXJjZS5hb01hcDtcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gc291cmNlLmFvTWFwSW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5zcGVjdWxhck1hcCA9IHNvdXJjZS5zcGVjdWxhck1hcDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBzb3VyY2UuYWxwaGFNYXA7XG5cblx0XHR0aGlzLmVudk1hcCA9IHNvdXJjZS5lbnZNYXA7XG5cdFx0dGhpcy5lbnZNYXBSb3RhdGlvbi5jb3B5KCBzb3VyY2UuZW52TWFwUm90YXRpb24gKTtcblx0XHR0aGlzLmNvbWJpbmUgPSBzb3VyY2UuY29tYmluZTtcblx0XHR0aGlzLnJlZmxlY3Rpdml0eSA9IHNvdXJjZS5yZWZsZWN0aXZpdHk7XG5cdFx0dGhpcy5yZWZyYWN0aW9uUmF0aW8gPSBzb3VyY2UucmVmcmFjdGlvblJhdGlvO1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBzb3VyY2Uud2lyZWZyYW1lO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSBzb3VyY2Uud2lyZWZyYW1lTGluZWNhcDtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVqb2luID0gc291cmNlLndpcmVmcmFtZUxpbmVqb2luO1xuXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbi8vIEZhc3QgSGFsZiBGbG9hdCBDb252ZXJzaW9ucywgaHR0cDovL3d3dy5mb3gtdG9vbGtpdC5vcmcvZnRwL2Zhc3RoYWxmZmxvYXRjb252ZXJzaW9uLnBkZlxuXG5jb25zdCBfdGFibGVzID0gLypAX19QVVJFX18qLyBfZ2VuZXJhdGVUYWJsZXMoKTtcblxuZnVuY3Rpb24gX2dlbmVyYXRlVGFibGVzKCkge1xuXG5cdC8vIGZsb2F0MzIgdG8gZmxvYXQxNiBoZWxwZXJzXG5cblx0Y29uc3QgYnVmZmVyID0gbmV3IEFycmF5QnVmZmVyKCA0ICk7XG5cdGNvbnN0IGZsb2F0VmlldyA9IG5ldyBGbG9hdDMyQXJyYXkoIGJ1ZmZlciApO1xuXHRjb25zdCB1aW50MzJWaWV3ID0gbmV3IFVpbnQzMkFycmF5KCBidWZmZXIgKTtcblxuXHRjb25zdCBiYXNlVGFibGUgPSBuZXcgVWludDMyQXJyYXkoIDUxMiApO1xuXHRjb25zdCBzaGlmdFRhYmxlID0gbmV3IFVpbnQzMkFycmF5KCA1MTIgKTtcblxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCAyNTY7ICsrIGkgKSB7XG5cblx0XHRjb25zdCBlID0gaSAtIDEyNztcblxuXHRcdC8vIHZlcnkgc21hbGwgbnVtYmVyICgwLCAtMClcblxuXHRcdGlmICggZSA8IC0gMjcgKSB7XG5cblx0XHRcdGJhc2VUYWJsZVsgaSBdID0gMHgwMDAwO1xuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9IDB4ODAwMDtcblx0XHRcdHNoaWZ0VGFibGVbIGkgXSA9IDI0O1xuXHRcdFx0c2hpZnRUYWJsZVsgaSB8IDB4MTAwIF0gPSAyNDtcblxuXHRcdFx0Ly8gc21hbGwgbnVtYmVyIChkZW5vcm0pXG5cblx0XHR9IGVsc2UgaWYgKCBlIDwgLSAxNCApIHtcblxuXHRcdFx0YmFzZVRhYmxlWyBpIF0gPSAweDA0MDAgPj4gKCAtIGUgLSAxNCApO1xuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9ICggMHgwNDAwID4+ICggLSBlIC0gMTQgKSApIHwgMHg4MDAwO1xuXHRcdFx0c2hpZnRUYWJsZVsgaSBdID0gLSBlIC0gMTtcblx0XHRcdHNoaWZ0VGFibGVbIGkgfCAweDEwMCBdID0gLSBlIC0gMTtcblxuXHRcdFx0Ly8gbm9ybWFsIG51bWJlclxuXG5cdFx0fSBlbHNlIGlmICggZSA8PSAxNSApIHtcblxuXHRcdFx0YmFzZVRhYmxlWyBpIF0gPSAoIGUgKyAxNSApIDw8IDEwO1xuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9ICggKCBlICsgMTUgKSA8PCAxMCApIHwgMHg4MDAwO1xuXHRcdFx0c2hpZnRUYWJsZVsgaSBdID0gMTM7XG5cdFx0XHRzaGlmdFRhYmxlWyBpIHwgMHgxMDAgXSA9IDEzO1xuXG5cdFx0XHQvLyBsYXJnZSBudW1iZXIgKEluZmluaXR5LCAtSW5maW5pdHkpXG5cblx0XHR9IGVsc2UgaWYgKCBlIDwgMTI4ICkge1xuXG5cdFx0XHRiYXNlVGFibGVbIGkgXSA9IDB4N2MwMDtcblx0XHRcdGJhc2VUYWJsZVsgaSB8IDB4MTAwIF0gPSAweGZjMDA7XG5cdFx0XHRzaGlmdFRhYmxlWyBpIF0gPSAyNDtcblx0XHRcdHNoaWZ0VGFibGVbIGkgfCAweDEwMCBdID0gMjQ7XG5cblx0XHRcdC8vIHN0YXkgKE5hTiwgSW5maW5pdHksIC1JbmZpbml0eSlcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGJhc2VUYWJsZVsgaSBdID0gMHg3YzAwO1xuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9IDB4ZmMwMDtcblx0XHRcdHNoaWZ0VGFibGVbIGkgXSA9IDEzO1xuXHRcdFx0c2hpZnRUYWJsZVsgaSB8IDB4MTAwIF0gPSAxMztcblxuXHRcdH1cblxuXHR9XG5cblx0Ly8gZmxvYXQxNiB0byBmbG9hdDMyIGhlbHBlcnNcblxuXHRjb25zdCBtYW50aXNzYVRhYmxlID0gbmV3IFVpbnQzMkFycmF5KCAyMDQ4ICk7XG5cdGNvbnN0IGV4cG9uZW50VGFibGUgPSBuZXcgVWludDMyQXJyYXkoIDY0ICk7XG5cdGNvbnN0IG9mZnNldFRhYmxlID0gbmV3IFVpbnQzMkFycmF5KCA2NCApO1xuXG5cdGZvciAoIGxldCBpID0gMTsgaSA8IDEwMjQ7ICsrIGkgKSB7XG5cblx0XHRsZXQgbSA9IGkgPDwgMTM7IC8vIHplcm8gcGFkIG1hbnRpc3NhIGJpdHNcblx0XHRsZXQgZSA9IDA7IC8vIHplcm8gZXhwb25lbnRcblxuXHRcdC8vIG5vcm1hbGl6ZWRcblx0XHR3aGlsZSAoICggbSAmIDB4MDA4MDAwMDAgKSA9PT0gMCApIHtcblxuXHRcdFx0bSA8PD0gMTtcblx0XHRcdGUgLT0gMHgwMDgwMDAwMDsgLy8gZGVjcmVtZW50IGV4cG9uZW50XG5cblx0XHR9XG5cblx0XHRtICY9IH4gMHgwMDgwMDAwMDsgLy8gY2xlYXIgbGVhZGluZyAxIGJpdFxuXHRcdGUgKz0gMHgzODgwMDAwMDsgLy8gYWRqdXN0IGJpYXNcblxuXHRcdG1hbnRpc3NhVGFibGVbIGkgXSA9IG0gfCBlO1xuXG5cdH1cblxuXHRmb3IgKCBsZXQgaSA9IDEwMjQ7IGkgPCAyMDQ4OyArKyBpICkge1xuXG5cdFx0bWFudGlzc2FUYWJsZVsgaSBdID0gMHgzODAwMDAwMCArICggKCBpIC0gMTAyNCApIDw8IDEzICk7XG5cblx0fVxuXG5cdGZvciAoIGxldCBpID0gMTsgaSA8IDMxOyArKyBpICkge1xuXG5cdFx0ZXhwb25lbnRUYWJsZVsgaSBdID0gaSA8PCAyMztcblxuXHR9XG5cblx0ZXhwb25lbnRUYWJsZVsgMzEgXSA9IDB4NDc4MDAwMDA7XG5cdGV4cG9uZW50VGFibGVbIDMyIF0gPSAweDgwMDAwMDAwO1xuXG5cdGZvciAoIGxldCBpID0gMzM7IGkgPCA2MzsgKysgaSApIHtcblxuXHRcdGV4cG9uZW50VGFibGVbIGkgXSA9IDB4ODAwMDAwMDAgKyAoICggaSAtIDMyICkgPDwgMjMgKTtcblxuXHR9XG5cblx0ZXhwb25lbnRUYWJsZVsgNjMgXSA9IDB4Yzc4MDAwMDA7XG5cblx0Zm9yICggbGV0IGkgPSAxOyBpIDwgNjQ7ICsrIGkgKSB7XG5cblx0XHRpZiAoIGkgIT09IDMyICkge1xuXG5cdFx0XHRvZmZzZXRUYWJsZVsgaSBdID0gMTAyNDtcblxuXHRcdH1cblxuXHR9XG5cblx0cmV0dXJuIHtcblx0XHRmbG9hdFZpZXc6IGZsb2F0Vmlldyxcblx0XHR1aW50MzJWaWV3OiB1aW50MzJWaWV3LFxuXHRcdGJhc2VUYWJsZTogYmFzZVRhYmxlLFxuXHRcdHNoaWZ0VGFibGU6IHNoaWZ0VGFibGUsXG5cdFx0bWFudGlzc2FUYWJsZTogbWFudGlzc2FUYWJsZSxcblx0XHRleHBvbmVudFRhYmxlOiBleHBvbmVudFRhYmxlLFxuXHRcdG9mZnNldFRhYmxlOiBvZmZzZXRUYWJsZVxuXHR9O1xuXG59XG5cbi8vIGZsb2F0MzIgdG8gZmxvYXQxNlxuXG5mdW5jdGlvbiB0b0hhbGZGbG9hdCggdmFsICkge1xuXG5cdGlmICggTWF0aC5hYnMoIHZhbCApID4gNjU1MDQgKSBjb25zb2xlLndhcm4oICdUSFJFRS5EYXRhVXRpbHMudG9IYWxmRmxvYXQoKTogVmFsdWUgb3V0IG9mIHJhbmdlLicgKTtcblxuXHR2YWwgPSBjbGFtcCggdmFsLCAtIDY1NTA0LCA2NTUwNCApO1xuXG5cdF90YWJsZXMuZmxvYXRWaWV3WyAwIF0gPSB2YWw7XG5cdGNvbnN0IGYgPSBfdGFibGVzLnVpbnQzMlZpZXdbIDAgXTtcblx0Y29uc3QgZSA9ICggZiA+PiAyMyApICYgMHgxZmY7XG5cdHJldHVybiBfdGFibGVzLmJhc2VUYWJsZVsgZSBdICsgKCAoIGYgJiAweDAwN2ZmZmZmICkgPj4gX3RhYmxlcy5zaGlmdFRhYmxlWyBlIF0gKTtcblxufVxuXG4vLyBmbG9hdDE2IHRvIGZsb2F0MzJcblxuZnVuY3Rpb24gZnJvbUhhbGZGbG9hdCggdmFsICkge1xuXG5cdGNvbnN0IG0gPSB2YWwgPj4gMTA7XG5cdF90YWJsZXMudWludDMyVmlld1sgMCBdID0gX3RhYmxlcy5tYW50aXNzYVRhYmxlWyBfdGFibGVzLm9mZnNldFRhYmxlWyBtIF0gKyAoIHZhbCAmIDB4M2ZmICkgXSArIF90YWJsZXMuZXhwb25lbnRUYWJsZVsgbSBdO1xuXHRyZXR1cm4gX3RhYmxlcy5mbG9hdFZpZXdbIDAgXTtcblxufVxuXG5jb25zdCBEYXRhVXRpbHMgPSB7XG5cdHRvSGFsZkZsb2F0OiB0b0hhbGZGbG9hdCxcblx0ZnJvbUhhbGZGbG9hdDogZnJvbUhhbGZGbG9hdCxcbn07XG5cbmNvbnN0IF92ZWN0b3IkOSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92ZWN0b3IyJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XG5cbmNsYXNzIEJ1ZmZlckF0dHJpYnV0ZSB7XG5cblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCA9IGZhbHNlICkge1xuXG5cdFx0aWYgKCBBcnJheS5pc0FycmF5KCBhcnJheSApICkge1xuXG5cdFx0XHR0aHJvdyBuZXcgVHlwZUVycm9yKCAnVEhSRUUuQnVmZmVyQXR0cmlidXRlOiBhcnJheSBzaG91bGQgYmUgYSBUeXBlZCBBcnJheS4nICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmlzQnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcblxuXHRcdHRoaXMubmFtZSA9ICcnO1xuXG5cdFx0dGhpcy5hcnJheSA9IGFycmF5O1xuXHRcdHRoaXMuaXRlbVNpemUgPSBpdGVtU2l6ZTtcblx0XHR0aGlzLmNvdW50ID0gYXJyYXkgIT09IHVuZGVmaW5lZCA/IGFycmF5Lmxlbmd0aCAvIGl0ZW1TaXplIDogMDtcblx0XHR0aGlzLm5vcm1hbGl6ZWQgPSBub3JtYWxpemVkO1xuXG5cdFx0dGhpcy51c2FnZSA9IFN0YXRpY0RyYXdVc2FnZTtcblx0XHR0aGlzLl91cGRhdGVSYW5nZSA9IHsgb2Zmc2V0OiAwLCBjb3VudDogLSAxIH07XG5cdFx0dGhpcy51cGRhdGVSYW5nZXMgPSBbXTtcblx0XHR0aGlzLmdwdVR5cGUgPSBGbG9hdFR5cGU7XG5cblx0XHR0aGlzLnZlcnNpb24gPSAwO1xuXG5cdH1cblxuXHRvblVwbG9hZENhbGxiYWNrKCkge31cblxuXHRzZXQgbmVlZHNVcGRhdGUoIHZhbHVlICkge1xuXG5cdFx0aWYgKCB2YWx1ZSA9PT0gdHJ1ZSApIHRoaXMudmVyc2lvbiArKztcblxuXHR9XG5cblx0Z2V0IHVwZGF0ZVJhbmdlKCkge1xuXG5cdFx0d2Fybk9uY2UoICdUSFJFRS5CdWZmZXJBdHRyaWJ1dGU6IHVwZGF0ZVJhbmdlKCkgaXMgZGVwcmVjYXRlZCBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHIxNjkuIFVzZSBhZGRVcGRhdGVSYW5nZSgpIGluc3RlYWQuJyApOyAvLyBAZGVwcmVjYXRlZCwgcjE1OVxuXHRcdHJldHVybiB0aGlzLl91cGRhdGVSYW5nZTtcblxuXHR9XG5cblx0c2V0VXNhZ2UoIHZhbHVlICkge1xuXG5cdFx0dGhpcy51c2FnZSA9IHZhbHVlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFkZFVwZGF0ZVJhbmdlKCBzdGFydCwgY291bnQgKSB7XG5cblx0XHR0aGlzLnVwZGF0ZVJhbmdlcy5wdXNoKCB7IHN0YXJ0LCBjb3VudCB9ICk7XG5cblx0fVxuXG5cdGNsZWFyVXBkYXRlUmFuZ2VzKCkge1xuXG5cdFx0dGhpcy51cGRhdGVSYW5nZXMubGVuZ3RoID0gMDtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0dGhpcy5uYW1lID0gc291cmNlLm5hbWU7XG5cdFx0dGhpcy5hcnJheSA9IG5ldyBzb3VyY2UuYXJyYXkuY29uc3RydWN0b3IoIHNvdXJjZS5hcnJheSApO1xuXHRcdHRoaXMuaXRlbVNpemUgPSBzb3VyY2UuaXRlbVNpemU7XG5cdFx0dGhpcy5jb3VudCA9IHNvdXJjZS5jb3VudDtcblx0XHR0aGlzLm5vcm1hbGl6ZWQgPSBzb3VyY2Uubm9ybWFsaXplZDtcblxuXHRcdHRoaXMudXNhZ2UgPSBzb3VyY2UudXNhZ2U7XG5cdFx0dGhpcy5ncHVUeXBlID0gc291cmNlLmdwdVR5cGU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weUF0KCBpbmRleDEsIGF0dHJpYnV0ZSwgaW5kZXgyICkge1xuXG5cdFx0aW5kZXgxICo9IHRoaXMuaXRlbVNpemU7XG5cdFx0aW5kZXgyICo9IGF0dHJpYnV0ZS5pdGVtU2l6ZTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuaXRlbVNpemU7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmFycmF5WyBpbmRleDEgKyBpIF0gPSBhdHRyaWJ1dGUuYXJyYXlbIGluZGV4MiArIGkgXTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb3B5QXJyYXkoIGFycmF5ICkge1xuXG5cdFx0dGhpcy5hcnJheS5zZXQoIGFycmF5ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXBwbHlNYXRyaXgzKCBtICkge1xuXG5cdFx0aWYgKCB0aGlzLml0ZW1TaXplID09PSAyICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRfdmVjdG9yMiQxLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHRoaXMsIGkgKTtcblx0XHRcdFx0X3ZlY3RvcjIkMS5hcHBseU1hdHJpeDMoIG0gKTtcblxuXHRcdFx0XHR0aGlzLnNldFhZKCBpLCBfdmVjdG9yMiQxLngsIF92ZWN0b3IyJDEueSApO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2UgaWYgKCB0aGlzLml0ZW1TaXplID09PSAzICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRfdmVjdG9yJDkuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xuXHRcdFx0XHRfdmVjdG9yJDkuYXBwbHlNYXRyaXgzKCBtICk7XG5cblx0XHRcdFx0dGhpcy5zZXRYWVooIGksIF92ZWN0b3IkOS54LCBfdmVjdG9yJDkueSwgX3ZlY3RvciQ5LnogKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFwcGx5TWF0cml4NCggbSApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY291bnQ7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRfdmVjdG9yJDkuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xuXG5cdFx0XHRfdmVjdG9yJDkuYXBwbHlNYXRyaXg0KCBtICk7XG5cblx0XHRcdHRoaXMuc2V0WFlaKCBpLCBfdmVjdG9yJDkueCwgX3ZlY3RvciQ5LnksIF92ZWN0b3IkOS56ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXBwbHlOb3JtYWxNYXRyaXgoIG0gKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0X3ZlY3RvciQ5LmZyb21CdWZmZXJBdHRyaWJ1dGUoIHRoaXMsIGkgKTtcblxuXHRcdFx0X3ZlY3RvciQ5LmFwcGx5Tm9ybWFsTWF0cml4KCBtICk7XG5cblx0XHRcdHRoaXMuc2V0WFlaKCBpLCBfdmVjdG9yJDkueCwgX3ZlY3RvciQ5LnksIF92ZWN0b3IkOS56ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJhbnNmb3JtRGlyZWN0aW9uKCBtICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5jb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdF92ZWN0b3IkOS5mcm9tQnVmZmVyQXR0cmlidXRlKCB0aGlzLCBpICk7XG5cblx0XHRcdF92ZWN0b3IkOS50cmFuc2Zvcm1EaXJlY3Rpb24oIG0gKTtcblxuXHRcdFx0dGhpcy5zZXRYWVooIGksIF92ZWN0b3IkOS54LCBfdmVjdG9yJDkueSwgX3ZlY3RvciQ5LnogKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXQoIHZhbHVlLCBvZmZzZXQgPSAwICkge1xuXG5cdFx0Ly8gTWF0Y2hpbmcgQnVmZmVyQXR0cmlidXRlIGNvbnN0cnVjdG9yLCBkbyBub3Qgbm9ybWFsaXplIHRoZSBhcnJheS5cblx0XHR0aGlzLmFycmF5LnNldCggdmFsdWUsIG9mZnNldCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldENvbXBvbmVudCggaW5kZXgsIGNvbXBvbmVudCApIHtcblxuXHRcdGxldCB2YWx1ZSA9IHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIGNvbXBvbmVudCBdO1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB2YWx1ZSA9IGRlbm9ybWFsaXplKCB2YWx1ZSwgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHZhbHVlO1xuXG5cdH1cblxuXHRzZXRDb21wb25lbnQoIGluZGV4LCBjb21wb25lbnQsIHZhbHVlICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB2YWx1ZSA9IG5vcm1hbGl6ZSggdmFsdWUsIHRoaXMuYXJyYXkgKTtcblxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIGNvbXBvbmVudCBdID0gdmFsdWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0WCggaW5kZXggKSB7XG5cblx0XHRsZXQgeCA9IHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSBdO1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB4ID0gZGVub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcblxuXHRcdHJldHVybiB4O1xuXG5cdH1cblxuXHRzZXRYKCBpbmRleCwgeCApIHtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplIF0gPSB4O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldFkoIGluZGV4ICkge1xuXG5cdFx0bGV0IHkgPSB0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAxIF07XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHkgPSBkZW5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHk7XG5cblx0fVxuXG5cdHNldFkoIGluZGV4LCB5ICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAxIF0gPSB5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldFooIGluZGV4ICkge1xuXG5cdFx0bGV0IHogPSB0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAyIF07XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHogPSBkZW5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHo7XG5cblx0fVxuXG5cdHNldFooIGluZGV4LCB6ICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAyIF0gPSB6O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldFcoIGluZGV4ICkge1xuXG5cdFx0bGV0IHcgPSB0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAzIF07XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHcgPSBkZW5vcm1hbGl6ZSggdywgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHc7XG5cblx0fVxuXG5cdHNldFcoIGluZGV4LCB3ICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB3ID0gbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAzIF0gPSB3O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFhZKCBpbmRleCwgeCwgeSApIHtcblxuXHRcdGluZGV4ICo9IHRoaXMuaXRlbVNpemU7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcblxuXHRcdFx0eCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAwIF0gPSB4O1xuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMSBdID0geTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRYWVooIGluZGV4LCB4LCB5LCB6ICkge1xuXG5cdFx0aW5kZXggKj0gdGhpcy5pdGVtU2l6ZTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkge1xuXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDAgXSA9IHg7XG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAxIF0gPSB5O1xuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMiBdID0gejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRYWVpXKCBpbmRleCwgeCwgeSwgeiwgdyApIHtcblxuXHRcdGluZGV4ICo9IHRoaXMuaXRlbVNpemU7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcblxuXHRcdFx0eCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xuXHRcdFx0eiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xuXHRcdFx0dyA9IG5vcm1hbGl6ZSggdywgdGhpcy5hcnJheSApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAwIF0gPSB4O1xuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMSBdID0geTtcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDIgXSA9IHo7XG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAzIF0gPSB3O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG9uVXBsb2FkKCBjYWxsYmFjayApIHtcblxuXHRcdHRoaXMub25VcGxvYWRDYWxsYmFjayA9IGNhbGxiYWNrO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCB0aGlzLmFycmF5LCB0aGlzLml0ZW1TaXplICkuY29weSggdGhpcyApO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0ge1xuXHRcdFx0aXRlbVNpemU6IHRoaXMuaXRlbVNpemUsXG5cdFx0XHR0eXBlOiB0aGlzLmFycmF5LmNvbnN0cnVjdG9yLm5hbWUsXG5cdFx0XHRhcnJheTogQXJyYXkuZnJvbSggdGhpcy5hcnJheSApLFxuXHRcdFx0bm9ybWFsaXplZDogdGhpcy5ub3JtYWxpemVkXG5cdFx0fTtcblxuXHRcdGlmICggdGhpcy5uYW1lICE9PSAnJyApIGRhdGEubmFtZSA9IHRoaXMubmFtZTtcblx0XHRpZiAoIHRoaXMudXNhZ2UgIT09IFN0YXRpY0RyYXdVc2FnZSApIGRhdGEudXNhZ2UgPSB0aGlzLnVzYWdlO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbi8vXG5cbmNsYXNzIEludDhCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xuXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKSB7XG5cblx0XHRzdXBlciggbmV3IEludDhBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgVWludDhCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xuXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKSB7XG5cblx0XHRzdXBlciggbmV3IFVpbnQ4QXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFVpbnQ4Q2xhbXBlZEJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XG5cblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcblxuXHRcdHN1cGVyKCBuZXcgVWludDhDbGFtcGVkQXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIEludDE2QnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcblxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xuXG5cdFx0c3VwZXIoIG5ldyBJbnQxNkFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBVaW50MTZCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xuXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKSB7XG5cblx0XHRzdXBlciggbmV3IFVpbnQxNkFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBJbnQzMkJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XG5cblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcblxuXHRcdHN1cGVyKCBuZXcgSW50MzJBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgVWludDMyQnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcblxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xuXG5cdFx0c3VwZXIoIG5ldyBVaW50MzJBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgRmxvYXQxNkJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XG5cblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcblxuXHRcdHN1cGVyKCBuZXcgVWludDE2QXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XG5cblx0XHR0aGlzLmlzRmxvYXQxNkJ1ZmZlckF0dHJpYnV0ZSA9IHRydWU7XG5cblx0fVxuXG5cdGdldFgoIGluZGV4ICkge1xuXG5cdFx0bGV0IHggPSBmcm9tSGFsZkZsb2F0KCB0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgXSApO1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB4ID0gZGVub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcblxuXHRcdHJldHVybiB4O1xuXG5cdH1cblxuXHRzZXRYKCBpbmRleCwgeCApIHtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplIF0gPSB0b0hhbGZGbG9hdCggeCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldFkoIGluZGV4ICkge1xuXG5cdFx0bGV0IHkgPSBmcm9tSGFsZkZsb2F0KCB0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAxIF0gKTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IGRlbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cblx0XHRyZXR1cm4geTtcblxuXHR9XG5cblx0c2V0WSggaW5kZXgsIHkgKSB7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcblxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDEgXSA9IHRvSGFsZkZsb2F0KCB5ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0WiggaW5kZXggKSB7XG5cblx0XHRsZXQgeiA9IGZyb21IYWxmRmxvYXQoIHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDIgXSApO1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB6ID0gZGVub3JtYWxpemUoIHosIHRoaXMuYXJyYXkgKTtcblxuXHRcdHJldHVybiB6O1xuXG5cdH1cblxuXHRzZXRaKCBpbmRleCwgeiApIHtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xuXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMiBdID0gdG9IYWxmRmxvYXQoIHogKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRXKCBpbmRleCApIHtcblxuXHRcdGxldCB3ID0gZnJvbUhhbGZGbG9hdCggdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMyBdICk7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHcgPSBkZW5vcm1hbGl6ZSggdywgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHc7XG5cblx0fVxuXG5cdHNldFcoIGluZGV4LCB3ICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB3ID0gbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAzIF0gPSB0b0hhbGZGbG9hdCggdyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFhZKCBpbmRleCwgeCwgeSApIHtcblxuXHRcdGluZGV4ICo9IHRoaXMuaXRlbVNpemU7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcblxuXHRcdFx0eCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAwIF0gPSB0b0hhbGZGbG9hdCggeCApO1xuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMSBdID0gdG9IYWxmRmxvYXQoIHkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRYWVooIGluZGV4LCB4LCB5LCB6ICkge1xuXG5cdFx0aW5kZXggKj0gdGhpcy5pdGVtU2l6ZTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkge1xuXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDAgXSA9IHRvSGFsZkZsb2F0KCB4ICk7XG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAxIF0gPSB0b0hhbGZGbG9hdCggeSApO1xuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMiBdID0gdG9IYWxmRmxvYXQoIHogKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRYWVpXKCBpbmRleCwgeCwgeSwgeiwgdyApIHtcblxuXHRcdGluZGV4ICo9IHRoaXMuaXRlbVNpemU7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcblxuXHRcdFx0eCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xuXHRcdFx0eiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xuXHRcdFx0dyA9IG5vcm1hbGl6ZSggdywgdGhpcy5hcnJheSApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAwIF0gPSB0b0hhbGZGbG9hdCggeCApO1xuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMSBdID0gdG9IYWxmRmxvYXQoIHkgKTtcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDIgXSA9IHRvSGFsZkZsb2F0KCB6ICk7XG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAzIF0gPSB0b0hhbGZGbG9hdCggdyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cblxuY2xhc3MgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XG5cblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcblxuXHRcdHN1cGVyKCBuZXcgRmxvYXQzMkFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xuXG5cdH1cblxufVxuXG5sZXQgX2lkJDIgPSAwO1xuXG5jb25zdCBfbTEkMiA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF9vYmogPSAvKkBfX1BVUkVfXyovIG5ldyBPYmplY3QzRCgpO1xuY29uc3QgX29mZnNldCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9ib3gkMiA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcbmNvbnN0IF9ib3hNb3JwaFRhcmdldHMgPSAvKkBfX1BVUkVfXyovIG5ldyBCb3gzKCk7XG5jb25zdCBfdmVjdG9yJDggPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNsYXNzIEJ1ZmZlckdlb21ldHJ5IGV4dGVuZHMgRXZlbnREaXNwYXRjaGVyIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzQnVmZmVyR2VvbWV0cnkgPSB0cnVlO1xuXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfaWQkMiArKyB9ICk7XG5cblx0XHR0aGlzLnV1aWQgPSBnZW5lcmF0ZVVVSUQoKTtcblxuXHRcdHRoaXMubmFtZSA9ICcnO1xuXHRcdHRoaXMudHlwZSA9ICdCdWZmZXJHZW9tZXRyeSc7XG5cblx0XHR0aGlzLmluZGV4ID0gbnVsbDtcblx0XHR0aGlzLmF0dHJpYnV0ZXMgPSB7fTtcblxuXHRcdHRoaXMubW9ycGhBdHRyaWJ1dGVzID0ge307XG5cdFx0dGhpcy5tb3JwaFRhcmdldHNSZWxhdGl2ZSA9IGZhbHNlO1xuXG5cdFx0dGhpcy5ncm91cHMgPSBbXTtcblxuXHRcdHRoaXMuYm91bmRpbmdCb3ggPSBudWxsO1xuXHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBudWxsO1xuXG5cdFx0dGhpcy5kcmF3UmFuZ2UgPSB7IHN0YXJ0OiAwLCBjb3VudDogSW5maW5pdHkgfTtcblxuXHRcdHRoaXMudXNlckRhdGEgPSB7fTtcblxuXHR9XG5cblx0Z2V0SW5kZXgoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5pbmRleDtcblxuXHR9XG5cblx0c2V0SW5kZXgoIGluZGV4ICkge1xuXG5cdFx0aWYgKCBBcnJheS5pc0FycmF5KCBpbmRleCApICkge1xuXG5cdFx0XHR0aGlzLmluZGV4ID0gbmV3ICggYXJyYXlOZWVkc1VpbnQzMiggaW5kZXggKSA/IFVpbnQzMkJ1ZmZlckF0dHJpYnV0ZSA6IFVpbnQxNkJ1ZmZlckF0dHJpYnV0ZSApKCBpbmRleCwgMSApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhpcy5pbmRleCA9IGluZGV4O1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldEF0dHJpYnV0ZSggbmFtZSApIHtcblxuXHRcdHJldHVybiB0aGlzLmF0dHJpYnV0ZXNbIG5hbWUgXTtcblxuXHR9XG5cblx0c2V0QXR0cmlidXRlKCBuYW1lLCBhdHRyaWJ1dGUgKSB7XG5cblx0XHR0aGlzLmF0dHJpYnV0ZXNbIG5hbWUgXSA9IGF0dHJpYnV0ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkZWxldGVBdHRyaWJ1dGUoIG5hbWUgKSB7XG5cblx0XHRkZWxldGUgdGhpcy5hdHRyaWJ1dGVzWyBuYW1lIF07XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0aGFzQXR0cmlidXRlKCBuYW1lICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuYXR0cmlidXRlc1sgbmFtZSBdICE9PSB1bmRlZmluZWQ7XG5cblx0fVxuXG5cdGFkZEdyb3VwKCBzdGFydCwgY291bnQsIG1hdGVyaWFsSW5kZXggPSAwICkge1xuXG5cdFx0dGhpcy5ncm91cHMucHVzaCgge1xuXG5cdFx0XHRzdGFydDogc3RhcnQsXG5cdFx0XHRjb3VudDogY291bnQsXG5cdFx0XHRtYXRlcmlhbEluZGV4OiBtYXRlcmlhbEluZGV4XG5cblx0XHR9ICk7XG5cblx0fVxuXG5cdGNsZWFyR3JvdXBzKCkge1xuXG5cdFx0dGhpcy5ncm91cHMgPSBbXTtcblxuXHR9XG5cblx0c2V0RHJhd1JhbmdlKCBzdGFydCwgY291bnQgKSB7XG5cblx0XHR0aGlzLmRyYXdSYW5nZS5zdGFydCA9IHN0YXJ0O1xuXHRcdHRoaXMuZHJhd1JhbmdlLmNvdW50ID0gY291bnQ7XG5cblx0fVxuXG5cdGFwcGx5TWF0cml4NCggbWF0cml4ICkge1xuXG5cdFx0Y29uc3QgcG9zaXRpb24gPSB0aGlzLmF0dHJpYnV0ZXMucG9zaXRpb247XG5cblx0XHRpZiAoIHBvc2l0aW9uICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHBvc2l0aW9uLmFwcGx5TWF0cml4NCggbWF0cml4ICk7XG5cblx0XHRcdHBvc2l0aW9uLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IG5vcm1hbCA9IHRoaXMuYXR0cmlidXRlcy5ub3JtYWw7XG5cblx0XHRpZiAoIG5vcm1hbCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjb25zdCBub3JtYWxNYXRyaXggPSBuZXcgTWF0cml4MygpLmdldE5vcm1hbE1hdHJpeCggbWF0cml4ICk7XG5cblx0XHRcdG5vcm1hbC5hcHBseU5vcm1hbE1hdHJpeCggbm9ybWFsTWF0cml4ICk7XG5cblx0XHRcdG5vcm1hbC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR9XG5cblx0XHRjb25zdCB0YW5nZW50ID0gdGhpcy5hdHRyaWJ1dGVzLnRhbmdlbnQ7XG5cblx0XHRpZiAoIHRhbmdlbnQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGFuZ2VudC50cmFuc2Zvcm1EaXJlY3Rpb24oIG1hdHJpeCApO1xuXG5cdFx0XHR0YW5nZW50Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5ib3VuZGluZ0JveCAhPT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5jb21wdXRlQm91bmRpbmdCb3goKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhcHBseVF1YXRlcm5pb24oIHEgKSB7XG5cblx0XHRfbTEkMi5tYWtlUm90YXRpb25Gcm9tUXVhdGVybmlvbiggcSApO1xuXG5cdFx0dGhpcy5hcHBseU1hdHJpeDQoIF9tMSQyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cm90YXRlWCggYW5nbGUgKSB7XG5cblx0XHQvLyByb3RhdGUgZ2VvbWV0cnkgYXJvdW5kIHdvcmxkIHgtYXhpc1xuXG5cdFx0X20xJDIubWFrZVJvdGF0aW9uWCggYW5nbGUgKTtcblxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEkMiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJvdGF0ZVkoIGFuZ2xlICkge1xuXG5cdFx0Ly8gcm90YXRlIGdlb21ldHJ5IGFyb3VuZCB3b3JsZCB5LWF4aXNcblxuXHRcdF9tMSQyLm1ha2VSb3RhdGlvblkoIGFuZ2xlICk7XG5cblx0XHR0aGlzLmFwcGx5TWF0cml4NCggX20xJDIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyb3RhdGVaKCBhbmdsZSApIHtcblxuXHRcdC8vIHJvdGF0ZSBnZW9tZXRyeSBhcm91bmQgd29ybGQgei1heGlzXG5cblx0XHRfbTEkMi5tYWtlUm90YXRpb25aKCBhbmdsZSApO1xuXG5cdFx0dGhpcy5hcHBseU1hdHJpeDQoIF9tMSQyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJhbnNsYXRlKCB4LCB5LCB6ICkge1xuXG5cdFx0Ly8gdHJhbnNsYXRlIGdlb21ldHJ5XG5cblx0XHRfbTEkMi5tYWtlVHJhbnNsYXRpb24oIHgsIHksIHogKTtcblxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEkMiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNjYWxlKCB4LCB5LCB6ICkge1xuXG5cdFx0Ly8gc2NhbGUgZ2VvbWV0cnlcblxuXHRcdF9tMSQyLm1ha2VTY2FsZSggeCwgeSwgeiApO1xuXG5cdFx0dGhpcy5hcHBseU1hdHJpeDQoIF9tMSQyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bG9va0F0KCB2ZWN0b3IgKSB7XG5cblx0XHRfb2JqLmxvb2tBdCggdmVjdG9yICk7XG5cblx0XHRfb2JqLnVwZGF0ZU1hdHJpeCgpO1xuXG5cdFx0dGhpcy5hcHBseU1hdHJpeDQoIF9vYmoubWF0cml4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2VudGVyKCkge1xuXG5cdFx0dGhpcy5jb21wdXRlQm91bmRpbmdCb3goKTtcblxuXHRcdHRoaXMuYm91bmRpbmdCb3guZ2V0Q2VudGVyKCBfb2Zmc2V0ICkubmVnYXRlKCk7XG5cblx0XHR0aGlzLnRyYW5zbGF0ZSggX29mZnNldC54LCBfb2Zmc2V0LnksIF9vZmZzZXQueiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21Qb2ludHMoIHBvaW50cyApIHtcblxuXHRcdGNvbnN0IHBvc2l0aW9uID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBwb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgcG9pbnQgPSBwb2ludHNbIGkgXTtcblx0XHRcdHBvc2l0aW9uLnB1c2goIHBvaW50LngsIHBvaW50LnksIHBvaW50LnogfHwgMCApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgMyApICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29tcHV0ZUJvdW5kaW5nQm94KCkge1xuXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nQm94ID09PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94ID0gbmV3IEJveDMoKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHBvc2l0aW9uID0gdGhpcy5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uID0gdGhpcy5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb247XG5cblx0XHRpZiAoIHBvc2l0aW9uICYmIHBvc2l0aW9uLmlzR0xCdWZmZXJBdHRyaWJ1dGUgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5CdWZmZXJHZW9tZXRyeS5jb21wdXRlQm91bmRpbmdCb3goKTogR0xCdWZmZXJBdHRyaWJ1dGUgcmVxdWlyZXMgYSBtYW51YWwgYm91bmRpbmcgYm94LicsIHRoaXMgKTtcblxuXHRcdFx0dGhpcy5ib3VuZGluZ0JveC5zZXQoXG5cdFx0XHRcdG5ldyBWZWN0b3IzKCAtIEluZmluaXR5LCAtIEluZmluaXR5LCAtIEluZmluaXR5ICksXG5cdFx0XHRcdG5ldyBWZWN0b3IzKCArIEluZmluaXR5LCArIEluZmluaXR5LCArIEluZmluaXR5IClcblx0XHRcdCk7XG5cblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdGlmICggcG9zaXRpb24gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGhpcy5ib3VuZGluZ0JveC5zZXRGcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiApO1xuXG5cdFx0XHQvLyBwcm9jZXNzIG1vcnBoIGF0dHJpYnV0ZXMgaWYgcHJlc2VudFxuXG5cdFx0XHRpZiAoIG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb25bIGkgXTtcblx0XHRcdFx0XHRfYm94JDIuc2V0RnJvbUJ1ZmZlckF0dHJpYnV0ZSggbW9ycGhBdHRyaWJ1dGUgKTtcblxuXHRcdFx0XHRcdGlmICggdGhpcy5tb3JwaFRhcmdldHNSZWxhdGl2ZSApIHtcblxuXHRcdFx0XHRcdFx0X3ZlY3RvciQ4LmFkZFZlY3RvcnMoIHRoaXMuYm91bmRpbmdCb3gubWluLCBfYm94JDIubWluICk7XG5cdFx0XHRcdFx0XHR0aGlzLmJvdW5kaW5nQm94LmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IkOCApO1xuXG5cdFx0XHRcdFx0XHRfdmVjdG9yJDguYWRkVmVjdG9ycyggdGhpcy5ib3VuZGluZ0JveC5tYXgsIF9ib3gkMi5tYXggKTtcblx0XHRcdFx0XHRcdHRoaXMuYm91bmRpbmdCb3guZXhwYW5kQnlQb2ludCggX3ZlY3RvciQ4ICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHR0aGlzLmJvdW5kaW5nQm94LmV4cGFuZEJ5UG9pbnQoIF9ib3gkMi5taW4gKTtcblx0XHRcdFx0XHRcdHRoaXMuYm91bmRpbmdCb3guZXhwYW5kQnlQb2ludCggX2JveCQyLm1heCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhpcy5ib3VuZGluZ0JveC5tYWtlRW1wdHkoKTtcblxuXHRcdH1cblxuXHRcdGlmICggaXNOYU4oIHRoaXMuYm91bmRpbmdCb3gubWluLnggKSB8fCBpc05hTiggdGhpcy5ib3VuZGluZ0JveC5taW4ueSApIHx8IGlzTmFOKCB0aGlzLmJvdW5kaW5nQm94Lm1pbi56ICkgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5CdWZmZXJHZW9tZXRyeS5jb21wdXRlQm91bmRpbmdCb3goKTogQ29tcHV0ZWQgbWluL21heCBoYXZlIE5hTiB2YWx1ZXMuIFRoZSBcInBvc2l0aW9uXCIgYXR0cmlidXRlIGlzIGxpa2VseSB0byBoYXZlIE5hTiB2YWx1ZXMuJywgdGhpcyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb21wdXRlQm91bmRpbmdTcGhlcmUoKSB7XG5cblx0XHRpZiAoIHRoaXMuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBwb3NpdGlvbiA9IHRoaXMuYXR0cmlidXRlcy5wb3NpdGlvbjtcblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvbiA9IHRoaXMubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXG5cdFx0aWYgKCBwb3NpdGlvbiAmJiBwb3NpdGlvbi5pc0dMQnVmZmVyQXR0cmlidXRlICkge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuQnVmZmVyR2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk6IEdMQnVmZmVyQXR0cmlidXRlIHJlcXVpcmVzIGEgbWFudWFsIGJvdW5kaW5nIHNwaGVyZS4nLCB0aGlzICk7XG5cblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUuc2V0KCBuZXcgVmVjdG9yMygpLCBJbmZpbml0eSApO1xuXG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHRpZiAoIHBvc2l0aW9uICkge1xuXG5cdFx0XHQvLyBmaXJzdCwgZmluZCB0aGUgY2VudGVyIG9mIHRoZSBib3VuZGluZyBzcGhlcmVcblxuXHRcdFx0Y29uc3QgY2VudGVyID0gdGhpcy5ib3VuZGluZ1NwaGVyZS5jZW50ZXI7XG5cblx0XHRcdF9ib3gkMi5zZXRGcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiApO1xuXG5cdFx0XHQvLyBwcm9jZXNzIG1vcnBoIGF0dHJpYnV0ZXMgaWYgcHJlc2VudFxuXG5cdFx0XHRpZiAoIG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb25bIGkgXTtcblx0XHRcdFx0XHRfYm94TW9ycGhUYXJnZXRzLnNldEZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoQXR0cmlidXRlICk7XG5cblx0XHRcdFx0XHRpZiAoIHRoaXMubW9ycGhUYXJnZXRzUmVsYXRpdmUgKSB7XG5cblx0XHRcdFx0XHRcdF92ZWN0b3IkOC5hZGRWZWN0b3JzKCBfYm94JDIubWluLCBfYm94TW9ycGhUYXJnZXRzLm1pbiApO1xuXHRcdFx0XHRcdFx0X2JveCQyLmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IkOCApO1xuXG5cdFx0XHRcdFx0XHRfdmVjdG9yJDguYWRkVmVjdG9ycyggX2JveCQyLm1heCwgX2JveE1vcnBoVGFyZ2V0cy5tYXggKTtcblx0XHRcdFx0XHRcdF9ib3gkMi5leHBhbmRCeVBvaW50KCBfdmVjdG9yJDggKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdF9ib3gkMi5leHBhbmRCeVBvaW50KCBfYm94TW9ycGhUYXJnZXRzLm1pbiApO1xuXHRcdFx0XHRcdFx0X2JveCQyLmV4cGFuZEJ5UG9pbnQoIF9ib3hNb3JwaFRhcmdldHMubWF4ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdF9ib3gkMi5nZXRDZW50ZXIoIGNlbnRlciApO1xuXG5cdFx0XHQvLyBzZWNvbmQsIHRyeSB0byBmaW5kIGEgYm91bmRpbmdTcGhlcmUgd2l0aCBhIHJhZGl1cyBzbWFsbGVyIHRoYW4gdGhlXG5cdFx0XHQvLyBib3VuZGluZ1NwaGVyZSBvZiB0aGUgYm91bmRpbmdCb3g6IHNxcnQoMykgc21hbGxlciBpbiB0aGUgYmVzdCBjYXNlXG5cblx0XHRcdGxldCBtYXhSYWRpdXNTcSA9IDA7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBwb3NpdGlvbi5jb3VudDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdF92ZWN0b3IkOC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaSApO1xuXG5cdFx0XHRcdG1heFJhZGl1c1NxID0gTWF0aC5tYXgoIG1heFJhZGl1c1NxLCBjZW50ZXIuZGlzdGFuY2VUb1NxdWFyZWQoIF92ZWN0b3IkOCApICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gcHJvY2VzcyBtb3JwaCBhdHRyaWJ1dGVzIGlmIHByZXNlbnRcblxuXHRcdFx0aWYgKCBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvbiApIHtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24ubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uWyBpIF07XG5cdFx0XHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzUmVsYXRpdmUgPSB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGogPSAwLCBqbCA9IG1vcnBoQXR0cmlidXRlLmNvdW50OyBqIDwgamw7IGogKysgKSB7XG5cblx0XHRcdFx0XHRcdF92ZWN0b3IkOC5mcm9tQnVmZmVyQXR0cmlidXRlKCBtb3JwaEF0dHJpYnV0ZSwgaiApO1xuXG5cdFx0XHRcdFx0XHRpZiAoIG1vcnBoVGFyZ2V0c1JlbGF0aXZlICkge1xuXG5cdFx0XHRcdFx0XHRcdF9vZmZzZXQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIGogKTtcblx0XHRcdFx0XHRcdFx0X3ZlY3RvciQ4LmFkZCggX29mZnNldCApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdG1heFJhZGl1c1NxID0gTWF0aC5tYXgoIG1heFJhZGl1c1NxLCBjZW50ZXIuZGlzdGFuY2VUb1NxdWFyZWQoIF92ZWN0b3IkOCApICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUucmFkaXVzID0gTWF0aC5zcXJ0KCBtYXhSYWRpdXNTcSApO1xuXG5cdFx0XHRpZiAoIGlzTmFOKCB0aGlzLmJvdW5kaW5nU3BoZXJlLnJhZGl1cyApICkge1xuXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5CdWZmZXJHZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTogQ29tcHV0ZWQgcmFkaXVzIGlzIE5hTi4gVGhlIFwicG9zaXRpb25cIiBhdHRyaWJ1dGUgaXMgbGlrZWx5IHRvIGhhdmUgTmFOIHZhbHVlcy4nLCB0aGlzICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0Y29tcHV0ZVRhbmdlbnRzKCkge1xuXG5cdFx0Y29uc3QgaW5kZXggPSB0aGlzLmluZGV4O1xuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSB0aGlzLmF0dHJpYnV0ZXM7XG5cblx0XHQvLyBiYXNlZCBvbiBodHRwOi8vd3d3LnRlcmF0aG9uLmNvbS9jb2RlL3RhbmdlbnQuaHRtbFxuXHRcdC8vIChwZXIgdmVydGV4IHRhbmdlbnRzKVxuXG5cdFx0aWYgKCBpbmRleCA9PT0gbnVsbCB8fFxuXHRcdFx0IGF0dHJpYnV0ZXMucG9zaXRpb24gPT09IHVuZGVmaW5lZCB8fFxuXHRcdFx0IGF0dHJpYnV0ZXMubm9ybWFsID09PSB1bmRlZmluZWQgfHxcblx0XHRcdCBhdHRyaWJ1dGVzLnV2ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5CdWZmZXJHZW9tZXRyeTogLmNvbXB1dGVUYW5nZW50cygpIGZhaWxlZC4gTWlzc2luZyByZXF1aXJlZCBhdHRyaWJ1dGVzIChpbmRleCwgcG9zaXRpb24sIG5vcm1hbCBvciB1diknICk7XG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXMucG9zaXRpb247XG5cdFx0Y29uc3Qgbm9ybWFsQXR0cmlidXRlID0gYXR0cmlidXRlcy5ub3JtYWw7XG5cdFx0Y29uc3QgdXZBdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzLnV2O1xuXG5cdFx0aWYgKCB0aGlzLmhhc0F0dHJpYnV0ZSggJ3RhbmdlbnQnICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3RhbmdlbnQnLCBuZXcgQnVmZmVyQXR0cmlidXRlKCBuZXcgRmxvYXQzMkFycmF5KCA0ICogcG9zaXRpb25BdHRyaWJ1dGUuY291bnQgKSwgNCApICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCB0YW5nZW50QXR0cmlidXRlID0gdGhpcy5nZXRBdHRyaWJ1dGUoICd0YW5nZW50JyApO1xuXG5cdFx0Y29uc3QgdGFuMSA9IFtdLCB0YW4yID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudDsgaSArKyApIHtcblxuXHRcdFx0dGFuMVsgaSBdID0gbmV3IFZlY3RvcjMoKTtcblx0XHRcdHRhbjJbIGkgXSA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHR9XG5cblx0XHRjb25zdCB2QSA9IG5ldyBWZWN0b3IzKCksXG5cdFx0XHR2QiA9IG5ldyBWZWN0b3IzKCksXG5cdFx0XHR2QyA9IG5ldyBWZWN0b3IzKCksXG5cblx0XHRcdHV2QSA9IG5ldyBWZWN0b3IyKCksXG5cdFx0XHR1dkIgPSBuZXcgVmVjdG9yMigpLFxuXHRcdFx0dXZDID0gbmV3IFZlY3RvcjIoKSxcblxuXHRcdFx0c2RpciA9IG5ldyBWZWN0b3IzKCksXG5cdFx0XHR0ZGlyID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdGZ1bmN0aW9uIGhhbmRsZVRyaWFuZ2xlKCBhLCBiLCBjICkge1xuXG5cdFx0XHR2QS5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgYSApO1xuXHRcdFx0dkIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGIgKTtcblx0XHRcdHZDLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBjICk7XG5cblx0XHRcdHV2QS5mcm9tQnVmZmVyQXR0cmlidXRlKCB1dkF0dHJpYnV0ZSwgYSApO1xuXHRcdFx0dXZCLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHV2QXR0cmlidXRlLCBiICk7XG5cdFx0XHR1dkMuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXZBdHRyaWJ1dGUsIGMgKTtcblxuXHRcdFx0dkIuc3ViKCB2QSApO1xuXHRcdFx0dkMuc3ViKCB2QSApO1xuXG5cdFx0XHR1dkIuc3ViKCB1dkEgKTtcblx0XHRcdHV2Qy5zdWIoIHV2QSApO1xuXG5cdFx0XHRjb25zdCByID0gMS4wIC8gKCB1dkIueCAqIHV2Qy55IC0gdXZDLnggKiB1dkIueSApO1xuXG5cdFx0XHQvLyBzaWxlbnRseSBpZ25vcmUgZGVnZW5lcmF0ZSB1diB0cmlhbmdsZXMgaGF2aW5nIGNvaW5jaWRlbnQgb3IgY29saW5lYXIgdmVydGljZXNcblxuXHRcdFx0aWYgKCAhIGlzRmluaXRlKCByICkgKSByZXR1cm47XG5cblx0XHRcdHNkaXIuY29weSggdkIgKS5tdWx0aXBseVNjYWxhciggdXZDLnkgKS5hZGRTY2FsZWRWZWN0b3IoIHZDLCAtIHV2Qi55ICkubXVsdGlwbHlTY2FsYXIoIHIgKTtcblx0XHRcdHRkaXIuY29weSggdkMgKS5tdWx0aXBseVNjYWxhciggdXZCLnggKS5hZGRTY2FsZWRWZWN0b3IoIHZCLCAtIHV2Qy54ICkubXVsdGlwbHlTY2FsYXIoIHIgKTtcblxuXHRcdFx0dGFuMVsgYSBdLmFkZCggc2RpciApO1xuXHRcdFx0dGFuMVsgYiBdLmFkZCggc2RpciApO1xuXHRcdFx0dGFuMVsgYyBdLmFkZCggc2RpciApO1xuXG5cdFx0XHR0YW4yWyBhIF0uYWRkKCB0ZGlyICk7XG5cdFx0XHR0YW4yWyBiIF0uYWRkKCB0ZGlyICk7XG5cdFx0XHR0YW4yWyBjIF0uYWRkKCB0ZGlyICk7XG5cblx0XHR9XG5cblx0XHRsZXQgZ3JvdXBzID0gdGhpcy5ncm91cHM7XG5cblx0XHRpZiAoIGdyb3Vwcy5sZW5ndGggPT09IDAgKSB7XG5cblx0XHRcdGdyb3VwcyA9IFsge1xuXHRcdFx0XHRzdGFydDogMCxcblx0XHRcdFx0Y291bnQ6IGluZGV4LmNvdW50XG5cdFx0XHR9IF07XG5cblx0XHR9XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGlsOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xuXG5cdFx0XHRjb25zdCBzdGFydCA9IGdyb3VwLnN0YXJ0O1xuXHRcdFx0Y29uc3QgY291bnQgPSBncm91cC5jb3VudDtcblxuXHRcdFx0Zm9yICggbGV0IGogPSBzdGFydCwgamwgPSBzdGFydCArIGNvdW50OyBqIDwgamw7IGogKz0gMyApIHtcblxuXHRcdFx0XHRoYW5kbGVUcmlhbmdsZShcblx0XHRcdFx0XHRpbmRleC5nZXRYKCBqICsgMCApLFxuXHRcdFx0XHRcdGluZGV4LmdldFgoIGogKyAxICksXG5cdFx0XHRcdFx0aW5kZXguZ2V0WCggaiArIDIgKVxuXHRcdFx0XHQpO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRjb25zdCB0bXAgPSBuZXcgVmVjdG9yMygpLCB0bXAyID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCBuID0gbmV3IFZlY3RvcjMoKSwgbjIgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlVmVydGV4KCB2ICkge1xuXG5cdFx0XHRuLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbEF0dHJpYnV0ZSwgdiApO1xuXHRcdFx0bjIuY29weSggbiApO1xuXG5cdFx0XHRjb25zdCB0ID0gdGFuMVsgdiBdO1xuXG5cdFx0XHQvLyBHcmFtLVNjaG1pZHQgb3J0aG9nb25hbGl6ZVxuXG5cdFx0XHR0bXAuY29weSggdCApO1xuXHRcdFx0dG1wLnN1Yiggbi5tdWx0aXBseVNjYWxhciggbi5kb3QoIHQgKSApICkubm9ybWFsaXplKCk7XG5cblx0XHRcdC8vIENhbGN1bGF0ZSBoYW5kZWRuZXNzXG5cblx0XHRcdHRtcDIuY3Jvc3NWZWN0b3JzKCBuMiwgdCApO1xuXHRcdFx0Y29uc3QgdGVzdCA9IHRtcDIuZG90KCB0YW4yWyB2IF0gKTtcblx0XHRcdGNvbnN0IHcgPSAoIHRlc3QgPCAwLjAgKSA/IC0gMS4wIDogMS4wO1xuXG5cdFx0XHR0YW5nZW50QXR0cmlidXRlLnNldFhZWlcoIHYsIHRtcC54LCB0bXAueSwgdG1wLnosIHcgKTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBncm91cHMubGVuZ3RoOyBpIDwgaWw7ICsrIGkgKSB7XG5cblx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBpIF07XG5cblx0XHRcdGNvbnN0IHN0YXJ0ID0gZ3JvdXAuc3RhcnQ7XG5cdFx0XHRjb25zdCBjb3VudCA9IGdyb3VwLmNvdW50O1xuXG5cdFx0XHRmb3IgKCBsZXQgaiA9IHN0YXJ0LCBqbCA9IHN0YXJ0ICsgY291bnQ7IGogPCBqbDsgaiArPSAzICkge1xuXG5cdFx0XHRcdGhhbmRsZVZlcnRleCggaW5kZXguZ2V0WCggaiArIDAgKSApO1xuXHRcdFx0XHRoYW5kbGVWZXJ0ZXgoIGluZGV4LmdldFgoIGogKyAxICkgKTtcblx0XHRcdFx0aGFuZGxlVmVydGV4KCBpbmRleC5nZXRYKCBqICsgMiApICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0Y29tcHV0ZVZlcnRleE5vcm1hbHMoKSB7XG5cblx0XHRjb25zdCBpbmRleCA9IHRoaXMuaW5kZXg7XG5cdFx0Y29uc3QgcG9zaXRpb25BdHRyaWJ1dGUgPSB0aGlzLmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApO1xuXG5cdFx0aWYgKCBwb3NpdGlvbkF0dHJpYnV0ZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRsZXQgbm9ybWFsQXR0cmlidXRlID0gdGhpcy5nZXRBdHRyaWJ1dGUoICdub3JtYWwnICk7XG5cblx0XHRcdGlmICggbm9ybWFsQXR0cmlidXRlID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0bm9ybWFsQXR0cmlidXRlID0gbmV3IEJ1ZmZlckF0dHJpYnV0ZSggbmV3IEZsb2F0MzJBcnJheSggcG9zaXRpb25BdHRyaWJ1dGUuY291bnQgKiAzICksIDMgKTtcblx0XHRcdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBub3JtYWxBdHRyaWJ1dGUgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyByZXNldCBleGlzdGluZyBub3JtYWxzIHRvIHplcm9cblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbm9ybWFsQXR0cmlidXRlLmNvdW50OyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUuc2V0WFlaKCBpLCAwLCAwLCAwICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHBBID0gbmV3IFZlY3RvcjMoKSwgcEIgPSBuZXcgVmVjdG9yMygpLCBwQyA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0XHRjb25zdCBuQSA9IG5ldyBWZWN0b3IzKCksIG5CID0gbmV3IFZlY3RvcjMoKSwgbkMgPSBuZXcgVmVjdG9yMygpO1xuXHRcdFx0Y29uc3QgY2IgPSBuZXcgVmVjdG9yMygpLCBhYiA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRcdC8vIGluZGV4ZWQgZWxlbWVudHNcblxuXHRcdFx0aWYgKCBpbmRleCApIHtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gaW5kZXguY291bnQ7IGkgPCBpbDsgaSArPSAzICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgdkEgPSBpbmRleC5nZXRYKCBpICsgMCApO1xuXHRcdFx0XHRcdGNvbnN0IHZCID0gaW5kZXguZ2V0WCggaSArIDEgKTtcblx0XHRcdFx0XHRjb25zdCB2QyA9IGluZGV4LmdldFgoIGkgKyAyICk7XG5cblx0XHRcdFx0XHRwQS5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgdkEgKTtcblx0XHRcdFx0XHRwQi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgdkIgKTtcblx0XHRcdFx0XHRwQy5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgdkMgKTtcblxuXHRcdFx0XHRcdGNiLnN1YlZlY3RvcnMoIHBDLCBwQiApO1xuXHRcdFx0XHRcdGFiLnN1YlZlY3RvcnMoIHBBLCBwQiApO1xuXHRcdFx0XHRcdGNiLmNyb3NzKCBhYiApO1xuXG5cdFx0XHRcdFx0bkEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFsQXR0cmlidXRlLCB2QSApO1xuXHRcdFx0XHRcdG5CLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbEF0dHJpYnV0ZSwgdkIgKTtcblx0XHRcdFx0XHRuQy5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWxBdHRyaWJ1dGUsIHZDICk7XG5cblx0XHRcdFx0XHRuQS5hZGQoIGNiICk7XG5cdFx0XHRcdFx0bkIuYWRkKCBjYiApO1xuXHRcdFx0XHRcdG5DLmFkZCggY2IgKTtcblxuXHRcdFx0XHRcdG5vcm1hbEF0dHJpYnV0ZS5zZXRYWVooIHZBLCBuQS54LCBuQS55LCBuQS56ICk7XG5cdFx0XHRcdFx0bm9ybWFsQXR0cmlidXRlLnNldFhZWiggdkIsIG5CLngsIG5CLnksIG5CLnogKTtcblx0XHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUuc2V0WFlaKCB2QywgbkMueCwgbkMueSwgbkMueiApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBub24taW5kZXhlZCBlbGVtZW50cyAodW5jb25uZWN0ZWQgdHJpYW5nbGUgc291cClcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gcG9zaXRpb25BdHRyaWJ1dGUuY291bnQ7IGkgPCBpbDsgaSArPSAzICkge1xuXG5cdFx0XHRcdFx0cEEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKyAwICk7XG5cdFx0XHRcdFx0cEIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKyAxICk7XG5cdFx0XHRcdFx0cEMuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKyAyICk7XG5cblx0XHRcdFx0XHRjYi5zdWJWZWN0b3JzKCBwQywgcEIgKTtcblx0XHRcdFx0XHRhYi5zdWJWZWN0b3JzKCBwQSwgcEIgKTtcblx0XHRcdFx0XHRjYi5jcm9zcyggYWIgKTtcblxuXHRcdFx0XHRcdG5vcm1hbEF0dHJpYnV0ZS5zZXRYWVooIGkgKyAwLCBjYi54LCBjYi55LCBjYi56ICk7XG5cdFx0XHRcdFx0bm9ybWFsQXR0cmlidXRlLnNldFhZWiggaSArIDEsIGNiLngsIGNiLnksIGNiLnogKTtcblx0XHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUuc2V0WFlaKCBpICsgMiwgY2IueCwgY2IueSwgY2IueiApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLm5vcm1hbGl6ZU5vcm1hbHMoKTtcblxuXHRcdFx0bm9ybWFsQXR0cmlidXRlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHR9XG5cblx0bm9ybWFsaXplTm9ybWFscygpIHtcblxuXHRcdGNvbnN0IG5vcm1hbHMgPSB0aGlzLmF0dHJpYnV0ZXMubm9ybWFsO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IG5vcm1hbHMuY291bnQ7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0X3ZlY3RvciQ4LmZyb21CdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIGkgKTtcblxuXHRcdFx0X3ZlY3RvciQ4Lm5vcm1hbGl6ZSgpO1xuXG5cdFx0XHRub3JtYWxzLnNldFhZWiggaSwgX3ZlY3RvciQ4LngsIF92ZWN0b3IkOC55LCBfdmVjdG9yJDgueiApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHR0b05vbkluZGV4ZWQoKSB7XG5cblx0XHRmdW5jdGlvbiBjb252ZXJ0QnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGluZGljZXMgKSB7XG5cblx0XHRcdGNvbnN0IGFycmF5ID0gYXR0cmlidXRlLmFycmF5O1xuXHRcdFx0Y29uc3QgaXRlbVNpemUgPSBhdHRyaWJ1dGUuaXRlbVNpemU7XG5cdFx0XHRjb25zdCBub3JtYWxpemVkID0gYXR0cmlidXRlLm5vcm1hbGl6ZWQ7XG5cblx0XHRcdGNvbnN0IGFycmF5MiA9IG5ldyBhcnJheS5jb25zdHJ1Y3RvciggaW5kaWNlcy5sZW5ndGggKiBpdGVtU2l6ZSApO1xuXG5cdFx0XHRsZXQgaW5kZXggPSAwLCBpbmRleDIgPSAwO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBpbmRpY2VzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0aWYgKCBhdHRyaWJ1dGUuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSApIHtcblxuXHRcdFx0XHRcdGluZGV4ID0gaW5kaWNlc1sgaSBdICogYXR0cmlidXRlLmRhdGEuc3RyaWRlICsgYXR0cmlidXRlLm9mZnNldDtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0aW5kZXggPSBpbmRpY2VzWyBpIF0gKiBpdGVtU2l6ZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgaXRlbVNpemU7IGogKysgKSB7XG5cblx0XHRcdFx0XHRhcnJheTJbIGluZGV4MiArKyBdID0gYXJyYXlbIGluZGV4ICsrIF07XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBuZXcgQnVmZmVyQXR0cmlidXRlKCBhcnJheTIsIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XG5cblx0XHR9XG5cblx0XHQvL1xuXG5cdFx0aWYgKCB0aGlzLmluZGV4ID09PSBudWxsICkge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5CdWZmZXJHZW9tZXRyeS50b05vbkluZGV4ZWQoKTogQnVmZmVyR2VvbWV0cnkgaXMgYWxyZWFkeSBub24taW5kZXhlZC4nICk7XG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH1cblxuXHRcdGNvbnN0IGdlb21ldHJ5MiA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IHRoaXMuaW5kZXguYXJyYXk7XG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IHRoaXMuYXR0cmlidXRlcztcblxuXHRcdC8vIGF0dHJpYnV0ZXNcblxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gYXR0cmlidXRlcyApIHtcblxuXHRcdFx0Y29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlc1sgbmFtZSBdO1xuXG5cdFx0XHRjb25zdCBuZXdBdHRyaWJ1dGUgPSBjb252ZXJ0QnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGluZGljZXMgKTtcblxuXHRcdFx0Z2VvbWV0cnkyLnNldEF0dHJpYnV0ZSggbmFtZSwgbmV3QXR0cmlidXRlICk7XG5cblx0XHR9XG5cblx0XHQvLyBtb3JwaCBhdHRyaWJ1dGVzXG5cblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSB0aGlzLm1vcnBoQXR0cmlidXRlcztcblxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gbW9ycGhBdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRjb25zdCBtb3JwaEFycmF5ID0gW107XG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlc1sgbmFtZSBdOyAvLyBtb3JwaEF0dHJpYnV0ZTogYXJyYXkgb2YgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZXNcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IG1vcnBoQXR0cmlidXRlLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlWyBpIF07XG5cblx0XHRcdFx0Y29uc3QgbmV3QXR0cmlidXRlID0gY29udmVydEJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpbmRpY2VzICk7XG5cblx0XHRcdFx0bW9ycGhBcnJheS5wdXNoKCBuZXdBdHRyaWJ1dGUgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRnZW9tZXRyeTIubW9ycGhBdHRyaWJ1dGVzWyBuYW1lIF0gPSBtb3JwaEFycmF5O1xuXG5cdFx0fVxuXG5cdFx0Z2VvbWV0cnkyLm1vcnBoVGFyZ2V0c1JlbGF0aXZlID0gdGhpcy5tb3JwaFRhcmdldHNSZWxhdGl2ZTtcblxuXHRcdC8vIGdyb3Vwc1xuXG5cdFx0Y29uc3QgZ3JvdXBzID0gdGhpcy5ncm91cHM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBncm91cHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcblx0XHRcdGdlb21ldHJ5Mi5hZGRHcm91cCggZ3JvdXAuc3RhcnQsIGdyb3VwLmNvdW50LCBncm91cC5tYXRlcmlhbEluZGV4ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gZ2VvbWV0cnkyO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0ge1xuXHRcdFx0bWV0YWRhdGE6IHtcblx0XHRcdFx0dmVyc2lvbjogNC42LFxuXHRcdFx0XHR0eXBlOiAnQnVmZmVyR2VvbWV0cnknLFxuXHRcdFx0XHRnZW5lcmF0b3I6ICdCdWZmZXJHZW9tZXRyeS50b0pTT04nXG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdC8vIHN0YW5kYXJkIEJ1ZmZlckdlb21ldHJ5IHNlcmlhbGl6YXRpb25cblxuXHRcdGRhdGEudXVpZCA9IHRoaXMudXVpZDtcblx0XHRkYXRhLnR5cGUgPSB0aGlzLnR5cGU7XG5cdFx0aWYgKCB0aGlzLm5hbWUgIT09ICcnICkgZGF0YS5uYW1lID0gdGhpcy5uYW1lO1xuXHRcdGlmICggT2JqZWN0LmtleXMoIHRoaXMudXNlckRhdGEgKS5sZW5ndGggPiAwICkgZGF0YS51c2VyRGF0YSA9IHRoaXMudXNlckRhdGE7XG5cblx0XHRpZiAoIHRoaXMucGFyYW1ldGVycyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjb25zdCBwYXJhbWV0ZXJzID0gdGhpcy5wYXJhbWV0ZXJzO1xuXG5cdFx0XHRmb3IgKCBjb25zdCBrZXkgaW4gcGFyYW1ldGVycyApIHtcblxuXHRcdFx0XHRpZiAoIHBhcmFtZXRlcnNbIGtleSBdICE9PSB1bmRlZmluZWQgKSBkYXRhWyBrZXkgXSA9IHBhcmFtZXRlcnNbIGtleSBdO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBkYXRhO1xuXG5cdFx0fVxuXG5cdFx0Ly8gZm9yIHNpbXBsaWNpdHkgdGhlIGNvZGUgYXNzdW1lcyBhdHRyaWJ1dGVzIGFyZSBub3Qgc2hhcmVkIGFjcm9zcyBnZW9tZXRyaWVzLCBzZWUgIzE1ODExXG5cblx0XHRkYXRhLmRhdGEgPSB7IGF0dHJpYnV0ZXM6IHt9IH07XG5cblx0XHRjb25zdCBpbmRleCA9IHRoaXMuaW5kZXg7XG5cblx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xuXG5cdFx0XHRkYXRhLmRhdGEuaW5kZXggPSB7XG5cdFx0XHRcdHR5cGU6IGluZGV4LmFycmF5LmNvbnN0cnVjdG9yLm5hbWUsXG5cdFx0XHRcdGFycmF5OiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCggaW5kZXguYXJyYXkgKVxuXHRcdFx0fTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSB0aGlzLmF0dHJpYnV0ZXM7XG5cblx0XHRmb3IgKCBjb25zdCBrZXkgaW4gYXR0cmlidXRlcyApIHtcblxuXHRcdFx0Y29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlc1sga2V5IF07XG5cblx0XHRcdGRhdGEuZGF0YS5hdHRyaWJ1dGVzWyBrZXkgXSA9IGF0dHJpYnV0ZS50b0pTT04oIGRhdGEuZGF0YSApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzID0ge307XG5cdFx0bGV0IGhhc01vcnBoQXR0cmlidXRlcyA9IGZhbHNlO1xuXG5cdFx0Zm9yICggY29uc3Qga2V5IGluIHRoaXMubW9ycGhBdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRjb25zdCBhdHRyaWJ1dGVBcnJheSA9IHRoaXMubW9ycGhBdHRyaWJ1dGVzWyBrZXkgXTtcblxuXHRcdFx0Y29uc3QgYXJyYXkgPSBbXTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGF0dHJpYnV0ZUFycmF5Lmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZUFycmF5WyBpIF07XG5cblx0XHRcdFx0YXJyYXkucHVzaCggYXR0cmlidXRlLnRvSlNPTiggZGF0YS5kYXRhICkgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGFycmF5Lmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdFx0bW9ycGhBdHRyaWJ1dGVzWyBrZXkgXSA9IGFycmF5O1xuXG5cdFx0XHRcdGhhc01vcnBoQXR0cmlidXRlcyA9IHRydWU7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggaGFzTW9ycGhBdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRkYXRhLmRhdGEubW9ycGhBdHRyaWJ1dGVzID0gbW9ycGhBdHRyaWJ1dGVzO1xuXHRcdFx0ZGF0YS5kYXRhLm1vcnBoVGFyZ2V0c1JlbGF0aXZlID0gdGhpcy5tb3JwaFRhcmdldHNSZWxhdGl2ZTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGdyb3VwcyA9IHRoaXMuZ3JvdXBzO1xuXG5cdFx0aWYgKCBncm91cHMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0ZGF0YS5kYXRhLmdyb3VwcyA9IEpTT04ucGFyc2UoIEpTT04uc3RyaW5naWZ5KCBncm91cHMgKSApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgYm91bmRpbmdTcGhlcmUgPSB0aGlzLmJvdW5kaW5nU3BoZXJlO1xuXG5cdFx0aWYgKCBib3VuZGluZ1NwaGVyZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0ZGF0YS5kYXRhLmJvdW5kaW5nU3BoZXJlID0ge1xuXHRcdFx0XHRjZW50ZXI6IGJvdW5kaW5nU3BoZXJlLmNlbnRlci50b0FycmF5KCksXG5cdFx0XHRcdHJhZGl1czogYm91bmRpbmdTcGhlcmUucmFkaXVzXG5cdFx0XHR9O1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHQvLyByZXNldFxuXG5cdFx0dGhpcy5pbmRleCA9IG51bGw7XG5cdFx0dGhpcy5hdHRyaWJ1dGVzID0ge307XG5cdFx0dGhpcy5tb3JwaEF0dHJpYnV0ZXMgPSB7fTtcblx0XHR0aGlzLmdyb3VwcyA9IFtdO1xuXHRcdHRoaXMuYm91bmRpbmdCb3ggPSBudWxsO1xuXHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBudWxsO1xuXG5cdFx0Ly8gdXNlZCBmb3Igc3RvcmluZyBjbG9uZWQsIHNoYXJlZCBkYXRhXG5cblx0XHRjb25zdCBkYXRhID0ge307XG5cblx0XHQvLyBuYW1lXG5cblx0XHR0aGlzLm5hbWUgPSBzb3VyY2UubmFtZTtcblxuXHRcdC8vIGluZGV4XG5cblx0XHRjb25zdCBpbmRleCA9IHNvdXJjZS5pbmRleDtcblxuXHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuc2V0SW5kZXgoIGluZGV4LmNsb25lKCBkYXRhICkgKTtcblxuXHRcdH1cblxuXHRcdC8vIGF0dHJpYnV0ZXNcblxuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSBzb3VyY2UuYXR0cmlidXRlcztcblxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gYXR0cmlidXRlcyApIHtcblxuXHRcdFx0Y29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlc1sgbmFtZSBdO1xuXHRcdFx0dGhpcy5zZXRBdHRyaWJ1dGUoIG5hbWUsIGF0dHJpYnV0ZS5jbG9uZSggZGF0YSApICk7XG5cblx0XHR9XG5cblx0XHQvLyBtb3JwaCBhdHRyaWJ1dGVzXG5cblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBzb3VyY2UubW9ycGhBdHRyaWJ1dGVzO1xuXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBtb3JwaEF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdGNvbnN0IGFycmF5ID0gW107XG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlc1sgbmFtZSBdOyAvLyBtb3JwaEF0dHJpYnV0ZTogYXJyYXkgb2YgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZXNcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gbW9ycGhBdHRyaWJ1dGUubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRhcnJheS5wdXNoKCBtb3JwaEF0dHJpYnV0ZVsgaSBdLmNsb25lKCBkYXRhICkgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLm1vcnBoQXR0cmlidXRlc1sgbmFtZSBdID0gYXJyYXk7XG5cblx0XHR9XG5cblx0XHR0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlID0gc291cmNlLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xuXG5cdFx0Ly8gZ3JvdXBzXG5cblx0XHRjb25zdCBncm91cHMgPSBzb3VyY2UuZ3JvdXBzO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBpIF07XG5cdFx0XHR0aGlzLmFkZEdyb3VwKCBncm91cC5zdGFydCwgZ3JvdXAuY291bnQsIGdyb3VwLm1hdGVyaWFsSW5kZXggKTtcblxuXHRcdH1cblxuXHRcdC8vIGJvdW5kaW5nIGJveFxuXG5cdFx0Y29uc3QgYm91bmRpbmdCb3ggPSBzb3VyY2UuYm91bmRpbmdCb3g7XG5cblx0XHRpZiAoIGJvdW5kaW5nQm94ICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94ID0gYm91bmRpbmdCb3guY2xvbmUoKTtcblxuXHRcdH1cblxuXHRcdC8vIGJvdW5kaW5nIHNwaGVyZVxuXG5cdFx0Y29uc3QgYm91bmRpbmdTcGhlcmUgPSBzb3VyY2UuYm91bmRpbmdTcGhlcmU7XG5cblx0XHRpZiAoIGJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlID0gYm91bmRpbmdTcGhlcmUuY2xvbmUoKTtcblxuXHRcdH1cblxuXHRcdC8vIGRyYXcgcmFuZ2VcblxuXHRcdHRoaXMuZHJhd1JhbmdlLnN0YXJ0ID0gc291cmNlLmRyYXdSYW5nZS5zdGFydDtcblx0XHR0aGlzLmRyYXdSYW5nZS5jb3VudCA9IHNvdXJjZS5kcmF3UmFuZ2UuY291bnQ7XG5cblx0XHQvLyB1c2VyIGRhdGFcblxuXHRcdHRoaXMudXNlckRhdGEgPSBzb3VyY2UudXNlckRhdGE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzcG9zZScgfSApO1xuXG5cdH1cblxufVxuXG5jb25zdCBfaW52ZXJzZU1hdHJpeCQzID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX3JheSQzID0gLypAX19QVVJFX18qLyBuZXcgUmF5KCk7XG5jb25zdCBfc3BoZXJlJDYgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcbmNvbnN0IF9zcGhlcmVIaXRBdCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY29uc3QgX3ZBJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdkIkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92QyQxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jb25zdCBfdGVtcEEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfbW9ycGhBID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jb25zdCBfdXZBJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XG5jb25zdCBfdXZCJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XG5jb25zdCBfdXZDJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XG5cbmNvbnN0IF9ub3JtYWxBID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX25vcm1hbEIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfbm9ybWFsQyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY29uc3QgX2ludGVyc2VjdGlvblBvaW50ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2ludGVyc2VjdGlvblBvaW50V29ybGQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNsYXNzIE1lc2ggZXh0ZW5kcyBPYmplY3QzRCB7XG5cblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCksIG1hdGVyaWFsID0gbmV3IE1lc2hCYXNpY01hdGVyaWFsKCkgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc01lc2ggPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ01lc2gnO1xuXG5cdFx0dGhpcy5nZW9tZXRyeSA9IGdlb21ldHJ5O1xuXHRcdHRoaXMubWF0ZXJpYWwgPSBtYXRlcmlhbDtcblxuXHRcdHRoaXMudXBkYXRlTW9ycGhUYXJnZXRzKCk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcblxuXHRcdGlmICggc291cmNlLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcyA9IHNvdXJjZS5tb3JwaFRhcmdldEluZmx1ZW5jZXMuc2xpY2UoKTtcblxuXHRcdH1cblxuXHRcdGlmICggc291cmNlLm1vcnBoVGFyZ2V0RGljdGlvbmFyeSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLm1vcnBoVGFyZ2V0RGljdGlvbmFyeSA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UubW9ycGhUYXJnZXREaWN0aW9uYXJ5ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLm1hdGVyaWFsID0gQXJyYXkuaXNBcnJheSggc291cmNlLm1hdGVyaWFsICkgPyBzb3VyY2UubWF0ZXJpYWwuc2xpY2UoKSA6IHNvdXJjZS5tYXRlcmlhbDtcblx0XHR0aGlzLmdlb21ldHJ5ID0gc291cmNlLmdlb21ldHJ5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHVwZGF0ZU1vcnBoVGFyZ2V0cygpIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcblxuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlcyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcztcblx0XHRjb25zdCBrZXlzID0gT2JqZWN0LmtleXMoIG1vcnBoQXR0cmlidXRlcyApO1xuXG5cdFx0aWYgKCBrZXlzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gbW9ycGhBdHRyaWJ1dGVzWyBrZXlzWyAwIF0gXTtcblxuXHRcdFx0aWYgKCBtb3JwaEF0dHJpYnV0ZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHRoaXMubW9ycGhUYXJnZXRJbmZsdWVuY2VzID0gW107XG5cdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5ID0ge307XG5cblx0XHRcdFx0Zm9yICggbGV0IG0gPSAwLCBtbCA9IG1vcnBoQXR0cmlidXRlLmxlbmd0aDsgbSA8IG1sOyBtICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgbmFtZSA9IG1vcnBoQXR0cmlidXRlWyBtIF0ubmFtZSB8fCBTdHJpbmcoIG0gKTtcblxuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXRJbmZsdWVuY2VzLnB1c2goIDAgKTtcblx0XHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0RGljdGlvbmFyeVsgbmFtZSBdID0gbTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0Z2V0VmVydGV4UG9zaXRpb24oIGluZGV4LCB0YXJnZXQgKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXHRcdGNvbnN0IG1vcnBoUG9zaXRpb24gPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb247XG5cdFx0Y29uc3QgbW9ycGhUYXJnZXRzUmVsYXRpdmUgPSBnZW9tZXRyeS5tb3JwaFRhcmdldHNSZWxhdGl2ZTtcblxuXHRcdHRhcmdldC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXggKTtcblxuXHRcdGNvbnN0IG1vcnBoSW5mbHVlbmNlcyA9IHRoaXMubW9ycGhUYXJnZXRJbmZsdWVuY2VzO1xuXG5cdFx0aWYgKCBtb3JwaFBvc2l0aW9uICYmIG1vcnBoSW5mbHVlbmNlcyApIHtcblxuXHRcdFx0X21vcnBoQS5zZXQoIDAsIDAsIDAgKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IG1vcnBoUG9zaXRpb24ubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgaW5mbHVlbmNlID0gbW9ycGhJbmZsdWVuY2VzWyBpIF07XG5cdFx0XHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gbW9ycGhQb3NpdGlvblsgaSBdO1xuXG5cdFx0XHRcdGlmICggaW5mbHVlbmNlID09PSAwICkgY29udGludWU7XG5cblx0XHRcdFx0X3RlbXBBLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoQXR0cmlidXRlLCBpbmRleCApO1xuXG5cdFx0XHRcdGlmICggbW9ycGhUYXJnZXRzUmVsYXRpdmUgKSB7XG5cblx0XHRcdFx0XHRfbW9ycGhBLmFkZFNjYWxlZFZlY3RvciggX3RlbXBBLCBpbmZsdWVuY2UgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0X21vcnBoQS5hZGRTY2FsZWRWZWN0b3IoIF90ZW1wQS5zdWIoIHRhcmdldCApLCBpbmZsdWVuY2UgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0dGFyZ2V0LmFkZCggX21vcnBoQSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0cmF5Y2FzdCggcmF5Y2FzdGVyLCBpbnRlcnNlY3RzICkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGNvbnN0IG1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbDtcblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XG5cblx0XHRpZiAoIG1hdGVyaWFsID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHQvLyB0ZXN0IHdpdGggYm91bmRpbmcgc3BoZXJlIGluIHdvcmxkIHNwYWNlXG5cblx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkgZ2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XG5cblx0XHRfc3BoZXJlJDYuY29weSggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgKTtcblx0XHRfc3BoZXJlJDYuYXBwbHlNYXRyaXg0KCBtYXRyaXhXb3JsZCApO1xuXG5cdFx0Ly8gY2hlY2sgZGlzdGFuY2UgZnJvbSByYXkgb3JpZ2luIHRvIGJvdW5kaW5nIHNwaGVyZVxuXG5cdFx0X3JheSQzLmNvcHkoIHJheWNhc3Rlci5yYXkgKS5yZWNhc3QoIHJheWNhc3Rlci5uZWFyICk7XG5cblx0XHRpZiAoIF9zcGhlcmUkNi5jb250YWluc1BvaW50KCBfcmF5JDMub3JpZ2luICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRpZiAoIF9yYXkkMy5pbnRlcnNlY3RTcGhlcmUoIF9zcGhlcmUkNiwgX3NwaGVyZUhpdEF0ICkgPT09IG51bGwgKSByZXR1cm47XG5cblx0XHRcdGlmICggX3JheSQzLm9yaWdpbi5kaXN0YW5jZVRvU3F1YXJlZCggX3NwaGVyZUhpdEF0ICkgPiAoIHJheWNhc3Rlci5mYXIgLSByYXljYXN0ZXIubmVhciApICoqIDIgKSByZXR1cm47XG5cblx0XHR9XG5cblx0XHQvLyBjb252ZXJ0IHJheSB0byBsb2NhbCBzcGFjZSBvZiBtZXNoXG5cblx0XHRfaW52ZXJzZU1hdHJpeCQzLmNvcHkoIG1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cdFx0X3JheSQzLmNvcHkoIHJheWNhc3Rlci5yYXkgKS5hcHBseU1hdHJpeDQoIF9pbnZlcnNlTWF0cml4JDMgKTtcblxuXHRcdC8vIHRlc3Qgd2l0aCBib3VuZGluZyBib3ggaW4gbG9jYWwgc3BhY2VcblxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdCb3ggIT09IG51bGwgKSB7XG5cblx0XHRcdGlmICggX3JheSQzLmludGVyc2VjdHNCb3goIGdlb21ldHJ5LmJvdW5kaW5nQm94ICkgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0Ly8gdGVzdCBmb3IgaW50ZXJzZWN0aW9ucyB3aXRoIGdlb21ldHJ5XG5cblx0XHR0aGlzLl9jb21wdXRlSW50ZXJzZWN0aW9ucyggcmF5Y2FzdGVyLCBpbnRlcnNlY3RzLCBfcmF5JDMgKTtcblxuXHR9XG5cblx0X2NvbXB1dGVJbnRlcnNlY3Rpb25zKCByYXljYXN0ZXIsIGludGVyc2VjdHMsIHJheUxvY2FsU3BhY2UgKSB7XG5cblx0XHRsZXQgaW50ZXJzZWN0aW9uO1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGNvbnN0IG1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbDtcblxuXHRcdGNvbnN0IGluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XG5cdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXHRcdGNvbnN0IHV2ID0gZ2VvbWV0cnkuYXR0cmlidXRlcy51djtcblx0XHRjb25zdCB1djEgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnV2MTtcblx0XHRjb25zdCBub3JtYWwgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLm5vcm1hbDtcblx0XHRjb25zdCBncm91cHMgPSBnZW9tZXRyeS5ncm91cHM7XG5cdFx0Y29uc3QgZHJhd1JhbmdlID0gZ2VvbWV0cnkuZHJhd1JhbmdlO1xuXG5cdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcblxuXHRcdFx0Ly8gaW5kZXhlZCBidWZmZXIgZ2VvbWV0cnlcblxuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBtYXRlcmlhbCApICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBncm91cHMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xuXHRcdFx0XHRcdGNvbnN0IGdyb3VwTWF0ZXJpYWwgPSBtYXRlcmlhbFsgZ3JvdXAubWF0ZXJpYWxJbmRleCBdO1xuXG5cdFx0XHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggZ3JvdXAuc3RhcnQsIGRyYXdSYW5nZS5zdGFydCApO1xuXHRcdFx0XHRcdGNvbnN0IGVuZCA9IE1hdGgubWluKCBpbmRleC5jb3VudCwgTWF0aC5taW4oICggZ3JvdXAuc3RhcnQgKyBncm91cC5jb3VudCApLCAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICkgKTtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gc3RhcnQsIGpsID0gZW5kOyBqIDwgamw7IGogKz0gMyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgYSA9IGluZGV4LmdldFgoIGogKTtcblx0XHRcdFx0XHRcdGNvbnN0IGIgPSBpbmRleC5nZXRYKCBqICsgMSApO1xuXHRcdFx0XHRcdFx0Y29uc3QgYyA9IGluZGV4LmdldFgoIGogKyAyICk7XG5cblx0XHRcdFx0XHRcdGludGVyc2VjdGlvbiA9IGNoZWNrR2VvbWV0cnlJbnRlcnNlY3Rpb24oIHRoaXMsIGdyb3VwTWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5TG9jYWxTcGFjZSwgdXYsIHV2MSwgbm9ybWFsLCBhLCBiLCBjICk7XG5cblx0XHRcdFx0XHRcdGlmICggaW50ZXJzZWN0aW9uICkge1xuXG5cdFx0XHRcdFx0XHRcdGludGVyc2VjdGlvbi5mYWNlSW5kZXggPSBNYXRoLmZsb29yKCBqIC8gMyApOyAvLyB0cmlhbmdsZSBudW1iZXIgaW4gaW5kZXhlZCBidWZmZXIgc2VtYW50aWNzXG5cdFx0XHRcdFx0XHRcdGludGVyc2VjdGlvbi5mYWNlLm1hdGVyaWFsSW5kZXggPSBncm91cC5tYXRlcmlhbEluZGV4O1xuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdGlvbiApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNvbnN0IHN0YXJ0ID0gTWF0aC5tYXgoIDAsIGRyYXdSYW5nZS5zdGFydCApO1xuXHRcdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggaW5kZXguY291bnQsICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IHN0YXJ0LCBpbCA9IGVuZDsgaSA8IGlsOyBpICs9IDMgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBhID0gaW5kZXguZ2V0WCggaSApO1xuXHRcdFx0XHRcdGNvbnN0IGIgPSBpbmRleC5nZXRYKCBpICsgMSApO1xuXHRcdFx0XHRcdGNvbnN0IGMgPSBpbmRleC5nZXRYKCBpICsgMiApO1xuXG5cdFx0XHRcdFx0aW50ZXJzZWN0aW9uID0gY2hlY2tHZW9tZXRyeUludGVyc2VjdGlvbiggdGhpcywgbWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5TG9jYWxTcGFjZSwgdXYsIHV2MSwgbm9ybWFsLCBhLCBiLCBjICk7XG5cblx0XHRcdFx0XHRpZiAoIGludGVyc2VjdGlvbiApIHtcblxuXHRcdFx0XHRcdFx0aW50ZXJzZWN0aW9uLmZhY2VJbmRleCA9IE1hdGguZmxvb3IoIGkgLyAzICk7IC8vIHRyaWFuZ2xlIG51bWJlciBpbiBpbmRleGVkIGJ1ZmZlciBzZW1hbnRpY3Ncblx0XHRcdFx0XHRcdGludGVyc2VjdHMucHVzaCggaW50ZXJzZWN0aW9uICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2UgaWYgKCBwb3NpdGlvbiAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHQvLyBub24taW5kZXhlZCBidWZmZXIgZ2VvbWV0cnlcblxuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBtYXRlcmlhbCApICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBncm91cHMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xuXHRcdFx0XHRcdGNvbnN0IGdyb3VwTWF0ZXJpYWwgPSBtYXRlcmlhbFsgZ3JvdXAubWF0ZXJpYWxJbmRleCBdO1xuXG5cdFx0XHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggZ3JvdXAuc3RhcnQsIGRyYXdSYW5nZS5zdGFydCApO1xuXHRcdFx0XHRcdGNvbnN0IGVuZCA9IE1hdGgubWluKCBwb3NpdGlvbi5jb3VudCwgTWF0aC5taW4oICggZ3JvdXAuc3RhcnQgKyBncm91cC5jb3VudCApLCAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICkgKTtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gc3RhcnQsIGpsID0gZW5kOyBqIDwgamw7IGogKz0gMyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgYSA9IGo7XG5cdFx0XHRcdFx0XHRjb25zdCBiID0gaiArIDE7XG5cdFx0XHRcdFx0XHRjb25zdCBjID0gaiArIDI7XG5cblx0XHRcdFx0XHRcdGludGVyc2VjdGlvbiA9IGNoZWNrR2VvbWV0cnlJbnRlcnNlY3Rpb24oIHRoaXMsIGdyb3VwTWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5TG9jYWxTcGFjZSwgdXYsIHV2MSwgbm9ybWFsLCBhLCBiLCBjICk7XG5cblx0XHRcdFx0XHRcdGlmICggaW50ZXJzZWN0aW9uICkge1xuXG5cdFx0XHRcdFx0XHRcdGludGVyc2VjdGlvbi5mYWNlSW5kZXggPSBNYXRoLmZsb29yKCBqIC8gMyApOyAvLyB0cmlhbmdsZSBudW1iZXIgaW4gbm9uLWluZGV4ZWQgYnVmZmVyIHNlbWFudGljc1xuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3Rpb24uZmFjZS5tYXRlcmlhbEluZGV4ID0gZ3JvdXAubWF0ZXJpYWxJbmRleDtcblx0XHRcdFx0XHRcdFx0aW50ZXJzZWN0cy5wdXNoKCBpbnRlcnNlY3Rpb24gKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zdCBzdGFydCA9IE1hdGgubWF4KCAwLCBkcmF3UmFuZ2Uuc3RhcnQgKTtcblx0XHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIHBvc2l0aW9uLmNvdW50LCAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICk7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSBzdGFydCwgaWwgPSBlbmQ7IGkgPCBpbDsgaSArPSAzICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgYSA9IGk7XG5cdFx0XHRcdFx0Y29uc3QgYiA9IGkgKyAxO1xuXHRcdFx0XHRcdGNvbnN0IGMgPSBpICsgMjtcblxuXHRcdFx0XHRcdGludGVyc2VjdGlvbiA9IGNoZWNrR2VvbWV0cnlJbnRlcnNlY3Rpb24oIHRoaXMsIG1hdGVyaWFsLCByYXljYXN0ZXIsIHJheUxvY2FsU3BhY2UsIHV2LCB1djEsIG5vcm1hbCwgYSwgYiwgYyApO1xuXG5cdFx0XHRcdFx0aWYgKCBpbnRlcnNlY3Rpb24gKSB7XG5cblx0XHRcdFx0XHRcdGludGVyc2VjdGlvbi5mYWNlSW5kZXggPSBNYXRoLmZsb29yKCBpIC8gMyApOyAvLyB0cmlhbmdsZSBudW1iZXIgaW4gbm9uLWluZGV4ZWQgYnVmZmVyIHNlbWFudGljc1xuXHRcdFx0XHRcdFx0aW50ZXJzZWN0cy5wdXNoKCBpbnRlcnNlY3Rpb24gKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gY2hlY2tJbnRlcnNlY3Rpb24kMSggb2JqZWN0LCBtYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXksIHBBLCBwQiwgcEMsIHBvaW50ICkge1xuXG5cdGxldCBpbnRlcnNlY3Q7XG5cblx0aWYgKCBtYXRlcmlhbC5zaWRlID09PSBCYWNrU2lkZSApIHtcblxuXHRcdGludGVyc2VjdCA9IHJheS5pbnRlcnNlY3RUcmlhbmdsZSggcEMsIHBCLCBwQSwgdHJ1ZSwgcG9pbnQgKTtcblxuXHR9IGVsc2Uge1xuXG5cdFx0aW50ZXJzZWN0ID0gcmF5LmludGVyc2VjdFRyaWFuZ2xlKCBwQSwgcEIsIHBDLCAoIG1hdGVyaWFsLnNpZGUgPT09IEZyb250U2lkZSApLCBwb2ludCApO1xuXG5cdH1cblxuXHRpZiAoIGludGVyc2VjdCA9PT0gbnVsbCApIHJldHVybiBudWxsO1xuXG5cdF9pbnRlcnNlY3Rpb25Qb2ludFdvcmxkLmNvcHkoIHBvaW50ICk7XG5cdF9pbnRlcnNlY3Rpb25Qb2ludFdvcmxkLmFwcGx5TWF0cml4NCggb2JqZWN0Lm1hdHJpeFdvcmxkICk7XG5cblx0Y29uc3QgZGlzdGFuY2UgPSByYXljYXN0ZXIucmF5Lm9yaWdpbi5kaXN0YW5jZVRvKCBfaW50ZXJzZWN0aW9uUG9pbnRXb3JsZCApO1xuXG5cdGlmICggZGlzdGFuY2UgPCByYXljYXN0ZXIubmVhciB8fCBkaXN0YW5jZSA+IHJheWNhc3Rlci5mYXIgKSByZXR1cm4gbnVsbDtcblxuXHRyZXR1cm4ge1xuXHRcdGRpc3RhbmNlOiBkaXN0YW5jZSxcblx0XHRwb2ludDogX2ludGVyc2VjdGlvblBvaW50V29ybGQuY2xvbmUoKSxcblx0XHRvYmplY3Q6IG9iamVjdFxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIGNoZWNrR2VvbWV0cnlJbnRlcnNlY3Rpb24oIG9iamVjdCwgbWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5LCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKSB7XG5cblx0b2JqZWN0LmdldFZlcnRleFBvc2l0aW9uKCBhLCBfdkEkMSApO1xuXHRvYmplY3QuZ2V0VmVydGV4UG9zaXRpb24oIGIsIF92QiQxICk7XG5cdG9iamVjdC5nZXRWZXJ0ZXhQb3NpdGlvbiggYywgX3ZDJDEgKTtcblxuXHRjb25zdCBpbnRlcnNlY3Rpb24gPSBjaGVja0ludGVyc2VjdGlvbiQxKCBvYmplY3QsIG1hdGVyaWFsLCByYXljYXN0ZXIsIHJheSwgX3ZBJDEsIF92QiQxLCBfdkMkMSwgX2ludGVyc2VjdGlvblBvaW50ICk7XG5cblx0aWYgKCBpbnRlcnNlY3Rpb24gKSB7XG5cblx0XHRpZiAoIHV2ICkge1xuXG5cdFx0XHRfdXZBJDEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXYsIGEgKTtcblx0XHRcdF91dkIkMS5mcm9tQnVmZmVyQXR0cmlidXRlKCB1diwgYiApO1xuXHRcdFx0X3V2QyQxLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHV2LCBjICk7XG5cblx0XHRcdGludGVyc2VjdGlvbi51diA9IFRyaWFuZ2xlLmdldEludGVycG9sYXRpb24oIF9pbnRlcnNlY3Rpb25Qb2ludCwgX3ZBJDEsIF92QiQxLCBfdkMkMSwgX3V2QSQxLCBfdXZCJDEsIF91dkMkMSwgbmV3IFZlY3RvcjIoKSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB1djEgKSB7XG5cblx0XHRcdF91dkEkMS5mcm9tQnVmZmVyQXR0cmlidXRlKCB1djEsIGEgKTtcblx0XHRcdF91dkIkMS5mcm9tQnVmZmVyQXR0cmlidXRlKCB1djEsIGIgKTtcblx0XHRcdF91dkMkMS5mcm9tQnVmZmVyQXR0cmlidXRlKCB1djEsIGMgKTtcblxuXHRcdFx0aW50ZXJzZWN0aW9uLnV2MSA9IFRyaWFuZ2xlLmdldEludGVycG9sYXRpb24oIF9pbnRlcnNlY3Rpb25Qb2ludCwgX3ZBJDEsIF92QiQxLCBfdkMkMSwgX3V2QSQxLCBfdXZCJDEsIF91dkMkMSwgbmV3IFZlY3RvcjIoKSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBub3JtYWwgKSB7XG5cblx0XHRcdF9ub3JtYWxBLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbCwgYSApO1xuXHRcdFx0X25vcm1hbEIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFsLCBiICk7XG5cdFx0XHRfbm9ybWFsQy5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWwsIGMgKTtcblxuXHRcdFx0aW50ZXJzZWN0aW9uLm5vcm1hbCA9IFRyaWFuZ2xlLmdldEludGVycG9sYXRpb24oIF9pbnRlcnNlY3Rpb25Qb2ludCwgX3ZBJDEsIF92QiQxLCBfdkMkMSwgX25vcm1hbEEsIF9ub3JtYWxCLCBfbm9ybWFsQywgbmV3IFZlY3RvcjMoKSApO1xuXG5cdFx0XHRpZiAoIGludGVyc2VjdGlvbi5ub3JtYWwuZG90KCByYXkuZGlyZWN0aW9uICkgPiAwICkge1xuXG5cdFx0XHRcdGludGVyc2VjdGlvbi5ub3JtYWwubXVsdGlwbHlTY2FsYXIoIC0gMSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRjb25zdCBmYWNlID0ge1xuXHRcdFx0YTogYSxcblx0XHRcdGI6IGIsXG5cdFx0XHRjOiBjLFxuXHRcdFx0bm9ybWFsOiBuZXcgVmVjdG9yMygpLFxuXHRcdFx0bWF0ZXJpYWxJbmRleDogMFxuXHRcdH07XG5cblx0XHRUcmlhbmdsZS5nZXROb3JtYWwoIF92QSQxLCBfdkIkMSwgX3ZDJDEsIGZhY2Uubm9ybWFsICk7XG5cblx0XHRpbnRlcnNlY3Rpb24uZmFjZSA9IGZhY2U7XG5cblx0fVxuXG5cdHJldHVybiBpbnRlcnNlY3Rpb247XG5cbn1cblxuY2xhc3MgQm94R2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgZGVwdGggPSAxLCB3aWR0aFNlZ21lbnRzID0gMSwgaGVpZ2h0U2VnbWVudHMgPSAxLCBkZXB0aFNlZ21lbnRzID0gMSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnQm94R2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0d2lkdGg6IHdpZHRoLFxuXHRcdFx0aGVpZ2h0OiBoZWlnaHQsXG5cdFx0XHRkZXB0aDogZGVwdGgsXG5cdFx0XHR3aWR0aFNlZ21lbnRzOiB3aWR0aFNlZ21lbnRzLFxuXHRcdFx0aGVpZ2h0U2VnbWVudHM6IGhlaWdodFNlZ21lbnRzLFxuXHRcdFx0ZGVwdGhTZWdtZW50czogZGVwdGhTZWdtZW50c1xuXHRcdH07XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHQvLyBzZWdtZW50c1xuXG5cdFx0d2lkdGhTZWdtZW50cyA9IE1hdGguZmxvb3IoIHdpZHRoU2VnbWVudHMgKTtcblx0XHRoZWlnaHRTZWdtZW50cyA9IE1hdGguZmxvb3IoIGhlaWdodFNlZ21lbnRzICk7XG5cdFx0ZGVwdGhTZWdtZW50cyA9IE1hdGguZmxvb3IoIGRlcHRoU2VnbWVudHMgKTtcblxuXHRcdC8vIGJ1ZmZlcnNcblxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcblx0XHRjb25zdCB1dnMgPSBbXTtcblxuXHRcdC8vIGhlbHBlciB2YXJpYWJsZXNcblxuXHRcdGxldCBudW1iZXJPZlZlcnRpY2VzID0gMDtcblx0XHRsZXQgZ3JvdXBTdGFydCA9IDA7XG5cblx0XHQvLyBidWlsZCBlYWNoIHNpZGUgb2YgdGhlIGJveCBnZW9tZXRyeVxuXG5cdFx0YnVpbGRQbGFuZSggJ3onLCAneScsICd4JywgLSAxLCAtIDEsIGRlcHRoLCBoZWlnaHQsIHdpZHRoLCBkZXB0aFNlZ21lbnRzLCBoZWlnaHRTZWdtZW50cywgMCApOyAvLyBweFxuXHRcdGJ1aWxkUGxhbmUoICd6JywgJ3knLCAneCcsIDEsIC0gMSwgZGVwdGgsIGhlaWdodCwgLSB3aWR0aCwgZGVwdGhTZWdtZW50cywgaGVpZ2h0U2VnbWVudHMsIDEgKTsgLy8gbnhcblx0XHRidWlsZFBsYW5lKCAneCcsICd6JywgJ3knLCAxLCAxLCB3aWR0aCwgZGVwdGgsIGhlaWdodCwgd2lkdGhTZWdtZW50cywgZGVwdGhTZWdtZW50cywgMiApOyAvLyBweVxuXHRcdGJ1aWxkUGxhbmUoICd4JywgJ3onLCAneScsIDEsIC0gMSwgd2lkdGgsIGRlcHRoLCAtIGhlaWdodCwgd2lkdGhTZWdtZW50cywgZGVwdGhTZWdtZW50cywgMyApOyAvLyBueVxuXHRcdGJ1aWxkUGxhbmUoICd4JywgJ3knLCAneicsIDEsIC0gMSwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIHdpZHRoU2VnbWVudHMsIGhlaWdodFNlZ21lbnRzLCA0ICk7IC8vIHB6XG5cdFx0YnVpbGRQbGFuZSggJ3gnLCAneScsICd6JywgLSAxLCAtIDEsIHdpZHRoLCBoZWlnaHQsIC0gZGVwdGgsIHdpZHRoU2VnbWVudHMsIGhlaWdodFNlZ21lbnRzLCA1ICk7IC8vIG56XG5cblx0XHQvLyBidWlsZCBnZW9tZXRyeVxuXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcblxuXHRcdGZ1bmN0aW9uIGJ1aWxkUGxhbmUoIHUsIHYsIHcsIHVkaXIsIHZkaXIsIHdpZHRoLCBoZWlnaHQsIGRlcHRoLCBncmlkWCwgZ3JpZFksIG1hdGVyaWFsSW5kZXggKSB7XG5cblx0XHRcdGNvbnN0IHNlZ21lbnRXaWR0aCA9IHdpZHRoIC8gZ3JpZFg7XG5cdFx0XHRjb25zdCBzZWdtZW50SGVpZ2h0ID0gaGVpZ2h0IC8gZ3JpZFk7XG5cblx0XHRcdGNvbnN0IHdpZHRoSGFsZiA9IHdpZHRoIC8gMjtcblx0XHRcdGNvbnN0IGhlaWdodEhhbGYgPSBoZWlnaHQgLyAyO1xuXHRcdFx0Y29uc3QgZGVwdGhIYWxmID0gZGVwdGggLyAyO1xuXG5cdFx0XHRjb25zdCBncmlkWDEgPSBncmlkWCArIDE7XG5cdFx0XHRjb25zdCBncmlkWTEgPSBncmlkWSArIDE7XG5cblx0XHRcdGxldCB2ZXJ0ZXhDb3VudGVyID0gMDtcblx0XHRcdGxldCBncm91cENvdW50ID0gMDtcblxuXHRcdFx0Y29uc3QgdmVjdG9yID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIG5vcm1hbHMgYW5kIHV2c1xuXG5cdFx0XHRmb3IgKCBsZXQgaXkgPSAwOyBpeSA8IGdyaWRZMTsgaXkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgeSA9IGl5ICogc2VnbWVudEhlaWdodCAtIGhlaWdodEhhbGY7XG5cblx0XHRcdFx0Zm9yICggbGV0IGl4ID0gMDsgaXggPCBncmlkWDE7IGl4ICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgeCA9IGl4ICogc2VnbWVudFdpZHRoIC0gd2lkdGhIYWxmO1xuXG5cdFx0XHRcdFx0Ly8gc2V0IHZhbHVlcyB0byBjb3JyZWN0IHZlY3RvciBjb21wb25lbnRcblxuXHRcdFx0XHRcdHZlY3RvclsgdSBdID0geCAqIHVkaXI7XG5cdFx0XHRcdFx0dmVjdG9yWyB2IF0gPSB5ICogdmRpcjtcblx0XHRcdFx0XHR2ZWN0b3JbIHcgXSA9IGRlcHRoSGFsZjtcblxuXHRcdFx0XHRcdC8vIG5vdyBhcHBseSB2ZWN0b3IgdG8gdmVydGV4IGJ1ZmZlclxuXG5cdFx0XHRcdFx0dmVydGljZXMucHVzaCggdmVjdG9yLngsIHZlY3Rvci55LCB2ZWN0b3IueiApO1xuXG5cdFx0XHRcdFx0Ly8gc2V0IHZhbHVlcyB0byBjb3JyZWN0IHZlY3RvciBjb21wb25lbnRcblxuXHRcdFx0XHRcdHZlY3RvclsgdSBdID0gMDtcblx0XHRcdFx0XHR2ZWN0b3JbIHYgXSA9IDA7XG5cdFx0XHRcdFx0dmVjdG9yWyB3IF0gPSBkZXB0aCA+IDAgPyAxIDogLSAxO1xuXG5cdFx0XHRcdFx0Ly8gbm93IGFwcGx5IHZlY3RvciB0byBub3JtYWwgYnVmZmVyXG5cblx0XHRcdFx0XHRub3JtYWxzLnB1c2goIHZlY3Rvci54LCB2ZWN0b3IueSwgdmVjdG9yLnogKTtcblxuXHRcdFx0XHRcdC8vIHV2c1xuXG5cdFx0XHRcdFx0dXZzLnB1c2goIGl4IC8gZ3JpZFggKTtcblx0XHRcdFx0XHR1dnMucHVzaCggMSAtICggaXkgLyBncmlkWSApICk7XG5cblx0XHRcdFx0XHQvLyBjb3VudGVyc1xuXG5cdFx0XHRcdFx0dmVydGV4Q291bnRlciArPSAxO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBpbmRpY2VzXG5cblx0XHRcdC8vIDEuIHlvdSBuZWVkIHRocmVlIGluZGljZXMgdG8gZHJhdyBhIHNpbmdsZSBmYWNlXG5cdFx0XHQvLyAyLiBhIHNpbmdsZSBzZWdtZW50IGNvbnNpc3RzIG9mIHR3byBmYWNlc1xuXHRcdFx0Ly8gMy4gc28gd2UgbmVlZCB0byBnZW5lcmF0ZSBzaXggKDIqMykgaW5kaWNlcyBwZXIgc2VnbWVudFxuXG5cdFx0XHRmb3IgKCBsZXQgaXkgPSAwOyBpeSA8IGdyaWRZOyBpeSArKyApIHtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaXggPSAwOyBpeCA8IGdyaWRYOyBpeCArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGEgPSBudW1iZXJPZlZlcnRpY2VzICsgaXggKyBncmlkWDEgKiBpeTtcblx0XHRcdFx0XHRjb25zdCBiID0gbnVtYmVyT2ZWZXJ0aWNlcyArIGl4ICsgZ3JpZFgxICogKCBpeSArIDEgKTtcblx0XHRcdFx0XHRjb25zdCBjID0gbnVtYmVyT2ZWZXJ0aWNlcyArICggaXggKyAxICkgKyBncmlkWDEgKiAoIGl5ICsgMSApO1xuXHRcdFx0XHRcdGNvbnN0IGQgPSBudW1iZXJPZlZlcnRpY2VzICsgKCBpeCArIDEgKSArIGdyaWRYMSAqIGl5O1xuXG5cdFx0XHRcdFx0Ly8gZmFjZXNcblxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYiwgYywgZCApO1xuXG5cdFx0XHRcdFx0Ly8gaW5jcmVhc2UgY291bnRlclxuXG5cdFx0XHRcdFx0Z3JvdXBDb3VudCArPSA2O1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBhZGQgYSBncm91cCB0byB0aGUgZ2VvbWV0cnkuIHRoaXMgd2lsbCBlbnN1cmUgbXVsdGkgbWF0ZXJpYWwgc3VwcG9ydFxuXG5cdFx0XHRzY29wZS5hZGRHcm91cCggZ3JvdXBTdGFydCwgZ3JvdXBDb3VudCwgbWF0ZXJpYWxJbmRleCApO1xuXG5cdFx0XHQvLyBjYWxjdWxhdGUgbmV3IHN0YXJ0IHZhbHVlIGZvciBncm91cHNcblxuXHRcdFx0Z3JvdXBTdGFydCArPSBncm91cENvdW50O1xuXG5cdFx0XHQvLyB1cGRhdGUgdG90YWwgbnVtYmVyIG9mIHZlcnRpY2VzXG5cblx0XHRcdG51bWJlck9mVmVydGljZXMgKz0gdmVydGV4Q291bnRlcjtcblxuXHRcdH1cblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IEJveEdlb21ldHJ5KCBkYXRhLndpZHRoLCBkYXRhLmhlaWdodCwgZGF0YS5kZXB0aCwgZGF0YS53aWR0aFNlZ21lbnRzLCBkYXRhLmhlaWdodFNlZ21lbnRzLCBkYXRhLmRlcHRoU2VnbWVudHMgKTtcblxuXHR9XG5cbn1cblxuLyoqXG4gKiBVbmlmb3JtIFV0aWxpdGllc1xuICovXG5cbmZ1bmN0aW9uIGNsb25lVW5pZm9ybXMoIHNyYyApIHtcblxuXHRjb25zdCBkc3QgPSB7fTtcblxuXHRmb3IgKCBjb25zdCB1IGluIHNyYyApIHtcblxuXHRcdGRzdFsgdSBdID0ge307XG5cblx0XHRmb3IgKCBjb25zdCBwIGluIHNyY1sgdSBdICkge1xuXG5cdFx0XHRjb25zdCBwcm9wZXJ0eSA9IHNyY1sgdSBdWyBwIF07XG5cblx0XHRcdGlmICggcHJvcGVydHkgJiYgKCBwcm9wZXJ0eS5pc0NvbG9yIHx8XG5cdFx0XHRcdHByb3BlcnR5LmlzTWF0cml4MyB8fCBwcm9wZXJ0eS5pc01hdHJpeDQgfHxcblx0XHRcdFx0cHJvcGVydHkuaXNWZWN0b3IyIHx8IHByb3BlcnR5LmlzVmVjdG9yMyB8fCBwcm9wZXJ0eS5pc1ZlY3RvcjQgfHxcblx0XHRcdFx0cHJvcGVydHkuaXNUZXh0dXJlIHx8IHByb3BlcnR5LmlzUXVhdGVybmlvbiApICkge1xuXG5cdFx0XHRcdGlmICggcHJvcGVydHkuaXNSZW5kZXJUYXJnZXRUZXh0dXJlICkge1xuXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVW5pZm9ybXNVdGlsczogVGV4dHVyZXMgb2YgcmVuZGVyIHRhcmdldHMgY2Fubm90IGJlIGNsb25lZCB2aWEgY2xvbmVVbmlmb3JtcygpIG9yIG1lcmdlVW5pZm9ybXMoKS4nICk7XG5cdFx0XHRcdFx0ZHN0WyB1IF1bIHAgXSA9IG51bGw7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGRzdFsgdSBdWyBwIF0gPSBwcm9wZXJ0eS5jbG9uZSgpO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIGlmICggQXJyYXkuaXNBcnJheSggcHJvcGVydHkgKSApIHtcblxuXHRcdFx0XHRkc3RbIHUgXVsgcCBdID0gcHJvcGVydHkuc2xpY2UoKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRkc3RbIHUgXVsgcCBdID0gcHJvcGVydHk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0cmV0dXJuIGRzdDtcblxufVxuXG5mdW5jdGlvbiBtZXJnZVVuaWZvcm1zKCB1bmlmb3JtcyApIHtcblxuXHRjb25zdCBtZXJnZWQgPSB7fTtcblxuXHRmb3IgKCBsZXQgdSA9IDA7IHUgPCB1bmlmb3Jtcy5sZW5ndGg7IHUgKysgKSB7XG5cblx0XHRjb25zdCB0bXAgPSBjbG9uZVVuaWZvcm1zKCB1bmlmb3Jtc1sgdSBdICk7XG5cblx0XHRmb3IgKCBjb25zdCBwIGluIHRtcCApIHtcblxuXHRcdFx0bWVyZ2VkWyBwIF0gPSB0bXBbIHAgXTtcblxuXHRcdH1cblxuXHR9XG5cblx0cmV0dXJuIG1lcmdlZDtcblxufVxuXG5mdW5jdGlvbiBjbG9uZVVuaWZvcm1zR3JvdXBzKCBzcmMgKSB7XG5cblx0Y29uc3QgZHN0ID0gW107XG5cblx0Zm9yICggbGV0IHUgPSAwOyB1IDwgc3JjLmxlbmd0aDsgdSArKyApIHtcblxuXHRcdGRzdC5wdXNoKCBzcmNbIHUgXS5jbG9uZSgpICk7XG5cblx0fVxuXG5cdHJldHVybiBkc3Q7XG5cbn1cblxuZnVuY3Rpb24gZ2V0VW5saXRVbmlmb3JtQ29sb3JTcGFjZSggcmVuZGVyZXIgKSB7XG5cblx0Y29uc3QgY3VycmVudFJlbmRlclRhcmdldCA9IHJlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xuXG5cdGlmICggY3VycmVudFJlbmRlclRhcmdldCA9PT0gbnVsbCApIHtcblxuXHRcdC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvcHVsbC8yMzkzNyNpc3N1ZWNvbW1lbnQtMTExMTA2NzM5OFxuXHRcdHJldHVybiByZW5kZXJlci5vdXRwdXRDb2xvclNwYWNlO1xuXG5cdH1cblxuXHQvLyBodHRwczovL2dpdGh1Yi5jb20vbXJkb29iL3RocmVlLmpzL2lzc3Vlcy8yNzg2OFxuXHRpZiAoIGN1cnJlbnRSZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSApIHtcblxuXHRcdHJldHVybiBjdXJyZW50UmVuZGVyVGFyZ2V0LnRleHR1cmUuY29sb3JTcGFjZTtcblxuXHR9XG5cblx0cmV0dXJuIENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZTtcblxufVxuXG4vLyBMZWdhY3lcblxuY29uc3QgVW5pZm9ybXNVdGlscyA9IHsgY2xvbmU6IGNsb25lVW5pZm9ybXMsIG1lcmdlOiBtZXJnZVVuaWZvcm1zIH07XG5cbnZhciBkZWZhdWx0X3ZlcnRleCA9IFwidm9pZCBtYWluKCkge1xcblxcdGdsX1Bvc2l0aW9uID0gcHJvamVjdGlvbk1hdHJpeCAqIG1vZGVsVmlld01hdHJpeCAqIHZlYzQoIHBvc2l0aW9uLCAxLjAgKTtcXG59XCI7XG5cbnZhciBkZWZhdWx0X2ZyYWdtZW50ID0gXCJ2b2lkIG1haW4oKSB7XFxuXFx0Z2xfRnJhZ0NvbG9yID0gdmVjNCggMS4wLCAwLjAsIDAuMCwgMS4wICk7XFxufVwiO1xuXG5jbGFzcyBTaGFkZXJNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzU2hhZGVyTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ1NoYWRlck1hdGVyaWFsJztcblxuXHRcdHRoaXMuZGVmaW5lcyA9IHt9O1xuXHRcdHRoaXMudW5pZm9ybXMgPSB7fTtcblx0XHR0aGlzLnVuaWZvcm1zR3JvdXBzID0gW107XG5cblx0XHR0aGlzLnZlcnRleFNoYWRlciA9IGRlZmF1bHRfdmVydGV4O1xuXHRcdHRoaXMuZnJhZ21lbnRTaGFkZXIgPSBkZWZhdWx0X2ZyYWdtZW50O1xuXG5cdFx0dGhpcy5saW5ld2lkdGggPSAxO1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XG5cblx0XHR0aGlzLmZvZyA9IGZhbHNlOyAvLyBzZXQgdG8gdXNlIHNjZW5lIGZvZ1xuXHRcdHRoaXMubGlnaHRzID0gZmFsc2U7IC8vIHNldCB0byB1c2Ugc2NlbmUgbGlnaHRzXG5cdFx0dGhpcy5jbGlwcGluZyA9IGZhbHNlOyAvLyBzZXQgdG8gdXNlIHVzZXItZGVmaW5lZCBjbGlwcGluZyBwbGFuZXNcblxuXHRcdHRoaXMuZm9yY2VTaW5nbGVQYXNzID0gdHJ1ZTtcblxuXHRcdHRoaXMuZXh0ZW5zaW9ucyA9IHtcblx0XHRcdGNsaXBDdWxsRGlzdGFuY2U6IGZhbHNlLCAvLyBzZXQgdG8gdXNlIHZlcnRleCBzaGFkZXIgY2xpcHBpbmdcblx0XHRcdG11bHRpRHJhdzogZmFsc2UgLy8gc2V0IHRvIHVzZSB2ZXJ0ZXggc2hhZGVyIG11bHRpX2RyYXcgLyBlbmFibGUgZ2xfRHJhd0lEXG5cdFx0fTtcblxuXHRcdC8vIFdoZW4gcmVuZGVyZWQgZ2VvbWV0cnkgZG9lc24ndCBpbmNsdWRlIHRoZXNlIGF0dHJpYnV0ZXMgYnV0IHRoZSBtYXRlcmlhbCBkb2VzLFxuXHRcdC8vIHVzZSB0aGVzZSBkZWZhdWx0IHZhbHVlcyBpbiBXZWJHTC4gVGhpcyBhdm9pZHMgZXJyb3JzIHdoZW4gYnVmZmVyIGRhdGEgaXMgbWlzc2luZy5cblx0XHR0aGlzLmRlZmF1bHRBdHRyaWJ1dGVWYWx1ZXMgPSB7XG5cdFx0XHQnY29sb3InOiBbIDEsIDEsIDEgXSxcblx0XHRcdCd1dic6IFsgMCwgMCBdLFxuXHRcdFx0J3V2MSc6IFsgMCwgMCBdXG5cdFx0fTtcblxuXHRcdHRoaXMuaW5kZXgwQXR0cmlidXRlTmFtZSA9IHVuZGVmaW5lZDtcblx0XHR0aGlzLnVuaWZvcm1zTmVlZFVwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0dGhpcy5nbHNsVmVyc2lvbiA9IG51bGw7XG5cblx0XHRpZiAoIHBhcmFtZXRlcnMgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLmZyYWdtZW50U2hhZGVyID0gc291cmNlLmZyYWdtZW50U2hhZGVyO1xuXHRcdHRoaXMudmVydGV4U2hhZGVyID0gc291cmNlLnZlcnRleFNoYWRlcjtcblxuXHRcdHRoaXMudW5pZm9ybXMgPSBjbG9uZVVuaWZvcm1zKCBzb3VyY2UudW5pZm9ybXMgKTtcblx0XHR0aGlzLnVuaWZvcm1zR3JvdXBzID0gY2xvbmVVbmlmb3Jtc0dyb3Vwcyggc291cmNlLnVuaWZvcm1zR3JvdXBzICk7XG5cblx0XHR0aGlzLmRlZmluZXMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLmRlZmluZXMgKTtcblxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XG5cblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XG5cdFx0dGhpcy5saWdodHMgPSBzb3VyY2UubGlnaHRzO1xuXHRcdHRoaXMuY2xpcHBpbmcgPSBzb3VyY2UuY2xpcHBpbmc7XG5cblx0XHR0aGlzLmV4dGVuc2lvbnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLmV4dGVuc2lvbnMgKTtcblxuXHRcdHRoaXMuZ2xzbFZlcnNpb24gPSBzb3VyY2UuZ2xzbFZlcnNpb247XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCBtZXRhICkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xuXG5cdFx0ZGF0YS5nbHNsVmVyc2lvbiA9IHRoaXMuZ2xzbFZlcnNpb247XG5cdFx0ZGF0YS51bmlmb3JtcyA9IHt9O1xuXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiB0aGlzLnVuaWZvcm1zICkge1xuXG5cdFx0XHRjb25zdCB1bmlmb3JtID0gdGhpcy51bmlmb3Jtc1sgbmFtZSBdO1xuXHRcdFx0Y29uc3QgdmFsdWUgPSB1bmlmb3JtLnZhbHVlO1xuXG5cdFx0XHRpZiAoIHZhbHVlICYmIHZhbHVlLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0XHRkYXRhLnVuaWZvcm1zWyBuYW1lIF0gPSB7XG5cdFx0XHRcdFx0dHlwZTogJ3QnLFxuXHRcdFx0XHRcdHZhbHVlOiB2YWx1ZS50b0pTT04oIG1ldGEgKS51dWlkXG5cdFx0XHRcdH07XG5cblx0XHRcdH0gZWxzZSBpZiAoIHZhbHVlICYmIHZhbHVlLmlzQ29sb3IgKSB7XG5cblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xuXHRcdFx0XHRcdHR5cGU6ICdjJyxcblx0XHRcdFx0XHR2YWx1ZTogdmFsdWUuZ2V0SGV4KClcblx0XHRcdFx0fTtcblxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNWZWN0b3IyICkge1xuXG5cdFx0XHRcdGRhdGEudW5pZm9ybXNbIG5hbWUgXSA9IHtcblx0XHRcdFx0XHR0eXBlOiAndjInLFxuXHRcdFx0XHRcdHZhbHVlOiB2YWx1ZS50b0FycmF5KClcblx0XHRcdFx0fTtcblxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNWZWN0b3IzICkge1xuXG5cdFx0XHRcdGRhdGEudW5pZm9ybXNbIG5hbWUgXSA9IHtcblx0XHRcdFx0XHR0eXBlOiAndjMnLFxuXHRcdFx0XHRcdHZhbHVlOiB2YWx1ZS50b0FycmF5KClcblx0XHRcdFx0fTtcblxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNWZWN0b3I0ICkge1xuXG5cdFx0XHRcdGRhdGEudW5pZm9ybXNbIG5hbWUgXSA9IHtcblx0XHRcdFx0XHR0eXBlOiAndjQnLFxuXHRcdFx0XHRcdHZhbHVlOiB2YWx1ZS50b0FycmF5KClcblx0XHRcdFx0fTtcblxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNNYXRyaXgzICkge1xuXG5cdFx0XHRcdGRhdGEudW5pZm9ybXNbIG5hbWUgXSA9IHtcblx0XHRcdFx0XHR0eXBlOiAnbTMnLFxuXHRcdFx0XHRcdHZhbHVlOiB2YWx1ZS50b0FycmF5KClcblx0XHRcdFx0fTtcblxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNNYXRyaXg0ICkge1xuXG5cdFx0XHRcdGRhdGEudW5pZm9ybXNbIG5hbWUgXSA9IHtcblx0XHRcdFx0XHR0eXBlOiAnbTQnLFxuXHRcdFx0XHRcdHZhbHVlOiB2YWx1ZS50b0FycmF5KClcblx0XHRcdFx0fTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRkYXRhLnVuaWZvcm1zWyBuYW1lIF0gPSB7XG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlXG5cdFx0XHRcdH07XG5cblx0XHRcdFx0Ly8gbm90ZTogdGhlIGFycmF5IHZhcmlhbnRzIHYydiwgdjN2LCB2NHYsIG00diBhbmQgdHYgYXJlIG5vdCBzdXBwb3J0ZWQgc28gZmFyXG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggT2JqZWN0LmtleXMoIHRoaXMuZGVmaW5lcyApLmxlbmd0aCA+IDAgKSBkYXRhLmRlZmluZXMgPSB0aGlzLmRlZmluZXM7XG5cblx0XHRkYXRhLnZlcnRleFNoYWRlciA9IHRoaXMudmVydGV4U2hhZGVyO1xuXHRcdGRhdGEuZnJhZ21lbnRTaGFkZXIgPSB0aGlzLmZyYWdtZW50U2hhZGVyO1xuXG5cdFx0ZGF0YS5saWdodHMgPSB0aGlzLmxpZ2h0cztcblx0XHRkYXRhLmNsaXBwaW5nID0gdGhpcy5jbGlwcGluZztcblxuXHRcdGNvbnN0IGV4dGVuc2lvbnMgPSB7fTtcblxuXHRcdGZvciAoIGNvbnN0IGtleSBpbiB0aGlzLmV4dGVuc2lvbnMgKSB7XG5cblx0XHRcdGlmICggdGhpcy5leHRlbnNpb25zWyBrZXkgXSA9PT0gdHJ1ZSApIGV4dGVuc2lvbnNbIGtleSBdID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdGlmICggT2JqZWN0LmtleXMoIGV4dGVuc2lvbnMgKS5sZW5ndGggPiAwICkgZGF0YS5leHRlbnNpb25zID0gZXh0ZW5zaW9ucztcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxufVxuXG5jbGFzcyBDYW1lcmEgZXh0ZW5kcyBPYmplY3QzRCB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc0NhbWVyYSA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnQ2FtZXJhJztcblxuXHRcdHRoaXMubWF0cml4V29ybGRJbnZlcnNlID0gbmV3IE1hdHJpeDQoKTtcblxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeCA9IG5ldyBNYXRyaXg0KCk7XG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZSA9IG5ldyBNYXRyaXg0KCk7XG5cblx0XHR0aGlzLmNvb3JkaW5hdGVTeXN0ZW0gPSBXZWJHTENvb3JkaW5hdGVTeXN0ZW07XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcblxuXHRcdHRoaXMubWF0cml4V29ybGRJbnZlcnNlLmNvcHkoIHNvdXJjZS5tYXRyaXhXb3JsZEludmVyc2UgKTtcblxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeC5jb3B5KCBzb3VyY2UucHJvamVjdGlvbk1hdHJpeCApO1xuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeEludmVyc2UuY29weSggc291cmNlLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlICk7XG5cblx0XHR0aGlzLmNvb3JkaW5hdGVTeXN0ZW0gPSBzb3VyY2UuY29vcmRpbmF0ZVN5c3RlbTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRXb3JsZERpcmVjdGlvbiggdGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIHN1cGVyLmdldFdvcmxkRGlyZWN0aW9uKCB0YXJnZXQgKS5uZWdhdGUoKTtcblxuXHR9XG5cblx0dXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICkge1xuXG5cdFx0c3VwZXIudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XG5cblx0XHR0aGlzLm1hdHJpeFdvcmxkSW52ZXJzZS5jb3B5KCB0aGlzLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cblx0fVxuXG5cdHVwZGF0ZVdvcmxkTWF0cml4KCB1cGRhdGVQYXJlbnRzLCB1cGRhdGVDaGlsZHJlbiApIHtcblxuXHRcdHN1cGVyLnVwZGF0ZVdvcmxkTWF0cml4KCB1cGRhdGVQYXJlbnRzLCB1cGRhdGVDaGlsZHJlbiApO1xuXG5cdFx0dGhpcy5tYXRyaXhXb3JsZEludmVyc2UuY29weSggdGhpcy5tYXRyaXhXb3JsZCApLmludmVydCgpO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcblxuXHR9XG5cbn1cblxuY29uc3QgX3YzJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfbWluVGFyZ2V0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xuY29uc3QgX21heFRhcmdldCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcblxuXG5jbGFzcyBQZXJzcGVjdGl2ZUNhbWVyYSBleHRlbmRzIENhbWVyYSB7XG5cblx0Y29uc3RydWN0b3IoIGZvdiA9IDUwLCBhc3BlY3QgPSAxLCBuZWFyID0gMC4xLCBmYXIgPSAyMDAwICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNQZXJzcGVjdGl2ZUNhbWVyYSA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnUGVyc3BlY3RpdmVDYW1lcmEnO1xuXG5cdFx0dGhpcy5mb3YgPSBmb3Y7XG5cdFx0dGhpcy56b29tID0gMTtcblxuXHRcdHRoaXMubmVhciA9IG5lYXI7XG5cdFx0dGhpcy5mYXIgPSBmYXI7XG5cdFx0dGhpcy5mb2N1cyA9IDEwO1xuXG5cdFx0dGhpcy5hc3BlY3QgPSBhc3BlY3Q7XG5cdFx0dGhpcy52aWV3ID0gbnVsbDtcblxuXHRcdHRoaXMuZmlsbUdhdWdlID0gMzU7XHQvLyB3aWR0aCBvZiB0aGUgZmlsbSAoZGVmYXVsdCBpbiBtaWxsaW1ldGVycylcblx0XHR0aGlzLmZpbG1PZmZzZXQgPSAwO1x0Ly8gaG9yaXpvbnRhbCBmaWxtIG9mZnNldCAoc2FtZSB1bml0IGFzIGdhdWdlKVxuXG5cdFx0dGhpcy51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcblxuXHRcdHRoaXMuZm92ID0gc291cmNlLmZvdjtcblx0XHR0aGlzLnpvb20gPSBzb3VyY2Uuem9vbTtcblxuXHRcdHRoaXMubmVhciA9IHNvdXJjZS5uZWFyO1xuXHRcdHRoaXMuZmFyID0gc291cmNlLmZhcjtcblx0XHR0aGlzLmZvY3VzID0gc291cmNlLmZvY3VzO1xuXG5cdFx0dGhpcy5hc3BlY3QgPSBzb3VyY2UuYXNwZWN0O1xuXHRcdHRoaXMudmlldyA9IHNvdXJjZS52aWV3ID09PSBudWxsID8gbnVsbCA6IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UudmlldyApO1xuXG5cdFx0dGhpcy5maWxtR2F1Z2UgPSBzb3VyY2UuZmlsbUdhdWdlO1xuXHRcdHRoaXMuZmlsbU9mZnNldCA9IHNvdXJjZS5maWxtT2Zmc2V0O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBTZXRzIHRoZSBGT1YgYnkgZm9jYWwgbGVuZ3RoIGluIHJlc3BlY3QgdG8gdGhlIGN1cnJlbnQgLmZpbG1HYXVnZS5cblx0ICpcblx0ICogVGhlIGRlZmF1bHQgZmlsbSBnYXVnZSBpcyAzNSwgc28gdGhhdCB0aGUgZm9jYWwgbGVuZ3RoIGNhbiBiZSBzcGVjaWZpZWQgZm9yXG5cdCAqIGEgMzVtbSAoZnVsbCBmcmFtZSkgY2FtZXJhLlxuXHQgKlxuXHQgKiBWYWx1ZXMgZm9yIGZvY2FsIGxlbmd0aCBhbmQgZmlsbSBnYXVnZSBtdXN0IGhhdmUgdGhlIHNhbWUgdW5pdC5cblx0ICovXG5cdHNldEZvY2FsTGVuZ3RoKCBmb2NhbExlbmd0aCApIHtcblxuXHRcdC8qKiBzZWUge0BsaW5rIGh0dHA6Ly93d3cuYm9iYXRraW5zLmNvbS9waG90b2dyYXBoeS90ZWNobmljYWwvZmllbGRfb2Zfdmlldy5odG1sfSAqL1xuXHRcdGNvbnN0IHZFeHRlbnRTbG9wZSA9IDAuNSAqIHRoaXMuZ2V0RmlsbUhlaWdodCgpIC8gZm9jYWxMZW5ndGg7XG5cblx0XHR0aGlzLmZvdiA9IFJBRDJERUcgKiAyICogTWF0aC5hdGFuKCB2RXh0ZW50U2xvcGUgKTtcblx0XHR0aGlzLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHR9XG5cblx0LyoqXG5cdCAqIENhbGN1bGF0ZXMgdGhlIGZvY2FsIGxlbmd0aCBmcm9tIHRoZSBjdXJyZW50IC5mb3YgYW5kIC5maWxtR2F1Z2UuXG5cdCAqL1xuXHRnZXRGb2NhbExlbmd0aCgpIHtcblxuXHRcdGNvbnN0IHZFeHRlbnRTbG9wZSA9IE1hdGgudGFuKCBERUcyUkFEICogMC41ICogdGhpcy5mb3YgKTtcblxuXHRcdHJldHVybiAwLjUgKiB0aGlzLmdldEZpbG1IZWlnaHQoKSAvIHZFeHRlbnRTbG9wZTtcblxuXHR9XG5cblx0Z2V0RWZmZWN0aXZlRk9WKCkge1xuXG5cdFx0cmV0dXJuIFJBRDJERUcgKiAyICogTWF0aC5hdGFuKFxuXHRcdFx0TWF0aC50YW4oIERFRzJSQUQgKiAwLjUgKiB0aGlzLmZvdiApIC8gdGhpcy56b29tICk7XG5cblx0fVxuXG5cdGdldEZpbG1XaWR0aCgpIHtcblxuXHRcdC8vIGZpbG0gbm90IGNvbXBsZXRlbHkgY292ZXJlZCBpbiBwb3J0cmFpdCBmb3JtYXQgKGFzcGVjdCA8IDEpXG5cdFx0cmV0dXJuIHRoaXMuZmlsbUdhdWdlICogTWF0aC5taW4oIHRoaXMuYXNwZWN0LCAxICk7XG5cblx0fVxuXG5cdGdldEZpbG1IZWlnaHQoKSB7XG5cblx0XHQvLyBmaWxtIG5vdCBjb21wbGV0ZWx5IGNvdmVyZWQgaW4gbGFuZHNjYXBlIGZvcm1hdCAoYXNwZWN0ID4gMSlcblx0XHRyZXR1cm4gdGhpcy5maWxtR2F1Z2UgLyBNYXRoLm1heCggdGhpcy5hc3BlY3QsIDEgKTtcblxuXHR9XG5cblx0LyoqXG5cdCAqIENvbXB1dGVzIHRoZSAyRCBib3VuZHMgb2YgdGhlIGNhbWVyYSdzIHZpZXdhYmxlIHJlY3RhbmdsZSBhdCBhIGdpdmVuIGRpc3RhbmNlIGFsb25nIHRoZSB2aWV3aW5nIGRpcmVjdGlvbi5cblx0ICogU2V0cyBtaW5UYXJnZXQgYW5kIG1heFRhcmdldCB0byB0aGUgY29vcmRpbmF0ZXMgb2YgdGhlIGxvd2VyLWxlZnQgYW5kIHVwcGVyLXJpZ2h0IGNvcm5lcnMgb2YgdGhlIHZpZXcgcmVjdGFuZ2xlLlxuXHQgKi9cblx0Z2V0Vmlld0JvdW5kcyggZGlzdGFuY2UsIG1pblRhcmdldCwgbWF4VGFyZ2V0ICkge1xuXG5cdFx0X3YzJDEuc2V0KCAtIDEsIC0gMSwgMC41ICkuYXBwbHlNYXRyaXg0KCB0aGlzLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlICk7XG5cblx0XHRtaW5UYXJnZXQuc2V0KCBfdjMkMS54LCBfdjMkMS55ICkubXVsdGlwbHlTY2FsYXIoIC0gZGlzdGFuY2UgLyBfdjMkMS56ICk7XG5cblx0XHRfdjMkMS5zZXQoIDEsIDEsIDAuNSApLmFwcGx5TWF0cml4NCggdGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZSApO1xuXG5cdFx0bWF4VGFyZ2V0LnNldCggX3YzJDEueCwgX3YzJDEueSApLm11bHRpcGx5U2NhbGFyKCAtIGRpc3RhbmNlIC8gX3YzJDEueiApO1xuXG5cdH1cblxuXHQvKipcblx0ICogQ29tcHV0ZXMgdGhlIHdpZHRoIGFuZCBoZWlnaHQgb2YgdGhlIGNhbWVyYSdzIHZpZXdhYmxlIHJlY3RhbmdsZSBhdCBhIGdpdmVuIGRpc3RhbmNlIGFsb25nIHRoZSB2aWV3aW5nIGRpcmVjdGlvbi5cblx0ICogQ29waWVzIHRoZSByZXN1bHQgaW50byB0aGUgdGFyZ2V0IFZlY3RvcjIsIHdoZXJlIHggaXMgd2lkdGggYW5kIHkgaXMgaGVpZ2h0LlxuXHQgKi9cblx0Z2V0Vmlld1NpemUoIGRpc3RhbmNlLCB0YXJnZXQgKSB7XG5cblx0XHR0aGlzLmdldFZpZXdCb3VuZHMoIGRpc3RhbmNlLCBfbWluVGFyZ2V0LCBfbWF4VGFyZ2V0ICk7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LnN1YlZlY3RvcnMoIF9tYXhUYXJnZXQsIF9taW5UYXJnZXQgKTtcblxuXHR9XG5cblx0LyoqXG5cdCAqIFNldHMgYW4gb2Zmc2V0IGluIGEgbGFyZ2VyIGZydXN0dW0uIFRoaXMgaXMgdXNlZnVsIGZvciBtdWx0aS13aW5kb3cgb3Jcblx0ICogbXVsdGktbW9uaXRvci9tdWx0aS1tYWNoaW5lIHNldHVwcy5cblx0ICpcblx0ICogRm9yIGV4YW1wbGUsIGlmIHlvdSBoYXZlIDN4MiBtb25pdG9ycyBhbmQgZWFjaCBtb25pdG9yIGlzIDE5MjB4MTA4MCBhbmRcblx0ICogdGhlIG1vbml0b3JzIGFyZSBpbiBncmlkIGxpa2UgdGhpc1xuXHQgKlxuXHQgKiAgICstLS0rLS0tKy0tLStcblx0ICogICB8IEEgfCBCIHwgQyB8XG5cdCAqICAgKy0tLSstLS0rLS0tK1xuXHQgKiAgIHwgRCB8IEUgfCBGIHxcblx0ICogICArLS0tKy0tLSstLS0rXG5cdCAqXG5cdCAqIHRoZW4gZm9yIGVhY2ggbW9uaXRvciB5b3Ugd291bGQgY2FsbCBpdCBsaWtlIHRoaXNcblx0ICpcblx0ICogICBjb25zdCB3ID0gMTkyMDtcblx0ICogICBjb25zdCBoID0gMTA4MDtcblx0ICogICBjb25zdCBmdWxsV2lkdGggPSB3ICogMztcblx0ICogICBjb25zdCBmdWxsSGVpZ2h0ID0gaCAqIDI7XG5cdCAqXG5cdCAqICAgLS1BLS1cblx0ICogICBjYW1lcmEuc2V0Vmlld09mZnNldCggZnVsbFdpZHRoLCBmdWxsSGVpZ2h0LCB3ICogMCwgaCAqIDAsIHcsIGggKTtcblx0ICogICAtLUItLVxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAxLCBoICogMCwgdywgaCApO1xuXHQgKiAgIC0tQy0tXG5cdCAqICAgY2FtZXJhLnNldFZpZXdPZmZzZXQoIGZ1bGxXaWR0aCwgZnVsbEhlaWdodCwgdyAqIDIsIGggKiAwLCB3LCBoICk7XG5cdCAqICAgLS1ELS1cblx0ICogICBjYW1lcmEuc2V0Vmlld09mZnNldCggZnVsbFdpZHRoLCBmdWxsSGVpZ2h0LCB3ICogMCwgaCAqIDEsIHcsIGggKTtcblx0ICogICAtLUUtLVxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAxLCBoICogMSwgdywgaCApO1xuXHQgKiAgIC0tRi0tXG5cdCAqICAgY2FtZXJhLnNldFZpZXdPZmZzZXQoIGZ1bGxXaWR0aCwgZnVsbEhlaWdodCwgdyAqIDIsIGggKiAxLCB3LCBoICk7XG5cdCAqXG5cdCAqICAgTm90ZSB0aGVyZSBpcyBubyByZWFzb24gbW9uaXRvcnMgaGF2ZSB0byBiZSB0aGUgc2FtZSBzaXplIG9yIGluIGEgZ3JpZC5cblx0ICovXG5cdHNldFZpZXdPZmZzZXQoIGZ1bGxXaWR0aCwgZnVsbEhlaWdodCwgeCwgeSwgd2lkdGgsIGhlaWdodCApIHtcblxuXHRcdHRoaXMuYXNwZWN0ID0gZnVsbFdpZHRoIC8gZnVsbEhlaWdodDtcblxuXHRcdGlmICggdGhpcy52aWV3ID09PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLnZpZXcgPSB7XG5cdFx0XHRcdGVuYWJsZWQ6IHRydWUsXG5cdFx0XHRcdGZ1bGxXaWR0aDogMSxcblx0XHRcdFx0ZnVsbEhlaWdodDogMSxcblx0XHRcdFx0b2Zmc2V0WDogMCxcblx0XHRcdFx0b2Zmc2V0WTogMCxcblx0XHRcdFx0d2lkdGg6IDEsXG5cdFx0XHRcdGhlaWdodDogMVxuXHRcdFx0fTtcblxuXHRcdH1cblxuXHRcdHRoaXMudmlldy5lbmFibGVkID0gdHJ1ZTtcblx0XHR0aGlzLnZpZXcuZnVsbFdpZHRoID0gZnVsbFdpZHRoO1xuXHRcdHRoaXMudmlldy5mdWxsSGVpZ2h0ID0gZnVsbEhlaWdodDtcblx0XHR0aGlzLnZpZXcub2Zmc2V0WCA9IHg7XG5cdFx0dGhpcy52aWV3Lm9mZnNldFkgPSB5O1xuXHRcdHRoaXMudmlldy53aWR0aCA9IHdpZHRoO1xuXHRcdHRoaXMudmlldy5oZWlnaHQgPSBoZWlnaHQ7XG5cblx0XHR0aGlzLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHR9XG5cblx0Y2xlYXJWaWV3T2Zmc2V0KCkge1xuXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMudmlldy5lbmFibGVkID0gZmFsc2U7XG5cblx0XHR9XG5cblx0XHR0aGlzLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHR9XG5cblx0dXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpIHtcblxuXHRcdGNvbnN0IG5lYXIgPSB0aGlzLm5lYXI7XG5cdFx0bGV0IHRvcCA9IG5lYXIgKiBNYXRoLnRhbiggREVHMlJBRCAqIDAuNSAqIHRoaXMuZm92ICkgLyB0aGlzLnpvb207XG5cdFx0bGV0IGhlaWdodCA9IDIgKiB0b3A7XG5cdFx0bGV0IHdpZHRoID0gdGhpcy5hc3BlY3QgKiBoZWlnaHQ7XG5cdFx0bGV0IGxlZnQgPSAtIDAuNSAqIHdpZHRoO1xuXHRcdGNvbnN0IHZpZXcgPSB0aGlzLnZpZXc7XG5cblx0XHRpZiAoIHRoaXMudmlldyAhPT0gbnVsbCAmJiB0aGlzLnZpZXcuZW5hYmxlZCApIHtcblxuXHRcdFx0Y29uc3QgZnVsbFdpZHRoID0gdmlldy5mdWxsV2lkdGgsXG5cdFx0XHRcdGZ1bGxIZWlnaHQgPSB2aWV3LmZ1bGxIZWlnaHQ7XG5cblx0XHRcdGxlZnQgKz0gdmlldy5vZmZzZXRYICogd2lkdGggLyBmdWxsV2lkdGg7XG5cdFx0XHR0b3AgLT0gdmlldy5vZmZzZXRZICogaGVpZ2h0IC8gZnVsbEhlaWdodDtcblx0XHRcdHdpZHRoICo9IHZpZXcud2lkdGggLyBmdWxsV2lkdGg7XG5cdFx0XHRoZWlnaHQgKj0gdmlldy5oZWlnaHQgLyBmdWxsSGVpZ2h0O1xuXG5cdFx0fVxuXG5cdFx0Y29uc3Qgc2tldyA9IHRoaXMuZmlsbU9mZnNldDtcblx0XHRpZiAoIHNrZXcgIT09IDAgKSBsZWZ0ICs9IG5lYXIgKiBza2V3IC8gdGhpcy5nZXRGaWxtV2lkdGgoKTtcblxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeC5tYWtlUGVyc3BlY3RpdmUoIGxlZnQsIGxlZnQgKyB3aWR0aCwgdG9wLCB0b3AgLSBoZWlnaHQsIG5lYXIsIHRoaXMuZmFyLCB0aGlzLmNvb3JkaW5hdGVTeXN0ZW0gKTtcblxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeEludmVyc2UuY29weSggdGhpcy5wcm9qZWN0aW9uTWF0cml4ICkuaW52ZXJ0KCk7XG5cblx0fVxuXG5cdHRvSlNPTiggbWV0YSApIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oIG1ldGEgKTtcblxuXHRcdGRhdGEub2JqZWN0LmZvdiA9IHRoaXMuZm92O1xuXHRcdGRhdGEub2JqZWN0Lnpvb20gPSB0aGlzLnpvb207XG5cblx0XHRkYXRhLm9iamVjdC5uZWFyID0gdGhpcy5uZWFyO1xuXHRcdGRhdGEub2JqZWN0LmZhciA9IHRoaXMuZmFyO1xuXHRcdGRhdGEub2JqZWN0LmZvY3VzID0gdGhpcy5mb2N1cztcblxuXHRcdGRhdGEub2JqZWN0LmFzcGVjdCA9IHRoaXMuYXNwZWN0O1xuXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgKSBkYXRhLm9iamVjdC52aWV3ID0gT2JqZWN0LmFzc2lnbigge30sIHRoaXMudmlldyApO1xuXG5cdFx0ZGF0YS5vYmplY3QuZmlsbUdhdWdlID0gdGhpcy5maWxtR2F1Z2U7XG5cdFx0ZGF0YS5vYmplY3QuZmlsbU9mZnNldCA9IHRoaXMuZmlsbU9mZnNldDtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxufVxuXG5jb25zdCBmb3YgPSAtIDkwOyAvLyBuZWdhdGl2ZSBmb3YgaXMgbm90IGFuIGVycm9yXG5jb25zdCBhc3BlY3QgPSAxO1xuXG5jbGFzcyBDdWJlQ2FtZXJhIGV4dGVuZHMgT2JqZWN0M0Qge1xuXG5cdGNvbnN0cnVjdG9yKCBuZWFyLCBmYXIsIHJlbmRlclRhcmdldCApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnQ3ViZUNhbWVyYSc7XG5cblx0XHR0aGlzLnJlbmRlclRhcmdldCA9IHJlbmRlclRhcmdldDtcblx0XHR0aGlzLmNvb3JkaW5hdGVTeXN0ZW0gPSBudWxsO1xuXHRcdHRoaXMuYWN0aXZlTWlwbWFwTGV2ZWwgPSAwO1xuXG5cdFx0Y29uc3QgY2FtZXJhUFggPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoIGZvdiwgYXNwZWN0LCBuZWFyLCBmYXIgKTtcblx0XHRjYW1lcmFQWC5sYXllcnMgPSB0aGlzLmxheWVycztcblx0XHR0aGlzLmFkZCggY2FtZXJhUFggKTtcblxuXHRcdGNvbnN0IGNhbWVyYU5YID0gbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCBmb3YsIGFzcGVjdCwgbmVhciwgZmFyICk7XG5cdFx0Y2FtZXJhTlgubGF5ZXJzID0gdGhpcy5sYXllcnM7XG5cdFx0dGhpcy5hZGQoIGNhbWVyYU5YICk7XG5cblx0XHRjb25zdCBjYW1lcmFQWSA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xuXHRcdGNhbWVyYVBZLmxheWVycyA9IHRoaXMubGF5ZXJzO1xuXHRcdHRoaXMuYWRkKCBjYW1lcmFQWSApO1xuXG5cdFx0Y29uc3QgY2FtZXJhTlkgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoIGZvdiwgYXNwZWN0LCBuZWFyLCBmYXIgKTtcblx0XHRjYW1lcmFOWS5sYXllcnMgPSB0aGlzLmxheWVycztcblx0XHR0aGlzLmFkZCggY2FtZXJhTlkgKTtcblxuXHRcdGNvbnN0IGNhbWVyYVBaID0gbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCBmb3YsIGFzcGVjdCwgbmVhciwgZmFyICk7XG5cdFx0Y2FtZXJhUFoubGF5ZXJzID0gdGhpcy5sYXllcnM7XG5cdFx0dGhpcy5hZGQoIGNhbWVyYVBaICk7XG5cblx0XHRjb25zdCBjYW1lcmFOWiA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xuXHRcdGNhbWVyYU5aLmxheWVycyA9IHRoaXMubGF5ZXJzO1xuXHRcdHRoaXMuYWRkKCBjYW1lcmFOWiApO1xuXG5cdH1cblxuXHR1cGRhdGVDb29yZGluYXRlU3lzdGVtKCkge1xuXG5cdFx0Y29uc3QgY29vcmRpbmF0ZVN5c3RlbSA9IHRoaXMuY29vcmRpbmF0ZVN5c3RlbTtcblxuXHRcdGNvbnN0IGNhbWVyYXMgPSB0aGlzLmNoaWxkcmVuLmNvbmNhdCgpO1xuXG5cdFx0Y29uc3QgWyBjYW1lcmFQWCwgY2FtZXJhTlgsIGNhbWVyYVBZLCBjYW1lcmFOWSwgY2FtZXJhUFosIGNhbWVyYU5aIF0gPSBjYW1lcmFzO1xuXG5cdFx0Zm9yICggY29uc3QgY2FtZXJhIG9mIGNhbWVyYXMgKSB0aGlzLnJlbW92ZSggY2FtZXJhICk7XG5cblx0XHRpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdFx0Y2FtZXJhUFgudXAuc2V0KCAwLCAxLCAwICk7XG5cdFx0XHRjYW1lcmFQWC5sb29rQXQoIDEsIDAsIDAgKTtcblxuXHRcdFx0Y2FtZXJhTlgudXAuc2V0KCAwLCAxLCAwICk7XG5cdFx0XHRjYW1lcmFOWC5sb29rQXQoIC0gMSwgMCwgMCApO1xuXG5cdFx0XHRjYW1lcmFQWS51cC5zZXQoIDAsIDAsIC0gMSApO1xuXHRcdFx0Y2FtZXJhUFkubG9va0F0KCAwLCAxLCAwICk7XG5cblx0XHRcdGNhbWVyYU5ZLnVwLnNldCggMCwgMCwgMSApO1xuXHRcdFx0Y2FtZXJhTlkubG9va0F0KCAwLCAtIDEsIDAgKTtcblxuXHRcdFx0Y2FtZXJhUFoudXAuc2V0KCAwLCAxLCAwICk7XG5cdFx0XHRjYW1lcmFQWi5sb29rQXQoIDAsIDAsIDEgKTtcblxuXHRcdFx0Y2FtZXJhTloudXAuc2V0KCAwLCAxLCAwICk7XG5cdFx0XHRjYW1lcmFOWi5sb29rQXQoIDAsIDAsIC0gMSApO1xuXG5cdFx0fSBlbHNlIGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR1BVQ29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdFx0Y2FtZXJhUFgudXAuc2V0KCAwLCAtIDEsIDAgKTtcblx0XHRcdGNhbWVyYVBYLmxvb2tBdCggLSAxLCAwLCAwICk7XG5cblx0XHRcdGNhbWVyYU5YLnVwLnNldCggMCwgLSAxLCAwICk7XG5cdFx0XHRjYW1lcmFOWC5sb29rQXQoIDEsIDAsIDAgKTtcblxuXHRcdFx0Y2FtZXJhUFkudXAuc2V0KCAwLCAwLCAxICk7XG5cdFx0XHRjYW1lcmFQWS5sb29rQXQoIDAsIDEsIDAgKTtcblxuXHRcdFx0Y2FtZXJhTlkudXAuc2V0KCAwLCAwLCAtIDEgKTtcblx0XHRcdGNhbWVyYU5ZLmxvb2tBdCggMCwgLSAxLCAwICk7XG5cblx0XHRcdGNhbWVyYVBaLnVwLnNldCggMCwgLSAxLCAwICk7XG5cdFx0XHRjYW1lcmFQWi5sb29rQXQoIDAsIDAsIDEgKTtcblxuXHRcdFx0Y2FtZXJhTloudXAuc2V0KCAwLCAtIDEsIDAgKTtcblx0XHRcdGNhbWVyYU5aLmxvb2tBdCggMCwgMCwgLSAxICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5DdWJlQ2FtZXJhLnVwZGF0ZUNvb3JkaW5hdGVTeXN0ZW0oKTogSW52YWxpZCBjb29yZGluYXRlIHN5c3RlbTogJyArIGNvb3JkaW5hdGVTeXN0ZW0gKTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGNvbnN0IGNhbWVyYSBvZiBjYW1lcmFzICkge1xuXG5cdFx0XHR0aGlzLmFkZCggY2FtZXJhICk7XG5cblx0XHRcdGNhbWVyYS51cGRhdGVNYXRyaXhXb3JsZCgpO1xuXG5cdFx0fVxuXG5cdH1cblxuXHR1cGRhdGUoIHJlbmRlcmVyLCBzY2VuZSApIHtcblxuXHRcdGlmICggdGhpcy5wYXJlbnQgPT09IG51bGwgKSB0aGlzLnVwZGF0ZU1hdHJpeFdvcmxkKCk7XG5cblx0XHRjb25zdCB7IHJlbmRlclRhcmdldCwgYWN0aXZlTWlwbWFwTGV2ZWwgfSA9IHRoaXM7XG5cblx0XHRpZiAoIHRoaXMuY29vcmRpbmF0ZVN5c3RlbSAhPT0gcmVuZGVyZXIuY29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdFx0dGhpcy5jb29yZGluYXRlU3lzdGVtID0gcmVuZGVyZXIuY29vcmRpbmF0ZVN5c3RlbTtcblxuXHRcdFx0dGhpcy51cGRhdGVDb29yZGluYXRlU3lzdGVtKCk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBbIGNhbWVyYVBYLCBjYW1lcmFOWCwgY2FtZXJhUFksIGNhbWVyYU5ZLCBjYW1lcmFQWiwgY2FtZXJhTlogXSA9IHRoaXMuY2hpbGRyZW47XG5cblx0XHRjb25zdCBjdXJyZW50UmVuZGVyVGFyZ2V0ID0gcmVuZGVyZXIuZ2V0UmVuZGVyVGFyZ2V0KCk7XG5cdFx0Y29uc3QgY3VycmVudEFjdGl2ZUN1YmVGYWNlID0gcmVuZGVyZXIuZ2V0QWN0aXZlQ3ViZUZhY2UoKTtcblx0XHRjb25zdCBjdXJyZW50QWN0aXZlTWlwbWFwTGV2ZWwgPSByZW5kZXJlci5nZXRBY3RpdmVNaXBtYXBMZXZlbCgpO1xuXG5cdFx0Y29uc3QgY3VycmVudFhyRW5hYmxlZCA9IHJlbmRlcmVyLnhyLmVuYWJsZWQ7XG5cblx0XHRyZW5kZXJlci54ci5lbmFibGVkID0gZmFsc2U7XG5cblx0XHRjb25zdCBnZW5lcmF0ZU1pcG1hcHMgPSByZW5kZXJUYXJnZXQudGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHM7XG5cblx0XHRyZW5kZXJUYXJnZXQudGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0LCAwLCBhY3RpdmVNaXBtYXBMZXZlbCApO1xuXHRcdHJlbmRlcmVyLnJlbmRlciggc2NlbmUsIGNhbWVyYVBYICk7XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCwgMSwgYWN0aXZlTWlwbWFwTGV2ZWwgKTtcblx0XHRyZW5kZXJlci5yZW5kZXIoIHNjZW5lLCBjYW1lcmFOWCApO1xuXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQsIDIsIGFjdGl2ZU1pcG1hcExldmVsICk7XG5cdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY2FtZXJhUFkgKTtcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0LCAzLCBhY3RpdmVNaXBtYXBMZXZlbCApO1xuXHRcdHJlbmRlcmVyLnJlbmRlciggc2NlbmUsIGNhbWVyYU5ZICk7XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCwgNCwgYWN0aXZlTWlwbWFwTGV2ZWwgKTtcblx0XHRyZW5kZXJlci5yZW5kZXIoIHNjZW5lLCBjYW1lcmFQWiApO1xuXG5cdFx0Ly8gbWlwbWFwcyBhcmUgZ2VuZXJhdGVkIGR1cmluZyB0aGUgbGFzdCBjYWxsIG9mIHJlbmRlcigpXG5cdFx0Ly8gYXQgdGhpcyBwb2ludCwgYWxsIHNpZGVzIG9mIHRoZSBjdWJlIHJlbmRlciB0YXJnZXQgYXJlIGRlZmluZWRcblxuXHRcdHJlbmRlclRhcmdldC50ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IGdlbmVyYXRlTWlwbWFwcztcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0LCA1LCBhY3RpdmVNaXBtYXBMZXZlbCApO1xuXHRcdHJlbmRlcmVyLnJlbmRlciggc2NlbmUsIGNhbWVyYU5aICk7XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1cnJlbnRSZW5kZXJUYXJnZXQsIGN1cnJlbnRBY3RpdmVDdWJlRmFjZSwgY3VycmVudEFjdGl2ZU1pcG1hcExldmVsICk7XG5cblx0XHRyZW5kZXJlci54ci5lbmFibGVkID0gY3VycmVudFhyRW5hYmxlZDtcblxuXHRcdHJlbmRlclRhcmdldC50ZXh0dXJlLm5lZWRzUE1SRU1VcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBDdWJlVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xuXG5cdGNvbnN0cnVjdG9yKCBpbWFnZXMsIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSwgY29sb3JTcGFjZSApIHtcblxuXHRcdGltYWdlcyA9IGltYWdlcyAhPT0gdW5kZWZpbmVkID8gaW1hZ2VzIDogW107XG5cdFx0bWFwcGluZyA9IG1hcHBpbmcgIT09IHVuZGVmaW5lZCA/IG1hcHBpbmcgOiBDdWJlUmVmbGVjdGlvbk1hcHBpbmc7XG5cblx0XHRzdXBlciggaW1hZ2VzLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHksIGNvbG9yU3BhY2UgKTtcblxuXHRcdHRoaXMuaXNDdWJlVGV4dHVyZSA9IHRydWU7XG5cblx0XHR0aGlzLmZsaXBZID0gZmFsc2U7XG5cblx0fVxuXG5cdGdldCBpbWFnZXMoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5pbWFnZTtcblxuXHR9XG5cblx0c2V0IGltYWdlcyggdmFsdWUgKSB7XG5cblx0XHR0aGlzLmltYWdlID0gdmFsdWU7XG5cblx0fVxuXG59XG5cbmNsYXNzIFdlYkdMQ3ViZVJlbmRlclRhcmdldCBleHRlbmRzIFdlYkdMUmVuZGVyVGFyZ2V0IHtcblxuXHRjb25zdHJ1Y3Rvciggc2l6ZSA9IDEsIG9wdGlvbnMgPSB7fSApIHtcblxuXHRcdHN1cGVyKCBzaXplLCBzaXplLCBvcHRpb25zICk7XG5cblx0XHR0aGlzLmlzV2ViR0xDdWJlUmVuZGVyVGFyZ2V0ID0gdHJ1ZTtcblxuXHRcdGNvbnN0IGltYWdlID0geyB3aWR0aDogc2l6ZSwgaGVpZ2h0OiBzaXplLCBkZXB0aDogMSB9O1xuXHRcdGNvbnN0IGltYWdlcyA9IFsgaW1hZ2UsIGltYWdlLCBpbWFnZSwgaW1hZ2UsIGltYWdlLCBpbWFnZSBdO1xuXG5cdFx0dGhpcy50ZXh0dXJlID0gbmV3IEN1YmVUZXh0dXJlKCBpbWFnZXMsIG9wdGlvbnMubWFwcGluZywgb3B0aW9ucy53cmFwUywgb3B0aW9ucy53cmFwVCwgb3B0aW9ucy5tYWdGaWx0ZXIsIG9wdGlvbnMubWluRmlsdGVyLCBvcHRpb25zLmZvcm1hdCwgb3B0aW9ucy50eXBlLCBvcHRpb25zLmFuaXNvdHJvcHksIG9wdGlvbnMuY29sb3JTcGFjZSApO1xuXG5cdFx0Ly8gQnkgY29udmVudGlvbiAtLSBsaWtlbHkgYmFzZWQgb24gdGhlIFJlbmRlck1hbiBzcGVjIGZyb20gdGhlIDE5OTAncyAtLSBjdWJlIG1hcHMgYXJlIHNwZWNpZmllZCBieSBXZWJHTCAoYW5kIHRocmVlLmpzKVxuXHRcdC8vIGluIGEgY29vcmRpbmF0ZSBzeXN0ZW0gaW4gd2hpY2ggcG9zaXRpdmUteCBpcyB0byB0aGUgcmlnaHQgd2hlbiBsb29raW5nIHVwIHRoZSBwb3NpdGl2ZS16IGF4aXMgLS0gaW4gb3RoZXIgd29yZHMsXG5cdFx0Ly8gaW4gYSBsZWZ0LWhhbmRlZCBjb29yZGluYXRlIHN5c3RlbS4gQnkgY29udGludWluZyB0aGlzIGNvbnZlbnRpb24sIHByZWV4aXN0aW5nIGN1YmUgbWFwcyBjb250aW51ZWQgdG8gcmVuZGVyIGNvcnJlY3RseS5cblxuXHRcdC8vIHRocmVlLmpzIHVzZXMgYSByaWdodC1oYW5kZWQgY29vcmRpbmF0ZSBzeXN0ZW0uIFNvIGVudmlyb25tZW50IG1hcHMgdXNlZCBpbiB0aHJlZS5qcyBhcHBlYXIgdG8gaGF2ZSBweCBhbmQgbnggc3dhcHBlZFxuXHRcdC8vIGFuZCB0aGUgZmxhZyBpc1JlbmRlclRhcmdldFRleHR1cmUgY29udHJvbHMgdGhpcyBjb252ZXJzaW9uLiBUaGUgZmxpcCBpcyBub3QgcmVxdWlyZWQgd2hlbiB1c2luZyBXZWJHTEN1YmVSZW5kZXJUYXJnZXQudGV4dHVyZVxuXHRcdC8vIGFzIGEgY3ViZSB0ZXh0dXJlICh0aGlzIGlzIGRldGVjdGVkIHdoZW4gaXNSZW5kZXJUYXJnZXRUZXh0dXJlIGlzIHNldCB0byB0cnVlIGZvciBjdWJlIHRleHR1cmVzKS5cblxuXHRcdHRoaXMudGV4dHVyZS5pc1JlbmRlclRhcmdldFRleHR1cmUgPSB0cnVlO1xuXG5cdFx0dGhpcy50ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IG9wdGlvbnMuZ2VuZXJhdGVNaXBtYXBzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmdlbmVyYXRlTWlwbWFwcyA6IGZhbHNlO1xuXHRcdHRoaXMudGV4dHVyZS5taW5GaWx0ZXIgPSBvcHRpb25zLm1pbkZpbHRlciAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5taW5GaWx0ZXIgOiBMaW5lYXJGaWx0ZXI7XG5cblx0fVxuXG5cdGZyb21FcXVpcmVjdGFuZ3VsYXJUZXh0dXJlKCByZW5kZXJlciwgdGV4dHVyZSApIHtcblxuXHRcdHRoaXMudGV4dHVyZS50eXBlID0gdGV4dHVyZS50eXBlO1xuXHRcdHRoaXMudGV4dHVyZS5jb2xvclNwYWNlID0gdGV4dHVyZS5jb2xvclNwYWNlO1xuXG5cdFx0dGhpcy50ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IHRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzO1xuXHRcdHRoaXMudGV4dHVyZS5taW5GaWx0ZXIgPSB0ZXh0dXJlLm1pbkZpbHRlcjtcblx0XHR0aGlzLnRleHR1cmUubWFnRmlsdGVyID0gdGV4dHVyZS5tYWdGaWx0ZXI7XG5cblx0XHRjb25zdCBzaGFkZXIgPSB7XG5cblx0XHRcdHVuaWZvcm1zOiB7XG5cdFx0XHRcdHRFcXVpcmVjdDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0fSxcblxuXHRcdFx0dmVydGV4U2hhZGVyOiAvKiBnbHNsICovYFxuXG5cdFx0XHRcdHZhcnlpbmcgdmVjMyB2V29ybGREaXJlY3Rpb247XG5cblx0XHRcdFx0dmVjMyB0cmFuc2Zvcm1EaXJlY3Rpb24oIGluIHZlYzMgZGlyLCBpbiBtYXQ0IG1hdHJpeCApIHtcblxuXHRcdFx0XHRcdHJldHVybiBub3JtYWxpemUoICggbWF0cml4ICogdmVjNCggZGlyLCAwLjAgKSApLnh5eiApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHR2b2lkIG1haW4oKSB7XG5cblx0XHRcdFx0XHR2V29ybGREaXJlY3Rpb24gPSB0cmFuc2Zvcm1EaXJlY3Rpb24oIHBvc2l0aW9uLCBtb2RlbE1hdHJpeCApO1xuXG5cdFx0XHRcdFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cblx0XHRcdFx0XHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XG5cblx0XHRcdFx0fVxuXHRcdFx0YCxcblxuXHRcdFx0ZnJhZ21lbnRTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHRcdFx0dW5pZm9ybSBzYW1wbGVyMkQgdEVxdWlyZWN0O1xuXG5cdFx0XHRcdHZhcnlpbmcgdmVjMyB2V29ybGREaXJlY3Rpb247XG5cblx0XHRcdFx0I2luY2x1ZGUgPGNvbW1vbj5cblxuXHRcdFx0XHR2b2lkIG1haW4oKSB7XG5cblx0XHRcdFx0XHR2ZWMzIGRpcmVjdGlvbiA9IG5vcm1hbGl6ZSggdldvcmxkRGlyZWN0aW9uICk7XG5cblx0XHRcdFx0XHR2ZWMyIHNhbXBsZVVWID0gZXF1aXJlY3RVdiggZGlyZWN0aW9uICk7XG5cblx0XHRcdFx0XHRnbF9GcmFnQ29sb3IgPSB0ZXh0dXJlMkQoIHRFcXVpcmVjdCwgc2FtcGxlVVYgKTtcblxuXHRcdFx0XHR9XG5cdFx0XHRgXG5cdFx0fTtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJveEdlb21ldHJ5KCA1LCA1LCA1ICk7XG5cblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xuXG5cdFx0XHRuYW1lOiAnQ3ViZW1hcEZyb21FcXVpcmVjdCcsXG5cblx0XHRcdHVuaWZvcm1zOiBjbG9uZVVuaWZvcm1zKCBzaGFkZXIudW5pZm9ybXMgKSxcblx0XHRcdHZlcnRleFNoYWRlcjogc2hhZGVyLnZlcnRleFNoYWRlcixcblx0XHRcdGZyYWdtZW50U2hhZGVyOiBzaGFkZXIuZnJhZ21lbnRTaGFkZXIsXG5cdFx0XHRzaWRlOiBCYWNrU2lkZSxcblx0XHRcdGJsZW5kaW5nOiBOb0JsZW5kaW5nXG5cblx0XHR9ICk7XG5cblx0XHRtYXRlcmlhbC51bmlmb3Jtcy50RXF1aXJlY3QudmFsdWUgPSB0ZXh0dXJlO1xuXG5cdFx0Y29uc3QgbWVzaCA9IG5ldyBNZXNoKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblxuXHRcdGNvbnN0IGN1cnJlbnRNaW5GaWx0ZXIgPSB0ZXh0dXJlLm1pbkZpbHRlcjtcblxuXHRcdC8vIEF2b2lkIGJsdXJyZWQgcG9sZXNcblx0XHRpZiAoIHRleHR1cmUubWluRmlsdGVyID09PSBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIgKSB0ZXh0dXJlLm1pbkZpbHRlciA9IExpbmVhckZpbHRlcjtcblxuXHRcdGNvbnN0IGNhbWVyYSA9IG5ldyBDdWJlQ2FtZXJhKCAxLCAxMCwgdGhpcyApO1xuXHRcdGNhbWVyYS51cGRhdGUoIHJlbmRlcmVyLCBtZXNoICk7XG5cblx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IGN1cnJlbnRNaW5GaWx0ZXI7XG5cblx0XHRtZXNoLmdlb21ldHJ5LmRpc3Bvc2UoKTtcblx0XHRtZXNoLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbGVhciggcmVuZGVyZXIsIGNvbG9yLCBkZXB0aCwgc3RlbmNpbCApIHtcblxuXHRcdGNvbnN0IGN1cnJlbnRSZW5kZXJUYXJnZXQgPSByZW5kZXJlci5nZXRSZW5kZXJUYXJnZXQoKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggdGhpcywgaSApO1xuXG5cdFx0XHRyZW5kZXJlci5jbGVhciggY29sb3IsIGRlcHRoLCBzdGVuY2lsICk7XG5cblx0XHR9XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1cnJlbnRSZW5kZXJUYXJnZXQgKTtcblxuXHR9XG5cbn1cblxuY29uc3QgX3ZlY3RvcjEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdmVjdG9yMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9ub3JtYWxNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCk7XG5cbmNsYXNzIFBsYW5lIHtcblxuXHRjb25zdHJ1Y3Rvciggbm9ybWFsID0gbmV3IFZlY3RvcjMoIDEsIDAsIDAgKSwgY29uc3RhbnQgPSAwICkge1xuXG5cdFx0dGhpcy5pc1BsYW5lID0gdHJ1ZTtcblxuXHRcdC8vIG5vcm1hbCBpcyBhc3N1bWVkIHRvIGJlIG5vcm1hbGl6ZWRcblxuXHRcdHRoaXMubm9ybWFsID0gbm9ybWFsO1xuXHRcdHRoaXMuY29uc3RhbnQgPSBjb25zdGFudDtcblxuXHR9XG5cblx0c2V0KCBub3JtYWwsIGNvbnN0YW50ICkge1xuXG5cdFx0dGhpcy5ub3JtYWwuY29weSggbm9ybWFsICk7XG5cdFx0dGhpcy5jb25zdGFudCA9IGNvbnN0YW50O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldENvbXBvbmVudHMoIHgsIHksIHosIHcgKSB7XG5cblx0XHR0aGlzLm5vcm1hbC5zZXQoIHgsIHksIHogKTtcblx0XHR0aGlzLmNvbnN0YW50ID0gdztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tTm9ybWFsQW5kQ29wbGFuYXJQb2ludCggbm9ybWFsLCBwb2ludCApIHtcblxuXHRcdHRoaXMubm9ybWFsLmNvcHkoIG5vcm1hbCApO1xuXHRcdHRoaXMuY29uc3RhbnQgPSAtIHBvaW50LmRvdCggdGhpcy5ub3JtYWwgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tQ29wbGFuYXJQb2ludHMoIGEsIGIsIGMgKSB7XG5cblx0XHRjb25zdCBub3JtYWwgPSBfdmVjdG9yMS5zdWJWZWN0b3JzKCBjLCBiICkuY3Jvc3MoIF92ZWN0b3IyLnN1YlZlY3RvcnMoIGEsIGIgKSApLm5vcm1hbGl6ZSgpO1xuXG5cdFx0Ly8gUTogc2hvdWxkIGFuIGVycm9yIGJlIHRocm93biBpZiBub3JtYWwgaXMgemVybyAoZS5nLiBkZWdlbmVyYXRlIHBsYW5lKT9cblxuXHRcdHRoaXMuc2V0RnJvbU5vcm1hbEFuZENvcGxhbmFyUG9pbnQoIG5vcm1hbCwgYSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvcHkoIHBsYW5lICkge1xuXG5cdFx0dGhpcy5ub3JtYWwuY29weSggcGxhbmUubm9ybWFsICk7XG5cdFx0dGhpcy5jb25zdGFudCA9IHBsYW5lLmNvbnN0YW50O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG5vcm1hbGl6ZSgpIHtcblxuXHRcdC8vIE5vdGU6IHdpbGwgbGVhZCB0byBhIGRpdmlkZSBieSB6ZXJvIGlmIHRoZSBwbGFuZSBpcyBpbnZhbGlkLlxuXG5cdFx0Y29uc3QgaW52ZXJzZU5vcm1hbExlbmd0aCA9IDEuMCAvIHRoaXMubm9ybWFsLmxlbmd0aCgpO1xuXHRcdHRoaXMubm9ybWFsLm11bHRpcGx5U2NhbGFyKCBpbnZlcnNlTm9ybWFsTGVuZ3RoICk7XG5cdFx0dGhpcy5jb25zdGFudCAqPSBpbnZlcnNlTm9ybWFsTGVuZ3RoO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG5lZ2F0ZSgpIHtcblxuXHRcdHRoaXMuY29uc3RhbnQgKj0gLSAxO1xuXHRcdHRoaXMubm9ybWFsLm5lZ2F0ZSgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRpc3RhbmNlVG9Qb2ludCggcG9pbnQgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5ub3JtYWwuZG90KCBwb2ludCApICsgdGhpcy5jb25zdGFudDtcblxuXHR9XG5cblx0ZGlzdGFuY2VUb1NwaGVyZSggc3BoZXJlICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZGlzdGFuY2VUb1BvaW50KCBzcGhlcmUuY2VudGVyICkgLSBzcGhlcmUucmFkaXVzO1xuXG5cdH1cblxuXHRwcm9qZWN0UG9pbnQoIHBvaW50LCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHBvaW50ICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLm5vcm1hbCwgLSB0aGlzLmRpc3RhbmNlVG9Qb2ludCggcG9pbnQgKSApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RMaW5lKCBsaW5lLCB0YXJnZXQgKSB7XG5cblx0XHRjb25zdCBkaXJlY3Rpb24gPSBsaW5lLmRlbHRhKCBfdmVjdG9yMSApO1xuXG5cdFx0Y29uc3QgZGVub21pbmF0b3IgPSB0aGlzLm5vcm1hbC5kb3QoIGRpcmVjdGlvbiApO1xuXG5cdFx0aWYgKCBkZW5vbWluYXRvciA9PT0gMCApIHtcblxuXHRcdFx0Ly8gbGluZSBpcyBjb3BsYW5hciwgcmV0dXJuIG9yaWdpblxuXHRcdFx0aWYgKCB0aGlzLmRpc3RhbmNlVG9Qb2ludCggbGluZS5zdGFydCApID09PSAwICkge1xuXG5cdFx0XHRcdHJldHVybiB0YXJnZXQuY29weSggbGluZS5zdGFydCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIFVuc3VyZSBpZiB0aGlzIGlzIHRoZSBjb3JyZWN0IG1ldGhvZCB0byBoYW5kbGUgdGhpcyBjYXNlLlxuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9XG5cblx0XHRjb25zdCB0ID0gLSAoIGxpbmUuc3RhcnQuZG90KCB0aGlzLm5vcm1hbCApICsgdGhpcy5jb25zdGFudCApIC8gZGVub21pbmF0b3I7XG5cblx0XHRpZiAoIHQgPCAwIHx8IHQgPiAxICkge1xuXG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0YXJnZXQuY29weSggbGluZS5zdGFydCApLmFkZFNjYWxlZFZlY3RvciggZGlyZWN0aW9uLCB0ICk7XG5cblx0fVxuXG5cdGludGVyc2VjdHNMaW5lKCBsaW5lICkge1xuXG5cdFx0Ly8gTm90ZTogdGhpcyB0ZXN0cyBpZiBhIGxpbmUgaW50ZXJzZWN0cyB0aGUgcGxhbmUsIG5vdCB3aGV0aGVyIGl0IChvciBpdHMgZW5kLXBvaW50cykgYXJlIGNvcGxhbmFyIHdpdGggaXQuXG5cblx0XHRjb25zdCBzdGFydFNpZ24gPSB0aGlzLmRpc3RhbmNlVG9Qb2ludCggbGluZS5zdGFydCApO1xuXHRcdGNvbnN0IGVuZFNpZ24gPSB0aGlzLmRpc3RhbmNlVG9Qb2ludCggbGluZS5lbmQgKTtcblxuXHRcdHJldHVybiAoIHN0YXJ0U2lnbiA8IDAgJiYgZW5kU2lnbiA+IDAgKSB8fCAoIGVuZFNpZ24gPCAwICYmIHN0YXJ0U2lnbiA+IDAgKTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c0JveCggYm94ICkge1xuXG5cdFx0cmV0dXJuIGJveC5pbnRlcnNlY3RzUGxhbmUoIHRoaXMgKTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c1NwaGVyZSggc3BoZXJlICkge1xuXG5cdFx0cmV0dXJuIHNwaGVyZS5pbnRlcnNlY3RzUGxhbmUoIHRoaXMgKTtcblxuXHR9XG5cblx0Y29wbGFuYXJQb2ludCggdGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIHRhcmdldC5jb3B5KCB0aGlzLm5vcm1hbCApLm11bHRpcGx5U2NhbGFyKCAtIHRoaXMuY29uc3RhbnQgKTtcblxuXHR9XG5cblx0YXBwbHlNYXRyaXg0KCBtYXRyaXgsIG9wdGlvbmFsTm9ybWFsTWF0cml4ICkge1xuXG5cdFx0Y29uc3Qgbm9ybWFsTWF0cml4ID0gb3B0aW9uYWxOb3JtYWxNYXRyaXggfHwgX25vcm1hbE1hdHJpeC5nZXROb3JtYWxNYXRyaXgoIG1hdHJpeCApO1xuXG5cdFx0Y29uc3QgcmVmZXJlbmNlUG9pbnQgPSB0aGlzLmNvcGxhbmFyUG9pbnQoIF92ZWN0b3IxICkuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTtcblxuXHRcdGNvbnN0IG5vcm1hbCA9IHRoaXMubm9ybWFsLmFwcGx5TWF0cml4Myggbm9ybWFsTWF0cml4ICkubm9ybWFsaXplKCk7XG5cblx0XHR0aGlzLmNvbnN0YW50ID0gLSByZWZlcmVuY2VQb2ludC5kb3QoIG5vcm1hbCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRyYW5zbGF0ZSggb2Zmc2V0ICkge1xuXG5cdFx0dGhpcy5jb25zdGFudCAtPSBvZmZzZXQuZG90KCB0aGlzLm5vcm1hbCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGVxdWFscyggcGxhbmUgKSB7XG5cblx0XHRyZXR1cm4gcGxhbmUubm9ybWFsLmVxdWFscyggdGhpcy5ub3JtYWwgKSAmJiAoIHBsYW5lLmNvbnN0YW50ID09PSB0aGlzLmNvbnN0YW50ICk7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxufVxuXG5jb25zdCBfc3BoZXJlJDUgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcbmNvbnN0IF92ZWN0b3IkNyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgRnJ1c3R1bSB7XG5cblx0Y29uc3RydWN0b3IoIHAwID0gbmV3IFBsYW5lKCksIHAxID0gbmV3IFBsYW5lKCksIHAyID0gbmV3IFBsYW5lKCksIHAzID0gbmV3IFBsYW5lKCksIHA0ID0gbmV3IFBsYW5lKCksIHA1ID0gbmV3IFBsYW5lKCkgKSB7XG5cblx0XHR0aGlzLnBsYW5lcyA9IFsgcDAsIHAxLCBwMiwgcDMsIHA0LCBwNSBdO1xuXG5cdH1cblxuXHRzZXQoIHAwLCBwMSwgcDIsIHAzLCBwNCwgcDUgKSB7XG5cblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcblxuXHRcdHBsYW5lc1sgMCBdLmNvcHkoIHAwICk7XG5cdFx0cGxhbmVzWyAxIF0uY29weSggcDEgKTtcblx0XHRwbGFuZXNbIDIgXS5jb3B5KCBwMiApO1xuXHRcdHBsYW5lc1sgMyBdLmNvcHkoIHAzICk7XG5cdFx0cGxhbmVzWyA0IF0uY29weSggcDQgKTtcblx0XHRwbGFuZXNbIDUgXS5jb3B5KCBwNSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvcHkoIGZydXN0dW0gKSB7XG5cblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdHBsYW5lc1sgaSBdLmNvcHkoIGZydXN0dW0ucGxhbmVzWyBpIF0gKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tUHJvamVjdGlvbk1hdHJpeCggbSwgY29vcmRpbmF0ZVN5c3RlbSA9IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdGNvbnN0IHBsYW5lcyA9IHRoaXMucGxhbmVzO1xuXHRcdGNvbnN0IG1lID0gbS5lbGVtZW50cztcblx0XHRjb25zdCBtZTAgPSBtZVsgMCBdLCBtZTEgPSBtZVsgMSBdLCBtZTIgPSBtZVsgMiBdLCBtZTMgPSBtZVsgMyBdO1xuXHRcdGNvbnN0IG1lNCA9IG1lWyA0IF0sIG1lNSA9IG1lWyA1IF0sIG1lNiA9IG1lWyA2IF0sIG1lNyA9IG1lWyA3IF07XG5cdFx0Y29uc3QgbWU4ID0gbWVbIDggXSwgbWU5ID0gbWVbIDkgXSwgbWUxMCA9IG1lWyAxMCBdLCBtZTExID0gbWVbIDExIF07XG5cdFx0Y29uc3QgbWUxMiA9IG1lWyAxMiBdLCBtZTEzID0gbWVbIDEzIF0sIG1lMTQgPSBtZVsgMTQgXSwgbWUxNSA9IG1lWyAxNSBdO1xuXG5cdFx0cGxhbmVzWyAwIF0uc2V0Q29tcG9uZW50cyggbWUzIC0gbWUwLCBtZTcgLSBtZTQsIG1lMTEgLSBtZTgsIG1lMTUgLSBtZTEyICkubm9ybWFsaXplKCk7XG5cdFx0cGxhbmVzWyAxIF0uc2V0Q29tcG9uZW50cyggbWUzICsgbWUwLCBtZTcgKyBtZTQsIG1lMTEgKyBtZTgsIG1lMTUgKyBtZTEyICkubm9ybWFsaXplKCk7XG5cdFx0cGxhbmVzWyAyIF0uc2V0Q29tcG9uZW50cyggbWUzICsgbWUxLCBtZTcgKyBtZTUsIG1lMTEgKyBtZTksIG1lMTUgKyBtZTEzICkubm9ybWFsaXplKCk7XG5cdFx0cGxhbmVzWyAzIF0uc2V0Q29tcG9uZW50cyggbWUzIC0gbWUxLCBtZTcgLSBtZTUsIG1lMTEgLSBtZTksIG1lMTUgLSBtZTEzICkubm9ybWFsaXplKCk7XG5cdFx0cGxhbmVzWyA0IF0uc2V0Q29tcG9uZW50cyggbWUzIC0gbWUyLCBtZTcgLSBtZTYsIG1lMTEgLSBtZTEwLCBtZTE1IC0gbWUxNCApLm5vcm1hbGl6ZSgpO1xuXG5cdFx0aWYgKCBjb29yZGluYXRlU3lzdGVtID09PSBXZWJHTENvb3JkaW5hdGVTeXN0ZW0gKSB7XG5cblx0XHRcdHBsYW5lc1sgNSBdLnNldENvbXBvbmVudHMoIG1lMyArIG1lMiwgbWU3ICsgbWU2LCBtZTExICsgbWUxMCwgbWUxNSArIG1lMTQgKS5ub3JtYWxpemUoKTtcblxuXHRcdH0gZWxzZSBpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdQVUNvb3JkaW5hdGVTeXN0ZW0gKSB7XG5cblx0XHRcdHBsYW5lc1sgNSBdLnNldENvbXBvbmVudHMoIG1lMiwgbWU2LCBtZTEwLCBtZTE0ICkubm9ybWFsaXplKCk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5GcnVzdHVtLnNldEZyb21Qcm9qZWN0aW9uTWF0cml4KCk6IEludmFsaWQgY29vcmRpbmF0ZSBzeXN0ZW06ICcgKyBjb29yZGluYXRlU3lzdGVtICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0aW50ZXJzZWN0c09iamVjdCggb2JqZWN0ICkge1xuXG5cdFx0aWYgKCBvYmplY3QuYm91bmRpbmdTcGhlcmUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0aWYgKCBvYmplY3QuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSBvYmplY3QuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XG5cblx0XHRcdF9zcGhlcmUkNS5jb3B5KCBvYmplY3QuYm91bmRpbmdTcGhlcmUgKS5hcHBseU1hdHJpeDQoIG9iamVjdC5tYXRyaXhXb3JsZCApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSBvYmplY3QuZ2VvbWV0cnk7XG5cblx0XHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSBnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcblxuXHRcdFx0X3NwaGVyZSQ1LmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICkuYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUkNSApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzU3ByaXRlKCBzcHJpdGUgKSB7XG5cblx0XHRfc3BoZXJlJDUuY2VudGVyLnNldCggMCwgMCwgMCApO1xuXHRcdF9zcGhlcmUkNS5yYWRpdXMgPSAwLjcwNzEwNjc4MTE4NjU0NzY7XG5cdFx0X3NwaGVyZSQ1LmFwcGx5TWF0cml4NCggc3ByaXRlLm1hdHJpeFdvcmxkICk7XG5cblx0XHRyZXR1cm4gdGhpcy5pbnRlcnNlY3RzU3BoZXJlKCBfc3BoZXJlJDUgKTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c1NwaGVyZSggc3BoZXJlICkge1xuXG5cdFx0Y29uc3QgcGxhbmVzID0gdGhpcy5wbGFuZXM7XG5cdFx0Y29uc3QgY2VudGVyID0gc3BoZXJlLmNlbnRlcjtcblx0XHRjb25zdCBuZWdSYWRpdXMgPSAtIHNwaGVyZS5yYWRpdXM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IHBsYW5lc1sgaSBdLmRpc3RhbmNlVG9Qb2ludCggY2VudGVyICk7XG5cblx0XHRcdGlmICggZGlzdGFuY2UgPCBuZWdSYWRpdXMgKSB7XG5cblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c0JveCggYm94ICkge1xuXG5cdFx0Y29uc3QgcGxhbmVzID0gdGhpcy5wbGFuZXM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBwbGFuZSA9IHBsYW5lc1sgaSBdO1xuXG5cdFx0XHQvLyBjb3JuZXIgYXQgbWF4IGRpc3RhbmNlXG5cblx0XHRcdF92ZWN0b3IkNy54ID0gcGxhbmUubm9ybWFsLnggPiAwID8gYm94Lm1heC54IDogYm94Lm1pbi54O1xuXHRcdFx0X3ZlY3RvciQ3LnkgPSBwbGFuZS5ub3JtYWwueSA+IDAgPyBib3gubWF4LnkgOiBib3gubWluLnk7XG5cdFx0XHRfdmVjdG9yJDcueiA9IHBsYW5lLm5vcm1hbC56ID4gMCA/IGJveC5tYXgueiA6IGJveC5taW4uejtcblxuXHRcdFx0aWYgKCBwbGFuZS5kaXN0YW5jZVRvUG9pbnQoIF92ZWN0b3IkNyApIDwgMCApIHtcblxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0cnVlO1xuXG5cdH1cblxuXHRjb250YWluc1BvaW50KCBwb2ludCApIHtcblxuXHRcdGNvbnN0IHBsYW5lcyA9IHRoaXMucGxhbmVzO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcblxuXHRcdFx0aWYgKCBwbGFuZXNbIGkgXS5kaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkgPCAwICkge1xuXG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBXZWJHTEFuaW1hdGlvbigpIHtcblxuXHRsZXQgY29udGV4dCA9IG51bGw7XG5cdGxldCBpc0FuaW1hdGluZyA9IGZhbHNlO1xuXHRsZXQgYW5pbWF0aW9uTG9vcCA9IG51bGw7XG5cdGxldCByZXF1ZXN0SWQgPSBudWxsO1xuXG5cdGZ1bmN0aW9uIG9uQW5pbWF0aW9uRnJhbWUoIHRpbWUsIGZyYW1lICkge1xuXG5cdFx0YW5pbWF0aW9uTG9vcCggdGltZSwgZnJhbWUgKTtcblxuXHRcdHJlcXVlc3RJZCA9IGNvbnRleHQucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCBvbkFuaW1hdGlvbkZyYW1lICk7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cblx0XHRzdGFydDogZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRpZiAoIGlzQW5pbWF0aW5nID09PSB0cnVlICkgcmV0dXJuO1xuXHRcdFx0aWYgKCBhbmltYXRpb25Mb29wID09PSBudWxsICkgcmV0dXJuO1xuXG5cdFx0XHRyZXF1ZXN0SWQgPSBjb250ZXh0LnJlcXVlc3RBbmltYXRpb25GcmFtZSggb25BbmltYXRpb25GcmFtZSApO1xuXG5cdFx0XHRpc0FuaW1hdGluZyA9IHRydWU7XG5cblx0XHR9LFxuXG5cdFx0c3RvcDogZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRjb250ZXh0LmNhbmNlbEFuaW1hdGlvbkZyYW1lKCByZXF1ZXN0SWQgKTtcblxuXHRcdFx0aXNBbmltYXRpbmcgPSBmYWxzZTtcblxuXHRcdH0sXG5cblx0XHRzZXRBbmltYXRpb25Mb29wOiBmdW5jdGlvbiAoIGNhbGxiYWNrICkge1xuXG5cdFx0XHRhbmltYXRpb25Mb29wID0gY2FsbGJhY2s7XG5cblx0XHR9LFxuXG5cdFx0c2V0Q29udGV4dDogZnVuY3Rpb24gKCB2YWx1ZSApIHtcblxuXHRcdFx0Y29udGV4dCA9IHZhbHVlO1xuXG5cdFx0fVxuXG5cdH07XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xBdHRyaWJ1dGVzKCBnbCApIHtcblxuXHRjb25zdCBidWZmZXJzID0gbmV3IFdlYWtNYXAoKTtcblxuXHRmdW5jdGlvbiBjcmVhdGVCdWZmZXIoIGF0dHJpYnV0ZSwgYnVmZmVyVHlwZSApIHtcblxuXHRcdGNvbnN0IGFycmF5ID0gYXR0cmlidXRlLmFycmF5O1xuXHRcdGNvbnN0IHVzYWdlID0gYXR0cmlidXRlLnVzYWdlO1xuXHRcdGNvbnN0IHNpemUgPSBhcnJheS5ieXRlTGVuZ3RoO1xuXG5cdFx0Y29uc3QgYnVmZmVyID0gZ2wuY3JlYXRlQnVmZmVyKCk7XG5cblx0XHRnbC5iaW5kQnVmZmVyKCBidWZmZXJUeXBlLCBidWZmZXIgKTtcblx0XHRnbC5idWZmZXJEYXRhKCBidWZmZXJUeXBlLCBhcnJheSwgdXNhZ2UgKTtcblxuXHRcdGF0dHJpYnV0ZS5vblVwbG9hZENhbGxiYWNrKCk7XG5cblx0XHRsZXQgdHlwZTtcblxuXHRcdGlmICggYXJyYXkgaW5zdGFuY2VvZiBGbG9hdDMyQXJyYXkgKSB7XG5cblx0XHRcdHR5cGUgPSBnbC5GTE9BVDtcblxuXHRcdH0gZWxzZSBpZiAoIGFycmF5IGluc3RhbmNlb2YgVWludDE2QXJyYXkgKSB7XG5cblx0XHRcdGlmICggYXR0cmlidXRlLmlzRmxvYXQxNkJ1ZmZlckF0dHJpYnV0ZSApIHtcblxuXHRcdFx0XHR0eXBlID0gZ2wuSEFMRl9GTE9BVDtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHR0eXBlID0gZ2wuVU5TSUdORURfU0hPUlQ7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSBpZiAoIGFycmF5IGluc3RhbmNlb2YgSW50MTZBcnJheSApIHtcblxuXHRcdFx0dHlwZSA9IGdsLlNIT1JUO1xuXG5cdFx0fSBlbHNlIGlmICggYXJyYXkgaW5zdGFuY2VvZiBVaW50MzJBcnJheSApIHtcblxuXHRcdFx0dHlwZSA9IGdsLlVOU0lHTkVEX0lOVDtcblxuXHRcdH0gZWxzZSBpZiAoIGFycmF5IGluc3RhbmNlb2YgSW50MzJBcnJheSApIHtcblxuXHRcdFx0dHlwZSA9IGdsLklOVDtcblxuXHRcdH0gZWxzZSBpZiAoIGFycmF5IGluc3RhbmNlb2YgSW50OEFycmF5ICkge1xuXG5cdFx0XHR0eXBlID0gZ2wuQllURTtcblxuXHRcdH0gZWxzZSBpZiAoIGFycmF5IGluc3RhbmNlb2YgVWludDhBcnJheSApIHtcblxuXHRcdFx0dHlwZSA9IGdsLlVOU0lHTkVEX0JZVEU7XG5cblx0XHR9IGVsc2UgaWYgKCBhcnJheSBpbnN0YW5jZW9mIFVpbnQ4Q2xhbXBlZEFycmF5ICkge1xuXG5cdFx0XHR0eXBlID0gZ2wuVU5TSUdORURfQllURTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLldlYkdMQXR0cmlidXRlczogVW5zdXBwb3J0ZWQgYnVmZmVyIGRhdGEgZm9ybWF0OiAnICsgYXJyYXkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB7XG5cdFx0XHRidWZmZXI6IGJ1ZmZlcixcblx0XHRcdHR5cGU6IHR5cGUsXG5cdFx0XHRieXRlc1BlckVsZW1lbnQ6IGFycmF5LkJZVEVTX1BFUl9FTEVNRU5ULFxuXHRcdFx0dmVyc2lvbjogYXR0cmlidXRlLnZlcnNpb24sXG5cdFx0XHRzaXplOiBzaXplXG5cdFx0fTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gdXBkYXRlQnVmZmVyKCBidWZmZXIsIGF0dHJpYnV0ZSwgYnVmZmVyVHlwZSApIHtcblxuXHRcdGNvbnN0IGFycmF5ID0gYXR0cmlidXRlLmFycmF5O1xuXHRcdGNvbnN0IHVwZGF0ZVJhbmdlID0gYXR0cmlidXRlLl91cGRhdGVSYW5nZTsgLy8gQGRlcHJlY2F0ZWQsIHIxNTlcblx0XHRjb25zdCB1cGRhdGVSYW5nZXMgPSBhdHRyaWJ1dGUudXBkYXRlUmFuZ2VzO1xuXG5cdFx0Z2wuYmluZEJ1ZmZlciggYnVmZmVyVHlwZSwgYnVmZmVyICk7XG5cblx0XHRpZiAoIHVwZGF0ZVJhbmdlLmNvdW50ID09PSAtIDEgJiYgdXBkYXRlUmFuZ2VzLmxlbmd0aCA9PT0gMCApIHtcblxuXHRcdFx0Ly8gTm90IHVzaW5nIHVwZGF0ZSByYW5nZXNcblx0XHRcdGdsLmJ1ZmZlclN1YkRhdGEoIGJ1ZmZlclR5cGUsIDAsIGFycmF5ICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHVwZGF0ZVJhbmdlcy5sZW5ndGggIT09IDAgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHVwZGF0ZVJhbmdlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHJhbmdlID0gdXBkYXRlUmFuZ2VzWyBpIF07XG5cblx0XHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggYnVmZmVyVHlwZSwgcmFuZ2Uuc3RhcnQgKiBhcnJheS5CWVRFU19QRVJfRUxFTUVOVCxcblx0XHRcdFx0XHRhcnJheSwgcmFuZ2Uuc3RhcnQsIHJhbmdlLmNvdW50ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0YXR0cmlidXRlLmNsZWFyVXBkYXRlUmFuZ2VzKCk7XG5cblx0XHR9XG5cblx0XHQvLyBAZGVwcmVjYXRlZCwgcjE1OVxuXHRcdGlmICggdXBkYXRlUmFuZ2UuY291bnQgIT09IC0gMSApIHtcblxuXHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggYnVmZmVyVHlwZSwgdXBkYXRlUmFuZ2Uub2Zmc2V0ICogYXJyYXkuQllURVNfUEVSX0VMRU1FTlQsXG5cdFx0XHRcdGFycmF5LCB1cGRhdGVSYW5nZS5vZmZzZXQsIHVwZGF0ZVJhbmdlLmNvdW50ICk7XG5cblx0XHRcdHVwZGF0ZVJhbmdlLmNvdW50ID0gLSAxOyAvLyByZXNldCByYW5nZVxuXG5cdFx0fVxuXG5cdFx0YXR0cmlidXRlLm9uVXBsb2FkQ2FsbGJhY2soKTtcblxuXHR9XG5cblx0Ly9cblxuXHRmdW5jdGlvbiBnZXQoIGF0dHJpYnV0ZSApIHtcblxuXHRcdGlmICggYXR0cmlidXRlLmlzSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUgKSBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGUuZGF0YTtcblxuXHRcdHJldHVybiBidWZmZXJzLmdldCggYXR0cmlidXRlICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlbW92ZSggYXR0cmlidXRlICkge1xuXG5cdFx0aWYgKCBhdHRyaWJ1dGUuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSApIGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZS5kYXRhO1xuXG5cdFx0Y29uc3QgZGF0YSA9IGJ1ZmZlcnMuZ2V0KCBhdHRyaWJ1dGUgKTtcblxuXHRcdGlmICggZGF0YSApIHtcblxuXHRcdFx0Z2wuZGVsZXRlQnVmZmVyKCBkYXRhLmJ1ZmZlciApO1xuXG5cdFx0XHRidWZmZXJzLmRlbGV0ZSggYXR0cmlidXRlICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHVwZGF0ZSggYXR0cmlidXRlLCBidWZmZXJUeXBlICkge1xuXG5cdFx0aWYgKCBhdHRyaWJ1dGUuaXNHTEJ1ZmZlckF0dHJpYnV0ZSApIHtcblxuXHRcdFx0Y29uc3QgY2FjaGVkID0gYnVmZmVycy5nZXQoIGF0dHJpYnV0ZSApO1xuXG5cdFx0XHRpZiAoICEgY2FjaGVkIHx8IGNhY2hlZC52ZXJzaW9uIDwgYXR0cmlidXRlLnZlcnNpb24gKSB7XG5cblx0XHRcdFx0YnVmZmVycy5zZXQoIGF0dHJpYnV0ZSwge1xuXHRcdFx0XHRcdGJ1ZmZlcjogYXR0cmlidXRlLmJ1ZmZlcixcblx0XHRcdFx0XHR0eXBlOiBhdHRyaWJ1dGUudHlwZSxcblx0XHRcdFx0XHRieXRlc1BlckVsZW1lbnQ6IGF0dHJpYnV0ZS5lbGVtZW50U2l6ZSxcblx0XHRcdFx0XHR2ZXJzaW9uOiBhdHRyaWJ1dGUudmVyc2lvblxuXHRcdFx0XHR9ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBhdHRyaWJ1dGUuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSApIGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZS5kYXRhO1xuXG5cdFx0Y29uc3QgZGF0YSA9IGJ1ZmZlcnMuZ2V0KCBhdHRyaWJ1dGUgKTtcblxuXHRcdGlmICggZGF0YSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRidWZmZXJzLnNldCggYXR0cmlidXRlLCBjcmVhdGVCdWZmZXIoIGF0dHJpYnV0ZSwgYnVmZmVyVHlwZSApICk7XG5cblx0XHR9IGVsc2UgaWYgKCBkYXRhLnZlcnNpb24gPCBhdHRyaWJ1dGUudmVyc2lvbiApIHtcblxuXHRcdFx0aWYgKCBkYXRhLnNpemUgIT09IGF0dHJpYnV0ZS5hcnJheS5ieXRlTGVuZ3RoICkge1xuXG5cdFx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLldlYkdMQXR0cmlidXRlczogVGhlIHNpemUgb2YgdGhlIGJ1ZmZlciBhdHRyaWJ1dGVcXCdzIGFycmF5IGJ1ZmZlciBkb2VzIG5vdCBtYXRjaCB0aGUgb3JpZ2luYWwgc2l6ZS4gUmVzaXppbmcgYnVmZmVyIGF0dHJpYnV0ZXMgaXMgbm90IHN1cHBvcnRlZC4nICk7XG5cblx0XHRcdH1cblxuXHRcdFx0dXBkYXRlQnVmZmVyKCBkYXRhLmJ1ZmZlciwgYXR0cmlidXRlLCBidWZmZXJUeXBlICk7XG5cblx0XHRcdGRhdGEudmVyc2lvbiA9IGF0dHJpYnV0ZS52ZXJzaW9uO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4ge1xuXG5cdFx0Z2V0OiBnZXQsXG5cdFx0cmVtb3ZlOiByZW1vdmUsXG5cdFx0dXBkYXRlOiB1cGRhdGVcblxuXHR9O1xuXG59XG5cbmNsYXNzIFBsYW5lR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgd2lkdGhTZWdtZW50cyA9IDEsIGhlaWdodFNlZ21lbnRzID0gMSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnUGxhbmVHZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHR3aWR0aDogd2lkdGgsXG5cdFx0XHRoZWlnaHQ6IGhlaWdodCxcblx0XHRcdHdpZHRoU2VnbWVudHM6IHdpZHRoU2VnbWVudHMsXG5cdFx0XHRoZWlnaHRTZWdtZW50czogaGVpZ2h0U2VnbWVudHNcblx0XHR9O1xuXG5cdFx0Y29uc3Qgd2lkdGhfaGFsZiA9IHdpZHRoIC8gMjtcblx0XHRjb25zdCBoZWlnaHRfaGFsZiA9IGhlaWdodCAvIDI7XG5cblx0XHRjb25zdCBncmlkWCA9IE1hdGguZmxvb3IoIHdpZHRoU2VnbWVudHMgKTtcblx0XHRjb25zdCBncmlkWSA9IE1hdGguZmxvb3IoIGhlaWdodFNlZ21lbnRzICk7XG5cblx0XHRjb25zdCBncmlkWDEgPSBncmlkWCArIDE7XG5cdFx0Y29uc3QgZ3JpZFkxID0gZ3JpZFkgKyAxO1xuXG5cdFx0Y29uc3Qgc2VnbWVudF93aWR0aCA9IHdpZHRoIC8gZ3JpZFg7XG5cdFx0Y29uc3Qgc2VnbWVudF9oZWlnaHQgPSBoZWlnaHQgLyBncmlkWTtcblxuXHRcdC8vXG5cblx0XHRjb25zdCBpbmRpY2VzID0gW107XG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcblx0XHRjb25zdCBub3JtYWxzID0gW107XG5cdFx0Y29uc3QgdXZzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaXkgPSAwOyBpeSA8IGdyaWRZMTsgaXkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHkgPSBpeSAqIHNlZ21lbnRfaGVpZ2h0IC0gaGVpZ2h0X2hhbGY7XG5cblx0XHRcdGZvciAoIGxldCBpeCA9IDA7IGl4IDwgZ3JpZFgxOyBpeCArKyApIHtcblxuXHRcdFx0XHRjb25zdCB4ID0gaXggKiBzZWdtZW50X3dpZHRoIC0gd2lkdGhfaGFsZjtcblxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB4LCAtIHksIDAgKTtcblxuXHRcdFx0XHRub3JtYWxzLnB1c2goIDAsIDAsIDEgKTtcblxuXHRcdFx0XHR1dnMucHVzaCggaXggLyBncmlkWCApO1xuXHRcdFx0XHR1dnMucHVzaCggMSAtICggaXkgLyBncmlkWSApICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZvciAoIGxldCBpeSA9IDA7IGl5IDwgZ3JpZFk7IGl5ICsrICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaXggPSAwOyBpeCA8IGdyaWRYOyBpeCArKyApIHtcblxuXHRcdFx0XHRjb25zdCBhID0gaXggKyBncmlkWDEgKiBpeTtcblx0XHRcdFx0Y29uc3QgYiA9IGl4ICsgZ3JpZFgxICogKCBpeSArIDEgKTtcblx0XHRcdFx0Y29uc3QgYyA9ICggaXggKyAxICkgKyBncmlkWDEgKiAoIGl5ICsgMSApO1xuXHRcdFx0XHRjb25zdCBkID0gKCBpeCArIDEgKSArIGdyaWRYMSAqIGl5O1xuXG5cdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGIsIGMsIGQgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IFBsYW5lR2VvbWV0cnkoIGRhdGEud2lkdGgsIGRhdGEuaGVpZ2h0LCBkYXRhLndpZHRoU2VnbWVudHMsIGRhdGEuaGVpZ2h0U2VnbWVudHMgKTtcblxuXHR9XG5cbn1cblxudmFyIGFscGhhaGFzaF9mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9BTFBIQUhBU0hcXG5cXHRpZiAoIGRpZmZ1c2VDb2xvci5hIDwgZ2V0QWxwaGFIYXNoVGhyZXNob2xkKCB2UG9zaXRpb24gKSApIGRpc2NhcmQ7XFxuI2VuZGlmXCI7XG5cbnZhciBhbHBoYWhhc2hfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9BTFBIQUhBU0hcXG5cXHRjb25zdCBmbG9hdCBBTFBIQV9IQVNIX1NDQUxFID0gMC4wNTtcXG5cXHRmbG9hdCBoYXNoMkQoIHZlYzIgdmFsdWUgKSB7XFxuXFx0XFx0cmV0dXJuIGZyYWN0KCAxLjBlNCAqIHNpbiggMTcuMCAqIHZhbHVlLnggKyAwLjEgKiB2YWx1ZS55ICkgKiAoIDAuMSArIGFicyggc2luKCAxMy4wICogdmFsdWUueSArIHZhbHVlLnggKSApICkgKTtcXG5cXHR9XFxuXFx0ZmxvYXQgaGFzaDNEKCB2ZWMzIHZhbHVlICkge1xcblxcdFxcdHJldHVybiBoYXNoMkQoIHZlYzIoIGhhc2gyRCggdmFsdWUueHkgKSwgdmFsdWUueiApICk7XFxuXFx0fVxcblxcdGZsb2F0IGdldEFscGhhSGFzaFRocmVzaG9sZCggdmVjMyBwb3NpdGlvbiApIHtcXG5cXHRcXHRmbG9hdCBtYXhEZXJpdiA9IG1heChcXG5cXHRcXHRcXHRsZW5ndGgoIGRGZHgoIHBvc2l0aW9uLnh5eiApICksXFxuXFx0XFx0XFx0bGVuZ3RoKCBkRmR5KCBwb3NpdGlvbi54eXogKSApXFxuXFx0XFx0KTtcXG5cXHRcXHRmbG9hdCBwaXhTY2FsZSA9IDEuMCAvICggQUxQSEFfSEFTSF9TQ0FMRSAqIG1heERlcml2ICk7XFxuXFx0XFx0dmVjMiBwaXhTY2FsZXMgPSB2ZWMyKFxcblxcdFxcdFxcdGV4cDIoIGZsb29yKCBsb2cyKCBwaXhTY2FsZSApICkgKSxcXG5cXHRcXHRcXHRleHAyKCBjZWlsKCBsb2cyKCBwaXhTY2FsZSApICkgKVxcblxcdFxcdCk7XFxuXFx0XFx0dmVjMiBhbHBoYSA9IHZlYzIoXFxuXFx0XFx0XFx0aGFzaDNEKCBmbG9vciggcGl4U2NhbGVzLnggKiBwb3NpdGlvbi54eXogKSApLFxcblxcdFxcdFxcdGhhc2gzRCggZmxvb3IoIHBpeFNjYWxlcy55ICogcG9zaXRpb24ueHl6ICkgKVxcblxcdFxcdCk7XFxuXFx0XFx0ZmxvYXQgbGVycEZhY3RvciA9IGZyYWN0KCBsb2cyKCBwaXhTY2FsZSApICk7XFxuXFx0XFx0ZmxvYXQgeCA9ICggMS4wIC0gbGVycEZhY3RvciApICogYWxwaGEueCArIGxlcnBGYWN0b3IgKiBhbHBoYS55O1xcblxcdFxcdGZsb2F0IGEgPSBtaW4oIGxlcnBGYWN0b3IsIDEuMCAtIGxlcnBGYWN0b3IgKTtcXG5cXHRcXHR2ZWMzIGNhc2VzID0gdmVjMyhcXG5cXHRcXHRcXHR4ICogeCAvICggMi4wICogYSAqICggMS4wIC0gYSApICksXFxuXFx0XFx0XFx0KCB4IC0gMC41ICogYSApIC8gKCAxLjAgLSBhICksXFxuXFx0XFx0XFx0MS4wIC0gKCAoIDEuMCAtIHggKSAqICggMS4wIC0geCApIC8gKCAyLjAgKiBhICogKCAxLjAgLSBhICkgKSApXFxuXFx0XFx0KTtcXG5cXHRcXHRmbG9hdCB0aHJlc2hvbGQgPSAoIHggPCAoIDEuMCAtIGEgKSApXFxuXFx0XFx0XFx0PyAoICggeCA8IGEgKSA/IGNhc2VzLnggOiBjYXNlcy55IClcXG5cXHRcXHRcXHQ6IGNhc2VzLno7XFxuXFx0XFx0cmV0dXJuIGNsYW1wKCB0aHJlc2hvbGQgLCAxLjBlLTYsIDEuMCApO1xcblxcdH1cXG4jZW5kaWZcIjtcblxudmFyIGFscGhhbWFwX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0FMUEhBTUFQXFxuXFx0ZGlmZnVzZUNvbG9yLmEgKj0gdGV4dHVyZTJEKCBhbHBoYU1hcCwgdkFscGhhTWFwVXYgKS5nO1xcbiNlbmRpZlwiO1xuXG52YXIgYWxwaGFtYXBfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9BTFBIQU1BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGFscGhhTWFwO1xcbiNlbmRpZlwiO1xuXG52YXIgYWxwaGF0ZXN0X2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0FMUEhBVEVTVFxcblxcdCNpZmRlZiBBTFBIQV9UT19DT1ZFUkFHRVxcblxcdGRpZmZ1c2VDb2xvci5hID0gc21vb3Roc3RlcCggYWxwaGFUZXN0LCBhbHBoYVRlc3QgKyBmd2lkdGgoIGRpZmZ1c2VDb2xvci5hICksIGRpZmZ1c2VDb2xvci5hICk7XFxuXFx0aWYgKCBkaWZmdXNlQ29sb3IuYSA9PSAwLjAgKSBkaXNjYXJkO1xcblxcdCNlbHNlXFxuXFx0aWYgKCBkaWZmdXNlQ29sb3IuYSA8IGFscGhhVGVzdCApIGRpc2NhcmQ7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXCI7XG5cbnZhciBhbHBoYXRlc3RfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9BTFBIQVRFU1RcXG5cXHR1bmlmb3JtIGZsb2F0IGFscGhhVGVzdDtcXG4jZW5kaWZcIjtcblxudmFyIGFvbWFwX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0FPTUFQXFxuXFx0ZmxvYXQgYW1iaWVudE9jY2x1c2lvbiA9ICggdGV4dHVyZTJEKCBhb01hcCwgdkFvTWFwVXYgKS5yIC0gMS4wICkgKiBhb01hcEludGVuc2l0eSArIDEuMDtcXG5cXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKj0gYW1iaWVudE9jY2x1c2lvbjtcXG5cXHQjaWYgZGVmaW5lZCggVVNFX0NMRUFSQ09BVCApIFxcblxcdFxcdGNsZWFyY29hdFNwZWN1bGFySW5kaXJlY3QgKj0gYW1iaWVudE9jY2x1c2lvbjtcXG5cXHQjZW5kaWZcXG5cXHQjaWYgZGVmaW5lZCggVVNFX1NIRUVOICkgXFxuXFx0XFx0c2hlZW5TcGVjdWxhckluZGlyZWN0ICo9IGFtYmllbnRPY2NsdXNpb247XFxuXFx0I2VuZGlmXFxuXFx0I2lmIGRlZmluZWQoIFVTRV9FTlZNQVAgKSAmJiBkZWZpbmVkKCBTVEFOREFSRCApXFxuXFx0XFx0ZmxvYXQgZG90TlYgPSBzYXR1cmF0ZSggZG90KCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyICkgKTtcXG5cXHRcXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdFNwZWN1bGFyICo9IGNvbXB1dGVTcGVjdWxhck9jY2x1c2lvbiggZG90TlYsIGFtYmllbnRPY2NsdXNpb24sIG1hdGVyaWFsLnJvdWdobmVzcyApO1xcblxcdCNlbmRpZlxcbiNlbmRpZlwiO1xuXG52YXIgYW9tYXBfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9BT01BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGFvTWFwO1xcblxcdHVuaWZvcm0gZmxvYXQgYW9NYXBJbnRlbnNpdHk7XFxuI2VuZGlmXCI7XG5cbnZhciBiYXRjaGluZ19wYXJzX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9CQVRDSElOR1xcblxcdCNpZiAhIGRlZmluZWQoIEdMX0FOR0xFX211bHRpX2RyYXcgKVxcblxcdCNkZWZpbmUgZ2xfRHJhd0lEIF9nbF9EcmF3SURcXG5cXHR1bmlmb3JtIGludCBfZ2xfRHJhd0lEO1xcblxcdCNlbmRpZlxcblxcdHVuaWZvcm0gaGlnaHAgc2FtcGxlcjJEIGJhdGNoaW5nVGV4dHVyZTtcXG5cXHR1bmlmb3JtIGhpZ2hwIHVzYW1wbGVyMkQgYmF0Y2hpbmdJZFRleHR1cmU7XFxuXFx0bWF0NCBnZXRCYXRjaGluZ01hdHJpeCggY29uc3QgaW4gZmxvYXQgaSApIHtcXG5cXHRcXHRpbnQgc2l6ZSA9IHRleHR1cmVTaXplKCBiYXRjaGluZ1RleHR1cmUsIDAgKS54O1xcblxcdFxcdGludCBqID0gaW50KCBpICkgKiA0O1xcblxcdFxcdGludCB4ID0gaiAlIHNpemU7XFxuXFx0XFx0aW50IHkgPSBqIC8gc2l6ZTtcXG5cXHRcXHR2ZWM0IHYxID0gdGV4ZWxGZXRjaCggYmF0Y2hpbmdUZXh0dXJlLCBpdmVjMiggeCwgeSApLCAwICk7XFxuXFx0XFx0dmVjNCB2MiA9IHRleGVsRmV0Y2goIGJhdGNoaW5nVGV4dHVyZSwgaXZlYzIoIHggKyAxLCB5ICksIDAgKTtcXG5cXHRcXHR2ZWM0IHYzID0gdGV4ZWxGZXRjaCggYmF0Y2hpbmdUZXh0dXJlLCBpdmVjMiggeCArIDIsIHkgKSwgMCApO1xcblxcdFxcdHZlYzQgdjQgPSB0ZXhlbEZldGNoKCBiYXRjaGluZ1RleHR1cmUsIGl2ZWMyKCB4ICsgMywgeSApLCAwICk7XFxuXFx0XFx0cmV0dXJuIG1hdDQoIHYxLCB2MiwgdjMsIHY0ICk7XFxuXFx0fVxcblxcdGZsb2F0IGdldEluZGlyZWN0SW5kZXgoIGNvbnN0IGluIGludCBpICkge1xcblxcdFxcdGludCBzaXplID0gdGV4dHVyZVNpemUoIGJhdGNoaW5nSWRUZXh0dXJlLCAwICkueDtcXG5cXHRcXHRpbnQgeCA9IGkgJSBzaXplO1xcblxcdFxcdGludCB5ID0gaSAvIHNpemU7XFxuXFx0XFx0cmV0dXJuIGZsb2F0KCB0ZXhlbEZldGNoKCBiYXRjaGluZ0lkVGV4dHVyZSwgaXZlYzIoIHgsIHkgKSwgMCApLnIgKTtcXG5cXHR9XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9CQVRDSElOR19DT0xPUlxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGJhdGNoaW5nQ29sb3JUZXh0dXJlO1xcblxcdHZlYzMgZ2V0QmF0Y2hpbmdDb2xvciggY29uc3QgaW4gZmxvYXQgaSApIHtcXG5cXHRcXHRpbnQgc2l6ZSA9IHRleHR1cmVTaXplKCBiYXRjaGluZ0NvbG9yVGV4dHVyZSwgMCApLng7XFxuXFx0XFx0aW50IGogPSBpbnQoIGkgKTtcXG5cXHRcXHRpbnQgeCA9IGogJSBzaXplO1xcblxcdFxcdGludCB5ID0gaiAvIHNpemU7XFxuXFx0XFx0cmV0dXJuIHRleGVsRmV0Y2goIGJhdGNoaW5nQ29sb3JUZXh0dXJlLCBpdmVjMiggeCwgeSApLCAwICkucmdiO1xcblxcdH1cXG4jZW5kaWZcIjtcblxudmFyIGJhdGNoaW5nX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9CQVRDSElOR1xcblxcdG1hdDQgYmF0Y2hpbmdNYXRyaXggPSBnZXRCYXRjaGluZ01hdHJpeCggZ2V0SW5kaXJlY3RJbmRleCggZ2xfRHJhd0lEICkgKTtcXG4jZW5kaWZcIjtcblxudmFyIGJlZ2luX3ZlcnRleCA9IFwidmVjMyB0cmFuc2Zvcm1lZCA9IHZlYzMoIHBvc2l0aW9uICk7XFxuI2lmZGVmIFVTRV9BTFBIQUhBU0hcXG5cXHR2UG9zaXRpb24gPSB2ZWMzKCBwb3NpdGlvbiApO1xcbiNlbmRpZlwiO1xuXG52YXIgYmVnaW5ub3JtYWxfdmVydGV4ID0gXCJ2ZWMzIG9iamVjdE5vcm1hbCA9IHZlYzMoIG5vcm1hbCApO1xcbiNpZmRlZiBVU0VfVEFOR0VOVFxcblxcdHZlYzMgb2JqZWN0VGFuZ2VudCA9IHZlYzMoIHRhbmdlbnQueHl6ICk7XFxuI2VuZGlmXCI7XG5cbnZhciBic2RmcyA9IFwiZmxvYXQgR19CbGlublBob25nX0ltcGxpY2l0KCApIHtcXG5cXHRyZXR1cm4gMC4yNTtcXG59XFxuZmxvYXQgRF9CbGlublBob25nKCBjb25zdCBpbiBmbG9hdCBzaGluaW5lc3MsIGNvbnN0IGluIGZsb2F0IGRvdE5IICkge1xcblxcdHJldHVybiBSRUNJUFJPQ0FMX1BJICogKCBzaGluaW5lc3MgKiAwLjUgKyAxLjAgKSAqIHBvdyggZG90TkgsIHNoaW5pbmVzcyApO1xcbn1cXG52ZWMzIEJSREZfQmxpbm5QaG9uZyggY29uc3QgaW4gdmVjMyBsaWdodERpciwgY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgY29uc3QgaW4gdmVjMyBzcGVjdWxhckNvbG9yLCBjb25zdCBpbiBmbG9hdCBzaGluaW5lc3MgKSB7XFxuXFx0dmVjMyBoYWxmRGlyID0gbm9ybWFsaXplKCBsaWdodERpciArIHZpZXdEaXIgKTtcXG5cXHRmbG9hdCBkb3ROSCA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgaGFsZkRpciApICk7XFxuXFx0ZmxvYXQgZG90VkggPSBzYXR1cmF0ZSggZG90KCB2aWV3RGlyLCBoYWxmRGlyICkgKTtcXG5cXHR2ZWMzIEYgPSBGX1NjaGxpY2soIHNwZWN1bGFyQ29sb3IsIDEuMCwgZG90VkggKTtcXG5cXHRmbG9hdCBHID0gR19CbGlublBob25nX0ltcGxpY2l0KCApO1xcblxcdGZsb2F0IEQgPSBEX0JsaW5uUGhvbmcoIHNoaW5pbmVzcywgZG90TkggKTtcXG5cXHRyZXR1cm4gRiAqICggRyAqIEQgKTtcXG59IC8vIHZhbGlkYXRlZFwiO1xuXG52YXIgaXJpZGVzY2VuY2VfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcXG5cXHRjb25zdCBtYXQzIFhZWl9UT19SRUM3MDkgPSBtYXQzKFxcblxcdFxcdCAzLjI0MDQ1NDIsIC0wLjk2OTI2NjAsICAwLjA1NTY0MzQsXFxuXFx0XFx0LTEuNTM3MTM4NSwgIDEuODc2MDEwOCwgLTAuMjA0MDI1OSxcXG5cXHRcXHQtMC40OTg1MzE0LCAgMC4wNDE1NTYwLCAgMS4wNTcyMjUyXFxuXFx0KTtcXG5cXHR2ZWMzIEZyZXNuZWwwVG9Jb3IoIHZlYzMgZnJlc25lbDAgKSB7XFxuXFx0XFx0dmVjMyBzcXJ0RjAgPSBzcXJ0KCBmcmVzbmVsMCApO1xcblxcdFxcdHJldHVybiAoIHZlYzMoIDEuMCApICsgc3FydEYwICkgLyAoIHZlYzMoIDEuMCApIC0gc3FydEYwICk7XFxuXFx0fVxcblxcdHZlYzMgSW9yVG9GcmVzbmVsMCggdmVjMyB0cmFuc21pdHRlZElvciwgZmxvYXQgaW5jaWRlbnRJb3IgKSB7XFxuXFx0XFx0cmV0dXJuIHBvdzIoICggdHJhbnNtaXR0ZWRJb3IgLSB2ZWMzKCBpbmNpZGVudElvciApICkgLyAoIHRyYW5zbWl0dGVkSW9yICsgdmVjMyggaW5jaWRlbnRJb3IgKSApICk7XFxuXFx0fVxcblxcdGZsb2F0IElvclRvRnJlc25lbDAoIGZsb2F0IHRyYW5zbWl0dGVkSW9yLCBmbG9hdCBpbmNpZGVudElvciApIHtcXG5cXHRcXHRyZXR1cm4gcG93MiggKCB0cmFuc21pdHRlZElvciAtIGluY2lkZW50SW9yICkgLyAoIHRyYW5zbWl0dGVkSW9yICsgaW5jaWRlbnRJb3IgKSk7XFxuXFx0fVxcblxcdHZlYzMgZXZhbFNlbnNpdGl2aXR5KCBmbG9hdCBPUEQsIHZlYzMgc2hpZnQgKSB7XFxuXFx0XFx0ZmxvYXQgcGhhc2UgPSAyLjAgKiBQSSAqIE9QRCAqIDEuMGUtOTtcXG5cXHRcXHR2ZWMzIHZhbCA9IHZlYzMoIDUuNDg1NmUtMTMsIDQuNDIwMWUtMTMsIDUuMjQ4MWUtMTMgKTtcXG5cXHRcXHR2ZWMzIHBvcyA9IHZlYzMoIDEuNjgxMGUrMDYsIDEuNzk1M2UrMDYsIDIuMjA4NGUrMDYgKTtcXG5cXHRcXHR2ZWMzIHZhciA9IHZlYzMoIDQuMzI3OGUrMDksIDkuMzA0NmUrMDksIDYuNjEyMWUrMDkgKTtcXG5cXHRcXHR2ZWMzIHh5eiA9IHZhbCAqIHNxcnQoIDIuMCAqIFBJICogdmFyICkgKiBjb3MoIHBvcyAqIHBoYXNlICsgc2hpZnQgKSAqIGV4cCggLSBwb3cyKCBwaGFzZSApICogdmFyICk7XFxuXFx0XFx0eHl6LnggKz0gOS43NDcwZS0xNCAqIHNxcnQoIDIuMCAqIFBJICogNC41MjgyZSswOSApICogY29zKCAyLjIzOTllKzA2ICogcGhhc2UgKyBzaGlmdFsgMCBdICkgKiBleHAoIC0gNC41MjgyZSswOSAqIHBvdzIoIHBoYXNlICkgKTtcXG5cXHRcXHR4eXogLz0gMS4wNjg1ZS03O1xcblxcdFxcdHZlYzMgcmdiID0gWFlaX1RPX1JFQzcwOSAqIHh5ejtcXG5cXHRcXHRyZXR1cm4gcmdiO1xcblxcdH1cXG5cXHR2ZWMzIGV2YWxJcmlkZXNjZW5jZSggZmxvYXQgb3V0c2lkZUlPUiwgZmxvYXQgZXRhMiwgZmxvYXQgY29zVGhldGExLCBmbG9hdCB0aGluRmlsbVRoaWNrbmVzcywgdmVjMyBiYXNlRjAgKSB7XFxuXFx0XFx0dmVjMyBJO1xcblxcdFxcdGZsb2F0IGlyaWRlc2NlbmNlSU9SID0gbWl4KCBvdXRzaWRlSU9SLCBldGEyLCBzbW9vdGhzdGVwKCAwLjAsIDAuMDMsIHRoaW5GaWxtVGhpY2tuZXNzICkgKTtcXG5cXHRcXHRmbG9hdCBzaW5UaGV0YTJTcSA9IHBvdzIoIG91dHNpZGVJT1IgLyBpcmlkZXNjZW5jZUlPUiApICogKCAxLjAgLSBwb3cyKCBjb3NUaGV0YTEgKSApO1xcblxcdFxcdGZsb2F0IGNvc1RoZXRhMlNxID0gMS4wIC0gc2luVGhldGEyU3E7XFxuXFx0XFx0aWYgKCBjb3NUaGV0YTJTcSA8IDAuMCApIHtcXG5cXHRcXHRcXHRyZXR1cm4gdmVjMyggMS4wICk7XFxuXFx0XFx0fVxcblxcdFxcdGZsb2F0IGNvc1RoZXRhMiA9IHNxcnQoIGNvc1RoZXRhMlNxICk7XFxuXFx0XFx0ZmxvYXQgUjAgPSBJb3JUb0ZyZXNuZWwwKCBpcmlkZXNjZW5jZUlPUiwgb3V0c2lkZUlPUiApO1xcblxcdFxcdGZsb2F0IFIxMiA9IEZfU2NobGljayggUjAsIDEuMCwgY29zVGhldGExICk7XFxuXFx0XFx0ZmxvYXQgVDEyMSA9IDEuMCAtIFIxMjtcXG5cXHRcXHRmbG9hdCBwaGkxMiA9IDAuMDtcXG5cXHRcXHRpZiAoIGlyaWRlc2NlbmNlSU9SIDwgb3V0c2lkZUlPUiApIHBoaTEyID0gUEk7XFxuXFx0XFx0ZmxvYXQgcGhpMjEgPSBQSSAtIHBoaTEyO1xcblxcdFxcdHZlYzMgYmFzZUlPUiA9IEZyZXNuZWwwVG9Jb3IoIGNsYW1wKCBiYXNlRjAsIDAuMCwgMC45OTk5ICkgKTtcXHRcXHR2ZWMzIFIxID0gSW9yVG9GcmVzbmVsMCggYmFzZUlPUiwgaXJpZGVzY2VuY2VJT1IgKTtcXG5cXHRcXHR2ZWMzIFIyMyA9IEZfU2NobGljayggUjEsIDEuMCwgY29zVGhldGEyICk7XFxuXFx0XFx0dmVjMyBwaGkyMyA9IHZlYzMoIDAuMCApO1xcblxcdFxcdGlmICggYmFzZUlPUlsgMCBdIDwgaXJpZGVzY2VuY2VJT1IgKSBwaGkyM1sgMCBdID0gUEk7XFxuXFx0XFx0aWYgKCBiYXNlSU9SWyAxIF0gPCBpcmlkZXNjZW5jZUlPUiApIHBoaTIzWyAxIF0gPSBQSTtcXG5cXHRcXHRpZiAoIGJhc2VJT1JbIDIgXSA8IGlyaWRlc2NlbmNlSU9SICkgcGhpMjNbIDIgXSA9IFBJO1xcblxcdFxcdGZsb2F0IE9QRCA9IDIuMCAqIGlyaWRlc2NlbmNlSU9SICogdGhpbkZpbG1UaGlja25lc3MgKiBjb3NUaGV0YTI7XFxuXFx0XFx0dmVjMyBwaGkgPSB2ZWMzKCBwaGkyMSApICsgcGhpMjM7XFxuXFx0XFx0dmVjMyBSMTIzID0gY2xhbXAoIFIxMiAqIFIyMywgMWUtNSwgMC45OTk5ICk7XFxuXFx0XFx0dmVjMyByMTIzID0gc3FydCggUjEyMyApO1xcblxcdFxcdHZlYzMgUnMgPSBwb3cyKCBUMTIxICkgKiBSMjMgLyAoIHZlYzMoIDEuMCApIC0gUjEyMyApO1xcblxcdFxcdHZlYzMgQzAgPSBSMTIgKyBScztcXG5cXHRcXHRJID0gQzA7XFxuXFx0XFx0dmVjMyBDbSA9IFJzIC0gVDEyMTtcXG5cXHRcXHRmb3IgKCBpbnQgbSA9IDE7IG0gPD0gMjsgKysgbSApIHtcXG5cXHRcXHRcXHRDbSAqPSByMTIzO1xcblxcdFxcdFxcdHZlYzMgU20gPSAyLjAgKiBldmFsU2Vuc2l0aXZpdHkoIGZsb2F0KCBtICkgKiBPUEQsIGZsb2F0KCBtICkgKiBwaGkgKTtcXG5cXHRcXHRcXHRJICs9IENtICogU207XFxuXFx0XFx0fVxcblxcdFxcdHJldHVybiBtYXgoIEksIHZlYzMoIDAuMCApICk7XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgYnVtcG1hcF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0JVTVBNQVBcXG5cXHR1bmlmb3JtIHNhbXBsZXIyRCBidW1wTWFwO1xcblxcdHVuaWZvcm0gZmxvYXQgYnVtcFNjYWxlO1xcblxcdHZlYzIgZEhkeHlfZndkKCkge1xcblxcdFxcdHZlYzIgZFNUZHggPSBkRmR4KCB2QnVtcE1hcFV2ICk7XFxuXFx0XFx0dmVjMiBkU1RkeSA9IGRGZHkoIHZCdW1wTWFwVXYgKTtcXG5cXHRcXHRmbG9hdCBIbGwgPSBidW1wU2NhbGUgKiB0ZXh0dXJlMkQoIGJ1bXBNYXAsIHZCdW1wTWFwVXYgKS54O1xcblxcdFxcdGZsb2F0IGRCeCA9IGJ1bXBTY2FsZSAqIHRleHR1cmUyRCggYnVtcE1hcCwgdkJ1bXBNYXBVdiArIGRTVGR4ICkueCAtIEhsbDtcXG5cXHRcXHRmbG9hdCBkQnkgPSBidW1wU2NhbGUgKiB0ZXh0dXJlMkQoIGJ1bXBNYXAsIHZCdW1wTWFwVXYgKyBkU1RkeSApLnggLSBIbGw7XFxuXFx0XFx0cmV0dXJuIHZlYzIoIGRCeCwgZEJ5ICk7XFxuXFx0fVxcblxcdHZlYzMgcGVydHVyYk5vcm1hbEFyYiggdmVjMyBzdXJmX3BvcywgdmVjMyBzdXJmX25vcm0sIHZlYzIgZEhkeHksIGZsb2F0IGZhY2VEaXJlY3Rpb24gKSB7XFxuXFx0XFx0dmVjMyB2U2lnbWFYID0gbm9ybWFsaXplKCBkRmR4KCBzdXJmX3Bvcy54eXogKSApO1xcblxcdFxcdHZlYzMgdlNpZ21hWSA9IG5vcm1hbGl6ZSggZEZkeSggc3VyZl9wb3MueHl6ICkgKTtcXG5cXHRcXHR2ZWMzIHZOID0gc3VyZl9ub3JtO1xcblxcdFxcdHZlYzMgUjEgPSBjcm9zcyggdlNpZ21hWSwgdk4gKTtcXG5cXHRcXHR2ZWMzIFIyID0gY3Jvc3MoIHZOLCB2U2lnbWFYICk7XFxuXFx0XFx0ZmxvYXQgZkRldCA9IGRvdCggdlNpZ21hWCwgUjEgKSAqIGZhY2VEaXJlY3Rpb247XFxuXFx0XFx0dmVjMyB2R3JhZCA9IHNpZ24oIGZEZXQgKSAqICggZEhkeHkueCAqIFIxICsgZEhkeHkueSAqIFIyICk7XFxuXFx0XFx0cmV0dXJuIG5vcm1hbGl6ZSggYWJzKCBmRGV0ICkgKiBzdXJmX25vcm0gLSB2R3JhZCApO1xcblxcdH1cXG4jZW5kaWZcIjtcblxudmFyIGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudCA9IFwiI2lmIE5VTV9DTElQUElOR19QTEFORVMgPiAwXFxuXFx0dmVjNCBwbGFuZTtcXG5cXHQjaWZkZWYgQUxQSEFfVE9fQ09WRVJBR0VcXG5cXHRcXHRmbG9hdCBkaXN0YW5jZVRvUGxhbmUsIGRpc3RhbmNlR3JhZGllbnQ7XFxuXFx0XFx0ZmxvYXQgY2xpcE9wYWNpdHkgPSAxLjA7XFxuXFx0XFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxcblxcdFxcdGZvciAoIGludCBpID0gMDsgaSA8IFVOSU9OX0NMSVBQSU5HX1BMQU5FUzsgaSArKyApIHtcXG5cXHRcXHRcXHRwbGFuZSA9IGNsaXBwaW5nUGxhbmVzWyBpIF07XFxuXFx0XFx0XFx0ZGlzdGFuY2VUb1BsYW5lID0gLSBkb3QoIHZDbGlwUG9zaXRpb24sIHBsYW5lLnh5eiApICsgcGxhbmUudztcXG5cXHRcXHRcXHRkaXN0YW5jZUdyYWRpZW50ID0gZndpZHRoKCBkaXN0YW5jZVRvUGxhbmUgKSAvIDIuMDtcXG5cXHRcXHRcXHRjbGlwT3BhY2l0eSAqPSBzbW9vdGhzdGVwKCAtIGRpc3RhbmNlR3JhZGllbnQsIGRpc3RhbmNlR3JhZGllbnQsIGRpc3RhbmNlVG9QbGFuZSApO1xcblxcdFxcdFxcdGlmICggY2xpcE9wYWNpdHkgPT0gMC4wICkgZGlzY2FyZDtcXG5cXHRcXHR9XFxuXFx0XFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcXG5cXHRcXHQjaWYgVU5JT05fQ0xJUFBJTkdfUExBTkVTIDwgTlVNX0NMSVBQSU5HX1BMQU5FU1xcblxcdFxcdFxcdGZsb2F0IHVuaW9uQ2xpcE9wYWNpdHkgPSAxLjA7XFxuXFx0XFx0XFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxcblxcdFxcdFxcdGZvciAoIGludCBpID0gVU5JT05fQ0xJUFBJTkdfUExBTkVTOyBpIDwgTlVNX0NMSVBQSU5HX1BMQU5FUzsgaSArKyApIHtcXG5cXHRcXHRcXHRcXHRwbGFuZSA9IGNsaXBwaW5nUGxhbmVzWyBpIF07XFxuXFx0XFx0XFx0XFx0ZGlzdGFuY2VUb1BsYW5lID0gLSBkb3QoIHZDbGlwUG9zaXRpb24sIHBsYW5lLnh5eiApICsgcGxhbmUudztcXG5cXHRcXHRcXHRcXHRkaXN0YW5jZUdyYWRpZW50ID0gZndpZHRoKCBkaXN0YW5jZVRvUGxhbmUgKSAvIDIuMDtcXG5cXHRcXHRcXHRcXHR1bmlvbkNsaXBPcGFjaXR5ICo9IDEuMCAtIHNtb290aHN0ZXAoIC0gZGlzdGFuY2VHcmFkaWVudCwgZGlzdGFuY2VHcmFkaWVudCwgZGlzdGFuY2VUb1BsYW5lICk7XFxuXFx0XFx0XFx0fVxcblxcdFxcdFxcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXFxuXFx0XFx0XFx0Y2xpcE9wYWNpdHkgKj0gMS4wIC0gdW5pb25DbGlwT3BhY2l0eTtcXG5cXHRcXHQjZW5kaWZcXG5cXHRcXHRkaWZmdXNlQ29sb3IuYSAqPSBjbGlwT3BhY2l0eTtcXG5cXHRcXHRpZiAoIGRpZmZ1c2VDb2xvci5hID09IDAuMCApIGRpc2NhcmQ7XFxuXFx0I2Vsc2VcXG5cXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XFxuXFx0XFx0Zm9yICggaW50IGkgPSAwOyBpIDwgVU5JT05fQ0xJUFBJTkdfUExBTkVTOyBpICsrICkge1xcblxcdFxcdFxcdHBsYW5lID0gY2xpcHBpbmdQbGFuZXNbIGkgXTtcXG5cXHRcXHRcXHRpZiAoIGRvdCggdkNsaXBQb3NpdGlvbiwgcGxhbmUueHl6ICkgPiBwbGFuZS53ICkgZGlzY2FyZDtcXG5cXHRcXHR9XFxuXFx0XFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcXG5cXHRcXHQjaWYgVU5JT05fQ0xJUFBJTkdfUExBTkVTIDwgTlVNX0NMSVBQSU5HX1BMQU5FU1xcblxcdFxcdFxcdGJvb2wgY2xpcHBlZCA9IHRydWU7XFxuXFx0XFx0XFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxcblxcdFxcdFxcdGZvciAoIGludCBpID0gVU5JT05fQ0xJUFBJTkdfUExBTkVTOyBpIDwgTlVNX0NMSVBQSU5HX1BMQU5FUzsgaSArKyApIHtcXG5cXHRcXHRcXHRcXHRwbGFuZSA9IGNsaXBwaW5nUGxhbmVzWyBpIF07XFxuXFx0XFx0XFx0XFx0Y2xpcHBlZCA9ICggZG90KCB2Q2xpcFBvc2l0aW9uLCBwbGFuZS54eXogKSA+IHBsYW5lLncgKSAmJiBjbGlwcGVkO1xcblxcdFxcdFxcdH1cXG5cXHRcXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxcblxcdFxcdFxcdGlmICggY2xpcHBlZCApIGRpc2NhcmQ7XFxuXFx0XFx0I2VuZGlmXFxuXFx0I2VuZGlmXFxuI2VuZGlmXCI7XG5cbnZhciBjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudCA9IFwiI2lmIE5VTV9DTElQUElOR19QTEFORVMgPiAwXFxuXFx0dmFyeWluZyB2ZWMzIHZDbGlwUG9zaXRpb247XFxuXFx0dW5pZm9ybSB2ZWM0IGNsaXBwaW5nUGxhbmVzWyBOVU1fQ0xJUFBJTkdfUExBTkVTIF07XFxuI2VuZGlmXCI7XG5cbnZhciBjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXggPSBcIiNpZiBOVU1fQ0xJUFBJTkdfUExBTkVTID4gMFxcblxcdHZhcnlpbmcgdmVjMyB2Q2xpcFBvc2l0aW9uO1xcbiNlbmRpZlwiO1xuXG52YXIgY2xpcHBpbmdfcGxhbmVzX3ZlcnRleCA9IFwiI2lmIE5VTV9DTElQUElOR19QTEFORVMgPiAwXFxuXFx0dkNsaXBQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XFxuI2VuZGlmXCI7XG5cbnZhciBjb2xvcl9mcmFnbWVudCA9IFwiI2lmIGRlZmluZWQoIFVTRV9DT0xPUl9BTFBIQSApXFxuXFx0ZGlmZnVzZUNvbG9yICo9IHZDb2xvcjtcXG4jZWxpZiBkZWZpbmVkKCBVU0VfQ09MT1IgKVxcblxcdGRpZmZ1c2VDb2xvci5yZ2IgKj0gdkNvbG9yO1xcbiNlbmRpZlwiO1xuXG52YXIgY29sb3JfcGFyc19mcmFnbWVudCA9IFwiI2lmIGRlZmluZWQoIFVTRV9DT0xPUl9BTFBIQSApXFxuXFx0dmFyeWluZyB2ZWM0IHZDb2xvcjtcXG4jZWxpZiBkZWZpbmVkKCBVU0VfQ09MT1IgKVxcblxcdHZhcnlpbmcgdmVjMyB2Q29sb3I7XFxuI2VuZGlmXCI7XG5cbnZhciBjb2xvcl9wYXJzX3ZlcnRleCA9IFwiI2lmIGRlZmluZWQoIFVTRV9DT0xPUl9BTFBIQSApXFxuXFx0dmFyeWluZyB2ZWM0IHZDb2xvcjtcXG4jZWxpZiBkZWZpbmVkKCBVU0VfQ09MT1IgKSB8fCBkZWZpbmVkKCBVU0VfSU5TVEFOQ0lOR19DT0xPUiApIHx8IGRlZmluZWQoIFVTRV9CQVRDSElOR19DT0xPUiApXFxuXFx0dmFyeWluZyB2ZWMzIHZDb2xvcjtcXG4jZW5kaWZcIjtcblxudmFyIGNvbG9yX3ZlcnRleCA9IFwiI2lmIGRlZmluZWQoIFVTRV9DT0xPUl9BTFBIQSApXFxuXFx0dkNvbG9yID0gdmVjNCggMS4wICk7XFxuI2VsaWYgZGVmaW5lZCggVVNFX0NPTE9SICkgfHwgZGVmaW5lZCggVVNFX0lOU1RBTkNJTkdfQ09MT1IgKSB8fCBkZWZpbmVkKCBVU0VfQkFUQ0hJTkdfQ09MT1IgKVxcblxcdHZDb2xvciA9IHZlYzMoIDEuMCApO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ09MT1JcXG5cXHR2Q29sb3IgKj0gY29sb3I7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9JTlNUQU5DSU5HX0NPTE9SXFxuXFx0dkNvbG9yLnh5eiAqPSBpbnN0YW5jZUNvbG9yLnh5ejtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0JBVENISU5HX0NPTE9SXFxuXFx0dmVjMyBiYXRjaGluZ0NvbG9yID0gZ2V0QmF0Y2hpbmdDb2xvciggZ2V0SW5kaXJlY3RJbmRleCggZ2xfRHJhd0lEICkgKTtcXG5cXHR2Q29sb3IueHl6ICo9IGJhdGNoaW5nQ29sb3IueHl6O1xcbiNlbmRpZlwiO1xuXG52YXIgY29tbW9uID0gXCIjZGVmaW5lIFBJIDMuMTQxNTkyNjUzNTg5NzkzXFxuI2RlZmluZSBQSTIgNi4yODMxODUzMDcxNzk1ODZcXG4jZGVmaW5lIFBJX0hBTEYgMS41NzA3OTYzMjY3OTQ4OTY2XFxuI2RlZmluZSBSRUNJUFJPQ0FMX1BJIDAuMzE4MzA5ODg2MTgzNzkwN1xcbiNkZWZpbmUgUkVDSVBST0NBTF9QSTIgMC4xNTkxNTQ5NDMwOTE4OTUzNVxcbiNkZWZpbmUgRVBTSUxPTiAxZS02XFxuI2lmbmRlZiBzYXR1cmF0ZVxcbiNkZWZpbmUgc2F0dXJhdGUoIGEgKSBjbGFtcCggYSwgMC4wLCAxLjAgKVxcbiNlbmRpZlxcbiNkZWZpbmUgd2hpdGVDb21wbGVtZW50KCBhICkgKCAxLjAgLSBzYXR1cmF0ZSggYSApIClcXG5mbG9hdCBwb3cyKCBjb25zdCBpbiBmbG9hdCB4ICkgeyByZXR1cm4geCp4OyB9XFxudmVjMyBwb3cyKCBjb25zdCBpbiB2ZWMzIHggKSB7IHJldHVybiB4Kng7IH1cXG5mbG9hdCBwb3czKCBjb25zdCBpbiBmbG9hdCB4ICkgeyByZXR1cm4geCp4Kng7IH1cXG5mbG9hdCBwb3c0KCBjb25zdCBpbiBmbG9hdCB4ICkgeyBmbG9hdCB4MiA9IHgqeDsgcmV0dXJuIHgyKngyOyB9XFxuZmxvYXQgbWF4MyggY29uc3QgaW4gdmVjMyB2ICkgeyByZXR1cm4gbWF4KCBtYXgoIHYueCwgdi55ICksIHYueiApOyB9XFxuZmxvYXQgYXZlcmFnZSggY29uc3QgaW4gdmVjMyB2ICkgeyByZXR1cm4gZG90KCB2LCB2ZWMzKCAwLjMzMzMzMzMgKSApOyB9XFxuaGlnaHAgZmxvYXQgcmFuZCggY29uc3QgaW4gdmVjMiB1diApIHtcXG5cXHRjb25zdCBoaWdocCBmbG9hdCBhID0gMTIuOTg5OCwgYiA9IDc4LjIzMywgYyA9IDQzNzU4LjU0NTM7XFxuXFx0aGlnaHAgZmxvYXQgZHQgPSBkb3QoIHV2Lnh5LCB2ZWMyKCBhLGIgKSApLCBzbiA9IG1vZCggZHQsIFBJICk7XFxuXFx0cmV0dXJuIGZyYWN0KCBzaW4oIHNuICkgKiBjICk7XFxufVxcbiNpZmRlZiBISUdIX1BSRUNJU0lPTlxcblxcdGZsb2F0IHByZWNpc2lvblNhZmVMZW5ndGgoIHZlYzMgdiApIHsgcmV0dXJuIGxlbmd0aCggdiApOyB9XFxuI2Vsc2VcXG5cXHRmbG9hdCBwcmVjaXNpb25TYWZlTGVuZ3RoKCB2ZWMzIHYgKSB7XFxuXFx0XFx0ZmxvYXQgbWF4Q29tcG9uZW50ID0gbWF4MyggYWJzKCB2ICkgKTtcXG5cXHRcXHRyZXR1cm4gbGVuZ3RoKCB2IC8gbWF4Q29tcG9uZW50ICkgKiBtYXhDb21wb25lbnQ7XFxuXFx0fVxcbiNlbmRpZlxcbnN0cnVjdCBJbmNpZGVudExpZ2h0IHtcXG5cXHR2ZWMzIGNvbG9yO1xcblxcdHZlYzMgZGlyZWN0aW9uO1xcblxcdGJvb2wgdmlzaWJsZTtcXG59O1xcbnN0cnVjdCBSZWZsZWN0ZWRMaWdodCB7XFxuXFx0dmVjMyBkaXJlY3REaWZmdXNlO1xcblxcdHZlYzMgZGlyZWN0U3BlY3VsYXI7XFxuXFx0dmVjMyBpbmRpcmVjdERpZmZ1c2U7XFxuXFx0dmVjMyBpbmRpcmVjdFNwZWN1bGFyO1xcbn07XFxuI2lmZGVmIFVTRV9BTFBIQUhBU0hcXG5cXHR2YXJ5aW5nIHZlYzMgdlBvc2l0aW9uO1xcbiNlbmRpZlxcbnZlYzMgdHJhbnNmb3JtRGlyZWN0aW9uKCBpbiB2ZWMzIGRpciwgaW4gbWF0NCBtYXRyaXggKSB7XFxuXFx0cmV0dXJuIG5vcm1hbGl6ZSggKCBtYXRyaXggKiB2ZWM0KCBkaXIsIDAuMCApICkueHl6ICk7XFxufVxcbnZlYzMgaW52ZXJzZVRyYW5zZm9ybURpcmVjdGlvbiggaW4gdmVjMyBkaXIsIGluIG1hdDQgbWF0cml4ICkge1xcblxcdHJldHVybiBub3JtYWxpemUoICggdmVjNCggZGlyLCAwLjAgKSAqIG1hdHJpeCApLnh5eiApO1xcbn1cXG5tYXQzIHRyYW5zcG9zZU1hdDMoIGNvbnN0IGluIG1hdDMgbSApIHtcXG5cXHRtYXQzIHRtcDtcXG5cXHR0bXBbIDAgXSA9IHZlYzMoIG1bIDAgXS54LCBtWyAxIF0ueCwgbVsgMiBdLnggKTtcXG5cXHR0bXBbIDEgXSA9IHZlYzMoIG1bIDAgXS55LCBtWyAxIF0ueSwgbVsgMiBdLnkgKTtcXG5cXHR0bXBbIDIgXSA9IHZlYzMoIG1bIDAgXS56LCBtWyAxIF0ueiwgbVsgMiBdLnogKTtcXG5cXHRyZXR1cm4gdG1wO1xcbn1cXG5mbG9hdCBsdW1pbmFuY2UoIGNvbnN0IGluIHZlYzMgcmdiICkge1xcblxcdGNvbnN0IHZlYzMgd2VpZ2h0cyA9IHZlYzMoIDAuMjEyNjcyOSwgMC43MTUxNTIyLCAwLjA3MjE3NTAgKTtcXG5cXHRyZXR1cm4gZG90KCB3ZWlnaHRzLCByZ2IgKTtcXG59XFxuYm9vbCBpc1BlcnNwZWN0aXZlTWF0cml4KCBtYXQ0IG0gKSB7XFxuXFx0cmV0dXJuIG1bIDIgXVsgMyBdID09IC0gMS4wO1xcbn1cXG52ZWMyIGVxdWlyZWN0VXYoIGluIHZlYzMgZGlyICkge1xcblxcdGZsb2F0IHUgPSBhdGFuKCBkaXIueiwgZGlyLnggKSAqIFJFQ0lQUk9DQUxfUEkyICsgMC41O1xcblxcdGZsb2F0IHYgPSBhc2luKCBjbGFtcCggZGlyLnksIC0gMS4wLCAxLjAgKSApICogUkVDSVBST0NBTF9QSSArIDAuNTtcXG5cXHRyZXR1cm4gdmVjMiggdSwgdiApO1xcbn1cXG52ZWMzIEJSREZfTGFtYmVydCggY29uc3QgaW4gdmVjMyBkaWZmdXNlQ29sb3IgKSB7XFxuXFx0cmV0dXJuIFJFQ0lQUk9DQUxfUEkgKiBkaWZmdXNlQ29sb3I7XFxufVxcbnZlYzMgRl9TY2hsaWNrKCBjb25zdCBpbiB2ZWMzIGYwLCBjb25zdCBpbiBmbG9hdCBmOTAsIGNvbnN0IGluIGZsb2F0IGRvdFZIICkge1xcblxcdGZsb2F0IGZyZXNuZWwgPSBleHAyKCAoIC0gNS41NTQ3MyAqIGRvdFZIIC0gNi45ODMxNiApICogZG90VkggKTtcXG5cXHRyZXR1cm4gZjAgKiAoIDEuMCAtIGZyZXNuZWwgKSArICggZjkwICogZnJlc25lbCApO1xcbn1cXG5mbG9hdCBGX1NjaGxpY2soIGNvbnN0IGluIGZsb2F0IGYwLCBjb25zdCBpbiBmbG9hdCBmOTAsIGNvbnN0IGluIGZsb2F0IGRvdFZIICkge1xcblxcdGZsb2F0IGZyZXNuZWwgPSBleHAyKCAoIC0gNS41NTQ3MyAqIGRvdFZIIC0gNi45ODMxNiApICogZG90VkggKTtcXG5cXHRyZXR1cm4gZjAgKiAoIDEuMCAtIGZyZXNuZWwgKSArICggZjkwICogZnJlc25lbCApO1xcbn0gLy8gdmFsaWRhdGVkXCI7XG5cbnZhciBjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQgPSBcIiNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFX1VWXFxuXFx0I2RlZmluZSBjdWJlVVZfbWluTWlwTGV2ZWwgNC4wXFxuXFx0I2RlZmluZSBjdWJlVVZfbWluVGlsZVNpemUgMTYuMFxcblxcdGZsb2F0IGdldEZhY2UoIHZlYzMgZGlyZWN0aW9uICkge1xcblxcdFxcdHZlYzMgYWJzRGlyZWN0aW9uID0gYWJzKCBkaXJlY3Rpb24gKTtcXG5cXHRcXHRmbG9hdCBmYWNlID0gLSAxLjA7XFxuXFx0XFx0aWYgKCBhYnNEaXJlY3Rpb24ueCA+IGFic0RpcmVjdGlvbi56ICkge1xcblxcdFxcdFxcdGlmICggYWJzRGlyZWN0aW9uLnggPiBhYnNEaXJlY3Rpb24ueSApXFxuXFx0XFx0XFx0XFx0ZmFjZSA9IGRpcmVjdGlvbi54ID4gMC4wID8gMC4wIDogMy4wO1xcblxcdFxcdFxcdGVsc2VcXG5cXHRcXHRcXHRcXHRmYWNlID0gZGlyZWN0aW9uLnkgPiAwLjAgPyAxLjAgOiA0LjA7XFxuXFx0XFx0fSBlbHNlIHtcXG5cXHRcXHRcXHRpZiAoIGFic0RpcmVjdGlvbi56ID4gYWJzRGlyZWN0aW9uLnkgKVxcblxcdFxcdFxcdFxcdGZhY2UgPSBkaXJlY3Rpb24ueiA+IDAuMCA/IDIuMCA6IDUuMDtcXG5cXHRcXHRcXHRlbHNlXFxuXFx0XFx0XFx0XFx0ZmFjZSA9IGRpcmVjdGlvbi55ID4gMC4wID8gMS4wIDogNC4wO1xcblxcdFxcdH1cXG5cXHRcXHRyZXR1cm4gZmFjZTtcXG5cXHR9XFxuXFx0dmVjMiBnZXRVViggdmVjMyBkaXJlY3Rpb24sIGZsb2F0IGZhY2UgKSB7XFxuXFx0XFx0dmVjMiB1djtcXG5cXHRcXHRpZiAoIGZhY2UgPT0gMC4wICkge1xcblxcdFxcdFxcdHV2ID0gdmVjMiggZGlyZWN0aW9uLnosIGRpcmVjdGlvbi55ICkgLyBhYnMoIGRpcmVjdGlvbi54ICk7XFxuXFx0XFx0fSBlbHNlIGlmICggZmFjZSA9PSAxLjAgKSB7XFxuXFx0XFx0XFx0dXYgPSB2ZWMyKCAtIGRpcmVjdGlvbi54LCAtIGRpcmVjdGlvbi56ICkgLyBhYnMoIGRpcmVjdGlvbi55ICk7XFxuXFx0XFx0fSBlbHNlIGlmICggZmFjZSA9PSAyLjAgKSB7XFxuXFx0XFx0XFx0dXYgPSB2ZWMyKCAtIGRpcmVjdGlvbi54LCBkaXJlY3Rpb24ueSApIC8gYWJzKCBkaXJlY3Rpb24ueiApO1xcblxcdFxcdH0gZWxzZSBpZiAoIGZhY2UgPT0gMy4wICkge1xcblxcdFxcdFxcdHV2ID0gdmVjMiggLSBkaXJlY3Rpb24ueiwgZGlyZWN0aW9uLnkgKSAvIGFicyggZGlyZWN0aW9uLnggKTtcXG5cXHRcXHR9IGVsc2UgaWYgKCBmYWNlID09IDQuMCApIHtcXG5cXHRcXHRcXHR1diA9IHZlYzIoIC0gZGlyZWN0aW9uLngsIGRpcmVjdGlvbi56ICkgLyBhYnMoIGRpcmVjdGlvbi55ICk7XFxuXFx0XFx0fSBlbHNlIHtcXG5cXHRcXHRcXHR1diA9IHZlYzIoIGRpcmVjdGlvbi54LCBkaXJlY3Rpb24ueSApIC8gYWJzKCBkaXJlY3Rpb24ueiApO1xcblxcdFxcdH1cXG5cXHRcXHRyZXR1cm4gMC41ICogKCB1diArIDEuMCApO1xcblxcdH1cXG5cXHR2ZWMzIGJpbGluZWFyQ3ViZVVWKCBzYW1wbGVyMkQgZW52TWFwLCB2ZWMzIGRpcmVjdGlvbiwgZmxvYXQgbWlwSW50ICkge1xcblxcdFxcdGZsb2F0IGZhY2UgPSBnZXRGYWNlKCBkaXJlY3Rpb24gKTtcXG5cXHRcXHRmbG9hdCBmaWx0ZXJJbnQgPSBtYXgoIGN1YmVVVl9taW5NaXBMZXZlbCAtIG1pcEludCwgMC4wICk7XFxuXFx0XFx0bWlwSW50ID0gbWF4KCBtaXBJbnQsIGN1YmVVVl9taW5NaXBMZXZlbCApO1xcblxcdFxcdGZsb2F0IGZhY2VTaXplID0gZXhwMiggbWlwSW50ICk7XFxuXFx0XFx0aGlnaHAgdmVjMiB1diA9IGdldFVWKCBkaXJlY3Rpb24sIGZhY2UgKSAqICggZmFjZVNpemUgLSAyLjAgKSArIDEuMDtcXG5cXHRcXHRpZiAoIGZhY2UgPiAyLjAgKSB7XFxuXFx0XFx0XFx0dXYueSArPSBmYWNlU2l6ZTtcXG5cXHRcXHRcXHRmYWNlIC09IDMuMDtcXG5cXHRcXHR9XFxuXFx0XFx0dXYueCArPSBmYWNlICogZmFjZVNpemU7XFxuXFx0XFx0dXYueCArPSBmaWx0ZXJJbnQgKiAzLjAgKiBjdWJlVVZfbWluVGlsZVNpemU7XFxuXFx0XFx0dXYueSArPSA0LjAgKiAoIGV4cDIoIENVQkVVVl9NQVhfTUlQICkgLSBmYWNlU2l6ZSApO1xcblxcdFxcdHV2LnggKj0gQ1VCRVVWX1RFWEVMX1dJRFRIO1xcblxcdFxcdHV2LnkgKj0gQ1VCRVVWX1RFWEVMX0hFSUdIVDtcXG5cXHRcXHQjaWZkZWYgdGV4dHVyZTJER3JhZEVYVFxcblxcdFxcdFxcdHJldHVybiB0ZXh0dXJlMkRHcmFkRVhUKCBlbnZNYXAsIHV2LCB2ZWMyKCAwLjAgKSwgdmVjMiggMC4wICkgKS5yZ2I7XFxuXFx0XFx0I2Vsc2VcXG5cXHRcXHRcXHRyZXR1cm4gdGV4dHVyZTJEKCBlbnZNYXAsIHV2ICkucmdiO1xcblxcdFxcdCNlbmRpZlxcblxcdH1cXG5cXHQjZGVmaW5lIGN1YmVVVl9yMCAxLjBcXG5cXHQjZGVmaW5lIGN1YmVVVl9tMCAtIDIuMFxcblxcdCNkZWZpbmUgY3ViZVVWX3IxIDAuOFxcblxcdCNkZWZpbmUgY3ViZVVWX20xIC0gMS4wXFxuXFx0I2RlZmluZSBjdWJlVVZfcjQgMC40XFxuXFx0I2RlZmluZSBjdWJlVVZfbTQgMi4wXFxuXFx0I2RlZmluZSBjdWJlVVZfcjUgMC4zMDVcXG5cXHQjZGVmaW5lIGN1YmVVVl9tNSAzLjBcXG5cXHQjZGVmaW5lIGN1YmVVVl9yNiAwLjIxXFxuXFx0I2RlZmluZSBjdWJlVVZfbTYgNC4wXFxuXFx0ZmxvYXQgcm91Z2huZXNzVG9NaXAoIGZsb2F0IHJvdWdobmVzcyApIHtcXG5cXHRcXHRmbG9hdCBtaXAgPSAwLjA7XFxuXFx0XFx0aWYgKCByb3VnaG5lc3MgPj0gY3ViZVVWX3IxICkge1xcblxcdFxcdFxcdG1pcCA9ICggY3ViZVVWX3IwIC0gcm91Z2huZXNzICkgKiAoIGN1YmVVVl9tMSAtIGN1YmVVVl9tMCApIC8gKCBjdWJlVVZfcjAgLSBjdWJlVVZfcjEgKSArIGN1YmVVVl9tMDtcXG5cXHRcXHR9IGVsc2UgaWYgKCByb3VnaG5lc3MgPj0gY3ViZVVWX3I0ICkge1xcblxcdFxcdFxcdG1pcCA9ICggY3ViZVVWX3IxIC0gcm91Z2huZXNzICkgKiAoIGN1YmVVVl9tNCAtIGN1YmVVVl9tMSApIC8gKCBjdWJlVVZfcjEgLSBjdWJlVVZfcjQgKSArIGN1YmVVVl9tMTtcXG5cXHRcXHR9IGVsc2UgaWYgKCByb3VnaG5lc3MgPj0gY3ViZVVWX3I1ICkge1xcblxcdFxcdFxcdG1pcCA9ICggY3ViZVVWX3I0IC0gcm91Z2huZXNzICkgKiAoIGN1YmVVVl9tNSAtIGN1YmVVVl9tNCApIC8gKCBjdWJlVVZfcjQgLSBjdWJlVVZfcjUgKSArIGN1YmVVVl9tNDtcXG5cXHRcXHR9IGVsc2UgaWYgKCByb3VnaG5lc3MgPj0gY3ViZVVWX3I2ICkge1xcblxcdFxcdFxcdG1pcCA9ICggY3ViZVVWX3I1IC0gcm91Z2huZXNzICkgKiAoIGN1YmVVVl9tNiAtIGN1YmVVVl9tNSApIC8gKCBjdWJlVVZfcjUgLSBjdWJlVVZfcjYgKSArIGN1YmVVVl9tNTtcXG5cXHRcXHR9IGVsc2Uge1xcblxcdFxcdFxcdG1pcCA9IC0gMi4wICogbG9nMiggMS4xNiAqIHJvdWdobmVzcyApO1xcdFxcdH1cXG5cXHRcXHRyZXR1cm4gbWlwO1xcblxcdH1cXG5cXHR2ZWM0IHRleHR1cmVDdWJlVVYoIHNhbXBsZXIyRCBlbnZNYXAsIHZlYzMgc2FtcGxlRGlyLCBmbG9hdCByb3VnaG5lc3MgKSB7XFxuXFx0XFx0ZmxvYXQgbWlwID0gY2xhbXAoIHJvdWdobmVzc1RvTWlwKCByb3VnaG5lc3MgKSwgY3ViZVVWX20wLCBDVUJFVVZfTUFYX01JUCApO1xcblxcdFxcdGZsb2F0IG1pcEYgPSBmcmFjdCggbWlwICk7XFxuXFx0XFx0ZmxvYXQgbWlwSW50ID0gZmxvb3IoIG1pcCApO1xcblxcdFxcdHZlYzMgY29sb3IwID0gYmlsaW5lYXJDdWJlVVYoIGVudk1hcCwgc2FtcGxlRGlyLCBtaXBJbnQgKTtcXG5cXHRcXHRpZiAoIG1pcEYgPT0gMC4wICkge1xcblxcdFxcdFxcdHJldHVybiB2ZWM0KCBjb2xvcjAsIDEuMCApO1xcblxcdFxcdH0gZWxzZSB7XFxuXFx0XFx0XFx0dmVjMyBjb2xvcjEgPSBiaWxpbmVhckN1YmVVViggZW52TWFwLCBzYW1wbGVEaXIsIG1pcEludCArIDEuMCApO1xcblxcdFxcdFxcdHJldHVybiB2ZWM0KCBtaXgoIGNvbG9yMCwgY29sb3IxLCBtaXBGICksIDEuMCApO1xcblxcdFxcdH1cXG5cXHR9XFxuI2VuZGlmXCI7XG5cbnZhciBkZWZhdWx0bm9ybWFsX3ZlcnRleCA9IFwidmVjMyB0cmFuc2Zvcm1lZE5vcm1hbCA9IG9iamVjdE5vcm1hbDtcXG4jaWZkZWYgVVNFX1RBTkdFTlRcXG5cXHR2ZWMzIHRyYW5zZm9ybWVkVGFuZ2VudCA9IG9iamVjdFRhbmdlbnQ7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9CQVRDSElOR1xcblxcdG1hdDMgYm0gPSBtYXQzKCBiYXRjaGluZ01hdHJpeCApO1xcblxcdHRyYW5zZm9ybWVkTm9ybWFsIC89IHZlYzMoIGRvdCggYm1bIDAgXSwgYm1bIDAgXSApLCBkb3QoIGJtWyAxIF0sIGJtWyAxIF0gKSwgZG90KCBibVsgMiBdLCBibVsgMiBdICkgKTtcXG5cXHR0cmFuc2Zvcm1lZE5vcm1hbCA9IGJtICogdHJhbnNmb3JtZWROb3JtYWw7XFxuXFx0I2lmZGVmIFVTRV9UQU5HRU5UXFxuXFx0XFx0dHJhbnNmb3JtZWRUYW5nZW50ID0gYm0gKiB0cmFuc2Zvcm1lZFRhbmdlbnQ7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9JTlNUQU5DSU5HXFxuXFx0bWF0MyBpbSA9IG1hdDMoIGluc3RhbmNlTWF0cml4ICk7XFxuXFx0dHJhbnNmb3JtZWROb3JtYWwgLz0gdmVjMyggZG90KCBpbVsgMCBdLCBpbVsgMCBdICksIGRvdCggaW1bIDEgXSwgaW1bIDEgXSApLCBkb3QoIGltWyAyIF0sIGltWyAyIF0gKSApO1xcblxcdHRyYW5zZm9ybWVkTm9ybWFsID0gaW0gKiB0cmFuc2Zvcm1lZE5vcm1hbDtcXG5cXHQjaWZkZWYgVVNFX1RBTkdFTlRcXG5cXHRcXHR0cmFuc2Zvcm1lZFRhbmdlbnQgPSBpbSAqIHRyYW5zZm9ybWVkVGFuZ2VudDtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcXG50cmFuc2Zvcm1lZE5vcm1hbCA9IG5vcm1hbE1hdHJpeCAqIHRyYW5zZm9ybWVkTm9ybWFsO1xcbiNpZmRlZiBGTElQX1NJREVEXFxuXFx0dHJhbnNmb3JtZWROb3JtYWwgPSAtIHRyYW5zZm9ybWVkTm9ybWFsO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfVEFOR0VOVFxcblxcdHRyYW5zZm9ybWVkVGFuZ2VudCA9ICggbW9kZWxWaWV3TWF0cml4ICogdmVjNCggdHJhbnNmb3JtZWRUYW5nZW50LCAwLjAgKSApLnh5ejtcXG5cXHQjaWZkZWYgRkxJUF9TSURFRFxcblxcdFxcdHRyYW5zZm9ybWVkVGFuZ2VudCA9IC0gdHJhbnNmb3JtZWRUYW5nZW50O1xcblxcdCNlbmRpZlxcbiNlbmRpZlwiO1xuXG52YXIgZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4ID0gXCIjaWZkZWYgVVNFX0RJU1BMQUNFTUVOVE1BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGRpc3BsYWNlbWVudE1hcDtcXG5cXHR1bmlmb3JtIGZsb2F0IGRpc3BsYWNlbWVudFNjYWxlO1xcblxcdHVuaWZvcm0gZmxvYXQgZGlzcGxhY2VtZW50QmlhcztcXG4jZW5kaWZcIjtcblxudmFyIGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXggPSBcIiNpZmRlZiBVU0VfRElTUExBQ0VNRU5UTUFQXFxuXFx0dHJhbnNmb3JtZWQgKz0gbm9ybWFsaXplKCBvYmplY3ROb3JtYWwgKSAqICggdGV4dHVyZTJEKCBkaXNwbGFjZW1lbnRNYXAsIHZEaXNwbGFjZW1lbnRNYXBVdiApLnggKiBkaXNwbGFjZW1lbnRTY2FsZSArIGRpc3BsYWNlbWVudEJpYXMgKTtcXG4jZW5kaWZcIjtcblxudmFyIGVtaXNzaXZlbWFwX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0VNSVNTSVZFTUFQXFxuXFx0dmVjNCBlbWlzc2l2ZUNvbG9yID0gdGV4dHVyZTJEKCBlbWlzc2l2ZU1hcCwgdkVtaXNzaXZlTWFwVXYgKTtcXG5cXHR0b3RhbEVtaXNzaXZlUmFkaWFuY2UgKj0gZW1pc3NpdmVDb2xvci5yZ2I7XFxuI2VuZGlmXCI7XG5cbnZhciBlbWlzc2l2ZW1hcF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0VNSVNTSVZFTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgZW1pc3NpdmVNYXA7XFxuI2VuZGlmXCI7XG5cbnZhciBjb2xvcnNwYWNlX2ZyYWdtZW50ID0gXCJnbF9GcmFnQ29sb3IgPSBsaW5lYXJUb091dHB1dFRleGVsKCBnbF9GcmFnQ29sb3IgKTtcIjtcblxudmFyIGNvbG9yc3BhY2VfcGFyc19mcmFnbWVudCA9IFwiXFxuY29uc3QgbWF0MyBMSU5FQVJfU1JHQl9UT19MSU5FQVJfRElTUExBWV9QMyA9IG1hdDMoXFxuXFx0dmVjMyggMC44MjI0NjIxLCAwLjE3NzUzOCwgMC4wICksXFxuXFx0dmVjMyggMC4wMzMxOTQxLCAwLjk2NjgwNTgsIDAuMCApLFxcblxcdHZlYzMoIDAuMDE3MDgyNywgMC4wNzIzOTc0LCAwLjkxMDUxOTkgKVxcbik7XFxuY29uc3QgbWF0MyBMSU5FQVJfRElTUExBWV9QM19UT19MSU5FQVJfU1JHQiA9IG1hdDMoXFxuXFx0dmVjMyggMS4yMjQ5NDAxLCAtIDAuMjI0OTQwNCwgMC4wICksXFxuXFx0dmVjMyggLSAwLjA0MjA1NjksIDEuMDQyMDU3MSwgMC4wICksXFxuXFx0dmVjMyggLSAwLjAxOTYzNzYsIC0gMC4wNzg2MzYxLCAxLjA5ODI3MzUgKVxcbik7XFxudmVjNCBMaW5lYXJTUkdCVG9MaW5lYXJEaXNwbGF5UDMoIGluIHZlYzQgdmFsdWUgKSB7XFxuXFx0cmV0dXJuIHZlYzQoIHZhbHVlLnJnYiAqIExJTkVBUl9TUkdCX1RPX0xJTkVBUl9ESVNQTEFZX1AzLCB2YWx1ZS5hICk7XFxufVxcbnZlYzQgTGluZWFyRGlzcGxheVAzVG9MaW5lYXJTUkdCKCBpbiB2ZWM0IHZhbHVlICkge1xcblxcdHJldHVybiB2ZWM0KCB2YWx1ZS5yZ2IgKiBMSU5FQVJfRElTUExBWV9QM19UT19MSU5FQVJfU1JHQiwgdmFsdWUuYSApO1xcbn1cXG52ZWM0IExpbmVhclRyYW5zZmVyT0VURiggaW4gdmVjNCB2YWx1ZSApIHtcXG5cXHRyZXR1cm4gdmFsdWU7XFxufVxcbnZlYzQgc1JHQlRyYW5zZmVyT0VURiggaW4gdmVjNCB2YWx1ZSApIHtcXG5cXHRyZXR1cm4gdmVjNCggbWl4KCBwb3coIHZhbHVlLnJnYiwgdmVjMyggMC40MTY2NiApICkgKiAxLjA1NSAtIHZlYzMoIDAuMDU1ICksIHZhbHVlLnJnYiAqIDEyLjkyLCB2ZWMzKCBsZXNzVGhhbkVxdWFsKCB2YWx1ZS5yZ2IsIHZlYzMoIDAuMDAzMTMwOCApICkgKSApLCB2YWx1ZS5hICk7XFxufVxcbnZlYzQgTGluZWFyVG9MaW5lYXIoIGluIHZlYzQgdmFsdWUgKSB7XFxuXFx0cmV0dXJuIHZhbHVlO1xcbn1cXG52ZWM0IExpbmVhclRvc1JHQiggaW4gdmVjNCB2YWx1ZSApIHtcXG5cXHRyZXR1cm4gc1JHQlRyYW5zZmVyT0VURiggdmFsdWUgKTtcXG59XCI7XG5cbnZhciBlbnZtYXBfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfRU5WTUFQXFxuXFx0I2lmZGVmIEVOVl9XT1JMRFBPU1xcblxcdFxcdHZlYzMgY2FtZXJhVG9GcmFnO1xcblxcdFxcdGlmICggaXNPcnRob2dyYXBoaWMgKSB7XFxuXFx0XFx0XFx0Y2FtZXJhVG9GcmFnID0gbm9ybWFsaXplKCB2ZWMzKCAtIHZpZXdNYXRyaXhbIDAgXVsgMiBdLCAtIHZpZXdNYXRyaXhbIDEgXVsgMiBdLCAtIHZpZXdNYXRyaXhbIDIgXVsgMiBdICkgKTtcXG5cXHRcXHR9IGVsc2Uge1xcblxcdFxcdFxcdGNhbWVyYVRvRnJhZyA9IG5vcm1hbGl6ZSggdldvcmxkUG9zaXRpb24gLSBjYW1lcmFQb3NpdGlvbiApO1xcblxcdFxcdH1cXG5cXHRcXHR2ZWMzIHdvcmxkTm9ybWFsID0gaW52ZXJzZVRyYW5zZm9ybURpcmVjdGlvbiggbm9ybWFsLCB2aWV3TWF0cml4ICk7XFxuXFx0XFx0I2lmZGVmIEVOVk1BUF9NT0RFX1JFRkxFQ1RJT05cXG5cXHRcXHRcXHR2ZWMzIHJlZmxlY3RWZWMgPSByZWZsZWN0KCBjYW1lcmFUb0ZyYWcsIHdvcmxkTm9ybWFsICk7XFxuXFx0XFx0I2Vsc2VcXG5cXHRcXHRcXHR2ZWMzIHJlZmxlY3RWZWMgPSByZWZyYWN0KCBjYW1lcmFUb0ZyYWcsIHdvcmxkTm9ybWFsLCByZWZyYWN0aW9uUmF0aW8gKTtcXG5cXHRcXHQjZW5kaWZcXG5cXHQjZWxzZVxcblxcdFxcdHZlYzMgcmVmbGVjdFZlYyA9IHZSZWZsZWN0O1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFXFxuXFx0XFx0dmVjNCBlbnZDb2xvciA9IHRleHR1cmVDdWJlKCBlbnZNYXAsIGVudk1hcFJvdGF0aW9uICogdmVjMyggZmxpcEVudk1hcCAqIHJlZmxlY3RWZWMueCwgcmVmbGVjdFZlYy55eiApICk7XFxuXFx0I2Vsc2VcXG5cXHRcXHR2ZWM0IGVudkNvbG9yID0gdmVjNCggMC4wICk7XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIEVOVk1BUF9CTEVORElOR19NVUxUSVBMWVxcblxcdFxcdG91dGdvaW5nTGlnaHQgPSBtaXgoIG91dGdvaW5nTGlnaHQsIG91dGdvaW5nTGlnaHQgKiBlbnZDb2xvci54eXosIHNwZWN1bGFyU3RyZW5ndGggKiByZWZsZWN0aXZpdHkgKTtcXG5cXHQjZWxpZiBkZWZpbmVkKCBFTlZNQVBfQkxFTkRJTkdfTUlYIClcXG5cXHRcXHRvdXRnb2luZ0xpZ2h0ID0gbWl4KCBvdXRnb2luZ0xpZ2h0LCBlbnZDb2xvci54eXosIHNwZWN1bGFyU3RyZW5ndGggKiByZWZsZWN0aXZpdHkgKTtcXG5cXHQjZWxpZiBkZWZpbmVkKCBFTlZNQVBfQkxFTkRJTkdfQUREIClcXG5cXHRcXHRvdXRnb2luZ0xpZ2h0ICs9IGVudkNvbG9yLnh5eiAqIHNwZWN1bGFyU3RyZW5ndGggKiByZWZsZWN0aXZpdHk7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXCI7XG5cbnZhciBlbnZtYXBfY29tbW9uX3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfRU5WTUFQXFxuXFx0dW5pZm9ybSBmbG9hdCBlbnZNYXBJbnRlbnNpdHk7XFxuXFx0dW5pZm9ybSBmbG9hdCBmbGlwRW52TWFwO1xcblxcdHVuaWZvcm0gbWF0MyBlbnZNYXBSb3RhdGlvbjtcXG5cXHQjaWZkZWYgRU5WTUFQX1RZUEVfQ1VCRVxcblxcdFxcdHVuaWZvcm0gc2FtcGxlckN1YmUgZW52TWFwO1xcblxcdCNlbHNlXFxuXFx0XFx0dW5pZm9ybSBzYW1wbGVyMkQgZW52TWFwO1xcblxcdCNlbmRpZlxcblxcdFxcbiNlbmRpZlwiO1xuXG52YXIgZW52bWFwX3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfRU5WTUFQXFxuXFx0dW5pZm9ybSBmbG9hdCByZWZsZWN0aXZpdHk7XFxuXFx0I2lmIGRlZmluZWQoIFVTRV9CVU1QTUFQICkgfHwgZGVmaW5lZCggVVNFX05PUk1BTE1BUCApIHx8IGRlZmluZWQoIFBIT05HICkgfHwgZGVmaW5lZCggTEFNQkVSVCApXFxuXFx0XFx0I2RlZmluZSBFTlZfV09STERQT1NcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgRU5WX1dPUkxEUE9TXFxuXFx0XFx0dmFyeWluZyB2ZWMzIHZXb3JsZFBvc2l0aW9uO1xcblxcdFxcdHVuaWZvcm0gZmxvYXQgcmVmcmFjdGlvblJhdGlvO1xcblxcdCNlbHNlXFxuXFx0XFx0dmFyeWluZyB2ZWMzIHZSZWZsZWN0O1xcblxcdCNlbmRpZlxcbiNlbmRpZlwiO1xuXG52YXIgZW52bWFwX3BhcnNfdmVydGV4ID0gXCIjaWZkZWYgVVNFX0VOVk1BUFxcblxcdCNpZiBkZWZpbmVkKCBVU0VfQlVNUE1BUCApIHx8IGRlZmluZWQoIFVTRV9OT1JNQUxNQVAgKSB8fCBkZWZpbmVkKCBQSE9ORyApIHx8IGRlZmluZWQoIExBTUJFUlQgKVxcblxcdFxcdCNkZWZpbmUgRU5WX1dPUkxEUE9TXFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIEVOVl9XT1JMRFBPU1xcblxcdFxcdFxcblxcdFxcdHZhcnlpbmcgdmVjMyB2V29ybGRQb3NpdGlvbjtcXG5cXHQjZWxzZVxcblxcdFxcdHZhcnlpbmcgdmVjMyB2UmVmbGVjdDtcXG5cXHRcXHR1bmlmb3JtIGZsb2F0IHJlZnJhY3Rpb25SYXRpbztcXG5cXHQjZW5kaWZcXG4jZW5kaWZcIjtcblxudmFyIGVudm1hcF92ZXJ0ZXggPSBcIiNpZmRlZiBVU0VfRU5WTUFQXFxuXFx0I2lmZGVmIEVOVl9XT1JMRFBPU1xcblxcdFxcdHZXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbi54eXo7XFxuXFx0I2Vsc2VcXG5cXHRcXHR2ZWMzIGNhbWVyYVRvVmVydGV4O1xcblxcdFxcdGlmICggaXNPcnRob2dyYXBoaWMgKSB7XFxuXFx0XFx0XFx0Y2FtZXJhVG9WZXJ0ZXggPSBub3JtYWxpemUoIHZlYzMoIC0gdmlld01hdHJpeFsgMCBdWyAyIF0sIC0gdmlld01hdHJpeFsgMSBdWyAyIF0sIC0gdmlld01hdHJpeFsgMiBdWyAyIF0gKSApO1xcblxcdFxcdH0gZWxzZSB7XFxuXFx0XFx0XFx0Y2FtZXJhVG9WZXJ0ZXggPSBub3JtYWxpemUoIHdvcmxkUG9zaXRpb24ueHl6IC0gY2FtZXJhUG9zaXRpb24gKTtcXG5cXHRcXHR9XFxuXFx0XFx0dmVjMyB3b3JsZE5vcm1hbCA9IGludmVyc2VUcmFuc2Zvcm1EaXJlY3Rpb24oIHRyYW5zZm9ybWVkTm9ybWFsLCB2aWV3TWF0cml4ICk7XFxuXFx0XFx0I2lmZGVmIEVOVk1BUF9NT0RFX1JFRkxFQ1RJT05cXG5cXHRcXHRcXHR2UmVmbGVjdCA9IHJlZmxlY3QoIGNhbWVyYVRvVmVydGV4LCB3b3JsZE5vcm1hbCApO1xcblxcdFxcdCNlbHNlXFxuXFx0XFx0XFx0dlJlZmxlY3QgPSByZWZyYWN0KCBjYW1lcmFUb1ZlcnRleCwgd29ybGROb3JtYWwsIHJlZnJhY3Rpb25SYXRpbyApO1xcblxcdFxcdCNlbmRpZlxcblxcdCNlbmRpZlxcbiNlbmRpZlwiO1xuXG52YXIgZm9nX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9GT0dcXG5cXHR2Rm9nRGVwdGggPSAtIG12UG9zaXRpb24uejtcXG4jZW5kaWZcIjtcblxudmFyIGZvZ19wYXJzX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9GT0dcXG5cXHR2YXJ5aW5nIGZsb2F0IHZGb2dEZXB0aDtcXG4jZW5kaWZcIjtcblxudmFyIGZvZ19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9GT0dcXG5cXHQjaWZkZWYgRk9HX0VYUDJcXG5cXHRcXHRmbG9hdCBmb2dGYWN0b3IgPSAxLjAgLSBleHAoIC0gZm9nRGVuc2l0eSAqIGZvZ0RlbnNpdHkgKiB2Rm9nRGVwdGggKiB2Rm9nRGVwdGggKTtcXG5cXHQjZWxzZVxcblxcdFxcdGZsb2F0IGZvZ0ZhY3RvciA9IHNtb290aHN0ZXAoIGZvZ05lYXIsIGZvZ0ZhciwgdkZvZ0RlcHRoICk7XFxuXFx0I2VuZGlmXFxuXFx0Z2xfRnJhZ0NvbG9yLnJnYiA9IG1peCggZ2xfRnJhZ0NvbG9yLnJnYiwgZm9nQ29sb3IsIGZvZ0ZhY3RvciApO1xcbiNlbmRpZlwiO1xuXG52YXIgZm9nX3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfRk9HXFxuXFx0dW5pZm9ybSB2ZWMzIGZvZ0NvbG9yO1xcblxcdHZhcnlpbmcgZmxvYXQgdkZvZ0RlcHRoO1xcblxcdCNpZmRlZiBGT0dfRVhQMlxcblxcdFxcdHVuaWZvcm0gZmxvYXQgZm9nRGVuc2l0eTtcXG5cXHQjZWxzZVxcblxcdFxcdHVuaWZvcm0gZmxvYXQgZm9nTmVhcjtcXG5cXHRcXHR1bmlmb3JtIGZsb2F0IGZvZ0ZhcjtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcIjtcblxudmFyIGdyYWRpZW50bWFwX3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfR1JBRElFTlRNQVBcXG5cXHR1bmlmb3JtIHNhbXBsZXIyRCBncmFkaWVudE1hcDtcXG4jZW5kaWZcXG52ZWMzIGdldEdyYWRpZW50SXJyYWRpYW5jZSggdmVjMyBub3JtYWwsIHZlYzMgbGlnaHREaXJlY3Rpb24gKSB7XFxuXFx0ZmxvYXQgZG90TkwgPSBkb3QoIG5vcm1hbCwgbGlnaHREaXJlY3Rpb24gKTtcXG5cXHR2ZWMyIGNvb3JkID0gdmVjMiggZG90TkwgKiAwLjUgKyAwLjUsIDAuMCApO1xcblxcdCNpZmRlZiBVU0VfR1JBRElFTlRNQVBcXG5cXHRcXHRyZXR1cm4gdmVjMyggdGV4dHVyZTJEKCBncmFkaWVudE1hcCwgY29vcmQgKS5yICk7XFxuXFx0I2Vsc2VcXG5cXHRcXHR2ZWMyIGZ3ID0gZndpZHRoKCBjb29yZCApICogMC41O1xcblxcdFxcdHJldHVybiBtaXgoIHZlYzMoIDAuNyApLCB2ZWMzKCAxLjAgKSwgc21vb3Roc3RlcCggMC43IC0gZncueCwgMC43ICsgZncueCwgY29vcmQueCApICk7XFxuXFx0I2VuZGlmXFxufVwiO1xuXG52YXIgbGlnaHRtYXBfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9MSUdIVE1BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGxpZ2h0TWFwO1xcblxcdHVuaWZvcm0gZmxvYXQgbGlnaHRNYXBJbnRlbnNpdHk7XFxuI2VuZGlmXCI7XG5cbnZhciBsaWdodHNfbGFtYmVydF9mcmFnbWVudCA9IFwiTGFtYmVydE1hdGVyaWFsIG1hdGVyaWFsO1xcbm1hdGVyaWFsLmRpZmZ1c2VDb2xvciA9IGRpZmZ1c2VDb2xvci5yZ2I7XFxubWF0ZXJpYWwuc3BlY3VsYXJTdHJlbmd0aCA9IHNwZWN1bGFyU3RyZW5ndGg7XCI7XG5cbnZhciBsaWdodHNfbGFtYmVydF9wYXJzX2ZyYWdtZW50ID0gXCJ2YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcXG5zdHJ1Y3QgTGFtYmVydE1hdGVyaWFsIHtcXG5cXHR2ZWMzIGRpZmZ1c2VDb2xvcjtcXG5cXHRmbG9hdCBzcGVjdWxhclN0cmVuZ3RoO1xcbn07XFxudm9pZCBSRV9EaXJlY3RfTGFtYmVydCggY29uc3QgaW4gSW5jaWRlbnRMaWdodCBkaXJlY3RMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gTGFtYmVydE1hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcXG5cXHRmbG9hdCBkb3ROTCA9IHNhdHVyYXRlKCBkb3QoIGdlb21ldHJ5Tm9ybWFsLCBkaXJlY3RMaWdodC5kaXJlY3Rpb24gKSApO1xcblxcdHZlYzMgaXJyYWRpYW5jZSA9IGRvdE5MICogZGlyZWN0TGlnaHQuY29sb3I7XFxuXFx0cmVmbGVjdGVkTGlnaHQuZGlyZWN0RGlmZnVzZSArPSBpcnJhZGlhbmNlICogQlJERl9MYW1iZXJ0KCBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKTtcXG59XFxudm9pZCBSRV9JbmRpcmVjdERpZmZ1c2VfTGFtYmVydCggY29uc3QgaW4gdmVjMyBpcnJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBMYW1iZXJ0TWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xcblxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSArPSBpcnJhZGlhbmNlICogQlJERl9MYW1iZXJ0KCBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKTtcXG59XFxuI2RlZmluZSBSRV9EaXJlY3RcXHRcXHRcXHRcXHRSRV9EaXJlY3RfTGFtYmVydFxcbiNkZWZpbmUgUkVfSW5kaXJlY3REaWZmdXNlXFx0XFx0UkVfSW5kaXJlY3REaWZmdXNlX0xhbWJlcnRcIjtcblxudmFyIGxpZ2h0c19wYXJzX2JlZ2luID0gXCJ1bmlmb3JtIGJvb2wgcmVjZWl2ZVNoYWRvdztcXG51bmlmb3JtIHZlYzMgYW1iaWVudExpZ2h0Q29sb3I7XFxuI2lmIGRlZmluZWQoIFVTRV9MSUdIVF9QUk9CRVMgKVxcblxcdHVuaWZvcm0gdmVjMyBsaWdodFByb2JlWyA5IF07XFxuI2VuZGlmXFxudmVjMyBzaEdldElycmFkaWFuY2VBdCggaW4gdmVjMyBub3JtYWwsIGluIHZlYzMgc2hDb2VmZmljaWVudHNbIDkgXSApIHtcXG5cXHRmbG9hdCB4ID0gbm9ybWFsLngsIHkgPSBub3JtYWwueSwgeiA9IG5vcm1hbC56O1xcblxcdHZlYzMgcmVzdWx0ID0gc2hDb2VmZmljaWVudHNbIDAgXSAqIDAuODg2MjI3O1xcblxcdHJlc3VsdCArPSBzaENvZWZmaWNpZW50c1sgMSBdICogMi4wICogMC41MTE2NjQgKiB5O1xcblxcdHJlc3VsdCArPSBzaENvZWZmaWNpZW50c1sgMiBdICogMi4wICogMC41MTE2NjQgKiB6O1xcblxcdHJlc3VsdCArPSBzaENvZWZmaWNpZW50c1sgMyBdICogMi4wICogMC41MTE2NjQgKiB4O1xcblxcdHJlc3VsdCArPSBzaENvZWZmaWNpZW50c1sgNCBdICogMi4wICogMC40MjkwNDMgKiB4ICogeTtcXG5cXHRyZXN1bHQgKz0gc2hDb2VmZmljaWVudHNbIDUgXSAqIDIuMCAqIDAuNDI5MDQzICogeSAqIHo7XFxuXFx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyA2IF0gKiAoIDAuNzQzMTI1ICogeiAqIHogLSAwLjI0NzcwOCApO1xcblxcdHJlc3VsdCArPSBzaENvZWZmaWNpZW50c1sgNyBdICogMi4wICogMC40MjkwNDMgKiB4ICogejtcXG5cXHRyZXN1bHQgKz0gc2hDb2VmZmljaWVudHNbIDggXSAqIDAuNDI5MDQzICogKCB4ICogeCAtIHkgKiB5ICk7XFxuXFx0cmV0dXJuIHJlc3VsdDtcXG59XFxudmVjMyBnZXRMaWdodFByb2JlSXJyYWRpYW5jZSggY29uc3QgaW4gdmVjMyBsaWdodFByb2JlWyA5IF0sIGNvbnN0IGluIHZlYzMgbm9ybWFsICkge1xcblxcdHZlYzMgd29ybGROb3JtYWwgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCBub3JtYWwsIHZpZXdNYXRyaXggKTtcXG5cXHR2ZWMzIGlycmFkaWFuY2UgPSBzaEdldElycmFkaWFuY2VBdCggd29ybGROb3JtYWwsIGxpZ2h0UHJvYmUgKTtcXG5cXHRyZXR1cm4gaXJyYWRpYW5jZTtcXG59XFxudmVjMyBnZXRBbWJpZW50TGlnaHRJcnJhZGlhbmNlKCBjb25zdCBpbiB2ZWMzIGFtYmllbnRMaWdodENvbG9yICkge1xcblxcdHZlYzMgaXJyYWRpYW5jZSA9IGFtYmllbnRMaWdodENvbG9yO1xcblxcdHJldHVybiBpcnJhZGlhbmNlO1xcbn1cXG5mbG9hdCBnZXREaXN0YW5jZUF0dGVudWF0aW9uKCBjb25zdCBpbiBmbG9hdCBsaWdodERpc3RhbmNlLCBjb25zdCBpbiBmbG9hdCBjdXRvZmZEaXN0YW5jZSwgY29uc3QgaW4gZmxvYXQgZGVjYXlFeHBvbmVudCApIHtcXG5cXHRmbG9hdCBkaXN0YW5jZUZhbGxvZmYgPSAxLjAgLyBtYXgoIHBvdyggbGlnaHREaXN0YW5jZSwgZGVjYXlFeHBvbmVudCApLCAwLjAxICk7XFxuXFx0aWYgKCBjdXRvZmZEaXN0YW5jZSA+IDAuMCApIHtcXG5cXHRcXHRkaXN0YW5jZUZhbGxvZmYgKj0gcG93Miggc2F0dXJhdGUoIDEuMCAtIHBvdzQoIGxpZ2h0RGlzdGFuY2UgLyBjdXRvZmZEaXN0YW5jZSApICkgKTtcXG5cXHR9XFxuXFx0cmV0dXJuIGRpc3RhbmNlRmFsbG9mZjtcXG59XFxuZmxvYXQgZ2V0U3BvdEF0dGVudWF0aW9uKCBjb25zdCBpbiBmbG9hdCBjb25lQ29zaW5lLCBjb25zdCBpbiBmbG9hdCBwZW51bWJyYUNvc2luZSwgY29uc3QgaW4gZmxvYXQgYW5nbGVDb3NpbmUgKSB7XFxuXFx0cmV0dXJuIHNtb290aHN0ZXAoIGNvbmVDb3NpbmUsIHBlbnVtYnJhQ29zaW5lLCBhbmdsZUNvc2luZSApO1xcbn1cXG4jaWYgTlVNX0RJUl9MSUdIVFMgPiAwXFxuXFx0c3RydWN0IERpcmVjdGlvbmFsTGlnaHQge1xcblxcdFxcdHZlYzMgZGlyZWN0aW9uO1xcblxcdFxcdHZlYzMgY29sb3I7XFxuXFx0fTtcXG5cXHR1bmlmb3JtIERpcmVjdGlvbmFsTGlnaHQgZGlyZWN0aW9uYWxMaWdodHNbIE5VTV9ESVJfTElHSFRTIF07XFxuXFx0dm9pZCBnZXREaXJlY3Rpb25hbExpZ2h0SW5mbyggY29uc3QgaW4gRGlyZWN0aW9uYWxMaWdodCBkaXJlY3Rpb25hbExpZ2h0LCBvdXQgSW5jaWRlbnRMaWdodCBsaWdodCApIHtcXG5cXHRcXHRsaWdodC5jb2xvciA9IGRpcmVjdGlvbmFsTGlnaHQuY29sb3I7XFxuXFx0XFx0bGlnaHQuZGlyZWN0aW9uID0gZGlyZWN0aW9uYWxMaWdodC5kaXJlY3Rpb247XFxuXFx0XFx0bGlnaHQudmlzaWJsZSA9IHRydWU7XFxuXFx0fVxcbiNlbmRpZlxcbiNpZiBOVU1fUE9JTlRfTElHSFRTID4gMFxcblxcdHN0cnVjdCBQb2ludExpZ2h0IHtcXG5cXHRcXHR2ZWMzIHBvc2l0aW9uO1xcblxcdFxcdHZlYzMgY29sb3I7XFxuXFx0XFx0ZmxvYXQgZGlzdGFuY2U7XFxuXFx0XFx0ZmxvYXQgZGVjYXk7XFxuXFx0fTtcXG5cXHR1bmlmb3JtIFBvaW50TGlnaHQgcG9pbnRMaWdodHNbIE5VTV9QT0lOVF9MSUdIVFMgXTtcXG5cXHR2b2lkIGdldFBvaW50TGlnaHRJbmZvKCBjb25zdCBpbiBQb2ludExpZ2h0IHBvaW50TGlnaHQsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgb3V0IEluY2lkZW50TGlnaHQgbGlnaHQgKSB7XFxuXFx0XFx0dmVjMyBsVmVjdG9yID0gcG9pbnRMaWdodC5wb3NpdGlvbiAtIGdlb21ldHJ5UG9zaXRpb247XFxuXFx0XFx0bGlnaHQuZGlyZWN0aW9uID0gbm9ybWFsaXplKCBsVmVjdG9yICk7XFxuXFx0XFx0ZmxvYXQgbGlnaHREaXN0YW5jZSA9IGxlbmd0aCggbFZlY3RvciApO1xcblxcdFxcdGxpZ2h0LmNvbG9yID0gcG9pbnRMaWdodC5jb2xvcjtcXG5cXHRcXHRsaWdodC5jb2xvciAqPSBnZXREaXN0YW5jZUF0dGVudWF0aW9uKCBsaWdodERpc3RhbmNlLCBwb2ludExpZ2h0LmRpc3RhbmNlLCBwb2ludExpZ2h0LmRlY2F5ICk7XFxuXFx0XFx0bGlnaHQudmlzaWJsZSA9ICggbGlnaHQuY29sb3IgIT0gdmVjMyggMC4wICkgKTtcXG5cXHR9XFxuI2VuZGlmXFxuI2lmIE5VTV9TUE9UX0xJR0hUUyA+IDBcXG5cXHRzdHJ1Y3QgU3BvdExpZ2h0IHtcXG5cXHRcXHR2ZWMzIHBvc2l0aW9uO1xcblxcdFxcdHZlYzMgZGlyZWN0aW9uO1xcblxcdFxcdHZlYzMgY29sb3I7XFxuXFx0XFx0ZmxvYXQgZGlzdGFuY2U7XFxuXFx0XFx0ZmxvYXQgZGVjYXk7XFxuXFx0XFx0ZmxvYXQgY29uZUNvcztcXG5cXHRcXHRmbG9hdCBwZW51bWJyYUNvcztcXG5cXHR9O1xcblxcdHVuaWZvcm0gU3BvdExpZ2h0IHNwb3RMaWdodHNbIE5VTV9TUE9UX0xJR0hUUyBdO1xcblxcdHZvaWQgZ2V0U3BvdExpZ2h0SW5mbyggY29uc3QgaW4gU3BvdExpZ2h0IHNwb3RMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBvdXQgSW5jaWRlbnRMaWdodCBsaWdodCApIHtcXG5cXHRcXHR2ZWMzIGxWZWN0b3IgPSBzcG90TGlnaHQucG9zaXRpb24gLSBnZW9tZXRyeVBvc2l0aW9uO1xcblxcdFxcdGxpZ2h0LmRpcmVjdGlvbiA9IG5vcm1hbGl6ZSggbFZlY3RvciApO1xcblxcdFxcdGZsb2F0IGFuZ2xlQ29zID0gZG90KCBsaWdodC5kaXJlY3Rpb24sIHNwb3RMaWdodC5kaXJlY3Rpb24gKTtcXG5cXHRcXHRmbG9hdCBzcG90QXR0ZW51YXRpb24gPSBnZXRTcG90QXR0ZW51YXRpb24oIHNwb3RMaWdodC5jb25lQ29zLCBzcG90TGlnaHQucGVudW1icmFDb3MsIGFuZ2xlQ29zICk7XFxuXFx0XFx0aWYgKCBzcG90QXR0ZW51YXRpb24gPiAwLjAgKSB7XFxuXFx0XFx0XFx0ZmxvYXQgbGlnaHREaXN0YW5jZSA9IGxlbmd0aCggbFZlY3RvciApO1xcblxcdFxcdFxcdGxpZ2h0LmNvbG9yID0gc3BvdExpZ2h0LmNvbG9yICogc3BvdEF0dGVudWF0aW9uO1xcblxcdFxcdFxcdGxpZ2h0LmNvbG9yICo9IGdldERpc3RhbmNlQXR0ZW51YXRpb24oIGxpZ2h0RGlzdGFuY2UsIHNwb3RMaWdodC5kaXN0YW5jZSwgc3BvdExpZ2h0LmRlY2F5ICk7XFxuXFx0XFx0XFx0bGlnaHQudmlzaWJsZSA9ICggbGlnaHQuY29sb3IgIT0gdmVjMyggMC4wICkgKTtcXG5cXHRcXHR9IGVsc2Uge1xcblxcdFxcdFxcdGxpZ2h0LmNvbG9yID0gdmVjMyggMC4wICk7XFxuXFx0XFx0XFx0bGlnaHQudmlzaWJsZSA9IGZhbHNlO1xcblxcdFxcdH1cXG5cXHR9XFxuI2VuZGlmXFxuI2lmIE5VTV9SRUNUX0FSRUFfTElHSFRTID4gMFxcblxcdHN0cnVjdCBSZWN0QXJlYUxpZ2h0IHtcXG5cXHRcXHR2ZWMzIGNvbG9yO1xcblxcdFxcdHZlYzMgcG9zaXRpb247XFxuXFx0XFx0dmVjMyBoYWxmV2lkdGg7XFxuXFx0XFx0dmVjMyBoYWxmSGVpZ2h0O1xcblxcdH07XFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgbHRjXzE7XFx0dW5pZm9ybSBzYW1wbGVyMkQgbHRjXzI7XFxuXFx0dW5pZm9ybSBSZWN0QXJlYUxpZ2h0IHJlY3RBcmVhTGlnaHRzWyBOVU1fUkVDVF9BUkVBX0xJR0hUUyBdO1xcbiNlbmRpZlxcbiNpZiBOVU1fSEVNSV9MSUdIVFMgPiAwXFxuXFx0c3RydWN0IEhlbWlzcGhlcmVMaWdodCB7XFxuXFx0XFx0dmVjMyBkaXJlY3Rpb247XFxuXFx0XFx0dmVjMyBza3lDb2xvcjtcXG5cXHRcXHR2ZWMzIGdyb3VuZENvbG9yO1xcblxcdH07XFxuXFx0dW5pZm9ybSBIZW1pc3BoZXJlTGlnaHQgaGVtaXNwaGVyZUxpZ2h0c1sgTlVNX0hFTUlfTElHSFRTIF07XFxuXFx0dmVjMyBnZXRIZW1pc3BoZXJlTGlnaHRJcnJhZGlhbmNlKCBjb25zdCBpbiBIZW1pc3BoZXJlTGlnaHQgaGVtaUxpZ2h0LCBjb25zdCBpbiB2ZWMzIG5vcm1hbCApIHtcXG5cXHRcXHRmbG9hdCBkb3ROTCA9IGRvdCggbm9ybWFsLCBoZW1pTGlnaHQuZGlyZWN0aW9uICk7XFxuXFx0XFx0ZmxvYXQgaGVtaURpZmZ1c2VXZWlnaHQgPSAwLjUgKiBkb3ROTCArIDAuNTtcXG5cXHRcXHR2ZWMzIGlycmFkaWFuY2UgPSBtaXgoIGhlbWlMaWdodC5ncm91bmRDb2xvciwgaGVtaUxpZ2h0LnNreUNvbG9yLCBoZW1pRGlmZnVzZVdlaWdodCApO1xcblxcdFxcdHJldHVybiBpcnJhZGlhbmNlO1xcblxcdH1cXG4jZW5kaWZcIjtcblxudmFyIGVudm1hcF9waHlzaWNhbF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0VOVk1BUFxcblxcdHZlYzMgZ2V0SUJMSXJyYWRpYW5jZSggY29uc3QgaW4gdmVjMyBub3JtYWwgKSB7XFxuXFx0XFx0I2lmZGVmIEVOVk1BUF9UWVBFX0NVQkVfVVZcXG5cXHRcXHRcXHR2ZWMzIHdvcmxkTm9ybWFsID0gaW52ZXJzZVRyYW5zZm9ybURpcmVjdGlvbiggbm9ybWFsLCB2aWV3TWF0cml4ICk7XFxuXFx0XFx0XFx0dmVjNCBlbnZNYXBDb2xvciA9IHRleHR1cmVDdWJlVVYoIGVudk1hcCwgZW52TWFwUm90YXRpb24gKiB3b3JsZE5vcm1hbCwgMS4wICk7XFxuXFx0XFx0XFx0cmV0dXJuIFBJICogZW52TWFwQ29sb3IucmdiICogZW52TWFwSW50ZW5zaXR5O1xcblxcdFxcdCNlbHNlXFxuXFx0XFx0XFx0cmV0dXJuIHZlYzMoIDAuMCApO1xcblxcdFxcdCNlbmRpZlxcblxcdH1cXG5cXHR2ZWMzIGdldElCTFJhZGlhbmNlKCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MgKSB7XFxuXFx0XFx0I2lmZGVmIEVOVk1BUF9UWVBFX0NVQkVfVVZcXG5cXHRcXHRcXHR2ZWMzIHJlZmxlY3RWZWMgPSByZWZsZWN0KCAtIHZpZXdEaXIsIG5vcm1hbCApO1xcblxcdFxcdFxcdHJlZmxlY3RWZWMgPSBub3JtYWxpemUoIG1peCggcmVmbGVjdFZlYywgbm9ybWFsLCByb3VnaG5lc3MgKiByb3VnaG5lc3MpICk7XFxuXFx0XFx0XFx0cmVmbGVjdFZlYyA9IGludmVyc2VUcmFuc2Zvcm1EaXJlY3Rpb24oIHJlZmxlY3RWZWMsIHZpZXdNYXRyaXggKTtcXG5cXHRcXHRcXHR2ZWM0IGVudk1hcENvbG9yID0gdGV4dHVyZUN1YmVVViggZW52TWFwLCBlbnZNYXBSb3RhdGlvbiAqIHJlZmxlY3RWZWMsIHJvdWdobmVzcyApO1xcblxcdFxcdFxcdHJldHVybiBlbnZNYXBDb2xvci5yZ2IgKiBlbnZNYXBJbnRlbnNpdHk7XFxuXFx0XFx0I2Vsc2VcXG5cXHRcXHRcXHRyZXR1cm4gdmVjMyggMC4wICk7XFxuXFx0XFx0I2VuZGlmXFxuXFx0fVxcblxcdCNpZmRlZiBVU0VfQU5JU09UUk9QWVxcblxcdFxcdHZlYzMgZ2V0SUJMQW5pc290cm9weVJhZGlhbmNlKCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MsIGNvbnN0IGluIHZlYzMgYml0YW5nZW50LCBjb25zdCBpbiBmbG9hdCBhbmlzb3Ryb3B5ICkge1xcblxcdFxcdFxcdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFX1VWXFxuXFx0XFx0XFx0XFx0dmVjMyBiZW50Tm9ybWFsID0gY3Jvc3MoIGJpdGFuZ2VudCwgdmlld0RpciApO1xcblxcdFxcdFxcdFxcdGJlbnROb3JtYWwgPSBub3JtYWxpemUoIGNyb3NzKCBiZW50Tm9ybWFsLCBiaXRhbmdlbnQgKSApO1xcblxcdFxcdFxcdFxcdGJlbnROb3JtYWwgPSBub3JtYWxpemUoIG1peCggYmVudE5vcm1hbCwgbm9ybWFsLCBwb3cyKCBwb3cyKCAxLjAgLSBhbmlzb3Ryb3B5ICogKCAxLjAgLSByb3VnaG5lc3MgKSApICkgKSApO1xcblxcdFxcdFxcdFxcdHJldHVybiBnZXRJQkxSYWRpYW5jZSggdmlld0RpciwgYmVudE5vcm1hbCwgcm91Z2huZXNzICk7XFxuXFx0XFx0XFx0I2Vsc2VcXG5cXHRcXHRcXHRcXHRyZXR1cm4gdmVjMyggMC4wICk7XFxuXFx0XFx0XFx0I2VuZGlmXFxuXFx0XFx0fVxcblxcdCNlbmRpZlxcbiNlbmRpZlwiO1xuXG52YXIgbGlnaHRzX3Rvb25fZnJhZ21lbnQgPSBcIlRvb25NYXRlcmlhbCBtYXRlcmlhbDtcXG5tYXRlcmlhbC5kaWZmdXNlQ29sb3IgPSBkaWZmdXNlQ29sb3IucmdiO1wiO1xuXG52YXIgbGlnaHRzX3Rvb25fcGFyc19mcmFnbWVudCA9IFwidmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XFxuc3RydWN0IFRvb25NYXRlcmlhbCB7XFxuXFx0dmVjMyBkaWZmdXNlQ29sb3I7XFxufTtcXG52b2lkIFJFX0RpcmVjdF9Ub29uKCBjb25zdCBpbiBJbmNpZGVudExpZ2h0IGRpcmVjdExpZ2h0LCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBUb29uTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xcblxcdHZlYzMgaXJyYWRpYW5jZSA9IGdldEdyYWRpZW50SXJyYWRpYW5jZSggZ2VvbWV0cnlOb3JtYWwsIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiApICogZGlyZWN0TGlnaHQuY29sb3I7XFxuXFx0cmVmbGVjdGVkTGlnaHQuZGlyZWN0RGlmZnVzZSArPSBpcnJhZGlhbmNlICogQlJERl9MYW1iZXJ0KCBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKTtcXG59XFxudm9pZCBSRV9JbmRpcmVjdERpZmZ1c2VfVG9vbiggY29uc3QgaW4gdmVjMyBpcnJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBUb29uTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xcblxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSArPSBpcnJhZGlhbmNlICogQlJERl9MYW1iZXJ0KCBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKTtcXG59XFxuI2RlZmluZSBSRV9EaXJlY3RcXHRcXHRcXHRcXHRSRV9EaXJlY3RfVG9vblxcbiNkZWZpbmUgUkVfSW5kaXJlY3REaWZmdXNlXFx0XFx0UkVfSW5kaXJlY3REaWZmdXNlX1Rvb25cIjtcblxudmFyIGxpZ2h0c19waG9uZ19mcmFnbWVudCA9IFwiQmxpbm5QaG9uZ01hdGVyaWFsIG1hdGVyaWFsO1xcbm1hdGVyaWFsLmRpZmZ1c2VDb2xvciA9IGRpZmZ1c2VDb2xvci5yZ2I7XFxubWF0ZXJpYWwuc3BlY3VsYXJDb2xvciA9IHNwZWN1bGFyO1xcbm1hdGVyaWFsLnNwZWN1bGFyU2hpbmluZXNzID0gc2hpbmluZXNzO1xcbm1hdGVyaWFsLnNwZWN1bGFyU3RyZW5ndGggPSBzcGVjdWxhclN0cmVuZ3RoO1wiO1xuXG52YXIgbGlnaHRzX3Bob25nX3BhcnNfZnJhZ21lbnQgPSBcInZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xcbnN0cnVjdCBCbGlublBob25nTWF0ZXJpYWwge1xcblxcdHZlYzMgZGlmZnVzZUNvbG9yO1xcblxcdHZlYzMgc3BlY3VsYXJDb2xvcjtcXG5cXHRmbG9hdCBzcGVjdWxhclNoaW5pbmVzcztcXG5cXHRmbG9hdCBzcGVjdWxhclN0cmVuZ3RoO1xcbn07XFxudm9pZCBSRV9EaXJlY3RfQmxpbm5QaG9uZyggY29uc3QgaW4gSW5jaWRlbnRMaWdodCBkaXJlY3RMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gQmxpbm5QaG9uZ01hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcXG5cXHRmbG9hdCBkb3ROTCA9IHNhdHVyYXRlKCBkb3QoIGdlb21ldHJ5Tm9ybWFsLCBkaXJlY3RMaWdodC5kaXJlY3Rpb24gKSApO1xcblxcdHZlYzMgaXJyYWRpYW5jZSA9IGRvdE5MICogZGlyZWN0TGlnaHQuY29sb3I7XFxuXFx0cmVmbGVjdGVkTGlnaHQuZGlyZWN0RGlmZnVzZSArPSBpcnJhZGlhbmNlICogQlJERl9MYW1iZXJ0KCBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKTtcXG5cXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3RTcGVjdWxhciArPSBpcnJhZGlhbmNlICogQlJERl9CbGlublBob25nKCBkaXJlY3RMaWdodC5kaXJlY3Rpb24sIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlOb3JtYWwsIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IsIG1hdGVyaWFsLnNwZWN1bGFyU2hpbmluZXNzICkgKiBtYXRlcmlhbC5zcGVjdWxhclN0cmVuZ3RoO1xcbn1cXG52b2lkIFJFX0luZGlyZWN0RGlmZnVzZV9CbGlublBob25nKCBjb25zdCBpbiB2ZWMzIGlycmFkaWFuY2UsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeU5vcm1hbCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVZpZXdEaXIsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGNvbnN0IGluIEJsaW5uUGhvbmdNYXRlcmlhbCBtYXRlcmlhbCwgaW5vdXQgUmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgKSB7XFxuXFx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xcbn1cXG4jZGVmaW5lIFJFX0RpcmVjdFxcdFxcdFxcdFxcdFJFX0RpcmVjdF9CbGlublBob25nXFxuI2RlZmluZSBSRV9JbmRpcmVjdERpZmZ1c2VcXHRcXHRSRV9JbmRpcmVjdERpZmZ1c2VfQmxpbm5QaG9uZ1wiO1xuXG52YXIgbGlnaHRzX3BoeXNpY2FsX2ZyYWdtZW50ID0gXCJQaHlzaWNhbE1hdGVyaWFsIG1hdGVyaWFsO1xcbm1hdGVyaWFsLmRpZmZ1c2VDb2xvciA9IGRpZmZ1c2VDb2xvci5yZ2IgKiAoIDEuMCAtIG1ldGFsbmVzc0ZhY3RvciApO1xcbnZlYzMgZHh5ID0gbWF4KCBhYnMoIGRGZHgoIG5vblBlcnR1cmJlZE5vcm1hbCApICksIGFicyggZEZkeSggbm9uUGVydHVyYmVkTm9ybWFsICkgKSApO1xcbmZsb2F0IGdlb21ldHJ5Um91Z2huZXNzID0gbWF4KCBtYXgoIGR4eS54LCBkeHkueSApLCBkeHkueiApO1xcbm1hdGVyaWFsLnJvdWdobmVzcyA9IG1heCggcm91Z2huZXNzRmFjdG9yLCAwLjA1MjUgKTttYXRlcmlhbC5yb3VnaG5lc3MgKz0gZ2VvbWV0cnlSb3VnaG5lc3M7XFxubWF0ZXJpYWwucm91Z2huZXNzID0gbWluKCBtYXRlcmlhbC5yb3VnaG5lc3MsIDEuMCApO1xcbiNpZmRlZiBJT1JcXG5cXHRtYXRlcmlhbC5pb3IgPSBpb3I7XFxuXFx0I2lmZGVmIFVTRV9TUEVDVUxBUlxcblxcdFxcdGZsb2F0IHNwZWN1bGFySW50ZW5zaXR5RmFjdG9yID0gc3BlY3VsYXJJbnRlbnNpdHk7XFxuXFx0XFx0dmVjMyBzcGVjdWxhckNvbG9yRmFjdG9yID0gc3BlY3VsYXJDb2xvcjtcXG5cXHRcXHQjaWZkZWYgVVNFX1NQRUNVTEFSX0NPTE9STUFQXFxuXFx0XFx0XFx0c3BlY3VsYXJDb2xvckZhY3RvciAqPSB0ZXh0dXJlMkQoIHNwZWN1bGFyQ29sb3JNYXAsIHZTcGVjdWxhckNvbG9yTWFwVXYgKS5yZ2I7XFxuXFx0XFx0I2VuZGlmXFxuXFx0XFx0I2lmZGVmIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVBcXG5cXHRcXHRcXHRzcGVjdWxhckludGVuc2l0eUZhY3RvciAqPSB0ZXh0dXJlMkQoIHNwZWN1bGFySW50ZW5zaXR5TWFwLCB2U3BlY3VsYXJJbnRlbnNpdHlNYXBVdiApLmE7XFxuXFx0XFx0I2VuZGlmXFxuXFx0XFx0bWF0ZXJpYWwuc3BlY3VsYXJGOTAgPSBtaXgoIHNwZWN1bGFySW50ZW5zaXR5RmFjdG9yLCAxLjAsIG1ldGFsbmVzc0ZhY3RvciApO1xcblxcdCNlbHNlXFxuXFx0XFx0ZmxvYXQgc3BlY3VsYXJJbnRlbnNpdHlGYWN0b3IgPSAxLjA7XFxuXFx0XFx0dmVjMyBzcGVjdWxhckNvbG9yRmFjdG9yID0gdmVjMyggMS4wICk7XFxuXFx0XFx0bWF0ZXJpYWwuc3BlY3VsYXJGOTAgPSAxLjA7XFxuXFx0I2VuZGlmXFxuXFx0bWF0ZXJpYWwuc3BlY3VsYXJDb2xvciA9IG1peCggbWluKCBwb3cyKCAoIG1hdGVyaWFsLmlvciAtIDEuMCApIC8gKCBtYXRlcmlhbC5pb3IgKyAxLjAgKSApICogc3BlY3VsYXJDb2xvckZhY3RvciwgdmVjMyggMS4wICkgKSAqIHNwZWN1bGFySW50ZW5zaXR5RmFjdG9yLCBkaWZmdXNlQ29sb3IucmdiLCBtZXRhbG5lc3NGYWN0b3IgKTtcXG4jZWxzZVxcblxcdG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgPSBtaXgoIHZlYzMoIDAuMDQgKSwgZGlmZnVzZUNvbG9yLnJnYiwgbWV0YWxuZXNzRmFjdG9yICk7XFxuXFx0bWF0ZXJpYWwuc3BlY3VsYXJGOTAgPSAxLjA7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRcXG5cXHRtYXRlcmlhbC5jbGVhcmNvYXQgPSBjbGVhcmNvYXQ7XFxuXFx0bWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzID0gY2xlYXJjb2F0Um91Z2huZXNzO1xcblxcdG1hdGVyaWFsLmNsZWFyY29hdEYwID0gdmVjMyggMC4wNCApO1xcblxcdG1hdGVyaWFsLmNsZWFyY29hdEY5MCA9IDEuMDtcXG5cXHQjaWZkZWYgVVNFX0NMRUFSQ09BVE1BUFxcblxcdFxcdG1hdGVyaWFsLmNsZWFyY29hdCAqPSB0ZXh0dXJlMkQoIGNsZWFyY29hdE1hcCwgdkNsZWFyY29hdE1hcFV2ICkueDtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX0NMRUFSQ09BVF9ST1VHSE5FU1NNQVBcXG5cXHRcXHRtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgKj0gdGV4dHVyZTJEKCBjbGVhcmNvYXRSb3VnaG5lc3NNYXAsIHZDbGVhcmNvYXRSb3VnaG5lc3NNYXBVdiApLnk7XFxuXFx0I2VuZGlmXFxuXFx0bWF0ZXJpYWwuY2xlYXJjb2F0ID0gc2F0dXJhdGUoIG1hdGVyaWFsLmNsZWFyY29hdCApO1xcdG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcyA9IG1heCggbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzLCAwLjA1MjUgKTtcXG5cXHRtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgKz0gZ2VvbWV0cnlSb3VnaG5lc3M7XFxuXFx0bWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzID0gbWluKCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MsIDEuMCApO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfRElTUEVSU0lPTlxcblxcdG1hdGVyaWFsLmRpc3BlcnNpb24gPSBkaXNwZXJzaW9uO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcXG5cXHRtYXRlcmlhbC5pcmlkZXNjZW5jZSA9IGlyaWRlc2NlbmNlO1xcblxcdG1hdGVyaWFsLmlyaWRlc2NlbmNlSU9SID0gaXJpZGVzY2VuY2VJT1I7XFxuXFx0I2lmZGVmIFVTRV9JUklERVNDRU5DRU1BUFxcblxcdFxcdG1hdGVyaWFsLmlyaWRlc2NlbmNlICo9IHRleHR1cmUyRCggaXJpZGVzY2VuY2VNYXAsIHZJcmlkZXNjZW5jZU1hcFV2ICkucjtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX0lSSURFU0NFTkNFX1RISUNLTkVTU01BUFxcblxcdFxcdG1hdGVyaWFsLmlyaWRlc2NlbmNlVGhpY2tuZXNzID0gKGlyaWRlc2NlbmNlVGhpY2tuZXNzTWF4aW11bSAtIGlyaWRlc2NlbmNlVGhpY2tuZXNzTWluaW11bSkgKiB0ZXh0dXJlMkQoIGlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwLCB2SXJpZGVzY2VuY2VUaGlja25lc3NNYXBVdiApLmcgKyBpcmlkZXNjZW5jZVRoaWNrbmVzc01pbmltdW07XFxuXFx0I2Vsc2VcXG5cXHRcXHRtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzcyA9IGlyaWRlc2NlbmNlVGhpY2tuZXNzTWF4aW11bTtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NIRUVOXFxuXFx0bWF0ZXJpYWwuc2hlZW5Db2xvciA9IHNoZWVuQ29sb3I7XFxuXFx0I2lmZGVmIFVTRV9TSEVFTl9DT0xPUk1BUFxcblxcdFxcdG1hdGVyaWFsLnNoZWVuQ29sb3IgKj0gdGV4dHVyZTJEKCBzaGVlbkNvbG9yTWFwLCB2U2hlZW5Db2xvck1hcFV2ICkucmdiO1xcblxcdCNlbmRpZlxcblxcdG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzID0gY2xhbXAoIHNoZWVuUm91Z2huZXNzLCAwLjA3LCAxLjAgKTtcXG5cXHQjaWZkZWYgVVNFX1NIRUVOX1JPVUdITkVTU01BUFxcblxcdFxcdG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzICo9IHRleHR1cmUyRCggc2hlZW5Sb3VnaG5lc3NNYXAsIHZTaGVlblJvdWdobmVzc01hcFV2ICkuYTtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0FOSVNPVFJPUFlcXG5cXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlNQVBcXG5cXHRcXHRtYXQyIGFuaXNvdHJvcHlNYXQgPSBtYXQyKCBhbmlzb3Ryb3B5VmVjdG9yLngsIGFuaXNvdHJvcHlWZWN0b3IueSwgLSBhbmlzb3Ryb3B5VmVjdG9yLnksIGFuaXNvdHJvcHlWZWN0b3IueCApO1xcblxcdFxcdHZlYzMgYW5pc290cm9weVBvbGFyID0gdGV4dHVyZTJEKCBhbmlzb3Ryb3B5TWFwLCB2QW5pc290cm9weU1hcFV2ICkucmdiO1xcblxcdFxcdHZlYzIgYW5pc290cm9weVYgPSBhbmlzb3Ryb3B5TWF0ICogbm9ybWFsaXplKCAyLjAgKiBhbmlzb3Ryb3B5UG9sYXIucmcgLSB2ZWMyKCAxLjAgKSApICogYW5pc290cm9weVBvbGFyLmI7XFxuXFx0I2Vsc2VcXG5cXHRcXHR2ZWMyIGFuaXNvdHJvcHlWID0gYW5pc290cm9weVZlY3RvcjtcXG5cXHQjZW5kaWZcXG5cXHRtYXRlcmlhbC5hbmlzb3Ryb3B5ID0gbGVuZ3RoKCBhbmlzb3Ryb3B5ViApO1xcblxcdGlmKCBtYXRlcmlhbC5hbmlzb3Ryb3B5ID09IDAuMCApIHtcXG5cXHRcXHRhbmlzb3Ryb3B5ViA9IHZlYzIoIDEuMCwgMC4wICk7XFxuXFx0fSBlbHNlIHtcXG5cXHRcXHRhbmlzb3Ryb3B5ViAvPSBtYXRlcmlhbC5hbmlzb3Ryb3B5O1xcblxcdFxcdG1hdGVyaWFsLmFuaXNvdHJvcHkgPSBzYXR1cmF0ZSggbWF0ZXJpYWwuYW5pc290cm9weSApO1xcblxcdH1cXG5cXHRtYXRlcmlhbC5hbHBoYVQgPSBtaXgoIHBvdzIoIG1hdGVyaWFsLnJvdWdobmVzcyApLCAxLjAsIHBvdzIoIG1hdGVyaWFsLmFuaXNvdHJvcHkgKSApO1xcblxcdG1hdGVyaWFsLmFuaXNvdHJvcHlUID0gdGJuWyAwIF0gKiBhbmlzb3Ryb3B5Vi54ICsgdGJuWyAxIF0gKiBhbmlzb3Ryb3B5Vi55O1xcblxcdG1hdGVyaWFsLmFuaXNvdHJvcHlCID0gdGJuWyAxIF0gKiBhbmlzb3Ryb3B5Vi54IC0gdGJuWyAwIF0gKiBhbmlzb3Ryb3B5Vi55O1xcbiNlbmRpZlwiO1xuXG52YXIgbGlnaHRzX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQgPSBcInN0cnVjdCBQaHlzaWNhbE1hdGVyaWFsIHtcXG5cXHR2ZWMzIGRpZmZ1c2VDb2xvcjtcXG5cXHRmbG9hdCByb3VnaG5lc3M7XFxuXFx0dmVjMyBzcGVjdWxhckNvbG9yO1xcblxcdGZsb2F0IHNwZWN1bGFyRjkwO1xcblxcdGZsb2F0IGRpc3BlcnNpb247XFxuXFx0I2lmZGVmIFVTRV9DTEVBUkNPQVRcXG5cXHRcXHRmbG9hdCBjbGVhcmNvYXQ7XFxuXFx0XFx0ZmxvYXQgY2xlYXJjb2F0Um91Z2huZXNzO1xcblxcdFxcdHZlYzMgY2xlYXJjb2F0RjA7XFxuXFx0XFx0ZmxvYXQgY2xlYXJjb2F0RjkwO1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcXG5cXHRcXHRmbG9hdCBpcmlkZXNjZW5jZTtcXG5cXHRcXHRmbG9hdCBpcmlkZXNjZW5jZUlPUjtcXG5cXHRcXHRmbG9hdCBpcmlkZXNjZW5jZVRoaWNrbmVzcztcXG5cXHRcXHR2ZWMzIGlyaWRlc2NlbmNlRnJlc25lbDtcXG5cXHRcXHR2ZWMzIGlyaWRlc2NlbmNlRjA7XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIFVTRV9TSEVFTlxcblxcdFxcdHZlYzMgc2hlZW5Db2xvcjtcXG5cXHRcXHRmbG9hdCBzaGVlblJvdWdobmVzcztcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgSU9SXFxuXFx0XFx0ZmxvYXQgaW9yO1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OXFxuXFx0XFx0ZmxvYXQgdHJhbnNtaXNzaW9uO1xcblxcdFxcdGZsb2F0IHRyYW5zbWlzc2lvbkFscGhhO1xcblxcdFxcdGZsb2F0IHRoaWNrbmVzcztcXG5cXHRcXHRmbG9hdCBhdHRlbnVhdGlvbkRpc3RhbmNlO1xcblxcdFxcdHZlYzMgYXR0ZW51YXRpb25Db2xvcjtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlcXG5cXHRcXHRmbG9hdCBhbmlzb3Ryb3B5O1xcblxcdFxcdGZsb2F0IGFscGhhVDtcXG5cXHRcXHR2ZWMzIGFuaXNvdHJvcHlUO1xcblxcdFxcdHZlYzMgYW5pc290cm9weUI7XFxuXFx0I2VuZGlmXFxufTtcXG52ZWMzIGNsZWFyY29hdFNwZWN1bGFyRGlyZWN0ID0gdmVjMyggMC4wICk7XFxudmVjMyBjbGVhcmNvYXRTcGVjdWxhckluZGlyZWN0ID0gdmVjMyggMC4wICk7XFxudmVjMyBzaGVlblNwZWN1bGFyRGlyZWN0ID0gdmVjMyggMC4wICk7XFxudmVjMyBzaGVlblNwZWN1bGFySW5kaXJlY3QgPSB2ZWMzKDAuMCApO1xcbnZlYzMgU2NobGlja190b19GMCggY29uc3QgaW4gdmVjMyBmLCBjb25zdCBpbiBmbG9hdCBmOTAsIGNvbnN0IGluIGZsb2F0IGRvdFZIICkge1xcbiAgICBmbG9hdCB4ID0gY2xhbXAoIDEuMCAtIGRvdFZILCAwLjAsIDEuMCApO1xcbiAgICBmbG9hdCB4MiA9IHggKiB4O1xcbiAgICBmbG9hdCB4NSA9IGNsYW1wKCB4ICogeDIgKiB4MiwgMC4wLCAwLjk5OTkgKTtcXG4gICAgcmV0dXJuICggZiAtIHZlYzMoIGY5MCApICogeDUgKSAvICggMS4wIC0geDUgKTtcXG59XFxuZmxvYXQgVl9HR1hfU21pdGhDb3JyZWxhdGVkKCBjb25zdCBpbiBmbG9hdCBhbHBoYSwgY29uc3QgaW4gZmxvYXQgZG90TkwsIGNvbnN0IGluIGZsb2F0IGRvdE5WICkge1xcblxcdGZsb2F0IGEyID0gcG93MiggYWxwaGEgKTtcXG5cXHRmbG9hdCBndiA9IGRvdE5MICogc3FydCggYTIgKyAoIDEuMCAtIGEyICkgKiBwb3cyKCBkb3ROViApICk7XFxuXFx0ZmxvYXQgZ2wgPSBkb3ROViAqIHNxcnQoIGEyICsgKCAxLjAgLSBhMiApICogcG93MiggZG90TkwgKSApO1xcblxcdHJldHVybiAwLjUgLyBtYXgoIGd2ICsgZ2wsIEVQU0lMT04gKTtcXG59XFxuZmxvYXQgRF9HR1goIGNvbnN0IGluIGZsb2F0IGFscGhhLCBjb25zdCBpbiBmbG9hdCBkb3ROSCApIHtcXG5cXHRmbG9hdCBhMiA9IHBvdzIoIGFscGhhICk7XFxuXFx0ZmxvYXQgZGVub20gPSBwb3cyKCBkb3ROSCApICogKCBhMiAtIDEuMCApICsgMS4wO1xcblxcdHJldHVybiBSRUNJUFJPQ0FMX1BJICogYTIgLyBwb3cyKCBkZW5vbSApO1xcbn1cXG4jaWZkZWYgVVNFX0FOSVNPVFJPUFlcXG5cXHRmbG9hdCBWX0dHWF9TbWl0aENvcnJlbGF0ZWRfQW5pc290cm9waWMoIGNvbnN0IGluIGZsb2F0IGFscGhhVCwgY29uc3QgaW4gZmxvYXQgYWxwaGFCLCBjb25zdCBpbiBmbG9hdCBkb3RUViwgY29uc3QgaW4gZmxvYXQgZG90QlYsIGNvbnN0IGluIGZsb2F0IGRvdFRMLCBjb25zdCBpbiBmbG9hdCBkb3RCTCwgY29uc3QgaW4gZmxvYXQgZG90TlYsIGNvbnN0IGluIGZsb2F0IGRvdE5MICkge1xcblxcdFxcdGZsb2F0IGd2ID0gZG90TkwgKiBsZW5ndGgoIHZlYzMoIGFscGhhVCAqIGRvdFRWLCBhbHBoYUIgKiBkb3RCViwgZG90TlYgKSApO1xcblxcdFxcdGZsb2F0IGdsID0gZG90TlYgKiBsZW5ndGgoIHZlYzMoIGFscGhhVCAqIGRvdFRMLCBhbHBoYUIgKiBkb3RCTCwgZG90TkwgKSApO1xcblxcdFxcdGZsb2F0IHYgPSAwLjUgLyAoIGd2ICsgZ2wgKTtcXG5cXHRcXHRyZXR1cm4gc2F0dXJhdGUodik7XFxuXFx0fVxcblxcdGZsb2F0IERfR0dYX0FuaXNvdHJvcGljKCBjb25zdCBpbiBmbG9hdCBhbHBoYVQsIGNvbnN0IGluIGZsb2F0IGFscGhhQiwgY29uc3QgaW4gZmxvYXQgZG90TkgsIGNvbnN0IGluIGZsb2F0IGRvdFRILCBjb25zdCBpbiBmbG9hdCBkb3RCSCApIHtcXG5cXHRcXHRmbG9hdCBhMiA9IGFscGhhVCAqIGFscGhhQjtcXG5cXHRcXHRoaWdocCB2ZWMzIHYgPSB2ZWMzKCBhbHBoYUIgKiBkb3RUSCwgYWxwaGFUICogZG90QkgsIGEyICogZG90TkggKTtcXG5cXHRcXHRoaWdocCBmbG9hdCB2MiA9IGRvdCggdiwgdiApO1xcblxcdFxcdGZsb2F0IHcyID0gYTIgLyB2MjtcXG5cXHRcXHRyZXR1cm4gUkVDSVBST0NBTF9QSSAqIGEyICogcG93MiAoIHcyICk7XFxuXFx0fVxcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUXFxuXFx0dmVjMyBCUkRGX0dHWF9DbGVhcmNvYXQoIGNvbnN0IGluIHZlYzMgbGlnaHREaXIsIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIFBoeXNpY2FsTWF0ZXJpYWwgbWF0ZXJpYWwpIHtcXG5cXHRcXHR2ZWMzIGYwID0gbWF0ZXJpYWwuY2xlYXJjb2F0RjA7XFxuXFx0XFx0ZmxvYXQgZjkwID0gbWF0ZXJpYWwuY2xlYXJjb2F0RjkwO1xcblxcdFxcdGZsb2F0IHJvdWdobmVzcyA9IG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcztcXG5cXHRcXHRmbG9hdCBhbHBoYSA9IHBvdzIoIHJvdWdobmVzcyApO1xcblxcdFxcdHZlYzMgaGFsZkRpciA9IG5vcm1hbGl6ZSggbGlnaHREaXIgKyB2aWV3RGlyICk7XFxuXFx0XFx0ZmxvYXQgZG90TkwgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGxpZ2h0RGlyICkgKTtcXG5cXHRcXHRmbG9hdCBkb3ROViA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgdmlld0RpciApICk7XFxuXFx0XFx0ZmxvYXQgZG90TkggPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGhhbGZEaXIgKSApO1xcblxcdFxcdGZsb2F0IGRvdFZIID0gc2F0dXJhdGUoIGRvdCggdmlld0RpciwgaGFsZkRpciApICk7XFxuXFx0XFx0dmVjMyBGID0gRl9TY2hsaWNrKCBmMCwgZjkwLCBkb3RWSCApO1xcblxcdFxcdGZsb2F0IFYgPSBWX0dHWF9TbWl0aENvcnJlbGF0ZWQoIGFscGhhLCBkb3ROTCwgZG90TlYgKTtcXG5cXHRcXHRmbG9hdCBEID0gRF9HR1goIGFscGhhLCBkb3ROSCApO1xcblxcdFxcdHJldHVybiBGICogKCBWICogRCApO1xcblxcdH1cXG4jZW5kaWZcXG52ZWMzIEJSREZfR0dYKCBjb25zdCBpbiB2ZWMzIGxpZ2h0RGlyLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiBQaHlzaWNhbE1hdGVyaWFsIG1hdGVyaWFsICkge1xcblxcdHZlYzMgZjAgPSBtYXRlcmlhbC5zcGVjdWxhckNvbG9yO1xcblxcdGZsb2F0IGY5MCA9IG1hdGVyaWFsLnNwZWN1bGFyRjkwO1xcblxcdGZsb2F0IHJvdWdobmVzcyA9IG1hdGVyaWFsLnJvdWdobmVzcztcXG5cXHRmbG9hdCBhbHBoYSA9IHBvdzIoIHJvdWdobmVzcyApO1xcblxcdHZlYzMgaGFsZkRpciA9IG5vcm1hbGl6ZSggbGlnaHREaXIgKyB2aWV3RGlyICk7XFxuXFx0ZmxvYXQgZG90TkwgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGxpZ2h0RGlyICkgKTtcXG5cXHRmbG9hdCBkb3ROViA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgdmlld0RpciApICk7XFxuXFx0ZmxvYXQgZG90TkggPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGhhbGZEaXIgKSApO1xcblxcdGZsb2F0IGRvdFZIID0gc2F0dXJhdGUoIGRvdCggdmlld0RpciwgaGFsZkRpciApICk7XFxuXFx0dmVjMyBGID0gRl9TY2hsaWNrKCBmMCwgZjkwLCBkb3RWSCApO1xcblxcdCNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcXG5cXHRcXHRGID0gbWl4KCBGLCBtYXRlcmlhbC5pcmlkZXNjZW5jZUZyZXNuZWwsIG1hdGVyaWFsLmlyaWRlc2NlbmNlICk7XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIFVTRV9BTklTT1RST1BZXFxuXFx0XFx0ZmxvYXQgZG90VEwgPSBkb3QoIG1hdGVyaWFsLmFuaXNvdHJvcHlULCBsaWdodERpciApO1xcblxcdFxcdGZsb2F0IGRvdFRWID0gZG90KCBtYXRlcmlhbC5hbmlzb3Ryb3B5VCwgdmlld0RpciApO1xcblxcdFxcdGZsb2F0IGRvdFRIID0gZG90KCBtYXRlcmlhbC5hbmlzb3Ryb3B5VCwgaGFsZkRpciApO1xcblxcdFxcdGZsb2F0IGRvdEJMID0gZG90KCBtYXRlcmlhbC5hbmlzb3Ryb3B5QiwgbGlnaHREaXIgKTtcXG5cXHRcXHRmbG9hdCBkb3RCViA9IGRvdCggbWF0ZXJpYWwuYW5pc290cm9weUIsIHZpZXdEaXIgKTtcXG5cXHRcXHRmbG9hdCBkb3RCSCA9IGRvdCggbWF0ZXJpYWwuYW5pc290cm9weUIsIGhhbGZEaXIgKTtcXG5cXHRcXHRmbG9hdCBWID0gVl9HR1hfU21pdGhDb3JyZWxhdGVkX0FuaXNvdHJvcGljKCBtYXRlcmlhbC5hbHBoYVQsIGFscGhhLCBkb3RUViwgZG90QlYsIGRvdFRMLCBkb3RCTCwgZG90TlYsIGRvdE5MICk7XFxuXFx0XFx0ZmxvYXQgRCA9IERfR0dYX0FuaXNvdHJvcGljKCBtYXRlcmlhbC5hbHBoYVQsIGFscGhhLCBkb3ROSCwgZG90VEgsIGRvdEJIICk7XFxuXFx0I2Vsc2VcXG5cXHRcXHRmbG9hdCBWID0gVl9HR1hfU21pdGhDb3JyZWxhdGVkKCBhbHBoYSwgZG90TkwsIGRvdE5WICk7XFxuXFx0XFx0ZmxvYXQgRCA9IERfR0dYKCBhbHBoYSwgZG90TkggKTtcXG5cXHQjZW5kaWZcXG5cXHRyZXR1cm4gRiAqICggViAqIEQgKTtcXG59XFxudmVjMiBMVENfVXYoIGNvbnN0IGluIHZlYzMgTiwgY29uc3QgaW4gdmVjMyBWLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MgKSB7XFxuXFx0Y29uc3QgZmxvYXQgTFVUX1NJWkUgPSA2NC4wO1xcblxcdGNvbnN0IGZsb2F0IExVVF9TQ0FMRSA9ICggTFVUX1NJWkUgLSAxLjAgKSAvIExVVF9TSVpFO1xcblxcdGNvbnN0IGZsb2F0IExVVF9CSUFTID0gMC41IC8gTFVUX1NJWkU7XFxuXFx0ZmxvYXQgZG90TlYgPSBzYXR1cmF0ZSggZG90KCBOLCBWICkgKTtcXG5cXHR2ZWMyIHV2ID0gdmVjMiggcm91Z2huZXNzLCBzcXJ0KCAxLjAgLSBkb3ROViApICk7XFxuXFx0dXYgPSB1diAqIExVVF9TQ0FMRSArIExVVF9CSUFTO1xcblxcdHJldHVybiB1djtcXG59XFxuZmxvYXQgTFRDX0NsaXBwZWRTcGhlcmVGb3JtRmFjdG9yKCBjb25zdCBpbiB2ZWMzIGYgKSB7XFxuXFx0ZmxvYXQgbCA9IGxlbmd0aCggZiApO1xcblxcdHJldHVybiBtYXgoICggbCAqIGwgKyBmLnogKSAvICggbCArIDEuMCApLCAwLjAgKTtcXG59XFxudmVjMyBMVENfRWRnZVZlY3RvckZvcm1GYWN0b3IoIGNvbnN0IGluIHZlYzMgdjEsIGNvbnN0IGluIHZlYzMgdjIgKSB7XFxuXFx0ZmxvYXQgeCA9IGRvdCggdjEsIHYyICk7XFxuXFx0ZmxvYXQgeSA9IGFicyggeCApO1xcblxcdGZsb2F0IGEgPSAwLjg1NDM5ODUgKyAoIDAuNDk2NTE1NSArIDAuMDE0NTIwNiAqIHkgKSAqIHk7XFxuXFx0ZmxvYXQgYiA9IDMuNDE3NTk0MCArICggNC4xNjE2NzI0ICsgeSApICogeTtcXG5cXHRmbG9hdCB2ID0gYSAvIGI7XFxuXFx0ZmxvYXQgdGhldGFfc2ludGhldGEgPSAoIHggPiAwLjAgKSA/IHYgOiAwLjUgKiBpbnZlcnNlc3FydCggbWF4KCAxLjAgLSB4ICogeCwgMWUtNyApICkgLSB2O1xcblxcdHJldHVybiBjcm9zcyggdjEsIHYyICkgKiB0aGV0YV9zaW50aGV0YTtcXG59XFxudmVjMyBMVENfRXZhbHVhdGUoIGNvbnN0IGluIHZlYzMgTiwgY29uc3QgaW4gdmVjMyBWLCBjb25zdCBpbiB2ZWMzIFAsIGNvbnN0IGluIG1hdDMgbUludiwgY29uc3QgaW4gdmVjMyByZWN0Q29vcmRzWyA0IF0gKSB7XFxuXFx0dmVjMyB2MSA9IHJlY3RDb29yZHNbIDEgXSAtIHJlY3RDb29yZHNbIDAgXTtcXG5cXHR2ZWMzIHYyID0gcmVjdENvb3Jkc1sgMyBdIC0gcmVjdENvb3Jkc1sgMCBdO1xcblxcdHZlYzMgbGlnaHROb3JtYWwgPSBjcm9zcyggdjEsIHYyICk7XFxuXFx0aWYoIGRvdCggbGlnaHROb3JtYWwsIFAgLSByZWN0Q29vcmRzWyAwIF0gKSA8IDAuMCApIHJldHVybiB2ZWMzKCAwLjAgKTtcXG5cXHR2ZWMzIFQxLCBUMjtcXG5cXHRUMSA9IG5vcm1hbGl6ZSggViAtIE4gKiBkb3QoIFYsIE4gKSApO1xcblxcdFQyID0gLSBjcm9zcyggTiwgVDEgKTtcXG5cXHRtYXQzIG1hdCA9IG1JbnYgKiB0cmFuc3Bvc2VNYXQzKCBtYXQzKCBUMSwgVDIsIE4gKSApO1xcblxcdHZlYzMgY29vcmRzWyA0IF07XFxuXFx0Y29vcmRzWyAwIF0gPSBtYXQgKiAoIHJlY3RDb29yZHNbIDAgXSAtIFAgKTtcXG5cXHRjb29yZHNbIDEgXSA9IG1hdCAqICggcmVjdENvb3Jkc1sgMSBdIC0gUCApO1xcblxcdGNvb3Jkc1sgMiBdID0gbWF0ICogKCByZWN0Q29vcmRzWyAyIF0gLSBQICk7XFxuXFx0Y29vcmRzWyAzIF0gPSBtYXQgKiAoIHJlY3RDb29yZHNbIDMgXSAtIFAgKTtcXG5cXHRjb29yZHNbIDAgXSA9IG5vcm1hbGl6ZSggY29vcmRzWyAwIF0gKTtcXG5cXHRjb29yZHNbIDEgXSA9IG5vcm1hbGl6ZSggY29vcmRzWyAxIF0gKTtcXG5cXHRjb29yZHNbIDIgXSA9IG5vcm1hbGl6ZSggY29vcmRzWyAyIF0gKTtcXG5cXHRjb29yZHNbIDMgXSA9IG5vcm1hbGl6ZSggY29vcmRzWyAzIF0gKTtcXG5cXHR2ZWMzIHZlY3RvckZvcm1GYWN0b3IgPSB2ZWMzKCAwLjAgKTtcXG5cXHR2ZWN0b3JGb3JtRmFjdG9yICs9IExUQ19FZGdlVmVjdG9yRm9ybUZhY3RvciggY29vcmRzWyAwIF0sIGNvb3Jkc1sgMSBdICk7XFxuXFx0dmVjdG9yRm9ybUZhY3RvciArPSBMVENfRWRnZVZlY3RvckZvcm1GYWN0b3IoIGNvb3Jkc1sgMSBdLCBjb29yZHNbIDIgXSApO1xcblxcdHZlY3RvckZvcm1GYWN0b3IgKz0gTFRDX0VkZ2VWZWN0b3JGb3JtRmFjdG9yKCBjb29yZHNbIDIgXSwgY29vcmRzWyAzIF0gKTtcXG5cXHR2ZWN0b3JGb3JtRmFjdG9yICs9IExUQ19FZGdlVmVjdG9yRm9ybUZhY3RvciggY29vcmRzWyAzIF0sIGNvb3Jkc1sgMCBdICk7XFxuXFx0ZmxvYXQgcmVzdWx0ID0gTFRDX0NsaXBwZWRTcGhlcmVGb3JtRmFjdG9yKCB2ZWN0b3JGb3JtRmFjdG9yICk7XFxuXFx0cmV0dXJuIHZlYzMoIHJlc3VsdCApO1xcbn1cXG4jaWYgZGVmaW5lZCggVVNFX1NIRUVOIClcXG5mbG9hdCBEX0NoYXJsaWUoIGZsb2F0IHJvdWdobmVzcywgZmxvYXQgZG90TkggKSB7XFxuXFx0ZmxvYXQgYWxwaGEgPSBwb3cyKCByb3VnaG5lc3MgKTtcXG5cXHRmbG9hdCBpbnZBbHBoYSA9IDEuMCAvIGFscGhhO1xcblxcdGZsb2F0IGNvczJoID0gZG90TkggKiBkb3ROSDtcXG5cXHRmbG9hdCBzaW4yaCA9IG1heCggMS4wIC0gY29zMmgsIDAuMDA3ODEyNSApO1xcblxcdHJldHVybiAoIDIuMCArIGludkFscGhhICkgKiBwb3coIHNpbjJoLCBpbnZBbHBoYSAqIDAuNSApIC8gKCAyLjAgKiBQSSApO1xcbn1cXG5mbG9hdCBWX05ldWJlbHQoIGZsb2F0IGRvdE5WLCBmbG9hdCBkb3ROTCApIHtcXG5cXHRyZXR1cm4gc2F0dXJhdGUoIDEuMCAvICggNC4wICogKCBkb3ROTCArIGRvdE5WIC0gZG90TkwgKiBkb3ROViApICkgKTtcXG59XFxudmVjMyBCUkRGX1NoZWVuKCBjb25zdCBpbiB2ZWMzIGxpZ2h0RGlyLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgbm9ybWFsLCB2ZWMzIHNoZWVuQ29sb3IsIGNvbnN0IGluIGZsb2F0IHNoZWVuUm91Z2huZXNzICkge1xcblxcdHZlYzMgaGFsZkRpciA9IG5vcm1hbGl6ZSggbGlnaHREaXIgKyB2aWV3RGlyICk7XFxuXFx0ZmxvYXQgZG90TkwgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGxpZ2h0RGlyICkgKTtcXG5cXHRmbG9hdCBkb3ROViA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgdmlld0RpciApICk7XFxuXFx0ZmxvYXQgZG90TkggPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGhhbGZEaXIgKSApO1xcblxcdGZsb2F0IEQgPSBEX0NoYXJsaWUoIHNoZWVuUm91Z2huZXNzLCBkb3ROSCApO1xcblxcdGZsb2F0IFYgPSBWX05ldWJlbHQoIGRvdE5WLCBkb3ROTCApO1xcblxcdHJldHVybiBzaGVlbkNvbG9yICogKCBEICogViApO1xcbn1cXG4jZW5kaWZcXG5mbG9hdCBJQkxTaGVlbkJSREYoIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcyApIHtcXG5cXHRmbG9hdCBkb3ROViA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgdmlld0RpciApICk7XFxuXFx0ZmxvYXQgcjIgPSByb3VnaG5lc3MgKiByb3VnaG5lc3M7XFxuXFx0ZmxvYXQgYSA9IHJvdWdobmVzcyA8IDAuMjUgPyAtMzM5LjIgKiByMiArIDE2MS40ICogcm91Z2huZXNzIC0gMjUuOSA6IC04LjQ4ICogcjIgKyAxNC4zICogcm91Z2huZXNzIC0gOS45NTtcXG5cXHRmbG9hdCBiID0gcm91Z2huZXNzIDwgMC4yNSA/IDQ0LjAgKiByMiAtIDIzLjcgKiByb3VnaG5lc3MgKyAzLjI2IDogMS45NyAqIHIyIC0gMy4yNyAqIHJvdWdobmVzcyArIDAuNzI7XFxuXFx0ZmxvYXQgREcgPSBleHAoIGEgKiBkb3ROViArIGIgKSArICggcm91Z2huZXNzIDwgMC4yNSA/IDAuMCA6IDAuMSAqICggcm91Z2huZXNzIC0gMC4yNSApICk7XFxuXFx0cmV0dXJuIHNhdHVyYXRlKCBERyAqIFJFQ0lQUk9DQUxfUEkgKTtcXG59XFxudmVjMiBERkdBcHByb3goIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcyApIHtcXG5cXHRmbG9hdCBkb3ROViA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgdmlld0RpciApICk7XFxuXFx0Y29uc3QgdmVjNCBjMCA9IHZlYzQoIC0gMSwgLSAwLjAyNzUsIC0gMC41NzIsIDAuMDIyICk7XFxuXFx0Y29uc3QgdmVjNCBjMSA9IHZlYzQoIDEsIDAuMDQyNSwgMS4wNCwgLSAwLjA0ICk7XFxuXFx0dmVjNCByID0gcm91Z2huZXNzICogYzAgKyBjMTtcXG5cXHRmbG9hdCBhMDA0ID0gbWluKCByLnggKiByLngsIGV4cDIoIC0gOS4yOCAqIGRvdE5WICkgKSAqIHIueCArIHIueTtcXG5cXHR2ZWMyIGZhYiA9IHZlYzIoIC0gMS4wNCwgMS4wNCApICogYTAwNCArIHIuenc7XFxuXFx0cmV0dXJuIGZhYjtcXG59XFxudmVjMyBFbnZpcm9ubWVudEJSREYoIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgc3BlY3VsYXJDb2xvciwgY29uc3QgaW4gZmxvYXQgc3BlY3VsYXJGOTAsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcyApIHtcXG5cXHR2ZWMyIGZhYiA9IERGR0FwcHJveCggbm9ybWFsLCB2aWV3RGlyLCByb3VnaG5lc3MgKTtcXG5cXHRyZXR1cm4gc3BlY3VsYXJDb2xvciAqIGZhYi54ICsgc3BlY3VsYXJGOTAgKiBmYWIueTtcXG59XFxuI2lmZGVmIFVTRV9JUklERVNDRU5DRVxcbnZvaWQgY29tcHV0ZU11bHRpc2NhdHRlcmluZ0lyaWRlc2NlbmNlKCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiB2ZWMzIHNwZWN1bGFyQ29sb3IsIGNvbnN0IGluIGZsb2F0IHNwZWN1bGFyRjkwLCBjb25zdCBpbiBmbG9hdCBpcmlkZXNjZW5jZSwgY29uc3QgaW4gdmVjMyBpcmlkZXNjZW5jZUYwLCBjb25zdCBpbiBmbG9hdCByb3VnaG5lc3MsIGlub3V0IHZlYzMgc2luZ2xlU2NhdHRlciwgaW5vdXQgdmVjMyBtdWx0aVNjYXR0ZXIgKSB7XFxuI2Vsc2VcXG52b2lkIGNvbXB1dGVNdWx0aXNjYXR0ZXJpbmcoIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgc3BlY3VsYXJDb2xvciwgY29uc3QgaW4gZmxvYXQgc3BlY3VsYXJGOTAsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcywgaW5vdXQgdmVjMyBzaW5nbGVTY2F0dGVyLCBpbm91dCB2ZWMzIG11bHRpU2NhdHRlciApIHtcXG4jZW5kaWZcXG5cXHR2ZWMyIGZhYiA9IERGR0FwcHJveCggbm9ybWFsLCB2aWV3RGlyLCByb3VnaG5lc3MgKTtcXG5cXHQjaWZkZWYgVVNFX0lSSURFU0NFTkNFXFxuXFx0XFx0dmVjMyBGciA9IG1peCggc3BlY3VsYXJDb2xvciwgaXJpZGVzY2VuY2VGMCwgaXJpZGVzY2VuY2UgKTtcXG5cXHQjZWxzZVxcblxcdFxcdHZlYzMgRnIgPSBzcGVjdWxhckNvbG9yO1xcblxcdCNlbmRpZlxcblxcdHZlYzMgRnNzRXNzID0gRnIgKiBmYWIueCArIHNwZWN1bGFyRjkwICogZmFiLnk7XFxuXFx0ZmxvYXQgRXNzID0gZmFiLnggKyBmYWIueTtcXG5cXHRmbG9hdCBFbXMgPSAxLjAgLSBFc3M7XFxuXFx0dmVjMyBGYXZnID0gRnIgKyAoIDEuMCAtIEZyICkgKiAwLjA0NzYxOTtcXHR2ZWMzIEZtcyA9IEZzc0VzcyAqIEZhdmcgLyAoIDEuMCAtIEVtcyAqIEZhdmcgKTtcXG5cXHRzaW5nbGVTY2F0dGVyICs9IEZzc0VzcztcXG5cXHRtdWx0aVNjYXR0ZXIgKz0gRm1zICogRW1zO1xcbn1cXG4jaWYgTlVNX1JFQ1RfQVJFQV9MSUdIVFMgPiAwXFxuXFx0dm9pZCBSRV9EaXJlY3RfUmVjdEFyZWFfUGh5c2ljYWwoIGNvbnN0IGluIFJlY3RBcmVhTGlnaHQgcmVjdEFyZWFMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gUGh5c2ljYWxNYXRlcmlhbCBtYXRlcmlhbCwgaW5vdXQgUmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgKSB7XFxuXFx0XFx0dmVjMyBub3JtYWwgPSBnZW9tZXRyeU5vcm1hbDtcXG5cXHRcXHR2ZWMzIHZpZXdEaXIgPSBnZW9tZXRyeVZpZXdEaXI7XFxuXFx0XFx0dmVjMyBwb3NpdGlvbiA9IGdlb21ldHJ5UG9zaXRpb247XFxuXFx0XFx0dmVjMyBsaWdodFBvcyA9IHJlY3RBcmVhTGlnaHQucG9zaXRpb247XFxuXFx0XFx0dmVjMyBoYWxmV2lkdGggPSByZWN0QXJlYUxpZ2h0LmhhbGZXaWR0aDtcXG5cXHRcXHR2ZWMzIGhhbGZIZWlnaHQgPSByZWN0QXJlYUxpZ2h0LmhhbGZIZWlnaHQ7XFxuXFx0XFx0dmVjMyBsaWdodENvbG9yID0gcmVjdEFyZWFMaWdodC5jb2xvcjtcXG5cXHRcXHRmbG9hdCByb3VnaG5lc3MgPSBtYXRlcmlhbC5yb3VnaG5lc3M7XFxuXFx0XFx0dmVjMyByZWN0Q29vcmRzWyA0IF07XFxuXFx0XFx0cmVjdENvb3Jkc1sgMCBdID0gbGlnaHRQb3MgKyBoYWxmV2lkdGggLSBoYWxmSGVpZ2h0O1xcdFxcdHJlY3RDb29yZHNbIDEgXSA9IGxpZ2h0UG9zIC0gaGFsZldpZHRoIC0gaGFsZkhlaWdodDtcXG5cXHRcXHRyZWN0Q29vcmRzWyAyIF0gPSBsaWdodFBvcyAtIGhhbGZXaWR0aCArIGhhbGZIZWlnaHQ7XFxuXFx0XFx0cmVjdENvb3Jkc1sgMyBdID0gbGlnaHRQb3MgKyBoYWxmV2lkdGggKyBoYWxmSGVpZ2h0O1xcblxcdFxcdHZlYzIgdXYgPSBMVENfVXYoIG5vcm1hbCwgdmlld0Rpciwgcm91Z2huZXNzICk7XFxuXFx0XFx0dmVjNCB0MSA9IHRleHR1cmUyRCggbHRjXzEsIHV2ICk7XFxuXFx0XFx0dmVjNCB0MiA9IHRleHR1cmUyRCggbHRjXzIsIHV2ICk7XFxuXFx0XFx0bWF0MyBtSW52ID0gbWF0MyhcXG5cXHRcXHRcXHR2ZWMzKCB0MS54LCAwLCB0MS55ICksXFxuXFx0XFx0XFx0dmVjMyggICAgMCwgMSwgICAgMCApLFxcblxcdFxcdFxcdHZlYzMoIHQxLnosIDAsIHQxLncgKVxcblxcdFxcdCk7XFxuXFx0XFx0dmVjMyBmcmVzbmVsID0gKCBtYXRlcmlhbC5zcGVjdWxhckNvbG9yICogdDIueCArICggdmVjMyggMS4wICkgLSBtYXRlcmlhbC5zcGVjdWxhckNvbG9yICkgKiB0Mi55ICk7XFxuXFx0XFx0cmVmbGVjdGVkTGlnaHQuZGlyZWN0U3BlY3VsYXIgKz0gbGlnaHRDb2xvciAqIGZyZXNuZWwgKiBMVENfRXZhbHVhdGUoIG5vcm1hbCwgdmlld0RpciwgcG9zaXRpb24sIG1JbnYsIHJlY3RDb29yZHMgKTtcXG5cXHRcXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICs9IGxpZ2h0Q29sb3IgKiBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKiBMVENfRXZhbHVhdGUoIG5vcm1hbCwgdmlld0RpciwgcG9zaXRpb24sIG1hdDMoIDEuMCApLCByZWN0Q29vcmRzICk7XFxuXFx0fVxcbiNlbmRpZlxcbnZvaWQgUkVfRGlyZWN0X1BoeXNpY2FsKCBjb25zdCBpbiBJbmNpZGVudExpZ2h0IGRpcmVjdExpZ2h0LCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBQaHlzaWNhbE1hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcXG5cXHRmbG9hdCBkb3ROTCA9IHNhdHVyYXRlKCBkb3QoIGdlb21ldHJ5Tm9ybWFsLCBkaXJlY3RMaWdodC5kaXJlY3Rpb24gKSApO1xcblxcdHZlYzMgaXJyYWRpYW5jZSA9IGRvdE5MICogZGlyZWN0TGlnaHQuY29sb3I7XFxuXFx0I2lmZGVmIFVTRV9DTEVBUkNPQVRcXG5cXHRcXHRmbG9hdCBkb3ROTGNjID0gc2F0dXJhdGUoIGRvdCggZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiApICk7XFxuXFx0XFx0dmVjMyBjY0lycmFkaWFuY2UgPSBkb3ROTGNjICogZGlyZWN0TGlnaHQuY29sb3I7XFxuXFx0XFx0Y2xlYXJjb2F0U3BlY3VsYXJEaXJlY3QgKz0gY2NJcnJhZGlhbmNlICogQlJERl9HR1hfQ2xlYXJjb2F0KCBkaXJlY3RMaWdodC5kaXJlY3Rpb24sIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIG1hdGVyaWFsICk7XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIFVTRV9TSEVFTlxcblxcdFxcdHNoZWVuU3BlY3VsYXJEaXJlY3QgKz0gaXJyYWRpYW5jZSAqIEJSREZfU2hlZW4oIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiwgZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeU5vcm1hbCwgbWF0ZXJpYWwuc2hlZW5Db2xvciwgbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3MgKTtcXG5cXHQjZW5kaWZcXG5cXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3RTcGVjdWxhciArPSBpcnJhZGlhbmNlICogQlJERl9HR1goIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiwgZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeU5vcm1hbCwgbWF0ZXJpYWwgKTtcXG5cXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xcbn1cXG52b2lkIFJFX0luZGlyZWN0RGlmZnVzZV9QaHlzaWNhbCggY29uc3QgaW4gdmVjMyBpcnJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBQaHlzaWNhbE1hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcXG5cXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKz0gaXJyYWRpYW5jZSAqIEJSREZfTGFtYmVydCggbWF0ZXJpYWwuZGlmZnVzZUNvbG9yICk7XFxufVxcbnZvaWQgUkVfSW5kaXJlY3RTcGVjdWxhcl9QaHlzaWNhbCggY29uc3QgaW4gdmVjMyByYWRpYW5jZSwgY29uc3QgaW4gdmVjMyBpcnJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGNsZWFyY29hdFJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBQaHlzaWNhbE1hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCkge1xcblxcdCNpZmRlZiBVU0VfQ0xFQVJDT0FUXFxuXFx0XFx0Y2xlYXJjb2F0U3BlY3VsYXJJbmRpcmVjdCArPSBjbGVhcmNvYXRSYWRpYW5jZSAqIEVudmlyb25tZW50QlJERiggZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgbWF0ZXJpYWwuY2xlYXJjb2F0RjAsIG1hdGVyaWFsLmNsZWFyY29hdEY5MCwgbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzICk7XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIFVTRV9TSEVFTlxcblxcdFxcdHNoZWVuU3BlY3VsYXJJbmRpcmVjdCArPSBpcnJhZGlhbmNlICogbWF0ZXJpYWwuc2hlZW5Db2xvciAqIElCTFNoZWVuQlJERiggZ2VvbWV0cnlOb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3MgKTtcXG5cXHQjZW5kaWZcXG5cXHR2ZWMzIHNpbmdsZVNjYXR0ZXJpbmcgPSB2ZWMzKCAwLjAgKTtcXG5cXHR2ZWMzIG11bHRpU2NhdHRlcmluZyA9IHZlYzMoIDAuMCApO1xcblxcdHZlYzMgY29zaW5lV2VpZ2h0ZWRJcnJhZGlhbmNlID0gaXJyYWRpYW5jZSAqIFJFQ0lQUk9DQUxfUEk7XFxuXFx0I2lmZGVmIFVTRV9JUklERVNDRU5DRVxcblxcdFxcdGNvbXB1dGVNdWx0aXNjYXR0ZXJpbmdJcmlkZXNjZW5jZSggZ2VvbWV0cnlOb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciwgbWF0ZXJpYWwuc3BlY3VsYXJGOTAsIG1hdGVyaWFsLmlyaWRlc2NlbmNlLCBtYXRlcmlhbC5pcmlkZXNjZW5jZUZyZXNuZWwsIG1hdGVyaWFsLnJvdWdobmVzcywgc2luZ2xlU2NhdHRlcmluZywgbXVsdGlTY2F0dGVyaW5nICk7XFxuXFx0I2Vsc2VcXG5cXHRcXHRjb21wdXRlTXVsdGlzY2F0dGVyaW5nKCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBtYXRlcmlhbC5zcGVjdWxhckNvbG9yLCBtYXRlcmlhbC5zcGVjdWxhckY5MCwgbWF0ZXJpYWwucm91Z2huZXNzLCBzaW5nbGVTY2F0dGVyaW5nLCBtdWx0aVNjYXR0ZXJpbmcgKTtcXG5cXHQjZW5kaWZcXG5cXHR2ZWMzIHRvdGFsU2NhdHRlcmluZyA9IHNpbmdsZVNjYXR0ZXJpbmcgKyBtdWx0aVNjYXR0ZXJpbmc7XFxuXFx0dmVjMyBkaWZmdXNlID0gbWF0ZXJpYWwuZGlmZnVzZUNvbG9yICogKCAxLjAgLSBtYXgoIG1heCggdG90YWxTY2F0dGVyaW5nLnIsIHRvdGFsU2NhdHRlcmluZy5nICksIHRvdGFsU2NhdHRlcmluZy5iICkgKTtcXG5cXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdFNwZWN1bGFyICs9IHJhZGlhbmNlICogc2luZ2xlU2NhdHRlcmluZztcXG5cXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdFNwZWN1bGFyICs9IG11bHRpU2NhdHRlcmluZyAqIGNvc2luZVdlaWdodGVkSXJyYWRpYW5jZTtcXG5cXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKz0gZGlmZnVzZSAqIGNvc2luZVdlaWdodGVkSXJyYWRpYW5jZTtcXG59XFxuI2RlZmluZSBSRV9EaXJlY3RcXHRcXHRcXHRcXHRSRV9EaXJlY3RfUGh5c2ljYWxcXG4jZGVmaW5lIFJFX0RpcmVjdF9SZWN0QXJlYVxcdFxcdFJFX0RpcmVjdF9SZWN0QXJlYV9QaHlzaWNhbFxcbiNkZWZpbmUgUkVfSW5kaXJlY3REaWZmdXNlXFx0XFx0UkVfSW5kaXJlY3REaWZmdXNlX1BoeXNpY2FsXFxuI2RlZmluZSBSRV9JbmRpcmVjdFNwZWN1bGFyXFx0XFx0UkVfSW5kaXJlY3RTcGVjdWxhcl9QaHlzaWNhbFxcbmZsb2F0IGNvbXB1dGVTcGVjdWxhck9jY2x1c2lvbiggY29uc3QgaW4gZmxvYXQgZG90TlYsIGNvbnN0IGluIGZsb2F0IGFtYmllbnRPY2NsdXNpb24sIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcyApIHtcXG5cXHRyZXR1cm4gc2F0dXJhdGUoIHBvdyggZG90TlYgKyBhbWJpZW50T2NjbHVzaW9uLCBleHAyKCAtIDE2LjAgKiByb3VnaG5lc3MgLSAxLjAgKSApIC0gMS4wICsgYW1iaWVudE9jY2x1c2lvbiApO1xcbn1cIjtcblxudmFyIGxpZ2h0c19mcmFnbWVudF9iZWdpbiA9IFwiXFxudmVjMyBnZW9tZXRyeVBvc2l0aW9uID0gLSB2Vmlld1Bvc2l0aW9uO1xcbnZlYzMgZ2VvbWV0cnlOb3JtYWwgPSBub3JtYWw7XFxudmVjMyBnZW9tZXRyeVZpZXdEaXIgPSAoIGlzT3J0aG9ncmFwaGljICkgPyB2ZWMzKCAwLCAwLCAxICkgOiBub3JtYWxpemUoIHZWaWV3UG9zaXRpb24gKTtcXG52ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsID0gdmVjMyggMC4wICk7XFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRcXG5cXHRnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCA9IGNsZWFyY29hdE5vcm1hbDtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFXFxuXFx0ZmxvYXQgZG90TlZpID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIgKSApO1xcblxcdGlmICggbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3MgPT0gMC4wICkge1xcblxcdFxcdG1hdGVyaWFsLmlyaWRlc2NlbmNlID0gMC4wO1xcblxcdH0gZWxzZSB7XFxuXFx0XFx0bWF0ZXJpYWwuaXJpZGVzY2VuY2UgPSBzYXR1cmF0ZSggbWF0ZXJpYWwuaXJpZGVzY2VuY2UgKTtcXG5cXHR9XFxuXFx0aWYgKCBtYXRlcmlhbC5pcmlkZXNjZW5jZSA+IDAuMCApIHtcXG5cXHRcXHRtYXRlcmlhbC5pcmlkZXNjZW5jZUZyZXNuZWwgPSBldmFsSXJpZGVzY2VuY2UoIDEuMCwgbWF0ZXJpYWwuaXJpZGVzY2VuY2VJT1IsIGRvdE5WaSwgbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3MsIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgKTtcXG5cXHRcXHRtYXRlcmlhbC5pcmlkZXNjZW5jZUYwID0gU2NobGlja190b19GMCggbWF0ZXJpYWwuaXJpZGVzY2VuY2VGcmVzbmVsLCAxLjAsIGRvdE5WaSApO1xcblxcdH1cXG4jZW5kaWZcXG5JbmNpZGVudExpZ2h0IGRpcmVjdExpZ2h0O1xcbiNpZiAoIE5VTV9QT0lOVF9MSUdIVFMgPiAwICkgJiYgZGVmaW5lZCggUkVfRGlyZWN0IClcXG5cXHRQb2ludExpZ2h0IHBvaW50TGlnaHQ7XFxuXFx0I2lmIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKSAmJiBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHRQb2ludExpZ2h0U2hhZG93IHBvaW50TGlnaHRTaGFkb3c7XFxuXFx0I2VuZGlmXFxuXFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxcblxcdGZvciAoIGludCBpID0gMDsgaSA8IE5VTV9QT0lOVF9MSUdIVFM7IGkgKysgKSB7XFxuXFx0XFx0cG9pbnRMaWdodCA9IHBvaW50TGlnaHRzWyBpIF07XFxuXFx0XFx0Z2V0UG9pbnRMaWdodEluZm8oIHBvaW50TGlnaHQsIGdlb21ldHJ5UG9zaXRpb24sIGRpcmVjdExpZ2h0ICk7XFxuXFx0XFx0I2lmIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKSAmJiAoIFVOUk9MTEVEX0xPT1BfSU5ERVggPCBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUyApXFxuXFx0XFx0cG9pbnRMaWdodFNoYWRvdyA9IHBvaW50TGlnaHRTaGFkb3dzWyBpIF07XFxuXFx0XFx0ZGlyZWN0TGlnaHQuY29sb3IgKj0gKCBkaXJlY3RMaWdodC52aXNpYmxlICYmIHJlY2VpdmVTaGFkb3cgKSA/IGdldFBvaW50U2hhZG93KCBwb2ludFNoYWRvd01hcFsgaSBdLCBwb2ludExpZ2h0U2hhZG93LnNoYWRvd01hcFNpemUsIHBvaW50TGlnaHRTaGFkb3cuc2hhZG93SW50ZW5zaXR5LCBwb2ludExpZ2h0U2hhZG93LnNoYWRvd0JpYXMsIHBvaW50TGlnaHRTaGFkb3cuc2hhZG93UmFkaXVzLCB2UG9pbnRTaGFkb3dDb29yZFsgaSBdLCBwb2ludExpZ2h0U2hhZG93LnNoYWRvd0NhbWVyYU5lYXIsIHBvaW50TGlnaHRTaGFkb3cuc2hhZG93Q2FtZXJhRmFyICkgOiAxLjA7XFxuXFx0XFx0I2VuZGlmXFxuXFx0XFx0UkVfRGlyZWN0KCBkaXJlY3RMaWdodCwgZ2VvbWV0cnlQb3NpdGlvbiwgZ2VvbWV0cnlOb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIG1hdGVyaWFsLCByZWZsZWN0ZWRMaWdodCApO1xcblxcdH1cXG5cXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxcbiNlbmRpZlxcbiNpZiAoIE5VTV9TUE9UX0xJR0hUUyA+IDAgKSAmJiBkZWZpbmVkKCBSRV9EaXJlY3QgKVxcblxcdFNwb3RMaWdodCBzcG90TGlnaHQ7XFxuXFx0dmVjNCBzcG90Q29sb3I7XFxuXFx0dmVjMyBzcG90TGlnaHRDb29yZDtcXG5cXHRib29sIGluU3BvdExpZ2h0TWFwO1xcblxcdCNpZiBkZWZpbmVkKCBVU0VfU0hBRE9XTUFQICkgJiYgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHRTcG90TGlnaHRTaGFkb3cgc3BvdExpZ2h0U2hhZG93O1xcblxcdCNlbmRpZlxcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcXG5cXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fU1BPVF9MSUdIVFM7IGkgKysgKSB7XFxuXFx0XFx0c3BvdExpZ2h0ID0gc3BvdExpZ2h0c1sgaSBdO1xcblxcdFxcdGdldFNwb3RMaWdodEluZm8oIHNwb3RMaWdodCwgZ2VvbWV0cnlQb3NpdGlvbiwgZGlyZWN0TGlnaHQgKTtcXG5cXHRcXHQjaWYgKCBVTlJPTExFRF9MT09QX0lOREVYIDwgTlVNX1NQT1RfTElHSFRfU0hBRE9XU19XSVRIX01BUFMgKVxcblxcdFxcdCNkZWZpbmUgU1BPVF9MSUdIVF9NQVBfSU5ERVggVU5ST0xMRURfTE9PUF9JTkRFWFxcblxcdFxcdCNlbGlmICggVU5ST0xMRURfTE9PUF9JTkRFWCA8IE5VTV9TUE9UX0xJR0hUX1NIQURPV1MgKVxcblxcdFxcdCNkZWZpbmUgU1BPVF9MSUdIVF9NQVBfSU5ERVggTlVNX1NQT1RfTElHSFRfTUFQU1xcblxcdFxcdCNlbHNlXFxuXFx0XFx0I2RlZmluZSBTUE9UX0xJR0hUX01BUF9JTkRFWCAoIFVOUk9MTEVEX0xPT1BfSU5ERVggLSBOVU1fU1BPVF9MSUdIVF9TSEFET1dTICsgTlVNX1NQT1RfTElHSFRfU0hBRE9XU19XSVRIX01BUFMgKVxcblxcdFxcdCNlbmRpZlxcblxcdFxcdCNpZiAoIFNQT1RfTElHSFRfTUFQX0lOREVYIDwgTlVNX1NQT1RfTElHSFRfTUFQUyApXFxuXFx0XFx0XFx0c3BvdExpZ2h0Q29vcmQgPSB2U3BvdExpZ2h0Q29vcmRbIGkgXS54eXogLyB2U3BvdExpZ2h0Q29vcmRbIGkgXS53O1xcblxcdFxcdFxcdGluU3BvdExpZ2h0TWFwID0gYWxsKCBsZXNzVGhhbiggYWJzKCBzcG90TGlnaHRDb29yZCAqIDIuIC0gMS4gKSwgdmVjMyggMS4wICkgKSApO1xcblxcdFxcdFxcdHNwb3RDb2xvciA9IHRleHR1cmUyRCggc3BvdExpZ2h0TWFwWyBTUE9UX0xJR0hUX01BUF9JTkRFWCBdLCBzcG90TGlnaHRDb29yZC54eSApO1xcblxcdFxcdFxcdGRpcmVjdExpZ2h0LmNvbG9yID0gaW5TcG90TGlnaHRNYXAgPyBkaXJlY3RMaWdodC5jb2xvciAqIHNwb3RDb2xvci5yZ2IgOiBkaXJlY3RMaWdodC5jb2xvcjtcXG5cXHRcXHQjZW5kaWZcXG5cXHRcXHQjdW5kZWYgU1BPVF9MSUdIVF9NQVBfSU5ERVhcXG5cXHRcXHQjaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmICggVU5ST0xMRURfTE9PUF9JTkRFWCA8IE5VTV9TUE9UX0xJR0hUX1NIQURPV1MgKVxcblxcdFxcdHNwb3RMaWdodFNoYWRvdyA9IHNwb3RMaWdodFNoYWRvd3NbIGkgXTtcXG5cXHRcXHRkaXJlY3RMaWdodC5jb2xvciAqPSAoIGRpcmVjdExpZ2h0LnZpc2libGUgJiYgcmVjZWl2ZVNoYWRvdyApID8gZ2V0U2hhZG93KCBzcG90U2hhZG93TWFwWyBpIF0sIHNwb3RMaWdodFNoYWRvdy5zaGFkb3dNYXBTaXplLCBzcG90TGlnaHRTaGFkb3cuc2hhZG93SW50ZW5zaXR5LCBzcG90TGlnaHRTaGFkb3cuc2hhZG93Qmlhcywgc3BvdExpZ2h0U2hhZG93LnNoYWRvd1JhZGl1cywgdlNwb3RMaWdodENvb3JkWyBpIF0gKSA6IDEuMDtcXG5cXHRcXHQjZW5kaWZcXG5cXHRcXHRSRV9EaXJlY3QoIGRpcmVjdExpZ2h0LCBnZW9tZXRyeVBvc2l0aW9uLCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgbWF0ZXJpYWwsIHJlZmxlY3RlZExpZ2h0ICk7XFxuXFx0fVxcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXFxuI2VuZGlmXFxuI2lmICggTlVNX0RJUl9MSUdIVFMgPiAwICkgJiYgZGVmaW5lZCggUkVfRGlyZWN0IClcXG5cXHREaXJlY3Rpb25hbExpZ2h0IGRpcmVjdGlvbmFsTGlnaHQ7XFxuXFx0I2lmIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKSAmJiBOVU1fRElSX0xJR0hUX1NIQURPV1MgPiAwXFxuXFx0RGlyZWN0aW9uYWxMaWdodFNoYWRvdyBkaXJlY3Rpb25hbExpZ2h0U2hhZG93O1xcblxcdCNlbmRpZlxcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcXG5cXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fRElSX0xJR0hUUzsgaSArKyApIHtcXG5cXHRcXHRkaXJlY3Rpb25hbExpZ2h0ID0gZGlyZWN0aW9uYWxMaWdodHNbIGkgXTtcXG5cXHRcXHRnZXREaXJlY3Rpb25hbExpZ2h0SW5mbyggZGlyZWN0aW9uYWxMaWdodCwgZGlyZWN0TGlnaHQgKTtcXG5cXHRcXHQjaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmICggVU5ST0xMRURfTE9PUF9JTkRFWCA8IE5VTV9ESVJfTElHSFRfU0hBRE9XUyApXFxuXFx0XFx0ZGlyZWN0aW9uYWxMaWdodFNoYWRvdyA9IGRpcmVjdGlvbmFsTGlnaHRTaGFkb3dzWyBpIF07XFxuXFx0XFx0ZGlyZWN0TGlnaHQuY29sb3IgKj0gKCBkaXJlY3RMaWdodC52aXNpYmxlICYmIHJlY2VpdmVTaGFkb3cgKSA/IGdldFNoYWRvdyggZGlyZWN0aW9uYWxTaGFkb3dNYXBbIGkgXSwgZGlyZWN0aW9uYWxMaWdodFNoYWRvdy5zaGFkb3dNYXBTaXplLCBkaXJlY3Rpb25hbExpZ2h0U2hhZG93LnNoYWRvd0ludGVuc2l0eSwgZGlyZWN0aW9uYWxMaWdodFNoYWRvdy5zaGFkb3dCaWFzLCBkaXJlY3Rpb25hbExpZ2h0U2hhZG93LnNoYWRvd1JhZGl1cywgdkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIGkgXSApIDogMS4wO1xcblxcdFxcdCNlbmRpZlxcblxcdFxcdFJFX0RpcmVjdCggZGlyZWN0TGlnaHQsIGdlb21ldHJ5UG9zaXRpb24sIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCwgcmVmbGVjdGVkTGlnaHQgKTtcXG5cXHR9XFxuXFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcXG4jZW5kaWZcXG4jaWYgKCBOVU1fUkVDVF9BUkVBX0xJR0hUUyA+IDAgKSAmJiBkZWZpbmVkKCBSRV9EaXJlY3RfUmVjdEFyZWEgKVxcblxcdFJlY3RBcmVhTGlnaHQgcmVjdEFyZWFMaWdodDtcXG5cXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XFxuXFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1JFQ1RfQVJFQV9MSUdIVFM7IGkgKysgKSB7XFxuXFx0XFx0cmVjdEFyZWFMaWdodCA9IHJlY3RBcmVhTGlnaHRzWyBpIF07XFxuXFx0XFx0UkVfRGlyZWN0X1JlY3RBcmVhKCByZWN0QXJlYUxpZ2h0LCBnZW9tZXRyeVBvc2l0aW9uLCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgbWF0ZXJpYWwsIHJlZmxlY3RlZExpZ2h0ICk7XFxuXFx0fVxcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXFxuI2VuZGlmXFxuI2lmIGRlZmluZWQoIFJFX0luZGlyZWN0RGlmZnVzZSApXFxuXFx0dmVjMyBpYmxJcnJhZGlhbmNlID0gdmVjMyggMC4wICk7XFxuXFx0dmVjMyBpcnJhZGlhbmNlID0gZ2V0QW1iaWVudExpZ2h0SXJyYWRpYW5jZSggYW1iaWVudExpZ2h0Q29sb3IgKTtcXG5cXHQjaWYgZGVmaW5lZCggVVNFX0xJR0hUX1BST0JFUyApXFxuXFx0XFx0aXJyYWRpYW5jZSArPSBnZXRMaWdodFByb2JlSXJyYWRpYW5jZSggbGlnaHRQcm9iZSwgZ2VvbWV0cnlOb3JtYWwgKTtcXG5cXHQjZW5kaWZcXG5cXHQjaWYgKCBOVU1fSEVNSV9MSUdIVFMgPiAwIClcXG5cXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XFxuXFx0XFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX0hFTUlfTElHSFRTOyBpICsrICkge1xcblxcdFxcdFxcdGlycmFkaWFuY2UgKz0gZ2V0SGVtaXNwaGVyZUxpZ2h0SXJyYWRpYW5jZSggaGVtaXNwaGVyZUxpZ2h0c1sgaSBdLCBnZW9tZXRyeU5vcm1hbCApO1xcblxcdFxcdH1cXG5cXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxcblxcdCNlbmRpZlxcbiNlbmRpZlxcbiNpZiBkZWZpbmVkKCBSRV9JbmRpcmVjdFNwZWN1bGFyIClcXG5cXHR2ZWMzIHJhZGlhbmNlID0gdmVjMyggMC4wICk7XFxuXFx0dmVjMyBjbGVhcmNvYXRSYWRpYW5jZSA9IHZlYzMoIDAuMCApO1xcbiNlbmRpZlwiO1xuXG52YXIgbGlnaHRzX2ZyYWdtZW50X21hcHMgPSBcIiNpZiBkZWZpbmVkKCBSRV9JbmRpcmVjdERpZmZ1c2UgKVxcblxcdCNpZmRlZiBVU0VfTElHSFRNQVBcXG5cXHRcXHR2ZWM0IGxpZ2h0TWFwVGV4ZWwgPSB0ZXh0dXJlMkQoIGxpZ2h0TWFwLCB2TGlnaHRNYXBVdiApO1xcblxcdFxcdHZlYzMgbGlnaHRNYXBJcnJhZGlhbmNlID0gbGlnaHRNYXBUZXhlbC5yZ2IgKiBsaWdodE1hcEludGVuc2l0eTtcXG5cXHRcXHRpcnJhZGlhbmNlICs9IGxpZ2h0TWFwSXJyYWRpYW5jZTtcXG5cXHQjZW5kaWZcXG5cXHQjaWYgZGVmaW5lZCggVVNFX0VOVk1BUCApICYmIGRlZmluZWQoIFNUQU5EQVJEICkgJiYgZGVmaW5lZCggRU5WTUFQX1RZUEVfQ1VCRV9VViApXFxuXFx0XFx0aWJsSXJyYWRpYW5jZSArPSBnZXRJQkxJcnJhZGlhbmNlKCBnZW9tZXRyeU5vcm1hbCApO1xcblxcdCNlbmRpZlxcbiNlbmRpZlxcbiNpZiBkZWZpbmVkKCBVU0VfRU5WTUFQICkgJiYgZGVmaW5lZCggUkVfSW5kaXJlY3RTcGVjdWxhciApXFxuXFx0I2lmZGVmIFVTRV9BTklTT1RST1BZXFxuXFx0XFx0cmFkaWFuY2UgKz0gZ2V0SUJMQW5pc290cm9weVJhZGlhbmNlKCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Tm9ybWFsLCBtYXRlcmlhbC5yb3VnaG5lc3MsIG1hdGVyaWFsLmFuaXNvdHJvcHlCLCBtYXRlcmlhbC5hbmlzb3Ryb3B5ICk7XFxuXFx0I2Vsc2VcXG5cXHRcXHRyYWRpYW5jZSArPSBnZXRJQkxSYWRpYW5jZSggZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeU5vcm1hbCwgbWF0ZXJpYWwucm91Z2huZXNzICk7XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIFVTRV9DTEVBUkNPQVRcXG5cXHRcXHRjbGVhcmNvYXRSYWRpYW5jZSArPSBnZXRJQkxSYWRpYW5jZSggZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzICk7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXCI7XG5cbnZhciBsaWdodHNfZnJhZ21lbnRfZW5kID0gXCIjaWYgZGVmaW5lZCggUkVfSW5kaXJlY3REaWZmdXNlIClcXG5cXHRSRV9JbmRpcmVjdERpZmZ1c2UoIGlycmFkaWFuY2UsIGdlb21ldHJ5UG9zaXRpb24sIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCwgcmVmbGVjdGVkTGlnaHQgKTtcXG4jZW5kaWZcXG4jaWYgZGVmaW5lZCggUkVfSW5kaXJlY3RTcGVjdWxhciApXFxuXFx0UkVfSW5kaXJlY3RTcGVjdWxhciggcmFkaWFuY2UsIGlibElycmFkaWFuY2UsIGNsZWFyY29hdFJhZGlhbmNlLCBnZW9tZXRyeVBvc2l0aW9uLCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgbWF0ZXJpYWwsIHJlZmxlY3RlZExpZ2h0ICk7XFxuI2VuZGlmXCI7XG5cbnZhciBsb2dkZXB0aGJ1Zl9mcmFnbWVudCA9IFwiI2lmIGRlZmluZWQoIFVTRV9MT0dERVBUSEJVRiApXFxuXFx0Z2xfRnJhZ0RlcHRoID0gdklzUGVyc3BlY3RpdmUgPT0gMC4wID8gZ2xfRnJhZ0Nvb3JkLnogOiBsb2cyKCB2RnJhZ0RlcHRoICkgKiBsb2dEZXB0aEJ1ZkZDICogMC41O1xcbiNlbmRpZlwiO1xuXG52YXIgbG9nZGVwdGhidWZfcGFyc19mcmFnbWVudCA9IFwiI2lmIGRlZmluZWQoIFVTRV9MT0dERVBUSEJVRiApXFxuXFx0dW5pZm9ybSBmbG9hdCBsb2dEZXB0aEJ1ZkZDO1xcblxcdHZhcnlpbmcgZmxvYXQgdkZyYWdEZXB0aDtcXG5cXHR2YXJ5aW5nIGZsb2F0IHZJc1BlcnNwZWN0aXZlO1xcbiNlbmRpZlwiO1xuXG52YXIgbG9nZGVwdGhidWZfcGFyc192ZXJ0ZXggPSBcIiNpZmRlZiBVU0VfTE9HREVQVEhCVUZcXG5cXHR2YXJ5aW5nIGZsb2F0IHZGcmFnRGVwdGg7XFxuXFx0dmFyeWluZyBmbG9hdCB2SXNQZXJzcGVjdGl2ZTtcXG4jZW5kaWZcIjtcblxudmFyIGxvZ2RlcHRoYnVmX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9MT0dERVBUSEJVRlxcblxcdHZGcmFnRGVwdGggPSAxLjAgKyBnbF9Qb3NpdGlvbi53O1xcblxcdHZJc1BlcnNwZWN0aXZlID0gZmxvYXQoIGlzUGVyc3BlY3RpdmVNYXRyaXgoIHByb2plY3Rpb25NYXRyaXggKSApO1xcbiNlbmRpZlwiO1xuXG52YXIgbWFwX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX01BUFxcblxcdHZlYzQgc2FtcGxlZERpZmZ1c2VDb2xvciA9IHRleHR1cmUyRCggbWFwLCB2TWFwVXYgKTtcXG5cXHQjaWZkZWYgREVDT0RFX1ZJREVPX1RFWFRVUkVcXG5cXHRcXHRzYW1wbGVkRGlmZnVzZUNvbG9yID0gdmVjNCggbWl4KCBwb3coIHNhbXBsZWREaWZmdXNlQ29sb3IucmdiICogMC45NDc4NjcyOTg2ICsgdmVjMyggMC4wNTIxMzI3MDE0ICksIHZlYzMoIDIuNCApICksIHNhbXBsZWREaWZmdXNlQ29sb3IucmdiICogMC4wNzczOTkzODA4LCB2ZWMzKCBsZXNzVGhhbkVxdWFsKCBzYW1wbGVkRGlmZnVzZUNvbG9yLnJnYiwgdmVjMyggMC4wNDA0NSApICkgKSApLCBzYW1wbGVkRGlmZnVzZUNvbG9yLncgKTtcXG5cXHRcXG5cXHQjZW5kaWZcXG5cXHRkaWZmdXNlQ29sb3IgKj0gc2FtcGxlZERpZmZ1c2VDb2xvcjtcXG4jZW5kaWZcIjtcblxudmFyIG1hcF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX01BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIG1hcDtcXG4jZW5kaWZcIjtcblxudmFyIG1hcF9wYXJ0aWNsZV9mcmFnbWVudCA9IFwiI2lmIGRlZmluZWQoIFVTRV9NQVAgKSB8fCBkZWZpbmVkKCBVU0VfQUxQSEFNQVAgKVxcblxcdCNpZiBkZWZpbmVkKCBVU0VfUE9JTlRTX1VWIClcXG5cXHRcXHR2ZWMyIHV2ID0gdlV2O1xcblxcdCNlbHNlXFxuXFx0XFx0dmVjMiB1diA9ICggdXZUcmFuc2Zvcm0gKiB2ZWMzKCBnbF9Qb2ludENvb3JkLngsIDEuMCAtIGdsX1BvaW50Q29vcmQueSwgMSApICkueHk7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9NQVBcXG5cXHRkaWZmdXNlQ29sb3IgKj0gdGV4dHVyZTJEKCBtYXAsIHV2ICk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9BTFBIQU1BUFxcblxcdGRpZmZ1c2VDb2xvci5hICo9IHRleHR1cmUyRCggYWxwaGFNYXAsIHV2ICkuZztcXG4jZW5kaWZcIjtcblxudmFyIG1hcF9wYXJ0aWNsZV9wYXJzX2ZyYWdtZW50ID0gXCIjaWYgZGVmaW5lZCggVVNFX1BPSU5UU19VViApXFxuXFx0dmFyeWluZyB2ZWMyIHZVdjtcXG4jZWxzZVxcblxcdCNpZiBkZWZpbmVkKCBVU0VfTUFQICkgfHwgZGVmaW5lZCggVVNFX0FMUEhBTUFQIClcXG5cXHRcXHR1bmlmb3JtIG1hdDMgdXZUcmFuc2Zvcm07XFxuXFx0I2VuZGlmXFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9NQVBcXG5cXHR1bmlmb3JtIHNhbXBsZXIyRCBtYXA7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9BTFBIQU1BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGFscGhhTWFwO1xcbiNlbmRpZlwiO1xuXG52YXIgbWV0YWxuZXNzbWFwX2ZyYWdtZW50ID0gXCJmbG9hdCBtZXRhbG5lc3NGYWN0b3IgPSBtZXRhbG5lc3M7XFxuI2lmZGVmIFVTRV9NRVRBTE5FU1NNQVBcXG5cXHR2ZWM0IHRleGVsTWV0YWxuZXNzID0gdGV4dHVyZTJEKCBtZXRhbG5lc3NNYXAsIHZNZXRhbG5lc3NNYXBVdiApO1xcblxcdG1ldGFsbmVzc0ZhY3RvciAqPSB0ZXhlbE1ldGFsbmVzcy5iO1xcbiNlbmRpZlwiO1xuXG52YXIgbWV0YWxuZXNzbWFwX3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfTUVUQUxORVNTTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgbWV0YWxuZXNzTWFwO1xcbiNlbmRpZlwiO1xuXG52YXIgbW9ycGhpbnN0YW5jZV92ZXJ0ZXggPSBcIiNpZmRlZiBVU0VfSU5TVEFOQ0lOR19NT1JQSFxcblxcdGZsb2F0IG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgTU9SUEhUQVJHRVRTX0NPVU5UIF07XFxuXFx0ZmxvYXQgbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlID0gdGV4ZWxGZXRjaCggbW9ycGhUZXh0dXJlLCBpdmVjMiggMCwgZ2xfSW5zdGFuY2VJRCApLCAwICkucjtcXG5cXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBNT1JQSFRBUkdFVFNfQ09VTlQ7IGkgKysgKSB7XFxuXFx0XFx0bW9ycGhUYXJnZXRJbmZsdWVuY2VzW2ldID0gIHRleGVsRmV0Y2goIG1vcnBoVGV4dHVyZSwgaXZlYzIoIGkgKyAxLCBnbF9JbnN0YW5jZUlEICksIDAgKS5yO1xcblxcdH1cXG4jZW5kaWZcIjtcblxudmFyIG1vcnBoY29sb3JfdmVydGV4ID0gXCIjaWYgZGVmaW5lZCggVVNFX01PUlBIQ09MT1JTIClcXG5cXHR2Q29sb3IgKj0gbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlO1xcblxcdGZvciAoIGludCBpID0gMDsgaSA8IE1PUlBIVEFSR0VUU19DT1VOVDsgaSArKyApIHtcXG5cXHRcXHQjaWYgZGVmaW5lZCggVVNFX0NPTE9SX0FMUEhBIClcXG5cXHRcXHRcXHRpZiAoIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgaSBdICE9IDAuMCApIHZDb2xvciArPSBnZXRNb3JwaCggZ2xfVmVydGV4SUQsIGksIDIgKSAqIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgaSBdO1xcblxcdFxcdCNlbGlmIGRlZmluZWQoIFVTRV9DT0xPUiApXFxuXFx0XFx0XFx0aWYgKCBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIGkgXSAhPSAwLjAgKSB2Q29sb3IgKz0gZ2V0TW9ycGgoIGdsX1ZlcnRleElELCBpLCAyICkucmdiICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF07XFxuXFx0XFx0I2VuZGlmXFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgbW9ycGhub3JtYWxfdmVydGV4ID0gXCIjaWZkZWYgVVNFX01PUlBITk9STUFMU1xcblxcdG9iamVjdE5vcm1hbCAqPSBtb3JwaFRhcmdldEJhc2VJbmZsdWVuY2U7XFxuXFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTU9SUEhUQVJHRVRTX0NPVU5UOyBpICsrICkge1xcblxcdFxcdGlmICggbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF0gIT0gMC4wICkgb2JqZWN0Tm9ybWFsICs9IGdldE1vcnBoKCBnbF9WZXJ0ZXhJRCwgaSwgMSApLnh5eiAqIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgaSBdO1xcblxcdH1cXG4jZW5kaWZcIjtcblxudmFyIG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4ID0gXCIjaWZkZWYgVVNFX01PUlBIVEFSR0VUU1xcblxcdCNpZm5kZWYgVVNFX0lOU1RBTkNJTkdfTU9SUEhcXG5cXHRcXHR1bmlmb3JtIGZsb2F0IG1vcnBoVGFyZ2V0QmFzZUluZmx1ZW5jZTtcXG5cXHRcXHR1bmlmb3JtIGZsb2F0IG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgTU9SUEhUQVJHRVRTX0NPVU5UIF07XFxuXFx0I2VuZGlmXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkRBcnJheSBtb3JwaFRhcmdldHNUZXh0dXJlO1xcblxcdHVuaWZvcm0gaXZlYzIgbW9ycGhUYXJnZXRzVGV4dHVyZVNpemU7XFxuXFx0dmVjNCBnZXRNb3JwaCggY29uc3QgaW4gaW50IHZlcnRleEluZGV4LCBjb25zdCBpbiBpbnQgbW9ycGhUYXJnZXRJbmRleCwgY29uc3QgaW4gaW50IG9mZnNldCApIHtcXG5cXHRcXHRpbnQgdGV4ZWxJbmRleCA9IHZlcnRleEluZGV4ICogTU9SUEhUQVJHRVRTX1RFWFRVUkVfU1RSSURFICsgb2Zmc2V0O1xcblxcdFxcdGludCB5ID0gdGV4ZWxJbmRleCAvIG1vcnBoVGFyZ2V0c1RleHR1cmVTaXplLng7XFxuXFx0XFx0aW50IHggPSB0ZXhlbEluZGV4IC0geSAqIG1vcnBoVGFyZ2V0c1RleHR1cmVTaXplLng7XFxuXFx0XFx0aXZlYzMgbW9ycGhVViA9IGl2ZWMzKCB4LCB5LCBtb3JwaFRhcmdldEluZGV4ICk7XFxuXFx0XFx0cmV0dXJuIHRleGVsRmV0Y2goIG1vcnBoVGFyZ2V0c1RleHR1cmUsIG1vcnBoVVYsIDAgKTtcXG5cXHR9XFxuI2VuZGlmXCI7XG5cbnZhciBtb3JwaHRhcmdldF92ZXJ0ZXggPSBcIiNpZmRlZiBVU0VfTU9SUEhUQVJHRVRTXFxuXFx0dHJhbnNmb3JtZWQgKj0gbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlO1xcblxcdGZvciAoIGludCBpID0gMDsgaSA8IE1PUlBIVEFSR0VUU19DT1VOVDsgaSArKyApIHtcXG5cXHRcXHRpZiAoIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgaSBdICE9IDAuMCApIHRyYW5zZm9ybWVkICs9IGdldE1vcnBoKCBnbF9WZXJ0ZXhJRCwgaSwgMCApLnh5eiAqIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgaSBdO1xcblxcdH1cXG4jZW5kaWZcIjtcblxudmFyIG5vcm1hbF9mcmFnbWVudF9iZWdpbiA9IFwiZmxvYXQgZmFjZURpcmVjdGlvbiA9IGdsX0Zyb250RmFjaW5nID8gMS4wIDogLSAxLjA7XFxuI2lmZGVmIEZMQVRfU0hBREVEXFxuXFx0dmVjMyBmZHggPSBkRmR4KCB2Vmlld1Bvc2l0aW9uICk7XFxuXFx0dmVjMyBmZHkgPSBkRmR5KCB2Vmlld1Bvc2l0aW9uICk7XFxuXFx0dmVjMyBub3JtYWwgPSBub3JtYWxpemUoIGNyb3NzKCBmZHgsIGZkeSApICk7XFxuI2Vsc2VcXG5cXHR2ZWMzIG5vcm1hbCA9IG5vcm1hbGl6ZSggdk5vcm1hbCApO1xcblxcdCNpZmRlZiBET1VCTEVfU0lERURcXG5cXHRcXHRub3JtYWwgKj0gZmFjZURpcmVjdGlvbjtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcXG4jaWYgZGVmaW5lZCggVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UgKSB8fCBkZWZpbmVkKCBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUCApIHx8IGRlZmluZWQoIFVTRV9BTklTT1RST1BZIClcXG5cXHQjaWZkZWYgVVNFX1RBTkdFTlRcXG5cXHRcXHRtYXQzIHRibiA9IG1hdDMoIG5vcm1hbGl6ZSggdlRhbmdlbnQgKSwgbm9ybWFsaXplKCB2Qml0YW5nZW50ICksIG5vcm1hbCApO1xcblxcdCNlbHNlXFxuXFx0XFx0bWF0MyB0Ym4gPSBnZXRUYW5nZW50RnJhbWUoIC0gdlZpZXdQb3NpdGlvbiwgbm9ybWFsLFxcblxcdFxcdCNpZiBkZWZpbmVkKCBVU0VfTk9STUFMTUFQIClcXG5cXHRcXHRcXHR2Tm9ybWFsTWFwVXZcXG5cXHRcXHQjZWxpZiBkZWZpbmVkKCBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUCApXFxuXFx0XFx0XFx0dkNsZWFyY29hdE5vcm1hbE1hcFV2XFxuXFx0XFx0I2Vsc2VcXG5cXHRcXHRcXHR2VXZcXG5cXHRcXHQjZW5kaWZcXG5cXHRcXHQpO1xcblxcdCNlbmRpZlxcblxcdCNpZiBkZWZpbmVkKCBET1VCTEVfU0lERUQgKSAmJiAhIGRlZmluZWQoIEZMQVRfU0hBREVEIClcXG5cXHRcXHR0Ym5bMF0gKj0gZmFjZURpcmVjdGlvbjtcXG5cXHRcXHR0Ym5bMV0gKj0gZmFjZURpcmVjdGlvbjtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVBcXG5cXHQjaWZkZWYgVVNFX1RBTkdFTlRcXG5cXHRcXHRtYXQzIHRibjIgPSBtYXQzKCBub3JtYWxpemUoIHZUYW5nZW50ICksIG5vcm1hbGl6ZSggdkJpdGFuZ2VudCApLCBub3JtYWwgKTtcXG5cXHQjZWxzZVxcblxcdFxcdG1hdDMgdGJuMiA9IGdldFRhbmdlbnRGcmFtZSggLSB2Vmlld1Bvc2l0aW9uLCBub3JtYWwsIHZDbGVhcmNvYXROb3JtYWxNYXBVdiApO1xcblxcdCNlbmRpZlxcblxcdCNpZiBkZWZpbmVkKCBET1VCTEVfU0lERUQgKSAmJiAhIGRlZmluZWQoIEZMQVRfU0hBREVEIClcXG5cXHRcXHR0Ym4yWzBdICo9IGZhY2VEaXJlY3Rpb247XFxuXFx0XFx0dGJuMlsxXSAqPSBmYWNlRGlyZWN0aW9uO1xcblxcdCNlbmRpZlxcbiNlbmRpZlxcbnZlYzMgbm9uUGVydHVyYmVkTm9ybWFsID0gbm9ybWFsO1wiO1xuXG52YXIgbm9ybWFsX2ZyYWdtZW50X21hcHMgPSBcIiNpZmRlZiBVU0VfTk9STUFMTUFQX09CSkVDVFNQQUNFXFxuXFx0bm9ybWFsID0gdGV4dHVyZTJEKCBub3JtYWxNYXAsIHZOb3JtYWxNYXBVdiApLnh5eiAqIDIuMCAtIDEuMDtcXG5cXHQjaWZkZWYgRkxJUF9TSURFRFxcblxcdFxcdG5vcm1hbCA9IC0gbm9ybWFsO1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBET1VCTEVfU0lERURcXG5cXHRcXHRub3JtYWwgPSBub3JtYWwgKiBmYWNlRGlyZWN0aW9uO1xcblxcdCNlbmRpZlxcblxcdG5vcm1hbCA9IG5vcm1hbGl6ZSggbm9ybWFsTWF0cml4ICogbm9ybWFsICk7XFxuI2VsaWYgZGVmaW5lZCggVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UgKVxcblxcdHZlYzMgbWFwTiA9IHRleHR1cmUyRCggbm9ybWFsTWFwLCB2Tm9ybWFsTWFwVXYgKS54eXogKiAyLjAgLSAxLjA7XFxuXFx0bWFwTi54eSAqPSBub3JtYWxTY2FsZTtcXG5cXHRub3JtYWwgPSBub3JtYWxpemUoIHRibiAqIG1hcE4gKTtcXG4jZWxpZiBkZWZpbmVkKCBVU0VfQlVNUE1BUCApXFxuXFx0bm9ybWFsID0gcGVydHVyYk5vcm1hbEFyYiggLSB2Vmlld1Bvc2l0aW9uLCBub3JtYWwsIGRIZHh5X2Z3ZCgpLCBmYWNlRGlyZWN0aW9uICk7XFxuI2VuZGlmXCI7XG5cbnZhciBub3JtYWxfcGFyc19mcmFnbWVudCA9IFwiI2lmbmRlZiBGTEFUX1NIQURFRFxcblxcdHZhcnlpbmcgdmVjMyB2Tm9ybWFsO1xcblxcdCNpZmRlZiBVU0VfVEFOR0VOVFxcblxcdFxcdHZhcnlpbmcgdmVjMyB2VGFuZ2VudDtcXG5cXHRcXHR2YXJ5aW5nIHZlYzMgdkJpdGFuZ2VudDtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcIjtcblxudmFyIG5vcm1hbF9wYXJzX3ZlcnRleCA9IFwiI2lmbmRlZiBGTEFUX1NIQURFRFxcblxcdHZhcnlpbmcgdmVjMyB2Tm9ybWFsO1xcblxcdCNpZmRlZiBVU0VfVEFOR0VOVFxcblxcdFxcdHZhcnlpbmcgdmVjMyB2VGFuZ2VudDtcXG5cXHRcXHR2YXJ5aW5nIHZlYzMgdkJpdGFuZ2VudDtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcIjtcblxudmFyIG5vcm1hbF92ZXJ0ZXggPSBcIiNpZm5kZWYgRkxBVF9TSEFERURcXG5cXHR2Tm9ybWFsID0gbm9ybWFsaXplKCB0cmFuc2Zvcm1lZE5vcm1hbCApO1xcblxcdCNpZmRlZiBVU0VfVEFOR0VOVFxcblxcdFxcdHZUYW5nZW50ID0gbm9ybWFsaXplKCB0cmFuc2Zvcm1lZFRhbmdlbnQgKTtcXG5cXHRcXHR2Qml0YW5nZW50ID0gbm9ybWFsaXplKCBjcm9zcyggdk5vcm1hbCwgdlRhbmdlbnQgKSAqIHRhbmdlbnQudyApO1xcblxcdCNlbmRpZlxcbiNlbmRpZlwiO1xuXG52YXIgbm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfTk9STUFMTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgbm9ybWFsTWFwO1xcblxcdHVuaWZvcm0gdmVjMiBub3JtYWxTY2FsZTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX05PUk1BTE1BUF9PQkpFQ1RTUEFDRVxcblxcdHVuaWZvcm0gbWF0MyBub3JtYWxNYXRyaXg7XFxuI2VuZGlmXFxuI2lmICEgZGVmaW5lZCAoIFVTRV9UQU5HRU5UICkgJiYgKCBkZWZpbmVkICggVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UgKSB8fCBkZWZpbmVkICggVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVAgKSB8fCBkZWZpbmVkKCBVU0VfQU5JU09UUk9QWSApIClcXG5cXHRtYXQzIGdldFRhbmdlbnRGcmFtZSggdmVjMyBleWVfcG9zLCB2ZWMzIHN1cmZfbm9ybSwgdmVjMiB1diApIHtcXG5cXHRcXHR2ZWMzIHEwID0gZEZkeCggZXllX3Bvcy54eXogKTtcXG5cXHRcXHR2ZWMzIHExID0gZEZkeSggZXllX3Bvcy54eXogKTtcXG5cXHRcXHR2ZWMyIHN0MCA9IGRGZHgoIHV2LnN0ICk7XFxuXFx0XFx0dmVjMiBzdDEgPSBkRmR5KCB1di5zdCApO1xcblxcdFxcdHZlYzMgTiA9IHN1cmZfbm9ybTtcXG5cXHRcXHR2ZWMzIHExcGVycCA9IGNyb3NzKCBxMSwgTiApO1xcblxcdFxcdHZlYzMgcTBwZXJwID0gY3Jvc3MoIE4sIHEwICk7XFxuXFx0XFx0dmVjMyBUID0gcTFwZXJwICogc3QwLnggKyBxMHBlcnAgKiBzdDEueDtcXG5cXHRcXHR2ZWMzIEIgPSBxMXBlcnAgKiBzdDAueSArIHEwcGVycCAqIHN0MS55O1xcblxcdFxcdGZsb2F0IGRldCA9IG1heCggZG90KCBULCBUICksIGRvdCggQiwgQiApICk7XFxuXFx0XFx0ZmxvYXQgc2NhbGUgPSAoIGRldCA9PSAwLjAgKSA/IDAuMCA6IGludmVyc2VzcXJ0KCBkZXQgKTtcXG5cXHRcXHRyZXR1cm4gbWF0MyggVCAqIHNjYWxlLCBCICogc2NhbGUsIE4gKTtcXG5cXHR9XFxuI2VuZGlmXCI7XG5cbnZhciBjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X2JlZ2luID0gXCIjaWZkZWYgVVNFX0NMRUFSQ09BVFxcblxcdHZlYzMgY2xlYXJjb2F0Tm9ybWFsID0gbm9uUGVydHVyYmVkTm9ybWFsO1xcbiNlbmRpZlwiO1xuXG52YXIgY2xlYXJjb2F0X25vcm1hbF9mcmFnbWVudF9tYXBzID0gXCIjaWZkZWYgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVBcXG5cXHR2ZWMzIGNsZWFyY29hdE1hcE4gPSB0ZXh0dXJlMkQoIGNsZWFyY29hdE5vcm1hbE1hcCwgdkNsZWFyY29hdE5vcm1hbE1hcFV2ICkueHl6ICogMi4wIC0gMS4wO1xcblxcdGNsZWFyY29hdE1hcE4ueHkgKj0gY2xlYXJjb2F0Tm9ybWFsU2NhbGU7XFxuXFx0Y2xlYXJjb2F0Tm9ybWFsID0gbm9ybWFsaXplKCB0Ym4yICogY2xlYXJjb2F0TWFwTiApO1xcbiNlbmRpZlwiO1xuXG52YXIgY2xlYXJjb2F0X3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfQ0xFQVJDT0FUTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgY2xlYXJjb2F0TWFwO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGNsZWFyY29hdE5vcm1hbE1hcDtcXG5cXHR1bmlmb3JtIHZlYzIgY2xlYXJjb2F0Tm9ybWFsU2NhbGU7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRfUk9VR0hORVNTTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgY2xlYXJjb2F0Um91Z2huZXNzTWFwO1xcbiNlbmRpZlwiO1xuXG52YXIgaXJpZGVzY2VuY2VfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9JUklERVNDRU5DRU1BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGlyaWRlc2NlbmNlTWFwO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgaXJpZGVzY2VuY2VUaGlja25lc3NNYXA7XFxuI2VuZGlmXCI7XG5cbnZhciBvcGFxdWVfZnJhZ21lbnQgPSBcIiNpZmRlZiBPUEFRVUVcXG5kaWZmdXNlQ29sb3IuYSA9IDEuMDtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1RSQU5TTUlTU0lPTlxcbmRpZmZ1c2VDb2xvci5hICo9IG1hdGVyaWFsLnRyYW5zbWlzc2lvbkFscGhhO1xcbiNlbmRpZlxcbmdsX0ZyYWdDb2xvciA9IHZlYzQoIG91dGdvaW5nTGlnaHQsIGRpZmZ1c2VDb2xvci5hICk7XCI7XG5cbnZhciBwYWNraW5nID0gXCJ2ZWMzIHBhY2tOb3JtYWxUb1JHQiggY29uc3QgaW4gdmVjMyBub3JtYWwgKSB7XFxuXFx0cmV0dXJuIG5vcm1hbGl6ZSggbm9ybWFsICkgKiAwLjUgKyAwLjU7XFxufVxcbnZlYzMgdW5wYWNrUkdCVG9Ob3JtYWwoIGNvbnN0IGluIHZlYzMgcmdiICkge1xcblxcdHJldHVybiAyLjAgKiByZ2IueHl6IC0gMS4wO1xcbn1cXG5jb25zdCBmbG9hdCBQYWNrVXBzY2FsZSA9IDI1Ni4gLyAyNTUuO2NvbnN0IGZsb2F0IFVucGFja0Rvd25zY2FsZSA9IDI1NS4gLyAyNTYuO1xcbmNvbnN0IHZlYzMgUGFja0ZhY3RvcnMgPSB2ZWMzKCAyNTYuICogMjU2LiAqIDI1Ni4sIDI1Ni4gKiAyNTYuLCAyNTYuICk7XFxuY29uc3QgdmVjNCBVbnBhY2tGYWN0b3JzID0gVW5wYWNrRG93bnNjYWxlIC8gdmVjNCggUGFja0ZhY3RvcnMsIDEuICk7XFxuY29uc3QgZmxvYXQgU2hpZnRSaWdodDggPSAxLiAvIDI1Ni47XFxudmVjNCBwYWNrRGVwdGhUb1JHQkEoIGNvbnN0IGluIGZsb2F0IHYgKSB7XFxuXFx0dmVjNCByID0gdmVjNCggZnJhY3QoIHYgKiBQYWNrRmFjdG9ycyApLCB2ICk7XFxuXFx0ci55encgLT0gci54eXogKiBTaGlmdFJpZ2h0ODtcXHRyZXR1cm4gciAqIFBhY2tVcHNjYWxlO1xcbn1cXG5mbG9hdCB1bnBhY2tSR0JBVG9EZXB0aCggY29uc3QgaW4gdmVjNCB2ICkge1xcblxcdHJldHVybiBkb3QoIHYsIFVucGFja0ZhY3RvcnMgKTtcXG59XFxudmVjMiBwYWNrRGVwdGhUb1JHKCBpbiBoaWdocCBmbG9hdCB2ICkge1xcblxcdHJldHVybiBwYWNrRGVwdGhUb1JHQkEoIHYgKS55eDtcXG59XFxuZmxvYXQgdW5wYWNrUkdUb0RlcHRoKCBjb25zdCBpbiBoaWdocCB2ZWMyIHYgKSB7XFxuXFx0cmV0dXJuIHVucGFja1JHQkFUb0RlcHRoKCB2ZWM0KCB2Lnh5LCAwLjAsIDAuMCApICk7XFxufVxcbnZlYzQgcGFjazJIYWxmVG9SR0JBKCB2ZWMyIHYgKSB7XFxuXFx0dmVjNCByID0gdmVjNCggdi54LCBmcmFjdCggdi54ICogMjU1LjAgKSwgdi55LCBmcmFjdCggdi55ICogMjU1LjAgKSApO1xcblxcdHJldHVybiB2ZWM0KCByLnggLSByLnkgLyAyNTUuMCwgci55LCByLnogLSByLncgLyAyNTUuMCwgci53ICk7XFxufVxcbnZlYzIgdW5wYWNrUkdCQVRvMkhhbGYoIHZlYzQgdiApIHtcXG5cXHRyZXR1cm4gdmVjMiggdi54ICsgKCB2LnkgLyAyNTUuMCApLCB2LnogKyAoIHYudyAvIDI1NS4wICkgKTtcXG59XFxuZmxvYXQgdmlld1pUb09ydGhvZ3JhcGhpY0RlcHRoKCBjb25zdCBpbiBmbG9hdCB2aWV3WiwgY29uc3QgaW4gZmxvYXQgbmVhciwgY29uc3QgaW4gZmxvYXQgZmFyICkge1xcblxcdHJldHVybiAoIHZpZXdaICsgbmVhciApIC8gKCBuZWFyIC0gZmFyICk7XFxufVxcbmZsb2F0IG9ydGhvZ3JhcGhpY0RlcHRoVG9WaWV3WiggY29uc3QgaW4gZmxvYXQgZGVwdGgsIGNvbnN0IGluIGZsb2F0IG5lYXIsIGNvbnN0IGluIGZsb2F0IGZhciApIHtcXG5cXHRyZXR1cm4gZGVwdGggKiAoIG5lYXIgLSBmYXIgKSAtIG5lYXI7XFxufVxcbmZsb2F0IHZpZXdaVG9QZXJzcGVjdGl2ZURlcHRoKCBjb25zdCBpbiBmbG9hdCB2aWV3WiwgY29uc3QgaW4gZmxvYXQgbmVhciwgY29uc3QgaW4gZmxvYXQgZmFyICkge1xcblxcdHJldHVybiAoICggbmVhciArIHZpZXdaICkgKiBmYXIgKSAvICggKCBmYXIgLSBuZWFyICkgKiB2aWV3WiApO1xcbn1cXG5mbG9hdCBwZXJzcGVjdGl2ZURlcHRoVG9WaWV3WiggY29uc3QgaW4gZmxvYXQgZGVwdGgsIGNvbnN0IGluIGZsb2F0IG5lYXIsIGNvbnN0IGluIGZsb2F0IGZhciApIHtcXG5cXHRyZXR1cm4gKCBuZWFyICogZmFyICkgLyAoICggZmFyIC0gbmVhciApICogZGVwdGggLSBmYXIgKTtcXG59XCI7XG5cbnZhciBwcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50ID0gXCIjaWZkZWYgUFJFTVVMVElQTElFRF9BTFBIQVxcblxcdGdsX0ZyYWdDb2xvci5yZ2IgKj0gZ2xfRnJhZ0NvbG9yLmE7XFxuI2VuZGlmXCI7XG5cbnZhciBwcm9qZWN0X3ZlcnRleCA9IFwidmVjNCBtdlBvc2l0aW9uID0gdmVjNCggdHJhbnNmb3JtZWQsIDEuMCApO1xcbiNpZmRlZiBVU0VfQkFUQ0hJTkdcXG5cXHRtdlBvc2l0aW9uID0gYmF0Y2hpbmdNYXRyaXggKiBtdlBvc2l0aW9uO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfSU5TVEFOQ0lOR1xcblxcdG12UG9zaXRpb24gPSBpbnN0YW5jZU1hdHJpeCAqIG12UG9zaXRpb247XFxuI2VuZGlmXFxubXZQb3NpdGlvbiA9IG1vZGVsVmlld01hdHJpeCAqIG12UG9zaXRpb247XFxuZ2xfUG9zaXRpb24gPSBwcm9qZWN0aW9uTWF0cml4ICogbXZQb3NpdGlvbjtcIjtcblxudmFyIGRpdGhlcmluZ19mcmFnbWVudCA9IFwiI2lmZGVmIERJVEhFUklOR1xcblxcdGdsX0ZyYWdDb2xvci5yZ2IgPSBkaXRoZXJpbmcoIGdsX0ZyYWdDb2xvci5yZ2IgKTtcXG4jZW5kaWZcIjtcblxudmFyIGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgRElUSEVSSU5HXFxuXFx0dmVjMyBkaXRoZXJpbmcoIHZlYzMgY29sb3IgKSB7XFxuXFx0XFx0ZmxvYXQgZ3JpZF9wb3NpdGlvbiA9IHJhbmQoIGdsX0ZyYWdDb29yZC54eSApO1xcblxcdFxcdHZlYzMgZGl0aGVyX3NoaWZ0X1JHQiA9IHZlYzMoIDAuMjUgLyAyNTUuMCwgLTAuMjUgLyAyNTUuMCwgMC4yNSAvIDI1NS4wICk7XFxuXFx0XFx0ZGl0aGVyX3NoaWZ0X1JHQiA9IG1peCggMi4wICogZGl0aGVyX3NoaWZ0X1JHQiwgLTIuMCAqIGRpdGhlcl9zaGlmdF9SR0IsIGdyaWRfcG9zaXRpb24gKTtcXG5cXHRcXHRyZXR1cm4gY29sb3IgKyBkaXRoZXJfc2hpZnRfUkdCO1xcblxcdH1cXG4jZW5kaWZcIjtcblxudmFyIHJvdWdobmVzc21hcF9mcmFnbWVudCA9IFwiZmxvYXQgcm91Z2huZXNzRmFjdG9yID0gcm91Z2huZXNzO1xcbiNpZmRlZiBVU0VfUk9VR0hORVNTTUFQXFxuXFx0dmVjNCB0ZXhlbFJvdWdobmVzcyA9IHRleHR1cmUyRCggcm91Z2huZXNzTWFwLCB2Um91Z2huZXNzTWFwVXYgKTtcXG5cXHRyb3VnaG5lc3NGYWN0b3IgKj0gdGV4ZWxSb3VnaG5lc3MuZztcXG4jZW5kaWZcIjtcblxudmFyIHJvdWdobmVzc21hcF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX1JPVUdITkVTU01BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIHJvdWdobmVzc01hcDtcXG4jZW5kaWZcIjtcblxudmFyIHNoYWRvd21hcF9wYXJzX2ZyYWdtZW50ID0gXCIjaWYgTlVNX1NQT1RfTElHSFRfQ09PUkRTID4gMFxcblxcdHZhcnlpbmcgdmVjNCB2U3BvdExpZ2h0Q29vcmRbIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyBdO1xcbiNlbmRpZlxcbiNpZiBOVU1fU1BPVF9MSUdIVF9NQVBTID4gMFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIHNwb3RMaWdodE1hcFsgTlVNX1NQT1RfTElHSFRfTUFQUyBdO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfU0hBRE9XTUFQXFxuXFx0I2lmIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHRcXHR1bmlmb3JtIHNhbXBsZXIyRCBkaXJlY3Rpb25hbFNoYWRvd01hcFsgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XFxuXFx0XFx0dmFyeWluZyB2ZWM0IHZEaXJlY3Rpb25hbFNoYWRvd0Nvb3JkWyBOVU1fRElSX0xJR0hUX1NIQURPV1MgXTtcXG5cXHRcXHRzdHJ1Y3QgRGlyZWN0aW9uYWxMaWdodFNoYWRvdyB7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93SW50ZW5zaXR5O1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd0JpYXM7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93Tm9ybWFsQmlhcztcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dSYWRpdXM7XFxuXFx0XFx0XFx0dmVjMiBzaGFkb3dNYXBTaXplO1xcblxcdFxcdH07XFxuXFx0XFx0dW5pZm9ybSBEaXJlY3Rpb25hbExpZ2h0U2hhZG93IGRpcmVjdGlvbmFsTGlnaHRTaGFkb3dzWyBOVU1fRElSX0xJR0hUX1NIQURPV1MgXTtcXG5cXHQjZW5kaWZcXG5cXHQjaWYgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHRcXHR1bmlmb3JtIHNhbXBsZXIyRCBzcG90U2hhZG93TWFwWyBOVU1fU1BPVF9MSUdIVF9TSEFET1dTIF07XFxuXFx0XFx0c3RydWN0IFNwb3RMaWdodFNoYWRvdyB7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93SW50ZW5zaXR5O1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd0JpYXM7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93Tm9ybWFsQmlhcztcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dSYWRpdXM7XFxuXFx0XFx0XFx0dmVjMiBzaGFkb3dNYXBTaXplO1xcblxcdFxcdH07XFxuXFx0XFx0dW5pZm9ybSBTcG90TGlnaHRTaGFkb3cgc3BvdExpZ2h0U2hhZG93c1sgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyBdO1xcblxcdCNlbmRpZlxcblxcdCNpZiBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHRcXHR1bmlmb3JtIHNhbXBsZXIyRCBwb2ludFNoYWRvd01hcFsgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgXTtcXG5cXHRcXHR2YXJ5aW5nIHZlYzQgdlBvaW50U2hhZG93Q29vcmRbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XFxuXFx0XFx0c3RydWN0IFBvaW50TGlnaHRTaGFkb3cge1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd0ludGVuc2l0eTtcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dCaWFzO1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd05vcm1hbEJpYXM7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93UmFkaXVzO1xcblxcdFxcdFxcdHZlYzIgc2hhZG93TWFwU2l6ZTtcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dDYW1lcmFOZWFyO1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd0NhbWVyYUZhcjtcXG5cXHRcXHR9O1xcblxcdFxcdHVuaWZvcm0gUG9pbnRMaWdodFNoYWRvdyBwb2ludExpZ2h0U2hhZG93c1sgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgXTtcXG5cXHQjZW5kaWZcXG5cXHRmbG9hdCB0ZXh0dXJlMkRDb21wYXJlKCBzYW1wbGVyMkQgZGVwdGhzLCB2ZWMyIHV2LCBmbG9hdCBjb21wYXJlICkge1xcblxcdFxcdHJldHVybiBzdGVwKCBjb21wYXJlLCB1bnBhY2tSR0JBVG9EZXB0aCggdGV4dHVyZTJEKCBkZXB0aHMsIHV2ICkgKSApO1xcblxcdH1cXG5cXHR2ZWMyIHRleHR1cmUyRERpc3RyaWJ1dGlvbiggc2FtcGxlcjJEIHNoYWRvdywgdmVjMiB1diApIHtcXG5cXHRcXHRyZXR1cm4gdW5wYWNrUkdCQVRvMkhhbGYoIHRleHR1cmUyRCggc2hhZG93LCB1diApICk7XFxuXFx0fVxcblxcdGZsb2F0IFZTTVNoYWRvdyAoc2FtcGxlcjJEIHNoYWRvdywgdmVjMiB1diwgZmxvYXQgY29tcGFyZSApe1xcblxcdFxcdGZsb2F0IG9jY2x1c2lvbiA9IDEuMDtcXG5cXHRcXHR2ZWMyIGRpc3RyaWJ1dGlvbiA9IHRleHR1cmUyRERpc3RyaWJ1dGlvbiggc2hhZG93LCB1diApO1xcblxcdFxcdGZsb2F0IGhhcmRfc2hhZG93ID0gc3RlcCggY29tcGFyZSAsIGRpc3RyaWJ1dGlvbi54ICk7XFxuXFx0XFx0aWYgKGhhcmRfc2hhZG93ICE9IDEuMCApIHtcXG5cXHRcXHRcXHRmbG9hdCBkaXN0YW5jZSA9IGNvbXBhcmUgLSBkaXN0cmlidXRpb24ueCA7XFxuXFx0XFx0XFx0ZmxvYXQgdmFyaWFuY2UgPSBtYXgoIDAuMDAwMDAsIGRpc3RyaWJ1dGlvbi55ICogZGlzdHJpYnV0aW9uLnkgKTtcXG5cXHRcXHRcXHRmbG9hdCBzb2Z0bmVzc19wcm9iYWJpbGl0eSA9IHZhcmlhbmNlIC8gKHZhcmlhbmNlICsgZGlzdGFuY2UgKiBkaXN0YW5jZSApO1xcdFxcdFxcdHNvZnRuZXNzX3Byb2JhYmlsaXR5ID0gY2xhbXAoICggc29mdG5lc3NfcHJvYmFiaWxpdHkgLSAwLjMgKSAvICggMC45NSAtIDAuMyApLCAwLjAsIDEuMCApO1xcdFxcdFxcdG9jY2x1c2lvbiA9IGNsYW1wKCBtYXgoIGhhcmRfc2hhZG93LCBzb2Z0bmVzc19wcm9iYWJpbGl0eSApLCAwLjAsIDEuMCApO1xcblxcdFxcdH1cXG5cXHRcXHRyZXR1cm4gb2NjbHVzaW9uO1xcblxcdH1cXG5cXHRmbG9hdCBnZXRTaGFkb3coIHNhbXBsZXIyRCBzaGFkb3dNYXAsIHZlYzIgc2hhZG93TWFwU2l6ZSwgZmxvYXQgc2hhZG93SW50ZW5zaXR5LCBmbG9hdCBzaGFkb3dCaWFzLCBmbG9hdCBzaGFkb3dSYWRpdXMsIHZlYzQgc2hhZG93Q29vcmQgKSB7XFxuXFx0XFx0ZmxvYXQgc2hhZG93ID0gMS4wO1xcblxcdFxcdHNoYWRvd0Nvb3JkLnh5eiAvPSBzaGFkb3dDb29yZC53O1xcblxcdFxcdHNoYWRvd0Nvb3JkLnogKz0gc2hhZG93QmlhcztcXG5cXHRcXHRib29sIGluRnJ1c3R1bSA9IHNoYWRvd0Nvb3JkLnggPj0gMC4wICYmIHNoYWRvd0Nvb3JkLnggPD0gMS4wICYmIHNoYWRvd0Nvb3JkLnkgPj0gMC4wICYmIHNoYWRvd0Nvb3JkLnkgPD0gMS4wO1xcblxcdFxcdGJvb2wgZnJ1c3R1bVRlc3QgPSBpbkZydXN0dW0gJiYgc2hhZG93Q29vcmQueiA8PSAxLjA7XFxuXFx0XFx0aWYgKCBmcnVzdHVtVGVzdCApIHtcXG5cXHRcXHQjaWYgZGVmaW5lZCggU0hBRE9XTUFQX1RZUEVfUENGIClcXG5cXHRcXHRcXHR2ZWMyIHRleGVsU2l6ZSA9IHZlYzIoIDEuMCApIC8gc2hhZG93TWFwU2l6ZTtcXG5cXHRcXHRcXHRmbG9hdCBkeDAgPSAtIHRleGVsU2l6ZS54ICogc2hhZG93UmFkaXVzO1xcblxcdFxcdFxcdGZsb2F0IGR5MCA9IC0gdGV4ZWxTaXplLnkgKiBzaGFkb3dSYWRpdXM7XFxuXFx0XFx0XFx0ZmxvYXQgZHgxID0gKyB0ZXhlbFNpemUueCAqIHNoYWRvd1JhZGl1cztcXG5cXHRcXHRcXHRmbG9hdCBkeTEgPSArIHRleGVsU2l6ZS55ICogc2hhZG93UmFkaXVzO1xcblxcdFxcdFxcdGZsb2F0IGR4MiA9IGR4MCAvIDIuMDtcXG5cXHRcXHRcXHRmbG9hdCBkeTIgPSBkeTAgLyAyLjA7XFxuXFx0XFx0XFx0ZmxvYXQgZHgzID0gZHgxIC8gMi4wO1xcblxcdFxcdFxcdGZsb2F0IGR5MyA9IGR5MSAvIDIuMDtcXG5cXHRcXHRcXHRzaGFkb3cgPSAoXFxuXFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSArIHZlYzIoIGR4MCwgZHkwICksIHNoYWRvd0Nvb3JkLnogKSArXFxuXFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSArIHZlYzIoIDAuMCwgZHkwICksIHNoYWRvd0Nvb3JkLnogKSArXFxuXFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSArIHZlYzIoIGR4MSwgZHkwICksIHNoYWRvd0Nvb3JkLnogKSArXFxuXFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSArIHZlYzIoIGR4MiwgZHkyICksIHNoYWRvd0Nvb3JkLnogKSArXFxuXFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSArIHZlYzIoIDAuMCwgZHkyICksIHNoYWRvd0Nvb3JkLnogKSArXFxuXFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSArIHZlYzIoIGR4MywgZHkyICksIHNoYWRvd0Nvb3JkLnogKSArXFxuXFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSArIHZlYzIoIGR4MCwgMC4wICksIHNoYWRvd0Nvb3JkLnogKSArXFxuXFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSArIHZlYzIoIGR4MiwgMC4wICksIHNoYWRvd0Nvb3JkLnogKSArXFxuXFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgzLCAwLjAgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgxLCAwLjAgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgyLCBkeTMgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggMC4wLCBkeTMgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgzLCBkeTMgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgwLCBkeTEgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggMC4wLCBkeTEgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgxLCBkeTEgKSwgc2hhZG93Q29vcmQueiApXFxuXFx0XFx0XFx0KSAqICggMS4wIC8gMTcuMCApO1xcblxcdFxcdCNlbGlmIGRlZmluZWQoIFNIQURPV01BUF9UWVBFX1BDRl9TT0ZUIClcXG5cXHRcXHRcXHR2ZWMyIHRleGVsU2l6ZSA9IHZlYzIoIDEuMCApIC8gc2hhZG93TWFwU2l6ZTtcXG5cXHRcXHRcXHRmbG9hdCBkeCA9IHRleGVsU2l6ZS54O1xcblxcdFxcdFxcdGZsb2F0IGR5ID0gdGV4ZWxTaXplLnk7XFxuXFx0XFx0XFx0dmVjMiB1diA9IHNoYWRvd0Nvb3JkLnh5O1xcblxcdFxcdFxcdHZlYzIgZiA9IGZyYWN0KCB1diAqIHNoYWRvd01hcFNpemUgKyAwLjUgKTtcXG5cXHRcXHRcXHR1diAtPSBmICogdGV4ZWxTaXplO1xcblxcdFxcdFxcdHNoYWRvdyA9IChcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2LCBzaGFkb3dDb29yZC56ICkgK1xcblxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCBkeCwgMC4wICksIHNoYWRvd0Nvb3JkLnogKSArXFxuXFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIDAuMCwgZHkgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdGV4ZWxTaXplLCBzaGFkb3dDb29yZC56ICkgK1xcblxcdFxcdFxcdFxcdG1peCggdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIC1keCwgMC4wICksIHNoYWRvd0Nvb3JkLnogKSxcXG5cXHRcXHRcXHRcXHRcXHQgdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIDIuMCAqIGR4LCAwLjAgKSwgc2hhZG93Q29vcmQueiApLFxcblxcdFxcdFxcdFxcdFxcdCBmLnggKSArXFxuXFx0XFx0XFx0XFx0bWl4KCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggLWR4LCBkeSApLCBzaGFkb3dDb29yZC56ICksXFxuXFx0XFx0XFx0XFx0XFx0IHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAyLjAgKiBkeCwgZHkgKSwgc2hhZG93Q29vcmQueiApLFxcblxcdFxcdFxcdFxcdFxcdCBmLnggKSArXFxuXFx0XFx0XFx0XFx0bWl4KCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggMC4wLCAtZHkgKSwgc2hhZG93Q29vcmQueiApLFxcblxcdFxcdFxcdFxcdFxcdCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggMC4wLCAyLjAgKiBkeSApLCBzaGFkb3dDb29yZC56ICksXFxuXFx0XFx0XFx0XFx0XFx0IGYueSApICtcXG5cXHRcXHRcXHRcXHRtaXgoIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCBkeCwgLWR5ICksIHNoYWRvd0Nvb3JkLnogKSxcXG5cXHRcXHRcXHRcXHRcXHQgdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIGR4LCAyLjAgKiBkeSApLCBzaGFkb3dDb29yZC56ICksXFxuXFx0XFx0XFx0XFx0XFx0IGYueSApICtcXG5cXHRcXHRcXHRcXHRtaXgoIG1peCggdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIC1keCwgLWR5ICksIHNoYWRvd0Nvb3JkLnogKSxcXG5cXHRcXHRcXHRcXHRcXHRcXHQgIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAyLjAgKiBkeCwgLWR5ICksIHNoYWRvd0Nvb3JkLnogKSxcXG5cXHRcXHRcXHRcXHRcXHRcXHQgIGYueCApLFxcblxcdFxcdFxcdFxcdFxcdCBtaXgoIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAtZHgsIDIuMCAqIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcXG5cXHRcXHRcXHRcXHRcXHRcXHQgIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAyLjAgKiBkeCwgMi4wICogZHkgKSwgc2hhZG93Q29vcmQueiApLFxcblxcdFxcdFxcdFxcdFxcdFxcdCAgZi54ICksXFxuXFx0XFx0XFx0XFx0XFx0IGYueSApXFxuXFx0XFx0XFx0KSAqICggMS4wIC8gOS4wICk7XFxuXFx0XFx0I2VsaWYgZGVmaW5lZCggU0hBRE9XTUFQX1RZUEVfVlNNIClcXG5cXHRcXHRcXHRzaGFkb3cgPSBWU01TaGFkb3coIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHksIHNoYWRvd0Nvb3JkLnogKTtcXG5cXHRcXHQjZWxzZVxcblxcdFxcdFxcdHNoYWRvdyA9IHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHksIHNoYWRvd0Nvb3JkLnogKTtcXG5cXHRcXHQjZW5kaWZcXG5cXHRcXHR9XFxuXFx0XFx0cmV0dXJuIG1peCggMS4wLCBzaGFkb3csIHNoYWRvd0ludGVuc2l0eSApO1xcblxcdH1cXG5cXHR2ZWMyIGN1YmVUb1VWKCB2ZWMzIHYsIGZsb2F0IHRleGVsU2l6ZVkgKSB7XFxuXFx0XFx0dmVjMyBhYnNWID0gYWJzKCB2ICk7XFxuXFx0XFx0ZmxvYXQgc2NhbGVUb0N1YmUgPSAxLjAgLyBtYXgoIGFic1YueCwgbWF4KCBhYnNWLnksIGFic1YueiApICk7XFxuXFx0XFx0YWJzViAqPSBzY2FsZVRvQ3ViZTtcXG5cXHRcXHR2ICo9IHNjYWxlVG9DdWJlICogKCAxLjAgLSAyLjAgKiB0ZXhlbFNpemVZICk7XFxuXFx0XFx0dmVjMiBwbGFuYXIgPSB2Lnh5O1xcblxcdFxcdGZsb2F0IGFsbW9zdEFUZXhlbCA9IDEuNSAqIHRleGVsU2l6ZVk7XFxuXFx0XFx0ZmxvYXQgYWxtb3N0T25lID0gMS4wIC0gYWxtb3N0QVRleGVsO1xcblxcdFxcdGlmICggYWJzVi56ID49IGFsbW9zdE9uZSApIHtcXG5cXHRcXHRcXHRpZiAoIHYueiA+IDAuMCApXFxuXFx0XFx0XFx0XFx0cGxhbmFyLnggPSA0LjAgLSB2Lng7XFxuXFx0XFx0fSBlbHNlIGlmICggYWJzVi54ID49IGFsbW9zdE9uZSApIHtcXG5cXHRcXHRcXHRmbG9hdCBzaWduWCA9IHNpZ24oIHYueCApO1xcblxcdFxcdFxcdHBsYW5hci54ID0gdi56ICogc2lnblggKyAyLjAgKiBzaWduWDtcXG5cXHRcXHR9IGVsc2UgaWYgKCBhYnNWLnkgPj0gYWxtb3N0T25lICkge1xcblxcdFxcdFxcdGZsb2F0IHNpZ25ZID0gc2lnbiggdi55ICk7XFxuXFx0XFx0XFx0cGxhbmFyLnggPSB2LnggKyAyLjAgKiBzaWduWSArIDIuMDtcXG5cXHRcXHRcXHRwbGFuYXIueSA9IHYueiAqIHNpZ25ZIC0gMi4wO1xcblxcdFxcdH1cXG5cXHRcXHRyZXR1cm4gdmVjMiggMC4xMjUsIDAuMjUgKSAqIHBsYW5hciArIHZlYzIoIDAuMzc1LCAwLjc1ICk7XFxuXFx0fVxcblxcdGZsb2F0IGdldFBvaW50U2hhZG93KCBzYW1wbGVyMkQgc2hhZG93TWFwLCB2ZWMyIHNoYWRvd01hcFNpemUsIGZsb2F0IHNoYWRvd0ludGVuc2l0eSwgZmxvYXQgc2hhZG93QmlhcywgZmxvYXQgc2hhZG93UmFkaXVzLCB2ZWM0IHNoYWRvd0Nvb3JkLCBmbG9hdCBzaGFkb3dDYW1lcmFOZWFyLCBmbG9hdCBzaGFkb3dDYW1lcmFGYXIgKSB7XFxuXFx0XFx0ZmxvYXQgc2hhZG93ID0gMS4wO1xcblxcdFxcdHZlYzMgbGlnaHRUb1Bvc2l0aW9uID0gc2hhZG93Q29vcmQueHl6O1xcblxcdFxcdFxcblxcdFxcdGZsb2F0IGxpZ2h0VG9Qb3NpdGlvbkxlbmd0aCA9IGxlbmd0aCggbGlnaHRUb1Bvc2l0aW9uICk7XFxuXFx0XFx0aWYgKCBsaWdodFRvUG9zaXRpb25MZW5ndGggLSBzaGFkb3dDYW1lcmFGYXIgPD0gMC4wICYmIGxpZ2h0VG9Qb3NpdGlvbkxlbmd0aCAtIHNoYWRvd0NhbWVyYU5lYXIgPj0gMC4wICkge1xcblxcdFxcdFxcdGZsb2F0IGRwID0gKCBsaWdodFRvUG9zaXRpb25MZW5ndGggLSBzaGFkb3dDYW1lcmFOZWFyICkgLyAoIHNoYWRvd0NhbWVyYUZhciAtIHNoYWRvd0NhbWVyYU5lYXIgKTtcXHRcXHRcXHRkcCArPSBzaGFkb3dCaWFzO1xcblxcdFxcdFxcdHZlYzMgYmQzRCA9IG5vcm1hbGl6ZSggbGlnaHRUb1Bvc2l0aW9uICk7XFxuXFx0XFx0XFx0dmVjMiB0ZXhlbFNpemUgPSB2ZWMyKCAxLjAgKSAvICggc2hhZG93TWFwU2l6ZSAqIHZlYzIoIDQuMCwgMi4wICkgKTtcXG5cXHRcXHRcXHQjaWYgZGVmaW5lZCggU0hBRE9XTUFQX1RZUEVfUENGICkgfHwgZGVmaW5lZCggU0hBRE9XTUFQX1RZUEVfUENGX1NPRlQgKSB8fCBkZWZpbmVkKCBTSEFET1dNQVBfVFlQRV9WU00gKVxcblxcdFxcdFxcdFxcdHZlYzIgb2Zmc2V0ID0gdmVjMiggLSAxLCAxICkgKiBzaGFkb3dSYWRpdXMgKiB0ZXhlbFNpemUueTtcXG5cXHRcXHRcXHRcXHRzaGFkb3cgPSAoXFxuXFx0XFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBjdWJlVG9VViggYmQzRCArIG9mZnNldC54eXksIHRleGVsU2l6ZS55ICksIGRwICkgK1xcblxcdFxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QgKyBvZmZzZXQueXl5LCB0ZXhlbFNpemUueSApLCBkcCApICtcXG5cXHRcXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNEICsgb2Zmc2V0Lnh5eCwgdGV4ZWxTaXplLnkgKSwgZHAgKSArXFxuXFx0XFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBjdWJlVG9VViggYmQzRCArIG9mZnNldC55eXgsIHRleGVsU2l6ZS55ICksIGRwICkgK1xcblxcdFxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QsIHRleGVsU2l6ZS55ICksIGRwICkgK1xcblxcdFxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QgKyBvZmZzZXQueHh5LCB0ZXhlbFNpemUueSApLCBkcCApICtcXG5cXHRcXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNEICsgb2Zmc2V0Lnl4eSwgdGV4ZWxTaXplLnkgKSwgZHAgKSArXFxuXFx0XFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBjdWJlVG9VViggYmQzRCArIG9mZnNldC54eHgsIHRleGVsU2l6ZS55ICksIGRwICkgK1xcblxcdFxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QgKyBvZmZzZXQueXh4LCB0ZXhlbFNpemUueSApLCBkcCApXFxuXFx0XFx0XFx0XFx0KSAqICggMS4wIC8gOS4wICk7XFxuXFx0XFx0XFx0I2Vsc2VcXG5cXHRcXHRcXHRcXHRzaGFkb3cgPSB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNELCB0ZXhlbFNpemUueSApLCBkcCApO1xcblxcdFxcdFxcdCNlbmRpZlxcblxcdFxcdH1cXG5cXHRcXHRyZXR1cm4gbWl4KCAxLjAsIHNoYWRvdywgc2hhZG93SW50ZW5zaXR5ICk7XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgc2hhZG93bWFwX3BhcnNfdmVydGV4ID0gXCIjaWYgTlVNX1NQT1RfTElHSFRfQ09PUkRTID4gMFxcblxcdHVuaWZvcm0gbWF0NCBzcG90TGlnaHRNYXRyaXhbIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyBdO1xcblxcdHZhcnlpbmcgdmVjNCB2U3BvdExpZ2h0Q29vcmRbIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyBdO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfU0hBRE9XTUFQXFxuXFx0I2lmIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHRcXHR1bmlmb3JtIG1hdDQgZGlyZWN0aW9uYWxTaGFkb3dNYXRyaXhbIE5VTV9ESVJfTElHSFRfU0hBRE9XUyBdO1xcblxcdFxcdHZhcnlpbmcgdmVjNCB2RGlyZWN0aW9uYWxTaGFkb3dDb29yZFsgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XFxuXFx0XFx0c3RydWN0IERpcmVjdGlvbmFsTGlnaHRTaGFkb3cge1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd0ludGVuc2l0eTtcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dCaWFzO1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd05vcm1hbEJpYXM7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93UmFkaXVzO1xcblxcdFxcdFxcdHZlYzIgc2hhZG93TWFwU2l6ZTtcXG5cXHRcXHR9O1xcblxcdFxcdHVuaWZvcm0gRGlyZWN0aW9uYWxMaWdodFNoYWRvdyBkaXJlY3Rpb25hbExpZ2h0U2hhZG93c1sgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XFxuXFx0I2VuZGlmXFxuXFx0I2lmIE5VTV9TUE9UX0xJR0hUX1NIQURPV1MgPiAwXFxuXFx0XFx0c3RydWN0IFNwb3RMaWdodFNoYWRvdyB7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93SW50ZW5zaXR5O1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd0JpYXM7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93Tm9ybWFsQmlhcztcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dSYWRpdXM7XFxuXFx0XFx0XFx0dmVjMiBzaGFkb3dNYXBTaXplO1xcblxcdFxcdH07XFxuXFx0XFx0dW5pZm9ybSBTcG90TGlnaHRTaGFkb3cgc3BvdExpZ2h0U2hhZG93c1sgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyBdO1xcblxcdCNlbmRpZlxcblxcdCNpZiBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHRcXHR1bmlmb3JtIG1hdDQgcG9pbnRTaGFkb3dNYXRyaXhbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XFxuXFx0XFx0dmFyeWluZyB2ZWM0IHZQb2ludFNoYWRvd0Nvb3JkWyBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUyBdO1xcblxcdFxcdHN0cnVjdCBQb2ludExpZ2h0U2hhZG93IHtcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dJbnRlbnNpdHk7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93QmlhcztcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dOb3JtYWxCaWFzO1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd1JhZGl1cztcXG5cXHRcXHRcXHR2ZWMyIHNoYWRvd01hcFNpemU7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93Q2FtZXJhTmVhcjtcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dDYW1lcmFGYXI7XFxuXFx0XFx0fTtcXG5cXHRcXHR1bmlmb3JtIFBvaW50TGlnaHRTaGFkb3cgcG9pbnRMaWdodFNoYWRvd3NbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XFxuXFx0I2VuZGlmXFxuI2VuZGlmXCI7XG5cbnZhciBzaGFkb3dtYXBfdmVydGV4ID0gXCIjaWYgKCBkZWZpbmVkKCBVU0VfU0hBRE9XTUFQICkgJiYgKCBOVU1fRElSX0xJR0hUX1NIQURPV1MgPiAwIHx8IE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTID4gMCApICkgfHwgKCBOVU1fU1BPVF9MSUdIVF9DT09SRFMgPiAwIClcXG5cXHR2ZWMzIHNoYWRvd1dvcmxkTm9ybWFsID0gaW52ZXJzZVRyYW5zZm9ybURpcmVjdGlvbiggdHJhbnNmb3JtZWROb3JtYWwsIHZpZXdNYXRyaXggKTtcXG5cXHR2ZWM0IHNoYWRvd1dvcmxkUG9zaXRpb247XFxuI2VuZGlmXFxuI2lmIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKVxcblxcdCNpZiBOVU1fRElSX0xJR0hUX1NIQURPV1MgPiAwXFxuXFx0XFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxcblxcdFxcdGZvciAoIGludCBpID0gMDsgaSA8IE5VTV9ESVJfTElHSFRfU0hBRE9XUzsgaSArKyApIHtcXG5cXHRcXHRcXHRzaGFkb3dXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbiArIHZlYzQoIHNoYWRvd1dvcmxkTm9ybWFsICogZGlyZWN0aW9uYWxMaWdodFNoYWRvd3NbIGkgXS5zaGFkb3dOb3JtYWxCaWFzLCAwICk7XFxuXFx0XFx0XFx0dkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIGkgXSA9IGRpcmVjdGlvbmFsU2hhZG93TWF0cml4WyBpIF0gKiBzaGFkb3dXb3JsZFBvc2l0aW9uO1xcblxcdFxcdH1cXG5cXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxcblxcdCNlbmRpZlxcblxcdCNpZiBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XFxuXFx0XFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1M7IGkgKysgKSB7XFxuXFx0XFx0XFx0c2hhZG93V29ybGRQb3NpdGlvbiA9IHdvcmxkUG9zaXRpb24gKyB2ZWM0KCBzaGFkb3dXb3JsZE5vcm1hbCAqIHBvaW50TGlnaHRTaGFkb3dzWyBpIF0uc2hhZG93Tm9ybWFsQmlhcywgMCApO1xcblxcdFxcdFxcdHZQb2ludFNoYWRvd0Nvb3JkWyBpIF0gPSBwb2ludFNoYWRvd01hdHJpeFsgaSBdICogc2hhZG93V29ybGRQb3NpdGlvbjtcXG5cXHRcXHR9XFxuXFx0XFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcXG5cXHQjZW5kaWZcXG4jZW5kaWZcXG4jaWYgTlVNX1NQT1RfTElHSFRfQ09PUkRTID4gMFxcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcXG5cXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fU1BPVF9MSUdIVF9DT09SRFM7IGkgKysgKSB7XFxuXFx0XFx0c2hhZG93V29ybGRQb3NpdGlvbiA9IHdvcmxkUG9zaXRpb247XFxuXFx0XFx0I2lmICggZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmIFVOUk9MTEVEX0xPT1BfSU5ERVggPCBOVU1fU1BPVF9MSUdIVF9TSEFET1dTIClcXG5cXHRcXHRcXHRzaGFkb3dXb3JsZFBvc2l0aW9uLnh5eiArPSBzaGFkb3dXb3JsZE5vcm1hbCAqIHNwb3RMaWdodFNoYWRvd3NbIGkgXS5zaGFkb3dOb3JtYWxCaWFzO1xcblxcdFxcdCNlbmRpZlxcblxcdFxcdHZTcG90TGlnaHRDb29yZFsgaSBdID0gc3BvdExpZ2h0TWF0cml4WyBpIF0gKiBzaGFkb3dXb3JsZFBvc2l0aW9uO1xcblxcdH1cXG5cXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxcbiNlbmRpZlwiO1xuXG52YXIgc2hhZG93bWFza19wYXJzX2ZyYWdtZW50ID0gXCJmbG9hdCBnZXRTaGFkb3dNYXNrKCkge1xcblxcdGZsb2F0IHNoYWRvdyA9IDEuMDtcXG5cXHQjaWZkZWYgVVNFX1NIQURPV01BUFxcblxcdCNpZiBOVU1fRElSX0xJR0hUX1NIQURPV1MgPiAwXFxuXFx0RGlyZWN0aW9uYWxMaWdodFNoYWRvdyBkaXJlY3Rpb25hbExpZ2h0O1xcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcXG5cXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fRElSX0xJR0hUX1NIQURPV1M7IGkgKysgKSB7XFxuXFx0XFx0ZGlyZWN0aW9uYWxMaWdodCA9IGRpcmVjdGlvbmFsTGlnaHRTaGFkb3dzWyBpIF07XFxuXFx0XFx0c2hhZG93ICo9IHJlY2VpdmVTaGFkb3cgPyBnZXRTaGFkb3coIGRpcmVjdGlvbmFsU2hhZG93TWFwWyBpIF0sIGRpcmVjdGlvbmFsTGlnaHQuc2hhZG93TWFwU2l6ZSwgZGlyZWN0aW9uYWxMaWdodC5zaGFkb3dJbnRlbnNpdHksIGRpcmVjdGlvbmFsTGlnaHQuc2hhZG93QmlhcywgZGlyZWN0aW9uYWxMaWdodC5zaGFkb3dSYWRpdXMsIHZEaXJlY3Rpb25hbFNoYWRvd0Nvb3JkWyBpIF0gKSA6IDEuMDtcXG5cXHR9XFxuXFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcXG5cXHQjZW5kaWZcXG5cXHQjaWYgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHRTcG90TGlnaHRTaGFkb3cgc3BvdExpZ2h0O1xcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcXG5cXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fU1BPVF9MSUdIVF9TSEFET1dTOyBpICsrICkge1xcblxcdFxcdHNwb3RMaWdodCA9IHNwb3RMaWdodFNoYWRvd3NbIGkgXTtcXG5cXHRcXHRzaGFkb3cgKj0gcmVjZWl2ZVNoYWRvdyA/IGdldFNoYWRvdyggc3BvdFNoYWRvd01hcFsgaSBdLCBzcG90TGlnaHQuc2hhZG93TWFwU2l6ZSwgc3BvdExpZ2h0LnNoYWRvd0ludGVuc2l0eSwgc3BvdExpZ2h0LnNoYWRvd0JpYXMsIHNwb3RMaWdodC5zaGFkb3dSYWRpdXMsIHZTcG90TGlnaHRDb29yZFsgaSBdICkgOiAxLjA7XFxuXFx0fVxcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXFxuXFx0I2VuZGlmXFxuXFx0I2lmIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTID4gMFxcblxcdFBvaW50TGlnaHRTaGFkb3cgcG9pbnRMaWdodDtcXG5cXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XFxuXFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1M7IGkgKysgKSB7XFxuXFx0XFx0cG9pbnRMaWdodCA9IHBvaW50TGlnaHRTaGFkb3dzWyBpIF07XFxuXFx0XFx0c2hhZG93ICo9IHJlY2VpdmVTaGFkb3cgPyBnZXRQb2ludFNoYWRvdyggcG9pbnRTaGFkb3dNYXBbIGkgXSwgcG9pbnRMaWdodC5zaGFkb3dNYXBTaXplLCBwb2ludExpZ2h0LnNoYWRvd0ludGVuc2l0eSwgcG9pbnRMaWdodC5zaGFkb3dCaWFzLCBwb2ludExpZ2h0LnNoYWRvd1JhZGl1cywgdlBvaW50U2hhZG93Q29vcmRbIGkgXSwgcG9pbnRMaWdodC5zaGFkb3dDYW1lcmFOZWFyLCBwb2ludExpZ2h0LnNoYWRvd0NhbWVyYUZhciApIDogMS4wO1xcblxcdH1cXG5cXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxcblxcdCNlbmRpZlxcblxcdCNlbmRpZlxcblxcdHJldHVybiBzaGFkb3c7XFxufVwiO1xuXG52YXIgc2tpbmJhc2VfdmVydGV4ID0gXCIjaWZkZWYgVVNFX1NLSU5OSU5HXFxuXFx0bWF0NCBib25lTWF0WCA9IGdldEJvbmVNYXRyaXgoIHNraW5JbmRleC54ICk7XFxuXFx0bWF0NCBib25lTWF0WSA9IGdldEJvbmVNYXRyaXgoIHNraW5JbmRleC55ICk7XFxuXFx0bWF0NCBib25lTWF0WiA9IGdldEJvbmVNYXRyaXgoIHNraW5JbmRleC56ICk7XFxuXFx0bWF0NCBib25lTWF0VyA9IGdldEJvbmVNYXRyaXgoIHNraW5JbmRleC53ICk7XFxuI2VuZGlmXCI7XG5cbnZhciBza2lubmluZ19wYXJzX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9TS0lOTklOR1xcblxcdHVuaWZvcm0gbWF0NCBiaW5kTWF0cml4O1xcblxcdHVuaWZvcm0gbWF0NCBiaW5kTWF0cml4SW52ZXJzZTtcXG5cXHR1bmlmb3JtIGhpZ2hwIHNhbXBsZXIyRCBib25lVGV4dHVyZTtcXG5cXHRtYXQ0IGdldEJvbmVNYXRyaXgoIGNvbnN0IGluIGZsb2F0IGkgKSB7XFxuXFx0XFx0aW50IHNpemUgPSB0ZXh0dXJlU2l6ZSggYm9uZVRleHR1cmUsIDAgKS54O1xcblxcdFxcdGludCBqID0gaW50KCBpICkgKiA0O1xcblxcdFxcdGludCB4ID0gaiAlIHNpemU7XFxuXFx0XFx0aW50IHkgPSBqIC8gc2l6ZTtcXG5cXHRcXHR2ZWM0IHYxID0gdGV4ZWxGZXRjaCggYm9uZVRleHR1cmUsIGl2ZWMyKCB4LCB5ICksIDAgKTtcXG5cXHRcXHR2ZWM0IHYyID0gdGV4ZWxGZXRjaCggYm9uZVRleHR1cmUsIGl2ZWMyKCB4ICsgMSwgeSApLCAwICk7XFxuXFx0XFx0dmVjNCB2MyA9IHRleGVsRmV0Y2goIGJvbmVUZXh0dXJlLCBpdmVjMiggeCArIDIsIHkgKSwgMCApO1xcblxcdFxcdHZlYzQgdjQgPSB0ZXhlbEZldGNoKCBib25lVGV4dHVyZSwgaXZlYzIoIHggKyAzLCB5ICksIDAgKTtcXG5cXHRcXHRyZXR1cm4gbWF0NCggdjEsIHYyLCB2MywgdjQgKTtcXG5cXHR9XFxuI2VuZGlmXCI7XG5cbnZhciBza2lubmluZ192ZXJ0ZXggPSBcIiNpZmRlZiBVU0VfU0tJTk5JTkdcXG5cXHR2ZWM0IHNraW5WZXJ0ZXggPSBiaW5kTWF0cml4ICogdmVjNCggdHJhbnNmb3JtZWQsIDEuMCApO1xcblxcdHZlYzQgc2tpbm5lZCA9IHZlYzQoIDAuMCApO1xcblxcdHNraW5uZWQgKz0gYm9uZU1hdFggKiBza2luVmVydGV4ICogc2tpbldlaWdodC54O1xcblxcdHNraW5uZWQgKz0gYm9uZU1hdFkgKiBza2luVmVydGV4ICogc2tpbldlaWdodC55O1xcblxcdHNraW5uZWQgKz0gYm9uZU1hdFogKiBza2luVmVydGV4ICogc2tpbldlaWdodC56O1xcblxcdHNraW5uZWQgKz0gYm9uZU1hdFcgKiBza2luVmVydGV4ICogc2tpbldlaWdodC53O1xcblxcdHRyYW5zZm9ybWVkID0gKCBiaW5kTWF0cml4SW52ZXJzZSAqIHNraW5uZWQgKS54eXo7XFxuI2VuZGlmXCI7XG5cbnZhciBza2lubm9ybWFsX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9TS0lOTklOR1xcblxcdG1hdDQgc2tpbk1hdHJpeCA9IG1hdDQoIDAuMCApO1xcblxcdHNraW5NYXRyaXggKz0gc2tpbldlaWdodC54ICogYm9uZU1hdFg7XFxuXFx0c2tpbk1hdHJpeCArPSBza2luV2VpZ2h0LnkgKiBib25lTWF0WTtcXG5cXHRza2luTWF0cml4ICs9IHNraW5XZWlnaHQueiAqIGJvbmVNYXRaO1xcblxcdHNraW5NYXRyaXggKz0gc2tpbldlaWdodC53ICogYm9uZU1hdFc7XFxuXFx0c2tpbk1hdHJpeCA9IGJpbmRNYXRyaXhJbnZlcnNlICogc2tpbk1hdHJpeCAqIGJpbmRNYXRyaXg7XFxuXFx0b2JqZWN0Tm9ybWFsID0gdmVjNCggc2tpbk1hdHJpeCAqIHZlYzQoIG9iamVjdE5vcm1hbCwgMC4wICkgKS54eXo7XFxuXFx0I2lmZGVmIFVTRV9UQU5HRU5UXFxuXFx0XFx0b2JqZWN0VGFuZ2VudCA9IHZlYzQoIHNraW5NYXRyaXggKiB2ZWM0KCBvYmplY3RUYW5nZW50LCAwLjAgKSApLnh5ejtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcIjtcblxudmFyIHNwZWN1bGFybWFwX2ZyYWdtZW50ID0gXCJmbG9hdCBzcGVjdWxhclN0cmVuZ3RoO1xcbiNpZmRlZiBVU0VfU1BFQ1VMQVJNQVBcXG5cXHR2ZWM0IHRleGVsU3BlY3VsYXIgPSB0ZXh0dXJlMkQoIHNwZWN1bGFyTWFwLCB2U3BlY3VsYXJNYXBVdiApO1xcblxcdHNwZWN1bGFyU3RyZW5ndGggPSB0ZXhlbFNwZWN1bGFyLnI7XFxuI2Vsc2VcXG5cXHRzcGVjdWxhclN0cmVuZ3RoID0gMS4wO1xcbiNlbmRpZlwiO1xuXG52YXIgc3BlY3VsYXJtYXBfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9TUEVDVUxBUk1BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIHNwZWN1bGFyTWFwO1xcbiNlbmRpZlwiO1xuXG52YXIgdG9uZW1hcHBpbmdfZnJhZ21lbnQgPSBcIiNpZiBkZWZpbmVkKCBUT05FX01BUFBJTkcgKVxcblxcdGdsX0ZyYWdDb2xvci5yZ2IgPSB0b25lTWFwcGluZyggZ2xfRnJhZ0NvbG9yLnJnYiApO1xcbiNlbmRpZlwiO1xuXG52YXIgdG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudCA9IFwiI2lmbmRlZiBzYXR1cmF0ZVxcbiNkZWZpbmUgc2F0dXJhdGUoIGEgKSBjbGFtcCggYSwgMC4wLCAxLjAgKVxcbiNlbmRpZlxcbnVuaWZvcm0gZmxvYXQgdG9uZU1hcHBpbmdFeHBvc3VyZTtcXG52ZWMzIExpbmVhclRvbmVNYXBwaW5nKCB2ZWMzIGNvbG9yICkge1xcblxcdHJldHVybiBzYXR1cmF0ZSggdG9uZU1hcHBpbmdFeHBvc3VyZSAqIGNvbG9yICk7XFxufVxcbnZlYzMgUmVpbmhhcmRUb25lTWFwcGluZyggdmVjMyBjb2xvciApIHtcXG5cXHRjb2xvciAqPSB0b25lTWFwcGluZ0V4cG9zdXJlO1xcblxcdHJldHVybiBzYXR1cmF0ZSggY29sb3IgLyAoIHZlYzMoIDEuMCApICsgY29sb3IgKSApO1xcbn1cXG52ZWMzIE9wdGltaXplZENpbmVvblRvbmVNYXBwaW5nKCB2ZWMzIGNvbG9yICkge1xcblxcdGNvbG9yICo9IHRvbmVNYXBwaW5nRXhwb3N1cmU7XFxuXFx0Y29sb3IgPSBtYXgoIHZlYzMoIDAuMCApLCBjb2xvciAtIDAuMDA0ICk7XFxuXFx0cmV0dXJuIHBvdyggKCBjb2xvciAqICggNi4yICogY29sb3IgKyAwLjUgKSApIC8gKCBjb2xvciAqICggNi4yICogY29sb3IgKyAxLjcgKSArIDAuMDYgKSwgdmVjMyggMi4yICkgKTtcXG59XFxudmVjMyBSUlRBbmRPRFRGaXQoIHZlYzMgdiApIHtcXG5cXHR2ZWMzIGEgPSB2ICogKCB2ICsgMC4wMjQ1Nzg2ICkgLSAwLjAwMDA5MDUzNztcXG5cXHR2ZWMzIGIgPSB2ICogKCAwLjk4MzcyOSAqIHYgKyAwLjQzMjk1MTAgKSArIDAuMjM4MDgxO1xcblxcdHJldHVybiBhIC8gYjtcXG59XFxudmVjMyBBQ0VTRmlsbWljVG9uZU1hcHBpbmcoIHZlYzMgY29sb3IgKSB7XFxuXFx0Y29uc3QgbWF0MyBBQ0VTSW5wdXRNYXQgPSBtYXQzKFxcblxcdFxcdHZlYzMoIDAuNTk3MTksIDAuMDc2MDAsIDAuMDI4NDAgKSxcXHRcXHR2ZWMzKCAwLjM1NDU4LCAwLjkwODM0LCAwLjEzMzgzICksXFxuXFx0XFx0dmVjMyggMC4wNDgyMywgMC4wMTU2NiwgMC44Mzc3NyApXFxuXFx0KTtcXG5cXHRjb25zdCBtYXQzIEFDRVNPdXRwdXRNYXQgPSBtYXQzKFxcblxcdFxcdHZlYzMoICAxLjYwNDc1LCAtMC4xMDIwOCwgLTAuMDAzMjcgKSxcXHRcXHR2ZWMzKCAtMC41MzEwOCwgIDEuMTA4MTMsIC0wLjA3Mjc2ICksXFxuXFx0XFx0dmVjMyggLTAuMDczNjcsIC0wLjAwNjA1LCAgMS4wNzYwMiApXFxuXFx0KTtcXG5cXHRjb2xvciAqPSB0b25lTWFwcGluZ0V4cG9zdXJlIC8gMC42O1xcblxcdGNvbG9yID0gQUNFU0lucHV0TWF0ICogY29sb3I7XFxuXFx0Y29sb3IgPSBSUlRBbmRPRFRGaXQoIGNvbG9yICk7XFxuXFx0Y29sb3IgPSBBQ0VTT3V0cHV0TWF0ICogY29sb3I7XFxuXFx0cmV0dXJuIHNhdHVyYXRlKCBjb2xvciApO1xcbn1cXG5jb25zdCBtYXQzIExJTkVBUl9SRUMyMDIwX1RPX0xJTkVBUl9TUkdCID0gbWF0MyhcXG5cXHR2ZWMzKCAxLjY2MDUsIC0gMC4xMjQ2LCAtIDAuMDE4MiApLFxcblxcdHZlYzMoIC0gMC41ODc2LCAxLjEzMjksIC0gMC4xMDA2ICksXFxuXFx0dmVjMyggLSAwLjA3MjgsIC0gMC4wMDgzLCAxLjExODcgKVxcbik7XFxuY29uc3QgbWF0MyBMSU5FQVJfU1JHQl9UT19MSU5FQVJfUkVDMjAyMCA9IG1hdDMoXFxuXFx0dmVjMyggMC42Mjc0LCAwLjA2OTEsIDAuMDE2NCApLFxcblxcdHZlYzMoIDAuMzI5MywgMC45MTk1LCAwLjA4ODAgKSxcXG5cXHR2ZWMzKCAwLjA0MzMsIDAuMDExMywgMC44OTU2IClcXG4pO1xcbnZlYzMgYWd4RGVmYXVsdENvbnRyYXN0QXBwcm94KCB2ZWMzIHggKSB7XFxuXFx0dmVjMyB4MiA9IHggKiB4O1xcblxcdHZlYzMgeDQgPSB4MiAqIHgyO1xcblxcdHJldHVybiArIDE1LjUgKiB4NCAqIHgyXFxuXFx0XFx0LSA0MC4xNCAqIHg0ICogeFxcblxcdFxcdCsgMzEuOTYgKiB4NFxcblxcdFxcdC0gNi44NjggKiB4MiAqIHhcXG5cXHRcXHQrIDAuNDI5OCAqIHgyXFxuXFx0XFx0KyAwLjExOTEgKiB4XFxuXFx0XFx0LSAwLjAwMjMyO1xcbn1cXG52ZWMzIEFnWFRvbmVNYXBwaW5nKCB2ZWMzIGNvbG9yICkge1xcblxcdGNvbnN0IG1hdDMgQWdYSW5zZXRNYXRyaXggPSBtYXQzKFxcblxcdFxcdHZlYzMoIDAuODU2NjI3MTUzMzE1OTgzLCAwLjEzNzMxODk3MjkyOTg0NywgMC4xMTE4OTgyMTI5OTk5NSApLFxcblxcdFxcdHZlYzMoIDAuMDk1MTIxMjQwNTM4MTU4OCwgMC43NjEyNDE5OTA2MDI1OTEsIDAuMDc2Nzk5NDE4NjAzMTkwMyApLFxcblxcdFxcdHZlYzMoIDAuMDQ4MjUxNjA2MTQ1ODU4MywgMC4xMDE0MzkwMzY0Njc1NjIsIDAuODExMzAyMzY4Mzk2ODU5IClcXG5cXHQpO1xcblxcdGNvbnN0IG1hdDMgQWdYT3V0c2V0TWF0cml4ID0gbWF0MyhcXG5cXHRcXHR2ZWMzKCAxLjEyNzEwMDU4MTgxNDQzNjgsIC0gMC4xNDEzMjk3NjM0OTg0MzgzLCAtIDAuMTQxMzI5NzYzNDk4NDM4MjYgKSxcXG5cXHRcXHR2ZWMzKCAtIDAuMTEwNjA2NjQzMDk2NjAzMjMsIDEuMTU3ODIzNzAyMjE2MjcyLCAtIDAuMTEwNjA2NjQzMDk2NjAyOTQgKSxcXG5cXHRcXHR2ZWMzKCAtIDAuMDE2NDkzOTM4NzE3ODM0NTczLCAtIDAuMDE2NDkzOTM4NzE3ODM0MjU3LCAxLjI1MTkzNjQwNjU5NTA0MDUgKVxcblxcdCk7XFxuXFx0Y29uc3QgZmxvYXQgQWd4TWluRXYgPSAtIDEyLjQ3MzkzO1xcdGNvbnN0IGZsb2F0IEFneE1heEV2ID0gNC4wMjYwNjk7XFxuXFx0Y29sb3IgKj0gdG9uZU1hcHBpbmdFeHBvc3VyZTtcXG5cXHRjb2xvciA9IExJTkVBUl9TUkdCX1RPX0xJTkVBUl9SRUMyMDIwICogY29sb3I7XFxuXFx0Y29sb3IgPSBBZ1hJbnNldE1hdHJpeCAqIGNvbG9yO1xcblxcdGNvbG9yID0gbWF4KCBjb2xvciwgMWUtMTAgKTtcXHRjb2xvciA9IGxvZzIoIGNvbG9yICk7XFxuXFx0Y29sb3IgPSAoIGNvbG9yIC0gQWd4TWluRXYgKSAvICggQWd4TWF4RXYgLSBBZ3hNaW5FdiApO1xcblxcdGNvbG9yID0gY2xhbXAoIGNvbG9yLCAwLjAsIDEuMCApO1xcblxcdGNvbG9yID0gYWd4RGVmYXVsdENvbnRyYXN0QXBwcm94KCBjb2xvciApO1xcblxcdGNvbG9yID0gQWdYT3V0c2V0TWF0cml4ICogY29sb3I7XFxuXFx0Y29sb3IgPSBwb3coIG1heCggdmVjMyggMC4wICksIGNvbG9yICksIHZlYzMoIDIuMiApICk7XFxuXFx0Y29sb3IgPSBMSU5FQVJfUkVDMjAyMF9UT19MSU5FQVJfU1JHQiAqIGNvbG9yO1xcblxcdGNvbG9yID0gY2xhbXAoIGNvbG9yLCAwLjAsIDEuMCApO1xcblxcdHJldHVybiBjb2xvcjtcXG59XFxudmVjMyBOZXV0cmFsVG9uZU1hcHBpbmcoIHZlYzMgY29sb3IgKSB7XFxuXFx0Y29uc3QgZmxvYXQgU3RhcnRDb21wcmVzc2lvbiA9IDAuOCAtIDAuMDQ7XFxuXFx0Y29uc3QgZmxvYXQgRGVzYXR1cmF0aW9uID0gMC4xNTtcXG5cXHRjb2xvciAqPSB0b25lTWFwcGluZ0V4cG9zdXJlO1xcblxcdGZsb2F0IHggPSBtaW4oIGNvbG9yLnIsIG1pbiggY29sb3IuZywgY29sb3IuYiApICk7XFxuXFx0ZmxvYXQgb2Zmc2V0ID0geCA8IDAuMDggPyB4IC0gNi4yNSAqIHggKiB4IDogMC4wNDtcXG5cXHRjb2xvciAtPSBvZmZzZXQ7XFxuXFx0ZmxvYXQgcGVhayA9IG1heCggY29sb3IuciwgbWF4KCBjb2xvci5nLCBjb2xvci5iICkgKTtcXG5cXHRpZiAoIHBlYWsgPCBTdGFydENvbXByZXNzaW9uICkgcmV0dXJuIGNvbG9yO1xcblxcdGZsb2F0IGQgPSAxLiAtIFN0YXJ0Q29tcHJlc3Npb247XFxuXFx0ZmxvYXQgbmV3UGVhayA9IDEuIC0gZCAqIGQgLyAoIHBlYWsgKyBkIC0gU3RhcnRDb21wcmVzc2lvbiApO1xcblxcdGNvbG9yICo9IG5ld1BlYWsgLyBwZWFrO1xcblxcdGZsb2F0IGcgPSAxLiAtIDEuIC8gKCBEZXNhdHVyYXRpb24gKiAoIHBlYWsgLSBuZXdQZWFrICkgKyAxLiApO1xcblxcdHJldHVybiBtaXgoIGNvbG9yLCB2ZWMzKCBuZXdQZWFrICksIGcgKTtcXG59XFxudmVjMyBDdXN0b21Ub25lTWFwcGluZyggdmVjMyBjb2xvciApIHsgcmV0dXJuIGNvbG9yOyB9XCI7XG5cbnZhciB0cmFuc21pc3Npb25fZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OXFxuXFx0bWF0ZXJpYWwudHJhbnNtaXNzaW9uID0gdHJhbnNtaXNzaW9uO1xcblxcdG1hdGVyaWFsLnRyYW5zbWlzc2lvbkFscGhhID0gMS4wO1xcblxcdG1hdGVyaWFsLnRoaWNrbmVzcyA9IHRoaWNrbmVzcztcXG5cXHRtYXRlcmlhbC5hdHRlbnVhdGlvbkRpc3RhbmNlID0gYXR0ZW51YXRpb25EaXN0YW5jZTtcXG5cXHRtYXRlcmlhbC5hdHRlbnVhdGlvbkNvbG9yID0gYXR0ZW51YXRpb25Db2xvcjtcXG5cXHQjaWZkZWYgVVNFX1RSQU5TTUlTU0lPTk1BUFxcblxcdFxcdG1hdGVyaWFsLnRyYW5zbWlzc2lvbiAqPSB0ZXh0dXJlMkQoIHRyYW5zbWlzc2lvbk1hcCwgdlRyYW5zbWlzc2lvbk1hcFV2ICkucjtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX1RISUNLTkVTU01BUFxcblxcdFxcdG1hdGVyaWFsLnRoaWNrbmVzcyAqPSB0ZXh0dXJlMkQoIHRoaWNrbmVzc01hcCwgdlRoaWNrbmVzc01hcFV2ICkuZztcXG5cXHQjZW5kaWZcXG5cXHR2ZWMzIHBvcyA9IHZXb3JsZFBvc2l0aW9uO1xcblxcdHZlYzMgdiA9IG5vcm1hbGl6ZSggY2FtZXJhUG9zaXRpb24gLSBwb3MgKTtcXG5cXHR2ZWMzIG4gPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCBub3JtYWwsIHZpZXdNYXRyaXggKTtcXG5cXHR2ZWM0IHRyYW5zbWl0dGVkID0gZ2V0SUJMVm9sdW1lUmVmcmFjdGlvbihcXG5cXHRcXHRuLCB2LCBtYXRlcmlhbC5yb3VnaG5lc3MsIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciwgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciwgbWF0ZXJpYWwuc3BlY3VsYXJGOTAsXFxuXFx0XFx0cG9zLCBtb2RlbE1hdHJpeCwgdmlld01hdHJpeCwgcHJvamVjdGlvbk1hdHJpeCwgbWF0ZXJpYWwuZGlzcGVyc2lvbiwgbWF0ZXJpYWwuaW9yLCBtYXRlcmlhbC50aGlja25lc3MsXFxuXFx0XFx0bWF0ZXJpYWwuYXR0ZW51YXRpb25Db2xvciwgbWF0ZXJpYWwuYXR0ZW51YXRpb25EaXN0YW5jZSApO1xcblxcdG1hdGVyaWFsLnRyYW5zbWlzc2lvbkFscGhhID0gbWl4KCBtYXRlcmlhbC50cmFuc21pc3Npb25BbHBoYSwgdHJhbnNtaXR0ZWQuYSwgbWF0ZXJpYWwudHJhbnNtaXNzaW9uICk7XFxuXFx0dG90YWxEaWZmdXNlID0gbWl4KCB0b3RhbERpZmZ1c2UsIHRyYW5zbWl0dGVkLnJnYiwgbWF0ZXJpYWwudHJhbnNtaXNzaW9uICk7XFxuI2VuZGlmXCI7XG5cbnZhciB0cmFuc21pc3Npb25fcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9UUkFOU01JU1NJT05cXG5cXHR1bmlmb3JtIGZsb2F0IHRyYW5zbWlzc2lvbjtcXG5cXHR1bmlmb3JtIGZsb2F0IHRoaWNrbmVzcztcXG5cXHR1bmlmb3JtIGZsb2F0IGF0dGVudWF0aW9uRGlzdGFuY2U7XFxuXFx0dW5pZm9ybSB2ZWMzIGF0dGVudWF0aW9uQ29sb3I7XFxuXFx0I2lmZGVmIFVTRV9UUkFOU01JU1NJT05NQVBcXG5cXHRcXHR1bmlmb3JtIHNhbXBsZXIyRCB0cmFuc21pc3Npb25NYXA7XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIFVTRV9USElDS05FU1NNQVBcXG5cXHRcXHR1bmlmb3JtIHNhbXBsZXIyRCB0aGlja25lc3NNYXA7XFxuXFx0I2VuZGlmXFxuXFx0dW5pZm9ybSB2ZWMyIHRyYW5zbWlzc2lvblNhbXBsZXJTaXplO1xcblxcdHVuaWZvcm0gc2FtcGxlcjJEIHRyYW5zbWlzc2lvblNhbXBsZXJNYXA7XFxuXFx0dW5pZm9ybSBtYXQ0IG1vZGVsTWF0cml4O1xcblxcdHVuaWZvcm0gbWF0NCBwcm9qZWN0aW9uTWF0cml4O1xcblxcdHZhcnlpbmcgdmVjMyB2V29ybGRQb3NpdGlvbjtcXG5cXHRmbG9hdCB3MCggZmxvYXQgYSApIHtcXG5cXHRcXHRyZXR1cm4gKCAxLjAgLyA2LjAgKSAqICggYSAqICggYSAqICggLSBhICsgMy4wICkgLSAzLjAgKSArIDEuMCApO1xcblxcdH1cXG5cXHRmbG9hdCB3MSggZmxvYXQgYSApIHtcXG5cXHRcXHRyZXR1cm4gKCAxLjAgLyA2LjAgKSAqICggYSAqICBhICogKCAzLjAgKiBhIC0gNi4wICkgKyA0LjAgKTtcXG5cXHR9XFxuXFx0ZmxvYXQgdzIoIGZsb2F0IGEgKXtcXG5cXHRcXHRyZXR1cm4gKCAxLjAgLyA2LjAgKSAqICggYSAqICggYSAqICggLSAzLjAgKiBhICsgMy4wICkgKyAzLjAgKSArIDEuMCApO1xcblxcdH1cXG5cXHRmbG9hdCB3MyggZmxvYXQgYSApIHtcXG5cXHRcXHRyZXR1cm4gKCAxLjAgLyA2LjAgKSAqICggYSAqIGEgKiBhICk7XFxuXFx0fVxcblxcdGZsb2F0IGcwKCBmbG9hdCBhICkge1xcblxcdFxcdHJldHVybiB3MCggYSApICsgdzEoIGEgKTtcXG5cXHR9XFxuXFx0ZmxvYXQgZzEoIGZsb2F0IGEgKSB7XFxuXFx0XFx0cmV0dXJuIHcyKCBhICkgKyB3MyggYSApO1xcblxcdH1cXG5cXHRmbG9hdCBoMCggZmxvYXQgYSApIHtcXG5cXHRcXHRyZXR1cm4gLSAxLjAgKyB3MSggYSApIC8gKCB3MCggYSApICsgdzEoIGEgKSApO1xcblxcdH1cXG5cXHRmbG9hdCBoMSggZmxvYXQgYSApIHtcXG5cXHRcXHRyZXR1cm4gMS4wICsgdzMoIGEgKSAvICggdzIoIGEgKSArIHczKCBhICkgKTtcXG5cXHR9XFxuXFx0dmVjNCBiaWN1YmljKCBzYW1wbGVyMkQgdGV4LCB2ZWMyIHV2LCB2ZWM0IHRleGVsU2l6ZSwgZmxvYXQgbG9kICkge1xcblxcdFxcdHV2ID0gdXYgKiB0ZXhlbFNpemUuencgKyAwLjU7XFxuXFx0XFx0dmVjMiBpdXYgPSBmbG9vciggdXYgKTtcXG5cXHRcXHR2ZWMyIGZ1diA9IGZyYWN0KCB1diApO1xcblxcdFxcdGZsb2F0IGcweCA9IGcwKCBmdXYueCApO1xcblxcdFxcdGZsb2F0IGcxeCA9IGcxKCBmdXYueCApO1xcblxcdFxcdGZsb2F0IGgweCA9IGgwKCBmdXYueCApO1xcblxcdFxcdGZsb2F0IGgxeCA9IGgxKCBmdXYueCApO1xcblxcdFxcdGZsb2F0IGgweSA9IGgwKCBmdXYueSApO1xcblxcdFxcdGZsb2F0IGgxeSA9IGgxKCBmdXYueSApO1xcblxcdFxcdHZlYzIgcDAgPSAoIHZlYzIoIGl1di54ICsgaDB4LCBpdXYueSArIGgweSApIC0gMC41ICkgKiB0ZXhlbFNpemUueHk7XFxuXFx0XFx0dmVjMiBwMSA9ICggdmVjMiggaXV2LnggKyBoMXgsIGl1di55ICsgaDB5ICkgLSAwLjUgKSAqIHRleGVsU2l6ZS54eTtcXG5cXHRcXHR2ZWMyIHAyID0gKCB2ZWMyKCBpdXYueCArIGgweCwgaXV2LnkgKyBoMXkgKSAtIDAuNSApICogdGV4ZWxTaXplLnh5O1xcblxcdFxcdHZlYzIgcDMgPSAoIHZlYzIoIGl1di54ICsgaDF4LCBpdXYueSArIGgxeSApIC0gMC41ICkgKiB0ZXhlbFNpemUueHk7XFxuXFx0XFx0cmV0dXJuIGcwKCBmdXYueSApICogKCBnMHggKiB0ZXh0dXJlTG9kKCB0ZXgsIHAwLCBsb2QgKSArIGcxeCAqIHRleHR1cmVMb2QoIHRleCwgcDEsIGxvZCApICkgK1xcblxcdFxcdFxcdGcxKCBmdXYueSApICogKCBnMHggKiB0ZXh0dXJlTG9kKCB0ZXgsIHAyLCBsb2QgKSArIGcxeCAqIHRleHR1cmVMb2QoIHRleCwgcDMsIGxvZCApICk7XFxuXFx0fVxcblxcdHZlYzQgdGV4dHVyZUJpY3ViaWMoIHNhbXBsZXIyRCBzYW1wbGVyLCB2ZWMyIHV2LCBmbG9hdCBsb2QgKSB7XFxuXFx0XFx0dmVjMiBmTG9kU2l6ZSA9IHZlYzIoIHRleHR1cmVTaXplKCBzYW1wbGVyLCBpbnQoIGxvZCApICkgKTtcXG5cXHRcXHR2ZWMyIGNMb2RTaXplID0gdmVjMiggdGV4dHVyZVNpemUoIHNhbXBsZXIsIGludCggbG9kICsgMS4wICkgKSApO1xcblxcdFxcdHZlYzIgZkxvZFNpemVJbnYgPSAxLjAgLyBmTG9kU2l6ZTtcXG5cXHRcXHR2ZWMyIGNMb2RTaXplSW52ID0gMS4wIC8gY0xvZFNpemU7XFxuXFx0XFx0dmVjNCBmU2FtcGxlID0gYmljdWJpYyggc2FtcGxlciwgdXYsIHZlYzQoIGZMb2RTaXplSW52LCBmTG9kU2l6ZSApLCBmbG9vciggbG9kICkgKTtcXG5cXHRcXHR2ZWM0IGNTYW1wbGUgPSBiaWN1YmljKCBzYW1wbGVyLCB1diwgdmVjNCggY0xvZFNpemVJbnYsIGNMb2RTaXplICksIGNlaWwoIGxvZCApICk7XFxuXFx0XFx0cmV0dXJuIG1peCggZlNhbXBsZSwgY1NhbXBsZSwgZnJhY3QoIGxvZCApICk7XFxuXFx0fVxcblxcdHZlYzMgZ2V0Vm9sdW1lVHJhbnNtaXNzaW9uUmF5KCBjb25zdCBpbiB2ZWMzIG4sIGNvbnN0IGluIHZlYzMgdiwgY29uc3QgaW4gZmxvYXQgdGhpY2tuZXNzLCBjb25zdCBpbiBmbG9hdCBpb3IsIGNvbnN0IGluIG1hdDQgbW9kZWxNYXRyaXggKSB7XFxuXFx0XFx0dmVjMyByZWZyYWN0aW9uVmVjdG9yID0gcmVmcmFjdCggLSB2LCBub3JtYWxpemUoIG4gKSwgMS4wIC8gaW9yICk7XFxuXFx0XFx0dmVjMyBtb2RlbFNjYWxlO1xcblxcdFxcdG1vZGVsU2NhbGUueCA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDAgXS54eXogKSApO1xcblxcdFxcdG1vZGVsU2NhbGUueSA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDEgXS54eXogKSApO1xcblxcdFxcdG1vZGVsU2NhbGUueiA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDIgXS54eXogKSApO1xcblxcdFxcdHJldHVybiBub3JtYWxpemUoIHJlZnJhY3Rpb25WZWN0b3IgKSAqIHRoaWNrbmVzcyAqIG1vZGVsU2NhbGU7XFxuXFx0fVxcblxcdGZsb2F0IGFwcGx5SW9yVG9Sb3VnaG5lc3MoIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcywgY29uc3QgaW4gZmxvYXQgaW9yICkge1xcblxcdFxcdHJldHVybiByb3VnaG5lc3MgKiBjbGFtcCggaW9yICogMi4wIC0gMi4wLCAwLjAsIDEuMCApO1xcblxcdH1cXG5cXHR2ZWM0IGdldFRyYW5zbWlzc2lvblNhbXBsZSggY29uc3QgaW4gdmVjMiBmcmFnQ29vcmQsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcywgY29uc3QgaW4gZmxvYXQgaW9yICkge1xcblxcdFxcdGZsb2F0IGxvZCA9IGxvZzIoIHRyYW5zbWlzc2lvblNhbXBsZXJTaXplLnggKSAqIGFwcGx5SW9yVG9Sb3VnaG5lc3MoIHJvdWdobmVzcywgaW9yICk7XFxuXFx0XFx0cmV0dXJuIHRleHR1cmVCaWN1YmljKCB0cmFuc21pc3Npb25TYW1wbGVyTWFwLCBmcmFnQ29vcmQueHksIGxvZCApO1xcblxcdH1cXG5cXHR2ZWMzIHZvbHVtZUF0dGVudWF0aW9uKCBjb25zdCBpbiBmbG9hdCB0cmFuc21pc3Npb25EaXN0YW5jZSwgY29uc3QgaW4gdmVjMyBhdHRlbnVhdGlvbkNvbG9yLCBjb25zdCBpbiBmbG9hdCBhdHRlbnVhdGlvbkRpc3RhbmNlICkge1xcblxcdFxcdGlmICggaXNpbmYoIGF0dGVudWF0aW9uRGlzdGFuY2UgKSApIHtcXG5cXHRcXHRcXHRyZXR1cm4gdmVjMyggMS4wICk7XFxuXFx0XFx0fSBlbHNlIHtcXG5cXHRcXHRcXHR2ZWMzIGF0dGVudWF0aW9uQ29lZmZpY2llbnQgPSAtbG9nKCBhdHRlbnVhdGlvbkNvbG9yICkgLyBhdHRlbnVhdGlvbkRpc3RhbmNlO1xcblxcdFxcdFxcdHZlYzMgdHJhbnNtaXR0YW5jZSA9IGV4cCggLSBhdHRlbnVhdGlvbkNvZWZmaWNpZW50ICogdHJhbnNtaXNzaW9uRGlzdGFuY2UgKTtcXHRcXHRcXHRyZXR1cm4gdHJhbnNtaXR0YW5jZTtcXG5cXHRcXHR9XFxuXFx0fVxcblxcdHZlYzQgZ2V0SUJMVm9sdW1lUmVmcmFjdGlvbiggY29uc3QgaW4gdmVjMyBuLCBjb25zdCBpbiB2ZWMzIHYsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcywgY29uc3QgaW4gdmVjMyBkaWZmdXNlQ29sb3IsXFxuXFx0XFx0Y29uc3QgaW4gdmVjMyBzcGVjdWxhckNvbG9yLCBjb25zdCBpbiBmbG9hdCBzcGVjdWxhckY5MCwgY29uc3QgaW4gdmVjMyBwb3NpdGlvbiwgY29uc3QgaW4gbWF0NCBtb2RlbE1hdHJpeCxcXG5cXHRcXHRjb25zdCBpbiBtYXQ0IHZpZXdNYXRyaXgsIGNvbnN0IGluIG1hdDQgcHJvak1hdHJpeCwgY29uc3QgaW4gZmxvYXQgZGlzcGVyc2lvbiwgY29uc3QgaW4gZmxvYXQgaW9yLCBjb25zdCBpbiBmbG9hdCB0aGlja25lc3MsXFxuXFx0XFx0Y29uc3QgaW4gdmVjMyBhdHRlbnVhdGlvbkNvbG9yLCBjb25zdCBpbiBmbG9hdCBhdHRlbnVhdGlvbkRpc3RhbmNlICkge1xcblxcdFxcdHZlYzQgdHJhbnNtaXR0ZWRMaWdodDtcXG5cXHRcXHR2ZWMzIHRyYW5zbWl0dGFuY2U7XFxuXFx0XFx0I2lmZGVmIFVTRV9ESVNQRVJTSU9OXFxuXFx0XFx0XFx0ZmxvYXQgaGFsZlNwcmVhZCA9ICggaW9yIC0gMS4wICkgKiAwLjAyNSAqIGRpc3BlcnNpb247XFxuXFx0XFx0XFx0dmVjMyBpb3JzID0gdmVjMyggaW9yIC0gaGFsZlNwcmVhZCwgaW9yLCBpb3IgKyBoYWxmU3ByZWFkICk7XFxuXFx0XFx0XFx0Zm9yICggaW50IGkgPSAwOyBpIDwgMzsgaSArKyApIHtcXG5cXHRcXHRcXHRcXHR2ZWMzIHRyYW5zbWlzc2lvblJheSA9IGdldFZvbHVtZVRyYW5zbWlzc2lvblJheSggbiwgdiwgdGhpY2tuZXNzLCBpb3JzWyBpIF0sIG1vZGVsTWF0cml4ICk7XFxuXFx0XFx0XFx0XFx0dmVjMyByZWZyYWN0ZWRSYXlFeGl0ID0gcG9zaXRpb24gKyB0cmFuc21pc3Npb25SYXk7XFxuXFx0XFx0XFxuXFx0XFx0XFx0XFx0dmVjNCBuZGNQb3MgPSBwcm9qTWF0cml4ICogdmlld01hdHJpeCAqIHZlYzQoIHJlZnJhY3RlZFJheUV4aXQsIDEuMCApO1xcblxcdFxcdFxcdFxcdHZlYzIgcmVmcmFjdGlvbkNvb3JkcyA9IG5kY1Bvcy54eSAvIG5kY1Bvcy53O1xcblxcdFxcdFxcdFxcdHJlZnJhY3Rpb25Db29yZHMgKz0gMS4wO1xcblxcdFxcdFxcdFxcdHJlZnJhY3Rpb25Db29yZHMgLz0gMi4wO1xcblxcdFxcdFxcblxcdFxcdFxcdFxcdHZlYzQgdHJhbnNtaXNzaW9uU2FtcGxlID0gZ2V0VHJhbnNtaXNzaW9uU2FtcGxlKCByZWZyYWN0aW9uQ29vcmRzLCByb3VnaG5lc3MsIGlvcnNbIGkgXSApO1xcblxcdFxcdFxcdFxcdHRyYW5zbWl0dGVkTGlnaHRbIGkgXSA9IHRyYW5zbWlzc2lvblNhbXBsZVsgaSBdO1xcblxcdFxcdFxcdFxcdHRyYW5zbWl0dGVkTGlnaHQuYSArPSB0cmFuc21pc3Npb25TYW1wbGUuYTtcXG5cXHRcXHRcXHRcXHR0cmFuc21pdHRhbmNlWyBpIF0gPSBkaWZmdXNlQ29sb3JbIGkgXSAqIHZvbHVtZUF0dGVudWF0aW9uKCBsZW5ndGgoIHRyYW5zbWlzc2lvblJheSApLCBhdHRlbnVhdGlvbkNvbG9yLCBhdHRlbnVhdGlvbkRpc3RhbmNlIClbIGkgXTtcXG5cXHRcXHRcXHR9XFxuXFx0XFx0XFx0dHJhbnNtaXR0ZWRMaWdodC5hIC89IDMuMDtcXG5cXHRcXHRcXG5cXHRcXHQjZWxzZVxcblxcdFxcdFxcblxcdFxcdFxcdHZlYzMgdHJhbnNtaXNzaW9uUmF5ID0gZ2V0Vm9sdW1lVHJhbnNtaXNzaW9uUmF5KCBuLCB2LCB0aGlja25lc3MsIGlvciwgbW9kZWxNYXRyaXggKTtcXG5cXHRcXHRcXHR2ZWMzIHJlZnJhY3RlZFJheUV4aXQgPSBwb3NpdGlvbiArIHRyYW5zbWlzc2lvblJheTtcXG5cXHRcXHRcXHR2ZWM0IG5kY1BvcyA9IHByb2pNYXRyaXggKiB2aWV3TWF0cml4ICogdmVjNCggcmVmcmFjdGVkUmF5RXhpdCwgMS4wICk7XFxuXFx0XFx0XFx0dmVjMiByZWZyYWN0aW9uQ29vcmRzID0gbmRjUG9zLnh5IC8gbmRjUG9zLnc7XFxuXFx0XFx0XFx0cmVmcmFjdGlvbkNvb3JkcyArPSAxLjA7XFxuXFx0XFx0XFx0cmVmcmFjdGlvbkNvb3JkcyAvPSAyLjA7XFxuXFx0XFx0XFx0dHJhbnNtaXR0ZWRMaWdodCA9IGdldFRyYW5zbWlzc2lvblNhbXBsZSggcmVmcmFjdGlvbkNvb3Jkcywgcm91Z2huZXNzLCBpb3IgKTtcXG5cXHRcXHRcXHR0cmFuc21pdHRhbmNlID0gZGlmZnVzZUNvbG9yICogdm9sdW1lQXR0ZW51YXRpb24oIGxlbmd0aCggdHJhbnNtaXNzaW9uUmF5ICksIGF0dGVudWF0aW9uQ29sb3IsIGF0dGVudWF0aW9uRGlzdGFuY2UgKTtcXG5cXHRcXHRcXG5cXHRcXHQjZW5kaWZcXG5cXHRcXHR2ZWMzIGF0dGVudWF0ZWRDb2xvciA9IHRyYW5zbWl0dGFuY2UgKiB0cmFuc21pdHRlZExpZ2h0LnJnYjtcXG5cXHRcXHR2ZWMzIEYgPSBFbnZpcm9ubWVudEJSREYoIG4sIHYsIHNwZWN1bGFyQ29sb3IsIHNwZWN1bGFyRjkwLCByb3VnaG5lc3MgKTtcXG5cXHRcXHRmbG9hdCB0cmFuc21pdHRhbmNlRmFjdG9yID0gKCB0cmFuc21pdHRhbmNlLnIgKyB0cmFuc21pdHRhbmNlLmcgKyB0cmFuc21pdHRhbmNlLmIgKSAvIDMuMDtcXG5cXHRcXHRyZXR1cm4gdmVjNCggKCAxLjAgLSBGICkgKiBhdHRlbnVhdGVkQ29sb3IsIDEuMCAtICggMS4wIC0gdHJhbnNtaXR0ZWRMaWdodC5hICkgKiB0cmFuc21pdHRhbmNlRmFjdG9yICk7XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgdXZfcGFyc19mcmFnbWVudCA9IFwiI2lmIGRlZmluZWQoIFVTRV9VViApIHx8IGRlZmluZWQoIFVTRV9BTklTT1RST1BZIClcXG5cXHR2YXJ5aW5nIHZlYzIgdlV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0FMUEhBTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZBbHBoYU1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTElHSFRNQVBcXG5cXHR2YXJ5aW5nIHZlYzIgdkxpZ2h0TWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9BT01BUFxcblxcdHZhcnlpbmcgdmVjMiB2QW9NYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0JVTVBNQVBcXG5cXHR2YXJ5aW5nIHZlYzIgdkJ1bXBNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX05PUk1BTE1BUFxcblxcdHZhcnlpbmcgdmVjMiB2Tm9ybWFsTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9FTUlTU0lWRU1BUFxcblxcdHZhcnlpbmcgdmVjMiB2RW1pc3NpdmVNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX01FVEFMTkVTU01BUFxcblxcdHZhcnlpbmcgdmVjMiB2TWV0YWxuZXNzTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9ST1VHSE5FU1NNQVBcXG5cXHR2YXJ5aW5nIHZlYzIgdlJvdWdobmVzc01hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQU5JU09UUk9QWU1BUFxcblxcdHZhcnlpbmcgdmVjMiB2QW5pc290cm9weU1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXRNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVBcXG5cXHR2YXJ5aW5nIHZlYzIgdkNsZWFyY29hdE5vcm1hbE1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUFxcblxcdHZhcnlpbmcgdmVjMiB2Q2xlYXJjb2F0Um91Z2huZXNzTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9JUklERVNDRU5DRU1BUFxcblxcdHZhcnlpbmcgdmVjMiB2SXJpZGVzY2VuY2VNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFX1RISUNLTkVTU01BUFxcblxcdHZhcnlpbmcgdmVjMiB2SXJpZGVzY2VuY2VUaGlja25lc3NNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NIRUVOX0NPTE9STUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZTaGVlbkNvbG9yTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TSEVFTl9ST1VHSE5FU1NNQVBcXG5cXHR2YXJ5aW5nIHZlYzIgdlNoZWVuUm91Z2huZXNzTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TUEVDVUxBUk1BUFxcblxcdHZhcnlpbmcgdmVjMiB2U3BlY3VsYXJNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NQRUNVTEFSX0NPTE9STUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZTcGVjdWxhckNvbG9yTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVBcXG5cXHR2YXJ5aW5nIHZlYzIgdlNwZWN1bGFySW50ZW5zaXR5TWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9UUkFOU01JU1NJT05NQVBcXG5cXHR1bmlmb3JtIG1hdDMgdHJhbnNtaXNzaW9uTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2VHJhbnNtaXNzaW9uTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9USElDS05FU1NNQVBcXG5cXHR1bmlmb3JtIG1hdDMgdGhpY2tuZXNzTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2VGhpY2tuZXNzTWFwVXY7XFxuI2VuZGlmXCI7XG5cbnZhciB1dl9wYXJzX3ZlcnRleCA9IFwiI2lmIGRlZmluZWQoIFVTRV9VViApIHx8IGRlZmluZWQoIFVTRV9BTklTT1RST1BZIClcXG5cXHR2YXJ5aW5nIHZlYzIgdlV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTUFQXFxuXFx0dW5pZm9ybSBtYXQzIG1hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdk1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQUxQSEFNQVBcXG5cXHR1bmlmb3JtIG1hdDMgYWxwaGFNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZBbHBoYU1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTElHSFRNQVBcXG5cXHR1bmlmb3JtIG1hdDMgbGlnaHRNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZMaWdodE1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQU9NQVBcXG5cXHR1bmlmb3JtIG1hdDMgYW9NYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZBb01hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQlVNUE1BUFxcblxcdHVuaWZvcm0gbWF0MyBidW1wTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2QnVtcE1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTk9STUFMTUFQXFxuXFx0dW5pZm9ybSBtYXQzIG5vcm1hbE1hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdk5vcm1hbE1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfRElTUExBQ0VNRU5UTUFQXFxuXFx0dW5pZm9ybSBtYXQzIGRpc3BsYWNlbWVudE1hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdkRpc3BsYWNlbWVudE1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfRU1JU1NJVkVNQVBcXG5cXHR1bmlmb3JtIG1hdDMgZW1pc3NpdmVNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZFbWlzc2l2ZU1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTUVUQUxORVNTTUFQXFxuXFx0dW5pZm9ybSBtYXQzIG1ldGFsbmVzc01hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdk1ldGFsbmVzc01hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfUk9VR0hORVNTTUFQXFxuXFx0dW5pZm9ybSBtYXQzIHJvdWdobmVzc01hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdlJvdWdobmVzc01hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQU5JU09UUk9QWU1BUFxcblxcdHVuaWZvcm0gbWF0MyBhbmlzb3Ryb3B5TWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2QW5pc290cm9weU1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUTUFQXFxuXFx0dW5pZm9ybSBtYXQzIGNsZWFyY29hdE1hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdkNsZWFyY29hdE1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUFxcblxcdHVuaWZvcm0gbWF0MyBjbGVhcmNvYXROb3JtYWxNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXROb3JtYWxNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9ST1VHSE5FU1NNQVBcXG5cXHR1bmlmb3JtIG1hdDMgY2xlYXJjb2F0Um91Z2huZXNzTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2Q2xlYXJjb2F0Um91Z2huZXNzTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TSEVFTl9DT0xPUk1BUFxcblxcdHVuaWZvcm0gbWF0MyBzaGVlbkNvbG9yTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2U2hlZW5Db2xvck1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfU0hFRU5fUk9VR0hORVNTTUFQXFxuXFx0dW5pZm9ybSBtYXQzIHNoZWVuUm91Z2huZXNzTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2U2hlZW5Sb3VnaG5lc3NNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFTUFQXFxuXFx0dW5pZm9ybSBtYXQzIGlyaWRlc2NlbmNlTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2SXJpZGVzY2VuY2VNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFX1RISUNLTkVTU01BUFxcblxcdHVuaWZvcm0gbWF0MyBpcmlkZXNjZW5jZVRoaWNrbmVzc01hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdklyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TUEVDVUxBUk1BUFxcblxcdHVuaWZvcm0gbWF0MyBzcGVjdWxhck1hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdlNwZWN1bGFyTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TUEVDVUxBUl9DT0xPUk1BUFxcblxcdHVuaWZvcm0gbWF0MyBzcGVjdWxhckNvbG9yTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2U3BlY3VsYXJDb2xvck1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfU1BFQ1VMQVJfSU5URU5TSVRZTUFQXFxuXFx0dW5pZm9ybSBtYXQzIHNwZWN1bGFySW50ZW5zaXR5TWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2U3BlY3VsYXJJbnRlbnNpdHlNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1RSQU5TTUlTU0lPTk1BUFxcblxcdHVuaWZvcm0gbWF0MyB0cmFuc21pc3Npb25NYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZUcmFuc21pc3Npb25NYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1RISUNLTkVTU01BUFxcblxcdHVuaWZvcm0gbWF0MyB0aGlja25lc3NNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZUaGlja25lc3NNYXBVdjtcXG4jZW5kaWZcIjtcblxudmFyIHV2X3ZlcnRleCA9IFwiI2lmIGRlZmluZWQoIFVTRV9VViApIHx8IGRlZmluZWQoIFVTRV9BTklTT1RST1BZIClcXG5cXHR2VXYgPSB2ZWMzKCB1diwgMSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTUFQXFxuXFx0dk1hcFV2ID0gKCBtYXBUcmFuc2Zvcm0gKiB2ZWMzKCBNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQUxQSEFNQVBcXG5cXHR2QWxwaGFNYXBVdiA9ICggYWxwaGFNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBBTFBIQU1BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9MSUdIVE1BUFxcblxcdHZMaWdodE1hcFV2ID0gKCBsaWdodE1hcFRyYW5zZm9ybSAqIHZlYzMoIExJR0hUTUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0FPTUFQXFxuXFx0dkFvTWFwVXYgPSAoIGFvTWFwVHJhbnNmb3JtICogdmVjMyggQU9NQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQlVNUE1BUFxcblxcdHZCdW1wTWFwVXYgPSAoIGJ1bXBNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBCVU1QTUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX05PUk1BTE1BUFxcblxcdHZOb3JtYWxNYXBVdiA9ICggbm9ybWFsTWFwVHJhbnNmb3JtICogdmVjMyggTk9STUFMTUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0RJU1BMQUNFTUVOVE1BUFxcblxcdHZEaXNwbGFjZW1lbnRNYXBVdiA9ICggZGlzcGxhY2VtZW50TWFwVHJhbnNmb3JtICogdmVjMyggRElTUExBQ0VNRU5UTUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0VNSVNTSVZFTUFQXFxuXFx0dkVtaXNzaXZlTWFwVXYgPSAoIGVtaXNzaXZlTWFwVHJhbnNmb3JtICogdmVjMyggRU1JU1NJVkVNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTUVUQUxORVNTTUFQXFxuXFx0dk1ldGFsbmVzc01hcFV2ID0gKCBtZXRhbG5lc3NNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBNRVRBTE5FU1NNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfUk9VR0hORVNTTUFQXFxuXFx0dlJvdWdobmVzc01hcFV2ID0gKCByb3VnaG5lc3NNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBST1VHSE5FU1NNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQU5JU09UUk9QWU1BUFxcblxcdHZBbmlzb3Ryb3B5TWFwVXYgPSAoIGFuaXNvdHJvcHlNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBBTklTT1RST1BZTUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0NMRUFSQ09BVE1BUFxcblxcdHZDbGVhcmNvYXRNYXBVdiA9ICggY2xlYXJjb2F0TWFwVHJhbnNmb3JtICogdmVjMyggQ0xFQVJDT0FUTUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVBcXG5cXHR2Q2xlYXJjb2F0Tm9ybWFsTWFwVXYgPSAoIGNsZWFyY29hdE5vcm1hbE1hcFRyYW5zZm9ybSAqIHZlYzMoIENMRUFSQ09BVF9OT1JNQUxNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUFxcblxcdHZDbGVhcmNvYXRSb3VnaG5lc3NNYXBVdiA9ICggY2xlYXJjb2F0Um91Z2huZXNzTWFwVHJhbnNmb3JtICogdmVjMyggQ0xFQVJDT0FUX1JPVUdITkVTU01BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9JUklERVNDRU5DRU1BUFxcblxcdHZJcmlkZXNjZW5jZU1hcFV2ID0gKCBpcmlkZXNjZW5jZU1hcFRyYW5zZm9ybSAqIHZlYzMoIElSSURFU0NFTkNFTUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFX1RISUNLTkVTU01BUFxcblxcdHZJcmlkZXNjZW5jZVRoaWNrbmVzc01hcFV2ID0gKCBpcmlkZXNjZW5jZVRoaWNrbmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIElSSURFU0NFTkNFX1RISUNLTkVTU01BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TSEVFTl9DT0xPUk1BUFxcblxcdHZTaGVlbkNvbG9yTWFwVXYgPSAoIHNoZWVuQ29sb3JNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBTSEVFTl9DT0xPUk1BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TSEVFTl9ST1VHSE5FU1NNQVBcXG5cXHR2U2hlZW5Sb3VnaG5lc3NNYXBVdiA9ICggc2hlZW5Sb3VnaG5lc3NNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBTSEVFTl9ST1VHSE5FU1NNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfU1BFQ1VMQVJNQVBcXG5cXHR2U3BlY3VsYXJNYXBVdiA9ICggc3BlY3VsYXJNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBTUEVDVUxBUk1BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TUEVDVUxBUl9DT0xPUk1BUFxcblxcdHZTcGVjdWxhckNvbG9yTWFwVXYgPSAoIHNwZWN1bGFyQ29sb3JNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBTUEVDVUxBUl9DT0xPUk1BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVBcXG5cXHR2U3BlY3VsYXJJbnRlbnNpdHlNYXBVdiA9ICggc3BlY3VsYXJJbnRlbnNpdHlNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBTUEVDVUxBUl9JTlRFTlNJVFlNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OTUFQXFxuXFx0dlRyYW5zbWlzc2lvbk1hcFV2ID0gKCB0cmFuc21pc3Npb25NYXBUcmFuc2Zvcm0gKiB2ZWMzKCBUUkFOU01JU1NJT05NQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfVEhJQ0tORVNTTUFQXFxuXFx0dlRoaWNrbmVzc01hcFV2ID0gKCB0aGlja25lc3NNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBUSElDS05FU1NNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlwiO1xuXG52YXIgd29ybGRwb3NfdmVydGV4ID0gXCIjaWYgZGVmaW5lZCggVVNFX0VOVk1BUCApIHx8IGRlZmluZWQoIERJU1RBTkNFICkgfHwgZGVmaW5lZCAoIFVTRV9TSEFET1dNQVAgKSB8fCBkZWZpbmVkICggVVNFX1RSQU5TTUlTU0lPTiApIHx8IE5VTV9TUE9UX0xJR0hUX0NPT1JEUyA+IDBcXG5cXHR2ZWM0IHdvcmxkUG9zaXRpb24gPSB2ZWM0KCB0cmFuc2Zvcm1lZCwgMS4wICk7XFxuXFx0I2lmZGVmIFVTRV9CQVRDSElOR1xcblxcdFxcdHdvcmxkUG9zaXRpb24gPSBiYXRjaGluZ01hdHJpeCAqIHdvcmxkUG9zaXRpb247XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIFVTRV9JTlNUQU5DSU5HXFxuXFx0XFx0d29ybGRQb3NpdGlvbiA9IGluc3RhbmNlTWF0cml4ICogd29ybGRQb3NpdGlvbjtcXG5cXHQjZW5kaWZcXG5cXHR3b3JsZFBvc2l0aW9uID0gbW9kZWxNYXRyaXggKiB3b3JsZFBvc2l0aW9uO1xcbiNlbmRpZlwiO1xuXG5jb25zdCB2ZXJ0ZXgkaCA9IFwidmFyeWluZyB2ZWMyIHZVdjtcXG51bmlmb3JtIG1hdDMgdXZUcmFuc2Zvcm07XFxudm9pZCBtYWluKCkge1xcblxcdHZVdiA9ICggdXZUcmFuc2Zvcm0gKiB2ZWMzKCB1diwgMSApICkueHk7XFxuXFx0Z2xfUG9zaXRpb24gPSB2ZWM0KCBwb3NpdGlvbi54eSwgMS4wLCAxLjAgKTtcXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JGggPSBcInVuaWZvcm0gc2FtcGxlcjJEIHQyRDtcXG51bmlmb3JtIGZsb2F0IGJhY2tncm91bmRJbnRlbnNpdHk7XFxudmFyeWluZyB2ZWMyIHZVdjtcXG52b2lkIG1haW4oKSB7XFxuXFx0dmVjNCB0ZXhDb2xvciA9IHRleHR1cmUyRCggdDJELCB2VXYgKTtcXG5cXHQjaWZkZWYgREVDT0RFX1ZJREVPX1RFWFRVUkVcXG5cXHRcXHR0ZXhDb2xvciA9IHZlYzQoIG1peCggcG93KCB0ZXhDb2xvci5yZ2IgKiAwLjk0Nzg2NzI5ODYgKyB2ZWMzKCAwLjA1MjEzMjcwMTQgKSwgdmVjMyggMi40ICkgKSwgdGV4Q29sb3IucmdiICogMC4wNzczOTkzODA4LCB2ZWMzKCBsZXNzVGhhbkVxdWFsKCB0ZXhDb2xvci5yZ2IsIHZlYzMoIDAuMDQwNDUgKSApICkgKSwgdGV4Q29sb3IudyApO1xcblxcdCNlbmRpZlxcblxcdHRleENvbG9yLnJnYiAqPSBiYWNrZ3JvdW5kSW50ZW5zaXR5O1xcblxcdGdsX0ZyYWdDb2xvciA9IHRleENvbG9yO1xcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG59XCI7XG5cbmNvbnN0IHZlcnRleCRnID0gXCJ2YXJ5aW5nIHZlYzMgdldvcmxkRGlyZWN0aW9uO1xcbiNpbmNsdWRlIDxjb21tb24+XFxudm9pZCBtYWluKCkge1xcblxcdHZXb3JsZERpcmVjdGlvbiA9IHRyYW5zZm9ybURpcmVjdGlvbiggcG9zaXRpb24sIG1vZGVsTWF0cml4ICk7XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxuXFx0Z2xfUG9zaXRpb24ueiA9IGdsX1Bvc2l0aW9uLnc7XFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCRnID0gXCIjaWZkZWYgRU5WTUFQX1RZUEVfQ1VCRVxcblxcdHVuaWZvcm0gc2FtcGxlckN1YmUgZW52TWFwO1xcbiNlbGlmIGRlZmluZWQoIEVOVk1BUF9UWVBFX0NVQkVfVVYgKVxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGVudk1hcDtcXG4jZW5kaWZcXG51bmlmb3JtIGZsb2F0IGZsaXBFbnZNYXA7XFxudW5pZm9ybSBmbG9hdCBiYWNrZ3JvdW5kQmx1cnJpbmVzcztcXG51bmlmb3JtIGZsb2F0IGJhY2tncm91bmRJbnRlbnNpdHk7XFxudW5pZm9ybSBtYXQzIGJhY2tncm91bmRSb3RhdGlvbjtcXG52YXJ5aW5nIHZlYzMgdldvcmxkRGlyZWN0aW9uO1xcbiNpbmNsdWRlIDxjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQ+XFxudm9pZCBtYWluKCkge1xcblxcdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFXFxuXFx0XFx0dmVjNCB0ZXhDb2xvciA9IHRleHR1cmVDdWJlKCBlbnZNYXAsIGJhY2tncm91bmRSb3RhdGlvbiAqIHZlYzMoIGZsaXBFbnZNYXAgKiB2V29ybGREaXJlY3Rpb24ueCwgdldvcmxkRGlyZWN0aW9uLnl6ICkgKTtcXG5cXHQjZWxpZiBkZWZpbmVkKCBFTlZNQVBfVFlQRV9DVUJFX1VWIClcXG5cXHRcXHR2ZWM0IHRleENvbG9yID0gdGV4dHVyZUN1YmVVViggZW52TWFwLCBiYWNrZ3JvdW5kUm90YXRpb24gKiB2V29ybGREaXJlY3Rpb24sIGJhY2tncm91bmRCbHVycmluZXNzICk7XFxuXFx0I2Vsc2VcXG5cXHRcXHR2ZWM0IHRleENvbG9yID0gdmVjNCggMC4wLCAwLjAsIDAuMCwgMS4wICk7XFxuXFx0I2VuZGlmXFxuXFx0dGV4Q29sb3IucmdiICo9IGJhY2tncm91bmRJbnRlbnNpdHk7XFxuXFx0Z2xfRnJhZ0NvbG9yID0gdGV4Q29sb3I7XFxuXFx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JGYgPSBcInZhcnlpbmcgdmVjMyB2V29ybGREaXJlY3Rpb247XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG52b2lkIG1haW4oKSB7XFxuXFx0dldvcmxkRGlyZWN0aW9uID0gdHJhbnNmb3JtRGlyZWN0aW9uKCBwb3NpdGlvbiwgbW9kZWxNYXRyaXggKTtcXG5cXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxcblxcdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cXG5cXHRnbF9Qb3NpdGlvbi56ID0gZ2xfUG9zaXRpb24udztcXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JGYgPSBcInVuaWZvcm0gc2FtcGxlckN1YmUgdEN1YmU7XFxudW5pZm9ybSBmbG9hdCB0RmxpcDtcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcXG52b2lkIG1haW4oKSB7XFxuXFx0dmVjNCB0ZXhDb2xvciA9IHRleHR1cmVDdWJlKCB0Q3ViZSwgdmVjMyggdEZsaXAgKiB2V29ybGREaXJlY3Rpb24ueCwgdldvcmxkRGlyZWN0aW9uLnl6ICkgKTtcXG5cXHRnbF9GcmFnQ29sb3IgPSB0ZXhDb2xvcjtcXG5cXHRnbF9GcmFnQ29sb3IuYSAqPSBvcGFjaXR5O1xcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG59XCI7XG5cbmNvbnN0IHZlcnRleCRlID0gXCIjaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxiYXRjaGluZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxcbnZhcnlpbmcgdmVjMiB2SGlnaFByZWNpc2lvblpXO1xcbnZvaWQgbWFpbigpIHtcXG5cXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5iYXNlX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2lmZGVmIFVTRV9ESVNQTEFDRU1FTlRNQVBcXG5cXHRcXHQjaW5jbHVkZSA8YmVnaW5ub3JtYWxfdmVydGV4PlxcblxcdFxcdCNpbmNsdWRlIDxtb3JwaG5vcm1hbF92ZXJ0ZXg+XFxuXFx0XFx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxcblxcdCNlbmRpZlxcblxcdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBodGFyZ2V0X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbm5pbmdfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxcblxcdHZIaWdoUHJlY2lzaW9uWlcgPSBnbF9Qb3NpdGlvbi56dztcXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JGUgPSBcIiNpZiBERVBUSF9QQUNLSU5HID09IDMyMDBcXG5cXHR1bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2VuZGlmXFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8cGFja2luZz5cXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQ+XFxudmFyeWluZyB2ZWMyIHZIaWdoUHJlY2lzaW9uWlc7XFxudm9pZCBtYWluKCkge1xcblxcdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggMS4wICk7XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cXG5cXHQjaWYgREVQVEhfUEFDS0lORyA9PSAzMjAwXFxuXFx0XFx0ZGlmZnVzZUNvbG9yLmEgPSBvcGFjaXR5O1xcblxcdCNlbmRpZlxcblxcdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XFxuXFx0ZmxvYXQgZnJhZ0Nvb3JkWiA9IDAuNSAqIHZIaWdoUHJlY2lzaW9uWldbMF0gLyB2SGlnaFByZWNpc2lvblpXWzFdICsgMC41O1xcblxcdCNpZiBERVBUSF9QQUNLSU5HID09IDMyMDBcXG5cXHRcXHRnbF9GcmFnQ29sb3IgPSB2ZWM0KCB2ZWMzKCAxLjAgLSBmcmFnQ29vcmRaICksIG9wYWNpdHkgKTtcXG5cXHQjZWxpZiBERVBUSF9QQUNLSU5HID09IDMyMDFcXG5cXHRcXHRnbF9GcmFnQ29sb3IgPSBwYWNrRGVwdGhUb1JHQkEoIGZyYWdDb29yZFogKTtcXG5cXHQjZW5kaWZcXG59XCI7XG5cbmNvbnN0IHZlcnRleCRkID0gXCIjZGVmaW5lIERJU1RBTkNFXFxudmFyeWluZyB2ZWMzIHZXb3JsZFBvc2l0aW9uO1xcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cXG52b2lkIG1haW4oKSB7XFxuXFx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoaW5zdGFuY2VfdmVydGV4PlxcblxcdCNpZmRlZiBVU0VfRElTUExBQ0VNRU5UTUFQXFxuXFx0XFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHRcXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxcblxcdFxcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjZW5kaWZcXG5cXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHdvcmxkcG9zX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cXG5cXHR2V29ybGRQb3NpdGlvbiA9IHdvcmxkUG9zaXRpb24ueHl6O1xcbn1cIjtcblxuY29uc3QgZnJhZ21lbnQkZCA9IFwiI2RlZmluZSBESVNUQU5DRVxcbnVuaWZvcm0gdmVjMyByZWZlcmVuY2VQb3NpdGlvbjtcXG51bmlmb3JtIGZsb2F0IG5lYXJEaXN0YW5jZTtcXG51bmlmb3JtIGZsb2F0IGZhckRpc3RhbmNlO1xcbnZhcnlpbmcgdmVjMyB2V29ybGRQb3NpdGlvbjtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxwYWNraW5nPlxcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGFtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cXG52b2lkIG1haW4gKCkge1xcblxcdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggMS4wICk7XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XFxuXFx0ZmxvYXQgZGlzdCA9IGxlbmd0aCggdldvcmxkUG9zaXRpb24gLSByZWZlcmVuY2VQb3NpdGlvbiApO1xcblxcdGRpc3QgPSAoIGRpc3QgLSBuZWFyRGlzdGFuY2UgKSAvICggZmFyRGlzdGFuY2UgLSBuZWFyRGlzdGFuY2UgKTtcXG5cXHRkaXN0ID0gc2F0dXJhdGUoIGRpc3QgKTtcXG5cXHRnbF9GcmFnQ29sb3IgPSBwYWNrRGVwdGhUb1JHQkEoIGRpc3QgKTtcXG59XCI7XG5cbmNvbnN0IHZlcnRleCRjID0gXCJ2YXJ5aW5nIHZlYzMgdldvcmxkRGlyZWN0aW9uO1xcbiNpbmNsdWRlIDxjb21tb24+XFxudm9pZCBtYWluKCkge1xcblxcdHZXb3JsZERpcmVjdGlvbiA9IHRyYW5zZm9ybURpcmVjdGlvbiggcG9zaXRpb24sIG1vZGVsTWF0cml4ICk7XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCRjID0gXCJ1bmlmb3JtIHNhbXBsZXIyRCB0RXF1aXJlY3Q7XFxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWMzIGRpcmVjdGlvbiA9IG5vcm1hbGl6ZSggdldvcmxkRGlyZWN0aW9uICk7XFxuXFx0dmVjMiBzYW1wbGVVViA9IGVxdWlyZWN0VXYoIGRpcmVjdGlvbiApO1xcblxcdGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCggdEVxdWlyZWN0LCBzYW1wbGVVViApO1xcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG59XCI7XG5cbmNvbnN0IHZlcnRleCRiID0gXCJ1bmlmb3JtIGZsb2F0IHNjYWxlO1xcbmF0dHJpYnV0ZSBmbG9hdCBsaW5lRGlzdGFuY2U7XFxudmFyeWluZyBmbG9hdCB2TGluZURpc3RhbmNlO1xcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPHV2X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cXG52b2lkIG1haW4oKSB7XFxuXFx0dkxpbmVEaXN0YW5jZSA9IHNjYWxlICogbGluZURpc3RhbmNlO1xcblxcdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBodGFyZ2V0X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JGIgPSBcInVuaWZvcm0gdmVjMyBkaWZmdXNlO1xcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcXG51bmlmb3JtIGZsb2F0IGRhc2hTaXplO1xcbnVuaWZvcm0gZmxvYXQgdG90YWxTaXplO1xcbnZhcnlpbmcgZmxvYXQgdkxpbmVEaXN0YW5jZTtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdGlmICggbW9kKCB2TGluZURpc3RhbmNlLCB0b3RhbFNpemUgKSA+IGRhc2hTaXplICkge1xcblxcdFxcdGRpc2NhcmQ7XFxuXFx0fVxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHZlYzMoIDAuMCApO1xcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cXG5cXHRvdXRnb2luZ0xpZ2h0ID0gZGlmZnVzZUNvbG9yLnJnYjtcXG5cXHQjaW5jbHVkZSA8b3BhcXVlX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxwcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JGEgPSBcIiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XFxudm9pZCBtYWluKCkge1xcblxcdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XFxuXFx0I2lmIGRlZmluZWQgKCBVU0VfRU5WTUFQICkgfHwgZGVmaW5lZCAoIFVTRV9TS0lOTklORyApXFxuXFx0XFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHRcXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxcblxcdFxcdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XFxuXFx0XFx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxcblxcdFxcdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cXG5cXHQjZW5kaWZcXG5cXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8d29ybGRwb3NfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxlbnZtYXBfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxmb2dfdmVydGV4Plxcbn1cIjtcblxuY29uc3QgZnJhZ21lbnQkYSA9IFwidW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XFxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xcbiNpZm5kZWYgRkxBVF9TSEFERURcXG5cXHR2YXJ5aW5nIHZlYzMgdk5vcm1hbDtcXG4jZW5kaWZcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxkaXRoZXJpbmdfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bGlnaHRtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8ZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxlbnZtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHNwZWN1bGFybWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGFtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhdGVzdF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGFoYXNoX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxzcGVjdWxhcm1hcF9mcmFnbWVudD5cXG5cXHRSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCA9IFJlZmxlY3RlZExpZ2h0KCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSApO1xcblxcdCNpZmRlZiBVU0VfTElHSFRNQVBcXG5cXHRcXHR2ZWM0IGxpZ2h0TWFwVGV4ZWwgPSB0ZXh0dXJlMkQoIGxpZ2h0TWFwLCB2TGlnaHRNYXBVdiApO1xcblxcdFxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSArPSBsaWdodE1hcFRleGVsLnJnYiAqIGxpZ2h0TWFwSW50ZW5zaXR5ICogUkVDSVBST0NBTF9QSTtcXG5cXHQjZWxzZVxcblxcdFxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSArPSB2ZWMzKCAxLjAgKTtcXG5cXHQjZW5kaWZcXG5cXHQjaW5jbHVkZSA8YW9tYXBfZnJhZ21lbnQ+XFxuXFx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICo9IGRpZmZ1c2VDb2xvci5yZ2I7XFxuXFx0dmVjMyBvdXRnb2luZ0xpZ2h0ID0gcmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlO1xcblxcdCNpbmNsdWRlIDxlbnZtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JDkgPSBcIiNkZWZpbmUgTEFNQkVSVFxcbnZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxlbnZtYXBfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XFxudm9pZCBtYWluKCkge1xcblxcdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cXG5cXHR2Vmlld1Bvc2l0aW9uID0gLSBtdlBvc2l0aW9uLnh5ejtcXG5cXHQjaW5jbHVkZSA8d29ybGRwb3NfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxlbnZtYXBfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxzaGFkb3dtYXBfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxmb2dfdmVydGV4Plxcbn1cIjtcblxuY29uc3QgZnJhZ21lbnQkOSA9IFwiI2RlZmluZSBMQU1CRVJUXFxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XFxudW5pZm9ybSB2ZWMzIGVtaXNzaXZlO1xcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxwYWNraW5nPlxcbiNpbmNsdWRlIDxkaXRoZXJpbmdfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bGlnaHRtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8ZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8ZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxlbnZtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGJzZGZzPlxcbiNpbmNsdWRlIDxsaWdodHNfcGFyc19iZWdpbj5cXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxpZ2h0c19sYW1iZXJ0X3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHNoYWRvd21hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxidW1wbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxzcGVjdWxhcm1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cXG52b2lkIG1haW4oKSB7XFxuXFx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cXG5cXHRSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCA9IFJlZmxlY3RlZExpZ2h0KCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSApO1xcblxcdHZlYzMgdG90YWxFbWlzc2l2ZVJhZGlhbmNlID0gZW1pc3NpdmU7XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPHNwZWN1bGFybWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfYmVnaW4+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9tYXBzPlxcblxcdCNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2xhbWJlcnRfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9iZWdpbj5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X21hcHM+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9lbmQ+XFxuXFx0I2luY2x1ZGUgPGFvbWFwX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKyByZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XFxuXFx0I2luY2x1ZGUgPGVudm1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8b3BhcXVlX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxwcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxkaXRoZXJpbmdfZnJhZ21lbnQ+XFxufVwiO1xuXG5jb25zdCB2ZXJ0ZXgkOCA9IFwiI2RlZmluZSBNQVRDQVBcXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxiYXRjaGluZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XFxudm9pZCBtYWluKCkge1xcblxcdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cXG5cXHR2Vmlld1Bvc2l0aW9uID0gLSBtdlBvc2l0aW9uLnh5ejtcXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JDggPSBcIiNkZWZpbmUgTUFUQ0FQXFxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XFxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xcbnVuaWZvcm0gc2FtcGxlcjJEIG1hdGNhcDtcXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxkaXRoZXJpbmdfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxidW1wbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cXG52b2lkIG1haW4oKSB7XFxuXFx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X2JlZ2luPlxcblxcdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfbWFwcz5cXG5cXHR2ZWMzIHZpZXdEaXIgPSBub3JtYWxpemUoIHZWaWV3UG9zaXRpb24gKTtcXG5cXHR2ZWMzIHggPSBub3JtYWxpemUoIHZlYzMoIHZpZXdEaXIueiwgMC4wLCAtIHZpZXdEaXIueCApICk7XFxuXFx0dmVjMyB5ID0gY3Jvc3MoIHZpZXdEaXIsIHggKTtcXG5cXHR2ZWMyIHV2ID0gdmVjMiggZG90KCB4LCBub3JtYWwgKSwgZG90KCB5LCBub3JtYWwgKSApICogMC40OTUgKyAwLjU7XFxuXFx0I2lmZGVmIFVTRV9NQVRDQVBcXG5cXHRcXHR2ZWM0IG1hdGNhcENvbG9yID0gdGV4dHVyZTJEKCBtYXRjYXAsIHV2ICk7XFxuXFx0I2Vsc2VcXG5cXHRcXHR2ZWM0IG1hdGNhcENvbG9yID0gdmVjNCggdmVjMyggbWl4KCAwLjIsIDAuOCwgdXYueSApICksIDEuMCApO1xcblxcdCNlbmRpZlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IGRpZmZ1c2VDb2xvci5yZ2IgKiBtYXRjYXBDb2xvci5yZ2I7XFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JDcgPSBcIiNkZWZpbmUgTk9STUFMXFxuI2lmIGRlZmluZWQoIEZMQVRfU0hBREVEICkgfHwgZGVmaW5lZCggVVNFX0JVTVBNQVAgKSB8fCBkZWZpbmVkKCBVU0VfTk9STUFMTUFQX1RBTkdFTlRTUEFDRSApXFxuXFx0dmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XFxuI2VuZGlmXFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8YmF0Y2hpbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPHV2X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxcbnZvaWQgbWFpbigpIHtcXG5cXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XFxuI2lmIGRlZmluZWQoIEZMQVRfU0hBREVEICkgfHwgZGVmaW5lZCggVVNFX0JVTVBNQVAgKSB8fCBkZWZpbmVkKCBVU0VfTk9STUFMTUFQX1RBTkdFTlRTUEFDRSApXFxuXFx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XFxuI2VuZGlmXFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCQ3ID0gXCIjZGVmaW5lIE5PUk1BTFxcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcXG4jaWYgZGVmaW5lZCggRkxBVF9TSEFERUQgKSB8fCBkZWZpbmVkKCBVU0VfQlVNUE1BUCApIHx8IGRlZmluZWQoIFVTRV9OT1JNQUxNQVBfVEFOR0VOVFNQQUNFIClcXG5cXHR2YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcXG4jZW5kaWZcXG4jaW5jbHVkZSA8cGFja2luZz5cXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIDAuMCwgMC4wLCAwLjAsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X2JlZ2luPlxcblxcdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfbWFwcz5cXG5cXHRnbF9GcmFnQ29sb3IgPSB2ZWM0KCBwYWNrTm9ybWFsVG9SR0IoIG5vcm1hbCApLCBkaWZmdXNlQ29sb3IuYSApO1xcblxcdCNpZmRlZiBPUEFRVUVcXG5cXHRcXHRnbF9GcmFnQ29sb3IuYSA9IDEuMDtcXG5cXHQjZW5kaWZcXG59XCI7XG5cbmNvbnN0IHZlcnRleCQ2ID0gXCIjZGVmaW5lIFBIT05HXFxudmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8YmF0Y2hpbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPHV2X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGVudm1hcF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y29sb3JfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPHNoYWRvd21hcF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cXG52b2lkIG1haW4oKSB7XFxuXFx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiZWdpbm5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoaW5zdGFuY2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5iYXNlX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbm5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGRlZmF1bHRub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBodGFyZ2V0X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbm5pbmdfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxcblxcdHZWaWV3UG9zaXRpb24gPSAtIG12UG9zaXRpb24ueHl6O1xcblxcdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGVudm1hcF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNoYWRvd21hcF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCQ2ID0gXCIjZGVmaW5lIFBIT05HXFxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XFxudW5pZm9ybSB2ZWMzIGVtaXNzaXZlO1xcbnVuaWZvcm0gdmVjMyBzcGVjdWxhcjtcXG51bmlmb3JtIGZsb2F0IHNoaW5pbmVzcztcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8cGFja2luZz5cXG4jaW5jbHVkZSA8ZGl0aGVyaW5nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGFoYXNoX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFvbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGVtaXNzaXZlbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGVudm1hcF9jb21tb25fcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxic2Rmcz5cXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XFxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxsaWdodHNfcGhvbmdfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHNwZWN1bGFybWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ID0gUmVmbGVjdGVkTGlnaHQoIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApICk7XFxuXFx0dmVjMyB0b3RhbEVtaXNzaXZlUmFkaWFuY2UgPSBlbWlzc2l2ZTtcXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8c3BlY3VsYXJtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9iZWdpbj5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X21hcHM+XFxuXFx0I2luY2x1ZGUgPGVtaXNzaXZlbWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxsaWdodHNfcGhvbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9iZWdpbj5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X21hcHM+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9lbmQ+XFxuXFx0I2luY2x1ZGUgPGFvbWFwX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKyByZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKyByZWZsZWN0ZWRMaWdodC5kaXJlY3RTcGVjdWxhciArIHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0U3BlY3VsYXIgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XFxuXFx0I2luY2x1ZGUgPGVudm1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8b3BhcXVlX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxwcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxkaXRoZXJpbmdfZnJhZ21lbnQ+XFxufVwiO1xuXG5jb25zdCB2ZXJ0ZXgkNSA9IFwiI2RlZmluZSBTVEFOREFSRFxcbnZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xcbiNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OXFxuXFx0dmFyeWluZyB2ZWMzIHZXb3JsZFBvc2l0aW9uO1xcbiNlbmRpZlxcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxub3JtYWxfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxza2lubmluZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxcbnZvaWQgbWFpbigpIHtcXG5cXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxjb2xvcl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoaW5zdGFuY2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiZWdpbm5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XFxuXFx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XFxuXFx0I2luY2x1ZGUgPHdvcmxkcG9zX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2hhZG93bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cXG4jaWZkZWYgVVNFX1RSQU5TTUlTU0lPTlxcblxcdHZXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbi54eXo7XFxuI2VuZGlmXFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCQ1ID0gXCIjZGVmaW5lIFNUQU5EQVJEXFxuI2lmZGVmIFBIWVNJQ0FMXFxuXFx0I2RlZmluZSBJT1JcXG5cXHQjZGVmaW5lIFVTRV9TUEVDVUxBUlxcbiNlbmRpZlxcbnVuaWZvcm0gdmVjMyBkaWZmdXNlO1xcbnVuaWZvcm0gdmVjMyBlbWlzc2l2ZTtcXG51bmlmb3JtIGZsb2F0IHJvdWdobmVzcztcXG51bmlmb3JtIGZsb2F0IG1ldGFsbmVzcztcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2lmZGVmIElPUlxcblxcdHVuaWZvcm0gZmxvYXQgaW9yO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfU1BFQ1VMQVJcXG5cXHR1bmlmb3JtIGZsb2F0IHNwZWN1bGFySW50ZW5zaXR5O1xcblxcdHVuaWZvcm0gdmVjMyBzcGVjdWxhckNvbG9yO1xcblxcdCNpZmRlZiBVU0VfU1BFQ1VMQVJfQ09MT1JNQVBcXG5cXHRcXHR1bmlmb3JtIHNhbXBsZXIyRCBzcGVjdWxhckNvbG9yTWFwO1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBVU0VfU1BFQ1VMQVJfSU5URU5TSVRZTUFQXFxuXFx0XFx0dW5pZm9ybSBzYW1wbGVyMkQgc3BlY3VsYXJJbnRlbnNpdHlNYXA7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRcXG5cXHR1bmlmb3JtIGZsb2F0IGNsZWFyY29hdDtcXG5cXHR1bmlmb3JtIGZsb2F0IGNsZWFyY29hdFJvdWdobmVzcztcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0RJU1BFUlNJT05cXG5cXHR1bmlmb3JtIGZsb2F0IGRpc3BlcnNpb247XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9JUklERVNDRU5DRVxcblxcdHVuaWZvcm0gZmxvYXQgaXJpZGVzY2VuY2U7XFxuXFx0dW5pZm9ybSBmbG9hdCBpcmlkZXNjZW5jZUlPUjtcXG5cXHR1bmlmb3JtIGZsb2F0IGlyaWRlc2NlbmNlVGhpY2tuZXNzTWluaW11bTtcXG5cXHR1bmlmb3JtIGZsb2F0IGlyaWRlc2NlbmNlVGhpY2tuZXNzTWF4aW11bTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NIRUVOXFxuXFx0dW5pZm9ybSB2ZWMzIHNoZWVuQ29sb3I7XFxuXFx0dW5pZm9ybSBmbG9hdCBzaGVlblJvdWdobmVzcztcXG5cXHQjaWZkZWYgVVNFX1NIRUVOX0NPTE9STUFQXFxuXFx0XFx0dW5pZm9ybSBzYW1wbGVyMkQgc2hlZW5Db2xvck1hcDtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX1NIRUVOX1JPVUdITkVTU01BUFxcblxcdFxcdHVuaWZvcm0gc2FtcGxlcjJEIHNoZWVuUm91Z2huZXNzTWFwO1xcblxcdCNlbmRpZlxcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQU5JU09UUk9QWVxcblxcdHVuaWZvcm0gdmVjMiBhbmlzb3Ryb3B5VmVjdG9yO1xcblxcdCNpZmRlZiBVU0VfQU5JU09UUk9QWU1BUFxcblxcdFxcdHVuaWZvcm0gc2FtcGxlcjJEIGFuaXNvdHJvcHlNYXA7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXFxudmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8cGFja2luZz5cXG4jaW5jbHVkZSA8ZGl0aGVyaW5nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGFoYXNoX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFvbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGVtaXNzaXZlbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGlyaWRlc2NlbmNlX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGVudm1hcF9jb21tb25fcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8ZW52bWFwX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxsaWdodHNfcGFyc19iZWdpbj5cXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxpZ2h0c19waHlzaWNhbF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDx0cmFuc21pc3Npb25fcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsZWFyY29hdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxpcmlkZXNjZW5jZV9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxyb3VnaG5lc3NtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWV0YWxuZXNzbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ID0gUmVmbGVjdGVkTGlnaHQoIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApICk7XFxuXFx0dmVjMyB0b3RhbEVtaXNzaXZlUmFkaWFuY2UgPSBlbWlzc2l2ZTtcXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cm91Z2huZXNzbWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxtZXRhbG5lc3NtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9iZWdpbj5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X21hcHM+XFxuXFx0I2luY2x1ZGUgPGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfYmVnaW4+XFxuXFx0I2luY2x1ZGUgPGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfbWFwcz5cXG5cXHQjaW5jbHVkZSA8ZW1pc3NpdmVtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19waHlzaWNhbF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X2JlZ2luPlxcblxcdCNpbmNsdWRlIDxsaWdodHNfZnJhZ21lbnRfbWFwcz5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X2VuZD5cXG5cXHQjaW5jbHVkZSA8YW9tYXBfZnJhZ21lbnQ+XFxuXFx0dmVjMyB0b3RhbERpZmZ1c2UgPSByZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICsgcmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlO1xcblxcdHZlYzMgdG90YWxTcGVjdWxhciA9IHJlZmxlY3RlZExpZ2h0LmRpcmVjdFNwZWN1bGFyICsgcmVmbGVjdGVkTGlnaHQuaW5kaXJlY3RTcGVjdWxhcjtcXG5cXHQjaW5jbHVkZSA8dHJhbnNtaXNzaW9uX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHRvdGFsRGlmZnVzZSArIHRvdGFsU3BlY3VsYXIgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XFxuXFx0I2lmZGVmIFVTRV9TSEVFTlxcblxcdFxcdGZsb2F0IHNoZWVuRW5lcmd5Q29tcCA9IDEuMCAtIDAuMTU3ICogbWF4MyggbWF0ZXJpYWwuc2hlZW5Db2xvciApO1xcblxcdFxcdG91dGdvaW5nTGlnaHQgPSBvdXRnb2luZ0xpZ2h0ICogc2hlZW5FbmVyZ3lDb21wICsgc2hlZW5TcGVjdWxhckRpcmVjdCArIHNoZWVuU3BlY3VsYXJJbmRpcmVjdDtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX0NMRUFSQ09BVFxcblxcdFxcdGZsb2F0IGRvdE5WY2MgPSBzYXR1cmF0ZSggZG90KCBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyICkgKTtcXG5cXHRcXHR2ZWMzIEZjYyA9IEZfU2NobGljayggbWF0ZXJpYWwuY2xlYXJjb2F0RjAsIG1hdGVyaWFsLmNsZWFyY29hdEY5MCwgZG90TlZjYyApO1xcblxcdFxcdG91dGdvaW5nTGlnaHQgPSBvdXRnb2luZ0xpZ2h0ICogKCAxLjAgLSBtYXRlcmlhbC5jbGVhcmNvYXQgKiBGY2MgKSArICggY2xlYXJjb2F0U3BlY3VsYXJEaXJlY3QgKyBjbGVhcmNvYXRTcGVjdWxhckluZGlyZWN0ICkgKiBtYXRlcmlhbC5jbGVhcmNvYXQ7XFxuXFx0I2VuZGlmXFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JDQgPSBcIiNkZWZpbmUgVE9PTlxcbnZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxub3JtYWxfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxza2lubmluZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxcbnZvaWQgbWFpbigpIHtcXG5cXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxjb2xvcl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoaW5zdGFuY2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiZWdpbm5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XFxuXFx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XFxuXFx0I2luY2x1ZGUgPHdvcmxkcG9zX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2hhZG93bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JDQgPSBcIiNkZWZpbmUgVE9PTlxcbnVuaWZvcm0gdmVjMyBkaWZmdXNlO1xcbnVuaWZvcm0gdmVjMyBlbWlzc2l2ZTtcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8cGFja2luZz5cXG4jaW5jbHVkZSA8ZGl0aGVyaW5nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGFoYXNoX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFvbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGVtaXNzaXZlbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGdyYWRpZW50bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxic2Rmcz5cXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XFxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxsaWdodHNfdG9vbl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YnVtcG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxub3JtYWxtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQ+XFxudm9pZCBtYWluKCkge1xcblxcdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggZGlmZnVzZSwgb3BhY2l0eSApO1xcblxcdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfZnJhZ21lbnQ+XFxuXFx0UmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgPSBSZWZsZWN0ZWRMaWdodCggdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICkgKTtcXG5cXHR2ZWMzIHRvdGFsRW1pc3NpdmVSYWRpYW5jZSA9IGVtaXNzaXZlO1xcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGFtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhdGVzdF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGFoYXNoX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfYmVnaW4+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9tYXBzPlxcblxcdCNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX3Rvb25fZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9iZWdpbj5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X21hcHM+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9lbmQ+XFxuXFx0I2luY2x1ZGUgPGFvbWFwX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKyByZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JDMgPSBcInVuaWZvcm0gZmxvYXQgc2l6ZTtcXG51bmlmb3JtIGZsb2F0IHNjYWxlO1xcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxcbiNpZmRlZiBVU0VfUE9JTlRTX1VWXFxuXFx0dmFyeWluZyB2ZWMyIHZVdjtcXG5cXHR1bmlmb3JtIG1hdDMgdXZUcmFuc2Zvcm07XFxuI2VuZGlmXFxudm9pZCBtYWluKCkge1xcblxcdCNpZmRlZiBVU0VfUE9JTlRTX1VWXFxuXFx0XFx0dlV2ID0gKCB1dlRyYW5zZm9ybSAqIHZlYzMoIHV2LCAxICkgKS54eTtcXG5cXHQjZW5kaWZcXG5cXHQjaW5jbHVkZSA8Y29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaGluc3RhbmNlX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhjb2xvcl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cXG5cXHRnbF9Qb2ludFNpemUgPSBzaXplO1xcblxcdCNpZmRlZiBVU0VfU0laRUFUVEVOVUFUSU9OXFxuXFx0XFx0Ym9vbCBpc1BlcnNwZWN0aXZlID0gaXNQZXJzcGVjdGl2ZU1hdHJpeCggcHJvamVjdGlvbk1hdHJpeCApO1xcblxcdFxcdGlmICggaXNQZXJzcGVjdGl2ZSApIGdsX1BvaW50U2l6ZSAqPSAoIHNjYWxlIC8gLSBtdlBvc2l0aW9uLnogKTtcXG5cXHQjZW5kaWZcXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxcblxcdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCQzID0gXCJ1bmlmb3JtIHZlYzMgZGlmZnVzZTtcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHZlYzMoIDAuMCApO1xcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX3BhcnRpY2xlX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XFxuXFx0b3V0Z29pbmdMaWdodCA9IGRpZmZ1c2VDb2xvci5yZ2I7XFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cXG59XCI7XG5cbmNvbnN0IHZlcnRleCQyID0gXCIjaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxiYXRjaGluZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc192ZXJ0ZXg+XFxudm9pZCBtYWluKCkge1xcblxcdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHdvcmxkcG9zX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2hhZG93bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JDIgPSBcInVuaWZvcm0gdmVjMyBjb2xvcjtcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8cGFja2luZz5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGJzZGZzPlxcbiNpbmNsdWRlIDxsaWdodHNfcGFyc19iZWdpbj5cXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHNoYWRvd21hc2tfcGFyc19mcmFnbWVudD5cXG52b2lkIG1haW4oKSB7XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxcblxcdGdsX0ZyYWdDb2xvciA9IHZlYzQoIGNvbG9yLCBvcGFjaXR5ICogKCAxLjAgLSBnZXRTaGFkb3dNYXNrKCkgKSApO1xcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JDEgPSBcInVuaWZvcm0gZmxvYXQgcm90YXRpb247XFxudW5pZm9ybSB2ZWMyIGNlbnRlcjtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxcbnZvaWQgbWFpbigpIHtcXG5cXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxcblxcdHZlYzQgbXZQb3NpdGlvbiA9IG1vZGVsVmlld01hdHJpeCAqIHZlYzQoIDAuMCwgMC4wLCAwLjAsIDEuMCApO1xcblxcdHZlYzIgc2NhbGU7XFxuXFx0c2NhbGUueCA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDAgXS54LCBtb2RlbE1hdHJpeFsgMCBdLnksIG1vZGVsTWF0cml4WyAwIF0ueiApICk7XFxuXFx0c2NhbGUueSA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDEgXS54LCBtb2RlbE1hdHJpeFsgMSBdLnksIG1vZGVsTWF0cml4WyAxIF0ueiApICk7XFxuXFx0I2lmbmRlZiBVU0VfU0laRUFUVEVOVUFUSU9OXFxuXFx0XFx0Ym9vbCBpc1BlcnNwZWN0aXZlID0gaXNQZXJzcGVjdGl2ZU1hdHJpeCggcHJvamVjdGlvbk1hdHJpeCApO1xcblxcdFxcdGlmICggaXNQZXJzcGVjdGl2ZSApIHNjYWxlICo9IC0gbXZQb3NpdGlvbi56O1xcblxcdCNlbmRpZlxcblxcdHZlYzIgYWxpZ25lZFBvc2l0aW9uID0gKCBwb3NpdGlvbi54eSAtICggY2VudGVyIC0gdmVjMiggMC41ICkgKSApICogc2NhbGU7XFxuXFx0dmVjMiByb3RhdGVkUG9zaXRpb247XFxuXFx0cm90YXRlZFBvc2l0aW9uLnggPSBjb3MoIHJvdGF0aW9uICkgKiBhbGlnbmVkUG9zaXRpb24ueCAtIHNpbiggcm90YXRpb24gKSAqIGFsaWduZWRQb3NpdGlvbi55O1xcblxcdHJvdGF0ZWRQb3NpdGlvbi55ID0gc2luKCByb3RhdGlvbiApICogYWxpZ25lZFBvc2l0aW9uLnggKyBjb3MoIHJvdGF0aW9uICkgKiBhbGlnbmVkUG9zaXRpb24ueTtcXG5cXHRtdlBvc2l0aW9uLnh5ICs9IHJvdGF0ZWRQb3NpdGlvbjtcXG5cXHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtdlBvc2l0aW9uO1xcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCQxID0gXCJ1bmlmb3JtIHZlYzMgZGlmZnVzZTtcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHZlYzMoIDAuMCApO1xcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XFxuXFx0b3V0Z29pbmdMaWdodCA9IGRpZmZ1c2VDb2xvci5yZ2I7XFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG59XCI7XG5cbmNvbnN0IFNoYWRlckNodW5rID0ge1xuXHRhbHBoYWhhc2hfZnJhZ21lbnQ6IGFscGhhaGFzaF9mcmFnbWVudCxcblx0YWxwaGFoYXNoX3BhcnNfZnJhZ21lbnQ6IGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50LFxuXHRhbHBoYW1hcF9mcmFnbWVudDogYWxwaGFtYXBfZnJhZ21lbnQsXG5cdGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ6IGFscGhhbWFwX3BhcnNfZnJhZ21lbnQsXG5cdGFscGhhdGVzdF9mcmFnbWVudDogYWxwaGF0ZXN0X2ZyYWdtZW50LFxuXHRhbHBoYXRlc3RfcGFyc19mcmFnbWVudDogYWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQsXG5cdGFvbWFwX2ZyYWdtZW50OiBhb21hcF9mcmFnbWVudCxcblx0YW9tYXBfcGFyc19mcmFnbWVudDogYW9tYXBfcGFyc19mcmFnbWVudCxcblx0YmF0Y2hpbmdfcGFyc192ZXJ0ZXg6IGJhdGNoaW5nX3BhcnNfdmVydGV4LFxuXHRiYXRjaGluZ192ZXJ0ZXg6IGJhdGNoaW5nX3ZlcnRleCxcblx0YmVnaW5fdmVydGV4OiBiZWdpbl92ZXJ0ZXgsXG5cdGJlZ2lubm9ybWFsX3ZlcnRleDogYmVnaW5ub3JtYWxfdmVydGV4LFxuXHRic2RmczogYnNkZnMsXG5cdGlyaWRlc2NlbmNlX2ZyYWdtZW50OiBpcmlkZXNjZW5jZV9mcmFnbWVudCxcblx0YnVtcG1hcF9wYXJzX2ZyYWdtZW50OiBidW1wbWFwX3BhcnNfZnJhZ21lbnQsXG5cdGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudDogY2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50LFxuXHRjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudDogY2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQsXG5cdGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleDogY2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4LFxuXHRjbGlwcGluZ19wbGFuZXNfdmVydGV4OiBjbGlwcGluZ19wbGFuZXNfdmVydGV4LFxuXHRjb2xvcl9mcmFnbWVudDogY29sb3JfZnJhZ21lbnQsXG5cdGNvbG9yX3BhcnNfZnJhZ21lbnQ6IGNvbG9yX3BhcnNfZnJhZ21lbnQsXG5cdGNvbG9yX3BhcnNfdmVydGV4OiBjb2xvcl9wYXJzX3ZlcnRleCxcblx0Y29sb3JfdmVydGV4OiBjb2xvcl92ZXJ0ZXgsXG5cdGNvbW1vbjogY29tbW9uLFxuXHRjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQ6IGN1YmVfdXZfcmVmbGVjdGlvbl9mcmFnbWVudCxcblx0ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg6IGRlZmF1bHRub3JtYWxfdmVydGV4LFxuXHRkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg6IGRpc3BsYWNlbWVudG1hcF9wYXJzX3ZlcnRleCxcblx0ZGlzcGxhY2VtZW50bWFwX3ZlcnRleDogZGlzcGxhY2VtZW50bWFwX3ZlcnRleCxcblx0ZW1pc3NpdmVtYXBfZnJhZ21lbnQ6IGVtaXNzaXZlbWFwX2ZyYWdtZW50LFxuXHRlbWlzc2l2ZW1hcF9wYXJzX2ZyYWdtZW50OiBlbWlzc2l2ZW1hcF9wYXJzX2ZyYWdtZW50LFxuXHRjb2xvcnNwYWNlX2ZyYWdtZW50OiBjb2xvcnNwYWNlX2ZyYWdtZW50LFxuXHRjb2xvcnNwYWNlX3BhcnNfZnJhZ21lbnQ6IGNvbG9yc3BhY2VfcGFyc19mcmFnbWVudCxcblx0ZW52bWFwX2ZyYWdtZW50OiBlbnZtYXBfZnJhZ21lbnQsXG5cdGVudm1hcF9jb21tb25fcGFyc19mcmFnbWVudDogZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50LFxuXHRlbnZtYXBfcGFyc19mcmFnbWVudDogZW52bWFwX3BhcnNfZnJhZ21lbnQsXG5cdGVudm1hcF9wYXJzX3ZlcnRleDogZW52bWFwX3BhcnNfdmVydGV4LFxuXHRlbnZtYXBfcGh5c2ljYWxfcGFyc19mcmFnbWVudDogZW52bWFwX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQsXG5cdGVudm1hcF92ZXJ0ZXg6IGVudm1hcF92ZXJ0ZXgsXG5cdGZvZ192ZXJ0ZXg6IGZvZ192ZXJ0ZXgsXG5cdGZvZ19wYXJzX3ZlcnRleDogZm9nX3BhcnNfdmVydGV4LFxuXHRmb2dfZnJhZ21lbnQ6IGZvZ19mcmFnbWVudCxcblx0Zm9nX3BhcnNfZnJhZ21lbnQ6IGZvZ19wYXJzX2ZyYWdtZW50LFxuXHRncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50OiBncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50LFxuXHRsaWdodG1hcF9wYXJzX2ZyYWdtZW50OiBsaWdodG1hcF9wYXJzX2ZyYWdtZW50LFxuXHRsaWdodHNfbGFtYmVydF9mcmFnbWVudDogbGlnaHRzX2xhbWJlcnRfZnJhZ21lbnQsXG5cdGxpZ2h0c19sYW1iZXJ0X3BhcnNfZnJhZ21lbnQ6IGxpZ2h0c19sYW1iZXJ0X3BhcnNfZnJhZ21lbnQsXG5cdGxpZ2h0c19wYXJzX2JlZ2luOiBsaWdodHNfcGFyc19iZWdpbixcblx0bGlnaHRzX3Rvb25fZnJhZ21lbnQ6IGxpZ2h0c190b29uX2ZyYWdtZW50LFxuXHRsaWdodHNfdG9vbl9wYXJzX2ZyYWdtZW50OiBsaWdodHNfdG9vbl9wYXJzX2ZyYWdtZW50LFxuXHRsaWdodHNfcGhvbmdfZnJhZ21lbnQ6IGxpZ2h0c19waG9uZ19mcmFnbWVudCxcblx0bGlnaHRzX3Bob25nX3BhcnNfZnJhZ21lbnQ6IGxpZ2h0c19waG9uZ19wYXJzX2ZyYWdtZW50LFxuXHRsaWdodHNfcGh5c2ljYWxfZnJhZ21lbnQ6IGxpZ2h0c19waHlzaWNhbF9mcmFnbWVudCxcblx0bGlnaHRzX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQ6IGxpZ2h0c19waHlzaWNhbF9wYXJzX2ZyYWdtZW50LFxuXHRsaWdodHNfZnJhZ21lbnRfYmVnaW46IGxpZ2h0c19mcmFnbWVudF9iZWdpbixcblx0bGlnaHRzX2ZyYWdtZW50X21hcHM6IGxpZ2h0c19mcmFnbWVudF9tYXBzLFxuXHRsaWdodHNfZnJhZ21lbnRfZW5kOiBsaWdodHNfZnJhZ21lbnRfZW5kLFxuXHRsb2dkZXB0aGJ1Zl9mcmFnbWVudDogbG9nZGVwdGhidWZfZnJhZ21lbnQsXG5cdGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ6IGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQsXG5cdGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4OiBsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleCxcblx0bG9nZGVwdGhidWZfdmVydGV4OiBsb2dkZXB0aGJ1Zl92ZXJ0ZXgsXG5cdG1hcF9mcmFnbWVudDogbWFwX2ZyYWdtZW50LFxuXHRtYXBfcGFyc19mcmFnbWVudDogbWFwX3BhcnNfZnJhZ21lbnQsXG5cdG1hcF9wYXJ0aWNsZV9mcmFnbWVudDogbWFwX3BhcnRpY2xlX2ZyYWdtZW50LFxuXHRtYXBfcGFydGljbGVfcGFyc19mcmFnbWVudDogbWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQsXG5cdG1ldGFsbmVzc21hcF9mcmFnbWVudDogbWV0YWxuZXNzbWFwX2ZyYWdtZW50LFxuXHRtZXRhbG5lc3NtYXBfcGFyc19mcmFnbWVudDogbWV0YWxuZXNzbWFwX3BhcnNfZnJhZ21lbnQsXG5cdG1vcnBoaW5zdGFuY2VfdmVydGV4OiBtb3JwaGluc3RhbmNlX3ZlcnRleCxcblx0bW9ycGhjb2xvcl92ZXJ0ZXg6IG1vcnBoY29sb3JfdmVydGV4LFxuXHRtb3JwaG5vcm1hbF92ZXJ0ZXg6IG1vcnBobm9ybWFsX3ZlcnRleCxcblx0bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg6IG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4LFxuXHRtb3JwaHRhcmdldF92ZXJ0ZXg6IG1vcnBodGFyZ2V0X3ZlcnRleCxcblx0bm9ybWFsX2ZyYWdtZW50X2JlZ2luOiBub3JtYWxfZnJhZ21lbnRfYmVnaW4sXG5cdG5vcm1hbF9mcmFnbWVudF9tYXBzOiBub3JtYWxfZnJhZ21lbnRfbWFwcyxcblx0bm9ybWFsX3BhcnNfZnJhZ21lbnQ6IG5vcm1hbF9wYXJzX2ZyYWdtZW50LFxuXHRub3JtYWxfcGFyc192ZXJ0ZXg6IG5vcm1hbF9wYXJzX3ZlcnRleCxcblx0bm9ybWFsX3ZlcnRleDogbm9ybWFsX3ZlcnRleCxcblx0bm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQ6IG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50LFxuXHRjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X2JlZ2luOiBjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X2JlZ2luLFxuXHRjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X21hcHM6IGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfbWFwcyxcblx0Y2xlYXJjb2F0X3BhcnNfZnJhZ21lbnQ6IGNsZWFyY29hdF9wYXJzX2ZyYWdtZW50LFxuXHRpcmlkZXNjZW5jZV9wYXJzX2ZyYWdtZW50OiBpcmlkZXNjZW5jZV9wYXJzX2ZyYWdtZW50LFxuXHRvcGFxdWVfZnJhZ21lbnQ6IG9wYXF1ZV9mcmFnbWVudCxcblx0cGFja2luZzogcGFja2luZyxcblx0cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudDogcHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudCxcblx0cHJvamVjdF92ZXJ0ZXg6IHByb2plY3RfdmVydGV4LFxuXHRkaXRoZXJpbmdfZnJhZ21lbnQ6IGRpdGhlcmluZ19mcmFnbWVudCxcblx0ZGl0aGVyaW5nX3BhcnNfZnJhZ21lbnQ6IGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50LFxuXHRyb3VnaG5lc3NtYXBfZnJhZ21lbnQ6IHJvdWdobmVzc21hcF9mcmFnbWVudCxcblx0cm91Z2huZXNzbWFwX3BhcnNfZnJhZ21lbnQ6IHJvdWdobmVzc21hcF9wYXJzX2ZyYWdtZW50LFxuXHRzaGFkb3dtYXBfcGFyc19mcmFnbWVudDogc2hhZG93bWFwX3BhcnNfZnJhZ21lbnQsXG5cdHNoYWRvd21hcF9wYXJzX3ZlcnRleDogc2hhZG93bWFwX3BhcnNfdmVydGV4LFxuXHRzaGFkb3dtYXBfdmVydGV4OiBzaGFkb3dtYXBfdmVydGV4LFxuXHRzaGFkb3dtYXNrX3BhcnNfZnJhZ21lbnQ6IHNoYWRvd21hc2tfcGFyc19mcmFnbWVudCxcblx0c2tpbmJhc2VfdmVydGV4OiBza2luYmFzZV92ZXJ0ZXgsXG5cdHNraW5uaW5nX3BhcnNfdmVydGV4OiBza2lubmluZ19wYXJzX3ZlcnRleCxcblx0c2tpbm5pbmdfdmVydGV4OiBza2lubmluZ192ZXJ0ZXgsXG5cdHNraW5ub3JtYWxfdmVydGV4OiBza2lubm9ybWFsX3ZlcnRleCxcblx0c3BlY3VsYXJtYXBfZnJhZ21lbnQ6IHNwZWN1bGFybWFwX2ZyYWdtZW50LFxuXHRzcGVjdWxhcm1hcF9wYXJzX2ZyYWdtZW50OiBzcGVjdWxhcm1hcF9wYXJzX2ZyYWdtZW50LFxuXHR0b25lbWFwcGluZ19mcmFnbWVudDogdG9uZW1hcHBpbmdfZnJhZ21lbnQsXG5cdHRvbmVtYXBwaW5nX3BhcnNfZnJhZ21lbnQ6IHRvbmVtYXBwaW5nX3BhcnNfZnJhZ21lbnQsXG5cdHRyYW5zbWlzc2lvbl9mcmFnbWVudDogdHJhbnNtaXNzaW9uX2ZyYWdtZW50LFxuXHR0cmFuc21pc3Npb25fcGFyc19mcmFnbWVudDogdHJhbnNtaXNzaW9uX3BhcnNfZnJhZ21lbnQsXG5cdHV2X3BhcnNfZnJhZ21lbnQ6IHV2X3BhcnNfZnJhZ21lbnQsXG5cdHV2X3BhcnNfdmVydGV4OiB1dl9wYXJzX3ZlcnRleCxcblx0dXZfdmVydGV4OiB1dl92ZXJ0ZXgsXG5cdHdvcmxkcG9zX3ZlcnRleDogd29ybGRwb3NfdmVydGV4LFxuXG5cdGJhY2tncm91bmRfdmVydDogdmVydGV4JGgsXG5cdGJhY2tncm91bmRfZnJhZzogZnJhZ21lbnQkaCxcblx0YmFja2dyb3VuZEN1YmVfdmVydDogdmVydGV4JGcsXG5cdGJhY2tncm91bmRDdWJlX2ZyYWc6IGZyYWdtZW50JGcsXG5cdGN1YmVfdmVydDogdmVydGV4JGYsXG5cdGN1YmVfZnJhZzogZnJhZ21lbnQkZixcblx0ZGVwdGhfdmVydDogdmVydGV4JGUsXG5cdGRlcHRoX2ZyYWc6IGZyYWdtZW50JGUsXG5cdGRpc3RhbmNlUkdCQV92ZXJ0OiB2ZXJ0ZXgkZCxcblx0ZGlzdGFuY2VSR0JBX2ZyYWc6IGZyYWdtZW50JGQsXG5cdGVxdWlyZWN0X3ZlcnQ6IHZlcnRleCRjLFxuXHRlcXVpcmVjdF9mcmFnOiBmcmFnbWVudCRjLFxuXHRsaW5lZGFzaGVkX3ZlcnQ6IHZlcnRleCRiLFxuXHRsaW5lZGFzaGVkX2ZyYWc6IGZyYWdtZW50JGIsXG5cdG1lc2hiYXNpY192ZXJ0OiB2ZXJ0ZXgkYSxcblx0bWVzaGJhc2ljX2ZyYWc6IGZyYWdtZW50JGEsXG5cdG1lc2hsYW1iZXJ0X3ZlcnQ6IHZlcnRleCQ5LFxuXHRtZXNobGFtYmVydF9mcmFnOiBmcmFnbWVudCQ5LFxuXHRtZXNobWF0Y2FwX3ZlcnQ6IHZlcnRleCQ4LFxuXHRtZXNobWF0Y2FwX2ZyYWc6IGZyYWdtZW50JDgsXG5cdG1lc2hub3JtYWxfdmVydDogdmVydGV4JDcsXG5cdG1lc2hub3JtYWxfZnJhZzogZnJhZ21lbnQkNyxcblx0bWVzaHBob25nX3ZlcnQ6IHZlcnRleCQ2LFxuXHRtZXNocGhvbmdfZnJhZzogZnJhZ21lbnQkNixcblx0bWVzaHBoeXNpY2FsX3ZlcnQ6IHZlcnRleCQ1LFxuXHRtZXNocGh5c2ljYWxfZnJhZzogZnJhZ21lbnQkNSxcblx0bWVzaHRvb25fdmVydDogdmVydGV4JDQsXG5cdG1lc2h0b29uX2ZyYWc6IGZyYWdtZW50JDQsXG5cdHBvaW50c192ZXJ0OiB2ZXJ0ZXgkMyxcblx0cG9pbnRzX2ZyYWc6IGZyYWdtZW50JDMsXG5cdHNoYWRvd192ZXJ0OiB2ZXJ0ZXgkMixcblx0c2hhZG93X2ZyYWc6IGZyYWdtZW50JDIsXG5cdHNwcml0ZV92ZXJ0OiB2ZXJ0ZXgkMSxcblx0c3ByaXRlX2ZyYWc6IGZyYWdtZW50JDFcbn07XG5cbi8qKlxuICogVW5pZm9ybXMgbGlicmFyeSBmb3Igc2hhcmVkIHdlYmdsIHNoYWRlcnNcbiAqL1xuXG5jb25zdCBVbmlmb3Jtc0xpYiA9IHtcblxuXHRjb21tb246IHtcblxuXHRcdGRpZmZ1c2U6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweGZmZmZmZiApIH0sXG5cdFx0b3BhY2l0eTogeyB2YWx1ZTogMS4wIH0sXG5cblx0XHRtYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRtYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXG5cdFx0YWxwaGFNYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRhbHBoYU1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cblx0XHRhbHBoYVRlc3Q6IHsgdmFsdWU6IDAgfVxuXG5cdH0sXG5cblx0c3BlY3VsYXJtYXA6IHtcblxuXHRcdHNwZWN1bGFyTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0c3BlY3VsYXJNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XG5cblx0fSxcblxuXHRlbnZtYXA6IHtcblxuXHRcdGVudk1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGVudk1hcFJvdGF0aW9uOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRmbGlwRW52TWFwOiB7IHZhbHVlOiAtIDEgfSxcblx0XHRyZWZsZWN0aXZpdHk6IHsgdmFsdWU6IDEuMCB9LCAvLyBiYXNpYywgbGFtYmVydCwgcGhvbmdcblx0XHRpb3I6IHsgdmFsdWU6IDEuNSB9LCAvLyBwaHlzaWNhbFxuXHRcdHJlZnJhY3Rpb25SYXRpbzogeyB2YWx1ZTogMC45OCB9LCAvLyBiYXNpYywgbGFtYmVydCwgcGhvbmdcblxuXHR9LFxuXG5cdGFvbWFwOiB7XG5cblx0XHRhb01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGFvTWFwSW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0sXG5cdFx0YW9NYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XG5cblx0fSxcblxuXHRsaWdodG1hcDoge1xuXG5cdFx0bGlnaHRNYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRsaWdodE1hcEludGVuc2l0eTogeyB2YWx1ZTogMSB9LFxuXHRcdGxpZ2h0TWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfVxuXG5cdH0sXG5cblx0YnVtcG1hcDoge1xuXG5cdFx0YnVtcE1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGJ1bXBNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdGJ1bXBTY2FsZTogeyB2YWx1ZTogMSB9XG5cblx0fSxcblxuXHRub3JtYWxtYXA6IHtcblxuXHRcdG5vcm1hbE1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdG5vcm1hbE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cdFx0bm9ybWFsU2NhbGU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoIDEsIDEgKSB9XG5cblx0fSxcblxuXHRkaXNwbGFjZW1lbnRtYXA6IHtcblxuXHRcdGRpc3BsYWNlbWVudE1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGRpc3BsYWNlbWVudE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cdFx0ZGlzcGxhY2VtZW50U2NhbGU6IHsgdmFsdWU6IDEgfSxcblx0XHRkaXNwbGFjZW1lbnRCaWFzOiB7IHZhbHVlOiAwIH1cblxuXHR9LFxuXG5cdGVtaXNzaXZlbWFwOiB7XG5cblx0XHRlbWlzc2l2ZU1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGVtaXNzaXZlTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfVxuXG5cdH0sXG5cblx0bWV0YWxuZXNzbWFwOiB7XG5cblx0XHRtZXRhbG5lc3NNYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRtZXRhbG5lc3NNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XG5cblx0fSxcblxuXHRyb3VnaG5lc3NtYXA6IHtcblxuXHRcdHJvdWdobmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdHJvdWdobmVzc01hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH1cblxuXHR9LFxuXG5cdGdyYWRpZW50bWFwOiB7XG5cblx0XHRncmFkaWVudE1hcDogeyB2YWx1ZTogbnVsbCB9XG5cblx0fSxcblxuXHRmb2c6IHtcblxuXHRcdGZvZ0RlbnNpdHk6IHsgdmFsdWU6IDAuMDAwMjUgfSxcblx0XHRmb2dOZWFyOiB7IHZhbHVlOiAxIH0sXG5cdFx0Zm9nRmFyOiB7IHZhbHVlOiAyMDAwIH0sXG5cdFx0Zm9nQ29sb3I6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweGZmZmZmZiApIH1cblxuXHR9LFxuXG5cdGxpZ2h0czoge1xuXG5cdFx0YW1iaWVudExpZ2h0Q29sb3I6IHsgdmFsdWU6IFtdIH0sXG5cblx0XHRsaWdodFByb2JlOiB7IHZhbHVlOiBbXSB9LFxuXG5cdFx0ZGlyZWN0aW9uYWxMaWdodHM6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XG5cdFx0XHRkaXJlY3Rpb246IHt9LFxuXHRcdFx0Y29sb3I6IHt9XG5cdFx0fSB9LFxuXG5cdFx0ZGlyZWN0aW9uYWxMaWdodFNoYWRvd3M6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XG5cdFx0XHRzaGFkb3dJbnRlbnNpdHk6IDEsXG5cdFx0XHRzaGFkb3dCaWFzOiB7fSxcblx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IHt9LFxuXHRcdFx0c2hhZG93UmFkaXVzOiB7fSxcblx0XHRcdHNoYWRvd01hcFNpemU6IHt9XG5cdFx0fSB9LFxuXG5cdFx0ZGlyZWN0aW9uYWxTaGFkb3dNYXA6IHsgdmFsdWU6IFtdIH0sXG5cdFx0ZGlyZWN0aW9uYWxTaGFkb3dNYXRyaXg6IHsgdmFsdWU6IFtdIH0sXG5cblx0XHRzcG90TGlnaHRzOiB7IHZhbHVlOiBbXSwgcHJvcGVydGllczoge1xuXHRcdFx0Y29sb3I6IHt9LFxuXHRcdFx0cG9zaXRpb246IHt9LFxuXHRcdFx0ZGlyZWN0aW9uOiB7fSxcblx0XHRcdGRpc3RhbmNlOiB7fSxcblx0XHRcdGNvbmVDb3M6IHt9LFxuXHRcdFx0cGVudW1icmFDb3M6IHt9LFxuXHRcdFx0ZGVjYXk6IHt9XG5cdFx0fSB9LFxuXG5cdFx0c3BvdExpZ2h0U2hhZG93czogeyB2YWx1ZTogW10sIHByb3BlcnRpZXM6IHtcblx0XHRcdHNoYWRvd0ludGVuc2l0eTogMSxcblx0XHRcdHNoYWRvd0JpYXM6IHt9LFxuXHRcdFx0c2hhZG93Tm9ybWFsQmlhczoge30sXG5cdFx0XHRzaGFkb3dSYWRpdXM6IHt9LFxuXHRcdFx0c2hhZG93TWFwU2l6ZToge31cblx0XHR9IH0sXG5cblx0XHRzcG90TGlnaHRNYXA6IHsgdmFsdWU6IFtdIH0sXG5cdFx0c3BvdFNoYWRvd01hcDogeyB2YWx1ZTogW10gfSxcblx0XHRzcG90TGlnaHRNYXRyaXg6IHsgdmFsdWU6IFtdIH0sXG5cblx0XHRwb2ludExpZ2h0czogeyB2YWx1ZTogW10sIHByb3BlcnRpZXM6IHtcblx0XHRcdGNvbG9yOiB7fSxcblx0XHRcdHBvc2l0aW9uOiB7fSxcblx0XHRcdGRlY2F5OiB7fSxcblx0XHRcdGRpc3RhbmNlOiB7fVxuXHRcdH0gfSxcblxuXHRcdHBvaW50TGlnaHRTaGFkb3dzOiB7IHZhbHVlOiBbXSwgcHJvcGVydGllczoge1xuXHRcdFx0c2hhZG93SW50ZW5zaXR5OiAxLFxuXHRcdFx0c2hhZG93Qmlhczoge30sXG5cdFx0XHRzaGFkb3dOb3JtYWxCaWFzOiB7fSxcblx0XHRcdHNoYWRvd1JhZGl1czoge30sXG5cdFx0XHRzaGFkb3dNYXBTaXplOiB7fSxcblx0XHRcdHNoYWRvd0NhbWVyYU5lYXI6IHt9LFxuXHRcdFx0c2hhZG93Q2FtZXJhRmFyOiB7fVxuXHRcdH0gfSxcblxuXHRcdHBvaW50U2hhZG93TWFwOiB7IHZhbHVlOiBbXSB9LFxuXHRcdHBvaW50U2hhZG93TWF0cml4OiB7IHZhbHVlOiBbXSB9LFxuXG5cdFx0aGVtaXNwaGVyZUxpZ2h0czogeyB2YWx1ZTogW10sIHByb3BlcnRpZXM6IHtcblx0XHRcdGRpcmVjdGlvbjoge30sXG5cdFx0XHRza3lDb2xvcjoge30sXG5cdFx0XHRncm91bmRDb2xvcjoge31cblx0XHR9IH0sXG5cblx0XHQvLyBUT0RPIChhYmVsbmF0aW9uKTogUmVjdEFyZWFMaWdodCBCUkRGIGRhdGEgbmVlZHMgdG8gYmUgbW92ZWQgZnJvbSBleGFtcGxlIHRvIG1haW4gc3JjXG5cdFx0cmVjdEFyZWFMaWdodHM6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XG5cdFx0XHRjb2xvcjoge30sXG5cdFx0XHRwb3NpdGlvbjoge30sXG5cdFx0XHR3aWR0aDoge30sXG5cdFx0XHRoZWlnaHQ6IHt9XG5cdFx0fSB9LFxuXG5cdFx0bHRjXzE6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRsdGNfMjogeyB2YWx1ZTogbnVsbCB9XG5cblx0fSxcblxuXHRwb2ludHM6IHtcblxuXHRcdGRpZmZ1c2U6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweGZmZmZmZiApIH0sXG5cdFx0b3BhY2l0eTogeyB2YWx1ZTogMS4wIH0sXG5cdFx0c2l6ZTogeyB2YWx1ZTogMS4wIH0sXG5cdFx0c2NhbGU6IHsgdmFsdWU6IDEuMCB9LFxuXHRcdG1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGFscGhhTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0YWxwaGFNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdGFscGhhVGVzdDogeyB2YWx1ZTogMCB9LFxuXHRcdHV2VHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfVxuXG5cdH0sXG5cblx0c3ByaXRlOiB7XG5cblx0XHRkaWZmdXNlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHhmZmZmZmYgKSB9LFxuXHRcdG9wYWNpdHk6IHsgdmFsdWU6IDEuMCB9LFxuXHRcdGNlbnRlcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMiggMC41LCAwLjUgKSB9LFxuXHRcdHJvdGF0aW9uOiB7IHZhbHVlOiAwLjAgfSxcblx0XHRtYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRtYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdGFscGhhTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0YWxwaGFNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdGFscGhhVGVzdDogeyB2YWx1ZTogMCB9XG5cblx0fVxuXG59O1xuXG5jb25zdCBTaGFkZXJMaWIgPSB7XG5cblx0YmFzaWM6IHtcblxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcblx0XHRcdFVuaWZvcm1zTGliLnNwZWN1bGFybWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuZW52bWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuYW9tYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmZvZ1xuXHRcdF0gKSxcblxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaGJhc2ljX3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hiYXNpY19mcmFnXG5cblx0fSxcblxuXHRsYW1iZXJ0OiB7XG5cblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXG5cdFx0XHRVbmlmb3Jtc0xpYi5jb21tb24sXG5cdFx0XHRVbmlmb3Jtc0xpYi5zcGVjdWxhcm1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmVudm1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmFvbWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbWlzc2l2ZW1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmJ1bXBtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5ub3JtYWxtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2csXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodHMsXG5cdFx0XHR7XG5cdFx0XHRcdGVtaXNzaXZlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgwMDAwMDAgKSB9XG5cdFx0XHR9XG5cdFx0XSApLFxuXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobGFtYmVydF92ZXJ0LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobGFtYmVydF9mcmFnXG5cblx0fSxcblxuXHRwaG9uZzoge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxuXHRcdFx0VW5pZm9ybXNMaWIuc3BlY3VsYXJtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbnZtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5hb21hcCxcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0bWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuZW1pc3NpdmVtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5idW1wbWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIubm9ybWFsbWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuZGlzcGxhY2VtZW50bWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuZm9nLFxuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRzLFxuXHRcdFx0e1xuXHRcdFx0XHRlbWlzc2l2ZTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDB4MDAwMDAwICkgfSxcblx0XHRcdFx0c3BlY3VsYXI6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDExMTExMSApIH0sXG5cdFx0XHRcdHNoaW5pbmVzczogeyB2YWx1ZTogMzAgfVxuXHRcdFx0fVxuXHRcdF0gKSxcblxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaHBob25nX3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hwaG9uZ19mcmFnXG5cblx0fSxcblxuXHRzdGFuZGFyZDoge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxuXHRcdFx0VW5pZm9ybXNMaWIuZW52bWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuYW9tYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmVtaXNzaXZlbWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuYnVtcG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLm5vcm1hbG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmRpc3BsYWNlbWVudG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLnJvdWdobmVzc21hcCxcblx0XHRcdFVuaWZvcm1zTGliLm1ldGFsbmVzc21hcCxcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0cyxcblx0XHRcdHtcblx0XHRcdFx0ZW1pc3NpdmU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDAwMDAwMCApIH0sXG5cdFx0XHRcdHJvdWdobmVzczogeyB2YWx1ZTogMS4wIH0sXG5cdFx0XHRcdG1ldGFsbmVzczogeyB2YWx1ZTogMC4wIH0sXG5cdFx0XHRcdGVudk1hcEludGVuc2l0eTogeyB2YWx1ZTogMSB9XG5cdFx0XHR9XG5cdFx0XSApLFxuXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNocGh5c2ljYWxfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaHBoeXNpY2FsX2ZyYWdcblxuXHR9LFxuXG5cdHRvb246IHtcblxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcblx0XHRcdFVuaWZvcm1zTGliLmFvbWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbWlzc2l2ZW1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmJ1bXBtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5ub3JtYWxtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5ncmFkaWVudG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0cyxcblx0XHRcdHtcblx0XHRcdFx0ZW1pc3NpdmU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDAwMDAwMCApIH1cblx0XHRcdH1cblx0XHRdICksXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2h0b29uX3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2h0b29uX2ZyYWdcblxuXHR9LFxuXG5cdG1hdGNhcDoge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxuXHRcdFx0VW5pZm9ybXNMaWIuYnVtcG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLm5vcm1hbG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmRpc3BsYWNlbWVudG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcblx0XHRcdHtcblx0XHRcdFx0bWF0Y2FwOiB7IHZhbHVlOiBudWxsIH1cblx0XHRcdH1cblx0XHRdICksXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2htYXRjYXBfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaG1hdGNhcF9mcmFnXG5cblx0fSxcblxuXHRwb2ludHM6IHtcblxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRcdFVuaWZvcm1zTGliLnBvaW50cyxcblx0XHRcdFVuaWZvcm1zTGliLmZvZ1xuXHRcdF0gKSxcblxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsucG9pbnRzX3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLnBvaW50c19mcmFnXG5cblx0fSxcblxuXHRkYXNoZWQ6IHtcblxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcblx0XHRcdHtcblx0XHRcdFx0c2NhbGU6IHsgdmFsdWU6IDEgfSxcblx0XHRcdFx0ZGFzaFNpemU6IHsgdmFsdWU6IDEgfSxcblx0XHRcdFx0dG90YWxTaXplOiB7IHZhbHVlOiAyIH1cblx0XHRcdH1cblx0XHRdICksXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmxpbmVkYXNoZWRfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubGluZWRhc2hlZF9mcmFnXG5cblx0fSxcblxuXHRkZXB0aDoge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxuXHRcdFx0VW5pZm9ybXNMaWIuZGlzcGxhY2VtZW50bWFwXG5cdFx0XSApLFxuXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5kZXB0aF92ZXJ0LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5kZXB0aF9mcmFnXG5cblx0fSxcblxuXHRub3JtYWw6IHtcblxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcblx0XHRcdFVuaWZvcm1zTGliLmJ1bXBtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5ub3JtYWxtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXG5cdFx0XHR7XG5cdFx0XHRcdG9wYWNpdHk6IHsgdmFsdWU6IDEuMCB9XG5cdFx0XHR9XG5cdFx0XSApLFxuXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobm9ybWFsX3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hub3JtYWxfZnJhZ1xuXG5cdH0sXG5cblx0c3ByaXRlOiB7XG5cblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXG5cdFx0XHRVbmlmb3Jtc0xpYi5zcHJpdGUsXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2dcblx0XHRdICksXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLnNwcml0ZV92ZXJ0LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5zcHJpdGVfZnJhZ1xuXG5cdH0sXG5cblx0YmFja2dyb3VuZDoge1xuXG5cdFx0dW5pZm9ybXM6IHtcblx0XHRcdHV2VHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRcdHQyRDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0YmFja2dyb3VuZEludGVuc2l0eTogeyB2YWx1ZTogMSB9XG5cdFx0fSxcblxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsuYmFja2dyb3VuZF92ZXJ0LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5iYWNrZ3JvdW5kX2ZyYWdcblxuXHR9LFxuXG5cdGJhY2tncm91bmRDdWJlOiB7XG5cblx0XHR1bmlmb3Jtczoge1xuXHRcdFx0ZW52TWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRmbGlwRW52TWFwOiB7IHZhbHVlOiAtIDEgfSxcblx0XHRcdGJhY2tncm91bmRCbHVycmluZXNzOiB7IHZhbHVlOiAwIH0sXG5cdFx0XHRiYWNrZ3JvdW5kSW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0sXG5cdFx0XHRiYWNrZ3JvdW5kUm90YXRpb246IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XG5cdFx0fSxcblxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsuYmFja2dyb3VuZEN1YmVfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsuYmFja2dyb3VuZEN1YmVfZnJhZ1xuXG5cdH0sXG5cblx0Y3ViZToge1xuXG5cdFx0dW5pZm9ybXM6IHtcblx0XHRcdHRDdWJlOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHR0RmxpcDogeyB2YWx1ZTogLSAxIH0sXG5cdFx0XHRvcGFjaXR5OiB7IHZhbHVlOiAxLjAgfVxuXHRcdH0sXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmN1YmVfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsuY3ViZV9mcmFnXG5cblx0fSxcblxuXHRlcXVpcmVjdDoge1xuXG5cdFx0dW5pZm9ybXM6IHtcblx0XHRcdHRFcXVpcmVjdDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdH0sXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmVxdWlyZWN0X3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLmVxdWlyZWN0X2ZyYWdcblxuXHR9LFxuXG5cdGRpc3RhbmNlUkdCQToge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxuXHRcdFx0VW5pZm9ybXNMaWIuZGlzcGxhY2VtZW50bWFwLFxuXHRcdFx0e1xuXHRcdFx0XHRyZWZlcmVuY2VQb3NpdGlvbjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpIH0sXG5cdFx0XHRcdG5lYXJEaXN0YW5jZTogeyB2YWx1ZTogMSB9LFxuXHRcdFx0XHRmYXJEaXN0YW5jZTogeyB2YWx1ZTogMTAwMCB9XG5cdFx0XHR9XG5cdFx0XSApLFxuXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5kaXN0YW5jZVJHQkFfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsuZGlzdGFuY2VSR0JBX2ZyYWdcblxuXHR9LFxuXG5cdHNoYWRvdzoge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRzLFxuXHRcdFx0VW5pZm9ybXNMaWIuZm9nLFxuXHRcdFx0e1xuXHRcdFx0XHRjb2xvcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDB4MDAwMDAgKSB9LFxuXHRcdFx0XHRvcGFjaXR5OiB7IHZhbHVlOiAxLjAgfVxuXHRcdFx0fSxcblx0XHRdICksXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLnNoYWRvd192ZXJ0LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5zaGFkb3dfZnJhZ1xuXG5cdH1cblxufTtcblxuU2hhZGVyTGliLnBoeXNpY2FsID0ge1xuXG5cdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRTaGFkZXJMaWIuc3RhbmRhcmQudW5pZm9ybXMsXG5cdFx0e1xuXHRcdFx0Y2xlYXJjb2F0OiB7IHZhbHVlOiAwIH0sXG5cdFx0XHRjbGVhcmNvYXRNYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdGNsZWFyY29hdE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cdFx0XHRjbGVhcmNvYXROb3JtYWxNYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdGNsZWFyY29hdE5vcm1hbE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cdFx0XHRjbGVhcmNvYXROb3JtYWxTY2FsZTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMiggMSwgMSApIH0sXG5cdFx0XHRjbGVhcmNvYXRSb3VnaG5lc3M6IHsgdmFsdWU6IDAgfSxcblx0XHRcdGNsZWFyY29hdFJvdWdobmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0Y2xlYXJjb2F0Um91Z2huZXNzTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRcdGRpc3BlcnNpb246IHsgdmFsdWU6IDAgfSxcblx0XHRcdGlyaWRlc2NlbmNlOiB7IHZhbHVlOiAwIH0sXG5cdFx0XHRpcmlkZXNjZW5jZU1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0aXJpZGVzY2VuY2VNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdFx0aXJpZGVzY2VuY2VJT1I6IHsgdmFsdWU6IDEuMyB9LFxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNaW5pbXVtOiB7IHZhbHVlOiAxMDAgfSxcblx0XHRcdGlyaWRlc2NlbmNlVGhpY2tuZXNzTWF4aW11bTogeyB2YWx1ZTogNDAwIH0sXG5cdFx0XHRpcmlkZXNjZW5jZVRoaWNrbmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdFx0c2hlZW46IHsgdmFsdWU6IDAgfSxcblx0XHRcdHNoZWVuQ29sb3I6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDAwMDAwMCApIH0sXG5cdFx0XHRzaGVlbkNvbG9yTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRzaGVlbkNvbG9yTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRcdHNoZWVuUm91Z2huZXNzOiB7IHZhbHVlOiAxIH0sXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0c2hlZW5Sb3VnaG5lc3NNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdFx0dHJhbnNtaXNzaW9uOiB7IHZhbHVlOiAwIH0sXG5cdFx0XHR0cmFuc21pc3Npb25NYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdHRyYW5zbWlzc2lvbk1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cdFx0XHR0cmFuc21pc3Npb25TYW1wbGVyU2l6ZTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpIH0sXG5cdFx0XHR0cmFuc21pc3Npb25TYW1wbGVyTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHR0aGlja25lc3M6IHsgdmFsdWU6IDAgfSxcblx0XHRcdHRoaWNrbmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0dGhpY2tuZXNzTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRcdGF0dGVudWF0aW9uRGlzdGFuY2U6IHsgdmFsdWU6IDAgfSxcblx0XHRcdGF0dGVudWF0aW9uQ29sb3I6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDAwMDAwMCApIH0sXG5cdFx0XHRzcGVjdWxhckNvbG9yOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMSwgMSwgMSApIH0sXG5cdFx0XHRzcGVjdWxhckNvbG9yTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRzcGVjdWxhckNvbG9yTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0sXG5cdFx0XHRzcGVjdWxhckludGVuc2l0eU1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0c3BlY3VsYXJJbnRlbnNpdHlNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdFx0YW5pc290cm9weVZlY3RvcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpIH0sXG5cdFx0XHRhbmlzb3Ryb3B5TWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRhbmlzb3Ryb3B5TWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHR9XG5cdF0gKSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hwaHlzaWNhbF92ZXJ0LFxuXHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaHBoeXNpY2FsX2ZyYWdcblxufTtcblxuY29uc3QgX3JnYiA9IHsgcjogMCwgYjogMCwgZzogMCB9O1xuY29uc3QgX2UxJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBFdWxlcigpO1xuY29uc3QgX20xJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5cbmZ1bmN0aW9uIFdlYkdMQmFja2dyb3VuZCggcmVuZGVyZXIsIGN1YmVtYXBzLCBjdWJldXZtYXBzLCBzdGF0ZSwgb2JqZWN0cywgYWxwaGEsIHByZW11bHRpcGxpZWRBbHBoYSApIHtcblxuXHRjb25zdCBjbGVhckNvbG9yID0gbmV3IENvbG9yKCAweDAwMDAwMCApO1xuXHRsZXQgY2xlYXJBbHBoYSA9IGFscGhhID09PSB0cnVlID8gMCA6IDE7XG5cblx0bGV0IHBsYW5lTWVzaDtcblx0bGV0IGJveE1lc2g7XG5cblx0bGV0IGN1cnJlbnRCYWNrZ3JvdW5kID0gbnVsbDtcblx0bGV0IGN1cnJlbnRCYWNrZ3JvdW5kVmVyc2lvbiA9IDA7XG5cdGxldCBjdXJyZW50VG9uZW1hcHBpbmcgPSBudWxsO1xuXG5cdGZ1bmN0aW9uIGdldEJhY2tncm91bmQoIHNjZW5lICkge1xuXG5cdFx0bGV0IGJhY2tncm91bmQgPSBzY2VuZS5pc1NjZW5lID09PSB0cnVlID8gc2NlbmUuYmFja2dyb3VuZCA6IG51bGw7XG5cblx0XHRpZiAoIGJhY2tncm91bmQgJiYgYmFja2dyb3VuZC5pc1RleHR1cmUgKSB7XG5cblx0XHRcdGNvbnN0IHVzZVBNUkVNID0gc2NlbmUuYmFja2dyb3VuZEJsdXJyaW5lc3MgPiAwOyAvLyB1c2UgUE1SRU0gaWYgdGhlIHVzZXIgd2FudHMgdG8gYmx1ciB0aGUgYmFja2dyb3VuZFxuXHRcdFx0YmFja2dyb3VuZCA9ICggdXNlUE1SRU0gPyBjdWJldXZtYXBzIDogY3ViZW1hcHMgKS5nZXQoIGJhY2tncm91bmQgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBiYWNrZ3JvdW5kO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXIoIHNjZW5lICkge1xuXG5cdFx0bGV0IGZvcmNlQ2xlYXIgPSBmYWxzZTtcblx0XHRjb25zdCBiYWNrZ3JvdW5kID0gZ2V0QmFja2dyb3VuZCggc2NlbmUgKTtcblxuXHRcdGlmICggYmFja2dyb3VuZCA9PT0gbnVsbCApIHtcblxuXHRcdFx0c2V0Q2xlYXIoIGNsZWFyQ29sb3IsIGNsZWFyQWxwaGEgKTtcblxuXHRcdH0gZWxzZSBpZiAoIGJhY2tncm91bmQgJiYgYmFja2dyb3VuZC5pc0NvbG9yICkge1xuXG5cdFx0XHRzZXRDbGVhciggYmFja2dyb3VuZCwgMSApO1xuXHRcdFx0Zm9yY2VDbGVhciA9IHRydWU7XG5cblx0XHR9XG5cblx0XHRjb25zdCBlbnZpcm9ubWVudEJsZW5kTW9kZSA9IHJlbmRlcmVyLnhyLmdldEVudmlyb25tZW50QmxlbmRNb2RlKCk7XG5cblx0XHRpZiAoIGVudmlyb25tZW50QmxlbmRNb2RlID09PSAnYWRkaXRpdmUnICkge1xuXG5cdFx0XHRzdGF0ZS5idWZmZXJzLmNvbG9yLnNldENsZWFyKCAwLCAwLCAwLCAxLCBwcmVtdWx0aXBsaWVkQWxwaGEgKTtcblxuXHRcdH0gZWxzZSBpZiAoIGVudmlyb25tZW50QmxlbmRNb2RlID09PSAnYWxwaGEtYmxlbmQnICkge1xuXG5cdFx0XHRzdGF0ZS5idWZmZXJzLmNvbG9yLnNldENsZWFyKCAwLCAwLCAwLCAwLCBwcmVtdWx0aXBsaWVkQWxwaGEgKTtcblxuXHRcdH1cblxuXHRcdGlmICggcmVuZGVyZXIuYXV0b0NsZWFyIHx8IGZvcmNlQ2xlYXIgKSB7XG5cblx0XHRcdC8vIGJ1ZmZlcnMgbWlnaHQgbm90IGJlIHdyaXRhYmxlIHdoaWNoIGlzIHJlcXVpcmVkIHRvIGVuc3VyZSBhIGNvcnJlY3QgY2xlYXJcblxuXHRcdFx0c3RhdGUuYnVmZmVycy5kZXB0aC5zZXRUZXN0KCB0cnVlICk7XG5cdFx0XHRzdGF0ZS5idWZmZXJzLmRlcHRoLnNldE1hc2soIHRydWUgKTtcblx0XHRcdHN0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0TWFzayggdHJ1ZSApO1xuXG5cdFx0XHRyZW5kZXJlci5jbGVhciggcmVuZGVyZXIuYXV0b0NsZWFyQ29sb3IsIHJlbmRlcmVyLmF1dG9DbGVhckRlcHRoLCByZW5kZXJlci5hdXRvQ2xlYXJTdGVuY2lsICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGFkZFRvUmVuZGVyTGlzdCggcmVuZGVyTGlzdCwgc2NlbmUgKSB7XG5cblx0XHRjb25zdCBiYWNrZ3JvdW5kID0gZ2V0QmFja2dyb3VuZCggc2NlbmUgKTtcblxuXHRcdGlmICggYmFja2dyb3VuZCAmJiAoIGJhY2tncm91bmQuaXNDdWJlVGV4dHVyZSB8fCBiYWNrZ3JvdW5kLm1hcHBpbmcgPT09IEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nICkgKSB7XG5cblx0XHRcdGlmICggYm94TWVzaCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGJveE1lc2ggPSBuZXcgTWVzaChcblx0XHRcdFx0XHRuZXcgQm94R2VvbWV0cnkoIDEsIDEsIDEgKSxcblx0XHRcdFx0XHRuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcblx0XHRcdFx0XHRcdG5hbWU6ICdCYWNrZ3JvdW5kQ3ViZU1hdGVyaWFsJyxcblx0XHRcdFx0XHRcdHVuaWZvcm1zOiBjbG9uZVVuaWZvcm1zKCBTaGFkZXJMaWIuYmFja2dyb3VuZEN1YmUudW5pZm9ybXMgKSxcblx0XHRcdFx0XHRcdHZlcnRleFNoYWRlcjogU2hhZGVyTGliLmJhY2tncm91bmRDdWJlLnZlcnRleFNoYWRlcixcblx0XHRcdFx0XHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJMaWIuYmFja2dyb3VuZEN1YmUuZnJhZ21lbnRTaGFkZXIsXG5cdFx0XHRcdFx0XHRzaWRlOiBCYWNrU2lkZSxcblx0XHRcdFx0XHRcdGRlcHRoVGVzdDogZmFsc2UsXG5cdFx0XHRcdFx0XHRkZXB0aFdyaXRlOiBmYWxzZSxcblx0XHRcdFx0XHRcdGZvZzogZmFsc2Vcblx0XHRcdFx0XHR9IClcblx0XHRcdFx0KTtcblxuXHRcdFx0XHRib3hNZXNoLmdlb21ldHJ5LmRlbGV0ZUF0dHJpYnV0ZSggJ25vcm1hbCcgKTtcblx0XHRcdFx0Ym94TWVzaC5nZW9tZXRyeS5kZWxldGVBdHRyaWJ1dGUoICd1dicgKTtcblxuXHRcdFx0XHRib3hNZXNoLm9uQmVmb3JlUmVuZGVyID0gZnVuY3Rpb24gKCByZW5kZXJlciwgc2NlbmUsIGNhbWVyYSApIHtcblxuXHRcdFx0XHRcdHRoaXMubWF0cml4V29ybGQuY29weVBvc2l0aW9uKCBjYW1lcmEubWF0cml4V29ybGQgKTtcblxuXHRcdFx0XHR9O1xuXG5cdFx0XHRcdC8vIGFkZCBcImVudk1hcFwiIG1hdGVyaWFsIHByb3BlcnR5IHNvIHRoZSByZW5kZXJlciBjYW4gZXZhbHVhdGUgaXQgbGlrZSBmb3IgYnVpbHQtaW4gbWF0ZXJpYWxzXG5cdFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggYm94TWVzaC5tYXRlcmlhbCwgJ2Vudk1hcCcsIHtcblxuXHRcdFx0XHRcdGdldDogZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy51bmlmb3Jtcy5lbnZNYXAudmFsdWU7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdG9iamVjdHMudXBkYXRlKCBib3hNZXNoICk7XG5cblx0XHRcdH1cblxuXHRcdFx0X2UxJDEuY29weSggc2NlbmUuYmFja2dyb3VuZFJvdGF0aW9uICk7XG5cblx0XHRcdC8vIGFjY29tbW9kYXRlIGxlZnQtaGFuZGVkIGZyYW1lXG5cdFx0XHRfZTEkMS54ICo9IC0gMTsgX2UxJDEueSAqPSAtIDE7IF9lMSQxLnogKj0gLSAxO1xuXG5cdFx0XHRpZiAoIGJhY2tncm91bmQuaXNDdWJlVGV4dHVyZSAmJiBiYWNrZ3JvdW5kLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0Ly8gZW52aXJvbm1lbnQgbWFwcyB3aGljaCBhcmUgbm90IGN1YmUgcmVuZGVyIHRhcmdldHMgb3IgUE1SRU1zIGZvbGxvdyBhIGRpZmZlcmVudCBjb252ZW50aW9uXG5cdFx0XHRcdF9lMSQxLnkgKj0gLSAxO1xuXHRcdFx0XHRfZTEkMS56ICo9IC0gMTtcblxuXHRcdFx0fVxuXG5cdFx0XHRib3hNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmVudk1hcC52YWx1ZSA9IGJhY2tncm91bmQ7XG5cdFx0XHRib3hNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmZsaXBFbnZNYXAudmFsdWUgPSAoIGJhY2tncm91bmQuaXNDdWJlVGV4dHVyZSAmJiBiYWNrZ3JvdW5kLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSA/IC0gMSA6IDE7XG5cdFx0XHRib3hNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmJhY2tncm91bmRCbHVycmluZXNzLnZhbHVlID0gc2NlbmUuYmFja2dyb3VuZEJsdXJyaW5lc3M7XG5cdFx0XHRib3hNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmJhY2tncm91bmRJbnRlbnNpdHkudmFsdWUgPSBzY2VuZS5iYWNrZ3JvdW5kSW50ZW5zaXR5O1xuXHRcdFx0Ym94TWVzaC5tYXRlcmlhbC51bmlmb3Jtcy5iYWNrZ3JvdW5kUm90YXRpb24udmFsdWUuc2V0RnJvbU1hdHJpeDQoIF9tMSQxLm1ha2VSb3RhdGlvbkZyb21FdWxlciggX2UxJDEgKSApO1xuXHRcdFx0Ym94TWVzaC5tYXRlcmlhbC50b25lTWFwcGVkID0gQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBiYWNrZ3JvdW5kLmNvbG9yU3BhY2UgKSAhPT0gU1JHQlRyYW5zZmVyO1xuXG5cdFx0XHRpZiAoIGN1cnJlbnRCYWNrZ3JvdW5kICE9PSBiYWNrZ3JvdW5kIHx8XG5cdFx0XHRcdGN1cnJlbnRCYWNrZ3JvdW5kVmVyc2lvbiAhPT0gYmFja2dyb3VuZC52ZXJzaW9uIHx8XG5cdFx0XHRcdGN1cnJlbnRUb25lbWFwcGluZyAhPT0gcmVuZGVyZXIudG9uZU1hcHBpbmcgKSB7XG5cblx0XHRcdFx0Ym94TWVzaC5tYXRlcmlhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdFx0Y3VycmVudEJhY2tncm91bmQgPSBiYWNrZ3JvdW5kO1xuXHRcdFx0XHRjdXJyZW50QmFja2dyb3VuZFZlcnNpb24gPSBiYWNrZ3JvdW5kLnZlcnNpb247XG5cdFx0XHRcdGN1cnJlbnRUb25lbWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xuXG5cdFx0XHR9XG5cblx0XHRcdGJveE1lc2gubGF5ZXJzLmVuYWJsZUFsbCgpO1xuXG5cdFx0XHQvLyBwdXNoIHRvIHRoZSBwcmUtc29ydGVkIG9wYXF1ZSByZW5kZXIgbGlzdFxuXHRcdFx0cmVuZGVyTGlzdC51bnNoaWZ0KCBib3hNZXNoLCBib3hNZXNoLmdlb21ldHJ5LCBib3hNZXNoLm1hdGVyaWFsLCAwLCAwLCBudWxsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBiYWNrZ3JvdW5kICYmIGJhY2tncm91bmQuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRpZiAoIHBsYW5lTWVzaCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHBsYW5lTWVzaCA9IG5ldyBNZXNoKFxuXHRcdFx0XHRcdG5ldyBQbGFuZUdlb21ldHJ5KCAyLCAyICksXG5cdFx0XHRcdFx0bmV3IFNoYWRlck1hdGVyaWFsKCB7XG5cdFx0XHRcdFx0XHRuYW1lOiAnQmFja2dyb3VuZE1hdGVyaWFsJyxcblx0XHRcdFx0XHRcdHVuaWZvcm1zOiBjbG9uZVVuaWZvcm1zKCBTaGFkZXJMaWIuYmFja2dyb3VuZC51bmlmb3JtcyApLFxuXHRcdFx0XHRcdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJMaWIuYmFja2dyb3VuZC52ZXJ0ZXhTaGFkZXIsXG5cdFx0XHRcdFx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyTGliLmJhY2tncm91bmQuZnJhZ21lbnRTaGFkZXIsXG5cdFx0XHRcdFx0XHRzaWRlOiBGcm9udFNpZGUsXG5cdFx0XHRcdFx0XHRkZXB0aFRlc3Q6IGZhbHNlLFxuXHRcdFx0XHRcdFx0ZGVwdGhXcml0ZTogZmFsc2UsXG5cdFx0XHRcdFx0XHRmb2c6IGZhbHNlXG5cdFx0XHRcdFx0fSApXG5cdFx0XHRcdCk7XG5cblx0XHRcdFx0cGxhbmVNZXNoLmdlb21ldHJ5LmRlbGV0ZUF0dHJpYnV0ZSggJ25vcm1hbCcgKTtcblxuXHRcdFx0XHQvLyBhZGQgXCJtYXBcIiBtYXRlcmlhbCBwcm9wZXJ0eSBzbyB0aGUgcmVuZGVyZXIgY2FuIGV2YWx1YXRlIGl0IGxpa2UgZm9yIGJ1aWx0LWluIG1hdGVyaWFsc1xuXHRcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoIHBsYW5lTWVzaC5tYXRlcmlhbCwgJ21hcCcsIHtcblxuXHRcdFx0XHRcdGdldDogZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy51bmlmb3Jtcy50MkQudmFsdWU7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdG9iamVjdHMudXBkYXRlKCBwbGFuZU1lc2ggKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRwbGFuZU1lc2gubWF0ZXJpYWwudW5pZm9ybXMudDJELnZhbHVlID0gYmFja2dyb3VuZDtcblx0XHRcdHBsYW5lTWVzaC5tYXRlcmlhbC51bmlmb3Jtcy5iYWNrZ3JvdW5kSW50ZW5zaXR5LnZhbHVlID0gc2NlbmUuYmFja2dyb3VuZEludGVuc2l0eTtcblx0XHRcdHBsYW5lTWVzaC5tYXRlcmlhbC50b25lTWFwcGVkID0gQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBiYWNrZ3JvdW5kLmNvbG9yU3BhY2UgKSAhPT0gU1JHQlRyYW5zZmVyO1xuXG5cdFx0XHRpZiAoIGJhY2tncm91bmQubWF0cml4QXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRiYWNrZ3JvdW5kLnVwZGF0ZU1hdHJpeCgpO1xuXG5cdFx0XHR9XG5cblx0XHRcdHBsYW5lTWVzaC5tYXRlcmlhbC51bmlmb3Jtcy51dlRyYW5zZm9ybS52YWx1ZS5jb3B5KCBiYWNrZ3JvdW5kLm1hdHJpeCApO1xuXG5cdFx0XHRpZiAoIGN1cnJlbnRCYWNrZ3JvdW5kICE9PSBiYWNrZ3JvdW5kIHx8XG5cdFx0XHRcdGN1cnJlbnRCYWNrZ3JvdW5kVmVyc2lvbiAhPT0gYmFja2dyb3VuZC52ZXJzaW9uIHx8XG5cdFx0XHRcdGN1cnJlbnRUb25lbWFwcGluZyAhPT0gcmVuZGVyZXIudG9uZU1hcHBpbmcgKSB7XG5cblx0XHRcdFx0cGxhbmVNZXNoLm1hdGVyaWFsLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdFx0XHRjdXJyZW50QmFja2dyb3VuZCA9IGJhY2tncm91bmQ7XG5cdFx0XHRcdGN1cnJlbnRCYWNrZ3JvdW5kVmVyc2lvbiA9IGJhY2tncm91bmQudmVyc2lvbjtcblx0XHRcdFx0Y3VycmVudFRvbmVtYXBwaW5nID0gcmVuZGVyZXIudG9uZU1hcHBpbmc7XG5cblx0XHRcdH1cblxuXHRcdFx0cGxhbmVNZXNoLmxheWVycy5lbmFibGVBbGwoKTtcblxuXHRcdFx0Ly8gcHVzaCB0byB0aGUgcHJlLXNvcnRlZCBvcGFxdWUgcmVuZGVyIGxpc3Rcblx0XHRcdHJlbmRlckxpc3QudW5zaGlmdCggcGxhbmVNZXNoLCBwbGFuZU1lc2guZ2VvbWV0cnksIHBsYW5lTWVzaC5tYXRlcmlhbCwgMCwgMCwgbnVsbCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBzZXRDbGVhciggY29sb3IsIGFscGhhICkge1xuXG5cdFx0Y29sb3IuZ2V0UkdCKCBfcmdiLCBnZXRVbmxpdFVuaWZvcm1Db2xvclNwYWNlKCByZW5kZXJlciApICk7XG5cblx0XHRzdGF0ZS5idWZmZXJzLmNvbG9yLnNldENsZWFyKCBfcmdiLnIsIF9yZ2IuZywgX3JnYi5iLCBhbHBoYSwgcHJlbXVsdGlwbGllZEFscGhhICk7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cblx0XHRnZXRDbGVhckNvbG9yOiBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBjbGVhckNvbG9yO1xuXG5cdFx0fSxcblx0XHRzZXRDbGVhckNvbG9yOiBmdW5jdGlvbiAoIGNvbG9yLCBhbHBoYSA9IDEgKSB7XG5cblx0XHRcdGNsZWFyQ29sb3Iuc2V0KCBjb2xvciApO1xuXHRcdFx0Y2xlYXJBbHBoYSA9IGFscGhhO1xuXHRcdFx0c2V0Q2xlYXIoIGNsZWFyQ29sb3IsIGNsZWFyQWxwaGEgKTtcblxuXHRcdH0sXG5cdFx0Z2V0Q2xlYXJBbHBoYTogZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gY2xlYXJBbHBoYTtcblxuXHRcdH0sXG5cdFx0c2V0Q2xlYXJBbHBoYTogZnVuY3Rpb24gKCBhbHBoYSApIHtcblxuXHRcdFx0Y2xlYXJBbHBoYSA9IGFscGhhO1xuXHRcdFx0c2V0Q2xlYXIoIGNsZWFyQ29sb3IsIGNsZWFyQWxwaGEgKTtcblxuXHRcdH0sXG5cdFx0cmVuZGVyOiByZW5kZXIsXG5cdFx0YWRkVG9SZW5kZXJMaXN0OiBhZGRUb1JlbmRlckxpc3RcblxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMQmluZGluZ1N0YXRlcyggZ2wsIGF0dHJpYnV0ZXMgKSB7XG5cblx0Y29uc3QgbWF4VmVydGV4QXR0cmlidXRlcyA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1ZFUlRFWF9BVFRSSUJTICk7XG5cblx0Y29uc3QgYmluZGluZ1N0YXRlcyA9IHt9O1xuXG5cdGNvbnN0IGRlZmF1bHRTdGF0ZSA9IGNyZWF0ZUJpbmRpbmdTdGF0ZSggbnVsbCApO1xuXHRsZXQgY3VycmVudFN0YXRlID0gZGVmYXVsdFN0YXRlO1xuXHRsZXQgZm9yY2VVcGRhdGUgPSBmYWxzZTtcblxuXHRmdW5jdGlvbiBzZXR1cCggb2JqZWN0LCBtYXRlcmlhbCwgcHJvZ3JhbSwgZ2VvbWV0cnksIGluZGV4ICkge1xuXG5cdFx0bGV0IHVwZGF0ZUJ1ZmZlcnMgPSBmYWxzZTtcblxuXHRcdGNvbnN0IHN0YXRlID0gZ2V0QmluZGluZ1N0YXRlKCBnZW9tZXRyeSwgcHJvZ3JhbSwgbWF0ZXJpYWwgKTtcblxuXHRcdGlmICggY3VycmVudFN0YXRlICE9PSBzdGF0ZSApIHtcblxuXHRcdFx0Y3VycmVudFN0YXRlID0gc3RhdGU7XG5cdFx0XHRiaW5kVmVydGV4QXJyYXlPYmplY3QoIGN1cnJlbnRTdGF0ZS5vYmplY3QgKTtcblxuXHRcdH1cblxuXHRcdHVwZGF0ZUJ1ZmZlcnMgPSBuZWVkc1VwZGF0ZSggb2JqZWN0LCBnZW9tZXRyeSwgcHJvZ3JhbSwgaW5kZXggKTtcblxuXHRcdGlmICggdXBkYXRlQnVmZmVycyApIHNhdmVDYWNoZSggb2JqZWN0LCBnZW9tZXRyeSwgcHJvZ3JhbSwgaW5kZXggKTtcblxuXHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XG5cblx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBpbmRleCwgZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdXBkYXRlQnVmZmVycyB8fCBmb3JjZVVwZGF0ZSApIHtcblxuXHRcdFx0Zm9yY2VVcGRhdGUgPSBmYWxzZTtcblxuXHRcdFx0c2V0dXBWZXJ0ZXhBdHRyaWJ1dGVzKCBvYmplY3QsIG1hdGVyaWFsLCBwcm9ncmFtLCBnZW9tZXRyeSApO1xuXG5cdFx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGdsLmJpbmRCdWZmZXIoIGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCBhdHRyaWJ1dGVzLmdldCggaW5kZXggKS5idWZmZXIgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBjcmVhdGVWZXJ0ZXhBcnJheU9iamVjdCgpIHtcblxuXHRcdHJldHVybiBnbC5jcmVhdGVWZXJ0ZXhBcnJheSgpO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBiaW5kVmVydGV4QXJyYXlPYmplY3QoIHZhbyApIHtcblxuXHRcdHJldHVybiBnbC5iaW5kVmVydGV4QXJyYXkoIHZhbyApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBkZWxldGVWZXJ0ZXhBcnJheU9iamVjdCggdmFvICkge1xuXG5cdFx0cmV0dXJuIGdsLmRlbGV0ZVZlcnRleEFycmF5KCB2YW8gKTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0QmluZGluZ1N0YXRlKCBnZW9tZXRyeSwgcHJvZ3JhbSwgbWF0ZXJpYWwgKSB7XG5cblx0XHRjb25zdCB3aXJlZnJhbWUgPSAoIG1hdGVyaWFsLndpcmVmcmFtZSA9PT0gdHJ1ZSApO1xuXG5cdFx0bGV0IHByb2dyYW1NYXAgPSBiaW5kaW5nU3RhdGVzWyBnZW9tZXRyeS5pZCBdO1xuXG5cdFx0aWYgKCBwcm9ncmFtTWFwID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHByb2dyYW1NYXAgPSB7fTtcblx0XHRcdGJpbmRpbmdTdGF0ZXNbIGdlb21ldHJ5LmlkIF0gPSBwcm9ncmFtTWFwO1xuXG5cdFx0fVxuXG5cdFx0bGV0IHN0YXRlTWFwID0gcHJvZ3JhbU1hcFsgcHJvZ3JhbS5pZCBdO1xuXG5cdFx0aWYgKCBzdGF0ZU1hcCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRzdGF0ZU1hcCA9IHt9O1xuXHRcdFx0cHJvZ3JhbU1hcFsgcHJvZ3JhbS5pZCBdID0gc3RhdGVNYXA7XG5cblx0XHR9XG5cblx0XHRsZXQgc3RhdGUgPSBzdGF0ZU1hcFsgd2lyZWZyYW1lIF07XG5cblx0XHRpZiAoIHN0YXRlID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHN0YXRlID0gY3JlYXRlQmluZGluZ1N0YXRlKCBjcmVhdGVWZXJ0ZXhBcnJheU9iamVjdCgpICk7XG5cdFx0XHRzdGF0ZU1hcFsgd2lyZWZyYW1lIF0gPSBzdGF0ZTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBzdGF0ZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gY3JlYXRlQmluZGluZ1N0YXRlKCB2YW8gKSB7XG5cblx0XHRjb25zdCBuZXdBdHRyaWJ1dGVzID0gW107XG5cdFx0Y29uc3QgZW5hYmxlZEF0dHJpYnV0ZXMgPSBbXTtcblx0XHRjb25zdCBhdHRyaWJ1dGVEaXZpc29ycyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbWF4VmVydGV4QXR0cmlidXRlczsgaSArKyApIHtcblxuXHRcdFx0bmV3QXR0cmlidXRlc1sgaSBdID0gMDtcblx0XHRcdGVuYWJsZWRBdHRyaWJ1dGVzWyBpIF0gPSAwO1xuXHRcdFx0YXR0cmlidXRlRGl2aXNvcnNbIGkgXSA9IDA7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4ge1xuXG5cdFx0XHQvLyBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSBvbiBub24tVkFPIHN1cHBvcnQgYnJvd3NlclxuXHRcdFx0Z2VvbWV0cnk6IG51bGwsXG5cdFx0XHRwcm9ncmFtOiBudWxsLFxuXHRcdFx0d2lyZWZyYW1lOiBmYWxzZSxcblxuXHRcdFx0bmV3QXR0cmlidXRlczogbmV3QXR0cmlidXRlcyxcblx0XHRcdGVuYWJsZWRBdHRyaWJ1dGVzOiBlbmFibGVkQXR0cmlidXRlcyxcblx0XHRcdGF0dHJpYnV0ZURpdmlzb3JzOiBhdHRyaWJ1dGVEaXZpc29ycyxcblx0XHRcdG9iamVjdDogdmFvLFxuXHRcdFx0YXR0cmlidXRlczoge30sXG5cdFx0XHRpbmRleDogbnVsbFxuXG5cdFx0fTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gbmVlZHNVcGRhdGUoIG9iamVjdCwgZ2VvbWV0cnksIHByb2dyYW0sIGluZGV4ICkge1xuXG5cdFx0Y29uc3QgY2FjaGVkQXR0cmlidXRlcyA9IGN1cnJlbnRTdGF0ZS5hdHRyaWJ1dGVzO1xuXHRcdGNvbnN0IGdlb21ldHJ5QXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XG5cblx0XHRsZXQgYXR0cmlidXRlc051bSA9IDA7XG5cblx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlcyA9IHByb2dyYW0uZ2V0QXR0cmlidXRlcygpO1xuXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBwcm9ncmFtQXR0cmlidXRlcyApIHtcblxuXHRcdFx0Y29uc3QgcHJvZ3JhbUF0dHJpYnV0ZSA9IHByb2dyYW1BdHRyaWJ1dGVzWyBuYW1lIF07XG5cblx0XHRcdGlmICggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiA+PSAwICkge1xuXG5cdFx0XHRcdGNvbnN0IGNhY2hlZEF0dHJpYnV0ZSA9IGNhY2hlZEF0dHJpYnV0ZXNbIG5hbWUgXTtcblx0XHRcdFx0bGV0IGdlb21ldHJ5QXR0cmlidXRlID0gZ2VvbWV0cnlBdHRyaWJ1dGVzWyBuYW1lIF07XG5cblx0XHRcdFx0aWYgKCBnZW9tZXRyeUF0dHJpYnV0ZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0aWYgKCBuYW1lID09PSAnaW5zdGFuY2VNYXRyaXgnICYmIG9iamVjdC5pbnN0YW5jZU1hdHJpeCApIGdlb21ldHJ5QXR0cmlidXRlID0gb2JqZWN0Lmluc3RhbmNlTWF0cml4O1xuXHRcdFx0XHRcdGlmICggbmFtZSA9PT0gJ2luc3RhbmNlQ29sb3InICYmIG9iamVjdC5pbnN0YW5jZUNvbG9yICkgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBvYmplY3QuaW5zdGFuY2VDb2xvcjtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBjYWNoZWRBdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIHJldHVybiB0cnVlO1xuXG5cdFx0XHRcdGlmICggY2FjaGVkQXR0cmlidXRlLmF0dHJpYnV0ZSAhPT0gZ2VvbWV0cnlBdHRyaWJ1dGUgKSByZXR1cm4gdHJ1ZTtcblxuXHRcdFx0XHRpZiAoIGdlb21ldHJ5QXR0cmlidXRlICYmIGNhY2hlZEF0dHJpYnV0ZS5kYXRhICE9PSBnZW9tZXRyeUF0dHJpYnV0ZS5kYXRhICkgcmV0dXJuIHRydWU7XG5cblx0XHRcdFx0YXR0cmlidXRlc051bSArKztcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBjdXJyZW50U3RhdGUuYXR0cmlidXRlc051bSAhPT0gYXR0cmlidXRlc051bSApIHJldHVybiB0cnVlO1xuXG5cdFx0aWYgKCBjdXJyZW50U3RhdGUuaW5kZXggIT09IGluZGV4ICkgcmV0dXJuIHRydWU7XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHNhdmVDYWNoZSggb2JqZWN0LCBnZW9tZXRyeSwgcHJvZ3JhbSwgaW5kZXggKSB7XG5cblx0XHRjb25zdCBjYWNoZSA9IHt9O1xuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzO1xuXHRcdGxldCBhdHRyaWJ1dGVzTnVtID0gMDtcblxuXHRcdGNvbnN0IHByb2dyYW1BdHRyaWJ1dGVzID0gcHJvZ3JhbS5nZXRBdHRyaWJ1dGVzKCk7XG5cblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIHByb2dyYW1BdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlID0gcHJvZ3JhbUF0dHJpYnV0ZXNbIG5hbWUgXTtcblxuXHRcdFx0aWYgKCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uID49IDAgKSB7XG5cblx0XHRcdFx0bGV0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXNbIG5hbWUgXTtcblxuXHRcdFx0XHRpZiAoIGF0dHJpYnV0ZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0aWYgKCBuYW1lID09PSAnaW5zdGFuY2VNYXRyaXgnICYmIG9iamVjdC5pbnN0YW5jZU1hdHJpeCApIGF0dHJpYnV0ZSA9IG9iamVjdC5pbnN0YW5jZU1hdHJpeDtcblx0XHRcdFx0XHRpZiAoIG5hbWUgPT09ICdpbnN0YW5jZUNvbG9yJyAmJiBvYmplY3QuaW5zdGFuY2VDb2xvciApIGF0dHJpYnV0ZSA9IG9iamVjdC5pbnN0YW5jZUNvbG9yO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRjb25zdCBkYXRhID0ge307XG5cdFx0XHRcdGRhdGEuYXR0cmlidXRlID0gYXR0cmlidXRlO1xuXG5cdFx0XHRcdGlmICggYXR0cmlidXRlICYmIGF0dHJpYnV0ZS5kYXRhICkge1xuXG5cdFx0XHRcdFx0ZGF0YS5kYXRhID0gYXR0cmlidXRlLmRhdGE7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNhY2hlWyBuYW1lIF0gPSBkYXRhO1xuXG5cdFx0XHRcdGF0dHJpYnV0ZXNOdW0gKys7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGN1cnJlbnRTdGF0ZS5hdHRyaWJ1dGVzID0gY2FjaGU7XG5cdFx0Y3VycmVudFN0YXRlLmF0dHJpYnV0ZXNOdW0gPSBhdHRyaWJ1dGVzTnVtO1xuXG5cdFx0Y3VycmVudFN0YXRlLmluZGV4ID0gaW5kZXg7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGluaXRBdHRyaWJ1dGVzKCkge1xuXG5cdFx0Y29uc3QgbmV3QXR0cmlidXRlcyA9IGN1cnJlbnRTdGF0ZS5uZXdBdHRyaWJ1dGVzO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IG5ld0F0dHJpYnV0ZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdG5ld0F0dHJpYnV0ZXNbIGkgXSA9IDA7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGVuYWJsZUF0dHJpYnV0ZSggYXR0cmlidXRlICkge1xuXG5cdFx0ZW5hYmxlQXR0cmlidXRlQW5kRGl2aXNvciggYXR0cmlidXRlLCAwICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGVuYWJsZUF0dHJpYnV0ZUFuZERpdmlzb3IoIGF0dHJpYnV0ZSwgbWVzaFBlckF0dHJpYnV0ZSApIHtcblxuXHRcdGNvbnN0IG5ld0F0dHJpYnV0ZXMgPSBjdXJyZW50U3RhdGUubmV3QXR0cmlidXRlcztcblx0XHRjb25zdCBlbmFibGVkQXR0cmlidXRlcyA9IGN1cnJlbnRTdGF0ZS5lbmFibGVkQXR0cmlidXRlcztcblx0XHRjb25zdCBhdHRyaWJ1dGVEaXZpc29ycyA9IGN1cnJlbnRTdGF0ZS5hdHRyaWJ1dGVEaXZpc29ycztcblxuXHRcdG5ld0F0dHJpYnV0ZXNbIGF0dHJpYnV0ZSBdID0gMTtcblxuXHRcdGlmICggZW5hYmxlZEF0dHJpYnV0ZXNbIGF0dHJpYnV0ZSBdID09PSAwICkge1xuXG5cdFx0XHRnbC5lbmFibGVWZXJ0ZXhBdHRyaWJBcnJheSggYXR0cmlidXRlICk7XG5cdFx0XHRlbmFibGVkQXR0cmlidXRlc1sgYXR0cmlidXRlIF0gPSAxO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBhdHRyaWJ1dGVEaXZpc29yc1sgYXR0cmlidXRlIF0gIT09IG1lc2hQZXJBdHRyaWJ1dGUgKSB7XG5cblx0XHRcdGdsLnZlcnRleEF0dHJpYkRpdmlzb3IoIGF0dHJpYnV0ZSwgbWVzaFBlckF0dHJpYnV0ZSApO1xuXHRcdFx0YXR0cmlidXRlRGl2aXNvcnNbIGF0dHJpYnV0ZSBdID0gbWVzaFBlckF0dHJpYnV0ZTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gZGlzYWJsZVVudXNlZEF0dHJpYnV0ZXMoKSB7XG5cblx0XHRjb25zdCBuZXdBdHRyaWJ1dGVzID0gY3VycmVudFN0YXRlLm5ld0F0dHJpYnV0ZXM7XG5cdFx0Y29uc3QgZW5hYmxlZEF0dHJpYnV0ZXMgPSBjdXJyZW50U3RhdGUuZW5hYmxlZEF0dHJpYnV0ZXM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gZW5hYmxlZEF0dHJpYnV0ZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdGlmICggZW5hYmxlZEF0dHJpYnV0ZXNbIGkgXSAhPT0gbmV3QXR0cmlidXRlc1sgaSBdICkge1xuXG5cdFx0XHRcdGdsLmRpc2FibGVWZXJ0ZXhBdHRyaWJBcnJheSggaSApO1xuXHRcdFx0XHRlbmFibGVkQXR0cmlidXRlc1sgaSBdID0gMDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB2ZXJ0ZXhBdHRyaWJQb2ludGVyKCBpbmRleCwgc2l6ZSwgdHlwZSwgbm9ybWFsaXplZCwgc3RyaWRlLCBvZmZzZXQsIGludGVnZXIgKSB7XG5cblx0XHRpZiAoIGludGVnZXIgPT09IHRydWUgKSB7XG5cblx0XHRcdGdsLnZlcnRleEF0dHJpYklQb2ludGVyKCBpbmRleCwgc2l6ZSwgdHlwZSwgc3RyaWRlLCBvZmZzZXQgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoIGluZGV4LCBzaXplLCB0eXBlLCBub3JtYWxpemVkLCBzdHJpZGUsIG9mZnNldCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBzZXR1cFZlcnRleEF0dHJpYnV0ZXMoIG9iamVjdCwgbWF0ZXJpYWwsIHByb2dyYW0sIGdlb21ldHJ5ICkge1xuXG5cdFx0aW5pdEF0dHJpYnV0ZXMoKTtcblxuXHRcdGNvbnN0IGdlb21ldHJ5QXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XG5cblx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlcyA9IHByb2dyYW0uZ2V0QXR0cmlidXRlcygpO1xuXG5cdFx0Y29uc3QgbWF0ZXJpYWxEZWZhdWx0QXR0cmlidXRlVmFsdWVzID0gbWF0ZXJpYWwuZGVmYXVsdEF0dHJpYnV0ZVZhbHVlcztcblxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gcHJvZ3JhbUF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdGNvbnN0IHByb2dyYW1BdHRyaWJ1dGUgPSBwcm9ncmFtQXR0cmlidXRlc1sgbmFtZSBdO1xuXG5cdFx0XHRpZiAoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gPj0gMCApIHtcblxuXHRcdFx0XHRsZXQgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBnZW9tZXRyeUF0dHJpYnV0ZXNbIG5hbWUgXTtcblxuXHRcdFx0XHRpZiAoIGdlb21ldHJ5QXR0cmlidXRlID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRpZiAoIG5hbWUgPT09ICdpbnN0YW5jZU1hdHJpeCcgJiYgb2JqZWN0Lmluc3RhbmNlTWF0cml4ICkgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBvYmplY3QuaW5zdGFuY2VNYXRyaXg7XG5cdFx0XHRcdFx0aWYgKCBuYW1lID09PSAnaW5zdGFuY2VDb2xvcicgJiYgb2JqZWN0Lmluc3RhbmNlQ29sb3IgKSBnZW9tZXRyeUF0dHJpYnV0ZSA9IG9iamVjdC5pbnN0YW5jZUNvbG9yO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIGdlb21ldHJ5QXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBub3JtYWxpemVkID0gZ2VvbWV0cnlBdHRyaWJ1dGUubm9ybWFsaXplZDtcblx0XHRcdFx0XHRjb25zdCBzaXplID0gZ2VvbWV0cnlBdHRyaWJ1dGUuaXRlbVNpemU7XG5cblx0XHRcdFx0XHRjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzLmdldCggZ2VvbWV0cnlBdHRyaWJ1dGUgKTtcblxuXHRcdFx0XHRcdC8vIFRPRE8gQXR0cmlidXRlIG1heSBub3QgYmUgYXZhaWxhYmxlIG9uIGNvbnRleHQgcmVzdG9yZVxuXG5cdFx0XHRcdFx0aWYgKCBhdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIGNvbnRpbnVlO1xuXG5cdFx0XHRcdFx0Y29uc3QgYnVmZmVyID0gYXR0cmlidXRlLmJ1ZmZlcjtcblx0XHRcdFx0XHRjb25zdCB0eXBlID0gYXR0cmlidXRlLnR5cGU7XG5cdFx0XHRcdFx0Y29uc3QgYnl0ZXNQZXJFbGVtZW50ID0gYXR0cmlidXRlLmJ5dGVzUGVyRWxlbWVudDtcblxuXHRcdFx0XHRcdC8vIGNoZWNrIGZvciBpbnRlZ2VyIGF0dHJpYnV0ZXNcblxuXHRcdFx0XHRcdGNvbnN0IGludGVnZXIgPSAoIHR5cGUgPT09IGdsLklOVCB8fCB0eXBlID09PSBnbC5VTlNJR05FRF9JTlQgfHwgZ2VvbWV0cnlBdHRyaWJ1dGUuZ3B1VHlwZSA9PT0gSW50VHlwZSApO1xuXG5cdFx0XHRcdFx0aWYgKCBnZW9tZXRyeUF0dHJpYnV0ZS5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBkYXRhID0gZ2VvbWV0cnlBdHRyaWJ1dGUuZGF0YTtcblx0XHRcdFx0XHRcdGNvbnN0IHN0cmlkZSA9IGRhdGEuc3RyaWRlO1xuXHRcdFx0XHRcdFx0Y29uc3Qgb2Zmc2V0ID0gZ2VvbWV0cnlBdHRyaWJ1dGUub2Zmc2V0O1xuXG5cdFx0XHRcdFx0XHRpZiAoIGRhdGEuaXNJbnN0YW5jZWRJbnRlcmxlYXZlZEJ1ZmZlciApIHtcblxuXHRcdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGVuYWJsZUF0dHJpYnV0ZUFuZERpdmlzb3IoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gKyBpLCBkYXRhLm1lc2hQZXJBdHRyaWJ1dGUgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBvYmplY3QuaXNJbnN0YW5jZWRNZXNoICE9PSB0cnVlICYmIGdlb21ldHJ5Ll9tYXhJbnN0YW5jZUNvdW50ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudCA9IGRhdGEubWVzaFBlckF0dHJpYnV0ZSAqIGRhdGEuY291bnQ7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb25TaXplOyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0ZW5hYmxlQXR0cmlidXRlKCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uICsgaSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRnbC5iaW5kQnVmZmVyKCBnbC5BUlJBWV9CVUZGRVIsIGJ1ZmZlciApO1xuXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0XHR2ZXJ0ZXhBdHRyaWJQb2ludGVyKFxuXHRcdFx0XHRcdFx0XHRcdHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gKyBpLFxuXHRcdFx0XHRcdFx0XHRcdHNpemUgLyBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZSxcblx0XHRcdFx0XHRcdFx0XHR0eXBlLFxuXHRcdFx0XHRcdFx0XHRcdG5vcm1hbGl6ZWQsXG5cdFx0XHRcdFx0XHRcdFx0c3RyaWRlICogYnl0ZXNQZXJFbGVtZW50LFxuXHRcdFx0XHRcdFx0XHRcdCggb2Zmc2V0ICsgKCBzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUgKSAqIGkgKSAqIGJ5dGVzUGVyRWxlbWVudCxcblx0XHRcdFx0XHRcdFx0XHRpbnRlZ2VyXG5cdFx0XHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGlmICggZ2VvbWV0cnlBdHRyaWJ1dGUuaXNJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUgKSB7XG5cblx0XHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemU7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRlbmFibGVBdHRyaWJ1dGVBbmREaXZpc29yKCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uICsgaSwgZ2VvbWV0cnlBdHRyaWJ1dGUubWVzaFBlckF0dHJpYnV0ZSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggIT09IHRydWUgJiYgZ2VvbWV0cnkuX21heEluc3RhbmNlQ291bnQgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGdlb21ldHJ5Ll9tYXhJbnN0YW5jZUNvdW50ID0gZ2VvbWV0cnlBdHRyaWJ1dGUubWVzaFBlckF0dHJpYnV0ZSAqIGdlb21ldHJ5QXR0cmlidXRlLmNvdW50O1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGVuYWJsZUF0dHJpYnV0ZSggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiArIGkgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0Z2wuYmluZEJ1ZmZlciggZ2wuQVJSQVlfQlVGRkVSLCBidWZmZXIgKTtcblxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemU7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdFx0dmVydGV4QXR0cmliUG9pbnRlcihcblx0XHRcdFx0XHRcdFx0XHRwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uICsgaSxcblx0XHRcdFx0XHRcdFx0XHRzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUsXG5cdFx0XHRcdFx0XHRcdFx0dHlwZSxcblx0XHRcdFx0XHRcdFx0XHRub3JtYWxpemVkLFxuXHRcdFx0XHRcdFx0XHRcdHNpemUgKiBieXRlc1BlckVsZW1lbnQsXG5cdFx0XHRcdFx0XHRcdFx0KCBzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUgKSAqIGkgKiBieXRlc1BlckVsZW1lbnQsXG5cdFx0XHRcdFx0XHRcdFx0aW50ZWdlclxuXHRcdFx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxEZWZhdWx0QXR0cmlidXRlVmFsdWVzICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB2YWx1ZSA9IG1hdGVyaWFsRGVmYXVsdEF0dHJpYnV0ZVZhbHVlc1sgbmFtZSBdO1xuXG5cdFx0XHRcdFx0aWYgKCB2YWx1ZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRzd2l0Y2ggKCB2YWx1ZS5sZW5ndGggKSB7XG5cblx0XHRcdFx0XHRcdFx0Y2FzZSAyOlxuXHRcdFx0XHRcdFx0XHRcdGdsLnZlcnRleEF0dHJpYjJmdiggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiwgdmFsdWUgKTtcblx0XHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0XHRjYXNlIDM6XG5cdFx0XHRcdFx0XHRcdFx0Z2wudmVydGV4QXR0cmliM2Z2KCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uLCB2YWx1ZSApO1xuXHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRcdGNhc2UgNDpcblx0XHRcdFx0XHRcdFx0XHRnbC52ZXJ0ZXhBdHRyaWI0ZnYoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24sIHZhbHVlICk7XG5cdFx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHRcdFx0XHRnbC52ZXJ0ZXhBdHRyaWIxZnYoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24sIHZhbHVlICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGRpc2FibGVVbnVzZWRBdHRyaWJ1dGVzKCk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG5cblx0XHRyZXNldCgpO1xuXG5cdFx0Zm9yICggY29uc3QgZ2VvbWV0cnlJZCBpbiBiaW5kaW5nU3RhdGVzICkge1xuXG5cdFx0XHRjb25zdCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnlJZCBdO1xuXG5cdFx0XHRmb3IgKCBjb25zdCBwcm9ncmFtSWQgaW4gcHJvZ3JhbU1hcCApIHtcblxuXHRcdFx0XHRjb25zdCBzdGF0ZU1hcCA9IHByb2dyYW1NYXBbIHByb2dyYW1JZCBdO1xuXG5cdFx0XHRcdGZvciAoIGNvbnN0IHdpcmVmcmFtZSBpbiBzdGF0ZU1hcCApIHtcblxuXHRcdFx0XHRcdGRlbGV0ZVZlcnRleEFycmF5T2JqZWN0KCBzdGF0ZU1hcFsgd2lyZWZyYW1lIF0ub2JqZWN0ICk7XG5cblx0XHRcdFx0XHRkZWxldGUgc3RhdGVNYXBbIHdpcmVmcmFtZSBdO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRkZWxldGUgcHJvZ3JhbU1hcFsgcHJvZ3JhbUlkIF07XG5cblx0XHRcdH1cblxuXHRcdFx0ZGVsZXRlIGJpbmRpbmdTdGF0ZXNbIGdlb21ldHJ5SWQgXTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVsZWFzZVN0YXRlc09mR2VvbWV0cnkoIGdlb21ldHJ5ICkge1xuXG5cdFx0aWYgKCBiaW5kaW5nU3RhdGVzWyBnZW9tZXRyeS5pZCBdID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHRjb25zdCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnkuaWQgXTtcblxuXHRcdGZvciAoIGNvbnN0IHByb2dyYW1JZCBpbiBwcm9ncmFtTWFwICkge1xuXG5cdFx0XHRjb25zdCBzdGF0ZU1hcCA9IHByb2dyYW1NYXBbIHByb2dyYW1JZCBdO1xuXG5cdFx0XHRmb3IgKCBjb25zdCB3aXJlZnJhbWUgaW4gc3RhdGVNYXAgKSB7XG5cblx0XHRcdFx0ZGVsZXRlVmVydGV4QXJyYXlPYmplY3QoIHN0YXRlTWFwWyB3aXJlZnJhbWUgXS5vYmplY3QgKTtcblxuXHRcdFx0XHRkZWxldGUgc3RhdGVNYXBbIHdpcmVmcmFtZSBdO1xuXG5cdFx0XHR9XG5cblx0XHRcdGRlbGV0ZSBwcm9ncmFtTWFwWyBwcm9ncmFtSWQgXTtcblxuXHRcdH1cblxuXHRcdGRlbGV0ZSBiaW5kaW5nU3RhdGVzWyBnZW9tZXRyeS5pZCBdO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZWxlYXNlU3RhdGVzT2ZQcm9ncmFtKCBwcm9ncmFtICkge1xuXG5cdFx0Zm9yICggY29uc3QgZ2VvbWV0cnlJZCBpbiBiaW5kaW5nU3RhdGVzICkge1xuXG5cdFx0XHRjb25zdCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnlJZCBdO1xuXG5cdFx0XHRpZiAoIHByb2dyYW1NYXBbIHByb2dyYW0uaWQgXSA9PT0gdW5kZWZpbmVkICkgY29udGludWU7XG5cblx0XHRcdGNvbnN0IHN0YXRlTWFwID0gcHJvZ3JhbU1hcFsgcHJvZ3JhbS5pZCBdO1xuXG5cdFx0XHRmb3IgKCBjb25zdCB3aXJlZnJhbWUgaW4gc3RhdGVNYXAgKSB7XG5cblx0XHRcdFx0ZGVsZXRlVmVydGV4QXJyYXlPYmplY3QoIHN0YXRlTWFwWyB3aXJlZnJhbWUgXS5vYmplY3QgKTtcblxuXHRcdFx0XHRkZWxldGUgc3RhdGVNYXBbIHdpcmVmcmFtZSBdO1xuXG5cdFx0XHR9XG5cblx0XHRcdGRlbGV0ZSBwcm9ncmFtTWFwWyBwcm9ncmFtLmlkIF07XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlc2V0KCkge1xuXG5cdFx0cmVzZXREZWZhdWx0U3RhdGUoKTtcblx0XHRmb3JjZVVwZGF0ZSA9IHRydWU7XG5cblx0XHRpZiAoIGN1cnJlbnRTdGF0ZSA9PT0gZGVmYXVsdFN0YXRlICkgcmV0dXJuO1xuXG5cdFx0Y3VycmVudFN0YXRlID0gZGVmYXVsdFN0YXRlO1xuXHRcdGJpbmRWZXJ0ZXhBcnJheU9iamVjdCggY3VycmVudFN0YXRlLm9iamVjdCApO1xuXG5cdH1cblxuXHQvLyBmb3IgYmFja3dhcmQtY29tcGF0aWJpbGl0eVxuXG5cdGZ1bmN0aW9uIHJlc2V0RGVmYXVsdFN0YXRlKCkge1xuXG5cdFx0ZGVmYXVsdFN0YXRlLmdlb21ldHJ5ID0gbnVsbDtcblx0XHRkZWZhdWx0U3RhdGUucHJvZ3JhbSA9IG51bGw7XG5cdFx0ZGVmYXVsdFN0YXRlLndpcmVmcmFtZSA9IGZhbHNlO1xuXG5cdH1cblxuXHRyZXR1cm4ge1xuXG5cdFx0c2V0dXA6IHNldHVwLFxuXHRcdHJlc2V0OiByZXNldCxcblx0XHRyZXNldERlZmF1bHRTdGF0ZTogcmVzZXREZWZhdWx0U3RhdGUsXG5cdFx0ZGlzcG9zZTogZGlzcG9zZSxcblx0XHRyZWxlYXNlU3RhdGVzT2ZHZW9tZXRyeTogcmVsZWFzZVN0YXRlc09mR2VvbWV0cnksXG5cdFx0cmVsZWFzZVN0YXRlc09mUHJvZ3JhbTogcmVsZWFzZVN0YXRlc09mUHJvZ3JhbSxcblxuXHRcdGluaXRBdHRyaWJ1dGVzOiBpbml0QXR0cmlidXRlcyxcblx0XHRlbmFibGVBdHRyaWJ1dGU6IGVuYWJsZUF0dHJpYnV0ZSxcblx0XHRkaXNhYmxlVW51c2VkQXR0cmlidXRlczogZGlzYWJsZVVudXNlZEF0dHJpYnV0ZXNcblxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMQnVmZmVyUmVuZGVyZXIoIGdsLCBleHRlbnNpb25zLCBpbmZvICkge1xuXG5cdGxldCBtb2RlO1xuXG5cdGZ1bmN0aW9uIHNldE1vZGUoIHZhbHVlICkge1xuXG5cdFx0bW9kZSA9IHZhbHVlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXIoIHN0YXJ0LCBjb3VudCApIHtcblxuXHRcdGdsLmRyYXdBcnJheXMoIG1vZGUsIHN0YXJ0LCBjb3VudCApO1xuXG5cdFx0aW5mby51cGRhdGUoIGNvdW50LCBtb2RlLCAxICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlbmRlckluc3RhbmNlcyggc3RhcnQsIGNvdW50LCBwcmltY291bnQgKSB7XG5cblx0XHRpZiAoIHByaW1jb3VudCA9PT0gMCApIHJldHVybjtcblxuXHRcdGdsLmRyYXdBcnJheXNJbnN0YW5jZWQoIG1vZGUsIHN0YXJ0LCBjb3VudCwgcHJpbWNvdW50ICk7XG5cblx0XHRpbmZvLnVwZGF0ZSggY291bnQsIG1vZGUsIHByaW1jb3VudCApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXJNdWx0aURyYXcoIHN0YXJ0cywgY291bnRzLCBkcmF3Q291bnQgKSB7XG5cblx0XHRpZiAoIGRyYXdDb3VudCA9PT0gMCApIHJldHVybjtcblxuXHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbXVsdGlfZHJhdycgKTtcblx0XHRleHRlbnNpb24ubXVsdGlEcmF3QXJyYXlzV0VCR0woIG1vZGUsIHN0YXJ0cywgMCwgY291bnRzLCAwLCBkcmF3Q291bnQgKTtcblxuXHRcdGxldCBlbGVtZW50Q291bnQgPSAwO1xuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGRyYXdDb3VudDsgaSArKyApIHtcblxuXHRcdFx0ZWxlbWVudENvdW50ICs9IGNvdW50c1sgaSBdO1xuXG5cdFx0fVxuXG5cdFx0aW5mby51cGRhdGUoIGVsZW1lbnRDb3VudCwgbW9kZSwgMSApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXJNdWx0aURyYXdJbnN0YW5jZXMoIHN0YXJ0cywgY291bnRzLCBkcmF3Q291bnQsIHByaW1jb3VudCApIHtcblxuXHRcdGlmICggZHJhd0NvdW50ID09PSAwICkgcmV0dXJuO1xuXG5cdFx0Y29uc3QgZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9tdWx0aV9kcmF3JyApO1xuXG5cdFx0aWYgKCBleHRlbnNpb24gPT09IG51bGwgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHN0YXJ0cy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0cmVuZGVySW5zdGFuY2VzKCBzdGFydHNbIGkgXSwgY291bnRzWyBpIF0sIHByaW1jb3VudFsgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGV4dGVuc2lvbi5tdWx0aURyYXdBcnJheXNJbnN0YW5jZWRXRUJHTCggbW9kZSwgc3RhcnRzLCAwLCBjb3VudHMsIDAsIHByaW1jb3VudCwgMCwgZHJhd0NvdW50ICk7XG5cblx0XHRcdGxldCBlbGVtZW50Q291bnQgPSAwO1xuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZHJhd0NvdW50OyBpICsrICkge1xuXG5cdFx0XHRcdGVsZW1lbnRDb3VudCArPSBjb3VudHNbIGkgXTtcblxuXHRcdFx0fVxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcmltY291bnQubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGluZm8udXBkYXRlKCBlbGVtZW50Q291bnQsIG1vZGUsIHByaW1jb3VudFsgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0Ly9cblxuXHR0aGlzLnNldE1vZGUgPSBzZXRNb2RlO1xuXHR0aGlzLnJlbmRlciA9IHJlbmRlcjtcblx0dGhpcy5yZW5kZXJJbnN0YW5jZXMgPSByZW5kZXJJbnN0YW5jZXM7XG5cdHRoaXMucmVuZGVyTXVsdGlEcmF3ID0gcmVuZGVyTXVsdGlEcmF3O1xuXHR0aGlzLnJlbmRlck11bHRpRHJhd0luc3RhbmNlcyA9IHJlbmRlck11bHRpRHJhd0luc3RhbmNlcztcblxufVxuXG5mdW5jdGlvbiBXZWJHTENhcGFiaWxpdGllcyggZ2wsIGV4dGVuc2lvbnMsIHBhcmFtZXRlcnMsIHV0aWxzICkge1xuXG5cdGxldCBtYXhBbmlzb3Ryb3B5O1xuXG5cdGZ1bmN0aW9uIGdldE1heEFuaXNvdHJvcHkoKSB7XG5cblx0XHRpZiAoIG1heEFuaXNvdHJvcHkgIT09IHVuZGVmaW5lZCApIHJldHVybiBtYXhBbmlzb3Ryb3B5O1xuXG5cdFx0aWYgKCBleHRlbnNpb25zLmhhcyggJ0VYVF90ZXh0dXJlX2ZpbHRlcl9hbmlzb3Ryb3BpYycgKSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0Y29uc3QgZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfdGV4dHVyZV9maWx0ZXJfYW5pc290cm9waWMnICk7XG5cblx0XHRcdG1heEFuaXNvdHJvcHkgPSBnbC5nZXRQYXJhbWV0ZXIoIGV4dGVuc2lvbi5NQVhfVEVYVFVSRV9NQVhfQU5JU09UUk9QWV9FWFQgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdG1heEFuaXNvdHJvcHkgPSAwO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG1heEFuaXNvdHJvcHk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHRleHR1cmVGb3JtYXRSZWFkYWJsZSggdGV4dHVyZUZvcm1hdCApIHtcblxuXHRcdGlmICggdGV4dHVyZUZvcm1hdCAhPT0gUkdCQUZvcm1hdCAmJiB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlRm9ybWF0ICkgIT09IGdsLmdldFBhcmFtZXRlciggZ2wuSU1QTEVNRU5UQVRJT05fQ09MT1JfUkVBRF9GT1JNQVQgKSApIHtcblxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHRleHR1cmVUeXBlUmVhZGFibGUoIHRleHR1cmVUeXBlICkge1xuXG5cdFx0Y29uc3QgaGFsZkZsb2F0U3VwcG9ydGVkQnlFeHQgPSAoIHRleHR1cmVUeXBlID09PSBIYWxmRmxvYXRUeXBlICkgJiYgKCBleHRlbnNpb25zLmhhcyggJ0VYVF9jb2xvcl9idWZmZXJfaGFsZl9mbG9hdCcgKSB8fCBleHRlbnNpb25zLmhhcyggJ0VYVF9jb2xvcl9idWZmZXJfZmxvYXQnICkgKTtcblxuXHRcdGlmICggdGV4dHVyZVR5cGUgIT09IFVuc2lnbmVkQnl0ZVR5cGUgJiYgdXRpbHMuY29udmVydCggdGV4dHVyZVR5cGUgKSAhPT0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5JTVBMRU1FTlRBVElPTl9DT0xPUl9SRUFEX1RZUEUgKSAmJiAvLyBFZGdlIGFuZCBDaHJvbWUgTWFjIDwgNTIgKCM5NTEzKVxuXHRcdFx0dGV4dHVyZVR5cGUgIT09IEZsb2F0VHlwZSAmJiAhIGhhbGZGbG9hdFN1cHBvcnRlZEJ5RXh0ICkge1xuXG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0TWF4UHJlY2lzaW9uKCBwcmVjaXNpb24gKSB7XG5cblx0XHRpZiAoIHByZWNpc2lvbiA9PT0gJ2hpZ2hwJyApIHtcblxuXHRcdFx0aWYgKCBnbC5nZXRTaGFkZXJQcmVjaXNpb25Gb3JtYXQoIGdsLlZFUlRFWF9TSEFERVIsIGdsLkhJR0hfRkxPQVQgKS5wcmVjaXNpb24gPiAwICYmXG5cdFx0XHRcdGdsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCggZ2wuRlJBR01FTlRfU0hBREVSLCBnbC5ISUdIX0ZMT0FUICkucHJlY2lzaW9uID4gMCApIHtcblxuXHRcdFx0XHRyZXR1cm4gJ2hpZ2hwJztcblxuXHRcdFx0fVxuXG5cdFx0XHRwcmVjaXNpb24gPSAnbWVkaXVtcCc7XG5cblx0XHR9XG5cblx0XHRpZiAoIHByZWNpc2lvbiA9PT0gJ21lZGl1bXAnICkge1xuXG5cdFx0XHRpZiAoIGdsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCggZ2wuVkVSVEVYX1NIQURFUiwgZ2wuTUVESVVNX0ZMT0FUICkucHJlY2lzaW9uID4gMCAmJlxuXHRcdFx0XHRnbC5nZXRTaGFkZXJQcmVjaXNpb25Gb3JtYXQoIGdsLkZSQUdNRU5UX1NIQURFUiwgZ2wuTUVESVVNX0ZMT0FUICkucHJlY2lzaW9uID4gMCApIHtcblxuXHRcdFx0XHRyZXR1cm4gJ21lZGl1bXAnO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gJ2xvd3AnO1xuXG5cdH1cblxuXHRsZXQgcHJlY2lzaW9uID0gcGFyYW1ldGVycy5wcmVjaXNpb24gIT09IHVuZGVmaW5lZCA/IHBhcmFtZXRlcnMucHJlY2lzaW9uIDogJ2hpZ2hwJztcblx0Y29uc3QgbWF4UHJlY2lzaW9uID0gZ2V0TWF4UHJlY2lzaW9uKCBwcmVjaXNpb24gKTtcblxuXHRpZiAoIG1heFByZWNpc2lvbiAhPT0gcHJlY2lzaW9uICkge1xuXG5cdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjonLCBwcmVjaXNpb24sICdub3Qgc3VwcG9ydGVkLCB1c2luZycsIG1heFByZWNpc2lvbiwgJ2luc3RlYWQuJyApO1xuXHRcdHByZWNpc2lvbiA9IG1heFByZWNpc2lvbjtcblxuXHR9XG5cblx0Y29uc3QgbG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA9IHBhcmFtZXRlcnMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA9PT0gdHJ1ZTtcblxuXHRjb25zdCBtYXhUZXh0dXJlcyA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1RFWFRVUkVfSU1BR0VfVU5JVFMgKTtcblx0Y29uc3QgbWF4VmVydGV4VGV4dHVyZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WRVJURVhfVEVYVFVSRV9JTUFHRV9VTklUUyApO1xuXHRjb25zdCBtYXhUZXh0dXJlU2l6ZSA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1RFWFRVUkVfU0laRSApO1xuXHRjb25zdCBtYXhDdWJlbWFwU2l6ZSA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX0NVQkVfTUFQX1RFWFRVUkVfU0laRSApO1xuXG5cdGNvbnN0IG1heEF0dHJpYnV0ZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WRVJURVhfQVRUUklCUyApO1xuXHRjb25zdCBtYXhWZXJ0ZXhVbmlmb3JtcyA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1ZFUlRFWF9VTklGT1JNX1ZFQ1RPUlMgKTtcblx0Y29uc3QgbWF4VmFyeWluZ3MgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WQVJZSU5HX1ZFQ1RPUlMgKTtcblx0Y29uc3QgbWF4RnJhZ21lbnRVbmlmb3JtcyA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX0ZSQUdNRU5UX1VOSUZPUk1fVkVDVE9SUyApO1xuXG5cdGNvbnN0IHZlcnRleFRleHR1cmVzID0gbWF4VmVydGV4VGV4dHVyZXMgPiAwO1xuXG5cdGNvbnN0IG1heFNhbXBsZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9TQU1QTEVTICk7XG5cblx0cmV0dXJuIHtcblxuXHRcdGlzV2ViR0wyOiB0cnVlLCAvLyBrZWVwaW5nIHRoaXMgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5XG5cblx0XHRnZXRNYXhBbmlzb3Ryb3B5OiBnZXRNYXhBbmlzb3Ryb3B5LFxuXHRcdGdldE1heFByZWNpc2lvbjogZ2V0TWF4UHJlY2lzaW9uLFxuXG5cdFx0dGV4dHVyZUZvcm1hdFJlYWRhYmxlOiB0ZXh0dXJlRm9ybWF0UmVhZGFibGUsXG5cdFx0dGV4dHVyZVR5cGVSZWFkYWJsZTogdGV4dHVyZVR5cGVSZWFkYWJsZSxcblxuXHRcdHByZWNpc2lvbjogcHJlY2lzaW9uLFxuXHRcdGxvZ2FyaXRobWljRGVwdGhCdWZmZXI6IGxvZ2FyaXRobWljRGVwdGhCdWZmZXIsXG5cblx0XHRtYXhUZXh0dXJlczogbWF4VGV4dHVyZXMsXG5cdFx0bWF4VmVydGV4VGV4dHVyZXM6IG1heFZlcnRleFRleHR1cmVzLFxuXHRcdG1heFRleHR1cmVTaXplOiBtYXhUZXh0dXJlU2l6ZSxcblx0XHRtYXhDdWJlbWFwU2l6ZTogbWF4Q3ViZW1hcFNpemUsXG5cblx0XHRtYXhBdHRyaWJ1dGVzOiBtYXhBdHRyaWJ1dGVzLFxuXHRcdG1heFZlcnRleFVuaWZvcm1zOiBtYXhWZXJ0ZXhVbmlmb3Jtcyxcblx0XHRtYXhWYXJ5aW5nczogbWF4VmFyeWluZ3MsXG5cdFx0bWF4RnJhZ21lbnRVbmlmb3JtczogbWF4RnJhZ21lbnRVbmlmb3JtcyxcblxuXHRcdHZlcnRleFRleHR1cmVzOiB2ZXJ0ZXhUZXh0dXJlcyxcblxuXHRcdG1heFNhbXBsZXM6IG1heFNhbXBsZXNcblxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMQ2xpcHBpbmcoIHByb3BlcnRpZXMgKSB7XG5cblx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdGxldCBnbG9iYWxTdGF0ZSA9IG51bGwsXG5cdFx0bnVtR2xvYmFsUGxhbmVzID0gMCxcblx0XHRsb2NhbENsaXBwaW5nRW5hYmxlZCA9IGZhbHNlLFxuXHRcdHJlbmRlcmluZ1NoYWRvd3MgPSBmYWxzZTtcblxuXHRjb25zdCBwbGFuZSA9IG5ldyBQbGFuZSgpLFxuXHRcdHZpZXdOb3JtYWxNYXRyaXggPSBuZXcgTWF0cml4MygpLFxuXG5cdFx0dW5pZm9ybSA9IHsgdmFsdWU6IG51bGwsIG5lZWRzVXBkYXRlOiBmYWxzZSB9O1xuXG5cdHRoaXMudW5pZm9ybSA9IHVuaWZvcm07XG5cdHRoaXMubnVtUGxhbmVzID0gMDtcblx0dGhpcy5udW1JbnRlcnNlY3Rpb24gPSAwO1xuXG5cdHRoaXMuaW5pdCA9IGZ1bmN0aW9uICggcGxhbmVzLCBlbmFibGVMb2NhbENsaXBwaW5nICkge1xuXG5cdFx0Y29uc3QgZW5hYmxlZCA9XG5cdFx0XHRwbGFuZXMubGVuZ3RoICE9PSAwIHx8XG5cdFx0XHRlbmFibGVMb2NhbENsaXBwaW5nIHx8XG5cdFx0XHQvLyBlbmFibGUgc3RhdGUgb2YgcHJldmlvdXMgZnJhbWUgLSB0aGUgY2xpcHBpbmcgY29kZSBoYXMgdG9cblx0XHRcdC8vIHJ1biBhbm90aGVyIGZyYW1lIGluIG9yZGVyIHRvIHJlc2V0IHRoZSBzdGF0ZTpcblx0XHRcdG51bUdsb2JhbFBsYW5lcyAhPT0gMCB8fFxuXHRcdFx0bG9jYWxDbGlwcGluZ0VuYWJsZWQ7XG5cblx0XHRsb2NhbENsaXBwaW5nRW5hYmxlZCA9IGVuYWJsZUxvY2FsQ2xpcHBpbmc7XG5cblx0XHRudW1HbG9iYWxQbGFuZXMgPSBwbGFuZXMubGVuZ3RoO1xuXG5cdFx0cmV0dXJuIGVuYWJsZWQ7XG5cblx0fTtcblxuXHR0aGlzLmJlZ2luU2hhZG93cyA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdHJlbmRlcmluZ1NoYWRvd3MgPSB0cnVlO1xuXHRcdHByb2plY3RQbGFuZXMoIG51bGwgKTtcblxuXHR9O1xuXG5cdHRoaXMuZW5kU2hhZG93cyA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdHJlbmRlcmluZ1NoYWRvd3MgPSBmYWxzZTtcblxuXHR9O1xuXG5cdHRoaXMuc2V0R2xvYmFsU3RhdGUgPSBmdW5jdGlvbiAoIHBsYW5lcywgY2FtZXJhICkge1xuXG5cdFx0Z2xvYmFsU3RhdGUgPSBwcm9qZWN0UGxhbmVzKCBwbGFuZXMsIGNhbWVyYSwgMCApO1xuXG5cdH07XG5cblx0dGhpcy5zZXRTdGF0ZSA9IGZ1bmN0aW9uICggbWF0ZXJpYWwsIGNhbWVyYSwgdXNlQ2FjaGUgKSB7XG5cblx0XHRjb25zdCBwbGFuZXMgPSBtYXRlcmlhbC5jbGlwcGluZ1BsYW5lcyxcblx0XHRcdGNsaXBJbnRlcnNlY3Rpb24gPSBtYXRlcmlhbC5jbGlwSW50ZXJzZWN0aW9uLFxuXHRcdFx0Y2xpcFNoYWRvd3MgPSBtYXRlcmlhbC5jbGlwU2hhZG93cztcblxuXHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xuXG5cdFx0aWYgKCAhIGxvY2FsQ2xpcHBpbmdFbmFibGVkIHx8IHBsYW5lcyA9PT0gbnVsbCB8fCBwbGFuZXMubGVuZ3RoID09PSAwIHx8IHJlbmRlcmluZ1NoYWRvd3MgJiYgISBjbGlwU2hhZG93cyApIHtcblxuXHRcdFx0Ly8gdGhlcmUncyBubyBsb2NhbCBjbGlwcGluZ1xuXG5cdFx0XHRpZiAoIHJlbmRlcmluZ1NoYWRvd3MgKSB7XG5cblx0XHRcdFx0Ly8gdGhlcmUncyBubyBnbG9iYWwgY2xpcHBpbmdcblxuXHRcdFx0XHRwcm9qZWN0UGxhbmVzKCBudWxsICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0cmVzZXRHbG9iYWxTdGF0ZSgpO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zdCBuR2xvYmFsID0gcmVuZGVyaW5nU2hhZG93cyA/IDAgOiBudW1HbG9iYWxQbGFuZXMsXG5cdFx0XHRcdGxHbG9iYWwgPSBuR2xvYmFsICogNDtcblxuXHRcdFx0bGV0IGRzdEFycmF5ID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLmNsaXBwaW5nU3RhdGUgfHwgbnVsbDtcblxuXHRcdFx0dW5pZm9ybS52YWx1ZSA9IGRzdEFycmF5OyAvLyBlbnN1cmUgdW5pcXVlIHN0YXRlXG5cblx0XHRcdGRzdEFycmF5ID0gcHJvamVjdFBsYW5lcyggcGxhbmVzLCBjYW1lcmEsIGxHbG9iYWwsIHVzZUNhY2hlICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbEdsb2JhbDsgKysgaSApIHtcblxuXHRcdFx0XHRkc3RBcnJheVsgaSBdID0gZ2xvYmFsU3RhdGVbIGkgXTtcblxuXHRcdFx0fVxuXG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMuY2xpcHBpbmdTdGF0ZSA9IGRzdEFycmF5O1xuXHRcdFx0dGhpcy5udW1JbnRlcnNlY3Rpb24gPSBjbGlwSW50ZXJzZWN0aW9uID8gdGhpcy5udW1QbGFuZXMgOiAwO1xuXHRcdFx0dGhpcy5udW1QbGFuZXMgKz0gbkdsb2JhbDtcblxuXHRcdH1cblxuXG5cdH07XG5cblx0ZnVuY3Rpb24gcmVzZXRHbG9iYWxTdGF0ZSgpIHtcblxuXHRcdGlmICggdW5pZm9ybS52YWx1ZSAhPT0gZ2xvYmFsU3RhdGUgKSB7XG5cblx0XHRcdHVuaWZvcm0udmFsdWUgPSBnbG9iYWxTdGF0ZTtcblx0XHRcdHVuaWZvcm0ubmVlZHNVcGRhdGUgPSBudW1HbG9iYWxQbGFuZXMgPiAwO1xuXG5cdFx0fVxuXG5cdFx0c2NvcGUubnVtUGxhbmVzID0gbnVtR2xvYmFsUGxhbmVzO1xuXHRcdHNjb3BlLm51bUludGVyc2VjdGlvbiA9IDA7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHByb2plY3RQbGFuZXMoIHBsYW5lcywgY2FtZXJhLCBkc3RPZmZzZXQsIHNraXBUcmFuc2Zvcm0gKSB7XG5cblx0XHRjb25zdCBuUGxhbmVzID0gcGxhbmVzICE9PSBudWxsID8gcGxhbmVzLmxlbmd0aCA6IDA7XG5cdFx0bGV0IGRzdEFycmF5ID0gbnVsbDtcblxuXHRcdGlmICggblBsYW5lcyAhPT0gMCApIHtcblxuXHRcdFx0ZHN0QXJyYXkgPSB1bmlmb3JtLnZhbHVlO1xuXG5cdFx0XHRpZiAoIHNraXBUcmFuc2Zvcm0gIT09IHRydWUgfHwgZHN0QXJyYXkgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0Y29uc3QgZmxhdFNpemUgPSBkc3RPZmZzZXQgKyBuUGxhbmVzICogNCxcblx0XHRcdFx0XHR2aWV3TWF0cml4ID0gY2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZTtcblxuXHRcdFx0XHR2aWV3Tm9ybWFsTWF0cml4LmdldE5vcm1hbE1hdHJpeCggdmlld01hdHJpeCApO1xuXG5cdFx0XHRcdGlmICggZHN0QXJyYXkgPT09IG51bGwgfHwgZHN0QXJyYXkubGVuZ3RoIDwgZmxhdFNpemUgKSB7XG5cblx0XHRcdFx0XHRkc3RBcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoIGZsYXRTaXplICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaTQgPSBkc3RPZmZzZXQ7IGkgIT09IG5QbGFuZXM7ICsrIGksIGk0ICs9IDQgKSB7XG5cblx0XHRcdFx0XHRwbGFuZS5jb3B5KCBwbGFuZXNbIGkgXSApLmFwcGx5TWF0cml4NCggdmlld01hdHJpeCwgdmlld05vcm1hbE1hdHJpeCApO1xuXG5cdFx0XHRcdFx0cGxhbmUubm9ybWFsLnRvQXJyYXkoIGRzdEFycmF5LCBpNCApO1xuXHRcdFx0XHRcdGRzdEFycmF5WyBpNCArIDMgXSA9IHBsYW5lLmNvbnN0YW50O1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHR1bmlmb3JtLnZhbHVlID0gZHN0QXJyYXk7XG5cdFx0XHR1bmlmb3JtLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdHNjb3BlLm51bVBsYW5lcyA9IG5QbGFuZXM7XG5cdFx0c2NvcGUubnVtSW50ZXJzZWN0aW9uID0gMDtcblxuXHRcdHJldHVybiBkc3RBcnJheTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xDdWJlTWFwcyggcmVuZGVyZXIgKSB7XG5cblx0bGV0IGN1YmVtYXBzID0gbmV3IFdlYWtNYXAoKTtcblxuXHRmdW5jdGlvbiBtYXBUZXh0dXJlTWFwcGluZyggdGV4dHVyZSwgbWFwcGluZyApIHtcblxuXHRcdGlmICggbWFwcGluZyA9PT0gRXF1aXJlY3Rhbmd1bGFyUmVmbGVjdGlvbk1hcHBpbmcgKSB7XG5cblx0XHRcdHRleHR1cmUubWFwcGluZyA9IEN1YmVSZWZsZWN0aW9uTWFwcGluZztcblxuXHRcdH0gZWxzZSBpZiAoIG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZnJhY3Rpb25NYXBwaW5nICkge1xuXG5cdFx0XHR0ZXh0dXJlLm1hcHBpbmcgPSBDdWJlUmVmcmFjdGlvbk1hcHBpbmc7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGV4dHVyZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0KCB0ZXh0dXJlICkge1xuXG5cdFx0aWYgKCB0ZXh0dXJlICYmIHRleHR1cmUuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRjb25zdCBtYXBwaW5nID0gdGV4dHVyZS5tYXBwaW5nO1xuXG5cdFx0XHRpZiAoIG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nIHx8IG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZnJhY3Rpb25NYXBwaW5nICkge1xuXG5cdFx0XHRcdGlmICggY3ViZW1hcHMuaGFzKCB0ZXh0dXJlICkgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBjdWJlbWFwID0gY3ViZW1hcHMuZ2V0KCB0ZXh0dXJlICkudGV4dHVyZTtcblx0XHRcdFx0XHRyZXR1cm4gbWFwVGV4dHVyZU1hcHBpbmcoIGN1YmVtYXAsIHRleHR1cmUubWFwcGluZyApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRjb25zdCBpbWFnZSA9IHRleHR1cmUuaW1hZ2U7XG5cblx0XHRcdFx0XHRpZiAoIGltYWdlICYmIGltYWdlLmhlaWdodCA+IDAgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IHJlbmRlclRhcmdldCA9IG5ldyBXZWJHTEN1YmVSZW5kZXJUYXJnZXQoIGltYWdlLmhlaWdodCApO1xuXHRcdFx0XHRcdFx0cmVuZGVyVGFyZ2V0LmZyb21FcXVpcmVjdGFuZ3VsYXJUZXh0dXJlKCByZW5kZXJlciwgdGV4dHVyZSApO1xuXHRcdFx0XHRcdFx0Y3ViZW1hcHMuc2V0KCB0ZXh0dXJlLCByZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHRcdFx0dGV4dHVyZS5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVGV4dHVyZURpc3Bvc2UgKTtcblxuXHRcdFx0XHRcdFx0cmV0dXJuIG1hcFRleHR1cmVNYXBwaW5nKCByZW5kZXJUYXJnZXQudGV4dHVyZSwgdGV4dHVyZS5tYXBwaW5nICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHQvLyBpbWFnZSBub3QgeWV0IHJlYWR5LiB0cnkgdGhlIGNvbnZlcnNpb24gbmV4dCBmcmFtZVxuXG5cdFx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0ZXh0dXJlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBvblRleHR1cmVEaXNwb3NlKCBldmVudCApIHtcblxuXHRcdGNvbnN0IHRleHR1cmUgPSBldmVudC50YXJnZXQ7XG5cblx0XHR0ZXh0dXJlLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25UZXh0dXJlRGlzcG9zZSApO1xuXG5cdFx0Y29uc3QgY3ViZW1hcCA9IGN1YmVtYXBzLmdldCggdGV4dHVyZSApO1xuXG5cdFx0aWYgKCBjdWJlbWFwICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGN1YmVtYXBzLmRlbGV0ZSggdGV4dHVyZSApO1xuXHRcdFx0Y3ViZW1hcC5kaXNwb3NlKCk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG5cblx0XHRjdWJlbWFwcyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0Z2V0OiBnZXQsXG5cdFx0ZGlzcG9zZTogZGlzcG9zZVxuXHR9O1xuXG59XG5cbmNsYXNzIE9ydGhvZ3JhcGhpY0NhbWVyYSBleHRlbmRzIENhbWVyYSB7XG5cblx0Y29uc3RydWN0b3IoIGxlZnQgPSAtIDEsIHJpZ2h0ID0gMSwgdG9wID0gMSwgYm90dG9tID0gLSAxLCBuZWFyID0gMC4xLCBmYXIgPSAyMDAwICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNPcnRob2dyYXBoaWNDYW1lcmEgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ09ydGhvZ3JhcGhpY0NhbWVyYSc7XG5cblx0XHR0aGlzLnpvb20gPSAxO1xuXHRcdHRoaXMudmlldyA9IG51bGw7XG5cblx0XHR0aGlzLmxlZnQgPSBsZWZ0O1xuXHRcdHRoaXMucmlnaHQgPSByaWdodDtcblx0XHR0aGlzLnRvcCA9IHRvcDtcblx0XHR0aGlzLmJvdHRvbSA9IGJvdHRvbTtcblxuXHRcdHRoaXMubmVhciA9IG5lYXI7XG5cdFx0dGhpcy5mYXIgPSBmYXI7XG5cblx0XHR0aGlzLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0dGhpcy5sZWZ0ID0gc291cmNlLmxlZnQ7XG5cdFx0dGhpcy5yaWdodCA9IHNvdXJjZS5yaWdodDtcblx0XHR0aGlzLnRvcCA9IHNvdXJjZS50b3A7XG5cdFx0dGhpcy5ib3R0b20gPSBzb3VyY2UuYm90dG9tO1xuXHRcdHRoaXMubmVhciA9IHNvdXJjZS5uZWFyO1xuXHRcdHRoaXMuZmFyID0gc291cmNlLmZhcjtcblxuXHRcdHRoaXMuem9vbSA9IHNvdXJjZS56b29tO1xuXHRcdHRoaXMudmlldyA9IHNvdXJjZS52aWV3ID09PSBudWxsID8gbnVsbCA6IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UudmlldyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFZpZXdPZmZzZXQoIGZ1bGxXaWR0aCwgZnVsbEhlaWdodCwgeCwgeSwgd2lkdGgsIGhlaWdodCApIHtcblxuXHRcdGlmICggdGhpcy52aWV3ID09PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLnZpZXcgPSB7XG5cdFx0XHRcdGVuYWJsZWQ6IHRydWUsXG5cdFx0XHRcdGZ1bGxXaWR0aDogMSxcblx0XHRcdFx0ZnVsbEhlaWdodDogMSxcblx0XHRcdFx0b2Zmc2V0WDogMCxcblx0XHRcdFx0b2Zmc2V0WTogMCxcblx0XHRcdFx0d2lkdGg6IDEsXG5cdFx0XHRcdGhlaWdodDogMVxuXHRcdFx0fTtcblxuXHRcdH1cblxuXHRcdHRoaXMudmlldy5lbmFibGVkID0gdHJ1ZTtcblx0XHR0aGlzLnZpZXcuZnVsbFdpZHRoID0gZnVsbFdpZHRoO1xuXHRcdHRoaXMudmlldy5mdWxsSGVpZ2h0ID0gZnVsbEhlaWdodDtcblx0XHR0aGlzLnZpZXcub2Zmc2V0WCA9IHg7XG5cdFx0dGhpcy52aWV3Lm9mZnNldFkgPSB5O1xuXHRcdHRoaXMudmlldy53aWR0aCA9IHdpZHRoO1xuXHRcdHRoaXMudmlldy5oZWlnaHQgPSBoZWlnaHQ7XG5cblx0XHR0aGlzLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHR9XG5cblx0Y2xlYXJWaWV3T2Zmc2V0KCkge1xuXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMudmlldy5lbmFibGVkID0gZmFsc2U7XG5cblx0XHR9XG5cblx0XHR0aGlzLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHR9XG5cblx0dXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpIHtcblxuXHRcdGNvbnN0IGR4ID0gKCB0aGlzLnJpZ2h0IC0gdGhpcy5sZWZ0ICkgLyAoIDIgKiB0aGlzLnpvb20gKTtcblx0XHRjb25zdCBkeSA9ICggdGhpcy50b3AgLSB0aGlzLmJvdHRvbSApIC8gKCAyICogdGhpcy56b29tICk7XG5cdFx0Y29uc3QgY3ggPSAoIHRoaXMucmlnaHQgKyB0aGlzLmxlZnQgKSAvIDI7XG5cdFx0Y29uc3QgY3kgPSAoIHRoaXMudG9wICsgdGhpcy5ib3R0b20gKSAvIDI7XG5cblx0XHRsZXQgbGVmdCA9IGN4IC0gZHg7XG5cdFx0bGV0IHJpZ2h0ID0gY3ggKyBkeDtcblx0XHRsZXQgdG9wID0gY3kgKyBkeTtcblx0XHRsZXQgYm90dG9tID0gY3kgLSBkeTtcblxuXHRcdGlmICggdGhpcy52aWV3ICE9PSBudWxsICYmIHRoaXMudmlldy5lbmFibGVkICkge1xuXG5cdFx0XHRjb25zdCBzY2FsZVcgPSAoIHRoaXMucmlnaHQgLSB0aGlzLmxlZnQgKSAvIHRoaXMudmlldy5mdWxsV2lkdGggLyB0aGlzLnpvb207XG5cdFx0XHRjb25zdCBzY2FsZUggPSAoIHRoaXMudG9wIC0gdGhpcy5ib3R0b20gKSAvIHRoaXMudmlldy5mdWxsSGVpZ2h0IC8gdGhpcy56b29tO1xuXG5cdFx0XHRsZWZ0ICs9IHNjYWxlVyAqIHRoaXMudmlldy5vZmZzZXRYO1xuXHRcdFx0cmlnaHQgPSBsZWZ0ICsgc2NhbGVXICogdGhpcy52aWV3LndpZHRoO1xuXHRcdFx0dG9wIC09IHNjYWxlSCAqIHRoaXMudmlldy5vZmZzZXRZO1xuXHRcdFx0Ym90dG9tID0gdG9wIC0gc2NhbGVIICogdGhpcy52aWV3LmhlaWdodDtcblxuXHRcdH1cblxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeC5tYWtlT3J0aG9ncmFwaGljKCBsZWZ0LCByaWdodCwgdG9wLCBib3R0b20sIHRoaXMubmVhciwgdGhpcy5mYXIsIHRoaXMuY29vcmRpbmF0ZVN5c3RlbSApO1xuXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZS5jb3B5KCB0aGlzLnByb2plY3Rpb25NYXRyaXggKS5pbnZlcnQoKTtcblxuXHR9XG5cblx0dG9KU09OKCBtZXRhICkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xuXG5cdFx0ZGF0YS5vYmplY3Quem9vbSA9IHRoaXMuem9vbTtcblx0XHRkYXRhLm9iamVjdC5sZWZ0ID0gdGhpcy5sZWZ0O1xuXHRcdGRhdGEub2JqZWN0LnJpZ2h0ID0gdGhpcy5yaWdodDtcblx0XHRkYXRhLm9iamVjdC50b3AgPSB0aGlzLnRvcDtcblx0XHRkYXRhLm9iamVjdC5ib3R0b20gPSB0aGlzLmJvdHRvbTtcblx0XHRkYXRhLm9iamVjdC5uZWFyID0gdGhpcy5uZWFyO1xuXHRcdGRhdGEub2JqZWN0LmZhciA9IHRoaXMuZmFyO1xuXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgKSBkYXRhLm9iamVjdC52aWV3ID0gT2JqZWN0LmFzc2lnbigge30sIHRoaXMudmlldyApO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbmNvbnN0IExPRF9NSU4gPSA0O1xuXG4vLyBUaGUgc3RhbmRhcmQgZGV2aWF0aW9ucyAocmFkaWFucykgYXNzb2NpYXRlZCB3aXRoIHRoZSBleHRyYSBtaXBzLiBUaGVzZSBhcmVcbi8vIGNob3NlbiB0byBhcHByb3hpbWF0ZSBhIFRyb3dicmlkZ2UtUmVpdHogZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIHRpbWVzIHRoZVxuLy8gZ2VvbWV0cmljIHNoYWRvd2luZyBmdW5jdGlvbi4gVGhlc2Ugc2lnbWEgdmFsdWVzIHNxdWFyZWQgbXVzdCBtYXRjaCB0aGVcbi8vIHZhcmlhbmNlICNkZWZpbmVzIGluIGN1YmVfdXZfcmVmbGVjdGlvbl9mcmFnbWVudC5nbHNsLmpzLlxuY29uc3QgRVhUUkFfTE9EX1NJR01BID0gWyAwLjEyNSwgMC4yMTUsIDAuMzUsIDAuNDQ2LCAwLjUyNiwgMC41ODIgXTtcblxuLy8gVGhlIG1heGltdW0gbGVuZ3RoIG9mIHRoZSBibHVyIGZvciBsb29wLiBTbWFsbGVyIHNpZ21hcyB3aWxsIHVzZSBmZXdlclxuLy8gc2FtcGxlcyBhbmQgZXhpdCBlYXJseSwgYnV0IG5vdCByZWNvbXBpbGUgdGhlIHNoYWRlci5cbmNvbnN0IE1BWF9TQU1QTEVTID0gMjA7XG5cbmNvbnN0IF9mbGF0Q2FtZXJhID0gLypAX19QVVJFX18qLyBuZXcgT3J0aG9ncmFwaGljQ2FtZXJhKCk7XG5jb25zdCBfY2xlYXJDb2xvciA9IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCk7XG5sZXQgX29sZFRhcmdldCA9IG51bGw7XG5sZXQgX29sZEFjdGl2ZUN1YmVGYWNlID0gMDtcbmxldCBfb2xkQWN0aXZlTWlwbWFwTGV2ZWwgPSAwO1xubGV0IF9vbGRYckVuYWJsZWQgPSBmYWxzZTtcblxuLy8gR29sZGVuIFJhdGlvXG5jb25zdCBQSEkgPSAoIDEgKyBNYXRoLnNxcnQoIDUgKSApIC8gMjtcbmNvbnN0IElOVl9QSEkgPSAxIC8gUEhJO1xuXG4vLyBWZXJ0aWNlcyBvZiBhIGRvZGVjYWhlZHJvbiAoZXhjZXB0IHRoZSBvcHBvc2l0ZXMsIHdoaWNoIHJlcHJlc2VudCB0aGVcbi8vIHNhbWUgYXhpcyksIHVzZWQgYXMgYXhpcyBkaXJlY3Rpb25zIGV2ZW5seSBzcHJlYWQgb24gYSBzcGhlcmUuXG5jb25zdCBfYXhpc0RpcmVjdGlvbnMgPSBbXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIC0gUEhJLCBJTlZfUEhJLCAwICksXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIFBISSwgSU5WX1BISSwgMCApLFxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAtIElOVl9QSEksIDAsIFBISSApLFxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCBJTlZfUEhJLCAwLCBQSEkgKSxcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgUEhJLCAtIElOVl9QSEkgKSxcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgUEhJLCBJTlZfUEhJICksXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIC0gMSwgMSwgLSAxICksXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDEsIDEsIC0gMSApLFxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAtIDEsIDEsIDEgKSxcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMSwgMSwgMSApIF07XG5cbi8qKlxuICogVGhpcyBjbGFzcyBnZW5lcmF0ZXMgYSBQcmVmaWx0ZXJlZCwgTWlwbWFwcGVkIFJhZGlhbmNlIEVudmlyb25tZW50IE1hcFxuICogKFBNUkVNKSBmcm9tIGEgY3ViZU1hcCBlbnZpcm9ubWVudCB0ZXh0dXJlLiBUaGlzIGFsbG93cyBkaWZmZXJlbnQgbGV2ZWxzIG9mXG4gKiBibHVyIHRvIGJlIHF1aWNrbHkgYWNjZXNzZWQgYmFzZWQgb24gbWF0ZXJpYWwgcm91Z2huZXNzLiBJdCBpcyBwYWNrZWQgaW50byBhXG4gKiBzcGVjaWFsIEN1YmVVViBmb3JtYXQgdGhhdCBhbGxvd3MgdXMgdG8gcGVyZm9ybSBjdXN0b20gaW50ZXJwb2xhdGlvbiBzbyB0aGF0XG4gKiB3ZSBjYW4gc3VwcG9ydCBub25saW5lYXIgZm9ybWF0cyBzdWNoIGFzIFJHQkUuIFVubGlrZSBhIHRyYWRpdGlvbmFsIG1pcG1hcFxuICogY2hhaW4sIGl0IG9ubHkgZ29lcyBkb3duIHRvIHRoZSBMT0RfTUlOIGxldmVsIChhYm92ZSksIGFuZCB0aGVuIGNyZWF0ZXMgZXh0cmFcbiAqIGV2ZW4gbW9yZSBmaWx0ZXJlZCAnbWlwcycgYXQgdGhlIHNhbWUgTE9EX01JTiByZXNvbHV0aW9uLCBhc3NvY2lhdGVkIHdpdGhcbiAqIGhpZ2hlciByb3VnaG5lc3MgbGV2ZWxzLiBJbiB0aGlzIHdheSB3ZSBtYWludGFpbiByZXNvbHV0aW9uIHRvIHNtb290aGx5XG4gKiBpbnRlcnBvbGF0ZSBkaWZmdXNlIGxpZ2h0aW5nIHdoaWxlIGxpbWl0aW5nIHNhbXBsaW5nIGNvbXB1dGF0aW9uLlxuICpcbiAqIFBhcGVyOiBGYXN0LCBBY2N1cmF0ZSBJbWFnZS1CYXNlZCBMaWdodGluZ1xuICogaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xNXk4cl9VcEtsVTlTdlY0SUxiMEMzcUNQZWNTOHB2THovdmlld1xuKi9cblxuY2xhc3MgUE1SRU1HZW5lcmF0b3Ige1xuXG5cdGNvbnN0cnVjdG9yKCByZW5kZXJlciApIHtcblxuXHRcdHRoaXMuX3JlbmRlcmVyID0gcmVuZGVyZXI7XG5cdFx0dGhpcy5fcGluZ1BvbmdSZW5kZXJUYXJnZXQgPSBudWxsO1xuXG5cdFx0dGhpcy5fbG9kTWF4ID0gMDtcblx0XHR0aGlzLl9jdWJlU2l6ZSA9IDA7XG5cdFx0dGhpcy5fbG9kUGxhbmVzID0gW107XG5cdFx0dGhpcy5fc2l6ZUxvZHMgPSBbXTtcblx0XHR0aGlzLl9zaWdtYXMgPSBbXTtcblxuXHRcdHRoaXMuX2JsdXJNYXRlcmlhbCA9IG51bGw7XG5cdFx0dGhpcy5fY3ViZW1hcE1hdGVyaWFsID0gbnVsbDtcblx0XHR0aGlzLl9lcXVpcmVjdE1hdGVyaWFsID0gbnVsbDtcblxuXHRcdHRoaXMuX2NvbXBpbGVNYXRlcmlhbCggdGhpcy5fYmx1ck1hdGVyaWFsICk7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBHZW5lcmF0ZXMgYSBQTVJFTSBmcm9tIGEgc3VwcGxpZWQgU2NlbmUsIHdoaWNoIGNhbiBiZSBmYXN0ZXIgdGhhbiB1c2luZyBhblxuXHQgKiBpbWFnZSBpZiBuZXR3b3JraW5nIGJhbmR3aWR0aCBpcyBsb3cuIE9wdGlvbmFsIHNpZ21hIHNwZWNpZmllcyBhIGJsdXIgcmFkaXVzXG5cdCAqIGluIHJhZGlhbnMgdG8gYmUgYXBwbGllZCB0byB0aGUgc2NlbmUgYmVmb3JlIFBNUkVNIGdlbmVyYXRpb24uIE9wdGlvbmFsIG5lYXJcblx0ICogYW5kIGZhciBwbGFuZXMgZW5zdXJlIHRoZSBzY2VuZSBpcyByZW5kZXJlZCBpbiBpdHMgZW50aXJldHkgKHRoZSBjdWJlQ2FtZXJhXG5cdCAqIGlzIHBsYWNlZCBhdCB0aGUgb3JpZ2luKS5cblx0ICovXG5cdGZyb21TY2VuZSggc2NlbmUsIHNpZ21hID0gMCwgbmVhciA9IDAuMSwgZmFyID0gMTAwICkge1xuXG5cdFx0X29sZFRhcmdldCA9IHRoaXMuX3JlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xuXHRcdF9vbGRBY3RpdmVDdWJlRmFjZSA9IHRoaXMuX3JlbmRlcmVyLmdldEFjdGl2ZUN1YmVGYWNlKCk7XG5cdFx0X29sZEFjdGl2ZU1pcG1hcExldmVsID0gdGhpcy5fcmVuZGVyZXIuZ2V0QWN0aXZlTWlwbWFwTGV2ZWwoKTtcblx0XHRfb2xkWHJFbmFibGVkID0gdGhpcy5fcmVuZGVyZXIueHIuZW5hYmxlZDtcblxuXHRcdHRoaXMuX3JlbmRlcmVyLnhyLmVuYWJsZWQgPSBmYWxzZTtcblxuXHRcdHRoaXMuX3NldFNpemUoIDI1NiApO1xuXG5cdFx0Y29uc3QgY3ViZVVWUmVuZGVyVGFyZ2V0ID0gdGhpcy5fYWxsb2NhdGVUYXJnZXRzKCk7XG5cdFx0Y3ViZVVWUmVuZGVyVGFyZ2V0LmRlcHRoQnVmZmVyID0gdHJ1ZTtcblxuXHRcdHRoaXMuX3NjZW5lVG9DdWJlVVYoIHNjZW5lLCBuZWFyLCBmYXIsIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXG5cdFx0aWYgKCBzaWdtYSA+IDAgKSB7XG5cblx0XHRcdHRoaXMuX2JsdXIoIGN1YmVVVlJlbmRlclRhcmdldCwgMCwgMCwgc2lnbWEgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuX2FwcGx5UE1SRU0oIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXHRcdHRoaXMuX2NsZWFudXAoIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXG5cdFx0cmV0dXJuIGN1YmVVVlJlbmRlclRhcmdldDtcblxuXHR9XG5cblx0LyoqXG5cdCAqIEdlbmVyYXRlcyBhIFBNUkVNIGZyb20gYW4gZXF1aXJlY3Rhbmd1bGFyIHRleHR1cmUsIHdoaWNoIGNhbiBiZSBlaXRoZXIgTERSXG5cdCAqIG9yIEhEUi4gVGhlIGlkZWFsIGlucHV0IGltYWdlIHNpemUgaXMgMWsgKDEwMjQgeCA1MTIpLFxuXHQgKiBhcyB0aGlzIG1hdGNoZXMgYmVzdCB3aXRoIHRoZSAyNTYgeCAyNTYgY3ViZW1hcCBvdXRwdXQuXG5cdCAqIFRoZSBzbWFsbGVzdCBzdXBwb3J0ZWQgZXF1aXJlY3Rhbmd1bGFyIGltYWdlIHNpemUgaXMgNjQgeCAzMi5cblx0ICovXG5cdGZyb21FcXVpcmVjdGFuZ3VsYXIoIGVxdWlyZWN0YW5ndWxhciwgcmVuZGVyVGFyZ2V0ID0gbnVsbCApIHtcblxuXHRcdHJldHVybiB0aGlzLl9mcm9tVGV4dHVyZSggZXF1aXJlY3Rhbmd1bGFyLCByZW5kZXJUYXJnZXQgKTtcblxuXHR9XG5cblx0LyoqXG5cdCAqIEdlbmVyYXRlcyBhIFBNUkVNIGZyb20gYW4gY3ViZW1hcCB0ZXh0dXJlLCB3aGljaCBjYW4gYmUgZWl0aGVyIExEUlxuXHQgKiBvciBIRFIuIFRoZSBpZGVhbCBpbnB1dCBjdWJlIHNpemUgaXMgMjU2IHggMjU2LFxuXHQgKiBhcyB0aGlzIG1hdGNoZXMgYmVzdCB3aXRoIHRoZSAyNTYgeCAyNTYgY3ViZW1hcCBvdXRwdXQuXG5cdCAqIFRoZSBzbWFsbGVzdCBzdXBwb3J0ZWQgY3ViZSBzaXplIGlzIDE2IHggMTYuXG5cdCAqL1xuXHRmcm9tQ3ViZW1hcCggY3ViZW1hcCwgcmVuZGVyVGFyZ2V0ID0gbnVsbCApIHtcblxuXHRcdHJldHVybiB0aGlzLl9mcm9tVGV4dHVyZSggY3ViZW1hcCwgcmVuZGVyVGFyZ2V0ICk7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBQcmUtY29tcGlsZXMgdGhlIGN1YmVtYXAgc2hhZGVyLiBZb3UgY2FuIGdldCBmYXN0ZXIgc3RhcnQtdXAgYnkgaW52b2tpbmcgdGhpcyBtZXRob2QgZHVyaW5nXG5cdCAqIHlvdXIgdGV4dHVyZSdzIG5ldHdvcmsgZmV0Y2ggZm9yIGluY3JlYXNlZCBjb25jdXJyZW5jeS5cblx0ICovXG5cdGNvbXBpbGVDdWJlbWFwU2hhZGVyKCkge1xuXG5cdFx0aWYgKCB0aGlzLl9jdWJlbWFwTWF0ZXJpYWwgPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX2N1YmVtYXBNYXRlcmlhbCA9IF9nZXRDdWJlbWFwTWF0ZXJpYWwoKTtcblx0XHRcdHRoaXMuX2NvbXBpbGVNYXRlcmlhbCggdGhpcy5fY3ViZW1hcE1hdGVyaWFsICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBQcmUtY29tcGlsZXMgdGhlIGVxdWlyZWN0YW5ndWxhciBzaGFkZXIuIFlvdSBjYW4gZ2V0IGZhc3RlciBzdGFydC11cCBieSBpbnZva2luZyB0aGlzIG1ldGhvZCBkdXJpbmdcblx0ICogeW91ciB0ZXh0dXJlJ3MgbmV0d29yayBmZXRjaCBmb3IgaW5jcmVhc2VkIGNvbmN1cnJlbmN5LlxuXHQgKi9cblx0Y29tcGlsZUVxdWlyZWN0YW5ndWxhclNoYWRlcigpIHtcblxuXHRcdGlmICggdGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9IF9nZXRFcXVpcmVjdE1hdGVyaWFsKCk7XG5cdFx0XHR0aGlzLl9jb21waWxlTWF0ZXJpYWwoIHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWwgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0LyoqXG5cdCAqIERpc3Bvc2VzIG9mIHRoZSBQTVJFTUdlbmVyYXRvcidzIGludGVybmFsIG1lbW9yeS4gTm90ZSB0aGF0IFBNUkVNR2VuZXJhdG9yIGlzIGEgc3RhdGljIGNsYXNzLFxuXHQgKiBzbyB5b3Ugc2hvdWxkIG5vdCBuZWVkIG1vcmUgdGhhbiBvbmUgUE1SRU1HZW5lcmF0b3Igb2JqZWN0LiBJZiB5b3UgZG8sIGNhbGxpbmcgZGlzcG9zZSgpIG9uXG5cdCAqIG9uZSBvZiB0aGVtIHdpbGwgY2F1c2UgYW55IG90aGVycyB0byBhbHNvIGJlY29tZSB1bnVzYWJsZS5cblx0ICovXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLl9kaXNwb3NlKCk7XG5cblx0XHRpZiAoIHRoaXMuX2N1YmVtYXBNYXRlcmlhbCAhPT0gbnVsbCApIHRoaXMuX2N1YmVtYXBNYXRlcmlhbC5kaXNwb3NlKCk7XG5cdFx0aWYgKCB0aGlzLl9lcXVpcmVjdE1hdGVyaWFsICE9PSBudWxsICkgdGhpcy5fZXF1aXJlY3RNYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0fVxuXG5cdC8vIHByaXZhdGUgaW50ZXJmYWNlXG5cblx0X3NldFNpemUoIGN1YmVTaXplICkge1xuXG5cdFx0dGhpcy5fbG9kTWF4ID0gTWF0aC5mbG9vciggTWF0aC5sb2cyKCBjdWJlU2l6ZSApICk7XG5cdFx0dGhpcy5fY3ViZVNpemUgPSBNYXRoLnBvdyggMiwgdGhpcy5fbG9kTWF4ICk7XG5cblx0fVxuXG5cdF9kaXNwb3NlKCkge1xuXG5cdFx0aWYgKCB0aGlzLl9ibHVyTWF0ZXJpYWwgIT09IG51bGwgKSB0aGlzLl9ibHVyTWF0ZXJpYWwuZGlzcG9zZSgpO1xuXG5cdFx0aWYgKCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldCAhPT0gbnVsbCApIHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0LmRpc3Bvc2UoKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMuX2xvZFBsYW5lcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuX2xvZFBsYW5lc1sgaSBdLmRpc3Bvc2UoKTtcblxuXHRcdH1cblxuXHR9XG5cblx0X2NsZWFudXAoIG91dHB1dFRhcmdldCApIHtcblxuXHRcdHRoaXMuX3JlbmRlcmVyLnNldFJlbmRlclRhcmdldCggX29sZFRhcmdldCwgX29sZEFjdGl2ZUN1YmVGYWNlLCBfb2xkQWN0aXZlTWlwbWFwTGV2ZWwgKTtcblx0XHR0aGlzLl9yZW5kZXJlci54ci5lbmFibGVkID0gX29sZFhyRW5hYmxlZDtcblxuXHRcdG91dHB1dFRhcmdldC5zY2lzc29yVGVzdCA9IGZhbHNlO1xuXHRcdF9zZXRWaWV3cG9ydCggb3V0cHV0VGFyZ2V0LCAwLCAwLCBvdXRwdXRUYXJnZXQud2lkdGgsIG91dHB1dFRhcmdldC5oZWlnaHQgKTtcblxuXHR9XG5cblx0X2Zyb21UZXh0dXJlKCB0ZXh0dXJlLCByZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRpZiAoIHRleHR1cmUubWFwcGluZyA9PT0gQ3ViZVJlZmxlY3Rpb25NYXBwaW5nIHx8IHRleHR1cmUubWFwcGluZyA9PT0gQ3ViZVJlZnJhY3Rpb25NYXBwaW5nICkge1xuXG5cdFx0XHR0aGlzLl9zZXRTaXplKCB0ZXh0dXJlLmltYWdlLmxlbmd0aCA9PT0gMCA/IDE2IDogKCB0ZXh0dXJlLmltYWdlWyAwIF0ud2lkdGggfHwgdGV4dHVyZS5pbWFnZVsgMCBdLmltYWdlLndpZHRoICkgKTtcblxuXHRcdH0gZWxzZSB7IC8vIEVxdWlyZWN0YW5ndWxhclxuXG5cdFx0XHR0aGlzLl9zZXRTaXplKCB0ZXh0dXJlLmltYWdlLndpZHRoIC8gNCApO1xuXG5cdFx0fVxuXG5cdFx0X29sZFRhcmdldCA9IHRoaXMuX3JlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xuXHRcdF9vbGRBY3RpdmVDdWJlRmFjZSA9IHRoaXMuX3JlbmRlcmVyLmdldEFjdGl2ZUN1YmVGYWNlKCk7XG5cdFx0X29sZEFjdGl2ZU1pcG1hcExldmVsID0gdGhpcy5fcmVuZGVyZXIuZ2V0QWN0aXZlTWlwbWFwTGV2ZWwoKTtcblx0XHRfb2xkWHJFbmFibGVkID0gdGhpcy5fcmVuZGVyZXIueHIuZW5hYmxlZDtcblxuXHRcdHRoaXMuX3JlbmRlcmVyLnhyLmVuYWJsZWQgPSBmYWxzZTtcblxuXHRcdGNvbnN0IGN1YmVVVlJlbmRlclRhcmdldCA9IHJlbmRlclRhcmdldCB8fCB0aGlzLl9hbGxvY2F0ZVRhcmdldHMoKTtcblx0XHR0aGlzLl90ZXh0dXJlVG9DdWJlVVYoIHRleHR1cmUsIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXHRcdHRoaXMuX2FwcGx5UE1SRU0oIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXHRcdHRoaXMuX2NsZWFudXAoIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXG5cdFx0cmV0dXJuIGN1YmVVVlJlbmRlclRhcmdldDtcblxuXHR9XG5cblx0X2FsbG9jYXRlVGFyZ2V0cygpIHtcblxuXHRcdGNvbnN0IHdpZHRoID0gMyAqIE1hdGgubWF4KCB0aGlzLl9jdWJlU2l6ZSwgMTYgKiA3ICk7XG5cdFx0Y29uc3QgaGVpZ2h0ID0gNCAqIHRoaXMuX2N1YmVTaXplO1xuXG5cdFx0Y29uc3QgcGFyYW1zID0ge1xuXHRcdFx0bWFnRmlsdGVyOiBMaW5lYXJGaWx0ZXIsXG5cdFx0XHRtaW5GaWx0ZXI6IExpbmVhckZpbHRlcixcblx0XHRcdGdlbmVyYXRlTWlwbWFwczogZmFsc2UsXG5cdFx0XHR0eXBlOiBIYWxmRmxvYXRUeXBlLFxuXHRcdFx0Zm9ybWF0OiBSR0JBRm9ybWF0LFxuXHRcdFx0Y29sb3JTcGFjZTogTGluZWFyU1JHQkNvbG9yU3BhY2UsXG5cdFx0XHRkZXB0aEJ1ZmZlcjogZmFsc2Vcblx0XHR9O1xuXG5cdFx0Y29uc3QgY3ViZVVWUmVuZGVyVGFyZ2V0ID0gX2NyZWF0ZVJlbmRlclRhcmdldCggd2lkdGgsIGhlaWdodCwgcGFyYW1zICk7XG5cblx0XHRpZiAoIHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0ID09PSBudWxsIHx8IHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0LndpZHRoICE9PSB3aWR0aCB8fCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldC5oZWlnaHQgIT09IGhlaWdodCApIHtcblxuXHRcdFx0aWYgKCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHR0aGlzLl9kaXNwb3NlKCk7XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fcGluZ1BvbmdSZW5kZXJUYXJnZXQgPSBfY3JlYXRlUmVuZGVyVGFyZ2V0KCB3aWR0aCwgaGVpZ2h0LCBwYXJhbXMgKTtcblxuXHRcdFx0Y29uc3QgeyBfbG9kTWF4IH0gPSB0aGlzO1xuXHRcdFx0KCB7IHNpemVMb2RzOiB0aGlzLl9zaXplTG9kcywgbG9kUGxhbmVzOiB0aGlzLl9sb2RQbGFuZXMsIHNpZ21hczogdGhpcy5fc2lnbWFzIH0gPSBfY3JlYXRlUGxhbmVzKCBfbG9kTWF4ICkgKTtcblxuXHRcdFx0dGhpcy5fYmx1ck1hdGVyaWFsID0gX2dldEJsdXJTaGFkZXIoIF9sb2RNYXgsIHdpZHRoLCBoZWlnaHQgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBjdWJlVVZSZW5kZXJUYXJnZXQ7XG5cblx0fVxuXG5cdF9jb21waWxlTWF0ZXJpYWwoIG1hdGVyaWFsICkge1xuXG5cdFx0Y29uc3QgdG1wTWVzaCA9IG5ldyBNZXNoKCB0aGlzLl9sb2RQbGFuZXNbIDAgXSwgbWF0ZXJpYWwgKTtcblx0XHR0aGlzLl9yZW5kZXJlci5jb21waWxlKCB0bXBNZXNoLCBfZmxhdENhbWVyYSApO1xuXG5cdH1cblxuXHRfc2NlbmVUb0N1YmVVViggc2NlbmUsIG5lYXIsIGZhciwgY3ViZVVWUmVuZGVyVGFyZ2V0ICkge1xuXG5cdFx0Y29uc3QgZm92ID0gOTA7XG5cdFx0Y29uc3QgYXNwZWN0ID0gMTtcblx0XHRjb25zdCBjdWJlQ2FtZXJhID0gbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCBmb3YsIGFzcGVjdCwgbmVhciwgZmFyICk7XG5cdFx0Y29uc3QgdXBTaWduID0gWyAxLCAtIDEsIDEsIDEsIDEsIDEgXTtcblx0XHRjb25zdCBmb3J3YXJkU2lnbiA9IFsgMSwgMSwgMSwgLSAxLCAtIDEsIC0gMSBdO1xuXHRcdGNvbnN0IHJlbmRlcmVyID0gdGhpcy5fcmVuZGVyZXI7XG5cblx0XHRjb25zdCBvcmlnaW5hbEF1dG9DbGVhciA9IHJlbmRlcmVyLmF1dG9DbGVhcjtcblx0XHRjb25zdCB0b25lTWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xuXHRcdHJlbmRlcmVyLmdldENsZWFyQ29sb3IoIF9jbGVhckNvbG9yICk7XG5cblx0XHRyZW5kZXJlci50b25lTWFwcGluZyA9IE5vVG9uZU1hcHBpbmc7XG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gZmFsc2U7XG5cblx0XHRjb25zdCBiYWNrZ3JvdW5kTWF0ZXJpYWwgPSBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHtcblx0XHRcdG5hbWU6ICdQTVJFTS5CYWNrZ3JvdW5kJyxcblx0XHRcdHNpZGU6IEJhY2tTaWRlLFxuXHRcdFx0ZGVwdGhXcml0ZTogZmFsc2UsXG5cdFx0XHRkZXB0aFRlc3Q6IGZhbHNlLFxuXHRcdH0gKTtcblxuXHRcdGNvbnN0IGJhY2tncm91bmRCb3ggPSBuZXcgTWVzaCggbmV3IEJveEdlb21ldHJ5KCksIGJhY2tncm91bmRNYXRlcmlhbCApO1xuXG5cdFx0bGV0IHVzZVNvbGlkQ29sb3IgPSBmYWxzZTtcblx0XHRjb25zdCBiYWNrZ3JvdW5kID0gc2NlbmUuYmFja2dyb3VuZDtcblxuXHRcdGlmICggYmFja2dyb3VuZCApIHtcblxuXHRcdFx0aWYgKCBiYWNrZ3JvdW5kLmlzQ29sb3IgKSB7XG5cblx0XHRcdFx0YmFja2dyb3VuZE1hdGVyaWFsLmNvbG9yLmNvcHkoIGJhY2tncm91bmQgKTtcblx0XHRcdFx0c2NlbmUuYmFja2dyb3VuZCA9IG51bGw7XG5cdFx0XHRcdHVzZVNvbGlkQ29sb3IgPSB0cnVlO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRiYWNrZ3JvdW5kTWF0ZXJpYWwuY29sb3IuY29weSggX2NsZWFyQ29sb3IgKTtcblx0XHRcdHVzZVNvbGlkQ29sb3IgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgY29sID0gaSAlIDM7XG5cblx0XHRcdGlmICggY29sID09PSAwICkge1xuXG5cdFx0XHRcdGN1YmVDYW1lcmEudXAuc2V0KCAwLCB1cFNpZ25bIGkgXSwgMCApO1xuXHRcdFx0XHRjdWJlQ2FtZXJhLmxvb2tBdCggZm9yd2FyZFNpZ25bIGkgXSwgMCwgMCApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBjb2wgPT09IDEgKSB7XG5cblx0XHRcdFx0Y3ViZUNhbWVyYS51cC5zZXQoIDAsIDAsIHVwU2lnblsgaSBdICk7XG5cdFx0XHRcdGN1YmVDYW1lcmEubG9va0F0KCAwLCBmb3J3YXJkU2lnblsgaSBdLCAwICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Y3ViZUNhbWVyYS51cC5zZXQoIDAsIHVwU2lnblsgaSBdLCAwICk7XG5cdFx0XHRcdGN1YmVDYW1lcmEubG9va0F0KCAwLCAwLCBmb3J3YXJkU2lnblsgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3Qgc2l6ZSA9IHRoaXMuX2N1YmVTaXplO1xuXG5cdFx0XHRfc2V0Vmlld3BvcnQoIGN1YmVVVlJlbmRlclRhcmdldCwgY29sICogc2l6ZSwgaSA+IDIgPyBzaXplIDogMCwgc2l6ZSwgc2l6ZSApO1xuXG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXG5cdFx0XHRpZiAoIHVzZVNvbGlkQ29sb3IgKSB7XG5cblx0XHRcdFx0cmVuZGVyZXIucmVuZGVyKCBiYWNrZ3JvdW5kQm94LCBjdWJlQ2FtZXJhICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY3ViZUNhbWVyYSApO1xuXG5cdFx0fVxuXG5cdFx0YmFja2dyb3VuZEJveC5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0YmFja2dyb3VuZEJveC5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0XHRyZW5kZXJlci50b25lTWFwcGluZyA9IHRvbmVNYXBwaW5nO1xuXHRcdHJlbmRlcmVyLmF1dG9DbGVhciA9IG9yaWdpbmFsQXV0b0NsZWFyO1xuXHRcdHNjZW5lLmJhY2tncm91bmQgPSBiYWNrZ3JvdW5kO1xuXG5cdH1cblxuXHRfdGV4dHVyZVRvQ3ViZVVWKCB0ZXh0dXJlLCBjdWJlVVZSZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRjb25zdCByZW5kZXJlciA9IHRoaXMuX3JlbmRlcmVyO1xuXG5cdFx0Y29uc3QgaXNDdWJlVGV4dHVyZSA9ICggdGV4dHVyZS5tYXBwaW5nID09PSBDdWJlUmVmbGVjdGlvbk1hcHBpbmcgfHwgdGV4dHVyZS5tYXBwaW5nID09PSBDdWJlUmVmcmFjdGlvbk1hcHBpbmcgKTtcblxuXHRcdGlmICggaXNDdWJlVGV4dHVyZSApIHtcblxuXHRcdFx0aWYgKCB0aGlzLl9jdWJlbWFwTWF0ZXJpYWwgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0dGhpcy5fY3ViZW1hcE1hdGVyaWFsID0gX2dldEN1YmVtYXBNYXRlcmlhbCgpO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2N1YmVtYXBNYXRlcmlhbC51bmlmb3Jtcy5mbGlwRW52TWFwLnZhbHVlID0gKCB0ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSA/IC0gMSA6IDE7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWwgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0dGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9IF9nZXRFcXVpcmVjdE1hdGVyaWFsKCk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IG1hdGVyaWFsID0gaXNDdWJlVGV4dHVyZSA/IHRoaXMuX2N1YmVtYXBNYXRlcmlhbCA6IHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWw7XG5cdFx0Y29uc3QgbWVzaCA9IG5ldyBNZXNoKCB0aGlzLl9sb2RQbGFuZXNbIDAgXSwgbWF0ZXJpYWwgKTtcblxuXHRcdGNvbnN0IHVuaWZvcm1zID0gbWF0ZXJpYWwudW5pZm9ybXM7XG5cblx0XHR1bmlmb3Jtc1sgJ2Vudk1hcCcgXS52YWx1ZSA9IHRleHR1cmU7XG5cblx0XHRjb25zdCBzaXplID0gdGhpcy5fY3ViZVNpemU7XG5cblx0XHRfc2V0Vmlld3BvcnQoIGN1YmVVVlJlbmRlclRhcmdldCwgMCwgMCwgMyAqIHNpemUsIDIgKiBzaXplICk7XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXHRcdHJlbmRlcmVyLnJlbmRlciggbWVzaCwgX2ZsYXRDYW1lcmEgKTtcblxuXHR9XG5cblx0X2FwcGx5UE1SRU0oIGN1YmVVVlJlbmRlclRhcmdldCApIHtcblxuXHRcdGNvbnN0IHJlbmRlcmVyID0gdGhpcy5fcmVuZGVyZXI7XG5cdFx0Y29uc3QgYXV0b0NsZWFyID0gcmVuZGVyZXIuYXV0b0NsZWFyO1xuXHRcdHJlbmRlcmVyLmF1dG9DbGVhciA9IGZhbHNlO1xuXHRcdGNvbnN0IG4gPSB0aGlzLl9sb2RQbGFuZXMubGVuZ3RoO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAxOyBpIDwgbjsgaSArKyApIHtcblxuXHRcdFx0Y29uc3Qgc2lnbWEgPSBNYXRoLnNxcnQoIHRoaXMuX3NpZ21hc1sgaSBdICogdGhpcy5fc2lnbWFzWyBpIF0gLSB0aGlzLl9zaWdtYXNbIGkgLSAxIF0gKiB0aGlzLl9zaWdtYXNbIGkgLSAxIF0gKTtcblxuXHRcdFx0Y29uc3QgcG9sZUF4aXMgPSBfYXhpc0RpcmVjdGlvbnNbICggbiAtIGkgLSAxICkgJSBfYXhpc0RpcmVjdGlvbnMubGVuZ3RoIF07XG5cblx0XHRcdHRoaXMuX2JsdXIoIGN1YmVVVlJlbmRlclRhcmdldCwgaSAtIDEsIGksIHNpZ21hLCBwb2xlQXhpcyApO1xuXG5cdFx0fVxuXG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gYXV0b0NsZWFyO1xuXG5cdH1cblxuXHQvKipcblx0ICogVGhpcyBpcyBhIHR3by1wYXNzIEdhdXNzaWFuIGJsdXIgZm9yIGEgY3ViZW1hcC4gTm9ybWFsbHkgdGhpcyBpcyBkb25lXG5cdCAqIHZlcnRpY2FsbHkgYW5kIGhvcml6b250YWxseSwgYnV0IHRoaXMgYnJlYWtzIGRvd24gb24gYSBjdWJlLiBIZXJlIHdlIGFwcGx5XG5cdCAqIHRoZSBibHVyIGxhdGl0dWRpbmFsbHkgKGFyb3VuZCB0aGUgcG9sZXMpLCBhbmQgdGhlbiBsb25naXR1ZGluYWxseSAodG93YXJkc1xuXHQgKiB0aGUgcG9sZXMpIHRvIGFwcHJveGltYXRlIHRoZSBvcnRob2dvbmFsbHktc2VwYXJhYmxlIGJsdXIuIEl0IGlzIGxlYXN0XG5cdCAqIGFjY3VyYXRlIGF0IHRoZSBwb2xlcywgYnV0IHN0aWxsIGRvZXMgYSBkZWNlbnQgam9iLlxuXHQgKi9cblx0X2JsdXIoIGN1YmVVVlJlbmRlclRhcmdldCwgbG9kSW4sIGxvZE91dCwgc2lnbWEsIHBvbGVBeGlzICkge1xuXG5cdFx0Y29uc3QgcGluZ1BvbmdSZW5kZXJUYXJnZXQgPSB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldDtcblxuXHRcdHRoaXMuX2hhbGZCbHVyKFxuXHRcdFx0Y3ViZVVWUmVuZGVyVGFyZ2V0LFxuXHRcdFx0cGluZ1BvbmdSZW5kZXJUYXJnZXQsXG5cdFx0XHRsb2RJbixcblx0XHRcdGxvZE91dCxcblx0XHRcdHNpZ21hLFxuXHRcdFx0J2xhdGl0dWRpbmFsJyxcblx0XHRcdHBvbGVBeGlzICk7XG5cblx0XHR0aGlzLl9oYWxmQmx1cihcblx0XHRcdHBpbmdQb25nUmVuZGVyVGFyZ2V0LFxuXHRcdFx0Y3ViZVVWUmVuZGVyVGFyZ2V0LFxuXHRcdFx0bG9kT3V0LFxuXHRcdFx0bG9kT3V0LFxuXHRcdFx0c2lnbWEsXG5cdFx0XHQnbG9uZ2l0dWRpbmFsJyxcblx0XHRcdHBvbGVBeGlzICk7XG5cblx0fVxuXG5cdF9oYWxmQmx1ciggdGFyZ2V0SW4sIHRhcmdldE91dCwgbG9kSW4sIGxvZE91dCwgc2lnbWFSYWRpYW5zLCBkaXJlY3Rpb24sIHBvbGVBeGlzICkge1xuXG5cdFx0Y29uc3QgcmVuZGVyZXIgPSB0aGlzLl9yZW5kZXJlcjtcblx0XHRjb25zdCBibHVyTWF0ZXJpYWwgPSB0aGlzLl9ibHVyTWF0ZXJpYWw7XG5cblx0XHRpZiAoIGRpcmVjdGlvbiAhPT0gJ2xhdGl0dWRpbmFsJyAmJiBkaXJlY3Rpb24gIT09ICdsb25naXR1ZGluYWwnICkge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKFxuXHRcdFx0XHQnYmx1ciBkaXJlY3Rpb24gbXVzdCBiZSBlaXRoZXIgbGF0aXR1ZGluYWwgb3IgbG9uZ2l0dWRpbmFsIScgKTtcblxuXHRcdH1cblxuXHRcdC8vIE51bWJlciBvZiBzdGFuZGFyZCBkZXZpYXRpb25zIGF0IHdoaWNoIHRvIGN1dCBvZmYgdGhlIGRpc2NyZXRlIGFwcHJveGltYXRpb24uXG5cdFx0Y29uc3QgU1RBTkRBUkRfREVWSUFUSU9OUyA9IDM7XG5cblx0XHRjb25zdCBibHVyTWVzaCA9IG5ldyBNZXNoKCB0aGlzLl9sb2RQbGFuZXNbIGxvZE91dCBdLCBibHVyTWF0ZXJpYWwgKTtcblx0XHRjb25zdCBibHVyVW5pZm9ybXMgPSBibHVyTWF0ZXJpYWwudW5pZm9ybXM7XG5cblx0XHRjb25zdCBwaXhlbHMgPSB0aGlzLl9zaXplTG9kc1sgbG9kSW4gXSAtIDE7XG5cdFx0Y29uc3QgcmFkaWFuc1BlclBpeGVsID0gaXNGaW5pdGUoIHNpZ21hUmFkaWFucyApID8gTWF0aC5QSSAvICggMiAqIHBpeGVscyApIDogMiAqIE1hdGguUEkgLyAoIDIgKiBNQVhfU0FNUExFUyAtIDEgKTtcblx0XHRjb25zdCBzaWdtYVBpeGVscyA9IHNpZ21hUmFkaWFucyAvIHJhZGlhbnNQZXJQaXhlbDtcblx0XHRjb25zdCBzYW1wbGVzID0gaXNGaW5pdGUoIHNpZ21hUmFkaWFucyApID8gMSArIE1hdGguZmxvb3IoIFNUQU5EQVJEX0RFVklBVElPTlMgKiBzaWdtYVBpeGVscyApIDogTUFYX1NBTVBMRVM7XG5cblx0XHRpZiAoIHNhbXBsZXMgPiBNQVhfU0FNUExFUyApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCBgc2lnbWFSYWRpYW5zLCAke1xuXHRcdFx0XHRzaWdtYVJhZGlhbnN9LCBpcyB0b28gbGFyZ2UgYW5kIHdpbGwgY2xpcCwgYXMgaXQgcmVxdWVzdGVkICR7XG5cdFx0XHRcdHNhbXBsZXN9IHNhbXBsZXMgd2hlbiB0aGUgbWF4aW11bSBpcyBzZXQgdG8gJHtNQVhfU0FNUExFU31gICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCB3ZWlnaHRzID0gW107XG5cdFx0bGV0IHN1bSA9IDA7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBNQVhfU0FNUExFUzsgKysgaSApIHtcblxuXHRcdFx0Y29uc3QgeCA9IGkgLyBzaWdtYVBpeGVscztcblx0XHRcdGNvbnN0IHdlaWdodCA9IE1hdGguZXhwKCAtIHggKiB4IC8gMiApO1xuXHRcdFx0d2VpZ2h0cy5wdXNoKCB3ZWlnaHQgKTtcblxuXHRcdFx0aWYgKCBpID09PSAwICkge1xuXG5cdFx0XHRcdHN1bSArPSB3ZWlnaHQ7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGkgPCBzYW1wbGVzICkge1xuXG5cdFx0XHRcdHN1bSArPSAyICogd2VpZ2h0O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB3ZWlnaHRzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0d2VpZ2h0c1sgaSBdID0gd2VpZ2h0c1sgaSBdIC8gc3VtO1xuXG5cdFx0fVxuXG5cdFx0Ymx1clVuaWZvcm1zWyAnZW52TWFwJyBdLnZhbHVlID0gdGFyZ2V0SW4udGV4dHVyZTtcblx0XHRibHVyVW5pZm9ybXNbICdzYW1wbGVzJyBdLnZhbHVlID0gc2FtcGxlcztcblx0XHRibHVyVW5pZm9ybXNbICd3ZWlnaHRzJyBdLnZhbHVlID0gd2VpZ2h0cztcblx0XHRibHVyVW5pZm9ybXNbICdsYXRpdHVkaW5hbCcgXS52YWx1ZSA9IGRpcmVjdGlvbiA9PT0gJ2xhdGl0dWRpbmFsJztcblxuXHRcdGlmICggcG9sZUF4aXMgKSB7XG5cblx0XHRcdGJsdXJVbmlmb3Jtc1sgJ3BvbGVBeGlzJyBdLnZhbHVlID0gcG9sZUF4aXM7XG5cblx0XHR9XG5cblx0XHRjb25zdCB7IF9sb2RNYXggfSA9IHRoaXM7XG5cdFx0Ymx1clVuaWZvcm1zWyAnZFRoZXRhJyBdLnZhbHVlID0gcmFkaWFuc1BlclBpeGVsO1xuXHRcdGJsdXJVbmlmb3Jtc1sgJ21pcEludCcgXS52YWx1ZSA9IF9sb2RNYXggLSBsb2RJbjtcblxuXHRcdGNvbnN0IG91dHB1dFNpemUgPSB0aGlzLl9zaXplTG9kc1sgbG9kT3V0IF07XG5cdFx0Y29uc3QgeCA9IDMgKiBvdXRwdXRTaXplICogKCBsb2RPdXQgPiBfbG9kTWF4IC0gTE9EX01JTiA/IGxvZE91dCAtIF9sb2RNYXggKyBMT0RfTUlOIDogMCApO1xuXHRcdGNvbnN0IHkgPSA0ICogKCB0aGlzLl9jdWJlU2l6ZSAtIG91dHB1dFNpemUgKTtcblxuXHRcdF9zZXRWaWV3cG9ydCggdGFyZ2V0T3V0LCB4LCB5LCAzICogb3V0cHV0U2l6ZSwgMiAqIG91dHB1dFNpemUgKTtcblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHRhcmdldE91dCApO1xuXHRcdHJlbmRlcmVyLnJlbmRlciggYmx1ck1lc2gsIF9mbGF0Q2FtZXJhICk7XG5cblx0fVxuXG59XG5cblxuXG5mdW5jdGlvbiBfY3JlYXRlUGxhbmVzKCBsb2RNYXggKSB7XG5cblx0Y29uc3QgbG9kUGxhbmVzID0gW107XG5cdGNvbnN0IHNpemVMb2RzID0gW107XG5cdGNvbnN0IHNpZ21hcyA9IFtdO1xuXG5cdGxldCBsb2QgPSBsb2RNYXg7XG5cblx0Y29uc3QgdG90YWxMb2RzID0gbG9kTWF4IC0gTE9EX01JTiArIDEgKyBFWFRSQV9MT0RfU0lHTUEubGVuZ3RoO1xuXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IHRvdGFsTG9kczsgaSArKyApIHtcblxuXHRcdGNvbnN0IHNpemVMb2QgPSBNYXRoLnBvdyggMiwgbG9kICk7XG5cdFx0c2l6ZUxvZHMucHVzaCggc2l6ZUxvZCApO1xuXHRcdGxldCBzaWdtYSA9IDEuMCAvIHNpemVMb2Q7XG5cblx0XHRpZiAoIGkgPiBsb2RNYXggLSBMT0RfTUlOICkge1xuXG5cdFx0XHRzaWdtYSA9IEVYVFJBX0xPRF9TSUdNQVsgaSAtIGxvZE1heCArIExPRF9NSU4gLSAxIF07XG5cblx0XHR9IGVsc2UgaWYgKCBpID09PSAwICkge1xuXG5cdFx0XHRzaWdtYSA9IDA7XG5cblx0XHR9XG5cblx0XHRzaWdtYXMucHVzaCggc2lnbWEgKTtcblxuXHRcdGNvbnN0IHRleGVsU2l6ZSA9IDEuMCAvICggc2l6ZUxvZCAtIDIgKTtcblx0XHRjb25zdCBtaW4gPSAtIHRleGVsU2l6ZTtcblx0XHRjb25zdCBtYXggPSAxICsgdGV4ZWxTaXplO1xuXHRcdGNvbnN0IHV2MSA9IFsgbWluLCBtaW4sIG1heCwgbWluLCBtYXgsIG1heCwgbWluLCBtaW4sIG1heCwgbWF4LCBtaW4sIG1heCBdO1xuXG5cdFx0Y29uc3QgY3ViZUZhY2VzID0gNjtcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IDY7XG5cdFx0Y29uc3QgcG9zaXRpb25TaXplID0gMztcblx0XHRjb25zdCB1dlNpemUgPSAyO1xuXHRcdGNvbnN0IGZhY2VJbmRleFNpemUgPSAxO1xuXG5cdFx0Y29uc3QgcG9zaXRpb24gPSBuZXcgRmxvYXQzMkFycmF5KCBwb3NpdGlvblNpemUgKiB2ZXJ0aWNlcyAqIGN1YmVGYWNlcyApO1xuXHRcdGNvbnN0IHV2ID0gbmV3IEZsb2F0MzJBcnJheSggdXZTaXplICogdmVydGljZXMgKiBjdWJlRmFjZXMgKTtcblx0XHRjb25zdCBmYWNlSW5kZXggPSBuZXcgRmxvYXQzMkFycmF5KCBmYWNlSW5kZXhTaXplICogdmVydGljZXMgKiBjdWJlRmFjZXMgKTtcblxuXHRcdGZvciAoIGxldCBmYWNlID0gMDsgZmFjZSA8IGN1YmVGYWNlczsgZmFjZSArKyApIHtcblxuXHRcdFx0Y29uc3QgeCA9ICggZmFjZSAlIDMgKSAqIDIgLyAzIC0gMTtcblx0XHRcdGNvbnN0IHkgPSBmYWNlID4gMiA/IDAgOiAtIDE7XG5cdFx0XHRjb25zdCBjb29yZGluYXRlcyA9IFtcblx0XHRcdFx0eCwgeSwgMCxcblx0XHRcdFx0eCArIDIgLyAzLCB5LCAwLFxuXHRcdFx0XHR4ICsgMiAvIDMsIHkgKyAxLCAwLFxuXHRcdFx0XHR4LCB5LCAwLFxuXHRcdFx0XHR4ICsgMiAvIDMsIHkgKyAxLCAwLFxuXHRcdFx0XHR4LCB5ICsgMSwgMFxuXHRcdFx0XTtcblx0XHRcdHBvc2l0aW9uLnNldCggY29vcmRpbmF0ZXMsIHBvc2l0aW9uU2l6ZSAqIHZlcnRpY2VzICogZmFjZSApO1xuXHRcdFx0dXYuc2V0KCB1djEsIHV2U2l6ZSAqIHZlcnRpY2VzICogZmFjZSApO1xuXHRcdFx0Y29uc3QgZmlsbCA9IFsgZmFjZSwgZmFjZSwgZmFjZSwgZmFjZSwgZmFjZSwgZmFjZSBdO1xuXHRcdFx0ZmFjZUluZGV4LnNldCggZmlsbCwgZmFjZUluZGV4U2l6ZSAqIHZlcnRpY2VzICogZmFjZSApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgcGxhbmVzID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cdFx0cGxhbmVzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIHBvc2l0aW9uU2l6ZSApICk7XG5cdFx0cGxhbmVzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEJ1ZmZlckF0dHJpYnV0ZSggdXYsIHV2U2l6ZSApICk7XG5cdFx0cGxhbmVzLnNldEF0dHJpYnV0ZSggJ2ZhY2VJbmRleCcsIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGZhY2VJbmRleCwgZmFjZUluZGV4U2l6ZSApICk7XG5cdFx0bG9kUGxhbmVzLnB1c2goIHBsYW5lcyApO1xuXG5cdFx0aWYgKCBsb2QgPiBMT0RfTUlOICkge1xuXG5cdFx0XHRsb2QgLS07XG5cblx0XHR9XG5cblx0fVxuXG5cdHJldHVybiB7IGxvZFBsYW5lcywgc2l6ZUxvZHMsIHNpZ21hcyB9O1xuXG59XG5cbmZ1bmN0aW9uIF9jcmVhdGVSZW5kZXJUYXJnZXQoIHdpZHRoLCBoZWlnaHQsIHBhcmFtcyApIHtcblxuXHRjb25zdCBjdWJlVVZSZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoIHdpZHRoLCBoZWlnaHQsIHBhcmFtcyApO1xuXHRjdWJlVVZSZW5kZXJUYXJnZXQudGV4dHVyZS5tYXBwaW5nID0gQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmc7XG5cdGN1YmVVVlJlbmRlclRhcmdldC50ZXh0dXJlLm5hbWUgPSAnUE1SRU0uY3ViZVV2Jztcblx0Y3ViZVVWUmVuZGVyVGFyZ2V0LnNjaXNzb3JUZXN0ID0gdHJ1ZTtcblx0cmV0dXJuIGN1YmVVVlJlbmRlclRhcmdldDtcblxufVxuXG5mdW5jdGlvbiBfc2V0Vmlld3BvcnQoIHRhcmdldCwgeCwgeSwgd2lkdGgsIGhlaWdodCApIHtcblxuXHR0YXJnZXQudmlld3BvcnQuc2V0KCB4LCB5LCB3aWR0aCwgaGVpZ2h0ICk7XG5cdHRhcmdldC5zY2lzc29yLnNldCggeCwgeSwgd2lkdGgsIGhlaWdodCApO1xuXG59XG5cbmZ1bmN0aW9uIF9nZXRCbHVyU2hhZGVyKCBsb2RNYXgsIHdpZHRoLCBoZWlnaHQgKSB7XG5cblx0Y29uc3Qgd2VpZ2h0cyA9IG5ldyBGbG9hdDMyQXJyYXkoIE1BWF9TQU1QTEVTICk7XG5cdGNvbnN0IHBvbGVBeGlzID0gbmV3IFZlY3RvcjMoIDAsIDEsIDAgKTtcblx0Y29uc3Qgc2hhZGVyTWF0ZXJpYWwgPSBuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcblxuXHRcdG5hbWU6ICdTcGhlcmljYWxHYXVzc2lhbkJsdXInLFxuXG5cdFx0ZGVmaW5lczoge1xuXHRcdFx0J24nOiBNQVhfU0FNUExFUyxcblx0XHRcdCdDVUJFVVZfVEVYRUxfV0lEVEgnOiAxLjAgLyB3aWR0aCxcblx0XHRcdCdDVUJFVVZfVEVYRUxfSEVJR0hUJzogMS4wIC8gaGVpZ2h0LFxuXHRcdFx0J0NVQkVVVl9NQVhfTUlQJzogYCR7bG9kTWF4fS4wYCxcblx0XHR9LFxuXG5cdFx0dW5pZm9ybXM6IHtcblx0XHRcdCdlbnZNYXAnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHQnc2FtcGxlcyc6IHsgdmFsdWU6IDEgfSxcblx0XHRcdCd3ZWlnaHRzJzogeyB2YWx1ZTogd2VpZ2h0cyB9LFxuXHRcdFx0J2xhdGl0dWRpbmFsJzogeyB2YWx1ZTogZmFsc2UgfSxcblx0XHRcdCdkVGhldGEnOiB7IHZhbHVlOiAwIH0sXG5cdFx0XHQnbWlwSW50JzogeyB2YWx1ZTogMCB9LFxuXHRcdFx0J3BvbGVBeGlzJzogeyB2YWx1ZTogcG9sZUF4aXMgfVxuXHRcdH0sXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IF9nZXRDb21tb25WZXJ0ZXhTaGFkZXIoKSxcblxuXHRcdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxuXG5cdFx0XHRwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDtcblx0XHRcdHByZWNpc2lvbiBtZWRpdW1wIGludDtcblxuXHRcdFx0dmFyeWluZyB2ZWMzIHZPdXRwdXREaXJlY3Rpb247XG5cblx0XHRcdHVuaWZvcm0gc2FtcGxlcjJEIGVudk1hcDtcblx0XHRcdHVuaWZvcm0gaW50IHNhbXBsZXM7XG5cdFx0XHR1bmlmb3JtIGZsb2F0IHdlaWdodHNbIG4gXTtcblx0XHRcdHVuaWZvcm0gYm9vbCBsYXRpdHVkaW5hbDtcblx0XHRcdHVuaWZvcm0gZmxvYXQgZFRoZXRhO1xuXHRcdFx0dW5pZm9ybSBmbG9hdCBtaXBJbnQ7XG5cdFx0XHR1bmlmb3JtIHZlYzMgcG9sZUF4aXM7XG5cblx0XHRcdCNkZWZpbmUgRU5WTUFQX1RZUEVfQ1VCRV9VVlxuXHRcdFx0I2luY2x1ZGUgPGN1YmVfdXZfcmVmbGVjdGlvbl9mcmFnbWVudD5cblxuXHRcdFx0dmVjMyBnZXRTYW1wbGUoIGZsb2F0IHRoZXRhLCB2ZWMzIGF4aXMgKSB7XG5cblx0XHRcdFx0ZmxvYXQgY29zVGhldGEgPSBjb3MoIHRoZXRhICk7XG5cdFx0XHRcdC8vIFJvZHJpZ3VlcycgYXhpcy1hbmdsZSByb3RhdGlvblxuXHRcdFx0XHR2ZWMzIHNhbXBsZURpcmVjdGlvbiA9IHZPdXRwdXREaXJlY3Rpb24gKiBjb3NUaGV0YVxuXHRcdFx0XHRcdCsgY3Jvc3MoIGF4aXMsIHZPdXRwdXREaXJlY3Rpb24gKSAqIHNpbiggdGhldGEgKVxuXHRcdFx0XHRcdCsgYXhpcyAqIGRvdCggYXhpcywgdk91dHB1dERpcmVjdGlvbiApICogKCAxLjAgLSBjb3NUaGV0YSApO1xuXG5cdFx0XHRcdHJldHVybiBiaWxpbmVhckN1YmVVViggZW52TWFwLCBzYW1wbGVEaXJlY3Rpb24sIG1pcEludCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0XHR2ZWMzIGF4aXMgPSBsYXRpdHVkaW5hbCA/IHBvbGVBeGlzIDogY3Jvc3MoIHBvbGVBeGlzLCB2T3V0cHV0RGlyZWN0aW9uICk7XG5cblx0XHRcdFx0aWYgKCBhbGwoIGVxdWFsKCBheGlzLCB2ZWMzKCAwLjAgKSApICkgKSB7XG5cblx0XHRcdFx0XHRheGlzID0gdmVjMyggdk91dHB1dERpcmVjdGlvbi56LCAwLjAsIC0gdk91dHB1dERpcmVjdGlvbi54ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGF4aXMgPSBub3JtYWxpemUoIGF4aXMgKTtcblxuXHRcdFx0XHRnbF9GcmFnQ29sb3IgPSB2ZWM0KCAwLjAsIDAuMCwgMC4wLCAxLjAgKTtcblx0XHRcdFx0Z2xfRnJhZ0NvbG9yLnJnYiArPSB3ZWlnaHRzWyAwIF0gKiBnZXRTYW1wbGUoIDAuMCwgYXhpcyApO1xuXG5cdFx0XHRcdGZvciAoIGludCBpID0gMTsgaSA8IG47IGkrKyApIHtcblxuXHRcdFx0XHRcdGlmICggaSA+PSBzYW1wbGVzICkge1xuXG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGZsb2F0IHRoZXRhID0gZFRoZXRhICogZmxvYXQoIGkgKTtcblx0XHRcdFx0XHRnbF9GcmFnQ29sb3IucmdiICs9IHdlaWdodHNbIGkgXSAqIGdldFNhbXBsZSggLTEuMCAqIHRoZXRhLCBheGlzICk7XG5cdFx0XHRcdFx0Z2xfRnJhZ0NvbG9yLnJnYiArPSB3ZWlnaHRzWyBpIF0gKiBnZXRTYW1wbGUoIHRoZXRhLCBheGlzICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cdFx0YCxcblxuXHRcdGJsZW5kaW5nOiBOb0JsZW5kaW5nLFxuXHRcdGRlcHRoVGVzdDogZmFsc2UsXG5cdFx0ZGVwdGhXcml0ZTogZmFsc2VcblxuXHR9ICk7XG5cblx0cmV0dXJuIHNoYWRlck1hdGVyaWFsO1xuXG59XG5cbmZ1bmN0aW9uIF9nZXRFcXVpcmVjdE1hdGVyaWFsKCkge1xuXG5cdHJldHVybiBuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcblxuXHRcdG5hbWU6ICdFcXVpcmVjdGFuZ3VsYXJUb0N1YmVVVicsXG5cblx0XHR1bmlmb3Jtczoge1xuXHRcdFx0J2Vudk1hcCc6IHsgdmFsdWU6IG51bGwgfVxuXHRcdH0sXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IF9nZXRDb21tb25WZXJ0ZXhTaGFkZXIoKSxcblxuXHRcdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxuXG5cdFx0XHRwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDtcblx0XHRcdHByZWNpc2lvbiBtZWRpdW1wIGludDtcblxuXHRcdFx0dmFyeWluZyB2ZWMzIHZPdXRwdXREaXJlY3Rpb247XG5cblx0XHRcdHVuaWZvcm0gc2FtcGxlcjJEIGVudk1hcDtcblxuXHRcdFx0I2luY2x1ZGUgPGNvbW1vbj5cblxuXHRcdFx0dm9pZCBtYWluKCkge1xuXG5cdFx0XHRcdHZlYzMgb3V0cHV0RGlyZWN0aW9uID0gbm9ybWFsaXplKCB2T3V0cHV0RGlyZWN0aW9uICk7XG5cdFx0XHRcdHZlYzIgdXYgPSBlcXVpcmVjdFV2KCBvdXRwdXREaXJlY3Rpb24gKTtcblxuXHRcdFx0XHRnbF9GcmFnQ29sb3IgPSB2ZWM0KCB0ZXh0dXJlMkQgKCBlbnZNYXAsIHV2ICkucmdiLCAxLjAgKTtcblxuXHRcdFx0fVxuXHRcdGAsXG5cblx0XHRibGVuZGluZzogTm9CbGVuZGluZyxcblx0XHRkZXB0aFRlc3Q6IGZhbHNlLFxuXHRcdGRlcHRoV3JpdGU6IGZhbHNlXG5cblx0fSApO1xuXG59XG5cbmZ1bmN0aW9uIF9nZXRDdWJlbWFwTWF0ZXJpYWwoKSB7XG5cblx0cmV0dXJuIG5ldyBTaGFkZXJNYXRlcmlhbCgge1xuXG5cdFx0bmFtZTogJ0N1YmVtYXBUb0N1YmVVVicsXG5cblx0XHR1bmlmb3Jtczoge1xuXHRcdFx0J2Vudk1hcCc6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdCdmbGlwRW52TWFwJzogeyB2YWx1ZTogLSAxIH1cblx0XHR9LFxuXG5cdFx0dmVydGV4U2hhZGVyOiBfZ2V0Q29tbW9uVmVydGV4U2hhZGVyKCksXG5cblx0XHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2BcblxuXHRcdFx0cHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7XG5cdFx0XHRwcmVjaXNpb24gbWVkaXVtcCBpbnQ7XG5cblx0XHRcdHVuaWZvcm0gZmxvYXQgZmxpcEVudk1hcDtcblxuXHRcdFx0dmFyeWluZyB2ZWMzIHZPdXRwdXREaXJlY3Rpb247XG5cblx0XHRcdHVuaWZvcm0gc2FtcGxlckN1YmUgZW52TWFwO1xuXG5cdFx0XHR2b2lkIG1haW4oKSB7XG5cblx0XHRcdFx0Z2xfRnJhZ0NvbG9yID0gdGV4dHVyZUN1YmUoIGVudk1hcCwgdmVjMyggZmxpcEVudk1hcCAqIHZPdXRwdXREaXJlY3Rpb24ueCwgdk91dHB1dERpcmVjdGlvbi55eiApICk7XG5cblx0XHRcdH1cblx0XHRgLFxuXG5cdFx0YmxlbmRpbmc6IE5vQmxlbmRpbmcsXG5cdFx0ZGVwdGhUZXN0OiBmYWxzZSxcblx0XHRkZXB0aFdyaXRlOiBmYWxzZVxuXG5cdH0gKTtcblxufVxuXG5mdW5jdGlvbiBfZ2V0Q29tbW9uVmVydGV4U2hhZGVyKCkge1xuXG5cdHJldHVybiAvKiBnbHNsICovYFxuXG5cdFx0cHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7XG5cdFx0cHJlY2lzaW9uIG1lZGl1bXAgaW50O1xuXG5cdFx0YXR0cmlidXRlIGZsb2F0IGZhY2VJbmRleDtcblxuXHRcdHZhcnlpbmcgdmVjMyB2T3V0cHV0RGlyZWN0aW9uO1xuXG5cdFx0Ly8gUkggY29vcmRpbmF0ZSBzeXN0ZW07IFBNUkVNIGZhY2UtaW5kZXhpbmcgY29udmVudGlvblxuXHRcdHZlYzMgZ2V0RGlyZWN0aW9uKCB2ZWMyIHV2LCBmbG9hdCBmYWNlICkge1xuXG5cdFx0XHR1diA9IDIuMCAqIHV2IC0gMS4wO1xuXG5cdFx0XHR2ZWMzIGRpcmVjdGlvbiA9IHZlYzMoIHV2LCAxLjAgKTtcblxuXHRcdFx0aWYgKCBmYWNlID09IDAuMCApIHtcblxuXHRcdFx0XHRkaXJlY3Rpb24gPSBkaXJlY3Rpb24uenl4OyAvLyAoIDEsIHYsIHUgKSBwb3MgeFxuXG5cdFx0XHR9IGVsc2UgaWYgKCBmYWNlID09IDEuMCApIHtcblxuXHRcdFx0XHRkaXJlY3Rpb24gPSBkaXJlY3Rpb24ueHp5O1xuXHRcdFx0XHRkaXJlY3Rpb24ueHogKj0gLTEuMDsgLy8gKCAtdSwgMSwgLXYgKSBwb3MgeVxuXG5cdFx0XHR9IGVsc2UgaWYgKCBmYWNlID09IDIuMCApIHtcblxuXHRcdFx0XHRkaXJlY3Rpb24ueCAqPSAtMS4wOyAvLyAoIC11LCB2LCAxICkgcG9zIHpcblxuXHRcdFx0fSBlbHNlIGlmICggZmFjZSA9PSAzLjAgKSB7XG5cblx0XHRcdFx0ZGlyZWN0aW9uID0gZGlyZWN0aW9uLnp5eDtcblx0XHRcdFx0ZGlyZWN0aW9uLnh6ICo9IC0xLjA7IC8vICggLTEsIHYsIC11ICkgbmVnIHhcblxuXHRcdFx0fSBlbHNlIGlmICggZmFjZSA9PSA0LjAgKSB7XG5cblx0XHRcdFx0ZGlyZWN0aW9uID0gZGlyZWN0aW9uLnh6eTtcblx0XHRcdFx0ZGlyZWN0aW9uLnh5ICo9IC0xLjA7IC8vICggLXUsIC0xLCB2ICkgbmVnIHlcblxuXHRcdFx0fSBlbHNlIGlmICggZmFjZSA9PSA1LjAgKSB7XG5cblx0XHRcdFx0ZGlyZWN0aW9uLnogKj0gLTEuMDsgLy8gKCB1LCB2LCAtMSApIG5lZyB6XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGRpcmVjdGlvbjtcblxuXHRcdH1cblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0dk91dHB1dERpcmVjdGlvbiA9IGdldERpcmVjdGlvbiggdXYsIGZhY2VJbmRleCApO1xuXHRcdFx0Z2xfUG9zaXRpb24gPSB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XG5cblx0XHR9XG5cdGA7XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xDdWJlVVZNYXBzKCByZW5kZXJlciApIHtcblxuXHRsZXQgY3ViZVVWbWFwcyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0bGV0IHBtcmVtR2VuZXJhdG9yID0gbnVsbDtcblxuXHRmdW5jdGlvbiBnZXQoIHRleHR1cmUgKSB7XG5cblx0XHRpZiAoIHRleHR1cmUgJiYgdGV4dHVyZS5pc1RleHR1cmUgKSB7XG5cblx0XHRcdGNvbnN0IG1hcHBpbmcgPSB0ZXh0dXJlLm1hcHBpbmc7XG5cblx0XHRcdGNvbnN0IGlzRXF1aXJlY3RNYXAgPSAoIG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nIHx8IG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZnJhY3Rpb25NYXBwaW5nICk7XG5cdFx0XHRjb25zdCBpc0N1YmVNYXAgPSAoIG1hcHBpbmcgPT09IEN1YmVSZWZsZWN0aW9uTWFwcGluZyB8fCBtYXBwaW5nID09PSBDdWJlUmVmcmFjdGlvbk1hcHBpbmcgKTtcblxuXHRcdFx0Ly8gZXF1aXJlY3QvY3ViZSBtYXAgdG8gY3ViZVVWIGNvbnZlcnNpb25cblxuXHRcdFx0aWYgKCBpc0VxdWlyZWN0TWFwIHx8IGlzQ3ViZU1hcCApIHtcblxuXHRcdFx0XHRsZXQgcmVuZGVyVGFyZ2V0ID0gY3ViZVVWbWFwcy5nZXQoIHRleHR1cmUgKTtcblxuXHRcdFx0XHRjb25zdCBjdXJyZW50UE1SRU1WZXJzaW9uID0gcmVuZGVyVGFyZ2V0ICE9PSB1bmRlZmluZWQgPyByZW5kZXJUYXJnZXQudGV4dHVyZS5wbXJlbVZlcnNpb24gOiAwO1xuXG5cdFx0XHRcdGlmICggdGV4dHVyZS5pc1JlbmRlclRhcmdldFRleHR1cmUgJiYgdGV4dHVyZS5wbXJlbVZlcnNpb24gIT09IGN1cnJlbnRQTVJFTVZlcnNpb24gKSB7XG5cblx0XHRcdFx0XHRpZiAoIHBtcmVtR2VuZXJhdG9yID09PSBudWxsICkgcG1yZW1HZW5lcmF0b3IgPSBuZXcgUE1SRU1HZW5lcmF0b3IoIHJlbmRlcmVyICk7XG5cblx0XHRcdFx0XHRyZW5kZXJUYXJnZXQgPSBpc0VxdWlyZWN0TWFwID8gcG1yZW1HZW5lcmF0b3IuZnJvbUVxdWlyZWN0YW5ndWxhciggdGV4dHVyZSwgcmVuZGVyVGFyZ2V0ICkgOiBwbXJlbUdlbmVyYXRvci5mcm9tQ3ViZW1hcCggdGV4dHVyZSwgcmVuZGVyVGFyZ2V0ICk7XG5cdFx0XHRcdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUucG1yZW1WZXJzaW9uID0gdGV4dHVyZS5wbXJlbVZlcnNpb247XG5cblx0XHRcdFx0XHRjdWJlVVZtYXBzLnNldCggdGV4dHVyZSwgcmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRcdFx0XHRyZXR1cm4gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRcdHJldHVybiByZW5kZXJUYXJnZXQudGV4dHVyZTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGltYWdlID0gdGV4dHVyZS5pbWFnZTtcblxuXHRcdFx0XHRcdFx0aWYgKCAoIGlzRXF1aXJlY3RNYXAgJiYgaW1hZ2UgJiYgaW1hZ2UuaGVpZ2h0ID4gMCApIHx8ICggaXNDdWJlTWFwICYmIGltYWdlICYmIGlzQ3ViZVRleHR1cmVDb21wbGV0ZSggaW1hZ2UgKSApICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggcG1yZW1HZW5lcmF0b3IgPT09IG51bGwgKSBwbXJlbUdlbmVyYXRvciA9IG5ldyBQTVJFTUdlbmVyYXRvciggcmVuZGVyZXIgKTtcblxuXHRcdFx0XHRcdFx0XHRyZW5kZXJUYXJnZXQgPSBpc0VxdWlyZWN0TWFwID8gcG1yZW1HZW5lcmF0b3IuZnJvbUVxdWlyZWN0YW5ndWxhciggdGV4dHVyZSApIDogcG1yZW1HZW5lcmF0b3IuZnJvbUN1YmVtYXAoIHRleHR1cmUgKTtcblx0XHRcdFx0XHRcdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUucG1yZW1WZXJzaW9uID0gdGV4dHVyZS5wbXJlbVZlcnNpb247XG5cblx0XHRcdFx0XHRcdFx0Y3ViZVVWbWFwcy5zZXQoIHRleHR1cmUsIHJlbmRlclRhcmdldCApO1xuXG5cdFx0XHRcdFx0XHRcdHRleHR1cmUuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XG5cblx0XHRcdFx0XHRcdFx0cmV0dXJuIHJlbmRlclRhcmdldC50ZXh0dXJlO1xuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdC8vIGltYWdlIG5vdCB5ZXQgcmVhZHkuIHRyeSB0aGUgY29udmVyc2lvbiBuZXh0IGZyYW1lXG5cblx0XHRcdFx0XHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0ZXh0dXJlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBpc0N1YmVUZXh0dXJlQ29tcGxldGUoIGltYWdlICkge1xuXG5cdFx0bGV0IGNvdW50ID0gMDtcblx0XHRjb25zdCBsZW5ndGggPSA2O1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRpZiAoIGltYWdlWyBpIF0gIT09IHVuZGVmaW5lZCApIGNvdW50ICsrO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNvdW50ID09PSBsZW5ndGg7XG5cblxuXHR9XG5cblx0ZnVuY3Rpb24gb25UZXh0dXJlRGlzcG9zZSggZXZlbnQgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlID0gZXZlbnQudGFyZ2V0O1xuXG5cdFx0dGV4dHVyZS5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVGV4dHVyZURpc3Bvc2UgKTtcblxuXHRcdGNvbnN0IGN1YmVtYXBVViA9IGN1YmVVVm1hcHMuZ2V0KCB0ZXh0dXJlICk7XG5cblx0XHRpZiAoIGN1YmVtYXBVViAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjdWJlVVZtYXBzLmRlbGV0ZSggdGV4dHVyZSApO1xuXHRcdFx0Y3ViZW1hcFVWLmRpc3Bvc2UoKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gZGlzcG9zZSgpIHtcblxuXHRcdGN1YmVVVm1hcHMgPSBuZXcgV2Vha01hcCgpO1xuXG5cdFx0aWYgKCBwbXJlbUdlbmVyYXRvciAhPT0gbnVsbCApIHtcblxuXHRcdFx0cG1yZW1HZW5lcmF0b3IuZGlzcG9zZSgpO1xuXHRcdFx0cG1yZW1HZW5lcmF0b3IgPSBudWxsO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4ge1xuXHRcdGdldDogZ2V0LFxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2Vcblx0fTtcblxufVxuXG5mdW5jdGlvbiBXZWJHTEV4dGVuc2lvbnMoIGdsICkge1xuXG5cdGNvbnN0IGV4dGVuc2lvbnMgPSB7fTtcblxuXHRmdW5jdGlvbiBnZXRFeHRlbnNpb24oIG5hbWUgKSB7XG5cblx0XHRpZiAoIGV4dGVuc2lvbnNbIG5hbWUgXSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRyZXR1cm4gZXh0ZW5zaW9uc1sgbmFtZSBdO1xuXG5cdFx0fVxuXG5cdFx0bGV0IGV4dGVuc2lvbjtcblxuXHRcdHN3aXRjaCAoIG5hbWUgKSB7XG5cblx0XHRcdGNhc2UgJ1dFQkdMX2RlcHRoX3RleHR1cmUnOlxuXHRcdFx0XHRleHRlbnNpb24gPSBnbC5nZXRFeHRlbnNpb24oICdXRUJHTF9kZXB0aF90ZXh0dXJlJyApIHx8IGdsLmdldEV4dGVuc2lvbiggJ01PWl9XRUJHTF9kZXB0aF90ZXh0dXJlJyApIHx8IGdsLmdldEV4dGVuc2lvbiggJ1dFQktJVF9XRUJHTF9kZXB0aF90ZXh0dXJlJyApO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJzpcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJyApIHx8IGdsLmdldEV4dGVuc2lvbiggJ01PWl9FWFRfdGV4dHVyZV9maWx0ZXJfYW5pc290cm9waWMnICkgfHwgZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCS0lUX0VYVF90ZXh0dXJlX2ZpbHRlcl9hbmlzb3Ryb3BpYycgKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9zM3RjJzpcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3MzdGMnICkgfHwgZ2wuZ2V0RXh0ZW5zaW9uKCAnTU9aX1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9zM3RjJyApIHx8IGdsLmdldEV4dGVuc2lvbiggJ1dFQktJVF9XRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfczN0YycgKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9wdnJ0Yyc6XG5cdFx0XHRcdGV4dGVuc2lvbiA9IGdsLmdldEV4dGVuc2lvbiggJ1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9wdnJ0YycgKSB8fCBnbC5nZXRFeHRlbnNpb24oICdXRUJLSVRfV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3B2cnRjJyApO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCBuYW1lICk7XG5cblx0XHR9XG5cblx0XHRleHRlbnNpb25zWyBuYW1lIF0gPSBleHRlbnNpb247XG5cblx0XHRyZXR1cm4gZXh0ZW5zaW9uO1xuXG5cdH1cblxuXHRyZXR1cm4ge1xuXG5cdFx0aGFzOiBmdW5jdGlvbiAoIG5hbWUgKSB7XG5cblx0XHRcdHJldHVybiBnZXRFeHRlbnNpb24oIG5hbWUgKSAhPT0gbnVsbDtcblxuXHRcdH0sXG5cblx0XHRpbml0OiBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdGdldEV4dGVuc2lvbiggJ0VYVF9jb2xvcl9idWZmZXJfZmxvYXQnICk7XG5cdFx0XHRnZXRFeHRlbnNpb24oICdXRUJHTF9jbGlwX2N1bGxfZGlzdGFuY2UnICk7XG5cdFx0XHRnZXRFeHRlbnNpb24oICdPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXInICk7XG5cdFx0XHRnZXRFeHRlbnNpb24oICdFWFRfY29sb3JfYnVmZmVyX2hhbGZfZmxvYXQnICk7XG5cdFx0XHRnZXRFeHRlbnNpb24oICdXRUJHTF9tdWx0aXNhbXBsZWRfcmVuZGVyX3RvX3RleHR1cmUnICk7XG5cdFx0XHRnZXRFeHRlbnNpb24oICdXRUJHTF9yZW5kZXJfc2hhcmVkX2V4cG9uZW50JyApO1xuXG5cdFx0fSxcblxuXHRcdGdldDogZnVuY3Rpb24gKCBuYW1lICkge1xuXG5cdFx0XHRjb25zdCBleHRlbnNpb24gPSBnZXRFeHRlbnNpb24oIG5hbWUgKTtcblxuXHRcdFx0aWYgKCBleHRlbnNpb24gPT09IG51bGwgKSB7XG5cblx0XHRcdFx0d2Fybk9uY2UoICdUSFJFRS5XZWJHTFJlbmRlcmVyOiAnICsgbmFtZSArICcgZXh0ZW5zaW9uIG5vdCBzdXBwb3J0ZWQuJyApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBleHRlbnNpb247XG5cblx0XHR9XG5cblx0fTtcblxufVxuXG5mdW5jdGlvbiBXZWJHTEdlb21ldHJpZXMoIGdsLCBhdHRyaWJ1dGVzLCBpbmZvLCBiaW5kaW5nU3RhdGVzICkge1xuXG5cdGNvbnN0IGdlb21ldHJpZXMgPSB7fTtcblx0Y29uc3Qgd2lyZWZyYW1lQXR0cmlidXRlcyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0ZnVuY3Rpb24gb25HZW9tZXRyeURpc3Bvc2UoIGV2ZW50ICkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBldmVudC50YXJnZXQ7XG5cblx0XHRpZiAoIGdlb21ldHJ5LmluZGV4ICE9PSBudWxsICkge1xuXG5cdFx0XHRhdHRyaWJ1dGVzLnJlbW92ZSggZ2VvbWV0cnkuaW5kZXggKTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gZ2VvbWV0cnkuYXR0cmlidXRlcyApIHtcblxuXHRcdFx0YXR0cmlidXRlcy5yZW1vdmUoIGdlb21ldHJ5LmF0dHJpYnV0ZXNbIG5hbWUgXSApO1xuXG5cdFx0fVxuXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdGNvbnN0IGFycmF5ID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzWyBuYW1lIF07XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGFycmF5Lmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0YXR0cmlidXRlcy5yZW1vdmUoIGFycmF5WyBpIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Z2VvbWV0cnkucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvbkdlb21ldHJ5RGlzcG9zZSApO1xuXG5cdFx0ZGVsZXRlIGdlb21ldHJpZXNbIGdlb21ldHJ5LmlkIF07XG5cblx0XHRjb25zdCBhdHRyaWJ1dGUgPSB3aXJlZnJhbWVBdHRyaWJ1dGVzLmdldCggZ2VvbWV0cnkgKTtcblxuXHRcdGlmICggYXR0cmlidXRlICkge1xuXG5cdFx0XHRhdHRyaWJ1dGVzLnJlbW92ZSggYXR0cmlidXRlICk7XG5cdFx0XHR3aXJlZnJhbWVBdHRyaWJ1dGVzLmRlbGV0ZSggZ2VvbWV0cnkgKTtcblxuXHRcdH1cblxuXHRcdGJpbmRpbmdTdGF0ZXMucmVsZWFzZVN0YXRlc09mR2VvbWV0cnkoIGdlb21ldHJ5ICk7XG5cblx0XHRpZiAoIGdlb21ldHJ5LmlzSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgPT09IHRydWUgKSB7XG5cblx0XHRcdGRlbGV0ZSBnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudDtcblxuXHRcdH1cblxuXHRcdC8vXG5cblx0XHRpbmZvLm1lbW9yeS5nZW9tZXRyaWVzIC0tO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBnZXQoIG9iamVjdCwgZ2VvbWV0cnkgKSB7XG5cblx0XHRpZiAoIGdlb21ldHJpZXNbIGdlb21ldHJ5LmlkIF0gPT09IHRydWUgKSByZXR1cm4gZ2VvbWV0cnk7XG5cblx0XHRnZW9tZXRyeS5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uR2VvbWV0cnlEaXNwb3NlICk7XG5cblx0XHRnZW9tZXRyaWVzWyBnZW9tZXRyeS5pZCBdID0gdHJ1ZTtcblxuXHRcdGluZm8ubWVtb3J5Lmdlb21ldHJpZXMgKys7XG5cblx0XHRyZXR1cm4gZ2VvbWV0cnk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHVwZGF0ZSggZ2VvbWV0cnkgKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeUF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzO1xuXG5cdFx0Ly8gVXBkYXRpbmcgaW5kZXggYnVmZmVyIGluIFZBTyBub3cuIFNlZSBXZWJHTEJpbmRpbmdTdGF0ZXMuXG5cblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIGdlb21ldHJ5QXR0cmlidXRlcyApIHtcblxuXHRcdFx0YXR0cmlidXRlcy51cGRhdGUoIGdlb21ldHJ5QXR0cmlidXRlc1sgbmFtZSBdLCBnbC5BUlJBWV9CVUZGRVIgKTtcblxuXHRcdH1cblxuXHRcdC8vIG1vcnBoIHRhcmdldHNcblxuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlcyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcztcblxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gbW9ycGhBdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRjb25zdCBhcnJheSA9IG1vcnBoQXR0cmlidXRlc1sgbmFtZSBdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBhcnJheS5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBhcnJheVsgaSBdLCBnbC5BUlJBWV9CVUZGRVIgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB1cGRhdGVXaXJlZnJhbWVBdHRyaWJ1dGUoIGdlb21ldHJ5ICkge1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnlJbmRleCA9IGdlb21ldHJ5LmluZGV4O1xuXHRcdGNvbnN0IGdlb21ldHJ5UG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXHRcdGxldCB2ZXJzaW9uID0gMDtcblxuXHRcdGlmICggZ2VvbWV0cnlJbmRleCAhPT0gbnVsbCApIHtcblxuXHRcdFx0Y29uc3QgYXJyYXkgPSBnZW9tZXRyeUluZGV4LmFycmF5O1xuXHRcdFx0dmVyc2lvbiA9IGdlb21ldHJ5SW5kZXgudmVyc2lvbjtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gYXJyYXkubGVuZ3RoOyBpIDwgbDsgaSArPSAzICkge1xuXG5cdFx0XHRcdGNvbnN0IGEgPSBhcnJheVsgaSArIDAgXTtcblx0XHRcdFx0Y29uc3QgYiA9IGFycmF5WyBpICsgMSBdO1xuXHRcdFx0XHRjb25zdCBjID0gYXJyYXlbIGkgKyAyIF07XG5cblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBhLCBiLCBiLCBjLCBjLCBhICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSBpZiAoIGdlb21ldHJ5UG9zaXRpb24gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3QgYXJyYXkgPSBnZW9tZXRyeVBvc2l0aW9uLmFycmF5O1xuXHRcdFx0dmVyc2lvbiA9IGdlb21ldHJ5UG9zaXRpb24udmVyc2lvbjtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gKCBhcnJheS5sZW5ndGggLyAzICkgLSAxOyBpIDwgbDsgaSArPSAzICkge1xuXG5cdFx0XHRcdGNvbnN0IGEgPSBpICsgMDtcblx0XHRcdFx0Y29uc3QgYiA9IGkgKyAxO1xuXHRcdFx0XHRjb25zdCBjID0gaSArIDI7XG5cblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBhLCBiLCBiLCBjLCBjLCBhICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGF0dHJpYnV0ZSA9IG5ldyAoIGFycmF5TmVlZHNVaW50MzIoIGluZGljZXMgKSA/IFVpbnQzMkJ1ZmZlckF0dHJpYnV0ZSA6IFVpbnQxNkJ1ZmZlckF0dHJpYnV0ZSApKCBpbmRpY2VzLCAxICk7XG5cdFx0YXR0cmlidXRlLnZlcnNpb24gPSB2ZXJzaW9uO1xuXG5cdFx0Ly8gVXBkYXRpbmcgaW5kZXggYnVmZmVyIGluIFZBTyBub3cuIFNlZSBXZWJHTEJpbmRpbmdTdGF0ZXNcblxuXHRcdC8vXG5cblx0XHRjb25zdCBwcmV2aW91c0F0dHJpYnV0ZSA9IHdpcmVmcmFtZUF0dHJpYnV0ZXMuZ2V0KCBnZW9tZXRyeSApO1xuXG5cdFx0aWYgKCBwcmV2aW91c0F0dHJpYnV0ZSApIGF0dHJpYnV0ZXMucmVtb3ZlKCBwcmV2aW91c0F0dHJpYnV0ZSApO1xuXG5cdFx0Ly9cblxuXHRcdHdpcmVmcmFtZUF0dHJpYnV0ZXMuc2V0KCBnZW9tZXRyeSwgYXR0cmlidXRlICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldFdpcmVmcmFtZUF0dHJpYnV0ZSggZ2VvbWV0cnkgKSB7XG5cblx0XHRjb25zdCBjdXJyZW50QXR0cmlidXRlID0gd2lyZWZyYW1lQXR0cmlidXRlcy5nZXQoIGdlb21ldHJ5ICk7XG5cblx0XHRpZiAoIGN1cnJlbnRBdHRyaWJ1dGUgKSB7XG5cblx0XHRcdGNvbnN0IGdlb21ldHJ5SW5kZXggPSBnZW9tZXRyeS5pbmRleDtcblxuXHRcdFx0aWYgKCBnZW9tZXRyeUluZGV4ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdC8vIGlmIHRoZSBhdHRyaWJ1dGUgaXMgb2Jzb2xldGUsIGNyZWF0ZSBhIG5ldyBvbmVcblxuXHRcdFx0XHRpZiAoIGN1cnJlbnRBdHRyaWJ1dGUudmVyc2lvbiA8IGdlb21ldHJ5SW5kZXgudmVyc2lvbiApIHtcblxuXHRcdFx0XHRcdHVwZGF0ZVdpcmVmcmFtZUF0dHJpYnV0ZSggZ2VvbWV0cnkgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHVwZGF0ZVdpcmVmcmFtZUF0dHJpYnV0ZSggZ2VvbWV0cnkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB3aXJlZnJhbWVBdHRyaWJ1dGVzLmdldCggZ2VvbWV0cnkgKTtcblxuXHR9XG5cblx0cmV0dXJuIHtcblxuXHRcdGdldDogZ2V0LFxuXHRcdHVwZGF0ZTogdXBkYXRlLFxuXG5cdFx0Z2V0V2lyZWZyYW1lQXR0cmlidXRlOiBnZXRXaXJlZnJhbWVBdHRyaWJ1dGVcblxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMSW5kZXhlZEJ1ZmZlclJlbmRlcmVyKCBnbCwgZXh0ZW5zaW9ucywgaW5mbyApIHtcblxuXHRsZXQgbW9kZTtcblxuXHRmdW5jdGlvbiBzZXRNb2RlKCB2YWx1ZSApIHtcblxuXHRcdG1vZGUgPSB2YWx1ZTtcblxuXHR9XG5cblx0bGV0IHR5cGUsIGJ5dGVzUGVyRWxlbWVudDtcblxuXHRmdW5jdGlvbiBzZXRJbmRleCggdmFsdWUgKSB7XG5cblx0XHR0eXBlID0gdmFsdWUudHlwZTtcblx0XHRieXRlc1BlckVsZW1lbnQgPSB2YWx1ZS5ieXRlc1BlckVsZW1lbnQ7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlbmRlciggc3RhcnQsIGNvdW50ICkge1xuXG5cdFx0Z2wuZHJhd0VsZW1lbnRzKCBtb2RlLCBjb3VudCwgdHlwZSwgc3RhcnQgKiBieXRlc1BlckVsZW1lbnQgKTtcblxuXHRcdGluZm8udXBkYXRlKCBjb3VudCwgbW9kZSwgMSApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXJJbnN0YW5jZXMoIHN0YXJ0LCBjb3VudCwgcHJpbWNvdW50ICkge1xuXG5cdFx0aWYgKCBwcmltY291bnQgPT09IDAgKSByZXR1cm47XG5cblx0XHRnbC5kcmF3RWxlbWVudHNJbnN0YW5jZWQoIG1vZGUsIGNvdW50LCB0eXBlLCBzdGFydCAqIGJ5dGVzUGVyRWxlbWVudCwgcHJpbWNvdW50ICk7XG5cblx0XHRpbmZvLnVwZGF0ZSggY291bnQsIG1vZGUsIHByaW1jb3VudCApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXJNdWx0aURyYXcoIHN0YXJ0cywgY291bnRzLCBkcmF3Q291bnQgKSB7XG5cblx0XHRpZiAoIGRyYXdDb3VudCA9PT0gMCApIHJldHVybjtcblxuXHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbXVsdGlfZHJhdycgKTtcblx0XHRleHRlbnNpb24ubXVsdGlEcmF3RWxlbWVudHNXRUJHTCggbW9kZSwgY291bnRzLCAwLCB0eXBlLCBzdGFydHMsIDAsIGRyYXdDb3VudCApO1xuXG5cdFx0bGV0IGVsZW1lbnRDb3VudCA9IDA7XG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZHJhd0NvdW50OyBpICsrICkge1xuXG5cdFx0XHRlbGVtZW50Q291bnQgKz0gY291bnRzWyBpIF07XG5cblx0XHR9XG5cblx0XHRpbmZvLnVwZGF0ZSggZWxlbWVudENvdW50LCBtb2RlLCAxICk7XG5cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVuZGVyTXVsdGlEcmF3SW5zdGFuY2VzKCBzdGFydHMsIGNvdW50cywgZHJhd0NvdW50LCBwcmltY291bnQgKSB7XG5cblx0XHRpZiAoIGRyYXdDb3VudCA9PT0gMCApIHJldHVybjtcblxuXHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbXVsdGlfZHJhdycgKTtcblxuXHRcdGlmICggZXh0ZW5zaW9uID09PSBudWxsICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzdGFydHMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdHJlbmRlckluc3RhbmNlcyggc3RhcnRzWyBpIF0gLyBieXRlc1BlckVsZW1lbnQsIGNvdW50c1sgaSBdLCBwcmltY291bnRbIGkgXSApO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRleHRlbnNpb24ubXVsdGlEcmF3RWxlbWVudHNJbnN0YW5jZWRXRUJHTCggbW9kZSwgY291bnRzLCAwLCB0eXBlLCBzdGFydHMsIDAsIHByaW1jb3VudCwgMCwgZHJhd0NvdW50ICk7XG5cblx0XHRcdGxldCBlbGVtZW50Q291bnQgPSAwO1xuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZHJhd0NvdW50OyBpICsrICkge1xuXG5cdFx0XHRcdGVsZW1lbnRDb3VudCArPSBjb3VudHNbIGkgXTtcblxuXHRcdFx0fVxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcmltY291bnQubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGluZm8udXBkYXRlKCBlbGVtZW50Q291bnQsIG1vZGUsIHByaW1jb3VudFsgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0Ly9cblxuXHR0aGlzLnNldE1vZGUgPSBzZXRNb2RlO1xuXHR0aGlzLnNldEluZGV4ID0gc2V0SW5kZXg7XG5cdHRoaXMucmVuZGVyID0gcmVuZGVyO1xuXHR0aGlzLnJlbmRlckluc3RhbmNlcyA9IHJlbmRlckluc3RhbmNlcztcblx0dGhpcy5yZW5kZXJNdWx0aURyYXcgPSByZW5kZXJNdWx0aURyYXc7XG5cdHRoaXMucmVuZGVyTXVsdGlEcmF3SW5zdGFuY2VzID0gcmVuZGVyTXVsdGlEcmF3SW5zdGFuY2VzO1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMSW5mbyggZ2wgKSB7XG5cblx0Y29uc3QgbWVtb3J5ID0ge1xuXHRcdGdlb21ldHJpZXM6IDAsXG5cdFx0dGV4dHVyZXM6IDBcblx0fTtcblxuXHRjb25zdCByZW5kZXIgPSB7XG5cdFx0ZnJhbWU6IDAsXG5cdFx0Y2FsbHM6IDAsXG5cdFx0dHJpYW5nbGVzOiAwLFxuXHRcdHBvaW50czogMCxcblx0XHRsaW5lczogMFxuXHR9O1xuXG5cdGZ1bmN0aW9uIHVwZGF0ZSggY291bnQsIG1vZGUsIGluc3RhbmNlQ291bnQgKSB7XG5cblx0XHRyZW5kZXIuY2FsbHMgKys7XG5cblx0XHRzd2l0Y2ggKCBtb2RlICkge1xuXG5cdFx0XHRjYXNlIGdsLlRSSUFOR0xFUzpcblx0XHRcdFx0cmVuZGVyLnRyaWFuZ2xlcyArPSBpbnN0YW5jZUNvdW50ICogKCBjb3VudCAvIDMgKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgZ2wuTElORVM6XG5cdFx0XHRcdHJlbmRlci5saW5lcyArPSBpbnN0YW5jZUNvdW50ICogKCBjb3VudCAvIDIgKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgZ2wuTElORV9TVFJJUDpcblx0XHRcdFx0cmVuZGVyLmxpbmVzICs9IGluc3RhbmNlQ291bnQgKiAoIGNvdW50IC0gMSApO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSBnbC5MSU5FX0xPT1A6XG5cdFx0XHRcdHJlbmRlci5saW5lcyArPSBpbnN0YW5jZUNvdW50ICogY291bnQ7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlIGdsLlBPSU5UUzpcblx0XHRcdFx0cmVuZGVyLnBvaW50cyArPSBpbnN0YW5jZUNvdW50ICogY291bnQ7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xJbmZvOiBVbmtub3duIGRyYXcgbW9kZTonLCBtb2RlICk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiByZXNldCgpIHtcblxuXHRcdHJlbmRlci5jYWxscyA9IDA7XG5cdFx0cmVuZGVyLnRyaWFuZ2xlcyA9IDA7XG5cdFx0cmVuZGVyLnBvaW50cyA9IDA7XG5cdFx0cmVuZGVyLmxpbmVzID0gMDtcblxuXHR9XG5cblx0cmV0dXJuIHtcblx0XHRtZW1vcnk6IG1lbW9yeSxcblx0XHRyZW5kZXI6IHJlbmRlcixcblx0XHRwcm9ncmFtczogbnVsbCxcblx0XHRhdXRvUmVzZXQ6IHRydWUsXG5cdFx0cmVzZXQ6IHJlc2V0LFxuXHRcdHVwZGF0ZTogdXBkYXRlXG5cdH07XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xNb3JwaHRhcmdldHMoIGdsLCBjYXBhYmlsaXRpZXMsIHRleHR1cmVzICkge1xuXG5cdGNvbnN0IG1vcnBoVGV4dHVyZXMgPSBuZXcgV2Vha01hcCgpO1xuXHRjb25zdCBtb3JwaCA9IG5ldyBWZWN0b3I0KCk7XG5cblx0ZnVuY3Rpb24gdXBkYXRlKCBvYmplY3QsIGdlb21ldHJ5LCBwcm9ncmFtICkge1xuXG5cdFx0Y29uc3Qgb2JqZWN0SW5mbHVlbmNlcyA9IG9iamVjdC5tb3JwaFRhcmdldEluZmx1ZW5jZXM7XG5cblx0XHQvLyB0aGUgZm9sbG93aW5nIGVuY29kZXMgbW9ycGggdGFyZ2V0cyBpbnRvIGFuIGFycmF5IG9mIGRhdGEgdGV4dHVyZXMuIEVhY2ggbGF5ZXIgcmVwcmVzZW50cyBhIHNpbmdsZSBtb3JwaCB0YXJnZXQuXG5cblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiB8fCBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsIHx8IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvcjtcblx0XHRjb25zdCBtb3JwaFRhcmdldHNDb3VudCA9ICggbW9ycGhBdHRyaWJ1dGUgIT09IHVuZGVmaW5lZCApID8gbW9ycGhBdHRyaWJ1dGUubGVuZ3RoIDogMDtcblxuXHRcdGxldCBlbnRyeSA9IG1vcnBoVGV4dHVyZXMuZ2V0KCBnZW9tZXRyeSApO1xuXG5cdFx0aWYgKCBlbnRyeSA9PT0gdW5kZWZpbmVkIHx8IGVudHJ5LmNvdW50ICE9PSBtb3JwaFRhcmdldHNDb3VudCApIHtcblxuXHRcdFx0aWYgKCBlbnRyeSAhPT0gdW5kZWZpbmVkICkgZW50cnkudGV4dHVyZS5kaXNwb3NlKCk7XG5cblx0XHRcdGNvbnN0IGhhc01vcnBoUG9zaXRpb24gPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb24gIT09IHVuZGVmaW5lZDtcblx0XHRcdGNvbnN0IGhhc01vcnBoTm9ybWFscyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5ub3JtYWwgIT09IHVuZGVmaW5lZDtcblx0XHRcdGNvbnN0IGhhc01vcnBoQ29sb3JzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yICE9PSB1bmRlZmluZWQ7XG5cblx0XHRcdGNvbnN0IG1vcnBoVGFyZ2V0cyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiB8fCBbXTtcblx0XHRcdGNvbnN0IG1vcnBoTm9ybWFscyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5ub3JtYWwgfHwgW107XG5cdFx0XHRjb25zdCBtb3JwaENvbG9ycyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvciB8fCBbXTtcblxuXHRcdFx0bGV0IHZlcnRleERhdGFDb3VudCA9IDA7XG5cblx0XHRcdGlmICggaGFzTW9ycGhQb3NpdGlvbiA9PT0gdHJ1ZSApIHZlcnRleERhdGFDb3VudCA9IDE7XG5cdFx0XHRpZiAoIGhhc01vcnBoTm9ybWFscyA9PT0gdHJ1ZSApIHZlcnRleERhdGFDb3VudCA9IDI7XG5cdFx0XHRpZiAoIGhhc01vcnBoQ29sb3JzID09PSB0cnVlICkgdmVydGV4RGF0YUNvdW50ID0gMztcblxuXHRcdFx0bGV0IHdpZHRoID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi5jb3VudCAqIHZlcnRleERhdGFDb3VudDtcblx0XHRcdGxldCBoZWlnaHQgPSAxO1xuXG5cdFx0XHRpZiAoIHdpZHRoID4gY2FwYWJpbGl0aWVzLm1heFRleHR1cmVTaXplICkge1xuXG5cdFx0XHRcdGhlaWdodCA9IE1hdGguY2VpbCggd2lkdGggLyBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemUgKTtcblx0XHRcdFx0d2lkdGggPSBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemU7XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgYnVmZmVyID0gbmV3IEZsb2F0MzJBcnJheSggd2lkdGggKiBoZWlnaHQgKiA0ICogbW9ycGhUYXJnZXRzQ291bnQgKTtcblxuXHRcdFx0Y29uc3QgdGV4dHVyZSA9IG5ldyBEYXRhQXJyYXlUZXh0dXJlKCBidWZmZXIsIHdpZHRoLCBoZWlnaHQsIG1vcnBoVGFyZ2V0c0NvdW50ICk7XG5cdFx0XHR0ZXh0dXJlLnR5cGUgPSBGbG9hdFR5cGU7XG5cdFx0XHR0ZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdFx0Ly8gZmlsbCBidWZmZXJcblxuXHRcdFx0Y29uc3QgdmVydGV4RGF0YVN0cmlkZSA9IHZlcnRleERhdGFDb3VudCAqIDQ7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG1vcnBoVGFyZ2V0c0NvdW50OyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IG1vcnBoVGFyZ2V0ID0gbW9ycGhUYXJnZXRzWyBpIF07XG5cdFx0XHRcdGNvbnN0IG1vcnBoTm9ybWFsID0gbW9ycGhOb3JtYWxzWyBpIF07XG5cdFx0XHRcdGNvbnN0IG1vcnBoQ29sb3IgPSBtb3JwaENvbG9yc1sgaSBdO1xuXG5cdFx0XHRcdGNvbnN0IG9mZnNldCA9IHdpZHRoICogaGVpZ2h0ICogNCAqIGk7XG5cblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgbW9ycGhUYXJnZXQuY291bnQ7IGogKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBzdHJpZGUgPSBqICogdmVydGV4RGF0YVN0cmlkZTtcblxuXHRcdFx0XHRcdGlmICggaGFzTW9ycGhQb3NpdGlvbiA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdFx0bW9ycGguZnJvbUJ1ZmZlckF0dHJpYnV0ZSggbW9ycGhUYXJnZXQsIGogKTtcblxuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAwIF0gPSBtb3JwaC54O1xuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAxIF0gPSBtb3JwaC55O1xuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAyIF0gPSBtb3JwaC56O1xuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAzIF0gPSAwO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCBoYXNNb3JwaE5vcm1hbHMgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRcdG1vcnBoLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoTm9ybWFsLCBqICk7XG5cblx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgNCBdID0gbW9ycGgueDtcblx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgNSBdID0gbW9ycGgueTtcblx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgNiBdID0gbW9ycGguejtcblx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgNyBdID0gMDtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggaGFzTW9ycGhDb2xvcnMgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRcdG1vcnBoLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoQ29sb3IsIGogKTtcblxuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyA4IF0gPSBtb3JwaC54O1xuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyA5IF0gPSBtb3JwaC55O1xuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAxMCBdID0gbW9ycGguejtcblx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgMTEgXSA9ICggbW9ycGhDb2xvci5pdGVtU2l6ZSA9PT0gNCApID8gbW9ycGgudyA6IDE7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGVudHJ5ID0ge1xuXHRcdFx0XHRjb3VudDogbW9ycGhUYXJnZXRzQ291bnQsXG5cdFx0XHRcdHRleHR1cmU6IHRleHR1cmUsXG5cdFx0XHRcdHNpemU6IG5ldyBWZWN0b3IyKCB3aWR0aCwgaGVpZ2h0IClcblx0XHRcdH07XG5cblx0XHRcdG1vcnBoVGV4dHVyZXMuc2V0KCBnZW9tZXRyeSwgZW50cnkgKTtcblxuXHRcdFx0ZnVuY3Rpb24gZGlzcG9zZVRleHR1cmUoKSB7XG5cblx0XHRcdFx0dGV4dHVyZS5kaXNwb3NlKCk7XG5cblx0XHRcdFx0bW9ycGhUZXh0dXJlcy5kZWxldGUoIGdlb21ldHJ5ICk7XG5cblx0XHRcdFx0Z2VvbWV0cnkucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBkaXNwb3NlVGV4dHVyZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGdlb21ldHJ5LmFkZEV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgZGlzcG9zZVRleHR1cmUgKTtcblxuXHRcdH1cblxuXHRcdC8vXG5cdFx0aWYgKCBvYmplY3QuaXNJbnN0YW5jZWRNZXNoID09PSB0cnVlICYmIG9iamVjdC5tb3JwaFRleHR1cmUgIT09IG51bGwgKSB7XG5cblx0XHRcdHByb2dyYW0uZ2V0VW5pZm9ybXMoKS5zZXRWYWx1ZSggZ2wsICdtb3JwaFRleHR1cmUnLCBvYmplY3QubW9ycGhUZXh0dXJlLCB0ZXh0dXJlcyApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0bGV0IG1vcnBoSW5mbHVlbmNlc1N1bSA9IDA7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG9iamVjdEluZmx1ZW5jZXMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdG1vcnBoSW5mbHVlbmNlc1N1bSArPSBvYmplY3RJbmZsdWVuY2VzWyBpIF07XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgbW9ycGhCYXNlSW5mbHVlbmNlID0gZ2VvbWV0cnkubW9ycGhUYXJnZXRzUmVsYXRpdmUgPyAxIDogMSAtIG1vcnBoSW5mbHVlbmNlc1N1bTtcblxuXG5cdFx0XHRwcm9ncmFtLmdldFVuaWZvcm1zKCkuc2V0VmFsdWUoIGdsLCAnbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlJywgbW9ycGhCYXNlSW5mbHVlbmNlICk7XG5cdFx0XHRwcm9ncmFtLmdldFVuaWZvcm1zKCkuc2V0VmFsdWUoIGdsLCAnbW9ycGhUYXJnZXRJbmZsdWVuY2VzJywgb2JqZWN0SW5mbHVlbmNlcyApO1xuXG5cdFx0fVxuXG5cdFx0cHJvZ3JhbS5nZXRVbmlmb3JtcygpLnNldFZhbHVlKCBnbCwgJ21vcnBoVGFyZ2V0c1RleHR1cmUnLCBlbnRyeS50ZXh0dXJlLCB0ZXh0dXJlcyApO1xuXHRcdHByb2dyYW0uZ2V0VW5pZm9ybXMoKS5zZXRWYWx1ZSggZ2wsICdtb3JwaFRhcmdldHNUZXh0dXJlU2l6ZScsIGVudHJ5LnNpemUgKTtcblxuXHR9XG5cblx0cmV0dXJuIHtcblxuXHRcdHVwZGF0ZTogdXBkYXRlXG5cblx0fTtcblxufVxuXG5mdW5jdGlvbiBXZWJHTE9iamVjdHMoIGdsLCBnZW9tZXRyaWVzLCBhdHRyaWJ1dGVzLCBpbmZvICkge1xuXG5cdGxldCB1cGRhdGVNYXAgPSBuZXcgV2Vha01hcCgpO1xuXG5cdGZ1bmN0aW9uIHVwZGF0ZSggb2JqZWN0ICkge1xuXG5cdFx0Y29uc3QgZnJhbWUgPSBpbmZvLnJlbmRlci5mcmFtZTtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0Lmdlb21ldHJ5O1xuXHRcdGNvbnN0IGJ1ZmZlcmdlb21ldHJ5ID0gZ2VvbWV0cmllcy5nZXQoIG9iamVjdCwgZ2VvbWV0cnkgKTtcblxuXHRcdC8vIFVwZGF0ZSBvbmNlIHBlciBmcmFtZVxuXG5cdFx0aWYgKCB1cGRhdGVNYXAuZ2V0KCBidWZmZXJnZW9tZXRyeSApICE9PSBmcmFtZSApIHtcblxuXHRcdFx0Z2VvbWV0cmllcy51cGRhdGUoIGJ1ZmZlcmdlb21ldHJ5ICk7XG5cblx0XHRcdHVwZGF0ZU1hcC5zZXQoIGJ1ZmZlcmdlb21ldHJ5LCBmcmFtZSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBvYmplY3QuaXNJbnN0YW5jZWRNZXNoICkge1xuXG5cdFx0XHRpZiAoIG9iamVjdC5oYXNFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uSW5zdGFuY2VkTWVzaERpc3Bvc2UgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0b2JqZWN0LmFkZEV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25JbnN0YW5jZWRNZXNoRGlzcG9zZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdXBkYXRlTWFwLmdldCggb2JqZWN0ICkgIT09IGZyYW1lICkge1xuXG5cdFx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBvYmplY3QuaW5zdGFuY2VNYXRyaXgsIGdsLkFSUkFZX0JVRkZFUiApO1xuXG5cdFx0XHRcdGlmICggb2JqZWN0Lmluc3RhbmNlQ29sb3IgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRhdHRyaWJ1dGVzLnVwZGF0ZSggb2JqZWN0Lmluc3RhbmNlQ29sb3IsIGdsLkFSUkFZX0JVRkZFUiApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHR1cGRhdGVNYXAuc2V0KCBvYmplY3QsIGZyYW1lICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggb2JqZWN0LmlzU2tpbm5lZE1lc2ggKSB7XG5cblx0XHRcdGNvbnN0IHNrZWxldG9uID0gb2JqZWN0LnNrZWxldG9uO1xuXG5cdFx0XHRpZiAoIHVwZGF0ZU1hcC5nZXQoIHNrZWxldG9uICkgIT09IGZyYW1lICkge1xuXG5cdFx0XHRcdHNrZWxldG9uLnVwZGF0ZSgpO1xuXG5cdFx0XHRcdHVwZGF0ZU1hcC5zZXQoIHNrZWxldG9uLCBmcmFtZSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gYnVmZmVyZ2VvbWV0cnk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG5cblx0XHR1cGRhdGVNYXAgPSBuZXcgV2Vha01hcCgpO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBvbkluc3RhbmNlZE1lc2hEaXNwb3NlKCBldmVudCApIHtcblxuXHRcdGNvbnN0IGluc3RhbmNlZE1lc2ggPSBldmVudC50YXJnZXQ7XG5cblx0XHRpbnN0YW5jZWRNZXNoLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25JbnN0YW5jZWRNZXNoRGlzcG9zZSApO1xuXG5cdFx0YXR0cmlidXRlcy5yZW1vdmUoIGluc3RhbmNlZE1lc2guaW5zdGFuY2VNYXRyaXggKTtcblxuXHRcdGlmICggaW5zdGFuY2VkTWVzaC5pbnN0YW5jZUNvbG9yICE9PSBudWxsICkgYXR0cmlidXRlcy5yZW1vdmUoIGluc3RhbmNlZE1lc2guaW5zdGFuY2VDb2xvciApO1xuXG5cdH1cblxuXHRyZXR1cm4ge1xuXG5cdFx0dXBkYXRlOiB1cGRhdGUsXG5cdFx0ZGlzcG9zZTogZGlzcG9zZVxuXG5cdH07XG5cbn1cblxuY2xhc3MgRGVwdGhUZXh0dXJlIGV4dGVuZHMgVGV4dHVyZSB7XG5cblx0Y29uc3RydWN0b3IoIHdpZHRoLCBoZWlnaHQsIHR5cGUsIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGFuaXNvdHJvcHksIGZvcm1hdCA9IERlcHRoRm9ybWF0ICkge1xuXG5cdFx0aWYgKCBmb3JtYXQgIT09IERlcHRoRm9ybWF0ICYmIGZvcm1hdCAhPT0gRGVwdGhTdGVuY2lsRm9ybWF0ICkge1xuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdEZXB0aFRleHR1cmUgZm9ybWF0IG11c3QgYmUgZWl0aGVyIFRIUkVFLkRlcHRoRm9ybWF0IG9yIFRIUkVFLkRlcHRoU3RlbmNpbEZvcm1hdCcgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdHlwZSA9PT0gdW5kZWZpbmVkICYmIGZvcm1hdCA9PT0gRGVwdGhGb3JtYXQgKSB0eXBlID0gVW5zaWduZWRJbnRUeXBlO1xuXHRcdGlmICggdHlwZSA9PT0gdW5kZWZpbmVkICYmIGZvcm1hdCA9PT0gRGVwdGhTdGVuY2lsRm9ybWF0ICkgdHlwZSA9IFVuc2lnbmVkSW50MjQ4VHlwZTtcblxuXHRcdHN1cGVyKCBudWxsLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHkgKTtcblxuXHRcdHRoaXMuaXNEZXB0aFRleHR1cmUgPSB0cnVlO1xuXG5cdFx0dGhpcy5pbWFnZSA9IHsgd2lkdGg6IHdpZHRoLCBoZWlnaHQ6IGhlaWdodCB9O1xuXG5cdFx0dGhpcy5tYWdGaWx0ZXIgPSBtYWdGaWx0ZXIgIT09IHVuZGVmaW5lZCA/IG1hZ0ZpbHRlciA6IE5lYXJlc3RGaWx0ZXI7XG5cdFx0dGhpcy5taW5GaWx0ZXIgPSBtaW5GaWx0ZXIgIT09IHVuZGVmaW5lZCA/IG1pbkZpbHRlciA6IE5lYXJlc3RGaWx0ZXI7XG5cblx0XHR0aGlzLmZsaXBZID0gZmFsc2U7XG5cdFx0dGhpcy5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcblxuXHRcdHRoaXMuY29tcGFyZUZ1bmN0aW9uID0gbnVsbDtcblxuXHR9XG5cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuY29tcGFyZUZ1bmN0aW9uID0gc291cmNlLmNvbXBhcmVGdW5jdGlvbjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oIG1ldGEgKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCBtZXRhICk7XG5cblx0XHRpZiAoIHRoaXMuY29tcGFyZUZ1bmN0aW9uICE9PSBudWxsICkgZGF0YS5jb21wYXJlRnVuY3Rpb24gPSB0aGlzLmNvbXBhcmVGdW5jdGlvbjtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxufVxuXG4vKipcbiAqIFVuaWZvcm1zIG9mIGEgcHJvZ3JhbS5cbiAqIFRob3NlIGZvcm0gYSB0cmVlIHN0cnVjdHVyZSB3aXRoIGEgc3BlY2lhbCB0b3AtbGV2ZWwgY29udGFpbmVyIGZvciB0aGUgcm9vdCxcbiAqIHdoaWNoIHlvdSBnZXQgYnkgY2FsbGluZyAnbmV3IFdlYkdMVW5pZm9ybXMoIGdsLCBwcm9ncmFtICknLlxuICpcbiAqXG4gKiBQcm9wZXJ0aWVzIG9mIGlubmVyIG5vZGVzIGluY2x1ZGluZyB0aGUgdG9wLWxldmVsIGNvbnRhaW5lcjpcbiAqXG4gKiAuc2VxIC0gYXJyYXkgb2YgbmVzdGVkIHVuaWZvcm1zXG4gKiAubWFwIC0gbmVzdGVkIHVuaWZvcm1zIGJ5IG5hbWVcbiAqXG4gKlxuICogTWV0aG9kcyBvZiBhbGwgbm9kZXMgZXhjZXB0IHRoZSB0b3AtbGV2ZWwgY29udGFpbmVyOlxuICpcbiAqIC5zZXRWYWx1ZSggZ2wsIHZhbHVlLCBbdGV4dHVyZXNdIClcbiAqXG4gKiBcdFx0dXBsb2FkcyBhIHVuaWZvcm0gdmFsdWUocylcbiAqICBcdHRoZSAndGV4dHVyZXMnIHBhcmFtZXRlciBpcyBuZWVkZWQgZm9yIHNhbXBsZXIgdW5pZm9ybXNcbiAqXG4gKlxuICogU3RhdGljIG1ldGhvZHMgb2YgdGhlIHRvcC1sZXZlbCBjb250YWluZXIgKHRleHR1cmVzIGZhY3Rvcml6YXRpb25zKTpcbiAqXG4gKiAudXBsb2FkKCBnbCwgc2VxLCB2YWx1ZXMsIHRleHR1cmVzIClcbiAqXG4gKiBcdFx0c2V0cyB1bmlmb3JtcyBpbiAnc2VxJyB0byAndmFsdWVzW2lkXS52YWx1ZSdcbiAqXG4gKiAuc2VxV2l0aFZhbHVlKCBzZXEsIHZhbHVlcyApIDogZmlsdGVyZWRTZXFcbiAqXG4gKiBcdFx0ZmlsdGVycyAnc2VxJyBlbnRyaWVzIHdpdGggY29ycmVzcG9uZGluZyBlbnRyeSBpbiB2YWx1ZXNcbiAqXG4gKlxuICogTWV0aG9kcyBvZiB0aGUgdG9wLWxldmVsIGNvbnRhaW5lciAodGV4dHVyZXMgZmFjdG9yaXphdGlvbnMpOlxuICpcbiAqIC5zZXRWYWx1ZSggZ2wsIG5hbWUsIHZhbHVlLCB0ZXh0dXJlcyApXG4gKlxuICogXHRcdHNldHMgdW5pZm9ybSB3aXRoICBuYW1lICduYW1lJyB0byAndmFsdWUnXG4gKlxuICogLnNldE9wdGlvbmFsKCBnbCwgb2JqLCBwcm9wIClcbiAqXG4gKiBcdFx0bGlrZSAuc2V0IGZvciBhbiBvcHRpb25hbCBwcm9wZXJ0eSBvZiB0aGUgb2JqZWN0XG4gKlxuICovXG5cblxuY29uc3QgZW1wdHlUZXh0dXJlID0gLypAX19QVVJFX18qLyBuZXcgVGV4dHVyZSgpO1xuXG5jb25zdCBlbXB0eVNoYWRvd1RleHR1cmUgPSAvKkBfX1BVUkVfXyovIG5ldyBEZXB0aFRleHR1cmUoIDEsIDEgKTtcblxuY29uc3QgZW1wdHlBcnJheVRleHR1cmUgPSAvKkBfX1BVUkVfXyovIG5ldyBEYXRhQXJyYXlUZXh0dXJlKCk7XG5jb25zdCBlbXB0eTNkVGV4dHVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IERhdGEzRFRleHR1cmUoKTtcbmNvbnN0IGVtcHR5Q3ViZVRleHR1cmUgPSAvKkBfX1BVUkVfXyovIG5ldyBDdWJlVGV4dHVyZSgpO1xuXG4vLyAtLS0gVXRpbGl0aWVzIC0tLVxuXG4vLyBBcnJheSBDYWNoZXMgKHByb3ZpZGUgdHlwZWQgYXJyYXlzIGZvciB0ZW1wb3JhcnkgYnkgc2l6ZSlcblxuY29uc3QgYXJyYXlDYWNoZUYzMiA9IFtdO1xuY29uc3QgYXJyYXlDYWNoZUkzMiA9IFtdO1xuXG4vLyBGbG9hdDMyQXJyYXkgY2FjaGVzIHVzZWQgZm9yIHVwbG9hZGluZyBNYXRyaXggdW5pZm9ybXNcblxuY29uc3QgbWF0NGFycmF5ID0gbmV3IEZsb2F0MzJBcnJheSggMTYgKTtcbmNvbnN0IG1hdDNhcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoIDkgKTtcbmNvbnN0IG1hdDJhcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoIDQgKTtcblxuLy8gRmxhdHRlbmluZyBmb3IgYXJyYXlzIG9mIHZlY3RvcnMgYW5kIG1hdHJpY2VzXG5cbmZ1bmN0aW9uIGZsYXR0ZW4oIGFycmF5LCBuQmxvY2tzLCBibG9ja1NpemUgKSB7XG5cblx0Y29uc3QgZmlyc3RFbGVtID0gYXJyYXlbIDAgXTtcblxuXHRpZiAoIGZpcnN0RWxlbSA8PSAwIHx8IGZpcnN0RWxlbSA+IDAgKSByZXR1cm4gYXJyYXk7XG5cdC8vIHVub3B0aW1pemVkOiAhIGlzTmFOKCBmaXJzdEVsZW0gKVxuXHQvLyBzZWUgaHR0cDovL2phY2tzb25kdW5zdGFuLmNvbS9hcnRpY2xlcy85ODNcblxuXHRjb25zdCBuID0gbkJsb2NrcyAqIGJsb2NrU2l6ZTtcblx0bGV0IHIgPSBhcnJheUNhY2hlRjMyWyBuIF07XG5cblx0aWYgKCByID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRyID0gbmV3IEZsb2F0MzJBcnJheSggbiApO1xuXHRcdGFycmF5Q2FjaGVGMzJbIG4gXSA9IHI7XG5cblx0fVxuXG5cdGlmICggbkJsb2NrcyAhPT0gMCApIHtcblxuXHRcdGZpcnN0RWxlbS50b0FycmF5KCByLCAwICk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDEsIG9mZnNldCA9IDA7IGkgIT09IG5CbG9ja3M7ICsrIGkgKSB7XG5cblx0XHRcdG9mZnNldCArPSBibG9ja1NpemU7XG5cdFx0XHRhcnJheVsgaSBdLnRvQXJyYXkoIHIsIG9mZnNldCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4gcjtcblxufVxuXG5mdW5jdGlvbiBhcnJheXNFcXVhbCggYSwgYiApIHtcblxuXHRpZiAoIGEubGVuZ3RoICE9PSBiLmxlbmd0aCApIHJldHVybiBmYWxzZTtcblxuXHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBhLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRpZiAoIGFbIGkgXSAhPT0gYlsgaSBdICkgcmV0dXJuIGZhbHNlO1xuXG5cdH1cblxuXHRyZXR1cm4gdHJ1ZTtcblxufVxuXG5mdW5jdGlvbiBjb3B5QXJyYXkoIGEsIGIgKSB7XG5cblx0Zm9yICggbGV0IGkgPSAwLCBsID0gYi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0YVsgaSBdID0gYlsgaSBdO1xuXG5cdH1cblxufVxuXG4vLyBUZXh0dXJlIHVuaXQgYWxsb2NhdGlvblxuXG5mdW5jdGlvbiBhbGxvY1RleFVuaXRzKCB0ZXh0dXJlcywgbiApIHtcblxuXHRsZXQgciA9IGFycmF5Q2FjaGVJMzJbIG4gXTtcblxuXHRpZiAoIHIgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdHIgPSBuZXcgSW50MzJBcnJheSggbiApO1xuXHRcdGFycmF5Q2FjaGVJMzJbIG4gXSA9IHI7XG5cblx0fVxuXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdHJbIGkgXSA9IHRleHR1cmVzLmFsbG9jYXRlVGV4dHVyZVVuaXQoKTtcblxuXHR9XG5cblx0cmV0dXJuIHI7XG5cbn1cblxuLy8gLS0tIFNldHRlcnMgLS0tXG5cbi8vIE5vdGU6IERlZmluaW5nIHRoZXNlIG1ldGhvZHMgZXh0ZXJuYWxseSwgYmVjYXVzZSB0aGV5IGNvbWUgaW4gYSBidW5jaFxuLy8gYW5kIHRoaXMgd2F5IHRoZWlyIG5hbWVzIG1pbmlmeS5cblxuLy8gU2luZ2xlIHNjYWxhclxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYxZiggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGlmICggY2FjaGVbIDAgXSA9PT0gdiApIHJldHVybjtcblxuXHRnbC51bmlmb3JtMWYoIHRoaXMuYWRkciwgdiApO1xuXG5cdGNhY2hlWyAwIF0gPSB2O1xuXG59XG5cbi8vIFNpbmdsZSBmbG9hdCB2ZWN0b3IgKGZyb20gZmxhdCBhcnJheSBvciBUSFJFRS5WZWN0b3JOKVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYyZiggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRpZiAoIGNhY2hlWyAwIF0gIT09IHYueCB8fCBjYWNoZVsgMSBdICE9PSB2LnkgKSB7XG5cblx0XHRcdGdsLnVuaWZvcm0yZiggdGhpcy5hZGRyLCB2LngsIHYueSApO1xuXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcblxuXHRcdH1cblxuXHR9IGVsc2Uge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcblxuXHRcdGdsLnVuaWZvcm0yZnYoIHRoaXMuYWRkciwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYzZiggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRpZiAoIGNhY2hlWyAwIF0gIT09IHYueCB8fCBjYWNoZVsgMSBdICE9PSB2LnkgfHwgY2FjaGVbIDIgXSAhPT0gdi56ICkge1xuXG5cdFx0XHRnbC51bmlmb3JtM2YoIHRoaXMuYWRkciwgdi54LCB2LnksIHYueiApO1xuXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcblx0XHRcdGNhY2hlWyAyIF0gPSB2Lno7XG5cblx0XHR9XG5cblx0fSBlbHNlIGlmICggdi5yICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRpZiAoIGNhY2hlWyAwIF0gIT09IHYuciB8fCBjYWNoZVsgMSBdICE9PSB2LmcgfHwgY2FjaGVbIDIgXSAhPT0gdi5iICkge1xuXG5cdFx0XHRnbC51bmlmb3JtM2YoIHRoaXMuYWRkciwgdi5yLCB2LmcsIHYuYiApO1xuXG5cdFx0XHRjYWNoZVsgMCBdID0gdi5yO1xuXHRcdFx0Y2FjaGVbIDEgXSA9IHYuZztcblx0XHRcdGNhY2hlWyAyIF0gPSB2LmI7XG5cblx0XHR9XG5cblx0fSBlbHNlIHtcblxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XG5cblx0XHRnbC51bmlmb3JtM2Z2KCB0aGlzLmFkZHIsIHYgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gc2V0VmFsdWVWNGYoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55IHx8IGNhY2hlWyAyIF0gIT09IHYueiB8fCBjYWNoZVsgMyBdICE9PSB2LncgKSB7XG5cblx0XHRcdGdsLnVuaWZvcm00ZiggdGhpcy5hZGRyLCB2LngsIHYueSwgdi56LCB2LncgKTtcblxuXHRcdFx0Y2FjaGVbIDAgXSA9IHYueDtcblx0XHRcdGNhY2hlWyAxIF0gPSB2Lnk7XG5cdFx0XHRjYWNoZVsgMiBdID0gdi56O1xuXHRcdFx0Y2FjaGVbIDMgXSA9IHYudztcblxuXHRcdH1cblxuXHR9IGVsc2Uge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcblxuXHRcdGdsLnVuaWZvcm00ZnYoIHRoaXMuYWRkciwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH1cblxufVxuXG4vLyBTaW5nbGUgbWF0cml4IChmcm9tIGZsYXQgYXJyYXkgb3IgVEhSRUUuTWF0cml4TilcblxuZnVuY3Rpb24gc2V0VmFsdWVNMiggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXHRjb25zdCBlbGVtZW50cyA9IHYuZWxlbWVudHM7XG5cblx0aWYgKCBlbGVtZW50cyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcblxuXHRcdGdsLnVuaWZvcm1NYXRyaXgyZnYoIHRoaXMuYWRkciwgZmFsc2UsIHYgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcblxuXHR9IGVsc2Uge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIGVsZW1lbnRzICkgKSByZXR1cm47XG5cblx0XHRtYXQyYXJyYXkuc2V0KCBlbGVtZW50cyApO1xuXG5cdFx0Z2wudW5pZm9ybU1hdHJpeDJmdiggdGhpcy5hZGRyLCBmYWxzZSwgbWF0MmFycmF5ICk7XG5cblx0XHRjb3B5QXJyYXkoIGNhY2hlLCBlbGVtZW50cyApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZU0zKCBnbCwgdiApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cdGNvbnN0IGVsZW1lbnRzID0gdi5lbGVtZW50cztcblxuXHRpZiAoIGVsZW1lbnRzID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xuXG5cdFx0Z2wudW5pZm9ybU1hdHJpeDNmdiggdGhpcy5hZGRyLCBmYWxzZSwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgZWxlbWVudHMgKSApIHJldHVybjtcblxuXHRcdG1hdDNhcnJheS5zZXQoIGVsZW1lbnRzICk7XG5cblx0XHRnbC51bmlmb3JtTWF0cml4M2Z2KCB0aGlzLmFkZHIsIGZhbHNlLCBtYXQzYXJyYXkgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIGVsZW1lbnRzICk7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlTTQoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblx0Y29uc3QgZWxlbWVudHMgPSB2LmVsZW1lbnRzO1xuXG5cdGlmICggZWxlbWVudHMgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XG5cblx0XHRnbC51bmlmb3JtTWF0cml4NGZ2KCB0aGlzLmFkZHIsIGZhbHNlLCB2ICk7XG5cblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XG5cblx0fSBlbHNlIHtcblxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCBlbGVtZW50cyApICkgcmV0dXJuO1xuXG5cdFx0bWF0NGFycmF5LnNldCggZWxlbWVudHMgKTtcblxuXHRcdGdsLnVuaWZvcm1NYXRyaXg0ZnYoIHRoaXMuYWRkciwgZmFsc2UsIG1hdDRhcnJheSApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgZWxlbWVudHMgKTtcblxuXHR9XG5cbn1cblxuLy8gU2luZ2xlIGludGVnZXIgLyBib29sZWFuXG5cbmZ1bmN0aW9uIHNldFZhbHVlVjFpKCBnbCwgdiApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cblx0aWYgKCBjYWNoZVsgMCBdID09PSB2ICkgcmV0dXJuO1xuXG5cdGdsLnVuaWZvcm0xaSggdGhpcy5hZGRyLCB2ICk7XG5cblx0Y2FjaGVbIDAgXSA9IHY7XG5cbn1cblxuLy8gU2luZ2xlIGludGVnZXIgLyBib29sZWFuIHZlY3RvciAoZnJvbSBmbGF0IGFycmF5IG9yIFRIUkVFLlZlY3Rvck4pXG5cbmZ1bmN0aW9uIHNldFZhbHVlVjJpKCBnbCwgdiApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cblx0aWYgKCB2LnggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSApIHtcblxuXHRcdFx0Z2wudW5pZm9ybTJpKCB0aGlzLmFkZHIsIHYueCwgdi55ICk7XG5cblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xuXG5cdFx0fVxuXG5cdH0gZWxzZSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xuXG5cdFx0Z2wudW5pZm9ybTJpdiggdGhpcy5hZGRyLCB2ICk7XG5cblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlVjNpKCBnbCwgdiApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cblx0aWYgKCB2LnggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogKSB7XG5cblx0XHRcdGdsLnVuaWZvcm0zaSggdGhpcy5hZGRyLCB2LngsIHYueSwgdi56ICk7XG5cblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xuXHRcdFx0Y2FjaGVbIDIgXSA9IHYuejtcblxuXHRcdH1cblxuXHR9IGVsc2Uge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcblxuXHRcdGdsLnVuaWZvcm0zaXYoIHRoaXMuYWRkciwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVY0aSggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRpZiAoIGNhY2hlWyAwIF0gIT09IHYueCB8fCBjYWNoZVsgMSBdICE9PSB2LnkgfHwgY2FjaGVbIDIgXSAhPT0gdi56IHx8IGNhY2hlWyAzIF0gIT09IHYudyApIHtcblxuXHRcdFx0Z2wudW5pZm9ybTRpKCB0aGlzLmFkZHIsIHYueCwgdi55LCB2LnosIHYudyApO1xuXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcblx0XHRcdGNhY2hlWyAyIF0gPSB2Lno7XG5cdFx0XHRjYWNoZVsgMyBdID0gdi53O1xuXG5cdFx0fVxuXG5cdH0gZWxzZSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xuXG5cdFx0Z2wudW5pZm9ybTRpdiggdGhpcy5hZGRyLCB2ICk7XG5cblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XG5cblx0fVxuXG59XG5cbi8vIFNpbmdsZSB1bnNpZ25lZCBpbnRlZ2VyXG5cbmZ1bmN0aW9uIHNldFZhbHVlVjF1aSggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGlmICggY2FjaGVbIDAgXSA9PT0gdiApIHJldHVybjtcblxuXHRnbC51bmlmb3JtMXVpKCB0aGlzLmFkZHIsIHYgKTtcblxuXHRjYWNoZVsgMCBdID0gdjtcblxufVxuXG4vLyBTaW5nbGUgdW5zaWduZWQgaW50ZWdlciB2ZWN0b3IgKGZyb20gZmxhdCBhcnJheSBvciBUSFJFRS5WZWN0b3JOKVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYydWkoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55ICkge1xuXG5cdFx0XHRnbC51bmlmb3JtMnVpKCB0aGlzLmFkZHIsIHYueCwgdi55ICk7XG5cblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xuXG5cdFx0fVxuXG5cdH0gZWxzZSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xuXG5cdFx0Z2wudW5pZm9ybTJ1aXYoIHRoaXMuYWRkciwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYzdWkoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55IHx8IGNhY2hlWyAyIF0gIT09IHYueiApIHtcblxuXHRcdFx0Z2wudW5pZm9ybTN1aSggdGhpcy5hZGRyLCB2LngsIHYueSwgdi56ICk7XG5cblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xuXHRcdFx0Y2FjaGVbIDIgXSA9IHYuejtcblxuXHRcdH1cblxuXHR9IGVsc2Uge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcblxuXHRcdGdsLnVuaWZvcm0zdWl2KCB0aGlzLmFkZHIsIHYgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gc2V0VmFsdWVWNHVpKCBnbCwgdiApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cblx0aWYgKCB2LnggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogfHwgY2FjaGVbIDMgXSAhPT0gdi53ICkge1xuXG5cdFx0XHRnbC51bmlmb3JtNHVpKCB0aGlzLmFkZHIsIHYueCwgdi55LCB2LnosIHYudyApO1xuXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcblx0XHRcdGNhY2hlWyAyIF0gPSB2Lno7XG5cdFx0XHRjYWNoZVsgMyBdID0gdi53O1xuXG5cdFx0fVxuXG5cdH0gZWxzZSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xuXG5cdFx0Z2wudW5pZm9ybTR1aXYoIHRoaXMuYWRkciwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH1cblxufVxuXG5cbi8vIFNpbmdsZSB0ZXh0dXJlICgyRCAvIEN1YmUpXG5cbmZ1bmN0aW9uIHNldFZhbHVlVDEoIGdsLCB2LCB0ZXh0dXJlcyApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cdGNvbnN0IHVuaXQgPSB0ZXh0dXJlcy5hbGxvY2F0ZVRleHR1cmVVbml0KCk7XG5cblx0aWYgKCBjYWNoZVsgMCBdICE9PSB1bml0ICkge1xuXG5cdFx0Z2wudW5pZm9ybTFpKCB0aGlzLmFkZHIsIHVuaXQgKTtcblx0XHRjYWNoZVsgMCBdID0gdW5pdDtcblxuXHR9XG5cblx0bGV0IGVtcHR5VGV4dHVyZTJEO1xuXG5cdGlmICggdGhpcy50eXBlID09PSBnbC5TQU1QTEVSXzJEX1NIQURPVyApIHtcblxuXHRcdGVtcHR5U2hhZG93VGV4dHVyZS5jb21wYXJlRnVuY3Rpb24gPSBMZXNzRXF1YWxDb21wYXJlOyAvLyAjMjg2NzBcblx0XHRlbXB0eVRleHR1cmUyRCA9IGVtcHR5U2hhZG93VGV4dHVyZTtcblxuXHR9IGVsc2Uge1xuXG5cdFx0ZW1wdHlUZXh0dXJlMkQgPSBlbXB0eVRleHR1cmU7XG5cblx0fVxuXG5cdHRleHR1cmVzLnNldFRleHR1cmUyRCggdiB8fCBlbXB0eVRleHR1cmUyRCwgdW5pdCApO1xuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlVDNEMSggZ2wsIHYsIHRleHR1cmVzICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblx0Y29uc3QgdW5pdCA9IHRleHR1cmVzLmFsbG9jYXRlVGV4dHVyZVVuaXQoKTtcblxuXHRpZiAoIGNhY2hlWyAwIF0gIT09IHVuaXQgKSB7XG5cblx0XHRnbC51bmlmb3JtMWkoIHRoaXMuYWRkciwgdW5pdCApO1xuXHRcdGNhY2hlWyAwIF0gPSB1bml0O1xuXG5cdH1cblxuXHR0ZXh0dXJlcy5zZXRUZXh0dXJlM0QoIHYgfHwgZW1wdHkzZFRleHR1cmUsIHVuaXQgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVQ2KCBnbCwgdiwgdGV4dHVyZXMgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXHRjb25zdCB1bml0ID0gdGV4dHVyZXMuYWxsb2NhdGVUZXh0dXJlVW5pdCgpO1xuXG5cdGlmICggY2FjaGVbIDAgXSAhPT0gdW5pdCApIHtcblxuXHRcdGdsLnVuaWZvcm0xaSggdGhpcy5hZGRyLCB1bml0ICk7XG5cdFx0Y2FjaGVbIDAgXSA9IHVuaXQ7XG5cblx0fVxuXG5cdHRleHR1cmVzLnNldFRleHR1cmVDdWJlKCB2IHx8IGVtcHR5Q3ViZVRleHR1cmUsIHVuaXQgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVQyREFycmF5MSggZ2wsIHYsIHRleHR1cmVzICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblx0Y29uc3QgdW5pdCA9IHRleHR1cmVzLmFsbG9jYXRlVGV4dHVyZVVuaXQoKTtcblxuXHRpZiAoIGNhY2hlWyAwIF0gIT09IHVuaXQgKSB7XG5cblx0XHRnbC51bmlmb3JtMWkoIHRoaXMuYWRkciwgdW5pdCApO1xuXHRcdGNhY2hlWyAwIF0gPSB1bml0O1xuXG5cdH1cblxuXHR0ZXh0dXJlcy5zZXRUZXh0dXJlMkRBcnJheSggdiB8fCBlbXB0eUFycmF5VGV4dHVyZSwgdW5pdCApO1xuXG59XG5cbi8vIEhlbHBlciB0byBwaWNrIHRoZSByaWdodCBzZXR0ZXIgZm9yIHRoZSBzaW5ndWxhciBjYXNlXG5cbmZ1bmN0aW9uIGdldFNpbmd1bGFyU2V0dGVyKCB0eXBlICkge1xuXG5cdHN3aXRjaCAoIHR5cGUgKSB7XG5cblx0XHRjYXNlIDB4MTQwNjogcmV0dXJuIHNldFZhbHVlVjFmOyAvLyBGTE9BVFxuXHRcdGNhc2UgMHg4YjUwOiByZXR1cm4gc2V0VmFsdWVWMmY7IC8vIF9WRUMyXG5cdFx0Y2FzZSAweDhiNTE6IHJldHVybiBzZXRWYWx1ZVYzZjsgLy8gX1ZFQzNcblx0XHRjYXNlIDB4OGI1MjogcmV0dXJuIHNldFZhbHVlVjRmOyAvLyBfVkVDNFxuXG5cdFx0Y2FzZSAweDhiNWE6IHJldHVybiBzZXRWYWx1ZU0yOyAvLyBfTUFUMlxuXHRcdGNhc2UgMHg4YjViOiByZXR1cm4gc2V0VmFsdWVNMzsgLy8gX01BVDNcblx0XHRjYXNlIDB4OGI1YzogcmV0dXJuIHNldFZhbHVlTTQ7IC8vIF9NQVQ0XG5cblx0XHRjYXNlIDB4MTQwNDogY2FzZSAweDhiNTY6IHJldHVybiBzZXRWYWx1ZVYxaTsgLy8gSU5ULCBCT09MXG5cdFx0Y2FzZSAweDhiNTM6IGNhc2UgMHg4YjU3OiByZXR1cm4gc2V0VmFsdWVWMmk7IC8vIF9WRUMyXG5cdFx0Y2FzZSAweDhiNTQ6IGNhc2UgMHg4YjU4OiByZXR1cm4gc2V0VmFsdWVWM2k7IC8vIF9WRUMzXG5cdFx0Y2FzZSAweDhiNTU6IGNhc2UgMHg4YjU5OiByZXR1cm4gc2V0VmFsdWVWNGk7IC8vIF9WRUM0XG5cblx0XHRjYXNlIDB4MTQwNTogcmV0dXJuIHNldFZhbHVlVjF1aTsgLy8gVUlOVFxuXHRcdGNhc2UgMHg4ZGM2OiByZXR1cm4gc2V0VmFsdWVWMnVpOyAvLyBfVkVDMlxuXHRcdGNhc2UgMHg4ZGM3OiByZXR1cm4gc2V0VmFsdWVWM3VpOyAvLyBfVkVDM1xuXHRcdGNhc2UgMHg4ZGM4OiByZXR1cm4gc2V0VmFsdWVWNHVpOyAvLyBfVkVDNFxuXG5cdFx0Y2FzZSAweDhiNWU6IC8vIFNBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGQ2NjogLy8gU0FNUExFUl9FWFRFUk5BTF9PRVNcblx0XHRjYXNlIDB4OGRjYTogLy8gSU5UX1NBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGRkMjogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGI2MjogLy8gU0FNUExFUl8yRF9TSEFET1dcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQxO1xuXG5cdFx0Y2FzZSAweDhiNWY6IC8vIFNBTVBMRVJfM0Rcblx0XHRjYXNlIDB4OGRjYjogLy8gSU5UX1NBTVBMRVJfM0Rcblx0XHRjYXNlIDB4OGRkMzogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfM0Rcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQzRDE7XG5cblx0XHRjYXNlIDB4OGI2MDogLy8gU0FNUExFUl9DVUJFXG5cdFx0Y2FzZSAweDhkY2M6IC8vIElOVF9TQU1QTEVSX0NVQkVcblx0XHRjYXNlIDB4OGRkNDogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfQ1VCRVxuXHRcdGNhc2UgMHg4ZGM1OiAvLyBTQU1QTEVSX0NVQkVfU0hBRE9XXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUNjtcblxuXHRcdGNhc2UgMHg4ZGMxOiAvLyBTQU1QTEVSXzJEX0FSUkFZXG5cdFx0Y2FzZSAweDhkY2Y6IC8vIElOVF9TQU1QTEVSXzJEX0FSUkFZXG5cdFx0Y2FzZSAweDhkZDc6IC8vIFVOU0lHTkVEX0lOVF9TQU1QTEVSXzJEX0FSUkFZXG5cdFx0Y2FzZSAweDhkYzQ6IC8vIFNBTVBMRVJfMkRfQVJSQVlfU0hBRE9XXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUMkRBcnJheTE7XG5cblx0fVxuXG59XG5cblxuLy8gQXJyYXkgb2Ygc2NhbGFyc1xuXG5mdW5jdGlvbiBzZXRWYWx1ZVYxZkFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtMWZ2KCB0aGlzLmFkZHIsIHYgKTtcblxufVxuXG4vLyBBcnJheSBvZiB2ZWN0b3JzIChmcm9tIGZsYXQgYXJyYXkgb3IgYXJyYXkgb2YgVEhSRUUuVmVjdG9yTilcblxuZnVuY3Rpb24gc2V0VmFsdWVWMmZBcnJheSggZ2wsIHYgKSB7XG5cblx0Y29uc3QgZGF0YSA9IGZsYXR0ZW4oIHYsIHRoaXMuc2l6ZSwgMiApO1xuXG5cdGdsLnVuaWZvcm0yZnYoIHRoaXMuYWRkciwgZGF0YSApO1xuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlVjNmQXJyYXkoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGRhdGEgPSBmbGF0dGVuKCB2LCB0aGlzLnNpemUsIDMgKTtcblxuXHRnbC51bmlmb3JtM2Z2KCB0aGlzLmFkZHIsIGRhdGEgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVY0ZkFycmF5KCBnbCwgdiApIHtcblxuXHRjb25zdCBkYXRhID0gZmxhdHRlbiggdiwgdGhpcy5zaXplLCA0ICk7XG5cblx0Z2wudW5pZm9ybTRmdiggdGhpcy5hZGRyLCBkYXRhICk7XG5cbn1cblxuLy8gQXJyYXkgb2YgbWF0cmljZXMgKGZyb20gZmxhdCBhcnJheSBvciBhcnJheSBvZiBUSFJFRS5NYXRyaXhOKVxuXG5mdW5jdGlvbiBzZXRWYWx1ZU0yQXJyYXkoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGRhdGEgPSBmbGF0dGVuKCB2LCB0aGlzLnNpemUsIDQgKTtcblxuXHRnbC51bmlmb3JtTWF0cml4MmZ2KCB0aGlzLmFkZHIsIGZhbHNlLCBkYXRhICk7XG5cbn1cblxuZnVuY3Rpb24gc2V0VmFsdWVNM0FycmF5KCBnbCwgdiApIHtcblxuXHRjb25zdCBkYXRhID0gZmxhdHRlbiggdiwgdGhpcy5zaXplLCA5ICk7XG5cblx0Z2wudW5pZm9ybU1hdHJpeDNmdiggdGhpcy5hZGRyLCBmYWxzZSwgZGF0YSApO1xuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlTTRBcnJheSggZ2wsIHYgKSB7XG5cblx0Y29uc3QgZGF0YSA9IGZsYXR0ZW4oIHYsIHRoaXMuc2l6ZSwgMTYgKTtcblxuXHRnbC51bmlmb3JtTWF0cml4NGZ2KCB0aGlzLmFkZHIsIGZhbHNlLCBkYXRhICk7XG5cbn1cblxuLy8gQXJyYXkgb2YgaW50ZWdlciAvIGJvb2xlYW5cblxuZnVuY3Rpb24gc2V0VmFsdWVWMWlBcnJheSggZ2wsIHYgKSB7XG5cblx0Z2wudW5pZm9ybTFpdiggdGhpcy5hZGRyLCB2ICk7XG5cbn1cblxuLy8gQXJyYXkgb2YgaW50ZWdlciAvIGJvb2xlYW4gdmVjdG9ycyAoZnJvbSBmbGF0IGFycmF5KVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYyaUFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtMml2KCB0aGlzLmFkZHIsIHYgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYzaUFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtM2l2KCB0aGlzLmFkZHIsIHYgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVY0aUFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtNGl2KCB0aGlzLmFkZHIsIHYgKTtcblxufVxuXG4vLyBBcnJheSBvZiB1bnNpZ25lZCBpbnRlZ2VyXG5cbmZ1bmN0aW9uIHNldFZhbHVlVjF1aUFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtMXVpdiggdGhpcy5hZGRyLCB2ICk7XG5cbn1cblxuLy8gQXJyYXkgb2YgdW5zaWduZWQgaW50ZWdlciB2ZWN0b3JzIChmcm9tIGZsYXQgYXJyYXkpXG5cbmZ1bmN0aW9uIHNldFZhbHVlVjJ1aUFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtMnVpdiggdGhpcy5hZGRyLCB2ICk7XG5cbn1cblxuZnVuY3Rpb24gc2V0VmFsdWVWM3VpQXJyYXkoIGdsLCB2ICkge1xuXG5cdGdsLnVuaWZvcm0zdWl2KCB0aGlzLmFkZHIsIHYgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVY0dWlBcnJheSggZ2wsIHYgKSB7XG5cblx0Z2wudW5pZm9ybTR1aXYoIHRoaXMuYWRkciwgdiApO1xuXG59XG5cblxuLy8gQXJyYXkgb2YgdGV4dHVyZXMgKDJEIC8gM0QgLyBDdWJlIC8gMkRBcnJheSlcblxuZnVuY3Rpb24gc2V0VmFsdWVUMUFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGNvbnN0IG4gPSB2Lmxlbmd0aDtcblxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XG5cblx0aWYgKCAhIGFycmF5c0VxdWFsKCBjYWNoZSwgdW5pdHMgKSApIHtcblxuXHRcdGdsLnVuaWZvcm0xaXYoIHRoaXMuYWRkciwgdW5pdHMgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XG5cblx0fVxuXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUyRCggdlsgaSBdIHx8IGVtcHR5VGV4dHVyZSwgdW5pdHNbIGkgXSApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVQzREFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGNvbnN0IG4gPSB2Lmxlbmd0aDtcblxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XG5cblx0aWYgKCAhIGFycmF5c0VxdWFsKCBjYWNoZSwgdW5pdHMgKSApIHtcblxuXHRcdGdsLnVuaWZvcm0xaXYoIHRoaXMuYWRkciwgdW5pdHMgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XG5cblx0fVxuXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUzRCggdlsgaSBdIHx8IGVtcHR5M2RUZXh0dXJlLCB1bml0c1sgaSBdICk7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlVDZBcnJheSggZ2wsIHYsIHRleHR1cmVzICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblxuXHRjb25zdCBuID0gdi5sZW5ndGg7XG5cblx0Y29uc3QgdW5pdHMgPSBhbGxvY1RleFVuaXRzKCB0ZXh0dXJlcywgbiApO1xuXG5cdGlmICggISBhcnJheXNFcXVhbCggY2FjaGUsIHVuaXRzICkgKSB7XG5cblx0XHRnbC51bmlmb3JtMWl2KCB0aGlzLmFkZHIsIHVuaXRzICk7XG5cblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB1bml0cyApO1xuXG5cdH1cblxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlQ3ViZSggdlsgaSBdIHx8IGVtcHR5Q3ViZVRleHR1cmUsIHVuaXRzWyBpIF0gKTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gc2V0VmFsdWVUMkRBcnJheUFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGNvbnN0IG4gPSB2Lmxlbmd0aDtcblxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XG5cblx0aWYgKCAhIGFycmF5c0VxdWFsKCBjYWNoZSwgdW5pdHMgKSApIHtcblxuXHRcdGdsLnVuaWZvcm0xaXYoIHRoaXMuYWRkciwgdW5pdHMgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XG5cblx0fVxuXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUyREFycmF5KCB2WyBpIF0gfHwgZW1wdHlBcnJheVRleHR1cmUsIHVuaXRzWyBpIF0gKTtcblxuXHR9XG5cbn1cblxuXG4vLyBIZWxwZXIgdG8gcGljayB0aGUgcmlnaHQgc2V0dGVyIGZvciBhIHB1cmUgKGJvdHRvbS1sZXZlbCkgYXJyYXlcblxuZnVuY3Rpb24gZ2V0UHVyZUFycmF5U2V0dGVyKCB0eXBlICkge1xuXG5cdHN3aXRjaCAoIHR5cGUgKSB7XG5cblx0XHRjYXNlIDB4MTQwNjogcmV0dXJuIHNldFZhbHVlVjFmQXJyYXk7IC8vIEZMT0FUXG5cdFx0Y2FzZSAweDhiNTA6IHJldHVybiBzZXRWYWx1ZVYyZkFycmF5OyAvLyBfVkVDMlxuXHRcdGNhc2UgMHg4YjUxOiByZXR1cm4gc2V0VmFsdWVWM2ZBcnJheTsgLy8gX1ZFQzNcblx0XHRjYXNlIDB4OGI1MjogcmV0dXJuIHNldFZhbHVlVjRmQXJyYXk7IC8vIF9WRUM0XG5cblx0XHRjYXNlIDB4OGI1YTogcmV0dXJuIHNldFZhbHVlTTJBcnJheTsgLy8gX01BVDJcblx0XHRjYXNlIDB4OGI1YjogcmV0dXJuIHNldFZhbHVlTTNBcnJheTsgLy8gX01BVDNcblx0XHRjYXNlIDB4OGI1YzogcmV0dXJuIHNldFZhbHVlTTRBcnJheTsgLy8gX01BVDRcblxuXHRcdGNhc2UgMHgxNDA0OiBjYXNlIDB4OGI1NjogcmV0dXJuIHNldFZhbHVlVjFpQXJyYXk7IC8vIElOVCwgQk9PTFxuXHRcdGNhc2UgMHg4YjUzOiBjYXNlIDB4OGI1NzogcmV0dXJuIHNldFZhbHVlVjJpQXJyYXk7IC8vIF9WRUMyXG5cdFx0Y2FzZSAweDhiNTQ6IGNhc2UgMHg4YjU4OiByZXR1cm4gc2V0VmFsdWVWM2lBcnJheTsgLy8gX1ZFQzNcblx0XHRjYXNlIDB4OGI1NTogY2FzZSAweDhiNTk6IHJldHVybiBzZXRWYWx1ZVY0aUFycmF5OyAvLyBfVkVDNFxuXG5cdFx0Y2FzZSAweDE0MDU6IHJldHVybiBzZXRWYWx1ZVYxdWlBcnJheTsgLy8gVUlOVFxuXHRcdGNhc2UgMHg4ZGM2OiByZXR1cm4gc2V0VmFsdWVWMnVpQXJyYXk7IC8vIF9WRUMyXG5cdFx0Y2FzZSAweDhkYzc6IHJldHVybiBzZXRWYWx1ZVYzdWlBcnJheTsgLy8gX1ZFQzNcblx0XHRjYXNlIDB4OGRjODogcmV0dXJuIHNldFZhbHVlVjR1aUFycmF5OyAvLyBfVkVDNFxuXG5cdFx0Y2FzZSAweDhiNWU6IC8vIFNBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGQ2NjogLy8gU0FNUExFUl9FWFRFUk5BTF9PRVNcblx0XHRjYXNlIDB4OGRjYTogLy8gSU5UX1NBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGRkMjogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGI2MjogLy8gU0FNUExFUl8yRF9TSEFET1dcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQxQXJyYXk7XG5cblx0XHRjYXNlIDB4OGI1ZjogLy8gU0FNUExFUl8zRFxuXHRcdGNhc2UgMHg4ZGNiOiAvLyBJTlRfU0FNUExFUl8zRFxuXHRcdGNhc2UgMHg4ZGQzOiAvLyBVTlNJR05FRF9JTlRfU0FNUExFUl8zRFxuXHRcdFx0cmV0dXJuIHNldFZhbHVlVDNEQXJyYXk7XG5cblx0XHRjYXNlIDB4OGI2MDogLy8gU0FNUExFUl9DVUJFXG5cdFx0Y2FzZSAweDhkY2M6IC8vIElOVF9TQU1QTEVSX0NVQkVcblx0XHRjYXNlIDB4OGRkNDogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfQ1VCRVxuXHRcdGNhc2UgMHg4ZGM1OiAvLyBTQU1QTEVSX0NVQkVfU0hBRE9XXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUNkFycmF5O1xuXG5cdFx0Y2FzZSAweDhkYzE6IC8vIFNBTVBMRVJfMkRfQVJSQVlcblx0XHRjYXNlIDB4OGRjZjogLy8gSU5UX1NBTVBMRVJfMkRfQVJSQVlcblx0XHRjYXNlIDB4OGRkNzogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfMkRfQVJSQVlcblx0XHRjYXNlIDB4OGRjNDogLy8gU0FNUExFUl8yRF9BUlJBWV9TSEFET1dcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQyREFycmF5QXJyYXk7XG5cblx0fVxuXG59XG5cbi8vIC0tLSBVbmlmb3JtIENsYXNzZXMgLS0tXG5cbmNsYXNzIFNpbmdsZVVuaWZvcm0ge1xuXG5cdGNvbnN0cnVjdG9yKCBpZCwgYWN0aXZlSW5mbywgYWRkciApIHtcblxuXHRcdHRoaXMuaWQgPSBpZDtcblx0XHR0aGlzLmFkZHIgPSBhZGRyO1xuXHRcdHRoaXMuY2FjaGUgPSBbXTtcblx0XHR0aGlzLnR5cGUgPSBhY3RpdmVJbmZvLnR5cGU7XG5cdFx0dGhpcy5zZXRWYWx1ZSA9IGdldFNpbmd1bGFyU2V0dGVyKCBhY3RpdmVJbmZvLnR5cGUgKTtcblxuXHRcdC8vIHRoaXMucGF0aCA9IGFjdGl2ZUluZm8ubmFtZTsgLy8gREVCVUdcblxuXHR9XG5cbn1cblxuY2xhc3MgUHVyZUFycmF5VW5pZm9ybSB7XG5cblx0Y29uc3RydWN0b3IoIGlkLCBhY3RpdmVJbmZvLCBhZGRyICkge1xuXG5cdFx0dGhpcy5pZCA9IGlkO1xuXHRcdHRoaXMuYWRkciA9IGFkZHI7XG5cdFx0dGhpcy5jYWNoZSA9IFtdO1xuXHRcdHRoaXMudHlwZSA9IGFjdGl2ZUluZm8udHlwZTtcblx0XHR0aGlzLnNpemUgPSBhY3RpdmVJbmZvLnNpemU7XG5cdFx0dGhpcy5zZXRWYWx1ZSA9IGdldFB1cmVBcnJheVNldHRlciggYWN0aXZlSW5mby50eXBlICk7XG5cblx0XHQvLyB0aGlzLnBhdGggPSBhY3RpdmVJbmZvLm5hbWU7IC8vIERFQlVHXG5cblx0fVxuXG59XG5cbmNsYXNzIFN0cnVjdHVyZWRVbmlmb3JtIHtcblxuXHRjb25zdHJ1Y3RvciggaWQgKSB7XG5cblx0XHR0aGlzLmlkID0gaWQ7XG5cblx0XHR0aGlzLnNlcSA9IFtdO1xuXHRcdHRoaXMubWFwID0ge307XG5cblx0fVxuXG5cdHNldFZhbHVlKCBnbCwgdmFsdWUsIHRleHR1cmVzICkge1xuXG5cdFx0Y29uc3Qgc2VxID0gdGhpcy5zZXE7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBzZXEubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCB1ID0gc2VxWyBpIF07XG5cdFx0XHR1LnNldFZhbHVlKCBnbCwgdmFsdWVbIHUuaWQgXSwgdGV4dHVyZXMgKTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuLy8gLS0tIFRvcC1sZXZlbCAtLS1cblxuLy8gUGFyc2VyIC0gYnVpbGRzIHVwIHRoZSBwcm9wZXJ0eSB0cmVlIGZyb20gdGhlIHBhdGggc3RyaW5nc1xuXG5jb25zdCBSZVBhdGhQYXJ0ID0gLyhcXHcrKShcXF0pPyhcXFt8XFwuKT8vZztcblxuLy8gZXh0cmFjdHNcbi8vIFx0LSB0aGUgaWRlbnRpZmllciAobWVtYmVyIG5hbWUgb3IgYXJyYXkgaW5kZXgpXG4vLyAgLSBmb2xsb3dlZCBieSBhbiBvcHRpb25hbCByaWdodCBicmFja2V0IChmb3VuZCB3aGVuIGFycmF5IGluZGV4KVxuLy8gIC0gZm9sbG93ZWQgYnkgYW4gb3B0aW9uYWwgbGVmdCBicmFja2V0IG9yIGRvdCAodHlwZSBvZiBzdWJzY3JpcHQpXG4vL1xuLy8gTm90ZTogVGhlc2UgcG9ydGlvbnMgY2FuIGJlIHJlYWQgaW4gYSBub24tb3ZlcmxhcHBpbmcgZmFzaGlvbiBhbmRcbi8vIGFsbG93IHN0cmFpZ2h0Zm9yd2FyZCBwYXJzaW5nIG9mIHRoZSBoaWVyYXJjaHkgdGhhdCBXZWJHTCBlbmNvZGVzXG4vLyBpbiB0aGUgdW5pZm9ybSBuYW1lcy5cblxuZnVuY3Rpb24gYWRkVW5pZm9ybSggY29udGFpbmVyLCB1bmlmb3JtT2JqZWN0ICkge1xuXG5cdGNvbnRhaW5lci5zZXEucHVzaCggdW5pZm9ybU9iamVjdCApO1xuXHRjb250YWluZXIubWFwWyB1bmlmb3JtT2JqZWN0LmlkIF0gPSB1bmlmb3JtT2JqZWN0O1xuXG59XG5cbmZ1bmN0aW9uIHBhcnNlVW5pZm9ybSggYWN0aXZlSW5mbywgYWRkciwgY29udGFpbmVyICkge1xuXG5cdGNvbnN0IHBhdGggPSBhY3RpdmVJbmZvLm5hbWUsXG5cdFx0cGF0aExlbmd0aCA9IHBhdGgubGVuZ3RoO1xuXG5cdC8vIHJlc2V0IFJlZ0V4cCBvYmplY3QsIGJlY2F1c2Ugb2YgdGhlIGVhcmx5IGV4aXQgb2YgYSBwcmV2aW91cyBydW5cblx0UmVQYXRoUGFydC5sYXN0SW5kZXggPSAwO1xuXG5cdHdoaWxlICggdHJ1ZSApIHtcblxuXHRcdGNvbnN0IG1hdGNoID0gUmVQYXRoUGFydC5leGVjKCBwYXRoICksXG5cdFx0XHRtYXRjaEVuZCA9IFJlUGF0aFBhcnQubGFzdEluZGV4O1xuXG5cdFx0bGV0IGlkID0gbWF0Y2hbIDEgXTtcblx0XHRjb25zdCBpZElzSW5kZXggPSBtYXRjaFsgMiBdID09PSAnXScsXG5cdFx0XHRzdWJzY3JpcHQgPSBtYXRjaFsgMyBdO1xuXG5cdFx0aWYgKCBpZElzSW5kZXggKSBpZCA9IGlkIHwgMDsgLy8gY29udmVydCB0byBpbnRlZ2VyXG5cblx0XHRpZiAoIHN1YnNjcmlwdCA9PT0gdW5kZWZpbmVkIHx8IHN1YnNjcmlwdCA9PT0gJ1snICYmIG1hdGNoRW5kICsgMiA9PT0gcGF0aExlbmd0aCApIHtcblxuXHRcdFx0Ly8gYmFyZSBuYW1lIG9yIFwicHVyZVwiIGJvdHRvbS1sZXZlbCBhcnJheSBcIlswXVwiIHN1ZmZpeFxuXG5cdFx0XHRhZGRVbmlmb3JtKCBjb250YWluZXIsIHN1YnNjcmlwdCA9PT0gdW5kZWZpbmVkID9cblx0XHRcdFx0bmV3IFNpbmdsZVVuaWZvcm0oIGlkLCBhY3RpdmVJbmZvLCBhZGRyICkgOlxuXHRcdFx0XHRuZXcgUHVyZUFycmF5VW5pZm9ybSggaWQsIGFjdGl2ZUluZm8sIGFkZHIgKSApO1xuXG5cdFx0XHRicmVhaztcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIHN0ZXAgaW50byBpbm5lciBub2RlIC8gY3JlYXRlIGl0IGluIGNhc2UgaXQgZG9lc24ndCBleGlzdFxuXG5cdFx0XHRjb25zdCBtYXAgPSBjb250YWluZXIubWFwO1xuXHRcdFx0bGV0IG5leHQgPSBtYXBbIGlkIF07XG5cblx0XHRcdGlmICggbmV4dCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdG5leHQgPSBuZXcgU3RydWN0dXJlZFVuaWZvcm0oIGlkICk7XG5cdFx0XHRcdGFkZFVuaWZvcm0oIGNvbnRhaW5lciwgbmV4dCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnRhaW5lciA9IG5leHQ7XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbi8vIFJvb3QgQ29udGFpbmVyXG5cbmNsYXNzIFdlYkdMVW5pZm9ybXMge1xuXG5cdGNvbnN0cnVjdG9yKCBnbCwgcHJvZ3JhbSApIHtcblxuXHRcdHRoaXMuc2VxID0gW107XG5cdFx0dGhpcy5tYXAgPSB7fTtcblxuXHRcdGNvbnN0IG4gPSBnbC5nZXRQcm9ncmFtUGFyYW1ldGVyKCBwcm9ncmFtLCBnbC5BQ1RJVkVfVU5JRk9STVMgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG47ICsrIGkgKSB7XG5cblx0XHRcdGNvbnN0IGluZm8gPSBnbC5nZXRBY3RpdmVVbmlmb3JtKCBwcm9ncmFtLCBpICksXG5cdFx0XHRcdGFkZHIgPSBnbC5nZXRVbmlmb3JtTG9jYXRpb24oIHByb2dyYW0sIGluZm8ubmFtZSApO1xuXG5cdFx0XHRwYXJzZVVuaWZvcm0oIGluZm8sIGFkZHIsIHRoaXMgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0c2V0VmFsdWUoIGdsLCBuYW1lLCB2YWx1ZSwgdGV4dHVyZXMgKSB7XG5cblx0XHRjb25zdCB1ID0gdGhpcy5tYXBbIG5hbWUgXTtcblxuXHRcdGlmICggdSAhPT0gdW5kZWZpbmVkICkgdS5zZXRWYWx1ZSggZ2wsIHZhbHVlLCB0ZXh0dXJlcyApO1xuXG5cdH1cblxuXHRzZXRPcHRpb25hbCggZ2wsIG9iamVjdCwgbmFtZSApIHtcblxuXHRcdGNvbnN0IHYgPSBvYmplY3RbIG5hbWUgXTtcblxuXHRcdGlmICggdiAhPT0gdW5kZWZpbmVkICkgdGhpcy5zZXRWYWx1ZSggZ2wsIG5hbWUsIHYgKTtcblxuXHR9XG5cblx0c3RhdGljIHVwbG9hZCggZ2wsIHNlcSwgdmFsdWVzLCB0ZXh0dXJlcyApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IHNlcS5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdGNvbnN0IHUgPSBzZXFbIGkgXSxcblx0XHRcdFx0diA9IHZhbHVlc1sgdS5pZCBdO1xuXG5cdFx0XHRpZiAoIHYubmVlZHNVcGRhdGUgIT09IGZhbHNlICkge1xuXG5cdFx0XHRcdC8vIG5vdGU6IGFsd2F5cyB1cGRhdGluZyB3aGVuIC5uZWVkc1VwZGF0ZSBpcyB1bmRlZmluZWRcblx0XHRcdFx0dS5zZXRWYWx1ZSggZ2wsIHYudmFsdWUsIHRleHR1cmVzICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0c3RhdGljIHNlcVdpdGhWYWx1ZSggc2VxLCB2YWx1ZXMgKSB7XG5cblx0XHRjb25zdCByID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBzZXEubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCB1ID0gc2VxWyBpIF07XG5cdFx0XHRpZiAoIHUuaWQgaW4gdmFsdWVzICkgci5wdXNoKCB1ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcjtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xTaGFkZXIoIGdsLCB0eXBlLCBzdHJpbmcgKSB7XG5cblx0Y29uc3Qgc2hhZGVyID0gZ2wuY3JlYXRlU2hhZGVyKCB0eXBlICk7XG5cblx0Z2wuc2hhZGVyU291cmNlKCBzaGFkZXIsIHN0cmluZyApO1xuXHRnbC5jb21waWxlU2hhZGVyKCBzaGFkZXIgKTtcblxuXHRyZXR1cm4gc2hhZGVyO1xuXG59XG5cbi8vIEZyb20gaHR0cHM6Ly93d3cua2hyb25vcy5vcmcvcmVnaXN0cnkvd2ViZ2wvZXh0ZW5zaW9ucy9LSFJfcGFyYWxsZWxfc2hhZGVyX2NvbXBpbGUvXG5jb25zdCBDT01QTEVUSU9OX1NUQVRVU19LSFIgPSAweDkxQjE7XG5cbmxldCBwcm9ncmFtSWRDb3VudCA9IDA7XG5cbmZ1bmN0aW9uIGhhbmRsZVNvdXJjZSggc3RyaW5nLCBlcnJvckxpbmUgKSB7XG5cblx0Y29uc3QgbGluZXMgPSBzdHJpbmcuc3BsaXQoICdcXG4nICk7XG5cdGNvbnN0IGxpbmVzMiA9IFtdO1xuXG5cdGNvbnN0IGZyb20gPSBNYXRoLm1heCggZXJyb3JMaW5lIC0gNiwgMCApO1xuXHRjb25zdCB0byA9IE1hdGgubWluKCBlcnJvckxpbmUgKyA2LCBsaW5lcy5sZW5ndGggKTtcblxuXHRmb3IgKCBsZXQgaSA9IGZyb207IGkgPCB0bzsgaSArKyApIHtcblxuXHRcdGNvbnN0IGxpbmUgPSBpICsgMTtcblx0XHRsaW5lczIucHVzaCggYCR7bGluZSA9PT0gZXJyb3JMaW5lID8gJz4nIDogJyAnfSAke2xpbmV9OiAke2xpbmVzWyBpIF19YCApO1xuXG5cdH1cblxuXHRyZXR1cm4gbGluZXMyLmpvaW4oICdcXG4nICk7XG5cbn1cblxuZnVuY3Rpb24gZ2V0RW5jb2RpbmdDb21wb25lbnRzKCBjb2xvclNwYWNlICkge1xuXG5cdGNvbnN0IHdvcmtpbmdQcmltYXJpZXMgPSBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCBDb2xvck1hbmFnZW1lbnQud29ya2luZ0NvbG9yU3BhY2UgKTtcblx0Y29uc3QgZW5jb2RpbmdQcmltYXJpZXMgPSBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCBjb2xvclNwYWNlICk7XG5cblx0bGV0IGdhbXV0TWFwcGluZztcblxuXHRpZiAoIHdvcmtpbmdQcmltYXJpZXMgPT09IGVuY29kaW5nUHJpbWFyaWVzICkge1xuXG5cdFx0Z2FtdXRNYXBwaW5nID0gJyc7XG5cblx0fSBlbHNlIGlmICggd29ya2luZ1ByaW1hcmllcyA9PT0gUDNQcmltYXJpZXMgJiYgZW5jb2RpbmdQcmltYXJpZXMgPT09IFJlYzcwOVByaW1hcmllcyApIHtcblxuXHRcdGdhbXV0TWFwcGluZyA9ICdMaW5lYXJEaXNwbGF5UDNUb0xpbmVhclNSR0InO1xuXG5cdH0gZWxzZSBpZiAoIHdvcmtpbmdQcmltYXJpZXMgPT09IFJlYzcwOVByaW1hcmllcyAmJiBlbmNvZGluZ1ByaW1hcmllcyA9PT0gUDNQcmltYXJpZXMgKSB7XG5cblx0XHRnYW11dE1hcHBpbmcgPSAnTGluZWFyU1JHQlRvTGluZWFyRGlzcGxheVAzJztcblxuXHR9XG5cblx0c3dpdGNoICggY29sb3JTcGFjZSApIHtcblxuXHRcdGNhc2UgTGluZWFyU1JHQkNvbG9yU3BhY2U6XG5cdFx0Y2FzZSBMaW5lYXJEaXNwbGF5UDNDb2xvclNwYWNlOlxuXHRcdFx0cmV0dXJuIFsgZ2FtdXRNYXBwaW5nLCAnTGluZWFyVHJhbnNmZXJPRVRGJyBdO1xuXG5cdFx0Y2FzZSBTUkdCQ29sb3JTcGFjZTpcblx0XHRjYXNlIERpc3BsYXlQM0NvbG9yU3BhY2U6XG5cdFx0XHRyZXR1cm4gWyBnYW11dE1hcHBpbmcsICdzUkdCVHJhbnNmZXJPRVRGJyBdO1xuXG5cdFx0ZGVmYXVsdDpcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUHJvZ3JhbTogVW5zdXBwb3J0ZWQgY29sb3Igc3BhY2U6JywgY29sb3JTcGFjZSApO1xuXHRcdFx0cmV0dXJuIFsgZ2FtdXRNYXBwaW5nLCAnTGluZWFyVHJhbnNmZXJPRVRGJyBdO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBnZXRTaGFkZXJFcnJvcnMoIGdsLCBzaGFkZXIsIHR5cGUgKSB7XG5cblx0Y29uc3Qgc3RhdHVzID0gZ2wuZ2V0U2hhZGVyUGFyYW1ldGVyKCBzaGFkZXIsIGdsLkNPTVBJTEVfU1RBVFVTICk7XG5cdGNvbnN0IGVycm9ycyA9IGdsLmdldFNoYWRlckluZm9Mb2coIHNoYWRlciApLnRyaW0oKTtcblxuXHRpZiAoIHN0YXR1cyAmJiBlcnJvcnMgPT09ICcnICkgcmV0dXJuICcnO1xuXG5cdGNvbnN0IGVycm9yTWF0Y2hlcyA9IC9FUlJPUjogMDooXFxkKykvLmV4ZWMoIGVycm9ycyApO1xuXHRpZiAoIGVycm9yTWF0Y2hlcyApIHtcblxuXHRcdC8vIC0tZW5hYmxlLXByaXZpbGVnZWQtd2ViZ2wtZXh0ZW5zaW9uXG5cdFx0Ly8gY29uc29sZS5sb2coICcqKicgKyB0eXBlICsgJyoqJywgZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCR0xfZGVidWdfc2hhZGVycycgKS5nZXRUcmFuc2xhdGVkU2hhZGVyU291cmNlKCBzaGFkZXIgKSApO1xuXG5cdFx0Y29uc3QgZXJyb3JMaW5lID0gcGFyc2VJbnQoIGVycm9yTWF0Y2hlc1sgMSBdICk7XG5cdFx0cmV0dXJuIHR5cGUudG9VcHBlckNhc2UoKSArICdcXG5cXG4nICsgZXJyb3JzICsgJ1xcblxcbicgKyBoYW5kbGVTb3VyY2UoIGdsLmdldFNoYWRlclNvdXJjZSggc2hhZGVyICksIGVycm9yTGluZSApO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRyZXR1cm4gZXJyb3JzO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBnZXRUZXhlbEVuY29kaW5nRnVuY3Rpb24oIGZ1bmN0aW9uTmFtZSwgY29sb3JTcGFjZSApIHtcblxuXHRjb25zdCBjb21wb25lbnRzID0gZ2V0RW5jb2RpbmdDb21wb25lbnRzKCBjb2xvclNwYWNlICk7XG5cdHJldHVybiBgdmVjNCAke2Z1bmN0aW9uTmFtZX0oIHZlYzQgdmFsdWUgKSB7IHJldHVybiAke2NvbXBvbmVudHNbIDAgXX0oICR7Y29tcG9uZW50c1sgMSBdfSggdmFsdWUgKSApOyB9YDtcblxufVxuXG5mdW5jdGlvbiBnZXRUb25lTWFwcGluZ0Z1bmN0aW9uKCBmdW5jdGlvbk5hbWUsIHRvbmVNYXBwaW5nICkge1xuXG5cdGxldCB0b25lTWFwcGluZ05hbWU7XG5cblx0c3dpdGNoICggdG9uZU1hcHBpbmcgKSB7XG5cblx0XHRjYXNlIExpbmVhclRvbmVNYXBwaW5nOlxuXHRcdFx0dG9uZU1hcHBpbmdOYW1lID0gJ0xpbmVhcic7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgUmVpbmhhcmRUb25lTWFwcGluZzpcblx0XHRcdHRvbmVNYXBwaW5nTmFtZSA9ICdSZWluaGFyZCc7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgQ2luZW9uVG9uZU1hcHBpbmc6XG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnT3B0aW1pemVkQ2luZW9uJztcblx0XHRcdGJyZWFrO1xuXG5cdFx0Y2FzZSBBQ0VTRmlsbWljVG9uZU1hcHBpbmc6XG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnQUNFU0ZpbG1pYyc7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgQWdYVG9uZU1hcHBpbmc6XG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnQWdYJztcblx0XHRcdGJyZWFrO1xuXG5cdFx0Y2FzZSBOZXV0cmFsVG9uZU1hcHBpbmc6XG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnTmV1dHJhbCc7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgQ3VzdG9tVG9uZU1hcHBpbmc6XG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnQ3VzdG9tJztcblx0XHRcdGJyZWFrO1xuXG5cdFx0ZGVmYXVsdDpcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUHJvZ3JhbTogVW5zdXBwb3J0ZWQgdG9uZU1hcHBpbmc6JywgdG9uZU1hcHBpbmcgKTtcblx0XHRcdHRvbmVNYXBwaW5nTmFtZSA9ICdMaW5lYXInO1xuXG5cdH1cblxuXHRyZXR1cm4gJ3ZlYzMgJyArIGZ1bmN0aW9uTmFtZSArICcoIHZlYzMgY29sb3IgKSB7IHJldHVybiAnICsgdG9uZU1hcHBpbmdOYW1lICsgJ1RvbmVNYXBwaW5nKCBjb2xvciApOyB9JztcblxufVxuXG5mdW5jdGlvbiBnZW5lcmF0ZVZlcnRleEV4dGVuc2lvbnMoIHBhcmFtZXRlcnMgKSB7XG5cblx0Y29uc3QgY2h1bmtzID0gW1xuXHRcdHBhcmFtZXRlcnMuZXh0ZW5zaW9uQ2xpcEN1bGxEaXN0YW5jZSA/ICcjZXh0ZW5zaW9uIEdMX0FOR0xFX2NsaXBfY3VsbF9kaXN0YW5jZSA6IHJlcXVpcmUnIDogJycsXG5cdFx0cGFyYW1ldGVycy5leHRlbnNpb25NdWx0aURyYXcgPyAnI2V4dGVuc2lvbiBHTF9BTkdMRV9tdWx0aV9kcmF3IDogcmVxdWlyZScgOiAnJyxcblx0XTtcblxuXHRyZXR1cm4gY2h1bmtzLmZpbHRlciggZmlsdGVyRW1wdHlMaW5lICkuam9pbiggJ1xcbicgKTtcblxufVxuXG5mdW5jdGlvbiBnZW5lcmF0ZURlZmluZXMoIGRlZmluZXMgKSB7XG5cblx0Y29uc3QgY2h1bmtzID0gW107XG5cblx0Zm9yICggY29uc3QgbmFtZSBpbiBkZWZpbmVzICkge1xuXG5cdFx0Y29uc3QgdmFsdWUgPSBkZWZpbmVzWyBuYW1lIF07XG5cblx0XHRpZiAoIHZhbHVlID09PSBmYWxzZSApIGNvbnRpbnVlO1xuXG5cdFx0Y2h1bmtzLnB1c2goICcjZGVmaW5lICcgKyBuYW1lICsgJyAnICsgdmFsdWUgKTtcblxuXHR9XG5cblx0cmV0dXJuIGNodW5rcy5qb2luKCAnXFxuJyApO1xuXG59XG5cbmZ1bmN0aW9uIGZldGNoQXR0cmlidXRlTG9jYXRpb25zKCBnbCwgcHJvZ3JhbSApIHtcblxuXHRjb25zdCBhdHRyaWJ1dGVzID0ge307XG5cblx0Y29uc3QgbiA9IGdsLmdldFByb2dyYW1QYXJhbWV0ZXIoIHByb2dyYW0sIGdsLkFDVElWRV9BVFRSSUJVVEVTICk7XG5cblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbjsgaSArKyApIHtcblxuXHRcdGNvbnN0IGluZm8gPSBnbC5nZXRBY3RpdmVBdHRyaWIoIHByb2dyYW0sIGkgKTtcblx0XHRjb25zdCBuYW1lID0gaW5mby5uYW1lO1xuXG5cdFx0bGV0IGxvY2F0aW9uU2l6ZSA9IDE7XG5cdFx0aWYgKCBpbmZvLnR5cGUgPT09IGdsLkZMT0FUX01BVDIgKSBsb2NhdGlvblNpemUgPSAyO1xuXHRcdGlmICggaW5mby50eXBlID09PSBnbC5GTE9BVF9NQVQzICkgbG9jYXRpb25TaXplID0gMztcblx0XHRpZiAoIGluZm8udHlwZSA9PT0gZ2wuRkxPQVRfTUFUNCApIGxvY2F0aW9uU2l6ZSA9IDQ7XG5cblx0XHQvLyBjb25zb2xlLmxvZyggJ1RIUkVFLldlYkdMUHJvZ3JhbTogQUNUSVZFIFZFUlRFWCBBVFRSSUJVVEU6JywgbmFtZSwgaSApO1xuXG5cdFx0YXR0cmlidXRlc1sgbmFtZSBdID0ge1xuXHRcdFx0dHlwZTogaW5mby50eXBlLFxuXHRcdFx0bG9jYXRpb246IGdsLmdldEF0dHJpYkxvY2F0aW9uKCBwcm9ncmFtLCBuYW1lICksXG5cdFx0XHRsb2NhdGlvblNpemU6IGxvY2F0aW9uU2l6ZVxuXHRcdH07XG5cblx0fVxuXG5cdHJldHVybiBhdHRyaWJ1dGVzO1xuXG59XG5cbmZ1bmN0aW9uIGZpbHRlckVtcHR5TGluZSggc3RyaW5nICkge1xuXG5cdHJldHVybiBzdHJpbmcgIT09ICcnO1xuXG59XG5cbmZ1bmN0aW9uIHJlcGxhY2VMaWdodE51bXMoIHN0cmluZywgcGFyYW1ldGVycyApIHtcblxuXHRjb25zdCBudW1TcG90TGlnaHRDb29yZHMgPSBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodFNoYWRvd3MgKyBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodE1hcHMgLSBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodFNoYWRvd3NXaXRoTWFwcztcblxuXHRyZXR1cm4gc3RyaW5nXG5cdFx0LnJlcGxhY2UoIC9OVU1fRElSX0xJR0hUUy9nLCBwYXJhbWV0ZXJzLm51bURpckxpZ2h0cyApXG5cdFx0LnJlcGxhY2UoIC9OVU1fU1BPVF9MSUdIVFMvZywgcGFyYW1ldGVycy5udW1TcG90TGlnaHRzIClcblx0XHQucmVwbGFjZSggL05VTV9TUE9UX0xJR0hUX01BUFMvZywgcGFyYW1ldGVycy5udW1TcG90TGlnaHRNYXBzIClcblx0XHQucmVwbGFjZSggL05VTV9TUE9UX0xJR0hUX0NPT1JEUy9nLCBudW1TcG90TGlnaHRDb29yZHMgKVxuXHRcdC5yZXBsYWNlKCAvTlVNX1JFQ1RfQVJFQV9MSUdIVFMvZywgcGFyYW1ldGVycy5udW1SZWN0QXJlYUxpZ2h0cyApXG5cdFx0LnJlcGxhY2UoIC9OVU1fUE9JTlRfTElHSFRTL2csIHBhcmFtZXRlcnMubnVtUG9pbnRMaWdodHMgKVxuXHRcdC5yZXBsYWNlKCAvTlVNX0hFTUlfTElHSFRTL2csIHBhcmFtZXRlcnMubnVtSGVtaUxpZ2h0cyApXG5cdFx0LnJlcGxhY2UoIC9OVU1fRElSX0xJR0hUX1NIQURPV1MvZywgcGFyYW1ldGVycy5udW1EaXJMaWdodFNoYWRvd3MgKVxuXHRcdC5yZXBsYWNlKCAvTlVNX1NQT1RfTElHSFRfU0hBRE9XU19XSVRIX01BUFMvZywgcGFyYW1ldGVycy5udW1TcG90TGlnaHRTaGFkb3dzV2l0aE1hcHMgKVxuXHRcdC5yZXBsYWNlKCAvTlVNX1NQT1RfTElHSFRfU0hBRE9XUy9nLCBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodFNoYWRvd3MgKVxuXHRcdC5yZXBsYWNlKCAvTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MvZywgcGFyYW1ldGVycy5udW1Qb2ludExpZ2h0U2hhZG93cyApO1xuXG59XG5cbmZ1bmN0aW9uIHJlcGxhY2VDbGlwcGluZ1BsYW5lTnVtcyggc3RyaW5nLCBwYXJhbWV0ZXJzICkge1xuXG5cdHJldHVybiBzdHJpbmdcblx0XHQucmVwbGFjZSggL05VTV9DTElQUElOR19QTEFORVMvZywgcGFyYW1ldGVycy5udW1DbGlwcGluZ1BsYW5lcyApXG5cdFx0LnJlcGxhY2UoIC9VTklPTl9DTElQUElOR19QTEFORVMvZywgKCBwYXJhbWV0ZXJzLm51bUNsaXBwaW5nUGxhbmVzIC0gcGFyYW1ldGVycy5udW1DbGlwSW50ZXJzZWN0aW9uICkgKTtcblxufVxuXG4vLyBSZXNvbHZlIEluY2x1ZGVzXG5cbmNvbnN0IGluY2x1ZGVQYXR0ZXJuID0gL15bIFxcdF0qI2luY2x1ZGUgKzwoW1xcd1xcZC4vXSspPi9nbTtcblxuZnVuY3Rpb24gcmVzb2x2ZUluY2x1ZGVzKCBzdHJpbmcgKSB7XG5cblx0cmV0dXJuIHN0cmluZy5yZXBsYWNlKCBpbmNsdWRlUGF0dGVybiwgaW5jbHVkZVJlcGxhY2VyICk7XG5cbn1cblxuY29uc3Qgc2hhZGVyQ2h1bmtNYXAgPSBuZXcgTWFwKCk7XG5cbmZ1bmN0aW9uIGluY2x1ZGVSZXBsYWNlciggbWF0Y2gsIGluY2x1ZGUgKSB7XG5cblx0bGV0IHN0cmluZyA9IFNoYWRlckNodW5rWyBpbmNsdWRlIF07XG5cblx0aWYgKCBzdHJpbmcgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGNvbnN0IG5ld0luY2x1ZGUgPSBzaGFkZXJDaHVua01hcC5nZXQoIGluY2x1ZGUgKTtcblxuXHRcdGlmICggbmV3SW5jbHVkZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRzdHJpbmcgPSBTaGFkZXJDaHVua1sgbmV3SW5jbHVkZSBdO1xuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogU2hhZGVyIGNodW5rIFwiJXNcIiBoYXMgYmVlbiBkZXByZWNhdGVkLiBVc2UgXCIlc1wiIGluc3RlYWQuJywgaW5jbHVkZSwgbmV3SW5jbHVkZSApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnQ2FuIG5vdCByZXNvbHZlICNpbmNsdWRlIDwnICsgaW5jbHVkZSArICc+JyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4gcmVzb2x2ZUluY2x1ZGVzKCBzdHJpbmcgKTtcblxufVxuXG4vLyBVbnJvbGwgTG9vcHNcblxuY29uc3QgdW5yb2xsTG9vcFBhdHRlcm4gPSAvI3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxccytmb3JcXHMqXFwoXFxzKmludFxccytpXFxzKj1cXHMqKFxcZCspXFxzKjtcXHMqaVxccyo8XFxzKihcXGQrKVxccyo7XFxzKmlcXHMqXFwrXFwrXFxzKlxcKVxccyp7KFtcXHNcXFNdKz8pfVxccysjcHJhZ21hIHVucm9sbF9sb29wX2VuZC9nO1xuXG5mdW5jdGlvbiB1bnJvbGxMb29wcyggc3RyaW5nICkge1xuXG5cdHJldHVybiBzdHJpbmcucmVwbGFjZSggdW5yb2xsTG9vcFBhdHRlcm4sIGxvb3BSZXBsYWNlciApO1xuXG59XG5cbmZ1bmN0aW9uIGxvb3BSZXBsYWNlciggbWF0Y2gsIHN0YXJ0LCBlbmQsIHNuaXBwZXQgKSB7XG5cblx0bGV0IHN0cmluZyA9ICcnO1xuXG5cdGZvciAoIGxldCBpID0gcGFyc2VJbnQoIHN0YXJ0ICk7IGkgPCBwYXJzZUludCggZW5kICk7IGkgKysgKSB7XG5cblx0XHRzdHJpbmcgKz0gc25pcHBldFxuXHRcdFx0LnJlcGxhY2UoIC9cXFtcXHMqaVxccypcXF0vZywgJ1sgJyArIGkgKyAnIF0nIClcblx0XHRcdC5yZXBsYWNlKCAvVU5ST0xMRURfTE9PUF9JTkRFWC9nLCBpICk7XG5cblx0fVxuXG5cdHJldHVybiBzdHJpbmc7XG5cbn1cblxuLy9cblxuZnVuY3Rpb24gZ2VuZXJhdGVQcmVjaXNpb24oIHBhcmFtZXRlcnMgKSB7XG5cblx0bGV0IHByZWNpc2lvbnN0cmluZyA9IGBwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gZmxvYXQ7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBpbnQ7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBzYW1wbGVyMkQ7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBzYW1wbGVyQ3ViZTtcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHNhbXBsZXIzRDtcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHNhbXBsZXIyREFycmF5O1xuXHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gc2FtcGxlcjJEU2hhZG93O1xuXHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gc2FtcGxlckN1YmVTaGFkb3c7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBzYW1wbGVyMkRBcnJheVNoYWRvdztcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IGlzYW1wbGVyMkQ7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBpc2FtcGxlcjNEO1xuXHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gaXNhbXBsZXJDdWJlO1xuXHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gaXNhbXBsZXIyREFycmF5O1xuXHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gdXNhbXBsZXIyRDtcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHVzYW1wbGVyM0Q7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSB1c2FtcGxlckN1YmU7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSB1c2FtcGxlcjJEQXJyYXk7XG5cdGA7XG5cblx0aWYgKCBwYXJhbWV0ZXJzLnByZWNpc2lvbiA9PT0gJ2hpZ2hwJyApIHtcblxuXHRcdHByZWNpc2lvbnN0cmluZyArPSAnXFxuI2RlZmluZSBISUdIX1BSRUNJU0lPTic7XG5cblx0fSBlbHNlIGlmICggcGFyYW1ldGVycy5wcmVjaXNpb24gPT09ICdtZWRpdW1wJyApIHtcblxuXHRcdHByZWNpc2lvbnN0cmluZyArPSAnXFxuI2RlZmluZSBNRURJVU1fUFJFQ0lTSU9OJztcblxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLnByZWNpc2lvbiA9PT0gJ2xvd3AnICkge1xuXG5cdFx0cHJlY2lzaW9uc3RyaW5nICs9ICdcXG4jZGVmaW5lIExPV19QUkVDSVNJT04nO1xuXG5cdH1cblxuXHRyZXR1cm4gcHJlY2lzaW9uc3RyaW5nO1xuXG59XG5cbmZ1bmN0aW9uIGdlbmVyYXRlU2hhZG93TWFwVHlwZURlZmluZSggcGFyYW1ldGVycyApIHtcblxuXHRsZXQgc2hhZG93TWFwVHlwZURlZmluZSA9ICdTSEFET1dNQVBfVFlQRV9CQVNJQyc7XG5cblx0aWYgKCBwYXJhbWV0ZXJzLnNoYWRvd01hcFR5cGUgPT09IFBDRlNoYWRvd01hcCApIHtcblxuXHRcdHNoYWRvd01hcFR5cGVEZWZpbmUgPSAnU0hBRE9XTUFQX1RZUEVfUENGJztcblxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLnNoYWRvd01hcFR5cGUgPT09IFBDRlNvZnRTaGFkb3dNYXAgKSB7XG5cblx0XHRzaGFkb3dNYXBUeXBlRGVmaW5lID0gJ1NIQURPV01BUF9UWVBFX1BDRl9TT0ZUJztcblxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLnNoYWRvd01hcFR5cGUgPT09IFZTTVNoYWRvd01hcCApIHtcblxuXHRcdHNoYWRvd01hcFR5cGVEZWZpbmUgPSAnU0hBRE9XTUFQX1RZUEVfVlNNJztcblxuXHR9XG5cblx0cmV0dXJuIHNoYWRvd01hcFR5cGVEZWZpbmU7XG5cbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVFbnZNYXBUeXBlRGVmaW5lKCBwYXJhbWV0ZXJzICkge1xuXG5cdGxldCBlbnZNYXBUeXBlRGVmaW5lID0gJ0VOVk1BUF9UWVBFX0NVQkUnO1xuXG5cdGlmICggcGFyYW1ldGVycy5lbnZNYXAgKSB7XG5cblx0XHRzd2l0Y2ggKCBwYXJhbWV0ZXJzLmVudk1hcE1vZGUgKSB7XG5cblx0XHRcdGNhc2UgQ3ViZVJlZmxlY3Rpb25NYXBwaW5nOlxuXHRcdFx0Y2FzZSBDdWJlUmVmcmFjdGlvbk1hcHBpbmc6XG5cdFx0XHRcdGVudk1hcFR5cGVEZWZpbmUgPSAnRU5WTUFQX1RZUEVfQ1VCRSc7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlIEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nOlxuXHRcdFx0XHRlbnZNYXBUeXBlRGVmaW5lID0gJ0VOVk1BUF9UWVBFX0NVQkVfVVYnO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdH1cblxuXHR9XG5cblx0cmV0dXJuIGVudk1hcFR5cGVEZWZpbmU7XG5cbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVFbnZNYXBNb2RlRGVmaW5lKCBwYXJhbWV0ZXJzICkge1xuXG5cdGxldCBlbnZNYXBNb2RlRGVmaW5lID0gJ0VOVk1BUF9NT0RFX1JFRkxFQ1RJT04nO1xuXG5cdGlmICggcGFyYW1ldGVycy5lbnZNYXAgKSB7XG5cblx0XHRzd2l0Y2ggKCBwYXJhbWV0ZXJzLmVudk1hcE1vZGUgKSB7XG5cblx0XHRcdGNhc2UgQ3ViZVJlZnJhY3Rpb25NYXBwaW5nOlxuXG5cdFx0XHRcdGVudk1hcE1vZGVEZWZpbmUgPSAnRU5WTUFQX01PREVfUkVGUkFDVElPTic7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4gZW52TWFwTW9kZURlZmluZTtcblxufVxuXG5mdW5jdGlvbiBnZW5lcmF0ZUVudk1hcEJsZW5kaW5nRGVmaW5lKCBwYXJhbWV0ZXJzICkge1xuXG5cdGxldCBlbnZNYXBCbGVuZGluZ0RlZmluZSA9ICdFTlZNQVBfQkxFTkRJTkdfTk9ORSc7XG5cblx0aWYgKCBwYXJhbWV0ZXJzLmVudk1hcCApIHtcblxuXHRcdHN3aXRjaCAoIHBhcmFtZXRlcnMuY29tYmluZSApIHtcblxuXHRcdFx0Y2FzZSBNdWx0aXBseU9wZXJhdGlvbjpcblx0XHRcdFx0ZW52TWFwQmxlbmRpbmdEZWZpbmUgPSAnRU5WTUFQX0JMRU5ESU5HX01VTFRJUExZJztcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgTWl4T3BlcmF0aW9uOlxuXHRcdFx0XHRlbnZNYXBCbGVuZGluZ0RlZmluZSA9ICdFTlZNQVBfQkxFTkRJTkdfTUlYJztcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgQWRkT3BlcmF0aW9uOlxuXHRcdFx0XHRlbnZNYXBCbGVuZGluZ0RlZmluZSA9ICdFTlZNQVBfQkxFTkRJTkdfQUREJztcblx0XHRcdFx0YnJlYWs7XG5cblx0XHR9XG5cblx0fVxuXG5cdHJldHVybiBlbnZNYXBCbGVuZGluZ0RlZmluZTtcblxufVxuXG5mdW5jdGlvbiBnZW5lcmF0ZUN1YmVVVlNpemUoIHBhcmFtZXRlcnMgKSB7XG5cblx0Y29uc3QgaW1hZ2VIZWlnaHQgPSBwYXJhbWV0ZXJzLmVudk1hcEN1YmVVVkhlaWdodDtcblxuXHRpZiAoIGltYWdlSGVpZ2h0ID09PSBudWxsICkgcmV0dXJuIG51bGw7XG5cblx0Y29uc3QgbWF4TWlwID0gTWF0aC5sb2cyKCBpbWFnZUhlaWdodCApIC0gMjtcblxuXHRjb25zdCB0ZXhlbEhlaWdodCA9IDEuMCAvIGltYWdlSGVpZ2h0O1xuXG5cdGNvbnN0IHRleGVsV2lkdGggPSAxLjAgLyAoIDMgKiBNYXRoLm1heCggTWF0aC5wb3coIDIsIG1heE1pcCApLCA3ICogMTYgKSApO1xuXG5cdHJldHVybiB7IHRleGVsV2lkdGgsIHRleGVsSGVpZ2h0LCBtYXhNaXAgfTtcblxufVxuXG5mdW5jdGlvbiBXZWJHTFByb2dyYW0oIHJlbmRlcmVyLCBjYWNoZUtleSwgcGFyYW1ldGVycywgYmluZGluZ1N0YXRlcyApIHtcblxuXHQvLyBUT0RPIFNlbmQgdGhpcyBldmVudCB0byBUaHJlZS5qcyBEZXZUb29sc1xuXHQvLyBjb25zb2xlLmxvZyggJ1dlYkdMUHJvZ3JhbScsIGNhY2hlS2V5ICk7XG5cblx0Y29uc3QgZ2wgPSByZW5kZXJlci5nZXRDb250ZXh0KCk7XG5cblx0Y29uc3QgZGVmaW5lcyA9IHBhcmFtZXRlcnMuZGVmaW5lcztcblxuXHRsZXQgdmVydGV4U2hhZGVyID0gcGFyYW1ldGVycy52ZXJ0ZXhTaGFkZXI7XG5cdGxldCBmcmFnbWVudFNoYWRlciA9IHBhcmFtZXRlcnMuZnJhZ21lbnRTaGFkZXI7XG5cblx0Y29uc3Qgc2hhZG93TWFwVHlwZURlZmluZSA9IGdlbmVyYXRlU2hhZG93TWFwVHlwZURlZmluZSggcGFyYW1ldGVycyApO1xuXHRjb25zdCBlbnZNYXBUeXBlRGVmaW5lID0gZ2VuZXJhdGVFbnZNYXBUeXBlRGVmaW5lKCBwYXJhbWV0ZXJzICk7XG5cdGNvbnN0IGVudk1hcE1vZGVEZWZpbmUgPSBnZW5lcmF0ZUVudk1hcE1vZGVEZWZpbmUoIHBhcmFtZXRlcnMgKTtcblx0Y29uc3QgZW52TWFwQmxlbmRpbmdEZWZpbmUgPSBnZW5lcmF0ZUVudk1hcEJsZW5kaW5nRGVmaW5lKCBwYXJhbWV0ZXJzICk7XG5cdGNvbnN0IGVudk1hcEN1YmVVVlNpemUgPSBnZW5lcmF0ZUN1YmVVVlNpemUoIHBhcmFtZXRlcnMgKTtcblxuXHRjb25zdCBjdXN0b21WZXJ0ZXhFeHRlbnNpb25zID0gZ2VuZXJhdGVWZXJ0ZXhFeHRlbnNpb25zKCBwYXJhbWV0ZXJzICk7XG5cblx0Y29uc3QgY3VzdG9tRGVmaW5lcyA9IGdlbmVyYXRlRGVmaW5lcyggZGVmaW5lcyApO1xuXG5cdGNvbnN0IHByb2dyYW0gPSBnbC5jcmVhdGVQcm9ncmFtKCk7XG5cblx0bGV0IHByZWZpeFZlcnRleCwgcHJlZml4RnJhZ21lbnQ7XG5cdGxldCB2ZXJzaW9uU3RyaW5nID0gcGFyYW1ldGVycy5nbHNsVmVyc2lvbiA/ICcjdmVyc2lvbiAnICsgcGFyYW1ldGVycy5nbHNsVmVyc2lvbiArICdcXG4nIDogJyc7XG5cblx0aWYgKCBwYXJhbWV0ZXJzLmlzUmF3U2hhZGVyTWF0ZXJpYWwgKSB7XG5cblx0XHRwcmVmaXhWZXJ0ZXggPSBbXG5cblx0XHRcdCcjZGVmaW5lIFNIQURFUl9UWVBFICcgKyBwYXJhbWV0ZXJzLnNoYWRlclR5cGUsXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfTkFNRSAnICsgcGFyYW1ldGVycy5zaGFkZXJOYW1lLFxuXG5cdFx0XHRjdXN0b21EZWZpbmVzXG5cblx0XHRdLmZpbHRlciggZmlsdGVyRW1wdHlMaW5lICkuam9pbiggJ1xcbicgKTtcblxuXHRcdGlmICggcHJlZml4VmVydGV4Lmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdHByZWZpeFZlcnRleCArPSAnXFxuJztcblxuXHRcdH1cblxuXHRcdHByZWZpeEZyYWdtZW50ID0gW1xuXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfVFlQRSAnICsgcGFyYW1ldGVycy5zaGFkZXJUeXBlLFxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX05BTUUgJyArIHBhcmFtZXRlcnMuc2hhZGVyTmFtZSxcblxuXHRcdFx0Y3VzdG9tRGVmaW5lc1xuXG5cdFx0XS5maWx0ZXIoIGZpbHRlckVtcHR5TGluZSApLmpvaW4oICdcXG4nICk7XG5cblx0XHRpZiAoIHByZWZpeEZyYWdtZW50Lmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdHByZWZpeEZyYWdtZW50ICs9ICdcXG4nO1xuXG5cdFx0fVxuXG5cdH0gZWxzZSB7XG5cblx0XHRwcmVmaXhWZXJ0ZXggPSBbXG5cblx0XHRcdGdlbmVyYXRlUHJlY2lzaW9uKCBwYXJhbWV0ZXJzICksXG5cblx0XHRcdCcjZGVmaW5lIFNIQURFUl9UWVBFICcgKyBwYXJhbWV0ZXJzLnNoYWRlclR5cGUsXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfTkFNRSAnICsgcGFyYW1ldGVycy5zaGFkZXJOYW1lLFxuXG5cdFx0XHRjdXN0b21EZWZpbmVzLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmV4dGVuc2lvbkNsaXBDdWxsRGlzdGFuY2UgPyAnI2RlZmluZSBVU0VfQ0xJUF9ESVNUQU5DRScgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuYmF0Y2hpbmcgPyAnI2RlZmluZSBVU0VfQkFUQ0hJTkcnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmJhdGNoaW5nQ29sb3IgPyAnI2RlZmluZSBVU0VfQkFUQ0hJTkdfQ09MT1InIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmluc3RhbmNpbmcgPyAnI2RlZmluZSBVU0VfSU5TVEFOQ0lORycgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuaW5zdGFuY2luZ0NvbG9yID8gJyNkZWZpbmUgVVNFX0lOU1RBTkNJTkdfQ09MT1InIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmluc3RhbmNpbmdNb3JwaCA/ICcjZGVmaW5lIFVTRV9JTlNUQU5DSU5HX01PUlBIJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnVzZUZvZyAmJiBwYXJhbWV0ZXJzLmZvZyA/ICcjZGVmaW5lIFVTRV9GT0cnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnVzZUZvZyAmJiBwYXJhbWV0ZXJzLmZvZ0V4cDIgPyAnI2RlZmluZSBGT0dfRVhQMicgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5tYXAgPyAnI2RlZmluZSBVU0VfTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5lbnZNYXAgPyAnI2RlZmluZSBVU0VfRU5WTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5lbnZNYXAgPyAnI2RlZmluZSAnICsgZW52TWFwTW9kZURlZmluZSA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5saWdodE1hcCA/ICcjZGVmaW5lIFVTRV9MSUdIVE1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuYW9NYXAgPyAnI2RlZmluZSBVU0VfQU9NQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmJ1bXBNYXAgPyAnI2RlZmluZSBVU0VfQlVNUE1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMubm9ybWFsTWFwID8gJyNkZWZpbmUgVVNFX05PUk1BTE1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMubm9ybWFsTWFwT2JqZWN0U3BhY2UgPyAnI2RlZmluZSBVU0VfTk9STUFMTUFQX09CSkVDVFNQQUNFJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5ub3JtYWxNYXBUYW5nZW50U3BhY2UgPyAnI2RlZmluZSBVU0VfTk9STUFMTUFQX1RBTkdFTlRTUEFDRScgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuZGlzcGxhY2VtZW50TWFwID8gJyNkZWZpbmUgVVNFX0RJU1BMQUNFTUVOVE1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuZW1pc3NpdmVNYXAgPyAnI2RlZmluZSBVU0VfRU1JU1NJVkVNQVAnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuYW5pc290cm9weSA/ICcjZGVmaW5lIFVTRV9BTklTT1RST1BZJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5hbmlzb3Ryb3B5TWFwID8gJyNkZWZpbmUgVVNFX0FOSVNPVFJPUFlNQVAnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuY2xlYXJjb2F0TWFwID8gJyNkZWZpbmUgVVNFX0NMRUFSQ09BVE1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuY2xlYXJjb2F0Um91Z2huZXNzTWFwID8gJyNkZWZpbmUgVVNFX0NMRUFSQ09BVF9ST1VHSE5FU1NNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdE5vcm1hbE1hcCA/ICcjZGVmaW5lIFVTRV9DTEVBUkNPQVRfTk9STUFMTUFQJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlTWFwID8gJyNkZWZpbmUgVVNFX0lSSURFU0NFTkNFTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcCA/ICcjZGVmaW5lIFVTRV9JUklERVNDRU5DRV9USElDS05FU1NNQVAnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJNYXAgPyAnI2RlZmluZSBVU0VfU1BFQ1VMQVJNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnNwZWN1bGFyQ29sb3JNYXAgPyAnI2RlZmluZSBVU0VfU1BFQ1VMQVJfQ09MT1JNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnNwZWN1bGFySW50ZW5zaXR5TWFwID8gJyNkZWZpbmUgVVNFX1NQRUNVTEFSX0lOVEVOU0lUWU1BUCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5yb3VnaG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfUk9VR0hORVNTTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5tZXRhbG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfTUVUQUxORVNTTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5hbHBoYU1hcCA/ICcjZGVmaW5lIFVTRV9BTFBIQU1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuYWxwaGFIYXNoID8gJyNkZWZpbmUgVVNFX0FMUEhBSEFTSCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy50cmFuc21pc3Npb24gPyAnI2RlZmluZSBVU0VfVFJBTlNNSVNTSU9OJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy50cmFuc21pc3Npb25NYXAgPyAnI2RlZmluZSBVU0VfVFJBTlNNSVNTSU9OTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy50aGlja25lc3NNYXAgPyAnI2RlZmluZSBVU0VfVEhJQ0tORVNTTUFQJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnNoZWVuQ29sb3JNYXAgPyAnI2RlZmluZSBVU0VfU0hFRU5fQ09MT1JNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnNoZWVuUm91Z2huZXNzTWFwID8gJyNkZWZpbmUgVVNFX1NIRUVOX1JPVUdITkVTU01BUCcgOiAnJyxcblxuXHRcdFx0Ly9cblxuXHRcdFx0cGFyYW1ldGVycy5tYXBVdiA/ICcjZGVmaW5lIE1BUF9VViAnICsgcGFyYW1ldGVycy5tYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5hbHBoYU1hcFV2ID8gJyNkZWZpbmUgQUxQSEFNQVBfVVYgJyArIHBhcmFtZXRlcnMuYWxwaGFNYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5saWdodE1hcFV2ID8gJyNkZWZpbmUgTElHSFRNQVBfVVYgJyArIHBhcmFtZXRlcnMubGlnaHRNYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5hb01hcFV2ID8gJyNkZWZpbmUgQU9NQVBfVVYgJyArIHBhcmFtZXRlcnMuYW9NYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5lbWlzc2l2ZU1hcFV2ID8gJyNkZWZpbmUgRU1JU1NJVkVNQVBfVVYgJyArIHBhcmFtZXRlcnMuZW1pc3NpdmVNYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5idW1wTWFwVXYgPyAnI2RlZmluZSBCVU1QTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmJ1bXBNYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5ub3JtYWxNYXBVdiA/ICcjZGVmaW5lIE5PUk1BTE1BUF9VViAnICsgcGFyYW1ldGVycy5ub3JtYWxNYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5kaXNwbGFjZW1lbnRNYXBVdiA/ICcjZGVmaW5lIERJU1BMQUNFTUVOVE1BUF9VViAnICsgcGFyYW1ldGVycy5kaXNwbGFjZW1lbnRNYXBVdiA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLm1ldGFsbmVzc01hcFV2ID8gJyNkZWZpbmUgTUVUQUxORVNTTUFQX1VWICcgKyBwYXJhbWV0ZXJzLm1ldGFsbmVzc01hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnJvdWdobmVzc01hcFV2ID8gJyNkZWZpbmUgUk9VR0hORVNTTUFQX1VWICcgKyBwYXJhbWV0ZXJzLnJvdWdobmVzc01hcFV2IDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuYW5pc290cm9weU1hcFV2ID8gJyNkZWZpbmUgQU5JU09UUk9QWU1BUF9VViAnICsgcGFyYW1ldGVycy5hbmlzb3Ryb3B5TWFwVXYgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXRNYXBVdiA/ICcjZGVmaW5lIENMRUFSQ09BVE1BUF9VViAnICsgcGFyYW1ldGVycy5jbGVhcmNvYXRNYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXROb3JtYWxNYXBVdiA/ICcjZGVmaW5lIENMRUFSQ09BVF9OT1JNQUxNQVBfVVYgJyArIHBhcmFtZXRlcnMuY2xlYXJjb2F0Tm9ybWFsTWFwVXYgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuY2xlYXJjb2F0Um91Z2huZXNzTWFwVXYgPyAnI2RlZmluZSBDTEVBUkNPQVRfUk9VR0hORVNTTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmNsZWFyY29hdFJvdWdobmVzc01hcFV2IDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VNYXBVdiA/ICcjZGVmaW5lIElSSURFU0NFTkNFTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlTWFwVXYgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXBVdiA/ICcjZGVmaW5lIElSSURFU0NFTkNFX1RISUNLTkVTU01BUF9VViAnICsgcGFyYW1ldGVycy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcFV2IDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuc2hlZW5Db2xvck1hcFV2ID8gJyNkZWZpbmUgU0hFRU5fQ09MT1JNQVBfVVYgJyArIHBhcmFtZXRlcnMuc2hlZW5Db2xvck1hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnNoZWVuUm91Z2huZXNzTWFwVXYgPyAnI2RlZmluZSBTSEVFTl9ST1VHSE5FU1NNQVBfVVYgJyArIHBhcmFtZXRlcnMuc2hlZW5Sb3VnaG5lc3NNYXBVdiA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnNwZWN1bGFyTWFwVXYgPyAnI2RlZmluZSBTUEVDVUxBUk1BUF9VViAnICsgcGFyYW1ldGVycy5zcGVjdWxhck1hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnNwZWN1bGFyQ29sb3JNYXBVdiA/ICcjZGVmaW5lIFNQRUNVTEFSX0NPTE9STUFQX1VWICcgKyBwYXJhbWV0ZXJzLnNwZWN1bGFyQ29sb3JNYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhckludGVuc2l0eU1hcFV2ID8gJyNkZWZpbmUgU1BFQ1VMQVJfSU5URU5TSVRZTUFQX1VWICcgKyBwYXJhbWV0ZXJzLnNwZWN1bGFySW50ZW5zaXR5TWFwVXYgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy50cmFuc21pc3Npb25NYXBVdiA/ICcjZGVmaW5lIFRSQU5TTUlTU0lPTk1BUF9VViAnICsgcGFyYW1ldGVycy50cmFuc21pc3Npb25NYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy50aGlja25lc3NNYXBVdiA/ICcjZGVmaW5lIFRISUNLTkVTU01BUF9VViAnICsgcGFyYW1ldGVycy50aGlja25lc3NNYXBVdiA6ICcnLFxuXG5cdFx0XHQvL1xuXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFRhbmdlbnRzICYmIHBhcmFtZXRlcnMuZmxhdFNoYWRpbmcgPT09IGZhbHNlID8gJyNkZWZpbmUgVVNFX1RBTkdFTlQnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleENvbG9ycyA/ICcjZGVmaW5lIFVTRV9DT0xPUicgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4QWxwaGFzID8gJyNkZWZpbmUgVVNFX0NPTE9SX0FMUEhBJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjFzID8gJyNkZWZpbmUgVVNFX1VWMScgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4VXYycyA/ICcjZGVmaW5lIFVTRV9VVjInIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2M3MgPyAnI2RlZmluZSBVU0VfVVYzJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnBvaW50c1V2cyA/ICcjZGVmaW5lIFVTRV9QT0lOVFNfVVYnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuZmxhdFNoYWRpbmcgPyAnI2RlZmluZSBGTEFUX1NIQURFRCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5za2lubmluZyA/ICcjZGVmaW5lIFVTRV9TS0lOTklORycgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5tb3JwaFRhcmdldHMgPyAnI2RlZmluZSBVU0VfTU9SUEhUQVJHRVRTJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5tb3JwaE5vcm1hbHMgJiYgcGFyYW1ldGVycy5mbGF0U2hhZGluZyA9PT0gZmFsc2UgPyAnI2RlZmluZSBVU0VfTU9SUEhOT1JNQUxTJyA6ICcnLFxuXHRcdFx0KCBwYXJhbWV0ZXJzLm1vcnBoQ29sb3JzICkgPyAnI2RlZmluZSBVU0VfTU9SUEhDT0xPUlMnIDogJycsXG5cdFx0XHQoIHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQgPiAwICkgPyAnI2RlZmluZSBNT1JQSFRBUkdFVFNfVEVYVFVSRV9TVFJJREUgJyArIHBhcmFtZXRlcnMubW9ycGhUZXh0dXJlU3RyaWRlIDogJycsXG5cdFx0XHQoIHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQgPiAwICkgPyAnI2RlZmluZSBNT1JQSFRBUkdFVFNfQ09VTlQgJyArIHBhcmFtZXRlcnMubW9ycGhUYXJnZXRzQ291bnQgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuZG91YmxlU2lkZWQgPyAnI2RlZmluZSBET1VCTEVfU0lERUQnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmZsaXBTaWRlZCA/ICcjZGVmaW5lIEZMSVBfU0lERUQnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuc2hhZG93TWFwRW5hYmxlZCA/ICcjZGVmaW5lIFVTRV9TSEFET1dNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnNoYWRvd01hcEVuYWJsZWQgPyAnI2RlZmluZSAnICsgc2hhZG93TWFwVHlwZURlZmluZSA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnNpemVBdHRlbnVhdGlvbiA/ICcjZGVmaW5lIFVTRV9TSVpFQVRURU5VQVRJT04nIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMubnVtTGlnaHRQcm9iZXMgPiAwID8gJyNkZWZpbmUgVVNFX0xJR0hUX1BST0JFUycgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5sb2dhcml0aG1pY0RlcHRoQnVmZmVyID8gJyNkZWZpbmUgVVNFX0xPR0RFUFRIQlVGJyA6ICcnLFxuXG5cdFx0XHQndW5pZm9ybSBtYXQ0IG1vZGVsTWF0cml4OycsXG5cdFx0XHQndW5pZm9ybSBtYXQ0IG1vZGVsVmlld01hdHJpeDsnLFxuXHRcdFx0J3VuaWZvcm0gbWF0NCBwcm9qZWN0aW9uTWF0cml4OycsXG5cdFx0XHQndW5pZm9ybSBtYXQ0IHZpZXdNYXRyaXg7Jyxcblx0XHRcdCd1bmlmb3JtIG1hdDMgbm9ybWFsTWF0cml4OycsXG5cdFx0XHQndW5pZm9ybSB2ZWMzIGNhbWVyYVBvc2l0aW9uOycsXG5cdFx0XHQndW5pZm9ybSBib29sIGlzT3J0aG9ncmFwaGljOycsXG5cblx0XHRcdCcjaWZkZWYgVVNFX0lOU1RBTkNJTkcnLFxuXG5cdFx0XHQnXHRhdHRyaWJ1dGUgbWF0NCBpbnN0YW5jZU1hdHJpeDsnLFxuXG5cdFx0XHQnI2VuZGlmJyxcblxuXHRcdFx0JyNpZmRlZiBVU0VfSU5TVEFOQ0lOR19DT0xPUicsXG5cblx0XHRcdCdcdGF0dHJpYnV0ZSB2ZWMzIGluc3RhbmNlQ29sb3I7JyxcblxuXHRcdFx0JyNlbmRpZicsXG5cblx0XHRcdCcjaWZkZWYgVVNFX0lOU1RBTkNJTkdfTU9SUEgnLFxuXG5cdFx0XHQnXHR1bmlmb3JtIHNhbXBsZXIyRCBtb3JwaFRleHR1cmU7JyxcblxuXHRcdFx0JyNlbmRpZicsXG5cblx0XHRcdCdhdHRyaWJ1dGUgdmVjMyBwb3NpdGlvbjsnLFxuXHRcdFx0J2F0dHJpYnV0ZSB2ZWMzIG5vcm1hbDsnLFxuXHRcdFx0J2F0dHJpYnV0ZSB2ZWMyIHV2OycsXG5cblx0XHRcdCcjaWZkZWYgVVNFX1VWMScsXG5cblx0XHRcdCdcdGF0dHJpYnV0ZSB2ZWMyIHV2MTsnLFxuXG5cdFx0XHQnI2VuZGlmJyxcblxuXHRcdFx0JyNpZmRlZiBVU0VfVVYyJyxcblxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzIgdXYyOycsXG5cblx0XHRcdCcjZW5kaWYnLFxuXG5cdFx0XHQnI2lmZGVmIFVTRV9VVjMnLFxuXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjMiB1djM7JyxcblxuXHRcdFx0JyNlbmRpZicsXG5cblx0XHRcdCcjaWZkZWYgVVNFX1RBTkdFTlQnLFxuXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjNCB0YW5nZW50OycsXG5cblx0XHRcdCcjZW5kaWYnLFxuXG5cdFx0XHQnI2lmIGRlZmluZWQoIFVTRV9DT0xPUl9BTFBIQSApJyxcblxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzQgY29sb3I7JyxcblxuXHRcdFx0JyNlbGlmIGRlZmluZWQoIFVTRV9DT0xPUiApJyxcblxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzMgY29sb3I7JyxcblxuXHRcdFx0JyNlbmRpZicsXG5cblx0XHRcdCcjaWZkZWYgVVNFX1NLSU5OSU5HJyxcblxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzQgc2tpbkluZGV4OycsXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjNCBza2luV2VpZ2h0OycsXG5cblx0XHRcdCcjZW5kaWYnLFxuXG5cdFx0XHQnXFxuJ1xuXG5cdFx0XS5maWx0ZXIoIGZpbHRlckVtcHR5TGluZSApLmpvaW4oICdcXG4nICk7XG5cblx0XHRwcmVmaXhGcmFnbWVudCA9IFtcblxuXHRcdFx0Z2VuZXJhdGVQcmVjaXNpb24oIHBhcmFtZXRlcnMgKSxcblxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX1RZUEUgJyArIHBhcmFtZXRlcnMuc2hhZGVyVHlwZSxcblx0XHRcdCcjZGVmaW5lIFNIQURFUl9OQU1FICcgKyBwYXJhbWV0ZXJzLnNoYWRlck5hbWUsXG5cblx0XHRcdGN1c3RvbURlZmluZXMsXG5cblx0XHRcdHBhcmFtZXRlcnMudXNlRm9nICYmIHBhcmFtZXRlcnMuZm9nID8gJyNkZWZpbmUgVVNFX0ZPRycgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudXNlRm9nICYmIHBhcmFtZXRlcnMuZm9nRXhwMiA/ICcjZGVmaW5lIEZPR19FWFAyJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmFscGhhVG9Db3ZlcmFnZSA/ICcjZGVmaW5lIEFMUEhBX1RPX0NPVkVSQUdFJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5tYXAgPyAnI2RlZmluZSBVU0VfTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5tYXRjYXAgPyAnI2RlZmluZSBVU0VfTUFUQ0FQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5lbnZNYXAgPyAnI2RlZmluZSBVU0VfRU5WTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5lbnZNYXAgPyAnI2RlZmluZSAnICsgZW52TWFwVHlwZURlZmluZSA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5lbnZNYXAgPyAnI2RlZmluZSAnICsgZW52TWFwTW9kZURlZmluZSA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5lbnZNYXAgPyAnI2RlZmluZSAnICsgZW52TWFwQmxlbmRpbmdEZWZpbmUgOiAnJyxcblx0XHRcdGVudk1hcEN1YmVVVlNpemUgPyAnI2RlZmluZSBDVUJFVVZfVEVYRUxfV0lEVEggJyArIGVudk1hcEN1YmVVVlNpemUudGV4ZWxXaWR0aCA6ICcnLFxuXHRcdFx0ZW52TWFwQ3ViZVVWU2l6ZSA/ICcjZGVmaW5lIENVQkVVVl9URVhFTF9IRUlHSFQgJyArIGVudk1hcEN1YmVVVlNpemUudGV4ZWxIZWlnaHQgOiAnJyxcblx0XHRcdGVudk1hcEN1YmVVVlNpemUgPyAnI2RlZmluZSBDVUJFVVZfTUFYX01JUCAnICsgZW52TWFwQ3ViZVVWU2l6ZS5tYXhNaXAgKyAnLjAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmxpZ2h0TWFwID8gJyNkZWZpbmUgVVNFX0xJR0hUTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5hb01hcCA/ICcjZGVmaW5lIFVTRV9BT01BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuYnVtcE1hcCA/ICcjZGVmaW5lIFVTRV9CVU1QTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5ub3JtYWxNYXAgPyAnI2RlZmluZSBVU0VfTk9STUFMTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5ub3JtYWxNYXBPYmplY3RTcGFjZSA/ICcjZGVmaW5lIFVTRV9OT1JNQUxNQVBfT0JKRUNUU1BBQ0UnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLm5vcm1hbE1hcFRhbmdlbnRTcGFjZSA/ICcjZGVmaW5lIFVTRV9OT1JNQUxNQVBfVEFOR0VOVFNQQUNFJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5lbWlzc2l2ZU1hcCA/ICcjZGVmaW5lIFVTRV9FTUlTU0lWRU1BUCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5hbmlzb3Ryb3B5ID8gJyNkZWZpbmUgVVNFX0FOSVNPVFJPUFknIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmFuaXNvdHJvcHlNYXAgPyAnI2RlZmluZSBVU0VfQU5JU09UUk9QWU1BUCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXQgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXRNYXAgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuY2xlYXJjb2F0Tm9ybWFsTWFwID8gJyNkZWZpbmUgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVAnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuZGlzcGVyc2lvbiA/ICcjZGVmaW5lIFVTRV9ESVNQRVJTSU9OJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlID8gJyNkZWZpbmUgVVNFX0lSSURFU0NFTkNFJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5pcmlkZXNjZW5jZU1hcCA/ICcjZGVmaW5lIFVTRV9JUklERVNDRU5DRU1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgPyAnI2RlZmluZSBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnNwZWN1bGFyTWFwID8gJyNkZWZpbmUgVVNFX1NQRUNVTEFSTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhckNvbG9yTWFwID8gJyNkZWZpbmUgVVNFX1NQRUNVTEFSX0NPTE9STUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhckludGVuc2l0eU1hcCA/ICcjZGVmaW5lIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVAnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMucm91Z2huZXNzTWFwID8gJyNkZWZpbmUgVVNFX1JPVUdITkVTU01BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMubWV0YWxuZXNzTWFwID8gJyNkZWZpbmUgVVNFX01FVEFMTkVTU01BUCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5hbHBoYU1hcCA/ICcjZGVmaW5lIFVTRV9BTFBIQU1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuYWxwaGFUZXN0ID8gJyNkZWZpbmUgVVNFX0FMUEhBVEVTVCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuYWxwaGFIYXNoID8gJyNkZWZpbmUgVVNFX0FMUEhBSEFTSCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5zaGVlbiA/ICcjZGVmaW5lIFVTRV9TSEVFTicgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuc2hlZW5Db2xvck1hcCA/ICcjZGVmaW5lIFVTRV9TSEVFTl9DT0xPUk1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuc2hlZW5Sb3VnaG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfU0hFRU5fUk9VR0hORVNTTUFQJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbiA/ICcjZGVmaW5lIFVTRV9UUkFOU01JU1NJT04nIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbk1hcCA/ICcjZGVmaW5lIFVTRV9UUkFOU01JU1NJT05NQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnRoaWNrbmVzc01hcCA/ICcjZGVmaW5lIFVTRV9USElDS05FU1NNQVAnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMudmVydGV4VGFuZ2VudHMgJiYgcGFyYW1ldGVycy5mbGF0U2hhZGluZyA9PT0gZmFsc2UgPyAnI2RlZmluZSBVU0VfVEFOR0VOVCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4Q29sb3JzIHx8IHBhcmFtZXRlcnMuaW5zdGFuY2luZ0NvbG9yIHx8IHBhcmFtZXRlcnMuYmF0Y2hpbmdDb2xvciA/ICcjZGVmaW5lIFVTRV9DT0xPUicgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4QWxwaGFzID8gJyNkZWZpbmUgVVNFX0NPTE9SX0FMUEhBJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjFzID8gJyNkZWZpbmUgVVNFX1VWMScgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4VXYycyA/ICcjZGVmaW5lIFVTRV9VVjInIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2M3MgPyAnI2RlZmluZSBVU0VfVVYzJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnBvaW50c1V2cyA/ICcjZGVmaW5lIFVTRV9QT0lOVFNfVVYnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuZ3JhZGllbnRNYXAgPyAnI2RlZmluZSBVU0VfR1JBRElFTlRNQVAnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuZmxhdFNoYWRpbmcgPyAnI2RlZmluZSBGTEFUX1NIQURFRCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5kb3VibGVTaWRlZCA/ICcjZGVmaW5lIERPVUJMRV9TSURFRCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuZmxpcFNpZGVkID8gJyNkZWZpbmUgRkxJUF9TSURFRCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5zaGFkb3dNYXBFbmFibGVkID8gJyNkZWZpbmUgVVNFX1NIQURPV01BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuc2hhZG93TWFwRW5hYmxlZCA/ICcjZGVmaW5lICcgKyBzaGFkb3dNYXBUeXBlRGVmaW5lIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMucHJlbXVsdGlwbGllZEFscGhhID8gJyNkZWZpbmUgUFJFTVVMVElQTElFRF9BTFBIQScgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5udW1MaWdodFByb2JlcyA+IDAgPyAnI2RlZmluZSBVU0VfTElHSFRfUFJPQkVTJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmRlY29kZVZpZGVvVGV4dHVyZSA/ICcjZGVmaW5lIERFQ09ERV9WSURFT19URVhUVVJFJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmxvZ2FyaXRobWljRGVwdGhCdWZmZXIgPyAnI2RlZmluZSBVU0VfTE9HREVQVEhCVUYnIDogJycsXG5cblx0XHRcdCd1bmlmb3JtIG1hdDQgdmlld01hdHJpeDsnLFxuXHRcdFx0J3VuaWZvcm0gdmVjMyBjYW1lcmFQb3NpdGlvbjsnLFxuXHRcdFx0J3VuaWZvcm0gYm9vbCBpc09ydGhvZ3JhcGhpYzsnLFxuXG5cdFx0XHQoIHBhcmFtZXRlcnMudG9uZU1hcHBpbmcgIT09IE5vVG9uZU1hcHBpbmcgKSA/ICcjZGVmaW5lIFRPTkVfTUFQUElORycgOiAnJyxcblx0XHRcdCggcGFyYW1ldGVycy50b25lTWFwcGluZyAhPT0gTm9Ub25lTWFwcGluZyApID8gU2hhZGVyQ2h1bmtbICd0b25lbWFwcGluZ19wYXJzX2ZyYWdtZW50JyBdIDogJycsIC8vIHRoaXMgY29kZSBpcyByZXF1aXJlZCBoZXJlIGJlY2F1c2UgaXQgaXMgdXNlZCBieSB0aGUgdG9uZU1hcHBpbmcoKSBmdW5jdGlvbiBkZWZpbmVkIGJlbG93XG5cdFx0XHQoIHBhcmFtZXRlcnMudG9uZU1hcHBpbmcgIT09IE5vVG9uZU1hcHBpbmcgKSA/IGdldFRvbmVNYXBwaW5nRnVuY3Rpb24oICd0b25lTWFwcGluZycsIHBhcmFtZXRlcnMudG9uZU1hcHBpbmcgKSA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmRpdGhlcmluZyA/ICcjZGVmaW5lIERJVEhFUklORycgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMub3BhcXVlID8gJyNkZWZpbmUgT1BBUVVFJyA6ICcnLFxuXG5cdFx0XHRTaGFkZXJDaHVua1sgJ2NvbG9yc3BhY2VfcGFyc19mcmFnbWVudCcgXSwgLy8gdGhpcyBjb2RlIGlzIHJlcXVpcmVkIGhlcmUgYmVjYXVzZSBpdCBpcyB1c2VkIGJ5IHRoZSB2YXJpb3VzIGVuY29kaW5nL2RlY29kaW5nIGZ1bmN0aW9uIGRlZmluZWQgYmVsb3dcblx0XHRcdGdldFRleGVsRW5jb2RpbmdGdW5jdGlvbiggJ2xpbmVhclRvT3V0cHV0VGV4ZWwnLCBwYXJhbWV0ZXJzLm91dHB1dENvbG9yU3BhY2UgKSxcblxuXHRcdFx0cGFyYW1ldGVycy51c2VEZXB0aFBhY2tpbmcgPyAnI2RlZmluZSBERVBUSF9QQUNLSU5HICcgKyBwYXJhbWV0ZXJzLmRlcHRoUGFja2luZyA6ICcnLFxuXG5cdFx0XHQnXFxuJ1xuXG5cdFx0XS5maWx0ZXIoIGZpbHRlckVtcHR5TGluZSApLmpvaW4oICdcXG4nICk7XG5cblx0fVxuXG5cdHZlcnRleFNoYWRlciA9IHJlc29sdmVJbmNsdWRlcyggdmVydGV4U2hhZGVyICk7XG5cdHZlcnRleFNoYWRlciA9IHJlcGxhY2VMaWdodE51bXMoIHZlcnRleFNoYWRlciwgcGFyYW1ldGVycyApO1xuXHR2ZXJ0ZXhTaGFkZXIgPSByZXBsYWNlQ2xpcHBpbmdQbGFuZU51bXMoIHZlcnRleFNoYWRlciwgcGFyYW1ldGVycyApO1xuXG5cdGZyYWdtZW50U2hhZGVyID0gcmVzb2x2ZUluY2x1ZGVzKCBmcmFnbWVudFNoYWRlciApO1xuXHRmcmFnbWVudFNoYWRlciA9IHJlcGxhY2VMaWdodE51bXMoIGZyYWdtZW50U2hhZGVyLCBwYXJhbWV0ZXJzICk7XG5cdGZyYWdtZW50U2hhZGVyID0gcmVwbGFjZUNsaXBwaW5nUGxhbmVOdW1zKCBmcmFnbWVudFNoYWRlciwgcGFyYW1ldGVycyApO1xuXG5cdHZlcnRleFNoYWRlciA9IHVucm9sbExvb3BzKCB2ZXJ0ZXhTaGFkZXIgKTtcblx0ZnJhZ21lbnRTaGFkZXIgPSB1bnJvbGxMb29wcyggZnJhZ21lbnRTaGFkZXIgKTtcblxuXHRpZiAoIHBhcmFtZXRlcnMuaXNSYXdTaGFkZXJNYXRlcmlhbCAhPT0gdHJ1ZSApIHtcblxuXHRcdC8vIEdMU0wgMy4wIGNvbnZlcnNpb24gZm9yIGJ1aWx0LWluIG1hdGVyaWFscyBhbmQgU2hhZGVyTWF0ZXJpYWxcblxuXHRcdHZlcnNpb25TdHJpbmcgPSAnI3ZlcnNpb24gMzAwIGVzXFxuJztcblxuXHRcdHByZWZpeFZlcnRleCA9IFtcblx0XHRcdGN1c3RvbVZlcnRleEV4dGVuc2lvbnMsXG5cdFx0XHQnI2RlZmluZSBhdHRyaWJ1dGUgaW4nLFxuXHRcdFx0JyNkZWZpbmUgdmFyeWluZyBvdXQnLFxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEIHRleHR1cmUnXG5cdFx0XS5qb2luKCAnXFxuJyApICsgJ1xcbicgKyBwcmVmaXhWZXJ0ZXg7XG5cblx0XHRwcmVmaXhGcmFnbWVudCA9IFtcblx0XHRcdCcjZGVmaW5lIHZhcnlpbmcgaW4nLFxuXHRcdFx0KCBwYXJhbWV0ZXJzLmdsc2xWZXJzaW9uID09PSBHTFNMMyApID8gJycgOiAnbGF5b3V0KGxvY2F0aW9uID0gMCkgb3V0IGhpZ2hwIHZlYzQgcGNfZnJhZ0NvbG9yOycsXG5cdFx0XHQoIHBhcmFtZXRlcnMuZ2xzbFZlcnNpb24gPT09IEdMU0wzICkgPyAnJyA6ICcjZGVmaW5lIGdsX0ZyYWdDb2xvciBwY19mcmFnQ29sb3InLFxuXHRcdFx0JyNkZWZpbmUgZ2xfRnJhZ0RlcHRoRVhUIGdsX0ZyYWdEZXB0aCcsXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlMkQgdGV4dHVyZScsXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlQ3ViZSB0ZXh0dXJlJyxcblx0XHRcdCcjZGVmaW5lIHRleHR1cmUyRFByb2ogdGV4dHVyZVByb2onLFxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJETG9kRVhUIHRleHR1cmVMb2QnLFxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEUHJvakxvZEVYVCB0ZXh0dXJlUHJvakxvZCcsXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlQ3ViZUxvZEVYVCB0ZXh0dXJlTG9kJyxcblx0XHRcdCcjZGVmaW5lIHRleHR1cmUyREdyYWRFWFQgdGV4dHVyZUdyYWQnLFxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEUHJvakdyYWRFWFQgdGV4dHVyZVByb2pHcmFkJyxcblx0XHRcdCcjZGVmaW5lIHRleHR1cmVDdWJlR3JhZEVYVCB0ZXh0dXJlR3JhZCdcblx0XHRdLmpvaW4oICdcXG4nICkgKyAnXFxuJyArIHByZWZpeEZyYWdtZW50O1xuXG5cdH1cblxuXHRjb25zdCB2ZXJ0ZXhHbHNsID0gdmVyc2lvblN0cmluZyArIHByZWZpeFZlcnRleCArIHZlcnRleFNoYWRlcjtcblx0Y29uc3QgZnJhZ21lbnRHbHNsID0gdmVyc2lvblN0cmluZyArIHByZWZpeEZyYWdtZW50ICsgZnJhZ21lbnRTaGFkZXI7XG5cblx0Ly8gY29uc29sZS5sb2coICcqVkVSVEVYKicsIHZlcnRleEdsc2wgKTtcblx0Ly8gY29uc29sZS5sb2coICcqRlJBR01FTlQqJywgZnJhZ21lbnRHbHNsICk7XG5cblx0Y29uc3QgZ2xWZXJ0ZXhTaGFkZXIgPSBXZWJHTFNoYWRlciggZ2wsIGdsLlZFUlRFWF9TSEFERVIsIHZlcnRleEdsc2wgKTtcblx0Y29uc3QgZ2xGcmFnbWVudFNoYWRlciA9IFdlYkdMU2hhZGVyKCBnbCwgZ2wuRlJBR01FTlRfU0hBREVSLCBmcmFnbWVudEdsc2wgKTtcblxuXHRnbC5hdHRhY2hTaGFkZXIoIHByb2dyYW0sIGdsVmVydGV4U2hhZGVyICk7XG5cdGdsLmF0dGFjaFNoYWRlciggcHJvZ3JhbSwgZ2xGcmFnbWVudFNoYWRlciApO1xuXG5cdC8vIEZvcmNlIGEgcGFydGljdWxhciBhdHRyaWJ1dGUgdG8gaW5kZXggMC5cblxuXHRpZiAoIHBhcmFtZXRlcnMuaW5kZXgwQXR0cmlidXRlTmFtZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0Z2wuYmluZEF0dHJpYkxvY2F0aW9uKCBwcm9ncmFtLCAwLCBwYXJhbWV0ZXJzLmluZGV4MEF0dHJpYnV0ZU5hbWUgKTtcblxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLm1vcnBoVGFyZ2V0cyA9PT0gdHJ1ZSApIHtcblxuXHRcdC8vIHByb2dyYW1zIHdpdGggbW9ycGhUYXJnZXRzIGRpc3BsYWNlIHBvc2l0aW9uIG91dCBvZiBhdHRyaWJ1dGUgMFxuXHRcdGdsLmJpbmRBdHRyaWJMb2NhdGlvbiggcHJvZ3JhbSwgMCwgJ3Bvc2l0aW9uJyApO1xuXG5cdH1cblxuXHRnbC5saW5rUHJvZ3JhbSggcHJvZ3JhbSApO1xuXG5cdGZ1bmN0aW9uIG9uRmlyc3RVc2UoIHNlbGYgKSB7XG5cblx0XHQvLyBjaGVjayBmb3IgbGluayBlcnJvcnNcblx0XHRpZiAoIHJlbmRlcmVyLmRlYnVnLmNoZWNrU2hhZGVyRXJyb3JzICkge1xuXG5cdFx0XHRjb25zdCBwcm9ncmFtTG9nID0gZ2wuZ2V0UHJvZ3JhbUluZm9Mb2coIHByb2dyYW0gKS50cmltKCk7XG5cdFx0XHRjb25zdCB2ZXJ0ZXhMb2cgPSBnbC5nZXRTaGFkZXJJbmZvTG9nKCBnbFZlcnRleFNoYWRlciApLnRyaW0oKTtcblx0XHRcdGNvbnN0IGZyYWdtZW50TG9nID0gZ2wuZ2V0U2hhZGVySW5mb0xvZyggZ2xGcmFnbWVudFNoYWRlciApLnRyaW0oKTtcblxuXHRcdFx0bGV0IHJ1bm5hYmxlID0gdHJ1ZTtcblx0XHRcdGxldCBoYXZlRGlhZ25vc3RpY3MgPSB0cnVlO1xuXG5cdFx0XHRpZiAoIGdsLmdldFByb2dyYW1QYXJhbWV0ZXIoIHByb2dyYW0sIGdsLkxJTktfU1RBVFVTICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdHJ1bm5hYmxlID0gZmFsc2U7XG5cblx0XHRcdFx0aWYgKCB0eXBlb2YgcmVuZGVyZXIuZGVidWcub25TaGFkZXJFcnJvciA9PT0gJ2Z1bmN0aW9uJyApIHtcblxuXHRcdFx0XHRcdHJlbmRlcmVyLmRlYnVnLm9uU2hhZGVyRXJyb3IoIGdsLCBwcm9ncmFtLCBnbFZlcnRleFNoYWRlciwgZ2xGcmFnbWVudFNoYWRlciApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBkZWZhdWx0IGVycm9yIHJlcG9ydGluZ1xuXG5cdFx0XHRcdFx0Y29uc3QgdmVydGV4RXJyb3JzID0gZ2V0U2hhZGVyRXJyb3JzKCBnbCwgZ2xWZXJ0ZXhTaGFkZXIsICd2ZXJ0ZXgnICk7XG5cdFx0XHRcdFx0Y29uc3QgZnJhZ21lbnRFcnJvcnMgPSBnZXRTaGFkZXJFcnJvcnMoIGdsLCBnbEZyYWdtZW50U2hhZGVyLCAnZnJhZ21lbnQnICk7XG5cblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKFxuXHRcdFx0XHRcdFx0J1RIUkVFLldlYkdMUHJvZ3JhbTogU2hhZGVyIEVycm9yICcgKyBnbC5nZXRFcnJvcigpICsgJyAtICcgK1xuXHRcdFx0XHRcdFx0J1ZBTElEQVRFX1NUQVRVUyAnICsgZ2wuZ2V0UHJvZ3JhbVBhcmFtZXRlciggcHJvZ3JhbSwgZ2wuVkFMSURBVEVfU1RBVFVTICkgKyAnXFxuXFxuJyArXG5cdFx0XHRcdFx0XHQnTWF0ZXJpYWwgTmFtZTogJyArIHNlbGYubmFtZSArICdcXG4nICtcblx0XHRcdFx0XHRcdCdNYXRlcmlhbCBUeXBlOiAnICsgc2VsZi50eXBlICsgJ1xcblxcbicgK1xuXHRcdFx0XHRcdFx0J1Byb2dyYW0gSW5mbyBMb2c6ICcgKyBwcm9ncmFtTG9nICsgJ1xcbicgK1xuXHRcdFx0XHRcdFx0dmVydGV4RXJyb3JzICsgJ1xcbicgK1xuXHRcdFx0XHRcdFx0ZnJhZ21lbnRFcnJvcnNcblx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIGlmICggcHJvZ3JhbUxvZyAhPT0gJycgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xQcm9ncmFtOiBQcm9ncmFtIEluZm8gTG9nOicsIHByb2dyYW1Mb2cgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggdmVydGV4TG9nID09PSAnJyB8fCBmcmFnbWVudExvZyA9PT0gJycgKSB7XG5cblx0XHRcdFx0aGF2ZURpYWdub3N0aWNzID0gZmFsc2U7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBoYXZlRGlhZ25vc3RpY3MgKSB7XG5cblx0XHRcdFx0c2VsZi5kaWFnbm9zdGljcyA9IHtcblxuXHRcdFx0XHRcdHJ1bm5hYmxlOiBydW5uYWJsZSxcblxuXHRcdFx0XHRcdHByb2dyYW1Mb2c6IHByb2dyYW1Mb2csXG5cblx0XHRcdFx0XHR2ZXJ0ZXhTaGFkZXI6IHtcblxuXHRcdFx0XHRcdFx0bG9nOiB2ZXJ0ZXhMb2csXG5cdFx0XHRcdFx0XHRwcmVmaXg6IHByZWZpeFZlcnRleFxuXG5cdFx0XHRcdFx0fSxcblxuXHRcdFx0XHRcdGZyYWdtZW50U2hhZGVyOiB7XG5cblx0XHRcdFx0XHRcdGxvZzogZnJhZ21lbnRMb2csXG5cdFx0XHRcdFx0XHRwcmVmaXg6IHByZWZpeEZyYWdtZW50XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gQ2xlYW4gdXBcblxuXHRcdC8vIENyYXNoZXMgaW4gaU9TOSBhbmQgaU9TMTAuICMxODQwMlxuXHRcdC8vIGdsLmRldGFjaFNoYWRlciggcHJvZ3JhbSwgZ2xWZXJ0ZXhTaGFkZXIgKTtcblx0XHQvLyBnbC5kZXRhY2hTaGFkZXIoIHByb2dyYW0sIGdsRnJhZ21lbnRTaGFkZXIgKTtcblxuXHRcdGdsLmRlbGV0ZVNoYWRlciggZ2xWZXJ0ZXhTaGFkZXIgKTtcblx0XHRnbC5kZWxldGVTaGFkZXIoIGdsRnJhZ21lbnRTaGFkZXIgKTtcblxuXHRcdGNhY2hlZFVuaWZvcm1zID0gbmV3IFdlYkdMVW5pZm9ybXMoIGdsLCBwcm9ncmFtICk7XG5cdFx0Y2FjaGVkQXR0cmlidXRlcyA9IGZldGNoQXR0cmlidXRlTG9jYXRpb25zKCBnbCwgcHJvZ3JhbSApO1xuXG5cdH1cblxuXHQvLyBzZXQgdXAgY2FjaGluZyBmb3IgdW5pZm9ybSBsb2NhdGlvbnNcblxuXHRsZXQgY2FjaGVkVW5pZm9ybXM7XG5cblx0dGhpcy5nZXRVbmlmb3JtcyA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdGlmICggY2FjaGVkVW5pZm9ybXMgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Ly8gUG9wdWxhdGVzIGNhY2hlZFVuaWZvcm1zIGFuZCBjYWNoZWRBdHRyaWJ1dGVzXG5cdFx0XHRvbkZpcnN0VXNlKCB0aGlzICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gY2FjaGVkVW5pZm9ybXM7XG5cblx0fTtcblxuXHQvLyBzZXQgdXAgY2FjaGluZyBmb3IgYXR0cmlidXRlIGxvY2F0aW9uc1xuXG5cdGxldCBjYWNoZWRBdHRyaWJ1dGVzO1xuXG5cdHRoaXMuZ2V0QXR0cmlidXRlcyA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdGlmICggY2FjaGVkQXR0cmlidXRlcyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHQvLyBQb3B1bGF0ZXMgY2FjaGVkQXR0cmlidXRlcyBhbmQgY2FjaGVkVW5pZm9ybXNcblx0XHRcdG9uRmlyc3RVc2UoIHRoaXMgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBjYWNoZWRBdHRyaWJ1dGVzO1xuXG5cdH07XG5cblx0Ly8gaW5kaWNhdGUgd2hlbiB0aGUgcHJvZ3JhbSBpcyByZWFkeSB0byBiZSB1c2VkLiBpZiB0aGUgS0hSX3BhcmFsbGVsX3NoYWRlcl9jb21waWxlIGV4dGVuc2lvbiBpc24ndCBzdXBwb3J0ZWQsXG5cdC8vIGZsYWcgdGhlIHByb2dyYW0gYXMgcmVhZHkgaW1tZWRpYXRlbHkuIEl0IG1heSBjYXVzZSBhIHN0YWxsIHdoZW4gaXQncyBmaXJzdCB1c2VkLlxuXG5cdGxldCBwcm9ncmFtUmVhZHkgPSAoIHBhcmFtZXRlcnMucmVuZGVyZXJFeHRlbnNpb25QYXJhbGxlbFNoYWRlckNvbXBpbGUgPT09IGZhbHNlICk7XG5cblx0dGhpcy5pc1JlYWR5ID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0aWYgKCBwcm9ncmFtUmVhZHkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRwcm9ncmFtUmVhZHkgPSBnbC5nZXRQcm9ncmFtUGFyYW1ldGVyKCBwcm9ncmFtLCBDT01QTEVUSU9OX1NUQVRVU19LSFIgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBwcm9ncmFtUmVhZHk7XG5cblx0fTtcblxuXHQvLyBmcmVlIHJlc291cmNlXG5cblx0dGhpcy5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0YmluZGluZ1N0YXRlcy5yZWxlYXNlU3RhdGVzT2ZQcm9ncmFtKCB0aGlzICk7XG5cblx0XHRnbC5kZWxldGVQcm9ncmFtKCBwcm9ncmFtICk7XG5cdFx0dGhpcy5wcm9ncmFtID0gdW5kZWZpbmVkO1xuXG5cdH07XG5cblx0Ly9cblxuXHR0aGlzLnR5cGUgPSBwYXJhbWV0ZXJzLnNoYWRlclR5cGU7XG5cdHRoaXMubmFtZSA9IHBhcmFtZXRlcnMuc2hhZGVyTmFtZTtcblx0dGhpcy5pZCA9IHByb2dyYW1JZENvdW50ICsrO1xuXHR0aGlzLmNhY2hlS2V5ID0gY2FjaGVLZXk7XG5cdHRoaXMudXNlZFRpbWVzID0gMTtcblx0dGhpcy5wcm9ncmFtID0gcHJvZ3JhbTtcblx0dGhpcy52ZXJ0ZXhTaGFkZXIgPSBnbFZlcnRleFNoYWRlcjtcblx0dGhpcy5mcmFnbWVudFNoYWRlciA9IGdsRnJhZ21lbnRTaGFkZXI7XG5cblx0cmV0dXJuIHRoaXM7XG5cbn1cblxubGV0IF9pZCQxID0gMDtcblxuY2xhc3MgV2ViR0xTaGFkZXJDYWNoZSB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHR0aGlzLnNoYWRlckNhY2hlID0gbmV3IE1hcCgpO1xuXHRcdHRoaXMubWF0ZXJpYWxDYWNoZSA9IG5ldyBNYXAoKTtcblxuXHR9XG5cblx0dXBkYXRlKCBtYXRlcmlhbCApIHtcblxuXHRcdGNvbnN0IHZlcnRleFNoYWRlciA9IG1hdGVyaWFsLnZlcnRleFNoYWRlcjtcblx0XHRjb25zdCBmcmFnbWVudFNoYWRlciA9IG1hdGVyaWFsLmZyYWdtZW50U2hhZGVyO1xuXG5cdFx0Y29uc3QgdmVydGV4U2hhZGVyU3RhZ2UgPSB0aGlzLl9nZXRTaGFkZXJTdGFnZSggdmVydGV4U2hhZGVyICk7XG5cdFx0Y29uc3QgZnJhZ21lbnRTaGFkZXJTdGFnZSA9IHRoaXMuX2dldFNoYWRlclN0YWdlKCBmcmFnbWVudFNoYWRlciApO1xuXG5cdFx0Y29uc3QgbWF0ZXJpYWxTaGFkZXJzID0gdGhpcy5fZ2V0U2hhZGVyQ2FjaGVGb3JNYXRlcmlhbCggbWF0ZXJpYWwgKTtcblxuXHRcdGlmICggbWF0ZXJpYWxTaGFkZXJzLmhhcyggdmVydGV4U2hhZGVyU3RhZ2UgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdG1hdGVyaWFsU2hhZGVycy5hZGQoIHZlcnRleFNoYWRlclN0YWdlICk7XG5cdFx0XHR2ZXJ0ZXhTaGFkZXJTdGFnZS51c2VkVGltZXMgKys7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsU2hhZGVycy5oYXMoIGZyYWdtZW50U2hhZGVyU3RhZ2UgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdG1hdGVyaWFsU2hhZGVycy5hZGQoIGZyYWdtZW50U2hhZGVyU3RhZ2UgKTtcblx0XHRcdGZyYWdtZW50U2hhZGVyU3RhZ2UudXNlZFRpbWVzICsrO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJlbW92ZSggbWF0ZXJpYWwgKSB7XG5cblx0XHRjb25zdCBtYXRlcmlhbFNoYWRlcnMgPSB0aGlzLm1hdGVyaWFsQ2FjaGUuZ2V0KCBtYXRlcmlhbCApO1xuXG5cdFx0Zm9yICggY29uc3Qgc2hhZGVyU3RhZ2Ugb2YgbWF0ZXJpYWxTaGFkZXJzICkge1xuXG5cdFx0XHRzaGFkZXJTdGFnZS51c2VkVGltZXMgLS07XG5cblx0XHRcdGlmICggc2hhZGVyU3RhZ2UudXNlZFRpbWVzID09PSAwICkgdGhpcy5zaGFkZXJDYWNoZS5kZWxldGUoIHNoYWRlclN0YWdlLmNvZGUgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMubWF0ZXJpYWxDYWNoZS5kZWxldGUoIG1hdGVyaWFsICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0VmVydGV4U2hhZGVySUQoIG1hdGVyaWFsICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX2dldFNoYWRlclN0YWdlKCBtYXRlcmlhbC52ZXJ0ZXhTaGFkZXIgKS5pZDtcblxuXHR9XG5cblx0Z2V0RnJhZ21lbnRTaGFkZXJJRCggbWF0ZXJpYWwgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fZ2V0U2hhZGVyU3RhZ2UoIG1hdGVyaWFsLmZyYWdtZW50U2hhZGVyICkuaWQ7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLnNoYWRlckNhY2hlLmNsZWFyKCk7XG5cdFx0dGhpcy5tYXRlcmlhbENhY2hlLmNsZWFyKCk7XG5cblx0fVxuXG5cdF9nZXRTaGFkZXJDYWNoZUZvck1hdGVyaWFsKCBtYXRlcmlhbCApIHtcblxuXHRcdGNvbnN0IGNhY2hlID0gdGhpcy5tYXRlcmlhbENhY2hlO1xuXHRcdGxldCBzZXQgPSBjYWNoZS5nZXQoIG1hdGVyaWFsICk7XG5cblx0XHRpZiAoIHNldCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRzZXQgPSBuZXcgU2V0KCk7XG5cdFx0XHRjYWNoZS5zZXQoIG1hdGVyaWFsLCBzZXQgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBzZXQ7XG5cblx0fVxuXG5cdF9nZXRTaGFkZXJTdGFnZSggY29kZSApIHtcblxuXHRcdGNvbnN0IGNhY2hlID0gdGhpcy5zaGFkZXJDYWNoZTtcblx0XHRsZXQgc3RhZ2UgPSBjYWNoZS5nZXQoIGNvZGUgKTtcblxuXHRcdGlmICggc3RhZ2UgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0c3RhZ2UgPSBuZXcgV2ViR0xTaGFkZXJTdGFnZSggY29kZSApO1xuXHRcdFx0Y2FjaGUuc2V0KCBjb2RlLCBzdGFnZSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHN0YWdlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBXZWJHTFNoYWRlclN0YWdlIHtcblxuXHRjb25zdHJ1Y3RvciggY29kZSApIHtcblxuXHRcdHRoaXMuaWQgPSBfaWQkMSArKztcblxuXHRcdHRoaXMuY29kZSA9IGNvZGU7XG5cdFx0dGhpcy51c2VkVGltZXMgPSAwO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBXZWJHTFByb2dyYW1zKCByZW5kZXJlciwgY3ViZW1hcHMsIGN1YmV1dm1hcHMsIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcywgYmluZGluZ1N0YXRlcywgY2xpcHBpbmcgKSB7XG5cblx0Y29uc3QgX3Byb2dyYW1MYXllcnMgPSBuZXcgTGF5ZXJzKCk7XG5cdGNvbnN0IF9jdXN0b21TaGFkZXJzID0gbmV3IFdlYkdMU2hhZGVyQ2FjaGUoKTtcblx0Y29uc3QgX2FjdGl2ZUNoYW5uZWxzID0gbmV3IFNldCgpO1xuXHRjb25zdCBwcm9ncmFtcyA9IFtdO1xuXG5cdGNvbnN0IGxvZ2FyaXRobWljRGVwdGhCdWZmZXIgPSBjYXBhYmlsaXRpZXMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlcjtcblx0Y29uc3QgU1VQUE9SVFNfVkVSVEVYX1RFWFRVUkVTID0gY2FwYWJpbGl0aWVzLnZlcnRleFRleHR1cmVzO1xuXG5cdGxldCBwcmVjaXNpb24gPSBjYXBhYmlsaXRpZXMucHJlY2lzaW9uO1xuXG5cdGNvbnN0IHNoYWRlcklEcyA9IHtcblx0XHRNZXNoRGVwdGhNYXRlcmlhbDogJ2RlcHRoJyxcblx0XHRNZXNoRGlzdGFuY2VNYXRlcmlhbDogJ2Rpc3RhbmNlUkdCQScsXG5cdFx0TWVzaE5vcm1hbE1hdGVyaWFsOiAnbm9ybWFsJyxcblx0XHRNZXNoQmFzaWNNYXRlcmlhbDogJ2Jhc2ljJyxcblx0XHRNZXNoTGFtYmVydE1hdGVyaWFsOiAnbGFtYmVydCcsXG5cdFx0TWVzaFBob25nTWF0ZXJpYWw6ICdwaG9uZycsXG5cdFx0TWVzaFRvb25NYXRlcmlhbDogJ3Rvb24nLFxuXHRcdE1lc2hTdGFuZGFyZE1hdGVyaWFsOiAncGh5c2ljYWwnLFxuXHRcdE1lc2hQaHlzaWNhbE1hdGVyaWFsOiAncGh5c2ljYWwnLFxuXHRcdE1lc2hNYXRjYXBNYXRlcmlhbDogJ21hdGNhcCcsXG5cdFx0TGluZUJhc2ljTWF0ZXJpYWw6ICdiYXNpYycsXG5cdFx0TGluZURhc2hlZE1hdGVyaWFsOiAnZGFzaGVkJyxcblx0XHRQb2ludHNNYXRlcmlhbDogJ3BvaW50cycsXG5cdFx0U2hhZG93TWF0ZXJpYWw6ICdzaGFkb3cnLFxuXHRcdFNwcml0ZU1hdGVyaWFsOiAnc3ByaXRlJ1xuXHR9O1xuXG5cdGZ1bmN0aW9uIGdldENoYW5uZWwoIHZhbHVlICkge1xuXG5cdFx0X2FjdGl2ZUNoYW5uZWxzLmFkZCggdmFsdWUgKTtcblxuXHRcdGlmICggdmFsdWUgPT09IDAgKSByZXR1cm4gJ3V2JztcblxuXHRcdHJldHVybiBgdXYkeyB2YWx1ZSB9YDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0UGFyYW1ldGVycyggbWF0ZXJpYWwsIGxpZ2h0cywgc2hhZG93cywgc2NlbmUsIG9iamVjdCApIHtcblxuXHRcdGNvbnN0IGZvZyA9IHNjZW5lLmZvZztcblx0XHRjb25zdCBnZW9tZXRyeSA9IG9iamVjdC5nZW9tZXRyeTtcblx0XHRjb25zdCBlbnZpcm9ubWVudCA9IG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBzY2VuZS5lbnZpcm9ubWVudCA6IG51bGw7XG5cblx0XHRjb25zdCBlbnZNYXAgPSAoIG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBjdWJldXZtYXBzIDogY3ViZW1hcHMgKS5nZXQoIG1hdGVyaWFsLmVudk1hcCB8fCBlbnZpcm9ubWVudCApO1xuXHRcdGNvbnN0IGVudk1hcEN1YmVVVkhlaWdodCA9ICggISEgZW52TWFwICkgJiYgKCBlbnZNYXAubWFwcGluZyA9PT0gQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmcgKSA/IGVudk1hcC5pbWFnZS5oZWlnaHQgOiBudWxsO1xuXG5cdFx0Y29uc3Qgc2hhZGVySUQgPSBzaGFkZXJJRHNbIG1hdGVyaWFsLnR5cGUgXTtcblxuXHRcdC8vIGhldXJpc3RpY3MgdG8gY3JlYXRlIHNoYWRlciBwYXJhbWV0ZXJzIGFjY29yZGluZyB0byBsaWdodHMgaW4gdGhlIHNjZW5lXG5cdFx0Ly8gKG5vdCB0byBibG93IG92ZXIgbWF4TGlnaHRzIGJ1ZGdldClcblxuXHRcdGlmICggbWF0ZXJpYWwucHJlY2lzaW9uICE9PSBudWxsICkge1xuXG5cdFx0XHRwcmVjaXNpb24gPSBjYXBhYmlsaXRpZXMuZ2V0TWF4UHJlY2lzaW9uKCBtYXRlcmlhbC5wcmVjaXNpb24gKTtcblxuXHRcdFx0aWYgKCBwcmVjaXNpb24gIT09IG1hdGVyaWFsLnByZWNpc2lvbiApIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFByb2dyYW0uZ2V0UGFyYW1ldGVyczonLCBtYXRlcmlhbC5wcmVjaXNpb24sICdub3Qgc3VwcG9ydGVkLCB1c2luZycsIHByZWNpc2lvbiwgJ2luc3RlYWQuJyApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvL1xuXG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb24gfHwgZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLm5vcm1hbCB8fCBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMuY29sb3I7XG5cdFx0Y29uc3QgbW9ycGhUYXJnZXRzQ291bnQgPSAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSA/IG1vcnBoQXR0cmlidXRlLmxlbmd0aCA6IDA7XG5cblx0XHRsZXQgbW9ycGhUZXh0dXJlU3RyaWRlID0gMDtcblxuXHRcdGlmICggZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uICE9PSB1bmRlZmluZWQgKSBtb3JwaFRleHR1cmVTdHJpZGUgPSAxO1xuXHRcdGlmICggZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLm5vcm1hbCAhPT0gdW5kZWZpbmVkICkgbW9ycGhUZXh0dXJlU3RyaWRlID0gMjtcblx0XHRpZiAoIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvciAhPT0gdW5kZWZpbmVkICkgbW9ycGhUZXh0dXJlU3RyaWRlID0gMztcblxuXHRcdC8vXG5cblx0XHRsZXQgdmVydGV4U2hhZGVyLCBmcmFnbWVudFNoYWRlcjtcblx0XHRsZXQgY3VzdG9tVmVydGV4U2hhZGVySUQsIGN1c3RvbUZyYWdtZW50U2hhZGVySUQ7XG5cblx0XHRpZiAoIHNoYWRlcklEICkge1xuXG5cdFx0XHRjb25zdCBzaGFkZXIgPSBTaGFkZXJMaWJbIHNoYWRlcklEIF07XG5cblx0XHRcdHZlcnRleFNoYWRlciA9IHNoYWRlci52ZXJ0ZXhTaGFkZXI7XG5cdFx0XHRmcmFnbWVudFNoYWRlciA9IHNoYWRlci5mcmFnbWVudFNoYWRlcjtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHZlcnRleFNoYWRlciA9IG1hdGVyaWFsLnZlcnRleFNoYWRlcjtcblx0XHRcdGZyYWdtZW50U2hhZGVyID0gbWF0ZXJpYWwuZnJhZ21lbnRTaGFkZXI7XG5cblx0XHRcdF9jdXN0b21TaGFkZXJzLnVwZGF0ZSggbWF0ZXJpYWwgKTtcblxuXHRcdFx0Y3VzdG9tVmVydGV4U2hhZGVySUQgPSBfY3VzdG9tU2hhZGVycy5nZXRWZXJ0ZXhTaGFkZXJJRCggbWF0ZXJpYWwgKTtcblx0XHRcdGN1c3RvbUZyYWdtZW50U2hhZGVySUQgPSBfY3VzdG9tU2hhZGVycy5nZXRGcmFnbWVudFNoYWRlcklEKCBtYXRlcmlhbCApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgY3VycmVudFJlbmRlclRhcmdldCA9IHJlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xuXG5cdFx0Y29uc3QgSVNfSU5TVEFOQ0VETUVTSCA9IG9iamVjdC5pc0luc3RhbmNlZE1lc2ggPT09IHRydWU7XG5cdFx0Y29uc3QgSVNfQkFUQ0hFRE1FU0ggPSBvYmplY3QuaXNCYXRjaGVkTWVzaCA9PT0gdHJ1ZTtcblxuXHRcdGNvbnN0IEhBU19NQVAgPSAhISBtYXRlcmlhbC5tYXA7XG5cdFx0Y29uc3QgSEFTX01BVENBUCA9ICEhIG1hdGVyaWFsLm1hdGNhcDtcblx0XHRjb25zdCBIQVNfRU5WTUFQID0gISEgZW52TWFwO1xuXHRcdGNvbnN0IEhBU19BT01BUCA9ICEhIG1hdGVyaWFsLmFvTWFwO1xuXHRcdGNvbnN0IEhBU19MSUdIVE1BUCA9ICEhIG1hdGVyaWFsLmxpZ2h0TWFwO1xuXHRcdGNvbnN0IEhBU19CVU1QTUFQID0gISEgbWF0ZXJpYWwuYnVtcE1hcDtcblx0XHRjb25zdCBIQVNfTk9STUFMTUFQID0gISEgbWF0ZXJpYWwubm9ybWFsTWFwO1xuXHRcdGNvbnN0IEhBU19ESVNQTEFDRU1FTlRNQVAgPSAhISBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXA7XG5cdFx0Y29uc3QgSEFTX0VNSVNTSVZFTUFQID0gISEgbWF0ZXJpYWwuZW1pc3NpdmVNYXA7XG5cblx0XHRjb25zdCBIQVNfTUVUQUxORVNTTUFQID0gISEgbWF0ZXJpYWwubWV0YWxuZXNzTWFwO1xuXHRcdGNvbnN0IEhBU19ST1VHSE5FU1NNQVAgPSAhISBtYXRlcmlhbC5yb3VnaG5lc3NNYXA7XG5cblx0XHRjb25zdCBIQVNfQU5JU09UUk9QWSA9IG1hdGVyaWFsLmFuaXNvdHJvcHkgPiAwO1xuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVQgPSBtYXRlcmlhbC5jbGVhcmNvYXQgPiAwO1xuXHRcdGNvbnN0IEhBU19ESVNQRVJTSU9OID0gbWF0ZXJpYWwuZGlzcGVyc2lvbiA+IDA7XG5cdFx0Y29uc3QgSEFTX0lSSURFU0NFTkNFID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2UgPiAwO1xuXHRcdGNvbnN0IEhBU19TSEVFTiA9IG1hdGVyaWFsLnNoZWVuID4gMDtcblx0XHRjb25zdCBIQVNfVFJBTlNNSVNTSU9OID0gbWF0ZXJpYWwudHJhbnNtaXNzaW9uID4gMDtcblxuXHRcdGNvbnN0IEhBU19BTklTT1RST1BZTUFQID0gSEFTX0FOSVNPVFJPUFkgJiYgISEgbWF0ZXJpYWwuYW5pc290cm9weU1hcDtcblxuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVRNQVAgPSBIQVNfQ0xFQVJDT0FUICYmICEhIG1hdGVyaWFsLmNsZWFyY29hdE1hcDtcblx0XHRjb25zdCBIQVNfQ0xFQVJDT0FUX05PUk1BTE1BUCA9IEhBU19DTEVBUkNPQVQgJiYgISEgbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsTWFwO1xuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVRfUk9VR0hORVNTTUFQID0gSEFTX0NMRUFSQ09BVCAmJiAhISBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3NNYXA7XG5cblx0XHRjb25zdCBIQVNfSVJJREVTQ0VOQ0VNQVAgPSBIQVNfSVJJREVTQ0VOQ0UgJiYgISEgbWF0ZXJpYWwuaXJpZGVzY2VuY2VNYXA7XG5cdFx0Y29uc3QgSEFTX0lSSURFU0NFTkNFX1RISUNLTkVTU01BUCA9IEhBU19JUklERVNDRU5DRSAmJiAhISBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcDtcblxuXHRcdGNvbnN0IEhBU19TSEVFTl9DT0xPUk1BUCA9IEhBU19TSEVFTiAmJiAhISBtYXRlcmlhbC5zaGVlbkNvbG9yTWFwO1xuXHRcdGNvbnN0IEhBU19TSEVFTl9ST1VHSE5FU1NNQVAgPSBIQVNfU0hFRU4gJiYgISEgbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3NNYXA7XG5cblx0XHRjb25zdCBIQVNfU1BFQ1VMQVJNQVAgPSAhISBtYXRlcmlhbC5zcGVjdWxhck1hcDtcblx0XHRjb25zdCBIQVNfU1BFQ1VMQVJfQ09MT1JNQVAgPSAhISBtYXRlcmlhbC5zcGVjdWxhckNvbG9yTWFwO1xuXHRcdGNvbnN0IEhBU19TUEVDVUxBUl9JTlRFTlNJVFlNQVAgPSAhISBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eU1hcDtcblxuXHRcdGNvbnN0IEhBU19UUkFOU01JU1NJT05NQVAgPSBIQVNfVFJBTlNNSVNTSU9OICYmICEhIG1hdGVyaWFsLnRyYW5zbWlzc2lvbk1hcDtcblx0XHRjb25zdCBIQVNfVEhJQ0tORVNTTUFQID0gSEFTX1RSQU5TTUlTU0lPTiAmJiAhISBtYXRlcmlhbC50aGlja25lc3NNYXA7XG5cblx0XHRjb25zdCBIQVNfR1JBRElFTlRNQVAgPSAhISBtYXRlcmlhbC5ncmFkaWVudE1hcDtcblxuXHRcdGNvbnN0IEhBU19BTFBIQU1BUCA9ICEhIG1hdGVyaWFsLmFscGhhTWFwO1xuXG5cdFx0Y29uc3QgSEFTX0FMUEhBVEVTVCA9IG1hdGVyaWFsLmFscGhhVGVzdCA+IDA7XG5cblx0XHRjb25zdCBIQVNfQUxQSEFIQVNIID0gISEgbWF0ZXJpYWwuYWxwaGFIYXNoO1xuXG5cdFx0Y29uc3QgSEFTX0VYVEVOU0lPTlMgPSAhISBtYXRlcmlhbC5leHRlbnNpb25zO1xuXG5cdFx0bGV0IHRvbmVNYXBwaW5nID0gTm9Ub25lTWFwcGluZztcblxuXHRcdGlmICggbWF0ZXJpYWwudG9uZU1hcHBlZCApIHtcblxuXHRcdFx0aWYgKCBjdXJyZW50UmVuZGVyVGFyZ2V0ID09PSBudWxsIHx8IGN1cnJlbnRSZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHR0b25lTWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRjb25zdCBwYXJhbWV0ZXJzID0ge1xuXG5cdFx0XHRzaGFkZXJJRDogc2hhZGVySUQsXG5cdFx0XHRzaGFkZXJUeXBlOiBtYXRlcmlhbC50eXBlLFxuXHRcdFx0c2hhZGVyTmFtZTogbWF0ZXJpYWwubmFtZSxcblxuXHRcdFx0dmVydGV4U2hhZGVyOiB2ZXJ0ZXhTaGFkZXIsXG5cdFx0XHRmcmFnbWVudFNoYWRlcjogZnJhZ21lbnRTaGFkZXIsXG5cdFx0XHRkZWZpbmVzOiBtYXRlcmlhbC5kZWZpbmVzLFxuXG5cdFx0XHRjdXN0b21WZXJ0ZXhTaGFkZXJJRDogY3VzdG9tVmVydGV4U2hhZGVySUQsXG5cdFx0XHRjdXN0b21GcmFnbWVudFNoYWRlcklEOiBjdXN0b21GcmFnbWVudFNoYWRlcklELFxuXG5cdFx0XHRpc1Jhd1NoYWRlck1hdGVyaWFsOiBtYXRlcmlhbC5pc1Jhd1NoYWRlck1hdGVyaWFsID09PSB0cnVlLFxuXHRcdFx0Z2xzbFZlcnNpb246IG1hdGVyaWFsLmdsc2xWZXJzaW9uLFxuXG5cdFx0XHRwcmVjaXNpb246IHByZWNpc2lvbixcblxuXHRcdFx0YmF0Y2hpbmc6IElTX0JBVENIRURNRVNILFxuXHRcdFx0YmF0Y2hpbmdDb2xvcjogSVNfQkFUQ0hFRE1FU0ggJiYgb2JqZWN0Ll9jb2xvcnNUZXh0dXJlICE9PSBudWxsLFxuXHRcdFx0aW5zdGFuY2luZzogSVNfSU5TVEFOQ0VETUVTSCxcblx0XHRcdGluc3RhbmNpbmdDb2xvcjogSVNfSU5TVEFOQ0VETUVTSCAmJiBvYmplY3QuaW5zdGFuY2VDb2xvciAhPT0gbnVsbCxcblx0XHRcdGluc3RhbmNpbmdNb3JwaDogSVNfSU5TVEFOQ0VETUVTSCAmJiBvYmplY3QubW9ycGhUZXh0dXJlICE9PSBudWxsLFxuXG5cdFx0XHRzdXBwb3J0c1ZlcnRleFRleHR1cmVzOiBTVVBQT1JUU19WRVJURVhfVEVYVFVSRVMsXG5cdFx0XHRvdXRwdXRDb2xvclNwYWNlOiAoIGN1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgKSA/IHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2UgOiAoIGN1cnJlbnRSZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSA/IGN1cnJlbnRSZW5kZXJUYXJnZXQudGV4dHVyZS5jb2xvclNwYWNlIDogTGluZWFyU1JHQkNvbG9yU3BhY2UgKSxcblx0XHRcdGFscGhhVG9Db3ZlcmFnZTogISEgbWF0ZXJpYWwuYWxwaGFUb0NvdmVyYWdlLFxuXG5cdFx0XHRtYXA6IEhBU19NQVAsXG5cdFx0XHRtYXRjYXA6IEhBU19NQVRDQVAsXG5cdFx0XHRlbnZNYXA6IEhBU19FTlZNQVAsXG5cdFx0XHRlbnZNYXBNb2RlOiBIQVNfRU5WTUFQICYmIGVudk1hcC5tYXBwaW5nLFxuXHRcdFx0ZW52TWFwQ3ViZVVWSGVpZ2h0OiBlbnZNYXBDdWJlVVZIZWlnaHQsXG5cdFx0XHRhb01hcDogSEFTX0FPTUFQLFxuXHRcdFx0bGlnaHRNYXA6IEhBU19MSUdIVE1BUCxcblx0XHRcdGJ1bXBNYXA6IEhBU19CVU1QTUFQLFxuXHRcdFx0bm9ybWFsTWFwOiBIQVNfTk9STUFMTUFQLFxuXHRcdFx0ZGlzcGxhY2VtZW50TWFwOiBTVVBQT1JUU19WRVJURVhfVEVYVFVSRVMgJiYgSEFTX0RJU1BMQUNFTUVOVE1BUCxcblx0XHRcdGVtaXNzaXZlTWFwOiBIQVNfRU1JU1NJVkVNQVAsXG5cblx0XHRcdG5vcm1hbE1hcE9iamVjdFNwYWNlOiBIQVNfTk9STUFMTUFQICYmIG1hdGVyaWFsLm5vcm1hbE1hcFR5cGUgPT09IE9iamVjdFNwYWNlTm9ybWFsTWFwLFxuXHRcdFx0bm9ybWFsTWFwVGFuZ2VudFNwYWNlOiBIQVNfTk9STUFMTUFQICYmIG1hdGVyaWFsLm5vcm1hbE1hcFR5cGUgPT09IFRhbmdlbnRTcGFjZU5vcm1hbE1hcCxcblxuXHRcdFx0bWV0YWxuZXNzTWFwOiBIQVNfTUVUQUxORVNTTUFQLFxuXHRcdFx0cm91Z2huZXNzTWFwOiBIQVNfUk9VR0hORVNTTUFQLFxuXG5cdFx0XHRhbmlzb3Ryb3B5OiBIQVNfQU5JU09UUk9QWSxcblx0XHRcdGFuaXNvdHJvcHlNYXA6IEhBU19BTklTT1RST1BZTUFQLFxuXG5cdFx0XHRjbGVhcmNvYXQ6IEhBU19DTEVBUkNPQVQsXG5cdFx0XHRjbGVhcmNvYXRNYXA6IEhBU19DTEVBUkNPQVRNQVAsXG5cdFx0XHRjbGVhcmNvYXROb3JtYWxNYXA6IEhBU19DTEVBUkNPQVRfTk9STUFMTUFQLFxuXHRcdFx0Y2xlYXJjb2F0Um91Z2huZXNzTWFwOiBIQVNfQ0xFQVJDT0FUX1JPVUdITkVTU01BUCxcblxuXHRcdFx0ZGlzcGVyc2lvbjogSEFTX0RJU1BFUlNJT04sXG5cblx0XHRcdGlyaWRlc2NlbmNlOiBIQVNfSVJJREVTQ0VOQ0UsXG5cdFx0XHRpcmlkZXNjZW5jZU1hcDogSEFTX0lSSURFU0NFTkNFTUFQLFxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNYXA6IEhBU19JUklERVNDRU5DRV9USElDS05FU1NNQVAsXG5cblx0XHRcdHNoZWVuOiBIQVNfU0hFRU4sXG5cdFx0XHRzaGVlbkNvbG9yTWFwOiBIQVNfU0hFRU5fQ09MT1JNQVAsXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcDogSEFTX1NIRUVOX1JPVUdITkVTU01BUCxcblxuXHRcdFx0c3BlY3VsYXJNYXA6IEhBU19TUEVDVUxBUk1BUCxcblx0XHRcdHNwZWN1bGFyQ29sb3JNYXA6IEhBU19TUEVDVUxBUl9DT0xPUk1BUCxcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5TWFwOiBIQVNfU1BFQ1VMQVJfSU5URU5TSVRZTUFQLFxuXG5cdFx0XHR0cmFuc21pc3Npb246IEhBU19UUkFOU01JU1NJT04sXG5cdFx0XHR0cmFuc21pc3Npb25NYXA6IEhBU19UUkFOU01JU1NJT05NQVAsXG5cdFx0XHR0aGlja25lc3NNYXA6IEhBU19USElDS05FU1NNQVAsXG5cblx0XHRcdGdyYWRpZW50TWFwOiBIQVNfR1JBRElFTlRNQVAsXG5cblx0XHRcdG9wYXF1ZTogbWF0ZXJpYWwudHJhbnNwYXJlbnQgPT09IGZhbHNlICYmIG1hdGVyaWFsLmJsZW5kaW5nID09PSBOb3JtYWxCbGVuZGluZyAmJiBtYXRlcmlhbC5hbHBoYVRvQ292ZXJhZ2UgPT09IGZhbHNlLFxuXG5cdFx0XHRhbHBoYU1hcDogSEFTX0FMUEhBTUFQLFxuXHRcdFx0YWxwaGFUZXN0OiBIQVNfQUxQSEFURVNULFxuXHRcdFx0YWxwaGFIYXNoOiBIQVNfQUxQSEFIQVNILFxuXG5cdFx0XHRjb21iaW5lOiBtYXRlcmlhbC5jb21iaW5lLFxuXG5cdFx0XHQvL1xuXG5cdFx0XHRtYXBVdjogSEFTX01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5tYXAuY2hhbm5lbCApLFxuXHRcdFx0YW9NYXBVdjogSEFTX0FPTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmFvTWFwLmNoYW5uZWwgKSxcblx0XHRcdGxpZ2h0TWFwVXY6IEhBU19MSUdIVE1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5saWdodE1hcC5jaGFubmVsICksXG5cdFx0XHRidW1wTWFwVXY6IEhBU19CVU1QTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmJ1bXBNYXAuY2hhbm5lbCApLFxuXHRcdFx0bm9ybWFsTWFwVXY6IEhBU19OT1JNQUxNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwubm9ybWFsTWFwLmNoYW5uZWwgKSxcblx0XHRcdGRpc3BsYWNlbWVudE1hcFV2OiBIQVNfRElTUExBQ0VNRU5UTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmRpc3BsYWNlbWVudE1hcC5jaGFubmVsICksXG5cdFx0XHRlbWlzc2l2ZU1hcFV2OiBIQVNfRU1JU1NJVkVNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuZW1pc3NpdmVNYXAuY2hhbm5lbCApLFxuXG5cdFx0XHRtZXRhbG5lc3NNYXBVdjogSEFTX01FVEFMTkVTU01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5tZXRhbG5lc3NNYXAuY2hhbm5lbCApLFxuXHRcdFx0cm91Z2huZXNzTWFwVXY6IEhBU19ST1VHSE5FU1NNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwucm91Z2huZXNzTWFwLmNoYW5uZWwgKSxcblxuXHRcdFx0YW5pc290cm9weU1hcFV2OiBIQVNfQU5JU09UUk9QWU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5hbmlzb3Ryb3B5TWFwLmNoYW5uZWwgKSxcblxuXHRcdFx0Y2xlYXJjb2F0TWFwVXY6IEhBU19DTEVBUkNPQVRNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuY2xlYXJjb2F0TWFwLmNoYW5uZWwgKSxcblx0XHRcdGNsZWFyY29hdE5vcm1hbE1hcFV2OiBIQVNfQ0xFQVJDT0FUX05PUk1BTE1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxNYXAuY2hhbm5lbCApLFxuXHRcdFx0Y2xlYXJjb2F0Um91Z2huZXNzTWFwVXY6IEhBU19DTEVBUkNPQVRfUk9VR0hORVNTTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzc01hcC5jaGFubmVsICksXG5cblx0XHRcdGlyaWRlc2NlbmNlTWFwVXY6IEhBU19JUklERVNDRU5DRU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcC5jaGFubmVsICksXG5cdFx0XHRpcmlkZXNjZW5jZVRoaWNrbmVzc01hcFV2OiBIQVNfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwLmNoYW5uZWwgKSxcblxuXHRcdFx0c2hlZW5Db2xvck1hcFV2OiBIQVNfU0hFRU5fQ09MT1JNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuc2hlZW5Db2xvck1hcC5jaGFubmVsICksXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcFV2OiBIQVNfU0hFRU5fUk9VR0hORVNTTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzTWFwLmNoYW5uZWwgKSxcblxuXHRcdFx0c3BlY3VsYXJNYXBVdjogSEFTX1NQRUNVTEFSTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLnNwZWN1bGFyTWFwLmNoYW5uZWwgKSxcblx0XHRcdHNwZWN1bGFyQ29sb3JNYXBVdjogSEFTX1NQRUNVTEFSX0NPTE9STUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3JNYXAuY2hhbm5lbCApLFxuXHRcdFx0c3BlY3VsYXJJbnRlbnNpdHlNYXBVdjogSEFTX1NQRUNVTEFSX0lOVEVOU0lUWU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eU1hcC5jaGFubmVsICksXG5cblx0XHRcdHRyYW5zbWlzc2lvbk1hcFV2OiBIQVNfVFJBTlNNSVNTSU9OTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLnRyYW5zbWlzc2lvbk1hcC5jaGFubmVsICksXG5cdFx0XHR0aGlja25lc3NNYXBVdjogSEFTX1RISUNLTkVTU01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC50aGlja25lc3NNYXAuY2hhbm5lbCApLFxuXG5cdFx0XHRhbHBoYU1hcFV2OiBIQVNfQUxQSEFNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuYWxwaGFNYXAuY2hhbm5lbCApLFxuXG5cdFx0XHQvL1xuXG5cdFx0XHR2ZXJ0ZXhUYW5nZW50czogISEgZ2VvbWV0cnkuYXR0cmlidXRlcy50YW5nZW50ICYmICggSEFTX05PUk1BTE1BUCB8fCBIQVNfQU5JU09UUk9QWSApLFxuXHRcdFx0dmVydGV4Q29sb3JzOiBtYXRlcmlhbC52ZXJ0ZXhDb2xvcnMsXG5cdFx0XHR2ZXJ0ZXhBbHBoYXM6IG1hdGVyaWFsLnZlcnRleENvbG9ycyA9PT0gdHJ1ZSAmJiAhISBnZW9tZXRyeS5hdHRyaWJ1dGVzLmNvbG9yICYmIGdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IuaXRlbVNpemUgPT09IDQsXG5cblx0XHRcdHBvaW50c1V2czogb2JqZWN0LmlzUG9pbnRzID09PSB0cnVlICYmICEhIGdlb21ldHJ5LmF0dHJpYnV0ZXMudXYgJiYgKCBIQVNfTUFQIHx8IEhBU19BTFBIQU1BUCApLFxuXG5cdFx0XHRmb2c6ICEhIGZvZyxcblx0XHRcdHVzZUZvZzogbWF0ZXJpYWwuZm9nID09PSB0cnVlLFxuXHRcdFx0Zm9nRXhwMjogKCAhISBmb2cgJiYgZm9nLmlzRm9nRXhwMiApLFxuXG5cdFx0XHRmbGF0U2hhZGluZzogbWF0ZXJpYWwuZmxhdFNoYWRpbmcgPT09IHRydWUsXG5cblx0XHRcdHNpemVBdHRlbnVhdGlvbjogbWF0ZXJpYWwuc2l6ZUF0dGVudWF0aW9uID09PSB0cnVlLFxuXHRcdFx0bG9nYXJpdGhtaWNEZXB0aEJ1ZmZlcjogbG9nYXJpdGhtaWNEZXB0aEJ1ZmZlcixcblxuXHRcdFx0c2tpbm5pbmc6IG9iamVjdC5pc1NraW5uZWRNZXNoID09PSB0cnVlLFxuXG5cdFx0XHRtb3JwaFRhcmdldHM6IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiAhPT0gdW5kZWZpbmVkLFxuXHRcdFx0bW9ycGhOb3JtYWxzOiBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsICE9PSB1bmRlZmluZWQsXG5cdFx0XHRtb3JwaENvbG9yczogZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yICE9PSB1bmRlZmluZWQsXG5cdFx0XHRtb3JwaFRhcmdldHNDb3VudDogbW9ycGhUYXJnZXRzQ291bnQsXG5cdFx0XHRtb3JwaFRleHR1cmVTdHJpZGU6IG1vcnBoVGV4dHVyZVN0cmlkZSxcblxuXHRcdFx0bnVtRGlyTGlnaHRzOiBsaWdodHMuZGlyZWN0aW9uYWwubGVuZ3RoLFxuXHRcdFx0bnVtUG9pbnRMaWdodHM6IGxpZ2h0cy5wb2ludC5sZW5ndGgsXG5cdFx0XHRudW1TcG90TGlnaHRzOiBsaWdodHMuc3BvdC5sZW5ndGgsXG5cdFx0XHRudW1TcG90TGlnaHRNYXBzOiBsaWdodHMuc3BvdExpZ2h0TWFwLmxlbmd0aCxcblx0XHRcdG51bVJlY3RBcmVhTGlnaHRzOiBsaWdodHMucmVjdEFyZWEubGVuZ3RoLFxuXHRcdFx0bnVtSGVtaUxpZ2h0czogbGlnaHRzLmhlbWkubGVuZ3RoLFxuXG5cdFx0XHRudW1EaXJMaWdodFNoYWRvd3M6IGxpZ2h0cy5kaXJlY3Rpb25hbFNoYWRvd01hcC5sZW5ndGgsXG5cdFx0XHRudW1Qb2ludExpZ2h0U2hhZG93czogbGlnaHRzLnBvaW50U2hhZG93TWFwLmxlbmd0aCxcblx0XHRcdG51bVNwb3RMaWdodFNoYWRvd3M6IGxpZ2h0cy5zcG90U2hhZG93TWFwLmxlbmd0aCxcblx0XHRcdG51bVNwb3RMaWdodFNoYWRvd3NXaXRoTWFwczogbGlnaHRzLm51bVNwb3RMaWdodFNoYWRvd3NXaXRoTWFwcyxcblxuXHRcdFx0bnVtTGlnaHRQcm9iZXM6IGxpZ2h0cy5udW1MaWdodFByb2JlcyxcblxuXHRcdFx0bnVtQ2xpcHBpbmdQbGFuZXM6IGNsaXBwaW5nLm51bVBsYW5lcyxcblx0XHRcdG51bUNsaXBJbnRlcnNlY3Rpb246IGNsaXBwaW5nLm51bUludGVyc2VjdGlvbixcblxuXHRcdFx0ZGl0aGVyaW5nOiBtYXRlcmlhbC5kaXRoZXJpbmcsXG5cblx0XHRcdHNoYWRvd01hcEVuYWJsZWQ6IHJlbmRlcmVyLnNoYWRvd01hcC5lbmFibGVkICYmIHNoYWRvd3MubGVuZ3RoID4gMCxcblx0XHRcdHNoYWRvd01hcFR5cGU6IHJlbmRlcmVyLnNoYWRvd01hcC50eXBlLFxuXG5cdFx0XHR0b25lTWFwcGluZzogdG9uZU1hcHBpbmcsXG5cblx0XHRcdGRlY29kZVZpZGVvVGV4dHVyZTogSEFTX01BUCAmJiAoIG1hdGVyaWFsLm1hcC5pc1ZpZGVvVGV4dHVyZSA9PT0gdHJ1ZSApICYmICggQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBtYXRlcmlhbC5tYXAuY29sb3JTcGFjZSApID09PSBTUkdCVHJhbnNmZXIgKSxcblxuXHRcdFx0cHJlbXVsdGlwbGllZEFscGhhOiBtYXRlcmlhbC5wcmVtdWx0aXBsaWVkQWxwaGEsXG5cblx0XHRcdGRvdWJsZVNpZGVkOiBtYXRlcmlhbC5zaWRlID09PSBEb3VibGVTaWRlLFxuXHRcdFx0ZmxpcFNpZGVkOiBtYXRlcmlhbC5zaWRlID09PSBCYWNrU2lkZSxcblxuXHRcdFx0dXNlRGVwdGhQYWNraW5nOiBtYXRlcmlhbC5kZXB0aFBhY2tpbmcgPj0gMCxcblx0XHRcdGRlcHRoUGFja2luZzogbWF0ZXJpYWwuZGVwdGhQYWNraW5nIHx8IDAsXG5cblx0XHRcdGluZGV4MEF0dHJpYnV0ZU5hbWU6IG1hdGVyaWFsLmluZGV4MEF0dHJpYnV0ZU5hbWUsXG5cblx0XHRcdGV4dGVuc2lvbkNsaXBDdWxsRGlzdGFuY2U6IEhBU19FWFRFTlNJT05TICYmIG1hdGVyaWFsLmV4dGVuc2lvbnMuY2xpcEN1bGxEaXN0YW5jZSA9PT0gdHJ1ZSAmJiBleHRlbnNpb25zLmhhcyggJ1dFQkdMX2NsaXBfY3VsbF9kaXN0YW5jZScgKSxcblx0XHRcdGV4dGVuc2lvbk11bHRpRHJhdzogKCBIQVNfRVhURU5TSU9OUyAmJiBtYXRlcmlhbC5leHRlbnNpb25zLm11bHRpRHJhdyA9PT0gdHJ1ZSB8fCBJU19CQVRDSEVETUVTSCApICYmIGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfbXVsdGlfZHJhdycgKSxcblxuXHRcdFx0cmVuZGVyZXJFeHRlbnNpb25QYXJhbGxlbFNoYWRlckNvbXBpbGU6IGV4dGVuc2lvbnMuaGFzKCAnS0hSX3BhcmFsbGVsX3NoYWRlcl9jb21waWxlJyApLFxuXG5cdFx0XHRjdXN0b21Qcm9ncmFtQ2FjaGVLZXk6IG1hdGVyaWFsLmN1c3RvbVByb2dyYW1DYWNoZUtleSgpXG5cblx0XHR9O1xuXG5cdFx0Ly8gdGhlIHVzYWdlIG9mIGdldENoYW5uZWwoKSBkZXRlcm1pbmVzIHRoZSBhY3RpdmUgdGV4dHVyZSBjaGFubmVscyBmb3IgdGhpcyBzaGFkZXJcblxuXHRcdHBhcmFtZXRlcnMudmVydGV4VXYxcyA9IF9hY3RpdmVDaGFubmVscy5oYXMoIDEgKTtcblx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2MnMgPSBfYWN0aXZlQ2hhbm5lbHMuaGFzKCAyICk7XG5cdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjNzID0gX2FjdGl2ZUNoYW5uZWxzLmhhcyggMyApO1xuXG5cdFx0X2FjdGl2ZUNoYW5uZWxzLmNsZWFyKCk7XG5cblx0XHRyZXR1cm4gcGFyYW1ldGVycztcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0UHJvZ3JhbUNhY2hlS2V5KCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0Y29uc3QgYXJyYXkgPSBbXTtcblxuXHRcdGlmICggcGFyYW1ldGVycy5zaGFkZXJJRCApIHtcblxuXHRcdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zaGFkZXJJRCApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jdXN0b21WZXJ0ZXhTaGFkZXJJRCApO1xuXHRcdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jdXN0b21GcmFnbWVudFNoYWRlcklEICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHBhcmFtZXRlcnMuZGVmaW5lcyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRmb3IgKCBjb25zdCBuYW1lIGluIHBhcmFtZXRlcnMuZGVmaW5lcyApIHtcblxuXHRcdFx0XHRhcnJheS5wdXNoKCBuYW1lICk7XG5cdFx0XHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuZGVmaW5lc1sgbmFtZSBdICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggcGFyYW1ldGVycy5pc1Jhd1NoYWRlck1hdGVyaWFsID09PSBmYWxzZSApIHtcblxuXHRcdFx0Z2V0UHJvZ3JhbUNhY2hlS2V5UGFyYW1ldGVycyggYXJyYXksIHBhcmFtZXRlcnMgKTtcblx0XHRcdGdldFByb2dyYW1DYWNoZUtleUJvb2xlYW5zKCBhcnJheSwgcGFyYW1ldGVycyApO1xuXHRcdFx0YXJyYXkucHVzaCggcmVuZGVyZXIub3V0cHV0Q29sb3JTcGFjZSApO1xuXG5cdFx0fVxuXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jdXN0b21Qcm9ncmFtQ2FjaGVLZXkgKTtcblxuXHRcdHJldHVybiBhcnJheS5qb2luKCk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldFByb2dyYW1DYWNoZUtleVBhcmFtZXRlcnMoIGFycmF5LCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5wcmVjaXNpb24gKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm91dHB1dENvbG9yU3BhY2UgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmVudk1hcE1vZGUgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmVudk1hcEN1YmVVVkhlaWdodCApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmFscGhhTWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmxpZ2h0TWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmFvTWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmJ1bXBNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubm9ybWFsTWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmRpc3BsYWNlbWVudE1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5lbWlzc2l2ZU1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5tZXRhbG5lc3NNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMucm91Z2huZXNzTWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmFuaXNvdHJvcHlNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuY2xlYXJjb2F0TWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmNsZWFyY29hdE5vcm1hbE1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jbGVhcmNvYXRSb3VnaG5lc3NNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuc2hlZW5Db2xvck1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zaGVlblJvdWdobmVzc01hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zcGVjdWxhck1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zcGVjdWxhckNvbG9yTWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnNwZWN1bGFySW50ZW5zaXR5TWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbk1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy50aGlja25lc3NNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuY29tYmluZSApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuZm9nRXhwMiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuc2l6ZUF0dGVudWF0aW9uICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5tb3JwaFRhcmdldHNDb3VudCApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubW9ycGhBdHRyaWJ1dGVDb3VudCApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtRGlyTGlnaHRzICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5udW1Qb2ludExpZ2h0cyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0cyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0TWFwcyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtSGVtaUxpZ2h0cyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtUmVjdEFyZWFMaWdodHMgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bURpckxpZ2h0U2hhZG93cyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtUG9pbnRMaWdodFNoYWRvd3MgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodFNoYWRvd3MgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodFNoYWRvd3NXaXRoTWFwcyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtTGlnaHRQcm9iZXMgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnNoYWRvd01hcFR5cGUgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnRvbmVNYXBwaW5nICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5udW1DbGlwcGluZ1BsYW5lcyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtQ2xpcEludGVyc2VjdGlvbiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuZGVwdGhQYWNraW5nICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldFByb2dyYW1DYWNoZUtleUJvb2xlYW5zKCBhcnJheSwgcGFyYW1ldGVycyApIHtcblxuXHRcdF9wcm9ncmFtTGF5ZXJzLmRpc2FibGVBbGwoKTtcblxuXHRcdGlmICggcGFyYW1ldGVycy5zdXBwb3J0c1ZlcnRleFRleHR1cmVzIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMCApO1xuXHRcdGlmICggcGFyYW1ldGVycy5pbnN0YW5jaW5nIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMSApO1xuXHRcdGlmICggcGFyYW1ldGVycy5pbnN0YW5jaW5nQ29sb3IgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAyICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmluc3RhbmNpbmdNb3JwaCApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDMgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMubWF0Y2FwIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggNCApO1xuXHRcdGlmICggcGFyYW1ldGVycy5lbnZNYXAgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA1ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLm5vcm1hbE1hcE9iamVjdFNwYWNlIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggNiApO1xuXHRcdGlmICggcGFyYW1ldGVycy5ub3JtYWxNYXBUYW5nZW50U3BhY2UgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA3ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmNsZWFyY29hdCApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDggKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2UgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA5ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFscGhhVGVzdCApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEwICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleENvbG9ycyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDExICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleEFscGhhcyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEyICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleFV2MXMgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMyApO1xuXHRcdGlmICggcGFyYW1ldGVycy52ZXJ0ZXhVdjJzIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTQgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMudmVydGV4VXYzcyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE1ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleFRhbmdlbnRzIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTYgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuYW5pc290cm9weSApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE3ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFscGhhSGFzaCApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE4ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmJhdGNoaW5nIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTkgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuZGlzcGVyc2lvbiApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDIwICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmJhdGNoaW5nQ29sb3IgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAyMSApO1xuXG5cdFx0YXJyYXkucHVzaCggX3Byb2dyYW1MYXllcnMubWFzayApO1xuXHRcdF9wcm9ncmFtTGF5ZXJzLmRpc2FibGVBbGwoKTtcblxuXHRcdGlmICggcGFyYW1ldGVycy5mb2cgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAwICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnVzZUZvZyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuZmxhdFNoYWRpbmcgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAyICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmxvZ2FyaXRobWljRGVwdGhCdWZmZXIgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAzICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnNraW5uaW5nIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggNCApO1xuXHRcdGlmICggcGFyYW1ldGVycy5tb3JwaFRhcmdldHMgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA1ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLm1vcnBoTm9ybWFscyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDYgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMubW9ycGhDb2xvcnMgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA3ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnByZW11bHRpcGxpZWRBbHBoYSApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDggKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuc2hhZG93TWFwRW5hYmxlZCApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDkgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuZG91YmxlU2lkZWQgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMCApO1xuXHRcdGlmICggcGFyYW1ldGVycy5mbGlwU2lkZWQgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMSApO1xuXHRcdGlmICggcGFyYW1ldGVycy51c2VEZXB0aFBhY2tpbmcgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMiApO1xuXHRcdGlmICggcGFyYW1ldGVycy5kaXRoZXJpbmcgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMyApO1xuXHRcdGlmICggcGFyYW1ldGVycy50cmFuc21pc3Npb24gKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxNCApO1xuXHRcdGlmICggcGFyYW1ldGVycy5zaGVlbiApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE1ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLm9wYXF1ZSApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE2ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnBvaW50c1V2cyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE3ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmRlY29kZVZpZGVvVGV4dHVyZSApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE4ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFscGhhVG9Db3ZlcmFnZSApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE5ICk7XG5cblx0XHRhcnJheS5wdXNoKCBfcHJvZ3JhbUxheWVycy5tYXNrICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldFVuaWZvcm1zKCBtYXRlcmlhbCApIHtcblxuXHRcdGNvbnN0IHNoYWRlcklEID0gc2hhZGVySURzWyBtYXRlcmlhbC50eXBlIF07XG5cdFx0bGV0IHVuaWZvcm1zO1xuXG5cdFx0aWYgKCBzaGFkZXJJRCApIHtcblxuXHRcdFx0Y29uc3Qgc2hhZGVyID0gU2hhZGVyTGliWyBzaGFkZXJJRCBdO1xuXHRcdFx0dW5pZm9ybXMgPSBVbmlmb3Jtc1V0aWxzLmNsb25lKCBzaGFkZXIudW5pZm9ybXMgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHVuaWZvcm1zID0gbWF0ZXJpYWwudW5pZm9ybXM7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdW5pZm9ybXM7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGFjcXVpcmVQcm9ncmFtKCBwYXJhbWV0ZXJzLCBjYWNoZUtleSApIHtcblxuXHRcdGxldCBwcm9ncmFtO1xuXG5cdFx0Ly8gQ2hlY2sgaWYgY29kZSBoYXMgYmVlbiBhbHJlYWR5IGNvbXBpbGVkXG5cdFx0Zm9yICggbGV0IHAgPSAwLCBwbCA9IHByb2dyYW1zLmxlbmd0aDsgcCA8IHBsOyBwICsrICkge1xuXG5cdFx0XHRjb25zdCBwcmVleGlzdGluZ1Byb2dyYW0gPSBwcm9ncmFtc1sgcCBdO1xuXG5cdFx0XHRpZiAoIHByZWV4aXN0aW5nUHJvZ3JhbS5jYWNoZUtleSA9PT0gY2FjaGVLZXkgKSB7XG5cblx0XHRcdFx0cHJvZ3JhbSA9IHByZWV4aXN0aW5nUHJvZ3JhbTtcblx0XHRcdFx0KysgcHJvZ3JhbS51c2VkVGltZXM7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggcHJvZ3JhbSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRwcm9ncmFtID0gbmV3IFdlYkdMUHJvZ3JhbSggcmVuZGVyZXIsIGNhY2hlS2V5LCBwYXJhbWV0ZXJzLCBiaW5kaW5nU3RhdGVzICk7XG5cdFx0XHRwcm9ncmFtcy5wdXNoKCBwcm9ncmFtICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcHJvZ3JhbTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVsZWFzZVByb2dyYW0oIHByb2dyYW0gKSB7XG5cblx0XHRpZiAoIC0tIHByb2dyYW0udXNlZFRpbWVzID09PSAwICkge1xuXG5cdFx0XHQvLyBSZW1vdmUgZnJvbSB1bm9yZGVyZWQgc2V0XG5cdFx0XHRjb25zdCBpID0gcHJvZ3JhbXMuaW5kZXhPZiggcHJvZ3JhbSApO1xuXHRcdFx0cHJvZ3JhbXNbIGkgXSA9IHByb2dyYW1zWyBwcm9ncmFtcy5sZW5ndGggLSAxIF07XG5cdFx0XHRwcm9ncmFtcy5wb3AoKTtcblxuXHRcdFx0Ly8gRnJlZSBXZWJHTCByZXNvdXJjZXNcblx0XHRcdHByb2dyYW0uZGVzdHJveSgpO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiByZWxlYXNlU2hhZGVyQ2FjaGUoIG1hdGVyaWFsICkge1xuXG5cdFx0X2N1c3RvbVNoYWRlcnMucmVtb3ZlKCBtYXRlcmlhbCApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xuXG5cdFx0X2N1c3RvbVNoYWRlcnMuZGlzcG9zZSgpO1xuXG5cdH1cblxuXHRyZXR1cm4ge1xuXHRcdGdldFBhcmFtZXRlcnM6IGdldFBhcmFtZXRlcnMsXG5cdFx0Z2V0UHJvZ3JhbUNhY2hlS2V5OiBnZXRQcm9ncmFtQ2FjaGVLZXksXG5cdFx0Z2V0VW5pZm9ybXM6IGdldFVuaWZvcm1zLFxuXHRcdGFjcXVpcmVQcm9ncmFtOiBhY3F1aXJlUHJvZ3JhbSxcblx0XHRyZWxlYXNlUHJvZ3JhbTogcmVsZWFzZVByb2dyYW0sXG5cdFx0cmVsZWFzZVNoYWRlckNhY2hlOiByZWxlYXNlU2hhZGVyQ2FjaGUsXG5cdFx0Ly8gRXhwb3NlZCBmb3IgcmVzb3VyY2UgbW9uaXRvcmluZyAmIGVycm9yIGZlZWRiYWNrIHZpYSByZW5kZXJlci5pbmZvOlxuXHRcdHByb2dyYW1zOiBwcm9ncmFtcyxcblx0XHRkaXNwb3NlOiBkaXNwb3NlXG5cdH07XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xQcm9wZXJ0aWVzKCkge1xuXG5cdGxldCBwcm9wZXJ0aWVzID0gbmV3IFdlYWtNYXAoKTtcblxuXHRmdW5jdGlvbiBnZXQoIG9iamVjdCApIHtcblxuXHRcdGxldCBtYXAgPSBwcm9wZXJ0aWVzLmdldCggb2JqZWN0ICk7XG5cblx0XHRpZiAoIG1hcCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRtYXAgPSB7fTtcblx0XHRcdHByb3BlcnRpZXMuc2V0KCBvYmplY3QsIG1hcCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG1hcDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVtb3ZlKCBvYmplY3QgKSB7XG5cblx0XHRwcm9wZXJ0aWVzLmRlbGV0ZSggb2JqZWN0ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHVwZGF0ZSggb2JqZWN0LCBrZXksIHZhbHVlICkge1xuXG5cdFx0cHJvcGVydGllcy5nZXQoIG9iamVjdCApWyBrZXkgXSA9IHZhbHVlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xuXG5cdFx0cHJvcGVydGllcyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0Z2V0OiBnZXQsXG5cdFx0cmVtb3ZlOiByZW1vdmUsXG5cdFx0dXBkYXRlOiB1cGRhdGUsXG5cdFx0ZGlzcG9zZTogZGlzcG9zZVxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIHBhaW50ZXJTb3J0U3RhYmxlKCBhLCBiICkge1xuXG5cdGlmICggYS5ncm91cE9yZGVyICE9PSBiLmdyb3VwT3JkZXIgKSB7XG5cblx0XHRyZXR1cm4gYS5ncm91cE9yZGVyIC0gYi5ncm91cE9yZGVyO1xuXG5cdH0gZWxzZSBpZiAoIGEucmVuZGVyT3JkZXIgIT09IGIucmVuZGVyT3JkZXIgKSB7XG5cblx0XHRyZXR1cm4gYS5yZW5kZXJPcmRlciAtIGIucmVuZGVyT3JkZXI7XG5cblx0fSBlbHNlIGlmICggYS5tYXRlcmlhbC5pZCAhPT0gYi5tYXRlcmlhbC5pZCApIHtcblxuXHRcdHJldHVybiBhLm1hdGVyaWFsLmlkIC0gYi5tYXRlcmlhbC5pZDtcblxuXHR9IGVsc2UgaWYgKCBhLnogIT09IGIueiApIHtcblxuXHRcdHJldHVybiBhLnogLSBiLno7XG5cblx0fSBlbHNlIHtcblxuXHRcdHJldHVybiBhLmlkIC0gYi5pZDtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gcmV2ZXJzZVBhaW50ZXJTb3J0U3RhYmxlKCBhLCBiICkge1xuXG5cdGlmICggYS5ncm91cE9yZGVyICE9PSBiLmdyb3VwT3JkZXIgKSB7XG5cblx0XHRyZXR1cm4gYS5ncm91cE9yZGVyIC0gYi5ncm91cE9yZGVyO1xuXG5cdH0gZWxzZSBpZiAoIGEucmVuZGVyT3JkZXIgIT09IGIucmVuZGVyT3JkZXIgKSB7XG5cblx0XHRyZXR1cm4gYS5yZW5kZXJPcmRlciAtIGIucmVuZGVyT3JkZXI7XG5cblx0fSBlbHNlIGlmICggYS56ICE9PSBiLnogKSB7XG5cblx0XHRyZXR1cm4gYi56IC0gYS56O1xuXG5cdH0gZWxzZSB7XG5cblx0XHRyZXR1cm4gYS5pZCAtIGIuaWQ7XG5cblx0fVxuXG59XG5cblxuZnVuY3Rpb24gV2ViR0xSZW5kZXJMaXN0KCkge1xuXG5cdGNvbnN0IHJlbmRlckl0ZW1zID0gW107XG5cdGxldCByZW5kZXJJdGVtc0luZGV4ID0gMDtcblxuXHRjb25zdCBvcGFxdWUgPSBbXTtcblx0Y29uc3QgdHJhbnNtaXNzaXZlID0gW107XG5cdGNvbnN0IHRyYW5zcGFyZW50ID0gW107XG5cblx0ZnVuY3Rpb24gaW5pdCgpIHtcblxuXHRcdHJlbmRlckl0ZW1zSW5kZXggPSAwO1xuXG5cdFx0b3BhcXVlLmxlbmd0aCA9IDA7XG5cdFx0dHJhbnNtaXNzaXZlLmxlbmd0aCA9IDA7XG5cdFx0dHJhbnNwYXJlbnQubGVuZ3RoID0gMDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0TmV4dFJlbmRlckl0ZW0oIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApIHtcblxuXHRcdGxldCByZW5kZXJJdGVtID0gcmVuZGVySXRlbXNbIHJlbmRlckl0ZW1zSW5kZXggXTtcblxuXHRcdGlmICggcmVuZGVySXRlbSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRyZW5kZXJJdGVtID0ge1xuXHRcdFx0XHRpZDogb2JqZWN0LmlkLFxuXHRcdFx0XHRvYmplY3Q6IG9iamVjdCxcblx0XHRcdFx0Z2VvbWV0cnk6IGdlb21ldHJ5LFxuXHRcdFx0XHRtYXRlcmlhbDogbWF0ZXJpYWwsXG5cdFx0XHRcdGdyb3VwT3JkZXI6IGdyb3VwT3JkZXIsXG5cdFx0XHRcdHJlbmRlck9yZGVyOiBvYmplY3QucmVuZGVyT3JkZXIsXG5cdFx0XHRcdHo6IHosXG5cdFx0XHRcdGdyb3VwOiBncm91cFxuXHRcdFx0fTtcblxuXHRcdFx0cmVuZGVySXRlbXNbIHJlbmRlckl0ZW1zSW5kZXggXSA9IHJlbmRlckl0ZW07XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRyZW5kZXJJdGVtLmlkID0gb2JqZWN0LmlkO1xuXHRcdFx0cmVuZGVySXRlbS5vYmplY3QgPSBvYmplY3Q7XG5cdFx0XHRyZW5kZXJJdGVtLmdlb21ldHJ5ID0gZ2VvbWV0cnk7XG5cdFx0XHRyZW5kZXJJdGVtLm1hdGVyaWFsID0gbWF0ZXJpYWw7XG5cdFx0XHRyZW5kZXJJdGVtLmdyb3VwT3JkZXIgPSBncm91cE9yZGVyO1xuXHRcdFx0cmVuZGVySXRlbS5yZW5kZXJPcmRlciA9IG9iamVjdC5yZW5kZXJPcmRlcjtcblx0XHRcdHJlbmRlckl0ZW0ueiA9IHo7XG5cdFx0XHRyZW5kZXJJdGVtLmdyb3VwID0gZ3JvdXA7XG5cblx0XHR9XG5cblx0XHRyZW5kZXJJdGVtc0luZGV4ICsrO1xuXG5cdFx0cmV0dXJuIHJlbmRlckl0ZW07XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHB1c2goIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApIHtcblxuXHRcdGNvbnN0IHJlbmRlckl0ZW0gPSBnZXROZXh0UmVuZGVySXRlbSggb2JqZWN0LCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwT3JkZXIsIHosIGdyb3VwICk7XG5cblx0XHRpZiAoIG1hdGVyaWFsLnRyYW5zbWlzc2lvbiA+IDAuMCApIHtcblxuXHRcdFx0dHJhbnNtaXNzaXZlLnB1c2goIHJlbmRlckl0ZW0gKTtcblxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLnRyYW5zcGFyZW50ID09PSB0cnVlICkge1xuXG5cdFx0XHR0cmFuc3BhcmVudC5wdXNoKCByZW5kZXJJdGVtICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRvcGFxdWUucHVzaCggcmVuZGVySXRlbSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB1bnNoaWZ0KCBvYmplY3QsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXBPcmRlciwgeiwgZ3JvdXAgKSB7XG5cblx0XHRjb25zdCByZW5kZXJJdGVtID0gZ2V0TmV4dFJlbmRlckl0ZW0oIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApO1xuXG5cdFx0aWYgKCBtYXRlcmlhbC50cmFuc21pc3Npb24gPiAwLjAgKSB7XG5cblx0XHRcdHRyYW5zbWlzc2l2ZS51bnNoaWZ0KCByZW5kZXJJdGVtICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC50cmFuc3BhcmVudCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0dHJhbnNwYXJlbnQudW5zaGlmdCggcmVuZGVySXRlbSApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0b3BhcXVlLnVuc2hpZnQoIHJlbmRlckl0ZW0gKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gc29ydCggY3VzdG9tT3BhcXVlU29ydCwgY3VzdG9tVHJhbnNwYXJlbnRTb3J0ICkge1xuXG5cdFx0aWYgKCBvcGFxdWUubGVuZ3RoID4gMSApIG9wYXF1ZS5zb3J0KCBjdXN0b21PcGFxdWVTb3J0IHx8IHBhaW50ZXJTb3J0U3RhYmxlICk7XG5cdFx0aWYgKCB0cmFuc21pc3NpdmUubGVuZ3RoID4gMSApIHRyYW5zbWlzc2l2ZS5zb3J0KCBjdXN0b21UcmFuc3BhcmVudFNvcnQgfHwgcmV2ZXJzZVBhaW50ZXJTb3J0U3RhYmxlICk7XG5cdFx0aWYgKCB0cmFuc3BhcmVudC5sZW5ndGggPiAxICkgdHJhbnNwYXJlbnQuc29ydCggY3VzdG9tVHJhbnNwYXJlbnRTb3J0IHx8IHJldmVyc2VQYWludGVyU29ydFN0YWJsZSApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBmaW5pc2goKSB7XG5cblx0XHQvLyBDbGVhciByZWZlcmVuY2VzIGZyb20gaW5hY3RpdmUgcmVuZGVySXRlbXMgaW4gdGhlIGxpc3RcblxuXHRcdGZvciAoIGxldCBpID0gcmVuZGVySXRlbXNJbmRleCwgaWwgPSByZW5kZXJJdGVtcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgcmVuZGVySXRlbSA9IHJlbmRlckl0ZW1zWyBpIF07XG5cblx0XHRcdGlmICggcmVuZGVySXRlbS5pZCA9PT0gbnVsbCApIGJyZWFrO1xuXG5cdFx0XHRyZW5kZXJJdGVtLmlkID0gbnVsbDtcblx0XHRcdHJlbmRlckl0ZW0ub2JqZWN0ID0gbnVsbDtcblx0XHRcdHJlbmRlckl0ZW0uZ2VvbWV0cnkgPSBudWxsO1xuXHRcdFx0cmVuZGVySXRlbS5tYXRlcmlhbCA9IG51bGw7XG5cdFx0XHRyZW5kZXJJdGVtLmdyb3VwID0gbnVsbDtcblxuXHRcdH1cblxuXHR9XG5cblx0cmV0dXJuIHtcblxuXHRcdG9wYXF1ZTogb3BhcXVlLFxuXHRcdHRyYW5zbWlzc2l2ZTogdHJhbnNtaXNzaXZlLFxuXHRcdHRyYW5zcGFyZW50OiB0cmFuc3BhcmVudCxcblxuXHRcdGluaXQ6IGluaXQsXG5cdFx0cHVzaDogcHVzaCxcblx0XHR1bnNoaWZ0OiB1bnNoaWZ0LFxuXHRcdGZpbmlzaDogZmluaXNoLFxuXG5cdFx0c29ydDogc29ydFxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMUmVuZGVyTGlzdHMoKSB7XG5cblx0bGV0IGxpc3RzID0gbmV3IFdlYWtNYXAoKTtcblxuXHRmdW5jdGlvbiBnZXQoIHNjZW5lLCByZW5kZXJDYWxsRGVwdGggKSB7XG5cblx0XHRjb25zdCBsaXN0QXJyYXkgPSBsaXN0cy5nZXQoIHNjZW5lICk7XG5cdFx0bGV0IGxpc3Q7XG5cblx0XHRpZiAoIGxpc3RBcnJheSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRsaXN0ID0gbmV3IFdlYkdMUmVuZGVyTGlzdCgpO1xuXHRcdFx0bGlzdHMuc2V0KCBzY2VuZSwgWyBsaXN0IF0gKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGlmICggcmVuZGVyQ2FsbERlcHRoID49IGxpc3RBcnJheS5sZW5ndGggKSB7XG5cblx0XHRcdFx0bGlzdCA9IG5ldyBXZWJHTFJlbmRlckxpc3QoKTtcblx0XHRcdFx0bGlzdEFycmF5LnB1c2goIGxpc3QgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRsaXN0ID0gbGlzdEFycmF5WyByZW5kZXJDYWxsRGVwdGggXTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGxpc3Q7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG5cblx0XHRsaXN0cyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0Z2V0OiBnZXQsXG5cdFx0ZGlzcG9zZTogZGlzcG9zZVxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFVuaWZvcm1zQ2FjaGUoKSB7XG5cblx0Y29uc3QgbGlnaHRzID0ge307XG5cblx0cmV0dXJuIHtcblxuXHRcdGdldDogZnVuY3Rpb24gKCBsaWdodCApIHtcblxuXHRcdFx0aWYgKCBsaWdodHNbIGxpZ2h0LmlkIF0gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRyZXR1cm4gbGlnaHRzWyBsaWdodC5pZCBdO1xuXG5cdFx0XHR9XG5cblx0XHRcdGxldCB1bmlmb3JtcztcblxuXHRcdFx0c3dpdGNoICggbGlnaHQudHlwZSApIHtcblxuXHRcdFx0XHRjYXNlICdEaXJlY3Rpb25hbExpZ2h0Jzpcblx0XHRcdFx0XHR1bmlmb3JtcyA9IHtcblx0XHRcdFx0XHRcdGRpcmVjdGlvbjogbmV3IFZlY3RvcjMoKSxcblx0XHRcdFx0XHRcdGNvbG9yOiBuZXcgQ29sb3IoKVxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAnU3BvdExpZ2h0Jzpcblx0XHRcdFx0XHR1bmlmb3JtcyA9IHtcblx0XHRcdFx0XHRcdHBvc2l0aW9uOiBuZXcgVmVjdG9yMygpLFxuXHRcdFx0XHRcdFx0ZGlyZWN0aW9uOiBuZXcgVmVjdG9yMygpLFxuXHRcdFx0XHRcdFx0Y29sb3I6IG5ldyBDb2xvcigpLFxuXHRcdFx0XHRcdFx0ZGlzdGFuY2U6IDAsXG5cdFx0XHRcdFx0XHRjb25lQ29zOiAwLFxuXHRcdFx0XHRcdFx0cGVudW1icmFDb3M6IDAsXG5cdFx0XHRcdFx0XHRkZWNheTogMFxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAnUG9pbnRMaWdodCc6XG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XG5cdFx0XHRcdFx0XHRwb3NpdGlvbjogbmV3IFZlY3RvcjMoKSxcblx0XHRcdFx0XHRcdGNvbG9yOiBuZXcgQ29sb3IoKSxcblx0XHRcdFx0XHRcdGRpc3RhbmNlOiAwLFxuXHRcdFx0XHRcdFx0ZGVjYXk6IDBcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgJ0hlbWlzcGhlcmVMaWdodCc6XG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XG5cdFx0XHRcdFx0XHRkaXJlY3Rpb246IG5ldyBWZWN0b3IzKCksXG5cdFx0XHRcdFx0XHRza3lDb2xvcjogbmV3IENvbG9yKCksXG5cdFx0XHRcdFx0XHRncm91bmRDb2xvcjogbmV3IENvbG9yKClcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgJ1JlY3RBcmVhTGlnaHQnOlxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xuXHRcdFx0XHRcdFx0Y29sb3I6IG5ldyBDb2xvcigpLFxuXHRcdFx0XHRcdFx0cG9zaXRpb246IG5ldyBWZWN0b3IzKCksXG5cdFx0XHRcdFx0XHRoYWxmV2lkdGg6IG5ldyBWZWN0b3IzKCksXG5cdFx0XHRcdFx0XHRoYWxmSGVpZ2h0OiBuZXcgVmVjdG9yMygpXG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0fVxuXG5cdFx0XHRsaWdodHNbIGxpZ2h0LmlkIF0gPSB1bmlmb3JtcztcblxuXHRcdFx0cmV0dXJuIHVuaWZvcm1zO1xuXG5cdFx0fVxuXG5cdH07XG5cbn1cblxuZnVuY3Rpb24gU2hhZG93VW5pZm9ybXNDYWNoZSgpIHtcblxuXHRjb25zdCBsaWdodHMgPSB7fTtcblxuXHRyZXR1cm4ge1xuXG5cdFx0Z2V0OiBmdW5jdGlvbiAoIGxpZ2h0ICkge1xuXG5cdFx0XHRpZiAoIGxpZ2h0c1sgbGlnaHQuaWQgXSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHJldHVybiBsaWdodHNbIGxpZ2h0LmlkIF07XG5cblx0XHRcdH1cblxuXHRcdFx0bGV0IHVuaWZvcm1zO1xuXG5cdFx0XHRzd2l0Y2ggKCBsaWdodC50eXBlICkge1xuXG5cdFx0XHRcdGNhc2UgJ0RpcmVjdGlvbmFsTGlnaHQnOlxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xuXHRcdFx0XHRcdFx0c2hhZG93SW50ZW5zaXR5OiAxLFxuXHRcdFx0XHRcdFx0c2hhZG93QmlhczogMCxcblx0XHRcdFx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IDAsXG5cdFx0XHRcdFx0XHRzaGFkb3dSYWRpdXM6IDEsXG5cdFx0XHRcdFx0XHRzaGFkb3dNYXBTaXplOiBuZXcgVmVjdG9yMigpXG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlICdTcG90TGlnaHQnOlxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xuXHRcdFx0XHRcdFx0c2hhZG93SW50ZW5zaXR5OiAxLFxuXHRcdFx0XHRcdFx0c2hhZG93QmlhczogMCxcblx0XHRcdFx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IDAsXG5cdFx0XHRcdFx0XHRzaGFkb3dSYWRpdXM6IDEsXG5cdFx0XHRcdFx0XHRzaGFkb3dNYXBTaXplOiBuZXcgVmVjdG9yMigpXG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlICdQb2ludExpZ2h0Jzpcblx0XHRcdFx0XHR1bmlmb3JtcyA9IHtcblx0XHRcdFx0XHRcdHNoYWRvd0ludGVuc2l0eTogMSxcblx0XHRcdFx0XHRcdHNoYWRvd0JpYXM6IDAsXG5cdFx0XHRcdFx0XHRzaGFkb3dOb3JtYWxCaWFzOiAwLFxuXHRcdFx0XHRcdFx0c2hhZG93UmFkaXVzOiAxLFxuXHRcdFx0XHRcdFx0c2hhZG93TWFwU2l6ZTogbmV3IFZlY3RvcjIoKSxcblx0XHRcdFx0XHRcdHNoYWRvd0NhbWVyYU5lYXI6IDEsXG5cdFx0XHRcdFx0XHRzaGFkb3dDYW1lcmFGYXI6IDEwMDBcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdC8vIFRPRE8gKGFiZWxuYXRpb24pOiBzZXQgUmVjdEFyZWFMaWdodCBzaGFkb3cgdW5pZm9ybXNcblxuXHRcdFx0fVxuXG5cdFx0XHRsaWdodHNbIGxpZ2h0LmlkIF0gPSB1bmlmb3JtcztcblxuXHRcdFx0cmV0dXJuIHVuaWZvcm1zO1xuXG5cdFx0fVxuXG5cdH07XG5cbn1cblxuXG5cbmxldCBuZXh0VmVyc2lvbiA9IDA7XG5cbmZ1bmN0aW9uIHNoYWRvd0Nhc3RpbmdBbmRUZXh0dXJpbmdMaWdodHNGaXJzdCggbGlnaHRBLCBsaWdodEIgKSB7XG5cblx0cmV0dXJuICggbGlnaHRCLmNhc3RTaGFkb3cgPyAyIDogMCApIC0gKCBsaWdodEEuY2FzdFNoYWRvdyA/IDIgOiAwICkgKyAoIGxpZ2h0Qi5tYXAgPyAxIDogMCApIC0gKCBsaWdodEEubWFwID8gMSA6IDAgKTtcblxufVxuXG5mdW5jdGlvbiBXZWJHTExpZ2h0cyggZXh0ZW5zaW9ucyApIHtcblxuXHRjb25zdCBjYWNoZSA9IG5ldyBVbmlmb3Jtc0NhY2hlKCk7XG5cblx0Y29uc3Qgc2hhZG93Q2FjaGUgPSBTaGFkb3dVbmlmb3Jtc0NhY2hlKCk7XG5cblx0Y29uc3Qgc3RhdGUgPSB7XG5cblx0XHR2ZXJzaW9uOiAwLFxuXG5cdFx0aGFzaDoge1xuXHRcdFx0ZGlyZWN0aW9uYWxMZW5ndGg6IC0gMSxcblx0XHRcdHBvaW50TGVuZ3RoOiAtIDEsXG5cdFx0XHRzcG90TGVuZ3RoOiAtIDEsXG5cdFx0XHRyZWN0QXJlYUxlbmd0aDogLSAxLFxuXHRcdFx0aGVtaUxlbmd0aDogLSAxLFxuXG5cdFx0XHRudW1EaXJlY3Rpb25hbFNoYWRvd3M6IC0gMSxcblx0XHRcdG51bVBvaW50U2hhZG93czogLSAxLFxuXHRcdFx0bnVtU3BvdFNoYWRvd3M6IC0gMSxcblx0XHRcdG51bVNwb3RNYXBzOiAtIDEsXG5cblx0XHRcdG51bUxpZ2h0UHJvYmVzOiAtIDFcblx0XHR9LFxuXG5cdFx0YW1iaWVudDogWyAwLCAwLCAwIF0sXG5cdFx0cHJvYmU6IFtdLFxuXHRcdGRpcmVjdGlvbmFsOiBbXSxcblx0XHRkaXJlY3Rpb25hbFNoYWRvdzogW10sXG5cdFx0ZGlyZWN0aW9uYWxTaGFkb3dNYXA6IFtdLFxuXHRcdGRpcmVjdGlvbmFsU2hhZG93TWF0cml4OiBbXSxcblx0XHRzcG90OiBbXSxcblx0XHRzcG90TGlnaHRNYXA6IFtdLFxuXHRcdHNwb3RTaGFkb3c6IFtdLFxuXHRcdHNwb3RTaGFkb3dNYXA6IFtdLFxuXHRcdHNwb3RMaWdodE1hdHJpeDogW10sXG5cdFx0cmVjdEFyZWE6IFtdLFxuXHRcdHJlY3RBcmVhTFRDMTogbnVsbCxcblx0XHRyZWN0QXJlYUxUQzI6IG51bGwsXG5cdFx0cG9pbnQ6IFtdLFxuXHRcdHBvaW50U2hhZG93OiBbXSxcblx0XHRwb2ludFNoYWRvd01hcDogW10sXG5cdFx0cG9pbnRTaGFkb3dNYXRyaXg6IFtdLFxuXHRcdGhlbWk6IFtdLFxuXHRcdG51bVNwb3RMaWdodFNoYWRvd3NXaXRoTWFwczogMCxcblx0XHRudW1MaWdodFByb2JlczogMFxuXG5cdH07XG5cblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHN0YXRlLnByb2JlLnB1c2goIG5ldyBWZWN0b3IzKCkgKTtcblxuXHRjb25zdCB2ZWN0b3IzID0gbmV3IFZlY3RvcjMoKTtcblx0Y29uc3QgbWF0cml4NCA9IG5ldyBNYXRyaXg0KCk7XG5cdGNvbnN0IG1hdHJpeDQyID0gbmV3IE1hdHJpeDQoKTtcblxuXHRmdW5jdGlvbiBzZXR1cCggbGlnaHRzICkge1xuXG5cdFx0bGV0IHIgPSAwLCBnID0gMCwgYiA9IDA7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkgc3RhdGUucHJvYmVbIGkgXS5zZXQoIDAsIDAsIDAgKTtcblxuXHRcdGxldCBkaXJlY3Rpb25hbExlbmd0aCA9IDA7XG5cdFx0bGV0IHBvaW50TGVuZ3RoID0gMDtcblx0XHRsZXQgc3BvdExlbmd0aCA9IDA7XG5cdFx0bGV0IHJlY3RBcmVhTGVuZ3RoID0gMDtcblx0XHRsZXQgaGVtaUxlbmd0aCA9IDA7XG5cblx0XHRsZXQgbnVtRGlyZWN0aW9uYWxTaGFkb3dzID0gMDtcblx0XHRsZXQgbnVtUG9pbnRTaGFkb3dzID0gMDtcblx0XHRsZXQgbnVtU3BvdFNoYWRvd3MgPSAwO1xuXHRcdGxldCBudW1TcG90TWFwcyA9IDA7XG5cdFx0bGV0IG51bVNwb3RTaGFkb3dzV2l0aE1hcHMgPSAwO1xuXG5cdFx0bGV0IG51bUxpZ2h0UHJvYmVzID0gMDtcblxuXHRcdC8vIG9yZGVyaW5nIDogW3NoYWRvdyBjYXN0aW5nICsgbWFwIHRleHR1cmluZywgbWFwIHRleHR1cmluZywgc2hhZG93IGNhc3RpbmcsIG5vbmUgXVxuXHRcdGxpZ2h0cy5zb3J0KCBzaGFkb3dDYXN0aW5nQW5kVGV4dHVyaW5nTGlnaHRzRmlyc3QgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGxpZ2h0cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBsaWdodCA9IGxpZ2h0c1sgaSBdO1xuXG5cdFx0XHRjb25zdCBjb2xvciA9IGxpZ2h0LmNvbG9yO1xuXHRcdFx0Y29uc3QgaW50ZW5zaXR5ID0gbGlnaHQuaW50ZW5zaXR5O1xuXHRcdFx0Y29uc3QgZGlzdGFuY2UgPSBsaWdodC5kaXN0YW5jZTtcblxuXHRcdFx0Y29uc3Qgc2hhZG93TWFwID0gKCBsaWdodC5zaGFkb3cgJiYgbGlnaHQuc2hhZG93Lm1hcCApID8gbGlnaHQuc2hhZG93Lm1hcC50ZXh0dXJlIDogbnVsbDtcblxuXHRcdFx0aWYgKCBsaWdodC5pc0FtYmllbnRMaWdodCApIHtcblxuXHRcdFx0XHRyICs9IGNvbG9yLnIgKiBpbnRlbnNpdHk7XG5cdFx0XHRcdGcgKz0gY29sb3IuZyAqIGludGVuc2l0eTtcblx0XHRcdFx0YiArPSBjb2xvci5iICogaW50ZW5zaXR5O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc0xpZ2h0UHJvYmUgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgOTsgaiArKyApIHtcblxuXHRcdFx0XHRcdHN0YXRlLnByb2JlWyBqIF0uYWRkU2NhbGVkVmVjdG9yKCBsaWdodC5zaC5jb2VmZmljaWVudHNbIGogXSwgaW50ZW5zaXR5ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdG51bUxpZ2h0UHJvYmVzICsrO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc0RpcmVjdGlvbmFsTGlnaHQgKSB7XG5cblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBjYWNoZS5nZXQoIGxpZ2h0ICk7XG5cblx0XHRcdFx0dW5pZm9ybXMuY29sb3IuY29weSggbGlnaHQuY29sb3IgKS5tdWx0aXBseVNjYWxhciggbGlnaHQuaW50ZW5zaXR5ICk7XG5cblx0XHRcdFx0aWYgKCBsaWdodC5jYXN0U2hhZG93ICkge1xuXG5cdFx0XHRcdFx0Y29uc3Qgc2hhZG93ID0gbGlnaHQuc2hhZG93O1xuXG5cdFx0XHRcdFx0Y29uc3Qgc2hhZG93VW5pZm9ybXMgPSBzaGFkb3dDYWNoZS5nZXQoIGxpZ2h0ICk7XG5cblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dJbnRlbnNpdHkgPSBzaGFkb3cuaW50ZW5zaXR5O1xuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0JpYXMgPSBzaGFkb3cuYmlhcztcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dOb3JtYWxCaWFzID0gc2hhZG93Lm5vcm1hbEJpYXM7XG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93UmFkaXVzID0gc2hhZG93LnJhZGl1cztcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dNYXBTaXplID0gc2hhZG93Lm1hcFNpemU7XG5cblx0XHRcdFx0XHRzdGF0ZS5kaXJlY3Rpb25hbFNoYWRvd1sgZGlyZWN0aW9uYWxMZW5ndGggXSA9IHNoYWRvd1VuaWZvcm1zO1xuXHRcdFx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWFwWyBkaXJlY3Rpb25hbExlbmd0aCBdID0gc2hhZG93TWFwO1xuXHRcdFx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWF0cml4WyBkaXJlY3Rpb25hbExlbmd0aCBdID0gbGlnaHQuc2hhZG93Lm1hdHJpeDtcblxuXHRcdFx0XHRcdG51bURpcmVjdGlvbmFsU2hhZG93cyArKztcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0c3RhdGUuZGlyZWN0aW9uYWxbIGRpcmVjdGlvbmFsTGVuZ3RoIF0gPSB1bmlmb3JtcztcblxuXHRcdFx0XHRkaXJlY3Rpb25hbExlbmd0aCArKztcblxuXHRcdFx0fSBlbHNlIGlmICggbGlnaHQuaXNTcG90TGlnaHQgKSB7XG5cblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBjYWNoZS5nZXQoIGxpZ2h0ICk7XG5cblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xuXG5cdFx0XHRcdHVuaWZvcm1zLmNvbG9yLmNvcHkoIGNvbG9yICkubXVsdGlwbHlTY2FsYXIoIGludGVuc2l0eSApO1xuXHRcdFx0XHR1bmlmb3Jtcy5kaXN0YW5jZSA9IGRpc3RhbmNlO1xuXG5cdFx0XHRcdHVuaWZvcm1zLmNvbmVDb3MgPSBNYXRoLmNvcyggbGlnaHQuYW5nbGUgKTtcblx0XHRcdFx0dW5pZm9ybXMucGVudW1icmFDb3MgPSBNYXRoLmNvcyggbGlnaHQuYW5nbGUgKiAoIDEgLSBsaWdodC5wZW51bWJyYSApICk7XG5cdFx0XHRcdHVuaWZvcm1zLmRlY2F5ID0gbGlnaHQuZGVjYXk7XG5cblx0XHRcdFx0c3RhdGUuc3BvdFsgc3BvdExlbmd0aCBdID0gdW5pZm9ybXM7XG5cblx0XHRcdFx0Y29uc3Qgc2hhZG93ID0gbGlnaHQuc2hhZG93O1xuXG5cdFx0XHRcdGlmICggbGlnaHQubWFwICkge1xuXG5cdFx0XHRcdFx0c3RhdGUuc3BvdExpZ2h0TWFwWyBudW1TcG90TWFwcyBdID0gbGlnaHQubWFwO1xuXHRcdFx0XHRcdG51bVNwb3RNYXBzICsrO1xuXG5cdFx0XHRcdFx0Ly8gbWFrZSBzdXJlIHRoZSBsaWdodE1hdHJpeCBpcyB1cCB0byBkYXRlXG5cdFx0XHRcdFx0Ly8gVE9ETyA6IGRvIGl0IGlmIHJlcXVpcmVkIG9ubHlcblx0XHRcdFx0XHRzaGFkb3cudXBkYXRlTWF0cmljZXMoIGxpZ2h0ICk7XG5cblx0XHRcdFx0XHRpZiAoIGxpZ2h0LmNhc3RTaGFkb3cgKSBudW1TcG90U2hhZG93c1dpdGhNYXBzICsrO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXRyaXhbIHNwb3RMZW5ndGggXSA9IHNoYWRvdy5tYXRyaXg7XG5cblx0XHRcdFx0aWYgKCBsaWdodC5jYXN0U2hhZG93ICkge1xuXG5cdFx0XHRcdFx0Y29uc3Qgc2hhZG93VW5pZm9ybXMgPSBzaGFkb3dDYWNoZS5nZXQoIGxpZ2h0ICk7XG5cblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dJbnRlbnNpdHkgPSBzaGFkb3cuaW50ZW5zaXR5O1xuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0JpYXMgPSBzaGFkb3cuYmlhcztcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dOb3JtYWxCaWFzID0gc2hhZG93Lm5vcm1hbEJpYXM7XG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93UmFkaXVzID0gc2hhZG93LnJhZGl1cztcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dNYXBTaXplID0gc2hhZG93Lm1hcFNpemU7XG5cblx0XHRcdFx0XHRzdGF0ZS5zcG90U2hhZG93WyBzcG90TGVuZ3RoIF0gPSBzaGFkb3dVbmlmb3Jtcztcblx0XHRcdFx0XHRzdGF0ZS5zcG90U2hhZG93TWFwWyBzcG90TGVuZ3RoIF0gPSBzaGFkb3dNYXA7XG5cblx0XHRcdFx0XHRudW1TcG90U2hhZG93cyArKztcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0c3BvdExlbmd0aCArKztcblxuXHRcdFx0fSBlbHNlIGlmICggbGlnaHQuaXNSZWN0QXJlYUxpZ2h0ICkge1xuXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gY2FjaGUuZ2V0KCBsaWdodCApO1xuXG5cdFx0XHRcdHVuaWZvcm1zLmNvbG9yLmNvcHkoIGNvbG9yICkubXVsdGlwbHlTY2FsYXIoIGludGVuc2l0eSApO1xuXG5cdFx0XHRcdHVuaWZvcm1zLmhhbGZXaWR0aC5zZXQoIGxpZ2h0LndpZHRoICogMC41LCAwLjAsIDAuMCApO1xuXHRcdFx0XHR1bmlmb3Jtcy5oYWxmSGVpZ2h0LnNldCggMC4wLCBsaWdodC5oZWlnaHQgKiAwLjUsIDAuMCApO1xuXG5cdFx0XHRcdHN0YXRlLnJlY3RBcmVhWyByZWN0QXJlYUxlbmd0aCBdID0gdW5pZm9ybXM7XG5cblx0XHRcdFx0cmVjdEFyZWFMZW5ndGggKys7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzUG9pbnRMaWdodCApIHtcblxuXHRcdFx0XHRjb25zdCB1bmlmb3JtcyA9IGNhY2hlLmdldCggbGlnaHQgKTtcblxuXHRcdFx0XHR1bmlmb3Jtcy5jb2xvci5jb3B5KCBsaWdodC5jb2xvciApLm11bHRpcGx5U2NhbGFyKCBsaWdodC5pbnRlbnNpdHkgKTtcblx0XHRcdFx0dW5pZm9ybXMuZGlzdGFuY2UgPSBsaWdodC5kaXN0YW5jZTtcblx0XHRcdFx0dW5pZm9ybXMuZGVjYXkgPSBsaWdodC5kZWNheTtcblxuXHRcdFx0XHRpZiAoIGxpZ2h0LmNhc3RTaGFkb3cgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBzaGFkb3cgPSBsaWdodC5zaGFkb3c7XG5cblx0XHRcdFx0XHRjb25zdCBzaGFkb3dVbmlmb3JtcyA9IHNoYWRvd0NhY2hlLmdldCggbGlnaHQgKTtcblxuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0ludGVuc2l0eSA9IHNoYWRvdy5pbnRlbnNpdHk7XG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93QmlhcyA9IHNoYWRvdy5iaWFzO1xuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd05vcm1hbEJpYXMgPSBzaGFkb3cubm9ybWFsQmlhcztcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dSYWRpdXMgPSBzaGFkb3cucmFkaXVzO1xuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd01hcFNpemUgPSBzaGFkb3cubWFwU2l6ZTtcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dDYW1lcmFOZWFyID0gc2hhZG93LmNhbWVyYS5uZWFyO1xuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0NhbWVyYUZhciA9IHNoYWRvdy5jYW1lcmEuZmFyO1xuXG5cdFx0XHRcdFx0c3RhdGUucG9pbnRTaGFkb3dbIHBvaW50TGVuZ3RoIF0gPSBzaGFkb3dVbmlmb3Jtcztcblx0XHRcdFx0XHRzdGF0ZS5wb2ludFNoYWRvd01hcFsgcG9pbnRMZW5ndGggXSA9IHNoYWRvd01hcDtcblx0XHRcdFx0XHRzdGF0ZS5wb2ludFNoYWRvd01hdHJpeFsgcG9pbnRMZW5ndGggXSA9IGxpZ2h0LnNoYWRvdy5tYXRyaXg7XG5cblx0XHRcdFx0XHRudW1Qb2ludFNoYWRvd3MgKys7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHN0YXRlLnBvaW50WyBwb2ludExlbmd0aCBdID0gdW5pZm9ybXM7XG5cblx0XHRcdFx0cG9pbnRMZW5ndGggKys7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzSGVtaXNwaGVyZUxpZ2h0ICkge1xuXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gY2FjaGUuZ2V0KCBsaWdodCApO1xuXG5cdFx0XHRcdHVuaWZvcm1zLnNreUNvbG9yLmNvcHkoIGxpZ2h0LmNvbG9yICkubXVsdGlwbHlTY2FsYXIoIGludGVuc2l0eSApO1xuXHRcdFx0XHR1bmlmb3Jtcy5ncm91bmRDb2xvci5jb3B5KCBsaWdodC5ncm91bmRDb2xvciApLm11bHRpcGx5U2NhbGFyKCBpbnRlbnNpdHkgKTtcblxuXHRcdFx0XHRzdGF0ZS5oZW1pWyBoZW1pTGVuZ3RoIF0gPSB1bmlmb3JtcztcblxuXHRcdFx0XHRoZW1pTGVuZ3RoICsrO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIHJlY3RBcmVhTGVuZ3RoID4gMCApIHtcblxuXHRcdFx0aWYgKCBleHRlbnNpb25zLmhhcyggJ09FU190ZXh0dXJlX2Zsb2F0X2xpbmVhcicgKSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRzdGF0ZS5yZWN0QXJlYUxUQzEgPSBVbmlmb3Jtc0xpYi5MVENfRkxPQVRfMTtcblx0XHRcdFx0c3RhdGUucmVjdEFyZWFMVEMyID0gVW5pZm9ybXNMaWIuTFRDX0ZMT0FUXzI7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0c3RhdGUucmVjdEFyZWFMVEMxID0gVW5pZm9ybXNMaWIuTFRDX0hBTEZfMTtcblx0XHRcdFx0c3RhdGUucmVjdEFyZWFMVEMyID0gVW5pZm9ybXNMaWIuTFRDX0hBTEZfMjtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0c3RhdGUuYW1iaWVudFsgMCBdID0gcjtcblx0XHRzdGF0ZS5hbWJpZW50WyAxIF0gPSBnO1xuXHRcdHN0YXRlLmFtYmllbnRbIDIgXSA9IGI7XG5cblx0XHRjb25zdCBoYXNoID0gc3RhdGUuaGFzaDtcblxuXHRcdGlmICggaGFzaC5kaXJlY3Rpb25hbExlbmd0aCAhPT0gZGlyZWN0aW9uYWxMZW5ndGggfHxcblx0XHRcdGhhc2gucG9pbnRMZW5ndGggIT09IHBvaW50TGVuZ3RoIHx8XG5cdFx0XHRoYXNoLnNwb3RMZW5ndGggIT09IHNwb3RMZW5ndGggfHxcblx0XHRcdGhhc2gucmVjdEFyZWFMZW5ndGggIT09IHJlY3RBcmVhTGVuZ3RoIHx8XG5cdFx0XHRoYXNoLmhlbWlMZW5ndGggIT09IGhlbWlMZW5ndGggfHxcblx0XHRcdGhhc2gubnVtRGlyZWN0aW9uYWxTaGFkb3dzICE9PSBudW1EaXJlY3Rpb25hbFNoYWRvd3MgfHxcblx0XHRcdGhhc2gubnVtUG9pbnRTaGFkb3dzICE9PSBudW1Qb2ludFNoYWRvd3MgfHxcblx0XHRcdGhhc2gubnVtU3BvdFNoYWRvd3MgIT09IG51bVNwb3RTaGFkb3dzIHx8XG5cdFx0XHRoYXNoLm51bVNwb3RNYXBzICE9PSBudW1TcG90TWFwcyB8fFxuXHRcdFx0aGFzaC5udW1MaWdodFByb2JlcyAhPT0gbnVtTGlnaHRQcm9iZXMgKSB7XG5cblx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsLmxlbmd0aCA9IGRpcmVjdGlvbmFsTGVuZ3RoO1xuXHRcdFx0c3RhdGUuc3BvdC5sZW5ndGggPSBzcG90TGVuZ3RoO1xuXHRcdFx0c3RhdGUucmVjdEFyZWEubGVuZ3RoID0gcmVjdEFyZWFMZW5ndGg7XG5cdFx0XHRzdGF0ZS5wb2ludC5sZW5ndGggPSBwb2ludExlbmd0aDtcblx0XHRcdHN0YXRlLmhlbWkubGVuZ3RoID0gaGVtaUxlbmd0aDtcblxuXHRcdFx0c3RhdGUuZGlyZWN0aW9uYWxTaGFkb3cubGVuZ3RoID0gbnVtRGlyZWN0aW9uYWxTaGFkb3dzO1xuXHRcdFx0c3RhdGUuZGlyZWN0aW9uYWxTaGFkb3dNYXAubGVuZ3RoID0gbnVtRGlyZWN0aW9uYWxTaGFkb3dzO1xuXHRcdFx0c3RhdGUucG9pbnRTaGFkb3cubGVuZ3RoID0gbnVtUG9pbnRTaGFkb3dzO1xuXHRcdFx0c3RhdGUucG9pbnRTaGFkb3dNYXAubGVuZ3RoID0gbnVtUG9pbnRTaGFkb3dzO1xuXHRcdFx0c3RhdGUuc3BvdFNoYWRvdy5sZW5ndGggPSBudW1TcG90U2hhZG93cztcblx0XHRcdHN0YXRlLnNwb3RTaGFkb3dNYXAubGVuZ3RoID0gbnVtU3BvdFNoYWRvd3M7XG5cdFx0XHRzdGF0ZS5kaXJlY3Rpb25hbFNoYWRvd01hdHJpeC5sZW5ndGggPSBudW1EaXJlY3Rpb25hbFNoYWRvd3M7XG5cdFx0XHRzdGF0ZS5wb2ludFNoYWRvd01hdHJpeC5sZW5ndGggPSBudW1Qb2ludFNoYWRvd3M7XG5cdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXRyaXgubGVuZ3RoID0gbnVtU3BvdFNoYWRvd3MgKyBudW1TcG90TWFwcyAtIG51bVNwb3RTaGFkb3dzV2l0aE1hcHM7XG5cdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXAubGVuZ3RoID0gbnVtU3BvdE1hcHM7XG5cdFx0XHRzdGF0ZS5udW1TcG90TGlnaHRTaGFkb3dzV2l0aE1hcHMgPSBudW1TcG90U2hhZG93c1dpdGhNYXBzO1xuXHRcdFx0c3RhdGUubnVtTGlnaHRQcm9iZXMgPSBudW1MaWdodFByb2JlcztcblxuXHRcdFx0aGFzaC5kaXJlY3Rpb25hbExlbmd0aCA9IGRpcmVjdGlvbmFsTGVuZ3RoO1xuXHRcdFx0aGFzaC5wb2ludExlbmd0aCA9IHBvaW50TGVuZ3RoO1xuXHRcdFx0aGFzaC5zcG90TGVuZ3RoID0gc3BvdExlbmd0aDtcblx0XHRcdGhhc2gucmVjdEFyZWFMZW5ndGggPSByZWN0QXJlYUxlbmd0aDtcblx0XHRcdGhhc2guaGVtaUxlbmd0aCA9IGhlbWlMZW5ndGg7XG5cblx0XHRcdGhhc2gubnVtRGlyZWN0aW9uYWxTaGFkb3dzID0gbnVtRGlyZWN0aW9uYWxTaGFkb3dzO1xuXHRcdFx0aGFzaC5udW1Qb2ludFNoYWRvd3MgPSBudW1Qb2ludFNoYWRvd3M7XG5cdFx0XHRoYXNoLm51bVNwb3RTaGFkb3dzID0gbnVtU3BvdFNoYWRvd3M7XG5cdFx0XHRoYXNoLm51bVNwb3RNYXBzID0gbnVtU3BvdE1hcHM7XG5cblx0XHRcdGhhc2gubnVtTGlnaHRQcm9iZXMgPSBudW1MaWdodFByb2JlcztcblxuXHRcdFx0c3RhdGUudmVyc2lvbiA9IG5leHRWZXJzaW9uICsrO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBzZXR1cFZpZXcoIGxpZ2h0cywgY2FtZXJhICkge1xuXG5cdFx0bGV0IGRpcmVjdGlvbmFsTGVuZ3RoID0gMDtcblx0XHRsZXQgcG9pbnRMZW5ndGggPSAwO1xuXHRcdGxldCBzcG90TGVuZ3RoID0gMDtcblx0XHRsZXQgcmVjdEFyZWFMZW5ndGggPSAwO1xuXHRcdGxldCBoZW1pTGVuZ3RoID0gMDtcblxuXHRcdGNvbnN0IHZpZXdNYXRyaXggPSBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gbGlnaHRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGxpZ2h0ID0gbGlnaHRzWyBpIF07XG5cblx0XHRcdGlmICggbGlnaHQuaXNEaXJlY3Rpb25hbExpZ2h0ICkge1xuXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gc3RhdGUuZGlyZWN0aW9uYWxbIGRpcmVjdGlvbmFsTGVuZ3RoIF07XG5cblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcblx0XHRcdFx0dmVjdG9yMy5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGxpZ2h0LnRhcmdldC5tYXRyaXhXb3JsZCApO1xuXHRcdFx0XHR1bmlmb3Jtcy5kaXJlY3Rpb24uc3ViKCB2ZWN0b3IzICk7XG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi50cmFuc2Zvcm1EaXJlY3Rpb24oIHZpZXdNYXRyaXggKTtcblxuXHRcdFx0XHRkaXJlY3Rpb25hbExlbmd0aCArKztcblxuXHRcdFx0fSBlbHNlIGlmICggbGlnaHQuaXNTcG90TGlnaHQgKSB7XG5cblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBzdGF0ZS5zcG90WyBzcG90TGVuZ3RoIF07XG5cblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xuXHRcdFx0XHR1bmlmb3Jtcy5wb3NpdGlvbi5hcHBseU1hdHJpeDQoIHZpZXdNYXRyaXggKTtcblxuXHRcdFx0XHR1bmlmb3Jtcy5kaXJlY3Rpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xuXHRcdFx0XHR2ZWN0b3IzLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQudGFyZ2V0Lm1hdHJpeFdvcmxkICk7XG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi5zdWIoIHZlY3RvcjMgKTtcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnRyYW5zZm9ybURpcmVjdGlvbiggdmlld01hdHJpeCApO1xuXG5cdFx0XHRcdHNwb3RMZW5ndGggKys7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzUmVjdEFyZWFMaWdodCApIHtcblxuXHRcdFx0XHRjb25zdCB1bmlmb3JtcyA9IHN0YXRlLnJlY3RBcmVhWyByZWN0QXJlYUxlbmd0aCBdO1xuXG5cdFx0XHRcdHVuaWZvcm1zLnBvc2l0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uYXBwbHlNYXRyaXg0KCB2aWV3TWF0cml4ICk7XG5cblx0XHRcdFx0Ly8gZXh0cmFjdCBsb2NhbCByb3RhdGlvbiBvZiBsaWdodCB0byBkZXJpdmUgd2lkdGgvaGVpZ2h0IGhhbGYgdmVjdG9yc1xuXHRcdFx0XHRtYXRyaXg0Mi5pZGVudGl0eSgpO1xuXHRcdFx0XHRtYXRyaXg0LmNvcHkoIGxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cdFx0XHRcdG1hdHJpeDQucHJlbXVsdGlwbHkoIHZpZXdNYXRyaXggKTtcblx0XHRcdFx0bWF0cml4NDIuZXh0cmFjdFJvdGF0aW9uKCBtYXRyaXg0ICk7XG5cblx0XHRcdFx0dW5pZm9ybXMuaGFsZldpZHRoLnNldCggbGlnaHQud2lkdGggKiAwLjUsIDAuMCwgMC4wICk7XG5cdFx0XHRcdHVuaWZvcm1zLmhhbGZIZWlnaHQuc2V0KCAwLjAsIGxpZ2h0LmhlaWdodCAqIDAuNSwgMC4wICk7XG5cblx0XHRcdFx0dW5pZm9ybXMuaGFsZldpZHRoLmFwcGx5TWF0cml4NCggbWF0cml4NDIgKTtcblx0XHRcdFx0dW5pZm9ybXMuaGFsZkhlaWdodC5hcHBseU1hdHJpeDQoIG1hdHJpeDQyICk7XG5cblx0XHRcdFx0cmVjdEFyZWFMZW5ndGggKys7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzUG9pbnRMaWdodCApIHtcblxuXHRcdFx0XHRjb25zdCB1bmlmb3JtcyA9IHN0YXRlLnBvaW50WyBwb2ludExlbmd0aCBdO1xuXG5cdFx0XHRcdHVuaWZvcm1zLnBvc2l0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uYXBwbHlNYXRyaXg0KCB2aWV3TWF0cml4ICk7XG5cblx0XHRcdFx0cG9pbnRMZW5ndGggKys7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzSGVtaXNwaGVyZUxpZ2h0ICkge1xuXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gc3RhdGUuaGVtaVsgaGVtaUxlbmd0aCBdO1xuXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi50cmFuc2Zvcm1EaXJlY3Rpb24oIHZpZXdNYXRyaXggKTtcblxuXHRcdFx0XHRoZW1pTGVuZ3RoICsrO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0c2V0dXA6IHNldHVwLFxuXHRcdHNldHVwVmlldzogc2V0dXBWaWV3LFxuXHRcdHN0YXRlOiBzdGF0ZVxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMUmVuZGVyU3RhdGUoIGV4dGVuc2lvbnMgKSB7XG5cblx0Y29uc3QgbGlnaHRzID0gbmV3IFdlYkdMTGlnaHRzKCBleHRlbnNpb25zICk7XG5cblx0Y29uc3QgbGlnaHRzQXJyYXkgPSBbXTtcblx0Y29uc3Qgc2hhZG93c0FycmF5ID0gW107XG5cblx0ZnVuY3Rpb24gaW5pdCggY2FtZXJhICkge1xuXG5cdFx0c3RhdGUuY2FtZXJhID0gY2FtZXJhO1xuXG5cdFx0bGlnaHRzQXJyYXkubGVuZ3RoID0gMDtcblx0XHRzaGFkb3dzQXJyYXkubGVuZ3RoID0gMDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gcHVzaExpZ2h0KCBsaWdodCApIHtcblxuXHRcdGxpZ2h0c0FycmF5LnB1c2goIGxpZ2h0ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHB1c2hTaGFkb3coIHNoYWRvd0xpZ2h0ICkge1xuXG5cdFx0c2hhZG93c0FycmF5LnB1c2goIHNoYWRvd0xpZ2h0ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHNldHVwTGlnaHRzKCkge1xuXG5cdFx0bGlnaHRzLnNldHVwKCBsaWdodHNBcnJheSApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBzZXR1cExpZ2h0c1ZpZXcoIGNhbWVyYSApIHtcblxuXHRcdGxpZ2h0cy5zZXR1cFZpZXcoIGxpZ2h0c0FycmF5LCBjYW1lcmEgKTtcblxuXHR9XG5cblx0Y29uc3Qgc3RhdGUgPSB7XG5cdFx0bGlnaHRzQXJyYXk6IGxpZ2h0c0FycmF5LFxuXHRcdHNoYWRvd3NBcnJheTogc2hhZG93c0FycmF5LFxuXG5cdFx0Y2FtZXJhOiBudWxsLFxuXG5cdFx0bGlnaHRzOiBsaWdodHMsXG5cblx0XHR0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQ6IHt9XG5cdH07XG5cblx0cmV0dXJuIHtcblx0XHRpbml0OiBpbml0LFxuXHRcdHN0YXRlOiBzdGF0ZSxcblx0XHRzZXR1cExpZ2h0czogc2V0dXBMaWdodHMsXG5cdFx0c2V0dXBMaWdodHNWaWV3OiBzZXR1cExpZ2h0c1ZpZXcsXG5cblx0XHRwdXNoTGlnaHQ6IHB1c2hMaWdodCxcblx0XHRwdXNoU2hhZG93OiBwdXNoU2hhZG93XG5cdH07XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xSZW5kZXJTdGF0ZXMoIGV4dGVuc2lvbnMgKSB7XG5cblx0bGV0IHJlbmRlclN0YXRlcyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0ZnVuY3Rpb24gZ2V0KCBzY2VuZSwgcmVuZGVyQ2FsbERlcHRoID0gMCApIHtcblxuXHRcdGNvbnN0IHJlbmRlclN0YXRlQXJyYXkgPSByZW5kZXJTdGF0ZXMuZ2V0KCBzY2VuZSApO1xuXHRcdGxldCByZW5kZXJTdGF0ZTtcblxuXHRcdGlmICggcmVuZGVyU3RhdGVBcnJheSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRyZW5kZXJTdGF0ZSA9IG5ldyBXZWJHTFJlbmRlclN0YXRlKCBleHRlbnNpb25zICk7XG5cdFx0XHRyZW5kZXJTdGF0ZXMuc2V0KCBzY2VuZSwgWyByZW5kZXJTdGF0ZSBdICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIHJlbmRlckNhbGxEZXB0aCA+PSByZW5kZXJTdGF0ZUFycmF5Lmxlbmd0aCApIHtcblxuXHRcdFx0XHRyZW5kZXJTdGF0ZSA9IG5ldyBXZWJHTFJlbmRlclN0YXRlKCBleHRlbnNpb25zICk7XG5cdFx0XHRcdHJlbmRlclN0YXRlQXJyYXkucHVzaCggcmVuZGVyU3RhdGUgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRyZW5kZXJTdGF0ZSA9IHJlbmRlclN0YXRlQXJyYXlbIHJlbmRlckNhbGxEZXB0aCBdO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcmVuZGVyU3RhdGU7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG5cblx0XHRyZW5kZXJTdGF0ZXMgPSBuZXcgV2Vha01hcCgpO1xuXG5cdH1cblxuXHRyZXR1cm4ge1xuXHRcdGdldDogZ2V0LFxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2Vcblx0fTtcblxufVxuXG5jbGFzcyBNZXNoRGVwdGhNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTWVzaERlcHRoTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ01lc2hEZXB0aE1hdGVyaWFsJztcblxuXHRcdHRoaXMuZGVwdGhQYWNraW5nID0gQmFzaWNEZXB0aFBhY2tpbmc7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XG5cblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuZGVwdGhQYWNraW5nID0gc291cmNlLmRlcHRoUGFja2luZztcblxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBzb3VyY2UuYWxwaGFNYXA7XG5cblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IHNvdXJjZS5kaXNwbGFjZW1lbnRTY2FsZTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcblxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgTWVzaERpc3RhbmNlTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc01lc2hEaXN0YW5jZU1hdGVyaWFsID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdNZXNoRGlzdGFuY2VNYXRlcmlhbCc7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xuXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xuXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBzb3VyY2UuZGlzcGxhY2VtZW50TWFwO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY29uc3QgdmVydGV4ID0gXCJ2b2lkIG1haW4oKSB7XFxuXFx0Z2xfUG9zaXRpb24gPSB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCA9IFwidW5pZm9ybSBzYW1wbGVyMkQgc2hhZG93X3Bhc3M7XFxudW5pZm9ybSB2ZWMyIHJlc29sdXRpb247XFxudW5pZm9ybSBmbG9hdCByYWRpdXM7XFxuI2luY2x1ZGUgPHBhY2tpbmc+XFxudm9pZCBtYWluKCkge1xcblxcdGNvbnN0IGZsb2F0IHNhbXBsZXMgPSBmbG9hdCggVlNNX1NBTVBMRVMgKTtcXG5cXHRmbG9hdCBtZWFuID0gMC4wO1xcblxcdGZsb2F0IHNxdWFyZWRfbWVhbiA9IDAuMDtcXG5cXHRmbG9hdCB1dlN0cmlkZSA9IHNhbXBsZXMgPD0gMS4wID8gMC4wIDogMi4wIC8gKCBzYW1wbGVzIC0gMS4wICk7XFxuXFx0ZmxvYXQgdXZTdGFydCA9IHNhbXBsZXMgPD0gMS4wID8gMC4wIDogLSAxLjA7XFxuXFx0Zm9yICggZmxvYXQgaSA9IDAuMDsgaSA8IHNhbXBsZXM7IGkgKysgKSB7XFxuXFx0XFx0ZmxvYXQgdXZPZmZzZXQgPSB1dlN0YXJ0ICsgaSAqIHV2U3RyaWRlO1xcblxcdFxcdCNpZmRlZiBIT1JJWk9OVEFMX1BBU1NcXG5cXHRcXHRcXHR2ZWMyIGRpc3RyaWJ1dGlvbiA9IHVucGFja1JHQkFUbzJIYWxmKCB0ZXh0dXJlMkQoIHNoYWRvd19wYXNzLCAoIGdsX0ZyYWdDb29yZC54eSArIHZlYzIoIHV2T2Zmc2V0LCAwLjAgKSAqIHJhZGl1cyApIC8gcmVzb2x1dGlvbiApICk7XFxuXFx0XFx0XFx0bWVhbiArPSBkaXN0cmlidXRpb24ueDtcXG5cXHRcXHRcXHRzcXVhcmVkX21lYW4gKz0gZGlzdHJpYnV0aW9uLnkgKiBkaXN0cmlidXRpb24ueSArIGRpc3RyaWJ1dGlvbi54ICogZGlzdHJpYnV0aW9uLng7XFxuXFx0XFx0I2Vsc2VcXG5cXHRcXHRcXHRmbG9hdCBkZXB0aCA9IHVucGFja1JHQkFUb0RlcHRoKCB0ZXh0dXJlMkQoIHNoYWRvd19wYXNzLCAoIGdsX0ZyYWdDb29yZC54eSArIHZlYzIoIDAuMCwgdXZPZmZzZXQgKSAqIHJhZGl1cyApIC8gcmVzb2x1dGlvbiApICk7XFxuXFx0XFx0XFx0bWVhbiArPSBkZXB0aDtcXG5cXHRcXHRcXHRzcXVhcmVkX21lYW4gKz0gZGVwdGggKiBkZXB0aDtcXG5cXHRcXHQjZW5kaWZcXG5cXHR9XFxuXFx0bWVhbiA9IG1lYW4gLyBzYW1wbGVzO1xcblxcdHNxdWFyZWRfbWVhbiA9IHNxdWFyZWRfbWVhbiAvIHNhbXBsZXM7XFxuXFx0ZmxvYXQgc3RkX2RldiA9IHNxcnQoIHNxdWFyZWRfbWVhbiAtIG1lYW4gKiBtZWFuICk7XFxuXFx0Z2xfRnJhZ0NvbG9yID0gcGFjazJIYWxmVG9SR0JBKCB2ZWMyKCBtZWFuLCBzdGRfZGV2ICkgKTtcXG59XCI7XG5cbmZ1bmN0aW9uIFdlYkdMU2hhZG93TWFwKCByZW5kZXJlciwgb2JqZWN0cywgY2FwYWJpbGl0aWVzICkge1xuXG5cdGxldCBfZnJ1c3R1bSA9IG5ldyBGcnVzdHVtKCk7XG5cblx0Y29uc3QgX3NoYWRvd01hcFNpemUgPSBuZXcgVmVjdG9yMigpLFxuXHRcdF92aWV3cG9ydFNpemUgPSBuZXcgVmVjdG9yMigpLFxuXG5cdFx0X3ZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKSxcblxuXHRcdF9kZXB0aE1hdGVyaWFsID0gbmV3IE1lc2hEZXB0aE1hdGVyaWFsKCB7IGRlcHRoUGFja2luZzogUkdCQURlcHRoUGFja2luZyB9ICksXG5cdFx0X2Rpc3RhbmNlTWF0ZXJpYWwgPSBuZXcgTWVzaERpc3RhbmNlTWF0ZXJpYWwoKSxcblxuXHRcdF9tYXRlcmlhbENhY2hlID0ge30sXG5cblx0XHRfbWF4VGV4dHVyZVNpemUgPSBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemU7XG5cblx0Y29uc3Qgc2hhZG93U2lkZSA9IHsgWyBGcm9udFNpZGUgXTogQmFja1NpZGUsIFsgQmFja1NpZGUgXTogRnJvbnRTaWRlLCBbIERvdWJsZVNpZGUgXTogRG91YmxlU2lkZSB9O1xuXG5cdGNvbnN0IHNoYWRvd01hdGVyaWFsVmVydGljYWwgPSBuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcblx0XHRkZWZpbmVzOiB7XG5cdFx0XHRWU01fU0FNUExFUzogOFxuXHRcdH0sXG5cdFx0dW5pZm9ybXM6IHtcblx0XHRcdHNoYWRvd19wYXNzOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRyZXNvbHV0aW9uOiB7IHZhbHVlOiBuZXcgVmVjdG9yMigpIH0sXG5cdFx0XHRyYWRpdXM6IHsgdmFsdWU6IDQuMCB9XG5cdFx0fSxcblxuXHRcdHZlcnRleFNoYWRlcjogdmVydGV4LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBmcmFnbWVudFxuXG5cdH0gKTtcblxuXHRjb25zdCBzaGFkb3dNYXRlcmlhbEhvcml6b250YWwgPSBzaGFkb3dNYXRlcmlhbFZlcnRpY2FsLmNsb25lKCk7XG5cdHNoYWRvd01hdGVyaWFsSG9yaXpvbnRhbC5kZWZpbmVzLkhPUklaT05UQUxfUEFTUyA9IDE7XG5cblx0Y29uc3QgZnVsbFNjcmVlblRyaSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXHRmdWxsU2NyZWVuVHJpLnNldEF0dHJpYnV0ZShcblx0XHQncG9zaXRpb24nLFxuXHRcdG5ldyBCdWZmZXJBdHRyaWJ1dGUoXG5cdFx0XHRuZXcgRmxvYXQzMkFycmF5KCBbIC0gMSwgLSAxLCAwLjUsIDMsIC0gMSwgMC41LCAtIDEsIDMsIDAuNSBdICksXG5cdFx0XHQzXG5cdFx0KVxuXHQpO1xuXG5cdGNvbnN0IGZ1bGxTY3JlZW5NZXNoID0gbmV3IE1lc2goIGZ1bGxTY3JlZW5UcmksIHNoYWRvd01hdGVyaWFsVmVydGljYWwgKTtcblxuXHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0dGhpcy5lbmFibGVkID0gZmFsc2U7XG5cblx0dGhpcy5hdXRvVXBkYXRlID0gdHJ1ZTtcblx0dGhpcy5uZWVkc1VwZGF0ZSA9IGZhbHNlO1xuXG5cdHRoaXMudHlwZSA9IFBDRlNoYWRvd01hcDtcblx0bGV0IF9wcmV2aW91c1R5cGUgPSB0aGlzLnR5cGU7XG5cblx0dGhpcy5yZW5kZXIgPSBmdW5jdGlvbiAoIGxpZ2h0cywgc2NlbmUsIGNhbWVyYSApIHtcblxuXHRcdGlmICggc2NvcGUuZW5hYmxlZCA9PT0gZmFsc2UgKSByZXR1cm47XG5cdFx0aWYgKCBzY29wZS5hdXRvVXBkYXRlID09PSBmYWxzZSAmJiBzY29wZS5uZWVkc1VwZGF0ZSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHRpZiAoIGxpZ2h0cy5sZW5ndGggPT09IDAgKSByZXR1cm47XG5cblx0XHRjb25zdCBjdXJyZW50UmVuZGVyVGFyZ2V0ID0gcmVuZGVyZXIuZ2V0UmVuZGVyVGFyZ2V0KCk7XG5cdFx0Y29uc3QgYWN0aXZlQ3ViZUZhY2UgPSByZW5kZXJlci5nZXRBY3RpdmVDdWJlRmFjZSgpO1xuXHRcdGNvbnN0IGFjdGl2ZU1pcG1hcExldmVsID0gcmVuZGVyZXIuZ2V0QWN0aXZlTWlwbWFwTGV2ZWwoKTtcblxuXHRcdGNvbnN0IF9zdGF0ZSA9IHJlbmRlcmVyLnN0YXRlO1xuXG5cdFx0Ly8gU2V0IEdMIHN0YXRlIGZvciBkZXB0aCBtYXAuXG5cdFx0X3N0YXRlLnNldEJsZW5kaW5nKCBOb0JsZW5kaW5nICk7XG5cdFx0X3N0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0Q2xlYXIoIDEsIDEsIDEsIDEgKTtcblx0XHRfc3RhdGUuYnVmZmVycy5kZXB0aC5zZXRUZXN0KCB0cnVlICk7XG5cdFx0X3N0YXRlLnNldFNjaXNzb3JUZXN0KCBmYWxzZSApO1xuXG5cdFx0Ly8gY2hlY2sgZm9yIHNoYWRvdyBtYXAgdHlwZSBjaGFuZ2VzXG5cblx0XHRjb25zdCB0b1ZTTSA9ICggX3ByZXZpb3VzVHlwZSAhPT0gVlNNU2hhZG93TWFwICYmIHRoaXMudHlwZSA9PT0gVlNNU2hhZG93TWFwICk7XG5cdFx0Y29uc3QgZnJvbVZTTSA9ICggX3ByZXZpb3VzVHlwZSA9PT0gVlNNU2hhZG93TWFwICYmIHRoaXMudHlwZSAhPT0gVlNNU2hhZG93TWFwICk7XG5cblx0XHQvLyByZW5kZXIgZGVwdGggbWFwXG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbGlnaHRzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBsaWdodCA9IGxpZ2h0c1sgaSBdO1xuXHRcdFx0Y29uc3Qgc2hhZG93ID0gbGlnaHQuc2hhZG93O1xuXG5cdFx0XHRpZiAoIHNoYWRvdyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMU2hhZG93TWFwOicsIGxpZ2h0LCAnaGFzIG5vIHNoYWRvdy4nICk7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggc2hhZG93LmF1dG9VcGRhdGUgPT09IGZhbHNlICYmIHNoYWRvdy5uZWVkc1VwZGF0ZSA9PT0gZmFsc2UgKSBjb250aW51ZTtcblxuXHRcdFx0X3NoYWRvd01hcFNpemUuY29weSggc2hhZG93Lm1hcFNpemUgKTtcblxuXHRcdFx0Y29uc3Qgc2hhZG93RnJhbWVFeHRlbnRzID0gc2hhZG93LmdldEZyYW1lRXh0ZW50cygpO1xuXG5cdFx0XHRfc2hhZG93TWFwU2l6ZS5tdWx0aXBseSggc2hhZG93RnJhbWVFeHRlbnRzICk7XG5cblx0XHRcdF92aWV3cG9ydFNpemUuY29weSggc2hhZG93Lm1hcFNpemUgKTtcblxuXHRcdFx0aWYgKCBfc2hhZG93TWFwU2l6ZS54ID4gX21heFRleHR1cmVTaXplIHx8IF9zaGFkb3dNYXBTaXplLnkgPiBfbWF4VGV4dHVyZVNpemUgKSB7XG5cblx0XHRcdFx0aWYgKCBfc2hhZG93TWFwU2l6ZS54ID4gX21heFRleHR1cmVTaXplICkge1xuXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS54ID0gTWF0aC5mbG9vciggX21heFRleHR1cmVTaXplIC8gc2hhZG93RnJhbWVFeHRlbnRzLnggKTtcblx0XHRcdFx0XHRfc2hhZG93TWFwU2l6ZS54ID0gX3ZpZXdwb3J0U2l6ZS54ICogc2hhZG93RnJhbWVFeHRlbnRzLng7XG5cdFx0XHRcdFx0c2hhZG93Lm1hcFNpemUueCA9IF92aWV3cG9ydFNpemUueDtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBfc2hhZG93TWFwU2l6ZS55ID4gX21heFRleHR1cmVTaXplICkge1xuXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS55ID0gTWF0aC5mbG9vciggX21heFRleHR1cmVTaXplIC8gc2hhZG93RnJhbWVFeHRlbnRzLnkgKTtcblx0XHRcdFx0XHRfc2hhZG93TWFwU2l6ZS55ID0gX3ZpZXdwb3J0U2l6ZS55ICogc2hhZG93RnJhbWVFeHRlbnRzLnk7XG5cdFx0XHRcdFx0c2hhZG93Lm1hcFNpemUueSA9IF92aWV3cG9ydFNpemUueTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBzaGFkb3cubWFwID09PSBudWxsIHx8IHRvVlNNID09PSB0cnVlIHx8IGZyb21WU00gPT09IHRydWUgKSB7XG5cblx0XHRcdFx0Y29uc3QgcGFycyA9ICggdGhpcy50eXBlICE9PSBWU01TaGFkb3dNYXAgKSA/IHsgbWluRmlsdGVyOiBOZWFyZXN0RmlsdGVyLCBtYWdGaWx0ZXI6IE5lYXJlc3RGaWx0ZXIgfSA6IHt9O1xuXG5cdFx0XHRcdGlmICggc2hhZG93Lm1hcCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdHNoYWRvdy5tYXAuZGlzcG9zZSgpO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzaGFkb3cubWFwID0gbmV3IFdlYkdMUmVuZGVyVGFyZ2V0KCBfc2hhZG93TWFwU2l6ZS54LCBfc2hhZG93TWFwU2l6ZS55LCBwYXJzICk7XG5cdFx0XHRcdHNoYWRvdy5tYXAudGV4dHVyZS5uYW1lID0gbGlnaHQubmFtZSArICcuc2hhZG93TWFwJztcblxuXHRcdFx0XHRzaGFkb3cuY2FtZXJhLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHNoYWRvdy5tYXAgKTtcblx0XHRcdHJlbmRlcmVyLmNsZWFyKCk7XG5cblx0XHRcdGNvbnN0IHZpZXdwb3J0Q291bnQgPSBzaGFkb3cuZ2V0Vmlld3BvcnRDb3VudCgpO1xuXG5cdFx0XHRmb3IgKCBsZXQgdnAgPSAwOyB2cCA8IHZpZXdwb3J0Q291bnQ7IHZwICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHZpZXdwb3J0ID0gc2hhZG93LmdldFZpZXdwb3J0KCB2cCApO1xuXG5cdFx0XHRcdF92aWV3cG9ydC5zZXQoXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS54ICogdmlld3BvcnQueCxcblx0XHRcdFx0XHRfdmlld3BvcnRTaXplLnkgKiB2aWV3cG9ydC55LFxuXHRcdFx0XHRcdF92aWV3cG9ydFNpemUueCAqIHZpZXdwb3J0LnosXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS55ICogdmlld3BvcnQud1xuXHRcdFx0XHQpO1xuXG5cdFx0XHRcdF9zdGF0ZS52aWV3cG9ydCggX3ZpZXdwb3J0ICk7XG5cblx0XHRcdFx0c2hhZG93LnVwZGF0ZU1hdHJpY2VzKCBsaWdodCwgdnAgKTtcblxuXHRcdFx0XHRfZnJ1c3R1bSA9IHNoYWRvdy5nZXRGcnVzdHVtKCk7XG5cblx0XHRcdFx0cmVuZGVyT2JqZWN0KCBzY2VuZSwgY2FtZXJhLCBzaGFkb3cuY2FtZXJhLCBsaWdodCwgdGhpcy50eXBlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gZG8gYmx1ciBwYXNzIGZvciBWU01cblxuXHRcdFx0aWYgKCBzaGFkb3cuaXNQb2ludExpZ2h0U2hhZG93ICE9PSB0cnVlICYmIHRoaXMudHlwZSA9PT0gVlNNU2hhZG93TWFwICkge1xuXG5cdFx0XHRcdFZTTVBhc3MoIHNoYWRvdywgY2FtZXJhICk7XG5cblx0XHRcdH1cblxuXHRcdFx0c2hhZG93Lm5lZWRzVXBkYXRlID0gZmFsc2U7XG5cblx0XHR9XG5cblx0XHRfcHJldmlvdXNUeXBlID0gdGhpcy50eXBlO1xuXG5cdFx0c2NvcGUubmVlZHNVcGRhdGUgPSBmYWxzZTtcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggY3VycmVudFJlbmRlclRhcmdldCwgYWN0aXZlQ3ViZUZhY2UsIGFjdGl2ZU1pcG1hcExldmVsICk7XG5cblx0fTtcblxuXHRmdW5jdGlvbiBWU01QYXNzKCBzaGFkb3csIGNhbWVyYSApIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0cy51cGRhdGUoIGZ1bGxTY3JlZW5NZXNoICk7XG5cblx0XHRpZiAoIHNoYWRvd01hdGVyaWFsVmVydGljYWwuZGVmaW5lcy5WU01fU0FNUExFUyAhPT0gc2hhZG93LmJsdXJTYW1wbGVzICkge1xuXG5cdFx0XHRzaGFkb3dNYXRlcmlhbFZlcnRpY2FsLmRlZmluZXMuVlNNX1NBTVBMRVMgPSBzaGFkb3cuYmx1clNhbXBsZXM7XG5cdFx0XHRzaGFkb3dNYXRlcmlhbEhvcml6b250YWwuZGVmaW5lcy5WU01fU0FNUExFUyA9IHNoYWRvdy5ibHVyU2FtcGxlcztcblxuXHRcdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0XHRzaGFkb3dNYXRlcmlhbEhvcml6b250YWwubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBzaGFkb3cubWFwUGFzcyA9PT0gbnVsbCApIHtcblxuXHRcdFx0c2hhZG93Lm1hcFBhc3MgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoIF9zaGFkb3dNYXBTaXplLngsIF9zaGFkb3dNYXBTaXplLnkgKTtcblxuXHRcdH1cblxuXHRcdC8vIHZlcnRpY2FsIHBhc3NcblxuXHRcdHNoYWRvd01hdGVyaWFsVmVydGljYWwudW5pZm9ybXMuc2hhZG93X3Bhc3MudmFsdWUgPSBzaGFkb3cubWFwLnRleHR1cmU7XG5cdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC51bmlmb3Jtcy5yZXNvbHV0aW9uLnZhbHVlID0gc2hhZG93Lm1hcFNpemU7XG5cdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC51bmlmb3Jtcy5yYWRpdXMudmFsdWUgPSBzaGFkb3cucmFkaXVzO1xuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggc2hhZG93Lm1hcFBhc3MgKTtcblx0XHRyZW5kZXJlci5jbGVhcigpO1xuXHRcdHJlbmRlcmVyLnJlbmRlckJ1ZmZlckRpcmVjdCggY2FtZXJhLCBudWxsLCBnZW9tZXRyeSwgc2hhZG93TWF0ZXJpYWxWZXJ0aWNhbCwgZnVsbFNjcmVlbk1lc2gsIG51bGwgKTtcblxuXHRcdC8vIGhvcml6b250YWwgcGFzc1xuXG5cdFx0c2hhZG93TWF0ZXJpYWxIb3Jpem9udGFsLnVuaWZvcm1zLnNoYWRvd19wYXNzLnZhbHVlID0gc2hhZG93Lm1hcFBhc3MudGV4dHVyZTtcblx0XHRzaGFkb3dNYXRlcmlhbEhvcml6b250YWwudW5pZm9ybXMucmVzb2x1dGlvbi52YWx1ZSA9IHNoYWRvdy5tYXBTaXplO1xuXHRcdHNoYWRvd01hdGVyaWFsSG9yaXpvbnRhbC51bmlmb3Jtcy5yYWRpdXMudmFsdWUgPSBzaGFkb3cucmFkaXVzO1xuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggc2hhZG93Lm1hcCApO1xuXHRcdHJlbmRlcmVyLmNsZWFyKCk7XG5cdFx0cmVuZGVyZXIucmVuZGVyQnVmZmVyRGlyZWN0KCBjYW1lcmEsIG51bGwsIGdlb21ldHJ5LCBzaGFkb3dNYXRlcmlhbEhvcml6b250YWwsIGZ1bGxTY3JlZW5NZXNoLCBudWxsICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldERlcHRoTWF0ZXJpYWwoIG9iamVjdCwgbWF0ZXJpYWwsIGxpZ2h0LCB0eXBlICkge1xuXG5cdFx0bGV0IHJlc3VsdCA9IG51bGw7XG5cblx0XHRjb25zdCBjdXN0b21NYXRlcmlhbCA9ICggbGlnaHQuaXNQb2ludExpZ2h0ID09PSB0cnVlICkgPyBvYmplY3QuY3VzdG9tRGlzdGFuY2VNYXRlcmlhbCA6IG9iamVjdC5jdXN0b21EZXB0aE1hdGVyaWFsO1xuXG5cdFx0aWYgKCBjdXN0b21NYXRlcmlhbCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRyZXN1bHQgPSBjdXN0b21NYXRlcmlhbDtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJlc3VsdCA9ICggbGlnaHQuaXNQb2ludExpZ2h0ID09PSB0cnVlICkgPyBfZGlzdGFuY2VNYXRlcmlhbCA6IF9kZXB0aE1hdGVyaWFsO1xuXG5cdFx0XHRpZiAoICggcmVuZGVyZXIubG9jYWxDbGlwcGluZ0VuYWJsZWQgJiYgbWF0ZXJpYWwuY2xpcFNoYWRvd3MgPT09IHRydWUgJiYgQXJyYXkuaXNBcnJheSggbWF0ZXJpYWwuY2xpcHBpbmdQbGFuZXMgKSAmJiBtYXRlcmlhbC5jbGlwcGluZ1BsYW5lcy5sZW5ndGggIT09IDAgKSB8fFxuXHRcdFx0XHQoIG1hdGVyaWFsLmRpc3BsYWNlbWVudE1hcCAmJiBtYXRlcmlhbC5kaXNwbGFjZW1lbnRTY2FsZSAhPT0gMCApIHx8XG5cdFx0XHRcdCggbWF0ZXJpYWwuYWxwaGFNYXAgJiYgbWF0ZXJpYWwuYWxwaGFUZXN0ID4gMCApIHx8XG5cdFx0XHRcdCggbWF0ZXJpYWwubWFwICYmIG1hdGVyaWFsLmFscGhhVGVzdCA+IDAgKSApIHtcblxuXHRcdFx0XHQvLyBpbiB0aGlzIGNhc2Ugd2UgbmVlZCBhIHVuaXF1ZSBtYXRlcmlhbCBpbnN0YW5jZSByZWZsZWN0aW5nIHRoZVxuXHRcdFx0XHQvLyBhcHByb3ByaWF0ZSBzdGF0ZVxuXG5cdFx0XHRcdGNvbnN0IGtleUEgPSByZXN1bHQudXVpZCwga2V5QiA9IG1hdGVyaWFsLnV1aWQ7XG5cblx0XHRcdFx0bGV0IG1hdGVyaWFsc0ZvclZhcmlhbnQgPSBfbWF0ZXJpYWxDYWNoZVsga2V5QSBdO1xuXG5cdFx0XHRcdGlmICggbWF0ZXJpYWxzRm9yVmFyaWFudCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0bWF0ZXJpYWxzRm9yVmFyaWFudCA9IHt9O1xuXHRcdFx0XHRcdF9tYXRlcmlhbENhY2hlWyBrZXlBIF0gPSBtYXRlcmlhbHNGb3JWYXJpYW50O1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRsZXQgY2FjaGVkTWF0ZXJpYWwgPSBtYXRlcmlhbHNGb3JWYXJpYW50WyBrZXlCIF07XG5cblx0XHRcdFx0aWYgKCBjYWNoZWRNYXRlcmlhbCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0Y2FjaGVkTWF0ZXJpYWwgPSByZXN1bHQuY2xvbmUoKTtcblx0XHRcdFx0XHRtYXRlcmlhbHNGb3JWYXJpYW50WyBrZXlCIF0gPSBjYWNoZWRNYXRlcmlhbDtcblx0XHRcdFx0XHRtYXRlcmlhbC5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uTWF0ZXJpYWxEaXNwb3NlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJlc3VsdCA9IGNhY2hlZE1hdGVyaWFsO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXN1bHQudmlzaWJsZSA9IG1hdGVyaWFsLnZpc2libGU7XG5cdFx0cmVzdWx0LndpcmVmcmFtZSA9IG1hdGVyaWFsLndpcmVmcmFtZTtcblxuXHRcdGlmICggdHlwZSA9PT0gVlNNU2hhZG93TWFwICkge1xuXG5cdFx0XHRyZXN1bHQuc2lkZSA9ICggbWF0ZXJpYWwuc2hhZG93U2lkZSAhPT0gbnVsbCApID8gbWF0ZXJpYWwuc2hhZG93U2lkZSA6IG1hdGVyaWFsLnNpZGU7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRyZXN1bHQuc2lkZSA9ICggbWF0ZXJpYWwuc2hhZG93U2lkZSAhPT0gbnVsbCApID8gbWF0ZXJpYWwuc2hhZG93U2lkZSA6IHNoYWRvd1NpZGVbIG1hdGVyaWFsLnNpZGUgXTtcblxuXHRcdH1cblxuXHRcdHJlc3VsdC5hbHBoYU1hcCA9IG1hdGVyaWFsLmFscGhhTWFwO1xuXHRcdHJlc3VsdC5hbHBoYVRlc3QgPSBtYXRlcmlhbC5hbHBoYVRlc3Q7XG5cdFx0cmVzdWx0Lm1hcCA9IG1hdGVyaWFsLm1hcDtcblxuXHRcdHJlc3VsdC5jbGlwU2hhZG93cyA9IG1hdGVyaWFsLmNsaXBTaGFkb3dzO1xuXHRcdHJlc3VsdC5jbGlwcGluZ1BsYW5lcyA9IG1hdGVyaWFsLmNsaXBwaW5nUGxhbmVzO1xuXHRcdHJlc3VsdC5jbGlwSW50ZXJzZWN0aW9uID0gbWF0ZXJpYWwuY2xpcEludGVyc2VjdGlvbjtcblxuXHRcdHJlc3VsdC5kaXNwbGFjZW1lbnRNYXAgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXA7XG5cdFx0cmVzdWx0LmRpc3BsYWNlbWVudFNjYWxlID0gbWF0ZXJpYWwuZGlzcGxhY2VtZW50U2NhbGU7XG5cdFx0cmVzdWx0LmRpc3BsYWNlbWVudEJpYXMgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRCaWFzO1xuXG5cdFx0cmVzdWx0LndpcmVmcmFtZUxpbmV3aWR0aCA9IG1hdGVyaWFsLndpcmVmcmFtZUxpbmV3aWR0aDtcblx0XHRyZXN1bHQubGluZXdpZHRoID0gbWF0ZXJpYWwubGluZXdpZHRoO1xuXG5cdFx0aWYgKCBsaWdodC5pc1BvaW50TGlnaHQgPT09IHRydWUgJiYgcmVzdWx0LmlzTWVzaERpc3RhbmNlTWF0ZXJpYWwgPT09IHRydWUgKSB7XG5cblx0XHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHJlbmRlcmVyLnByb3BlcnRpZXMuZ2V0KCByZXN1bHQgKTtcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5saWdodCA9IGxpZ2h0O1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJlc3VsdDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVuZGVyT2JqZWN0KCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBsaWdodCwgdHlwZSApIHtcblxuXHRcdGlmICggb2JqZWN0LnZpc2libGUgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0Y29uc3QgdmlzaWJsZSA9IG9iamVjdC5sYXllcnMudGVzdCggY2FtZXJhLmxheWVycyApO1xuXG5cdFx0aWYgKCB2aXNpYmxlICYmICggb2JqZWN0LmlzTWVzaCB8fCBvYmplY3QuaXNMaW5lIHx8IG9iamVjdC5pc1BvaW50cyApICkge1xuXG5cdFx0XHRpZiAoICggb2JqZWN0LmNhc3RTaGFkb3cgfHwgKCBvYmplY3QucmVjZWl2ZVNoYWRvdyAmJiB0eXBlID09PSBWU01TaGFkb3dNYXAgKSApICYmICggISBvYmplY3QuZnJ1c3R1bUN1bGxlZCB8fCBfZnJ1c3R1bS5pbnRlcnNlY3RzT2JqZWN0KCBvYmplY3QgKSApICkge1xuXG5cdFx0XHRcdG9iamVjdC5tb2RlbFZpZXdNYXRyaXgubXVsdGlwbHlNYXRyaWNlcyggc2hhZG93Q2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSwgb2JqZWN0Lm1hdHJpeFdvcmxkICk7XG5cblx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSBvYmplY3RzLnVwZGF0ZSggb2JqZWN0ICk7XG5cdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gb2JqZWN0Lm1hdGVyaWFsO1xuXG5cdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggbWF0ZXJpYWwgKSApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGdyb3VwcyA9IGdlb21ldHJ5Lmdyb3VwcztcblxuXHRcdFx0XHRcdGZvciAoIGxldCBrID0gMCwga2wgPSBncm91cHMubGVuZ3RoOyBrIDwga2w7IGsgKysgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBrIF07XG5cdFx0XHRcdFx0XHRjb25zdCBncm91cE1hdGVyaWFsID0gbWF0ZXJpYWxbIGdyb3VwLm1hdGVyaWFsSW5kZXggXTtcblxuXHRcdFx0XHRcdFx0aWYgKCBncm91cE1hdGVyaWFsICYmIGdyb3VwTWF0ZXJpYWwudmlzaWJsZSApIHtcblxuXHRcdFx0XHRcdFx0XHRjb25zdCBkZXB0aE1hdGVyaWFsID0gZ2V0RGVwdGhNYXRlcmlhbCggb2JqZWN0LCBncm91cE1hdGVyaWFsLCBsaWdodCwgdHlwZSApO1xuXG5cdFx0XHRcdFx0XHRcdG9iamVjdC5vbkJlZm9yZVNoYWRvdyggcmVuZGVyZXIsIG9iamVjdCwgY2FtZXJhLCBzaGFkb3dDYW1lcmEsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsLCBncm91cCApO1xuXG5cdFx0XHRcdFx0XHRcdHJlbmRlcmVyLnJlbmRlckJ1ZmZlckRpcmVjdCggc2hhZG93Q2FtZXJhLCBudWxsLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgb2JqZWN0LCBncm91cCApO1xuXG5cdFx0XHRcdFx0XHRcdG9iamVjdC5vbkFmdGVyU2hhZG93KCByZW5kZXJlciwgb2JqZWN0LCBjYW1lcmEsIHNoYWRvd0NhbWVyYSwgZ2VvbWV0cnksIGRlcHRoTWF0ZXJpYWwsIGdyb3VwICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC52aXNpYmxlICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgZGVwdGhNYXRlcmlhbCA9IGdldERlcHRoTWF0ZXJpYWwoIG9iamVjdCwgbWF0ZXJpYWwsIGxpZ2h0LCB0eXBlICk7XG5cblx0XHRcdFx0XHRvYmplY3Qub25CZWZvcmVTaGFkb3coIHJlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgbnVsbCApO1xuXG5cdFx0XHRcdFx0cmVuZGVyZXIucmVuZGVyQnVmZmVyRGlyZWN0KCBzaGFkb3dDYW1lcmEsIG51bGwsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsLCBvYmplY3QsIG51bGwgKTtcblxuXHRcdFx0XHRcdG9iamVjdC5vbkFmdGVyU2hhZG93KCByZW5kZXJlciwgb2JqZWN0LCBjYW1lcmEsIHNoYWRvd0NhbWVyYSwgZ2VvbWV0cnksIGRlcHRoTWF0ZXJpYWwsIG51bGwgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IGNoaWxkcmVuID0gb2JqZWN0LmNoaWxkcmVuO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0cmVuZGVyT2JqZWN0KCBjaGlsZHJlblsgaSBdLCBjYW1lcmEsIHNoYWRvd0NhbWVyYSwgbGlnaHQsIHR5cGUgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gb25NYXRlcmlhbERpc3Bvc2UoIGV2ZW50ICkge1xuXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBldmVudC50YXJnZXQ7XG5cblx0XHRtYXRlcmlhbC5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uTWF0ZXJpYWxEaXNwb3NlICk7XG5cblx0XHQvLyBtYWtlIHN1cmUgdG8gcmVtb3ZlIHRoZSB1bmlxdWUgZGlzdGFuY2UvZGVwdGggbWF0ZXJpYWxzIHVzZWQgZm9yIHNoYWRvdyBtYXAgcmVuZGVyaW5nXG5cblx0XHRmb3IgKCBjb25zdCBpZCBpbiBfbWF0ZXJpYWxDYWNoZSApIHtcblxuXHRcdFx0Y29uc3QgY2FjaGUgPSBfbWF0ZXJpYWxDYWNoZVsgaWQgXTtcblxuXHRcdFx0Y29uc3QgdXVpZCA9IGV2ZW50LnRhcmdldC51dWlkO1xuXG5cdFx0XHRpZiAoIHV1aWQgaW4gY2FjaGUgKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2hhZG93TWF0ZXJpYWwgPSBjYWNoZVsgdXVpZCBdO1xuXHRcdFx0XHRzaGFkb3dNYXRlcmlhbC5kaXNwb3NlKCk7XG5cdFx0XHRcdGRlbGV0ZSBjYWNoZVsgdXVpZCBdO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIFdlYkdMU3RhdGUoIGdsICkge1xuXG5cdGZ1bmN0aW9uIENvbG9yQnVmZmVyKCkge1xuXG5cdFx0bGV0IGxvY2tlZCA9IGZhbHNlO1xuXG5cdFx0Y29uc3QgY29sb3IgPSBuZXcgVmVjdG9yNCgpO1xuXHRcdGxldCBjdXJyZW50Q29sb3JNYXNrID0gbnVsbDtcblx0XHRjb25zdCBjdXJyZW50Q29sb3JDbGVhciA9IG5ldyBWZWN0b3I0KCAwLCAwLCAwLCAwICk7XG5cblx0XHRyZXR1cm4ge1xuXG5cdFx0XHRzZXRNYXNrOiBmdW5jdGlvbiAoIGNvbG9yTWFzayApIHtcblxuXHRcdFx0XHRpZiAoIGN1cnJlbnRDb2xvck1hc2sgIT09IGNvbG9yTWFzayAmJiAhIGxvY2tlZCApIHtcblxuXHRcdFx0XHRcdGdsLmNvbG9yTWFzayggY29sb3JNYXNrLCBjb2xvck1hc2ssIGNvbG9yTWFzaywgY29sb3JNYXNrICk7XG5cdFx0XHRcdFx0Y3VycmVudENvbG9yTWFzayA9IGNvbG9yTWFzaztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldExvY2tlZDogZnVuY3Rpb24gKCBsb2NrICkge1xuXG5cdFx0XHRcdGxvY2tlZCA9IGxvY2s7XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldENsZWFyOiBmdW5jdGlvbiAoIHIsIGcsIGIsIGEsIHByZW11bHRpcGxpZWRBbHBoYSApIHtcblxuXHRcdFx0XHRpZiAoIHByZW11bHRpcGxpZWRBbHBoYSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdHIgKj0gYTsgZyAqPSBhOyBiICo9IGE7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNvbG9yLnNldCggciwgZywgYiwgYSApO1xuXG5cdFx0XHRcdGlmICggY3VycmVudENvbG9yQ2xlYXIuZXF1YWxzKCBjb2xvciApID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHRcdGdsLmNsZWFyQ29sb3IoIHIsIGcsIGIsIGEgKTtcblx0XHRcdFx0XHRjdXJyZW50Q29sb3JDbGVhci5jb3B5KCBjb2xvciApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblxuXHRcdFx0cmVzZXQ6IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRsb2NrZWQgPSBmYWxzZTtcblxuXHRcdFx0XHRjdXJyZW50Q29sb3JNYXNrID0gbnVsbDtcblx0XHRcdFx0Y3VycmVudENvbG9yQ2xlYXIuc2V0KCAtIDEsIDAsIDAsIDAgKTsgLy8gc2V0IHRvIGludmFsaWQgc3RhdGVcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gRGVwdGhCdWZmZXIoKSB7XG5cblx0XHRsZXQgbG9ja2VkID0gZmFsc2U7XG5cblx0XHRsZXQgY3VycmVudERlcHRoTWFzayA9IG51bGw7XG5cdFx0bGV0IGN1cnJlbnREZXB0aEZ1bmMgPSBudWxsO1xuXHRcdGxldCBjdXJyZW50RGVwdGhDbGVhciA9IG51bGw7XG5cblx0XHRyZXR1cm4ge1xuXG5cdFx0XHRzZXRUZXN0OiBmdW5jdGlvbiAoIGRlcHRoVGVzdCApIHtcblxuXHRcdFx0XHRpZiAoIGRlcHRoVGVzdCApIHtcblxuXHRcdFx0XHRcdGVuYWJsZSggZ2wuREVQVEhfVEVTVCApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRkaXNhYmxlKCBnbC5ERVBUSF9URVNUICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9LFxuXG5cdFx0XHRzZXRNYXNrOiBmdW5jdGlvbiAoIGRlcHRoTWFzayApIHtcblxuXHRcdFx0XHRpZiAoIGN1cnJlbnREZXB0aE1hc2sgIT09IGRlcHRoTWFzayAmJiAhIGxvY2tlZCApIHtcblxuXHRcdFx0XHRcdGdsLmRlcHRoTWFzayggZGVwdGhNYXNrICk7XG5cdFx0XHRcdFx0Y3VycmVudERlcHRoTWFzayA9IGRlcHRoTWFzaztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldEZ1bmM6IGZ1bmN0aW9uICggZGVwdGhGdW5jICkge1xuXG5cdFx0XHRcdGlmICggY3VycmVudERlcHRoRnVuYyAhPT0gZGVwdGhGdW5jICkge1xuXG5cdFx0XHRcdFx0c3dpdGNoICggZGVwdGhGdW5jICkge1xuXG5cdFx0XHRcdFx0XHRjYXNlIE5ldmVyRGVwdGg6XG5cblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5ORVZFUiApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBBbHdheXNEZXB0aDpcblxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLkFMV0FZUyApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBMZXNzRGVwdGg6XG5cblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5MRVNTICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRjYXNlIExlc3NFcXVhbERlcHRoOlxuXG5cdFx0XHRcdFx0XHRcdGdsLmRlcHRoRnVuYyggZ2wuTEVRVUFMICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRjYXNlIEVxdWFsRGVwdGg6XG5cblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5FUVVBTCApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBHcmVhdGVyRXF1YWxEZXB0aDpcblxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLkdFUVVBTCApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBHcmVhdGVyRGVwdGg6XG5cblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5HUkVBVEVSICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRjYXNlIE5vdEVxdWFsRGVwdGg6XG5cblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5OT1RFUVVBTCApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0ZGVmYXVsdDpcblxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLkxFUVVBTCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Y3VycmVudERlcHRoRnVuYyA9IGRlcHRoRnVuYztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldExvY2tlZDogZnVuY3Rpb24gKCBsb2NrICkge1xuXG5cdFx0XHRcdGxvY2tlZCA9IGxvY2s7XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldENsZWFyOiBmdW5jdGlvbiAoIGRlcHRoICkge1xuXG5cdFx0XHRcdGlmICggY3VycmVudERlcHRoQ2xlYXIgIT09IGRlcHRoICkge1xuXG5cdFx0XHRcdFx0Z2wuY2xlYXJEZXB0aCggZGVwdGggKTtcblx0XHRcdFx0XHRjdXJyZW50RGVwdGhDbGVhciA9IGRlcHRoO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblxuXHRcdFx0cmVzZXQ6IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRsb2NrZWQgPSBmYWxzZTtcblxuXHRcdFx0XHRjdXJyZW50RGVwdGhNYXNrID0gbnVsbDtcblx0XHRcdFx0Y3VycmVudERlcHRoRnVuYyA9IG51bGw7XG5cdFx0XHRcdGN1cnJlbnREZXB0aENsZWFyID0gbnVsbDtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gU3RlbmNpbEJ1ZmZlcigpIHtcblxuXHRcdGxldCBsb2NrZWQgPSBmYWxzZTtcblxuXHRcdGxldCBjdXJyZW50U3RlbmNpbE1hc2sgPSBudWxsO1xuXHRcdGxldCBjdXJyZW50U3RlbmNpbEZ1bmMgPSBudWxsO1xuXHRcdGxldCBjdXJyZW50U3RlbmNpbFJlZiA9IG51bGw7XG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsRnVuY01hc2sgPSBudWxsO1xuXHRcdGxldCBjdXJyZW50U3RlbmNpbEZhaWwgPSBudWxsO1xuXHRcdGxldCBjdXJyZW50U3RlbmNpbFpGYWlsID0gbnVsbDtcblx0XHRsZXQgY3VycmVudFN0ZW5jaWxaUGFzcyA9IG51bGw7XG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsQ2xlYXIgPSBudWxsO1xuXG5cdFx0cmV0dXJuIHtcblxuXHRcdFx0c2V0VGVzdDogZnVuY3Rpb24gKCBzdGVuY2lsVGVzdCApIHtcblxuXHRcdFx0XHRpZiAoICEgbG9ja2VkICkge1xuXG5cdFx0XHRcdFx0aWYgKCBzdGVuY2lsVGVzdCApIHtcblxuXHRcdFx0XHRcdFx0ZW5hYmxlKCBnbC5TVEVOQ0lMX1RFU1QgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGRpc2FibGUoIGdsLlNURU5DSUxfVEVTVCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblxuXHRcdFx0c2V0TWFzazogZnVuY3Rpb24gKCBzdGVuY2lsTWFzayApIHtcblxuXHRcdFx0XHRpZiAoIGN1cnJlbnRTdGVuY2lsTWFzayAhPT0gc3RlbmNpbE1hc2sgJiYgISBsb2NrZWQgKSB7XG5cblx0XHRcdFx0XHRnbC5zdGVuY2lsTWFzayggc3RlbmNpbE1hc2sgKTtcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbE1hc2sgPSBzdGVuY2lsTWFzaztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldEZ1bmM6IGZ1bmN0aW9uICggc3RlbmNpbEZ1bmMsIHN0ZW5jaWxSZWYsIHN0ZW5jaWxNYXNrICkge1xuXG5cdFx0XHRcdGlmICggY3VycmVudFN0ZW5jaWxGdW5jICE9PSBzdGVuY2lsRnVuYyB8fFxuXHRcdFx0XHQgICAgIGN1cnJlbnRTdGVuY2lsUmVmICE9PSBzdGVuY2lsUmVmIHx8XG5cdFx0XHRcdCAgICAgY3VycmVudFN0ZW5jaWxGdW5jTWFzayAhPT0gc3RlbmNpbE1hc2sgKSB7XG5cblx0XHRcdFx0XHRnbC5zdGVuY2lsRnVuYyggc3RlbmNpbEZ1bmMsIHN0ZW5jaWxSZWYsIHN0ZW5jaWxNYXNrICk7XG5cblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbEZ1bmMgPSBzdGVuY2lsRnVuYztcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbFJlZiA9IHN0ZW5jaWxSZWY7XG5cdFx0XHRcdFx0Y3VycmVudFN0ZW5jaWxGdW5jTWFzayA9IHN0ZW5jaWxNYXNrO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblxuXHRcdFx0c2V0T3A6IGZ1bmN0aW9uICggc3RlbmNpbEZhaWwsIHN0ZW5jaWxaRmFpbCwgc3RlbmNpbFpQYXNzICkge1xuXG5cdFx0XHRcdGlmICggY3VycmVudFN0ZW5jaWxGYWlsICE9PSBzdGVuY2lsRmFpbCB8fFxuXHRcdFx0XHQgICAgIGN1cnJlbnRTdGVuY2lsWkZhaWwgIT09IHN0ZW5jaWxaRmFpbCB8fFxuXHRcdFx0XHQgICAgIGN1cnJlbnRTdGVuY2lsWlBhc3MgIT09IHN0ZW5jaWxaUGFzcyApIHtcblxuXHRcdFx0XHRcdGdsLnN0ZW5jaWxPcCggc3RlbmNpbEZhaWwsIHN0ZW5jaWxaRmFpbCwgc3RlbmNpbFpQYXNzICk7XG5cblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbEZhaWwgPSBzdGVuY2lsRmFpbDtcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbFpGYWlsID0gc3RlbmNpbFpGYWlsO1xuXHRcdFx0XHRcdGN1cnJlbnRTdGVuY2lsWlBhc3MgPSBzdGVuY2lsWlBhc3M7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9LFxuXG5cdFx0XHRzZXRMb2NrZWQ6IGZ1bmN0aW9uICggbG9jayApIHtcblxuXHRcdFx0XHRsb2NrZWQgPSBsb2NrO1xuXG5cdFx0XHR9LFxuXG5cdFx0XHRzZXRDbGVhcjogZnVuY3Rpb24gKCBzdGVuY2lsICkge1xuXG5cdFx0XHRcdGlmICggY3VycmVudFN0ZW5jaWxDbGVhciAhPT0gc3RlbmNpbCApIHtcblxuXHRcdFx0XHRcdGdsLmNsZWFyU3RlbmNpbCggc3RlbmNpbCApO1xuXHRcdFx0XHRcdGN1cnJlbnRTdGVuY2lsQ2xlYXIgPSBzdGVuY2lsO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblxuXHRcdFx0cmVzZXQ6IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRsb2NrZWQgPSBmYWxzZTtcblxuXHRcdFx0XHRjdXJyZW50U3RlbmNpbE1hc2sgPSBudWxsO1xuXHRcdFx0XHRjdXJyZW50U3RlbmNpbEZ1bmMgPSBudWxsO1xuXHRcdFx0XHRjdXJyZW50U3RlbmNpbFJlZiA9IG51bGw7XG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsRnVuY01hc2sgPSBudWxsO1xuXHRcdFx0XHRjdXJyZW50U3RlbmNpbEZhaWwgPSBudWxsO1xuXHRcdFx0XHRjdXJyZW50U3RlbmNpbFpGYWlsID0gbnVsbDtcblx0XHRcdFx0Y3VycmVudFN0ZW5jaWxaUGFzcyA9IG51bGw7XG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsQ2xlYXIgPSBudWxsO1xuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdH1cblxuXHQvL1xuXG5cdGNvbnN0IGNvbG9yQnVmZmVyID0gbmV3IENvbG9yQnVmZmVyKCk7XG5cdGNvbnN0IGRlcHRoQnVmZmVyID0gbmV3IERlcHRoQnVmZmVyKCk7XG5cdGNvbnN0IHN0ZW5jaWxCdWZmZXIgPSBuZXcgU3RlbmNpbEJ1ZmZlcigpO1xuXG5cdGNvbnN0IHVib0JpbmRpbmdzID0gbmV3IFdlYWtNYXAoKTtcblx0Y29uc3QgdWJvUHJvZ3JhbU1hcCA9IG5ldyBXZWFrTWFwKCk7XG5cblx0bGV0IGVuYWJsZWRDYXBhYmlsaXRpZXMgPSB7fTtcblxuXHRsZXQgY3VycmVudEJvdW5kRnJhbWVidWZmZXJzID0ge307XG5cdGxldCBjdXJyZW50RHJhd2J1ZmZlcnMgPSBuZXcgV2Vha01hcCgpO1xuXHRsZXQgZGVmYXVsdERyYXdidWZmZXJzID0gW107XG5cblx0bGV0IGN1cnJlbnRQcm9ncmFtID0gbnVsbDtcblxuXHRsZXQgY3VycmVudEJsZW5kaW5nRW5hYmxlZCA9IGZhbHNlO1xuXHRsZXQgY3VycmVudEJsZW5kaW5nID0gbnVsbDtcblx0bGV0IGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gbnVsbDtcblx0bGV0IGN1cnJlbnRCbGVuZFNyYyA9IG51bGw7XG5cdGxldCBjdXJyZW50QmxlbmREc3QgPSBudWxsO1xuXHRsZXQgY3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSA9IG51bGw7XG5cdGxldCBjdXJyZW50QmxlbmRTcmNBbHBoYSA9IG51bGw7XG5cdGxldCBjdXJyZW50QmxlbmREc3RBbHBoYSA9IG51bGw7XG5cdGxldCBjdXJyZW50QmxlbmRDb2xvciA9IG5ldyBDb2xvciggMCwgMCwgMCApO1xuXHRsZXQgY3VycmVudEJsZW5kQWxwaGEgPSAwO1xuXHRsZXQgY3VycmVudFByZW11bHRpcGxlZEFscGhhID0gZmFsc2U7XG5cblx0bGV0IGN1cnJlbnRGbGlwU2lkZWQgPSBudWxsO1xuXHRsZXQgY3VycmVudEN1bGxGYWNlID0gbnVsbDtcblxuXHRsZXQgY3VycmVudExpbmVXaWR0aCA9IG51bGw7XG5cblx0bGV0IGN1cnJlbnRQb2x5Z29uT2Zmc2V0RmFjdG9yID0gbnVsbDtcblx0bGV0IGN1cnJlbnRQb2x5Z29uT2Zmc2V0VW5pdHMgPSBudWxsO1xuXG5cdGNvbnN0IG1heFRleHR1cmVzID0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfQ09NQklORURfVEVYVFVSRV9JTUFHRV9VTklUUyApO1xuXG5cdGxldCBsaW5lV2lkdGhBdmFpbGFibGUgPSBmYWxzZTtcblx0bGV0IHZlcnNpb24gPSAwO1xuXHRjb25zdCBnbFZlcnNpb24gPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLlZFUlNJT04gKTtcblxuXHRpZiAoIGdsVmVyc2lvbi5pbmRleE9mKCAnV2ViR0wnICkgIT09IC0gMSApIHtcblxuXHRcdHZlcnNpb24gPSBwYXJzZUZsb2F0KCAvXldlYkdMIChcXGQpLy5leGVjKCBnbFZlcnNpb24gKVsgMSBdICk7XG5cdFx0bGluZVdpZHRoQXZhaWxhYmxlID0gKCB2ZXJzaW9uID49IDEuMCApO1xuXG5cdH0gZWxzZSBpZiAoIGdsVmVyc2lvbi5pbmRleE9mKCAnT3BlbkdMIEVTJyApICE9PSAtIDEgKSB7XG5cblx0XHR2ZXJzaW9uID0gcGFyc2VGbG9hdCggL15PcGVuR0wgRVMgKFxcZCkvLmV4ZWMoIGdsVmVyc2lvbiApWyAxIF0gKTtcblx0XHRsaW5lV2lkdGhBdmFpbGFibGUgPSAoIHZlcnNpb24gPj0gMi4wICk7XG5cblx0fVxuXG5cdGxldCBjdXJyZW50VGV4dHVyZVNsb3QgPSBudWxsO1xuXHRsZXQgY3VycmVudEJvdW5kVGV4dHVyZXMgPSB7fTtcblxuXHRjb25zdCBzY2lzc29yUGFyYW0gPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLlNDSVNTT1JfQk9YICk7XG5cdGNvbnN0IHZpZXdwb3J0UGFyYW0gPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLlZJRVdQT1JUICk7XG5cblx0Y29uc3QgY3VycmVudFNjaXNzb3IgPSBuZXcgVmVjdG9yNCgpLmZyb21BcnJheSggc2Npc3NvclBhcmFtICk7XG5cdGNvbnN0IGN1cnJlbnRWaWV3cG9ydCA9IG5ldyBWZWN0b3I0KCkuZnJvbUFycmF5KCB2aWV3cG9ydFBhcmFtICk7XG5cblx0ZnVuY3Rpb24gY3JlYXRlVGV4dHVyZSggdHlwZSwgdGFyZ2V0LCBjb3VudCwgZGltZW5zaW9ucyApIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBuZXcgVWludDhBcnJheSggNCApOyAvLyA0IGlzIHJlcXVpcmVkIHRvIG1hdGNoIGRlZmF1bHQgdW5wYWNrIGFsaWdubWVudCBvZiA0LlxuXHRcdGNvbnN0IHRleHR1cmUgPSBnbC5jcmVhdGVUZXh0dXJlKCk7XG5cblx0XHRnbC5iaW5kVGV4dHVyZSggdHlwZSwgdGV4dHVyZSApO1xuXHRcdGdsLnRleFBhcmFtZXRlcmkoIHR5cGUsIGdsLlRFWFRVUkVfTUlOX0ZJTFRFUiwgZ2wuTkVBUkVTVCApO1xuXHRcdGdsLnRleFBhcmFtZXRlcmkoIHR5cGUsIGdsLlRFWFRVUkVfTUFHX0ZJTFRFUiwgZ2wuTkVBUkVTVCApO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY291bnQ7IGkgKysgKSB7XG5cblx0XHRcdGlmICggdHlwZSA9PT0gZ2wuVEVYVFVSRV8zRCB8fCB0eXBlID09PSBnbC5URVhUVVJFXzJEX0FSUkFZICkge1xuXG5cdFx0XHRcdGdsLnRleEltYWdlM0QoIHRhcmdldCwgMCwgZ2wuUkdCQSwgMSwgMSwgZGltZW5zaW9ucywgMCwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgZGF0YSApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGdsLnRleEltYWdlMkQoIHRhcmdldCArIGksIDAsIGdsLlJHQkEsIDEsIDEsIDAsIGdsLlJHQkEsIGdsLlVOU0lHTkVEX0JZVEUsIGRhdGEgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRleHR1cmU7XG5cblx0fVxuXG5cdGNvbnN0IGVtcHR5VGV4dHVyZXMgPSB7fTtcblx0ZW1wdHlUZXh0dXJlc1sgZ2wuVEVYVFVSRV8yRCBdID0gY3JlYXRlVGV4dHVyZSggZ2wuVEVYVFVSRV8yRCwgZ2wuVEVYVFVSRV8yRCwgMSApO1xuXHRlbXB0eVRleHR1cmVzWyBnbC5URVhUVVJFX0NVQkVfTUFQIF0gPSBjcmVhdGVUZXh0dXJlKCBnbC5URVhUVVJFX0NVQkVfTUFQLCBnbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1gsIDYgKTtcblx0ZW1wdHlUZXh0dXJlc1sgZ2wuVEVYVFVSRV8yRF9BUlJBWSBdID0gY3JlYXRlVGV4dHVyZSggZ2wuVEVYVFVSRV8yRF9BUlJBWSwgZ2wuVEVYVFVSRV8yRF9BUlJBWSwgMSwgMSApO1xuXHRlbXB0eVRleHR1cmVzWyBnbC5URVhUVVJFXzNEIF0gPSBjcmVhdGVUZXh0dXJlKCBnbC5URVhUVVJFXzNELCBnbC5URVhUVVJFXzNELCAxLCAxICk7XG5cblx0Ly8gaW5pdFxuXG5cdGNvbG9yQnVmZmVyLnNldENsZWFyKCAwLCAwLCAwLCAxICk7XG5cdGRlcHRoQnVmZmVyLnNldENsZWFyKCAxICk7XG5cdHN0ZW5jaWxCdWZmZXIuc2V0Q2xlYXIoIDAgKTtcblxuXHRlbmFibGUoIGdsLkRFUFRIX1RFU1QgKTtcblx0ZGVwdGhCdWZmZXIuc2V0RnVuYyggTGVzc0VxdWFsRGVwdGggKTtcblxuXHRzZXRGbGlwU2lkZWQoIGZhbHNlICk7XG5cdHNldEN1bGxGYWNlKCBDdWxsRmFjZUJhY2sgKTtcblx0ZW5hYmxlKCBnbC5DVUxMX0ZBQ0UgKTtcblxuXHRzZXRCbGVuZGluZyggTm9CbGVuZGluZyApO1xuXG5cdC8vXG5cblx0ZnVuY3Rpb24gZW5hYmxlKCBpZCApIHtcblxuXHRcdGlmICggZW5hYmxlZENhcGFiaWxpdGllc1sgaWQgXSAhPT0gdHJ1ZSApIHtcblxuXHRcdFx0Z2wuZW5hYmxlKCBpZCApO1xuXHRcdFx0ZW5hYmxlZENhcGFiaWxpdGllc1sgaWQgXSA9IHRydWU7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc2FibGUoIGlkICkge1xuXG5cdFx0aWYgKCBlbmFibGVkQ2FwYWJpbGl0aWVzWyBpZCBdICE9PSBmYWxzZSApIHtcblxuXHRcdFx0Z2wuZGlzYWJsZSggaWQgKTtcblx0XHRcdGVuYWJsZWRDYXBhYmlsaXRpZXNbIGlkIF0gPSBmYWxzZTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gYmluZEZyYW1lYnVmZmVyKCB0YXJnZXQsIGZyYW1lYnVmZmVyICkge1xuXG5cdFx0aWYgKCBjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnNbIHRhcmdldCBdICE9PSBmcmFtZWJ1ZmZlciApIHtcblxuXHRcdFx0Z2wuYmluZEZyYW1lYnVmZmVyKCB0YXJnZXQsIGZyYW1lYnVmZmVyICk7XG5cblx0XHRcdGN1cnJlbnRCb3VuZEZyYW1lYnVmZmVyc1sgdGFyZ2V0IF0gPSBmcmFtZWJ1ZmZlcjtcblxuXHRcdFx0Ly8gZ2wuRFJBV19GUkFNRUJVRkZFUiBpcyBlcXVpdmFsZW50IHRvIGdsLkZSQU1FQlVGRkVSXG5cblx0XHRcdGlmICggdGFyZ2V0ID09PSBnbC5EUkFXX0ZSQU1FQlVGRkVSICkge1xuXG5cdFx0XHRcdGN1cnJlbnRCb3VuZEZyYW1lYnVmZmVyc1sgZ2wuRlJBTUVCVUZGRVIgXSA9IGZyYW1lYnVmZmVyO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGFyZ2V0ID09PSBnbC5GUkFNRUJVRkZFUiApIHtcblxuXHRcdFx0XHRjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnNbIGdsLkRSQVdfRlJBTUVCVUZGRVIgXSA9IGZyYW1lYnVmZmVyO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBkcmF3QnVmZmVycyggcmVuZGVyVGFyZ2V0LCBmcmFtZWJ1ZmZlciApIHtcblxuXHRcdGxldCBkcmF3QnVmZmVycyA9IGRlZmF1bHREcmF3YnVmZmVycztcblxuXHRcdGxldCBuZWVkc1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRcdGRyYXdCdWZmZXJzID0gY3VycmVudERyYXdidWZmZXJzLmdldCggZnJhbWVidWZmZXIgKTtcblxuXHRcdFx0aWYgKCBkcmF3QnVmZmVycyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGRyYXdCdWZmZXJzID0gW107XG5cdFx0XHRcdGN1cnJlbnREcmF3YnVmZmVycy5zZXQoIGZyYW1lYnVmZmVyLCBkcmF3QnVmZmVycyApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmVzO1xuXG5cdFx0XHRpZiAoIGRyYXdCdWZmZXJzLmxlbmd0aCAhPT0gdGV4dHVyZXMubGVuZ3RoIHx8IGRyYXdCdWZmZXJzWyAwIF0gIT09IGdsLkNPTE9SX0FUVEFDSE1FTlQwICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGRyYXdCdWZmZXJzWyBpIF0gPSBnbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGRyYXdCdWZmZXJzLmxlbmd0aCA9IHRleHR1cmVzLmxlbmd0aDtcblxuXHRcdFx0XHRuZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGlmICggZHJhd0J1ZmZlcnNbIDAgXSAhPT0gZ2wuQkFDSyApIHtcblxuXHRcdFx0XHRkcmF3QnVmZmVyc1sgMCBdID0gZ2wuQkFDSztcblxuXHRcdFx0XHRuZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggbmVlZHNVcGRhdGUgKSB7XG5cblx0XHRcdGdsLmRyYXdCdWZmZXJzKCBkcmF3QnVmZmVycyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB1c2VQcm9ncmFtKCBwcm9ncmFtICkge1xuXG5cdFx0aWYgKCBjdXJyZW50UHJvZ3JhbSAhPT0gcHJvZ3JhbSApIHtcblxuXHRcdFx0Z2wudXNlUHJvZ3JhbSggcHJvZ3JhbSApO1xuXG5cdFx0XHRjdXJyZW50UHJvZ3JhbSA9IHByb2dyYW07XG5cblx0XHRcdHJldHVybiB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXG5cdH1cblxuXHRjb25zdCBlcXVhdGlvblRvR0wgPSB7XG5cdFx0WyBBZGRFcXVhdGlvbiBdOiBnbC5GVU5DX0FERCxcblx0XHRbIFN1YnRyYWN0RXF1YXRpb24gXTogZ2wuRlVOQ19TVUJUUkFDVCxcblx0XHRbIFJldmVyc2VTdWJ0cmFjdEVxdWF0aW9uIF06IGdsLkZVTkNfUkVWRVJTRV9TVUJUUkFDVFxuXHR9O1xuXG5cdGVxdWF0aW9uVG9HTFsgTWluRXF1YXRpb24gXSA9IGdsLk1JTjtcblx0ZXF1YXRpb25Ub0dMWyBNYXhFcXVhdGlvbiBdID0gZ2wuTUFYO1xuXG5cdGNvbnN0IGZhY3RvclRvR0wgPSB7XG5cdFx0WyBaZXJvRmFjdG9yIF06IGdsLlpFUk8sXG5cdFx0WyBPbmVGYWN0b3IgXTogZ2wuT05FLFxuXHRcdFsgU3JjQ29sb3JGYWN0b3IgXTogZ2wuU1JDX0NPTE9SLFxuXHRcdFsgU3JjQWxwaGFGYWN0b3IgXTogZ2wuU1JDX0FMUEhBLFxuXHRcdFsgU3JjQWxwaGFTYXR1cmF0ZUZhY3RvciBdOiBnbC5TUkNfQUxQSEFfU0FUVVJBVEUsXG5cdFx0WyBEc3RDb2xvckZhY3RvciBdOiBnbC5EU1RfQ09MT1IsXG5cdFx0WyBEc3RBbHBoYUZhY3RvciBdOiBnbC5EU1RfQUxQSEEsXG5cdFx0WyBPbmVNaW51c1NyY0NvbG9yRmFjdG9yIF06IGdsLk9ORV9NSU5VU19TUkNfQ09MT1IsXG5cdFx0WyBPbmVNaW51c1NyY0FscGhhRmFjdG9yIF06IGdsLk9ORV9NSU5VU19TUkNfQUxQSEEsXG5cdFx0WyBPbmVNaW51c0RzdENvbG9yRmFjdG9yIF06IGdsLk9ORV9NSU5VU19EU1RfQ09MT1IsXG5cdFx0WyBPbmVNaW51c0RzdEFscGhhRmFjdG9yIF06IGdsLk9ORV9NSU5VU19EU1RfQUxQSEEsXG5cdFx0WyBDb25zdGFudENvbG9yRmFjdG9yIF06IGdsLkNPTlNUQU5UX0NPTE9SLFxuXHRcdFsgT25lTWludXNDb25zdGFudENvbG9yRmFjdG9yIF06IGdsLk9ORV9NSU5VU19DT05TVEFOVF9DT0xPUixcblx0XHRbIENvbnN0YW50QWxwaGFGYWN0b3IgXTogZ2wuQ09OU1RBTlRfQUxQSEEsXG5cdFx0WyBPbmVNaW51c0NvbnN0YW50QWxwaGFGYWN0b3IgXTogZ2wuT05FX01JTlVTX0NPTlNUQU5UX0FMUEhBXG5cdH07XG5cblx0ZnVuY3Rpb24gc2V0QmxlbmRpbmcoIGJsZW5kaW5nLCBibGVuZEVxdWF0aW9uLCBibGVuZFNyYywgYmxlbmREc3QsIGJsZW5kRXF1YXRpb25BbHBoYSwgYmxlbmRTcmNBbHBoYSwgYmxlbmREc3RBbHBoYSwgYmxlbmRDb2xvciwgYmxlbmRBbHBoYSwgcHJlbXVsdGlwbGllZEFscGhhICkge1xuXG5cdFx0aWYgKCBibGVuZGluZyA9PT0gTm9CbGVuZGluZyApIHtcblxuXHRcdFx0aWYgKCBjdXJyZW50QmxlbmRpbmdFbmFibGVkID09PSB0cnVlICkge1xuXG5cdFx0XHRcdGRpc2FibGUoIGdsLkJMRU5EICk7XG5cdFx0XHRcdGN1cnJlbnRCbGVuZGluZ0VuYWJsZWQgPSBmYWxzZTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHRpZiAoIGN1cnJlbnRCbGVuZGluZ0VuYWJsZWQgPT09IGZhbHNlICkge1xuXG5cdFx0XHRlbmFibGUoIGdsLkJMRU5EICk7XG5cdFx0XHRjdXJyZW50QmxlbmRpbmdFbmFibGVkID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdGlmICggYmxlbmRpbmcgIT09IEN1c3RvbUJsZW5kaW5nICkge1xuXG5cdFx0XHRpZiAoIGJsZW5kaW5nICE9PSBjdXJyZW50QmxlbmRpbmcgfHwgcHJlbXVsdGlwbGllZEFscGhhICE9PSBjdXJyZW50UHJlbXVsdGlwbGVkQWxwaGEgKSB7XG5cblx0XHRcdFx0aWYgKCBjdXJyZW50QmxlbmRFcXVhdGlvbiAhPT0gQWRkRXF1YXRpb24gfHwgY3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSAhPT0gQWRkRXF1YXRpb24gKSB7XG5cblx0XHRcdFx0XHRnbC5ibGVuZEVxdWF0aW9uKCBnbC5GVU5DX0FERCApO1xuXG5cdFx0XHRcdFx0Y3VycmVudEJsZW5kRXF1YXRpb24gPSBBZGRFcXVhdGlvbjtcblx0XHRcdFx0XHRjdXJyZW50QmxlbmRFcXVhdGlvbkFscGhhID0gQWRkRXF1YXRpb247XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggcHJlbXVsdGlwbGllZEFscGhhICkge1xuXG5cdFx0XHRcdFx0c3dpdGNoICggYmxlbmRpbmcgKSB7XG5cblx0XHRcdFx0XHRcdGNhc2UgTm9ybWFsQmxlbmRpbmc6XG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuY1NlcGFyYXRlKCBnbC5PTkUsIGdsLk9ORV9NSU5VU19TUkNfQUxQSEEsIGdsLk9ORSwgZ2wuT05FX01JTlVTX1NSQ19BTFBIQSApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBBZGRpdGl2ZUJsZW5kaW5nOlxuXHRcdFx0XHRcdFx0XHRnbC5ibGVuZEZ1bmMoIGdsLk9ORSwgZ2wuT05FICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRjYXNlIFN1YnRyYWN0aXZlQmxlbmRpbmc6XG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuY1NlcGFyYXRlKCBnbC5aRVJPLCBnbC5PTkVfTUlOVVNfU1JDX0NPTE9SLCBnbC5aRVJPLCBnbC5PTkUgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdGNhc2UgTXVsdGlwbHlCbGVuZGluZzpcblx0XHRcdFx0XHRcdFx0Z2wuYmxlbmRGdW5jU2VwYXJhdGUoIGdsLlpFUk8sIGdsLlNSQ19DT0xPUiwgZ2wuWkVSTywgZ2wuU1JDX0FMUEhBICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTogSW52YWxpZCBibGVuZGluZzogJywgYmxlbmRpbmcgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHN3aXRjaCAoIGJsZW5kaW5nICkge1xuXG5cdFx0XHRcdFx0XHRjYXNlIE5vcm1hbEJsZW5kaW5nOlxuXHRcdFx0XHRcdFx0XHRnbC5ibGVuZEZ1bmNTZXBhcmF0ZSggZ2wuU1JDX0FMUEhBLCBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBLCBnbC5PTkUsIGdsLk9ORV9NSU5VU19TUkNfQUxQSEEgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdGNhc2UgQWRkaXRpdmVCbGVuZGluZzpcblx0XHRcdFx0XHRcdFx0Z2wuYmxlbmRGdW5jKCBnbC5TUkNfQUxQSEEsIGdsLk9ORSApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBTdWJ0cmFjdGl2ZUJsZW5kaW5nOlxuXHRcdFx0XHRcdFx0XHRnbC5ibGVuZEZ1bmNTZXBhcmF0ZSggZ2wuWkVSTywgZ2wuT05FX01JTlVTX1NSQ19DT0xPUiwgZ2wuWkVSTywgZ2wuT05FICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRjYXNlIE11bHRpcGx5QmxlbmRpbmc6XG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuYyggZ2wuWkVSTywgZ2wuU1JDX0NPTE9SICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTogSW52YWxpZCBibGVuZGluZzogJywgYmxlbmRpbmcgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGN1cnJlbnRCbGVuZFNyYyA9IG51bGw7XG5cdFx0XHRcdGN1cnJlbnRCbGVuZERzdCA9IG51bGw7XG5cdFx0XHRcdGN1cnJlbnRCbGVuZFNyY0FscGhhID0gbnVsbDtcblx0XHRcdFx0Y3VycmVudEJsZW5kRHN0QWxwaGEgPSBudWxsO1xuXHRcdFx0XHRjdXJyZW50QmxlbmRDb2xvci5zZXQoIDAsIDAsIDAgKTtcblx0XHRcdFx0Y3VycmVudEJsZW5kQWxwaGEgPSAwO1xuXG5cdFx0XHRcdGN1cnJlbnRCbGVuZGluZyA9IGJsZW5kaW5nO1xuXHRcdFx0XHRjdXJyZW50UHJlbXVsdGlwbGVkQWxwaGEgPSBwcmVtdWx0aXBsaWVkQWxwaGE7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0Ly8gY3VzdG9tIGJsZW5kaW5nXG5cblx0XHRibGVuZEVxdWF0aW9uQWxwaGEgPSBibGVuZEVxdWF0aW9uQWxwaGEgfHwgYmxlbmRFcXVhdGlvbjtcblx0XHRibGVuZFNyY0FscGhhID0gYmxlbmRTcmNBbHBoYSB8fCBibGVuZFNyYztcblx0XHRibGVuZERzdEFscGhhID0gYmxlbmREc3RBbHBoYSB8fCBibGVuZERzdDtcblxuXHRcdGlmICggYmxlbmRFcXVhdGlvbiAhPT0gY3VycmVudEJsZW5kRXF1YXRpb24gfHwgYmxlbmRFcXVhdGlvbkFscGhhICE9PSBjdXJyZW50QmxlbmRFcXVhdGlvbkFscGhhICkge1xuXG5cdFx0XHRnbC5ibGVuZEVxdWF0aW9uU2VwYXJhdGUoIGVxdWF0aW9uVG9HTFsgYmxlbmRFcXVhdGlvbiBdLCBlcXVhdGlvblRvR0xbIGJsZW5kRXF1YXRpb25BbHBoYSBdICk7XG5cblx0XHRcdGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gYmxlbmRFcXVhdGlvbjtcblx0XHRcdGN1cnJlbnRCbGVuZEVxdWF0aW9uQWxwaGEgPSBibGVuZEVxdWF0aW9uQWxwaGE7XG5cblx0XHR9XG5cblx0XHRpZiAoIGJsZW5kU3JjICE9PSBjdXJyZW50QmxlbmRTcmMgfHwgYmxlbmREc3QgIT09IGN1cnJlbnRCbGVuZERzdCB8fCBibGVuZFNyY0FscGhhICE9PSBjdXJyZW50QmxlbmRTcmNBbHBoYSB8fCBibGVuZERzdEFscGhhICE9PSBjdXJyZW50QmxlbmREc3RBbHBoYSApIHtcblxuXHRcdFx0Z2wuYmxlbmRGdW5jU2VwYXJhdGUoIGZhY3RvclRvR0xbIGJsZW5kU3JjIF0sIGZhY3RvclRvR0xbIGJsZW5kRHN0IF0sIGZhY3RvclRvR0xbIGJsZW5kU3JjQWxwaGEgXSwgZmFjdG9yVG9HTFsgYmxlbmREc3RBbHBoYSBdICk7XG5cblx0XHRcdGN1cnJlbnRCbGVuZFNyYyA9IGJsZW5kU3JjO1xuXHRcdFx0Y3VycmVudEJsZW5kRHN0ID0gYmxlbmREc3Q7XG5cdFx0XHRjdXJyZW50QmxlbmRTcmNBbHBoYSA9IGJsZW5kU3JjQWxwaGE7XG5cdFx0XHRjdXJyZW50QmxlbmREc3RBbHBoYSA9IGJsZW5kRHN0QWxwaGE7XG5cblx0XHR9XG5cblx0XHRpZiAoIGJsZW5kQ29sb3IuZXF1YWxzKCBjdXJyZW50QmxlbmRDb2xvciApID09PSBmYWxzZSB8fCBibGVuZEFscGhhICE9PSBjdXJyZW50QmxlbmRBbHBoYSApIHtcblxuXHRcdFx0Z2wuYmxlbmRDb2xvciggYmxlbmRDb2xvci5yLCBibGVuZENvbG9yLmcsIGJsZW5kQ29sb3IuYiwgYmxlbmRBbHBoYSApO1xuXG5cdFx0XHRjdXJyZW50QmxlbmRDb2xvci5jb3B5KCBibGVuZENvbG9yICk7XG5cdFx0XHRjdXJyZW50QmxlbmRBbHBoYSA9IGJsZW5kQWxwaGE7XG5cblx0XHR9XG5cblx0XHRjdXJyZW50QmxlbmRpbmcgPSBibGVuZGluZztcblx0XHRjdXJyZW50UHJlbXVsdGlwbGVkQWxwaGEgPSBmYWxzZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gc2V0TWF0ZXJpYWwoIG1hdGVyaWFsLCBmcm9udEZhY2VDVyApIHtcblxuXHRcdG1hdGVyaWFsLnNpZGUgPT09IERvdWJsZVNpZGVcblx0XHRcdD8gZGlzYWJsZSggZ2wuQ1VMTF9GQUNFIClcblx0XHRcdDogZW5hYmxlKCBnbC5DVUxMX0ZBQ0UgKTtcblxuXHRcdGxldCBmbGlwU2lkZWQgPSAoIG1hdGVyaWFsLnNpZGUgPT09IEJhY2tTaWRlICk7XG5cdFx0aWYgKCBmcm9udEZhY2VDVyApIGZsaXBTaWRlZCA9ICEgZmxpcFNpZGVkO1xuXG5cdFx0c2V0RmxpcFNpZGVkKCBmbGlwU2lkZWQgKTtcblxuXHRcdCggbWF0ZXJpYWwuYmxlbmRpbmcgPT09IE5vcm1hbEJsZW5kaW5nICYmIG1hdGVyaWFsLnRyYW5zcGFyZW50ID09PSBmYWxzZSApXG5cdFx0XHQ/IHNldEJsZW5kaW5nKCBOb0JsZW5kaW5nIClcblx0XHRcdDogc2V0QmxlbmRpbmcoIG1hdGVyaWFsLmJsZW5kaW5nLCBtYXRlcmlhbC5ibGVuZEVxdWF0aW9uLCBtYXRlcmlhbC5ibGVuZFNyYywgbWF0ZXJpYWwuYmxlbmREc3QsIG1hdGVyaWFsLmJsZW5kRXF1YXRpb25BbHBoYSwgbWF0ZXJpYWwuYmxlbmRTcmNBbHBoYSwgbWF0ZXJpYWwuYmxlbmREc3RBbHBoYSwgbWF0ZXJpYWwuYmxlbmRDb2xvciwgbWF0ZXJpYWwuYmxlbmRBbHBoYSwgbWF0ZXJpYWwucHJlbXVsdGlwbGllZEFscGhhICk7XG5cblx0XHRkZXB0aEJ1ZmZlci5zZXRGdW5jKCBtYXRlcmlhbC5kZXB0aEZ1bmMgKTtcblx0XHRkZXB0aEJ1ZmZlci5zZXRUZXN0KCBtYXRlcmlhbC5kZXB0aFRlc3QgKTtcblx0XHRkZXB0aEJ1ZmZlci5zZXRNYXNrKCBtYXRlcmlhbC5kZXB0aFdyaXRlICk7XG5cdFx0Y29sb3JCdWZmZXIuc2V0TWFzayggbWF0ZXJpYWwuY29sb3JXcml0ZSApO1xuXG5cdFx0Y29uc3Qgc3RlbmNpbFdyaXRlID0gbWF0ZXJpYWwuc3RlbmNpbFdyaXRlO1xuXHRcdHN0ZW5jaWxCdWZmZXIuc2V0VGVzdCggc3RlbmNpbFdyaXRlICk7XG5cdFx0aWYgKCBzdGVuY2lsV3JpdGUgKSB7XG5cblx0XHRcdHN0ZW5jaWxCdWZmZXIuc2V0TWFzayggbWF0ZXJpYWwuc3RlbmNpbFdyaXRlTWFzayApO1xuXHRcdFx0c3RlbmNpbEJ1ZmZlci5zZXRGdW5jKCBtYXRlcmlhbC5zdGVuY2lsRnVuYywgbWF0ZXJpYWwuc3RlbmNpbFJlZiwgbWF0ZXJpYWwuc3RlbmNpbEZ1bmNNYXNrICk7XG5cdFx0XHRzdGVuY2lsQnVmZmVyLnNldE9wKCBtYXRlcmlhbC5zdGVuY2lsRmFpbCwgbWF0ZXJpYWwuc3RlbmNpbFpGYWlsLCBtYXRlcmlhbC5zdGVuY2lsWlBhc3MgKTtcblxuXHRcdH1cblxuXHRcdHNldFBvbHlnb25PZmZzZXQoIG1hdGVyaWFsLnBvbHlnb25PZmZzZXQsIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRGYWN0b3IsIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRVbml0cyApO1xuXG5cdFx0bWF0ZXJpYWwuYWxwaGFUb0NvdmVyYWdlID09PSB0cnVlXG5cdFx0XHQ/IGVuYWJsZSggZ2wuU0FNUExFX0FMUEhBX1RPX0NPVkVSQUdFIClcblx0XHRcdDogZGlzYWJsZSggZ2wuU0FNUExFX0FMUEhBX1RPX0NPVkVSQUdFICk7XG5cblx0fVxuXG5cdC8vXG5cblx0ZnVuY3Rpb24gc2V0RmxpcFNpZGVkKCBmbGlwU2lkZWQgKSB7XG5cblx0XHRpZiAoIGN1cnJlbnRGbGlwU2lkZWQgIT09IGZsaXBTaWRlZCApIHtcblxuXHRcdFx0aWYgKCBmbGlwU2lkZWQgKSB7XG5cblx0XHRcdFx0Z2wuZnJvbnRGYWNlKCBnbC5DVyApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGdsLmZyb250RmFjZSggZ2wuQ0NXICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Y3VycmVudEZsaXBTaWRlZCA9IGZsaXBTaWRlZDtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gc2V0Q3VsbEZhY2UoIGN1bGxGYWNlICkge1xuXG5cdFx0aWYgKCBjdWxsRmFjZSAhPT0gQ3VsbEZhY2VOb25lICkge1xuXG5cdFx0XHRlbmFibGUoIGdsLkNVTExfRkFDRSApO1xuXG5cdFx0XHRpZiAoIGN1bGxGYWNlICE9PSBjdXJyZW50Q3VsbEZhY2UgKSB7XG5cblx0XHRcdFx0aWYgKCBjdWxsRmFjZSA9PT0gQ3VsbEZhY2VCYWNrICkge1xuXG5cdFx0XHRcdFx0Z2wuY3VsbEZhY2UoIGdsLkJBQ0sgKTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBjdWxsRmFjZSA9PT0gQ3VsbEZhY2VGcm9udCApIHtcblxuXHRcdFx0XHRcdGdsLmN1bGxGYWNlKCBnbC5GUk9OVCApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRnbC5jdWxsRmFjZSggZ2wuRlJPTlRfQU5EX0JBQ0sgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGRpc2FibGUoIGdsLkNVTExfRkFDRSApO1xuXG5cdFx0fVxuXG5cdFx0Y3VycmVudEN1bGxGYWNlID0gY3VsbEZhY2U7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHNldExpbmVXaWR0aCggd2lkdGggKSB7XG5cblx0XHRpZiAoIHdpZHRoICE9PSBjdXJyZW50TGluZVdpZHRoICkge1xuXG5cdFx0XHRpZiAoIGxpbmVXaWR0aEF2YWlsYWJsZSApIGdsLmxpbmVXaWR0aCggd2lkdGggKTtcblxuXHRcdFx0Y3VycmVudExpbmVXaWR0aCA9IHdpZHRoO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBzZXRQb2x5Z29uT2Zmc2V0KCBwb2x5Z29uT2Zmc2V0LCBmYWN0b3IsIHVuaXRzICkge1xuXG5cdFx0aWYgKCBwb2x5Z29uT2Zmc2V0ICkge1xuXG5cdFx0XHRlbmFibGUoIGdsLlBPTFlHT05fT0ZGU0VUX0ZJTEwgKTtcblxuXHRcdFx0aWYgKCBjdXJyZW50UG9seWdvbk9mZnNldEZhY3RvciAhPT0gZmFjdG9yIHx8IGN1cnJlbnRQb2x5Z29uT2Zmc2V0VW5pdHMgIT09IHVuaXRzICkge1xuXG5cdFx0XHRcdGdsLnBvbHlnb25PZmZzZXQoIGZhY3RvciwgdW5pdHMgKTtcblxuXHRcdFx0XHRjdXJyZW50UG9seWdvbk9mZnNldEZhY3RvciA9IGZhY3Rvcjtcblx0XHRcdFx0Y3VycmVudFBvbHlnb25PZmZzZXRVbml0cyA9IHVuaXRzO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRkaXNhYmxlKCBnbC5QT0xZR09OX09GRlNFVF9GSUxMICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHNldFNjaXNzb3JUZXN0KCBzY2lzc29yVGVzdCApIHtcblxuXHRcdGlmICggc2Npc3NvclRlc3QgKSB7XG5cblx0XHRcdGVuYWJsZSggZ2wuU0NJU1NPUl9URVNUICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRkaXNhYmxlKCBnbC5TQ0lTU09SX1RFU1QgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Ly8gdGV4dHVyZVxuXG5cdGZ1bmN0aW9uIGFjdGl2ZVRleHR1cmUoIHdlYmdsU2xvdCApIHtcblxuXHRcdGlmICggd2ViZ2xTbG90ID09PSB1bmRlZmluZWQgKSB3ZWJnbFNsb3QgPSBnbC5URVhUVVJFMCArIG1heFRleHR1cmVzIC0gMTtcblxuXHRcdGlmICggY3VycmVudFRleHR1cmVTbG90ICE9PSB3ZWJnbFNsb3QgKSB7XG5cblx0XHRcdGdsLmFjdGl2ZVRleHR1cmUoIHdlYmdsU2xvdCApO1xuXHRcdFx0Y3VycmVudFRleHR1cmVTbG90ID0gd2ViZ2xTbG90O1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBiaW5kVGV4dHVyZSggd2ViZ2xUeXBlLCB3ZWJnbFRleHR1cmUsIHdlYmdsU2xvdCApIHtcblxuXHRcdGlmICggd2ViZ2xTbG90ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGlmICggY3VycmVudFRleHR1cmVTbG90ID09PSBudWxsICkge1xuXG5cdFx0XHRcdHdlYmdsU2xvdCA9IGdsLlRFWFRVUkUwICsgbWF4VGV4dHVyZXMgLSAxO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHdlYmdsU2xvdCA9IGN1cnJlbnRUZXh0dXJlU2xvdDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0bGV0IGJvdW5kVGV4dHVyZSA9IGN1cnJlbnRCb3VuZFRleHR1cmVzWyB3ZWJnbFNsb3QgXTtcblxuXHRcdGlmICggYm91bmRUZXh0dXJlID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGJvdW5kVGV4dHVyZSA9IHsgdHlwZTogdW5kZWZpbmVkLCB0ZXh0dXJlOiB1bmRlZmluZWQgfTtcblx0XHRcdGN1cnJlbnRCb3VuZFRleHR1cmVzWyB3ZWJnbFNsb3QgXSA9IGJvdW5kVGV4dHVyZTtcblxuXHRcdH1cblxuXHRcdGlmICggYm91bmRUZXh0dXJlLnR5cGUgIT09IHdlYmdsVHlwZSB8fCBib3VuZFRleHR1cmUudGV4dHVyZSAhPT0gd2ViZ2xUZXh0dXJlICkge1xuXG5cdFx0XHRpZiAoIGN1cnJlbnRUZXh0dXJlU2xvdCAhPT0gd2ViZ2xTbG90ICkge1xuXG5cdFx0XHRcdGdsLmFjdGl2ZVRleHR1cmUoIHdlYmdsU2xvdCApO1xuXHRcdFx0XHRjdXJyZW50VGV4dHVyZVNsb3QgPSB3ZWJnbFNsb3Q7XG5cblx0XHRcdH1cblxuXHRcdFx0Z2wuYmluZFRleHR1cmUoIHdlYmdsVHlwZSwgd2ViZ2xUZXh0dXJlIHx8IGVtcHR5VGV4dHVyZXNbIHdlYmdsVHlwZSBdICk7XG5cblx0XHRcdGJvdW5kVGV4dHVyZS50eXBlID0gd2ViZ2xUeXBlO1xuXHRcdFx0Ym91bmRUZXh0dXJlLnRleHR1cmUgPSB3ZWJnbFRleHR1cmU7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHVuYmluZFRleHR1cmUoKSB7XG5cblx0XHRjb25zdCBib3VuZFRleHR1cmUgPSBjdXJyZW50Qm91bmRUZXh0dXJlc1sgY3VycmVudFRleHR1cmVTbG90IF07XG5cblx0XHRpZiAoIGJvdW5kVGV4dHVyZSAhPT0gdW5kZWZpbmVkICYmIGJvdW5kVGV4dHVyZS50eXBlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGdsLmJpbmRUZXh0dXJlKCBib3VuZFRleHR1cmUudHlwZSwgbnVsbCApO1xuXG5cdFx0XHRib3VuZFRleHR1cmUudHlwZSA9IHVuZGVmaW5lZDtcblx0XHRcdGJvdW5kVGV4dHVyZS50ZXh0dXJlID0gdW5kZWZpbmVkO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBjb21wcmVzc2VkVGV4SW1hZ2UyRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLmNvbXByZXNzZWRUZXhJbWFnZTJELmFwcGx5KCBnbCwgYXJndW1lbnRzICk7XG5cblx0XHR9IGNhdGNoICggZXJyb3IgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGNvbXByZXNzZWRUZXhJbWFnZTNEKCkge1xuXG5cdFx0dHJ5IHtcblxuXHRcdFx0Z2wuY29tcHJlc3NlZFRleEltYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gdGV4U3ViSW1hZ2UyRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLnRleFN1YkltYWdlMkQuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gdGV4U3ViSW1hZ2UzRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLnRleFN1YkltYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gY29tcHJlc3NlZFRleFN1YkltYWdlMkQoKSB7XG5cblx0XHR0cnkge1xuXG5cdFx0XHRnbC5jb21wcmVzc2VkVGV4U3ViSW1hZ2UyRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xuXG5cdFx0fSBjYXRjaCAoIGVycm9yICkge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTonLCBlcnJvciApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBjb21wcmVzc2VkVGV4U3ViSW1hZ2UzRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLmNvbXByZXNzZWRUZXhTdWJJbWFnZTNELmFwcGx5KCBnbCwgYXJndW1lbnRzICk7XG5cblx0XHR9IGNhdGNoICggZXJyb3IgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHRleFN0b3JhZ2UyRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLnRleFN0b3JhZ2UyRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xuXG5cdFx0fSBjYXRjaCAoIGVycm9yICkge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTonLCBlcnJvciApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB0ZXhTdG9yYWdlM0QoKSB7XG5cblx0XHR0cnkge1xuXG5cdFx0XHRnbC50ZXhTdG9yYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gdGV4SW1hZ2UyRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLnRleEltYWdlMkQuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gdGV4SW1hZ2UzRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLnRleEltYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Ly9cblxuXHRmdW5jdGlvbiBzY2lzc29yKCBzY2lzc29yICkge1xuXG5cdFx0aWYgKCBjdXJyZW50U2Npc3Nvci5lcXVhbHMoIHNjaXNzb3IgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdGdsLnNjaXNzb3IoIHNjaXNzb3IueCwgc2Npc3Nvci55LCBzY2lzc29yLnosIHNjaXNzb3IudyApO1xuXHRcdFx0Y3VycmVudFNjaXNzb3IuY29weSggc2Npc3NvciApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB2aWV3cG9ydCggdmlld3BvcnQgKSB7XG5cblx0XHRpZiAoIGN1cnJlbnRWaWV3cG9ydC5lcXVhbHMoIHZpZXdwb3J0ICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRnbC52aWV3cG9ydCggdmlld3BvcnQueCwgdmlld3BvcnQueSwgdmlld3BvcnQueiwgdmlld3BvcnQudyApO1xuXHRcdFx0Y3VycmVudFZpZXdwb3J0LmNvcHkoIHZpZXdwb3J0ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHVwZGF0ZVVCT01hcHBpbmcoIHVuaWZvcm1zR3JvdXAsIHByb2dyYW0gKSB7XG5cblx0XHRsZXQgbWFwcGluZyA9IHVib1Byb2dyYW1NYXAuZ2V0KCBwcm9ncmFtICk7XG5cblx0XHRpZiAoIG1hcHBpbmcgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0bWFwcGluZyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0XHRcdHVib1Byb2dyYW1NYXAuc2V0KCBwcm9ncmFtLCBtYXBwaW5nICk7XG5cblx0XHR9XG5cblx0XHRsZXQgYmxvY2tJbmRleCA9IG1hcHBpbmcuZ2V0KCB1bmlmb3Jtc0dyb3VwICk7XG5cblx0XHRpZiAoIGJsb2NrSW5kZXggPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0YmxvY2tJbmRleCA9IGdsLmdldFVuaWZvcm1CbG9ja0luZGV4KCBwcm9ncmFtLCB1bmlmb3Jtc0dyb3VwLm5hbWUgKTtcblxuXHRcdFx0bWFwcGluZy5zZXQoIHVuaWZvcm1zR3JvdXAsIGJsb2NrSW5kZXggKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gdW5pZm9ybUJsb2NrQmluZGluZyggdW5pZm9ybXNHcm91cCwgcHJvZ3JhbSApIHtcblxuXHRcdGNvbnN0IG1hcHBpbmcgPSB1Ym9Qcm9ncmFtTWFwLmdldCggcHJvZ3JhbSApO1xuXHRcdGNvbnN0IGJsb2NrSW5kZXggPSBtYXBwaW5nLmdldCggdW5pZm9ybXNHcm91cCApO1xuXG5cdFx0aWYgKCB1Ym9CaW5kaW5ncy5nZXQoIHByb2dyYW0gKSAhPT0gYmxvY2tJbmRleCApIHtcblxuXHRcdFx0Ly8gYmluZCBzaGFkZXIgc3BlY2lmaWMgYmxvY2sgaW5kZXggdG8gZ2xvYmFsIGJsb2NrIHBvaW50XG5cdFx0XHRnbC51bmlmb3JtQmxvY2tCaW5kaW5nKCBwcm9ncmFtLCBibG9ja0luZGV4LCB1bmlmb3Jtc0dyb3VwLl9fYmluZGluZ1BvaW50SW5kZXggKTtcblxuXHRcdFx0dWJvQmluZGluZ3Muc2V0KCBwcm9ncmFtLCBibG9ja0luZGV4ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdC8vXG5cblx0ZnVuY3Rpb24gcmVzZXQoKSB7XG5cblx0XHQvLyByZXNldCBzdGF0ZVxuXG5cdFx0Z2wuZGlzYWJsZSggZ2wuQkxFTkQgKTtcblx0XHRnbC5kaXNhYmxlKCBnbC5DVUxMX0ZBQ0UgKTtcblx0XHRnbC5kaXNhYmxlKCBnbC5ERVBUSF9URVNUICk7XG5cdFx0Z2wuZGlzYWJsZSggZ2wuUE9MWUdPTl9PRkZTRVRfRklMTCApO1xuXHRcdGdsLmRpc2FibGUoIGdsLlNDSVNTT1JfVEVTVCApO1xuXHRcdGdsLmRpc2FibGUoIGdsLlNURU5DSUxfVEVTVCApO1xuXHRcdGdsLmRpc2FibGUoIGdsLlNBTVBMRV9BTFBIQV9UT19DT1ZFUkFHRSApO1xuXG5cdFx0Z2wuYmxlbmRFcXVhdGlvbiggZ2wuRlVOQ19BREQgKTtcblx0XHRnbC5ibGVuZEZ1bmMoIGdsLk9ORSwgZ2wuWkVSTyApO1xuXHRcdGdsLmJsZW5kRnVuY1NlcGFyYXRlKCBnbC5PTkUsIGdsLlpFUk8sIGdsLk9ORSwgZ2wuWkVSTyApO1xuXHRcdGdsLmJsZW5kQ29sb3IoIDAsIDAsIDAsIDAgKTtcblxuXHRcdGdsLmNvbG9yTWFzayggdHJ1ZSwgdHJ1ZSwgdHJ1ZSwgdHJ1ZSApO1xuXHRcdGdsLmNsZWFyQ29sb3IoIDAsIDAsIDAsIDAgKTtcblxuXHRcdGdsLmRlcHRoTWFzayggdHJ1ZSApO1xuXHRcdGdsLmRlcHRoRnVuYyggZ2wuTEVTUyApO1xuXHRcdGdsLmNsZWFyRGVwdGgoIDEgKTtcblxuXHRcdGdsLnN0ZW5jaWxNYXNrKCAweGZmZmZmZmZmICk7XG5cdFx0Z2wuc3RlbmNpbEZ1bmMoIGdsLkFMV0FZUywgMCwgMHhmZmZmZmZmZiApO1xuXHRcdGdsLnN0ZW5jaWxPcCggZ2wuS0VFUCwgZ2wuS0VFUCwgZ2wuS0VFUCApO1xuXHRcdGdsLmNsZWFyU3RlbmNpbCggMCApO1xuXG5cdFx0Z2wuY3VsbEZhY2UoIGdsLkJBQ0sgKTtcblx0XHRnbC5mcm9udEZhY2UoIGdsLkNDVyApO1xuXG5cdFx0Z2wucG9seWdvbk9mZnNldCggMCwgMCApO1xuXG5cdFx0Z2wuYWN0aXZlVGV4dHVyZSggZ2wuVEVYVFVSRTAgKTtcblxuXHRcdGdsLmJpbmRGcmFtZWJ1ZmZlciggZ2wuRlJBTUVCVUZGRVIsIG51bGwgKTtcblx0XHRnbC5iaW5kRnJhbWVidWZmZXIoIGdsLkRSQVdfRlJBTUVCVUZGRVIsIG51bGwgKTtcblx0XHRnbC5iaW5kRnJhbWVidWZmZXIoIGdsLlJFQURfRlJBTUVCVUZGRVIsIG51bGwgKTtcblxuXHRcdGdsLnVzZVByb2dyYW0oIG51bGwgKTtcblxuXHRcdGdsLmxpbmVXaWR0aCggMSApO1xuXG5cdFx0Z2wuc2Npc3NvciggMCwgMCwgZ2wuY2FudmFzLndpZHRoLCBnbC5jYW52YXMuaGVpZ2h0ICk7XG5cdFx0Z2wudmlld3BvcnQoIDAsIDAsIGdsLmNhbnZhcy53aWR0aCwgZ2wuY2FudmFzLmhlaWdodCApO1xuXG5cdFx0Ly8gcmVzZXQgaW50ZXJuYWxzXG5cblx0XHRlbmFibGVkQ2FwYWJpbGl0aWVzID0ge307XG5cblx0XHRjdXJyZW50VGV4dHVyZVNsb3QgPSBudWxsO1xuXHRcdGN1cnJlbnRCb3VuZFRleHR1cmVzID0ge307XG5cblx0XHRjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnMgPSB7fTtcblx0XHRjdXJyZW50RHJhd2J1ZmZlcnMgPSBuZXcgV2Vha01hcCgpO1xuXHRcdGRlZmF1bHREcmF3YnVmZmVycyA9IFtdO1xuXG5cdFx0Y3VycmVudFByb2dyYW0gPSBudWxsO1xuXG5cdFx0Y3VycmVudEJsZW5kaW5nRW5hYmxlZCA9IGZhbHNlO1xuXHRcdGN1cnJlbnRCbGVuZGluZyA9IG51bGw7XG5cdFx0Y3VycmVudEJsZW5kRXF1YXRpb24gPSBudWxsO1xuXHRcdGN1cnJlbnRCbGVuZFNyYyA9IG51bGw7XG5cdFx0Y3VycmVudEJsZW5kRHN0ID0gbnVsbDtcblx0XHRjdXJyZW50QmxlbmRFcXVhdGlvbkFscGhhID0gbnVsbDtcblx0XHRjdXJyZW50QmxlbmRTcmNBbHBoYSA9IG51bGw7XG5cdFx0Y3VycmVudEJsZW5kRHN0QWxwaGEgPSBudWxsO1xuXHRcdGN1cnJlbnRCbGVuZENvbG9yID0gbmV3IENvbG9yKCAwLCAwLCAwICk7XG5cdFx0Y3VycmVudEJsZW5kQWxwaGEgPSAwO1xuXHRcdGN1cnJlbnRQcmVtdWx0aXBsZWRBbHBoYSA9IGZhbHNlO1xuXG5cdFx0Y3VycmVudEZsaXBTaWRlZCA9IG51bGw7XG5cdFx0Y3VycmVudEN1bGxGYWNlID0gbnVsbDtcblxuXHRcdGN1cnJlbnRMaW5lV2lkdGggPSBudWxsO1xuXG5cdFx0Y3VycmVudFBvbHlnb25PZmZzZXRGYWN0b3IgPSBudWxsO1xuXHRcdGN1cnJlbnRQb2x5Z29uT2Zmc2V0VW5pdHMgPSBudWxsO1xuXG5cdFx0Y3VycmVudFNjaXNzb3Iuc2V0KCAwLCAwLCBnbC5jYW52YXMud2lkdGgsIGdsLmNhbnZhcy5oZWlnaHQgKTtcblx0XHRjdXJyZW50Vmlld3BvcnQuc2V0KCAwLCAwLCBnbC5jYW52YXMud2lkdGgsIGdsLmNhbnZhcy5oZWlnaHQgKTtcblxuXHRcdGNvbG9yQnVmZmVyLnJlc2V0KCk7XG5cdFx0ZGVwdGhCdWZmZXIucmVzZXQoKTtcblx0XHRzdGVuY2lsQnVmZmVyLnJlc2V0KCk7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cblx0XHRidWZmZXJzOiB7XG5cdFx0XHRjb2xvcjogY29sb3JCdWZmZXIsXG5cdFx0XHRkZXB0aDogZGVwdGhCdWZmZXIsXG5cdFx0XHRzdGVuY2lsOiBzdGVuY2lsQnVmZmVyXG5cdFx0fSxcblxuXHRcdGVuYWJsZTogZW5hYmxlLFxuXHRcdGRpc2FibGU6IGRpc2FibGUsXG5cblx0XHRiaW5kRnJhbWVidWZmZXI6IGJpbmRGcmFtZWJ1ZmZlcixcblx0XHRkcmF3QnVmZmVyczogZHJhd0J1ZmZlcnMsXG5cblx0XHR1c2VQcm9ncmFtOiB1c2VQcm9ncmFtLFxuXG5cdFx0c2V0QmxlbmRpbmc6IHNldEJsZW5kaW5nLFxuXHRcdHNldE1hdGVyaWFsOiBzZXRNYXRlcmlhbCxcblxuXHRcdHNldEZsaXBTaWRlZDogc2V0RmxpcFNpZGVkLFxuXHRcdHNldEN1bGxGYWNlOiBzZXRDdWxsRmFjZSxcblxuXHRcdHNldExpbmVXaWR0aDogc2V0TGluZVdpZHRoLFxuXHRcdHNldFBvbHlnb25PZmZzZXQ6IHNldFBvbHlnb25PZmZzZXQsXG5cblx0XHRzZXRTY2lzc29yVGVzdDogc2V0U2Npc3NvclRlc3QsXG5cblx0XHRhY3RpdmVUZXh0dXJlOiBhY3RpdmVUZXh0dXJlLFxuXHRcdGJpbmRUZXh0dXJlOiBiaW5kVGV4dHVyZSxcblx0XHR1bmJpbmRUZXh0dXJlOiB1bmJpbmRUZXh0dXJlLFxuXHRcdGNvbXByZXNzZWRUZXhJbWFnZTJEOiBjb21wcmVzc2VkVGV4SW1hZ2UyRCxcblx0XHRjb21wcmVzc2VkVGV4SW1hZ2UzRDogY29tcHJlc3NlZFRleEltYWdlM0QsXG5cdFx0dGV4SW1hZ2UyRDogdGV4SW1hZ2UyRCxcblx0XHR0ZXhJbWFnZTNEOiB0ZXhJbWFnZTNELFxuXG5cdFx0dXBkYXRlVUJPTWFwcGluZzogdXBkYXRlVUJPTWFwcGluZyxcblx0XHR1bmlmb3JtQmxvY2tCaW5kaW5nOiB1bmlmb3JtQmxvY2tCaW5kaW5nLFxuXG5cdFx0dGV4U3RvcmFnZTJEOiB0ZXhTdG9yYWdlMkQsXG5cdFx0dGV4U3RvcmFnZTNEOiB0ZXhTdG9yYWdlM0QsXG5cdFx0dGV4U3ViSW1hZ2UyRDogdGV4U3ViSW1hZ2UyRCxcblx0XHR0ZXhTdWJJbWFnZTNEOiB0ZXhTdWJJbWFnZTNELFxuXHRcdGNvbXByZXNzZWRUZXhTdWJJbWFnZTJEOiBjb21wcmVzc2VkVGV4U3ViSW1hZ2UyRCxcblx0XHRjb21wcmVzc2VkVGV4U3ViSW1hZ2UzRDogY29tcHJlc3NlZFRleFN1YkltYWdlM0QsXG5cblx0XHRzY2lzc29yOiBzY2lzc29yLFxuXHRcdHZpZXdwb3J0OiB2aWV3cG9ydCxcblxuXHRcdHJlc2V0OiByZXNldFxuXG5cdH07XG5cbn1cblxuZnVuY3Rpb24gY29udGFpbiggdGV4dHVyZSwgYXNwZWN0ICkge1xuXG5cdGNvbnN0IGltYWdlQXNwZWN0ID0gKCB0ZXh0dXJlLmltYWdlICYmIHRleHR1cmUuaW1hZ2Uud2lkdGggKSA/IHRleHR1cmUuaW1hZ2Uud2lkdGggLyB0ZXh0dXJlLmltYWdlLmhlaWdodCA6IDE7XG5cblx0aWYgKCBpbWFnZUFzcGVjdCA+IGFzcGVjdCApIHtcblxuXHRcdHRleHR1cmUucmVwZWF0LnggPSAxO1xuXHRcdHRleHR1cmUucmVwZWF0LnkgPSBpbWFnZUFzcGVjdCAvIGFzcGVjdDtcblxuXHRcdHRleHR1cmUub2Zmc2V0LnggPSAwO1xuXHRcdHRleHR1cmUub2Zmc2V0LnkgPSAoIDEgLSB0ZXh0dXJlLnJlcGVhdC55ICkgLyAyO1xuXG5cdH0gZWxzZSB7XG5cblx0XHR0ZXh0dXJlLnJlcGVhdC54ID0gYXNwZWN0IC8gaW1hZ2VBc3BlY3Q7XG5cdFx0dGV4dHVyZS5yZXBlYXQueSA9IDE7XG5cblx0XHR0ZXh0dXJlLm9mZnNldC54ID0gKCAxIC0gdGV4dHVyZS5yZXBlYXQueCApIC8gMjtcblx0XHR0ZXh0dXJlLm9mZnNldC55ID0gMDtcblxuXHR9XG5cblx0cmV0dXJuIHRleHR1cmU7XG5cbn1cblxuZnVuY3Rpb24gY292ZXIoIHRleHR1cmUsIGFzcGVjdCApIHtcblxuXHRjb25zdCBpbWFnZUFzcGVjdCA9ICggdGV4dHVyZS5pbWFnZSAmJiB0ZXh0dXJlLmltYWdlLndpZHRoICkgPyB0ZXh0dXJlLmltYWdlLndpZHRoIC8gdGV4dHVyZS5pbWFnZS5oZWlnaHQgOiAxO1xuXG5cdGlmICggaW1hZ2VBc3BlY3QgPiBhc3BlY3QgKSB7XG5cblx0XHR0ZXh0dXJlLnJlcGVhdC54ID0gYXNwZWN0IC8gaW1hZ2VBc3BlY3Q7XG5cdFx0dGV4dHVyZS5yZXBlYXQueSA9IDE7XG5cblx0XHR0ZXh0dXJlLm9mZnNldC54ID0gKCAxIC0gdGV4dHVyZS5yZXBlYXQueCApIC8gMjtcblx0XHR0ZXh0dXJlLm9mZnNldC55ID0gMDtcblxuXHR9IGVsc2Uge1xuXG5cdFx0dGV4dHVyZS5yZXBlYXQueCA9IDE7XG5cdFx0dGV4dHVyZS5yZXBlYXQueSA9IGltYWdlQXNwZWN0IC8gYXNwZWN0O1xuXG5cdFx0dGV4dHVyZS5vZmZzZXQueCA9IDA7XG5cdFx0dGV4dHVyZS5vZmZzZXQueSA9ICggMSAtIHRleHR1cmUucmVwZWF0LnkgKSAvIDI7XG5cblx0fVxuXG5cdHJldHVybiB0ZXh0dXJlO1xuXG59XG5cbmZ1bmN0aW9uIGZpbGwoIHRleHR1cmUgKSB7XG5cblx0dGV4dHVyZS5yZXBlYXQueCA9IDE7XG5cdHRleHR1cmUucmVwZWF0LnkgPSAxO1xuXG5cdHRleHR1cmUub2Zmc2V0LnggPSAwO1xuXHR0ZXh0dXJlLm9mZnNldC55ID0gMDtcblxuXHRyZXR1cm4gdGV4dHVyZTtcblxufVxuXG5cblxuLyoqXG4gKiBHaXZlbiB0aGUgd2lkdGgsIGhlaWdodCwgZm9ybWF0LCBhbmQgdHlwZSBvZiBhIHRleHR1cmUuIERldGVybWluZXMgaG93IG1hbnlcbiAqIGJ5dGVzIG11c3QgYmUgdXNlZCB0byByZXByZXNlbnQgdGhlIHRleHR1cmUuXG4gKi9cbmZ1bmN0aW9uIGdldEJ5dGVMZW5ndGgoIHdpZHRoLCBoZWlnaHQsIGZvcm1hdCwgdHlwZSApIHtcblxuXHRjb25zdCB0eXBlQnl0ZUxlbmd0aCA9IGdldFRleHR1cmVUeXBlQnl0ZUxlbmd0aCggdHlwZSApO1xuXG5cdHN3aXRjaCAoIGZvcm1hdCApIHtcblxuXHRcdC8vIGh0dHBzOi8vcmVnaXN0cnkua2hyb25vcy5vcmcvT3BlbkdMLVJlZnBhZ2VzL2VzMy4wL2h0bWwvZ2xUZXhJbWFnZTJELnhodG1sXG5cdFx0Y2FzZSBBbHBoYUZvcm1hdDpcblx0XHRcdHJldHVybiB3aWR0aCAqIGhlaWdodDtcblx0XHRjYXNlIEx1bWluYW5jZUZvcm1hdDpcblx0XHRcdHJldHVybiB3aWR0aCAqIGhlaWdodDtcblx0XHRjYXNlIEx1bWluYW5jZUFscGhhRm9ybWF0OlxuXHRcdFx0cmV0dXJuIHdpZHRoICogaGVpZ2h0ICogMjtcblx0XHRjYXNlIFJlZEZvcm1hdDpcblx0XHRcdHJldHVybiAoICggd2lkdGggKiBoZWlnaHQgKSAvIHR5cGVCeXRlTGVuZ3RoLmNvbXBvbmVudHMgKSAqIHR5cGVCeXRlTGVuZ3RoLmJ5dGVMZW5ndGg7XG5cdFx0Y2FzZSBSZWRJbnRlZ2VyRm9ybWF0OlxuXHRcdFx0cmV0dXJuICggKCB3aWR0aCAqIGhlaWdodCApIC8gdHlwZUJ5dGVMZW5ndGguY29tcG9uZW50cyApICogdHlwZUJ5dGVMZW5ndGguYnl0ZUxlbmd0aDtcblx0XHRjYXNlIFJHRm9ybWF0OlxuXHRcdFx0cmV0dXJuICggKCB3aWR0aCAqIGhlaWdodCAqIDIgKSAvIHR5cGVCeXRlTGVuZ3RoLmNvbXBvbmVudHMgKSAqIHR5cGVCeXRlTGVuZ3RoLmJ5dGVMZW5ndGg7XG5cdFx0Y2FzZSBSR0ludGVnZXJGb3JtYXQ6XG5cdFx0XHRyZXR1cm4gKCAoIHdpZHRoICogaGVpZ2h0ICogMiApIC8gdHlwZUJ5dGVMZW5ndGguY29tcG9uZW50cyApICogdHlwZUJ5dGVMZW5ndGguYnl0ZUxlbmd0aDtcblx0XHRjYXNlIFJHQkZvcm1hdDpcblx0XHRcdHJldHVybiAoICggd2lkdGggKiBoZWlnaHQgKiAzICkgLyB0eXBlQnl0ZUxlbmd0aC5jb21wb25lbnRzICkgKiB0eXBlQnl0ZUxlbmd0aC5ieXRlTGVuZ3RoO1xuXHRcdGNhc2UgUkdCQUZvcm1hdDpcblx0XHRcdHJldHVybiAoICggd2lkdGggKiBoZWlnaHQgKiA0ICkgLyB0eXBlQnl0ZUxlbmd0aC5jb21wb25lbnRzICkgKiB0eXBlQnl0ZUxlbmd0aC5ieXRlTGVuZ3RoO1xuXHRcdGNhc2UgUkdCQUludGVnZXJGb3JtYXQ6XG5cdFx0XHRyZXR1cm4gKCAoIHdpZHRoICogaGVpZ2h0ICogNCApIC8gdHlwZUJ5dGVMZW5ndGguY29tcG9uZW50cyApICogdHlwZUJ5dGVMZW5ndGguYnl0ZUxlbmd0aDtcblxuXHRcdC8vIGh0dHBzOi8vcmVnaXN0cnkua2hyb25vcy5vcmcvd2ViZ2wvZXh0ZW5zaW9ucy9XRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfczN0Y19zcmdiL1xuXHRcdGNhc2UgUkdCX1MzVENfRFhUMV9Gb3JtYXQ6XG5cdFx0Y2FzZSBSR0JBX1MzVENfRFhUMV9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDMgKSAvIDQgKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgMyApIC8gNCApICogODtcblx0XHRjYXNlIFJHQkFfUzNUQ19EWFQzX0Zvcm1hdDpcblx0XHRjYXNlIFJHQkFfUzNUQ19EWFQ1X0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgMyApIC8gNCApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyAzICkgLyA0ICkgKiAxNjtcblxuXHRcdC8vIGh0dHBzOi8vcmVnaXN0cnkua2hyb25vcy5vcmcvd2ViZ2wvZXh0ZW5zaW9ucy9XRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfcHZydGMvXG5cdFx0Y2FzZSBSR0JfUFZSVENfMkJQUFYxX0Zvcm1hdDpcblx0XHRjYXNlIFJHQkFfUFZSVENfMkJQUFYxX0Zvcm1hdDpcblx0XHRcdHJldHVybiAoIE1hdGgubWF4KCB3aWR0aCwgMTYgKSAqIE1hdGgubWF4KCBoZWlnaHQsIDggKSApIC8gNDtcblx0XHRjYXNlIFJHQl9QVlJUQ180QlBQVjFfRm9ybWF0OlxuXHRcdGNhc2UgUkdCQV9QVlJUQ180QlBQVjFfRm9ybWF0OlxuXHRcdFx0cmV0dXJuICggTWF0aC5tYXgoIHdpZHRoLCA4ICkgKiBNYXRoLm1heCggaGVpZ2h0LCA4ICkgKSAvIDI7XG5cblx0XHQvLyBodHRwczovL3JlZ2lzdHJ5Lmtocm9ub3Mub3JnL3dlYmdsL2V4dGVuc2lvbnMvV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX2V0Yy9cblx0XHRjYXNlIFJHQl9FVEMxX0Zvcm1hdDpcblx0XHRjYXNlIFJHQl9FVEMyX0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgMyApIC8gNCApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyAzICkgLyA0ICkgKiA4O1xuXHRcdGNhc2UgUkdCQV9FVEMyX0VBQ19Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDMgKSAvIDQgKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgMyApIC8gNCApICogMTY7XG5cblx0XHQvLyBodHRwczovL3JlZ2lzdHJ5Lmtocm9ub3Mub3JnL3dlYmdsL2V4dGVuc2lvbnMvV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX2FzdGMvXG5cdFx0Y2FzZSBSR0JBX0FTVENfNHg0X0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgMyApIC8gNCApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyAzICkgLyA0ICkgKiAxNjtcblx0XHRjYXNlIFJHQkFfQVNUQ181eDRfRm9ybWF0OlxuXHRcdFx0cmV0dXJuIE1hdGguZmxvb3IoICggd2lkdGggKyA0ICkgLyA1ICkgKiBNYXRoLmZsb29yKCAoIGhlaWdodCArIDMgKSAvIDQgKSAqIDE2O1xuXHRcdGNhc2UgUkdCQV9BU1RDXzV4NV9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDQgKSAvIDUgKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgNCApIC8gNSApICogMTY7XG5cdFx0Y2FzZSBSR0JBX0FTVENfNng1X0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgNSApIC8gNiApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyA0ICkgLyA1ICkgKiAxNjtcblx0XHRjYXNlIFJHQkFfQVNUQ182eDZfRm9ybWF0OlxuXHRcdFx0cmV0dXJuIE1hdGguZmxvb3IoICggd2lkdGggKyA1ICkgLyA2ICkgKiBNYXRoLmZsb29yKCAoIGhlaWdodCArIDUgKSAvIDYgKSAqIDE2O1xuXHRcdGNhc2UgUkdCQV9BU1RDXzh4NV9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDcgKSAvIDggKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgNCApIC8gNSApICogMTY7XG5cdFx0Y2FzZSBSR0JBX0FTVENfOHg2X0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgNyApIC8gOCApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyA1ICkgLyA2ICkgKiAxNjtcblx0XHRjYXNlIFJHQkFfQVNUQ184eDhfRm9ybWF0OlxuXHRcdFx0cmV0dXJuIE1hdGguZmxvb3IoICggd2lkdGggKyA3ICkgLyA4ICkgKiBNYXRoLmZsb29yKCAoIGhlaWdodCArIDcgKSAvIDggKSAqIDE2O1xuXHRcdGNhc2UgUkdCQV9BU1RDXzEweDVfRm9ybWF0OlxuXHRcdFx0cmV0dXJuIE1hdGguZmxvb3IoICggd2lkdGggKyA5ICkgLyAxMCApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyA0ICkgLyA1ICkgKiAxNjtcblx0XHRjYXNlIFJHQkFfQVNUQ18xMHg2X0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgOSApIC8gMTAgKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgNSApIC8gNiApICogMTY7XG5cdFx0Y2FzZSBSR0JBX0FTVENfMTB4OF9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDkgKSAvIDEwICkgKiBNYXRoLmZsb29yKCAoIGhlaWdodCArIDcgKSAvIDggKSAqIDE2O1xuXHRcdGNhc2UgUkdCQV9BU1RDXzEweDEwX0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgOSApIC8gMTAgKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgOSApIC8gMTAgKSAqIDE2O1xuXHRcdGNhc2UgUkdCQV9BU1RDXzEyeDEwX0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgMTEgKSAvIDEyICkgKiBNYXRoLmZsb29yKCAoIGhlaWdodCArIDkgKSAvIDEwICkgKiAxNjtcblx0XHRjYXNlIFJHQkFfQVNUQ18xMngxMl9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDExICkgLyAxMiApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyAxMSApIC8gMTIgKSAqIDE2O1xuXG5cdFx0Ly8gaHR0cHM6Ly9yZWdpc3RyeS5raHJvbm9zLm9yZy93ZWJnbC9leHRlbnNpb25zL0VYVF90ZXh0dXJlX2NvbXByZXNzaW9uX2JwdGMvXG5cdFx0Y2FzZSBSR0JBX0JQVENfRm9ybWF0OlxuXHRcdGNhc2UgUkdCX0JQVENfU0lHTkVEX0Zvcm1hdDpcblx0XHRjYXNlIFJHQl9CUFRDX1VOU0lHTkVEX0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmNlaWwoIHdpZHRoIC8gNCApICogTWF0aC5jZWlsKCBoZWlnaHQgLyA0ICkgKiAxNjtcblxuXHRcdC8vIGh0dHBzOi8vcmVnaXN0cnkua2hyb25vcy5vcmcvd2ViZ2wvZXh0ZW5zaW9ucy9FWFRfdGV4dHVyZV9jb21wcmVzc2lvbl9yZ3RjL1xuXHRcdGNhc2UgUkVEX1JHVEMxX0Zvcm1hdDpcblx0XHRjYXNlIFNJR05FRF9SRURfUkdUQzFfRm9ybWF0OlxuXHRcdFx0cmV0dXJuIE1hdGguY2VpbCggd2lkdGggLyA0ICkgKiBNYXRoLmNlaWwoIGhlaWdodCAvIDQgKSAqIDg7XG5cdFx0Y2FzZSBSRURfR1JFRU5fUkdUQzJfRm9ybWF0OlxuXHRcdGNhc2UgU0lHTkVEX1JFRF9HUkVFTl9SR1RDMl9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5jZWlsKCB3aWR0aCAvIDQgKSAqIE1hdGguY2VpbCggaGVpZ2h0IC8gNCApICogMTY7XG5cblx0fVxuXG5cdHRocm93IG5ldyBFcnJvcihcblx0XHRgVW5hYmxlIHRvIGRldGVybWluZSB0ZXh0dXJlIGJ5dGUgbGVuZ3RoIGZvciAke2Zvcm1hdH0gZm9ybWF0LmAsXG5cdCk7XG5cbn1cblxuZnVuY3Rpb24gZ2V0VGV4dHVyZVR5cGVCeXRlTGVuZ3RoKCB0eXBlICkge1xuXG5cdHN3aXRjaCAoIHR5cGUgKSB7XG5cblx0XHRjYXNlIFVuc2lnbmVkQnl0ZVR5cGU6XG5cdFx0Y2FzZSBCeXRlVHlwZTpcblx0XHRcdHJldHVybiB7IGJ5dGVMZW5ndGg6IDEsIGNvbXBvbmVudHM6IDEgfTtcblx0XHRjYXNlIFVuc2lnbmVkU2hvcnRUeXBlOlxuXHRcdGNhc2UgU2hvcnRUeXBlOlxuXHRcdGNhc2UgSGFsZkZsb2F0VHlwZTpcblx0XHRcdHJldHVybiB7IGJ5dGVMZW5ndGg6IDIsIGNvbXBvbmVudHM6IDEgfTtcblx0XHRjYXNlIFVuc2lnbmVkU2hvcnQ0NDQ0VHlwZTpcblx0XHRjYXNlIFVuc2lnbmVkU2hvcnQ1NTUxVHlwZTpcblx0XHRcdHJldHVybiB7IGJ5dGVMZW5ndGg6IDIsIGNvbXBvbmVudHM6IDQgfTtcblx0XHRjYXNlIFVuc2lnbmVkSW50VHlwZTpcblx0XHRjYXNlIEludFR5cGU6XG5cdFx0Y2FzZSBGbG9hdFR5cGU6XG5cdFx0XHRyZXR1cm4geyBieXRlTGVuZ3RoOiA0LCBjb21wb25lbnRzOiAxIH07XG5cdFx0Y2FzZSBVbnNpZ25lZEludDU5OTlUeXBlOlxuXHRcdFx0cmV0dXJuIHsgYnl0ZUxlbmd0aDogNCwgY29tcG9uZW50czogMyB9O1xuXG5cdH1cblxuXHR0aHJvdyBuZXcgRXJyb3IoIGBVbmtub3duIHRleHR1cmUgdHlwZSAke3R5cGV9LmAgKTtcblxufVxuXG5jb25zdCBUZXh0dXJlVXRpbHMgPSB7XG5cdGNvbnRhaW4sXG5cdGNvdmVyLFxuXHRmaWxsLFxuXHRnZXRCeXRlTGVuZ3RoXG59O1xuXG5mdW5jdGlvbiBXZWJHTFRleHR1cmVzKCBfZ2wsIGV4dGVuc2lvbnMsIHN0YXRlLCBwcm9wZXJ0aWVzLCBjYXBhYmlsaXRpZXMsIHV0aWxzLCBpbmZvICkge1xuXG5cdGNvbnN0IG11bHRpc2FtcGxlZFJUVEV4dCA9IGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfbXVsdGlzYW1wbGVkX3JlbmRlcl90b190ZXh0dXJlJyApID8gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9tdWx0aXNhbXBsZWRfcmVuZGVyX3RvX3RleHR1cmUnICkgOiBudWxsO1xuXHRjb25zdCBzdXBwb3J0c0ludmFsaWRhdGVGcmFtZWJ1ZmZlciA9IHR5cGVvZiBuYXZpZ2F0b3IgPT09ICd1bmRlZmluZWQnID8gZmFsc2UgOiAvT2N1bHVzQnJvd3Nlci9nLnRlc3QoIG5hdmlnYXRvci51c2VyQWdlbnQgKTtcblxuXHRjb25zdCBfaW1hZ2VEaW1lbnNpb25zID0gbmV3IFZlY3RvcjIoKTtcblx0Y29uc3QgX3ZpZGVvVGV4dHVyZXMgPSBuZXcgV2Vha01hcCgpO1xuXHRsZXQgX2NhbnZhcztcblxuXHRjb25zdCBfc291cmNlcyA9IG5ldyBXZWFrTWFwKCk7IC8vIG1hcHMgV2ViZ2xUZXh0dXJlIG9iamVjdHMgdG8gaW5zdGFuY2VzIG9mIFNvdXJjZVxuXG5cdC8vIGNvcmRvdmEgaU9TIChhcyBvZiA1LjApIHN0aWxsIHVzZXMgVUlXZWJWaWV3LCB3aGljaCBwcm92aWRlcyBPZmZzY3JlZW5DYW52YXMsXG5cdC8vIGFsc28gT2Zmc2NyZWVuQ2FudmFzLmdldENvbnRleHQoXCJ3ZWJnbFwiKSwgYnV0IG5vdCBPZmZzY3JlZW5DYW52YXMuZ2V0Q29udGV4dChcIjJkXCIpIVxuXHQvLyBTb21lIGltcGxlbWVudGF0aW9ucyBtYXkgb25seSBpbXBsZW1lbnQgT2Zmc2NyZWVuQ2FudmFzIHBhcnRpYWxseSAoZS5nLiBsYWNraW5nIDJkKS5cblxuXHRsZXQgdXNlT2Zmc2NyZWVuQ2FudmFzID0gZmFsc2U7XG5cblx0dHJ5IHtcblxuXHRcdHVzZU9mZnNjcmVlbkNhbnZhcyA9IHR5cGVvZiBPZmZzY3JlZW5DYW52YXMgIT09ICd1bmRlZmluZWQnXG5cdFx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY29tcGF0L2NvbXBhdFxuXHRcdFx0JiYgKCBuZXcgT2Zmc2NyZWVuQ2FudmFzKCAxLCAxICkuZ2V0Q29udGV4dCggJzJkJyApICkgIT09IG51bGw7XG5cblx0fSBjYXRjaCAoIGVyciApIHtcblxuXHRcdC8vIElnbm9yZSBhbnkgZXJyb3JzXG5cblx0fVxuXG5cdGZ1bmN0aW9uIGNyZWF0ZUNhbnZhcyggd2lkdGgsIGhlaWdodCApIHtcblxuXHRcdC8vIFVzZSBPZmZzY3JlZW5DYW52YXMgd2hlbiBhdmFpbGFibGUuIFNwZWNpYWxseSBuZWVkZWQgaW4gd2ViIHdvcmtlcnNcblxuXHRcdHJldHVybiB1c2VPZmZzY3JlZW5DYW52YXMgP1xuXHRcdFx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBhdC9jb21wYXRcblx0XHRcdG5ldyBPZmZzY3JlZW5DYW52YXMoIHdpZHRoLCBoZWlnaHQgKSA6IGNyZWF0ZUVsZW1lbnROUyggJ2NhbnZhcycgKTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVzaXplSW1hZ2UoIGltYWdlLCBuZWVkc05ld0NhbnZhcywgbWF4U2l6ZSApIHtcblxuXHRcdGxldCBzY2FsZSA9IDE7XG5cblx0XHRjb25zdCBkaW1lbnNpb25zID0gZ2V0RGltZW5zaW9ucyggaW1hZ2UgKTtcblxuXHRcdC8vIGhhbmRsZSBjYXNlIGlmIHRleHR1cmUgZXhjZWVkcyBtYXggc2l6ZVxuXG5cdFx0aWYgKCBkaW1lbnNpb25zLndpZHRoID4gbWF4U2l6ZSB8fCBkaW1lbnNpb25zLmhlaWdodCA+IG1heFNpemUgKSB7XG5cblx0XHRcdHNjYWxlID0gbWF4U2l6ZSAvIE1hdGgubWF4KCBkaW1lbnNpb25zLndpZHRoLCBkaW1lbnNpb25zLmhlaWdodCApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gb25seSBwZXJmb3JtIHJlc2l6ZSBpZiBuZWNlc3NhcnlcblxuXHRcdGlmICggc2NhbGUgPCAxICkge1xuXG5cdFx0XHQvLyBvbmx5IHBlcmZvcm0gcmVzaXplIGZvciBjZXJ0YWluIGltYWdlIHR5cGVzXG5cblx0XHRcdGlmICggKCB0eXBlb2YgSFRNTEltYWdlRWxlbWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBIVE1MSW1hZ2VFbGVtZW50ICkgfHxcblx0XHRcdFx0KCB0eXBlb2YgSFRNTENhbnZhc0VsZW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGltYWdlIGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQgKSB8fFxuXHRcdFx0XHQoIHR5cGVvZiBJbWFnZUJpdG1hcCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBJbWFnZUJpdG1hcCApIHx8XG5cdFx0XHRcdCggdHlwZW9mIFZpZGVvRnJhbWUgIT09ICd1bmRlZmluZWQnICYmIGltYWdlIGluc3RhbmNlb2YgVmlkZW9GcmFtZSApICkge1xuXG5cdFx0XHRcdGNvbnN0IHdpZHRoID0gTWF0aC5mbG9vciggc2NhbGUgKiBkaW1lbnNpb25zLndpZHRoICk7XG5cdFx0XHRcdGNvbnN0IGhlaWdodCA9IE1hdGguZmxvb3IoIHNjYWxlICogZGltZW5zaW9ucy5oZWlnaHQgKTtcblxuXHRcdFx0XHRpZiAoIF9jYW52YXMgPT09IHVuZGVmaW5lZCApIF9jYW52YXMgPSBjcmVhdGVDYW52YXMoIHdpZHRoLCBoZWlnaHQgKTtcblxuXHRcdFx0XHQvLyBjdWJlIHRleHR1cmVzIGNhbid0IHJldXNlIHRoZSBzYW1lIGNhbnZhc1xuXG5cdFx0XHRcdGNvbnN0IGNhbnZhcyA9IG5lZWRzTmV3Q2FudmFzID8gY3JlYXRlQ2FudmFzKCB3aWR0aCwgaGVpZ2h0ICkgOiBfY2FudmFzO1xuXG5cdFx0XHRcdGNhbnZhcy53aWR0aCA9IHdpZHRoO1xuXHRcdFx0XHRjYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xuXG5cdFx0XHRcdGNvbnN0IGNvbnRleHQgPSBjYW52YXMuZ2V0Q29udGV4dCggJzJkJyApO1xuXHRcdFx0XHRjb250ZXh0LmRyYXdJbWFnZSggaW1hZ2UsIDAsIDAsIHdpZHRoLCBoZWlnaHQgKTtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBUZXh0dXJlIGhhcyBiZWVuIHJlc2l6ZWQgZnJvbSAoJyArIGRpbWVuc2lvbnMud2lkdGggKyAneCcgKyBkaW1lbnNpb25zLmhlaWdodCArICcpIHRvICgnICsgd2lkdGggKyAneCcgKyBoZWlnaHQgKyAnKS4nICk7XG5cblx0XHRcdFx0cmV0dXJuIGNhbnZhcztcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRpZiAoICdkYXRhJyBpbiBpbWFnZSApIHtcblxuXHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IEltYWdlIGluIERhdGFUZXh0dXJlIGlzIHRvbyBiaWcgKCcgKyBkaW1lbnNpb25zLndpZHRoICsgJ3gnICsgZGltZW5zaW9ucy5oZWlnaHQgKyAnKS4nICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiBpbWFnZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGltYWdlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiB0ZXh0dXJlTmVlZHNHZW5lcmF0ZU1pcG1hcHMoIHRleHR1cmUgKSB7XG5cblx0XHRyZXR1cm4gdGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgJiYgdGV4dHVyZS5taW5GaWx0ZXIgIT09IE5lYXJlc3RGaWx0ZXIgJiYgdGV4dHVyZS5taW5GaWx0ZXIgIT09IExpbmVhckZpbHRlcjtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2VuZXJhdGVNaXBtYXAoIHRhcmdldCApIHtcblxuXHRcdF9nbC5nZW5lcmF0ZU1pcG1hcCggdGFyZ2V0ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldEludGVybmFsRm9ybWF0KCBpbnRlcm5hbEZvcm1hdE5hbWUsIGdsRm9ybWF0LCBnbFR5cGUsIGNvbG9yU3BhY2UsIGZvcmNlTGluZWFyVHJhbnNmZXIgPSBmYWxzZSApIHtcblxuXHRcdGlmICggaW50ZXJuYWxGb3JtYXROYW1lICE9PSBudWxsICkge1xuXG5cdFx0XHRpZiAoIF9nbFsgaW50ZXJuYWxGb3JtYXROYW1lIF0gIT09IHVuZGVmaW5lZCApIHJldHVybiBfZ2xbIGludGVybmFsRm9ybWF0TmFtZSBdO1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBBdHRlbXB0IHRvIHVzZSBub24tZXhpc3RpbmcgV2ViR0wgaW50ZXJuYWwgZm9ybWF0IFxcJycgKyBpbnRlcm5hbEZvcm1hdE5hbWUgKyAnXFwnJyApO1xuXG5cdFx0fVxuXG5cdFx0bGV0IGludGVybmFsRm9ybWF0ID0gZ2xGb3JtYXQ7XG5cblx0XHRpZiAoIGdsRm9ybWF0ID09PSBfZ2wuUkVEICkge1xuXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkZMT0FUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjMyRjtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuSEFMRl9GTE9BVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlIxNkY7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX0JZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SODtcblxuXHRcdH1cblxuXHRcdGlmICggZ2xGb3JtYXQgPT09IF9nbC5SRURfSU5URUdFUiApIHtcblxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9CWVRFICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjhVSTtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfU0hPUlQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SMTZVSTtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfSU5UICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjMyVUk7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkJZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SOEk7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlNIT1JUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjE2STtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuSU5UICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjMySTtcblxuXHRcdH1cblxuXHRcdGlmICggZ2xGb3JtYXQgPT09IF9nbC5SRyApIHtcblxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5GTE9BVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHMzJGO1xuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5IQUxGX0ZMT0FUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkcxNkY7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX0JZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SRzg7XG5cblx0XHR9XG5cblx0XHRpZiAoIGdsRm9ybWF0ID09PSBfZ2wuUkdfSU5URUdFUiApIHtcblxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9CWVRFICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkc4VUk7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX1NIT1JUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkcxNlVJO1xuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9JTlQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SRzMyVUk7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkJZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SRzhJO1xuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5TSE9SVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHMTZJO1xuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5JTlQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SRzMySTtcblxuXHRcdH1cblxuXHRcdGlmICggZ2xGb3JtYXQgPT09IF9nbC5SR0IgKSB7XG5cblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfSU5UXzVfOV85XzlfUkVWICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkdCOV9FNTtcblxuXHRcdH1cblxuXHRcdGlmICggZ2xGb3JtYXQgPT09IF9nbC5SR0JBICkge1xuXG5cdFx0XHRjb25zdCB0cmFuc2ZlciA9IGZvcmNlTGluZWFyVHJhbnNmZXIgPyBMaW5lYXJUcmFuc2ZlciA6IENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggY29sb3JTcGFjZSApO1xuXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkZMT0FUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkdCQTMyRjtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuSEFMRl9GTE9BVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHQkExNkY7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX0JZVEUgKSBpbnRlcm5hbEZvcm1hdCA9ICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gX2dsLlNSR0I4X0FMUEhBOCA6IF9nbC5SR0JBODtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfU0hPUlRfNF80XzRfNCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHQkE0O1xuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9TSE9SVF81XzVfNV8xICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkdCNV9BMTtcblxuXHRcdH1cblxuXHRcdGlmICggaW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SMTZGIHx8IGludGVybmFsRm9ybWF0ID09PSBfZ2wuUjMyRiB8fFxuXHRcdFx0aW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SRzE2RiB8fCBpbnRlcm5hbEZvcm1hdCA9PT0gX2dsLlJHMzJGIHx8XG5cdFx0XHRpbnRlcm5hbEZvcm1hdCA9PT0gX2dsLlJHQkExNkYgfHwgaW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SR0JBMzJGICkge1xuXG5cdFx0XHRleHRlbnNpb25zLmdldCggJ0VYVF9jb2xvcl9idWZmZXJfZmxvYXQnICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gaW50ZXJuYWxGb3JtYXQ7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldEludGVybmFsRGVwdGhGb3JtYXQoIHVzZVN0ZW5jaWwsIGRlcHRoVHlwZSApIHtcblxuXHRcdGxldCBnbEludGVybmFsRm9ybWF0O1xuXHRcdGlmICggdXNlU3RlbmNpbCApIHtcblxuXHRcdFx0aWYgKCBkZXB0aFR5cGUgPT09IG51bGwgfHwgZGVwdGhUeXBlID09PSBVbnNpZ25lZEludFR5cGUgfHwgZGVwdGhUeXBlID09PSBVbnNpZ25lZEludDI0OFR5cGUgKSB7XG5cblx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IF9nbC5ERVBUSDI0X1NURU5DSUw4O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBkZXB0aFR5cGUgPT09IEZsb2F0VHlwZSApIHtcblxuXHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gX2dsLkRFUFRIMzJGX1NURU5DSUw4O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBkZXB0aFR5cGUgPT09IFVuc2lnbmVkU2hvcnRUeXBlICkge1xuXG5cdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBfZ2wuREVQVEgyNF9TVEVOQ0lMODtcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnRGVwdGhUZXh0dXJlOiAxNiBiaXQgZGVwdGggYXR0YWNobWVudCBpcyBub3Qgc3VwcG9ydGVkIHdpdGggc3RlbmNpbC4gVXNpbmcgMjQtYml0IGF0dGFjaG1lbnQuJyApO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIGRlcHRoVHlwZSA9PT0gbnVsbCB8fCBkZXB0aFR5cGUgPT09IFVuc2lnbmVkSW50VHlwZSB8fCBkZXB0aFR5cGUgPT09IFVuc2lnbmVkSW50MjQ4VHlwZSApIHtcblxuXHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gX2dsLkRFUFRIX0NPTVBPTkVOVDI0O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBkZXB0aFR5cGUgPT09IEZsb2F0VHlwZSApIHtcblxuXHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gX2dsLkRFUFRIX0NPTVBPTkVOVDMyRjtcblxuXHRcdFx0fSBlbHNlIGlmICggZGVwdGhUeXBlID09PSBVbnNpZ25lZFNob3J0VHlwZSApIHtcblxuXHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gX2dsLkRFUFRIX0NPTVBPTkVOVDE2O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gZ2xJbnRlcm5hbEZvcm1hdDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0TWlwTGV2ZWxzKCB0ZXh0dXJlLCBpbWFnZSApIHtcblxuXHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlICkgPT09IHRydWUgfHwgKCB0ZXh0dXJlLmlzRnJhbWVidWZmZXJUZXh0dXJlICYmIHRleHR1cmUubWluRmlsdGVyICE9PSBOZWFyZXN0RmlsdGVyICYmIHRleHR1cmUubWluRmlsdGVyICE9PSBMaW5lYXJGaWx0ZXIgKSApIHtcblxuXHRcdFx0cmV0dXJuIE1hdGgubG9nMiggTWF0aC5tYXgoIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKSApICsgMTtcblxuXHRcdH0gZWxzZSBpZiAoIHRleHR1cmUubWlwbWFwcyAhPT0gdW5kZWZpbmVkICYmIHRleHR1cmUubWlwbWFwcy5sZW5ndGggPiAwICkge1xuXG5cdFx0XHQvLyB1c2VyLWRlZmluZWQgbWlwbWFwc1xuXG5cdFx0XHRyZXR1cm4gdGV4dHVyZS5taXBtYXBzLmxlbmd0aDtcblxuXHRcdH0gZWxzZSBpZiAoIHRleHR1cmUuaXNDb21wcmVzc2VkVGV4dHVyZSAmJiBBcnJheS5pc0FycmF5KCB0ZXh0dXJlLmltYWdlICkgKSB7XG5cblx0XHRcdHJldHVybiBpbWFnZS5taXBtYXBzLmxlbmd0aDtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIHRleHR1cmUgd2l0aG91dCBtaXBtYXBzIChvbmx5IGJhc2UgbGV2ZWwpXG5cblx0XHRcdHJldHVybiAxO1xuXG5cdFx0fVxuXG5cdH1cblxuXHQvL1xuXG5cdGZ1bmN0aW9uIG9uVGV4dHVyZURpc3Bvc2UoIGV2ZW50ICkge1xuXG5cdFx0Y29uc3QgdGV4dHVyZSA9IGV2ZW50LnRhcmdldDtcblxuXHRcdHRleHR1cmUucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XG5cblx0XHRkZWFsbG9jYXRlVGV4dHVyZSggdGV4dHVyZSApO1xuXG5cdFx0aWYgKCB0ZXh0dXJlLmlzVmlkZW9UZXh0dXJlICkge1xuXG5cdFx0XHRfdmlkZW9UZXh0dXJlcy5kZWxldGUoIHRleHR1cmUgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gb25SZW5kZXJUYXJnZXREaXNwb3NlKCBldmVudCApIHtcblxuXHRcdGNvbnN0IHJlbmRlclRhcmdldCA9IGV2ZW50LnRhcmdldDtcblxuXHRcdHJlbmRlclRhcmdldC5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uUmVuZGVyVGFyZ2V0RGlzcG9zZSApO1xuXG5cdFx0ZGVhbGxvY2F0ZVJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0ICk7XG5cblx0fVxuXG5cdC8vXG5cblx0ZnVuY3Rpb24gZGVhbGxvY2F0ZVRleHR1cmUoIHRleHR1cmUgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICk7XG5cblx0XHRpZiAoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xJbml0ID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHQvLyBjaGVjayBpZiBpdCdzIG5lY2Vzc2FyeSB0byByZW1vdmUgdGhlIFdlYkdMVGV4dHVyZSBvYmplY3RcblxuXHRcdGNvbnN0IHNvdXJjZSA9IHRleHR1cmUuc291cmNlO1xuXHRcdGNvbnN0IHdlYmdsVGV4dHVyZXMgPSBfc291cmNlcy5nZXQoIHNvdXJjZSApO1xuXG5cdFx0aWYgKCB3ZWJnbFRleHR1cmVzICkge1xuXG5cdFx0XHRjb25zdCB3ZWJnbFRleHR1cmUgPSB3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlUHJvcGVydGllcy5fX2NhY2hlS2V5IF07XG5cdFx0XHR3ZWJnbFRleHR1cmUudXNlZFRpbWVzIC0tO1xuXG5cdFx0XHQvLyB0aGUgV2ViR0xUZXh0dXJlIG9iamVjdCBpcyBub3QgdXNlZCBhbnltb3JlLCByZW1vdmUgaXRcblxuXHRcdFx0aWYgKCB3ZWJnbFRleHR1cmUudXNlZFRpbWVzID09PSAwICkge1xuXG5cdFx0XHRcdGRlbGV0ZVRleHR1cmUoIHRleHR1cmUgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyByZW1vdmUgdGhlIHdlYWsgbWFwIGVudHJ5IGlmIG5vIFdlYkdMVGV4dHVyZSB1c2VzIHRoZSBzb3VyY2UgYW55bW9yZVxuXG5cdFx0XHRpZiAoIE9iamVjdC5rZXlzKCB3ZWJnbFRleHR1cmVzICkubGVuZ3RoID09PSAwICkge1xuXG5cdFx0XHRcdF9zb3VyY2VzLmRlbGV0ZSggc291cmNlICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHByb3BlcnRpZXMucmVtb3ZlKCB0ZXh0dXJlICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRlbGV0ZVRleHR1cmUoIHRleHR1cmUgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICk7XG5cdFx0X2dsLmRlbGV0ZVRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlICk7XG5cblx0XHRjb25zdCBzb3VyY2UgPSB0ZXh0dXJlLnNvdXJjZTtcblx0XHRjb25zdCB3ZWJnbFRleHR1cmVzID0gX3NvdXJjZXMuZ2V0KCBzb3VyY2UgKTtcblx0XHRkZWxldGUgd2ViZ2xUZXh0dXJlc1sgdGV4dHVyZVByb3BlcnRpZXMuX19jYWNoZUtleSBdO1xuXG5cdFx0aW5mby5tZW1vcnkudGV4dHVyZXMgLS07XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRlYWxsb2NhdGVSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCApIHtcblxuXHRcdGNvbnN0IHJlbmRlclRhcmdldFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgKSB7XG5cblx0XHRcdHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUuZGlzcG9zZSgpO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgaSBdICkgKSB7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgbGV2ZWwgPSAwOyBsZXZlbCA8IHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF0ubGVuZ3RoOyBsZXZlbCArKyApIF9nbC5kZWxldGVGcmFtZWJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXVsgbGV2ZWwgXSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRfZ2wuZGVsZXRlRnJhbWVidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF0gKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciApIF9nbC5kZWxldGVSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyWyBpIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciApICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBsZXZlbCA9IDA7IGxldmVsIDwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIubGVuZ3RoOyBsZXZlbCArKyApIF9nbC5kZWxldGVGcmFtZWJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGxldmVsIF0gKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRfZ2wuZGVsZXRlRnJhbWVidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciApIF9nbC5kZWxldGVSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyICk7XG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICkgX2dsLmRlbGV0ZUZyYW1lYnVmZmVyKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlciApO1xuXG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsQ29sb3JSZW5kZXJidWZmZXJbIGkgXSApIF9nbC5kZWxldGVSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyWyBpIF0gKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aFJlbmRlcmJ1ZmZlciApIF9nbC5kZWxldGVSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoUmVuZGVyYnVmZmVyICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCB0ZXh0dXJlcyA9IHJlbmRlclRhcmdldC50ZXh0dXJlcztcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgYXR0YWNobWVudFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZXNbIGkgXSApO1xuXG5cdFx0XHRpZiAoIGF0dGFjaG1lbnRQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlICkge1xuXG5cdFx0XHRcdF9nbC5kZWxldGVUZXh0dXJlKCBhdHRhY2htZW50UHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xuXG5cdFx0XHRcdGluZm8ubWVtb3J5LnRleHR1cmVzIC0tO1xuXG5cdFx0XHR9XG5cblx0XHRcdHByb3BlcnRpZXMucmVtb3ZlKCB0ZXh0dXJlc1sgaSBdICk7XG5cblx0XHR9XG5cblx0XHRwcm9wZXJ0aWVzLnJlbW92ZSggcmVuZGVyVGFyZ2V0ICk7XG5cblx0fVxuXG5cdC8vXG5cblx0bGV0IHRleHR1cmVVbml0cyA9IDA7XG5cblx0ZnVuY3Rpb24gcmVzZXRUZXh0dXJlVW5pdHMoKSB7XG5cblx0XHR0ZXh0dXJlVW5pdHMgPSAwO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBhbGxvY2F0ZVRleHR1cmVVbml0KCkge1xuXG5cdFx0Y29uc3QgdGV4dHVyZVVuaXQgPSB0ZXh0dXJlVW5pdHM7XG5cblx0XHRpZiAoIHRleHR1cmVVbml0ID49IGNhcGFiaWxpdGllcy5tYXhUZXh0dXJlcyApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xUZXh0dXJlczogVHJ5aW5nIHRvIHVzZSAnICsgdGV4dHVyZVVuaXQgKyAnIHRleHR1cmUgdW5pdHMgd2hpbGUgdGhpcyBHUFUgc3VwcG9ydHMgb25seSAnICsgY2FwYWJpbGl0aWVzLm1heFRleHR1cmVzICk7XG5cblx0XHR9XG5cblx0XHR0ZXh0dXJlVW5pdHMgKz0gMTtcblxuXHRcdHJldHVybiB0ZXh0dXJlVW5pdDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0VGV4dHVyZUNhY2hlS2V5KCB0ZXh0dXJlICkge1xuXG5cdFx0Y29uc3QgYXJyYXkgPSBbXTtcblxuXHRcdGFycmF5LnB1c2goIHRleHR1cmUud3JhcFMgKTtcblx0XHRhcnJheS5wdXNoKCB0ZXh0dXJlLndyYXBUICk7XG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS53cmFwUiB8fCAwICk7XG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5tYWdGaWx0ZXIgKTtcblx0XHRhcnJheS5wdXNoKCB0ZXh0dXJlLm1pbkZpbHRlciApO1xuXHRcdGFycmF5LnB1c2goIHRleHR1cmUuYW5pc290cm9weSApO1xuXHRcdGFycmF5LnB1c2goIHRleHR1cmUuaW50ZXJuYWxGb3JtYXQgKTtcblx0XHRhcnJheS5wdXNoKCB0ZXh0dXJlLmZvcm1hdCApO1xuXHRcdGFycmF5LnB1c2goIHRleHR1cmUudHlwZSApO1xuXHRcdGFycmF5LnB1c2goIHRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzICk7XG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5wcmVtdWx0aXBseUFscGhhICk7XG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5mbGlwWSApO1xuXHRcdGFycmF5LnB1c2goIHRleHR1cmUudW5wYWNrQWxpZ25tZW50ICk7XG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cblx0XHRyZXR1cm4gYXJyYXkuam9pbigpO1xuXG5cdH1cblxuXHQvL1xuXG5cdGZ1bmN0aW9uIHNldFRleHR1cmUyRCggdGV4dHVyZSwgc2xvdCApIHtcblxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcblxuXHRcdGlmICggdGV4dHVyZS5pc1ZpZGVvVGV4dHVyZSApIHVwZGF0ZVZpZGVvVGV4dHVyZSggdGV4dHVyZSApO1xuXG5cdFx0aWYgKCB0ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgJiYgdGV4dHVyZS52ZXJzaW9uID4gMCAmJiB0ZXh0dXJlUHJvcGVydGllcy5fX3ZlcnNpb24gIT09IHRleHR1cmUudmVyc2lvbiApIHtcblxuXHRcdFx0Y29uc3QgaW1hZ2UgPSB0ZXh0dXJlLmltYWdlO1xuXG5cdFx0XHRpZiAoIGltYWdlID09PSBudWxsICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFRleHR1cmUgbWFya2VkIGZvciB1cGRhdGUgYnV0IG5vIGltYWdlIGRhdGEgZm91bmQuJyApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBpbWFnZS5jb21wbGV0ZSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVGV4dHVyZSBtYXJrZWQgZm9yIHVwZGF0ZSBidXQgaW1hZ2UgaXMgaW5jb21wbGV0ZScgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHR1cGxvYWRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApO1xuXHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBfZ2wuVEVYVFVSRV8yRCwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIF9nbC5URVhUVVJFMCArIHNsb3QgKTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gc2V0VGV4dHVyZTJEQXJyYXkoIHRleHR1cmUsIHNsb3QgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICk7XG5cblx0XHRpZiAoIHRleHR1cmUudmVyc2lvbiA+IDAgJiYgdGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uICE9PSB0ZXh0dXJlLnZlcnNpb24gKSB7XG5cblx0XHRcdHVwbG9hZFRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLCB0ZXh0dXJlLCBzbG90ICk7XG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHRzdGF0ZS5iaW5kVGV4dHVyZSggX2dsLlRFWFRVUkVfMkRfQVJSQVksIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlLCBfZ2wuVEVYVFVSRTAgKyBzbG90ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHNldFRleHR1cmUzRCggdGV4dHVyZSwgc2xvdCApIHtcblxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcblxuXHRcdGlmICggdGV4dHVyZS52ZXJzaW9uID4gMCAmJiB0ZXh0dXJlUHJvcGVydGllcy5fX3ZlcnNpb24gIT09IHRleHR1cmUudmVyc2lvbiApIHtcblxuXHRcdFx0dXBsb2FkVGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMsIHRleHR1cmUsIHNsb3QgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBfZ2wuVEVYVFVSRV8zRCwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIF9nbC5URVhUVVJFMCArIHNsb3QgKTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gc2V0VGV4dHVyZUN1YmUoIHRleHR1cmUsIHNsb3QgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICk7XG5cblx0XHRpZiAoIHRleHR1cmUudmVyc2lvbiA+IDAgJiYgdGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uICE9PSB0ZXh0dXJlLnZlcnNpb24gKSB7XG5cblx0XHRcdHVwbG9hZEN1YmVUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApO1xuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgX2dsLlRFWFRVUkUwICsgc2xvdCApO1xuXG5cdH1cblxuXHRjb25zdCB3cmFwcGluZ1RvR0wgPSB7XG5cdFx0WyBSZXBlYXRXcmFwcGluZyBdOiBfZ2wuUkVQRUFULFxuXHRcdFsgQ2xhbXBUb0VkZ2VXcmFwcGluZyBdOiBfZ2wuQ0xBTVBfVE9fRURHRSxcblx0XHRbIE1pcnJvcmVkUmVwZWF0V3JhcHBpbmcgXTogX2dsLk1JUlJPUkVEX1JFUEVBVFxuXHR9O1xuXG5cdGNvbnN0IGZpbHRlclRvR0wgPSB7XG5cdFx0WyBOZWFyZXN0RmlsdGVyIF06IF9nbC5ORUFSRVNULFxuXHRcdFsgTmVhcmVzdE1pcG1hcE5lYXJlc3RGaWx0ZXIgXTogX2dsLk5FQVJFU1RfTUlQTUFQX05FQVJFU1QsXG5cdFx0WyBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyIF06IF9nbC5ORUFSRVNUX01JUE1BUF9MSU5FQVIsXG5cblx0XHRbIExpbmVhckZpbHRlciBdOiBfZ2wuTElORUFSLFxuXHRcdFsgTGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlciBdOiBfZ2wuTElORUFSX01JUE1BUF9ORUFSRVNULFxuXHRcdFsgTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyIF06IF9nbC5MSU5FQVJfTUlQTUFQX0xJTkVBUlxuXHR9O1xuXG5cdGNvbnN0IGNvbXBhcmVUb0dMID0ge1xuXHRcdFsgTmV2ZXJDb21wYXJlIF06IF9nbC5ORVZFUixcblx0XHRbIEFsd2F5c0NvbXBhcmUgXTogX2dsLkFMV0FZUyxcblx0XHRbIExlc3NDb21wYXJlIF06IF9nbC5MRVNTLFxuXHRcdFsgTGVzc0VxdWFsQ29tcGFyZSBdOiBfZ2wuTEVRVUFMLFxuXHRcdFsgRXF1YWxDb21wYXJlIF06IF9nbC5FUVVBTCxcblx0XHRbIEdyZWF0ZXJFcXVhbENvbXBhcmUgXTogX2dsLkdFUVVBTCxcblx0XHRbIEdyZWF0ZXJDb21wYXJlIF06IF9nbC5HUkVBVEVSLFxuXHRcdFsgTm90RXF1YWxDb21wYXJlIF06IF9nbC5OT1RFUVVBTFxuXHR9O1xuXG5cdGZ1bmN0aW9uIHNldFRleHR1cmVQYXJhbWV0ZXJzKCB0ZXh0dXJlVHlwZSwgdGV4dHVyZSApIHtcblxuXHRcdGlmICggdGV4dHVyZS50eXBlID09PSBGbG9hdFR5cGUgJiYgZXh0ZW5zaW9ucy5oYXMoICdPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXInICkgPT09IGZhbHNlICYmXG5cdFx0XHQoIHRleHR1cmUubWFnRmlsdGVyID09PSBMaW5lYXJGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IExpbmVhck1pcG1hcE5lYXJlc3RGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IExpbmVhck1pcG1hcExpbmVhckZpbHRlciB8fFxuXHRcdFx0dGV4dHVyZS5taW5GaWx0ZXIgPT09IExpbmVhckZpbHRlciB8fCB0ZXh0dXJlLm1pbkZpbHRlciA9PT0gTGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlciB8fCB0ZXh0dXJlLm1pbkZpbHRlciA9PT0gTmVhcmVzdE1pcG1hcExpbmVhckZpbHRlciB8fCB0ZXh0dXJlLm1pbkZpbHRlciA9PT0gTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyICkgKSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFVuYWJsZSB0byB1c2UgbGluZWFyIGZpbHRlcmluZyB3aXRoIGZsb2F0aW5nIHBvaW50IHRleHR1cmVzLiBPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXIgbm90IHN1cHBvcnRlZCBvbiB0aGlzIGRldmljZS4nICk7XG5cblx0XHR9XG5cblx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX1dSQVBfUywgd3JhcHBpbmdUb0dMWyB0ZXh0dXJlLndyYXBTIF0gKTtcblx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX1dSQVBfVCwgd3JhcHBpbmdUb0dMWyB0ZXh0dXJlLndyYXBUIF0gKTtcblxuXHRcdGlmICggdGV4dHVyZVR5cGUgPT09IF9nbC5URVhUVVJFXzNEIHx8IHRleHR1cmVUeXBlID09PSBfZ2wuVEVYVFVSRV8yRF9BUlJBWSApIHtcblxuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9XUkFQX1IsIHdyYXBwaW5nVG9HTFsgdGV4dHVyZS53cmFwUiBdICk7XG5cblx0XHR9XG5cblx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX01BR19GSUxURVIsIGZpbHRlclRvR0xbIHRleHR1cmUubWFnRmlsdGVyIF0gKTtcblx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX01JTl9GSUxURVIsIGZpbHRlclRvR0xbIHRleHR1cmUubWluRmlsdGVyIF0gKTtcblxuXHRcdGlmICggdGV4dHVyZS5jb21wYXJlRnVuY3Rpb24gKSB7XG5cblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfQ09NUEFSRV9NT0RFLCBfZ2wuQ09NUEFSRV9SRUZfVE9fVEVYVFVSRSApO1xuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9DT01QQVJFX0ZVTkMsIGNvbXBhcmVUb0dMWyB0ZXh0dXJlLmNvbXBhcmVGdW5jdGlvbiBdICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIGV4dGVuc2lvbnMuaGFzKCAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJyApID09PSB0cnVlICkge1xuXG5cdFx0XHRpZiAoIHRleHR1cmUubWFnRmlsdGVyID09PSBOZWFyZXN0RmlsdGVyICkgcmV0dXJuO1xuXHRcdFx0aWYgKCB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTmVhcmVzdE1pcG1hcExpbmVhckZpbHRlciAmJiB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyICkgcmV0dXJuO1xuXHRcdFx0aWYgKCB0ZXh0dXJlLnR5cGUgPT09IEZsb2F0VHlwZSAmJiBleHRlbnNpb25zLmhhcyggJ09FU190ZXh0dXJlX2Zsb2F0X2xpbmVhcicgKSA9PT0gZmFsc2UgKSByZXR1cm47IC8vIHZlcmlmeSBleHRlbnNpb25cblxuXHRcdFx0aWYgKCB0ZXh0dXJlLmFuaXNvdHJvcHkgPiAxIHx8IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX19jdXJyZW50QW5pc290cm9weSApIHtcblxuXHRcdFx0XHRjb25zdCBleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ0VYVF90ZXh0dXJlX2ZpbHRlcl9hbmlzb3Ryb3BpYycgKTtcblx0XHRcdFx0X2dsLnRleFBhcmFtZXRlcmYoIHRleHR1cmVUeXBlLCBleHRlbnNpb24uVEVYVFVSRV9NQVhfQU5JU09UUk9QWV9FWFQsIE1hdGgubWluKCB0ZXh0dXJlLmFuaXNvdHJvcHksIGNhcGFiaWxpdGllcy5nZXRNYXhBbmlzb3Ryb3B5KCkgKSApO1xuXHRcdFx0XHRwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApLl9fY3VycmVudEFuaXNvdHJvcHkgPSB0ZXh0dXJlLmFuaXNvdHJvcHk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gaW5pdFRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLCB0ZXh0dXJlICkge1xuXG5cdFx0bGV0IGZvcmNlVXBsb2FkID0gZmFsc2U7XG5cblx0XHRpZiAoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xJbml0ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xJbml0ID0gdHJ1ZTtcblxuXHRcdFx0dGV4dHVyZS5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVGV4dHVyZURpc3Bvc2UgKTtcblxuXHRcdH1cblxuXHRcdC8vIGNyZWF0ZSBTb3VyY2UgPC0+IFdlYkdMVGV4dHVyZXMgbWFwcGluZyBpZiBuZWNlc3NhcnlcblxuXHRcdGNvbnN0IHNvdXJjZSA9IHRleHR1cmUuc291cmNlO1xuXHRcdGxldCB3ZWJnbFRleHR1cmVzID0gX3NvdXJjZXMuZ2V0KCBzb3VyY2UgKTtcblxuXHRcdGlmICggd2ViZ2xUZXh0dXJlcyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR3ZWJnbFRleHR1cmVzID0ge307XG5cdFx0XHRfc291cmNlcy5zZXQoIHNvdXJjZSwgd2ViZ2xUZXh0dXJlcyApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gY2hlY2sgaWYgdGhlcmUgaXMgYWxyZWFkeSBhIFdlYkdMVGV4dHVyZSBvYmplY3QgZm9yIHRoZSBnaXZlbiB0ZXh0dXJlIHBhcmFtZXRlcnNcblxuXHRcdGNvbnN0IHRleHR1cmVDYWNoZUtleSA9IGdldFRleHR1cmVDYWNoZUtleSggdGV4dHVyZSApO1xuXG5cdFx0aWYgKCB0ZXh0dXJlQ2FjaGVLZXkgIT09IHRleHR1cmVQcm9wZXJ0aWVzLl9fY2FjaGVLZXkgKSB7XG5cblx0XHRcdC8vIGlmIG5vdCwgY3JlYXRlIGEgbmV3IGluc3RhbmNlIG9mIFdlYkdMVGV4dHVyZVxuXG5cdFx0XHRpZiAoIHdlYmdsVGV4dHVyZXNbIHRleHR1cmVDYWNoZUtleSBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Ly8gY3JlYXRlIG5ldyBlbnRyeVxuXG5cdFx0XHRcdHdlYmdsVGV4dHVyZXNbIHRleHR1cmVDYWNoZUtleSBdID0ge1xuXHRcdFx0XHRcdHRleHR1cmU6IF9nbC5jcmVhdGVUZXh0dXJlKCksXG5cdFx0XHRcdFx0dXNlZFRpbWVzOiAwXG5cdFx0XHRcdH07XG5cblx0XHRcdFx0aW5mby5tZW1vcnkudGV4dHVyZXMgKys7XG5cblx0XHRcdFx0Ly8gd2hlbiBhIG5ldyBpbnN0YW5jZSBvZiBXZWJHTFRleHR1cmUgd2FzIGNyZWF0ZWQsIGEgdGV4dHVyZSB1cGxvYWQgaXMgcmVxdWlyZWRcblx0XHRcdFx0Ly8gZXZlbiBpZiB0aGUgaW1hZ2UgY29udGVudHMgYXJlIGlkZW50aWNhbFxuXG5cdFx0XHRcdGZvcmNlVXBsb2FkID0gdHJ1ZTtcblxuXHRcdFx0fVxuXG5cdFx0XHR3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlQ2FjaGVLZXkgXS51c2VkVGltZXMgKys7XG5cblx0XHRcdC8vIGV2ZXJ5IHRpbWUgdGhlIHRleHR1cmUgY2FjaGUga2V5IGNoYW5nZXMsIGl0J3MgbmVjZXNzYXJ5IHRvIGNoZWNrIGlmIGFuIGluc3RhbmNlIG9mXG5cdFx0XHQvLyBXZWJHTFRleHR1cmUgY2FuIGJlIGRlbGV0ZWQgaW4gb3JkZXIgdG8gYXZvaWQgYSBtZW1vcnkgbGVhay5cblxuXHRcdFx0Y29uc3Qgd2ViZ2xUZXh0dXJlID0gd2ViZ2xUZXh0dXJlc1sgdGV4dHVyZVByb3BlcnRpZXMuX19jYWNoZUtleSBdO1xuXG5cdFx0XHRpZiAoIHdlYmdsVGV4dHVyZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHdlYmdsVGV4dHVyZXNbIHRleHR1cmVQcm9wZXJ0aWVzLl9fY2FjaGVLZXkgXS51c2VkVGltZXMgLS07XG5cblx0XHRcdFx0aWYgKCB3ZWJnbFRleHR1cmUudXNlZFRpbWVzID09PSAwICkge1xuXG5cdFx0XHRcdFx0ZGVsZXRlVGV4dHVyZSggdGV4dHVyZSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBzdG9yZSByZWZlcmVuY2VzIHRvIGNhY2hlIGtleSBhbmQgV2ViR0xUZXh0dXJlIG9iamVjdFxuXG5cdFx0XHR0ZXh0dXJlUHJvcGVydGllcy5fX2NhY2hlS2V5ID0gdGV4dHVyZUNhY2hlS2V5O1xuXHRcdFx0dGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgPSB3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlQ2FjaGVLZXkgXS50ZXh0dXJlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZvcmNlVXBsb2FkO1xuXG5cdH1cblxuXHRmdW5jdGlvbiB1cGxvYWRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApIHtcblxuXHRcdGxldCB0ZXh0dXJlVHlwZSA9IF9nbC5URVhUVVJFXzJEO1xuXG5cdFx0aWYgKCB0ZXh0dXJlLmlzRGF0YUFycmF5VGV4dHVyZSB8fCB0ZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHRleHR1cmVUeXBlID0gX2dsLlRFWFRVUkVfMkRfQVJSQVk7XG5cdFx0aWYgKCB0ZXh0dXJlLmlzRGF0YTNEVGV4dHVyZSApIHRleHR1cmVUeXBlID0gX2dsLlRFWFRVUkVfM0Q7XG5cblx0XHRjb25zdCBmb3JjZVVwbG9hZCA9IGluaXRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSApO1xuXHRcdGNvbnN0IHNvdXJjZSA9IHRleHR1cmUuc291cmNlO1xuXG5cdFx0c3RhdGUuYmluZFRleHR1cmUoIHRleHR1cmVUeXBlLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgX2dsLlRFWFRVUkUwICsgc2xvdCApO1xuXG5cdFx0Y29uc3Qgc291cmNlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBzb3VyY2UgKTtcblxuXHRcdGlmICggc291cmNlLnZlcnNpb24gIT09IHNvdXJjZVByb3BlcnRpZXMuX192ZXJzaW9uIHx8IGZvcmNlVXBsb2FkID09PSB0cnVlICkge1xuXG5cdFx0XHRzdGF0ZS5hY3RpdmVUZXh0dXJlKCBfZ2wuVEVYVFVSRTAgKyBzbG90ICk7XG5cblx0XHRcdGNvbnN0IHdvcmtpbmdQcmltYXJpZXMgPSBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCBDb2xvck1hbmFnZW1lbnQud29ya2luZ0NvbG9yU3BhY2UgKTtcblx0XHRcdGNvbnN0IHRleHR1cmVQcmltYXJpZXMgPSB0ZXh0dXJlLmNvbG9yU3BhY2UgPT09IE5vQ29sb3JTcGFjZSA/IG51bGwgOiBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCB0ZXh0dXJlLmNvbG9yU3BhY2UgKTtcblx0XHRcdGNvbnN0IHVucGFja0NvbnZlcnNpb24gPSB0ZXh0dXJlLmNvbG9yU3BhY2UgPT09IE5vQ29sb3JTcGFjZSB8fCB3b3JraW5nUHJpbWFyaWVzID09PSB0ZXh0dXJlUHJpbWFyaWVzID8gX2dsLk5PTkUgOiBfZ2wuQlJPV1NFUl9ERUZBVUxUX1dFQkdMO1xuXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfRkxJUF9ZX1dFQkdMLCB0ZXh0dXJlLmZsaXBZICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfUFJFTVVMVElQTFlfQUxQSEFfV0VCR0wsIHRleHR1cmUucHJlbXVsdGlwbHlBbHBoYSApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0FMSUdOTUVOVCwgdGV4dHVyZS51bnBhY2tBbGlnbm1lbnQgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19DT0xPUlNQQUNFX0NPTlZFUlNJT05fV0VCR0wsIHVucGFja0NvbnZlcnNpb24gKTtcblxuXHRcdFx0bGV0IGltYWdlID0gcmVzaXplSW1hZ2UoIHRleHR1cmUuaW1hZ2UsIGZhbHNlLCBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemUgKTtcblx0XHRcdGltYWdlID0gdmVyaWZ5Q29sb3JTcGFjZSggdGV4dHVyZSwgaW1hZ2UgKTtcblxuXHRcdFx0Y29uc3QgZ2xGb3JtYXQgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLmZvcm1hdCwgdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cblx0XHRcdGNvbnN0IGdsVHlwZSA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUudHlwZSApO1xuXHRcdFx0bGV0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlLCB0ZXh0dXJlLmlzVmlkZW9UZXh0dXJlICk7XG5cblx0XHRcdHNldFRleHR1cmVQYXJhbWV0ZXJzKCB0ZXh0dXJlVHlwZSwgdGV4dHVyZSApO1xuXG5cdFx0XHRsZXQgbWlwbWFwO1xuXHRcdFx0Y29uc3QgbWlwbWFwcyA9IHRleHR1cmUubWlwbWFwcztcblxuXHRcdFx0Y29uc3QgdXNlVGV4U3RvcmFnZSA9ICggdGV4dHVyZS5pc1ZpZGVvVGV4dHVyZSAhPT0gdHJ1ZSApO1xuXHRcdFx0Y29uc3QgYWxsb2NhdGVNZW1vcnkgPSAoIHNvdXJjZVByb3BlcnRpZXMuX192ZXJzaW9uID09PSB1bmRlZmluZWQgKSB8fCAoIGZvcmNlVXBsb2FkID09PSB0cnVlICk7XG5cdFx0XHRjb25zdCBkYXRhUmVhZHkgPSBzb3VyY2UuZGF0YVJlYWR5O1xuXHRcdFx0Y29uc3QgbGV2ZWxzID0gZ2V0TWlwTGV2ZWxzKCB0ZXh0dXJlLCBpbWFnZSApO1xuXG5cdFx0XHRpZiAoIHRleHR1cmUuaXNEZXB0aFRleHR1cmUgKSB7XG5cblx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IGdldEludGVybmFsRGVwdGhGb3JtYXQoIHRleHR1cmUuZm9ybWF0ID09PSBEZXB0aFN0ZW5jaWxGb3JtYXQsIHRleHR1cmUudHlwZSApO1xuXG5cdFx0XHRcdC8vXG5cblx0XHRcdFx0aWYgKCBhbGxvY2F0ZU1lbW9yeSApIHtcblxuXHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgMSwgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG51bGwgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSBpZiAoIHRleHR1cmUuaXNEYXRhVGV4dHVyZSApIHtcblxuXHRcdFx0XHQvLyB1c2UgbWFudWFsbHkgY3JlYXRlZCBtaXBtYXBzIGlmIGF2YWlsYWJsZVxuXHRcdFx0XHQvLyBpZiB0aGVyZSBhcmUgbm8gbWFudWFsIG1pcG1hcHNcblx0XHRcdFx0Ly8gc2V0IDAgbGV2ZWwgbWlwbWFwIGFuZCB0aGVuIHVzZSBHTCB0byBnZW5lcmF0ZSBvdGhlciBtaXBtYXAgbGV2ZWxzXG5cblx0XHRcdFx0aWYgKCBtaXBtYXBzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgJiYgYWxsb2NhdGVNZW1vcnkgKSB7XG5cblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwc1sgMCBdLndpZHRoLCBtaXBtYXBzWyAwIF0uaGVpZ2h0ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbWlwbWFwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0bWlwbWFwID0gbWlwbWFwc1sgaSBdO1xuXG5cdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgMCwgMCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR0ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdGlmICggYWxsb2NhdGVNZW1vcnkgKSB7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0ICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIDAsIDAsIDAsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSBpZiAoIHRleHR1cmUuaXNDb21wcmVzc2VkVGV4dHVyZSApIHtcblxuXHRcdFx0XHRpZiAoIHRleHR1cmUuaXNDb21wcmVzc2VkQXJyYXlUZXh0dXJlICkge1xuXG5cdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICYmIGFsbG9jYXRlTWVtb3J5ICkge1xuXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlM0QoIF9nbC5URVhUVVJFXzJEX0FSUkFZLCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcHNbIDAgXS53aWR0aCwgbWlwbWFwc1sgMCBdLmhlaWdodCwgaW1hZ2UuZGVwdGggKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtaXBtYXBzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRtaXBtYXAgPSBtaXBtYXBzWyBpIF07XG5cblx0XHRcdFx0XHRcdGlmICggdGV4dHVyZS5mb3JtYXQgIT09IFJHQkFGb3JtYXQgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBnbEZvcm1hdCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLmxheWVyVXBkYXRlcy5zaXplID4gMCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdGNvbnN0IGxheWVyQnl0ZUxlbmd0aCA9IGdldEJ5dGVMZW5ndGgoIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUudHlwZSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Zm9yICggY29uc3QgbGF5ZXJJbmRleCBvZiB0ZXh0dXJlLmxheWVyVXBkYXRlcyApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Y29uc3QgbGF5ZXJEYXRhID0gbWlwbWFwLmRhdGEuc3ViYXJyYXkoXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdGxheWVySW5kZXggKiBsYXllckJ5dGVMZW5ndGggLyBtaXBtYXAuZGF0YS5CWVRFU19QRVJfRUxFTUVOVCxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KCBsYXllckluZGV4ICsgMSApICogbGF5ZXJCeXRlTGVuZ3RoIC8gbWlwbWFwLmRhdGEuQllURVNfUEVSX0VMRU1FTlRcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS5jb21wcmVzc2VkVGV4U3ViSW1hZ2UzRCggX2dsLlRFWFRVUkVfMkRfQVJSQVksIGksIDAsIDAsIGxheWVySW5kZXgsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMSwgZ2xGb3JtYXQsIGxheWVyRGF0YSwgMCwgMCApO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0dGV4dHVyZS5jbGVhckxheWVyVXBkYXRlcygpO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS5jb21wcmVzc2VkVGV4U3ViSW1hZ2UzRCggX2dsLlRFWFRVUkVfMkRfQVJSQVksIGksIDAsIDAsIDAsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgaW1hZ2UuZGVwdGgsIGdsRm9ybWF0LCBtaXBtYXAuZGF0YSwgMCwgMCApO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUuY29tcHJlc3NlZFRleEltYWdlM0QoIF9nbC5URVhUVVJFXzJEX0FSUkFZLCBpLCBnbEludGVybmFsRm9ybWF0LCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGltYWdlLmRlcHRoLCAwLCBtaXBtYXAuZGF0YSwgMCwgMCApO1xuXG5cdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBBdHRlbXB0IHRvIGxvYWQgdW5zdXBwb3J0ZWQgY29tcHJlc3NlZCB0ZXh0dXJlIGZvcm1hdCBpbiAudXBsb2FkVGV4dHVyZSgpJyApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UzRCggX2dsLlRFWFRVUkVfMkRfQVJSQVksIGksIDAsIDAsIDAsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgaW1hZ2UuZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcC5kYXRhICk7XG5cblx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlM0QoIF9nbC5URVhUVVJFXzJEX0FSUkFZLCBpLCBnbEludGVybmFsRm9ybWF0LCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGltYWdlLmRlcHRoLCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgJiYgYWxsb2NhdGVNZW1vcnkgKSB7XG5cblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwc1sgMCBdLndpZHRoLCBtaXBtYXBzWyAwIF0uaGVpZ2h0ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbWlwbWFwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0bWlwbWFwID0gbWlwbWFwc1sgaSBdO1xuXG5cdFx0XHRcdFx0XHRpZiAoIHRleHR1cmUuZm9ybWF0ICE9PSBSR0JBRm9ybWF0ICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggZ2xGb3JtYXQgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLmNvbXByZXNzZWRUZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgMCwgMCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBnbEZvcm1hdCwgbWlwbWFwLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUuY29tcHJlc3NlZFRleEltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBpLCBnbEludGVybmFsRm9ybWF0LCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIDAsIG1pcG1hcC5kYXRhICk7XG5cblx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IEF0dGVtcHQgdG8gbG9hZCB1bnN1cHBvcnRlZCBjb21wcmVzc2VkIHRleHR1cmUgZm9ybWF0IGluIC51cGxvYWRUZXh0dXJlKCknICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgMCwgMCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0RhdGFBcnJheVRleHR1cmUgKSB7XG5cblx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xuXG5cdFx0XHRcdFx0aWYgKCBhbGxvY2F0ZU1lbW9yeSApIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCBpbWFnZS5kZXB0aCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdGlmICggdGV4dHVyZS5sYXllclVwZGF0ZXMuc2l6ZSA+IDAgKSB7XG5cblx0XHRcdFx0XHRcdFx0Y29uc3QgbGF5ZXJCeXRlTGVuZ3RoID0gZ2V0Qnl0ZUxlbmd0aCggaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUudHlwZSApO1xuXG5cdFx0XHRcdFx0XHRcdGZvciAoIGNvbnN0IGxheWVySW5kZXggb2YgdGV4dHVyZS5sYXllclVwZGF0ZXMgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRjb25zdCBsYXllckRhdGEgPSBpbWFnZS5kYXRhLnN1YmFycmF5KFxuXHRcdFx0XHRcdFx0XHRcdFx0bGF5ZXJJbmRleCAqIGxheWVyQnl0ZUxlbmd0aCAvIGltYWdlLmRhdGEuQllURVNfUEVSX0VMRU1FTlQsXG5cdFx0XHRcdFx0XHRcdFx0XHQoIGxheWVySW5kZXggKyAxICkgKiBsYXllckJ5dGVMZW5ndGggLyBpbWFnZS5kYXRhLkJZVEVTX1BFUl9FTEVNRU5UXG5cdFx0XHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgMCwgMCwgMCwgbGF5ZXJJbmRleCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgMSwgZ2xGb3JtYXQsIGdsVHlwZSwgbGF5ZXJEYXRhICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdHRleHR1cmUuY2xlYXJMYXllclVwZGF0ZXMoKTtcblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgMCwgMCwgMCwgMCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGgsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSBpZiAoIHRleHR1cmUuaXNEYXRhM0RUZXh0dXJlICkge1xuXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdGlmICggYWxsb2NhdGVNZW1vcnkgKSB7XG5cblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UzRCggX2dsLlRFWFRVUkVfM0QsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGggKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xuXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTNEKCBfZ2wuVEVYVFVSRV8zRCwgMCwgMCwgMCwgMCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UzRCggX2dsLlRFWFRVUkVfM0QsIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQsIGltYWdlLmRlcHRoLCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBpbWFnZS5kYXRhICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLmlzRnJhbWVidWZmZXJUZXh0dXJlICkge1xuXG5cdFx0XHRcdGlmICggYWxsb2NhdGVNZW1vcnkgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0bGV0IHdpZHRoID0gaW1hZ2Uud2lkdGgsIGhlaWdodCA9IGltYWdlLmhlaWdodDtcblxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbGV2ZWxzOyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBpLCBnbEludGVybmFsRm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBudWxsICk7XG5cblx0XHRcdFx0XHRcdFx0d2lkdGggPj49IDE7XG5cdFx0XHRcdFx0XHRcdGhlaWdodCA+Pj0gMTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyByZWd1bGFyIFRleHR1cmUgKGltYWdlLCB2aWRlbywgY2FudmFzKVxuXG5cdFx0XHRcdC8vIHVzZSBtYW51YWxseSBjcmVhdGVkIG1pcG1hcHMgaWYgYXZhaWxhYmxlXG5cdFx0XHRcdC8vIGlmIHRoZXJlIGFyZSBubyBtYW51YWwgbWlwbWFwc1xuXHRcdFx0XHQvLyBzZXQgMCBsZXZlbCBtaXBtYXAgYW5kIHRoZW4gdXNlIEdMIHRvIGdlbmVyYXRlIG90aGVyIG1pcG1hcCBsZXZlbHNcblxuXHRcdFx0XHRpZiAoIG1pcG1hcHMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgZGltZW5zaW9ucyA9IGdldERpbWVuc2lvbnMoIG1pcG1hcHNbIDAgXSApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIGRpbWVuc2lvbnMud2lkdGgsIGRpbWVuc2lvbnMuaGVpZ2h0ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbWlwbWFwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0bWlwbWFwID0gbWlwbWFwc1sgaSBdO1xuXG5cdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBpLCBnbEludGVybmFsRm9ybWF0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0dGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xuXG5cdFx0XHRcdFx0XHRpZiAoIGFsbG9jYXRlTWVtb3J5ICkge1xuXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGRpbWVuc2lvbnMgPSBnZXREaW1lbnNpb25zKCBpbWFnZSApO1xuXG5cdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgZGltZW5zaW9ucy53aWR0aCwgZGltZW5zaW9ucy5oZWlnaHQgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcblxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgMCwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlICkgKSB7XG5cblx0XHRcdFx0Z2VuZXJhdGVNaXBtYXAoIHRleHR1cmVUeXBlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0c291cmNlUHJvcGVydGllcy5fX3ZlcnNpb24gPSBzb3VyY2UudmVyc2lvbjtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlLm9uVXBkYXRlICkgdGV4dHVyZS5vblVwZGF0ZSggdGV4dHVyZSApO1xuXG5cdFx0fVxuXG5cdFx0dGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uID0gdGV4dHVyZS52ZXJzaW9uO1xuXG5cdH1cblxuXHRmdW5jdGlvbiB1cGxvYWRDdWJlVGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMsIHRleHR1cmUsIHNsb3QgKSB7XG5cblx0XHRpZiAoIHRleHR1cmUuaW1hZ2UubGVuZ3RoICE9PSA2ICkgcmV0dXJuO1xuXG5cdFx0Y29uc3QgZm9yY2VVcGxvYWQgPSBpbml0VGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMsIHRleHR1cmUgKTtcblx0XHRjb25zdCBzb3VyY2UgPSB0ZXh0dXJlLnNvdXJjZTtcblxuXHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBfZ2wuVEVYVFVSRV9DVUJFX01BUCwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIF9nbC5URVhUVVJFMCArIHNsb3QgKTtcblxuXHRcdGNvbnN0IHNvdXJjZVByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggc291cmNlICk7XG5cblx0XHRpZiAoIHNvdXJjZS52ZXJzaW9uICE9PSBzb3VyY2VQcm9wZXJ0aWVzLl9fdmVyc2lvbiB8fCBmb3JjZVVwbG9hZCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0c3RhdGUuYWN0aXZlVGV4dHVyZSggX2dsLlRFWFRVUkUwICsgc2xvdCApO1xuXG5cdFx0XHRjb25zdCB3b3JraW5nUHJpbWFyaWVzID0gQ29sb3JNYW5hZ2VtZW50LmdldFByaW1hcmllcyggQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlICk7XG5cdFx0XHRjb25zdCB0ZXh0dXJlUHJpbWFyaWVzID0gdGV4dHVyZS5jb2xvclNwYWNlID09PSBOb0NvbG9yU3BhY2UgPyBudWxsIDogQ29sb3JNYW5hZ2VtZW50LmdldFByaW1hcmllcyggdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cdFx0XHRjb25zdCB1bnBhY2tDb252ZXJzaW9uID0gdGV4dHVyZS5jb2xvclNwYWNlID09PSBOb0NvbG9yU3BhY2UgfHwgd29ya2luZ1ByaW1hcmllcyA9PT0gdGV4dHVyZVByaW1hcmllcyA/IF9nbC5OT05FIDogX2dsLkJST1dTRVJfREVGQVVMVF9XRUJHTDtcblxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0ZMSVBfWV9XRUJHTCwgdGV4dHVyZS5mbGlwWSApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1BSRU1VTFRJUExZX0FMUEhBX1dFQkdMLCB0ZXh0dXJlLnByZW11bHRpcGx5QWxwaGEgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19BTElHTk1FTlQsIHRleHR1cmUudW5wYWNrQWxpZ25tZW50ICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfQ09MT1JTUEFDRV9DT05WRVJTSU9OX1dFQkdMLCB1bnBhY2tDb252ZXJzaW9uICk7XG5cblx0XHRcdGNvbnN0IGlzQ29tcHJlc3NlZCA9ICggdGV4dHVyZS5pc0NvbXByZXNzZWRUZXh0dXJlIHx8IHRleHR1cmUuaW1hZ2VbIDAgXS5pc0NvbXByZXNzZWRUZXh0dXJlICk7XG5cdFx0XHRjb25zdCBpc0RhdGFUZXh0dXJlID0gKCB0ZXh0dXJlLmltYWdlWyAwIF0gJiYgdGV4dHVyZS5pbWFnZVsgMCBdLmlzRGF0YVRleHR1cmUgKTtcblxuXHRcdFx0Y29uc3QgY3ViZUltYWdlID0gW107XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdFx0aWYgKCAhIGlzQ29tcHJlc3NlZCAmJiAhIGlzRGF0YVRleHR1cmUgKSB7XG5cblx0XHRcdFx0XHRjdWJlSW1hZ2VbIGkgXSA9IHJlc2l6ZUltYWdlKCB0ZXh0dXJlLmltYWdlWyBpIF0sIHRydWUsIGNhcGFiaWxpdGllcy5tYXhDdWJlbWFwU2l6ZSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRjdWJlSW1hZ2VbIGkgXSA9IGlzRGF0YVRleHR1cmUgPyB0ZXh0dXJlLmltYWdlWyBpIF0uaW1hZ2UgOiB0ZXh0dXJlLmltYWdlWyBpIF07XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGN1YmVJbWFnZVsgaSBdID0gdmVyaWZ5Q29sb3JTcGFjZSggdGV4dHVyZSwgY3ViZUltYWdlWyBpIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBpbWFnZSA9IGN1YmVJbWFnZVsgMCBdLFxuXHRcdFx0XHRnbEZvcm1hdCA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUuZm9ybWF0LCB0ZXh0dXJlLmNvbG9yU3BhY2UgKSxcblx0XHRcdFx0Z2xUeXBlID0gdXRpbHMuY29udmVydCggdGV4dHVyZS50eXBlICksXG5cdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cblx0XHRcdGNvbnN0IHVzZVRleFN0b3JhZ2UgPSAoIHRleHR1cmUuaXNWaWRlb1RleHR1cmUgIT09IHRydWUgKTtcblx0XHRcdGNvbnN0IGFsbG9jYXRlTWVtb3J5ID0gKCBzb3VyY2VQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9PT0gdW5kZWZpbmVkICkgfHwgKCBmb3JjZVVwbG9hZCA9PT0gdHJ1ZSApO1xuXHRcdFx0Y29uc3QgZGF0YVJlYWR5ID0gc291cmNlLmRhdGFSZWFkeTtcblx0XHRcdGxldCBsZXZlbHMgPSBnZXRNaXBMZXZlbHMoIHRleHR1cmUsIGltYWdlICk7XG5cblx0XHRcdHNldFRleHR1cmVQYXJhbWV0ZXJzKCBfZ2wuVEVYVFVSRV9DVUJFX01BUCwgdGV4dHVyZSApO1xuXG5cdFx0XHRsZXQgbWlwbWFwcztcblxuXHRcdFx0aWYgKCBpc0NvbXByZXNzZWQgKSB7XG5cblx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICYmIGFsbG9jYXRlTWVtb3J5ICkge1xuXG5cdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUCwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRtaXBtYXBzID0gY3ViZUltYWdlWyBpIF0ubWlwbWFwcztcblxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IG1pcG1hcHMubGVuZ3RoOyBqICsrICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBtaXBtYXAgPSBtaXBtYXBzWyBqIF07XG5cblx0XHRcdFx0XHRcdGlmICggdGV4dHVyZS5mb3JtYXQgIT09IFJHQkFGb3JtYXQgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBnbEZvcm1hdCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUuY29tcHJlc3NlZFRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqLCAwLCAwLCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGdsRm9ybWF0LCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS5jb21wcmVzc2VkVGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIGosIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMCwgbWlwbWFwLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQXR0ZW1wdCB0byBsb2FkIHVuc3VwcG9ydGVkIGNvbXByZXNzZWQgdGV4dHVyZSBmb3JtYXQgaW4gLnNldFRleHR1cmVDdWJlKCknICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgaiwgMCwgMCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgaiwgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRtaXBtYXBzID0gdGV4dHVyZS5taXBtYXBzO1xuXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcblxuXHRcdFx0XHRcdC8vIFRPRE86IFVuaWZvcm1seSBoYW5kbGUgbWlwbWFwIGRlZmluaXRpb25zXG5cdFx0XHRcdFx0Ly8gTm9ybWFsIHRleHR1cmVzIGFuZCBjb21wcmVzc2VkIGN1YmUgdGV4dHVyZXMgZGVmaW5lIGJhc2UgbGV2ZWwgKyBtaXBzIHdpdGggdGhlaXIgbWlwbWFwIGFycmF5XG5cdFx0XHRcdFx0Ly8gVW5jb21wcmVzc2VkIGN1YmUgdGV4dHVyZXMgdXNlIHRoZWlyIG1pcG1hcCBhcnJheSBvbmx5IGZvciBtaXBzIChubyBiYXNlIGxldmVsKVxuXG5cdFx0XHRcdFx0aWYgKCBtaXBtYXBzLmxlbmd0aCA+IDAgKSBsZXZlbHMgKys7XG5cblx0XHRcdFx0XHRjb25zdCBkaW1lbnNpb25zID0gZ2V0RGltZW5zaW9ucyggY3ViZUltYWdlWyAwIF0gKTtcblxuXHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVAsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgZGltZW5zaW9ucy53aWR0aCwgZGltZW5zaW9ucy5oZWlnaHQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcblxuXHRcdFx0XHRcdGlmICggaXNEYXRhVGV4dHVyZSApIHtcblxuXHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIDAsIDAsIDAsIGN1YmVJbWFnZVsgaSBdLndpZHRoLCBjdWJlSW1hZ2VbIGkgXS5oZWlnaHQsIGdsRm9ybWF0LCBnbFR5cGUsIGN1YmVJbWFnZVsgaSBdLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGN1YmVJbWFnZVsgaSBdLndpZHRoLCBjdWJlSW1hZ2VbIGkgXS5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIGN1YmVJbWFnZVsgaSBdLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBtaXBtYXBzLmxlbmd0aDsgaiArKyApIHtcblxuXHRcdFx0XHRcdFx0XHRjb25zdCBtaXBtYXAgPSBtaXBtYXBzWyBqIF07XG5cdFx0XHRcdFx0XHRcdGNvbnN0IG1pcG1hcEltYWdlID0gbWlwbWFwLmltYWdlWyBpIF0uaW1hZ2U7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqICsgMSwgMCwgMCwgbWlwbWFwSW1hZ2Uud2lkdGgsIG1pcG1hcEltYWdlLmhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwSW1hZ2UuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgaiArIDEsIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcEltYWdlLndpZHRoLCBtaXBtYXBJbWFnZS5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcEltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCAwLCAwLCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBjdWJlSW1hZ2VbIGkgXSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgY3ViZUltYWdlWyBpIF0gKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBtaXBtYXBzLmxlbmd0aDsgaiArKyApIHtcblxuXHRcdFx0XHRcdFx0XHRjb25zdCBtaXBtYXAgPSBtaXBtYXBzWyBqIF07XG5cblx0XHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqICsgMSwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmltYWdlWyBpIF0gKTtcblxuXHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIGogKyAxLCBnbEludGVybmFsRm9ybWF0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuaW1hZ2VbIGkgXSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRleHR1cmVOZWVkc0dlbmVyYXRlTWlwbWFwcyggdGV4dHVyZSApICkge1xuXG5cdFx0XHRcdC8vIFdlIGFzc3VtZSBpbWFnZXMgZm9yIGN1YmUgbWFwIGhhdmUgdGhlIHNhbWUgc2l6ZS5cblx0XHRcdFx0Z2VuZXJhdGVNaXBtYXAoIF9nbC5URVhUVVJFX0NVQkVfTUFQICk7XG5cblx0XHRcdH1cblxuXHRcdFx0c291cmNlUHJvcGVydGllcy5fX3ZlcnNpb24gPSBzb3VyY2UudmVyc2lvbjtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlLm9uVXBkYXRlICkgdGV4dHVyZS5vblVwZGF0ZSggdGV4dHVyZSApO1xuXG5cdFx0fVxuXG5cdFx0dGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uID0gdGV4dHVyZS52ZXJzaW9uO1xuXG5cdH1cblxuXHQvLyBSZW5kZXIgdGFyZ2V0c1xuXG5cdC8vIFNldHVwIHN0b3JhZ2UgZm9yIHRhcmdldCB0ZXh0dXJlIGFuZCBiaW5kIGl0IHRvIGNvcnJlY3QgZnJhbWVidWZmZXJcblx0ZnVuY3Rpb24gc2V0dXBGcmFtZUJ1ZmZlclRleHR1cmUoIGZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQsIHRleHR1cmUsIGF0dGFjaG1lbnQsIHRleHR1cmVUYXJnZXQsIGxldmVsICkge1xuXG5cdFx0Y29uc3QgZ2xGb3JtYXQgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLmZvcm1hdCwgdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cdFx0Y29uc3QgZ2xUeXBlID0gdXRpbHMuY29udmVydCggdGV4dHVyZS50eXBlICk7XG5cdFx0Y29uc3QgZ2xJbnRlcm5hbEZvcm1hdCA9IGdldEludGVybmFsRm9ybWF0KCB0ZXh0dXJlLmludGVybmFsRm9ybWF0LCBnbEZvcm1hdCwgZ2xUeXBlLCB0ZXh0dXJlLmNvbG9yU3BhY2UgKTtcblx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xuXG5cdFx0aWYgKCAhIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX19oYXNFeHRlcm5hbFRleHR1cmVzICkge1xuXG5cdFx0XHRjb25zdCB3aWR0aCA9IE1hdGgubWF4KCAxLCByZW5kZXJUYXJnZXQud2lkdGggPj4gbGV2ZWwgKTtcblx0XHRcdGNvbnN0IGhlaWdodCA9IE1hdGgubWF4KCAxLCByZW5kZXJUYXJnZXQuaGVpZ2h0ID4+IGxldmVsICk7XG5cblx0XHRcdGlmICggdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfM0QgfHwgdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfMkRfQVJSQVkgKSB7XG5cblx0XHRcdFx0c3RhdGUudGV4SW1hZ2UzRCggdGV4dHVyZVRhcmdldCwgbGV2ZWwsIGdsSW50ZXJuYWxGb3JtYXQsIHdpZHRoLCBoZWlnaHQsIHJlbmRlclRhcmdldC5kZXB0aCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbnVsbCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIHRleHR1cmVUYXJnZXQsIGxldmVsLCBnbEludGVybmFsRm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBudWxsICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xuXG5cdFx0aWYgKCB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApICkge1xuXG5cdFx0XHRtdWx0aXNhbXBsZWRSVFRFeHQuZnJhbWVidWZmZXJUZXh0dXJlMkRNdWx0aXNhbXBsZUVYVCggX2dsLkZSQU1FQlVGRkVSLCBhdHRhY2htZW50LCB0ZXh0dXJlVGFyZ2V0LCBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlLCAwLCBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKSApO1xuXG5cdFx0fSBlbHNlIGlmICggdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfMkQgfHwgKCB0ZXh0dXJlVGFyZ2V0ID49IF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggJiYgdGV4dHVyZVRhcmdldCA8PSBfZ2wuVEVYVFVSRV9DVUJFX01BUF9ORUdBVElWRV9aICkgKSB7IC8vIHNlZSAjMjQ3NTNcblxuXHRcdFx0X2dsLmZyYW1lYnVmZmVyVGV4dHVyZTJEKCBfZ2wuRlJBTUVCVUZGRVIsIGF0dGFjaG1lbnQsIHRleHR1cmVUYXJnZXQsIHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX193ZWJnbFRleHR1cmUsIGxldmVsICk7XG5cblx0XHR9XG5cblx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgbnVsbCApO1xuXG5cdH1cblxuXHQvLyBTZXR1cCBzdG9yYWdlIGZvciBpbnRlcm5hbCBkZXB0aC9zdGVuY2lsIGJ1ZmZlcnMgYW5kIGJpbmQgdG8gY29ycmVjdCBmcmFtZWJ1ZmZlclxuXHRmdW5jdGlvbiBzZXR1cFJlbmRlckJ1ZmZlclN0b3JhZ2UoIHJlbmRlcmJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCBpc011bHRpc2FtcGxlICkge1xuXG5cdFx0X2dsLmJpbmRSZW5kZXJidWZmZXIoIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlcmJ1ZmZlciApO1xuXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgKSB7XG5cblx0XHRcdC8vIHJldHJpZXZlIHRoZSBkZXB0aCBhdHRhY2htZW50IHR5cGVzXG5cdFx0XHRjb25zdCBkZXB0aFRleHR1cmUgPSByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlO1xuXHRcdFx0Y29uc3QgZGVwdGhUeXBlID0gZGVwdGhUZXh0dXJlICYmIGRlcHRoVGV4dHVyZS5pc0RlcHRoVGV4dHVyZSA/IGRlcHRoVGV4dHVyZS50eXBlIDogbnVsbDtcblx0XHRcdGNvbnN0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbERlcHRoRm9ybWF0KCByZW5kZXJUYXJnZXQuc3RlbmNpbEJ1ZmZlciwgZGVwdGhUeXBlICk7XG5cdFx0XHRjb25zdCBnbEF0dGFjaG1lbnRUeXBlID0gcmVuZGVyVGFyZ2V0LnN0ZW5jaWxCdWZmZXIgPyBfZ2wuREVQVEhfU1RFTkNJTF9BVFRBQ0hNRU5UIDogX2dsLkRFUFRIX0FUVEFDSE1FTlQ7XG5cblx0XHRcdC8vIHNldCB1cCB0aGUgYXR0YWNobWVudFxuXHRcdFx0Y29uc3Qgc2FtcGxlcyA9IGdldFJlbmRlclRhcmdldFNhbXBsZXMoIHJlbmRlclRhcmdldCApO1xuXHRcdFx0Y29uc3QgaXNVc2VNdWx0aXNhbXBsZWRSVFQgPSB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApO1xuXHRcdFx0aWYgKCBpc1VzZU11bHRpc2FtcGxlZFJUVCApIHtcblxuXHRcdFx0XHRtdWx0aXNhbXBsZWRSVFRFeHQucmVuZGVyYnVmZmVyU3RvcmFnZU11bHRpc2FtcGxlRVhUKCBfZ2wuUkVOREVSQlVGRkVSLCBzYW1wbGVzLCBnbEludGVybmFsRm9ybWF0LCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggaXNNdWx0aXNhbXBsZSApIHtcblxuXHRcdFx0XHRfZ2wucmVuZGVyYnVmZmVyU3RvcmFnZU11bHRpc2FtcGxlKCBfZ2wuUkVOREVSQlVGRkVSLCBzYW1wbGVzLCBnbEludGVybmFsRm9ybWF0LCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRfZ2wucmVuZGVyYnVmZmVyU3RvcmFnZSggX2dsLlJFTkRFUkJVRkZFUiwgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0X2dsLmZyYW1lYnVmZmVyUmVuZGVyYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIGdsQXR0YWNobWVudFR5cGUsIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlcmJ1ZmZlciApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc3QgdGV4dHVyZXMgPSByZW5kZXJUYXJnZXQudGV4dHVyZXM7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRleHR1cmVzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCB0ZXh0dXJlID0gdGV4dHVyZXNbIGkgXTtcblxuXHRcdFx0XHRjb25zdCBnbEZvcm1hdCA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUuZm9ybWF0LCB0ZXh0dXJlLmNvbG9yU3BhY2UgKTtcblx0XHRcdFx0Y29uc3QgZ2xUeXBlID0gdXRpbHMuY29udmVydCggdGV4dHVyZS50eXBlICk7XG5cdFx0XHRcdGNvbnN0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cdFx0XHRcdGNvbnN0IHNhbXBsZXMgPSBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHRpZiAoIGlzTXVsdGlzYW1wbGUgJiYgdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0XHRfZ2wucmVuZGVyYnVmZmVyU3RvcmFnZU11bHRpc2FtcGxlKCBfZ2wuUkVOREVSQlVGRkVSLCBzYW1wbGVzLCBnbEludGVybmFsRm9ybWF0LCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApICkge1xuXG5cdFx0XHRcdFx0bXVsdGlzYW1wbGVkUlRURXh0LnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZUVYVCggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdF9nbC5yZW5kZXJidWZmZXJTdG9yYWdlKCBfZ2wuUkVOREVSQlVGRkVSLCBnbEludGVybmFsRm9ybWF0LCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdF9nbC5iaW5kUmVuZGVyYnVmZmVyKCBfZ2wuUkVOREVSQlVGRkVSLCBudWxsICk7XG5cblx0fVxuXG5cdC8vIFNldHVwIHJlc291cmNlcyBmb3IgYSBEZXB0aCBUZXh0dXJlIGZvciBhIEZCTyAobmVlZHMgYW4gZXh0ZW5zaW9uKVxuXHRmdW5jdGlvbiBzZXR1cERlcHRoVGV4dHVyZSggZnJhbWVidWZmZXIsIHJlbmRlclRhcmdldCApIHtcblxuXHRcdGNvbnN0IGlzQ3ViZSA9ICggcmVuZGVyVGFyZ2V0ICYmIHJlbmRlclRhcmdldC5pc1dlYkdMQ3ViZVJlbmRlclRhcmdldCApO1xuXHRcdGlmICggaXNDdWJlICkgdGhyb3cgbmV3IEVycm9yKCAnRGVwdGggVGV4dHVyZSB3aXRoIGN1YmUgcmVuZGVyIHRhcmdldHMgaXMgbm90IHN1cHBvcnRlZCcgKTtcblxuXHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xuXG5cdFx0aWYgKCAhICggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSAmJiByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmlzRGVwdGhUZXh0dXJlICkgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ3JlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgbXVzdCBiZSBhbiBpbnN0YW5jZSBvZiBUSFJFRS5EZXB0aFRleHR1cmUnICk7XG5cblx0XHR9XG5cblx0XHQvLyB1cGxvYWQgYW4gZW1wdHkgZGVwdGggdGV4dHVyZSB3aXRoIGZyYW1lYnVmZmVyIHNpemVcblx0XHRpZiAoICEgcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgKS5fX3dlYmdsVGV4dHVyZSB8fFxuXHRcdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmltYWdlLndpZHRoICE9PSByZW5kZXJUYXJnZXQud2lkdGggfHxcblx0XHRcdFx0cmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZS5pbWFnZS5oZWlnaHQgIT09IHJlbmRlclRhcmdldC5oZWlnaHQgKSB7XG5cblx0XHRcdHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUuaW1hZ2Uud2lkdGggPSByZW5kZXJUYXJnZXQud2lkdGg7XG5cdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmltYWdlLmhlaWdodCA9IHJlbmRlclRhcmdldC5oZWlnaHQ7XG5cdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdHNldFRleHR1cmUyRCggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSwgMCApO1xuXG5cdFx0Y29uc3Qgd2ViZ2xEZXB0aFRleHR1cmUgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlO1xuXHRcdGNvbnN0IHNhbXBsZXMgPSBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKTtcblxuXHRcdGlmICggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZS5mb3JtYXQgPT09IERlcHRoRm9ybWF0ICkge1xuXG5cdFx0XHRpZiAoIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgKSB7XG5cblx0XHRcdFx0bXVsdGlzYW1wbGVkUlRURXh0LmZyYW1lYnVmZmVyVGV4dHVyZTJETXVsdGlzYW1wbGVFWFQoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX0FUVEFDSE1FTlQsIF9nbC5URVhUVVJFXzJELCB3ZWJnbERlcHRoVGV4dHVyZSwgMCwgc2FtcGxlcyApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkZSQU1FQlVGRkVSLCBfZ2wuREVQVEhfQVRUQUNITUVOVCwgX2dsLlRFWFRVUkVfMkQsIHdlYmdsRGVwdGhUZXh0dXJlLCAwICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSBpZiAoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUuZm9ybWF0ID09PSBEZXB0aFN0ZW5jaWxGb3JtYXQgKSB7XG5cblx0XHRcdGlmICggdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSApIHtcblxuXHRcdFx0XHRtdWx0aXNhbXBsZWRSVFRFeHQuZnJhbWVidWZmZXJUZXh0dXJlMkRNdWx0aXNhbXBsZUVYVCggX2dsLkZSQU1FQlVGRkVSLCBfZ2wuREVQVEhfU1RFTkNJTF9BVFRBQ0hNRU5ULCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xEZXB0aFRleHR1cmUsIDAsIHNhbXBsZXMgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlMkQoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCwgX2dsLlRFWFRVUkVfMkQsIHdlYmdsRGVwdGhUZXh0dXJlLCAwICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1Vua25vd24gZGVwdGhUZXh0dXJlIGZvcm1hdCcgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Ly8gU2V0dXAgR0wgcmVzb3VyY2VzIGZvciBhIG5vbi10ZXh0dXJlIGRlcHRoIGJ1ZmZlclxuXHRmdW5jdGlvbiBzZXR1cERlcHRoUmVuZGVyYnVmZmVyKCByZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xuXHRcdGNvbnN0IGlzQ3ViZSA9ICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xDdWJlUmVuZGVyVGFyZ2V0ID09PSB0cnVlICk7XG5cblx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgJiYgISByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fYXV0b0FsbG9jYXRlRGVwdGhCdWZmZXIgKSB7XG5cblx0XHRcdGlmICggaXNDdWJlICkgdGhyb3cgbmV3IEVycm9yKCAndGFyZ2V0LmRlcHRoVGV4dHVyZSBub3Qgc3VwcG9ydGVkIGluIEN1YmUgcmVuZGVyIHRhcmdldHMnICk7XG5cblx0XHRcdHNldHVwRGVwdGhUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciwgcmVuZGVyVGFyZ2V0ICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIGlzQ3ViZSApIHtcblxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciA9IFtdO1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXSApO1xuXHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyWyBpIF0gPSBfZ2wuY3JlYXRlUmVuZGVyYnVmZmVyKCk7XG5cdFx0XHRcdFx0c2V0dXBSZW5kZXJCdWZmZXJTdG9yYWdlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlclsgaSBdLCByZW5kZXJUYXJnZXQsIGZhbHNlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciApO1xuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciA9IF9nbC5jcmVhdGVSZW5kZXJidWZmZXIoKTtcblx0XHRcdFx0c2V0dXBSZW5kZXJCdWZmZXJTdG9yYWdlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCBmYWxzZSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgbnVsbCApO1xuXG5cdH1cblxuXHQvLyByZWJpbmQgZnJhbWVidWZmZXIgd2l0aCBleHRlcm5hbCB0ZXh0dXJlc1xuXHRmdW5jdGlvbiByZWJpbmRUZXh0dXJlcyggcmVuZGVyVGFyZ2V0LCBjb2xvclRleHR1cmUsIGRlcHRoVGV4dHVyZSApIHtcblxuXHRcdGNvbnN0IHJlbmRlclRhcmdldFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRpZiAoIGNvbG9yVGV4dHVyZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRzZXR1cEZyYW1lQnVmZmVyVGV4dHVyZSggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIsIHJlbmRlclRhcmdldCwgcmVuZGVyVGFyZ2V0LnRleHR1cmUsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCwgX2dsLlRFWFRVUkVfMkQsIDAgKTtcblxuXHRcdH1cblxuXHRcdGlmICggZGVwdGhUZXh0dXJlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHNldHVwRGVwdGhSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHQvLyBTZXQgdXAgR0wgcmVzb3VyY2VzIGZvciB0aGUgcmVuZGVyIHRhcmdldFxuXHRmdW5jdGlvbiBzZXR1cFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0ICkge1xuXG5cdFx0Y29uc3QgdGV4dHVyZSA9IHJlbmRlclRhcmdldC50ZXh0dXJlO1xuXG5cdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcblx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICk7XG5cblx0XHRyZW5kZXJUYXJnZXQuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblJlbmRlclRhcmdldERpc3Bvc2UgKTtcblxuXHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmVzO1xuXG5cdFx0Y29uc3QgaXNDdWJlID0gKCByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgPT09IHRydWUgKTtcblx0XHRjb25zdCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyA9ICggdGV4dHVyZXMubGVuZ3RoID4gMSApO1xuXG5cdFx0aWYgKCAhIGlzTXVsdGlwbGVSZW5kZXJUYXJnZXRzICkge1xuXG5cdFx0XHRpZiAoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgPSBfZ2wuY3JlYXRlVGV4dHVyZSgpO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9IHRleHR1cmUudmVyc2lvbjtcblx0XHRcdGluZm8ubWVtb3J5LnRleHR1cmVzICsrO1xuXG5cdFx0fVxuXG5cdFx0Ly8gU2V0dXAgZnJhbWVidWZmZXJcblxuXHRcdGlmICggaXNDdWJlICkge1xuXG5cdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9IFtdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xuXG5cdFx0XHRcdGlmICggdGV4dHVyZS5taXBtYXBzICYmIHRleHR1cmUubWlwbWFwcy5sZW5ndGggPiAwICkge1xuXG5cdFx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXSA9IFtdO1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGxldmVsID0gMDsgbGV2ZWwgPCB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoOyBsZXZlbCArKyApIHtcblxuXHRcdFx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXVsgbGV2ZWwgXSA9IF9nbC5jcmVhdGVGcmFtZWJ1ZmZlcigpO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgaSBdID0gX2dsLmNyZWF0ZUZyYW1lYnVmZmVyKCk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIHRleHR1cmUubWlwbWFwcyAmJiB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9IFtdO1xuXG5cdFx0XHRcdGZvciAoIGxldCBsZXZlbCA9IDA7IGxldmVsIDwgdGV4dHVyZS5taXBtYXBzLmxlbmd0aDsgbGV2ZWwgKysgKSB7XG5cblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgbGV2ZWwgXSA9IF9nbC5jcmVhdGVGcmFtZWJ1ZmZlcigpO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9IF9nbC5jcmVhdGVGcmFtZWJ1ZmZlcigpO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggaXNNdWx0aXBsZVJlbmRlclRhcmdldHMgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRleHR1cmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgYXR0YWNobWVudFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZXNbIGkgXSApO1xuXG5cdFx0XHRcdFx0aWYgKCBhdHRhY2htZW50UHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRhdHRhY2htZW50UHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSA9IF9nbC5jcmVhdGVUZXh0dXJlKCk7XG5cblx0XHRcdFx0XHRcdGluZm8ubWVtb3J5LnRleHR1cmVzICsrO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICggcmVuZGVyVGFyZ2V0LnNhbXBsZXMgPiAwICkgJiYgdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsTXVsdGlzYW1wbGVkRnJhbWVidWZmZXIgPSBfZ2wuY3JlYXRlRnJhbWVidWZmZXIoKTtcblx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsQ29sb3JSZW5kZXJidWZmZXIgPSBbXTtcblxuXHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsTXVsdGlzYW1wbGVkRnJhbWVidWZmZXIgKTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0ZXh0dXJlcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB0ZXh0dXJlID0gdGV4dHVyZXNbIGkgXTtcblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlclsgaSBdID0gX2dsLmNyZWF0ZVJlbmRlcmJ1ZmZlcigpO1xuXG5cdFx0XHRcdFx0X2dsLmJpbmRSZW5kZXJidWZmZXIoIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyWyBpIF0gKTtcblxuXHRcdFx0XHRcdGNvbnN0IGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUuY29sb3JTcGFjZSApO1xuXHRcdFx0XHRcdGNvbnN0IGdsVHlwZSA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUudHlwZSApO1xuXHRcdFx0XHRcdGNvbnN0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlLCByZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSApO1xuXHRcdFx0XHRcdGNvbnN0IHNhbXBsZXMgPSBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKTtcblx0XHRcdFx0XHRfZ2wucmVuZGVyYnVmZmVyU3RvcmFnZU11bHRpc2FtcGxlKCBfZ2wuUkVOREVSQlVGRkVSLCBzYW1wbGVzLCBnbEludGVybmFsRm9ybWF0LCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclJlbmRlcmJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAgKyBpLCBfZ2wuUkVOREVSQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlclsgaSBdICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdF9nbC5iaW5kUmVuZGVyYnVmZmVyKCBfZ2wuUkVOREVSQlVGRkVSLCBudWxsICk7XG5cblx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgKSB7XG5cblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aFJlbmRlcmJ1ZmZlciA9IF9nbC5jcmVhdGVSZW5kZXJidWZmZXIoKTtcblx0XHRcdFx0XHRzZXR1cFJlbmRlckJ1ZmZlclN0b3JhZ2UoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoUmVuZGVyYnVmZmVyLCByZW5kZXJUYXJnZXQsIHRydWUgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIG51bGwgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gU2V0dXAgY29sb3IgYnVmZmVyXG5cblx0XHRpZiAoIGlzQ3ViZSApIHtcblxuXHRcdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xuXHRcdFx0c2V0VGV4dHVyZVBhcmFtZXRlcnMoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCB0ZXh0dXJlICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdFx0aWYgKCB0ZXh0dXJlLm1pcG1hcHMgJiYgdGV4dHVyZS5taXBtYXBzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgbGV2ZWwgPSAwOyBsZXZlbCA8IHRleHR1cmUubWlwbWFwcy5sZW5ndGg7IGxldmVsICsrICkge1xuXG5cdFx0XHRcdFx0XHRzZXR1cEZyYW1lQnVmZmVyVGV4dHVyZSggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXVsgbGV2ZWwgXSwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBsZXZlbCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRzZXR1cEZyYW1lQnVmZmVyVGV4dHVyZSggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXSwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCAwICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlICkgKSB7XG5cblx0XHRcdFx0Z2VuZXJhdGVNaXBtYXAoIF9nbC5URVhUVVJFX0NVQkVfTUFQICk7XG5cblx0XHRcdH1cblxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xuXG5cdFx0fSBlbHNlIGlmICggaXNNdWx0aXBsZVJlbmRlclRhcmdldHMgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBhdHRhY2htZW50ID0gdGV4dHVyZXNbIGkgXTtcblx0XHRcdFx0Y29uc3QgYXR0YWNobWVudFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggYXR0YWNobWVudCApO1xuXG5cdFx0XHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBfZ2wuVEVYVFVSRV8yRCwgYXR0YWNobWVudFByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgKTtcblx0XHRcdFx0c2V0VGV4dHVyZVBhcmFtZXRlcnMoIF9nbC5URVhUVVJFXzJELCBhdHRhY2htZW50ICk7XG5cdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCBhdHRhY2htZW50LCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAgKyBpLCBfZ2wuVEVYVFVSRV8yRCwgMCApO1xuXG5cdFx0XHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCBhdHRhY2htZW50ICkgKSB7XG5cblx0XHRcdFx0XHRnZW5lcmF0ZU1pcG1hcCggX2dsLlRFWFRVUkVfMkQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0bGV0IGdsVGV4dHVyZVR5cGUgPSBfZ2wuVEVYVFVSRV8yRDtcblxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTDNEUmVuZGVyVGFyZ2V0IHx8IHJlbmRlclRhcmdldC5pc1dlYkdMQXJyYXlSZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRcdFx0Z2xUZXh0dXJlVHlwZSA9IHJlbmRlclRhcmdldC5pc1dlYkdMM0RSZW5kZXJUYXJnZXQgPyBfZ2wuVEVYVFVSRV8zRCA6IF9nbC5URVhUVVJFXzJEX0FSUkFZO1xuXG5cdFx0XHR9XG5cblx0XHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBnbFRleHR1cmVUeXBlLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xuXHRcdFx0c2V0VGV4dHVyZVBhcmFtZXRlcnMoIGdsVGV4dHVyZVR5cGUsIHRleHR1cmUgKTtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlLm1pcG1hcHMgJiYgdGV4dHVyZS5taXBtYXBzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGxldmVsID0gMDsgbGV2ZWwgPCB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoOyBsZXZlbCArKyApIHtcblxuXHRcdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgbGV2ZWwgXSwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIGdsVGV4dHVyZVR5cGUsIGxldmVsICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIGdsVGV4dHVyZVR5cGUsIDAgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRleHR1cmVOZWVkc0dlbmVyYXRlTWlwbWFwcyggdGV4dHVyZSApICkge1xuXG5cdFx0XHRcdGdlbmVyYXRlTWlwbWFwKCBnbFRleHR1cmVUeXBlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xuXG5cdFx0fVxuXG5cdFx0Ly8gU2V0dXAgZGVwdGggYW5kIHN0ZW5jaWwgYnVmZmVyc1xuXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgKSB7XG5cblx0XHRcdHNldHVwRGVwdGhSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB1cGRhdGVSZW5kZXJUYXJnZXRNaXBtYXAoIHJlbmRlclRhcmdldCApIHtcblxuXHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmVzO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRleHR1cmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCB0ZXh0dXJlID0gdGV4dHVyZXNbIGkgXTtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlTmVlZHNHZW5lcmF0ZU1pcG1hcHMoIHRleHR1cmUgKSApIHtcblxuXHRcdFx0XHRjb25zdCB0YXJnZXQgPSByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgPyBfZ2wuVEVYVFVSRV9DVUJFX01BUCA6IF9nbC5URVhUVVJFXzJEO1xuXHRcdFx0XHRjb25zdCB3ZWJnbFRleHR1cmUgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlO1xuXG5cdFx0XHRcdHN0YXRlLmJpbmRUZXh0dXJlKCB0YXJnZXQsIHdlYmdsVGV4dHVyZSApO1xuXHRcdFx0XHRnZW5lcmF0ZU1pcG1hcCggdGFyZ2V0ICk7XG5cdFx0XHRcdHN0YXRlLnVuYmluZFRleHR1cmUoKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRjb25zdCBpbnZhbGlkYXRpb25BcnJheVJlYWQgPSBbXTtcblx0Y29uc3QgaW52YWxpZGF0aW9uQXJyYXlEcmF3ID0gW107XG5cblx0ZnVuY3Rpb24gdXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCApIHtcblxuXHRcdGlmICggcmVuZGVyVGFyZ2V0LnNhbXBsZXMgPiAwICkge1xuXG5cdFx0XHRpZiAoIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmVzO1xuXHRcdFx0XHRjb25zdCB3aWR0aCA9IHJlbmRlclRhcmdldC53aWR0aDtcblx0XHRcdFx0Y29uc3QgaGVpZ2h0ID0gcmVuZGVyVGFyZ2V0LmhlaWdodDtcblx0XHRcdFx0bGV0IG1hc2sgPSBfZ2wuQ09MT1JfQlVGRkVSX0JJVDtcblx0XHRcdFx0Y29uc3QgZGVwdGhTdHlsZSA9IHJlbmRlclRhcmdldC5zdGVuY2lsQnVmZmVyID8gX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCA6IF9nbC5ERVBUSF9BVFRBQ0hNRU5UO1xuXHRcdFx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xuXHRcdFx0XHRjb25zdCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyA9ICggdGV4dHVyZXMubGVuZ3RoID4gMSApO1xuXG5cdFx0XHRcdC8vIElmIE1SVCB3ZSBuZWVkIHRvIHJlbW92ZSBGQk8gYXR0YWNobWVudHNcblx0XHRcdFx0aWYgKCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRleHR1cmVzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XG5cdFx0XHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJSZW5kZXJidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwICsgaSwgX2dsLlJFTkRFUkJVRkZFUiwgbnVsbCApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIgKTtcblx0XHRcdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5URVhUVVJFXzJELCBudWxsLCAwICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLlJFQURfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGV4dHVyZXMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXQucmVzb2x2ZURlcHRoQnVmZmVyICkge1xuXG5cdFx0XHRcdFx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aEJ1ZmZlciApIG1hc2sgfD0gX2dsLkRFUFRIX0JVRkZFUl9CSVQ7XG5cblx0XHRcdFx0XHRcdC8vIHJlc29sdmluZyBzdGVuY2lsIGlzIHNsb3cgd2l0aCBhIEQzRCBiYWNrZW5kLiBkaXNhYmxlIGl0IGZvciBhbGwgdHJhbnNtaXNzaW9uIHJlbmRlciB0YXJnZXRzIChzZWUgIzI3Nzk5KVxuXG5cdFx0XHRcdFx0XHRpZiAoIHJlbmRlclRhcmdldC5zdGVuY2lsQnVmZmVyICYmIHJlbmRlclRhcmdldC5yZXNvbHZlU3RlbmNpbEJ1ZmZlciApIG1hc2sgfD0gX2dsLlNURU5DSUxfQlVGRkVSX0JJVDtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggaXNNdWx0aXBsZVJlbmRlclRhcmdldHMgKSB7XG5cblx0XHRcdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclJlbmRlcmJ1ZmZlciggX2dsLlJFQURfRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCwgX2dsLlJFTkRFUkJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsQ29sb3JSZW5kZXJidWZmZXJbIGkgXSApO1xuXG5cdFx0XHRcdFx0XHRjb25zdCB3ZWJnbFRleHR1cmUgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZXNbIGkgXSApLl9fd2ViZ2xUZXh0dXJlO1xuXHRcdFx0XHRcdFx0X2dsLmZyYW1lYnVmZmVyVGV4dHVyZTJEKCBfZ2wuRFJBV19GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwLCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xUZXh0dXJlLCAwICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRfZ2wuYmxpdEZyYW1lYnVmZmVyKCAwLCAwLCB3aWR0aCwgaGVpZ2h0LCAwLCAwLCB3aWR0aCwgaGVpZ2h0LCBtYXNrLCBfZ2wuTkVBUkVTVCApO1xuXG5cdFx0XHRcdFx0aWYgKCBzdXBwb3J0c0ludmFsaWRhdGVGcmFtZWJ1ZmZlciA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdFx0aW52YWxpZGF0aW9uQXJyYXlSZWFkLmxlbmd0aCA9IDA7XG5cdFx0XHRcdFx0XHRpbnZhbGlkYXRpb25BcnJheURyYXcubGVuZ3RoID0gMDtcblxuXHRcdFx0XHRcdFx0aW52YWxpZGF0aW9uQXJyYXlSZWFkLnB1c2goIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGkgKTtcblxuXHRcdFx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgJiYgcmVuZGVyVGFyZ2V0LnJlc29sdmVEZXB0aEJ1ZmZlciA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0XHRcdFx0aW52YWxpZGF0aW9uQXJyYXlSZWFkLnB1c2goIGRlcHRoU3R5bGUgKTtcblx0XHRcdFx0XHRcdFx0aW52YWxpZGF0aW9uQXJyYXlEcmF3LnB1c2goIGRlcHRoU3R5bGUgKTtcblxuXHRcdFx0XHRcdFx0XHRfZ2wuaW52YWxpZGF0ZUZyYW1lYnVmZmVyKCBfZ2wuRFJBV19GUkFNRUJVRkZFUiwgaW52YWxpZGF0aW9uQXJyYXlEcmF3ICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0X2dsLmludmFsaWRhdGVGcmFtZWJ1ZmZlciggX2dsLlJFQURfRlJBTUVCVUZGRVIsIGludmFsaWRhdGlvbkFycmF5UmVhZCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5SRUFEX0ZSQU1FQlVGRkVSLCBudWxsICk7XG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIG51bGwgKTtcblxuXHRcdFx0XHQvLyBJZiBNUlQgc2luY2UgcHJlLWJsaXQgd2UgcmVtb3ZlZCB0aGUgRkJPIHdlIG5lZWQgdG8gcmVjb25zdHJ1Y3QgdGhlIGF0dGFjaG1lbnRzXG5cdFx0XHRcdGlmICggaXNNdWx0aXBsZVJlbmRlclRhcmdldHMgKSB7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0ZXh0dXJlcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlciApO1xuXHRcdFx0XHRcdFx0X2dsLmZyYW1lYnVmZmVyUmVuZGVyYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyWyBpIF0gKTtcblxuXHRcdFx0XHRcdFx0Y29uc3Qgd2ViZ2xUZXh0dXJlID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmVzWyBpIF0gKS5fX3dlYmdsVGV4dHVyZTtcblxuXHRcdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XG5cdFx0XHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlMkQoIF9nbC5EUkFXX0ZSQU1FQlVGRkVSLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAgKyBpLCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xUZXh0dXJlLCAwICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgJiYgcmVuZGVyVGFyZ2V0LnJlc29sdmVEZXB0aEJ1ZmZlciA9PT0gZmFsc2UgJiYgc3VwcG9ydHNJbnZhbGlkYXRlRnJhbWVidWZmZXIgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBkZXB0aFN0eWxlID0gcmVuZGVyVGFyZ2V0LnN0ZW5jaWxCdWZmZXIgPyBfZ2wuREVQVEhfU1RFTkNJTF9BVFRBQ0hNRU5UIDogX2dsLkRFUFRIX0FUVEFDSE1FTlQ7XG5cblx0XHRcdFx0XHRfZ2wuaW52YWxpZGF0ZUZyYW1lYnVmZmVyKCBfZ2wuRFJBV19GUkFNRUJVRkZFUiwgWyBkZXB0aFN0eWxlIF0gKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0UmVuZGVyVGFyZ2V0U2FtcGxlcyggcmVuZGVyVGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIE1hdGgubWluKCBjYXBhYmlsaXRpZXMubWF4U2FtcGxlcywgcmVuZGVyVGFyZ2V0LnNhbXBsZXMgKTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xuXG5cdFx0cmV0dXJuIHJlbmRlclRhcmdldC5zYW1wbGVzID4gMCAmJiBleHRlbnNpb25zLmhhcyggJ1dFQkdMX211bHRpc2FtcGxlZF9yZW5kZXJfdG9fdGV4dHVyZScgKSA9PT0gdHJ1ZSAmJiByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fdXNlUmVuZGVyVG9UZXh0dXJlICE9PSBmYWxzZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gdXBkYXRlVmlkZW9UZXh0dXJlKCB0ZXh0dXJlICkge1xuXG5cdFx0Y29uc3QgZnJhbWUgPSBpbmZvLnJlbmRlci5mcmFtZTtcblxuXHRcdC8vIENoZWNrIHRoZSBsYXN0IGZyYW1lIHdlIHVwZGF0ZWQgdGhlIFZpZGVvVGV4dHVyZVxuXG5cdFx0aWYgKCBfdmlkZW9UZXh0dXJlcy5nZXQoIHRleHR1cmUgKSAhPT0gZnJhbWUgKSB7XG5cblx0XHRcdF92aWRlb1RleHR1cmVzLnNldCggdGV4dHVyZSwgZnJhbWUgKTtcblx0XHRcdHRleHR1cmUudXBkYXRlKCk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHZlcmlmeUNvbG9yU3BhY2UoIHRleHR1cmUsIGltYWdlICkge1xuXG5cdFx0Y29uc3QgY29sb3JTcGFjZSA9IHRleHR1cmUuY29sb3JTcGFjZTtcblx0XHRjb25zdCBmb3JtYXQgPSB0ZXh0dXJlLmZvcm1hdDtcblx0XHRjb25zdCB0eXBlID0gdGV4dHVyZS50eXBlO1xuXG5cdFx0aWYgKCB0ZXh0dXJlLmlzQ29tcHJlc3NlZFRleHR1cmUgPT09IHRydWUgfHwgdGV4dHVyZS5pc1ZpZGVvVGV4dHVyZSA9PT0gdHJ1ZSApIHJldHVybiBpbWFnZTtcblxuXHRcdGlmICggY29sb3JTcGFjZSAhPT0gTGluZWFyU1JHQkNvbG9yU3BhY2UgJiYgY29sb3JTcGFjZSAhPT0gTm9Db2xvclNwYWNlICkge1xuXG5cdFx0XHQvLyBzUkdCXG5cblx0XHRcdGlmICggQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBjb2xvclNwYWNlICkgPT09IFNSR0JUcmFuc2ZlciApIHtcblxuXHRcdFx0XHQvLyBpbiBXZWJHTCAyIHVuY29tcHJlc3NlZCB0ZXh0dXJlcyBjYW4gb25seSBiZSBzUkdCIGVuY29kZWQgaWYgdGhleSBoYXZlIHRoZSBSR0JBOCBmb3JtYXRcblxuXHRcdFx0XHRpZiAoIGZvcm1hdCAhPT0gUkdCQUZvcm1hdCB8fCB0eXBlICE9PSBVbnNpZ25lZEJ5dGVUeXBlICkge1xuXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xUZXh0dXJlczogc1JHQiBlbmNvZGVkIHRleHR1cmVzIGhhdmUgdG8gdXNlIFJHQkFGb3JtYXQgYW5kIFVuc2lnbmVkQnl0ZVR5cGUuJyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xUZXh0dXJlczogVW5zdXBwb3J0ZWQgdGV4dHVyZSBjb2xvciBzcGFjZTonLCBjb2xvclNwYWNlICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiBpbWFnZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0RGltZW5zaW9ucyggaW1hZ2UgKSB7XG5cblx0XHRpZiAoIHR5cGVvZiBIVE1MSW1hZ2VFbGVtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEhUTUxJbWFnZUVsZW1lbnQgKSB7XG5cblx0XHRcdC8vIGlmIGludHJpbnNpYyBkYXRhIGFyZSBub3QgYXZhaWxhYmxlLCBmYWxsYmFjayB0byB3aWR0aC9oZWlnaHRcblxuXHRcdFx0X2ltYWdlRGltZW5zaW9ucy53aWR0aCA9IGltYWdlLm5hdHVyYWxXaWR0aCB8fCBpbWFnZS53aWR0aDtcblx0XHRcdF9pbWFnZURpbWVuc2lvbnMuaGVpZ2h0ID0gaW1hZ2UubmF0dXJhbEhlaWdodCB8fCBpbWFnZS5oZWlnaHQ7XG5cblx0XHR9IGVsc2UgaWYgKCB0eXBlb2YgVmlkZW9GcmFtZSAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBWaWRlb0ZyYW1lICkge1xuXG5cdFx0XHRfaW1hZ2VEaW1lbnNpb25zLndpZHRoID0gaW1hZ2UuZGlzcGxheVdpZHRoO1xuXHRcdFx0X2ltYWdlRGltZW5zaW9ucy5oZWlnaHQgPSBpbWFnZS5kaXNwbGF5SGVpZ2h0O1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0X2ltYWdlRGltZW5zaW9ucy53aWR0aCA9IGltYWdlLndpZHRoO1xuXHRcdFx0X2ltYWdlRGltZW5zaW9ucy5oZWlnaHQgPSBpbWFnZS5oZWlnaHQ7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gX2ltYWdlRGltZW5zaW9ucztcblxuXHR9XG5cblx0Ly9cblxuXHR0aGlzLmFsbG9jYXRlVGV4dHVyZVVuaXQgPSBhbGxvY2F0ZVRleHR1cmVVbml0O1xuXHR0aGlzLnJlc2V0VGV4dHVyZVVuaXRzID0gcmVzZXRUZXh0dXJlVW5pdHM7XG5cblx0dGhpcy5zZXRUZXh0dXJlMkQgPSBzZXRUZXh0dXJlMkQ7XG5cdHRoaXMuc2V0VGV4dHVyZTJEQXJyYXkgPSBzZXRUZXh0dXJlMkRBcnJheTtcblx0dGhpcy5zZXRUZXh0dXJlM0QgPSBzZXRUZXh0dXJlM0Q7XG5cdHRoaXMuc2V0VGV4dHVyZUN1YmUgPSBzZXRUZXh0dXJlQ3ViZTtcblx0dGhpcy5yZWJpbmRUZXh0dXJlcyA9IHJlYmluZFRleHR1cmVzO1xuXHR0aGlzLnNldHVwUmVuZGVyVGFyZ2V0ID0gc2V0dXBSZW5kZXJUYXJnZXQ7XG5cdHRoaXMudXBkYXRlUmVuZGVyVGFyZ2V0TWlwbWFwID0gdXBkYXRlUmVuZGVyVGFyZ2V0TWlwbWFwO1xuXHR0aGlzLnVwZGF0ZU11bHRpc2FtcGxlUmVuZGVyVGFyZ2V0ID0gdXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQ7XG5cdHRoaXMuc2V0dXBEZXB0aFJlbmRlcmJ1ZmZlciA9IHNldHVwRGVwdGhSZW5kZXJidWZmZXI7XG5cdHRoaXMuc2V0dXBGcmFtZUJ1ZmZlclRleHR1cmUgPSBzZXR1cEZyYW1lQnVmZmVyVGV4dHVyZTtcblx0dGhpcy51c2VNdWx0aXNhbXBsZWRSVFQgPSB1c2VNdWx0aXNhbXBsZWRSVFQ7XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xVdGlscyggZ2wsIGV4dGVuc2lvbnMgKSB7XG5cblx0ZnVuY3Rpb24gY29udmVydCggcCwgY29sb3JTcGFjZSA9IE5vQ29sb3JTcGFjZSApIHtcblxuXHRcdGxldCBleHRlbnNpb247XG5cblx0XHRjb25zdCB0cmFuc2ZlciA9IENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggY29sb3JTcGFjZSApO1xuXG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZEJ5dGVUeXBlICkgcmV0dXJuIGdsLlVOU0lHTkVEX0JZVEU7XG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZFNob3J0NDQ0NFR5cGUgKSByZXR1cm4gZ2wuVU5TSUdORURfU0hPUlRfNF80XzRfNDtcblx0XHRpZiAoIHAgPT09IFVuc2lnbmVkU2hvcnQ1NTUxVHlwZSApIHJldHVybiBnbC5VTlNJR05FRF9TSE9SVF81XzVfNV8xO1xuXHRcdGlmICggcCA9PT0gVW5zaWduZWRJbnQ1OTk5VHlwZSApIHJldHVybiBnbC5VTlNJR05FRF9JTlRfNV85XzlfOV9SRVY7XG5cblx0XHRpZiAoIHAgPT09IEJ5dGVUeXBlICkgcmV0dXJuIGdsLkJZVEU7XG5cdFx0aWYgKCBwID09PSBTaG9ydFR5cGUgKSByZXR1cm4gZ2wuU0hPUlQ7XG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZFNob3J0VHlwZSApIHJldHVybiBnbC5VTlNJR05FRF9TSE9SVDtcblx0XHRpZiAoIHAgPT09IEludFR5cGUgKSByZXR1cm4gZ2wuSU5UO1xuXHRcdGlmICggcCA9PT0gVW5zaWduZWRJbnRUeXBlICkgcmV0dXJuIGdsLlVOU0lHTkVEX0lOVDtcblx0XHRpZiAoIHAgPT09IEZsb2F0VHlwZSApIHJldHVybiBnbC5GTE9BVDtcblx0XHRpZiAoIHAgPT09IEhhbGZGbG9hdFR5cGUgKSByZXR1cm4gZ2wuSEFMRl9GTE9BVDtcblxuXHRcdGlmICggcCA9PT0gQWxwaGFGb3JtYXQgKSByZXR1cm4gZ2wuQUxQSEE7XG5cdFx0aWYgKCBwID09PSBSR0JGb3JtYXQgKSByZXR1cm4gZ2wuUkdCO1xuXHRcdGlmICggcCA9PT0gUkdCQUZvcm1hdCApIHJldHVybiBnbC5SR0JBO1xuXHRcdGlmICggcCA9PT0gTHVtaW5hbmNlRm9ybWF0ICkgcmV0dXJuIGdsLkxVTUlOQU5DRTtcblx0XHRpZiAoIHAgPT09IEx1bWluYW5jZUFscGhhRm9ybWF0ICkgcmV0dXJuIGdsLkxVTUlOQU5DRV9BTFBIQTtcblx0XHRpZiAoIHAgPT09IERlcHRoRm9ybWF0ICkgcmV0dXJuIGdsLkRFUFRIX0NPTVBPTkVOVDtcblx0XHRpZiAoIHAgPT09IERlcHRoU3RlbmNpbEZvcm1hdCApIHJldHVybiBnbC5ERVBUSF9TVEVOQ0lMO1xuXG5cdFx0Ly8gV2ViR0wyIGZvcm1hdHMuXG5cblx0XHRpZiAoIHAgPT09IFJlZEZvcm1hdCApIHJldHVybiBnbC5SRUQ7XG5cdFx0aWYgKCBwID09PSBSZWRJbnRlZ2VyRm9ybWF0ICkgcmV0dXJuIGdsLlJFRF9JTlRFR0VSO1xuXHRcdGlmICggcCA9PT0gUkdGb3JtYXQgKSByZXR1cm4gZ2wuUkc7XG5cdFx0aWYgKCBwID09PSBSR0ludGVnZXJGb3JtYXQgKSByZXR1cm4gZ2wuUkdfSU5URUdFUjtcblx0XHRpZiAoIHAgPT09IFJHQkFJbnRlZ2VyRm9ybWF0ICkgcmV0dXJuIGdsLlJHQkFfSU5URUdFUjtcblxuXHRcdC8vIFMzVENcblxuXHRcdGlmICggcCA9PT0gUkdCX1MzVENfRFhUMV9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9TM1RDX0RYVDFfRm9ybWF0IHx8IHAgPT09IFJHQkFfUzNUQ19EWFQzX0Zvcm1hdCB8fCBwID09PSBSR0JBX1MzVENfRFhUNV9Gb3JtYXQgKSB7XG5cblx0XHRcdGlmICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApIHtcblxuXHRcdFx0XHRleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9zM3RjX3NyZ2InICk7XG5cblx0XHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHAgPT09IFJHQl9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfUzNUQ19EWFQxX0VYVDtcblx0XHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfUzNUQ19EWFQxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCX0FMUEhBX1MzVENfRFhUMV9FWFQ7XG5cdFx0XHRcdFx0aWYgKCBwID09PSBSR0JBX1MzVENfRFhUM19Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQl9BTFBIQV9TM1RDX0RYVDNfRVhUO1xuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDVfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfQUxQSEFfUzNUQ19EWFQ1X0VYVDtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3MzdGMnICk7XG5cblx0XHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHAgPT09IFJHQl9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQl9TM1RDX0RYVDFfRVhUO1xuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfUzNUQ19EWFQxX0VYVDtcblx0XHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfUzNUQ19EWFQzX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX1MzVENfRFhUM19FWFQ7XG5cdFx0XHRcdFx0aWYgKCBwID09PSBSR0JBX1MzVENfRFhUNV9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9TM1RDX0RYVDVfRVhUO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIFBWUlRDXG5cblx0XHRpZiAoIHAgPT09IFJHQl9QVlJUQ180QlBQVjFfRm9ybWF0IHx8IHAgPT09IFJHQl9QVlJUQ18yQlBQVjFfRm9ybWF0IHx8IHAgPT09IFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCB8fCBwID09PSBSR0JBX1BWUlRDXzJCUFBWMV9Gb3JtYXQgKSB7XG5cblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3B2cnRjJyApO1xuXG5cdFx0XHRpZiAoIGV4dGVuc2lvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9QVlJUQ180QlBQVjFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQl9QVlJUQ180QlBQVjFfSU1HO1xuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9QVlJUQ18yQlBQVjFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQl9QVlJUQ18yQlBQVjFfSU1HO1xuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX1BWUlRDXzRCUFBWMV9JTUc7XG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9QVlJUQ18yQlBQVjFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfUFZSVENfMkJQUFYxX0lNRztcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gRVRDXG5cblx0XHRpZiAoIHAgPT09IFJHQl9FVEMxX0Zvcm1hdCB8fCBwID09PSBSR0JfRVRDMl9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9FVEMyX0VBQ19Gb3JtYXQgKSB7XG5cblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX2V0YycgKTtcblxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0aWYgKCBwID09PSBSR0JfRVRDMV9Gb3JtYXQgfHwgcCA9PT0gUkdCX0VUQzJfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfRVRDMiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQjhfRVRDMjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0VUQzJfRUFDX0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9FVEMyX0VBQyA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkE4X0VUQzJfRUFDO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBBU1RDXG5cblx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ180eDRfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ181eDRfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ181eDVfRm9ybWF0IHx8XG5cdFx0XHRwID09PSBSR0JBX0FTVENfNng1X0Zvcm1hdCB8fCBwID09PSBSR0JBX0FTVENfNng2X0Zvcm1hdCB8fCBwID09PSBSR0JBX0FTVENfOHg1X0Zvcm1hdCB8fFxuXHRcdFx0cCA9PT0gUkdCQV9BU1RDXzh4Nl9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9BU1RDXzh4OF9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9BU1RDXzEweDVfRm9ybWF0IHx8XG5cdFx0XHRwID09PSBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9BU1RDXzEweDhfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ18xMHgxMF9Gb3JtYXQgfHxcblx0XHRcdHAgPT09IFJHQkFfQVNUQ18xMngxMF9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9BU1RDXzEyeDEyX0Zvcm1hdCApIHtcblxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfYXN0YycgKTtcblxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNHg0X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzR4NF9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNHg0X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNXg0X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzV4NF9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNXg0X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNXg1X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzV4NV9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNXg1X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNng1X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzZ4NV9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNng1X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNng2X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzZ4Nl9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNng2X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfOHg1X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzh4NV9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfOHg1X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfOHg2X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzh4Nl9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfOHg2X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfOHg4X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzh4OF9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfOHg4X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4NV9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ18xMHg1X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ18xMHg1X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ18xMHg2X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ18xMHg2X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4OF9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ18xMHg4X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ18xMHg4X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4MTBfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfMTB4MTBfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzEweDEwX0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTJ4MTBfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfMTJ4MTBfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzEyeDEwX0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTJ4MTJfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfMTJ4MTJfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzEyeDEyX0tIUjtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gQlBUQ1xuXG5cdFx0aWYgKCBwID09PSBSR0JBX0JQVENfRm9ybWF0IHx8IHAgPT09IFJHQl9CUFRDX1NJR05FRF9Gb3JtYXQgfHwgcCA9PT0gUkdCX0JQVENfVU5TSUdORURfRm9ybWF0ICkge1xuXG5cdFx0XHRleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ0VYVF90ZXh0dXJlX2NvbXByZXNzaW9uX2JwdGMnICk7XG5cblx0XHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9CUFRDX0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfQUxQSEFfQlBUQ19VTk9STV9FWFQgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0JQVENfVU5PUk1fRVhUO1xuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9CUFRDX1NJR05FRF9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCX0JQVENfU0lHTkVEX0ZMT0FUX0VYVDtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JfQlBUQ19VTlNJR05FRF9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCX0JQVENfVU5TSUdORURfRkxPQVRfRVhUO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBSR1RDXG5cblx0XHRpZiAoIHAgPT09IFJFRF9SR1RDMV9Gb3JtYXQgfHwgcCA9PT0gU0lHTkVEX1JFRF9SR1RDMV9Gb3JtYXQgfHwgcCA9PT0gUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCB8fCBwID09PSBTSUdORURfUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCApIHtcblxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfdGV4dHVyZV9jb21wcmVzc2lvbl9yZ3RjJyApO1xuXG5cdFx0XHRpZiAoIGV4dGVuc2lvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQlBUQ19Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkVEX1JHVEMxX0VYVDtcblx0XHRcdFx0aWYgKCBwID09PSBTSUdORURfUkVEX1JHVEMxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9TSUdORURfUkVEX1JHVEMxX0VYVDtcblx0XHRcdFx0aWYgKCBwID09PSBSRURfR1JFRU5fUkdUQzJfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JFRF9HUkVFTl9SR1RDMl9FWFQ7XG5cdFx0XHRcdGlmICggcCA9PT0gU0lHTkVEX1JFRF9HUkVFTl9SR1RDMl9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU0lHTkVEX1JFRF9HUkVFTl9SR1RDMl9FWFQ7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vXG5cblx0XHRpZiAoIHAgPT09IFVuc2lnbmVkSW50MjQ4VHlwZSApIHJldHVybiBnbC5VTlNJR05FRF9JTlRfMjRfODtcblxuXHRcdC8vIGlmIFwicFwiIGNhbid0IGJlIHJlc29sdmVkLCBhc3N1bWUgdGhlIHVzZXIgZGVmaW5lcyBhIFdlYkdMIGNvbnN0YW50IGFzIGEgc3RyaW5nIChmYWxsYmFjay93b3JrYXJvdW5kIGZvciBwYWNrZWQgUkdCIGZvcm1hdHMpXG5cblx0XHRyZXR1cm4gKCBnbFsgcCBdICE9PSB1bmRlZmluZWQgKSA/IGdsWyBwIF0gOiBudWxsO1xuXG5cdH1cblxuXHRyZXR1cm4geyBjb252ZXJ0OiBjb252ZXJ0IH07XG5cbn1cblxuY2xhc3MgQXJyYXlDYW1lcmEgZXh0ZW5kcyBQZXJzcGVjdGl2ZUNhbWVyYSB7XG5cblx0Y29uc3RydWN0b3IoIGFycmF5ID0gW10gKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc0FycmF5Q2FtZXJhID0gdHJ1ZTtcblxuXHRcdHRoaXMuY2FtZXJhcyA9IGFycmF5O1xuXG5cdH1cblxufVxuXG5jbGFzcyBHcm91cCBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzR3JvdXAgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0dyb3VwJztcblxuXHR9XG5cbn1cblxuY29uc3QgX21vdmVFdmVudCA9IHsgdHlwZTogJ21vdmUnIH07XG5cbmNsYXNzIFdlYlhSQ29udHJvbGxlciB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHR0aGlzLl90YXJnZXRSYXkgPSBudWxsO1xuXHRcdHRoaXMuX2dyaXAgPSBudWxsO1xuXHRcdHRoaXMuX2hhbmQgPSBudWxsO1xuXG5cdH1cblxuXHRnZXRIYW5kU3BhY2UoKSB7XG5cblx0XHRpZiAoIHRoaXMuX2hhbmQgPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX2hhbmQgPSBuZXcgR3JvdXAoKTtcblx0XHRcdHRoaXMuX2hhbmQubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xuXHRcdFx0dGhpcy5faGFuZC52aXNpYmxlID0gZmFsc2U7XG5cblx0XHRcdHRoaXMuX2hhbmQuam9pbnRzID0ge307XG5cdFx0XHR0aGlzLl9oYW5kLmlucHV0U3RhdGUgPSB7IHBpbmNoaW5nOiBmYWxzZSB9O1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuX2hhbmQ7XG5cblx0fVxuXG5cdGdldFRhcmdldFJheVNwYWNlKCkge1xuXG5cdFx0aWYgKCB0aGlzLl90YXJnZXRSYXkgPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX3RhcmdldFJheSA9IG5ldyBHcm91cCgpO1xuXHRcdFx0dGhpcy5fdGFyZ2V0UmF5Lm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblx0XHRcdHRoaXMuX3RhcmdldFJheS52aXNpYmxlID0gZmFsc2U7XG5cdFx0XHR0aGlzLl90YXJnZXRSYXkuaGFzTGluZWFyVmVsb2NpdHkgPSBmYWxzZTtcblx0XHRcdHRoaXMuX3RhcmdldFJheS5saW5lYXJWZWxvY2l0eSA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0XHR0aGlzLl90YXJnZXRSYXkuaGFzQW5ndWxhclZlbG9jaXR5ID0gZmFsc2U7XG5cdFx0XHR0aGlzLl90YXJnZXRSYXkuYW5ndWxhclZlbG9jaXR5ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLl90YXJnZXRSYXk7XG5cblx0fVxuXG5cdGdldEdyaXBTcGFjZSgpIHtcblxuXHRcdGlmICggdGhpcy5fZ3JpcCA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5fZ3JpcCA9IG5ldyBHcm91cCgpO1xuXHRcdFx0dGhpcy5fZ3JpcC5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XG5cdFx0XHR0aGlzLl9ncmlwLnZpc2libGUgPSBmYWxzZTtcblx0XHRcdHRoaXMuX2dyaXAuaGFzTGluZWFyVmVsb2NpdHkgPSBmYWxzZTtcblx0XHRcdHRoaXMuX2dyaXAubGluZWFyVmVsb2NpdHkgPSBuZXcgVmVjdG9yMygpO1xuXHRcdFx0dGhpcy5fZ3JpcC5oYXNBbmd1bGFyVmVsb2NpdHkgPSBmYWxzZTtcblx0XHRcdHRoaXMuX2dyaXAuYW5ndWxhclZlbG9jaXR5ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLl9ncmlwO1xuXG5cdH1cblxuXHRkaXNwYXRjaEV2ZW50KCBldmVudCApIHtcblxuXHRcdGlmICggdGhpcy5fdGFyZ2V0UmF5ICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl90YXJnZXRSYXkuZGlzcGF0Y2hFdmVudCggZXZlbnQgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fZ3JpcCAhPT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5fZ3JpcC5kaXNwYXRjaEV2ZW50KCBldmVudCApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl9oYW5kICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl9oYW5kLmRpc3BhdGNoRXZlbnQoIGV2ZW50ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29ubmVjdCggaW5wdXRTb3VyY2UgKSB7XG5cblx0XHRpZiAoIGlucHV0U291cmNlICYmIGlucHV0U291cmNlLmhhbmQgKSB7XG5cblx0XHRcdGNvbnN0IGhhbmQgPSB0aGlzLl9oYW5kO1xuXG5cdFx0XHRpZiAoIGhhbmQgKSB7XG5cblx0XHRcdFx0Zm9yICggY29uc3QgaW5wdXRqb2ludCBvZiBpbnB1dFNvdXJjZS5oYW5kLnZhbHVlcygpICkge1xuXG5cdFx0XHRcdFx0Ly8gSW5pdGlhbGl6ZSBoYW5kIHdpdGggam9pbnRzIHdoZW4gY29ubmVjdGVkXG5cdFx0XHRcdFx0dGhpcy5fZ2V0SGFuZEpvaW50KCBoYW5kLCBpbnB1dGpvaW50ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHR0aGlzLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogJ2Nvbm5lY3RlZCcsIGRhdGE6IGlucHV0U291cmNlIH0gKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkaXNjb25uZWN0KCBpbnB1dFNvdXJjZSApIHtcblxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzY29ubmVjdGVkJywgZGF0YTogaW5wdXRTb3VyY2UgfSApO1xuXG5cdFx0aWYgKCB0aGlzLl90YXJnZXRSYXkgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX3RhcmdldFJheS52aXNpYmxlID0gZmFsc2U7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX2dyaXAgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX2dyaXAudmlzaWJsZSA9IGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl9oYW5kICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl9oYW5kLnZpc2libGUgPSBmYWxzZTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR1cGRhdGUoIGlucHV0U291cmNlLCBmcmFtZSwgcmVmZXJlbmNlU3BhY2UgKSB7XG5cblx0XHRsZXQgaW5wdXRQb3NlID0gbnVsbDtcblx0XHRsZXQgZ3JpcFBvc2UgPSBudWxsO1xuXHRcdGxldCBoYW5kUG9zZSA9IG51bGw7XG5cblx0XHRjb25zdCB0YXJnZXRSYXkgPSB0aGlzLl90YXJnZXRSYXk7XG5cdFx0Y29uc3QgZ3JpcCA9IHRoaXMuX2dyaXA7XG5cdFx0Y29uc3QgaGFuZCA9IHRoaXMuX2hhbmQ7XG5cblx0XHRpZiAoIGlucHV0U291cmNlICYmIGZyYW1lLnNlc3Npb24udmlzaWJpbGl0eVN0YXRlICE9PSAndmlzaWJsZS1ibHVycmVkJyApIHtcblxuXHRcdFx0aWYgKCBoYW5kICYmIGlucHV0U291cmNlLmhhbmQgKSB7XG5cblx0XHRcdFx0aGFuZFBvc2UgPSB0cnVlO1xuXG5cdFx0XHRcdGZvciAoIGNvbnN0IGlucHV0am9pbnQgb2YgaW5wdXRTb3VyY2UuaGFuZC52YWx1ZXMoKSApIHtcblxuXHRcdFx0XHRcdC8vIFVwZGF0ZSB0aGUgam9pbnRzIGdyb3VwcyB3aXRoIHRoZSBYUkpvaW50IHBvc2VzXG5cdFx0XHRcdFx0Y29uc3Qgam9pbnRQb3NlID0gZnJhbWUuZ2V0Sm9pbnRQb3NlKCBpbnB1dGpvaW50LCByZWZlcmVuY2VTcGFjZSApO1xuXG5cdFx0XHRcdFx0Ly8gVGhlIHRyYW5zZm9ybSBvZiB0aGlzIGpvaW50IHdpbGwgYmUgdXBkYXRlZCB3aXRoIHRoZSBqb2ludCBwb3NlIG9uIGVhY2ggZnJhbWVcblx0XHRcdFx0XHRjb25zdCBqb2ludCA9IHRoaXMuX2dldEhhbmRKb2ludCggaGFuZCwgaW5wdXRqb2ludCApO1xuXG5cdFx0XHRcdFx0aWYgKCBqb2ludFBvc2UgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRcdGpvaW50Lm1hdHJpeC5mcm9tQXJyYXkoIGpvaW50UG9zZS50cmFuc2Zvcm0ubWF0cml4ICk7XG5cdFx0XHRcdFx0XHRqb2ludC5tYXRyaXguZGVjb21wb3NlKCBqb2ludC5wb3NpdGlvbiwgam9pbnQucm90YXRpb24sIGpvaW50LnNjYWxlICk7XG5cdFx0XHRcdFx0XHRqb2ludC5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlID0gdHJ1ZTtcblx0XHRcdFx0XHRcdGpvaW50LmpvaW50UmFkaXVzID0gam9pbnRQb3NlLnJhZGl1cztcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGpvaW50LnZpc2libGUgPSBqb2ludFBvc2UgIT09IG51bGw7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIEN1c3RvbSBldmVudHNcblxuXHRcdFx0XHQvLyBDaGVjayBwaW5jaHpcblx0XHRcdFx0Y29uc3QgaW5kZXhUaXAgPSBoYW5kLmpvaW50c1sgJ2luZGV4LWZpbmdlci10aXAnIF07XG5cdFx0XHRcdGNvbnN0IHRodW1iVGlwID0gaGFuZC5qb2ludHNbICd0aHVtYi10aXAnIF07XG5cdFx0XHRcdGNvbnN0IGRpc3RhbmNlID0gaW5kZXhUaXAucG9zaXRpb24uZGlzdGFuY2VUbyggdGh1bWJUaXAucG9zaXRpb24gKTtcblxuXHRcdFx0XHRjb25zdCBkaXN0YW5jZVRvUGluY2ggPSAwLjAyO1xuXHRcdFx0XHRjb25zdCB0aHJlc2hvbGQgPSAwLjAwNTtcblxuXHRcdFx0XHRpZiAoIGhhbmQuaW5wdXRTdGF0ZS5waW5jaGluZyAmJiBkaXN0YW5jZSA+IGRpc3RhbmNlVG9QaW5jaCArIHRocmVzaG9sZCApIHtcblxuXHRcdFx0XHRcdGhhbmQuaW5wdXRTdGF0ZS5waW5jaGluZyA9IGZhbHNlO1xuXHRcdFx0XHRcdHRoaXMuZGlzcGF0Y2hFdmVudCgge1xuXHRcdFx0XHRcdFx0dHlwZTogJ3BpbmNoZW5kJyxcblx0XHRcdFx0XHRcdGhhbmRlZG5lc3M6IGlucHV0U291cmNlLmhhbmRlZG5lc3MsXG5cdFx0XHRcdFx0XHR0YXJnZXQ6IHRoaXNcblx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggISBoYW5kLmlucHV0U3RhdGUucGluY2hpbmcgJiYgZGlzdGFuY2UgPD0gZGlzdGFuY2VUb1BpbmNoIC0gdGhyZXNob2xkICkge1xuXG5cdFx0XHRcdFx0aGFuZC5pbnB1dFN0YXRlLnBpbmNoaW5nID0gdHJ1ZTtcblx0XHRcdFx0XHR0aGlzLmRpc3BhdGNoRXZlbnQoIHtcblx0XHRcdFx0XHRcdHR5cGU6ICdwaW5jaHN0YXJ0Jyxcblx0XHRcdFx0XHRcdGhhbmRlZG5lc3M6IGlucHV0U291cmNlLmhhbmRlZG5lc3MsXG5cdFx0XHRcdFx0XHR0YXJnZXQ6IHRoaXNcblx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGlmICggZ3JpcCAhPT0gbnVsbCAmJiBpbnB1dFNvdXJjZS5ncmlwU3BhY2UgKSB7XG5cblx0XHRcdFx0XHRncmlwUG9zZSA9IGZyYW1lLmdldFBvc2UoIGlucHV0U291cmNlLmdyaXBTcGFjZSwgcmVmZXJlbmNlU3BhY2UgKTtcblxuXHRcdFx0XHRcdGlmICggZ3JpcFBvc2UgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRcdGdyaXAubWF0cml4LmZyb21BcnJheSggZ3JpcFBvc2UudHJhbnNmb3JtLm1hdHJpeCApO1xuXHRcdFx0XHRcdFx0Z3JpcC5tYXRyaXguZGVjb21wb3NlKCBncmlwLnBvc2l0aW9uLCBncmlwLnJvdGF0aW9uLCBncmlwLnNjYWxlICk7XG5cdFx0XHRcdFx0XHRncmlwLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0XHRcdFx0XHRpZiAoIGdyaXBQb3NlLmxpbmVhclZlbG9jaXR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdGdyaXAuaGFzTGluZWFyVmVsb2NpdHkgPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRncmlwLmxpbmVhclZlbG9jaXR5LmNvcHkoIGdyaXBQb3NlLmxpbmVhclZlbG9jaXR5ICk7XG5cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0Z3JpcC5oYXNMaW5lYXJWZWxvY2l0eSA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdGlmICggZ3JpcFBvc2UuYW5ndWxhclZlbG9jaXR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdGdyaXAuaGFzQW5ndWxhclZlbG9jaXR5ID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0Z3JpcC5hbmd1bGFyVmVsb2NpdHkuY29weSggZ3JpcFBvc2UuYW5ndWxhclZlbG9jaXR5ICk7XG5cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0Z3JpcC5oYXNBbmd1bGFyVmVsb2NpdHkgPSBmYWxzZTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRhcmdldFJheSAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRpbnB1dFBvc2UgPSBmcmFtZS5nZXRQb3NlKCBpbnB1dFNvdXJjZS50YXJnZXRSYXlTcGFjZSwgcmVmZXJlbmNlU3BhY2UgKTtcblxuXHRcdFx0XHQvLyBTb21lIHJ1bnRpbWVzIChuYW1lbHkgVml2ZSBDb3Ntb3Mgd2l0aCBWaXZlIE9wZW5YUiBSdW50aW1lKSBoYXZlIG9ubHkgZ3JpcCBzcGFjZSBhbmQgcmF5IHNwYWNlIGlzIGVxdWFsIHRvIGl0XG5cdFx0XHRcdGlmICggaW5wdXRQb3NlID09PSBudWxsICYmIGdyaXBQb3NlICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0aW5wdXRQb3NlID0gZ3JpcFBvc2U7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggaW5wdXRQb3NlICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0dGFyZ2V0UmF5Lm1hdHJpeC5mcm9tQXJyYXkoIGlucHV0UG9zZS50cmFuc2Zvcm0ubWF0cml4ICk7XG5cdFx0XHRcdFx0dGFyZ2V0UmF5Lm1hdHJpeC5kZWNvbXBvc2UoIHRhcmdldFJheS5wb3NpdGlvbiwgdGFyZ2V0UmF5LnJvdGF0aW9uLCB0YXJnZXRSYXkuc2NhbGUgKTtcblx0XHRcdFx0XHR0YXJnZXRSYXkubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdFx0XHRpZiAoIGlucHV0UG9zZS5saW5lYXJWZWxvY2l0eSApIHtcblxuXHRcdFx0XHRcdFx0dGFyZ2V0UmF5Lmhhc0xpbmVhclZlbG9jaXR5ID0gdHJ1ZTtcblx0XHRcdFx0XHRcdHRhcmdldFJheS5saW5lYXJWZWxvY2l0eS5jb3B5KCBpbnB1dFBvc2UubGluZWFyVmVsb2NpdHkgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHRhcmdldFJheS5oYXNMaW5lYXJWZWxvY2l0eSA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCBpbnB1dFBvc2UuYW5ndWxhclZlbG9jaXR5ICkge1xuXG5cdFx0XHRcdFx0XHR0YXJnZXRSYXkuaGFzQW5ndWxhclZlbG9jaXR5ID0gdHJ1ZTtcblx0XHRcdFx0XHRcdHRhcmdldFJheS5hbmd1bGFyVmVsb2NpdHkuY29weSggaW5wdXRQb3NlLmFuZ3VsYXJWZWxvY2l0eSApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0dGFyZ2V0UmF5Lmhhc0FuZ3VsYXJWZWxvY2l0eSA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCBfbW92ZUV2ZW50ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblxuXHRcdH1cblxuXHRcdGlmICggdGFyZ2V0UmF5ICE9PSBudWxsICkge1xuXG5cdFx0XHR0YXJnZXRSYXkudmlzaWJsZSA9ICggaW5wdXRQb3NlICE9PSBudWxsICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIGdyaXAgIT09IG51bGwgKSB7XG5cblx0XHRcdGdyaXAudmlzaWJsZSA9ICggZ3JpcFBvc2UgIT09IG51bGwgKTtcblxuXHRcdH1cblxuXHRcdGlmICggaGFuZCAhPT0gbnVsbCApIHtcblxuXHRcdFx0aGFuZC52aXNpYmxlID0gKCBoYW5kUG9zZSAhPT0gbnVsbCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIHByaXZhdGUgbWV0aG9kXG5cblx0X2dldEhhbmRKb2ludCggaGFuZCwgaW5wdXRqb2ludCApIHtcblxuXHRcdGlmICggaGFuZC5qb2ludHNbIGlucHV0am9pbnQuam9pbnROYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3Qgam9pbnQgPSBuZXcgR3JvdXAoKTtcblx0XHRcdGpvaW50Lm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblx0XHRcdGpvaW50LnZpc2libGUgPSBmYWxzZTtcblx0XHRcdGhhbmQuam9pbnRzWyBpbnB1dGpvaW50LmpvaW50TmFtZSBdID0gam9pbnQ7XG5cblx0XHRcdGhhbmQuYWRkKCBqb2ludCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGhhbmQuam9pbnRzWyBpbnB1dGpvaW50LmpvaW50TmFtZSBdO1xuXG5cdH1cblxufVxuXG5jb25zdCBfb2NjbHVzaW9uX3ZlcnRleCA9IGBcbnZvaWQgbWFpbigpIHtcblxuXHRnbF9Qb3NpdGlvbiA9IHZlYzQoIHBvc2l0aW9uLCAxLjAgKTtcblxufWA7XG5cbmNvbnN0IF9vY2NsdXNpb25fZnJhZ21lbnQgPSBgXG51bmlmb3JtIHNhbXBsZXIyREFycmF5IGRlcHRoQ29sb3I7XG51bmlmb3JtIGZsb2F0IGRlcHRoV2lkdGg7XG51bmlmb3JtIGZsb2F0IGRlcHRoSGVpZ2h0O1xuXG52b2lkIG1haW4oKSB7XG5cblx0dmVjMiBjb29yZCA9IHZlYzIoIGdsX0ZyYWdDb29yZC54IC8gZGVwdGhXaWR0aCwgZ2xfRnJhZ0Nvb3JkLnkgLyBkZXB0aEhlaWdodCApO1xuXG5cdGlmICggY29vcmQueCA+PSAxLjAgKSB7XG5cblx0XHRnbF9GcmFnRGVwdGggPSB0ZXh0dXJlKCBkZXB0aENvbG9yLCB2ZWMzKCBjb29yZC54IC0gMS4wLCBjb29yZC55LCAxICkgKS5yO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRnbF9GcmFnRGVwdGggPSB0ZXh0dXJlKCBkZXB0aENvbG9yLCB2ZWMzKCBjb29yZC54LCBjb29yZC55LCAwICkgKS5yO1xuXG5cdH1cblxufWA7XG5cbmNsYXNzIFdlYlhSRGVwdGhTZW5zaW5nIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHRoaXMudGV4dHVyZSA9IG51bGw7XG5cdFx0dGhpcy5tZXNoID0gbnVsbDtcblxuXHRcdHRoaXMuZGVwdGhOZWFyID0gMDtcblx0XHR0aGlzLmRlcHRoRmFyID0gMDtcblxuXHR9XG5cblx0aW5pdCggcmVuZGVyZXIsIGRlcHRoRGF0YSwgcmVuZGVyU3RhdGUgKSB7XG5cblx0XHRpZiAoIHRoaXMudGV4dHVyZSA9PT0gbnVsbCApIHtcblxuXHRcdFx0Y29uc3QgdGV4dHVyZSA9IG5ldyBUZXh0dXJlKCk7XG5cblx0XHRcdGNvbnN0IHRleFByb3BzID0gcmVuZGVyZXIucHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcblx0XHRcdHRleFByb3BzLl9fd2ViZ2xUZXh0dXJlID0gZGVwdGhEYXRhLnRleHR1cmU7XG5cblx0XHRcdGlmICggKCBkZXB0aERhdGEuZGVwdGhOZWFyICE9IHJlbmRlclN0YXRlLmRlcHRoTmVhciApIHx8ICggZGVwdGhEYXRhLmRlcHRoRmFyICE9IHJlbmRlclN0YXRlLmRlcHRoRmFyICkgKSB7XG5cblx0XHRcdFx0dGhpcy5kZXB0aE5lYXIgPSBkZXB0aERhdGEuZGVwdGhOZWFyO1xuXHRcdFx0XHR0aGlzLmRlcHRoRmFyID0gZGVwdGhEYXRhLmRlcHRoRmFyO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMudGV4dHVyZSA9IHRleHR1cmU7XG5cblx0XHR9XG5cblx0fVxuXG5cdGdldE1lc2goIGNhbWVyYVhSICkge1xuXG5cdFx0aWYgKCB0aGlzLnRleHR1cmUgIT09IG51bGwgKSB7XG5cblx0XHRcdGlmICggdGhpcy5tZXNoID09PSBudWxsICkge1xuXG5cdFx0XHRcdGNvbnN0IHZpZXdwb3J0ID0gY2FtZXJhWFIuY2FtZXJhc1sgMCBdLnZpZXdwb3J0O1xuXHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xuXHRcdFx0XHRcdHZlcnRleFNoYWRlcjogX29jY2x1c2lvbl92ZXJ0ZXgsXG5cdFx0XHRcdFx0ZnJhZ21lbnRTaGFkZXI6IF9vY2NsdXNpb25fZnJhZ21lbnQsXG5cdFx0XHRcdFx0dW5pZm9ybXM6IHtcblx0XHRcdFx0XHRcdGRlcHRoQ29sb3I6IHsgdmFsdWU6IHRoaXMudGV4dHVyZSB9LFxuXHRcdFx0XHRcdFx0ZGVwdGhXaWR0aDogeyB2YWx1ZTogdmlld3BvcnQueiB9LFxuXHRcdFx0XHRcdFx0ZGVwdGhIZWlnaHQ6IHsgdmFsdWU6IHZpZXdwb3J0LncgfVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdHRoaXMubWVzaCA9IG5ldyBNZXNoKCBuZXcgUGxhbmVHZW9tZXRyeSggMjAsIDIwICksIG1hdGVyaWFsICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLm1lc2g7XG5cblx0fVxuXG5cdHJlc2V0KCkge1xuXG5cdFx0dGhpcy50ZXh0dXJlID0gbnVsbDtcblx0XHR0aGlzLm1lc2ggPSBudWxsO1xuXG5cdH1cblxuXHRnZXREZXB0aFRleHR1cmUoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy50ZXh0dXJlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBXZWJYUk1hbmFnZXIgZXh0ZW5kcyBFdmVudERpc3BhdGNoZXIge1xuXG5cdGNvbnN0cnVjdG9yKCByZW5kZXJlciwgZ2wgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0bGV0IHNlc3Npb24gPSBudWxsO1xuXG5cdFx0bGV0IGZyYW1lYnVmZmVyU2NhbGVGYWN0b3IgPSAxLjA7XG5cblx0XHRsZXQgcmVmZXJlbmNlU3BhY2UgPSBudWxsO1xuXHRcdGxldCByZWZlcmVuY2VTcGFjZVR5cGUgPSAnbG9jYWwtZmxvb3InO1xuXHRcdC8vIFNldCBkZWZhdWx0IGZvdmVhdGlvbiB0byBtYXhpbXVtLlxuXHRcdGxldCBmb3ZlYXRpb24gPSAxLjA7XG5cdFx0bGV0IGN1c3RvbVJlZmVyZW5jZVNwYWNlID0gbnVsbDtcblxuXHRcdGxldCBwb3NlID0gbnVsbDtcblx0XHRsZXQgZ2xCaW5kaW5nID0gbnVsbDtcblx0XHRsZXQgZ2xQcm9qTGF5ZXIgPSBudWxsO1xuXHRcdGxldCBnbEJhc2VMYXllciA9IG51bGw7XG5cdFx0bGV0IHhyRnJhbWUgPSBudWxsO1xuXG5cdFx0Y29uc3QgZGVwdGhTZW5zaW5nID0gbmV3IFdlYlhSRGVwdGhTZW5zaW5nKCk7XG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IGdsLmdldENvbnRleHRBdHRyaWJ1dGVzKCk7XG5cblx0XHRsZXQgaW5pdGlhbFJlbmRlclRhcmdldCA9IG51bGw7XG5cdFx0bGV0IG5ld1JlbmRlclRhcmdldCA9IG51bGw7XG5cblx0XHRjb25zdCBjb250cm9sbGVycyA9IFtdO1xuXHRcdGNvbnN0IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXMgPSBbXTtcblxuXHRcdGNvbnN0IGN1cnJlbnRTaXplID0gbmV3IFZlY3RvcjIoKTtcblx0XHRsZXQgY3VycmVudFBpeGVsUmF0aW8gPSBudWxsO1xuXG5cdFx0Ly9cblxuXHRcdGNvbnN0IGNhbWVyYUwgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoKTtcblx0XHRjYW1lcmFMLmxheWVycy5lbmFibGUoIDEgKTtcblx0XHRjYW1lcmFMLnZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKTtcblxuXHRcdGNvbnN0IGNhbWVyYVIgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoKTtcblx0XHRjYW1lcmFSLmxheWVycy5lbmFibGUoIDIgKTtcblx0XHRjYW1lcmFSLnZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKTtcblxuXHRcdGNvbnN0IGNhbWVyYXMgPSBbIGNhbWVyYUwsIGNhbWVyYVIgXTtcblxuXHRcdGNvbnN0IGNhbWVyYVhSID0gbmV3IEFycmF5Q2FtZXJhKCk7XG5cdFx0Y2FtZXJhWFIubGF5ZXJzLmVuYWJsZSggMSApO1xuXHRcdGNhbWVyYVhSLmxheWVycy5lbmFibGUoIDIgKTtcblxuXHRcdGxldCBfY3VycmVudERlcHRoTmVhciA9IG51bGw7XG5cdFx0bGV0IF9jdXJyZW50RGVwdGhGYXIgPSBudWxsO1xuXG5cdFx0Ly9cblxuXHRcdHRoaXMuY2FtZXJhQXV0b1VwZGF0ZSA9IHRydWU7XG5cdFx0dGhpcy5lbmFibGVkID0gZmFsc2U7XG5cblx0XHR0aGlzLmlzUHJlc2VudGluZyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5nZXRDb250cm9sbGVyID0gZnVuY3Rpb24gKCBpbmRleCApIHtcblxuXHRcdFx0bGV0IGNvbnRyb2xsZXIgPSBjb250cm9sbGVyc1sgaW5kZXggXTtcblxuXHRcdFx0aWYgKCBjb250cm9sbGVyID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29udHJvbGxlciA9IG5ldyBXZWJYUkNvbnRyb2xsZXIoKTtcblx0XHRcdFx0Y29udHJvbGxlcnNbIGluZGV4IF0gPSBjb250cm9sbGVyO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBjb250cm9sbGVyLmdldFRhcmdldFJheVNwYWNlKCk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRDb250cm9sbGVyR3JpcCA9IGZ1bmN0aW9uICggaW5kZXggKSB7XG5cblx0XHRcdGxldCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGluZGV4IF07XG5cblx0XHRcdGlmICggY29udHJvbGxlciA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGNvbnRyb2xsZXIgPSBuZXcgV2ViWFJDb250cm9sbGVyKCk7XG5cdFx0XHRcdGNvbnRyb2xsZXJzWyBpbmRleCBdID0gY29udHJvbGxlcjtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gY29udHJvbGxlci5nZXRHcmlwU3BhY2UoKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldEhhbmQgPSBmdW5jdGlvbiAoIGluZGV4ICkge1xuXG5cdFx0XHRsZXQgY29udHJvbGxlciA9IGNvbnRyb2xsZXJzWyBpbmRleCBdO1xuXG5cdFx0XHRpZiAoIGNvbnRyb2xsZXIgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRjb250cm9sbGVyID0gbmV3IFdlYlhSQ29udHJvbGxlcigpO1xuXHRcdFx0XHRjb250cm9sbGVyc1sgaW5kZXggXSA9IGNvbnRyb2xsZXI7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGNvbnRyb2xsZXIuZ2V0SGFuZFNwYWNlKCk7XG5cblx0XHR9O1xuXG5cdFx0Ly9cblxuXHRcdGZ1bmN0aW9uIG9uU2Vzc2lvbkV2ZW50KCBldmVudCApIHtcblxuXHRcdFx0Y29uc3QgY29udHJvbGxlckluZGV4ID0gY29udHJvbGxlcklucHV0U291cmNlcy5pbmRleE9mKCBldmVudC5pbnB1dFNvdXJjZSApO1xuXG5cdFx0XHRpZiAoIGNvbnRyb2xsZXJJbmRleCA9PT0gLSAxICkge1xuXG5cdFx0XHRcdHJldHVybjtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGNvbnRyb2xsZXJJbmRleCBdO1xuXG5cdFx0XHRpZiAoIGNvbnRyb2xsZXIgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRjb250cm9sbGVyLnVwZGF0ZSggZXZlbnQuaW5wdXRTb3VyY2UsIGV2ZW50LmZyYW1lLCBjdXN0b21SZWZlcmVuY2VTcGFjZSB8fCByZWZlcmVuY2VTcGFjZSApO1xuXHRcdFx0XHRjb250cm9sbGVyLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogZXZlbnQudHlwZSwgZGF0YTogZXZlbnQuaW5wdXRTb3VyY2UgfSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBvblNlc3Npb25FbmQoKSB7XG5cblx0XHRcdHNlc3Npb24ucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3NlbGVjdCcsIG9uU2Vzc2lvbkV2ZW50ICk7XG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdzZWxlY3RzdGFydCcsIG9uU2Vzc2lvbkV2ZW50ICk7XG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdzZWxlY3RlbmQnLCBvblNlc3Npb25FdmVudCApO1xuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZScsIG9uU2Vzc2lvbkV2ZW50ICk7XG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdzcXVlZXplc3RhcnQnLCBvblNlc3Npb25FdmVudCApO1xuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZWVuZCcsIG9uU2Vzc2lvbkV2ZW50ICk7XG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdlbmQnLCBvblNlc3Npb25FbmQgKTtcblx0XHRcdHNlc3Npb24ucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2lucHV0c291cmNlc2NoYW5nZScsIG9uSW5wdXRTb3VyY2VzQ2hhbmdlICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvbnRyb2xsZXJzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbnB1dFNvdXJjZSA9IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXNbIGkgXTtcblxuXHRcdFx0XHRpZiAoIGlucHV0U291cmNlID09PSBudWxsICkgY29udGludWU7XG5cblx0XHRcdFx0Y29udHJvbGxlcklucHV0U291cmNlc1sgaSBdID0gbnVsbDtcblxuXHRcdFx0XHRjb250cm9sbGVyc1sgaSBdLmRpc2Nvbm5lY3QoIGlucHV0U291cmNlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0X2N1cnJlbnREZXB0aE5lYXIgPSBudWxsO1xuXHRcdFx0X2N1cnJlbnREZXB0aEZhciA9IG51bGw7XG5cblx0XHRcdGRlcHRoU2Vuc2luZy5yZXNldCgpO1xuXG5cdFx0XHQvLyByZXN0b3JlIGZyYW1lYnVmZmVyL3JlbmRlcmluZyBzdGF0ZVxuXG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGluaXRpYWxSZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0Z2xCYXNlTGF5ZXIgPSBudWxsO1xuXHRcdFx0Z2xQcm9qTGF5ZXIgPSBudWxsO1xuXHRcdFx0Z2xCaW5kaW5nID0gbnVsbDtcblx0XHRcdHNlc3Npb24gPSBudWxsO1xuXHRcdFx0bmV3UmVuZGVyVGFyZ2V0ID0gbnVsbDtcblxuXHRcdFx0Ly9cblxuXHRcdFx0YW5pbWF0aW9uLnN0b3AoKTtcblxuXHRcdFx0c2NvcGUuaXNQcmVzZW50aW5nID0gZmFsc2U7XG5cblx0XHRcdHJlbmRlcmVyLnNldFBpeGVsUmF0aW8oIGN1cnJlbnRQaXhlbFJhdGlvICk7XG5cdFx0XHRyZW5kZXJlci5zZXRTaXplKCBjdXJyZW50U2l6ZS53aWR0aCwgY3VycmVudFNpemUuaGVpZ2h0LCBmYWxzZSApO1xuXG5cdFx0XHRzY29wZS5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdzZXNzaW9uZW5kJyB9ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLnNldEZyYW1lYnVmZmVyU2NhbGVGYWN0b3IgPSBmdW5jdGlvbiAoIHZhbHVlICkge1xuXG5cdFx0XHRmcmFtZWJ1ZmZlclNjYWxlRmFjdG9yID0gdmFsdWU7XG5cblx0XHRcdGlmICggc2NvcGUuaXNQcmVzZW50aW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYlhSTWFuYWdlcjogQ2Fubm90IGNoYW5nZSBmcmFtZWJ1ZmZlciBzY2FsZSB3aGlsZSBwcmVzZW50aW5nLicgKTtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0UmVmZXJlbmNlU3BhY2VUeXBlID0gZnVuY3Rpb24gKCB2YWx1ZSApIHtcblxuXHRcdFx0cmVmZXJlbmNlU3BhY2VUeXBlID0gdmFsdWU7XG5cblx0XHRcdGlmICggc2NvcGUuaXNQcmVzZW50aW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYlhSTWFuYWdlcjogQ2Fubm90IGNoYW5nZSByZWZlcmVuY2Ugc3BhY2UgdHlwZSB3aGlsZSBwcmVzZW50aW5nLicgKTtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0UmVmZXJlbmNlU3BhY2UgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBjdXN0b21SZWZlcmVuY2VTcGFjZSB8fCByZWZlcmVuY2VTcGFjZTtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldFJlZmVyZW5jZVNwYWNlID0gZnVuY3Rpb24gKCBzcGFjZSApIHtcblxuXHRcdFx0Y3VzdG9tUmVmZXJlbmNlU3BhY2UgPSBzcGFjZTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldEJhc2VMYXllciA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIGdsUHJvakxheWVyICE9PSBudWxsID8gZ2xQcm9qTGF5ZXIgOiBnbEJhc2VMYXllcjtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldEJpbmRpbmcgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBnbEJpbmRpbmc7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRGcmFtZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIHhyRnJhbWU7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRTZXNzaW9uID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gc2Vzc2lvbjtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldFNlc3Npb24gPSBhc3luYyBmdW5jdGlvbiAoIHZhbHVlICkge1xuXG5cdFx0XHRzZXNzaW9uID0gdmFsdWU7XG5cblx0XHRcdGlmICggc2Vzc2lvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRpbml0aWFsUmVuZGVyVGFyZ2V0ID0gcmVuZGVyZXIuZ2V0UmVuZGVyVGFyZ2V0KCk7XG5cblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnc2VsZWN0Jywgb25TZXNzaW9uRXZlbnQgKTtcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnc2VsZWN0c3RhcnQnLCBvblNlc3Npb25FdmVudCApO1xuXHRcdFx0XHRzZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoICdzZWxlY3RlbmQnLCBvblNlc3Npb25FdmVudCApO1xuXHRcdFx0XHRzZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoICdzcXVlZXplJywgb25TZXNzaW9uRXZlbnQgKTtcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZXN0YXJ0Jywgb25TZXNzaW9uRXZlbnQgKTtcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZWVuZCcsIG9uU2Vzc2lvbkV2ZW50ICk7XG5cdFx0XHRcdHNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lciggJ2VuZCcsIG9uU2Vzc2lvbkVuZCApO1xuXHRcdFx0XHRzZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoICdpbnB1dHNvdXJjZXNjaGFuZ2UnLCBvbklucHV0U291cmNlc0NoYW5nZSApO1xuXG5cdFx0XHRcdGlmICggYXR0cmlidXRlcy54ckNvbXBhdGlibGUgIT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRhd2FpdCBnbC5tYWtlWFJDb21wYXRpYmxlKCk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGN1cnJlbnRQaXhlbFJhdGlvID0gcmVuZGVyZXIuZ2V0UGl4ZWxSYXRpbygpO1xuXHRcdFx0XHRyZW5kZXJlci5nZXRTaXplKCBjdXJyZW50U2l6ZSApO1xuXG5cdFx0XHRcdGlmICggc2Vzc2lvbi5yZW5kZXJTdGF0ZS5sYXllcnMgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGxheWVySW5pdCA9IHtcblx0XHRcdFx0XHRcdGFudGlhbGlhczogYXR0cmlidXRlcy5hbnRpYWxpYXMsXG5cdFx0XHRcdFx0XHRhbHBoYTogdHJ1ZSxcblx0XHRcdFx0XHRcdGRlcHRoOiBhdHRyaWJ1dGVzLmRlcHRoLFxuXHRcdFx0XHRcdFx0c3RlbmNpbDogYXR0cmlidXRlcy5zdGVuY2lsLFxuXHRcdFx0XHRcdFx0ZnJhbWVidWZmZXJTY2FsZUZhY3RvcjogZnJhbWVidWZmZXJTY2FsZUZhY3RvclxuXHRcdFx0XHRcdH07XG5cblx0XHRcdFx0XHRnbEJhc2VMYXllciA9IG5ldyBYUldlYkdMTGF5ZXIoIHNlc3Npb24sIGdsLCBsYXllckluaXQgKTtcblxuXHRcdFx0XHRcdHNlc3Npb24udXBkYXRlUmVuZGVyU3RhdGUoIHsgYmFzZUxheWVyOiBnbEJhc2VMYXllciB9ICk7XG5cblx0XHRcdFx0XHRyZW5kZXJlci5zZXRQaXhlbFJhdGlvKCAxICk7XG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0U2l6ZSggZ2xCYXNlTGF5ZXIuZnJhbWVidWZmZXJXaWR0aCwgZ2xCYXNlTGF5ZXIuZnJhbWVidWZmZXJIZWlnaHQsIGZhbHNlICk7XG5cblx0XHRcdFx0XHRuZXdSZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoXG5cdFx0XHRcdFx0XHRnbEJhc2VMYXllci5mcmFtZWJ1ZmZlcldpZHRoLFxuXHRcdFx0XHRcdFx0Z2xCYXNlTGF5ZXIuZnJhbWVidWZmZXJIZWlnaHQsXG5cdFx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRcdGZvcm1hdDogUkdCQUZvcm1hdCxcblx0XHRcdFx0XHRcdFx0dHlwZTogVW5zaWduZWRCeXRlVHlwZSxcblx0XHRcdFx0XHRcdFx0Y29sb3JTcGFjZTogcmVuZGVyZXIub3V0cHV0Q29sb3JTcGFjZSxcblx0XHRcdFx0XHRcdFx0c3RlbmNpbEJ1ZmZlcjogYXR0cmlidXRlcy5zdGVuY2lsXG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0KTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0bGV0IGRlcHRoRm9ybWF0ID0gbnVsbDtcblx0XHRcdFx0XHRsZXQgZGVwdGhUeXBlID0gbnVsbDtcblx0XHRcdFx0XHRsZXQgZ2xEZXB0aEZvcm1hdCA9IG51bGw7XG5cblx0XHRcdFx0XHRpZiAoIGF0dHJpYnV0ZXMuZGVwdGggKSB7XG5cblx0XHRcdFx0XHRcdGdsRGVwdGhGb3JtYXQgPSBhdHRyaWJ1dGVzLnN0ZW5jaWwgPyBnbC5ERVBUSDI0X1NURU5DSUw4IDogZ2wuREVQVEhfQ09NUE9ORU5UMjQ7XG5cdFx0XHRcdFx0XHRkZXB0aEZvcm1hdCA9IGF0dHJpYnV0ZXMuc3RlbmNpbCA/IERlcHRoU3RlbmNpbEZvcm1hdCA6IERlcHRoRm9ybWF0O1xuXHRcdFx0XHRcdFx0ZGVwdGhUeXBlID0gYXR0cmlidXRlcy5zdGVuY2lsID8gVW5zaWduZWRJbnQyNDhUeXBlIDogVW5zaWduZWRJbnRUeXBlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Y29uc3QgcHJvamVjdGlvbmxheWVySW5pdCA9IHtcblx0XHRcdFx0XHRcdGNvbG9yRm9ybWF0OiBnbC5SR0JBOCxcblx0XHRcdFx0XHRcdGRlcHRoRm9ybWF0OiBnbERlcHRoRm9ybWF0LFxuXHRcdFx0XHRcdFx0c2NhbGVGYWN0b3I6IGZyYW1lYnVmZmVyU2NhbGVGYWN0b3Jcblx0XHRcdFx0XHR9O1xuXG5cdFx0XHRcdFx0Z2xCaW5kaW5nID0gbmV3IFhSV2ViR0xCaW5kaW5nKCBzZXNzaW9uLCBnbCApO1xuXG5cdFx0XHRcdFx0Z2xQcm9qTGF5ZXIgPSBnbEJpbmRpbmcuY3JlYXRlUHJvamVjdGlvbkxheWVyKCBwcm9qZWN0aW9ubGF5ZXJJbml0ICk7XG5cblx0XHRcdFx0XHRzZXNzaW9uLnVwZGF0ZVJlbmRlclN0YXRlKCB7IGxheWVyczogWyBnbFByb2pMYXllciBdIH0gKTtcblxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldFBpeGVsUmF0aW8oIDEgKTtcblx0XHRcdFx0XHRyZW5kZXJlci5zZXRTaXplKCBnbFByb2pMYXllci50ZXh0dXJlV2lkdGgsIGdsUHJvakxheWVyLnRleHR1cmVIZWlnaHQsIGZhbHNlICk7XG5cblx0XHRcdFx0XHRuZXdSZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoXG5cdFx0XHRcdFx0XHRnbFByb2pMYXllci50ZXh0dXJlV2lkdGgsXG5cdFx0XHRcdFx0XHRnbFByb2pMYXllci50ZXh0dXJlSGVpZ2h0LFxuXHRcdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0XHRmb3JtYXQ6IFJHQkFGb3JtYXQsXG5cdFx0XHRcdFx0XHRcdHR5cGU6IFVuc2lnbmVkQnl0ZVR5cGUsXG5cdFx0XHRcdFx0XHRcdGRlcHRoVGV4dHVyZTogbmV3IERlcHRoVGV4dHVyZSggZ2xQcm9qTGF5ZXIudGV4dHVyZVdpZHRoLCBnbFByb2pMYXllci50ZXh0dXJlSGVpZ2h0LCBkZXB0aFR5cGUsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIGRlcHRoRm9ybWF0ICksXG5cdFx0XHRcdFx0XHRcdHN0ZW5jaWxCdWZmZXI6IGF0dHJpYnV0ZXMuc3RlbmNpbCxcblx0XHRcdFx0XHRcdFx0Y29sb3JTcGFjZTogcmVuZGVyZXIub3V0cHV0Q29sb3JTcGFjZSxcblx0XHRcdFx0XHRcdFx0c2FtcGxlczogYXR0cmlidXRlcy5hbnRpYWxpYXMgPyA0IDogMCxcblx0XHRcdFx0XHRcdFx0cmVzb2x2ZURlcHRoQnVmZmVyOiAoIGdsUHJvakxheWVyLmlnbm9yZURlcHRoVmFsdWVzID09PSBmYWxzZSApXG5cdFx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdG5ld1JlbmRlclRhcmdldC5pc1hSUmVuZGVyVGFyZ2V0ID0gdHJ1ZTsgLy8gVE9ETyBSZW1vdmUgdGhpcyB3aGVuIHBvc3NpYmxlLCBzZWUgIzIzMjc4XG5cblx0XHRcdFx0dGhpcy5zZXRGb3ZlYXRpb24oIGZvdmVhdGlvbiApO1xuXG5cdFx0XHRcdGN1c3RvbVJlZmVyZW5jZVNwYWNlID0gbnVsbDtcblx0XHRcdFx0cmVmZXJlbmNlU3BhY2UgPSBhd2FpdCBzZXNzaW9uLnJlcXVlc3RSZWZlcmVuY2VTcGFjZSggcmVmZXJlbmNlU3BhY2VUeXBlICk7XG5cblx0XHRcdFx0YW5pbWF0aW9uLnNldENvbnRleHQoIHNlc3Npb24gKTtcblx0XHRcdFx0YW5pbWF0aW9uLnN0YXJ0KCk7XG5cblx0XHRcdFx0c2NvcGUuaXNQcmVzZW50aW5nID0gdHJ1ZTtcblxuXHRcdFx0XHRzY29wZS5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdzZXNzaW9uc3RhcnQnIH0gKTtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0RW52aXJvbm1lbnRCbGVuZE1vZGUgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdGlmICggc2Vzc2lvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRyZXR1cm4gc2Vzc2lvbi5lbnZpcm9ubWVudEJsZW5kTW9kZTtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0RGVwdGhUZXh0dXJlID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gZGVwdGhTZW5zaW5nLmdldERlcHRoVGV4dHVyZSgpO1xuXG5cdFx0fTtcblxuXHRcdGZ1bmN0aW9uIG9uSW5wdXRTb3VyY2VzQ2hhbmdlKCBldmVudCApIHtcblxuXHRcdFx0Ly8gTm90aWZ5IGRpc2Nvbm5lY3RlZFxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBldmVudC5yZW1vdmVkLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbnB1dFNvdXJjZSA9IGV2ZW50LnJlbW92ZWRbIGkgXTtcblx0XHRcdFx0Y29uc3QgaW5kZXggPSBjb250cm9sbGVySW5wdXRTb3VyY2VzLmluZGV4T2YoIGlucHV0U291cmNlICk7XG5cblx0XHRcdFx0aWYgKCBpbmRleCA+PSAwICkge1xuXG5cdFx0XHRcdFx0Y29udHJvbGxlcklucHV0U291cmNlc1sgaW5kZXggXSA9IG51bGw7XG5cdFx0XHRcdFx0Y29udHJvbGxlcnNbIGluZGV4IF0uZGlzY29ubmVjdCggaW5wdXRTb3VyY2UgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gTm90aWZ5IGNvbm5lY3RlZFxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBldmVudC5hZGRlZC5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgaW5wdXRTb3VyY2UgPSBldmVudC5hZGRlZFsgaSBdO1xuXG5cdFx0XHRcdGxldCBjb250cm9sbGVySW5kZXggPSBjb250cm9sbGVySW5wdXRTb3VyY2VzLmluZGV4T2YoIGlucHV0U291cmNlICk7XG5cblx0XHRcdFx0aWYgKCBjb250cm9sbGVySW5kZXggPT09IC0gMSApIHtcblxuXHRcdFx0XHRcdC8vIEFzc2lnbiBpbnB1dCBzb3VyY2UgYSBjb250cm9sbGVyIHRoYXQgY3VycmVudGx5IGhhcyBubyBpbnB1dCBzb3VyY2VcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvbnRyb2xsZXJzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0aWYgKCBpID49IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXMubGVuZ3RoICkge1xuXG5cdFx0XHRcdFx0XHRcdGNvbnRyb2xsZXJJbnB1dFNvdXJjZXMucHVzaCggaW5wdXRTb3VyY2UgKTtcblx0XHRcdFx0XHRcdFx0Y29udHJvbGxlckluZGV4ID0gaTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIGNvbnRyb2xsZXJJbnB1dFNvdXJjZXNbIGkgXSA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdFx0XHRjb250cm9sbGVySW5wdXRTb3VyY2VzWyBpIF0gPSBpbnB1dFNvdXJjZTtcblx0XHRcdFx0XHRcdFx0Y29udHJvbGxlckluZGV4ID0gaTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIElmIGFsbCBjb250cm9sbGVycyBkbyBjdXJyZW50bHkgcmVjZWl2ZSBpbnB1dCB3ZSBpZ25vcmUgbmV3IG9uZXNcblxuXHRcdFx0XHRcdGlmICggY29udHJvbGxlckluZGV4ID09PSAtIDEgKSBicmVhaztcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Y29uc3QgY29udHJvbGxlciA9IGNvbnRyb2xsZXJzWyBjb250cm9sbGVySW5kZXggXTtcblxuXHRcdFx0XHRpZiAoIGNvbnRyb2xsZXIgKSB7XG5cblx0XHRcdFx0XHRjb250cm9sbGVyLmNvbm5lY3QoIGlucHV0U291cmNlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvL1xuXG5cdFx0Y29uc3QgY2FtZXJhTFBvcyA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0Y29uc3QgY2FtZXJhUlBvcyA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHQvKipcblx0XHQgKiBBc3N1bWVzIDIgY2FtZXJhcyB0aGF0IGFyZSBwYXJhbGxlbCBhbmQgc2hhcmUgYW4gWC1heGlzLCBhbmQgdGhhdFxuXHRcdCAqIHRoZSBjYW1lcmFzJyBwcm9qZWN0aW9uIGFuZCB3b3JsZCBtYXRyaWNlcyBoYXZlIGFscmVhZHkgYmVlbiBzZXQuXG5cdFx0ICogQW5kIHRoYXQgbmVhciBhbmQgZmFyIHBsYW5lcyBhcmUgaWRlbnRpY2FsIGZvciBib3RoIGNhbWVyYXMuXG5cdFx0ICogVmlzdWFsaXphdGlvbiBvZiB0aGlzIHRlY2huaXF1ZTogaHR0cHM6Ly9jb21wdXRlcmdyYXBoaWNzLnN0YWNrZXhjaGFuZ2UuY29tL2EvNDc2NVxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIHNldFByb2plY3Rpb25Gcm9tVW5pb24oIGNhbWVyYSwgY2FtZXJhTCwgY2FtZXJhUiApIHtcblxuXHRcdFx0Y2FtZXJhTFBvcy5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGNhbWVyYUwubWF0cml4V29ybGQgKTtcblx0XHRcdGNhbWVyYVJQb3Muc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBjYW1lcmFSLm1hdHJpeFdvcmxkICk7XG5cblx0XHRcdGNvbnN0IGlwZCA9IGNhbWVyYUxQb3MuZGlzdGFuY2VUbyggY2FtZXJhUlBvcyApO1xuXG5cdFx0XHRjb25zdCBwcm9qTCA9IGNhbWVyYUwucHJvamVjdGlvbk1hdHJpeC5lbGVtZW50cztcblx0XHRcdGNvbnN0IHByb2pSID0gY2FtZXJhUi5wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzO1xuXG5cdFx0XHQvLyBWUiBzeXN0ZW1zIHdpbGwgaGF2ZSBpZGVudGljYWwgZmFyIGFuZCBuZWFyIHBsYW5lcywgYW5kXG5cdFx0XHQvLyBtb3N0IGxpa2VseSBpZGVudGljYWwgdG9wIGFuZCBib3R0b20gZnJ1c3R1bSBleHRlbnRzLlxuXHRcdFx0Ly8gVXNlIHRoZSBsZWZ0IGNhbWVyYSBmb3IgdGhlc2UgdmFsdWVzLlxuXHRcdFx0Y29uc3QgbmVhciA9IHByb2pMWyAxNCBdIC8gKCBwcm9qTFsgMTAgXSAtIDEgKTtcblx0XHRcdGNvbnN0IGZhciA9IHByb2pMWyAxNCBdIC8gKCBwcm9qTFsgMTAgXSArIDEgKTtcblx0XHRcdGNvbnN0IHRvcEZvdiA9ICggcHJvakxbIDkgXSArIDEgKSAvIHByb2pMWyA1IF07XG5cdFx0XHRjb25zdCBib3R0b21Gb3YgPSAoIHByb2pMWyA5IF0gLSAxICkgLyBwcm9qTFsgNSBdO1xuXG5cdFx0XHRjb25zdCBsZWZ0Rm92ID0gKCBwcm9qTFsgOCBdIC0gMSApIC8gcHJvakxbIDAgXTtcblx0XHRcdGNvbnN0IHJpZ2h0Rm92ID0gKCBwcm9qUlsgOCBdICsgMSApIC8gcHJvalJbIDAgXTtcblx0XHRcdGNvbnN0IGxlZnQgPSBuZWFyICogbGVmdEZvdjtcblx0XHRcdGNvbnN0IHJpZ2h0ID0gbmVhciAqIHJpZ2h0Rm92O1xuXG5cdFx0XHQvLyBDYWxjdWxhdGUgdGhlIG5ldyBjYW1lcmEncyBwb3NpdGlvbiBvZmZzZXQgZnJvbSB0aGVcblx0XHRcdC8vIGxlZnQgY2FtZXJhLiB4T2Zmc2V0IHNob3VsZCBiZSByb3VnaGx5IGhhbGYgYGlwZGAuXG5cdFx0XHRjb25zdCB6T2Zmc2V0ID0gaXBkIC8gKCAtIGxlZnRGb3YgKyByaWdodEZvdiApO1xuXHRcdFx0Y29uc3QgeE9mZnNldCA9IHpPZmZzZXQgKiAtIGxlZnRGb3Y7XG5cblx0XHRcdC8vIFRPRE86IEJldHRlciB3YXkgdG8gYXBwbHkgdGhpcyBvZmZzZXQ/XG5cdFx0XHRjYW1lcmFMLm1hdHJpeFdvcmxkLmRlY29tcG9zZSggY2FtZXJhLnBvc2l0aW9uLCBjYW1lcmEucXVhdGVybmlvbiwgY2FtZXJhLnNjYWxlICk7XG5cdFx0XHRjYW1lcmEudHJhbnNsYXRlWCggeE9mZnNldCApO1xuXHRcdFx0Y2FtZXJhLnRyYW5zbGF0ZVooIHpPZmZzZXQgKTtcblx0XHRcdGNhbWVyYS5tYXRyaXhXb3JsZC5jb21wb3NlKCBjYW1lcmEucG9zaXRpb24sIGNhbWVyYS5xdWF0ZXJuaW9uLCBjYW1lcmEuc2NhbGUgKTtcblx0XHRcdGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UuY29weSggY2FtZXJhLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cblx0XHRcdC8vIEZpbmQgdGhlIHVuaW9uIG9mIHRoZSBmcnVzdHVtIHZhbHVlcyBvZiB0aGUgY2FtZXJhcyBhbmQgc2NhbGVcblx0XHRcdC8vIHRoZSB2YWx1ZXMgc28gdGhhdCB0aGUgbmVhciBwbGFuZSdzIHBvc2l0aW9uIGRvZXMgbm90IGNoYW5nZSBpbiB3b3JsZCBzcGFjZSxcblx0XHRcdC8vIGFsdGhvdWdoIG11c3Qgbm93IGJlIHJlbGF0aXZlIHRvIHRoZSBuZXcgdW5pb24gY2FtZXJhLlxuXHRcdFx0Y29uc3QgbmVhcjIgPSBuZWFyICsgek9mZnNldDtcblx0XHRcdGNvbnN0IGZhcjIgPSBmYXIgKyB6T2Zmc2V0O1xuXHRcdFx0Y29uc3QgbGVmdDIgPSBsZWZ0IC0geE9mZnNldDtcblx0XHRcdGNvbnN0IHJpZ2h0MiA9IHJpZ2h0ICsgKCBpcGQgLSB4T2Zmc2V0ICk7XG5cdFx0XHRjb25zdCB0b3AyID0gdG9wRm92ICogZmFyIC8gZmFyMiAqIG5lYXIyO1xuXHRcdFx0Y29uc3QgYm90dG9tMiA9IGJvdHRvbUZvdiAqIGZhciAvIGZhcjIgKiBuZWFyMjtcblxuXHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXgubWFrZVBlcnNwZWN0aXZlKCBsZWZ0MiwgcmlnaHQyLCB0b3AyLCBib3R0b20yLCBuZWFyMiwgZmFyMiApO1xuXHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlLmNvcHkoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4ICkuaW52ZXJ0KCk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiB1cGRhdGVDYW1lcmEoIGNhbWVyYSwgcGFyZW50ICkge1xuXG5cdFx0XHRpZiAoIHBhcmVudCA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRjYW1lcmEubWF0cml4V29ybGQuY29weSggY2FtZXJhLm1hdHJpeCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNhbWVyYS5tYXRyaXhXb3JsZC5tdWx0aXBseU1hdHJpY2VzKCBwYXJlbnQubWF0cml4V29ybGQsIGNhbWVyYS5tYXRyaXggKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlLmNvcHkoIGNhbWVyYS5tYXRyaXhXb3JsZCApLmludmVydCgpO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy51cGRhdGVDYW1lcmEgPSBmdW5jdGlvbiAoIGNhbWVyYSApIHtcblxuXHRcdFx0aWYgKCBzZXNzaW9uID09PSBudWxsICkgcmV0dXJuO1xuXG5cdFx0XHRpZiAoIGRlcHRoU2Vuc2luZy50ZXh0dXJlICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGNhbWVyYS5uZWFyID0gZGVwdGhTZW5zaW5nLmRlcHRoTmVhcjtcblx0XHRcdFx0Y2FtZXJhLmZhciA9IGRlcHRoU2Vuc2luZy5kZXB0aEZhcjtcblxuXHRcdFx0fVxuXG5cdFx0XHRjYW1lcmFYUi5uZWFyID0gY2FtZXJhUi5uZWFyID0gY2FtZXJhTC5uZWFyID0gY2FtZXJhLm5lYXI7XG5cdFx0XHRjYW1lcmFYUi5mYXIgPSBjYW1lcmFSLmZhciA9IGNhbWVyYUwuZmFyID0gY2FtZXJhLmZhcjtcblxuXHRcdFx0aWYgKCBfY3VycmVudERlcHRoTmVhciAhPT0gY2FtZXJhWFIubmVhciB8fCBfY3VycmVudERlcHRoRmFyICE9PSBjYW1lcmFYUi5mYXIgKSB7XG5cblx0XHRcdFx0Ly8gTm90ZSB0aGF0IHRoZSBuZXcgcmVuZGVyU3RhdGUgd29uJ3QgYXBwbHkgdW50aWwgdGhlIG5leHQgZnJhbWUuIFNlZSAjMTgzMjBcblxuXHRcdFx0XHRzZXNzaW9uLnVwZGF0ZVJlbmRlclN0YXRlKCB7XG5cdFx0XHRcdFx0ZGVwdGhOZWFyOiBjYW1lcmFYUi5uZWFyLFxuXHRcdFx0XHRcdGRlcHRoRmFyOiBjYW1lcmFYUi5mYXJcblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdF9jdXJyZW50RGVwdGhOZWFyID0gY2FtZXJhWFIubmVhcjtcblx0XHRcdFx0X2N1cnJlbnREZXB0aEZhciA9IGNhbWVyYVhSLmZhcjtcblxuXHRcdFx0XHRjYW1lcmFMLm5lYXIgPSBfY3VycmVudERlcHRoTmVhcjtcblx0XHRcdFx0Y2FtZXJhTC5mYXIgPSBfY3VycmVudERlcHRoRmFyO1xuXHRcdFx0XHRjYW1lcmFSLm5lYXIgPSBfY3VycmVudERlcHRoTmVhcjtcblx0XHRcdFx0Y2FtZXJhUi5mYXIgPSBfY3VycmVudERlcHRoRmFyO1xuXG5cdFx0XHRcdGNhbWVyYUwudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXHRcdFx0XHRjYW1lcmFSLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblx0XHRcdFx0Y2FtZXJhLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBwYXJlbnQgPSBjYW1lcmEucGFyZW50O1xuXHRcdFx0Y29uc3QgY2FtZXJhcyA9IGNhbWVyYVhSLmNhbWVyYXM7XG5cblx0XHRcdHVwZGF0ZUNhbWVyYSggY2FtZXJhWFIsIHBhcmVudCApO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjYW1lcmFzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHR1cGRhdGVDYW1lcmEoIGNhbWVyYXNbIGkgXSwgcGFyZW50ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gdXBkYXRlIHByb2plY3Rpb24gbWF0cml4IGZvciBwcm9wZXIgdmlldyBmcnVzdHVtIGN1bGxpbmdcblxuXHRcdFx0aWYgKCBjYW1lcmFzLmxlbmd0aCA9PT0gMiApIHtcblxuXHRcdFx0XHRzZXRQcm9qZWN0aW9uRnJvbVVuaW9uKCBjYW1lcmFYUiwgY2FtZXJhTCwgY2FtZXJhUiApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIGFzc3VtZSBzaW5nbGUgY2FtZXJhIHNldHVwIChBUilcblxuXHRcdFx0XHRjYW1lcmFYUi5wcm9qZWN0aW9uTWF0cml4LmNvcHkoIGNhbWVyYUwucHJvamVjdGlvbk1hdHJpeCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIHVwZGF0ZSB1c2VyIGNhbWVyYSBhbmQgaXRzIGNoaWxkcmVuXG5cblx0XHRcdHVwZGF0ZVVzZXJDYW1lcmEoIGNhbWVyYSwgY2FtZXJhWFIsIHBhcmVudCApO1xuXG5cdFx0fTtcblxuXHRcdGZ1bmN0aW9uIHVwZGF0ZVVzZXJDYW1lcmEoIGNhbWVyYSwgY2FtZXJhWFIsIHBhcmVudCApIHtcblxuXHRcdFx0aWYgKCBwYXJlbnQgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0Y2FtZXJhLm1hdHJpeC5jb3B5KCBjYW1lcmFYUi5tYXRyaXhXb3JsZCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNhbWVyYS5tYXRyaXguY29weSggcGFyZW50Lm1hdHJpeFdvcmxkICk7XG5cdFx0XHRcdGNhbWVyYS5tYXRyaXguaW52ZXJ0KCk7XG5cdFx0XHRcdGNhbWVyYS5tYXRyaXgubXVsdGlwbHkoIGNhbWVyYVhSLm1hdHJpeFdvcmxkICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Y2FtZXJhLm1hdHJpeC5kZWNvbXBvc2UoIGNhbWVyYS5wb3NpdGlvbiwgY2FtZXJhLnF1YXRlcm5pb24sIGNhbWVyYS5zY2FsZSApO1xuXHRcdFx0Y2FtZXJhLnVwZGF0ZU1hdHJpeFdvcmxkKCB0cnVlICk7XG5cblx0XHRcdGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LmNvcHkoIGNhbWVyYVhSLnByb2plY3Rpb25NYXRyaXggKTtcblx0XHRcdGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZS5jb3B5KCBjYW1lcmFYUi5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZSApO1xuXG5cdFx0XHRpZiAoIGNhbWVyYS5pc1BlcnNwZWN0aXZlQ2FtZXJhICkge1xuXG5cdFx0XHRcdGNhbWVyYS5mb3YgPSBSQUQyREVHICogMiAqIE1hdGguYXRhbiggMSAvIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyA1IF0gKTtcblx0XHRcdFx0Y2FtZXJhLnpvb20gPSAxO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHR0aGlzLmdldENhbWVyYSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIGNhbWVyYVhSO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0Rm92ZWF0aW9uID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRpZiAoIGdsUHJvakxheWVyID09PSBudWxsICYmIGdsQmFzZUxheWVyID09PSBudWxsICkge1xuXG5cdFx0XHRcdHJldHVybiB1bmRlZmluZWQ7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGZvdmVhdGlvbjtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldEZvdmVhdGlvbiA9IGZ1bmN0aW9uICggdmFsdWUgKSB7XG5cblx0XHRcdC8vIDAgPSBubyBmb3ZlYXRpb24gPSBmdWxsIHJlc29sdXRpb25cblx0XHRcdC8vIDEgPSBtYXhpbXVtIGZvdmVhdGlvbiA9IHRoZSBlZGdlcyByZW5kZXIgYXQgbG93ZXIgcmVzb2x1dGlvblxuXG5cdFx0XHRmb3ZlYXRpb24gPSB2YWx1ZTtcblxuXHRcdFx0aWYgKCBnbFByb2pMYXllciAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRnbFByb2pMYXllci5maXhlZEZvdmVhdGlvbiA9IHZhbHVlO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggZ2xCYXNlTGF5ZXIgIT09IG51bGwgJiYgZ2xCYXNlTGF5ZXIuZml4ZWRGb3ZlYXRpb24gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRnbEJhc2VMYXllci5maXhlZEZvdmVhdGlvbiA9IHZhbHVlO1xuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5oYXNEZXB0aFNlbnNpbmcgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBkZXB0aFNlbnNpbmcudGV4dHVyZSAhPT0gbnVsbDtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldERlcHRoU2Vuc2luZ01lc2ggPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBkZXB0aFNlbnNpbmcuZ2V0TWVzaCggY2FtZXJhWFIgKTtcblxuXHRcdH07XG5cblx0XHQvLyBBbmltYXRpb24gTG9vcFxuXG5cdFx0bGV0IG9uQW5pbWF0aW9uRnJhbWVDYWxsYmFjayA9IG51bGw7XG5cblx0XHRmdW5jdGlvbiBvbkFuaW1hdGlvbkZyYW1lKCB0aW1lLCBmcmFtZSApIHtcblxuXHRcdFx0cG9zZSA9IGZyYW1lLmdldFZpZXdlclBvc2UoIGN1c3RvbVJlZmVyZW5jZVNwYWNlIHx8IHJlZmVyZW5jZVNwYWNlICk7XG5cdFx0XHR4ckZyYW1lID0gZnJhbWU7XG5cblx0XHRcdGlmICggcG9zZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRjb25zdCB2aWV3cyA9IHBvc2Uudmlld3M7XG5cblx0XHRcdFx0aWYgKCBnbEJhc2VMYXllciAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldEZyYW1lYnVmZmVyKCBuZXdSZW5kZXJUYXJnZXQsIGdsQmFzZUxheWVyLmZyYW1lYnVmZmVyICk7XG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCBuZXdSZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0bGV0IGNhbWVyYVhSTmVlZHNVcGRhdGUgPSBmYWxzZTtcblxuXHRcdFx0XHQvLyBjaGVjayBpZiBpdCdzIG5lY2Vzc2FyeSB0byByZWJ1aWxkIGNhbWVyYVhSJ3MgY2FtZXJhIGxpc3RcblxuXHRcdFx0XHRpZiAoIHZpZXdzLmxlbmd0aCAhPT0gY2FtZXJhWFIuY2FtZXJhcy5sZW5ndGggKSB7XG5cblx0XHRcdFx0XHRjYW1lcmFYUi5jYW1lcmFzLmxlbmd0aCA9IDA7XG5cdFx0XHRcdFx0Y2FtZXJhWFJOZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHZpZXdzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IHZpZXcgPSB2aWV3c1sgaSBdO1xuXG5cdFx0XHRcdFx0bGV0IHZpZXdwb3J0ID0gbnVsbDtcblxuXHRcdFx0XHRcdGlmICggZ2xCYXNlTGF5ZXIgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRcdHZpZXdwb3J0ID0gZ2xCYXNlTGF5ZXIuZ2V0Vmlld3BvcnQoIHZpZXcgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGdsU3ViSW1hZ2UgPSBnbEJpbmRpbmcuZ2V0Vmlld1N1YkltYWdlKCBnbFByb2pMYXllciwgdmlldyApO1xuXHRcdFx0XHRcdFx0dmlld3BvcnQgPSBnbFN1YkltYWdlLnZpZXdwb3J0O1xuXG5cdFx0XHRcdFx0XHQvLyBGb3Igc2lkZS1ieS1zaWRlIHByb2plY3Rpb24sIHdlIG9ubHkgcHJvZHVjZSBhIHNpbmdsZSB0ZXh0dXJlIGZvciBib3RoIGV5ZXMuXG5cdFx0XHRcdFx0XHRpZiAoIGkgPT09IDAgKSB7XG5cblx0XHRcdFx0XHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0VGV4dHVyZXMoXG5cdFx0XHRcdFx0XHRcdFx0bmV3UmVuZGVyVGFyZ2V0LFxuXHRcdFx0XHRcdFx0XHRcdGdsU3ViSW1hZ2UuY29sb3JUZXh0dXJlLFxuXHRcdFx0XHRcdFx0XHRcdGdsUHJvakxheWVyLmlnbm9yZURlcHRoVmFsdWVzID8gdW5kZWZpbmVkIDogZ2xTdWJJbWFnZS5kZXB0aFN0ZW5jaWxUZXh0dXJlICk7XG5cblx0XHRcdFx0XHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCBuZXdSZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0bGV0IGNhbWVyYSA9IGNhbWVyYXNbIGkgXTtcblxuXHRcdFx0XHRcdGlmICggY2FtZXJhID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRcdGNhbWVyYSA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSgpO1xuXHRcdFx0XHRcdFx0Y2FtZXJhLmxheWVycy5lbmFibGUoIGkgKTtcblx0XHRcdFx0XHRcdGNhbWVyYS52aWV3cG9ydCA9IG5ldyBWZWN0b3I0KCk7XG5cdFx0XHRcdFx0XHRjYW1lcmFzWyBpIF0gPSBjYW1lcmE7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRjYW1lcmEubWF0cml4LmZyb21BcnJheSggdmlldy50cmFuc2Zvcm0ubWF0cml4ICk7XG5cdFx0XHRcdFx0Y2FtZXJhLm1hdHJpeC5kZWNvbXBvc2UoIGNhbWVyYS5wb3NpdGlvbiwgY2FtZXJhLnF1YXRlcm5pb24sIGNhbWVyYS5zY2FsZSApO1xuXHRcdFx0XHRcdGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LmZyb21BcnJheSggdmlldy5wcm9qZWN0aW9uTWF0cml4ICk7XG5cdFx0XHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlLmNvcHkoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4ICkuaW52ZXJ0KCk7XG5cdFx0XHRcdFx0Y2FtZXJhLnZpZXdwb3J0LnNldCggdmlld3BvcnQueCwgdmlld3BvcnQueSwgdmlld3BvcnQud2lkdGgsIHZpZXdwb3J0LmhlaWdodCApO1xuXG5cdFx0XHRcdFx0aWYgKCBpID09PSAwICkge1xuXG5cdFx0XHRcdFx0XHRjYW1lcmFYUi5tYXRyaXguY29weSggY2FtZXJhLm1hdHJpeCApO1xuXHRcdFx0XHRcdFx0Y2FtZXJhWFIubWF0cml4LmRlY29tcG9zZSggY2FtZXJhWFIucG9zaXRpb24sIGNhbWVyYVhSLnF1YXRlcm5pb24sIGNhbWVyYVhSLnNjYWxlICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoIGNhbWVyYVhSTmVlZHNVcGRhdGUgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRcdGNhbWVyYVhSLmNhbWVyYXMucHVzaCggY2FtZXJhICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vXG5cblx0XHRcdFx0Y29uc3QgZW5hYmxlZEZlYXR1cmVzID0gc2Vzc2lvbi5lbmFibGVkRmVhdHVyZXM7XG5cblx0XHRcdFx0aWYgKCBlbmFibGVkRmVhdHVyZXMgJiYgZW5hYmxlZEZlYXR1cmVzLmluY2x1ZGVzKCAnZGVwdGgtc2Vuc2luZycgKSApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGRlcHRoRGF0YSA9IGdsQmluZGluZy5nZXREZXB0aEluZm9ybWF0aW9uKCB2aWV3c1sgMCBdICk7XG5cblx0XHRcdFx0XHRpZiAoIGRlcHRoRGF0YSAmJiBkZXB0aERhdGEuaXNWYWxpZCAmJiBkZXB0aERhdGEudGV4dHVyZSApIHtcblxuXHRcdFx0XHRcdFx0ZGVwdGhTZW5zaW5nLmluaXQoIHJlbmRlcmVyLCBkZXB0aERhdGEsIHNlc3Npb24ucmVuZGVyU3RhdGUgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9cblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY29udHJvbGxlcnMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGlucHV0U291cmNlID0gY29udHJvbGxlcklucHV0U291cmNlc1sgaSBdO1xuXHRcdFx0XHRjb25zdCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGkgXTtcblxuXHRcdFx0XHRpZiAoIGlucHV0U291cmNlICE9PSBudWxsICYmIGNvbnRyb2xsZXIgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGNvbnRyb2xsZXIudXBkYXRlKCBpbnB1dFNvdXJjZSwgZnJhbWUsIGN1c3RvbVJlZmVyZW5jZVNwYWNlIHx8IHJlZmVyZW5jZVNwYWNlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggb25BbmltYXRpb25GcmFtZUNhbGxiYWNrICkgb25BbmltYXRpb25GcmFtZUNhbGxiYWNrKCB0aW1lLCBmcmFtZSApO1xuXG5cdFx0XHRpZiAoIGZyYW1lLmRldGVjdGVkUGxhbmVzICkge1xuXG5cdFx0XHRcdHNjb3BlLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogJ3BsYW5lc2RldGVjdGVkJywgZGF0YTogZnJhbWUgfSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHhyRnJhbWUgPSBudWxsO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgYW5pbWF0aW9uID0gbmV3IFdlYkdMQW5pbWF0aW9uKCk7XG5cblx0XHRhbmltYXRpb24uc2V0QW5pbWF0aW9uTG9vcCggb25BbmltYXRpb25GcmFtZSApO1xuXG5cdFx0dGhpcy5zZXRBbmltYXRpb25Mb29wID0gZnVuY3Rpb24gKCBjYWxsYmFjayApIHtcblxuXHRcdFx0b25BbmltYXRpb25GcmFtZUNhbGxiYWNrID0gY2FsbGJhY2s7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5kaXNwb3NlID0gZnVuY3Rpb24gKCkge307XG5cblx0fVxuXG59XG5cbmNvbnN0IF9lMSA9IC8qQF9fUFVSRV9fKi8gbmV3IEV1bGVyKCk7XG5jb25zdCBfbTEgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5cbmZ1bmN0aW9uIFdlYkdMTWF0ZXJpYWxzKCByZW5kZXJlciwgcHJvcGVydGllcyApIHtcblxuXHRmdW5jdGlvbiByZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWFwLCB1bmlmb3JtICkge1xuXG5cdFx0aWYgKCBtYXAubWF0cml4QXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0bWFwLnVwZGF0ZU1hdHJpeCgpO1xuXG5cdFx0fVxuXG5cdFx0dW5pZm9ybS52YWx1ZS5jb3B5KCBtYXAubWF0cml4ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hGb2dVbmlmb3JtcyggdW5pZm9ybXMsIGZvZyApIHtcblxuXHRcdGZvZy5jb2xvci5nZXRSR0IoIHVuaWZvcm1zLmZvZ0NvbG9yLnZhbHVlLCBnZXRVbmxpdFVuaWZvcm1Db2xvclNwYWNlKCByZW5kZXJlciApICk7XG5cblx0XHRpZiAoIGZvZy5pc0ZvZyApIHtcblxuXHRcdFx0dW5pZm9ybXMuZm9nTmVhci52YWx1ZSA9IGZvZy5uZWFyO1xuXHRcdFx0dW5pZm9ybXMuZm9nRmFyLnZhbHVlID0gZm9nLmZhcjtcblxuXHRcdH0gZWxzZSBpZiAoIGZvZy5pc0ZvZ0V4cDIgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmZvZ0RlbnNpdHkudmFsdWUgPSBmb2cuZGVuc2l0eTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaE1hdGVyaWFsVW5pZm9ybXMoIHVuaWZvcm1zLCBtYXRlcmlhbCwgcGl4ZWxSYXRpbywgaGVpZ2h0LCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaEJhc2ljTWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hMYW1iZXJ0TWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hUb29uTWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNUb29uKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcblxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmlzTWVzaFBob25nTWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNQaG9uZyggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsICkge1xuXG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNDb21tb24oIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xuXHRcdFx0cmVmcmVzaFVuaWZvcm1zU3RhbmRhcmQoIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaFBoeXNpY2FsTWF0ZXJpYWwgKSB7XG5cblx0XHRcdFx0cmVmcmVzaFVuaWZvcm1zUGh5c2ljYWwoIHVuaWZvcm1zLCBtYXRlcmlhbCwgdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmlzTWVzaE1hdGNhcE1hdGVyaWFsICkge1xuXG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNDb21tb24oIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xuXHRcdFx0cmVmcmVzaFVuaWZvcm1zTWF0Y2FwKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcblxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmlzTWVzaERlcHRoTWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hEaXN0YW5jZU1hdGVyaWFsICkge1xuXG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNDb21tb24oIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xuXHRcdFx0cmVmcmVzaFVuaWZvcm1zRGlzdGFuY2UoIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xuXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNNZXNoTm9ybWFsTWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc0xpbmVCYXNpY01hdGVyaWFsICkge1xuXG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNMaW5lKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcblxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pc0xpbmVEYXNoZWRNYXRlcmlhbCApIHtcblxuXHRcdFx0XHRyZWZyZXNoVW5pZm9ybXNEYXNoKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNQb2ludHNNYXRlcmlhbCApIHtcblxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zUG9pbnRzKCB1bmlmb3JtcywgbWF0ZXJpYWwsIHBpeGVsUmF0aW8sIGhlaWdodCApO1xuXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNTcHJpdGVNYXRlcmlhbCApIHtcblxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zU3ByaXRlcyggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc1NoYWRvd01hdGVyaWFsICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5jb2xvci52YWx1ZS5jb3B5KCBtYXRlcmlhbC5jb2xvciApO1xuXHRcdFx0dW5pZm9ybXMub3BhY2l0eS52YWx1ZSA9IG1hdGVyaWFsLm9wYWNpdHk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc1NoYWRlck1hdGVyaWFsICkge1xuXG5cdFx0XHRtYXRlcmlhbC51bmlmb3Jtc05lZWRVcGRhdGUgPSBmYWxzZTsgLy8gIzE1NTgxXG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xuXG5cdFx0dW5pZm9ybXMub3BhY2l0eS52YWx1ZSA9IG1hdGVyaWFsLm9wYWNpdHk7XG5cblx0XHRpZiAoIG1hdGVyaWFsLmNvbG9yICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5kaWZmdXNlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLmNvbG9yICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmVtaXNzaXZlICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5lbWlzc2l2ZS52YWx1ZS5jb3B5KCBtYXRlcmlhbC5lbWlzc2l2ZSApLm11bHRpcGx5U2NhbGFyKCBtYXRlcmlhbC5lbWlzc2l2ZUludGVuc2l0eSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5tYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLm1hcC52YWx1ZSA9IG1hdGVyaWFsLm1hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1hcCwgdW5pZm9ybXMubWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmFscGhhTWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5hbHBoYU1hcC52YWx1ZSA9IG1hdGVyaWFsLmFscGhhTWFwO1xuXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuYWxwaGFNYXAsIHVuaWZvcm1zLmFscGhhTWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmJ1bXBNYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmJ1bXBNYXAudmFsdWUgPSBtYXRlcmlhbC5idW1wTWFwO1xuXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuYnVtcE1hcCwgdW5pZm9ybXMuYnVtcE1hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR1bmlmb3Jtcy5idW1wU2NhbGUudmFsdWUgPSBtYXRlcmlhbC5idW1wU2NhbGU7XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuc2lkZSA9PT0gQmFja1NpZGUgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMuYnVtcFNjYWxlLnZhbHVlICo9IC0gMTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5ub3JtYWxNYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLm5vcm1hbE1hcC52YWx1ZSA9IG1hdGVyaWFsLm5vcm1hbE1hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm5vcm1hbE1hcCwgdW5pZm9ybXMubm9ybWFsTWFwVHJhbnNmb3JtICk7XG5cblx0XHRcdHVuaWZvcm1zLm5vcm1hbFNjYWxlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLm5vcm1hbFNjYWxlICk7XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuc2lkZSA9PT0gQmFja1NpZGUgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMubm9ybWFsU2NhbGUudmFsdWUubmVnYXRlKCk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwuZGlzcGxhY2VtZW50TWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWUgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXA7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXAsIHVuaWZvcm1zLmRpc3BsYWNlbWVudE1hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR1bmlmb3Jtcy5kaXNwbGFjZW1lbnRTY2FsZS52YWx1ZSA9IG1hdGVyaWFsLmRpc3BsYWNlbWVudFNjYWxlO1xuXHRcdFx0dW5pZm9ybXMuZGlzcGxhY2VtZW50Qmlhcy52YWx1ZSA9IG1hdGVyaWFsLmRpc3BsYWNlbWVudEJpYXM7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmVtaXNzaXZlTWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5lbWlzc2l2ZU1hcC52YWx1ZSA9IG1hdGVyaWFsLmVtaXNzaXZlTWFwO1xuXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuZW1pc3NpdmVNYXAsIHVuaWZvcm1zLmVtaXNzaXZlTWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLnNwZWN1bGFyTWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5zcGVjdWxhck1hcC52YWx1ZSA9IG1hdGVyaWFsLnNwZWN1bGFyTWFwO1xuXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc3BlY3VsYXJNYXAsIHVuaWZvcm1zLnNwZWN1bGFyTWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmFscGhhVGVzdCA+IDAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmFscGhhVGVzdC52YWx1ZSA9IG1hdGVyaWFsLmFscGhhVGVzdDtcblxuXHRcdH1cblxuXHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xuXG5cdFx0Y29uc3QgZW52TWFwID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLmVudk1hcDtcblx0XHRjb25zdCBlbnZNYXBSb3RhdGlvbiA9IG1hdGVyaWFsUHJvcGVydGllcy5lbnZNYXBSb3RhdGlvbjtcblxuXHRcdGlmICggZW52TWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5lbnZNYXAudmFsdWUgPSBlbnZNYXA7XG5cblx0XHRcdF9lMS5jb3B5KCBlbnZNYXBSb3RhdGlvbiApO1xuXG5cdFx0XHQvLyBhY2NvbW1vZGF0ZSBsZWZ0LWhhbmRlZCBmcmFtZVxuXHRcdFx0X2UxLnggKj0gLSAxOyBfZTEueSAqPSAtIDE7IF9lMS56ICo9IC0gMTtcblxuXHRcdFx0aWYgKCBlbnZNYXAuaXNDdWJlVGV4dHVyZSAmJiBlbnZNYXAuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHQvLyBlbnZpcm9ubWVudCBtYXBzIHdoaWNoIGFyZSBub3QgY3ViZSByZW5kZXIgdGFyZ2V0cyBvciBQTVJFTXMgZm9sbG93IGEgZGlmZmVyZW50IGNvbnZlbnRpb25cblx0XHRcdFx0X2UxLnkgKj0gLSAxO1xuXHRcdFx0XHRfZTEueiAqPSAtIDE7XG5cblx0XHRcdH1cblxuXHRcdFx0dW5pZm9ybXMuZW52TWFwUm90YXRpb24udmFsdWUuc2V0RnJvbU1hdHJpeDQoIF9tMS5tYWtlUm90YXRpb25Gcm9tRXVsZXIoIF9lMSApICk7XG5cblx0XHRcdHVuaWZvcm1zLmZsaXBFbnZNYXAudmFsdWUgPSAoIGVudk1hcC5pc0N1YmVUZXh0dXJlICYmIGVudk1hcC5pc1JlbmRlclRhcmdldFRleHR1cmUgPT09IGZhbHNlICkgPyAtIDEgOiAxO1xuXG5cdFx0XHR1bmlmb3Jtcy5yZWZsZWN0aXZpdHkudmFsdWUgPSBtYXRlcmlhbC5yZWZsZWN0aXZpdHk7XG5cdFx0XHR1bmlmb3Jtcy5pb3IudmFsdWUgPSBtYXRlcmlhbC5pb3I7XG5cdFx0XHR1bmlmb3Jtcy5yZWZyYWN0aW9uUmF0aW8udmFsdWUgPSBtYXRlcmlhbC5yZWZyYWN0aW9uUmF0aW87XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmxpZ2h0TWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5saWdodE1hcC52YWx1ZSA9IG1hdGVyaWFsLmxpZ2h0TWFwO1xuXHRcdFx0dW5pZm9ybXMubGlnaHRNYXBJbnRlbnNpdHkudmFsdWUgPSBtYXRlcmlhbC5saWdodE1hcEludGVuc2l0eTtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmxpZ2h0TWFwLCB1bmlmb3Jtcy5saWdodE1hcFRyYW5zZm9ybSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5hb01hcCApIHtcblxuXHRcdFx0dW5pZm9ybXMuYW9NYXAudmFsdWUgPSBtYXRlcmlhbC5hb01hcDtcblx0XHRcdHVuaWZvcm1zLmFvTWFwSW50ZW5zaXR5LnZhbHVlID0gbWF0ZXJpYWwuYW9NYXBJbnRlbnNpdHk7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5hb01hcCwgdW5pZm9ybXMuYW9NYXBUcmFuc2Zvcm0gKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zTGluZSggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xuXG5cdFx0dW5pZm9ybXMuZGlmZnVzZS52YWx1ZS5jb3B5KCBtYXRlcmlhbC5jb2xvciApO1xuXHRcdHVuaWZvcm1zLm9wYWNpdHkudmFsdWUgPSBtYXRlcmlhbC5vcGFjaXR5O1xuXG5cdFx0aWYgKCBtYXRlcmlhbC5tYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLm1hcC52YWx1ZSA9IG1hdGVyaWFsLm1hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1hcCwgdW5pZm9ybXMubWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc0Rhc2goIHVuaWZvcm1zLCBtYXRlcmlhbCApIHtcblxuXHRcdHVuaWZvcm1zLmRhc2hTaXplLnZhbHVlID0gbWF0ZXJpYWwuZGFzaFNpemU7XG5cdFx0dW5pZm9ybXMudG90YWxTaXplLnZhbHVlID0gbWF0ZXJpYWwuZGFzaFNpemUgKyBtYXRlcmlhbC5nYXBTaXplO1xuXHRcdHVuaWZvcm1zLnNjYWxlLnZhbHVlID0gbWF0ZXJpYWwuc2NhbGU7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc1BvaW50cyggdW5pZm9ybXMsIG1hdGVyaWFsLCBwaXhlbFJhdGlvLCBoZWlnaHQgKSB7XG5cblx0XHR1bmlmb3Jtcy5kaWZmdXNlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLmNvbG9yICk7XG5cdFx0dW5pZm9ybXMub3BhY2l0eS52YWx1ZSA9IG1hdGVyaWFsLm9wYWNpdHk7XG5cdFx0dW5pZm9ybXMuc2l6ZS52YWx1ZSA9IG1hdGVyaWFsLnNpemUgKiBwaXhlbFJhdGlvO1xuXHRcdHVuaWZvcm1zLnNjYWxlLnZhbHVlID0gaGVpZ2h0ICogMC41O1xuXG5cdFx0aWYgKCBtYXRlcmlhbC5tYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLm1hcC52YWx1ZSA9IG1hdGVyaWFsLm1hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1hcCwgdW5pZm9ybXMudXZUcmFuc2Zvcm0gKTtcblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwuYWxwaGFNYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmFscGhhTWFwLnZhbHVlID0gbWF0ZXJpYWwuYWxwaGFNYXA7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5hbHBoYU1hcCwgdW5pZm9ybXMuYWxwaGFNYXBUcmFuc2Zvcm0gKTtcblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwuYWxwaGFUZXN0ID4gMCApIHtcblxuXHRcdFx0dW5pZm9ybXMuYWxwaGFUZXN0LnZhbHVlID0gbWF0ZXJpYWwuYWxwaGFUZXN0O1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNTcHJpdGVzKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XG5cblx0XHR1bmlmb3Jtcy5kaWZmdXNlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLmNvbG9yICk7XG5cdFx0dW5pZm9ybXMub3BhY2l0eS52YWx1ZSA9IG1hdGVyaWFsLm9wYWNpdHk7XG5cdFx0dW5pZm9ybXMucm90YXRpb24udmFsdWUgPSBtYXRlcmlhbC5yb3RhdGlvbjtcblxuXHRcdGlmICggbWF0ZXJpYWwubWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5tYXAudmFsdWUgPSBtYXRlcmlhbC5tYXA7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5tYXAsIHVuaWZvcm1zLm1hcFRyYW5zZm9ybSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5hbHBoYU1hcCApIHtcblxuXHRcdFx0dW5pZm9ybXMuYWxwaGFNYXAudmFsdWUgPSBtYXRlcmlhbC5hbHBoYU1hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmFscGhhTWFwLCB1bmlmb3Jtcy5hbHBoYU1hcFRyYW5zZm9ybSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5hbHBoYVRlc3QgPiAwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5hbHBoYVRlc3QudmFsdWUgPSBtYXRlcmlhbC5hbHBoYVRlc3Q7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc1Bob25nKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XG5cblx0XHR1bmlmb3Jtcy5zcGVjdWxhci52YWx1ZS5jb3B5KCBtYXRlcmlhbC5zcGVjdWxhciApO1xuXHRcdHVuaWZvcm1zLnNoaW5pbmVzcy52YWx1ZSA9IE1hdGgubWF4KCBtYXRlcmlhbC5zaGluaW5lc3MsIDFlLTQgKTsgLy8gdG8gcHJldmVudCBwb3coIDAuMCwgMC4wIClcblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zVG9vbiggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xuXG5cdFx0aWYgKCBtYXRlcmlhbC5ncmFkaWVudE1hcCApIHtcblxuXHRcdFx0dW5pZm9ybXMuZ3JhZGllbnRNYXAudmFsdWUgPSBtYXRlcmlhbC5ncmFkaWVudE1hcDtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zU3RhbmRhcmQoIHVuaWZvcm1zLCBtYXRlcmlhbCApIHtcblxuXHRcdHVuaWZvcm1zLm1ldGFsbmVzcy52YWx1ZSA9IG1hdGVyaWFsLm1ldGFsbmVzcztcblxuXHRcdGlmICggbWF0ZXJpYWwubWV0YWxuZXNzTWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5tZXRhbG5lc3NNYXAudmFsdWUgPSBtYXRlcmlhbC5tZXRhbG5lc3NNYXA7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5tZXRhbG5lc3NNYXAsIHVuaWZvcm1zLm1ldGFsbmVzc01hcFRyYW5zZm9ybSApO1xuXG5cdFx0fVxuXG5cdFx0dW5pZm9ybXMucm91Z2huZXNzLnZhbHVlID0gbWF0ZXJpYWwucm91Z2huZXNzO1xuXG5cdFx0aWYgKCBtYXRlcmlhbC5yb3VnaG5lc3NNYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLnJvdWdobmVzc01hcC52YWx1ZSA9IG1hdGVyaWFsLnJvdWdobmVzc01hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLnJvdWdobmVzc01hcCwgdW5pZm9ybXMucm91Z2huZXNzTWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmVudk1hcCApIHtcblxuXHRcdFx0Ly91bmlmb3Jtcy5lbnZNYXAudmFsdWUgPSBtYXRlcmlhbC5lbnZNYXA7IC8vIHBhcnQgb2YgdW5pZm9ybXMgY29tbW9uXG5cblx0XHRcdHVuaWZvcm1zLmVudk1hcEludGVuc2l0eS52YWx1ZSA9IG1hdGVyaWFsLmVudk1hcEludGVuc2l0eTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zUGh5c2ljYWwoIHVuaWZvcm1zLCBtYXRlcmlhbCwgdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICkge1xuXG5cdFx0dW5pZm9ybXMuaW9yLnZhbHVlID0gbWF0ZXJpYWwuaW9yOyAvLyBhbHNvIHBhcnQgb2YgdW5pZm9ybXMgY29tbW9uXG5cblx0XHRpZiAoIG1hdGVyaWFsLnNoZWVuID4gMCApIHtcblxuXHRcdFx0dW5pZm9ybXMuc2hlZW5Db2xvci52YWx1ZS5jb3B5KCBtYXRlcmlhbC5zaGVlbkNvbG9yICkubXVsdGlwbHlTY2FsYXIoIG1hdGVyaWFsLnNoZWVuICk7XG5cblx0XHRcdHVuaWZvcm1zLnNoZWVuUm91Z2huZXNzLnZhbHVlID0gbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3M7XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuc2hlZW5Db2xvck1hcCApIHtcblxuXHRcdFx0XHR1bmlmb3Jtcy5zaGVlbkNvbG9yTWFwLnZhbHVlID0gbWF0ZXJpYWwuc2hlZW5Db2xvck1hcDtcblxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc2hlZW5Db2xvck1hcCwgdW5pZm9ybXMuc2hlZW5Db2xvck1hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3NNYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMuc2hlZW5Sb3VnaG5lc3NNYXAudmFsdWUgPSBtYXRlcmlhbC5zaGVlblJvdWdobmVzc01hcDtcblxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3NNYXAsIHVuaWZvcm1zLnNoZWVuUm91Z2huZXNzTWFwVHJhbnNmb3JtICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwuY2xlYXJjb2F0ID4gMCApIHtcblxuXHRcdFx0dW5pZm9ybXMuY2xlYXJjb2F0LnZhbHVlID0gbWF0ZXJpYWwuY2xlYXJjb2F0O1xuXHRcdFx0dW5pZm9ybXMuY2xlYXJjb2F0Um91Z2huZXNzLnZhbHVlID0gbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzO1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmNsZWFyY29hdE1hcCApIHtcblxuXHRcdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXRNYXAudmFsdWUgPSBtYXRlcmlhbC5jbGVhcmNvYXRNYXA7XG5cblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmNsZWFyY29hdE1hcCwgdW5pZm9ybXMuY2xlYXJjb2F0TWFwVHJhbnNmb3JtICk7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwLnZhbHVlID0gbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzTWFwO1xuXG5cdFx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3NNYXAsIHVuaWZvcm1zLmNsZWFyY29hdFJvdWdobmVzc01hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsTWFwICkge1xuXG5cdFx0XHRcdHVuaWZvcm1zLmNsZWFyY29hdE5vcm1hbE1hcC52YWx1ZSA9IG1hdGVyaWFsLmNsZWFyY29hdE5vcm1hbE1hcDtcblxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsTWFwLCB1bmlmb3Jtcy5jbGVhcmNvYXROb3JtYWxNYXBUcmFuc2Zvcm0gKTtcblxuXHRcdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXROb3JtYWxTY2FsZS52YWx1ZS5jb3B5KCBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxTY2FsZSApO1xuXG5cdFx0XHRcdGlmICggbWF0ZXJpYWwuc2lkZSA9PT0gQmFja1NpZGUgKSB7XG5cblx0XHRcdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXROb3JtYWxTY2FsZS52YWx1ZS5uZWdhdGUoKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwuZGlzcGVyc2lvbiA+IDAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmRpc3BlcnNpb24udmFsdWUgPSBtYXRlcmlhbC5kaXNwZXJzaW9uO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5pcmlkZXNjZW5jZSA+IDAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmlyaWRlc2NlbmNlLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2U7XG5cdFx0XHR1bmlmb3Jtcy5pcmlkZXNjZW5jZUlPUi52YWx1ZSA9IG1hdGVyaWFsLmlyaWRlc2NlbmNlSU9SO1xuXHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VUaGlja25lc3NNaW5pbXVtLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZVsgMCBdO1xuXHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXhpbXVtLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZVsgMSBdO1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlyaWRlc2NlbmNlTWFwICkge1xuXG5cdFx0XHRcdHVuaWZvcm1zLmlyaWRlc2NlbmNlTWFwLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2VNYXA7XG5cblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmlyaWRlc2NlbmNlTWFwLCB1bmlmb3Jtcy5pcmlkZXNjZW5jZU1hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAudmFsdWUgPSBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcDtcblxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAsIHVuaWZvcm1zLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVHJhbnNmb3JtICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwudHJhbnNtaXNzaW9uID4gMCApIHtcblxuXHRcdFx0dW5pZm9ybXMudHJhbnNtaXNzaW9uLnZhbHVlID0gbWF0ZXJpYWwudHJhbnNtaXNzaW9uO1xuXHRcdFx0dW5pZm9ybXMudHJhbnNtaXNzaW9uU2FtcGxlck1hcC52YWx1ZSA9IHRyYW5zbWlzc2lvblJlbmRlclRhcmdldC50ZXh0dXJlO1xuXHRcdFx0dW5pZm9ybXMudHJhbnNtaXNzaW9uU2FtcGxlclNpemUudmFsdWUuc2V0KCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQud2lkdGgsIHRyYW5zbWlzc2lvblJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0aWYgKCBtYXRlcmlhbC50cmFuc21pc3Npb25NYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMudHJhbnNtaXNzaW9uTWFwLnZhbHVlID0gbWF0ZXJpYWwudHJhbnNtaXNzaW9uTWFwO1xuXG5cdFx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC50cmFuc21pc3Npb25NYXAsIHVuaWZvcm1zLnRyYW5zbWlzc2lvbk1hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHVuaWZvcm1zLnRoaWNrbmVzcy52YWx1ZSA9IG1hdGVyaWFsLnRoaWNrbmVzcztcblxuXHRcdFx0aWYgKCBtYXRlcmlhbC50aGlja25lc3NNYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMudGhpY2tuZXNzTWFwLnZhbHVlID0gbWF0ZXJpYWwudGhpY2tuZXNzTWFwO1xuXG5cdFx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC50aGlja25lc3NNYXAsIHVuaWZvcm1zLnRoaWNrbmVzc01hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHVuaWZvcm1zLmF0dGVudWF0aW9uRGlzdGFuY2UudmFsdWUgPSBtYXRlcmlhbC5hdHRlbnVhdGlvbkRpc3RhbmNlO1xuXHRcdFx0dW5pZm9ybXMuYXR0ZW51YXRpb25Db2xvci52YWx1ZS5jb3B5KCBtYXRlcmlhbC5hdHRlbnVhdGlvbkNvbG9yICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmFuaXNvdHJvcHkgPiAwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5hbmlzb3Ryb3B5VmVjdG9yLnZhbHVlLnNldCggbWF0ZXJpYWwuYW5pc290cm9weSAqIE1hdGguY29zKCBtYXRlcmlhbC5hbmlzb3Ryb3B5Um90YXRpb24gKSwgbWF0ZXJpYWwuYW5pc290cm9weSAqIE1hdGguc2luKCBtYXRlcmlhbC5hbmlzb3Ryb3B5Um90YXRpb24gKSApO1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmFuaXNvdHJvcHlNYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMuYW5pc290cm9weU1hcC52YWx1ZSA9IG1hdGVyaWFsLmFuaXNvdHJvcHlNYXA7XG5cblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmFuaXNvdHJvcHlNYXAsIHVuaWZvcm1zLmFuaXNvdHJvcHlNYXBUcmFuc2Zvcm0gKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0dW5pZm9ybXMuc3BlY3VsYXJJbnRlbnNpdHkudmFsdWUgPSBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eTtcblx0XHR1bmlmb3Jtcy5zcGVjdWxhckNvbG9yLnZhbHVlLmNvcHkoIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgKTtcblxuXHRcdGlmICggbWF0ZXJpYWwuc3BlY3VsYXJDb2xvck1hcCApIHtcblxuXHRcdFx0dW5pZm9ybXMuc3BlY3VsYXJDb2xvck1hcC52YWx1ZSA9IG1hdGVyaWFsLnNwZWN1bGFyQ29sb3JNYXA7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5zcGVjdWxhckNvbG9yTWFwLCB1bmlmb3Jtcy5zcGVjdWxhckNvbG9yTWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLnNwZWN1bGFySW50ZW5zaXR5TWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5zcGVjdWxhckludGVuc2l0eU1hcC52YWx1ZSA9IG1hdGVyaWFsLnNwZWN1bGFySW50ZW5zaXR5TWFwO1xuXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc3BlY3VsYXJJbnRlbnNpdHlNYXAsIHVuaWZvcm1zLnNwZWN1bGFySW50ZW5zaXR5TWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc01hdGNhcCggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xuXG5cdFx0aWYgKCBtYXRlcmlhbC5tYXRjYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLm1hdGNhcC52YWx1ZSA9IG1hdGVyaWFsLm1hdGNhcDtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zRGlzdGFuY2UoIHVuaWZvcm1zLCBtYXRlcmlhbCApIHtcblxuXHRcdGNvbnN0IGxpZ2h0ID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICkubGlnaHQ7XG5cblx0XHR1bmlmb3Jtcy5yZWZlcmVuY2VQb3NpdGlvbi52YWx1ZS5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cdFx0dW5pZm9ybXMubmVhckRpc3RhbmNlLnZhbHVlID0gbGlnaHQuc2hhZG93LmNhbWVyYS5uZWFyO1xuXHRcdHVuaWZvcm1zLmZhckRpc3RhbmNlLnZhbHVlID0gbGlnaHQuc2hhZG93LmNhbWVyYS5mYXI7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0cmVmcmVzaEZvZ1VuaWZvcm1zOiByZWZyZXNoRm9nVW5pZm9ybXMsXG5cdFx0cmVmcmVzaE1hdGVyaWFsVW5pZm9ybXM6IHJlZnJlc2hNYXRlcmlhbFVuaWZvcm1zXG5cdH07XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xVbmlmb3Jtc0dyb3VwcyggZ2wsIGluZm8sIGNhcGFiaWxpdGllcywgc3RhdGUgKSB7XG5cblx0bGV0IGJ1ZmZlcnMgPSB7fTtcblx0bGV0IHVwZGF0ZUxpc3QgPSB7fTtcblx0bGV0IGFsbG9jYXRlZEJpbmRpbmdQb2ludHMgPSBbXTtcblxuXHRjb25zdCBtYXhCaW5kaW5nUG9pbnRzID0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfVU5JRk9STV9CVUZGRVJfQklORElOR1MgKTsgLy8gYmluZGluZyBwb2ludHMgYXJlIGdsb2JhbCB3aGVyZWFzIGJsb2NrIGluZGljZXMgYXJlIHBlciBzaGFkZXIgcHJvZ3JhbVxuXG5cdGZ1bmN0aW9uIGJpbmQoIHVuaWZvcm1zR3JvdXAsIHByb2dyYW0gKSB7XG5cblx0XHRjb25zdCB3ZWJnbFByb2dyYW0gPSBwcm9ncmFtLnByb2dyYW07XG5cdFx0c3RhdGUudW5pZm9ybUJsb2NrQmluZGluZyggdW5pZm9ybXNHcm91cCwgd2ViZ2xQcm9ncmFtICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHVwZGF0ZSggdW5pZm9ybXNHcm91cCwgcHJvZ3JhbSApIHtcblxuXHRcdGxldCBidWZmZXIgPSBidWZmZXJzWyB1bmlmb3Jtc0dyb3VwLmlkIF07XG5cblx0XHRpZiAoIGJ1ZmZlciA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRwcmVwYXJlVW5pZm9ybXNHcm91cCggdW5pZm9ybXNHcm91cCApO1xuXG5cdFx0XHRidWZmZXIgPSBjcmVhdGVCdWZmZXIoIHVuaWZvcm1zR3JvdXAgKTtcblx0XHRcdGJ1ZmZlcnNbIHVuaWZvcm1zR3JvdXAuaWQgXSA9IGJ1ZmZlcjtcblxuXHRcdFx0dW5pZm9ybXNHcm91cC5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVW5pZm9ybXNHcm91cHNEaXNwb3NlICk7XG5cblx0XHR9XG5cblx0XHQvLyBlbnN1cmUgdG8gdXBkYXRlIHRoZSBiaW5kaW5nIHBvaW50cy9ibG9jayBpbmRpY2VzIG1hcHBpbmcgZm9yIHRoaXMgcHJvZ3JhbVxuXG5cdFx0Y29uc3Qgd2ViZ2xQcm9ncmFtID0gcHJvZ3JhbS5wcm9ncmFtO1xuXHRcdHN0YXRlLnVwZGF0ZVVCT01hcHBpbmcoIHVuaWZvcm1zR3JvdXAsIHdlYmdsUHJvZ3JhbSApO1xuXG5cdFx0Ly8gdXBkYXRlIFVCTyBvbmNlIHBlciBmcmFtZVxuXG5cdFx0Y29uc3QgZnJhbWUgPSBpbmZvLnJlbmRlci5mcmFtZTtcblxuXHRcdGlmICggdXBkYXRlTGlzdFsgdW5pZm9ybXNHcm91cC5pZCBdICE9PSBmcmFtZSApIHtcblxuXHRcdFx0dXBkYXRlQnVmZmVyRGF0YSggdW5pZm9ybXNHcm91cCApO1xuXG5cdFx0XHR1cGRhdGVMaXN0WyB1bmlmb3Jtc0dyb3VwLmlkIF0gPSBmcmFtZTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gY3JlYXRlQnVmZmVyKCB1bmlmb3Jtc0dyb3VwICkge1xuXG5cdFx0Ly8gdGhlIHNldHVwIG9mIGFuIFVCTyBpcyBpbmRlcGVuZGVudCBvZiBhIHBhcnRpY3VsYXIgc2hhZGVyIHByb2dyYW0gYnV0IGdsb2JhbFxuXG5cdFx0Y29uc3QgYmluZGluZ1BvaW50SW5kZXggPSBhbGxvY2F0ZUJpbmRpbmdQb2ludEluZGV4KCk7XG5cdFx0dW5pZm9ybXNHcm91cC5fX2JpbmRpbmdQb2ludEluZGV4ID0gYmluZGluZ1BvaW50SW5kZXg7XG5cblx0XHRjb25zdCBidWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcblx0XHRjb25zdCBzaXplID0gdW5pZm9ybXNHcm91cC5fX3NpemU7XG5cdFx0Y29uc3QgdXNhZ2UgPSB1bmlmb3Jtc0dyb3VwLnVzYWdlO1xuXG5cdFx0Z2wuYmluZEJ1ZmZlciggZ2wuVU5JRk9STV9CVUZGRVIsIGJ1ZmZlciApO1xuXHRcdGdsLmJ1ZmZlckRhdGEoIGdsLlVOSUZPUk1fQlVGRkVSLCBzaXplLCB1c2FnZSApO1xuXHRcdGdsLmJpbmRCdWZmZXIoIGdsLlVOSUZPUk1fQlVGRkVSLCBudWxsICk7XG5cdFx0Z2wuYmluZEJ1ZmZlckJhc2UoIGdsLlVOSUZPUk1fQlVGRkVSLCBiaW5kaW5nUG9pbnRJbmRleCwgYnVmZmVyICk7XG5cblx0XHRyZXR1cm4gYnVmZmVyO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBhbGxvY2F0ZUJpbmRpbmdQb2ludEluZGV4KCkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbWF4QmluZGluZ1BvaW50czsgaSArKyApIHtcblxuXHRcdFx0aWYgKCBhbGxvY2F0ZWRCaW5kaW5nUG9pbnRzLmluZGV4T2YoIGkgKSA9PT0gLSAxICkge1xuXG5cdFx0XHRcdGFsbG9jYXRlZEJpbmRpbmdQb2ludHMucHVzaCggaSApO1xuXHRcdFx0XHRyZXR1cm4gaTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IE1heGltdW0gbnVtYmVyIG9mIHNpbXVsdGFuZW91c2x5IHVzYWJsZSB1bmlmb3JtcyBncm91cHMgcmVhY2hlZC4nICk7XG5cblx0XHRyZXR1cm4gMDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gdXBkYXRlQnVmZmVyRGF0YSggdW5pZm9ybXNHcm91cCApIHtcblxuXHRcdGNvbnN0IGJ1ZmZlciA9IGJ1ZmZlcnNbIHVuaWZvcm1zR3JvdXAuaWQgXTtcblx0XHRjb25zdCB1bmlmb3JtcyA9IHVuaWZvcm1zR3JvdXAudW5pZm9ybXM7XG5cdFx0Y29uc3QgY2FjaGUgPSB1bmlmb3Jtc0dyb3VwLl9fY2FjaGU7XG5cblx0XHRnbC5iaW5kQnVmZmVyKCBnbC5VTklGT1JNX0JVRkZFUiwgYnVmZmVyICk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdW5pZm9ybXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHVuaWZvcm1BcnJheSA9IEFycmF5LmlzQXJyYXkoIHVuaWZvcm1zWyBpIF0gKSA/IHVuaWZvcm1zWyBpIF0gOiBbIHVuaWZvcm1zWyBpIF0gXTtcblxuXHRcdFx0Zm9yICggbGV0IGogPSAwLCBqbCA9IHVuaWZvcm1BcnJheS5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcblxuXHRcdFx0XHRjb25zdCB1bmlmb3JtID0gdW5pZm9ybUFycmF5WyBqIF07XG5cblx0XHRcdFx0aWYgKCBoYXNVbmlmb3JtQ2hhbmdlZCggdW5pZm9ybSwgaSwgaiwgY2FjaGUgKSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdGNvbnN0IG9mZnNldCA9IHVuaWZvcm0uX19vZmZzZXQ7XG5cblx0XHRcdFx0XHRjb25zdCB2YWx1ZXMgPSBBcnJheS5pc0FycmF5KCB1bmlmb3JtLnZhbHVlICkgPyB1bmlmb3JtLnZhbHVlIDogWyB1bmlmb3JtLnZhbHVlIF07XG5cblx0XHRcdFx0XHRsZXQgYXJyYXlPZmZzZXQgPSAwO1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGsgPSAwOyBrIDwgdmFsdWVzLmxlbmd0aDsgayArKyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgdmFsdWUgPSB2YWx1ZXNbIGsgXTtcblxuXHRcdFx0XHRcdFx0Y29uc3QgaW5mbyA9IGdldFVuaWZvcm1TaXplKCB2YWx1ZSApO1xuXG5cdFx0XHRcdFx0XHQvLyBUT0RPIGFkZCBpbnRlZ2VyIGFuZCBzdHJ1Y3Qgc3VwcG9ydFxuXHRcdFx0XHRcdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nICkge1xuXG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyAwIF0gPSB2YWx1ZTtcblx0XHRcdFx0XHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggZ2wuVU5JRk9STV9CVUZGRVIsIG9mZnNldCArIGFycmF5T2Zmc2V0LCB1bmlmb3JtLl9fZGF0YSApO1xuXG5cdFx0XHRcdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZS5pc01hdHJpeDMgKSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gbWFudWFsbHkgY29udmVydGluZyAzeDMgdG8gM3g0XG5cblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDAgXSA9IHZhbHVlLmVsZW1lbnRzWyAwIF07XG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyAxIF0gPSB2YWx1ZS5lbGVtZW50c1sgMSBdO1xuXHRcdFx0XHRcdFx0XHR1bmlmb3JtLl9fZGF0YVsgMiBdID0gdmFsdWUuZWxlbWVudHNbIDIgXTtcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDMgXSA9IDA7XG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyA0IF0gPSB2YWx1ZS5lbGVtZW50c1sgMyBdO1xuXHRcdFx0XHRcdFx0XHR1bmlmb3JtLl9fZGF0YVsgNSBdID0gdmFsdWUuZWxlbWVudHNbIDQgXTtcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDYgXSA9IHZhbHVlLmVsZW1lbnRzWyA1IF07XG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyA3IF0gPSAwO1xuXHRcdFx0XHRcdFx0XHR1bmlmb3JtLl9fZGF0YVsgOCBdID0gdmFsdWUuZWxlbWVudHNbIDYgXTtcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDkgXSA9IHZhbHVlLmVsZW1lbnRzWyA3IF07XG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyAxMCBdID0gdmFsdWUuZWxlbWVudHNbIDggXTtcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDExIF0gPSAwO1xuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdHZhbHVlLnRvQXJyYXkoIHVuaWZvcm0uX19kYXRhLCBhcnJheU9mZnNldCApO1xuXG5cdFx0XHRcdFx0XHRcdGFycmF5T2Zmc2V0ICs9IGluZm8uc3RvcmFnZSAvIEZsb2F0MzJBcnJheS5CWVRFU19QRVJfRUxFTUVOVDtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggZ2wuVU5JRk9STV9CVUZGRVIsIG9mZnNldCwgdW5pZm9ybS5fX2RhdGEgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGdsLmJpbmRCdWZmZXIoIGdsLlVOSUZPUk1fQlVGRkVSLCBudWxsICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGhhc1VuaWZvcm1DaGFuZ2VkKCB1bmlmb3JtLCBpbmRleCwgaW5kZXhBcnJheSwgY2FjaGUgKSB7XG5cblx0XHRjb25zdCB2YWx1ZSA9IHVuaWZvcm0udmFsdWU7XG5cdFx0Y29uc3QgaW5kZXhTdHJpbmcgPSBpbmRleCArICdfJyArIGluZGV4QXJyYXk7XG5cblx0XHRpZiAoIGNhY2hlWyBpbmRleFN0cmluZyBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdC8vIGNhY2hlIGVudHJ5IGRvZXMgbm90IGV4aXN0IHNvIGZhclxuXG5cdFx0XHRpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgfHwgdHlwZW9mIHZhbHVlID09PSAnYm9vbGVhbicgKSB7XG5cblx0XHRcdFx0Y2FjaGVbIGluZGV4U3RyaW5nIF0gPSB2YWx1ZTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjYWNoZVsgaW5kZXhTdHJpbmcgXSA9IHZhbHVlLmNsb25lKCk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRydWU7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zdCBjYWNoZWRPYmplY3QgPSBjYWNoZVsgaW5kZXhTdHJpbmcgXTtcblxuXHRcdFx0Ly8gY29tcGFyZSBjdXJyZW50IHZhbHVlIHdpdGggY2FjaGVkIGVudHJ5XG5cblx0XHRcdGlmICggdHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyB8fCB0eXBlb2YgdmFsdWUgPT09ICdib29sZWFuJyApIHtcblxuXHRcdFx0XHRpZiAoIGNhY2hlZE9iamVjdCAhPT0gdmFsdWUgKSB7XG5cblx0XHRcdFx0XHRjYWNoZVsgaW5kZXhTdHJpbmcgXSA9IHZhbHVlO1xuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRpZiAoIGNhY2hlZE9iamVjdC5lcXVhbHMoIHZhbHVlICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdFx0Y2FjaGVkT2JqZWN0LmNvcHkoIHZhbHVlICk7XG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHByZXBhcmVVbmlmb3Jtc0dyb3VwKCB1bmlmb3Jtc0dyb3VwICkge1xuXG5cdFx0Ly8gZGV0ZXJtaW5lIHRvdGFsIGJ1ZmZlciBzaXplIGFjY29yZGluZyB0byB0aGUgU1REMTQwIGxheW91dFxuXHRcdC8vIEhpbnQ6IFNURDE0MCBpcyB0aGUgb25seSBzdXBwb3J0ZWQgbGF5b3V0IGluIFdlYkdMIDJcblxuXHRcdGNvbnN0IHVuaWZvcm1zID0gdW5pZm9ybXNHcm91cC51bmlmb3JtcztcblxuXHRcdGxldCBvZmZzZXQgPSAwOyAvLyBnbG9iYWwgYnVmZmVyIG9mZnNldCBpbiBieXRlc1xuXHRcdGNvbnN0IGNodW5rU2l6ZSA9IDE2OyAvLyBzaXplIG9mIGEgY2h1bmsgaW4gYnl0ZXNcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHVuaWZvcm1zLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHVuaWZvcm1BcnJheSA9IEFycmF5LmlzQXJyYXkoIHVuaWZvcm1zWyBpIF0gKSA/IHVuaWZvcm1zWyBpIF0gOiBbIHVuaWZvcm1zWyBpIF0gXTtcblxuXHRcdFx0Zm9yICggbGV0IGogPSAwLCBqbCA9IHVuaWZvcm1BcnJheS5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcblxuXHRcdFx0XHRjb25zdCB1bmlmb3JtID0gdW5pZm9ybUFycmF5WyBqIF07XG5cblx0XHRcdFx0Y29uc3QgdmFsdWVzID0gQXJyYXkuaXNBcnJheSggdW5pZm9ybS52YWx1ZSApID8gdW5pZm9ybS52YWx1ZSA6IFsgdW5pZm9ybS52YWx1ZSBdO1xuXG5cdFx0XHRcdGZvciAoIGxldCBrID0gMCwga2wgPSB2YWx1ZXMubGVuZ3RoOyBrIDwga2w7IGsgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB2YWx1ZSA9IHZhbHVlc1sgayBdO1xuXG5cdFx0XHRcdFx0Y29uc3QgaW5mbyA9IGdldFVuaWZvcm1TaXplKCB2YWx1ZSApO1xuXG5cdFx0XHRcdFx0Ly8gQ2FsY3VsYXRlIHRoZSBjaHVuayBvZmZzZXRcblx0XHRcdFx0XHRjb25zdCBjaHVua09mZnNldFVuaWZvcm0gPSBvZmZzZXQgJSBjaHVua1NpemU7XG5cblx0XHRcdFx0XHQvLyBDaGVjayBmb3IgY2h1bmsgb3ZlcmZsb3dcblx0XHRcdFx0XHRpZiAoIGNodW5rT2Zmc2V0VW5pZm9ybSAhPT0gMCAmJiAoIGNodW5rU2l6ZSAtIGNodW5rT2Zmc2V0VW5pZm9ybSApIDwgaW5mby5ib3VuZGFyeSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gQWRkIHBhZGRpbmcgYW5kIGFkanVzdCBvZmZzZXRcblx0XHRcdFx0XHRcdG9mZnNldCArPSAoIGNodW5rU2l6ZSAtIGNodW5rT2Zmc2V0VW5pZm9ybSApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gdGhlIGZvbGxvd2luZyB0d28gcHJvcGVydGllcyB3aWxsIGJlIHVzZWQgZm9yIHBhcnRpYWwgYnVmZmVyIHVwZGF0ZXNcblxuXHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhID0gbmV3IEZsb2F0MzJBcnJheSggaW5mby5zdG9yYWdlIC8gRmxvYXQzMkFycmF5LkJZVEVTX1BFUl9FTEVNRU5UICk7XG5cdFx0XHRcdFx0dW5pZm9ybS5fX29mZnNldCA9IG9mZnNldDtcblxuXG5cdFx0XHRcdFx0Ly8gVXBkYXRlIHRoZSBnbG9iYWwgb2Zmc2V0XG5cdFx0XHRcdFx0b2Zmc2V0ICs9IGluZm8uc3RvcmFnZTtcblxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gZW5zdXJlIGNvcnJlY3QgZmluYWwgcGFkZGluZ1xuXG5cdFx0Y29uc3QgY2h1bmtPZmZzZXQgPSBvZmZzZXQgJSBjaHVua1NpemU7XG5cblx0XHRpZiAoIGNodW5rT2Zmc2V0ID4gMCApIG9mZnNldCArPSAoIGNodW5rU2l6ZSAtIGNodW5rT2Zmc2V0ICk7XG5cblx0XHQvL1xuXG5cdFx0dW5pZm9ybXNHcm91cC5fX3NpemUgPSBvZmZzZXQ7XG5cdFx0dW5pZm9ybXNHcm91cC5fX2NhY2hlID0ge307XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0VW5pZm9ybVNpemUoIHZhbHVlICkge1xuXG5cdFx0Y29uc3QgaW5mbyA9IHtcblx0XHRcdGJvdW5kYXJ5OiAwLCAvLyBieXRlc1xuXHRcdFx0c3RvcmFnZTogMCAvLyBieXRlc1xuXHRcdH07XG5cblx0XHQvLyBkZXRlcm1pbmUgc2l6ZXMgYWNjb3JkaW5nIHRvIFNURDE0MFxuXG5cdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nICkge1xuXG5cdFx0XHQvLyBmbG9hdC9pbnQvYm9vbFxuXG5cdFx0XHRpbmZvLmJvdW5kYXJ5ID0gNDtcblx0XHRcdGluZm8uc3RvcmFnZSA9IDQ7XG5cblx0XHR9IGVsc2UgaWYgKCB2YWx1ZS5pc1ZlY3RvcjIgKSB7XG5cblx0XHRcdC8vIHZlYzJcblxuXHRcdFx0aW5mby5ib3VuZGFyeSA9IDg7XG5cdFx0XHRpbmZvLnN0b3JhZ2UgPSA4O1xuXG5cdFx0fSBlbHNlIGlmICggdmFsdWUuaXNWZWN0b3IzIHx8IHZhbHVlLmlzQ29sb3IgKSB7XG5cblx0XHRcdC8vIHZlYzNcblxuXHRcdFx0aW5mby5ib3VuZGFyeSA9IDE2O1xuXHRcdFx0aW5mby5zdG9yYWdlID0gMTI7IC8vIGV2aWw6IHZlYzMgbXVzdCBzdGFydCBvbiBhIDE2LWJ5dGUgYm91bmRhcnkgYnV0IGl0IG9ubHkgY29uc3VtZXMgMTIgYnl0ZXNcblxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzVmVjdG9yNCApIHtcblxuXHRcdFx0Ly8gdmVjNFxuXG5cdFx0XHRpbmZvLmJvdW5kYXJ5ID0gMTY7XG5cdFx0XHRpbmZvLnN0b3JhZ2UgPSAxNjtcblxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzTWF0cml4MyApIHtcblxuXHRcdFx0Ly8gbWF0MyAoaW4gU1REMTQwIGEgM3gzIG1hdHJpeCBpcyByZXByZXNlbnRlZCBhcyAzeDQpXG5cblx0XHRcdGluZm8uYm91bmRhcnkgPSA0ODtcblx0XHRcdGluZm8uc3RvcmFnZSA9IDQ4O1xuXG5cdFx0fSBlbHNlIGlmICggdmFsdWUuaXNNYXRyaXg0ICkge1xuXG5cdFx0XHQvLyBtYXQ0XG5cblx0XHRcdGluZm8uYm91bmRhcnkgPSA2NDtcblx0XHRcdGluZm8uc3RvcmFnZSA9IDY0O1xuXG5cdFx0fSBlbHNlIGlmICggdmFsdWUuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBUZXh0dXJlIHNhbXBsZXJzIGNhbiBub3QgYmUgcGFydCBvZiBhbiB1bmlmb3JtcyBncm91cC4nICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBVbnN1cHBvcnRlZCB1bmlmb3JtIHZhbHVlIHR5cGUuJywgdmFsdWUgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBpbmZvO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBvblVuaWZvcm1zR3JvdXBzRGlzcG9zZSggZXZlbnQgKSB7XG5cblx0XHRjb25zdCB1bmlmb3Jtc0dyb3VwID0gZXZlbnQudGFyZ2V0O1xuXG5cdFx0dW5pZm9ybXNHcm91cC5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVW5pZm9ybXNHcm91cHNEaXNwb3NlICk7XG5cblx0XHRjb25zdCBpbmRleCA9IGFsbG9jYXRlZEJpbmRpbmdQb2ludHMuaW5kZXhPZiggdW5pZm9ybXNHcm91cC5fX2JpbmRpbmdQb2ludEluZGV4ICk7XG5cdFx0YWxsb2NhdGVkQmluZGluZ1BvaW50cy5zcGxpY2UoIGluZGV4LCAxICk7XG5cblx0XHRnbC5kZWxldGVCdWZmZXIoIGJ1ZmZlcnNbIHVuaWZvcm1zR3JvdXAuaWQgXSApO1xuXG5cdFx0ZGVsZXRlIGJ1ZmZlcnNbIHVuaWZvcm1zR3JvdXAuaWQgXTtcblx0XHRkZWxldGUgdXBkYXRlTGlzdFsgdW5pZm9ybXNHcm91cC5pZCBdO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xuXG5cdFx0Zm9yICggY29uc3QgaWQgaW4gYnVmZmVycyApIHtcblxuXHRcdFx0Z2wuZGVsZXRlQnVmZmVyKCBidWZmZXJzWyBpZCBdICk7XG5cblx0XHR9XG5cblx0XHRhbGxvY2F0ZWRCaW5kaW5nUG9pbnRzID0gW107XG5cdFx0YnVmZmVycyA9IHt9O1xuXHRcdHVwZGF0ZUxpc3QgPSB7fTtcblxuXHR9XG5cblx0cmV0dXJuIHtcblxuXHRcdGJpbmQ6IGJpbmQsXG5cdFx0dXBkYXRlOiB1cGRhdGUsXG5cblx0XHRkaXNwb3NlOiBkaXNwb3NlXG5cblx0fTtcblxufVxuXG5jbGFzcyBXZWJHTFJlbmRlcmVyIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyA9IHt9ICkge1xuXG5cdFx0Y29uc3Qge1xuXHRcdFx0Y2FudmFzID0gY3JlYXRlQ2FudmFzRWxlbWVudCgpLFxuXHRcdFx0Y29udGV4dCA9IG51bGwsXG5cdFx0XHRkZXB0aCA9IHRydWUsXG5cdFx0XHRzdGVuY2lsID0gZmFsc2UsXG5cdFx0XHRhbHBoYSA9IGZhbHNlLFxuXHRcdFx0YW50aWFsaWFzID0gZmFsc2UsXG5cdFx0XHRwcmVtdWx0aXBsaWVkQWxwaGEgPSB0cnVlLFxuXHRcdFx0cHJlc2VydmVEcmF3aW5nQnVmZmVyID0gZmFsc2UsXG5cdFx0XHRwb3dlclByZWZlcmVuY2UgPSAnZGVmYXVsdCcsXG5cdFx0XHRmYWlsSWZNYWpvclBlcmZvcm1hbmNlQ2F2ZWF0ID0gZmFsc2UsXG5cdFx0fSA9IHBhcmFtZXRlcnM7XG5cblx0XHR0aGlzLmlzV2ViR0xSZW5kZXJlciA9IHRydWU7XG5cblx0XHRsZXQgX2FscGhhO1xuXG5cdFx0aWYgKCBjb250ZXh0ICE9PSBudWxsICkge1xuXG5cdFx0XHRpZiAoIHR5cGVvZiBXZWJHTFJlbmRlcmluZ0NvbnRleHQgIT09ICd1bmRlZmluZWQnICYmIGNvbnRleHQgaW5zdGFuY2VvZiBXZWJHTFJlbmRlcmluZ0NvbnRleHQgKSB7XG5cblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogV2ViR0wgMSBpcyBub3Qgc3VwcG9ydGVkIHNpbmNlIHIxNjMuJyApO1xuXG5cdFx0XHR9XG5cblx0XHRcdF9hbHBoYSA9IGNvbnRleHQuZ2V0Q29udGV4dEF0dHJpYnV0ZXMoKS5hbHBoYTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdF9hbHBoYSA9IGFscGhhO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgdWludENsZWFyQ29sb3IgPSBuZXcgVWludDMyQXJyYXkoIDQgKTtcblx0XHRjb25zdCBpbnRDbGVhckNvbG9yID0gbmV3IEludDMyQXJyYXkoIDQgKTtcblxuXHRcdGxldCBjdXJyZW50UmVuZGVyTGlzdCA9IG51bGw7XG5cdFx0bGV0IGN1cnJlbnRSZW5kZXJTdGF0ZSA9IG51bGw7XG5cblx0XHQvLyByZW5kZXIoKSBjYW4gYmUgY2FsbGVkIGZyb20gd2l0aGluIGEgY2FsbGJhY2sgdHJpZ2dlcmVkIGJ5IGFub3RoZXIgcmVuZGVyLlxuXHRcdC8vIFdlIHRyYWNrIHRoaXMgc28gdGhhdCB0aGUgbmVzdGVkIHJlbmRlciBjYWxsIGdldHMgaXRzIGxpc3QgYW5kIHN0YXRlIGlzb2xhdGVkIGZyb20gdGhlIHBhcmVudCByZW5kZXIgY2FsbC5cblxuXHRcdGNvbnN0IHJlbmRlckxpc3RTdGFjayA9IFtdO1xuXHRcdGNvbnN0IHJlbmRlclN0YXRlU3RhY2sgPSBbXTtcblxuXHRcdC8vIHB1YmxpYyBwcm9wZXJ0aWVzXG5cblx0XHR0aGlzLmRvbUVsZW1lbnQgPSBjYW52YXM7XG5cblx0XHQvLyBEZWJ1ZyBjb25maWd1cmF0aW9uIGNvbnRhaW5lclxuXHRcdHRoaXMuZGVidWcgPSB7XG5cblx0XHRcdC8qKlxuXHRcdFx0ICogRW5hYmxlcyBlcnJvciBjaGVja2luZyBhbmQgcmVwb3J0aW5nIHdoZW4gc2hhZGVyIHByb2dyYW1zIGFyZSBiZWluZyBjb21waWxlZFxuXHRcdFx0ICogQHR5cGUge2Jvb2xlYW59XG5cdFx0XHQgKi9cblx0XHRcdGNoZWNrU2hhZGVyRXJyb3JzOiB0cnVlLFxuXHRcdFx0LyoqXG5cdFx0XHQgKiBDYWxsYmFjayBmb3IgY3VzdG9tIGVycm9yIHJlcG9ydGluZy5cblx0XHRcdCAqIEB0eXBlIHs/RnVuY3Rpb259XG5cdFx0XHQgKi9cblx0XHRcdG9uU2hhZGVyRXJyb3I6IG51bGxcblx0XHR9O1xuXG5cdFx0Ly8gY2xlYXJpbmdcblxuXHRcdHRoaXMuYXV0b0NsZWFyID0gdHJ1ZTtcblx0XHR0aGlzLmF1dG9DbGVhckNvbG9yID0gdHJ1ZTtcblx0XHR0aGlzLmF1dG9DbGVhckRlcHRoID0gdHJ1ZTtcblx0XHR0aGlzLmF1dG9DbGVhclN0ZW5jaWwgPSB0cnVlO1xuXG5cdFx0Ly8gc2NlbmUgZ3JhcGhcblxuXHRcdHRoaXMuc29ydE9iamVjdHMgPSB0cnVlO1xuXG5cdFx0Ly8gdXNlci1kZWZpbmVkIGNsaXBwaW5nXG5cblx0XHR0aGlzLmNsaXBwaW5nUGxhbmVzID0gW107XG5cdFx0dGhpcy5sb2NhbENsaXBwaW5nRW5hYmxlZCA9IGZhbHNlO1xuXG5cdFx0Ly8gcGh5c2ljYWxseSBiYXNlZCBzaGFkaW5nXG5cblx0XHR0aGlzLl9vdXRwdXRDb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2U7XG5cblx0XHQvLyB0b25lIG1hcHBpbmdcblxuXHRcdHRoaXMudG9uZU1hcHBpbmcgPSBOb1RvbmVNYXBwaW5nO1xuXHRcdHRoaXMudG9uZU1hcHBpbmdFeHBvc3VyZSA9IDEuMDtcblxuXHRcdC8vIGludGVybmFsIHByb3BlcnRpZXNcblxuXHRcdGNvbnN0IF90aGlzID0gdGhpcztcblxuXHRcdGxldCBfaXNDb250ZXh0TG9zdCA9IGZhbHNlO1xuXG5cdFx0Ly8gaW50ZXJuYWwgc3RhdGUgY2FjaGVcblxuXHRcdGxldCBfY3VycmVudEFjdGl2ZUN1YmVGYWNlID0gMDtcblx0XHRsZXQgX2N1cnJlbnRBY3RpdmVNaXBtYXBMZXZlbCA9IDA7XG5cdFx0bGV0IF9jdXJyZW50UmVuZGVyVGFyZ2V0ID0gbnVsbDtcblx0XHRsZXQgX2N1cnJlbnRNYXRlcmlhbElkID0gLSAxO1xuXG5cdFx0bGV0IF9jdXJyZW50Q2FtZXJhID0gbnVsbDtcblxuXHRcdGNvbnN0IF9jdXJyZW50Vmlld3BvcnQgPSBuZXcgVmVjdG9yNCgpO1xuXHRcdGNvbnN0IF9jdXJyZW50U2Npc3NvciA9IG5ldyBWZWN0b3I0KCk7XG5cdFx0bGV0IF9jdXJyZW50U2Npc3NvclRlc3QgPSBudWxsO1xuXG5cdFx0Y29uc3QgX2N1cnJlbnRDbGVhckNvbG9yID0gbmV3IENvbG9yKCAweDAwMDAwMCApO1xuXHRcdGxldCBfY3VycmVudENsZWFyQWxwaGEgPSAwO1xuXG5cdFx0Ly9cblxuXHRcdGxldCBfd2lkdGggPSBjYW52YXMud2lkdGg7XG5cdFx0bGV0IF9oZWlnaHQgPSBjYW52YXMuaGVpZ2h0O1xuXG5cdFx0bGV0IF9waXhlbFJhdGlvID0gMTtcblx0XHRsZXQgX29wYXF1ZVNvcnQgPSBudWxsO1xuXHRcdGxldCBfdHJhbnNwYXJlbnRTb3J0ID0gbnVsbDtcblxuXHRcdGNvbnN0IF92aWV3cG9ydCA9IG5ldyBWZWN0b3I0KCAwLCAwLCBfd2lkdGgsIF9oZWlnaHQgKTtcblx0XHRjb25zdCBfc2Npc3NvciA9IG5ldyBWZWN0b3I0KCAwLCAwLCBfd2lkdGgsIF9oZWlnaHQgKTtcblx0XHRsZXQgX3NjaXNzb3JUZXN0ID0gZmFsc2U7XG5cblx0XHQvLyBmcnVzdHVtXG5cblx0XHRjb25zdCBfZnJ1c3R1bSA9IG5ldyBGcnVzdHVtKCk7XG5cblx0XHQvLyBjbGlwcGluZ1xuXG5cdFx0bGV0IF9jbGlwcGluZ0VuYWJsZWQgPSBmYWxzZTtcblx0XHRsZXQgX2xvY2FsQ2xpcHBpbmdFbmFibGVkID0gZmFsc2U7XG5cblx0XHQvLyBjYW1lcmEgbWF0cmljZXMgY2FjaGVcblxuXHRcdGNvbnN0IF9wcm9qU2NyZWVuTWF0cml4ID0gbmV3IE1hdHJpeDQoKTtcblxuXHRcdGNvbnN0IF92ZWN0b3IzID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdGNvbnN0IF92ZWN0b3I0ID0gbmV3IFZlY3RvcjQoKTtcblxuXHRcdGNvbnN0IF9lbXB0eVNjZW5lID0geyBiYWNrZ3JvdW5kOiBudWxsLCBmb2c6IG51bGwsIGVudmlyb25tZW50OiBudWxsLCBvdmVycmlkZU1hdGVyaWFsOiBudWxsLCBpc1NjZW5lOiB0cnVlIH07XG5cblx0XHRsZXQgX3JlbmRlckJhY2tncm91bmQgPSBmYWxzZTtcblxuXHRcdGZ1bmN0aW9uIGdldFRhcmdldFBpeGVsUmF0aW8oKSB7XG5cblx0XHRcdHJldHVybiBfY3VycmVudFJlbmRlclRhcmdldCA9PT0gbnVsbCA/IF9waXhlbFJhdGlvIDogMTtcblxuXHRcdH1cblxuXHRcdC8vIGluaXRpYWxpemVcblxuXHRcdGxldCBfZ2wgPSBjb250ZXh0O1xuXG5cdFx0ZnVuY3Rpb24gZ2V0Q29udGV4dCggY29udGV4dE5hbWUsIGNvbnRleHRBdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRyZXR1cm4gY2FudmFzLmdldENvbnRleHQoIGNvbnRleHROYW1lLCBjb250ZXh0QXR0cmlidXRlcyApO1xuXG5cdFx0fVxuXG5cdFx0dHJ5IHtcblxuXHRcdFx0Y29uc3QgY29udGV4dEF0dHJpYnV0ZXMgPSB7XG5cdFx0XHRcdGFscGhhOiB0cnVlLFxuXHRcdFx0XHRkZXB0aCxcblx0XHRcdFx0c3RlbmNpbCxcblx0XHRcdFx0YW50aWFsaWFzLFxuXHRcdFx0XHRwcmVtdWx0aXBsaWVkQWxwaGEsXG5cdFx0XHRcdHByZXNlcnZlRHJhd2luZ0J1ZmZlcixcblx0XHRcdFx0cG93ZXJQcmVmZXJlbmNlLFxuXHRcdFx0XHRmYWlsSWZNYWpvclBlcmZvcm1hbmNlQ2F2ZWF0LFxuXHRcdFx0fTtcblxuXHRcdFx0Ly8gT2Zmc2NyZWVuQ2FudmFzIGRvZXMgbm90IGhhdmUgc2V0QXR0cmlidXRlLCBzZWUgIzIyODExXG5cdFx0XHRpZiAoICdzZXRBdHRyaWJ1dGUnIGluIGNhbnZhcyApIGNhbnZhcy5zZXRBdHRyaWJ1dGUoICdkYXRhLWVuZ2luZScsIGB0aHJlZS5qcyByJHtSRVZJU0lPTn1gICk7XG5cblx0XHRcdC8vIGV2ZW50IGxpc3RlbmVycyBtdXN0IGJlIHJlZ2lzdGVyZWQgYmVmb3JlIFdlYkdMIGNvbnRleHQgaXMgY3JlYXRlZCwgc2VlICMxMjc1M1xuXHRcdFx0Y2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoICd3ZWJnbGNvbnRleHRsb3N0Jywgb25Db250ZXh0TG9zdCwgZmFsc2UgKTtcblx0XHRcdGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCAnd2ViZ2xjb250ZXh0cmVzdG9yZWQnLCBvbkNvbnRleHRSZXN0b3JlLCBmYWxzZSApO1xuXHRcdFx0Y2FudmFzLmFkZEV2ZW50TGlzdGVuZXIoICd3ZWJnbGNvbnRleHRjcmVhdGlvbmVycm9yJywgb25Db250ZXh0Q3JlYXRpb25FcnJvciwgZmFsc2UgKTtcblxuXHRcdFx0aWYgKCBfZ2wgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0Y29uc3QgY29udGV4dE5hbWUgPSAnd2ViZ2wyJztcblxuXHRcdFx0XHRfZ2wgPSBnZXRDb250ZXh0KCBjb250ZXh0TmFtZSwgY29udGV4dEF0dHJpYnV0ZXMgKTtcblxuXHRcdFx0XHRpZiAoIF9nbCA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdGlmICggZ2V0Q29udGV4dCggY29udGV4dE5hbWUgKSApIHtcblxuXHRcdFx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnRXJyb3IgY3JlYXRpbmcgV2ViR0wgY29udGV4dCB3aXRoIHlvdXIgc2VsZWN0ZWQgYXR0cmlidXRlcy4nICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdFcnJvciBjcmVhdGluZyBXZWJHTCBjb250ZXh0LicgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXI6ICcgKyBlcnJvci5tZXNzYWdlICk7XG5cdFx0XHR0aHJvdyBlcnJvcjtcblxuXHRcdH1cblxuXHRcdGxldCBleHRlbnNpb25zLCBjYXBhYmlsaXRpZXMsIHN0YXRlLCBpbmZvO1xuXHRcdGxldCBwcm9wZXJ0aWVzLCB0ZXh0dXJlcywgY3ViZW1hcHMsIGN1YmV1dm1hcHMsIGF0dHJpYnV0ZXMsIGdlb21ldHJpZXMsIG9iamVjdHM7XG5cdFx0bGV0IHByb2dyYW1DYWNoZSwgbWF0ZXJpYWxzLCByZW5kZXJMaXN0cywgcmVuZGVyU3RhdGVzLCBjbGlwcGluZywgc2hhZG93TWFwO1xuXG5cdFx0bGV0IGJhY2tncm91bmQsIG1vcnBodGFyZ2V0cywgYnVmZmVyUmVuZGVyZXIsIGluZGV4ZWRCdWZmZXJSZW5kZXJlcjtcblxuXHRcdGxldCB1dGlscywgYmluZGluZ1N0YXRlcywgdW5pZm9ybXNHcm91cHM7XG5cblx0XHRmdW5jdGlvbiBpbml0R0xDb250ZXh0KCkge1xuXG5cdFx0XHRleHRlbnNpb25zID0gbmV3IFdlYkdMRXh0ZW5zaW9ucyggX2dsICk7XG5cdFx0XHRleHRlbnNpb25zLmluaXQoKTtcblxuXHRcdFx0dXRpbHMgPSBuZXcgV2ViR0xVdGlscyggX2dsLCBleHRlbnNpb25zICk7XG5cblx0XHRcdGNhcGFiaWxpdGllcyA9IG5ldyBXZWJHTENhcGFiaWxpdGllcyggX2dsLCBleHRlbnNpb25zLCBwYXJhbWV0ZXJzLCB1dGlscyApO1xuXG5cdFx0XHRzdGF0ZSA9IG5ldyBXZWJHTFN0YXRlKCBfZ2wgKTtcblxuXHRcdFx0aW5mbyA9IG5ldyBXZWJHTEluZm8oIF9nbCApO1xuXHRcdFx0cHJvcGVydGllcyA9IG5ldyBXZWJHTFByb3BlcnRpZXMoKTtcblx0XHRcdHRleHR1cmVzID0gbmV3IFdlYkdMVGV4dHVyZXMoIF9nbCwgZXh0ZW5zaW9ucywgc3RhdGUsIHByb3BlcnRpZXMsIGNhcGFiaWxpdGllcywgdXRpbHMsIGluZm8gKTtcblx0XHRcdGN1YmVtYXBzID0gbmV3IFdlYkdMQ3ViZU1hcHMoIF90aGlzICk7XG5cdFx0XHRjdWJldXZtYXBzID0gbmV3IFdlYkdMQ3ViZVVWTWFwcyggX3RoaXMgKTtcblx0XHRcdGF0dHJpYnV0ZXMgPSBuZXcgV2ViR0xBdHRyaWJ1dGVzKCBfZ2wgKTtcblx0XHRcdGJpbmRpbmdTdGF0ZXMgPSBuZXcgV2ViR0xCaW5kaW5nU3RhdGVzKCBfZ2wsIGF0dHJpYnV0ZXMgKTtcblx0XHRcdGdlb21ldHJpZXMgPSBuZXcgV2ViR0xHZW9tZXRyaWVzKCBfZ2wsIGF0dHJpYnV0ZXMsIGluZm8sIGJpbmRpbmdTdGF0ZXMgKTtcblx0XHRcdG9iamVjdHMgPSBuZXcgV2ViR0xPYmplY3RzKCBfZ2wsIGdlb21ldHJpZXMsIGF0dHJpYnV0ZXMsIGluZm8gKTtcblx0XHRcdG1vcnBodGFyZ2V0cyA9IG5ldyBXZWJHTE1vcnBodGFyZ2V0cyggX2dsLCBjYXBhYmlsaXRpZXMsIHRleHR1cmVzICk7XG5cdFx0XHRjbGlwcGluZyA9IG5ldyBXZWJHTENsaXBwaW5nKCBwcm9wZXJ0aWVzICk7XG5cdFx0XHRwcm9ncmFtQ2FjaGUgPSBuZXcgV2ViR0xQcm9ncmFtcyggX3RoaXMsIGN1YmVtYXBzLCBjdWJldXZtYXBzLCBleHRlbnNpb25zLCBjYXBhYmlsaXRpZXMsIGJpbmRpbmdTdGF0ZXMsIGNsaXBwaW5nICk7XG5cdFx0XHRtYXRlcmlhbHMgPSBuZXcgV2ViR0xNYXRlcmlhbHMoIF90aGlzLCBwcm9wZXJ0aWVzICk7XG5cdFx0XHRyZW5kZXJMaXN0cyA9IG5ldyBXZWJHTFJlbmRlckxpc3RzKCk7XG5cdFx0XHRyZW5kZXJTdGF0ZXMgPSBuZXcgV2ViR0xSZW5kZXJTdGF0ZXMoIGV4dGVuc2lvbnMgKTtcblx0XHRcdGJhY2tncm91bmQgPSBuZXcgV2ViR0xCYWNrZ3JvdW5kKCBfdGhpcywgY3ViZW1hcHMsIGN1YmV1dm1hcHMsIHN0YXRlLCBvYmplY3RzLCBfYWxwaGEsIHByZW11bHRpcGxpZWRBbHBoYSApO1xuXHRcdFx0c2hhZG93TWFwID0gbmV3IFdlYkdMU2hhZG93TWFwKCBfdGhpcywgb2JqZWN0cywgY2FwYWJpbGl0aWVzICk7XG5cdFx0XHR1bmlmb3Jtc0dyb3VwcyA9IG5ldyBXZWJHTFVuaWZvcm1zR3JvdXBzKCBfZ2wsIGluZm8sIGNhcGFiaWxpdGllcywgc3RhdGUgKTtcblxuXHRcdFx0YnVmZmVyUmVuZGVyZXIgPSBuZXcgV2ViR0xCdWZmZXJSZW5kZXJlciggX2dsLCBleHRlbnNpb25zLCBpbmZvICk7XG5cdFx0XHRpbmRleGVkQnVmZmVyUmVuZGVyZXIgPSBuZXcgV2ViR0xJbmRleGVkQnVmZmVyUmVuZGVyZXIoIF9nbCwgZXh0ZW5zaW9ucywgaW5mbyApO1xuXG5cdFx0XHRpbmZvLnByb2dyYW1zID0gcHJvZ3JhbUNhY2hlLnByb2dyYW1zO1xuXG5cdFx0XHRfdGhpcy5jYXBhYmlsaXRpZXMgPSBjYXBhYmlsaXRpZXM7XG5cdFx0XHRfdGhpcy5leHRlbnNpb25zID0gZXh0ZW5zaW9ucztcblx0XHRcdF90aGlzLnByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzO1xuXHRcdFx0X3RoaXMucmVuZGVyTGlzdHMgPSByZW5kZXJMaXN0cztcblx0XHRcdF90aGlzLnNoYWRvd01hcCA9IHNoYWRvd01hcDtcblx0XHRcdF90aGlzLnN0YXRlID0gc3RhdGU7XG5cdFx0XHRfdGhpcy5pbmZvID0gaW5mbztcblxuXHRcdH1cblxuXHRcdGluaXRHTENvbnRleHQoKTtcblxuXHRcdC8vIHhyXG5cblx0XHRjb25zdCB4ciA9IG5ldyBXZWJYUk1hbmFnZXIoIF90aGlzLCBfZ2wgKTtcblxuXHRcdHRoaXMueHIgPSB4cjtcblxuXHRcdC8vIEFQSVxuXG5cdFx0dGhpcy5nZXRDb250ZXh0ID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gX2dsO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0Q29udGV4dEF0dHJpYnV0ZXMgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBfZ2wuZ2V0Q29udGV4dEF0dHJpYnV0ZXMoKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmZvcmNlQ29udGV4dExvc3MgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbG9zZV9jb250ZXh0JyApO1xuXHRcdFx0aWYgKCBleHRlbnNpb24gKSBleHRlbnNpb24ubG9zZUNvbnRleHQoKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmZvcmNlQ29udGV4dFJlc3RvcmUgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbG9zZV9jb250ZXh0JyApO1xuXHRcdFx0aWYgKCBleHRlbnNpb24gKSBleHRlbnNpb24ucmVzdG9yZUNvbnRleHQoKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldFBpeGVsUmF0aW8gPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBfcGl4ZWxSYXRpbztcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldFBpeGVsUmF0aW8gPSBmdW5jdGlvbiAoIHZhbHVlICkge1xuXG5cdFx0XHRpZiAoIHZhbHVlID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHRcdF9waXhlbFJhdGlvID0gdmFsdWU7XG5cblx0XHRcdHRoaXMuc2V0U2l6ZSggX3dpZHRoLCBfaGVpZ2h0LCBmYWxzZSApO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0U2l6ZSA9IGZ1bmN0aW9uICggdGFyZ2V0ICkge1xuXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LnNldCggX3dpZHRoLCBfaGVpZ2h0ICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5zZXRTaXplID0gZnVuY3Rpb24gKCB3aWR0aCwgaGVpZ2h0LCB1cGRhdGVTdHlsZSA9IHRydWUgKSB7XG5cblx0XHRcdGlmICggeHIuaXNQcmVzZW50aW5nICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IENhblxcJ3QgY2hhbmdlIHNpemUgd2hpbGUgVlIgZGV2aWNlIGlzIHByZXNlbnRpbmcuJyApO1xuXHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdH1cblxuXHRcdFx0X3dpZHRoID0gd2lkdGg7XG5cdFx0XHRfaGVpZ2h0ID0gaGVpZ2h0O1xuXG5cdFx0XHRjYW52YXMud2lkdGggPSBNYXRoLmZsb29yKCB3aWR0aCAqIF9waXhlbFJhdGlvICk7XG5cdFx0XHRjYW52YXMuaGVpZ2h0ID0gTWF0aC5mbG9vciggaGVpZ2h0ICogX3BpeGVsUmF0aW8gKTtcblxuXHRcdFx0aWYgKCB1cGRhdGVTdHlsZSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRjYW52YXMuc3R5bGUud2lkdGggPSB3aWR0aCArICdweCc7XG5cdFx0XHRcdGNhbnZhcy5zdHlsZS5oZWlnaHQgPSBoZWlnaHQgKyAncHgnO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuc2V0Vmlld3BvcnQoIDAsIDAsIHdpZHRoLCBoZWlnaHQgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldERyYXdpbmdCdWZmZXJTaXplID0gZnVuY3Rpb24gKCB0YXJnZXQgKSB7XG5cblx0XHRcdHJldHVybiB0YXJnZXQuc2V0KCBfd2lkdGggKiBfcGl4ZWxSYXRpbywgX2hlaWdodCAqIF9waXhlbFJhdGlvICkuZmxvb3IoKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldERyYXdpbmdCdWZmZXJTaXplID0gZnVuY3Rpb24gKCB3aWR0aCwgaGVpZ2h0LCBwaXhlbFJhdGlvICkge1xuXG5cdFx0XHRfd2lkdGggPSB3aWR0aDtcblx0XHRcdF9oZWlnaHQgPSBoZWlnaHQ7XG5cblx0XHRcdF9waXhlbFJhdGlvID0gcGl4ZWxSYXRpbztcblxuXHRcdFx0Y2FudmFzLndpZHRoID0gTWF0aC5mbG9vciggd2lkdGggKiBwaXhlbFJhdGlvICk7XG5cdFx0XHRjYW52YXMuaGVpZ2h0ID0gTWF0aC5mbG9vciggaGVpZ2h0ICogcGl4ZWxSYXRpbyApO1xuXG5cdFx0XHR0aGlzLnNldFZpZXdwb3J0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRDdXJyZW50Vmlld3BvcnQgPSBmdW5jdGlvbiAoIHRhcmdldCApIHtcblxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBfY3VycmVudFZpZXdwb3J0ICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRWaWV3cG9ydCA9IGZ1bmN0aW9uICggdGFyZ2V0ICkge1xuXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIF92aWV3cG9ydCApO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0Vmlld3BvcnQgPSBmdW5jdGlvbiAoIHgsIHksIHdpZHRoLCBoZWlnaHQgKSB7XG5cblx0XHRcdGlmICggeC5pc1ZlY3RvcjQgKSB7XG5cblx0XHRcdFx0X3ZpZXdwb3J0LnNldCggeC54LCB4LnksIHgueiwgeC53ICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0X3ZpZXdwb3J0LnNldCggeCwgeSwgd2lkdGgsIGhlaWdodCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHN0YXRlLnZpZXdwb3J0KCBfY3VycmVudFZpZXdwb3J0LmNvcHkoIF92aWV3cG9ydCApLm11bHRpcGx5U2NhbGFyKCBfcGl4ZWxSYXRpbyApLnJvdW5kKCkgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldFNjaXNzb3IgPSBmdW5jdGlvbiAoIHRhcmdldCApIHtcblxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBfc2Npc3NvciApO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0U2Npc3NvciA9IGZ1bmN0aW9uICggeCwgeSwgd2lkdGgsIGhlaWdodCApIHtcblxuXHRcdFx0aWYgKCB4LmlzVmVjdG9yNCApIHtcblxuXHRcdFx0XHRfc2Npc3Nvci5zZXQoIHgueCwgeC55LCB4LnosIHgudyApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdF9zY2lzc29yLnNldCggeCwgeSwgd2lkdGgsIGhlaWdodCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHN0YXRlLnNjaXNzb3IoIF9jdXJyZW50U2Npc3Nvci5jb3B5KCBfc2Npc3NvciApLm11bHRpcGx5U2NhbGFyKCBfcGl4ZWxSYXRpbyApLnJvdW5kKCkgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldFNjaXNzb3JUZXN0ID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gX3NjaXNzb3JUZXN0O1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0U2Npc3NvclRlc3QgPSBmdW5jdGlvbiAoIGJvb2xlYW4gKSB7XG5cblx0XHRcdHN0YXRlLnNldFNjaXNzb3JUZXN0KCBfc2Npc3NvclRlc3QgPSBib29sZWFuICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5zZXRPcGFxdWVTb3J0ID0gZnVuY3Rpb24gKCBtZXRob2QgKSB7XG5cblx0XHRcdF9vcGFxdWVTb3J0ID0gbWV0aG9kO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0VHJhbnNwYXJlbnRTb3J0ID0gZnVuY3Rpb24gKCBtZXRob2QgKSB7XG5cblx0XHRcdF90cmFuc3BhcmVudFNvcnQgPSBtZXRob2Q7XG5cblx0XHR9O1xuXG5cdFx0Ly8gQ2xlYXJpbmdcblxuXHRcdHRoaXMuZ2V0Q2xlYXJDb2xvciA9IGZ1bmN0aW9uICggdGFyZ2V0ICkge1xuXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGJhY2tncm91bmQuZ2V0Q2xlYXJDb2xvcigpICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5zZXRDbGVhckNvbG9yID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRiYWNrZ3JvdW5kLnNldENsZWFyQ29sb3IuYXBwbHkoIGJhY2tncm91bmQsIGFyZ3VtZW50cyApO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0Q2xlYXJBbHBoYSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIGJhY2tncm91bmQuZ2V0Q2xlYXJBbHBoYSgpO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0Q2xlYXJBbHBoYSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0YmFja2dyb3VuZC5zZXRDbGVhckFscGhhLmFwcGx5KCBiYWNrZ3JvdW5kLCBhcmd1bWVudHMgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmNsZWFyID0gZnVuY3Rpb24gKCBjb2xvciA9IHRydWUsIGRlcHRoID0gdHJ1ZSwgc3RlbmNpbCA9IHRydWUgKSB7XG5cblx0XHRcdGxldCBiaXRzID0gMDtcblxuXHRcdFx0aWYgKCBjb2xvciApIHtcblxuXHRcdFx0XHQvLyBjaGVjayBpZiB3ZSdyZSB0cnlpbmcgdG8gY2xlYXIgYW4gaW50ZWdlciB0YXJnZXRcblx0XHRcdFx0bGV0IGlzSW50ZWdlckZvcm1hdCA9IGZhbHNlO1xuXHRcdFx0XHRpZiAoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgdGFyZ2V0Rm9ybWF0ID0gX2N1cnJlbnRSZW5kZXJUYXJnZXQudGV4dHVyZS5mb3JtYXQ7XG5cdFx0XHRcdFx0aXNJbnRlZ2VyRm9ybWF0ID0gdGFyZ2V0Rm9ybWF0ID09PSBSR0JBSW50ZWdlckZvcm1hdCB8fFxuXHRcdFx0XHRcdFx0dGFyZ2V0Rm9ybWF0ID09PSBSR0ludGVnZXJGb3JtYXQgfHxcblx0XHRcdFx0XHRcdHRhcmdldEZvcm1hdCA9PT0gUmVkSW50ZWdlckZvcm1hdDtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gdXNlIHRoZSBhcHByb3ByaWF0ZSBjbGVhciBmdW5jdGlvbnMgdG8gY2xlYXIgdGhlIHRhcmdldCBpZiBpdCdzIGEgc2lnbmVkXG5cdFx0XHRcdC8vIG9yIHVuc2lnbmVkIGludGVnZXIgdGFyZ2V0XG5cdFx0XHRcdGlmICggaXNJbnRlZ2VyRm9ybWF0ICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgdGFyZ2V0VHlwZSA9IF9jdXJyZW50UmVuZGVyVGFyZ2V0LnRleHR1cmUudHlwZTtcblx0XHRcdFx0XHRjb25zdCBpc1Vuc2lnbmVkVHlwZSA9IHRhcmdldFR5cGUgPT09IFVuc2lnbmVkQnl0ZVR5cGUgfHxcblx0XHRcdFx0XHRcdHRhcmdldFR5cGUgPT09IFVuc2lnbmVkSW50VHlwZSB8fFxuXHRcdFx0XHRcdFx0dGFyZ2V0VHlwZSA9PT0gVW5zaWduZWRTaG9ydFR5cGUgfHxcblx0XHRcdFx0XHRcdHRhcmdldFR5cGUgPT09IFVuc2lnbmVkSW50MjQ4VHlwZSB8fFxuXHRcdFx0XHRcdFx0dGFyZ2V0VHlwZSA9PT0gVW5zaWduZWRTaG9ydDQ0NDRUeXBlIHx8XG5cdFx0XHRcdFx0XHR0YXJnZXRUeXBlID09PSBVbnNpZ25lZFNob3J0NTU1MVR5cGU7XG5cblx0XHRcdFx0XHRjb25zdCBjbGVhckNvbG9yID0gYmFja2dyb3VuZC5nZXRDbGVhckNvbG9yKCk7XG5cdFx0XHRcdFx0Y29uc3QgYSA9IGJhY2tncm91bmQuZ2V0Q2xlYXJBbHBoYSgpO1xuXHRcdFx0XHRcdGNvbnN0IHIgPSBjbGVhckNvbG9yLnI7XG5cdFx0XHRcdFx0Y29uc3QgZyA9IGNsZWFyQ29sb3IuZztcblx0XHRcdFx0XHRjb25zdCBiID0gY2xlYXJDb2xvci5iO1xuXG5cdFx0XHRcdFx0aWYgKCBpc1Vuc2lnbmVkVHlwZSApIHtcblxuXHRcdFx0XHRcdFx0dWludENsZWFyQ29sb3JbIDAgXSA9IHI7XG5cdFx0XHRcdFx0XHR1aW50Q2xlYXJDb2xvclsgMSBdID0gZztcblx0XHRcdFx0XHRcdHVpbnRDbGVhckNvbG9yWyAyIF0gPSBiO1xuXHRcdFx0XHRcdFx0dWludENsZWFyQ29sb3JbIDMgXSA9IGE7XG5cdFx0XHRcdFx0XHRfZ2wuY2xlYXJCdWZmZXJ1aXYoIF9nbC5DT0xPUiwgMCwgdWludENsZWFyQ29sb3IgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGludENsZWFyQ29sb3JbIDAgXSA9IHI7XG5cdFx0XHRcdFx0XHRpbnRDbGVhckNvbG9yWyAxIF0gPSBnO1xuXHRcdFx0XHRcdFx0aW50Q2xlYXJDb2xvclsgMiBdID0gYjtcblx0XHRcdFx0XHRcdGludENsZWFyQ29sb3JbIDMgXSA9IGE7XG5cdFx0XHRcdFx0XHRfZ2wuY2xlYXJCdWZmZXJpdiggX2dsLkNPTE9SLCAwLCBpbnRDbGVhckNvbG9yICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGJpdHMgfD0gX2dsLkNPTE9SX0JVRkZFUl9CSVQ7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggZGVwdGggKSBiaXRzIHw9IF9nbC5ERVBUSF9CVUZGRVJfQklUO1xuXHRcdFx0aWYgKCBzdGVuY2lsICkge1xuXG5cdFx0XHRcdGJpdHMgfD0gX2dsLlNURU5DSUxfQlVGRkVSX0JJVDtcblx0XHRcdFx0dGhpcy5zdGF0ZS5idWZmZXJzLnN0ZW5jaWwuc2V0TWFzayggMHhmZmZmZmZmZiApO1xuXG5cdFx0XHR9XG5cblx0XHRcdF9nbC5jbGVhciggYml0cyApO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuY2xlYXJDb2xvciA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0dGhpcy5jbGVhciggdHJ1ZSwgZmFsc2UsIGZhbHNlICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5jbGVhckRlcHRoID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHR0aGlzLmNsZWFyKCBmYWxzZSwgdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmNsZWFyU3RlbmNpbCA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0dGhpcy5jbGVhciggZmFsc2UsIGZhbHNlLCB0cnVlICk7XG5cblx0XHR9O1xuXG5cdFx0Ly9cblxuXHRcdHRoaXMuZGlzcG9zZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0Y2FudmFzLnJlbW92ZUV2ZW50TGlzdGVuZXIoICd3ZWJnbGNvbnRleHRsb3N0Jywgb25Db250ZXh0TG9zdCwgZmFsc2UgKTtcblx0XHRcdGNhbnZhcy5yZW1vdmVFdmVudExpc3RlbmVyKCAnd2ViZ2xjb250ZXh0cmVzdG9yZWQnLCBvbkNvbnRleHRSZXN0b3JlLCBmYWxzZSApO1xuXHRcdFx0Y2FudmFzLnJlbW92ZUV2ZW50TGlzdGVuZXIoICd3ZWJnbGNvbnRleHRjcmVhdGlvbmVycm9yJywgb25Db250ZXh0Q3JlYXRpb25FcnJvciwgZmFsc2UgKTtcblxuXHRcdFx0cmVuZGVyTGlzdHMuZGlzcG9zZSgpO1xuXHRcdFx0cmVuZGVyU3RhdGVzLmRpc3Bvc2UoKTtcblx0XHRcdHByb3BlcnRpZXMuZGlzcG9zZSgpO1xuXHRcdFx0Y3ViZW1hcHMuZGlzcG9zZSgpO1xuXHRcdFx0Y3ViZXV2bWFwcy5kaXNwb3NlKCk7XG5cdFx0XHRvYmplY3RzLmRpc3Bvc2UoKTtcblx0XHRcdGJpbmRpbmdTdGF0ZXMuZGlzcG9zZSgpO1xuXHRcdFx0dW5pZm9ybXNHcm91cHMuZGlzcG9zZSgpO1xuXHRcdFx0cHJvZ3JhbUNhY2hlLmRpc3Bvc2UoKTtcblxuXHRcdFx0eHIuZGlzcG9zZSgpO1xuXG5cdFx0XHR4ci5yZW1vdmVFdmVudExpc3RlbmVyKCAnc2Vzc2lvbnN0YXJ0Jywgb25YUlNlc3Npb25TdGFydCApO1xuXHRcdFx0eHIucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3Nlc3Npb25lbmQnLCBvblhSU2Vzc2lvbkVuZCApO1xuXG5cdFx0XHRhbmltYXRpb24uc3RvcCgpO1xuXG5cdFx0fTtcblxuXHRcdC8vIEV2ZW50c1xuXG5cdFx0ZnVuY3Rpb24gb25Db250ZXh0TG9zdCggZXZlbnQgKSB7XG5cblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRcdGNvbnNvbGUubG9nKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQ29udGV4dCBMb3N0LicgKTtcblxuXHRcdFx0X2lzQ29udGV4dExvc3QgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gb25Db250ZXh0UmVzdG9yZSggLyogZXZlbnQgKi8gKSB7XG5cblx0XHRcdGNvbnNvbGUubG9nKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQ29udGV4dCBSZXN0b3JlZC4nICk7XG5cblx0XHRcdF9pc0NvbnRleHRMb3N0ID0gZmFsc2U7XG5cblx0XHRcdGNvbnN0IGluZm9BdXRvUmVzZXQgPSBpbmZvLmF1dG9SZXNldDtcblx0XHRcdGNvbnN0IHNoYWRvd01hcEVuYWJsZWQgPSBzaGFkb3dNYXAuZW5hYmxlZDtcblx0XHRcdGNvbnN0IHNoYWRvd01hcEF1dG9VcGRhdGUgPSBzaGFkb3dNYXAuYXV0b1VwZGF0ZTtcblx0XHRcdGNvbnN0IHNoYWRvd01hcE5lZWRzVXBkYXRlID0gc2hhZG93TWFwLm5lZWRzVXBkYXRlO1xuXHRcdFx0Y29uc3Qgc2hhZG93TWFwVHlwZSA9IHNoYWRvd01hcC50eXBlO1xuXG5cdFx0XHRpbml0R0xDb250ZXh0KCk7XG5cblx0XHRcdGluZm8uYXV0b1Jlc2V0ID0gaW5mb0F1dG9SZXNldDtcblx0XHRcdHNoYWRvd01hcC5lbmFibGVkID0gc2hhZG93TWFwRW5hYmxlZDtcblx0XHRcdHNoYWRvd01hcC5hdXRvVXBkYXRlID0gc2hhZG93TWFwQXV0b1VwZGF0ZTtcblx0XHRcdHNoYWRvd01hcC5uZWVkc1VwZGF0ZSA9IHNoYWRvd01hcE5lZWRzVXBkYXRlO1xuXHRcdFx0c2hhZG93TWFwLnR5cGUgPSBzaGFkb3dNYXBUeXBlO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gb25Db250ZXh0Q3JlYXRpb25FcnJvciggZXZlbnQgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBBIFdlYkdMIGNvbnRleHQgY291bGQgbm90IGJlIGNyZWF0ZWQuIFJlYXNvbjogJywgZXZlbnQuc3RhdHVzTWVzc2FnZSApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gb25NYXRlcmlhbERpc3Bvc2UoIGV2ZW50ICkge1xuXG5cdFx0XHRjb25zdCBtYXRlcmlhbCA9IGV2ZW50LnRhcmdldDtcblxuXHRcdFx0bWF0ZXJpYWwucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvbk1hdGVyaWFsRGlzcG9zZSApO1xuXG5cdFx0XHRkZWFsbG9jYXRlTWF0ZXJpYWwoIG1hdGVyaWFsICk7XG5cblx0XHR9XG5cblx0XHQvLyBCdWZmZXIgZGVhbGxvY2F0aW9uXG5cblx0XHRmdW5jdGlvbiBkZWFsbG9jYXRlTWF0ZXJpYWwoIG1hdGVyaWFsICkge1xuXG5cdFx0XHRyZWxlYXNlTWF0ZXJpYWxQcm9ncmFtUmVmZXJlbmNlcyggbWF0ZXJpYWwgKTtcblxuXHRcdFx0cHJvcGVydGllcy5yZW1vdmUoIG1hdGVyaWFsICk7XG5cblx0XHR9XG5cblxuXHRcdGZ1bmN0aW9uIHJlbGVhc2VNYXRlcmlhbFByb2dyYW1SZWZlcmVuY2VzKCBtYXRlcmlhbCApIHtcblxuXHRcdFx0Y29uc3QgcHJvZ3JhbXMgPSBwcm9wZXJ0aWVzLmdldCggbWF0ZXJpYWwgKS5wcm9ncmFtcztcblxuXHRcdFx0aWYgKCBwcm9ncmFtcyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHByb2dyYW1zLmZvckVhY2goIGZ1bmN0aW9uICggcHJvZ3JhbSApIHtcblxuXHRcdFx0XHRcdHByb2dyYW1DYWNoZS5yZWxlYXNlUHJvZ3JhbSggcHJvZ3JhbSApO1xuXG5cdFx0XHRcdH0gKTtcblxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsLmlzU2hhZGVyTWF0ZXJpYWwgKSB7XG5cblx0XHRcdFx0XHRwcm9ncmFtQ2FjaGUucmVsZWFzZVNoYWRlckNhY2hlKCBtYXRlcmlhbCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gQnVmZmVyIHJlbmRlcmluZ1xuXG5cdFx0dGhpcy5yZW5kZXJCdWZmZXJEaXJlY3QgPSBmdW5jdGlvbiAoIGNhbWVyYSwgc2NlbmUsIGdlb21ldHJ5LCBtYXRlcmlhbCwgb2JqZWN0LCBncm91cCApIHtcblxuXHRcdFx0aWYgKCBzY2VuZSA9PT0gbnVsbCApIHNjZW5lID0gX2VtcHR5U2NlbmU7IC8vIHJlbmRlckJ1ZmZlckRpcmVjdCBzZWNvbmQgcGFyYW1ldGVyIHVzZWQgdG8gYmUgZm9nIChjb3VsZCBiZSBudWxsKVxuXG5cdFx0XHRjb25zdCBmcm9udEZhY2VDVyA9ICggb2JqZWN0LmlzTWVzaCAmJiBvYmplY3QubWF0cml4V29ybGQuZGV0ZXJtaW5hbnQoKSA8IDAgKTtcblxuXHRcdFx0Y29uc3QgcHJvZ3JhbSA9IHNldFByb2dyYW0oIGNhbWVyYSwgc2NlbmUsIGdlb21ldHJ5LCBtYXRlcmlhbCwgb2JqZWN0ICk7XG5cblx0XHRcdHN0YXRlLnNldE1hdGVyaWFsKCBtYXRlcmlhbCwgZnJvbnRGYWNlQ1cgKTtcblxuXHRcdFx0Ly9cblxuXHRcdFx0bGV0IGluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XG5cdFx0XHRsZXQgcmFuZ2VGYWN0b3IgPSAxO1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLndpcmVmcmFtZSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRpbmRleCA9IGdlb21ldHJpZXMuZ2V0V2lyZWZyYW1lQXR0cmlidXRlKCBnZW9tZXRyeSApO1xuXG5cdFx0XHRcdGlmICggaW5kZXggPT09IHVuZGVmaW5lZCApIHJldHVybjtcblxuXHRcdFx0XHRyYW5nZUZhY3RvciA9IDI7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9cblxuXHRcdFx0Y29uc3QgZHJhd1JhbmdlID0gZ2VvbWV0cnkuZHJhd1JhbmdlO1xuXHRcdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXG5cdFx0XHRsZXQgZHJhd1N0YXJ0ID0gZHJhd1JhbmdlLnN0YXJ0ICogcmFuZ2VGYWN0b3I7XG5cdFx0XHRsZXQgZHJhd0VuZCA9ICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKiByYW5nZUZhY3RvcjtcblxuXHRcdFx0aWYgKCBncm91cCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRkcmF3U3RhcnQgPSBNYXRoLm1heCggZHJhd1N0YXJ0LCBncm91cC5zdGFydCAqIHJhbmdlRmFjdG9yICk7XG5cdFx0XHRcdGRyYXdFbmQgPSBNYXRoLm1pbiggZHJhd0VuZCwgKCBncm91cC5zdGFydCArIGdyb3VwLmNvdW50ICkgKiByYW5nZUZhY3RvciApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XG5cblx0XHRcdFx0ZHJhd1N0YXJ0ID0gTWF0aC5tYXgoIGRyYXdTdGFydCwgMCApO1xuXHRcdFx0XHRkcmF3RW5kID0gTWF0aC5taW4oIGRyYXdFbmQsIGluZGV4LmNvdW50ICk7XG5cblx0XHRcdH0gZWxzZSBpZiAoIHBvc2l0aW9uICE9PSB1bmRlZmluZWQgJiYgcG9zaXRpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0ZHJhd1N0YXJ0ID0gTWF0aC5tYXgoIGRyYXdTdGFydCwgMCApO1xuXHRcdFx0XHRkcmF3RW5kID0gTWF0aC5taW4oIGRyYXdFbmQsIHBvc2l0aW9uLmNvdW50ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgZHJhd0NvdW50ID0gZHJhd0VuZCAtIGRyYXdTdGFydDtcblxuXHRcdFx0aWYgKCBkcmF3Q291bnQgPCAwIHx8IGRyYXdDb3VudCA9PT0gSW5maW5pdHkgKSByZXR1cm47XG5cblx0XHRcdC8vXG5cblx0XHRcdGJpbmRpbmdTdGF0ZXMuc2V0dXAoIG9iamVjdCwgbWF0ZXJpYWwsIHByb2dyYW0sIGdlb21ldHJ5LCBpbmRleCApO1xuXG5cdFx0XHRsZXQgYXR0cmlidXRlO1xuXHRcdFx0bGV0IHJlbmRlcmVyID0gYnVmZmVyUmVuZGVyZXI7XG5cblx0XHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XG5cblx0XHRcdFx0YXR0cmlidXRlID0gYXR0cmlidXRlcy5nZXQoIGluZGV4ICk7XG5cblx0XHRcdFx0cmVuZGVyZXIgPSBpbmRleGVkQnVmZmVyUmVuZGVyZXI7XG5cdFx0XHRcdHJlbmRlcmVyLnNldEluZGV4KCBhdHRyaWJ1dGUgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvL1xuXG5cdFx0XHRpZiAoIG9iamVjdC5pc01lc2ggKSB7XG5cblx0XHRcdFx0aWYgKCBtYXRlcmlhbC53aXJlZnJhbWUgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRzdGF0ZS5zZXRMaW5lV2lkdGgoIG1hdGVyaWFsLndpcmVmcmFtZUxpbmV3aWR0aCAqIGdldFRhcmdldFBpeGVsUmF0aW8oKSApO1xuXHRcdFx0XHRcdHJlbmRlcmVyLnNldE1vZGUoIF9nbC5MSU5FUyApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRyZW5kZXJlci5zZXRNb2RlKCBfZ2wuVFJJQU5HTEVTICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNMaW5lICkge1xuXG5cdFx0XHRcdGxldCBsaW5lV2lkdGggPSBtYXRlcmlhbC5saW5ld2lkdGg7XG5cblx0XHRcdFx0aWYgKCBsaW5lV2lkdGggPT09IHVuZGVmaW5lZCApIGxpbmVXaWR0aCA9IDE7IC8vIE5vdCB1c2luZyBMaW5lKk1hdGVyaWFsXG5cblx0XHRcdFx0c3RhdGUuc2V0TGluZVdpZHRoKCBsaW5lV2lkdGggKiBnZXRUYXJnZXRQaXhlbFJhdGlvKCkgKTtcblxuXHRcdFx0XHRpZiAoIG9iamVjdC5pc0xpbmVTZWdtZW50cyApIHtcblxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldE1vZGUoIF9nbC5MSU5FUyApO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0xpbmVMb29wICkge1xuXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0TW9kZSggX2dsLkxJTkVfTE9PUCApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRyZW5kZXJlci5zZXRNb2RlKCBfZ2wuTElORV9TVFJJUCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzUG9pbnRzICkge1xuXG5cdFx0XHRcdHJlbmRlcmVyLnNldE1vZGUoIF9nbC5QT0lOVFMgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzU3ByaXRlICkge1xuXG5cdFx0XHRcdHJlbmRlcmVyLnNldE1vZGUoIF9nbC5UUklBTkdMRVMgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG9iamVjdC5pc0JhdGNoZWRNZXNoICkge1xuXG5cdFx0XHRcdGlmICggb2JqZWN0Ll9tdWx0aURyYXdJbnN0YW5jZXMgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRyZW5kZXJlci5yZW5kZXJNdWx0aURyYXdJbnN0YW5jZXMoIG9iamVjdC5fbXVsdGlEcmF3U3RhcnRzLCBvYmplY3QuX211bHRpRHJhd0NvdW50cywgb2JqZWN0Ll9tdWx0aURyYXdDb3VudCwgb2JqZWN0Ll9tdWx0aURyYXdJbnN0YW5jZXMgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0aWYgKCAhIGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbXVsdGlfZHJhdycgKSApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3Qgc3RhcnRzID0gb2JqZWN0Ll9tdWx0aURyYXdTdGFydHM7XG5cdFx0XHRcdFx0XHRjb25zdCBjb3VudHMgPSBvYmplY3QuX211bHRpRHJhd0NvdW50cztcblx0XHRcdFx0XHRcdGNvbnN0IGRyYXdDb3VudCA9IG9iamVjdC5fbXVsdGlEcmF3Q291bnQ7XG5cdFx0XHRcdFx0XHRjb25zdCBieXRlc1BlckVsZW1lbnQgPSBpbmRleCA/IGF0dHJpYnV0ZXMuZ2V0KCBpbmRleCApLmJ5dGVzUGVyRWxlbWVudCA6IDE7XG5cdFx0XHRcdFx0XHRjb25zdCB1bmlmb3JtcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApLmN1cnJlbnRQcm9ncmFtLmdldFVuaWZvcm1zKCk7XG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBkcmF3Q291bnQ7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdFx0dW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ19nbF9EcmF3SUQnLCBpICk7XG5cdFx0XHRcdFx0XHRcdHJlbmRlcmVyLnJlbmRlciggc3RhcnRzWyBpIF0gLyBieXRlc1BlckVsZW1lbnQsIGNvdW50c1sgaSBdICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHJlbmRlcmVyLnJlbmRlck11bHRpRHJhdyggb2JqZWN0Ll9tdWx0aURyYXdTdGFydHMsIG9iamVjdC5fbXVsdGlEcmF3Q291bnRzLCBvYmplY3QuX211bHRpRHJhd0NvdW50ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNJbnN0YW5jZWRNZXNoICkge1xuXG5cdFx0XHRcdHJlbmRlcmVyLnJlbmRlckluc3RhbmNlcyggZHJhd1N0YXJ0LCBkcmF3Q291bnQsIG9iamVjdC5jb3VudCApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBnZW9tZXRyeS5pc0luc3RhbmNlZEJ1ZmZlckdlb21ldHJ5ICkge1xuXG5cdFx0XHRcdGNvbnN0IG1heEluc3RhbmNlQ291bnQgPSBnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudCAhPT0gdW5kZWZpbmVkID8gZ2VvbWV0cnkuX21heEluc3RhbmNlQ291bnQgOiBJbmZpbml0eTtcblx0XHRcdFx0Y29uc3QgaW5zdGFuY2VDb3VudCA9IE1hdGgubWluKCBnZW9tZXRyeS5pbnN0YW5jZUNvdW50LCBtYXhJbnN0YW5jZUNvdW50ICk7XG5cblx0XHRcdFx0cmVuZGVyZXIucmVuZGVySW5zdGFuY2VzKCBkcmF3U3RhcnQsIGRyYXdDb3VudCwgaW5zdGFuY2VDb3VudCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHJlbmRlcmVyLnJlbmRlciggZHJhd1N0YXJ0LCBkcmF3Q291bnQgKTtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdC8vIENvbXBpbGVcblxuXHRcdGZ1bmN0aW9uIHByZXBhcmVNYXRlcmlhbCggbWF0ZXJpYWwsIHNjZW5lLCBvYmplY3QgKSB7XG5cblx0XHRcdGlmICggbWF0ZXJpYWwudHJhbnNwYXJlbnQgPT09IHRydWUgJiYgbWF0ZXJpYWwuc2lkZSA9PT0gRG91YmxlU2lkZSAmJiBtYXRlcmlhbC5mb3JjZVNpbmdsZVBhc3MgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBCYWNrU2lkZTtcblx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xuXHRcdFx0XHRnZXRQcm9ncmFtKCBtYXRlcmlhbCwgc2NlbmUsIG9iamVjdCApO1xuXG5cdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBGcm9udFNpZGU7XG5cdFx0XHRcdG1hdGVyaWFsLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblx0XHRcdFx0Z2V0UHJvZ3JhbSggbWF0ZXJpYWwsIHNjZW5lLCBvYmplY3QgKTtcblxuXHRcdFx0XHRtYXRlcmlhbC5zaWRlID0gRG91YmxlU2lkZTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRnZXRQcm9ncmFtKCBtYXRlcmlhbCwgc2NlbmUsIG9iamVjdCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHR0aGlzLmNvbXBpbGUgPSBmdW5jdGlvbiAoIHNjZW5lLCBjYW1lcmEsIHRhcmdldFNjZW5lID0gbnVsbCApIHtcblxuXHRcdFx0aWYgKCB0YXJnZXRTY2VuZSA9PT0gbnVsbCApIHRhcmdldFNjZW5lID0gc2NlbmU7XG5cblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IHJlbmRlclN0YXRlcy5nZXQoIHRhcmdldFNjZW5lICk7XG5cdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUuaW5pdCggY2FtZXJhICk7XG5cblx0XHRcdHJlbmRlclN0YXRlU3RhY2sucHVzaCggY3VycmVudFJlbmRlclN0YXRlICk7XG5cblx0XHRcdC8vIGdhdGhlciBsaWdodHMgZnJvbSBib3RoIHRoZSB0YXJnZXQgc2NlbmUgYW5kIHRoZSBuZXcgb2JqZWN0IHRoYXQgd2lsbCBiZSBhZGRlZCB0byB0aGUgc2NlbmUuXG5cblx0XHRcdHRhcmdldFNjZW5lLnRyYXZlcnNlVmlzaWJsZSggZnVuY3Rpb24gKCBvYmplY3QgKSB7XG5cblx0XHRcdFx0aWYgKCBvYmplY3QuaXNMaWdodCAmJiBvYmplY3QubGF5ZXJzLnRlc3QoIGNhbWVyYS5sYXllcnMgKSApIHtcblxuXHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5wdXNoTGlnaHQoIG9iamVjdCApO1xuXG5cdFx0XHRcdFx0aWYgKCBvYmplY3QuY2FzdFNoYWRvdyApIHtcblxuXHRcdFx0XHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLnB1c2hTaGFkb3coIG9iamVjdCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSApO1xuXG5cdFx0XHRpZiAoIHNjZW5lICE9PSB0YXJnZXRTY2VuZSApIHtcblxuXHRcdFx0XHRzY2VuZS50cmF2ZXJzZVZpc2libGUoIGZ1bmN0aW9uICggb2JqZWN0ICkge1xuXG5cdFx0XHRcdFx0aWYgKCBvYmplY3QuaXNMaWdodCAmJiBvYmplY3QubGF5ZXJzLnRlc3QoIGNhbWVyYS5sYXllcnMgKSApIHtcblxuXHRcdFx0XHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLnB1c2hMaWdodCggb2JqZWN0ICk7XG5cblx0XHRcdFx0XHRcdGlmICggb2JqZWN0LmNhc3RTaGFkb3cgKSB7XG5cblx0XHRcdFx0XHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLnB1c2hTaGFkb3coIG9iamVjdCApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5zZXR1cExpZ2h0cygpO1xuXG5cdFx0XHQvLyBPbmx5IGluaXRpYWxpemUgbWF0ZXJpYWxzIGluIHRoZSBuZXcgc2NlbmUsIG5vdCB0aGUgdGFyZ2V0U2NlbmUuXG5cblx0XHRcdGNvbnN0IG1hdGVyaWFscyA9IG5ldyBTZXQoKTtcblxuXHRcdFx0c2NlbmUudHJhdmVyc2UoIGZ1bmN0aW9uICggb2JqZWN0ICkge1xuXG5cdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gb2JqZWN0Lm1hdGVyaWFsO1xuXG5cdFx0XHRcdGlmICggbWF0ZXJpYWwgKSB7XG5cblx0XHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsICkgKSB7XG5cblx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG1hdGVyaWFsLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0XHRjb25zdCBtYXRlcmlhbDIgPSBtYXRlcmlhbFsgaSBdO1xuXG5cdFx0XHRcdFx0XHRcdHByZXBhcmVNYXRlcmlhbCggbWF0ZXJpYWwyLCB0YXJnZXRTY2VuZSwgb2JqZWN0ICk7XG5cdFx0XHRcdFx0XHRcdG1hdGVyaWFscy5hZGQoIG1hdGVyaWFsMiApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRwcmVwYXJlTWF0ZXJpYWwoIG1hdGVyaWFsLCB0YXJnZXRTY2VuZSwgb2JqZWN0ICk7XG5cdFx0XHRcdFx0XHRtYXRlcmlhbHMuYWRkKCBtYXRlcmlhbCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSApO1xuXG5cdFx0XHRyZW5kZXJTdGF0ZVN0YWNrLnBvcCgpO1xuXHRcdFx0Y3VycmVudFJlbmRlclN0YXRlID0gbnVsbDtcblxuXHRcdFx0cmV0dXJuIG1hdGVyaWFscztcblxuXHRcdH07XG5cblx0XHQvLyBjb21waWxlQXN5bmNcblxuXHRcdHRoaXMuY29tcGlsZUFzeW5jID0gZnVuY3Rpb24gKCBzY2VuZSwgY2FtZXJhLCB0YXJnZXRTY2VuZSA9IG51bGwgKSB7XG5cblx0XHRcdGNvbnN0IG1hdGVyaWFscyA9IHRoaXMuY29tcGlsZSggc2NlbmUsIGNhbWVyYSwgdGFyZ2V0U2NlbmUgKTtcblxuXHRcdFx0Ly8gV2FpdCBmb3IgYWxsIHRoZSBtYXRlcmlhbHMgaW4gdGhlIG5ldyBvYmplY3QgdG8gaW5kaWNhdGUgdGhhdCB0aGV5J3JlXG5cdFx0XHQvLyByZWFkeSB0byBiZSB1c2VkIGJlZm9yZSByZXNvbHZpbmcgdGhlIHByb21pc2UuXG5cblx0XHRcdHJldHVybiBuZXcgUHJvbWlzZSggKCByZXNvbHZlICkgPT4ge1xuXG5cdFx0XHRcdGZ1bmN0aW9uIGNoZWNrTWF0ZXJpYWxzUmVhZHkoKSB7XG5cblx0XHRcdFx0XHRtYXRlcmlhbHMuZm9yRWFjaCggZnVuY3Rpb24gKCBtYXRlcmlhbCApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgbWF0ZXJpYWxQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICk7XG5cdFx0XHRcdFx0XHRjb25zdCBwcm9ncmFtID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLmN1cnJlbnRQcm9ncmFtO1xuXG5cdFx0XHRcdFx0XHRpZiAoIHByb2dyYW0uaXNSZWFkeSgpICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIHJlbW92ZSBhbnkgcHJvZ3JhbXMgdGhhdCByZXBvcnQgdGhleSdyZSByZWFkeSB0byB1c2UgZnJvbSB0aGUgbGlzdFxuXHRcdFx0XHRcdFx0XHRtYXRlcmlhbHMuZGVsZXRlKCBtYXRlcmlhbCApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0XHQvLyBvbmNlIHRoZSBsaXN0IG9mIGNvbXBpbGluZyBtYXRlcmlhbHMgaXMgZW1wdHksIGNhbGwgdGhlIGNhbGxiYWNrXG5cblx0XHRcdFx0XHRpZiAoIG1hdGVyaWFscy5zaXplID09PSAwICkge1xuXG5cdFx0XHRcdFx0XHRyZXNvbHZlKCBzY2VuZSApO1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gaWYgc29tZSBtYXRlcmlhbHMgYXJlIHN0aWxsIG5vdCByZWFkeSwgd2FpdCBhIGJpdCBhbmQgY2hlY2sgYWdhaW5cblxuXHRcdFx0XHRcdHNldFRpbWVvdXQoIGNoZWNrTWF0ZXJpYWxzUmVhZHksIDEwICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggZXh0ZW5zaW9ucy5nZXQoICdLSFJfcGFyYWxsZWxfc2hhZGVyX2NvbXBpbGUnICkgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHQvLyBJZiB3ZSBjYW4gY2hlY2sgdGhlIGNvbXBpbGF0aW9uIHN0YXR1cyBvZiB0aGUgbWF0ZXJpYWxzIHdpdGhvdXRcblx0XHRcdFx0XHQvLyBibG9ja2luZyB0aGVuIGRvIHNvIHJpZ2h0IGF3YXkuXG5cblx0XHRcdFx0XHRjaGVja01hdGVyaWFsc1JlYWR5KCk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdC8vIE90aGVyd2lzZSBzdGFydCBieSB3YWl0aW5nIGEgYml0IHRvIGdpdmUgdGhlIG1hdGVyaWFscyB3ZSBqdXN0XG5cdFx0XHRcdFx0Ly8gaW5pdGlhbGl6ZWQgYSBjaGFuY2UgdG8gZmluaXNoLlxuXG5cdFx0XHRcdFx0c2V0VGltZW91dCggY2hlY2tNYXRlcmlhbHNSZWFkeSwgMTAgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gKTtcblxuXHRcdH07XG5cblx0XHQvLyBBbmltYXRpb24gTG9vcFxuXG5cdFx0bGV0IG9uQW5pbWF0aW9uRnJhbWVDYWxsYmFjayA9IG51bGw7XG5cblx0XHRmdW5jdGlvbiBvbkFuaW1hdGlvbkZyYW1lKCB0aW1lICkge1xuXG5cdFx0XHRpZiAoIG9uQW5pbWF0aW9uRnJhbWVDYWxsYmFjayApIG9uQW5pbWF0aW9uRnJhbWVDYWxsYmFjayggdGltZSApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gb25YUlNlc3Npb25TdGFydCgpIHtcblxuXHRcdFx0YW5pbWF0aW9uLnN0b3AoKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uWFJTZXNzaW9uRW5kKCkge1xuXG5cdFx0XHRhbmltYXRpb24uc3RhcnQoKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGFuaW1hdGlvbiA9IG5ldyBXZWJHTEFuaW1hdGlvbigpO1xuXHRcdGFuaW1hdGlvbi5zZXRBbmltYXRpb25Mb29wKCBvbkFuaW1hdGlvbkZyYW1lICk7XG5cblx0XHRpZiAoIHR5cGVvZiBzZWxmICE9PSAndW5kZWZpbmVkJyApIGFuaW1hdGlvbi5zZXRDb250ZXh0KCBzZWxmICk7XG5cblx0XHR0aGlzLnNldEFuaW1hdGlvbkxvb3AgPSBmdW5jdGlvbiAoIGNhbGxiYWNrICkge1xuXG5cdFx0XHRvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2sgPSBjYWxsYmFjaztcblx0XHRcdHhyLnNldEFuaW1hdGlvbkxvb3AoIGNhbGxiYWNrICk7XG5cblx0XHRcdCggY2FsbGJhY2sgPT09IG51bGwgKSA/IGFuaW1hdGlvbi5zdG9wKCkgOiBhbmltYXRpb24uc3RhcnQoKTtcblxuXHRcdH07XG5cblx0XHR4ci5hZGRFdmVudExpc3RlbmVyKCAnc2Vzc2lvbnN0YXJ0Jywgb25YUlNlc3Npb25TdGFydCApO1xuXHRcdHhyLmFkZEV2ZW50TGlzdGVuZXIoICdzZXNzaW9uZW5kJywgb25YUlNlc3Npb25FbmQgKTtcblxuXHRcdC8vIFJlbmRlcmluZ1xuXG5cdFx0dGhpcy5yZW5kZXIgPSBmdW5jdGlvbiAoIHNjZW5lLCBjYW1lcmEgKSB7XG5cblx0XHRcdGlmICggY2FtZXJhICE9PSB1bmRlZmluZWQgJiYgY2FtZXJhLmlzQ2FtZXJhICE9PSB0cnVlICkge1xuXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyLnJlbmRlcjogY2FtZXJhIGlzIG5vdCBhbiBpbnN0YW5jZSBvZiBUSFJFRS5DYW1lcmEuJyApO1xuXHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBfaXNDb250ZXh0TG9zdCA9PT0gdHJ1ZSApIHJldHVybjtcblxuXHRcdFx0Ly8gdXBkYXRlIHNjZW5lIGdyYXBoXG5cblx0XHRcdGlmICggc2NlbmUubWF0cml4V29ybGRBdXRvVXBkYXRlID09PSB0cnVlICkgc2NlbmUudXBkYXRlTWF0cml4V29ybGQoKTtcblxuXHRcdFx0Ly8gdXBkYXRlIGNhbWVyYSBtYXRyaWNlcyBhbmQgZnJ1c3R1bVxuXG5cdFx0XHRpZiAoIGNhbWVyYS5wYXJlbnQgPT09IG51bGwgJiYgY2FtZXJhLm1hdHJpeFdvcmxkQXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIGNhbWVyYS51cGRhdGVNYXRyaXhXb3JsZCgpO1xuXG5cdFx0XHRpZiAoIHhyLmVuYWJsZWQgPT09IHRydWUgJiYgeHIuaXNQcmVzZW50aW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdGlmICggeHIuY2FtZXJhQXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIHhyLnVwZGF0ZUNhbWVyYSggY2FtZXJhICk7XG5cblx0XHRcdFx0Y2FtZXJhID0geHIuZ2V0Q2FtZXJhKCk7IC8vIHVzZSBYUiBjYW1lcmEgZm9yIHJlbmRlcmluZ1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vXG5cdFx0XHRpZiAoIHNjZW5lLmlzU2NlbmUgPT09IHRydWUgKSBzY2VuZS5vbkJlZm9yZVJlbmRlciggX3RoaXMsIHNjZW5lLCBjYW1lcmEsIF9jdXJyZW50UmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IHJlbmRlclN0YXRlcy5nZXQoIHNjZW5lLCByZW5kZXJTdGF0ZVN0YWNrLmxlbmd0aCApO1xuXHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLmluaXQoIGNhbWVyYSApO1xuXG5cdFx0XHRyZW5kZXJTdGF0ZVN0YWNrLnB1c2goIGN1cnJlbnRSZW5kZXJTdGF0ZSApO1xuXG5cdFx0XHRfcHJvalNjcmVlbk1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeCwgY2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSApO1xuXHRcdFx0X2ZydXN0dW0uc2V0RnJvbVByb2plY3Rpb25NYXRyaXgoIF9wcm9qU2NyZWVuTWF0cml4ICk7XG5cblx0XHRcdF9sb2NhbENsaXBwaW5nRW5hYmxlZCA9IHRoaXMubG9jYWxDbGlwcGluZ0VuYWJsZWQ7XG5cdFx0XHRfY2xpcHBpbmdFbmFibGVkID0gY2xpcHBpbmcuaW5pdCggdGhpcy5jbGlwcGluZ1BsYW5lcywgX2xvY2FsQ2xpcHBpbmdFbmFibGVkICk7XG5cblx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0ID0gcmVuZGVyTGlzdHMuZ2V0KCBzY2VuZSwgcmVuZGVyTGlzdFN0YWNrLmxlbmd0aCApO1xuXHRcdFx0Y3VycmVudFJlbmRlckxpc3QuaW5pdCgpO1xuXG5cdFx0XHRyZW5kZXJMaXN0U3RhY2sucHVzaCggY3VycmVudFJlbmRlckxpc3QgKTtcblxuXHRcdFx0aWYgKCB4ci5lbmFibGVkID09PSB0cnVlICYmIHhyLmlzUHJlc2VudGluZyA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRjb25zdCBkZXB0aFNlbnNpbmdNZXNoID0gX3RoaXMueHIuZ2V0RGVwdGhTZW5zaW5nTWVzaCgpO1xuXG5cdFx0XHRcdGlmICggZGVwdGhTZW5zaW5nTWVzaCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdHByb2plY3RPYmplY3QoIGRlcHRoU2Vuc2luZ01lc2gsIGNhbWVyYSwgLSBJbmZpbml0eSwgX3RoaXMuc29ydE9iamVjdHMgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0cHJvamVjdE9iamVjdCggc2NlbmUsIGNhbWVyYSwgMCwgX3RoaXMuc29ydE9iamVjdHMgKTtcblxuXHRcdFx0Y3VycmVudFJlbmRlckxpc3QuZmluaXNoKCk7XG5cblx0XHRcdGlmICggX3RoaXMuc29ydE9iamVjdHMgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3Quc29ydCggX29wYXF1ZVNvcnQsIF90cmFuc3BhcmVudFNvcnQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRfcmVuZGVyQmFja2dyb3VuZCA9IHhyLmVuYWJsZWQgPT09IGZhbHNlIHx8IHhyLmlzUHJlc2VudGluZyA9PT0gZmFsc2UgfHwgeHIuaGFzRGVwdGhTZW5zaW5nKCkgPT09IGZhbHNlO1xuXHRcdFx0aWYgKCBfcmVuZGVyQmFja2dyb3VuZCApIHtcblxuXHRcdFx0XHRiYWNrZ3JvdW5kLmFkZFRvUmVuZGVyTGlzdCggY3VycmVudFJlbmRlckxpc3QsIHNjZW5lICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9cblxuXHRcdFx0dGhpcy5pbmZvLnJlbmRlci5mcmFtZSArKztcblxuXHRcdFx0aWYgKCBfY2xpcHBpbmdFbmFibGVkID09PSB0cnVlICkgY2xpcHBpbmcuYmVnaW5TaGFkb3dzKCk7XG5cblx0XHRcdGNvbnN0IHNoYWRvd3NBcnJheSA9IGN1cnJlbnRSZW5kZXJTdGF0ZS5zdGF0ZS5zaGFkb3dzQXJyYXk7XG5cblx0XHRcdHNoYWRvd01hcC5yZW5kZXIoIHNoYWRvd3NBcnJheSwgc2NlbmUsIGNhbWVyYSApO1xuXG5cdFx0XHRpZiAoIF9jbGlwcGluZ0VuYWJsZWQgPT09IHRydWUgKSBjbGlwcGluZy5lbmRTaGFkb3dzKCk7XG5cblx0XHRcdC8vXG5cblx0XHRcdGlmICggdGhpcy5pbmZvLmF1dG9SZXNldCA9PT0gdHJ1ZSApIHRoaXMuaW5mby5yZXNldCgpO1xuXG5cdFx0XHQvLyByZW5kZXIgc2NlbmVcblxuXHRcdFx0Y29uc3Qgb3BhcXVlT2JqZWN0cyA9IGN1cnJlbnRSZW5kZXJMaXN0Lm9wYXF1ZTtcblx0XHRcdGNvbnN0IHRyYW5zbWlzc2l2ZU9iamVjdHMgPSBjdXJyZW50UmVuZGVyTGlzdC50cmFuc21pc3NpdmU7XG5cblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5zZXR1cExpZ2h0cygpO1xuXG5cdFx0XHRpZiAoIGNhbWVyYS5pc0FycmF5Q2FtZXJhICkge1xuXG5cdFx0XHRcdGNvbnN0IGNhbWVyYXMgPSBjYW1lcmEuY2FtZXJhcztcblxuXHRcdFx0XHRpZiAoIHRyYW5zbWlzc2l2ZU9iamVjdHMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNhbWVyYXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgY2FtZXJhMiA9IGNhbWVyYXNbIGkgXTtcblxuXHRcdFx0XHRcdFx0cmVuZGVyVHJhbnNtaXNzaW9uUGFzcyggb3BhcXVlT2JqZWN0cywgdHJhbnNtaXNzaXZlT2JqZWN0cywgc2NlbmUsIGNhbWVyYTIgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBfcmVuZGVyQmFja2dyb3VuZCApIGJhY2tncm91bmQucmVuZGVyKCBzY2VuZSApO1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNhbWVyYXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGNhbWVyYTIgPSBjYW1lcmFzWyBpIF07XG5cblx0XHRcdFx0XHRyZW5kZXJTY2VuZSggY3VycmVudFJlbmRlckxpc3QsIHNjZW5lLCBjYW1lcmEyLCBjYW1lcmEyLnZpZXdwb3J0ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGlmICggdHJhbnNtaXNzaXZlT2JqZWN0cy5sZW5ndGggPiAwICkgcmVuZGVyVHJhbnNtaXNzaW9uUGFzcyggb3BhcXVlT2JqZWN0cywgdHJhbnNtaXNzaXZlT2JqZWN0cywgc2NlbmUsIGNhbWVyYSApO1xuXG5cdFx0XHRcdGlmICggX3JlbmRlckJhY2tncm91bmQgKSBiYWNrZ3JvdW5kLnJlbmRlciggc2NlbmUgKTtcblxuXHRcdFx0XHRyZW5kZXJTY2VuZSggY3VycmVudFJlbmRlckxpc3QsIHNjZW5lLCBjYW1lcmEgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvL1xuXG5cdFx0XHRpZiAoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdC8vIHJlc29sdmUgbXVsdGlzYW1wbGUgcmVuZGVyYnVmZmVycyB0byBhIHNpbmdsZS1zYW1wbGUgdGV4dHVyZSBpZiBuZWNlc3NhcnlcblxuXHRcdFx0XHR0ZXh0dXJlcy51cGRhdGVNdWx0aXNhbXBsZVJlbmRlclRhcmdldCggX2N1cnJlbnRSZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHQvLyBHZW5lcmF0ZSBtaXBtYXAgaWYgd2UncmUgdXNpbmcgYW55IGtpbmQgb2YgbWlwbWFwIGZpbHRlcmluZ1xuXG5cdFx0XHRcdHRleHR1cmVzLnVwZGF0ZVJlbmRlclRhcmdldE1pcG1hcCggX2N1cnJlbnRSZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvL1xuXG5cdFx0XHRpZiAoIHNjZW5lLmlzU2NlbmUgPT09IHRydWUgKSBzY2VuZS5vbkFmdGVyUmVuZGVyKCBfdGhpcywgc2NlbmUsIGNhbWVyYSApO1xuXG5cdFx0XHQvLyBfZ2wuZmluaXNoKCk7XG5cblx0XHRcdGJpbmRpbmdTdGF0ZXMucmVzZXREZWZhdWx0U3RhdGUoKTtcblx0XHRcdF9jdXJyZW50TWF0ZXJpYWxJZCA9IC0gMTtcblx0XHRcdF9jdXJyZW50Q2FtZXJhID0gbnVsbDtcblxuXHRcdFx0cmVuZGVyU3RhdGVTdGFjay5wb3AoKTtcblxuXHRcdFx0aWYgKCByZW5kZXJTdGF0ZVN0YWNrLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdFx0Y3VycmVudFJlbmRlclN0YXRlID0gcmVuZGVyU3RhdGVTdGFja1sgcmVuZGVyU3RhdGVTdGFjay5sZW5ndGggLSAxIF07XG5cblx0XHRcdFx0aWYgKCBfY2xpcHBpbmdFbmFibGVkID09PSB0cnVlICkgY2xpcHBpbmcuc2V0R2xvYmFsU3RhdGUoIF90aGlzLmNsaXBwaW5nUGxhbmVzLCBjdXJyZW50UmVuZGVyU3RhdGUuc3RhdGUuY2FtZXJhICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Y3VycmVudFJlbmRlclN0YXRlID0gbnVsbDtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZW5kZXJMaXN0U3RhY2sucG9wKCk7XG5cblx0XHRcdGlmICggcmVuZGVyTGlzdFN0YWNrLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3QgPSByZW5kZXJMaXN0U3RhY2tbIHJlbmRlckxpc3RTdGFjay5sZW5ndGggLSAxIF07XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3QgPSBudWxsO1xuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdFx0ZnVuY3Rpb24gcHJvamVjdE9iamVjdCggb2JqZWN0LCBjYW1lcmEsIGdyb3VwT3JkZXIsIHNvcnRPYmplY3RzICkge1xuXG5cdFx0XHRpZiAoIG9iamVjdC52aXNpYmxlID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0Y29uc3QgdmlzaWJsZSA9IG9iamVjdC5sYXllcnMudGVzdCggY2FtZXJhLmxheWVycyApO1xuXG5cdFx0XHRpZiAoIHZpc2libGUgKSB7XG5cblx0XHRcdFx0aWYgKCBvYmplY3QuaXNHcm91cCApIHtcblxuXHRcdFx0XHRcdGdyb3VwT3JkZXIgPSBvYmplY3QucmVuZGVyT3JkZXI7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzTE9EICkge1xuXG5cdFx0XHRcdFx0aWYgKCBvYmplY3QuYXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIG9iamVjdC51cGRhdGUoIGNhbWVyYSApO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0xpZ2h0ICkge1xuXG5cdFx0XHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLnB1c2hMaWdodCggb2JqZWN0ICk7XG5cblx0XHRcdFx0XHRpZiAoIG9iamVjdC5jYXN0U2hhZG93ICkge1xuXG5cdFx0XHRcdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUucHVzaFNoYWRvdyggb2JqZWN0ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzU3ByaXRlICkge1xuXG5cdFx0XHRcdFx0aWYgKCAhIG9iamVjdC5mcnVzdHVtQ3VsbGVkIHx8IF9mcnVzdHVtLmludGVyc2VjdHNTcHJpdGUoIG9iamVjdCApICkge1xuXG5cdFx0XHRcdFx0XHRpZiAoIHNvcnRPYmplY3RzICkge1xuXG5cdFx0XHRcdFx0XHRcdF92ZWN0b3I0LnNldEZyb21NYXRyaXhQb3NpdGlvbiggb2JqZWN0Lm1hdHJpeFdvcmxkIClcblx0XHRcdFx0XHRcdFx0XHQuYXBwbHlNYXRyaXg0KCBfcHJvalNjcmVlbk1hdHJpeCApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0cy51cGRhdGUoIG9iamVjdCApO1xuXHRcdFx0XHRcdFx0Y29uc3QgbWF0ZXJpYWwgPSBvYmplY3QubWF0ZXJpYWw7XG5cblx0XHRcdFx0XHRcdGlmICggbWF0ZXJpYWwudmlzaWJsZSApIHtcblxuXHRcdFx0XHRcdFx0XHRjdXJyZW50UmVuZGVyTGlzdC5wdXNoKCBvYmplY3QsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXBPcmRlciwgX3ZlY3RvcjQueiwgbnVsbCApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzTWVzaCB8fCBvYmplY3QuaXNMaW5lIHx8IG9iamVjdC5pc1BvaW50cyApIHtcblxuXHRcdFx0XHRcdGlmICggISBvYmplY3QuZnJ1c3R1bUN1bGxlZCB8fCBfZnJ1c3R1bS5pbnRlcnNlY3RzT2JqZWN0KCBvYmplY3QgKSApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSBvYmplY3RzLnVwZGF0ZSggb2JqZWN0ICk7XG5cdFx0XHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IG9iamVjdC5tYXRlcmlhbDtcblxuXHRcdFx0XHRcdFx0aWYgKCBzb3J0T2JqZWN0cyApIHtcblxuXHRcdFx0XHRcdFx0XHRpZiAoIG9iamVjdC5ib3VuZGluZ1NwaGVyZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBvYmplY3QuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSBvYmplY3QuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XG5cdFx0XHRcdFx0XHRcdFx0X3ZlY3RvcjQuY29weSggb2JqZWN0LmJvdW5kaW5nU3BoZXJlLmNlbnRlciApO1xuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkgZ2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XG5cdFx0XHRcdFx0XHRcdFx0X3ZlY3RvcjQuY29weSggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUuY2VudGVyICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdF92ZWN0b3I0XG5cdFx0XHRcdFx0XHRcdFx0LmFwcGx5TWF0cml4NCggb2JqZWN0Lm1hdHJpeFdvcmxkIClcblx0XHRcdFx0XHRcdFx0XHQuYXBwbHlNYXRyaXg0KCBfcHJvalNjcmVlbk1hdHJpeCApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggbWF0ZXJpYWwgKSApIHtcblxuXHRcdFx0XHRcdFx0XHRjb25zdCBncm91cHMgPSBnZW9tZXRyeS5ncm91cHM7XG5cblx0XHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZ3JvdXBzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xuXHRcdFx0XHRcdFx0XHRcdGNvbnN0IGdyb3VwTWF0ZXJpYWwgPSBtYXRlcmlhbFsgZ3JvdXAubWF0ZXJpYWxJbmRleCBdO1xuXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBncm91cE1hdGVyaWFsICYmIGdyb3VwTWF0ZXJpYWwudmlzaWJsZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3QucHVzaCggb2JqZWN0LCBnZW9tZXRyeSwgZ3JvdXBNYXRlcmlhbCwgZ3JvdXBPcmRlciwgX3ZlY3RvcjQueiwgZ3JvdXAgKTtcblxuXHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLnZpc2libGUgKSB7XG5cblx0XHRcdFx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3QucHVzaCggb2JqZWN0LCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwT3JkZXIsIF92ZWN0b3I0LnosIG51bGwgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBjaGlsZHJlbiA9IG9iamVjdC5jaGlsZHJlbjtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRwcm9qZWN0T2JqZWN0KCBjaGlsZHJlblsgaSBdLCBjYW1lcmEsIGdyb3VwT3JkZXIsIHNvcnRPYmplY3RzICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHJlbmRlclNjZW5lKCBjdXJyZW50UmVuZGVyTGlzdCwgc2NlbmUsIGNhbWVyYSwgdmlld3BvcnQgKSB7XG5cblx0XHRcdGNvbnN0IG9wYXF1ZU9iamVjdHMgPSBjdXJyZW50UmVuZGVyTGlzdC5vcGFxdWU7XG5cdFx0XHRjb25zdCB0cmFuc21pc3NpdmVPYmplY3RzID0gY3VycmVudFJlbmRlckxpc3QudHJhbnNtaXNzaXZlO1xuXHRcdFx0Y29uc3QgdHJhbnNwYXJlbnRPYmplY3RzID0gY3VycmVudFJlbmRlckxpc3QudHJhbnNwYXJlbnQ7XG5cblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5zZXR1cExpZ2h0c1ZpZXcoIGNhbWVyYSApO1xuXG5cdFx0XHRpZiAoIF9jbGlwcGluZ0VuYWJsZWQgPT09IHRydWUgKSBjbGlwcGluZy5zZXRHbG9iYWxTdGF0ZSggX3RoaXMuY2xpcHBpbmdQbGFuZXMsIGNhbWVyYSApO1xuXG5cdFx0XHRpZiAoIHZpZXdwb3J0ICkgc3RhdGUudmlld3BvcnQoIF9jdXJyZW50Vmlld3BvcnQuY29weSggdmlld3BvcnQgKSApO1xuXG5cdFx0XHRpZiAoIG9wYXF1ZU9iamVjdHMubGVuZ3RoID4gMCApIHJlbmRlck9iamVjdHMoIG9wYXF1ZU9iamVjdHMsIHNjZW5lLCBjYW1lcmEgKTtcblx0XHRcdGlmICggdHJhbnNtaXNzaXZlT2JqZWN0cy5sZW5ndGggPiAwICkgcmVuZGVyT2JqZWN0cyggdHJhbnNtaXNzaXZlT2JqZWN0cywgc2NlbmUsIGNhbWVyYSApO1xuXHRcdFx0aWYgKCB0cmFuc3BhcmVudE9iamVjdHMubGVuZ3RoID4gMCApIHJlbmRlck9iamVjdHMoIHRyYW5zcGFyZW50T2JqZWN0cywgc2NlbmUsIGNhbWVyYSApO1xuXG5cdFx0XHQvLyBFbnN1cmUgZGVwdGggYnVmZmVyIHdyaXRpbmcgaXMgZW5hYmxlZCBzbyBpdCBjYW4gYmUgY2xlYXJlZCBvbiBuZXh0IHJlbmRlclxuXG5cdFx0XHRzdGF0ZS5idWZmZXJzLmRlcHRoLnNldFRlc3QoIHRydWUgKTtcblx0XHRcdHN0YXRlLmJ1ZmZlcnMuZGVwdGguc2V0TWFzayggdHJ1ZSApO1xuXHRcdFx0c3RhdGUuYnVmZmVycy5jb2xvci5zZXRNYXNrKCB0cnVlICk7XG5cblx0XHRcdHN0YXRlLnNldFBvbHlnb25PZmZzZXQoIGZhbHNlICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiByZW5kZXJUcmFuc21pc3Npb25QYXNzKCBvcGFxdWVPYmplY3RzLCB0cmFuc21pc3NpdmVPYmplY3RzLCBzY2VuZSwgY2FtZXJhICkge1xuXG5cdFx0XHRjb25zdCBvdmVycmlkZU1hdGVyaWFsID0gc2NlbmUuaXNTY2VuZSA9PT0gdHJ1ZSA/IHNjZW5lLm92ZXJyaWRlTWF0ZXJpYWwgOiBudWxsO1xuXG5cdFx0XHRpZiAoIG92ZXJyaWRlTWF0ZXJpYWwgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLnRyYW5zbWlzc2lvblJlbmRlclRhcmdldFsgY2FtZXJhLmlkIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUuc3RhdGUudHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0WyBjYW1lcmEuaWQgXSA9IG5ldyBXZWJHTFJlbmRlclRhcmdldCggMSwgMSwge1xuXHRcdFx0XHRcdGdlbmVyYXRlTWlwbWFwczogdHJ1ZSxcblx0XHRcdFx0XHR0eXBlOiAoIGV4dGVuc2lvbnMuaGFzKCAnRVhUX2NvbG9yX2J1ZmZlcl9oYWxmX2Zsb2F0JyApIHx8IGV4dGVuc2lvbnMuaGFzKCAnRVhUX2NvbG9yX2J1ZmZlcl9mbG9hdCcgKSApID8gSGFsZkZsb2F0VHlwZSA6IFVuc2lnbmVkQnl0ZVR5cGUsXG5cdFx0XHRcdFx0bWluRmlsdGVyOiBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIsXG5cdFx0XHRcdFx0c2FtcGxlczogNCxcblx0XHRcdFx0XHRzdGVuY2lsQnVmZmVyOiBzdGVuY2lsLFxuXHRcdFx0XHRcdHJlc29sdmVEZXB0aEJ1ZmZlcjogZmFsc2UsXG5cdFx0XHRcdFx0cmVzb2x2ZVN0ZW5jaWxCdWZmZXI6IGZhbHNlLFxuXHRcdFx0XHRcdGNvbG9yU3BhY2U6IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSxcblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdC8vIGRlYnVnXG5cblx0XHRcdFx0Lypcblx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgUGxhbmVHZW9tZXRyeSgpO1xuXHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBNZXNoQmFzaWNNYXRlcmlhbCggeyBtYXA6IF90cmFuc21pc3Npb25SZW5kZXJUYXJnZXQudGV4dHVyZSB9ICk7XG5cblx0XHRcdFx0Y29uc3QgbWVzaCA9IG5ldyBNZXNoKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblx0XHRcdFx0c2NlbmUuYWRkKCBtZXNoICk7XG5cdFx0XHRcdCovXG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ID0gY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLnRyYW5zbWlzc2lvblJlbmRlclRhcmdldFsgY2FtZXJhLmlkIF07XG5cblx0XHRcdGNvbnN0IGFjdGl2ZVZpZXdwb3J0ID0gY2FtZXJhLnZpZXdwb3J0IHx8IF9jdXJyZW50Vmlld3BvcnQ7XG5cdFx0XHR0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQuc2V0U2l6ZSggYWN0aXZlVmlld3BvcnQueiwgYWN0aXZlVmlld3BvcnQudyApO1xuXG5cdFx0XHQvL1xuXG5cdFx0XHRjb25zdCBjdXJyZW50UmVuZGVyVGFyZ2V0ID0gX3RoaXMuZ2V0UmVuZGVyVGFyZ2V0KCk7XG5cdFx0XHRfdGhpcy5zZXRSZW5kZXJUYXJnZXQoIHRyYW5zbWlzc2lvblJlbmRlclRhcmdldCApO1xuXG5cdFx0XHRfdGhpcy5nZXRDbGVhckNvbG9yKCBfY3VycmVudENsZWFyQ29sb3IgKTtcblx0XHRcdF9jdXJyZW50Q2xlYXJBbHBoYSA9IF90aGlzLmdldENsZWFyQWxwaGEoKTtcblx0XHRcdGlmICggX2N1cnJlbnRDbGVhckFscGhhIDwgMSApIF90aGlzLnNldENsZWFyQ29sb3IoIDB4ZmZmZmZmLCAwLjUgKTtcblxuXHRcdFx0aWYgKCBfcmVuZGVyQmFja2dyb3VuZCApIHtcblxuXHRcdFx0XHRiYWNrZ3JvdW5kLnJlbmRlciggc2NlbmUgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRfdGhpcy5jbGVhcigpO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIFR1cm4gb2ZmIHRoZSBmZWF0dXJlcyB3aGljaCBjYW4gYWZmZWN0IHRoZSBmcmFnIGNvbG9yIGZvciBvcGFxdWUgb2JqZWN0cyBwYXNzLlxuXHRcdFx0Ly8gT3RoZXJ3aXNlIHRoZXkgYXJlIGFwcGxpZWQgdHdpY2UgaW4gb3BhcXVlIG9iamVjdHMgcGFzcyBhbmQgdHJhbnNtaXNzaW9uIG9iamVjdHMgcGFzcy5cblx0XHRcdGNvbnN0IGN1cnJlbnRUb25lTWFwcGluZyA9IF90aGlzLnRvbmVNYXBwaW5nO1xuXHRcdFx0X3RoaXMudG9uZU1hcHBpbmcgPSBOb1RvbmVNYXBwaW5nO1xuXG5cdFx0XHQvLyBSZW1vdmUgdmlld3BvcnQgZnJvbSBjYW1lcmEgdG8gYXZvaWQgbmVzdGVkIHJlbmRlciBjYWxscyByZXNldHRpbmcgdmlld3BvcnQgdG8gaXQgKGUuZyBSZWZsZWN0b3IpLlxuXHRcdFx0Ly8gVHJhbnNtaXNzaW9uIHJlbmRlciBwYXNzIHJlcXVpcmVzIHZpZXdwb3J0IHRvIG1hdGNoIHRoZSB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQuXG5cdFx0XHRjb25zdCBjdXJyZW50Q2FtZXJhVmlld3BvcnQgPSBjYW1lcmEudmlld3BvcnQ7XG5cdFx0XHRpZiAoIGNhbWVyYS52aWV3cG9ydCAhPT0gdW5kZWZpbmVkICkgY2FtZXJhLnZpZXdwb3J0ID0gdW5kZWZpbmVkO1xuXG5cdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUuc2V0dXBMaWdodHNWaWV3KCBjYW1lcmEgKTtcblxuXHRcdFx0aWYgKCBfY2xpcHBpbmdFbmFibGVkID09PSB0cnVlICkgY2xpcHBpbmcuc2V0R2xvYmFsU3RhdGUoIF90aGlzLmNsaXBwaW5nUGxhbmVzLCBjYW1lcmEgKTtcblxuXHRcdFx0cmVuZGVyT2JqZWN0cyggb3BhcXVlT2JqZWN0cywgc2NlbmUsIGNhbWVyYSApO1xuXG5cdFx0XHR0ZXh0dXJlcy51cGRhdGVNdWx0aXNhbXBsZVJlbmRlclRhcmdldCggdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICk7XG5cdFx0XHR0ZXh0dXJlcy51cGRhdGVSZW5kZXJUYXJnZXRNaXBtYXAoIHRyYW5zbWlzc2lvblJlbmRlclRhcmdldCApO1xuXG5cdFx0XHRpZiAoIGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfbXVsdGlzYW1wbGVkX3JlbmRlcl90b190ZXh0dXJlJyApID09PSBmYWxzZSApIHsgLy8gc2VlICMyODEzMVxuXG5cdFx0XHRcdGxldCByZW5kZXJUYXJnZXROZWVkc1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRyYW5zbWlzc2l2ZU9iamVjdHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IHJlbmRlckl0ZW0gPSB0cmFuc21pc3NpdmVPYmplY3RzWyBpIF07XG5cblx0XHRcdFx0XHRjb25zdCBvYmplY3QgPSByZW5kZXJJdGVtLm9iamVjdDtcblx0XHRcdFx0XHRjb25zdCBnZW9tZXRyeSA9IHJlbmRlckl0ZW0uZ2VvbWV0cnk7XG5cdFx0XHRcdFx0Y29uc3QgbWF0ZXJpYWwgPSByZW5kZXJJdGVtLm1hdGVyaWFsO1xuXHRcdFx0XHRcdGNvbnN0IGdyb3VwID0gcmVuZGVySXRlbS5ncm91cDtcblxuXHRcdFx0XHRcdGlmICggbWF0ZXJpYWwuc2lkZSA9PT0gRG91YmxlU2lkZSAmJiBvYmplY3QubGF5ZXJzLnRlc3QoIGNhbWVyYS5sYXllcnMgKSApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgY3VycmVudFNpZGUgPSBtYXRlcmlhbC5zaWRlO1xuXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC5zaWRlID0gQmFja1NpZGU7XG5cdFx0XHRcdFx0XHRtYXRlcmlhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdFx0XHRcdHJlbmRlck9iamVjdCggb2JqZWN0LCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwICk7XG5cblx0XHRcdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBjdXJyZW50U2lkZTtcblx0XHRcdFx0XHRcdG1hdGVyaWFsLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdFx0XHRcdFx0cmVuZGVyVGFyZ2V0TmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIHJlbmRlclRhcmdldE5lZWRzVXBkYXRlID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0dGV4dHVyZXMudXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQoIHRyYW5zbWlzc2lvblJlbmRlclRhcmdldCApO1xuXHRcdFx0XHRcdHRleHR1cmVzLnVwZGF0ZVJlbmRlclRhcmdldE1pcG1hcCggdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdF90aGlzLnNldFJlbmRlclRhcmdldCggY3VycmVudFJlbmRlclRhcmdldCApO1xuXG5cdFx0XHRfdGhpcy5zZXRDbGVhckNvbG9yKCBfY3VycmVudENsZWFyQ29sb3IsIF9jdXJyZW50Q2xlYXJBbHBoYSApO1xuXG5cdFx0XHRpZiAoIGN1cnJlbnRDYW1lcmFWaWV3cG9ydCAhPT0gdW5kZWZpbmVkICkgY2FtZXJhLnZpZXdwb3J0ID0gY3VycmVudENhbWVyYVZpZXdwb3J0O1xuXG5cdFx0XHRfdGhpcy50b25lTWFwcGluZyA9IGN1cnJlbnRUb25lTWFwcGluZztcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHJlbmRlck9iamVjdHMoIHJlbmRlckxpc3QsIHNjZW5lLCBjYW1lcmEgKSB7XG5cblx0XHRcdGNvbnN0IG92ZXJyaWRlTWF0ZXJpYWwgPSBzY2VuZS5pc1NjZW5lID09PSB0cnVlID8gc2NlbmUub3ZlcnJpZGVNYXRlcmlhbCA6IG51bGw7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHJlbmRlckxpc3QubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCByZW5kZXJJdGVtID0gcmVuZGVyTGlzdFsgaSBdO1xuXG5cdFx0XHRcdGNvbnN0IG9iamVjdCA9IHJlbmRlckl0ZW0ub2JqZWN0O1xuXHRcdFx0XHRjb25zdCBnZW9tZXRyeSA9IHJlbmRlckl0ZW0uZ2VvbWV0cnk7XG5cdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gb3ZlcnJpZGVNYXRlcmlhbCA9PT0gbnVsbCA/IHJlbmRlckl0ZW0ubWF0ZXJpYWwgOiBvdmVycmlkZU1hdGVyaWFsO1xuXHRcdFx0XHRjb25zdCBncm91cCA9IHJlbmRlckl0ZW0uZ3JvdXA7XG5cblx0XHRcdFx0aWYgKCBvYmplY3QubGF5ZXJzLnRlc3QoIGNhbWVyYS5sYXllcnMgKSApIHtcblxuXHRcdFx0XHRcdHJlbmRlck9iamVjdCggb2JqZWN0LCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiByZW5kZXJPYmplY3QoIG9iamVjdCwgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCApIHtcblxuXHRcdFx0b2JqZWN0Lm9uQmVmb3JlUmVuZGVyKCBfdGhpcywgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCApO1xuXG5cdFx0XHRvYmplY3QubW9kZWxWaWV3TWF0cml4Lm11bHRpcGx5TWF0cmljZXMoIGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UsIG9iamVjdC5tYXRyaXhXb3JsZCApO1xuXHRcdFx0b2JqZWN0Lm5vcm1hbE1hdHJpeC5nZXROb3JtYWxNYXRyaXgoIG9iamVjdC5tb2RlbFZpZXdNYXRyaXggKTtcblxuXHRcdFx0aWYgKCBtYXRlcmlhbC50cmFuc3BhcmVudCA9PT0gdHJ1ZSAmJiBtYXRlcmlhbC5zaWRlID09PSBEb3VibGVTaWRlICYmIG1hdGVyaWFsLmZvcmNlU2luZ2xlUGFzcyA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0bWF0ZXJpYWwuc2lkZSA9IEJhY2tTaWRlO1xuXHRcdFx0XHRtYXRlcmlhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0XHRcdF90aGlzLnJlbmRlckJ1ZmZlckRpcmVjdCggY2FtZXJhLCBzY2VuZSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBvYmplY3QsIGdyb3VwICk7XG5cblx0XHRcdFx0bWF0ZXJpYWwuc2lkZSA9IEZyb250U2lkZTtcblx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xuXHRcdFx0XHRfdGhpcy5yZW5kZXJCdWZmZXJEaXJlY3QoIGNhbWVyYSwgc2NlbmUsIGdlb21ldHJ5LCBtYXRlcmlhbCwgb2JqZWN0LCBncm91cCApO1xuXG5cdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBEb3VibGVTaWRlO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdF90aGlzLnJlbmRlckJ1ZmZlckRpcmVjdCggY2FtZXJhLCBzY2VuZSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBvYmplY3QsIGdyb3VwICk7XG5cblx0XHRcdH1cblxuXHRcdFx0b2JqZWN0Lm9uQWZ0ZXJSZW5kZXIoIF90aGlzLCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBnZXRQcm9ncmFtKCBtYXRlcmlhbCwgc2NlbmUsIG9iamVjdCApIHtcblxuXHRcdFx0aWYgKCBzY2VuZS5pc1NjZW5lICE9PSB0cnVlICkgc2NlbmUgPSBfZW1wdHlTY2VuZTsgLy8gc2NlbmUgY291bGQgYmUgYSBNZXNoLCBMaW5lLCBQb2ludHMsIC4uLlxuXG5cdFx0XHRjb25zdCBtYXRlcmlhbFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggbWF0ZXJpYWwgKTtcblxuXHRcdFx0Y29uc3QgbGlnaHRzID0gY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLmxpZ2h0cztcblx0XHRcdGNvbnN0IHNoYWRvd3NBcnJheSA9IGN1cnJlbnRSZW5kZXJTdGF0ZS5zdGF0ZS5zaGFkb3dzQXJyYXk7XG5cblx0XHRcdGNvbnN0IGxpZ2h0c1N0YXRlVmVyc2lvbiA9IGxpZ2h0cy5zdGF0ZS52ZXJzaW9uO1xuXG5cdFx0XHRjb25zdCBwYXJhbWV0ZXJzID0gcHJvZ3JhbUNhY2hlLmdldFBhcmFtZXRlcnMoIG1hdGVyaWFsLCBsaWdodHMuc3RhdGUsIHNoYWRvd3NBcnJheSwgc2NlbmUsIG9iamVjdCApO1xuXHRcdFx0Y29uc3QgcHJvZ3JhbUNhY2hlS2V5ID0gcHJvZ3JhbUNhY2hlLmdldFByb2dyYW1DYWNoZUtleSggcGFyYW1ldGVycyApO1xuXG5cdFx0XHRsZXQgcHJvZ3JhbXMgPSBtYXRlcmlhbFByb3BlcnRpZXMucHJvZ3JhbXM7XG5cblx0XHRcdC8vIGFsd2F5cyB1cGRhdGUgZW52aXJvbm1lbnQgYW5kIGZvZyAtIGNoYW5naW5nIHRoZXNlIHRyaWdnZXIgYW4gZ2V0UHJvZ3JhbSBjYWxsLCBidXQgaXQncyBwb3NzaWJsZSB0aGF0IHRoZSBwcm9ncmFtIGRvZXNuJ3QgY2hhbmdlXG5cblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5lbnZpcm9ubWVudCA9IG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBzY2VuZS5lbnZpcm9ubWVudCA6IG51bGw7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMuZm9nID0gc2NlbmUuZm9nO1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmVudk1hcCA9ICggbWF0ZXJpYWwuaXNNZXNoU3RhbmRhcmRNYXRlcmlhbCA/IGN1YmV1dm1hcHMgOiBjdWJlbWFwcyApLmdldCggbWF0ZXJpYWwuZW52TWFwIHx8IG1hdGVyaWFsUHJvcGVydGllcy5lbnZpcm9ubWVudCApO1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmVudk1hcFJvdGF0aW9uID0gKCBtYXRlcmlhbFByb3BlcnRpZXMuZW52aXJvbm1lbnQgIT09IG51bGwgJiYgbWF0ZXJpYWwuZW52TWFwID09PSBudWxsICkgPyBzY2VuZS5lbnZpcm9ubWVudFJvdGF0aW9uIDogbWF0ZXJpYWwuZW52TWFwUm90YXRpb247XG5cblx0XHRcdGlmICggcHJvZ3JhbXMgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHQvLyBuZXcgbWF0ZXJpYWxcblxuXHRcdFx0XHRtYXRlcmlhbC5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uTWF0ZXJpYWxEaXNwb3NlICk7XG5cblx0XHRcdFx0cHJvZ3JhbXMgPSBuZXcgTWFwKCk7XG5cdFx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5wcm9ncmFtcyA9IHByb2dyYW1zO1xuXG5cdFx0XHR9XG5cblx0XHRcdGxldCBwcm9ncmFtID0gcHJvZ3JhbXMuZ2V0KCBwcm9ncmFtQ2FjaGVLZXkgKTtcblxuXHRcdFx0aWYgKCBwcm9ncmFtICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Ly8gZWFybHkgb3V0IGlmIHByb2dyYW0gYW5kIGxpZ2h0IHN0YXRlIGlzIGlkZW50aWNhbFxuXG5cdFx0XHRcdGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLmN1cnJlbnRQcm9ncmFtID09PSBwcm9ncmFtICYmIG1hdGVyaWFsUHJvcGVydGllcy5saWdodHNTdGF0ZVZlcnNpb24gPT09IGxpZ2h0c1N0YXRlVmVyc2lvbiApIHtcblxuXHRcdFx0XHRcdHVwZGF0ZUNvbW1vbk1hdGVyaWFsUHJvcGVydGllcyggbWF0ZXJpYWwsIHBhcmFtZXRlcnMgKTtcblxuXHRcdFx0XHRcdHJldHVybiBwcm9ncmFtO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRwYXJhbWV0ZXJzLnVuaWZvcm1zID0gcHJvZ3JhbUNhY2hlLmdldFVuaWZvcm1zKCBtYXRlcmlhbCApO1xuXG5cdFx0XHRcdG1hdGVyaWFsLm9uQmVmb3JlQ29tcGlsZSggcGFyYW1ldGVycywgX3RoaXMgKTtcblxuXHRcdFx0XHRwcm9ncmFtID0gcHJvZ3JhbUNhY2hlLmFjcXVpcmVQcm9ncmFtKCBwYXJhbWV0ZXJzLCBwcm9ncmFtQ2FjaGVLZXkgKTtcblx0XHRcdFx0cHJvZ3JhbXMuc2V0KCBwcm9ncmFtQ2FjaGVLZXksIHByb2dyYW0gKTtcblxuXHRcdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMudW5pZm9ybXMgPSBwYXJhbWV0ZXJzLnVuaWZvcm1zO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHVuaWZvcm1zID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zO1xuXG5cdFx0XHRpZiAoICggISBtYXRlcmlhbC5pc1NoYWRlck1hdGVyaWFsICYmICEgbWF0ZXJpYWwuaXNSYXdTaGFkZXJNYXRlcmlhbCApIHx8IG1hdGVyaWFsLmNsaXBwaW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdHVuaWZvcm1zLmNsaXBwaW5nUGxhbmVzID0gY2xpcHBpbmcudW5pZm9ybTtcblxuXHRcdFx0fVxuXG5cdFx0XHR1cGRhdGVDb21tb25NYXRlcmlhbFByb3BlcnRpZXMoIG1hdGVyaWFsLCBwYXJhbWV0ZXJzICk7XG5cblx0XHRcdC8vIHN0b3JlIHRoZSBsaWdodCBzZXR1cCBpdCB3YXMgY3JlYXRlZCBmb3JcblxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLm5lZWRzTGlnaHRzID0gbWF0ZXJpYWxOZWVkc0xpZ2h0cyggbWF0ZXJpYWwgKTtcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5saWdodHNTdGF0ZVZlcnNpb24gPSBsaWdodHNTdGF0ZVZlcnNpb247XG5cblx0XHRcdGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm5lZWRzTGlnaHRzICkge1xuXG5cdFx0XHRcdC8vIHdpcmUgdXAgdGhlIG1hdGVyaWFsIHRvIHRoaXMgcmVuZGVyZXIncyBsaWdodGluZyBzdGF0ZVxuXG5cdFx0XHRcdHVuaWZvcm1zLmFtYmllbnRMaWdodENvbG9yLnZhbHVlID0gbGlnaHRzLnN0YXRlLmFtYmllbnQ7XG5cdFx0XHRcdHVuaWZvcm1zLmxpZ2h0UHJvYmUudmFsdWUgPSBsaWdodHMuc3RhdGUucHJvYmU7XG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsTGlnaHRzLnZhbHVlID0gbGlnaHRzLnN0YXRlLmRpcmVjdGlvbmFsO1xuXHRcdFx0XHR1bmlmb3Jtcy5kaXJlY3Rpb25hbExpZ2h0U2hhZG93cy52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5kaXJlY3Rpb25hbFNoYWRvdztcblx0XHRcdFx0dW5pZm9ybXMuc3BvdExpZ2h0cy52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5zcG90O1xuXHRcdFx0XHR1bmlmb3Jtcy5zcG90TGlnaHRTaGFkb3dzLnZhbHVlID0gbGlnaHRzLnN0YXRlLnNwb3RTaGFkb3c7XG5cdFx0XHRcdHVuaWZvcm1zLnJlY3RBcmVhTGlnaHRzLnZhbHVlID0gbGlnaHRzLnN0YXRlLnJlY3RBcmVhO1xuXHRcdFx0XHR1bmlmb3Jtcy5sdGNfMS52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5yZWN0QXJlYUxUQzE7XG5cdFx0XHRcdHVuaWZvcm1zLmx0Y18yLnZhbHVlID0gbGlnaHRzLnN0YXRlLnJlY3RBcmVhTFRDMjtcblx0XHRcdFx0dW5pZm9ybXMucG9pbnRMaWdodHMudmFsdWUgPSBsaWdodHMuc3RhdGUucG9pbnQ7XG5cdFx0XHRcdHVuaWZvcm1zLnBvaW50TGlnaHRTaGFkb3dzLnZhbHVlID0gbGlnaHRzLnN0YXRlLnBvaW50U2hhZG93O1xuXHRcdFx0XHR1bmlmb3Jtcy5oZW1pc3BoZXJlTGlnaHRzLnZhbHVlID0gbGlnaHRzLnN0YXRlLmhlbWk7XG5cblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uYWxTaGFkb3dNYXAudmFsdWUgPSBsaWdodHMuc3RhdGUuZGlyZWN0aW9uYWxTaGFkb3dNYXA7XG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsU2hhZG93TWF0cml4LnZhbHVlID0gbGlnaHRzLnN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWF0cml4O1xuXHRcdFx0XHR1bmlmb3Jtcy5zcG90U2hhZG93TWFwLnZhbHVlID0gbGlnaHRzLnN0YXRlLnNwb3RTaGFkb3dNYXA7XG5cdFx0XHRcdHVuaWZvcm1zLnNwb3RMaWdodE1hdHJpeC52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5zcG90TGlnaHRNYXRyaXg7XG5cdFx0XHRcdHVuaWZvcm1zLnNwb3RMaWdodE1hcC52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5zcG90TGlnaHRNYXA7XG5cdFx0XHRcdHVuaWZvcm1zLnBvaW50U2hhZG93TWFwLnZhbHVlID0gbGlnaHRzLnN0YXRlLnBvaW50U2hhZG93TWFwO1xuXHRcdFx0XHR1bmlmb3Jtcy5wb2ludFNoYWRvd01hdHJpeC52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5wb2ludFNoYWRvd01hdHJpeDtcblx0XHRcdFx0Ly8gVE9ETyAoYWJlbG5hdGlvbik6IGFkZCBhcmVhIGxpZ2h0cyBzaGFkb3cgaW5mbyB0byB1bmlmb3Jtc1xuXG5cdFx0XHR9XG5cblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5jdXJyZW50UHJvZ3JhbSA9IHByb2dyYW07XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMudW5pZm9ybXNMaXN0ID0gbnVsbDtcblxuXHRcdFx0cmV0dXJuIHByb2dyYW07XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBnZXRVbmlmb3JtTGlzdCggbWF0ZXJpYWxQcm9wZXJ0aWVzICkge1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsUHJvcGVydGllcy51bmlmb3Jtc0xpc3QgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0Y29uc3QgcHJvZ1VuaWZvcm1zID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLmN1cnJlbnRQcm9ncmFtLmdldFVuaWZvcm1zKCk7XG5cdFx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy51bmlmb3Jtc0xpc3QgPSBXZWJHTFVuaWZvcm1zLnNlcVdpdGhWYWx1ZSggcHJvZ1VuaWZvcm1zLnNlcSwgbWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIG1hdGVyaWFsUHJvcGVydGllcy51bmlmb3Jtc0xpc3Q7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiB1cGRhdGVDb21tb25NYXRlcmlhbFByb3BlcnRpZXMoIG1hdGVyaWFsLCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0XHRjb25zdCBtYXRlcmlhbFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggbWF0ZXJpYWwgKTtcblxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLm91dHB1dENvbG9yU3BhY2UgPSBwYXJhbWV0ZXJzLm91dHB1dENvbG9yU3BhY2U7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMuYmF0Y2hpbmcgPSBwYXJhbWV0ZXJzLmJhdGNoaW5nO1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmJhdGNoaW5nQ29sb3IgPSBwYXJhbWV0ZXJzLmJhdGNoaW5nQ29sb3I7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMuaW5zdGFuY2luZyA9IHBhcmFtZXRlcnMuaW5zdGFuY2luZztcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5pbnN0YW5jaW5nQ29sb3IgPSBwYXJhbWV0ZXJzLmluc3RhbmNpbmdDb2xvcjtcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5pbnN0YW5jaW5nTW9ycGggPSBwYXJhbWV0ZXJzLmluc3RhbmNpbmdNb3JwaDtcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5za2lubmluZyA9IHBhcmFtZXRlcnMuc2tpbm5pbmc7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhUYXJnZXRzID0gcGFyYW1ldGVycy5tb3JwaFRhcmdldHM7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhOb3JtYWxzID0gcGFyYW1ldGVycy5tb3JwaE5vcm1hbHM7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhDb2xvcnMgPSBwYXJhbWV0ZXJzLm1vcnBoQ29sb3JzO1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLm1vcnBoVGFyZ2V0c0NvdW50ID0gcGFyYW1ldGVycy5tb3JwaFRhcmdldHNDb3VudDtcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5udW1DbGlwcGluZ1BsYW5lcyA9IHBhcmFtZXRlcnMubnVtQ2xpcHBpbmdQbGFuZXM7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMubnVtSW50ZXJzZWN0aW9uID0gcGFyYW1ldGVycy5udW1DbGlwSW50ZXJzZWN0aW9uO1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnZlcnRleEFscGhhcyA9IHBhcmFtZXRlcnMudmVydGV4QWxwaGFzO1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnZlcnRleFRhbmdlbnRzID0gcGFyYW1ldGVycy52ZXJ0ZXhUYW5nZW50cztcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy50b25lTWFwcGluZyA9IHBhcmFtZXRlcnMudG9uZU1hcHBpbmc7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBzZXRQcm9ncmFtKCBjYW1lcmEsIHNjZW5lLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIG9iamVjdCApIHtcblxuXHRcdFx0aWYgKCBzY2VuZS5pc1NjZW5lICE9PSB0cnVlICkgc2NlbmUgPSBfZW1wdHlTY2VuZTsgLy8gc2NlbmUgY291bGQgYmUgYSBNZXNoLCBMaW5lLCBQb2ludHMsIC4uLlxuXG5cdFx0XHR0ZXh0dXJlcy5yZXNldFRleHR1cmVVbml0cygpO1xuXG5cdFx0XHRjb25zdCBmb2cgPSBzY2VuZS5mb2c7XG5cdFx0XHRjb25zdCBlbnZpcm9ubWVudCA9IG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBzY2VuZS5lbnZpcm9ubWVudCA6IG51bGw7XG5cdFx0XHRjb25zdCBjb2xvclNwYWNlID0gKCBfY3VycmVudFJlbmRlclRhcmdldCA9PT0gbnVsbCApID8gX3RoaXMub3V0cHV0Q29sb3JTcGFjZSA6ICggX2N1cnJlbnRSZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSA/IF9jdXJyZW50UmVuZGVyVGFyZ2V0LnRleHR1cmUuY29sb3JTcGFjZSA6IExpbmVhclNSR0JDb2xvclNwYWNlICk7XG5cdFx0XHRjb25zdCBlbnZNYXAgPSAoIG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBjdWJldXZtYXBzIDogY3ViZW1hcHMgKS5nZXQoIG1hdGVyaWFsLmVudk1hcCB8fCBlbnZpcm9ubWVudCApO1xuXHRcdFx0Y29uc3QgdmVydGV4QWxwaGFzID0gbWF0ZXJpYWwudmVydGV4Q29sb3JzID09PSB0cnVlICYmICEhIGdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IgJiYgZ2VvbWV0cnkuYXR0cmlidXRlcy5jb2xvci5pdGVtU2l6ZSA9PT0gNDtcblx0XHRcdGNvbnN0IHZlcnRleFRhbmdlbnRzID0gISEgZ2VvbWV0cnkuYXR0cmlidXRlcy50YW5nZW50ICYmICggISEgbWF0ZXJpYWwubm9ybWFsTWFwIHx8IG1hdGVyaWFsLmFuaXNvdHJvcHkgPiAwICk7XG5cdFx0XHRjb25zdCBtb3JwaFRhcmdldHMgPSAhISBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb247XG5cdFx0XHRjb25zdCBtb3JwaE5vcm1hbHMgPSAhISBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsO1xuXHRcdFx0Y29uc3QgbW9ycGhDb2xvcnMgPSAhISBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMuY29sb3I7XG5cblx0XHRcdGxldCB0b25lTWFwcGluZyA9IE5vVG9uZU1hcHBpbmc7XG5cblx0XHRcdGlmICggbWF0ZXJpYWwudG9uZU1hcHBlZCApIHtcblxuXHRcdFx0XHRpZiAoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ID09PSBudWxsIHx8IF9jdXJyZW50UmVuZGVyVGFyZ2V0LmlzWFJSZW5kZXJUYXJnZXQgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHR0b25lTWFwcGluZyA9IF90aGlzLnRvbmVNYXBwaW5nO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiB8fCBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsIHx8IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvcjtcblx0XHRcdGNvbnN0IG1vcnBoVGFyZ2V0c0NvdW50ID0gKCBtb3JwaEF0dHJpYnV0ZSAhPT0gdW5kZWZpbmVkICkgPyBtb3JwaEF0dHJpYnV0ZS5sZW5ndGggOiAwO1xuXG5cdFx0XHRjb25zdCBtYXRlcmlhbFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggbWF0ZXJpYWwgKTtcblx0XHRcdGNvbnN0IGxpZ2h0cyA9IGN1cnJlbnRSZW5kZXJTdGF0ZS5zdGF0ZS5saWdodHM7XG5cblx0XHRcdGlmICggX2NsaXBwaW5nRW5hYmxlZCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRpZiAoIF9sb2NhbENsaXBwaW5nRW5hYmxlZCA9PT0gdHJ1ZSB8fCBjYW1lcmEgIT09IF9jdXJyZW50Q2FtZXJhICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgdXNlQ2FjaGUgPVxuXHRcdFx0XHRcdFx0Y2FtZXJhID09PSBfY3VycmVudENhbWVyYSAmJlxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwuaWQgPT09IF9jdXJyZW50TWF0ZXJpYWxJZDtcblxuXHRcdFx0XHRcdC8vIHdlIG1pZ2h0IHdhbnQgdG8gY2FsbCB0aGlzIGZ1bmN0aW9uIHdpdGggc29tZSBDbGlwcGluZ0dyb3VwXG5cdFx0XHRcdFx0Ly8gb2JqZWN0IGluc3RlYWQgb2YgdGhlIG1hdGVyaWFsLCBvbmNlIGl0IGJlY29tZXMgZmVhc2libGVcblx0XHRcdFx0XHQvLyAoIzg0NjUsICM4Mzc5KVxuXHRcdFx0XHRcdGNsaXBwaW5nLnNldFN0YXRlKCBtYXRlcmlhbCwgY2FtZXJhLCB1c2VDYWNoZSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvL1xuXG5cdFx0XHRsZXQgbmVlZHNQcm9ncmFtQ2hhbmdlID0gZmFsc2U7XG5cblx0XHRcdGlmICggbWF0ZXJpYWwudmVyc2lvbiA9PT0gbWF0ZXJpYWxQcm9wZXJ0aWVzLl9fdmVyc2lvbiApIHtcblxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5uZWVkc0xpZ2h0cyAmJiAoIG1hdGVyaWFsUHJvcGVydGllcy5saWdodHNTdGF0ZVZlcnNpb24gIT09IGxpZ2h0cy5zdGF0ZS52ZXJzaW9uICkgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5vdXRwdXRDb2xvclNwYWNlICE9PSBjb2xvclNwYWNlICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNCYXRjaGVkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuYmF0Y2hpbmcgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCAhIG9iamVjdC5pc0JhdGNoZWRNZXNoICYmIG1hdGVyaWFsUHJvcGVydGllcy5iYXRjaGluZyA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzQmF0Y2hlZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmJhdGNoaW5nQ29sb3IgPT09IHRydWUgJiYgb2JqZWN0LmNvbG9yVGV4dHVyZSA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzQmF0Y2hlZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmJhdGNoaW5nQ29sb3IgPT09IGZhbHNlICYmIG9iamVjdC5jb2xvclRleHR1cmUgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmcgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCAhIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmcgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc1NraW5uZWRNZXNoICYmIG1hdGVyaWFsUHJvcGVydGllcy5za2lubmluZyA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoICEgb2JqZWN0LmlzU2tpbm5lZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLnNraW5uaW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNJbnN0YW5jZWRNZXNoICYmIG1hdGVyaWFsUHJvcGVydGllcy5pbnN0YW5jaW5nQ29sb3IgPT09IHRydWUgJiYgb2JqZWN0Lmluc3RhbmNlQ29sb3IgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmdDb2xvciA9PT0gZmFsc2UgJiYgb2JqZWN0Lmluc3RhbmNlQ29sb3IgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmdNb3JwaCA9PT0gdHJ1ZSAmJiBvYmplY3QubW9ycGhUZXh0dXJlID09PSBudWxsICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNJbnN0YW5jZWRNZXNoICYmIG1hdGVyaWFsUHJvcGVydGllcy5pbnN0YW5jaW5nTW9ycGggPT09IGZhbHNlICYmIG9iamVjdC5tb3JwaFRleHR1cmUgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5lbnZNYXAgIT09IGVudk1hcCApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuZm9nID09PSB0cnVlICYmIG1hdGVyaWFsUHJvcGVydGllcy5mb2cgIT09IGZvZyApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm51bUNsaXBwaW5nUGxhbmVzICE9PSB1bmRlZmluZWQgJiZcblx0XHRcdFx0XHQoIG1hdGVyaWFsUHJvcGVydGllcy5udW1DbGlwcGluZ1BsYW5lcyAhPT0gY2xpcHBpbmcubnVtUGxhbmVzIHx8XG5cdFx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLm51bUludGVyc2VjdGlvbiAhPT0gY2xpcHBpbmcubnVtSW50ZXJzZWN0aW9uICkgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy52ZXJ0ZXhBbHBoYXMgIT09IHZlcnRleEFscGhhcyApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLnZlcnRleFRhbmdlbnRzICE9PSB2ZXJ0ZXhUYW5nZW50cyApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm1vcnBoVGFyZ2V0cyAhPT0gbW9ycGhUYXJnZXRzICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhOb3JtYWxzICE9PSBtb3JwaE5vcm1hbHMgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaENvbG9ycyAhPT0gbW9ycGhDb2xvcnMgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy50b25lTWFwcGluZyAhPT0gdG9uZU1hcHBpbmcgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaFRhcmdldHNDb3VudCAhPT0gbW9ycGhUYXJnZXRzQ291bnQgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXHRcdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMuX192ZXJzaW9uID0gbWF0ZXJpYWwudmVyc2lvbjtcblxuXHRcdFx0fVxuXG5cdFx0XHQvL1xuXG5cdFx0XHRsZXQgcHJvZ3JhbSA9IG1hdGVyaWFsUHJvcGVydGllcy5jdXJyZW50UHJvZ3JhbTtcblxuXHRcdFx0aWYgKCBuZWVkc1Byb2dyYW1DaGFuZ2UgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0cHJvZ3JhbSA9IGdldFByb2dyYW0oIG1hdGVyaWFsLCBzY2VuZSwgb2JqZWN0ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0bGV0IHJlZnJlc2hQcm9ncmFtID0gZmFsc2U7XG5cdFx0XHRsZXQgcmVmcmVzaE1hdGVyaWFsID0gZmFsc2U7XG5cdFx0XHRsZXQgcmVmcmVzaExpZ2h0cyA9IGZhbHNlO1xuXG5cdFx0XHRjb25zdCBwX3VuaWZvcm1zID0gcHJvZ3JhbS5nZXRVbmlmb3JtcygpLFxuXHRcdFx0XHRtX3VuaWZvcm1zID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zO1xuXG5cdFx0XHRpZiAoIHN0YXRlLnVzZVByb2dyYW0oIHByb2dyYW0ucHJvZ3JhbSApICkge1xuXG5cdFx0XHRcdHJlZnJlc2hQcm9ncmFtID0gdHJ1ZTtcblx0XHRcdFx0cmVmcmVzaE1hdGVyaWFsID0gdHJ1ZTtcblx0XHRcdFx0cmVmcmVzaExpZ2h0cyA9IHRydWU7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pZCAhPT0gX2N1cnJlbnRNYXRlcmlhbElkICkge1xuXG5cdFx0XHRcdF9jdXJyZW50TWF0ZXJpYWxJZCA9IG1hdGVyaWFsLmlkO1xuXG5cdFx0XHRcdHJlZnJlc2hNYXRlcmlhbCA9IHRydWU7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCByZWZyZXNoUHJvZ3JhbSB8fCBfY3VycmVudENhbWVyYSAhPT0gY2FtZXJhICkge1xuXG5cdFx0XHRcdC8vIGNvbW1vbiBjYW1lcmEgdW5pZm9ybXNcblxuXHRcdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdwcm9qZWN0aW9uTWF0cml4JywgY2FtZXJhLnByb2plY3Rpb25NYXRyaXggKTtcblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAndmlld01hdHJpeCcsIGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UgKTtcblxuXHRcdFx0XHRjb25zdCB1Q2FtUG9zID0gcF91bmlmb3Jtcy5tYXAuY2FtZXJhUG9zaXRpb247XG5cblx0XHRcdFx0aWYgKCB1Q2FtUG9zICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHR1Q2FtUG9zLnNldFZhbHVlKCBfZ2wsIF92ZWN0b3IzLnNldEZyb21NYXRyaXhQb3NpdGlvbiggY2FtZXJhLm1hdHJpeFdvcmxkICkgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBjYXBhYmlsaXRpZXMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciApIHtcblxuXHRcdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ2xvZ0RlcHRoQnVmRkMnLFxuXHRcdFx0XHRcdFx0Mi4wIC8gKCBNYXRoLmxvZyggY2FtZXJhLmZhciArIDEuMCApIC8gTWF0aC5MTjIgKSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBjb25zaWRlciBtb3ZpbmcgaXNPcnRob2dyYXBoaWMgdG8gVW5pZm9ybUxpYiBhbmQgV2ViR0xNYXRlcmlhbHMsIHNlZSBodHRwczovL2dpdGh1Yi5jb20vbXJkb29iL3RocmVlLmpzL3B1bGwvMjY0NjcjaXNzdWVjb21tZW50LTE2NDUxODUwNjdcblxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaFBob25nTWF0ZXJpYWwgfHxcblx0XHRcdFx0XHRtYXRlcmlhbC5pc01lc2hUb29uTWF0ZXJpYWwgfHxcblx0XHRcdFx0XHRtYXRlcmlhbC5pc01lc2hMYW1iZXJ0TWF0ZXJpYWwgfHxcblx0XHRcdFx0XHRtYXRlcmlhbC5pc01lc2hCYXNpY01hdGVyaWFsIHx8XG5cdFx0XHRcdFx0bWF0ZXJpYWwuaXNNZXNoU3RhbmRhcmRNYXRlcmlhbCB8fFxuXHRcdFx0XHRcdG1hdGVyaWFsLmlzU2hhZGVyTWF0ZXJpYWwgKSB7XG5cblx0XHRcdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdpc09ydGhvZ3JhcGhpYycsIGNhbWVyYS5pc09ydGhvZ3JhcGhpY0NhbWVyYSA9PT0gdHJ1ZSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIF9jdXJyZW50Q2FtZXJhICE9PSBjYW1lcmEgKSB7XG5cblx0XHRcdFx0XHRfY3VycmVudENhbWVyYSA9IGNhbWVyYTtcblxuXHRcdFx0XHRcdC8vIGxpZ2h0aW5nIHVuaWZvcm1zIGRlcGVuZCBvbiB0aGUgY2FtZXJhIHNvIGVuZm9yY2UgYW4gdXBkYXRlXG5cdFx0XHRcdFx0Ly8gbm93LCBpbiBjYXNlIHRoaXMgbWF0ZXJpYWwgc3VwcG9ydHMgbGlnaHRzIC0gb3IgbGF0ZXIsIHdoZW5cblx0XHRcdFx0XHQvLyB0aGUgbmV4dCBtYXRlcmlhbCB0aGF0IGRvZXMgZ2V0cyBhY3RpdmF0ZWQ6XG5cblx0XHRcdFx0XHRyZWZyZXNoTWF0ZXJpYWwgPSB0cnVlO1x0XHQvLyBzZXQgdG8gdHJ1ZSBvbiBtYXRlcmlhbCBjaGFuZ2Vcblx0XHRcdFx0XHRyZWZyZXNoTGlnaHRzID0gdHJ1ZTtcdFx0Ly8gcmVtYWlucyBzZXQgdW50aWwgdXBkYXRlIGRvbmVcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gc2tpbm5pbmcgYW5kIG1vcnBoIHRhcmdldCB1bmlmb3JtcyBtdXN0IGJlIHNldCBldmVuIGlmIG1hdGVyaWFsIGRpZG4ndCBjaGFuZ2Vcblx0XHRcdC8vIGF1dG8tc2V0dGluZyBvZiB0ZXh0dXJlIHVuaXQgZm9yIGJvbmUgYW5kIG1vcnBoIHRleHR1cmUgbXVzdCBnbyBiZWZvcmUgb3RoZXIgdGV4dHVyZXNcblx0XHRcdC8vIG90aGVyd2lzZSB0ZXh0dXJlcyB1c2VkIGZvciBza2lubmluZyBhbmQgbW9ycGhpbmcgY2FuIHRha2Ugb3ZlciB0ZXh0dXJlIHVuaXRzIHJlc2VydmVkIGZvciBvdGhlciBtYXRlcmlhbCB0ZXh0dXJlc1xuXG5cdFx0XHRpZiAoIG9iamVjdC5pc1NraW5uZWRNZXNoICkge1xuXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0T3B0aW9uYWwoIF9nbCwgb2JqZWN0LCAnYmluZE1hdHJpeCcgKTtcblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRPcHRpb25hbCggX2dsLCBvYmplY3QsICdiaW5kTWF0cml4SW52ZXJzZScgKTtcblxuXHRcdFx0XHRjb25zdCBza2VsZXRvbiA9IG9iamVjdC5za2VsZXRvbjtcblxuXHRcdFx0XHRpZiAoIHNrZWxldG9uICkge1xuXG5cdFx0XHRcdFx0aWYgKCBza2VsZXRvbi5ib25lVGV4dHVyZSA9PT0gbnVsbCApIHNrZWxldG9uLmNvbXB1dGVCb25lVGV4dHVyZSgpO1xuXG5cdFx0XHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnYm9uZVRleHR1cmUnLCBza2VsZXRvbi5ib25lVGV4dHVyZSwgdGV4dHVyZXMgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBvYmplY3QuaXNCYXRjaGVkTWVzaCApIHtcblxuXHRcdFx0XHRwX3VuaWZvcm1zLnNldE9wdGlvbmFsKCBfZ2wsIG9iamVjdCwgJ2JhdGNoaW5nVGV4dHVyZScgKTtcblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnYmF0Y2hpbmdUZXh0dXJlJywgb2JqZWN0Ll9tYXRyaWNlc1RleHR1cmUsIHRleHR1cmVzICk7XG5cblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRPcHRpb25hbCggX2dsLCBvYmplY3QsICdiYXRjaGluZ0lkVGV4dHVyZScgKTtcblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnYmF0Y2hpbmdJZFRleHR1cmUnLCBvYmplY3QuX2luZGlyZWN0VGV4dHVyZSwgdGV4dHVyZXMgKTtcblxuXHRcdFx0XHRwX3VuaWZvcm1zLnNldE9wdGlvbmFsKCBfZ2wsIG9iamVjdCwgJ2JhdGNoaW5nQ29sb3JUZXh0dXJlJyApO1xuXHRcdFx0XHRpZiAoIG9iamVjdC5fY29sb3JzVGV4dHVyZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ2JhdGNoaW5nQ29sb3JUZXh0dXJlJywgb2JqZWN0Ll9jb2xvcnNUZXh0dXJlLCB0ZXh0dXJlcyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXM7XG5cblx0XHRcdGlmICggbW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uICE9PSB1bmRlZmluZWQgfHwgbW9ycGhBdHRyaWJ1dGVzLm5vcm1hbCAhPT0gdW5kZWZpbmVkIHx8ICggbW9ycGhBdHRyaWJ1dGVzLmNvbG9yICE9PSB1bmRlZmluZWQgKSApIHtcblxuXHRcdFx0XHRtb3JwaHRhcmdldHMudXBkYXRlKCBvYmplY3QsIGdlb21ldHJ5LCBwcm9ncmFtICk7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCByZWZyZXNoTWF0ZXJpYWwgfHwgbWF0ZXJpYWxQcm9wZXJ0aWVzLnJlY2VpdmVTaGFkb3cgIT09IG9iamVjdC5yZWNlaXZlU2hhZG93ICkge1xuXG5cdFx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5yZWNlaXZlU2hhZG93ID0gb2JqZWN0LnJlY2VpdmVTaGFkb3c7XG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ3JlY2VpdmVTaGFkb3cnLCBvYmplY3QucmVjZWl2ZVNoYWRvdyApO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvcHVsbC8yNDQ2NyNpc3N1ZWNvbW1lbnQtMTIwOTAzMTUxMlxuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaEdvdXJhdWRNYXRlcmlhbCAmJiBtYXRlcmlhbC5lbnZNYXAgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0bV91bmlmb3Jtcy5lbnZNYXAudmFsdWUgPSBlbnZNYXA7XG5cblx0XHRcdFx0bV91bmlmb3Jtcy5mbGlwRW52TWFwLnZhbHVlID0gKCBlbnZNYXAuaXNDdWJlVGV4dHVyZSAmJiBlbnZNYXAuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID09PSBmYWxzZSApID8gLSAxIDogMTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgJiYgbWF0ZXJpYWwuZW52TWFwID09PSBudWxsICYmIHNjZW5lLmVudmlyb25tZW50ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdG1fdW5pZm9ybXMuZW52TWFwSW50ZW5zaXR5LnZhbHVlID0gc2NlbmUuZW52aXJvbm1lbnRJbnRlbnNpdHk7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCByZWZyZXNoTWF0ZXJpYWwgKSB7XG5cblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAndG9uZU1hcHBpbmdFeHBvc3VyZScsIF90aGlzLnRvbmVNYXBwaW5nRXhwb3N1cmUgKTtcblxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5uZWVkc0xpZ2h0cyApIHtcblxuXHRcdFx0XHRcdC8vIHRoZSBjdXJyZW50IG1hdGVyaWFsIHJlcXVpcmVzIGxpZ2h0aW5nIGluZm9cblxuXHRcdFx0XHRcdC8vIG5vdGU6IGFsbCBsaWdodGluZyB1bmlmb3JtcyBhcmUgYWx3YXlzIHNldCBjb3JyZWN0bHlcblx0XHRcdFx0XHQvLyB0aGV5IHNpbXBseSByZWZlcmVuY2UgdGhlIHJlbmRlcmVyJ3Mgc3RhdGUgZm9yIHRoZWlyXG5cdFx0XHRcdFx0Ly8gdmFsdWVzXG5cdFx0XHRcdFx0Ly9cblx0XHRcdFx0XHQvLyB1c2UgdGhlIGN1cnJlbnQgbWF0ZXJpYWwncyAubmVlZHNVcGRhdGUgZmxhZ3MgdG8gc2V0XG5cdFx0XHRcdFx0Ly8gdGhlIEdMIHN0YXRlIHdoZW4gcmVxdWlyZWRcblxuXHRcdFx0XHRcdG1hcmtVbmlmb3Jtc0xpZ2h0c05lZWRzVXBkYXRlKCBtX3VuaWZvcm1zLCByZWZyZXNoTGlnaHRzICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIHJlZnJlc2ggdW5pZm9ybXMgY29tbW9uIHRvIHNldmVyYWwgbWF0ZXJpYWxzXG5cblx0XHRcdFx0aWYgKCBmb2cgJiYgbWF0ZXJpYWwuZm9nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0bWF0ZXJpYWxzLnJlZnJlc2hGb2dVbmlmb3JtcyggbV91bmlmb3JtcywgZm9nICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdG1hdGVyaWFscy5yZWZyZXNoTWF0ZXJpYWxVbmlmb3JtcyggbV91bmlmb3JtcywgbWF0ZXJpYWwsIF9waXhlbFJhdGlvLCBfaGVpZ2h0LCBjdXJyZW50UmVuZGVyU3RhdGUuc3RhdGUudHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0WyBjYW1lcmEuaWQgXSApO1xuXG5cdFx0XHRcdFdlYkdMVW5pZm9ybXMudXBsb2FkKCBfZ2wsIGdldFVuaWZvcm1MaXN0KCBtYXRlcmlhbFByb3BlcnRpZXMgKSwgbV91bmlmb3JtcywgdGV4dHVyZXMgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlzU2hhZGVyTWF0ZXJpYWwgJiYgbWF0ZXJpYWwudW5pZm9ybXNOZWVkVXBkYXRlID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFdlYkdMVW5pZm9ybXMudXBsb2FkKCBfZ2wsIGdldFVuaWZvcm1MaXN0KCBtYXRlcmlhbFByb3BlcnRpZXMgKSwgbV91bmlmb3JtcywgdGV4dHVyZXMgKTtcblx0XHRcdFx0bWF0ZXJpYWwudW5pZm9ybXNOZWVkVXBkYXRlID0gZmFsc2U7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pc1Nwcml0ZU1hdGVyaWFsICkge1xuXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ2NlbnRlcicsIG9iamVjdC5jZW50ZXIgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBjb21tb24gbWF0cmljZXNcblxuXHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnbW9kZWxWaWV3TWF0cml4Jywgb2JqZWN0Lm1vZGVsVmlld01hdHJpeCApO1xuXHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnbm9ybWFsTWF0cml4Jywgb2JqZWN0Lm5vcm1hbE1hdHJpeCApO1xuXHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnbW9kZWxNYXRyaXgnLCBvYmplY3QubWF0cml4V29ybGQgKTtcblxuXHRcdFx0Ly8gVUJPc1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlzU2hhZGVyTWF0ZXJpYWwgfHwgbWF0ZXJpYWwuaXNSYXdTaGFkZXJNYXRlcmlhbCApIHtcblxuXHRcdFx0XHRjb25zdCBncm91cHMgPSBtYXRlcmlhbC51bmlmb3Jtc0dyb3VwcztcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBncm91cHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBpIF07XG5cblx0XHRcdFx0XHR1bmlmb3Jtc0dyb3Vwcy51cGRhdGUoIGdyb3VwLCBwcm9ncmFtICk7XG5cdFx0XHRcdFx0dW5pZm9ybXNHcm91cHMuYmluZCggZ3JvdXAsIHByb2dyYW0gKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHByb2dyYW07XG5cblx0XHR9XG5cblx0XHQvLyBJZiB1bmlmb3JtcyBhcmUgbWFya2VkIGFzIGNsZWFuLCB0aGV5IGRvbid0IG5lZWQgdG8gYmUgbG9hZGVkIHRvIHRoZSBHUFUuXG5cblx0XHRmdW5jdGlvbiBtYXJrVW5pZm9ybXNMaWdodHNOZWVkc1VwZGF0ZSggdW5pZm9ybXMsIHZhbHVlICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5hbWJpZW50TGlnaHRDb2xvci5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xuXHRcdFx0dW5pZm9ybXMubGlnaHRQcm9iZS5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xuXG5cdFx0XHR1bmlmb3Jtcy5kaXJlY3Rpb25hbExpZ2h0cy5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xuXHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uYWxMaWdodFNoYWRvd3MubmVlZHNVcGRhdGUgPSB2YWx1ZTtcblx0XHRcdHVuaWZvcm1zLnBvaW50TGlnaHRzLm5lZWRzVXBkYXRlID0gdmFsdWU7XG5cdFx0XHR1bmlmb3Jtcy5wb2ludExpZ2h0U2hhZG93cy5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xuXHRcdFx0dW5pZm9ybXMuc3BvdExpZ2h0cy5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xuXHRcdFx0dW5pZm9ybXMuc3BvdExpZ2h0U2hhZG93cy5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xuXHRcdFx0dW5pZm9ybXMucmVjdEFyZWFMaWdodHMubmVlZHNVcGRhdGUgPSB2YWx1ZTtcblx0XHRcdHVuaWZvcm1zLmhlbWlzcGhlcmVMaWdodHMubmVlZHNVcGRhdGUgPSB2YWx1ZTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG1hdGVyaWFsTmVlZHNMaWdodHMoIG1hdGVyaWFsICkge1xuXG5cdFx0XHRyZXR1cm4gbWF0ZXJpYWwuaXNNZXNoTGFtYmVydE1hdGVyaWFsIHx8IG1hdGVyaWFsLmlzTWVzaFRvb25NYXRlcmlhbCB8fCBtYXRlcmlhbC5pc01lc2hQaG9uZ01hdGVyaWFsIHx8XG5cdFx0XHRcdG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgfHwgbWF0ZXJpYWwuaXNTaGFkb3dNYXRlcmlhbCB8fFxuXHRcdFx0XHQoIG1hdGVyaWFsLmlzU2hhZGVyTWF0ZXJpYWwgJiYgbWF0ZXJpYWwubGlnaHRzID09PSB0cnVlICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmdldEFjdGl2ZUN1YmVGYWNlID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gX2N1cnJlbnRBY3RpdmVDdWJlRmFjZTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldEFjdGl2ZU1pcG1hcExldmVsID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gX2N1cnJlbnRBY3RpdmVNaXBtYXBMZXZlbDtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldFJlbmRlclRhcmdldCA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIF9jdXJyZW50UmVuZGVyVGFyZ2V0O1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0UmVuZGVyVGFyZ2V0VGV4dHVyZXMgPSBmdW5jdGlvbiAoIHJlbmRlclRhcmdldCwgY29sb3JUZXh0dXJlLCBkZXB0aFRleHR1cmUgKSB7XG5cblx0XHRcdHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQudGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlID0gY29sb3JUZXh0dXJlO1xuXHRcdFx0cHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgKS5fX3dlYmdsVGV4dHVyZSA9IGRlcHRoVGV4dHVyZTtcblxuXHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcblx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX19oYXNFeHRlcm5hbFRleHR1cmVzID0gdHJ1ZTtcblxuXHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX2F1dG9BbGxvY2F0ZURlcHRoQnVmZmVyID0gZGVwdGhUZXh0dXJlID09PSB1bmRlZmluZWQ7XG5cblx0XHRcdGlmICggISByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fYXV0b0FsbG9jYXRlRGVwdGhCdWZmZXIgKSB7XG5cblx0XHRcdFx0Ly8gVGhlIG11bHRpc2FtcGxlX3JlbmRlcl90b190ZXh0dXJlIGV4dGVuc2lvbiBkb2Vzbid0IHdvcmsgcHJvcGVybHkgaWYgdGhlcmVcblx0XHRcdFx0Ly8gYXJlIG1pZGZyYW1lIGZsdXNoZXMgYW5kIGFuIGV4dGVybmFsIGRlcHRoIGJ1ZmZlci4gRGlzYWJsZSB1c2Ugb2YgdGhlIGV4dGVuc2lvbi5cblx0XHRcdFx0aWYgKCBleHRlbnNpb25zLmhhcyggJ1dFQkdMX211bHRpc2FtcGxlZF9yZW5kZXJfdG9fdGV4dHVyZScgKSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFJlbmRlci10by10ZXh0dXJlIGV4dGVuc2lvbiB3YXMgZGlzYWJsZWQgYmVjYXVzZSBhbiBleHRlcm5hbCB0ZXh0dXJlIHdhcyBwcm92aWRlZCcgKTtcblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fdXNlUmVuZGVyVG9UZXh0dXJlID0gZmFsc2U7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5zZXRSZW5kZXJUYXJnZXRGcmFtZWJ1ZmZlciA9IGZ1bmN0aW9uICggcmVuZGVyVGFyZ2V0LCBkZWZhdWx0RnJhbWVidWZmZXIgKSB7XG5cblx0XHRcdGNvbnN0IHJlbmRlclRhcmdldFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0ICk7XG5cdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9IGRlZmF1bHRGcmFtZWJ1ZmZlcjtcblx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX191c2VEZWZhdWx0RnJhbWVidWZmZXIgPSBkZWZhdWx0RnJhbWVidWZmZXIgPT09IHVuZGVmaW5lZDtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldFJlbmRlclRhcmdldCA9IGZ1bmN0aW9uICggcmVuZGVyVGFyZ2V0LCBhY3RpdmVDdWJlRmFjZSA9IDAsIGFjdGl2ZU1pcG1hcExldmVsID0gMCApIHtcblxuXHRcdFx0X2N1cnJlbnRSZW5kZXJUYXJnZXQgPSByZW5kZXJUYXJnZXQ7XG5cdFx0XHRfY3VycmVudEFjdGl2ZUN1YmVGYWNlID0gYWN0aXZlQ3ViZUZhY2U7XG5cdFx0XHRfY3VycmVudEFjdGl2ZU1pcG1hcExldmVsID0gYWN0aXZlTWlwbWFwTGV2ZWw7XG5cblx0XHRcdGxldCB1c2VEZWZhdWx0RnJhbWVidWZmZXIgPSB0cnVlO1xuXHRcdFx0bGV0IGZyYW1lYnVmZmVyID0gbnVsbDtcblx0XHRcdGxldCBpc0N1YmUgPSBmYWxzZTtcblx0XHRcdGxldCBpc1JlbmRlclRhcmdldDNEID0gZmFsc2U7XG5cblx0XHRcdGlmICggcmVuZGVyVGFyZ2V0ICkge1xuXG5cdFx0XHRcdGNvbnN0IHJlbmRlclRhcmdldFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fdXNlRGVmYXVsdEZyYW1lYnVmZmVyICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHQvLyBXZSBuZWVkIHRvIG1ha2Ugc3VyZSB0byByZWJpbmQgdGhlIGZyYW1lYnVmZmVyLlxuXHRcdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBudWxsICk7XG5cdFx0XHRcdFx0dXNlRGVmYXVsdEZyYW1lYnVmZmVyID0gZmFsc2U7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdHRleHR1cmVzLnNldHVwUmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9faGFzRXh0ZXJuYWxUZXh0dXJlcyApIHtcblxuXHRcdFx0XHRcdC8vIENvbG9yIGFuZCBkZXB0aCB0ZXh0dXJlIG11c3QgYmUgcmVib3VuZCBpbiBvcmRlciBmb3IgdGhlIHN3YXBjaGFpbiB0byB1cGRhdGUuXG5cdFx0XHRcdFx0dGV4dHVyZXMucmViaW5kVGV4dHVyZXMoIHJlbmRlclRhcmdldCwgcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldC50ZXh0dXJlICkuX193ZWJnbFRleHR1cmUsIHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlICkuX193ZWJnbFRleHR1cmUgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Y29uc3QgdGV4dHVyZSA9IHJlbmRlclRhcmdldC50ZXh0dXJlO1xuXG5cdFx0XHRcdGlmICggdGV4dHVyZS5pc0RhdGEzRFRleHR1cmUgfHwgdGV4dHVyZS5pc0RhdGFBcnJheVRleHR1cmUgfHwgdGV4dHVyZS5pc0NvbXByZXNzZWRBcnJheVRleHR1cmUgKSB7XG5cblx0XHRcdFx0XHRpc1JlbmRlclRhcmdldDNEID0gdHJ1ZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Y29uc3QgX193ZWJnbEZyYW1lYnVmZmVyID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApLl9fd2ViZ2xGcmFtZWJ1ZmZlcjtcblxuXHRcdFx0XHRpZiAoIHJlbmRlclRhcmdldC5pc1dlYkdMQ3ViZVJlbmRlclRhcmdldCApIHtcblxuXHRcdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggX193ZWJnbEZyYW1lYnVmZmVyWyBhY3RpdmVDdWJlRmFjZSBdICkgKSB7XG5cblx0XHRcdFx0XHRcdGZyYW1lYnVmZmVyID0gX193ZWJnbEZyYW1lYnVmZmVyWyBhY3RpdmVDdWJlRmFjZSBdWyBhY3RpdmVNaXBtYXBMZXZlbCBdO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0ZnJhbWVidWZmZXIgPSBfX3dlYmdsRnJhbWVidWZmZXJbIGFjdGl2ZUN1YmVGYWNlIF07XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpc0N1YmUgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoICggcmVuZGVyVGFyZ2V0LnNhbXBsZXMgPiAwICkgJiYgdGV4dHVyZXMudXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0XHRmcmFtZWJ1ZmZlciA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKS5fX3dlYmdsTXVsdGlzYW1wbGVkRnJhbWVidWZmZXI7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggX193ZWJnbEZyYW1lYnVmZmVyICkgKSB7XG5cblx0XHRcdFx0XHRcdGZyYW1lYnVmZmVyID0gX193ZWJnbEZyYW1lYnVmZmVyWyBhY3RpdmVNaXBtYXBMZXZlbCBdO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0ZnJhbWVidWZmZXIgPSBfX3dlYmdsRnJhbWVidWZmZXI7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdF9jdXJyZW50Vmlld3BvcnQuY29weSggcmVuZGVyVGFyZ2V0LnZpZXdwb3J0ICk7XG5cdFx0XHRcdF9jdXJyZW50U2Npc3Nvci5jb3B5KCByZW5kZXJUYXJnZXQuc2Npc3NvciApO1xuXHRcdFx0XHRfY3VycmVudFNjaXNzb3JUZXN0ID0gcmVuZGVyVGFyZ2V0LnNjaXNzb3JUZXN0O1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdF9jdXJyZW50Vmlld3BvcnQuY29weSggX3ZpZXdwb3J0ICkubXVsdGlwbHlTY2FsYXIoIF9waXhlbFJhdGlvICkuZmxvb3IoKTtcblx0XHRcdFx0X2N1cnJlbnRTY2lzc29yLmNvcHkoIF9zY2lzc29yICkubXVsdGlwbHlTY2FsYXIoIF9waXhlbFJhdGlvICkuZmxvb3IoKTtcblx0XHRcdFx0X2N1cnJlbnRTY2lzc29yVGVzdCA9IF9zY2lzc29yVGVzdDtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBmcmFtZWJ1ZmZlckJvdW5kID0gc3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIGZyYW1lYnVmZmVyICk7XG5cblx0XHRcdGlmICggZnJhbWVidWZmZXJCb3VuZCAmJiB1c2VEZWZhdWx0RnJhbWVidWZmZXIgKSB7XG5cblx0XHRcdFx0c3RhdGUuZHJhd0J1ZmZlcnMoIHJlbmRlclRhcmdldCwgZnJhbWVidWZmZXIgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRzdGF0ZS52aWV3cG9ydCggX2N1cnJlbnRWaWV3cG9ydCApO1xuXHRcdFx0c3RhdGUuc2Npc3NvciggX2N1cnJlbnRTY2lzc29yICk7XG5cdFx0XHRzdGF0ZS5zZXRTY2lzc29yVGVzdCggX2N1cnJlbnRTY2lzc29yVGVzdCApO1xuXG5cdFx0XHRpZiAoIGlzQ3ViZSApIHtcblxuXHRcdFx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQudGV4dHVyZSApO1xuXHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlMkQoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwLCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgYWN0aXZlQ3ViZUZhY2UsIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlLCBhY3RpdmVNaXBtYXBMZXZlbCApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBpc1JlbmRlclRhcmdldDNEICkge1xuXG5cdFx0XHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldC50ZXh0dXJlICk7XG5cdFx0XHRcdGNvbnN0IGxheWVyID0gYWN0aXZlQ3ViZUZhY2UgfHwgMDtcblx0XHRcdFx0X2dsLmZyYW1lYnVmZmVyVGV4dHVyZUxheWVyKCBfZ2wuRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIGFjdGl2ZU1pcG1hcExldmVsIHx8IDAsIGxheWVyICk7XG5cblx0XHRcdH1cblxuXHRcdFx0X2N1cnJlbnRNYXRlcmlhbElkID0gLSAxOyAvLyByZXNldCBjdXJyZW50IG1hdGVyaWFsIHRvIGVuc3VyZSBjb3JyZWN0IHVuaWZvcm0gYmluZGluZ3NcblxuXHRcdH07XG5cblx0XHR0aGlzLnJlYWRSZW5kZXJUYXJnZXRQaXhlbHMgPSBmdW5jdGlvbiAoIHJlbmRlclRhcmdldCwgeCwgeSwgd2lkdGgsIGhlaWdodCwgYnVmZmVyLCBhY3RpdmVDdWJlRmFjZUluZGV4ICkge1xuXG5cdFx0XHRpZiAoICEgKCByZW5kZXJUYXJnZXQgJiYgcmVuZGVyVGFyZ2V0LmlzV2ViR0xSZW5kZXJUYXJnZXQgKSApIHtcblxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xSZW5kZXJlci5yZWFkUmVuZGVyVGFyZ2V0UGl4ZWxzOiByZW5kZXJUYXJnZXQgaXMgbm90IFRIUkVFLldlYkdMUmVuZGVyVGFyZ2V0LicgKTtcblx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHR9XG5cblx0XHRcdGxldCBmcmFtZWJ1ZmZlciA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKS5fX3dlYmdsRnJhbWVidWZmZXI7XG5cblx0XHRcdGlmICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xDdWJlUmVuZGVyVGFyZ2V0ICYmIGFjdGl2ZUN1YmVGYWNlSW5kZXggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRmcmFtZWJ1ZmZlciA9IGZyYW1lYnVmZmVyWyBhY3RpdmVDdWJlRmFjZUluZGV4IF07XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBmcmFtZWJ1ZmZlciApIHtcblxuXHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgZnJhbWVidWZmZXIgKTtcblxuXHRcdFx0XHR0cnkge1xuXG5cdFx0XHRcdFx0Y29uc3QgdGV4dHVyZSA9IHJlbmRlclRhcmdldC50ZXh0dXJlO1xuXHRcdFx0XHRcdGNvbnN0IHRleHR1cmVGb3JtYXQgPSB0ZXh0dXJlLmZvcm1hdDtcblx0XHRcdFx0XHRjb25zdCB0ZXh0dXJlVHlwZSA9IHRleHR1cmUudHlwZTtcblxuXHRcdFx0XHRcdGlmICggISBjYXBhYmlsaXRpZXMudGV4dHVyZUZvcm1hdFJlYWRhYmxlKCB0ZXh0dXJlRm9ybWF0ICkgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyLnJlYWRSZW5kZXJUYXJnZXRQaXhlbHM6IHJlbmRlclRhcmdldCBpcyBub3QgaW4gUkdCQSBvciBpbXBsZW1lbnRhdGlvbiBkZWZpbmVkIGZvcm1hdC4nICk7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoICEgY2FwYWJpbGl0aWVzLnRleHR1cmVUeXBlUmVhZGFibGUoIHRleHR1cmVUeXBlICkgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyLnJlYWRSZW5kZXJUYXJnZXRQaXhlbHM6IHJlbmRlclRhcmdldCBpcyBub3QgaW4gVW5zaWduZWRCeXRlVHlwZSBvciBpbXBsZW1lbnRhdGlvbiBkZWZpbmVkIHR5cGUuJyApO1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gdGhlIGZvbGxvd2luZyBpZiBzdGF0ZW1lbnQgZW5zdXJlcyB2YWxpZCByZWFkIHJlcXVlc3RzIChubyBvdXQtb2YtYm91bmRzIHBpeGVscywgc2VlICM4NjA0KVxuXG5cdFx0XHRcdFx0aWYgKCAoIHggPj0gMCAmJiB4IDw9ICggcmVuZGVyVGFyZ2V0LndpZHRoIC0gd2lkdGggKSApICYmICggeSA+PSAwICYmIHkgPD0gKCByZW5kZXJUYXJnZXQuaGVpZ2h0IC0gaGVpZ2h0ICkgKSApIHtcblxuXHRcdFx0XHRcdFx0X2dsLnJlYWRQaXhlbHMoIHgsIHksIHdpZHRoLCBoZWlnaHQsIHV0aWxzLmNvbnZlcnQoIHRleHR1cmVGb3JtYXQgKSwgdXRpbHMuY29udmVydCggdGV4dHVyZVR5cGUgKSwgYnVmZmVyICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBmaW5hbGx5IHtcblxuXHRcdFx0XHRcdC8vIHJlc3RvcmUgZnJhbWVidWZmZXIgb2YgY3VycmVudCByZW5kZXIgdGFyZ2V0IGlmIG5lY2Vzc2FyeVxuXG5cdFx0XHRcdFx0Y29uc3QgZnJhbWVidWZmZXIgPSAoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ICE9PSBudWxsICkgPyBwcm9wZXJ0aWVzLmdldCggX2N1cnJlbnRSZW5kZXJUYXJnZXQgKS5fX3dlYmdsRnJhbWVidWZmZXIgOiBudWxsO1xuXHRcdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdHRoaXMucmVhZFJlbmRlclRhcmdldFBpeGVsc0FzeW5jID0gYXN5bmMgZnVuY3Rpb24gKCByZW5kZXJUYXJnZXQsIHgsIHksIHdpZHRoLCBoZWlnaHQsIGJ1ZmZlciwgYWN0aXZlQ3ViZUZhY2VJbmRleCApIHtcblxuXHRcdFx0aWYgKCAhICggcmVuZGVyVGFyZ2V0ICYmIHJlbmRlclRhcmdldC5pc1dlYkdMUmVuZGVyVGFyZ2V0ICkgKSB7XG5cblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuV2ViR0xSZW5kZXJlci5yZWFkUmVuZGVyVGFyZ2V0UGl4ZWxzOiByZW5kZXJUYXJnZXQgaXMgbm90IFRIUkVFLldlYkdMUmVuZGVyVGFyZ2V0LicgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRsZXQgZnJhbWVidWZmZXIgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0ICkuX193ZWJnbEZyYW1lYnVmZmVyO1xuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgJiYgYWN0aXZlQ3ViZUZhY2VJbmRleCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGZyYW1lYnVmZmVyID0gZnJhbWVidWZmZXJbIGFjdGl2ZUN1YmVGYWNlSW5kZXggXTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGZyYW1lYnVmZmVyICkge1xuXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xuXG5cdFx0XHRcdHRyeSB7XG5cblx0XHRcdFx0XHRjb25zdCB0ZXh0dXJlID0gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XG5cdFx0XHRcdFx0Y29uc3QgdGV4dHVyZUZvcm1hdCA9IHRleHR1cmUuZm9ybWF0O1xuXHRcdFx0XHRcdGNvbnN0IHRleHR1cmVUeXBlID0gdGV4dHVyZS50eXBlO1xuXG5cdFx0XHRcdFx0aWYgKCAhIGNhcGFiaWxpdGllcy50ZXh0dXJlRm9ybWF0UmVhZGFibGUoIHRleHR1cmVGb3JtYXQgKSApIHtcblxuXHRcdFx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuV2ViR0xSZW5kZXJlci5yZWFkUmVuZGVyVGFyZ2V0UGl4ZWxzQXN5bmM6IHJlbmRlclRhcmdldCBpcyBub3QgaW4gUkdCQSBvciBpbXBsZW1lbnRhdGlvbiBkZWZpbmVkIGZvcm1hdC4nICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoICEgY2FwYWJpbGl0aWVzLnRleHR1cmVUeXBlUmVhZGFibGUoIHRleHR1cmVUeXBlICkgKSB7XG5cblx0XHRcdFx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXIucmVhZFJlbmRlclRhcmdldFBpeGVsc0FzeW5jOiByZW5kZXJUYXJnZXQgaXMgbm90IGluIFVuc2lnbmVkQnl0ZVR5cGUgb3IgaW1wbGVtZW50YXRpb24gZGVmaW5lZCB0eXBlLicgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIHRoZSBmb2xsb3dpbmcgaWYgc3RhdGVtZW50IGVuc3VyZXMgdmFsaWQgcmVhZCByZXF1ZXN0cyAobm8gb3V0LW9mLWJvdW5kcyBwaXhlbHMsIHNlZSAjODYwNClcblx0XHRcdFx0XHRpZiAoICggeCA+PSAwICYmIHggPD0gKCByZW5kZXJUYXJnZXQud2lkdGggLSB3aWR0aCApICkgJiYgKCB5ID49IDAgJiYgeSA8PSAoIHJlbmRlclRhcmdldC5oZWlnaHQgLSBoZWlnaHQgKSApICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBnbEJ1ZmZlciA9IF9nbC5jcmVhdGVCdWZmZXIoKTtcblx0XHRcdFx0XHRcdF9nbC5iaW5kQnVmZmVyKCBfZ2wuUElYRUxfUEFDS19CVUZGRVIsIGdsQnVmZmVyICk7XG5cdFx0XHRcdFx0XHRfZ2wuYnVmZmVyRGF0YSggX2dsLlBJWEVMX1BBQ0tfQlVGRkVSLCBidWZmZXIuYnl0ZUxlbmd0aCwgX2dsLlNUUkVBTV9SRUFEICk7XG5cdFx0XHRcdFx0XHRfZ2wucmVhZFBpeGVscyggeCwgeSwgd2lkdGgsIGhlaWdodCwgdXRpbHMuY29udmVydCggdGV4dHVyZUZvcm1hdCApLCB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlVHlwZSApLCAwICk7XG5cdFx0XHRcdFx0XHRfZ2wuZmx1c2goKTtcblxuXHRcdFx0XHRcdFx0Ly8gY2hlY2sgaWYgdGhlIGNvbW1hbmRzIGhhdmUgZmluaXNoZWQgZXZlcnkgOCBtc1xuXHRcdFx0XHRcdFx0Y29uc3Qgc3luYyA9IF9nbC5mZW5jZVN5bmMoIF9nbC5TWU5DX0dQVV9DT01NQU5EU19DT01QTEVURSwgMCApO1xuXHRcdFx0XHRcdFx0YXdhaXQgcHJvYmVBc3luYyggX2dsLCBzeW5jLCA0ICk7XG5cblx0XHRcdFx0XHRcdHRyeSB7XG5cblx0XHRcdFx0XHRcdFx0X2dsLmJpbmRCdWZmZXIoIF9nbC5QSVhFTF9QQUNLX0JVRkZFUiwgZ2xCdWZmZXIgKTtcblx0XHRcdFx0XHRcdFx0X2dsLmdldEJ1ZmZlclN1YkRhdGEoIF9nbC5QSVhFTF9QQUNLX0JVRkZFUiwgMCwgYnVmZmVyICk7XG5cblx0XHRcdFx0XHRcdH0gZmluYWxseSB7XG5cblx0XHRcdFx0XHRcdFx0X2dsLmRlbGV0ZUJ1ZmZlciggZ2xCdWZmZXIgKTtcblx0XHRcdFx0XHRcdFx0X2dsLmRlbGV0ZVN5bmMoIHN5bmMgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRyZXR1cm4gYnVmZmVyO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZmluYWxseSB7XG5cblx0XHRcdFx0XHQvLyByZXN0b3JlIGZyYW1lYnVmZmVyIG9mIGN1cnJlbnQgcmVuZGVyIHRhcmdldCBpZiBuZWNlc3NhcnlcblxuXHRcdFx0XHRcdGNvbnN0IGZyYW1lYnVmZmVyID0gKCBfY3VycmVudFJlbmRlclRhcmdldCAhPT0gbnVsbCApID8gcHJvcGVydGllcy5nZXQoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ICkuX193ZWJnbEZyYW1lYnVmZmVyIDogbnVsbDtcblx0XHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgZnJhbWVidWZmZXIgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH07XG5cblx0XHR0aGlzLmNvcHlGcmFtZWJ1ZmZlclRvVGV4dHVyZSA9IGZ1bmN0aW9uICggdGV4dHVyZSwgcG9zaXRpb24gPSBudWxsLCBsZXZlbCA9IDAgKSB7XG5cblx0XHRcdC8vIHN1cHBvcnQgcHJldmlvdXMgc2lnbmF0dXJlIHdpdGggcG9zaXRpb24gZmlyc3Rcblx0XHRcdGlmICggdGV4dHVyZS5pc1RleHR1cmUgIT09IHRydWUgKSB7XG5cblx0XHRcdFx0Ly8gQGRlcHJlY2F0ZWQsIHIxNjVcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnV2ViR0xSZW5kZXJlcjogY29weUZyYW1lYnVmZmVyVG9UZXh0dXJlIGZ1bmN0aW9uIHNpZ25hdHVyZSBoYXMgY2hhbmdlZC4nICk7XG5cblx0XHRcdFx0cG9zaXRpb24gPSBhcmd1bWVudHNbIDAgXSB8fCBudWxsO1xuXHRcdFx0XHR0ZXh0dXJlID0gYXJndW1lbnRzWyAxIF07XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgbGV2ZWxTY2FsZSA9IE1hdGgucG93KCAyLCAtIGxldmVsICk7XG5cdFx0XHRjb25zdCB3aWR0aCA9IE1hdGguZmxvb3IoIHRleHR1cmUuaW1hZ2Uud2lkdGggKiBsZXZlbFNjYWxlICk7XG5cdFx0XHRjb25zdCBoZWlnaHQgPSBNYXRoLmZsb29yKCB0ZXh0dXJlLmltYWdlLmhlaWdodCAqIGxldmVsU2NhbGUgKTtcblxuXHRcdFx0Y29uc3QgeCA9IHBvc2l0aW9uICE9PSBudWxsID8gcG9zaXRpb24ueCA6IDA7XG5cdFx0XHRjb25zdCB5ID0gcG9zaXRpb24gIT09IG51bGwgPyBwb3NpdGlvbi55IDogMDtcblxuXHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZTJEKCB0ZXh0dXJlLCAwICk7XG5cblx0XHRcdF9nbC5jb3B5VGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVsLCAwLCAwLCB4LCB5LCB3aWR0aCwgaGVpZ2h0ICk7XG5cblx0XHRcdHN0YXRlLnVuYmluZFRleHR1cmUoKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmNvcHlUZXh0dXJlVG9UZXh0dXJlID0gZnVuY3Rpb24gKCBzcmNUZXh0dXJlLCBkc3RUZXh0dXJlLCBzcmNSZWdpb24gPSBudWxsLCBkc3RQb3NpdGlvbiA9IG51bGwsIGxldmVsID0gMCApIHtcblxuXHRcdFx0Ly8gc3VwcG9ydCBwcmV2aW91cyBzaWduYXR1cmUgd2l0aCBkc3RQb3NpdGlvbiBmaXJzdFxuXHRcdFx0aWYgKCBzcmNUZXh0dXJlLmlzVGV4dHVyZSAhPT0gdHJ1ZSApIHtcblxuXHRcdFx0XHQvLyBAZGVwcmVjYXRlZCwgcjE2NVxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdXZWJHTFJlbmRlcmVyOiBjb3B5VGV4dHVyZVRvVGV4dHVyZSBmdW5jdGlvbiBzaWduYXR1cmUgaGFzIGNoYW5nZWQuJyApO1xuXG5cdFx0XHRcdGRzdFBvc2l0aW9uID0gYXJndW1lbnRzWyAwIF0gfHwgbnVsbDtcblx0XHRcdFx0c3JjVGV4dHVyZSA9IGFyZ3VtZW50c1sgMSBdO1xuXHRcdFx0XHRkc3RUZXh0dXJlID0gYXJndW1lbnRzWyAyIF07XG5cdFx0XHRcdGxldmVsID0gYXJndW1lbnRzWyAzIF0gfHwgMDtcblx0XHRcdFx0c3JjUmVnaW9uID0gbnVsbDtcblxuXHRcdFx0fVxuXG5cdFx0XHRsZXQgd2lkdGgsIGhlaWdodCwgbWluWCwgbWluWTtcblx0XHRcdGxldCBkc3RYLCBkc3RZO1xuXHRcdFx0aWYgKCBzcmNSZWdpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0d2lkdGggPSBzcmNSZWdpb24ubWF4LnggLSBzcmNSZWdpb24ubWluLng7XG5cdFx0XHRcdGhlaWdodCA9IHNyY1JlZ2lvbi5tYXgueSAtIHNyY1JlZ2lvbi5taW4ueTtcblx0XHRcdFx0bWluWCA9IHNyY1JlZ2lvbi5taW4ueDtcblx0XHRcdFx0bWluWSA9IHNyY1JlZ2lvbi5taW4ueTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHR3aWR0aCA9IHNyY1RleHR1cmUuaW1hZ2Uud2lkdGg7XG5cdFx0XHRcdGhlaWdodCA9IHNyY1RleHR1cmUuaW1hZ2UuaGVpZ2h0O1xuXHRcdFx0XHRtaW5YID0gMDtcblx0XHRcdFx0bWluWSA9IDA7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBkc3RQb3NpdGlvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRkc3RYID0gZHN0UG9zaXRpb24ueDtcblx0XHRcdFx0ZHN0WSA9IGRzdFBvc2l0aW9uLnk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0ZHN0WCA9IDA7XG5cdFx0XHRcdGRzdFkgPSAwO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggZHN0VGV4dHVyZS5mb3JtYXQgKTtcblx0XHRcdGNvbnN0IGdsVHlwZSA9IHV0aWxzLmNvbnZlcnQoIGRzdFRleHR1cmUudHlwZSApO1xuXG5cdFx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlMkQoIGRzdFRleHR1cmUsIDAgKTtcblxuXHRcdFx0Ly8gQXMgYW5vdGhlciB0ZXh0dXJlIHVwbG9hZCBtYXkgaGF2ZSBjaGFuZ2VkIHBpeGVsU3RvcmVpXG5cdFx0XHQvLyBwYXJhbWV0ZXJzLCBtYWtlIHN1cmUgdGhleSBhcmUgY29ycmVjdCBmb3IgdGhlIGRzdFRleHR1cmVcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19GTElQX1lfV0VCR0wsIGRzdFRleHR1cmUuZmxpcFkgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19QUkVNVUxUSVBMWV9BTFBIQV9XRUJHTCwgZHN0VGV4dHVyZS5wcmVtdWx0aXBseUFscGhhICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfQUxJR05NRU5ULCBkc3RUZXh0dXJlLnVucGFja0FsaWdubWVudCApO1xuXG5cdFx0XHRjb25zdCBjdXJyZW50VW5wYWNrUm93TGVuID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19ST1dfTEVOR1RIICk7XG5cdFx0XHRjb25zdCBjdXJyZW50VW5wYWNrSW1hZ2VIZWlnaHQgPSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuVU5QQUNLX0lNQUdFX0hFSUdIVCApO1xuXHRcdFx0Y29uc3QgY3VycmVudFVucGFja1NraXBQaXhlbHMgPSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuVU5QQUNLX1NLSVBfUElYRUxTICk7XG5cdFx0XHRjb25zdCBjdXJyZW50VW5wYWNrU2tpcFJvd3MgPSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuVU5QQUNLX1NLSVBfUk9XUyApO1xuXHRcdFx0Y29uc3QgY3VycmVudFVucGFja1NraXBJbWFnZXMgPSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuVU5QQUNLX1NLSVBfSU1BR0VTICk7XG5cblx0XHRcdGNvbnN0IGltYWdlID0gc3JjVGV4dHVyZS5pc0NvbXByZXNzZWRUZXh0dXJlID8gc3JjVGV4dHVyZS5taXBtYXBzWyBsZXZlbCBdIDogc3JjVGV4dHVyZS5pbWFnZTtcblxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1JPV19MRU5HVEgsIGltYWdlLndpZHRoICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfSU1BR0VfSEVJR0hULCBpbWFnZS5oZWlnaHQgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19TS0lQX1BJWEVMUywgbWluWCApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUk9XUywgbWluWSApO1xuXG5cdFx0XHRpZiAoIHNyY1RleHR1cmUuaXNEYXRhVGV4dHVyZSApIHtcblxuXHRcdFx0XHRfZ2wudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVsLCBkc3RYLCBkc3RZLCB3aWR0aCwgaGVpZ2h0LCBnbEZvcm1hdCwgZ2xUeXBlLCBpbWFnZS5kYXRhICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0aWYgKCBzcmNUZXh0dXJlLmlzQ29tcHJlc3NlZFRleHR1cmUgKSB7XG5cblx0XHRcdFx0XHRfZ2wuY29tcHJlc3NlZFRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbCwgZHN0WCwgZHN0WSwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgZ2xGb3JtYXQsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0X2dsLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbCwgZHN0WCwgZHN0WSwgd2lkdGgsIGhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1JPV19MRU5HVEgsIGN1cnJlbnRVbnBhY2tSb3dMZW4gKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19JTUFHRV9IRUlHSFQsIGN1cnJlbnRVbnBhY2tJbWFnZUhlaWdodCApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUElYRUxTLCBjdXJyZW50VW5wYWNrU2tpcFBpeGVscyApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUk9XUywgY3VycmVudFVucGFja1NraXBSb3dzICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfU0tJUF9JTUFHRVMsIGN1cnJlbnRVbnBhY2tTa2lwSW1hZ2VzICk7XG5cblx0XHRcdC8vIEdlbmVyYXRlIG1pcG1hcHMgb25seSB3aGVuIGNvcHlpbmcgbGV2ZWwgMFxuXHRcdFx0aWYgKCBsZXZlbCA9PT0gMCAmJiBkc3RUZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyApIF9nbC5nZW5lcmF0ZU1pcG1hcCggX2dsLlRFWFRVUkVfMkQgKTtcblxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuY29weVRleHR1cmVUb1RleHR1cmUzRCA9IGZ1bmN0aW9uICggc3JjVGV4dHVyZSwgZHN0VGV4dHVyZSwgc3JjUmVnaW9uID0gbnVsbCwgZHN0UG9zaXRpb24gPSBudWxsLCBsZXZlbCA9IDAgKSB7XG5cblx0XHRcdC8vIHN1cHBvcnQgcHJldmlvdXMgc2lnbmF0dXJlIHdpdGggc291cmNlIGJveCBmaXJzdFxuXHRcdFx0aWYgKCBzcmNUZXh0dXJlLmlzVGV4dHVyZSAhPT0gdHJ1ZSApIHtcblxuXHRcdFx0XHQvLyBAZGVwcmVjYXRlZCwgcjE2NVxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdXZWJHTFJlbmRlcmVyOiBjb3B5VGV4dHVyZVRvVGV4dHVyZTNEIGZ1bmN0aW9uIHNpZ25hdHVyZSBoYXMgY2hhbmdlZC4nICk7XG5cblx0XHRcdFx0c3JjUmVnaW9uID0gYXJndW1lbnRzWyAwIF0gfHwgbnVsbDtcblx0XHRcdFx0ZHN0UG9zaXRpb24gPSBhcmd1bWVudHNbIDEgXSB8fCBudWxsO1xuXHRcdFx0XHRzcmNUZXh0dXJlID0gYXJndW1lbnRzWyAyIF07XG5cdFx0XHRcdGRzdFRleHR1cmUgPSBhcmd1bWVudHNbIDMgXTtcblx0XHRcdFx0bGV2ZWwgPSBhcmd1bWVudHNbIDQgXSB8fCAwO1xuXG5cdFx0XHR9XG5cblx0XHRcdGxldCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCwgbWluWCwgbWluWSwgbWluWjtcblx0XHRcdGxldCBkc3RYLCBkc3RZLCBkc3RaO1xuXHRcdFx0Y29uc3QgaW1hZ2UgPSBzcmNUZXh0dXJlLmlzQ29tcHJlc3NlZFRleHR1cmUgPyBzcmNUZXh0dXJlLm1pcG1hcHNbIGxldmVsIF0gOiBzcmNUZXh0dXJlLmltYWdlO1xuXHRcdFx0aWYgKCBzcmNSZWdpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0d2lkdGggPSBzcmNSZWdpb24ubWF4LnggLSBzcmNSZWdpb24ubWluLng7XG5cdFx0XHRcdGhlaWdodCA9IHNyY1JlZ2lvbi5tYXgueSAtIHNyY1JlZ2lvbi5taW4ueTtcblx0XHRcdFx0ZGVwdGggPSBzcmNSZWdpb24ubWF4LnogLSBzcmNSZWdpb24ubWluLno7XG5cdFx0XHRcdG1pblggPSBzcmNSZWdpb24ubWluLng7XG5cdFx0XHRcdG1pblkgPSBzcmNSZWdpb24ubWluLnk7XG5cdFx0XHRcdG1pblogPSBzcmNSZWdpb24ubWluLno7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0d2lkdGggPSBpbWFnZS53aWR0aDtcblx0XHRcdFx0aGVpZ2h0ID0gaW1hZ2UuaGVpZ2h0O1xuXHRcdFx0XHRkZXB0aCA9IGltYWdlLmRlcHRoO1xuXHRcdFx0XHRtaW5YID0gMDtcblx0XHRcdFx0bWluWSA9IDA7XG5cdFx0XHRcdG1pblogPSAwO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggZHN0UG9zaXRpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0ZHN0WCA9IGRzdFBvc2l0aW9uLng7XG5cdFx0XHRcdGRzdFkgPSBkc3RQb3NpdGlvbi55O1xuXHRcdFx0XHRkc3RaID0gZHN0UG9zaXRpb24uejtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRkc3RYID0gMDtcblx0XHRcdFx0ZHN0WSA9IDA7XG5cdFx0XHRcdGRzdFogPSAwO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggZHN0VGV4dHVyZS5mb3JtYXQgKTtcblx0XHRcdGNvbnN0IGdsVHlwZSA9IHV0aWxzLmNvbnZlcnQoIGRzdFRleHR1cmUudHlwZSApO1xuXHRcdFx0bGV0IGdsVGFyZ2V0O1xuXG5cdFx0XHRpZiAoIGRzdFRleHR1cmUuaXNEYXRhM0RUZXh0dXJlICkge1xuXG5cdFx0XHRcdHRleHR1cmVzLnNldFRleHR1cmUzRCggZHN0VGV4dHVyZSwgMCApO1xuXHRcdFx0XHRnbFRhcmdldCA9IF9nbC5URVhUVVJFXzNEO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBkc3RUZXh0dXJlLmlzRGF0YUFycmF5VGV4dHVyZSB8fCBkc3RUZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHtcblxuXHRcdFx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlMkRBcnJheSggZHN0VGV4dHVyZSwgMCApO1xuXHRcdFx0XHRnbFRhcmdldCA9IF9nbC5URVhUVVJFXzJEX0FSUkFZO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXIuY29weVRleHR1cmVUb1RleHR1cmUzRDogb25seSBzdXBwb3J0cyBUSFJFRS5EYXRhVGV4dHVyZTNEIGFuZCBUSFJFRS5EYXRhVGV4dHVyZTJEQXJyYXkuJyApO1xuXHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdH1cblxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0ZMSVBfWV9XRUJHTCwgZHN0VGV4dHVyZS5mbGlwWSApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1BSRU1VTFRJUExZX0FMUEhBX1dFQkdMLCBkc3RUZXh0dXJlLnByZW11bHRpcGx5QWxwaGEgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19BTElHTk1FTlQsIGRzdFRleHR1cmUudW5wYWNrQWxpZ25tZW50ICk7XG5cblx0XHRcdGNvbnN0IGN1cnJlbnRVbnBhY2tSb3dMZW4gPSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuVU5QQUNLX1JPV19MRU5HVEggKTtcblx0XHRcdGNvbnN0IGN1cnJlbnRVbnBhY2tJbWFnZUhlaWdodCA9IF9nbC5nZXRQYXJhbWV0ZXIoIF9nbC5VTlBBQ0tfSU1BR0VfSEVJR0hUICk7XG5cdFx0XHRjb25zdCBjdXJyZW50VW5wYWNrU2tpcFBpeGVscyA9IF9nbC5nZXRQYXJhbWV0ZXIoIF9nbC5VTlBBQ0tfU0tJUF9QSVhFTFMgKTtcblx0XHRcdGNvbnN0IGN1cnJlbnRVbnBhY2tTa2lwUm93cyA9IF9nbC5nZXRQYXJhbWV0ZXIoIF9nbC5VTlBBQ0tfU0tJUF9ST1dTICk7XG5cdFx0XHRjb25zdCBjdXJyZW50VW5wYWNrU2tpcEltYWdlcyA9IF9nbC5nZXRQYXJhbWV0ZXIoIF9nbC5VTlBBQ0tfU0tJUF9JTUFHRVMgKTtcblxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1JPV19MRU5HVEgsIGltYWdlLndpZHRoICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfSU1BR0VfSEVJR0hULCBpbWFnZS5oZWlnaHQgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19TS0lQX1BJWEVMUywgbWluWCApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUk9XUywgbWluWSApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfSU1BR0VTLCBtaW5aICk7XG5cblx0XHRcdGlmICggc3JjVGV4dHVyZS5pc0RhdGFUZXh0dXJlIHx8IHNyY1RleHR1cmUuaXNEYXRhM0RUZXh0dXJlICkge1xuXG5cdFx0XHRcdF9nbC50ZXhTdWJJbWFnZTNEKCBnbFRhcmdldCwgbGV2ZWwsIGRzdFgsIGRzdFksIGRzdFosIHdpZHRoLCBoZWlnaHQsIGRlcHRoLCBnbEZvcm1hdCwgZ2xUeXBlLCBpbWFnZS5kYXRhICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0aWYgKCBkc3RUZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHtcblxuXHRcdFx0XHRcdF9nbC5jb21wcmVzc2VkVGV4U3ViSW1hZ2UzRCggZ2xUYXJnZXQsIGxldmVsLCBkc3RYLCBkc3RZLCBkc3RaLCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCwgZ2xGb3JtYXQsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0X2dsLnRleFN1YkltYWdlM0QoIGdsVGFyZ2V0LCBsZXZlbCwgZHN0WCwgZHN0WSwgZHN0Wiwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19ST1dfTEVOR1RILCBjdXJyZW50VW5wYWNrUm93TGVuICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfSU1BR0VfSEVJR0hULCBjdXJyZW50VW5wYWNrSW1hZ2VIZWlnaHQgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19TS0lQX1BJWEVMUywgY3VycmVudFVucGFja1NraXBQaXhlbHMgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19TS0lQX1JPV1MsIGN1cnJlbnRVbnBhY2tTa2lwUm93cyApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfSU1BR0VTLCBjdXJyZW50VW5wYWNrU2tpcEltYWdlcyApO1xuXG5cdFx0XHQvLyBHZW5lcmF0ZSBtaXBtYXBzIG9ubHkgd2hlbiBjb3B5aW5nIGxldmVsIDBcblx0XHRcdGlmICggbGV2ZWwgPT09IDAgJiYgZHN0VGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgKSBfZ2wuZ2VuZXJhdGVNaXBtYXAoIGdsVGFyZ2V0ICk7XG5cblx0XHRcdHN0YXRlLnVuYmluZFRleHR1cmUoKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmluaXRSZW5kZXJUYXJnZXQgPSBmdW5jdGlvbiAoIHRhcmdldCApIHtcblxuXHRcdFx0aWYgKCBwcm9wZXJ0aWVzLmdldCggdGFyZ2V0ICkuX193ZWJnbEZyYW1lYnVmZmVyID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGV4dHVyZXMuc2V0dXBSZW5kZXJUYXJnZXQoIHRhcmdldCApO1xuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5pbml0VGV4dHVyZSA9IGZ1bmN0aW9uICggdGV4dHVyZSApIHtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlLmlzQ3ViZVRleHR1cmUgKSB7XG5cblx0XHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZUN1YmUoIHRleHR1cmUsIDAgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0RhdGEzRFRleHR1cmUgKSB7XG5cblx0XHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZTNEKCB0ZXh0dXJlLCAwICk7XG5cblx0XHRcdH0gZWxzZSBpZiAoIHRleHR1cmUuaXNEYXRhQXJyYXlUZXh0dXJlIHx8IHRleHR1cmUuaXNDb21wcmVzc2VkQXJyYXlUZXh0dXJlICkge1xuXG5cdFx0XHRcdHRleHR1cmVzLnNldFRleHR1cmUyREFycmF5KCB0ZXh0dXJlLCAwICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZTJEKCB0ZXh0dXJlLCAwICk7XG5cblx0XHRcdH1cblxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMucmVzZXRTdGF0ZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0X2N1cnJlbnRBY3RpdmVDdWJlRmFjZSA9IDA7XG5cdFx0XHRfY3VycmVudEFjdGl2ZU1pcG1hcExldmVsID0gMDtcblx0XHRcdF9jdXJyZW50UmVuZGVyVGFyZ2V0ID0gbnVsbDtcblxuXHRcdFx0c3RhdGUucmVzZXQoKTtcblx0XHRcdGJpbmRpbmdTdGF0ZXMucmVzZXQoKTtcblxuXHRcdH07XG5cblx0XHRpZiAoIHR5cGVvZiBfX1RIUkVFX0RFVlRPT0xTX18gIT09ICd1bmRlZmluZWQnICkge1xuXG5cdFx0XHRfX1RIUkVFX0RFVlRPT0xTX18uZGlzcGF0Y2hFdmVudCggbmV3IEN1c3RvbUV2ZW50KCAnb2JzZXJ2ZScsIHsgZGV0YWlsOiB0aGlzIH0gKSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRnZXQgY29vcmRpbmF0ZVN5c3RlbSgpIHtcblxuXHRcdHJldHVybiBXZWJHTENvb3JkaW5hdGVTeXN0ZW07XG5cblx0fVxuXG5cdGdldCBvdXRwdXRDb2xvclNwYWNlKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX291dHB1dENvbG9yU3BhY2U7XG5cblx0fVxuXG5cdHNldCBvdXRwdXRDb2xvclNwYWNlKCBjb2xvclNwYWNlICkge1xuXG5cdFx0dGhpcy5fb3V0cHV0Q29sb3JTcGFjZSA9IGNvbG9yU3BhY2U7XG5cblx0XHRjb25zdCBnbCA9IHRoaXMuZ2V0Q29udGV4dCgpO1xuXHRcdGdsLmRyYXdpbmdCdWZmZXJDb2xvclNwYWNlID0gY29sb3JTcGFjZSA9PT0gRGlzcGxheVAzQ29sb3JTcGFjZSA/ICdkaXNwbGF5LXAzJyA6ICdzcmdiJztcblx0XHRnbC51bnBhY2tDb2xvclNwYWNlID0gQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlID09PSBMaW5lYXJEaXNwbGF5UDNDb2xvclNwYWNlID8gJ2Rpc3BsYXktcDMnIDogJ3NyZ2InO1xuXG5cdH1cblxufVxuXG5jbGFzcyBGb2dFeHAyIHtcblxuXHRjb25zdHJ1Y3RvciggY29sb3IsIGRlbnNpdHkgPSAwLjAwMDI1ICkge1xuXG5cdFx0dGhpcy5pc0ZvZ0V4cDIgPSB0cnVlO1xuXG5cdFx0dGhpcy5uYW1lID0gJyc7XG5cblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCBjb2xvciApO1xuXHRcdHRoaXMuZGVuc2l0eSA9IGRlbnNpdHk7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyBGb2dFeHAyKCB0aGlzLmNvbG9yLCB0aGlzLmRlbnNpdHkgKTtcblxuXHR9XG5cblx0dG9KU09OKCAvKiBtZXRhICovICkge1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHR5cGU6ICdGb2dFeHAyJyxcblx0XHRcdG5hbWU6IHRoaXMubmFtZSxcblx0XHRcdGNvbG9yOiB0aGlzLmNvbG9yLmdldEhleCgpLFxuXHRcdFx0ZGVuc2l0eTogdGhpcy5kZW5zaXR5XG5cdFx0fTtcblxuXHR9XG5cbn1cblxuY2xhc3MgRm9nIHtcblxuXHRjb25zdHJ1Y3RvciggY29sb3IsIG5lYXIgPSAxLCBmYXIgPSAxMDAwICkge1xuXG5cdFx0dGhpcy5pc0ZvZyA9IHRydWU7XG5cblx0XHR0aGlzLm5hbWUgPSAnJztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIGNvbG9yICk7XG5cblx0XHR0aGlzLm5lYXIgPSBuZWFyO1xuXHRcdHRoaXMuZmFyID0gZmFyO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgRm9nKCB0aGlzLmNvbG9yLCB0aGlzLm5lYXIsIHRoaXMuZmFyICk7XG5cblx0fVxuXG5cdHRvSlNPTiggLyogbWV0YSAqLyApIHtcblxuXHRcdHJldHVybiB7XG5cdFx0XHR0eXBlOiAnRm9nJyxcblx0XHRcdG5hbWU6IHRoaXMubmFtZSxcblx0XHRcdGNvbG9yOiB0aGlzLmNvbG9yLmdldEhleCgpLFxuXHRcdFx0bmVhcjogdGhpcy5uZWFyLFxuXHRcdFx0ZmFyOiB0aGlzLmZhclxuXHRcdH07XG5cblx0fVxuXG59XG5cbmNsYXNzIFNjZW5lIGV4dGVuZHMgT2JqZWN0M0Qge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNTY2VuZSA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnU2NlbmUnO1xuXG5cdFx0dGhpcy5iYWNrZ3JvdW5kID0gbnVsbDtcblx0XHR0aGlzLmVudmlyb25tZW50ID0gbnVsbDtcblx0XHR0aGlzLmZvZyA9IG51bGw7XG5cblx0XHR0aGlzLmJhY2tncm91bmRCbHVycmluZXNzID0gMDtcblx0XHR0aGlzLmJhY2tncm91bmRJbnRlbnNpdHkgPSAxO1xuXHRcdHRoaXMuYmFja2dyb3VuZFJvdGF0aW9uID0gbmV3IEV1bGVyKCk7XG5cblx0XHR0aGlzLmVudmlyb25tZW50SW50ZW5zaXR5ID0gMTtcblx0XHR0aGlzLmVudmlyb25tZW50Um90YXRpb24gPSBuZXcgRXVsZXIoKTtcblxuXHRcdHRoaXMub3ZlcnJpZGVNYXRlcmlhbCA9IG51bGw7XG5cblx0XHRpZiAoIHR5cGVvZiBfX1RIUkVFX0RFVlRPT0xTX18gIT09ICd1bmRlZmluZWQnICkge1xuXG5cdFx0XHRfX1RIUkVFX0RFVlRPT0xTX18uZGlzcGF0Y2hFdmVudCggbmV3IEN1c3RvbUV2ZW50KCAnb2JzZXJ2ZScsIHsgZGV0YWlsOiB0aGlzIH0gKSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XG5cblx0XHRpZiAoIHNvdXJjZS5iYWNrZ3JvdW5kICE9PSBudWxsICkgdGhpcy5iYWNrZ3JvdW5kID0gc291cmNlLmJhY2tncm91bmQuY2xvbmUoKTtcblx0XHRpZiAoIHNvdXJjZS5lbnZpcm9ubWVudCAhPT0gbnVsbCApIHRoaXMuZW52aXJvbm1lbnQgPSBzb3VyY2UuZW52aXJvbm1lbnQuY2xvbmUoKTtcblx0XHRpZiAoIHNvdXJjZS5mb2cgIT09IG51bGwgKSB0aGlzLmZvZyA9IHNvdXJjZS5mb2cuY2xvbmUoKTtcblxuXHRcdHRoaXMuYmFja2dyb3VuZEJsdXJyaW5lc3MgPSBzb3VyY2UuYmFja2dyb3VuZEJsdXJyaW5lc3M7XG5cdFx0dGhpcy5iYWNrZ3JvdW5kSW50ZW5zaXR5ID0gc291cmNlLmJhY2tncm91bmRJbnRlbnNpdHk7XG5cdFx0dGhpcy5iYWNrZ3JvdW5kUm90YXRpb24uY29weSggc291cmNlLmJhY2tncm91bmRSb3RhdGlvbiApO1xuXG5cdFx0dGhpcy5lbnZpcm9ubWVudEludGVuc2l0eSA9IHNvdXJjZS5lbnZpcm9ubWVudEludGVuc2l0eTtcblx0XHR0aGlzLmVudmlyb25tZW50Um90YXRpb24uY29weSggc291cmNlLmVudmlyb25tZW50Um90YXRpb24gKTtcblxuXHRcdGlmICggc291cmNlLm92ZXJyaWRlTWF0ZXJpYWwgIT09IG51bGwgKSB0aGlzLm92ZXJyaWRlTWF0ZXJpYWwgPSBzb3VyY2Uub3ZlcnJpZGVNYXRlcmlhbC5jbG9uZSgpO1xuXG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gc291cmNlLm1hdHJpeEF1dG9VcGRhdGU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCBtZXRhICkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xuXG5cdFx0aWYgKCB0aGlzLmZvZyAhPT0gbnVsbCApIGRhdGEub2JqZWN0LmZvZyA9IHRoaXMuZm9nLnRvSlNPTigpO1xuXG5cdFx0aWYgKCB0aGlzLmJhY2tncm91bmRCbHVycmluZXNzID4gMCApIGRhdGEub2JqZWN0LmJhY2tncm91bmRCbHVycmluZXNzID0gdGhpcy5iYWNrZ3JvdW5kQmx1cnJpbmVzcztcblx0XHRpZiAoIHRoaXMuYmFja2dyb3VuZEludGVuc2l0eSAhPT0gMSApIGRhdGEub2JqZWN0LmJhY2tncm91bmRJbnRlbnNpdHkgPSB0aGlzLmJhY2tncm91bmRJbnRlbnNpdHk7XG5cdFx0ZGF0YS5vYmplY3QuYmFja2dyb3VuZFJvdGF0aW9uID0gdGhpcy5iYWNrZ3JvdW5kUm90YXRpb24udG9BcnJheSgpO1xuXG5cdFx0aWYgKCB0aGlzLmVudmlyb25tZW50SW50ZW5zaXR5ICE9PSAxICkgZGF0YS5vYmplY3QuZW52aXJvbm1lbnRJbnRlbnNpdHkgPSB0aGlzLmVudmlyb25tZW50SW50ZW5zaXR5O1xuXHRcdGRhdGEub2JqZWN0LmVudmlyb25tZW50Um90YXRpb24gPSB0aGlzLmVudmlyb25tZW50Um90YXRpb24udG9BcnJheSgpO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbmNsYXNzIEludGVybGVhdmVkQnVmZmVyIHtcblxuXHRjb25zdHJ1Y3RvciggYXJyYXksIHN0cmlkZSApIHtcblxuXHRcdHRoaXMuaXNJbnRlcmxlYXZlZEJ1ZmZlciA9IHRydWU7XG5cblx0XHR0aGlzLmFycmF5ID0gYXJyYXk7XG5cdFx0dGhpcy5zdHJpZGUgPSBzdHJpZGU7XG5cdFx0dGhpcy5jb3VudCA9IGFycmF5ICE9PSB1bmRlZmluZWQgPyBhcnJheS5sZW5ndGggLyBzdHJpZGUgOiAwO1xuXG5cdFx0dGhpcy51c2FnZSA9IFN0YXRpY0RyYXdVc2FnZTtcblx0XHR0aGlzLl91cGRhdGVSYW5nZSA9IHsgb2Zmc2V0OiAwLCBjb3VudDogLSAxIH07XG5cdFx0dGhpcy51cGRhdGVSYW5nZXMgPSBbXTtcblxuXHRcdHRoaXMudmVyc2lvbiA9IDA7XG5cblx0XHR0aGlzLnV1aWQgPSBnZW5lcmF0ZVVVSUQoKTtcblxuXHR9XG5cblx0b25VcGxvYWRDYWxsYmFjaygpIHt9XG5cblx0c2V0IG5lZWRzVXBkYXRlKCB2YWx1ZSApIHtcblxuXHRcdGlmICggdmFsdWUgPT09IHRydWUgKSB0aGlzLnZlcnNpb24gKys7XG5cblx0fVxuXG5cdGdldCB1cGRhdGVSYW5nZSgpIHtcblxuXHRcdHdhcm5PbmNlKCAnVEhSRUUuSW50ZXJsZWF2ZWRCdWZmZXI6IHVwZGF0ZVJhbmdlKCkgaXMgZGVwcmVjYXRlZCBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHIxNjkuIFVzZSBhZGRVcGRhdGVSYW5nZSgpIGluc3RlYWQuJyApOyAvLyBAZGVwcmVjYXRlZCwgcjE1OVxuXHRcdHJldHVybiB0aGlzLl91cGRhdGVSYW5nZTtcblxuXHR9XG5cblx0c2V0VXNhZ2UoIHZhbHVlICkge1xuXG5cdFx0dGhpcy51c2FnZSA9IHZhbHVlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFkZFVwZGF0ZVJhbmdlKCBzdGFydCwgY291bnQgKSB7XG5cblx0XHR0aGlzLnVwZGF0ZVJhbmdlcy5wdXNoKCB7IHN0YXJ0LCBjb3VudCB9ICk7XG5cblx0fVxuXG5cdGNsZWFyVXBkYXRlUmFuZ2VzKCkge1xuXG5cdFx0dGhpcy51cGRhdGVSYW5nZXMubGVuZ3RoID0gMDtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0dGhpcy5hcnJheSA9IG5ldyBzb3VyY2UuYXJyYXkuY29uc3RydWN0b3IoIHNvdXJjZS5hcnJheSApO1xuXHRcdHRoaXMuY291bnQgPSBzb3VyY2UuY291bnQ7XG5cdFx0dGhpcy5zdHJpZGUgPSBzb3VyY2Uuc3RyaWRlO1xuXHRcdHRoaXMudXNhZ2UgPSBzb3VyY2UudXNhZ2U7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weUF0KCBpbmRleDEsIGF0dHJpYnV0ZSwgaW5kZXgyICkge1xuXG5cdFx0aW5kZXgxICo9IHRoaXMuc3RyaWRlO1xuXHRcdGluZGV4MiAqPSBhdHRyaWJ1dGUuc3RyaWRlO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5zdHJpZGU7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmFycmF5WyBpbmRleDEgKyBpIF0gPSBhdHRyaWJ1dGUuYXJyYXlbIGluZGV4MiArIGkgXTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXQoIHZhbHVlLCBvZmZzZXQgPSAwICkge1xuXG5cdFx0dGhpcy5hcnJheS5zZXQoIHZhbHVlLCBvZmZzZXQgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSggZGF0YSApIHtcblxuXHRcdGlmICggZGF0YS5hcnJheUJ1ZmZlcnMgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0ZGF0YS5hcnJheUJ1ZmZlcnMgPSB7fTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5hcnJheS5idWZmZXIuX3V1aWQgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGhpcy5hcnJheS5idWZmZXIuX3V1aWQgPSBnZW5lcmF0ZVVVSUQoKTtcblxuXHRcdH1cblxuXHRcdGlmICggZGF0YS5hcnJheUJ1ZmZlcnNbIHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0ZGF0YS5hcnJheUJ1ZmZlcnNbIHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkIF0gPSB0aGlzLmFycmF5LnNsaWNlKCAwICkuYnVmZmVyO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgYXJyYXkgPSBuZXcgdGhpcy5hcnJheS5jb25zdHJ1Y3RvciggZGF0YS5hcnJheUJ1ZmZlcnNbIHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkIF0gKTtcblxuXHRcdGNvbnN0IGliID0gbmV3IHRoaXMuY29uc3RydWN0b3IoIGFycmF5LCB0aGlzLnN0cmlkZSApO1xuXHRcdGliLnNldFVzYWdlKCB0aGlzLnVzYWdlICk7XG5cblx0XHRyZXR1cm4gaWI7XG5cblx0fVxuXG5cdG9uVXBsb2FkKCBjYWxsYmFjayApIHtcblxuXHRcdHRoaXMub25VcGxvYWRDYWxsYmFjayA9IGNhbGxiYWNrO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTiggZGF0YSApIHtcblxuXHRcdGlmICggZGF0YS5hcnJheUJ1ZmZlcnMgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0ZGF0YS5hcnJheUJ1ZmZlcnMgPSB7fTtcblxuXHRcdH1cblxuXHRcdC8vIGdlbmVyYXRlIFVVSUQgZm9yIGFycmF5IGJ1ZmZlciBpZiBuZWNlc3NhcnlcblxuXHRcdGlmICggdGhpcy5hcnJheS5idWZmZXIuX3V1aWQgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGhpcy5hcnJheS5idWZmZXIuX3V1aWQgPSBnZW5lcmF0ZVVVSUQoKTtcblxuXHRcdH1cblxuXHRcdGlmICggZGF0YS5hcnJheUJ1ZmZlcnNbIHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0ZGF0YS5hcnJheUJ1ZmZlcnNbIHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkIF0gPSBBcnJheS5mcm9tKCBuZXcgVWludDMyQXJyYXkoIHRoaXMuYXJyYXkuYnVmZmVyICkgKTtcblxuXHRcdH1cblxuXHRcdC8vXG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0dXVpZDogdGhpcy51dWlkLFxuXHRcdFx0YnVmZmVyOiB0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCxcblx0XHRcdHR5cGU6IHRoaXMuYXJyYXkuY29uc3RydWN0b3IubmFtZSxcblx0XHRcdHN0cmlkZTogdGhpcy5zdHJpZGVcblx0XHR9O1xuXG5cdH1cblxufVxuXG5jb25zdCBfdmVjdG9yJDYgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNsYXNzIEludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlIHtcblxuXHRjb25zdHJ1Y3RvciggaW50ZXJsZWF2ZWRCdWZmZXIsIGl0ZW1TaXplLCBvZmZzZXQsIG5vcm1hbGl6ZWQgPSBmYWxzZSApIHtcblxuXHRcdHRoaXMuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSA9IHRydWU7XG5cblx0XHR0aGlzLm5hbWUgPSAnJztcblxuXHRcdHRoaXMuZGF0YSA9IGludGVybGVhdmVkQnVmZmVyO1xuXHRcdHRoaXMuaXRlbVNpemUgPSBpdGVtU2l6ZTtcblx0XHR0aGlzLm9mZnNldCA9IG9mZnNldDtcblxuXHRcdHRoaXMubm9ybWFsaXplZCA9IG5vcm1hbGl6ZWQ7XG5cblx0fVxuXG5cdGdldCBjb3VudCgpIHtcblxuXHRcdHJldHVybiB0aGlzLmRhdGEuY291bnQ7XG5cblx0fVxuXG5cdGdldCBhcnJheSgpIHtcblxuXHRcdHJldHVybiB0aGlzLmRhdGEuYXJyYXk7XG5cblx0fVxuXG5cdHNldCBuZWVkc1VwZGF0ZSggdmFsdWUgKSB7XG5cblx0XHR0aGlzLmRhdGEubmVlZHNVcGRhdGUgPSB2YWx1ZTtcblxuXHR9XG5cblx0YXBwbHlNYXRyaXg0KCBtICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5kYXRhLmNvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0X3ZlY3RvciQ2LmZyb21CdWZmZXJBdHRyaWJ1dGUoIHRoaXMsIGkgKTtcblxuXHRcdFx0X3ZlY3RvciQ2LmFwcGx5TWF0cml4NCggbSApO1xuXG5cdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3RvciQ2LngsIF92ZWN0b3IkNi55LCBfdmVjdG9yJDYueiApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFwcGx5Tm9ybWFsTWF0cml4KCBtICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5jb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdF92ZWN0b3IkNi5mcm9tQnVmZmVyQXR0cmlidXRlKCB0aGlzLCBpICk7XG5cblx0XHRcdF92ZWN0b3IkNi5hcHBseU5vcm1hbE1hdHJpeCggbSApO1xuXG5cdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3RvciQ2LngsIF92ZWN0b3IkNi55LCBfdmVjdG9yJDYueiApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRyYW5zZm9ybURpcmVjdGlvbiggbSApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY291bnQ7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRfdmVjdG9yJDYuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xuXG5cdFx0XHRfdmVjdG9yJDYudHJhbnNmb3JtRGlyZWN0aW9uKCBtICk7XG5cblx0XHRcdHRoaXMuc2V0WFlaKCBpLCBfdmVjdG9yJDYueCwgX3ZlY3RvciQ2LnksIF92ZWN0b3IkNi56ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0Q29tcG9uZW50KCBpbmRleCwgY29tcG9uZW50ICkge1xuXG5cdFx0bGV0IHZhbHVlID0gdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyBjb21wb25lbnQgXTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdmFsdWUgPSBkZW5vcm1hbGl6ZSggdmFsdWUsIHRoaXMuYXJyYXkgKTtcblxuXHRcdHJldHVybiB2YWx1ZTtcblxuXHR9XG5cblx0c2V0Q29tcG9uZW50KCBpbmRleCwgY29tcG9uZW50LCB2YWx1ZSApIHtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdmFsdWUgPSBub3JtYWxpemUoIHZhbHVlLCB0aGlzLmFycmF5ICk7XG5cblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgY29tcG9uZW50IF0gPSB2YWx1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRYKCBpbmRleCwgeCApIHtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldCBdID0geDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRZKCBpbmRleCwgeSApIHtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xuXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldCArIDEgXSA9IHk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0WiggaW5kZXgsIHogKSB7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHogPSBub3JtYWxpemUoIHosIHRoaXMuYXJyYXkgKTtcblxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyAyIF0gPSB6O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFcoIGluZGV4LCB3ICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB3ID0gbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XG5cblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgMyBdID0gdztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRYKCBpbmRleCApIHtcblxuXHRcdGxldCB4ID0gdGhpcy5kYXRhLmFycmF5WyBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldCBdO1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB4ID0gZGVub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcblxuXHRcdHJldHVybiB4O1xuXG5cdH1cblxuXHRnZXRZKCBpbmRleCApIHtcblxuXHRcdGxldCB5ID0gdGhpcy5kYXRhLmFycmF5WyBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldCArIDEgXTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IGRlbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cblx0XHRyZXR1cm4geTtcblxuXHR9XG5cblx0Z2V0WiggaW5kZXggKSB7XG5cblx0XHRsZXQgeiA9IHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyAyIF07XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHogPSBkZW5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHo7XG5cblx0fVxuXG5cdGdldFcoIGluZGV4ICkge1xuXG5cdFx0bGV0IHcgPSB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgMyBdO1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB3ID0gZGVub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcblxuXHRcdHJldHVybiB3O1xuXG5cdH1cblxuXHRzZXRYWSggaW5kZXgsIHgsIHkgKSB7XG5cblx0XHRpbmRleCA9IGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0O1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XG5cblx0XHRcdHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAwIF0gPSB4O1xuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAxIF0gPSB5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFhZWiggaW5kZXgsIHgsIHksIHogKSB7XG5cblx0XHRpbmRleCA9IGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0O1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XG5cblx0XHRcdHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcblx0XHRcdHogPSBub3JtYWxpemUoIHosIHRoaXMuYXJyYXkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAwIF0gPSB4O1xuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAxIF0gPSB5O1xuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAyIF0gPSB6O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFhZWlcoIGluZGV4LCB4LCB5LCB6LCB3ICkge1xuXG5cdFx0aW5kZXggPSBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldDtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkge1xuXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR3ID0gbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgMCBdID0geDtcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgMSBdID0geTtcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgMiBdID0gejtcblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgMyBdID0gdztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSggZGF0YSApIHtcblxuXHRcdGlmICggZGF0YSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjb25zb2xlLmxvZyggJ1RIUkVFLkludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlLmNsb25lKCk6IENsb25pbmcgYW4gaW50ZXJsZWF2ZWQgYnVmZmVyIGF0dHJpYnV0ZSB3aWxsIGRlLWludGVybGVhdmUgYnVmZmVyIGRhdGEuJyApO1xuXG5cdFx0XHRjb25zdCBhcnJheSA9IFtdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLmNvdW50OyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGluZGV4ID0gaSAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldDtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCB0aGlzLml0ZW1TaXplOyBqICsrICkge1xuXG5cdFx0XHRcdFx0YXJyYXkucHVzaCggdGhpcy5kYXRhLmFycmF5WyBpbmRleCArIGogXSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gbmV3IEJ1ZmZlckF0dHJpYnV0ZSggbmV3IHRoaXMuYXJyYXkuY29uc3RydWN0b3IoIGFycmF5ICksIHRoaXMuaXRlbVNpemUsIHRoaXMubm9ybWFsaXplZCApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0aWYgKCBkYXRhLmludGVybGVhdmVkQnVmZmVycyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGRhdGEuaW50ZXJsZWF2ZWRCdWZmZXJzID0ge307XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBkYXRhLmludGVybGVhdmVkQnVmZmVyc1sgdGhpcy5kYXRhLnV1aWQgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGRhdGEuaW50ZXJsZWF2ZWRCdWZmZXJzWyB0aGlzLmRhdGEudXVpZCBdID0gdGhpcy5kYXRhLmNsb25lKCBkYXRhICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIG5ldyBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSggZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnNbIHRoaXMuZGF0YS51dWlkIF0sIHRoaXMuaXRlbVNpemUsIHRoaXMub2Zmc2V0LCB0aGlzLm5vcm1hbGl6ZWQgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0dG9KU09OKCBkYXRhICkge1xuXG5cdFx0aWYgKCBkYXRhID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnNvbGUubG9nKCAnVEhSRUUuSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUudG9KU09OKCk6IFNlcmlhbGl6aW5nIGFuIGludGVybGVhdmVkIGJ1ZmZlciBhdHRyaWJ1dGUgd2lsbCBkZS1pbnRlcmxlYXZlIGJ1ZmZlciBkYXRhLicgKTtcblxuXHRcdFx0Y29uc3QgYXJyYXkgPSBbXTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy5jb3VudDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbmRleCA9IGkgKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQ7XG5cblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgdGhpcy5pdGVtU2l6ZTsgaiArKyApIHtcblxuXHRcdFx0XHRcdGFycmF5LnB1c2goIHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyBqIF0gKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gZGUtaW50ZXJsZWF2ZSBkYXRhIGFuZCBzYXZlIGl0IGFzIGFuIG9yZGluYXJ5IGJ1ZmZlciBhdHRyaWJ1dGUgZm9yIG5vd1xuXG5cdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRpdGVtU2l6ZTogdGhpcy5pdGVtU2l6ZSxcblx0XHRcdFx0dHlwZTogdGhpcy5hcnJheS5jb25zdHJ1Y3Rvci5uYW1lLFxuXHRcdFx0XHRhcnJheTogYXJyYXksXG5cdFx0XHRcdG5vcm1hbGl6ZWQ6IHRoaXMubm9ybWFsaXplZFxuXHRcdFx0fTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIHNhdmUgYXMgdHJ1ZSBpbnRlcmxlYXZlZCBhdHRyaWJ1dGVcblxuXHRcdFx0aWYgKCBkYXRhLmludGVybGVhdmVkQnVmZmVycyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGRhdGEuaW50ZXJsZWF2ZWRCdWZmZXJzID0ge307XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBkYXRhLmludGVybGVhdmVkQnVmZmVyc1sgdGhpcy5kYXRhLnV1aWQgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGRhdGEuaW50ZXJsZWF2ZWRCdWZmZXJzWyB0aGlzLmRhdGEudXVpZCBdID0gdGhpcy5kYXRhLnRvSlNPTiggZGF0YSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdGlzSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGU6IHRydWUsXG5cdFx0XHRcdGl0ZW1TaXplOiB0aGlzLml0ZW1TaXplLFxuXHRcdFx0XHRkYXRhOiB0aGlzLmRhdGEudXVpZCxcblx0XHRcdFx0b2Zmc2V0OiB0aGlzLm9mZnNldCxcblx0XHRcdFx0bm9ybWFsaXplZDogdGhpcy5ub3JtYWxpemVkXG5cdFx0XHR9O1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5jbGFzcyBTcHJpdGVNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzU3ByaXRlTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ1Nwcml0ZU1hdGVyaWFsJztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcblxuXHRcdHRoaXMucm90YXRpb24gPSAwO1xuXG5cdFx0dGhpcy5zaXplQXR0ZW51YXRpb24gPSB0cnVlO1xuXG5cdFx0dGhpcy50cmFuc3BhcmVudCA9IHRydWU7XG5cblx0XHR0aGlzLmZvZyA9IHRydWU7XG5cblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XG5cblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xuXG5cdFx0dGhpcy5yb3RhdGlvbiA9IHNvdXJjZS5yb3RhdGlvbjtcblxuXHRcdHRoaXMuc2l6ZUF0dGVudWF0aW9uID0gc291cmNlLnNpemVBdHRlbnVhdGlvbjtcblxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5sZXQgX2dlb21ldHJ5O1xuXG5jb25zdCBfaW50ZXJzZWN0UG9pbnQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfd29ybGRTY2FsZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9tdlBvc2l0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jb25zdCBfYWxpZ25lZFBvc2l0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xuY29uc3QgX3JvdGF0ZWRQb3NpdGlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcbmNvbnN0IF92aWV3V29ybGRNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5cbmNvbnN0IF92QSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92QiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92QyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY29uc3QgX3V2QSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcbmNvbnN0IF91dkIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XG5jb25zdCBfdXZDID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xuXG5jbGFzcyBTcHJpdGUgZXh0ZW5kcyBPYmplY3QzRCB7XG5cblx0Y29uc3RydWN0b3IoIG1hdGVyaWFsID0gbmV3IFNwcml0ZU1hdGVyaWFsKCkgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc1Nwcml0ZSA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnU3ByaXRlJztcblxuXHRcdGlmICggX2dlb21ldHJ5ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdF9nZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXG5cdFx0XHRjb25zdCBmbG9hdDMyQXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KCBbXG5cdFx0XHRcdC0gMC41LCAtIDAuNSwgMCwgMCwgMCxcblx0XHRcdFx0MC41LCAtIDAuNSwgMCwgMSwgMCxcblx0XHRcdFx0MC41LCAwLjUsIDAsIDEsIDEsXG5cdFx0XHRcdC0gMC41LCAwLjUsIDAsIDAsIDFcblx0XHRcdF0gKTtcblxuXHRcdFx0Y29uc3QgaW50ZXJsZWF2ZWRCdWZmZXIgPSBuZXcgSW50ZXJsZWF2ZWRCdWZmZXIoIGZsb2F0MzJBcnJheSwgNSApO1xuXG5cdFx0XHRfZ2VvbWV0cnkuc2V0SW5kZXgoIFsgMCwgMSwgMixcdDAsIDIsIDMgXSApO1xuXHRcdFx0X2dlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlKCBpbnRlcmxlYXZlZEJ1ZmZlciwgMywgMCwgZmFsc2UgKSApO1xuXHRcdFx0X2dlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlKCBpbnRlcmxlYXZlZEJ1ZmZlciwgMiwgMywgZmFsc2UgKSApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5nZW9tZXRyeSA9IF9nZW9tZXRyeTtcblx0XHR0aGlzLm1hdGVyaWFsID0gbWF0ZXJpYWw7XG5cblx0XHR0aGlzLmNlbnRlciA9IG5ldyBWZWN0b3IyKCAwLjUsIDAuNSApO1xuXG5cdH1cblxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XG5cblx0XHRpZiAoIHJheWNhc3Rlci5jYW1lcmEgPT09IG51bGwgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5TcHJpdGU6IFwiUmF5Y2FzdGVyLmNhbWVyYVwiIG5lZWRzIHRvIGJlIHNldCBpbiBvcmRlciB0byByYXljYXN0IGFnYWluc3Qgc3ByaXRlcy4nICk7XG5cblx0XHR9XG5cblx0XHRfd29ybGRTY2FsZS5zZXRGcm9tTWF0cml4U2NhbGUoIHRoaXMubWF0cml4V29ybGQgKTtcblxuXHRcdF92aWV3V29ybGRNYXRyaXguY29weSggcmF5Y2FzdGVyLmNhbWVyYS5tYXRyaXhXb3JsZCApO1xuXHRcdHRoaXMubW9kZWxWaWV3TWF0cml4Lm11bHRpcGx5TWF0cmljZXMoIHJheWNhc3Rlci5jYW1lcmEubWF0cml4V29ybGRJbnZlcnNlLCB0aGlzLm1hdHJpeFdvcmxkICk7XG5cblx0XHRfbXZQb3NpdGlvbi5zZXRGcm9tTWF0cml4UG9zaXRpb24oIHRoaXMubW9kZWxWaWV3TWF0cml4ICk7XG5cblx0XHRpZiAoIHJheWNhc3Rlci5jYW1lcmEuaXNQZXJzcGVjdGl2ZUNhbWVyYSAmJiB0aGlzLm1hdGVyaWFsLnNpemVBdHRlbnVhdGlvbiA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdF93b3JsZFNjYWxlLm11bHRpcGx5U2NhbGFyKCAtIF9tdlBvc2l0aW9uLnogKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHJvdGF0aW9uID0gdGhpcy5tYXRlcmlhbC5yb3RhdGlvbjtcblx0XHRsZXQgc2luLCBjb3M7XG5cblx0XHRpZiAoIHJvdGF0aW9uICE9PSAwICkge1xuXG5cdFx0XHRjb3MgPSBNYXRoLmNvcyggcm90YXRpb24gKTtcblx0XHRcdHNpbiA9IE1hdGguc2luKCByb3RhdGlvbiApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgY2VudGVyID0gdGhpcy5jZW50ZXI7XG5cblx0XHR0cmFuc2Zvcm1WZXJ0ZXgoIF92QS5zZXQoIC0gMC41LCAtIDAuNSwgMCApLCBfbXZQb3NpdGlvbiwgY2VudGVyLCBfd29ybGRTY2FsZSwgc2luLCBjb3MgKTtcblx0XHR0cmFuc2Zvcm1WZXJ0ZXgoIF92Qi5zZXQoIDAuNSwgLSAwLjUsIDAgKSwgX212UG9zaXRpb24sIGNlbnRlciwgX3dvcmxkU2NhbGUsIHNpbiwgY29zICk7XG5cdFx0dHJhbnNmb3JtVmVydGV4KCBfdkMuc2V0KCAwLjUsIDAuNSwgMCApLCBfbXZQb3NpdGlvbiwgY2VudGVyLCBfd29ybGRTY2FsZSwgc2luLCBjb3MgKTtcblxuXHRcdF91dkEuc2V0KCAwLCAwICk7XG5cdFx0X3V2Qi5zZXQoIDEsIDAgKTtcblx0XHRfdXZDLnNldCggMSwgMSApO1xuXG5cdFx0Ly8gY2hlY2sgZmlyc3QgdHJpYW5nbGVcblx0XHRsZXQgaW50ZXJzZWN0ID0gcmF5Y2FzdGVyLnJheS5pbnRlcnNlY3RUcmlhbmdsZSggX3ZBLCBfdkIsIF92QywgZmFsc2UsIF9pbnRlcnNlY3RQb2ludCApO1xuXG5cdFx0aWYgKCBpbnRlcnNlY3QgPT09IG51bGwgKSB7XG5cblx0XHRcdC8vIGNoZWNrIHNlY29uZCB0cmlhbmdsZVxuXHRcdFx0dHJhbnNmb3JtVmVydGV4KCBfdkIuc2V0KCAtIDAuNSwgMC41LCAwICksIF9tdlBvc2l0aW9uLCBjZW50ZXIsIF93b3JsZFNjYWxlLCBzaW4sIGNvcyApO1xuXHRcdFx0X3V2Qi5zZXQoIDAsIDEgKTtcblxuXHRcdFx0aW50ZXJzZWN0ID0gcmF5Y2FzdGVyLnJheS5pbnRlcnNlY3RUcmlhbmdsZSggX3ZBLCBfdkMsIF92QiwgZmFsc2UsIF9pbnRlcnNlY3RQb2ludCApO1xuXHRcdFx0aWYgKCBpbnRlcnNlY3QgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRjb25zdCBkaXN0YW5jZSA9IHJheWNhc3Rlci5yYXkub3JpZ2luLmRpc3RhbmNlVG8oIF9pbnRlcnNlY3RQb2ludCApO1xuXG5cdFx0aWYgKCBkaXN0YW5jZSA8IHJheWNhc3Rlci5uZWFyIHx8IGRpc3RhbmNlID4gcmF5Y2FzdGVyLmZhciApIHJldHVybjtcblxuXHRcdGludGVyc2VjdHMucHVzaCgge1xuXG5cdFx0XHRkaXN0YW5jZTogZGlzdGFuY2UsXG5cdFx0XHRwb2ludDogX2ludGVyc2VjdFBvaW50LmNsb25lKCksXG5cdFx0XHR1djogVHJpYW5nbGUuZ2V0SW50ZXJwb2xhdGlvbiggX2ludGVyc2VjdFBvaW50LCBfdkEsIF92QiwgX3ZDLCBfdXZBLCBfdXZCLCBfdXZDLCBuZXcgVmVjdG9yMigpICksXG5cdFx0XHRmYWNlOiBudWxsLFxuXHRcdFx0b2JqZWN0OiB0aGlzXG5cblx0XHR9ICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcblxuXHRcdGlmICggc291cmNlLmNlbnRlciAhPT0gdW5kZWZpbmVkICkgdGhpcy5jZW50ZXIuY29weSggc291cmNlLmNlbnRlciApO1xuXG5cdFx0dGhpcy5tYXRlcmlhbCA9IHNvdXJjZS5tYXRlcmlhbDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiB0cmFuc2Zvcm1WZXJ0ZXgoIHZlcnRleFBvc2l0aW9uLCBtdlBvc2l0aW9uLCBjZW50ZXIsIHNjYWxlLCBzaW4sIGNvcyApIHtcblxuXHQvLyBjb21wdXRlIHBvc2l0aW9uIGluIGNhbWVyYSBzcGFjZVxuXHRfYWxpZ25lZFBvc2l0aW9uLnN1YlZlY3RvcnMoIHZlcnRleFBvc2l0aW9uLCBjZW50ZXIgKS5hZGRTY2FsYXIoIDAuNSApLm11bHRpcGx5KCBzY2FsZSApO1xuXG5cdC8vIHRvIGNoZWNrIGlmIHJvdGF0aW9uIGlzIG5vdCB6ZXJvXG5cdGlmICggc2luICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRfcm90YXRlZFBvc2l0aW9uLnggPSAoIGNvcyAqIF9hbGlnbmVkUG9zaXRpb24ueCApIC0gKCBzaW4gKiBfYWxpZ25lZFBvc2l0aW9uLnkgKTtcblx0XHRfcm90YXRlZFBvc2l0aW9uLnkgPSAoIHNpbiAqIF9hbGlnbmVkUG9zaXRpb24ueCApICsgKCBjb3MgKiBfYWxpZ25lZFBvc2l0aW9uLnkgKTtcblxuXHR9IGVsc2Uge1xuXG5cdFx0X3JvdGF0ZWRQb3NpdGlvbi5jb3B5KCBfYWxpZ25lZFBvc2l0aW9uICk7XG5cblx0fVxuXG5cblx0dmVydGV4UG9zaXRpb24uY29weSggbXZQb3NpdGlvbiApO1xuXHR2ZXJ0ZXhQb3NpdGlvbi54ICs9IF9yb3RhdGVkUG9zaXRpb24ueDtcblx0dmVydGV4UG9zaXRpb24ueSArPSBfcm90YXRlZFBvc2l0aW9uLnk7XG5cblx0Ly8gdHJhbnNmb3JtIHRvIHdvcmxkIHNwYWNlXG5cdHZlcnRleFBvc2l0aW9uLmFwcGx5TWF0cml4NCggX3ZpZXdXb3JsZE1hdHJpeCApO1xuXG59XG5cbmNvbnN0IF92MSQyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3YyJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNsYXNzIExPRCBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLl9jdXJyZW50TGV2ZWwgPSAwO1xuXG5cdFx0dGhpcy50eXBlID0gJ0xPRCc7XG5cblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydGllcyggdGhpcywge1xuXHRcdFx0bGV2ZWxzOiB7XG5cdFx0XHRcdGVudW1lcmFibGU6IHRydWUsXG5cdFx0XHRcdHZhbHVlOiBbXVxuXHRcdFx0fSxcblx0XHRcdGlzTE9EOiB7XG5cdFx0XHRcdHZhbHVlOiB0cnVlLFxuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHRoaXMuYXV0b1VwZGF0ZSA9IHRydWU7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgZmFsc2UgKTtcblxuXHRcdGNvbnN0IGxldmVscyA9IHNvdXJjZS5sZXZlbHM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBsZXZlbHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgbGV2ZWwgPSBsZXZlbHNbIGkgXTtcblxuXHRcdFx0dGhpcy5hZGRMZXZlbCggbGV2ZWwub2JqZWN0LmNsb25lKCksIGxldmVsLmRpc3RhbmNlLCBsZXZlbC5oeXN0ZXJlc2lzICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmF1dG9VcGRhdGUgPSBzb3VyY2UuYXV0b1VwZGF0ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhZGRMZXZlbCggb2JqZWN0LCBkaXN0YW5jZSA9IDAsIGh5c3RlcmVzaXMgPSAwICkge1xuXG5cdFx0ZGlzdGFuY2UgPSBNYXRoLmFicyggZGlzdGFuY2UgKTtcblxuXHRcdGNvbnN0IGxldmVscyA9IHRoaXMubGV2ZWxzO1xuXG5cdFx0bGV0IGw7XG5cblx0XHRmb3IgKCBsID0gMDsgbCA8IGxldmVscy5sZW5ndGg7IGwgKysgKSB7XG5cblx0XHRcdGlmICggZGlzdGFuY2UgPCBsZXZlbHNbIGwgXS5kaXN0YW5jZSApIHtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0bGV2ZWxzLnNwbGljZSggbCwgMCwgeyBkaXN0YW5jZTogZGlzdGFuY2UsIGh5c3RlcmVzaXM6IGh5c3RlcmVzaXMsIG9iamVjdDogb2JqZWN0IH0gKTtcblxuXHRcdHRoaXMuYWRkKCBvYmplY3QgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRDdXJyZW50TGV2ZWwoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fY3VycmVudExldmVsO1xuXG5cdH1cblxuXG5cblx0Z2V0T2JqZWN0Rm9yRGlzdGFuY2UoIGRpc3RhbmNlICkge1xuXG5cdFx0Y29uc3QgbGV2ZWxzID0gdGhpcy5sZXZlbHM7XG5cblx0XHRpZiAoIGxldmVscy5sZW5ndGggPiAwICkge1xuXG5cdFx0XHRsZXQgaSwgbDtcblxuXHRcdFx0Zm9yICggaSA9IDEsIGwgPSBsZXZlbHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRsZXQgbGV2ZWxEaXN0YW5jZSA9IGxldmVsc1sgaSBdLmRpc3RhbmNlO1xuXG5cdFx0XHRcdGlmICggbGV2ZWxzWyBpIF0ub2JqZWN0LnZpc2libGUgKSB7XG5cblx0XHRcdFx0XHRsZXZlbERpc3RhbmNlIC09IGxldmVsRGlzdGFuY2UgKiBsZXZlbHNbIGkgXS5oeXN0ZXJlc2lzO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIGRpc3RhbmNlIDwgbGV2ZWxEaXN0YW5jZSApIHtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gbGV2ZWxzWyBpIC0gMSBdLm9iamVjdDtcblxuXHRcdH1cblxuXHRcdHJldHVybiBudWxsO1xuXG5cdH1cblxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XG5cblx0XHRjb25zdCBsZXZlbHMgPSB0aGlzLmxldmVscztcblxuXHRcdGlmICggbGV2ZWxzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdF92MSQyLnNldEZyb21NYXRyaXhQb3NpdGlvbiggdGhpcy5tYXRyaXhXb3JsZCApO1xuXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IHJheWNhc3Rlci5yYXkub3JpZ2luLmRpc3RhbmNlVG8oIF92MSQyICk7XG5cblx0XHRcdHRoaXMuZ2V0T2JqZWN0Rm9yRGlzdGFuY2UoIGRpc3RhbmNlICkucmF5Y2FzdCggcmF5Y2FzdGVyLCBpbnRlcnNlY3RzICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHVwZGF0ZSggY2FtZXJhICkge1xuXG5cdFx0Y29uc3QgbGV2ZWxzID0gdGhpcy5sZXZlbHM7XG5cblx0XHRpZiAoIGxldmVscy5sZW5ndGggPiAxICkge1xuXG5cdFx0XHRfdjEkMi5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGNhbWVyYS5tYXRyaXhXb3JsZCApO1xuXHRcdFx0X3YyJDEuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1hdHJpeFdvcmxkICk7XG5cblx0XHRcdGNvbnN0IGRpc3RhbmNlID0gX3YxJDIuZGlzdGFuY2VUbyggX3YyJDEgKSAvIGNhbWVyYS56b29tO1xuXG5cdFx0XHRsZXZlbHNbIDAgXS5vYmplY3QudmlzaWJsZSA9IHRydWU7XG5cblx0XHRcdGxldCBpLCBsO1xuXG5cdFx0XHRmb3IgKCBpID0gMSwgbCA9IGxldmVscy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGxldCBsZXZlbERpc3RhbmNlID0gbGV2ZWxzWyBpIF0uZGlzdGFuY2U7XG5cblx0XHRcdFx0aWYgKCBsZXZlbHNbIGkgXS5vYmplY3QudmlzaWJsZSApIHtcblxuXHRcdFx0XHRcdGxldmVsRGlzdGFuY2UgLT0gbGV2ZWxEaXN0YW5jZSAqIGxldmVsc1sgaSBdLmh5c3RlcmVzaXM7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggZGlzdGFuY2UgPj0gbGV2ZWxEaXN0YW5jZSApIHtcblxuXHRcdFx0XHRcdGxldmVsc1sgaSAtIDEgXS5vYmplY3QudmlzaWJsZSA9IGZhbHNlO1xuXHRcdFx0XHRcdGxldmVsc1sgaSBdLm9iamVjdC52aXNpYmxlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2N1cnJlbnRMZXZlbCA9IGkgLSAxO1xuXG5cdFx0XHRmb3IgKCA7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGxldmVsc1sgaSBdLm9iamVjdC52aXNpYmxlID0gZmFsc2U7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0dG9KU09OKCBtZXRhICkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xuXG5cdFx0aWYgKCB0aGlzLmF1dG9VcGRhdGUgPT09IGZhbHNlICkgZGF0YS5vYmplY3QuYXV0b1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0ZGF0YS5vYmplY3QubGV2ZWxzID0gW107XG5cblx0XHRjb25zdCBsZXZlbHMgPSB0aGlzLmxldmVscztcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGxldmVscy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBsZXZlbCA9IGxldmVsc1sgaSBdO1xuXG5cdFx0XHRkYXRhLm9iamVjdC5sZXZlbHMucHVzaCgge1xuXHRcdFx0XHRvYmplY3Q6IGxldmVsLm9iamVjdC51dWlkLFxuXHRcdFx0XHRkaXN0YW5jZTogbGV2ZWwuZGlzdGFuY2UsXG5cdFx0XHRcdGh5c3RlcmVzaXM6IGxldmVsLmh5c3RlcmVzaXNcblx0XHRcdH0gKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxufVxuXG5jb25zdCBfYmFzZVBvc2l0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jb25zdCBfc2tpbkluZGV4ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yNCgpO1xuY29uc3QgX3NraW5XZWlnaHQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3I0KCk7XG5cbmNvbnN0IF92ZWN0b3IzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX21hdHJpeDQgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfdmVydGV4ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jb25zdCBfc3BoZXJlJDQgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcbmNvbnN0IF9pbnZlcnNlTWF0cml4JDIgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfcmF5JDIgPSAvKkBfX1BVUkVfXyovIG5ldyBSYXkoKTtcblxuY2xhc3MgU2tpbm5lZE1lc2ggZXh0ZW5kcyBNZXNoIHtcblxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnksIG1hdGVyaWFsICkge1xuXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xuXG5cdFx0dGhpcy5pc1NraW5uZWRNZXNoID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdTa2lubmVkTWVzaCc7XG5cblx0XHR0aGlzLmJpbmRNb2RlID0gQXR0YWNoZWRCaW5kTW9kZTtcblx0XHR0aGlzLmJpbmRNYXRyaXggPSBuZXcgTWF0cml4NCgpO1xuXHRcdHRoaXMuYmluZE1hdHJpeEludmVyc2UgPSBuZXcgTWF0cml4NCgpO1xuXG5cdFx0dGhpcy5ib3VuZGluZ0JveCA9IG51bGw7XG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG51bGw7XG5cblx0fVxuXG5cdGNvbXB1dGVCb3VuZGluZ0JveCgpIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcblxuXHRcdGlmICggdGhpcy5ib3VuZGluZ0JveCA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5ib3VuZGluZ0JveCA9IG5ldyBCb3gzKCk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmJvdW5kaW5nQm94Lm1ha2VFbXB0eSgpO1xuXG5cdFx0Y29uc3QgcG9zaXRpb25BdHRyaWJ1dGUgPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHBvc2l0aW9uQXR0cmlidXRlLmNvdW50OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmdldFZlcnRleFBvc2l0aW9uKCBpLCBfdmVydGV4ICk7XG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94LmV4cGFuZEJ5UG9pbnQoIF92ZXJ0ZXggKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Y29tcHV0ZUJvdW5kaW5nU3BoZXJlKCkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlID0gbmV3IFNwaGVyZSgpO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZS5tYWtlRW1wdHkoKTtcblxuXHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudDsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5nZXRWZXJ0ZXhQb3NpdGlvbiggaSwgX3ZlcnRleCApO1xuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZS5leHBhbmRCeVBvaW50KCBfdmVydGV4ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcblxuXHRcdHRoaXMuYmluZE1vZGUgPSBzb3VyY2UuYmluZE1vZGU7XG5cdFx0dGhpcy5iaW5kTWF0cml4LmNvcHkoIHNvdXJjZS5iaW5kTWF0cml4ICk7XG5cdFx0dGhpcy5iaW5kTWF0cml4SW52ZXJzZS5jb3B5KCBzb3VyY2UuYmluZE1hdHJpeEludmVyc2UgKTtcblxuXHRcdHRoaXMuc2tlbGV0b24gPSBzb3VyY2Uuc2tlbGV0b247XG5cblx0XHRpZiAoIHNvdXJjZS5ib3VuZGluZ0JveCAhPT0gbnVsbCApIHRoaXMuYm91bmRpbmdCb3ggPSBzb3VyY2UuYm91bmRpbmdCb3guY2xvbmUoKTtcblx0XHRpZiAoIHNvdXJjZS5ib3VuZGluZ1NwaGVyZSAhPT0gbnVsbCApIHRoaXMuYm91bmRpbmdTcGhlcmUgPSBzb3VyY2UuYm91bmRpbmdTcGhlcmUuY2xvbmUoKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XG5cblx0XHRjb25zdCBtYXRlcmlhbCA9IHRoaXMubWF0ZXJpYWw7XG5cdFx0Y29uc3QgbWF0cml4V29ybGQgPSB0aGlzLm1hdHJpeFdvcmxkO1xuXG5cdFx0aWYgKCBtYXRlcmlhbCA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xuXG5cdFx0Ly8gdGVzdCB3aXRoIGJvdW5kaW5nIHNwaGVyZSBpbiB3b3JsZCBzcGFjZVxuXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkgdGhpcy5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcblxuXHRcdF9zcGhlcmUkNC5jb3B5KCB0aGlzLmJvdW5kaW5nU3BoZXJlICk7XG5cdFx0X3NwaGVyZSQ0LmFwcGx5TWF0cml4NCggbWF0cml4V29ybGQgKTtcblxuXHRcdGlmICggcmF5Y2FzdGVyLnJheS5pbnRlcnNlY3RzU3BoZXJlKCBfc3BoZXJlJDQgKSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHQvLyBjb252ZXJ0IHJheSB0byBsb2NhbCBzcGFjZSBvZiBza2lubmVkIG1lc2hcblxuXHRcdF9pbnZlcnNlTWF0cml4JDIuY29weSggbWF0cml4V29ybGQgKS5pbnZlcnQoKTtcblx0XHRfcmF5JDIuY29weSggcmF5Y2FzdGVyLnJheSApLmFwcGx5TWF0cml4NCggX2ludmVyc2VNYXRyaXgkMiApO1xuXG5cdFx0Ly8gdGVzdCB3aXRoIGJvdW5kaW5nIGJveCBpbiBsb2NhbCBzcGFjZVxuXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nQm94ICE9PSBudWxsICkge1xuXG5cdFx0XHRpZiAoIF9yYXkkMi5pbnRlcnNlY3RzQm94KCB0aGlzLmJvdW5kaW5nQm94ICkgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0Ly8gdGVzdCBmb3IgaW50ZXJzZWN0aW9ucyB3aXRoIGdlb21ldHJ5XG5cblx0XHR0aGlzLl9jb21wdXRlSW50ZXJzZWN0aW9ucyggcmF5Y2FzdGVyLCBpbnRlcnNlY3RzLCBfcmF5JDIgKTtcblxuXHR9XG5cblx0Z2V0VmVydGV4UG9zaXRpb24oIGluZGV4LCB0YXJnZXQgKSB7XG5cblx0XHRzdXBlci5nZXRWZXJ0ZXhQb3NpdGlvbiggaW5kZXgsIHRhcmdldCApO1xuXG5cdFx0dGhpcy5hcHBseUJvbmVUcmFuc2Zvcm0oIGluZGV4LCB0YXJnZXQgKTtcblxuXHRcdHJldHVybiB0YXJnZXQ7XG5cblx0fVxuXG5cdGJpbmQoIHNrZWxldG9uLCBiaW5kTWF0cml4ICkge1xuXG5cdFx0dGhpcy5za2VsZXRvbiA9IHNrZWxldG9uO1xuXG5cdFx0aWYgKCBiaW5kTWF0cml4ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHRoaXMudXBkYXRlTWF0cml4V29ybGQoIHRydWUgKTtcblxuXHRcdFx0dGhpcy5za2VsZXRvbi5jYWxjdWxhdGVJbnZlcnNlcygpO1xuXG5cdFx0XHRiaW5kTWF0cml4ID0gdGhpcy5tYXRyaXhXb3JsZDtcblxuXHRcdH1cblxuXHRcdHRoaXMuYmluZE1hdHJpeC5jb3B5KCBiaW5kTWF0cml4ICk7XG5cdFx0dGhpcy5iaW5kTWF0cml4SW52ZXJzZS5jb3B5KCBiaW5kTWF0cml4ICkuaW52ZXJ0KCk7XG5cblx0fVxuXG5cdHBvc2UoKSB7XG5cblx0XHR0aGlzLnNrZWxldG9uLnBvc2UoKTtcblxuXHR9XG5cblx0bm9ybWFsaXplU2tpbldlaWdodHMoKSB7XG5cblx0XHRjb25zdCB2ZWN0b3IgPSBuZXcgVmVjdG9yNCgpO1xuXG5cdFx0Y29uc3Qgc2tpbldlaWdodCA9IHRoaXMuZ2VvbWV0cnkuYXR0cmlidXRlcy5za2luV2VpZ2h0O1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2tpbldlaWdodC5jb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdHZlY3Rvci5mcm9tQnVmZmVyQXR0cmlidXRlKCBza2luV2VpZ2h0LCBpICk7XG5cblx0XHRcdGNvbnN0IHNjYWxlID0gMS4wIC8gdmVjdG9yLm1hbmhhdHRhbkxlbmd0aCgpO1xuXG5cdFx0XHRpZiAoIHNjYWxlICE9PSBJbmZpbml0eSApIHtcblxuXHRcdFx0XHR2ZWN0b3IubXVsdGlwbHlTY2FsYXIoIHNjYWxlICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0dmVjdG9yLnNldCggMSwgMCwgMCwgMCApOyAvLyBkbyBzb21ldGhpbmcgcmVhc29uYWJsZVxuXG5cdFx0XHR9XG5cblx0XHRcdHNraW5XZWlnaHQuc2V0WFlaVyggaSwgdmVjdG9yLngsIHZlY3Rvci55LCB2ZWN0b3IueiwgdmVjdG9yLncgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0dXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICkge1xuXG5cdFx0c3VwZXIudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XG5cblx0XHRpZiAoIHRoaXMuYmluZE1vZGUgPT09IEF0dGFjaGVkQmluZE1vZGUgKSB7XG5cblx0XHRcdHRoaXMuYmluZE1hdHJpeEludmVyc2UuY29weSggdGhpcy5tYXRyaXhXb3JsZCApLmludmVydCgpO1xuXG5cdFx0fSBlbHNlIGlmICggdGhpcy5iaW5kTW9kZSA9PT0gRGV0YWNoZWRCaW5kTW9kZSApIHtcblxuXHRcdFx0dGhpcy5iaW5kTWF0cml4SW52ZXJzZS5jb3B5KCB0aGlzLmJpbmRNYXRyaXggKS5pbnZlcnQoKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLlNraW5uZWRNZXNoOiBVbnJlY29nbml6ZWQgYmluZE1vZGU6ICcgKyB0aGlzLmJpbmRNb2RlICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGFwcGx5Qm9uZVRyYW5zZm9ybSggaW5kZXgsIHZlY3RvciApIHtcblxuXHRcdGNvbnN0IHNrZWxldG9uID0gdGhpcy5za2VsZXRvbjtcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cblx0XHRfc2tpbkluZGV4LmZyb21CdWZmZXJBdHRyaWJ1dGUoIGdlb21ldHJ5LmF0dHJpYnV0ZXMuc2tpbkluZGV4LCBpbmRleCApO1xuXHRcdF9za2luV2VpZ2h0LmZyb21CdWZmZXJBdHRyaWJ1dGUoIGdlb21ldHJ5LmF0dHJpYnV0ZXMuc2tpbldlaWdodCwgaW5kZXggKTtcblxuXHRcdF9iYXNlUG9zaXRpb24uY29weSggdmVjdG9yICkuYXBwbHlNYXRyaXg0KCB0aGlzLmJpbmRNYXRyaXggKTtcblxuXHRcdHZlY3Rvci5zZXQoIDAsIDAsIDAgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDQ7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHdlaWdodCA9IF9za2luV2VpZ2h0LmdldENvbXBvbmVudCggaSApO1xuXG5cdFx0XHRpZiAoIHdlaWdodCAhPT0gMCApIHtcblxuXHRcdFx0XHRjb25zdCBib25lSW5kZXggPSBfc2tpbkluZGV4LmdldENvbXBvbmVudCggaSApO1xuXG5cdFx0XHRcdF9tYXRyaXg0Lm11bHRpcGx5TWF0cmljZXMoIHNrZWxldG9uLmJvbmVzWyBib25lSW5kZXggXS5tYXRyaXhXb3JsZCwgc2tlbGV0b24uYm9uZUludmVyc2VzWyBib25lSW5kZXggXSApO1xuXG5cdFx0XHRcdHZlY3Rvci5hZGRTY2FsZWRWZWN0b3IoIF92ZWN0b3IzLmNvcHkoIF9iYXNlUG9zaXRpb24gKS5hcHBseU1hdHJpeDQoIF9tYXRyaXg0ICksIHdlaWdodCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdmVjdG9yLmFwcGx5TWF0cml4NCggdGhpcy5iaW5kTWF0cml4SW52ZXJzZSApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBCb25lIGV4dGVuZHMgT2JqZWN0M0Qge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNCb25lID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdCb25lJztcblxuXHR9XG5cbn1cblxuY2xhc3MgRGF0YVRleHR1cmUgZXh0ZW5kcyBUZXh0dXJlIHtcblxuXHRjb25zdHJ1Y3RvciggZGF0YSA9IG51bGwsIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgZm9ybWF0LCB0eXBlLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciA9IE5lYXJlc3RGaWx0ZXIsIG1pbkZpbHRlciA9IE5lYXJlc3RGaWx0ZXIsIGFuaXNvdHJvcHksIGNvbG9yU3BhY2UgKSB7XG5cblx0XHRzdXBlciggbnVsbCwgbWFwcGluZywgd3JhcFMsIHdyYXBULCBtYWdGaWx0ZXIsIG1pbkZpbHRlciwgZm9ybWF0LCB0eXBlLCBhbmlzb3Ryb3B5LCBjb2xvclNwYWNlICk7XG5cblx0XHR0aGlzLmlzRGF0YVRleHR1cmUgPSB0cnVlO1xuXG5cdFx0dGhpcy5pbWFnZSA9IHsgZGF0YTogZGF0YSwgd2lkdGg6IHdpZHRoLCBoZWlnaHQ6IGhlaWdodCB9O1xuXG5cdFx0dGhpcy5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcblx0XHR0aGlzLmZsaXBZID0gZmFsc2U7XG5cdFx0dGhpcy51bnBhY2tBbGlnbm1lbnQgPSAxO1xuXG5cdH1cblxufVxuXG5jb25zdCBfb2Zmc2V0TWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX2lkZW50aXR5TWF0cml4JDEgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5cbmNsYXNzIFNrZWxldG9uIHtcblxuXHRjb25zdHJ1Y3RvciggYm9uZXMgPSBbXSwgYm9uZUludmVyc2VzID0gW10gKSB7XG5cblx0XHR0aGlzLnV1aWQgPSBnZW5lcmF0ZVVVSUQoKTtcblxuXHRcdHRoaXMuYm9uZXMgPSBib25lcy5zbGljZSggMCApO1xuXHRcdHRoaXMuYm9uZUludmVyc2VzID0gYm9uZUludmVyc2VzO1xuXHRcdHRoaXMuYm9uZU1hdHJpY2VzID0gbnVsbDtcblxuXHRcdHRoaXMuYm9uZVRleHR1cmUgPSBudWxsO1xuXG5cdFx0dGhpcy5pbml0KCk7XG5cblx0fVxuXG5cdGluaXQoKSB7XG5cblx0XHRjb25zdCBib25lcyA9IHRoaXMuYm9uZXM7XG5cdFx0Y29uc3QgYm9uZUludmVyc2VzID0gdGhpcy5ib25lSW52ZXJzZXM7XG5cblx0XHR0aGlzLmJvbmVNYXRyaWNlcyA9IG5ldyBGbG9hdDMyQXJyYXkoIGJvbmVzLmxlbmd0aCAqIDE2ICk7XG5cblx0XHQvLyBjYWxjdWxhdGUgaW52ZXJzZSBib25lIG1hdHJpY2VzIGlmIG5lY2Vzc2FyeVxuXG5cdFx0aWYgKCBib25lSW52ZXJzZXMubGVuZ3RoID09PSAwICkge1xuXG5cdFx0XHR0aGlzLmNhbGN1bGF0ZUludmVyc2VzKCk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBoYW5kbGUgc3BlY2lhbCBjYXNlXG5cblx0XHRcdGlmICggYm9uZXMubGVuZ3RoICE9PSBib25lSW52ZXJzZXMubGVuZ3RoICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLlNrZWxldG9uOiBOdW1iZXIgb2YgaW52ZXJzZSBib25lIG1hdHJpY2VzIGRvZXMgbm90IG1hdGNoIGFtb3VudCBvZiBib25lcy4nICk7XG5cblx0XHRcdFx0dGhpcy5ib25lSW52ZXJzZXMgPSBbXTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdGhpcy5ib25lcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdHRoaXMuYm9uZUludmVyc2VzLnB1c2goIG5ldyBNYXRyaXg0KCkgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0Y2FsY3VsYXRlSW52ZXJzZXMoKSB7XG5cblx0XHR0aGlzLmJvbmVJbnZlcnNlcy5sZW5ndGggPSAwO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRoaXMuYm9uZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGludmVyc2UgPSBuZXcgTWF0cml4NCgpO1xuXG5cdFx0XHRpZiAoIHRoaXMuYm9uZXNbIGkgXSApIHtcblxuXHRcdFx0XHRpbnZlcnNlLmNvcHkoIHRoaXMuYm9uZXNbIGkgXS5tYXRyaXhXb3JsZCApLmludmVydCgpO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuYm9uZUludmVyc2VzLnB1c2goIGludmVyc2UgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0cG9zZSgpIHtcblxuXHRcdC8vIHJlY292ZXIgdGhlIGJpbmQtdGltZSB3b3JsZCBtYXRyaWNlc1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRoaXMuYm9uZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGJvbmUgPSB0aGlzLmJvbmVzWyBpIF07XG5cblx0XHRcdGlmICggYm9uZSApIHtcblxuXHRcdFx0XHRib25lLm1hdHJpeFdvcmxkLmNvcHkoIHRoaXMuYm9uZUludmVyc2VzWyBpIF0gKS5pbnZlcnQoKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gY29tcHV0ZSB0aGUgbG9jYWwgbWF0cmljZXMsIHBvc2l0aW9ucywgcm90YXRpb25zIGFuZCBzY2FsZXNcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0aGlzLmJvbmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBib25lID0gdGhpcy5ib25lc1sgaSBdO1xuXG5cdFx0XHRpZiAoIGJvbmUgKSB7XG5cblx0XHRcdFx0aWYgKCBib25lLnBhcmVudCAmJiBib25lLnBhcmVudC5pc0JvbmUgKSB7XG5cblx0XHRcdFx0XHRib25lLm1hdHJpeC5jb3B5KCBib25lLnBhcmVudC5tYXRyaXhXb3JsZCApLmludmVydCgpO1xuXHRcdFx0XHRcdGJvbmUubWF0cml4Lm11bHRpcGx5KCBib25lLm1hdHJpeFdvcmxkICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGJvbmUubWF0cml4LmNvcHkoIGJvbmUubWF0cml4V29ybGQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ym9uZS5tYXRyaXguZGVjb21wb3NlKCBib25lLnBvc2l0aW9uLCBib25lLnF1YXRlcm5pb24sIGJvbmUuc2NhbGUgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHR1cGRhdGUoKSB7XG5cblx0XHRjb25zdCBib25lcyA9IHRoaXMuYm9uZXM7XG5cdFx0Y29uc3QgYm9uZUludmVyc2VzID0gdGhpcy5ib25lSW52ZXJzZXM7XG5cdFx0Y29uc3QgYm9uZU1hdHJpY2VzID0gdGhpcy5ib25lTWF0cmljZXM7XG5cdFx0Y29uc3QgYm9uZVRleHR1cmUgPSB0aGlzLmJvbmVUZXh0dXJlO1xuXG5cdFx0Ly8gZmxhdHRlbiBib25lIG1hdHJpY2VzIHRvIGFycmF5XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYm9uZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdC8vIGNvbXB1dGUgdGhlIG9mZnNldCBiZXR3ZWVuIHRoZSBjdXJyZW50IGFuZCB0aGUgb3JpZ2luYWwgdHJhbnNmb3JtXG5cblx0XHRcdGNvbnN0IG1hdHJpeCA9IGJvbmVzWyBpIF0gPyBib25lc1sgaSBdLm1hdHJpeFdvcmxkIDogX2lkZW50aXR5TWF0cml4JDE7XG5cblx0XHRcdF9vZmZzZXRNYXRyaXgubXVsdGlwbHlNYXRyaWNlcyggbWF0cml4LCBib25lSW52ZXJzZXNbIGkgXSApO1xuXHRcdFx0X29mZnNldE1hdHJpeC50b0FycmF5KCBib25lTWF0cmljZXMsIGkgKiAxNiApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBib25lVGV4dHVyZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0Ym9uZVRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgU2tlbGV0b24oIHRoaXMuYm9uZXMsIHRoaXMuYm9uZUludmVyc2VzICk7XG5cblx0fVxuXG5cdGNvbXB1dGVCb25lVGV4dHVyZSgpIHtcblxuXHRcdC8vIGxheW91dCAoMSBtYXRyaXggPSA0IHBpeGVscylcblx0XHQvLyAgICAgIFJHQkEgUkdCQSBSR0JBIFJHQkEgKD0+IGNvbHVtbjEsIGNvbHVtbjIsIGNvbHVtbjMsIGNvbHVtbjQpXG5cdFx0Ly8gIHdpdGggIDh4OCAgcGl4ZWwgdGV4dHVyZSBtYXggICAxNiBib25lcyAqIDQgcGl4ZWxzID0gICg4ICogOClcblx0XHQvLyAgICAgICAxNngxNiBwaXhlbCB0ZXh0dXJlIG1heCAgIDY0IGJvbmVzICogNCBwaXhlbHMgPSAoMTYgKiAxNilcblx0XHQvLyAgICAgICAzMngzMiBwaXhlbCB0ZXh0dXJlIG1heCAgMjU2IGJvbmVzICogNCBwaXhlbHMgPSAoMzIgKiAzMilcblx0XHQvLyAgICAgICA2NHg2NCBwaXhlbCB0ZXh0dXJlIG1heCAxMDI0IGJvbmVzICogNCBwaXhlbHMgPSAoNjQgKiA2NClcblxuXHRcdGxldCBzaXplID0gTWF0aC5zcXJ0KCB0aGlzLmJvbmVzLmxlbmd0aCAqIDQgKTsgLy8gNCBwaXhlbHMgbmVlZGVkIGZvciAxIG1hdHJpeFxuXHRcdHNpemUgPSBNYXRoLmNlaWwoIHNpemUgLyA0ICkgKiA0O1xuXHRcdHNpemUgPSBNYXRoLm1heCggc2l6ZSwgNCApO1xuXG5cdFx0Y29uc3QgYm9uZU1hdHJpY2VzID0gbmV3IEZsb2F0MzJBcnJheSggc2l6ZSAqIHNpemUgKiA0ICk7IC8vIDQgZmxvYXRzIHBlciBSR0JBIHBpeGVsXG5cdFx0Ym9uZU1hdHJpY2VzLnNldCggdGhpcy5ib25lTWF0cmljZXMgKTsgLy8gY29weSBjdXJyZW50IHZhbHVlc1xuXG5cdFx0Y29uc3QgYm9uZVRleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoIGJvbmVNYXRyaWNlcywgc2l6ZSwgc2l6ZSwgUkdCQUZvcm1hdCwgRmxvYXRUeXBlICk7XG5cdFx0Ym9uZVRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0dGhpcy5ib25lTWF0cmljZXMgPSBib25lTWF0cmljZXM7XG5cdFx0dGhpcy5ib25lVGV4dHVyZSA9IGJvbmVUZXh0dXJlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldEJvbmVCeU5hbWUoIG5hbWUgKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdGhpcy5ib25lcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgYm9uZSA9IHRoaXMuYm9uZXNbIGkgXTtcblxuXHRcdFx0aWYgKCBib25lLm5hbWUgPT09IG5hbWUgKSB7XG5cblx0XHRcdFx0cmV0dXJuIGJvbmU7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB1bmRlZmluZWQ7XG5cblx0fVxuXG5cdGRpc3Bvc2UoICkge1xuXG5cdFx0aWYgKCB0aGlzLmJvbmVUZXh0dXJlICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLmJvbmVUZXh0dXJlLmRpc3Bvc2UoKTtcblxuXHRcdFx0dGhpcy5ib25lVGV4dHVyZSA9IG51bGw7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZyb21KU09OKCBqc29uLCBib25lcyApIHtcblxuXHRcdHRoaXMudXVpZCA9IGpzb24udXVpZDtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24uYm9uZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgdXVpZCA9IGpzb24uYm9uZXNbIGkgXTtcblx0XHRcdGxldCBib25lID0gYm9uZXNbIHV1aWQgXTtcblxuXHRcdFx0aWYgKCBib25lID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuU2tlbGV0b246IE5vIGJvbmUgZm91bmQgd2l0aCBVVUlEOicsIHV1aWQgKTtcblx0XHRcdFx0Ym9uZSA9IG5ldyBCb25lKCk7XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5ib25lcy5wdXNoKCBib25lICk7XG5cdFx0XHR0aGlzLmJvbmVJbnZlcnNlcy5wdXNoKCBuZXcgTWF0cml4NCgpLmZyb21BcnJheSgganNvbi5ib25lSW52ZXJzZXNbIGkgXSApICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmluaXQoKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0ge1xuXHRcdFx0bWV0YWRhdGE6IHtcblx0XHRcdFx0dmVyc2lvbjogNC42LFxuXHRcdFx0XHR0eXBlOiAnU2tlbGV0b24nLFxuXHRcdFx0XHRnZW5lcmF0b3I6ICdTa2VsZXRvbi50b0pTT04nXG5cdFx0XHR9LFxuXHRcdFx0Ym9uZXM6IFtdLFxuXHRcdFx0Ym9uZUludmVyc2VzOiBbXVxuXHRcdH07XG5cblx0XHRkYXRhLnV1aWQgPSB0aGlzLnV1aWQ7XG5cblx0XHRjb25zdCBib25lcyA9IHRoaXMuYm9uZXM7XG5cdFx0Y29uc3QgYm9uZUludmVyc2VzID0gdGhpcy5ib25lSW52ZXJzZXM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBib25lcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBib25lID0gYm9uZXNbIGkgXTtcblx0XHRcdGRhdGEuYm9uZXMucHVzaCggYm9uZS51dWlkICk7XG5cblx0XHRcdGNvbnN0IGJvbmVJbnZlcnNlID0gYm9uZUludmVyc2VzWyBpIF07XG5cdFx0XHRkYXRhLmJvbmVJbnZlcnNlcy5wdXNoKCBib25lSW52ZXJzZS50b0FycmF5KCkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxufVxuXG5jbGFzcyBJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xuXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQsIG1lc2hQZXJBdHRyaWJ1dGUgPSAxICkge1xuXG5cdFx0c3VwZXIoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xuXG5cdFx0dGhpcy5pc0luc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSA9IHRydWU7XG5cblx0XHR0aGlzLm1lc2hQZXJBdHRyaWJ1dGUgPSBtZXNoUGVyQXR0cmlidXRlO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMubWVzaFBlckF0dHJpYnV0ZSA9IHNvdXJjZS5tZXNoUGVyQXR0cmlidXRlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcblxuXHRcdGRhdGEubWVzaFBlckF0dHJpYnV0ZSA9IHRoaXMubWVzaFBlckF0dHJpYnV0ZTtcblxuXHRcdGRhdGEuaXNJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUgPSB0cnVlO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9pbnN0YW5jZUxvY2FsTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX2luc3RhbmNlV29ybGRNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5cbmNvbnN0IF9pbnN0YW5jZUludGVyc2VjdHMgPSBbXTtcblxuY29uc3QgX2JveDMgPSAvKkBfX1BVUkVfXyovIG5ldyBCb3gzKCk7XG5jb25zdCBfaWRlbnRpdHkgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfbWVzaCQxID0gLypAX19QVVJFX18qLyBuZXcgTWVzaCgpO1xuY29uc3QgX3NwaGVyZSQzID0gLypAX19QVVJFX18qLyBuZXcgU3BoZXJlKCk7XG5cbmNsYXNzIEluc3RhbmNlZE1lc2ggZXh0ZW5kcyBNZXNoIHtcblxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnksIG1hdGVyaWFsLCBjb3VudCApIHtcblxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblxuXHRcdHRoaXMuaXNJbnN0YW5jZWRNZXNoID0gdHJ1ZTtcblxuXHRcdHRoaXMuaW5zdGFuY2VNYXRyaXggPSBuZXcgSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlKCBuZXcgRmxvYXQzMkFycmF5KCBjb3VudCAqIDE2ICksIDE2ICk7XG5cdFx0dGhpcy5pbnN0YW5jZUNvbG9yID0gbnVsbDtcblx0XHR0aGlzLm1vcnBoVGV4dHVyZSA9IG51bGw7XG5cblx0XHR0aGlzLmNvdW50ID0gY291bnQ7XG5cblx0XHR0aGlzLmJvdW5kaW5nQm94ID0gbnVsbDtcblx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlID0gbnVsbDtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvdW50OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLnNldE1hdHJpeEF0KCBpLCBfaWRlbnRpdHkgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Y29tcHV0ZUJvdW5kaW5nQm94KCkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGNvbnN0IGNvdW50ID0gdGhpcy5jb3VudDtcblxuXHRcdGlmICggdGhpcy5ib3VuZGluZ0JveCA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5ib3VuZGluZ0JveCA9IG5ldyBCb3gzKCk7XG5cblx0XHR9XG5cblx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nQm94ID09PSBudWxsICkge1xuXG5cdFx0XHRnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdCb3goKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuYm91bmRpbmdCb3gubWFrZUVtcHR5KCk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb3VudDsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX2luc3RhbmNlTG9jYWxNYXRyaXggKTtcblxuXHRcdFx0X2JveDMuY29weSggZ2VvbWV0cnkuYm91bmRpbmdCb3ggKS5hcHBseU1hdHJpeDQoIF9pbnN0YW5jZUxvY2FsTWF0cml4ICk7XG5cblx0XHRcdHRoaXMuYm91bmRpbmdCb3gudW5pb24oIF9ib3gzICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcblx0XHRjb25zdCBjb3VudCA9IHRoaXMuY291bnQ7XG5cblx0XHRpZiAoIHRoaXMuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCk7XG5cblx0XHR9XG5cblx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkge1xuXG5cdFx0XHRnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuYm91bmRpbmdTcGhlcmUubWFrZUVtcHR5KCk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb3VudDsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX2luc3RhbmNlTG9jYWxNYXRyaXggKTtcblxuXHRcdFx0X3NwaGVyZSQzLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICkuYXBwbHlNYXRyaXg0KCBfaW5zdGFuY2VMb2NhbE1hdHJpeCApO1xuXG5cdFx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlLnVuaW9uKCBfc3BoZXJlJDMgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0dGhpcy5pbnN0YW5jZU1hdHJpeC5jb3B5KCBzb3VyY2UuaW5zdGFuY2VNYXRyaXggKTtcblxuXHRcdGlmICggc291cmNlLm1vcnBoVGV4dHVyZSAhPT0gbnVsbCApIHRoaXMubW9ycGhUZXh0dXJlID0gc291cmNlLm1vcnBoVGV4dHVyZS5jbG9uZSgpO1xuXHRcdGlmICggc291cmNlLmluc3RhbmNlQ29sb3IgIT09IG51bGwgKSB0aGlzLmluc3RhbmNlQ29sb3IgPSBzb3VyY2UuaW5zdGFuY2VDb2xvci5jbG9uZSgpO1xuXG5cdFx0dGhpcy5jb3VudCA9IHNvdXJjZS5jb3VudDtcblxuXHRcdGlmICggc291cmNlLmJvdW5kaW5nQm94ICE9PSBudWxsICkgdGhpcy5ib3VuZGluZ0JveCA9IHNvdXJjZS5ib3VuZGluZ0JveC5jbG9uZSgpO1xuXHRcdGlmICggc291cmNlLmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkgdGhpcy5ib3VuZGluZ1NwaGVyZSA9IHNvdXJjZS5ib3VuZGluZ1NwaGVyZS5jbG9uZSgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldENvbG9yQXQoIGluZGV4LCBjb2xvciApIHtcblxuXHRcdGNvbG9yLmZyb21BcnJheSggdGhpcy5pbnN0YW5jZUNvbG9yLmFycmF5LCBpbmRleCAqIDMgKTtcblxuXHR9XG5cblx0Z2V0TWF0cml4QXQoIGluZGV4LCBtYXRyaXggKSB7XG5cblx0XHRtYXRyaXguZnJvbUFycmF5KCB0aGlzLmluc3RhbmNlTWF0cml4LmFycmF5LCBpbmRleCAqIDE2ICk7XG5cblx0fVxuXG5cdGdldE1vcnBoQXQoIGluZGV4LCBvYmplY3QgKSB7XG5cblx0XHRjb25zdCBvYmplY3RJbmZsdWVuY2VzID0gb2JqZWN0Lm1vcnBoVGFyZ2V0SW5mbHVlbmNlcztcblxuXHRcdGNvbnN0IGFycmF5ID0gdGhpcy5tb3JwaFRleHR1cmUuc291cmNlLmRhdGEuZGF0YTtcblxuXHRcdGNvbnN0IGxlbiA9IG9iamVjdEluZmx1ZW5jZXMubGVuZ3RoICsgMTsgLy8gQWxsIGluZmx1ZW5jZXMgKyB0aGUgYmFzZUluZmx1ZW5jZVN1bVxuXG5cdFx0Y29uc3QgZGF0YUluZGV4ID0gaW5kZXggKiBsZW4gKyAxOyAvLyBTa2lwIHRoZSBiYXNlSW5mbHVlbmNlU3VtIGF0IHRoZSBiZWdpbm5pbmdcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG9iamVjdEluZmx1ZW5jZXMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRvYmplY3RJbmZsdWVuY2VzWyBpIF0gPSBhcnJheVsgZGF0YUluZGV4ICsgaSBdO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XG5cblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XG5cdFx0Y29uc3QgcmF5Y2FzdFRpbWVzID0gdGhpcy5jb3VudDtcblxuXHRcdF9tZXNoJDEuZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdF9tZXNoJDEubWF0ZXJpYWwgPSB0aGlzLm1hdGVyaWFsO1xuXG5cdFx0aWYgKCBfbWVzaCQxLm1hdGVyaWFsID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHQvLyB0ZXN0IHdpdGggYm91bmRpbmcgc3BoZXJlIGZpcnN0XG5cblx0XHRpZiAoIHRoaXMuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB0aGlzLmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xuXG5cdFx0X3NwaGVyZSQzLmNvcHkoIHRoaXMuYm91bmRpbmdTcGhlcmUgKTtcblx0XHRfc3BoZXJlJDMuYXBwbHlNYXRyaXg0KCBtYXRyaXhXb3JsZCApO1xuXG5cdFx0aWYgKCByYXljYXN0ZXIucmF5LmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUkMyApID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdC8vIG5vdyB0ZXN0IGVhY2ggaW5zdGFuY2VcblxuXHRcdGZvciAoIGxldCBpbnN0YW5jZUlkID0gMDsgaW5zdGFuY2VJZCA8IHJheWNhc3RUaW1lczsgaW5zdGFuY2VJZCArKyApIHtcblxuXHRcdFx0Ly8gY2FsY3VsYXRlIHRoZSB3b3JsZCBtYXRyaXggZm9yIGVhY2ggaW5zdGFuY2VcblxuXHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaW5zdGFuY2VJZCwgX2luc3RhbmNlTG9jYWxNYXRyaXggKTtcblxuXHRcdFx0X2luc3RhbmNlV29ybGRNYXRyaXgubXVsdGlwbHlNYXRyaWNlcyggbWF0cml4V29ybGQsIF9pbnN0YW5jZUxvY2FsTWF0cml4ICk7XG5cblx0XHRcdC8vIHRoZSBtZXNoIHJlcHJlc2VudHMgdGhpcyBzaW5nbGUgaW5zdGFuY2VcblxuXHRcdFx0X21lc2gkMS5tYXRyaXhXb3JsZCA9IF9pbnN0YW5jZVdvcmxkTWF0cml4O1xuXG5cdFx0XHRfbWVzaCQxLnJheWNhc3QoIHJheWNhc3RlciwgX2luc3RhbmNlSW50ZXJzZWN0cyApO1xuXG5cdFx0XHQvLyBwcm9jZXNzIHRoZSByZXN1bHQgb2YgcmF5Y2FzdFxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBfaW5zdGFuY2VJbnRlcnNlY3RzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgaW50ZXJzZWN0ID0gX2luc3RhbmNlSW50ZXJzZWN0c1sgaSBdO1xuXHRcdFx0XHRpbnRlcnNlY3QuaW5zdGFuY2VJZCA9IGluc3RhbmNlSWQ7XG5cdFx0XHRcdGludGVyc2VjdC5vYmplY3QgPSB0aGlzO1xuXHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdF9pbnN0YW5jZUludGVyc2VjdHMubGVuZ3RoID0gMDtcblxuXHRcdH1cblxuXHR9XG5cblx0c2V0Q29sb3JBdCggaW5kZXgsIGNvbG9yICkge1xuXG5cdFx0aWYgKCB0aGlzLmluc3RhbmNlQ29sb3IgPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuaW5zdGFuY2VDb2xvciA9IG5ldyBJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUoIG5ldyBGbG9hdDMyQXJyYXkoIHRoaXMuaW5zdGFuY2VNYXRyaXguY291bnQgKiAzICksIDMgKTtcblxuXHRcdH1cblxuXHRcdGNvbG9yLnRvQXJyYXkoIHRoaXMuaW5zdGFuY2VDb2xvci5hcnJheSwgaW5kZXggKiAzICk7XG5cblx0fVxuXG5cdHNldE1hdHJpeEF0KCBpbmRleCwgbWF0cml4ICkge1xuXG5cdFx0bWF0cml4LnRvQXJyYXkoIHRoaXMuaW5zdGFuY2VNYXRyaXguYXJyYXksIGluZGV4ICogMTYgKTtcblxuXHR9XG5cblx0c2V0TW9ycGhBdCggaW5kZXgsIG9iamVjdCApIHtcblxuXHRcdGNvbnN0IG9iamVjdEluZmx1ZW5jZXMgPSBvYmplY3QubW9ycGhUYXJnZXRJbmZsdWVuY2VzO1xuXG5cdFx0Y29uc3QgbGVuID0gb2JqZWN0SW5mbHVlbmNlcy5sZW5ndGggKyAxOyAvLyBtb3JwaEJhc2VJbmZsdWVuY2UgKyBhbGwgaW5mbHVlbmNlc1xuXG5cdFx0aWYgKCB0aGlzLm1vcnBoVGV4dHVyZSA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5tb3JwaFRleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoIG5ldyBGbG9hdDMyQXJyYXkoIGxlbiAqIHRoaXMuY291bnQgKSwgbGVuLCB0aGlzLmNvdW50LCBSZWRGb3JtYXQsIEZsb2F0VHlwZSApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgYXJyYXkgPSB0aGlzLm1vcnBoVGV4dHVyZS5zb3VyY2UuZGF0YS5kYXRhO1xuXG5cdFx0bGV0IG1vcnBoSW5mbHVlbmNlc1N1bSA9IDA7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBvYmplY3RJbmZsdWVuY2VzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0bW9ycGhJbmZsdWVuY2VzU3VtICs9IG9iamVjdEluZmx1ZW5jZXNbIGkgXTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IG1vcnBoQmFzZUluZmx1ZW5jZSA9IHRoaXMuZ2VvbWV0cnkubW9ycGhUYXJnZXRzUmVsYXRpdmUgPyAxIDogMSAtIG1vcnBoSW5mbHVlbmNlc1N1bTtcblxuXHRcdGNvbnN0IGRhdGFJbmRleCA9IGxlbiAqIGluZGV4O1xuXG5cdFx0YXJyYXlbIGRhdGFJbmRleCBdID0gbW9ycGhCYXNlSW5mbHVlbmNlO1xuXG5cdFx0YXJyYXkuc2V0KCBvYmplY3RJbmZsdWVuY2VzLCBkYXRhSW5kZXggKyAxICk7XG5cblx0fVxuXG5cdHVwZGF0ZU1vcnBoVGFyZ2V0cygpIHtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzcG9zZScgfSApO1xuXG5cdFx0aWYgKCB0aGlzLm1vcnBoVGV4dHVyZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5tb3JwaFRleHR1cmUuZGlzcG9zZSgpO1xuXHRcdFx0dGhpcy5tb3JwaFRleHR1cmUgPSBudWxsO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHNvcnRPcGFxdWUoIGEsIGIgKSB7XG5cblx0cmV0dXJuIGEueiAtIGIuejtcblxufVxuXG5mdW5jdGlvbiBzb3J0VHJhbnNwYXJlbnQoIGEsIGIgKSB7XG5cblx0cmV0dXJuIGIueiAtIGEuejtcblxufVxuXG5jbGFzcyBNdWx0aURyYXdSZW5kZXJMaXN0IHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHRoaXMuaW5kZXggPSAwO1xuXHRcdHRoaXMucG9vbCA9IFtdO1xuXHRcdHRoaXMubGlzdCA9IFtdO1xuXG5cdH1cblxuXHRwdXNoKCBkcmF3UmFuZ2UsIHosIGluZGV4ICkge1xuXG5cdFx0Y29uc3QgcG9vbCA9IHRoaXMucG9vbDtcblx0XHRjb25zdCBsaXN0ID0gdGhpcy5saXN0O1xuXHRcdGlmICggdGhpcy5pbmRleCA+PSBwb29sLmxlbmd0aCApIHtcblxuXHRcdFx0cG9vbC5wdXNoKCB7XG5cblx0XHRcdFx0c3RhcnQ6IC0gMSxcblx0XHRcdFx0Y291bnQ6IC0gMSxcblx0XHRcdFx0ejogLSAxLFxuXHRcdFx0XHRpbmRleDogLSAxLFxuXG5cdFx0XHR9ICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBpdGVtID0gcG9vbFsgdGhpcy5pbmRleCBdO1xuXHRcdGxpc3QucHVzaCggaXRlbSApO1xuXHRcdHRoaXMuaW5kZXggKys7XG5cblx0XHRpdGVtLnN0YXJ0ID0gZHJhd1JhbmdlLnN0YXJ0O1xuXHRcdGl0ZW0uY291bnQgPSBkcmF3UmFuZ2UuY291bnQ7XG5cdFx0aXRlbS56ID0gejtcblx0XHRpdGVtLmluZGV4ID0gaW5kZXg7XG5cblx0fVxuXG5cdHJlc2V0KCkge1xuXG5cdFx0dGhpcy5saXN0Lmxlbmd0aCA9IDA7XG5cdFx0dGhpcy5pbmRleCA9IDA7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9tYXRyaXgkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF9pbnZNYXRyaXhXb3JsZCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF9pZGVudGl0eU1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF93aGl0ZUNvbG9yID0gLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDEsIDEsIDEgKTtcbmNvbnN0IF9wcm9qU2NyZWVuTWF0cml4JDIgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfZnJ1c3R1bSA9IC8qQF9fUFVSRV9fKi8gbmV3IEZydXN0dW0oKTtcbmNvbnN0IF9ib3gkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcbmNvbnN0IF9zcGhlcmUkMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFNwaGVyZSgpO1xuY29uc3QgX3ZlY3RvciQ1ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2ZvcndhcmQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdGVtcCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9yZW5kZXJMaXN0ID0gLypAX19QVVJFX18qLyBuZXcgTXVsdGlEcmF3UmVuZGVyTGlzdCgpO1xuY29uc3QgX21lc2ggPSAvKkBfX1BVUkVfXyovIG5ldyBNZXNoKCk7XG5jb25zdCBfYmF0Y2hJbnRlcnNlY3RzID0gW107XG5cbi8vIEBUT0RPOiBTa2lubmVkTWVzaCBzdXBwb3J0P1xuLy8gQFRPRE86IGdlb21ldHJ5Lmdyb3VwcyBzdXBwb3J0P1xuLy8gQFRPRE86IGdlb21ldHJ5LmRyYXdSYW5nZSBzdXBwb3J0P1xuLy8gQFRPRE86IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcyBzdXBwb3J0P1xuLy8gQFRPRE86IFN1cHBvcnQgdW5pZm9ybSBwYXJhbWV0ZXIgcGVyIGdlb21ldHJ5XG4vLyBAVE9ETzogQWRkIGFuIFwib3B0aW1pemVcIiBmdW5jdGlvbiB0byBwYWNrIGdlb21ldHJ5IGFuZCByZW1vdmUgZGF0YSBnYXBzXG5cbi8vIGNvcGllcyBkYXRhIGZyb20gYXR0cmlidXRlIFwic3JjXCIgaW50byBcInRhcmdldFwiIHN0YXJ0aW5nIGF0IFwidGFyZ2V0T2Zmc2V0XCJcbmZ1bmN0aW9uIGNvcHlBdHRyaWJ1dGVEYXRhKCBzcmMsIHRhcmdldCwgdGFyZ2V0T2Zmc2V0ID0gMCApIHtcblxuXHRjb25zdCBpdGVtU2l6ZSA9IHRhcmdldC5pdGVtU2l6ZTtcblx0aWYgKCBzcmMuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSB8fCBzcmMuYXJyYXkuY29uc3RydWN0b3IgIT09IHRhcmdldC5hcnJheS5jb25zdHJ1Y3RvciApIHtcblxuXHRcdC8vIHVzZSB0aGUgY29tcG9uZW50IGdldHRlcnMgYW5kIHNldHRlcnMgaWYgdGhlIGFycmF5IGRhdGEgY2Fubm90XG5cdFx0Ly8gYmUgY29waWVkIGRpcmVjdGx5XG5cdFx0Y29uc3QgdmVydGV4Q291bnQgPSBzcmMuY291bnQ7XG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdmVydGV4Q291bnQ7IGkgKysgKSB7XG5cblx0XHRcdGZvciAoIGxldCBjID0gMDsgYyA8IGl0ZW1TaXplOyBjICsrICkge1xuXG5cdFx0XHRcdHRhcmdldC5zZXRDb21wb25lbnQoIGkgKyB0YXJnZXRPZmZzZXQsIGMsIHNyYy5nZXRDb21wb25lbnQoIGksIGMgKSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fSBlbHNlIHtcblxuXHRcdC8vIGZhc3RlciBjb3B5IGFwcHJvYWNoIHVzaW5nIHR5cGVkIGFycmF5IHNldCBmdW5jdGlvblxuXHRcdHRhcmdldC5hcnJheS5zZXQoIHNyYy5hcnJheSwgdGFyZ2V0T2Zmc2V0ICogaXRlbVNpemUgKTtcblxuXHR9XG5cblx0dGFyZ2V0Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxufVxuXG5jbGFzcyBCYXRjaGVkTWVzaCBleHRlbmRzIE1lc2gge1xuXG5cdGdldCBtYXhJbnN0YW5jZUNvdW50KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX21heEluc3RhbmNlQ291bnQ7XG5cblx0fVxuXG5cdGNvbnN0cnVjdG9yKCBtYXhJbnN0YW5jZUNvdW50LCBtYXhWZXJ0ZXhDb3VudCwgbWF4SW5kZXhDb3VudCA9IG1heFZlcnRleENvdW50ICogMiwgbWF0ZXJpYWwgKSB7XG5cblx0XHRzdXBlciggbmV3IEJ1ZmZlckdlb21ldHJ5KCksIG1hdGVyaWFsICk7XG5cblx0XHR0aGlzLmlzQmF0Y2hlZE1lc2ggPSB0cnVlO1xuXHRcdHRoaXMucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCA9IHRydWU7XG5cdFx0dGhpcy5zb3J0T2JqZWN0cyA9IHRydWU7XG5cdFx0dGhpcy5ib3VuZGluZ0JveCA9IG51bGw7XG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG51bGw7XG5cdFx0dGhpcy5jdXN0b21Tb3J0ID0gbnVsbDtcblxuXHRcdC8vIHN0b3JlcyB2aXNpYmxlLCBhY3RpdmUsIGFuZCBnZW9tZXRyeSBpZCBwZXIgb2JqZWN0XG5cdFx0dGhpcy5fZHJhd0luZm8gPSBbXTtcblxuXHRcdC8vIGdlb21ldHJ5IGluZm9ybWF0aW9uXG5cdFx0dGhpcy5fZHJhd1JhbmdlcyA9IFtdO1xuXHRcdHRoaXMuX3Jlc2VydmVkUmFuZ2VzID0gW107XG5cdFx0dGhpcy5fYm91bmRzID0gW107XG5cblx0XHR0aGlzLl9tYXhJbnN0YW5jZUNvdW50ID0gbWF4SW5zdGFuY2VDb3VudDtcblx0XHR0aGlzLl9tYXhWZXJ0ZXhDb3VudCA9IG1heFZlcnRleENvdW50O1xuXHRcdHRoaXMuX21heEluZGV4Q291bnQgPSBtYXhJbmRleENvdW50O1xuXG5cdFx0dGhpcy5fZ2VvbWV0cnlJbml0aWFsaXplZCA9IGZhbHNlO1xuXHRcdHRoaXMuX2dlb21ldHJ5Q291bnQgPSAwO1xuXHRcdHRoaXMuX211bHRpRHJhd0NvdW50cyA9IG5ldyBJbnQzMkFycmF5KCBtYXhJbnN0YW5jZUNvdW50ICk7XG5cdFx0dGhpcy5fbXVsdGlEcmF3U3RhcnRzID0gbmV3IEludDMyQXJyYXkoIG1heEluc3RhbmNlQ291bnQgKTtcblx0XHR0aGlzLl9tdWx0aURyYXdDb3VudCA9IDA7XG5cdFx0dGhpcy5fbXVsdGlEcmF3SW5zdGFuY2VzID0gbnVsbDtcblx0XHR0aGlzLl92aXNpYmlsaXR5Q2hhbmdlZCA9IHRydWU7XG5cblx0XHQvLyBMb2NhbCBtYXRyaXggcGVyIGdlb21ldHJ5IGJ5IHVzaW5nIGRhdGEgdGV4dHVyZVxuXHRcdHRoaXMuX21hdHJpY2VzVGV4dHVyZSA9IG51bGw7XG5cdFx0dGhpcy5faW5kaXJlY3RUZXh0dXJlID0gbnVsbDtcblx0XHR0aGlzLl9jb2xvcnNUZXh0dXJlID0gbnVsbDtcblxuXHRcdHRoaXMuX2luaXRNYXRyaWNlc1RleHR1cmUoKTtcblx0XHR0aGlzLl9pbml0SW5kaXJlY3RUZXh0dXJlKCk7XG5cblx0fVxuXG5cdF9pbml0TWF0cmljZXNUZXh0dXJlKCkge1xuXG5cdFx0Ly8gbGF5b3V0ICgxIG1hdHJpeCA9IDQgcGl4ZWxzKVxuXHRcdC8vICAgICAgUkdCQSBSR0JBIFJHQkEgUkdCQSAoPT4gY29sdW1uMSwgY29sdW1uMiwgY29sdW1uMywgY29sdW1uNClcblx0XHQvLyAgd2l0aCAgOHg4ICBwaXhlbCB0ZXh0dXJlIG1heCAgIDE2IG1hdHJpY2VzICogNCBwaXhlbHMgPSAgKDggKiA4KVxuXHRcdC8vICAgICAgIDE2eDE2IHBpeGVsIHRleHR1cmUgbWF4ICAgNjQgbWF0cmljZXMgKiA0IHBpeGVscyA9ICgxNiAqIDE2KVxuXHRcdC8vICAgICAgIDMyeDMyIHBpeGVsIHRleHR1cmUgbWF4ICAyNTYgbWF0cmljZXMgKiA0IHBpeGVscyA9ICgzMiAqIDMyKVxuXHRcdC8vICAgICAgIDY0eDY0IHBpeGVsIHRleHR1cmUgbWF4IDEwMjQgbWF0cmljZXMgKiA0IHBpeGVscyA9ICg2NCAqIDY0KVxuXG5cdFx0bGV0IHNpemUgPSBNYXRoLnNxcnQoIHRoaXMuX21heEluc3RhbmNlQ291bnQgKiA0ICk7IC8vIDQgcGl4ZWxzIG5lZWRlZCBmb3IgMSBtYXRyaXhcblx0XHRzaXplID0gTWF0aC5jZWlsKCBzaXplIC8gNCApICogNDtcblx0XHRzaXplID0gTWF0aC5tYXgoIHNpemUsIDQgKTtcblxuXHRcdGNvbnN0IG1hdHJpY2VzQXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KCBzaXplICogc2l6ZSAqIDQgKTsgLy8gNCBmbG9hdHMgcGVyIFJHQkEgcGl4ZWxcblx0XHRjb25zdCBtYXRyaWNlc1RleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoIG1hdHJpY2VzQXJyYXksIHNpemUsIHNpemUsIFJHQkFGb3JtYXQsIEZsb2F0VHlwZSApO1xuXG5cdFx0dGhpcy5fbWF0cmljZXNUZXh0dXJlID0gbWF0cmljZXNUZXh0dXJlO1xuXG5cdH1cblxuXHRfaW5pdEluZGlyZWN0VGV4dHVyZSgpIHtcblxuXHRcdGxldCBzaXplID0gTWF0aC5zcXJ0KCB0aGlzLl9tYXhJbnN0YW5jZUNvdW50ICk7XG5cdFx0c2l6ZSA9IE1hdGguY2VpbCggc2l6ZSApO1xuXG5cdFx0Y29uc3QgaW5kaXJlY3RBcnJheSA9IG5ldyBVaW50MzJBcnJheSggc2l6ZSAqIHNpemUgKTtcblx0XHRjb25zdCBpbmRpcmVjdFRleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoIGluZGlyZWN0QXJyYXksIHNpemUsIHNpemUsIFJlZEludGVnZXJGb3JtYXQsIFVuc2lnbmVkSW50VHlwZSApO1xuXG5cdFx0dGhpcy5faW5kaXJlY3RUZXh0dXJlID0gaW5kaXJlY3RUZXh0dXJlO1xuXG5cdH1cblxuXHRfaW5pdENvbG9yc1RleHR1cmUoKSB7XG5cblx0XHRsZXQgc2l6ZSA9IE1hdGguc3FydCggdGhpcy5fbWF4SW5kZXhDb3VudCApO1xuXHRcdHNpemUgPSBNYXRoLmNlaWwoIHNpemUgKTtcblxuXHRcdC8vIDQgZmxvYXRzIHBlciBSR0JBIHBpeGVsIGluaXRpYWxpemVkIHRvIHdoaXRlXG5cdFx0Y29uc3QgY29sb3JzQXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KCBzaXplICogc2l6ZSAqIDQgKS5maWxsKCAxICk7XG5cdFx0Y29uc3QgY29sb3JzVGV4dHVyZSA9IG5ldyBEYXRhVGV4dHVyZSggY29sb3JzQXJyYXksIHNpemUsIHNpemUsIFJHQkFGb3JtYXQsIEZsb2F0VHlwZSApO1xuXHRcdGNvbG9yc1RleHR1cmUuY29sb3JTcGFjZSA9IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZTtcblxuXHRcdHRoaXMuX2NvbG9yc1RleHR1cmUgPSBjb2xvcnNUZXh0dXJlO1xuXG5cdH1cblxuXHRfaW5pdGlhbGl6ZUdlb21ldHJ5KCByZWZlcmVuY2UgKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cdFx0Y29uc3QgbWF4VmVydGV4Q291bnQgPSB0aGlzLl9tYXhWZXJ0ZXhDb3VudDtcblx0XHRjb25zdCBtYXhJbmRleENvdW50ID0gdGhpcy5fbWF4SW5kZXhDb3VudDtcblx0XHRpZiAoIHRoaXMuX2dlb21ldHJ5SW5pdGlhbGl6ZWQgPT09IGZhbHNlICkge1xuXG5cdFx0XHRmb3IgKCBjb25zdCBhdHRyaWJ1dGVOYW1lIGluIHJlZmVyZW5jZS5hdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRcdGNvbnN0IHNyY0F0dHJpYnV0ZSA9IHJlZmVyZW5jZS5nZXRBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUgKTtcblx0XHRcdFx0Y29uc3QgeyBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgfSA9IHNyY0F0dHJpYnV0ZTtcblxuXHRcdFx0XHRjb25zdCBkc3RBcnJheSA9IG5ldyBhcnJheS5jb25zdHJ1Y3RvciggbWF4VmVydGV4Q291bnQgKiBpdGVtU2l6ZSApO1xuXHRcdFx0XHRjb25zdCBkc3RBdHRyaWJ1dGUgPSBuZXcgQnVmZmVyQXR0cmlidXRlKCBkc3RBcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcblxuXHRcdFx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUsIGRzdEF0dHJpYnV0ZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggcmVmZXJlbmNlLmdldEluZGV4KCkgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0Ly8gUmVzZXJ2ZSBsYXN0IHUxNiBpbmRleCBmb3IgcHJpbWl0aXZlIHJlc3RhcnQuXG5cdFx0XHRcdGNvbnN0IGluZGV4QXJyYXkgPSBtYXhWZXJ0ZXhDb3VudCA+IDY1NTM1XG5cdFx0XHRcdFx0PyBuZXcgVWludDMyQXJyYXkoIG1heEluZGV4Q291bnQgKVxuXHRcdFx0XHRcdDogbmV3IFVpbnQxNkFycmF5KCBtYXhJbmRleENvdW50ICk7XG5cblx0XHRcdFx0Z2VvbWV0cnkuc2V0SW5kZXgoIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGluZGV4QXJyYXksIDEgKSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2dlb21ldHJ5SW5pdGlhbGl6ZWQgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdH1cblxuXHQvLyBNYWtlIHN1cmUgdGhlIGdlb21ldHJ5IGlzIGNvbXBhdGlibGUgd2l0aCB0aGUgZXhpc3RpbmcgY29tYmluZWQgZ2VvbWV0cnkgYXR0cmlidXRlc1xuXHRfdmFsaWRhdGVHZW9tZXRyeSggZ2VvbWV0cnkgKSB7XG5cblx0XHQvLyBjaGVjayB0byBlbnN1cmUgdGhlIGdlb21ldHJpZXMgYXJlIHVzaW5nIGNvbnNpc3RlbnQgYXR0cmlidXRlcyBhbmQgaW5kaWNlc1xuXHRcdGNvbnN0IGJhdGNoR2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGlmICggQm9vbGVhbiggZ2VvbWV0cnkuZ2V0SW5kZXgoKSApICE9PSBCb29sZWFuKCBiYXRjaEdlb21ldHJ5LmdldEluZGV4KCkgKSApIHtcblxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnQmF0Y2hlZE1lc2g6IEFsbCBnZW9tZXRyaWVzIG11c3QgY29uc2lzdGVudGx5IGhhdmUgXCJpbmRleFwiLicgKTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGNvbnN0IGF0dHJpYnV0ZU5hbWUgaW4gYmF0Y2hHZW9tZXRyeS5hdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRpZiAoICEgZ2VvbWV0cnkuaGFzQXR0cmlidXRlKCBhdHRyaWJ1dGVOYW1lICkgKSB7XG5cblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCBgQmF0Y2hlZE1lc2g6IEFkZGVkIGdlb21ldHJ5IG1pc3NpbmcgXCIkeyBhdHRyaWJ1dGVOYW1lIH1cIi4gQWxsIGdlb21ldHJpZXMgbXVzdCBoYXZlIGNvbnNpc3RlbnQgYXR0cmlidXRlcy5gICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3Qgc3JjQXR0cmlidXRlID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCBhdHRyaWJ1dGVOYW1lICk7XG5cdFx0XHRjb25zdCBkc3RBdHRyaWJ1dGUgPSBiYXRjaEdlb21ldHJ5LmdldEF0dHJpYnV0ZSggYXR0cmlidXRlTmFtZSApO1xuXHRcdFx0aWYgKCBzcmNBdHRyaWJ1dGUuaXRlbVNpemUgIT09IGRzdEF0dHJpYnV0ZS5pdGVtU2l6ZSB8fCBzcmNBdHRyaWJ1dGUubm9ybWFsaXplZCAhPT0gZHN0QXR0cmlidXRlLm5vcm1hbGl6ZWQgKSB7XG5cblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnQmF0Y2hlZE1lc2g6IEFsbCBhdHRyaWJ1dGVzIG11c3QgaGF2ZSBhIGNvbnNpc3RlbnQgaXRlbVNpemUgYW5kIG5vcm1hbGl6ZWQgdmFsdWUuJyApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdHNldEN1c3RvbVNvcnQoIGZ1bmMgKSB7XG5cblx0XHR0aGlzLmN1c3RvbVNvcnQgPSBmdW5jO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb21wdXRlQm91bmRpbmdCb3goKSB7XG5cblx0XHRpZiAoIHRoaXMuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuYm91bmRpbmdCb3ggPSBuZXcgQm94MygpO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgZ2VvbWV0cnlDb3VudCA9IHRoaXMuX2dlb21ldHJ5Q291bnQ7XG5cdFx0Y29uc3QgYm91bmRpbmdCb3ggPSB0aGlzLmJvdW5kaW5nQm94O1xuXHRcdGNvbnN0IGRyYXdJbmZvID0gdGhpcy5fZHJhd0luZm87XG5cblx0XHRib3VuZGluZ0JveC5tYWtlRW1wdHkoKTtcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBnZW9tZXRyeUNvdW50OyBpICsrICkge1xuXG5cdFx0XHRpZiAoIGRyYXdJbmZvWyBpIF0uYWN0aXZlID09PSBmYWxzZSApIGNvbnRpbnVlO1xuXG5cdFx0XHRjb25zdCBnZW9tZXRyeUlkID0gZHJhd0luZm9bIGkgXS5nZW9tZXRyeUluZGV4O1xuXHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX21hdHJpeCQxICk7XG5cdFx0XHR0aGlzLmdldEJvdW5kaW5nQm94QXQoIGdlb21ldHJ5SWQsIF9ib3gkMSApLmFwcGx5TWF0cml4NCggX21hdHJpeCQxICk7XG5cdFx0XHRib3VuZGluZ0JveC51bmlvbiggX2JveCQxICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpIHtcblxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG5ldyBTcGhlcmUoKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGJvdW5kaW5nU3BoZXJlID0gdGhpcy5ib3VuZGluZ1NwaGVyZTtcblx0XHRjb25zdCBkcmF3SW5mbyA9IHRoaXMuX2RyYXdJbmZvO1xuXG5cdFx0Ym91bmRpbmdTcGhlcmUubWFrZUVtcHR5KCk7XG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZHJhd0luZm8ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0aWYgKCBkcmF3SW5mb1sgaSBdLmFjdGl2ZSA9PT0gZmFsc2UgKSBjb250aW51ZTtcblxuXHRcdFx0Y29uc3QgZ2VvbWV0cnlJZCA9IGRyYXdJbmZvWyBpIF0uZ2VvbWV0cnlJbmRleDtcblx0XHRcdHRoaXMuZ2V0TWF0cml4QXQoIGksIF9tYXRyaXgkMSApO1xuXHRcdFx0dGhpcy5nZXRCb3VuZGluZ1NwaGVyZUF0KCBnZW9tZXRyeUlkLCBfc3BoZXJlJDIgKS5hcHBseU1hdHJpeDQoIF9tYXRyaXgkMSApO1xuXHRcdFx0Ym91bmRpbmdTcGhlcmUudW5pb24oIF9zcGhlcmUkMiApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRhZGRJbnN0YW5jZSggZ2VvbWV0cnlJZCApIHtcblxuXHRcdC8vIGVuc3VyZSB3ZSdyZSBub3Qgb3ZlciBnZW9tZXRyeVxuXHRcdGlmICggdGhpcy5fZHJhd0luZm8ubGVuZ3RoID49IHRoaXMuX21heEluc3RhbmNlQ291bnQgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBNYXhpbXVtIGl0ZW0gY291bnQgcmVhY2hlZC4nICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLl9kcmF3SW5mby5wdXNoKCB7XG5cblx0XHRcdHZpc2libGU6IHRydWUsXG5cdFx0XHRhY3RpdmU6IHRydWUsXG5cdFx0XHRnZW9tZXRyeUluZGV4OiBnZW9tZXRyeUlkLFxuXG5cdFx0fSApO1xuXG5cdFx0Ly8gaW5pdGlhbGl6ZSB0aGUgbWF0cml4XG5cdFx0Y29uc3QgZHJhd0lkID0gdGhpcy5fZHJhd0luZm8ubGVuZ3RoIC0gMTtcblx0XHRjb25zdCBtYXRyaWNlc1RleHR1cmUgPSB0aGlzLl9tYXRyaWNlc1RleHR1cmU7XG5cdFx0Y29uc3QgbWF0cmljZXNBcnJheSA9IG1hdHJpY2VzVGV4dHVyZS5pbWFnZS5kYXRhO1xuXHRcdF9pZGVudGl0eU1hdHJpeC50b0FycmF5KCBtYXRyaWNlc0FycmF5LCBkcmF3SWQgKiAxNiApO1xuXHRcdG1hdHJpY2VzVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRjb25zdCBjb2xvcnNUZXh0dXJlID0gdGhpcy5fY29sb3JzVGV4dHVyZTtcblx0XHRpZiAoIGNvbG9yc1RleHR1cmUgKSB7XG5cblx0XHRcdF93aGl0ZUNvbG9yLnRvQXJyYXkoIGNvbG9yc1RleHR1cmUuaW1hZ2UuZGF0YSwgZHJhd0lkICogNCApO1xuXHRcdFx0Y29sb3JzVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gZHJhd0lkO1xuXG5cdH1cblxuXHRhZGRHZW9tZXRyeSggZ2VvbWV0cnksIHZlcnRleENvdW50ID0gLSAxLCBpbmRleENvdW50ID0gLSAxICkge1xuXG5cdFx0dGhpcy5faW5pdGlhbGl6ZUdlb21ldHJ5KCBnZW9tZXRyeSApO1xuXG5cdFx0dGhpcy5fdmFsaWRhdGVHZW9tZXRyeSggZ2VvbWV0cnkgKTtcblxuXHRcdC8vIGVuc3VyZSB3ZSdyZSBub3Qgb3ZlciBnZW9tZXRyeVxuXHRcdGlmICggdGhpcy5fZHJhd0luZm8ubGVuZ3RoID49IHRoaXMuX21heEluc3RhbmNlQ291bnQgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBNYXhpbXVtIGl0ZW0gY291bnQgcmVhY2hlZC4nICk7XG5cblx0XHR9XG5cblx0XHQvLyBnZXQgdGhlIG5lY2Vzc2FyeSByYW5nZSBmbyB0aGUgZ2VvbWV0cnlcblx0XHRjb25zdCByZXNlcnZlZFJhbmdlID0ge1xuXHRcdFx0dmVydGV4U3RhcnQ6IC0gMSxcblx0XHRcdHZlcnRleENvdW50OiAtIDEsXG5cdFx0XHRpbmRleFN0YXJ0OiAtIDEsXG5cdFx0XHRpbmRleENvdW50OiAtIDEsXG5cdFx0fTtcblxuXHRcdGxldCBsYXN0UmFuZ2UgPSBudWxsO1xuXHRcdGNvbnN0IHJlc2VydmVkUmFuZ2VzID0gdGhpcy5fcmVzZXJ2ZWRSYW5nZXM7XG5cdFx0Y29uc3QgZHJhd1JhbmdlcyA9IHRoaXMuX2RyYXdSYW5nZXM7XG5cdFx0Y29uc3QgYm91bmRzID0gdGhpcy5fYm91bmRzO1xuXHRcdGlmICggdGhpcy5fZ2VvbWV0cnlDb3VudCAhPT0gMCApIHtcblxuXHRcdFx0bGFzdFJhbmdlID0gcmVzZXJ2ZWRSYW5nZXNbIHJlc2VydmVkUmFuZ2VzLmxlbmd0aCAtIDEgXTtcblxuXHRcdH1cblxuXHRcdGlmICggdmVydGV4Q291bnQgPT09IC0gMSApIHtcblxuXHRcdFx0cmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhDb3VudCA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApLmNvdW50O1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhDb3VudCA9IHZlcnRleENvdW50O1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBsYXN0UmFuZ2UgPT09IG51bGwgKSB7XG5cblx0XHRcdHJlc2VydmVkUmFuZ2UudmVydGV4U3RhcnQgPSAwO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhTdGFydCA9IGxhc3RSYW5nZS52ZXJ0ZXhTdGFydCArIGxhc3RSYW5nZS52ZXJ0ZXhDb3VudDtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGluZGV4ID0gZ2VvbWV0cnkuZ2V0SW5kZXgoKTtcblx0XHRjb25zdCBoYXNJbmRleCA9IGluZGV4ICE9PSBudWxsO1xuXHRcdGlmICggaGFzSW5kZXggKSB7XG5cblx0XHRcdGlmICggaW5kZXhDb3VudFx0PT09IC0gMSApIHtcblxuXHRcdFx0XHRyZXNlcnZlZFJhbmdlLmluZGV4Q291bnQgPSBpbmRleC5jb3VudDtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRyZXNlcnZlZFJhbmdlLmluZGV4Q291bnQgPSBpbmRleENvdW50O1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggbGFzdFJhbmdlID09PSBudWxsICkge1xuXG5cdFx0XHRcdHJlc2VydmVkUmFuZ2UuaW5kZXhTdGFydCA9IDA7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0cmVzZXJ2ZWRSYW5nZS5pbmRleFN0YXJ0ID0gbGFzdFJhbmdlLmluZGV4U3RhcnQgKyBsYXN0UmFuZ2UuaW5kZXhDb3VudDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKFxuXHRcdFx0cmVzZXJ2ZWRSYW5nZS5pbmRleFN0YXJ0ICE9PSAtIDEgJiZcblx0XHRcdHJlc2VydmVkUmFuZ2UuaW5kZXhTdGFydCArIHJlc2VydmVkUmFuZ2UuaW5kZXhDb3VudCA+IHRoaXMuX21heEluZGV4Q291bnQgfHxcblx0XHRcdHJlc2VydmVkUmFuZ2UudmVydGV4U3RhcnQgKyByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50ID4gdGhpcy5fbWF4VmVydGV4Q291bnRcblx0XHQpIHtcblxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnQmF0Y2hlZE1lc2g6IFJlc2VydmVkIHNwYWNlIHJlcXVlc3QgZXhjZWVkcyB0aGUgbWF4aW11bSBidWZmZXIgc2l6ZS4nICk7XG5cblx0XHR9XG5cblx0XHQvLyB1cGRhdGUgaWRcblx0XHRjb25zdCBnZW9tZXRyeUlkID0gdGhpcy5fZ2VvbWV0cnlDb3VudDtcblx0XHR0aGlzLl9nZW9tZXRyeUNvdW50ICsrO1xuXG5cdFx0Ly8gYWRkIHRoZSByZXNlcnZlZCByYW5nZSBhbmQgZHJhdyByYW5nZSBvYmplY3RzXG5cdFx0cmVzZXJ2ZWRSYW5nZXMucHVzaCggcmVzZXJ2ZWRSYW5nZSApO1xuXHRcdGRyYXdSYW5nZXMucHVzaCgge1xuXHRcdFx0c3RhcnQ6IGhhc0luZGV4ID8gcmVzZXJ2ZWRSYW5nZS5pbmRleFN0YXJ0IDogcmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhTdGFydCxcblx0XHRcdGNvdW50OiAtIDFcblx0XHR9ICk7XG5cdFx0Ym91bmRzLnB1c2goIHtcblx0XHRcdGJveEluaXRpYWxpemVkOiBmYWxzZSxcblx0XHRcdGJveDogbmV3IEJveDMoKSxcblxuXHRcdFx0c3BoZXJlSW5pdGlhbGl6ZWQ6IGZhbHNlLFxuXHRcdFx0c3BoZXJlOiBuZXcgU3BoZXJlKClcblx0XHR9ICk7XG5cblx0XHQvLyB1cGRhdGUgdGhlIGdlb21ldHJ5XG5cdFx0dGhpcy5zZXRHZW9tZXRyeUF0KCBnZW9tZXRyeUlkLCBnZW9tZXRyeSApO1xuXG5cdFx0cmV0dXJuIGdlb21ldHJ5SWQ7XG5cblx0fVxuXG5cdHNldEdlb21ldHJ5QXQoIGdlb21ldHJ5SWQsIGdlb21ldHJ5ICkge1xuXG5cdFx0aWYgKCBnZW9tZXRyeUlkID49IHRoaXMuX2dlb21ldHJ5Q291bnQgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBNYXhpbXVtIGdlb21ldHJ5IGNvdW50IHJlYWNoZWQuJyApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5fdmFsaWRhdGVHZW9tZXRyeSggZ2VvbWV0cnkgKTtcblxuXHRcdGNvbnN0IGJhdGNoR2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGNvbnN0IGhhc0luZGV4ID0gYmF0Y2hHZW9tZXRyeS5nZXRJbmRleCgpICE9PSBudWxsO1xuXHRcdGNvbnN0IGRzdEluZGV4ID0gYmF0Y2hHZW9tZXRyeS5nZXRJbmRleCgpO1xuXHRcdGNvbnN0IHNyY0luZGV4ID0gZ2VvbWV0cnkuZ2V0SW5kZXgoKTtcblx0XHRjb25zdCByZXNlcnZlZFJhbmdlID0gdGhpcy5fcmVzZXJ2ZWRSYW5nZXNbIGdlb21ldHJ5SWQgXTtcblx0XHRpZiAoXG5cdFx0XHRoYXNJbmRleCAmJlxuXHRcdFx0c3JjSW5kZXguY291bnQgPiByZXNlcnZlZFJhbmdlLmluZGV4Q291bnQgfHxcblx0XHRcdGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24uY291bnQgPiByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50XG5cdFx0KSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBSZXNlcnZlZCBzcGFjZSBub3QgbGFyZ2UgZW5vdWdoIGZvciBwcm92aWRlZCBnZW9tZXRyeS4nICk7XG5cblx0XHR9XG5cblx0XHQvLyBjb3B5IGdlb21ldHJ5IG92ZXJcblx0XHRjb25zdCB2ZXJ0ZXhTdGFydCA9IHJlc2VydmVkUmFuZ2UudmVydGV4U3RhcnQ7XG5cdFx0Y29uc3QgdmVydGV4Q291bnQgPSByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50O1xuXHRcdGZvciAoIGNvbnN0IGF0dHJpYnV0ZU5hbWUgaW4gYmF0Y2hHZW9tZXRyeS5hdHRyaWJ1dGVzICkge1xuXG5cdFx0XHQvLyBjb3B5IGF0dHJpYnV0ZSBkYXRhXG5cdFx0XHRjb25zdCBzcmNBdHRyaWJ1dGUgPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUgKTtcblx0XHRcdGNvbnN0IGRzdEF0dHJpYnV0ZSA9IGJhdGNoR2VvbWV0cnkuZ2V0QXR0cmlidXRlKCBhdHRyaWJ1dGVOYW1lICk7XG5cdFx0XHRjb3B5QXR0cmlidXRlRGF0YSggc3JjQXR0cmlidXRlLCBkc3RBdHRyaWJ1dGUsIHZlcnRleFN0YXJ0ICk7XG5cblx0XHRcdC8vIGZpbGwgdGhlIHJlc3QgaW4gd2l0aCB6ZXJvZXNcblx0XHRcdGNvbnN0IGl0ZW1TaXplID0gc3JjQXR0cmlidXRlLml0ZW1TaXplO1xuXHRcdFx0Zm9yICggbGV0IGkgPSBzcmNBdHRyaWJ1dGUuY291bnQsIGwgPSB2ZXJ0ZXhDb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgaW5kZXggPSB2ZXJ0ZXhTdGFydCArIGk7XG5cdFx0XHRcdGZvciAoIGxldCBjID0gMDsgYyA8IGl0ZW1TaXplOyBjICsrICkge1xuXG5cdFx0XHRcdFx0ZHN0QXR0cmlidXRlLnNldENvbXBvbmVudCggaW5kZXgsIGMsIDAgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0ZHN0QXR0cmlidXRlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblx0XHRcdGRzdEF0dHJpYnV0ZS5hZGRVcGRhdGVSYW5nZSggdmVydGV4U3RhcnQgKiBpdGVtU2l6ZSwgdmVydGV4Q291bnQgKiBpdGVtU2l6ZSApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gY29weSBpbmRleFxuXHRcdGlmICggaGFzSW5kZXggKSB7XG5cblx0XHRcdGNvbnN0IGluZGV4U3RhcnQgPSByZXNlcnZlZFJhbmdlLmluZGV4U3RhcnQ7XG5cblx0XHRcdC8vIGNvcHkgaW5kZXggZGF0YSBvdmVyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzcmNJbmRleC5jb3VudDsgaSArKyApIHtcblxuXHRcdFx0XHRkc3RJbmRleC5zZXRYKCBpbmRleFN0YXJ0ICsgaSwgdmVydGV4U3RhcnQgKyBzcmNJbmRleC5nZXRYKCBpICkgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBmaWxsIHRoZSByZXN0IGluIHdpdGggemVyb2VzXG5cdFx0XHRmb3IgKCBsZXQgaSA9IHNyY0luZGV4LmNvdW50LCBsID0gcmVzZXJ2ZWRSYW5nZS5pbmRleENvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRkc3RJbmRleC5zZXRYKCBpbmRleFN0YXJ0ICsgaSwgdmVydGV4U3RhcnQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRkc3RJbmRleC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0XHRkc3RJbmRleC5hZGRVcGRhdGVSYW5nZSggaW5kZXhTdGFydCwgcmVzZXJ2ZWRSYW5nZS5pbmRleENvdW50ICk7XG5cblx0XHR9XG5cblx0XHQvLyBzdG9yZSB0aGUgYm91bmRpbmcgYm94ZXNcblx0XHRjb25zdCBib3VuZCA9IHRoaXMuX2JvdW5kc1sgZ2VvbWV0cnlJZCBdO1xuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdCb3ggIT09IG51bGwgKSB7XG5cblx0XHRcdGJvdW5kLmJveC5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ0JveCApO1xuXHRcdFx0Ym91bmQuYm94SW5pdGlhbGl6ZWQgPSB0cnVlO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ym91bmQuYm94SW5pdGlhbGl6ZWQgPSBmYWxzZTtcblxuXHRcdH1cblxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgIT09IG51bGwgKSB7XG5cblx0XHRcdGJvdW5kLnNwaGVyZS5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSApO1xuXHRcdFx0Ym91bmQuc3BoZXJlSW5pdGlhbGl6ZWQgPSB0cnVlO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ym91bmQuc3BoZXJlSW5pdGlhbGl6ZWQgPSBmYWxzZTtcblxuXHRcdH1cblxuXHRcdC8vIHNldCBkcmF3UmFuZ2UgY291bnRcblx0XHRjb25zdCBkcmF3UmFuZ2UgPSB0aGlzLl9kcmF3UmFuZ2VzWyBnZW9tZXRyeUlkIF07XG5cdFx0Y29uc3QgcG9zQXR0ciA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApO1xuXHRcdGRyYXdSYW5nZS5jb3VudCA9IGhhc0luZGV4ID8gc3JjSW5kZXguY291bnQgOiBwb3NBdHRyLmNvdW50O1xuXHRcdHRoaXMuX3Zpc2liaWxpdHlDaGFuZ2VkID0gdHJ1ZTtcblxuXHRcdHJldHVybiBnZW9tZXRyeUlkO1xuXG5cdH1cblxuXHQvKlxuXHRkZWxldGVHZW9tZXRyeSggZ2VvbWV0cnlJZCApIHtcblxuXHRcdC8vIFRPRE86IGRlbGV0ZSBnZW9tZXRyeSBhbmQgYXNzb2NpYXRlZCBpbnN0YW5jZXNcblxuXHR9XG5cdCovXG5cblx0Lypcblx0ZGVsZXRlSW5zdGFuY2UoIGluc3RhbmNlSWQgKSB7XG5cblx0XHQvLyBOb3RlOiBVc2VyIG5lZWRzIHRvIGNhbGwgb3B0aW1pemUoKSBhZnRlcndhcmQgdG8gcGFjayB0aGUgZGF0YS5cblxuXHRcdGNvbnN0IGRyYXdJbmZvID0gdGhpcy5fZHJhd0luZm87XG5cdFx0aWYgKCBpbnN0YW5jZUlkID49IGRyYXdJbmZvLmxlbmd0aCB8fCBkcmF3SW5mb1sgaW5zdGFuY2VJZCBdLmFjdGl2ZSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fVxuXG5cdFx0ZHJhd0luZm9bIGluc3RhbmNlSWQgXS5hY3RpdmUgPSBmYWxzZTtcblx0XHR0aGlzLl92aXNpYmlsaXR5Q2hhbmdlZCA9IHRydWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cdCovXG5cblx0Ly8gZ2V0IGJvdW5kaW5nIGJveCBhbmQgY29tcHV0ZSBpdCBpZiBpdCBkb2Vzbid0IGV4aXN0XG5cdGdldEJvdW5kaW5nQm94QXQoIGdlb21ldHJ5SWQsIHRhcmdldCApIHtcblxuXHRcdGlmICggZ2VvbWV0cnlJZCA+PSB0aGlzLl9nZW9tZXRyeUNvdW50ICkge1xuXG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdC8vIGNvbXB1dGUgYm91bmRpbmcgYm94XG5cdFx0Y29uc3QgYm91bmQgPSB0aGlzLl9ib3VuZHNbIGdlb21ldHJ5SWQgXTtcblx0XHRjb25zdCBib3ggPSBib3VuZC5ib3g7XG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGlmICggYm91bmQuYm94SW5pdGlhbGl6ZWQgPT09IGZhbHNlICkge1xuXG5cdFx0XHRib3gubWFrZUVtcHR5KCk7XG5cblx0XHRcdGNvbnN0IGluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XG5cdFx0XHRjb25zdCBwb3NpdGlvbiA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb247XG5cdFx0XHRjb25zdCBkcmF3UmFuZ2UgPSB0aGlzLl9kcmF3UmFuZ2VzWyBnZW9tZXRyeUlkIF07XG5cdFx0XHRmb3IgKCBsZXQgaSA9IGRyYXdSYW5nZS5zdGFydCwgbCA9IGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0bGV0IGl2ID0gaTtcblx0XHRcdFx0aWYgKCBpbmRleCApIHtcblxuXHRcdFx0XHRcdGl2ID0gaW5kZXguZ2V0WCggaXYgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ym94LmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IkNS5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaXYgKSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGJvdW5kLmJveEluaXRpYWxpemVkID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdHRhcmdldC5jb3B5KCBib3ggKTtcblx0XHRyZXR1cm4gdGFyZ2V0O1xuXG5cdH1cblxuXHQvLyBnZXQgYm91bmRpbmcgc3BoZXJlIGFuZCBjb21wdXRlIGl0IGlmIGl0IGRvZXNuJ3QgZXhpc3Rcblx0Z2V0Qm91bmRpbmdTcGhlcmVBdCggZ2VvbWV0cnlJZCwgdGFyZ2V0ICkge1xuXG5cdFx0aWYgKCBnZW9tZXRyeUlkID49IHRoaXMuX2dlb21ldHJ5Q291bnQgKSB7XG5cblx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0fVxuXG5cdFx0Ly8gY29tcHV0ZSBib3VuZGluZyBzcGhlcmVcblx0XHRjb25zdCBib3VuZCA9IHRoaXMuX2JvdW5kc1sgZ2VvbWV0cnlJZCBdO1xuXHRcdGNvbnN0IHNwaGVyZSA9IGJvdW5kLnNwaGVyZTtcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cdFx0aWYgKCBib3VuZC5zcGhlcmVJbml0aWFsaXplZCA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdHNwaGVyZS5tYWtlRW1wdHkoKTtcblxuXHRcdFx0dGhpcy5nZXRCb3VuZGluZ0JveEF0KCBnZW9tZXRyeUlkLCBfYm94JDEgKTtcblx0XHRcdF9ib3gkMS5nZXRDZW50ZXIoIHNwaGVyZS5jZW50ZXIgKTtcblxuXHRcdFx0Y29uc3QgaW5kZXggPSBnZW9tZXRyeS5pbmRleDtcblx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcblx0XHRcdGNvbnN0IGRyYXdSYW5nZSA9IHRoaXMuX2RyYXdSYW5nZXNbIGdlb21ldHJ5SWQgXTtcblxuXHRcdFx0bGV0IG1heFJhZGl1c1NxID0gMDtcblx0XHRcdGZvciAoIGxldCBpID0gZHJhd1JhbmdlLnN0YXJ0LCBsID0gZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRsZXQgaXYgPSBpO1xuXHRcdFx0XHRpZiAoIGluZGV4ICkge1xuXG5cdFx0XHRcdFx0aXYgPSBpbmRleC5nZXRYKCBpdiApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRfdmVjdG9yJDUuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIGl2ICk7XG5cdFx0XHRcdG1heFJhZGl1c1NxID0gTWF0aC5tYXgoIG1heFJhZGl1c1NxLCBzcGhlcmUuY2VudGVyLmRpc3RhbmNlVG9TcXVhcmVkKCBfdmVjdG9yJDUgKSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHNwaGVyZS5yYWRpdXMgPSBNYXRoLnNxcnQoIG1heFJhZGl1c1NxICk7XG5cdFx0XHRib3VuZC5zcGhlcmVJbml0aWFsaXplZCA9IHRydWU7XG5cblx0XHR9XG5cblx0XHR0YXJnZXQuY29weSggc3BoZXJlICk7XG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0c2V0TWF0cml4QXQoIGluc3RhbmNlSWQsIG1hdHJpeCApIHtcblxuXHRcdC8vIEBUT0RPOiBNYXAgZ2VvbWV0cnlJZCB0byBpbmRleCBvZiB0aGUgYXJyYXlzIGJlY2F1c2Vcblx0XHQvLyAgICAgICAgb3B0aW1pemUoKSBjYW4gbWFrZSBnZW9tZXRyeUlkIG1pc21hdGNoIHRoZSBpbmRleFxuXG5cdFx0Y29uc3QgZHJhd0luZm8gPSB0aGlzLl9kcmF3SW5mbztcblx0XHRjb25zdCBtYXRyaWNlc1RleHR1cmUgPSB0aGlzLl9tYXRyaWNlc1RleHR1cmU7XG5cdFx0Y29uc3QgbWF0cmljZXNBcnJheSA9IHRoaXMuX21hdHJpY2VzVGV4dHVyZS5pbWFnZS5kYXRhO1xuXHRcdGlmICggaW5zdGFuY2VJZCA+PSBkcmF3SW5mby5sZW5ndGggfHwgZHJhd0luZm9bIGluc3RhbmNlSWQgXS5hY3RpdmUgPT09IGZhbHNlICkge1xuXG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH1cblxuXHRcdG1hdHJpeC50b0FycmF5KCBtYXRyaWNlc0FycmF5LCBpbnN0YW5jZUlkICogMTYgKTtcblx0XHRtYXRyaWNlc1RleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldE1hdHJpeEF0KCBpbnN0YW5jZUlkLCBtYXRyaXggKSB7XG5cblx0XHRjb25zdCBkcmF3SW5mbyA9IHRoaXMuX2RyYXdJbmZvO1xuXHRcdGNvbnN0IG1hdHJpY2VzQXJyYXkgPSB0aGlzLl9tYXRyaWNlc1RleHR1cmUuaW1hZ2UuZGF0YTtcblx0XHRpZiAoIGluc3RhbmNlSWQgPj0gZHJhd0luZm8ubGVuZ3RoIHx8IGRyYXdJbmZvWyBpbnN0YW5jZUlkIF0uYWN0aXZlID09PSBmYWxzZSApIHtcblxuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gbWF0cml4LmZyb21BcnJheSggbWF0cmljZXNBcnJheSwgaW5zdGFuY2VJZCAqIDE2ICk7XG5cblx0fVxuXG5cdHNldENvbG9yQXQoIGluc3RhbmNlSWQsIGNvbG9yICkge1xuXG5cdFx0aWYgKCB0aGlzLl9jb2xvcnNUZXh0dXJlID09PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl9pbml0Q29sb3JzVGV4dHVyZSgpO1xuXG5cdFx0fVxuXG5cdFx0Ly8gQFRPRE86IE1hcCBpZCB0byBpbmRleCBvZiB0aGUgYXJyYXlzIGJlY2F1c2Vcblx0XHQvLyAgICAgICAgb3B0aW1pemUoKSBjYW4gbWFrZSBpZCBtaXNtYXRjaCB0aGUgaW5kZXhcblxuXHRcdGNvbnN0IGNvbG9yc1RleHR1cmUgPSB0aGlzLl9jb2xvcnNUZXh0dXJlO1xuXHRcdGNvbnN0IGNvbG9yc0FycmF5ID0gdGhpcy5fY29sb3JzVGV4dHVyZS5pbWFnZS5kYXRhO1xuXHRcdGNvbnN0IGRyYXdJbmZvID0gdGhpcy5fZHJhd0luZm87XG5cdFx0aWYgKCBpbnN0YW5jZUlkID49IGRyYXdJbmZvLmxlbmd0aCB8fCBkcmF3SW5mb1sgaW5zdGFuY2VJZCBdLmFjdGl2ZSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fVxuXG5cdFx0Y29sb3IudG9BcnJheSggY29sb3JzQXJyYXksIGluc3RhbmNlSWQgKiA0ICk7XG5cdFx0Y29sb3JzVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0Q29sb3JBdCggaW5zdGFuY2VJZCwgY29sb3IgKSB7XG5cblx0XHRjb25zdCBjb2xvcnNBcnJheSA9IHRoaXMuX2NvbG9yc1RleHR1cmUuaW1hZ2UuZGF0YTtcblx0XHRjb25zdCBkcmF3SW5mbyA9IHRoaXMuX2RyYXdJbmZvO1xuXHRcdGlmICggaW5zdGFuY2VJZCA+PSBkcmF3SW5mby5sZW5ndGggfHwgZHJhd0luZm9bIGluc3RhbmNlSWQgXS5hY3RpdmUgPT09IGZhbHNlICkge1xuXG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdHJldHVybiBjb2xvci5mcm9tQXJyYXkoIGNvbG9yc0FycmF5LCBpbnN0YW5jZUlkICogNCApO1xuXG5cdH1cblxuXHRzZXRWaXNpYmxlQXQoIGluc3RhbmNlSWQsIHZhbHVlICkge1xuXG5cdFx0Ly8gaWYgdGhlIGdlb21ldHJ5IGlzIG91dCBvZiByYW5nZSwgbm90IGFjdGl2ZSwgb3IgdmlzaWJpbGl0eSBzdGF0ZVxuXHRcdC8vIGRvZXMgbm90IGNoYW5nZSB0aGVuIHJldHVybiBlYXJseVxuXHRcdGNvbnN0IGRyYXdJbmZvID0gdGhpcy5fZHJhd0luZm87XG5cdFx0aWYgKFxuXHRcdFx0aW5zdGFuY2VJZCA+PSBkcmF3SW5mby5sZW5ndGggfHxcblx0XHRcdGRyYXdJbmZvWyBpbnN0YW5jZUlkIF0uYWN0aXZlID09PSBmYWxzZSB8fFxuXHRcdFx0ZHJhd0luZm9bIGluc3RhbmNlSWQgXS52aXNpYmxlID09PSB2YWx1ZVxuXHRcdCkge1xuXG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH1cblxuXHRcdGRyYXdJbmZvWyBpbnN0YW5jZUlkIF0udmlzaWJsZSA9IHZhbHVlO1xuXHRcdHRoaXMuX3Zpc2liaWxpdHlDaGFuZ2VkID0gdHJ1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRWaXNpYmxlQXQoIGluc3RhbmNlSWQgKSB7XG5cblx0XHQvLyByZXR1cm4gZWFybHkgaWYgdGhlIGdlb21ldHJ5IGlzIG91dCBvZiByYW5nZSBvciBub3QgYWN0aXZlXG5cdFx0Y29uc3QgZHJhd0luZm8gPSB0aGlzLl9kcmF3SW5mbztcblx0XHRpZiAoIGluc3RhbmNlSWQgPj0gZHJhd0luZm8ubGVuZ3RoIHx8IGRyYXdJbmZvWyBpbnN0YW5jZUlkIF0uYWN0aXZlID09PSBmYWxzZSApIHtcblxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRyYXdJbmZvWyBpbnN0YW5jZUlkIF0udmlzaWJsZTtcblxuXHR9XG5cblx0cmF5Y2FzdCggcmF5Y2FzdGVyLCBpbnRlcnNlY3RzICkge1xuXG5cdFx0Y29uc3QgZHJhd0luZm8gPSB0aGlzLl9kcmF3SW5mbztcblx0XHRjb25zdCBkcmF3UmFuZ2VzID0gdGhpcy5fZHJhd1Jhbmdlcztcblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XG5cdFx0Y29uc3QgYmF0Y2hHZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cblx0XHQvLyBpdGVyYXRlIG92ZXIgZWFjaCBnZW9tZXRyeVxuXHRcdF9tZXNoLm1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbDtcblx0XHRfbWVzaC5nZW9tZXRyeS5pbmRleCA9IGJhdGNoR2VvbWV0cnkuaW5kZXg7XG5cdFx0X21lc2guZ2VvbWV0cnkuYXR0cmlidXRlcyA9IGJhdGNoR2VvbWV0cnkuYXR0cmlidXRlcztcblx0XHRpZiAoIF9tZXNoLmdlb21ldHJ5LmJvdW5kaW5nQm94ID09PSBudWxsICkge1xuXG5cdFx0XHRfbWVzaC5nZW9tZXRyeS5ib3VuZGluZ0JveCA9IG5ldyBCb3gzKCk7XG5cblx0XHR9XG5cblx0XHRpZiAoIF9tZXNoLmdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkge1xuXG5cdFx0XHRfbWVzaC5nZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9IG5ldyBTcGhlcmUoKTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGRyYXdJbmZvLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGlmICggISBkcmF3SW5mb1sgaSBdLnZpc2libGUgfHwgISBkcmF3SW5mb1sgaSBdLmFjdGl2ZSApIHtcblxuXHRcdFx0XHRjb250aW51ZTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBnZW9tZXRyeUlkID0gZHJhd0luZm9bIGkgXS5nZW9tZXRyeUluZGV4O1xuXHRcdFx0Y29uc3QgZHJhd1JhbmdlID0gZHJhd1Jhbmdlc1sgZ2VvbWV0cnlJZCBdO1xuXHRcdFx0X21lc2guZ2VvbWV0cnkuc2V0RHJhd1JhbmdlKCBkcmF3UmFuZ2Uuc3RhcnQsIGRyYXdSYW5nZS5jb3VudCApO1xuXG5cdFx0XHQvLyBnZSB0aGUgaW50ZXJzZWN0c1xuXHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX21lc2gubWF0cml4V29ybGQgKS5wcmVtdWx0aXBseSggbWF0cml4V29ybGQgKTtcblx0XHRcdHRoaXMuZ2V0Qm91bmRpbmdCb3hBdCggZ2VvbWV0cnlJZCwgX21lc2guZ2VvbWV0cnkuYm91bmRpbmdCb3ggKTtcblx0XHRcdHRoaXMuZ2V0Qm91bmRpbmdTcGhlcmVBdCggZ2VvbWV0cnlJZCwgX21lc2guZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgKTtcblx0XHRcdF9tZXNoLnJheWNhc3QoIHJheWNhc3RlciwgX2JhdGNoSW50ZXJzZWN0cyApO1xuXG5cdFx0XHQvLyBhZGQgYmF0Y2ggaWQgdG8gdGhlIGludGVyc2VjdHNcblx0XHRcdGZvciAoIGxldCBqID0gMCwgbCA9IF9iYXRjaEludGVyc2VjdHMubGVuZ3RoOyBqIDwgbDsgaiArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbnRlcnNlY3QgPSBfYmF0Y2hJbnRlcnNlY3RzWyBqIF07XG5cdFx0XHRcdGludGVyc2VjdC5vYmplY3QgPSB0aGlzO1xuXHRcdFx0XHRpbnRlcnNlY3QuYmF0Y2hJZCA9IGk7XG5cdFx0XHRcdGludGVyc2VjdHMucHVzaCggaW50ZXJzZWN0ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0X2JhdGNoSW50ZXJzZWN0cy5sZW5ndGggPSAwO1xuXG5cdFx0fVxuXG5cdFx0X21lc2gubWF0ZXJpYWwgPSBudWxsO1xuXHRcdF9tZXNoLmdlb21ldHJ5LmluZGV4ID0gbnVsbDtcblx0XHRfbWVzaC5nZW9tZXRyeS5hdHRyaWJ1dGVzID0ge307XG5cdFx0X21lc2guZ2VvbWV0cnkuc2V0RHJhd1JhbmdlKCAwLCBJbmZpbml0eSApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuZ2VvbWV0cnkgPSBzb3VyY2UuZ2VvbWV0cnkuY2xvbmUoKTtcblx0XHR0aGlzLnBlck9iamVjdEZydXN0dW1DdWxsZWQgPSBzb3VyY2UucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZDtcblx0XHR0aGlzLnNvcnRPYmplY3RzID0gc291cmNlLnNvcnRPYmplY3RzO1xuXHRcdHRoaXMuYm91bmRpbmdCb3ggPSBzb3VyY2UuYm91bmRpbmdCb3ggIT09IG51bGwgPyBzb3VyY2UuYm91bmRpbmdCb3guY2xvbmUoKSA6IG51bGw7XG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IHNvdXJjZS5ib3VuZGluZ1NwaGVyZSAhPT0gbnVsbCA/IHNvdXJjZS5ib3VuZGluZ1NwaGVyZS5jbG9uZSgpIDogbnVsbDtcblxuXHRcdHRoaXMuX2RyYXdSYW5nZXMgPSBzb3VyY2UuX2RyYXdSYW5nZXMubWFwKCByYW5nZSA9PiAoIHsgLi4ucmFuZ2UgfSApICk7XG5cdFx0dGhpcy5fcmVzZXJ2ZWRSYW5nZXMgPSBzb3VyY2UuX3Jlc2VydmVkUmFuZ2VzLm1hcCggcmFuZ2UgPT4gKCB7IC4uLnJhbmdlIH0gKSApO1xuXG5cdFx0dGhpcy5fZHJhd0luZm8gPSBzb3VyY2UuX2RyYXdJbmZvLm1hcCggaW5mID0+ICggeyAuLi5pbmYgfSApICk7XG5cdFx0dGhpcy5fYm91bmRzID0gc291cmNlLl9ib3VuZHMubWFwKCBib3VuZCA9PiAoIHtcblx0XHRcdGJveEluaXRpYWxpemVkOiBib3VuZC5ib3hJbml0aWFsaXplZCxcblx0XHRcdGJveDogYm91bmQuYm94LmNsb25lKCksXG5cblx0XHRcdHNwaGVyZUluaXRpYWxpemVkOiBib3VuZC5zcGhlcmVJbml0aWFsaXplZCxcblx0XHRcdHNwaGVyZTogYm91bmQuc3BoZXJlLmNsb25lKClcblx0XHR9ICkgKTtcblxuXHRcdHRoaXMuX21heEluc3RhbmNlQ291bnQgPSBzb3VyY2UuX21heEluc3RhbmNlQ291bnQ7XG5cdFx0dGhpcy5fbWF4VmVydGV4Q291bnQgPSBzb3VyY2UuX21heFZlcnRleENvdW50O1xuXHRcdHRoaXMuX21heEluZGV4Q291bnQgPSBzb3VyY2UuX21heEluZGV4Q291bnQ7XG5cblx0XHR0aGlzLl9nZW9tZXRyeUluaXRpYWxpemVkID0gc291cmNlLl9nZW9tZXRyeUluaXRpYWxpemVkO1xuXHRcdHRoaXMuX2dlb21ldHJ5Q291bnQgPSBzb3VyY2UuX2dlb21ldHJ5Q291bnQ7XG5cdFx0dGhpcy5fbXVsdGlEcmF3Q291bnRzID0gc291cmNlLl9tdWx0aURyYXdDb3VudHMuc2xpY2UoKTtcblx0XHR0aGlzLl9tdWx0aURyYXdTdGFydHMgPSBzb3VyY2UuX211bHRpRHJhd1N0YXJ0cy5zbGljZSgpO1xuXG5cdFx0dGhpcy5fbWF0cmljZXNUZXh0dXJlID0gc291cmNlLl9tYXRyaWNlc1RleHR1cmUuY2xvbmUoKTtcblx0XHR0aGlzLl9tYXRyaWNlc1RleHR1cmUuaW1hZ2UuZGF0YSA9IHRoaXMuX21hdHJpY2VzVGV4dHVyZS5pbWFnZS5zbGljZSgpO1xuXG5cdFx0aWYgKCB0aGlzLl9jb2xvcnNUZXh0dXJlICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl9jb2xvcnNUZXh0dXJlID0gc291cmNlLl9jb2xvcnNUZXh0dXJlLmNsb25lKCk7XG5cdFx0XHR0aGlzLl9jb2xvcnNUZXh0dXJlLmltYWdlLmRhdGEgPSB0aGlzLl9jb2xvcnNUZXh0dXJlLmltYWdlLnNsaWNlKCk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdC8vIEFzc3VtaW5nIHRoZSBnZW9tZXRyeSBpcyBub3Qgc2hhcmVkIHdpdGggb3RoZXIgbWVzaGVzXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cblx0XHR0aGlzLl9tYXRyaWNlc1RleHR1cmUuZGlzcG9zZSgpO1xuXHRcdHRoaXMuX21hdHJpY2VzVGV4dHVyZSA9IG51bGw7XG5cblx0XHR0aGlzLl9pbmRpcmVjdFRleHR1cmUuZGlzcG9zZSgpO1xuXHRcdHRoaXMuX2luZGlyZWN0VGV4dHVyZSA9IG51bGw7XG5cblx0XHRpZiAoIHRoaXMuX2NvbG9yc1RleHR1cmUgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX2NvbG9yc1RleHR1cmUuZGlzcG9zZSgpO1xuXHRcdFx0dGhpcy5fY29sb3JzVGV4dHVyZSA9IG51bGw7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0b25CZWZvcmVSZW5kZXIoIHJlbmRlcmVyLCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwvKiwgX2dyb3VwKi8gKSB7XG5cblx0XHQvLyBpZiB2aXNpYmlsaXR5IGhhcyBub3QgY2hhbmdlZCBhbmQgZnJ1c3R1bSBjdWxsaW5nIGFuZCBvYmplY3Qgc29ydGluZyBpcyBub3QgcmVxdWlyZWRcblx0XHQvLyB0aGVuIHNraXAgaXRlcmF0aW5nIG92ZXIgYWxsIGl0ZW1zXG5cdFx0aWYgKCAhIHRoaXMuX3Zpc2liaWxpdHlDaGFuZ2VkICYmICEgdGhpcy5wZXJPYmplY3RGcnVzdHVtQ3VsbGVkICYmICEgdGhpcy5zb3J0T2JqZWN0cyApIHtcblxuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0Ly8gdGhlIGluZGV4ZWQgdmVyc2lvbiBvZiB0aGUgbXVsdGkgZHJhdyBmdW5jdGlvbiByZXF1aXJlcyBzcGVjaWZ5aW5nIHRoZSBzdGFydFxuXHRcdC8vIG9mZnNldCBpbiBieXRlcy5cblx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmdldEluZGV4KCk7XG5cdFx0Y29uc3QgYnl0ZXNQZXJFbGVtZW50ID0gaW5kZXggPT09IG51bGwgPyAxIDogaW5kZXguYXJyYXkuQllURVNfUEVSX0VMRU1FTlQ7XG5cblx0XHRjb25zdCBkcmF3SW5mbyA9IHRoaXMuX2RyYXdJbmZvO1xuXHRcdGNvbnN0IG11bHRpRHJhd1N0YXJ0cyA9IHRoaXMuX211bHRpRHJhd1N0YXJ0cztcblx0XHRjb25zdCBtdWx0aURyYXdDb3VudHMgPSB0aGlzLl9tdWx0aURyYXdDb3VudHM7XG5cdFx0Y29uc3QgZHJhd1JhbmdlcyA9IHRoaXMuX2RyYXdSYW5nZXM7XG5cdFx0Y29uc3QgcGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCA9IHRoaXMucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZDtcblx0XHRjb25zdCBpbmRpcmVjdFRleHR1cmUgPSB0aGlzLl9pbmRpcmVjdFRleHR1cmU7XG5cdFx0Y29uc3QgaW5kaXJlY3RBcnJheSA9IGluZGlyZWN0VGV4dHVyZS5pbWFnZS5kYXRhO1xuXG5cdFx0Ly8gcHJlcGFyZSB0aGUgZnJ1c3R1bSBpbiB0aGUgbG9jYWwgZnJhbWVcblx0XHRpZiAoIHBlck9iamVjdEZydXN0dW1DdWxsZWQgKSB7XG5cblx0XHRcdF9wcm9qU2NyZWVuTWF0cml4JDJcblx0XHRcdFx0Lm11bHRpcGx5TWF0cmljZXMoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LCBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlIClcblx0XHRcdFx0Lm11bHRpcGx5KCB0aGlzLm1hdHJpeFdvcmxkICk7XG5cdFx0XHRfZnJ1c3R1bS5zZXRGcm9tUHJvamVjdGlvbk1hdHJpeChcblx0XHRcdFx0X3Byb2pTY3JlZW5NYXRyaXgkMixcblx0XHRcdFx0cmVuZGVyZXIuY29vcmRpbmF0ZVN5c3RlbVxuXHRcdFx0KTtcblxuXHRcdH1cblxuXHRcdGxldCBjb3VudCA9IDA7XG5cdFx0aWYgKCB0aGlzLnNvcnRPYmplY3RzICkge1xuXG5cdFx0XHQvLyBnZXQgdGhlIGNhbWVyYSBwb3NpdGlvbiBpbiB0aGUgbG9jYWwgZnJhbWVcblx0XHRcdF9pbnZNYXRyaXhXb3JsZC5jb3B5KCB0aGlzLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cdFx0XHRfdmVjdG9yJDUuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBjYW1lcmEubWF0cml4V29ybGQgKS5hcHBseU1hdHJpeDQoIF9pbnZNYXRyaXhXb3JsZCApO1xuXHRcdFx0X2ZvcndhcmQuc2V0KCAwLCAwLCAtIDEgKS50cmFuc2Zvcm1EaXJlY3Rpb24oIGNhbWVyYS5tYXRyaXhXb3JsZCApLnRyYW5zZm9ybURpcmVjdGlvbiggX2ludk1hdHJpeFdvcmxkICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGRyYXdJbmZvLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0aWYgKCBkcmF3SW5mb1sgaSBdLnZpc2libGUgJiYgZHJhd0luZm9bIGkgXS5hY3RpdmUgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBnZW9tZXRyeUlkID0gZHJhd0luZm9bIGkgXS5nZW9tZXRyeUluZGV4O1xuXG5cdFx0XHRcdFx0Ly8gZ2V0IHRoZSBib3VuZHMgaW4gd29ybGQgc3BhY2Vcblx0XHRcdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpLCBfbWF0cml4JDEgKTtcblx0XHRcdFx0XHR0aGlzLmdldEJvdW5kaW5nU3BoZXJlQXQoIGdlb21ldHJ5SWQsIF9zcGhlcmUkMiApLmFwcGx5TWF0cml4NCggX21hdHJpeCQxICk7XG5cblx0XHRcdFx0XHQvLyBkZXRlcm1pbmUgd2hldGhlciB0aGUgYmF0Y2hlZCBnZW9tZXRyeSBpcyB3aXRoaW4gdGhlIGZydXN0dW1cblx0XHRcdFx0XHRsZXQgY3VsbGVkID0gZmFsc2U7XG5cdFx0XHRcdFx0aWYgKCBwZXJPYmplY3RGcnVzdHVtQ3VsbGVkICkge1xuXG5cdFx0XHRcdFx0XHRjdWxsZWQgPSAhIF9mcnVzdHVtLmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUkMiApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCAhIGN1bGxlZCApIHtcblxuXHRcdFx0XHRcdFx0Ly8gZ2V0IHRoZSBkaXN0YW5jZSBmcm9tIGNhbWVyYSB1c2VkIGZvciBzb3J0aW5nXG5cdFx0XHRcdFx0XHRjb25zdCB6ID0gX3RlbXAuc3ViVmVjdG9ycyggX3NwaGVyZSQyLmNlbnRlciwgX3ZlY3RvciQ1ICkuZG90KCBfZm9yd2FyZCApO1xuXHRcdFx0XHRcdFx0X3JlbmRlckxpc3QucHVzaCggZHJhd1Jhbmdlc1sgZ2VvbWV0cnlJZCBdLCB6LCBpICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdC8vIFNvcnQgdGhlIGRyYXcgcmFuZ2VzIGFuZCBwcmVwIGZvciByZW5kZXJpbmdcblx0XHRcdGNvbnN0IGxpc3QgPSBfcmVuZGVyTGlzdC5saXN0O1xuXHRcdFx0Y29uc3QgY3VzdG9tU29ydCA9IHRoaXMuY3VzdG9tU29ydDtcblx0XHRcdGlmICggY3VzdG9tU29ydCA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRsaXN0LnNvcnQoIG1hdGVyaWFsLnRyYW5zcGFyZW50ID8gc29ydFRyYW5zcGFyZW50IDogc29ydE9wYXF1ZSApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGN1c3RvbVNvcnQuY2FsbCggdGhpcywgbGlzdCwgY2FtZXJhICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gbGlzdC5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGl0ZW0gPSBsaXN0WyBpIF07XG5cdFx0XHRcdG11bHRpRHJhd1N0YXJ0c1sgY291bnQgXSA9IGl0ZW0uc3RhcnQgKiBieXRlc1BlckVsZW1lbnQ7XG5cdFx0XHRcdG11bHRpRHJhd0NvdW50c1sgY291bnQgXSA9IGl0ZW0uY291bnQ7XG5cdFx0XHRcdGluZGlyZWN0QXJyYXlbIGNvdW50IF0gPSBpdGVtLmluZGV4O1xuXHRcdFx0XHRjb3VudCArKztcblxuXHRcdFx0fVxuXG5cdFx0XHRfcmVuZGVyTGlzdC5yZXNldCgpO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZHJhd0luZm8ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRpZiAoIGRyYXdJbmZvWyBpIF0udmlzaWJsZSAmJiBkcmF3SW5mb1sgaSBdLmFjdGl2ZSApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGdlb21ldHJ5SWQgPSBkcmF3SW5mb1sgaSBdLmdlb21ldHJ5SW5kZXg7XG5cblx0XHRcdFx0XHQvLyBkZXRlcm1pbmUgd2hldGhlciB0aGUgYmF0Y2hlZCBnZW9tZXRyeSBpcyB3aXRoaW4gdGhlIGZydXN0dW1cblx0XHRcdFx0XHRsZXQgY3VsbGVkID0gZmFsc2U7XG5cdFx0XHRcdFx0aWYgKCBwZXJPYmplY3RGcnVzdHVtQ3VsbGVkICkge1xuXG5cdFx0XHRcdFx0XHQvLyBnZXQgdGhlIGJvdW5kcyBpbiB3b3JsZCBzcGFjZVxuXHRcdFx0XHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX21hdHJpeCQxICk7XG5cdFx0XHRcdFx0XHR0aGlzLmdldEJvdW5kaW5nU3BoZXJlQXQoIGdlb21ldHJ5SWQsIF9zcGhlcmUkMiApLmFwcGx5TWF0cml4NCggX21hdHJpeCQxICk7XG5cdFx0XHRcdFx0XHRjdWxsZWQgPSAhIF9mcnVzdHVtLmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUkMiApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCAhIGN1bGxlZCApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgcmFuZ2UgPSBkcmF3UmFuZ2VzWyBnZW9tZXRyeUlkIF07XG5cdFx0XHRcdFx0XHRtdWx0aURyYXdTdGFydHNbIGNvdW50IF0gPSByYW5nZS5zdGFydCAqIGJ5dGVzUGVyRWxlbWVudDtcblx0XHRcdFx0XHRcdG11bHRpRHJhd0NvdW50c1sgY291bnQgXSA9IHJhbmdlLmNvdW50O1xuXHRcdFx0XHRcdFx0aW5kaXJlY3RBcnJheVsgY291bnQgXSA9IGk7XG5cdFx0XHRcdFx0XHRjb3VudCArKztcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGluZGlyZWN0VGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0dGhpcy5fbXVsdGlEcmF3Q291bnQgPSBjb3VudDtcblx0XHR0aGlzLl92aXNpYmlsaXR5Q2hhbmdlZCA9IGZhbHNlO1xuXG5cdH1cblxuXHRvbkJlZm9yZVNoYWRvdyggcmVuZGVyZXIsIG9iamVjdCwgY2FtZXJhLCBzaGFkb3dDYW1lcmEsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsLyogLCBncm91cCAqLyApIHtcblxuXHRcdHRoaXMub25CZWZvcmVSZW5kZXIoIHJlbmRlcmVyLCBudWxsLCBzaGFkb3dDYW1lcmEsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIExpbmVCYXNpY01hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNMaW5lQmFzaWNNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnTGluZUJhc2ljTWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHhmZmZmZmYgKTtcblxuXHRcdHRoaXMubWFwID0gbnVsbDtcblxuXHRcdHRoaXMubGluZXdpZHRoID0gMTtcblx0XHR0aGlzLmxpbmVjYXAgPSAncm91bmQnO1xuXHRcdHRoaXMubGluZWpvaW4gPSAncm91bmQnO1xuXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xuXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcblxuXHR9XG5cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XG5cblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XG5cblx0XHR0aGlzLmxpbmV3aWR0aCA9IHNvdXJjZS5saW5ld2lkdGg7XG5cdFx0dGhpcy5saW5lY2FwID0gc291cmNlLmxpbmVjYXA7XG5cdFx0dGhpcy5saW5lam9pbiA9IHNvdXJjZS5saW5lam9pbjtcblxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jb25zdCBfdlN0YXJ0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3ZFbmQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNvbnN0IF9pbnZlcnNlTWF0cml4JDEgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfcmF5JDEgPSAvKkBfX1BVUkVfXyovIG5ldyBSYXkoKTtcbmNvbnN0IF9zcGhlcmUkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFNwaGVyZSgpO1xuXG5jb25zdCBfaW50ZXJzZWN0UG9pbnRPblJheSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9pbnRlcnNlY3RQb2ludE9uU2VnbWVudCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgTGluZSBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKSwgbWF0ZXJpYWwgPSBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoKSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTGluZSA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnTGluZSc7XG5cblx0XHR0aGlzLmdlb21ldHJ5ID0gZ2VvbWV0cnk7XG5cdFx0dGhpcy5tYXRlcmlhbCA9IG1hdGVyaWFsO1xuXG5cdFx0dGhpcy51cGRhdGVNb3JwaFRhcmdldHMoKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0dGhpcy5tYXRlcmlhbCA9IEFycmF5LmlzQXJyYXkoIHNvdXJjZS5tYXRlcmlhbCApID8gc291cmNlLm1hdGVyaWFsLnNsaWNlKCkgOiBzb3VyY2UubWF0ZXJpYWw7XG5cdFx0dGhpcy5nZW9tZXRyeSA9IHNvdXJjZS5nZW9tZXRyeTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb21wdXRlTGluZURpc3RhbmNlcygpIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcblxuXHRcdC8vIHdlIGFzc3VtZSBub24taW5kZXhlZCBnZW9tZXRyeVxuXG5cdFx0aWYgKCBnZW9tZXRyeS5pbmRleCA9PT0gbnVsbCApIHtcblxuXHRcdFx0Y29uc3QgcG9zaXRpb25BdHRyaWJ1dGUgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXHRcdFx0Y29uc3QgbGluZURpc3RhbmNlcyA9IFsgMCBdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDEsIGwgPSBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0X3ZTdGFydC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSAtIDEgKTtcblx0XHRcdFx0X3ZFbmQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKTtcblxuXHRcdFx0XHRsaW5lRGlzdGFuY2VzWyBpIF0gPSBsaW5lRGlzdGFuY2VzWyBpIC0gMSBdO1xuXHRcdFx0XHRsaW5lRGlzdGFuY2VzWyBpIF0gKz0gX3ZTdGFydC5kaXN0YW5jZVRvKCBfdkVuZCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2xpbmVEaXN0YW5jZScsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBsaW5lRGlzdGFuY2VzLCAxICkgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkxpbmUuY29tcHV0ZUxpbmVEaXN0YW5jZXMoKTogQ29tcHV0YXRpb24gb25seSBwb3NzaWJsZSB3aXRoIG5vbi1pbmRleGVkIEJ1ZmZlckdlb21ldHJ5LicgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cdFx0Y29uc3QgbWF0cml4V29ybGQgPSB0aGlzLm1hdHJpeFdvcmxkO1xuXHRcdGNvbnN0IHRocmVzaG9sZCA9IHJheWNhc3Rlci5wYXJhbXMuTGluZS50aHJlc2hvbGQ7XG5cdFx0Y29uc3QgZHJhd1JhbmdlID0gZ2VvbWV0cnkuZHJhd1JhbmdlO1xuXG5cdFx0Ly8gQ2hlY2tpbmcgYm91bmRpbmdTcGhlcmUgZGlzdGFuY2UgdG8gcmF5XG5cblx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkgZ2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XG5cblx0XHRfc3BoZXJlJDEuY29weSggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgKTtcblx0XHRfc3BoZXJlJDEuYXBwbHlNYXRyaXg0KCBtYXRyaXhXb3JsZCApO1xuXHRcdF9zcGhlcmUkMS5yYWRpdXMgKz0gdGhyZXNob2xkO1xuXG5cdFx0aWYgKCByYXljYXN0ZXIucmF5LmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUkMSApID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdC8vXG5cblx0XHRfaW52ZXJzZU1hdHJpeCQxLmNvcHkoIG1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cdFx0X3JheSQxLmNvcHkoIHJheWNhc3Rlci5yYXkgKS5hcHBseU1hdHJpeDQoIF9pbnZlcnNlTWF0cml4JDEgKTtcblxuXHRcdGNvbnN0IGxvY2FsVGhyZXNob2xkID0gdGhyZXNob2xkIC8gKCAoIHRoaXMuc2NhbGUueCArIHRoaXMuc2NhbGUueSArIHRoaXMuc2NhbGUueiApIC8gMyApO1xuXHRcdGNvbnN0IGxvY2FsVGhyZXNob2xkU3EgPSBsb2NhbFRocmVzaG9sZCAqIGxvY2FsVGhyZXNob2xkO1xuXG5cdFx0Y29uc3Qgc3RlcCA9IHRoaXMuaXNMaW5lU2VnbWVudHMgPyAyIDogMTtcblxuXHRcdGNvbnN0IGluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XG5cdFx0Y29uc3QgcG9zaXRpb25BdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXG5cdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcblxuXHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggMCwgZHJhd1JhbmdlLnN0YXJ0ICk7XG5cdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggaW5kZXguY291bnQsICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSBzdGFydCwgbCA9IGVuZCAtIDE7IGkgPCBsOyBpICs9IHN0ZXAgKSB7XG5cblx0XHRcdFx0Y29uc3QgYSA9IGluZGV4LmdldFgoIGkgKTtcblx0XHRcdFx0Y29uc3QgYiA9IGluZGV4LmdldFgoIGkgKyAxICk7XG5cblx0XHRcdFx0Y29uc3QgaW50ZXJzZWN0ID0gY2hlY2tJbnRlcnNlY3Rpb24oIHRoaXMsIHJheWNhc3RlciwgX3JheSQxLCBsb2NhbFRocmVzaG9sZFNxLCBhLCBiICk7XG5cblx0XHRcdFx0aWYgKCBpbnRlcnNlY3QgKSB7XG5cblx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRoaXMuaXNMaW5lTG9vcCApIHtcblxuXHRcdFx0XHRjb25zdCBhID0gaW5kZXguZ2V0WCggZW5kIC0gMSApO1xuXHRcdFx0XHRjb25zdCBiID0gaW5kZXguZ2V0WCggc3RhcnQgKTtcblxuXHRcdFx0XHRjb25zdCBpbnRlcnNlY3QgPSBjaGVja0ludGVyc2VjdGlvbiggdGhpcywgcmF5Y2FzdGVyLCBfcmF5JDEsIGxvY2FsVGhyZXNob2xkU3EsIGEsIGIgKTtcblxuXHRcdFx0XHRpZiAoIGludGVyc2VjdCApIHtcblxuXHRcdFx0XHRcdGludGVyc2VjdHMucHVzaCggaW50ZXJzZWN0ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zdCBzdGFydCA9IE1hdGgubWF4KCAwLCBkcmF3UmFuZ2Uuc3RhcnQgKTtcblx0XHRcdGNvbnN0IGVuZCA9IE1hdGgubWluKCBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudCwgKCBkcmF3UmFuZ2Uuc3RhcnQgKyBkcmF3UmFuZ2UuY291bnQgKSApO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IHN0YXJ0LCBsID0gZW5kIC0gMTsgaSA8IGw7IGkgKz0gc3RlcCApIHtcblxuXHRcdFx0XHRjb25zdCBpbnRlcnNlY3QgPSBjaGVja0ludGVyc2VjdGlvbiggdGhpcywgcmF5Y2FzdGVyLCBfcmF5JDEsIGxvY2FsVGhyZXNob2xkU3EsIGksIGkgKyAxICk7XG5cblx0XHRcdFx0aWYgKCBpbnRlcnNlY3QgKSB7XG5cblx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRoaXMuaXNMaW5lTG9vcCApIHtcblxuXHRcdFx0XHRjb25zdCBpbnRlcnNlY3QgPSBjaGVja0ludGVyc2VjdGlvbiggdGhpcywgcmF5Y2FzdGVyLCBfcmF5JDEsIGxvY2FsVGhyZXNob2xkU3EsIGVuZCAtIDEsIHN0YXJ0ICk7XG5cblx0XHRcdFx0aWYgKCBpbnRlcnNlY3QgKSB7XG5cblx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHR1cGRhdGVNb3JwaFRhcmdldHMoKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXM7XG5cdFx0Y29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKCBtb3JwaEF0dHJpYnV0ZXMgKTtcblxuXHRcdGlmICgga2V5cy5sZW5ndGggPiAwICkge1xuXG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlc1sga2V5c1sgMCBdIF07XG5cblx0XHRcdGlmICggbW9ycGhBdHRyaWJ1dGUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcyA9IFtdO1xuXHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0RGljdGlvbmFyeSA9IHt9O1xuXG5cdFx0XHRcdGZvciAoIGxldCBtID0gMCwgbWwgPSBtb3JwaEF0dHJpYnV0ZS5sZW5ndGg7IG0gPCBtbDsgbSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IG5hbWUgPSBtb3JwaEF0dHJpYnV0ZVsgbSBdLm5hbWUgfHwgU3RyaW5nKCBtICk7XG5cblx0XHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcy5wdXNoKCAwICk7XG5cdFx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldERpY3Rpb25hcnlbIG5hbWUgXSA9IG07XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIGNoZWNrSW50ZXJzZWN0aW9uKCBvYmplY3QsIHJheWNhc3RlciwgcmF5LCB0aHJlc2hvbGRTcSwgYSwgYiApIHtcblxuXHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IG9iamVjdC5nZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXG5cdF92U3RhcnQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGEgKTtcblx0X3ZFbmQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGIgKTtcblxuXHRjb25zdCBkaXN0U3EgPSByYXkuZGlzdGFuY2VTcVRvU2VnbWVudCggX3ZTdGFydCwgX3ZFbmQsIF9pbnRlcnNlY3RQb2ludE9uUmF5LCBfaW50ZXJzZWN0UG9pbnRPblNlZ21lbnQgKTtcblxuXHRpZiAoIGRpc3RTcSA+IHRocmVzaG9sZFNxICkgcmV0dXJuO1xuXG5cdF9pbnRlcnNlY3RQb2ludE9uUmF5LmFwcGx5TWF0cml4NCggb2JqZWN0Lm1hdHJpeFdvcmxkICk7IC8vIE1vdmUgYmFjayB0byB3b3JsZCBzcGFjZSBmb3IgZGlzdGFuY2UgY2FsY3VsYXRpb25cblxuXHRjb25zdCBkaXN0YW5jZSA9IHJheWNhc3Rlci5yYXkub3JpZ2luLmRpc3RhbmNlVG8oIF9pbnRlcnNlY3RQb2ludE9uUmF5ICk7XG5cblx0aWYgKCBkaXN0YW5jZSA8IHJheWNhc3Rlci5uZWFyIHx8IGRpc3RhbmNlID4gcmF5Y2FzdGVyLmZhciApIHJldHVybjtcblxuXHRyZXR1cm4ge1xuXG5cdFx0ZGlzdGFuY2U6IGRpc3RhbmNlLFxuXHRcdC8vIFdoYXQgZG8gd2Ugd2FudD8gaW50ZXJzZWN0aW9uIHBvaW50IG9uIHRoZSByYXkgb3Igb24gdGhlIHNlZ21lbnQ/P1xuXHRcdC8vIHBvaW50OiByYXljYXN0ZXIucmF5LmF0KCBkaXN0YW5jZSApLFxuXHRcdHBvaW50OiBfaW50ZXJzZWN0UG9pbnRPblNlZ21lbnQuY2xvbmUoKS5hcHBseU1hdHJpeDQoIG9iamVjdC5tYXRyaXhXb3JsZCApLFxuXHRcdGluZGV4OiBhLFxuXHRcdGZhY2U6IG51bGwsXG5cdFx0ZmFjZUluZGV4OiBudWxsLFxuXHRcdG9iamVjdDogb2JqZWN0XG5cblx0fTtcblxufVxuXG5jb25zdCBfc3RhcnQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfZW5kID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jbGFzcyBMaW5lU2VnbWVudHMgZXh0ZW5kcyBMaW5lIHtcblxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnksIG1hdGVyaWFsICkge1xuXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xuXG5cdFx0dGhpcy5pc0xpbmVTZWdtZW50cyA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnTGluZVNlZ21lbnRzJztcblxuXHR9XG5cblx0Y29tcHV0ZUxpbmVEaXN0YW5jZXMoKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cblx0XHQvLyB3ZSBhc3N1bWUgbm9uLWluZGV4ZWQgZ2VvbWV0cnlcblxuXHRcdGlmICggZ2VvbWV0cnkuaW5kZXggPT09IG51bGwgKSB7XG5cblx0XHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcblx0XHRcdGNvbnN0IGxpbmVEaXN0YW5jZXMgPSBbXTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gcG9zaXRpb25BdHRyaWJ1dGUuY291bnQ7IGkgPCBsOyBpICs9IDIgKSB7XG5cblx0XHRcdFx0X3N0YXJ0LmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBpICk7XG5cdFx0XHRcdF9lbmQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKyAxICk7XG5cblx0XHRcdFx0bGluZURpc3RhbmNlc1sgaSBdID0gKCBpID09PSAwICkgPyAwIDogbGluZURpc3RhbmNlc1sgaSAtIDEgXTtcblx0XHRcdFx0bGluZURpc3RhbmNlc1sgaSArIDEgXSA9IGxpbmVEaXN0YW5jZXNbIGkgXSArIF9zdGFydC5kaXN0YW5jZVRvKCBfZW5kICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnbGluZURpc3RhbmNlJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGxpbmVEaXN0YW5jZXMsIDEgKSApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuTGluZVNlZ21lbnRzLmNvbXB1dGVMaW5lRGlzdGFuY2VzKCk6IENvbXB1dGF0aW9uIG9ubHkgcG9zc2libGUgd2l0aCBub24taW5kZXhlZCBCdWZmZXJHZW9tZXRyeS4nICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgTGluZUxvb3AgZXh0ZW5kcyBMaW5lIHtcblxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnksIG1hdGVyaWFsICkge1xuXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xuXG5cdFx0dGhpcy5pc0xpbmVMb29wID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdMaW5lTG9vcCc7XG5cblx0fVxuXG59XG5cbmNsYXNzIFBvaW50c01hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNQb2ludHNNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnUG9pbnRzTWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHhmZmZmZmYgKTtcblxuXHRcdHRoaXMubWFwID0gbnVsbDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5zaXplID0gMTtcblx0XHR0aGlzLnNpemVBdHRlbnVhdGlvbiA9IHRydWU7XG5cblx0XHR0aGlzLmZvZyA9IHRydWU7XG5cblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XG5cblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xuXG5cdFx0dGhpcy5zaXplID0gc291cmNlLnNpemU7XG5cdFx0dGhpcy5zaXplQXR0ZW51YXRpb24gPSBzb3VyY2Uuc2l6ZUF0dGVudWF0aW9uO1xuXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9pbnZlcnNlTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX3JheSA9IC8qQF9fUFVSRV9fKi8gbmV3IFJheSgpO1xuY29uc3QgX3NwaGVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFNwaGVyZSgpO1xuY29uc3QgX3Bvc2l0aW9uJDIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNsYXNzIFBvaW50cyBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKSwgbWF0ZXJpYWwgPSBuZXcgUG9pbnRzTWF0ZXJpYWwoKSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzUG9pbnRzID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdQb2ludHMnO1xuXG5cdFx0dGhpcy5nZW9tZXRyeSA9IGdlb21ldHJ5O1xuXHRcdHRoaXMubWF0ZXJpYWwgPSBtYXRlcmlhbDtcblxuXHRcdHRoaXMudXBkYXRlTW9ycGhUYXJnZXRzKCk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcblxuXHRcdHRoaXMubWF0ZXJpYWwgPSBBcnJheS5pc0FycmF5KCBzb3VyY2UubWF0ZXJpYWwgKSA/IHNvdXJjZS5tYXRlcmlhbC5zbGljZSgpIDogc291cmNlLm1hdGVyaWFsO1xuXHRcdHRoaXMuZ2VvbWV0cnkgPSBzb3VyY2UuZ2VvbWV0cnk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cmF5Y2FzdCggcmF5Y2FzdGVyLCBpbnRlcnNlY3RzICkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGNvbnN0IG1hdHJpeFdvcmxkID0gdGhpcy5tYXRyaXhXb3JsZDtcblx0XHRjb25zdCB0aHJlc2hvbGQgPSByYXljYXN0ZXIucGFyYW1zLlBvaW50cy50aHJlc2hvbGQ7XG5cdFx0Y29uc3QgZHJhd1JhbmdlID0gZ2VvbWV0cnkuZHJhd1JhbmdlO1xuXG5cdFx0Ly8gQ2hlY2tpbmcgYm91bmRpbmdTcGhlcmUgZGlzdGFuY2UgdG8gcmF5XG5cblx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkgZ2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XG5cblx0XHRfc3BoZXJlLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICk7XG5cdFx0X3NwaGVyZS5hcHBseU1hdHJpeDQoIG1hdHJpeFdvcmxkICk7XG5cdFx0X3NwaGVyZS5yYWRpdXMgKz0gdGhyZXNob2xkO1xuXG5cdFx0aWYgKCByYXljYXN0ZXIucmF5LmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUgKSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHQvL1xuXG5cdFx0X2ludmVyc2VNYXRyaXguY29weSggbWF0cml4V29ybGQgKS5pbnZlcnQoKTtcblx0XHRfcmF5LmNvcHkoIHJheWNhc3Rlci5yYXkgKS5hcHBseU1hdHJpeDQoIF9pbnZlcnNlTWF0cml4ICk7XG5cblx0XHRjb25zdCBsb2NhbFRocmVzaG9sZCA9IHRocmVzaG9sZCAvICggKCB0aGlzLnNjYWxlLnggKyB0aGlzLnNjYWxlLnkgKyB0aGlzLnNjYWxlLnogKSAvIDMgKTtcblx0XHRjb25zdCBsb2NhbFRocmVzaG9sZFNxID0gbG9jYWxUaHJlc2hvbGQgKiBsb2NhbFRocmVzaG9sZDtcblxuXHRcdGNvbnN0IGluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XG5cdFx0Y29uc3QgcG9zaXRpb25BdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXG5cdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcblxuXHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggMCwgZHJhd1JhbmdlLnN0YXJ0ICk7XG5cdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggaW5kZXguY291bnQsICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSBzdGFydCwgaWwgPSBlbmQ7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBhID0gaW5kZXguZ2V0WCggaSApO1xuXG5cdFx0XHRcdF9wb3NpdGlvbiQyLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBhICk7XG5cblx0XHRcdFx0dGVzdFBvaW50KCBfcG9zaXRpb24kMiwgYSwgbG9jYWxUaHJlc2hvbGRTcSwgbWF0cml4V29ybGQsIHJheWNhc3RlciwgaW50ZXJzZWN0cywgdGhpcyApO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zdCBzdGFydCA9IE1hdGgubWF4KCAwLCBkcmF3UmFuZ2Uuc3RhcnQgKTtcblx0XHRcdGNvbnN0IGVuZCA9IE1hdGgubWluKCBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudCwgKCBkcmF3UmFuZ2Uuc3RhcnQgKyBkcmF3UmFuZ2UuY291bnQgKSApO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IHN0YXJ0LCBsID0gZW5kOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRfcG9zaXRpb24kMi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSApO1xuXG5cdFx0XHRcdHRlc3RQb2ludCggX3Bvc2l0aW9uJDIsIGksIGxvY2FsVGhyZXNob2xkU3EsIG1hdHJpeFdvcmxkLCByYXljYXN0ZXIsIGludGVyc2VjdHMsIHRoaXMgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHR1cGRhdGVNb3JwaFRhcmdldHMoKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXM7XG5cdFx0Y29uc3Qga2V5cyA9IE9iamVjdC5rZXlzKCBtb3JwaEF0dHJpYnV0ZXMgKTtcblxuXHRcdGlmICgga2V5cy5sZW5ndGggPiAwICkge1xuXG5cdFx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IG1vcnBoQXR0cmlidXRlc1sga2V5c1sgMCBdIF07XG5cblx0XHRcdGlmICggbW9ycGhBdHRyaWJ1dGUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcyA9IFtdO1xuXHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0RGljdGlvbmFyeSA9IHt9O1xuXG5cdFx0XHRcdGZvciAoIGxldCBtID0gMCwgbWwgPSBtb3JwaEF0dHJpYnV0ZS5sZW5ndGg7IG0gPCBtbDsgbSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IG5hbWUgPSBtb3JwaEF0dHJpYnV0ZVsgbSBdLm5hbWUgfHwgU3RyaW5nKCBtICk7XG5cblx0XHRcdFx0XHR0aGlzLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcy5wdXNoKCAwICk7XG5cdFx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldERpY3Rpb25hcnlbIG5hbWUgXSA9IG07XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHRlc3RQb2ludCggcG9pbnQsIGluZGV4LCBsb2NhbFRocmVzaG9sZFNxLCBtYXRyaXhXb3JsZCwgcmF5Y2FzdGVyLCBpbnRlcnNlY3RzLCBvYmplY3QgKSB7XG5cblx0Y29uc3QgcmF5UG9pbnREaXN0YW5jZVNxID0gX3JheS5kaXN0YW5jZVNxVG9Qb2ludCggcG9pbnQgKTtcblxuXHRpZiAoIHJheVBvaW50RGlzdGFuY2VTcSA8IGxvY2FsVGhyZXNob2xkU3EgKSB7XG5cblx0XHRjb25zdCBpbnRlcnNlY3RQb2ludCA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRfcmF5LmNsb3Nlc3RQb2ludFRvUG9pbnQoIHBvaW50LCBpbnRlcnNlY3RQb2ludCApO1xuXHRcdGludGVyc2VjdFBvaW50LmFwcGx5TWF0cml4NCggbWF0cml4V29ybGQgKTtcblxuXHRcdGNvbnN0IGRpc3RhbmNlID0gcmF5Y2FzdGVyLnJheS5vcmlnaW4uZGlzdGFuY2VUbyggaW50ZXJzZWN0UG9pbnQgKTtcblxuXHRcdGlmICggZGlzdGFuY2UgPCByYXljYXN0ZXIubmVhciB8fCBkaXN0YW5jZSA+IHJheWNhc3Rlci5mYXIgKSByZXR1cm47XG5cblx0XHRpbnRlcnNlY3RzLnB1c2goIHtcblxuXHRcdFx0ZGlzdGFuY2U6IGRpc3RhbmNlLFxuXHRcdFx0ZGlzdGFuY2VUb1JheTogTWF0aC5zcXJ0KCByYXlQb2ludERpc3RhbmNlU3EgKSxcblx0XHRcdHBvaW50OiBpbnRlcnNlY3RQb2ludCxcblx0XHRcdGluZGV4OiBpbmRleCxcblx0XHRcdGZhY2U6IG51bGwsXG5cdFx0XHRvYmplY3Q6IG9iamVjdFxuXG5cdFx0fSApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBWaWRlb1RleHR1cmUgZXh0ZW5kcyBUZXh0dXJlIHtcblxuXHRjb25zdHJ1Y3RvciggdmlkZW8sIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSApIHtcblxuXHRcdHN1cGVyKCB2aWRlbywgbWFwcGluZywgd3JhcFMsIHdyYXBULCBtYWdGaWx0ZXIsIG1pbkZpbHRlciwgZm9ybWF0LCB0eXBlLCBhbmlzb3Ryb3B5ICk7XG5cblx0XHR0aGlzLmlzVmlkZW9UZXh0dXJlID0gdHJ1ZTtcblxuXHRcdHRoaXMubWluRmlsdGVyID0gbWluRmlsdGVyICE9PSB1bmRlZmluZWQgPyBtaW5GaWx0ZXIgOiBMaW5lYXJGaWx0ZXI7XG5cdFx0dGhpcy5tYWdGaWx0ZXIgPSBtYWdGaWx0ZXIgIT09IHVuZGVmaW5lZCA/IG1hZ0ZpbHRlciA6IExpbmVhckZpbHRlcjtcblxuXHRcdHRoaXMuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRmdW5jdGlvbiB1cGRhdGVWaWRlbygpIHtcblxuXHRcdFx0c2NvcGUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXHRcdFx0dmlkZW8ucmVxdWVzdFZpZGVvRnJhbWVDYWxsYmFjayggdXBkYXRlVmlkZW8gKTtcblxuXHRcdH1cblxuXHRcdGlmICggJ3JlcXVlc3RWaWRlb0ZyYW1lQ2FsbGJhY2snIGluIHZpZGVvICkge1xuXG5cdFx0XHR2aWRlby5yZXF1ZXN0VmlkZW9GcmFtZUNhbGxiYWNrKCB1cGRhdGVWaWRlbyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy5pbWFnZSApLmNvcHkoIHRoaXMgKTtcblxuXHR9XG5cblx0dXBkYXRlKCkge1xuXG5cdFx0Y29uc3QgdmlkZW8gPSB0aGlzLmltYWdlO1xuXHRcdGNvbnN0IGhhc1ZpZGVvRnJhbWVDYWxsYmFjayA9ICdyZXF1ZXN0VmlkZW9GcmFtZUNhbGxiYWNrJyBpbiB2aWRlbztcblxuXHRcdGlmICggaGFzVmlkZW9GcmFtZUNhbGxiYWNrID09PSBmYWxzZSAmJiB2aWRlby5yZWFkeVN0YXRlID49IHZpZGVvLkhBVkVfQ1VSUkVOVF9EQVRBICkge1xuXG5cdFx0XHR0aGlzLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuY2xhc3MgRnJhbWVidWZmZXJUZXh0dXJlIGV4dGVuZHMgVGV4dHVyZSB7XG5cblx0Y29uc3RydWN0b3IoIHdpZHRoLCBoZWlnaHQgKSB7XG5cblx0XHRzdXBlciggeyB3aWR0aCwgaGVpZ2h0IH0gKTtcblxuXHRcdHRoaXMuaXNGcmFtZWJ1ZmZlclRleHR1cmUgPSB0cnVlO1xuXG5cdFx0dGhpcy5tYWdGaWx0ZXIgPSBOZWFyZXN0RmlsdGVyO1xuXHRcdHRoaXMubWluRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcblxuXHRcdHRoaXMuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XG5cblx0XHR0aGlzLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQ29tcHJlc3NlZFRleHR1cmUgZXh0ZW5kcyBUZXh0dXJlIHtcblxuXHRjb25zdHJ1Y3RvciggbWlwbWFwcywgd2lkdGgsIGhlaWdodCwgZm9ybWF0LCB0eXBlLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBhbmlzb3Ryb3B5LCBjb2xvclNwYWNlICkge1xuXG5cdFx0c3VwZXIoIG51bGwsIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSwgY29sb3JTcGFjZSApO1xuXG5cdFx0dGhpcy5pc0NvbXByZXNzZWRUZXh0dXJlID0gdHJ1ZTtcblxuXHRcdHRoaXMuaW1hZ2UgPSB7IHdpZHRoOiB3aWR0aCwgaGVpZ2h0OiBoZWlnaHQgfTtcblx0XHR0aGlzLm1pcG1hcHMgPSBtaXBtYXBzO1xuXG5cdFx0Ly8gbm8gZmxpcHBpbmcgZm9yIGN1YmUgdGV4dHVyZXNcblx0XHQvLyAoYWxzbyBmbGlwcGluZyBkb2Vzbid0IHdvcmsgZm9yIGNvbXByZXNzZWQgdGV4dHVyZXMgKVxuXG5cdFx0dGhpcy5mbGlwWSA9IGZhbHNlO1xuXG5cdFx0Ly8gY2FuJ3QgZ2VuZXJhdGUgbWlwbWFwcyBmb3IgY29tcHJlc3NlZCB0ZXh0dXJlc1xuXHRcdC8vIG1pcHMgbXVzdCBiZSBlbWJlZGRlZCBpbiBERFMgZmlsZXNcblxuXHRcdHRoaXMuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XG5cblx0fVxuXG59XG5cbmNsYXNzIENvbXByZXNzZWRBcnJheVRleHR1cmUgZXh0ZW5kcyBDb21wcmVzc2VkVGV4dHVyZSB7XG5cblx0Y29uc3RydWN0b3IoIG1pcG1hcHMsIHdpZHRoLCBoZWlnaHQsIGRlcHRoLCBmb3JtYXQsIHR5cGUgKSB7XG5cblx0XHRzdXBlciggbWlwbWFwcywgd2lkdGgsIGhlaWdodCwgZm9ybWF0LCB0eXBlICk7XG5cblx0XHR0aGlzLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSA9IHRydWU7XG5cdFx0dGhpcy5pbWFnZS5kZXB0aCA9IGRlcHRoO1xuXHRcdHRoaXMud3JhcFIgPSBDbGFtcFRvRWRnZVdyYXBwaW5nO1xuXG5cdFx0dGhpcy5sYXllclVwZGF0ZXMgPSBuZXcgU2V0KCk7XG5cblx0fVxuXG5cdGFkZExheWVyVXBkYXRlKCBsYXllckluZGV4ICkge1xuXG5cdFx0dGhpcy5sYXllclVwZGF0ZXMuYWRkKCBsYXllckluZGV4ICk7XG5cblx0fVxuXG5cdGNsZWFyTGF5ZXJVcGRhdGVzKCkge1xuXG5cdFx0dGhpcy5sYXllclVwZGF0ZXMuY2xlYXIoKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQ29tcHJlc3NlZEN1YmVUZXh0dXJlIGV4dGVuZHMgQ29tcHJlc3NlZFRleHR1cmUge1xuXG5cdGNvbnN0cnVjdG9yKCBpbWFnZXMsIGZvcm1hdCwgdHlwZSApIHtcblxuXHRcdHN1cGVyKCB1bmRlZmluZWQsIGltYWdlc1sgMCBdLndpZHRoLCBpbWFnZXNbIDAgXS5oZWlnaHQsIGZvcm1hdCwgdHlwZSwgQ3ViZVJlZmxlY3Rpb25NYXBwaW5nICk7XG5cblx0XHR0aGlzLmlzQ29tcHJlc3NlZEN1YmVUZXh0dXJlID0gdHJ1ZTtcblx0XHR0aGlzLmlzQ3ViZVRleHR1cmUgPSB0cnVlO1xuXG5cdFx0dGhpcy5pbWFnZSA9IGltYWdlcztcblxuXHR9XG5cbn1cblxuY2xhc3MgQ2FudmFzVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xuXG5cdGNvbnN0cnVjdG9yKCBjYW52YXMsIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSApIHtcblxuXHRcdHN1cGVyKCBjYW52YXMsIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSApO1xuXG5cdFx0dGhpcy5pc0NhbnZhc1RleHR1cmUgPSB0cnVlO1xuXG5cdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0fVxuXG59XG5cbi8qKlxuICogRXh0ZW5zaWJsZSBjdXJ2ZSBvYmplY3QuXG4gKlxuICogU29tZSBjb21tb24gb2YgY3VydmUgbWV0aG9kczpcbiAqIC5nZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgKSwgLmdldFRhbmdlbnQoIHQsIG9wdGlvbmFsVGFyZ2V0IClcbiAqIC5nZXRQb2ludEF0KCB1LCBvcHRpb25hbFRhcmdldCApLCAuZ2V0VGFuZ2VudEF0KCB1LCBvcHRpb25hbFRhcmdldCApXG4gKiAuZ2V0UG9pbnRzKCksIC5nZXRTcGFjZWRQb2ludHMoKVxuICogLmdldExlbmd0aCgpXG4gKiAudXBkYXRlQXJjTGVuZ3RocygpXG4gKlxuICogVGhpcyBmb2xsb3dpbmcgY3VydmVzIGluaGVyaXQgZnJvbSBUSFJFRS5DdXJ2ZTpcbiAqXG4gKiAtLSAyRCBjdXJ2ZXMgLS1cbiAqIFRIUkVFLkFyY0N1cnZlXG4gKiBUSFJFRS5DdWJpY0JlemllckN1cnZlXG4gKiBUSFJFRS5FbGxpcHNlQ3VydmVcbiAqIFRIUkVFLkxpbmVDdXJ2ZVxuICogVEhSRUUuUXVhZHJhdGljQmV6aWVyQ3VydmVcbiAqIFRIUkVFLlNwbGluZUN1cnZlXG4gKlxuICogLS0gM0QgY3VydmVzIC0tXG4gKiBUSFJFRS5DYXRtdWxsUm9tQ3VydmUzXG4gKiBUSFJFRS5DdWJpY0JlemllckN1cnZlM1xuICogVEhSRUUuTGluZUN1cnZlM1xuICogVEhSRUUuUXVhZHJhdGljQmV6aWVyQ3VydmUzXG4gKlxuICogQSBzZXJpZXMgb2YgY3VydmVzIGNhbiBiZSByZXByZXNlbnRlZCBhcyBhIFRIUkVFLkN1cnZlUGF0aC5cbiAqXG4gKiovXG5cbmNsYXNzIEN1cnZlIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHRoaXMudHlwZSA9ICdDdXJ2ZSc7XG5cblx0XHR0aGlzLmFyY0xlbmd0aERpdmlzaW9ucyA9IDIwMDtcblxuXHR9XG5cblx0Ly8gVmlydHVhbCBiYXNlIGNsYXNzIG1ldGhvZCB0byBvdmVyd3JpdGUgYW5kIGltcGxlbWVudCBpbiBzdWJjbGFzc2VzXG5cdC8vXHQtIHQgWzAgLi4gMV1cblxuXHRnZXRQb2ludCggLyogdCwgb3B0aW9uYWxUYXJnZXQgKi8gKSB7XG5cblx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5DdXJ2ZTogLmdldFBvaW50KCkgbm90IGltcGxlbWVudGVkLicgKTtcblx0XHRyZXR1cm4gbnVsbDtcblxuXHR9XG5cblx0Ly8gR2V0IHBvaW50IGF0IHJlbGF0aXZlIHBvc2l0aW9uIGluIGN1cnZlIGFjY29yZGluZyB0byBhcmMgbGVuZ3RoXG5cdC8vIC0gdSBbMCAuLiAxXVxuXG5cdGdldFBvaW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICkge1xuXG5cdFx0Y29uc3QgdCA9IHRoaXMuZ2V0VXRvVG1hcHBpbmcoIHUgKTtcblx0XHRyZXR1cm4gdGhpcy5nZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgKTtcblxuXHR9XG5cblx0Ly8gR2V0IHNlcXVlbmNlIG9mIHBvaW50cyB1c2luZyBnZXRQb2ludCggdCApXG5cblx0Z2V0UG9pbnRzKCBkaXZpc2lvbnMgPSA1ICkge1xuXG5cdFx0Y29uc3QgcG9pbnRzID0gW107XG5cblx0XHRmb3IgKCBsZXQgZCA9IDA7IGQgPD0gZGl2aXNpb25zOyBkICsrICkge1xuXG5cdFx0XHRwb2ludHMucHVzaCggdGhpcy5nZXRQb2ludCggZCAvIGRpdmlzaW9ucyApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcG9pbnRzO1xuXG5cdH1cblxuXHQvLyBHZXQgc2VxdWVuY2Ugb2YgcG9pbnRzIHVzaW5nIGdldFBvaW50QXQoIHUgKVxuXG5cdGdldFNwYWNlZFBvaW50cyggZGl2aXNpb25zID0gNSApIHtcblxuXHRcdGNvbnN0IHBvaW50cyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGQgPSAwOyBkIDw9IGRpdmlzaW9uczsgZCArKyApIHtcblxuXHRcdFx0cG9pbnRzLnB1c2goIHRoaXMuZ2V0UG9pbnRBdCggZCAvIGRpdmlzaW9ucyApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcG9pbnRzO1xuXG5cdH1cblxuXHQvLyBHZXQgdG90YWwgY3VydmUgYXJjIGxlbmd0aFxuXG5cdGdldExlbmd0aCgpIHtcblxuXHRcdGNvbnN0IGxlbmd0aHMgPSB0aGlzLmdldExlbmd0aHMoKTtcblx0XHRyZXR1cm4gbGVuZ3Roc1sgbGVuZ3Rocy5sZW5ndGggLSAxIF07XG5cblx0fVxuXG5cdC8vIEdldCBsaXN0IG9mIGN1bXVsYXRpdmUgc2VnbWVudCBsZW5ndGhzXG5cblx0Z2V0TGVuZ3RocyggZGl2aXNpb25zID0gdGhpcy5hcmNMZW5ndGhEaXZpc2lvbnMgKSB7XG5cblx0XHRpZiAoIHRoaXMuY2FjaGVBcmNMZW5ndGhzICYmXG5cdFx0XHQoIHRoaXMuY2FjaGVBcmNMZW5ndGhzLmxlbmd0aCA9PT0gZGl2aXNpb25zICsgMSApICYmXG5cdFx0XHQhIHRoaXMubmVlZHNVcGRhdGUgKSB7XG5cblx0XHRcdHJldHVybiB0aGlzLmNhY2hlQXJjTGVuZ3RocztcblxuXHRcdH1cblxuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSBmYWxzZTtcblxuXHRcdGNvbnN0IGNhY2hlID0gW107XG5cdFx0bGV0IGN1cnJlbnQsIGxhc3QgPSB0aGlzLmdldFBvaW50KCAwICk7XG5cdFx0bGV0IHN1bSA9IDA7XG5cblx0XHRjYWNoZS5wdXNoKCAwICk7XG5cblx0XHRmb3IgKCBsZXQgcCA9IDE7IHAgPD0gZGl2aXNpb25zOyBwICsrICkge1xuXG5cdFx0XHRjdXJyZW50ID0gdGhpcy5nZXRQb2ludCggcCAvIGRpdmlzaW9ucyApO1xuXHRcdFx0c3VtICs9IGN1cnJlbnQuZGlzdGFuY2VUbyggbGFzdCApO1xuXHRcdFx0Y2FjaGUucHVzaCggc3VtICk7XG5cdFx0XHRsYXN0ID0gY3VycmVudDtcblxuXHRcdH1cblxuXHRcdHRoaXMuY2FjaGVBcmNMZW5ndGhzID0gY2FjaGU7XG5cblx0XHRyZXR1cm4gY2FjaGU7IC8vIHsgc3VtczogY2FjaGUsIHN1bTogc3VtIH07IFN1bSBpcyBpbiB0aGUgbGFzdCBlbGVtZW50LlxuXG5cdH1cblxuXHR1cGRhdGVBcmNMZW5ndGhzKCkge1xuXG5cdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0dGhpcy5nZXRMZW5ndGhzKCk7XG5cblx0fVxuXG5cdC8vIEdpdmVuIHUgKCAwIC4uIDEgKSwgZ2V0IGEgdCB0byBmaW5kIHAuIFRoaXMgZ2l2ZXMgeW91IHBvaW50cyB3aGljaCBhcmUgZXF1aWRpc3RhbnRcblxuXHRnZXRVdG9UbWFwcGluZyggdSwgZGlzdGFuY2UgKSB7XG5cblx0XHRjb25zdCBhcmNMZW5ndGhzID0gdGhpcy5nZXRMZW5ndGhzKCk7XG5cblx0XHRsZXQgaSA9IDA7XG5cdFx0Y29uc3QgaWwgPSBhcmNMZW5ndGhzLmxlbmd0aDtcblxuXHRcdGxldCB0YXJnZXRBcmNMZW5ndGg7IC8vIFRoZSB0YXJnZXRlZCB1IGRpc3RhbmNlIHZhbHVlIHRvIGdldFxuXG5cdFx0aWYgKCBkaXN0YW5jZSApIHtcblxuXHRcdFx0dGFyZ2V0QXJjTGVuZ3RoID0gZGlzdGFuY2U7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0YXJnZXRBcmNMZW5ndGggPSB1ICogYXJjTGVuZ3Roc1sgaWwgLSAxIF07XG5cblx0XHR9XG5cblx0XHQvLyBiaW5hcnkgc2VhcmNoIGZvciB0aGUgaW5kZXggd2l0aCBsYXJnZXN0IHZhbHVlIHNtYWxsZXIgdGhhbiB0YXJnZXQgdSBkaXN0YW5jZVxuXG5cdFx0bGV0IGxvdyA9IDAsIGhpZ2ggPSBpbCAtIDEsIGNvbXBhcmlzb247XG5cblx0XHR3aGlsZSAoIGxvdyA8PSBoaWdoICkge1xuXG5cdFx0XHRpID0gTWF0aC5mbG9vciggbG93ICsgKCBoaWdoIC0gbG93ICkgLyAyICk7IC8vIGxlc3MgbGlrZWx5IHRvIG92ZXJmbG93LCB0aG91Z2ggcHJvYmFibHkgbm90IGlzc3VlIGhlcmUsIEpTIGRvZXNuJ3QgcmVhbGx5IGhhdmUgaW50ZWdlcnMsIGFsbCBudW1iZXJzIGFyZSBmbG9hdHNcblxuXHRcdFx0Y29tcGFyaXNvbiA9IGFyY0xlbmd0aHNbIGkgXSAtIHRhcmdldEFyY0xlbmd0aDtcblxuXHRcdFx0aWYgKCBjb21wYXJpc29uIDwgMCApIHtcblxuXHRcdFx0XHRsb3cgPSBpICsgMTtcblxuXHRcdFx0fSBlbHNlIGlmICggY29tcGFyaXNvbiA+IDAgKSB7XG5cblx0XHRcdFx0aGlnaCA9IGkgLSAxO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGhpZ2ggPSBpO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHQvLyBET05FXG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGkgPSBoaWdoO1xuXG5cdFx0aWYgKCBhcmNMZW5ndGhzWyBpIF0gPT09IHRhcmdldEFyY0xlbmd0aCApIHtcblxuXHRcdFx0cmV0dXJuIGkgLyAoIGlsIC0gMSApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gd2UgY291bGQgZ2V0IGZpbmVyIGdyYWluIGF0IGxlbmd0aHMsIG9yIHVzZSBzaW1wbGUgaW50ZXJwb2xhdGlvbiBiZXR3ZWVuIHR3byBwb2ludHNcblxuXHRcdGNvbnN0IGxlbmd0aEJlZm9yZSA9IGFyY0xlbmd0aHNbIGkgXTtcblx0XHRjb25zdCBsZW5ndGhBZnRlciA9IGFyY0xlbmd0aHNbIGkgKyAxIF07XG5cblx0XHRjb25zdCBzZWdtZW50TGVuZ3RoID0gbGVuZ3RoQWZ0ZXIgLSBsZW5ndGhCZWZvcmU7XG5cblx0XHQvLyBkZXRlcm1pbmUgd2hlcmUgd2UgYXJlIGJldHdlZW4gdGhlICdiZWZvcmUnIGFuZCAnYWZ0ZXInIHBvaW50c1xuXG5cdFx0Y29uc3Qgc2VnbWVudEZyYWN0aW9uID0gKCB0YXJnZXRBcmNMZW5ndGggLSBsZW5ndGhCZWZvcmUgKSAvIHNlZ21lbnRMZW5ndGg7XG5cblx0XHQvLyBhZGQgdGhhdCBmcmFjdGlvbmFsIGFtb3VudCB0byB0XG5cblx0XHRjb25zdCB0ID0gKCBpICsgc2VnbWVudEZyYWN0aW9uICkgLyAoIGlsIC0gMSApO1xuXG5cdFx0cmV0dXJuIHQ7XG5cblx0fVxuXG5cdC8vIFJldHVybnMgYSB1bml0IHZlY3RvciB0YW5nZW50IGF0IHRcblx0Ly8gSW4gY2FzZSBhbnkgc3ViIGN1cnZlIGRvZXMgbm90IGltcGxlbWVudCBpdHMgdGFuZ2VudCBkZXJpdmF0aW9uLFxuXHQvLyAyIHBvaW50cyBhIHNtYWxsIGRlbHRhIGFwYXJ0IHdpbGwgYmUgdXNlZCB0byBmaW5kIGl0cyBncmFkaWVudFxuXHQvLyB3aGljaCBzZWVtcyB0byBnaXZlIGEgcmVhc29uYWJsZSBhcHByb3hpbWF0aW9uXG5cblx0Z2V0VGFuZ2VudCggdCwgb3B0aW9uYWxUYXJnZXQgKSB7XG5cblx0XHRjb25zdCBkZWx0YSA9IDAuMDAwMTtcblx0XHRsZXQgdDEgPSB0IC0gZGVsdGE7XG5cdFx0bGV0IHQyID0gdCArIGRlbHRhO1xuXG5cdFx0Ly8gQ2FwcGluZyBpbiBjYXNlIG9mIGRhbmdlclxuXG5cdFx0aWYgKCB0MSA8IDAgKSB0MSA9IDA7XG5cdFx0aWYgKCB0MiA+IDEgKSB0MiA9IDE7XG5cblx0XHRjb25zdCBwdDEgPSB0aGlzLmdldFBvaW50KCB0MSApO1xuXHRcdGNvbnN0IHB0MiA9IHRoaXMuZ2V0UG9pbnQoIHQyICk7XG5cblx0XHRjb25zdCB0YW5nZW50ID0gb3B0aW9uYWxUYXJnZXQgfHwgKCAoIHB0MS5pc1ZlY3RvcjIgKSA/IG5ldyBWZWN0b3IyKCkgOiBuZXcgVmVjdG9yMygpICk7XG5cblx0XHR0YW5nZW50LmNvcHkoIHB0MiApLnN1YiggcHQxICkubm9ybWFsaXplKCk7XG5cblx0XHRyZXR1cm4gdGFuZ2VudDtcblxuXHR9XG5cblx0Z2V0VGFuZ2VudEF0KCB1LCBvcHRpb25hbFRhcmdldCApIHtcblxuXHRcdGNvbnN0IHQgPSB0aGlzLmdldFV0b1RtYXBwaW5nKCB1ICk7XG5cdFx0cmV0dXJuIHRoaXMuZ2V0VGFuZ2VudCggdCwgb3B0aW9uYWxUYXJnZXQgKTtcblxuXHR9XG5cblx0Y29tcHV0ZUZyZW5ldEZyYW1lcyggc2VnbWVudHMsIGNsb3NlZCApIHtcblxuXHRcdC8vIHNlZSBodHRwOi8vd3d3LmNzLmluZGlhbmEuZWR1L3B1Yi90ZWNocmVwb3J0cy9UUjQyNS5wZGZcblxuXHRcdGNvbnN0IG5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRjb25zdCB0YW5nZW50cyA9IFtdO1xuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcblx0XHRjb25zdCBiaW5vcm1hbHMgPSBbXTtcblxuXHRcdGNvbnN0IHZlYyA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0Y29uc3QgbWF0ID0gbmV3IE1hdHJpeDQoKTtcblxuXHRcdC8vIGNvbXB1dGUgdGhlIHRhbmdlbnQgdmVjdG9ycyBmb3IgZWFjaCBzZWdtZW50IG9uIHRoZSBjdXJ2ZVxuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IHNlZ21lbnRzOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCB1ID0gaSAvIHNlZ21lbnRzO1xuXG5cdFx0XHR0YW5nZW50c1sgaSBdID0gdGhpcy5nZXRUYW5nZW50QXQoIHUsIG5ldyBWZWN0b3IzKCkgKTtcblxuXHRcdH1cblxuXHRcdC8vIHNlbGVjdCBhbiBpbml0aWFsIG5vcm1hbCB2ZWN0b3IgcGVycGVuZGljdWxhciB0byB0aGUgZmlyc3QgdGFuZ2VudCB2ZWN0b3IsXG5cdFx0Ly8gYW5kIGluIHRoZSBkaXJlY3Rpb24gb2YgdGhlIG1pbmltdW0gdGFuZ2VudCB4eXogY29tcG9uZW50XG5cblx0XHRub3JtYWxzWyAwIF0gPSBuZXcgVmVjdG9yMygpO1xuXHRcdGJpbm9ybWFsc1sgMCBdID0gbmV3IFZlY3RvcjMoKTtcblx0XHRsZXQgbWluID0gTnVtYmVyLk1BWF9WQUxVRTtcblx0XHRjb25zdCB0eCA9IE1hdGguYWJzKCB0YW5nZW50c1sgMCBdLnggKTtcblx0XHRjb25zdCB0eSA9IE1hdGguYWJzKCB0YW5nZW50c1sgMCBdLnkgKTtcblx0XHRjb25zdCB0eiA9IE1hdGguYWJzKCB0YW5nZW50c1sgMCBdLnogKTtcblxuXHRcdGlmICggdHggPD0gbWluICkge1xuXG5cdFx0XHRtaW4gPSB0eDtcblx0XHRcdG5vcm1hbC5zZXQoIDEsIDAsIDAgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdHkgPD0gbWluICkge1xuXG5cdFx0XHRtaW4gPSB0eTtcblx0XHRcdG5vcm1hbC5zZXQoIDAsIDEsIDAgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdHogPD0gbWluICkge1xuXG5cdFx0XHRub3JtYWwuc2V0KCAwLCAwLCAxICk7XG5cblx0XHR9XG5cblx0XHR2ZWMuY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgMCBdLCBub3JtYWwgKS5ub3JtYWxpemUoKTtcblxuXHRcdG5vcm1hbHNbIDAgXS5jcm9zc1ZlY3RvcnMoIHRhbmdlbnRzWyAwIF0sIHZlYyApO1xuXHRcdGJpbm9ybWFsc1sgMCBdLmNyb3NzVmVjdG9ycyggdGFuZ2VudHNbIDAgXSwgbm9ybWFsc1sgMCBdICk7XG5cblxuXHRcdC8vIGNvbXB1dGUgdGhlIHNsb3dseS12YXJ5aW5nIG5vcm1hbCBhbmQgYmlub3JtYWwgdmVjdG9ycyBmb3IgZWFjaCBzZWdtZW50IG9uIHRoZSBjdXJ2ZVxuXG5cdFx0Zm9yICggbGV0IGkgPSAxOyBpIDw9IHNlZ21lbnRzOyBpICsrICkge1xuXG5cdFx0XHRub3JtYWxzWyBpIF0gPSBub3JtYWxzWyBpIC0gMSBdLmNsb25lKCk7XG5cblx0XHRcdGJpbm9ybWFsc1sgaSBdID0gYmlub3JtYWxzWyBpIC0gMSBdLmNsb25lKCk7XG5cblx0XHRcdHZlYy5jcm9zc1ZlY3RvcnMoIHRhbmdlbnRzWyBpIC0gMSBdLCB0YW5nZW50c1sgaSBdICk7XG5cblx0XHRcdGlmICggdmVjLmxlbmd0aCgpID4gTnVtYmVyLkVQU0lMT04gKSB7XG5cblx0XHRcdFx0dmVjLm5vcm1hbGl6ZSgpO1xuXG5cdFx0XHRcdGNvbnN0IHRoZXRhID0gTWF0aC5hY29zKCBjbGFtcCggdGFuZ2VudHNbIGkgLSAxIF0uZG90KCB0YW5nZW50c1sgaSBdICksIC0gMSwgMSApICk7IC8vIGNsYW1wIGZvciBmbG9hdGluZyBwdCBlcnJvcnNcblxuXHRcdFx0XHRub3JtYWxzWyBpIF0uYXBwbHlNYXRyaXg0KCBtYXQubWFrZVJvdGF0aW9uQXhpcyggdmVjLCB0aGV0YSApICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ymlub3JtYWxzWyBpIF0uY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgaSBdLCBub3JtYWxzWyBpIF0gKTtcblxuXHRcdH1cblxuXHRcdC8vIGlmIHRoZSBjdXJ2ZSBpcyBjbG9zZWQsIHBvc3Rwcm9jZXNzIHRoZSB2ZWN0b3JzIHNvIHRoZSBmaXJzdCBhbmQgbGFzdCBub3JtYWwgdmVjdG9ycyBhcmUgdGhlIHNhbWVcblxuXHRcdGlmICggY2xvc2VkID09PSB0cnVlICkge1xuXG5cdFx0XHRsZXQgdGhldGEgPSBNYXRoLmFjb3MoIGNsYW1wKCBub3JtYWxzWyAwIF0uZG90KCBub3JtYWxzWyBzZWdtZW50cyBdICksIC0gMSwgMSApICk7XG5cdFx0XHR0aGV0YSAvPSBzZWdtZW50cztcblxuXHRcdFx0aWYgKCB0YW5nZW50c1sgMCBdLmRvdCggdmVjLmNyb3NzVmVjdG9ycyggbm9ybWFsc1sgMCBdLCBub3JtYWxzWyBzZWdtZW50cyBdICkgKSA+IDAgKSB7XG5cblx0XHRcdFx0dGhldGEgPSAtIHRoZXRhO1xuXG5cdFx0XHR9XG5cblx0XHRcdGZvciAoIGxldCBpID0gMTsgaSA8PSBzZWdtZW50czsgaSArKyApIHtcblxuXHRcdFx0XHQvLyB0d2lzdCBhIGxpdHRsZS4uLlxuXHRcdFx0XHRub3JtYWxzWyBpIF0uYXBwbHlNYXRyaXg0KCBtYXQubWFrZVJvdGF0aW9uQXhpcyggdGFuZ2VudHNbIGkgXSwgdGhldGEgKiBpICkgKTtcblx0XHRcdFx0Ymlub3JtYWxzWyBpIF0uY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgaSBdLCBub3JtYWxzWyBpIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHRhbmdlbnRzOiB0YW5nZW50cyxcblx0XHRcdG5vcm1hbHM6IG5vcm1hbHMsXG5cdFx0XHRiaW5vcm1hbHM6IGJpbm9ybWFsc1xuXHRcdH07XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHR0aGlzLmFyY0xlbmd0aERpdmlzaW9ucyA9IHNvdXJjZS5hcmNMZW5ndGhEaXZpc2lvbnM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHtcblx0XHRcdG1ldGFkYXRhOiB7XG5cdFx0XHRcdHZlcnNpb246IDQuNixcblx0XHRcdFx0dHlwZTogJ0N1cnZlJyxcblx0XHRcdFx0Z2VuZXJhdG9yOiAnQ3VydmUudG9KU09OJ1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHRkYXRhLmFyY0xlbmd0aERpdmlzaW9ucyA9IHRoaXMuYXJjTGVuZ3RoRGl2aXNpb25zO1xuXHRcdGRhdGEudHlwZSA9IHRoaXMudHlwZTtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxuXHRmcm9tSlNPTigganNvbiApIHtcblxuXHRcdHRoaXMuYXJjTGVuZ3RoRGl2aXNpb25zID0ganNvbi5hcmNMZW5ndGhEaXZpc2lvbnM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgRWxsaXBzZUN1cnZlIGV4dGVuZHMgQ3VydmUge1xuXG5cdGNvbnN0cnVjdG9yKCBhWCA9IDAsIGFZID0gMCwgeFJhZGl1cyA9IDEsIHlSYWRpdXMgPSAxLCBhU3RhcnRBbmdsZSA9IDAsIGFFbmRBbmdsZSA9IE1hdGguUEkgKiAyLCBhQ2xvY2t3aXNlID0gZmFsc2UsIGFSb3RhdGlvbiA9IDAgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc0VsbGlwc2VDdXJ2ZSA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnRWxsaXBzZUN1cnZlJztcblxuXHRcdHRoaXMuYVggPSBhWDtcblx0XHR0aGlzLmFZID0gYVk7XG5cblx0XHR0aGlzLnhSYWRpdXMgPSB4UmFkaXVzO1xuXHRcdHRoaXMueVJhZGl1cyA9IHlSYWRpdXM7XG5cblx0XHR0aGlzLmFTdGFydEFuZ2xlID0gYVN0YXJ0QW5nbGU7XG5cdFx0dGhpcy5hRW5kQW5nbGUgPSBhRW5kQW5nbGU7XG5cblx0XHR0aGlzLmFDbG9ja3dpc2UgPSBhQ2xvY2t3aXNlO1xuXG5cdFx0dGhpcy5hUm90YXRpb24gPSBhUm90YXRpb247XG5cblx0fVxuXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IyKCkgKSB7XG5cblx0XHRjb25zdCBwb2ludCA9IG9wdGlvbmFsVGFyZ2V0O1xuXG5cdFx0Y29uc3QgdHdvUGkgPSBNYXRoLlBJICogMjtcblx0XHRsZXQgZGVsdGFBbmdsZSA9IHRoaXMuYUVuZEFuZ2xlIC0gdGhpcy5hU3RhcnRBbmdsZTtcblx0XHRjb25zdCBzYW1lUG9pbnRzID0gTWF0aC5hYnMoIGRlbHRhQW5nbGUgKSA8IE51bWJlci5FUFNJTE9OO1xuXG5cdFx0Ly8gZW5zdXJlcyB0aGF0IGRlbHRhQW5nbGUgaXMgMCAuLiAyIFBJXG5cdFx0d2hpbGUgKCBkZWx0YUFuZ2xlIDwgMCApIGRlbHRhQW5nbGUgKz0gdHdvUGk7XG5cdFx0d2hpbGUgKCBkZWx0YUFuZ2xlID4gdHdvUGkgKSBkZWx0YUFuZ2xlIC09IHR3b1BpO1xuXG5cdFx0aWYgKCBkZWx0YUFuZ2xlIDwgTnVtYmVyLkVQU0lMT04gKSB7XG5cblx0XHRcdGlmICggc2FtZVBvaW50cyApIHtcblxuXHRcdFx0XHRkZWx0YUFuZ2xlID0gMDtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRkZWx0YUFuZ2xlID0gdHdvUGk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5hQ2xvY2t3aXNlID09PSB0cnVlICYmICEgc2FtZVBvaW50cyApIHtcblxuXHRcdFx0aWYgKCBkZWx0YUFuZ2xlID09PSB0d29QaSApIHtcblxuXHRcdFx0XHRkZWx0YUFuZ2xlID0gLSB0d29QaTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRkZWx0YUFuZ2xlID0gZGVsdGFBbmdsZSAtIHR3b1BpO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRjb25zdCBhbmdsZSA9IHRoaXMuYVN0YXJ0QW5nbGUgKyB0ICogZGVsdGFBbmdsZTtcblx0XHRsZXQgeCA9IHRoaXMuYVggKyB0aGlzLnhSYWRpdXMgKiBNYXRoLmNvcyggYW5nbGUgKTtcblx0XHRsZXQgeSA9IHRoaXMuYVkgKyB0aGlzLnlSYWRpdXMgKiBNYXRoLnNpbiggYW5nbGUgKTtcblxuXHRcdGlmICggdGhpcy5hUm90YXRpb24gIT09IDAgKSB7XG5cblx0XHRcdGNvbnN0IGNvcyA9IE1hdGguY29zKCB0aGlzLmFSb3RhdGlvbiApO1xuXHRcdFx0Y29uc3Qgc2luID0gTWF0aC5zaW4oIHRoaXMuYVJvdGF0aW9uICk7XG5cblx0XHRcdGNvbnN0IHR4ID0geCAtIHRoaXMuYVg7XG5cdFx0XHRjb25zdCB0eSA9IHkgLSB0aGlzLmFZO1xuXG5cdFx0XHQvLyBSb3RhdGUgdGhlIHBvaW50IGFib3V0IHRoZSBjZW50ZXIgb2YgdGhlIGVsbGlwc2UuXG5cdFx0XHR4ID0gdHggKiBjb3MgLSB0eSAqIHNpbiArIHRoaXMuYVg7XG5cdFx0XHR5ID0gdHggKiBzaW4gKyB0eSAqIGNvcyArIHRoaXMuYVk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcG9pbnQuc2V0KCB4LCB5ICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5hWCA9IHNvdXJjZS5hWDtcblx0XHR0aGlzLmFZID0gc291cmNlLmFZO1xuXG5cdFx0dGhpcy54UmFkaXVzID0gc291cmNlLnhSYWRpdXM7XG5cdFx0dGhpcy55UmFkaXVzID0gc291cmNlLnlSYWRpdXM7XG5cblx0XHR0aGlzLmFTdGFydEFuZ2xlID0gc291cmNlLmFTdGFydEFuZ2xlO1xuXHRcdHRoaXMuYUVuZEFuZ2xlID0gc291cmNlLmFFbmRBbmdsZTtcblxuXHRcdHRoaXMuYUNsb2Nrd2lzZSA9IHNvdXJjZS5hQ2xvY2t3aXNlO1xuXG5cdFx0dGhpcy5hUm90YXRpb24gPSBzb3VyY2UuYVJvdGF0aW9uO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcblxuXHRcdGRhdGEuYVggPSB0aGlzLmFYO1xuXHRcdGRhdGEuYVkgPSB0aGlzLmFZO1xuXG5cdFx0ZGF0YS54UmFkaXVzID0gdGhpcy54UmFkaXVzO1xuXHRcdGRhdGEueVJhZGl1cyA9IHRoaXMueVJhZGl1cztcblxuXHRcdGRhdGEuYVN0YXJ0QW5nbGUgPSB0aGlzLmFTdGFydEFuZ2xlO1xuXHRcdGRhdGEuYUVuZEFuZ2xlID0gdGhpcy5hRW5kQW5nbGU7XG5cblx0XHRkYXRhLmFDbG9ja3dpc2UgPSB0aGlzLmFDbG9ja3dpc2U7XG5cblx0XHRkYXRhLmFSb3RhdGlvbiA9IHRoaXMuYVJvdGF0aW9uO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdGZyb21KU09OKCBqc29uICkge1xuXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcblxuXHRcdHRoaXMuYVggPSBqc29uLmFYO1xuXHRcdHRoaXMuYVkgPSBqc29uLmFZO1xuXG5cdFx0dGhpcy54UmFkaXVzID0ganNvbi54UmFkaXVzO1xuXHRcdHRoaXMueVJhZGl1cyA9IGpzb24ueVJhZGl1cztcblxuXHRcdHRoaXMuYVN0YXJ0QW5nbGUgPSBqc29uLmFTdGFydEFuZ2xlO1xuXHRcdHRoaXMuYUVuZEFuZ2xlID0ganNvbi5hRW5kQW5nbGU7XG5cblx0XHR0aGlzLmFDbG9ja3dpc2UgPSBqc29uLmFDbG9ja3dpc2U7XG5cblx0XHR0aGlzLmFSb3RhdGlvbiA9IGpzb24uYVJvdGF0aW9uO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIEFyY0N1cnZlIGV4dGVuZHMgRWxsaXBzZUN1cnZlIHtcblxuXHRjb25zdHJ1Y3RvciggYVgsIGFZLCBhUmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICkge1xuXG5cdFx0c3VwZXIoIGFYLCBhWSwgYVJhZGl1cywgYVJhZGl1cywgYVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSApO1xuXG5cdFx0dGhpcy5pc0FyY0N1cnZlID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdBcmNDdXJ2ZSc7XG5cblx0fVxuXG59XG5cbi8qKlxuICogQ2VudHJpcGV0YWwgQ2F0bXVsbFJvbSBDdXJ2ZSAtIHdoaWNoIGlzIHVzZWZ1bCBmb3IgYXZvaWRpbmdcbiAqIGN1c3BzIGFuZCBzZWxmLWludGVyc2VjdGlvbnMgaW4gbm9uLXVuaWZvcm0gY2F0bXVsbCByb20gY3VydmVzLlxuICogaHR0cDovL3d3dy5jZW15dWtzZWwuY29tL3Jlc2VhcmNoL2NhdG11bGxyb21fcGFyYW0vY2F0bXVsbHJvbS5wZGZcbiAqXG4gKiBjdXJ2ZS50eXBlIGFjY2VwdHMgY2VudHJpcGV0YWwoZGVmYXVsdCksIGNob3JkYWwgYW5kIGNhdG11bGxyb21cbiAqIGN1cnZlLnRlbnNpb24gaXMgdXNlZCBmb3IgY2F0bXVsbHJvbSB3aGljaCBkZWZhdWx0cyB0byAwLjVcbiAqL1xuXG5cbi8qXG5CYXNlZCBvbiBhbiBvcHRpbWl6ZWQgYysrIHNvbHV0aW9uIGluXG4gLSBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzk0ODk3MzYvY2F0bXVsbC1yb20tY3VydmUtd2l0aC1uby1jdXNwcy1hbmQtbm8tc2VsZi1pbnRlcnNlY3Rpb25zL1xuIC0gaHR0cDovL2lkZW9uZS5jb20vTm9FYlZNXG5cblRoaXMgQ3ViaWNQb2x5IGNsYXNzIGNvdWxkIGJlIHVzZWQgZm9yIHJldXNpbmcgc29tZSB2YXJpYWJsZXMgYW5kIGNhbGN1bGF0aW9ucyxcbmJ1dCBmb3IgdGhyZWUuanMgY3VydmUgdXNlLCBpdCBjb3VsZCBiZSBwb3NzaWJsZSBpbmxpbmVkIGFuZCBmbGF0dGVuIGludG8gYSBzaW5nbGUgZnVuY3Rpb24gY2FsbFxud2hpY2ggY2FuIGJlIHBsYWNlZCBpbiBDdXJ2ZVV0aWxzLlxuKi9cblxuZnVuY3Rpb24gQ3ViaWNQb2x5KCkge1xuXG5cdGxldCBjMCA9IDAsIGMxID0gMCwgYzIgPSAwLCBjMyA9IDA7XG5cblx0Lypcblx0ICogQ29tcHV0ZSBjb2VmZmljaWVudHMgZm9yIGEgY3ViaWMgcG9seW5vbWlhbFxuXHQgKiAgIHAocykgPSBjMCArIGMxKnMgKyBjMipzXjIgKyBjMypzXjNcblx0ICogc3VjaCB0aGF0XG5cdCAqICAgcCgwKSA9IHgwLCBwKDEpID0geDFcblx0ICogIGFuZFxuXHQgKiAgIHAnKDApID0gdDAsIHAnKDEpID0gdDEuXG5cdCAqL1xuXHRmdW5jdGlvbiBpbml0KCB4MCwgeDEsIHQwLCB0MSApIHtcblxuXHRcdGMwID0geDA7XG5cdFx0YzEgPSB0MDtcblx0XHRjMiA9IC0gMyAqIHgwICsgMyAqIHgxIC0gMiAqIHQwIC0gdDE7XG5cdFx0YzMgPSAyICogeDAgLSAyICogeDEgKyB0MCArIHQxO1xuXG5cdH1cblxuXHRyZXR1cm4ge1xuXG5cdFx0aW5pdENhdG11bGxSb206IGZ1bmN0aW9uICggeDAsIHgxLCB4MiwgeDMsIHRlbnNpb24gKSB7XG5cblx0XHRcdGluaXQoIHgxLCB4MiwgdGVuc2lvbiAqICggeDIgLSB4MCApLCB0ZW5zaW9uICogKCB4MyAtIHgxICkgKTtcblxuXHRcdH0sXG5cblx0XHRpbml0Tm9udW5pZm9ybUNhdG11bGxSb206IGZ1bmN0aW9uICggeDAsIHgxLCB4MiwgeDMsIGR0MCwgZHQxLCBkdDIgKSB7XG5cblx0XHRcdC8vIGNvbXB1dGUgdGFuZ2VudHMgd2hlbiBwYXJhbWV0ZXJpemVkIGluIFt0MSx0Ml1cblx0XHRcdGxldCB0MSA9ICggeDEgLSB4MCApIC8gZHQwIC0gKCB4MiAtIHgwICkgLyAoIGR0MCArIGR0MSApICsgKCB4MiAtIHgxICkgLyBkdDE7XG5cdFx0XHRsZXQgdDIgPSAoIHgyIC0geDEgKSAvIGR0MSAtICggeDMgLSB4MSApIC8gKCBkdDEgKyBkdDIgKSArICggeDMgLSB4MiApIC8gZHQyO1xuXG5cdFx0XHQvLyByZXNjYWxlIHRhbmdlbnRzIGZvciBwYXJhbWV0cml6YXRpb24gaW4gWzAsMV1cblx0XHRcdHQxICo9IGR0MTtcblx0XHRcdHQyICo9IGR0MTtcblxuXHRcdFx0aW5pdCggeDEsIHgyLCB0MSwgdDIgKTtcblxuXHRcdH0sXG5cblx0XHRjYWxjOiBmdW5jdGlvbiAoIHQgKSB7XG5cblx0XHRcdGNvbnN0IHQyID0gdCAqIHQ7XG5cdFx0XHRjb25zdCB0MyA9IHQyICogdDtcblx0XHRcdHJldHVybiBjMCArIGMxICogdCArIGMyICogdDIgKyBjMyAqIHQzO1xuXG5cdFx0fVxuXG5cdH07XG5cbn1cblxuLy9cblxuY29uc3QgdG1wID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgcHggPSAvKkBfX1BVUkVfXyovIG5ldyBDdWJpY1BvbHkoKTtcbmNvbnN0IHB5ID0gLypAX19QVVJFX18qLyBuZXcgQ3ViaWNQb2x5KCk7XG5jb25zdCBweiA9IC8qQF9fUFVSRV9fKi8gbmV3IEN1YmljUG9seSgpO1xuXG5jbGFzcyBDYXRtdWxsUm9tQ3VydmUzIGV4dGVuZHMgQ3VydmUge1xuXG5cdGNvbnN0cnVjdG9yKCBwb2ludHMgPSBbXSwgY2xvc2VkID0gZmFsc2UsIGN1cnZlVHlwZSA9ICdjZW50cmlwZXRhbCcsIHRlbnNpb24gPSAwLjUgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc0NhdG11bGxSb21DdXJ2ZTMgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0NhdG11bGxSb21DdXJ2ZTMnO1xuXG5cdFx0dGhpcy5wb2ludHMgPSBwb2ludHM7XG5cdFx0dGhpcy5jbG9zZWQgPSBjbG9zZWQ7XG5cdFx0dGhpcy5jdXJ2ZVR5cGUgPSBjdXJ2ZVR5cGU7XG5cdFx0dGhpcy50ZW5zaW9uID0gdGVuc2lvbjtcblxuXHR9XG5cblx0Z2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjMoKSApIHtcblxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XG5cblx0XHRjb25zdCBwb2ludHMgPSB0aGlzLnBvaW50cztcblx0XHRjb25zdCBsID0gcG9pbnRzLmxlbmd0aDtcblxuXHRcdGNvbnN0IHAgPSAoIGwgLSAoIHRoaXMuY2xvc2VkID8gMCA6IDEgKSApICogdDtcblx0XHRsZXQgaW50UG9pbnQgPSBNYXRoLmZsb29yKCBwICk7XG5cdFx0bGV0IHdlaWdodCA9IHAgLSBpbnRQb2ludDtcblxuXHRcdGlmICggdGhpcy5jbG9zZWQgKSB7XG5cblx0XHRcdGludFBvaW50ICs9IGludFBvaW50ID4gMCA/IDAgOiAoIE1hdGguZmxvb3IoIE1hdGguYWJzKCBpbnRQb2ludCApIC8gbCApICsgMSApICogbDtcblxuXHRcdH0gZWxzZSBpZiAoIHdlaWdodCA9PT0gMCAmJiBpbnRQb2ludCA9PT0gbCAtIDEgKSB7XG5cblx0XHRcdGludFBvaW50ID0gbCAtIDI7XG5cdFx0XHR3ZWlnaHQgPSAxO1xuXG5cdFx0fVxuXG5cdFx0bGV0IHAwLCBwMzsgLy8gNCBwb2ludHMgKHAxICYgcDIgZGVmaW5lZCBiZWxvdylcblxuXHRcdGlmICggdGhpcy5jbG9zZWQgfHwgaW50UG9pbnQgPiAwICkge1xuXG5cdFx0XHRwMCA9IHBvaW50c1sgKCBpbnRQb2ludCAtIDEgKSAlIGwgXTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIGV4dHJhcG9sYXRlIGZpcnN0IHBvaW50XG5cdFx0XHR0bXAuc3ViVmVjdG9ycyggcG9pbnRzWyAwIF0sIHBvaW50c1sgMSBdICkuYWRkKCBwb2ludHNbIDAgXSApO1xuXHRcdFx0cDAgPSB0bXA7XG5cblx0XHR9XG5cblx0XHRjb25zdCBwMSA9IHBvaW50c1sgaW50UG9pbnQgJSBsIF07XG5cdFx0Y29uc3QgcDIgPSBwb2ludHNbICggaW50UG9pbnQgKyAxICkgJSBsIF07XG5cblx0XHRpZiAoIHRoaXMuY2xvc2VkIHx8IGludFBvaW50ICsgMiA8IGwgKSB7XG5cblx0XHRcdHAzID0gcG9pbnRzWyAoIGludFBvaW50ICsgMiApICUgbCBdO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gZXh0cmFwb2xhdGUgbGFzdCBwb2ludFxuXHRcdFx0dG1wLnN1YlZlY3RvcnMoIHBvaW50c1sgbCAtIDEgXSwgcG9pbnRzWyBsIC0gMiBdICkuYWRkKCBwb2ludHNbIGwgLSAxIF0gKTtcblx0XHRcdHAzID0gdG1wO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmN1cnZlVHlwZSA9PT0gJ2NlbnRyaXBldGFsJyB8fCB0aGlzLmN1cnZlVHlwZSA9PT0gJ2Nob3JkYWwnICkge1xuXG5cdFx0XHQvLyBpbml0IENlbnRyaXBldGFsIC8gQ2hvcmRhbCBDYXRtdWxsLVJvbVxuXHRcdFx0Y29uc3QgcG93ID0gdGhpcy5jdXJ2ZVR5cGUgPT09ICdjaG9yZGFsJyA/IDAuNSA6IDAuMjU7XG5cdFx0XHRsZXQgZHQwID0gTWF0aC5wb3coIHAwLmRpc3RhbmNlVG9TcXVhcmVkKCBwMSApLCBwb3cgKTtcblx0XHRcdGxldCBkdDEgPSBNYXRoLnBvdyggcDEuZGlzdGFuY2VUb1NxdWFyZWQoIHAyICksIHBvdyApO1xuXHRcdFx0bGV0IGR0MiA9IE1hdGgucG93KCBwMi5kaXN0YW5jZVRvU3F1YXJlZCggcDMgKSwgcG93ICk7XG5cblx0XHRcdC8vIHNhZmV0eSBjaGVjayBmb3IgcmVwZWF0ZWQgcG9pbnRzXG5cdFx0XHRpZiAoIGR0MSA8IDFlLTQgKSBkdDEgPSAxLjA7XG5cdFx0XHRpZiAoIGR0MCA8IDFlLTQgKSBkdDAgPSBkdDE7XG5cdFx0XHRpZiAoIGR0MiA8IDFlLTQgKSBkdDIgPSBkdDE7XG5cblx0XHRcdHB4LmluaXROb251bmlmb3JtQ2F0bXVsbFJvbSggcDAueCwgcDEueCwgcDIueCwgcDMueCwgZHQwLCBkdDEsIGR0MiApO1xuXHRcdFx0cHkuaW5pdE5vbnVuaWZvcm1DYXRtdWxsUm9tKCBwMC55LCBwMS55LCBwMi55LCBwMy55LCBkdDAsIGR0MSwgZHQyICk7XG5cdFx0XHRwei5pbml0Tm9udW5pZm9ybUNhdG11bGxSb20oIHAwLnosIHAxLnosIHAyLnosIHAzLnosIGR0MCwgZHQxLCBkdDIgKTtcblxuXHRcdH0gZWxzZSBpZiAoIHRoaXMuY3VydmVUeXBlID09PSAnY2F0bXVsbHJvbScgKSB7XG5cblx0XHRcdHB4LmluaXRDYXRtdWxsUm9tKCBwMC54LCBwMS54LCBwMi54LCBwMy54LCB0aGlzLnRlbnNpb24gKTtcblx0XHRcdHB5LmluaXRDYXRtdWxsUm9tKCBwMC55LCBwMS55LCBwMi55LCBwMy55LCB0aGlzLnRlbnNpb24gKTtcblx0XHRcdHB6LmluaXRDYXRtdWxsUm9tKCBwMC56LCBwMS56LCBwMi56LCBwMy56LCB0aGlzLnRlbnNpb24gKTtcblxuXHRcdH1cblxuXHRcdHBvaW50LnNldChcblx0XHRcdHB4LmNhbGMoIHdlaWdodCApLFxuXHRcdFx0cHkuY2FsYyggd2VpZ2h0ICksXG5cdFx0XHRwei5jYWxjKCB3ZWlnaHQgKVxuXHRcdCk7XG5cblx0XHRyZXR1cm4gcG9pbnQ7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5wb2ludHMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNvdXJjZS5wb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgcG9pbnQgPSBzb3VyY2UucG9pbnRzWyBpIF07XG5cblx0XHRcdHRoaXMucG9pbnRzLnB1c2goIHBvaW50LmNsb25lKCkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuY2xvc2VkID0gc291cmNlLmNsb3NlZDtcblx0XHR0aGlzLmN1cnZlVHlwZSA9IHNvdXJjZS5jdXJ2ZVR5cGU7XG5cdFx0dGhpcy50ZW5zaW9uID0gc291cmNlLnRlbnNpb247XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS5wb2ludHMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMucG9pbnRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHBvaW50ID0gdGhpcy5wb2ludHNbIGkgXTtcblx0XHRcdGRhdGEucG9pbnRzLnB1c2goIHBvaW50LnRvQXJyYXkoKSApO1xuXG5cdFx0fVxuXG5cdFx0ZGF0YS5jbG9zZWQgPSB0aGlzLmNsb3NlZDtcblx0XHRkYXRhLmN1cnZlVHlwZSA9IHRoaXMuY3VydmVUeXBlO1xuXHRcdGRhdGEudGVuc2lvbiA9IHRoaXMudGVuc2lvbjtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxuXHRmcm9tSlNPTigganNvbiApIHtcblxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XG5cblx0XHR0aGlzLnBvaW50cyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0ganNvbi5wb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgcG9pbnQgPSBqc29uLnBvaW50c1sgaSBdO1xuXHRcdFx0dGhpcy5wb2ludHMucHVzaCggbmV3IFZlY3RvcjMoKS5mcm9tQXJyYXkoIHBvaW50ICkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuY2xvc2VkID0ganNvbi5jbG9zZWQ7XG5cdFx0dGhpcy5jdXJ2ZVR5cGUgPSBqc29uLmN1cnZlVHlwZTtcblx0XHR0aGlzLnRlbnNpb24gPSBqc29uLnRlbnNpb247XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuLyoqXG4gKiBCZXppZXIgQ3VydmVzIGZvcm11bGFzIG9idGFpbmVkIGZyb21cbiAqIGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL0IlQzMlQTl6aWVyX2N1cnZlXG4gKi9cblxuZnVuY3Rpb24gQ2F0bXVsbFJvbSggdCwgcDAsIHAxLCBwMiwgcDMgKSB7XG5cblx0Y29uc3QgdjAgPSAoIHAyIC0gcDAgKSAqIDAuNTtcblx0Y29uc3QgdjEgPSAoIHAzIC0gcDEgKSAqIDAuNTtcblx0Y29uc3QgdDIgPSB0ICogdDtcblx0Y29uc3QgdDMgPSB0ICogdDI7XG5cdHJldHVybiAoIDIgKiBwMSAtIDIgKiBwMiArIHYwICsgdjEgKSAqIHQzICsgKCAtIDMgKiBwMSArIDMgKiBwMiAtIDIgKiB2MCAtIHYxICkgKiB0MiArIHYwICogdCArIHAxO1xuXG59XG5cbi8vXG5cbmZ1bmN0aW9uIFF1YWRyYXRpY0JlemllclAwKCB0LCBwICkge1xuXG5cdGNvbnN0IGsgPSAxIC0gdDtcblx0cmV0dXJuIGsgKiBrICogcDtcblxufVxuXG5mdW5jdGlvbiBRdWFkcmF0aWNCZXppZXJQMSggdCwgcCApIHtcblxuXHRyZXR1cm4gMiAqICggMSAtIHQgKSAqIHQgKiBwO1xuXG59XG5cbmZ1bmN0aW9uIFF1YWRyYXRpY0JlemllclAyKCB0LCBwICkge1xuXG5cdHJldHVybiB0ICogdCAqIHA7XG5cbn1cblxuZnVuY3Rpb24gUXVhZHJhdGljQmV6aWVyKCB0LCBwMCwgcDEsIHAyICkge1xuXG5cdHJldHVybiBRdWFkcmF0aWNCZXppZXJQMCggdCwgcDAgKSArIFF1YWRyYXRpY0JlemllclAxKCB0LCBwMSApICtcblx0XHRRdWFkcmF0aWNCZXppZXJQMiggdCwgcDIgKTtcblxufVxuXG4vL1xuXG5mdW5jdGlvbiBDdWJpY0JlemllclAwKCB0LCBwICkge1xuXG5cdGNvbnN0IGsgPSAxIC0gdDtcblx0cmV0dXJuIGsgKiBrICogayAqIHA7XG5cbn1cblxuZnVuY3Rpb24gQ3ViaWNCZXppZXJQMSggdCwgcCApIHtcblxuXHRjb25zdCBrID0gMSAtIHQ7XG5cdHJldHVybiAzICogayAqIGsgKiB0ICogcDtcblxufVxuXG5mdW5jdGlvbiBDdWJpY0JlemllclAyKCB0LCBwICkge1xuXG5cdHJldHVybiAzICogKCAxIC0gdCApICogdCAqIHQgKiBwO1xuXG59XG5cbmZ1bmN0aW9uIEN1YmljQmV6aWVyUDMoIHQsIHAgKSB7XG5cblx0cmV0dXJuIHQgKiB0ICogdCAqIHA7XG5cbn1cblxuZnVuY3Rpb24gQ3ViaWNCZXppZXIoIHQsIHAwLCBwMSwgcDIsIHAzICkge1xuXG5cdHJldHVybiBDdWJpY0JlemllclAwKCB0LCBwMCApICsgQ3ViaWNCZXppZXJQMSggdCwgcDEgKSArIEN1YmljQmV6aWVyUDIoIHQsIHAyICkgK1xuXHRcdEN1YmljQmV6aWVyUDMoIHQsIHAzICk7XG5cbn1cblxuY2xhc3MgQ3ViaWNCZXppZXJDdXJ2ZSBleHRlbmRzIEN1cnZlIHtcblxuXHRjb25zdHJ1Y3RvciggdjAgPSBuZXcgVmVjdG9yMigpLCB2MSA9IG5ldyBWZWN0b3IyKCksIHYyID0gbmV3IFZlY3RvcjIoKSwgdjMgPSBuZXcgVmVjdG9yMigpICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNDdWJpY0JlemllckN1cnZlID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdDdWJpY0JlemllckN1cnZlJztcblxuXHRcdHRoaXMudjAgPSB2MDtcblx0XHR0aGlzLnYxID0gdjE7XG5cdFx0dGhpcy52MiA9IHYyO1xuXHRcdHRoaXMudjMgPSB2MztcblxuXHR9XG5cblx0Z2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjIoKSApIHtcblxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XG5cblx0XHRjb25zdCB2MCA9IHRoaXMudjAsIHYxID0gdGhpcy52MSwgdjIgPSB0aGlzLnYyLCB2MyA9IHRoaXMudjM7XG5cblx0XHRwb2ludC5zZXQoXG5cdFx0XHRDdWJpY0JlemllciggdCwgdjAueCwgdjEueCwgdjIueCwgdjMueCApLFxuXHRcdFx0Q3ViaWNCZXppZXIoIHQsIHYwLnksIHYxLnksIHYyLnksIHYzLnkgKVxuXHRcdCk7XG5cblx0XHRyZXR1cm4gcG9pbnQ7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy52MC5jb3B5KCBzb3VyY2UudjAgKTtcblx0XHR0aGlzLnYxLmNvcHkoIHNvdXJjZS52MSApO1xuXHRcdHRoaXMudjIuY29weSggc291cmNlLnYyICk7XG5cdFx0dGhpcy52My5jb3B5KCBzb3VyY2UudjMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XG5cblx0XHRkYXRhLnYwID0gdGhpcy52MC50b0FycmF5KCk7XG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xuXHRcdGRhdGEudjIgPSB0aGlzLnYyLnRvQXJyYXkoKTtcblx0XHRkYXRhLnYzID0gdGhpcy52My50b0FycmF5KCk7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cblx0ZnJvbUpTT04oIGpzb24gKSB7XG5cblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xuXG5cdFx0dGhpcy52MC5mcm9tQXJyYXkoIGpzb24udjAgKTtcblx0XHR0aGlzLnYxLmZyb21BcnJheSgganNvbi52MSApO1xuXHRcdHRoaXMudjIuZnJvbUFycmF5KCBqc29uLnYyICk7XG5cdFx0dGhpcy52My5mcm9tQXJyYXkoIGpzb24udjMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBDdWJpY0JlemllckN1cnZlMyBleHRlbmRzIEN1cnZlIHtcblxuXHRjb25zdHJ1Y3RvciggdjAgPSBuZXcgVmVjdG9yMygpLCB2MSA9IG5ldyBWZWN0b3IzKCksIHYyID0gbmV3IFZlY3RvcjMoKSwgdjMgPSBuZXcgVmVjdG9yMygpICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNDdWJpY0JlemllckN1cnZlMyA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnQ3ViaWNCZXppZXJDdXJ2ZTMnO1xuXG5cdFx0dGhpcy52MCA9IHYwO1xuXHRcdHRoaXMudjEgPSB2MTtcblx0XHR0aGlzLnYyID0gdjI7XG5cdFx0dGhpcy52MyA9IHYzO1xuXG5cdH1cblxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgPSBuZXcgVmVjdG9yMygpICkge1xuXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcblxuXHRcdGNvbnN0IHYwID0gdGhpcy52MCwgdjEgPSB0aGlzLnYxLCB2MiA9IHRoaXMudjIsIHYzID0gdGhpcy52MztcblxuXHRcdHBvaW50LnNldChcblx0XHRcdEN1YmljQmV6aWVyKCB0LCB2MC54LCB2MS54LCB2Mi54LCB2My54ICksXG5cdFx0XHRDdWJpY0JlemllciggdCwgdjAueSwgdjEueSwgdjIueSwgdjMueSApLFxuXHRcdFx0Q3ViaWNCZXppZXIoIHQsIHYwLnosIHYxLnosIHYyLnosIHYzLnogKVxuXHRcdCk7XG5cblx0XHRyZXR1cm4gcG9pbnQ7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy52MC5jb3B5KCBzb3VyY2UudjAgKTtcblx0XHR0aGlzLnYxLmNvcHkoIHNvdXJjZS52MSApO1xuXHRcdHRoaXMudjIuY29weSggc291cmNlLnYyICk7XG5cdFx0dGhpcy52My5jb3B5KCBzb3VyY2UudjMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XG5cblx0XHRkYXRhLnYwID0gdGhpcy52MC50b0FycmF5KCk7XG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xuXHRcdGRhdGEudjIgPSB0aGlzLnYyLnRvQXJyYXkoKTtcblx0XHRkYXRhLnYzID0gdGhpcy52My50b0FycmF5KCk7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cblx0ZnJvbUpTT04oIGpzb24gKSB7XG5cblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xuXG5cdFx0dGhpcy52MC5mcm9tQXJyYXkoIGpzb24udjAgKTtcblx0XHR0aGlzLnYxLmZyb21BcnJheSgganNvbi52MSApO1xuXHRcdHRoaXMudjIuZnJvbUFycmF5KCBqc29uLnYyICk7XG5cdFx0dGhpcy52My5mcm9tQXJyYXkoIGpzb24udjMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBMaW5lQ3VydmUgZXh0ZW5kcyBDdXJ2ZSB7XG5cblx0Y29uc3RydWN0b3IoIHYxID0gbmV3IFZlY3RvcjIoKSwgdjIgPSBuZXcgVmVjdG9yMigpICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNMaW5lQ3VydmUgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0xpbmVDdXJ2ZSc7XG5cblx0XHR0aGlzLnYxID0gdjE7XG5cdFx0dGhpcy52MiA9IHYyO1xuXG5cdH1cblxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgPSBuZXcgVmVjdG9yMigpICkge1xuXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcblxuXHRcdGlmICggdCA9PT0gMSApIHtcblxuXHRcdFx0cG9pbnQuY29weSggdGhpcy52MiApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cG9pbnQuY29weSggdGhpcy52MiApLnN1YiggdGhpcy52MSApO1xuXHRcdFx0cG9pbnQubXVsdGlwbHlTY2FsYXIoIHQgKS5hZGQoIHRoaXMudjEgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBwb2ludDtcblxuXHR9XG5cblx0Ly8gTGluZSBjdXJ2ZSBpcyBsaW5lYXIsIHNvIHdlIGNhbiBvdmVyd3JpdGUgZGVmYXVsdCBnZXRQb2ludEF0XG5cdGdldFBvaW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZ2V0UG9pbnQoIHUsIG9wdGlvbmFsVGFyZ2V0ICk7XG5cblx0fVxuXG5cdGdldFRhbmdlbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjIoKSApIHtcblxuXHRcdHJldHVybiBvcHRpb25hbFRhcmdldC5zdWJWZWN0b3JzKCB0aGlzLnYyLCB0aGlzLnYxICkubm9ybWFsaXplKCk7XG5cblx0fVxuXG5cdGdldFRhbmdlbnRBdCggdSwgb3B0aW9uYWxUYXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5nZXRUYW5nZW50KCB1LCBvcHRpb25hbFRhcmdldCApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMudjEuY29weSggc291cmNlLnYxICk7XG5cdFx0dGhpcy52Mi5jb3B5KCBzb3VyY2UudjIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XG5cblx0XHRkYXRhLnYxID0gdGhpcy52MS50b0FycmF5KCk7XG5cdFx0ZGF0YS52MiA9IHRoaXMudjIudG9BcnJheSgpO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdGZyb21KU09OKCBqc29uICkge1xuXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcblxuXHRcdHRoaXMudjEuZnJvbUFycmF5KCBqc29uLnYxICk7XG5cdFx0dGhpcy52Mi5mcm9tQXJyYXkoIGpzb24udjIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBMaW5lQ3VydmUzIGV4dGVuZHMgQ3VydmUge1xuXG5cdGNvbnN0cnVjdG9yKCB2MSA9IG5ldyBWZWN0b3IzKCksIHYyID0gbmV3IFZlY3RvcjMoKSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTGluZUN1cnZlMyA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnTGluZUN1cnZlMyc7XG5cblx0XHR0aGlzLnYxID0gdjE7XG5cdFx0dGhpcy52MiA9IHYyO1xuXG5cdH1cblxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgPSBuZXcgVmVjdG9yMygpICkge1xuXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcblxuXHRcdGlmICggdCA9PT0gMSApIHtcblxuXHRcdFx0cG9pbnQuY29weSggdGhpcy52MiApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cG9pbnQuY29weSggdGhpcy52MiApLnN1YiggdGhpcy52MSApO1xuXHRcdFx0cG9pbnQubXVsdGlwbHlTY2FsYXIoIHQgKS5hZGQoIHRoaXMudjEgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBwb2ludDtcblxuXHR9XG5cblx0Ly8gTGluZSBjdXJ2ZSBpcyBsaW5lYXIsIHNvIHdlIGNhbiBvdmVyd3JpdGUgZGVmYXVsdCBnZXRQb2ludEF0XG5cdGdldFBvaW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZ2V0UG9pbnQoIHUsIG9wdGlvbmFsVGFyZ2V0ICk7XG5cblx0fVxuXG5cdGdldFRhbmdlbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjMoKSApIHtcblxuXHRcdHJldHVybiBvcHRpb25hbFRhcmdldC5zdWJWZWN0b3JzKCB0aGlzLnYyLCB0aGlzLnYxICkubm9ybWFsaXplKCk7XG5cblx0fVxuXG5cdGdldFRhbmdlbnRBdCggdSwgb3B0aW9uYWxUYXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5nZXRUYW5nZW50KCB1LCBvcHRpb25hbFRhcmdldCApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMudjEuY29weSggc291cmNlLnYxICk7XG5cdFx0dGhpcy52Mi5jb3B5KCBzb3VyY2UudjIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XG5cblx0XHRkYXRhLnYxID0gdGhpcy52MS50b0FycmF5KCk7XG5cdFx0ZGF0YS52MiA9IHRoaXMudjIudG9BcnJheSgpO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdGZyb21KU09OKCBqc29uICkge1xuXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcblxuXHRcdHRoaXMudjEuZnJvbUFycmF5KCBqc29uLnYxICk7XG5cdFx0dGhpcy52Mi5mcm9tQXJyYXkoIGpzb24udjIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBRdWFkcmF0aWNCZXppZXJDdXJ2ZSBleHRlbmRzIEN1cnZlIHtcblxuXHRjb25zdHJ1Y3RvciggdjAgPSBuZXcgVmVjdG9yMigpLCB2MSA9IG5ldyBWZWN0b3IyKCksIHYyID0gbmV3IFZlY3RvcjIoKSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzUXVhZHJhdGljQmV6aWVyQ3VydmUgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ1F1YWRyYXRpY0JlemllckN1cnZlJztcblxuXHRcdHRoaXMudjAgPSB2MDtcblx0XHR0aGlzLnYxID0gdjE7XG5cdFx0dGhpcy52MiA9IHYyO1xuXG5cdH1cblxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgPSBuZXcgVmVjdG9yMigpICkge1xuXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcblxuXHRcdGNvbnN0IHYwID0gdGhpcy52MCwgdjEgPSB0aGlzLnYxLCB2MiA9IHRoaXMudjI7XG5cblx0XHRwb2ludC5zZXQoXG5cdFx0XHRRdWFkcmF0aWNCZXppZXIoIHQsIHYwLngsIHYxLngsIHYyLnggKSxcblx0XHRcdFF1YWRyYXRpY0JlemllciggdCwgdjAueSwgdjEueSwgdjIueSApXG5cdFx0KTtcblxuXHRcdHJldHVybiBwb2ludDtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLnYwLmNvcHkoIHNvdXJjZS52MCApO1xuXHRcdHRoaXMudjEuY29weSggc291cmNlLnYxICk7XG5cdFx0dGhpcy52Mi5jb3B5KCBzb3VyY2UudjIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XG5cblx0XHRkYXRhLnYwID0gdGhpcy52MC50b0FycmF5KCk7XG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xuXHRcdGRhdGEudjIgPSB0aGlzLnYyLnRvQXJyYXkoKTtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxuXHRmcm9tSlNPTigganNvbiApIHtcblxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XG5cblx0XHR0aGlzLnYwLmZyb21BcnJheSgganNvbi52MCApO1xuXHRcdHRoaXMudjEuZnJvbUFycmF5KCBqc29uLnYxICk7XG5cdFx0dGhpcy52Mi5mcm9tQXJyYXkoIGpzb24udjIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBRdWFkcmF0aWNCZXppZXJDdXJ2ZTMgZXh0ZW5kcyBDdXJ2ZSB7XG5cblx0Y29uc3RydWN0b3IoIHYwID0gbmV3IFZlY3RvcjMoKSwgdjEgPSBuZXcgVmVjdG9yMygpLCB2MiA9IG5ldyBWZWN0b3IzKCkgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc1F1YWRyYXRpY0JlemllckN1cnZlMyA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnUXVhZHJhdGljQmV6aWVyQ3VydmUzJztcblxuXHRcdHRoaXMudjAgPSB2MDtcblx0XHR0aGlzLnYxID0gdjE7XG5cdFx0dGhpcy52MiA9IHYyO1xuXG5cdH1cblxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgPSBuZXcgVmVjdG9yMygpICkge1xuXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcblxuXHRcdGNvbnN0IHYwID0gdGhpcy52MCwgdjEgPSB0aGlzLnYxLCB2MiA9IHRoaXMudjI7XG5cblx0XHRwb2ludC5zZXQoXG5cdFx0XHRRdWFkcmF0aWNCZXppZXIoIHQsIHYwLngsIHYxLngsIHYyLnggKSxcblx0XHRcdFF1YWRyYXRpY0JlemllciggdCwgdjAueSwgdjEueSwgdjIueSApLFxuXHRcdFx0UXVhZHJhdGljQmV6aWVyKCB0LCB2MC56LCB2MS56LCB2Mi56IClcblx0XHQpO1xuXG5cdFx0cmV0dXJuIHBvaW50O1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMudjAuY29weSggc291cmNlLnYwICk7XG5cdFx0dGhpcy52MS5jb3B5KCBzb3VyY2UudjEgKTtcblx0XHR0aGlzLnYyLmNvcHkoIHNvdXJjZS52MiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcblxuXHRcdGRhdGEudjAgPSB0aGlzLnYwLnRvQXJyYXkoKTtcblx0XHRkYXRhLnYxID0gdGhpcy52MS50b0FycmF5KCk7XG5cdFx0ZGF0YS52MiA9IHRoaXMudjIudG9BcnJheSgpO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdGZyb21KU09OKCBqc29uICkge1xuXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcblxuXHRcdHRoaXMudjAuZnJvbUFycmF5KCBqc29uLnYwICk7XG5cdFx0dGhpcy52MS5mcm9tQXJyYXkoIGpzb24udjEgKTtcblx0XHR0aGlzLnYyLmZyb21BcnJheSgganNvbi52MiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIFNwbGluZUN1cnZlIGV4dGVuZHMgQ3VydmUge1xuXG5cdGNvbnN0cnVjdG9yKCBwb2ludHMgPSBbXSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzU3BsaW5lQ3VydmUgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ1NwbGluZUN1cnZlJztcblxuXHRcdHRoaXMucG9pbnRzID0gcG9pbnRzO1xuXG5cdH1cblxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgPSBuZXcgVmVjdG9yMigpICkge1xuXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcblxuXHRcdGNvbnN0IHBvaW50cyA9IHRoaXMucG9pbnRzO1xuXHRcdGNvbnN0IHAgPSAoIHBvaW50cy5sZW5ndGggLSAxICkgKiB0O1xuXG5cdFx0Y29uc3QgaW50UG9pbnQgPSBNYXRoLmZsb29yKCBwICk7XG5cdFx0Y29uc3Qgd2VpZ2h0ID0gcCAtIGludFBvaW50O1xuXG5cdFx0Y29uc3QgcDAgPSBwb2ludHNbIGludFBvaW50ID09PSAwID8gaW50UG9pbnQgOiBpbnRQb2ludCAtIDEgXTtcblx0XHRjb25zdCBwMSA9IHBvaW50c1sgaW50UG9pbnQgXTtcblx0XHRjb25zdCBwMiA9IHBvaW50c1sgaW50UG9pbnQgPiBwb2ludHMubGVuZ3RoIC0gMiA/IHBvaW50cy5sZW5ndGggLSAxIDogaW50UG9pbnQgKyAxIF07XG5cdFx0Y29uc3QgcDMgPSBwb2ludHNbIGludFBvaW50ID4gcG9pbnRzLmxlbmd0aCAtIDMgPyBwb2ludHMubGVuZ3RoIC0gMSA6IGludFBvaW50ICsgMiBdO1xuXG5cdFx0cG9pbnQuc2V0KFxuXHRcdFx0Q2F0bXVsbFJvbSggd2VpZ2h0LCBwMC54LCBwMS54LCBwMi54LCBwMy54ICksXG5cdFx0XHRDYXRtdWxsUm9tKCB3ZWlnaHQsIHAwLnksIHAxLnksIHAyLnksIHAzLnkgKVxuXHRcdCk7XG5cblx0XHRyZXR1cm4gcG9pbnQ7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5wb2ludHMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNvdXJjZS5wb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgcG9pbnQgPSBzb3VyY2UucG9pbnRzWyBpIF07XG5cblx0XHRcdHRoaXMucG9pbnRzLnB1c2goIHBvaW50LmNsb25lKCkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XG5cblx0XHRkYXRhLnBvaW50cyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5wb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgcG9pbnQgPSB0aGlzLnBvaW50c1sgaSBdO1xuXHRcdFx0ZGF0YS5wb2ludHMucHVzaCggcG9pbnQudG9BcnJheSgpICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cblx0ZnJvbUpTT04oIGpzb24gKSB7XG5cblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xuXG5cdFx0dGhpcy5wb2ludHMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ucG9pbnRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHBvaW50ID0ganNvbi5wb2ludHNbIGkgXTtcblx0XHRcdHRoaXMucG9pbnRzLnB1c2goIG5ldyBWZWN0b3IyKCkuZnJvbUFycmF5KCBwb2ludCApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxudmFyIEN1cnZlcyA9IC8qI19fUFVSRV9fKi9PYmplY3QuZnJlZXplKHtcblx0X19wcm90b19fOiBudWxsLFxuXHRBcmNDdXJ2ZTogQXJjQ3VydmUsXG5cdENhdG11bGxSb21DdXJ2ZTM6IENhdG11bGxSb21DdXJ2ZTMsXG5cdEN1YmljQmV6aWVyQ3VydmU6IEN1YmljQmV6aWVyQ3VydmUsXG5cdEN1YmljQmV6aWVyQ3VydmUzOiBDdWJpY0JlemllckN1cnZlMyxcblx0RWxsaXBzZUN1cnZlOiBFbGxpcHNlQ3VydmUsXG5cdExpbmVDdXJ2ZTogTGluZUN1cnZlLFxuXHRMaW5lQ3VydmUzOiBMaW5lQ3VydmUzLFxuXHRRdWFkcmF0aWNCZXppZXJDdXJ2ZTogUXVhZHJhdGljQmV6aWVyQ3VydmUsXG5cdFF1YWRyYXRpY0JlemllckN1cnZlMzogUXVhZHJhdGljQmV6aWVyQ3VydmUzLFxuXHRTcGxpbmVDdXJ2ZTogU3BsaW5lQ3VydmVcbn0pO1xuXG4vKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKipcbiAqXHRDdXJ2ZWQgUGF0aCAtIGEgY3VydmUgcGF0aCBpcyBzaW1wbHkgYSBhcnJheSBvZiBjb25uZWN0ZWRcbiAqICBjdXJ2ZXMsIGJ1dCByZXRhaW5zIHRoZSBhcGkgb2YgYSBjdXJ2ZVxuICoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqL1xuXG5jbGFzcyBDdXJ2ZVBhdGggZXh0ZW5kcyBDdXJ2ZSB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ0N1cnZlUGF0aCc7XG5cblx0XHR0aGlzLmN1cnZlcyA9IFtdO1xuXHRcdHRoaXMuYXV0b0Nsb3NlID0gZmFsc2U7IC8vIEF1dG9tYXRpY2FsbHkgY2xvc2VzIHRoZSBwYXRoXG5cblx0fVxuXG5cdGFkZCggY3VydmUgKSB7XG5cblx0XHR0aGlzLmN1cnZlcy5wdXNoKCBjdXJ2ZSApO1xuXG5cdH1cblxuXHRjbG9zZVBhdGgoKSB7XG5cblx0XHQvLyBBZGQgYSBsaW5lIGN1cnZlIGlmIHN0YXJ0IGFuZCBlbmQgb2YgbGluZXMgYXJlIG5vdCBjb25uZWN0ZWRcblx0XHRjb25zdCBzdGFydFBvaW50ID0gdGhpcy5jdXJ2ZXNbIDAgXS5nZXRQb2ludCggMCApO1xuXHRcdGNvbnN0IGVuZFBvaW50ID0gdGhpcy5jdXJ2ZXNbIHRoaXMuY3VydmVzLmxlbmd0aCAtIDEgXS5nZXRQb2ludCggMSApO1xuXG5cdFx0aWYgKCAhIHN0YXJ0UG9pbnQuZXF1YWxzKCBlbmRQb2ludCApICkge1xuXG5cdFx0XHRjb25zdCBsaW5lVHlwZSA9ICggc3RhcnRQb2ludC5pc1ZlY3RvcjIgPT09IHRydWUgKSA/ICdMaW5lQ3VydmUnIDogJ0xpbmVDdXJ2ZTMnO1xuXHRcdFx0dGhpcy5jdXJ2ZXMucHVzaCggbmV3IEN1cnZlc1sgbGluZVR5cGUgXSggZW5kUG9pbnQsIHN0YXJ0UG9pbnQgKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIFRvIGdldCBhY2N1cmF0ZSBwb2ludCB3aXRoIHJlZmVyZW5jZSB0b1xuXHQvLyBlbnRpcmUgcGF0aCBkaXN0YW5jZSBhdCB0aW1lIHQsXG5cdC8vIGZvbGxvd2luZyBoYXMgdG8gYmUgZG9uZTpcblxuXHQvLyAxLiBMZW5ndGggb2YgZWFjaCBzdWIgcGF0aCBoYXZlIHRvIGJlIGtub3duXG5cdC8vIDIuIExvY2F0ZSBhbmQgaWRlbnRpZnkgdHlwZSBvZiBjdXJ2ZVxuXHQvLyAzLiBHZXQgdCBmb3IgdGhlIGN1cnZlXG5cdC8vIDQuIFJldHVybiBjdXJ2ZS5nZXRQb2ludEF0KHQnKVxuXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCApIHtcblxuXHRcdGNvbnN0IGQgPSB0ICogdGhpcy5nZXRMZW5ndGgoKTtcblx0XHRjb25zdCBjdXJ2ZUxlbmd0aHMgPSB0aGlzLmdldEN1cnZlTGVuZ3RocygpO1xuXHRcdGxldCBpID0gMDtcblxuXHRcdC8vIFRvIHRoaW5rIGFib3V0IGJvdW5kYXJpZXMgcG9pbnRzLlxuXG5cdFx0d2hpbGUgKCBpIDwgY3VydmVMZW5ndGhzLmxlbmd0aCApIHtcblxuXHRcdFx0aWYgKCBjdXJ2ZUxlbmd0aHNbIGkgXSA+PSBkICkge1xuXG5cdFx0XHRcdGNvbnN0IGRpZmYgPSBjdXJ2ZUxlbmd0aHNbIGkgXSAtIGQ7XG5cdFx0XHRcdGNvbnN0IGN1cnZlID0gdGhpcy5jdXJ2ZXNbIGkgXTtcblxuXHRcdFx0XHRjb25zdCBzZWdtZW50TGVuZ3RoID0gY3VydmUuZ2V0TGVuZ3RoKCk7XG5cdFx0XHRcdGNvbnN0IHUgPSBzZWdtZW50TGVuZ3RoID09PSAwID8gMCA6IDEgLSBkaWZmIC8gc2VnbWVudExlbmd0aDtcblxuXHRcdFx0XHRyZXR1cm4gY3VydmUuZ2V0UG9pbnRBdCggdSwgb3B0aW9uYWxUYXJnZXQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpICsrO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG51bGw7XG5cblx0XHQvLyBsb29wIHdoZXJlIHN1bSAhPSAwLCBzdW0gPiBkICwgc3VtKzEgPGRcblxuXHR9XG5cblx0Ly8gV2UgY2Fubm90IHVzZSB0aGUgZGVmYXVsdCBUSFJFRS5DdXJ2ZSBnZXRQb2ludCgpIHdpdGggZ2V0TGVuZ3RoKCkgYmVjYXVzZSBpblxuXHQvLyBUSFJFRS5DdXJ2ZSwgZ2V0TGVuZ3RoKCkgZGVwZW5kcyBvbiBnZXRQb2ludCgpIGJ1dCBpbiBUSFJFRS5DdXJ2ZVBhdGhcblx0Ly8gZ2V0UG9pbnQoKSBkZXBlbmRzIG9uIGdldExlbmd0aFxuXG5cdGdldExlbmd0aCgpIHtcblxuXHRcdGNvbnN0IGxlbnMgPSB0aGlzLmdldEN1cnZlTGVuZ3RocygpO1xuXHRcdHJldHVybiBsZW5zWyBsZW5zLmxlbmd0aCAtIDEgXTtcblxuXHR9XG5cblx0Ly8gY2FjaGVMZW5ndGhzIG11c3QgYmUgcmVjYWxjdWxhdGVkLlxuXHR1cGRhdGVBcmNMZW5ndGhzKCkge1xuXG5cdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0dGhpcy5jYWNoZUxlbmd0aHMgPSBudWxsO1xuXHRcdHRoaXMuZ2V0Q3VydmVMZW5ndGhzKCk7XG5cblx0fVxuXG5cdC8vIENvbXB1dGUgbGVuZ3RocyBhbmQgY2FjaGUgdGhlbVxuXHQvLyBXZSBjYW5ub3Qgb3ZlcndyaXRlIGdldExlbmd0aHMoKSBiZWNhdXNlIFV0b1QgbWFwcGluZyB1c2VzIGl0LlxuXG5cdGdldEN1cnZlTGVuZ3RocygpIHtcblxuXHRcdC8vIFdlIHVzZSBjYWNoZSB2YWx1ZXMgaWYgY3VydmVzIGFuZCBjYWNoZSBhcnJheSBhcmUgc2FtZSBsZW5ndGhcblxuXHRcdGlmICggdGhpcy5jYWNoZUxlbmd0aHMgJiYgdGhpcy5jYWNoZUxlbmd0aHMubGVuZ3RoID09PSB0aGlzLmN1cnZlcy5sZW5ndGggKSB7XG5cblx0XHRcdHJldHVybiB0aGlzLmNhY2hlTGVuZ3RocztcblxuXHRcdH1cblxuXHRcdC8vIEdldCBsZW5ndGggb2Ygc3ViLWN1cnZlXG5cdFx0Ly8gUHVzaCBzdW1zIGludG8gY2FjaGVkIGFycmF5XG5cblx0XHRjb25zdCBsZW5ndGhzID0gW107XG5cdFx0bGV0IHN1bXMgPSAwO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5jdXJ2ZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0c3VtcyArPSB0aGlzLmN1cnZlc1sgaSBdLmdldExlbmd0aCgpO1xuXHRcdFx0bGVuZ3Rocy5wdXNoKCBzdW1zICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmNhY2hlTGVuZ3RocyA9IGxlbmd0aHM7XG5cblx0XHRyZXR1cm4gbGVuZ3RocztcblxuXHR9XG5cblx0Z2V0U3BhY2VkUG9pbnRzKCBkaXZpc2lvbnMgPSA0MCApIHtcblxuXHRcdGNvbnN0IHBvaW50cyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IGRpdmlzaW9uczsgaSArKyApIHtcblxuXHRcdFx0cG9pbnRzLnB1c2goIHRoaXMuZ2V0UG9pbnQoIGkgLyBkaXZpc2lvbnMgKSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmF1dG9DbG9zZSApIHtcblxuXHRcdFx0cG9pbnRzLnB1c2goIHBvaW50c1sgMCBdICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcG9pbnRzO1xuXG5cdH1cblxuXHRnZXRQb2ludHMoIGRpdmlzaW9ucyA9IDEyICkge1xuXG5cdFx0Y29uc3QgcG9pbnRzID0gW107XG5cdFx0bGV0IGxhc3Q7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGN1cnZlcyA9IHRoaXMuY3VydmVzOyBpIDwgY3VydmVzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgY3VydmUgPSBjdXJ2ZXNbIGkgXTtcblx0XHRcdGNvbnN0IHJlc29sdXRpb24gPSBjdXJ2ZS5pc0VsbGlwc2VDdXJ2ZSA/IGRpdmlzaW9ucyAqIDJcblx0XHRcdFx0OiAoIGN1cnZlLmlzTGluZUN1cnZlIHx8IGN1cnZlLmlzTGluZUN1cnZlMyApID8gMVxuXHRcdFx0XHRcdDogY3VydmUuaXNTcGxpbmVDdXJ2ZSA/IGRpdmlzaW9ucyAqIGN1cnZlLnBvaW50cy5sZW5ndGhcblx0XHRcdFx0XHRcdDogZGl2aXNpb25zO1xuXG5cdFx0XHRjb25zdCBwdHMgPSBjdXJ2ZS5nZXRQb2ludHMoIHJlc29sdXRpb24gKTtcblxuXHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgcHRzLmxlbmd0aDsgaiArKyApIHtcblxuXHRcdFx0XHRjb25zdCBwb2ludCA9IHB0c1sgaiBdO1xuXG5cdFx0XHRcdGlmICggbGFzdCAmJiBsYXN0LmVxdWFscyggcG9pbnQgKSApIGNvbnRpbnVlOyAvLyBlbnN1cmVzIG5vIGNvbnNlY3V0aXZlIHBvaW50cyBhcmUgZHVwbGljYXRlc1xuXG5cdFx0XHRcdHBvaW50cy5wdXNoKCBwb2ludCApO1xuXHRcdFx0XHRsYXN0ID0gcG9pbnQ7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5hdXRvQ2xvc2UgJiYgcG9pbnRzLmxlbmd0aCA+IDEgJiYgISBwb2ludHNbIHBvaW50cy5sZW5ndGggLSAxIF0uZXF1YWxzKCBwb2ludHNbIDAgXSApICkge1xuXG5cdFx0XHRwb2ludHMucHVzaCggcG9pbnRzWyAwIF0gKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBwb2ludHM7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5jdXJ2ZXMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNvdXJjZS5jdXJ2ZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgY3VydmUgPSBzb3VyY2UuY3VydmVzWyBpIF07XG5cblx0XHRcdHRoaXMuY3VydmVzLnB1c2goIGN1cnZlLmNsb25lKCkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuYXV0b0Nsb3NlID0gc291cmNlLmF1dG9DbG9zZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XG5cblx0XHRkYXRhLmF1dG9DbG9zZSA9IHRoaXMuYXV0b0Nsb3NlO1xuXHRcdGRhdGEuY3VydmVzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmN1cnZlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBjdXJ2ZSA9IHRoaXMuY3VydmVzWyBpIF07XG5cdFx0XHRkYXRhLmN1cnZlcy5wdXNoKCBjdXJ2ZS50b0pTT04oKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdGZyb21KU09OKCBqc29uICkge1xuXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcblxuXHRcdHRoaXMuYXV0b0Nsb3NlID0ganNvbi5hdXRvQ2xvc2U7XG5cdFx0dGhpcy5jdXJ2ZXMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24uY3VydmVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGN1cnZlID0ganNvbi5jdXJ2ZXNbIGkgXTtcblx0XHRcdHRoaXMuY3VydmVzLnB1c2goIG5ldyBDdXJ2ZXNbIGN1cnZlLnR5cGUgXSgpLmZyb21KU09OKCBjdXJ2ZSApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgUGF0aCBleHRlbmRzIEN1cnZlUGF0aCB7XG5cblx0Y29uc3RydWN0b3IoIHBvaW50cyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnUGF0aCc7XG5cblx0XHR0aGlzLmN1cnJlbnRQb2ludCA9IG5ldyBWZWN0b3IyKCk7XG5cblx0XHRpZiAoIHBvaW50cyApIHtcblxuXHRcdFx0dGhpcy5zZXRGcm9tUG9pbnRzKCBwb2ludHMgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0c2V0RnJvbVBvaW50cyggcG9pbnRzICkge1xuXG5cdFx0dGhpcy5tb3ZlVG8oIHBvaW50c1sgMCBdLngsIHBvaW50c1sgMCBdLnkgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMSwgbCA9IHBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmxpbmVUbyggcG9pbnRzWyBpIF0ueCwgcG9pbnRzWyBpIF0ueSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1vdmVUbyggeCwgeSApIHtcblxuXHRcdHRoaXMuY3VycmVudFBvaW50LnNldCggeCwgeSApOyAvLyBUT0RPIGNvbnNpZGVyIHJlZmVyZW5jaW5nIHZlY3RvcnMgaW5zdGVhZCBvZiBjb3B5aW5nP1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGxpbmVUbyggeCwgeSApIHtcblxuXHRcdGNvbnN0IGN1cnZlID0gbmV3IExpbmVDdXJ2ZSggdGhpcy5jdXJyZW50UG9pbnQuY2xvbmUoKSwgbmV3IFZlY3RvcjIoIHgsIHkgKSApO1xuXHRcdHRoaXMuY3VydmVzLnB1c2goIGN1cnZlICk7XG5cblx0XHR0aGlzLmN1cnJlbnRQb2ludC5zZXQoIHgsIHkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRxdWFkcmF0aWNDdXJ2ZVRvKCBhQ1B4LCBhQ1B5LCBhWCwgYVkgKSB7XG5cblx0XHRjb25zdCBjdXJ2ZSA9IG5ldyBRdWFkcmF0aWNCZXppZXJDdXJ2ZShcblx0XHRcdHRoaXMuY3VycmVudFBvaW50LmNsb25lKCksXG5cdFx0XHRuZXcgVmVjdG9yMiggYUNQeCwgYUNQeSApLFxuXHRcdFx0bmV3IFZlY3RvcjIoIGFYLCBhWSApXG5cdFx0KTtcblxuXHRcdHRoaXMuY3VydmVzLnB1c2goIGN1cnZlICk7XG5cblx0XHR0aGlzLmN1cnJlbnRQb2ludC5zZXQoIGFYLCBhWSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGJlemllckN1cnZlVG8oIGFDUDF4LCBhQ1AxeSwgYUNQMngsIGFDUDJ5LCBhWCwgYVkgKSB7XG5cblx0XHRjb25zdCBjdXJ2ZSA9IG5ldyBDdWJpY0JlemllckN1cnZlKFxuXHRcdFx0dGhpcy5jdXJyZW50UG9pbnQuY2xvbmUoKSxcblx0XHRcdG5ldyBWZWN0b3IyKCBhQ1AxeCwgYUNQMXkgKSxcblx0XHRcdG5ldyBWZWN0b3IyKCBhQ1AyeCwgYUNQMnkgKSxcblx0XHRcdG5ldyBWZWN0b3IyKCBhWCwgYVkgKVxuXHRcdCk7XG5cblx0XHR0aGlzLmN1cnZlcy5wdXNoKCBjdXJ2ZSApO1xuXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuc2V0KCBhWCwgYVkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzcGxpbmVUaHJ1KCBwdHMgLypBcnJheSBvZiBWZWN0b3IqLyApIHtcblxuXHRcdGNvbnN0IG5wdHMgPSBbIHRoaXMuY3VycmVudFBvaW50LmNsb25lKCkgXS5jb25jYXQoIHB0cyApO1xuXG5cdFx0Y29uc3QgY3VydmUgPSBuZXcgU3BsaW5lQ3VydmUoIG5wdHMgKTtcblx0XHR0aGlzLmN1cnZlcy5wdXNoKCBjdXJ2ZSApO1xuXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuY29weSggcHRzWyBwdHMubGVuZ3RoIC0gMSBdICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXJjKCBhWCwgYVksIGFSYWRpdXMsIGFTdGFydEFuZ2xlLCBhRW5kQW5nbGUsIGFDbG9ja3dpc2UgKSB7XG5cblx0XHRjb25zdCB4MCA9IHRoaXMuY3VycmVudFBvaW50Lng7XG5cdFx0Y29uc3QgeTAgPSB0aGlzLmN1cnJlbnRQb2ludC55O1xuXG5cdFx0dGhpcy5hYnNhcmMoIGFYICsgeDAsIGFZICsgeTAsIGFSYWRpdXMsXG5cdFx0XHRhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWJzYXJjKCBhWCwgYVksIGFSYWRpdXMsIGFTdGFydEFuZ2xlLCBhRW5kQW5nbGUsIGFDbG9ja3dpc2UgKSB7XG5cblx0XHR0aGlzLmFic2VsbGlwc2UoIGFYLCBhWSwgYVJhZGl1cywgYVJhZGl1cywgYVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGVsbGlwc2UoIGFYLCBhWSwgeFJhZGl1cywgeVJhZGl1cywgYVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSwgYVJvdGF0aW9uICkge1xuXG5cdFx0Y29uc3QgeDAgPSB0aGlzLmN1cnJlbnRQb2ludC54O1xuXHRcdGNvbnN0IHkwID0gdGhpcy5jdXJyZW50UG9pbnQueTtcblxuXHRcdHRoaXMuYWJzZWxsaXBzZSggYVggKyB4MCwgYVkgKyB5MCwgeFJhZGl1cywgeVJhZGl1cywgYVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSwgYVJvdGF0aW9uICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWJzZWxsaXBzZSggYVgsIGFZLCB4UmFkaXVzLCB5UmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlLCBhUm90YXRpb24gKSB7XG5cblx0XHRjb25zdCBjdXJ2ZSA9IG5ldyBFbGxpcHNlQ3VydmUoIGFYLCBhWSwgeFJhZGl1cywgeVJhZGl1cywgYVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSwgYVJvdGF0aW9uICk7XG5cblx0XHRpZiAoIHRoaXMuY3VydmVzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdC8vIGlmIGEgcHJldmlvdXMgY3VydmUgaXMgcHJlc2VudCwgYXR0ZW1wdCB0byBqb2luXG5cdFx0XHRjb25zdCBmaXJzdFBvaW50ID0gY3VydmUuZ2V0UG9pbnQoIDAgKTtcblxuXHRcdFx0aWYgKCAhIGZpcnN0UG9pbnQuZXF1YWxzKCB0aGlzLmN1cnJlbnRQb2ludCApICkge1xuXG5cdFx0XHRcdHRoaXMubGluZVRvKCBmaXJzdFBvaW50LngsIGZpcnN0UG9pbnQueSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHR0aGlzLmN1cnZlcy5wdXNoKCBjdXJ2ZSApO1xuXG5cdFx0Y29uc3QgbGFzdFBvaW50ID0gY3VydmUuZ2V0UG9pbnQoIDEgKTtcblx0XHR0aGlzLmN1cnJlbnRQb2ludC5jb3B5KCBsYXN0UG9pbnQgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuY3VycmVudFBvaW50LmNvcHkoIHNvdXJjZS5jdXJyZW50UG9pbnQgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XG5cblx0XHRkYXRhLmN1cnJlbnRQb2ludCA9IHRoaXMuY3VycmVudFBvaW50LnRvQXJyYXkoKTtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxuXHRmcm9tSlNPTigganNvbiApIHtcblxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XG5cblx0XHR0aGlzLmN1cnJlbnRQb2ludC5mcm9tQXJyYXkoIGpzb24uY3VycmVudFBvaW50ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgTGF0aGVHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggcG9pbnRzID0gWyBuZXcgVmVjdG9yMiggMCwgLSAwLjUgKSwgbmV3IFZlY3RvcjIoIDAuNSwgMCApLCBuZXcgVmVjdG9yMiggMCwgMC41ICkgXSwgc2VnbWVudHMgPSAxMiwgcGhpU3RhcnQgPSAwLCBwaGlMZW5ndGggPSBNYXRoLlBJICogMiApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnTGF0aGVHZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRwb2ludHM6IHBvaW50cyxcblx0XHRcdHNlZ21lbnRzOiBzZWdtZW50cyxcblx0XHRcdHBoaVN0YXJ0OiBwaGlTdGFydCxcblx0XHRcdHBoaUxlbmd0aDogcGhpTGVuZ3RoXG5cdFx0fTtcblxuXHRcdHNlZ21lbnRzID0gTWF0aC5mbG9vciggc2VnbWVudHMgKTtcblxuXHRcdC8vIGNsYW1wIHBoaUxlbmd0aCBzbyBpdCdzIGluIHJhbmdlIG9mIFsgMCwgMlBJIF1cblxuXHRcdHBoaUxlbmd0aCA9IGNsYW1wKCBwaGlMZW5ndGgsIDAsIE1hdGguUEkgKiAyICk7XG5cblx0XHQvLyBidWZmZXJzXG5cblx0XHRjb25zdCBpbmRpY2VzID0gW107XG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcblx0XHRjb25zdCB1dnMgPSBbXTtcblx0XHRjb25zdCBpbml0Tm9ybWFscyA9IFtdO1xuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcblxuXHRcdC8vIGhlbHBlciB2YXJpYWJsZXNcblxuXHRcdGNvbnN0IGludmVyc2VTZWdtZW50cyA9IDEuMCAvIHNlZ21lbnRzO1xuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0Y29uc3QgdXYgPSBuZXcgVmVjdG9yMigpO1xuXHRcdGNvbnN0IG5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0Y29uc3QgY3VyTm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCBwcmV2Tm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcblx0XHRsZXQgZHggPSAwO1xuXHRcdGxldCBkeSA9IDA7XG5cblx0XHQvLyBwcmUtY29tcHV0ZSBub3JtYWxzIGZvciBpbml0aWFsIFwibWVyaWRpYW5cIlxuXG5cdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9ICggcG9pbnRzLmxlbmd0aCAtIDEgKTsgaiArKyApIHtcblxuXHRcdFx0c3dpdGNoICggaiApIHtcblxuXHRcdFx0XHRjYXNlIDA6XHRcdFx0XHQvLyBzcGVjaWFsIGhhbmRsaW5nIGZvciAxc3QgdmVydGV4IG9uIHBhdGhcblxuXHRcdFx0XHRcdGR4ID0gcG9pbnRzWyBqICsgMSBdLnggLSBwb2ludHNbIGogXS54O1xuXHRcdFx0XHRcdGR5ID0gcG9pbnRzWyBqICsgMSBdLnkgLSBwb2ludHNbIGogXS55O1xuXG5cdFx0XHRcdFx0bm9ybWFsLnggPSBkeSAqIDEuMDtcblx0XHRcdFx0XHRub3JtYWwueSA9IC0gZHg7XG5cdFx0XHRcdFx0bm9ybWFsLnogPSBkeSAqIDAuMDtcblxuXHRcdFx0XHRcdHByZXZOb3JtYWwuY29weSggbm9ybWFsICk7XG5cblx0XHRcdFx0XHRub3JtYWwubm9ybWFsaXplKCk7XG5cblx0XHRcdFx0XHRpbml0Tm9ybWFscy5wdXNoKCBub3JtYWwueCwgbm9ybWFsLnksIG5vcm1hbC56ICk7XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlICggcG9pbnRzLmxlbmd0aCAtIDEgKTpcdC8vIHNwZWNpYWwgaGFuZGxpbmcgZm9yIGxhc3QgVmVydGV4IG9uIHBhdGhcblxuXHRcdFx0XHRcdGluaXROb3JtYWxzLnB1c2goIHByZXZOb3JtYWwueCwgcHJldk5vcm1hbC55LCBwcmV2Tm9ybWFsLnogKTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGRlZmF1bHQ6XHRcdFx0Ly8gZGVmYXVsdCBoYW5kbGluZyBmb3IgYWxsIHZlcnRpY2VzIGluIGJldHdlZW5cblxuXHRcdFx0XHRcdGR4ID0gcG9pbnRzWyBqICsgMSBdLnggLSBwb2ludHNbIGogXS54O1xuXHRcdFx0XHRcdGR5ID0gcG9pbnRzWyBqICsgMSBdLnkgLSBwb2ludHNbIGogXS55O1xuXG5cdFx0XHRcdFx0bm9ybWFsLnggPSBkeSAqIDEuMDtcblx0XHRcdFx0XHRub3JtYWwueSA9IC0gZHg7XG5cdFx0XHRcdFx0bm9ybWFsLnogPSBkeSAqIDAuMDtcblxuXHRcdFx0XHRcdGN1ck5vcm1hbC5jb3B5KCBub3JtYWwgKTtcblxuXHRcdFx0XHRcdG5vcm1hbC54ICs9IHByZXZOb3JtYWwueDtcblx0XHRcdFx0XHRub3JtYWwueSArPSBwcmV2Tm9ybWFsLnk7XG5cdFx0XHRcdFx0bm9ybWFsLnogKz0gcHJldk5vcm1hbC56O1xuXG5cdFx0XHRcdFx0bm9ybWFsLm5vcm1hbGl6ZSgpO1xuXG5cdFx0XHRcdFx0aW5pdE5vcm1hbHMucHVzaCggbm9ybWFsLngsIG5vcm1hbC55LCBub3JtYWwueiApO1xuXG5cdFx0XHRcdFx0cHJldk5vcm1hbC5jb3B5KCBjdXJOb3JtYWwgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIHV2cyBhbmQgbm9ybWFsc1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IHNlZ21lbnRzOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBwaGkgPSBwaGlTdGFydCArIGkgKiBpbnZlcnNlU2VnbWVudHMgKiBwaGlMZW5ndGg7XG5cblx0XHRcdGNvbnN0IHNpbiA9IE1hdGguc2luKCBwaGkgKTtcblx0XHRcdGNvbnN0IGNvcyA9IE1hdGguY29zKCBwaGkgKTtcblxuXHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9ICggcG9pbnRzLmxlbmd0aCAtIDEgKTsgaiArKyApIHtcblxuXHRcdFx0XHQvLyB2ZXJ0ZXhcblxuXHRcdFx0XHR2ZXJ0ZXgueCA9IHBvaW50c1sgaiBdLnggKiBzaW47XG5cdFx0XHRcdHZlcnRleC55ID0gcG9pbnRzWyBqIF0ueTtcblx0XHRcdFx0dmVydGV4LnogPSBwb2ludHNbIGogXS54ICogY29zO1xuXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcblxuXHRcdFx0XHQvLyB1dlxuXG5cdFx0XHRcdHV2LnggPSBpIC8gc2VnbWVudHM7XG5cdFx0XHRcdHV2LnkgPSBqIC8gKCBwb2ludHMubGVuZ3RoIC0gMSApO1xuXG5cdFx0XHRcdHV2cy5wdXNoKCB1di54LCB1di55ICk7XG5cblx0XHRcdFx0Ly8gbm9ybWFsXG5cblx0XHRcdFx0Y29uc3QgeCA9IGluaXROb3JtYWxzWyAzICogaiArIDAgXSAqIHNpbjtcblx0XHRcdFx0Y29uc3QgeSA9IGluaXROb3JtYWxzWyAzICogaiArIDEgXTtcblx0XHRcdFx0Y29uc3QgeiA9IGluaXROb3JtYWxzWyAzICogaiArIDAgXSAqIGNvcztcblxuXHRcdFx0XHRub3JtYWxzLnB1c2goIHgsIHksIHogKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gaW5kaWNlc1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgc2VnbWVudHM7IGkgKysgKSB7XG5cblx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8ICggcG9pbnRzLmxlbmd0aCAtIDEgKTsgaiArKyApIHtcblxuXHRcdFx0XHRjb25zdCBiYXNlID0gaiArIGkgKiBwb2ludHMubGVuZ3RoO1xuXG5cdFx0XHRcdGNvbnN0IGEgPSBiYXNlO1xuXHRcdFx0XHRjb25zdCBiID0gYmFzZSArIHBvaW50cy5sZW5ndGg7XG5cdFx0XHRcdGNvbnN0IGMgPSBiYXNlICsgcG9pbnRzLmxlbmd0aCArIDE7XG5cdFx0XHRcdGNvbnN0IGQgPSBiYXNlICsgMTtcblxuXHRcdFx0XHQvLyBmYWNlc1xuXG5cdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGMsIGQsIGIgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcblxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xuXG5cdFx0cmV0dXJuIG5ldyBMYXRoZUdlb21ldHJ5KCBkYXRhLnBvaW50cywgZGF0YS5zZWdtZW50cywgZGF0YS5waGlTdGFydCwgZGF0YS5waGlMZW5ndGggKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQ2Fwc3VsZUdlb21ldHJ5IGV4dGVuZHMgTGF0aGVHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIGxlbmd0aCA9IDEsIGNhcFNlZ21lbnRzID0gNCwgcmFkaWFsU2VnbWVudHMgPSA4ICkge1xuXG5cdFx0Y29uc3QgcGF0aCA9IG5ldyBQYXRoKCk7XG5cdFx0cGF0aC5hYnNhcmMoIDAsIC0gbGVuZ3RoIC8gMiwgcmFkaXVzLCBNYXRoLlBJICogMS41LCAwICk7XG5cdFx0cGF0aC5hYnNhcmMoIDAsIGxlbmd0aCAvIDIsIHJhZGl1cywgMCwgTWF0aC5QSSAqIDAuNSApO1xuXG5cdFx0c3VwZXIoIHBhdGguZ2V0UG9pbnRzKCBjYXBTZWdtZW50cyApLCByYWRpYWxTZWdtZW50cyApO1xuXG5cdFx0dGhpcy50eXBlID0gJ0NhcHN1bGVHZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcblx0XHRcdGxlbmd0aDogbGVuZ3RoLFxuXHRcdFx0Y2FwU2VnbWVudHM6IGNhcFNlZ21lbnRzLFxuXHRcdFx0cmFkaWFsU2VnbWVudHM6IHJhZGlhbFNlZ21lbnRzLFxuXHRcdH07XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdHJldHVybiBuZXcgQ2Fwc3VsZUdlb21ldHJ5KCBkYXRhLnJhZGl1cywgZGF0YS5sZW5ndGgsIGRhdGEuY2FwU2VnbWVudHMsIGRhdGEucmFkaWFsU2VnbWVudHMgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQ2lyY2xlR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIHNlZ21lbnRzID0gMzIsIHRoZXRhU3RhcnQgPSAwLCB0aGV0YUxlbmd0aCA9IE1hdGguUEkgKiAyICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdDaXJjbGVHZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcblx0XHRcdHNlZ21lbnRzOiBzZWdtZW50cyxcblx0XHRcdHRoZXRhU3RhcnQ6IHRoZXRhU3RhcnQsXG5cdFx0XHR0aGV0YUxlbmd0aDogdGhldGFMZW5ndGhcblx0XHR9O1xuXG5cdFx0c2VnbWVudHMgPSBNYXRoLm1heCggMywgc2VnbWVudHMgKTtcblxuXHRcdC8vIGJ1ZmZlcnNcblxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcblx0XHRjb25zdCB1dnMgPSBbXTtcblxuXHRcdC8vIGhlbHBlciB2YXJpYWJsZXNcblxuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0Y29uc3QgdXYgPSBuZXcgVmVjdG9yMigpO1xuXG5cdFx0Ly8gY2VudGVyIHBvaW50XG5cblx0XHR2ZXJ0aWNlcy5wdXNoKCAwLCAwLCAwICk7XG5cdFx0bm9ybWFscy5wdXNoKCAwLCAwLCAxICk7XG5cdFx0dXZzLnB1c2goIDAuNSwgMC41ICk7XG5cblx0XHRmb3IgKCBsZXQgcyA9IDAsIGkgPSAzOyBzIDw9IHNlZ21lbnRzOyBzICsrLCBpICs9IDMgKSB7XG5cblx0XHRcdGNvbnN0IHNlZ21lbnQgPSB0aGV0YVN0YXJ0ICsgcyAvIHNlZ21lbnRzICogdGhldGFMZW5ndGg7XG5cblx0XHRcdC8vIHZlcnRleFxuXG5cdFx0XHR2ZXJ0ZXgueCA9IHJhZGl1cyAqIE1hdGguY29zKCBzZWdtZW50ICk7XG5cdFx0XHR2ZXJ0ZXgueSA9IHJhZGl1cyAqIE1hdGguc2luKCBzZWdtZW50ICk7XG5cblx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcblxuXHRcdFx0Ly8gbm9ybWFsXG5cblx0XHRcdG5vcm1hbHMucHVzaCggMCwgMCwgMSApO1xuXG5cdFx0XHQvLyB1dnNcblxuXHRcdFx0dXYueCA9ICggdmVydGljZXNbIGkgXSAvIHJhZGl1cyArIDEgKSAvIDI7XG5cdFx0XHR1di55ID0gKCB2ZXJ0aWNlc1sgaSArIDEgXSAvIHJhZGl1cyArIDEgKSAvIDI7XG5cblx0XHRcdHV2cy5wdXNoKCB1di54LCB1di55ICk7XG5cblx0XHR9XG5cblx0XHQvLyBpbmRpY2VzXG5cblx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPD0gc2VnbWVudHM7IGkgKysgKSB7XG5cblx0XHRcdGluZGljZXMucHVzaCggaSwgaSArIDEsIDAgKTtcblxuXHRcdH1cblxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XG5cblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdHJldHVybiBuZXcgQ2lyY2xlR2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLnNlZ21lbnRzLCBkYXRhLnRoZXRhU3RhcnQsIGRhdGEudGhldGFMZW5ndGggKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQ3lsaW5kZXJHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggcmFkaXVzVG9wID0gMSwgcmFkaXVzQm90dG9tID0gMSwgaGVpZ2h0ID0gMSwgcmFkaWFsU2VnbWVudHMgPSAzMiwgaGVpZ2h0U2VnbWVudHMgPSAxLCBvcGVuRW5kZWQgPSBmYWxzZSwgdGhldGFTdGFydCA9IDAsIHRoZXRhTGVuZ3RoID0gTWF0aC5QSSAqIDIgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ0N5bGluZGVyR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0cmFkaXVzVG9wOiByYWRpdXNUb3AsXG5cdFx0XHRyYWRpdXNCb3R0b206IHJhZGl1c0JvdHRvbSxcblx0XHRcdGhlaWdodDogaGVpZ2h0LFxuXHRcdFx0cmFkaWFsU2VnbWVudHM6IHJhZGlhbFNlZ21lbnRzLFxuXHRcdFx0aGVpZ2h0U2VnbWVudHM6IGhlaWdodFNlZ21lbnRzLFxuXHRcdFx0b3BlbkVuZGVkOiBvcGVuRW5kZWQsXG5cdFx0XHR0aGV0YVN0YXJ0OiB0aGV0YVN0YXJ0LFxuXHRcdFx0dGhldGFMZW5ndGg6IHRoZXRhTGVuZ3RoXG5cdFx0fTtcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdHJhZGlhbFNlZ21lbnRzID0gTWF0aC5mbG9vciggcmFkaWFsU2VnbWVudHMgKTtcblx0XHRoZWlnaHRTZWdtZW50cyA9IE1hdGguZmxvb3IoIGhlaWdodFNlZ21lbnRzICk7XG5cblx0XHQvLyBidWZmZXJzXG5cblx0XHRjb25zdCBpbmRpY2VzID0gW107XG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcblx0XHRjb25zdCBub3JtYWxzID0gW107XG5cdFx0Y29uc3QgdXZzID0gW107XG5cblx0XHQvLyBoZWxwZXIgdmFyaWFibGVzXG5cblx0XHRsZXQgaW5kZXggPSAwO1xuXHRcdGNvbnN0IGluZGV4QXJyYXkgPSBbXTtcblx0XHRjb25zdCBoYWxmSGVpZ2h0ID0gaGVpZ2h0IC8gMjtcblx0XHRsZXQgZ3JvdXBTdGFydCA9IDA7XG5cblx0XHQvLyBnZW5lcmF0ZSBnZW9tZXRyeVxuXG5cdFx0Z2VuZXJhdGVUb3JzbygpO1xuXG5cdFx0aWYgKCBvcGVuRW5kZWQgPT09IGZhbHNlICkge1xuXG5cdFx0XHRpZiAoIHJhZGl1c1RvcCA+IDAgKSBnZW5lcmF0ZUNhcCggdHJ1ZSApO1xuXHRcdFx0aWYgKCByYWRpdXNCb3R0b20gPiAwICkgZ2VuZXJhdGVDYXAoIGZhbHNlICk7XG5cblx0XHR9XG5cblx0XHQvLyBidWlsZCBnZW9tZXRyeVxuXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcblxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlVG9yc28oKSB7XG5cblx0XHRcdGNvbnN0IG5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHRsZXQgZ3JvdXBDb3VudCA9IDA7XG5cblx0XHRcdC8vIHRoaXMgd2lsbCBiZSB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgbm9ybWFsXG5cdFx0XHRjb25zdCBzbG9wZSA9ICggcmFkaXVzQm90dG9tIC0gcmFkaXVzVG9wICkgLyBoZWlnaHQ7XG5cblx0XHRcdC8vIGdlbmVyYXRlIHZlcnRpY2VzLCBub3JtYWxzIGFuZCB1dnNcblxuXHRcdFx0Zm9yICggbGV0IHkgPSAwOyB5IDw9IGhlaWdodFNlZ21lbnRzOyB5ICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGluZGV4Um93ID0gW107XG5cblx0XHRcdFx0Y29uc3QgdiA9IHkgLyBoZWlnaHRTZWdtZW50cztcblxuXHRcdFx0XHQvLyBjYWxjdWxhdGUgdGhlIHJhZGl1cyBvZiB0aGUgY3VycmVudCByb3dcblxuXHRcdFx0XHRjb25zdCByYWRpdXMgPSB2ICogKCByYWRpdXNCb3R0b20gLSByYWRpdXNUb3AgKSArIHJhZGl1c1RvcDtcblxuXHRcdFx0XHRmb3IgKCBsZXQgeCA9IDA7IHggPD0gcmFkaWFsU2VnbWVudHM7IHggKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB1ID0geCAvIHJhZGlhbFNlZ21lbnRzO1xuXG5cdFx0XHRcdFx0Y29uc3QgdGhldGEgPSB1ICogdGhldGFMZW5ndGggKyB0aGV0YVN0YXJ0O1xuXG5cdFx0XHRcdFx0Y29uc3Qgc2luVGhldGEgPSBNYXRoLnNpbiggdGhldGEgKTtcblx0XHRcdFx0XHRjb25zdCBjb3NUaGV0YSA9IE1hdGguY29zKCB0aGV0YSApO1xuXG5cdFx0XHRcdFx0Ly8gdmVydGV4XG5cblx0XHRcdFx0XHR2ZXJ0ZXgueCA9IHJhZGl1cyAqIHNpblRoZXRhO1xuXHRcdFx0XHRcdHZlcnRleC55ID0gLSB2ICogaGVpZ2h0ICsgaGFsZkhlaWdodDtcblx0XHRcdFx0XHR2ZXJ0ZXgueiA9IHJhZGl1cyAqIGNvc1RoZXRhO1xuXHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcblxuXHRcdFx0XHRcdC8vIG5vcm1hbFxuXG5cdFx0XHRcdFx0bm9ybWFsLnNldCggc2luVGhldGEsIHNsb3BlLCBjb3NUaGV0YSApLm5vcm1hbGl6ZSgpO1xuXHRcdFx0XHRcdG5vcm1hbHMucHVzaCggbm9ybWFsLngsIG5vcm1hbC55LCBub3JtYWwueiApO1xuXG5cdFx0XHRcdFx0Ly8gdXZcblxuXHRcdFx0XHRcdHV2cy5wdXNoKCB1LCAxIC0gdiApO1xuXG5cdFx0XHRcdFx0Ly8gc2F2ZSBpbmRleCBvZiB2ZXJ0ZXggaW4gcmVzcGVjdGl2ZSByb3dcblxuXHRcdFx0XHRcdGluZGV4Um93LnB1c2goIGluZGV4ICsrICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIG5vdyBzYXZlIHZlcnRpY2VzIG9mIHRoZSByb3cgaW4gb3VyIGluZGV4IGFycmF5XG5cblx0XHRcdFx0aW5kZXhBcnJheS5wdXNoKCBpbmRleFJvdyApO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGdlbmVyYXRlIGluZGljZXNcblxuXHRcdFx0Zm9yICggbGV0IHggPSAwOyB4IDwgcmFkaWFsU2VnbWVudHM7IHggKysgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IHkgPSAwOyB5IDwgaGVpZ2h0U2VnbWVudHM7IHkgKysgKSB7XG5cblx0XHRcdFx0XHQvLyB3ZSB1c2UgdGhlIGluZGV4IGFycmF5IHRvIGFjY2VzcyB0aGUgY29ycmVjdCBpbmRpY2VzXG5cblx0XHRcdFx0XHRjb25zdCBhID0gaW5kZXhBcnJheVsgeSBdWyB4IF07XG5cdFx0XHRcdFx0Y29uc3QgYiA9IGluZGV4QXJyYXlbIHkgKyAxIF1bIHggXTtcblx0XHRcdFx0XHRjb25zdCBjID0gaW5kZXhBcnJheVsgeSArIDEgXVsgeCArIDEgXTtcblx0XHRcdFx0XHRjb25zdCBkID0gaW5kZXhBcnJheVsgeSBdWyB4ICsgMSBdO1xuXG5cdFx0XHRcdFx0Ly8gZmFjZXNcblxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYiwgYywgZCApO1xuXG5cdFx0XHRcdFx0Ly8gdXBkYXRlIGdyb3VwIGNvdW50ZXJcblxuXHRcdFx0XHRcdGdyb3VwQ291bnQgKz0gNjtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gYWRkIGEgZ3JvdXAgdG8gdGhlIGdlb21ldHJ5LiB0aGlzIHdpbGwgZW5zdXJlIG11bHRpIG1hdGVyaWFsIHN1cHBvcnRcblxuXHRcdFx0c2NvcGUuYWRkR3JvdXAoIGdyb3VwU3RhcnQsIGdyb3VwQ291bnQsIDAgKTtcblxuXHRcdFx0Ly8gY2FsY3VsYXRlIG5ldyBzdGFydCB2YWx1ZSBmb3IgZ3JvdXBzXG5cblx0XHRcdGdyb3VwU3RhcnQgKz0gZ3JvdXBDb3VudDtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlQ2FwKCB0b3AgKSB7XG5cblx0XHRcdC8vIHNhdmUgdGhlIGluZGV4IG9mIHRoZSBmaXJzdCBjZW50ZXIgdmVydGV4XG5cdFx0XHRjb25zdCBjZW50ZXJJbmRleFN0YXJ0ID0gaW5kZXg7XG5cblx0XHRcdGNvbnN0IHV2ID0gbmV3IFZlY3RvcjIoKTtcblx0XHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRcdGxldCBncm91cENvdW50ID0gMDtcblxuXHRcdFx0Y29uc3QgcmFkaXVzID0gKCB0b3AgPT09IHRydWUgKSA/IHJhZGl1c1RvcCA6IHJhZGl1c0JvdHRvbTtcblx0XHRcdGNvbnN0IHNpZ24gPSAoIHRvcCA9PT0gdHJ1ZSApID8gMSA6IC0gMTtcblxuXHRcdFx0Ly8gZmlyc3Qgd2UgZ2VuZXJhdGUgdGhlIGNlbnRlciB2ZXJ0ZXggZGF0YSBvZiB0aGUgY2FwLlxuXHRcdFx0Ly8gYmVjYXVzZSB0aGUgZ2VvbWV0cnkgbmVlZHMgb25lIHNldCBvZiB1dnMgcGVyIGZhY2UsXG5cdFx0XHQvLyB3ZSBtdXN0IGdlbmVyYXRlIGEgY2VudGVyIHZlcnRleCBwZXIgZmFjZS9zZWdtZW50XG5cblx0XHRcdGZvciAoIGxldCB4ID0gMTsgeCA8PSByYWRpYWxTZWdtZW50czsgeCArKyApIHtcblxuXHRcdFx0XHQvLyB2ZXJ0ZXhcblxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCAwLCBoYWxmSGVpZ2h0ICogc2lnbiwgMCApO1xuXG5cdFx0XHRcdC8vIG5vcm1hbFxuXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgc2lnbiwgMCApO1xuXG5cdFx0XHRcdC8vIHV2XG5cblx0XHRcdFx0dXZzLnB1c2goIDAuNSwgMC41ICk7XG5cblx0XHRcdFx0Ly8gaW5jcmVhc2UgaW5kZXhcblxuXHRcdFx0XHRpbmRleCArKztcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBzYXZlIHRoZSBpbmRleCBvZiB0aGUgbGFzdCBjZW50ZXIgdmVydGV4XG5cdFx0XHRjb25zdCBjZW50ZXJJbmRleEVuZCA9IGluZGV4O1xuXG5cdFx0XHQvLyBub3cgd2UgZ2VuZXJhdGUgdGhlIHN1cnJvdW5kaW5nIHZlcnRpY2VzLCBub3JtYWxzIGFuZCB1dnNcblxuXHRcdFx0Zm9yICggbGV0IHggPSAwOyB4IDw9IHJhZGlhbFNlZ21lbnRzOyB4ICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHUgPSB4IC8gcmFkaWFsU2VnbWVudHM7XG5cdFx0XHRcdGNvbnN0IHRoZXRhID0gdSAqIHRoZXRhTGVuZ3RoICsgdGhldGFTdGFydDtcblxuXHRcdFx0XHRjb25zdCBjb3NUaGV0YSA9IE1hdGguY29zKCB0aGV0YSApO1xuXHRcdFx0XHRjb25zdCBzaW5UaGV0YSA9IE1hdGguc2luKCB0aGV0YSApO1xuXG5cdFx0XHRcdC8vIHZlcnRleFxuXG5cdFx0XHRcdHZlcnRleC54ID0gcmFkaXVzICogc2luVGhldGE7XG5cdFx0XHRcdHZlcnRleC55ID0gaGFsZkhlaWdodCAqIHNpZ247XG5cdFx0XHRcdHZlcnRleC56ID0gcmFkaXVzICogY29zVGhldGE7XG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcblxuXHRcdFx0XHQvLyBub3JtYWxcblxuXHRcdFx0XHRub3JtYWxzLnB1c2goIDAsIHNpZ24sIDAgKTtcblxuXHRcdFx0XHQvLyB1dlxuXG5cdFx0XHRcdHV2LnggPSAoIGNvc1RoZXRhICogMC41ICkgKyAwLjU7XG5cdFx0XHRcdHV2LnkgPSAoIHNpblRoZXRhICogMC41ICogc2lnbiApICsgMC41O1xuXHRcdFx0XHR1dnMucHVzaCggdXYueCwgdXYueSApO1xuXG5cdFx0XHRcdC8vIGluY3JlYXNlIGluZGV4XG5cblx0XHRcdFx0aW5kZXggKys7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gZ2VuZXJhdGUgaW5kaWNlc1xuXG5cdFx0XHRmb3IgKCBsZXQgeCA9IDA7IHggPCByYWRpYWxTZWdtZW50czsgeCArKyApIHtcblxuXHRcdFx0XHRjb25zdCBjID0gY2VudGVySW5kZXhTdGFydCArIHg7XG5cdFx0XHRcdGNvbnN0IGkgPSBjZW50ZXJJbmRleEVuZCArIHg7XG5cblx0XHRcdFx0aWYgKCB0b3AgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHQvLyBmYWNlIHRvcFxuXG5cdFx0XHRcdFx0aW5kaWNlcy5wdXNoKCBpLCBpICsgMSwgYyApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBmYWNlIGJvdHRvbVxuXG5cdFx0XHRcdFx0aW5kaWNlcy5wdXNoKCBpICsgMSwgaSwgYyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRncm91cENvdW50ICs9IDM7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gYWRkIGEgZ3JvdXAgdG8gdGhlIGdlb21ldHJ5LiB0aGlzIHdpbGwgZW5zdXJlIG11bHRpIG1hdGVyaWFsIHN1cHBvcnRcblxuXHRcdFx0c2NvcGUuYWRkR3JvdXAoIGdyb3VwU3RhcnQsIGdyb3VwQ291bnQsIHRvcCA9PT0gdHJ1ZSA/IDEgOiAyICk7XG5cblx0XHRcdC8vIGNhbGN1bGF0ZSBuZXcgc3RhcnQgdmFsdWUgZm9yIGdyb3Vwc1xuXG5cdFx0XHRncm91cFN0YXJ0ICs9IGdyb3VwQ291bnQ7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xuXG5cdFx0cmV0dXJuIG5ldyBDeWxpbmRlckdlb21ldHJ5KCBkYXRhLnJhZGl1c1RvcCwgZGF0YS5yYWRpdXNCb3R0b20sIGRhdGEuaGVpZ2h0LCBkYXRhLnJhZGlhbFNlZ21lbnRzLCBkYXRhLmhlaWdodFNlZ21lbnRzLCBkYXRhLm9wZW5FbmRlZCwgZGF0YS50aGV0YVN0YXJ0LCBkYXRhLnRoZXRhTGVuZ3RoICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIENvbmVHZW9tZXRyeSBleHRlbmRzIEN5bGluZGVyR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBoZWlnaHQgPSAxLCByYWRpYWxTZWdtZW50cyA9IDMyLCBoZWlnaHRTZWdtZW50cyA9IDEsIG9wZW5FbmRlZCA9IGZhbHNlLCB0aGV0YVN0YXJ0ID0gMCwgdGhldGFMZW5ndGggPSBNYXRoLlBJICogMiApIHtcblxuXHRcdHN1cGVyKCAwLCByYWRpdXMsIGhlaWdodCwgcmFkaWFsU2VnbWVudHMsIGhlaWdodFNlZ21lbnRzLCBvcGVuRW5kZWQsIHRoZXRhU3RhcnQsIHRoZXRhTGVuZ3RoICk7XG5cblx0XHR0aGlzLnR5cGUgPSAnQ29uZUdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHJhZGl1czogcmFkaXVzLFxuXHRcdFx0aGVpZ2h0OiBoZWlnaHQsXG5cdFx0XHRyYWRpYWxTZWdtZW50czogcmFkaWFsU2VnbWVudHMsXG5cdFx0XHRoZWlnaHRTZWdtZW50czogaGVpZ2h0U2VnbWVudHMsXG5cdFx0XHRvcGVuRW5kZWQ6IG9wZW5FbmRlZCxcblx0XHRcdHRoZXRhU3RhcnQ6IHRoZXRhU3RhcnQsXG5cdFx0XHR0aGV0YUxlbmd0aDogdGhldGFMZW5ndGhcblx0XHR9O1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IENvbmVHZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEuaGVpZ2h0LCBkYXRhLnJhZGlhbFNlZ21lbnRzLCBkYXRhLmhlaWdodFNlZ21lbnRzLCBkYXRhLm9wZW5FbmRlZCwgZGF0YS50aGV0YVN0YXJ0LCBkYXRhLnRoZXRhTGVuZ3RoICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFBvbHloZWRyb25HZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggdmVydGljZXMgPSBbXSwgaW5kaWNlcyA9IFtdLCByYWRpdXMgPSAxLCBkZXRhaWwgPSAwICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdQb2x5aGVkcm9uR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0dmVydGljZXM6IHZlcnRpY2VzLFxuXHRcdFx0aW5kaWNlczogaW5kaWNlcyxcblx0XHRcdHJhZGl1czogcmFkaXVzLFxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcblx0XHR9O1xuXG5cdFx0Ly8gZGVmYXVsdCBidWZmZXIgZGF0YVxuXG5cdFx0Y29uc3QgdmVydGV4QnVmZmVyID0gW107XG5cdFx0Y29uc3QgdXZCdWZmZXIgPSBbXTtcblxuXHRcdC8vIHRoZSBzdWJkaXZpc2lvbiBjcmVhdGVzIHRoZSB2ZXJ0ZXggYnVmZmVyIGRhdGFcblxuXHRcdHN1YmRpdmlkZSggZGV0YWlsICk7XG5cblx0XHQvLyBhbGwgdmVydGljZXMgc2hvdWxkIGxpZSBvbiBhIGNvbmNlcHR1YWwgc3BoZXJlIHdpdGggYSBnaXZlbiByYWRpdXNcblxuXHRcdGFwcGx5UmFkaXVzKCByYWRpdXMgKTtcblxuXHRcdC8vIGZpbmFsbHksIGNyZWF0ZSB0aGUgdXYgZGF0YVxuXG5cdFx0Z2VuZXJhdGVVVnMoKTtcblxuXHRcdC8vIGJ1aWxkIG5vbi1pbmRleGVkIGdlb21ldHJ5XG5cblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRleEJ1ZmZlciwgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGV4QnVmZmVyLnNsaWNlKCksIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZCdWZmZXIsIDIgKSApO1xuXG5cdFx0aWYgKCBkZXRhaWwgPT09IDAgKSB7XG5cblx0XHRcdHRoaXMuY29tcHV0ZVZlcnRleE5vcm1hbHMoKTsgLy8gZmxhdCBub3JtYWxzXG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLm5vcm1hbGl6ZU5vcm1hbHMoKTsgLy8gc21vb3RoIG5vcm1hbHNcblxuXHRcdH1cblxuXHRcdC8vIGhlbHBlciBmdW5jdGlvbnNcblxuXHRcdGZ1bmN0aW9uIHN1YmRpdmlkZSggZGV0YWlsICkge1xuXG5cdFx0XHRjb25zdCBhID0gbmV3IFZlY3RvcjMoKTtcblx0XHRcdGNvbnN0IGIgPSBuZXcgVmVjdG9yMygpO1xuXHRcdFx0Y29uc3QgYyA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRcdC8vIGl0ZXJhdGUgb3ZlciBhbGwgZmFjZXMgYW5kIGFwcGx5IGEgc3ViZGl2aXNpb24gd2l0aCB0aGUgZ2l2ZW4gZGV0YWlsIHZhbHVlXG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGluZGljZXMubGVuZ3RoOyBpICs9IDMgKSB7XG5cblx0XHRcdFx0Ly8gZ2V0IHRoZSB2ZXJ0aWNlcyBvZiB0aGUgZmFjZVxuXG5cdFx0XHRcdGdldFZlcnRleEJ5SW5kZXgoIGluZGljZXNbIGkgKyAwIF0sIGEgKTtcblx0XHRcdFx0Z2V0VmVydGV4QnlJbmRleCggaW5kaWNlc1sgaSArIDEgXSwgYiApO1xuXHRcdFx0XHRnZXRWZXJ0ZXhCeUluZGV4KCBpbmRpY2VzWyBpICsgMiBdLCBjICk7XG5cblx0XHRcdFx0Ly8gcGVyZm9ybSBzdWJkaXZpc2lvblxuXG5cdFx0XHRcdHN1YmRpdmlkZUZhY2UoIGEsIGIsIGMsIGRldGFpbCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBzdWJkaXZpZGVGYWNlKCBhLCBiLCBjLCBkZXRhaWwgKSB7XG5cblx0XHRcdGNvbnN0IGNvbHMgPSBkZXRhaWwgKyAxO1xuXG5cdFx0XHQvLyB3ZSB1c2UgdGhpcyBtdWx0aWRpbWVuc2lvbmFsIGFycmF5IGFzIGEgZGF0YSBzdHJ1Y3R1cmUgZm9yIGNyZWF0aW5nIHRoZSBzdWJkaXZpc2lvblxuXG5cdFx0XHRjb25zdCB2ID0gW107XG5cblx0XHRcdC8vIGNvbnN0cnVjdCBhbGwgb2YgdGhlIHZlcnRpY2VzIGZvciB0aGlzIHN1YmRpdmlzaW9uXG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSBjb2xzOyBpICsrICkge1xuXG5cdFx0XHRcdHZbIGkgXSA9IFtdO1xuXG5cdFx0XHRcdGNvbnN0IGFqID0gYS5jbG9uZSgpLmxlcnAoIGMsIGkgLyBjb2xzICk7XG5cdFx0XHRcdGNvbnN0IGJqID0gYi5jbG9uZSgpLmxlcnAoIGMsIGkgLyBjb2xzICk7XG5cblx0XHRcdFx0Y29uc3Qgcm93cyA9IGNvbHMgLSBpO1xuXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSByb3dzOyBqICsrICkge1xuXG5cdFx0XHRcdFx0aWYgKCBqID09PSAwICYmIGkgPT09IGNvbHMgKSB7XG5cblx0XHRcdFx0XHRcdHZbIGkgXVsgaiBdID0gYWo7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHR2WyBpIF1bIGogXSA9IGFqLmNsb25lKCkubGVycCggYmosIGogLyByb3dzICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGNvbnN0cnVjdCBhbGwgb2YgdGhlIGZhY2VzXG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvbHM7IGkgKysgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgMiAqICggY29scyAtIGkgKSAtIDE7IGogKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBrID0gTWF0aC5mbG9vciggaiAvIDIgKTtcblxuXHRcdFx0XHRcdGlmICggaiAlIDIgPT09IDAgKSB7XG5cblx0XHRcdFx0XHRcdHB1c2hWZXJ0ZXgoIHZbIGkgXVsgayArIDEgXSApO1xuXHRcdFx0XHRcdFx0cHVzaFZlcnRleCggdlsgaSArIDEgXVsgayBdICk7XG5cdFx0XHRcdFx0XHRwdXNoVmVydGV4KCB2WyBpIF1bIGsgXSApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0cHVzaFZlcnRleCggdlsgaSBdWyBrICsgMSBdICk7XG5cdFx0XHRcdFx0XHRwdXNoVmVydGV4KCB2WyBpICsgMSBdWyBrICsgMSBdICk7XG5cdFx0XHRcdFx0XHRwdXNoVmVydGV4KCB2WyBpICsgMSBdWyBrIF0gKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGFwcGx5UmFkaXVzKCByYWRpdXMgKSB7XG5cblx0XHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRcdC8vIGl0ZXJhdGUgb3ZlciB0aGUgZW50aXJlIGJ1ZmZlciBhbmQgYXBwbHkgdGhlIHJhZGl1cyB0byBlYWNoIHZlcnRleFxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2ZXJ0ZXhCdWZmZXIubGVuZ3RoOyBpICs9IDMgKSB7XG5cblx0XHRcdFx0dmVydGV4LnggPSB2ZXJ0ZXhCdWZmZXJbIGkgKyAwIF07XG5cdFx0XHRcdHZlcnRleC55ID0gdmVydGV4QnVmZmVyWyBpICsgMSBdO1xuXHRcdFx0XHR2ZXJ0ZXgueiA9IHZlcnRleEJ1ZmZlclsgaSArIDIgXTtcblxuXHRcdFx0XHR2ZXJ0ZXgubm9ybWFsaXplKCkubXVsdGlwbHlTY2FsYXIoIHJhZGl1cyApO1xuXG5cdFx0XHRcdHZlcnRleEJ1ZmZlclsgaSArIDAgXSA9IHZlcnRleC54O1xuXHRcdFx0XHR2ZXJ0ZXhCdWZmZXJbIGkgKyAxIF0gPSB2ZXJ0ZXgueTtcblx0XHRcdFx0dmVydGV4QnVmZmVyWyBpICsgMiBdID0gdmVydGV4Lno7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlVVZzKCkge1xuXG5cdFx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB2ZXJ0ZXhCdWZmZXIubGVuZ3RoOyBpICs9IDMgKSB7XG5cblx0XHRcdFx0dmVydGV4LnggPSB2ZXJ0ZXhCdWZmZXJbIGkgKyAwIF07XG5cdFx0XHRcdHZlcnRleC55ID0gdmVydGV4QnVmZmVyWyBpICsgMSBdO1xuXHRcdFx0XHR2ZXJ0ZXgueiA9IHZlcnRleEJ1ZmZlclsgaSArIDIgXTtcblxuXHRcdFx0XHRjb25zdCB1ID0gYXppbXV0aCggdmVydGV4ICkgLyAyIC8gTWF0aC5QSSArIDAuNTtcblx0XHRcdFx0Y29uc3QgdiA9IGluY2xpbmF0aW9uKCB2ZXJ0ZXggKSAvIE1hdGguUEkgKyAwLjU7XG5cdFx0XHRcdHV2QnVmZmVyLnB1c2goIHUsIDEgLSB2ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Y29ycmVjdFVWcygpO1xuXG5cdFx0XHRjb3JyZWN0U2VhbSgpO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gY29ycmVjdFNlYW0oKSB7XG5cblx0XHRcdC8vIGhhbmRsZSBjYXNlIHdoZW4gZmFjZSBzdHJhZGRsZXMgdGhlIHNlYW0sIHNlZSAjMzI2OVxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB1dkJ1ZmZlci5sZW5ndGg7IGkgKz0gNiApIHtcblxuXHRcdFx0XHQvLyB1diBkYXRhIG9mIGEgc2luZ2xlIGZhY2VcblxuXHRcdFx0XHRjb25zdCB4MCA9IHV2QnVmZmVyWyBpICsgMCBdO1xuXHRcdFx0XHRjb25zdCB4MSA9IHV2QnVmZmVyWyBpICsgMiBdO1xuXHRcdFx0XHRjb25zdCB4MiA9IHV2QnVmZmVyWyBpICsgNCBdO1xuXG5cdFx0XHRcdGNvbnN0IG1heCA9IE1hdGgubWF4KCB4MCwgeDEsIHgyICk7XG5cdFx0XHRcdGNvbnN0IG1pbiA9IE1hdGgubWluKCB4MCwgeDEsIHgyICk7XG5cblx0XHRcdFx0Ly8gMC45IGlzIHNvbWV3aGF0IGFyYml0cmFyeVxuXG5cdFx0XHRcdGlmICggbWF4ID4gMC45ICYmIG1pbiA8IDAuMSApIHtcblxuXHRcdFx0XHRcdGlmICggeDAgPCAwLjIgKSB1dkJ1ZmZlclsgaSArIDAgXSArPSAxO1xuXHRcdFx0XHRcdGlmICggeDEgPCAwLjIgKSB1dkJ1ZmZlclsgaSArIDIgXSArPSAxO1xuXHRcdFx0XHRcdGlmICggeDIgPCAwLjIgKSB1dkJ1ZmZlclsgaSArIDQgXSArPSAxO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gcHVzaFZlcnRleCggdmVydGV4ICkge1xuXG5cdFx0XHR2ZXJ0ZXhCdWZmZXIucHVzaCggdmVydGV4LngsIHZlcnRleC55LCB2ZXJ0ZXgueiApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gZ2V0VmVydGV4QnlJbmRleCggaW5kZXgsIHZlcnRleCApIHtcblxuXHRcdFx0Y29uc3Qgc3RyaWRlID0gaW5kZXggKiAzO1xuXG5cdFx0XHR2ZXJ0ZXgueCA9IHZlcnRpY2VzWyBzdHJpZGUgKyAwIF07XG5cdFx0XHR2ZXJ0ZXgueSA9IHZlcnRpY2VzWyBzdHJpZGUgKyAxIF07XG5cdFx0XHR2ZXJ0ZXgueiA9IHZlcnRpY2VzWyBzdHJpZGUgKyAyIF07XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBjb3JyZWN0VVZzKCkge1xuXG5cdFx0XHRjb25zdCBhID0gbmV3IFZlY3RvcjMoKTtcblx0XHRcdGNvbnN0IGIgPSBuZXcgVmVjdG9yMygpO1xuXHRcdFx0Y29uc3QgYyA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRcdGNvbnN0IGNlbnRyb2lkID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdFx0Y29uc3QgdXZBID0gbmV3IFZlY3RvcjIoKTtcblx0XHRcdGNvbnN0IHV2QiA9IG5ldyBWZWN0b3IyKCk7XG5cdFx0XHRjb25zdCB1dkMgPSBuZXcgVmVjdG9yMigpO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGogPSAwOyBpIDwgdmVydGV4QnVmZmVyLmxlbmd0aDsgaSArPSA5LCBqICs9IDYgKSB7XG5cblx0XHRcdFx0YS5zZXQoIHZlcnRleEJ1ZmZlclsgaSArIDAgXSwgdmVydGV4QnVmZmVyWyBpICsgMSBdLCB2ZXJ0ZXhCdWZmZXJbIGkgKyAyIF0gKTtcblx0XHRcdFx0Yi5zZXQoIHZlcnRleEJ1ZmZlclsgaSArIDMgXSwgdmVydGV4QnVmZmVyWyBpICsgNCBdLCB2ZXJ0ZXhCdWZmZXJbIGkgKyA1IF0gKTtcblx0XHRcdFx0Yy5zZXQoIHZlcnRleEJ1ZmZlclsgaSArIDYgXSwgdmVydGV4QnVmZmVyWyBpICsgNyBdLCB2ZXJ0ZXhCdWZmZXJbIGkgKyA4IF0gKTtcblxuXHRcdFx0XHR1dkEuc2V0KCB1dkJ1ZmZlclsgaiArIDAgXSwgdXZCdWZmZXJbIGogKyAxIF0gKTtcblx0XHRcdFx0dXZCLnNldCggdXZCdWZmZXJbIGogKyAyIF0sIHV2QnVmZmVyWyBqICsgMyBdICk7XG5cdFx0XHRcdHV2Qy5zZXQoIHV2QnVmZmVyWyBqICsgNCBdLCB1dkJ1ZmZlclsgaiArIDUgXSApO1xuXG5cdFx0XHRcdGNlbnRyb2lkLmNvcHkoIGEgKS5hZGQoIGIgKS5hZGQoIGMgKS5kaXZpZGVTY2FsYXIoIDMgKTtcblxuXHRcdFx0XHRjb25zdCBhemkgPSBhemltdXRoKCBjZW50cm9pZCApO1xuXG5cdFx0XHRcdGNvcnJlY3RVViggdXZBLCBqICsgMCwgYSwgYXppICk7XG5cdFx0XHRcdGNvcnJlY3RVViggdXZCLCBqICsgMiwgYiwgYXppICk7XG5cdFx0XHRcdGNvcnJlY3RVViggdXZDLCBqICsgNCwgYywgYXppICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGNvcnJlY3RVViggdXYsIHN0cmlkZSwgdmVjdG9yLCBhemltdXRoICkge1xuXG5cdFx0XHRpZiAoICggYXppbXV0aCA8IDAgKSAmJiAoIHV2LnggPT09IDEgKSApIHtcblxuXHRcdFx0XHR1dkJ1ZmZlclsgc3RyaWRlIF0gPSB1di54IC0gMTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICggdmVjdG9yLnggPT09IDAgKSAmJiAoIHZlY3Rvci56ID09PSAwICkgKSB7XG5cblx0XHRcdFx0dXZCdWZmZXJbIHN0cmlkZSBdID0gYXppbXV0aCAvIDIgLyBNYXRoLlBJICsgMC41O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBBbmdsZSBhcm91bmQgdGhlIFkgYXhpcywgY291bnRlci1jbG9ja3dpc2Ugd2hlbiBsb29raW5nIGZyb20gYWJvdmUuXG5cblx0XHRmdW5jdGlvbiBhemltdXRoKCB2ZWN0b3IgKSB7XG5cblx0XHRcdHJldHVybiBNYXRoLmF0YW4yKCB2ZWN0b3IueiwgLSB2ZWN0b3IueCApO1xuXG5cdFx0fVxuXG5cblx0XHQvLyBBbmdsZSBhYm92ZSB0aGUgWFogcGxhbmUuXG5cblx0XHRmdW5jdGlvbiBpbmNsaW5hdGlvbiggdmVjdG9yICkge1xuXG5cdFx0XHRyZXR1cm4gTWF0aC5hdGFuMiggLSB2ZWN0b3IueSwgTWF0aC5zcXJ0KCAoIHZlY3Rvci54ICogdmVjdG9yLnggKSArICggdmVjdG9yLnogKiB2ZWN0b3IueiApICkgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IFBvbHloZWRyb25HZW9tZXRyeSggZGF0YS52ZXJ0aWNlcywgZGF0YS5pbmRpY2VzLCBkYXRhLnJhZGl1cywgZGF0YS5kZXRhaWxzICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIERvZGVjYWhlZHJvbkdlb21ldHJ5IGV4dGVuZHMgUG9seWhlZHJvbkdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgZGV0YWlsID0gMCApIHtcblxuXHRcdGNvbnN0IHQgPSAoIDEgKyBNYXRoLnNxcnQoIDUgKSApIC8gMjtcblx0XHRjb25zdCByID0gMSAvIHQ7XG5cblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtcblxuXHRcdFx0Ly8gKMKxMSwgwrExLCDCsTEpXG5cdFx0XHQtIDEsIC0gMSwgLSAxLFx0LSAxLCAtIDEsIDEsXG5cdFx0XHQtIDEsIDEsIC0gMSwgLSAxLCAxLCAxLFxuXHRcdFx0MSwgLSAxLCAtIDEsIDEsIC0gMSwgMSxcblx0XHRcdDEsIDEsIC0gMSwgMSwgMSwgMSxcblxuXHRcdFx0Ly8gKDAsIMKxMS/PhiwgwrHPhilcblx0XHRcdDAsIC0gciwgLSB0LCAwLCAtIHIsIHQsXG5cdFx0XHQwLCByLCAtIHQsIDAsIHIsIHQsXG5cblx0XHRcdC8vICjCsTEvz4YsIMKxz4YsIDApXG5cdFx0XHQtIHIsIC0gdCwgMCwgLSByLCB0LCAwLFxuXHRcdFx0ciwgLSB0LCAwLCByLCB0LCAwLFxuXG5cdFx0XHQvLyAowrHPhiwgMCwgwrExL8+GKVxuXHRcdFx0LSB0LCAwLCAtIHIsIHQsIDAsIC0gcixcblx0XHRcdC0gdCwgMCwgciwgdCwgMCwgclxuXHRcdF07XG5cblx0XHRjb25zdCBpbmRpY2VzID0gW1xuXHRcdFx0MywgMTEsIDcsIFx0MywgNywgMTUsIFx0MywgMTUsIDEzLFxuXHRcdFx0NywgMTksIDE3LCBcdDcsIDE3LCA2LCBcdDcsIDYsIDE1LFxuXHRcdFx0MTcsIDQsIDgsIFx0MTcsIDgsIDEwLCBcdDE3LCAxMCwgNixcblx0XHRcdDgsIDAsIDE2LCBcdDgsIDE2LCAyLCBcdDgsIDIsIDEwLFxuXHRcdFx0MCwgMTIsIDEsIFx0MCwgMSwgMTgsIFx0MCwgMTgsIDE2LFxuXHRcdFx0NiwgMTAsIDIsIFx0NiwgMiwgMTMsIFx0NiwgMTMsIDE1LFxuXHRcdFx0MiwgMTYsIDE4LCBcdDIsIDE4LCAzLCBcdDIsIDMsIDEzLFxuXHRcdFx0MTgsIDEsIDksIFx0MTgsIDksIDExLCBcdDE4LCAxMSwgMyxcblx0XHRcdDQsIDE0LCAxMiwgXHQ0LCAxMiwgMCwgXHQ0LCAwLCA4LFxuXHRcdFx0MTEsIDksIDUsIFx0MTEsIDUsIDE5LCBcdDExLCAxOSwgNyxcblx0XHRcdDE5LCA1LCAxNCwgXHQxOSwgMTQsIDQsIFx0MTksIDQsIDE3LFxuXHRcdFx0MSwgMTIsIDE0LCBcdDEsIDE0LCA1LCBcdDEsIDUsIDlcblx0XHRdO1xuXG5cdFx0c3VwZXIoIHZlcnRpY2VzLCBpbmRpY2VzLCByYWRpdXMsIGRldGFpbCApO1xuXG5cdFx0dGhpcy50eXBlID0gJ0RvZGVjYWhlZHJvbkdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHJhZGl1czogcmFkaXVzLFxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcblx0XHR9O1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IERvZGVjYWhlZHJvbkdlb21ldHJ5KCBkYXRhLnJhZGl1cywgZGF0YS5kZXRhaWwgKTtcblxuXHR9XG5cbn1cblxuY29uc3QgX3YwID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3YxJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfbm9ybWFsID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3RyaWFuZ2xlID0gLypAX19QVVJFX18qLyBuZXcgVHJpYW5nbGUoKTtcblxuY2xhc3MgRWRnZXNHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnkgPSBudWxsLCB0aHJlc2hvbGRBbmdsZSA9IDEgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ0VkZ2VzR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0Z2VvbWV0cnk6IGdlb21ldHJ5LFxuXHRcdFx0dGhyZXNob2xkQW5nbGU6IHRocmVzaG9sZEFuZ2xlXG5cdFx0fTtcblxuXHRcdGlmICggZ2VvbWV0cnkgIT09IG51bGwgKSB7XG5cblx0XHRcdGNvbnN0IHByZWNpc2lvblBvaW50cyA9IDQ7XG5cdFx0XHRjb25zdCBwcmVjaXNpb24gPSBNYXRoLnBvdyggMTAsIHByZWNpc2lvblBvaW50cyApO1xuXHRcdFx0Y29uc3QgdGhyZXNob2xkRG90ID0gTWF0aC5jb3MoIERFRzJSQUQgKiB0aHJlc2hvbGRBbmdsZSApO1xuXG5cdFx0XHRjb25zdCBpbmRleEF0dHIgPSBnZW9tZXRyeS5nZXRJbmRleCgpO1xuXHRcdFx0Y29uc3QgcG9zaXRpb25BdHRyID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XG5cdFx0XHRjb25zdCBpbmRleENvdW50ID0gaW5kZXhBdHRyID8gaW5kZXhBdHRyLmNvdW50IDogcG9zaXRpb25BdHRyLmNvdW50O1xuXG5cdFx0XHRjb25zdCBpbmRleEFyciA9IFsgMCwgMCwgMCBdO1xuXHRcdFx0Y29uc3QgdmVydEtleXMgPSBbICdhJywgJ2InLCAnYycgXTtcblx0XHRcdGNvbnN0IGhhc2hlcyA9IG5ldyBBcnJheSggMyApO1xuXG5cdFx0XHRjb25zdCBlZGdlRGF0YSA9IHt9O1xuXHRcdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGluZGV4Q291bnQ7IGkgKz0gMyApIHtcblxuXHRcdFx0XHRpZiAoIGluZGV4QXR0ciApIHtcblxuXHRcdFx0XHRcdGluZGV4QXJyWyAwIF0gPSBpbmRleEF0dHIuZ2V0WCggaSApO1xuXHRcdFx0XHRcdGluZGV4QXJyWyAxIF0gPSBpbmRleEF0dHIuZ2V0WCggaSArIDEgKTtcblx0XHRcdFx0XHRpbmRleEFyclsgMiBdID0gaW5kZXhBdHRyLmdldFgoIGkgKyAyICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGluZGV4QXJyWyAwIF0gPSBpO1xuXHRcdFx0XHRcdGluZGV4QXJyWyAxIF0gPSBpICsgMTtcblx0XHRcdFx0XHRpbmRleEFyclsgMiBdID0gaSArIDI7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNvbnN0IHsgYSwgYiwgYyB9ID0gX3RyaWFuZ2xlO1xuXHRcdFx0XHRhLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0ciwgaW5kZXhBcnJbIDAgXSApO1xuXHRcdFx0XHRiLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0ciwgaW5kZXhBcnJbIDEgXSApO1xuXHRcdFx0XHRjLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0ciwgaW5kZXhBcnJbIDIgXSApO1xuXHRcdFx0XHRfdHJpYW5nbGUuZ2V0Tm9ybWFsKCBfbm9ybWFsICk7XG5cblx0XHRcdFx0Ly8gY3JlYXRlIGhhc2hlcyBmb3IgdGhlIGVkZ2UgZnJvbSB0aGUgdmVydGljZXNcblx0XHRcdFx0aGFzaGVzWyAwIF0gPSBgJHsgTWF0aC5yb3VuZCggYS54ICogcHJlY2lzaW9uICkgfSwkeyBNYXRoLnJvdW5kKCBhLnkgKiBwcmVjaXNpb24gKSB9LCR7IE1hdGgucm91bmQoIGEueiAqIHByZWNpc2lvbiApIH1gO1xuXHRcdFx0XHRoYXNoZXNbIDEgXSA9IGAkeyBNYXRoLnJvdW5kKCBiLnggKiBwcmVjaXNpb24gKSB9LCR7IE1hdGgucm91bmQoIGIueSAqIHByZWNpc2lvbiApIH0sJHsgTWF0aC5yb3VuZCggYi56ICogcHJlY2lzaW9uICkgfWA7XG5cdFx0XHRcdGhhc2hlc1sgMiBdID0gYCR7IE1hdGgucm91bmQoIGMueCAqIHByZWNpc2lvbiApIH0sJHsgTWF0aC5yb3VuZCggYy55ICogcHJlY2lzaW9uICkgfSwkeyBNYXRoLnJvdW5kKCBjLnogKiBwcmVjaXNpb24gKSB9YDtcblxuXHRcdFx0XHQvLyBza2lwIGRlZ2VuZXJhdGUgdHJpYW5nbGVzXG5cdFx0XHRcdGlmICggaGFzaGVzWyAwIF0gPT09IGhhc2hlc1sgMSBdIHx8IGhhc2hlc1sgMSBdID09PSBoYXNoZXNbIDIgXSB8fCBoYXNoZXNbIDIgXSA9PT0gaGFzaGVzWyAwIF0gKSB7XG5cblx0XHRcdFx0XHRjb250aW51ZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gaXRlcmF0ZSBvdmVyIGV2ZXJ5IGVkZ2Vcblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgMzsgaiArKyApIHtcblxuXHRcdFx0XHRcdC8vIGdldCB0aGUgZmlyc3QgYW5kIG5leHQgdmVydGV4IG1ha2luZyB1cCB0aGUgZWRnZVxuXHRcdFx0XHRcdGNvbnN0IGpOZXh0ID0gKCBqICsgMSApICUgMztcblx0XHRcdFx0XHRjb25zdCB2ZWNIYXNoMCA9IGhhc2hlc1sgaiBdO1xuXHRcdFx0XHRcdGNvbnN0IHZlY0hhc2gxID0gaGFzaGVzWyBqTmV4dCBdO1xuXHRcdFx0XHRcdGNvbnN0IHYwID0gX3RyaWFuZ2xlWyB2ZXJ0S2V5c1sgaiBdIF07XG5cdFx0XHRcdFx0Y29uc3QgdjEgPSBfdHJpYW5nbGVbIHZlcnRLZXlzWyBqTmV4dCBdIF07XG5cblx0XHRcdFx0XHRjb25zdCBoYXNoID0gYCR7IHZlY0hhc2gwIH1fJHsgdmVjSGFzaDEgfWA7XG5cdFx0XHRcdFx0Y29uc3QgcmV2ZXJzZUhhc2ggPSBgJHsgdmVjSGFzaDEgfV8keyB2ZWNIYXNoMCB9YDtcblxuXHRcdFx0XHRcdGlmICggcmV2ZXJzZUhhc2ggaW4gZWRnZURhdGEgJiYgZWRnZURhdGFbIHJldmVyc2VIYXNoIF0gKSB7XG5cblx0XHRcdFx0XHRcdC8vIGlmIHdlIGZvdW5kIGEgc2libGluZyBlZGdlIGFkZCBpdCBpbnRvIHRoZSB2ZXJ0ZXggYXJyYXkgaWZcblx0XHRcdFx0XHRcdC8vIGl0IG1lZXRzIHRoZSBhbmdsZSB0aHJlc2hvbGQgYW5kIGRlbGV0ZSB0aGUgZWRnZSBmcm9tIHRoZSBtYXAuXG5cdFx0XHRcdFx0XHRpZiAoIF9ub3JtYWwuZG90KCBlZGdlRGF0YVsgcmV2ZXJzZUhhc2ggXS5ub3JtYWwgKSA8PSB0aHJlc2hvbGREb3QgKSB7XG5cblx0XHRcdFx0XHRcdFx0dmVydGljZXMucHVzaCggdjAueCwgdjAueSwgdjAueiApO1xuXHRcdFx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2MS54LCB2MS55LCB2MS56ICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0ZWRnZURhdGFbIHJldmVyc2VIYXNoIF0gPSBudWxsO1xuXG5cdFx0XHRcdFx0fSBlbHNlIGlmICggISAoIGhhc2ggaW4gZWRnZURhdGEgKSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gaWYgd2UndmUgYWxyZWFkeSBnb3QgYW4gZWRnZSBoZXJlIHRoZW4gc2tpcCBhZGRpbmcgYSBuZXcgb25lXG5cdFx0XHRcdFx0XHRlZGdlRGF0YVsgaGFzaCBdID0ge1xuXG5cdFx0XHRcdFx0XHRcdGluZGV4MDogaW5kZXhBcnJbIGogXSxcblx0XHRcdFx0XHRcdFx0aW5kZXgxOiBpbmRleEFyclsgak5leHQgXSxcblx0XHRcdFx0XHRcdFx0bm9ybWFsOiBfbm9ybWFsLmNsb25lKCksXG5cblx0XHRcdFx0XHRcdH07XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGl0ZXJhdGUgb3ZlciBhbGwgcmVtYWluaW5nLCB1bm1hdGNoZWQgZWRnZXMgYW5kIGFkZCB0aGVtIHRvIHRoZSB2ZXJ0ZXggYXJyYXlcblx0XHRcdGZvciAoIGNvbnN0IGtleSBpbiBlZGdlRGF0YSApIHtcblxuXHRcdFx0XHRpZiAoIGVkZ2VEYXRhWyBrZXkgXSApIHtcblxuXHRcdFx0XHRcdGNvbnN0IHsgaW5kZXgwLCBpbmRleDEgfSA9IGVkZ2VEYXRhWyBrZXkgXTtcblx0XHRcdFx0XHRfdjAuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyLCBpbmRleDAgKTtcblx0XHRcdFx0XHRfdjEkMS5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHIsIGluZGV4MSApO1xuXG5cdFx0XHRcdFx0dmVydGljZXMucHVzaCggX3YwLngsIF92MC55LCBfdjAueiApO1xuXHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIF92MSQxLngsIF92MSQxLnksIF92MSQxLnogKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgU2hhcGUgZXh0ZW5kcyBQYXRoIHtcblxuXHRjb25zdHJ1Y3RvciggcG9pbnRzICkge1xuXG5cdFx0c3VwZXIoIHBvaW50cyApO1xuXG5cdFx0dGhpcy51dWlkID0gZ2VuZXJhdGVVVUlEKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnU2hhcGUnO1xuXG5cdFx0dGhpcy5ob2xlcyA9IFtdO1xuXG5cdH1cblxuXHRnZXRQb2ludHNIb2xlcyggZGl2aXNpb25zICkge1xuXG5cdFx0Y29uc3QgaG9sZXNQdHMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuaG9sZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0aG9sZXNQdHNbIGkgXSA9IHRoaXMuaG9sZXNbIGkgXS5nZXRQb2ludHMoIGRpdmlzaW9ucyApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGhvbGVzUHRzO1xuXG5cdH1cblxuXHQvLyBnZXQgcG9pbnRzIG9mIHNoYXBlIGFuZCBob2xlcyAoa2V5cG9pbnRzIGJhc2VkIG9uIHNlZ21lbnRzIHBhcmFtZXRlcilcblxuXHRleHRyYWN0UG9pbnRzKCBkaXZpc2lvbnMgKSB7XG5cblx0XHRyZXR1cm4ge1xuXG5cdFx0XHRzaGFwZTogdGhpcy5nZXRQb2ludHMoIGRpdmlzaW9ucyApLFxuXHRcdFx0aG9sZXM6IHRoaXMuZ2V0UG9pbnRzSG9sZXMoIGRpdmlzaW9ucyApXG5cblx0XHR9O1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuaG9sZXMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNvdXJjZS5ob2xlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBob2xlID0gc291cmNlLmhvbGVzWyBpIF07XG5cblx0XHRcdHRoaXMuaG9sZXMucHVzaCggaG9sZS5jbG9uZSgpICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS51dWlkID0gdGhpcy51dWlkO1xuXHRcdGRhdGEuaG9sZXMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuaG9sZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgaG9sZSA9IHRoaXMuaG9sZXNbIGkgXTtcblx0XHRcdGRhdGEuaG9sZXMucHVzaCggaG9sZS50b0pTT04oKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdGZyb21KU09OKCBqc29uICkge1xuXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcblxuXHRcdHRoaXMudXVpZCA9IGpzb24udXVpZDtcblx0XHR0aGlzLmhvbGVzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmhvbGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGhvbGUgPSBqc29uLmhvbGVzWyBpIF07XG5cdFx0XHR0aGlzLmhvbGVzLnB1c2goIG5ldyBQYXRoKCkuZnJvbUpTT04oIGhvbGUgKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbi8qKlxuICogUG9ydCBmcm9tIGh0dHBzOi8vZ2l0aHViLmNvbS9tYXBib3gvZWFyY3V0ICh2Mi4yLjQpXG4gKi9cblxuY29uc3QgRWFyY3V0ID0ge1xuXG5cdHRyaWFuZ3VsYXRlOiBmdW5jdGlvbiAoIGRhdGEsIGhvbGVJbmRpY2VzLCBkaW0gPSAyICkge1xuXG5cdFx0Y29uc3QgaGFzSG9sZXMgPSBob2xlSW5kaWNlcyAmJiBob2xlSW5kaWNlcy5sZW5ndGg7XG5cdFx0Y29uc3Qgb3V0ZXJMZW4gPSBoYXNIb2xlcyA/IGhvbGVJbmRpY2VzWyAwIF0gKiBkaW0gOiBkYXRhLmxlbmd0aDtcblx0XHRsZXQgb3V0ZXJOb2RlID0gbGlua2VkTGlzdCggZGF0YSwgMCwgb3V0ZXJMZW4sIGRpbSwgdHJ1ZSApO1xuXHRcdGNvbnN0IHRyaWFuZ2xlcyA9IFtdO1xuXG5cdFx0aWYgKCAhIG91dGVyTm9kZSB8fCBvdXRlck5vZGUubmV4dCA9PT0gb3V0ZXJOb2RlLnByZXYgKSByZXR1cm4gdHJpYW5nbGVzO1xuXG5cdFx0bGV0IG1pblgsIG1pblksIG1heFgsIG1heFksIHgsIHksIGludlNpemU7XG5cblx0XHRpZiAoIGhhc0hvbGVzICkgb3V0ZXJOb2RlID0gZWxpbWluYXRlSG9sZXMoIGRhdGEsIGhvbGVJbmRpY2VzLCBvdXRlck5vZGUsIGRpbSApO1xuXG5cdFx0Ly8gaWYgdGhlIHNoYXBlIGlzIG5vdCB0b28gc2ltcGxlLCB3ZSdsbCB1c2Ugei1vcmRlciBjdXJ2ZSBoYXNoIGxhdGVyOyBjYWxjdWxhdGUgcG9seWdvbiBiYm94XG5cdFx0aWYgKCBkYXRhLmxlbmd0aCA+IDgwICogZGltICkge1xuXG5cdFx0XHRtaW5YID0gbWF4WCA9IGRhdGFbIDAgXTtcblx0XHRcdG1pblkgPSBtYXhZID0gZGF0YVsgMSBdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IGRpbTsgaSA8IG91dGVyTGVuOyBpICs9IGRpbSApIHtcblxuXHRcdFx0XHR4ID0gZGF0YVsgaSBdO1xuXHRcdFx0XHR5ID0gZGF0YVsgaSArIDEgXTtcblx0XHRcdFx0aWYgKCB4IDwgbWluWCApIG1pblggPSB4O1xuXHRcdFx0XHRpZiAoIHkgPCBtaW5ZICkgbWluWSA9IHk7XG5cdFx0XHRcdGlmICggeCA+IG1heFggKSBtYXhYID0geDtcblx0XHRcdFx0aWYgKCB5ID4gbWF4WSApIG1heFkgPSB5O1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIG1pblgsIG1pblkgYW5kIGludlNpemUgYXJlIGxhdGVyIHVzZWQgdG8gdHJhbnNmb3JtIGNvb3JkcyBpbnRvIGludGVnZXJzIGZvciB6LW9yZGVyIGNhbGN1bGF0aW9uXG5cdFx0XHRpbnZTaXplID0gTWF0aC5tYXgoIG1heFggLSBtaW5YLCBtYXhZIC0gbWluWSApO1xuXHRcdFx0aW52U2l6ZSA9IGludlNpemUgIT09IDAgPyAzMjc2NyAvIGludlNpemUgOiAwO1xuXG5cdFx0fVxuXG5cdFx0ZWFyY3V0TGlua2VkKCBvdXRlck5vZGUsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAwICk7XG5cblx0XHRyZXR1cm4gdHJpYW5nbGVzO1xuXG5cdH1cblxufTtcblxuLy8gY3JlYXRlIGEgY2lyY3VsYXIgZG91Ymx5IGxpbmtlZCBsaXN0IGZyb20gcG9seWdvbiBwb2ludHMgaW4gdGhlIHNwZWNpZmllZCB3aW5kaW5nIG9yZGVyXG5mdW5jdGlvbiBsaW5rZWRMaXN0KCBkYXRhLCBzdGFydCwgZW5kLCBkaW0sIGNsb2Nrd2lzZSApIHtcblxuXHRsZXQgaSwgbGFzdDtcblxuXHRpZiAoIGNsb2Nrd2lzZSA9PT0gKCBzaWduZWRBcmVhKCBkYXRhLCBzdGFydCwgZW5kLCBkaW0gKSA+IDAgKSApIHtcblxuXHRcdGZvciAoIGkgPSBzdGFydDsgaSA8IGVuZDsgaSArPSBkaW0gKSBsYXN0ID0gaW5zZXJ0Tm9kZSggaSwgZGF0YVsgaSBdLCBkYXRhWyBpICsgMSBdLCBsYXN0ICk7XG5cblx0fSBlbHNlIHtcblxuXHRcdGZvciAoIGkgPSBlbmQgLSBkaW07IGkgPj0gc3RhcnQ7IGkgLT0gZGltICkgbGFzdCA9IGluc2VydE5vZGUoIGksIGRhdGFbIGkgXSwgZGF0YVsgaSArIDEgXSwgbGFzdCApO1xuXG5cdH1cblxuXHRpZiAoIGxhc3QgJiYgZXF1YWxzKCBsYXN0LCBsYXN0Lm5leHQgKSApIHtcblxuXHRcdHJlbW92ZU5vZGUoIGxhc3QgKTtcblx0XHRsYXN0ID0gbGFzdC5uZXh0O1xuXG5cdH1cblxuXHRyZXR1cm4gbGFzdDtcblxufVxuXG4vLyBlbGltaW5hdGUgY29saW5lYXIgb3IgZHVwbGljYXRlIHBvaW50c1xuZnVuY3Rpb24gZmlsdGVyUG9pbnRzKCBzdGFydCwgZW5kICkge1xuXG5cdGlmICggISBzdGFydCApIHJldHVybiBzdGFydDtcblx0aWYgKCAhIGVuZCApIGVuZCA9IHN0YXJ0O1xuXG5cdGxldCBwID0gc3RhcnQsXG5cdFx0YWdhaW47XG5cdGRvIHtcblxuXHRcdGFnYWluID0gZmFsc2U7XG5cblx0XHRpZiAoICEgcC5zdGVpbmVyICYmICggZXF1YWxzKCBwLCBwLm5leHQgKSB8fCBhcmVhKCBwLnByZXYsIHAsIHAubmV4dCApID09PSAwICkgKSB7XG5cblx0XHRcdHJlbW92ZU5vZGUoIHAgKTtcblx0XHRcdHAgPSBlbmQgPSBwLnByZXY7XG5cdFx0XHRpZiAoIHAgPT09IHAubmV4dCApIGJyZWFrO1xuXHRcdFx0YWdhaW4gPSB0cnVlO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cCA9IHAubmV4dDtcblxuXHRcdH1cblxuXHR9IHdoaWxlICggYWdhaW4gfHwgcCAhPT0gZW5kICk7XG5cblx0cmV0dXJuIGVuZDtcblxufVxuXG4vLyBtYWluIGVhciBzbGljaW5nIGxvb3Agd2hpY2ggdHJpYW5ndWxhdGVzIGEgcG9seWdvbiAoZ2l2ZW4gYXMgYSBsaW5rZWQgbGlzdClcbmZ1bmN0aW9uIGVhcmN1dExpbmtlZCggZWFyLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSwgcGFzcyApIHtcblxuXHRpZiAoICEgZWFyICkgcmV0dXJuO1xuXG5cdC8vIGludGVybGluayBwb2x5Z29uIG5vZGVzIGluIHotb3JkZXJcblx0aWYgKCAhIHBhc3MgJiYgaW52U2l6ZSApIGluZGV4Q3VydmUoIGVhciwgbWluWCwgbWluWSwgaW52U2l6ZSApO1xuXG5cdGxldCBzdG9wID0gZWFyLFxuXHRcdHByZXYsIG5leHQ7XG5cblx0Ly8gaXRlcmF0ZSB0aHJvdWdoIGVhcnMsIHNsaWNpbmcgdGhlbSBvbmUgYnkgb25lXG5cdHdoaWxlICggZWFyLnByZXYgIT09IGVhci5uZXh0ICkge1xuXG5cdFx0cHJldiA9IGVhci5wcmV2O1xuXHRcdG5leHQgPSBlYXIubmV4dDtcblxuXHRcdGlmICggaW52U2l6ZSA/IGlzRWFySGFzaGVkKCBlYXIsIG1pblgsIG1pblksIGludlNpemUgKSA6IGlzRWFyKCBlYXIgKSApIHtcblxuXHRcdFx0Ly8gY3V0IG9mZiB0aGUgdHJpYW5nbGVcblx0XHRcdHRyaWFuZ2xlcy5wdXNoKCBwcmV2LmkgLyBkaW0gfCAwICk7XG5cdFx0XHR0cmlhbmdsZXMucHVzaCggZWFyLmkgLyBkaW0gfCAwICk7XG5cdFx0XHR0cmlhbmdsZXMucHVzaCggbmV4dC5pIC8gZGltIHwgMCApO1xuXG5cdFx0XHRyZW1vdmVOb2RlKCBlYXIgKTtcblxuXHRcdFx0Ly8gc2tpcHBpbmcgdGhlIG5leHQgdmVydGV4IGxlYWRzIHRvIGxlc3Mgc2xpdmVyIHRyaWFuZ2xlc1xuXHRcdFx0ZWFyID0gbmV4dC5uZXh0O1xuXHRcdFx0c3RvcCA9IG5leHQubmV4dDtcblxuXHRcdFx0Y29udGludWU7XG5cblx0XHR9XG5cblx0XHRlYXIgPSBuZXh0O1xuXG5cdFx0Ly8gaWYgd2UgbG9vcGVkIHRocm91Z2ggdGhlIHdob2xlIHJlbWFpbmluZyBwb2x5Z29uIGFuZCBjYW4ndCBmaW5kIGFueSBtb3JlIGVhcnNcblx0XHRpZiAoIGVhciA9PT0gc3RvcCApIHtcblxuXHRcdFx0Ly8gdHJ5IGZpbHRlcmluZyBwb2ludHMgYW5kIHNsaWNpbmcgYWdhaW5cblx0XHRcdGlmICggISBwYXNzICkge1xuXG5cdFx0XHRcdGVhcmN1dExpbmtlZCggZmlsdGVyUG9pbnRzKCBlYXIgKSwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUsIDEgKTtcblxuXHRcdFx0XHQvLyBpZiB0aGlzIGRpZG4ndCB3b3JrLCB0cnkgY3VyaW5nIGFsbCBzbWFsbCBzZWxmLWludGVyc2VjdGlvbnMgbG9jYWxseVxuXG5cdFx0XHR9IGVsc2UgaWYgKCBwYXNzID09PSAxICkge1xuXG5cdFx0XHRcdGVhciA9IGN1cmVMb2NhbEludGVyc2VjdGlvbnMoIGZpbHRlclBvaW50cyggZWFyICksIHRyaWFuZ2xlcywgZGltICk7XG5cdFx0XHRcdGVhcmN1dExpbmtlZCggZWFyLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSwgMiApO1xuXG5cdFx0XHRcdC8vIGFzIGEgbGFzdCByZXNvcnQsIHRyeSBzcGxpdHRpbmcgdGhlIHJlbWFpbmluZyBwb2x5Z29uIGludG8gdHdvXG5cblx0XHRcdH0gZWxzZSBpZiAoIHBhc3MgPT09IDIgKSB7XG5cblx0XHRcdFx0c3BsaXRFYXJjdXQoIGVhciwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRicmVhaztcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuLy8gY2hlY2sgd2hldGhlciBhIHBvbHlnb24gbm9kZSBmb3JtcyBhIHZhbGlkIGVhciB3aXRoIGFkamFjZW50IG5vZGVzXG5mdW5jdGlvbiBpc0VhciggZWFyICkge1xuXG5cdGNvbnN0IGEgPSBlYXIucHJldixcblx0XHRiID0gZWFyLFxuXHRcdGMgPSBlYXIubmV4dDtcblxuXHRpZiAoIGFyZWEoIGEsIGIsIGMgKSA+PSAwICkgcmV0dXJuIGZhbHNlOyAvLyByZWZsZXgsIGNhbid0IGJlIGFuIGVhclxuXG5cdC8vIG5vdyBtYWtlIHN1cmUgd2UgZG9uJ3QgaGF2ZSBvdGhlciBwb2ludHMgaW5zaWRlIHRoZSBwb3RlbnRpYWwgZWFyXG5cdGNvbnN0IGF4ID0gYS54LCBieCA9IGIueCwgY3ggPSBjLngsIGF5ID0gYS55LCBieSA9IGIueSwgY3kgPSBjLnk7XG5cblx0Ly8gdHJpYW5nbGUgYmJveDsgbWluICYgbWF4IGFyZSBjYWxjdWxhdGVkIGxpa2UgdGhpcyBmb3Igc3BlZWRcblx0Y29uc3QgeDAgPSBheCA8IGJ4ID8gKCBheCA8IGN4ID8gYXggOiBjeCApIDogKCBieCA8IGN4ID8gYnggOiBjeCApLFxuXHRcdHkwID0gYXkgPCBieSA/ICggYXkgPCBjeSA/IGF5IDogY3kgKSA6ICggYnkgPCBjeSA/IGJ5IDogY3kgKSxcblx0XHR4MSA9IGF4ID4gYnggPyAoIGF4ID4gY3ggPyBheCA6IGN4ICkgOiAoIGJ4ID4gY3ggPyBieCA6IGN4ICksXG5cdFx0eTEgPSBheSA+IGJ5ID8gKCBheSA+IGN5ID8gYXkgOiBjeSApIDogKCBieSA+IGN5ID8gYnkgOiBjeSApO1xuXG5cdGxldCBwID0gYy5uZXh0O1xuXHR3aGlsZSAoIHAgIT09IGEgKSB7XG5cblx0XHRpZiAoIHAueCA+PSB4MCAmJiBwLnggPD0geDEgJiYgcC55ID49IHkwICYmIHAueSA8PSB5MSAmJlxuXHRcdFx0cG9pbnRJblRyaWFuZ2xlKCBheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBwLngsIHAueSApICYmXG5cdFx0XHRhcmVhKCBwLnByZXYsIHAsIHAubmV4dCApID49IDAgKSByZXR1cm4gZmFsc2U7XG5cdFx0cCA9IHAubmV4dDtcblxuXHR9XG5cblx0cmV0dXJuIHRydWU7XG5cbn1cblxuZnVuY3Rpb24gaXNFYXJIYXNoZWQoIGVhciwgbWluWCwgbWluWSwgaW52U2l6ZSApIHtcblxuXHRjb25zdCBhID0gZWFyLnByZXYsXG5cdFx0YiA9IGVhcixcblx0XHRjID0gZWFyLm5leHQ7XG5cblx0aWYgKCBhcmVhKCBhLCBiLCBjICkgPj0gMCApIHJldHVybiBmYWxzZTsgLy8gcmVmbGV4LCBjYW4ndCBiZSBhbiBlYXJcblxuXHRjb25zdCBheCA9IGEueCwgYnggPSBiLngsIGN4ID0gYy54LCBheSA9IGEueSwgYnkgPSBiLnksIGN5ID0gYy55O1xuXG5cdC8vIHRyaWFuZ2xlIGJib3g7IG1pbiAmIG1heCBhcmUgY2FsY3VsYXRlZCBsaWtlIHRoaXMgZm9yIHNwZWVkXG5cdGNvbnN0IHgwID0gYXggPCBieCA/ICggYXggPCBjeCA/IGF4IDogY3ggKSA6ICggYnggPCBjeCA/IGJ4IDogY3ggKSxcblx0XHR5MCA9IGF5IDwgYnkgPyAoIGF5IDwgY3kgPyBheSA6IGN5ICkgOiAoIGJ5IDwgY3kgPyBieSA6IGN5ICksXG5cdFx0eDEgPSBheCA+IGJ4ID8gKCBheCA+IGN4ID8gYXggOiBjeCApIDogKCBieCA+IGN4ID8gYnggOiBjeCApLFxuXHRcdHkxID0gYXkgPiBieSA/ICggYXkgPiBjeSA/IGF5IDogY3kgKSA6ICggYnkgPiBjeSA/IGJ5IDogY3kgKTtcblxuXHQvLyB6LW9yZGVyIHJhbmdlIGZvciB0aGUgY3VycmVudCB0cmlhbmdsZSBiYm94O1xuXHRjb25zdCBtaW5aID0gek9yZGVyKCB4MCwgeTAsIG1pblgsIG1pblksIGludlNpemUgKSxcblx0XHRtYXhaID0gek9yZGVyKCB4MSwgeTEsIG1pblgsIG1pblksIGludlNpemUgKTtcblxuXHRsZXQgcCA9IGVhci5wcmV2Wixcblx0XHRuID0gZWFyLm5leHRaO1xuXG5cdC8vIGxvb2sgZm9yIHBvaW50cyBpbnNpZGUgdGhlIHRyaWFuZ2xlIGluIGJvdGggZGlyZWN0aW9uc1xuXHR3aGlsZSAoIHAgJiYgcC56ID49IG1pblogJiYgbiAmJiBuLnogPD0gbWF4WiApIHtcblxuXHRcdGlmICggcC54ID49IHgwICYmIHAueCA8PSB4MSAmJiBwLnkgPj0geTAgJiYgcC55IDw9IHkxICYmIHAgIT09IGEgJiYgcCAhPT0gYyAmJlxuXHRcdFx0cG9pbnRJblRyaWFuZ2xlKCBheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBwLngsIHAueSApICYmIGFyZWEoIHAucHJldiwgcCwgcC5uZXh0ICkgPj0gMCApIHJldHVybiBmYWxzZTtcblx0XHRwID0gcC5wcmV2WjtcblxuXHRcdGlmICggbi54ID49IHgwICYmIG4ueCA8PSB4MSAmJiBuLnkgPj0geTAgJiYgbi55IDw9IHkxICYmIG4gIT09IGEgJiYgbiAhPT0gYyAmJlxuXHRcdFx0cG9pbnRJblRyaWFuZ2xlKCBheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBuLngsIG4ueSApICYmIGFyZWEoIG4ucHJldiwgbiwgbi5uZXh0ICkgPj0gMCApIHJldHVybiBmYWxzZTtcblx0XHRuID0gbi5uZXh0WjtcblxuXHR9XG5cblx0Ly8gbG9vayBmb3IgcmVtYWluaW5nIHBvaW50cyBpbiBkZWNyZWFzaW5nIHotb3JkZXJcblx0d2hpbGUgKCBwICYmIHAueiA+PSBtaW5aICkge1xuXG5cdFx0aWYgKCBwLnggPj0geDAgJiYgcC54IDw9IHgxICYmIHAueSA+PSB5MCAmJiBwLnkgPD0geTEgJiYgcCAhPT0gYSAmJiBwICE9PSBjICYmXG5cdFx0XHRwb2ludEluVHJpYW5nbGUoIGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHAueCwgcC55ICkgJiYgYXJlYSggcC5wcmV2LCBwLCBwLm5leHQgKSA+PSAwICkgcmV0dXJuIGZhbHNlO1xuXHRcdHAgPSBwLnByZXZaO1xuXG5cdH1cblxuXHQvLyBsb29rIGZvciByZW1haW5pbmcgcG9pbnRzIGluIGluY3JlYXNpbmcgei1vcmRlclxuXHR3aGlsZSAoIG4gJiYgbi56IDw9IG1heFogKSB7XG5cblx0XHRpZiAoIG4ueCA+PSB4MCAmJiBuLnggPD0geDEgJiYgbi55ID49IHkwICYmIG4ueSA8PSB5MSAmJiBuICE9PSBhICYmIG4gIT09IGMgJiZcblx0XHRcdHBvaW50SW5UcmlhbmdsZSggYXgsIGF5LCBieCwgYnksIGN4LCBjeSwgbi54LCBuLnkgKSAmJiBhcmVhKCBuLnByZXYsIG4sIG4ubmV4dCApID49IDAgKSByZXR1cm4gZmFsc2U7XG5cdFx0biA9IG4ubmV4dFo7XG5cblx0fVxuXG5cdHJldHVybiB0cnVlO1xuXG59XG5cbi8vIGdvIHRocm91Z2ggYWxsIHBvbHlnb24gbm9kZXMgYW5kIGN1cmUgc21hbGwgbG9jYWwgc2VsZi1pbnRlcnNlY3Rpb25zXG5mdW5jdGlvbiBjdXJlTG9jYWxJbnRlcnNlY3Rpb25zKCBzdGFydCwgdHJpYW5nbGVzLCBkaW0gKSB7XG5cblx0bGV0IHAgPSBzdGFydDtcblx0ZG8ge1xuXG5cdFx0Y29uc3QgYSA9IHAucHJldixcblx0XHRcdGIgPSBwLm5leHQubmV4dDtcblxuXHRcdGlmICggISBlcXVhbHMoIGEsIGIgKSAmJiBpbnRlcnNlY3RzKCBhLCBwLCBwLm5leHQsIGIgKSAmJiBsb2NhbGx5SW5zaWRlKCBhLCBiICkgJiYgbG9jYWxseUluc2lkZSggYiwgYSApICkge1xuXG5cdFx0XHR0cmlhbmdsZXMucHVzaCggYS5pIC8gZGltIHwgMCApO1xuXHRcdFx0dHJpYW5nbGVzLnB1c2goIHAuaSAvIGRpbSB8IDAgKTtcblx0XHRcdHRyaWFuZ2xlcy5wdXNoKCBiLmkgLyBkaW0gfCAwICk7XG5cblx0XHRcdC8vIHJlbW92ZSB0d28gbm9kZXMgaW52b2x2ZWRcblx0XHRcdHJlbW92ZU5vZGUoIHAgKTtcblx0XHRcdHJlbW92ZU5vZGUoIHAubmV4dCApO1xuXG5cdFx0XHRwID0gc3RhcnQgPSBiO1xuXG5cdFx0fVxuXG5cdFx0cCA9IHAubmV4dDtcblxuXHR9IHdoaWxlICggcCAhPT0gc3RhcnQgKTtcblxuXHRyZXR1cm4gZmlsdGVyUG9pbnRzKCBwICk7XG5cbn1cblxuLy8gdHJ5IHNwbGl0dGluZyBwb2x5Z29uIGludG8gdHdvIGFuZCB0cmlhbmd1bGF0ZSB0aGVtIGluZGVwZW5kZW50bHlcbmZ1bmN0aW9uIHNwbGl0RWFyY3V0KCBzdGFydCwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUgKSB7XG5cblx0Ly8gbG9vayBmb3IgYSB2YWxpZCBkaWFnb25hbCB0aGF0IGRpdmlkZXMgdGhlIHBvbHlnb24gaW50byB0d29cblx0bGV0IGEgPSBzdGFydDtcblx0ZG8ge1xuXG5cdFx0bGV0IGIgPSBhLm5leHQubmV4dDtcblx0XHR3aGlsZSAoIGIgIT09IGEucHJldiApIHtcblxuXHRcdFx0aWYgKCBhLmkgIT09IGIuaSAmJiBpc1ZhbGlkRGlhZ29uYWwoIGEsIGIgKSApIHtcblxuXHRcdFx0XHQvLyBzcGxpdCB0aGUgcG9seWdvbiBpbiB0d28gYnkgdGhlIGRpYWdvbmFsXG5cdFx0XHRcdGxldCBjID0gc3BsaXRQb2x5Z29uKCBhLCBiICk7XG5cblx0XHRcdFx0Ly8gZmlsdGVyIGNvbGluZWFyIHBvaW50cyBhcm91bmQgdGhlIGN1dHNcblx0XHRcdFx0YSA9IGZpbHRlclBvaW50cyggYSwgYS5uZXh0ICk7XG5cdFx0XHRcdGMgPSBmaWx0ZXJQb2ludHMoIGMsIGMubmV4dCApO1xuXG5cdFx0XHRcdC8vIHJ1biBlYXJjdXQgb24gZWFjaCBoYWxmXG5cdFx0XHRcdGVhcmN1dExpbmtlZCggYSwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUsIDAgKTtcblx0XHRcdFx0ZWFyY3V0TGlua2VkKCBjLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSwgMCApO1xuXHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdH1cblxuXHRcdFx0YiA9IGIubmV4dDtcblxuXHRcdH1cblxuXHRcdGEgPSBhLm5leHQ7XG5cblx0fSB3aGlsZSAoIGEgIT09IHN0YXJ0ICk7XG5cbn1cblxuLy8gbGluayBldmVyeSBob2xlIGludG8gdGhlIG91dGVyIGxvb3AsIHByb2R1Y2luZyBhIHNpbmdsZS1yaW5nIHBvbHlnb24gd2l0aG91dCBob2xlc1xuZnVuY3Rpb24gZWxpbWluYXRlSG9sZXMoIGRhdGEsIGhvbGVJbmRpY2VzLCBvdXRlck5vZGUsIGRpbSApIHtcblxuXHRjb25zdCBxdWV1ZSA9IFtdO1xuXHRsZXQgaSwgbGVuLCBzdGFydCwgZW5kLCBsaXN0O1xuXG5cdGZvciAoIGkgPSAwLCBsZW4gPSBob2xlSW5kaWNlcy5sZW5ndGg7IGkgPCBsZW47IGkgKysgKSB7XG5cblx0XHRzdGFydCA9IGhvbGVJbmRpY2VzWyBpIF0gKiBkaW07XG5cdFx0ZW5kID0gaSA8IGxlbiAtIDEgPyBob2xlSW5kaWNlc1sgaSArIDEgXSAqIGRpbSA6IGRhdGEubGVuZ3RoO1xuXHRcdGxpc3QgPSBsaW5rZWRMaXN0KCBkYXRhLCBzdGFydCwgZW5kLCBkaW0sIGZhbHNlICk7XG5cdFx0aWYgKCBsaXN0ID09PSBsaXN0Lm5leHQgKSBsaXN0LnN0ZWluZXIgPSB0cnVlO1xuXHRcdHF1ZXVlLnB1c2goIGdldExlZnRtb3N0KCBsaXN0ICkgKTtcblxuXHR9XG5cblx0cXVldWUuc29ydCggY29tcGFyZVggKTtcblxuXHQvLyBwcm9jZXNzIGhvbGVzIGZyb20gbGVmdCB0byByaWdodFxuXHRmb3IgKCBpID0gMDsgaSA8IHF1ZXVlLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdG91dGVyTm9kZSA9IGVsaW1pbmF0ZUhvbGUoIHF1ZXVlWyBpIF0sIG91dGVyTm9kZSApO1xuXG5cdH1cblxuXHRyZXR1cm4gb3V0ZXJOb2RlO1xuXG59XG5cbmZ1bmN0aW9uIGNvbXBhcmVYKCBhLCBiICkge1xuXG5cdHJldHVybiBhLnggLSBiLng7XG5cbn1cblxuLy8gZmluZCBhIGJyaWRnZSBiZXR3ZWVuIHZlcnRpY2VzIHRoYXQgY29ubmVjdHMgaG9sZSB3aXRoIGFuIG91dGVyIHJpbmcgYW5kIGxpbmsgaXRcbmZ1bmN0aW9uIGVsaW1pbmF0ZUhvbGUoIGhvbGUsIG91dGVyTm9kZSApIHtcblxuXHRjb25zdCBicmlkZ2UgPSBmaW5kSG9sZUJyaWRnZSggaG9sZSwgb3V0ZXJOb2RlICk7XG5cdGlmICggISBicmlkZ2UgKSB7XG5cblx0XHRyZXR1cm4gb3V0ZXJOb2RlO1xuXG5cdH1cblxuXHRjb25zdCBicmlkZ2VSZXZlcnNlID0gc3BsaXRQb2x5Z29uKCBicmlkZ2UsIGhvbGUgKTtcblxuXHQvLyBmaWx0ZXIgY29sbGluZWFyIHBvaW50cyBhcm91bmQgdGhlIGN1dHNcblx0ZmlsdGVyUG9pbnRzKCBicmlkZ2VSZXZlcnNlLCBicmlkZ2VSZXZlcnNlLm5leHQgKTtcblx0cmV0dXJuIGZpbHRlclBvaW50cyggYnJpZGdlLCBicmlkZ2UubmV4dCApO1xuXG59XG5cbi8vIERhdmlkIEViZXJseSdzIGFsZ29yaXRobSBmb3IgZmluZGluZyBhIGJyaWRnZSBiZXR3ZWVuIGhvbGUgYW5kIG91dGVyIHBvbHlnb25cbmZ1bmN0aW9uIGZpbmRIb2xlQnJpZGdlKCBob2xlLCBvdXRlck5vZGUgKSB7XG5cblx0bGV0IHAgPSBvdXRlck5vZGUsXG5cdFx0cXggPSAtIEluZmluaXR5LFxuXHRcdG07XG5cblx0Y29uc3QgaHggPSBob2xlLngsIGh5ID0gaG9sZS55O1xuXG5cdC8vIGZpbmQgYSBzZWdtZW50IGludGVyc2VjdGVkIGJ5IGEgcmF5IGZyb20gdGhlIGhvbGUncyBsZWZ0bW9zdCBwb2ludCB0byB0aGUgbGVmdDtcblx0Ly8gc2VnbWVudCdzIGVuZHBvaW50IHdpdGggbGVzc2VyIHggd2lsbCBiZSBwb3RlbnRpYWwgY29ubmVjdGlvbiBwb2ludFxuXHRkbyB7XG5cblx0XHRpZiAoIGh5IDw9IHAueSAmJiBoeSA+PSBwLm5leHQueSAmJiBwLm5leHQueSAhPT0gcC55ICkge1xuXG5cdFx0XHRjb25zdCB4ID0gcC54ICsgKCBoeSAtIHAueSApICogKCBwLm5leHQueCAtIHAueCApIC8gKCBwLm5leHQueSAtIHAueSApO1xuXHRcdFx0aWYgKCB4IDw9IGh4ICYmIHggPiBxeCApIHtcblxuXHRcdFx0XHRxeCA9IHg7XG5cdFx0XHRcdG0gPSBwLnggPCBwLm5leHQueCA/IHAgOiBwLm5leHQ7XG5cdFx0XHRcdGlmICggeCA9PT0gaHggKSByZXR1cm4gbTsgLy8gaG9sZSB0b3VjaGVzIG91dGVyIHNlZ21lbnQ7IHBpY2sgbGVmdG1vc3QgZW5kcG9pbnRcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cCA9IHAubmV4dDtcblxuXHR9IHdoaWxlICggcCAhPT0gb3V0ZXJOb2RlICk7XG5cblx0aWYgKCAhIG0gKSByZXR1cm4gbnVsbDtcblxuXHQvLyBsb29rIGZvciBwb2ludHMgaW5zaWRlIHRoZSB0cmlhbmdsZSBvZiBob2xlIHBvaW50LCBzZWdtZW50IGludGVyc2VjdGlvbiBhbmQgZW5kcG9pbnQ7XG5cdC8vIGlmIHRoZXJlIGFyZSBubyBwb2ludHMgZm91bmQsIHdlIGhhdmUgYSB2YWxpZCBjb25uZWN0aW9uO1xuXHQvLyBvdGhlcndpc2UgY2hvb3NlIHRoZSBwb2ludCBvZiB0aGUgbWluaW11bSBhbmdsZSB3aXRoIHRoZSByYXkgYXMgY29ubmVjdGlvbiBwb2ludFxuXG5cdGNvbnN0IHN0b3AgPSBtLFxuXHRcdG14ID0gbS54LFxuXHRcdG15ID0gbS55O1xuXHRsZXQgdGFuTWluID0gSW5maW5pdHksIHRhbjtcblxuXHRwID0gbTtcblxuXHRkbyB7XG5cblx0XHRpZiAoIGh4ID49IHAueCAmJiBwLnggPj0gbXggJiYgaHggIT09IHAueCAmJlxuXHRcdFx0XHRwb2ludEluVHJpYW5nbGUoIGh5IDwgbXkgPyBoeCA6IHF4LCBoeSwgbXgsIG15LCBoeSA8IG15ID8gcXggOiBoeCwgaHksIHAueCwgcC55ICkgKSB7XG5cblx0XHRcdHRhbiA9IE1hdGguYWJzKCBoeSAtIHAueSApIC8gKCBoeCAtIHAueCApOyAvLyB0YW5nZW50aWFsXG5cblx0XHRcdGlmICggbG9jYWxseUluc2lkZSggcCwgaG9sZSApICYmICggdGFuIDwgdGFuTWluIHx8ICggdGFuID09PSB0YW5NaW4gJiYgKCBwLnggPiBtLnggfHwgKCBwLnggPT09IG0ueCAmJiBzZWN0b3JDb250YWluc1NlY3RvciggbSwgcCApICkgKSApICkgKSB7XG5cblx0XHRcdFx0bSA9IHA7XG5cdFx0XHRcdHRhbk1pbiA9IHRhbjtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cCA9IHAubmV4dDtcblxuXHR9IHdoaWxlICggcCAhPT0gc3RvcCApO1xuXG5cdHJldHVybiBtO1xuXG59XG5cbi8vIHdoZXRoZXIgc2VjdG9yIGluIHZlcnRleCBtIGNvbnRhaW5zIHNlY3RvciBpbiB2ZXJ0ZXggcCBpbiB0aGUgc2FtZSBjb29yZGluYXRlc1xuZnVuY3Rpb24gc2VjdG9yQ29udGFpbnNTZWN0b3IoIG0sIHAgKSB7XG5cblx0cmV0dXJuIGFyZWEoIG0ucHJldiwgbSwgcC5wcmV2ICkgPCAwICYmIGFyZWEoIHAubmV4dCwgbSwgbS5uZXh0ICkgPCAwO1xuXG59XG5cbi8vIGludGVybGluayBwb2x5Z29uIG5vZGVzIGluIHotb3JkZXJcbmZ1bmN0aW9uIGluZGV4Q3VydmUoIHN0YXJ0LCBtaW5YLCBtaW5ZLCBpbnZTaXplICkge1xuXG5cdGxldCBwID0gc3RhcnQ7XG5cdGRvIHtcblxuXHRcdGlmICggcC56ID09PSAwICkgcC56ID0gek9yZGVyKCBwLngsIHAueSwgbWluWCwgbWluWSwgaW52U2l6ZSApO1xuXHRcdHAucHJldlogPSBwLnByZXY7XG5cdFx0cC5uZXh0WiA9IHAubmV4dDtcblx0XHRwID0gcC5uZXh0O1xuXG5cdH0gd2hpbGUgKCBwICE9PSBzdGFydCApO1xuXG5cdHAucHJldloubmV4dFogPSBudWxsO1xuXHRwLnByZXZaID0gbnVsbDtcblxuXHRzb3J0TGlua2VkKCBwICk7XG5cbn1cblxuLy8gU2ltb24gVGF0aGFtJ3MgbGlua2VkIGxpc3QgbWVyZ2Ugc29ydCBhbGdvcml0aG1cbi8vIGh0dHA6Ly93d3cuY2hpYXJrLmdyZWVuZW5kLm9yZy51ay9+c2d0YXRoYW0vYWxnb3JpdGhtcy9saXN0c29ydC5odG1sXG5mdW5jdGlvbiBzb3J0TGlua2VkKCBsaXN0ICkge1xuXG5cdGxldCBpLCBwLCBxLCBlLCB0YWlsLCBudW1NZXJnZXMsIHBTaXplLCBxU2l6ZSxcblx0XHRpblNpemUgPSAxO1xuXG5cdGRvIHtcblxuXHRcdHAgPSBsaXN0O1xuXHRcdGxpc3QgPSBudWxsO1xuXHRcdHRhaWwgPSBudWxsO1xuXHRcdG51bU1lcmdlcyA9IDA7XG5cblx0XHR3aGlsZSAoIHAgKSB7XG5cblx0XHRcdG51bU1lcmdlcyArKztcblx0XHRcdHEgPSBwO1xuXHRcdFx0cFNpemUgPSAwO1xuXHRcdFx0Zm9yICggaSA9IDA7IGkgPCBpblNpemU7IGkgKysgKSB7XG5cblx0XHRcdFx0cFNpemUgKys7XG5cdFx0XHRcdHEgPSBxLm5leHRaO1xuXHRcdFx0XHRpZiAoICEgcSApIGJyZWFrO1xuXG5cdFx0XHR9XG5cblx0XHRcdHFTaXplID0gaW5TaXplO1xuXG5cdFx0XHR3aGlsZSAoIHBTaXplID4gMCB8fCAoIHFTaXplID4gMCAmJiBxICkgKSB7XG5cblx0XHRcdFx0aWYgKCBwU2l6ZSAhPT0gMCAmJiAoIHFTaXplID09PSAwIHx8ICEgcSB8fCBwLnogPD0gcS56ICkgKSB7XG5cblx0XHRcdFx0XHRlID0gcDtcblx0XHRcdFx0XHRwID0gcC5uZXh0Wjtcblx0XHRcdFx0XHRwU2l6ZSAtLTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0ZSA9IHE7XG5cdFx0XHRcdFx0cSA9IHEubmV4dFo7XG5cdFx0XHRcdFx0cVNpemUgLS07XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggdGFpbCApIHRhaWwubmV4dFogPSBlO1xuXHRcdFx0XHRlbHNlIGxpc3QgPSBlO1xuXG5cdFx0XHRcdGUucHJldlogPSB0YWlsO1xuXHRcdFx0XHR0YWlsID0gZTtcblxuXHRcdFx0fVxuXG5cdFx0XHRwID0gcTtcblxuXHRcdH1cblxuXHRcdHRhaWwubmV4dFogPSBudWxsO1xuXHRcdGluU2l6ZSAqPSAyO1xuXG5cdH0gd2hpbGUgKCBudW1NZXJnZXMgPiAxICk7XG5cblx0cmV0dXJuIGxpc3Q7XG5cbn1cblxuLy8gei1vcmRlciBvZiBhIHBvaW50IGdpdmVuIGNvb3JkcyBhbmQgaW52ZXJzZSBvZiB0aGUgbG9uZ2VyIHNpZGUgb2YgZGF0YSBiYm94XG5mdW5jdGlvbiB6T3JkZXIoIHgsIHksIG1pblgsIG1pblksIGludlNpemUgKSB7XG5cblx0Ly8gY29vcmRzIGFyZSB0cmFuc2Zvcm1lZCBpbnRvIG5vbi1uZWdhdGl2ZSAxNS1iaXQgaW50ZWdlciByYW5nZVxuXHR4ID0gKCB4IC0gbWluWCApICogaW52U2l6ZSB8IDA7XG5cdHkgPSAoIHkgLSBtaW5ZICkgKiBpbnZTaXplIHwgMDtcblxuXHR4ID0gKCB4IHwgKCB4IDw8IDggKSApICYgMHgwMEZGMDBGRjtcblx0eCA9ICggeCB8ICggeCA8PCA0ICkgKSAmIDB4MEYwRjBGMEY7XG5cdHggPSAoIHggfCAoIHggPDwgMiApICkgJiAweDMzMzMzMzMzO1xuXHR4ID0gKCB4IHwgKCB4IDw8IDEgKSApICYgMHg1NTU1NTU1NTtcblxuXHR5ID0gKCB5IHwgKCB5IDw8IDggKSApICYgMHgwMEZGMDBGRjtcblx0eSA9ICggeSB8ICggeSA8PCA0ICkgKSAmIDB4MEYwRjBGMEY7XG5cdHkgPSAoIHkgfCAoIHkgPDwgMiApICkgJiAweDMzMzMzMzMzO1xuXHR5ID0gKCB5IHwgKCB5IDw8IDEgKSApICYgMHg1NTU1NTU1NTtcblxuXHRyZXR1cm4geCB8ICggeSA8PCAxICk7XG5cbn1cblxuLy8gZmluZCB0aGUgbGVmdG1vc3Qgbm9kZSBvZiBhIHBvbHlnb24gcmluZ1xuZnVuY3Rpb24gZ2V0TGVmdG1vc3QoIHN0YXJ0ICkge1xuXG5cdGxldCBwID0gc3RhcnQsXG5cdFx0bGVmdG1vc3QgPSBzdGFydDtcblx0ZG8ge1xuXG5cdFx0aWYgKCBwLnggPCBsZWZ0bW9zdC54IHx8ICggcC54ID09PSBsZWZ0bW9zdC54ICYmIHAueSA8IGxlZnRtb3N0LnkgKSApIGxlZnRtb3N0ID0gcDtcblx0XHRwID0gcC5uZXh0O1xuXG5cdH0gd2hpbGUgKCBwICE9PSBzdGFydCApO1xuXG5cdHJldHVybiBsZWZ0bW9zdDtcblxufVxuXG4vLyBjaGVjayBpZiBhIHBvaW50IGxpZXMgd2l0aGluIGEgY29udmV4IHRyaWFuZ2xlXG5mdW5jdGlvbiBwb2ludEluVHJpYW5nbGUoIGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIHB4LCBweSApIHtcblxuXHRyZXR1cm4gKCBjeCAtIHB4ICkgKiAoIGF5IC0gcHkgKSA+PSAoIGF4IC0gcHggKSAqICggY3kgLSBweSApICYmXG4gICAgICAgICAgICggYXggLSBweCApICogKCBieSAtIHB5ICkgPj0gKCBieCAtIHB4ICkgKiAoIGF5IC0gcHkgKSAmJlxuICAgICAgICAgICAoIGJ4IC0gcHggKSAqICggY3kgLSBweSApID49ICggY3ggLSBweCApICogKCBieSAtIHB5ICk7XG5cbn1cblxuLy8gY2hlY2sgaWYgYSBkaWFnb25hbCBiZXR3ZWVuIHR3byBwb2x5Z29uIG5vZGVzIGlzIHZhbGlkIChsaWVzIGluIHBvbHlnb24gaW50ZXJpb3IpXG5mdW5jdGlvbiBpc1ZhbGlkRGlhZ29uYWwoIGEsIGIgKSB7XG5cblx0cmV0dXJuIGEubmV4dC5pICE9PSBiLmkgJiYgYS5wcmV2LmkgIT09IGIuaSAmJiAhIGludGVyc2VjdHNQb2x5Z29uKCBhLCBiICkgJiYgLy8gZG9uZXMndCBpbnRlcnNlY3Qgb3RoZXIgZWRnZXNcbiAgICAgICAgICAgKCBsb2NhbGx5SW5zaWRlKCBhLCBiICkgJiYgbG9jYWxseUluc2lkZSggYiwgYSApICYmIG1pZGRsZUluc2lkZSggYSwgYiApICYmIC8vIGxvY2FsbHkgdmlzaWJsZVxuICAgICAgICAgICAgKCBhcmVhKCBhLnByZXYsIGEsIGIucHJldiApIHx8IGFyZWEoIGEsIGIucHJldiwgYiApICkgfHwgLy8gZG9lcyBub3QgY3JlYXRlIG9wcG9zaXRlLWZhY2luZyBzZWN0b3JzXG4gICAgICAgICAgICBlcXVhbHMoIGEsIGIgKSAmJiBhcmVhKCBhLnByZXYsIGEsIGEubmV4dCApID4gMCAmJiBhcmVhKCBiLnByZXYsIGIsIGIubmV4dCApID4gMCApOyAvLyBzcGVjaWFsIHplcm8tbGVuZ3RoIGNhc2VcblxufVxuXG4vLyBzaWduZWQgYXJlYSBvZiBhIHRyaWFuZ2xlXG5mdW5jdGlvbiBhcmVhKCBwLCBxLCByICkge1xuXG5cdHJldHVybiAoIHEueSAtIHAueSApICogKCByLnggLSBxLnggKSAtICggcS54IC0gcC54ICkgKiAoIHIueSAtIHEueSApO1xuXG59XG5cbi8vIGNoZWNrIGlmIHR3byBwb2ludHMgYXJlIGVxdWFsXG5mdW5jdGlvbiBlcXVhbHMoIHAxLCBwMiApIHtcblxuXHRyZXR1cm4gcDEueCA9PT0gcDIueCAmJiBwMS55ID09PSBwMi55O1xuXG59XG5cbi8vIGNoZWNrIGlmIHR3byBzZWdtZW50cyBpbnRlcnNlY3RcbmZ1bmN0aW9uIGludGVyc2VjdHMoIHAxLCBxMSwgcDIsIHEyICkge1xuXG5cdGNvbnN0IG8xID0gc2lnbiggYXJlYSggcDEsIHExLCBwMiApICk7XG5cdGNvbnN0IG8yID0gc2lnbiggYXJlYSggcDEsIHExLCBxMiApICk7XG5cdGNvbnN0IG8zID0gc2lnbiggYXJlYSggcDIsIHEyLCBwMSApICk7XG5cdGNvbnN0IG80ID0gc2lnbiggYXJlYSggcDIsIHEyLCBxMSApICk7XG5cblx0aWYgKCBvMSAhPT0gbzIgJiYgbzMgIT09IG80ICkgcmV0dXJuIHRydWU7IC8vIGdlbmVyYWwgY2FzZVxuXG5cdGlmICggbzEgPT09IDAgJiYgb25TZWdtZW50KCBwMSwgcDIsIHExICkgKSByZXR1cm4gdHJ1ZTsgLy8gcDEsIHExIGFuZCBwMiBhcmUgY29sbGluZWFyIGFuZCBwMiBsaWVzIG9uIHAxcTFcblx0aWYgKCBvMiA9PT0gMCAmJiBvblNlZ21lbnQoIHAxLCBxMiwgcTEgKSApIHJldHVybiB0cnVlOyAvLyBwMSwgcTEgYW5kIHEyIGFyZSBjb2xsaW5lYXIgYW5kIHEyIGxpZXMgb24gcDFxMVxuXHRpZiAoIG8zID09PSAwICYmIG9uU2VnbWVudCggcDIsIHAxLCBxMiApICkgcmV0dXJuIHRydWU7IC8vIHAyLCBxMiBhbmQgcDEgYXJlIGNvbGxpbmVhciBhbmQgcDEgbGllcyBvbiBwMnEyXG5cdGlmICggbzQgPT09IDAgJiYgb25TZWdtZW50KCBwMiwgcTEsIHEyICkgKSByZXR1cm4gdHJ1ZTsgLy8gcDIsIHEyIGFuZCBxMSBhcmUgY29sbGluZWFyIGFuZCBxMSBsaWVzIG9uIHAycTJcblxuXHRyZXR1cm4gZmFsc2U7XG5cbn1cblxuLy8gZm9yIGNvbGxpbmVhciBwb2ludHMgcCwgcSwgciwgY2hlY2sgaWYgcG9pbnQgcSBsaWVzIG9uIHNlZ21lbnQgcHJcbmZ1bmN0aW9uIG9uU2VnbWVudCggcCwgcSwgciApIHtcblxuXHRyZXR1cm4gcS54IDw9IE1hdGgubWF4KCBwLngsIHIueCApICYmIHEueCA+PSBNYXRoLm1pbiggcC54LCByLnggKSAmJiBxLnkgPD0gTWF0aC5tYXgoIHAueSwgci55ICkgJiYgcS55ID49IE1hdGgubWluKCBwLnksIHIueSApO1xuXG59XG5cbmZ1bmN0aW9uIHNpZ24oIG51bSApIHtcblxuXHRyZXR1cm4gbnVtID4gMCA/IDEgOiBudW0gPCAwID8gLSAxIDogMDtcblxufVxuXG4vLyBjaGVjayBpZiBhIHBvbHlnb24gZGlhZ29uYWwgaW50ZXJzZWN0cyBhbnkgcG9seWdvbiBzZWdtZW50c1xuZnVuY3Rpb24gaW50ZXJzZWN0c1BvbHlnb24oIGEsIGIgKSB7XG5cblx0bGV0IHAgPSBhO1xuXHRkbyB7XG5cblx0XHRpZiAoIHAuaSAhPT0gYS5pICYmIHAubmV4dC5pICE9PSBhLmkgJiYgcC5pICE9PSBiLmkgJiYgcC5uZXh0LmkgIT09IGIuaSAmJlxuXHRcdFx0aW50ZXJzZWN0cyggcCwgcC5uZXh0LCBhLCBiICkgKSByZXR1cm4gdHJ1ZTtcblx0XHRwID0gcC5uZXh0O1xuXG5cdH0gd2hpbGUgKCBwICE9PSBhICk7XG5cblx0cmV0dXJuIGZhbHNlO1xuXG59XG5cbi8vIGNoZWNrIGlmIGEgcG9seWdvbiBkaWFnb25hbCBpcyBsb2NhbGx5IGluc2lkZSB0aGUgcG9seWdvblxuZnVuY3Rpb24gbG9jYWxseUluc2lkZSggYSwgYiApIHtcblxuXHRyZXR1cm4gYXJlYSggYS5wcmV2LCBhLCBhLm5leHQgKSA8IDAgP1xuXHRcdGFyZWEoIGEsIGIsIGEubmV4dCApID49IDAgJiYgYXJlYSggYSwgYS5wcmV2LCBiICkgPj0gMCA6XG5cdFx0YXJlYSggYSwgYiwgYS5wcmV2ICkgPCAwIHx8IGFyZWEoIGEsIGEubmV4dCwgYiApIDwgMDtcblxufVxuXG4vLyBjaGVjayBpZiB0aGUgbWlkZGxlIHBvaW50IG9mIGEgcG9seWdvbiBkaWFnb25hbCBpcyBpbnNpZGUgdGhlIHBvbHlnb25cbmZ1bmN0aW9uIG1pZGRsZUluc2lkZSggYSwgYiApIHtcblxuXHRsZXQgcCA9IGEsXG5cdFx0aW5zaWRlID0gZmFsc2U7XG5cdGNvbnN0IHB4ID0gKCBhLnggKyBiLnggKSAvIDIsXG5cdFx0cHkgPSAoIGEueSArIGIueSApIC8gMjtcblx0ZG8ge1xuXG5cdFx0aWYgKCAoICggcC55ID4gcHkgKSAhPT0gKCBwLm5leHQueSA+IHB5ICkgKSAmJiBwLm5leHQueSAhPT0gcC55ICYmXG5cdFx0XHQoIHB4IDwgKCBwLm5leHQueCAtIHAueCApICogKCBweSAtIHAueSApIC8gKCBwLm5leHQueSAtIHAueSApICsgcC54ICkgKVxuXHRcdFx0aW5zaWRlID0gISBpbnNpZGU7XG5cdFx0cCA9IHAubmV4dDtcblxuXHR9IHdoaWxlICggcCAhPT0gYSApO1xuXG5cdHJldHVybiBpbnNpZGU7XG5cbn1cblxuLy8gbGluayB0d28gcG9seWdvbiB2ZXJ0aWNlcyB3aXRoIGEgYnJpZGdlOyBpZiB0aGUgdmVydGljZXMgYmVsb25nIHRvIHRoZSBzYW1lIHJpbmcsIGl0IHNwbGl0cyBwb2x5Z29uIGludG8gdHdvO1xuLy8gaWYgb25lIGJlbG9uZ3MgdG8gdGhlIG91dGVyIHJpbmcgYW5kIGFub3RoZXIgdG8gYSBob2xlLCBpdCBtZXJnZXMgaXQgaW50byBhIHNpbmdsZSByaW5nXG5mdW5jdGlvbiBzcGxpdFBvbHlnb24oIGEsIGIgKSB7XG5cblx0Y29uc3QgYTIgPSBuZXcgTm9kZSggYS5pLCBhLngsIGEueSApLFxuXHRcdGIyID0gbmV3IE5vZGUoIGIuaSwgYi54LCBiLnkgKSxcblx0XHRhbiA9IGEubmV4dCxcblx0XHRicCA9IGIucHJldjtcblxuXHRhLm5leHQgPSBiO1xuXHRiLnByZXYgPSBhO1xuXG5cdGEyLm5leHQgPSBhbjtcblx0YW4ucHJldiA9IGEyO1xuXG5cdGIyLm5leHQgPSBhMjtcblx0YTIucHJldiA9IGIyO1xuXG5cdGJwLm5leHQgPSBiMjtcblx0YjIucHJldiA9IGJwO1xuXG5cdHJldHVybiBiMjtcblxufVxuXG4vLyBjcmVhdGUgYSBub2RlIGFuZCBvcHRpb25hbGx5IGxpbmsgaXQgd2l0aCBwcmV2aW91cyBvbmUgKGluIGEgY2lyY3VsYXIgZG91Ymx5IGxpbmtlZCBsaXN0KVxuZnVuY3Rpb24gaW5zZXJ0Tm9kZSggaSwgeCwgeSwgbGFzdCApIHtcblxuXHRjb25zdCBwID0gbmV3IE5vZGUoIGksIHgsIHkgKTtcblxuXHRpZiAoICEgbGFzdCApIHtcblxuXHRcdHAucHJldiA9IHA7XG5cdFx0cC5uZXh0ID0gcDtcblxuXHR9IGVsc2Uge1xuXG5cdFx0cC5uZXh0ID0gbGFzdC5uZXh0O1xuXHRcdHAucHJldiA9IGxhc3Q7XG5cdFx0bGFzdC5uZXh0LnByZXYgPSBwO1xuXHRcdGxhc3QubmV4dCA9IHA7XG5cblx0fVxuXG5cdHJldHVybiBwO1xuXG59XG5cbmZ1bmN0aW9uIHJlbW92ZU5vZGUoIHAgKSB7XG5cblx0cC5uZXh0LnByZXYgPSBwLnByZXY7XG5cdHAucHJldi5uZXh0ID0gcC5uZXh0O1xuXG5cdGlmICggcC5wcmV2WiApIHAucHJldloubmV4dFogPSBwLm5leHRaO1xuXHRpZiAoIHAubmV4dFogKSBwLm5leHRaLnByZXZaID0gcC5wcmV2WjtcblxufVxuXG5mdW5jdGlvbiBOb2RlKCBpLCB4LCB5ICkge1xuXG5cdC8vIHZlcnRleCBpbmRleCBpbiBjb29yZGluYXRlcyBhcnJheVxuXHR0aGlzLmkgPSBpO1xuXG5cdC8vIHZlcnRleCBjb29yZGluYXRlc1xuXHR0aGlzLnggPSB4O1xuXHR0aGlzLnkgPSB5O1xuXG5cdC8vIHByZXZpb3VzIGFuZCBuZXh0IHZlcnRleCBub2RlcyBpbiBhIHBvbHlnb24gcmluZ1xuXHR0aGlzLnByZXYgPSBudWxsO1xuXHR0aGlzLm5leHQgPSBudWxsO1xuXG5cdC8vIHotb3JkZXIgY3VydmUgdmFsdWVcblx0dGhpcy56ID0gMDtcblxuXHQvLyBwcmV2aW91cyBhbmQgbmV4dCBub2RlcyBpbiB6LW9yZGVyXG5cdHRoaXMucHJldlogPSBudWxsO1xuXHR0aGlzLm5leHRaID0gbnVsbDtcblxuXHQvLyBpbmRpY2F0ZXMgd2hldGhlciB0aGlzIGlzIGEgc3RlaW5lciBwb2ludFxuXHR0aGlzLnN0ZWluZXIgPSBmYWxzZTtcblxufVxuXG5mdW5jdGlvbiBzaWduZWRBcmVhKCBkYXRhLCBzdGFydCwgZW5kLCBkaW0gKSB7XG5cblx0bGV0IHN1bSA9IDA7XG5cdGZvciAoIGxldCBpID0gc3RhcnQsIGogPSBlbmQgLSBkaW07IGkgPCBlbmQ7IGkgKz0gZGltICkge1xuXG5cdFx0c3VtICs9ICggZGF0YVsgaiBdIC0gZGF0YVsgaSBdICkgKiAoIGRhdGFbIGkgKyAxIF0gKyBkYXRhWyBqICsgMSBdICk7XG5cdFx0aiA9IGk7XG5cblx0fVxuXG5cdHJldHVybiBzdW07XG5cbn1cblxuY2xhc3MgU2hhcGVVdGlscyB7XG5cblx0Ly8gY2FsY3VsYXRlIGFyZWEgb2YgdGhlIGNvbnRvdXIgcG9seWdvblxuXG5cdHN0YXRpYyBhcmVhKCBjb250b3VyICkge1xuXG5cdFx0Y29uc3QgbiA9IGNvbnRvdXIubGVuZ3RoO1xuXHRcdGxldCBhID0gMC4wO1xuXG5cdFx0Zm9yICggbGV0IHAgPSBuIC0gMSwgcSA9IDA7IHEgPCBuOyBwID0gcSArKyApIHtcblxuXHRcdFx0YSArPSBjb250b3VyWyBwIF0ueCAqIGNvbnRvdXJbIHEgXS55IC0gY29udG91clsgcSBdLnggKiBjb250b3VyWyBwIF0ueTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBhICogMC41O1xuXG5cdH1cblxuXHRzdGF0aWMgaXNDbG9ja1dpc2UoIHB0cyApIHtcblxuXHRcdHJldHVybiBTaGFwZVV0aWxzLmFyZWEoIHB0cyApIDwgMDtcblxuXHR9XG5cblx0c3RhdGljIHRyaWFuZ3VsYXRlU2hhcGUoIGNvbnRvdXIsIGhvbGVzICkge1xuXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTsgLy8gZmxhdCBhcnJheSBvZiB2ZXJ0aWNlcyBsaWtlIFsgeDAseTAsIHgxLHkxLCB4Mix5MiwgLi4uIF1cblx0XHRjb25zdCBob2xlSW5kaWNlcyA9IFtdOyAvLyBhcnJheSBvZiBob2xlIGluZGljZXNcblx0XHRjb25zdCBmYWNlcyA9IFtdOyAvLyBmaW5hbCBhcnJheSBvZiB2ZXJ0ZXggaW5kaWNlcyBsaWtlIFsgWyBhLGIsZCBdLCBbIGIsYyxkIF0gXVxuXG5cdFx0cmVtb3ZlRHVwRW5kUHRzKCBjb250b3VyICk7XG5cdFx0YWRkQ29udG91ciggdmVydGljZXMsIGNvbnRvdXIgKTtcblxuXHRcdC8vXG5cblx0XHRsZXQgaG9sZUluZGV4ID0gY29udG91ci5sZW5ndGg7XG5cblx0XHRob2xlcy5mb3JFYWNoKCByZW1vdmVEdXBFbmRQdHMgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGhvbGVzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0aG9sZUluZGljZXMucHVzaCggaG9sZUluZGV4ICk7XG5cdFx0XHRob2xlSW5kZXggKz0gaG9sZXNbIGkgXS5sZW5ndGg7XG5cdFx0XHRhZGRDb250b3VyKCB2ZXJ0aWNlcywgaG9sZXNbIGkgXSApO1xuXG5cdFx0fVxuXG5cdFx0Ly9cblxuXHRcdGNvbnN0IHRyaWFuZ2xlcyA9IEVhcmN1dC50cmlhbmd1bGF0ZSggdmVydGljZXMsIGhvbGVJbmRpY2VzICk7XG5cblx0XHQvL1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdHJpYW5nbGVzLmxlbmd0aDsgaSArPSAzICkge1xuXG5cdFx0XHRmYWNlcy5wdXNoKCB0cmlhbmdsZXMuc2xpY2UoIGksIGkgKyAzICkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBmYWNlcztcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gcmVtb3ZlRHVwRW5kUHRzKCBwb2ludHMgKSB7XG5cblx0Y29uc3QgbCA9IHBvaW50cy5sZW5ndGg7XG5cblx0aWYgKCBsID4gMiAmJiBwb2ludHNbIGwgLSAxIF0uZXF1YWxzKCBwb2ludHNbIDAgXSApICkge1xuXG5cdFx0cG9pbnRzLnBvcCgpO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBhZGRDb250b3VyKCB2ZXJ0aWNlcywgY29udG91ciApIHtcblxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb250b3VyLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdHZlcnRpY2VzLnB1c2goIGNvbnRvdXJbIGkgXS54ICk7XG5cdFx0dmVydGljZXMucHVzaCggY29udG91clsgaSBdLnkgKTtcblxuXHR9XG5cbn1cblxuLyoqXG4gKiBDcmVhdGVzIGV4dHJ1ZGVkIGdlb21ldHJ5IGZyb20gYSBwYXRoIHNoYXBlLlxuICpcbiAqIHBhcmFtZXRlcnMgPSB7XG4gKlxuICogIGN1cnZlU2VnbWVudHM6IDxpbnQ+LCAvLyBudW1iZXIgb2YgcG9pbnRzIG9uIHRoZSBjdXJ2ZXNcbiAqICBzdGVwczogPGludD4sIC8vIG51bWJlciBvZiBwb2ludHMgZm9yIHotc2lkZSBleHRydXNpb25zIC8gdXNlZCBmb3Igc3ViZGl2aWRpbmcgc2VnbWVudHMgb2YgZXh0cnVkZSBzcGxpbmUgdG9vXG4gKiAgZGVwdGg6IDxmbG9hdD4sIC8vIERlcHRoIHRvIGV4dHJ1ZGUgdGhlIHNoYXBlXG4gKlxuICogIGJldmVsRW5hYmxlZDogPGJvb2w+LCAvLyB0dXJuIG9uIGJldmVsXG4gKiAgYmV2ZWxUaGlja25lc3M6IDxmbG9hdD4sIC8vIGhvdyBkZWVwIGludG8gdGhlIG9yaWdpbmFsIHNoYXBlIGJldmVsIGdvZXNcbiAqICBiZXZlbFNpemU6IDxmbG9hdD4sIC8vIGhvdyBmYXIgZnJvbSBzaGFwZSBvdXRsaW5lIChpbmNsdWRpbmcgYmV2ZWxPZmZzZXQpIGlzIGJldmVsXG4gKiAgYmV2ZWxPZmZzZXQ6IDxmbG9hdD4sIC8vIGhvdyBmYXIgZnJvbSBzaGFwZSBvdXRsaW5lIGRvZXMgYmV2ZWwgc3RhcnRcbiAqICBiZXZlbFNlZ21lbnRzOiA8aW50PiwgLy8gbnVtYmVyIG9mIGJldmVsIGxheWVyc1xuICpcbiAqICBleHRydWRlUGF0aDogPFRIUkVFLkN1cnZlPiAvLyBjdXJ2ZSB0byBleHRydWRlIHNoYXBlIGFsb25nXG4gKlxuICogIFVWR2VuZXJhdG9yOiA8T2JqZWN0PiAvLyBvYmplY3QgdGhhdCBwcm92aWRlcyBVViBnZW5lcmF0b3IgZnVuY3Rpb25zXG4gKlxuICogfVxuICovXG5cblxuY2xhc3MgRXh0cnVkZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCBzaGFwZXMgPSBuZXcgU2hhcGUoIFsgbmV3IFZlY3RvcjIoIDAuNSwgMC41ICksIG5ldyBWZWN0b3IyKCAtIDAuNSwgMC41ICksIG5ldyBWZWN0b3IyKCAtIDAuNSwgLSAwLjUgKSwgbmV3IFZlY3RvcjIoIDAuNSwgLSAwLjUgKSBdICksIG9wdGlvbnMgPSB7fSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnRXh0cnVkZUdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHNoYXBlczogc2hhcGVzLFxuXHRcdFx0b3B0aW9uczogb3B0aW9uc1xuXHRcdH07XG5cblx0XHRzaGFwZXMgPSBBcnJheS5pc0FycmF5KCBzaGFwZXMgKSA/IHNoYXBlcyA6IFsgc2hhcGVzIF07XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRjb25zdCB2ZXJ0aWNlc0FycmF5ID0gW107XG5cdFx0Y29uc3QgdXZBcnJheSA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHNoYXBlID0gc2hhcGVzWyBpIF07XG5cdFx0XHRhZGRTaGFwZSggc2hhcGUgKTtcblxuXHRcdH1cblxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XG5cblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzQXJyYXksIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZBcnJheSwgMiApICk7XG5cblx0XHR0aGlzLmNvbXB1dGVWZXJ0ZXhOb3JtYWxzKCk7XG5cblx0XHQvLyBmdW5jdGlvbnNcblxuXHRcdGZ1bmN0aW9uIGFkZFNoYXBlKCBzaGFwZSApIHtcblxuXHRcdFx0Y29uc3QgcGxhY2Vob2xkZXIgPSBbXTtcblxuXHRcdFx0Ly8gb3B0aW9uc1xuXG5cdFx0XHRjb25zdCBjdXJ2ZVNlZ21lbnRzID0gb3B0aW9ucy5jdXJ2ZVNlZ21lbnRzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmN1cnZlU2VnbWVudHMgOiAxMjtcblx0XHRcdGNvbnN0IHN0ZXBzID0gb3B0aW9ucy5zdGVwcyAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5zdGVwcyA6IDE7XG5cdFx0XHRjb25zdCBkZXB0aCA9IG9wdGlvbnMuZGVwdGggIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuZGVwdGggOiAxO1xuXG5cdFx0XHRsZXQgYmV2ZWxFbmFibGVkID0gb3B0aW9ucy5iZXZlbEVuYWJsZWQgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuYmV2ZWxFbmFibGVkIDogdHJ1ZTtcblx0XHRcdGxldCBiZXZlbFRoaWNrbmVzcyA9IG9wdGlvbnMuYmV2ZWxUaGlja25lc3MgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuYmV2ZWxUaGlja25lc3MgOiAwLjI7XG5cdFx0XHRsZXQgYmV2ZWxTaXplID0gb3B0aW9ucy5iZXZlbFNpemUgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuYmV2ZWxTaXplIDogYmV2ZWxUaGlja25lc3MgLSAwLjE7XG5cdFx0XHRsZXQgYmV2ZWxPZmZzZXQgPSBvcHRpb25zLmJldmVsT2Zmc2V0ICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmJldmVsT2Zmc2V0IDogMDtcblx0XHRcdGxldCBiZXZlbFNlZ21lbnRzID0gb3B0aW9ucy5iZXZlbFNlZ21lbnRzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmJldmVsU2VnbWVudHMgOiAzO1xuXG5cdFx0XHRjb25zdCBleHRydWRlUGF0aCA9IG9wdGlvbnMuZXh0cnVkZVBhdGg7XG5cblx0XHRcdGNvbnN0IHV2Z2VuID0gb3B0aW9ucy5VVkdlbmVyYXRvciAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5VVkdlbmVyYXRvciA6IFdvcmxkVVZHZW5lcmF0b3I7XG5cblx0XHRcdC8vXG5cblx0XHRcdGxldCBleHRydWRlUHRzLCBleHRydWRlQnlQYXRoID0gZmFsc2U7XG5cdFx0XHRsZXQgc3BsaW5lVHViZSwgYmlub3JtYWwsIG5vcm1hbCwgcG9zaXRpb24yO1xuXG5cdFx0XHRpZiAoIGV4dHJ1ZGVQYXRoICkge1xuXG5cdFx0XHRcdGV4dHJ1ZGVQdHMgPSBleHRydWRlUGF0aC5nZXRTcGFjZWRQb2ludHMoIHN0ZXBzICk7XG5cblx0XHRcdFx0ZXh0cnVkZUJ5UGF0aCA9IHRydWU7XG5cdFx0XHRcdGJldmVsRW5hYmxlZCA9IGZhbHNlOyAvLyBiZXZlbHMgbm90IHN1cHBvcnRlZCBmb3IgcGF0aCBleHRydXNpb25cblxuXHRcdFx0XHQvLyBTRVRVUCBUTkIgdmFyaWFibGVzXG5cblx0XHRcdFx0Ly8gVE9ETzEgLSBoYXZlIGEgLmlzQ2xvc2VkIGluIHNwbGluZT9cblxuXHRcdFx0XHRzcGxpbmVUdWJlID0gZXh0cnVkZVBhdGguY29tcHV0ZUZyZW5ldEZyYW1lcyggc3RlcHMsIGZhbHNlICk7XG5cblx0XHRcdFx0Ly8gY29uc29sZS5sb2coc3BsaW5lVHViZSwgJ3NwbGluZVR1YmUnLCBzcGxpbmVUdWJlLm5vcm1hbHMubGVuZ3RoLCAnc3RlcHMnLCBzdGVwcywgJ2V4dHJ1ZGVQdHMnLCBleHRydWRlUHRzLmxlbmd0aCk7XG5cblx0XHRcdFx0Ymlub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xuXHRcdFx0XHRub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xuXHRcdFx0XHRwb3NpdGlvbjIgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIFNhZmVndWFyZHMgaWYgYmV2ZWxzIGFyZSBub3QgZW5hYmxlZFxuXG5cdFx0XHRpZiAoICEgYmV2ZWxFbmFibGVkICkge1xuXG5cdFx0XHRcdGJldmVsU2VnbWVudHMgPSAwO1xuXHRcdFx0XHRiZXZlbFRoaWNrbmVzcyA9IDA7XG5cdFx0XHRcdGJldmVsU2l6ZSA9IDA7XG5cdFx0XHRcdGJldmVsT2Zmc2V0ID0gMDtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBWYXJpYWJsZXMgaW5pdGlhbGl6YXRpb25cblxuXHRcdFx0Y29uc3Qgc2hhcGVQb2ludHMgPSBzaGFwZS5leHRyYWN0UG9pbnRzKCBjdXJ2ZVNlZ21lbnRzICk7XG5cblx0XHRcdGxldCB2ZXJ0aWNlcyA9IHNoYXBlUG9pbnRzLnNoYXBlO1xuXHRcdFx0Y29uc3QgaG9sZXMgPSBzaGFwZVBvaW50cy5ob2xlcztcblxuXHRcdFx0Y29uc3QgcmV2ZXJzZSA9ICEgU2hhcGVVdGlscy5pc0Nsb2NrV2lzZSggdmVydGljZXMgKTtcblxuXHRcdFx0aWYgKCByZXZlcnNlICkge1xuXG5cdFx0XHRcdHZlcnRpY2VzID0gdmVydGljZXMucmV2ZXJzZSgpO1xuXG5cdFx0XHRcdC8vIE1heWJlIHdlIHNob3VsZCBhbHNvIGNoZWNrIGlmIGhvbGVzIGFyZSBpbiB0aGUgb3Bwb3NpdGUgZGlyZWN0aW9uLCBqdXN0IHRvIGJlIHNhZmUgLi4uXG5cblx0XHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgYWhvbGUgPSBob2xlc1sgaCBdO1xuXG5cdFx0XHRcdFx0aWYgKCBTaGFwZVV0aWxzLmlzQ2xvY2tXaXNlKCBhaG9sZSApICkge1xuXG5cdFx0XHRcdFx0XHRob2xlc1sgaCBdID0gYWhvbGUucmV2ZXJzZSgpO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cblx0XHRcdGNvbnN0IGZhY2VzID0gU2hhcGVVdGlscy50cmlhbmd1bGF0ZVNoYXBlKCB2ZXJ0aWNlcywgaG9sZXMgKTtcblxuXHRcdFx0LyogVmVydGljZXMgKi9cblxuXHRcdFx0Y29uc3QgY29udG91ciA9IHZlcnRpY2VzOyAvLyB2ZXJ0aWNlcyBoYXMgYWxsIHBvaW50cyBidXQgY29udG91ciBoYXMgb25seSBwb2ludHMgb2YgY2lyY3VtZmVyZW5jZVxuXG5cdFx0XHRmb3IgKCBsZXQgaCA9IDAsIGhsID0gaG9sZXMubGVuZ3RoOyBoIDwgaGw7IGggKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgYWhvbGUgPSBob2xlc1sgaCBdO1xuXG5cdFx0XHRcdHZlcnRpY2VzID0gdmVydGljZXMuY29uY2F0KCBhaG9sZSApO1xuXG5cdFx0XHR9XG5cblxuXHRcdFx0ZnVuY3Rpb24gc2NhbGVQdDIoIHB0LCB2ZWMsIHNpemUgKSB7XG5cblx0XHRcdFx0aWYgKCAhIHZlYyApIGNvbnNvbGUuZXJyb3IoICdUSFJFRS5FeHRydWRlR2VvbWV0cnk6IHZlYyBkb2VzIG5vdCBleGlzdCcgKTtcblxuXHRcdFx0XHRyZXR1cm4gcHQuY2xvbmUoKS5hZGRTY2FsZWRWZWN0b3IoIHZlYywgc2l6ZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHZsZW4gPSB2ZXJ0aWNlcy5sZW5ndGgsIGZsZW4gPSBmYWNlcy5sZW5ndGg7XG5cblxuXHRcdFx0Ly8gRmluZCBkaXJlY3Rpb25zIGZvciBwb2ludCBtb3ZlbWVudFxuXG5cblx0XHRcdGZ1bmN0aW9uIGdldEJldmVsVmVjKCBpblB0LCBpblByZXYsIGluTmV4dCApIHtcblxuXHRcdFx0XHQvLyBjb21wdXRlcyBmb3IgaW5QdCB0aGUgY29ycmVzcG9uZGluZyBwb2ludCBpblB0JyBvbiBhIG5ldyBjb250b3VyXG5cdFx0XHRcdC8vICAgc2hpZnRlZCBieSAxIHVuaXQgKGxlbmd0aCBvZiBub3JtYWxpemVkIHZlY3RvcikgdG8gdGhlIGxlZnRcblx0XHRcdFx0Ly8gaWYgd2Ugd2FsayBhbG9uZyBjb250b3VyIGNsb2Nrd2lzZSwgdGhpcyBuZXcgY29udG91ciBpcyBvdXRzaWRlIHRoZSBvbGQgb25lXG5cdFx0XHRcdC8vXG5cdFx0XHRcdC8vIGluUHQnIGlzIHRoZSBpbnRlcnNlY3Rpb24gb2YgdGhlIHR3byBsaW5lcyBwYXJhbGxlbCB0byB0aGUgdHdvXG5cdFx0XHRcdC8vICBhZGphY2VudCBlZGdlcyBvZiBpblB0IGF0IGEgZGlzdGFuY2Ugb2YgMSB1bml0IG9uIHRoZSBsZWZ0IHNpZGUuXG5cblx0XHRcdFx0bGV0IHZfdHJhbnNfeCwgdl90cmFuc195LCBzaHJpbmtfYnk7IC8vIHJlc3VsdGluZyB0cmFuc2xhdGlvbiB2ZWN0b3IgZm9yIGluUHRcblxuXHRcdFx0XHQvLyBnb29kIHJlYWRpbmcgZm9yIGdlb21ldHJ5IGFsZ29yaXRobXMgKGhlcmU6IGxpbmUtbGluZSBpbnRlcnNlY3Rpb24pXG5cdFx0XHRcdC8vIGh0dHA6Ly9nZW9tYWxnb3JpdGhtcy5jb20vYTA1LV9pbnRlcnNlY3QtMS5odG1sXG5cblx0XHRcdFx0Y29uc3Qgdl9wcmV2X3ggPSBpblB0LnggLSBpblByZXYueCxcblx0XHRcdFx0XHR2X3ByZXZfeSA9IGluUHQueSAtIGluUHJldi55O1xuXHRcdFx0XHRjb25zdCB2X25leHRfeCA9IGluTmV4dC54IC0gaW5QdC54LFxuXHRcdFx0XHRcdHZfbmV4dF95ID0gaW5OZXh0LnkgLSBpblB0Lnk7XG5cblx0XHRcdFx0Y29uc3Qgdl9wcmV2X2xlbnNxID0gKCB2X3ByZXZfeCAqIHZfcHJldl94ICsgdl9wcmV2X3kgKiB2X3ByZXZfeSApO1xuXG5cdFx0XHRcdC8vIGNoZWNrIGZvciBjb2xsaW5lYXIgZWRnZXNcblx0XHRcdFx0Y29uc3QgY29sbGluZWFyMCA9ICggdl9wcmV2X3ggKiB2X25leHRfeSAtIHZfcHJldl95ICogdl9uZXh0X3ggKTtcblxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBjb2xsaW5lYXIwICkgPiBOdW1iZXIuRVBTSUxPTiApIHtcblxuXHRcdFx0XHRcdC8vIG5vdCBjb2xsaW5lYXJcblxuXHRcdFx0XHRcdC8vIGxlbmd0aCBvZiB2ZWN0b3JzIGZvciBub3JtYWxpemluZ1xuXG5cdFx0XHRcdFx0Y29uc3Qgdl9wcmV2X2xlbiA9IE1hdGguc3FydCggdl9wcmV2X2xlbnNxICk7XG5cdFx0XHRcdFx0Y29uc3Qgdl9uZXh0X2xlbiA9IE1hdGguc3FydCggdl9uZXh0X3ggKiB2X25leHRfeCArIHZfbmV4dF95ICogdl9uZXh0X3kgKTtcblxuXHRcdFx0XHRcdC8vIHNoaWZ0IGFkamFjZW50IHBvaW50cyBieSB1bml0IHZlY3RvcnMgdG8gdGhlIGxlZnRcblxuXHRcdFx0XHRcdGNvbnN0IHB0UHJldlNoaWZ0X3ggPSAoIGluUHJldi54IC0gdl9wcmV2X3kgLyB2X3ByZXZfbGVuICk7XG5cdFx0XHRcdFx0Y29uc3QgcHRQcmV2U2hpZnRfeSA9ICggaW5QcmV2LnkgKyB2X3ByZXZfeCAvIHZfcHJldl9sZW4gKTtcblxuXHRcdFx0XHRcdGNvbnN0IHB0TmV4dFNoaWZ0X3ggPSAoIGluTmV4dC54IC0gdl9uZXh0X3kgLyB2X25leHRfbGVuICk7XG5cdFx0XHRcdFx0Y29uc3QgcHROZXh0U2hpZnRfeSA9ICggaW5OZXh0LnkgKyB2X25leHRfeCAvIHZfbmV4dF9sZW4gKTtcblxuXHRcdFx0XHRcdC8vIHNjYWxpbmcgZmFjdG9yIGZvciB2X3ByZXYgdG8gaW50ZXJzZWN0aW9uIHBvaW50XG5cblx0XHRcdFx0XHRjb25zdCBzZiA9ICggKCBwdE5leHRTaGlmdF94IC0gcHRQcmV2U2hpZnRfeCApICogdl9uZXh0X3kgLVxuXHRcdFx0XHRcdFx0XHQoIHB0TmV4dFNoaWZ0X3kgLSBwdFByZXZTaGlmdF95ICkgKiB2X25leHRfeCApIC9cblx0XHRcdFx0XHRcdCggdl9wcmV2X3ggKiB2X25leHRfeSAtIHZfcHJldl95ICogdl9uZXh0X3ggKTtcblxuXHRcdFx0XHRcdC8vIHZlY3RvciBmcm9tIGluUHQgdG8gaW50ZXJzZWN0aW9uIHBvaW50XG5cblx0XHRcdFx0XHR2X3RyYW5zX3ggPSAoIHB0UHJldlNoaWZ0X3ggKyB2X3ByZXZfeCAqIHNmIC0gaW5QdC54ICk7XG5cdFx0XHRcdFx0dl90cmFuc195ID0gKCBwdFByZXZTaGlmdF95ICsgdl9wcmV2X3kgKiBzZiAtIGluUHQueSApO1xuXG5cdFx0XHRcdFx0Ly8gRG9uJ3Qgbm9ybWFsaXplISwgb3RoZXJ3aXNlIHNoYXJwIGNvcm5lcnMgYmVjb21lIHVnbHlcblx0XHRcdFx0XHQvLyAgYnV0IHByZXZlbnQgY3Jhenkgc3Bpa2VzXG5cdFx0XHRcdFx0Y29uc3Qgdl90cmFuc19sZW5zcSA9ICggdl90cmFuc194ICogdl90cmFuc194ICsgdl90cmFuc195ICogdl90cmFuc195ICk7XG5cdFx0XHRcdFx0aWYgKCB2X3RyYW5zX2xlbnNxIDw9IDIgKSB7XG5cblx0XHRcdFx0XHRcdHJldHVybiBuZXcgVmVjdG9yMiggdl90cmFuc194LCB2X3RyYW5zX3kgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHNocmlua19ieSA9IE1hdGguc3FydCggdl90cmFuc19sZW5zcSAvIDIgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ly8gaGFuZGxlIHNwZWNpYWwgY2FzZSBvZiBjb2xsaW5lYXIgZWRnZXNcblxuXHRcdFx0XHRcdGxldCBkaXJlY3Rpb25fZXEgPSBmYWxzZTsgLy8gYXNzdW1lczogb3Bwb3NpdGVcblxuXHRcdFx0XHRcdGlmICggdl9wcmV2X3ggPiBOdW1iZXIuRVBTSUxPTiApIHtcblxuXHRcdFx0XHRcdFx0aWYgKCB2X25leHRfeCA+IE51bWJlci5FUFNJTE9OICkge1xuXG5cdFx0XHRcdFx0XHRcdGRpcmVjdGlvbl9lcSA9IHRydWU7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGlmICggdl9wcmV2X3ggPCAtIE51bWJlci5FUFNJTE9OICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggdl9uZXh0X3ggPCAtIE51bWJlci5FUFNJTE9OICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0ZGlyZWN0aW9uX2VxID0gdHJ1ZTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBNYXRoLnNpZ24oIHZfcHJldl95ICkgPT09IE1hdGguc2lnbiggdl9uZXh0X3kgKSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGRpcmVjdGlvbl9lcSA9IHRydWU7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoIGRpcmVjdGlvbl9lcSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gY29uc29sZS5sb2coXCJXYXJuaW5nOiBsaW5lcyBhcmUgYSBzdHJhaWdodCBzZXF1ZW5jZVwiKTtcblx0XHRcdFx0XHRcdHZfdHJhbnNfeCA9IC0gdl9wcmV2X3k7XG5cdFx0XHRcdFx0XHR2X3RyYW5zX3kgPSB2X3ByZXZfeDtcblx0XHRcdFx0XHRcdHNocmlua19ieSA9IE1hdGguc3FydCggdl9wcmV2X2xlbnNxICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHQvLyBjb25zb2xlLmxvZyhcIldhcm5pbmc6IGxpbmVzIGFyZSBhIHN0cmFpZ2h0IHNwaWtlXCIpO1xuXHRcdFx0XHRcdFx0dl90cmFuc194ID0gdl9wcmV2X3g7XG5cdFx0XHRcdFx0XHR2X3RyYW5zX3kgPSB2X3ByZXZfeTtcblx0XHRcdFx0XHRcdHNocmlua19ieSA9IE1hdGguc3FydCggdl9wcmV2X2xlbnNxIC8gMiApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gbmV3IFZlY3RvcjIoIHZfdHJhbnNfeCAvIHNocmlua19ieSwgdl90cmFuc195IC8gc2hyaW5rX2J5ICk7XG5cblx0XHRcdH1cblxuXG5cdFx0XHRjb25zdCBjb250b3VyTW92ZW1lbnRzID0gW107XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBjb250b3VyLmxlbmd0aCwgaiA9IGlsIC0gMSwgayA9IGkgKyAxOyBpIDwgaWw7IGkgKyssIGogKyssIGsgKysgKSB7XG5cblx0XHRcdFx0aWYgKCBqID09PSBpbCApIGogPSAwO1xuXHRcdFx0XHRpZiAoIGsgPT09IGlsICkgayA9IDA7XG5cblx0XHRcdFx0Ly8gIChqKS0tLShpKS0tLShrKVxuXHRcdFx0XHQvLyBjb25zb2xlLmxvZygnaSxqLGsnLCBpLCBqICwgaylcblxuXHRcdFx0XHRjb250b3VyTW92ZW1lbnRzWyBpIF0gPSBnZXRCZXZlbFZlYyggY29udG91clsgaSBdLCBjb250b3VyWyBqIF0sIGNvbnRvdXJbIGsgXSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGhvbGVzTW92ZW1lbnRzID0gW107XG5cdFx0XHRsZXQgb25lSG9sZU1vdmVtZW50cywgdmVydGljZXNNb3ZlbWVudHMgPSBjb250b3VyTW92ZW1lbnRzLmNvbmNhdCgpO1xuXG5cdFx0XHRmb3IgKCBsZXQgaCA9IDAsIGhsID0gaG9sZXMubGVuZ3RoOyBoIDwgaGw7IGggKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgYWhvbGUgPSBob2xlc1sgaCBdO1xuXG5cdFx0XHRcdG9uZUhvbGVNb3ZlbWVudHMgPSBbXTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYWhvbGUubGVuZ3RoLCBqID0gaWwgLSAxLCBrID0gaSArIDE7IGkgPCBpbDsgaSArKywgaiArKywgayArKyApIHtcblxuXHRcdFx0XHRcdGlmICggaiA9PT0gaWwgKSBqID0gMDtcblx0XHRcdFx0XHRpZiAoIGsgPT09IGlsICkgayA9IDA7XG5cblx0XHRcdFx0XHQvLyAgKGopLS0tKGkpLS0tKGspXG5cdFx0XHRcdFx0b25lSG9sZU1vdmVtZW50c1sgaSBdID0gZ2V0QmV2ZWxWZWMoIGFob2xlWyBpIF0sIGFob2xlWyBqIF0sIGFob2xlWyBrIF0gKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aG9sZXNNb3ZlbWVudHMucHVzaCggb25lSG9sZU1vdmVtZW50cyApO1xuXHRcdFx0XHR2ZXJ0aWNlc01vdmVtZW50cyA9IHZlcnRpY2VzTW92ZW1lbnRzLmNvbmNhdCggb25lSG9sZU1vdmVtZW50cyApO1xuXG5cdFx0XHR9XG5cblxuXHRcdFx0Ly8gTG9vcCBiZXZlbFNlZ21lbnRzLCAxIGZvciB0aGUgZnJvbnQsIDEgZm9yIHRoZSBiYWNrXG5cblx0XHRcdGZvciAoIGxldCBiID0gMDsgYiA8IGJldmVsU2VnbWVudHM7IGIgKysgKSB7XG5cblx0XHRcdFx0Ly9mb3IgKCBiID0gYmV2ZWxTZWdtZW50czsgYiA+IDA7IGIgLS0gKSB7XG5cblx0XHRcdFx0Y29uc3QgdCA9IGIgLyBiZXZlbFNlZ21lbnRzO1xuXHRcdFx0XHRjb25zdCB6ID0gYmV2ZWxUaGlja25lc3MgKiBNYXRoLmNvcyggdCAqIE1hdGguUEkgLyAyICk7XG5cdFx0XHRcdGNvbnN0IGJzID0gYmV2ZWxTaXplICogTWF0aC5zaW4oIHQgKiBNYXRoLlBJIC8gMiApICsgYmV2ZWxPZmZzZXQ7XG5cblx0XHRcdFx0Ly8gY29udHJhY3Qgc2hhcGVcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gY29udG91ci5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IHZlcnQgPSBzY2FsZVB0MiggY29udG91clsgaSBdLCBjb250b3VyTW92ZW1lbnRzWyBpIF0sIGJzICk7XG5cblx0XHRcdFx0XHR2KCB2ZXJ0LngsIHZlcnQueSwgLSB6ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIGV4cGFuZCBob2xlc1xuXG5cdFx0XHRcdGZvciAoIGxldCBoID0gMCwgaGwgPSBob2xlcy5sZW5ndGg7IGggPCBobDsgaCArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcblx0XHRcdFx0XHRvbmVIb2xlTW92ZW1lbnRzID0gaG9sZXNNb3ZlbWVudHNbIGggXTtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBhaG9sZS5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgdmVydCA9IHNjYWxlUHQyKCBhaG9sZVsgaSBdLCBvbmVIb2xlTW92ZW1lbnRzWyBpIF0sIGJzICk7XG5cblx0XHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCAtIHogKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgYnMgPSBiZXZlbFNpemUgKyBiZXZlbE9mZnNldDtcblxuXHRcdFx0Ly8gQmFjayBmYWNpbmcgdmVydGljZXNcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdmxlbjsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCB2ZXJ0ID0gYmV2ZWxFbmFibGVkID8gc2NhbGVQdDIoIHZlcnRpY2VzWyBpIF0sIHZlcnRpY2VzTW92ZW1lbnRzWyBpIF0sIGJzICkgOiB2ZXJ0aWNlc1sgaSBdO1xuXG5cdFx0XHRcdGlmICggISBleHRydWRlQnlQYXRoICkge1xuXG5cdFx0XHRcdFx0diggdmVydC54LCB2ZXJ0LnksIDAgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ly8gdiggdmVydC54LCB2ZXJ0LnkgKyBleHRydWRlUHRzWyAwIF0ueSwgZXh0cnVkZVB0c1sgMCBdLnggKTtcblxuXHRcdFx0XHRcdG5vcm1hbC5jb3B5KCBzcGxpbmVUdWJlLm5vcm1hbHNbIDAgXSApLm11bHRpcGx5U2NhbGFyKCB2ZXJ0LnggKTtcblx0XHRcdFx0XHRiaW5vcm1hbC5jb3B5KCBzcGxpbmVUdWJlLmJpbm9ybWFsc1sgMCBdICkubXVsdGlwbHlTY2FsYXIoIHZlcnQueSApO1xuXG5cdFx0XHRcdFx0cG9zaXRpb24yLmNvcHkoIGV4dHJ1ZGVQdHNbIDAgXSApLmFkZCggbm9ybWFsICkuYWRkKCBiaW5vcm1hbCApO1xuXG5cdFx0XHRcdFx0diggcG9zaXRpb24yLngsIHBvc2l0aW9uMi55LCBwb3NpdGlvbjIueiApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBBZGQgc3RlcHBlZCB2ZXJ0aWNlcy4uLlxuXHRcdFx0Ly8gSW5jbHVkaW5nIGZyb250IGZhY2luZyB2ZXJ0aWNlc1xuXG5cdFx0XHRmb3IgKCBsZXQgcyA9IDE7IHMgPD0gc3RlcHM7IHMgKysgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdmxlbjsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IHZlcnQgPSBiZXZlbEVuYWJsZWQgPyBzY2FsZVB0MiggdmVydGljZXNbIGkgXSwgdmVydGljZXNNb3ZlbWVudHNbIGkgXSwgYnMgKSA6IHZlcnRpY2VzWyBpIF07XG5cblx0XHRcdFx0XHRpZiAoICEgZXh0cnVkZUJ5UGF0aCApIHtcblxuXHRcdFx0XHRcdFx0diggdmVydC54LCB2ZXJ0LnksIGRlcHRoIC8gc3RlcHMgKiBzICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHQvLyB2KCB2ZXJ0LngsIHZlcnQueSArIGV4dHJ1ZGVQdHNbIHMgLSAxIF0ueSwgZXh0cnVkZVB0c1sgcyAtIDEgXS54ICk7XG5cblx0XHRcdFx0XHRcdG5vcm1hbC5jb3B5KCBzcGxpbmVUdWJlLm5vcm1hbHNbIHMgXSApLm11bHRpcGx5U2NhbGFyKCB2ZXJ0LnggKTtcblx0XHRcdFx0XHRcdGJpbm9ybWFsLmNvcHkoIHNwbGluZVR1YmUuYmlub3JtYWxzWyBzIF0gKS5tdWx0aXBseVNjYWxhciggdmVydC55ICk7XG5cblx0XHRcdFx0XHRcdHBvc2l0aW9uMi5jb3B5KCBleHRydWRlUHRzWyBzIF0gKS5hZGQoIG5vcm1hbCApLmFkZCggYmlub3JtYWwgKTtcblxuXHRcdFx0XHRcdFx0diggcG9zaXRpb24yLngsIHBvc2l0aW9uMi55LCBwb3NpdGlvbjIueiApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cblx0XHRcdC8vIEFkZCBiZXZlbCBzZWdtZW50cyBwbGFuZXNcblxuXHRcdFx0Ly9mb3IgKCBiID0gMTsgYiA8PSBiZXZlbFNlZ21lbnRzOyBiICsrICkge1xuXHRcdFx0Zm9yICggbGV0IGIgPSBiZXZlbFNlZ21lbnRzIC0gMTsgYiA+PSAwOyBiIC0tICkge1xuXG5cdFx0XHRcdGNvbnN0IHQgPSBiIC8gYmV2ZWxTZWdtZW50cztcblx0XHRcdFx0Y29uc3QgeiA9IGJldmVsVGhpY2tuZXNzICogTWF0aC5jb3MoIHQgKiBNYXRoLlBJIC8gMiApO1xuXHRcdFx0XHRjb25zdCBicyA9IGJldmVsU2l6ZSAqIE1hdGguc2luKCB0ICogTWF0aC5QSSAvIDIgKSArIGJldmVsT2Zmc2V0O1xuXG5cdFx0XHRcdC8vIGNvbnRyYWN0IHNoYXBlXG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGNvbnRvdXIubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB2ZXJ0ID0gc2NhbGVQdDIoIGNvbnRvdXJbIGkgXSwgY29udG91ck1vdmVtZW50c1sgaSBdLCBicyApO1xuXHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCBkZXB0aCArIHogKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gZXhwYW5kIGhvbGVzXG5cblx0XHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgYWhvbGUgPSBob2xlc1sgaCBdO1xuXHRcdFx0XHRcdG9uZUhvbGVNb3ZlbWVudHMgPSBob2xlc01vdmVtZW50c1sgaCBdO1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGFob2xlLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCB2ZXJ0ID0gc2NhbGVQdDIoIGFob2xlWyBpIF0sIG9uZUhvbGVNb3ZlbWVudHNbIGkgXSwgYnMgKTtcblxuXHRcdFx0XHRcdFx0aWYgKCAhIGV4dHJ1ZGVCeVBhdGggKSB7XG5cblx0XHRcdFx0XHRcdFx0diggdmVydC54LCB2ZXJ0LnksIGRlcHRoICsgeiApO1xuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55ICsgZXh0cnVkZVB0c1sgc3RlcHMgLSAxIF0ueSwgZXh0cnVkZVB0c1sgc3RlcHMgLSAxIF0ueCArIHogKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvKiBGYWNlcyAqL1xuXG5cdFx0XHQvLyBUb3AgYW5kIGJvdHRvbSBmYWNlc1xuXG5cdFx0XHRidWlsZExpZEZhY2VzKCk7XG5cblx0XHRcdC8vIFNpZGVzIGZhY2VzXG5cblx0XHRcdGJ1aWxkU2lkZUZhY2VzKCk7XG5cblxuXHRcdFx0Ly8vLy8gIEludGVybmFsIGZ1bmN0aW9uc1xuXG5cdFx0XHRmdW5jdGlvbiBidWlsZExpZEZhY2VzKCkge1xuXG5cdFx0XHRcdGNvbnN0IHN0YXJ0ID0gdmVydGljZXNBcnJheS5sZW5ndGggLyAzO1xuXG5cdFx0XHRcdGlmICggYmV2ZWxFbmFibGVkICkge1xuXG5cdFx0XHRcdFx0bGV0IGxheWVyID0gMDsgLy8gc3RlcHMgKyAxXG5cdFx0XHRcdFx0bGV0IG9mZnNldCA9IHZsZW4gKiBsYXllcjtcblxuXHRcdFx0XHRcdC8vIEJvdHRvbSBmYWNlc1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZmxlbjsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgZmFjZSA9IGZhY2VzWyBpIF07XG5cdFx0XHRcdFx0XHRmMyggZmFjZVsgMiBdICsgb2Zmc2V0LCBmYWNlWyAxIF0gKyBvZmZzZXQsIGZhY2VbIDAgXSArIG9mZnNldCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0bGF5ZXIgPSBzdGVwcyArIGJldmVsU2VnbWVudHMgKiAyO1xuXHRcdFx0XHRcdG9mZnNldCA9IHZsZW4gKiBsYXllcjtcblxuXHRcdFx0XHRcdC8vIFRvcCBmYWNlc1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZmxlbjsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgZmFjZSA9IGZhY2VzWyBpIF07XG5cdFx0XHRcdFx0XHRmMyggZmFjZVsgMCBdICsgb2Zmc2V0LCBmYWNlWyAxIF0gKyBvZmZzZXQsIGZhY2VbIDIgXSArIG9mZnNldCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBCb3R0b20gZmFjZXNcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGZsZW47IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGZhY2UgPSBmYWNlc1sgaSBdO1xuXHRcdFx0XHRcdFx0ZjMoIGZhY2VbIDIgXSwgZmFjZVsgMSBdLCBmYWNlWyAwIF0gKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIFRvcCBmYWNlc1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZmxlbjsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgZmFjZSA9IGZhY2VzWyBpIF07XG5cdFx0XHRcdFx0XHRmMyggZmFjZVsgMCBdICsgdmxlbiAqIHN0ZXBzLCBmYWNlWyAxIF0gKyB2bGVuICogc3RlcHMsIGZhY2VbIDIgXSArIHZsZW4gKiBzdGVwcyApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzY29wZS5hZGRHcm91cCggc3RhcnQsIHZlcnRpY2VzQXJyYXkubGVuZ3RoIC8gMyAtIHN0YXJ0LCAwICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gQ3JlYXRlIGZhY2VzIGZvciB0aGUgei1zaWRlcyBvZiB0aGUgc2hhcGVcblxuXHRcdFx0ZnVuY3Rpb24gYnVpbGRTaWRlRmFjZXMoKSB7XG5cblx0XHRcdFx0Y29uc3Qgc3RhcnQgPSB2ZXJ0aWNlc0FycmF5Lmxlbmd0aCAvIDM7XG5cdFx0XHRcdGxldCBsYXllcm9mZnNldCA9IDA7XG5cdFx0XHRcdHNpZGV3YWxscyggY29udG91ciwgbGF5ZXJvZmZzZXQgKTtcblx0XHRcdFx0bGF5ZXJvZmZzZXQgKz0gY29udG91ci5sZW5ndGg7XG5cblx0XHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgYWhvbGUgPSBob2xlc1sgaCBdO1xuXHRcdFx0XHRcdHNpZGV3YWxscyggYWhvbGUsIGxheWVyb2Zmc2V0ICk7XG5cblx0XHRcdFx0XHQvLywgdHJ1ZVxuXHRcdFx0XHRcdGxheWVyb2Zmc2V0ICs9IGFob2xlLmxlbmd0aDtcblxuXHRcdFx0XHR9XG5cblxuXHRcdFx0XHRzY29wZS5hZGRHcm91cCggc3RhcnQsIHZlcnRpY2VzQXJyYXkubGVuZ3RoIC8gMyAtIHN0YXJ0LCAxICk7XG5cblxuXHRcdFx0fVxuXG5cdFx0XHRmdW5jdGlvbiBzaWRld2FsbHMoIGNvbnRvdXIsIGxheWVyb2Zmc2V0ICkge1xuXG5cdFx0XHRcdGxldCBpID0gY29udG91ci5sZW5ndGg7XG5cblx0XHRcdFx0d2hpbGUgKCAtLSBpID49IDAgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBqID0gaTtcblx0XHRcdFx0XHRsZXQgayA9IGkgLSAxO1xuXHRcdFx0XHRcdGlmICggayA8IDAgKSBrID0gY29udG91ci5sZW5ndGggLSAxO1xuXG5cdFx0XHRcdFx0Ly9jb25zb2xlLmxvZygnYicsIGksaiwgaS0xLCBrLHZlcnRpY2VzLmxlbmd0aCk7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgcyA9IDAsIHNsID0gKCBzdGVwcyArIGJldmVsU2VnbWVudHMgKiAyICk7IHMgPCBzbDsgcyArKyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3Qgc2xlbjEgPSB2bGVuICogcztcblx0XHRcdFx0XHRcdGNvbnN0IHNsZW4yID0gdmxlbiAqICggcyArIDEgKTtcblxuXHRcdFx0XHRcdFx0Y29uc3QgYSA9IGxheWVyb2Zmc2V0ICsgaiArIHNsZW4xLFxuXHRcdFx0XHRcdFx0XHRiID0gbGF5ZXJvZmZzZXQgKyBrICsgc2xlbjEsXG5cdFx0XHRcdFx0XHRcdGMgPSBsYXllcm9mZnNldCArIGsgKyBzbGVuMixcblx0XHRcdFx0XHRcdFx0ZCA9IGxheWVyb2Zmc2V0ICsgaiArIHNsZW4yO1xuXG5cdFx0XHRcdFx0XHRmNCggYSwgYiwgYywgZCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRmdW5jdGlvbiB2KCB4LCB5LCB6ICkge1xuXG5cdFx0XHRcdHBsYWNlaG9sZGVyLnB1c2goIHggKTtcblx0XHRcdFx0cGxhY2Vob2xkZXIucHVzaCggeSApO1xuXHRcdFx0XHRwbGFjZWhvbGRlci5wdXNoKCB6ICk7XG5cblx0XHRcdH1cblxuXG5cdFx0XHRmdW5jdGlvbiBmMyggYSwgYiwgYyApIHtcblxuXHRcdFx0XHRhZGRWZXJ0ZXgoIGEgKTtcblx0XHRcdFx0YWRkVmVydGV4KCBiICk7XG5cdFx0XHRcdGFkZFZlcnRleCggYyApO1xuXG5cdFx0XHRcdGNvbnN0IG5leHRJbmRleCA9IHZlcnRpY2VzQXJyYXkubGVuZ3RoIC8gMztcblx0XHRcdFx0Y29uc3QgdXZzID0gdXZnZW4uZ2VuZXJhdGVUb3BVViggc2NvcGUsIHZlcnRpY2VzQXJyYXksIG5leHRJbmRleCAtIDMsIG5leHRJbmRleCAtIDIsIG5leHRJbmRleCAtIDEgKTtcblxuXHRcdFx0XHRhZGRVViggdXZzWyAwIF0gKTtcblx0XHRcdFx0YWRkVVYoIHV2c1sgMSBdICk7XG5cdFx0XHRcdGFkZFVWKCB1dnNbIDIgXSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGZ1bmN0aW9uIGY0KCBhLCBiLCBjLCBkICkge1xuXG5cdFx0XHRcdGFkZFZlcnRleCggYSApO1xuXHRcdFx0XHRhZGRWZXJ0ZXgoIGIgKTtcblx0XHRcdFx0YWRkVmVydGV4KCBkICk7XG5cblx0XHRcdFx0YWRkVmVydGV4KCBiICk7XG5cdFx0XHRcdGFkZFZlcnRleCggYyApO1xuXHRcdFx0XHRhZGRWZXJ0ZXgoIGQgKTtcblxuXG5cdFx0XHRcdGNvbnN0IG5leHRJbmRleCA9IHZlcnRpY2VzQXJyYXkubGVuZ3RoIC8gMztcblx0XHRcdFx0Y29uc3QgdXZzID0gdXZnZW4uZ2VuZXJhdGVTaWRlV2FsbFVWKCBzY29wZSwgdmVydGljZXNBcnJheSwgbmV4dEluZGV4IC0gNiwgbmV4dEluZGV4IC0gMywgbmV4dEluZGV4IC0gMiwgbmV4dEluZGV4IC0gMSApO1xuXG5cdFx0XHRcdGFkZFVWKCB1dnNbIDAgXSApO1xuXHRcdFx0XHRhZGRVViggdXZzWyAxIF0gKTtcblx0XHRcdFx0YWRkVVYoIHV2c1sgMyBdICk7XG5cblx0XHRcdFx0YWRkVVYoIHV2c1sgMSBdICk7XG5cdFx0XHRcdGFkZFVWKCB1dnNbIDIgXSApO1xuXHRcdFx0XHRhZGRVViggdXZzWyAzIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRmdW5jdGlvbiBhZGRWZXJ0ZXgoIGluZGV4ICkge1xuXG5cdFx0XHRcdHZlcnRpY2VzQXJyYXkucHVzaCggcGxhY2Vob2xkZXJbIGluZGV4ICogMyArIDAgXSApO1xuXHRcdFx0XHR2ZXJ0aWNlc0FycmF5LnB1c2goIHBsYWNlaG9sZGVyWyBpbmRleCAqIDMgKyAxIF0gKTtcblx0XHRcdFx0dmVydGljZXNBcnJheS5wdXNoKCBwbGFjZWhvbGRlclsgaW5kZXggKiAzICsgMiBdICk7XG5cblx0XHRcdH1cblxuXG5cdFx0XHRmdW5jdGlvbiBhZGRVViggdmVjdG9yMiApIHtcblxuXHRcdFx0XHR1dkFycmF5LnB1c2goIHZlY3RvcjIueCApO1xuXHRcdFx0XHR1dkFycmF5LnB1c2goIHZlY3RvcjIueSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0Y29uc3Qgc2hhcGVzID0gdGhpcy5wYXJhbWV0ZXJzLnNoYXBlcztcblx0XHRjb25zdCBvcHRpb25zID0gdGhpcy5wYXJhbWV0ZXJzLm9wdGlvbnM7XG5cblx0XHRyZXR1cm4gdG9KU09OJDEoIHNoYXBlcywgb3B0aW9ucywgZGF0YSApO1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEsIHNoYXBlcyApIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5U2hhcGVzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaiA9IDAsIGpsID0gZGF0YS5zaGFwZXMubGVuZ3RoOyBqIDwgamw7IGogKysgKSB7XG5cblx0XHRcdGNvbnN0IHNoYXBlID0gc2hhcGVzWyBkYXRhLnNoYXBlc1sgaiBdIF07XG5cblx0XHRcdGdlb21ldHJ5U2hhcGVzLnB1c2goIHNoYXBlICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBleHRydWRlUGF0aCA9IGRhdGEub3B0aW9ucy5leHRydWRlUGF0aDtcblxuXHRcdGlmICggZXh0cnVkZVBhdGggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0ZGF0YS5vcHRpb25zLmV4dHJ1ZGVQYXRoID0gbmV3IEN1cnZlc1sgZXh0cnVkZVBhdGgudHlwZSBdKCkuZnJvbUpTT04oIGV4dHJ1ZGVQYXRoICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gbmV3IEV4dHJ1ZGVHZW9tZXRyeSggZ2VvbWV0cnlTaGFwZXMsIGRhdGEub3B0aW9ucyApO1xuXG5cdH1cblxufVxuXG5jb25zdCBXb3JsZFVWR2VuZXJhdG9yID0ge1xuXG5cdGdlbmVyYXRlVG9wVVY6IGZ1bmN0aW9uICggZ2VvbWV0cnksIHZlcnRpY2VzLCBpbmRleEEsIGluZGV4QiwgaW5kZXhDICkge1xuXG5cdFx0Y29uc3QgYV94ID0gdmVydGljZXNbIGluZGV4QSAqIDMgXTtcblx0XHRjb25zdCBhX3kgPSB2ZXJ0aWNlc1sgaW5kZXhBICogMyArIDEgXTtcblx0XHRjb25zdCBiX3ggPSB2ZXJ0aWNlc1sgaW5kZXhCICogMyBdO1xuXHRcdGNvbnN0IGJfeSA9IHZlcnRpY2VzWyBpbmRleEIgKiAzICsgMSBdO1xuXHRcdGNvbnN0IGNfeCA9IHZlcnRpY2VzWyBpbmRleEMgKiAzIF07XG5cdFx0Y29uc3QgY195ID0gdmVydGljZXNbIGluZGV4QyAqIDMgKyAxIF07XG5cblx0XHRyZXR1cm4gW1xuXHRcdFx0bmV3IFZlY3RvcjIoIGFfeCwgYV95ICksXG5cdFx0XHRuZXcgVmVjdG9yMiggYl94LCBiX3kgKSxcblx0XHRcdG5ldyBWZWN0b3IyKCBjX3gsIGNfeSApXG5cdFx0XTtcblxuXHR9LFxuXG5cdGdlbmVyYXRlU2lkZVdhbGxVVjogZnVuY3Rpb24gKCBnZW9tZXRyeSwgdmVydGljZXMsIGluZGV4QSwgaW5kZXhCLCBpbmRleEMsIGluZGV4RCApIHtcblxuXHRcdGNvbnN0IGFfeCA9IHZlcnRpY2VzWyBpbmRleEEgKiAzIF07XG5cdFx0Y29uc3QgYV95ID0gdmVydGljZXNbIGluZGV4QSAqIDMgKyAxIF07XG5cdFx0Y29uc3QgYV96ID0gdmVydGljZXNbIGluZGV4QSAqIDMgKyAyIF07XG5cdFx0Y29uc3QgYl94ID0gdmVydGljZXNbIGluZGV4QiAqIDMgXTtcblx0XHRjb25zdCBiX3kgPSB2ZXJ0aWNlc1sgaW5kZXhCICogMyArIDEgXTtcblx0XHRjb25zdCBiX3ogPSB2ZXJ0aWNlc1sgaW5kZXhCICogMyArIDIgXTtcblx0XHRjb25zdCBjX3ggPSB2ZXJ0aWNlc1sgaW5kZXhDICogMyBdO1xuXHRcdGNvbnN0IGNfeSA9IHZlcnRpY2VzWyBpbmRleEMgKiAzICsgMSBdO1xuXHRcdGNvbnN0IGNfeiA9IHZlcnRpY2VzWyBpbmRleEMgKiAzICsgMiBdO1xuXHRcdGNvbnN0IGRfeCA9IHZlcnRpY2VzWyBpbmRleEQgKiAzIF07XG5cdFx0Y29uc3QgZF95ID0gdmVydGljZXNbIGluZGV4RCAqIDMgKyAxIF07XG5cdFx0Y29uc3QgZF96ID0gdmVydGljZXNbIGluZGV4RCAqIDMgKyAyIF07XG5cblx0XHRpZiAoIE1hdGguYWJzKCBhX3kgLSBiX3kgKSA8IE1hdGguYWJzKCBhX3ggLSBiX3ggKSApIHtcblxuXHRcdFx0cmV0dXJuIFtcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGFfeCwgMSAtIGFfeiApLFxuXHRcdFx0XHRuZXcgVmVjdG9yMiggYl94LCAxIC0gYl96ICksXG5cdFx0XHRcdG5ldyBWZWN0b3IyKCBjX3gsIDEgLSBjX3ogKSxcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGRfeCwgMSAtIGRfeiApXG5cdFx0XHRdO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmV0dXJuIFtcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGFfeSwgMSAtIGFfeiApLFxuXHRcdFx0XHRuZXcgVmVjdG9yMiggYl95LCAxIC0gYl96ICksXG5cdFx0XHRcdG5ldyBWZWN0b3IyKCBjX3ksIDEgLSBjX3ogKSxcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGRfeSwgMSAtIGRfeiApXG5cdFx0XHRdO1xuXG5cdFx0fVxuXG5cdH1cblxufTtcblxuZnVuY3Rpb24gdG9KU09OJDEoIHNoYXBlcywgb3B0aW9ucywgZGF0YSApIHtcblxuXHRkYXRhLnNoYXBlcyA9IFtdO1xuXG5cdGlmICggQXJyYXkuaXNBcnJheSggc2hhcGVzICkgKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzaGFwZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3Qgc2hhcGUgPSBzaGFwZXNbIGkgXTtcblxuXHRcdFx0ZGF0YS5zaGFwZXMucHVzaCggc2hhcGUudXVpZCApO1xuXG5cdFx0fVxuXG5cdH0gZWxzZSB7XG5cblx0XHRkYXRhLnNoYXBlcy5wdXNoKCBzaGFwZXMudXVpZCApO1xuXG5cdH1cblxuXHRkYXRhLm9wdGlvbnMgPSBPYmplY3QuYXNzaWduKCB7fSwgb3B0aW9ucyApO1xuXG5cdGlmICggb3B0aW9ucy5leHRydWRlUGF0aCAhPT0gdW5kZWZpbmVkICkgZGF0YS5vcHRpb25zLmV4dHJ1ZGVQYXRoID0gb3B0aW9ucy5leHRydWRlUGF0aC50b0pTT04oKTtcblxuXHRyZXR1cm4gZGF0YTtcblxufVxuXG5jbGFzcyBJY29zYWhlZHJvbkdlb21ldHJ5IGV4dGVuZHMgUG9seWhlZHJvbkdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgZGV0YWlsID0gMCApIHtcblxuXHRcdGNvbnN0IHQgPSAoIDEgKyBNYXRoLnNxcnQoIDUgKSApIC8gMjtcblxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW1xuXHRcdFx0LSAxLCB0LCAwLCBcdDEsIHQsIDAsIFx0LSAxLCAtIHQsIDAsIFx0MSwgLSB0LCAwLFxuXHRcdFx0MCwgLSAxLCB0LCBcdDAsIDEsIHQsXHQwLCAtIDEsIC0gdCwgXHQwLCAxLCAtIHQsXG5cdFx0XHR0LCAwLCAtIDEsIFx0dCwgMCwgMSwgXHQtIHQsIDAsIC0gMSwgXHQtIHQsIDAsIDFcblx0XHRdO1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtcblx0XHRcdDAsIDExLCA1LCBcdDAsIDUsIDEsIFx0MCwgMSwgNywgXHQwLCA3LCAxMCwgXHQwLCAxMCwgMTEsXG5cdFx0XHQxLCA1LCA5LCBcdDUsIDExLCA0LFx0MTEsIDEwLCAyLFx0MTAsIDcsIDYsXHQ3LCAxLCA4LFxuXHRcdFx0MywgOSwgNCwgXHQzLCA0LCAyLFx0MywgMiwgNixcdDMsIDYsIDgsXHQzLCA4LCA5LFxuXHRcdFx0NCwgOSwgNSwgXHQyLCA0LCAxMSxcdDYsIDIsIDEwLFx0OCwgNiwgNyxcdDksIDgsIDFcblx0XHRdO1xuXG5cdFx0c3VwZXIoIHZlcnRpY2VzLCBpbmRpY2VzLCByYWRpdXMsIGRldGFpbCApO1xuXG5cdFx0dGhpcy50eXBlID0gJ0ljb3NhaGVkcm9uR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0cmFkaXVzOiByYWRpdXMsXG5cdFx0XHRkZXRhaWw6IGRldGFpbFxuXHRcdH07XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdHJldHVybiBuZXcgSWNvc2FoZWRyb25HZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEuZGV0YWlsICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIE9jdGFoZWRyb25HZW9tZXRyeSBleHRlbmRzIFBvbHloZWRyb25HZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIGRldGFpbCA9IDAgKSB7XG5cblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtcblx0XHRcdDEsIDAsIDAsIFx0LSAxLCAwLCAwLFx0MCwgMSwgMCxcblx0XHRcdDAsIC0gMSwgMCwgXHQwLCAwLCAxLFx0MCwgMCwgLSAxXG5cdFx0XTtcblxuXHRcdGNvbnN0IGluZGljZXMgPSBbXG5cdFx0XHQwLCAyLCA0LFx0MCwgNCwgMyxcdDAsIDMsIDUsXG5cdFx0XHQwLCA1LCAyLFx0MSwgMiwgNSxcdDEsIDUsIDMsXG5cdFx0XHQxLCAzLCA0LFx0MSwgNCwgMlxuXHRcdF07XG5cblx0XHRzdXBlciggdmVydGljZXMsIGluZGljZXMsIHJhZGl1cywgZGV0YWlsICk7XG5cblx0XHR0aGlzLnR5cGUgPSAnT2N0YWhlZHJvbkdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHJhZGl1czogcmFkaXVzLFxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcblx0XHR9O1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IE9jdGFoZWRyb25HZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEuZGV0YWlsICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFJpbmdHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggaW5uZXJSYWRpdXMgPSAwLjUsIG91dGVyUmFkaXVzID0gMSwgdGhldGFTZWdtZW50cyA9IDMyLCBwaGlTZWdtZW50cyA9IDEsIHRoZXRhU3RhcnQgPSAwLCB0aGV0YUxlbmd0aCA9IE1hdGguUEkgKiAyICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdSaW5nR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0aW5uZXJSYWRpdXM6IGlubmVyUmFkaXVzLFxuXHRcdFx0b3V0ZXJSYWRpdXM6IG91dGVyUmFkaXVzLFxuXHRcdFx0dGhldGFTZWdtZW50czogdGhldGFTZWdtZW50cyxcblx0XHRcdHBoaVNlZ21lbnRzOiBwaGlTZWdtZW50cyxcblx0XHRcdHRoZXRhU3RhcnQ6IHRoZXRhU3RhcnQsXG5cdFx0XHR0aGV0YUxlbmd0aDogdGhldGFMZW5ndGhcblx0XHR9O1xuXG5cdFx0dGhldGFTZWdtZW50cyA9IE1hdGgubWF4KCAzLCB0aGV0YVNlZ21lbnRzICk7XG5cdFx0cGhpU2VnbWVudHMgPSBNYXRoLm1heCggMSwgcGhpU2VnbWVudHMgKTtcblxuXHRcdC8vIGJ1ZmZlcnNcblxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcblx0XHRjb25zdCB1dnMgPSBbXTtcblxuXHRcdC8vIHNvbWUgaGVscGVyIHZhcmlhYmxlc1xuXG5cdFx0bGV0IHJhZGl1cyA9IGlubmVyUmFkaXVzO1xuXHRcdGNvbnN0IHJhZGl1c1N0ZXAgPSAoICggb3V0ZXJSYWRpdXMgLSBpbm5lclJhZGl1cyApIC8gcGhpU2VnbWVudHMgKTtcblx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IHV2ID0gbmV3IFZlY3RvcjIoKTtcblxuXHRcdC8vIGdlbmVyYXRlIHZlcnRpY2VzLCBub3JtYWxzIGFuZCB1dnNcblxuXHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSBwaGlTZWdtZW50czsgaiArKyApIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IHRoZXRhU2VnbWVudHM7IGkgKysgKSB7XG5cblx0XHRcdFx0Ly8gdmFsdWVzIGFyZSBnZW5lcmF0ZSBmcm9tIHRoZSBpbnNpZGUgb2YgdGhlIHJpbmcgdG8gdGhlIG91dHNpZGVcblxuXHRcdFx0XHRjb25zdCBzZWdtZW50ID0gdGhldGFTdGFydCArIGkgLyB0aGV0YVNlZ21lbnRzICogdGhldGFMZW5ndGg7XG5cblx0XHRcdFx0Ly8gdmVydGV4XG5cblx0XHRcdFx0dmVydGV4LnggPSByYWRpdXMgKiBNYXRoLmNvcyggc2VnbWVudCApO1xuXHRcdFx0XHR2ZXJ0ZXgueSA9IHJhZGl1cyAqIE1hdGguc2luKCBzZWdtZW50ICk7XG5cblx0XHRcdFx0dmVydGljZXMucHVzaCggdmVydGV4LngsIHZlcnRleC55LCB2ZXJ0ZXgueiApO1xuXG5cdFx0XHRcdC8vIG5vcm1hbFxuXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgMCwgMSApO1xuXG5cdFx0XHRcdC8vIHV2XG5cblx0XHRcdFx0dXYueCA9ICggdmVydGV4LnggLyBvdXRlclJhZGl1cyArIDEgKSAvIDI7XG5cdFx0XHRcdHV2LnkgPSAoIHZlcnRleC55IC8gb3V0ZXJSYWRpdXMgKyAxICkgLyAyO1xuXG5cdFx0XHRcdHV2cy5wdXNoKCB1di54LCB1di55ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gaW5jcmVhc2UgdGhlIHJhZGl1cyBmb3IgbmV4dCByb3cgb2YgdmVydGljZXNcblxuXHRcdFx0cmFkaXVzICs9IHJhZGl1c1N0ZXA7XG5cblx0XHR9XG5cblx0XHQvLyBpbmRpY2VzXG5cblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBwaGlTZWdtZW50czsgaiArKyApIHtcblxuXHRcdFx0Y29uc3QgdGhldGFTZWdtZW50TGV2ZWwgPSBqICogKCB0aGV0YVNlZ21lbnRzICsgMSApO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGV0YVNlZ21lbnRzOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHNlZ21lbnQgPSBpICsgdGhldGFTZWdtZW50TGV2ZWw7XG5cblx0XHRcdFx0Y29uc3QgYSA9IHNlZ21lbnQ7XG5cdFx0XHRcdGNvbnN0IGIgPSBzZWdtZW50ICsgdGhldGFTZWdtZW50cyArIDE7XG5cdFx0XHRcdGNvbnN0IGMgPSBzZWdtZW50ICsgdGhldGFTZWdtZW50cyArIDI7XG5cdFx0XHRcdGNvbnN0IGQgPSBzZWdtZW50ICsgMTtcblxuXHRcdFx0XHQvLyBmYWNlc1xuXG5cdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGIsIGMsIGQgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcblxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBub3JtYWxzLCAzICkgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xuXG5cdFx0cmV0dXJuIG5ldyBSaW5nR2VvbWV0cnkoIGRhdGEuaW5uZXJSYWRpdXMsIGRhdGEub3V0ZXJSYWRpdXMsIGRhdGEudGhldGFTZWdtZW50cywgZGF0YS5waGlTZWdtZW50cywgZGF0YS50aGV0YVN0YXJ0LCBkYXRhLnRoZXRhTGVuZ3RoICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFNoYXBlR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHNoYXBlcyA9IG5ldyBTaGFwZSggWyBuZXcgVmVjdG9yMiggMCwgMC41ICksIG5ldyBWZWN0b3IyKCAtIDAuNSwgLSAwLjUgKSwgbmV3IFZlY3RvcjIoIDAuNSwgLSAwLjUgKSBdICksIGN1cnZlU2VnbWVudHMgPSAxMiApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnU2hhcGVHZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRzaGFwZXM6IHNoYXBlcyxcblx0XHRcdGN1cnZlU2VnbWVudHM6IGN1cnZlU2VnbWVudHNcblx0XHR9O1xuXG5cdFx0Ly8gYnVmZmVyc1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xuXHRcdGNvbnN0IHV2cyA9IFtdO1xuXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xuXG5cdFx0bGV0IGdyb3VwU3RhcnQgPSAwO1xuXHRcdGxldCBncm91cENvdW50ID0gMDtcblxuXHRcdC8vIGFsbG93IHNpbmdsZSBhbmQgYXJyYXkgdmFsdWVzIGZvciBcInNoYXBlc1wiIHBhcmFtZXRlclxuXG5cdFx0aWYgKCBBcnJheS5pc0FycmF5KCBzaGFwZXMgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdGFkZFNoYXBlKCBzaGFwZXMgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHNoYXBlcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0YWRkU2hhcGUoIHNoYXBlc1sgaSBdICk7XG5cblx0XHRcdFx0dGhpcy5hZGRHcm91cCggZ3JvdXBTdGFydCwgZ3JvdXBDb3VudCwgaSApOyAvLyBlbmFibGVzIE11bHRpTWF0ZXJpYWwgc3VwcG9ydFxuXG5cdFx0XHRcdGdyb3VwU3RhcnQgKz0gZ3JvdXBDb3VudDtcblx0XHRcdFx0Z3JvdXBDb3VudCA9IDA7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XG5cblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xuXG5cblx0XHQvLyBoZWxwZXIgZnVuY3Rpb25zXG5cblx0XHRmdW5jdGlvbiBhZGRTaGFwZSggc2hhcGUgKSB7XG5cblx0XHRcdGNvbnN0IGluZGV4T2Zmc2V0ID0gdmVydGljZXMubGVuZ3RoIC8gMztcblx0XHRcdGNvbnN0IHBvaW50cyA9IHNoYXBlLmV4dHJhY3RQb2ludHMoIGN1cnZlU2VnbWVudHMgKTtcblxuXHRcdFx0bGV0IHNoYXBlVmVydGljZXMgPSBwb2ludHMuc2hhcGU7XG5cdFx0XHRjb25zdCBzaGFwZUhvbGVzID0gcG9pbnRzLmhvbGVzO1xuXG5cdFx0XHQvLyBjaGVjayBkaXJlY3Rpb24gb2YgdmVydGljZXNcblxuXHRcdFx0aWYgKCBTaGFwZVV0aWxzLmlzQ2xvY2tXaXNlKCBzaGFwZVZlcnRpY2VzICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdHNoYXBlVmVydGljZXMgPSBzaGFwZVZlcnRpY2VzLnJldmVyc2UoKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzaGFwZUhvbGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2hhcGVIb2xlID0gc2hhcGVIb2xlc1sgaSBdO1xuXG5cdFx0XHRcdGlmICggU2hhcGVVdGlscy5pc0Nsb2NrV2lzZSggc2hhcGVIb2xlICkgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRzaGFwZUhvbGVzWyBpIF0gPSBzaGFwZUhvbGUucmV2ZXJzZSgpO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBmYWNlcyA9IFNoYXBlVXRpbHMudHJpYW5ndWxhdGVTaGFwZSggc2hhcGVWZXJ0aWNlcywgc2hhcGVIb2xlcyApO1xuXG5cdFx0XHQvLyBqb2luIHZlcnRpY2VzIG9mIGlubmVyIGFuZCBvdXRlciBwYXRocyB0byBhIHNpbmdsZSBhcnJheVxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzaGFwZUhvbGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2hhcGVIb2xlID0gc2hhcGVIb2xlc1sgaSBdO1xuXHRcdFx0XHRzaGFwZVZlcnRpY2VzID0gc2hhcGVWZXJ0aWNlcy5jb25jYXQoIHNoYXBlSG9sZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIHZlcnRpY2VzLCBub3JtYWxzLCB1dnNcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVWZXJ0aWNlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHZlcnRleCA9IHNoYXBlVmVydGljZXNbIGkgXTtcblxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIDAgKTtcblx0XHRcdFx0bm9ybWFscy5wdXNoKCAwLCAwLCAxICk7XG5cdFx0XHRcdHV2cy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnkgKTsgLy8gd29ybGQgdXZzXG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gaW5kaWNlc1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBmYWNlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGZhY2UgPSBmYWNlc1sgaSBdO1xuXG5cdFx0XHRcdGNvbnN0IGEgPSBmYWNlWyAwIF0gKyBpbmRleE9mZnNldDtcblx0XHRcdFx0Y29uc3QgYiA9IGZhY2VbIDEgXSArIGluZGV4T2Zmc2V0O1xuXHRcdFx0XHRjb25zdCBjID0gZmFjZVsgMiBdICsgaW5kZXhPZmZzZXQ7XG5cblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBhLCBiLCBjICk7XG5cdFx0XHRcdGdyb3VwQ291bnQgKz0gMztcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcblxuXHRcdGNvbnN0IHNoYXBlcyA9IHRoaXMucGFyYW1ldGVycy5zaGFwZXM7XG5cblx0XHRyZXR1cm4gdG9KU09OKCBzaGFwZXMsIGRhdGEgKTtcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhLCBzaGFwZXMgKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeVNoYXBlcyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGogPSAwLCBqbCA9IGRhdGEuc2hhcGVzLmxlbmd0aDsgaiA8IGpsOyBqICsrICkge1xuXG5cdFx0XHRjb25zdCBzaGFwZSA9IHNoYXBlc1sgZGF0YS5zaGFwZXNbIGogXSBdO1xuXG5cdFx0XHRnZW9tZXRyeVNoYXBlcy5wdXNoKCBzaGFwZSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG5ldyBTaGFwZUdlb21ldHJ5KCBnZW9tZXRyeVNoYXBlcywgZGF0YS5jdXJ2ZVNlZ21lbnRzICk7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHRvSlNPTiggc2hhcGVzLCBkYXRhICkge1xuXG5cdGRhdGEuc2hhcGVzID0gW107XG5cblx0aWYgKCBBcnJheS5pc0FycmF5KCBzaGFwZXMgKSApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNoYXBlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBzaGFwZSA9IHNoYXBlc1sgaSBdO1xuXG5cdFx0XHRkYXRhLnNoYXBlcy5wdXNoKCBzaGFwZS51dWlkICk7XG5cblx0XHR9XG5cblx0fSBlbHNlIHtcblxuXHRcdGRhdGEuc2hhcGVzLnB1c2goIHNoYXBlcy51dWlkICk7XG5cblx0fVxuXG5cdHJldHVybiBkYXRhO1xuXG59XG5cbmNsYXNzIFNwaGVyZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCB3aWR0aFNlZ21lbnRzID0gMzIsIGhlaWdodFNlZ21lbnRzID0gMTYsIHBoaVN0YXJ0ID0gMCwgcGhpTGVuZ3RoID0gTWF0aC5QSSAqIDIsIHRoZXRhU3RhcnQgPSAwLCB0aGV0YUxlbmd0aCA9IE1hdGguUEkgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ1NwaGVyZUdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHJhZGl1czogcmFkaXVzLFxuXHRcdFx0d2lkdGhTZWdtZW50czogd2lkdGhTZWdtZW50cyxcblx0XHRcdGhlaWdodFNlZ21lbnRzOiBoZWlnaHRTZWdtZW50cyxcblx0XHRcdHBoaVN0YXJ0OiBwaGlTdGFydCxcblx0XHRcdHBoaUxlbmd0aDogcGhpTGVuZ3RoLFxuXHRcdFx0dGhldGFTdGFydDogdGhldGFTdGFydCxcblx0XHRcdHRoZXRhTGVuZ3RoOiB0aGV0YUxlbmd0aFxuXHRcdH07XG5cblx0XHR3aWR0aFNlZ21lbnRzID0gTWF0aC5tYXgoIDMsIE1hdGguZmxvb3IoIHdpZHRoU2VnbWVudHMgKSApO1xuXHRcdGhlaWdodFNlZ21lbnRzID0gTWF0aC5tYXgoIDIsIE1hdGguZmxvb3IoIGhlaWdodFNlZ21lbnRzICkgKTtcblxuXHRcdGNvbnN0IHRoZXRhRW5kID0gTWF0aC5taW4oIHRoZXRhU3RhcnQgKyB0aGV0YUxlbmd0aCwgTWF0aC5QSSApO1xuXG5cdFx0bGV0IGluZGV4ID0gMDtcblx0XHRjb25zdCBncmlkID0gW107XG5cblx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IG5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHQvLyBidWZmZXJzXG5cblx0XHRjb25zdCBpbmRpY2VzID0gW107XG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcblx0XHRjb25zdCBub3JtYWxzID0gW107XG5cdFx0Y29uc3QgdXZzID0gW107XG5cblx0XHQvLyBnZW5lcmF0ZSB2ZXJ0aWNlcywgbm9ybWFscyBhbmQgdXZzXG5cblx0XHRmb3IgKCBsZXQgaXkgPSAwOyBpeSA8PSBoZWlnaHRTZWdtZW50czsgaXkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHZlcnRpY2VzUm93ID0gW107XG5cblx0XHRcdGNvbnN0IHYgPSBpeSAvIGhlaWdodFNlZ21lbnRzO1xuXG5cdFx0XHQvLyBzcGVjaWFsIGNhc2UgZm9yIHRoZSBwb2xlc1xuXG5cdFx0XHRsZXQgdU9mZnNldCA9IDA7XG5cblx0XHRcdGlmICggaXkgPT09IDAgJiYgdGhldGFTdGFydCA9PT0gMCApIHtcblxuXHRcdFx0XHR1T2Zmc2V0ID0gMC41IC8gd2lkdGhTZWdtZW50cztcblxuXHRcdFx0fSBlbHNlIGlmICggaXkgPT09IGhlaWdodFNlZ21lbnRzICYmIHRoZXRhRW5kID09PSBNYXRoLlBJICkge1xuXG5cdFx0XHRcdHVPZmZzZXQgPSAtIDAuNSAvIHdpZHRoU2VnbWVudHM7XG5cblx0XHRcdH1cblxuXHRcdFx0Zm9yICggbGV0IGl4ID0gMDsgaXggPD0gd2lkdGhTZWdtZW50czsgaXggKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgdSA9IGl4IC8gd2lkdGhTZWdtZW50cztcblxuXHRcdFx0XHQvLyB2ZXJ0ZXhcblxuXHRcdFx0XHR2ZXJ0ZXgueCA9IC0gcmFkaXVzICogTWF0aC5jb3MoIHBoaVN0YXJ0ICsgdSAqIHBoaUxlbmd0aCApICogTWF0aC5zaW4oIHRoZXRhU3RhcnQgKyB2ICogdGhldGFMZW5ndGggKTtcblx0XHRcdFx0dmVydGV4LnkgPSByYWRpdXMgKiBNYXRoLmNvcyggdGhldGFTdGFydCArIHYgKiB0aGV0YUxlbmd0aCApO1xuXHRcdFx0XHR2ZXJ0ZXgueiA9IHJhZGl1cyAqIE1hdGguc2luKCBwaGlTdGFydCArIHUgKiBwaGlMZW5ndGggKSAqIE1hdGguc2luKCB0aGV0YVN0YXJ0ICsgdiAqIHRoZXRhTGVuZ3RoICk7XG5cblx0XHRcdFx0dmVydGljZXMucHVzaCggdmVydGV4LngsIHZlcnRleC55LCB2ZXJ0ZXgueiApO1xuXG5cdFx0XHRcdC8vIG5vcm1hbFxuXG5cdFx0XHRcdG5vcm1hbC5jb3B5KCB2ZXJ0ZXggKS5ub3JtYWxpemUoKTtcblx0XHRcdFx0bm9ybWFscy5wdXNoKCBub3JtYWwueCwgbm9ybWFsLnksIG5vcm1hbC56ICk7XG5cblx0XHRcdFx0Ly8gdXZcblxuXHRcdFx0XHR1dnMucHVzaCggdSArIHVPZmZzZXQsIDEgLSB2ICk7XG5cblx0XHRcdFx0dmVydGljZXNSb3cucHVzaCggaW5kZXggKysgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRncmlkLnB1c2goIHZlcnRpY2VzUm93ICk7XG5cblx0XHR9XG5cblx0XHQvLyBpbmRpY2VzXG5cblx0XHRmb3IgKCBsZXQgaXkgPSAwOyBpeSA8IGhlaWdodFNlZ21lbnRzOyBpeSArKyApIHtcblxuXHRcdFx0Zm9yICggbGV0IGl4ID0gMDsgaXggPCB3aWR0aFNlZ21lbnRzOyBpeCArKyApIHtcblxuXHRcdFx0XHRjb25zdCBhID0gZ3JpZFsgaXkgXVsgaXggKyAxIF07XG5cdFx0XHRcdGNvbnN0IGIgPSBncmlkWyBpeSBdWyBpeCBdO1xuXHRcdFx0XHRjb25zdCBjID0gZ3JpZFsgaXkgKyAxIF1bIGl4IF07XG5cdFx0XHRcdGNvbnN0IGQgPSBncmlkWyBpeSArIDEgXVsgaXggKyAxIF07XG5cblx0XHRcdFx0aWYgKCBpeSAhPT0gMCB8fCB0aGV0YVN0YXJ0ID4gMCApIGluZGljZXMucHVzaCggYSwgYiwgZCApO1xuXHRcdFx0XHRpZiAoIGl5ICE9PSBoZWlnaHRTZWdtZW50cyAtIDEgfHwgdGhldGFFbmQgPCBNYXRoLlBJICkgaW5kaWNlcy5wdXNoKCBiLCBjLCBkICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XG5cblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdHJldHVybiBuZXcgU3BoZXJlR2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLndpZHRoU2VnbWVudHMsIGRhdGEuaGVpZ2h0U2VnbWVudHMsIGRhdGEucGhpU3RhcnQsIGRhdGEucGhpTGVuZ3RoLCBkYXRhLnRoZXRhU3RhcnQsIGRhdGEudGhldGFMZW5ndGggKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgVGV0cmFoZWRyb25HZW9tZXRyeSBleHRlbmRzIFBvbHloZWRyb25HZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIGRldGFpbCA9IDAgKSB7XG5cblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtcblx0XHRcdDEsIDEsIDEsIFx0LSAxLCAtIDEsIDEsIFx0LSAxLCAxLCAtIDEsIFx0MSwgLSAxLCAtIDFcblx0XHRdO1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtcblx0XHRcdDIsIDEsIDAsIFx0MCwgMywgMixcdDEsIDMsIDAsXHQyLCAzLCAxXG5cdFx0XTtcblxuXHRcdHN1cGVyKCB2ZXJ0aWNlcywgaW5kaWNlcywgcmFkaXVzLCBkZXRhaWwgKTtcblxuXHRcdHRoaXMudHlwZSA9ICdUZXRyYWhlZHJvbkdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHJhZGl1czogcmFkaXVzLFxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcblx0XHR9O1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IFRldHJhaGVkcm9uR2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLmRldGFpbCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBUb3J1c0dlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCB0dWJlID0gMC40LCByYWRpYWxTZWdtZW50cyA9IDEyLCB0dWJ1bGFyU2VnbWVudHMgPSA0OCwgYXJjID0gTWF0aC5QSSAqIDIgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ1RvcnVzR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0cmFkaXVzOiByYWRpdXMsXG5cdFx0XHR0dWJlOiB0dWJlLFxuXHRcdFx0cmFkaWFsU2VnbWVudHM6IHJhZGlhbFNlZ21lbnRzLFxuXHRcdFx0dHVidWxhclNlZ21lbnRzOiB0dWJ1bGFyU2VnbWVudHMsXG5cdFx0XHRhcmM6IGFyY1xuXHRcdH07XG5cblx0XHRyYWRpYWxTZWdtZW50cyA9IE1hdGguZmxvb3IoIHJhZGlhbFNlZ21lbnRzICk7XG5cdFx0dHVidWxhclNlZ21lbnRzID0gTWF0aC5mbG9vciggdHVidWxhclNlZ21lbnRzICk7XG5cblx0XHQvLyBidWZmZXJzXG5cblx0XHRjb25zdCBpbmRpY2VzID0gW107XG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcblx0XHRjb25zdCBub3JtYWxzID0gW107XG5cdFx0Y29uc3QgdXZzID0gW107XG5cblx0XHQvLyBoZWxwZXIgdmFyaWFibGVzXG5cblx0XHRjb25zdCBjZW50ZXIgPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0Y29uc3Qgbm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdC8vIGdlbmVyYXRlIHZlcnRpY2VzLCBub3JtYWxzIGFuZCB1dnNcblxuXHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSByYWRpYWxTZWdtZW50czsgaiArKyApIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IHR1YnVsYXJTZWdtZW50czsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCB1ID0gaSAvIHR1YnVsYXJTZWdtZW50cyAqIGFyYztcblx0XHRcdFx0Y29uc3QgdiA9IGogLyByYWRpYWxTZWdtZW50cyAqIE1hdGguUEkgKiAyO1xuXG5cdFx0XHRcdC8vIHZlcnRleFxuXG5cdFx0XHRcdHZlcnRleC54ID0gKCByYWRpdXMgKyB0dWJlICogTWF0aC5jb3MoIHYgKSApICogTWF0aC5jb3MoIHUgKTtcblx0XHRcdFx0dmVydGV4LnkgPSAoIHJhZGl1cyArIHR1YmUgKiBNYXRoLmNvcyggdiApICkgKiBNYXRoLnNpbiggdSApO1xuXHRcdFx0XHR2ZXJ0ZXgueiA9IHR1YmUgKiBNYXRoLnNpbiggdiApO1xuXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcblxuXHRcdFx0XHQvLyBub3JtYWxcblxuXHRcdFx0XHRjZW50ZXIueCA9IHJhZGl1cyAqIE1hdGguY29zKCB1ICk7XG5cdFx0XHRcdGNlbnRlci55ID0gcmFkaXVzICogTWF0aC5zaW4oIHUgKTtcblx0XHRcdFx0bm9ybWFsLnN1YlZlY3RvcnMoIHZlcnRleCwgY2VudGVyICkubm9ybWFsaXplKCk7XG5cblx0XHRcdFx0bm9ybWFscy5wdXNoKCBub3JtYWwueCwgbm9ybWFsLnksIG5vcm1hbC56ICk7XG5cblx0XHRcdFx0Ly8gdXZcblxuXHRcdFx0XHR1dnMucHVzaCggaSAvIHR1YnVsYXJTZWdtZW50cyApO1xuXHRcdFx0XHR1dnMucHVzaCggaiAvIHJhZGlhbFNlZ21lbnRzICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGdlbmVyYXRlIGluZGljZXNcblxuXHRcdGZvciAoIGxldCBqID0gMTsgaiA8PSByYWRpYWxTZWdtZW50czsgaiArKyApIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAxOyBpIDw9IHR1YnVsYXJTZWdtZW50czsgaSArKyApIHtcblxuXHRcdFx0XHQvLyBpbmRpY2VzXG5cblx0XHRcdFx0Y29uc3QgYSA9ICggdHVidWxhclNlZ21lbnRzICsgMSApICogaiArIGkgLSAxO1xuXHRcdFx0XHRjb25zdCBiID0gKCB0dWJ1bGFyU2VnbWVudHMgKyAxICkgKiAoIGogLSAxICkgKyBpIC0gMTtcblx0XHRcdFx0Y29uc3QgYyA9ICggdHVidWxhclNlZ21lbnRzICsgMSApICogKCBqIC0gMSApICsgaTtcblx0XHRcdFx0Y29uc3QgZCA9ICggdHVidWxhclNlZ21lbnRzICsgMSApICogaiArIGk7XG5cblx0XHRcdFx0Ly8gZmFjZXNcblxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBiLCBjLCBkICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XG5cblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdHJldHVybiBuZXcgVG9ydXNHZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEudHViZSwgZGF0YS5yYWRpYWxTZWdtZW50cywgZGF0YS50dWJ1bGFyU2VnbWVudHMsIGRhdGEuYXJjICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFRvcnVzS25vdEdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCB0dWJlID0gMC40LCB0dWJ1bGFyU2VnbWVudHMgPSA2NCwgcmFkaWFsU2VnbWVudHMgPSA4LCBwID0gMiwgcSA9IDMgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ1RvcnVzS25vdEdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHJhZGl1czogcmFkaXVzLFxuXHRcdFx0dHViZTogdHViZSxcblx0XHRcdHR1YnVsYXJTZWdtZW50czogdHVidWxhclNlZ21lbnRzLFxuXHRcdFx0cmFkaWFsU2VnbWVudHM6IHJhZGlhbFNlZ21lbnRzLFxuXHRcdFx0cDogcCxcblx0XHRcdHE6IHFcblx0XHR9O1xuXG5cdFx0dHVidWxhclNlZ21lbnRzID0gTWF0aC5mbG9vciggdHVidWxhclNlZ21lbnRzICk7XG5cdFx0cmFkaWFsU2VnbWVudHMgPSBNYXRoLmZsb29yKCByYWRpYWxTZWdtZW50cyApO1xuXG5cdFx0Ly8gYnVmZmVyc1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xuXHRcdGNvbnN0IHV2cyA9IFtdO1xuXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xuXG5cdFx0Y29uc3QgdmVydGV4ID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0Y29uc3QgUDEgPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IFAyID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdGNvbnN0IEIgPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IFQgPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IE4gPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIG5vcm1hbHMgYW5kIHV2c1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDw9IHR1YnVsYXJTZWdtZW50czsgKysgaSApIHtcblxuXHRcdFx0Ly8gdGhlIHJhZGlhbiBcInVcIiBpcyB1c2VkIHRvIGNhbGN1bGF0ZSB0aGUgcG9zaXRpb24gb24gdGhlIHRvcnVzIGN1cnZlIG9mIHRoZSBjdXJyZW50IHR1YnVsYXIgc2VnbWVudFxuXG5cdFx0XHRjb25zdCB1ID0gaSAvIHR1YnVsYXJTZWdtZW50cyAqIHAgKiBNYXRoLlBJICogMjtcblxuXHRcdFx0Ly8gbm93IHdlIGNhbGN1bGF0ZSB0d28gcG9pbnRzLiBQMSBpcyBvdXIgY3VycmVudCBwb3NpdGlvbiBvbiB0aGUgY3VydmUsIFAyIGlzIGEgbGl0dGxlIGZhcnRoZXIgYWhlYWQuXG5cdFx0XHQvLyB0aGVzZSBwb2ludHMgYXJlIHVzZWQgdG8gY3JlYXRlIGEgc3BlY2lhbCBcImNvb3JkaW5hdGUgc3BhY2VcIiwgd2hpY2ggaXMgbmVjZXNzYXJ5IHRvIGNhbGN1bGF0ZSB0aGUgY29ycmVjdCB2ZXJ0ZXggcG9zaXRpb25zXG5cblx0XHRcdGNhbGN1bGF0ZVBvc2l0aW9uT25DdXJ2ZSggdSwgcCwgcSwgcmFkaXVzLCBQMSApO1xuXHRcdFx0Y2FsY3VsYXRlUG9zaXRpb25PbkN1cnZlKCB1ICsgMC4wMSwgcCwgcSwgcmFkaXVzLCBQMiApO1xuXG5cdFx0XHQvLyBjYWxjdWxhdGUgb3J0aG9ub3JtYWwgYmFzaXNcblxuXHRcdFx0VC5zdWJWZWN0b3JzKCBQMiwgUDEgKTtcblx0XHRcdE4uYWRkVmVjdG9ycyggUDIsIFAxICk7XG5cdFx0XHRCLmNyb3NzVmVjdG9ycyggVCwgTiApO1xuXHRcdFx0Ti5jcm9zc1ZlY3RvcnMoIEIsIFQgKTtcblxuXHRcdFx0Ly8gbm9ybWFsaXplIEIsIE4uIFQgY2FuIGJlIGlnbm9yZWQsIHdlIGRvbid0IHVzZSBpdFxuXG5cdFx0XHRCLm5vcm1hbGl6ZSgpO1xuXHRcdFx0Ti5ub3JtYWxpemUoKTtcblxuXHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9IHJhZGlhbFNlZ21lbnRzOyArKyBqICkge1xuXG5cdFx0XHRcdC8vIG5vdyBjYWxjdWxhdGUgdGhlIHZlcnRpY2VzLiB0aGV5IGFyZSBub3RoaW5nIG1vcmUgdGhhbiBhbiBleHRydXNpb24gb2YgdGhlIHRvcnVzIGN1cnZlLlxuXHRcdFx0XHQvLyBiZWNhdXNlIHdlIGV4dHJ1ZGUgYSBzaGFwZSBpbiB0aGUgeHktcGxhbmUsIHRoZXJlIGlzIG5vIG5lZWQgdG8gY2FsY3VsYXRlIGEgei12YWx1ZS5cblxuXHRcdFx0XHRjb25zdCB2ID0gaiAvIHJhZGlhbFNlZ21lbnRzICogTWF0aC5QSSAqIDI7XG5cdFx0XHRcdGNvbnN0IGN4ID0gLSB0dWJlICogTWF0aC5jb3MoIHYgKTtcblx0XHRcdFx0Y29uc3QgY3kgPSB0dWJlICogTWF0aC5zaW4oIHYgKTtcblxuXHRcdFx0XHQvLyBub3cgY2FsY3VsYXRlIHRoZSBmaW5hbCB2ZXJ0ZXggcG9zaXRpb24uXG5cdFx0XHRcdC8vIGZpcnN0IHdlIG9yaWVudCB0aGUgZXh0cnVzaW9uIHdpdGggb3VyIGJhc2lzIHZlY3RvcnMsIHRoZW4gd2UgYWRkIGl0IHRvIHRoZSBjdXJyZW50IHBvc2l0aW9uIG9uIHRoZSBjdXJ2ZVxuXG5cdFx0XHRcdHZlcnRleC54ID0gUDEueCArICggY3ggKiBOLnggKyBjeSAqIEIueCApO1xuXHRcdFx0XHR2ZXJ0ZXgueSA9IFAxLnkgKyAoIGN4ICogTi55ICsgY3kgKiBCLnkgKTtcblx0XHRcdFx0dmVydGV4LnogPSBQMS56ICsgKCBjeCAqIE4ueiArIGN5ICogQi56ICk7XG5cblx0XHRcdFx0dmVydGljZXMucHVzaCggdmVydGV4LngsIHZlcnRleC55LCB2ZXJ0ZXgueiApO1xuXG5cdFx0XHRcdC8vIG5vcm1hbCAoUDEgaXMgYWx3YXlzIHRoZSBjZW50ZXIvb3JpZ2luIG9mIHRoZSBleHRydXNpb24sIHRodXMgd2UgY2FuIHVzZSBpdCB0byBjYWxjdWxhdGUgdGhlIG5vcm1hbClcblxuXHRcdFx0XHRub3JtYWwuc3ViVmVjdG9ycyggdmVydGV4LCBQMSApLm5vcm1hbGl6ZSgpO1xuXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggbm9ybWFsLngsIG5vcm1hbC55LCBub3JtYWwueiApO1xuXG5cdFx0XHRcdC8vIHV2XG5cblx0XHRcdFx0dXZzLnB1c2goIGkgLyB0dWJ1bGFyU2VnbWVudHMgKTtcblx0XHRcdFx0dXZzLnB1c2goIGogLyByYWRpYWxTZWdtZW50cyApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBnZW5lcmF0ZSBpbmRpY2VzXG5cblx0XHRmb3IgKCBsZXQgaiA9IDE7IGogPD0gdHVidWxhclNlZ21lbnRzOyBqICsrICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPD0gcmFkaWFsU2VnbWVudHM7IGkgKysgKSB7XG5cblx0XHRcdFx0Ly8gaW5kaWNlc1xuXG5cdFx0XHRcdGNvbnN0IGEgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogKCBqIC0gMSApICsgKCBpIC0gMSApO1xuXHRcdFx0XHRjb25zdCBiID0gKCByYWRpYWxTZWdtZW50cyArIDEgKSAqIGogKyAoIGkgLSAxICk7XG5cdFx0XHRcdGNvbnN0IGMgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogaiArIGk7XG5cdFx0XHRcdGNvbnN0IGQgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogKCBqIC0gMSApICsgaTtcblxuXHRcdFx0XHQvLyBmYWNlc1xuXG5cdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGIsIGMsIGQgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcblxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBub3JtYWxzLCAzICkgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XG5cblx0XHQvLyB0aGlzIGZ1bmN0aW9uIGNhbGN1bGF0ZXMgdGhlIGN1cnJlbnQgcG9zaXRpb24gb24gdGhlIHRvcnVzIGN1cnZlXG5cblx0XHRmdW5jdGlvbiBjYWxjdWxhdGVQb3NpdGlvbk9uQ3VydmUoIHUsIHAsIHEsIHJhZGl1cywgcG9zaXRpb24gKSB7XG5cblx0XHRcdGNvbnN0IGN1ID0gTWF0aC5jb3MoIHUgKTtcblx0XHRcdGNvbnN0IHN1ID0gTWF0aC5zaW4oIHUgKTtcblx0XHRcdGNvbnN0IHF1T3ZlclAgPSBxIC8gcCAqIHU7XG5cdFx0XHRjb25zdCBjcyA9IE1hdGguY29zKCBxdU92ZXJQICk7XG5cblx0XHRcdHBvc2l0aW9uLnggPSByYWRpdXMgKiAoIDIgKyBjcyApICogMC41ICogY3U7XG5cdFx0XHRwb3NpdGlvbi55ID0gcmFkaXVzICogKCAyICsgY3MgKSAqIHN1ICogMC41O1xuXHRcdFx0cG9zaXRpb24ueiA9IHJhZGl1cyAqIE1hdGguc2luKCBxdU92ZXJQICkgKiAwLjU7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xuXG5cdFx0cmV0dXJuIG5ldyBUb3J1c0tub3RHZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEudHViZSwgZGF0YS50dWJ1bGFyU2VnbWVudHMsIGRhdGEucmFkaWFsU2VnbWVudHMsIGRhdGEucCwgZGF0YS5xICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFR1YmVHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggcGF0aCA9IG5ldyBRdWFkcmF0aWNCZXppZXJDdXJ2ZTMoIG5ldyBWZWN0b3IzKCAtIDEsIC0gMSwgMCApLCBuZXcgVmVjdG9yMyggLSAxLCAxLCAwICksIG5ldyBWZWN0b3IzKCAxLCAxLCAwICkgKSwgdHVidWxhclNlZ21lbnRzID0gNjQsIHJhZGl1cyA9IDEsIHJhZGlhbFNlZ21lbnRzID0gOCwgY2xvc2VkID0gZmFsc2UgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ1R1YmVHZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRwYXRoOiBwYXRoLFxuXHRcdFx0dHVidWxhclNlZ21lbnRzOiB0dWJ1bGFyU2VnbWVudHMsXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcblx0XHRcdHJhZGlhbFNlZ21lbnRzOiByYWRpYWxTZWdtZW50cyxcblx0XHRcdGNsb3NlZDogY2xvc2VkXG5cdFx0fTtcblxuXHRcdGNvbnN0IGZyYW1lcyA9IHBhdGguY29tcHV0ZUZyZW5ldEZyYW1lcyggdHVidWxhclNlZ21lbnRzLCBjbG9zZWQgKTtcblxuXHRcdC8vIGV4cG9zZSBpbnRlcm5hbHNcblxuXHRcdHRoaXMudGFuZ2VudHMgPSBmcmFtZXMudGFuZ2VudHM7XG5cdFx0dGhpcy5ub3JtYWxzID0gZnJhbWVzLm5vcm1hbHM7XG5cdFx0dGhpcy5iaW5vcm1hbHMgPSBmcmFtZXMuYmlub3JtYWxzO1xuXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xuXG5cdFx0Y29uc3QgdmVydGV4ID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IHV2ID0gbmV3IFZlY3RvcjIoKTtcblx0XHRsZXQgUCA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHQvLyBidWZmZXJcblxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xuXHRcdGNvbnN0IHV2cyA9IFtdO1xuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcblxuXHRcdC8vIGNyZWF0ZSBidWZmZXIgZGF0YVxuXG5cdFx0Z2VuZXJhdGVCdWZmZXJEYXRhKCk7XG5cblx0XHQvLyBidWlsZCBnZW9tZXRyeVxuXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcblxuXHRcdC8vIGZ1bmN0aW9uc1xuXG5cdFx0ZnVuY3Rpb24gZ2VuZXJhdGVCdWZmZXJEYXRhKCkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0dWJ1bGFyU2VnbWVudHM7IGkgKysgKSB7XG5cblx0XHRcdFx0Z2VuZXJhdGVTZWdtZW50KCBpICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gaWYgdGhlIGdlb21ldHJ5IGlzIG5vdCBjbG9zZWQsIGdlbmVyYXRlIHRoZSBsYXN0IHJvdyBvZiB2ZXJ0aWNlcyBhbmQgbm9ybWFsc1xuXHRcdFx0Ly8gYXQgdGhlIHJlZ3VsYXIgcG9zaXRpb24gb24gdGhlIGdpdmVuIHBhdGhcblx0XHRcdC8vXG5cdFx0XHQvLyBpZiB0aGUgZ2VvbWV0cnkgaXMgY2xvc2VkLCBkdXBsaWNhdGUgdGhlIGZpcnN0IHJvdyBvZiB2ZXJ0aWNlcyBhbmQgbm9ybWFscyAodXZzIHdpbGwgZGlmZmVyKVxuXG5cdFx0XHRnZW5lcmF0ZVNlZ21lbnQoICggY2xvc2VkID09PSBmYWxzZSApID8gdHVidWxhclNlZ21lbnRzIDogMCApO1xuXG5cdFx0XHQvLyB1dnMgYXJlIGdlbmVyYXRlZCBpbiBhIHNlcGFyYXRlIGZ1bmN0aW9uLlxuXHRcdFx0Ly8gdGhpcyBtYWtlcyBpdCBlYXN5IGNvbXB1dGUgY29ycmVjdCB2YWx1ZXMgZm9yIGNsb3NlZCBnZW9tZXRyaWVzXG5cblx0XHRcdGdlbmVyYXRlVVZzKCk7XG5cblx0XHRcdC8vIGZpbmFsbHkgY3JlYXRlIGZhY2VzXG5cblx0XHRcdGdlbmVyYXRlSW5kaWNlcygpO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gZ2VuZXJhdGVTZWdtZW50KCBpICkge1xuXG5cdFx0XHQvLyB3ZSB1c2UgZ2V0UG9pbnRBdCB0byBzYW1wbGUgZXZlbmx5IGRpc3RyaWJ1dGVkIHBvaW50cyBmcm9tIHRoZSBnaXZlbiBwYXRoXG5cblx0XHRcdFAgPSBwYXRoLmdldFBvaW50QXQoIGkgLyB0dWJ1bGFyU2VnbWVudHMsIFAgKTtcblxuXHRcdFx0Ly8gcmV0cmlldmUgY29ycmVzcG9uZGluZyBub3JtYWwgYW5kIGJpbm9ybWFsXG5cblx0XHRcdGNvbnN0IE4gPSBmcmFtZXMubm9ybWFsc1sgaSBdO1xuXHRcdFx0Y29uc3QgQiA9IGZyYW1lcy5iaW5vcm1hbHNbIGkgXTtcblxuXHRcdFx0Ly8gZ2VuZXJhdGUgbm9ybWFscyBhbmQgdmVydGljZXMgZm9yIHRoZSBjdXJyZW50IHNlZ21lbnRcblxuXHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9IHJhZGlhbFNlZ21lbnRzOyBqICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHYgPSBqIC8gcmFkaWFsU2VnbWVudHMgKiBNYXRoLlBJICogMjtcblxuXHRcdFx0XHRjb25zdCBzaW4gPSBNYXRoLnNpbiggdiApO1xuXHRcdFx0XHRjb25zdCBjb3MgPSAtIE1hdGguY29zKCB2ICk7XG5cblx0XHRcdFx0Ly8gbm9ybWFsXG5cblx0XHRcdFx0bm9ybWFsLnggPSAoIGNvcyAqIE4ueCArIHNpbiAqIEIueCApO1xuXHRcdFx0XHRub3JtYWwueSA9ICggY29zICogTi55ICsgc2luICogQi55ICk7XG5cdFx0XHRcdG5vcm1hbC56ID0gKCBjb3MgKiBOLnogKyBzaW4gKiBCLnogKTtcblx0XHRcdFx0bm9ybWFsLm5vcm1hbGl6ZSgpO1xuXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggbm9ybWFsLngsIG5vcm1hbC55LCBub3JtYWwueiApO1xuXG5cdFx0XHRcdC8vIHZlcnRleFxuXG5cdFx0XHRcdHZlcnRleC54ID0gUC54ICsgcmFkaXVzICogbm9ybWFsLng7XG5cdFx0XHRcdHZlcnRleC55ID0gUC55ICsgcmFkaXVzICogbm9ybWFsLnk7XG5cdFx0XHRcdHZlcnRleC56ID0gUC56ICsgcmFkaXVzICogbm9ybWFsLno7XG5cblx0XHRcdFx0dmVydGljZXMucHVzaCggdmVydGV4LngsIHZlcnRleC55LCB2ZXJ0ZXgueiApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBnZW5lcmF0ZUluZGljZXMoKSB7XG5cblx0XHRcdGZvciAoIGxldCBqID0gMTsgaiA8PSB0dWJ1bGFyU2VnbWVudHM7IGogKysgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAxOyBpIDw9IHJhZGlhbFNlZ21lbnRzOyBpICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgYSA9ICggcmFkaWFsU2VnbWVudHMgKyAxICkgKiAoIGogLSAxICkgKyAoIGkgLSAxICk7XG5cdFx0XHRcdFx0Y29uc3QgYiA9ICggcmFkaWFsU2VnbWVudHMgKyAxICkgKiBqICsgKCBpIC0gMSApO1xuXHRcdFx0XHRcdGNvbnN0IGMgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogaiArIGk7XG5cdFx0XHRcdFx0Y29uc3QgZCA9ICggcmFkaWFsU2VnbWVudHMgKyAxICkgKiAoIGogLSAxICkgKyBpO1xuXG5cdFx0XHRcdFx0Ly8gZmFjZXNcblxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgZCApO1xuXHRcdFx0XHRcdGluZGljZXMucHVzaCggYiwgYywgZCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gZ2VuZXJhdGVVVnMoKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSB0dWJ1bGFyU2VnbWVudHM7IGkgKysgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDw9IHJhZGlhbFNlZ21lbnRzOyBqICsrICkge1xuXG5cdFx0XHRcdFx0dXYueCA9IGkgLyB0dWJ1bGFyU2VnbWVudHM7XG5cdFx0XHRcdFx0dXYueSA9IGogLyByYWRpYWxTZWdtZW50cztcblxuXHRcdFx0XHRcdHV2cy5wdXNoKCB1di54LCB1di55ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS5wYXRoID0gdGhpcy5wYXJhbWV0ZXJzLnBhdGgudG9KU09OKCk7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xuXG5cdFx0Ly8gVGhpcyBvbmx5IHdvcmtzIGZvciBidWlsdC1pbiBjdXJ2ZXMgKGUuZy4gQ2F0bXVsbFJvbUN1cnZlMykuXG5cdFx0Ly8gVXNlciBkZWZpbmVkIGN1cnZlcyBvciBpbnN0YW5jZXMgb2YgQ3VydmVQYXRoIHdpbGwgbm90IGJlIGRlc2VyaWFsaXplZC5cblx0XHRyZXR1cm4gbmV3IFR1YmVHZW9tZXRyeShcblx0XHRcdG5ldyBDdXJ2ZXNbIGRhdGEucGF0aC50eXBlIF0oKS5mcm9tSlNPTiggZGF0YS5wYXRoICksXG5cdFx0XHRkYXRhLnR1YnVsYXJTZWdtZW50cyxcblx0XHRcdGRhdGEucmFkaXVzLFxuXHRcdFx0ZGF0YS5yYWRpYWxTZWdtZW50cyxcblx0XHRcdGRhdGEuY2xvc2VkXG5cdFx0KTtcblxuXHR9XG5cbn1cblxuY2xhc3MgV2lyZWZyYW1lR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5ID0gbnVsbCApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnV2lyZWZyYW1lR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0Z2VvbWV0cnk6IGdlb21ldHJ5XG5cdFx0fTtcblxuXHRcdGlmICggZ2VvbWV0cnkgIT09IG51bGwgKSB7XG5cblx0XHRcdC8vIGJ1ZmZlclxuXG5cdFx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xuXHRcdFx0Y29uc3QgZWRnZXMgPSBuZXcgU2V0KCk7XG5cblx0XHRcdC8vIGhlbHBlciB2YXJpYWJsZXNcblxuXHRcdFx0Y29uc3Qgc3RhcnQgPSBuZXcgVmVjdG9yMygpO1xuXHRcdFx0Y29uc3QgZW5kID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdFx0aWYgKCBnZW9tZXRyeS5pbmRleCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHQvLyBpbmRleGVkIEJ1ZmZlckdlb21ldHJ5XG5cblx0XHRcdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXHRcdFx0XHRjb25zdCBpbmRpY2VzID0gZ2VvbWV0cnkuaW5kZXg7XG5cdFx0XHRcdGxldCBncm91cHMgPSBnZW9tZXRyeS5ncm91cHM7XG5cblx0XHRcdFx0aWYgKCBncm91cHMubGVuZ3RoID09PSAwICkge1xuXG5cdFx0XHRcdFx0Z3JvdXBzID0gWyB7IHN0YXJ0OiAwLCBjb3VudDogaW5kaWNlcy5jb3VudCwgbWF0ZXJpYWxJbmRleDogMCB9IF07XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIGNyZWF0ZSBhIGRhdGEgc3RydWN0dXJlIHRoYXQgY29udGFpbnMgYWxsIGVkZ2VzIHdpdGhvdXQgZHVwbGljYXRlc1xuXG5cdFx0XHRcdGZvciAoIGxldCBvID0gMCwgb2wgPSBncm91cHMubGVuZ3RoOyBvIDwgb2w7ICsrIG8gKSB7XG5cblx0XHRcdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgbyBdO1xuXG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXBTdGFydCA9IGdyb3VwLnN0YXJ0O1xuXHRcdFx0XHRcdGNvbnN0IGdyb3VwQ291bnQgPSBncm91cC5jb3VudDtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gZ3JvdXBTdGFydCwgbCA9ICggZ3JvdXBTdGFydCArIGdyb3VwQ291bnQgKTsgaSA8IGw7IGkgKz0gMyApIHtcblxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgMzsgaiArKyApIHtcblxuXHRcdFx0XHRcdFx0XHRjb25zdCBpbmRleDEgPSBpbmRpY2VzLmdldFgoIGkgKyBqICk7XG5cdFx0XHRcdFx0XHRcdGNvbnN0IGluZGV4MiA9IGluZGljZXMuZ2V0WCggaSArICggaiArIDEgKSAlIDMgKTtcblxuXHRcdFx0XHRcdFx0XHRzdGFydC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXgxICk7XG5cdFx0XHRcdFx0XHRcdGVuZC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXgyICk7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBpc1VuaXF1ZUVkZ2UoIHN0YXJ0LCBlbmQsIGVkZ2VzICkgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCBzdGFydC54LCBzdGFydC55LCBzdGFydC56ICk7XG5cdFx0XHRcdFx0XHRcdFx0dmVydGljZXMucHVzaCggZW5kLngsIGVuZC55LCBlbmQueiApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBub24taW5kZXhlZCBCdWZmZXJHZW9tZXRyeVxuXG5cdFx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSAoIHBvc2l0aW9uLmNvdW50IC8gMyApOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IDM7IGogKysgKSB7XG5cblx0XHRcdFx0XHRcdC8vIHRocmVlIGVkZ2VzIHBlciB0cmlhbmdsZSwgYW4gZWRnZSBpcyByZXByZXNlbnRlZCBhcyAoaW5kZXgxLCBpbmRleDIpXG5cdFx0XHRcdFx0XHQvLyBlLmcuIHRoZSBmaXJzdCB0cmlhbmdsZSBoYXMgdGhlIGZvbGxvd2luZyBlZGdlczogKDAsMSksKDEsMiksKDIsMClcblxuXHRcdFx0XHRcdFx0Y29uc3QgaW5kZXgxID0gMyAqIGkgKyBqO1xuXHRcdFx0XHRcdFx0Y29uc3QgaW5kZXgyID0gMyAqIGkgKyAoICggaiArIDEgKSAlIDMgKTtcblxuXHRcdFx0XHRcdFx0c3RhcnQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIGluZGV4MSApO1xuXHRcdFx0XHRcdFx0ZW5kLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uLCBpbmRleDIgKTtcblxuXHRcdFx0XHRcdFx0aWYgKCBpc1VuaXF1ZUVkZ2UoIHN0YXJ0LCBlbmQsIGVkZ2VzICkgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRcdFx0dmVydGljZXMucHVzaCggc3RhcnQueCwgc3RhcnQueSwgc3RhcnQueiApO1xuXHRcdFx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCBlbmQueCwgZW5kLnksIGVuZC56ICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcblxuXHRcdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gaXNVbmlxdWVFZGdlKCBzdGFydCwgZW5kLCBlZGdlcyApIHtcblxuXHRjb25zdCBoYXNoMSA9IGAke3N0YXJ0Lnh9LCR7c3RhcnQueX0sJHtzdGFydC56fS0ke2VuZC54fSwke2VuZC55fSwke2VuZC56fWA7XG5cdGNvbnN0IGhhc2gyID0gYCR7ZW5kLnh9LCR7ZW5kLnl9LCR7ZW5kLnp9LSR7c3RhcnQueH0sJHtzdGFydC55fSwke3N0YXJ0Lnp9YDsgLy8gY29pbmNpZGVudCBlZGdlXG5cblx0aWYgKCBlZGdlcy5oYXMoIGhhc2gxICkgPT09IHRydWUgfHwgZWRnZXMuaGFzKCBoYXNoMiApID09PSB0cnVlICkge1xuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRlZGdlcy5hZGQoIGhhc2gxICk7XG5cdFx0ZWRnZXMuYWRkKCBoYXNoMiApO1xuXHRcdHJldHVybiB0cnVlO1xuXG5cdH1cblxufVxuXG52YXIgR2VvbWV0cmllcyA9IC8qI19fUFVSRV9fKi9PYmplY3QuZnJlZXplKHtcblx0X19wcm90b19fOiBudWxsLFxuXHRCb3hHZW9tZXRyeTogQm94R2VvbWV0cnksXG5cdENhcHN1bGVHZW9tZXRyeTogQ2Fwc3VsZUdlb21ldHJ5LFxuXHRDaXJjbGVHZW9tZXRyeTogQ2lyY2xlR2VvbWV0cnksXG5cdENvbmVHZW9tZXRyeTogQ29uZUdlb21ldHJ5LFxuXHRDeWxpbmRlckdlb21ldHJ5OiBDeWxpbmRlckdlb21ldHJ5LFxuXHREb2RlY2FoZWRyb25HZW9tZXRyeTogRG9kZWNhaGVkcm9uR2VvbWV0cnksXG5cdEVkZ2VzR2VvbWV0cnk6IEVkZ2VzR2VvbWV0cnksXG5cdEV4dHJ1ZGVHZW9tZXRyeTogRXh0cnVkZUdlb21ldHJ5LFxuXHRJY29zYWhlZHJvbkdlb21ldHJ5OiBJY29zYWhlZHJvbkdlb21ldHJ5LFxuXHRMYXRoZUdlb21ldHJ5OiBMYXRoZUdlb21ldHJ5LFxuXHRPY3RhaGVkcm9uR2VvbWV0cnk6IE9jdGFoZWRyb25HZW9tZXRyeSxcblx0UGxhbmVHZW9tZXRyeTogUGxhbmVHZW9tZXRyeSxcblx0UG9seWhlZHJvbkdlb21ldHJ5OiBQb2x5aGVkcm9uR2VvbWV0cnksXG5cdFJpbmdHZW9tZXRyeTogUmluZ0dlb21ldHJ5LFxuXHRTaGFwZUdlb21ldHJ5OiBTaGFwZUdlb21ldHJ5LFxuXHRTcGhlcmVHZW9tZXRyeTogU3BoZXJlR2VvbWV0cnksXG5cdFRldHJhaGVkcm9uR2VvbWV0cnk6IFRldHJhaGVkcm9uR2VvbWV0cnksXG5cdFRvcnVzR2VvbWV0cnk6IFRvcnVzR2VvbWV0cnksXG5cdFRvcnVzS25vdEdlb21ldHJ5OiBUb3J1c0tub3RHZW9tZXRyeSxcblx0VHViZUdlb21ldHJ5OiBUdWJlR2VvbWV0cnksXG5cdFdpcmVmcmFtZUdlb21ldHJ5OiBXaXJlZnJhbWVHZW9tZXRyeVxufSk7XG5cbmNsYXNzIFNoYWRvd01hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNTaGFkb3dNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnU2hhZG93TWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcblx0XHR0aGlzLnRyYW5zcGFyZW50ID0gdHJ1ZTtcblxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcblxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcblxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBSYXdTaGFkZXJNYXRlcmlhbCBleHRlbmRzIFNoYWRlck1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCBwYXJhbWV0ZXJzICk7XG5cblx0XHR0aGlzLmlzUmF3U2hhZGVyTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ1Jhd1NoYWRlck1hdGVyaWFsJztcblxuXHR9XG5cbn1cblxuY2xhc3MgTWVzaFN0YW5kYXJkTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc01lc2hTdGFuZGFyZE1hdGVyaWFsID0gdHJ1ZTtcblxuXHRcdHRoaXMuZGVmaW5lcyA9IHsgJ1NUQU5EQVJEJzogJycgfTtcblxuXHRcdHRoaXMudHlwZSA9ICdNZXNoU3RhbmRhcmRNYXRlcmlhbCc7XG5cblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCAweGZmZmZmZiApOyAvLyBkaWZmdXNlXG5cdFx0dGhpcy5yb3VnaG5lc3MgPSAxLjA7XG5cdFx0dGhpcy5tZXRhbG5lc3MgPSAwLjA7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmxpZ2h0TWFwID0gbnVsbDtcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gMS4wO1xuXG5cdFx0dGhpcy5hb01hcCA9IG51bGw7XG5cdFx0dGhpcy5hb01hcEludGVuc2l0eSA9IDEuMDtcblxuXHRcdHRoaXMuZW1pc3NpdmUgPSBuZXcgQ29sb3IoIDB4MDAwMDAwICk7XG5cdFx0dGhpcy5lbWlzc2l2ZUludGVuc2l0eSA9IDEuMDtcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuYnVtcE1hcCA9IG51bGw7XG5cdFx0dGhpcy5idW1wU2NhbGUgPSAxO1xuXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBudWxsO1xuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IFRhbmdlbnRTcGFjZU5vcm1hbE1hcDtcblx0XHR0aGlzLm5vcm1hbFNjYWxlID0gbmV3IFZlY3RvcjIoIDEsIDEgKTtcblxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xuXG5cdFx0dGhpcy5yb3VnaG5lc3NNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5tZXRhbG5lc3NNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5hbHBoYU1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmVudk1hcCA9IG51bGw7XG5cdFx0dGhpcy5lbnZNYXBSb3RhdGlvbiA9IG5ldyBFdWxlcigpO1xuXHRcdHRoaXMuZW52TWFwSW50ZW5zaXR5ID0gMS4wO1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gJ3JvdW5kJztcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVqb2luID0gJ3JvdW5kJztcblxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBmYWxzZTtcblxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcblxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5kZWZpbmVzID0geyAnU1RBTkRBUkQnOiAnJyB9O1xuXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcblx0XHR0aGlzLnJvdWdobmVzcyA9IHNvdXJjZS5yb3VnaG5lc3M7XG5cdFx0dGhpcy5tZXRhbG5lc3MgPSBzb3VyY2UubWV0YWxuZXNzO1xuXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xuXG5cdFx0dGhpcy5saWdodE1hcCA9IHNvdXJjZS5saWdodE1hcDtcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gc291cmNlLmxpZ2h0TWFwSW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5hb01hcCA9IHNvdXJjZS5hb01hcDtcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gc291cmNlLmFvTWFwSW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5lbWlzc2l2ZS5jb3B5KCBzb3VyY2UuZW1pc3NpdmUgKTtcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gc291cmNlLmVtaXNzaXZlTWFwO1xuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSBzb3VyY2UuZW1pc3NpdmVJbnRlbnNpdHk7XG5cblx0XHR0aGlzLmJ1bXBNYXAgPSBzb3VyY2UuYnVtcE1hcDtcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IHNvdXJjZS5idW1wU2NhbGU7XG5cblx0XHR0aGlzLm5vcm1hbE1hcCA9IHNvdXJjZS5ub3JtYWxNYXA7XG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gc291cmNlLm5vcm1hbE1hcFR5cGU7XG5cdFx0dGhpcy5ub3JtYWxTY2FsZS5jb3B5KCBzb3VyY2Uubm9ybWFsU2NhbGUgKTtcblxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gc291cmNlLmRpc3BsYWNlbWVudE1hcDtcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gc291cmNlLmRpc3BsYWNlbWVudFNjYWxlO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IHNvdXJjZS5kaXNwbGFjZW1lbnRCaWFzO1xuXG5cdFx0dGhpcy5yb3VnaG5lc3NNYXAgPSBzb3VyY2Uucm91Z2huZXNzTWFwO1xuXG5cdFx0dGhpcy5tZXRhbG5lc3NNYXAgPSBzb3VyY2UubWV0YWxuZXNzTWFwO1xuXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcblxuXHRcdHRoaXMuZW52TWFwID0gc291cmNlLmVudk1hcDtcblx0XHR0aGlzLmVudk1hcFJvdGF0aW9uLmNvcHkoIHNvdXJjZS5lbnZNYXBSb3RhdGlvbiApO1xuXHRcdHRoaXMuZW52TWFwSW50ZW5zaXR5ID0gc291cmNlLmVudk1hcEludGVuc2l0eTtcblxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gc291cmNlLndpcmVmcmFtZUxpbmVjYXA7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9IHNvdXJjZS53aXJlZnJhbWVMaW5lam9pbjtcblxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBzb3VyY2UuZmxhdFNoYWRpbmc7XG5cblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgTWVzaFBoeXNpY2FsTWF0ZXJpYWwgZXh0ZW5kcyBNZXNoU3RhbmRhcmRNYXRlcmlhbCB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc01lc2hQaHlzaWNhbE1hdGVyaWFsID0gdHJ1ZTtcblxuXHRcdHRoaXMuZGVmaW5lcyA9IHtcblxuXHRcdFx0J1NUQU5EQVJEJzogJycsXG5cdFx0XHQnUEhZU0lDQUwnOiAnJ1xuXG5cdFx0fTtcblxuXHRcdHRoaXMudHlwZSA9ICdNZXNoUGh5c2ljYWxNYXRlcmlhbCc7XG5cblx0XHR0aGlzLmFuaXNvdHJvcHlSb3RhdGlvbiA9IDA7XG5cdFx0dGhpcy5hbmlzb3Ryb3B5TWFwID0gbnVsbDtcblxuXHRcdHRoaXMuY2xlYXJjb2F0TWFwID0gbnVsbDtcblx0XHR0aGlzLmNsZWFyY29hdFJvdWdobmVzcyA9IDAuMDtcblx0XHR0aGlzLmNsZWFyY29hdFJvdWdobmVzc01hcCA9IG51bGw7XG5cdFx0dGhpcy5jbGVhcmNvYXROb3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XG5cdFx0dGhpcy5jbGVhcmNvYXROb3JtYWxNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5pb3IgPSAxLjU7XG5cblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoIHRoaXMsICdyZWZsZWN0aXZpdHknLCB7XG5cdFx0XHRnZXQ6IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRyZXR1cm4gKCBjbGFtcCggMi41ICogKCB0aGlzLmlvciAtIDEgKSAvICggdGhpcy5pb3IgKyAxICksIDAsIDEgKSApO1xuXG5cdFx0XHR9LFxuXHRcdFx0c2V0OiBmdW5jdGlvbiAoIHJlZmxlY3Rpdml0eSApIHtcblxuXHRcdFx0XHR0aGlzLmlvciA9ICggMSArIDAuNCAqIHJlZmxlY3Rpdml0eSApIC8gKCAxIC0gMC40ICogcmVmbGVjdGl2aXR5ICk7XG5cblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHR0aGlzLmlyaWRlc2NlbmNlTWFwID0gbnVsbDtcblx0XHR0aGlzLmlyaWRlc2NlbmNlSU9SID0gMS4zO1xuXHRcdHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZSA9IFsgMTAwLCA0MDAgXTtcblx0XHR0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuc2hlZW5Db2xvciA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcblx0XHR0aGlzLnNoZWVuQ29sb3JNYXAgPSBudWxsO1xuXHRcdHRoaXMuc2hlZW5Sb3VnaG5lc3MgPSAxLjA7XG5cdFx0dGhpcy5zaGVlblJvdWdobmVzc01hcCA9IG51bGw7XG5cblx0XHR0aGlzLnRyYW5zbWlzc2lvbk1hcCA9IG51bGw7XG5cblx0XHR0aGlzLnRoaWNrbmVzcyA9IDA7XG5cdFx0dGhpcy50aGlja25lc3NNYXAgPSBudWxsO1xuXHRcdHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSA9IEluZmluaXR5O1xuXHRcdHRoaXMuYXR0ZW51YXRpb25Db2xvciA9IG5ldyBDb2xvciggMSwgMSwgMSApO1xuXG5cdFx0dGhpcy5zcGVjdWxhckludGVuc2l0eSA9IDEuMDtcblx0XHR0aGlzLnNwZWN1bGFySW50ZW5zaXR5TWFwID0gbnVsbDtcblx0XHR0aGlzLnNwZWN1bGFyQ29sb3IgPSBuZXcgQ29sb3IoIDEsIDEsIDEgKTtcblx0XHR0aGlzLnNwZWN1bGFyQ29sb3JNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5fYW5pc290cm9weSA9IDA7XG5cdFx0dGhpcy5fY2xlYXJjb2F0ID0gMDtcblx0XHR0aGlzLl9kaXNwZXJzaW9uID0gMDtcblx0XHR0aGlzLl9pcmlkZXNjZW5jZSA9IDA7XG5cdFx0dGhpcy5fc2hlZW4gPSAwLjA7XG5cdFx0dGhpcy5fdHJhbnNtaXNzaW9uID0gMDtcblxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XG5cblx0fVxuXG5cdGdldCBhbmlzb3Ryb3B5KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX2FuaXNvdHJvcHk7XG5cblx0fVxuXG5cdHNldCBhbmlzb3Ryb3B5KCB2YWx1ZSApIHtcblxuXHRcdGlmICggdGhpcy5fYW5pc290cm9weSA+IDAgIT09IHZhbHVlID4gMCApIHtcblxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5fYW5pc290cm9weSA9IHZhbHVlO1xuXG5cdH1cblxuXHRnZXQgY2xlYXJjb2F0KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX2NsZWFyY29hdDtcblxuXHR9XG5cblx0c2V0IGNsZWFyY29hdCggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHRoaXMuX2NsZWFyY29hdCA+IDAgIT09IHZhbHVlID4gMCApIHtcblxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5fY2xlYXJjb2F0ID0gdmFsdWU7XG5cblx0fVxuXG5cdGdldCBpcmlkZXNjZW5jZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9pcmlkZXNjZW5jZTtcblxuXHR9XG5cblx0c2V0IGlyaWRlc2NlbmNlKCB2YWx1ZSApIHtcblxuXHRcdGlmICggdGhpcy5faXJpZGVzY2VuY2UgPiAwICE9PSB2YWx1ZSA+IDAgKSB7XG5cblx0XHRcdHRoaXMudmVyc2lvbiArKztcblxuXHRcdH1cblxuXHRcdHRoaXMuX2lyaWRlc2NlbmNlID0gdmFsdWU7XG5cblx0fVxuXG5cdGdldCBkaXNwZXJzaW9uKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX2Rpc3BlcnNpb247XG5cblx0fVxuXG5cdHNldCBkaXNwZXJzaW9uKCB2YWx1ZSApIHtcblxuXHRcdGlmICggdGhpcy5fZGlzcGVyc2lvbiA+IDAgIT09IHZhbHVlID4gMCApIHtcblxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5fZGlzcGVyc2lvbiA9IHZhbHVlO1xuXG5cdH1cblxuXHRnZXQgc2hlZW4oKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fc2hlZW47XG5cblx0fVxuXG5cdHNldCBzaGVlbiggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHRoaXMuX3NoZWVuID4gMCAhPT0gdmFsdWUgPiAwICkge1xuXG5cdFx0XHR0aGlzLnZlcnNpb24gKys7XG5cblx0XHR9XG5cblx0XHR0aGlzLl9zaGVlbiA9IHZhbHVlO1xuXG5cdH1cblxuXHRnZXQgdHJhbnNtaXNzaW9uKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3RyYW5zbWlzc2lvbjtcblxuXHR9XG5cblx0c2V0IHRyYW5zbWlzc2lvbiggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHRoaXMuX3RyYW5zbWlzc2lvbiA+IDAgIT09IHZhbHVlID4gMCApIHtcblxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5fdHJhbnNtaXNzaW9uID0gdmFsdWU7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5kZWZpbmVzID0ge1xuXG5cdFx0XHQnU1RBTkRBUkQnOiAnJyxcblx0XHRcdCdQSFlTSUNBTCc6ICcnXG5cblx0XHR9O1xuXG5cdFx0dGhpcy5hbmlzb3Ryb3B5ID0gc291cmNlLmFuaXNvdHJvcHk7XG5cdFx0dGhpcy5hbmlzb3Ryb3B5Um90YXRpb24gPSBzb3VyY2UuYW5pc290cm9weVJvdGF0aW9uO1xuXHRcdHRoaXMuYW5pc290cm9weU1hcCA9IHNvdXJjZS5hbmlzb3Ryb3B5TWFwO1xuXG5cdFx0dGhpcy5jbGVhcmNvYXQgPSBzb3VyY2UuY2xlYXJjb2F0O1xuXHRcdHRoaXMuY2xlYXJjb2F0TWFwID0gc291cmNlLmNsZWFyY29hdE1hcDtcblx0XHR0aGlzLmNsZWFyY29hdFJvdWdobmVzcyA9IHNvdXJjZS5jbGVhcmNvYXRSb3VnaG5lc3M7XG5cdFx0dGhpcy5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgPSBzb3VyY2UuY2xlYXJjb2F0Um91Z2huZXNzTWFwO1xuXHRcdHRoaXMuY2xlYXJjb2F0Tm9ybWFsTWFwID0gc291cmNlLmNsZWFyY29hdE5vcm1hbE1hcDtcblx0XHR0aGlzLmNsZWFyY29hdE5vcm1hbFNjYWxlLmNvcHkoIHNvdXJjZS5jbGVhcmNvYXROb3JtYWxTY2FsZSApO1xuXG5cdFx0dGhpcy5kaXNwZXJzaW9uID0gc291cmNlLmRpc3BlcnNpb247XG5cdFx0dGhpcy5pb3IgPSBzb3VyY2UuaW9yO1xuXG5cdFx0dGhpcy5pcmlkZXNjZW5jZSA9IHNvdXJjZS5pcmlkZXNjZW5jZTtcblx0XHR0aGlzLmlyaWRlc2NlbmNlTWFwID0gc291cmNlLmlyaWRlc2NlbmNlTWFwO1xuXHRcdHRoaXMuaXJpZGVzY2VuY2VJT1IgPSBzb3VyY2UuaXJpZGVzY2VuY2VJT1I7XG5cdFx0dGhpcy5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlID0gWyAuLi5zb3VyY2UuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZSBdO1xuXHRcdHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgPSBzb3VyY2UuaXJpZGVzY2VuY2VUaGlja25lc3NNYXA7XG5cblx0XHR0aGlzLnNoZWVuID0gc291cmNlLnNoZWVuO1xuXHRcdHRoaXMuc2hlZW5Db2xvci5jb3B5KCBzb3VyY2Uuc2hlZW5Db2xvciApO1xuXHRcdHRoaXMuc2hlZW5Db2xvck1hcCA9IHNvdXJjZS5zaGVlbkNvbG9yTWFwO1xuXHRcdHRoaXMuc2hlZW5Sb3VnaG5lc3MgPSBzb3VyY2Uuc2hlZW5Sb3VnaG5lc3M7XG5cdFx0dGhpcy5zaGVlblJvdWdobmVzc01hcCA9IHNvdXJjZS5zaGVlblJvdWdobmVzc01hcDtcblxuXHRcdHRoaXMudHJhbnNtaXNzaW9uID0gc291cmNlLnRyYW5zbWlzc2lvbjtcblx0XHR0aGlzLnRyYW5zbWlzc2lvbk1hcCA9IHNvdXJjZS50cmFuc21pc3Npb25NYXA7XG5cblx0XHR0aGlzLnRoaWNrbmVzcyA9IHNvdXJjZS50aGlja25lc3M7XG5cdFx0dGhpcy50aGlja25lc3NNYXAgPSBzb3VyY2UudGhpY2tuZXNzTWFwO1xuXHRcdHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSA9IHNvdXJjZS5hdHRlbnVhdGlvbkRpc3RhbmNlO1xuXHRcdHRoaXMuYXR0ZW51YXRpb25Db2xvci5jb3B5KCBzb3VyY2UuYXR0ZW51YXRpb25Db2xvciApO1xuXG5cdFx0dGhpcy5zcGVjdWxhckludGVuc2l0eSA9IHNvdXJjZS5zcGVjdWxhckludGVuc2l0eTtcblx0XHR0aGlzLnNwZWN1bGFySW50ZW5zaXR5TWFwID0gc291cmNlLnNwZWN1bGFySW50ZW5zaXR5TWFwO1xuXHRcdHRoaXMuc3BlY3VsYXJDb2xvci5jb3B5KCBzb3VyY2Uuc3BlY3VsYXJDb2xvciApO1xuXHRcdHRoaXMuc3BlY3VsYXJDb2xvck1hcCA9IHNvdXJjZS5zcGVjdWxhckNvbG9yTWFwO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIE1lc2hQaG9uZ01hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNNZXNoUGhvbmdNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnTWVzaFBob25nTWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHhmZmZmZmYgKTsgLy8gZGlmZnVzZVxuXHRcdHRoaXMuc3BlY3VsYXIgPSBuZXcgQ29sb3IoIDB4MTExMTExICk7XG5cdFx0dGhpcy5zaGluaW5lc3MgPSAzMDtcblxuXHRcdHRoaXMubWFwID0gbnVsbDtcblxuXHRcdHRoaXMubGlnaHRNYXAgPSBudWxsO1xuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSAxLjA7XG5cblx0XHR0aGlzLmFvTWFwID0gbnVsbDtcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gMS4wO1xuXG5cdFx0dGhpcy5lbWlzc2l2ZSA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcblx0XHR0aGlzLmVtaXNzaXZlSW50ZW5zaXR5ID0gMS4wO1xuXHRcdHRoaXMuZW1pc3NpdmVNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5idW1wTWFwID0gbnVsbDtcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IDE7XG5cblx0XHR0aGlzLm5vcm1hbE1hcCA9IG51bGw7XG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gVGFuZ2VudFNwYWNlTm9ybWFsTWFwO1xuXHRcdHRoaXMubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xuXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBudWxsO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSAxO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IDA7XG5cblx0XHR0aGlzLnNwZWN1bGFyTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5lbnZNYXAgPSBudWxsO1xuXHRcdHRoaXMuZW52TWFwUm90YXRpb24gPSBuZXcgRXVsZXIoKTtcblx0XHR0aGlzLmNvbWJpbmUgPSBNdWx0aXBseU9wZXJhdGlvbjtcblx0XHR0aGlzLnJlZmxlY3Rpdml0eSA9IDE7XG5cdFx0dGhpcy5yZWZyYWN0aW9uUmF0aW8gPSAwLjk4O1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gJ3JvdW5kJztcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVqb2luID0gJ3JvdW5kJztcblxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBmYWxzZTtcblxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcblxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcblx0XHR0aGlzLnNwZWN1bGFyLmNvcHkoIHNvdXJjZS5zcGVjdWxhciApO1xuXHRcdHRoaXMuc2hpbmluZXNzID0gc291cmNlLnNoaW5pbmVzcztcblxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcblxuXHRcdHRoaXMubGlnaHRNYXAgPSBzb3VyY2UubGlnaHRNYXA7XG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IHNvdXJjZS5saWdodE1hcEludGVuc2l0eTtcblxuXHRcdHRoaXMuYW9NYXAgPSBzb3VyY2UuYW9NYXA7XG5cdFx0dGhpcy5hb01hcEludGVuc2l0eSA9IHNvdXJjZS5hb01hcEludGVuc2l0eTtcblxuXHRcdHRoaXMuZW1pc3NpdmUuY29weSggc291cmNlLmVtaXNzaXZlICk7XG5cdFx0dGhpcy5lbWlzc2l2ZU1hcCA9IHNvdXJjZS5lbWlzc2l2ZU1hcDtcblx0XHR0aGlzLmVtaXNzaXZlSW50ZW5zaXR5ID0gc291cmNlLmVtaXNzaXZlSW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5idW1wTWFwID0gc291cmNlLmJ1bXBNYXA7XG5cdFx0dGhpcy5idW1wU2NhbGUgPSBzb3VyY2UuYnVtcFNjYWxlO1xuXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBzb3VyY2Uubm9ybWFsTWFwO1xuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IHNvdXJjZS5ub3JtYWxNYXBUeXBlO1xuXHRcdHRoaXMubm9ybWFsU2NhbGUuY29weSggc291cmNlLm5vcm1hbFNjYWxlICk7XG5cblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IHNvdXJjZS5kaXNwbGFjZW1lbnRTY2FsZTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcblxuXHRcdHRoaXMuc3BlY3VsYXJNYXAgPSBzb3VyY2Uuc3BlY3VsYXJNYXA7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xuXG5cdFx0dGhpcy5lbnZNYXAgPSBzb3VyY2UuZW52TWFwO1xuXHRcdHRoaXMuZW52TWFwUm90YXRpb24uY29weSggc291cmNlLmVudk1hcFJvdGF0aW9uICk7XG5cdFx0dGhpcy5jb21iaW5lID0gc291cmNlLmNvbWJpbmU7XG5cdFx0dGhpcy5yZWZsZWN0aXZpdHkgPSBzb3VyY2UucmVmbGVjdGl2aXR5O1xuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gc291cmNlLnJlZnJhY3Rpb25SYXRpbztcblxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gc291cmNlLndpcmVmcmFtZUxpbmVjYXA7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9IHNvdXJjZS53aXJlZnJhbWVMaW5lam9pbjtcblxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBzb3VyY2UuZmxhdFNoYWRpbmc7XG5cblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgTWVzaFRvb25NYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTWVzaFRvb25NYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLmRlZmluZXMgPSB7ICdUT09OJzogJycgfTtcblxuXHRcdHRoaXMudHlwZSA9ICdNZXNoVG9vbk1hdGVyaWFsJztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cdFx0dGhpcy5ncmFkaWVudE1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmxpZ2h0TWFwID0gbnVsbDtcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gMS4wO1xuXG5cdFx0dGhpcy5hb01hcCA9IG51bGw7XG5cdFx0dGhpcy5hb01hcEludGVuc2l0eSA9IDEuMDtcblxuXHRcdHRoaXMuZW1pc3NpdmUgPSBuZXcgQ29sb3IoIDB4MDAwMDAwICk7XG5cdFx0dGhpcy5lbWlzc2l2ZUludGVuc2l0eSA9IDEuMDtcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuYnVtcE1hcCA9IG51bGw7XG5cdFx0dGhpcy5idW1wU2NhbGUgPSAxO1xuXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBudWxsO1xuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IFRhbmdlbnRTcGFjZU5vcm1hbE1hcDtcblx0XHR0aGlzLm5vcm1hbFNjYWxlID0gbmV3IFZlY3RvcjIoIDEsIDEgKTtcblxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xuXG5cdFx0dGhpcy5hbHBoYU1hcCA9IG51bGw7XG5cblx0XHR0aGlzLndpcmVmcmFtZSA9IGZhbHNlO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gMTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSAncm91bmQnO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSAncm91bmQnO1xuXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xuXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLmNvbG9yLmNvcHkoIHNvdXJjZS5jb2xvciApO1xuXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xuXHRcdHRoaXMuZ3JhZGllbnRNYXAgPSBzb3VyY2UuZ3JhZGllbnRNYXA7XG5cblx0XHR0aGlzLmxpZ2h0TWFwID0gc291cmNlLmxpZ2h0TWFwO1xuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSBzb3VyY2UubGlnaHRNYXBJbnRlbnNpdHk7XG5cblx0XHR0aGlzLmFvTWFwID0gc291cmNlLmFvTWFwO1xuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSBzb3VyY2UuYW9NYXBJbnRlbnNpdHk7XG5cblx0XHR0aGlzLmVtaXNzaXZlLmNvcHkoIHNvdXJjZS5lbWlzc2l2ZSApO1xuXHRcdHRoaXMuZW1pc3NpdmVNYXAgPSBzb3VyY2UuZW1pc3NpdmVNYXA7XG5cdFx0dGhpcy5lbWlzc2l2ZUludGVuc2l0eSA9IHNvdXJjZS5lbWlzc2l2ZUludGVuc2l0eTtcblxuXHRcdHRoaXMuYnVtcE1hcCA9IHNvdXJjZS5idW1wTWFwO1xuXHRcdHRoaXMuYnVtcFNjYWxlID0gc291cmNlLmJ1bXBTY2FsZTtcblxuXHRcdHRoaXMubm9ybWFsTWFwID0gc291cmNlLm5vcm1hbE1hcDtcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBzb3VyY2Uubm9ybWFsTWFwVHlwZTtcblx0XHR0aGlzLm5vcm1hbFNjYWxlLmNvcHkoIHNvdXJjZS5ub3JtYWxTY2FsZSApO1xuXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBzb3VyY2UuZGlzcGxhY2VtZW50TWFwO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBzb3VyY2Uud2lyZWZyYW1lO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSBzb3VyY2Uud2lyZWZyYW1lTGluZWNhcDtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVqb2luID0gc291cmNlLndpcmVmcmFtZUxpbmVqb2luO1xuXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIE1lc2hOb3JtYWxNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTWVzaE5vcm1hbE1hdGVyaWFsID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdNZXNoTm9ybWFsTWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5idW1wTWFwID0gbnVsbDtcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IDE7XG5cblx0XHR0aGlzLm5vcm1hbE1hcCA9IG51bGw7XG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gVGFuZ2VudFNwYWNlTm9ybWFsTWFwO1xuXHRcdHRoaXMubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xuXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBudWxsO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSAxO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IDA7XG5cblx0XHR0aGlzLndpcmVmcmFtZSA9IGZhbHNlO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gMTtcblxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBmYWxzZTtcblxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5idW1wTWFwID0gc291cmNlLmJ1bXBNYXA7XG5cdFx0dGhpcy5idW1wU2NhbGUgPSBzb3VyY2UuYnVtcFNjYWxlO1xuXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBzb3VyY2Uubm9ybWFsTWFwO1xuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IHNvdXJjZS5ub3JtYWxNYXBUeXBlO1xuXHRcdHRoaXMubm9ybWFsU2NhbGUuY29weSggc291cmNlLm5vcm1hbFNjYWxlICk7XG5cblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IHNvdXJjZS5kaXNwbGFjZW1lbnRTY2FsZTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcblxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XG5cblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gc291cmNlLmZsYXRTaGFkaW5nO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIE1lc2hMYW1iZXJ0TWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc01lc2hMYW1iZXJ0TWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ01lc2hMYW1iZXJ0TWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHhmZmZmZmYgKTsgLy8gZGlmZnVzZVxuXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5saWdodE1hcCA9IG51bGw7XG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IDEuMDtcblxuXHRcdHRoaXMuYW9NYXAgPSBudWxsO1xuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSAxLjA7XG5cblx0XHR0aGlzLmVtaXNzaXZlID0gbmV3IENvbG9yKCAweDAwMDAwMCApO1xuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSAxLjA7XG5cdFx0dGhpcy5lbWlzc2l2ZU1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmJ1bXBNYXAgPSBudWxsO1xuXHRcdHRoaXMuYnVtcFNjYWxlID0gMTtcblxuXHRcdHRoaXMubm9ybWFsTWFwID0gbnVsbDtcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBUYW5nZW50U3BhY2VOb3JtYWxNYXA7XG5cdFx0dGhpcy5ub3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XG5cblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IG51bGw7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IDE7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gMDtcblxuXHRcdHRoaXMuc3BlY3VsYXJNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5hbHBoYU1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmVudk1hcCA9IG51bGw7XG5cdFx0dGhpcy5lbnZNYXBSb3RhdGlvbiA9IG5ldyBFdWxlcigpO1xuXHRcdHRoaXMuY29tYmluZSA9IE11bHRpcGx5T3BlcmF0aW9uO1xuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gMTtcblx0XHR0aGlzLnJlZnJhY3Rpb25SYXRpbyA9IDAuOTg7XG5cblx0XHR0aGlzLndpcmVmcmFtZSA9IGZhbHNlO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gMTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSAncm91bmQnO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSAncm91bmQnO1xuXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xuXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLmNvbG9yLmNvcHkoIHNvdXJjZS5jb2xvciApO1xuXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xuXG5cdFx0dGhpcy5saWdodE1hcCA9IHNvdXJjZS5saWdodE1hcDtcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gc291cmNlLmxpZ2h0TWFwSW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5hb01hcCA9IHNvdXJjZS5hb01hcDtcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gc291cmNlLmFvTWFwSW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5lbWlzc2l2ZS5jb3B5KCBzb3VyY2UuZW1pc3NpdmUgKTtcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gc291cmNlLmVtaXNzaXZlTWFwO1xuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSBzb3VyY2UuZW1pc3NpdmVJbnRlbnNpdHk7XG5cblx0XHR0aGlzLmJ1bXBNYXAgPSBzb3VyY2UuYnVtcE1hcDtcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IHNvdXJjZS5idW1wU2NhbGU7XG5cblx0XHR0aGlzLm5vcm1hbE1hcCA9IHNvdXJjZS5ub3JtYWxNYXA7XG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gc291cmNlLm5vcm1hbE1hcFR5cGU7XG5cdFx0dGhpcy5ub3JtYWxTY2FsZS5jb3B5KCBzb3VyY2Uubm9ybWFsU2NhbGUgKTtcblxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gc291cmNlLmRpc3BsYWNlbWVudE1hcDtcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gc291cmNlLmRpc3BsYWNlbWVudFNjYWxlO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IHNvdXJjZS5kaXNwbGFjZW1lbnRCaWFzO1xuXG5cdFx0dGhpcy5zcGVjdWxhck1hcCA9IHNvdXJjZS5zcGVjdWxhck1hcDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBzb3VyY2UuYWxwaGFNYXA7XG5cblx0XHR0aGlzLmVudk1hcCA9IHNvdXJjZS5lbnZNYXA7XG5cdFx0dGhpcy5lbnZNYXBSb3RhdGlvbi5jb3B5KCBzb3VyY2UuZW52TWFwUm90YXRpb24gKTtcblx0XHR0aGlzLmNvbWJpbmUgPSBzb3VyY2UuY29tYmluZTtcblx0XHR0aGlzLnJlZmxlY3Rpdml0eSA9IHNvdXJjZS5yZWZsZWN0aXZpdHk7XG5cdFx0dGhpcy5yZWZyYWN0aW9uUmF0aW8gPSBzb3VyY2UucmVmcmFjdGlvblJhdGlvO1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBzb3VyY2Uud2lyZWZyYW1lO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVjYXAgPSBzb3VyY2Uud2lyZWZyYW1lTGluZWNhcDtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVqb2luID0gc291cmNlLndpcmVmcmFtZUxpbmVqb2luO1xuXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IHNvdXJjZS5mbGF0U2hhZGluZztcblxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBNZXNoTWF0Y2FwTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc01lc2hNYXRjYXBNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLmRlZmluZXMgPSB7ICdNQVRDQVAnOiAnJyB9O1xuXG5cdFx0dGhpcy50eXBlID0gJ01lc2hNYXRjYXBNYXRlcmlhbCc7XG5cblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCAweGZmZmZmZiApOyAvLyBkaWZmdXNlXG5cblx0XHR0aGlzLm1hdGNhcCA9IG51bGw7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmJ1bXBNYXAgPSBudWxsO1xuXHRcdHRoaXMuYnVtcFNjYWxlID0gMTtcblxuXHRcdHRoaXMubm9ybWFsTWFwID0gbnVsbDtcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBUYW5nZW50U3BhY2VOb3JtYWxNYXA7XG5cdFx0dGhpcy5ub3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XG5cblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IG51bGw7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IDE7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gMDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xuXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcblxuXHR9XG5cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuZGVmaW5lcyA9IHsgJ01BVENBUCc6ICcnIH07XG5cblx0XHR0aGlzLmNvbG9yLmNvcHkoIHNvdXJjZS5jb2xvciApO1xuXG5cdFx0dGhpcy5tYXRjYXAgPSBzb3VyY2UubWF0Y2FwO1xuXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xuXG5cdFx0dGhpcy5idW1wTWFwID0gc291cmNlLmJ1bXBNYXA7XG5cdFx0dGhpcy5idW1wU2NhbGUgPSBzb3VyY2UuYnVtcFNjYWxlO1xuXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBzb3VyY2Uubm9ybWFsTWFwO1xuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IHNvdXJjZS5ub3JtYWxNYXBUeXBlO1xuXHRcdHRoaXMubm9ybWFsU2NhbGUuY29weSggc291cmNlLm5vcm1hbFNjYWxlICk7XG5cblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IHNvdXJjZS5kaXNwbGFjZW1lbnRTY2FsZTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBzb3VyY2UuYWxwaGFNYXA7XG5cblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gc291cmNlLmZsYXRTaGFkaW5nO1xuXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIExpbmVEYXNoZWRNYXRlcmlhbCBleHRlbmRzIExpbmVCYXNpY01hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTGluZURhc2hlZE1hdGVyaWFsID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdMaW5lRGFzaGVkTWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5zY2FsZSA9IDE7XG5cdFx0dGhpcy5kYXNoU2l6ZSA9IDM7XG5cdFx0dGhpcy5nYXBTaXplID0gMTtcblxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5zY2FsZSA9IHNvdXJjZS5zY2FsZTtcblx0XHR0aGlzLmRhc2hTaXplID0gc291cmNlLmRhc2hTaXplO1xuXHRcdHRoaXMuZ2FwU2l6ZSA9IHNvdXJjZS5nYXBTaXplO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbi8vIGNvbnZlcnRzIGFuIGFycmF5IHRvIGEgc3BlY2lmaWMgdHlwZVxuZnVuY3Rpb24gY29udmVydEFycmF5KCBhcnJheSwgdHlwZSwgZm9yY2VDbG9uZSApIHtcblxuXHRpZiAoICEgYXJyYXkgfHwgLy8gbGV0ICd1bmRlZmluZWQnIGFuZCAnbnVsbCcgcGFzc1xuXHRcdCEgZm9yY2VDbG9uZSAmJiBhcnJheS5jb25zdHJ1Y3RvciA9PT0gdHlwZSApIHJldHVybiBhcnJheTtcblxuXHRpZiAoIHR5cGVvZiB0eXBlLkJZVEVTX1BFUl9FTEVNRU5UID09PSAnbnVtYmVyJyApIHtcblxuXHRcdHJldHVybiBuZXcgdHlwZSggYXJyYXkgKTsgLy8gY3JlYXRlIHR5cGVkIGFycmF5XG5cblx0fVxuXG5cdHJldHVybiBBcnJheS5wcm90b3R5cGUuc2xpY2UuY2FsbCggYXJyYXkgKTsgLy8gY3JlYXRlIEFycmF5XG5cbn1cblxuZnVuY3Rpb24gaXNUeXBlZEFycmF5KCBvYmplY3QgKSB7XG5cblx0cmV0dXJuIEFycmF5QnVmZmVyLmlzVmlldyggb2JqZWN0ICkgJiZcblx0XHQhICggb2JqZWN0IGluc3RhbmNlb2YgRGF0YVZpZXcgKTtcblxufVxuXG4vLyByZXR1cm5zIGFuIGFycmF5IGJ5IHdoaWNoIHRpbWVzIGFuZCB2YWx1ZXMgY2FuIGJlIHNvcnRlZFxuZnVuY3Rpb24gZ2V0S2V5ZnJhbWVPcmRlciggdGltZXMgKSB7XG5cblx0ZnVuY3Rpb24gY29tcGFyZVRpbWUoIGksIGogKSB7XG5cblx0XHRyZXR1cm4gdGltZXNbIGkgXSAtIHRpbWVzWyBqIF07XG5cblx0fVxuXG5cdGNvbnN0IG4gPSB0aW1lcy5sZW5ndGg7XG5cdGNvbnN0IHJlc3VsdCA9IG5ldyBBcnJheSggbiApO1xuXHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IG47ICsrIGkgKSByZXN1bHRbIGkgXSA9IGk7XG5cblx0cmVzdWx0LnNvcnQoIGNvbXBhcmVUaW1lICk7XG5cblx0cmV0dXJuIHJlc3VsdDtcblxufVxuXG4vLyB1c2VzIHRoZSBhcnJheSBwcmV2aW91c2x5IHJldHVybmVkIGJ5ICdnZXRLZXlmcmFtZU9yZGVyJyB0byBzb3J0IGRhdGFcbmZ1bmN0aW9uIHNvcnRlZEFycmF5KCB2YWx1ZXMsIHN0cmlkZSwgb3JkZXIgKSB7XG5cblx0Y29uc3QgblZhbHVlcyA9IHZhbHVlcy5sZW5ndGg7XG5cdGNvbnN0IHJlc3VsdCA9IG5ldyB2YWx1ZXMuY29uc3RydWN0b3IoIG5WYWx1ZXMgKTtcblxuXHRmb3IgKCBsZXQgaSA9IDAsIGRzdE9mZnNldCA9IDA7IGRzdE9mZnNldCAhPT0gblZhbHVlczsgKysgaSApIHtcblxuXHRcdGNvbnN0IHNyY09mZnNldCA9IG9yZGVyWyBpIF0gKiBzdHJpZGU7XG5cblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogIT09IHN0cmlkZTsgKysgaiApIHtcblxuXHRcdFx0cmVzdWx0WyBkc3RPZmZzZXQgKysgXSA9IHZhbHVlc1sgc3JjT2Zmc2V0ICsgaiBdO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4gcmVzdWx0O1xuXG59XG5cbi8vIGZ1bmN0aW9uIGZvciBwYXJzaW5nIEFPUyBrZXlmcmFtZSBmb3JtYXRzXG5mdW5jdGlvbiBmbGF0dGVuSlNPTigganNvbktleXMsIHRpbWVzLCB2YWx1ZXMsIHZhbHVlUHJvcGVydHlOYW1lICkge1xuXG5cdGxldCBpID0gMSwga2V5ID0ganNvbktleXNbIDAgXTtcblxuXHR3aGlsZSAoIGtleSAhPT0gdW5kZWZpbmVkICYmIGtleVsgdmFsdWVQcm9wZXJ0eU5hbWUgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0a2V5ID0ganNvbktleXNbIGkgKysgXTtcblxuXHR9XG5cblx0aWYgKCBrZXkgPT09IHVuZGVmaW5lZCApIHJldHVybjsgLy8gbm8gZGF0YVxuXG5cdGxldCB2YWx1ZSA9IGtleVsgdmFsdWVQcm9wZXJ0eU5hbWUgXTtcblx0aWYgKCB2YWx1ZSA9PT0gdW5kZWZpbmVkICkgcmV0dXJuOyAvLyBubyBkYXRhXG5cblx0aWYgKCBBcnJheS5pc0FycmF5KCB2YWx1ZSApICkge1xuXG5cdFx0ZG8ge1xuXG5cdFx0XHR2YWx1ZSA9IGtleVsgdmFsdWVQcm9wZXJ0eU5hbWUgXTtcblxuXHRcdFx0aWYgKCB2YWx1ZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHRpbWVzLnB1c2goIGtleS50aW1lICk7XG5cdFx0XHRcdHZhbHVlcy5wdXNoLmFwcGx5KCB2YWx1ZXMsIHZhbHVlICk7IC8vIHB1c2ggYWxsIGVsZW1lbnRzXG5cblx0XHRcdH1cblxuXHRcdFx0a2V5ID0ganNvbktleXNbIGkgKysgXTtcblxuXHRcdH0gd2hpbGUgKCBrZXkgIT09IHVuZGVmaW5lZCApO1xuXG5cdH0gZWxzZSBpZiAoIHZhbHVlLnRvQXJyYXkgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdC8vIC4uLmFzc3VtZSBUSFJFRS5NYXRoLWlzaFxuXG5cdFx0ZG8ge1xuXG5cdFx0XHR2YWx1ZSA9IGtleVsgdmFsdWVQcm9wZXJ0eU5hbWUgXTtcblxuXHRcdFx0aWYgKCB2YWx1ZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHRpbWVzLnB1c2goIGtleS50aW1lICk7XG5cdFx0XHRcdHZhbHVlLnRvQXJyYXkoIHZhbHVlcywgdmFsdWVzLmxlbmd0aCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGtleSA9IGpzb25LZXlzWyBpICsrIF07XG5cblx0XHR9IHdoaWxlICgga2V5ICE9PSB1bmRlZmluZWQgKTtcblxuXHR9IGVsc2Uge1xuXG5cdFx0Ly8gb3RoZXJ3aXNlIHB1c2ggYXMtaXNcblxuXHRcdGRvIHtcblxuXHRcdFx0dmFsdWUgPSBrZXlbIHZhbHVlUHJvcGVydHlOYW1lIF07XG5cblx0XHRcdGlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0aW1lcy5wdXNoKCBrZXkudGltZSApO1xuXHRcdFx0XHR2YWx1ZXMucHVzaCggdmFsdWUgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRrZXkgPSBqc29uS2V5c1sgaSArKyBdO1xuXG5cdFx0fSB3aGlsZSAoIGtleSAhPT0gdW5kZWZpbmVkICk7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHN1YmNsaXAoIHNvdXJjZUNsaXAsIG5hbWUsIHN0YXJ0RnJhbWUsIGVuZEZyYW1lLCBmcHMgPSAzMCApIHtcblxuXHRjb25zdCBjbGlwID0gc291cmNlQ2xpcC5jbG9uZSgpO1xuXG5cdGNsaXAubmFtZSA9IG5hbWU7XG5cblx0Y29uc3QgdHJhY2tzID0gW107XG5cblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY2xpcC50cmFja3MubGVuZ3RoOyArKyBpICkge1xuXG5cdFx0Y29uc3QgdHJhY2sgPSBjbGlwLnRyYWNrc1sgaSBdO1xuXHRcdGNvbnN0IHZhbHVlU2l6ZSA9IHRyYWNrLmdldFZhbHVlU2l6ZSgpO1xuXG5cdFx0Y29uc3QgdGltZXMgPSBbXTtcblx0XHRjb25zdCB2YWx1ZXMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBqID0gMDsgaiA8IHRyYWNrLnRpbWVzLmxlbmd0aDsgKysgaiApIHtcblxuXHRcdFx0Y29uc3QgZnJhbWUgPSB0cmFjay50aW1lc1sgaiBdICogZnBzO1xuXG5cdFx0XHRpZiAoIGZyYW1lIDwgc3RhcnRGcmFtZSB8fCBmcmFtZSA+PSBlbmRGcmFtZSApIGNvbnRpbnVlO1xuXG5cdFx0XHR0aW1lcy5wdXNoKCB0cmFjay50aW1lc1sgaiBdICk7XG5cblx0XHRcdGZvciAoIGxldCBrID0gMDsgayA8IHZhbHVlU2l6ZTsgKysgayApIHtcblxuXHRcdFx0XHR2YWx1ZXMucHVzaCggdHJhY2sudmFsdWVzWyBqICogdmFsdWVTaXplICsgayBdICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggdGltZXMubGVuZ3RoID09PSAwICkgY29udGludWU7XG5cblx0XHR0cmFjay50aW1lcyA9IGNvbnZlcnRBcnJheSggdGltZXMsIHRyYWNrLnRpbWVzLmNvbnN0cnVjdG9yICk7XG5cdFx0dHJhY2sudmFsdWVzID0gY29udmVydEFycmF5KCB2YWx1ZXMsIHRyYWNrLnZhbHVlcy5jb25zdHJ1Y3RvciApO1xuXG5cdFx0dHJhY2tzLnB1c2goIHRyYWNrICk7XG5cblx0fVxuXG5cdGNsaXAudHJhY2tzID0gdHJhY2tzO1xuXG5cdC8vIGZpbmQgbWluaW11bSAudGltZXMgdmFsdWUgYWNyb3NzIGFsbCB0cmFja3MgaW4gdGhlIHRyaW1tZWQgY2xpcFxuXG5cdGxldCBtaW5TdGFydFRpbWUgPSBJbmZpbml0eTtcblxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjbGlwLnRyYWNrcy5sZW5ndGg7ICsrIGkgKSB7XG5cblx0XHRpZiAoIG1pblN0YXJ0VGltZSA+IGNsaXAudHJhY2tzWyBpIF0udGltZXNbIDAgXSApIHtcblxuXHRcdFx0bWluU3RhcnRUaW1lID0gY2xpcC50cmFja3NbIGkgXS50aW1lc1sgMCBdO1xuXG5cdFx0fVxuXG5cdH1cblxuXHQvLyBzaGlmdCBhbGwgdHJhY2tzIHN1Y2ggdGhhdCBjbGlwIGJlZ2lucyBhdCB0PTBcblxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjbGlwLnRyYWNrcy5sZW5ndGg7ICsrIGkgKSB7XG5cblx0XHRjbGlwLnRyYWNrc1sgaSBdLnNoaWZ0KCAtIDEgKiBtaW5TdGFydFRpbWUgKTtcblxuXHR9XG5cblx0Y2xpcC5yZXNldER1cmF0aW9uKCk7XG5cblx0cmV0dXJuIGNsaXA7XG5cbn1cblxuZnVuY3Rpb24gbWFrZUNsaXBBZGRpdGl2ZSggdGFyZ2V0Q2xpcCwgcmVmZXJlbmNlRnJhbWUgPSAwLCByZWZlcmVuY2VDbGlwID0gdGFyZ2V0Q2xpcCwgZnBzID0gMzAgKSB7XG5cblx0aWYgKCBmcHMgPD0gMCApIGZwcyA9IDMwO1xuXG5cdGNvbnN0IG51bVRyYWNrcyA9IHJlZmVyZW5jZUNsaXAudHJhY2tzLmxlbmd0aDtcblx0Y29uc3QgcmVmZXJlbmNlVGltZSA9IHJlZmVyZW5jZUZyYW1lIC8gZnBzO1xuXG5cdC8vIE1ha2UgZWFjaCB0cmFjaydzIHZhbHVlcyByZWxhdGl2ZSB0byB0aGUgdmFsdWVzIGF0IHRoZSByZWZlcmVuY2UgZnJhbWVcblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbnVtVHJhY2tzOyArKyBpICkge1xuXG5cdFx0Y29uc3QgcmVmZXJlbmNlVHJhY2sgPSByZWZlcmVuY2VDbGlwLnRyYWNrc1sgaSBdO1xuXHRcdGNvbnN0IHJlZmVyZW5jZVRyYWNrVHlwZSA9IHJlZmVyZW5jZVRyYWNrLlZhbHVlVHlwZU5hbWU7XG5cblx0XHQvLyBTa2lwIHRoaXMgdHJhY2sgaWYgaXQncyBub24tbnVtZXJpY1xuXHRcdGlmICggcmVmZXJlbmNlVHJhY2tUeXBlID09PSAnYm9vbCcgfHwgcmVmZXJlbmNlVHJhY2tUeXBlID09PSAnc3RyaW5nJyApIGNvbnRpbnVlO1xuXG5cdFx0Ly8gRmluZCB0aGUgdHJhY2sgaW4gdGhlIHRhcmdldCBjbGlwIHdob3NlIG5hbWUgYW5kIHR5cGUgbWF0Y2hlcyB0aGUgcmVmZXJlbmNlIHRyYWNrXG5cdFx0Y29uc3QgdGFyZ2V0VHJhY2sgPSB0YXJnZXRDbGlwLnRyYWNrcy5maW5kKCBmdW5jdGlvbiAoIHRyYWNrICkge1xuXG5cdFx0XHRyZXR1cm4gdHJhY2submFtZSA9PT0gcmVmZXJlbmNlVHJhY2submFtZVxuXHRcdFx0XHQmJiB0cmFjay5WYWx1ZVR5cGVOYW1lID09PSByZWZlcmVuY2VUcmFja1R5cGU7XG5cblx0XHR9ICk7XG5cblx0XHRpZiAoIHRhcmdldFRyYWNrID09PSB1bmRlZmluZWQgKSBjb250aW51ZTtcblxuXHRcdGxldCByZWZlcmVuY2VPZmZzZXQgPSAwO1xuXHRcdGNvbnN0IHJlZmVyZW5jZVZhbHVlU2l6ZSA9IHJlZmVyZW5jZVRyYWNrLmdldFZhbHVlU2l6ZSgpO1xuXG5cdFx0aWYgKCByZWZlcmVuY2VUcmFjay5jcmVhdGVJbnRlcnBvbGFudC5pc0ludGVycG9sYW50RmFjdG9yeU1ldGhvZEdMVEZDdWJpY1NwbGluZSApIHtcblxuXHRcdFx0cmVmZXJlbmNlT2Zmc2V0ID0gcmVmZXJlbmNlVmFsdWVTaXplIC8gMztcblxuXHRcdH1cblxuXHRcdGxldCB0YXJnZXRPZmZzZXQgPSAwO1xuXHRcdGNvbnN0IHRhcmdldFZhbHVlU2l6ZSA9IHRhcmdldFRyYWNrLmdldFZhbHVlU2l6ZSgpO1xuXG5cdFx0aWYgKCB0YXJnZXRUcmFjay5jcmVhdGVJbnRlcnBvbGFudC5pc0ludGVycG9sYW50RmFjdG9yeU1ldGhvZEdMVEZDdWJpY1NwbGluZSApIHtcblxuXHRcdFx0dGFyZ2V0T2Zmc2V0ID0gdGFyZ2V0VmFsdWVTaXplIC8gMztcblxuXHRcdH1cblxuXHRcdGNvbnN0IGxhc3RJbmRleCA9IHJlZmVyZW5jZVRyYWNrLnRpbWVzLmxlbmd0aCAtIDE7XG5cdFx0bGV0IHJlZmVyZW5jZVZhbHVlO1xuXG5cdFx0Ly8gRmluZCB0aGUgdmFsdWUgdG8gc3VidHJhY3Qgb3V0IG9mIHRoZSB0cmFja1xuXHRcdGlmICggcmVmZXJlbmNlVGltZSA8PSByZWZlcmVuY2VUcmFjay50aW1lc1sgMCBdICkge1xuXG5cdFx0XHQvLyBSZWZlcmVuY2UgZnJhbWUgaXMgZWFybGllciB0aGFuIHRoZSBmaXJzdCBrZXlmcmFtZSwgc28ganVzdCB1c2UgdGhlIGZpcnN0IGtleWZyYW1lXG5cdFx0XHRjb25zdCBzdGFydEluZGV4ID0gcmVmZXJlbmNlT2Zmc2V0O1xuXHRcdFx0Y29uc3QgZW5kSW5kZXggPSByZWZlcmVuY2VWYWx1ZVNpemUgLSByZWZlcmVuY2VPZmZzZXQ7XG5cdFx0XHRyZWZlcmVuY2VWYWx1ZSA9IHJlZmVyZW5jZVRyYWNrLnZhbHVlcy5zbGljZSggc3RhcnRJbmRleCwgZW5kSW5kZXggKTtcblxuXHRcdH0gZWxzZSBpZiAoIHJlZmVyZW5jZVRpbWUgPj0gcmVmZXJlbmNlVHJhY2sudGltZXNbIGxhc3RJbmRleCBdICkge1xuXG5cdFx0XHQvLyBSZWZlcmVuY2UgZnJhbWUgaXMgYWZ0ZXIgdGhlIGxhc3Qga2V5ZnJhbWUsIHNvIGp1c3QgdXNlIHRoZSBsYXN0IGtleWZyYW1lXG5cdFx0XHRjb25zdCBzdGFydEluZGV4ID0gbGFzdEluZGV4ICogcmVmZXJlbmNlVmFsdWVTaXplICsgcmVmZXJlbmNlT2Zmc2V0O1xuXHRcdFx0Y29uc3QgZW5kSW5kZXggPSBzdGFydEluZGV4ICsgcmVmZXJlbmNlVmFsdWVTaXplIC0gcmVmZXJlbmNlT2Zmc2V0O1xuXHRcdFx0cmVmZXJlbmNlVmFsdWUgPSByZWZlcmVuY2VUcmFjay52YWx1ZXMuc2xpY2UoIHN0YXJ0SW5kZXgsIGVuZEluZGV4ICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBJbnRlcnBvbGF0ZSB0byB0aGUgcmVmZXJlbmNlIHZhbHVlXG5cdFx0XHRjb25zdCBpbnRlcnBvbGFudCA9IHJlZmVyZW5jZVRyYWNrLmNyZWF0ZUludGVycG9sYW50KCk7XG5cdFx0XHRjb25zdCBzdGFydEluZGV4ID0gcmVmZXJlbmNlT2Zmc2V0O1xuXHRcdFx0Y29uc3QgZW5kSW5kZXggPSByZWZlcmVuY2VWYWx1ZVNpemUgLSByZWZlcmVuY2VPZmZzZXQ7XG5cdFx0XHRpbnRlcnBvbGFudC5ldmFsdWF0ZSggcmVmZXJlbmNlVGltZSApO1xuXHRcdFx0cmVmZXJlbmNlVmFsdWUgPSBpbnRlcnBvbGFudC5yZXN1bHRCdWZmZXIuc2xpY2UoIHN0YXJ0SW5kZXgsIGVuZEluZGV4ICk7XG5cblx0XHR9XG5cblx0XHQvLyBDb25qdWdhdGUgdGhlIHF1YXRlcm5pb25cblx0XHRpZiAoIHJlZmVyZW5jZVRyYWNrVHlwZSA9PT0gJ3F1YXRlcm5pb24nICkge1xuXG5cdFx0XHRjb25zdCByZWZlcmVuY2VRdWF0ID0gbmV3IFF1YXRlcm5pb24oKS5mcm9tQXJyYXkoIHJlZmVyZW5jZVZhbHVlICkubm9ybWFsaXplKCkuY29uanVnYXRlKCk7XG5cdFx0XHRyZWZlcmVuY2VRdWF0LnRvQXJyYXkoIHJlZmVyZW5jZVZhbHVlICk7XG5cblx0XHR9XG5cblx0XHQvLyBTdWJ0cmFjdCB0aGUgcmVmZXJlbmNlIHZhbHVlIGZyb20gYWxsIG9mIHRoZSB0cmFjayB2YWx1ZXNcblxuXHRcdGNvbnN0IG51bVRpbWVzID0gdGFyZ2V0VHJhY2sudGltZXMubGVuZ3RoO1xuXHRcdGZvciAoIGxldCBqID0gMDsgaiA8IG51bVRpbWVzOyArKyBqICkge1xuXG5cdFx0XHRjb25zdCB2YWx1ZVN0YXJ0ID0gaiAqIHRhcmdldFZhbHVlU2l6ZSArIHRhcmdldE9mZnNldDtcblxuXHRcdFx0aWYgKCByZWZlcmVuY2VUcmFja1R5cGUgPT09ICdxdWF0ZXJuaW9uJyApIHtcblxuXHRcdFx0XHQvLyBNdWx0aXBseSB0aGUgY29uanVnYXRlIGZvciBxdWF0ZXJuaW9uIHRyYWNrIHR5cGVzXG5cdFx0XHRcdFF1YXRlcm5pb24ubXVsdGlwbHlRdWF0ZXJuaW9uc0ZsYXQoXG5cdFx0XHRcdFx0dGFyZ2V0VHJhY2sudmFsdWVzLFxuXHRcdFx0XHRcdHZhbHVlU3RhcnQsXG5cdFx0XHRcdFx0cmVmZXJlbmNlVmFsdWUsXG5cdFx0XHRcdFx0MCxcblx0XHRcdFx0XHR0YXJnZXRUcmFjay52YWx1ZXMsXG5cdFx0XHRcdFx0dmFsdWVTdGFydFxuXHRcdFx0XHQpO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNvbnN0IHZhbHVlRW5kID0gdGFyZ2V0VmFsdWVTaXplIC0gdGFyZ2V0T2Zmc2V0ICogMjtcblxuXHRcdFx0XHQvLyBTdWJ0cmFjdCBlYWNoIHZhbHVlIGZvciBhbGwgb3RoZXIgbnVtZXJpYyB0cmFjayB0eXBlc1xuXHRcdFx0XHRmb3IgKCBsZXQgayA9IDA7IGsgPCB2YWx1ZUVuZDsgKysgayApIHtcblxuXHRcdFx0XHRcdHRhcmdldFRyYWNrLnZhbHVlc1sgdmFsdWVTdGFydCArIGsgXSAtPSByZWZlcmVuY2VWYWx1ZVsgayBdO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHR0YXJnZXRDbGlwLmJsZW5kTW9kZSA9IEFkZGl0aXZlQW5pbWF0aW9uQmxlbmRNb2RlO1xuXG5cdHJldHVybiB0YXJnZXRDbGlwO1xuXG59XG5cbmNvbnN0IEFuaW1hdGlvblV0aWxzID0ge1xuXHRjb252ZXJ0QXJyYXk6IGNvbnZlcnRBcnJheSxcblx0aXNUeXBlZEFycmF5OiBpc1R5cGVkQXJyYXksXG5cdGdldEtleWZyYW1lT3JkZXI6IGdldEtleWZyYW1lT3JkZXIsXG5cdHNvcnRlZEFycmF5OiBzb3J0ZWRBcnJheSxcblx0ZmxhdHRlbkpTT046IGZsYXR0ZW5KU09OLFxuXHRzdWJjbGlwOiBzdWJjbGlwLFxuXHRtYWtlQ2xpcEFkZGl0aXZlOiBtYWtlQ2xpcEFkZGl0aXZlXG59O1xuXG4vKipcbiAqIEFic3RyYWN0IGJhc2UgY2xhc3Mgb2YgaW50ZXJwb2xhbnRzIG92ZXIgcGFyYW1ldHJpYyBzYW1wbGVzLlxuICpcbiAqIFRoZSBwYXJhbWV0ZXIgZG9tYWluIGlzIG9uZSBkaW1lbnNpb25hbCwgdHlwaWNhbGx5IHRoZSB0aW1lIG9yIGEgcGF0aFxuICogYWxvbmcgYSBjdXJ2ZSBkZWZpbmVkIGJ5IHRoZSBkYXRhLlxuICpcbiAqIFRoZSBzYW1wbGUgdmFsdWVzIGNhbiBoYXZlIGFueSBkaW1lbnNpb25hbGl0eSBhbmQgZGVyaXZlZCBjbGFzc2VzIG1heVxuICogYXBwbHkgc3BlY2lhbCBpbnRlcnByZXRhdGlvbnMgdG8gdGhlIGRhdGEuXG4gKlxuICogVGhpcyBjbGFzcyBwcm92aWRlcyB0aGUgaW50ZXJ2YWwgc2VlayBpbiBhIFRlbXBsYXRlIE1ldGhvZCwgZGVmZXJyaW5nXG4gKiB0aGUgYWN0dWFsIGludGVycG9sYXRpb24gdG8gZGVyaXZlZCBjbGFzc2VzLlxuICpcbiAqIFRpbWUgY29tcGxleGl0eSBpcyBPKDEpIGZvciBsaW5lYXIgYWNjZXNzIGNyb3NzaW5nIGF0IG1vc3QgdHdvIHBvaW50c1xuICogYW5kIE8obG9nIE4pIGZvciByYW5kb20gYWNjZXNzLCB3aGVyZSBOIGlzIHRoZSBudW1iZXIgb2YgcG9zaXRpb25zLlxuICpcbiAqIFJlZmVyZW5jZXM6XG4gKlxuICogXHRcdGh0dHA6Ly93d3cub29kZXNpZ24uY29tL3RlbXBsYXRlLW1ldGhvZC1wYXR0ZXJuLmh0bWxcbiAqXG4gKi9cblxuY2xhc3MgSW50ZXJwb2xhbnQge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICkge1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJQb3NpdGlvbnMgPSBwYXJhbWV0ZXJQb3NpdGlvbnM7XG5cdFx0dGhpcy5fY2FjaGVkSW5kZXggPSAwO1xuXG5cdFx0dGhpcy5yZXN1bHRCdWZmZXIgPSByZXN1bHRCdWZmZXIgIT09IHVuZGVmaW5lZCA/XG5cdFx0XHRyZXN1bHRCdWZmZXIgOiBuZXcgc2FtcGxlVmFsdWVzLmNvbnN0cnVjdG9yKCBzYW1wbGVTaXplICk7XG5cdFx0dGhpcy5zYW1wbGVWYWx1ZXMgPSBzYW1wbGVWYWx1ZXM7XG5cdFx0dGhpcy52YWx1ZVNpemUgPSBzYW1wbGVTaXplO1xuXG5cdFx0dGhpcy5zZXR0aW5ncyA9IG51bGw7XG5cdFx0dGhpcy5EZWZhdWx0U2V0dGluZ3NfID0ge307XG5cblx0fVxuXG5cdGV2YWx1YXRlKCB0ICkge1xuXG5cdFx0Y29uc3QgcHAgPSB0aGlzLnBhcmFtZXRlclBvc2l0aW9ucztcblx0XHRsZXQgaTEgPSB0aGlzLl9jYWNoZWRJbmRleCxcblx0XHRcdHQxID0gcHBbIGkxIF0sXG5cdFx0XHR0MCA9IHBwWyBpMSAtIDEgXTtcblxuXHRcdHZhbGlkYXRlX2ludGVydmFsOiB7XG5cblx0XHRcdHNlZWs6IHtcblxuXHRcdFx0XHRsZXQgcmlnaHQ7XG5cblx0XHRcdFx0bGluZWFyX3NjYW46IHtcblxuXHRcdFx0XHRcdC8vLSBTZWUgaHR0cDovL2pzcGVyZi5jb20vY29tcGFyaXNvbi10by11bmRlZmluZWQvM1xuXHRcdFx0XHRcdC8vLSBzbG93ZXIgY29kZTpcblx0XHRcdFx0XHQvLy1cblx0XHRcdFx0XHQvLy0gXHRcdFx0XHRpZiAoIHQgPj0gdDEgfHwgdDEgPT09IHVuZGVmaW5lZCApIHtcblx0XHRcdFx0XHRmb3J3YXJkX3NjYW46IGlmICggISAoIHQgPCB0MSApICkge1xuXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgZ2l2ZVVwQXQgPSBpMSArIDI7IDsgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCB0MSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCB0IDwgdDAgKSBicmVhayBmb3J3YXJkX3NjYW47XG5cblx0XHRcdFx0XHRcdFx0XHQvLyBhZnRlciBlbmRcblxuXHRcdFx0XHRcdFx0XHRcdGkxID0gcHAubGVuZ3RoO1xuXHRcdFx0XHRcdFx0XHRcdHRoaXMuX2NhY2hlZEluZGV4ID0gaTE7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMuY29weVNhbXBsZVZhbHVlXyggaTEgLSAxICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdGlmICggaTEgPT09IGdpdmVVcEF0ICkgYnJlYWs7IC8vIHRoaXMgbG9vcFxuXG5cdFx0XHRcdFx0XHRcdHQwID0gdDE7XG5cdFx0XHRcdFx0XHRcdHQxID0gcHBbICsrIGkxIF07XG5cblx0XHRcdFx0XHRcdFx0aWYgKCB0IDwgdDEgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHQvLyB3ZSBoYXZlIGFycml2ZWQgYXQgdGhlIHNvdWdodCBpbnRlcnZhbFxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrIHNlZWs7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdC8vIHByZXBhcmUgYmluYXJ5IHNlYXJjaCBvbiB0aGUgcmlnaHQgc2lkZSBvZiB0aGUgaW5kZXhcblx0XHRcdFx0XHRcdHJpZ2h0ID0gcHAubGVuZ3RoO1xuXHRcdFx0XHRcdFx0YnJlYWsgbGluZWFyX3NjYW47XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLy0gc2xvd2VyIGNvZGU6XG5cdFx0XHRcdFx0Ly8tXHRcdFx0XHRcdGlmICggdCA8IHQwIHx8IHQwID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0aWYgKCAhICggdCA+PSB0MCApICkge1xuXG5cdFx0XHRcdFx0XHQvLyBsb29waW5nP1xuXG5cdFx0XHRcdFx0XHRjb25zdCB0MWdsb2JhbCA9IHBwWyAxIF07XG5cblx0XHRcdFx0XHRcdGlmICggdCA8IHQxZ2xvYmFsICkge1xuXG5cdFx0XHRcdFx0XHRcdGkxID0gMjsgLy8gKyAxLCB1c2luZyB0aGUgc2NhbiBmb3IgdGhlIGRldGFpbHNcblx0XHRcdFx0XHRcdFx0dDAgPSB0MWdsb2JhbDtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHQvLyBsaW5lYXIgcmV2ZXJzZSBzY2FuXG5cblx0XHRcdFx0XHRcdGZvciAoIGxldCBnaXZlVXBBdCA9IGkxIC0gMjsgOyApIHtcblxuXHRcdFx0XHRcdFx0XHRpZiAoIHQwID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHQvLyBiZWZvcmUgc3RhcnRcblxuXHRcdFx0XHRcdFx0XHRcdHRoaXMuX2NhY2hlZEluZGV4ID0gMDtcblx0XHRcdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy5jb3B5U2FtcGxlVmFsdWVfKCAwICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdGlmICggaTEgPT09IGdpdmVVcEF0ICkgYnJlYWs7IC8vIHRoaXMgbG9vcFxuXG5cdFx0XHRcdFx0XHRcdHQxID0gdDA7XG5cdFx0XHRcdFx0XHRcdHQwID0gcHBbIC0tIGkxIC0gMSBdO1xuXG5cdFx0XHRcdFx0XHRcdGlmICggdCA+PSB0MCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIHdlIGhhdmUgYXJyaXZlZCBhdCB0aGUgc291Z2h0IGludGVydmFsXG5cdFx0XHRcdFx0XHRcdFx0YnJlYWsgc2VlaztcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0Ly8gcHJlcGFyZSBiaW5hcnkgc2VhcmNoIG9uIHRoZSBsZWZ0IHNpZGUgb2YgdGhlIGluZGV4XG5cdFx0XHRcdFx0XHRyaWdodCA9IGkxO1xuXHRcdFx0XHRcdFx0aTEgPSAwO1xuXHRcdFx0XHRcdFx0YnJlYWsgbGluZWFyX3NjYW47XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyB0aGUgaW50ZXJ2YWwgaXMgdmFsaWRcblxuXHRcdFx0XHRcdGJyZWFrIHZhbGlkYXRlX2ludGVydmFsO1xuXG5cdFx0XHRcdH0gLy8gbGluZWFyIHNjYW5cblxuXHRcdFx0XHQvLyBiaW5hcnkgc2VhcmNoXG5cblx0XHRcdFx0d2hpbGUgKCBpMSA8IHJpZ2h0ICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgbWlkID0gKCBpMSArIHJpZ2h0ICkgPj4+IDE7XG5cblx0XHRcdFx0XHRpZiAoIHQgPCBwcFsgbWlkIF0gKSB7XG5cblx0XHRcdFx0XHRcdHJpZ2h0ID0gbWlkO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0aTEgPSBtaWQgKyAxO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHR0MSA9IHBwWyBpMSBdO1xuXHRcdFx0XHR0MCA9IHBwWyBpMSAtIDEgXTtcblxuXHRcdFx0XHQvLyBjaGVjayBib3VuZGFyeSBjYXNlcywgYWdhaW5cblxuXHRcdFx0XHRpZiAoIHQwID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHR0aGlzLl9jYWNoZWRJbmRleCA9IDA7XG5cdFx0XHRcdFx0cmV0dXJuIHRoaXMuY29weVNhbXBsZVZhbHVlXyggMCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIHQxID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRpMSA9IHBwLmxlbmd0aDtcblx0XHRcdFx0XHR0aGlzLl9jYWNoZWRJbmRleCA9IGkxO1xuXHRcdFx0XHRcdHJldHVybiB0aGlzLmNvcHlTYW1wbGVWYWx1ZV8oIGkxIC0gMSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSAvLyBzZWVrXG5cblx0XHRcdHRoaXMuX2NhY2hlZEluZGV4ID0gaTE7XG5cblx0XHRcdHRoaXMuaW50ZXJ2YWxDaGFuZ2VkXyggaTEsIHQwLCB0MSApO1xuXG5cdFx0fSAvLyB2YWxpZGF0ZV9pbnRlcnZhbFxuXG5cdFx0cmV0dXJuIHRoaXMuaW50ZXJwb2xhdGVfKCBpMSwgdDAsIHQsIHQxICk7XG5cblx0fVxuXG5cdGdldFNldHRpbmdzXygpIHtcblxuXHRcdHJldHVybiB0aGlzLnNldHRpbmdzIHx8IHRoaXMuRGVmYXVsdFNldHRpbmdzXztcblxuXHR9XG5cblx0Y29weVNhbXBsZVZhbHVlXyggaW5kZXggKSB7XG5cblx0XHQvLyBjb3BpZXMgYSBzYW1wbGUgdmFsdWUgdG8gdGhlIHJlc3VsdCBidWZmZXJcblxuXHRcdGNvbnN0IHJlc3VsdCA9IHRoaXMucmVzdWx0QnVmZmVyLFxuXHRcdFx0dmFsdWVzID0gdGhpcy5zYW1wbGVWYWx1ZXMsXG5cdFx0XHRzdHJpZGUgPSB0aGlzLnZhbHVlU2l6ZSxcblx0XHRcdG9mZnNldCA9IGluZGV4ICogc3RyaWRlO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBzdHJpZGU7ICsrIGkgKSB7XG5cblx0XHRcdHJlc3VsdFsgaSBdID0gdmFsdWVzWyBvZmZzZXQgKyBpIF07XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcmVzdWx0O1xuXG5cdH1cblxuXHQvLyBUZW1wbGF0ZSBtZXRob2RzIGZvciBkZXJpdmVkIGNsYXNzZXM6XG5cblx0aW50ZXJwb2xhdGVfKCAvKiBpMSwgdDAsIHQsIHQxICovICkge1xuXG5cdFx0dGhyb3cgbmV3IEVycm9yKCAnY2FsbCB0byBhYnN0cmFjdCBtZXRob2QnICk7XG5cdFx0Ly8gaW1wbGVtZW50YXRpb25zIHNoYWxsIHJldHVybiB0aGlzLnJlc3VsdEJ1ZmZlclxuXG5cdH1cblxuXHRpbnRlcnZhbENoYW5nZWRfKCAvKiBpMSwgdDAsIHQxICovICkge1xuXG5cdFx0Ly8gZW1wdHlcblxuXHR9XG5cbn1cblxuLyoqXG4gKiBGYXN0IGFuZCBzaW1wbGUgY3ViaWMgc3BsaW5lIGludGVycG9sYW50LlxuICpcbiAqIEl0IHdhcyBkZXJpdmVkIGZyb20gYSBIZXJtaXRpYW4gY29uc3RydWN0aW9uIHNldHRpbmcgdGhlIGZpcnN0IGRlcml2YXRpdmVcbiAqIGF0IGVhY2ggc2FtcGxlIHBvc2l0aW9uIHRvIHRoZSBsaW5lYXIgc2xvcGUgYmV0d2VlbiBuZWlnaGJvcmluZyBwb3NpdGlvbnNcbiAqIG92ZXIgdGhlaXIgcGFyYW1ldGVyIGludGVydmFsLlxuICovXG5cbmNsYXNzIEN1YmljSW50ZXJwb2xhbnQgZXh0ZW5kcyBJbnRlcnBvbGFudCB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlclBvc2l0aW9ucywgc2FtcGxlVmFsdWVzLCBzYW1wbGVTaXplLCByZXN1bHRCdWZmZXIgKSB7XG5cblx0XHRzdXBlciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApO1xuXG5cdFx0dGhpcy5fd2VpZ2h0UHJldiA9IC0gMDtcblx0XHR0aGlzLl9vZmZzZXRQcmV2ID0gLSAwO1xuXHRcdHRoaXMuX3dlaWdodE5leHQgPSAtIDA7XG5cdFx0dGhpcy5fb2Zmc2V0TmV4dCA9IC0gMDtcblxuXHRcdHRoaXMuRGVmYXVsdFNldHRpbmdzXyA9IHtcblxuXHRcdFx0ZW5kaW5nU3RhcnQ6IFplcm9DdXJ2YXR1cmVFbmRpbmcsXG5cdFx0XHRlbmRpbmdFbmQ6IFplcm9DdXJ2YXR1cmVFbmRpbmdcblxuXHRcdH07XG5cblx0fVxuXG5cdGludGVydmFsQ2hhbmdlZF8oIGkxLCB0MCwgdDEgKSB7XG5cblx0XHRjb25zdCBwcCA9IHRoaXMucGFyYW1ldGVyUG9zaXRpb25zO1xuXHRcdGxldCBpUHJldiA9IGkxIC0gMixcblx0XHRcdGlOZXh0ID0gaTEgKyAxLFxuXG5cdFx0XHR0UHJldiA9IHBwWyBpUHJldiBdLFxuXHRcdFx0dE5leHQgPSBwcFsgaU5leHQgXTtcblxuXHRcdGlmICggdFByZXYgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0c3dpdGNoICggdGhpcy5nZXRTZXR0aW5nc18oKS5lbmRpbmdTdGFydCApIHtcblxuXHRcdFx0XHRjYXNlIFplcm9TbG9wZUVuZGluZzpcblxuXHRcdFx0XHRcdC8vIGYnKHQwKSA9IDBcblx0XHRcdFx0XHRpUHJldiA9IGkxO1xuXHRcdFx0XHRcdHRQcmV2ID0gMiAqIHQwIC0gdDE7XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlIFdyYXBBcm91bmRFbmRpbmc6XG5cblx0XHRcdFx0XHQvLyB1c2UgdGhlIG90aGVyIGVuZCBvZiB0aGUgY3VydmVcblx0XHRcdFx0XHRpUHJldiA9IHBwLmxlbmd0aCAtIDI7XG5cdFx0XHRcdFx0dFByZXYgPSB0MCArIHBwWyBpUHJldiBdIC0gcHBbIGlQcmV2ICsgMSBdO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0ZGVmYXVsdDogLy8gWmVyb0N1cnZhdHVyZUVuZGluZ1xuXG5cdFx0XHRcdFx0Ly8gZicnKHQwKSA9IDAgYS5rLmEuIE5hdHVyYWwgU3BsaW5lXG5cdFx0XHRcdFx0aVByZXYgPSBpMTtcblx0XHRcdFx0XHR0UHJldiA9IHQxO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIHROZXh0ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHN3aXRjaCAoIHRoaXMuZ2V0U2V0dGluZ3NfKCkuZW5kaW5nRW5kICkge1xuXG5cdFx0XHRcdGNhc2UgWmVyb1Nsb3BlRW5kaW5nOlxuXG5cdFx0XHRcdFx0Ly8gZicodE4pID0gMFxuXHRcdFx0XHRcdGlOZXh0ID0gaTE7XG5cdFx0XHRcdFx0dE5leHQgPSAyICogdDEgLSB0MDtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgV3JhcEFyb3VuZEVuZGluZzpcblxuXHRcdFx0XHRcdC8vIHVzZSB0aGUgb3RoZXIgZW5kIG9mIHRoZSBjdXJ2ZVxuXHRcdFx0XHRcdGlOZXh0ID0gMTtcblx0XHRcdFx0XHR0TmV4dCA9IHQxICsgcHBbIDEgXSAtIHBwWyAwIF07XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRkZWZhdWx0OiAvLyBaZXJvQ3VydmF0dXJlRW5kaW5nXG5cblx0XHRcdFx0XHQvLyBmJycodE4pID0gMCwgYS5rLmEuIE5hdHVyYWwgU3BsaW5lXG5cdFx0XHRcdFx0aU5leHQgPSBpMSAtIDE7XG5cdFx0XHRcdFx0dE5leHQgPSB0MDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Y29uc3QgaGFsZkR0ID0gKCB0MSAtIHQwICkgKiAwLjUsXG5cdFx0XHRzdHJpZGUgPSB0aGlzLnZhbHVlU2l6ZTtcblxuXHRcdHRoaXMuX3dlaWdodFByZXYgPSBoYWxmRHQgLyAoIHQwIC0gdFByZXYgKTtcblx0XHR0aGlzLl93ZWlnaHROZXh0ID0gaGFsZkR0IC8gKCB0TmV4dCAtIHQxICk7XG5cdFx0dGhpcy5fb2Zmc2V0UHJldiA9IGlQcmV2ICogc3RyaWRlO1xuXHRcdHRoaXMuX29mZnNldE5leHQgPSBpTmV4dCAqIHN0cmlkZTtcblxuXHR9XG5cblx0aW50ZXJwb2xhdGVfKCBpMSwgdDAsIHQsIHQxICkge1xuXG5cdFx0Y29uc3QgcmVzdWx0ID0gdGhpcy5yZXN1bHRCdWZmZXIsXG5cdFx0XHR2YWx1ZXMgPSB0aGlzLnNhbXBsZVZhbHVlcyxcblx0XHRcdHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxuXG5cdFx0XHRvMSA9IGkxICogc3RyaWRlLFx0XHRvMCA9IG8xIC0gc3RyaWRlLFxuXHRcdFx0b1AgPSB0aGlzLl9vZmZzZXRQcmV2LCBcdG9OID0gdGhpcy5fb2Zmc2V0TmV4dCxcblx0XHRcdHdQID0gdGhpcy5fd2VpZ2h0UHJldixcdHdOID0gdGhpcy5fd2VpZ2h0TmV4dCxcblxuXHRcdFx0cCA9ICggdCAtIHQwICkgLyAoIHQxIC0gdDAgKSxcblx0XHRcdHBwID0gcCAqIHAsXG5cdFx0XHRwcHAgPSBwcCAqIHA7XG5cblx0XHQvLyBldmFsdWF0ZSBwb2x5bm9taWFsc1xuXG5cdFx0Y29uc3Qgc1AgPSAtIHdQICogcHBwICsgMiAqIHdQICogcHAgLSB3UCAqIHA7XG5cdFx0Y29uc3QgczAgPSAoIDEgKyB3UCApICogcHBwICsgKCAtIDEuNSAtIDIgKiB3UCApICogcHAgKyAoIC0gMC41ICsgd1AgKSAqIHAgKyAxO1xuXHRcdGNvbnN0IHMxID0gKCAtIDEgLSB3TiApICogcHBwICsgKCAxLjUgKyB3TiApICogcHAgKyAwLjUgKiBwO1xuXHRcdGNvbnN0IHNOID0gd04gKiBwcHAgLSB3TiAqIHBwO1xuXG5cdFx0Ly8gY29tYmluZSBkYXRhIGxpbmVhcmx5XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IHN0cmlkZTsgKysgaSApIHtcblxuXHRcdFx0cmVzdWx0WyBpIF0gPVxuXHRcdFx0XHRcdHNQICogdmFsdWVzWyBvUCArIGkgXSArXG5cdFx0XHRcdFx0czAgKiB2YWx1ZXNbIG8wICsgaSBdICtcblx0XHRcdFx0XHRzMSAqIHZhbHVlc1sgbzEgKyBpIF0gK1xuXHRcdFx0XHRcdHNOICogdmFsdWVzWyBvTiArIGkgXTtcblxuXHRcdH1cblxuXHRcdHJldHVybiByZXN1bHQ7XG5cblx0fVxuXG59XG5cbmNsYXNzIExpbmVhckludGVycG9sYW50IGV4dGVuZHMgSW50ZXJwb2xhbnQge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICkge1xuXG5cdFx0c3VwZXIoIHBhcmFtZXRlclBvc2l0aW9ucywgc2FtcGxlVmFsdWVzLCBzYW1wbGVTaXplLCByZXN1bHRCdWZmZXIgKTtcblxuXHR9XG5cblx0aW50ZXJwb2xhdGVfKCBpMSwgdDAsIHQsIHQxICkge1xuXG5cdFx0Y29uc3QgcmVzdWx0ID0gdGhpcy5yZXN1bHRCdWZmZXIsXG5cdFx0XHR2YWx1ZXMgPSB0aGlzLnNhbXBsZVZhbHVlcyxcblx0XHRcdHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxuXG5cdFx0XHRvZmZzZXQxID0gaTEgKiBzdHJpZGUsXG5cdFx0XHRvZmZzZXQwID0gb2Zmc2V0MSAtIHN0cmlkZSxcblxuXHRcdFx0d2VpZ2h0MSA9ICggdCAtIHQwICkgLyAoIHQxIC0gdDAgKSxcblx0XHRcdHdlaWdodDAgPSAxIC0gd2VpZ2h0MTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xuXG5cdFx0XHRyZXN1bHRbIGkgXSA9XG5cdFx0XHRcdFx0dmFsdWVzWyBvZmZzZXQwICsgaSBdICogd2VpZ2h0MCArXG5cdFx0XHRcdFx0dmFsdWVzWyBvZmZzZXQxICsgaSBdICogd2VpZ2h0MTtcblxuXHRcdH1cblxuXHRcdHJldHVybiByZXN1bHQ7XG5cblx0fVxuXG59XG5cbi8qKlxuICpcbiAqIEludGVycG9sYW50IHRoYXQgZXZhbHVhdGVzIHRvIHRoZSBzYW1wbGUgdmFsdWUgYXQgdGhlIHBvc2l0aW9uIHByZWNlZGluZ1xuICogdGhlIHBhcmFtZXRlci5cbiAqL1xuXG5jbGFzcyBEaXNjcmV0ZUludGVycG9sYW50IGV4dGVuZHMgSW50ZXJwb2xhbnQge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICkge1xuXG5cdFx0c3VwZXIoIHBhcmFtZXRlclBvc2l0aW9ucywgc2FtcGxlVmFsdWVzLCBzYW1wbGVTaXplLCByZXN1bHRCdWZmZXIgKTtcblxuXHR9XG5cblx0aW50ZXJwb2xhdGVfKCBpMSAvKiwgdDAsIHQsIHQxICovICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuY29weVNhbXBsZVZhbHVlXyggaTEgLSAxICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIEtleWZyYW1lVHJhY2sge1xuXG5cdGNvbnN0cnVjdG9yKCBuYW1lLCB0aW1lcywgdmFsdWVzLCBpbnRlcnBvbGF0aW9uICkge1xuXG5cdFx0aWYgKCBuYW1lID09PSB1bmRlZmluZWQgKSB0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiB0cmFjayBuYW1lIGlzIHVuZGVmaW5lZCcgKTtcblx0XHRpZiAoIHRpbWVzID09PSB1bmRlZmluZWQgfHwgdGltZXMubGVuZ3RoID09PSAwICkgdGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuS2V5ZnJhbWVUcmFjazogbm8ga2V5ZnJhbWVzIGluIHRyYWNrIG5hbWVkICcgKyBuYW1lICk7XG5cblx0XHR0aGlzLm5hbWUgPSBuYW1lO1xuXG5cdFx0dGhpcy50aW1lcyA9IGNvbnZlcnRBcnJheSggdGltZXMsIHRoaXMuVGltZUJ1ZmZlclR5cGUgKTtcblx0XHR0aGlzLnZhbHVlcyA9IGNvbnZlcnRBcnJheSggdmFsdWVzLCB0aGlzLlZhbHVlQnVmZmVyVHlwZSApO1xuXG5cdFx0dGhpcy5zZXRJbnRlcnBvbGF0aW9uKCBpbnRlcnBvbGF0aW9uIHx8IHRoaXMuRGVmYXVsdEludGVycG9sYXRpb24gKTtcblxuXHR9XG5cblx0Ly8gU2VyaWFsaXphdGlvbiAoaW4gc3RhdGljIGNvbnRleHQsIGJlY2F1c2Ugb2YgY29uc3RydWN0b3IgaW52b2NhdGlvblxuXHQvLyBhbmQgYXV0b21hdGljIGludm9jYXRpb24gb2YgLnRvSlNPTik6XG5cblx0c3RhdGljIHRvSlNPTiggdHJhY2sgKSB7XG5cblx0XHRjb25zdCB0cmFja1R5cGUgPSB0cmFjay5jb25zdHJ1Y3RvcjtcblxuXHRcdGxldCBqc29uO1xuXG5cdFx0Ly8gZGVyaXZlZCBjbGFzc2VzIGNhbiBkZWZpbmUgYSBzdGF0aWMgdG9KU09OIG1ldGhvZFxuXHRcdGlmICggdHJhY2tUeXBlLnRvSlNPTiAhPT0gdGhpcy50b0pTT04gKSB7XG5cblx0XHRcdGpzb24gPSB0cmFja1R5cGUudG9KU09OKCB0cmFjayApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gYnkgZGVmYXVsdCwgd2UgYXNzdW1lIHRoZSBkYXRhIGNhbiBiZSBzZXJpYWxpemVkIGFzLWlzXG5cdFx0XHRqc29uID0ge1xuXG5cdFx0XHRcdCduYW1lJzogdHJhY2submFtZSxcblx0XHRcdFx0J3RpbWVzJzogY29udmVydEFycmF5KCB0cmFjay50aW1lcywgQXJyYXkgKSxcblx0XHRcdFx0J3ZhbHVlcyc6IGNvbnZlcnRBcnJheSggdHJhY2sudmFsdWVzLCBBcnJheSApXG5cblx0XHRcdH07XG5cblx0XHRcdGNvbnN0IGludGVycG9sYXRpb24gPSB0cmFjay5nZXRJbnRlcnBvbGF0aW9uKCk7XG5cblx0XHRcdGlmICggaW50ZXJwb2xhdGlvbiAhPT0gdHJhY2suRGVmYXVsdEludGVycG9sYXRpb24gKSB7XG5cblx0XHRcdFx0anNvbi5pbnRlcnBvbGF0aW9uID0gaW50ZXJwb2xhdGlvbjtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0anNvbi50eXBlID0gdHJhY2suVmFsdWVUeXBlTmFtZTsgLy8gbWFuZGF0b3J5XG5cblx0XHRyZXR1cm4ganNvbjtcblxuXHR9XG5cblx0SW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kRGlzY3JldGUoIHJlc3VsdCApIHtcblxuXHRcdHJldHVybiBuZXcgRGlzY3JldGVJbnRlcnBvbGFudCggdGhpcy50aW1lcywgdGhpcy52YWx1ZXMsIHRoaXMuZ2V0VmFsdWVTaXplKCksIHJlc3VsdCApO1xuXG5cdH1cblxuXHRJbnRlcnBvbGFudEZhY3RvcnlNZXRob2RMaW5lYXIoIHJlc3VsdCApIHtcblxuXHRcdHJldHVybiBuZXcgTGluZWFySW50ZXJwb2xhbnQoIHRoaXMudGltZXMsIHRoaXMudmFsdWVzLCB0aGlzLmdldFZhbHVlU2l6ZSgpLCByZXN1bHQgKTtcblxuXHR9XG5cblx0SW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kU21vb3RoKCByZXN1bHQgKSB7XG5cblx0XHRyZXR1cm4gbmV3IEN1YmljSW50ZXJwb2xhbnQoIHRoaXMudGltZXMsIHRoaXMudmFsdWVzLCB0aGlzLmdldFZhbHVlU2l6ZSgpLCByZXN1bHQgKTtcblxuXHR9XG5cblx0c2V0SW50ZXJwb2xhdGlvbiggaW50ZXJwb2xhdGlvbiApIHtcblxuXHRcdGxldCBmYWN0b3J5TWV0aG9kO1xuXG5cdFx0c3dpdGNoICggaW50ZXJwb2xhdGlvbiApIHtcblxuXHRcdFx0Y2FzZSBJbnRlcnBvbGF0ZURpc2NyZXRlOlxuXG5cdFx0XHRcdGZhY3RvcnlNZXRob2QgPSB0aGlzLkludGVycG9sYW50RmFjdG9yeU1ldGhvZERpc2NyZXRlO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlIEludGVycG9sYXRlTGluZWFyOlxuXG5cdFx0XHRcdGZhY3RvcnlNZXRob2QgPSB0aGlzLkludGVycG9sYW50RmFjdG9yeU1ldGhvZExpbmVhcjtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSBJbnRlcnBvbGF0ZVNtb290aDpcblxuXHRcdFx0XHRmYWN0b3J5TWV0aG9kID0gdGhpcy5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RTbW9vdGg7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHR9XG5cblx0XHRpZiAoIGZhY3RvcnlNZXRob2QgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3QgbWVzc2FnZSA9ICd1bnN1cHBvcnRlZCBpbnRlcnBvbGF0aW9uIGZvciAnICtcblx0XHRcdFx0dGhpcy5WYWx1ZVR5cGVOYW1lICsgJyBrZXlmcmFtZSB0cmFjayBuYW1lZCAnICsgdGhpcy5uYW1lO1xuXG5cdFx0XHRpZiAoIHRoaXMuY3JlYXRlSW50ZXJwb2xhbnQgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHQvLyBmYWxsIGJhY2sgdG8gZGVmYXVsdCwgdW5sZXNzIHRoZSBkZWZhdWx0IGl0c2VsZiBpcyBtZXNzZWQgdXBcblx0XHRcdFx0aWYgKCBpbnRlcnBvbGF0aW9uICE9PSB0aGlzLkRlZmF1bHRJbnRlcnBvbGF0aW9uICkge1xuXG5cdFx0XHRcdFx0dGhpcy5zZXRJbnRlcnBvbGF0aW9uKCB0aGlzLkRlZmF1bHRJbnRlcnBvbGF0aW9uICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHRocm93IG5ldyBFcnJvciggbWVzc2FnZSApOyAvLyBmYXRhbCwgaW4gdGhpcyBjYXNlXG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLktleWZyYW1lVHJhY2s6JywgbWVzc2FnZSApO1xuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHR9XG5cblx0XHR0aGlzLmNyZWF0ZUludGVycG9sYW50ID0gZmFjdG9yeU1ldGhvZDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRJbnRlcnBvbGF0aW9uKCkge1xuXG5cdFx0c3dpdGNoICggdGhpcy5jcmVhdGVJbnRlcnBvbGFudCApIHtcblxuXHRcdFx0Y2FzZSB0aGlzLkludGVycG9sYW50RmFjdG9yeU1ldGhvZERpc2NyZXRlOlxuXG5cdFx0XHRcdHJldHVybiBJbnRlcnBvbGF0ZURpc2NyZXRlO1xuXG5cdFx0XHRjYXNlIHRoaXMuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kTGluZWFyOlxuXG5cdFx0XHRcdHJldHVybiBJbnRlcnBvbGF0ZUxpbmVhcjtcblxuXHRcdFx0Y2FzZSB0aGlzLkludGVycG9sYW50RmFjdG9yeU1ldGhvZFNtb290aDpcblxuXHRcdFx0XHRyZXR1cm4gSW50ZXJwb2xhdGVTbW9vdGg7XG5cblx0XHR9XG5cblx0fVxuXG5cdGdldFZhbHVlU2l6ZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLnZhbHVlcy5sZW5ndGggLyB0aGlzLnRpbWVzLmxlbmd0aDtcblxuXHR9XG5cblx0Ly8gbW92ZSBhbGwga2V5ZnJhbWVzIGVpdGhlciBmb3J3YXJkcyBvciBiYWNrd2FyZHMgaW4gdGltZVxuXHRzaGlmdCggdGltZU9mZnNldCApIHtcblxuXHRcdGlmICggdGltZU9mZnNldCAhPT0gMC4wICkge1xuXG5cdFx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXM7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbiA9IHRpbWVzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0XHR0aW1lc1sgaSBdICs9IHRpbWVPZmZzZXQ7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvLyBzY2FsZSBhbGwga2V5ZnJhbWUgdGltZXMgYnkgYSBmYWN0b3IgKHVzZWZ1bCBmb3IgZnJhbWUgPC0+IHNlY29uZHMgY29udmVyc2lvbnMpXG5cdHNjYWxlKCB0aW1lU2NhbGUgKSB7XG5cblx0XHRpZiAoIHRpbWVTY2FsZSAhPT0gMS4wICkge1xuXG5cdFx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXM7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbiA9IHRpbWVzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0XHR0aW1lc1sgaSBdICo9IHRpbWVTY2FsZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIHJlbW92ZXMga2V5ZnJhbWVzIGJlZm9yZSBhbmQgYWZ0ZXIgYW5pbWF0aW9uIHdpdGhvdXQgY2hhbmdpbmcgYW55IHZhbHVlcyB3aXRoaW4gdGhlIHJhbmdlIFtzdGFydFRpbWUsIGVuZFRpbWVdLlxuXHQvLyBJTVBPUlRBTlQ6IFdlIGRvIG5vdCBzaGlmdCBhcm91bmQga2V5cyB0byB0aGUgc3RhcnQgb2YgdGhlIHRyYWNrIHRpbWUsIGJlY2F1c2UgZm9yIGludGVycG9sYXRlZCBrZXlzIHRoaXMgd2lsbCBjaGFuZ2UgdGhlaXIgdmFsdWVzXG5cdHRyaW0oIHN0YXJ0VGltZSwgZW5kVGltZSApIHtcblxuXHRcdGNvbnN0IHRpbWVzID0gdGhpcy50aW1lcyxcblx0XHRcdG5LZXlzID0gdGltZXMubGVuZ3RoO1xuXG5cdFx0bGV0IGZyb20gPSAwLFxuXHRcdFx0dG8gPSBuS2V5cyAtIDE7XG5cblx0XHR3aGlsZSAoIGZyb20gIT09IG5LZXlzICYmIHRpbWVzWyBmcm9tIF0gPCBzdGFydFRpbWUgKSB7XG5cblx0XHRcdCsrIGZyb207XG5cblx0XHR9XG5cblx0XHR3aGlsZSAoIHRvICE9PSAtIDEgJiYgdGltZXNbIHRvIF0gPiBlbmRUaW1lICkge1xuXG5cdFx0XHQtLSB0bztcblxuXHRcdH1cblxuXHRcdCsrIHRvOyAvLyBpbmNsdXNpdmUgLT4gZXhjbHVzaXZlIGJvdW5kXG5cblx0XHRpZiAoIGZyb20gIT09IDAgfHwgdG8gIT09IG5LZXlzICkge1xuXG5cdFx0XHQvLyBlbXB0eSB0cmFja3MgYXJlIGZvcmJpZGRlbiwgc28ga2VlcCBhdCBsZWFzdCBvbmUga2V5ZnJhbWVcblx0XHRcdGlmICggZnJvbSA+PSB0byApIHtcblxuXHRcdFx0XHR0byA9IE1hdGgubWF4KCB0bywgMSApO1xuXHRcdFx0XHRmcm9tID0gdG8gLSAxO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHN0cmlkZSA9IHRoaXMuZ2V0VmFsdWVTaXplKCk7XG5cdFx0XHR0aGlzLnRpbWVzID0gdGltZXMuc2xpY2UoIGZyb20sIHRvICk7XG5cdFx0XHR0aGlzLnZhbHVlcyA9IHRoaXMudmFsdWVzLnNsaWNlKCBmcm9tICogc3RyaWRlLCB0byAqIHN0cmlkZSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIGVuc3VyZSB3ZSBkbyBub3QgZ2V0IGEgR2FyYmFnZUluR2FyYmFnZU91dCBzaXR1YXRpb24sIG1ha2Ugc3VyZSB0cmFja3MgYXJlIGF0IGxlYXN0IG1pbmltYWxseSB2aWFibGVcblx0dmFsaWRhdGUoKSB7XG5cblx0XHRsZXQgdmFsaWQgPSB0cnVlO1xuXG5cdFx0Y29uc3QgdmFsdWVTaXplID0gdGhpcy5nZXRWYWx1ZVNpemUoKTtcblx0XHRpZiAoIHZhbHVlU2l6ZSAtIE1hdGguZmxvb3IoIHZhbHVlU2l6ZSApICE9PSAwICkge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuS2V5ZnJhbWVUcmFjazogSW52YWxpZCB2YWx1ZSBzaXplIGluIHRyYWNrLicsIHRoaXMgKTtcblx0XHRcdHZhbGlkID0gZmFsc2U7XG5cblx0XHR9XG5cblx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXMsXG5cdFx0XHR2YWx1ZXMgPSB0aGlzLnZhbHVlcyxcblxuXHRcdFx0bktleXMgPSB0aW1lcy5sZW5ndGg7XG5cblx0XHRpZiAoIG5LZXlzID09PSAwICkge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuS2V5ZnJhbWVUcmFjazogVHJhY2sgaXMgZW1wdHkuJywgdGhpcyApO1xuXHRcdFx0dmFsaWQgPSBmYWxzZTtcblxuXHRcdH1cblxuXHRcdGxldCBwcmV2VGltZSA9IG51bGw7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IG5LZXlzOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBjdXJyVGltZSA9IHRpbWVzWyBpIF07XG5cblx0XHRcdGlmICggdHlwZW9mIGN1cnJUaW1lID09PSAnbnVtYmVyJyAmJiBpc05hTiggY3VyclRpbWUgKSApIHtcblxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuS2V5ZnJhbWVUcmFjazogVGltZSBpcyBub3QgYSB2YWxpZCBudW1iZXIuJywgdGhpcywgaSwgY3VyclRpbWUgKTtcblx0XHRcdFx0dmFsaWQgPSBmYWxzZTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBwcmV2VGltZSAhPT0gbnVsbCAmJiBwcmV2VGltZSA+IGN1cnJUaW1lICkge1xuXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiBPdXQgb2Ygb3JkZXIga2V5cy4nLCB0aGlzLCBpLCBjdXJyVGltZSwgcHJldlRpbWUgKTtcblx0XHRcdFx0dmFsaWQgPSBmYWxzZTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdH1cblxuXHRcdFx0cHJldlRpbWUgPSBjdXJyVGltZTtcblxuXHRcdH1cblxuXHRcdGlmICggdmFsdWVzICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGlmICggaXNUeXBlZEFycmF5KCB2YWx1ZXMgKSApIHtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSB2YWx1ZXMubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgdmFsdWUgPSB2YWx1ZXNbIGkgXTtcblxuXHRcdFx0XHRcdGlmICggaXNOYU4oIHZhbHVlICkgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5LZXlmcmFtZVRyYWNrOiBWYWx1ZSBpcyBub3QgYSB2YWxpZCBudW1iZXIuJywgdGhpcywgaSwgdmFsdWUgKTtcblx0XHRcdFx0XHRcdHZhbGlkID0gZmFsc2U7XG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB2YWxpZDtcblxuXHR9XG5cblx0Ly8gcmVtb3ZlcyBlcXVpdmFsZW50IHNlcXVlbnRpYWwga2V5cyBhcyBjb21tb24gaW4gbW9ycGggdGFyZ2V0IHNlcXVlbmNlc1xuXHQvLyAoMCwwLDAsMCwxLDEsMSwwLDAsMCwwLDAsMCwwKSAtLT4gKDAsMCwxLDEsMCwwKVxuXHRvcHRpbWl6ZSgpIHtcblxuXHRcdC8vIHRpbWVzIG9yIHZhbHVlcyBtYXkgYmUgc2hhcmVkIHdpdGggb3RoZXIgdHJhY2tzLCBzbyBvdmVyd3JpdGluZyBpcyB1bnNhZmVcblx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXMuc2xpY2UoKSxcblx0XHRcdHZhbHVlcyA9IHRoaXMudmFsdWVzLnNsaWNlKCksXG5cdFx0XHRzdHJpZGUgPSB0aGlzLmdldFZhbHVlU2l6ZSgpLFxuXG5cdFx0XHRzbW9vdGhJbnRlcnBvbGF0aW9uID0gdGhpcy5nZXRJbnRlcnBvbGF0aW9uKCkgPT09IEludGVycG9sYXRlU21vb3RoLFxuXG5cdFx0XHRsYXN0SW5kZXggPSB0aW1lcy5sZW5ndGggLSAxO1xuXG5cdFx0bGV0IHdyaXRlSW5kZXggPSAxO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAxOyBpIDwgbGFzdEluZGV4OyArKyBpICkge1xuXG5cdFx0XHRsZXQga2VlcCA9IGZhbHNlO1xuXG5cdFx0XHRjb25zdCB0aW1lID0gdGltZXNbIGkgXTtcblx0XHRcdGNvbnN0IHRpbWVOZXh0ID0gdGltZXNbIGkgKyAxIF07XG5cblx0XHRcdC8vIHJlbW92ZSBhZGphY2VudCBrZXlmcmFtZXMgc2NoZWR1bGVkIGF0IHRoZSBzYW1lIHRpbWVcblxuXHRcdFx0aWYgKCB0aW1lICE9PSB0aW1lTmV4dCAmJiAoIGkgIT09IDEgfHwgdGltZSAhPT0gdGltZXNbIDAgXSApICkge1xuXG5cdFx0XHRcdGlmICggISBzbW9vdGhJbnRlcnBvbGF0aW9uICkge1xuXG5cdFx0XHRcdFx0Ly8gcmVtb3ZlIHVubmVjZXNzYXJ5IGtleWZyYW1lcyBzYW1lIGFzIHRoZWlyIG5laWdoYm9yc1xuXG5cdFx0XHRcdFx0Y29uc3Qgb2Zmc2V0ID0gaSAqIHN0cmlkZSxcblx0XHRcdFx0XHRcdG9mZnNldFAgPSBvZmZzZXQgLSBzdHJpZGUsXG5cdFx0XHRcdFx0XHRvZmZzZXROID0gb2Zmc2V0ICsgc3RyaWRlO1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqICE9PSBzdHJpZGU7ICsrIGogKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IHZhbHVlID0gdmFsdWVzWyBvZmZzZXQgKyBqIF07XG5cblx0XHRcdFx0XHRcdGlmICggdmFsdWUgIT09IHZhbHVlc1sgb2Zmc2V0UCArIGogXSB8fFxuXHRcdFx0XHRcdFx0XHR2YWx1ZSAhPT0gdmFsdWVzWyBvZmZzZXROICsgaiBdICkge1xuXG5cdFx0XHRcdFx0XHRcdGtlZXAgPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRrZWVwID0gdHJ1ZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gaW4tcGxhY2UgY29tcGFjdGlvblxuXG5cdFx0XHRpZiAoIGtlZXAgKSB7XG5cblx0XHRcdFx0aWYgKCBpICE9PSB3cml0ZUluZGV4ICkge1xuXG5cdFx0XHRcdFx0dGltZXNbIHdyaXRlSW5kZXggXSA9IHRpbWVzWyBpIF07XG5cblx0XHRcdFx0XHRjb25zdCByZWFkT2Zmc2V0ID0gaSAqIHN0cmlkZSxcblx0XHRcdFx0XHRcdHdyaXRlT2Zmc2V0ID0gd3JpdGVJbmRleCAqIHN0cmlkZTtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiAhPT0gc3RyaWRlOyArKyBqICkge1xuXG5cdFx0XHRcdFx0XHR2YWx1ZXNbIHdyaXRlT2Zmc2V0ICsgaiBdID0gdmFsdWVzWyByZWFkT2Zmc2V0ICsgaiBdO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHQrKyB3cml0ZUluZGV4O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBmbHVzaCBsYXN0IGtleWZyYW1lIChjb21wYWN0aW9uIGxvb2tzIGFoZWFkKVxuXG5cdFx0aWYgKCBsYXN0SW5kZXggPiAwICkge1xuXG5cdFx0XHR0aW1lc1sgd3JpdGVJbmRleCBdID0gdGltZXNbIGxhc3RJbmRleCBdO1xuXG5cdFx0XHRmb3IgKCBsZXQgcmVhZE9mZnNldCA9IGxhc3RJbmRleCAqIHN0cmlkZSwgd3JpdGVPZmZzZXQgPSB3cml0ZUluZGV4ICogc3RyaWRlLCBqID0gMDsgaiAhPT0gc3RyaWRlOyArKyBqICkge1xuXG5cdFx0XHRcdHZhbHVlc1sgd3JpdGVPZmZzZXQgKyBqIF0gPSB2YWx1ZXNbIHJlYWRPZmZzZXQgKyBqIF07XG5cblx0XHRcdH1cblxuXHRcdFx0Kysgd3JpdGVJbmRleDtcblxuXHRcdH1cblxuXHRcdGlmICggd3JpdGVJbmRleCAhPT0gdGltZXMubGVuZ3RoICkge1xuXG5cdFx0XHR0aGlzLnRpbWVzID0gdGltZXMuc2xpY2UoIDAsIHdyaXRlSW5kZXggKTtcblx0XHRcdHRoaXMudmFsdWVzID0gdmFsdWVzLnNsaWNlKCAwLCB3cml0ZUluZGV4ICogc3RyaWRlICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLnRpbWVzID0gdGltZXM7XG5cdFx0XHR0aGlzLnZhbHVlcyA9IHZhbHVlcztcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdGNvbnN0IHRpbWVzID0gdGhpcy50aW1lcy5zbGljZSgpO1xuXHRcdGNvbnN0IHZhbHVlcyA9IHRoaXMudmFsdWVzLnNsaWNlKCk7XG5cblx0XHRjb25zdCBUeXBlZEtleWZyYW1lVHJhY2sgPSB0aGlzLmNvbnN0cnVjdG9yO1xuXHRcdGNvbnN0IHRyYWNrID0gbmV3IFR5cGVkS2V5ZnJhbWVUcmFjayggdGhpcy5uYW1lLCB0aW1lcywgdmFsdWVzICk7XG5cblx0XHQvLyBJbnRlcnBvbGFudCBhcmd1bWVudCB0byBjb25zdHJ1Y3RvciBpcyBub3Qgc2F2ZWQsIHNvIGNvcHkgdGhlIGZhY3RvcnkgbWV0aG9kIGRpcmVjdGx5LlxuXHRcdHRyYWNrLmNyZWF0ZUludGVycG9sYW50ID0gdGhpcy5jcmVhdGVJbnRlcnBvbGFudDtcblxuXHRcdHJldHVybiB0cmFjaztcblxuXHR9XG5cbn1cblxuS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuVGltZUJ1ZmZlclR5cGUgPSBGbG9hdDMyQXJyYXk7XG5LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZUJ1ZmZlclR5cGUgPSBGbG9hdDMyQXJyYXk7XG5LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5EZWZhdWx0SW50ZXJwb2xhdGlvbiA9IEludGVycG9sYXRlTGluZWFyO1xuXG4vKipcbiAqIEEgVHJhY2sgb2YgQm9vbGVhbiBrZXlmcmFtZSB2YWx1ZXMuXG4gKi9cbmNsYXNzIEJvb2xlYW5LZXlmcmFtZVRyYWNrIGV4dGVuZHMgS2V5ZnJhbWVUcmFjayB7XG5cblx0Ly8gTm8gaW50ZXJwb2xhdGlvbiBwYXJhbWV0ZXIgYmVjYXVzZSBvbmx5IEludGVycG9sYXRlRGlzY3JldGUgaXMgdmFsaWQuXG5cdGNvbnN0cnVjdG9yKCBuYW1lLCB0aW1lcywgdmFsdWVzICkge1xuXG5cdFx0c3VwZXIoIG5hbWUsIHRpbWVzLCB2YWx1ZXMgKTtcblxuXHR9XG5cbn1cblxuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlVHlwZU5hbWUgPSAnYm9vbCc7XG5Cb29sZWFuS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuVmFsdWVCdWZmZXJUeXBlID0gQXJyYXk7XG5Cb29sZWFuS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuRGVmYXVsdEludGVycG9sYXRpb24gPSBJbnRlcnBvbGF0ZURpc2NyZXRlO1xuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkludGVycG9sYW50RmFjdG9yeU1ldGhvZExpbmVhciA9IHVuZGVmaW5lZDtcbkJvb2xlYW5LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RTbW9vdGggPSB1bmRlZmluZWQ7XG5cbi8qKlxuICogQSBUcmFjayBvZiBrZXlmcmFtZSB2YWx1ZXMgdGhhdCByZXByZXNlbnQgY29sb3IuXG4gKi9cbmNsYXNzIENvbG9yS2V5ZnJhbWVUcmFjayBleHRlbmRzIEtleWZyYW1lVHJhY2sge31cblxuQ29sb3JLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZVR5cGVOYW1lID0gJ2NvbG9yJztcblxuLyoqXG4gKiBBIFRyYWNrIG9mIG51bWVyaWMga2V5ZnJhbWUgdmFsdWVzLlxuICovXG5jbGFzcyBOdW1iZXJLZXlmcmFtZVRyYWNrIGV4dGVuZHMgS2V5ZnJhbWVUcmFjayB7fVxuXG5OdW1iZXJLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZVR5cGVOYW1lID0gJ251bWJlcic7XG5cbi8qKlxuICogU3BoZXJpY2FsIGxpbmVhciB1bml0IHF1YXRlcm5pb24gaW50ZXJwb2xhbnQuXG4gKi9cblxuY2xhc3MgUXVhdGVybmlvbkxpbmVhckludGVycG9sYW50IGV4dGVuZHMgSW50ZXJwb2xhbnQge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICkge1xuXG5cdFx0c3VwZXIoIHBhcmFtZXRlclBvc2l0aW9ucywgc2FtcGxlVmFsdWVzLCBzYW1wbGVTaXplLCByZXN1bHRCdWZmZXIgKTtcblxuXHR9XG5cblx0aW50ZXJwb2xhdGVfKCBpMSwgdDAsIHQsIHQxICkge1xuXG5cdFx0Y29uc3QgcmVzdWx0ID0gdGhpcy5yZXN1bHRCdWZmZXIsXG5cdFx0XHR2YWx1ZXMgPSB0aGlzLnNhbXBsZVZhbHVlcyxcblx0XHRcdHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxuXG5cdFx0XHRhbHBoYSA9ICggdCAtIHQwICkgLyAoIHQxIC0gdDAgKTtcblxuXHRcdGxldCBvZmZzZXQgPSBpMSAqIHN0cmlkZTtcblxuXHRcdGZvciAoIGxldCBlbmQgPSBvZmZzZXQgKyBzdHJpZGU7IG9mZnNldCAhPT0gZW5kOyBvZmZzZXQgKz0gNCApIHtcblxuXHRcdFx0UXVhdGVybmlvbi5zbGVycEZsYXQoIHJlc3VsdCwgMCwgdmFsdWVzLCBvZmZzZXQgLSBzdHJpZGUsIHZhbHVlcywgb2Zmc2V0LCBhbHBoYSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJlc3VsdDtcblxuXHR9XG5cbn1cblxuLyoqXG4gKiBBIFRyYWNrIG9mIHF1YXRlcm5pb24ga2V5ZnJhbWUgdmFsdWVzLlxuICovXG5jbGFzcyBRdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjayBleHRlbmRzIEtleWZyYW1lVHJhY2sge1xuXG5cdEludGVycG9sYW50RmFjdG9yeU1ldGhvZExpbmVhciggcmVzdWx0ICkge1xuXG5cdFx0cmV0dXJuIG5ldyBRdWF0ZXJuaW9uTGluZWFySW50ZXJwb2xhbnQoIHRoaXMudGltZXMsIHRoaXMudmFsdWVzLCB0aGlzLmdldFZhbHVlU2l6ZSgpLCByZXN1bHQgKTtcblxuXHR9XG5cbn1cblxuUXVhdGVybmlvbktleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlVHlwZU5hbWUgPSAncXVhdGVybmlvbic7XG4vLyBWYWx1ZUJ1ZmZlclR5cGUgaXMgaW5oZXJpdGVkXG4vLyBEZWZhdWx0SW50ZXJwb2xhdGlvbiBpcyBpbmhlcml0ZWQ7XG5RdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kU21vb3RoID0gdW5kZWZpbmVkO1xuXG4vKipcbiAqIEEgVHJhY2sgdGhhdCBpbnRlcnBvbGF0ZXMgU3RyaW5nc1xuICovXG5jbGFzcyBTdHJpbmdLZXlmcmFtZVRyYWNrIGV4dGVuZHMgS2V5ZnJhbWVUcmFjayB7XG5cblx0Ly8gTm8gaW50ZXJwb2xhdGlvbiBwYXJhbWV0ZXIgYmVjYXVzZSBvbmx5IEludGVycG9sYXRlRGlzY3JldGUgaXMgdmFsaWQuXG5cdGNvbnN0cnVjdG9yKCBuYW1lLCB0aW1lcywgdmFsdWVzICkge1xuXG5cdFx0c3VwZXIoIG5hbWUsIHRpbWVzLCB2YWx1ZXMgKTtcblxuXHR9XG5cbn1cblxuU3RyaW5nS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuVmFsdWVUeXBlTmFtZSA9ICdzdHJpbmcnO1xuU3RyaW5nS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuVmFsdWVCdWZmZXJUeXBlID0gQXJyYXk7XG5TdHJpbmdLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5EZWZhdWx0SW50ZXJwb2xhdGlvbiA9IEludGVycG9sYXRlRGlzY3JldGU7XG5TdHJpbmdLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RMaW5lYXIgPSB1bmRlZmluZWQ7XG5TdHJpbmdLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RTbW9vdGggPSB1bmRlZmluZWQ7XG5cbi8qKlxuICogQSBUcmFjayBvZiB2ZWN0b3JlZCBrZXlmcmFtZSB2YWx1ZXMuXG4gKi9cbmNsYXNzIFZlY3RvcktleWZyYW1lVHJhY2sgZXh0ZW5kcyBLZXlmcmFtZVRyYWNrIHt9XG5cblZlY3RvcktleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlVHlwZU5hbWUgPSAndmVjdG9yJztcblxuY2xhc3MgQW5pbWF0aW9uQ2xpcCB7XG5cblx0Y29uc3RydWN0b3IoIG5hbWUgPSAnJywgZHVyYXRpb24gPSAtIDEsIHRyYWNrcyA9IFtdLCBibGVuZE1vZGUgPSBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGUgKSB7XG5cblx0XHR0aGlzLm5hbWUgPSBuYW1lO1xuXHRcdHRoaXMudHJhY2tzID0gdHJhY2tzO1xuXHRcdHRoaXMuZHVyYXRpb24gPSBkdXJhdGlvbjtcblx0XHR0aGlzLmJsZW5kTW9kZSA9IGJsZW5kTW9kZTtcblxuXHRcdHRoaXMudXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0Ly8gdGhpcyBtZWFucyBpdCBzaG91bGQgZmlndXJlIG91dCBpdHMgZHVyYXRpb24gYnkgc2Nhbm5pbmcgdGhlIHRyYWNrc1xuXHRcdGlmICggdGhpcy5kdXJhdGlvbiA8IDAgKSB7XG5cblx0XHRcdHRoaXMucmVzZXREdXJhdGlvbigpO1xuXG5cdFx0fVxuXG5cdH1cblxuXG5cdHN0YXRpYyBwYXJzZSgganNvbiApIHtcblxuXHRcdGNvbnN0IHRyYWNrcyA9IFtdLFxuXHRcdFx0anNvblRyYWNrcyA9IGpzb24udHJhY2tzLFxuXHRcdFx0ZnJhbWVUaW1lID0gMS4wIC8gKCBqc29uLmZwcyB8fCAxLjAgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGpzb25UcmFja3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHR0cmFja3MucHVzaCggcGFyc2VLZXlmcmFtZVRyYWNrKCBqc29uVHJhY2tzWyBpIF0gKS5zY2FsZSggZnJhbWVUaW1lICkgKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGNsaXAgPSBuZXcgdGhpcygganNvbi5uYW1lLCBqc29uLmR1cmF0aW9uLCB0cmFja3MsIGpzb24uYmxlbmRNb2RlICk7XG5cdFx0Y2xpcC51dWlkID0ganNvbi51dWlkO1xuXG5cdFx0cmV0dXJuIGNsaXA7XG5cblx0fVxuXG5cdHN0YXRpYyB0b0pTT04oIGNsaXAgKSB7XG5cblx0XHRjb25zdCB0cmFja3MgPSBbXSxcblx0XHRcdGNsaXBUcmFja3MgPSBjbGlwLnRyYWNrcztcblxuXHRcdGNvbnN0IGpzb24gPSB7XG5cblx0XHRcdCduYW1lJzogY2xpcC5uYW1lLFxuXHRcdFx0J2R1cmF0aW9uJzogY2xpcC5kdXJhdGlvbixcblx0XHRcdCd0cmFja3MnOiB0cmFja3MsXG5cdFx0XHQndXVpZCc6IGNsaXAudXVpZCxcblx0XHRcdCdibGVuZE1vZGUnOiBjbGlwLmJsZW5kTW9kZVxuXG5cdFx0fTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGNsaXBUcmFja3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHR0cmFja3MucHVzaCggS2V5ZnJhbWVUcmFjay50b0pTT04oIGNsaXBUcmFja3NbIGkgXSApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4ganNvbjtcblxuXHR9XG5cblx0c3RhdGljIENyZWF0ZUZyb21Nb3JwaFRhcmdldFNlcXVlbmNlKCBuYW1lLCBtb3JwaFRhcmdldFNlcXVlbmNlLCBmcHMsIG5vTG9vcCApIHtcblxuXHRcdGNvbnN0IG51bU1vcnBoVGFyZ2V0cyA9IG1vcnBoVGFyZ2V0U2VxdWVuY2UubGVuZ3RoO1xuXHRcdGNvbnN0IHRyYWNrcyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbnVtTW9ycGhUYXJnZXRzOyBpICsrICkge1xuXG5cdFx0XHRsZXQgdGltZXMgPSBbXTtcblx0XHRcdGxldCB2YWx1ZXMgPSBbXTtcblxuXHRcdFx0dGltZXMucHVzaChcblx0XHRcdFx0KCBpICsgbnVtTW9ycGhUYXJnZXRzIC0gMSApICUgbnVtTW9ycGhUYXJnZXRzLFxuXHRcdFx0XHRpLFxuXHRcdFx0XHQoIGkgKyAxICkgJSBudW1Nb3JwaFRhcmdldHMgKTtcblxuXHRcdFx0dmFsdWVzLnB1c2goIDAsIDEsIDAgKTtcblxuXHRcdFx0Y29uc3Qgb3JkZXIgPSBnZXRLZXlmcmFtZU9yZGVyKCB0aW1lcyApO1xuXHRcdFx0dGltZXMgPSBzb3J0ZWRBcnJheSggdGltZXMsIDEsIG9yZGVyICk7XG5cdFx0XHR2YWx1ZXMgPSBzb3J0ZWRBcnJheSggdmFsdWVzLCAxLCBvcmRlciApO1xuXG5cdFx0XHQvLyBpZiB0aGVyZSBpcyBhIGtleSBhdCB0aGUgZmlyc3QgZnJhbWUsIGR1cGxpY2F0ZSBpdCBhcyB0aGVcblx0XHRcdC8vIGxhc3QgZnJhbWUgYXMgd2VsbCBmb3IgcGVyZmVjdCBsb29wLlxuXHRcdFx0aWYgKCAhIG5vTG9vcCAmJiB0aW1lc1sgMCBdID09PSAwICkge1xuXG5cdFx0XHRcdHRpbWVzLnB1c2goIG51bU1vcnBoVGFyZ2V0cyApO1xuXHRcdFx0XHR2YWx1ZXMucHVzaCggdmFsdWVzWyAwIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHR0cmFja3MucHVzaChcblx0XHRcdFx0bmV3IE51bWJlcktleWZyYW1lVHJhY2soXG5cdFx0XHRcdFx0Jy5tb3JwaFRhcmdldEluZmx1ZW5jZXNbJyArIG1vcnBoVGFyZ2V0U2VxdWVuY2VbIGkgXS5uYW1lICsgJ10nLFxuXHRcdFx0XHRcdHRpbWVzLCB2YWx1ZXNcblx0XHRcdFx0KS5zY2FsZSggMS4wIC8gZnBzICkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBuZXcgdGhpcyggbmFtZSwgLSAxLCB0cmFja3MgKTtcblxuXHR9XG5cblx0c3RhdGljIGZpbmRCeU5hbWUoIG9iamVjdE9yQ2xpcEFycmF5LCBuYW1lICkge1xuXG5cdFx0bGV0IGNsaXBBcnJheSA9IG9iamVjdE9yQ2xpcEFycmF5O1xuXG5cdFx0aWYgKCAhIEFycmF5LmlzQXJyYXkoIG9iamVjdE9yQ2xpcEFycmF5ICkgKSB7XG5cblx0XHRcdGNvbnN0IG8gPSBvYmplY3RPckNsaXBBcnJheTtcblx0XHRcdGNsaXBBcnJheSA9IG8uZ2VvbWV0cnkgJiYgby5nZW9tZXRyeS5hbmltYXRpb25zIHx8IG8uYW5pbWF0aW9ucztcblxuXHRcdH1cblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNsaXBBcnJheS5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdGlmICggY2xpcEFycmF5WyBpIF0ubmFtZSA9PT0gbmFtZSApIHtcblxuXHRcdFx0XHRyZXR1cm4gY2xpcEFycmF5WyBpIF07XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiBudWxsO1xuXG5cdH1cblxuXHRzdGF0aWMgQ3JlYXRlQ2xpcHNGcm9tTW9ycGhUYXJnZXRTZXF1ZW5jZXMoIG1vcnBoVGFyZ2V0cywgZnBzLCBub0xvb3AgKSB7XG5cblx0XHRjb25zdCBhbmltYXRpb25Ub01vcnBoVGFyZ2V0cyA9IHt9O1xuXG5cdFx0Ly8gdGVzdGVkIHdpdGggaHR0cHM6Ly9yZWdleDEwMS5jb20vIG9uIHRyaWNrIHNlcXVlbmNlc1xuXHRcdC8vIHN1Y2ggZmxhbWluZ29fZmx5QV8wMDMsIGZsYW1pbmdvX3J1bjFfMDAzLCBjcmRlYXRoMDA1OVxuXHRcdGNvbnN0IHBhdHRlcm4gPSAvXihbXFx3LV0qPykoW1xcZF0rKSQvO1xuXG5cdFx0Ly8gc29ydCBtb3JwaCB0YXJnZXQgbmFtZXMgaW50byBhbmltYXRpb24gZ3JvdXBzIGJhc2VkXG5cdFx0Ly8gcGF0dGVybnMgbGlrZSBXYWxrXzAwMSwgV2Fsa18wMDIsIFJ1bl8wMDEsIFJ1bl8wMDJcblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbW9ycGhUYXJnZXRzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBtb3JwaFRhcmdldCA9IG1vcnBoVGFyZ2V0c1sgaSBdO1xuXHRcdFx0Y29uc3QgcGFydHMgPSBtb3JwaFRhcmdldC5uYW1lLm1hdGNoKCBwYXR0ZXJuICk7XG5cblx0XHRcdGlmICggcGFydHMgJiYgcGFydHMubGVuZ3RoID4gMSApIHtcblxuXHRcdFx0XHRjb25zdCBuYW1lID0gcGFydHNbIDEgXTtcblxuXHRcdFx0XHRsZXQgYW5pbWF0aW9uTW9ycGhUYXJnZXRzID0gYW5pbWF0aW9uVG9Nb3JwaFRhcmdldHNbIG5hbWUgXTtcblxuXHRcdFx0XHRpZiAoICEgYW5pbWF0aW9uTW9ycGhUYXJnZXRzICkge1xuXG5cdFx0XHRcdFx0YW5pbWF0aW9uVG9Nb3JwaFRhcmdldHNbIG5hbWUgXSA9IGFuaW1hdGlvbk1vcnBoVGFyZ2V0cyA9IFtdO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRhbmltYXRpb25Nb3JwaFRhcmdldHMucHVzaCggbW9ycGhUYXJnZXQgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Y29uc3QgY2xpcHMgPSBbXTtcblxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gYW5pbWF0aW9uVG9Nb3JwaFRhcmdldHMgKSB7XG5cblx0XHRcdGNsaXBzLnB1c2goIHRoaXMuQ3JlYXRlRnJvbU1vcnBoVGFyZ2V0U2VxdWVuY2UoIG5hbWUsIGFuaW1hdGlvblRvTW9ycGhUYXJnZXRzWyBuYW1lIF0sIGZwcywgbm9Mb29wICkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBjbGlwcztcblxuXHR9XG5cblx0Ly8gcGFyc2UgdGhlIGFuaW1hdGlvbi5oaWVyYXJjaHkgZm9ybWF0XG5cdHN0YXRpYyBwYXJzZUFuaW1hdGlvbiggYW5pbWF0aW9uLCBib25lcyApIHtcblxuXHRcdGlmICggISBhbmltYXRpb24gKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5BbmltYXRpb25DbGlwOiBObyBhbmltYXRpb24gaW4gSlNPTkxvYWRlciBkYXRhLicgKTtcblx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgYWRkTm9uZW1wdHlUcmFjayA9IGZ1bmN0aW9uICggdHJhY2tUeXBlLCB0cmFja05hbWUsIGFuaW1hdGlvbktleXMsIHByb3BlcnR5TmFtZSwgZGVzdFRyYWNrcyApIHtcblxuXHRcdFx0Ly8gb25seSByZXR1cm4gdHJhY2sgaWYgdGhlcmUgYXJlIGFjdHVhbGx5IGtleXMuXG5cdFx0XHRpZiAoIGFuaW1hdGlvbktleXMubGVuZ3RoICE9PSAwICkge1xuXG5cdFx0XHRcdGNvbnN0IHRpbWVzID0gW107XG5cdFx0XHRcdGNvbnN0IHZhbHVlcyA9IFtdO1xuXG5cdFx0XHRcdGZsYXR0ZW5KU09OKCBhbmltYXRpb25LZXlzLCB0aW1lcywgdmFsdWVzLCBwcm9wZXJ0eU5hbWUgKTtcblxuXHRcdFx0XHQvLyBlbXB0eSBrZXlzIGFyZSBmaWx0ZXJlZCBvdXQsIHNvIGNoZWNrIGFnYWluXG5cdFx0XHRcdGlmICggdGltZXMubGVuZ3RoICE9PSAwICkge1xuXG5cdFx0XHRcdFx0ZGVzdFRyYWNrcy5wdXNoKCBuZXcgdHJhY2tUeXBlKCB0cmFja05hbWUsIHRpbWVzLCB2YWx1ZXMgKSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdGNvbnN0IHRyYWNrcyA9IFtdO1xuXG5cdFx0Y29uc3QgY2xpcE5hbWUgPSBhbmltYXRpb24ubmFtZSB8fCAnZGVmYXVsdCc7XG5cdFx0Y29uc3QgZnBzID0gYW5pbWF0aW9uLmZwcyB8fCAzMDtcblx0XHRjb25zdCBibGVuZE1vZGUgPSBhbmltYXRpb24uYmxlbmRNb2RlO1xuXG5cdFx0Ly8gYXV0b21hdGljIGxlbmd0aCBkZXRlcm1pbmF0aW9uIGluIEFuaW1hdGlvbkNsaXAuXG5cdFx0bGV0IGR1cmF0aW9uID0gYW5pbWF0aW9uLmxlbmd0aCB8fCAtIDE7XG5cblx0XHRjb25zdCBoaWVyYXJjaHlUcmFja3MgPSBhbmltYXRpb24uaGllcmFyY2h5IHx8IFtdO1xuXG5cdFx0Zm9yICggbGV0IGggPSAwOyBoIDwgaGllcmFyY2h5VHJhY2tzLmxlbmd0aDsgaCArKyApIHtcblxuXHRcdFx0Y29uc3QgYW5pbWF0aW9uS2V5cyA9IGhpZXJhcmNoeVRyYWNrc1sgaCBdLmtleXM7XG5cblx0XHRcdC8vIHNraXAgZW1wdHkgdHJhY2tzXG5cdFx0XHRpZiAoICEgYW5pbWF0aW9uS2V5cyB8fCBhbmltYXRpb25LZXlzLmxlbmd0aCA9PT0gMCApIGNvbnRpbnVlO1xuXG5cdFx0XHQvLyBwcm9jZXNzIG1vcnBoIHRhcmdldHNcblx0XHRcdGlmICggYW5pbWF0aW9uS2V5c1sgMCBdLm1vcnBoVGFyZ2V0cyApIHtcblxuXHRcdFx0XHQvLyBmaWd1cmUgb3V0IGFsbCBtb3JwaCB0YXJnZXRzIHVzZWQgaW4gdGhpcyB0cmFja1xuXHRcdFx0XHRjb25zdCBtb3JwaFRhcmdldE5hbWVzID0ge307XG5cblx0XHRcdFx0bGV0IGs7XG5cblx0XHRcdFx0Zm9yICggayA9IDA7IGsgPCBhbmltYXRpb25LZXlzLmxlbmd0aDsgayArKyApIHtcblxuXHRcdFx0XHRcdGlmICggYW5pbWF0aW9uS2V5c1sgayBdLm1vcnBoVGFyZ2V0cyApIHtcblxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IG0gPSAwOyBtIDwgYW5pbWF0aW9uS2V5c1sgayBdLm1vcnBoVGFyZ2V0cy5sZW5ndGg7IG0gKysgKSB7XG5cblx0XHRcdFx0XHRcdFx0bW9ycGhUYXJnZXROYW1lc1sgYW5pbWF0aW9uS2V5c1sgayBdLm1vcnBoVGFyZ2V0c1sgbSBdIF0gPSAtIDE7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gY3JlYXRlIGEgdHJhY2sgZm9yIGVhY2ggbW9ycGggdGFyZ2V0IHdpdGggYWxsIHplcm9cblx0XHRcdFx0Ly8gbW9ycGhUYXJnZXRJbmZsdWVuY2VzIGV4Y2VwdCBmb3IgdGhlIGtleXMgaW4gd2hpY2hcblx0XHRcdFx0Ly8gdGhlIG1vcnBoVGFyZ2V0IGlzIG5hbWVkLlxuXHRcdFx0XHRmb3IgKCBjb25zdCBtb3JwaFRhcmdldE5hbWUgaW4gbW9ycGhUYXJnZXROYW1lcyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IHRpbWVzID0gW107XG5cdFx0XHRcdFx0Y29uc3QgdmFsdWVzID0gW107XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgbSA9IDA7IG0gIT09IGFuaW1hdGlvbktleXNbIGsgXS5tb3JwaFRhcmdldHMubGVuZ3RoOyArKyBtICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBhbmltYXRpb25LZXkgPSBhbmltYXRpb25LZXlzWyBrIF07XG5cblx0XHRcdFx0XHRcdHRpbWVzLnB1c2goIGFuaW1hdGlvbktleS50aW1lICk7XG5cdFx0XHRcdFx0XHR2YWx1ZXMucHVzaCggKCBhbmltYXRpb25LZXkubW9ycGhUYXJnZXQgPT09IG1vcnBoVGFyZ2V0TmFtZSApID8gMSA6IDAgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdHRyYWNrcy5wdXNoKCBuZXcgTnVtYmVyS2V5ZnJhbWVUcmFjayggJy5tb3JwaFRhcmdldEluZmx1ZW5jZVsnICsgbW9ycGhUYXJnZXROYW1lICsgJ10nLCB0aW1lcywgdmFsdWVzICkgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0ZHVyYXRpb24gPSBtb3JwaFRhcmdldE5hbWVzLmxlbmd0aCAqIGZwcztcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyAuLi5hc3N1bWUgc2tlbGV0YWwgYW5pbWF0aW9uXG5cblx0XHRcdFx0Y29uc3QgYm9uZU5hbWUgPSAnLmJvbmVzWycgKyBib25lc1sgaCBdLm5hbWUgKyAnXSc7XG5cblx0XHRcdFx0YWRkTm9uZW1wdHlUcmFjayhcblx0XHRcdFx0XHRWZWN0b3JLZXlmcmFtZVRyYWNrLCBib25lTmFtZSArICcucG9zaXRpb24nLFxuXHRcdFx0XHRcdGFuaW1hdGlvbktleXMsICdwb3MnLCB0cmFja3MgKTtcblxuXHRcdFx0XHRhZGROb25lbXB0eVRyYWNrKFxuXHRcdFx0XHRcdFF1YXRlcm5pb25LZXlmcmFtZVRyYWNrLCBib25lTmFtZSArICcucXVhdGVybmlvbicsXG5cdFx0XHRcdFx0YW5pbWF0aW9uS2V5cywgJ3JvdCcsIHRyYWNrcyApO1xuXG5cdFx0XHRcdGFkZE5vbmVtcHR5VHJhY2soXG5cdFx0XHRcdFx0VmVjdG9yS2V5ZnJhbWVUcmFjaywgYm9uZU5hbWUgKyAnLnNjYWxlJyxcblx0XHRcdFx0XHRhbmltYXRpb25LZXlzLCAnc2NsJywgdHJhY2tzICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggdHJhY2tzLmxlbmd0aCA9PT0gMCApIHtcblxuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9XG5cblx0XHRjb25zdCBjbGlwID0gbmV3IHRoaXMoIGNsaXBOYW1lLCBkdXJhdGlvbiwgdHJhY2tzLCBibGVuZE1vZGUgKTtcblxuXHRcdHJldHVybiBjbGlwO1xuXG5cdH1cblxuXHRyZXNldER1cmF0aW9uKCkge1xuXG5cdFx0Y29uc3QgdHJhY2tzID0gdGhpcy50cmFja3M7XG5cdFx0bGV0IGR1cmF0aW9uID0gMDtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IHRyYWNrcy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdGNvbnN0IHRyYWNrID0gdGhpcy50cmFja3NbIGkgXTtcblxuXHRcdFx0ZHVyYXRpb24gPSBNYXRoLm1heCggZHVyYXRpb24sIHRyYWNrLnRpbWVzWyB0cmFjay50aW1lcy5sZW5ndGggLSAxIF0gKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuZHVyYXRpb24gPSBkdXJhdGlvbjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0cmltKCkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy50cmFja3MubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLnRyYWNrc1sgaSBdLnRyaW0oIDAsIHRoaXMuZHVyYXRpb24gKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR2YWxpZGF0ZSgpIHtcblxuXHRcdGxldCB2YWxpZCA9IHRydWU7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLnRyYWNrcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdHZhbGlkID0gdmFsaWQgJiYgdGhpcy50cmFja3NbIGkgXS52YWxpZGF0ZSgpO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHZhbGlkO1xuXG5cdH1cblxuXHRvcHRpbWl6ZSgpIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMudHJhY2tzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0dGhpcy50cmFja3NbIGkgXS5vcHRpbWl6ZSgpO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0Y29uc3QgdHJhY2tzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLnRyYWNrcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdHRyYWNrcy5wdXNoKCB0aGlzLnRyYWNrc1sgaSBdLmNsb25lKCkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy5uYW1lLCB0aGlzLmR1cmF0aW9uLCB0cmFja3MsIHRoaXMuYmxlbmRNb2RlICk7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdHJldHVybiB0aGlzLmNvbnN0cnVjdG9yLnRvSlNPTiggdGhpcyApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBnZXRUcmFja1R5cGVGb3JWYWx1ZVR5cGVOYW1lKCB0eXBlTmFtZSApIHtcblxuXHRzd2l0Y2ggKCB0eXBlTmFtZS50b0xvd2VyQ2FzZSgpICkge1xuXG5cdFx0Y2FzZSAnc2NhbGFyJzpcblx0XHRjYXNlICdkb3VibGUnOlxuXHRcdGNhc2UgJ2Zsb2F0Jzpcblx0XHRjYXNlICdudW1iZXInOlxuXHRcdGNhc2UgJ2ludGVnZXInOlxuXG5cdFx0XHRyZXR1cm4gTnVtYmVyS2V5ZnJhbWVUcmFjaztcblxuXHRcdGNhc2UgJ3ZlY3Rvcic6XG5cdFx0Y2FzZSAndmVjdG9yMic6XG5cdFx0Y2FzZSAndmVjdG9yMyc6XG5cdFx0Y2FzZSAndmVjdG9yNCc6XG5cblx0XHRcdHJldHVybiBWZWN0b3JLZXlmcmFtZVRyYWNrO1xuXG5cdFx0Y2FzZSAnY29sb3InOlxuXG5cdFx0XHRyZXR1cm4gQ29sb3JLZXlmcmFtZVRyYWNrO1xuXG5cdFx0Y2FzZSAncXVhdGVybmlvbic6XG5cblx0XHRcdHJldHVybiBRdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjaztcblxuXHRcdGNhc2UgJ2Jvb2wnOlxuXHRcdGNhc2UgJ2Jvb2xlYW4nOlxuXG5cdFx0XHRyZXR1cm4gQm9vbGVhbktleWZyYW1lVHJhY2s7XG5cblx0XHRjYXNlICdzdHJpbmcnOlxuXG5cdFx0XHRyZXR1cm4gU3RyaW5nS2V5ZnJhbWVUcmFjaztcblxuXHR9XG5cblx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuS2V5ZnJhbWVUcmFjazogVW5zdXBwb3J0ZWQgdHlwZU5hbWU6ICcgKyB0eXBlTmFtZSApO1xuXG59XG5cbmZ1bmN0aW9uIHBhcnNlS2V5ZnJhbWVUcmFjaygganNvbiApIHtcblxuXHRpZiAoIGpzb24udHlwZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuS2V5ZnJhbWVUcmFjazogdHJhY2sgdHlwZSB1bmRlZmluZWQsIGNhbiBub3QgcGFyc2UnICk7XG5cblx0fVxuXG5cdGNvbnN0IHRyYWNrVHlwZSA9IGdldFRyYWNrVHlwZUZvclZhbHVlVHlwZU5hbWUoIGpzb24udHlwZSApO1xuXG5cdGlmICgganNvbi50aW1lcyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0Y29uc3QgdGltZXMgPSBbXSwgdmFsdWVzID0gW107XG5cblx0XHRmbGF0dGVuSlNPTigganNvbi5rZXlzLCB0aW1lcywgdmFsdWVzLCAndmFsdWUnICk7XG5cblx0XHRqc29uLnRpbWVzID0gdGltZXM7XG5cdFx0anNvbi52YWx1ZXMgPSB2YWx1ZXM7XG5cblx0fVxuXG5cdC8vIGRlcml2ZWQgY2xhc3NlcyBjYW4gZGVmaW5lIGEgc3RhdGljIHBhcnNlIG1ldGhvZFxuXHRpZiAoIHRyYWNrVHlwZS5wYXJzZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0cmV0dXJuIHRyYWNrVHlwZS5wYXJzZSgganNvbiApO1xuXG5cdH0gZWxzZSB7XG5cblx0XHQvLyBieSBkZWZhdWx0LCB3ZSBhc3N1bWUgYSBjb25zdHJ1Y3RvciBjb21wYXRpYmxlIHdpdGggdGhlIGJhc2Vcblx0XHRyZXR1cm4gbmV3IHRyYWNrVHlwZSgganNvbi5uYW1lLCBqc29uLnRpbWVzLCBqc29uLnZhbHVlcywganNvbi5pbnRlcnBvbGF0aW9uICk7XG5cblx0fVxuXG59XG5cbmNvbnN0IENhY2hlID0ge1xuXG5cdGVuYWJsZWQ6IGZhbHNlLFxuXG5cdGZpbGVzOiB7fSxcblxuXHRhZGQ6IGZ1bmN0aW9uICgga2V5LCBmaWxlICkge1xuXG5cdFx0aWYgKCB0aGlzLmVuYWJsZWQgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0Ly8gY29uc29sZS5sb2coICdUSFJFRS5DYWNoZScsICdBZGRpbmcga2V5OicsIGtleSApO1xuXG5cdFx0dGhpcy5maWxlc1sga2V5IF0gPSBmaWxlO1xuXG5cdH0sXG5cblx0Z2V0OiBmdW5jdGlvbiAoIGtleSApIHtcblxuXHRcdGlmICggdGhpcy5lbmFibGVkID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdC8vIGNvbnNvbGUubG9nKCAnVEhSRUUuQ2FjaGUnLCAnQ2hlY2tpbmcga2V5OicsIGtleSApO1xuXG5cdFx0cmV0dXJuIHRoaXMuZmlsZXNbIGtleSBdO1xuXG5cdH0sXG5cblx0cmVtb3ZlOiBmdW5jdGlvbiAoIGtleSApIHtcblxuXHRcdGRlbGV0ZSB0aGlzLmZpbGVzWyBrZXkgXTtcblxuXHR9LFxuXG5cdGNsZWFyOiBmdW5jdGlvbiAoKSB7XG5cblx0XHR0aGlzLmZpbGVzID0ge307XG5cblx0fVxuXG59O1xuXG5jbGFzcyBMb2FkaW5nTWFuYWdlciB7XG5cblx0Y29uc3RydWN0b3IoIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdGxldCBpc0xvYWRpbmcgPSBmYWxzZTtcblx0XHRsZXQgaXRlbXNMb2FkZWQgPSAwO1xuXHRcdGxldCBpdGVtc1RvdGFsID0gMDtcblx0XHRsZXQgdXJsTW9kaWZpZXIgPSB1bmRlZmluZWQ7XG5cdFx0Y29uc3QgaGFuZGxlcnMgPSBbXTtcblxuXHRcdC8vIFJlZmVyIHRvICM1Njg5IGZvciB0aGUgcmVhc29uIHdoeSB3ZSBkb24ndCBzZXQgLm9uU3RhcnRcblx0XHQvLyBpbiB0aGUgY29uc3RydWN0b3JcblxuXHRcdHRoaXMub25TdGFydCA9IHVuZGVmaW5lZDtcblx0XHR0aGlzLm9uTG9hZCA9IG9uTG9hZDtcblx0XHR0aGlzLm9uUHJvZ3Jlc3MgPSBvblByb2dyZXNzO1xuXHRcdHRoaXMub25FcnJvciA9IG9uRXJyb3I7XG5cblx0XHR0aGlzLml0ZW1TdGFydCA9IGZ1bmN0aW9uICggdXJsICkge1xuXG5cdFx0XHRpdGVtc1RvdGFsICsrO1xuXG5cdFx0XHRpZiAoIGlzTG9hZGluZyA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0aWYgKCBzY29wZS5vblN0YXJ0ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRzY29wZS5vblN0YXJ0KCB1cmwsIGl0ZW1zTG9hZGVkLCBpdGVtc1RvdGFsICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlzTG9hZGluZyA9IHRydWU7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5pdGVtRW5kID0gZnVuY3Rpb24gKCB1cmwgKSB7XG5cblx0XHRcdGl0ZW1zTG9hZGVkICsrO1xuXG5cdFx0XHRpZiAoIHNjb3BlLm9uUHJvZ3Jlc3MgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRzY29wZS5vblByb2dyZXNzKCB1cmwsIGl0ZW1zTG9hZGVkLCBpdGVtc1RvdGFsICk7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBpdGVtc0xvYWRlZCA9PT0gaXRlbXNUb3RhbCApIHtcblxuXHRcdFx0XHRpc0xvYWRpbmcgPSBmYWxzZTtcblxuXHRcdFx0XHRpZiAoIHNjb3BlLm9uTG9hZCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0c2NvcGUub25Mb2FkKCk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5pdGVtRXJyb3IgPSBmdW5jdGlvbiAoIHVybCApIHtcblxuXHRcdFx0aWYgKCBzY29wZS5vbkVycm9yICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0c2NvcGUub25FcnJvciggdXJsICk7XG5cblx0XHRcdH1cblxuXHRcdH07XG5cblx0XHR0aGlzLnJlc29sdmVVUkwgPSBmdW5jdGlvbiAoIHVybCApIHtcblxuXHRcdFx0aWYgKCB1cmxNb2RpZmllciApIHtcblxuXHRcdFx0XHRyZXR1cm4gdXJsTW9kaWZpZXIoIHVybCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB1cmw7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5zZXRVUkxNb2RpZmllciA9IGZ1bmN0aW9uICggdHJhbnNmb3JtICkge1xuXG5cdFx0XHR1cmxNb2RpZmllciA9IHRyYW5zZm9ybTtcblxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5hZGRIYW5kbGVyID0gZnVuY3Rpb24gKCByZWdleCwgbG9hZGVyICkge1xuXG5cdFx0XHRoYW5kbGVycy5wdXNoKCByZWdleCwgbG9hZGVyICk7XG5cblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMucmVtb3ZlSGFuZGxlciA9IGZ1bmN0aW9uICggcmVnZXggKSB7XG5cblx0XHRcdGNvbnN0IGluZGV4ID0gaGFuZGxlcnMuaW5kZXhPZiggcmVnZXggKTtcblxuXHRcdFx0aWYgKCBpbmRleCAhPT0gLSAxICkge1xuXG5cdFx0XHRcdGhhbmRsZXJzLnNwbGljZSggaW5kZXgsIDIgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldEhhbmRsZXIgPSBmdW5jdGlvbiAoIGZpbGUgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGhhbmRsZXJzLmxlbmd0aDsgaSA8IGw7IGkgKz0gMiApIHtcblxuXHRcdFx0XHRjb25zdCByZWdleCA9IGhhbmRsZXJzWyBpIF07XG5cdFx0XHRcdGNvbnN0IGxvYWRlciA9IGhhbmRsZXJzWyBpICsgMSBdO1xuXG5cdFx0XHRcdGlmICggcmVnZXguZ2xvYmFsICkgcmVnZXgubGFzdEluZGV4ID0gMDsgLy8gc2VlICMxNzkyMFxuXG5cdFx0XHRcdGlmICggcmVnZXgudGVzdCggZmlsZSApICkge1xuXG5cdFx0XHRcdFx0cmV0dXJuIGxvYWRlcjtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9O1xuXG5cdH1cblxufVxuXG5jb25zdCBEZWZhdWx0TG9hZGluZ01hbmFnZXIgPSAvKkBfX1BVUkVfXyovIG5ldyBMb2FkaW5nTWFuYWdlcigpO1xuXG5jbGFzcyBMb2FkZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xuXG5cdFx0dGhpcy5tYW5hZ2VyID0gKCBtYW5hZ2VyICE9PSB1bmRlZmluZWQgKSA/IG1hbmFnZXIgOiBEZWZhdWx0TG9hZGluZ01hbmFnZXI7XG5cblx0XHR0aGlzLmNyb3NzT3JpZ2luID0gJ2Fub255bW91cyc7XG5cdFx0dGhpcy53aXRoQ3JlZGVudGlhbHMgPSBmYWxzZTtcblx0XHR0aGlzLnBhdGggPSAnJztcblx0XHR0aGlzLnJlc291cmNlUGF0aCA9ICcnO1xuXHRcdHRoaXMucmVxdWVzdEhlYWRlciA9IHt9O1xuXG5cdH1cblxuXHRsb2FkKCAvKiB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciAqLyApIHt9XG5cblx0bG9hZEFzeW5jKCB1cmwsIG9uUHJvZ3Jlc3MgKSB7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRyZXR1cm4gbmV3IFByb21pc2UoIGZ1bmN0aW9uICggcmVzb2x2ZSwgcmVqZWN0ICkge1xuXG5cdFx0XHRzY29wZS5sb2FkKCB1cmwsIHJlc29sdmUsIG9uUHJvZ3Jlc3MsIHJlamVjdCApO1xuXG5cdFx0fSApO1xuXG5cdH1cblxuXHRwYXJzZSggLyogZGF0YSAqLyApIHt9XG5cblx0c2V0Q3Jvc3NPcmlnaW4oIGNyb3NzT3JpZ2luICkge1xuXG5cdFx0dGhpcy5jcm9zc09yaWdpbiA9IGNyb3NzT3JpZ2luO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRXaXRoQ3JlZGVudGlhbHMoIHZhbHVlICkge1xuXG5cdFx0dGhpcy53aXRoQ3JlZGVudGlhbHMgPSB2YWx1ZTtcblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0UGF0aCggcGF0aCApIHtcblxuXHRcdHRoaXMucGF0aCA9IHBhdGg7XG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFJlc291cmNlUGF0aCggcmVzb3VyY2VQYXRoICkge1xuXG5cdFx0dGhpcy5yZXNvdXJjZVBhdGggPSByZXNvdXJjZVBhdGg7XG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFJlcXVlc3RIZWFkZXIoIHJlcXVlc3RIZWFkZXIgKSB7XG5cblx0XHR0aGlzLnJlcXVlc3RIZWFkZXIgPSByZXF1ZXN0SGVhZGVyO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5Mb2FkZXIuREVGQVVMVF9NQVRFUklBTF9OQU1FID0gJ19fREVGQVVMVCc7XG5cbmNvbnN0IGxvYWRpbmcgPSB7fTtcblxuY2xhc3MgSHR0cEVycm9yIGV4dGVuZHMgRXJyb3Ige1xuXG5cdGNvbnN0cnVjdG9yKCBtZXNzYWdlLCByZXNwb25zZSApIHtcblxuXHRcdHN1cGVyKCBtZXNzYWdlICk7XG5cdFx0dGhpcy5yZXNwb25zZSA9IHJlc3BvbnNlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBGaWxlTG9hZGVyIGV4dGVuZHMgTG9hZGVyIHtcblxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcblxuXHRcdHN1cGVyKCBtYW5hZ2VyICk7XG5cblx0fVxuXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xuXG5cdFx0aWYgKCB1cmwgPT09IHVuZGVmaW5lZCApIHVybCA9ICcnO1xuXG5cdFx0aWYgKCB0aGlzLnBhdGggIT09IHVuZGVmaW5lZCApIHVybCA9IHRoaXMucGF0aCArIHVybDtcblxuXHRcdHVybCA9IHRoaXMubWFuYWdlci5yZXNvbHZlVVJMKCB1cmwgKTtcblxuXHRcdGNvbnN0IGNhY2hlZCA9IENhY2hlLmdldCggdXJsICk7XG5cblx0XHRpZiAoIGNhY2hlZCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLm1hbmFnZXIuaXRlbVN0YXJ0KCB1cmwgKTtcblxuXHRcdFx0c2V0VGltZW91dCggKCkgPT4ge1xuXG5cdFx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCBjYWNoZWQgKTtcblxuXHRcdFx0XHR0aGlzLm1hbmFnZXIuaXRlbUVuZCggdXJsICk7XG5cblx0XHRcdH0sIDAgKTtcblxuXHRcdFx0cmV0dXJuIGNhY2hlZDtcblxuXHRcdH1cblxuXHRcdC8vIENoZWNrIGlmIHJlcXVlc3QgaXMgZHVwbGljYXRlXG5cblx0XHRpZiAoIGxvYWRpbmdbIHVybCBdICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGxvYWRpbmdbIHVybCBdLnB1c2goIHtcblxuXHRcdFx0XHRvbkxvYWQ6IG9uTG9hZCxcblx0XHRcdFx0b25Qcm9ncmVzczogb25Qcm9ncmVzcyxcblx0XHRcdFx0b25FcnJvcjogb25FcnJvclxuXG5cdFx0XHR9ICk7XG5cblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdC8vIEluaXRpYWxpc2UgYXJyYXkgZm9yIGR1cGxpY2F0ZSByZXF1ZXN0c1xuXHRcdGxvYWRpbmdbIHVybCBdID0gW107XG5cblx0XHRsb2FkaW5nWyB1cmwgXS5wdXNoKCB7XG5cdFx0XHRvbkxvYWQ6IG9uTG9hZCxcblx0XHRcdG9uUHJvZ3Jlc3M6IG9uUHJvZ3Jlc3MsXG5cdFx0XHRvbkVycm9yOiBvbkVycm9yLFxuXHRcdH0gKTtcblxuXHRcdC8vIGNyZWF0ZSByZXF1ZXN0XG5cdFx0Y29uc3QgcmVxID0gbmV3IFJlcXVlc3QoIHVybCwge1xuXHRcdFx0aGVhZGVyczogbmV3IEhlYWRlcnMoIHRoaXMucmVxdWVzdEhlYWRlciApLFxuXHRcdFx0Y3JlZGVudGlhbHM6IHRoaXMud2l0aENyZWRlbnRpYWxzID8gJ2luY2x1ZGUnIDogJ3NhbWUtb3JpZ2luJyxcblx0XHRcdC8vIEFuIGFib3J0IGNvbnRyb2xsZXIgY291bGQgYmUgYWRkZWQgd2l0aGluIGEgZnV0dXJlIFBSXG5cdFx0fSApO1xuXG5cdFx0Ly8gcmVjb3JkIHN0YXRlcyAoIGF2b2lkIGRhdGEgcmFjZSApXG5cdFx0Y29uc3QgbWltZVR5cGUgPSB0aGlzLm1pbWVUeXBlO1xuXHRcdGNvbnN0IHJlc3BvbnNlVHlwZSA9IHRoaXMucmVzcG9uc2VUeXBlO1xuXG5cdFx0Ly8gc3RhcnQgdGhlIGZldGNoXG5cdFx0ZmV0Y2goIHJlcSApXG5cdFx0XHQudGhlbiggcmVzcG9uc2UgPT4ge1xuXG5cdFx0XHRcdGlmICggcmVzcG9uc2Uuc3RhdHVzID09PSAyMDAgfHwgcmVzcG9uc2Uuc3RhdHVzID09PSAwICkge1xuXG5cdFx0XHRcdFx0Ly8gU29tZSBicm93c2VycyByZXR1cm4gSFRUUCBTdGF0dXMgMCB3aGVuIHVzaW5nIG5vbi1odHRwIHByb3RvY29sXG5cdFx0XHRcdFx0Ly8gZS5nLiAnZmlsZTovLycgb3IgJ2RhdGE6Ly8nLiBIYW5kbGUgYXMgc3VjY2Vzcy5cblxuXHRcdFx0XHRcdGlmICggcmVzcG9uc2Uuc3RhdHVzID09PSAwICkge1xuXG5cdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5GaWxlTG9hZGVyOiBIVFRQIFN0YXR1cyAwIHJlY2VpdmVkLicgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIFdvcmthcm91bmQ6IENoZWNraW5nIGlmIHJlc3BvbnNlLmJvZHkgPT09IHVuZGVmaW5lZCBmb3IgQWxpcGF5IGJyb3dzZXIgIzIzNTQ4XG5cblx0XHRcdFx0XHRpZiAoIHR5cGVvZiBSZWFkYWJsZVN0cmVhbSA9PT0gJ3VuZGVmaW5lZCcgfHwgcmVzcG9uc2UuYm9keSA9PT0gdW5kZWZpbmVkIHx8IHJlc3BvbnNlLmJvZHkuZ2V0UmVhZGVyID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRcdHJldHVybiByZXNwb25zZTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGNvbnN0IGNhbGxiYWNrcyA9IGxvYWRpbmdbIHVybCBdO1xuXHRcdFx0XHRcdGNvbnN0IHJlYWRlciA9IHJlc3BvbnNlLmJvZHkuZ2V0UmVhZGVyKCk7XG5cblx0XHRcdFx0XHQvLyBOZ2lueCBuZWVkcyBYLUZpbGUtU2l6ZSBjaGVja1xuXHRcdFx0XHRcdC8vIGh0dHBzOi8vc2VydmVyZmF1bHQuY29tL3F1ZXN0aW9ucy80ODI4NzUvd2h5LWRvZXMtbmdpbngtcmVtb3ZlLWNvbnRlbnQtbGVuZ3RoLWhlYWRlci1mb3ItY2h1bmtlZC1jb250ZW50XG5cdFx0XHRcdFx0Y29uc3QgY29udGVudExlbmd0aCA9IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCAnWC1GaWxlLVNpemUnICkgfHwgcmVzcG9uc2UuaGVhZGVycy5nZXQoICdDb250ZW50LUxlbmd0aCcgKTtcblx0XHRcdFx0XHRjb25zdCB0b3RhbCA9IGNvbnRlbnRMZW5ndGggPyBwYXJzZUludCggY29udGVudExlbmd0aCApIDogMDtcblx0XHRcdFx0XHRjb25zdCBsZW5ndGhDb21wdXRhYmxlID0gdG90YWwgIT09IDA7XG5cdFx0XHRcdFx0bGV0IGxvYWRlZCA9IDA7XG5cblx0XHRcdFx0XHQvLyBwZXJpb2RpY2FsbHkgcmVhZCBkYXRhIGludG8gdGhlIG5ldyBzdHJlYW0gdHJhY2tpbmcgd2hpbGUgZG93bmxvYWQgcHJvZ3Jlc3Ncblx0XHRcdFx0XHRjb25zdCBzdHJlYW0gPSBuZXcgUmVhZGFibGVTdHJlYW0oIHtcblx0XHRcdFx0XHRcdHN0YXJ0KCBjb250cm9sbGVyICkge1xuXG5cdFx0XHRcdFx0XHRcdHJlYWREYXRhKCk7XG5cblx0XHRcdFx0XHRcdFx0ZnVuY3Rpb24gcmVhZERhdGEoKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRyZWFkZXIucmVhZCgpLnRoZW4oICggeyBkb25lLCB2YWx1ZSB9ICkgPT4ge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRpZiAoIGRvbmUgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0Y29udHJvbGxlci5jbG9zZSgpO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGxvYWRlZCArPSB2YWx1ZS5ieXRlTGVuZ3RoO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGNvbnN0IGV2ZW50ID0gbmV3IFByb2dyZXNzRXZlbnQoICdwcm9ncmVzcycsIHsgbGVuZ3RoQ29tcHV0YWJsZSwgbG9hZGVkLCB0b3RhbCB9ICk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBjYWxsYmFja3MubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRjb25zdCBjYWxsYmFjayA9IGNhbGxiYWNrc1sgaSBdO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdGlmICggY2FsbGJhY2sub25Qcm9ncmVzcyApIGNhbGxiYWNrLm9uUHJvZ3Jlc3MoIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGNvbnRyb2xsZXIuZW5xdWV1ZSggdmFsdWUgKTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0cmVhZERhdGEoKTtcblxuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0fSwgKCBlICkgPT4ge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRjb250cm9sbGVyLmVycm9yKCBlICk7XG5cblx0XHRcdFx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0XHRyZXR1cm4gbmV3IFJlc3BvbnNlKCBzdHJlYW0gKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0dGhyb3cgbmV3IEh0dHBFcnJvciggYGZldGNoIGZvciBcIiR7cmVzcG9uc2UudXJsfVwiIHJlc3BvbmRlZCB3aXRoICR7cmVzcG9uc2Uuc3RhdHVzfTogJHtyZXNwb25zZS5zdGF0dXNUZXh0fWAsIHJlc3BvbnNlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IClcblx0XHRcdC50aGVuKCByZXNwb25zZSA9PiB7XG5cblx0XHRcdFx0c3dpdGNoICggcmVzcG9uc2VUeXBlICkge1xuXG5cdFx0XHRcdFx0Y2FzZSAnYXJyYXlidWZmZXInOlxuXG5cdFx0XHRcdFx0XHRyZXR1cm4gcmVzcG9uc2UuYXJyYXlCdWZmZXIoKTtcblxuXHRcdFx0XHRcdGNhc2UgJ2Jsb2InOlxuXG5cdFx0XHRcdFx0XHRyZXR1cm4gcmVzcG9uc2UuYmxvYigpO1xuXG5cdFx0XHRcdFx0Y2FzZSAnZG9jdW1lbnQnOlxuXG5cdFx0XHRcdFx0XHRyZXR1cm4gcmVzcG9uc2UudGV4dCgpXG5cdFx0XHRcdFx0XHRcdC50aGVuKCB0ZXh0ID0+IHtcblxuXHRcdFx0XHRcdFx0XHRcdGNvbnN0IHBhcnNlciA9IG5ldyBET01QYXJzZXIoKTtcblx0XHRcdFx0XHRcdFx0XHRyZXR1cm4gcGFyc2VyLnBhcnNlRnJvbVN0cmluZyggdGV4dCwgbWltZVR5cGUgKTtcblxuXHRcdFx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0XHRjYXNlICdqc29uJzpcblxuXHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlLmpzb24oKTtcblxuXHRcdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRcdGlmICggbWltZVR5cGUgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdFx0XHRyZXR1cm4gcmVzcG9uc2UudGV4dCgpO1xuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdC8vIHNuaWZmIGVuY29kaW5nXG5cdFx0XHRcdFx0XHRcdGNvbnN0IHJlID0gL2NoYXJzZXQ9XCI/KFteO1wiXFxzXSopXCI/L2k7XG5cdFx0XHRcdFx0XHRcdGNvbnN0IGV4ZWMgPSByZS5leGVjKCBtaW1lVHlwZSApO1xuXHRcdFx0XHRcdFx0XHRjb25zdCBsYWJlbCA9IGV4ZWMgJiYgZXhlY1sgMSBdID8gZXhlY1sgMSBdLnRvTG93ZXJDYXNlKCkgOiB1bmRlZmluZWQ7XG5cdFx0XHRcdFx0XHRcdGNvbnN0IGRlY29kZXIgPSBuZXcgVGV4dERlY29kZXIoIGxhYmVsICk7XG5cdFx0XHRcdFx0XHRcdHJldHVybiByZXNwb25zZS5hcnJheUJ1ZmZlcigpLnRoZW4oIGFiID0+IGRlY29kZXIuZGVjb2RlKCBhYiApICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gKVxuXHRcdFx0LnRoZW4oIGRhdGEgPT4ge1xuXG5cdFx0XHRcdC8vIEFkZCB0byBjYWNoZSBvbmx5IG9uIEhUVFAgc3VjY2Vzcywgc28gdGhhdCB3ZSBkbyBub3QgY2FjaGVcblx0XHRcdFx0Ly8gZXJyb3IgcmVzcG9uc2UgYm9kaWVzIGFzIHByb3BlciByZXNwb25zZXMgdG8gcmVxdWVzdHMuXG5cdFx0XHRcdENhY2hlLmFkZCggdXJsLCBkYXRhICk7XG5cblx0XHRcdFx0Y29uc3QgY2FsbGJhY2tzID0gbG9hZGluZ1sgdXJsIF07XG5cdFx0XHRcdGRlbGV0ZSBsb2FkaW5nWyB1cmwgXTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gY2FsbGJhY2tzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgY2FsbGJhY2sgPSBjYWxsYmFja3NbIGkgXTtcblx0XHRcdFx0XHRpZiAoIGNhbGxiYWNrLm9uTG9hZCApIGNhbGxiYWNrLm9uTG9hZCggZGF0YSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSApXG5cdFx0XHQuY2F0Y2goIGVyciA9PiB7XG5cblx0XHRcdFx0Ly8gQWJvcnQgZXJyb3JzIGFuZCBvdGhlciBlcnJvcnMgYXJlIGhhbmRsZWQgdGhlIHNhbWVcblxuXHRcdFx0XHRjb25zdCBjYWxsYmFja3MgPSBsb2FkaW5nWyB1cmwgXTtcblxuXHRcdFx0XHRpZiAoIGNhbGxiYWNrcyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0Ly8gV2hlbiBvbkxvYWQgd2FzIGNhbGxlZCBhbmQgdXJsIHdhcyBkZWxldGVkIGluIGBsb2FkaW5nYFxuXHRcdFx0XHRcdHRoaXMubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xuXHRcdFx0XHRcdHRocm93IGVycjtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0ZGVsZXRlIGxvYWRpbmdbIHVybCBdO1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBjYWxsYmFja3MubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBjYWxsYmFjayA9IGNhbGxiYWNrc1sgaSBdO1xuXHRcdFx0XHRcdGlmICggY2FsbGJhY2sub25FcnJvciApIGNhbGxiYWNrLm9uRXJyb3IoIGVyciApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHR0aGlzLm1hbmFnZXIuaXRlbUVycm9yKCB1cmwgKTtcblxuXHRcdFx0fSApXG5cdFx0XHQuZmluYWxseSggKCkgPT4ge1xuXG5cdFx0XHRcdHRoaXMubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcblxuXHRcdFx0fSApO1xuXG5cdFx0dGhpcy5tYW5hZ2VyLml0ZW1TdGFydCggdXJsICk7XG5cblx0fVxuXG5cdHNldFJlc3BvbnNlVHlwZSggdmFsdWUgKSB7XG5cblx0XHR0aGlzLnJlc3BvbnNlVHlwZSA9IHZhbHVlO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRNaW1lVHlwZSggdmFsdWUgKSB7XG5cblx0XHR0aGlzLm1pbWVUeXBlID0gdmFsdWU7XG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIEFuaW1hdGlvbkxvYWRlciBleHRlbmRzIExvYWRlciB7XG5cblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XG5cblx0XHRzdXBlciggbWFuYWdlciApO1xuXG5cdH1cblxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdGNvbnN0IGxvYWRlciA9IG5ldyBGaWxlTG9hZGVyKCB0aGlzLm1hbmFnZXIgKTtcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XG5cdFx0bG9hZGVyLnNldFJlcXVlc3RIZWFkZXIoIHRoaXMucmVxdWVzdEhlYWRlciApO1xuXHRcdGxvYWRlci5zZXRXaXRoQ3JlZGVudGlhbHMoIHRoaXMud2l0aENyZWRlbnRpYWxzICk7XG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCB0ZXh0ICkge1xuXG5cdFx0XHR0cnkge1xuXG5cdFx0XHRcdG9uTG9hZCggc2NvcGUucGFyc2UoIEpTT04ucGFyc2UoIHRleHQgKSApICk7XG5cblx0XHRcdH0gY2F0Y2ggKCBlICkge1xuXG5cdFx0XHRcdGlmICggb25FcnJvciApIHtcblxuXHRcdFx0XHRcdG9uRXJyb3IoIGUgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Y29uc29sZS5lcnJvciggZSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FcnJvciggdXJsICk7XG5cblx0XHRcdH1cblxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcblxuXHR9XG5cblx0cGFyc2UoIGpzb24gKSB7XG5cblx0XHRjb25zdCBhbmltYXRpb25zID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBqc29uLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgY2xpcCA9IEFuaW1hdGlvbkNsaXAucGFyc2UoIGpzb25bIGkgXSApO1xuXG5cdFx0XHRhbmltYXRpb25zLnB1c2goIGNsaXAgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBhbmltYXRpb25zO1xuXG5cdH1cblxufVxuXG4vKipcbiAqIEFic3RyYWN0IEJhc2UgY2xhc3MgdG8gYmxvY2sgYmFzZWQgdGV4dHVyZXMgbG9hZGVyIChkZHMsIHB2ciwgLi4uKVxuICpcbiAqIFN1YiBjbGFzc2VzIGhhdmUgdG8gaW1wbGVtZW50IHRoZSBwYXJzZSgpIG1ldGhvZCB3aGljaCB3aWxsIGJlIHVzZWQgaW4gbG9hZCgpLlxuICovXG5cbmNsYXNzIENvbXByZXNzZWRUZXh0dXJlTG9hZGVyIGV4dGVuZHMgTG9hZGVyIHtcblxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcblxuXHRcdHN1cGVyKCBtYW5hZ2VyICk7XG5cblx0fVxuXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0Y29uc3QgaW1hZ2VzID0gW107XG5cblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IENvbXByZXNzZWRUZXh0dXJlKCk7XG5cblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XG5cdFx0bG9hZGVyLnNldFBhdGgoIHRoaXMucGF0aCApO1xuXHRcdGxvYWRlci5zZXRSZXNwb25zZVR5cGUoICdhcnJheWJ1ZmZlcicgKTtcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggdGhpcy5yZXF1ZXN0SGVhZGVyICk7XG5cdFx0bG9hZGVyLnNldFdpdGhDcmVkZW50aWFscyggc2NvcGUud2l0aENyZWRlbnRpYWxzICk7XG5cblx0XHRsZXQgbG9hZGVkID0gMDtcblxuXHRcdGZ1bmN0aW9uIGxvYWRUZXh0dXJlKCBpICkge1xuXG5cdFx0XHRsb2FkZXIubG9hZCggdXJsWyBpIF0sIGZ1bmN0aW9uICggYnVmZmVyICkge1xuXG5cdFx0XHRcdGNvbnN0IHRleERhdGFzID0gc2NvcGUucGFyc2UoIGJ1ZmZlciwgdHJ1ZSApO1xuXG5cdFx0XHRcdGltYWdlc1sgaSBdID0ge1xuXHRcdFx0XHRcdHdpZHRoOiB0ZXhEYXRhcy53aWR0aCxcblx0XHRcdFx0XHRoZWlnaHQ6IHRleERhdGFzLmhlaWdodCxcblx0XHRcdFx0XHRmb3JtYXQ6IHRleERhdGFzLmZvcm1hdCxcblx0XHRcdFx0XHRtaXBtYXBzOiB0ZXhEYXRhcy5taXBtYXBzXG5cdFx0XHRcdH07XG5cblx0XHRcdFx0bG9hZGVkICs9IDE7XG5cblx0XHRcdFx0aWYgKCBsb2FkZWQgPT09IDYgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHRleERhdGFzLm1pcG1hcENvdW50ID09PSAxICkgdGV4dHVyZS5taW5GaWx0ZXIgPSBMaW5lYXJGaWx0ZXI7XG5cblx0XHRcdFx0XHR0ZXh0dXJlLmltYWdlID0gaW1hZ2VzO1xuXHRcdFx0XHRcdHRleHR1cmUuZm9ybWF0ID0gdGV4RGF0YXMuZm9ybWF0O1xuXHRcdFx0XHRcdHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0XHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIHRleHR1cmUgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcblxuXHRcdH1cblxuXHRcdGlmICggQXJyYXkuaXNBcnJheSggdXJsICkgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB1cmwubGVuZ3RoOyBpIDwgaWw7ICsrIGkgKSB7XG5cblx0XHRcdFx0bG9hZFRleHR1cmUoIGkgKTtcblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gY29tcHJlc3NlZCBjdWJlbWFwIHRleHR1cmUgc3RvcmVkIGluIGEgc2luZ2xlIEREUyBmaWxlXG5cblx0XHRcdGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICggYnVmZmVyICkge1xuXG5cdFx0XHRcdGNvbnN0IHRleERhdGFzID0gc2NvcGUucGFyc2UoIGJ1ZmZlciwgdHJ1ZSApO1xuXG5cdFx0XHRcdGlmICggdGV4RGF0YXMuaXNDdWJlbWFwICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgZmFjZXMgPSB0ZXhEYXRhcy5taXBtYXBzLmxlbmd0aCAvIHRleERhdGFzLm1pcG1hcENvdW50O1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGYgPSAwOyBmIDwgZmFjZXM7IGYgKysgKSB7XG5cblx0XHRcdFx0XHRcdGltYWdlc1sgZiBdID0geyBtaXBtYXBzOiBbXSB9O1xuXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0ZXhEYXRhcy5taXBtYXBDb3VudDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0XHRpbWFnZXNbIGYgXS5taXBtYXBzLnB1c2goIHRleERhdGFzLm1pcG1hcHNbIGYgKiB0ZXhEYXRhcy5taXBtYXBDb3VudCArIGkgXSApO1xuXHRcdFx0XHRcdFx0XHRpbWFnZXNbIGYgXS5mb3JtYXQgPSB0ZXhEYXRhcy5mb3JtYXQ7XG5cdFx0XHRcdFx0XHRcdGltYWdlc1sgZiBdLndpZHRoID0gdGV4RGF0YXMud2lkdGg7XG5cdFx0XHRcdFx0XHRcdGltYWdlc1sgZiBdLmhlaWdodCA9IHRleERhdGFzLmhlaWdodDtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0dGV4dHVyZS5pbWFnZSA9IGltYWdlcztcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0dGV4dHVyZS5pbWFnZS53aWR0aCA9IHRleERhdGFzLndpZHRoO1xuXHRcdFx0XHRcdHRleHR1cmUuaW1hZ2UuaGVpZ2h0ID0gdGV4RGF0YXMuaGVpZ2h0O1xuXHRcdFx0XHRcdHRleHR1cmUubWlwbWFwcyA9IHRleERhdGFzLm1pcG1hcHM7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggdGV4RGF0YXMubWlwbWFwQ291bnQgPT09IDEgKSB7XG5cblx0XHRcdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IExpbmVhckZpbHRlcjtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0dGV4dHVyZS5mb3JtYXQgPSB0ZXhEYXRhcy5mb3JtYXQ7XG5cdFx0XHRcdHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCB0ZXh0dXJlICk7XG5cblx0XHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0ZXh0dXJlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBJbWFnZUxvYWRlciBleHRlbmRzIExvYWRlciB7XG5cblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XG5cblx0XHRzdXBlciggbWFuYWdlciApO1xuXG5cdH1cblxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcblxuXHRcdGlmICggdGhpcy5wYXRoICE9PSB1bmRlZmluZWQgKSB1cmwgPSB0aGlzLnBhdGggKyB1cmw7XG5cblx0XHR1cmwgPSB0aGlzLm1hbmFnZXIucmVzb2x2ZVVSTCggdXJsICk7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRjb25zdCBjYWNoZWQgPSBDYWNoZS5nZXQoIHVybCApO1xuXG5cdFx0aWYgKCBjYWNoZWQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtU3RhcnQoIHVybCApO1xuXG5cdFx0XHRzZXRUaW1lb3V0KCBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIGNhY2hlZCApO1xuXG5cdFx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbUVuZCggdXJsICk7XG5cblx0XHRcdH0sIDAgKTtcblxuXHRcdFx0cmV0dXJuIGNhY2hlZDtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGltYWdlID0gY3JlYXRlRWxlbWVudE5TKCAnaW1nJyApO1xuXG5cdFx0ZnVuY3Rpb24gb25JbWFnZUxvYWQoKSB7XG5cblx0XHRcdHJlbW92ZUV2ZW50TGlzdGVuZXJzKCk7XG5cblx0XHRcdENhY2hlLmFkZCggdXJsLCB0aGlzICk7XG5cblx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCB0aGlzICk7XG5cblx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbUVuZCggdXJsICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBvbkltYWdlRXJyb3IoIGV2ZW50ICkge1xuXG5cdFx0XHRyZW1vdmVFdmVudExpc3RlbmVycygpO1xuXG5cdFx0XHRpZiAoIG9uRXJyb3IgKSBvbkVycm9yKCBldmVudCApO1xuXG5cdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FcnJvciggdXJsICk7XG5cdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gcmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKSB7XG5cblx0XHRcdGltYWdlLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdsb2FkJywgb25JbWFnZUxvYWQsIGZhbHNlICk7XG5cdFx0XHRpbWFnZS5yZW1vdmVFdmVudExpc3RlbmVyKCAnZXJyb3InLCBvbkltYWdlRXJyb3IsIGZhbHNlICk7XG5cblx0XHR9XG5cblx0XHRpbWFnZS5hZGRFdmVudExpc3RlbmVyKCAnbG9hZCcsIG9uSW1hZ2VMb2FkLCBmYWxzZSApO1xuXHRcdGltYWdlLmFkZEV2ZW50TGlzdGVuZXIoICdlcnJvcicsIG9uSW1hZ2VFcnJvciwgZmFsc2UgKTtcblxuXHRcdGlmICggdXJsLnNsaWNlKCAwLCA1ICkgIT09ICdkYXRhOicgKSB7XG5cblx0XHRcdGlmICggdGhpcy5jcm9zc09yaWdpbiAhPT0gdW5kZWZpbmVkICkgaW1hZ2UuY3Jvc3NPcmlnaW4gPSB0aGlzLmNyb3NzT3JpZ2luO1xuXG5cdFx0fVxuXG5cdFx0c2NvcGUubWFuYWdlci5pdGVtU3RhcnQoIHVybCApO1xuXG5cdFx0aW1hZ2Uuc3JjID0gdXJsO1xuXG5cdFx0cmV0dXJuIGltYWdlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBDdWJlVGV4dHVyZUxvYWRlciBleHRlbmRzIExvYWRlciB7XG5cblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XG5cblx0XHRzdXBlciggbWFuYWdlciApO1xuXG5cdH1cblxuXHRsb2FkKCB1cmxzLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IEN1YmVUZXh0dXJlKCk7XG5cdFx0dGV4dHVyZS5jb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2U7XG5cblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgSW1hZ2VMb2FkZXIoIHRoaXMubWFuYWdlciApO1xuXHRcdGxvYWRlci5zZXRDcm9zc09yaWdpbiggdGhpcy5jcm9zc09yaWdpbiApO1xuXHRcdGxvYWRlci5zZXRQYXRoKCB0aGlzLnBhdGggKTtcblxuXHRcdGxldCBsb2FkZWQgPSAwO1xuXG5cdFx0ZnVuY3Rpb24gbG9hZFRleHR1cmUoIGkgKSB7XG5cblx0XHRcdGxvYWRlci5sb2FkKCB1cmxzWyBpIF0sIGZ1bmN0aW9uICggaW1hZ2UgKSB7XG5cblx0XHRcdFx0dGV4dHVyZS5pbWFnZXNbIGkgXSA9IGltYWdlO1xuXG5cdFx0XHRcdGxvYWRlZCArKztcblxuXHRcdFx0XHRpZiAoIGxvYWRlZCA9PT0gNiApIHtcblxuXHRcdFx0XHRcdHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0XHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIHRleHR1cmUgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0sIHVuZGVmaW5lZCwgb25FcnJvciApO1xuXG5cdFx0fVxuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdXJscy5sZW5ndGg7ICsrIGkgKSB7XG5cblx0XHRcdGxvYWRUZXh0dXJlKCBpICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGV4dHVyZTtcblxuXHR9XG5cbn1cblxuLyoqXG4gKiBBYnN0cmFjdCBCYXNlIGNsYXNzIHRvIGxvYWQgZ2VuZXJpYyBiaW5hcnkgdGV4dHVyZXMgZm9ybWF0cyAocmdiZSwgaGRyLCAuLi4pXG4gKlxuICogU3ViIGNsYXNzZXMgaGF2ZSB0byBpbXBsZW1lbnQgdGhlIHBhcnNlKCkgbWV0aG9kIHdoaWNoIHdpbGwgYmUgdXNlZCBpbiBsb2FkKCkuXG4gKi9cblxuY2xhc3MgRGF0YVRleHR1cmVMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xuXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcblxuXHR9XG5cblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IERhdGFUZXh0dXJlKCk7XG5cblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XG5cdFx0bG9hZGVyLnNldFJlc3BvbnNlVHlwZSggJ2FycmF5YnVmZmVyJyApO1xuXHRcdGxvYWRlci5zZXRSZXF1ZXN0SGVhZGVyKCB0aGlzLnJlcXVlc3RIZWFkZXIgKTtcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XG5cdFx0bG9hZGVyLnNldFdpdGhDcmVkZW50aWFscyggc2NvcGUud2l0aENyZWRlbnRpYWxzICk7XG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCBidWZmZXIgKSB7XG5cblx0XHRcdGxldCB0ZXhEYXRhO1xuXG5cdFx0XHR0cnkge1xuXG5cdFx0XHRcdHRleERhdGEgPSBzY29wZS5wYXJzZSggYnVmZmVyICk7XG5cblx0XHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0XHRpZiAoIG9uRXJyb3IgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdG9uRXJyb3IoIGVycm9yICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoIGVycm9yICk7XG5cdFx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRleERhdGEuaW1hZ2UgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0ZXh0dXJlLmltYWdlID0gdGV4RGF0YS5pbWFnZTtcblxuXHRcdFx0fSBlbHNlIGlmICggdGV4RGF0YS5kYXRhICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGV4dHVyZS5pbWFnZS53aWR0aCA9IHRleERhdGEud2lkdGg7XG5cdFx0XHRcdHRleHR1cmUuaW1hZ2UuaGVpZ2h0ID0gdGV4RGF0YS5oZWlnaHQ7XG5cdFx0XHRcdHRleHR1cmUuaW1hZ2UuZGF0YSA9IHRleERhdGEuZGF0YTtcblxuXHRcdFx0fVxuXG5cdFx0XHR0ZXh0dXJlLndyYXBTID0gdGV4RGF0YS53cmFwUyAhPT0gdW5kZWZpbmVkID8gdGV4RGF0YS53cmFwUyA6IENsYW1wVG9FZGdlV3JhcHBpbmc7XG5cdFx0XHR0ZXh0dXJlLndyYXBUID0gdGV4RGF0YS53cmFwVCAhPT0gdW5kZWZpbmVkID8gdGV4RGF0YS53cmFwVCA6IENsYW1wVG9FZGdlV3JhcHBpbmc7XG5cblx0XHRcdHRleHR1cmUubWFnRmlsdGVyID0gdGV4RGF0YS5tYWdGaWx0ZXIgIT09IHVuZGVmaW5lZCA/IHRleERhdGEubWFnRmlsdGVyIDogTGluZWFyRmlsdGVyO1xuXHRcdFx0dGV4dHVyZS5taW5GaWx0ZXIgPSB0ZXhEYXRhLm1pbkZpbHRlciAhPT0gdW5kZWZpbmVkID8gdGV4RGF0YS5taW5GaWx0ZXIgOiBMaW5lYXJGaWx0ZXI7XG5cblx0XHRcdHRleHR1cmUuYW5pc290cm9weSA9IHRleERhdGEuYW5pc290cm9weSAhPT0gdW5kZWZpbmVkID8gdGV4RGF0YS5hbmlzb3Ryb3B5IDogMTtcblxuXHRcdFx0aWYgKCB0ZXhEYXRhLmNvbG9yU3BhY2UgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0ZXh0dXJlLmNvbG9yU3BhY2UgPSB0ZXhEYXRhLmNvbG9yU3BhY2U7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0ZXhEYXRhLmZsaXBZICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGV4dHVyZS5mbGlwWSA9IHRleERhdGEuZmxpcFk7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0ZXhEYXRhLmZvcm1hdCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHRleHR1cmUuZm9ybWF0ID0gdGV4RGF0YS5mb3JtYXQ7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0ZXhEYXRhLnR5cGUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0ZXh0dXJlLnR5cGUgPSB0ZXhEYXRhLnR5cGU7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0ZXhEYXRhLm1pcG1hcHMgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0ZXh0dXJlLm1pcG1hcHMgPSB0ZXhEYXRhLm1pcG1hcHM7XG5cdFx0XHRcdHRleHR1cmUubWluRmlsdGVyID0gTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyOyAvLyBwcmVzdW1hYmx5Li4uXG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0ZXhEYXRhLm1pcG1hcENvdW50ID09PSAxICkge1xuXG5cdFx0XHRcdHRleHR1cmUubWluRmlsdGVyID0gTGluZWFyRmlsdGVyO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGV4RGF0YS5nZW5lcmF0ZU1pcG1hcHMgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IHRleERhdGEuZ2VuZXJhdGVNaXBtYXBzO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggdGV4dHVyZSwgdGV4RGF0YSApO1xuXG5cdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xuXG5cblx0XHRyZXR1cm4gdGV4dHVyZTtcblxuXHR9XG5cbn1cblxuY2xhc3MgVGV4dHVyZUxvYWRlciBleHRlbmRzIExvYWRlciB7XG5cblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XG5cblx0XHRzdXBlciggbWFuYWdlciApO1xuXG5cdH1cblxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcblxuXHRcdGNvbnN0IHRleHR1cmUgPSBuZXcgVGV4dHVyZSgpO1xuXG5cdFx0Y29uc3QgbG9hZGVyID0gbmV3IEltYWdlTG9hZGVyKCB0aGlzLm1hbmFnZXIgKTtcblx0XHRsb2FkZXIuc2V0Q3Jvc3NPcmlnaW4oIHRoaXMuY3Jvc3NPcmlnaW4gKTtcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XG5cblx0XHRsb2FkZXIubG9hZCggdXJsLCBmdW5jdGlvbiAoIGltYWdlICkge1xuXG5cdFx0XHR0ZXh0dXJlLmltYWdlID0gaW1hZ2U7XG5cdFx0XHR0ZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdFx0aWYgKCBvbkxvYWQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRvbkxvYWQoIHRleHR1cmUgKTtcblxuXHRcdFx0fVxuXG5cdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xuXG5cdFx0cmV0dXJuIHRleHR1cmU7XG5cblx0fVxuXG59XG5cbmNsYXNzIExpZ2h0IGV4dGVuZHMgT2JqZWN0M0Qge1xuXG5cdGNvbnN0cnVjdG9yKCBjb2xvciwgaW50ZW5zaXR5ID0gMSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTGlnaHQgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0xpZ2h0JztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIGNvbG9yICk7XG5cdFx0dGhpcy5pbnRlbnNpdHkgPSBpbnRlbnNpdHk7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHQvLyBFbXB0eSBoZXJlIGluIGJhc2UgY2xhc3M7IHNvbWUgc3ViY2xhc3NlcyBvdmVycmlkZS5cblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcblx0XHR0aGlzLmludGVuc2l0eSA9IHNvdXJjZS5pbnRlbnNpdHk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCBtZXRhICkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xuXG5cdFx0ZGF0YS5vYmplY3QuY29sb3IgPSB0aGlzLmNvbG9yLmdldEhleCgpO1xuXHRcdGRhdGEub2JqZWN0LmludGVuc2l0eSA9IHRoaXMuaW50ZW5zaXR5O1xuXG5cdFx0aWYgKCB0aGlzLmdyb3VuZENvbG9yICE9PSB1bmRlZmluZWQgKSBkYXRhLm9iamVjdC5ncm91bmRDb2xvciA9IHRoaXMuZ3JvdW5kQ29sb3IuZ2V0SGV4KCk7XG5cblx0XHRpZiAoIHRoaXMuZGlzdGFuY2UgIT09IHVuZGVmaW5lZCApIGRhdGEub2JqZWN0LmRpc3RhbmNlID0gdGhpcy5kaXN0YW5jZTtcblx0XHRpZiAoIHRoaXMuYW5nbGUgIT09IHVuZGVmaW5lZCApIGRhdGEub2JqZWN0LmFuZ2xlID0gdGhpcy5hbmdsZTtcblx0XHRpZiAoIHRoaXMuZGVjYXkgIT09IHVuZGVmaW5lZCApIGRhdGEub2JqZWN0LmRlY2F5ID0gdGhpcy5kZWNheTtcblx0XHRpZiAoIHRoaXMucGVudW1icmEgIT09IHVuZGVmaW5lZCApIGRhdGEub2JqZWN0LnBlbnVtYnJhID0gdGhpcy5wZW51bWJyYTtcblxuXHRcdGlmICggdGhpcy5zaGFkb3cgIT09IHVuZGVmaW5lZCApIGRhdGEub2JqZWN0LnNoYWRvdyA9IHRoaXMuc2hhZG93LnRvSlNPTigpO1xuXHRcdGlmICggdGhpcy50YXJnZXQgIT09IHVuZGVmaW5lZCApIGRhdGEub2JqZWN0LnRhcmdldCA9IHRoaXMudGFyZ2V0LnV1aWQ7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cbn1cblxuY2xhc3MgSGVtaXNwaGVyZUxpZ2h0IGV4dGVuZHMgTGlnaHQge1xuXG5cdGNvbnN0cnVjdG9yKCBza3lDb2xvciwgZ3JvdW5kQ29sb3IsIGludGVuc2l0eSApIHtcblxuXHRcdHN1cGVyKCBza3lDb2xvciwgaW50ZW5zaXR5ICk7XG5cblx0XHR0aGlzLmlzSGVtaXNwaGVyZUxpZ2h0ID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdIZW1pc3BoZXJlTGlnaHQnO1xuXG5cdFx0dGhpcy5wb3NpdGlvbi5jb3B5KCBPYmplY3QzRC5ERUZBVUxUX1VQICk7XG5cdFx0dGhpcy51cGRhdGVNYXRyaXgoKTtcblxuXHRcdHRoaXMuZ3JvdW5kQ29sb3IgPSBuZXcgQ29sb3IoIGdyb3VuZENvbG9yICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcblxuXHRcdHRoaXMuZ3JvdW5kQ29sb3IuY29weSggc291cmNlLmdyb3VuZENvbG9yICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY29uc3QgX3Byb2pTY3JlZW5NYXRyaXgkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF9saWdodFBvc2l0aW9uV29ybGQkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9sb29rVGFyZ2V0JDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNsYXNzIExpZ2h0U2hhZG93IHtcblxuXHRjb25zdHJ1Y3RvciggY2FtZXJhICkge1xuXG5cdFx0dGhpcy5jYW1lcmEgPSBjYW1lcmE7XG5cblx0XHR0aGlzLmludGVuc2l0eSA9IDE7XG5cblx0XHR0aGlzLmJpYXMgPSAwO1xuXHRcdHRoaXMubm9ybWFsQmlhcyA9IDA7XG5cdFx0dGhpcy5yYWRpdXMgPSAxO1xuXHRcdHRoaXMuYmx1clNhbXBsZXMgPSA4O1xuXG5cdFx0dGhpcy5tYXBTaXplID0gbmV3IFZlY3RvcjIoIDUxMiwgNTEyICk7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cdFx0dGhpcy5tYXBQYXNzID0gbnVsbDtcblx0XHR0aGlzLm1hdHJpeCA9IG5ldyBNYXRyaXg0KCk7XG5cblx0XHR0aGlzLmF1dG9VcGRhdGUgPSB0cnVlO1xuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSBmYWxzZTtcblxuXHRcdHRoaXMuX2ZydXN0dW0gPSBuZXcgRnJ1c3R1bSgpO1xuXHRcdHRoaXMuX2ZyYW1lRXh0ZW50cyA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XG5cblx0XHR0aGlzLl92aWV3cG9ydENvdW50ID0gMTtcblxuXHRcdHRoaXMuX3ZpZXdwb3J0cyA9IFtcblxuXHRcdFx0bmV3IFZlY3RvcjQoIDAsIDAsIDEsIDEgKVxuXG5cdFx0XTtcblxuXHR9XG5cblx0Z2V0Vmlld3BvcnRDb3VudCgpIHtcblxuXHRcdHJldHVybiB0aGlzLl92aWV3cG9ydENvdW50O1xuXG5cdH1cblxuXHRnZXRGcnVzdHVtKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX2ZydXN0dW07XG5cblx0fVxuXG5cdHVwZGF0ZU1hdHJpY2VzKCBsaWdodCApIHtcblxuXHRcdGNvbnN0IHNoYWRvd0NhbWVyYSA9IHRoaXMuY2FtZXJhO1xuXHRcdGNvbnN0IHNoYWRvd01hdHJpeCA9IHRoaXMubWF0cml4O1xuXG5cdFx0X2xpZ2h0UG9zaXRpb25Xb3JsZCQxLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcblx0XHRzaGFkb3dDYW1lcmEucG9zaXRpb24uY29weSggX2xpZ2h0UG9zaXRpb25Xb3JsZCQxICk7XG5cblx0XHRfbG9va1RhcmdldCQxLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQudGFyZ2V0Lm1hdHJpeFdvcmxkICk7XG5cdFx0c2hhZG93Q2FtZXJhLmxvb2tBdCggX2xvb2tUYXJnZXQkMSApO1xuXHRcdHNoYWRvd0NhbWVyYS51cGRhdGVNYXRyaXhXb3JsZCgpO1xuXG5cdFx0X3Byb2pTY3JlZW5NYXRyaXgkMS5tdWx0aXBseU1hdHJpY2VzKCBzaGFkb3dDYW1lcmEucHJvamVjdGlvbk1hdHJpeCwgc2hhZG93Q2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSApO1xuXHRcdHRoaXMuX2ZydXN0dW0uc2V0RnJvbVByb2plY3Rpb25NYXRyaXgoIF9wcm9qU2NyZWVuTWF0cml4JDEgKTtcblxuXHRcdHNoYWRvd01hdHJpeC5zZXQoXG5cdFx0XHQwLjUsIDAuMCwgMC4wLCAwLjUsXG5cdFx0XHQwLjAsIDAuNSwgMC4wLCAwLjUsXG5cdFx0XHQwLjAsIDAuMCwgMC41LCAwLjUsXG5cdFx0XHQwLjAsIDAuMCwgMC4wLCAxLjBcblx0XHQpO1xuXG5cdFx0c2hhZG93TWF0cml4Lm11bHRpcGx5KCBfcHJvalNjcmVlbk1hdHJpeCQxICk7XG5cblx0fVxuXG5cdGdldFZpZXdwb3J0KCB2aWV3cG9ydEluZGV4ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3ZpZXdwb3J0c1sgdmlld3BvcnRJbmRleCBdO1xuXG5cdH1cblxuXHRnZXRGcmFtZUV4dGVudHMoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fZnJhbWVFeHRlbnRzO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0aWYgKCB0aGlzLm1hcCApIHtcblxuXHRcdFx0dGhpcy5tYXAuZGlzcG9zZSgpO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm1hcFBhc3MgKSB7XG5cblx0XHRcdHRoaXMubWFwUGFzcy5kaXNwb3NlKCk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHRoaXMuY2FtZXJhID0gc291cmNlLmNhbWVyYS5jbG9uZSgpO1xuXG5cdFx0dGhpcy5pbnRlbnNpdHkgPSBzb3VyY2UuaW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5iaWFzID0gc291cmNlLmJpYXM7XG5cdFx0dGhpcy5yYWRpdXMgPSBzb3VyY2UucmFkaXVzO1xuXG5cdFx0dGhpcy5tYXBTaXplLmNvcHkoIHNvdXJjZS5tYXBTaXplICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IG9iamVjdCA9IHt9O1xuXG5cdFx0aWYgKCB0aGlzLmludGVuc2l0eSAhPT0gMSApIG9iamVjdC5pbnRlbnNpdHkgPSB0aGlzLmludGVuc2l0eTtcblx0XHRpZiAoIHRoaXMuYmlhcyAhPT0gMCApIG9iamVjdC5iaWFzID0gdGhpcy5iaWFzO1xuXHRcdGlmICggdGhpcy5ub3JtYWxCaWFzICE9PSAwICkgb2JqZWN0Lm5vcm1hbEJpYXMgPSB0aGlzLm5vcm1hbEJpYXM7XG5cdFx0aWYgKCB0aGlzLnJhZGl1cyAhPT0gMSApIG9iamVjdC5yYWRpdXMgPSB0aGlzLnJhZGl1cztcblx0XHRpZiAoIHRoaXMubWFwU2l6ZS54ICE9PSA1MTIgfHwgdGhpcy5tYXBTaXplLnkgIT09IDUxMiApIG9iamVjdC5tYXBTaXplID0gdGhpcy5tYXBTaXplLnRvQXJyYXkoKTtcblxuXHRcdG9iamVjdC5jYW1lcmEgPSB0aGlzLmNhbWVyYS50b0pTT04oIGZhbHNlICkub2JqZWN0O1xuXHRcdGRlbGV0ZSBvYmplY3QuY2FtZXJhLm1hdHJpeDtcblxuXHRcdHJldHVybiBvYmplY3Q7XG5cblx0fVxuXG59XG5cbmNsYXNzIFNwb3RMaWdodFNoYWRvdyBleHRlbmRzIExpZ2h0U2hhZG93IHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoIDUwLCAxLCAwLjUsIDUwMCApICk7XG5cblx0XHR0aGlzLmlzU3BvdExpZ2h0U2hhZG93ID0gdHJ1ZTtcblxuXHRcdHRoaXMuZm9jdXMgPSAxO1xuXG5cdH1cblxuXHR1cGRhdGVNYXRyaWNlcyggbGlnaHQgKSB7XG5cblx0XHRjb25zdCBjYW1lcmEgPSB0aGlzLmNhbWVyYTtcblxuXHRcdGNvbnN0IGZvdiA9IFJBRDJERUcgKiAyICogbGlnaHQuYW5nbGUgKiB0aGlzLmZvY3VzO1xuXHRcdGNvbnN0IGFzcGVjdCA9IHRoaXMubWFwU2l6ZS53aWR0aCAvIHRoaXMubWFwU2l6ZS5oZWlnaHQ7XG5cdFx0Y29uc3QgZmFyID0gbGlnaHQuZGlzdGFuY2UgfHwgY2FtZXJhLmZhcjtcblxuXHRcdGlmICggZm92ICE9PSBjYW1lcmEuZm92IHx8IGFzcGVjdCAhPT0gY2FtZXJhLmFzcGVjdCB8fCBmYXIgIT09IGNhbWVyYS5mYXIgKSB7XG5cblx0XHRcdGNhbWVyYS5mb3YgPSBmb3Y7XG5cdFx0XHRjYW1lcmEuYXNwZWN0ID0gYXNwZWN0O1xuXHRcdFx0Y2FtZXJhLmZhciA9IGZhcjtcblx0XHRcdGNhbWVyYS51cGRhdGVQcm9qZWN0aW9uTWF0cml4KCk7XG5cblx0XHR9XG5cblx0XHRzdXBlci51cGRhdGVNYXRyaWNlcyggbGlnaHQgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLmZvY3VzID0gc291cmNlLmZvY3VzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIFNwb3RMaWdodCBleHRlbmRzIExpZ2h0IHtcblxuXHRjb25zdHJ1Y3RvciggY29sb3IsIGludGVuc2l0eSwgZGlzdGFuY2UgPSAwLCBhbmdsZSA9IE1hdGguUEkgLyAzLCBwZW51bWJyYSA9IDAsIGRlY2F5ID0gMiApIHtcblxuXHRcdHN1cGVyKCBjb2xvciwgaW50ZW5zaXR5ICk7XG5cblx0XHR0aGlzLmlzU3BvdExpZ2h0ID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdTcG90TGlnaHQnO1xuXG5cdFx0dGhpcy5wb3NpdGlvbi5jb3B5KCBPYmplY3QzRC5ERUZBVUxUX1VQICk7XG5cdFx0dGhpcy51cGRhdGVNYXRyaXgoKTtcblxuXHRcdHRoaXMudGFyZ2V0ID0gbmV3IE9iamVjdDNEKCk7XG5cblx0XHR0aGlzLmRpc3RhbmNlID0gZGlzdGFuY2U7XG5cdFx0dGhpcy5hbmdsZSA9IGFuZ2xlO1xuXHRcdHRoaXMucGVudW1icmEgPSBwZW51bWJyYTtcblx0XHR0aGlzLmRlY2F5ID0gZGVjYXk7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLnNoYWRvdyA9IG5ldyBTcG90TGlnaHRTaGFkb3coKTtcblxuXHR9XG5cblx0Z2V0IHBvd2VyKCkge1xuXG5cdFx0Ly8gY29tcHV0ZSB0aGUgbGlnaHQncyBsdW1pbm91cyBwb3dlciAoaW4gbHVtZW5zKSBmcm9tIGl0cyBpbnRlbnNpdHkgKGluIGNhbmRlbGEpXG5cdFx0Ly8gYnkgY29udmVudGlvbiBmb3IgYSBzcG90bGlnaHQsIGx1bWlub3VzIHBvd2VyIChsbSkgPSDPgCAqIGx1bWlub3VzIGludGVuc2l0eSAoY2QpXG5cdFx0cmV0dXJuIHRoaXMuaW50ZW5zaXR5ICogTWF0aC5QSTtcblxuXHR9XG5cblx0c2V0IHBvd2VyKCBwb3dlciApIHtcblxuXHRcdC8vIHNldCB0aGUgbGlnaHQncyBpbnRlbnNpdHkgKGluIGNhbmRlbGEpIGZyb20gdGhlIGRlc2lyZWQgbHVtaW5vdXMgcG93ZXIgKGluIGx1bWVucylcblx0XHR0aGlzLmludGVuc2l0eSA9IHBvd2VyIC8gTWF0aC5QSTtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuc2hhZG93LmRpc3Bvc2UoKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0dGhpcy5kaXN0YW5jZSA9IHNvdXJjZS5kaXN0YW5jZTtcblx0XHR0aGlzLmFuZ2xlID0gc291cmNlLmFuZ2xlO1xuXHRcdHRoaXMucGVudW1icmEgPSBzb3VyY2UucGVudW1icmE7XG5cdFx0dGhpcy5kZWNheSA9IHNvdXJjZS5kZWNheTtcblxuXHRcdHRoaXMudGFyZ2V0ID0gc291cmNlLnRhcmdldC5jbG9uZSgpO1xuXG5cdFx0dGhpcy5zaGFkb3cgPSBzb3VyY2Uuc2hhZG93LmNsb25lKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY29uc3QgX3Byb2pTY3JlZW5NYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfbGlnaHRQb3NpdGlvbldvcmxkID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2xvb2tUYXJnZXQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNsYXNzIFBvaW50TGlnaHRTaGFkb3cgZXh0ZW5kcyBMaWdodFNoYWRvdyB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHRzdXBlciggbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCA5MCwgMSwgMC41LCA1MDAgKSApO1xuXG5cdFx0dGhpcy5pc1BvaW50TGlnaHRTaGFkb3cgPSB0cnVlO1xuXG5cdFx0dGhpcy5fZnJhbWVFeHRlbnRzID0gbmV3IFZlY3RvcjIoIDQsIDIgKTtcblxuXHRcdHRoaXMuX3ZpZXdwb3J0Q291bnQgPSA2O1xuXG5cdFx0dGhpcy5fdmlld3BvcnRzID0gW1xuXHRcdFx0Ly8gVGhlc2Ugdmlld3BvcnRzIG1hcCBhIGN1YmUtbWFwIG9udG8gYSAyRCB0ZXh0dXJlIHdpdGggdGhlXG5cdFx0XHQvLyBmb2xsb3dpbmcgb3JpZW50YXRpb246XG5cdFx0XHQvL1xuXHRcdFx0Ly8gIHh6WFpcblx0XHRcdC8vICAgeSBZXG5cdFx0XHQvL1xuXHRcdFx0Ly8gWCAtIFBvc2l0aXZlIHggZGlyZWN0aW9uXG5cdFx0XHQvLyB4IC0gTmVnYXRpdmUgeCBkaXJlY3Rpb25cblx0XHRcdC8vIFkgLSBQb3NpdGl2ZSB5IGRpcmVjdGlvblxuXHRcdFx0Ly8geSAtIE5lZ2F0aXZlIHkgZGlyZWN0aW9uXG5cdFx0XHQvLyBaIC0gUG9zaXRpdmUgeiBkaXJlY3Rpb25cblx0XHRcdC8vIHogLSBOZWdhdGl2ZSB6IGRpcmVjdGlvblxuXG5cdFx0XHQvLyBwb3NpdGl2ZSBYXG5cdFx0XHRuZXcgVmVjdG9yNCggMiwgMSwgMSwgMSApLFxuXHRcdFx0Ly8gbmVnYXRpdmUgWFxuXHRcdFx0bmV3IFZlY3RvcjQoIDAsIDEsIDEsIDEgKSxcblx0XHRcdC8vIHBvc2l0aXZlIFpcblx0XHRcdG5ldyBWZWN0b3I0KCAzLCAxLCAxLCAxICksXG5cdFx0XHQvLyBuZWdhdGl2ZSBaXG5cdFx0XHRuZXcgVmVjdG9yNCggMSwgMSwgMSwgMSApLFxuXHRcdFx0Ly8gcG9zaXRpdmUgWVxuXHRcdFx0bmV3IFZlY3RvcjQoIDMsIDAsIDEsIDEgKSxcblx0XHRcdC8vIG5lZ2F0aXZlIFlcblx0XHRcdG5ldyBWZWN0b3I0KCAxLCAwLCAxLCAxIClcblx0XHRdO1xuXG5cdFx0dGhpcy5fY3ViZURpcmVjdGlvbnMgPSBbXG5cdFx0XHRuZXcgVmVjdG9yMyggMSwgMCwgMCApLCBuZXcgVmVjdG9yMyggLSAxLCAwLCAwICksIG5ldyBWZWN0b3IzKCAwLCAwLCAxICksXG5cdFx0XHRuZXcgVmVjdG9yMyggMCwgMCwgLSAxICksIG5ldyBWZWN0b3IzKCAwLCAxLCAwICksIG5ldyBWZWN0b3IzKCAwLCAtIDEsIDAgKVxuXHRcdF07XG5cblx0XHR0aGlzLl9jdWJlVXBzID0gW1xuXHRcdFx0bmV3IFZlY3RvcjMoIDAsIDEsIDAgKSwgbmV3IFZlY3RvcjMoIDAsIDEsIDAgKSwgbmV3IFZlY3RvcjMoIDAsIDEsIDAgKSxcblx0XHRcdG5ldyBWZWN0b3IzKCAwLCAxLCAwICksIG5ldyBWZWN0b3IzKCAwLCAwLCAxICksXHRuZXcgVmVjdG9yMyggMCwgMCwgLSAxIClcblx0XHRdO1xuXG5cdH1cblxuXHR1cGRhdGVNYXRyaWNlcyggbGlnaHQsIHZpZXdwb3J0SW5kZXggPSAwICkge1xuXG5cdFx0Y29uc3QgY2FtZXJhID0gdGhpcy5jYW1lcmE7XG5cdFx0Y29uc3Qgc2hhZG93TWF0cml4ID0gdGhpcy5tYXRyaXg7XG5cblx0XHRjb25zdCBmYXIgPSBsaWdodC5kaXN0YW5jZSB8fCBjYW1lcmEuZmFyO1xuXG5cdFx0aWYgKCBmYXIgIT09IGNhbWVyYS5mYXIgKSB7XG5cblx0XHRcdGNhbWVyYS5mYXIgPSBmYXI7XG5cdFx0XHRjYW1lcmEudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXG5cdFx0fVxuXG5cdFx0X2xpZ2h0UG9zaXRpb25Xb3JsZC5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cdFx0Y2FtZXJhLnBvc2l0aW9uLmNvcHkoIF9saWdodFBvc2l0aW9uV29ybGQgKTtcblxuXHRcdF9sb29rVGFyZ2V0LmNvcHkoIGNhbWVyYS5wb3NpdGlvbiApO1xuXHRcdF9sb29rVGFyZ2V0LmFkZCggdGhpcy5fY3ViZURpcmVjdGlvbnNbIHZpZXdwb3J0SW5kZXggXSApO1xuXHRcdGNhbWVyYS51cC5jb3B5KCB0aGlzLl9jdWJlVXBzWyB2aWV3cG9ydEluZGV4IF0gKTtcblx0XHRjYW1lcmEubG9va0F0KCBfbG9va1RhcmdldCApO1xuXHRcdGNhbWVyYS51cGRhdGVNYXRyaXhXb3JsZCgpO1xuXG5cdFx0c2hhZG93TWF0cml4Lm1ha2VUcmFuc2xhdGlvbiggLSBfbGlnaHRQb3NpdGlvbldvcmxkLngsIC0gX2xpZ2h0UG9zaXRpb25Xb3JsZC55LCAtIF9saWdodFBvc2l0aW9uV29ybGQueiApO1xuXG5cdFx0X3Byb2pTY3JlZW5NYXRyaXgubXVsdGlwbHlNYXRyaWNlcyggY2FtZXJhLnByb2plY3Rpb25NYXRyaXgsIGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UgKTtcblx0XHR0aGlzLl9mcnVzdHVtLnNldEZyb21Qcm9qZWN0aW9uTWF0cml4KCBfcHJvalNjcmVlbk1hdHJpeCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBQb2ludExpZ2h0IGV4dGVuZHMgTGlnaHQge1xuXG5cdGNvbnN0cnVjdG9yKCBjb2xvciwgaW50ZW5zaXR5LCBkaXN0YW5jZSA9IDAsIGRlY2F5ID0gMiApIHtcblxuXHRcdHN1cGVyKCBjb2xvciwgaW50ZW5zaXR5ICk7XG5cblx0XHR0aGlzLmlzUG9pbnRMaWdodCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnUG9pbnRMaWdodCc7XG5cblx0XHR0aGlzLmRpc3RhbmNlID0gZGlzdGFuY2U7XG5cdFx0dGhpcy5kZWNheSA9IGRlY2F5O1xuXG5cdFx0dGhpcy5zaGFkb3cgPSBuZXcgUG9pbnRMaWdodFNoYWRvdygpO1xuXG5cdH1cblxuXHRnZXQgcG93ZXIoKSB7XG5cblx0XHQvLyBjb21wdXRlIHRoZSBsaWdodCdzIGx1bWlub3VzIHBvd2VyIChpbiBsdW1lbnMpIGZyb20gaXRzIGludGVuc2l0eSAoaW4gY2FuZGVsYSlcblx0XHQvLyBmb3IgYW4gaXNvdHJvcGljIGxpZ2h0IHNvdXJjZSwgbHVtaW5vdXMgcG93ZXIgKGxtKSA9IDQgz4AgbHVtaW5vdXMgaW50ZW5zaXR5IChjZClcblx0XHRyZXR1cm4gdGhpcy5pbnRlbnNpdHkgKiA0ICogTWF0aC5QSTtcblxuXHR9XG5cblx0c2V0IHBvd2VyKCBwb3dlciApIHtcblxuXHRcdC8vIHNldCB0aGUgbGlnaHQncyBpbnRlbnNpdHkgKGluIGNhbmRlbGEpIGZyb20gdGhlIGRlc2lyZWQgbHVtaW5vdXMgcG93ZXIgKGluIGx1bWVucylcblx0XHR0aGlzLmludGVuc2l0eSA9IHBvd2VyIC8gKCA0ICogTWF0aC5QSSApO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5zaGFkb3cuZGlzcG9zZSgpO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XG5cblx0XHR0aGlzLmRpc3RhbmNlID0gc291cmNlLmRpc3RhbmNlO1xuXHRcdHRoaXMuZGVjYXkgPSBzb3VyY2UuZGVjYXk7XG5cblx0XHR0aGlzLnNoYWRvdyA9IHNvdXJjZS5zaGFkb3cuY2xvbmUoKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBEaXJlY3Rpb25hbExpZ2h0U2hhZG93IGV4dGVuZHMgTGlnaHRTaGFkb3cge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoIG5ldyBPcnRob2dyYXBoaWNDYW1lcmEoIC0gNSwgNSwgNSwgLSA1LCAwLjUsIDUwMCApICk7XG5cblx0XHR0aGlzLmlzRGlyZWN0aW9uYWxMaWdodFNoYWRvdyA9IHRydWU7XG5cblx0fVxuXG59XG5cbmNsYXNzIERpcmVjdGlvbmFsTGlnaHQgZXh0ZW5kcyBMaWdodCB7XG5cblx0Y29uc3RydWN0b3IoIGNvbG9yLCBpbnRlbnNpdHkgKSB7XG5cblx0XHRzdXBlciggY29sb3IsIGludGVuc2l0eSApO1xuXG5cdFx0dGhpcy5pc0RpcmVjdGlvbmFsTGlnaHQgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0RpcmVjdGlvbmFsTGlnaHQnO1xuXG5cdFx0dGhpcy5wb3NpdGlvbi5jb3B5KCBPYmplY3QzRC5ERUZBVUxUX1VQICk7XG5cdFx0dGhpcy51cGRhdGVNYXRyaXgoKTtcblxuXHRcdHRoaXMudGFyZ2V0ID0gbmV3IE9iamVjdDNEKCk7XG5cblx0XHR0aGlzLnNoYWRvdyA9IG5ldyBEaXJlY3Rpb25hbExpZ2h0U2hhZG93KCk7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLnNoYWRvdy5kaXNwb3NlKCk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy50YXJnZXQgPSBzb3VyY2UudGFyZ2V0LmNsb25lKCk7XG5cdFx0dGhpcy5zaGFkb3cgPSBzb3VyY2Uuc2hhZG93LmNsb25lKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgQW1iaWVudExpZ2h0IGV4dGVuZHMgTGlnaHQge1xuXG5cdGNvbnN0cnVjdG9yKCBjb2xvciwgaW50ZW5zaXR5ICkge1xuXG5cdFx0c3VwZXIoIGNvbG9yLCBpbnRlbnNpdHkgKTtcblxuXHRcdHRoaXMuaXNBbWJpZW50TGlnaHQgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0FtYmllbnRMaWdodCc7XG5cblx0fVxuXG59XG5cbmNsYXNzIFJlY3RBcmVhTGlnaHQgZXh0ZW5kcyBMaWdodCB7XG5cblx0Y29uc3RydWN0b3IoIGNvbG9yLCBpbnRlbnNpdHksIHdpZHRoID0gMTAsIGhlaWdodCA9IDEwICkge1xuXG5cdFx0c3VwZXIoIGNvbG9yLCBpbnRlbnNpdHkgKTtcblxuXHRcdHRoaXMuaXNSZWN0QXJlYUxpZ2h0ID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdSZWN0QXJlYUxpZ2h0JztcblxuXHRcdHRoaXMud2lkdGggPSB3aWR0aDtcblx0XHR0aGlzLmhlaWdodCA9IGhlaWdodDtcblxuXHR9XG5cblx0Z2V0IHBvd2VyKCkge1xuXG5cdFx0Ly8gY29tcHV0ZSB0aGUgbGlnaHQncyBsdW1pbm91cyBwb3dlciAoaW4gbHVtZW5zKSBmcm9tIGl0cyBpbnRlbnNpdHkgKGluIG5pdHMpXG5cdFx0cmV0dXJuIHRoaXMuaW50ZW5zaXR5ICogdGhpcy53aWR0aCAqIHRoaXMuaGVpZ2h0ICogTWF0aC5QSTtcblxuXHR9XG5cblx0c2V0IHBvd2VyKCBwb3dlciApIHtcblxuXHRcdC8vIHNldCB0aGUgbGlnaHQncyBpbnRlbnNpdHkgKGluIG5pdHMpIGZyb20gdGhlIGRlc2lyZWQgbHVtaW5vdXMgcG93ZXIgKGluIGx1bWVucylcblx0XHR0aGlzLmludGVuc2l0eSA9IHBvd2VyIC8gKCB0aGlzLndpZHRoICogdGhpcy5oZWlnaHQgKiBNYXRoLlBJICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy53aWR0aCA9IHNvdXJjZS53aWR0aDtcblx0XHR0aGlzLmhlaWdodCA9IHNvdXJjZS5oZWlnaHQ7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCBtZXRhICkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xuXG5cdFx0ZGF0YS5vYmplY3Qud2lkdGggPSB0aGlzLndpZHRoO1xuXHRcdGRhdGEub2JqZWN0LmhlaWdodCA9IHRoaXMuaGVpZ2h0O1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbi8qKlxuICogUHJpbWFyeSByZWZlcmVuY2U6XG4gKiAgIGh0dHBzOi8vZ3JhcGhpY3Muc3RhbmZvcmQuZWR1L3BhcGVycy9lbnZtYXAvZW52bWFwLnBkZlxuICpcbiAqIFNlY29uZGFyeSByZWZlcmVuY2U6XG4gKiAgIGh0dHBzOi8vd3d3LnBwc2xvYW4ub3JnL3B1YmxpY2F0aW9ucy9TdHVwaWRTSDM2LnBkZlxuICovXG5cbi8vIDMtYmFuZCBTSCBkZWZpbmVkIGJ5IDkgY29lZmZpY2llbnRzXG5cbmNsYXNzIFNwaGVyaWNhbEhhcm1vbmljczMge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0dGhpcy5pc1NwaGVyaWNhbEhhcm1vbmljczMgPSB0cnVlO1xuXG5cdFx0dGhpcy5jb2VmZmljaWVudHMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuY29lZmZpY2llbnRzLnB1c2goIG5ldyBWZWN0b3IzKCkgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0c2V0KCBjb2VmZmljaWVudHMgKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmNvZWZmaWNpZW50c1sgaSBdLmNvcHkoIGNvZWZmaWNpZW50c1sgaSBdICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0emVybygpIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0uc2V0KCAwLCAwLCAwICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Ly8gZ2V0IHRoZSByYWRpYW5jZSBpbiB0aGUgZGlyZWN0aW9uIG9mIHRoZSBub3JtYWxcblx0Ly8gdGFyZ2V0IGlzIGEgVmVjdG9yM1xuXHRnZXRBdCggbm9ybWFsLCB0YXJnZXQgKSB7XG5cblx0XHQvLyBub3JtYWwgaXMgYXNzdW1lZCB0byBiZSB1bml0IGxlbmd0aFxuXG5cdFx0Y29uc3QgeCA9IG5vcm1hbC54LCB5ID0gbm9ybWFsLnksIHogPSBub3JtYWwuejtcblxuXHRcdGNvbnN0IGNvZWZmID0gdGhpcy5jb2VmZmljaWVudHM7XG5cblx0XHQvLyBiYW5kIDBcblx0XHR0YXJnZXQuY29weSggY29lZmZbIDAgXSApLm11bHRpcGx5U2NhbGFyKCAwLjI4MjA5NSApO1xuXG5cdFx0Ly8gYmFuZCAxXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDEgXSwgMC40ODg2MDMgKiB5ICk7XG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDIgXSwgMC40ODg2MDMgKiB6ICk7XG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDMgXSwgMC40ODg2MDMgKiB4ICk7XG5cblx0XHQvLyBiYW5kIDJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNCBdLCAxLjA5MjU0OCAqICggeCAqIHkgKSApO1xuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA1IF0sIDEuMDkyNTQ4ICogKCB5ICogeiApICk7XG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDYgXSwgMC4zMTUzOTIgKiAoIDMuMCAqIHogKiB6IC0gMS4wICkgKTtcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNyBdLCAxLjA5MjU0OCAqICggeCAqIHogKSApO1xuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA4IF0sIDAuNTQ2Mjc0ICogKCB4ICogeCAtIHkgKiB5ICkgKTtcblxuXHRcdHJldHVybiB0YXJnZXQ7XG5cblx0fVxuXG5cdC8vIGdldCB0aGUgaXJyYWRpYW5jZSAocmFkaWFuY2UgY29udm9sdmVkIHdpdGggY29zaW5lIGxvYmUpIGluIHRoZSBkaXJlY3Rpb24gb2YgdGhlIG5vcm1hbFxuXHQvLyB0YXJnZXQgaXMgYSBWZWN0b3IzXG5cdC8vIGh0dHBzOi8vZ3JhcGhpY3Muc3RhbmZvcmQuZWR1L3BhcGVycy9lbnZtYXAvZW52bWFwLnBkZlxuXHRnZXRJcnJhZGlhbmNlQXQoIG5vcm1hbCwgdGFyZ2V0ICkge1xuXG5cdFx0Ly8gbm9ybWFsIGlzIGFzc3VtZWQgdG8gYmUgdW5pdCBsZW5ndGhcblxuXHRcdGNvbnN0IHggPSBub3JtYWwueCwgeSA9IG5vcm1hbC55LCB6ID0gbm9ybWFsLno7XG5cblx0XHRjb25zdCBjb2VmZiA9IHRoaXMuY29lZmZpY2llbnRzO1xuXG5cdFx0Ly8gYmFuZCAwXG5cdFx0dGFyZ2V0LmNvcHkoIGNvZWZmWyAwIF0gKS5tdWx0aXBseVNjYWxhciggMC44ODYyMjcgKTsgLy8gz4AgKiAwLjI4MjA5NVxuXG5cdFx0Ly8gYmFuZCAxXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDEgXSwgMi4wICogMC41MTE2NjQgKiB5ICk7IC8vICggMiAqIM+AIC8gMyApICogMC40ODg2MDNcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgMiBdLCAyLjAgKiAwLjUxMTY2NCAqIHogKTtcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgMyBdLCAyLjAgKiAwLjUxMTY2NCAqIHggKTtcblxuXHRcdC8vIGJhbmQgMlxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA0IF0sIDIuMCAqIDAuNDI5MDQzICogeCAqIHkgKTsgLy8gKCDPgCAvIDQgKSAqIDEuMDkyNTQ4XG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDUgXSwgMi4wICogMC40MjkwNDMgKiB5ICogeiApO1xuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA2IF0sIDAuNzQzMTI1ICogeiAqIHogLSAwLjI0NzcwOCApOyAvLyAoIM+AIC8gNCApICogMC4zMTUzOTIgKiAzXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDcgXSwgMi4wICogMC40MjkwNDMgKiB4ICogeiApO1xuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA4IF0sIDAuNDI5MDQzICogKCB4ICogeCAtIHkgKiB5ICkgKTsgLy8gKCDPgCAvIDQgKSAqIDAuNTQ2Mjc0XG5cblx0XHRyZXR1cm4gdGFyZ2V0O1xuXG5cdH1cblxuXHRhZGQoIHNoICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5jb2VmZmljaWVudHNbIGkgXS5hZGQoIHNoLmNvZWZmaWNpZW50c1sgaSBdICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkU2NhbGVkU0goIHNoLCBzICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5jb2VmZmljaWVudHNbIGkgXS5hZGRTY2FsZWRWZWN0b3IoIHNoLmNvZWZmaWNpZW50c1sgaSBdLCBzICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2NhbGUoIHMgKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmNvZWZmaWNpZW50c1sgaSBdLm11bHRpcGx5U2NhbGFyKCBzICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bGVycCggc2gsIGFscGhhICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5jb2VmZmljaWVudHNbIGkgXS5sZXJwKCBzaC5jb2VmZmljaWVudHNbIGkgXSwgYWxwaGEgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRlcXVhbHMoIHNoICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcblxuXHRcdFx0aWYgKCAhIHRoaXMuY29lZmZpY2llbnRzWyBpIF0uZXF1YWxzKCBzaC5jb2VmZmljaWVudHNbIGkgXSApICkge1xuXG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fVxuXG5cdGNvcHkoIHNoICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuc2V0KCBzaC5jb2VmZmljaWVudHMgKTtcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG5cdGZyb21BcnJheSggYXJyYXksIG9mZnNldCA9IDAgKSB7XG5cblx0XHRjb25zdCBjb2VmZmljaWVudHMgPSB0aGlzLmNvZWZmaWNpZW50cztcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XG5cblx0XHRcdGNvZWZmaWNpZW50c1sgaSBdLmZyb21BcnJheSggYXJyYXksIG9mZnNldCArICggaSAqIDMgKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvQXJyYXkoIGFycmF5ID0gW10sIG9mZnNldCA9IDAgKSB7XG5cblx0XHRjb25zdCBjb2VmZmljaWVudHMgPSB0aGlzLmNvZWZmaWNpZW50cztcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XG5cblx0XHRcdGNvZWZmaWNpZW50c1sgaSBdLnRvQXJyYXkoIGFycmF5LCBvZmZzZXQgKyAoIGkgKiAzICkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBhcnJheTtcblxuXHR9XG5cblx0Ly8gZXZhbHVhdGUgdGhlIGJhc2lzIGZ1bmN0aW9uc1xuXHQvLyBzaEJhc2lzIGlzIGFuIEFycmF5WyA5IF1cblx0c3RhdGljIGdldEJhc2lzQXQoIG5vcm1hbCwgc2hCYXNpcyApIHtcblxuXHRcdC8vIG5vcm1hbCBpcyBhc3N1bWVkIHRvIGJlIHVuaXQgbGVuZ3RoXG5cblx0XHRjb25zdCB4ID0gbm9ybWFsLngsIHkgPSBub3JtYWwueSwgeiA9IG5vcm1hbC56O1xuXG5cdFx0Ly8gYmFuZCAwXG5cdFx0c2hCYXNpc1sgMCBdID0gMC4yODIwOTU7XG5cblx0XHQvLyBiYW5kIDFcblx0XHRzaEJhc2lzWyAxIF0gPSAwLjQ4ODYwMyAqIHk7XG5cdFx0c2hCYXNpc1sgMiBdID0gMC40ODg2MDMgKiB6O1xuXHRcdHNoQmFzaXNbIDMgXSA9IDAuNDg4NjAzICogeDtcblxuXHRcdC8vIGJhbmQgMlxuXHRcdHNoQmFzaXNbIDQgXSA9IDEuMDkyNTQ4ICogeCAqIHk7XG5cdFx0c2hCYXNpc1sgNSBdID0gMS4wOTI1NDggKiB5ICogejtcblx0XHRzaEJhc2lzWyA2IF0gPSAwLjMxNTM5MiAqICggMyAqIHogKiB6IC0gMSApO1xuXHRcdHNoQmFzaXNbIDcgXSA9IDEuMDkyNTQ4ICogeCAqIHo7XG5cdFx0c2hCYXNpc1sgOCBdID0gMC41NDYyNzQgKiAoIHggKiB4IC0geSAqIHkgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgTGlnaHRQcm9iZSBleHRlbmRzIExpZ2h0IHtcblxuXHRjb25zdHJ1Y3Rvciggc2ggPSBuZXcgU3BoZXJpY2FsSGFybW9uaWNzMygpLCBpbnRlbnNpdHkgPSAxICkge1xuXG5cdFx0c3VwZXIoIHVuZGVmaW5lZCwgaW50ZW5zaXR5ICk7XG5cblx0XHR0aGlzLmlzTGlnaHRQcm9iZSA9IHRydWU7XG5cblx0XHR0aGlzLnNoID0gc2g7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5zaC5jb3B5KCBzb3VyY2Uuc2ggKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRmcm9tSlNPTigganNvbiApIHtcblxuXHRcdHRoaXMuaW50ZW5zaXR5ID0ganNvbi5pbnRlbnNpdHk7IC8vIFRPRE86IE1vdmUgdGhpcyBiaXQgdG8gTGlnaHQuZnJvbUpTT04oKTtcblx0XHR0aGlzLnNoLmZyb21BcnJheSgganNvbi5zaCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTiggbWV0YSApIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oIG1ldGEgKTtcblxuXHRcdGRhdGEub2JqZWN0LnNoID0gdGhpcy5zaC50b0FycmF5KCk7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cbn1cblxuY2xhc3MgTWF0ZXJpYWxMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xuXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcblx0XHR0aGlzLnRleHR1cmVzID0ge307XG5cblx0fVxuXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0Y29uc3QgbG9hZGVyID0gbmV3IEZpbGVMb2FkZXIoIHNjb3BlLm1hbmFnZXIgKTtcblx0XHRsb2FkZXIuc2V0UGF0aCggc2NvcGUucGF0aCApO1xuXHRcdGxvYWRlci5zZXRSZXF1ZXN0SGVhZGVyKCBzY29wZS5yZXF1ZXN0SGVhZGVyICk7XG5cdFx0bG9hZGVyLnNldFdpdGhDcmVkZW50aWFscyggc2NvcGUud2l0aENyZWRlbnRpYWxzICk7XG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCB0ZXh0ICkge1xuXG5cdFx0XHR0cnkge1xuXG5cdFx0XHRcdG9uTG9hZCggc2NvcGUucGFyc2UoIEpTT04ucGFyc2UoIHRleHQgKSApICk7XG5cblx0XHRcdH0gY2F0Y2ggKCBlICkge1xuXG5cdFx0XHRcdGlmICggb25FcnJvciApIHtcblxuXHRcdFx0XHRcdG9uRXJyb3IoIGUgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Y29uc29sZS5lcnJvciggZSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FcnJvciggdXJsICk7XG5cblx0XHRcdH1cblxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcblxuXHR9XG5cblx0cGFyc2UoIGpzb24gKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlcyA9IHRoaXMudGV4dHVyZXM7XG5cblx0XHRmdW5jdGlvbiBnZXRUZXh0dXJlKCBuYW1lICkge1xuXG5cdFx0XHRpZiAoIHRleHR1cmVzWyBuYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5NYXRlcmlhbExvYWRlcjogVW5kZWZpbmVkIHRleHR1cmUnLCBuYW1lICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRleHR1cmVzWyBuYW1lIF07XG5cblx0XHR9XG5cblx0XHRjb25zdCBtYXRlcmlhbCA9IE1hdGVyaWFsTG9hZGVyLmNyZWF0ZU1hdGVyaWFsRnJvbVR5cGUoIGpzb24udHlwZSApO1xuXG5cdFx0aWYgKCBqc29uLnV1aWQgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnV1aWQgPSBqc29uLnV1aWQ7XG5cdFx0aWYgKCBqc29uLm5hbWUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLm5hbWUgPSBqc29uLm5hbWU7XG5cdFx0aWYgKCBqc29uLmNvbG9yICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuY29sb3IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNvbG9yLnNldEhleCgganNvbi5jb2xvciApO1xuXHRcdGlmICgganNvbi5yb3VnaG5lc3MgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnJvdWdobmVzcyA9IGpzb24ucm91Z2huZXNzO1xuXHRcdGlmICgganNvbi5tZXRhbG5lc3MgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLm1ldGFsbmVzcyA9IGpzb24ubWV0YWxuZXNzO1xuXHRcdGlmICgganNvbi5zaGVlbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2hlZW4gPSBqc29uLnNoZWVuO1xuXHRcdGlmICgganNvbi5zaGVlbkNvbG9yICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGVlbkNvbG9yID0gbmV3IENvbG9yKCkuc2V0SGV4KCBqc29uLnNoZWVuQ29sb3IgKTtcblx0XHRpZiAoIGpzb24uc2hlZW5Sb3VnaG5lc3MgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzID0ganNvbi5zaGVlblJvdWdobmVzcztcblx0XHRpZiAoIGpzb24uZW1pc3NpdmUgIT09IHVuZGVmaW5lZCAmJiBtYXRlcmlhbC5lbWlzc2l2ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZW1pc3NpdmUuc2V0SGV4KCBqc29uLmVtaXNzaXZlICk7XG5cdFx0aWYgKCBqc29uLnNwZWN1bGFyICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuc3BlY3VsYXIgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFyLnNldEhleCgganNvbi5zcGVjdWxhciApO1xuXHRcdGlmICgganNvbi5zcGVjdWxhckludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3BlY3VsYXJJbnRlbnNpdHkgPSBqc29uLnNwZWN1bGFySW50ZW5zaXR5O1xuXHRcdGlmICgganNvbi5zcGVjdWxhckNvbG9yICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvci5zZXRIZXgoIGpzb24uc3BlY3VsYXJDb2xvciApO1xuXHRcdGlmICgganNvbi5zaGluaW5lc3MgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNoaW5pbmVzcyA9IGpzb24uc2hpbmluZXNzO1xuXHRcdGlmICgganNvbi5jbGVhcmNvYXQgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNsZWFyY29hdCA9IGpzb24uY2xlYXJjb2F0O1xuXHRcdGlmICgganNvbi5jbGVhcmNvYXRSb3VnaG5lc3MgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcyA9IGpzb24uY2xlYXJjb2F0Um91Z2huZXNzO1xuXHRcdGlmICgganNvbi5kaXNwZXJzaW9uICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kaXNwZXJzaW9uID0ganNvbi5kaXNwZXJzaW9uO1xuXHRcdGlmICgganNvbi5pcmlkZXNjZW5jZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuaXJpZGVzY2VuY2UgPSBqc29uLmlyaWRlc2NlbmNlO1xuXHRcdGlmICgganNvbi5pcmlkZXNjZW5jZUlPUiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuaXJpZGVzY2VuY2VJT1IgPSBqc29uLmlyaWRlc2NlbmNlSU9SO1xuXHRcdGlmICgganNvbi5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlID0ganNvbi5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlO1xuXHRcdGlmICgganNvbi50cmFuc21pc3Npb24gIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnRyYW5zbWlzc2lvbiA9IGpzb24udHJhbnNtaXNzaW9uO1xuXHRcdGlmICgganNvbi50aGlja25lc3MgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnRoaWNrbmVzcyA9IGpzb24udGhpY2tuZXNzO1xuXHRcdGlmICgganNvbi5hdHRlbnVhdGlvbkRpc3RhbmNlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hdHRlbnVhdGlvbkRpc3RhbmNlID0ganNvbi5hdHRlbnVhdGlvbkRpc3RhbmNlO1xuXHRcdGlmICgganNvbi5hdHRlbnVhdGlvbkNvbG9yICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuYXR0ZW51YXRpb25Db2xvciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYXR0ZW51YXRpb25Db2xvci5zZXRIZXgoIGpzb24uYXR0ZW51YXRpb25Db2xvciApO1xuXHRcdGlmICgganNvbi5hbmlzb3Ryb3B5ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hbmlzb3Ryb3B5ID0ganNvbi5hbmlzb3Ryb3B5O1xuXHRcdGlmICgganNvbi5hbmlzb3Ryb3B5Um90YXRpb24gIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFuaXNvdHJvcHlSb3RhdGlvbiA9IGpzb24uYW5pc290cm9weVJvdGF0aW9uO1xuXHRcdGlmICgganNvbi5mb2cgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmZvZyA9IGpzb24uZm9nO1xuXHRcdGlmICgganNvbi5mbGF0U2hhZGluZyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZmxhdFNoYWRpbmcgPSBqc29uLmZsYXRTaGFkaW5nO1xuXHRcdGlmICgganNvbi5ibGVuZGluZyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRpbmcgPSBqc29uLmJsZW5kaW5nO1xuXHRcdGlmICgganNvbi5jb21iaW5lICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jb21iaW5lID0ganNvbi5jb21iaW5lO1xuXHRcdGlmICgganNvbi5zaWRlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaWRlID0ganNvbi5zaWRlO1xuXHRcdGlmICgganNvbi5zaGFkb3dTaWRlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGFkb3dTaWRlID0ganNvbi5zaGFkb3dTaWRlO1xuXHRcdGlmICgganNvbi5vcGFjaXR5ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5vcGFjaXR5ID0ganNvbi5vcGFjaXR5O1xuXHRcdGlmICgganNvbi50cmFuc3BhcmVudCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwudHJhbnNwYXJlbnQgPSBqc29uLnRyYW5zcGFyZW50O1xuXHRcdGlmICgganNvbi5hbHBoYVRlc3QgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFscGhhVGVzdCA9IGpzb24uYWxwaGFUZXN0O1xuXHRcdGlmICgganNvbi5hbHBoYUhhc2ggIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFscGhhSGFzaCA9IGpzb24uYWxwaGFIYXNoO1xuXHRcdGlmICgganNvbi5kZXB0aEZ1bmMgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRlcHRoRnVuYyA9IGpzb24uZGVwdGhGdW5jO1xuXHRcdGlmICgganNvbi5kZXB0aFRlc3QgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRlcHRoVGVzdCA9IGpzb24uZGVwdGhUZXN0O1xuXHRcdGlmICgganNvbi5kZXB0aFdyaXRlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kZXB0aFdyaXRlID0ganNvbi5kZXB0aFdyaXRlO1xuXHRcdGlmICgganNvbi5jb2xvcldyaXRlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jb2xvcldyaXRlID0ganNvbi5jb2xvcldyaXRlO1xuXHRcdGlmICgganNvbi5ibGVuZFNyYyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRTcmMgPSBqc29uLmJsZW5kU3JjO1xuXHRcdGlmICgganNvbi5ibGVuZERzdCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmREc3QgPSBqc29uLmJsZW5kRHN0O1xuXHRcdGlmICgganNvbi5ibGVuZEVxdWF0aW9uICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ibGVuZEVxdWF0aW9uID0ganNvbi5ibGVuZEVxdWF0aW9uO1xuXHRcdGlmICgganNvbi5ibGVuZFNyY0FscGhhICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ibGVuZFNyY0FscGhhID0ganNvbi5ibGVuZFNyY0FscGhhO1xuXHRcdGlmICgganNvbi5ibGVuZERzdEFscGhhICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ibGVuZERzdEFscGhhID0ganNvbi5ibGVuZERzdEFscGhhO1xuXHRcdGlmICgganNvbi5ibGVuZEVxdWF0aW9uQWxwaGEgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmJsZW5kRXF1YXRpb25BbHBoYSA9IGpzb24uYmxlbmRFcXVhdGlvbkFscGhhO1xuXHRcdGlmICgganNvbi5ibGVuZENvbG9yICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuYmxlbmRDb2xvciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRDb2xvci5zZXRIZXgoIGpzb24uYmxlbmRDb2xvciApO1xuXHRcdGlmICgganNvbi5ibGVuZEFscGhhICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ibGVuZEFscGhhID0ganNvbi5ibGVuZEFscGhhO1xuXHRcdGlmICgganNvbi5zdGVuY2lsV3JpdGVNYXNrICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zdGVuY2lsV3JpdGVNYXNrID0ganNvbi5zdGVuY2lsV3JpdGVNYXNrO1xuXHRcdGlmICgganNvbi5zdGVuY2lsRnVuYyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbEZ1bmMgPSBqc29uLnN0ZW5jaWxGdW5jO1xuXHRcdGlmICgganNvbi5zdGVuY2lsUmVmICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zdGVuY2lsUmVmID0ganNvbi5zdGVuY2lsUmVmO1xuXHRcdGlmICgganNvbi5zdGVuY2lsRnVuY01hc2sgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnN0ZW5jaWxGdW5jTWFzayA9IGpzb24uc3RlbmNpbEZ1bmNNYXNrO1xuXHRcdGlmICgganNvbi5zdGVuY2lsRmFpbCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbEZhaWwgPSBqc29uLnN0ZW5jaWxGYWlsO1xuXHRcdGlmICgganNvbi5zdGVuY2lsWkZhaWwgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnN0ZW5jaWxaRmFpbCA9IGpzb24uc3RlbmNpbFpGYWlsO1xuXHRcdGlmICgganNvbi5zdGVuY2lsWlBhc3MgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnN0ZW5jaWxaUGFzcyA9IGpzb24uc3RlbmNpbFpQYXNzO1xuXHRcdGlmICgganNvbi5zdGVuY2lsV3JpdGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnN0ZW5jaWxXcml0ZSA9IGpzb24uc3RlbmNpbFdyaXRlO1xuXG5cdFx0aWYgKCBqc29uLndpcmVmcmFtZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwud2lyZWZyYW1lID0ganNvbi53aXJlZnJhbWU7XG5cdFx0aWYgKCBqc29uLndpcmVmcmFtZUxpbmV3aWR0aCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwud2lyZWZyYW1lTGluZXdpZHRoID0ganNvbi53aXJlZnJhbWVMaW5ld2lkdGg7XG5cdFx0aWYgKCBqc29uLndpcmVmcmFtZUxpbmVjYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLndpcmVmcmFtZUxpbmVjYXAgPSBqc29uLndpcmVmcmFtZUxpbmVjYXA7XG5cdFx0aWYgKCBqc29uLndpcmVmcmFtZUxpbmVqb2luICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC53aXJlZnJhbWVMaW5lam9pbiA9IGpzb24ud2lyZWZyYW1lTGluZWpvaW47XG5cblx0XHRpZiAoIGpzb24ucm90YXRpb24gIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnJvdGF0aW9uID0ganNvbi5yb3RhdGlvbjtcblxuXHRcdGlmICgganNvbi5saW5ld2lkdGggIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmxpbmV3aWR0aCA9IGpzb24ubGluZXdpZHRoO1xuXHRcdGlmICgganNvbi5kYXNoU2l6ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZGFzaFNpemUgPSBqc29uLmRhc2hTaXplO1xuXHRcdGlmICgganNvbi5nYXBTaXplICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5nYXBTaXplID0ganNvbi5nYXBTaXplO1xuXHRcdGlmICgganNvbi5zY2FsZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2NhbGUgPSBqc29uLnNjYWxlO1xuXG5cdFx0aWYgKCBqc29uLnBvbHlnb25PZmZzZXQgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnBvbHlnb25PZmZzZXQgPSBqc29uLnBvbHlnb25PZmZzZXQ7XG5cdFx0aWYgKCBqc29uLnBvbHlnb25PZmZzZXRGYWN0b3IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRGYWN0b3IgPSBqc29uLnBvbHlnb25PZmZzZXRGYWN0b3I7XG5cdFx0aWYgKCBqc29uLnBvbHlnb25PZmZzZXRVbml0cyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwucG9seWdvbk9mZnNldFVuaXRzID0ganNvbi5wb2x5Z29uT2Zmc2V0VW5pdHM7XG5cblx0XHRpZiAoIGpzb24uZGl0aGVyaW5nICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kaXRoZXJpbmcgPSBqc29uLmRpdGhlcmluZztcblxuXHRcdGlmICgganNvbi5hbHBoYVRvQ292ZXJhZ2UgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFscGhhVG9Db3ZlcmFnZSA9IGpzb24uYWxwaGFUb0NvdmVyYWdlO1xuXHRcdGlmICgganNvbi5wcmVtdWx0aXBsaWVkQWxwaGEgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnByZW11bHRpcGxpZWRBbHBoYSA9IGpzb24ucHJlbXVsdGlwbGllZEFscGhhO1xuXHRcdGlmICgganNvbi5mb3JjZVNpbmdsZVBhc3MgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmZvcmNlU2luZ2xlUGFzcyA9IGpzb24uZm9yY2VTaW5nbGVQYXNzO1xuXG5cdFx0aWYgKCBqc29uLnZpc2libGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnZpc2libGUgPSBqc29uLnZpc2libGU7XG5cblx0XHRpZiAoIGpzb24udG9uZU1hcHBlZCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwudG9uZU1hcHBlZCA9IGpzb24udG9uZU1hcHBlZDtcblxuXHRcdGlmICgganNvbi51c2VyRGF0YSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwudXNlckRhdGEgPSBqc29uLnVzZXJEYXRhO1xuXG5cdFx0aWYgKCBqc29uLnZlcnRleENvbG9ycyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRpZiAoIHR5cGVvZiBqc29uLnZlcnRleENvbG9ycyA9PT0gJ251bWJlcicgKSB7XG5cblx0XHRcdFx0bWF0ZXJpYWwudmVydGV4Q29sb3JzID0gKCBqc29uLnZlcnRleENvbG9ycyA+IDAgKSA/IHRydWUgOiBmYWxzZTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRtYXRlcmlhbC52ZXJ0ZXhDb2xvcnMgPSBqc29uLnZlcnRleENvbG9ycztcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gU2hhZGVyIE1hdGVyaWFsXG5cblx0XHRpZiAoIGpzb24udW5pZm9ybXMgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Zm9yICggY29uc3QgbmFtZSBpbiBqc29uLnVuaWZvcm1zICkge1xuXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm0gPSBqc29uLnVuaWZvcm1zWyBuYW1lIF07XG5cblx0XHRcdFx0bWF0ZXJpYWwudW5pZm9ybXNbIG5hbWUgXSA9IHt9O1xuXG5cdFx0XHRcdHN3aXRjaCAoIHVuaWZvcm0udHlwZSApIHtcblxuXHRcdFx0XHRcdGNhc2UgJ3QnOlxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwudW5pZm9ybXNbIG5hbWUgXS52YWx1ZSA9IGdldFRleHR1cmUoIHVuaWZvcm0udmFsdWUgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0Y2FzZSAnYyc6XG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IENvbG9yKCkuc2V0SGV4KCB1bmlmb3JtLnZhbHVlICk7XG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdGNhc2UgJ3YyJzpcblx0XHRcdFx0XHRcdG1hdGVyaWFsLnVuaWZvcm1zWyBuYW1lIF0udmFsdWUgPSBuZXcgVmVjdG9yMigpLmZyb21BcnJheSggdW5pZm9ybS52YWx1ZSApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRjYXNlICd2Myc6XG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IFZlY3RvcjMoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0Y2FzZSAndjQnOlxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwudW5pZm9ybXNbIG5hbWUgXS52YWx1ZSA9IG5ldyBWZWN0b3I0KCkuZnJvbUFycmF5KCB1bmlmb3JtLnZhbHVlICk7XG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdGNhc2UgJ20zJzpcblx0XHRcdFx0XHRcdG1hdGVyaWFsLnVuaWZvcm1zWyBuYW1lIF0udmFsdWUgPSBuZXcgTWF0cml4MygpLmZyb21BcnJheSggdW5pZm9ybS52YWx1ZSApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRjYXNlICdtNCc6XG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IE1hdHJpeDQoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHRcdG1hdGVyaWFsLnVuaWZvcm1zWyBuYW1lIF0udmFsdWUgPSB1bmlmb3JtLnZhbHVlO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBqc29uLmRlZmluZXMgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRlZmluZXMgPSBqc29uLmRlZmluZXM7XG5cdFx0aWYgKCBqc29uLnZlcnRleFNoYWRlciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwudmVydGV4U2hhZGVyID0ganNvbi52ZXJ0ZXhTaGFkZXI7XG5cdFx0aWYgKCBqc29uLmZyYWdtZW50U2hhZGVyICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5mcmFnbWVudFNoYWRlciA9IGpzb24uZnJhZ21lbnRTaGFkZXI7XG5cdFx0aWYgKCBqc29uLmdsc2xWZXJzaW9uICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5nbHNsVmVyc2lvbiA9IGpzb24uZ2xzbFZlcnNpb247XG5cblx0XHRpZiAoIGpzb24uZXh0ZW5zaW9ucyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRmb3IgKCBjb25zdCBrZXkgaW4ganNvbi5leHRlbnNpb25zICkge1xuXG5cdFx0XHRcdG1hdGVyaWFsLmV4dGVuc2lvbnNbIGtleSBdID0ganNvbi5leHRlbnNpb25zWyBrZXkgXTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBqc29uLmxpZ2h0cyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwubGlnaHRzID0ganNvbi5saWdodHM7XG5cdFx0aWYgKCBqc29uLmNsaXBwaW5nICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGlwcGluZyA9IGpzb24uY2xpcHBpbmc7XG5cblx0XHQvLyBmb3IgUG9pbnRzTWF0ZXJpYWxcblxuXHRcdGlmICgganNvbi5zaXplICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaXplID0ganNvbi5zaXplO1xuXHRcdGlmICgganNvbi5zaXplQXR0ZW51YXRpb24gIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNpemVBdHRlbnVhdGlvbiA9IGpzb24uc2l6ZUF0dGVudWF0aW9uO1xuXG5cdFx0Ly8gbWFwc1xuXG5cdFx0aWYgKCBqc29uLm1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwubWFwID0gZ2V0VGV4dHVyZSgganNvbi5tYXAgKTtcblx0XHRpZiAoIGpzb24ubWF0Y2FwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5tYXRjYXAgPSBnZXRUZXh0dXJlKCBqc29uLm1hdGNhcCApO1xuXG5cdFx0aWYgKCBqc29uLmFscGhhTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hbHBoYU1hcCA9IGdldFRleHR1cmUoIGpzb24uYWxwaGFNYXAgKTtcblxuXHRcdGlmICgganNvbi5idW1wTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5idW1wTWFwID0gZ2V0VGV4dHVyZSgganNvbi5idW1wTWFwICk7XG5cdFx0aWYgKCBqc29uLmJ1bXBTY2FsZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYnVtcFNjYWxlID0ganNvbi5idW1wU2NhbGU7XG5cblx0XHRpZiAoIGpzb24ubm9ybWFsTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ub3JtYWxNYXAgPSBnZXRUZXh0dXJlKCBqc29uLm5vcm1hbE1hcCApO1xuXHRcdGlmICgganNvbi5ub3JtYWxNYXBUeXBlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ub3JtYWxNYXBUeXBlID0ganNvbi5ub3JtYWxNYXBUeXBlO1xuXHRcdGlmICgganNvbi5ub3JtYWxTY2FsZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRsZXQgbm9ybWFsU2NhbGUgPSBqc29uLm5vcm1hbFNjYWxlO1xuXG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG5vcm1hbFNjYWxlICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdC8vIEJsZW5kZXIgZXhwb3J0ZXIgdXNlZCB0byBleHBvcnQgYSBzY2FsYXIuIFNlZSAjNzQ1OVxuXG5cdFx0XHRcdG5vcm1hbFNjYWxlID0gWyBub3JtYWxTY2FsZSwgbm9ybWFsU2NhbGUgXTtcblxuXHRcdFx0fVxuXG5cdFx0XHRtYXRlcmlhbC5ub3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCkuZnJvbUFycmF5KCBub3JtYWxTY2FsZSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBqc29uLmRpc3BsYWNlbWVudE1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZGlzcGxhY2VtZW50TWFwID0gZ2V0VGV4dHVyZSgganNvbi5kaXNwbGFjZW1lbnRNYXAgKTtcblx0XHRpZiAoIGpzb24uZGlzcGxhY2VtZW50U2NhbGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRpc3BsYWNlbWVudFNjYWxlID0ganNvbi5kaXNwbGFjZW1lbnRTY2FsZTtcblx0XHRpZiAoIGpzb24uZGlzcGxhY2VtZW50QmlhcyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZGlzcGxhY2VtZW50QmlhcyA9IGpzb24uZGlzcGxhY2VtZW50QmlhcztcblxuXHRcdGlmICgganNvbi5yb3VnaG5lc3NNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnJvdWdobmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24ucm91Z2huZXNzTWFwICk7XG5cdFx0aWYgKCBqc29uLm1ldGFsbmVzc01hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwubWV0YWxuZXNzTWFwID0gZ2V0VGV4dHVyZSgganNvbi5tZXRhbG5lc3NNYXAgKTtcblxuXHRcdGlmICgganNvbi5lbWlzc2l2ZU1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZW1pc3NpdmVNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmVtaXNzaXZlTWFwICk7XG5cdFx0aWYgKCBqc29uLmVtaXNzaXZlSW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5lbWlzc2l2ZUludGVuc2l0eSA9IGpzb24uZW1pc3NpdmVJbnRlbnNpdHk7XG5cblx0XHRpZiAoIGpzb24uc3BlY3VsYXJNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFyTWFwID0gZ2V0VGV4dHVyZSgganNvbi5zcGVjdWxhck1hcCApO1xuXHRcdGlmICgganNvbi5zcGVjdWxhckludGVuc2l0eU1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3BlY3VsYXJJbnRlbnNpdHlNYXAgPSBnZXRUZXh0dXJlKCBqc29uLnNwZWN1bGFySW50ZW5zaXR5TWFwICk7XG5cdFx0aWYgKCBqc29uLnNwZWN1bGFyQ29sb3JNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3JNYXAgPSBnZXRUZXh0dXJlKCBqc29uLnNwZWN1bGFyQ29sb3JNYXAgKTtcblxuXHRcdGlmICgganNvbi5lbnZNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmVudk1hcCA9IGdldFRleHR1cmUoIGpzb24uZW52TWFwICk7XG5cdFx0aWYgKCBqc29uLmVudk1hcFJvdGF0aW9uICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5lbnZNYXBSb3RhdGlvbi5mcm9tQXJyYXkoIGpzb24uZW52TWFwUm90YXRpb24gKTtcblx0XHRpZiAoIGpzb24uZW52TWFwSW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5lbnZNYXBJbnRlbnNpdHkgPSBqc29uLmVudk1hcEludGVuc2l0eTtcblxuXHRcdGlmICgganNvbi5yZWZsZWN0aXZpdHkgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnJlZmxlY3Rpdml0eSA9IGpzb24ucmVmbGVjdGl2aXR5O1xuXHRcdGlmICgganNvbi5yZWZyYWN0aW9uUmF0aW8gIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnJlZnJhY3Rpb25SYXRpbyA9IGpzb24ucmVmcmFjdGlvblJhdGlvO1xuXG5cdFx0aWYgKCBqc29uLmxpZ2h0TWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5saWdodE1hcCA9IGdldFRleHR1cmUoIGpzb24ubGlnaHRNYXAgKTtcblx0XHRpZiAoIGpzb24ubGlnaHRNYXBJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmxpZ2h0TWFwSW50ZW5zaXR5ID0ganNvbi5saWdodE1hcEludGVuc2l0eTtcblxuXHRcdGlmICgganNvbi5hb01hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYW9NYXAgPSBnZXRUZXh0dXJlKCBqc29uLmFvTWFwICk7XG5cdFx0aWYgKCBqc29uLmFvTWFwSW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hb01hcEludGVuc2l0eSA9IGpzb24uYW9NYXBJbnRlbnNpdHk7XG5cblx0XHRpZiAoIGpzb24uZ3JhZGllbnRNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmdyYWRpZW50TWFwID0gZ2V0VGV4dHVyZSgganNvbi5ncmFkaWVudE1hcCApO1xuXG5cdFx0aWYgKCBqc29uLmNsZWFyY29hdE1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuY2xlYXJjb2F0TWFwID0gZ2V0VGV4dHVyZSgganNvbi5jbGVhcmNvYXRNYXAgKTtcblx0XHRpZiAoIGpzb24uY2xlYXJjb2F0Um91Z2huZXNzTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmNsZWFyY29hdFJvdWdobmVzc01hcCApO1xuXHRcdGlmICgganNvbi5jbGVhcmNvYXROb3JtYWxNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNsZWFyY29hdE5vcm1hbE1hcCA9IGdldFRleHR1cmUoIGpzb24uY2xlYXJjb2F0Tm9ybWFsTWFwICk7XG5cdFx0aWYgKCBqc29uLmNsZWFyY29hdE5vcm1hbFNjYWxlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCkuZnJvbUFycmF5KCBqc29uLmNsZWFyY29hdE5vcm1hbFNjYWxlICk7XG5cblx0XHRpZiAoIGpzb24uaXJpZGVzY2VuY2VNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmlyaWRlc2NlbmNlTWFwID0gZ2V0VGV4dHVyZSgganNvbi5pcmlkZXNjZW5jZU1hcCApO1xuXHRcdGlmICgganNvbi5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwICk7XG5cblx0XHRpZiAoIGpzb24udHJhbnNtaXNzaW9uTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC50cmFuc21pc3Npb25NYXAgPSBnZXRUZXh0dXJlKCBqc29uLnRyYW5zbWlzc2lvbk1hcCApO1xuXHRcdGlmICgganNvbi50aGlja25lc3NNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnRoaWNrbmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24udGhpY2tuZXNzTWFwICk7XG5cblx0XHRpZiAoIGpzb24uYW5pc290cm9weU1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYW5pc290cm9weU1hcCA9IGdldFRleHR1cmUoIGpzb24uYW5pc290cm9weU1hcCApO1xuXG5cdFx0aWYgKCBqc29uLnNoZWVuQ29sb3JNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNoZWVuQ29sb3JNYXAgPSBnZXRUZXh0dXJlKCBqc29uLnNoZWVuQ29sb3JNYXAgKTtcblx0XHRpZiAoIGpzb24uc2hlZW5Sb3VnaG5lc3NNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzTWFwID0gZ2V0VGV4dHVyZSgganNvbi5zaGVlblJvdWdobmVzc01hcCApO1xuXG5cdFx0cmV0dXJuIG1hdGVyaWFsO1xuXG5cdH1cblxuXHRzZXRUZXh0dXJlcyggdmFsdWUgKSB7XG5cblx0XHR0aGlzLnRleHR1cmVzID0gdmFsdWU7XG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN0YXRpYyBjcmVhdGVNYXRlcmlhbEZyb21UeXBlKCB0eXBlICkge1xuXG5cdFx0Y29uc3QgbWF0ZXJpYWxMaWIgPSB7XG5cdFx0XHRTaGFkb3dNYXRlcmlhbCxcblx0XHRcdFNwcml0ZU1hdGVyaWFsLFxuXHRcdFx0UmF3U2hhZGVyTWF0ZXJpYWwsXG5cdFx0XHRTaGFkZXJNYXRlcmlhbCxcblx0XHRcdFBvaW50c01hdGVyaWFsLFxuXHRcdFx0TWVzaFBoeXNpY2FsTWF0ZXJpYWwsXG5cdFx0XHRNZXNoU3RhbmRhcmRNYXRlcmlhbCxcblx0XHRcdE1lc2hQaG9uZ01hdGVyaWFsLFxuXHRcdFx0TWVzaFRvb25NYXRlcmlhbCxcblx0XHRcdE1lc2hOb3JtYWxNYXRlcmlhbCxcblx0XHRcdE1lc2hMYW1iZXJ0TWF0ZXJpYWwsXG5cdFx0XHRNZXNoRGVwdGhNYXRlcmlhbCxcblx0XHRcdE1lc2hEaXN0YW5jZU1hdGVyaWFsLFxuXHRcdFx0TWVzaEJhc2ljTWF0ZXJpYWwsXG5cdFx0XHRNZXNoTWF0Y2FwTWF0ZXJpYWwsXG5cdFx0XHRMaW5lRGFzaGVkTWF0ZXJpYWwsXG5cdFx0XHRMaW5lQmFzaWNNYXRlcmlhbCxcblx0XHRcdE1hdGVyaWFsXG5cdFx0fTtcblxuXHRcdHJldHVybiBuZXcgbWF0ZXJpYWxMaWJbIHR5cGUgXSgpO1xuXG5cdH1cblxufVxuXG5jbGFzcyBMb2FkZXJVdGlscyB7XG5cblx0c3RhdGljIGRlY29kZVRleHQoIGFycmF5ICkgeyAvLyBAZGVwcmVjYXRlZCwgcjE2NVxuXG5cdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuTG9hZGVyVXRpbHM6IGRlY29kZVRleHQoKSBoYXMgYmVlbiBkZXByZWNhdGVkIHdpdGggcjE2NSBhbmQgd2lsbCBiZSByZW1vdmVkIHdpdGggcjE3NS4gVXNlIFRleHREZWNvZGVyIGluc3RlYWQuJyApO1xuXG5cdFx0aWYgKCB0eXBlb2YgVGV4dERlY29kZXIgIT09ICd1bmRlZmluZWQnICkge1xuXG5cdFx0XHRyZXR1cm4gbmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKCBhcnJheSApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gQXZvaWQgdGhlIFN0cmluZy5mcm9tQ2hhckNvZGUuYXBwbHkobnVsbCwgYXJyYXkpIHNob3J0Y3V0LCB3aGljaFxuXHRcdC8vIHRocm93cyBhIFwibWF4aW11bSBjYWxsIHN0YWNrIHNpemUgZXhjZWVkZWRcIiBlcnJvciBmb3IgbGFyZ2UgYXJyYXlzLlxuXG5cdFx0bGV0IHMgPSAnJztcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBhcnJheS5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Ly8gSW1wbGljaXRseSBhc3N1bWVzIGxpdHRsZS1lbmRpYW4uXG5cdFx0XHRzICs9IFN0cmluZy5mcm9tQ2hhckNvZGUoIGFycmF5WyBpIF0gKTtcblxuXHRcdH1cblxuXHRcdHRyeSB7XG5cblx0XHRcdC8vIG1lcmdlcyBtdWx0aS1ieXRlIHV0Zi04IGNoYXJhY3RlcnMuXG5cblx0XHRcdHJldHVybiBkZWNvZGVVUklDb21wb25lbnQoIGVzY2FwZSggcyApICk7XG5cblx0XHR9IGNhdGNoICggZSApIHsgLy8gc2VlICMxNjM1OFxuXG5cdFx0XHRyZXR1cm4gcztcblxuXHRcdH1cblxuXHR9XG5cblx0c3RhdGljIGV4dHJhY3RVcmxCYXNlKCB1cmwgKSB7XG5cblx0XHRjb25zdCBpbmRleCA9IHVybC5sYXN0SW5kZXhPZiggJy8nICk7XG5cblx0XHRpZiAoIGluZGV4ID09PSAtIDEgKSByZXR1cm4gJy4vJztcblxuXHRcdHJldHVybiB1cmwuc2xpY2UoIDAsIGluZGV4ICsgMSApO1xuXG5cdH1cblxuXHRzdGF0aWMgcmVzb2x2ZVVSTCggdXJsLCBwYXRoICkge1xuXG5cdFx0Ly8gSW52YWxpZCBVUkxcblx0XHRpZiAoIHR5cGVvZiB1cmwgIT09ICdzdHJpbmcnIHx8IHVybCA9PT0gJycgKSByZXR1cm4gJyc7XG5cblx0XHQvLyBIb3N0IFJlbGF0aXZlIFVSTFxuXHRcdGlmICggL15odHRwcz86XFwvXFwvL2kudGVzdCggcGF0aCApICYmIC9eXFwvLy50ZXN0KCB1cmwgKSApIHtcblxuXHRcdFx0cGF0aCA9IHBhdGgucmVwbGFjZSggLyheaHR0cHM/OlxcL1xcL1teXFwvXSspLiovaSwgJyQxJyApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gQWJzb2x1dGUgVVJMIGh0dHA6Ly8saHR0cHM6Ly8sLy9cblx0XHRpZiAoIC9eKGh0dHBzPzopP1xcL1xcLy9pLnRlc3QoIHVybCApICkgcmV0dXJuIHVybDtcblxuXHRcdC8vIERhdGEgVVJJXG5cdFx0aWYgKCAvXmRhdGE6LiosLiokL2kudGVzdCggdXJsICkgKSByZXR1cm4gdXJsO1xuXG5cdFx0Ly8gQmxvYiBVUkxcblx0XHRpZiAoIC9eYmxvYjouKiQvaS50ZXN0KCB1cmwgKSApIHJldHVybiB1cmw7XG5cblx0XHQvLyBSZWxhdGl2ZSBVUkxcblx0XHRyZXR1cm4gcGF0aCArIHVybDtcblxuXHR9XG5cbn1cblxuY2xhc3MgSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc0luc3RhbmNlZEJ1ZmZlckdlb21ldHJ5ID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSc7XG5cdFx0dGhpcy5pbnN0YW5jZUNvdW50ID0gSW5maW5pdHk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5pbnN0YW5jZUNvdW50ID0gc291cmNlLmluc3RhbmNlQ291bnQ7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS5pbnN0YW5jZUNvdW50ID0gdGhpcy5pbnN0YW5jZUNvdW50O1xuXG5cdFx0ZGF0YS5pc0luc3RhbmNlZEJ1ZmZlckdlb21ldHJ5ID0gdHJ1ZTtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxufVxuXG5jbGFzcyBCdWZmZXJHZW9tZXRyeUxvYWRlciBleHRlbmRzIExvYWRlciB7XG5cblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XG5cblx0XHRzdXBlciggbWFuYWdlciApO1xuXG5cdH1cblxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdGNvbnN0IGxvYWRlciA9IG5ldyBGaWxlTG9hZGVyKCBzY29wZS5tYW5hZ2VyICk7XG5cdFx0bG9hZGVyLnNldFBhdGgoIHNjb3BlLnBhdGggKTtcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggc2NvcGUucmVxdWVzdEhlYWRlciApO1xuXHRcdGxvYWRlci5zZXRXaXRoQ3JlZGVudGlhbHMoIHNjb3BlLndpdGhDcmVkZW50aWFscyApO1xuXHRcdGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICggdGV4dCApIHtcblxuXHRcdFx0dHJ5IHtcblxuXHRcdFx0XHRvbkxvYWQoIHNjb3BlLnBhcnNlKCBKU09OLnBhcnNlKCB0ZXh0ICkgKSApO1xuXG5cdFx0XHR9IGNhdGNoICggZSApIHtcblxuXHRcdFx0XHRpZiAoIG9uRXJyb3IgKSB7XG5cblx0XHRcdFx0XHRvbkVycm9yKCBlICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoIGUgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xuXG5cdFx0XHR9XG5cblx0XHR9LCBvblByb2dyZXNzLCBvbkVycm9yICk7XG5cblx0fVxuXG5cdHBhcnNlKCBqc29uICkge1xuXG5cdFx0Y29uc3QgaW50ZXJsZWF2ZWRCdWZmZXJNYXAgPSB7fTtcblx0XHRjb25zdCBhcnJheUJ1ZmZlck1hcCA9IHt9O1xuXG5cdFx0ZnVuY3Rpb24gZ2V0SW50ZXJsZWF2ZWRCdWZmZXIoIGpzb24sIHV1aWQgKSB7XG5cblx0XHRcdGlmICggaW50ZXJsZWF2ZWRCdWZmZXJNYXBbIHV1aWQgXSAhPT0gdW5kZWZpbmVkICkgcmV0dXJuIGludGVybGVhdmVkQnVmZmVyTWFwWyB1dWlkIF07XG5cblx0XHRcdGNvbnN0IGludGVybGVhdmVkQnVmZmVycyA9IGpzb24uaW50ZXJsZWF2ZWRCdWZmZXJzO1xuXHRcdFx0Y29uc3QgaW50ZXJsZWF2ZWRCdWZmZXIgPSBpbnRlcmxlYXZlZEJ1ZmZlcnNbIHV1aWQgXTtcblxuXHRcdFx0Y29uc3QgYnVmZmVyID0gZ2V0QXJyYXlCdWZmZXIoIGpzb24sIGludGVybGVhdmVkQnVmZmVyLmJ1ZmZlciApO1xuXG5cdFx0XHRjb25zdCBhcnJheSA9IGdldFR5cGVkQXJyYXkoIGludGVybGVhdmVkQnVmZmVyLnR5cGUsIGJ1ZmZlciApO1xuXHRcdFx0Y29uc3QgaWIgPSBuZXcgSW50ZXJsZWF2ZWRCdWZmZXIoIGFycmF5LCBpbnRlcmxlYXZlZEJ1ZmZlci5zdHJpZGUgKTtcblx0XHRcdGliLnV1aWQgPSBpbnRlcmxlYXZlZEJ1ZmZlci51dWlkO1xuXG5cdFx0XHRpbnRlcmxlYXZlZEJ1ZmZlck1hcFsgdXVpZCBdID0gaWI7XG5cblx0XHRcdHJldHVybiBpYjtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdldEFycmF5QnVmZmVyKCBqc29uLCB1dWlkICkge1xuXG5cdFx0XHRpZiAoIGFycmF5QnVmZmVyTWFwWyB1dWlkIF0gIT09IHVuZGVmaW5lZCApIHJldHVybiBhcnJheUJ1ZmZlck1hcFsgdXVpZCBdO1xuXG5cdFx0XHRjb25zdCBhcnJheUJ1ZmZlcnMgPSBqc29uLmFycmF5QnVmZmVycztcblx0XHRcdGNvbnN0IGFycmF5QnVmZmVyID0gYXJyYXlCdWZmZXJzWyB1dWlkIF07XG5cblx0XHRcdGNvbnN0IGFiID0gbmV3IFVpbnQzMkFycmF5KCBhcnJheUJ1ZmZlciApLmJ1ZmZlcjtcblxuXHRcdFx0YXJyYXlCdWZmZXJNYXBbIHV1aWQgXSA9IGFiO1xuXG5cdFx0XHRyZXR1cm4gYWI7XG5cblx0XHR9XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IGpzb24uaXNJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSA/IG5ldyBJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSgpIDogbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cblx0XHRjb25zdCBpbmRleCA9IGpzb24uZGF0YS5pbmRleDtcblxuXHRcdGlmICggaW5kZXggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3QgdHlwZWRBcnJheSA9IGdldFR5cGVkQXJyYXkoIGluZGV4LnR5cGUsIGluZGV4LmFycmF5ICk7XG5cdFx0XHRnZW9tZXRyeS5zZXRJbmRleCggbmV3IEJ1ZmZlckF0dHJpYnV0ZSggdHlwZWRBcnJheSwgMSApICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBhdHRyaWJ1dGVzID0ganNvbi5kYXRhLmF0dHJpYnV0ZXM7XG5cblx0XHRmb3IgKCBjb25zdCBrZXkgaW4gYXR0cmlidXRlcyApIHtcblxuXHRcdFx0Y29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlc1sga2V5IF07XG5cdFx0XHRsZXQgYnVmZmVyQXR0cmlidXRlO1xuXG5cdFx0XHRpZiAoIGF0dHJpYnV0ZS5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlICkge1xuXG5cdFx0XHRcdGNvbnN0IGludGVybGVhdmVkQnVmZmVyID0gZ2V0SW50ZXJsZWF2ZWRCdWZmZXIoIGpzb24uZGF0YSwgYXR0cmlidXRlLmRhdGEgKTtcblx0XHRcdFx0YnVmZmVyQXR0cmlidXRlID0gbmV3IEludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlKCBpbnRlcmxlYXZlZEJ1ZmZlciwgYXR0cmlidXRlLml0ZW1TaXplLCBhdHRyaWJ1dGUub2Zmc2V0LCBhdHRyaWJ1dGUubm9ybWFsaXplZCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNvbnN0IHR5cGVkQXJyYXkgPSBnZXRUeXBlZEFycmF5KCBhdHRyaWJ1dGUudHlwZSwgYXR0cmlidXRlLmFycmF5ICk7XG5cdFx0XHRcdGNvbnN0IGJ1ZmZlckF0dHJpYnV0ZUNvbnN0ciA9IGF0dHJpYnV0ZS5pc0luc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSA/IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSA6IEJ1ZmZlckF0dHJpYnV0ZTtcblx0XHRcdFx0YnVmZmVyQXR0cmlidXRlID0gbmV3IGJ1ZmZlckF0dHJpYnV0ZUNvbnN0ciggdHlwZWRBcnJheSwgYXR0cmlidXRlLml0ZW1TaXplLCBhdHRyaWJ1dGUubm9ybWFsaXplZCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggYXR0cmlidXRlLm5hbWUgIT09IHVuZGVmaW5lZCApIGJ1ZmZlckF0dHJpYnV0ZS5uYW1lID0gYXR0cmlidXRlLm5hbWU7XG5cdFx0XHRpZiAoIGF0dHJpYnV0ZS51c2FnZSAhPT0gdW5kZWZpbmVkICkgYnVmZmVyQXR0cmlidXRlLnNldFVzYWdlKCBhdHRyaWJ1dGUudXNhZ2UgKTtcblxuXHRcdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCBrZXksIGJ1ZmZlckF0dHJpYnV0ZSApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzID0ganNvbi5kYXRhLm1vcnBoQXR0cmlidXRlcztcblxuXHRcdGlmICggbW9ycGhBdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRmb3IgKCBjb25zdCBrZXkgaW4gbW9ycGhBdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRcdGNvbnN0IGF0dHJpYnV0ZUFycmF5ID0gbW9ycGhBdHRyaWJ1dGVzWyBrZXkgXTtcblxuXHRcdFx0XHRjb25zdCBhcnJheSA9IFtdO1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBhdHRyaWJ1dGVBcnJheS5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZUFycmF5WyBpIF07XG5cdFx0XHRcdFx0bGV0IGJ1ZmZlckF0dHJpYnV0ZTtcblxuXHRcdFx0XHRcdGlmICggYXR0cmlidXRlLmlzSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGludGVybGVhdmVkQnVmZmVyID0gZ2V0SW50ZXJsZWF2ZWRCdWZmZXIoIGpzb24uZGF0YSwgYXR0cmlidXRlLmRhdGEgKTtcblx0XHRcdFx0XHRcdGJ1ZmZlckF0dHJpYnV0ZSA9IG5ldyBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSggaW50ZXJsZWF2ZWRCdWZmZXIsIGF0dHJpYnV0ZS5pdGVtU2l6ZSwgYXR0cmlidXRlLm9mZnNldCwgYXR0cmlidXRlLm5vcm1hbGl6ZWQgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IHR5cGVkQXJyYXkgPSBnZXRUeXBlZEFycmF5KCBhdHRyaWJ1dGUudHlwZSwgYXR0cmlidXRlLmFycmF5ICk7XG5cdFx0XHRcdFx0XHRidWZmZXJBdHRyaWJ1dGUgPSBuZXcgQnVmZmVyQXR0cmlidXRlKCB0eXBlZEFycmF5LCBhdHRyaWJ1dGUuaXRlbVNpemUsIGF0dHJpYnV0ZS5ub3JtYWxpemVkICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoIGF0dHJpYnV0ZS5uYW1lICE9PSB1bmRlZmluZWQgKSBidWZmZXJBdHRyaWJ1dGUubmFtZSA9IGF0dHJpYnV0ZS5uYW1lO1xuXHRcdFx0XHRcdGFycmF5LnB1c2goIGJ1ZmZlckF0dHJpYnV0ZSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXNbIGtleSBdID0gYXJyYXk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IG1vcnBoVGFyZ2V0c1JlbGF0aXZlID0ganNvbi5kYXRhLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xuXG5cdFx0aWYgKCBtb3JwaFRhcmdldHNSZWxhdGl2ZSApIHtcblxuXHRcdFx0Z2VvbWV0cnkubW9ycGhUYXJnZXRzUmVsYXRpdmUgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgZ3JvdXBzID0ganNvbi5kYXRhLmdyb3VwcyB8fCBqc29uLmRhdGEuZHJhd2NhbGxzIHx8IGpzb24uZGF0YS5vZmZzZXRzO1xuXG5cdFx0aWYgKCBncm91cHMgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gZ3JvdXBzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xuXG5cdFx0XHRcdGdlb21ldHJ5LmFkZEdyb3VwKCBncm91cC5zdGFydCwgZ3JvdXAuY291bnQsIGdyb3VwLm1hdGVyaWFsSW5kZXggKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Y29uc3QgYm91bmRpbmdTcGhlcmUgPSBqc29uLmRhdGEuYm91bmRpbmdTcGhlcmU7XG5cblx0XHRpZiAoIGJvdW5kaW5nU3BoZXJlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IGNlbnRlciA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRcdGlmICggYm91bmRpbmdTcGhlcmUuY2VudGVyICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y2VudGVyLmZyb21BcnJheSggYm91bmRpbmdTcGhlcmUuY2VudGVyICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Z2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCBjZW50ZXIsIGJvdW5kaW5nU3BoZXJlLnJhZGl1cyApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBqc29uLm5hbWUgKSBnZW9tZXRyeS5uYW1lID0ganNvbi5uYW1lO1xuXHRcdGlmICgganNvbi51c2VyRGF0YSApIGdlb21ldHJ5LnVzZXJEYXRhID0ganNvbi51c2VyRGF0YTtcblxuXHRcdHJldHVybiBnZW9tZXRyeTtcblxuXHR9XG5cbn1cblxuY2xhc3MgT2JqZWN0TG9hZGVyIGV4dGVuZHMgTG9hZGVyIHtcblxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcblxuXHRcdHN1cGVyKCBtYW5hZ2VyICk7XG5cblx0fVxuXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0Y29uc3QgcGF0aCA9ICggdGhpcy5wYXRoID09PSAnJyApID8gTG9hZGVyVXRpbHMuZXh0cmFjdFVybEJhc2UoIHVybCApIDogdGhpcy5wYXRoO1xuXHRcdHRoaXMucmVzb3VyY2VQYXRoID0gdGhpcy5yZXNvdXJjZVBhdGggfHwgcGF0aDtcblxuXHRcdGNvbnN0IGxvYWRlciA9IG5ldyBGaWxlTG9hZGVyKCB0aGlzLm1hbmFnZXIgKTtcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XG5cdFx0bG9hZGVyLnNldFJlcXVlc3RIZWFkZXIoIHRoaXMucmVxdWVzdEhlYWRlciApO1xuXHRcdGxvYWRlci5zZXRXaXRoQ3JlZGVudGlhbHMoIHRoaXMud2l0aENyZWRlbnRpYWxzICk7XG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCB0ZXh0ICkge1xuXG5cdFx0XHRsZXQganNvbiA9IG51bGw7XG5cblx0XHRcdHRyeSB7XG5cblx0XHRcdFx0anNvbiA9IEpTT04ucGFyc2UoIHRleHQgKTtcblxuXHRcdFx0fSBjYXRjaCAoIGVycm9yICkge1xuXG5cdFx0XHRcdGlmICggb25FcnJvciAhPT0gdW5kZWZpbmVkICkgb25FcnJvciggZXJyb3IgKTtcblxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUU6T2JqZWN0TG9hZGVyOiBDYW5cXCd0IHBhcnNlICcgKyB1cmwgKyAnLicsIGVycm9yLm1lc3NhZ2UgKTtcblxuXHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgbWV0YWRhdGEgPSBqc29uLm1ldGFkYXRhO1xuXG5cdFx0XHRpZiAoIG1ldGFkYXRhID09PSB1bmRlZmluZWQgfHwgbWV0YWRhdGEudHlwZSA9PT0gdW5kZWZpbmVkIHx8IG1ldGFkYXRhLnR5cGUudG9Mb3dlckNhc2UoKSA9PT0gJ2dlb21ldHJ5JyApIHtcblxuXHRcdFx0XHRpZiAoIG9uRXJyb3IgIT09IHVuZGVmaW5lZCApIG9uRXJyb3IoIG5ldyBFcnJvciggJ1RIUkVFLk9iamVjdExvYWRlcjogQ2FuXFwndCBsb2FkICcgKyB1cmwgKSApO1xuXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5PYmplY3RMb2FkZXI6IENhblxcJ3QgbG9hZCAnICsgdXJsICk7XG5cdFx0XHRcdHJldHVybjtcblxuXHRcdFx0fVxuXG5cdFx0XHRzY29wZS5wYXJzZSgganNvbiwgb25Mb2FkICk7XG5cblx0XHR9LCBvblByb2dyZXNzLCBvbkVycm9yICk7XG5cblx0fVxuXG5cdGFzeW5jIGxvYWRBc3luYyggdXJsLCBvblByb2dyZXNzICkge1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0Y29uc3QgcGF0aCA9ICggdGhpcy5wYXRoID09PSAnJyApID8gTG9hZGVyVXRpbHMuZXh0cmFjdFVybEJhc2UoIHVybCApIDogdGhpcy5wYXRoO1xuXHRcdHRoaXMucmVzb3VyY2VQYXRoID0gdGhpcy5yZXNvdXJjZVBhdGggfHwgcGF0aDtcblxuXHRcdGNvbnN0IGxvYWRlciA9IG5ldyBGaWxlTG9hZGVyKCB0aGlzLm1hbmFnZXIgKTtcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XG5cdFx0bG9hZGVyLnNldFJlcXVlc3RIZWFkZXIoIHRoaXMucmVxdWVzdEhlYWRlciApO1xuXHRcdGxvYWRlci5zZXRXaXRoQ3JlZGVudGlhbHMoIHRoaXMud2l0aENyZWRlbnRpYWxzICk7XG5cblx0XHRjb25zdCB0ZXh0ID0gYXdhaXQgbG9hZGVyLmxvYWRBc3luYyggdXJsLCBvblByb2dyZXNzICk7XG5cblx0XHRjb25zdCBqc29uID0gSlNPTi5wYXJzZSggdGV4dCApO1xuXG5cdFx0Y29uc3QgbWV0YWRhdGEgPSBqc29uLm1ldGFkYXRhO1xuXG5cdFx0aWYgKCBtZXRhZGF0YSA9PT0gdW5kZWZpbmVkIHx8IG1ldGFkYXRhLnR5cGUgPT09IHVuZGVmaW5lZCB8fCBtZXRhZGF0YS50eXBlLnRvTG93ZXJDYXNlKCkgPT09ICdnZW9tZXRyeScgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLk9iamVjdExvYWRlcjogQ2FuXFwndCBsb2FkICcgKyB1cmwgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBhd2FpdCBzY29wZS5wYXJzZUFzeW5jKCBqc29uICk7XG5cblx0fVxuXG5cdHBhcnNlKCBqc29uLCBvbkxvYWQgKSB7XG5cblx0XHRjb25zdCBhbmltYXRpb25zID0gdGhpcy5wYXJzZUFuaW1hdGlvbnMoIGpzb24uYW5pbWF0aW9ucyApO1xuXHRcdGNvbnN0IHNoYXBlcyA9IHRoaXMucGFyc2VTaGFwZXMoIGpzb24uc2hhcGVzICk7XG5cdFx0Y29uc3QgZ2VvbWV0cmllcyA9IHRoaXMucGFyc2VHZW9tZXRyaWVzKCBqc29uLmdlb21ldHJpZXMsIHNoYXBlcyApO1xuXG5cdFx0Y29uc3QgaW1hZ2VzID0gdGhpcy5wYXJzZUltYWdlcygganNvbi5pbWFnZXMsIGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0aWYgKCBvbkxvYWQgIT09IHVuZGVmaW5lZCApIG9uTG9hZCggb2JqZWN0ICk7XG5cblx0XHR9ICk7XG5cblx0XHRjb25zdCB0ZXh0dXJlcyA9IHRoaXMucGFyc2VUZXh0dXJlcygganNvbi50ZXh0dXJlcywgaW1hZ2VzICk7XG5cdFx0Y29uc3QgbWF0ZXJpYWxzID0gdGhpcy5wYXJzZU1hdGVyaWFscygganNvbi5tYXRlcmlhbHMsIHRleHR1cmVzICk7XG5cblx0XHRjb25zdCBvYmplY3QgPSB0aGlzLnBhcnNlT2JqZWN0KCBqc29uLm9iamVjdCwgZ2VvbWV0cmllcywgbWF0ZXJpYWxzLCB0ZXh0dXJlcywgYW5pbWF0aW9ucyApO1xuXHRcdGNvbnN0IHNrZWxldG9ucyA9IHRoaXMucGFyc2VTa2VsZXRvbnMoIGpzb24uc2tlbGV0b25zLCBvYmplY3QgKTtcblxuXHRcdHRoaXMuYmluZFNrZWxldG9ucyggb2JqZWN0LCBza2VsZXRvbnMgKTtcblx0XHR0aGlzLmJpbmRMaWdodFRhcmdldHMoIG9iamVjdCApO1xuXG5cdFx0Ly9cblxuXHRcdGlmICggb25Mb2FkICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGxldCBoYXNJbWFnZXMgPSBmYWxzZTtcblxuXHRcdFx0Zm9yICggY29uc3QgdXVpZCBpbiBpbWFnZXMgKSB7XG5cblx0XHRcdFx0aWYgKCBpbWFnZXNbIHV1aWQgXS5kYXRhIGluc3RhbmNlb2YgSFRNTEltYWdlRWxlbWVudCApIHtcblxuXHRcdFx0XHRcdGhhc0ltYWdlcyA9IHRydWU7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggaGFzSW1hZ2VzID09PSBmYWxzZSApIG9uTG9hZCggb2JqZWN0ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gb2JqZWN0O1xuXG5cdH1cblxuXHRhc3luYyBwYXJzZUFzeW5jKCBqc29uICkge1xuXG5cdFx0Y29uc3QgYW5pbWF0aW9ucyA9IHRoaXMucGFyc2VBbmltYXRpb25zKCBqc29uLmFuaW1hdGlvbnMgKTtcblx0XHRjb25zdCBzaGFwZXMgPSB0aGlzLnBhcnNlU2hhcGVzKCBqc29uLnNoYXBlcyApO1xuXHRcdGNvbnN0IGdlb21ldHJpZXMgPSB0aGlzLnBhcnNlR2VvbWV0cmllcygganNvbi5nZW9tZXRyaWVzLCBzaGFwZXMgKTtcblxuXHRcdGNvbnN0IGltYWdlcyA9IGF3YWl0IHRoaXMucGFyc2VJbWFnZXNBc3luYygganNvbi5pbWFnZXMgKTtcblxuXHRcdGNvbnN0IHRleHR1cmVzID0gdGhpcy5wYXJzZVRleHR1cmVzKCBqc29uLnRleHR1cmVzLCBpbWFnZXMgKTtcblx0XHRjb25zdCBtYXRlcmlhbHMgPSB0aGlzLnBhcnNlTWF0ZXJpYWxzKCBqc29uLm1hdGVyaWFscywgdGV4dHVyZXMgKTtcblxuXHRcdGNvbnN0IG9iamVjdCA9IHRoaXMucGFyc2VPYmplY3QoIGpzb24ub2JqZWN0LCBnZW9tZXRyaWVzLCBtYXRlcmlhbHMsIHRleHR1cmVzLCBhbmltYXRpb25zICk7XG5cdFx0Y29uc3Qgc2tlbGV0b25zID0gdGhpcy5wYXJzZVNrZWxldG9ucygganNvbi5za2VsZXRvbnMsIG9iamVjdCApO1xuXG5cdFx0dGhpcy5iaW5kU2tlbGV0b25zKCBvYmplY3QsIHNrZWxldG9ucyApO1xuXG5cdFx0cmV0dXJuIG9iamVjdDtcblxuXHR9XG5cblx0cGFyc2VTaGFwZXMoIGpzb24gKSB7XG5cblx0XHRjb25zdCBzaGFwZXMgPSB7fTtcblxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2hhcGUgPSBuZXcgU2hhcGUoKS5mcm9tSlNPTigganNvblsgaSBdICk7XG5cblx0XHRcdFx0c2hhcGVzWyBzaGFwZS51dWlkIF0gPSBzaGFwZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHNoYXBlcztcblxuXHR9XG5cblx0cGFyc2VTa2VsZXRvbnMoIGpzb24sIG9iamVjdCApIHtcblxuXHRcdGNvbnN0IHNrZWxldG9ucyA9IHt9O1xuXHRcdGNvbnN0IGJvbmVzID0ge307XG5cblx0XHQvLyBnZW5lcmF0ZSBib25lIGxvb2t1cCB0YWJsZVxuXG5cdFx0b2JqZWN0LnRyYXZlcnNlKCBmdW5jdGlvbiAoIGNoaWxkICkge1xuXG5cdFx0XHRpZiAoIGNoaWxkLmlzQm9uZSApIGJvbmVzWyBjaGlsZC51dWlkIF0gPSBjaGlsZDtcblxuXHRcdH0gKTtcblxuXHRcdC8vIGNyZWF0ZSBza2VsZXRvbnNcblxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2tlbGV0b24gPSBuZXcgU2tlbGV0b24oKS5mcm9tSlNPTigganNvblsgaSBdLCBib25lcyApO1xuXG5cdFx0XHRcdHNrZWxldG9uc1sgc2tlbGV0b24udXVpZCBdID0gc2tlbGV0b247XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiBza2VsZXRvbnM7XG5cblx0fVxuXG5cdHBhcnNlR2VvbWV0cmllcygganNvbiwgc2hhcGVzICkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cmllcyA9IHt9O1xuXG5cdFx0aWYgKCBqc29uICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IGJ1ZmZlckdlb21ldHJ5TG9hZGVyID0gbmV3IEJ1ZmZlckdlb21ldHJ5TG9hZGVyKCk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRsZXQgZ2VvbWV0cnk7XG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBqc29uWyBpIF07XG5cblx0XHRcdFx0c3dpdGNoICggZGF0YS50eXBlICkge1xuXG5cdFx0XHRcdFx0Y2FzZSAnQnVmZmVyR2VvbWV0cnknOlxuXHRcdFx0XHRcdGNhc2UgJ0luc3RhbmNlZEJ1ZmZlckdlb21ldHJ5JzpcblxuXHRcdFx0XHRcdFx0Z2VvbWV0cnkgPSBidWZmZXJHZW9tZXRyeUxvYWRlci5wYXJzZSggZGF0YSApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRkZWZhdWx0OlxuXG5cdFx0XHRcdFx0XHRpZiAoIGRhdGEudHlwZSBpbiBHZW9tZXRyaWVzICkge1xuXG5cdFx0XHRcdFx0XHRcdGdlb21ldHJ5ID0gR2VvbWV0cmllc1sgZGF0YS50eXBlIF0uZnJvbUpTT04oIGRhdGEsIHNoYXBlcyApO1xuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggYFRIUkVFLk9iamVjdExvYWRlcjogVW5zdXBwb3J0ZWQgZ2VvbWV0cnkgdHlwZSBcIiR7IGRhdGEudHlwZSB9XCJgICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Z2VvbWV0cnkudXVpZCA9IGRhdGEudXVpZDtcblxuXHRcdFx0XHRpZiAoIGRhdGEubmFtZSAhPT0gdW5kZWZpbmVkICkgZ2VvbWV0cnkubmFtZSA9IGRhdGEubmFtZTtcblx0XHRcdFx0aWYgKCBkYXRhLnVzZXJEYXRhICE9PSB1bmRlZmluZWQgKSBnZW9tZXRyeS51c2VyRGF0YSA9IGRhdGEudXNlckRhdGE7XG5cblx0XHRcdFx0Z2VvbWV0cmllc1sgZGF0YS51dWlkIF0gPSBnZW9tZXRyeTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGdlb21ldHJpZXM7XG5cblx0fVxuXG5cdHBhcnNlTWF0ZXJpYWxzKCBqc29uLCB0ZXh0dXJlcyApIHtcblxuXHRcdGNvbnN0IGNhY2hlID0ge307IC8vIE11bHRpTWF0ZXJpYWxcblx0XHRjb25zdCBtYXRlcmlhbHMgPSB7fTtcblxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjb25zdCBsb2FkZXIgPSBuZXcgTWF0ZXJpYWxMb2FkZXIoKTtcblx0XHRcdGxvYWRlci5zZXRUZXh0dXJlcyggdGV4dHVyZXMgKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0ganNvbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBqc29uWyBpIF07XG5cblx0XHRcdFx0aWYgKCBjYWNoZVsgZGF0YS51dWlkIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGNhY2hlWyBkYXRhLnV1aWQgXSA9IGxvYWRlci5wYXJzZSggZGF0YSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRtYXRlcmlhbHNbIGRhdGEudXVpZCBdID0gY2FjaGVbIGRhdGEudXVpZCBdO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gbWF0ZXJpYWxzO1xuXG5cdH1cblxuXHRwYXJzZUFuaW1hdGlvbnMoIGpzb24gKSB7XG5cblx0XHRjb25zdCBhbmltYXRpb25zID0ge307XG5cblx0XHRpZiAoIGpzb24gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwganNvbi5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgZGF0YSA9IGpzb25bIGkgXTtcblxuXHRcdFx0XHRjb25zdCBjbGlwID0gQW5pbWF0aW9uQ2xpcC5wYXJzZSggZGF0YSApO1xuXG5cdFx0XHRcdGFuaW1hdGlvbnNbIGNsaXAudXVpZCBdID0gY2xpcDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFuaW1hdGlvbnM7XG5cblx0fVxuXG5cdHBhcnNlSW1hZ2VzKCBqc29uLCBvbkxvYWQgKSB7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cdFx0Y29uc3QgaW1hZ2VzID0ge307XG5cblx0XHRsZXQgbG9hZGVyO1xuXG5cdFx0ZnVuY3Rpb24gbG9hZEltYWdlKCB1cmwgKSB7XG5cblx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbVN0YXJ0KCB1cmwgKTtcblxuXHRcdFx0cmV0dXJuIGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xuXG5cdFx0XHR9LCB1bmRlZmluZWQsIGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FcnJvciggdXJsICk7XG5cdFx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbUVuZCggdXJsICk7XG5cblx0XHRcdH0gKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGRlc2VyaWFsaXplSW1hZ2UoIGltYWdlICkge1xuXG5cdFx0XHRpZiAoIHR5cGVvZiBpbWFnZSA9PT0gJ3N0cmluZycgKSB7XG5cblx0XHRcdFx0Y29uc3QgdXJsID0gaW1hZ2U7XG5cblx0XHRcdFx0Y29uc3QgcGF0aCA9IC9eKFxcL1xcLyl8KFthLXpdKzooXFwvXFwvKT8pL2kudGVzdCggdXJsICkgPyB1cmwgOiBzY29wZS5yZXNvdXJjZVBhdGggKyB1cmw7XG5cblx0XHRcdFx0cmV0dXJuIGxvYWRJbWFnZSggcGF0aCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGlmICggaW1hZ2UuZGF0YSApIHtcblxuXHRcdFx0XHRcdHJldHVybiB7XG5cdFx0XHRcdFx0XHRkYXRhOiBnZXRUeXBlZEFycmF5KCBpbWFnZS50eXBlLCBpbWFnZS5kYXRhICksXG5cdFx0XHRcdFx0XHR3aWR0aDogaW1hZ2Uud2lkdGgsXG5cdFx0XHRcdFx0XHRoZWlnaHQ6IGltYWdlLmhlaWdodFxuXHRcdFx0XHRcdH07XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBqc29uICE9PSB1bmRlZmluZWQgJiYganNvbi5sZW5ndGggPiAwICkge1xuXG5cdFx0XHRjb25zdCBtYW5hZ2VyID0gbmV3IExvYWRpbmdNYW5hZ2VyKCBvbkxvYWQgKTtcblxuXHRcdFx0bG9hZGVyID0gbmV3IEltYWdlTG9hZGVyKCBtYW5hZ2VyICk7XG5cdFx0XHRsb2FkZXIuc2V0Q3Jvc3NPcmlnaW4oIHRoaXMuY3Jvc3NPcmlnaW4gKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGpzb24ubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgaW1hZ2UgPSBqc29uWyBpIF07XG5cdFx0XHRcdGNvbnN0IHVybCA9IGltYWdlLnVybDtcblxuXHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHVybCApICkge1xuXG5cdFx0XHRcdFx0Ly8gbG9hZCBhcnJheSBvZiBpbWFnZXMgZS5nIEN1YmVUZXh0dXJlXG5cblx0XHRcdFx0XHRjb25zdCBpbWFnZUFycmF5ID0gW107XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIGpsID0gdXJsLmxlbmd0aDsgaiA8IGpsOyBqICsrICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBjdXJyZW50VXJsID0gdXJsWyBqIF07XG5cblx0XHRcdFx0XHRcdGNvbnN0IGRlc2VyaWFsaXplZEltYWdlID0gZGVzZXJpYWxpemVJbWFnZSggY3VycmVudFVybCApO1xuXG5cdFx0XHRcdFx0XHRpZiAoIGRlc2VyaWFsaXplZEltYWdlICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggZGVzZXJpYWxpemVkSW1hZ2UgaW5zdGFuY2VvZiBIVE1MSW1hZ2VFbGVtZW50ICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0aW1hZ2VBcnJheS5wdXNoKCBkZXNlcmlhbGl6ZWRJbWFnZSApO1xuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHQvLyBzcGVjaWFsIGNhc2U6IGhhbmRsZSBhcnJheSBvZiBkYXRhIHRleHR1cmVzIGZvciBjdWJlIHRleHR1cmVzXG5cblx0XHRcdFx0XHRcdFx0XHRpbWFnZUFycmF5LnB1c2goIG5ldyBEYXRhVGV4dHVyZSggZGVzZXJpYWxpemVkSW1hZ2UuZGF0YSwgZGVzZXJpYWxpemVkSW1hZ2Uud2lkdGgsIGRlc2VyaWFsaXplZEltYWdlLmhlaWdodCApICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpbWFnZXNbIGltYWdlLnV1aWQgXSA9IG5ldyBTb3VyY2UoIGltYWdlQXJyYXkgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ly8gbG9hZCBzaW5nbGUgaW1hZ2VcblxuXHRcdFx0XHRcdGNvbnN0IGRlc2VyaWFsaXplZEltYWdlID0gZGVzZXJpYWxpemVJbWFnZSggaW1hZ2UudXJsICk7XG5cdFx0XHRcdFx0aW1hZ2VzWyBpbWFnZS51dWlkIF0gPSBuZXcgU291cmNlKCBkZXNlcmlhbGl6ZWRJbWFnZSApO1xuXG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gaW1hZ2VzO1xuXG5cdH1cblxuXHRhc3luYyBwYXJzZUltYWdlc0FzeW5jKCBqc29uICkge1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXHRcdGNvbnN0IGltYWdlcyA9IHt9O1xuXG5cdFx0bGV0IGxvYWRlcjtcblxuXHRcdGFzeW5jIGZ1bmN0aW9uIGRlc2VyaWFsaXplSW1hZ2UoIGltYWdlICkge1xuXG5cdFx0XHRpZiAoIHR5cGVvZiBpbWFnZSA9PT0gJ3N0cmluZycgKSB7XG5cblx0XHRcdFx0Y29uc3QgdXJsID0gaW1hZ2U7XG5cblx0XHRcdFx0Y29uc3QgcGF0aCA9IC9eKFxcL1xcLyl8KFthLXpdKzooXFwvXFwvKT8pL2kudGVzdCggdXJsICkgPyB1cmwgOiBzY29wZS5yZXNvdXJjZVBhdGggKyB1cmw7XG5cblx0XHRcdFx0cmV0dXJuIGF3YWl0IGxvYWRlci5sb2FkQXN5bmMoIHBhdGggKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRpZiAoIGltYWdlLmRhdGEgKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdFx0ZGF0YTogZ2V0VHlwZWRBcnJheSggaW1hZ2UudHlwZSwgaW1hZ2UuZGF0YSApLFxuXHRcdFx0XHRcdFx0d2lkdGg6IGltYWdlLndpZHRoLFxuXHRcdFx0XHRcdFx0aGVpZ2h0OiBpbWFnZS5oZWlnaHRcblx0XHRcdFx0XHR9O1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICYmIGpzb24ubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0bG9hZGVyID0gbmV3IEltYWdlTG9hZGVyKCB0aGlzLm1hbmFnZXIgKTtcblx0XHRcdGxvYWRlci5zZXRDcm9zc09yaWdpbiggdGhpcy5jcm9zc09yaWdpbiApO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0ganNvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbWFnZSA9IGpzb25bIGkgXTtcblx0XHRcdFx0Y29uc3QgdXJsID0gaW1hZ2UudXJsO1xuXG5cdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggdXJsICkgKSB7XG5cblx0XHRcdFx0XHQvLyBsb2FkIGFycmF5IG9mIGltYWdlcyBlLmcgQ3ViZVRleHR1cmVcblxuXHRcdFx0XHRcdGNvbnN0IGltYWdlQXJyYXkgPSBbXTtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMCwgamwgPSB1cmwubGVuZ3RoOyBqIDwgamw7IGogKysgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGN1cnJlbnRVcmwgPSB1cmxbIGogXTtcblxuXHRcdFx0XHRcdFx0Y29uc3QgZGVzZXJpYWxpemVkSW1hZ2UgPSBhd2FpdCBkZXNlcmlhbGl6ZUltYWdlKCBjdXJyZW50VXJsICk7XG5cblx0XHRcdFx0XHRcdGlmICggZGVzZXJpYWxpemVkSW1hZ2UgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBkZXNlcmlhbGl6ZWRJbWFnZSBpbnN0YW5jZW9mIEhUTUxJbWFnZUVsZW1lbnQgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRpbWFnZUFycmF5LnB1c2goIGRlc2VyaWFsaXplZEltYWdlICk7XG5cblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIHNwZWNpYWwgY2FzZTogaGFuZGxlIGFycmF5IG9mIGRhdGEgdGV4dHVyZXMgZm9yIGN1YmUgdGV4dHVyZXNcblxuXHRcdFx0XHRcdFx0XHRcdGltYWdlQXJyYXkucHVzaCggbmV3IERhdGFUZXh0dXJlKCBkZXNlcmlhbGl6ZWRJbWFnZS5kYXRhLCBkZXNlcmlhbGl6ZWRJbWFnZS53aWR0aCwgZGVzZXJpYWxpemVkSW1hZ2UuaGVpZ2h0ICkgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGltYWdlc1sgaW1hZ2UudXVpZCBdID0gbmV3IFNvdXJjZSggaW1hZ2VBcnJheSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBsb2FkIHNpbmdsZSBpbWFnZVxuXG5cdFx0XHRcdFx0Y29uc3QgZGVzZXJpYWxpemVkSW1hZ2UgPSBhd2FpdCBkZXNlcmlhbGl6ZUltYWdlKCBpbWFnZS51cmwgKTtcblx0XHRcdFx0XHRpbWFnZXNbIGltYWdlLnV1aWQgXSA9IG5ldyBTb3VyY2UoIGRlc2VyaWFsaXplZEltYWdlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gaW1hZ2VzO1xuXG5cdH1cblxuXHRwYXJzZVRleHR1cmVzKCBqc29uLCBpbWFnZXMgKSB7XG5cblx0XHRmdW5jdGlvbiBwYXJzZUNvbnN0YW50KCB2YWx1ZSwgdHlwZSApIHtcblxuXHRcdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInICkgcmV0dXJuIHZhbHVlO1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXIucGFyc2VUZXh0dXJlOiBDb25zdGFudCBzaG91bGQgYmUgaW4gbnVtZXJpYyBmb3JtLicsIHZhbHVlICk7XG5cblx0XHRcdHJldHVybiB0eXBlWyB2YWx1ZSBdO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgdGV4dHVyZXMgPSB7fTtcblxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgZGF0YSA9IGpzb25bIGkgXTtcblxuXHRcdFx0XHRpZiAoIGRhdGEuaW1hZ2UgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLk9iamVjdExvYWRlcjogTm8gXCJpbWFnZVwiIHNwZWNpZmllZCBmb3InLCBkYXRhLnV1aWQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBpbWFnZXNbIGRhdGEuaW1hZ2UgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBVbmRlZmluZWQgaW1hZ2UnLCBkYXRhLmltYWdlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNvbnN0IHNvdXJjZSA9IGltYWdlc1sgZGF0YS5pbWFnZSBdO1xuXHRcdFx0XHRjb25zdCBpbWFnZSA9IHNvdXJjZS5kYXRhO1xuXG5cdFx0XHRcdGxldCB0ZXh0dXJlO1xuXG5cdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggaW1hZ2UgKSApIHtcblxuXHRcdFx0XHRcdHRleHR1cmUgPSBuZXcgQ3ViZVRleHR1cmUoKTtcblxuXHRcdFx0XHRcdGlmICggaW1hZ2UubGVuZ3RoID09PSA2ICkgdGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGlmICggaW1hZ2UgJiYgaW1hZ2UuZGF0YSApIHtcblxuXHRcdFx0XHRcdFx0dGV4dHVyZSA9IG5ldyBEYXRhVGV4dHVyZSgpO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0dGV4dHVyZSA9IG5ldyBUZXh0dXJlKCk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoIGltYWdlICkgdGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7IC8vIHRleHR1cmVzIGNhbiBoYXZlIHVuZGVmaW5lZCBpbWFnZSBkYXRhXG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRleHR1cmUuc291cmNlID0gc291cmNlO1xuXG5cdFx0XHRcdHRleHR1cmUudXVpZCA9IGRhdGEudXVpZDtcblxuXHRcdFx0XHRpZiAoIGRhdGEubmFtZSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5uYW1lID0gZGF0YS5uYW1lO1xuXG5cdFx0XHRcdGlmICggZGF0YS5tYXBwaW5nICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLm1hcHBpbmcgPSBwYXJzZUNvbnN0YW50KCBkYXRhLm1hcHBpbmcsIFRFWFRVUkVfTUFQUElORyApO1xuXHRcdFx0XHRpZiAoIGRhdGEuY2hhbm5lbCAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5jaGFubmVsID0gZGF0YS5jaGFubmVsO1xuXG5cdFx0XHRcdGlmICggZGF0YS5vZmZzZXQgIT09IHVuZGVmaW5lZCApIHRleHR1cmUub2Zmc2V0LmZyb21BcnJheSggZGF0YS5vZmZzZXQgKTtcblx0XHRcdFx0aWYgKCBkYXRhLnJlcGVhdCAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5yZXBlYXQuZnJvbUFycmF5KCBkYXRhLnJlcGVhdCApO1xuXHRcdFx0XHRpZiAoIGRhdGEuY2VudGVyICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmNlbnRlci5mcm9tQXJyYXkoIGRhdGEuY2VudGVyICk7XG5cdFx0XHRcdGlmICggZGF0YS5yb3RhdGlvbiAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5yb3RhdGlvbiA9IGRhdGEucm90YXRpb247XG5cblx0XHRcdFx0aWYgKCBkYXRhLndyYXAgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdHRleHR1cmUud3JhcFMgPSBwYXJzZUNvbnN0YW50KCBkYXRhLndyYXBbIDAgXSwgVEVYVFVSRV9XUkFQUElORyApO1xuXHRcdFx0XHRcdHRleHR1cmUud3JhcFQgPSBwYXJzZUNvbnN0YW50KCBkYXRhLndyYXBbIDEgXSwgVEVYVFVSRV9XUkFQUElORyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIGRhdGEuZm9ybWF0ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmZvcm1hdCA9IGRhdGEuZm9ybWF0O1xuXHRcdFx0XHRpZiAoIGRhdGEuaW50ZXJuYWxGb3JtYXQgIT09IHVuZGVmaW5lZCApIHRleHR1cmUuaW50ZXJuYWxGb3JtYXQgPSBkYXRhLmludGVybmFsRm9ybWF0O1xuXHRcdFx0XHRpZiAoIGRhdGEudHlwZSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS50eXBlID0gZGF0YS50eXBlO1xuXHRcdFx0XHRpZiAoIGRhdGEuY29sb3JTcGFjZSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5jb2xvclNwYWNlID0gZGF0YS5jb2xvclNwYWNlO1xuXG5cdFx0XHRcdGlmICggZGF0YS5taW5GaWx0ZXIgIT09IHVuZGVmaW5lZCApIHRleHR1cmUubWluRmlsdGVyID0gcGFyc2VDb25zdGFudCggZGF0YS5taW5GaWx0ZXIsIFRFWFRVUkVfRklMVEVSICk7XG5cdFx0XHRcdGlmICggZGF0YS5tYWdGaWx0ZXIgIT09IHVuZGVmaW5lZCApIHRleHR1cmUubWFnRmlsdGVyID0gcGFyc2VDb25zdGFudCggZGF0YS5tYWdGaWx0ZXIsIFRFWFRVUkVfRklMVEVSICk7XG5cdFx0XHRcdGlmICggZGF0YS5hbmlzb3Ryb3B5ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmFuaXNvdHJvcHkgPSBkYXRhLmFuaXNvdHJvcHk7XG5cblx0XHRcdFx0aWYgKCBkYXRhLmZsaXBZICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmZsaXBZID0gZGF0YS5mbGlwWTtcblxuXHRcdFx0XHRpZiAoIGRhdGEuZ2VuZXJhdGVNaXBtYXBzICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IGRhdGEuZ2VuZXJhdGVNaXBtYXBzO1xuXHRcdFx0XHRpZiAoIGRhdGEucHJlbXVsdGlwbHlBbHBoYSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5wcmVtdWx0aXBseUFscGhhID0gZGF0YS5wcmVtdWx0aXBseUFscGhhO1xuXHRcdFx0XHRpZiAoIGRhdGEudW5wYWNrQWxpZ25tZW50ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLnVucGFja0FsaWdubWVudCA9IGRhdGEudW5wYWNrQWxpZ25tZW50O1xuXHRcdFx0XHRpZiAoIGRhdGEuY29tcGFyZUZ1bmN0aW9uICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmNvbXBhcmVGdW5jdGlvbiA9IGRhdGEuY29tcGFyZUZ1bmN0aW9uO1xuXG5cdFx0XHRcdGlmICggZGF0YS51c2VyRGF0YSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS51c2VyRGF0YSA9IGRhdGEudXNlckRhdGE7XG5cblx0XHRcdFx0dGV4dHVyZXNbIGRhdGEudXVpZCBdID0gdGV4dHVyZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRleHR1cmVzO1xuXG5cdH1cblxuXHRwYXJzZU9iamVjdCggZGF0YSwgZ2VvbWV0cmllcywgbWF0ZXJpYWxzLCB0ZXh0dXJlcywgYW5pbWF0aW9ucyApIHtcblxuXHRcdGxldCBvYmplY3Q7XG5cblx0XHRmdW5jdGlvbiBnZXRHZW9tZXRyeSggbmFtZSApIHtcblxuXHRcdFx0aWYgKCBnZW9tZXRyaWVzWyBuYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXI6IFVuZGVmaW5lZCBnZW9tZXRyeScsIG5hbWUgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZ2VvbWV0cmllc1sgbmFtZSBdO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gZ2V0TWF0ZXJpYWwoIG5hbWUgKSB7XG5cblx0XHRcdGlmICggbmFtZSA9PT0gdW5kZWZpbmVkICkgcmV0dXJuIHVuZGVmaW5lZDtcblxuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBuYW1lICkgKSB7XG5cblx0XHRcdFx0Y29uc3QgYXJyYXkgPSBbXTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBuYW1lLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB1dWlkID0gbmFtZVsgaSBdO1xuXG5cdFx0XHRcdFx0aWYgKCBtYXRlcmlhbHNbIHV1aWQgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXI6IFVuZGVmaW5lZCBtYXRlcmlhbCcsIHV1aWQgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGFycmF5LnB1c2goIG1hdGVyaWFsc1sgdXVpZCBdICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiBhcnJheTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG1hdGVyaWFsc1sgbmFtZSBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBVbmRlZmluZWQgbWF0ZXJpYWwnLCBuYW1lICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIG1hdGVyaWFsc1sgbmFtZSBdO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gZ2V0VGV4dHVyZSggdXVpZCApIHtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlc1sgdXVpZCBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBVbmRlZmluZWQgdGV4dHVyZScsIHV1aWQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gdGV4dHVyZXNbIHV1aWQgXTtcblxuXHRcdH1cblxuXHRcdGxldCBnZW9tZXRyeSwgbWF0ZXJpYWw7XG5cblx0XHRzd2l0Y2ggKCBkYXRhLnR5cGUgKSB7XG5cblx0XHRcdGNhc2UgJ1NjZW5lJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgU2NlbmUoKTtcblxuXHRcdFx0XHRpZiAoIGRhdGEuYmFja2dyb3VuZCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0aWYgKCBOdW1iZXIuaXNJbnRlZ2VyKCBkYXRhLmJhY2tncm91bmQgKSApIHtcblxuXHRcdFx0XHRcdFx0b2JqZWN0LmJhY2tncm91bmQgPSBuZXcgQ29sb3IoIGRhdGEuYmFja2dyb3VuZCApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0b2JqZWN0LmJhY2tncm91bmQgPSBnZXRUZXh0dXJlKCBkYXRhLmJhY2tncm91bmQgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBkYXRhLmVudmlyb25tZW50ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRvYmplY3QuZW52aXJvbm1lbnQgPSBnZXRUZXh0dXJlKCBkYXRhLmVudmlyb25tZW50ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggZGF0YS5mb2cgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGlmICggZGF0YS5mb2cudHlwZSA9PT0gJ0ZvZycgKSB7XG5cblx0XHRcdFx0XHRcdG9iamVjdC5mb2cgPSBuZXcgRm9nKCBkYXRhLmZvZy5jb2xvciwgZGF0YS5mb2cubmVhciwgZGF0YS5mb2cuZmFyICk7XG5cblx0XHRcdFx0XHR9IGVsc2UgaWYgKCBkYXRhLmZvZy50eXBlID09PSAnRm9nRXhwMicgKSB7XG5cblx0XHRcdFx0XHRcdG9iamVjdC5mb2cgPSBuZXcgRm9nRXhwMiggZGF0YS5mb2cuY29sb3IsIGRhdGEuZm9nLmRlbnNpdHkgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggZGF0YS5mb2cubmFtZSAhPT0gJycgKSB7XG5cblx0XHRcdFx0XHRcdG9iamVjdC5mb2cubmFtZSA9IGRhdGEuZm9nLm5hbWU7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggZGF0YS5iYWNrZ3JvdW5kQmx1cnJpbmVzcyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmJhY2tncm91bmRCbHVycmluZXNzID0gZGF0YS5iYWNrZ3JvdW5kQmx1cnJpbmVzcztcblx0XHRcdFx0aWYgKCBkYXRhLmJhY2tncm91bmRJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCApIG9iamVjdC5iYWNrZ3JvdW5kSW50ZW5zaXR5ID0gZGF0YS5iYWNrZ3JvdW5kSW50ZW5zaXR5O1xuXHRcdFx0XHRpZiAoIGRhdGEuYmFja2dyb3VuZFJvdGF0aW9uICE9PSB1bmRlZmluZWQgKSBvYmplY3QuYmFja2dyb3VuZFJvdGF0aW9uLmZyb21BcnJheSggZGF0YS5iYWNrZ3JvdW5kUm90YXRpb24gKTtcblxuXHRcdFx0XHRpZiAoIGRhdGEuZW52aXJvbm1lbnRJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCApIG9iamVjdC5lbnZpcm9ubWVudEludGVuc2l0eSA9IGRhdGEuZW52aXJvbm1lbnRJbnRlbnNpdHk7XG5cdFx0XHRcdGlmICggZGF0YS5lbnZpcm9ubWVudFJvdGF0aW9uICE9PSB1bmRlZmluZWQgKSBvYmplY3QuZW52aXJvbm1lbnRSb3RhdGlvbi5mcm9tQXJyYXkoIGRhdGEuZW52aXJvbm1lbnRSb3RhdGlvbiApO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdQZXJzcGVjdGl2ZUNhbWVyYSc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCBkYXRhLmZvdiwgZGF0YS5hc3BlY3QsIGRhdGEubmVhciwgZGF0YS5mYXIgKTtcblxuXHRcdFx0XHRpZiAoIGRhdGEuZm9jdXMgIT09IHVuZGVmaW5lZCApIG9iamVjdC5mb2N1cyA9IGRhdGEuZm9jdXM7XG5cdFx0XHRcdGlmICggZGF0YS56b29tICE9PSB1bmRlZmluZWQgKSBvYmplY3Quem9vbSA9IGRhdGEuem9vbTtcblx0XHRcdFx0aWYgKCBkYXRhLmZpbG1HYXVnZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmZpbG1HYXVnZSA9IGRhdGEuZmlsbUdhdWdlO1xuXHRcdFx0XHRpZiAoIGRhdGEuZmlsbU9mZnNldCAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmZpbG1PZmZzZXQgPSBkYXRhLmZpbG1PZmZzZXQ7XG5cdFx0XHRcdGlmICggZGF0YS52aWV3ICE9PSB1bmRlZmluZWQgKSBvYmplY3QudmlldyA9IE9iamVjdC5hc3NpZ24oIHt9LCBkYXRhLnZpZXcgKTtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnT3J0aG9ncmFwaGljQ2FtZXJhJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgT3J0aG9ncmFwaGljQ2FtZXJhKCBkYXRhLmxlZnQsIGRhdGEucmlnaHQsIGRhdGEudG9wLCBkYXRhLmJvdHRvbSwgZGF0YS5uZWFyLCBkYXRhLmZhciApO1xuXG5cdFx0XHRcdGlmICggZGF0YS56b29tICE9PSB1bmRlZmluZWQgKSBvYmplY3Quem9vbSA9IGRhdGEuem9vbTtcblx0XHRcdFx0aWYgKCBkYXRhLnZpZXcgIT09IHVuZGVmaW5lZCApIG9iamVjdC52aWV3ID0gT2JqZWN0LmFzc2lnbigge30sIGRhdGEudmlldyApO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdBbWJpZW50TGlnaHQnOlxuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBBbWJpZW50TGlnaHQoIGRhdGEuY29sb3IsIGRhdGEuaW50ZW5zaXR5ICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0RpcmVjdGlvbmFsTGlnaHQnOlxuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBEaXJlY3Rpb25hbExpZ2h0KCBkYXRhLmNvbG9yLCBkYXRhLmludGVuc2l0eSApO1xuXHRcdFx0XHRvYmplY3QudGFyZ2V0ID0gZGF0YS50YXJnZXQgfHzCoCcnO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdQb2ludExpZ2h0JzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgUG9pbnRMaWdodCggZGF0YS5jb2xvciwgZGF0YS5pbnRlbnNpdHksIGRhdGEuZGlzdGFuY2UsIGRhdGEuZGVjYXkgKTtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnUmVjdEFyZWFMaWdodCc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IFJlY3RBcmVhTGlnaHQoIGRhdGEuY29sb3IsIGRhdGEuaW50ZW5zaXR5LCBkYXRhLndpZHRoLCBkYXRhLmhlaWdodCApO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdTcG90TGlnaHQnOlxuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBTcG90TGlnaHQoIGRhdGEuY29sb3IsIGRhdGEuaW50ZW5zaXR5LCBkYXRhLmRpc3RhbmNlLCBkYXRhLmFuZ2xlLCBkYXRhLnBlbnVtYnJhLCBkYXRhLmRlY2F5ICk7XG5cdFx0XHRcdG9iamVjdC50YXJnZXQgPSBkYXRhLnRhcmdldCB8fMKgJyc7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0hlbWlzcGhlcmVMaWdodCc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IEhlbWlzcGhlcmVMaWdodCggZGF0YS5jb2xvciwgZGF0YS5ncm91bmRDb2xvciwgZGF0YS5pbnRlbnNpdHkgKTtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnTGlnaHRQcm9iZSc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IExpZ2h0UHJvYmUoKS5mcm9tSlNPTiggZGF0YSApO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdTa2lubmVkTWVzaCc6XG5cblx0XHRcdFx0Z2VvbWV0cnkgPSBnZXRHZW9tZXRyeSggZGF0YS5nZW9tZXRyeSApO1xuXHRcdFx0IFx0bWF0ZXJpYWwgPSBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApO1xuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBTa2lubmVkTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cblx0XHRcdFx0aWYgKCBkYXRhLmJpbmRNb2RlICE9PSB1bmRlZmluZWQgKSBvYmplY3QuYmluZE1vZGUgPSBkYXRhLmJpbmRNb2RlO1xuXHRcdFx0XHRpZiAoIGRhdGEuYmluZE1hdHJpeCAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmJpbmRNYXRyaXguZnJvbUFycmF5KCBkYXRhLmJpbmRNYXRyaXggKTtcblx0XHRcdFx0aWYgKCBkYXRhLnNrZWxldG9uICE9PSB1bmRlZmluZWQgKSBvYmplY3Quc2tlbGV0b24gPSBkYXRhLnNrZWxldG9uO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdNZXNoJzpcblxuXHRcdFx0XHRnZW9tZXRyeSA9IGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICk7XG5cdFx0XHRcdG1hdGVyaWFsID0gZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKTtcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0luc3RhbmNlZE1lc2gnOlxuXG5cdFx0XHRcdGdlb21ldHJ5ID0gZ2V0R2VvbWV0cnkoIGRhdGEuZ2VvbWV0cnkgKTtcblx0XHRcdFx0bWF0ZXJpYWwgPSBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApO1xuXHRcdFx0XHRjb25zdCBjb3VudCA9IGRhdGEuY291bnQ7XG5cdFx0XHRcdGNvbnN0IGluc3RhbmNlTWF0cml4ID0gZGF0YS5pbnN0YW5jZU1hdHJpeDtcblx0XHRcdFx0Y29uc3QgaW5zdGFuY2VDb2xvciA9IGRhdGEuaW5zdGFuY2VDb2xvcjtcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgSW5zdGFuY2VkTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsLCBjb3VudCApO1xuXHRcdFx0XHRvYmplY3QuaW5zdGFuY2VNYXRyaXggPSBuZXcgSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlKCBuZXcgRmxvYXQzMkFycmF5KCBpbnN0YW5jZU1hdHJpeC5hcnJheSApLCAxNiApO1xuXHRcdFx0XHRpZiAoIGluc3RhbmNlQ29sb3IgIT09IHVuZGVmaW5lZCApIG9iamVjdC5pbnN0YW5jZUNvbG9yID0gbmV3IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSggbmV3IEZsb2F0MzJBcnJheSggaW5zdGFuY2VDb2xvci5hcnJheSApLCBpbnN0YW5jZUNvbG9yLml0ZW1TaXplICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0JhdGNoZWRNZXNoJzpcblxuXHRcdFx0XHRnZW9tZXRyeSA9IGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICk7XG5cdFx0XHRcdG1hdGVyaWFsID0gZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKTtcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgQmF0Y2hlZE1lc2goIGRhdGEubWF4SW5zdGFuY2VDb3VudCwgZGF0YS5tYXhWZXJ0ZXhDb3VudCwgZGF0YS5tYXhJbmRleENvdW50LCBtYXRlcmlhbCApO1xuXHRcdFx0XHRvYmplY3QuZ2VvbWV0cnkgPSBnZW9tZXRyeTtcblx0XHRcdFx0b2JqZWN0LnBlck9iamVjdEZydXN0dW1DdWxsZWQgPSBkYXRhLnBlck9iamVjdEZydXN0dW1DdWxsZWQ7XG5cdFx0XHRcdG9iamVjdC5zb3J0T2JqZWN0cyA9IGRhdGEuc29ydE9iamVjdHM7XG5cblx0XHRcdFx0b2JqZWN0Ll9kcmF3UmFuZ2VzID0gZGF0YS5kcmF3UmFuZ2VzO1xuXHRcdFx0XHRvYmplY3QuX3Jlc2VydmVkUmFuZ2VzID0gZGF0YS5yZXNlcnZlZFJhbmdlcztcblxuXHRcdFx0XHRvYmplY3QuX3Zpc2liaWxpdHkgPSBkYXRhLnZpc2liaWxpdHk7XG5cdFx0XHRcdG9iamVjdC5fYWN0aXZlID0gZGF0YS5hY3RpdmU7XG5cdFx0XHRcdG9iamVjdC5fYm91bmRzID0gZGF0YS5ib3VuZHMubWFwKCBib3VuZCA9PiB7XG5cblx0XHRcdFx0XHRjb25zdCBib3ggPSBuZXcgQm94MygpO1xuXHRcdFx0XHRcdGJveC5taW4uZnJvbUFycmF5KCBib3VuZC5ib3hNaW4gKTtcblx0XHRcdFx0XHRib3gubWF4LmZyb21BcnJheSggYm91bmQuYm94TWF4ICk7XG5cblx0XHRcdFx0XHRjb25zdCBzcGhlcmUgPSBuZXcgU3BoZXJlKCk7XG5cdFx0XHRcdFx0c3BoZXJlLnJhZGl1cyA9IGJvdW5kLnNwaGVyZVJhZGl1cztcblx0XHRcdFx0XHRzcGhlcmUuY2VudGVyLmZyb21BcnJheSggYm91bmQuc3BoZXJlQ2VudGVyICk7XG5cblx0XHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdFx0Ym94SW5pdGlhbGl6ZWQ6IGJvdW5kLmJveEluaXRpYWxpemVkLFxuXHRcdFx0XHRcdFx0Ym94OiBib3gsXG5cblx0XHRcdFx0XHRcdHNwaGVyZUluaXRpYWxpemVkOiBib3VuZC5zcGhlcmVJbml0aWFsaXplZCxcblx0XHRcdFx0XHRcdHNwaGVyZTogc3BoZXJlXG5cdFx0XHRcdFx0fTtcblxuXHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0b2JqZWN0Ll9tYXhJbnN0YW5jZUNvdW50ID0gZGF0YS5tYXhJbnN0YW5jZUNvdW50O1xuXHRcdFx0XHRvYmplY3QuX21heFZlcnRleENvdW50ID0gZGF0YS5tYXhWZXJ0ZXhDb3VudDtcblx0XHRcdFx0b2JqZWN0Ll9tYXhJbmRleENvdW50ID0gZGF0YS5tYXhJbmRleENvdW50O1xuXG5cdFx0XHRcdG9iamVjdC5fZ2VvbWV0cnlJbml0aWFsaXplZCA9IGRhdGEuZ2VvbWV0cnlJbml0aWFsaXplZDtcblx0XHRcdFx0b2JqZWN0Ll9nZW9tZXRyeUNvdW50ID0gZGF0YS5nZW9tZXRyeUNvdW50O1xuXG5cdFx0XHRcdG9iamVjdC5fbWF0cmljZXNUZXh0dXJlID0gZ2V0VGV4dHVyZSggZGF0YS5tYXRyaWNlc1RleHR1cmUudXVpZCApO1xuXHRcdFx0XHRpZiAoIGRhdGEuY29sb3JzVGV4dHVyZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0Ll9jb2xvcnNUZXh0dXJlID0gZ2V0VGV4dHVyZSggZGF0YS5jb2xvcnNUZXh0dXJlLnV1aWQgKTtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnTE9EJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgTE9EKCk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0xpbmUnOlxuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBMaW5lKCBnZXRHZW9tZXRyeSggZGF0YS5nZW9tZXRyeSApLCBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0xpbmVMb29wJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgTGluZUxvb3AoIGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICksIGdldE1hdGVyaWFsKCBkYXRhLm1hdGVyaWFsICkgKTtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnTGluZVNlZ21lbnRzJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgTGluZVNlZ21lbnRzKCBnZXRHZW9tZXRyeSggZGF0YS5nZW9tZXRyeSApLCBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1BvaW50Q2xvdWQnOlxuXHRcdFx0Y2FzZSAnUG9pbnRzJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgUG9pbnRzKCBnZXRHZW9tZXRyeSggZGF0YS5nZW9tZXRyeSApLCBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1Nwcml0ZSc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IFNwcml0ZSggZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKSApO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdHcm91cCc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IEdyb3VwKCk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0JvbmUnOlxuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBCb25lKCk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IE9iamVjdDNEKCk7XG5cblx0XHR9XG5cblx0XHRvYmplY3QudXVpZCA9IGRhdGEudXVpZDtcblxuXHRcdGlmICggZGF0YS5uYW1lICE9PSB1bmRlZmluZWQgKSBvYmplY3QubmFtZSA9IGRhdGEubmFtZTtcblxuXHRcdGlmICggZGF0YS5tYXRyaXggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0b2JqZWN0Lm1hdHJpeC5mcm9tQXJyYXkoIGRhdGEubWF0cml4ICk7XG5cblx0XHRcdGlmICggZGF0YS5tYXRyaXhBdXRvVXBkYXRlICE9PSB1bmRlZmluZWQgKSBvYmplY3QubWF0cml4QXV0b1VwZGF0ZSA9IGRhdGEubWF0cml4QXV0b1VwZGF0ZTtcblx0XHRcdGlmICggb2JqZWN0Lm1hdHJpeEF1dG9VcGRhdGUgKSBvYmplY3QubWF0cml4LmRlY29tcG9zZSggb2JqZWN0LnBvc2l0aW9uLCBvYmplY3QucXVhdGVybmlvbiwgb2JqZWN0LnNjYWxlICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIGRhdGEucG9zaXRpb24gIT09IHVuZGVmaW5lZCApIG9iamVjdC5wb3NpdGlvbi5mcm9tQXJyYXkoIGRhdGEucG9zaXRpb24gKTtcblx0XHRcdGlmICggZGF0YS5yb3RhdGlvbiAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnJvdGF0aW9uLmZyb21BcnJheSggZGF0YS5yb3RhdGlvbiApO1xuXHRcdFx0aWYgKCBkYXRhLnF1YXRlcm5pb24gIT09IHVuZGVmaW5lZCApIG9iamVjdC5xdWF0ZXJuaW9uLmZyb21BcnJheSggZGF0YS5xdWF0ZXJuaW9uICk7XG5cdFx0XHRpZiAoIGRhdGEuc2NhbGUgIT09IHVuZGVmaW5lZCApIG9iamVjdC5zY2FsZS5mcm9tQXJyYXkoIGRhdGEuc2NhbGUgKTtcblxuXHRcdH1cblxuXHRcdGlmICggZGF0YS51cCAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnVwLmZyb21BcnJheSggZGF0YS51cCApO1xuXG5cdFx0aWYgKCBkYXRhLmNhc3RTaGFkb3cgIT09IHVuZGVmaW5lZCApIG9iamVjdC5jYXN0U2hhZG93ID0gZGF0YS5jYXN0U2hhZG93O1xuXHRcdGlmICggZGF0YS5yZWNlaXZlU2hhZG93ICE9PSB1bmRlZmluZWQgKSBvYmplY3QucmVjZWl2ZVNoYWRvdyA9IGRhdGEucmVjZWl2ZVNoYWRvdztcblxuXHRcdGlmICggZGF0YS5zaGFkb3cgKSB7XG5cblx0XHRcdGlmICggZGF0YS5zaGFkb3cuaW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBvYmplY3Quc2hhZG93LmludGVuc2l0eSA9IGRhdGEuc2hhZG93LmludGVuc2l0eTtcblx0XHRcdGlmICggZGF0YS5zaGFkb3cuYmlhcyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5iaWFzID0gZGF0YS5zaGFkb3cuYmlhcztcblx0XHRcdGlmICggZGF0YS5zaGFkb3cubm9ybWFsQmlhcyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5ub3JtYWxCaWFzID0gZGF0YS5zaGFkb3cubm9ybWFsQmlhcztcblx0XHRcdGlmICggZGF0YS5zaGFkb3cucmFkaXVzICE9PSB1bmRlZmluZWQgKSBvYmplY3Quc2hhZG93LnJhZGl1cyA9IGRhdGEuc2hhZG93LnJhZGl1cztcblx0XHRcdGlmICggZGF0YS5zaGFkb3cubWFwU2l6ZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5tYXBTaXplLmZyb21BcnJheSggZGF0YS5zaGFkb3cubWFwU2l6ZSApO1xuXHRcdFx0aWYgKCBkYXRhLnNoYWRvdy5jYW1lcmEgIT09IHVuZGVmaW5lZCApIG9iamVjdC5zaGFkb3cuY2FtZXJhID0gdGhpcy5wYXJzZU9iamVjdCggZGF0YS5zaGFkb3cuY2FtZXJhICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIGRhdGEudmlzaWJsZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnZpc2libGUgPSBkYXRhLnZpc2libGU7XG5cdFx0aWYgKCBkYXRhLmZydXN0dW1DdWxsZWQgIT09IHVuZGVmaW5lZCApIG9iamVjdC5mcnVzdHVtQ3VsbGVkID0gZGF0YS5mcnVzdHVtQ3VsbGVkO1xuXHRcdGlmICggZGF0YS5yZW5kZXJPcmRlciAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnJlbmRlck9yZGVyID0gZGF0YS5yZW5kZXJPcmRlcjtcblx0XHRpZiAoIGRhdGEudXNlckRhdGEgIT09IHVuZGVmaW5lZCApIG9iamVjdC51c2VyRGF0YSA9IGRhdGEudXNlckRhdGE7XG5cdFx0aWYgKCBkYXRhLmxheWVycyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmxheWVycy5tYXNrID0gZGF0YS5sYXllcnM7XG5cblx0XHRpZiAoIGRhdGEuY2hpbGRyZW4gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3QgY2hpbGRyZW4gPSBkYXRhLmNoaWxkcmVuO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0b2JqZWN0LmFkZCggdGhpcy5wYXJzZU9iamVjdCggY2hpbGRyZW5bIGkgXSwgZ2VvbWV0cmllcywgbWF0ZXJpYWxzLCB0ZXh0dXJlcywgYW5pbWF0aW9ucyApICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggZGF0YS5hbmltYXRpb25zICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IG9iamVjdEFuaW1hdGlvbnMgPSBkYXRhLmFuaW1hdGlvbnM7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG9iamVjdEFuaW1hdGlvbnMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHV1aWQgPSBvYmplY3RBbmltYXRpb25zWyBpIF07XG5cblx0XHRcdFx0b2JqZWN0LmFuaW1hdGlvbnMucHVzaCggYW5pbWF0aW9uc1sgdXVpZCBdICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggZGF0YS50eXBlID09PSAnTE9EJyApIHtcblxuXHRcdFx0aWYgKCBkYXRhLmF1dG9VcGRhdGUgIT09IHVuZGVmaW5lZCApIG9iamVjdC5hdXRvVXBkYXRlID0gZGF0YS5hdXRvVXBkYXRlO1xuXG5cdFx0XHRjb25zdCBsZXZlbHMgPSBkYXRhLmxldmVscztcblxuXHRcdFx0Zm9yICggbGV0IGwgPSAwOyBsIDwgbGV2ZWxzLmxlbmd0aDsgbCArKyApIHtcblxuXHRcdFx0XHRjb25zdCBsZXZlbCA9IGxldmVsc1sgbCBdO1xuXHRcdFx0XHRjb25zdCBjaGlsZCA9IG9iamVjdC5nZXRPYmplY3RCeVByb3BlcnR5KCAndXVpZCcsIGxldmVsLm9iamVjdCApO1xuXG5cdFx0XHRcdGlmICggY2hpbGQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdG9iamVjdC5hZGRMZXZlbCggY2hpbGQsIGxldmVsLmRpc3RhbmNlLCBsZXZlbC5oeXN0ZXJlc2lzICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gb2JqZWN0O1xuXG5cdH1cblxuXHRiaW5kU2tlbGV0b25zKCBvYmplY3QsIHNrZWxldG9ucyApIHtcblxuXHRcdGlmICggT2JqZWN0LmtleXMoIHNrZWxldG9ucyApLmxlbmd0aCA9PT0gMCApIHJldHVybjtcblxuXHRcdG9iamVjdC50cmF2ZXJzZSggZnVuY3Rpb24gKCBjaGlsZCApIHtcblxuXHRcdFx0aWYgKCBjaGlsZC5pc1NraW5uZWRNZXNoID09PSB0cnVlICYmIGNoaWxkLnNrZWxldG9uICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2tlbGV0b24gPSBza2VsZXRvbnNbIGNoaWxkLnNrZWxldG9uIF07XG5cblx0XHRcdFx0aWYgKCBza2VsZXRvbiA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBObyBza2VsZXRvbiBmb3VuZCB3aXRoIFVVSUQ6JywgY2hpbGQuc2tlbGV0b24gKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Y2hpbGQuYmluZCggc2tlbGV0b24sIGNoaWxkLmJpbmRNYXRyaXggKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH0gKTtcblxuXHR9XG5cblx0YmluZExpZ2h0VGFyZ2V0cyggb2JqZWN0ICkge1xuXG5cdFx0b2JqZWN0LnRyYXZlcnNlKCBmdW5jdGlvbiAoIGNoaWxkICkge1xuXG5cdFx0XHRpZiAoIGNoaWxkLmlzRGlyZWN0aW9uYWxMaWdodCB8fMKgY2hpbGQuaXNTcG90TGlnaHQgKSB7XG5cblx0XHRcdFx0Y29uc3QgdXVpZCA9IGNoaWxkLnRhcmdldDtcblxuXHRcdFx0XHRjb25zdCB0YXJnZXQgPSBvYmplY3QuZ2V0T2JqZWN0QnlQcm9wZXJ0eSggJ3V1aWQnLCB1dWlkICk7XG5cblx0XHRcdFx0aWYgKCB0YXJnZXQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGNoaWxkLnRhcmdldCA9IHRhcmdldDtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Y2hpbGQudGFyZ2V0ID0gbmV3IE9iamVjdDNEKCk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9ICk7XG5cblx0fVxuXG59XG5cbmNvbnN0IFRFWFRVUkVfTUFQUElORyA9IHtcblx0VVZNYXBwaW5nOiBVVk1hcHBpbmcsXG5cdEN1YmVSZWZsZWN0aW9uTWFwcGluZzogQ3ViZVJlZmxlY3Rpb25NYXBwaW5nLFxuXHRDdWJlUmVmcmFjdGlvbk1hcHBpbmc6IEN1YmVSZWZyYWN0aW9uTWFwcGluZyxcblx0RXF1aXJlY3Rhbmd1bGFyUmVmbGVjdGlvbk1hcHBpbmc6IEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nLFxuXHRFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZzogRXF1aXJlY3Rhbmd1bGFyUmVmcmFjdGlvbk1hcHBpbmcsXG5cdEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nOiBDdWJlVVZSZWZsZWN0aW9uTWFwcGluZ1xufTtcblxuY29uc3QgVEVYVFVSRV9XUkFQUElORyA9IHtcblx0UmVwZWF0V3JhcHBpbmc6IFJlcGVhdFdyYXBwaW5nLFxuXHRDbGFtcFRvRWRnZVdyYXBwaW5nOiBDbGFtcFRvRWRnZVdyYXBwaW5nLFxuXHRNaXJyb3JlZFJlcGVhdFdyYXBwaW5nOiBNaXJyb3JlZFJlcGVhdFdyYXBwaW5nXG59O1xuXG5jb25zdCBURVhUVVJFX0ZJTFRFUiA9IHtcblx0TmVhcmVzdEZpbHRlcjogTmVhcmVzdEZpbHRlcixcblx0TmVhcmVzdE1pcG1hcE5lYXJlc3RGaWx0ZXI6IE5lYXJlc3RNaXBtYXBOZWFyZXN0RmlsdGVyLFxuXHROZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyOiBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyLFxuXHRMaW5lYXJGaWx0ZXI6IExpbmVhckZpbHRlcixcblx0TGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlcjogTGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlcixcblx0TGluZWFyTWlwbWFwTGluZWFyRmlsdGVyOiBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXJcbn07XG5cbmNsYXNzIEltYWdlQml0bWFwTG9hZGVyIGV4dGVuZHMgTG9hZGVyIHtcblxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcblxuXHRcdHN1cGVyKCBtYW5hZ2VyICk7XG5cblx0XHR0aGlzLmlzSW1hZ2VCaXRtYXBMb2FkZXIgPSB0cnVlO1xuXG5cdFx0aWYgKCB0eXBlb2YgY3JlYXRlSW1hZ2VCaXRtYXAgPT09ICd1bmRlZmluZWQnICkge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5JbWFnZUJpdG1hcExvYWRlcjogY3JlYXRlSW1hZ2VCaXRtYXAoKSBub3Qgc3VwcG9ydGVkLicgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdHlwZW9mIGZldGNoID09PSAndW5kZWZpbmVkJyApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuSW1hZ2VCaXRtYXBMb2FkZXI6IGZldGNoKCkgbm90IHN1cHBvcnRlZC4nICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLm9wdGlvbnMgPSB7IHByZW11bHRpcGx5QWxwaGE6ICdub25lJyB9O1xuXG5cdH1cblxuXHRzZXRPcHRpb25zKCBvcHRpb25zICkge1xuXG5cdFx0dGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcblxuXHRcdGlmICggdXJsID09PSB1bmRlZmluZWQgKSB1cmwgPSAnJztcblxuXHRcdGlmICggdGhpcy5wYXRoICE9PSB1bmRlZmluZWQgKSB1cmwgPSB0aGlzLnBhdGggKyB1cmw7XG5cblx0XHR1cmwgPSB0aGlzLm1hbmFnZXIucmVzb2x2ZVVSTCggdXJsICk7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRjb25zdCBjYWNoZWQgPSBDYWNoZS5nZXQoIHVybCApO1xuXG5cdFx0aWYgKCBjYWNoZWQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtU3RhcnQoIHVybCApO1xuXG5cdFx0XHQvLyBJZiBjYWNoZWQgaXMgYSBwcm9taXNlLCB3YWl0IGZvciBpdCB0byByZXNvbHZlXG5cdFx0XHRpZiAoIGNhY2hlZC50aGVuICkge1xuXG5cdFx0XHRcdGNhY2hlZC50aGVuKCBpbWFnZUJpdG1hcCA9PiB7XG5cblx0XHRcdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggaW1hZ2VCaXRtYXAgKTtcblxuXHRcdFx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbUVuZCggdXJsICk7XG5cblx0XHRcdFx0fSApLmNhdGNoKCBlID0+IHtcblxuXHRcdFx0XHRcdGlmICggb25FcnJvciApIG9uRXJyb3IoIGUgKTtcblxuXHRcdFx0XHR9ICk7XG5cdFx0XHRcdHJldHVybjtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBJZiBjYWNoZWQgaXMgbm90IGEgcHJvbWlzZSAoaS5lLiwgaXQncyBhbHJlYWR5IGFuIGltYWdlQml0bWFwKVxuXHRcdFx0c2V0VGltZW91dCggZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCBjYWNoZWQgKTtcblxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xuXG5cdFx0XHR9LCAwICk7XG5cblx0XHRcdHJldHVybiBjYWNoZWQ7XG5cblx0XHR9XG5cblx0XHRjb25zdCBmZXRjaE9wdGlvbnMgPSB7fTtcblx0XHRmZXRjaE9wdGlvbnMuY3JlZGVudGlhbHMgPSAoIHRoaXMuY3Jvc3NPcmlnaW4gPT09ICdhbm9ueW1vdXMnICkgPyAnc2FtZS1vcmlnaW4nIDogJ2luY2x1ZGUnO1xuXHRcdGZldGNoT3B0aW9ucy5oZWFkZXJzID0gdGhpcy5yZXF1ZXN0SGVhZGVyO1xuXG5cdFx0Y29uc3QgcHJvbWlzZSA9IGZldGNoKCB1cmwsIGZldGNoT3B0aW9ucyApLnRoZW4oIGZ1bmN0aW9uICggcmVzICkge1xuXG5cdFx0XHRyZXR1cm4gcmVzLmJsb2IoKTtcblxuXHRcdH0gKS50aGVuKCBmdW5jdGlvbiAoIGJsb2IgKSB7XG5cblx0XHRcdHJldHVybiBjcmVhdGVJbWFnZUJpdG1hcCggYmxvYiwgT2JqZWN0LmFzc2lnbiggc2NvcGUub3B0aW9ucywgeyBjb2xvclNwYWNlQ29udmVyc2lvbjogJ25vbmUnIH0gKSApO1xuXG5cdFx0fSApLnRoZW4oIGZ1bmN0aW9uICggaW1hZ2VCaXRtYXAgKSB7XG5cblx0XHRcdENhY2hlLmFkZCggdXJsLCBpbWFnZUJpdG1hcCApO1xuXG5cdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggaW1hZ2VCaXRtYXAgKTtcblxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcblxuXHRcdFx0cmV0dXJuIGltYWdlQml0bWFwO1xuXG5cdFx0fSApLmNhdGNoKCBmdW5jdGlvbiAoIGUgKSB7XG5cblx0XHRcdGlmICggb25FcnJvciApIG9uRXJyb3IoIGUgKTtcblxuXHRcdFx0Q2FjaGUucmVtb3ZlKCB1cmwgKTtcblxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcblxuXHRcdH0gKTtcblxuXHRcdENhY2hlLmFkZCggdXJsLCBwcm9taXNlICk7XG5cdFx0c2NvcGUubWFuYWdlci5pdGVtU3RhcnQoIHVybCApO1xuXG5cdH1cblxufVxuXG5sZXQgX2NvbnRleHQ7XG5cbmNsYXNzIEF1ZGlvQ29udGV4dCB7XG5cblx0c3RhdGljIGdldENvbnRleHQoKSB7XG5cblx0XHRpZiAoIF9jb250ZXh0ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdF9jb250ZXh0ID0gbmV3ICggd2luZG93LkF1ZGlvQ29udGV4dCB8fCB3aW5kb3cud2Via2l0QXVkaW9Db250ZXh0ICkoKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBfY29udGV4dDtcblxuXHR9XG5cblx0c3RhdGljIHNldENvbnRleHQoIHZhbHVlICkge1xuXG5cdFx0X2NvbnRleHQgPSB2YWx1ZTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQXVkaW9Mb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xuXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcblxuXHR9XG5cblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XG5cdFx0bG9hZGVyLnNldFJlc3BvbnNlVHlwZSggJ2FycmF5YnVmZmVyJyApO1xuXHRcdGxvYWRlci5zZXRQYXRoKCB0aGlzLnBhdGggKTtcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggdGhpcy5yZXF1ZXN0SGVhZGVyICk7XG5cdFx0bG9hZGVyLnNldFdpdGhDcmVkZW50aWFscyggdGhpcy53aXRoQ3JlZGVudGlhbHMgKTtcblx0XHRsb2FkZXIubG9hZCggdXJsLCBmdW5jdGlvbiAoIGJ1ZmZlciApIHtcblxuXHRcdFx0dHJ5IHtcblxuXHRcdFx0XHQvLyBDcmVhdGUgYSBjb3B5IG9mIHRoZSBidWZmZXIuIFRoZSBgZGVjb2RlQXVkaW9EYXRhYCBtZXRob2Rcblx0XHRcdFx0Ly8gZGV0YWNoZXMgdGhlIGJ1ZmZlciB3aGVuIGNvbXBsZXRlLCBwcmV2ZW50aW5nIHJldXNlLlxuXHRcdFx0XHRjb25zdCBidWZmZXJDb3B5ID0gYnVmZmVyLnNsaWNlKCAwICk7XG5cblx0XHRcdFx0Y29uc3QgY29udGV4dCA9IEF1ZGlvQ29udGV4dC5nZXRDb250ZXh0KCk7XG5cdFx0XHRcdGNvbnRleHQuZGVjb2RlQXVkaW9EYXRhKCBidWZmZXJDb3B5LCBmdW5jdGlvbiAoIGF1ZGlvQnVmZmVyICkge1xuXG5cdFx0XHRcdFx0b25Mb2FkKCBhdWRpb0J1ZmZlciApO1xuXG5cdFx0XHRcdH0gKS5jYXRjaCggaGFuZGxlRXJyb3IgKTtcblxuXHRcdFx0fSBjYXRjaCAoIGUgKSB7XG5cblx0XHRcdFx0aGFuZGxlRXJyb3IoIGUgKTtcblxuXHRcdFx0fVxuXG5cdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlRXJyb3IoIGUgKSB7XG5cblx0XHRcdGlmICggb25FcnJvciApIHtcblxuXHRcdFx0XHRvbkVycm9yKCBlICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Y29uc29sZS5lcnJvciggZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbUVycm9yKCB1cmwgKTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuY29uc3QgX2V5ZVJpZ2h0ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX2V5ZUxlZnQgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfcHJvamVjdGlvbk1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcblxuY2xhc3MgU3RlcmVvQ2FtZXJhIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHRoaXMudHlwZSA9ICdTdGVyZW9DYW1lcmEnO1xuXG5cdFx0dGhpcy5hc3BlY3QgPSAxO1xuXG5cdFx0dGhpcy5leWVTZXAgPSAwLjA2NDtcblxuXHRcdHRoaXMuY2FtZXJhTCA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSgpO1xuXHRcdHRoaXMuY2FtZXJhTC5sYXllcnMuZW5hYmxlKCAxICk7XG5cdFx0dGhpcy5jYW1lcmFMLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblxuXHRcdHRoaXMuY2FtZXJhUiA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSgpO1xuXHRcdHRoaXMuY2FtZXJhUi5sYXllcnMuZW5hYmxlKCAyICk7XG5cdFx0dGhpcy5jYW1lcmFSLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblxuXHRcdHRoaXMuX2NhY2hlID0ge1xuXHRcdFx0Zm9jdXM6IG51bGwsXG5cdFx0XHRmb3Y6IG51bGwsXG5cdFx0XHRhc3BlY3Q6IG51bGwsXG5cdFx0XHRuZWFyOiBudWxsLFxuXHRcdFx0ZmFyOiBudWxsLFxuXHRcdFx0em9vbTogbnVsbCxcblx0XHRcdGV5ZVNlcDogbnVsbFxuXHRcdH07XG5cblx0fVxuXG5cdHVwZGF0ZSggY2FtZXJhICkge1xuXG5cdFx0Y29uc3QgY2FjaGUgPSB0aGlzLl9jYWNoZTtcblxuXHRcdGNvbnN0IG5lZWRzVXBkYXRlID0gY2FjaGUuZm9jdXMgIT09IGNhbWVyYS5mb2N1cyB8fCBjYWNoZS5mb3YgIT09IGNhbWVyYS5mb3YgfHxcblx0XHRcdGNhY2hlLmFzcGVjdCAhPT0gY2FtZXJhLmFzcGVjdCAqIHRoaXMuYXNwZWN0IHx8IGNhY2hlLm5lYXIgIT09IGNhbWVyYS5uZWFyIHx8XG5cdFx0XHRjYWNoZS5mYXIgIT09IGNhbWVyYS5mYXIgfHwgY2FjaGUuem9vbSAhPT0gY2FtZXJhLnpvb20gfHwgY2FjaGUuZXllU2VwICE9PSB0aGlzLmV5ZVNlcDtcblxuXHRcdGlmICggbmVlZHNVcGRhdGUgKSB7XG5cblx0XHRcdGNhY2hlLmZvY3VzID0gY2FtZXJhLmZvY3VzO1xuXHRcdFx0Y2FjaGUuZm92ID0gY2FtZXJhLmZvdjtcblx0XHRcdGNhY2hlLmFzcGVjdCA9IGNhbWVyYS5hc3BlY3QgKiB0aGlzLmFzcGVjdDtcblx0XHRcdGNhY2hlLm5lYXIgPSBjYW1lcmEubmVhcjtcblx0XHRcdGNhY2hlLmZhciA9IGNhbWVyYS5mYXI7XG5cdFx0XHRjYWNoZS56b29tID0gY2FtZXJhLnpvb207XG5cdFx0XHRjYWNoZS5leWVTZXAgPSB0aGlzLmV5ZVNlcDtcblxuXHRcdFx0Ly8gT2ZmLWF4aXMgc3RlcmVvc2NvcGljIGVmZmVjdCBiYXNlZCBvblxuXHRcdFx0Ly8gaHR0cDovL3BhdWxib3Vya2UubmV0L3N0ZXJlb2dyYXBoaWNzL3N0ZXJlb3JlbmRlci9cblxuXHRcdFx0X3Byb2plY3Rpb25NYXRyaXguY29weSggY2FtZXJhLnByb2plY3Rpb25NYXRyaXggKTtcblx0XHRcdGNvbnN0IGV5ZVNlcEhhbGYgPSBjYWNoZS5leWVTZXAgLyAyO1xuXHRcdFx0Y29uc3QgZXllU2VwT25Qcm9qZWN0aW9uID0gZXllU2VwSGFsZiAqIGNhY2hlLm5lYXIgLyBjYWNoZS5mb2N1cztcblx0XHRcdGNvbnN0IHltYXggPSAoIGNhY2hlLm5lYXIgKiBNYXRoLnRhbiggREVHMlJBRCAqIGNhY2hlLmZvdiAqIDAuNSApICkgLyBjYWNoZS56b29tO1xuXHRcdFx0bGV0IHhtaW4sIHhtYXg7XG5cblx0XHRcdC8vIHRyYW5zbGF0ZSB4T2Zmc2V0XG5cblx0XHRcdF9leWVMZWZ0LmVsZW1lbnRzWyAxMiBdID0gLSBleWVTZXBIYWxmO1xuXHRcdFx0X2V5ZVJpZ2h0LmVsZW1lbnRzWyAxMiBdID0gZXllU2VwSGFsZjtcblxuXHRcdFx0Ly8gZm9yIGxlZnQgZXllXG5cblx0XHRcdHhtaW4gPSAtIHltYXggKiBjYWNoZS5hc3BlY3QgKyBleWVTZXBPblByb2plY3Rpb247XG5cdFx0XHR4bWF4ID0geW1heCAqIGNhY2hlLmFzcGVjdCArIGV5ZVNlcE9uUHJvamVjdGlvbjtcblxuXHRcdFx0X3Byb2plY3Rpb25NYXRyaXguZWxlbWVudHNbIDAgXSA9IDIgKiBjYWNoZS5uZWFyIC8gKCB4bWF4IC0geG1pbiApO1xuXHRcdFx0X3Byb2plY3Rpb25NYXRyaXguZWxlbWVudHNbIDggXSA9ICggeG1heCArIHhtaW4gKSAvICggeG1heCAtIHhtaW4gKTtcblxuXHRcdFx0dGhpcy5jYW1lcmFMLnByb2plY3Rpb25NYXRyaXguY29weSggX3Byb2plY3Rpb25NYXRyaXggKTtcblxuXHRcdFx0Ly8gZm9yIHJpZ2h0IGV5ZVxuXG5cdFx0XHR4bWluID0gLSB5bWF4ICogY2FjaGUuYXNwZWN0IC0gZXllU2VwT25Qcm9qZWN0aW9uO1xuXHRcdFx0eG1heCA9IHltYXggKiBjYWNoZS5hc3BlY3QgLSBleWVTZXBPblByb2plY3Rpb247XG5cblx0XHRcdF9wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyAwIF0gPSAyICogY2FjaGUubmVhciAvICggeG1heCAtIHhtaW4gKTtcblx0XHRcdF9wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyA4IF0gPSAoIHhtYXggKyB4bWluICkgLyAoIHhtYXggLSB4bWluICk7XG5cblx0XHRcdHRoaXMuY2FtZXJhUi5wcm9qZWN0aW9uTWF0cml4LmNvcHkoIF9wcm9qZWN0aW9uTWF0cml4ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmNhbWVyYUwubWF0cml4V29ybGQuY29weSggY2FtZXJhLm1hdHJpeFdvcmxkICkubXVsdGlwbHkoIF9leWVMZWZ0ICk7XG5cdFx0dGhpcy5jYW1lcmFSLm1hdHJpeFdvcmxkLmNvcHkoIGNhbWVyYS5tYXRyaXhXb3JsZCApLm11bHRpcGx5KCBfZXllUmlnaHQgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQ2xvY2sge1xuXG5cdGNvbnN0cnVjdG9yKCBhdXRvU3RhcnQgPSB0cnVlICkge1xuXG5cdFx0dGhpcy5hdXRvU3RhcnQgPSBhdXRvU3RhcnQ7XG5cblx0XHR0aGlzLnN0YXJ0VGltZSA9IDA7XG5cdFx0dGhpcy5vbGRUaW1lID0gMDtcblx0XHR0aGlzLmVsYXBzZWRUaW1lID0gMDtcblxuXHRcdHRoaXMucnVubmluZyA9IGZhbHNlO1xuXG5cdH1cblxuXHRzdGFydCgpIHtcblxuXHRcdHRoaXMuc3RhcnRUaW1lID0gbm93KCk7XG5cblx0XHR0aGlzLm9sZFRpbWUgPSB0aGlzLnN0YXJ0VGltZTtcblx0XHR0aGlzLmVsYXBzZWRUaW1lID0gMDtcblx0XHR0aGlzLnJ1bm5pbmcgPSB0cnVlO1xuXG5cdH1cblxuXHRzdG9wKCkge1xuXG5cdFx0dGhpcy5nZXRFbGFwc2VkVGltZSgpO1xuXHRcdHRoaXMucnVubmluZyA9IGZhbHNlO1xuXHRcdHRoaXMuYXV0b1N0YXJ0ID0gZmFsc2U7XG5cblx0fVxuXG5cdGdldEVsYXBzZWRUaW1lKCkge1xuXG5cdFx0dGhpcy5nZXREZWx0YSgpO1xuXHRcdHJldHVybiB0aGlzLmVsYXBzZWRUaW1lO1xuXG5cdH1cblxuXHRnZXREZWx0YSgpIHtcblxuXHRcdGxldCBkaWZmID0gMDtcblxuXHRcdGlmICggdGhpcy5hdXRvU3RhcnQgJiYgISB0aGlzLnJ1bm5pbmcgKSB7XG5cblx0XHRcdHRoaXMuc3RhcnQoKTtcblx0XHRcdHJldHVybiAwO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLnJ1bm5pbmcgKSB7XG5cblx0XHRcdGNvbnN0IG5ld1RpbWUgPSBub3coKTtcblxuXHRcdFx0ZGlmZiA9ICggbmV3VGltZSAtIHRoaXMub2xkVGltZSApIC8gMTAwMDtcblx0XHRcdHRoaXMub2xkVGltZSA9IG5ld1RpbWU7XG5cblx0XHRcdHRoaXMuZWxhcHNlZFRpbWUgKz0gZGlmZjtcblxuXHRcdH1cblxuXHRcdHJldHVybiBkaWZmO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBub3coKSB7XG5cblx0cmV0dXJuICggdHlwZW9mIHBlcmZvcm1hbmNlID09PSAndW5kZWZpbmVkJyA/IERhdGUgOiBwZXJmb3JtYW5jZSApLm5vdygpOyAvLyBzZWUgIzEwNzMyXG5cbn1cblxuY29uc3QgX3Bvc2l0aW9uJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfcXVhdGVybmlvbiQxID0gLypAX19QVVJFX18qLyBuZXcgUXVhdGVybmlvbigpO1xuY29uc3QgX3NjYWxlJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfb3JpZW50YXRpb24kMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgQXVkaW9MaXN0ZW5lciBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnQXVkaW9MaXN0ZW5lcic7XG5cblx0XHR0aGlzLmNvbnRleHQgPSBBdWRpb0NvbnRleHQuZ2V0Q29udGV4dCgpO1xuXG5cdFx0dGhpcy5nYWluID0gdGhpcy5jb250ZXh0LmNyZWF0ZUdhaW4oKTtcblx0XHR0aGlzLmdhaW4uY29ubmVjdCggdGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uICk7XG5cblx0XHR0aGlzLmZpbHRlciA9IG51bGw7XG5cblx0XHR0aGlzLnRpbWVEZWx0YSA9IDA7XG5cblx0XHQvLyBwcml2YXRlXG5cblx0XHR0aGlzLl9jbG9jayA9IG5ldyBDbG9jaygpO1xuXG5cdH1cblxuXHRnZXRJbnB1dCgpIHtcblxuXHRcdHJldHVybiB0aGlzLmdhaW47XG5cblx0fVxuXG5cdHJlbW92ZUZpbHRlcigpIHtcblxuXHRcdGlmICggdGhpcy5maWx0ZXIgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuZ2Fpbi5kaXNjb25uZWN0KCB0aGlzLmZpbHRlciApO1xuXHRcdFx0dGhpcy5maWx0ZXIuZGlzY29ubmVjdCggdGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uICk7XG5cdFx0XHR0aGlzLmdhaW4uY29ubmVjdCggdGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uICk7XG5cdFx0XHR0aGlzLmZpbHRlciA9IG51bGw7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0RmlsdGVyKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZmlsdGVyO1xuXG5cdH1cblxuXHRzZXRGaWx0ZXIoIHZhbHVlICkge1xuXG5cdFx0aWYgKCB0aGlzLmZpbHRlciAhPT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5nYWluLmRpc2Nvbm5lY3QoIHRoaXMuZmlsdGVyICk7XG5cdFx0XHR0aGlzLmZpbHRlci5kaXNjb25uZWN0KCB0aGlzLmNvbnRleHQuZGVzdGluYXRpb24gKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuZ2Fpbi5kaXNjb25uZWN0KCB0aGlzLmNvbnRleHQuZGVzdGluYXRpb24gKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuZmlsdGVyID0gdmFsdWU7XG5cdFx0dGhpcy5nYWluLmNvbm5lY3QoIHRoaXMuZmlsdGVyICk7XG5cdFx0dGhpcy5maWx0ZXIuY29ubmVjdCggdGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0TWFzdGVyVm9sdW1lKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZ2Fpbi5nYWluLnZhbHVlO1xuXG5cdH1cblxuXHRzZXRNYXN0ZXJWb2x1bWUoIHZhbHVlICkge1xuXG5cdFx0dGhpcy5nYWluLmdhaW4uc2V0VGFyZ2V0QXRUaW1lKCB2YWx1ZSwgdGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lLCAwLjAxICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICkge1xuXG5cdFx0c3VwZXIudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XG5cblx0XHRjb25zdCBsaXN0ZW5lciA9IHRoaXMuY29udGV4dC5saXN0ZW5lcjtcblx0XHRjb25zdCB1cCA9IHRoaXMudXA7XG5cblx0XHR0aGlzLnRpbWVEZWx0YSA9IHRoaXMuX2Nsb2NrLmdldERlbHRhKCk7XG5cblx0XHR0aGlzLm1hdHJpeFdvcmxkLmRlY29tcG9zZSggX3Bvc2l0aW9uJDEsIF9xdWF0ZXJuaW9uJDEsIF9zY2FsZSQxICk7XG5cblx0XHRfb3JpZW50YXRpb24kMS5zZXQoIDAsIDAsIC0gMSApLmFwcGx5UXVhdGVybmlvbiggX3F1YXRlcm5pb24kMSApO1xuXG5cdFx0aWYgKCBsaXN0ZW5lci5wb3NpdGlvblggKSB7XG5cblx0XHRcdC8vIGNvZGUgcGF0aCBmb3IgQ2hyb21lIChzZWUgIzE0MzkzKVxuXG5cdFx0XHRjb25zdCBlbmRUaW1lID0gdGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lICsgdGhpcy50aW1lRGVsdGE7XG5cblx0XHRcdGxpc3RlbmVyLnBvc2l0aW9uWC5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX3Bvc2l0aW9uJDEueCwgZW5kVGltZSApO1xuXHRcdFx0bGlzdGVuZXIucG9zaXRpb25ZLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfcG9zaXRpb24kMS55LCBlbmRUaW1lICk7XG5cdFx0XHRsaXN0ZW5lci5wb3NpdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbiQxLnosIGVuZFRpbWUgKTtcblx0XHRcdGxpc3RlbmVyLmZvcndhcmRYLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfb3JpZW50YXRpb24kMS54LCBlbmRUaW1lICk7XG5cdFx0XHRsaXN0ZW5lci5mb3J3YXJkWS5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX29yaWVudGF0aW9uJDEueSwgZW5kVGltZSApO1xuXHRcdFx0bGlzdGVuZXIuZm9yd2FyZFoubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbiQxLnosIGVuZFRpbWUgKTtcblx0XHRcdGxpc3RlbmVyLnVwWC5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggdXAueCwgZW5kVGltZSApO1xuXHRcdFx0bGlzdGVuZXIudXBZLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCB1cC55LCBlbmRUaW1lICk7XG5cdFx0XHRsaXN0ZW5lci51cFoubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIHVwLnosIGVuZFRpbWUgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGxpc3RlbmVyLnNldFBvc2l0aW9uKCBfcG9zaXRpb24kMS54LCBfcG9zaXRpb24kMS55LCBfcG9zaXRpb24kMS56ICk7XG5cdFx0XHRsaXN0ZW5lci5zZXRPcmllbnRhdGlvbiggX29yaWVudGF0aW9uJDEueCwgX29yaWVudGF0aW9uJDEueSwgX29yaWVudGF0aW9uJDEueiwgdXAueCwgdXAueSwgdXAueiApO1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5jbGFzcyBBdWRpbyBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvciggbGlzdGVuZXIgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ0F1ZGlvJztcblxuXHRcdHRoaXMubGlzdGVuZXIgPSBsaXN0ZW5lcjtcblx0XHR0aGlzLmNvbnRleHQgPSBsaXN0ZW5lci5jb250ZXh0O1xuXG5cdFx0dGhpcy5nYWluID0gdGhpcy5jb250ZXh0LmNyZWF0ZUdhaW4oKTtcblx0XHR0aGlzLmdhaW4uY29ubmVjdCggbGlzdGVuZXIuZ2V0SW5wdXQoKSApO1xuXG5cdFx0dGhpcy5hdXRvcGxheSA9IGZhbHNlO1xuXG5cdFx0dGhpcy5idWZmZXIgPSBudWxsO1xuXHRcdHRoaXMuZGV0dW5lID0gMDtcblx0XHR0aGlzLmxvb3AgPSBmYWxzZTtcblx0XHR0aGlzLmxvb3BTdGFydCA9IDA7XG5cdFx0dGhpcy5sb29wRW5kID0gMDtcblx0XHR0aGlzLm9mZnNldCA9IDA7XG5cdFx0dGhpcy5kdXJhdGlvbiA9IHVuZGVmaW5lZDtcblx0XHR0aGlzLnBsYXliYWNrUmF0ZSA9IDE7XG5cdFx0dGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcblx0XHR0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9IHRydWU7XG5cdFx0dGhpcy5zb3VyY2UgPSBudWxsO1xuXHRcdHRoaXMuc291cmNlVHlwZSA9ICdlbXB0eSc7XG5cblx0XHR0aGlzLl9zdGFydGVkQXQgPSAwO1xuXHRcdHRoaXMuX3Byb2dyZXNzID0gMDtcblx0XHR0aGlzLl9jb25uZWN0ZWQgPSBmYWxzZTtcblxuXHRcdHRoaXMuZmlsdGVycyA9IFtdO1xuXG5cdH1cblxuXHRnZXRPdXRwdXQoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5nYWluO1xuXG5cdH1cblxuXHRzZXROb2RlU291cmNlKCBhdWRpb05vZGUgKSB7XG5cblx0XHR0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9IGZhbHNlO1xuXHRcdHRoaXMuc291cmNlVHlwZSA9ICdhdWRpb05vZGUnO1xuXHRcdHRoaXMuc291cmNlID0gYXVkaW9Ob2RlO1xuXHRcdHRoaXMuY29ubmVjdCgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldE1lZGlhRWxlbWVudFNvdXJjZSggbWVkaWFFbGVtZW50ICkge1xuXG5cdFx0dGhpcy5oYXNQbGF5YmFja0NvbnRyb2wgPSBmYWxzZTtcblx0XHR0aGlzLnNvdXJjZVR5cGUgPSAnbWVkaWFOb2RlJztcblx0XHR0aGlzLnNvdXJjZSA9IHRoaXMuY29udGV4dC5jcmVhdGVNZWRpYUVsZW1lbnRTb3VyY2UoIG1lZGlhRWxlbWVudCApO1xuXHRcdHRoaXMuY29ubmVjdCgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldE1lZGlhU3RyZWFtU291cmNlKCBtZWRpYVN0cmVhbSApIHtcblxuXHRcdHRoaXMuaGFzUGxheWJhY2tDb250cm9sID0gZmFsc2U7XG5cdFx0dGhpcy5zb3VyY2VUeXBlID0gJ21lZGlhU3RyZWFtTm9kZSc7XG5cdFx0dGhpcy5zb3VyY2UgPSB0aGlzLmNvbnRleHQuY3JlYXRlTWVkaWFTdHJlYW1Tb3VyY2UoIG1lZGlhU3RyZWFtICk7XG5cdFx0dGhpcy5jb25uZWN0KCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0QnVmZmVyKCBhdWRpb0J1ZmZlciApIHtcblxuXHRcdHRoaXMuYnVmZmVyID0gYXVkaW9CdWZmZXI7XG5cdFx0dGhpcy5zb3VyY2VUeXBlID0gJ2J1ZmZlcic7XG5cblx0XHRpZiAoIHRoaXMuYXV0b3BsYXkgKSB0aGlzLnBsYXkoKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRwbGF5KCBkZWxheSA9IDAgKSB7XG5cblx0XHRpZiAoIHRoaXMuaXNQbGF5aW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5BdWRpbzogQXVkaW8gaXMgYWxyZWFkeSBwbGF5aW5nLicgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5oYXNQbGF5YmFja0NvbnRyb2wgPT09IGZhbHNlICkge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5BdWRpbzogdGhpcyBBdWRpbyBoYXMgbm8gcGxheWJhY2sgY29udHJvbC4nICk7XG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHR0aGlzLl9zdGFydGVkQXQgPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgKyBkZWxheTtcblxuXHRcdGNvbnN0IHNvdXJjZSA9IHRoaXMuY29udGV4dC5jcmVhdGVCdWZmZXJTb3VyY2UoKTtcblx0XHRzb3VyY2UuYnVmZmVyID0gdGhpcy5idWZmZXI7XG5cdFx0c291cmNlLmxvb3AgPSB0aGlzLmxvb3A7XG5cdFx0c291cmNlLmxvb3BTdGFydCA9IHRoaXMubG9vcFN0YXJ0O1xuXHRcdHNvdXJjZS5sb29wRW5kID0gdGhpcy5sb29wRW5kO1xuXHRcdHNvdXJjZS5vbmVuZGVkID0gdGhpcy5vbkVuZGVkLmJpbmQoIHRoaXMgKTtcblx0XHRzb3VyY2Uuc3RhcnQoIHRoaXMuX3N0YXJ0ZWRBdCwgdGhpcy5fcHJvZ3Jlc3MgKyB0aGlzLm9mZnNldCwgdGhpcy5kdXJhdGlvbiApO1xuXG5cdFx0dGhpcy5pc1BsYXlpbmcgPSB0cnVlO1xuXG5cdFx0dGhpcy5zb3VyY2UgPSBzb3VyY2U7XG5cblx0XHR0aGlzLnNldERldHVuZSggdGhpcy5kZXR1bmUgKTtcblx0XHR0aGlzLnNldFBsYXliYWNrUmF0ZSggdGhpcy5wbGF5YmFja1JhdGUgKTtcblxuXHRcdHJldHVybiB0aGlzLmNvbm5lY3QoKTtcblxuXHR9XG5cblx0cGF1c2UoKSB7XG5cblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQXVkaW86IHRoaXMgQXVkaW8gaGFzIG5vIHBsYXliYWNrIGNvbnRyb2wuJyApO1xuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmlzUGxheWluZyA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0Ly8gdXBkYXRlIGN1cnJlbnQgcHJvZ3Jlc3NcblxuXHRcdFx0dGhpcy5fcHJvZ3Jlc3MgKz0gTWF0aC5tYXgoIHRoaXMuY29udGV4dC5jdXJyZW50VGltZSAtIHRoaXMuX3N0YXJ0ZWRBdCwgMCApICogdGhpcy5wbGF5YmFja1JhdGU7XG5cblx0XHRcdGlmICggdGhpcy5sb29wID09PSB0cnVlICkge1xuXG5cdFx0XHRcdC8vIGVuc3VyZSBfcHJvZ3Jlc3MgZG9lcyBub3QgZXhjZWVkIGR1cmF0aW9uIHdpdGggbG9vcGVkIGF1ZGlvc1xuXG5cdFx0XHRcdHRoaXMuX3Byb2dyZXNzID0gdGhpcy5fcHJvZ3Jlc3MgJSAoIHRoaXMuZHVyYXRpb24gfHwgdGhpcy5idWZmZXIuZHVyYXRpb24gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLnNvdXJjZS5zdG9wKCk7XG5cdFx0XHR0aGlzLnNvdXJjZS5vbmVuZGVkID0gbnVsbDtcblxuXHRcdFx0dGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdG9wKCkge1xuXG5cdFx0aWYgKCB0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdHRoaXMuX3Byb2dyZXNzID0gMDtcblxuXHRcdGlmICggdGhpcy5zb3VyY2UgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuc291cmNlLnN0b3AoKTtcblx0XHRcdHRoaXMuc291cmNlLm9uZW5kZWQgPSBudWxsO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb25uZWN0KCkge1xuXG5cdFx0aWYgKCB0aGlzLmZpbHRlcnMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0dGhpcy5zb3VyY2UuY29ubmVjdCggdGhpcy5maWx0ZXJzWyAwIF0gKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAxLCBsID0gdGhpcy5maWx0ZXJzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0dGhpcy5maWx0ZXJzWyBpIC0gMSBdLmNvbm5lY3QoIHRoaXMuZmlsdGVyc1sgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5maWx0ZXJzWyB0aGlzLmZpbHRlcnMubGVuZ3RoIC0gMSBdLmNvbm5lY3QoIHRoaXMuZ2V0T3V0cHV0KCkgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuc291cmNlLmNvbm5lY3QoIHRoaXMuZ2V0T3V0cHV0KCkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuX2Nvbm5lY3RlZCA9IHRydWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGlzY29ubmVjdCgpIHtcblxuXHRcdGlmICggdGhpcy5fY29ubmVjdGVkID09PSBmYWxzZSApIHtcblxuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmZpbHRlcnMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0dGhpcy5zb3VyY2UuZGlzY29ubmVjdCggdGhpcy5maWx0ZXJzWyAwIF0gKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAxLCBsID0gdGhpcy5maWx0ZXJzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0dGhpcy5maWx0ZXJzWyBpIC0gMSBdLmRpc2Nvbm5lY3QoIHRoaXMuZmlsdGVyc1sgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5maWx0ZXJzWyB0aGlzLmZpbHRlcnMubGVuZ3RoIC0gMSBdLmRpc2Nvbm5lY3QoIHRoaXMuZ2V0T3V0cHV0KCkgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuc291cmNlLmRpc2Nvbm5lY3QoIHRoaXMuZ2V0T3V0cHV0KCkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuX2Nvbm5lY3RlZCA9IGZhbHNlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldEZpbHRlcnMoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5maWx0ZXJzO1xuXG5cdH1cblxuXHRzZXRGaWx0ZXJzKCB2YWx1ZSApIHtcblxuXHRcdGlmICggISB2YWx1ZSApIHZhbHVlID0gW107XG5cblx0XHRpZiAoIHRoaXMuX2Nvbm5lY3RlZCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0dGhpcy5kaXNjb25uZWN0KCk7XG5cdFx0XHR0aGlzLmZpbHRlcnMgPSB2YWx1ZS5zbGljZSgpO1xuXHRcdFx0dGhpcy5jb25uZWN0KCk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLmZpbHRlcnMgPSB2YWx1ZS5zbGljZSgpO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldERldHVuZSggdmFsdWUgKSB7XG5cblx0XHR0aGlzLmRldHVuZSA9IHZhbHVlO1xuXG5cdFx0aWYgKCB0aGlzLmlzUGxheWluZyA9PT0gdHJ1ZSAmJiB0aGlzLnNvdXJjZS5kZXR1bmUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGhpcy5zb3VyY2UuZGV0dW5lLnNldFRhcmdldEF0VGltZSggdGhpcy5kZXR1bmUsIHRoaXMuY29udGV4dC5jdXJyZW50VGltZSwgMC4wMSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldERldHVuZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLmRldHVuZTtcblxuXHR9XG5cblx0Z2V0RmlsdGVyKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZ2V0RmlsdGVycygpWyAwIF07XG5cblx0fVxuXG5cdHNldEZpbHRlciggZmlsdGVyICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuc2V0RmlsdGVycyggZmlsdGVyID8gWyBmaWx0ZXIgXSA6IFtdICk7XG5cblx0fVxuXG5cdHNldFBsYXliYWNrUmF0ZSggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQXVkaW86IHRoaXMgQXVkaW8gaGFzIG5vIHBsYXliYWNrIGNvbnRyb2wuJyApO1xuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5wbGF5YmFja1JhdGUgPSB2YWx1ZTtcblxuXHRcdGlmICggdGhpcy5pc1BsYXlpbmcgPT09IHRydWUgKSB7XG5cblx0XHRcdHRoaXMuc291cmNlLnBsYXliYWNrUmF0ZS5zZXRUYXJnZXRBdFRpbWUoIHRoaXMucGxheWJhY2tSYXRlLCB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUsIDAuMDEgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRQbGF5YmFja1JhdGUoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5wbGF5YmFja1JhdGU7XG5cblx0fVxuXG5cdG9uRW5kZWQoKSB7XG5cblx0XHR0aGlzLmlzUGxheWluZyA9IGZhbHNlO1xuXG5cdH1cblxuXHRnZXRMb29wKCkge1xuXG5cdFx0aWYgKCB0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcblx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmxvb3A7XG5cblx0fVxuXG5cdHNldExvb3AoIHZhbHVlICkge1xuXG5cdFx0aWYgKCB0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdHRoaXMubG9vcCA9IHZhbHVlO1xuXG5cdFx0aWYgKCB0aGlzLmlzUGxheWluZyA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0dGhpcy5zb3VyY2UubG9vcCA9IHRoaXMubG9vcDtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRMb29wU3RhcnQoIHZhbHVlICkge1xuXG5cdFx0dGhpcy5sb29wU3RhcnQgPSB2YWx1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRMb29wRW5kKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMubG9vcEVuZCA9IHZhbHVlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldFZvbHVtZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLmdhaW4uZ2Fpbi52YWx1ZTtcblxuXHR9XG5cblx0c2V0Vm9sdW1lKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMuZ2Fpbi5nYWluLnNldFRhcmdldEF0VGltZSggdmFsdWUsIHRoaXMuY29udGV4dC5jdXJyZW50VGltZSwgMC4wMSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9wb3NpdGlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9xdWF0ZXJuaW9uID0gLypAX19QVVJFX18qLyBuZXcgUXVhdGVybmlvbigpO1xuY29uc3QgX3NjYWxlID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX29yaWVudGF0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jbGFzcyBQb3NpdGlvbmFsQXVkaW8gZXh0ZW5kcyBBdWRpbyB7XG5cblx0Y29uc3RydWN0b3IoIGxpc3RlbmVyICkge1xuXG5cdFx0c3VwZXIoIGxpc3RlbmVyICk7XG5cblx0XHR0aGlzLnBhbm5lciA9IHRoaXMuY29udGV4dC5jcmVhdGVQYW5uZXIoKTtcblx0XHR0aGlzLnBhbm5lci5wYW5uaW5nTW9kZWwgPSAnSFJURic7XG5cdFx0dGhpcy5wYW5uZXIuY29ubmVjdCggdGhpcy5nYWluICk7XG5cblx0fVxuXG5cdGNvbm5lY3QoKSB7XG5cblx0XHRzdXBlci5jb25uZWN0KCk7XG5cblx0XHR0aGlzLnBhbm5lci5jb25uZWN0KCB0aGlzLmdhaW4gKTtcblxuXHR9XG5cblx0ZGlzY29ubmVjdCgpIHtcblxuXHRcdHN1cGVyLmRpc2Nvbm5lY3QoKTtcblxuXHRcdHRoaXMucGFubmVyLmRpc2Nvbm5lY3QoIHRoaXMuZ2FpbiApO1xuXG5cdH1cblxuXHRnZXRPdXRwdXQoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5wYW5uZXI7XG5cblx0fVxuXG5cdGdldFJlZkRpc3RhbmNlKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMucGFubmVyLnJlZkRpc3RhbmNlO1xuXG5cdH1cblxuXHRzZXRSZWZEaXN0YW5jZSggdmFsdWUgKSB7XG5cblx0XHR0aGlzLnBhbm5lci5yZWZEaXN0YW5jZSA9IHZhbHVlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldFJvbGxvZmZGYWN0b3IoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5wYW5uZXIucm9sbG9mZkZhY3RvcjtcblxuXHR9XG5cblx0c2V0Um9sbG9mZkZhY3RvciggdmFsdWUgKSB7XG5cblx0XHR0aGlzLnBhbm5lci5yb2xsb2ZmRmFjdG9yID0gdmFsdWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0RGlzdGFuY2VNb2RlbCgpIHtcblxuXHRcdHJldHVybiB0aGlzLnBhbm5lci5kaXN0YW5jZU1vZGVsO1xuXG5cdH1cblxuXHRzZXREaXN0YW5jZU1vZGVsKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMucGFubmVyLmRpc3RhbmNlTW9kZWwgPSB2YWx1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRNYXhEaXN0YW5jZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLnBhbm5lci5tYXhEaXN0YW5jZTtcblxuXHR9XG5cblx0c2V0TWF4RGlzdGFuY2UoIHZhbHVlICkge1xuXG5cdFx0dGhpcy5wYW5uZXIubWF4RGlzdGFuY2UgPSB2YWx1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXREaXJlY3Rpb25hbENvbmUoIGNvbmVJbm5lckFuZ2xlLCBjb25lT3V0ZXJBbmdsZSwgY29uZU91dGVyR2FpbiApIHtcblxuXHRcdHRoaXMucGFubmVyLmNvbmVJbm5lckFuZ2xlID0gY29uZUlubmVyQW5nbGU7XG5cdFx0dGhpcy5wYW5uZXIuY29uZU91dGVyQW5nbGUgPSBjb25lT3V0ZXJBbmdsZTtcblx0XHR0aGlzLnBhbm5lci5jb25lT3V0ZXJHYWluID0gY29uZU91dGVyR2FpbjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XG5cblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcblxuXHRcdGlmICggdGhpcy5oYXNQbGF5YmFja0NvbnRyb2wgPT09IHRydWUgJiYgdGhpcy5pc1BsYXlpbmcgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0dGhpcy5tYXRyaXhXb3JsZC5kZWNvbXBvc2UoIF9wb3NpdGlvbiwgX3F1YXRlcm5pb24sIF9zY2FsZSApO1xuXG5cdFx0X29yaWVudGF0aW9uLnNldCggMCwgMCwgMSApLmFwcGx5UXVhdGVybmlvbiggX3F1YXRlcm5pb24gKTtcblxuXHRcdGNvbnN0IHBhbm5lciA9IHRoaXMucGFubmVyO1xuXG5cdFx0aWYgKCBwYW5uZXIucG9zaXRpb25YICkge1xuXG5cdFx0XHQvLyBjb2RlIHBhdGggZm9yIENocm9tZSBhbmQgRmlyZWZveCAoc2VlICMxNDM5MylcblxuXHRcdFx0Y29uc3QgZW5kVGltZSA9IHRoaXMuY29udGV4dC5jdXJyZW50VGltZSArIHRoaXMubGlzdGVuZXIudGltZURlbHRhO1xuXG5cdFx0XHRwYW5uZXIucG9zaXRpb25YLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfcG9zaXRpb24ueCwgZW5kVGltZSApO1xuXHRcdFx0cGFubmVyLnBvc2l0aW9uWS5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX3Bvc2l0aW9uLnksIGVuZFRpbWUgKTtcblx0XHRcdHBhbm5lci5wb3NpdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbi56LCBlbmRUaW1lICk7XG5cdFx0XHRwYW5uZXIub3JpZW50YXRpb25YLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfb3JpZW50YXRpb24ueCwgZW5kVGltZSApO1xuXHRcdFx0cGFubmVyLm9yaWVudGF0aW9uWS5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX29yaWVudGF0aW9uLnksIGVuZFRpbWUgKTtcblx0XHRcdHBhbm5lci5vcmllbnRhdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbi56LCBlbmRUaW1lICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRwYW5uZXIuc2V0UG9zaXRpb24oIF9wb3NpdGlvbi54LCBfcG9zaXRpb24ueSwgX3Bvc2l0aW9uLnogKTtcblx0XHRcdHBhbm5lci5zZXRPcmllbnRhdGlvbiggX29yaWVudGF0aW9uLngsIF9vcmllbnRhdGlvbi55LCBfb3JpZW50YXRpb24ueiApO1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5jbGFzcyBBdWRpb0FuYWx5c2VyIHtcblxuXHRjb25zdHJ1Y3RvciggYXVkaW8sIGZmdFNpemUgPSAyMDQ4ICkge1xuXG5cdFx0dGhpcy5hbmFseXNlciA9IGF1ZGlvLmNvbnRleHQuY3JlYXRlQW5hbHlzZXIoKTtcblx0XHR0aGlzLmFuYWx5c2VyLmZmdFNpemUgPSBmZnRTaXplO1xuXG5cdFx0dGhpcy5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoIHRoaXMuYW5hbHlzZXIuZnJlcXVlbmN5QmluQ291bnQgKTtcblxuXHRcdGF1ZGlvLmdldE91dHB1dCgpLmNvbm5lY3QoIHRoaXMuYW5hbHlzZXIgKTtcblxuXHR9XG5cblxuXHRnZXRGcmVxdWVuY3lEYXRhKCkge1xuXG5cdFx0dGhpcy5hbmFseXNlci5nZXRCeXRlRnJlcXVlbmN5RGF0YSggdGhpcy5kYXRhICk7XG5cblx0XHRyZXR1cm4gdGhpcy5kYXRhO1xuXG5cdH1cblxuXHRnZXRBdmVyYWdlRnJlcXVlbmN5KCkge1xuXG5cdFx0bGV0IHZhbHVlID0gMDtcblx0XHRjb25zdCBkYXRhID0gdGhpcy5nZXRGcmVxdWVuY3lEYXRhKCk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0dmFsdWUgKz0gZGF0YVsgaSBdO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHZhbHVlIC8gZGF0YS5sZW5ndGg7XG5cblx0fVxuXG59XG5cbmNsYXNzIFByb3BlcnR5TWl4ZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBiaW5kaW5nLCB0eXBlTmFtZSwgdmFsdWVTaXplICkge1xuXG5cdFx0dGhpcy5iaW5kaW5nID0gYmluZGluZztcblx0XHR0aGlzLnZhbHVlU2l6ZSA9IHZhbHVlU2l6ZTtcblxuXHRcdGxldCBtaXhGdW5jdGlvbixcblx0XHRcdG1peEZ1bmN0aW9uQWRkaXRpdmUsXG5cdFx0XHRzZXRJZGVudGl0eTtcblxuXHRcdC8vIGJ1ZmZlciBsYXlvdXQ6IFsgaW5jb21pbmcgfCBhY2N1MCB8IGFjY3UxIHwgb3JpZyB8IGFkZEFjY3UgfCAob3B0aW9uYWwgd29yaykgXVxuXHRcdC8vXG5cdFx0Ly8gaW50ZXJwb2xhdG9ycyBjYW4gdXNlIC5idWZmZXIgYXMgdGhlaXIgLnJlc3VsdFxuXHRcdC8vIHRoZSBkYXRhIHRoZW4gZ29lcyB0byAnaW5jb21pbmcnXG5cdFx0Ly9cblx0XHQvLyAnYWNjdTAnIGFuZCAnYWNjdTEnIGFyZSB1c2VkIGZyYW1lLWludGVybGVhdmVkIGZvclxuXHRcdC8vIHRoZSBjdW11bGF0aXZlIHJlc3VsdCBhbmQgYXJlIGNvbXBhcmVkIHRvIGRldGVjdFxuXHRcdC8vIGNoYW5nZXNcblx0XHQvL1xuXHRcdC8vICdvcmlnJyBzdG9yZXMgdGhlIG9yaWdpbmFsIHN0YXRlIG9mIHRoZSBwcm9wZXJ0eVxuXHRcdC8vXG5cdFx0Ly8gJ2FkZCcgaXMgdXNlZCBmb3IgYWRkaXRpdmUgY3VtdWxhdGl2ZSByZXN1bHRzXG5cdFx0Ly9cblx0XHQvLyAnd29yaycgaXMgb3B0aW9uYWwgYW5kIGlzIG9ubHkgcHJlc2VudCBmb3IgcXVhdGVybmlvbiB0eXBlcy4gSXQgaXMgdXNlZFxuXHRcdC8vIHRvIHN0b3JlIGludGVybWVkaWF0ZSBxdWF0ZXJuaW9uIG11bHRpcGxpY2F0aW9uIHJlc3VsdHNcblxuXHRcdHN3aXRjaCAoIHR5cGVOYW1lICkge1xuXG5cdFx0XHRjYXNlICdxdWF0ZXJuaW9uJzpcblx0XHRcdFx0bWl4RnVuY3Rpb24gPSB0aGlzLl9zbGVycDtcblx0XHRcdFx0bWl4RnVuY3Rpb25BZGRpdGl2ZSA9IHRoaXMuX3NsZXJwQWRkaXRpdmU7XG5cdFx0XHRcdHNldElkZW50aXR5ID0gdGhpcy5fc2V0QWRkaXRpdmVJZGVudGl0eVF1YXRlcm5pb247XG5cblx0XHRcdFx0dGhpcy5idWZmZXIgPSBuZXcgRmxvYXQ2NEFycmF5KCB2YWx1ZVNpemUgKiA2ICk7XG5cdFx0XHRcdHRoaXMuX3dvcmtJbmRleCA9IDU7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdzdHJpbmcnOlxuXHRcdFx0Y2FzZSAnYm9vbCc6XG5cdFx0XHRcdG1peEZ1bmN0aW9uID0gdGhpcy5fc2VsZWN0O1xuXG5cdFx0XHRcdC8vIFVzZSB0aGUgcmVndWxhciBtaXggZnVuY3Rpb24gYW5kIGZvciBhZGRpdGl2ZSBvbiB0aGVzZSB0eXBlcyxcblx0XHRcdFx0Ly8gYWRkaXRpdmUgaXMgbm90IHJlbGV2YW50IGZvciBub24tbnVtZXJpYyB0eXBlc1xuXHRcdFx0XHRtaXhGdW5jdGlvbkFkZGl0aXZlID0gdGhpcy5fc2VsZWN0O1xuXG5cdFx0XHRcdHNldElkZW50aXR5ID0gdGhpcy5fc2V0QWRkaXRpdmVJZGVudGl0eU90aGVyO1xuXG5cdFx0XHRcdHRoaXMuYnVmZmVyID0gbmV3IEFycmF5KCB2YWx1ZVNpemUgKiA1ICk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRtaXhGdW5jdGlvbiA9IHRoaXMuX2xlcnA7XG5cdFx0XHRcdG1peEZ1bmN0aW9uQWRkaXRpdmUgPSB0aGlzLl9sZXJwQWRkaXRpdmU7XG5cdFx0XHRcdHNldElkZW50aXR5ID0gdGhpcy5fc2V0QWRkaXRpdmVJZGVudGl0eU51bWVyaWM7XG5cblx0XHRcdFx0dGhpcy5idWZmZXIgPSBuZXcgRmxvYXQ2NEFycmF5KCB2YWx1ZVNpemUgKiA1ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb24gPSBtaXhGdW5jdGlvbjtcblx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb25BZGRpdGl2ZSA9IG1peEZ1bmN0aW9uQWRkaXRpdmU7XG5cdFx0dGhpcy5fc2V0SWRlbnRpdHkgPSBzZXRJZGVudGl0eTtcblx0XHR0aGlzLl9vcmlnSW5kZXggPSAzO1xuXHRcdHRoaXMuX2FkZEluZGV4ID0gNDtcblxuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodCA9IDA7XG5cdFx0dGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUgPSAwO1xuXG5cdFx0dGhpcy51c2VDb3VudCA9IDA7XG5cdFx0dGhpcy5yZWZlcmVuY2VDb3VudCA9IDA7XG5cblx0fVxuXG5cdC8vIGFjY3VtdWxhdGUgZGF0YSBpbiB0aGUgJ2luY29taW5nJyByZWdpb24gaW50byAnYWNjdTxpPidcblx0YWNjdW11bGF0ZSggYWNjdUluZGV4LCB3ZWlnaHQgKSB7XG5cblx0XHQvLyBub3RlOiBoYXBwaWx5IGFjY3VtdWxhdGluZyBub3RoaW5nIHdoZW4gd2VpZ2h0ID0gMCwgdGhlIGNhbGxlciBrbm93c1xuXHRcdC8vIHRoZSB3ZWlnaHQgYW5kIHNob3VsZG4ndCBoYXZlIG1hZGUgdGhlIGNhbGwgaW4gdGhlIGZpcnN0IHBsYWNlXG5cblx0XHRjb25zdCBidWZmZXIgPSB0aGlzLmJ1ZmZlcixcblx0XHRcdHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxuXHRcdFx0b2Zmc2V0ID0gYWNjdUluZGV4ICogc3RyaWRlICsgc3RyaWRlO1xuXG5cdFx0bGV0IGN1cnJlbnRXZWlnaHQgPSB0aGlzLmN1bXVsYXRpdmVXZWlnaHQ7XG5cblx0XHRpZiAoIGN1cnJlbnRXZWlnaHQgPT09IDAgKSB7XG5cblx0XHRcdC8vIGFjY3VOIDo9IGluY29taW5nICogd2VpZ2h0XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xuXG5cdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgaSBdID0gYnVmZmVyWyBpIF07XG5cblx0XHRcdH1cblxuXHRcdFx0Y3VycmVudFdlaWdodCA9IHdlaWdodDtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIGFjY3VOIDo9IGFjY3VOICsgaW5jb21pbmcgKiB3ZWlnaHRcblxuXHRcdFx0Y3VycmVudFdlaWdodCArPSB3ZWlnaHQ7XG5cdFx0XHRjb25zdCBtaXggPSB3ZWlnaHQgLyBjdXJyZW50V2VpZ2h0O1xuXHRcdFx0dGhpcy5fbWl4QnVmZmVyUmVnaW9uKCBidWZmZXIsIG9mZnNldCwgMCwgbWl4LCBzdHJpZGUgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodCA9IGN1cnJlbnRXZWlnaHQ7XG5cblx0fVxuXG5cdC8vIGFjY3VtdWxhdGUgZGF0YSBpbiB0aGUgJ2luY29taW5nJyByZWdpb24gaW50byAnYWRkJ1xuXHRhY2N1bXVsYXRlQWRkaXRpdmUoIHdlaWdodCApIHtcblxuXHRcdGNvbnN0IGJ1ZmZlciA9IHRoaXMuYnVmZmVyLFxuXHRcdFx0c3RyaWRlID0gdGhpcy52YWx1ZVNpemUsXG5cdFx0XHRvZmZzZXQgPSBzdHJpZGUgKiB0aGlzLl9hZGRJbmRleDtcblxuXHRcdGlmICggdGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUgPT09IDAgKSB7XG5cblx0XHRcdC8vIGFkZCA9IGlkZW50aXR5XG5cblx0XHRcdHRoaXMuX3NldElkZW50aXR5KCk7XG5cblx0XHR9XG5cblx0XHQvLyBhZGQgOj0gYWRkICsgaW5jb21pbmcgKiB3ZWlnaHRcblxuXHRcdHRoaXMuX21peEJ1ZmZlclJlZ2lvbkFkZGl0aXZlKCBidWZmZXIsIG9mZnNldCwgMCwgd2VpZ2h0LCBzdHJpZGUgKTtcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHRBZGRpdGl2ZSArPSB3ZWlnaHQ7XG5cblx0fVxuXG5cdC8vIGFwcGx5IHRoZSBzdGF0ZSBvZiAnYWNjdTxpPicgdG8gdGhlIGJpbmRpbmcgd2hlbiBhY2N1cyBkaWZmZXJcblx0YXBwbHkoIGFjY3VJbmRleCApIHtcblxuXHRcdGNvbnN0IHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxuXHRcdFx0YnVmZmVyID0gdGhpcy5idWZmZXIsXG5cdFx0XHRvZmZzZXQgPSBhY2N1SW5kZXggKiBzdHJpZGUgKyBzdHJpZGUsXG5cblx0XHRcdHdlaWdodCA9IHRoaXMuY3VtdWxhdGl2ZVdlaWdodCxcblx0XHRcdHdlaWdodEFkZGl0aXZlID0gdGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUsXG5cblx0XHRcdGJpbmRpbmcgPSB0aGlzLmJpbmRpbmc7XG5cblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHQgPSAwO1xuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodEFkZGl0aXZlID0gMDtcblxuXHRcdGlmICggd2VpZ2h0IDwgMSApIHtcblxuXHRcdFx0Ly8gYWNjdU4gOj0gYWNjdU4gKyBvcmlnaW5hbCAqICggMSAtIGN1bXVsYXRpdmVXZWlnaHQgKVxuXG5cdFx0XHRjb25zdCBvcmlnaW5hbFZhbHVlT2Zmc2V0ID0gc3RyaWRlICogdGhpcy5fb3JpZ0luZGV4O1xuXG5cdFx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb24oXG5cdFx0XHRcdGJ1ZmZlciwgb2Zmc2V0LCBvcmlnaW5hbFZhbHVlT2Zmc2V0LCAxIC0gd2VpZ2h0LCBzdHJpZGUgKTtcblxuXHRcdH1cblxuXHRcdGlmICggd2VpZ2h0QWRkaXRpdmUgPiAwICkge1xuXG5cdFx0XHQvLyBhY2N1TiA6PSBhY2N1TiArIGFkZGl0aXZlIGFjY3VOXG5cblx0XHRcdHRoaXMuX21peEJ1ZmZlclJlZ2lvbkFkZGl0aXZlKCBidWZmZXIsIG9mZnNldCwgdGhpcy5fYWRkSW5kZXggKiBzdHJpZGUsIDEsIHN0cmlkZSApO1xuXG5cdFx0fVxuXG5cdFx0Zm9yICggbGV0IGkgPSBzdHJpZGUsIGUgPSBzdHJpZGUgKyBzdHJpZGU7IGkgIT09IGU7ICsrIGkgKSB7XG5cblx0XHRcdGlmICggYnVmZmVyWyBpIF0gIT09IGJ1ZmZlclsgaSArIHN0cmlkZSBdICkge1xuXG5cdFx0XHRcdC8vIHZhbHVlIGhhcyBjaGFuZ2VkIC0+IHVwZGF0ZSBzY2VuZSBncmFwaFxuXG5cdFx0XHRcdGJpbmRpbmcuc2V0VmFsdWUoIGJ1ZmZlciwgb2Zmc2V0ICk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdC8vIHJlbWVtYmVyIHRoZSBzdGF0ZSBvZiB0aGUgYm91bmQgcHJvcGVydHkgYW5kIGNvcHkgaXQgdG8gYm90aCBhY2N1c1xuXHRzYXZlT3JpZ2luYWxTdGF0ZSgpIHtcblxuXHRcdGNvbnN0IGJpbmRpbmcgPSB0aGlzLmJpbmRpbmc7XG5cblx0XHRjb25zdCBidWZmZXIgPSB0aGlzLmJ1ZmZlcixcblx0XHRcdHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxuXG5cdFx0XHRvcmlnaW5hbFZhbHVlT2Zmc2V0ID0gc3RyaWRlICogdGhpcy5fb3JpZ0luZGV4O1xuXG5cdFx0YmluZGluZy5nZXRWYWx1ZSggYnVmZmVyLCBvcmlnaW5hbFZhbHVlT2Zmc2V0ICk7XG5cblx0XHQvLyBhY2N1WzAuLjFdIDo9IG9yaWcgLS0gaW5pdGlhbGx5IGRldGVjdCBjaGFuZ2VzIGFnYWluc3QgdGhlIG9yaWdpbmFsXG5cdFx0Zm9yICggbGV0IGkgPSBzdHJpZGUsIGUgPSBvcmlnaW5hbFZhbHVlT2Zmc2V0OyBpICE9PSBlOyArKyBpICkge1xuXG5cdFx0XHRidWZmZXJbIGkgXSA9IGJ1ZmZlclsgb3JpZ2luYWxWYWx1ZU9mZnNldCArICggaSAlIHN0cmlkZSApIF07XG5cblx0XHR9XG5cblx0XHQvLyBBZGQgdG8gaWRlbnRpdHkgZm9yIGFkZGl0aXZlXG5cdFx0dGhpcy5fc2V0SWRlbnRpdHkoKTtcblxuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodCA9IDA7XG5cdFx0dGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUgPSAwO1xuXG5cdH1cblxuXHQvLyBhcHBseSB0aGUgc3RhdGUgcHJldmlvdXNseSB0YWtlbiB2aWEgJ3NhdmVPcmlnaW5hbFN0YXRlJyB0byB0aGUgYmluZGluZ1xuXHRyZXN0b3JlT3JpZ2luYWxTdGF0ZSgpIHtcblxuXHRcdGNvbnN0IG9yaWdpbmFsVmFsdWVPZmZzZXQgPSB0aGlzLnZhbHVlU2l6ZSAqIDM7XG5cdFx0dGhpcy5iaW5kaW5nLnNldFZhbHVlKCB0aGlzLmJ1ZmZlciwgb3JpZ2luYWxWYWx1ZU9mZnNldCApO1xuXG5cdH1cblxuXHRfc2V0QWRkaXRpdmVJZGVudGl0eU51bWVyaWMoKSB7XG5cblx0XHRjb25zdCBzdGFydEluZGV4ID0gdGhpcy5fYWRkSW5kZXggKiB0aGlzLnZhbHVlU2l6ZTtcblx0XHRjb25zdCBlbmRJbmRleCA9IHN0YXJ0SW5kZXggKyB0aGlzLnZhbHVlU2l6ZTtcblxuXHRcdGZvciAoIGxldCBpID0gc3RhcnRJbmRleDsgaSA8IGVuZEluZGV4OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmJ1ZmZlclsgaSBdID0gMDtcblxuXHRcdH1cblxuXHR9XG5cblx0X3NldEFkZGl0aXZlSWRlbnRpdHlRdWF0ZXJuaW9uKCkge1xuXG5cdFx0dGhpcy5fc2V0QWRkaXRpdmVJZGVudGl0eU51bWVyaWMoKTtcblx0XHR0aGlzLmJ1ZmZlclsgdGhpcy5fYWRkSW5kZXggKiB0aGlzLnZhbHVlU2l6ZSArIDMgXSA9IDE7XG5cblx0fVxuXG5cdF9zZXRBZGRpdGl2ZUlkZW50aXR5T3RoZXIoKSB7XG5cblx0XHRjb25zdCBzdGFydEluZGV4ID0gdGhpcy5fb3JpZ0luZGV4ICogdGhpcy52YWx1ZVNpemU7XG5cdFx0Y29uc3QgdGFyZ2V0SW5kZXggPSB0aGlzLl9hZGRJbmRleCAqIHRoaXMudmFsdWVTaXplO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy52YWx1ZVNpemU7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuYnVmZmVyWyB0YXJnZXRJbmRleCArIGkgXSA9IHRoaXMuYnVmZmVyWyBzdGFydEluZGV4ICsgaSBdO1xuXG5cdFx0fVxuXG5cdH1cblxuXG5cdC8vIG1peCBmdW5jdGlvbnNcblxuXHRfc2VsZWN0KCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XG5cblx0XHRpZiAoIHQgPj0gMC41ICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IHN0cmlkZTsgKysgaSApIHtcblxuXHRcdFx0XHRidWZmZXJbIGRzdE9mZnNldCArIGkgXSA9IGJ1ZmZlclsgc3JjT2Zmc2V0ICsgaSBdO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdF9zbGVycCggYnVmZmVyLCBkc3RPZmZzZXQsIHNyY09mZnNldCwgdCApIHtcblxuXHRcdFF1YXRlcm5pb24uc2xlcnBGbGF0KCBidWZmZXIsIGRzdE9mZnNldCwgYnVmZmVyLCBkc3RPZmZzZXQsIGJ1ZmZlciwgc3JjT2Zmc2V0LCB0ICk7XG5cblx0fVxuXG5cdF9zbGVycEFkZGl0aXZlKCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XG5cblx0XHRjb25zdCB3b3JrT2Zmc2V0ID0gdGhpcy5fd29ya0luZGV4ICogc3RyaWRlO1xuXG5cdFx0Ly8gU3RvcmUgcmVzdWx0IGluIGludGVybWVkaWF0ZSBidWZmZXIgb2Zmc2V0XG5cdFx0UXVhdGVybmlvbi5tdWx0aXBseVF1YXRlcm5pb25zRmxhdCggYnVmZmVyLCB3b3JrT2Zmc2V0LCBidWZmZXIsIGRzdE9mZnNldCwgYnVmZmVyLCBzcmNPZmZzZXQgKTtcblxuXHRcdC8vIFNsZXJwIHRvIHRoZSBpbnRlcm1lZGlhdGUgcmVzdWx0XG5cdFx0UXVhdGVybmlvbi5zbGVycEZsYXQoIGJ1ZmZlciwgZHN0T2Zmc2V0LCBidWZmZXIsIGRzdE9mZnNldCwgYnVmZmVyLCB3b3JrT2Zmc2V0LCB0ICk7XG5cblx0fVxuXG5cdF9sZXJwKCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XG5cblx0XHRjb25zdCBzID0gMSAtIHQ7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IHN0cmlkZTsgKysgaSApIHtcblxuXHRcdFx0Y29uc3QgaiA9IGRzdE9mZnNldCArIGk7XG5cblx0XHRcdGJ1ZmZlclsgaiBdID0gYnVmZmVyWyBqIF0gKiBzICsgYnVmZmVyWyBzcmNPZmZzZXQgKyBpIF0gKiB0O1xuXG5cdFx0fVxuXG5cdH1cblxuXHRfbGVycEFkZGl0aXZlKCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IHN0cmlkZTsgKysgaSApIHtcblxuXHRcdFx0Y29uc3QgaiA9IGRzdE9mZnNldCArIGk7XG5cblx0XHRcdGJ1ZmZlclsgaiBdID0gYnVmZmVyWyBqIF0gKyBidWZmZXJbIHNyY09mZnNldCArIGkgXSAqIHQ7XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbi8vIENoYXJhY3RlcnMgW10uOi8gYXJlIHJlc2VydmVkIGZvciB0cmFjayBiaW5kaW5nIHN5bnRheC5cbmNvbnN0IF9SRVNFUlZFRF9DSEFSU19SRSA9ICdcXFxcW1xcXFxdXFxcXC46XFxcXC8nO1xuY29uc3QgX3Jlc2VydmVkUmUgPSBuZXcgUmVnRXhwKCAnWycgKyBfUkVTRVJWRURfQ0hBUlNfUkUgKyAnXScsICdnJyApO1xuXG4vLyBBdHRlbXB0cyB0byBhbGxvdyBub2RlIG5hbWVzIGZyb20gYW55IGxhbmd1YWdlLiBFUzUncyBgXFx3YCByZWdleHAgbWF0Y2hlc1xuLy8gb25seSBsYXRpbiBjaGFyYWN0ZXJzLCBhbmQgdGhlIHVuaWNvZGUgXFxwe0x9IGlzIG5vdCB5ZXQgc3VwcG9ydGVkLiBTb1xuLy8gaW5zdGVhZCwgd2UgZXhjbHVkZSByZXNlcnZlZCBjaGFyYWN0ZXJzIGFuZCBtYXRjaCBldmVyeXRoaW5nIGVsc2UuXG5jb25zdCBfd29yZENoYXIgPSAnW14nICsgX1JFU0VSVkVEX0NIQVJTX1JFICsgJ10nO1xuY29uc3QgX3dvcmRDaGFyT3JEb3QgPSAnW14nICsgX1JFU0VSVkVEX0NIQVJTX1JFLnJlcGxhY2UoICdcXFxcLicsICcnICkgKyAnXSc7XG5cbi8vIFBhcmVudCBkaXJlY3RvcmllcywgZGVsaW1pdGVkIGJ5ICcvJyBvciAnOicuIEN1cnJlbnRseSB1bnVzZWQsIGJ1dCBtdXN0XG4vLyBiZSBtYXRjaGVkIHRvIHBhcnNlIHRoZSByZXN0IG9mIHRoZSB0cmFjayBuYW1lLlxuY29uc3QgX2RpcmVjdG9yeVJlID0gLypAX19QVVJFX18qLyAvKCg/OldDK1tcXC86XSkqKS8uc291cmNlLnJlcGxhY2UoICdXQycsIF93b3JkQ2hhciApO1xuXG4vLyBUYXJnZXQgbm9kZS4gTWF5IGNvbnRhaW4gd29yZCBjaGFyYWN0ZXJzIChhLXpBLVowLTlfKSBhbmQgJy4nIG9yICctJy5cbmNvbnN0IF9ub2RlUmUgPSAvKkBfX1BVUkVfXyovIC8oV0NPRCspPy8uc291cmNlLnJlcGxhY2UoICdXQ09EJywgX3dvcmRDaGFyT3JEb3QgKTtcblxuLy8gT2JqZWN0IG9uIHRhcmdldCBub2RlLCBhbmQgYWNjZXNzb3IuIE1heSBub3QgY29udGFpbiByZXNlcnZlZFxuLy8gY2hhcmFjdGVycy4gQWNjZXNzb3IgbWF5IGNvbnRhaW4gYW55IGNoYXJhY3RlciBleGNlcHQgY2xvc2luZyBicmFja2V0LlxuY29uc3QgX29iamVjdFJlID0gLypAX19QVVJFX18qLyAvKD86XFwuKFdDKykoPzpcXFsoLispXFxdKT8pPy8uc291cmNlLnJlcGxhY2UoICdXQycsIF93b3JkQ2hhciApO1xuXG4vLyBQcm9wZXJ0eSBhbmQgYWNjZXNzb3IuIE1heSBub3QgY29udGFpbiByZXNlcnZlZCBjaGFyYWN0ZXJzLiBBY2Nlc3NvciBtYXlcbi8vIGNvbnRhaW4gYW55IG5vbi1icmFja2V0IGNoYXJhY3RlcnMuXG5jb25zdCBfcHJvcGVydHlSZSA9IC8qQF9fUFVSRV9fKi8gL1xcLihXQyspKD86XFxbKC4rKVxcXSk/Ly5zb3VyY2UucmVwbGFjZSggJ1dDJywgX3dvcmRDaGFyICk7XG5cbmNvbnN0IF90cmFja1JlID0gbmV3IFJlZ0V4cCggJydcblx0KyAnXidcblx0KyBfZGlyZWN0b3J5UmVcblx0KyBfbm9kZVJlXG5cdCsgX29iamVjdFJlXG5cdCsgX3Byb3BlcnR5UmVcblx0KyAnJCdcbik7XG5cbmNvbnN0IF9zdXBwb3J0ZWRPYmplY3ROYW1lcyA9IFsgJ21hdGVyaWFsJywgJ21hdGVyaWFscycsICdib25lcycsICdtYXAnIF07XG5cbmNsYXNzIENvbXBvc2l0ZSB7XG5cblx0Y29uc3RydWN0b3IoIHRhcmdldEdyb3VwLCBwYXRoLCBvcHRpb25hbFBhcnNlZFBhdGggKSB7XG5cblx0XHRjb25zdCBwYXJzZWRQYXRoID0gb3B0aW9uYWxQYXJzZWRQYXRoIHx8IFByb3BlcnR5QmluZGluZy5wYXJzZVRyYWNrTmFtZSggcGF0aCApO1xuXG5cdFx0dGhpcy5fdGFyZ2V0R3JvdXAgPSB0YXJnZXRHcm91cDtcblx0XHR0aGlzLl9iaW5kaW5ncyA9IHRhcmdldEdyb3VwLnN1YnNjcmliZV8oIHBhdGgsIHBhcnNlZFBhdGggKTtcblxuXHR9XG5cblx0Z2V0VmFsdWUoIGFycmF5LCBvZmZzZXQgKSB7XG5cblx0XHR0aGlzLmJpbmQoKTsgLy8gYmluZCBhbGwgYmluZGluZ1xuXG5cdFx0Y29uc3QgZmlyc3RWYWxpZEluZGV4ID0gdGhpcy5fdGFyZ2V0R3JvdXAubkNhY2hlZE9iamVjdHNfLFxuXHRcdFx0YmluZGluZyA9IHRoaXMuX2JpbmRpbmdzWyBmaXJzdFZhbGlkSW5kZXggXTtcblxuXHRcdC8vIGFuZCBvbmx5IGNhbGwgLmdldFZhbHVlIG9uIHRoZSBmaXJzdFxuXHRcdGlmICggYmluZGluZyAhPT0gdW5kZWZpbmVkICkgYmluZGluZy5nZXRWYWx1ZSggYXJyYXksIG9mZnNldCApO1xuXG5cdH1cblxuXHRzZXRWYWx1ZSggYXJyYXksIG9mZnNldCApIHtcblxuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3M7XG5cblx0XHRmb3IgKCBsZXQgaSA9IHRoaXMuX3RhcmdldEdyb3VwLm5DYWNoZWRPYmplY3RzXywgbiA9IGJpbmRpbmdzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0YmluZGluZ3NbIGkgXS5zZXRWYWx1ZSggYXJyYXksIG9mZnNldCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRiaW5kKCkge1xuXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncztcblxuXHRcdGZvciAoIGxldCBpID0gdGhpcy5fdGFyZ2V0R3JvdXAubkNhY2hlZE9iamVjdHNfLCBuID0gYmluZGluZ3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRiaW5kaW5nc1sgaSBdLmJpbmQoKTtcblxuXHRcdH1cblxuXHR9XG5cblx0dW5iaW5kKCkge1xuXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncztcblxuXHRcdGZvciAoIGxldCBpID0gdGhpcy5fdGFyZ2V0R3JvdXAubkNhY2hlZE9iamVjdHNfLCBuID0gYmluZGluZ3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRiaW5kaW5nc1sgaSBdLnVuYmluZCgpO1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG4vLyBOb3RlOiBUaGlzIGNsYXNzIHVzZXMgYSBTdGF0ZSBwYXR0ZXJuIG9uIGEgcGVyLW1ldGhvZCBiYXNpczpcbi8vICdiaW5kJyBzZXRzICd0aGlzLmdldFZhbHVlJyAvICdzZXRWYWx1ZScgYW5kIHNoYWRvd3MgdGhlXG4vLyBwcm90b3R5cGUgdmVyc2lvbiBvZiB0aGVzZSBtZXRob2RzIHdpdGggb25lIHRoYXQgcmVwcmVzZW50c1xuLy8gdGhlIGJvdW5kIHN0YXRlLiBXaGVuIHRoZSBwcm9wZXJ0eSBpcyBub3QgZm91bmQsIHRoZSBtZXRob2RzXG4vLyBiZWNvbWUgbm8tb3BzLlxuY2xhc3MgUHJvcGVydHlCaW5kaW5nIHtcblxuXHRjb25zdHJ1Y3Rvciggcm9vdE5vZGUsIHBhdGgsIHBhcnNlZFBhdGggKSB7XG5cblx0XHR0aGlzLnBhdGggPSBwYXRoO1xuXHRcdHRoaXMucGFyc2VkUGF0aCA9IHBhcnNlZFBhdGggfHwgUHJvcGVydHlCaW5kaW5nLnBhcnNlVHJhY2tOYW1lKCBwYXRoICk7XG5cblx0XHR0aGlzLm5vZGUgPSBQcm9wZXJ0eUJpbmRpbmcuZmluZE5vZGUoIHJvb3ROb2RlLCB0aGlzLnBhcnNlZFBhdGgubm9kZU5hbWUgKTtcblxuXHRcdHRoaXMucm9vdE5vZGUgPSByb290Tm9kZTtcblxuXHRcdC8vIGluaXRpYWwgc3RhdGUgb2YgdGhlc2UgbWV0aG9kcyB0aGF0IGNhbGxzICdiaW5kJ1xuXHRcdHRoaXMuZ2V0VmFsdWUgPSB0aGlzLl9nZXRWYWx1ZV91bmJvdW5kO1xuXHRcdHRoaXMuc2V0VmFsdWUgPSB0aGlzLl9zZXRWYWx1ZV91bmJvdW5kO1xuXG5cdH1cblxuXG5cdHN0YXRpYyBjcmVhdGUoIHJvb3QsIHBhdGgsIHBhcnNlZFBhdGggKSB7XG5cblx0XHRpZiAoICEgKCByb290ICYmIHJvb3QuaXNBbmltYXRpb25PYmplY3RHcm91cCApICkge1xuXG5cdFx0XHRyZXR1cm4gbmV3IFByb3BlcnR5QmluZGluZyggcm9vdCwgcGF0aCwgcGFyc2VkUGF0aCApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmV0dXJuIG5ldyBQcm9wZXJ0eUJpbmRpbmcuQ29tcG9zaXRlKCByb290LCBwYXRoLCBwYXJzZWRQYXRoICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBSZXBsYWNlcyBzcGFjZXMgd2l0aCB1bmRlcnNjb3JlcyBhbmQgcmVtb3ZlcyB1bnN1cHBvcnRlZCBjaGFyYWN0ZXJzIGZyb21cblx0ICogbm9kZSBuYW1lcywgdG8gZW5zdXJlIGNvbXBhdGliaWxpdHkgd2l0aCBwYXJzZVRyYWNrTmFtZSgpLlxuXHQgKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBOb2RlIG5hbWUgdG8gYmUgc2FuaXRpemVkLlxuXHQgKiBAcmV0dXJuIHtzdHJpbmd9XG5cdCAqL1xuXHRzdGF0aWMgc2FuaXRpemVOb2RlTmFtZSggbmFtZSApIHtcblxuXHRcdHJldHVybiBuYW1lLnJlcGxhY2UoIC9cXHMvZywgJ18nICkucmVwbGFjZSggX3Jlc2VydmVkUmUsICcnICk7XG5cblx0fVxuXG5cdHN0YXRpYyBwYXJzZVRyYWNrTmFtZSggdHJhY2tOYW1lICkge1xuXG5cdFx0Y29uc3QgbWF0Y2hlcyA9IF90cmFja1JlLmV4ZWMoIHRyYWNrTmFtZSApO1xuXG5cdFx0aWYgKCBtYXRjaGVzID09PSBudWxsICkge1xuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdQcm9wZXJ0eUJpbmRpbmc6IENhbm5vdCBwYXJzZSB0cmFja05hbWU6ICcgKyB0cmFja05hbWUgKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHJlc3VsdHMgPSB7XG5cdFx0XHQvLyBkaXJlY3RvcnlOYW1lOiBtYXRjaGVzWyAxIF0sIC8vICh0c2NodykgY3VycmVudGx5IHVudXNlZFxuXHRcdFx0bm9kZU5hbWU6IG1hdGNoZXNbIDIgXSxcblx0XHRcdG9iamVjdE5hbWU6IG1hdGNoZXNbIDMgXSxcblx0XHRcdG9iamVjdEluZGV4OiBtYXRjaGVzWyA0IF0sXG5cdFx0XHRwcm9wZXJ0eU5hbWU6IG1hdGNoZXNbIDUgXSwgLy8gcmVxdWlyZWRcblx0XHRcdHByb3BlcnR5SW5kZXg6IG1hdGNoZXNbIDYgXVxuXHRcdH07XG5cblx0XHRjb25zdCBsYXN0RG90ID0gcmVzdWx0cy5ub2RlTmFtZSAmJiByZXN1bHRzLm5vZGVOYW1lLmxhc3RJbmRleE9mKCAnLicgKTtcblxuXHRcdGlmICggbGFzdERvdCAhPT0gdW5kZWZpbmVkICYmIGxhc3REb3QgIT09IC0gMSApIHtcblxuXHRcdFx0Y29uc3Qgb2JqZWN0TmFtZSA9IHJlc3VsdHMubm9kZU5hbWUuc3Vic3RyaW5nKCBsYXN0RG90ICsgMSApO1xuXG5cdFx0XHQvLyBPYmplY3QgbmFtZXMgbXVzdCBiZSBjaGVja2VkIGFnYWluc3QgYW4gYWxsb3dsaXN0LiBPdGhlcndpc2UsIHRoZXJlXG5cdFx0XHQvLyBpcyBubyB3YXkgdG8gcGFyc2UgJ2Zvby5iYXIuYmF6JzogJ2JheicgbXVzdCBiZSBhIHByb3BlcnR5LCBidXRcblx0XHRcdC8vICdiYXInIGNvdWxkIGJlIHRoZSBvYmplY3ROYW1lLCBvciBwYXJ0IG9mIGEgbm9kZU5hbWUgKHdoaWNoIGNhblxuXHRcdFx0Ly8gaW5jbHVkZSAnLicgY2hhcmFjdGVycykuXG5cdFx0XHRpZiAoIF9zdXBwb3J0ZWRPYmplY3ROYW1lcy5pbmRleE9mKCBvYmplY3ROYW1lICkgIT09IC0gMSApIHtcblxuXHRcdFx0XHRyZXN1bHRzLm5vZGVOYW1lID0gcmVzdWx0cy5ub2RlTmFtZS5zdWJzdHJpbmcoIDAsIGxhc3REb3QgKTtcblx0XHRcdFx0cmVzdWx0cy5vYmplY3ROYW1lID0gb2JqZWN0TmFtZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCByZXN1bHRzLnByb3BlcnR5TmFtZSA9PT0gbnVsbCB8fCByZXN1bHRzLnByb3BlcnR5TmFtZS5sZW5ndGggPT09IDAgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1Byb3BlcnR5QmluZGluZzogY2FuIG5vdCBwYXJzZSBwcm9wZXJ0eU5hbWUgZnJvbSB0cmFja05hbWU6ICcgKyB0cmFja05hbWUgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiByZXN1bHRzO1xuXG5cdH1cblxuXHRzdGF0aWMgZmluZE5vZGUoIHJvb3QsIG5vZGVOYW1lICkge1xuXG5cdFx0aWYgKCBub2RlTmFtZSA9PT0gdW5kZWZpbmVkIHx8IG5vZGVOYW1lID09PSAnJyB8fCBub2RlTmFtZSA9PT0gJy4nIHx8IG5vZGVOYW1lID09PSAtIDEgfHwgbm9kZU5hbWUgPT09IHJvb3QubmFtZSB8fCBub2RlTmFtZSA9PT0gcm9vdC51dWlkICkge1xuXG5cdFx0XHRyZXR1cm4gcm9vdDtcblxuXHRcdH1cblxuXHRcdC8vIHNlYXJjaCBpbnRvIHNrZWxldG9uIGJvbmVzLlxuXHRcdGlmICggcm9vdC5za2VsZXRvbiApIHtcblxuXHRcdFx0Y29uc3QgYm9uZSA9IHJvb3Quc2tlbGV0b24uZ2V0Qm9uZUJ5TmFtZSggbm9kZU5hbWUgKTtcblxuXHRcdFx0aWYgKCBib25lICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0cmV0dXJuIGJvbmU7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIHNlYXJjaCBpbnRvIG5vZGUgc3VidHJlZS5cblx0XHRpZiAoIHJvb3QuY2hpbGRyZW4gKSB7XG5cblx0XHRcdGNvbnN0IHNlYXJjaE5vZGVTdWJ0cmVlID0gZnVuY3Rpb24gKCBjaGlsZHJlbiApIHtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBjaGlsZE5vZGUgPSBjaGlsZHJlblsgaSBdO1xuXG5cdFx0XHRcdFx0aWYgKCBjaGlsZE5vZGUubmFtZSA9PT0gbm9kZU5hbWUgfHwgY2hpbGROb2RlLnV1aWQgPT09IG5vZGVOYW1lICkge1xuXG5cdFx0XHRcdFx0XHRyZXR1cm4gY2hpbGROb2RlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Y29uc3QgcmVzdWx0ID0gc2VhcmNoTm9kZVN1YnRyZWUoIGNoaWxkTm9kZS5jaGlsZHJlbiApO1xuXG5cdFx0XHRcdFx0aWYgKCByZXN1bHQgKSByZXR1cm4gcmVzdWx0O1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0fTtcblxuXHRcdFx0Y29uc3Qgc3ViVHJlZU5vZGUgPSBzZWFyY2hOb2RlU3VidHJlZSggcm9vdC5jaGlsZHJlbiApO1xuXG5cdFx0XHRpZiAoIHN1YlRyZWVOb2RlICkge1xuXG5cdFx0XHRcdHJldHVybiBzdWJUcmVlTm9kZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG51bGw7XG5cblx0fVxuXG5cdC8vIHRoZXNlIGFyZSB1c2VkIHRvIFwiYmluZFwiIGEgbm9uZXhpc3RlbnQgcHJvcGVydHlcblx0X2dldFZhbHVlX3VuYXZhaWxhYmxlKCkge31cblx0X3NldFZhbHVlX3VuYXZhaWxhYmxlKCkge31cblxuXHQvLyBHZXR0ZXJzXG5cblx0X2dldFZhbHVlX2RpcmVjdCggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHRidWZmZXJbIG9mZnNldCBdID0gdGhpcy50YXJnZXRPYmplY3RbIHRoaXMucHJvcGVydHlOYW1lIF07XG5cblx0fVxuXG5cdF9nZXRWYWx1ZV9hcnJheSggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHRjb25zdCBzb3VyY2UgPSB0aGlzLnJlc29sdmVkUHJvcGVydHk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBzb3VyY2UubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRidWZmZXJbIG9mZnNldCArKyBdID0gc291cmNlWyBpIF07XG5cblx0XHR9XG5cblx0fVxuXG5cdF9nZXRWYWx1ZV9hcnJheUVsZW1lbnQoIGJ1ZmZlciwgb2Zmc2V0ICkge1xuXG5cdFx0YnVmZmVyWyBvZmZzZXQgXSA9IHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF07XG5cblx0fVxuXG5cdF9nZXRWYWx1ZV90b0FycmF5KCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eS50b0FycmF5KCBidWZmZXIsIG9mZnNldCApO1xuXG5cdH1cblxuXHQvLyBEaXJlY3RcblxuXHRfc2V0VmFsdWVfZGlyZWN0KCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMudGFyZ2V0T2JqZWN0WyB0aGlzLnByb3BlcnR5TmFtZSBdID0gYnVmZmVyWyBvZmZzZXQgXTtcblxuXHR9XG5cblx0X3NldFZhbHVlX2RpcmVjdF9zZXROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHR0aGlzLnRhcmdldE9iamVjdFsgdGhpcy5wcm9wZXJ0eU5hbWUgXSA9IGJ1ZmZlclsgb2Zmc2V0IF07XG5cdFx0dGhpcy50YXJnZXRPYmplY3QubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxuXHRfc2V0VmFsdWVfZGlyZWN0X3NldE1hdHJpeFdvcmxkTmVlZHNVcGRhdGUoIGJ1ZmZlciwgb2Zmc2V0ICkge1xuXG5cdFx0dGhpcy50YXJnZXRPYmplY3RbIHRoaXMucHJvcGVydHlOYW1lIF0gPSBidWZmZXJbIG9mZnNldCBdO1xuXHRcdHRoaXMudGFyZ2V0T2JqZWN0Lm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxuXHQvLyBFbnRpcmVBcnJheVxuXG5cdF9zZXRWYWx1ZV9hcnJheSggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHRjb25zdCBkZXN0ID0gdGhpcy5yZXNvbHZlZFByb3BlcnR5O1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gZGVzdC5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdGRlc3RbIGkgXSA9IGJ1ZmZlclsgb2Zmc2V0ICsrIF07XG5cblx0XHR9XG5cblx0fVxuXG5cdF9zZXRWYWx1ZV9hcnJheV9zZXROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHRjb25zdCBkZXN0ID0gdGhpcy5yZXNvbHZlZFByb3BlcnR5O1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gZGVzdC5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdGRlc3RbIGkgXSA9IGJ1ZmZlclsgb2Zmc2V0ICsrIF07XG5cblx0XHR9XG5cblx0XHR0aGlzLnRhcmdldE9iamVjdC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0fVxuXG5cdF9zZXRWYWx1ZV9hcnJheV9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdGNvbnN0IGRlc3QgPSB0aGlzLnJlc29sdmVkUHJvcGVydHk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBkZXN0Lmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0ZGVzdFsgaSBdID0gYnVmZmVyWyBvZmZzZXQgKysgXTtcblxuXHRcdH1cblxuXHRcdHRoaXMudGFyZ2V0T2JqZWN0Lm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxuXHQvLyBBcnJheUVsZW1lbnRcblxuXHRfc2V0VmFsdWVfYXJyYXlFbGVtZW50KCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF0gPSBidWZmZXJbIG9mZnNldCBdO1xuXG5cdH1cblxuXHRfc2V0VmFsdWVfYXJyYXlFbGVtZW50X3NldE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF0gPSBidWZmZXJbIG9mZnNldCBdO1xuXHRcdHRoaXMudGFyZ2V0T2JqZWN0Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHR9XG5cblx0X3NldFZhbHVlX2FycmF5RWxlbWVudF9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF0gPSBidWZmZXJbIG9mZnNldCBdO1xuXHRcdHRoaXMudGFyZ2V0T2JqZWN0Lm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxuXHQvLyBIYXNUb0Zyb21BcnJheVxuXG5cdF9zZXRWYWx1ZV9mcm9tQXJyYXkoIGJ1ZmZlciwgb2Zmc2V0ICkge1xuXG5cdFx0dGhpcy5yZXNvbHZlZFByb3BlcnR5LmZyb21BcnJheSggYnVmZmVyLCBvZmZzZXQgKTtcblxuXHR9XG5cblx0X3NldFZhbHVlX2Zyb21BcnJheV9zZXROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkuZnJvbUFycmF5KCBidWZmZXIsIG9mZnNldCApO1xuXHRcdHRoaXMudGFyZ2V0T2JqZWN0Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHR9XG5cblx0X3NldFZhbHVlX2Zyb21BcnJheV9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eS5mcm9tQXJyYXkoIGJ1ZmZlciwgb2Zmc2V0ICk7XG5cdFx0dGhpcy50YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0fVxuXG5cdF9nZXRWYWx1ZV91bmJvdW5kKCB0YXJnZXRBcnJheSwgb2Zmc2V0ICkge1xuXG5cdFx0dGhpcy5iaW5kKCk7XG5cdFx0dGhpcy5nZXRWYWx1ZSggdGFyZ2V0QXJyYXksIG9mZnNldCApO1xuXG5cdH1cblxuXHRfc2V0VmFsdWVfdW5ib3VuZCggc291cmNlQXJyYXksIG9mZnNldCApIHtcblxuXHRcdHRoaXMuYmluZCgpO1xuXHRcdHRoaXMuc2V0VmFsdWUoIHNvdXJjZUFycmF5LCBvZmZzZXQgKTtcblxuXHR9XG5cblx0Ly8gY3JlYXRlIGdldHRlciAvIHNldHRlciBwYWlyIGZvciBhIHByb3BlcnR5IGluIHRoZSBzY2VuZSBncmFwaFxuXHRiaW5kKCkge1xuXG5cdFx0bGV0IHRhcmdldE9iamVjdCA9IHRoaXMubm9kZTtcblx0XHRjb25zdCBwYXJzZWRQYXRoID0gdGhpcy5wYXJzZWRQYXRoO1xuXG5cdFx0Y29uc3Qgb2JqZWN0TmFtZSA9IHBhcnNlZFBhdGgub2JqZWN0TmFtZTtcblx0XHRjb25zdCBwcm9wZXJ0eU5hbWUgPSBwYXJzZWRQYXRoLnByb3BlcnR5TmFtZTtcblx0XHRsZXQgcHJvcGVydHlJbmRleCA9IHBhcnNlZFBhdGgucHJvcGVydHlJbmRleDtcblxuXHRcdGlmICggISB0YXJnZXRPYmplY3QgKSB7XG5cblx0XHRcdHRhcmdldE9iamVjdCA9IFByb3BlcnR5QmluZGluZy5maW5kTm9kZSggdGhpcy5yb290Tm9kZSwgcGFyc2VkUGF0aC5ub2RlTmFtZSApO1xuXG5cdFx0XHR0aGlzLm5vZGUgPSB0YXJnZXRPYmplY3Q7XG5cblx0XHR9XG5cblx0XHQvLyBzZXQgZmFpbCBzdGF0ZSBzbyB3ZSBjYW4ganVzdCAncmV0dXJuJyBvbiBlcnJvclxuXHRcdHRoaXMuZ2V0VmFsdWUgPSB0aGlzLl9nZXRWYWx1ZV91bmF2YWlsYWJsZTtcblx0XHR0aGlzLnNldFZhbHVlID0gdGhpcy5fc2V0VmFsdWVfdW5hdmFpbGFibGU7XG5cblx0XHQvLyBlbnN1cmUgdGhlcmUgaXMgYSB2YWx1ZSBub2RlXG5cdFx0aWYgKCAhIHRhcmdldE9iamVjdCApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBObyB0YXJnZXQgbm9kZSBmb3VuZCBmb3IgdHJhY2s6ICcgKyB0aGlzLnBhdGggKyAnLicgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdGlmICggb2JqZWN0TmFtZSApIHtcblxuXHRcdFx0bGV0IG9iamVjdEluZGV4ID0gcGFyc2VkUGF0aC5vYmplY3RJbmRleDtcblxuXHRcdFx0Ly8gc3BlY2lhbCBjYXNlcyB3ZXJlIHdlIG5lZWQgdG8gcmVhY2ggZGVlcGVyIGludG8gdGhlIGhpZXJhcmNoeSB0byBnZXQgdGhlIGZhY2UgbWF0ZXJpYWxzLi4uLlxuXHRcdFx0c3dpdGNoICggb2JqZWN0TmFtZSApIHtcblxuXHRcdFx0XHRjYXNlICdtYXRlcmlhbHMnOlxuXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5tYXRlcmlhbCApIHtcblxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogQ2FuIG5vdCBiaW5kIHRvIG1hdGVyaWFsIGFzIG5vZGUgZG9lcyBub3QgaGF2ZSBhIG1hdGVyaWFsLicsIHRoaXMgKTtcblx0XHRcdFx0XHRcdHJldHVybjtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggISB0YXJnZXRPYmplY3QubWF0ZXJpYWwubWF0ZXJpYWxzICkge1xuXG5cdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbWF0ZXJpYWwubWF0ZXJpYWxzIGFzIG5vZGUubWF0ZXJpYWwgZG9lcyBub3QgaGF2ZSBhIG1hdGVyaWFscyBhcnJheS4nLCB0aGlzICk7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3QubWF0ZXJpYWwubWF0ZXJpYWxzO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAnYm9uZXMnOlxuXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5za2VsZXRvbiApIHtcblxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogQ2FuIG5vdCBiaW5kIHRvIGJvbmVzIGFzIG5vZGUgZG9lcyBub3QgaGF2ZSBhIHNrZWxldG9uLicsIHRoaXMgKTtcblx0XHRcdFx0XHRcdHJldHVybjtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIHBvdGVudGlhbCBmdXR1cmUgb3B0aW1pemF0aW9uOiBza2lwIHRoaXMgaWYgcHJvcGVydHlJbmRleCBpcyBhbHJlYWR5IGFuIGludGVnZXJcblx0XHRcdFx0XHQvLyBhbmQgY29udmVydCB0aGUgaW50ZWdlciBzdHJpbmcgdG8gYSB0cnVlIGludGVnZXIuXG5cblx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3Quc2tlbGV0b24uYm9uZXM7XG5cblx0XHRcdFx0XHQvLyBzdXBwb3J0IHJlc29sdmluZyBtb3JwaFRhcmdldCBuYW1lcyBpbnRvIGluZGljZXMuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGFyZ2V0T2JqZWN0Lmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0aWYgKCB0YXJnZXRPYmplY3RbIGkgXS5uYW1lID09PSBvYmplY3RJbmRleCApIHtcblxuXHRcdFx0XHRcdFx0XHRvYmplY3RJbmRleCA9IGk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlICdtYXAnOlxuXG5cdFx0XHRcdFx0aWYgKCAnbWFwJyBpbiB0YXJnZXRPYmplY3QgKSB7XG5cblx0XHRcdFx0XHRcdHRhcmdldE9iamVjdCA9IHRhcmdldE9iamVjdC5tYXA7XG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggISB0YXJnZXRPYmplY3QubWF0ZXJpYWwgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IENhbiBub3QgYmluZCB0byBtYXRlcmlhbCBhcyBub2RlIGRvZXMgbm90IGhhdmUgYSBtYXRlcmlhbC4nLCB0aGlzICk7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoICEgdGFyZ2V0T2JqZWN0Lm1hdGVyaWFsLm1hcCApIHtcblxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogQ2FuIG5vdCBiaW5kIHRvIG1hdGVyaWFsLm1hcCBhcyBub2RlLm1hdGVyaWFsIGRvZXMgbm90IGhhdmUgYSBtYXAuJywgdGhpcyApO1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0dGFyZ2V0T2JqZWN0ID0gdGFyZ2V0T2JqZWN0Lm1hdGVyaWFsLm1hcDtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRkZWZhdWx0OlxuXG5cdFx0XHRcdFx0aWYgKCB0YXJnZXRPYmplY3RbIG9iamVjdE5hbWUgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gb2JqZWN0TmFtZSBvZiBub2RlIHVuZGVmaW5lZC4nLCB0aGlzICk7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3RbIG9iamVjdE5hbWUgXTtcblxuXHRcdFx0fVxuXG5cblx0XHRcdGlmICggb2JqZWN0SW5kZXggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRpZiAoIHRhcmdldE9iamVjdFsgb2JqZWN0SW5kZXggXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogVHJ5aW5nIHRvIGJpbmQgdG8gb2JqZWN0SW5kZXggb2Ygb2JqZWN0TmFtZSwgYnV0IGlzIHVuZGVmaW5lZC4nLCB0aGlzLCB0YXJnZXRPYmplY3QgKTtcblx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRhcmdldE9iamVjdCA9IHRhcmdldE9iamVjdFsgb2JqZWN0SW5kZXggXTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gcmVzb2x2ZSBwcm9wZXJ0eVxuXHRcdGNvbnN0IG5vZGVQcm9wZXJ0eSA9IHRhcmdldE9iamVjdFsgcHJvcGVydHlOYW1lIF07XG5cblx0XHRpZiAoIG5vZGVQcm9wZXJ0eSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjb25zdCBub2RlTmFtZSA9IHBhcnNlZFBhdGgubm9kZU5hbWU7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IFRyeWluZyB0byB1cGRhdGUgcHJvcGVydHkgZm9yIHRyYWNrOiAnICsgbm9kZU5hbWUgK1xuXHRcdFx0XHQnLicgKyBwcm9wZXJ0eU5hbWUgKyAnIGJ1dCBpdCB3YXNuXFwndCBmb3VuZC4nLCB0YXJnZXRPYmplY3QgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdC8vIGRldGVybWluZSB2ZXJzaW9uaW5nIHNjaGVtZVxuXHRcdGxldCB2ZXJzaW9uaW5nID0gdGhpcy5WZXJzaW9uaW5nLk5vbmU7XG5cblx0XHR0aGlzLnRhcmdldE9iamVjdCA9IHRhcmdldE9iamVjdDtcblxuXHRcdGlmICggdGFyZ2V0T2JqZWN0Lm5lZWRzVXBkYXRlICE9PSB1bmRlZmluZWQgKSB7IC8vIG1hdGVyaWFsXG5cblx0XHRcdHZlcnNpb25pbmcgPSB0aGlzLlZlcnNpb25pbmcuTmVlZHNVcGRhdGU7XG5cblx0XHR9IGVsc2UgaWYgKCB0YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSAhPT0gdW5kZWZpbmVkICkgeyAvLyBub2RlIHRyYW5zZm9ybVxuXG5cdFx0XHR2ZXJzaW9uaW5nID0gdGhpcy5WZXJzaW9uaW5nLk1hdHJpeFdvcmxkTmVlZHNVcGRhdGU7XG5cblx0XHR9XG5cblx0XHQvLyBkZXRlcm1pbmUgaG93IHRoZSBwcm9wZXJ0eSBnZXRzIGJvdW5kXG5cdFx0bGV0IGJpbmRpbmdUeXBlID0gdGhpcy5CaW5kaW5nVHlwZS5EaXJlY3Q7XG5cblx0XHRpZiAoIHByb3BlcnR5SW5kZXggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Ly8gYWNjZXNzIGEgc3ViIGVsZW1lbnQgb2YgdGhlIHByb3BlcnR5IGFycmF5IChvbmx5IHByaW1pdGl2ZXMgYXJlIHN1cHBvcnRlZCByaWdodCBub3cpXG5cblx0XHRcdGlmICggcHJvcGVydHlOYW1lID09PSAnbW9ycGhUYXJnZXRJbmZsdWVuY2VzJyApIHtcblxuXHRcdFx0XHQvLyBwb3RlbnRpYWwgb3B0aW1pemF0aW9uLCBza2lwIHRoaXMgaWYgcHJvcGVydHlJbmRleCBpcyBhbHJlYWR5IGFuIGludGVnZXIsIGFuZCBjb252ZXJ0IHRoZSBpbnRlZ2VyIHN0cmluZyB0byBhIHRydWUgaW50ZWdlci5cblxuXHRcdFx0XHQvLyBzdXBwb3J0IHJlc29sdmluZyBtb3JwaFRhcmdldCBuYW1lcyBpbnRvIGluZGljZXMuXG5cdFx0XHRcdGlmICggISB0YXJnZXRPYmplY3QuZ2VvbWV0cnkgKSB7XG5cblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbW9ycGhUYXJnZXRJbmZsdWVuY2VzIGJlY2F1c2Ugbm9kZSBkb2VzIG5vdCBoYXZlIGEgZ2VvbWV0cnkuJywgdGhpcyApO1xuXHRcdFx0XHRcdHJldHVybjtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5nZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbW9ycGhUYXJnZXRJbmZsdWVuY2VzIGJlY2F1c2Ugbm9kZSBkb2VzIG5vdCBoYXZlIGEgZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLicsIHRoaXMgKTtcblx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggdGFyZ2V0T2JqZWN0Lm1vcnBoVGFyZ2V0RGljdGlvbmFyeVsgcHJvcGVydHlJbmRleCBdICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRwcm9wZXJ0eUluZGV4ID0gdGFyZ2V0T2JqZWN0Lm1vcnBoVGFyZ2V0RGljdGlvbmFyeVsgcHJvcGVydHlJbmRleCBdO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRiaW5kaW5nVHlwZSA9IHRoaXMuQmluZGluZ1R5cGUuQXJyYXlFbGVtZW50O1xuXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XG5cdFx0XHR0aGlzLnByb3BlcnR5SW5kZXggPSBwcm9wZXJ0eUluZGV4O1xuXG5cdFx0fSBlbHNlIGlmICggbm9kZVByb3BlcnR5LmZyb21BcnJheSAhPT0gdW5kZWZpbmVkICYmIG5vZGVQcm9wZXJ0eS50b0FycmF5ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdC8vIG11c3QgdXNlIGNvcHkgZm9yIE9iamVjdDNELkV1bGVyL1F1YXRlcm5pb25cblxuXHRcdFx0YmluZGluZ1R5cGUgPSB0aGlzLkJpbmRpbmdUeXBlLkhhc0Zyb21Ub0FycmF5O1xuXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XG5cblx0XHR9IGVsc2UgaWYgKCBBcnJheS5pc0FycmF5KCBub2RlUHJvcGVydHkgKSApIHtcblxuXHRcdFx0YmluZGluZ1R5cGUgPSB0aGlzLkJpbmRpbmdUeXBlLkVudGlyZUFycmF5O1xuXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLnByb3BlcnR5TmFtZSA9IHByb3BlcnR5TmFtZTtcblxuXHRcdH1cblxuXHRcdC8vIHNlbGVjdCBnZXR0ZXIgLyBzZXR0ZXJcblx0XHR0aGlzLmdldFZhbHVlID0gdGhpcy5HZXR0ZXJCeUJpbmRpbmdUeXBlWyBiaW5kaW5nVHlwZSBdO1xuXHRcdHRoaXMuc2V0VmFsdWUgPSB0aGlzLlNldHRlckJ5QmluZGluZ1R5cGVBbmRWZXJzaW9uaW5nWyBiaW5kaW5nVHlwZSBdWyB2ZXJzaW9uaW5nIF07XG5cblx0fVxuXG5cdHVuYmluZCgpIHtcblxuXHRcdHRoaXMubm9kZSA9IG51bGw7XG5cblx0XHQvLyBiYWNrIHRvIHRoZSBwcm90b3R5cGUgdmVyc2lvbiBvZiBnZXRWYWx1ZSAvIHNldFZhbHVlXG5cdFx0Ly8gbm90ZTogYXZvaWRpbmcgdG8gbXV0YXRlIHRoZSBzaGFwZSBvZiAndGhpcycgdmlhICdkZWxldGUnXG5cdFx0dGhpcy5nZXRWYWx1ZSA9IHRoaXMuX2dldFZhbHVlX3VuYm91bmQ7XG5cdFx0dGhpcy5zZXRWYWx1ZSA9IHRoaXMuX3NldFZhbHVlX3VuYm91bmQ7XG5cblx0fVxuXG59XG5cblByb3BlcnR5QmluZGluZy5Db21wb3NpdGUgPSBDb21wb3NpdGU7XG5cblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuQmluZGluZ1R5cGUgPSB7XG5cdERpcmVjdDogMCxcblx0RW50aXJlQXJyYXk6IDEsXG5cdEFycmF5RWxlbWVudDogMixcblx0SGFzRnJvbVRvQXJyYXk6IDNcbn07XG5cblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuVmVyc2lvbmluZyA9IHtcblx0Tm9uZTogMCxcblx0TmVlZHNVcGRhdGU6IDEsXG5cdE1hdHJpeFdvcmxkTmVlZHNVcGRhdGU6IDJcbn07XG5cblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuR2V0dGVyQnlCaW5kaW5nVHlwZSA9IFtcblxuXHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9nZXRWYWx1ZV9kaXJlY3QsXG5cdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX2dldFZhbHVlX2FycmF5LFxuXHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9nZXRWYWx1ZV9hcnJheUVsZW1lbnQsXG5cdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX2dldFZhbHVlX3RvQXJyYXksXG5cbl07XG5cblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuU2V0dGVyQnlCaW5kaW5nVHlwZUFuZFZlcnNpb25pbmcgPSBbXG5cblx0W1xuXHRcdC8vIERpcmVjdFxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2RpcmVjdCxcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9kaXJlY3Rfc2V0TmVlZHNVcGRhdGUsXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfZGlyZWN0X3NldE1hdHJpeFdvcmxkTmVlZHNVcGRhdGUsXG5cblx0XSwgW1xuXG5cdFx0Ly8gRW50aXJlQXJyYXlcblxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2FycmF5LFxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2FycmF5X3NldE5lZWRzVXBkYXRlLFxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2FycmF5X3NldE1hdHJpeFdvcmxkTmVlZHNVcGRhdGUsXG5cblx0XSwgW1xuXG5cdFx0Ly8gQXJyYXlFbGVtZW50XG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfYXJyYXlFbGVtZW50LFxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2FycmF5RWxlbWVudF9zZXROZWVkc1VwZGF0ZSxcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9hcnJheUVsZW1lbnRfc2V0TWF0cml4V29ybGROZWVkc1VwZGF0ZSxcblxuXHRdLCBbXG5cblx0XHQvLyBIYXNUb0Zyb21BcnJheVxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2Zyb21BcnJheSxcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9mcm9tQXJyYXlfc2V0TmVlZHNVcGRhdGUsXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfZnJvbUFycmF5X3NldE1hdHJpeFdvcmxkTmVlZHNVcGRhdGUsXG5cblx0XVxuXG5dO1xuXG4vKipcbiAqXG4gKiBBIGdyb3VwIG9mIG9iamVjdHMgdGhhdCByZWNlaXZlcyBhIHNoYXJlZCBhbmltYXRpb24gc3RhdGUuXG4gKlxuICogVXNhZ2U6XG4gKlxuICogIC0gQWRkIG9iamVjdHMgeW91IHdvdWxkIG90aGVyd2lzZSBwYXNzIGFzICdyb290JyB0byB0aGVcbiAqICAgIGNvbnN0cnVjdG9yIG9yIHRoZSAuY2xpcEFjdGlvbiBtZXRob2Qgb2YgQW5pbWF0aW9uTWl4ZXIuXG4gKlxuICogIC0gSW5zdGVhZCBwYXNzIHRoaXMgb2JqZWN0IGFzICdyb290Jy5cbiAqXG4gKiAgLSBZb3UgY2FuIGFsc28gYWRkIGFuZCByZW1vdmUgb2JqZWN0cyBsYXRlciB3aGVuIHRoZSBtaXhlclxuICogICAgaXMgcnVubmluZy5cbiAqXG4gKiBOb3RlOlxuICpcbiAqICAgIE9iamVjdHMgb2YgdGhpcyBjbGFzcyBhcHBlYXIgYXMgb25lIG9iamVjdCB0byB0aGUgbWl4ZXIsXG4gKiAgICBzbyBjYWNoZSBjb250cm9sIG9mIHRoZSBpbmRpdmlkdWFsIG9iamVjdHMgbXVzdCBiZSBkb25lXG4gKiAgICBvbiB0aGUgZ3JvdXAuXG4gKlxuICogTGltaXRhdGlvbjpcbiAqXG4gKiAgLSBUaGUgYW5pbWF0ZWQgcHJvcGVydGllcyBtdXN0IGJlIGNvbXBhdGlibGUgYW1vbmcgdGhlXG4gKiAgICBhbGwgb2JqZWN0cyBpbiB0aGUgZ3JvdXAuXG4gKlxuICogIC0gQSBzaW5nbGUgcHJvcGVydHkgY2FuIGVpdGhlciBiZSBjb250cm9sbGVkIHRocm91Z2ggYVxuICogICAgdGFyZ2V0IGdyb3VwIG9yIGRpcmVjdGx5LCBidXQgbm90IGJvdGguXG4gKi9cblxuY2xhc3MgQW5pbWF0aW9uT2JqZWN0R3JvdXAge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0dGhpcy5pc0FuaW1hdGlvbk9iamVjdEdyb3VwID0gdHJ1ZTtcblxuXHRcdHRoaXMudXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0Ly8gY2FjaGVkIG9iamVjdHMgZm9sbG93ZWQgYnkgdGhlIGFjdGl2ZSBvbmVzXG5cdFx0dGhpcy5fb2JqZWN0cyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKCBhcmd1bWVudHMgKTtcblxuXHRcdHRoaXMubkNhY2hlZE9iamVjdHNfID0gMDsgLy8gdGhyZXNob2xkXG5cdFx0Ly8gbm90ZTogcmVhZCBieSBQcm9wZXJ0eUJpbmRpbmcuQ29tcG9zaXRlXG5cblx0XHRjb25zdCBpbmRpY2VzID0ge307XG5cdFx0dGhpcy5faW5kaWNlc0J5VVVJRCA9IGluZGljZXM7IC8vIGZvciBib29ra2VlcGluZ1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gYXJndW1lbnRzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0aW5kaWNlc1sgYXJndW1lbnRzWyBpIF0udXVpZCBdID0gaTtcblxuXHRcdH1cblxuXHRcdHRoaXMuX3BhdGhzID0gW107IC8vIGluc2lkZTogc3RyaW5nXG5cdFx0dGhpcy5fcGFyc2VkUGF0aHMgPSBbXTsgLy8gaW5zaWRlOiB7IHdlIGRvbid0IGNhcmUsIGhlcmUgfVxuXHRcdHRoaXMuX2JpbmRpbmdzID0gW107IC8vIGluc2lkZTogQXJyYXk8IFByb3BlcnR5QmluZGluZyA+XG5cdFx0dGhpcy5fYmluZGluZ3NJbmRpY2VzQnlQYXRoID0ge307IC8vIGluc2lkZTogaW5kaWNlcyBpbiB0aGVzZSBhcnJheXNcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdHRoaXMuc3RhdHMgPSB7XG5cblx0XHRcdG9iamVjdHM6IHtcblx0XHRcdFx0Z2V0IHRvdGFsKCkge1xuXG5cdFx0XHRcdFx0cmV0dXJuIHNjb3BlLl9vYmplY3RzLmxlbmd0aDtcblxuXHRcdFx0XHR9LFxuXHRcdFx0XHRnZXQgaW5Vc2UoKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gdGhpcy50b3RhbCAtIHNjb3BlLm5DYWNoZWRPYmplY3RzXztcblxuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0Z2V0IGJpbmRpbmdzUGVyT2JqZWN0KCkge1xuXG5cdFx0XHRcdHJldHVybiBzY29wZS5fYmluZGluZ3MubGVuZ3RoO1xuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdH1cblxuXHRhZGQoKSB7XG5cblx0XHRjb25zdCBvYmplY3RzID0gdGhpcy5fb2JqZWN0cyxcblx0XHRcdGluZGljZXNCeVVVSUQgPSB0aGlzLl9pbmRpY2VzQnlVVUlELFxuXHRcdFx0cGF0aHMgPSB0aGlzLl9wYXRocyxcblx0XHRcdHBhcnNlZFBhdGhzID0gdGhpcy5fcGFyc2VkUGF0aHMsXG5cdFx0XHRiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxuXHRcdFx0bkJpbmRpbmdzID0gYmluZGluZ3MubGVuZ3RoO1xuXG5cdFx0bGV0IGtub3duT2JqZWN0ID0gdW5kZWZpbmVkLFxuXHRcdFx0bk9iamVjdHMgPSBvYmplY3RzLmxlbmd0aCxcblx0XHRcdG5DYWNoZWRPYmplY3RzID0gdGhpcy5uQ2FjaGVkT2JqZWN0c187XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCBvYmplY3QgPSBhcmd1bWVudHNbIGkgXSxcblx0XHRcdFx0dXVpZCA9IG9iamVjdC51dWlkO1xuXHRcdFx0bGV0IGluZGV4ID0gaW5kaWNlc0J5VVVJRFsgdXVpZCBdO1xuXG5cdFx0XHRpZiAoIGluZGV4ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Ly8gdW5rbm93biBvYmplY3QgLT4gYWRkIGl0IHRvIHRoZSBBQ1RJVkUgcmVnaW9uXG5cblx0XHRcdFx0aW5kZXggPSBuT2JqZWN0cyArKztcblx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgdXVpZCBdID0gaW5kZXg7XG5cdFx0XHRcdG9iamVjdHMucHVzaCggb2JqZWN0ICk7XG5cblx0XHRcdFx0Ly8gYWNjb3VudGluZyBpcyBkb25lLCBub3cgZG8gdGhlIHNhbWUgZm9yIGFsbCBiaW5kaW5nc1xuXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMCwgbSA9IG5CaW5kaW5nczsgaiAhPT0gbTsgKysgaiApIHtcblxuXHRcdFx0XHRcdGJpbmRpbmdzWyBqIF0ucHVzaCggbmV3IFByb3BlcnR5QmluZGluZyggb2JqZWN0LCBwYXRoc1sgaiBdLCBwYXJzZWRQYXRoc1sgaiBdICkgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSBpZiAoIGluZGV4IDwgbkNhY2hlZE9iamVjdHMgKSB7XG5cblx0XHRcdFx0a25vd25PYmplY3QgPSBvYmplY3RzWyBpbmRleCBdO1xuXG5cdFx0XHRcdC8vIG1vdmUgZXhpc3Rpbmcgb2JqZWN0IHRvIHRoZSBBQ1RJVkUgcmVnaW9uXG5cblx0XHRcdFx0Y29uc3QgZmlyc3RBY3RpdmVJbmRleCA9IC0tIG5DYWNoZWRPYmplY3RzLFxuXHRcdFx0XHRcdGxhc3RDYWNoZWRPYmplY3QgPSBvYmplY3RzWyBmaXJzdEFjdGl2ZUluZGV4IF07XG5cblx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgbGFzdENhY2hlZE9iamVjdC51dWlkIF0gPSBpbmRleDtcblx0XHRcdFx0b2JqZWN0c1sgaW5kZXggXSA9IGxhc3RDYWNoZWRPYmplY3Q7XG5cblx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgdXVpZCBdID0gZmlyc3RBY3RpdmVJbmRleDtcblx0XHRcdFx0b2JqZWN0c1sgZmlyc3RBY3RpdmVJbmRleCBdID0gb2JqZWN0O1xuXG5cdFx0XHRcdC8vIGFjY291bnRpbmcgaXMgZG9uZSwgbm93IGRvIHRoZSBzYW1lIGZvciBhbGwgYmluZGluZ3NcblxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBuQmluZGluZ3M7IGogIT09IG07ICsrIGogKSB7XG5cblx0XHRcdFx0XHRjb25zdCBiaW5kaW5nc0ZvclBhdGggPSBiaW5kaW5nc1sgaiBdLFxuXHRcdFx0XHRcdFx0bGFzdENhY2hlZCA9IGJpbmRpbmdzRm9yUGF0aFsgZmlyc3RBY3RpdmVJbmRleCBdO1xuXG5cdFx0XHRcdFx0bGV0IGJpbmRpbmcgPSBiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF07XG5cblx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF0gPSBsYXN0Q2FjaGVkO1xuXG5cdFx0XHRcdFx0aWYgKCBiaW5kaW5nID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRcdC8vIHNpbmNlIHdlIGRvIG5vdCBib3RoZXIgdG8gY3JlYXRlIG5ldyBiaW5kaW5nc1xuXHRcdFx0XHRcdFx0Ly8gZm9yIG9iamVjdHMgdGhhdCBhcmUgY2FjaGVkLCB0aGUgYmluZGluZyBtYXlcblx0XHRcdFx0XHRcdC8vIG9yIG1heSBub3QgZXhpc3RcblxuXHRcdFx0XHRcdFx0YmluZGluZyA9IG5ldyBQcm9wZXJ0eUJpbmRpbmcoIG9iamVjdCwgcGF0aHNbIGogXSwgcGFyc2VkUGF0aHNbIGogXSApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoWyBmaXJzdEFjdGl2ZUluZGV4IF0gPSBiaW5kaW5nO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIGlmICggb2JqZWN0c1sgaW5kZXggXSAhPT0ga25vd25PYmplY3QgKSB7XG5cblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLkFuaW1hdGlvbk9iamVjdEdyb3VwOiBEaWZmZXJlbnQgb2JqZWN0cyB3aXRoIHRoZSBzYW1lIFVVSUQgJyArXG5cdFx0XHRcdFx0J2RldGVjdGVkLiBDbGVhbiB0aGUgY2FjaGVzIG9yIHJlY3JlYXRlIHlvdXIgaW5mcmFzdHJ1Y3R1cmUgd2hlbiByZWxvYWRpbmcgc2NlbmVzLicgKTtcblxuXHRcdFx0fSAvLyBlbHNlIHRoZSBvYmplY3QgaXMgYWxyZWFkeSB3aGVyZSB3ZSB3YW50IGl0IHRvIGJlXG5cblx0XHR9IC8vIGZvciBhcmd1bWVudHNcblxuXHRcdHRoaXMubkNhY2hlZE9iamVjdHNfID0gbkNhY2hlZE9iamVjdHM7XG5cblx0fVxuXG5cdHJlbW92ZSgpIHtcblxuXHRcdGNvbnN0IG9iamVjdHMgPSB0aGlzLl9vYmplY3RzLFxuXHRcdFx0aW5kaWNlc0J5VVVJRCA9IHRoaXMuX2luZGljZXNCeVVVSUQsXG5cdFx0XHRiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxuXHRcdFx0bkJpbmRpbmdzID0gYmluZGluZ3MubGVuZ3RoO1xuXG5cdFx0bGV0IG5DYWNoZWRPYmplY3RzID0gdGhpcy5uQ2FjaGVkT2JqZWN0c187XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCBvYmplY3QgPSBhcmd1bWVudHNbIGkgXSxcblx0XHRcdFx0dXVpZCA9IG9iamVjdC51dWlkLFxuXHRcdFx0XHRpbmRleCA9IGluZGljZXNCeVVVSURbIHV1aWQgXTtcblxuXHRcdFx0aWYgKCBpbmRleCAhPT0gdW5kZWZpbmVkICYmIGluZGV4ID49IG5DYWNoZWRPYmplY3RzICkge1xuXG5cdFx0XHRcdC8vIG1vdmUgZXhpc3Rpbmcgb2JqZWN0IGludG8gdGhlIENBQ0hFRCByZWdpb25cblxuXHRcdFx0XHRjb25zdCBsYXN0Q2FjaGVkSW5kZXggPSBuQ2FjaGVkT2JqZWN0cyArKyxcblx0XHRcdFx0XHRmaXJzdEFjdGl2ZU9iamVjdCA9IG9iamVjdHNbIGxhc3RDYWNoZWRJbmRleCBdO1xuXG5cdFx0XHRcdGluZGljZXNCeVVVSURbIGZpcnN0QWN0aXZlT2JqZWN0LnV1aWQgXSA9IGluZGV4O1xuXHRcdFx0XHRvYmplY3RzWyBpbmRleCBdID0gZmlyc3RBY3RpdmVPYmplY3Q7XG5cblx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgdXVpZCBdID0gbGFzdENhY2hlZEluZGV4O1xuXHRcdFx0XHRvYmplY3RzWyBsYXN0Q2FjaGVkSW5kZXggXSA9IG9iamVjdDtcblxuXHRcdFx0XHQvLyBhY2NvdW50aW5nIGlzIGRvbmUsIG5vdyBkbyB0aGUgc2FtZSBmb3IgYWxsIGJpbmRpbmdzXG5cblx0XHRcdFx0Zm9yICggbGV0IGogPSAwLCBtID0gbkJpbmRpbmdzOyBqICE9PSBtOyArKyBqICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgYmluZGluZ3NGb3JQYXRoID0gYmluZGluZ3NbIGogXSxcblx0XHRcdFx0XHRcdGZpcnN0QWN0aXZlID0gYmluZGluZ3NGb3JQYXRoWyBsYXN0Q2FjaGVkSW5kZXggXSxcblx0XHRcdFx0XHRcdGJpbmRpbmcgPSBiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF07XG5cblx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF0gPSBmaXJzdEFjdGl2ZTtcblx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGhbIGxhc3RDYWNoZWRJbmRleCBdID0gYmluZGluZztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH0gLy8gZm9yIGFyZ3VtZW50c1xuXG5cdFx0dGhpcy5uQ2FjaGVkT2JqZWN0c18gPSBuQ2FjaGVkT2JqZWN0cztcblxuXHR9XG5cblx0Ly8gcmVtb3ZlICYgZm9yZ2V0XG5cdHVuY2FjaGUoKSB7XG5cblx0XHRjb25zdCBvYmplY3RzID0gdGhpcy5fb2JqZWN0cyxcblx0XHRcdGluZGljZXNCeVVVSUQgPSB0aGlzLl9pbmRpY2VzQnlVVUlELFxuXHRcdFx0YmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcblx0XHRcdG5CaW5kaW5ncyA9IGJpbmRpbmdzLmxlbmd0aDtcblxuXHRcdGxldCBuQ2FjaGVkT2JqZWN0cyA9IHRoaXMubkNhY2hlZE9iamVjdHNfLFxuXHRcdFx0bk9iamVjdHMgPSBvYmplY3RzLmxlbmd0aDtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdGNvbnN0IG9iamVjdCA9IGFyZ3VtZW50c1sgaSBdLFxuXHRcdFx0XHR1dWlkID0gb2JqZWN0LnV1aWQsXG5cdFx0XHRcdGluZGV4ID0gaW5kaWNlc0J5VVVJRFsgdXVpZCBdO1xuXG5cdFx0XHRpZiAoIGluZGV4ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0ZGVsZXRlIGluZGljZXNCeVVVSURbIHV1aWQgXTtcblxuXHRcdFx0XHRpZiAoIGluZGV4IDwgbkNhY2hlZE9iamVjdHMgKSB7XG5cblx0XHRcdFx0XHQvLyBvYmplY3QgaXMgY2FjaGVkLCBzaHJpbmsgdGhlIENBQ0hFRCByZWdpb25cblxuXHRcdFx0XHRcdGNvbnN0IGZpcnN0QWN0aXZlSW5kZXggPSAtLSBuQ2FjaGVkT2JqZWN0cyxcblx0XHRcdFx0XHRcdGxhc3RDYWNoZWRPYmplY3QgPSBvYmplY3RzWyBmaXJzdEFjdGl2ZUluZGV4IF0sXG5cdFx0XHRcdFx0XHRsYXN0SW5kZXggPSAtLSBuT2JqZWN0cyxcblx0XHRcdFx0XHRcdGxhc3RPYmplY3QgPSBvYmplY3RzWyBsYXN0SW5kZXggXTtcblxuXHRcdFx0XHRcdC8vIGxhc3QgY2FjaGVkIG9iamVjdCB0YWtlcyB0aGlzIG9iamVjdCdzIHBsYWNlXG5cdFx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgbGFzdENhY2hlZE9iamVjdC51dWlkIF0gPSBpbmRleDtcblx0XHRcdFx0XHRvYmplY3RzWyBpbmRleCBdID0gbGFzdENhY2hlZE9iamVjdDtcblxuXHRcdFx0XHRcdC8vIGxhc3Qgb2JqZWN0IGdvZXMgdG8gdGhlIGFjdGl2YXRlZCBzbG90IGFuZCBwb3Bcblx0XHRcdFx0XHRpbmRpY2VzQnlVVUlEWyBsYXN0T2JqZWN0LnV1aWQgXSA9IGZpcnN0QWN0aXZlSW5kZXg7XG5cdFx0XHRcdFx0b2JqZWN0c1sgZmlyc3RBY3RpdmVJbmRleCBdID0gbGFzdE9iamVjdDtcblx0XHRcdFx0XHRvYmplY3RzLnBvcCgpO1xuXG5cdFx0XHRcdFx0Ly8gYWNjb3VudGluZyBpcyBkb25lLCBub3cgZG8gdGhlIHNhbWUgZm9yIGFsbCBiaW5kaW5nc1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGogPSAwLCBtID0gbkJpbmRpbmdzOyBqICE9PSBtOyArKyBqICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBiaW5kaW5nc0ZvclBhdGggPSBiaW5kaW5nc1sgaiBdLFxuXHRcdFx0XHRcdFx0XHRsYXN0Q2FjaGVkID0gYmluZGluZ3NGb3JQYXRoWyBmaXJzdEFjdGl2ZUluZGV4IF0sXG5cdFx0XHRcdFx0XHRcdGxhc3QgPSBiaW5kaW5nc0ZvclBhdGhbIGxhc3RJbmRleCBdO1xuXG5cdFx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF0gPSBsYXN0Q2FjaGVkO1xuXHRcdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoWyBmaXJzdEFjdGl2ZUluZGV4IF0gPSBsYXN0O1xuXHRcdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoLnBvcCgpO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBvYmplY3QgaXMgYWN0aXZlLCBqdXN0IHN3YXAgd2l0aCB0aGUgbGFzdCBhbmQgcG9wXG5cblx0XHRcdFx0XHRjb25zdCBsYXN0SW5kZXggPSAtLSBuT2JqZWN0cyxcblx0XHRcdFx0XHRcdGxhc3RPYmplY3QgPSBvYmplY3RzWyBsYXN0SW5kZXggXTtcblxuXHRcdFx0XHRcdGlmICggbGFzdEluZGV4ID4gMCApIHtcblxuXHRcdFx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgbGFzdE9iamVjdC51dWlkIF0gPSBpbmRleDtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdG9iamVjdHNbIGluZGV4IF0gPSBsYXN0T2JqZWN0O1xuXHRcdFx0XHRcdG9iamVjdHMucG9wKCk7XG5cblx0XHRcdFx0XHQvLyBhY2NvdW50aW5nIGlzIGRvbmUsIG5vdyBkbyB0aGUgc2FtZSBmb3IgYWxsIGJpbmRpbmdzXG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBuQmluZGluZ3M7IGogIT09IG07ICsrIGogKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGJpbmRpbmdzRm9yUGF0aCA9IGJpbmRpbmdzWyBqIF07XG5cblx0XHRcdFx0XHRcdGJpbmRpbmdzRm9yUGF0aFsgaW5kZXggXSA9IGJpbmRpbmdzRm9yUGF0aFsgbGFzdEluZGV4IF07XG5cdFx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGgucG9wKCk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSAvLyBjYWNoZWQgb3IgYWN0aXZlXG5cblx0XHRcdH0gLy8gaWYgb2JqZWN0IGlzIGtub3duXG5cblx0XHR9IC8vIGZvciBhcmd1bWVudHNcblxuXHRcdHRoaXMubkNhY2hlZE9iamVjdHNfID0gbkNhY2hlZE9iamVjdHM7XG5cblx0fVxuXG5cdC8vIEludGVybmFsIGludGVyZmFjZSB1c2VkIGJ5IGJlZnJpZW5kZWQgUHJvcGVydHlCaW5kaW5nLkNvbXBvc2l0ZTpcblxuXHRzdWJzY3JpYmVfKCBwYXRoLCBwYXJzZWRQYXRoICkge1xuXG5cdFx0Ly8gcmV0dXJucyBhbiBhcnJheSBvZiBiaW5kaW5ncyBmb3IgdGhlIGdpdmVuIHBhdGggdGhhdCBpcyBjaGFuZ2VkXG5cdFx0Ly8gYWNjb3JkaW5nIHRvIHRoZSBjb250YWluZWQgb2JqZWN0cyBpbiB0aGUgZ3JvdXBcblxuXHRcdGNvbnN0IGluZGljZXNCeVBhdGggPSB0aGlzLl9iaW5kaW5nc0luZGljZXNCeVBhdGg7XG5cdFx0bGV0IGluZGV4ID0gaW5kaWNlc0J5UGF0aFsgcGF0aCBdO1xuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3M7XG5cblx0XHRpZiAoIGluZGV4ICE9PSB1bmRlZmluZWQgKSByZXR1cm4gYmluZGluZ3NbIGluZGV4IF07XG5cblx0XHRjb25zdCBwYXRocyA9IHRoaXMuX3BhdGhzLFxuXHRcdFx0cGFyc2VkUGF0aHMgPSB0aGlzLl9wYXJzZWRQYXRocyxcblx0XHRcdG9iamVjdHMgPSB0aGlzLl9vYmplY3RzLFxuXHRcdFx0bk9iamVjdHMgPSBvYmplY3RzLmxlbmd0aCxcblx0XHRcdG5DYWNoZWRPYmplY3RzID0gdGhpcy5uQ2FjaGVkT2JqZWN0c18sXG5cdFx0XHRiaW5kaW5nc0ZvclBhdGggPSBuZXcgQXJyYXkoIG5PYmplY3RzICk7XG5cblx0XHRpbmRleCA9IGJpbmRpbmdzLmxlbmd0aDtcblxuXHRcdGluZGljZXNCeVBhdGhbIHBhdGggXSA9IGluZGV4O1xuXG5cdFx0cGF0aHMucHVzaCggcGF0aCApO1xuXHRcdHBhcnNlZFBhdGhzLnB1c2goIHBhcnNlZFBhdGggKTtcblx0XHRiaW5kaW5ncy5wdXNoKCBiaW5kaW5nc0ZvclBhdGggKTtcblxuXHRcdGZvciAoIGxldCBpID0gbkNhY2hlZE9iamVjdHMsIG4gPSBvYmplY3RzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0Y29uc3Qgb2JqZWN0ID0gb2JqZWN0c1sgaSBdO1xuXHRcdFx0YmluZGluZ3NGb3JQYXRoWyBpIF0gPSBuZXcgUHJvcGVydHlCaW5kaW5nKCBvYmplY3QsIHBhdGgsIHBhcnNlZFBhdGggKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBiaW5kaW5nc0ZvclBhdGg7XG5cblx0fVxuXG5cdHVuc3Vic2NyaWJlXyggcGF0aCApIHtcblxuXHRcdC8vIHRlbGxzIHRoZSBncm91cCB0byBmb3JnZXQgYWJvdXQgYSBwcm9wZXJ0eSBwYXRoIGFuZCBubyBsb25nZXJcblx0XHQvLyB1cGRhdGUgdGhlIGFycmF5IHByZXZpb3VzbHkgb2J0YWluZWQgd2l0aCAnc3Vic2NyaWJlXydcblxuXHRcdGNvbnN0IGluZGljZXNCeVBhdGggPSB0aGlzLl9iaW5kaW5nc0luZGljZXNCeVBhdGgsXG5cdFx0XHRpbmRleCA9IGluZGljZXNCeVBhdGhbIHBhdGggXTtcblxuXHRcdGlmICggaW5kZXggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3QgcGF0aHMgPSB0aGlzLl9wYXRocyxcblx0XHRcdFx0cGFyc2VkUGF0aHMgPSB0aGlzLl9wYXJzZWRQYXRocyxcblx0XHRcdFx0YmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcblx0XHRcdFx0bGFzdEJpbmRpbmdzSW5kZXggPSBiaW5kaW5ncy5sZW5ndGggLSAxLFxuXHRcdFx0XHRsYXN0QmluZGluZ3MgPSBiaW5kaW5nc1sgbGFzdEJpbmRpbmdzSW5kZXggXSxcblx0XHRcdFx0bGFzdEJpbmRpbmdzUGF0aCA9IHBhdGhbIGxhc3RCaW5kaW5nc0luZGV4IF07XG5cblx0XHRcdGluZGljZXNCeVBhdGhbIGxhc3RCaW5kaW5nc1BhdGggXSA9IGluZGV4O1xuXG5cdFx0XHRiaW5kaW5nc1sgaW5kZXggXSA9IGxhc3RCaW5kaW5ncztcblx0XHRcdGJpbmRpbmdzLnBvcCgpO1xuXG5cdFx0XHRwYXJzZWRQYXRoc1sgaW5kZXggXSA9IHBhcnNlZFBhdGhzWyBsYXN0QmluZGluZ3NJbmRleCBdO1xuXHRcdFx0cGFyc2VkUGF0aHMucG9wKCk7XG5cblx0XHRcdHBhdGhzWyBpbmRleCBdID0gcGF0aHNbIGxhc3RCaW5kaW5nc0luZGV4IF07XG5cdFx0XHRwYXRocy5wb3AoKTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuY2xhc3MgQW5pbWF0aW9uQWN0aW9uIHtcblxuXHRjb25zdHJ1Y3RvciggbWl4ZXIsIGNsaXAsIGxvY2FsUm9vdCA9IG51bGwsIGJsZW5kTW9kZSA9IGNsaXAuYmxlbmRNb2RlICkge1xuXG5cdFx0dGhpcy5fbWl4ZXIgPSBtaXhlcjtcblx0XHR0aGlzLl9jbGlwID0gY2xpcDtcblx0XHR0aGlzLl9sb2NhbFJvb3QgPSBsb2NhbFJvb3Q7XG5cdFx0dGhpcy5ibGVuZE1vZGUgPSBibGVuZE1vZGU7XG5cblx0XHRjb25zdCB0cmFja3MgPSBjbGlwLnRyYWNrcyxcblx0XHRcdG5UcmFja3MgPSB0cmFja3MubGVuZ3RoLFxuXHRcdFx0aW50ZXJwb2xhbnRzID0gbmV3IEFycmF5KCBuVHJhY2tzICk7XG5cblx0XHRjb25zdCBpbnRlcnBvbGFudFNldHRpbmdzID0ge1xuXHRcdFx0ZW5kaW5nU3RhcnQ6IFplcm9DdXJ2YXR1cmVFbmRpbmcsXG5cdFx0XHRlbmRpbmdFbmQ6IFplcm9DdXJ2YXR1cmVFbmRpbmdcblx0XHR9O1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuVHJhY2tzOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCBpbnRlcnBvbGFudCA9IHRyYWNrc1sgaSBdLmNyZWF0ZUludGVycG9sYW50KCBudWxsICk7XG5cdFx0XHRpbnRlcnBvbGFudHNbIGkgXSA9IGludGVycG9sYW50O1xuXHRcdFx0aW50ZXJwb2xhbnQuc2V0dGluZ3MgPSBpbnRlcnBvbGFudFNldHRpbmdzO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5faW50ZXJwb2xhbnRTZXR0aW5ncyA9IGludGVycG9sYW50U2V0dGluZ3M7XG5cblx0XHR0aGlzLl9pbnRlcnBvbGFudHMgPSBpbnRlcnBvbGFudHM7IC8vIGJvdW5kIGJ5IHRoZSBtaXhlclxuXG5cdFx0Ly8gaW5zaWRlOiBQcm9wZXJ0eU1peGVyIChtYW5hZ2VkIGJ5IHRoZSBtaXhlcilcblx0XHR0aGlzLl9wcm9wZXJ0eUJpbmRpbmdzID0gbmV3IEFycmF5KCBuVHJhY2tzICk7XG5cblx0XHR0aGlzLl9jYWNoZUluZGV4ID0gbnVsbDsgLy8gZm9yIHRoZSBtZW1vcnkgbWFuYWdlclxuXHRcdHRoaXMuX2J5Q2xpcENhY2hlSW5kZXggPSBudWxsOyAvLyBmb3IgdGhlIG1lbW9yeSBtYW5hZ2VyXG5cblx0XHR0aGlzLl90aW1lU2NhbGVJbnRlcnBvbGFudCA9IG51bGw7XG5cdFx0dGhpcy5fd2VpZ2h0SW50ZXJwb2xhbnQgPSBudWxsO1xuXG5cdFx0dGhpcy5sb29wID0gTG9vcFJlcGVhdDtcblx0XHR0aGlzLl9sb29wQ291bnQgPSAtIDE7XG5cblx0XHQvLyBnbG9iYWwgbWl4ZXIgdGltZSB3aGVuIHRoZSBhY3Rpb24gaXMgdG8gYmUgc3RhcnRlZFxuXHRcdC8vIGl0J3Mgc2V0IGJhY2sgdG8gJ251bGwnIHVwb24gc3RhcnQgb2YgdGhlIGFjdGlvblxuXHRcdHRoaXMuX3N0YXJ0VGltZSA9IG51bGw7XG5cblx0XHQvLyBzY2FsZWQgbG9jYWwgdGltZSBvZiB0aGUgYWN0aW9uXG5cdFx0Ly8gZ2V0cyBjbGFtcGVkIG9yIHdyYXBwZWQgdG8gMC4uY2xpcC5kdXJhdGlvbiBhY2NvcmRpbmcgdG8gbG9vcFxuXHRcdHRoaXMudGltZSA9IDA7XG5cblx0XHR0aGlzLnRpbWVTY2FsZSA9IDE7XG5cdFx0dGhpcy5fZWZmZWN0aXZlVGltZVNjYWxlID0gMTtcblxuXHRcdHRoaXMud2VpZ2h0ID0gMTtcblx0XHR0aGlzLl9lZmZlY3RpdmVXZWlnaHQgPSAxO1xuXG5cdFx0dGhpcy5yZXBldGl0aW9ucyA9IEluZmluaXR5OyAvLyBuby4gb2YgcmVwZXRpdGlvbnMgd2hlbiBsb29waW5nXG5cblx0XHR0aGlzLnBhdXNlZCA9IGZhbHNlOyAvLyB0cnVlIC0+IHplcm8gZWZmZWN0aXZlIHRpbWUgc2NhbGVcblx0XHR0aGlzLmVuYWJsZWQgPSB0cnVlOyAvLyBmYWxzZSAtPiB6ZXJvIGVmZmVjdGl2ZSB3ZWlnaHRcblxuXHRcdHRoaXMuY2xhbXBXaGVuRmluaXNoZWQgPSBmYWxzZTsvLyBrZWVwIGZlZWRpbmcgdGhlIGxhc3QgZnJhbWU/XG5cblx0XHR0aGlzLnplcm9TbG9wZUF0U3RhcnQgPSB0cnVlOy8vIGZvciBzbW9vdGggaW50ZXJwb2xhdGlvbiB3L28gc2VwYXJhdGVcblx0XHR0aGlzLnplcm9TbG9wZUF0RW5kID0gdHJ1ZTsvLyBjbGlwcyBmb3Igc3RhcnQsIGxvb3AgYW5kIGVuZFxuXG5cdH1cblxuXHQvLyBTdGF0ZSAmIFNjaGVkdWxpbmdcblxuXHRwbGF5KCkge1xuXG5cdFx0dGhpcy5fbWl4ZXIuX2FjdGl2YXRlQWN0aW9uKCB0aGlzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3RvcCgpIHtcblxuXHRcdHRoaXMuX21peGVyLl9kZWFjdGl2YXRlQWN0aW9uKCB0aGlzICk7XG5cblx0XHRyZXR1cm4gdGhpcy5yZXNldCgpO1xuXG5cdH1cblxuXHRyZXNldCgpIHtcblxuXHRcdHRoaXMucGF1c2VkID0gZmFsc2U7XG5cdFx0dGhpcy5lbmFibGVkID0gdHJ1ZTtcblxuXHRcdHRoaXMudGltZSA9IDA7IC8vIHJlc3RhcnQgY2xpcFxuXHRcdHRoaXMuX2xvb3BDb3VudCA9IC0gMTsvLyBmb3JnZXQgcHJldmlvdXMgbG9vcHNcblx0XHR0aGlzLl9zdGFydFRpbWUgPSBudWxsOy8vIGZvcmdldCBzY2hlZHVsaW5nXG5cblx0XHRyZXR1cm4gdGhpcy5zdG9wRmFkaW5nKCkuc3RvcFdhcnBpbmcoKTtcblxuXHR9XG5cblx0aXNSdW5uaW5nKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZW5hYmxlZCAmJiAhIHRoaXMucGF1c2VkICYmIHRoaXMudGltZVNjYWxlICE9PSAwICYmXG5cdFx0XHR0aGlzLl9zdGFydFRpbWUgPT09IG51bGwgJiYgdGhpcy5fbWl4ZXIuX2lzQWN0aXZlQWN0aW9uKCB0aGlzICk7XG5cblx0fVxuXG5cdC8vIHJldHVybiB0cnVlIHdoZW4gcGxheSBoYXMgYmVlbiBjYWxsZWRcblx0aXNTY2hlZHVsZWQoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fbWl4ZXIuX2lzQWN0aXZlQWN0aW9uKCB0aGlzICk7XG5cblx0fVxuXG5cdHN0YXJ0QXQoIHRpbWUgKSB7XG5cblx0XHR0aGlzLl9zdGFydFRpbWUgPSB0aW1lO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldExvb3AoIG1vZGUsIHJlcGV0aXRpb25zICkge1xuXG5cdFx0dGhpcy5sb29wID0gbW9kZTtcblx0XHR0aGlzLnJlcGV0aXRpb25zID0gcmVwZXRpdGlvbnM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Ly8gV2VpZ2h0XG5cblx0Ly8gc2V0IHRoZSB3ZWlnaHQgc3RvcHBpbmcgYW55IHNjaGVkdWxlZCBmYWRpbmdcblx0Ly8gYWx0aG91Z2ggLmVuYWJsZWQgPSBmYWxzZSB5aWVsZHMgYW4gZWZmZWN0aXZlIHdlaWdodCBvZiB6ZXJvLCB0aGlzXG5cdC8vIG1ldGhvZCBkb2VzICpub3QqIGNoYW5nZSAuZW5hYmxlZCwgYmVjYXVzZSBpdCB3b3VsZCBiZSBjb25mdXNpbmdcblx0c2V0RWZmZWN0aXZlV2VpZ2h0KCB3ZWlnaHQgKSB7XG5cblx0XHR0aGlzLndlaWdodCA9IHdlaWdodDtcblxuXHRcdC8vIG5vdGU6IHNhbWUgbG9naWMgYXMgd2hlbiB1cGRhdGVkIGF0IHJ1bnRpbWVcblx0XHR0aGlzLl9lZmZlY3RpdmVXZWlnaHQgPSB0aGlzLmVuYWJsZWQgPyB3ZWlnaHQgOiAwO1xuXG5cdFx0cmV0dXJuIHRoaXMuc3RvcEZhZGluZygpO1xuXG5cdH1cblxuXHQvLyByZXR1cm4gdGhlIHdlaWdodCBjb25zaWRlcmluZyBmYWRpbmcgYW5kIC5lbmFibGVkXG5cdGdldEVmZmVjdGl2ZVdlaWdodCgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9lZmZlY3RpdmVXZWlnaHQ7XG5cblx0fVxuXG5cdGZhZGVJbiggZHVyYXRpb24gKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fc2NoZWR1bGVGYWRpbmcoIGR1cmF0aW9uLCAwLCAxICk7XG5cblx0fVxuXG5cdGZhZGVPdXQoIGR1cmF0aW9uICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3NjaGVkdWxlRmFkaW5nKCBkdXJhdGlvbiwgMSwgMCApO1xuXG5cdH1cblxuXHRjcm9zc0ZhZGVGcm9tKCBmYWRlT3V0QWN0aW9uLCBkdXJhdGlvbiwgd2FycCApIHtcblxuXHRcdGZhZGVPdXRBY3Rpb24uZmFkZU91dCggZHVyYXRpb24gKTtcblx0XHR0aGlzLmZhZGVJbiggZHVyYXRpb24gKTtcblxuXHRcdGlmICggd2FycCApIHtcblxuXHRcdFx0Y29uc3QgZmFkZUluRHVyYXRpb24gPSB0aGlzLl9jbGlwLmR1cmF0aW9uLFxuXHRcdFx0XHRmYWRlT3V0RHVyYXRpb24gPSBmYWRlT3V0QWN0aW9uLl9jbGlwLmR1cmF0aW9uLFxuXG5cdFx0XHRcdHN0YXJ0RW5kUmF0aW8gPSBmYWRlT3V0RHVyYXRpb24gLyBmYWRlSW5EdXJhdGlvbixcblx0XHRcdFx0ZW5kU3RhcnRSYXRpbyA9IGZhZGVJbkR1cmF0aW9uIC8gZmFkZU91dER1cmF0aW9uO1xuXG5cdFx0XHRmYWRlT3V0QWN0aW9uLndhcnAoIDEuMCwgc3RhcnRFbmRSYXRpbywgZHVyYXRpb24gKTtcblx0XHRcdHRoaXMud2FycCggZW5kU3RhcnRSYXRpbywgMS4wLCBkdXJhdGlvbiApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNyb3NzRmFkZVRvKCBmYWRlSW5BY3Rpb24sIGR1cmF0aW9uLCB3YXJwICkge1xuXG5cdFx0cmV0dXJuIGZhZGVJbkFjdGlvbi5jcm9zc0ZhZGVGcm9tKCB0aGlzLCBkdXJhdGlvbiwgd2FycCApO1xuXG5cdH1cblxuXHRzdG9wRmFkaW5nKCkge1xuXG5cdFx0Y29uc3Qgd2VpZ2h0SW50ZXJwb2xhbnQgPSB0aGlzLl93ZWlnaHRJbnRlcnBvbGFudDtcblxuXHRcdGlmICggd2VpZ2h0SW50ZXJwb2xhbnQgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX3dlaWdodEludGVycG9sYW50ID0gbnVsbDtcblx0XHRcdHRoaXMuX21peGVyLl90YWtlQmFja0NvbnRyb2xJbnRlcnBvbGFudCggd2VpZ2h0SW50ZXJwb2xhbnQgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvLyBUaW1lIFNjYWxlIENvbnRyb2xcblxuXHQvLyBzZXQgdGhlIHRpbWUgc2NhbGUgc3RvcHBpbmcgYW55IHNjaGVkdWxlZCB3YXJwaW5nXG5cdC8vIGFsdGhvdWdoIC5wYXVzZWQgPSB0cnVlIHlpZWxkcyBhbiBlZmZlY3RpdmUgdGltZSBzY2FsZSBvZiB6ZXJvLCB0aGlzXG5cdC8vIG1ldGhvZCBkb2VzICpub3QqIGNoYW5nZSAucGF1c2VkLCBiZWNhdXNlIGl0IHdvdWxkIGJlIGNvbmZ1c2luZ1xuXHRzZXRFZmZlY3RpdmVUaW1lU2NhbGUoIHRpbWVTY2FsZSApIHtcblxuXHRcdHRoaXMudGltZVNjYWxlID0gdGltZVNjYWxlO1xuXHRcdHRoaXMuX2VmZmVjdGl2ZVRpbWVTY2FsZSA9IHRoaXMucGF1c2VkID8gMCA6IHRpbWVTY2FsZTtcblxuXHRcdHJldHVybiB0aGlzLnN0b3BXYXJwaW5nKCk7XG5cblx0fVxuXG5cdC8vIHJldHVybiB0aGUgdGltZSBzY2FsZSBjb25zaWRlcmluZyB3YXJwaW5nIGFuZCAucGF1c2VkXG5cdGdldEVmZmVjdGl2ZVRpbWVTY2FsZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9lZmZlY3RpdmVUaW1lU2NhbGU7XG5cblx0fVxuXG5cdHNldER1cmF0aW9uKCBkdXJhdGlvbiApIHtcblxuXHRcdHRoaXMudGltZVNjYWxlID0gdGhpcy5fY2xpcC5kdXJhdGlvbiAvIGR1cmF0aW9uO1xuXG5cdFx0cmV0dXJuIHRoaXMuc3RvcFdhcnBpbmcoKTtcblxuXHR9XG5cblx0c3luY1dpdGgoIGFjdGlvbiApIHtcblxuXHRcdHRoaXMudGltZSA9IGFjdGlvbi50aW1lO1xuXHRcdHRoaXMudGltZVNjYWxlID0gYWN0aW9uLnRpbWVTY2FsZTtcblxuXHRcdHJldHVybiB0aGlzLnN0b3BXYXJwaW5nKCk7XG5cblx0fVxuXG5cdGhhbHQoIGR1cmF0aW9uICkge1xuXG5cdFx0cmV0dXJuIHRoaXMud2FycCggdGhpcy5fZWZmZWN0aXZlVGltZVNjYWxlLCAwLCBkdXJhdGlvbiApO1xuXG5cdH1cblxuXHR3YXJwKCBzdGFydFRpbWVTY2FsZSwgZW5kVGltZVNjYWxlLCBkdXJhdGlvbiApIHtcblxuXHRcdGNvbnN0IG1peGVyID0gdGhpcy5fbWl4ZXIsXG5cdFx0XHRub3cgPSBtaXhlci50aW1lLFxuXHRcdFx0dGltZVNjYWxlID0gdGhpcy50aW1lU2NhbGU7XG5cblx0XHRsZXQgaW50ZXJwb2xhbnQgPSB0aGlzLl90aW1lU2NhbGVJbnRlcnBvbGFudDtcblxuXHRcdGlmICggaW50ZXJwb2xhbnQgPT09IG51bGwgKSB7XG5cblx0XHRcdGludGVycG9sYW50ID0gbWl4ZXIuX2xlbmRDb250cm9sSW50ZXJwb2xhbnQoKTtcblx0XHRcdHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50ID0gaW50ZXJwb2xhbnQ7XG5cblx0XHR9XG5cblx0XHRjb25zdCB0aW1lcyA9IGludGVycG9sYW50LnBhcmFtZXRlclBvc2l0aW9ucyxcblx0XHRcdHZhbHVlcyA9IGludGVycG9sYW50LnNhbXBsZVZhbHVlcztcblxuXHRcdHRpbWVzWyAwIF0gPSBub3c7XG5cdFx0dGltZXNbIDEgXSA9IG5vdyArIGR1cmF0aW9uO1xuXG5cdFx0dmFsdWVzWyAwIF0gPSBzdGFydFRpbWVTY2FsZSAvIHRpbWVTY2FsZTtcblx0XHR2YWx1ZXNbIDEgXSA9IGVuZFRpbWVTY2FsZSAvIHRpbWVTY2FsZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdG9wV2FycGluZygpIHtcblxuXHRcdGNvbnN0IHRpbWVTY2FsZUludGVycG9sYW50ID0gdGhpcy5fdGltZVNjYWxlSW50ZXJwb2xhbnQ7XG5cblx0XHRpZiAoIHRpbWVTY2FsZUludGVycG9sYW50ICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl90aW1lU2NhbGVJbnRlcnBvbGFudCA9IG51bGw7XG5cdFx0XHR0aGlzLl9taXhlci5fdGFrZUJhY2tDb250cm9sSW50ZXJwb2xhbnQoIHRpbWVTY2FsZUludGVycG9sYW50ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Ly8gT2JqZWN0IEFjY2Vzc29yc1xuXG5cdGdldE1peGVyKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX21peGVyO1xuXG5cdH1cblxuXHRnZXRDbGlwKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX2NsaXA7XG5cblx0fVxuXG5cdGdldFJvb3QoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fbG9jYWxSb290IHx8IHRoaXMuX21peGVyLl9yb290O1xuXG5cdH1cblxuXHQvLyBJbnRlcm5hXG5cblx0X3VwZGF0ZSggdGltZSwgZGVsdGFUaW1lLCB0aW1lRGlyZWN0aW9uLCBhY2N1SW5kZXggKSB7XG5cblx0XHQvLyBjYWxsZWQgYnkgdGhlIG1peGVyXG5cblx0XHRpZiAoICEgdGhpcy5lbmFibGVkICkge1xuXG5cdFx0XHQvLyBjYWxsIC5fdXBkYXRlV2VpZ2h0KCkgdG8gdXBkYXRlIC5fZWZmZWN0aXZlV2VpZ2h0XG5cblx0XHRcdHRoaXMuX3VwZGF0ZVdlaWdodCggdGltZSApO1xuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3Qgc3RhcnRUaW1lID0gdGhpcy5fc3RhcnRUaW1lO1xuXG5cdFx0aWYgKCBzdGFydFRpbWUgIT09IG51bGwgKSB7XG5cblx0XHRcdC8vIGNoZWNrIGZvciBzY2hlZHVsZWQgc3RhcnQgb2YgYWN0aW9uXG5cblx0XHRcdGNvbnN0IHRpbWVSdW5uaW5nID0gKCB0aW1lIC0gc3RhcnRUaW1lICkgKiB0aW1lRGlyZWN0aW9uO1xuXHRcdFx0aWYgKCB0aW1lUnVubmluZyA8IDAgfHwgdGltZURpcmVjdGlvbiA9PT0gMCApIHtcblxuXHRcdFx0XHRkZWx0YVRpbWUgPSAwO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cblx0XHRcdFx0dGhpcy5fc3RhcnRUaW1lID0gbnVsbDsgLy8gdW5zY2hlZHVsZVxuXHRcdFx0XHRkZWx0YVRpbWUgPSB0aW1lRGlyZWN0aW9uICogdGltZVJ1bm5pbmc7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGFwcGx5IHRpbWUgc2NhbGUgYW5kIGFkdmFuY2UgdGltZVxuXG5cdFx0ZGVsdGFUaW1lICo9IHRoaXMuX3VwZGF0ZVRpbWVTY2FsZSggdGltZSApO1xuXHRcdGNvbnN0IGNsaXBUaW1lID0gdGhpcy5fdXBkYXRlVGltZSggZGVsdGFUaW1lICk7XG5cblx0XHQvLyBub3RlOiBfdXBkYXRlVGltZSBtYXkgZGlzYWJsZSB0aGUgYWN0aW9uIHJlc3VsdGluZyBpblxuXHRcdC8vIGFuIGVmZmVjdGl2ZSB3ZWlnaHQgb2YgMFxuXG5cdFx0Y29uc3Qgd2VpZ2h0ID0gdGhpcy5fdXBkYXRlV2VpZ2h0KCB0aW1lICk7XG5cblx0XHRpZiAoIHdlaWdodCA+IDAgKSB7XG5cblx0XHRcdGNvbnN0IGludGVycG9sYW50cyA9IHRoaXMuX2ludGVycG9sYW50cztcblx0XHRcdGNvbnN0IHByb3BlcnR5TWl4ZXJzID0gdGhpcy5fcHJvcGVydHlCaW5kaW5ncztcblxuXHRcdFx0c3dpdGNoICggdGhpcy5ibGVuZE1vZGUgKSB7XG5cblx0XHRcdFx0Y2FzZSBBZGRpdGl2ZUFuaW1hdGlvbkJsZW5kTW9kZTpcblxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMCwgbSA9IGludGVycG9sYW50cy5sZW5ndGg7IGogIT09IG07ICsrIGogKSB7XG5cblx0XHRcdFx0XHRcdGludGVycG9sYW50c1sgaiBdLmV2YWx1YXRlKCBjbGlwVGltZSApO1xuXHRcdFx0XHRcdFx0cHJvcGVydHlNaXhlcnNbIGogXS5hY2N1bXVsYXRlQWRkaXRpdmUoIHdlaWdodCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGU6XG5cdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBpbnRlcnBvbGFudHMubGVuZ3RoOyBqICE9PSBtOyArKyBqICkge1xuXG5cdFx0XHRcdFx0XHRpbnRlcnBvbGFudHNbIGogXS5ldmFsdWF0ZSggY2xpcFRpbWUgKTtcblx0XHRcdFx0XHRcdHByb3BlcnR5TWl4ZXJzWyBqIF0uYWNjdW11bGF0ZSggYWNjdUluZGV4LCB3ZWlnaHQgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRfdXBkYXRlV2VpZ2h0KCB0aW1lICkge1xuXG5cdFx0bGV0IHdlaWdodCA9IDA7XG5cblx0XHRpZiAoIHRoaXMuZW5hYmxlZCApIHtcblxuXHRcdFx0d2VpZ2h0ID0gdGhpcy53ZWlnaHQ7XG5cdFx0XHRjb25zdCBpbnRlcnBvbGFudCA9IHRoaXMuX3dlaWdodEludGVycG9sYW50O1xuXG5cdFx0XHRpZiAoIGludGVycG9sYW50ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGNvbnN0IGludGVycG9sYW50VmFsdWUgPSBpbnRlcnBvbGFudC5ldmFsdWF0ZSggdGltZSApWyAwIF07XG5cblx0XHRcdFx0d2VpZ2h0ICo9IGludGVycG9sYW50VmFsdWU7XG5cblx0XHRcdFx0aWYgKCB0aW1lID4gaW50ZXJwb2xhbnQucGFyYW1ldGVyUG9zaXRpb25zWyAxIF0gKSB7XG5cblx0XHRcdFx0XHR0aGlzLnN0b3BGYWRpbmcoKTtcblxuXHRcdFx0XHRcdGlmICggaW50ZXJwb2xhbnRWYWx1ZSA9PT0gMCApIHtcblxuXHRcdFx0XHRcdFx0Ly8gZmFkZWQgb3V0LCBkaXNhYmxlXG5cdFx0XHRcdFx0XHR0aGlzLmVuYWJsZWQgPSBmYWxzZTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHRoaXMuX2VmZmVjdGl2ZVdlaWdodCA9IHdlaWdodDtcblx0XHRyZXR1cm4gd2VpZ2h0O1xuXG5cdH1cblxuXHRfdXBkYXRlVGltZVNjYWxlKCB0aW1lICkge1xuXG5cdFx0bGV0IHRpbWVTY2FsZSA9IDA7XG5cblx0XHRpZiAoICEgdGhpcy5wYXVzZWQgKSB7XG5cblx0XHRcdHRpbWVTY2FsZSA9IHRoaXMudGltZVNjYWxlO1xuXG5cdFx0XHRjb25zdCBpbnRlcnBvbGFudCA9IHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50O1xuXG5cdFx0XHRpZiAoIGludGVycG9sYW50ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGNvbnN0IGludGVycG9sYW50VmFsdWUgPSBpbnRlcnBvbGFudC5ldmFsdWF0ZSggdGltZSApWyAwIF07XG5cblx0XHRcdFx0dGltZVNjYWxlICo9IGludGVycG9sYW50VmFsdWU7XG5cblx0XHRcdFx0aWYgKCB0aW1lID4gaW50ZXJwb2xhbnQucGFyYW1ldGVyUG9zaXRpb25zWyAxIF0gKSB7XG5cblx0XHRcdFx0XHR0aGlzLnN0b3BXYXJwaW5nKCk7XG5cblx0XHRcdFx0XHRpZiAoIHRpbWVTY2FsZSA9PT0gMCApIHtcblxuXHRcdFx0XHRcdFx0Ly8gbW90aW9uIGhhcyBoYWx0ZWQsIHBhdXNlXG5cdFx0XHRcdFx0XHR0aGlzLnBhdXNlZCA9IHRydWU7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHQvLyB3YXJwIGRvbmUgLSBhcHBseSBmaW5hbCB0aW1lIHNjYWxlXG5cdFx0XHRcdFx0XHR0aGlzLnRpbWVTY2FsZSA9IHRpbWVTY2FsZTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHRoaXMuX2VmZmVjdGl2ZVRpbWVTY2FsZSA9IHRpbWVTY2FsZTtcblx0XHRyZXR1cm4gdGltZVNjYWxlO1xuXG5cdH1cblxuXHRfdXBkYXRlVGltZSggZGVsdGFUaW1lICkge1xuXG5cdFx0Y29uc3QgZHVyYXRpb24gPSB0aGlzLl9jbGlwLmR1cmF0aW9uO1xuXHRcdGNvbnN0IGxvb3AgPSB0aGlzLmxvb3A7XG5cblx0XHRsZXQgdGltZSA9IHRoaXMudGltZSArIGRlbHRhVGltZTtcblx0XHRsZXQgbG9vcENvdW50ID0gdGhpcy5fbG9vcENvdW50O1xuXG5cdFx0Y29uc3QgcGluZ1BvbmcgPSAoIGxvb3AgPT09IExvb3BQaW5nUG9uZyApO1xuXG5cdFx0aWYgKCBkZWx0YVRpbWUgPT09IDAgKSB7XG5cblx0XHRcdGlmICggbG9vcENvdW50ID09PSAtIDEgKSByZXR1cm4gdGltZTtcblxuXHRcdFx0cmV0dXJuICggcGluZ1BvbmcgJiYgKCBsb29wQ291bnQgJiAxICkgPT09IDEgKSA/IGR1cmF0aW9uIC0gdGltZSA6IHRpbWU7XG5cblx0XHR9XG5cblx0XHRpZiAoIGxvb3AgPT09IExvb3BPbmNlICkge1xuXG5cdFx0XHRpZiAoIGxvb3BDb3VudCA9PT0gLSAxICkge1xuXG5cdFx0XHRcdC8vIGp1c3Qgc3RhcnRlZFxuXG5cdFx0XHRcdHRoaXMuX2xvb3BDb3VudCA9IDA7XG5cdFx0XHRcdHRoaXMuX3NldEVuZGluZ3MoIHRydWUsIHRydWUsIGZhbHNlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0aGFuZGxlX3N0b3A6IHtcblxuXHRcdFx0XHRpZiAoIHRpbWUgPj0gZHVyYXRpb24gKSB7XG5cblx0XHRcdFx0XHR0aW1lID0gZHVyYXRpb247XG5cblx0XHRcdFx0fSBlbHNlIGlmICggdGltZSA8IDAgKSB7XG5cblx0XHRcdFx0XHR0aW1lID0gMDtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0dGhpcy50aW1lID0gdGltZTtcblxuXHRcdFx0XHRcdGJyZWFrIGhhbmRsZV9zdG9wO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIHRoaXMuY2xhbXBXaGVuRmluaXNoZWQgKSB0aGlzLnBhdXNlZCA9IHRydWU7XG5cdFx0XHRcdGVsc2UgdGhpcy5lbmFibGVkID0gZmFsc2U7XG5cblx0XHRcdFx0dGhpcy50aW1lID0gdGltZTtcblxuXHRcdFx0XHR0aGlzLl9taXhlci5kaXNwYXRjaEV2ZW50KCB7XG5cdFx0XHRcdFx0dHlwZTogJ2ZpbmlzaGVkJywgYWN0aW9uOiB0aGlzLFxuXHRcdFx0XHRcdGRpcmVjdGlvbjogZGVsdGFUaW1lIDwgMCA/IC0gMSA6IDFcblx0XHRcdFx0fSApO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2UgeyAvLyByZXBldGl0aXZlIFJlcGVhdCBvciBQaW5nUG9uZ1xuXG5cdFx0XHRpZiAoIGxvb3BDb3VudCA9PT0gLSAxICkge1xuXG5cdFx0XHRcdC8vIGp1c3Qgc3RhcnRlZFxuXG5cdFx0XHRcdGlmICggZGVsdGFUaW1lID49IDAgKSB7XG5cblx0XHRcdFx0XHRsb29wQ291bnQgPSAwO1xuXG5cdFx0XHRcdFx0dGhpcy5fc2V0RW5kaW5ncyggdHJ1ZSwgdGhpcy5yZXBldGl0aW9ucyA9PT0gMCwgcGluZ1BvbmcgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ly8gd2hlbiBsb29waW5nIGluIHJldmVyc2UgZGlyZWN0aW9uLCB0aGUgaW5pdGlhbFxuXHRcdFx0XHRcdC8vIHRyYW5zaXRpb24gdGhyb3VnaCB6ZXJvIGNvdW50cyBhcyBhIHJlcGV0aXRpb24sXG5cdFx0XHRcdFx0Ly8gc28gbGVhdmUgbG9vcENvdW50IGF0IC0xXG5cblx0XHRcdFx0XHR0aGlzLl9zZXRFbmRpbmdzKCB0aGlzLnJlcGV0aXRpb25zID09PSAwLCB0cnVlLCBwaW5nUG9uZyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRpbWUgPj0gZHVyYXRpb24gfHwgdGltZSA8IDAgKSB7XG5cblx0XHRcdFx0Ly8gd3JhcCBhcm91bmRcblxuXHRcdFx0XHRjb25zdCBsb29wRGVsdGEgPSBNYXRoLmZsb29yKCB0aW1lIC8gZHVyYXRpb24gKTsgLy8gc2lnbmVkXG5cdFx0XHRcdHRpbWUgLT0gZHVyYXRpb24gKiBsb29wRGVsdGE7XG5cblx0XHRcdFx0bG9vcENvdW50ICs9IE1hdGguYWJzKCBsb29wRGVsdGEgKTtcblxuXHRcdFx0XHRjb25zdCBwZW5kaW5nID0gdGhpcy5yZXBldGl0aW9ucyAtIGxvb3BDb3VudDtcblxuXHRcdFx0XHRpZiAoIHBlbmRpbmcgPD0gMCApIHtcblxuXHRcdFx0XHRcdC8vIGhhdmUgdG8gc3RvcCAoc3dpdGNoIHN0YXRlLCBjbGFtcCB0aW1lLCBmaXJlIGV2ZW50KVxuXG5cdFx0XHRcdFx0aWYgKCB0aGlzLmNsYW1wV2hlbkZpbmlzaGVkICkgdGhpcy5wYXVzZWQgPSB0cnVlO1xuXHRcdFx0XHRcdGVsc2UgdGhpcy5lbmFibGVkID0gZmFsc2U7XG5cblx0XHRcdFx0XHR0aW1lID0gZGVsdGFUaW1lID4gMCA/IGR1cmF0aW9uIDogMDtcblxuXHRcdFx0XHRcdHRoaXMudGltZSA9IHRpbWU7XG5cblx0XHRcdFx0XHR0aGlzLl9taXhlci5kaXNwYXRjaEV2ZW50KCB7XG5cdFx0XHRcdFx0XHR0eXBlOiAnZmluaXNoZWQnLCBhY3Rpb246IHRoaXMsXG5cdFx0XHRcdFx0XHRkaXJlY3Rpb246IGRlbHRhVGltZSA+IDAgPyAxIDogLSAxXG5cdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBrZWVwIHJ1bm5pbmdcblxuXHRcdFx0XHRcdGlmICggcGVuZGluZyA9PT0gMSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gZW50ZXJpbmcgdGhlIGxhc3Qgcm91bmRcblxuXHRcdFx0XHRcdFx0Y29uc3QgYXRTdGFydCA9IGRlbHRhVGltZSA8IDA7XG5cdFx0XHRcdFx0XHR0aGlzLl9zZXRFbmRpbmdzKCBhdFN0YXJ0LCAhIGF0U3RhcnQsIHBpbmdQb25nICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHR0aGlzLl9zZXRFbmRpbmdzKCBmYWxzZSwgZmFsc2UsIHBpbmdQb25nICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR0aGlzLl9sb29wQ291bnQgPSBsb29wQ291bnQ7XG5cblx0XHRcdFx0XHR0aGlzLnRpbWUgPSB0aW1lO1xuXG5cdFx0XHRcdFx0dGhpcy5fbWl4ZXIuZGlzcGF0Y2hFdmVudCgge1xuXHRcdFx0XHRcdFx0dHlwZTogJ2xvb3AnLCBhY3Rpb246IHRoaXMsIGxvb3BEZWx0YTogbG9vcERlbHRhXG5cdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHR0aGlzLnRpbWUgPSB0aW1lO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggcGluZ1BvbmcgJiYgKCBsb29wQ291bnQgJiAxICkgPT09IDEgKSB7XG5cblx0XHRcdFx0Ly8gaW52ZXJ0IHRpbWUgZm9yIHRoZSBcInBvbmcgcm91bmRcIlxuXG5cdFx0XHRcdHJldHVybiBkdXJhdGlvbiAtIHRpbWU7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0aW1lO1xuXG5cdH1cblxuXHRfc2V0RW5kaW5ncyggYXRTdGFydCwgYXRFbmQsIHBpbmdQb25nICkge1xuXG5cdFx0Y29uc3Qgc2V0dGluZ3MgPSB0aGlzLl9pbnRlcnBvbGFudFNldHRpbmdzO1xuXG5cdFx0aWYgKCBwaW5nUG9uZyApIHtcblxuXHRcdFx0c2V0dGluZ3MuZW5kaW5nU3RhcnQgPSBaZXJvU2xvcGVFbmRpbmc7XG5cdFx0XHRzZXR0aW5ncy5lbmRpbmdFbmQgPSBaZXJvU2xvcGVFbmRpbmc7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBhc3N1bWluZyBmb3IgTG9vcE9uY2UgYXRTdGFydCA9PSBhdEVuZCA9PSB0cnVlXG5cblx0XHRcdGlmICggYXRTdGFydCApIHtcblxuXHRcdFx0XHRzZXR0aW5ncy5lbmRpbmdTdGFydCA9IHRoaXMuemVyb1Nsb3BlQXRTdGFydCA/IFplcm9TbG9wZUVuZGluZyA6IFplcm9DdXJ2YXR1cmVFbmRpbmc7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0c2V0dGluZ3MuZW5kaW5nU3RhcnQgPSBXcmFwQXJvdW5kRW5kaW5nO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggYXRFbmQgKSB7XG5cblx0XHRcdFx0c2V0dGluZ3MuZW5kaW5nRW5kID0gdGhpcy56ZXJvU2xvcGVBdEVuZCA/IFplcm9TbG9wZUVuZGluZyA6IFplcm9DdXJ2YXR1cmVFbmRpbmc7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0c2V0dGluZ3MuZW5kaW5nRW5kIFx0ID0gV3JhcEFyb3VuZEVuZGluZztcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRfc2NoZWR1bGVGYWRpbmcoIGR1cmF0aW9uLCB3ZWlnaHROb3csIHdlaWdodFRoZW4gKSB7XG5cblx0XHRjb25zdCBtaXhlciA9IHRoaXMuX21peGVyLCBub3cgPSBtaXhlci50aW1lO1xuXHRcdGxldCBpbnRlcnBvbGFudCA9IHRoaXMuX3dlaWdodEludGVycG9sYW50O1xuXG5cdFx0aWYgKCBpbnRlcnBvbGFudCA9PT0gbnVsbCApIHtcblxuXHRcdFx0aW50ZXJwb2xhbnQgPSBtaXhlci5fbGVuZENvbnRyb2xJbnRlcnBvbGFudCgpO1xuXHRcdFx0dGhpcy5fd2VpZ2h0SW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudDtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHRpbWVzID0gaW50ZXJwb2xhbnQucGFyYW1ldGVyUG9zaXRpb25zLFxuXHRcdFx0dmFsdWVzID0gaW50ZXJwb2xhbnQuc2FtcGxlVmFsdWVzO1xuXG5cdFx0dGltZXNbIDAgXSA9IG5vdztcblx0XHR2YWx1ZXNbIDAgXSA9IHdlaWdodE5vdztcblx0XHR0aW1lc1sgMSBdID0gbm93ICsgZHVyYXRpb247XG5cdFx0dmFsdWVzWyAxIF0gPSB3ZWlnaHRUaGVuO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9jb250cm9sSW50ZXJwb2xhbnRzUmVzdWx0QnVmZmVyID0gbmV3IEZsb2F0MzJBcnJheSggMSApO1xuXG5cbmNsYXNzIEFuaW1hdGlvbk1peGVyIGV4dGVuZHMgRXZlbnREaXNwYXRjaGVyIHtcblxuXHRjb25zdHJ1Y3Rvciggcm9vdCApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLl9yb290ID0gcm9vdDtcblx0XHR0aGlzLl9pbml0TWVtb3J5TWFuYWdlcigpO1xuXHRcdHRoaXMuX2FjY3VJbmRleCA9IDA7XG5cdFx0dGhpcy50aW1lID0gMDtcblx0XHR0aGlzLnRpbWVTY2FsZSA9IDEuMDtcblxuXHR9XG5cblx0X2JpbmRBY3Rpb24oIGFjdGlvbiwgcHJvdG90eXBlQWN0aW9uICkge1xuXG5cdFx0Y29uc3Qgcm9vdCA9IGFjdGlvbi5fbG9jYWxSb290IHx8IHRoaXMuX3Jvb3QsXG5cdFx0XHR0cmFja3MgPSBhY3Rpb24uX2NsaXAudHJhY2tzLFxuXHRcdFx0blRyYWNrcyA9IHRyYWNrcy5sZW5ndGgsXG5cdFx0XHRiaW5kaW5ncyA9IGFjdGlvbi5fcHJvcGVydHlCaW5kaW5ncyxcblx0XHRcdGludGVycG9sYW50cyA9IGFjdGlvbi5faW50ZXJwb2xhbnRzLFxuXHRcdFx0cm9vdFV1aWQgPSByb290LnV1aWQsXG5cdFx0XHRiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZTtcblxuXHRcdGxldCBiaW5kaW5nc0J5TmFtZSA9IGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdO1xuXG5cdFx0aWYgKCBiaW5kaW5nc0J5TmFtZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRiaW5kaW5nc0J5TmFtZSA9IHt9O1xuXHRcdFx0YmluZGluZ3NCeVJvb3RbIHJvb3RVdWlkIF0gPSBiaW5kaW5nc0J5TmFtZTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gblRyYWNrczsgKysgaSApIHtcblxuXHRcdFx0Y29uc3QgdHJhY2sgPSB0cmFja3NbIGkgXSxcblx0XHRcdFx0dHJhY2tOYW1lID0gdHJhY2submFtZTtcblxuXHRcdFx0bGV0IGJpbmRpbmcgPSBiaW5kaW5nc0J5TmFtZVsgdHJhY2tOYW1lIF07XG5cblx0XHRcdGlmICggYmluZGluZyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdCsrIGJpbmRpbmcucmVmZXJlbmNlQ291bnQ7XG5cdFx0XHRcdGJpbmRpbmdzWyBpIF0gPSBiaW5kaW5nO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGJpbmRpbmcgPSBiaW5kaW5nc1sgaSBdO1xuXG5cdFx0XHRcdGlmICggYmluZGluZyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0Ly8gZXhpc3RpbmcgYmluZGluZywgbWFrZSBzdXJlIHRoZSBjYWNoZSBrbm93c1xuXG5cdFx0XHRcdFx0aWYgKCBiaW5kaW5nLl9jYWNoZUluZGV4ID09PSBudWxsICkge1xuXG5cdFx0XHRcdFx0XHQrKyBiaW5kaW5nLnJlZmVyZW5jZUNvdW50O1xuXHRcdFx0XHRcdFx0dGhpcy5fYWRkSW5hY3RpdmVCaW5kaW5nKCBiaW5kaW5nLCByb290VXVpZCwgdHJhY2tOYW1lICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRjb250aW51ZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Y29uc3QgcGF0aCA9IHByb3RvdHlwZUFjdGlvbiAmJiBwcm90b3R5cGVBY3Rpb24uXG5cdFx0XHRcdFx0X3Byb3BlcnR5QmluZGluZ3NbIGkgXS5iaW5kaW5nLnBhcnNlZFBhdGg7XG5cblx0XHRcdFx0YmluZGluZyA9IG5ldyBQcm9wZXJ0eU1peGVyKFxuXHRcdFx0XHRcdFByb3BlcnR5QmluZGluZy5jcmVhdGUoIHJvb3QsIHRyYWNrTmFtZSwgcGF0aCApLFxuXHRcdFx0XHRcdHRyYWNrLlZhbHVlVHlwZU5hbWUsIHRyYWNrLmdldFZhbHVlU2l6ZSgpICk7XG5cblx0XHRcdFx0KysgYmluZGluZy5yZWZlcmVuY2VDb3VudDtcblx0XHRcdFx0dGhpcy5fYWRkSW5hY3RpdmVCaW5kaW5nKCBiaW5kaW5nLCByb290VXVpZCwgdHJhY2tOYW1lICk7XG5cblx0XHRcdFx0YmluZGluZ3NbIGkgXSA9IGJpbmRpbmc7XG5cblx0XHRcdH1cblxuXHRcdFx0aW50ZXJwb2xhbnRzWyBpIF0ucmVzdWx0QnVmZmVyID0gYmluZGluZy5idWZmZXI7XG5cblx0XHR9XG5cblx0fVxuXG5cdF9hY3RpdmF0ZUFjdGlvbiggYWN0aW9uICkge1xuXG5cdFx0aWYgKCAhIHRoaXMuX2lzQWN0aXZlQWN0aW9uKCBhY3Rpb24gKSApIHtcblxuXHRcdFx0aWYgKCBhY3Rpb24uX2NhY2hlSW5kZXggPT09IG51bGwgKSB7XG5cblx0XHRcdFx0Ly8gdGhpcyBhY3Rpb24gaGFzIGJlZW4gZm9yZ290dGVuIGJ5IHRoZSBjYWNoZSwgYnV0IHRoZSB1c2VyXG5cdFx0XHRcdC8vIGFwcGVhcnMgdG8gYmUgc3RpbGwgdXNpbmcgaXQgLT4gcmViaW5kXG5cblx0XHRcdFx0Y29uc3Qgcm9vdFV1aWQgPSAoIGFjdGlvbi5fbG9jYWxSb290IHx8IHRoaXMuX3Jvb3QgKS51dWlkLFxuXHRcdFx0XHRcdGNsaXBVdWlkID0gYWN0aW9uLl9jbGlwLnV1aWQsXG5cdFx0XHRcdFx0YWN0aW9uc0ZvckNsaXAgPSB0aGlzLl9hY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xuXG5cdFx0XHRcdHRoaXMuX2JpbmRBY3Rpb24oIGFjdGlvbixcblx0XHRcdFx0XHRhY3Rpb25zRm9yQ2xpcCAmJiBhY3Rpb25zRm9yQ2xpcC5rbm93bkFjdGlvbnNbIDAgXSApO1xuXG5cdFx0XHRcdHRoaXMuX2FkZEluYWN0aXZlQWN0aW9uKCBhY3Rpb24sIGNsaXBVdWlkLCByb290VXVpZCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGJpbmRpbmdzID0gYWN0aW9uLl9wcm9wZXJ0eUJpbmRpbmdzO1xuXG5cdFx0XHQvLyBpbmNyZW1lbnQgcmVmZXJlbmNlIGNvdW50cyAvIHNvcnQgb3V0IHN0YXRlXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBiaW5kaW5ncy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdFx0Y29uc3QgYmluZGluZyA9IGJpbmRpbmdzWyBpIF07XG5cblx0XHRcdFx0aWYgKCBiaW5kaW5nLnVzZUNvdW50ICsrID09PSAwICkge1xuXG5cdFx0XHRcdFx0dGhpcy5fbGVuZEJpbmRpbmcoIGJpbmRpbmcgKTtcblx0XHRcdFx0XHRiaW5kaW5nLnNhdmVPcmlnaW5hbFN0YXRlKCk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2xlbmRBY3Rpb24oIGFjdGlvbiApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRfZGVhY3RpdmF0ZUFjdGlvbiggYWN0aW9uICkge1xuXG5cdFx0aWYgKCB0aGlzLl9pc0FjdGl2ZUFjdGlvbiggYWN0aW9uICkgKSB7XG5cblx0XHRcdGNvbnN0IGJpbmRpbmdzID0gYWN0aW9uLl9wcm9wZXJ0eUJpbmRpbmdzO1xuXG5cdFx0XHQvLyBkZWNyZW1lbnQgcmVmZXJlbmNlIGNvdW50cyAvIHNvcnQgb3V0IHN0YXRlXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBiaW5kaW5ncy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdFx0Y29uc3QgYmluZGluZyA9IGJpbmRpbmdzWyBpIF07XG5cblx0XHRcdFx0aWYgKCAtLSBiaW5kaW5nLnVzZUNvdW50ID09PSAwICkge1xuXG5cdFx0XHRcdFx0YmluZGluZy5yZXN0b3JlT3JpZ2luYWxTdGF0ZSgpO1xuXHRcdFx0XHRcdHRoaXMuX3Rha2VCYWNrQmluZGluZyggYmluZGluZyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLl90YWtlQmFja0FjdGlvbiggYWN0aW9uICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdC8vIE1lbW9yeSBtYW5hZ2VyXG5cblx0X2luaXRNZW1vcnlNYW5hZ2VyKCkge1xuXG5cdFx0dGhpcy5fYWN0aW9ucyA9IFtdOyAvLyAnbkFjdGl2ZUFjdGlvbnMnIGZvbGxvd2VkIGJ5IGluYWN0aXZlIG9uZXNcblx0XHR0aGlzLl9uQWN0aXZlQWN0aW9ucyA9IDA7XG5cblx0XHR0aGlzLl9hY3Rpb25zQnlDbGlwID0ge307XG5cdFx0Ly8gaW5zaWRlOlxuXHRcdC8vIHtcblx0XHQvLyBcdGtub3duQWN0aW9uczogQXJyYXk8IEFuaW1hdGlvbkFjdGlvbiA+IC0gdXNlZCBhcyBwcm90b3R5cGVzXG5cdFx0Ly8gXHRhY3Rpb25CeVJvb3Q6IEFuaW1hdGlvbkFjdGlvbiAtIGxvb2t1cFxuXHRcdC8vIH1cblxuXG5cdFx0dGhpcy5fYmluZGluZ3MgPSBbXTsgLy8gJ25BY3RpdmVCaW5kaW5ncycgZm9sbG93ZWQgYnkgaW5hY3RpdmUgb25lc1xuXHRcdHRoaXMuX25BY3RpdmVCaW5kaW5ncyA9IDA7XG5cblx0XHR0aGlzLl9iaW5kaW5nc0J5Um9vdEFuZE5hbWUgPSB7fTsgLy8gaW5zaWRlOiBNYXA8IG5hbWUsIFByb3BlcnR5TWl4ZXIgPlxuXG5cblx0XHR0aGlzLl9jb250cm9sSW50ZXJwb2xhbnRzID0gW107IC8vIHNhbWUgZ2FtZSBhcyBhYm92ZVxuXHRcdHRoaXMuX25BY3RpdmVDb250cm9sSW50ZXJwb2xhbnRzID0gMDtcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdHRoaXMuc3RhdHMgPSB7XG5cblx0XHRcdGFjdGlvbnM6IHtcblx0XHRcdFx0Z2V0IHRvdGFsKCkge1xuXG5cdFx0XHRcdFx0cmV0dXJuIHNjb3BlLl9hY3Rpb25zLmxlbmd0aDtcblxuXHRcdFx0XHR9LFxuXHRcdFx0XHRnZXQgaW5Vc2UoKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gc2NvcGUuX25BY3RpdmVBY3Rpb25zO1xuXG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cdFx0XHRiaW5kaW5nczoge1xuXHRcdFx0XHRnZXQgdG90YWwoKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gc2NvcGUuX2JpbmRpbmdzLmxlbmd0aDtcblxuXHRcdFx0XHR9LFxuXHRcdFx0XHRnZXQgaW5Vc2UoKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gc2NvcGUuX25BY3RpdmVCaW5kaW5ncztcblxuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0Y29udHJvbEludGVycG9sYW50czoge1xuXHRcdFx0XHRnZXQgdG90YWwoKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gc2NvcGUuX2NvbnRyb2xJbnRlcnBvbGFudHMubGVuZ3RoO1xuXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGdldCBpblVzZSgpIHtcblxuXHRcdFx0XHRcdHJldHVybiBzY29wZS5fbkFjdGl2ZUNvbnRyb2xJbnRlcnBvbGFudHM7XG5cblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHR9XG5cblx0Ly8gTWVtb3J5IG1hbmFnZW1lbnQgZm9yIEFuaW1hdGlvbkFjdGlvbiBvYmplY3RzXG5cblx0X2lzQWN0aXZlQWN0aW9uKCBhY3Rpb24gKSB7XG5cblx0XHRjb25zdCBpbmRleCA9IGFjdGlvbi5fY2FjaGVJbmRleDtcblx0XHRyZXR1cm4gaW5kZXggIT09IG51bGwgJiYgaW5kZXggPCB0aGlzLl9uQWN0aXZlQWN0aW9ucztcblxuXHR9XG5cblx0X2FkZEluYWN0aXZlQWN0aW9uKCBhY3Rpb24sIGNsaXBVdWlkLCByb290VXVpZCApIHtcblxuXHRcdGNvbnN0IGFjdGlvbnMgPSB0aGlzLl9hY3Rpb25zLFxuXHRcdFx0YWN0aW9uc0J5Q2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXA7XG5cblx0XHRsZXQgYWN0aW9uc0ZvckNsaXAgPSBhY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xuXG5cdFx0aWYgKCBhY3Rpb25zRm9yQ2xpcCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRhY3Rpb25zRm9yQ2xpcCA9IHtcblxuXHRcdFx0XHRrbm93bkFjdGlvbnM6IFsgYWN0aW9uIF0sXG5cdFx0XHRcdGFjdGlvbkJ5Um9vdDoge31cblxuXHRcdFx0fTtcblxuXHRcdFx0YWN0aW9uLl9ieUNsaXBDYWNoZUluZGV4ID0gMDtcblxuXHRcdFx0YWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXSA9IGFjdGlvbnNGb3JDbGlwO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc3Qga25vd25BY3Rpb25zID0gYWN0aW9uc0ZvckNsaXAua25vd25BY3Rpb25zO1xuXG5cdFx0XHRhY3Rpb24uX2J5Q2xpcENhY2hlSW5kZXggPSBrbm93bkFjdGlvbnMubGVuZ3RoO1xuXHRcdFx0a25vd25BY3Rpb25zLnB1c2goIGFjdGlvbiApO1xuXG5cdFx0fVxuXG5cdFx0YWN0aW9uLl9jYWNoZUluZGV4ID0gYWN0aW9ucy5sZW5ndGg7XG5cdFx0YWN0aW9ucy5wdXNoKCBhY3Rpb24gKTtcblxuXHRcdGFjdGlvbnNGb3JDbGlwLmFjdGlvbkJ5Um9vdFsgcm9vdFV1aWQgXSA9IGFjdGlvbjtcblxuXHR9XG5cblx0X3JlbW92ZUluYWN0aXZlQWN0aW9uKCBhY3Rpb24gKSB7XG5cblx0XHRjb25zdCBhY3Rpb25zID0gdGhpcy5fYWN0aW9ucyxcblx0XHRcdGxhc3RJbmFjdGl2ZUFjdGlvbiA9IGFjdGlvbnNbIGFjdGlvbnMubGVuZ3RoIC0gMSBdLFxuXHRcdFx0Y2FjaGVJbmRleCA9IGFjdGlvbi5fY2FjaGVJbmRleDtcblxuXHRcdGxhc3RJbmFjdGl2ZUFjdGlvbi5fY2FjaGVJbmRleCA9IGNhY2hlSW5kZXg7XG5cdFx0YWN0aW9uc1sgY2FjaGVJbmRleCBdID0gbGFzdEluYWN0aXZlQWN0aW9uO1xuXHRcdGFjdGlvbnMucG9wKCk7XG5cblx0XHRhY3Rpb24uX2NhY2hlSW5kZXggPSBudWxsO1xuXG5cblx0XHRjb25zdCBjbGlwVXVpZCA9IGFjdGlvbi5fY2xpcC51dWlkLFxuXHRcdFx0YWN0aW9uc0J5Q2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXAsXG5cdFx0XHRhY3Rpb25zRm9yQ2xpcCA9IGFjdGlvbnNCeUNsaXBbIGNsaXBVdWlkIF0sXG5cdFx0XHRrbm93bkFjdGlvbnNGb3JDbGlwID0gYWN0aW9uc0ZvckNsaXAua25vd25BY3Rpb25zLFxuXG5cdFx0XHRsYXN0S25vd25BY3Rpb24gPVxuXHRcdFx0XHRrbm93bkFjdGlvbnNGb3JDbGlwWyBrbm93bkFjdGlvbnNGb3JDbGlwLmxlbmd0aCAtIDEgXSxcblxuXHRcdFx0YnlDbGlwQ2FjaGVJbmRleCA9IGFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleDtcblxuXHRcdGxhc3RLbm93bkFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleCA9IGJ5Q2xpcENhY2hlSW5kZXg7XG5cdFx0a25vd25BY3Rpb25zRm9yQ2xpcFsgYnlDbGlwQ2FjaGVJbmRleCBdID0gbGFzdEtub3duQWN0aW9uO1xuXHRcdGtub3duQWN0aW9uc0ZvckNsaXAucG9wKCk7XG5cblx0XHRhY3Rpb24uX2J5Q2xpcENhY2hlSW5kZXggPSBudWxsO1xuXG5cblx0XHRjb25zdCBhY3Rpb25CeVJvb3QgPSBhY3Rpb25zRm9yQ2xpcC5hY3Rpb25CeVJvb3QsXG5cdFx0XHRyb290VXVpZCA9ICggYWN0aW9uLl9sb2NhbFJvb3QgfHwgdGhpcy5fcm9vdCApLnV1aWQ7XG5cblx0XHRkZWxldGUgYWN0aW9uQnlSb290WyByb290VXVpZCBdO1xuXG5cdFx0aWYgKCBrbm93bkFjdGlvbnNGb3JDbGlwLmxlbmd0aCA9PT0gMCApIHtcblxuXHRcdFx0ZGVsZXRlIGFjdGlvbnNCeUNsaXBbIGNsaXBVdWlkIF07XG5cblx0XHR9XG5cblx0XHR0aGlzLl9yZW1vdmVJbmFjdGl2ZUJpbmRpbmdzRm9yQWN0aW9uKCBhY3Rpb24gKTtcblxuXHR9XG5cblx0X3JlbW92ZUluYWN0aXZlQmluZGluZ3NGb3JBY3Rpb24oIGFjdGlvbiApIHtcblxuXHRcdGNvbnN0IGJpbmRpbmdzID0gYWN0aW9uLl9wcm9wZXJ0eUJpbmRpbmdzO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gYmluZGluZ3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCBiaW5kaW5nID0gYmluZGluZ3NbIGkgXTtcblxuXHRcdFx0aWYgKCAtLSBiaW5kaW5nLnJlZmVyZW5jZUNvdW50ID09PSAwICkge1xuXG5cdFx0XHRcdHRoaXMuX3JlbW92ZUluYWN0aXZlQmluZGluZyggYmluZGluZyApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdF9sZW5kQWN0aW9uKCBhY3Rpb24gKSB7XG5cblx0XHQvLyBbIGFjdGl2ZSBhY3Rpb25zIHwgIGluYWN0aXZlIGFjdGlvbnMgIF1cblx0XHQvLyBbICBhY3RpdmUgYWN0aW9ucyA+fCBpbmFjdGl2ZSBhY3Rpb25zIF1cblx0XHQvLyAgICAgICAgICAgICAgICAgcyAgICAgICAgYVxuXHRcdC8vICAgICAgICAgICAgICAgICAgPC1zd2FwLT5cblx0XHQvLyAgICAgICAgICAgICAgICAgYSAgICAgICAgc1xuXG5cdFx0Y29uc3QgYWN0aW9ucyA9IHRoaXMuX2FjdGlvbnMsXG5cdFx0XHRwcmV2SW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXgsXG5cblx0XHRcdGxhc3RBY3RpdmVJbmRleCA9IHRoaXMuX25BY3RpdmVBY3Rpb25zICsrLFxuXG5cdFx0XHRmaXJzdEluYWN0aXZlQWN0aW9uID0gYWN0aW9uc1sgbGFzdEFjdGl2ZUluZGV4IF07XG5cblx0XHRhY3Rpb24uX2NhY2hlSW5kZXggPSBsYXN0QWN0aXZlSW5kZXg7XG5cdFx0YWN0aW9uc1sgbGFzdEFjdGl2ZUluZGV4IF0gPSBhY3Rpb247XG5cblx0XHRmaXJzdEluYWN0aXZlQWN0aW9uLl9jYWNoZUluZGV4ID0gcHJldkluZGV4O1xuXHRcdGFjdGlvbnNbIHByZXZJbmRleCBdID0gZmlyc3RJbmFjdGl2ZUFjdGlvbjtcblxuXHR9XG5cblx0X3Rha2VCYWNrQWN0aW9uKCBhY3Rpb24gKSB7XG5cblx0XHQvLyBbICBhY3RpdmUgYWN0aW9ucyAgfCBpbmFjdGl2ZSBhY3Rpb25zIF1cblx0XHQvLyBbIGFjdGl2ZSBhY3Rpb25zIHw8IGluYWN0aXZlIGFjdGlvbnMgIF1cblx0XHQvLyAgICAgICAgYSAgICAgICAgc1xuXHRcdC8vICAgICAgICAgPC1zd2FwLT5cblx0XHQvLyAgICAgICAgcyAgICAgICAgYVxuXG5cdFx0Y29uc3QgYWN0aW9ucyA9IHRoaXMuX2FjdGlvbnMsXG5cdFx0XHRwcmV2SW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXgsXG5cblx0XHRcdGZpcnN0SW5hY3RpdmVJbmRleCA9IC0tIHRoaXMuX25BY3RpdmVBY3Rpb25zLFxuXG5cdFx0XHRsYXN0QWN0aXZlQWN0aW9uID0gYWN0aW9uc1sgZmlyc3RJbmFjdGl2ZUluZGV4IF07XG5cblx0XHRhY3Rpb24uX2NhY2hlSW5kZXggPSBmaXJzdEluYWN0aXZlSW5kZXg7XG5cdFx0YWN0aW9uc1sgZmlyc3RJbmFjdGl2ZUluZGV4IF0gPSBhY3Rpb247XG5cblx0XHRsYXN0QWN0aXZlQWN0aW9uLl9jYWNoZUluZGV4ID0gcHJldkluZGV4O1xuXHRcdGFjdGlvbnNbIHByZXZJbmRleCBdID0gbGFzdEFjdGl2ZUFjdGlvbjtcblxuXHR9XG5cblx0Ly8gTWVtb3J5IG1hbmFnZW1lbnQgZm9yIFByb3BlcnR5TWl4ZXIgb2JqZWN0c1xuXG5cdF9hZGRJbmFjdGl2ZUJpbmRpbmcoIGJpbmRpbmcsIHJvb3RVdWlkLCB0cmFja05hbWUgKSB7XG5cblx0XHRjb25zdCBiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZSxcblx0XHRcdGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3M7XG5cblx0XHRsZXQgYmluZGluZ0J5TmFtZSA9IGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdO1xuXG5cdFx0aWYgKCBiaW5kaW5nQnlOYW1lID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGJpbmRpbmdCeU5hbWUgPSB7fTtcblx0XHRcdGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdID0gYmluZGluZ0J5TmFtZTtcblxuXHRcdH1cblxuXHRcdGJpbmRpbmdCeU5hbWVbIHRyYWNrTmFtZSBdID0gYmluZGluZztcblxuXHRcdGJpbmRpbmcuX2NhY2hlSW5kZXggPSBiaW5kaW5ncy5sZW5ndGg7XG5cdFx0YmluZGluZ3MucHVzaCggYmluZGluZyApO1xuXG5cdH1cblxuXHRfcmVtb3ZlSW5hY3RpdmVCaW5kaW5nKCBiaW5kaW5nICkge1xuXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcblx0XHRcdHByb3BCaW5kaW5nID0gYmluZGluZy5iaW5kaW5nLFxuXHRcdFx0cm9vdFV1aWQgPSBwcm9wQmluZGluZy5yb290Tm9kZS51dWlkLFxuXHRcdFx0dHJhY2tOYW1lID0gcHJvcEJpbmRpbmcucGF0aCxcblx0XHRcdGJpbmRpbmdzQnlSb290ID0gdGhpcy5fYmluZGluZ3NCeVJvb3RBbmROYW1lLFxuXHRcdFx0YmluZGluZ0J5TmFtZSA9IGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdLFxuXG5cdFx0XHRsYXN0SW5hY3RpdmVCaW5kaW5nID0gYmluZGluZ3NbIGJpbmRpbmdzLmxlbmd0aCAtIDEgXSxcblx0XHRcdGNhY2hlSW5kZXggPSBiaW5kaW5nLl9jYWNoZUluZGV4O1xuXG5cdFx0bGFzdEluYWN0aXZlQmluZGluZy5fY2FjaGVJbmRleCA9IGNhY2hlSW5kZXg7XG5cdFx0YmluZGluZ3NbIGNhY2hlSW5kZXggXSA9IGxhc3RJbmFjdGl2ZUJpbmRpbmc7XG5cdFx0YmluZGluZ3MucG9wKCk7XG5cblx0XHRkZWxldGUgYmluZGluZ0J5TmFtZVsgdHJhY2tOYW1lIF07XG5cblx0XHRpZiAoIE9iamVjdC5rZXlzKCBiaW5kaW5nQnlOYW1lICkubGVuZ3RoID09PSAwICkge1xuXG5cdFx0XHRkZWxldGUgYmluZGluZ3NCeVJvb3RbIHJvb3RVdWlkIF07XG5cblx0XHR9XG5cblx0fVxuXG5cdF9sZW5kQmluZGluZyggYmluZGluZyApIHtcblxuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3MsXG5cdFx0XHRwcmV2SW5kZXggPSBiaW5kaW5nLl9jYWNoZUluZGV4LFxuXG5cdFx0XHRsYXN0QWN0aXZlSW5kZXggPSB0aGlzLl9uQWN0aXZlQmluZGluZ3MgKyssXG5cblx0XHRcdGZpcnN0SW5hY3RpdmVCaW5kaW5nID0gYmluZGluZ3NbIGxhc3RBY3RpdmVJbmRleCBdO1xuXG5cdFx0YmluZGluZy5fY2FjaGVJbmRleCA9IGxhc3RBY3RpdmVJbmRleDtcblx0XHRiaW5kaW5nc1sgbGFzdEFjdGl2ZUluZGV4IF0gPSBiaW5kaW5nO1xuXG5cdFx0Zmlyc3RJbmFjdGl2ZUJpbmRpbmcuX2NhY2hlSW5kZXggPSBwcmV2SW5kZXg7XG5cdFx0YmluZGluZ3NbIHByZXZJbmRleCBdID0gZmlyc3RJbmFjdGl2ZUJpbmRpbmc7XG5cblx0fVxuXG5cdF90YWtlQmFja0JpbmRpbmcoIGJpbmRpbmcgKSB7XG5cblx0XHRjb25zdCBiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxuXHRcdFx0cHJldkluZGV4ID0gYmluZGluZy5fY2FjaGVJbmRleCxcblxuXHRcdFx0Zmlyc3RJbmFjdGl2ZUluZGV4ID0gLS0gdGhpcy5fbkFjdGl2ZUJpbmRpbmdzLFxuXG5cdFx0XHRsYXN0QWN0aXZlQmluZGluZyA9IGJpbmRpbmdzWyBmaXJzdEluYWN0aXZlSW5kZXggXTtcblxuXHRcdGJpbmRpbmcuX2NhY2hlSW5kZXggPSBmaXJzdEluYWN0aXZlSW5kZXg7XG5cdFx0YmluZGluZ3NbIGZpcnN0SW5hY3RpdmVJbmRleCBdID0gYmluZGluZztcblxuXHRcdGxhc3RBY3RpdmVCaW5kaW5nLl9jYWNoZUluZGV4ID0gcHJldkluZGV4O1xuXHRcdGJpbmRpbmdzWyBwcmV2SW5kZXggXSA9IGxhc3RBY3RpdmVCaW5kaW5nO1xuXG5cdH1cblxuXG5cdC8vIE1lbW9yeSBtYW5hZ2VtZW50IG9mIEludGVycG9sYW50cyBmb3Igd2VpZ2h0IGFuZCB0aW1lIHNjYWxlXG5cblx0X2xlbmRDb250cm9sSW50ZXJwb2xhbnQoKSB7XG5cblx0XHRjb25zdCBpbnRlcnBvbGFudHMgPSB0aGlzLl9jb250cm9sSW50ZXJwb2xhbnRzLFxuXHRcdFx0bGFzdEFjdGl2ZUluZGV4ID0gdGhpcy5fbkFjdGl2ZUNvbnRyb2xJbnRlcnBvbGFudHMgKys7XG5cblx0XHRsZXQgaW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudHNbIGxhc3RBY3RpdmVJbmRleCBdO1xuXG5cdFx0aWYgKCBpbnRlcnBvbGFudCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRpbnRlcnBvbGFudCA9IG5ldyBMaW5lYXJJbnRlcnBvbGFudChcblx0XHRcdFx0bmV3IEZsb2F0MzJBcnJheSggMiApLCBuZXcgRmxvYXQzMkFycmF5KCAyICksXG5cdFx0XHRcdDEsIF9jb250cm9sSW50ZXJwb2xhbnRzUmVzdWx0QnVmZmVyICk7XG5cblx0XHRcdGludGVycG9sYW50Ll9fY2FjaGVJbmRleCA9IGxhc3RBY3RpdmVJbmRleDtcblx0XHRcdGludGVycG9sYW50c1sgbGFzdEFjdGl2ZUluZGV4IF0gPSBpbnRlcnBvbGFudDtcblxuXHRcdH1cblxuXHRcdHJldHVybiBpbnRlcnBvbGFudDtcblxuXHR9XG5cblx0X3Rha2VCYWNrQ29udHJvbEludGVycG9sYW50KCBpbnRlcnBvbGFudCApIHtcblxuXHRcdGNvbnN0IGludGVycG9sYW50cyA9IHRoaXMuX2NvbnRyb2xJbnRlcnBvbGFudHMsXG5cdFx0XHRwcmV2SW5kZXggPSBpbnRlcnBvbGFudC5fX2NhY2hlSW5kZXgsXG5cblx0XHRcdGZpcnN0SW5hY3RpdmVJbmRleCA9IC0tIHRoaXMuX25BY3RpdmVDb250cm9sSW50ZXJwb2xhbnRzLFxuXG5cdFx0XHRsYXN0QWN0aXZlSW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudHNbIGZpcnN0SW5hY3RpdmVJbmRleCBdO1xuXG5cdFx0aW50ZXJwb2xhbnQuX19jYWNoZUluZGV4ID0gZmlyc3RJbmFjdGl2ZUluZGV4O1xuXHRcdGludGVycG9sYW50c1sgZmlyc3RJbmFjdGl2ZUluZGV4IF0gPSBpbnRlcnBvbGFudDtcblxuXHRcdGxhc3RBY3RpdmVJbnRlcnBvbGFudC5fX2NhY2hlSW5kZXggPSBwcmV2SW5kZXg7XG5cdFx0aW50ZXJwb2xhbnRzWyBwcmV2SW5kZXggXSA9IGxhc3RBY3RpdmVJbnRlcnBvbGFudDtcblxuXHR9XG5cblx0Ly8gcmV0dXJuIGFuIGFjdGlvbiBmb3IgYSBjbGlwIG9wdGlvbmFsbHkgdXNpbmcgYSBjdXN0b20gcm9vdCB0YXJnZXRcblx0Ly8gb2JqZWN0ICh0aGlzIG1ldGhvZCBhbGxvY2F0ZXMgYSBsb3Qgb2YgZHluYW1pYyBtZW1vcnkgaW4gY2FzZSBhXG5cdC8vIHByZXZpb3VzbHkgdW5rbm93biBjbGlwL3Jvb3QgY29tYmluYXRpb24gaXMgc3BlY2lmaWVkKVxuXHRjbGlwQWN0aW9uKCBjbGlwLCBvcHRpb25hbFJvb3QsIGJsZW5kTW9kZSApIHtcblxuXHRcdGNvbnN0IHJvb3QgPSBvcHRpb25hbFJvb3QgfHwgdGhpcy5fcm9vdCxcblx0XHRcdHJvb3RVdWlkID0gcm9vdC51dWlkO1xuXG5cdFx0bGV0IGNsaXBPYmplY3QgPSB0eXBlb2YgY2xpcCA9PT0gJ3N0cmluZycgPyBBbmltYXRpb25DbGlwLmZpbmRCeU5hbWUoIHJvb3QsIGNsaXAgKSA6IGNsaXA7XG5cblx0XHRjb25zdCBjbGlwVXVpZCA9IGNsaXBPYmplY3QgIT09IG51bGwgPyBjbGlwT2JqZWN0LnV1aWQgOiBjbGlwO1xuXG5cdFx0Y29uc3QgYWN0aW9uc0ZvckNsaXAgPSB0aGlzLl9hY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xuXHRcdGxldCBwcm90b3R5cGVBY3Rpb24gPSBudWxsO1xuXG5cdFx0aWYgKCBibGVuZE1vZGUgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0aWYgKCBjbGlwT2JqZWN0ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGJsZW5kTW9kZSA9IGNsaXBPYmplY3QuYmxlbmRNb2RlO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGJsZW5kTW9kZSA9IE5vcm1hbEFuaW1hdGlvbkJsZW5kTW9kZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBhY3Rpb25zRm9yQ2xpcCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjb25zdCBleGlzdGluZ0FjdGlvbiA9IGFjdGlvbnNGb3JDbGlwLmFjdGlvbkJ5Um9vdFsgcm9vdFV1aWQgXTtcblxuXHRcdFx0aWYgKCBleGlzdGluZ0FjdGlvbiAhPT0gdW5kZWZpbmVkICYmIGV4aXN0aW5nQWN0aW9uLmJsZW5kTW9kZSA9PT0gYmxlbmRNb2RlICkge1xuXG5cdFx0XHRcdHJldHVybiBleGlzdGluZ0FjdGlvbjtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyB3ZSBrbm93IHRoZSBjbGlwLCBzbyB3ZSBkb24ndCBoYXZlIHRvIHBhcnNlIGFsbFxuXHRcdFx0Ly8gdGhlIGJpbmRpbmdzIGFnYWluIGJ1dCBjYW4ganVzdCBjb3B5XG5cdFx0XHRwcm90b3R5cGVBY3Rpb24gPSBhY3Rpb25zRm9yQ2xpcC5rbm93bkFjdGlvbnNbIDAgXTtcblxuXHRcdFx0Ly8gYWxzbywgdGFrZSB0aGUgY2xpcCBmcm9tIHRoZSBwcm90b3R5cGUgYWN0aW9uXG5cdFx0XHRpZiAoIGNsaXBPYmplY3QgPT09IG51bGwgKVxuXHRcdFx0XHRjbGlwT2JqZWN0ID0gcHJvdG90eXBlQWN0aW9uLl9jbGlwO1xuXG5cdFx0fVxuXG5cdFx0Ly8gY2xpcCBtdXN0IGJlIGtub3duIHdoZW4gc3BlY2lmaWVkIHZpYSBzdHJpbmdcblx0XHRpZiAoIGNsaXBPYmplY3QgPT09IG51bGwgKSByZXR1cm4gbnVsbDtcblxuXHRcdC8vIGFsbG9jYXRlIGFsbCByZXNvdXJjZXMgcmVxdWlyZWQgdG8gcnVuIGl0XG5cdFx0Y29uc3QgbmV3QWN0aW9uID0gbmV3IEFuaW1hdGlvbkFjdGlvbiggdGhpcywgY2xpcE9iamVjdCwgb3B0aW9uYWxSb290LCBibGVuZE1vZGUgKTtcblxuXHRcdHRoaXMuX2JpbmRBY3Rpb24oIG5ld0FjdGlvbiwgcHJvdG90eXBlQWN0aW9uICk7XG5cblx0XHQvLyBhbmQgbWFrZSB0aGUgYWN0aW9uIGtub3duIHRvIHRoZSBtZW1vcnkgbWFuYWdlclxuXHRcdHRoaXMuX2FkZEluYWN0aXZlQWN0aW9uKCBuZXdBY3Rpb24sIGNsaXBVdWlkLCByb290VXVpZCApO1xuXG5cdFx0cmV0dXJuIG5ld0FjdGlvbjtcblxuXHR9XG5cblx0Ly8gZ2V0IGFuIGV4aXN0aW5nIGFjdGlvblxuXHRleGlzdGluZ0FjdGlvbiggY2xpcCwgb3B0aW9uYWxSb290ICkge1xuXG5cdFx0Y29uc3Qgcm9vdCA9IG9wdGlvbmFsUm9vdCB8fCB0aGlzLl9yb290LFxuXHRcdFx0cm9vdFV1aWQgPSByb290LnV1aWQsXG5cblx0XHRcdGNsaXBPYmplY3QgPSB0eXBlb2YgY2xpcCA9PT0gJ3N0cmluZycgP1xuXHRcdFx0XHRBbmltYXRpb25DbGlwLmZpbmRCeU5hbWUoIHJvb3QsIGNsaXAgKSA6IGNsaXAsXG5cblx0XHRcdGNsaXBVdWlkID0gY2xpcE9iamVjdCA/IGNsaXBPYmplY3QudXVpZCA6IGNsaXAsXG5cblx0XHRcdGFjdGlvbnNGb3JDbGlwID0gdGhpcy5fYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXTtcblxuXHRcdGlmICggYWN0aW9uc0ZvckNsaXAgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0cmV0dXJuIGFjdGlvbnNGb3JDbGlwLmFjdGlvbkJ5Um9vdFsgcm9vdFV1aWQgXSB8fCBudWxsO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG51bGw7XG5cblx0fVxuXG5cdC8vIGRlYWN0aXZhdGVzIGFsbCBwcmV2aW91c2x5IHNjaGVkdWxlZCBhY3Rpb25zXG5cdHN0b3BBbGxBY3Rpb24oKSB7XG5cblx0XHRjb25zdCBhY3Rpb25zID0gdGhpcy5fYWN0aW9ucyxcblx0XHRcdG5BY3Rpb25zID0gdGhpcy5fbkFjdGl2ZUFjdGlvbnM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IG5BY3Rpb25zIC0gMTsgaSA+PSAwOyAtLSBpICkge1xuXG5cdFx0XHRhY3Rpb25zWyBpIF0uc3RvcCgpO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIGFkdmFuY2UgdGhlIHRpbWUgYW5kIHVwZGF0ZSBhcHBseSB0aGUgYW5pbWF0aW9uXG5cdHVwZGF0ZSggZGVsdGFUaW1lICkge1xuXG5cdFx0ZGVsdGFUaW1lICo9IHRoaXMudGltZVNjYWxlO1xuXG5cdFx0Y29uc3QgYWN0aW9ucyA9IHRoaXMuX2FjdGlvbnMsXG5cdFx0XHRuQWN0aW9ucyA9IHRoaXMuX25BY3RpdmVBY3Rpb25zLFxuXG5cdFx0XHR0aW1lID0gdGhpcy50aW1lICs9IGRlbHRhVGltZSxcblx0XHRcdHRpbWVEaXJlY3Rpb24gPSBNYXRoLnNpZ24oIGRlbHRhVGltZSApLFxuXG5cdFx0XHRhY2N1SW5kZXggPSB0aGlzLl9hY2N1SW5kZXggXj0gMTtcblxuXHRcdC8vIHJ1biBhY3RpdmUgYWN0aW9uc1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuQWN0aW9uczsgKysgaSApIHtcblxuXHRcdFx0Y29uc3QgYWN0aW9uID0gYWN0aW9uc1sgaSBdO1xuXG5cdFx0XHRhY3Rpb24uX3VwZGF0ZSggdGltZSwgZGVsdGFUaW1lLCB0aW1lRGlyZWN0aW9uLCBhY2N1SW5kZXggKTtcblxuXHRcdH1cblxuXHRcdC8vIHVwZGF0ZSBzY2VuZSBncmFwaFxuXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcblx0XHRcdG5CaW5kaW5ncyA9IHRoaXMuX25BY3RpdmVCaW5kaW5ncztcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbkJpbmRpbmdzOyArKyBpICkge1xuXG5cdFx0XHRiaW5kaW5nc1sgaSBdLmFwcGx5KCBhY2N1SW5kZXggKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvLyBBbGxvd3MgeW91IHRvIHNlZWsgdG8gYSBzcGVjaWZpYyB0aW1lIGluIGFuIGFuaW1hdGlvbi5cblx0c2V0VGltZSggdGltZUluU2Vjb25kcyApIHtcblxuXHRcdHRoaXMudGltZSA9IDA7IC8vIFplcm8gb3V0IHRpbWUgYXR0cmlidXRlIGZvciBBbmltYXRpb25NaXhlciBvYmplY3Q7XG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy5fYWN0aW9ucy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuX2FjdGlvbnNbIGkgXS50aW1lID0gMDsgLy8gWmVybyBvdXQgdGltZSBhdHRyaWJ1dGUgZm9yIGFsbCBhc3NvY2lhdGVkIEFuaW1hdGlvbkFjdGlvbiBvYmplY3RzLlxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMudXBkYXRlKCB0aW1lSW5TZWNvbmRzICk7IC8vIFVwZGF0ZSB1c2VkIHRvIHNldCBleGFjdCB0aW1lLiBSZXR1cm5zIFwidGhpc1wiIEFuaW1hdGlvbk1peGVyIG9iamVjdC5cblxuXHR9XG5cblx0Ly8gcmV0dXJuIHRoaXMgbWl4ZXIncyByb290IHRhcmdldCBvYmplY3Rcblx0Z2V0Um9vdCgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9yb290O1xuXG5cdH1cblxuXHQvLyBmcmVlIGFsbCByZXNvdXJjZXMgc3BlY2lmaWMgdG8gYSBwYXJ0aWN1bGFyIGNsaXBcblx0dW5jYWNoZUNsaXAoIGNsaXAgKSB7XG5cblx0XHRjb25zdCBhY3Rpb25zID0gdGhpcy5fYWN0aW9ucyxcblx0XHRcdGNsaXBVdWlkID0gY2xpcC51dWlkLFxuXHRcdFx0YWN0aW9uc0J5Q2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXAsXG5cdFx0XHRhY3Rpb25zRm9yQ2xpcCA9IGFjdGlvbnNCeUNsaXBbIGNsaXBVdWlkIF07XG5cblx0XHRpZiAoIGFjdGlvbnNGb3JDbGlwICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdC8vIG5vdGU6IGp1c3QgY2FsbGluZyBfcmVtb3ZlSW5hY3RpdmVBY3Rpb24gd291bGQgbWVzcyB1cCB0aGVcblx0XHRcdC8vIGl0ZXJhdGlvbiBzdGF0ZSBhbmQgYWxzbyByZXF1aXJlIHVwZGF0aW5nIHRoZSBzdGF0ZSB3ZSBjYW5cblx0XHRcdC8vIGp1c3QgdGhyb3cgYXdheVxuXG5cdFx0XHRjb25zdCBhY3Rpb25zVG9SZW1vdmUgPSBhY3Rpb25zRm9yQ2xpcC5rbm93bkFjdGlvbnM7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGFjdGlvbnNUb1JlbW92ZS5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdFx0Y29uc3QgYWN0aW9uID0gYWN0aW9uc1RvUmVtb3ZlWyBpIF07XG5cblx0XHRcdFx0dGhpcy5fZGVhY3RpdmF0ZUFjdGlvbiggYWN0aW9uICk7XG5cblx0XHRcdFx0Y29uc3QgY2FjaGVJbmRleCA9IGFjdGlvbi5fY2FjaGVJbmRleCxcblx0XHRcdFx0XHRsYXN0SW5hY3RpdmVBY3Rpb24gPSBhY3Rpb25zWyBhY3Rpb25zLmxlbmd0aCAtIDEgXTtcblxuXHRcdFx0XHRhY3Rpb24uX2NhY2hlSW5kZXggPSBudWxsO1xuXHRcdFx0XHRhY3Rpb24uX2J5Q2xpcENhY2hlSW5kZXggPSBudWxsO1xuXG5cdFx0XHRcdGxhc3RJbmFjdGl2ZUFjdGlvbi5fY2FjaGVJbmRleCA9IGNhY2hlSW5kZXg7XG5cdFx0XHRcdGFjdGlvbnNbIGNhY2hlSW5kZXggXSA9IGxhc3RJbmFjdGl2ZUFjdGlvbjtcblx0XHRcdFx0YWN0aW9ucy5wb3AoKTtcblxuXHRcdFx0XHR0aGlzLl9yZW1vdmVJbmFjdGl2ZUJpbmRpbmdzRm9yQWN0aW9uKCBhY3Rpb24gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRkZWxldGUgYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXTtcblxuXHRcdH1cblxuXHR9XG5cblx0Ly8gZnJlZSBhbGwgcmVzb3VyY2VzIHNwZWNpZmljIHRvIGEgcGFydGljdWxhciByb290IHRhcmdldCBvYmplY3Rcblx0dW5jYWNoZVJvb3QoIHJvb3QgKSB7XG5cblx0XHRjb25zdCByb290VXVpZCA9IHJvb3QudXVpZCxcblx0XHRcdGFjdGlvbnNCeUNsaXAgPSB0aGlzLl9hY3Rpb25zQnlDbGlwO1xuXG5cdFx0Zm9yICggY29uc3QgY2xpcFV1aWQgaW4gYWN0aW9uc0J5Q2xpcCApIHtcblxuXHRcdFx0Y29uc3QgYWN0aW9uQnlSb290ID0gYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXS5hY3Rpb25CeVJvb3QsXG5cdFx0XHRcdGFjdGlvbiA9IGFjdGlvbkJ5Um9vdFsgcm9vdFV1aWQgXTtcblxuXHRcdFx0aWYgKCBhY3Rpb24gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0aGlzLl9kZWFjdGl2YXRlQWN0aW9uKCBhY3Rpb24gKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlSW5hY3RpdmVBY3Rpb24oIGFjdGlvbiApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRjb25zdCBiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZSxcblx0XHRcdGJpbmRpbmdCeU5hbWUgPSBiaW5kaW5nc0J5Um9vdFsgcm9vdFV1aWQgXTtcblxuXHRcdGlmICggYmluZGluZ0J5TmFtZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRmb3IgKCBjb25zdCB0cmFja05hbWUgaW4gYmluZGluZ0J5TmFtZSApIHtcblxuXHRcdFx0XHRjb25zdCBiaW5kaW5nID0gYmluZGluZ0J5TmFtZVsgdHJhY2tOYW1lIF07XG5cdFx0XHRcdGJpbmRpbmcucmVzdG9yZU9yaWdpbmFsU3RhdGUoKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlSW5hY3RpdmVCaW5kaW5nKCBiaW5kaW5nICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0Ly8gcmVtb3ZlIGEgdGFyZ2V0ZWQgY2xpcCBmcm9tIHRoZSBjYWNoZVxuXHR1bmNhY2hlQWN0aW9uKCBjbGlwLCBvcHRpb25hbFJvb3QgKSB7XG5cblx0XHRjb25zdCBhY3Rpb24gPSB0aGlzLmV4aXN0aW5nQWN0aW9uKCBjbGlwLCBvcHRpb25hbFJvb3QgKTtcblxuXHRcdGlmICggYWN0aW9uICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl9kZWFjdGl2YXRlQWN0aW9uKCBhY3Rpb24gKTtcblx0XHRcdHRoaXMuX3JlbW92ZUluYWN0aXZlQWN0aW9uKCBhY3Rpb24gKTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuY2xhc3MgVW5pZm9ybSB7XG5cblx0Y29uc3RydWN0b3IoIHZhbHVlICkge1xuXG5cdFx0dGhpcy52YWx1ZSA9IHZhbHVlO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgVW5pZm9ybSggdGhpcy52YWx1ZS5jbG9uZSA9PT0gdW5kZWZpbmVkID8gdGhpcy52YWx1ZSA6IHRoaXMudmFsdWUuY2xvbmUoKSApO1xuXG5cdH1cblxufVxuXG5sZXQgX2lkID0gMDtcblxuY2xhc3MgVW5pZm9ybXNHcm91cCBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc1VuaWZvcm1zR3JvdXAgPSB0cnVlO1xuXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfaWQgKysgfSApO1xuXG5cdFx0dGhpcy5uYW1lID0gJyc7XG5cblx0XHR0aGlzLnVzYWdlID0gU3RhdGljRHJhd1VzYWdlO1xuXHRcdHRoaXMudW5pZm9ybXMgPSBbXTtcblxuXHR9XG5cblx0YWRkKCB1bmlmb3JtICkge1xuXG5cdFx0dGhpcy51bmlmb3Jtcy5wdXNoKCB1bmlmb3JtICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cmVtb3ZlKCB1bmlmb3JtICkge1xuXG5cdFx0Y29uc3QgaW5kZXggPSB0aGlzLnVuaWZvcm1zLmluZGV4T2YoIHVuaWZvcm0gKTtcblxuXHRcdGlmICggaW5kZXggIT09IC0gMSApIHRoaXMudW5pZm9ybXMuc3BsaWNlKCBpbmRleCwgMSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldE5hbWUoIG5hbWUgKSB7XG5cblx0XHR0aGlzLm5hbWUgPSBuYW1lO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFVzYWdlKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMudXNhZ2UgPSB2YWx1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0dGhpcy5uYW1lID0gc291cmNlLm5hbWU7XG5cdFx0dGhpcy51c2FnZSA9IHNvdXJjZS51c2FnZTtcblxuXHRcdGNvbnN0IHVuaWZvcm1zU291cmNlID0gc291cmNlLnVuaWZvcm1zO1xuXG5cdFx0dGhpcy51bmlmb3Jtcy5sZW5ndGggPSAwO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdW5pZm9ybXNTb3VyY2UubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBBcnJheS5pc0FycmF5KCB1bmlmb3Jtc1NvdXJjZVsgaSBdICkgPyB1bmlmb3Jtc1NvdXJjZVsgaSBdIDogWyB1bmlmb3Jtc1NvdXJjZVsgaSBdIF07XG5cblx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IHVuaWZvcm1zLmxlbmd0aDsgaiArKyApIHtcblxuXHRcdFx0XHR0aGlzLnVuaWZvcm1zLnB1c2goIHVuaWZvcm1zWyBqIF0uY2xvbmUoKSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIEluc3RhbmNlZEludGVybGVhdmVkQnVmZmVyIGV4dGVuZHMgSW50ZXJsZWF2ZWRCdWZmZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgc3RyaWRlLCBtZXNoUGVyQXR0cmlidXRlID0gMSApIHtcblxuXHRcdHN1cGVyKCBhcnJheSwgc3RyaWRlICk7XG5cblx0XHR0aGlzLmlzSW5zdGFuY2VkSW50ZXJsZWF2ZWRCdWZmZXIgPSB0cnVlO1xuXG5cdFx0dGhpcy5tZXNoUGVyQXR0cmlidXRlID0gbWVzaFBlckF0dHJpYnV0ZTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLm1lc2hQZXJBdHRyaWJ1dGUgPSBzb3VyY2UubWVzaFBlckF0dHJpYnV0ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSggZGF0YSApIHtcblxuXHRcdGNvbnN0IGliID0gc3VwZXIuY2xvbmUoIGRhdGEgKTtcblxuXHRcdGliLm1lc2hQZXJBdHRyaWJ1dGUgPSB0aGlzLm1lc2hQZXJBdHRyaWJ1dGU7XG5cblx0XHRyZXR1cm4gaWI7XG5cblx0fVxuXG5cdHRvSlNPTiggZGF0YSApIHtcblxuXHRcdGNvbnN0IGpzb24gPSBzdXBlci50b0pTT04oIGRhdGEgKTtcblxuXHRcdGpzb24uaXNJbnN0YW5jZWRJbnRlcmxlYXZlZEJ1ZmZlciA9IHRydWU7XG5cdFx0anNvbi5tZXNoUGVyQXR0cmlidXRlID0gdGhpcy5tZXNoUGVyQXR0cmlidXRlO1xuXG5cdFx0cmV0dXJuIGpzb247XG5cblx0fVxuXG59XG5cbmNsYXNzIEdMQnVmZmVyQXR0cmlidXRlIHtcblxuXHRjb25zdHJ1Y3RvciggYnVmZmVyLCB0eXBlLCBpdGVtU2l6ZSwgZWxlbWVudFNpemUsIGNvdW50ICkge1xuXG5cdFx0dGhpcy5pc0dMQnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcblxuXHRcdHRoaXMubmFtZSA9ICcnO1xuXG5cdFx0dGhpcy5idWZmZXIgPSBidWZmZXI7XG5cdFx0dGhpcy50eXBlID0gdHlwZTtcblx0XHR0aGlzLml0ZW1TaXplID0gaXRlbVNpemU7XG5cdFx0dGhpcy5lbGVtZW50U2l6ZSA9IGVsZW1lbnRTaXplO1xuXHRcdHRoaXMuY291bnQgPSBjb3VudDtcblxuXHRcdHRoaXMudmVyc2lvbiA9IDA7XG5cblx0fVxuXG5cdHNldCBuZWVkc1VwZGF0ZSggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHZhbHVlID09PSB0cnVlICkgdGhpcy52ZXJzaW9uICsrO1xuXG5cdH1cblxuXHRzZXRCdWZmZXIoIGJ1ZmZlciApIHtcblxuXHRcdHRoaXMuYnVmZmVyID0gYnVmZmVyO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFR5cGUoIHR5cGUsIGVsZW1lbnRTaXplICkge1xuXG5cdFx0dGhpcy50eXBlID0gdHlwZTtcblx0XHR0aGlzLmVsZW1lbnRTaXplID0gZWxlbWVudFNpemU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0SXRlbVNpemUoIGl0ZW1TaXplICkge1xuXG5cdFx0dGhpcy5pdGVtU2l6ZSA9IGl0ZW1TaXplO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldENvdW50KCBjb3VudCApIHtcblxuXHRcdHRoaXMuY291bnQgPSBjb3VudDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jb25zdCBfbWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuXG5jbGFzcyBSYXljYXN0ZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBvcmlnaW4sIGRpcmVjdGlvbiwgbmVhciA9IDAsIGZhciA9IEluZmluaXR5ICkge1xuXG5cdFx0dGhpcy5yYXkgPSBuZXcgUmF5KCBvcmlnaW4sIGRpcmVjdGlvbiApO1xuXHRcdC8vIGRpcmVjdGlvbiBpcyBhc3N1bWVkIHRvIGJlIG5vcm1hbGl6ZWQgKGZvciBhY2N1cmF0ZSBkaXN0YW5jZSBjYWxjdWxhdGlvbnMpXG5cblx0XHR0aGlzLm5lYXIgPSBuZWFyO1xuXHRcdHRoaXMuZmFyID0gZmFyO1xuXHRcdHRoaXMuY2FtZXJhID0gbnVsbDtcblx0XHR0aGlzLmxheWVycyA9IG5ldyBMYXllcnMoKTtcblxuXHRcdHRoaXMucGFyYW1zID0ge1xuXHRcdFx0TWVzaDoge30sXG5cdFx0XHRMaW5lOiB7IHRocmVzaG9sZDogMSB9LFxuXHRcdFx0TE9EOiB7fSxcblx0XHRcdFBvaW50czogeyB0aHJlc2hvbGQ6IDEgfSxcblx0XHRcdFNwcml0ZToge31cblx0XHR9O1xuXG5cdH1cblxuXHRzZXQoIG9yaWdpbiwgZGlyZWN0aW9uICkge1xuXG5cdFx0Ly8gZGlyZWN0aW9uIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZCAoZm9yIGFjY3VyYXRlIGRpc3RhbmNlIGNhbGN1bGF0aW9ucylcblxuXHRcdHRoaXMucmF5LnNldCggb3JpZ2luLCBkaXJlY3Rpb24gKTtcblxuXHR9XG5cblx0c2V0RnJvbUNhbWVyYSggY29vcmRzLCBjYW1lcmEgKSB7XG5cblx0XHRpZiAoIGNhbWVyYS5pc1BlcnNwZWN0aXZlQ2FtZXJhICkge1xuXG5cdFx0XHR0aGlzLnJheS5vcmlnaW4uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBjYW1lcmEubWF0cml4V29ybGQgKTtcblx0XHRcdHRoaXMucmF5LmRpcmVjdGlvbi5zZXQoIGNvb3Jkcy54LCBjb29yZHMueSwgMC41ICkudW5wcm9qZWN0KCBjYW1lcmEgKS5zdWIoIHRoaXMucmF5Lm9yaWdpbiApLm5vcm1hbGl6ZSgpO1xuXHRcdFx0dGhpcy5jYW1lcmEgPSBjYW1lcmE7XG5cblx0XHR9IGVsc2UgaWYgKCBjYW1lcmEuaXNPcnRob2dyYXBoaWNDYW1lcmEgKSB7XG5cblx0XHRcdHRoaXMucmF5Lm9yaWdpbi5zZXQoIGNvb3Jkcy54LCBjb29yZHMueSwgKCBjYW1lcmEubmVhciArIGNhbWVyYS5mYXIgKSAvICggY2FtZXJhLm5lYXIgLSBjYW1lcmEuZmFyICkgKS51bnByb2plY3QoIGNhbWVyYSApOyAvLyBzZXQgb3JpZ2luIGluIHBsYW5lIG9mIGNhbWVyYVxuXHRcdFx0dGhpcy5yYXkuZGlyZWN0aW9uLnNldCggMCwgMCwgLSAxICkudHJhbnNmb3JtRGlyZWN0aW9uKCBjYW1lcmEubWF0cml4V29ybGQgKTtcblx0XHRcdHRoaXMuY2FtZXJhID0gY2FtZXJhO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlJheWNhc3RlcjogVW5zdXBwb3J0ZWQgY2FtZXJhIHR5cGU6ICcgKyBjYW1lcmEudHlwZSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRzZXRGcm9tWFJDb250cm9sbGVyKCBjb250cm9sbGVyICkge1xuXG5cdFx0X21hdHJpeC5pZGVudGl0eSgpLmV4dHJhY3RSb3RhdGlvbiggY29udHJvbGxlci5tYXRyaXhXb3JsZCApO1xuXG5cdFx0dGhpcy5yYXkub3JpZ2luLnNldEZyb21NYXRyaXhQb3NpdGlvbiggY29udHJvbGxlci5tYXRyaXhXb3JsZCApO1xuXHRcdHRoaXMucmF5LmRpcmVjdGlvbi5zZXQoIDAsIDAsIC0gMSApLmFwcGx5TWF0cml4NCggX21hdHJpeCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGludGVyc2VjdE9iamVjdCggb2JqZWN0LCByZWN1cnNpdmUgPSB0cnVlLCBpbnRlcnNlY3RzID0gW10gKSB7XG5cblx0XHRpbnRlcnNlY3QoIG9iamVjdCwgdGhpcywgaW50ZXJzZWN0cywgcmVjdXJzaXZlICk7XG5cblx0XHRpbnRlcnNlY3RzLnNvcnQoIGFzY1NvcnQgKTtcblxuXHRcdHJldHVybiBpbnRlcnNlY3RzO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RPYmplY3RzKCBvYmplY3RzLCByZWN1cnNpdmUgPSB0cnVlLCBpbnRlcnNlY3RzID0gW10gKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBvYmplY3RzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGludGVyc2VjdCggb2JqZWN0c1sgaSBdLCB0aGlzLCBpbnRlcnNlY3RzLCByZWN1cnNpdmUgKTtcblxuXHRcdH1cblxuXHRcdGludGVyc2VjdHMuc29ydCggYXNjU29ydCApO1xuXG5cdFx0cmV0dXJuIGludGVyc2VjdHM7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIGFzY1NvcnQoIGEsIGIgKSB7XG5cblx0cmV0dXJuIGEuZGlzdGFuY2UgLSBiLmRpc3RhbmNlO1xuXG59XG5cbmZ1bmN0aW9uIGludGVyc2VjdCggb2JqZWN0LCByYXljYXN0ZXIsIGludGVyc2VjdHMsIHJlY3Vyc2l2ZSApIHtcblxuXHRsZXQgcHJvcGFnYXRlID0gdHJ1ZTtcblxuXHRpZiAoIG9iamVjdC5sYXllcnMudGVzdCggcmF5Y2FzdGVyLmxheWVycyApICkge1xuXG5cdFx0Y29uc3QgcmVzdWx0ID0gb2JqZWN0LnJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApO1xuXG5cdFx0aWYgKCByZXN1bHQgPT09IGZhbHNlICkgcHJvcGFnYXRlID0gZmFsc2U7XG5cblx0fVxuXG5cdGlmICggcHJvcGFnYXRlID09PSB0cnVlICYmIHJlY3Vyc2l2ZSA9PT0gdHJ1ZSApIHtcblxuXHRcdGNvbnN0IGNoaWxkcmVuID0gb2JqZWN0LmNoaWxkcmVuO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0aW50ZXJzZWN0KCBjaGlsZHJlblsgaSBdLCByYXljYXN0ZXIsIGludGVyc2VjdHMsIHRydWUgKTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuLyoqXG4gKiBSZWY6IGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1NwaGVyaWNhbF9jb29yZGluYXRlX3N5c3RlbVxuICpcbiAqIHBoaSAodGhlIHBvbGFyIGFuZ2xlKSBpcyBtZWFzdXJlZCBmcm9tIHRoZSBwb3NpdGl2ZSB5LWF4aXMuIFRoZSBwb3NpdGl2ZSB5LWF4aXMgaXMgdXAuXG4gKiB0aGV0YSAodGhlIGF6aW11dGhhbCBhbmdsZSkgaXMgbWVhc3VyZWQgZnJvbSB0aGUgcG9zaXRpdmUgei1heGlzLlxuICovXG5jbGFzcyBTcGhlcmljYWwge1xuXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBwaGkgPSAwLCB0aGV0YSA9IDAgKSB7XG5cblx0XHR0aGlzLnJhZGl1cyA9IHJhZGl1cztcblx0XHR0aGlzLnBoaSA9IHBoaTsgLy8gcG9sYXIgYW5nbGVcblx0XHR0aGlzLnRoZXRhID0gdGhldGE7IC8vIGF6aW11dGhhbCBhbmdsZVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldCggcmFkaXVzLCBwaGksIHRoZXRhICkge1xuXG5cdFx0dGhpcy5yYWRpdXMgPSByYWRpdXM7XG5cdFx0dGhpcy5waGkgPSBwaGk7XG5cdFx0dGhpcy50aGV0YSA9IHRoZXRhO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvcHkoIG90aGVyICkge1xuXG5cdFx0dGhpcy5yYWRpdXMgPSBvdGhlci5yYWRpdXM7XG5cdFx0dGhpcy5waGkgPSBvdGhlci5waGk7XG5cdFx0dGhpcy50aGV0YSA9IG90aGVyLnRoZXRhO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIHJlc3RyaWN0IHBoaSB0byBiZSBiZXR3ZWVuIEVQUyBhbmQgUEktRVBTXG5cdG1ha2VTYWZlKCkge1xuXG5cdFx0Y29uc3QgRVBTID0gMC4wMDAwMDE7XG5cdFx0dGhpcy5waGkgPSBNYXRoLm1heCggRVBTLCBNYXRoLm1pbiggTWF0aC5QSSAtIEVQUywgdGhpcy5waGkgKSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21WZWN0b3IzKCB2ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuc2V0RnJvbUNhcnRlc2lhbkNvb3Jkcyggdi54LCB2LnksIHYueiApO1xuXG5cdH1cblxuXHRzZXRGcm9tQ2FydGVzaWFuQ29vcmRzKCB4LCB5LCB6ICkge1xuXG5cdFx0dGhpcy5yYWRpdXMgPSBNYXRoLnNxcnQoIHggKiB4ICsgeSAqIHkgKyB6ICogeiApO1xuXG5cdFx0aWYgKCB0aGlzLnJhZGl1cyA9PT0gMCApIHtcblxuXHRcdFx0dGhpcy50aGV0YSA9IDA7XG5cdFx0XHR0aGlzLnBoaSA9IDA7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLnRoZXRhID0gTWF0aC5hdGFuMiggeCwgeiApO1xuXHRcdFx0dGhpcy5waGkgPSBNYXRoLmFjb3MoIGNsYW1wKCB5IC8gdGhpcy5yYWRpdXMsIC0gMSwgMSApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG59XG5cbi8qKlxuICogUmVmOiBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9DeWxpbmRyaWNhbF9jb29yZGluYXRlX3N5c3RlbVxuICovXG5cbmNsYXNzIEN5bGluZHJpY2FsIHtcblxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgdGhldGEgPSAwLCB5ID0gMCApIHtcblxuXHRcdHRoaXMucmFkaXVzID0gcmFkaXVzOyAvLyBkaXN0YW5jZSBmcm9tIHRoZSBvcmlnaW4gdG8gYSBwb2ludCBpbiB0aGUgeC16IHBsYW5lXG5cdFx0dGhpcy50aGV0YSA9IHRoZXRhOyAvLyBjb3VudGVyY2xvY2t3aXNlIGFuZ2xlIGluIHRoZSB4LXogcGxhbmUgbWVhc3VyZWQgaW4gcmFkaWFucyBmcm9tIHRoZSBwb3NpdGl2ZSB6LWF4aXNcblx0XHR0aGlzLnkgPSB5OyAvLyBoZWlnaHQgYWJvdmUgdGhlIHgteiBwbGFuZVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldCggcmFkaXVzLCB0aGV0YSwgeSApIHtcblxuXHRcdHRoaXMucmFkaXVzID0gcmFkaXVzO1xuXHRcdHRoaXMudGhldGEgPSB0aGV0YTtcblx0XHR0aGlzLnkgPSB5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvcHkoIG90aGVyICkge1xuXG5cdFx0dGhpcy5yYWRpdXMgPSBvdGhlci5yYWRpdXM7XG5cdFx0dGhpcy50aGV0YSA9IG90aGVyLnRoZXRhO1xuXHRcdHRoaXMueSA9IG90aGVyLnk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbVZlY3RvcjMoIHYgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5zZXRGcm9tQ2FydGVzaWFuQ29vcmRzKCB2LngsIHYueSwgdi56ICk7XG5cblx0fVxuXG5cdHNldEZyb21DYXJ0ZXNpYW5Db29yZHMoIHgsIHksIHogKSB7XG5cblx0XHR0aGlzLnJhZGl1cyA9IE1hdGguc3FydCggeCAqIHggKyB6ICogeiApO1xuXHRcdHRoaXMudGhldGEgPSBNYXRoLmF0YW4yKCB4LCB6ICk7XG5cdFx0dGhpcy55ID0geTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcblxuXHR9XG5cbn1cblxuY29uc3QgX3ZlY3RvciQ0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xuXG5jbGFzcyBCb3gyIHtcblxuXHRjb25zdHJ1Y3RvciggbWluID0gbmV3IFZlY3RvcjIoICsgSW5maW5pdHksICsgSW5maW5pdHkgKSwgbWF4ID0gbmV3IFZlY3RvcjIoIC0gSW5maW5pdHksIC0gSW5maW5pdHkgKSApIHtcblxuXHRcdHRoaXMuaXNCb3gyID0gdHJ1ZTtcblxuXHRcdHRoaXMubWluID0gbWluO1xuXHRcdHRoaXMubWF4ID0gbWF4O1xuXG5cdH1cblxuXHRzZXQoIG1pbiwgbWF4ICkge1xuXG5cdFx0dGhpcy5taW4uY29weSggbWluICk7XG5cdFx0dGhpcy5tYXguY29weSggbWF4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbVBvaW50cyggcG9pbnRzICkge1xuXG5cdFx0dGhpcy5tYWtlRW1wdHkoKTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBwb2ludHMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggcG9pbnRzWyBpIF0gKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tQ2VudGVyQW5kU2l6ZSggY2VudGVyLCBzaXplICkge1xuXG5cdFx0Y29uc3QgaGFsZlNpemUgPSBfdmVjdG9yJDQuY29weSggc2l6ZSApLm11bHRpcGx5U2NhbGFyKCAwLjUgKTtcblx0XHR0aGlzLm1pbi5jb3B5KCBjZW50ZXIgKS5zdWIoIGhhbGZTaXplICk7XG5cdFx0dGhpcy5tYXguY29weSggY2VudGVyICkuYWRkKCBoYWxmU2l6ZSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxuXHRjb3B5KCBib3ggKSB7XG5cblx0XHR0aGlzLm1pbi5jb3B5KCBib3gubWluICk7XG5cdFx0dGhpcy5tYXguY29weSggYm94Lm1heCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1ha2VFbXB0eSgpIHtcblxuXHRcdHRoaXMubWluLnggPSB0aGlzLm1pbi55ID0gKyBJbmZpbml0eTtcblx0XHR0aGlzLm1heC54ID0gdGhpcy5tYXgueSA9IC0gSW5maW5pdHk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0aXNFbXB0eSgpIHtcblxuXHRcdC8vIHRoaXMgaXMgYSBtb3JlIHJvYnVzdCBjaGVjayBmb3IgZW1wdHkgdGhhbiAoIHZvbHVtZSA8PSAwICkgYmVjYXVzZSB2b2x1bWUgY2FuIGdldCBwb3NpdGl2ZSB3aXRoIHR3byBuZWdhdGl2ZSBheGVzXG5cblx0XHRyZXR1cm4gKCB0aGlzLm1heC54IDwgdGhpcy5taW4ueCApIHx8ICggdGhpcy5tYXgueSA8IHRoaXMubWluLnkgKTtcblxuXHR9XG5cblx0Z2V0Q2VudGVyKCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5pc0VtcHR5KCkgPyB0YXJnZXQuc2V0KCAwLCAwICkgOiB0YXJnZXQuYWRkVmVjdG9ycyggdGhpcy5taW4sIHRoaXMubWF4ICkubXVsdGlwbHlTY2FsYXIoIDAuNSApO1xuXG5cdH1cblxuXHRnZXRTaXplKCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5pc0VtcHR5KCkgPyB0YXJnZXQuc2V0KCAwLCAwICkgOiB0YXJnZXQuc3ViVmVjdG9ycyggdGhpcy5tYXgsIHRoaXMubWluICk7XG5cblx0fVxuXG5cdGV4cGFuZEJ5UG9pbnQoIHBvaW50ICkge1xuXG5cdFx0dGhpcy5taW4ubWluKCBwb2ludCApO1xuXHRcdHRoaXMubWF4Lm1heCggcG9pbnQgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRleHBhbmRCeVZlY3RvciggdmVjdG9yICkge1xuXG5cdFx0dGhpcy5taW4uc3ViKCB2ZWN0b3IgKTtcblx0XHR0aGlzLm1heC5hZGQoIHZlY3RvciApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGV4cGFuZEJ5U2NhbGFyKCBzY2FsYXIgKSB7XG5cblx0XHR0aGlzLm1pbi5hZGRTY2FsYXIoIC0gc2NhbGFyICk7XG5cdFx0dGhpcy5tYXguYWRkU2NhbGFyKCBzY2FsYXIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb250YWluc1BvaW50KCBwb2ludCApIHtcblxuXHRcdHJldHVybiBwb2ludC54IDwgdGhpcy5taW4ueCB8fCBwb2ludC54ID4gdGhpcy5tYXgueCB8fFxuXHRcdFx0cG9pbnQueSA8IHRoaXMubWluLnkgfHwgcG9pbnQueSA+IHRoaXMubWF4LnkgPyBmYWxzZSA6IHRydWU7XG5cblx0fVxuXG5cdGNvbnRhaW5zQm94KCBib3ggKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5taW4ueCA8PSBib3gubWluLnggJiYgYm94Lm1heC54IDw9IHRoaXMubWF4LnggJiZcblx0XHRcdHRoaXMubWluLnkgPD0gYm94Lm1pbi55ICYmIGJveC5tYXgueSA8PSB0aGlzLm1heC55O1xuXG5cdH1cblxuXHRnZXRQYXJhbWV0ZXIoIHBvaW50LCB0YXJnZXQgKSB7XG5cblx0XHQvLyBUaGlzIGNhbiBwb3RlbnRpYWxseSBoYXZlIGEgZGl2aWRlIGJ5IHplcm8gaWYgdGhlIGJveFxuXHRcdC8vIGhhcyBhIHNpemUgZGltZW5zaW9uIG9mIDAuXG5cblx0XHRyZXR1cm4gdGFyZ2V0LnNldChcblx0XHRcdCggcG9pbnQueCAtIHRoaXMubWluLnggKSAvICggdGhpcy5tYXgueCAtIHRoaXMubWluLnggKSxcblx0XHRcdCggcG9pbnQueSAtIHRoaXMubWluLnkgKSAvICggdGhpcy5tYXgueSAtIHRoaXMubWluLnkgKVxuXHRcdCk7XG5cblx0fVxuXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcblxuXHRcdC8vIHVzaW5nIDQgc3BsaXR0aW5nIHBsYW5lcyB0byBydWxlIG91dCBpbnRlcnNlY3Rpb25zXG5cblx0XHRyZXR1cm4gYm94Lm1heC54IDwgdGhpcy5taW4ueCB8fCBib3gubWluLnggPiB0aGlzLm1heC54IHx8XG5cdFx0XHRib3gubWF4LnkgPCB0aGlzLm1pbi55IHx8IGJveC5taW4ueSA+IHRoaXMubWF4LnkgPyBmYWxzZSA6IHRydWU7XG5cblx0fVxuXG5cdGNsYW1wUG9pbnQoIHBvaW50LCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHBvaW50ICkuY2xhbXAoIHRoaXMubWluLCB0aGlzLm1heCApO1xuXG5cdH1cblxuXHRkaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuY2xhbXBQb2ludCggcG9pbnQsIF92ZWN0b3IkNCApLmRpc3RhbmNlVG8oIHBvaW50ICk7XG5cblx0fVxuXG5cdGludGVyc2VjdCggYm94ICkge1xuXG5cdFx0dGhpcy5taW4ubWF4KCBib3gubWluICk7XG5cdFx0dGhpcy5tYXgubWluKCBib3gubWF4ICk7XG5cblx0XHRpZiAoIHRoaXMuaXNFbXB0eSgpICkgdGhpcy5tYWtlRW1wdHkoKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR1bmlvbiggYm94ICkge1xuXG5cdFx0dGhpcy5taW4ubWluKCBib3gubWluICk7XG5cdFx0dGhpcy5tYXgubWF4KCBib3gubWF4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJhbnNsYXRlKCBvZmZzZXQgKSB7XG5cblx0XHR0aGlzLm1pbi5hZGQoIG9mZnNldCApO1xuXHRcdHRoaXMubWF4LmFkZCggb2Zmc2V0ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXF1YWxzKCBib3ggKSB7XG5cblx0XHRyZXR1cm4gYm94Lm1pbi5lcXVhbHMoIHRoaXMubWluICkgJiYgYm94Lm1heC5lcXVhbHMoIHRoaXMubWF4ICk7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9zdGFydFAgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfc3RhcnRFbmQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNsYXNzIExpbmUzIHtcblxuXHRjb25zdHJ1Y3Rvciggc3RhcnQgPSBuZXcgVmVjdG9yMygpLCBlbmQgPSBuZXcgVmVjdG9yMygpICkge1xuXG5cdFx0dGhpcy5zdGFydCA9IHN0YXJ0O1xuXHRcdHRoaXMuZW5kID0gZW5kO1xuXG5cdH1cblxuXHRzZXQoIHN0YXJ0LCBlbmQgKSB7XG5cblx0XHR0aGlzLnN0YXJ0LmNvcHkoIHN0YXJ0ICk7XG5cdFx0dGhpcy5lbmQuY29weSggZW5kICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weSggbGluZSApIHtcblxuXHRcdHRoaXMuc3RhcnQuY29weSggbGluZS5zdGFydCApO1xuXHRcdHRoaXMuZW5kLmNvcHkoIGxpbmUuZW5kICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0Q2VudGVyKCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LmFkZFZlY3RvcnMoIHRoaXMuc3RhcnQsIHRoaXMuZW5kICkubXVsdGlwbHlTY2FsYXIoIDAuNSApO1xuXG5cdH1cblxuXHRkZWx0YSggdGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIHRhcmdldC5zdWJWZWN0b3JzKCB0aGlzLmVuZCwgdGhpcy5zdGFydCApO1xuXG5cdH1cblxuXHRkaXN0YW5jZVNxKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuc3RhcnQuZGlzdGFuY2VUb1NxdWFyZWQoIHRoaXMuZW5kICk7XG5cblx0fVxuXG5cdGRpc3RhbmNlKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuc3RhcnQuZGlzdGFuY2VUbyggdGhpcy5lbmQgKTtcblxuXHR9XG5cblx0YXQoIHQsIHRhcmdldCApIHtcblxuXHRcdHJldHVybiB0aGlzLmRlbHRhKCB0YXJnZXQgKS5tdWx0aXBseVNjYWxhciggdCApLmFkZCggdGhpcy5zdGFydCApO1xuXG5cdH1cblxuXHRjbG9zZXN0UG9pbnRUb1BvaW50UGFyYW1ldGVyKCBwb2ludCwgY2xhbXBUb0xpbmUgKSB7XG5cblx0XHRfc3RhcnRQLnN1YlZlY3RvcnMoIHBvaW50LCB0aGlzLnN0YXJ0ICk7XG5cdFx0X3N0YXJ0RW5kLnN1YlZlY3RvcnMoIHRoaXMuZW5kLCB0aGlzLnN0YXJ0ICk7XG5cblx0XHRjb25zdCBzdGFydEVuZDIgPSBfc3RhcnRFbmQuZG90KCBfc3RhcnRFbmQgKTtcblx0XHRjb25zdCBzdGFydEVuZF9zdGFydFAgPSBfc3RhcnRFbmQuZG90KCBfc3RhcnRQICk7XG5cblx0XHRsZXQgdCA9IHN0YXJ0RW5kX3N0YXJ0UCAvIHN0YXJ0RW5kMjtcblxuXHRcdGlmICggY2xhbXBUb0xpbmUgKSB7XG5cblx0XHRcdHQgPSBjbGFtcCggdCwgMCwgMSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHQ7XG5cblx0fVxuXG5cdGNsb3Nlc3RQb2ludFRvUG9pbnQoIHBvaW50LCBjbGFtcFRvTGluZSwgdGFyZ2V0ICkge1xuXG5cdFx0Y29uc3QgdCA9IHRoaXMuY2xvc2VzdFBvaW50VG9Qb2ludFBhcmFtZXRlciggcG9pbnQsIGNsYW1wVG9MaW5lICk7XG5cblx0XHRyZXR1cm4gdGhpcy5kZWx0YSggdGFyZ2V0ICkubXVsdGlwbHlTY2FsYXIoIHQgKS5hZGQoIHRoaXMuc3RhcnQgKTtcblxuXHR9XG5cblx0YXBwbHlNYXRyaXg0KCBtYXRyaXggKSB7XG5cblx0XHR0aGlzLnN0YXJ0LmFwcGx5TWF0cml4NCggbWF0cml4ICk7XG5cdFx0dGhpcy5lbmQuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRlcXVhbHMoIGxpbmUgKSB7XG5cblx0XHRyZXR1cm4gbGluZS5zdGFydC5lcXVhbHMoIHRoaXMuc3RhcnQgKSAmJiBsaW5lLmVuZC5lcXVhbHMoIHRoaXMuZW5kICk7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxufVxuXG5jb25zdCBfdmVjdG9yJDMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNsYXNzIFNwb3RMaWdodEhlbHBlciBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvciggbGlnaHQsIGNvbG9yICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMubGlnaHQgPSBsaWdodDtcblxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0dGhpcy5jb2xvciA9IGNvbG9yO1xuXG5cdFx0dGhpcy50eXBlID0gJ1Nwb3RMaWdodEhlbHBlcic7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXG5cdFx0Y29uc3QgcG9zaXRpb25zID0gW1xuXHRcdFx0MCwgMCwgMCwgXHQwLCAwLCAxLFxuXHRcdFx0MCwgMCwgMCwgXHQxLCAwLCAxLFxuXHRcdFx0MCwgMCwgMCxcdC0gMSwgMCwgMSxcblx0XHRcdDAsIDAsIDAsIFx0MCwgMSwgMSxcblx0XHRcdDAsIDAsIDAsIFx0MCwgLSAxLCAxXG5cdFx0XTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaiA9IDEsIGwgPSAzMjsgaSA8IGw7IGkgKyssIGogKysgKSB7XG5cblx0XHRcdGNvbnN0IHAxID0gKCBpIC8gbCApICogTWF0aC5QSSAqIDI7XG5cdFx0XHRjb25zdCBwMiA9ICggaiAvIGwgKSAqIE1hdGguUEkgKiAyO1xuXG5cdFx0XHRwb3NpdGlvbnMucHVzaChcblx0XHRcdFx0TWF0aC5jb3MoIHAxICksIE1hdGguc2luKCBwMSApLCAxLFxuXHRcdFx0XHRNYXRoLmNvcyggcDIgKSwgTWF0aC5zaW4oIHAyICksIDFcblx0XHRcdCk7XG5cblx0XHR9XG5cblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbnMsIDMgKSApO1xuXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgZm9nOiBmYWxzZSwgdG9uZU1hcHBlZDogZmFsc2UgfSApO1xuXG5cdFx0dGhpcy5jb25lID0gbmV3IExpbmVTZWdtZW50cyggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cdFx0dGhpcy5hZGQoIHRoaXMuY29uZSApO1xuXG5cdFx0dGhpcy51cGRhdGUoKTtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuY29uZS5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5jb25lLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblxuXHR9XG5cblx0dXBkYXRlKCkge1xuXG5cdFx0dGhpcy5saWdodC51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblx0XHR0aGlzLmxpZ2h0LnRhcmdldC51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdC8vIHVwZGF0ZSB0aGUgbG9jYWwgbWF0cml4IGJhc2VkIG9uIHRoZSBwYXJlbnQgYW5kIGxpZ2h0IHRhcmdldCB0cmFuc2Zvcm1zXG5cdFx0aWYgKCB0aGlzLnBhcmVudCApIHtcblxuXHRcdFx0dGhpcy5wYXJlbnQudXBkYXRlV29ybGRNYXRyaXgoIHRydWUgKTtcblxuXHRcdFx0dGhpcy5tYXRyaXhcblx0XHRcdFx0LmNvcHkoIHRoaXMucGFyZW50Lm1hdHJpeFdvcmxkIClcblx0XHRcdFx0LmludmVydCgpXG5cdFx0XHRcdC5tdWx0aXBseSggdGhpcy5saWdodC5tYXRyaXhXb3JsZCApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhpcy5tYXRyaXguY29weSggdGhpcy5saWdodC5tYXRyaXhXb3JsZCApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5tYXRyaXhXb3JsZC5jb3B5KCB0aGlzLmxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cblx0XHRjb25zdCBjb25lTGVuZ3RoID0gdGhpcy5saWdodC5kaXN0YW5jZSA/IHRoaXMubGlnaHQuZGlzdGFuY2UgOiAxMDAwO1xuXHRcdGNvbnN0IGNvbmVXaWR0aCA9IGNvbmVMZW5ndGggKiBNYXRoLnRhbiggdGhpcy5saWdodC5hbmdsZSApO1xuXG5cdFx0dGhpcy5jb25lLnNjYWxlLnNldCggY29uZVdpZHRoLCBjb25lV2lkdGgsIGNvbmVMZW5ndGggKTtcblxuXHRcdF92ZWN0b3IkMy5zZXRGcm9tTWF0cml4UG9zaXRpb24oIHRoaXMubGlnaHQudGFyZ2V0Lm1hdHJpeFdvcmxkICk7XG5cblx0XHR0aGlzLmNvbmUubG9va0F0KCBfdmVjdG9yJDMgKTtcblxuXHRcdGlmICggdGhpcy5jb2xvciAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLmNvbmUubWF0ZXJpYWwuY29sb3Iuc2V0KCB0aGlzLmNvbG9yICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLmNvbmUubWF0ZXJpYWwuY29sb3IuY29weSggdGhpcy5saWdodC5jb2xvciApO1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5jb25zdCBfdmVjdG9yJDIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfYm9uZU1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF9tYXRyaXhXb3JsZEludiA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcblxuXG5jbGFzcyBTa2VsZXRvbkhlbHBlciBleHRlbmRzIExpbmVTZWdtZW50cyB7XG5cblx0Y29uc3RydWN0b3IoIG9iamVjdCApIHtcblxuXHRcdGNvbnN0IGJvbmVzID0gZ2V0Qm9uZUxpc3QoIG9iamVjdCApO1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcblxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0Y29uc3QgY29sb3JzID0gW107XG5cblx0XHRjb25zdCBjb2xvcjEgPSBuZXcgQ29sb3IoIDAsIDAsIDEgKTtcblx0XHRjb25zdCBjb2xvcjIgPSBuZXcgQ29sb3IoIDAsIDEsIDAgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGJvbmVzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgYm9uZSA9IGJvbmVzWyBpIF07XG5cblx0XHRcdGlmICggYm9uZS5wYXJlbnQgJiYgYm9uZS5wYXJlbnQuaXNCb25lICkge1xuXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIDAsIDAsIDAgKTtcblx0XHRcdFx0dmVydGljZXMucHVzaCggMCwgMCwgMCApO1xuXHRcdFx0XHRjb2xvcnMucHVzaCggY29sb3IxLnIsIGNvbG9yMS5nLCBjb2xvcjEuYiApO1xuXHRcdFx0XHRjb2xvcnMucHVzaCggY29sb3IyLnIsIGNvbG9yMi5nLCBjb2xvcjIuYiApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnY29sb3InLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggY29sb3JzLCAzICkgKTtcblxuXHRcdGNvbnN0IG1hdGVyaWFsID0gbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IHZlcnRleENvbG9yczogdHJ1ZSwgZGVwdGhUZXN0OiBmYWxzZSwgZGVwdGhXcml0ZTogZmFsc2UsIHRvbmVNYXBwZWQ6IGZhbHNlLCB0cmFuc3BhcmVudDogdHJ1ZSB9ICk7XG5cblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cblx0XHR0aGlzLmlzU2tlbGV0b25IZWxwZXIgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ1NrZWxldG9uSGVscGVyJztcblxuXHRcdHRoaXMucm9vdCA9IG9iamVjdDtcblx0XHR0aGlzLmJvbmVzID0gYm9uZXM7XG5cblx0XHR0aGlzLm1hdHJpeCA9IG9iamVjdC5tYXRyaXhXb3JsZDtcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblxuXHR9XG5cblx0dXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICkge1xuXG5cdFx0Y29uc3QgYm9uZXMgPSB0aGlzLmJvbmVzO1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XG5cblx0XHRfbWF0cml4V29ybGRJbnYuY29weSggdGhpcy5yb290Lm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGogPSAwOyBpIDwgYm9uZXMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBib25lID0gYm9uZXNbIGkgXTtcblxuXHRcdFx0aWYgKCBib25lLnBhcmVudCAmJiBib25lLnBhcmVudC5pc0JvbmUgKSB7XG5cblx0XHRcdFx0X2JvbmVNYXRyaXgubXVsdGlwbHlNYXRyaWNlcyggX21hdHJpeFdvcmxkSW52LCBib25lLm1hdHJpeFdvcmxkICk7XG5cdFx0XHRcdF92ZWN0b3IkMi5zZXRGcm9tTWF0cml4UG9zaXRpb24oIF9ib25lTWF0cml4ICk7XG5cdFx0XHRcdHBvc2l0aW9uLnNldFhZWiggaiwgX3ZlY3RvciQyLngsIF92ZWN0b3IkMi55LCBfdmVjdG9yJDIueiApO1xuXG5cdFx0XHRcdF9ib25lTWF0cml4Lm11bHRpcGx5TWF0cmljZXMoIF9tYXRyaXhXb3JsZEludiwgYm9uZS5wYXJlbnQubWF0cml4V29ybGQgKTtcblx0XHRcdFx0X3ZlY3RvciQyLnNldEZyb21NYXRyaXhQb3NpdGlvbiggX2JvbmVNYXRyaXggKTtcblx0XHRcdFx0cG9zaXRpb24uc2V0WFlaKCBqICsgMSwgX3ZlY3RvciQyLngsIF92ZWN0b3IkMi55LCBfdmVjdG9yJDIueiApO1xuXG5cdFx0XHRcdGogKz0gMjtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Z2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICkubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0c3VwZXIudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLmdlb21ldHJ5LmRpc3Bvc2UoKTtcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblxuXHR9XG5cbn1cblxuXG5mdW5jdGlvbiBnZXRCb25lTGlzdCggb2JqZWN0ICkge1xuXG5cdGNvbnN0IGJvbmVMaXN0ID0gW107XG5cblx0aWYgKCBvYmplY3QuaXNCb25lID09PSB0cnVlICkge1xuXG5cdFx0Ym9uZUxpc3QucHVzaCggb2JqZWN0ICk7XG5cblx0fVxuXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IG9iamVjdC5jaGlsZHJlbi5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRib25lTGlzdC5wdXNoLmFwcGx5KCBib25lTGlzdCwgZ2V0Qm9uZUxpc3QoIG9iamVjdC5jaGlsZHJlblsgaSBdICkgKTtcblxuXHR9XG5cblx0cmV0dXJuIGJvbmVMaXN0O1xuXG59XG5cbmNsYXNzIFBvaW50TGlnaHRIZWxwZXIgZXh0ZW5kcyBNZXNoIHtcblxuXHRjb25zdHJ1Y3RvciggbGlnaHQsIHNwaGVyZVNpemUsIGNvbG9yICkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgU3BoZXJlR2VvbWV0cnkoIHNwaGVyZVNpemUsIDQsIDIgKTtcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBNZXNoQmFzaWNNYXRlcmlhbCggeyB3aXJlZnJhbWU6IHRydWUsIGZvZzogZmFsc2UsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKTtcblxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblxuXHRcdHRoaXMubGlnaHQgPSBsaWdodDtcblxuXHRcdHRoaXMuY29sb3IgPSBjb2xvcjtcblxuXHRcdHRoaXMudHlwZSA9ICdQb2ludExpZ2h0SGVscGVyJztcblxuXHRcdHRoaXMubWF0cml4ID0gdGhpcy5saWdodC5tYXRyaXhXb3JsZDtcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblxuXHRcdHRoaXMudXBkYXRlKCk7XG5cblxuXHRcdC8qXG5cdC8vIFRPRE86IGRlbGV0ZSB0aGlzIGNvbW1lbnQ/XG5cdGNvbnN0IGRpc3RhbmNlR2VvbWV0cnkgPSBuZXcgVEhSRUUuSWNvc2FoZWRyb25HZW9tZXRyeSggMSwgMiApO1xuXHRjb25zdCBkaXN0YW5jZU1hdGVyaWFsID0gbmV3IFRIUkVFLk1lc2hCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBoZXhDb2xvciwgZm9nOiBmYWxzZSwgd2lyZWZyYW1lOiB0cnVlLCBvcGFjaXR5OiAwLjEsIHRyYW5zcGFyZW50OiB0cnVlIH0gKTtcblxuXHR0aGlzLmxpZ2h0U3BoZXJlID0gbmV3IFRIUkVFLk1lc2goIGJ1bGJHZW9tZXRyeSwgYnVsYk1hdGVyaWFsICk7XG5cdHRoaXMubGlnaHREaXN0YW5jZSA9IG5ldyBUSFJFRS5NZXNoKCBkaXN0YW5jZUdlb21ldHJ5LCBkaXN0YW5jZU1hdGVyaWFsICk7XG5cblx0Y29uc3QgZCA9IGxpZ2h0LmRpc3RhbmNlO1xuXG5cdGlmICggZCA9PT0gMC4wICkge1xuXG5cdFx0dGhpcy5saWdodERpc3RhbmNlLnZpc2libGUgPSBmYWxzZTtcblxuXHR9IGVsc2Uge1xuXG5cdFx0dGhpcy5saWdodERpc3RhbmNlLnNjYWxlLnNldCggZCwgZCwgZCApO1xuXG5cdH1cblxuXHR0aGlzLmFkZCggdGhpcy5saWdodERpc3RhbmNlICk7XG5cdCovXG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLmdlb21ldHJ5LmRpc3Bvc2UoKTtcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblxuXHR9XG5cblx0dXBkYXRlKCkge1xuXG5cdFx0dGhpcy5saWdodC51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdGlmICggdGhpcy5jb2xvciAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLm1hdGVyaWFsLmNvbG9yLnNldCggdGhpcy5jb2xvciApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhpcy5tYXRlcmlhbC5jb2xvci5jb3B5KCB0aGlzLmxpZ2h0LmNvbG9yICk7XG5cblx0XHR9XG5cblx0XHQvKlxuXHRcdGNvbnN0IGQgPSB0aGlzLmxpZ2h0LmRpc3RhbmNlO1xuXG5cdFx0aWYgKCBkID09PSAwLjAgKSB7XG5cblx0XHRcdHRoaXMubGlnaHREaXN0YW5jZS52aXNpYmxlID0gZmFsc2U7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLmxpZ2h0RGlzdGFuY2UudmlzaWJsZSA9IHRydWU7XG5cdFx0XHR0aGlzLmxpZ2h0RGlzdGFuY2Uuc2NhbGUuc2V0KCBkLCBkLCBkICk7XG5cblx0XHR9XG5cdFx0Ki9cblxuXHR9XG5cbn1cblxuY29uc3QgX3ZlY3RvciQxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2NvbG9yMSA9IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCk7XG5jb25zdCBfY29sb3IyID0gLypAX19QVVJFX18qLyBuZXcgQ29sb3IoKTtcblxuY2xhc3MgSGVtaXNwaGVyZUxpZ2h0SGVscGVyIGV4dGVuZHMgT2JqZWN0M0Qge1xuXG5cdGNvbnN0cnVjdG9yKCBsaWdodCwgc2l6ZSwgY29sb3IgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5saWdodCA9IGxpZ2h0O1xuXG5cdFx0dGhpcy5tYXRyaXggPSBsaWdodC5tYXRyaXhXb3JsZDtcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblxuXHRcdHRoaXMuY29sb3IgPSBjb2xvcjtcblxuXHRcdHRoaXMudHlwZSA9ICdIZW1pc3BoZXJlTGlnaHRIZWxwZXInO1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgT2N0YWhlZHJvbkdlb21ldHJ5KCBzaXplICk7XG5cdFx0Z2VvbWV0cnkucm90YXRlWSggTWF0aC5QSSAqIDAuNSApO1xuXG5cdFx0dGhpcy5tYXRlcmlhbCA9IG5ldyBNZXNoQmFzaWNNYXRlcmlhbCggeyB3aXJlZnJhbWU6IHRydWUsIGZvZzogZmFsc2UsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKTtcblx0XHRpZiAoIHRoaXMuY29sb3IgPT09IHVuZGVmaW5lZCApIHRoaXMubWF0ZXJpYWwudmVydGV4Q29sb3JzID0gdHJ1ZTtcblxuXHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XG5cdFx0Y29uc3QgY29sb3JzID0gbmV3IEZsb2F0MzJBcnJheSggcG9zaXRpb24uY291bnQgKiAzICk7XG5cblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdjb2xvcicsIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGNvbG9ycywgMyApICk7XG5cblx0XHR0aGlzLmFkZCggbmV3IE1lc2goIGdlb21ldHJ5LCB0aGlzLm1hdGVyaWFsICkgKTtcblxuXHRcdHRoaXMudXBkYXRlKCk7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLmNoaWxkcmVuWyAwIF0uZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXHRcdHRoaXMuY2hpbGRyZW5bIDAgXS5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0fVxuXG5cdHVwZGF0ZSgpIHtcblxuXHRcdGNvbnN0IG1lc2ggPSB0aGlzLmNoaWxkcmVuWyAwIF07XG5cblx0XHRpZiAoIHRoaXMuY29sb3IgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGhpcy5tYXRlcmlhbC5jb2xvci5zZXQoIHRoaXMuY29sb3IgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGNvbnN0IGNvbG9ycyA9IG1lc2guZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAnY29sb3InICk7XG5cblx0XHRcdF9jb2xvcjEuY29weSggdGhpcy5saWdodC5jb2xvciApO1xuXHRcdFx0X2NvbG9yMi5jb3B5KCB0aGlzLmxpZ2h0Lmdyb3VuZENvbG9yICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNvbG9ycy5jb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgY29sb3IgPSAoIGkgPCAoIGwgLyAyICkgKSA/IF9jb2xvcjEgOiBfY29sb3IyO1xuXG5cdFx0XHRcdGNvbG9ycy5zZXRYWVooIGksIGNvbG9yLnIsIGNvbG9yLmcsIGNvbG9yLmIgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb2xvcnMubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5saWdodC51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdG1lc2gubG9va0F0KCBfdmVjdG9yJDEuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLmxpZ2h0Lm1hdHJpeFdvcmxkICkubmVnYXRlKCkgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgR3JpZEhlbHBlciBleHRlbmRzIExpbmVTZWdtZW50cyB7XG5cblx0Y29uc3RydWN0b3IoIHNpemUgPSAxMCwgZGl2aXNpb25zID0gMTAsIGNvbG9yMSA9IDB4NDQ0NDQ0LCBjb2xvcjIgPSAweDg4ODg4OCApIHtcblxuXHRcdGNvbG9yMSA9IG5ldyBDb2xvciggY29sb3IxICk7XG5cdFx0Y29sb3IyID0gbmV3IENvbG9yKCBjb2xvcjIgKTtcblxuXHRcdGNvbnN0IGNlbnRlciA9IGRpdmlzaW9ucyAvIDI7XG5cdFx0Y29uc3Qgc3RlcCA9IHNpemUgLyBkaXZpc2lvbnM7XG5cdFx0Y29uc3QgaGFsZlNpemUgPSBzaXplIC8gMjtcblxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW10sIGNvbG9ycyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBqID0gMCwgayA9IC0gaGFsZlNpemU7IGkgPD0gZGl2aXNpb25zOyBpICsrLCBrICs9IHN0ZXAgKSB7XG5cblx0XHRcdHZlcnRpY2VzLnB1c2goIC0gaGFsZlNpemUsIDAsIGssIGhhbGZTaXplLCAwLCBrICk7XG5cdFx0XHR2ZXJ0aWNlcy5wdXNoKCBrLCAwLCAtIGhhbGZTaXplLCBrLCAwLCBoYWxmU2l6ZSApO1xuXG5cdFx0XHRjb25zdCBjb2xvciA9IGkgPT09IGNlbnRlciA/IGNvbG9yMSA6IGNvbG9yMjtcblxuXHRcdFx0Y29sb3IudG9BcnJheSggY29sb3JzLCBqICk7IGogKz0gMztcblx0XHRcdGNvbG9yLnRvQXJyYXkoIGNvbG9ycywgaiApOyBqICs9IDM7XG5cdFx0XHRjb2xvci50b0FycmF5KCBjb2xvcnMsIGogKTsgaiArPSAzO1xuXHRcdFx0Y29sb3IudG9BcnJheSggY29sb3JzLCBqICk7IGogKz0gMztcblxuXHRcdH1cblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2NvbG9yJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGNvbG9ycywgMyApICk7XG5cblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyB2ZXJ0ZXhDb2xvcnM6IHRydWUsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKTtcblxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblxuXHRcdHRoaXMudHlwZSA9ICdHcmlkSGVscGVyJztcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXG5cdH1cblxufVxuXG5jbGFzcyBQb2xhckdyaWRIZWxwZXIgZXh0ZW5kcyBMaW5lU2VnbWVudHMge1xuXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxMCwgc2VjdG9ycyA9IDE2LCByaW5ncyA9IDgsIGRpdmlzaW9ucyA9IDY0LCBjb2xvcjEgPSAweDQ0NDQ0NCwgY29sb3IyID0gMHg4ODg4ODggKSB7XG5cblx0XHRjb2xvcjEgPSBuZXcgQ29sb3IoIGNvbG9yMSApO1xuXHRcdGNvbG9yMiA9IG5ldyBDb2xvciggY29sb3IyICk7XG5cblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xuXHRcdGNvbnN0IGNvbG9ycyA9IFtdO1xuXG5cdFx0Ly8gY3JlYXRlIHRoZSBzZWN0b3JzXG5cblx0XHRpZiAoIHNlY3RvcnMgPiAxICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzZWN0b3JzOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHYgPSAoIGkgLyBzZWN0b3JzICkgKiAoIE1hdGguUEkgKiAyICk7XG5cblx0XHRcdFx0Y29uc3QgeCA9IE1hdGguc2luKCB2ICkgKiByYWRpdXM7XG5cdFx0XHRcdGNvbnN0IHogPSBNYXRoLmNvcyggdiApICogcmFkaXVzO1xuXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIDAsIDAsIDAgKTtcblx0XHRcdFx0dmVydGljZXMucHVzaCggeCwgMCwgeiApO1xuXG5cdFx0XHRcdGNvbnN0IGNvbG9yID0gKCBpICYgMSApID8gY29sb3IxIDogY29sb3IyO1xuXG5cdFx0XHRcdGNvbG9ycy5wdXNoKCBjb2xvci5yLCBjb2xvci5nLCBjb2xvci5iICk7XG5cdFx0XHRcdGNvbG9ycy5wdXNoKCBjb2xvci5yLCBjb2xvci5nLCBjb2xvci5iICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGNyZWF0ZSB0aGUgcmluZ3NcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHJpbmdzOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBjb2xvciA9ICggaSAmIDEgKSA/IGNvbG9yMSA6IGNvbG9yMjtcblxuXHRcdFx0Y29uc3QgciA9IHJhZGl1cyAtICggcmFkaXVzIC8gcmluZ3MgKiBpICk7XG5cblx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IGRpdmlzaW9uczsgaiArKyApIHtcblxuXHRcdFx0XHQvLyBmaXJzdCB2ZXJ0ZXhcblxuXHRcdFx0XHRsZXQgdiA9ICggaiAvIGRpdmlzaW9ucyApICogKCBNYXRoLlBJICogMiApO1xuXG5cdFx0XHRcdGxldCB4ID0gTWF0aC5zaW4oIHYgKSAqIHI7XG5cdFx0XHRcdGxldCB6ID0gTWF0aC5jb3MoIHYgKSAqIHI7XG5cblx0XHRcdFx0dmVydGljZXMucHVzaCggeCwgMCwgeiApO1xuXHRcdFx0XHRjb2xvcnMucHVzaCggY29sb3IuciwgY29sb3IuZywgY29sb3IuYiApO1xuXG5cdFx0XHRcdC8vIHNlY29uZCB2ZXJ0ZXhcblxuXHRcdFx0XHR2ID0gKCAoIGogKyAxICkgLyBkaXZpc2lvbnMgKSAqICggTWF0aC5QSSAqIDIgKTtcblxuXHRcdFx0XHR4ID0gTWF0aC5zaW4oIHYgKSAqIHI7XG5cdFx0XHRcdHogPSBNYXRoLmNvcyggdiApICogcjtcblxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB4LCAwLCB6ICk7XG5cdFx0XHRcdGNvbG9ycy5wdXNoKCBjb2xvci5yLCBjb2xvci5nLCBjb2xvci5iICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2NvbG9yJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGNvbG9ycywgMyApICk7XG5cblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyB2ZXJ0ZXhDb2xvcnM6IHRydWUsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKTtcblxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblxuXHRcdHRoaXMudHlwZSA9ICdQb2xhckdyaWRIZWxwZXInO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0fVxuXG59XG5cbmNvbnN0IF92MSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92MiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92MyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgRGlyZWN0aW9uYWxMaWdodEhlbHBlciBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvciggbGlnaHQsIHNpemUsIGNvbG9yICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMubGlnaHQgPSBsaWdodDtcblxuXHRcdHRoaXMubWF0cml4ID0gbGlnaHQubWF0cml4V29ybGQ7XG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XG5cblx0XHR0aGlzLmNvbG9yID0gY29sb3I7XG5cblx0XHR0aGlzLnR5cGUgPSAnRGlyZWN0aW9uYWxMaWdodEhlbHBlcic7XG5cblx0XHRpZiAoIHNpemUgPT09IHVuZGVmaW5lZCApIHNpemUgPSAxO1xuXG5cdFx0bGV0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggW1xuXHRcdFx0LSBzaXplLCBzaXplLCAwLFxuXHRcdFx0c2l6ZSwgc2l6ZSwgMCxcblx0XHRcdHNpemUsIC0gc2l6ZSwgMCxcblx0XHRcdC0gc2l6ZSwgLSBzaXplLCAwLFxuXHRcdFx0LSBzaXplLCBzaXplLCAwXG5cdFx0XSwgMyApICk7XG5cblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyBmb2c6IGZhbHNlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICk7XG5cblx0XHR0aGlzLmxpZ2h0UGxhbmUgPSBuZXcgTGluZSggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cdFx0dGhpcy5hZGQoIHRoaXMubGlnaHRQbGFuZSApO1xuXG5cdFx0Z2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBbIDAsIDAsIDAsIDAsIDAsIDEgXSwgMyApICk7XG5cblx0XHR0aGlzLnRhcmdldExpbmUgPSBuZXcgTGluZSggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cdFx0dGhpcy5hZGQoIHRoaXMudGFyZ2V0TGluZSApO1xuXG5cdFx0dGhpcy51cGRhdGUoKTtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMubGlnaHRQbGFuZS5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5saWdodFBsYW5lLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblx0XHR0aGlzLnRhcmdldExpbmUuZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXHRcdHRoaXMudGFyZ2V0TGluZS5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0fVxuXG5cdHVwZGF0ZSgpIHtcblxuXHRcdHRoaXMubGlnaHQudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XG5cdFx0dGhpcy5saWdodC50YXJnZXQudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XG5cblx0XHRfdjEuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLmxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cdFx0X3YyLnNldEZyb21NYXRyaXhQb3NpdGlvbiggdGhpcy5saWdodC50YXJnZXQubWF0cml4V29ybGQgKTtcblx0XHRfdjMuc3ViVmVjdG9ycyggX3YyLCBfdjEgKTtcblxuXHRcdHRoaXMubGlnaHRQbGFuZS5sb29rQXQoIF92MiApO1xuXG5cdFx0aWYgKCB0aGlzLmNvbG9yICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHRoaXMubGlnaHRQbGFuZS5tYXRlcmlhbC5jb2xvci5zZXQoIHRoaXMuY29sb3IgKTtcblx0XHRcdHRoaXMudGFyZ2V0TGluZS5tYXRlcmlhbC5jb2xvci5zZXQoIHRoaXMuY29sb3IgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMubGlnaHRQbGFuZS5tYXRlcmlhbC5jb2xvci5jb3B5KCB0aGlzLmxpZ2h0LmNvbG9yICk7XG5cdFx0XHR0aGlzLnRhcmdldExpbmUubWF0ZXJpYWwuY29sb3IuY29weSggdGhpcy5saWdodC5jb2xvciApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy50YXJnZXRMaW5lLmxvb2tBdCggX3YyICk7XG5cdFx0dGhpcy50YXJnZXRMaW5lLnNjYWxlLnogPSBfdjMubGVuZ3RoKCk7XG5cblx0fVxuXG59XG5cbmNvbnN0IF92ZWN0b3IgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfY2FtZXJhID0gLypAX19QVVJFX18qLyBuZXcgQ2FtZXJhKCk7XG5cbi8qKlxuICpcdC0gc2hvd3MgZnJ1c3R1bSwgbGluZSBvZiBzaWdodCBhbmQgdXAgb2YgdGhlIGNhbWVyYVxuICpcdC0gc3VpdGFibGUgZm9yIGZhc3QgdXBkYXRlc1xuICogXHQtIGJhc2VkIG9uIGZydXN0dW0gdmlzdWFsaXphdGlvbiBpbiBsaWdodGdsLmpzIHNoYWRvd21hcCBleGFtcGxlXG4gKlx0XHRodHRwczovL2dpdGh1Yi5jb20vZXZhbncvbGlnaHRnbC5qcy9ibG9iL21hc3Rlci90ZXN0cy9zaGFkb3dtYXAuaHRtbFxuICovXG5cbmNsYXNzIENhbWVyYUhlbHBlciBleHRlbmRzIExpbmVTZWdtZW50cyB7XG5cblx0Y29uc3RydWN0b3IoIGNhbWVyYSApIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgY29sb3I6IDB4ZmZmZmZmLCB2ZXJ0ZXhDb2xvcnM6IHRydWUsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKTtcblxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0Y29uc3QgY29sb3JzID0gW107XG5cblx0XHRjb25zdCBwb2ludE1hcCA9IHt9O1xuXG5cdFx0Ly8gbmVhclxuXG5cdFx0YWRkTGluZSggJ24xJywgJ24yJyApO1xuXHRcdGFkZExpbmUoICduMicsICduNCcgKTtcblx0XHRhZGRMaW5lKCAnbjQnLCAnbjMnICk7XG5cdFx0YWRkTGluZSggJ24zJywgJ24xJyApO1xuXG5cdFx0Ly8gZmFyXG5cblx0XHRhZGRMaW5lKCAnZjEnLCAnZjInICk7XG5cdFx0YWRkTGluZSggJ2YyJywgJ2Y0JyApO1xuXHRcdGFkZExpbmUoICdmNCcsICdmMycgKTtcblx0XHRhZGRMaW5lKCAnZjMnLCAnZjEnICk7XG5cblx0XHQvLyBzaWRlc1xuXG5cdFx0YWRkTGluZSggJ24xJywgJ2YxJyApO1xuXHRcdGFkZExpbmUoICduMicsICdmMicgKTtcblx0XHRhZGRMaW5lKCAnbjMnLCAnZjMnICk7XG5cdFx0YWRkTGluZSggJ240JywgJ2Y0JyApO1xuXG5cdFx0Ly8gY29uZVxuXG5cdFx0YWRkTGluZSggJ3AnLCAnbjEnICk7XG5cdFx0YWRkTGluZSggJ3AnLCAnbjInICk7XG5cdFx0YWRkTGluZSggJ3AnLCAnbjMnICk7XG5cdFx0YWRkTGluZSggJ3AnLCAnbjQnICk7XG5cblx0XHQvLyB1cFxuXG5cdFx0YWRkTGluZSggJ3UxJywgJ3UyJyApO1xuXHRcdGFkZExpbmUoICd1MicsICd1MycgKTtcblx0XHRhZGRMaW5lKCAndTMnLCAndTEnICk7XG5cblx0XHQvLyB0YXJnZXRcblxuXHRcdGFkZExpbmUoICdjJywgJ3QnICk7XG5cdFx0YWRkTGluZSggJ3AnLCAnYycgKTtcblxuXHRcdC8vIGNyb3NzXG5cblx0XHRhZGRMaW5lKCAnY24xJywgJ2NuMicgKTtcblx0XHRhZGRMaW5lKCAnY24zJywgJ2NuNCcgKTtcblxuXHRcdGFkZExpbmUoICdjZjEnLCAnY2YyJyApO1xuXHRcdGFkZExpbmUoICdjZjMnLCAnY2Y0JyApO1xuXG5cdFx0ZnVuY3Rpb24gYWRkTGluZSggYSwgYiApIHtcblxuXHRcdFx0YWRkUG9pbnQoIGEgKTtcblx0XHRcdGFkZFBvaW50KCBiICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBhZGRQb2ludCggaWQgKSB7XG5cblx0XHRcdHZlcnRpY2VzLnB1c2goIDAsIDAsIDAgKTtcblx0XHRcdGNvbG9ycy5wdXNoKCAwLCAwLCAwICk7XG5cblx0XHRcdGlmICggcG9pbnRNYXBbIGlkIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRwb2ludE1hcFsgaWQgXSA9IFtdO1xuXG5cdFx0XHR9XG5cblx0XHRcdHBvaW50TWFwWyBpZCBdLnB1c2goICggdmVydGljZXMubGVuZ3RoIC8gMyApIC0gMSApO1xuXG5cdFx0fVxuXG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2NvbG9yJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGNvbG9ycywgMyApICk7XG5cblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cblx0XHR0aGlzLnR5cGUgPSAnQ2FtZXJhSGVscGVyJztcblxuXHRcdHRoaXMuY2FtZXJhID0gY2FtZXJhO1xuXHRcdGlmICggdGhpcy5jYW1lcmEudXBkYXRlUHJvamVjdGlvbk1hdHJpeCApIHRoaXMuY2FtZXJhLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHRcdHRoaXMubWF0cml4ID0gY2FtZXJhLm1hdHJpeFdvcmxkO1xuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0dGhpcy5wb2ludE1hcCA9IHBvaW50TWFwO1xuXG5cdFx0dGhpcy51cGRhdGUoKTtcblxuXHRcdC8vIGNvbG9yc1xuXG5cdFx0Y29uc3QgY29sb3JGcnVzdHVtID0gbmV3IENvbG9yKCAweGZmYWEwMCApO1xuXHRcdGNvbnN0IGNvbG9yQ29uZSA9IG5ldyBDb2xvciggMHhmZjAwMDAgKTtcblx0XHRjb25zdCBjb2xvclVwID0gbmV3IENvbG9yKCAweDAwYWFmZiApO1xuXHRcdGNvbnN0IGNvbG9yVGFyZ2V0ID0gbmV3IENvbG9yKCAweGZmZmZmZiApO1xuXHRcdGNvbnN0IGNvbG9yQ3Jvc3MgPSBuZXcgQ29sb3IoIDB4MzMzMzMzICk7XG5cblx0XHR0aGlzLnNldENvbG9ycyggY29sb3JGcnVzdHVtLCBjb2xvckNvbmUsIGNvbG9yVXAsIGNvbG9yVGFyZ2V0LCBjb2xvckNyb3NzICk7XG5cblx0fVxuXG5cdHNldENvbG9ycyggZnJ1c3R1bSwgY29uZSwgdXAsIHRhcmdldCwgY3Jvc3MgKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cblx0XHRjb25zdCBjb2xvckF0dHJpYnV0ZSA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ2NvbG9yJyApO1xuXG5cdFx0Ly8gbmVhclxuXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAwLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMSwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBuMSwgbjJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDIsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG4yLCBuNFxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggNCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDUsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgLy8gbjQsIG4zXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA2LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggNywgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBuMywgbjFcblxuXHRcdC8vIGZhclxuXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA4LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggOSwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBmMSwgZjJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDEwLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMTEsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgLy8gZjIsIGY0XG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxMiwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDEzLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIGY0LCBmM1xuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMTQsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxNSwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBmMywgZjFcblxuXHRcdC8vIHNpZGVzXG5cblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDE2LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMTcsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgLy8gbjEsIGYxXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxOCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDE5LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG4yLCBmMlxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjAsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyMSwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBuMywgZjNcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDIyLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjMsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgLy8gbjQsIGY0XG5cblx0XHQvLyBjb25lXG5cblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDI0LCBjb25lLnIsIGNvbmUuZywgY29uZS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjUsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgLy8gcCwgbjFcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDI2LCBjb25lLnIsIGNvbmUuZywgY29uZS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjcsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgLy8gcCwgbjJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDI4LCBjb25lLnIsIGNvbmUuZywgY29uZS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjksIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgLy8gcCwgbjNcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDMwLCBjb25lLnIsIGNvbmUuZywgY29uZS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzEsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgLy8gcCwgbjRcblxuXHRcdC8vIHVwXG5cblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDMyLCB1cC5yLCB1cC5nLCB1cC5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzMsIHVwLnIsIHVwLmcsIHVwLmIgKTsgLy8gdTEsIHUyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzNCwgdXAuciwgdXAuZywgdXAuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDM1LCB1cC5yLCB1cC5nLCB1cC5iICk7IC8vIHUyLCB1M1xuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzYsIHVwLnIsIHVwLmcsIHVwLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzNywgdXAuciwgdXAuZywgdXAuYiApOyAvLyB1MywgdTFcblxuXHRcdC8vIHRhcmdldFxuXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzOCwgdGFyZ2V0LnIsIHRhcmdldC5nLCB0YXJnZXQuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDM5LCB0YXJnZXQuciwgdGFyZ2V0LmcsIHRhcmdldC5iICk7IC8vIGMsIHRcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQwLCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggNDEsIGNyb3NzLnIsIGNyb3NzLmcsIGNyb3NzLmIgKTsgLy8gcCwgY1xuXG5cdFx0Ly8gY3Jvc3NcblxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggNDIsIGNyb3NzLnIsIGNyb3NzLmcsIGNyb3NzLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0MywgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyAvLyBjbjEsIGNuMlxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggNDQsIGNyb3NzLnIsIGNyb3NzLmcsIGNyb3NzLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0NSwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyAvLyBjbjMsIGNuNFxuXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0NiwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQ3LCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IC8vIGNmMSwgY2YyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0OCwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQ5LCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IC8vIGNmMywgY2Y0XG5cblx0XHRjb2xvckF0dHJpYnV0ZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0fVxuXG5cdHVwZGF0ZSgpIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcblx0XHRjb25zdCBwb2ludE1hcCA9IHRoaXMucG9pbnRNYXA7XG5cblx0XHRjb25zdCB3ID0gMSwgaCA9IDE7XG5cblx0XHQvLyB3ZSBuZWVkIGp1c3QgY2FtZXJhIHByb2plY3Rpb24gbWF0cml4IGludmVyc2Vcblx0XHQvLyB3b3JsZCBtYXRyaXggbXVzdCBiZSBpZGVudGl0eVxuXG5cdFx0X2NhbWVyYS5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZS5jb3B5KCB0aGlzLmNhbWVyYS5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZSApO1xuXG5cdFx0Ly8gY2VudGVyIC8gdGFyZ2V0XG5cblx0XHRzZXRQb2ludCggJ2MnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIDAsIC0gMSApO1xuXHRcdHNldFBvaW50KCAndCcsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgMCwgMCwgMSApO1xuXG5cdFx0Ly8gbmVhclxuXG5cdFx0c2V0UG9pbnQoICduMScsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCAtIGgsIC0gMSApO1xuXHRcdHNldFBvaW50KCAnbjInLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIHcsIC0gaCwgLSAxICk7XG5cdFx0c2V0UG9pbnQoICduMycsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCBoLCAtIDEgKTtcblx0XHRzZXRQb2ludCggJ240JywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3LCBoLCAtIDEgKTtcblxuXHRcdC8vIGZhclxuXG5cdFx0c2V0UG9pbnQoICdmMScsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCAtIGgsIDEgKTtcblx0XHRzZXRQb2ludCggJ2YyJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3LCAtIGgsIDEgKTtcblx0XHRzZXRQb2ludCggJ2YzJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAtIHcsIGgsIDEgKTtcblx0XHRzZXRQb2ludCggJ2Y0JywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3LCBoLCAxICk7XG5cblx0XHQvLyB1cFxuXG5cdFx0c2V0UG9pbnQoICd1MScsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgdyAqIDAuNywgaCAqIDEuMSwgLSAxICk7XG5cdFx0c2V0UG9pbnQoICd1MicsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3ICogMC43LCBoICogMS4xLCAtIDEgKTtcblx0XHRzZXRQb2ludCggJ3UzJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAwLCBoICogMiwgLSAxICk7XG5cblx0XHQvLyBjcm9zc1xuXG5cdFx0c2V0UG9pbnQoICdjZjEnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIC0gdywgMCwgMSApO1xuXHRcdHNldFBvaW50KCAnY2YyJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3LCAwLCAxICk7XG5cdFx0c2V0UG9pbnQoICdjZjMnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIC0gaCwgMSApO1xuXHRcdHNldFBvaW50KCAnY2Y0JywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAwLCBoLCAxICk7XG5cblx0XHRzZXRQb2ludCggJ2NuMScsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCAwLCAtIDEgKTtcblx0XHRzZXRQb2ludCggJ2NuMicsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgdywgMCwgLSAxICk7XG5cdFx0c2V0UG9pbnQoICdjbjMnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIC0gaCwgLSAxICk7XG5cdFx0c2V0UG9pbnQoICdjbjQnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIGgsIC0gMSApO1xuXG5cdFx0Z2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICkubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0fVxuXG59XG5cblxuZnVuY3Rpb24gc2V0UG9pbnQoIHBvaW50LCBwb2ludE1hcCwgZ2VvbWV0cnksIGNhbWVyYSwgeCwgeSwgeiApIHtcblxuXHRfdmVjdG9yLnNldCggeCwgeSwgeiApLnVucHJvamVjdCggY2FtZXJhICk7XG5cblx0Y29uc3QgcG9pbnRzID0gcG9pbnRNYXBbIHBvaW50IF07XG5cblx0aWYgKCBwb2ludHMgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBwb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0cG9zaXRpb24uc2V0WFlaKCBwb2ludHNbIGkgXSwgX3ZlY3Rvci54LCBfdmVjdG9yLnksIF92ZWN0b3IueiApO1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5jb25zdCBfYm94ID0gLypAX19QVVJFX18qLyBuZXcgQm94MygpO1xuXG5jbGFzcyBCb3hIZWxwZXIgZXh0ZW5kcyBMaW5lU2VnbWVudHMge1xuXG5cdGNvbnN0cnVjdG9yKCBvYmplY3QsIGNvbG9yID0gMHhmZmZmMDAgKSB7XG5cblx0XHRjb25zdCBpbmRpY2VzID0gbmV3IFVpbnQxNkFycmF5KCBbIDAsIDEsIDEsIDIsIDIsIDMsIDMsIDAsIDQsIDUsIDUsIDYsIDYsIDcsIDcsIDQsIDAsIDQsIDEsIDUsIDIsIDYsIDMsIDcgXSApO1xuXHRcdGNvbnN0IHBvc2l0aW9ucyA9IG5ldyBGbG9hdDMyQXJyYXkoIDggKiAzICk7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXHRcdGdlb21ldHJ5LnNldEluZGV4KCBuZXcgQnVmZmVyQXR0cmlidXRlKCBpbmRpY2VzLCAxICkgKTtcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9ucywgMyApICk7XG5cblx0XHRzdXBlciggZ2VvbWV0cnksIG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyBjb2xvcjogY29sb3IsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKSApO1xuXG5cdFx0dGhpcy5vYmplY3QgPSBvYmplY3Q7XG5cdFx0dGhpcy50eXBlID0gJ0JveEhlbHBlcic7XG5cblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblxuXHRcdHRoaXMudXBkYXRlKCk7XG5cblx0fVxuXG5cdHVwZGF0ZSggb2JqZWN0ICkge1xuXG5cdFx0aWYgKCBvYmplY3QgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQm94SGVscGVyOiAudXBkYXRlKCkgaGFzIG5vIGxvbmdlciBhcmd1bWVudHMuJyApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm9iamVjdCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRfYm94LnNldEZyb21PYmplY3QoIHRoaXMub2JqZWN0ICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIF9ib3guaXNFbXB0eSgpICkgcmV0dXJuO1xuXG5cdFx0Y29uc3QgbWluID0gX2JveC5taW47XG5cdFx0Y29uc3QgbWF4ID0gX2JveC5tYXg7XG5cblx0XHQvKlxuXHRcdFx0NV9fX180XG5cdFx0MS9fX18wL3xcblx0XHR8IDZfX3xfN1xuXHRcdDIvX19fMy9cblxuXHRcdDA6IG1heC54LCBtYXgueSwgbWF4Lnpcblx0XHQxOiBtaW4ueCwgbWF4LnksIG1heC56XG5cdFx0MjogbWluLngsIG1pbi55LCBtYXguelxuXHRcdDM6IG1heC54LCBtaW4ueSwgbWF4Lnpcblx0XHQ0OiBtYXgueCwgbWF4LnksIG1pbi56XG5cdFx0NTogbWluLngsIG1heC55LCBtaW4uelxuXHRcdDY6IG1pbi54LCBtaW4ueSwgbWluLnpcblx0XHQ3OiBtYXgueCwgbWluLnksIG1pbi56XG5cdFx0Ki9cblxuXHRcdGNvbnN0IHBvc2l0aW9uID0gdGhpcy5nZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXHRcdGNvbnN0IGFycmF5ID0gcG9zaXRpb24uYXJyYXk7XG5cblx0XHRhcnJheVsgMCBdID0gbWF4Lng7IGFycmF5WyAxIF0gPSBtYXgueTsgYXJyYXlbIDIgXSA9IG1heC56O1xuXHRcdGFycmF5WyAzIF0gPSBtaW4ueDsgYXJyYXlbIDQgXSA9IG1heC55OyBhcnJheVsgNSBdID0gbWF4Lno7XG5cdFx0YXJyYXlbIDYgXSA9IG1pbi54OyBhcnJheVsgNyBdID0gbWluLnk7IGFycmF5WyA4IF0gPSBtYXguejtcblx0XHRhcnJheVsgOSBdID0gbWF4Lng7IGFycmF5WyAxMCBdID0gbWluLnk7IGFycmF5WyAxMSBdID0gbWF4Lno7XG5cdFx0YXJyYXlbIDEyIF0gPSBtYXgueDsgYXJyYXlbIDEzIF0gPSBtYXgueTsgYXJyYXlbIDE0IF0gPSBtaW4uejtcblx0XHRhcnJheVsgMTUgXSA9IG1pbi54OyBhcnJheVsgMTYgXSA9IG1heC55OyBhcnJheVsgMTcgXSA9IG1pbi56O1xuXHRcdGFycmF5WyAxOCBdID0gbWluLng7IGFycmF5WyAxOSBdID0gbWluLnk7IGFycmF5WyAyMCBdID0gbWluLno7XG5cdFx0YXJyYXlbIDIxIF0gPSBtYXgueDsgYXJyYXlbIDIyIF0gPSBtaW4ueTsgYXJyYXlbIDIzIF0gPSBtaW4uejtcblxuXHRcdHBvc2l0aW9uLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdHRoaXMuZ2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XG5cblx0fVxuXG5cdHNldEZyb21PYmplY3QoIG9iamVjdCApIHtcblxuXHRcdHRoaXMub2JqZWN0ID0gb2JqZWN0O1xuXHRcdHRoaXMudXBkYXRlKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0dGhpcy5vYmplY3QgPSBzb3VyY2Uub2JqZWN0O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLmdlb21ldHJ5LmRpc3Bvc2UoKTtcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQm94M0hlbHBlciBleHRlbmRzIExpbmVTZWdtZW50cyB7XG5cblx0Y29uc3RydWN0b3IoIGJveCwgY29sb3IgPSAweGZmZmYwMCApIHtcblxuXHRcdGNvbnN0IGluZGljZXMgPSBuZXcgVWludDE2QXJyYXkoIFsgMCwgMSwgMSwgMiwgMiwgMywgMywgMCwgNCwgNSwgNSwgNiwgNiwgNywgNywgNCwgMCwgNCwgMSwgNSwgMiwgNiwgMywgNyBdICk7XG5cblx0XHRjb25zdCBwb3NpdGlvbnMgPSBbIDEsIDEsIDEsIC0gMSwgMSwgMSwgLSAxLCAtIDEsIDEsIDEsIC0gMSwgMSwgMSwgMSwgLSAxLCAtIDEsIDEsIC0gMSwgLSAxLCAtIDEsIC0gMSwgMSwgLSAxLCAtIDEgXTtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cblx0XHRnZW9tZXRyeS5zZXRJbmRleCggbmV3IEJ1ZmZlckF0dHJpYnV0ZSggaW5kaWNlcywgMSApICk7XG5cblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbnMsIDMgKSApO1xuXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgY29sb3I6IGNvbG9yLCB0b25lTWFwcGVkOiBmYWxzZSB9ICkgKTtcblxuXHRcdHRoaXMuYm94ID0gYm94O1xuXG5cdFx0dGhpcy50eXBlID0gJ0JveDNIZWxwZXInO1xuXG5cdFx0dGhpcy5nZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcblxuXHR9XG5cblx0dXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICkge1xuXG5cdFx0Y29uc3QgYm94ID0gdGhpcy5ib3g7XG5cblx0XHRpZiAoIGJveC5pc0VtcHR5KCkgKSByZXR1cm47XG5cblx0XHRib3guZ2V0Q2VudGVyKCB0aGlzLnBvc2l0aW9uICk7XG5cblx0XHRib3guZ2V0U2l6ZSggdGhpcy5zY2FsZSApO1xuXG5cdFx0dGhpcy5zY2FsZS5tdWx0aXBseVNjYWxhciggMC41ICk7XG5cblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXG5cdH1cblxufVxuXG5jbGFzcyBQbGFuZUhlbHBlciBleHRlbmRzIExpbmUge1xuXG5cdGNvbnN0cnVjdG9yKCBwbGFuZSwgc2l6ZSA9IDEsIGhleCA9IDB4ZmZmZjAwICkge1xuXG5cdFx0Y29uc3QgY29sb3IgPSBoZXg7XG5cblx0XHRjb25zdCBwb3NpdGlvbnMgPSBbIDEsIC0gMSwgMCwgLSAxLCAxLCAwLCAtIDEsIC0gMSwgMCwgMSwgMSwgMCwgLSAxLCAxLCAwLCAtIDEsIC0gMSwgMCwgMSwgLSAxLCAwLCAxLCAxLCAwIF07XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9ucywgMyApICk7XG5cdFx0Z2VvbWV0cnkuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XG5cblx0XHRzdXBlciggZ2VvbWV0cnksIG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyBjb2xvcjogY29sb3IsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKSApO1xuXG5cdFx0dGhpcy50eXBlID0gJ1BsYW5lSGVscGVyJztcblxuXHRcdHRoaXMucGxhbmUgPSBwbGFuZTtcblxuXHRcdHRoaXMuc2l6ZSA9IHNpemU7XG5cblx0XHRjb25zdCBwb3NpdGlvbnMyID0gWyAxLCAxLCAwLCAtIDEsIDEsIDAsIC0gMSwgLSAxLCAwLCAxLCAxLCAwLCAtIDEsIC0gMSwgMCwgMSwgLSAxLCAwIF07XG5cblx0XHRjb25zdCBnZW9tZXRyeTIgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcblx0XHRnZW9tZXRyeTIuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25zMiwgMyApICk7XG5cdFx0Z2VvbWV0cnkyLmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xuXG5cdFx0dGhpcy5hZGQoIG5ldyBNZXNoKCBnZW9tZXRyeTIsIG5ldyBNZXNoQmFzaWNNYXRlcmlhbCggeyBjb2xvcjogY29sb3IsIG9wYWNpdHk6IDAuMiwgdHJhbnNwYXJlbnQ6IHRydWUsIGRlcHRoV3JpdGU6IGZhbHNlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICkgKSApO1xuXG5cdH1cblxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XG5cblx0XHR0aGlzLnBvc2l0aW9uLnNldCggMCwgMCwgMCApO1xuXG5cdFx0dGhpcy5zY2FsZS5zZXQoIDAuNSAqIHRoaXMuc2l6ZSwgMC41ICogdGhpcy5zaXplLCAxICk7XG5cblx0XHR0aGlzLmxvb2tBdCggdGhpcy5wbGFuZS5ub3JtYWwgKTtcblxuXHRcdHRoaXMudHJhbnNsYXRlWiggLSB0aGlzLnBsYW5lLmNvbnN0YW50ICk7XG5cblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXHRcdHRoaXMuY2hpbGRyZW5bIDAgXS5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5jaGlsZHJlblsgMCBdLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblxuXHR9XG5cbn1cblxuY29uc3QgX2F4aXMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5sZXQgX2xpbmVHZW9tZXRyeSwgX2NvbmVHZW9tZXRyeTtcblxuY2xhc3MgQXJyb3dIZWxwZXIgZXh0ZW5kcyBPYmplY3QzRCB7XG5cblx0Ly8gZGlyIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxuXG5cdGNvbnN0cnVjdG9yKCBkaXIgPSBuZXcgVmVjdG9yMyggMCwgMCwgMSApLCBvcmlnaW4gPSBuZXcgVmVjdG9yMyggMCwgMCwgMCApLCBsZW5ndGggPSAxLCBjb2xvciA9IDB4ZmZmZjAwLCBoZWFkTGVuZ3RoID0gbGVuZ3RoICogMC4yLCBoZWFkV2lkdGggPSBoZWFkTGVuZ3RoICogMC4yICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdBcnJvd0hlbHBlcic7XG5cblx0XHRpZiAoIF9saW5lR2VvbWV0cnkgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0X2xpbmVHZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXHRcdFx0X2xpbmVHZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBbIDAsIDAsIDAsIDAsIDEsIDAgXSwgMyApICk7XG5cblx0XHRcdF9jb25lR2VvbWV0cnkgPSBuZXcgQ3lsaW5kZXJHZW9tZXRyeSggMCwgMC41LCAxLCA1LCAxICk7XG5cdFx0XHRfY29uZUdlb21ldHJ5LnRyYW5zbGF0ZSggMCwgLSAwLjUsIDAgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMucG9zaXRpb24uY29weSggb3JpZ2luICk7XG5cblx0XHR0aGlzLmxpbmUgPSBuZXcgTGluZSggX2xpbmVHZW9tZXRyeSwgbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XG5cdFx0dGhpcy5saW5lLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblx0XHR0aGlzLmFkZCggdGhpcy5saW5lICk7XG5cblx0XHR0aGlzLmNvbmUgPSBuZXcgTWVzaCggX2NvbmVHZW9tZXRyeSwgbmV3IE1lc2hCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XG5cdFx0dGhpcy5jb25lLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblx0XHR0aGlzLmFkZCggdGhpcy5jb25lICk7XG5cblx0XHR0aGlzLnNldERpcmVjdGlvbiggZGlyICk7XG5cdFx0dGhpcy5zZXRMZW5ndGgoIGxlbmd0aCwgaGVhZExlbmd0aCwgaGVhZFdpZHRoICk7XG5cblx0fVxuXG5cdHNldERpcmVjdGlvbiggZGlyICkge1xuXG5cdFx0Ly8gZGlyIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxuXG5cdFx0aWYgKCBkaXIueSA+IDAuOTk5OTkgKSB7XG5cblx0XHRcdHRoaXMucXVhdGVybmlvbi5zZXQoIDAsIDAsIDAsIDEgKTtcblxuXHRcdH0gZWxzZSBpZiAoIGRpci55IDwgLSAwLjk5OTk5ICkge1xuXG5cdFx0XHR0aGlzLnF1YXRlcm5pb24uc2V0KCAxLCAwLCAwLCAwICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRfYXhpcy5zZXQoIGRpci56LCAwLCAtIGRpci54ICkubm9ybWFsaXplKCk7XG5cblx0XHRcdGNvbnN0IHJhZGlhbnMgPSBNYXRoLmFjb3MoIGRpci55ICk7XG5cblx0XHRcdHRoaXMucXVhdGVybmlvbi5zZXRGcm9tQXhpc0FuZ2xlKCBfYXhpcywgcmFkaWFucyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRzZXRMZW5ndGgoIGxlbmd0aCwgaGVhZExlbmd0aCA9IGxlbmd0aCAqIDAuMiwgaGVhZFdpZHRoID0gaGVhZExlbmd0aCAqIDAuMiApIHtcblxuXHRcdHRoaXMubGluZS5zY2FsZS5zZXQoIDEsIE1hdGgubWF4KCAwLjAwMDEsIGxlbmd0aCAtIGhlYWRMZW5ndGggKSwgMSApOyAvLyBzZWUgIzE3NDU4XG5cdFx0dGhpcy5saW5lLnVwZGF0ZU1hdHJpeCgpO1xuXG5cdFx0dGhpcy5jb25lLnNjYWxlLnNldCggaGVhZFdpZHRoLCBoZWFkTGVuZ3RoLCBoZWFkV2lkdGggKTtcblx0XHR0aGlzLmNvbmUucG9zaXRpb24ueSA9IGxlbmd0aDtcblx0XHR0aGlzLmNvbmUudXBkYXRlTWF0cml4KCk7XG5cblx0fVxuXG5cdHNldENvbG9yKCBjb2xvciApIHtcblxuXHRcdHRoaXMubGluZS5tYXRlcmlhbC5jb2xvci5zZXQoIGNvbG9yICk7XG5cdFx0dGhpcy5jb25lLm1hdGVyaWFsLmNvbG9yLnNldCggY29sb3IgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCBmYWxzZSApO1xuXG5cdFx0dGhpcy5saW5lLmNvcHkoIHNvdXJjZS5saW5lICk7XG5cdFx0dGhpcy5jb25lLmNvcHkoIHNvdXJjZS5jb25lICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMubGluZS5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5saW5lLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblx0XHR0aGlzLmNvbmUuZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXHRcdHRoaXMuY29uZS5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0fVxuXG59XG5cbmNsYXNzIEF4ZXNIZWxwZXIgZXh0ZW5kcyBMaW5lU2VnbWVudHMge1xuXG5cdGNvbnN0cnVjdG9yKCBzaXplID0gMSApIHtcblxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW1xuXHRcdFx0MCwgMCwgMCxcdHNpemUsIDAsIDAsXG5cdFx0XHQwLCAwLCAwLFx0MCwgc2l6ZSwgMCxcblx0XHRcdDAsIDAsIDAsXHQwLCAwLCBzaXplXG5cdFx0XTtcblxuXHRcdGNvbnN0IGNvbG9ycyA9IFtcblx0XHRcdDEsIDAsIDAsXHQxLCAwLjYsIDAsXG5cdFx0XHQwLCAxLCAwLFx0MC42LCAxLCAwLFxuXHRcdFx0MCwgMCwgMSxcdDAsIDAuNiwgMVxuXHRcdF07XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdjb2xvcicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBjb2xvcnMsIDMgKSApO1xuXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgdmVydGV4Q29sb3JzOiB0cnVlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICk7XG5cblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cblx0XHR0aGlzLnR5cGUgPSAnQXhlc0hlbHBlcic7XG5cblx0fVxuXG5cdHNldENvbG9ycyggeEF4aXNDb2xvciwgeUF4aXNDb2xvciwgekF4aXNDb2xvciApIHtcblxuXHRcdGNvbnN0IGNvbG9yID0gbmV3IENvbG9yKCk7XG5cdFx0Y29uc3QgYXJyYXkgPSB0aGlzLmdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IuYXJyYXk7XG5cblx0XHRjb2xvci5zZXQoIHhBeGlzQ29sb3IgKTtcblx0XHRjb2xvci50b0FycmF5KCBhcnJheSwgMCApO1xuXHRcdGNvbG9yLnRvQXJyYXkoIGFycmF5LCAzICk7XG5cblx0XHRjb2xvci5zZXQoIHlBeGlzQ29sb3IgKTtcblx0XHRjb2xvci50b0FycmF5KCBhcnJheSwgNiApO1xuXHRcdGNvbG9yLnRvQXJyYXkoIGFycmF5LCA5ICk7XG5cblx0XHRjb2xvci5zZXQoIHpBeGlzQ29sb3IgKTtcblx0XHRjb2xvci50b0FycmF5KCBhcnJheSwgMTIgKTtcblx0XHRjb2xvci50b0FycmF5KCBhcnJheSwgMTUgKTtcblxuXHRcdHRoaXMuZ2VvbWV0cnkuYXR0cmlidXRlcy5jb2xvci5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXG5cdH1cblxufVxuXG5jbGFzcyBTaGFwZVBhdGgge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0dGhpcy50eXBlID0gJ1NoYXBlUGF0aCc7XG5cblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCk7XG5cblx0XHR0aGlzLnN1YlBhdGhzID0gW107XG5cdFx0dGhpcy5jdXJyZW50UGF0aCA9IG51bGw7XG5cblx0fVxuXG5cdG1vdmVUbyggeCwgeSApIHtcblxuXHRcdHRoaXMuY3VycmVudFBhdGggPSBuZXcgUGF0aCgpO1xuXHRcdHRoaXMuc3ViUGF0aHMucHVzaCggdGhpcy5jdXJyZW50UGF0aCApO1xuXHRcdHRoaXMuY3VycmVudFBhdGgubW92ZVRvKCB4LCB5ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bGluZVRvKCB4LCB5ICkge1xuXG5cdFx0dGhpcy5jdXJyZW50UGF0aC5saW5lVG8oIHgsIHkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRxdWFkcmF0aWNDdXJ2ZVRvKCBhQ1B4LCBhQ1B5LCBhWCwgYVkgKSB7XG5cblx0XHR0aGlzLmN1cnJlbnRQYXRoLnF1YWRyYXRpY0N1cnZlVG8oIGFDUHgsIGFDUHksIGFYLCBhWSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGJlemllckN1cnZlVG8oIGFDUDF4LCBhQ1AxeSwgYUNQMngsIGFDUDJ5LCBhWCwgYVkgKSB7XG5cblx0XHR0aGlzLmN1cnJlbnRQYXRoLmJlemllckN1cnZlVG8oIGFDUDF4LCBhQ1AxeSwgYUNQMngsIGFDUDJ5LCBhWCwgYVkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzcGxpbmVUaHJ1KCBwdHMgKSB7XG5cblx0XHR0aGlzLmN1cnJlbnRQYXRoLnNwbGluZVRocnUoIHB0cyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvU2hhcGVzKCBpc0NDVyApIHtcblxuXHRcdGZ1bmN0aW9uIHRvU2hhcGVzTm9Ib2xlcyggaW5TdWJwYXRocyApIHtcblxuXHRcdFx0Y29uc3Qgc2hhcGVzID0gW107XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGluU3VicGF0aHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCB0bXBQYXRoID0gaW5TdWJwYXRoc1sgaSBdO1xuXG5cdFx0XHRcdGNvbnN0IHRtcFNoYXBlID0gbmV3IFNoYXBlKCk7XG5cdFx0XHRcdHRtcFNoYXBlLmN1cnZlcyA9IHRtcFBhdGguY3VydmVzO1xuXG5cdFx0XHRcdHNoYXBlcy5wdXNoKCB0bXBTaGFwZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBzaGFwZXM7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBpc1BvaW50SW5zaWRlUG9seWdvbiggaW5QdCwgaW5Qb2x5Z29uICkge1xuXG5cdFx0XHRjb25zdCBwb2x5TGVuID0gaW5Qb2x5Z29uLmxlbmd0aDtcblxuXHRcdFx0Ly8gaW5QdCBvbiBwb2x5Z29uIGNvbnRvdXIgPT4gaW1tZWRpYXRlIHN1Y2Nlc3MgICAgb3Jcblx0XHRcdC8vIHRvZ2dsaW5nIG9mIGluc2lkZS9vdXRzaWRlIGF0IGV2ZXJ5IHNpbmdsZSEgaW50ZXJzZWN0aW9uIHBvaW50IG9mIGFuIGVkZ2Vcblx0XHRcdC8vICB3aXRoIHRoZSBob3Jpem9udGFsIGxpbmUgdGhyb3VnaCBpblB0LCBsZWZ0IG9mIGluUHRcblx0XHRcdC8vICBub3QgY291bnRpbmcgbG93ZXJZIGVuZHBvaW50cyBvZiBlZGdlcyBhbmQgd2hvbGUgZWRnZXMgb24gdGhhdCBsaW5lXG5cdFx0XHRsZXQgaW5zaWRlID0gZmFsc2U7XG5cdFx0XHRmb3IgKCBsZXQgcCA9IHBvbHlMZW4gLSAxLCBxID0gMDsgcSA8IHBvbHlMZW47IHAgPSBxICsrICkge1xuXG5cdFx0XHRcdGxldCBlZGdlTG93UHQgPSBpblBvbHlnb25bIHAgXTtcblx0XHRcdFx0bGV0IGVkZ2VIaWdoUHQgPSBpblBvbHlnb25bIHEgXTtcblxuXHRcdFx0XHRsZXQgZWRnZUR4ID0gZWRnZUhpZ2hQdC54IC0gZWRnZUxvd1B0Lng7XG5cdFx0XHRcdGxldCBlZGdlRHkgPSBlZGdlSGlnaFB0LnkgLSBlZGdlTG93UHQueTtcblxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBlZGdlRHkgKSA+IE51bWJlci5FUFNJTE9OICkge1xuXG5cdFx0XHRcdFx0Ly8gbm90IHBhcmFsbGVsXG5cdFx0XHRcdFx0aWYgKCBlZGdlRHkgPCAwICkge1xuXG5cdFx0XHRcdFx0XHRlZGdlTG93UHQgPSBpblBvbHlnb25bIHEgXTsgZWRnZUR4ID0gLSBlZGdlRHg7XG5cdFx0XHRcdFx0XHRlZGdlSGlnaFB0ID0gaW5Qb2x5Z29uWyBwIF07IGVkZ2VEeSA9IC0gZWRnZUR5O1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCAoIGluUHQueSA8IGVkZ2VMb3dQdC55ICkgfHwgKCBpblB0LnkgPiBlZGdlSGlnaFB0LnkgKSApIFx0XHRjb250aW51ZTtcblxuXHRcdFx0XHRcdGlmICggaW5QdC55ID09PSBlZGdlTG93UHQueSApIHtcblxuXHRcdFx0XHRcdFx0aWYgKCBpblB0LnggPT09IGVkZ2VMb3dQdC54IClcdFx0cmV0dXJuXHR0cnVlO1x0XHQvLyBpblB0IGlzIG9uIGNvbnRvdXIgP1xuXHRcdFx0XHRcdFx0Ly8gY29udGludWU7XHRcdFx0XHQvLyBubyBpbnRlcnNlY3Rpb24gb3IgZWRnZUxvd1B0ID0+IGRvZXNuJ3QgY291bnQgISEhXG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBwZXJwRWRnZSA9IGVkZ2VEeSAqICggaW5QdC54IC0gZWRnZUxvd1B0LnggKSAtIGVkZ2VEeCAqICggaW5QdC55IC0gZWRnZUxvd1B0LnkgKTtcblx0XHRcdFx0XHRcdGlmICggcGVycEVkZ2UgPT09IDAgKVx0XHRcdFx0cmV0dXJuXHR0cnVlO1x0XHQvLyBpblB0IGlzIG9uIGNvbnRvdXIgP1xuXHRcdFx0XHRcdFx0aWYgKCBwZXJwRWRnZSA8IDAgKSBcdFx0XHRcdGNvbnRpbnVlO1xuXHRcdFx0XHRcdFx0aW5zaWRlID0gISBpbnNpZGU7XHRcdC8vIHRydWUgaW50ZXJzZWN0aW9uIGxlZnQgb2YgaW5QdFxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBwYXJhbGxlbCBvciBjb2xsaW5lYXJcblx0XHRcdFx0XHRpZiAoIGluUHQueSAhPT0gZWRnZUxvd1B0LnkgKSBcdFx0Y29udGludWU7XHRcdFx0Ly8gcGFyYWxsZWxcblx0XHRcdFx0XHQvLyBlZGdlIGxpZXMgb24gdGhlIHNhbWUgaG9yaXpvbnRhbCBsaW5lIGFzIGluUHRcblx0XHRcdFx0XHRpZiAoICggKCBlZGdlSGlnaFB0LnggPD0gaW5QdC54ICkgJiYgKCBpblB0LnggPD0gZWRnZUxvd1B0LnggKSApIHx8XG5cdFx0XHRcdFx0XHQgKCAoIGVkZ2VMb3dQdC54IDw9IGluUHQueCApICYmICggaW5QdC54IDw9IGVkZ2VIaWdoUHQueCApICkgKVx0XHRyZXR1cm5cdHRydWU7XHQvLyBpblB0OiBQb2ludCBvbiBjb250b3VyICFcblx0XHRcdFx0XHQvLyBjb250aW51ZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuXHRpbnNpZGU7XG5cblx0XHR9XG5cblx0XHRjb25zdCBpc0Nsb2NrV2lzZSA9IFNoYXBlVXRpbHMuaXNDbG9ja1dpc2U7XG5cblx0XHRjb25zdCBzdWJQYXRocyA9IHRoaXMuc3ViUGF0aHM7XG5cdFx0aWYgKCBzdWJQYXRocy5sZW5ndGggPT09IDAgKSByZXR1cm4gW107XG5cblx0XHRsZXQgc29saWQsIHRtcFBhdGgsIHRtcFNoYXBlO1xuXHRcdGNvbnN0IHNoYXBlcyA9IFtdO1xuXG5cdFx0aWYgKCBzdWJQYXRocy5sZW5ndGggPT09IDEgKSB7XG5cblx0XHRcdHRtcFBhdGggPSBzdWJQYXRoc1sgMCBdO1xuXHRcdFx0dG1wU2hhcGUgPSBuZXcgU2hhcGUoKTtcblx0XHRcdHRtcFNoYXBlLmN1cnZlcyA9IHRtcFBhdGguY3VydmVzO1xuXHRcdFx0c2hhcGVzLnB1c2goIHRtcFNoYXBlICk7XG5cdFx0XHRyZXR1cm4gc2hhcGVzO1xuXG5cdFx0fVxuXG5cdFx0bGV0IGhvbGVzRmlyc3QgPSAhIGlzQ2xvY2tXaXNlKCBzdWJQYXRoc1sgMCBdLmdldFBvaW50cygpICk7XG5cdFx0aG9sZXNGaXJzdCA9IGlzQ0NXID8gISBob2xlc0ZpcnN0IDogaG9sZXNGaXJzdDtcblxuXHRcdC8vIGNvbnNvbGUubG9nKFwiSG9sZXMgZmlyc3RcIiwgaG9sZXNGaXJzdCk7XG5cblx0XHRjb25zdCBiZXR0ZXJTaGFwZUhvbGVzID0gW107XG5cdFx0Y29uc3QgbmV3U2hhcGVzID0gW107XG5cdFx0bGV0IG5ld1NoYXBlSG9sZXMgPSBbXTtcblx0XHRsZXQgbWFpbklkeCA9IDA7XG5cdFx0bGV0IHRtcFBvaW50cztcblxuXHRcdG5ld1NoYXBlc1sgbWFpbklkeCBdID0gdW5kZWZpbmVkO1xuXHRcdG5ld1NoYXBlSG9sZXNbIG1haW5JZHggXSA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc3ViUGF0aHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0dG1wUGF0aCA9IHN1YlBhdGhzWyBpIF07XG5cdFx0XHR0bXBQb2ludHMgPSB0bXBQYXRoLmdldFBvaW50cygpO1xuXHRcdFx0c29saWQgPSBpc0Nsb2NrV2lzZSggdG1wUG9pbnRzICk7XG5cdFx0XHRzb2xpZCA9IGlzQ0NXID8gISBzb2xpZCA6IHNvbGlkO1xuXG5cdFx0XHRpZiAoIHNvbGlkICkge1xuXG5cdFx0XHRcdGlmICggKCAhIGhvbGVzRmlyc3QgKSAmJiAoIG5ld1NoYXBlc1sgbWFpbklkeCBdICkgKVx0bWFpbklkeCArKztcblxuXHRcdFx0XHRuZXdTaGFwZXNbIG1haW5JZHggXSA9IHsgczogbmV3IFNoYXBlKCksIHA6IHRtcFBvaW50cyB9O1xuXHRcdFx0XHRuZXdTaGFwZXNbIG1haW5JZHggXS5zLmN1cnZlcyA9IHRtcFBhdGguY3VydmVzO1xuXG5cdFx0XHRcdGlmICggaG9sZXNGaXJzdCApXHRtYWluSWR4ICsrO1xuXHRcdFx0XHRuZXdTaGFwZUhvbGVzWyBtYWluSWR4IF0gPSBbXTtcblxuXHRcdFx0XHQvL2NvbnNvbGUubG9nKCdjdycsIGkpO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdG5ld1NoYXBlSG9sZXNbIG1haW5JZHggXS5wdXNoKCB7IGg6IHRtcFBhdGgsIHA6IHRtcFBvaW50c1sgMCBdIH0gKTtcblxuXHRcdFx0XHQvL2NvbnNvbGUubG9nKCdjY3cnLCBpKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gb25seSBIb2xlcz8gLT4gcHJvYmFibHkgYWxsIFNoYXBlcyB3aXRoIHdyb25nIG9yaWVudGF0aW9uXG5cdFx0aWYgKCAhIG5ld1NoYXBlc1sgMCBdIClcdHJldHVyblx0dG9TaGFwZXNOb0hvbGVzKCBzdWJQYXRocyApO1xuXG5cblx0XHRpZiAoIG5ld1NoYXBlcy5sZW5ndGggPiAxICkge1xuXG5cdFx0XHRsZXQgYW1iaWd1b3VzID0gZmFsc2U7XG5cdFx0XHRsZXQgdG9DaGFuZ2UgPSAwO1xuXG5cdFx0XHRmb3IgKCBsZXQgc0lkeCA9IDAsIHNMZW4gPSBuZXdTaGFwZXMubGVuZ3RoOyBzSWR4IDwgc0xlbjsgc0lkeCArKyApIHtcblxuXHRcdFx0XHRiZXR0ZXJTaGFwZUhvbGVzWyBzSWR4IF0gPSBbXTtcblxuXHRcdFx0fVxuXG5cdFx0XHRmb3IgKCBsZXQgc0lkeCA9IDAsIHNMZW4gPSBuZXdTaGFwZXMubGVuZ3RoOyBzSWR4IDwgc0xlbjsgc0lkeCArKyApIHtcblxuXHRcdFx0XHRjb25zdCBzaG8gPSBuZXdTaGFwZUhvbGVzWyBzSWR4IF07XG5cblx0XHRcdFx0Zm9yICggbGV0IGhJZHggPSAwOyBoSWR4IDwgc2hvLmxlbmd0aDsgaElkeCArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGhvID0gc2hvWyBoSWR4IF07XG5cdFx0XHRcdFx0bGV0IGhvbGVfdW5hc3NpZ25lZCA9IHRydWU7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgczJJZHggPSAwOyBzMklkeCA8IG5ld1NoYXBlcy5sZW5ndGg7IHMySWR4ICsrICkge1xuXG5cdFx0XHRcdFx0XHRpZiAoIGlzUG9pbnRJbnNpZGVQb2x5Z29uKCBoby5wLCBuZXdTaGFwZXNbIHMySWR4IF0ucCApICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggc0lkeCAhPT0gczJJZHggKVx0dG9DaGFuZ2UgKys7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBob2xlX3VuYXNzaWduZWQgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRob2xlX3VuYXNzaWduZWQgPSBmYWxzZTtcblx0XHRcdFx0XHRcdFx0XHRiZXR0ZXJTaGFwZUhvbGVzWyBzMklkeCBdLnB1c2goIGhvICk7XG5cblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdGFtYmlndW91cyA9IHRydWU7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoIGhvbGVfdW5hc3NpZ25lZCApIHtcblxuXHRcdFx0XHRcdFx0YmV0dGVyU2hhcGVIb2xlc1sgc0lkeCBdLnB1c2goIGhvICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdG9DaGFuZ2UgPiAwICYmIGFtYmlndW91cyA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0bmV3U2hhcGVIb2xlcyA9IGJldHRlclNoYXBlSG9sZXM7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGxldCB0bXBIb2xlcztcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBuZXdTaGFwZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdHRtcFNoYXBlID0gbmV3U2hhcGVzWyBpIF0ucztcblx0XHRcdHNoYXBlcy5wdXNoKCB0bXBTaGFwZSApO1xuXHRcdFx0dG1wSG9sZXMgPSBuZXdTaGFwZUhvbGVzWyBpIF07XG5cblx0XHRcdGZvciAoIGxldCBqID0gMCwgamwgPSB0bXBIb2xlcy5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcblxuXHRcdFx0XHR0bXBTaGFwZS5ob2xlcy5wdXNoKCB0bXBIb2xlc1sgaiBdLmggKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly9jb25zb2xlLmxvZyhcInNoYXBlXCIsIHNoYXBlcyk7XG5cblx0XHRyZXR1cm4gc2hhcGVzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBXZWJHTE11bHRpcGxlUmVuZGVyVGFyZ2V0cyBleHRlbmRzIFdlYkdMUmVuZGVyVGFyZ2V0IHsgLy8gQGRlcHJlY2F0ZWQsIHIxNjJcblxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBjb3VudCA9IDEsIG9wdGlvbnMgPSB7fSApIHtcblxuXHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzIGhhcyBiZWVuIGRlcHJlY2F0ZWQgYW5kIHdpbGwgYmUgcmVtb3ZlZCBpbiByMTcyLiBVc2UgVEhSRUUuV2ViR0xSZW5kZXJUYXJnZXQgYW5kIHNldCB0aGUgXCJjb3VudFwiIHBhcmFtZXRlciB0byBlbmFibGUgTVJULicgKTtcblxuXHRcdHN1cGVyKCB3aWR0aCwgaGVpZ2h0LCB7IC4uLm9wdGlvbnMsIGNvdW50IH0gKTtcblxuXHRcdHRoaXMuaXNXZWJHTE11bHRpcGxlUmVuZGVyVGFyZ2V0cyA9IHRydWU7XG5cblx0fVxuXG5cdGdldCB0ZXh0dXJlKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMudGV4dHVyZXM7XG5cblx0fVxuXG59XG5cbmlmICggdHlwZW9mIF9fVEhSRUVfREVWVE9PTFNfXyAhPT0gJ3VuZGVmaW5lZCcgKSB7XG5cblx0X19USFJFRV9ERVZUT09MU19fLmRpc3BhdGNoRXZlbnQoIG5ldyBDdXN0b21FdmVudCggJ3JlZ2lzdGVyJywgeyBkZXRhaWw6IHtcblx0XHRyZXZpc2lvbjogUkVWSVNJT04sXG5cdH0gfSApICk7XG5cbn1cblxuaWYgKCB0eXBlb2Ygd2luZG93ICE9PSAndW5kZWZpbmVkJyApIHtcblxuXHRpZiAoIHdpbmRvdy5fX1RIUkVFX18gKSB7XG5cblx0XHRjb25zb2xlLndhcm4oICdXQVJOSU5HOiBNdWx0aXBsZSBpbnN0YW5jZXMgb2YgVGhyZWUuanMgYmVpbmcgaW1wb3J0ZWQuJyApO1xuXG5cdH0gZWxzZSB7XG5cblx0XHR3aW5kb3cuX19USFJFRV9fID0gUkVWSVNJT047XG5cblx0fVxuXG59XG5cbmV4cG9ydCB7IEFDRVNGaWxtaWNUb25lTWFwcGluZywgQWRkRXF1YXRpb24sIEFkZE9wZXJhdGlvbiwgQWRkaXRpdmVBbmltYXRpb25CbGVuZE1vZGUsIEFkZGl0aXZlQmxlbmRpbmcsIEFnWFRvbmVNYXBwaW5nLCBBbHBoYUZvcm1hdCwgQWx3YXlzQ29tcGFyZSwgQWx3YXlzRGVwdGgsIEFsd2F5c1N0ZW5jaWxGdW5jLCBBbWJpZW50TGlnaHQsIEFuaW1hdGlvbkFjdGlvbiwgQW5pbWF0aW9uQ2xpcCwgQW5pbWF0aW9uTG9hZGVyLCBBbmltYXRpb25NaXhlciwgQW5pbWF0aW9uT2JqZWN0R3JvdXAsIEFuaW1hdGlvblV0aWxzLCBBcmNDdXJ2ZSwgQXJyYXlDYW1lcmEsIEFycm93SGVscGVyLCBBdHRhY2hlZEJpbmRNb2RlLCBBdWRpbywgQXVkaW9BbmFseXNlciwgQXVkaW9Db250ZXh0LCBBdWRpb0xpc3RlbmVyLCBBdWRpb0xvYWRlciwgQXhlc0hlbHBlciwgQmFja1NpZGUsIEJhc2ljRGVwdGhQYWNraW5nLCBCYXNpY1NoYWRvd01hcCwgQmF0Y2hlZE1lc2gsIEJvbmUsIEJvb2xlYW5LZXlmcmFtZVRyYWNrLCBCb3gyLCBCb3gzLCBCb3gzSGVscGVyLCBCb3hHZW9tZXRyeSwgQm94SGVscGVyLCBCdWZmZXJBdHRyaWJ1dGUsIEJ1ZmZlckdlb21ldHJ5LCBCdWZmZXJHZW9tZXRyeUxvYWRlciwgQnl0ZVR5cGUsIENhY2hlLCBDYW1lcmEsIENhbWVyYUhlbHBlciwgQ2FudmFzVGV4dHVyZSwgQ2Fwc3VsZUdlb21ldHJ5LCBDYXRtdWxsUm9tQ3VydmUzLCBDaW5lb25Ub25lTWFwcGluZywgQ2lyY2xlR2VvbWV0cnksIENsYW1wVG9FZGdlV3JhcHBpbmcsIENsb2NrLCBDb2xvciwgQ29sb3JLZXlmcmFtZVRyYWNrLCBDb2xvck1hbmFnZW1lbnQsIENvbXByZXNzZWRBcnJheVRleHR1cmUsIENvbXByZXNzZWRDdWJlVGV4dHVyZSwgQ29tcHJlc3NlZFRleHR1cmUsIENvbXByZXNzZWRUZXh0dXJlTG9hZGVyLCBDb25lR2VvbWV0cnksIENvbnN0YW50QWxwaGFGYWN0b3IsIENvbnN0YW50Q29sb3JGYWN0b3IsIEN1YmVDYW1lcmEsIEN1YmVSZWZsZWN0aW9uTWFwcGluZywgQ3ViZVJlZnJhY3Rpb25NYXBwaW5nLCBDdWJlVGV4dHVyZSwgQ3ViZVRleHR1cmVMb2FkZXIsIEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nLCBDdWJpY0JlemllckN1cnZlLCBDdWJpY0JlemllckN1cnZlMywgQ3ViaWNJbnRlcnBvbGFudCwgQ3VsbEZhY2VCYWNrLCBDdWxsRmFjZUZyb250LCBDdWxsRmFjZUZyb250QmFjaywgQ3VsbEZhY2VOb25lLCBDdXJ2ZSwgQ3VydmVQYXRoLCBDdXN0b21CbGVuZGluZywgQ3VzdG9tVG9uZU1hcHBpbmcsIEN5bGluZGVyR2VvbWV0cnksIEN5bGluZHJpY2FsLCBEYXRhM0RUZXh0dXJlLCBEYXRhQXJyYXlUZXh0dXJlLCBEYXRhVGV4dHVyZSwgRGF0YVRleHR1cmVMb2FkZXIsIERhdGFVdGlscywgRGVjcmVtZW50U3RlbmNpbE9wLCBEZWNyZW1lbnRXcmFwU3RlbmNpbE9wLCBEZWZhdWx0TG9hZGluZ01hbmFnZXIsIERlcHRoRm9ybWF0LCBEZXB0aFN0ZW5jaWxGb3JtYXQsIERlcHRoVGV4dHVyZSwgRGV0YWNoZWRCaW5kTW9kZSwgRGlyZWN0aW9uYWxMaWdodCwgRGlyZWN0aW9uYWxMaWdodEhlbHBlciwgRGlzY3JldGVJbnRlcnBvbGFudCwgRGlzcGxheVAzQ29sb3JTcGFjZSwgRG9kZWNhaGVkcm9uR2VvbWV0cnksIERvdWJsZVNpZGUsIERzdEFscGhhRmFjdG9yLCBEc3RDb2xvckZhY3RvciwgRHluYW1pY0NvcHlVc2FnZSwgRHluYW1pY0RyYXdVc2FnZSwgRHluYW1pY1JlYWRVc2FnZSwgRWRnZXNHZW9tZXRyeSwgRWxsaXBzZUN1cnZlLCBFcXVhbENvbXBhcmUsIEVxdWFsRGVwdGgsIEVxdWFsU3RlbmNpbEZ1bmMsIEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nLCBFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZywgRXVsZXIsIEV2ZW50RGlzcGF0Y2hlciwgRXh0cnVkZUdlb21ldHJ5LCBGaWxlTG9hZGVyLCBGbG9hdDE2QnVmZmVyQXR0cmlidXRlLCBGbG9hdDMyQnVmZmVyQXR0cmlidXRlLCBGbG9hdFR5cGUsIEZvZywgRm9nRXhwMiwgRnJhbWVidWZmZXJUZXh0dXJlLCBGcm9udFNpZGUsIEZydXN0dW0sIEdMQnVmZmVyQXR0cmlidXRlLCBHTFNMMSwgR0xTTDMsIEdyZWF0ZXJDb21wYXJlLCBHcmVhdGVyRGVwdGgsIEdyZWF0ZXJFcXVhbENvbXBhcmUsIEdyZWF0ZXJFcXVhbERlcHRoLCBHcmVhdGVyRXF1YWxTdGVuY2lsRnVuYywgR3JlYXRlclN0ZW5jaWxGdW5jLCBHcmlkSGVscGVyLCBHcm91cCwgSGFsZkZsb2F0VHlwZSwgSGVtaXNwaGVyZUxpZ2h0LCBIZW1pc3BoZXJlTGlnaHRIZWxwZXIsIEljb3NhaGVkcm9uR2VvbWV0cnksIEltYWdlQml0bWFwTG9hZGVyLCBJbWFnZUxvYWRlciwgSW1hZ2VVdGlscywgSW5jcmVtZW50U3RlbmNpbE9wLCBJbmNyZW1lbnRXcmFwU3RlbmNpbE9wLCBJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUsIEluc3RhbmNlZEJ1ZmZlckdlb21ldHJ5LCBJbnN0YW5jZWRJbnRlcmxlYXZlZEJ1ZmZlciwgSW5zdGFuY2VkTWVzaCwgSW50MTZCdWZmZXJBdHRyaWJ1dGUsIEludDMyQnVmZmVyQXR0cmlidXRlLCBJbnQ4QnVmZmVyQXR0cmlidXRlLCBJbnRUeXBlLCBJbnRlcmxlYXZlZEJ1ZmZlciwgSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUsIEludGVycG9sYW50LCBJbnRlcnBvbGF0ZURpc2NyZXRlLCBJbnRlcnBvbGF0ZUxpbmVhciwgSW50ZXJwb2xhdGVTbW9vdGgsIEludmVydFN0ZW5jaWxPcCwgS2VlcFN0ZW5jaWxPcCwgS2V5ZnJhbWVUcmFjaywgTE9ELCBMYXRoZUdlb21ldHJ5LCBMYXllcnMsIExlc3NDb21wYXJlLCBMZXNzRGVwdGgsIExlc3NFcXVhbENvbXBhcmUsIExlc3NFcXVhbERlcHRoLCBMZXNzRXF1YWxTdGVuY2lsRnVuYywgTGVzc1N0ZW5jaWxGdW5jLCBMaWdodCwgTGlnaHRQcm9iZSwgTGluZSwgTGluZTMsIExpbmVCYXNpY01hdGVyaWFsLCBMaW5lQ3VydmUsIExpbmVDdXJ2ZTMsIExpbmVEYXNoZWRNYXRlcmlhbCwgTGluZUxvb3AsIExpbmVTZWdtZW50cywgTGluZWFyRGlzcGxheVAzQ29sb3JTcGFjZSwgTGluZWFyRmlsdGVyLCBMaW5lYXJJbnRlcnBvbGFudCwgTGluZWFyTWlwTWFwTGluZWFyRmlsdGVyLCBMaW5lYXJNaXBNYXBOZWFyZXN0RmlsdGVyLCBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIsIExpbmVhck1pcG1hcE5lYXJlc3RGaWx0ZXIsIExpbmVhclNSR0JDb2xvclNwYWNlLCBMaW5lYXJUb25lTWFwcGluZywgTGluZWFyVHJhbnNmZXIsIExvYWRlciwgTG9hZGVyVXRpbHMsIExvYWRpbmdNYW5hZ2VyLCBMb29wT25jZSwgTG9vcFBpbmdQb25nLCBMb29wUmVwZWF0LCBMdW1pbmFuY2VBbHBoYUZvcm1hdCwgTHVtaW5hbmNlRm9ybWF0LCBNT1VTRSwgTWF0ZXJpYWwsIE1hdGVyaWFsTG9hZGVyLCBNYXRoVXRpbHMsIE1hdHJpeDMsIE1hdHJpeDQsIE1heEVxdWF0aW9uLCBNZXNoLCBNZXNoQmFzaWNNYXRlcmlhbCwgTWVzaERlcHRoTWF0ZXJpYWwsIE1lc2hEaXN0YW5jZU1hdGVyaWFsLCBNZXNoTGFtYmVydE1hdGVyaWFsLCBNZXNoTWF0Y2FwTWF0ZXJpYWwsIE1lc2hOb3JtYWxNYXRlcmlhbCwgTWVzaFBob25nTWF0ZXJpYWwsIE1lc2hQaHlzaWNhbE1hdGVyaWFsLCBNZXNoU3RhbmRhcmRNYXRlcmlhbCwgTWVzaFRvb25NYXRlcmlhbCwgTWluRXF1YXRpb24sIE1pcnJvcmVkUmVwZWF0V3JhcHBpbmcsIE1peE9wZXJhdGlvbiwgTXVsdGlwbHlCbGVuZGluZywgTXVsdGlwbHlPcGVyYXRpb24sIE5lYXJlc3RGaWx0ZXIsIE5lYXJlc3RNaXBNYXBMaW5lYXJGaWx0ZXIsIE5lYXJlc3RNaXBNYXBOZWFyZXN0RmlsdGVyLCBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyLCBOZWFyZXN0TWlwbWFwTmVhcmVzdEZpbHRlciwgTmV1dHJhbFRvbmVNYXBwaW5nLCBOZXZlckNvbXBhcmUsIE5ldmVyRGVwdGgsIE5ldmVyU3RlbmNpbEZ1bmMsIE5vQmxlbmRpbmcsIE5vQ29sb3JTcGFjZSwgTm9Ub25lTWFwcGluZywgTm9ybWFsQW5pbWF0aW9uQmxlbmRNb2RlLCBOb3JtYWxCbGVuZGluZywgTm90RXF1YWxDb21wYXJlLCBOb3RFcXVhbERlcHRoLCBOb3RFcXVhbFN0ZW5jaWxGdW5jLCBOdW1iZXJLZXlmcmFtZVRyYWNrLCBPYmplY3QzRCwgT2JqZWN0TG9hZGVyLCBPYmplY3RTcGFjZU5vcm1hbE1hcCwgT2N0YWhlZHJvbkdlb21ldHJ5LCBPbmVGYWN0b3IsIE9uZU1pbnVzQ29uc3RhbnRBbHBoYUZhY3RvciwgT25lTWludXNDb25zdGFudENvbG9yRmFjdG9yLCBPbmVNaW51c0RzdEFscGhhRmFjdG9yLCBPbmVNaW51c0RzdENvbG9yRmFjdG9yLCBPbmVNaW51c1NyY0FscGhhRmFjdG9yLCBPbmVNaW51c1NyY0NvbG9yRmFjdG9yLCBPcnRob2dyYXBoaWNDYW1lcmEsIFAzUHJpbWFyaWVzLCBQQ0ZTaGFkb3dNYXAsIFBDRlNvZnRTaGFkb3dNYXAsIFBNUkVNR2VuZXJhdG9yLCBQYXRoLCBQZXJzcGVjdGl2ZUNhbWVyYSwgUGxhbmUsIFBsYW5lR2VvbWV0cnksIFBsYW5lSGVscGVyLCBQb2ludExpZ2h0LCBQb2ludExpZ2h0SGVscGVyLCBQb2ludHMsIFBvaW50c01hdGVyaWFsLCBQb2xhckdyaWRIZWxwZXIsIFBvbHloZWRyb25HZW9tZXRyeSwgUG9zaXRpb25hbEF1ZGlvLCBQcm9wZXJ0eUJpbmRpbmcsIFByb3BlcnR5TWl4ZXIsIFF1YWRyYXRpY0JlemllckN1cnZlLCBRdWFkcmF0aWNCZXppZXJDdXJ2ZTMsIFF1YXRlcm5pb24sIFF1YXRlcm5pb25LZXlmcmFtZVRyYWNrLCBRdWF0ZXJuaW9uTGluZWFySW50ZXJwb2xhbnQsIFJFRF9HUkVFTl9SR1RDMl9Gb3JtYXQsIFJFRF9SR1RDMV9Gb3JtYXQsIFJFVklTSU9OLCBSR0JBRGVwdGhQYWNraW5nLCBSR0JBRm9ybWF0LCBSR0JBSW50ZWdlckZvcm1hdCwgUkdCQV9BU1RDXzEweDEwX0Zvcm1hdCwgUkdCQV9BU1RDXzEweDVfRm9ybWF0LCBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQsIFJHQkFfQVNUQ18xMHg4X0Zvcm1hdCwgUkdCQV9BU1RDXzEyeDEwX0Zvcm1hdCwgUkdCQV9BU1RDXzEyeDEyX0Zvcm1hdCwgUkdCQV9BU1RDXzR4NF9Gb3JtYXQsIFJHQkFfQVNUQ181eDRfRm9ybWF0LCBSR0JBX0FTVENfNXg1X0Zvcm1hdCwgUkdCQV9BU1RDXzZ4NV9Gb3JtYXQsIFJHQkFfQVNUQ182eDZfRm9ybWF0LCBSR0JBX0FTVENfOHg1X0Zvcm1hdCwgUkdCQV9BU1RDXzh4Nl9Gb3JtYXQsIFJHQkFfQVNUQ184eDhfRm9ybWF0LCBSR0JBX0JQVENfRm9ybWF0LCBSR0JBX0VUQzJfRUFDX0Zvcm1hdCwgUkdCQV9QVlJUQ18yQlBQVjFfRm9ybWF0LCBSR0JBX1BWUlRDXzRCUFBWMV9Gb3JtYXQsIFJHQkFfUzNUQ19EWFQxX0Zvcm1hdCwgUkdCQV9TM1RDX0RYVDNfRm9ybWF0LCBSR0JBX1MzVENfRFhUNV9Gb3JtYXQsIFJHQkZvcm1hdCwgUkdCSW50ZWdlckZvcm1hdCwgUkdCX0JQVENfU0lHTkVEX0Zvcm1hdCwgUkdCX0JQVENfVU5TSUdORURfRm9ybWF0LCBSR0JfRVRDMV9Gb3JtYXQsIFJHQl9FVEMyX0Zvcm1hdCwgUkdCX1BWUlRDXzJCUFBWMV9Gb3JtYXQsIFJHQl9QVlJUQ180QlBQVjFfRm9ybWF0LCBSR0JfUzNUQ19EWFQxX0Zvcm1hdCwgUkdGb3JtYXQsIFJHSW50ZWdlckZvcm1hdCwgUmF3U2hhZGVyTWF0ZXJpYWwsIFJheSwgUmF5Y2FzdGVyLCBSZWM3MDlQcmltYXJpZXMsIFJlY3RBcmVhTGlnaHQsIFJlZEZvcm1hdCwgUmVkSW50ZWdlckZvcm1hdCwgUmVpbmhhcmRUb25lTWFwcGluZywgUmVuZGVyVGFyZ2V0LCBSZXBlYXRXcmFwcGluZywgUmVwbGFjZVN0ZW5jaWxPcCwgUmV2ZXJzZVN1YnRyYWN0RXF1YXRpb24sIFJpbmdHZW9tZXRyeSwgU0lHTkVEX1JFRF9HUkVFTl9SR1RDMl9Gb3JtYXQsIFNJR05FRF9SRURfUkdUQzFfRm9ybWF0LCBTUkdCQ29sb3JTcGFjZSwgU1JHQlRyYW5zZmVyLCBTY2VuZSwgU2hhZGVyQ2h1bmssIFNoYWRlckxpYiwgU2hhZGVyTWF0ZXJpYWwsIFNoYWRvd01hdGVyaWFsLCBTaGFwZSwgU2hhcGVHZW9tZXRyeSwgU2hhcGVQYXRoLCBTaGFwZVV0aWxzLCBTaG9ydFR5cGUsIFNrZWxldG9uLCBTa2VsZXRvbkhlbHBlciwgU2tpbm5lZE1lc2gsIFNvdXJjZSwgU3BoZXJlLCBTcGhlcmVHZW9tZXRyeSwgU3BoZXJpY2FsLCBTcGhlcmljYWxIYXJtb25pY3MzLCBTcGxpbmVDdXJ2ZSwgU3BvdExpZ2h0LCBTcG90TGlnaHRIZWxwZXIsIFNwcml0ZSwgU3ByaXRlTWF0ZXJpYWwsIFNyY0FscGhhRmFjdG9yLCBTcmNBbHBoYVNhdHVyYXRlRmFjdG9yLCBTcmNDb2xvckZhY3RvciwgU3RhdGljQ29weVVzYWdlLCBTdGF0aWNEcmF3VXNhZ2UsIFN0YXRpY1JlYWRVc2FnZSwgU3RlcmVvQ2FtZXJhLCBTdHJlYW1Db3B5VXNhZ2UsIFN0cmVhbURyYXdVc2FnZSwgU3RyZWFtUmVhZFVzYWdlLCBTdHJpbmdLZXlmcmFtZVRyYWNrLCBTdWJ0cmFjdEVxdWF0aW9uLCBTdWJ0cmFjdGl2ZUJsZW5kaW5nLCBUT1VDSCwgVGFuZ2VudFNwYWNlTm9ybWFsTWFwLCBUZXRyYWhlZHJvbkdlb21ldHJ5LCBUZXh0dXJlLCBUZXh0dXJlTG9hZGVyLCBUZXh0dXJlVXRpbHMsIFRvcnVzR2VvbWV0cnksIFRvcnVzS25vdEdlb21ldHJ5LCBUcmlhbmdsZSwgVHJpYW5nbGVGYW5EcmF3TW9kZSwgVHJpYW5nbGVTdHJpcERyYXdNb2RlLCBUcmlhbmdsZXNEcmF3TW9kZSwgVHViZUdlb21ldHJ5LCBVVk1hcHBpbmcsIFVpbnQxNkJ1ZmZlckF0dHJpYnV0ZSwgVWludDMyQnVmZmVyQXR0cmlidXRlLCBVaW50OEJ1ZmZlckF0dHJpYnV0ZSwgVWludDhDbGFtcGVkQnVmZmVyQXR0cmlidXRlLCBVbmlmb3JtLCBVbmlmb3Jtc0dyb3VwLCBVbmlmb3Jtc0xpYiwgVW5pZm9ybXNVdGlscywgVW5zaWduZWRCeXRlVHlwZSwgVW5zaWduZWRJbnQyNDhUeXBlLCBVbnNpZ25lZEludDU5OTlUeXBlLCBVbnNpZ25lZEludFR5cGUsIFVuc2lnbmVkU2hvcnQ0NDQ0VHlwZSwgVW5zaWduZWRTaG9ydDU1NTFUeXBlLCBVbnNpZ25lZFNob3J0VHlwZSwgVlNNU2hhZG93TWFwLCBWZWN0b3IyLCBWZWN0b3IzLCBWZWN0b3I0LCBWZWN0b3JLZXlmcmFtZVRyYWNrLCBWaWRlb1RleHR1cmUsIFdlYkdMM0RSZW5kZXJUYXJnZXQsIFdlYkdMQXJyYXlSZW5kZXJUYXJnZXQsIFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSwgV2ViR0xDdWJlUmVuZGVyVGFyZ2V0LCBXZWJHTE11bHRpcGxlUmVuZGVyVGFyZ2V0cywgV2ViR0xSZW5kZXJUYXJnZXQsIFdlYkdMUmVuZGVyZXIsIFdlYkdMVXRpbHMsIFdlYkdQVUNvb3JkaW5hdGVTeXN0ZW0sIFdpcmVmcmFtZUdlb21ldHJ5LCBXcmFwQXJvdW5kRW5kaW5nLCBaZXJvQ3VydmF0dXJlRW5kaW5nLCBaZXJvRmFjdG9yLCBaZXJvU2xvcGVFbmRpbmcsIFplcm9TdGVuY2lsT3AsIGNyZWF0ZUNhbnZhc0VsZW1lbnQgfTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///753\n")},580:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ N: () => (/* binding */ OrbitControls)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(753);\n\n\n// OrbitControls performs orbiting, dollying (zooming), and panning.\n// Unlike TrackballControls, it maintains the \"up\" direction object.up (+Y by default).\n//\n// Orbit - left mouse / touch: one-finger move\n// Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish\n// Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move\n\nconst _changeEvent = { type: 'change' };\nconst _startEvent = { type: 'start' };\nconst _endEvent = { type: 'end' };\nconst _ray = new three__WEBPACK_IMPORTED_MODULE_0__/* .Ray */ .RlV();\nconst _plane = new three__WEBPACK_IMPORTED_MODULE_0__/* .Plane */ .Zcv();\nconst TILT_LIMIT = Math.cos( 70 * three__WEBPACK_IMPORTED_MODULE_0__/* .MathUtils */ .cj9.DEG2RAD );\n\nclass OrbitControls extends three__WEBPACK_IMPORTED_MODULE_0__/* .EventDispatcher */ .Qev {\n\n\tconstructor( object, domElement ) {\n\n\t\tsuper();\n\n\t\tthis.object = object;\n\t\tthis.domElement = domElement;\n\t\tthis.domElement.style.touchAction = 'none'; // disable touch scroll\n\n\t\t// Set to false to disable this control\n\t\tthis.enabled = true;\n\n\t\t// \"target\" sets the location of focus, where the object orbits around\n\t\tthis.target = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t// Sets the 3D cursor (similar to Blender), from which the maxTargetRadius takes effect\n\t\tthis.cursor = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t// How far you can dolly in and out ( PerspectiveCamera only )\n\t\tthis.minDistance = 0;\n\t\tthis.maxDistance = Infinity;\n\n\t\t// How far you can zoom in and out ( OrthographicCamera only )\n\t\tthis.minZoom = 0;\n\t\tthis.maxZoom = Infinity;\n\n\t\t// Limit camera target within a spherical area around the cursor\n\t\tthis.minTargetRadius = 0;\n\t\tthis.maxTargetRadius = Infinity;\n\n\t\t// How far you can orbit vertically, upper and lower limits.\n\t\t// Range is 0 to Math.PI radians.\n\t\tthis.minPolarAngle = 0; // radians\n\t\tthis.maxPolarAngle = Math.PI; // radians\n\n\t\t// How far you can orbit horizontally, upper and lower limits.\n\t\t// If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI )\n\t\tthis.minAzimuthAngle = - Infinity; // radians\n\t\tthis.maxAzimuthAngle = Infinity; // radians\n\n\t\t// Set to true to enable damping (inertia)\n\t\t// If damping is enabled, you must call controls.update() in your animation loop\n\t\tthis.enableDamping = false;\n\t\tthis.dampingFactor = 0.05;\n\n\t\t// This option actually enables dollying in and out; left as \"zoom\" for backwards compatibility.\n\t\t// Set to false to disable zooming\n\t\tthis.enableZoom = true;\n\t\tthis.zoomSpeed = 1.0;\n\n\t\t// Set to false to disable rotating\n\t\tthis.enableRotate = true;\n\t\tthis.rotateSpeed = 1.0;\n\n\t\t// Set to false to disable panning\n\t\tthis.enablePan = true;\n\t\tthis.panSpeed = 1.0;\n\t\tthis.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up\n\t\tthis.keyPanSpeed = 7.0;\t// pixels moved per arrow key push\n\t\tthis.zoomToCursor = false;\n\n\t\t// Set to true to automatically rotate around the target\n\t\t// If auto-rotate is enabled, you must call controls.update() in your animation loop\n\t\tthis.autoRotate = false;\n\t\tthis.autoRotateSpeed = 2.0; // 30 seconds per orbit when fps is 60\n\n\t\t// The four arrow keys\n\t\tthis.keys = { LEFT: 'ArrowLeft', UP: 'ArrowUp', RIGHT: 'ArrowRight', BOTTOM: 'ArrowDown' };\n\n\t\t// Mouse buttons\n\t\tthis.mouseButtons = { LEFT: three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.ROTATE, MIDDLE: three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.DOLLY, RIGHT: three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.PAN };\n\n\t\t// Touch fingers\n\t\tthis.touches = { ONE: three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.ROTATE, TWO: three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.DOLLY_PAN };\n\n\t\t// for reset\n\t\tthis.target0 = this.target.clone();\n\t\tthis.position0 = this.object.position.clone();\n\t\tthis.zoom0 = this.object.zoom;\n\n\t\t// the target DOM element for key events\n\t\tthis._domElementKeyEvents = null;\n\n\t\t//\n\t\t// public methods\n\t\t//\n\n\t\tthis.getPolarAngle = function () {\n\n\t\t\treturn spherical.phi;\n\n\t\t};\n\n\t\tthis.getAzimuthalAngle = function () {\n\n\t\t\treturn spherical.theta;\n\n\t\t};\n\n\t\tthis.getDistance = function () {\n\n\t\t\treturn this.object.position.distanceTo( this.target );\n\n\t\t};\n\n\t\tthis.listenToKeyEvents = function ( domElement ) {\n\n\t\t\tdomElement.addEventListener( 'keydown', onKeyDown );\n\t\t\tthis._domElementKeyEvents = domElement;\n\n\t\t};\n\n\t\tthis.stopListenToKeyEvents = function () {\n\n\t\t\tthis._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown );\n\t\t\tthis._domElementKeyEvents = null;\n\n\t\t};\n\n\t\tthis.saveState = function () {\n\n\t\t\tscope.target0.copy( scope.target );\n\t\t\tscope.position0.copy( scope.object.position );\n\t\t\tscope.zoom0 = scope.object.zoom;\n\n\t\t};\n\n\t\tthis.reset = function () {\n\n\t\t\tscope.target.copy( scope.target0 );\n\t\t\tscope.object.position.copy( scope.position0 );\n\t\t\tscope.object.zoom = scope.zoom0;\n\n\t\t\tscope.object.updateProjectionMatrix();\n\t\t\tscope.dispatchEvent( _changeEvent );\n\n\t\t\tscope.update();\n\n\t\t\tstate = STATE.NONE;\n\n\t\t};\n\n\t\t// this method is exposed, but perhaps it would be better if we can make it private...\n\t\tthis.update = function () {\n\n\t\t\tconst offset = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t\t// so camera.up is the orbit axis\n\t\t\tconst quat = new three__WEBPACK_IMPORTED_MODULE_0__/* .Quaternion */ .PTz().setFromUnitVectors( object.up, new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0( 0, 1, 0 ) );\n\t\t\tconst quatInverse = quat.clone().invert();\n\n\t\t\tconst lastPosition = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\t\t\tconst lastQuaternion = new three__WEBPACK_IMPORTED_MODULE_0__/* .Quaternion */ .PTz();\n\t\t\tconst lastTargetPosition = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t\tconst twoPI = 2 * Math.PI;\n\n\t\t\treturn function update( deltaTime = null ) {\n\n\t\t\t\tconst position = scope.object.position;\n\n\t\t\t\toffset.copy( position ).sub( scope.target );\n\n\t\t\t\t// rotate offset to \"y-axis-is-up\" space\n\t\t\t\toffset.applyQuaternion( quat );\n\n\t\t\t\t// angle from z-axis around y-axis\n\t\t\t\tspherical.setFromVector3( offset );\n\n\t\t\t\tif ( scope.autoRotate && state === STATE.NONE ) {\n\n\t\t\t\t\trotateLeft( getAutoRotationAngle( deltaTime ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( scope.enableDamping ) {\n\n\t\t\t\t\tspherical.theta += sphericalDelta.theta * scope.dampingFactor;\n\t\t\t\t\tspherical.phi += sphericalDelta.phi * scope.dampingFactor;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tspherical.theta += sphericalDelta.theta;\n\t\t\t\t\tspherical.phi += sphericalDelta.phi;\n\n\t\t\t\t}\n\n\t\t\t\t// restrict theta to be between desired limits\n\n\t\t\t\tlet min = scope.minAzimuthAngle;\n\t\t\t\tlet max = scope.maxAzimuthAngle;\n\n\t\t\t\tif ( isFinite( min ) && isFinite( max ) ) {\n\n\t\t\t\t\tif ( min < - Math.PI ) min += twoPI; else if ( min > Math.PI ) min -= twoPI;\n\n\t\t\t\t\tif ( max < - Math.PI ) max += twoPI; else if ( max > Math.PI ) max -= twoPI;\n\n\t\t\t\t\tif ( min <= max ) {\n\n\t\t\t\t\t\tspherical.theta = Math.max( min, Math.min( max, spherical.theta ) );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tspherical.theta = ( spherical.theta > ( min + max ) / 2 ) ?\n\t\t\t\t\t\t\tMath.max( min, spherical.theta ) :\n\t\t\t\t\t\t\tMath.min( max, spherical.theta );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// restrict phi to be between desired limits\n\t\t\t\tspherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );\n\n\t\t\t\tspherical.makeSafe();\n\n\n\t\t\t\t// move target to panned location\n\n\t\t\t\tif ( scope.enableDamping === true ) {\n\n\t\t\t\t\tscope.target.addScaledVector( panOffset, scope.dampingFactor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tscope.target.add( panOffset );\n\n\t\t\t\t}\n\n\t\t\t\t// Limit the target distance from the cursor to create a sphere around the center of interest\n\t\t\t\tscope.target.sub( scope.cursor );\n\t\t\t\tscope.target.clampLength( scope.minTargetRadius, scope.maxTargetRadius );\n\t\t\t\tscope.target.add( scope.cursor );\n\n\t\t\t\tlet zoomChanged = false;\n\t\t\t\t// adjust the camera position based on zoom only if we're not zooming to the cursor or if it's an ortho camera\n\t\t\t\t// we adjust zoom later in these cases\n\t\t\t\tif ( scope.zoomToCursor && performCursorZoom || scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\tspherical.radius = clampDistance( spherical.radius );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconst prevRadius = spherical.radius;\n\t\t\t\t\tspherical.radius = clampDistance( spherical.radius * scale );\n\t\t\t\t\tzoomChanged = prevRadius != spherical.radius;\n\n\t\t\t\t}\n\n\t\t\t\toffset.setFromSpherical( spherical );\n\n\t\t\t\t// rotate offset back to \"camera-up-vector-is-up\" space\n\t\t\t\toffset.applyQuaternion( quatInverse );\n\n\t\t\t\tposition.copy( scope.target ).add( offset );\n\n\t\t\t\tscope.object.lookAt( scope.target );\n\n\t\t\t\tif ( scope.enableDamping === true ) {\n\n\t\t\t\t\tsphericalDelta.theta *= ( 1 - scope.dampingFactor );\n\t\t\t\t\tsphericalDelta.phi *= ( 1 - scope.dampingFactor );\n\n\t\t\t\t\tpanOffset.multiplyScalar( 1 - scope.dampingFactor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tsphericalDelta.set( 0, 0, 0 );\n\n\t\t\t\t\tpanOffset.set( 0, 0, 0 );\n\n\t\t\t\t}\n\n\t\t\t\t// adjust camera position\n\t\t\t\tif ( scope.zoomToCursor && performCursorZoom ) {\n\n\t\t\t\t\tlet newRadius = null;\n\t\t\t\t\tif ( scope.object.isPerspectiveCamera ) {\n\n\t\t\t\t\t\t// move the camera down the pointer ray\n\t\t\t\t\t\t// this method avoids floating point error\n\t\t\t\t\t\tconst prevRadius = offset.length();\n\t\t\t\t\t\tnewRadius = clampDistance( prevRadius * scale );\n\n\t\t\t\t\t\tconst radiusDelta = prevRadius - newRadius;\n\t\t\t\t\t\tscope.object.position.addScaledVector( dollyDirection, radiusDelta );\n\t\t\t\t\t\tscope.object.updateMatrixWorld();\n\n\t\t\t\t\t\tzoomChanged = !! radiusDelta;\n\n\t\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\t\t// adjust the ortho camera position based on zoom changes\n\t\t\t\t\t\tconst mouseBefore = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0( mouse.x, mouse.y, 0 );\n\t\t\t\t\t\tmouseBefore.unproject( scope.object );\n\n\t\t\t\t\t\tconst prevZoom = scope.object.zoom;\n\t\t\t\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) );\n\t\t\t\t\t\tscope.object.updateProjectionMatrix();\n\n\t\t\t\t\t\tzoomChanged = prevZoom !== scope.object.zoom;\n\n\t\t\t\t\t\tconst mouseAfter = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0( mouse.x, mouse.y, 0 );\n\t\t\t\t\t\tmouseAfter.unproject( scope.object );\n\n\t\t\t\t\t\tscope.object.position.sub( mouseAfter ).add( mouseBefore );\n\t\t\t\t\t\tscope.object.updateMatrixWorld();\n\n\t\t\t\t\t\tnewRadius = offset.length();\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled.' );\n\t\t\t\t\t\tscope.zoomToCursor = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// handle the placement of the target\n\t\t\t\t\tif ( newRadius !== null ) {\n\n\t\t\t\t\t\tif ( this.screenSpacePanning ) {\n\n\t\t\t\t\t\t\t// position the orbit target in front of the new camera position\n\t\t\t\t\t\t\tscope.target.set( 0, 0, - 1 )\n\t\t\t\t\t\t\t\t.transformDirection( scope.object.matrix )\n\t\t\t\t\t\t\t\t.multiplyScalar( newRadius )\n\t\t\t\t\t\t\t\t.add( scope.object.position );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// get the ray and translation plane to compute target\n\t\t\t\t\t\t\t_ray.origin.copy( scope.object.position );\n\t\t\t\t\t\t\t_ray.direction.set( 0, 0, - 1 ).transformDirection( scope.object.matrix );\n\n\t\t\t\t\t\t\t// if the camera is 20 degrees above the horizon then don't adjust the focus target to avoid\n\t\t\t\t\t\t\t// extremely large values\n\t\t\t\t\t\t\tif ( Math.abs( scope.object.up.dot( _ray.direction ) ) < TILT_LIMIT ) {\n\n\t\t\t\t\t\t\t\tobject.lookAt( scope.target );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t_plane.setFromNormalAndCoplanarPoint( scope.object.up, scope.target );\n\t\t\t\t\t\t\t\t_ray.intersectPlane( _plane, scope.target );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\tconst prevZoom = scope.object.zoom;\n\t\t\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) );\n\n\t\t\t\t\tif ( prevZoom !== scope.object.zoom ) {\n\n\t\t\t\t\t\tscope.object.updateProjectionMatrix();\n\t\t\t\t\t\tzoomChanged = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tscale = 1;\n\t\t\t\tperformCursorZoom = false;\n\n\t\t\t\t// update condition is:\n\t\t\t\t// min(camera displacement, camera rotation in radians)^2 > EPS\n\t\t\t\t// using small-angle approximation cos(x/2) = 1 - x^2 / 8\n\n\t\t\t\tif ( zoomChanged ||\n\t\t\t\t\tlastPosition.distanceToSquared( scope.object.position ) > EPS ||\n\t\t\t\t\t8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ||\n\t\t\t\t\tlastTargetPosition.distanceToSquared( scope.target ) > EPS ) {\n\n\t\t\t\t\tscope.dispatchEvent( _changeEvent );\n\n\t\t\t\t\tlastPosition.copy( scope.object.position );\n\t\t\t\t\tlastQuaternion.copy( scope.object.quaternion );\n\t\t\t\t\tlastTargetPosition.copy( scope.target );\n\n\t\t\t\t\treturn true;\n\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\n\t\t\t};\n\n\t\t}();\n\n\t\tthis.dispose = function () {\n\n\t\t\tscope.domElement.removeEventListener( 'contextmenu', onContextMenu );\n\n\t\t\tscope.domElement.removeEventListener( 'pointerdown', onPointerDown );\n\t\t\tscope.domElement.removeEventListener( 'pointercancel', onPointerUp );\n\t\t\tscope.domElement.removeEventListener( 'wheel', onMouseWheel );\n\n\t\t\tscope.domElement.removeEventListener( 'pointermove', onPointerMove );\n\t\t\tscope.domElement.removeEventListener( 'pointerup', onPointerUp );\n\n\t\t\tconst document = scope.domElement.getRootNode(); // offscreen canvas compatibility\n\n\t\t\tdocument.removeEventListener( 'keydown', interceptControlDown, { capture: true } );\n\n\t\t\tif ( scope._domElementKeyEvents !== null ) {\n\n\t\t\t\tscope._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown );\n\t\t\t\tscope._domElementKeyEvents = null;\n\n\t\t\t}\n\n\t\t\t//scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?\n\n\t\t};\n\n\t\t//\n\t\t// internals\n\t\t//\n\n\t\tconst scope = this;\n\n\t\tconst STATE = {\n\t\t\tNONE: - 1,\n\t\t\tROTATE: 0,\n\t\t\tDOLLY: 1,\n\t\t\tPAN: 2,\n\t\t\tTOUCH_ROTATE: 3,\n\t\t\tTOUCH_PAN: 4,\n\t\t\tTOUCH_DOLLY_PAN: 5,\n\t\t\tTOUCH_DOLLY_ROTATE: 6\n\t\t};\n\n\t\tlet state = STATE.NONE;\n\n\t\tconst EPS = 0.000001;\n\n\t\t// current position in spherical coordinates\n\t\tconst spherical = new three__WEBPACK_IMPORTED_MODULE_0__/* .Spherical */ .YHV();\n\t\tconst sphericalDelta = new three__WEBPACK_IMPORTED_MODULE_0__/* .Spherical */ .YHV();\n\n\t\tlet scale = 1;\n\t\tconst panOffset = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\tconst rotateStart = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst rotateEnd = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst rotateDelta = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\n\t\tconst panStart = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst panEnd = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst panDelta = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\n\t\tconst dollyStart = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst dollyEnd = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst dollyDelta = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\n\t\tconst dollyDirection = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\t\tconst mouse = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tlet performCursorZoom = false;\n\n\t\tconst pointers = [];\n\t\tconst pointerPositions = {};\n\n\t\tlet controlActive = false;\n\n\t\tfunction getAutoRotationAngle( deltaTime ) {\n\n\t\t\tif ( deltaTime !== null ) {\n\n\t\t\t\treturn ( 2 * Math.PI / 60 * scope.autoRotateSpeed ) * deltaTime;\n\n\t\t\t} else {\n\n\t\t\t\treturn 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getZoomScale( delta ) {\n\n\t\t\tconst normalizedDelta = Math.abs( delta * 0.01 );\n\t\t\treturn Math.pow( 0.95, scope.zoomSpeed * normalizedDelta );\n\n\t\t}\n\n\t\tfunction rotateLeft( angle ) {\n\n\t\t\tsphericalDelta.theta -= angle;\n\n\t\t}\n\n\t\tfunction rotateUp( angle ) {\n\n\t\t\tsphericalDelta.phi -= angle;\n\n\t\t}\n\n\t\tconst panLeft = function () {\n\n\t\t\tconst v = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t\treturn function panLeft( distance, objectMatrix ) {\n\n\t\t\t\tv.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix\n\t\t\t\tv.multiplyScalar( - distance );\n\n\t\t\t\tpanOffset.add( v );\n\n\t\t\t};\n\n\t\t}();\n\n\t\tconst panUp = function () {\n\n\t\t\tconst v = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t\treturn function panUp( distance, objectMatrix ) {\n\n\t\t\t\tif ( scope.screenSpacePanning === true ) {\n\n\t\t\t\t\tv.setFromMatrixColumn( objectMatrix, 1 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tv.setFromMatrixColumn( objectMatrix, 0 );\n\t\t\t\t\tv.crossVectors( scope.object.up, v );\n\n\t\t\t\t}\n\n\t\t\t\tv.multiplyScalar( distance );\n\n\t\t\t\tpanOffset.add( v );\n\n\t\t\t};\n\n\t\t}();\n\n\t\t// deltaX and deltaY are in pixels; right and down are positive\n\t\tconst pan = function () {\n\n\t\t\tconst offset = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t\treturn function pan( deltaX, deltaY ) {\n\n\t\t\t\tconst element = scope.domElement;\n\n\t\t\t\tif ( scope.object.isPerspectiveCamera ) {\n\n\t\t\t\t\t// perspective\n\t\t\t\t\tconst position = scope.object.position;\n\t\t\t\t\toffset.copy( position ).sub( scope.target );\n\t\t\t\t\tlet targetDistance = offset.length();\n\n\t\t\t\t\t// half of the fov is center to top of screen\n\t\t\t\t\ttargetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );\n\n\t\t\t\t\t// we use only clientHeight here so aspect ratio does not distort speed\n\t\t\t\t\tpanLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );\n\t\t\t\t\tpanUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );\n\n\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\t// orthographic\n\t\t\t\t\tpanLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );\n\t\t\t\t\tpanUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// camera neither orthographic nor perspective\n\t\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );\n\t\t\t\t\tscope.enablePan = false;\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}();\n\n\t\tfunction dollyOut( dollyScale ) {\n\n\t\t\tif ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) {\n\n\t\t\t\tscale /= dollyScale;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\t\tscope.enableZoom = false;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction dollyIn( dollyScale ) {\n\n\t\t\tif ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) {\n\n\t\t\t\tscale *= dollyScale;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\t\tscope.enableZoom = false;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction updateZoomParameters( x, y ) {\n\n\t\t\tif ( ! scope.zoomToCursor ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tperformCursorZoom = true;\n\n\t\t\tconst rect = scope.domElement.getBoundingClientRect();\n\t\t\tconst dx = x - rect.left;\n\t\t\tconst dy = y - rect.top;\n\t\t\tconst w = rect.width;\n\t\t\tconst h = rect.height;\n\n\t\t\tmouse.x = ( dx / w ) * 2 - 1;\n\t\t\tmouse.y = - ( dy / h ) * 2 + 1;\n\n\t\t\tdollyDirection.set( mouse.x, mouse.y, 1 ).unproject( scope.object ).sub( scope.object.position ).normalize();\n\n\t\t}\n\n\t\tfunction clampDistance( dist ) {\n\n\t\t\treturn Math.max( scope.minDistance, Math.min( scope.maxDistance, dist ) );\n\n\t\t}\n\n\t\t//\n\t\t// event callbacks - update the object state\n\t\t//\n\n\t\tfunction handleMouseDownRotate( event ) {\n\n\t\t\trotateStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseDownDolly( event ) {\n\n\t\t\tupdateZoomParameters( event.clientX, event.clientX );\n\t\t\tdollyStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseDownPan( event ) {\n\n\t\t\tpanStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseMoveRotate( event ) {\n\n\t\t\trotateEnd.set( event.clientX, event.clientY );\n\n\t\t\trotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );\n\n\t\t\tconst element = scope.domElement;\n\n\t\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height\n\n\t\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );\n\n\t\t\trotateStart.copy( rotateEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseMoveDolly( event ) {\n\n\t\t\tdollyEnd.set( event.clientX, event.clientY );\n\n\t\t\tdollyDelta.subVectors( dollyEnd, dollyStart );\n\n\t\t\tif ( dollyDelta.y > 0 ) {\n\n\t\t\t\tdollyOut( getZoomScale( dollyDelta.y ) );\n\n\t\t\t} else if ( dollyDelta.y < 0 ) {\n\n\t\t\t\tdollyIn( getZoomScale( dollyDelta.y ) );\n\n\t\t\t}\n\n\t\t\tdollyStart.copy( dollyEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseMovePan( event ) {\n\n\t\t\tpanEnd.set( event.clientX, event.clientY );\n\n\t\t\tpanDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );\n\n\t\t\tpan( panDelta.x, panDelta.y );\n\n\t\t\tpanStart.copy( panEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseWheel( event ) {\n\n\t\t\tupdateZoomParameters( event.clientX, event.clientY );\n\n\t\t\tif ( event.deltaY < 0 ) {\n\n\t\t\t\tdollyIn( getZoomScale( event.deltaY ) );\n\n\t\t\t} else if ( event.deltaY > 0 ) {\n\n\t\t\t\tdollyOut( getZoomScale( event.deltaY ) );\n\n\t\t\t}\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleKeyDown( event ) {\n\n\t\t\tlet needsUpdate = false;\n\n\t\t\tswitch ( event.code ) {\n\n\t\t\t\tcase scope.keys.UP:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateUp( 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( 0, scope.keyPanSpeed );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.BOTTOM:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateUp( - 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( 0, - scope.keyPanSpeed );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.LEFT:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateLeft( 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( scope.keyPanSpeed, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.RIGHT:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateLeft( - 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( - scope.keyPanSpeed, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( needsUpdate ) {\n\n\t\t\t\t// prevent the browser from scrolling on cursor keys\n\t\t\t\tevent.preventDefault();\n\n\t\t\t\tscope.update();\n\n\t\t\t}\n\n\n\t\t}\n\n\t\tfunction handleTouchStartRotate( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\trotateStart.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\trotateStart.set( x, y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction handleTouchStartPan( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\tpanStart.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\tpanStart.set( x, y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction handleTouchStartDolly( event ) {\n\n\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\tconst dx = event.pageX - position.x;\n\t\t\tconst dy = event.pageY - position.y;\n\n\t\t\tconst distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tdollyStart.set( 0, distance );\n\n\t\t}\n\n\t\tfunction handleTouchStartDollyPan( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchStartDolly( event );\n\n\t\t\tif ( scope.enablePan ) handleTouchStartPan( event );\n\n\t\t}\n\n\t\tfunction handleTouchStartDollyRotate( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchStartDolly( event );\n\n\t\t\tif ( scope.enableRotate ) handleTouchStartRotate( event );\n\n\t\t}\n\n\t\tfunction handleTouchMoveRotate( event ) {\n\n\t\t\tif ( pointers.length == 1 ) {\n\n\t\t\t\trotateEnd.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\trotateEnd.set( x, y );\n\n\t\t\t}\n\n\t\t\trotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );\n\n\t\t\tconst element = scope.domElement;\n\n\t\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height\n\n\t\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );\n\n\t\t\trotateStart.copy( rotateEnd );\n\n\t\t}\n\n\t\tfunction handleTouchMovePan( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\tpanEnd.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\tpanEnd.set( x, y );\n\n\t\t\t}\n\n\t\t\tpanDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );\n\n\t\t\tpan( panDelta.x, panDelta.y );\n\n\t\t\tpanStart.copy( panEnd );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDolly( event ) {\n\n\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\tconst dx = event.pageX - position.x;\n\t\t\tconst dy = event.pageY - position.y;\n\n\t\t\tconst distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tdollyEnd.set( 0, distance );\n\n\t\t\tdollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );\n\n\t\t\tdollyOut( dollyDelta.y );\n\n\t\t\tdollyStart.copy( dollyEnd );\n\n\t\t\tconst centerX = ( event.pageX + position.x ) * 0.5;\n\t\t\tconst centerY = ( event.pageY + position.y ) * 0.5;\n\n\t\t\tupdateZoomParameters( centerX, centerY );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDollyPan( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchMoveDolly( event );\n\n\t\t\tif ( scope.enablePan ) handleTouchMovePan( event );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDollyRotate( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchMoveDolly( event );\n\n\t\t\tif ( scope.enableRotate ) handleTouchMoveRotate( event );\n\n\t\t}\n\n\t\t//\n\t\t// event handlers - FSM: listen for events and reset state\n\t\t//\n\n\t\tfunction onPointerDown( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tif ( pointers.length === 0 ) {\n\n\t\t\t\tscope.domElement.setPointerCapture( event.pointerId );\n\n\t\t\t\tscope.domElement.addEventListener( 'pointermove', onPointerMove );\n\t\t\t\tscope.domElement.addEventListener( 'pointerup', onPointerUp );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( isTrackingPointer( event ) ) return;\n\n\t\t\t//\n\n\t\t\taddPointer( event );\n\n\t\t\tif ( event.pointerType === 'touch' ) {\n\n\t\t\t\tonTouchStart( event );\n\n\t\t\t} else {\n\n\t\t\t\tonMouseDown( event );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onPointerMove( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tif ( event.pointerType === 'touch' ) {\n\n\t\t\t\tonTouchMove( event );\n\n\t\t\t} else {\n\n\t\t\t\tonMouseMove( event );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onPointerUp( event ) {\n\n\t\t\tremovePointer( event );\n\n\t\t\tswitch ( pointers.length ) {\n\n\t\t\t\tcase 0:\n\n\t\t\t\t\tscope.domElement.releasePointerCapture( event.pointerId );\n\n\t\t\t\t\tscope.domElement.removeEventListener( 'pointermove', onPointerMove );\n\t\t\t\t\tscope.domElement.removeEventListener( 'pointerup', onPointerUp );\n\n\t\t\t\t\tscope.dispatchEvent( _endEvent );\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 1:\n\n\t\t\t\t\tconst pointerId = pointers[ 0 ];\n\t\t\t\t\tconst position = pointerPositions[ pointerId ];\n\n\t\t\t\t\t// minimal placeholder event - allows state correction on pointer-up\n\t\t\t\t\tonTouchStart( { pointerId: pointerId, pageX: position.x, pageY: position.y } );\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseDown( event ) {\n\n\t\t\tlet mouseAction;\n\n\t\t\tswitch ( event.button ) {\n\n\t\t\t\tcase 0:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.LEFT;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 1:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.MIDDLE;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.RIGHT;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tmouseAction = - 1;\n\n\t\t\t}\n\n\t\t\tswitch ( mouseAction ) {\n\n\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.DOLLY:\n\n\t\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\t\thandleMouseDownDolly( event );\n\n\t\t\t\t\tstate = STATE.DOLLY;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.ROTATE:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\thandleMouseDownPan( event );\n\n\t\t\t\t\t\tstate = STATE.PAN;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\thandleMouseDownRotate( event );\n\n\t\t\t\t\t\tstate = STATE.ROTATE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.PAN:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\thandleMouseDownRotate( event );\n\n\t\t\t\t\t\tstate = STATE.ROTATE;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\thandleMouseDownPan( event );\n\n\t\t\t\t\t\tstate = STATE.PAN;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t\tif ( state !== STATE.NONE ) {\n\n\t\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseMove( event ) {\n\n\t\t\tswitch ( state ) {\n\n\t\t\t\tcase STATE.ROTATE:\n\n\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleMouseMoveRotate( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.DOLLY:\n\n\t\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\t\thandleMouseMoveDolly( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.PAN:\n\n\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\thandleMouseMovePan( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseWheel( event ) {\n\n\t\t\tif ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return;\n\n\t\t\tevent.preventDefault();\n\n\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\thandleMouseWheel( customWheelEvent( event ) );\n\n\t\t\tscope.dispatchEvent( _endEvent );\n\n\t\t}\n\n\t\tfunction customWheelEvent( event ) {\n\n\t\t\tconst mode = event.deltaMode;\n\n\t\t\t// minimal wheel event altered to meet delta-zoom demand\n\t\t\tconst newEvent = {\n\t\t\t\tclientX: event.clientX,\n\t\t\t\tclientY: event.clientY,\n\t\t\t\tdeltaY: event.deltaY,\n\t\t\t};\n\n\t\t\tswitch ( mode ) {\n\n\t\t\t\tcase 1: // LINE_MODE\n\t\t\t\t\tnewEvent.deltaY *= 16;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2: // PAGE_MODE\n\t\t\t\t\tnewEvent.deltaY *= 100;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\t// detect if event was triggered by pinching\n\t\t\tif ( event.ctrlKey && ! controlActive ) {\n\n\t\t\t\tnewEvent.deltaY *= 10;\n\n\t\t\t}\n\n\t\t\treturn newEvent;\n\n\t\t}\n\n\t\tfunction interceptControlDown( event ) {\n\n\t\t\tif ( event.key === 'Control' ) {\n\n\t\t\t\tcontrolActive = true;\n\n\n\t\t\t\tconst document = scope.domElement.getRootNode(); // offscreen canvas compatibility\n\n\t\t\t\tdocument.addEventListener( 'keyup', interceptControlUp, { passive: true, capture: true } );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction interceptControlUp( event ) {\n\n\t\t\tif ( event.key === 'Control' ) {\n\n\t\t\t\tcontrolActive = false;\n\n\n\t\t\t\tconst document = scope.domElement.getRootNode(); // offscreen canvas compatibility\n\n\t\t\t\tdocument.removeEventListener( 'keyup', interceptControlUp, { passive: true, capture: true } );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onKeyDown( event ) {\n\n\t\t\tif ( scope.enabled === false || scope.enablePan === false ) return;\n\n\t\t\thandleKeyDown( event );\n\n\t\t}\n\n\t\tfunction onTouchStart( event ) {\n\n\t\t\ttrackPointer( event );\n\n\t\t\tswitch ( pointers.length ) {\n\n\t\t\t\tcase 1:\n\n\t\t\t\t\tswitch ( scope.touches.ONE ) {\n\n\t\t\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.ROTATE:\n\n\t\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartRotate( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_ROTATE;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.PAN:\n\n\t\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartPan( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_PAN;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2:\n\n\t\t\t\t\tswitch ( scope.touches.TWO ) {\n\n\t\t\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.DOLLY_PAN:\n\n\t\t\t\t\t\t\tif ( scope.enableZoom === false && scope.enablePan === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartDollyPan( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_DOLLY_PAN;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.DOLLY_ROTATE:\n\n\t\t\t\t\t\t\tif ( scope.enableZoom === false && scope.enableRotate === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartDollyRotate( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_DOLLY_ROTATE;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t\tif ( state !== STATE.NONE ) {\n\n\t\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onTouchMove( event ) {\n\n\t\t\ttrackPointer( event );\n\n\t\t\tswitch ( state ) {\n\n\t\t\t\tcase STATE.TOUCH_ROTATE:\n\n\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleTouchMoveRotate( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_PAN:\n\n\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\thandleTouchMovePan( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_DOLLY_PAN:\n\n\t\t\t\t\tif ( scope.enableZoom === false && scope.enablePan === false ) return;\n\n\t\t\t\t\thandleTouchMoveDollyPan( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_DOLLY_ROTATE:\n\n\t\t\t\t\tif ( scope.enableZoom === false && scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleTouchMoveDollyRotate( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onContextMenu( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tevent.preventDefault();\n\n\t\t}\n\n\t\tfunction addPointer( event ) {\n\n\t\t\tpointers.push( event.pointerId );\n\n\t\t}\n\n\t\tfunction removePointer( event ) {\n\n\t\t\tdelete pointerPositions[ event.pointerId ];\n\n\t\t\tfor ( let i = 0; i < pointers.length; i ++ ) {\n\n\t\t\t\tif ( pointers[ i ] == event.pointerId ) {\n\n\t\t\t\t\tpointers.splice( i, 1 );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction isTrackingPointer( event ) {\n\n\t\t\tfor ( let i = 0; i < pointers.length; i ++ ) {\n\n\t\t\t\tif ( pointers[ i ] == event.pointerId ) return true;\n\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tfunction trackPointer( event ) {\n\n\t\t\tlet position = pointerPositions[ event.pointerId ];\n\n\t\t\tif ( position === undefined ) {\n\n\t\t\t\tposition = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\t\t\tpointerPositions[ event.pointerId ] = position;\n\n\t\t\t}\n\n\t\t\tposition.set( event.pageX, event.pageY );\n\n\t\t}\n\n\t\tfunction getSecondPointerPosition( event ) {\n\n\t\t\tconst pointerId = ( event.pointerId === pointers[ 0 ] ) ? pointers[ 1 ] : pointers[ 0 ];\n\n\t\t\treturn pointerPositions[ pointerId ];\n\n\t\t}\n\n\t\t//\n\n\t\tscope.domElement.addEventListener( 'contextmenu', onContextMenu );\n\n\t\tscope.domElement.addEventListener( 'pointerdown', onPointerDown );\n\t\tscope.domElement.addEventListener( 'pointercancel', onPointerUp );\n\t\tscope.domElement.addEventListener( 'wheel', onMouseWheel, { passive: false } );\n\n\t\tconst document = scope.domElement.getRootNode(); // offscreen canvas compatibility\n\n\t\tdocument.addEventListener( 'keydown', interceptControlDown, { passive: true, capture: true } );\n\n\t\t// force an update at start\n\n\t\tthis.update();\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNTgwLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFXZTs7QUFFZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsdUJBQXVCO0FBQ3ZCLHNCQUFzQjtBQUN0QixvQkFBb0I7QUFDcEIsaUJBQWlCLGlEQUFHO0FBQ3BCLG1CQUFtQixtREFBSztBQUN4QixrQ0FBa0MsdURBQVM7O0FBRTNDLDRCQUE0Qiw2REFBZTs7QUFFM0M7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLDhDQUE4Qzs7QUFFOUM7QUFDQTs7QUFFQTtBQUNBLG9CQUFvQixxREFBTzs7QUFFM0I7QUFDQSxvQkFBb0IscURBQU87O0FBRTNCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSwwQkFBMEI7QUFDMUIsZ0NBQWdDOztBQUVoQztBQUNBO0FBQ0EscUNBQXFDO0FBQ3JDLG1DQUFtQzs7QUFFbkM7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsdURBQXVEO0FBQ3ZEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDO0FBQ2xDLDBCQUEwQjtBQUMxQjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSw4QkFBOEI7O0FBRTlCO0FBQ0EsZ0JBQWdCOztBQUVoQjtBQUNBLHdCQUF3QixNQUFNLG1EQUFLLGlCQUFpQixtREFBSyxlQUFlLG1EQUFLOztBQUU3RTtBQUNBLG1CQUFtQixLQUFLLG1EQUFLLGNBQWMsbURBQUs7O0FBRWhEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxzQkFBc0IscURBQU87O0FBRTdCO0FBQ0Esb0JBQW9CLHdEQUFVLHNDQUFzQyxxREFBTztBQUMzRTs7QUFFQSw0QkFBNEIscURBQU87QUFDbkMsOEJBQThCLHdEQUFVO0FBQ3hDLGtDQUFrQyxxREFBTzs7QUFFekM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsMENBQTBDOztBQUUxQywwQ0FBMEM7O0FBRTFDOztBQUVBOztBQUVBLE9BQU87O0FBRVA7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQO0FBQ0EsOEJBQThCLHFEQUFPO0FBQ3JDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSw2QkFBNkIscURBQU87QUFDcEM7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLFFBQVE7O0FBRVI7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxTQUFTOztBQUVUO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsb0RBQW9EOztBQUVwRCxvRUFBb0UsZ0JBQWdCOztBQUVwRjs7QUFFQTtBQUNBOztBQUVBOztBQUVBLDRCQUE0QixrQkFBa0IsR0FBRzs7QUFFakQ7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0Esd0JBQXdCLHVEQUFTO0FBQ2pDLDZCQUE2Qix1REFBUzs7QUFFdEM7QUFDQSx3QkFBd0IscURBQU87O0FBRS9CLDBCQUEwQixxREFBTztBQUNqQyx3QkFBd0IscURBQU87QUFDL0IsMEJBQTBCLHFEQUFPOztBQUVqQyx1QkFBdUIscURBQU87QUFDOUIscUJBQXFCLHFEQUFPO0FBQzVCLHVCQUF1QixxREFBTzs7QUFFOUIseUJBQXlCLHFEQUFPO0FBQ2hDLHVCQUF1QixxREFBTztBQUM5Qix5QkFBeUIscURBQU87O0FBRWhDLDZCQUE2QixxREFBTztBQUNwQyxvQkFBb0IscURBQU87QUFDM0I7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsaUJBQWlCLHFEQUFPOztBQUV4Qjs7QUFFQSw4Q0FBOEM7QUFDOUM7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQSxpQkFBaUIscURBQU87O0FBRXhCOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVILHNDQUFzQztBQUN0Qzs7QUFFQSxzQkFBc0IscURBQU87O0FBRTdCOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUVBQXFFOztBQUVyRTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUVBQXFFOztBQUVyRTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxxQkFBcUIsNkRBQTZEOztBQUVsRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxTQUFTLG1EQUFLOztBQUVkOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFNBQVMsbURBQUs7O0FBRWQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxTQUFTLG1EQUFLOztBQUVkOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0EscURBQXFEOztBQUVyRCw4REFBOEQsK0JBQStCOztBQUU3Rjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0EscURBQXFEOztBQUVyRCxpRUFBaUUsK0JBQStCOztBQUVoRzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxXQUFXLG1EQUFLOztBQUVoQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxXQUFXLG1EQUFLOztBQUVoQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxXQUFXLG1EQUFLOztBQUVoQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxXQUFXLG1EQUFLOztBQUVoQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IscUJBQXFCOztBQUV6Qzs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixxQkFBcUI7O0FBRXpDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixxREFBTztBQUMxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsOERBQThELGlCQUFpQjs7QUFFL0UsbURBQW1EOztBQUVuRCxnRUFBZ0UsK0JBQStCOztBQUUvRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFeUIiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9jb250cm9scy9PcmJpdENvbnRyb2xzLmpzP2E2ZTEiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0RXZlbnREaXNwYXRjaGVyLFxuXHRNT1VTRSxcblx0UXVhdGVybmlvbixcblx0U3BoZXJpY2FsLFxuXHRUT1VDSCxcblx0VmVjdG9yMixcblx0VmVjdG9yMyxcblx0UGxhbmUsXG5cdFJheSxcblx0TWF0aFV0aWxzXG59IGZyb20gJ3RocmVlJztcblxuLy8gT3JiaXRDb250cm9scyBwZXJmb3JtcyBvcmJpdGluZywgZG9sbHlpbmcgKHpvb21pbmcpLCBhbmQgcGFubmluZy5cbi8vIFVubGlrZSBUcmFja2JhbGxDb250cm9scywgaXQgbWFpbnRhaW5zIHRoZSBcInVwXCIgZGlyZWN0aW9uIG9iamVjdC51cCAoK1kgYnkgZGVmYXVsdCkuXG4vL1xuLy8gICAgT3JiaXQgLSBsZWZ0IG1vdXNlIC8gdG91Y2g6IG9uZS1maW5nZXIgbW92ZVxuLy8gICAgWm9vbSAtIG1pZGRsZSBtb3VzZSwgb3IgbW91c2V3aGVlbCAvIHRvdWNoOiB0d28tZmluZ2VyIHNwcmVhZCBvciBzcXVpc2hcbi8vICAgIFBhbiAtIHJpZ2h0IG1vdXNlLCBvciBsZWZ0IG1vdXNlICsgY3RybC9tZXRhL3NoaWZ0S2V5LCBvciBhcnJvdyBrZXlzIC8gdG91Y2g6IHR3by1maW5nZXIgbW92ZVxuXG5jb25zdCBfY2hhbmdlRXZlbnQgPSB7IHR5cGU6ICdjaGFuZ2UnIH07XG5jb25zdCBfc3RhcnRFdmVudCA9IHsgdHlwZTogJ3N0YXJ0JyB9O1xuY29uc3QgX2VuZEV2ZW50ID0geyB0eXBlOiAnZW5kJyB9O1xuY29uc3QgX3JheSA9IG5ldyBSYXkoKTtcbmNvbnN0IF9wbGFuZSA9IG5ldyBQbGFuZSgpO1xuY29uc3QgVElMVF9MSU1JVCA9IE1hdGguY29zKCA3MCAqIE1hdGhVdGlscy5ERUcyUkFEICk7XG5cbmNsYXNzIE9yYml0Q29udHJvbHMgZXh0ZW5kcyBFdmVudERpc3BhdGNoZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBvYmplY3QsIGRvbUVsZW1lbnQgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5vYmplY3QgPSBvYmplY3Q7XG5cdFx0dGhpcy5kb21FbGVtZW50ID0gZG9tRWxlbWVudDtcblx0XHR0aGlzLmRvbUVsZW1lbnQuc3R5bGUudG91Y2hBY3Rpb24gPSAnbm9uZSc7IC8vIGRpc2FibGUgdG91Y2ggc2Nyb2xsXG5cblx0XHQvLyBTZXQgdG8gZmFsc2UgdG8gZGlzYWJsZSB0aGlzIGNvbnRyb2xcblx0XHR0aGlzLmVuYWJsZWQgPSB0cnVlO1xuXG5cdFx0Ly8gXCJ0YXJnZXRcIiBzZXRzIHRoZSBsb2NhdGlvbiBvZiBmb2N1cywgd2hlcmUgdGhlIG9iamVjdCBvcmJpdHMgYXJvdW5kXG5cdFx0dGhpcy50YXJnZXQgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0Ly8gU2V0cyB0aGUgM0QgY3Vyc29yIChzaW1pbGFyIHRvIEJsZW5kZXIpLCBmcm9tIHdoaWNoIHRoZSBtYXhUYXJnZXRSYWRpdXMgdGFrZXMgZWZmZWN0XG5cdFx0dGhpcy5jdXJzb3IgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0Ly8gSG93IGZhciB5b3UgY2FuIGRvbGx5IGluIGFuZCBvdXQgKCBQZXJzcGVjdGl2ZUNhbWVyYSBvbmx5IClcblx0XHR0aGlzLm1pbkRpc3RhbmNlID0gMDtcblx0XHR0aGlzLm1heERpc3RhbmNlID0gSW5maW5pdHk7XG5cblx0XHQvLyBIb3cgZmFyIHlvdSBjYW4gem9vbSBpbiBhbmQgb3V0ICggT3J0aG9ncmFwaGljQ2FtZXJhIG9ubHkgKVxuXHRcdHRoaXMubWluWm9vbSA9IDA7XG5cdFx0dGhpcy5tYXhab29tID0gSW5maW5pdHk7XG5cblx0XHQvLyBMaW1pdCBjYW1lcmEgdGFyZ2V0IHdpdGhpbiBhIHNwaGVyaWNhbCBhcmVhIGFyb3VuZCB0aGUgY3Vyc29yXG5cdFx0dGhpcy5taW5UYXJnZXRSYWRpdXMgPSAwO1xuXHRcdHRoaXMubWF4VGFyZ2V0UmFkaXVzID0gSW5maW5pdHk7XG5cblx0XHQvLyBIb3cgZmFyIHlvdSBjYW4gb3JiaXQgdmVydGljYWxseSwgdXBwZXIgYW5kIGxvd2VyIGxpbWl0cy5cblx0XHQvLyBSYW5nZSBpcyAwIHRvIE1hdGguUEkgcmFkaWFucy5cblx0XHR0aGlzLm1pblBvbGFyQW5nbGUgPSAwOyAvLyByYWRpYW5zXG5cdFx0dGhpcy5tYXhQb2xhckFuZ2xlID0gTWF0aC5QSTsgLy8gcmFkaWFuc1xuXG5cdFx0Ly8gSG93IGZhciB5b3UgY2FuIG9yYml0IGhvcml6b250YWxseSwgdXBwZXIgYW5kIGxvd2VyIGxpbWl0cy5cblx0XHQvLyBJZiBzZXQsIHRoZSBpbnRlcnZhbCBbIG1pbiwgbWF4IF0gbXVzdCBiZSBhIHN1Yi1pbnRlcnZhbCBvZiBbIC0gMiBQSSwgMiBQSSBdLCB3aXRoICggbWF4IC0gbWluIDwgMiBQSSApXG5cdFx0dGhpcy5taW5BemltdXRoQW5nbGUgPSAtIEluZmluaXR5OyAvLyByYWRpYW5zXG5cdFx0dGhpcy5tYXhBemltdXRoQW5nbGUgPSBJbmZpbml0eTsgLy8gcmFkaWFuc1xuXG5cdFx0Ly8gU2V0IHRvIHRydWUgdG8gZW5hYmxlIGRhbXBpbmcgKGluZXJ0aWEpXG5cdFx0Ly8gSWYgZGFtcGluZyBpcyBlbmFibGVkLCB5b3UgbXVzdCBjYWxsIGNvbnRyb2xzLnVwZGF0ZSgpIGluIHlvdXIgYW5pbWF0aW9uIGxvb3Bcblx0XHR0aGlzLmVuYWJsZURhbXBpbmcgPSBmYWxzZTtcblx0XHR0aGlzLmRhbXBpbmdGYWN0b3IgPSAwLjA1O1xuXG5cdFx0Ly8gVGhpcyBvcHRpb24gYWN0dWFsbHkgZW5hYmxlcyBkb2xseWluZyBpbiBhbmQgb3V0OyBsZWZ0IGFzIFwiem9vbVwiIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eS5cblx0XHQvLyBTZXQgdG8gZmFsc2UgdG8gZGlzYWJsZSB6b29taW5nXG5cdFx0dGhpcy5lbmFibGVab29tID0gdHJ1ZTtcblx0XHR0aGlzLnpvb21TcGVlZCA9IDEuMDtcblxuXHRcdC8vIFNldCB0byBmYWxzZSB0byBkaXNhYmxlIHJvdGF0aW5nXG5cdFx0dGhpcy5lbmFibGVSb3RhdGUgPSB0cnVlO1xuXHRcdHRoaXMucm90YXRlU3BlZWQgPSAxLjA7XG5cblx0XHQvLyBTZXQgdG8gZmFsc2UgdG8gZGlzYWJsZSBwYW5uaW5nXG5cdFx0dGhpcy5lbmFibGVQYW4gPSB0cnVlO1xuXHRcdHRoaXMucGFuU3BlZWQgPSAxLjA7XG5cdFx0dGhpcy5zY3JlZW5TcGFjZVBhbm5pbmcgPSB0cnVlOyAvLyBpZiBmYWxzZSwgcGFuIG9ydGhvZ29uYWwgdG8gd29ybGQtc3BhY2UgZGlyZWN0aW9uIGNhbWVyYS51cFxuXHRcdHRoaXMua2V5UGFuU3BlZWQgPSA3LjA7XHQvLyBwaXhlbHMgbW92ZWQgcGVyIGFycm93IGtleSBwdXNoXG5cdFx0dGhpcy56b29tVG9DdXJzb3IgPSBmYWxzZTtcblxuXHRcdC8vIFNldCB0byB0cnVlIHRvIGF1dG9tYXRpY2FsbHkgcm90YXRlIGFyb3VuZCB0aGUgdGFyZ2V0XG5cdFx0Ly8gSWYgYXV0by1yb3RhdGUgaXMgZW5hYmxlZCwgeW91IG11c3QgY2FsbCBjb250cm9scy51cGRhdGUoKSBpbiB5b3VyIGFuaW1hdGlvbiBsb29wXG5cdFx0dGhpcy5hdXRvUm90YXRlID0gZmFsc2U7XG5cdFx0dGhpcy5hdXRvUm90YXRlU3BlZWQgPSAyLjA7IC8vIDMwIHNlY29uZHMgcGVyIG9yYml0IHdoZW4gZnBzIGlzIDYwXG5cblx0XHQvLyBUaGUgZm91ciBhcnJvdyBrZXlzXG5cdFx0dGhpcy5rZXlzID0geyBMRUZUOiAnQXJyb3dMZWZ0JywgVVA6ICdBcnJvd1VwJywgUklHSFQ6ICdBcnJvd1JpZ2h0JywgQk9UVE9NOiAnQXJyb3dEb3duJyB9O1xuXG5cdFx0Ly8gTW91c2UgYnV0dG9uc1xuXHRcdHRoaXMubW91c2VCdXR0b25zID0geyBMRUZUOiBNT1VTRS5ST1RBVEUsIE1JRERMRTogTU9VU0UuRE9MTFksIFJJR0hUOiBNT1VTRS5QQU4gfTtcblxuXHRcdC8vIFRvdWNoIGZpbmdlcnNcblx0XHR0aGlzLnRvdWNoZXMgPSB7IE9ORTogVE9VQ0guUk9UQVRFLCBUV086IFRPVUNILkRPTExZX1BBTiB9O1xuXG5cdFx0Ly8gZm9yIHJlc2V0XG5cdFx0dGhpcy50YXJnZXQwID0gdGhpcy50YXJnZXQuY2xvbmUoKTtcblx0XHR0aGlzLnBvc2l0aW9uMCA9IHRoaXMub2JqZWN0LnBvc2l0aW9uLmNsb25lKCk7XG5cdFx0dGhpcy56b29tMCA9IHRoaXMub2JqZWN0Lnpvb207XG5cblx0XHQvLyB0aGUgdGFyZ2V0IERPTSBlbGVtZW50IGZvciBrZXkgZXZlbnRzXG5cdFx0dGhpcy5fZG9tRWxlbWVudEtleUV2ZW50cyA9IG51bGw7XG5cblx0XHQvL1xuXHRcdC8vIHB1YmxpYyBtZXRob2RzXG5cdFx0Ly9cblxuXHRcdHRoaXMuZ2V0UG9sYXJBbmdsZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIHNwaGVyaWNhbC5waGk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRBemltdXRoYWxBbmdsZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIHNwaGVyaWNhbC50aGV0YTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldERpc3RhbmNlID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gdGhpcy5vYmplY3QucG9zaXRpb24uZGlzdGFuY2VUbyggdGhpcy50YXJnZXQgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmxpc3RlblRvS2V5RXZlbnRzID0gZnVuY3Rpb24gKCBkb21FbGVtZW50ICkge1xuXG5cdFx0XHRkb21FbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoICdrZXlkb3duJywgb25LZXlEb3duICk7XG5cdFx0XHR0aGlzLl9kb21FbGVtZW50S2V5RXZlbnRzID0gZG9tRWxlbWVudDtcblxuXHRcdH07XG5cblx0XHR0aGlzLnN0b3BMaXN0ZW5Ub0tleUV2ZW50cyA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0dGhpcy5fZG9tRWxlbWVudEtleUV2ZW50cy5yZW1vdmVFdmVudExpc3RlbmVyKCAna2V5ZG93bicsIG9uS2V5RG93biApO1xuXHRcdFx0dGhpcy5fZG9tRWxlbWVudEtleUV2ZW50cyA9IG51bGw7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5zYXZlU3RhdGUgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHNjb3BlLnRhcmdldDAuY29weSggc2NvcGUudGFyZ2V0ICk7XG5cdFx0XHRzY29wZS5wb3NpdGlvbjAuY29weSggc2NvcGUub2JqZWN0LnBvc2l0aW9uICk7XG5cdFx0XHRzY29wZS56b29tMCA9IHNjb3BlLm9iamVjdC56b29tO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMucmVzZXQgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHNjb3BlLnRhcmdldC5jb3B5KCBzY29wZS50YXJnZXQwICk7XG5cdFx0XHRzY29wZS5vYmplY3QucG9zaXRpb24uY29weSggc2NvcGUucG9zaXRpb24wICk7XG5cdFx0XHRzY29wZS5vYmplY3Quem9vbSA9IHNjb3BlLnpvb20wO1xuXG5cdFx0XHRzY29wZS5vYmplY3QudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXHRcdFx0c2NvcGUuZGlzcGF0Y2hFdmVudCggX2NoYW5nZUV2ZW50ICk7XG5cblx0XHRcdHNjb3BlLnVwZGF0ZSgpO1xuXG5cdFx0XHRzdGF0ZSA9IFNUQVRFLk5PTkU7XG5cblx0XHR9O1xuXG5cdFx0Ly8gdGhpcyBtZXRob2QgaXMgZXhwb3NlZCwgYnV0IHBlcmhhcHMgaXQgd291bGQgYmUgYmV0dGVyIGlmIHdlIGNhbiBtYWtlIGl0IHByaXZhdGUuLi5cblx0XHR0aGlzLnVwZGF0ZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0Y29uc3Qgb2Zmc2V0ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdFx0Ly8gc28gY2FtZXJhLnVwIGlzIHRoZSBvcmJpdCBheGlzXG5cdFx0XHRjb25zdCBxdWF0ID0gbmV3IFF1YXRlcm5pb24oKS5zZXRGcm9tVW5pdFZlY3RvcnMoIG9iamVjdC51cCwgbmV3IFZlY3RvcjMoIDAsIDEsIDAgKSApO1xuXHRcdFx0Y29uc3QgcXVhdEludmVyc2UgPSBxdWF0LmNsb25lKCkuaW52ZXJ0KCk7XG5cblx0XHRcdGNvbnN0IGxhc3RQb3NpdGlvbiA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0XHRjb25zdCBsYXN0UXVhdGVybmlvbiA9IG5ldyBRdWF0ZXJuaW9uKCk7XG5cdFx0XHRjb25zdCBsYXN0VGFyZ2V0UG9zaXRpb24gPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHRjb25zdCB0d29QSSA9IDIgKiBNYXRoLlBJO1xuXG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24gdXBkYXRlKCBkZWx0YVRpbWUgPSBudWxsICkge1xuXG5cdFx0XHRcdGNvbnN0IHBvc2l0aW9uID0gc2NvcGUub2JqZWN0LnBvc2l0aW9uO1xuXG5cdFx0XHRcdG9mZnNldC5jb3B5KCBwb3NpdGlvbiApLnN1Yiggc2NvcGUudGFyZ2V0ICk7XG5cblx0XHRcdFx0Ly8gcm90YXRlIG9mZnNldCB0byBcInktYXhpcy1pcy11cFwiIHNwYWNlXG5cdFx0XHRcdG9mZnNldC5hcHBseVF1YXRlcm5pb24oIHF1YXQgKTtcblxuXHRcdFx0XHQvLyBhbmdsZSBmcm9tIHotYXhpcyBhcm91bmQgeS1heGlzXG5cdFx0XHRcdHNwaGVyaWNhbC5zZXRGcm9tVmVjdG9yMyggb2Zmc2V0ICk7XG5cblx0XHRcdFx0aWYgKCBzY29wZS5hdXRvUm90YXRlICYmIHN0YXRlID09PSBTVEFURS5OT05FICkge1xuXG5cdFx0XHRcdFx0cm90YXRlTGVmdCggZ2V0QXV0b1JvdGF0aW9uQW5nbGUoIGRlbHRhVGltZSApICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlRGFtcGluZyApIHtcblxuXHRcdFx0XHRcdHNwaGVyaWNhbC50aGV0YSArPSBzcGhlcmljYWxEZWx0YS50aGV0YSAqIHNjb3BlLmRhbXBpbmdGYWN0b3I7XG5cdFx0XHRcdFx0c3BoZXJpY2FsLnBoaSArPSBzcGhlcmljYWxEZWx0YS5waGkgKiBzY29wZS5kYW1waW5nRmFjdG9yO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRzcGhlcmljYWwudGhldGEgKz0gc3BoZXJpY2FsRGVsdGEudGhldGE7XG5cdFx0XHRcdFx0c3BoZXJpY2FsLnBoaSArPSBzcGhlcmljYWxEZWx0YS5waGk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIHJlc3RyaWN0IHRoZXRhIHRvIGJlIGJldHdlZW4gZGVzaXJlZCBsaW1pdHNcblxuXHRcdFx0XHRsZXQgbWluID0gc2NvcGUubWluQXppbXV0aEFuZ2xlO1xuXHRcdFx0XHRsZXQgbWF4ID0gc2NvcGUubWF4QXppbXV0aEFuZ2xlO1xuXG5cdFx0XHRcdGlmICggaXNGaW5pdGUoIG1pbiApICYmIGlzRmluaXRlKCBtYXggKSApIHtcblxuXHRcdFx0XHRcdGlmICggbWluIDwgLSBNYXRoLlBJICkgbWluICs9IHR3b1BJOyBlbHNlIGlmICggbWluID4gTWF0aC5QSSApIG1pbiAtPSB0d29QSTtcblxuXHRcdFx0XHRcdGlmICggbWF4IDwgLSBNYXRoLlBJICkgbWF4ICs9IHR3b1BJOyBlbHNlIGlmICggbWF4ID4gTWF0aC5QSSApIG1heCAtPSB0d29QSTtcblxuXHRcdFx0XHRcdGlmICggbWluIDw9IG1heCApIHtcblxuXHRcdFx0XHRcdFx0c3BoZXJpY2FsLnRoZXRhID0gTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgc3BoZXJpY2FsLnRoZXRhICkgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHNwaGVyaWNhbC50aGV0YSA9ICggc3BoZXJpY2FsLnRoZXRhID4gKCBtaW4gKyBtYXggKSAvIDIgKSA/XG5cdFx0XHRcdFx0XHRcdE1hdGgubWF4KCBtaW4sIHNwaGVyaWNhbC50aGV0YSApIDpcblx0XHRcdFx0XHRcdFx0TWF0aC5taW4oIG1heCwgc3BoZXJpY2FsLnRoZXRhICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIHJlc3RyaWN0IHBoaSB0byBiZSBiZXR3ZWVuIGRlc2lyZWQgbGltaXRzXG5cdFx0XHRcdHNwaGVyaWNhbC5waGkgPSBNYXRoLm1heCggc2NvcGUubWluUG9sYXJBbmdsZSwgTWF0aC5taW4oIHNjb3BlLm1heFBvbGFyQW5nbGUsIHNwaGVyaWNhbC5waGkgKSApO1xuXG5cdFx0XHRcdHNwaGVyaWNhbC5tYWtlU2FmZSgpO1xuXG5cblx0XHRcdFx0Ly8gbW92ZSB0YXJnZXQgdG8gcGFubmVkIGxvY2F0aW9uXG5cblx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVEYW1waW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0c2NvcGUudGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggcGFuT2Zmc2V0LCBzY29wZS5kYW1waW5nRmFjdG9yICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHNjb3BlLnRhcmdldC5hZGQoIHBhbk9mZnNldCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBMaW1pdCB0aGUgdGFyZ2V0IGRpc3RhbmNlIGZyb20gdGhlIGN1cnNvciB0byBjcmVhdGUgYSBzcGhlcmUgYXJvdW5kIHRoZSBjZW50ZXIgb2YgaW50ZXJlc3Rcblx0XHRcdFx0c2NvcGUudGFyZ2V0LnN1Yiggc2NvcGUuY3Vyc29yICk7XG5cdFx0XHRcdHNjb3BlLnRhcmdldC5jbGFtcExlbmd0aCggc2NvcGUubWluVGFyZ2V0UmFkaXVzLCBzY29wZS5tYXhUYXJnZXRSYWRpdXMgKTtcblx0XHRcdFx0c2NvcGUudGFyZ2V0LmFkZCggc2NvcGUuY3Vyc29yICk7XG5cblx0XHRcdFx0bGV0IHpvb21DaGFuZ2VkID0gZmFsc2U7XG5cdFx0XHRcdC8vIGFkanVzdCB0aGUgY2FtZXJhIHBvc2l0aW9uIGJhc2VkIG9uIHpvb20gb25seSBpZiB3ZSdyZSBub3Qgem9vbWluZyB0byB0aGUgY3Vyc29yIG9yIGlmIGl0J3MgYW4gb3J0aG8gY2FtZXJhXG5cdFx0XHRcdC8vIHdlIGFkanVzdCB6b29tIGxhdGVyIGluIHRoZXNlIGNhc2VzXG5cdFx0XHRcdGlmICggc2NvcGUuem9vbVRvQ3Vyc29yICYmIHBlcmZvcm1DdXJzb3Jab29tIHx8IHNjb3BlLm9iamVjdC5pc09ydGhvZ3JhcGhpY0NhbWVyYSApIHtcblxuXHRcdFx0XHRcdHNwaGVyaWNhbC5yYWRpdXMgPSBjbGFtcERpc3RhbmNlKCBzcGhlcmljYWwucmFkaXVzICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGNvbnN0IHByZXZSYWRpdXMgPSBzcGhlcmljYWwucmFkaXVzO1xuXHRcdFx0XHRcdHNwaGVyaWNhbC5yYWRpdXMgPSBjbGFtcERpc3RhbmNlKCBzcGhlcmljYWwucmFkaXVzICogc2NhbGUgKTtcblx0XHRcdFx0XHR6b29tQ2hhbmdlZCA9IHByZXZSYWRpdXMgIT0gc3BoZXJpY2FsLnJhZGl1cztcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0b2Zmc2V0LnNldEZyb21TcGhlcmljYWwoIHNwaGVyaWNhbCApO1xuXG5cdFx0XHRcdC8vIHJvdGF0ZSBvZmZzZXQgYmFjayB0byBcImNhbWVyYS11cC12ZWN0b3ItaXMtdXBcIiBzcGFjZVxuXHRcdFx0XHRvZmZzZXQuYXBwbHlRdWF0ZXJuaW9uKCBxdWF0SW52ZXJzZSApO1xuXG5cdFx0XHRcdHBvc2l0aW9uLmNvcHkoIHNjb3BlLnRhcmdldCApLmFkZCggb2Zmc2V0ICk7XG5cblx0XHRcdFx0c2NvcGUub2JqZWN0Lmxvb2tBdCggc2NvcGUudGFyZ2V0ICk7XG5cblx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVEYW1waW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0c3BoZXJpY2FsRGVsdGEudGhldGEgKj0gKCAxIC0gc2NvcGUuZGFtcGluZ0ZhY3RvciApO1xuXHRcdFx0XHRcdHNwaGVyaWNhbERlbHRhLnBoaSAqPSAoIDEgLSBzY29wZS5kYW1waW5nRmFjdG9yICk7XG5cblx0XHRcdFx0XHRwYW5PZmZzZXQubXVsdGlwbHlTY2FsYXIoIDEgLSBzY29wZS5kYW1waW5nRmFjdG9yICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHNwaGVyaWNhbERlbHRhLnNldCggMCwgMCwgMCApO1xuXG5cdFx0XHRcdFx0cGFuT2Zmc2V0LnNldCggMCwgMCwgMCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBhZGp1c3QgY2FtZXJhIHBvc2l0aW9uXG5cdFx0XHRcdGlmICggc2NvcGUuem9vbVRvQ3Vyc29yICYmIHBlcmZvcm1DdXJzb3Jab29tICkge1xuXG5cdFx0XHRcdFx0bGV0IG5ld1JhZGl1cyA9IG51bGw7XG5cdFx0XHRcdFx0aWYgKCBzY29wZS5vYmplY3QuaXNQZXJzcGVjdGl2ZUNhbWVyYSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gbW92ZSB0aGUgY2FtZXJhIGRvd24gdGhlIHBvaW50ZXIgcmF5XG5cdFx0XHRcdFx0XHQvLyB0aGlzIG1ldGhvZCBhdm9pZHMgZmxvYXRpbmcgcG9pbnQgZXJyb3Jcblx0XHRcdFx0XHRcdGNvbnN0IHByZXZSYWRpdXMgPSBvZmZzZXQubGVuZ3RoKCk7XG5cdFx0XHRcdFx0XHRuZXdSYWRpdXMgPSBjbGFtcERpc3RhbmNlKCBwcmV2UmFkaXVzICogc2NhbGUgKTtcblxuXHRcdFx0XHRcdFx0Y29uc3QgcmFkaXVzRGVsdGEgPSBwcmV2UmFkaXVzIC0gbmV3UmFkaXVzO1xuXHRcdFx0XHRcdFx0c2NvcGUub2JqZWN0LnBvc2l0aW9uLmFkZFNjYWxlZFZlY3RvciggZG9sbHlEaXJlY3Rpb24sIHJhZGl1c0RlbHRhICk7XG5cdFx0XHRcdFx0XHRzY29wZS5vYmplY3QudXBkYXRlTWF0cml4V29ybGQoKTtcblxuXHRcdFx0XHRcdFx0em9vbUNoYW5nZWQgPSAhISByYWRpdXNEZWx0YTtcblxuXHRcdFx0XHRcdH0gZWxzZSBpZiAoIHNjb3BlLm9iamVjdC5pc09ydGhvZ3JhcGhpY0NhbWVyYSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gYWRqdXN0IHRoZSBvcnRobyBjYW1lcmEgcG9zaXRpb24gYmFzZWQgb24gem9vbSBjaGFuZ2VzXG5cdFx0XHRcdFx0XHRjb25zdCBtb3VzZUJlZm9yZSA9IG5ldyBWZWN0b3IzKCBtb3VzZS54LCBtb3VzZS55LCAwICk7XG5cdFx0XHRcdFx0XHRtb3VzZUJlZm9yZS51bnByb2plY3QoIHNjb3BlLm9iamVjdCApO1xuXG5cdFx0XHRcdFx0XHRjb25zdCBwcmV2Wm9vbSA9IHNjb3BlLm9iamVjdC56b29tO1xuXHRcdFx0XHRcdFx0c2NvcGUub2JqZWN0Lnpvb20gPSBNYXRoLm1heCggc2NvcGUubWluWm9vbSwgTWF0aC5taW4oIHNjb3BlLm1heFpvb20sIHNjb3BlLm9iamVjdC56b29tIC8gc2NhbGUgKSApO1xuXHRcdFx0XHRcdFx0c2NvcGUub2JqZWN0LnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHRcdFx0XHRcdFx0em9vbUNoYW5nZWQgPSBwcmV2Wm9vbSAhPT0gc2NvcGUub2JqZWN0Lnpvb207XG5cblx0XHRcdFx0XHRcdGNvbnN0IG1vdXNlQWZ0ZXIgPSBuZXcgVmVjdG9yMyggbW91c2UueCwgbW91c2UueSwgMCApO1xuXHRcdFx0XHRcdFx0bW91c2VBZnRlci51bnByb2plY3QoIHNjb3BlLm9iamVjdCApO1xuXG5cdFx0XHRcdFx0XHRzY29wZS5vYmplY3QucG9zaXRpb24uc3ViKCBtb3VzZUFmdGVyICkuYWRkKCBtb3VzZUJlZm9yZSApO1xuXHRcdFx0XHRcdFx0c2NvcGUub2JqZWN0LnVwZGF0ZU1hdHJpeFdvcmxkKCk7XG5cblx0XHRcdFx0XHRcdG5ld1JhZGl1cyA9IG9mZnNldC5sZW5ndGgoKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1dBUk5JTkc6IE9yYml0Q29udHJvbHMuanMgZW5jb3VudGVyZWQgYW4gdW5rbm93biBjYW1lcmEgdHlwZSAtIHpvb20gdG8gY3Vyc29yIGRpc2FibGVkLicgKTtcblx0XHRcdFx0XHRcdHNjb3BlLnpvb21Ub0N1cnNvciA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gaGFuZGxlIHRoZSBwbGFjZW1lbnQgb2YgdGhlIHRhcmdldFxuXHRcdFx0XHRcdGlmICggbmV3UmFkaXVzICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0XHRpZiAoIHRoaXMuc2NyZWVuU3BhY2VQYW5uaW5nICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIHBvc2l0aW9uIHRoZSBvcmJpdCB0YXJnZXQgaW4gZnJvbnQgb2YgdGhlIG5ldyBjYW1lcmEgcG9zaXRpb25cblx0XHRcdFx0XHRcdFx0c2NvcGUudGFyZ2V0LnNldCggMCwgMCwgLSAxIClcblx0XHRcdFx0XHRcdFx0XHQudHJhbnNmb3JtRGlyZWN0aW9uKCBzY29wZS5vYmplY3QubWF0cml4IClcblx0XHRcdFx0XHRcdFx0XHQubXVsdGlwbHlTY2FsYXIoIG5ld1JhZGl1cyApXG5cdFx0XHRcdFx0XHRcdFx0LmFkZCggc2NvcGUub2JqZWN0LnBvc2l0aW9uICk7XG5cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gZ2V0IHRoZSByYXkgYW5kIHRyYW5zbGF0aW9uIHBsYW5lIHRvIGNvbXB1dGUgdGFyZ2V0XG5cdFx0XHRcdFx0XHRcdF9yYXkub3JpZ2luLmNvcHkoIHNjb3BlLm9iamVjdC5wb3NpdGlvbiApO1xuXHRcdFx0XHRcdFx0XHRfcmF5LmRpcmVjdGlvbi5zZXQoIDAsIDAsIC0gMSApLnRyYW5zZm9ybURpcmVjdGlvbiggc2NvcGUub2JqZWN0Lm1hdHJpeCApO1xuXG5cdFx0XHRcdFx0XHRcdC8vIGlmIHRoZSBjYW1lcmEgaXMgMjAgZGVncmVlcyBhYm92ZSB0aGUgaG9yaXpvbiB0aGVuIGRvbid0IGFkanVzdCB0aGUgZm9jdXMgdGFyZ2V0IHRvIGF2b2lkXG5cdFx0XHRcdFx0XHRcdC8vIGV4dHJlbWVseSBsYXJnZSB2YWx1ZXNcblx0XHRcdFx0XHRcdFx0aWYgKCBNYXRoLmFicyggc2NvcGUub2JqZWN0LnVwLmRvdCggX3JheS5kaXJlY3Rpb24gKSApIDwgVElMVF9MSU1JVCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdG9iamVjdC5sb29rQXQoIHNjb3BlLnRhcmdldCApO1xuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRfcGxhbmUuc2V0RnJvbU5vcm1hbEFuZENvcGxhbmFyUG9pbnQoIHNjb3BlLm9iamVjdC51cCwgc2NvcGUudGFyZ2V0ICk7XG5cdFx0XHRcdFx0XHRcdFx0X3JheS5pbnRlcnNlY3RQbGFuZSggX3BsYW5lLCBzY29wZS50YXJnZXQgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBzY29wZS5vYmplY3QuaXNPcnRob2dyYXBoaWNDYW1lcmEgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBwcmV2Wm9vbSA9IHNjb3BlLm9iamVjdC56b29tO1xuXHRcdFx0XHRcdHNjb3BlLm9iamVjdC56b29tID0gTWF0aC5tYXgoIHNjb3BlLm1pblpvb20sIE1hdGgubWluKCBzY29wZS5tYXhab29tLCBzY29wZS5vYmplY3Quem9vbSAvIHNjYWxlICkgKTtcblxuXHRcdFx0XHRcdGlmICggcHJldlpvb20gIT09IHNjb3BlLm9iamVjdC56b29tICkge1xuXG5cdFx0XHRcdFx0XHRzY29wZS5vYmplY3QudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXHRcdFx0XHRcdFx0em9vbUNoYW5nZWQgPSB0cnVlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzY2FsZSA9IDE7XG5cdFx0XHRcdHBlcmZvcm1DdXJzb3Jab29tID0gZmFsc2U7XG5cblx0XHRcdFx0Ly8gdXBkYXRlIGNvbmRpdGlvbiBpczpcblx0XHRcdFx0Ly8gbWluKGNhbWVyYSBkaXNwbGFjZW1lbnQsIGNhbWVyYSByb3RhdGlvbiBpbiByYWRpYW5zKV4yID4gRVBTXG5cdFx0XHRcdC8vIHVzaW5nIHNtYWxsLWFuZ2xlIGFwcHJveGltYXRpb24gY29zKHgvMikgPSAxIC0geF4yIC8gOFxuXG5cdFx0XHRcdGlmICggem9vbUNoYW5nZWQgfHxcblx0XHRcdFx0XHRsYXN0UG9zaXRpb24uZGlzdGFuY2VUb1NxdWFyZWQoIHNjb3BlLm9iamVjdC5wb3NpdGlvbiApID4gRVBTIHx8XG5cdFx0XHRcdFx0OCAqICggMSAtIGxhc3RRdWF0ZXJuaW9uLmRvdCggc2NvcGUub2JqZWN0LnF1YXRlcm5pb24gKSApID4gRVBTIHx8XG5cdFx0XHRcdFx0bGFzdFRhcmdldFBvc2l0aW9uLmRpc3RhbmNlVG9TcXVhcmVkKCBzY29wZS50YXJnZXQgKSA+IEVQUyApIHtcblxuXHRcdFx0XHRcdHNjb3BlLmRpc3BhdGNoRXZlbnQoIF9jaGFuZ2VFdmVudCApO1xuXG5cdFx0XHRcdFx0bGFzdFBvc2l0aW9uLmNvcHkoIHNjb3BlLm9iamVjdC5wb3NpdGlvbiApO1xuXHRcdFx0XHRcdGxhc3RRdWF0ZXJuaW9uLmNvcHkoIHNjb3BlLm9iamVjdC5xdWF0ZXJuaW9uICk7XG5cdFx0XHRcdFx0bGFzdFRhcmdldFBvc2l0aW9uLmNvcHkoIHNjb3BlLnRhcmdldCApO1xuXG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdFx0fTtcblxuXHRcdH0oKTtcblxuXHRcdHRoaXMuZGlzcG9zZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0c2NvcGUuZG9tRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCAnY29udGV4dG1lbnUnLCBvbkNvbnRleHRNZW51ICk7XG5cblx0XHRcdHNjb3BlLmRvbUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3BvaW50ZXJkb3duJywgb25Qb2ludGVyRG93biApO1xuXHRcdFx0c2NvcGUuZG9tRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCAncG9pbnRlcmNhbmNlbCcsIG9uUG9pbnRlclVwICk7XG5cdFx0XHRzY29wZS5kb21FbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoICd3aGVlbCcsIG9uTW91c2VXaGVlbCApO1xuXG5cdFx0XHRzY29wZS5kb21FbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoICdwb2ludGVybW92ZScsIG9uUG9pbnRlck1vdmUgKTtcblx0XHRcdHNjb3BlLmRvbUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3BvaW50ZXJ1cCcsIG9uUG9pbnRlclVwICk7XG5cblx0XHRcdGNvbnN0IGRvY3VtZW50ID0gc2NvcGUuZG9tRWxlbWVudC5nZXRSb290Tm9kZSgpOyAvLyBvZmZzY3JlZW4gY2FudmFzIGNvbXBhdGliaWxpdHlcblxuXHRcdFx0ZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCBpbnRlcmNlcHRDb250cm9sRG93biwgeyBjYXB0dXJlOiB0cnVlIH0gKTtcblxuXHRcdFx0aWYgKCBzY29wZS5fZG9tRWxlbWVudEtleUV2ZW50cyAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRzY29wZS5fZG9tRWxlbWVudEtleUV2ZW50cy5yZW1vdmVFdmVudExpc3RlbmVyKCAna2V5ZG93bicsIG9uS2V5RG93biApO1xuXHRcdFx0XHRzY29wZS5fZG9tRWxlbWVudEtleUV2ZW50cyA9IG51bGw7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9zY29wZS5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7IC8vIHNob3VsZCB0aGlzIGJlIGFkZGVkIGhlcmU/XG5cblx0XHR9O1xuXG5cdFx0Ly9cblx0XHQvLyBpbnRlcm5hbHNcblx0XHQvL1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0Y29uc3QgU1RBVEUgPSB7XG5cdFx0XHROT05FOiAtIDEsXG5cdFx0XHRST1RBVEU6IDAsXG5cdFx0XHRET0xMWTogMSxcblx0XHRcdFBBTjogMixcblx0XHRcdFRPVUNIX1JPVEFURTogMyxcblx0XHRcdFRPVUNIX1BBTjogNCxcblx0XHRcdFRPVUNIX0RPTExZX1BBTjogNSxcblx0XHRcdFRPVUNIX0RPTExZX1JPVEFURTogNlxuXHRcdH07XG5cblx0XHRsZXQgc3RhdGUgPSBTVEFURS5OT05FO1xuXG5cdFx0Y29uc3QgRVBTID0gMC4wMDAwMDE7XG5cblx0XHQvLyBjdXJyZW50IHBvc2l0aW9uIGluIHNwaGVyaWNhbCBjb29yZGluYXRlc1xuXHRcdGNvbnN0IHNwaGVyaWNhbCA9IG5ldyBTcGhlcmljYWwoKTtcblx0XHRjb25zdCBzcGhlcmljYWxEZWx0YSA9IG5ldyBTcGhlcmljYWwoKTtcblxuXHRcdGxldCBzY2FsZSA9IDE7XG5cdFx0Y29uc3QgcGFuT2Zmc2V0ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdGNvbnN0IHJvdGF0ZVN0YXJ0ID0gbmV3IFZlY3RvcjIoKTtcblx0XHRjb25zdCByb3RhdGVFbmQgPSBuZXcgVmVjdG9yMigpO1xuXHRcdGNvbnN0IHJvdGF0ZURlbHRhID0gbmV3IFZlY3RvcjIoKTtcblxuXHRcdGNvbnN0IHBhblN0YXJ0ID0gbmV3IFZlY3RvcjIoKTtcblx0XHRjb25zdCBwYW5FbmQgPSBuZXcgVmVjdG9yMigpO1xuXHRcdGNvbnN0IHBhbkRlbHRhID0gbmV3IFZlY3RvcjIoKTtcblxuXHRcdGNvbnN0IGRvbGx5U3RhcnQgPSBuZXcgVmVjdG9yMigpO1xuXHRcdGNvbnN0IGRvbGx5RW5kID0gbmV3IFZlY3RvcjIoKTtcblx0XHRjb25zdCBkb2xseURlbHRhID0gbmV3IFZlY3RvcjIoKTtcblxuXHRcdGNvbnN0IGRvbGx5RGlyZWN0aW9uID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCBtb3VzZSA9IG5ldyBWZWN0b3IyKCk7XG5cdFx0bGV0IHBlcmZvcm1DdXJzb3Jab29tID0gZmFsc2U7XG5cblx0XHRjb25zdCBwb2ludGVycyA9IFtdO1xuXHRcdGNvbnN0IHBvaW50ZXJQb3NpdGlvbnMgPSB7fTtcblxuXHRcdGxldCBjb250cm9sQWN0aXZlID0gZmFsc2U7XG5cblx0XHRmdW5jdGlvbiBnZXRBdXRvUm90YXRpb25BbmdsZSggZGVsdGFUaW1lICkge1xuXG5cdFx0XHRpZiAoIGRlbHRhVGltZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRyZXR1cm4gKCAyICogTWF0aC5QSSAvIDYwICogc2NvcGUuYXV0b1JvdGF0ZVNwZWVkICkgKiBkZWx0YVRpbWU7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0cmV0dXJuIDIgKiBNYXRoLlBJIC8gNjAgLyA2MCAqIHNjb3BlLmF1dG9Sb3RhdGVTcGVlZDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gZ2V0Wm9vbVNjYWxlKCBkZWx0YSApIHtcblxuXHRcdFx0Y29uc3Qgbm9ybWFsaXplZERlbHRhID0gTWF0aC5hYnMoIGRlbHRhICogMC4wMSApO1xuXHRcdFx0cmV0dXJuIE1hdGgucG93KCAwLjk1LCBzY29wZS56b29tU3BlZWQgKiBub3JtYWxpemVkRGVsdGEgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHJvdGF0ZUxlZnQoIGFuZ2xlICkge1xuXG5cdFx0XHRzcGhlcmljYWxEZWx0YS50aGV0YSAtPSBhbmdsZTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHJvdGF0ZVVwKCBhbmdsZSApIHtcblxuXHRcdFx0c3BoZXJpY2FsRGVsdGEucGhpIC09IGFuZ2xlO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgcGFuTGVmdCA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0Y29uc3QgdiA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRcdHJldHVybiBmdW5jdGlvbiBwYW5MZWZ0KCBkaXN0YW5jZSwgb2JqZWN0TWF0cml4ICkge1xuXG5cdFx0XHRcdHYuc2V0RnJvbU1hdHJpeENvbHVtbiggb2JqZWN0TWF0cml4LCAwICk7IC8vIGdldCBYIGNvbHVtbiBvZiBvYmplY3RNYXRyaXhcblx0XHRcdFx0di5tdWx0aXBseVNjYWxhciggLSBkaXN0YW5jZSApO1xuXG5cdFx0XHRcdHBhbk9mZnNldC5hZGQoIHYgKTtcblxuXHRcdFx0fTtcblxuXHRcdH0oKTtcblxuXHRcdGNvbnN0IHBhblVwID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRjb25zdCB2ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uIHBhblVwKCBkaXN0YW5jZSwgb2JqZWN0TWF0cml4ICkge1xuXG5cdFx0XHRcdGlmICggc2NvcGUuc2NyZWVuU3BhY2VQYW5uaW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0di5zZXRGcm9tTWF0cml4Q29sdW1uKCBvYmplY3RNYXRyaXgsIDEgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0di5zZXRGcm9tTWF0cml4Q29sdW1uKCBvYmplY3RNYXRyaXgsIDAgKTtcblx0XHRcdFx0XHR2LmNyb3NzVmVjdG9ycyggc2NvcGUub2JqZWN0LnVwLCB2ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHYubXVsdGlwbHlTY2FsYXIoIGRpc3RhbmNlICk7XG5cblx0XHRcdFx0cGFuT2Zmc2V0LmFkZCggdiApO1xuXG5cdFx0XHR9O1xuXG5cdFx0fSgpO1xuXG5cdFx0Ly8gZGVsdGFYIGFuZCBkZWx0YVkgYXJlIGluIHBpeGVsczsgcmlnaHQgYW5kIGRvd24gYXJlIHBvc2l0aXZlXG5cdFx0Y29uc3QgcGFuID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRjb25zdCBvZmZzZXQgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24gcGFuKCBkZWx0YVgsIGRlbHRhWSApIHtcblxuXHRcdFx0XHRjb25zdCBlbGVtZW50ID0gc2NvcGUuZG9tRWxlbWVudDtcblxuXHRcdFx0XHRpZiAoIHNjb3BlLm9iamVjdC5pc1BlcnNwZWN0aXZlQ2FtZXJhICkge1xuXG5cdFx0XHRcdFx0Ly8gcGVyc3BlY3RpdmVcblx0XHRcdFx0XHRjb25zdCBwb3NpdGlvbiA9IHNjb3BlLm9iamVjdC5wb3NpdGlvbjtcblx0XHRcdFx0XHRvZmZzZXQuY29weSggcG9zaXRpb24gKS5zdWIoIHNjb3BlLnRhcmdldCApO1xuXHRcdFx0XHRcdGxldCB0YXJnZXREaXN0YW5jZSA9IG9mZnNldC5sZW5ndGgoKTtcblxuXHRcdFx0XHRcdC8vIGhhbGYgb2YgdGhlIGZvdiBpcyBjZW50ZXIgdG8gdG9wIG9mIHNjcmVlblxuXHRcdFx0XHRcdHRhcmdldERpc3RhbmNlICo9IE1hdGgudGFuKCAoIHNjb3BlLm9iamVjdC5mb3YgLyAyICkgKiBNYXRoLlBJIC8gMTgwLjAgKTtcblxuXHRcdFx0XHRcdC8vIHdlIHVzZSBvbmx5IGNsaWVudEhlaWdodCBoZXJlIHNvIGFzcGVjdCByYXRpbyBkb2VzIG5vdCBkaXN0b3J0IHNwZWVkXG5cdFx0XHRcdFx0cGFuTGVmdCggMiAqIGRlbHRhWCAqIHRhcmdldERpc3RhbmNlIC8gZWxlbWVudC5jbGllbnRIZWlnaHQsIHNjb3BlLm9iamVjdC5tYXRyaXggKTtcblx0XHRcdFx0XHRwYW5VcCggMiAqIGRlbHRhWSAqIHRhcmdldERpc3RhbmNlIC8gZWxlbWVudC5jbGllbnRIZWlnaHQsIHNjb3BlLm9iamVjdC5tYXRyaXggKTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBzY29wZS5vYmplY3QuaXNPcnRob2dyYXBoaWNDYW1lcmEgKSB7XG5cblx0XHRcdFx0XHQvLyBvcnRob2dyYXBoaWNcblx0XHRcdFx0XHRwYW5MZWZ0KCBkZWx0YVggKiAoIHNjb3BlLm9iamVjdC5yaWdodCAtIHNjb3BlLm9iamVjdC5sZWZ0ICkgLyBzY29wZS5vYmplY3Quem9vbSAvIGVsZW1lbnQuY2xpZW50V2lkdGgsIHNjb3BlLm9iamVjdC5tYXRyaXggKTtcblx0XHRcdFx0XHRwYW5VcCggZGVsdGFZICogKCBzY29wZS5vYmplY3QudG9wIC0gc2NvcGUub2JqZWN0LmJvdHRvbSApIC8gc2NvcGUub2JqZWN0Lnpvb20gLyBlbGVtZW50LmNsaWVudEhlaWdodCwgc2NvcGUub2JqZWN0Lm1hdHJpeCApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBjYW1lcmEgbmVpdGhlciBvcnRob2dyYXBoaWMgbm9yIHBlcnNwZWN0aXZlXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnV0FSTklORzogT3JiaXRDb250cm9scy5qcyBlbmNvdW50ZXJlZCBhbiB1bmtub3duIGNhbWVyYSB0eXBlIC0gcGFuIGRpc2FibGVkLicgKTtcblx0XHRcdFx0XHRzY29wZS5lbmFibGVQYW4gPSBmYWxzZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH07XG5cblx0XHR9KCk7XG5cblx0XHRmdW5jdGlvbiBkb2xseU91dCggZG9sbHlTY2FsZSApIHtcblxuXHRcdFx0aWYgKCBzY29wZS5vYmplY3QuaXNQZXJzcGVjdGl2ZUNhbWVyYSB8fCBzY29wZS5vYmplY3QuaXNPcnRob2dyYXBoaWNDYW1lcmEgKSB7XG5cblx0XHRcdFx0c2NhbGUgLz0gZG9sbHlTY2FsZTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdXQVJOSU5HOiBPcmJpdENvbnRyb2xzLmpzIGVuY291bnRlcmVkIGFuIHVua25vd24gY2FtZXJhIHR5cGUgLSBkb2xseS96b29tIGRpc2FibGVkLicgKTtcblx0XHRcdFx0c2NvcGUuZW5hYmxlWm9vbSA9IGZhbHNlO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBkb2xseUluKCBkb2xseVNjYWxlICkge1xuXG5cdFx0XHRpZiAoIHNjb3BlLm9iamVjdC5pc1BlcnNwZWN0aXZlQ2FtZXJhIHx8IHNjb3BlLm9iamVjdC5pc09ydGhvZ3JhcGhpY0NhbWVyYSApIHtcblxuXHRcdFx0XHRzY2FsZSAqPSBkb2xseVNjYWxlO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1dBUk5JTkc6IE9yYml0Q29udHJvbHMuanMgZW5jb3VudGVyZWQgYW4gdW5rbm93biBjYW1lcmEgdHlwZSAtIGRvbGx5L3pvb20gZGlzYWJsZWQuJyApO1xuXHRcdFx0XHRzY29wZS5lbmFibGVab29tID0gZmFsc2U7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHVwZGF0ZVpvb21QYXJhbWV0ZXJzKCB4LCB5ICkge1xuXG5cdFx0XHRpZiAoICEgc2NvcGUuem9vbVRvQ3Vyc29yICkge1xuXG5cdFx0XHRcdHJldHVybjtcblxuXHRcdFx0fVxuXG5cdFx0XHRwZXJmb3JtQ3Vyc29yWm9vbSA9IHRydWU7XG5cblx0XHRcdGNvbnN0IHJlY3QgPSBzY29wZS5kb21FbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXHRcdFx0Y29uc3QgZHggPSB4IC0gcmVjdC5sZWZ0O1xuXHRcdFx0Y29uc3QgZHkgPSB5IC0gcmVjdC50b3A7XG5cdFx0XHRjb25zdCB3ID0gcmVjdC53aWR0aDtcblx0XHRcdGNvbnN0IGggPSByZWN0LmhlaWdodDtcblxuXHRcdFx0bW91c2UueCA9ICggZHggLyB3ICkgKiAyIC0gMTtcblx0XHRcdG1vdXNlLnkgPSAtICggZHkgLyBoICkgKiAyICsgMTtcblxuXHRcdFx0ZG9sbHlEaXJlY3Rpb24uc2V0KCBtb3VzZS54LCBtb3VzZS55LCAxICkudW5wcm9qZWN0KCBzY29wZS5vYmplY3QgKS5zdWIoIHNjb3BlLm9iamVjdC5wb3NpdGlvbiApLm5vcm1hbGl6ZSgpO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gY2xhbXBEaXN0YW5jZSggZGlzdCApIHtcblxuXHRcdFx0cmV0dXJuIE1hdGgubWF4KCBzY29wZS5taW5EaXN0YW5jZSwgTWF0aC5taW4oIHNjb3BlLm1heERpc3RhbmNlLCBkaXN0ICkgKTtcblxuXHRcdH1cblxuXHRcdC8vXG5cdFx0Ly8gZXZlbnQgY2FsbGJhY2tzIC0gdXBkYXRlIHRoZSBvYmplY3Qgc3RhdGVcblx0XHQvL1xuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlTW91c2VEb3duUm90YXRlKCBldmVudCApIHtcblxuXHRcdFx0cm90YXRlU3RhcnQuc2V0KCBldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVNb3VzZURvd25Eb2xseSggZXZlbnQgKSB7XG5cblx0XHRcdHVwZGF0ZVpvb21QYXJhbWV0ZXJzKCBldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRYICk7XG5cdFx0XHRkb2xseVN0YXJ0LnNldCggZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlTW91c2VEb3duUGFuKCBldmVudCApIHtcblxuXHRcdFx0cGFuU3RhcnQuc2V0KCBldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVNb3VzZU1vdmVSb3RhdGUoIGV2ZW50ICkge1xuXG5cdFx0XHRyb3RhdGVFbmQuc2V0KCBldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZICk7XG5cblx0XHRcdHJvdGF0ZURlbHRhLnN1YlZlY3RvcnMoIHJvdGF0ZUVuZCwgcm90YXRlU3RhcnQgKS5tdWx0aXBseVNjYWxhciggc2NvcGUucm90YXRlU3BlZWQgKTtcblxuXHRcdFx0Y29uc3QgZWxlbWVudCA9IHNjb3BlLmRvbUVsZW1lbnQ7XG5cblx0XHRcdHJvdGF0ZUxlZnQoIDIgKiBNYXRoLlBJICogcm90YXRlRGVsdGEueCAvIGVsZW1lbnQuY2xpZW50SGVpZ2h0ICk7IC8vIHllcywgaGVpZ2h0XG5cblx0XHRcdHJvdGF0ZVVwKCAyICogTWF0aC5QSSAqIHJvdGF0ZURlbHRhLnkgLyBlbGVtZW50LmNsaWVudEhlaWdodCApO1xuXG5cdFx0XHRyb3RhdGVTdGFydC5jb3B5KCByb3RhdGVFbmQgKTtcblxuXHRcdFx0c2NvcGUudXBkYXRlKCk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVNb3VzZU1vdmVEb2xseSggZXZlbnQgKSB7XG5cblx0XHRcdGRvbGx5RW5kLnNldCggZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSApO1xuXG5cdFx0XHRkb2xseURlbHRhLnN1YlZlY3RvcnMoIGRvbGx5RW5kLCBkb2xseVN0YXJ0ICk7XG5cblx0XHRcdGlmICggZG9sbHlEZWx0YS55ID4gMCApIHtcblxuXHRcdFx0XHRkb2xseU91dCggZ2V0Wm9vbVNjYWxlKCBkb2xseURlbHRhLnkgKSApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBkb2xseURlbHRhLnkgPCAwICkge1xuXG5cdFx0XHRcdGRvbGx5SW4oIGdldFpvb21TY2FsZSggZG9sbHlEZWx0YS55ICkgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRkb2xseVN0YXJ0LmNvcHkoIGRvbGx5RW5kICk7XG5cblx0XHRcdHNjb3BlLnVwZGF0ZSgpO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlTW91c2VNb3ZlUGFuKCBldmVudCApIHtcblxuXHRcdFx0cGFuRW5kLnNldCggZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSApO1xuXG5cdFx0XHRwYW5EZWx0YS5zdWJWZWN0b3JzKCBwYW5FbmQsIHBhblN0YXJ0ICkubXVsdGlwbHlTY2FsYXIoIHNjb3BlLnBhblNwZWVkICk7XG5cblx0XHRcdHBhbiggcGFuRGVsdGEueCwgcGFuRGVsdGEueSApO1xuXG5cdFx0XHRwYW5TdGFydC5jb3B5KCBwYW5FbmQgKTtcblxuXHRcdFx0c2NvcGUudXBkYXRlKCk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVNb3VzZVdoZWVsKCBldmVudCApIHtcblxuXHRcdFx0dXBkYXRlWm9vbVBhcmFtZXRlcnMoIGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFkgKTtcblxuXHRcdFx0aWYgKCBldmVudC5kZWx0YVkgPCAwICkge1xuXG5cdFx0XHRcdGRvbGx5SW4oIGdldFpvb21TY2FsZSggZXZlbnQuZGVsdGFZICkgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggZXZlbnQuZGVsdGFZID4gMCApIHtcblxuXHRcdFx0XHRkb2xseU91dCggZ2V0Wm9vbVNjYWxlKCBldmVudC5kZWx0YVkgKSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHNjb3BlLnVwZGF0ZSgpO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlS2V5RG93biggZXZlbnQgKSB7XG5cblx0XHRcdGxldCBuZWVkc1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0XHRzd2l0Y2ggKCBldmVudC5jb2RlICkge1xuXG5cdFx0XHRcdGNhc2Ugc2NvcGUua2V5cy5VUDpcblxuXHRcdFx0XHRcdGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5IHx8IGV2ZW50LnNoaWZ0S2V5ICkge1xuXG5cdFx0XHRcdFx0XHRyb3RhdGVVcCggMiAqIE1hdGguUEkgKiBzY29wZS5yb3RhdGVTcGVlZCAvIHNjb3BlLmRvbUVsZW1lbnQuY2xpZW50SGVpZ2h0ICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRwYW4oIDAsIHNjb3BlLmtleVBhblNwZWVkICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRuZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBzY29wZS5rZXlzLkJPVFRPTTpcblxuXHRcdFx0XHRcdGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5IHx8IGV2ZW50LnNoaWZ0S2V5ICkge1xuXG5cdFx0XHRcdFx0XHRyb3RhdGVVcCggLSAyICogTWF0aC5QSSAqIHNjb3BlLnJvdGF0ZVNwZWVkIC8gc2NvcGUuZG9tRWxlbWVudC5jbGllbnRIZWlnaHQgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHBhbiggMCwgLSBzY29wZS5rZXlQYW5TcGVlZCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0bmVlZHNVcGRhdGUgPSB0cnVlO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2Ugc2NvcGUua2V5cy5MRUZUOlxuXG5cdFx0XHRcdFx0aWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuc2hpZnRLZXkgKSB7XG5cblx0XHRcdFx0XHRcdHJvdGF0ZUxlZnQoIDIgKiBNYXRoLlBJICogc2NvcGUucm90YXRlU3BlZWQgLyBzY29wZS5kb21FbGVtZW50LmNsaWVudEhlaWdodCApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0cGFuKCBzY29wZS5rZXlQYW5TcGVlZCwgMCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0bmVlZHNVcGRhdGUgPSB0cnVlO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2Ugc2NvcGUua2V5cy5SSUdIVDpcblxuXHRcdFx0XHRcdGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5IHx8IGV2ZW50LnNoaWZ0S2V5ICkge1xuXG5cdFx0XHRcdFx0XHRyb3RhdGVMZWZ0KCAtIDIgKiBNYXRoLlBJICogc2NvcGUucm90YXRlU3BlZWQgLyBzY29wZS5kb21FbGVtZW50LmNsaWVudEhlaWdodCApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0cGFuKCAtIHNjb3BlLmtleVBhblNwZWVkLCAwICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRuZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBuZWVkc1VwZGF0ZSApIHtcblxuXHRcdFx0XHQvLyBwcmV2ZW50IHRoZSBicm93c2VyIGZyb20gc2Nyb2xsaW5nIG9uIGN1cnNvciBrZXlzXG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRcdFx0c2NvcGUudXBkYXRlKCk7XG5cblx0XHRcdH1cblxuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlVG91Y2hTdGFydFJvdGF0ZSggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggcG9pbnRlcnMubGVuZ3RoID09PSAxICkge1xuXG5cdFx0XHRcdHJvdGF0ZVN0YXJ0LnNldCggZXZlbnQucGFnZVgsIGV2ZW50LnBhZ2VZICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Y29uc3QgcG9zaXRpb24gPSBnZXRTZWNvbmRQb2ludGVyUG9zaXRpb24oIGV2ZW50ICk7XG5cblx0XHRcdFx0Y29uc3QgeCA9IDAuNSAqICggZXZlbnQucGFnZVggKyBwb3NpdGlvbi54ICk7XG5cdFx0XHRcdGNvbnN0IHkgPSAwLjUgKiAoIGV2ZW50LnBhZ2VZICsgcG9zaXRpb24ueSApO1xuXG5cdFx0XHRcdHJvdGF0ZVN0YXJ0LnNldCggeCwgeSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVUb3VjaFN0YXJ0UGFuKCBldmVudCApIHtcblxuXHRcdFx0aWYgKCBwb2ludGVycy5sZW5ndGggPT09IDEgKSB7XG5cblx0XHRcdFx0cGFuU3RhcnQuc2V0KCBldmVudC5wYWdlWCwgZXZlbnQucGFnZVkgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zdCBwb3NpdGlvbiA9IGdldFNlY29uZFBvaW50ZXJQb3NpdGlvbiggZXZlbnQgKTtcblxuXHRcdFx0XHRjb25zdCB4ID0gMC41ICogKCBldmVudC5wYWdlWCArIHBvc2l0aW9uLnggKTtcblx0XHRcdFx0Y29uc3QgeSA9IDAuNSAqICggZXZlbnQucGFnZVkgKyBwb3NpdGlvbi55ICk7XG5cblx0XHRcdFx0cGFuU3RhcnQuc2V0KCB4LCB5ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGhhbmRsZVRvdWNoU3RhcnREb2xseSggZXZlbnQgKSB7XG5cblx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2V0U2Vjb25kUG9pbnRlclBvc2l0aW9uKCBldmVudCApO1xuXG5cdFx0XHRjb25zdCBkeCA9IGV2ZW50LnBhZ2VYIC0gcG9zaXRpb24ueDtcblx0XHRcdGNvbnN0IGR5ID0gZXZlbnQucGFnZVkgLSBwb3NpdGlvbi55O1xuXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IE1hdGguc3FydCggZHggKiBkeCArIGR5ICogZHkgKTtcblxuXHRcdFx0ZG9sbHlTdGFydC5zZXQoIDAsIGRpc3RhbmNlICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVUb3VjaFN0YXJ0RG9sbHlQYW4oIGV2ZW50ICkge1xuXG5cdFx0XHRpZiAoIHNjb3BlLmVuYWJsZVpvb20gKSBoYW5kbGVUb3VjaFN0YXJ0RG9sbHkoIGV2ZW50ICk7XG5cblx0XHRcdGlmICggc2NvcGUuZW5hYmxlUGFuICkgaGFuZGxlVG91Y2hTdGFydFBhbiggZXZlbnQgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGhhbmRsZVRvdWNoU3RhcnREb2xseVJvdGF0ZSggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggc2NvcGUuZW5hYmxlWm9vbSApIGhhbmRsZVRvdWNoU3RhcnREb2xseSggZXZlbnQgKTtcblxuXHRcdFx0aWYgKCBzY29wZS5lbmFibGVSb3RhdGUgKSBoYW5kbGVUb3VjaFN0YXJ0Um90YXRlKCBldmVudCApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlVG91Y2hNb3ZlUm90YXRlKCBldmVudCApIHtcblxuXHRcdFx0aWYgKCBwb2ludGVycy5sZW5ndGggPT0gMSApIHtcblxuXHRcdFx0XHRyb3RhdGVFbmQuc2V0KCBldmVudC5wYWdlWCwgZXZlbnQucGFnZVkgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zdCBwb3NpdGlvbiA9IGdldFNlY29uZFBvaW50ZXJQb3NpdGlvbiggZXZlbnQgKTtcblxuXHRcdFx0XHRjb25zdCB4ID0gMC41ICogKCBldmVudC5wYWdlWCArIHBvc2l0aW9uLnggKTtcblx0XHRcdFx0Y29uc3QgeSA9IDAuNSAqICggZXZlbnQucGFnZVkgKyBwb3NpdGlvbi55ICk7XG5cblx0XHRcdFx0cm90YXRlRW5kLnNldCggeCwgeSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJvdGF0ZURlbHRhLnN1YlZlY3RvcnMoIHJvdGF0ZUVuZCwgcm90YXRlU3RhcnQgKS5tdWx0aXBseVNjYWxhciggc2NvcGUucm90YXRlU3BlZWQgKTtcblxuXHRcdFx0Y29uc3QgZWxlbWVudCA9IHNjb3BlLmRvbUVsZW1lbnQ7XG5cblx0XHRcdHJvdGF0ZUxlZnQoIDIgKiBNYXRoLlBJICogcm90YXRlRGVsdGEueCAvIGVsZW1lbnQuY2xpZW50SGVpZ2h0ICk7IC8vIHllcywgaGVpZ2h0XG5cblx0XHRcdHJvdGF0ZVVwKCAyICogTWF0aC5QSSAqIHJvdGF0ZURlbHRhLnkgLyBlbGVtZW50LmNsaWVudEhlaWdodCApO1xuXG5cdFx0XHRyb3RhdGVTdGFydC5jb3B5KCByb3RhdGVFbmQgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGhhbmRsZVRvdWNoTW92ZVBhbiggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggcG9pbnRlcnMubGVuZ3RoID09PSAxICkge1xuXG5cdFx0XHRcdHBhbkVuZC5zZXQoIGV2ZW50LnBhZ2VYLCBldmVudC5wYWdlWSApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2V0U2Vjb25kUG9pbnRlclBvc2l0aW9uKCBldmVudCApO1xuXG5cdFx0XHRcdGNvbnN0IHggPSAwLjUgKiAoIGV2ZW50LnBhZ2VYICsgcG9zaXRpb24ueCApO1xuXHRcdFx0XHRjb25zdCB5ID0gMC41ICogKCBldmVudC5wYWdlWSArIHBvc2l0aW9uLnkgKTtcblxuXHRcdFx0XHRwYW5FbmQuc2V0KCB4LCB5ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cGFuRGVsdGEuc3ViVmVjdG9ycyggcGFuRW5kLCBwYW5TdGFydCApLm11bHRpcGx5U2NhbGFyKCBzY29wZS5wYW5TcGVlZCApO1xuXG5cdFx0XHRwYW4oIHBhbkRlbHRhLngsIHBhbkRlbHRhLnkgKTtcblxuXHRcdFx0cGFuU3RhcnQuY29weSggcGFuRW5kICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVUb3VjaE1vdmVEb2xseSggZXZlbnQgKSB7XG5cblx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2V0U2Vjb25kUG9pbnRlclBvc2l0aW9uKCBldmVudCApO1xuXG5cdFx0XHRjb25zdCBkeCA9IGV2ZW50LnBhZ2VYIC0gcG9zaXRpb24ueDtcblx0XHRcdGNvbnN0IGR5ID0gZXZlbnQucGFnZVkgLSBwb3NpdGlvbi55O1xuXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IE1hdGguc3FydCggZHggKiBkeCArIGR5ICogZHkgKTtcblxuXHRcdFx0ZG9sbHlFbmQuc2V0KCAwLCBkaXN0YW5jZSApO1xuXG5cdFx0XHRkb2xseURlbHRhLnNldCggMCwgTWF0aC5wb3coIGRvbGx5RW5kLnkgLyBkb2xseVN0YXJ0LnksIHNjb3BlLnpvb21TcGVlZCApICk7XG5cblx0XHRcdGRvbGx5T3V0KCBkb2xseURlbHRhLnkgKTtcblxuXHRcdFx0ZG9sbHlTdGFydC5jb3B5KCBkb2xseUVuZCApO1xuXG5cdFx0XHRjb25zdCBjZW50ZXJYID0gKCBldmVudC5wYWdlWCArIHBvc2l0aW9uLnggKSAqIDAuNTtcblx0XHRcdGNvbnN0IGNlbnRlclkgPSAoIGV2ZW50LnBhZ2VZICsgcG9zaXRpb24ueSApICogMC41O1xuXG5cdFx0XHR1cGRhdGVab29tUGFyYW1ldGVycyggY2VudGVyWCwgY2VudGVyWSApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlVG91Y2hNb3ZlRG9sbHlQYW4oIGV2ZW50ICkge1xuXG5cdFx0XHRpZiAoIHNjb3BlLmVuYWJsZVpvb20gKSBoYW5kbGVUb3VjaE1vdmVEb2xseSggZXZlbnQgKTtcblxuXHRcdFx0aWYgKCBzY29wZS5lbmFibGVQYW4gKSBoYW5kbGVUb3VjaE1vdmVQYW4oIGV2ZW50ICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVUb3VjaE1vdmVEb2xseVJvdGF0ZSggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggc2NvcGUuZW5hYmxlWm9vbSApIGhhbmRsZVRvdWNoTW92ZURvbGx5KCBldmVudCApO1xuXG5cdFx0XHRpZiAoIHNjb3BlLmVuYWJsZVJvdGF0ZSApIGhhbmRsZVRvdWNoTW92ZVJvdGF0ZSggZXZlbnQgKTtcblxuXHRcdH1cblxuXHRcdC8vXG5cdFx0Ly8gZXZlbnQgaGFuZGxlcnMgLSBGU006IGxpc3RlbiBmb3IgZXZlbnRzIGFuZCByZXNldCBzdGF0ZVxuXHRcdC8vXG5cblx0XHRmdW5jdGlvbiBvblBvaW50ZXJEb3duKCBldmVudCApIHtcblxuXHRcdFx0aWYgKCBzY29wZS5lbmFibGVkID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0aWYgKCBwb2ludGVycy5sZW5ndGggPT09IDAgKSB7XG5cblx0XHRcdFx0c2NvcGUuZG9tRWxlbWVudC5zZXRQb2ludGVyQ2FwdHVyZSggZXZlbnQucG9pbnRlcklkICk7XG5cblx0XHRcdFx0c2NvcGUuZG9tRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCAncG9pbnRlcm1vdmUnLCBvblBvaW50ZXJNb3ZlICk7XG5cdFx0XHRcdHNjb3BlLmRvbUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ3BvaW50ZXJ1cCcsIG9uUG9pbnRlclVwICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9cblxuXHRcdFx0aWYgKCBpc1RyYWNraW5nUG9pbnRlciggZXZlbnQgKSApIHJldHVybjtcblxuXHRcdFx0Ly9cblxuXHRcdFx0YWRkUG9pbnRlciggZXZlbnQgKTtcblxuXHRcdFx0aWYgKCBldmVudC5wb2ludGVyVHlwZSA9PT0gJ3RvdWNoJyApIHtcblxuXHRcdFx0XHRvblRvdWNoU3RhcnQoIGV2ZW50ICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0b25Nb3VzZURvd24oIGV2ZW50ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uUG9pbnRlck1vdmUoIGV2ZW50ICkge1xuXG5cdFx0XHRpZiAoIHNjb3BlLmVuYWJsZWQgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRpZiAoIGV2ZW50LnBvaW50ZXJUeXBlID09PSAndG91Y2gnICkge1xuXG5cdFx0XHRcdG9uVG91Y2hNb3ZlKCBldmVudCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdG9uTW91c2VNb3ZlKCBldmVudCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBvblBvaW50ZXJVcCggZXZlbnQgKSB7XG5cblx0XHRcdHJlbW92ZVBvaW50ZXIoIGV2ZW50ICk7XG5cblx0XHRcdHN3aXRjaCAoIHBvaW50ZXJzLmxlbmd0aCApIHtcblxuXHRcdFx0XHRjYXNlIDA6XG5cblx0XHRcdFx0XHRzY29wZS5kb21FbGVtZW50LnJlbGVhc2VQb2ludGVyQ2FwdHVyZSggZXZlbnQucG9pbnRlcklkICk7XG5cblx0XHRcdFx0XHRzY29wZS5kb21FbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoICdwb2ludGVybW92ZScsIG9uUG9pbnRlck1vdmUgKTtcblx0XHRcdFx0XHRzY29wZS5kb21FbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoICdwb2ludGVydXAnLCBvblBvaW50ZXJVcCApO1xuXG5cdFx0XHRcdFx0c2NvcGUuZGlzcGF0Y2hFdmVudCggX2VuZEV2ZW50ICk7XG5cblx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLk5PTkU7XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlIDE6XG5cblx0XHRcdFx0XHRjb25zdCBwb2ludGVySWQgPSBwb2ludGVyc1sgMCBdO1xuXHRcdFx0XHRcdGNvbnN0IHBvc2l0aW9uID0gcG9pbnRlclBvc2l0aW9uc1sgcG9pbnRlcklkIF07XG5cblx0XHRcdFx0XHQvLyBtaW5pbWFsIHBsYWNlaG9sZGVyIGV2ZW50IC0gYWxsb3dzIHN0YXRlIGNvcnJlY3Rpb24gb24gcG9pbnRlci11cFxuXHRcdFx0XHRcdG9uVG91Y2hTdGFydCggeyBwb2ludGVySWQ6IHBvaW50ZXJJZCwgcGFnZVg6IHBvc2l0aW9uLngsIHBhZ2VZOiBwb3NpdGlvbi55IH0gKTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBvbk1vdXNlRG93biggZXZlbnQgKSB7XG5cblx0XHRcdGxldCBtb3VzZUFjdGlvbjtcblxuXHRcdFx0c3dpdGNoICggZXZlbnQuYnV0dG9uICkge1xuXG5cdFx0XHRcdGNhc2UgMDpcblxuXHRcdFx0XHRcdG1vdXNlQWN0aW9uID0gc2NvcGUubW91c2VCdXR0b25zLkxFRlQ7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAxOlxuXG5cdFx0XHRcdFx0bW91c2VBY3Rpb24gPSBzY29wZS5tb3VzZUJ1dHRvbnMuTUlERExFO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgMjpcblxuXHRcdFx0XHRcdG1vdXNlQWN0aW9uID0gc2NvcGUubW91c2VCdXR0b25zLlJJR0hUO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRtb3VzZUFjdGlvbiA9IC0gMTtcblxuXHRcdFx0fVxuXG5cdFx0XHRzd2l0Y2ggKCBtb3VzZUFjdGlvbiApIHtcblxuXHRcdFx0XHRjYXNlIE1PVVNFLkRPTExZOlxuXG5cdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVab29tID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdGhhbmRsZU1vdXNlRG93bkRvbGx5KCBldmVudCApO1xuXG5cdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5ET0xMWTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgTU9VU0UuUk9UQVRFOlxuXG5cdFx0XHRcdFx0aWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuc2hpZnRLZXkgKSB7XG5cblx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlUGFuID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0aGFuZGxlTW91c2VEb3duUGFuKCBldmVudCApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLlBBTjtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlUm90YXRlID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0aGFuZGxlTW91c2VEb3duUm90YXRlKCBldmVudCApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLlJPVEFURTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgTU9VU0UuUEFOOlxuXG5cdFx0XHRcdFx0aWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuc2hpZnRLZXkgKSB7XG5cblx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlUm90YXRlID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0aGFuZGxlTW91c2VEb3duUm90YXRlKCBldmVudCApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLlJPVEFURTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlUGFuID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0aGFuZGxlTW91c2VEb3duUGFuKCBldmVudCApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLlBBTjtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLk5PTkU7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBzdGF0ZSAhPT0gU1RBVEUuTk9ORSApIHtcblxuXHRcdFx0XHRzY29wZS5kaXNwYXRjaEV2ZW50KCBfc3RhcnRFdmVudCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBvbk1vdXNlTW92ZSggZXZlbnQgKSB7XG5cblx0XHRcdHN3aXRjaCAoIHN0YXRlICkge1xuXG5cdFx0XHRcdGNhc2UgU1RBVEUuUk9UQVRFOlxuXG5cdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVSb3RhdGUgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRcdFx0aGFuZGxlTW91c2VNb3ZlUm90YXRlKCBldmVudCApO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBTVEFURS5ET0xMWTpcblxuXHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlWm9vbSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHRcdFx0XHRoYW5kbGVNb3VzZU1vdmVEb2xseSggZXZlbnQgKTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgU1RBVEUuUEFOOlxuXG5cdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVQYW4gPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRcdFx0aGFuZGxlTW91c2VNb3ZlUGFuKCBldmVudCApO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uTW91c2VXaGVlbCggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggc2NvcGUuZW5hYmxlZCA9PT0gZmFsc2UgfHwgc2NvcGUuZW5hYmxlWm9vbSA9PT0gZmFsc2UgfHwgc3RhdGUgIT09IFNUQVRFLk5PTkUgKSByZXR1cm47XG5cblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRcdHNjb3BlLmRpc3BhdGNoRXZlbnQoIF9zdGFydEV2ZW50ICk7XG5cblx0XHRcdGhhbmRsZU1vdXNlV2hlZWwoIGN1c3RvbVdoZWVsRXZlbnQoIGV2ZW50ICkgKTtcblxuXHRcdFx0c2NvcGUuZGlzcGF0Y2hFdmVudCggX2VuZEV2ZW50ICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBjdXN0b21XaGVlbEV2ZW50KCBldmVudCApIHtcblxuXHRcdFx0Y29uc3QgbW9kZSA9IGV2ZW50LmRlbHRhTW9kZTtcblxuXHRcdFx0Ly8gbWluaW1hbCB3aGVlbCBldmVudCBhbHRlcmVkIHRvIG1lZXQgZGVsdGEtem9vbSBkZW1hbmRcblx0XHRcdGNvbnN0IG5ld0V2ZW50ID0ge1xuXHRcdFx0XHRjbGllbnRYOiBldmVudC5jbGllbnRYLFxuXHRcdFx0XHRjbGllbnRZOiBldmVudC5jbGllbnRZLFxuXHRcdFx0XHRkZWx0YVk6IGV2ZW50LmRlbHRhWSxcblx0XHRcdH07XG5cblx0XHRcdHN3aXRjaCAoIG1vZGUgKSB7XG5cblx0XHRcdFx0Y2FzZSAxOiAvLyBMSU5FX01PREVcblx0XHRcdFx0XHRuZXdFdmVudC5kZWx0YVkgKj0gMTY7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAyOiAvLyBQQUdFX01PREVcblx0XHRcdFx0XHRuZXdFdmVudC5kZWx0YVkgKj0gMTAwO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGRldGVjdCBpZiBldmVudCB3YXMgdHJpZ2dlcmVkIGJ5IHBpbmNoaW5nXG5cdFx0XHRpZiAoIGV2ZW50LmN0cmxLZXkgJiYgISBjb250cm9sQWN0aXZlICkge1xuXG5cdFx0XHRcdG5ld0V2ZW50LmRlbHRhWSAqPSAxMDtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gbmV3RXZlbnQ7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBpbnRlcmNlcHRDb250cm9sRG93biggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggZXZlbnQua2V5ID09PSAnQ29udHJvbCcgKSB7XG5cblx0XHRcdFx0Y29udHJvbEFjdGl2ZSA9IHRydWU7XG5cblxuXHRcdFx0XHRjb25zdCBkb2N1bWVudCA9IHNjb3BlLmRvbUVsZW1lbnQuZ2V0Um9vdE5vZGUoKTsgLy8gb2Zmc2NyZWVuIGNhbnZhcyBjb21wYXRpYmlsaXR5XG5cblx0XHRcdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ2tleXVwJywgaW50ZXJjZXB0Q29udHJvbFVwLCB7IHBhc3NpdmU6IHRydWUsIGNhcHR1cmU6IHRydWUgfSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBpbnRlcmNlcHRDb250cm9sVXAoIGV2ZW50ICkge1xuXG5cdFx0XHRpZiAoIGV2ZW50LmtleSA9PT0gJ0NvbnRyb2wnICkge1xuXG5cdFx0XHRcdGNvbnRyb2xBY3RpdmUgPSBmYWxzZTtcblxuXG5cdFx0XHRcdGNvbnN0IGRvY3VtZW50ID0gc2NvcGUuZG9tRWxlbWVudC5nZXRSb290Tm9kZSgpOyAvLyBvZmZzY3JlZW4gY2FudmFzIGNvbXBhdGliaWxpdHlcblxuXHRcdFx0XHRkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCAna2V5dXAnLCBpbnRlcmNlcHRDb250cm9sVXAsIHsgcGFzc2l2ZTogdHJ1ZSwgY2FwdHVyZTogdHJ1ZSB9ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uS2V5RG93biggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggc2NvcGUuZW5hYmxlZCA9PT0gZmFsc2UgfHwgc2NvcGUuZW5hYmxlUGFuID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0aGFuZGxlS2V5RG93biggZXZlbnQgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uVG91Y2hTdGFydCggZXZlbnQgKSB7XG5cblx0XHRcdHRyYWNrUG9pbnRlciggZXZlbnQgKTtcblxuXHRcdFx0c3dpdGNoICggcG9pbnRlcnMubGVuZ3RoICkge1xuXG5cdFx0XHRcdGNhc2UgMTpcblxuXHRcdFx0XHRcdHN3aXRjaCAoIHNjb3BlLnRvdWNoZXMuT05FICkge1xuXG5cdFx0XHRcdFx0XHRjYXNlIFRPVUNILlJPVEFURTpcblxuXHRcdFx0XHRcdFx0XHRpZiAoIHNjb3BlLmVuYWJsZVJvdGF0ZSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHRcdFx0XHRcdFx0aGFuZGxlVG91Y2hTdGFydFJvdGF0ZSggZXZlbnQgKTtcblxuXHRcdFx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLlRPVUNIX1JPVEFURTtcblxuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBUT1VDSC5QQU46XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVQYW4gPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRcdFx0XHRcdGhhbmRsZVRvdWNoU3RhcnRQYW4oIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5UT1VDSF9QQU47XG5cblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5OT05FO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAyOlxuXG5cdFx0XHRcdFx0c3dpdGNoICggc2NvcGUudG91Y2hlcy5UV08gKSB7XG5cblx0XHRcdFx0XHRcdGNhc2UgVE9VQ0guRE9MTFlfUEFOOlxuXG5cdFx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlWm9vbSA9PT0gZmFsc2UgJiYgc2NvcGUuZW5hYmxlUGFuID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0XHRoYW5kbGVUb3VjaFN0YXJ0RG9sbHlQYW4oIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5UT1VDSF9ET0xMWV9QQU47XG5cblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdGNhc2UgVE9VQ0guRE9MTFlfUk9UQVRFOlxuXG5cdFx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlWm9vbSA9PT0gZmFsc2UgJiYgc2NvcGUuZW5hYmxlUm90YXRlID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0XHRoYW5kbGVUb3VjaFN0YXJ0RG9sbHlSb3RhdGUoIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5UT1VDSF9ET0xMWV9ST1RBVEU7XG5cblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5OT05FO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0ZGVmYXVsdDpcblxuXHRcdFx0XHRcdHN0YXRlID0gU1RBVEUuTk9ORTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHN0YXRlICE9PSBTVEFURS5OT05FICkge1xuXG5cdFx0XHRcdHNjb3BlLmRpc3BhdGNoRXZlbnQoIF9zdGFydEV2ZW50ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uVG91Y2hNb3ZlKCBldmVudCApIHtcblxuXHRcdFx0dHJhY2tQb2ludGVyKCBldmVudCApO1xuXG5cdFx0XHRzd2l0Y2ggKCBzdGF0ZSApIHtcblxuXHRcdFx0XHRjYXNlIFNUQVRFLlRPVUNIX1JPVEFURTpcblxuXHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlUm90YXRlID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdGhhbmRsZVRvdWNoTW92ZVJvdGF0ZSggZXZlbnQgKTtcblxuXHRcdFx0XHRcdHNjb3BlLnVwZGF0ZSgpO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBTVEFURS5UT1VDSF9QQU46XG5cblx0XHRcdFx0XHRpZiAoIHNjb3BlLmVuYWJsZVBhbiA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHRcdFx0XHRoYW5kbGVUb3VjaE1vdmVQYW4oIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRzY29wZS51cGRhdGUoKTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgU1RBVEUuVE9VQ0hfRE9MTFlfUEFOOlxuXG5cdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVab29tID09PSBmYWxzZSAmJiBzY29wZS5lbmFibGVQYW4gPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRcdFx0aGFuZGxlVG91Y2hNb3ZlRG9sbHlQYW4oIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRzY29wZS51cGRhdGUoKTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgU1RBVEUuVE9VQ0hfRE9MTFlfUk9UQVRFOlxuXG5cdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVab29tID09PSBmYWxzZSAmJiBzY29wZS5lbmFibGVSb3RhdGUgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRcdFx0aGFuZGxlVG91Y2hNb3ZlRG9sbHlSb3RhdGUoIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRzY29wZS51cGRhdGUoKTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLk5PTkU7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uQ29udGV4dE1lbnUoIGV2ZW50ICkge1xuXG5cdFx0XHRpZiAoIHNjb3BlLmVuYWJsZWQgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gYWRkUG9pbnRlciggZXZlbnQgKSB7XG5cblx0XHRcdHBvaW50ZXJzLnB1c2goIGV2ZW50LnBvaW50ZXJJZCApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gcmVtb3ZlUG9pbnRlciggZXZlbnQgKSB7XG5cblx0XHRcdGRlbGV0ZSBwb2ludGVyUG9zaXRpb25zWyBldmVudC5wb2ludGVySWQgXTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgcG9pbnRlcnMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGlmICggcG9pbnRlcnNbIGkgXSA9PSBldmVudC5wb2ludGVySWQgKSB7XG5cblx0XHRcdFx0XHRwb2ludGVycy5zcGxpY2UoIGksIDEgKTtcblx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBpc1RyYWNraW5nUG9pbnRlciggZXZlbnQgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHBvaW50ZXJzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRpZiAoIHBvaW50ZXJzWyBpIF0gPT0gZXZlbnQucG9pbnRlcklkICkgcmV0dXJuIHRydWU7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gdHJhY2tQb2ludGVyKCBldmVudCApIHtcblxuXHRcdFx0bGV0IHBvc2l0aW9uID0gcG9pbnRlclBvc2l0aW9uc1sgZXZlbnQucG9pbnRlcklkIF07XG5cblx0XHRcdGlmICggcG9zaXRpb24gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRwb3NpdGlvbiA9IG5ldyBWZWN0b3IyKCk7XG5cdFx0XHRcdHBvaW50ZXJQb3NpdGlvbnNbIGV2ZW50LnBvaW50ZXJJZCBdID0gcG9zaXRpb247XG5cblx0XHRcdH1cblxuXHRcdFx0cG9zaXRpb24uc2V0KCBldmVudC5wYWdlWCwgZXZlbnQucGFnZVkgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdldFNlY29uZFBvaW50ZXJQb3NpdGlvbiggZXZlbnQgKSB7XG5cblx0XHRcdGNvbnN0IHBvaW50ZXJJZCA9ICggZXZlbnQucG9pbnRlcklkID09PSBwb2ludGVyc1sgMCBdICkgPyBwb2ludGVyc1sgMSBdIDogcG9pbnRlcnNbIDAgXTtcblxuXHRcdFx0cmV0dXJuIHBvaW50ZXJQb3NpdGlvbnNbIHBvaW50ZXJJZCBdO1xuXG5cdFx0fVxuXG5cdFx0Ly9cblxuXHRcdHNjb3BlLmRvbUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ2NvbnRleHRtZW51Jywgb25Db250ZXh0TWVudSApO1xuXG5cdFx0c2NvcGUuZG9tRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCAncG9pbnRlcmRvd24nLCBvblBvaW50ZXJEb3duICk7XG5cdFx0c2NvcGUuZG9tRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCAncG9pbnRlcmNhbmNlbCcsIG9uUG9pbnRlclVwICk7XG5cdFx0c2NvcGUuZG9tRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCAnd2hlZWwnLCBvbk1vdXNlV2hlZWwsIHsgcGFzc2l2ZTogZmFsc2UgfSApO1xuXG5cdFx0Y29uc3QgZG9jdW1lbnQgPSBzY29wZS5kb21FbGVtZW50LmdldFJvb3ROb2RlKCk7IC8vIG9mZnNjcmVlbiBjYW52YXMgY29tcGF0aWJpbGl0eVxuXG5cdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCBpbnRlcmNlcHRDb250cm9sRG93biwgeyBwYXNzaXZlOiB0cnVlLCBjYXB0dXJlOiB0cnVlIH0gKTtcblxuXHRcdC8vIGZvcmNlIGFuIHVwZGF0ZSBhdCBzdGFydFxuXG5cdFx0dGhpcy51cGRhdGUoKTtcblxuXHR9XG5cbn1cblxuZXhwb3J0IHsgT3JiaXRDb250cm9scyB9O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///580\n")},596:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n s: () => (/* binding */ EffectComposer)\n});\n\n// EXTERNAL MODULE: ./node_modules/three/build/three.module.js\nvar three_module = __webpack_require__(753);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/shaders/CopyShader.js\nvar CopyShader = __webpack_require__(364);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/postprocessing/ShaderPass.js\nvar ShaderPass = __webpack_require__(45);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/postprocessing/Pass.js\nvar Pass = __webpack_require__(844);\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/postprocessing/MaskPass.js\n\n\nclass MaskPass extends Pass/* Pass */.o {\n\n\tconstructor( scene, camera ) {\n\n\t\tsuper();\n\n\t\tthis.scene = scene;\n\t\tthis.camera = camera;\n\n\t\tthis.clear = true;\n\t\tthis.needsSwap = false;\n\n\t\tthis.inverse = false;\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {\n\n\t\tconst context = renderer.getContext();\n\t\tconst state = renderer.state;\n\n\t\t// don't update color or depth\n\n\t\tstate.buffers.color.setMask( false );\n\t\tstate.buffers.depth.setMask( false );\n\n\t\t// lock buffers\n\n\t\tstate.buffers.color.setLocked( true );\n\t\tstate.buffers.depth.setLocked( true );\n\n\t\t// set up stencil\n\n\t\tlet writeValue, clearValue;\n\n\t\tif ( this.inverse ) {\n\n\t\t\twriteValue = 0;\n\t\t\tclearValue = 1;\n\n\t\t} else {\n\n\t\t\twriteValue = 1;\n\t\t\tclearValue = 0;\n\n\t\t}\n\n\t\tstate.buffers.stencil.setTest( true );\n\t\tstate.buffers.stencil.setOp( context.REPLACE, context.REPLACE, context.REPLACE );\n\t\tstate.buffers.stencil.setFunc( context.ALWAYS, writeValue, 0xffffffff );\n\t\tstate.buffers.stencil.setClear( clearValue );\n\t\tstate.buffers.stencil.setLocked( true );\n\n\t\t// draw into the stencil buffer\n\n\t\trenderer.setRenderTarget( readBuffer );\n\t\tif ( this.clear ) renderer.clear();\n\t\trenderer.render( this.scene, this.camera );\n\n\t\trenderer.setRenderTarget( writeBuffer );\n\t\tif ( this.clear ) renderer.clear();\n\t\trenderer.render( this.scene, this.camera );\n\n\t\t// unlock color and depth buffer and make them writable for subsequent rendering/clearing\n\n\t\tstate.buffers.color.setLocked( false );\n\t\tstate.buffers.depth.setLocked( false );\n\n\t\tstate.buffers.color.setMask( true );\n\t\tstate.buffers.depth.setMask( true );\n\n\t\t// only render where stencil is set to 1\n\n\t\tstate.buffers.stencil.setLocked( false );\n\t\tstate.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1\n\t\tstate.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );\n\t\tstate.buffers.stencil.setLocked( true );\n\n\t}\n\n}\n\nclass ClearMaskPass extends Pass/* Pass */.o {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.needsSwap = false;\n\n\t}\n\n\trender( renderer /*, writeBuffer, readBuffer, deltaTime, maskActive */ ) {\n\n\t\trenderer.state.buffers.stencil.setLocked( false );\n\t\trenderer.state.buffers.stencil.setTest( false );\n\n\t}\n\n}\n\n\n\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/postprocessing/EffectComposer.js\n\n\n\n\n\n\nclass EffectComposer {\n\n\tconstructor( renderer, renderTarget ) {\n\n\t\tthis.renderer = renderer;\n\n\t\tthis._pixelRatio = renderer.getPixelRatio();\n\n\t\tif ( renderTarget === undefined ) {\n\n\t\t\tconst size = renderer.getSize( new three_module/* Vector2 */.I9Y() );\n\t\t\tthis._width = size.width;\n\t\t\tthis._height = size.height;\n\n\t\t\trenderTarget = new three_module/* WebGLRenderTarget */.nWS( this._width * this._pixelRatio, this._height * this._pixelRatio, { type: three_module/* HalfFloatType */.ix0 } );\n\t\t\trenderTarget.texture.name = 'EffectComposer.rt1';\n\n\t\t} else {\n\n\t\t\tthis._width = renderTarget.width;\n\t\t\tthis._height = renderTarget.height;\n\n\t\t}\n\n\t\tthis.renderTarget1 = renderTarget;\n\t\tthis.renderTarget2 = renderTarget.clone();\n\t\tthis.renderTarget2.texture.name = 'EffectComposer.rt2';\n\n\t\tthis.writeBuffer = this.renderTarget1;\n\t\tthis.readBuffer = this.renderTarget2;\n\n\t\tthis.renderToScreen = true;\n\n\t\tthis.passes = [];\n\n\t\tthis.copyPass = new ShaderPass/* ShaderPass */.p( CopyShader/* CopyShader */.Z );\n\t\tthis.copyPass.material.blending = three_module/* NoBlending */.XIg;\n\n\t\tthis.clock = new three_module/* Clock */.zD7();\n\n\t}\n\n\tswapBuffers() {\n\n\t\tconst tmp = this.readBuffer;\n\t\tthis.readBuffer = this.writeBuffer;\n\t\tthis.writeBuffer = tmp;\n\n\t}\n\n\taddPass( pass ) {\n\n\t\tthis.passes.push( pass );\n\t\tpass.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );\n\n\t}\n\n\tinsertPass( pass, index ) {\n\n\t\tthis.passes.splice( index, 0, pass );\n\t\tpass.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );\n\n\t}\n\n\tremovePass( pass ) {\n\n\t\tconst index = this.passes.indexOf( pass );\n\n\t\tif ( index !== - 1 ) {\n\n\t\t\tthis.passes.splice( index, 1 );\n\n\t\t}\n\n\t}\n\n\tisLastEnabledPass( passIndex ) {\n\n\t\tfor ( let i = passIndex + 1; i < this.passes.length; i ++ ) {\n\n\t\t\tif ( this.passes[ i ].enabled ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\trender( deltaTime ) {\n\n\t\t// deltaTime value is in seconds\n\n\t\tif ( deltaTime === undefined ) {\n\n\t\t\tdeltaTime = this.clock.getDelta();\n\n\t\t}\n\n\t\tconst currentRenderTarget = this.renderer.getRenderTarget();\n\n\t\tlet maskActive = false;\n\n\t\tfor ( let i = 0, il = this.passes.length; i < il; i ++ ) {\n\n\t\t\tconst pass = this.passes[ i ];\n\n\t\t\tif ( pass.enabled === false ) continue;\n\n\t\t\tpass.renderToScreen = ( this.renderToScreen && this.isLastEnabledPass( i ) );\n\t\t\tpass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime, maskActive );\n\n\t\t\tif ( pass.needsSwap ) {\n\n\t\t\t\tif ( maskActive ) {\n\n\t\t\t\t\tconst context = this.renderer.getContext();\n\t\t\t\t\tconst stencil = this.renderer.state.buffers.stencil;\n\n\t\t\t\t\t//context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );\n\t\t\t\t\tstencil.setFunc( context.NOTEQUAL, 1, 0xffffffff );\n\n\t\t\t\t\tthis.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime );\n\n\t\t\t\t\t//context.stencilFunc( context.EQUAL, 1, 0xffffffff );\n\t\t\t\t\tstencil.setFunc( context.EQUAL, 1, 0xffffffff );\n\n\t\t\t\t}\n\n\t\t\t\tthis.swapBuffers();\n\n\t\t\t}\n\n\t\t\tif ( MaskPass !== undefined ) {\n\n\t\t\t\tif ( pass instanceof MaskPass ) {\n\n\t\t\t\t\tmaskActive = true;\n\n\t\t\t\t} else if ( pass instanceof ClearMaskPass ) {\n\n\t\t\t\t\tmaskActive = false;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.renderer.setRenderTarget( currentRenderTarget );\n\n\t}\n\n\treset( renderTarget ) {\n\n\t\tif ( renderTarget === undefined ) {\n\n\t\t\tconst size = this.renderer.getSize( new three_module/* Vector2 */.I9Y() );\n\t\t\tthis._pixelRatio = this.renderer.getPixelRatio();\n\t\t\tthis._width = size.width;\n\t\t\tthis._height = size.height;\n\n\t\t\trenderTarget = this.renderTarget1.clone();\n\t\t\trenderTarget.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );\n\n\t\t}\n\n\t\tthis.renderTarget1.dispose();\n\t\tthis.renderTarget2.dispose();\n\t\tthis.renderTarget1 = renderTarget;\n\t\tthis.renderTarget2 = renderTarget.clone();\n\n\t\tthis.writeBuffer = this.renderTarget1;\n\t\tthis.readBuffer = this.renderTarget2;\n\n\t}\n\n\tsetSize( width, height ) {\n\n\t\tthis._width = width;\n\t\tthis._height = height;\n\n\t\tconst effectiveWidth = this._width * this._pixelRatio;\n\t\tconst effectiveHeight = this._height * this._pixelRatio;\n\n\t\tthis.renderTarget1.setSize( effectiveWidth, effectiveHeight );\n\t\tthis.renderTarget2.setSize( effectiveWidth, effectiveHeight );\n\n\t\tfor ( let i = 0; i < this.passes.length; i ++ ) {\n\n\t\t\tthis.passes[ i ].setSize( effectiveWidth, effectiveHeight );\n\n\t\t}\n\n\t}\n\n\tsetPixelRatio( pixelRatio ) {\n\n\t\tthis._pixelRatio = pixelRatio;\n\n\t\tthis.setSize( this._width, this._height );\n\n\t}\n\n\tdispose() {\n\n\t\tthis.renderTarget1.dispose();\n\t\tthis.renderTarget2.dispose();\n\n\t\tthis.copyPass.dispose();\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNTk2LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7OztBQUFpQzs7QUFFakMsdUJBQXVCLGdCQUFJOztBQUUzQjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLGlFQUFpRTtBQUNqRTtBQUNBOztBQUVBOztBQUVBOztBQUVBLDRCQUE0QixnQkFBSTs7QUFFaEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFbUM7OztBQ2pHcEI7QUFDdUM7QUFDVDtBQUNKO0FBQ0s7O0FBRTlDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyw2QkFBTztBQUM3QztBQUNBOztBQUVBLHNCQUFzQix1Q0FBaUIscUVBQXFFLE1BQU0sbUNBQWEsR0FBRztBQUNsSTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsc0JBQXNCLDRCQUFVLEVBQUUsNEJBQVU7QUFDNUMsb0NBQW9DLGdDQUFVOztBQUU5QyxtQkFBbUIsMkJBQUs7O0FBRXhCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsK0JBQStCLHdCQUF3Qjs7QUFFdkQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNENBQTRDLFFBQVE7O0FBRXBEOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsUUFBUSxRQUFROztBQUVoQix5QkFBeUIsUUFBUTs7QUFFakM7O0FBRUEsTUFBTSwwQkFBMEIsYUFBYTs7QUFFN0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLDZCQUFPO0FBQ2xEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsbUJBQW1CLHdCQUF3Qjs7QUFFM0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFMEIiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9wb3N0cHJvY2Vzc2luZy9NYXNrUGFzcy5qcz9lMTA5Iiwid2VicGFjazovL3RocmVlanMtcG9zdHByb2Nlc3MvLi9ub2RlX21vZHVsZXMvdGhyZWUvZXhhbXBsZXMvanNtL3Bvc3Rwcm9jZXNzaW5nL0VmZmVjdENvbXBvc2VyLmpzPzM4NTkiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUGFzcyB9IGZyb20gJy4vUGFzcy5qcyc7XG5cbmNsYXNzIE1hc2tQYXNzIGV4dGVuZHMgUGFzcyB7XG5cblx0Y29uc3RydWN0b3IoIHNjZW5lLCBjYW1lcmEgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5zY2VuZSA9IHNjZW5lO1xuXHRcdHRoaXMuY2FtZXJhID0gY2FtZXJhO1xuXG5cdFx0dGhpcy5jbGVhciA9IHRydWU7XG5cdFx0dGhpcy5uZWVkc1N3YXAgPSBmYWxzZTtcblxuXHRcdHRoaXMuaW52ZXJzZSA9IGZhbHNlO1xuXG5cdH1cblxuXHRyZW5kZXIoIHJlbmRlcmVyLCB3cml0ZUJ1ZmZlciwgcmVhZEJ1ZmZlciAvKiwgZGVsdGFUaW1lLCBtYXNrQWN0aXZlICovICkge1xuXG5cdFx0Y29uc3QgY29udGV4dCA9IHJlbmRlcmVyLmdldENvbnRleHQoKTtcblx0XHRjb25zdCBzdGF0ZSA9IHJlbmRlcmVyLnN0YXRlO1xuXG5cdFx0Ly8gZG9uJ3QgdXBkYXRlIGNvbG9yIG9yIGRlcHRoXG5cblx0XHRzdGF0ZS5idWZmZXJzLmNvbG9yLnNldE1hc2soIGZhbHNlICk7XG5cdFx0c3RhdGUuYnVmZmVycy5kZXB0aC5zZXRNYXNrKCBmYWxzZSApO1xuXG5cdFx0Ly8gbG9jayBidWZmZXJzXG5cblx0XHRzdGF0ZS5idWZmZXJzLmNvbG9yLnNldExvY2tlZCggdHJ1ZSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuZGVwdGguc2V0TG9ja2VkKCB0cnVlICk7XG5cblx0XHQvLyBzZXQgdXAgc3RlbmNpbFxuXG5cdFx0bGV0IHdyaXRlVmFsdWUsIGNsZWFyVmFsdWU7XG5cblx0XHRpZiAoIHRoaXMuaW52ZXJzZSApIHtcblxuXHRcdFx0d3JpdGVWYWx1ZSA9IDA7XG5cdFx0XHRjbGVhclZhbHVlID0gMTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHdyaXRlVmFsdWUgPSAxO1xuXHRcdFx0Y2xlYXJWYWx1ZSA9IDA7XG5cblx0XHR9XG5cblx0XHRzdGF0ZS5idWZmZXJzLnN0ZW5jaWwuc2V0VGVzdCggdHJ1ZSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRPcCggY29udGV4dC5SRVBMQUNFLCBjb250ZXh0LlJFUExBQ0UsIGNvbnRleHQuUkVQTEFDRSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRGdW5jKCBjb250ZXh0LkFMV0FZUywgd3JpdGVWYWx1ZSwgMHhmZmZmZmZmZiApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRDbGVhciggY2xlYXJWYWx1ZSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRMb2NrZWQoIHRydWUgKTtcblxuXHRcdC8vIGRyYXcgaW50byB0aGUgc3RlbmNpbCBidWZmZXJcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVhZEJ1ZmZlciApO1xuXHRcdGlmICggdGhpcy5jbGVhciApIHJlbmRlcmVyLmNsZWFyKCk7XG5cdFx0cmVuZGVyZXIucmVuZGVyKCB0aGlzLnNjZW5lLCB0aGlzLmNhbWVyYSApO1xuXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCB3cml0ZUJ1ZmZlciApO1xuXHRcdGlmICggdGhpcy5jbGVhciApIHJlbmRlcmVyLmNsZWFyKCk7XG5cdFx0cmVuZGVyZXIucmVuZGVyKCB0aGlzLnNjZW5lLCB0aGlzLmNhbWVyYSApO1xuXG5cdFx0Ly8gdW5sb2NrIGNvbG9yIGFuZCBkZXB0aCBidWZmZXIgYW5kIG1ha2UgdGhlbSB3cml0YWJsZSBmb3Igc3Vic2VxdWVudCByZW5kZXJpbmcvY2xlYXJpbmdcblxuXHRcdHN0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0TG9ja2VkKCBmYWxzZSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuZGVwdGguc2V0TG9ja2VkKCBmYWxzZSApO1xuXG5cdFx0c3RhdGUuYnVmZmVycy5jb2xvci5zZXRNYXNrKCB0cnVlICk7XG5cdFx0c3RhdGUuYnVmZmVycy5kZXB0aC5zZXRNYXNrKCB0cnVlICk7XG5cblx0XHQvLyBvbmx5IHJlbmRlciB3aGVyZSBzdGVuY2lsIGlzIHNldCB0byAxXG5cblx0XHRzdGF0ZS5idWZmZXJzLnN0ZW5jaWwuc2V0TG9ja2VkKCBmYWxzZSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRGdW5jKCBjb250ZXh0LkVRVUFMLCAxLCAweGZmZmZmZmZmICk7IC8vIGRyYXcgaWYgPT0gMVxuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRPcCggY29udGV4dC5LRUVQLCBjb250ZXh0LktFRVAsIGNvbnRleHQuS0VFUCApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRMb2NrZWQoIHRydWUgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQ2xlYXJNYXNrUGFzcyBleHRlbmRzIFBhc3Mge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMubmVlZHNTd2FwID0gZmFsc2U7XG5cblx0fVxuXG5cdHJlbmRlciggcmVuZGVyZXIgLyosIHdyaXRlQnVmZmVyLCByZWFkQnVmZmVyLCBkZWx0YVRpbWUsIG1hc2tBY3RpdmUgKi8gKSB7XG5cblx0XHRyZW5kZXJlci5zdGF0ZS5idWZmZXJzLnN0ZW5jaWwuc2V0TG9ja2VkKCBmYWxzZSApO1xuXHRcdHJlbmRlcmVyLnN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRUZXN0KCBmYWxzZSApO1xuXG5cdH1cblxufVxuXG5leHBvcnQgeyBNYXNrUGFzcywgQ2xlYXJNYXNrUGFzcyB9O1xuIiwiaW1wb3J0IHtcblx0Q2xvY2ssXG5cdEhhbGZGbG9hdFR5cGUsXG5cdE5vQmxlbmRpbmcsXG5cdFZlY3RvcjIsXG5cdFdlYkdMUmVuZGVyVGFyZ2V0XG59IGZyb20gJ3RocmVlJztcbmltcG9ydCB7IENvcHlTaGFkZXIgfSBmcm9tICcuLi9zaGFkZXJzL0NvcHlTaGFkZXIuanMnO1xuaW1wb3J0IHsgU2hhZGVyUGFzcyB9IGZyb20gJy4vU2hhZGVyUGFzcy5qcyc7XG5pbXBvcnQgeyBNYXNrUGFzcyB9IGZyb20gJy4vTWFza1Bhc3MuanMnO1xuaW1wb3J0IHsgQ2xlYXJNYXNrUGFzcyB9IGZyb20gJy4vTWFza1Bhc3MuanMnO1xuXG5jbGFzcyBFZmZlY3RDb21wb3NlciB7XG5cblx0Y29uc3RydWN0b3IoIHJlbmRlcmVyLCByZW5kZXJUYXJnZXQgKSB7XG5cblx0XHR0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG5cblx0XHR0aGlzLl9waXhlbFJhdGlvID0gcmVuZGVyZXIuZ2V0UGl4ZWxSYXRpbygpO1xuXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3Qgc2l6ZSA9IHJlbmRlcmVyLmdldFNpemUoIG5ldyBWZWN0b3IyKCkgKTtcblx0XHRcdHRoaXMuX3dpZHRoID0gc2l6ZS53aWR0aDtcblx0XHRcdHRoaXMuX2hlaWdodCA9IHNpemUuaGVpZ2h0O1xuXG5cdFx0XHRyZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoIHRoaXMuX3dpZHRoICogdGhpcy5fcGl4ZWxSYXRpbywgdGhpcy5faGVpZ2h0ICogdGhpcy5fcGl4ZWxSYXRpbywgeyB0eXBlOiBIYWxmRmxvYXRUeXBlIH0gKTtcblx0XHRcdHJlbmRlclRhcmdldC50ZXh0dXJlLm5hbWUgPSAnRWZmZWN0Q29tcG9zZXIucnQxJztcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuX3dpZHRoID0gcmVuZGVyVGFyZ2V0LndpZHRoO1xuXHRcdFx0dGhpcy5faGVpZ2h0ID0gcmVuZGVyVGFyZ2V0LmhlaWdodDtcblxuXHRcdH1cblxuXHRcdHRoaXMucmVuZGVyVGFyZ2V0MSA9IHJlbmRlclRhcmdldDtcblx0XHR0aGlzLnJlbmRlclRhcmdldDIgPSByZW5kZXJUYXJnZXQuY2xvbmUoKTtcblx0XHR0aGlzLnJlbmRlclRhcmdldDIudGV4dHVyZS5uYW1lID0gJ0VmZmVjdENvbXBvc2VyLnJ0Mic7XG5cblx0XHR0aGlzLndyaXRlQnVmZmVyID0gdGhpcy5yZW5kZXJUYXJnZXQxO1xuXHRcdHRoaXMucmVhZEJ1ZmZlciA9IHRoaXMucmVuZGVyVGFyZ2V0MjtcblxuXHRcdHRoaXMucmVuZGVyVG9TY3JlZW4gPSB0cnVlO1xuXG5cdFx0dGhpcy5wYXNzZXMgPSBbXTtcblxuXHRcdHRoaXMuY29weVBhc3MgPSBuZXcgU2hhZGVyUGFzcyggQ29weVNoYWRlciApO1xuXHRcdHRoaXMuY29weVBhc3MubWF0ZXJpYWwuYmxlbmRpbmcgPSBOb0JsZW5kaW5nO1xuXG5cdFx0dGhpcy5jbG9jayA9IG5ldyBDbG9jaygpO1xuXG5cdH1cblxuXHRzd2FwQnVmZmVycygpIHtcblxuXHRcdGNvbnN0IHRtcCA9IHRoaXMucmVhZEJ1ZmZlcjtcblx0XHR0aGlzLnJlYWRCdWZmZXIgPSB0aGlzLndyaXRlQnVmZmVyO1xuXHRcdHRoaXMud3JpdGVCdWZmZXIgPSB0bXA7XG5cblx0fVxuXG5cdGFkZFBhc3MoIHBhc3MgKSB7XG5cblx0XHR0aGlzLnBhc3Nlcy5wdXNoKCBwYXNzICk7XG5cdFx0cGFzcy5zZXRTaXplKCB0aGlzLl93aWR0aCAqIHRoaXMuX3BpeGVsUmF0aW8sIHRoaXMuX2hlaWdodCAqIHRoaXMuX3BpeGVsUmF0aW8gKTtcblxuXHR9XG5cblx0aW5zZXJ0UGFzcyggcGFzcywgaW5kZXggKSB7XG5cblx0XHR0aGlzLnBhc3Nlcy5zcGxpY2UoIGluZGV4LCAwLCBwYXNzICk7XG5cdFx0cGFzcy5zZXRTaXplKCB0aGlzLl93aWR0aCAqIHRoaXMuX3BpeGVsUmF0aW8sIHRoaXMuX2hlaWdodCAqIHRoaXMuX3BpeGVsUmF0aW8gKTtcblxuXHR9XG5cblx0cmVtb3ZlUGFzcyggcGFzcyApIHtcblxuXHRcdGNvbnN0IGluZGV4ID0gdGhpcy5wYXNzZXMuaW5kZXhPZiggcGFzcyApO1xuXG5cdFx0aWYgKCBpbmRleCAhPT0gLSAxICkge1xuXG5cdFx0XHR0aGlzLnBhc3Nlcy5zcGxpY2UoIGluZGV4LCAxICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGlzTGFzdEVuYWJsZWRQYXNzKCBwYXNzSW5kZXggKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IHBhc3NJbmRleCArIDE7IGkgPCB0aGlzLnBhc3Nlcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdGlmICggdGhpcy5wYXNzZXNbIGkgXS5lbmFibGVkICkge1xuXG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fVxuXG5cdHJlbmRlciggZGVsdGFUaW1lICkge1xuXG5cdFx0Ly8gZGVsdGFUaW1lIHZhbHVlIGlzIGluIHNlY29uZHNcblxuXHRcdGlmICggZGVsdGFUaW1lID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGRlbHRhVGltZSA9IHRoaXMuY2xvY2suZ2V0RGVsdGEoKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGN1cnJlbnRSZW5kZXJUYXJnZXQgPSB0aGlzLnJlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xuXG5cdFx0bGV0IG1hc2tBY3RpdmUgPSBmYWxzZTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0aGlzLnBhc3Nlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgcGFzcyA9IHRoaXMucGFzc2VzWyBpIF07XG5cblx0XHRcdGlmICggcGFzcy5lbmFibGVkID09PSBmYWxzZSApIGNvbnRpbnVlO1xuXG5cdFx0XHRwYXNzLnJlbmRlclRvU2NyZWVuID0gKCB0aGlzLnJlbmRlclRvU2NyZWVuICYmIHRoaXMuaXNMYXN0RW5hYmxlZFBhc3MoIGkgKSApO1xuXHRcdFx0cGFzcy5yZW5kZXIoIHRoaXMucmVuZGVyZXIsIHRoaXMud3JpdGVCdWZmZXIsIHRoaXMucmVhZEJ1ZmZlciwgZGVsdGFUaW1lLCBtYXNrQWN0aXZlICk7XG5cblx0XHRcdGlmICggcGFzcy5uZWVkc1N3YXAgKSB7XG5cblx0XHRcdFx0aWYgKCBtYXNrQWN0aXZlICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgY29udGV4dCA9IHRoaXMucmVuZGVyZXIuZ2V0Q29udGV4dCgpO1xuXHRcdFx0XHRcdGNvbnN0IHN0ZW5jaWwgPSB0aGlzLnJlbmRlcmVyLnN0YXRlLmJ1ZmZlcnMuc3RlbmNpbDtcblxuXHRcdFx0XHRcdC8vY29udGV4dC5zdGVuY2lsRnVuYyggY29udGV4dC5OT1RFUVVBTCwgMSwgMHhmZmZmZmZmZiApO1xuXHRcdFx0XHRcdHN0ZW5jaWwuc2V0RnVuYyggY29udGV4dC5OT1RFUVVBTCwgMSwgMHhmZmZmZmZmZiApO1xuXG5cdFx0XHRcdFx0dGhpcy5jb3B5UGFzcy5yZW5kZXIoIHRoaXMucmVuZGVyZXIsIHRoaXMud3JpdGVCdWZmZXIsIHRoaXMucmVhZEJ1ZmZlciwgZGVsdGFUaW1lICk7XG5cblx0XHRcdFx0XHQvL2NvbnRleHQuc3RlbmNpbEZ1bmMoIGNvbnRleHQuRVFVQUwsIDEsIDB4ZmZmZmZmZmYgKTtcblx0XHRcdFx0XHRzdGVuY2lsLnNldEZ1bmMoIGNvbnRleHQuRVFVQUwsIDEsIDB4ZmZmZmZmZmYgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0dGhpcy5zd2FwQnVmZmVycygpO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggTWFza1Bhc3MgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRpZiAoIHBhc3MgaW5zdGFuY2VvZiBNYXNrUGFzcyApIHtcblxuXHRcdFx0XHRcdG1hc2tBY3RpdmUgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHBhc3MgaW5zdGFuY2VvZiBDbGVhck1hc2tQYXNzICkge1xuXG5cdFx0XHRcdFx0bWFza0FjdGl2ZSA9IGZhbHNlO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0dGhpcy5yZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1cnJlbnRSZW5kZXJUYXJnZXQgKTtcblxuXHR9XG5cblx0cmVzZXQoIHJlbmRlclRhcmdldCApIHtcblxuXHRcdGlmICggcmVuZGVyVGFyZ2V0ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IHNpemUgPSB0aGlzLnJlbmRlcmVyLmdldFNpemUoIG5ldyBWZWN0b3IyKCkgKTtcblx0XHRcdHRoaXMuX3BpeGVsUmF0aW8gPSB0aGlzLnJlbmRlcmVyLmdldFBpeGVsUmF0aW8oKTtcblx0XHRcdHRoaXMuX3dpZHRoID0gc2l6ZS53aWR0aDtcblx0XHRcdHRoaXMuX2hlaWdodCA9IHNpemUuaGVpZ2h0O1xuXG5cdFx0XHRyZW5kZXJUYXJnZXQgPSB0aGlzLnJlbmRlclRhcmdldDEuY2xvbmUoKTtcblx0XHRcdHJlbmRlclRhcmdldC5zZXRTaXplKCB0aGlzLl93aWR0aCAqIHRoaXMuX3BpeGVsUmF0aW8sIHRoaXMuX2hlaWdodCAqIHRoaXMuX3BpeGVsUmF0aW8gKTtcblxuXHRcdH1cblxuXHRcdHRoaXMucmVuZGVyVGFyZ2V0MS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5yZW5kZXJUYXJnZXQyLmRpc3Bvc2UoKTtcblx0XHR0aGlzLnJlbmRlclRhcmdldDEgPSByZW5kZXJUYXJnZXQ7XG5cdFx0dGhpcy5yZW5kZXJUYXJnZXQyID0gcmVuZGVyVGFyZ2V0LmNsb25lKCk7XG5cblx0XHR0aGlzLndyaXRlQnVmZmVyID0gdGhpcy5yZW5kZXJUYXJnZXQxO1xuXHRcdHRoaXMucmVhZEJ1ZmZlciA9IHRoaXMucmVuZGVyVGFyZ2V0MjtcblxuXHR9XG5cblx0c2V0U2l6ZSggd2lkdGgsIGhlaWdodCApIHtcblxuXHRcdHRoaXMuX3dpZHRoID0gd2lkdGg7XG5cdFx0dGhpcy5faGVpZ2h0ID0gaGVpZ2h0O1xuXG5cdFx0Y29uc3QgZWZmZWN0aXZlV2lkdGggPSB0aGlzLl93aWR0aCAqIHRoaXMuX3BpeGVsUmF0aW87XG5cdFx0Y29uc3QgZWZmZWN0aXZlSGVpZ2h0ID0gdGhpcy5faGVpZ2h0ICogdGhpcy5fcGl4ZWxSYXRpbztcblxuXHRcdHRoaXMucmVuZGVyVGFyZ2V0MS5zZXRTaXplKCBlZmZlY3RpdmVXaWR0aCwgZWZmZWN0aXZlSGVpZ2h0ICk7XG5cdFx0dGhpcy5yZW5kZXJUYXJnZXQyLnNldFNpemUoIGVmZmVjdGl2ZVdpZHRoLCBlZmZlY3RpdmVIZWlnaHQgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMucGFzc2VzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5wYXNzZXNbIGkgXS5zZXRTaXplKCBlZmZlY3RpdmVXaWR0aCwgZWZmZWN0aXZlSGVpZ2h0ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHNldFBpeGVsUmF0aW8oIHBpeGVsUmF0aW8gKSB7XG5cblx0XHR0aGlzLl9waXhlbFJhdGlvID0gcGl4ZWxSYXRpbztcblxuXHRcdHRoaXMuc2V0U2l6ZSggdGhpcy5fd2lkdGgsIHRoaXMuX2hlaWdodCApO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5yZW5kZXJUYXJnZXQxLmRpc3Bvc2UoKTtcblx0XHR0aGlzLnJlbmRlclRhcmdldDIuZGlzcG9zZSgpO1xuXG5cdFx0dGhpcy5jb3B5UGFzcy5kaXNwb3NlKCk7XG5cblx0fVxuXG59XG5cbmV4cG9ydCB7IEVmZmVjdENvbXBvc2VyIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///596\n")},296:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n X: () => (/* binding */ OutputPass)\n});\n\n// EXTERNAL MODULE: ./node_modules/three/build/three.module.js\nvar three_module = __webpack_require__(753);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/postprocessing/Pass.js\nvar Pass = __webpack_require__(844);\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/shaders/OutputShader.js\nconst OutputShader = {\n\n\tname: 'OutputShader',\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'toneMappingExposure': { value: 1 }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\t\tprecision highp float;\n\n\t\tuniform mat4 modelViewMatrix;\n\t\tuniform mat4 projectionMatrix;\n\n\t\tattribute vec3 position;\n\t\tattribute vec2 uv;\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\t\n\t\tprecision highp float;\n\n\t\tuniform sampler2D tDiffuse;\n\n\t\t#include \n\t\t#include \n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tgl_FragColor = texture2D( tDiffuse, vUv );\n\n\t\t\t// tone mapping\n\n\t\t\t#ifdef LINEAR_TONE_MAPPING\n\n\t\t\t\tgl_FragColor.rgb = LinearToneMapping( gl_FragColor.rgb );\n\n\t\t\t#elif defined( REINHARD_TONE_MAPPING )\n\n\t\t\t\tgl_FragColor.rgb = ReinhardToneMapping( gl_FragColor.rgb );\n\n\t\t\t#elif defined( CINEON_TONE_MAPPING )\n\n\t\t\t\tgl_FragColor.rgb = OptimizedCineonToneMapping( gl_FragColor.rgb );\n\n\t\t\t#elif defined( ACES_FILMIC_TONE_MAPPING )\n\n\t\t\t\tgl_FragColor.rgb = ACESFilmicToneMapping( gl_FragColor.rgb );\n\n\t\t\t#elif defined( AGX_TONE_MAPPING )\n\n\t\t\t\tgl_FragColor.rgb = AgXToneMapping( gl_FragColor.rgb );\n\n\t\t\t#elif defined( NEUTRAL_TONE_MAPPING )\n\n\t\t\t\tgl_FragColor.rgb = NeutralToneMapping( gl_FragColor.rgb );\n\n\t\t\t#endif\n\n\t\t\t// color space\n\n\t\t\t#ifdef SRGB_TRANSFER\n\n\t\t\t\tgl_FragColor = sRGBTransferOETF( gl_FragColor );\n\n\t\t\t#endif\n\n\t\t}`\n\n};\n\n\n\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/postprocessing/OutputPass.js\n\n\n\n\nclass OutputPass extends Pass/* Pass */.o {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\t//\n\n\t\tconst shader = OutputShader;\n\n\t\tthis.uniforms = three_module/* UniformsUtils */.LlO.clone( shader.uniforms );\n\n\t\tthis.material = new three_module/* RawShaderMaterial */.D$Q( {\n\t\t\tname: shader.name,\n\t\t\tuniforms: this.uniforms,\n\t\t\tvertexShader: shader.vertexShader,\n\t\t\tfragmentShader: shader.fragmentShader\n\t\t} );\n\n\t\tthis.fsQuad = new Pass/* FullScreenQuad */.F( this.material );\n\n\t\t// internal cache\n\n\t\tthis._outputColorSpace = null;\n\t\tthis._toneMapping = null;\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive */ ) {\n\n\t\tthis.uniforms[ 'tDiffuse' ].value = readBuffer.texture;\n\t\tthis.uniforms[ 'toneMappingExposure' ].value = renderer.toneMappingExposure;\n\n\t\t// rebuild defines if required\n\n\t\tif ( this._outputColorSpace !== renderer.outputColorSpace || this._toneMapping !== renderer.toneMapping ) {\n\n\t\t\tthis._outputColorSpace = renderer.outputColorSpace;\n\t\t\tthis._toneMapping = renderer.toneMapping;\n\n\t\t\tthis.material.defines = {};\n\n\t\t\tif ( three_module/* ColorManagement */.ppV.getTransfer( this._outputColorSpace ) === three_module/* SRGBTransfer */.KLL ) this.material.defines.SRGB_TRANSFER = '';\n\n\t\t\tif ( this._toneMapping === three_module/* LinearToneMapping */.kyO ) this.material.defines.LINEAR_TONE_MAPPING = '';\n\t\t\telse if ( this._toneMapping === three_module/* ReinhardToneMapping */.Mjd ) this.material.defines.REINHARD_TONE_MAPPING = '';\n\t\t\telse if ( this._toneMapping === three_module/* CineonToneMapping */.nNL ) this.material.defines.CINEON_TONE_MAPPING = '';\n\t\t\telse if ( this._toneMapping === three_module/* ACESFilmicToneMapping */.FV ) this.material.defines.ACES_FILMIC_TONE_MAPPING = '';\n\t\t\telse if ( this._toneMapping === three_module/* AgXToneMapping */.LAk ) this.material.defines.AGX_TONE_MAPPING = '';\n\t\t\telse if ( this._toneMapping === three_module/* NeutralToneMapping */.aJ8 ) this.material.defines.NEUTRAL_TONE_MAPPING = '';\n\n\t\t\tthis.material.needsUpdate = true;\n\n\t\t}\n\n\t\t//\n\n\t\tif ( this.renderToScreen === true ) {\n\n\t\t\trenderer.setRenderTarget( null );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t} else {\n\n\t\t\trenderer.setRenderTarget( writeBuffer );\n\t\t\tif ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t}\n\n\t}\n\n\tdispose() {\n\n\t\tthis.material.dispose();\n\t\tthis.fsQuad.dispose();\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMjk2LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQUE7O0FBRUE7O0FBRUE7O0FBRUEsZ0JBQWdCLGFBQWE7QUFDN0IsMkJBQTJCOztBQUUzQixFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUV3Qjs7O0FDekVUO0FBQ2tDO0FBQ1M7O0FBRTFELHlCQUF5QixnQkFBSTs7QUFFN0I7O0FBRUE7O0FBRUE7O0FBRUEsaUJBQWlCLFlBQVk7O0FBRTdCLGtCQUFrQixtQ0FBYTs7QUFFL0Isc0JBQXNCLHVDQUFpQjtBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUosb0JBQW9CLDBCQUFjOztBQUVsQzs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxRQUFRLHFDQUFlLDJDQUEyQyxrQ0FBWTs7QUFFOUUsOEJBQThCLHVDQUFpQjtBQUMvQyxtQ0FBbUMseUNBQW1CO0FBQ3RELG1DQUFtQyx1Q0FBaUI7QUFDcEQsbUNBQW1DLDBDQUFxQjtBQUN4RCxtQ0FBbUMsb0NBQWM7QUFDakQsbUNBQW1DLHdDQUFrQjs7QUFFckQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVzQiIsInNvdXJjZXMiOlsid2VicGFjazovL3RocmVlanMtcG9zdHByb2Nlc3MvLi9ub2RlX21vZHVsZXMvdGhyZWUvZXhhbXBsZXMvanNtL3NoYWRlcnMvT3V0cHV0U2hhZGVyLmpzPzA5YzQiLCJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy90aHJlZS9leGFtcGxlcy9qc20vcG9zdHByb2Nlc3NpbmcvT3V0cHV0UGFzcy5qcz8yN2U3Il0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IE91dHB1dFNoYWRlciA9IHtcblxuXHRuYW1lOiAnT3V0cHV0U2hhZGVyJyxcblxuXHR1bmlmb3Jtczoge1xuXG5cdFx0J3REaWZmdXNlJzogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdCd0b25lTWFwcGluZ0V4cG9zdXJlJzogeyB2YWx1ZTogMSB9XG5cblx0fSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cdFx0cHJlY2lzaW9uIGhpZ2hwIGZsb2F0O1xuXG5cdFx0dW5pZm9ybSBtYXQ0IG1vZGVsVmlld01hdHJpeDtcblx0XHR1bmlmb3JtIG1hdDQgcHJvamVjdGlvbk1hdHJpeDtcblxuXHRcdGF0dHJpYnV0ZSB2ZWMzIHBvc2l0aW9uO1xuXHRcdGF0dHJpYnV0ZSB2ZWMyIHV2O1xuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0dlV2ID0gdXY7XG5cdFx0XHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XG5cblx0XHR9YCxcblxuXHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2Bcblx0XG5cdFx0cHJlY2lzaW9uIGhpZ2hwIGZsb2F0O1xuXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgdERpZmZ1c2U7XG5cblx0XHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudD5cblx0XHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9wYXJzX2ZyYWdtZW50PlxuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0Z2xfRnJhZ0NvbG9yID0gdGV4dHVyZTJEKCB0RGlmZnVzZSwgdlV2ICk7XG5cblx0XHRcdC8vIHRvbmUgbWFwcGluZ1xuXG5cdFx0XHQjaWZkZWYgTElORUFSX1RPTkVfTUFQUElOR1xuXG5cdFx0XHRcdGdsX0ZyYWdDb2xvci5yZ2IgPSBMaW5lYXJUb25lTWFwcGluZyggZ2xfRnJhZ0NvbG9yLnJnYiApO1xuXG5cdFx0XHQjZWxpZiBkZWZpbmVkKCBSRUlOSEFSRF9UT05FX01BUFBJTkcgKVxuXG5cdFx0XHRcdGdsX0ZyYWdDb2xvci5yZ2IgPSBSZWluaGFyZFRvbmVNYXBwaW5nKCBnbF9GcmFnQ29sb3IucmdiICk7XG5cblx0XHRcdCNlbGlmIGRlZmluZWQoIENJTkVPTl9UT05FX01BUFBJTkcgKVxuXG5cdFx0XHRcdGdsX0ZyYWdDb2xvci5yZ2IgPSBPcHRpbWl6ZWRDaW5lb25Ub25lTWFwcGluZyggZ2xfRnJhZ0NvbG9yLnJnYiApO1xuXG5cdFx0XHQjZWxpZiBkZWZpbmVkKCBBQ0VTX0ZJTE1JQ19UT05FX01BUFBJTkcgKVxuXG5cdFx0XHRcdGdsX0ZyYWdDb2xvci5yZ2IgPSBBQ0VTRmlsbWljVG9uZU1hcHBpbmcoIGdsX0ZyYWdDb2xvci5yZ2IgKTtcblxuXHRcdFx0I2VsaWYgZGVmaW5lZCggQUdYX1RPTkVfTUFQUElORyApXG5cblx0XHRcdFx0Z2xfRnJhZ0NvbG9yLnJnYiA9IEFnWFRvbmVNYXBwaW5nKCBnbF9GcmFnQ29sb3IucmdiICk7XG5cblx0XHRcdCNlbGlmIGRlZmluZWQoIE5FVVRSQUxfVE9ORV9NQVBQSU5HIClcblxuXHRcdFx0XHRnbF9GcmFnQ29sb3IucmdiID0gTmV1dHJhbFRvbmVNYXBwaW5nKCBnbF9GcmFnQ29sb3IucmdiICk7XG5cblx0XHRcdCNlbmRpZlxuXG5cdFx0XHQvLyBjb2xvciBzcGFjZVxuXG5cdFx0XHQjaWZkZWYgU1JHQl9UUkFOU0ZFUlxuXG5cdFx0XHRcdGdsX0ZyYWdDb2xvciA9IHNSR0JUcmFuc2Zlck9FVEYoIGdsX0ZyYWdDb2xvciApO1xuXG5cdFx0XHQjZW5kaWZcblxuXHRcdH1gXG5cbn07XG5cbmV4cG9ydCB7IE91dHB1dFNoYWRlciB9O1xuIiwiaW1wb3J0IHtcblx0Q29sb3JNYW5hZ2VtZW50LFxuXHRSYXdTaGFkZXJNYXRlcmlhbCxcblx0VW5pZm9ybXNVdGlscyxcblx0TGluZWFyVG9uZU1hcHBpbmcsXG5cdFJlaW5oYXJkVG9uZU1hcHBpbmcsXG5cdENpbmVvblRvbmVNYXBwaW5nLFxuXHRBZ1hUb25lTWFwcGluZyxcblx0QUNFU0ZpbG1pY1RvbmVNYXBwaW5nLFxuXHROZXV0cmFsVG9uZU1hcHBpbmcsXG5cdFNSR0JUcmFuc2ZlclxufSBmcm9tICd0aHJlZSc7XG5pbXBvcnQgeyBQYXNzLCBGdWxsU2NyZWVuUXVhZCB9IGZyb20gJy4vUGFzcy5qcyc7XG5pbXBvcnQgeyBPdXRwdXRTaGFkZXIgfSBmcm9tICcuLi9zaGFkZXJzL091dHB1dFNoYWRlci5qcyc7XG5cbmNsYXNzIE91dHB1dFBhc3MgZXh0ZW5kcyBQYXNzIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHQvL1xuXG5cdFx0Y29uc3Qgc2hhZGVyID0gT3V0cHV0U2hhZGVyO1xuXG5cdFx0dGhpcy51bmlmb3JtcyA9IFVuaWZvcm1zVXRpbHMuY2xvbmUoIHNoYWRlci51bmlmb3JtcyApO1xuXG5cdFx0dGhpcy5tYXRlcmlhbCA9IG5ldyBSYXdTaGFkZXJNYXRlcmlhbCgge1xuXHRcdFx0bmFtZTogc2hhZGVyLm5hbWUsXG5cdFx0XHR1bmlmb3JtczogdGhpcy51bmlmb3Jtcyxcblx0XHRcdHZlcnRleFNoYWRlcjogc2hhZGVyLnZlcnRleFNoYWRlcixcblx0XHRcdGZyYWdtZW50U2hhZGVyOiBzaGFkZXIuZnJhZ21lbnRTaGFkZXJcblx0XHR9ICk7XG5cblx0XHR0aGlzLmZzUXVhZCA9IG5ldyBGdWxsU2NyZWVuUXVhZCggdGhpcy5tYXRlcmlhbCApO1xuXG5cdFx0Ly8gaW50ZXJuYWwgY2FjaGVcblxuXHRcdHRoaXMuX291dHB1dENvbG9yU3BhY2UgPSBudWxsO1xuXHRcdHRoaXMuX3RvbmVNYXBwaW5nID0gbnVsbDtcblxuXHR9XG5cblx0cmVuZGVyKCByZW5kZXJlciwgd3JpdGVCdWZmZXIsIHJlYWRCdWZmZXIvKiwgZGVsdGFUaW1lLCBtYXNrQWN0aXZlICovICkge1xuXG5cdFx0dGhpcy51bmlmb3Jtc1sgJ3REaWZmdXNlJyBdLnZhbHVlID0gcmVhZEJ1ZmZlci50ZXh0dXJlO1xuXHRcdHRoaXMudW5pZm9ybXNbICd0b25lTWFwcGluZ0V4cG9zdXJlJyBdLnZhbHVlID0gcmVuZGVyZXIudG9uZU1hcHBpbmdFeHBvc3VyZTtcblxuXHRcdC8vIHJlYnVpbGQgZGVmaW5lcyBpZiByZXF1aXJlZFxuXG5cdFx0aWYgKCB0aGlzLl9vdXRwdXRDb2xvclNwYWNlICE9PSByZW5kZXJlci5vdXRwdXRDb2xvclNwYWNlIHx8IHRoaXMuX3RvbmVNYXBwaW5nICE9PSByZW5kZXJlci50b25lTWFwcGluZyApIHtcblxuXHRcdFx0dGhpcy5fb3V0cHV0Q29sb3JTcGFjZSA9IHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2U7XG5cdFx0XHR0aGlzLl90b25lTWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xuXG5cdFx0XHR0aGlzLm1hdGVyaWFsLmRlZmluZXMgPSB7fTtcblxuXHRcdFx0aWYgKCBDb2xvck1hbmFnZW1lbnQuZ2V0VHJhbnNmZXIoIHRoaXMuX291dHB1dENvbG9yU3BhY2UgKSA9PT0gU1JHQlRyYW5zZmVyICkgdGhpcy5tYXRlcmlhbC5kZWZpbmVzLlNSR0JfVFJBTlNGRVIgPSAnJztcblxuXHRcdFx0aWYgKCB0aGlzLl90b25lTWFwcGluZyA9PT0gTGluZWFyVG9uZU1hcHBpbmcgKSB0aGlzLm1hdGVyaWFsLmRlZmluZXMuTElORUFSX1RPTkVfTUFQUElORyA9ICcnO1xuXHRcdFx0ZWxzZSBpZiAoIHRoaXMuX3RvbmVNYXBwaW5nID09PSBSZWluaGFyZFRvbmVNYXBwaW5nICkgdGhpcy5tYXRlcmlhbC5kZWZpbmVzLlJFSU5IQVJEX1RPTkVfTUFQUElORyA9ICcnO1xuXHRcdFx0ZWxzZSBpZiAoIHRoaXMuX3RvbmVNYXBwaW5nID09PSBDaW5lb25Ub25lTWFwcGluZyApIHRoaXMubWF0ZXJpYWwuZGVmaW5lcy5DSU5FT05fVE9ORV9NQVBQSU5HID0gJyc7XG5cdFx0XHRlbHNlIGlmICggdGhpcy5fdG9uZU1hcHBpbmcgPT09IEFDRVNGaWxtaWNUb25lTWFwcGluZyApIHRoaXMubWF0ZXJpYWwuZGVmaW5lcy5BQ0VTX0ZJTE1JQ19UT05FX01BUFBJTkcgPSAnJztcblx0XHRcdGVsc2UgaWYgKCB0aGlzLl90b25lTWFwcGluZyA9PT0gQWdYVG9uZU1hcHBpbmcgKSB0aGlzLm1hdGVyaWFsLmRlZmluZXMuQUdYX1RPTkVfTUFQUElORyA9ICcnO1xuXHRcdFx0ZWxzZSBpZiAoIHRoaXMuX3RvbmVNYXBwaW5nID09PSBOZXV0cmFsVG9uZU1hcHBpbmcgKSB0aGlzLm1hdGVyaWFsLmRlZmluZXMuTkVVVFJBTF9UT05FX01BUFBJTkcgPSAnJztcblxuXHRcdFx0dGhpcy5tYXRlcmlhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR9XG5cblx0XHQvL1xuXG5cdFx0aWYgKCB0aGlzLnJlbmRlclRvU2NyZWVuID09PSB0cnVlICkge1xuXG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIG51bGwgKTtcblx0XHRcdHRoaXMuZnNRdWFkLnJlbmRlciggcmVuZGVyZXIgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggd3JpdGVCdWZmZXIgKTtcblx0XHRcdGlmICggdGhpcy5jbGVhciApIHJlbmRlcmVyLmNsZWFyKCByZW5kZXJlci5hdXRvQ2xlYXJDb2xvciwgcmVuZGVyZXIuYXV0b0NsZWFyRGVwdGgsIHJlbmRlcmVyLmF1dG9DbGVhclN0ZW5jaWwgKTtcblx0XHRcdHRoaXMuZnNRdWFkLnJlbmRlciggcmVuZGVyZXIgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXHRcdHRoaXMuZnNRdWFkLmRpc3Bvc2UoKTtcblxuXHR9XG5cbn1cblxuZXhwb3J0IHsgT3V0cHV0UGFzcyB9O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///296\n")},844:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ F: () => (/* binding */ FullScreenQuad),\n/* harmony export */ o: () => (/* binding */ Pass)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(753);\n\n\nclass Pass {\n\n\tconstructor() {\n\n\t\tthis.isPass = true;\n\n\t\t// if set to true, the pass is processed by the composer\n\t\tthis.enabled = true;\n\n\t\t// if set to true, the pass indicates to swap read and write buffer after rendering\n\t\tthis.needsSwap = true;\n\n\t\t// if set to true, the pass clears its buffer before rendering\n\t\tthis.clear = false;\n\n\t\t// if set to true, the result of the pass is rendered to screen. This is set automatically by EffectComposer.\n\t\tthis.renderToScreen = false;\n\n\t}\n\n\tsetSize( /* width, height */ ) {}\n\n\trender( /* renderer, writeBuffer, readBuffer, deltaTime, maskActive */ ) {\n\n\t\tconsole.error( 'THREE.Pass: .render() must be implemented in derived pass.' );\n\n\t}\n\n\tdispose() {}\n\n}\n\n// Helper for passes that need to fill the viewport with a single quad.\n\nconst _camera = new three__WEBPACK_IMPORTED_MODULE_0__/* .OrthographicCamera */ .qUd( - 1, 1, 1, - 1, 0, 1 );\n\n// https://github.com/mrdoob/three.js/pull/21358\n\nclass FullscreenTriangleGeometry extends three__WEBPACK_IMPORTED_MODULE_0__/* .BufferGeometry */ .LoY {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.setAttribute( 'position', new three__WEBPACK_IMPORTED_MODULE_0__/* .Float32BufferAttribute */ .qtW( [ - 1, 3, 0, - 1, - 1, 0, 3, - 1, 0 ], 3 ) );\n\t\tthis.setAttribute( 'uv', new three__WEBPACK_IMPORTED_MODULE_0__/* .Float32BufferAttribute */ .qtW( [ 0, 2, 0, 0, 2, 0 ], 2 ) );\n\n\t}\n\n}\n\nconst _geometry = new FullscreenTriangleGeometry();\n\nclass FullScreenQuad {\n\n\tconstructor( material ) {\n\n\t\tthis._mesh = new three__WEBPACK_IMPORTED_MODULE_0__/* .Mesh */ .eaF( _geometry, material );\n\n\t}\n\n\tdispose() {\n\n\t\tthis._mesh.geometry.dispose();\n\n\t}\n\n\trender( renderer ) {\n\n\t\trenderer.render( this._mesh, _camera );\n\n\t}\n\n\tget material() {\n\n\t\treturn this._mesh.material;\n\n\t}\n\n\tset material( value ) {\n\n\t\tthis._mesh.material = value;\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiODQ0LmpzIiwibWFwcGluZ3MiOiI7Ozs7O0FBS2U7O0FBRWY7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsZ0VBQWtCOztBQUV0Qzs7QUFFQSx5Q0FBeUMsNERBQWM7O0FBRXZEOztBQUVBOztBQUVBLHFDQUFxQyxvRUFBc0I7QUFDM0QsK0JBQStCLG9FQUFzQjs7QUFFckQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGtEQUFJOztBQUV2Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFZ0MiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9wb3N0cHJvY2Vzc2luZy9QYXNzLmpzP2FlMWYiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0QnVmZmVyR2VvbWV0cnksXG5cdEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUsXG5cdE9ydGhvZ3JhcGhpY0NhbWVyYSxcblx0TWVzaFxufSBmcm9tICd0aHJlZSc7XG5cbmNsYXNzIFBhc3Mge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0dGhpcy5pc1Bhc3MgPSB0cnVlO1xuXG5cdFx0Ly8gaWYgc2V0IHRvIHRydWUsIHRoZSBwYXNzIGlzIHByb2Nlc3NlZCBieSB0aGUgY29tcG9zZXJcblx0XHR0aGlzLmVuYWJsZWQgPSB0cnVlO1xuXG5cdFx0Ly8gaWYgc2V0IHRvIHRydWUsIHRoZSBwYXNzIGluZGljYXRlcyB0byBzd2FwIHJlYWQgYW5kIHdyaXRlIGJ1ZmZlciBhZnRlciByZW5kZXJpbmdcblx0XHR0aGlzLm5lZWRzU3dhcCA9IHRydWU7XG5cblx0XHQvLyBpZiBzZXQgdG8gdHJ1ZSwgdGhlIHBhc3MgY2xlYXJzIGl0cyBidWZmZXIgYmVmb3JlIHJlbmRlcmluZ1xuXHRcdHRoaXMuY2xlYXIgPSBmYWxzZTtcblxuXHRcdC8vIGlmIHNldCB0byB0cnVlLCB0aGUgcmVzdWx0IG9mIHRoZSBwYXNzIGlzIHJlbmRlcmVkIHRvIHNjcmVlbi4gVGhpcyBpcyBzZXQgYXV0b21hdGljYWxseSBieSBFZmZlY3RDb21wb3Nlci5cblx0XHR0aGlzLnJlbmRlclRvU2NyZWVuID0gZmFsc2U7XG5cblx0fVxuXG5cdHNldFNpemUoIC8qIHdpZHRoLCBoZWlnaHQgKi8gKSB7fVxuXG5cdHJlbmRlciggLyogcmVuZGVyZXIsIHdyaXRlQnVmZmVyLCByZWFkQnVmZmVyLCBkZWx0YVRpbWUsIG1hc2tBY3RpdmUgKi8gKSB7XG5cblx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUGFzczogLnJlbmRlcigpIG11c3QgYmUgaW1wbGVtZW50ZWQgaW4gZGVyaXZlZCBwYXNzLicgKTtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHt9XG5cbn1cblxuLy8gSGVscGVyIGZvciBwYXNzZXMgdGhhdCBuZWVkIHRvIGZpbGwgdGhlIHZpZXdwb3J0IHdpdGggYSBzaW5nbGUgcXVhZC5cblxuY29uc3QgX2NhbWVyYSA9IG5ldyBPcnRob2dyYXBoaWNDYW1lcmEoIC0gMSwgMSwgMSwgLSAxLCAwLCAxICk7XG5cbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvcHVsbC8yMTM1OFxuXG5jbGFzcyBGdWxsc2NyZWVuVHJpYW5nbGVHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIFsgLSAxLCAzLCAwLCAtIDEsIC0gMSwgMCwgMywgLSAxLCAwIF0sIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggWyAwLCAyLCAwLCAwLCAyLCAwIF0sIDIgKSApO1xuXG5cdH1cblxufVxuXG5jb25zdCBfZ2VvbWV0cnkgPSBuZXcgRnVsbHNjcmVlblRyaWFuZ2xlR2VvbWV0cnkoKTtcblxuY2xhc3MgRnVsbFNjcmVlblF1YWQge1xuXG5cdGNvbnN0cnVjdG9yKCBtYXRlcmlhbCApIHtcblxuXHRcdHRoaXMuX21lc2ggPSBuZXcgTWVzaCggX2dlb21ldHJ5LCBtYXRlcmlhbCApO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5fbWVzaC5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cblx0fVxuXG5cdHJlbmRlciggcmVuZGVyZXIgKSB7XG5cblx0XHRyZW5kZXJlci5yZW5kZXIoIHRoaXMuX21lc2gsIF9jYW1lcmEgKTtcblxuXHR9XG5cblx0Z2V0IG1hdGVyaWFsKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX21lc2gubWF0ZXJpYWw7XG5cblx0fVxuXG5cdHNldCBtYXRlcmlhbCggdmFsdWUgKSB7XG5cblx0XHR0aGlzLl9tZXNoLm1hdGVyaWFsID0gdmFsdWU7XG5cblx0fVxuXG59XG5cbmV4cG9ydCB7IFBhc3MsIEZ1bGxTY3JlZW5RdWFkIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///844\n")},968:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ A: () => (/* binding */ RenderPass)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(753);\n/* harmony import */ var _Pass_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(844);\n\n\n\nclass RenderPass extends _Pass_js__WEBPACK_IMPORTED_MODULE_0__/* .Pass */ .o {\n\n\tconstructor( scene, camera, overrideMaterial = null, clearColor = null, clearAlpha = null ) {\n\n\t\tsuper();\n\n\t\tthis.scene = scene;\n\t\tthis.camera = camera;\n\n\t\tthis.overrideMaterial = overrideMaterial;\n\n\t\tthis.clearColor = clearColor;\n\t\tthis.clearAlpha = clearAlpha;\n\n\t\tthis.clear = true;\n\t\tthis.clearDepth = false;\n\t\tthis.needsSwap = false;\n\t\tthis._oldClearColor = new three__WEBPACK_IMPORTED_MODULE_1__/* .Color */ .Q1f();\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {\n\n\t\tconst oldAutoClear = renderer.autoClear;\n\t\trenderer.autoClear = false;\n\n\t\tlet oldClearAlpha, oldOverrideMaterial;\n\n\t\tif ( this.overrideMaterial !== null ) {\n\n\t\t\toldOverrideMaterial = this.scene.overrideMaterial;\n\n\t\t\tthis.scene.overrideMaterial = this.overrideMaterial;\n\n\t\t}\n\n\t\tif ( this.clearColor !== null ) {\n\n\t\t\trenderer.getClearColor( this._oldClearColor );\n\t\t\trenderer.setClearColor( this.clearColor, renderer.getClearAlpha() );\n\n\t\t}\n\n\t\tif ( this.clearAlpha !== null ) {\n\n\t\t\toldClearAlpha = renderer.getClearAlpha();\n\t\t\trenderer.setClearAlpha( this.clearAlpha );\n\n\t\t}\n\n\t\tif ( this.clearDepth == true ) {\n\n\t\t\trenderer.clearDepth();\n\n\t\t}\n\n\t\trenderer.setRenderTarget( this.renderToScreen ? null : readBuffer );\n\n\t\tif ( this.clear === true ) {\n\n\t\t\t// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600\n\t\t\trenderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );\n\n\t\t}\n\n\t\trenderer.render( this.scene, this.camera );\n\n\t\t// restore\n\n\t\tif ( this.clearColor !== null ) {\n\n\t\t\trenderer.setClearColor( this._oldClearColor );\n\n\t\t}\n\n\t\tif ( this.clearAlpha !== null ) {\n\n\t\t\trenderer.setClearAlpha( oldClearAlpha );\n\n\t\t}\n\n\t\tif ( this.overrideMaterial !== null ) {\n\n\t\t\tthis.scene.overrideMaterial = oldOverrideMaterial;\n\n\t\t}\n\n\t\trenderer.autoClear = oldAutoClear;\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiOTY4LmpzIiwibWFwcGluZ3MiOiI7Ozs7O0FBRWU7QUFDa0I7O0FBRWpDLHlCQUF5QixtREFBSTs7QUFFN0I7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDRCQUE0QixtREFBSzs7QUFFakM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFc0IiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9wb3N0cHJvY2Vzc2luZy9SZW5kZXJQYXNzLmpzPzZjNDIiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0Q29sb3Jcbn0gZnJvbSAndGhyZWUnO1xuaW1wb3J0IHsgUGFzcyB9IGZyb20gJy4vUGFzcy5qcyc7XG5cbmNsYXNzIFJlbmRlclBhc3MgZXh0ZW5kcyBQYXNzIHtcblxuXHRjb25zdHJ1Y3Rvciggc2NlbmUsIGNhbWVyYSwgb3ZlcnJpZGVNYXRlcmlhbCA9IG51bGwsIGNsZWFyQ29sb3IgPSBudWxsLCBjbGVhckFscGhhID0gbnVsbCApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnNjZW5lID0gc2NlbmU7XG5cdFx0dGhpcy5jYW1lcmEgPSBjYW1lcmE7XG5cblx0XHR0aGlzLm92ZXJyaWRlTWF0ZXJpYWwgPSBvdmVycmlkZU1hdGVyaWFsO1xuXG5cdFx0dGhpcy5jbGVhckNvbG9yID0gY2xlYXJDb2xvcjtcblx0XHR0aGlzLmNsZWFyQWxwaGEgPSBjbGVhckFscGhhO1xuXG5cdFx0dGhpcy5jbGVhciA9IHRydWU7XG5cdFx0dGhpcy5jbGVhckRlcHRoID0gZmFsc2U7XG5cdFx0dGhpcy5uZWVkc1N3YXAgPSBmYWxzZTtcblx0XHR0aGlzLl9vbGRDbGVhckNvbG9yID0gbmV3IENvbG9yKCk7XG5cblx0fVxuXG5cdHJlbmRlciggcmVuZGVyZXIsIHdyaXRlQnVmZmVyLCByZWFkQnVmZmVyIC8qLCBkZWx0YVRpbWUsIG1hc2tBY3RpdmUgKi8gKSB7XG5cblx0XHRjb25zdCBvbGRBdXRvQ2xlYXIgPSByZW5kZXJlci5hdXRvQ2xlYXI7XG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gZmFsc2U7XG5cblx0XHRsZXQgb2xkQ2xlYXJBbHBoYSwgb2xkT3ZlcnJpZGVNYXRlcmlhbDtcblxuXHRcdGlmICggdGhpcy5vdmVycmlkZU1hdGVyaWFsICE9PSBudWxsICkge1xuXG5cdFx0XHRvbGRPdmVycmlkZU1hdGVyaWFsID0gdGhpcy5zY2VuZS5vdmVycmlkZU1hdGVyaWFsO1xuXG5cdFx0XHR0aGlzLnNjZW5lLm92ZXJyaWRlTWF0ZXJpYWwgPSB0aGlzLm92ZXJyaWRlTWF0ZXJpYWw7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuY2xlYXJDb2xvciAhPT0gbnVsbCApIHtcblxuXHRcdFx0cmVuZGVyZXIuZ2V0Q2xlYXJDb2xvciggdGhpcy5fb2xkQ2xlYXJDb2xvciApO1xuXHRcdFx0cmVuZGVyZXIuc2V0Q2xlYXJDb2xvciggdGhpcy5jbGVhckNvbG9yLCByZW5kZXJlci5nZXRDbGVhckFscGhhKCkgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5jbGVhckFscGhhICE9PSBudWxsICkge1xuXG5cdFx0XHRvbGRDbGVhckFscGhhID0gcmVuZGVyZXIuZ2V0Q2xlYXJBbHBoYSgpO1xuXHRcdFx0cmVuZGVyZXIuc2V0Q2xlYXJBbHBoYSggdGhpcy5jbGVhckFscGhhICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuY2xlYXJEZXB0aCA9PSB0cnVlICkge1xuXG5cdFx0XHRyZW5kZXJlci5jbGVhckRlcHRoKCk7XG5cblx0XHR9XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHRoaXMucmVuZGVyVG9TY3JlZW4gPyBudWxsIDogcmVhZEJ1ZmZlciApO1xuXG5cdFx0aWYgKCB0aGlzLmNsZWFyID09PSB0cnVlICkge1xuXG5cdFx0XHQvLyBUT0RPOiBBdm9pZCB1c2luZyBhdXRvQ2xlYXIgcHJvcGVydGllcywgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvcHVsbC8xNTU3MSNpc3N1ZWNvbW1lbnQtNDY1NjY5NjAwXG5cdFx0XHRyZW5kZXJlci5jbGVhciggcmVuZGVyZXIuYXV0b0NsZWFyQ29sb3IsIHJlbmRlcmVyLmF1dG9DbGVhckRlcHRoLCByZW5kZXJlci5hdXRvQ2xlYXJTdGVuY2lsICk7XG5cblx0XHR9XG5cblx0XHRyZW5kZXJlci5yZW5kZXIoIHRoaXMuc2NlbmUsIHRoaXMuY2FtZXJhICk7XG5cblx0XHQvLyByZXN0b3JlXG5cblx0XHRpZiAoIHRoaXMuY2xlYXJDb2xvciAhPT0gbnVsbCApIHtcblxuXHRcdFx0cmVuZGVyZXIuc2V0Q2xlYXJDb2xvciggdGhpcy5fb2xkQ2xlYXJDb2xvciApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmNsZWFyQWxwaGEgIT09IG51bGwgKSB7XG5cblx0XHRcdHJlbmRlcmVyLnNldENsZWFyQWxwaGEoIG9sZENsZWFyQWxwaGEgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5vdmVycmlkZU1hdGVyaWFsICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLnNjZW5lLm92ZXJyaWRlTWF0ZXJpYWwgPSBvbGRPdmVycmlkZU1hdGVyaWFsO1xuXG5cdFx0fVxuXG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gb2xkQXV0b0NsZWFyO1xuXG5cdH1cblxufVxuXG5leHBvcnQgeyBSZW5kZXJQYXNzIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///968\n")},737:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n I: () => (/* binding */ SMAAPass)\n});\n\n// EXTERNAL MODULE: ./node_modules/three/build/three.module.js\nvar three_module = __webpack_require__(753);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/postprocessing/Pass.js\nvar Pass = __webpack_require__(844);\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/shaders/SMAAShader.js\n\n\n/**\n * WebGL port of Subpixel Morphological Antialiasing (SMAA) v2.8\n * Preset: SMAA 1x Medium (with color edge detection)\n * https://github.com/iryoku/smaa/releases/tag/v2.8\n */\n\nconst SMAAEdgesShader = {\n\n\tname: 'SMAAEdgesShader',\n\n\tdefines: {\n\n\t\t'SMAA_THRESHOLD': '0.1'\n\n\t},\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'resolution': { value: new three_module/* Vector2 */.I9Y( 1 / 1024, 1 / 512 ) }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[ 3 ];\n\n\t\tvoid SMAAEdgeDetectionVS( vec2 texcoord ) {\n\t\t\tvOffset[ 0 ] = texcoord.xyxy + resolution.xyxy * vec4( -1.0, 0.0, 0.0, 1.0 ); // WebGL port note: Changed sign in W component\n\t\t\tvOffset[ 1 ] = texcoord.xyxy + resolution.xyxy * vec4( 1.0, 0.0, 0.0, -1.0 ); // WebGL port note: Changed sign in W component\n\t\t\tvOffset[ 2 ] = texcoord.xyxy + resolution.xyxy * vec4( -2.0, 0.0, 0.0, 2.0 ); // WebGL port note: Changed sign in W component\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\n\t\t\tSMAAEdgeDetectionVS( vUv );\n\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\n\t\tuniform sampler2D tDiffuse;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[ 3 ];\n\n\t\tvec4 SMAAColorEdgeDetectionPS( vec2 texcoord, vec4 offset[3], sampler2D colorTex ) {\n\t\t\tvec2 threshold = vec2( SMAA_THRESHOLD, SMAA_THRESHOLD );\n\n\t\t\t// Calculate color deltas:\n\t\t\tvec4 delta;\n\t\t\tvec3 C = texture2D( colorTex, texcoord ).rgb;\n\n\t\t\tvec3 Cleft = texture2D( colorTex, offset[0].xy ).rgb;\n\t\t\tvec3 t = abs( C - Cleft );\n\t\t\tdelta.x = max( max( t.r, t.g ), t.b );\n\n\t\t\tvec3 Ctop = texture2D( colorTex, offset[0].zw ).rgb;\n\t\t\tt = abs( C - Ctop );\n\t\t\tdelta.y = max( max( t.r, t.g ), t.b );\n\n\t\t\t// We do the usual threshold:\n\t\t\tvec2 edges = step( threshold, delta.xy );\n\n\t\t\t// Then discard if there is no edge:\n\t\t\tif ( dot( edges, vec2( 1.0, 1.0 ) ) == 0.0 )\n\t\t\t\tdiscard;\n\n\t\t\t// Calculate right and bottom deltas:\n\t\t\tvec3 Cright = texture2D( colorTex, offset[1].xy ).rgb;\n\t\t\tt = abs( C - Cright );\n\t\t\tdelta.z = max( max( t.r, t.g ), t.b );\n\n\t\t\tvec3 Cbottom = texture2D( colorTex, offset[1].zw ).rgb;\n\t\t\tt = abs( C - Cbottom );\n\t\t\tdelta.w = max( max( t.r, t.g ), t.b );\n\n\t\t\t// Calculate the maximum delta in the direct neighborhood:\n\t\t\tfloat maxDelta = max( max( max( delta.x, delta.y ), delta.z ), delta.w );\n\n\t\t\t// Calculate left-left and top-top deltas:\n\t\t\tvec3 Cleftleft = texture2D( colorTex, offset[2].xy ).rgb;\n\t\t\tt = abs( C - Cleftleft );\n\t\t\tdelta.z = max( max( t.r, t.g ), t.b );\n\n\t\t\tvec3 Ctoptop = texture2D( colorTex, offset[2].zw ).rgb;\n\t\t\tt = abs( C - Ctoptop );\n\t\t\tdelta.w = max( max( t.r, t.g ), t.b );\n\n\t\t\t// Calculate the final maximum delta:\n\t\t\tmaxDelta = max( max( maxDelta, delta.z ), delta.w );\n\n\t\t\t// Local contrast adaptation in action:\n\t\t\tedges.xy *= step( 0.5 * maxDelta, delta.xy );\n\n\t\t\treturn vec4( edges, 0.0, 0.0 );\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tgl_FragColor = SMAAColorEdgeDetectionPS( vUv, vOffset, tDiffuse );\n\n\t\t}`\n\n};\n\nconst SMAAWeightsShader = {\n\n\tname: 'SMAAWeightsShader',\n\n\tdefines: {\n\n\t\t'SMAA_MAX_SEARCH_STEPS': '8',\n\t\t'SMAA_AREATEX_MAX_DISTANCE': '16',\n\t\t'SMAA_AREATEX_PIXEL_SIZE': '( 1.0 / vec2( 160.0, 560.0 ) )',\n\t\t'SMAA_AREATEX_SUBTEX_SIZE': '( 1.0 / 7.0 )'\n\n\t},\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'tArea': { value: null },\n\t\t'tSearch': { value: null },\n\t\t'resolution': { value: new three_module/* Vector2 */.I9Y( 1 / 1024, 1 / 512 ) }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[ 3 ];\n\t\tvarying vec2 vPixcoord;\n\n\t\tvoid SMAABlendingWeightCalculationVS( vec2 texcoord ) {\n\t\t\tvPixcoord = texcoord / resolution;\n\n\t\t\t// We will use these offsets for the searches later on (see @PSEUDO_GATHER4):\n\t\t\tvOffset[ 0 ] = texcoord.xyxy + resolution.xyxy * vec4( -0.25, 0.125, 1.25, 0.125 ); // WebGL port note: Changed sign in Y and W components\n\t\t\tvOffset[ 1 ] = texcoord.xyxy + resolution.xyxy * vec4( -0.125, 0.25, -0.125, -1.25 ); // WebGL port note: Changed sign in Y and W components\n\n\t\t\t// And these for the searches, they indicate the ends of the loops:\n\t\t\tvOffset[ 2 ] = vec4( vOffset[ 0 ].xz, vOffset[ 1 ].yw ) + vec4( -2.0, 2.0, -2.0, 2.0 ) * resolution.xxyy * float( SMAA_MAX_SEARCH_STEPS );\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\n\t\t\tSMAABlendingWeightCalculationVS( vUv );\n\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\n\t\t#define SMAASampleLevelZeroOffset( tex, coord, offset ) texture2D( tex, coord + float( offset ) * resolution, 0.0 )\n\n\t\tuniform sampler2D tDiffuse;\n\t\tuniform sampler2D tArea;\n\t\tuniform sampler2D tSearch;\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[3];\n\t\tvarying vec2 vPixcoord;\n\n\t\t#if __VERSION__ == 100\n\t\tvec2 round( vec2 x ) {\n\t\t\treturn sign( x ) * floor( abs( x ) + 0.5 );\n\t\t}\n\t\t#endif\n\n\t\tfloat SMAASearchLength( sampler2D searchTex, vec2 e, float bias, float scale ) {\n\t\t\t// Not required if searchTex accesses are set to point:\n\t\t\t// float2 SEARCH_TEX_PIXEL_SIZE = 1.0 / float2(66.0, 33.0);\n\t\t\t// e = float2(bias, 0.0) + 0.5 * SEARCH_TEX_PIXEL_SIZE +\n\t\t\t// e * float2(scale, 1.0) * float2(64.0, 32.0) * SEARCH_TEX_PIXEL_SIZE;\n\t\t\te.r = bias + e.r * scale;\n\t\t\treturn 255.0 * texture2D( searchTex, e, 0.0 ).r;\n\t\t}\n\n\t\tfloat SMAASearchXLeft( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {\n\t\t\t/**\n\t\t\t\t* @PSEUDO_GATHER4\n\t\t\t\t* This texcoord has been offset by (-0.25, -0.125) in the vertex shader to\n\t\t\t\t* sample between edge, thus fetching four edges in a row.\n\t\t\t\t* Sampling with different offsets in each direction allows to disambiguate\n\t\t\t\t* which edges are active from the four fetched ones.\n\t\t\t\t*/\n\t\t\tvec2 e = vec2( 0.0, 1.0 );\n\n\t\t\tfor ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for\n\t\t\t\te = texture2D( edgesTex, texcoord, 0.0 ).rg;\n\t\t\t\ttexcoord -= vec2( 2.0, 0.0 ) * resolution;\n\t\t\t\tif ( ! ( texcoord.x > end && e.g > 0.8281 && e.r == 0.0 ) ) break;\n\t\t\t}\n\n\t\t\t// We correct the previous (-0.25, -0.125) offset we applied:\n\t\t\ttexcoord.x += 0.25 * resolution.x;\n\n\t\t\t// The searches are bias by 1, so adjust the coords accordingly:\n\t\t\ttexcoord.x += resolution.x;\n\n\t\t\t// Disambiguate the length added by the last step:\n\t\t\ttexcoord.x += 2.0 * resolution.x; // Undo last step\n\t\t\ttexcoord.x -= resolution.x * SMAASearchLength(searchTex, e, 0.0, 0.5);\n\n\t\t\treturn texcoord.x;\n\t\t}\n\n\t\tfloat SMAASearchXRight( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {\n\t\t\tvec2 e = vec2( 0.0, 1.0 );\n\n\t\t\tfor ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for\n\t\t\t\te = texture2D( edgesTex, texcoord, 0.0 ).rg;\n\t\t\t\ttexcoord += vec2( 2.0, 0.0 ) * resolution;\n\t\t\t\tif ( ! ( texcoord.x < end && e.g > 0.8281 && e.r == 0.0 ) ) break;\n\t\t\t}\n\n\t\t\ttexcoord.x -= 0.25 * resolution.x;\n\t\t\ttexcoord.x -= resolution.x;\n\t\t\ttexcoord.x -= 2.0 * resolution.x;\n\t\t\ttexcoord.x += resolution.x * SMAASearchLength( searchTex, e, 0.5, 0.5 );\n\n\t\t\treturn texcoord.x;\n\t\t}\n\n\t\tfloat SMAASearchYUp( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {\n\t\t\tvec2 e = vec2( 1.0, 0.0 );\n\n\t\t\tfor ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for\n\t\t\t\te = texture2D( edgesTex, texcoord, 0.0 ).rg;\n\t\t\t\ttexcoord += vec2( 0.0, 2.0 ) * resolution; // WebGL port note: Changed sign\n\t\t\t\tif ( ! ( texcoord.y > end && e.r > 0.8281 && e.g == 0.0 ) ) break;\n\t\t\t}\n\n\t\t\ttexcoord.y -= 0.25 * resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y -= resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y -= 2.0 * resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y += resolution.y * SMAASearchLength( searchTex, e.gr, 0.0, 0.5 ); // WebGL port note: Changed sign\n\n\t\t\treturn texcoord.y;\n\t\t}\n\n\t\tfloat SMAASearchYDown( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {\n\t\t\tvec2 e = vec2( 1.0, 0.0 );\n\n\t\t\tfor ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for\n\t\t\t\te = texture2D( edgesTex, texcoord, 0.0 ).rg;\n\t\t\t\ttexcoord -= vec2( 0.0, 2.0 ) * resolution; // WebGL port note: Changed sign\n\t\t\t\tif ( ! ( texcoord.y < end && e.r > 0.8281 && e.g == 0.0 ) ) break;\n\t\t\t}\n\n\t\t\ttexcoord.y += 0.25 * resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y += resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y += 2.0 * resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y -= resolution.y * SMAASearchLength( searchTex, e.gr, 0.5, 0.5 ); // WebGL port note: Changed sign\n\n\t\t\treturn texcoord.y;\n\t\t}\n\n\t\tvec2 SMAAArea( sampler2D areaTex, vec2 dist, float e1, float e2, float offset ) {\n\t\t\t// Rounding prevents precision errors of bilinear filtering:\n\t\t\tvec2 texcoord = float( SMAA_AREATEX_MAX_DISTANCE ) * round( 4.0 * vec2( e1, e2 ) ) + dist;\n\n\t\t\t// We do a scale and bias for mapping to texel space:\n\t\t\ttexcoord = SMAA_AREATEX_PIXEL_SIZE * texcoord + ( 0.5 * SMAA_AREATEX_PIXEL_SIZE );\n\n\t\t\t// Move to proper place, according to the subpixel offset:\n\t\t\ttexcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;\n\n\t\t\treturn texture2D( areaTex, texcoord, 0.0 ).rg;\n\t\t}\n\n\t\tvec4 SMAABlendingWeightCalculationPS( vec2 texcoord, vec2 pixcoord, vec4 offset[ 3 ], sampler2D edgesTex, sampler2D areaTex, sampler2D searchTex, ivec4 subsampleIndices ) {\n\t\t\tvec4 weights = vec4( 0.0, 0.0, 0.0, 0.0 );\n\n\t\t\tvec2 e = texture2D( edgesTex, texcoord ).rg;\n\n\t\t\tif ( e.g > 0.0 ) { // Edge at north\n\t\t\t\tvec2 d;\n\n\t\t\t\t// Find the distance to the left:\n\t\t\t\tvec2 coords;\n\t\t\t\tcoords.x = SMAASearchXLeft( edgesTex, searchTex, offset[ 0 ].xy, offset[ 2 ].x );\n\t\t\t\tcoords.y = offset[ 1 ].y; // offset[1].y = texcoord.y - 0.25 * resolution.y (@CROSSING_OFFSET)\n\t\t\t\td.x = coords.x;\n\n\t\t\t\t// Now fetch the left crossing edges, two at a time using bilinear\n\t\t\t\t// filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to\n\t\t\t\t// discern what value each edge has:\n\t\t\t\tfloat e1 = texture2D( edgesTex, coords, 0.0 ).r;\n\n\t\t\t\t// Find the distance to the right:\n\t\t\t\tcoords.x = SMAASearchXRight( edgesTex, searchTex, offset[ 0 ].zw, offset[ 2 ].y );\n\t\t\t\td.y = coords.x;\n\n\t\t\t\t// We want the distances to be in pixel units (doing this here allow to\n\t\t\t\t// better interleave arithmetic and memory accesses):\n\t\t\t\td = d / resolution.x - pixcoord.x;\n\n\t\t\t\t// SMAAArea below needs a sqrt, as the areas texture is compressed\n\t\t\t\t// quadratically:\n\t\t\t\tvec2 sqrt_d = sqrt( abs( d ) );\n\n\t\t\t\t// Fetch the right crossing edges:\n\t\t\t\tcoords.y -= 1.0 * resolution.y; // WebGL port note: Added\n\t\t\t\tfloat e2 = SMAASampleLevelZeroOffset( edgesTex, coords, ivec2( 1, 0 ) ).r;\n\n\t\t\t\t// Ok, we know how this pattern looks like, now it is time for getting\n\t\t\t\t// the actual area:\n\t\t\t\tweights.rg = SMAAArea( areaTex, sqrt_d, e1, e2, float( subsampleIndices.y ) );\n\t\t\t}\n\n\t\t\tif ( e.r > 0.0 ) { // Edge at west\n\t\t\t\tvec2 d;\n\n\t\t\t\t// Find the distance to the top:\n\t\t\t\tvec2 coords;\n\n\t\t\t\tcoords.y = SMAASearchYUp( edgesTex, searchTex, offset[ 1 ].xy, offset[ 2 ].z );\n\t\t\t\tcoords.x = offset[ 0 ].x; // offset[1].x = texcoord.x - 0.25 * resolution.x;\n\t\t\t\td.x = coords.y;\n\n\t\t\t\t// Fetch the top crossing edges:\n\t\t\t\tfloat e1 = texture2D( edgesTex, coords, 0.0 ).g;\n\n\t\t\t\t// Find the distance to the bottom:\n\t\t\t\tcoords.y = SMAASearchYDown( edgesTex, searchTex, offset[ 1 ].zw, offset[ 2 ].w );\n\t\t\t\td.y = coords.y;\n\n\t\t\t\t// We want the distances to be in pixel units:\n\t\t\t\td = d / resolution.y - pixcoord.y;\n\n\t\t\t\t// SMAAArea below needs a sqrt, as the areas texture is compressed\n\t\t\t\t// quadratically:\n\t\t\t\tvec2 sqrt_d = sqrt( abs( d ) );\n\n\t\t\t\t// Fetch the bottom crossing edges:\n\t\t\t\tcoords.y -= 1.0 * resolution.y; // WebGL port note: Added\n\t\t\t\tfloat e2 = SMAASampleLevelZeroOffset( edgesTex, coords, ivec2( 0, 1 ) ).g;\n\n\t\t\t\t// Get the area for this direction:\n\t\t\t\tweights.ba = SMAAArea( areaTex, sqrt_d, e1, e2, float( subsampleIndices.x ) );\n\t\t\t}\n\n\t\t\treturn weights;\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tgl_FragColor = SMAABlendingWeightCalculationPS( vUv, vPixcoord, vOffset, tDiffuse, tArea, tSearch, ivec4( 0.0 ) );\n\n\t\t}`\n\n};\n\nconst SMAABlendShader = {\n\n\tname: 'SMAABlendShader',\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'tColor': { value: null },\n\t\t'resolution': { value: new three_module/* Vector2 */.I9Y( 1 / 1024, 1 / 512 ) }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[ 2 ];\n\n\t\tvoid SMAANeighborhoodBlendingVS( vec2 texcoord ) {\n\t\t\tvOffset[ 0 ] = texcoord.xyxy + resolution.xyxy * vec4( -1.0, 0.0, 0.0, 1.0 ); // WebGL port note: Changed sign in W component\n\t\t\tvOffset[ 1 ] = texcoord.xyxy + resolution.xyxy * vec4( 1.0, 0.0, 0.0, -1.0 ); // WebGL port note: Changed sign in W component\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\n\t\t\tSMAANeighborhoodBlendingVS( vUv );\n\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\n\t\tuniform sampler2D tDiffuse;\n\t\tuniform sampler2D tColor;\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[ 2 ];\n\n\t\tvec4 SMAANeighborhoodBlendingPS( vec2 texcoord, vec4 offset[ 2 ], sampler2D colorTex, sampler2D blendTex ) {\n\t\t\t// Fetch the blending weights for current pixel:\n\t\t\tvec4 a;\n\t\t\ta.xz = texture2D( blendTex, texcoord ).xz;\n\t\t\ta.y = texture2D( blendTex, offset[ 1 ].zw ).g;\n\t\t\ta.w = texture2D( blendTex, offset[ 1 ].xy ).a;\n\n\t\t\t// Is there any blending weight with a value greater than 0.0?\n\t\t\tif ( dot(a, vec4( 1.0, 1.0, 1.0, 1.0 )) < 1e-5 ) {\n\t\t\t\treturn texture2D( colorTex, texcoord, 0.0 );\n\t\t\t} else {\n\t\t\t\t// Up to 4 lines can be crossing a pixel (one through each edge). We\n\t\t\t\t// favor blending by choosing the line with the maximum weight for each\n\t\t\t\t// direction:\n\t\t\t\tvec2 offset;\n\t\t\t\toffset.x = a.a > a.b ? a.a : -a.b; // left vs. right\n\t\t\t\toffset.y = a.g > a.r ? -a.g : a.r; // top vs. bottom // WebGL port note: Changed signs\n\n\t\t\t\t// Then we go in the direction that has the maximum weight:\n\t\t\t\tif ( abs( offset.x ) > abs( offset.y )) { // horizontal vs. vertical\n\t\t\t\t\toffset.y = 0.0;\n\t\t\t\t} else {\n\t\t\t\t\toffset.x = 0.0;\n\t\t\t\t}\n\n\t\t\t\t// Fetch the opposite color and lerp by hand:\n\t\t\t\tvec4 C = texture2D( colorTex, texcoord, 0.0 );\n\t\t\t\ttexcoord += sign( offset ) * resolution;\n\t\t\t\tvec4 Cop = texture2D( colorTex, texcoord, 0.0 );\n\t\t\t\tfloat s = abs( offset.x ) > abs( offset.y ) ? abs( offset.x ) : abs( offset.y );\n\n\t\t\t\t// WebGL port note: Added gamma correction\n\t\t\t\tC.xyz = pow(C.xyz, vec3(2.2));\n\t\t\t\tCop.xyz = pow(Cop.xyz, vec3(2.2));\n\t\t\t\tvec4 mixed = mix(C, Cop, s);\n\t\t\t\tmixed.xyz = pow(mixed.xyz, vec3(1.0 / 2.2));\n\n\t\t\t\treturn mixed;\n\t\t\t}\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tgl_FragColor = SMAANeighborhoodBlendingPS( vUv, vOffset, tColor, tDiffuse );\n\n\t\t}`\n\n};\n\n\n\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/postprocessing/SMAAPass.js\n\n\n\n\n\n\nclass SMAAPass extends Pass/* Pass */.o {\n\n\tconstructor( width, height ) {\n\n\t\tsuper();\n\n\t\t// render targets\n\n\t\tthis.edgesRT = new three_module/* WebGLRenderTarget */.nWS( width, height, {\n\t\t\tdepthBuffer: false,\n\t\t\ttype: three_module/* HalfFloatType */.ix0\n\t\t} );\n\t\tthis.edgesRT.texture.name = 'SMAAPass.edges';\n\n\t\tthis.weightsRT = new three_module/* WebGLRenderTarget */.nWS( width, height, {\n\t\t\tdepthBuffer: false,\n\t\t\ttype: three_module/* HalfFloatType */.ix0\n\t\t} );\n\t\tthis.weightsRT.texture.name = 'SMAAPass.weights';\n\n\t\t// textures\n\t\tconst scope = this;\n\n\t\tconst areaTextureImage = new Image();\n\t\tareaTextureImage.src = this.getAreaTexture();\n\t\tareaTextureImage.onload = function () {\n\n\t\t\t// assigning data to HTMLImageElement.src is asynchronous (see #15162)\n\t\t\tscope.areaTexture.needsUpdate = true;\n\n\t\t};\n\n\t\tthis.areaTexture = new three_module/* Texture */.gPd();\n\t\tthis.areaTexture.name = 'SMAAPass.area';\n\t\tthis.areaTexture.image = areaTextureImage;\n\t\tthis.areaTexture.minFilter = three_module/* LinearFilter */.k6q;\n\t\tthis.areaTexture.generateMipmaps = false;\n\t\tthis.areaTexture.flipY = false;\n\n\t\tconst searchTextureImage = new Image();\n\t\tsearchTextureImage.src = this.getSearchTexture();\n\t\tsearchTextureImage.onload = function () {\n\n\t\t\t// assigning data to HTMLImageElement.src is asynchronous (see #15162)\n\t\t\tscope.searchTexture.needsUpdate = true;\n\n\t\t};\n\n\t\tthis.searchTexture = new three_module/* Texture */.gPd();\n\t\tthis.searchTexture.name = 'SMAAPass.search';\n\t\tthis.searchTexture.image = searchTextureImage;\n\t\tthis.searchTexture.magFilter = three_module/* NearestFilter */.hxR;\n\t\tthis.searchTexture.minFilter = three_module/* NearestFilter */.hxR;\n\t\tthis.searchTexture.generateMipmaps = false;\n\t\tthis.searchTexture.flipY = false;\n\n\t\t// materials - pass 1\n\n\t\tthis.uniformsEdges = three_module/* UniformsUtils */.LlO.clone( SMAAEdgesShader.uniforms );\n\n\t\tthis.uniformsEdges[ 'resolution' ].value.set( 1 / width, 1 / height );\n\n\t\tthis.materialEdges = new three_module/* ShaderMaterial */.BKk( {\n\t\t\tdefines: Object.assign( {}, SMAAEdgesShader.defines ),\n\t\t\tuniforms: this.uniformsEdges,\n\t\t\tvertexShader: SMAAEdgesShader.vertexShader,\n\t\t\tfragmentShader: SMAAEdgesShader.fragmentShader\n\t\t} );\n\n\t\t// materials - pass 2\n\n\t\tthis.uniformsWeights = three_module/* UniformsUtils */.LlO.clone( SMAAWeightsShader.uniforms );\n\n\t\tthis.uniformsWeights[ 'resolution' ].value.set( 1 / width, 1 / height );\n\t\tthis.uniformsWeights[ 'tDiffuse' ].value = this.edgesRT.texture;\n\t\tthis.uniformsWeights[ 'tArea' ].value = this.areaTexture;\n\t\tthis.uniformsWeights[ 'tSearch' ].value = this.searchTexture;\n\n\t\tthis.materialWeights = new three_module/* ShaderMaterial */.BKk( {\n\t\t\tdefines: Object.assign( {}, SMAAWeightsShader.defines ),\n\t\t\tuniforms: this.uniformsWeights,\n\t\t\tvertexShader: SMAAWeightsShader.vertexShader,\n\t\t\tfragmentShader: SMAAWeightsShader.fragmentShader\n\t\t} );\n\n\t\t// materials - pass 3\n\n\t\tthis.uniformsBlend = three_module/* UniformsUtils */.LlO.clone( SMAABlendShader.uniforms );\n\n\t\tthis.uniformsBlend[ 'resolution' ].value.set( 1 / width, 1 / height );\n\t\tthis.uniformsBlend[ 'tDiffuse' ].value = this.weightsRT.texture;\n\n\t\tthis.materialBlend = new three_module/* ShaderMaterial */.BKk( {\n\t\t\tuniforms: this.uniformsBlend,\n\t\t\tvertexShader: SMAABlendShader.vertexShader,\n\t\t\tfragmentShader: SMAABlendShader.fragmentShader\n\t\t} );\n\n\t\tthis.fsQuad = new Pass/* FullScreenQuad */.F( null );\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) {\n\n\t\t// pass 1\n\n\t\tthis.uniformsEdges[ 'tDiffuse' ].value = readBuffer.texture;\n\n\t\tthis.fsQuad.material = this.materialEdges;\n\n\t\trenderer.setRenderTarget( this.edgesRT );\n\t\tif ( this.clear ) renderer.clear();\n\t\tthis.fsQuad.render( renderer );\n\n\t\t// pass 2\n\n\t\tthis.fsQuad.material = this.materialWeights;\n\n\t\trenderer.setRenderTarget( this.weightsRT );\n\t\tif ( this.clear ) renderer.clear();\n\t\tthis.fsQuad.render( renderer );\n\n\t\t// pass 3\n\n\t\tthis.uniformsBlend[ 'tColor' ].value = readBuffer.texture;\n\n\t\tthis.fsQuad.material = this.materialBlend;\n\n\t\tif ( this.renderToScreen ) {\n\n\t\t\trenderer.setRenderTarget( null );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t} else {\n\n\t\t\trenderer.setRenderTarget( writeBuffer );\n\t\t\tif ( this.clear ) renderer.clear();\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t}\n\n\t}\n\n\tsetSize( width, height ) {\n\n\t\tthis.edgesRT.setSize( width, height );\n\t\tthis.weightsRT.setSize( width, height );\n\n\t\tthis.materialEdges.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height );\n\t\tthis.materialWeights.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height );\n\t\tthis.materialBlend.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height );\n\n\t}\n\n\tgetAreaTexture() {\n\n\t\treturn 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAIwCAIAAACOVPcQAACBeklEQVR42u39W4xlWXrnh/3WWvuciIzMrKxrV8/0rWbY0+SQFKcb4owIkSIFCjY9AC1BT/LYBozRi+EX+cV+8IMsYAaCwRcBwjzMiw2jAWtgwC8WR5Q8mDFHZLNHTarZGrLJJllt1W2qKrsumZWZcTvn7L3W54e1vrXX3vuciLPPORFR1XE2EomorB0nVuz//r71re/y/1eMvb4Cb3N11xV/PP/2v4UBAwJG/7H8urx6/25/Gf8O5hypMQ0EEEQwAqLfoN/Z+97f/SW+/NvcgQk4sGBJK6H7N4PFVL+K+e0N11yNfkKvwUdwdlUAXPHHL38oa15f/i/46Ih6SuMSPmLAYAwyRKn7dfMGH97jaMFBYCJUgotIC2YAdu+LyW9vvubxAP8kAL8H/koAuOKP3+q6+xGnd5kdYCeECnGIJViwGJMAkQKfDvB3WZxjLKGh8VSCCzhwEWBpMc5/kBbjawT4HnwJfhr+pPBIu7uu+OOTo9vsmtQcniMBGkKFd4jDWMSCRUpLjJYNJkM+IRzQ+PQvIeAMTrBS2LEiaiR9b/5PuT6Ap/AcfAFO4Y3dA3DFH7/VS+M8k4baEAQfMI4QfbVDDGIRg7GKaIY52qAjTAgTvGBAPGIIghOCYAUrGFNgzA7Q3QhgCwfwAnwe5vDejgG44o/fbm1C5ZlYQvQDARPAIQGxCWBM+wWl37ZQESb4gImexGMDouhGLx1Cst0Saa4b4AqO4Hk4gxo+3DHAV/nx27p3JziPM2pVgoiia5MdEzCGULprIN7gEEeQ5IQxEBBBQnxhsDb5auGmAAYcHMA9eAAz8PBol8/xij9+C4Djlim4gJjWcwZBhCBgMIIYxGAVIkH3ZtcBuLdtRFMWsPGoY9rN+HoBji9VBYdwD2ZQg4cnO7OSq/z4rU5KKdwVbFAjNojCQzTlCLPFSxtamwh2jMUcEgg2Wm/6XgErIBhBckQtGN3CzbVacERgCnfgLswhnvqf7QyAq/z4rRZm1YglYE3affGITaZsdIe2FmMIpnOCap25I6jt2kCwCW0D1uAD9sZctNGXcQIHCkINDQgc78aCr+zjtw3BU/ijdpw3zhCwcaONwBvdeS2YZKkJNJsMPf2JKEvC28RXxxI0ASJyzQCjCEQrO4Q7sFArEzjZhaFc4cdv+/JFdKULM4px0DfUBI2hIsy06BqLhGTQEVdbfAIZXYMPesq6VoCHICzUyjwInO4Y411//LYLs6TDa9wvg2CC2rElgAnpTBziThxaL22MYhzfkghz6GAs2VHbbdM91VZu1MEEpupMMwKyVTb5ij9+u4VJG/5EgEMMmFF01cFai3isRbKbzb+YaU/MQbAm2XSMoUPAmvZzbuKYRIFApbtlrfFuUGd6vq2hXNnH78ZLh/iFhsQG3T4D1ib7k5CC6vY0DCbtrohgLEIClXiGtl10zc0CnEGIhhatLBva7NP58Tvw0qE8yWhARLQ8h4+AhQSP+I4F5xoU+VilGRJs6wnS7ruti/4KvAY/CfdgqjsMy4pf8fodQO8/gnuX3f/3xi3om1/h7THr+co3x93PP9+FBUfbNUjcjEmhcrkT+8K7ml7V10Jo05mpIEFy1NmCJWx9SIKKt+EjAL4Ez8EBVOB6havuT/rByPvHXK+9zUcfcbb254+9fydJknYnRr1oGfdaiAgpxu1Rx/Rek8KISftx3L+DfsLWAANn8Hvw0/AFeAGO9DFV3c6D+CcWbL8Dj9e7f+T1k8AZv/d7+PXWM/Z+VvdCrIvuAKO09RpEEQJM0Ci6+B4xhTWr4cZNOvhktabw0ta0rSJmqz3Yw5/AKXwenod7cAhTmBSPKf6JBdvH8IP17h95pXqw50/+BFnj88fev4NchyaK47OPhhtI8RFSvAfDSNh0Ck0p2gLxGkib5NJj/JWCr90EWQJvwBzO4AHcgztwAFN1evHPUVGwfXON+0debT1YeGON9Yy9/63X+OguiwmhIhQhD7l4sMqlG3D86Suc3qWZ4rWjI1X7u0Ytw6x3rIMeIOPDprfe2XzNgyj6PahhBjO4C3e6puDgXrdg+/5l948vF3bqwZetZ+z9Rx9zdIY5pInPK4Nk0t+l52xdK2B45Qd87nM8fsD5EfUhIcJcERw4RdqqH7Yde5V7m1vhNmtedkz6EDzUMF/2jJYWbC+4fzzA/Y+/8PPH3j9dcBAPIRP8JLXd5BpAu03aziOL3VVHZzz3CXWDPWd+SH2AnxIqQoTZpo9Ckc6HIrFbAbzNmlcg8Ag8NFDDAhbJvTBZXbC94P7t68EXfv6o+21gUtPETU7bbkLxvNKRFG2+KXzvtObonPP4rBvsgmaKj404DlshFole1Glfh02fE7bYR7dZ82oTewIBGn1Md6CG6YUF26X376oevOLzx95vhUmgblI6LBZwTCDY7vMq0op5WVXgsObOXJ+1x3qaBl9j1FeLxbhU9w1F+Wiba6s1X/TBz1LnUfuYDi4r2C69f1f14BWfP+p+W2GFKuC9phcELMYRRLur9DEZTUdEH+iEqWdaM7X4WOoPGI+ZYD2+wcQ+y+ioHUZ9dTDbArzxmi/bJI9BND0Ynd6lBdve/butBw8+f/T9D3ABa3AG8W3VPX4hBin+bj8dMMmSpp5pg7fJ6xrBFE2WQQEWnV8Qg3FbAWzYfM1rREEnmvkN2o1+acG2d/9u68GDzx91v3mAjb1zkpqT21OipPKO0b9TO5W0nTdOmAQm0TObts3aBKgwARtoPDiCT0gHgwnbArzxmtcLc08HgF1asN0C4Ms/fvD5I+7PhfqyXE/b7RbbrGyRQRT9ARZcwAUmgdoz0ehJ9Fn7QAhUjhDAQSw0bV3T3WbNa59jzmiP6GsWbGXDX2ytjy8+f9T97fiBPq9YeLdBmyuizZHaqXITnXiMUEEVcJ7K4j3BFPurtB4bixW8wTpweL8DC95szWMOqucFYGsWbGU7p3TxxxefP+r+oTVktxY0v5hbq3KiOKYnY8ddJVSBxuMMVffNbxwIOERShst73HZ78DZrHpmJmH3K6sGz0fe3UUj0eyRrSCGTTc+rjVNoGzNSv05srAxUBh8IhqChiQgVNIIBH3AVPnrsnXQZbLTm8ammv8eVXn/vWpaTem5IXRlt+U/LA21zhSb9cye6jcOfCnOwhIAYXAMVTUNV0QhVha9xjgA27ODJbLbmitt3tRN80lqG6N/khgot4ZVlOyO4WNg3OIMzhIZQpUEHieg2im6F91hB3I2tubql6BYNN9Hj5S7G0G2tahslBWKDnOiIvuAEDzakDQKDNFQT6gbn8E2y4BBubM230YIpBnDbMa+y3dx0n1S0BtuG62lCCXwcY0F72T1VRR3t2ONcsmDjbmzNt9RFs2LO2hQNyb022JisaI8rAWuw4HI3FuAIhZdOGIcdjLJvvObqlpqvWTJnnQbyi/1M9O8UxWhBs//H42I0q1Yb/XPGONzcmm+ri172mHKvZBpHkJaNJz6v9jxqiklDj3U4CA2ugpAaYMWqNXsdXbmJNd9egCnJEsphXNM+MnK3m0FCJ5S1kmJpa3DgPVbnQnPGWIDspW9ozbcO4K/9LkfaQO2KHuqlfFXSbdNzcEcwoqNEFE9zcIXu9/6n/ym/BC/C3aJLzEKPuYVlbFnfhZ8kcWxV3dbv4bKl28566wD+8C53aw49lTABp9PWbsB+knfc/Li3eVizf5vv/xmvnPKg5ihwKEwlrcHqucuVcVOxEv8aH37E3ZqpZypUulrHEtIWKUr+txHg+ojZDGlwnqmkGlzcVi1dLiNSJiHjfbRNOPwKpx9TVdTn3K05DBx4psIk4Ei8aCkJahRgffk4YnEXe07T4H2RR1u27E6wfQsBDofUgjFUFnwC2AiVtA+05J2zpiDK2Oa0c5fmAecN1iJzmpqFZxqYBCYhFTCsUNEmUnIcZ6aEA5rQVhEywG6w7HSW02XfOoBlQmjwulOFQAg66SvJblrTEX1YtJ3uG15T/BH1OfOQeuR8g/c0gdpT5fx2SKbs9EfHTKdM8A1GaJRHLVIwhcGyydZsbifAFVKl5EMKNU2Hryo+06BeTgqnxzYjThVySDikbtJPieco75lYfKAJOMEZBTjoITuWHXXZVhcUDIS2hpiXHV9Ku4u44bN5OYLDOkJo8w+xJSMbhBRHEdEs9JZUCkQrPMAvaHyLkxgkEHxiNkx/x2YB0mGsQ8EUWj/stW5YLhtS5SMu+/YBbNPDCkGTUybN8krRLBGPlZkVOA0j+a1+rkyQKWGaPHPLZOkJhioQYnVZ2hS3zVxMtgC46KuRwbJNd9nV2PHgb36F194ecf/Yeu2vAFe5nm/bRBFrnY4BauE8ERmZRFUn0k8hbftiVYSKMEme2dJCJSCGYAlNqh87bXOPdUkGy24P6d1ll21MBqqx48Fvv8ZHH8HZFY7j/uAq1xMJUFqCSUlJPmNbIiNsmwuMs/q9CMtsZsFO6SprzCS1Z7QL8xCQClEelpjTduDMsmWD8S1PT152BtvmIGvUeDA/yRn83u/x0/4qxoPHjx+PXY9pqX9bgMvh/Nz9kpP4pOe1/fYf3axUiMdHLlPpZCNjgtNFAhcHEDxTumNONhHrBduW+vOyY++70WWnPXj98eA4kOt/mj/5E05l9+O4o8ePx67HFqyC+qSSnyselqjZGaVK2TadbFLPWAQ4NBhHqDCCV7OTpo34AlSSylPtIdd2AJZlyzYQrDJ5lcWGNceD80CunPLGGzsfD+7wRb95NevJI5docQ3tgCyr5bGnyaPRlmwNsFELViOOx9loebGNq2moDOKpHLVP5al2cymWHbkfzGXL7kfRl44H9wZy33tvt+PB/Xnf93e+nh5ZlU18wCiRUa9m7kib9LYuOk+hudQNbxwm0AQqbfloimaB2lM5fChex+ylMwuTbfmXQtmWlenZljbdXTLuOxjI/fDDHY4Hjx8/Hrse0zXfPFxbUN1kKqSCCSk50m0Ajtx3ub9XHBKHXESb8iO6E+qGytF4nO0OG3SXzbJlhxBnKtKyl0NwybjvYCD30aMdjgePHz8eu56SVTBbgxJMliQ3Oauwg0QHxXE2Ez/EIReLdQj42Gzb4CLS0YJD9xUx7bsi0vJi5mUbW1QzL0h0PFk17rtiIPfJk52MB48fPx67npJJwyrBa2RCCQRTbGZSPCxTPOiND4G2pYyOQ4h4jINIJh5wFU1NFZt+IsZ59LSnDqBjZ2awbOku+yInunLcd8VA7rNnOxkPHj9+PGY9B0MWJJNozOJmlglvDMXDEozdhQWbgs/U6oBanGzLrdSNNnZFjOkmbi5bNt1lX7JLLhn3vXAg9/h4y/Hg8ePHI9dzQMEkWCgdRfYykYKnkP7D4rIujsujaKPBsB54vE2TS00ccvFY/Tth7JXeq1hz+qgVy04sAJawTsvOknHfCwdyT062HA8eP348Zj0vdoXF4pilKa2BROed+9fyw9rWRXeTFXESMOanvDZfJuJaSXouQdMdDJZtekZcLLvEeK04d8m474UDuaenW44Hjx8/Xns9YYqZpszGWB3AN/4VHw+k7WSFtJ3Qicuqb/NlVmgXWsxh570xg2UwxUw3WfO6B5nOuO8aA7lnZxuPB48fPx6znm1i4bsfcbaptF3zNT78eFPtwi1OaCNOqp1x3zUGcs/PN++AGD1+fMXrSVm2baTtPhPahbPhA71wIHd2bXzRa69nG+3CraTtPivahV/55tXWg8fyRY/9AdsY8VbSdp8V7cKrrgdfM//z6ILQFtJ2nxHtwmuoB4/kf74+gLeRtvvMaBdeSz34+vifx0YG20jbfTa0C6+tHrwe//NmOG0L8EbSdp8R7cLrrQe/996O+ai3ujQOskpTNULa7jOjXXj99eCd8lHvoFiwsbTdZ0a78PrrwTvlo966pLuRtB2fFe3Cm6oHP9kNH/W2FryxtN1nTLvwRurBO+Kj3pWXHidtx2dFu/Bm68Fb81HvykuPlrb7LGkX3mw9eGs+6h1Y8MbSdjegXcguQLjmevDpTQLMxtJ2N6NdyBZu9AbrwVvwUW+LbteULUpCdqm0HTelXbhNPe8G68Gb8lFvVfYfSNuxvrTdTWoXbozAzdaDZzfkorOj1oxVxlIMlpSIlpLrt8D4hrQL17z+c3h6hU/wv4Q/utps4+bm+6P/hIcf0JwQ5oQGPBL0eKPTYEXTW+eL/2DKn73J9BTXYANG57hz1cEMviVf/4tf5b/6C5pTQkMIWoAq7hTpOJjtAM4pxKu5vg5vXeUrtI09/Mo/5H+4z+Mp5xULh7cEm2QbRP2tFIKR7WM3fPf/jZ3SWCqLM2l4NxID5zB72HQXv3jj/8mLR5xXNA5v8EbFQEz7PpRfl1+MB/hlAN65qgDn3wTgH13hK7T59bmP+NIx1SHHU84nLOITt3iVz8mNO+lPrjGAnBFqmioNn1mTyk1ta47R6d4MrX7tjrnjYUpdUbv2rVr6YpVfsGG58AG8Ah9eyUN8CX4WfgV+G8LVWPDGb+Zd4cU584CtqSbMKxauxTg+dyn/LkVgA+IR8KHtejeFKRtTmLLpxN6mYVLjYxwXf5x2VofiZcp/lwKk4wGOpYDnoIZPdg/AAbwMfx0+ge9dgZvYjuqKe4HnGnykYo5TvJbG0Vj12JagRhwKa44H95ShkZa5RyLGGdfYvG7aw1TsF6iapPAS29mNS3NmsTQZCmgTzFwgL3upCTgtBTRwvGMAKrgLn4evwin8+afJRcff+8izUGUM63GOOuAs3tJkw7J4kyoNreqrpO6cYLQeFUd7TTpr5YOTLc9RUUogUOVJQ1GYJaFLAW0oTmKyYS46ZooP4S4EON3xQ5zC8/CX4CnM4c1PE8ApexpoYuzqlP3d4S3OJP8ZDK7cKWNaTlqmgDiiHwl1YsE41w1zT4iRTm3DBqxvOUsbMKKDa/EHxagtnta072ejc3DOIh5ojvh8l3tk1JF/AV6FU6jh3U8HwEazLgdCLYSQ+MYiAI2ltomkzttUb0gGHdSUUgsIYjTzLG3mObX4FBRaYtpDVNZrih9TgTeYOBxsEnN1gOCTM8Bsw/ieMc75w9kuAT6A+/AiHGvN/+Gn4KRkiuzpNNDYhDGFndWRpE6SVfm8U5bxnSgVV2jrg6JCKmneqey8VMFgq2+AM/i4L4RUbfSi27lNXZ7R7W9RTcq/q9fk4Xw3AMQd4I5ifAZz8FcVtm9SAom/dyN4lczJQW/kC42ZrHgcCoIf1oVMKkVItmMBi9cOeNHGLqOZk+QqQmrbc5YmYgxELUUN35z2iohstgfLIFmcMV7s4CFmI74L9+EFmGsi+tGnAOD4Yk9gIpo01Y4cA43BWGygMdr4YZekG3OBIUXXNukvJS8tqa06e+lSDCtnqqMFu6hWHXCF+WaYt64m9QBmNxi7Ioy7D+fa1yHw+FMAcPt7SysFLtoG4PXAk7JOA3aAxBRqUiAdU9Yp5lK3HLSRFtOim0sa8euEt08xvKjYjzeJ2GU7YawexrnKI9tmobInjFXCewpwriY9+RR4aaezFhMhGCppKwom0ChrgFlKzyPKkGlTW1YQrE9HJqu8hKGgMc6hVi5QRq0PZxNfrYNgE64utmRv6KKHRpxf6VDUaOvNP5jCEx5q185My/7RKz69UQu2im5k4/eownpxZxNLwiZ1AZTO2ZjWjkU9uaB2HFn6Q3u0JcsSx/qV9hTEApRzeBLDJQXxYmTnq7bdLa3+uqFrxLJ5w1TehnNHx5ECvCh2g2c3hHH5YsfdaSKddztfjQ6imKFGSyFwlLzxEGPp6r5IevVjk1AMx3wMqi1NxDVjLBiPs9tbsCkIY5we5/ML22zrCScFxnNtzsr9Wcc3CnD+pYO+4VXXiDE0oc/vQQ/fDK3oPESJMYXNmJa/DuloJZkcTpcYE8lIH8Dz8DJMiynNC86Mb2lNaaqP/+L7f2fcE/yP7/Lde8xfgSOdMxvOixZf/9p3+M4hT1+F+zApxg9XfUvYjc8qX2lfOOpK2gNRtB4flpFu9FTKCp2XJRgXnX6olp1zyYjTKJSkGmLE2NjUr1bxFM4AeAAHBUFIeSLqXR+NvH/M9fOnfHzOD2vCSyQJKzfgsCh+yi/Mmc35F2fUrw7miW33W9hBD1vpuUojFphIyvg7aTeoymDkIkeW3XLHmguMzbIAJejN6B5MDrhipE2y6SoFRO/AK/AcHHZHNIfiWrEe/C6cr3f/yOvrQKB+zMM55/GQdLDsR+ifr5Fiuu+/y+M78LzOE5dsNuXC3PYvYWd8NXvphLSkJIasrlD2/HOqQ+RjcRdjKTGWYhhVUm4yxlyiGPuMsZR7sMCHUBeTuNWA7if+ifXgc/hovftHXs/DV+Fvwe+f8shzMiMcweFgBly3//vwJfg5AN4450fn1Hd1Rm1aBLu22Dy3y3H2+OqMemkbGZ4jozcDjJf6596xOLpC0eMTHbKnxLxH27uZ/bMTGs2jOaMOY4m87CfQwF0dw53oa1k80JRuz/XgS+8fX3N9Af4qPIMfzKgCp4H5TDGe9GGeFPzSsZz80SlPTxXjgwJmC45njzgt2vbQ4b4OAdUK4/vWhO8d8v6EE8fMUsfakXbPpFJeLs2ubM/qdm/la3WP91uWhxXHjoWhyRUq2iJ/+5mA73zwIIo+LoZ/SgvIRjAd1IMvvn98PfgOvAJfhhm8scAKVWDuaRaK8aQ9f7vuPDH6Bj47ZXau7rqYJ66mTDwEDU6lLbCjCK0qTXyl5mnDoeNRxanj3FJbaksTk0faXxHxLrssgPkWB9LnA/MFleXcJozzjwsUvUG0X/QCve51qkMDXp9mtcyOy3rwBfdvVJK7D6/ACSzg3RoruIq5UDeESfEmVclDxnniU82vxMLtceD0hGZWzBNPMM/jSPne2OVatiTKUpY5vY7gc0LdUAWeWM5tH+O2I66AOWw9xT2BuyRVLGdoDHUsVRXOo/c+ZdRXvFfnxWyIV4upFLCl9eAL7h8Zv0QH8Ry8pA2cHzQpGesctVA37ZtklBTgHjyvdSeKY/RZw/kJMk0Y25cSNRWSigQtlULPTw+kzuJPeYEkXjQRpoGZobYsLF79pyd1dMRHInbgFTZqNLhDqiIsTNpoex2WLcy0/X6rHcdMMQvFSd5dWA++4P7xv89deACnmr36uGlL69bRCL6BSZsS6c0TU2TKK5gtWCzgAOOwQcurqk9j8whvziZSMLcq5hbuwBEsYjopUBkqw1yYBGpLA97SRElEmx5MCInBY5vgLk94iKqSWmhIGmkJ4Bi9m4L645J68LyY4wsFYBfUg5feP/6gWWm58IEmKQM89hq7KsZNaKtP5TxxrUZZVkNmMJtjbKrGxLNEbHPJxhqy7lAmbC32ZqeF6lTaknRWcYaFpfLUBh/rwaQycCCJmW15Kstv6jRHyJFry2C1ahkkIW0LO75s61+owxK1y3XqweX9m5YLM2DPFeOjn/iiqCKJ+yKXF8t5Yl/kNsqaSCryxPq5xWTFIaP8KSW0RYxqupaUf0RcTNSSdJZGcKYdYA6kdtrtmyBckfKXwqk0pHpUHlwWaffjNRBYFPUDWa8e3Lt/o0R0CdisKDM89cX0pvRHEfM8ca4t0s2Xx4kgo91MPQJ/0c9MQYq0co8MBh7bz1fio0UUHLR4aAIOvOmoYO6kwlEVODSSTliWtOtH6sPkrtctF9ZtJ9GIerBskvhdVS5cFNv9s1BU0AbdUgdK4FG+dRnjFmDTzniRMdZO1QhzMK355vigbdkpz9P6qjUGE5J2qAcXmwJ20cZUiAD0z+pGMx6xkzJkmEf40Hr4qZfVg2XzF9YOyoV5BjzVkUJngKf8lgNYwKECEHrCNDrWZzMlflS3yBhr/InyoUgBc/lKT4pxVrrC6g1YwcceK3BmNxZcAtz3j5EIpqguh9H6wc011YN75cKDLpFDxuwkrPQmUwW4KTbj9mZTwBwLq4aQMUZbHm1rylJ46dzR0dua2n3RYCWZsiHROeywyJGR7mXKlpryyCiouY56sFkBWEnkEB/raeh/Sw4162KeuAxMQpEkzy5alMY5wamMsWKKrtW2WpEWNnReZWONKWjrdsKZarpFjqCslq773PLmEhM448Pc3+FKr1+94vv/rfw4tEcu+lKTBe4kZSdijBrykwv9vbCMPcLQTygBjzVckSLPRVGslqdunwJ4oegtFOYb4SwxNgWLCmD7T9kVjTv5YDgpo0XBmN34Z/rEHp0sgyz7lngsrm4lvMm2Mr1zNOJYJ5cuxuQxwMGJq/TP5emlb8fsQBZviK4t8hFL+zbhtlpwaRSxQRWfeETjuauPsdGxsBVdO7nmP4xvzSoT29pRl7kGqz+k26B3Oy0YNV+SXbbQas1ctC/GarskRdFpKczVAF1ZXnLcpaMuzVe6lZ2g/1ndcvOVgRG3sdUAY1bKD6achijMPdMxV4muKVorSpiDHituH7rSTs7n/4y5DhRXo4FVBN4vO/zbAcxhENzGbHCzU/98Mcx5e7a31kWjw9FCe/zNeYyQjZsWb1uc7U33pN4Mji6hCLhivqfa9Ss6xLg031AgfesA/l99m9fgvnaF9JoE6bYKmkGNK3aPbHB96w3+DnxFm4hs0drLsk7U8kf/N/CvwQNtllna0rjq61sH8L80HAuvwH1tvBy2ChqWSCaYTaGN19sTvlfzFD6n+iKTbvtayfrfe9ueWh6GJFoxLdr7V72a5ZpvHcCPDzma0wTO4EgbLyedxstO81n57LYBOBzyfsOhUKsW1J1BB5vr/tz8RyqOFylQP9Tvst2JALsC5lsH8PyQ40DV4ANzYa4dedNiKNR1s+x2wwbR7q4/4cTxqEk4LWDebfisuo36JXLiWFjOtLrlNWh3K1rRS4xvHcDNlFnNmWBBAl5SWaL3oPOfnvbr5pdjVnEaeBJSYjuLEkyLLsWhKccadmOphZkOPgVdalj2QpSmfOsADhMWE2ZBu4+EEJI4wKTAuCoC4xwQbWXBltpxbjkXJtKxxabo9e7tyhlgb6gNlSbUpMh+l/FaqzVwewGu8BW1Zx7pTpQDJUjb8tsUTW6+GDXbMn3mLbXlXJiGdggxFAoUrtPS3wE4Nk02UZG2OOzlk7fRs7i95QCLo3E0jtrjnM7SR3uS1p4qtS2nJ5OwtQVHgOvArLBFijZUV9QtSl8dAY5d0E0hM0w3HS2DpIeB6m/A1+HfhJcGUq4sOxH+x3f5+VO+Ds9rYNI7zPXOYWPrtf8bYMx6fuOAX5jzNR0PdsuON+X1f7EERxMJJoU6GkTEWBvVolVlb5lh3tKCg6Wx1IbaMDdJ+9sUCc5KC46hKGCk3IVOS4TCqdBNfUs7Kd4iXf2RjnT/LLysJy3XDcHLh/vde3x8DoGvwgsa67vBk91G5Pe/HbOe7xwym0NXbtiuuDkGO2IJDh9oQvJ4cY4vdoqLDuoH9Zl2F/ofsekn8lkuhIlhQcffUtSjytFyp++p6NiE7Rqx/lodgKVoceEp/CP4FfjrquZaTtj2AvH5K/ywpn7M34K/SsoYDAdIN448I1/0/wveW289T1/lX5xBzc8N5IaHr0XMOQdHsIkDuJFifj20pBm5jzwUv9e2FhwRsvhAbalCIuIw3bhJihY3p6nTFFIZgiSYjfTf3aXuOjmeGn4bPoGvwl+CFzTRczBIuHBEeImHc37/lGfwZR0cXzVDOvaKfNHvwe+suZ771K/y/XcBlsoN996JpBhoE2toYxOznNEOS5TJc6Id5GEXLjrWo+LEWGNpPDU4WAwsIRROu+1vM+0oW37z/MBN9kqHnSArwPfgFJ7Cq/Ai3Ie7g7ncmI09v8sjzw9mzOAEXoIHxURueaAce5V80f/DOuuZwHM8vsMb5wBzOFWM7wymTXPAEvm4vcFpZ2ut0VZRjkiP2MlmLd6DIpbGSiHOjdnUHN90hRYmhTnmvhzp1iKDNj+b7t5hi79lWGwQ+HN9RsfFMy0FXbEwhfuczKgCbyxYwBmcFhhvo/7a44v+i3XWcwDP86PzpGQYdWh7csP5dBvZ1jNzdxC8pBGuxqSW5vw40nBpj5JhMwvOzN0RWqERHMr4Lv1kWX84xLR830G3j6yqZ1a8UstTlW+qJPOZ+sZ7xZPKTJLhiNOAFd6tk+jrTH31ncLOxid8+nzRb128HhUcru/y0Wn6iT254YPC6FtVSIMoW2sk727AhvTtrWKZTvgsmckfXYZWeNRXx/3YQ2OUxLDrbHtN11IwrgXT6c8dATDwLniYwxzO4RzuQqTKSC5gAofMZ1QBK3zQ4JWobFbcvJm87FK+6JXrKahLn54m3p+McXzzYtP8VF/QpJuh1OwieElEoI1pRxPS09FBrkq2tWCU59+HdhNtTIqKm8EBrw2RTOEDpG3IKo2Y7mFdLm3ZeVjYwVw11o/oznceMve4CgMfNym/utA/d/ILMR7gpXzRy9eDsgLcgbs8O2Va1L0zzIdwGGemTBuwROHeoMShkUc7P+ISY3KH5ZZeWqO8mFTxQYeXTNuzvvK5FGPdQfuu00DwYFY9dyhctEt+OJDdnucfpmyhzUJzfsJjr29l8S0bXBfwRS9ZT26tmMIdZucch5ZboMz3Nio3nIOsYHCGoDT4kUA9MiXEp9Xsui1S8th/kbWIrMBxDGLodWUQIWcvnXy+9M23xPiSMOiRPqM+YMXkUN3gXFrZJwXGzUaMpJfyRS9ZT0lPe8TpScuRlbMHeUmlaKDoNuy62iWNTWNFYjoxFzuJs8oR+RhRx7O4SVNSXpa0ZJQ0K1LAHDQ+D9IepkMXpcsq5EVCvClBUIzDhDoyKwDw1Lc59GbTeORivugw1IcuaEOaGWdNm+Ps5fQ7/tm0DjMegq3yM3vb5j12qUId5UZD2oxDSEWOZMSqFl/W+5oynWDa/aI04tJRQ2eTXusg86SQVu/nwSYwpW6wLjlqIzwLuxGIvoAvul0PS+ZNz0/akp/pniO/8JDnGyaCkzbhl6YcqmK/69prxPqtpx2+Km9al9sjL+rwMgHw4jE/C8/HQ3m1vBuL1fldbzd8mOueVJ92syqdEY4KJjSCde3mcRw2TA6szxedn+zwhZMps0XrqEsiUjnC1hw0TELC2Ek7uAAdzcheXv1BYLagspxpzSAoZZUsIzIq35MnFQ9DOrlNB30jq3L4pkhccKUAA8/ocvN1Rzx9QyOtERs4CVsJRK/DF71kPYrxYsGsm6RMh4cps5g1DOmM54Ly1ii0Hd3Y/BMk8VWFgBVmhqrkJCPBHAolwZaWzLR9Vb7bcWdX9NyUYE+uB2BKfuaeBUcjDljbYVY4DdtsVWvzRZdWnyUzDpjNl1Du3aloAjVJTNDpcIOVVhrHFF66lLfJL1zJr9PQ2nFJSBaKoDe+sAvLufZVHVzYh7W0h/c6AAZ+7Tvj6q9j68G/cTCS/3n1vLKHZwNi+P+pS0WkZNMBMUl+LDLuiE4omZy71r3UFMwNJV+VJ/GC5ixVUkBStsT4gGKh0Gm4Oy3qvq7Lbmq24nPdDuDR9deR11XzP4vFu3TYzfnIyiSVmgizUYGqkIXNdKTY9pgb9D2Ix5t0+NHkVzCdU03suWkkVZAoCONCn0T35gAeW38de43mf97sMOpSvj4aa1KYUm58USI7Wxxes03bAZdRzk6UtbzMaCQ6IxO0dy7X+XsjoD16hpsBeGz9dfzHj+R/Hp8nCxZRqkEDTaCKCSywjiaoMJ1TITE9eg7Jqnq8HL6gDwiZb0u0V0Rr/rmvqjxKuaLCX7ZWXTvAY+uvm3z8CP7nzVpngqrJpZKwWnCUjIviYVlirlGOzPLI3SMVyp/elvBUjjDkNhrtufFFErQ8pmdSlbK16toBHlt/HV8uHMX/vEGALkV3RJREiSlopxwdMXOZPLZ+ix+kAHpMKIk8UtE1ygtquttwxNhphrIZ1IBzjGF3IIGxGcBj6q8bHJBG8T9vdsoWrTFEuebEZuVxhhClH6P5Zo89OG9fwHNjtNQTpD0TG9PJLEYqvEY6Rlxy+ZZGfL0Aj62/bnQCXp//eeM4KzfQVJbgMQbUjlMFIm6TpcfWlZje7NBSV6IsEVmumWIbjiloUzQX9OzYdo8L1wjw2PrrpimONfmfNyzKklrgnEkSzT5QWYQW40YShyzqsRmMXbvVxKtGuYyMKaU1ugenLDm5Ily4iT14fP11Mx+xJv+zZ3MvnfdFqxU3a1W/FTB4m3Qfsyc1XUcdVhDeUDZXSFHHLQj/Y5jtC7ZqM0CXGwB4bP11i3LhOvzPGygYtiUBiwQV/4wFO0majijGsafHyRLu0yG6q35cL1rOpVxr2s5cM2jJYMCdc10Aj6q/blRpWJ//+dmm5psMl0KA2+AFRx9jMe2WbC4jQxnikd4DU8TwUjRVacgdlhmr3bpddzuJ9zXqr2xnxJfzP29RexdtjDVZqzkqa6PyvcojGrfkXiJ8SEtml/nYskicv0ivlxbqjemwUjMw5evdg8fUX9nOiC/lf94Q2i7MURk9nW1MSj5j8eAyV6y5CN2S6qbnw3vdA1Iwq+XOSCl663udN3IzLnrt+us25cI1+Z83SXQUldqQq0b5XOT17bGpLd6ssN1VMPf8c+jG8L3NeCnMdF+Ra3fRa9dft39/LuZ/3vwHoHrqGmQFafmiQw6eyzMxS05K4bL9uA+SKUQzCnSDkqOGokXyJvbgJ/BHI+qvY69//4rl20NsmK2ou2dTsyIALv/91/8n3P2Aao71WFGi8KKv1fRC5+J67Q/507/E/SOshqN5TsmYIjVt+kcjAx98iz/4SaojbIV1rexE7/C29HcYD/DX4a0rBOF5VTu7omsb11L/AWcVlcVZHSsqGuXLLp9ha8I//w3Mv+T4Ew7nTBsmgapoCrNFObIcN4pf/Ob/mrvHTGqqgAupL8qWjWPS9m/31jAe4DjA+4+uCoQoT/zOzlrNd3qd4SdphFxsUvYwGWbTWtISc3wNOWH+kHBMfc6kpmpwPgHWwqaSUG2ZWWheYOGQGaHB+eQ/kn6b3pOgLV+ODSn94wDvr8Bvb70/LLuiPPEr8OGVWfDmr45PZyccEmsVXZGe1pRNX9SU5+AVQkNTIVPCHF/jGmyDC9j4R9LfWcQvfiETmgMMUCMN1uNCakkweZsowdYobiMSlnKA93u7NzTXlSfe+SVbfnPQXmg9LpYAQxpwEtONyEyaueWM4FPjjyjG3uOaFmBTWDNgBXGEiQpsaWhnAqIijB07Dlsy3fUGeP989xbWkyf+FF2SNEtT1E0f4DYYVlxFlbaSMPIRMk/3iMU5pME2SIWJvjckciebkQuIRRyhUvkHg/iUljG5kzVog5hV7vIlCuBrmlhvgPfNHQM8lCf+FEGsYbMIBC0qC9a0uuy2wLXVbLBaP5kjHokCRxapkQyzI4QEcwgYHRZBp+XEFTqXFuNVzMtjXLJgX4gAid24Hjwc4N3dtVSe+NNiwTrzH4WVUOlDobUqr1FuAgYllc8pmzoVrELRHSIW8ViPxNy4xwjBpyR55I6J220qQTZYR4guvUICJiSpr9gFFle4RcF/OMB7BRiX8sSfhpNSO3lvEZCQfLUVTKT78Ek1LRLhWN+yLyTnp8qWUZ46b6vxdRGXfHVqx3eI75YaLa4iNNiK4NOW7wPW6lhbSOF9/M9qw8e/aoB3d156qTzxp8pXx5BKAsYSTOIIiPkp68GmTq7sZtvyzBQaRLNxIZ+paozHWoLFeExIhRBrWitHCAHrCF7/thhD8JhYz84wg93QRV88wLuLY8zF8sQ36qF1J455bOlgnELfshKVxYOXKVuKx0jaj22sczTQqPqtV/XDgpswmGTWWMSDw3ssyUunLLrVPGjYRsH5ggHeHSWiV8kT33ycFSfMgkoOK8apCye0J6VW6GOYvffgU9RWsukEi2kUV2nl4dOYUzRik9p7bcA4ggdJ53LxKcEe17B1R8eqAd7dOepV8sTXf5lhejoL85hUdhDdknPtKHFhljOT+bdq0hxbm35p2nc8+Ja1Iw+tJykgp0EWuAAZYwMVwac5KzYMslhvgHdHRrxKnvhTYcfKsxTxtTETkjHO7rr3zjoV25lAQHrqpV7bTiy2aXMmUhTBnKS91jhtR3GEoF0oLnWhWNnYgtcc4N0FxlcgT7yz3TgNIKkscx9jtV1ZKpWW+Ub1tc1eOv5ucdgpx+FJy9pgbLE7xDyXb/f+hLHVGeitHOi6A7ybo3sF8sS7w7cgdk0nJaOn3hLj3uyD0Zp5pazFIUXUpuTTU18d1EPkDoX8SkmWTnVIozEdbTcZjoqxhNHf1JrSS/AcvHjZ/SMHhL/7i5z+POsTUh/8BvNfYMTA8n+yU/MlTZxSJDRStqvEuLQKWwDctMTQogUDyQRoTQG5Kc6oQRE1yV1jCA7ri7jdZyK0sYTRjCR0Hnnd+y7nHxNgTULqw+8wj0mQKxpYvhjm9uSUxg+TTy7s2GtLUGcywhXSKZN275GsqlclX90J6bRI1aouxmgL7Q0Nen5ziM80SqMIo8cSOo+8XplT/5DHNWsSUr/6lLN/QQ3rDyzLruEW5enpf7KqZoShEduuSFOV7DLX7Ye+GmXb6/hnNNqKsVXuMDFpb9Y9eH3C6NGEzuOuI3gpMH/I6e+zDiH1fXi15t3vA1czsLws0TGEtmPEJdiiFPwlwKbgLHAFk4P6ZyPdymYYHGE0dutsChQBl2JcBFlrEkY/N5bQeXQ18gjunuMfMfsBlxJSx3niO485fwO4fGD5T/+3fPQqkneWVdwnw/3bMPkW9Wbqg+iC765Zk+xcT98ibKZc2EdgHcLoF8cSOo/Oc8fS+OyEULF4g4sJqXVcmfMfsc7A8v1/yfGXmL9I6Fn5pRwZhsPv0TxFNlAfZCvG+Oohi82UC5f/2IsJo0cTOm9YrDoKhFPEUr/LBYTUNht9zelHXDqwfPCIw4owp3mOcIQcLttWXFe3VZ/j5H3cIc0G6oPbCR+6Y2xF2EC5cGUm6wKC5tGEzhsWqw5hNidUiKX5gFWE1GXh4/Qplw4sVzOmx9QxU78g3EF6wnZlEN4FzJ1QPSLEZz1KfXC7vd8ssGdIbNUYpVx4UapyFUHzJoTOo1McSkeNn1M5MDQfs4qQuhhX5vQZFw8suwWTcyYTgioISk2YdmkhehG4PkE7w51inyAGGaU+uCXADabGzJR1fn3lwkty0asIo8cROm9Vy1g0yDxxtPvHDAmpu+PKnM8Ix1wwsGw91YJqhteaWgjYBmmQiebmSpwKKzE19hx7jkzSWOm66oPbzZ8Yj6kxVSpYjVAuvLzYMCRo3oTQecOOjjgi3NQ4l9K5/hOGhNTdcWVOTrlgYNkEXINbpCkBRyqhp+LdRB3g0OU6rMfW2HPCFFMV9nSp+uB2woepdbLBuJQyaw/ZFysXrlXwHxI0b0LovEkiOpXGA1Ijagf+KUNC6rKNa9bQnLFqYNkEnMc1uJrg2u64ELPBHpkgWbmwKpJoDhMwNbbGzAp7Yg31wS2T5rGtzit59PrKhesWG550CZpHEzpv2NGRaxlNjbMqpmEIzygJqQfjypycs2pg2cS2RY9r8HUqkqdEgKTWtWTKoRvOBPDYBltja2SO0RGjy9UHtxwRjA11ujbKF+ti5cIR9eCnxUg6owidtyoU5tK4NLji5Q3HCtiyF2IqLGYsHViOXTXOYxucDqG0HyttqYAKqYo3KTY1ekyDXRAm2AWh9JmsVh/ccg9WJ2E8YjG201sPq5ULxxX8n3XLXuMInbft2mk80rRGjCGctJ8/GFdmEQ9Ug4FlE1ll1Y7jtiraqm5Fe04VV8lvSVBL8hiPrfFVd8+7QH3Qbu2ipTVi8cvSGivc9cj8yvH11YMHdNSERtuOslM97feYFOPKzGcsI4zW0YGAbTAOaxCnxdfiYUmVWslxiIblCeAYr9VYR1gM7GmoPrilunSxxeT3DN/2eBQ9H11+nk1adn6VK71+5+Jfct4/el10/7KBZfNryUunWSCPxPECk1rdOv1WVSrQmpC+Tl46YD3ikQYcpunSQgzVB2VHFhxHVGKDgMEY5GLlQnP7FMDzw7IacAWnO6sBr12u+XanW2AO0wQ8pknnFhsL7KYIqhkEPmEXFkwaN5KQphbkUmG72wgw7WSm9RiL9QT925hkjiVIIhphFS9HKI6/8QAjlpXqg9W2C0apyaVDwKQwrwLY3j6ADR13ZyUNByQXHQu6RY09Hu6zMqXRaNZGS/KEJs0cJEe9VH1QdvBSJv9h09eiRmy0V2uJcqHcShcdvbSNg5fxkenkVprXM9rDVnX24/y9MVtncvbKY706anNl3ASll9a43UiacVquXGhvq4s2FP62NGKfQLIQYu9q1WmdMfmUrDGt8eDS0cXozH/fjmUH6Jruvm50hBDSaEU/2Ru2LEN/dl006TSc/g7tfJERxGMsgDUEr104pfWH9lQaN+M4KWQjwZbVc2rZVNHsyHal23wZtIs2JJqtIc/WLXXRFCpJkfE9jvWlfFbsNQ9pP5ZBS0zKh4R0aMFj1IjTcTnvi0Zz2rt7NdvQb2mgbju1plsH8MmbnEk7KbK0b+wC2iy3aX3szW8xeZvDwET6hWZYwqTXSSG+wMETKum0Dq/q+x62gt2ua2ppAo309TRk9TPazfV3qL9H8z7uhGqGqxNVg/FKx0HBl9OVUORn8Q8Jx9gFttGQUDr3tzcXX9xGgN0EpzN9mdZ3GATtPhL+CjxFDmkeEU6x56kqZRusLzALXVqkCN7zMEcqwjmywDQ6OhyUe0Xao1Qpyncrg6wKp9XfWDsaZplElvQ/b3sdweeghorwBDlHzgk1JmMc/wiERICVy2VJFdMjFuLQSp3S0W3+sngt2njwNgLssFGVQdJ0tu0KH4ky1LW4yrbkuaA6Iy9oz/qEMMXMMDWyIHhsAyFZc2peV9hc7kiKvfULxCl9iddfRK1f8kk9qvbdOoBtOg7ZkOZ5MsGrSHsokgLXUp9y88smniwWyuFSIRVmjplga3yD8Uij5QS1ZiM4U3Qw5QlSm2bXjFe6jzzBFtpg+/YBbLAWG7OPynNjlCw65fukGNdkJRf7yM1fOxVzbxOJVocFoYIaGwH22mIQkrvu1E2nGuebxIgW9U9TSiukPGU+Lt++c3DJPKhyhEEbXCQLUpae2exiKy6tMPe9mDRBFCEMTWrtwxN8qvuGnt6MoihKWS5NSyBhbH8StXoAz8PLOrRgLtOT/+4vcu+7vDLnqNvztOq7fmd8sMmY9Xzn1zj8Dq8+XVdu2Nv0IIySgEdQo3xVHps3Q5i3fLFsV4aiqzAiBhbgMDEd1uh8qZZ+lwhjkgokkOIv4xNJmyncdfUUzgB4oFMBtiu71Xumpz/P+cfUP+SlwFExwWW62r7b+LSPxqxn/gvMZ5z9C16t15UbNlq+jbGJtco7p8wbYlL4alSyfWdeuu0j7JA3JFNuVAwtst7F7FhWBbPFNKIUORndWtLraFLmMu7KFVDDOzqkeaiN33YAW/r76wR4XDN/yN1z7hejPau06EddkS/6XThfcz1fI/4K736fO48vlxt2PXJYFaeUkFS8U15XE3428xdtn2kc8GQlf1vkIaNRRnOMvLTWrZbElEHeLWi1o0dlKPAh1MVgbbVquPJ5+Cr8LU5/H/+I2QlHIU2ClXM9G8v7Rr7oc/hozfUUgsPnb3D+I+7WF8kNO92GY0SNvuxiE+2Bt8prVJTkzE64sfOstxuwfxUUoyk8VjcTlsqe2qITSFoSj6Epd4KsT6BZOWmtgE3hBfir8IzZDwgV4ZTZvD8VvPHERo8v+vL1DASHTz/i9OlKueHDjK5Rnx/JB1Vb1ioXdBra16dmt7dgik10yA/FwJSVY6XjA3oy4SqM2frqDPPSRMex9qs3XQtoWxMj7/Er8GWYsXgjaVz4OYumP2+9kbxvny/6kvWsEBw+fcb5bInc8APdhpOSs01tEqIkoiZjbAqKMruLbJYddHuHFRIyJcbdEdbl2sVLaySygunutBg96Y2/JjKRCdyHV+AEFtTvIpbKIXOamknYSiB6KV/0JetZITgcjjk5ZdaskBtWO86UF0ap6ozGXJk2WNiRUlCPFir66lzdm/SLSuK7EUdPz8f1z29Skq6F1fXg8+5UVR6bszncP4Tn4KUkkdJ8UFCY1zR1i8RmL/qQL3rlei4THG7OODlnKko4oI01kd3CaM08Ia18kC3GNoVaO9iDh+hWxSyTXFABXoau7Q6q9OxYg/OVEMw6jdbtSrJ9cBcewGmaZmg+bvkUnUUaGr+ZfnMH45Ivevl61hMcXsxYLFTu1hTm2zViCp7u0o5l+2PSUh9bDj6FgYypufBDhqK2+oXkiuHFHR3zfj+9PtA8oR0xnqX8qn+sx3bFODSbbF0X8EUvWQ8jBIcjo5bRmLOljDNtcqNtOe756h3l0VhKa9hDd2l1eqmsnh0MNMT/Cqnx6BInumhLT8luljzQ53RiJeA/0dxe5NK0o2fA1+GLXr6eNQWHNUOJssQaTRlGpLHKL9fD+IrQzTOMZS9fNQD4AnRNVxvTdjC+fJdcDDWQcyB00B0t9BDwTxXgaAfzDZ/DBXzRnfWMFRwuNqocOmX6OKNkY63h5n/fFcB28McVHqnXZVI27K0i4rDLNE9lDKV/rT+udVbD8dFFu2GGZ8mOt0kAXcoX3ZkIWVtw+MNf5NjR2FbivROHmhV1/pj2egv/fMGIOWTIWrV3Av8N9imV9IWml36H6cUjqEWNv9aNc+veb2sH46PRaHSuMBxvtW+twxctq0z+QsHhux8Q7rCY4Ct8lqsx7c6Sy0dl5T89rIeEuZKoVctIk1hNpfavER6yyH1Vvm3MbsUHy4ab4hWr/OZPcsRBphnaV65/ZcdYPNNwsjN/djlf9NqCw9U5ExCPcdhKxUgLSmfROpLp4WSUr8ojdwbncbvCf+a/YzRaEc6QOvXcGO256TXc5Lab9POvB+AWY7PigWYjzhifbovuunzRawsO24ZqQQAqguBtmpmPB7ysXJfyDDaV/aPGillgz1MdQg4u5MYaEtBNNHFjkRlSpd65lp4hd2AVPTfbV7FGpyIOfmNc/XVsPfg7vzaS/3nkvLL593ANLvMuRMGpQIhiF7kUEW9QDpAUbTWYBcbp4WpacHHY1aacqQyjGZS9HI3yCBT9kUZJhVOD+zUDvEH9ddR11fzPcTDQ5TlgB0KwqdXSavk9BC0pKp0WmcuowSw07VXmXC5guzSa4p0UvRw2lbDiYUx0ExJJRzWzi6Gm8cnEkfXXsdcG/M/jAJa0+bmCgdmQ9CYlNlSYZOKixmRsgiFxkrmW4l3KdFKv1DM8tk6WxPYJZhUUzcd8Kdtgrw/gkfXXDT7+avmfVak32qhtkg6NVdUS5wgkru1YzIkSduTW1FDwVWV3JQVJVuieTc0y4iDpFwc7/BvSalvKdQM8sv662cevz/+8sQVnjVAT0W2wLllw1JiMhJRxgDjCjLQsOzSFSgZqx7lAW1JW0e03yAD3asC+GD3NbQhbe+mN5GXH1F83KDOM4n/e5JIuH4NpdQARrFPBVptUNcjj4cVMcFSRTE2NpR1LEYbYMmfWpXgP9KejaPsLUhuvLCsVXznAG9dfx9SR1ud/3hZdCLHb1GMdPqRJgqDmm76mHbvOXDtiO2QPUcKo/TWkQ0i2JFXpBoo7vij1i1Lp3ADAo+qvG3V0rM//vFnnTE4hxd5Ka/Cor5YEdsLVJyKtDgVoHgtW11pWSjolPNMnrlrVj9Fv2Qn60twMwKPqr+N/wvr8z5tZcDsDrv06tkqyzESM85Ycv6XBWA2birlNCXrI6VbD2lx2L0vQO0QVTVVLH4SE67fgsfVXv8n7sz7/85Z7cMtbE6f088wSaR4kCkCm10s6pKbJhfqiUNGLq+0gLWC6eUAZFPnLjwqtKd8EwGvWX59t7iPW4X/eAN1svgRVSY990YZg06BD1ohLMtyFTI4pKTJsS9xREq9EOaPWiO2gpms7397x6nQJkbh+Fz2q/rqRROX6/M8bJrqlVW4l6JEptKeUFuMYUbtCQ7CIttpGc6MY93x1r1vgAnRXvY5cvwWPqb9uWQm+lP95QxdNMeWhOq1x0Db55C7GcUv2ZUuN6n8iKzsvOxibC//Yfs9Na8r2Rlz02vXXDT57FP/zJi66/EJSmsJKa8QxnoqW3VLQ+jZVUtJwJ8PNX1NQCwfNgdhhHD9on7PdRdrdGPF28rJr1F+3LBdeyv+8yYfLoMYet1vX4upNAjVvwOUWnlNXJXlkzk5Il6kqeoiL0C07qno+/CYBXq/+utlnsz7/Mzvy0tmI4zm4ag23PRN3t/CWryoUVJGm+5+K8RJ0V8Hc88/XHUX/HfiAq7t+BH+x6v8t438enWmdJwFA6ZINriLGKv/95f8lT9/FnyA1NMVEvQyaXuu+gz36f/DD73E4pwqpLcvm/o0Vle78n//+L/NPvoefp1pTJye6e4A/D082FERa5/opeH9zpvh13cNm19/4v/LDe5xMWTi8I0Ta0qKlK27AS/v3/r+/x/2GO9K2c7kVMonDpq7//jc5PKCxeNPpFVzaRr01wF8C4Pu76hXuX18H4LduTr79guuFD3n5BHfI+ZRFhY8w29TYhbbLi/bvBdqKE4fUgg1pBKnV3FEaCWOWyA+m3WpORZr/j+9TKJtW8yBTF2/ZEODI9/QavHkVdGFp/Pjn4Q+u5hXapsP5sOH+OXXA1LiKuqJxiMNbhTkbdJTCy4llEt6NnqRT4dhg1V3nbdrm6dYMecA1yTOL4PWTE9L5VzPFlLBCvlG58AhehnN4uHsAYinyJ+AZ/NkVvELbfOBUuOO5syBIEtiqHU1k9XeISX5bsimrkUUhnGDxourN8SgUsCZVtKyGbyGzHXdjOhsAvOAswSRyIBddRdEZWP6GZhNK/yjwew9ehBo+3jEADu7Ay2n8mDc+TS7awUHg0OMzR0LABhqLD4hJEh/BEGyBdGlSJoXYXtr+3HS4ijzVpgi0paWXtdruGTknXBz+11qT1Q2inxaTzQCO46P3lfLpyS4fou2PH/PupwZgCxNhGlj4IvUuWEsTkqMWm6i4xCSMc9N1RDQoCVcuGItJ/MRWefais+3synowi/dESgJjkilnWnBTGvRWmaw8oR15257t7CHmCf8HOn7cwI8+NQBXMBEmAa8PMRemrNCEhLGEhDQKcGZWS319BX9PFBEwGTbRBhLbDcaV3drFcDqk5kCTd2JF1Wp0HraqBx8U0wwBTnbpCadwBA/gTH/CDrcCs93LV8E0YlmmcyQRQnjBa8JESmGUfIjK/7fkaDJpmD2QptFNVJU1bbtIAjjWQizepOKptRjbzR9Kag6xZmMLLjHOtcLT3Tx9o/0EcTT1XN3E45u24AiwEypDJXihKjQxjLprEwcmRKclaDNZCVqr/V8mYWyFADbusiY5hvgFoU2vio49RgJLn5OsReRFN6tabeetiiy0V7KFHT3HyZLx491u95sn4K1QQSPKM9hNT0wMVvAWbzDSVdrKw4zRjZMyJIHkfq1VAVCDl/bUhNKlGq0zGr05+YAceXVPCttVk0oqjVwMPt+BBefx4yPtGVkUsqY3CHDPiCM5ngupUwCdbkpd8kbPrCWHhkmtIKLEetF2499eS1jZlIPGYnlcPXeM2KD9vLS0bW3ktYNqUllpKLn5ZrsxlIzxvDu5eHxzGLctkZLEY4PgSOg2IUVVcUONzUDBEpRaMoXNmUc0tFZrTZquiLyKxrSm3DvIW9Fil+AkhXu5PhEPx9mUNwqypDvZWdKlhIJQY7vn2OsnmBeOWnYZ0m1iwbbw1U60by5om47iHRV6fOgzjMf/DAZrlP40Z7syxpLK0lJ0gqaAK1c2KQKu7tabTXkLFz0sCftuwX++MyNeNn68k5Buq23YQhUh0SNTJa1ioQ0p4nUG2y0XilF1JqODqdImloPS4Bp111DEWT0jJjVv95uX9BBV7eB3bUWcu0acSVM23YZdd8R8UbQUxJ9wdu3oMuhdt929ME+mh6JXJ8di2RxbTi6TbrDquqV4aUKR2iwT6aZbyOwEXN3DUsWr8Hn4EhwNyHuXHh7/pdaUjtR7vnDh/d8c9xD/s5f501eQ1+CuDiCvGhk1AN/4Tf74RfxPwD3toLarR0zNtsnPzmS64KIRk861dMWCU8ArasG9T9H0ZBpsDGnjtAOM2+/LuIb2iIUGXNgl5ZmKD/Tw8TlaAuihaFP5yrw18v4x1898zIdP+DDAX1bM3GAMvPgRP/cJn3zCW013nrhHkrITyvYuwOUkcHuKlRSW5C6rzIdY4ppnF7J8aAJbQepgbJYBjCY9usGXDKQxq7RZfh9eg5d1UHMVATRaD/4BHK93/1iAgYZ/+jqPn8Dn4UExmWrpa3+ZOK6MvM3bjwfzxNWA2dhs8+51XHSPJiaAhGSpWevEs5xHLXcEGFXYiCONySH3fPWq93JIsBiSWvWyc3CAN+EcXoT7rCSANloPPoa31rt/5PUA/gp8Q/jDD3hyrjzlR8VkanfOvB1XPubt17vzxAfdSVbD1pzAnfgyF3ycadOTOTXhpEUoLC1HZyNGW3dtmjeXgr2r56JNmRwdNNWaQVBddd6rh4MhviEB9EFRD/7RGvePvCbwAL4Mx/D6M541hHO4D3e7g6PafdcZVw689z7NGTwo5om7A8sPhccT6qKcl9NJl9aM/9kX+e59Hh1yPqGuCCZxuITcsmNaJ5F7d0q6J3H48TO1/+M57085q2icdu2U+W36Ldllz9Agiv4YGljoEN908EzvDOrBF98/vtJwCC/BF2AG75xxEmjmMIcjxbjoaxqOK3/4hPOZzhMPBpYPG44CM0dTVm1LjLtUWWVz1Bcf8tEx0zs8O2A2YVHRxKYOiy/aOVoAaMu0i7ubu43njjmd4ibMHU1sIDHaQNKrZND/FZYdk54oCXetjq7E7IVl9eAL7t+oHnwXXtLx44czzoRFHBztYVwtH1d+NOMkupZ5MTM+gUmq90X+Bh9zjRlmaQ+m7YMqUL/veemcecAtOJ0yq1JnVlN27di2E0+Klp1tAJ4KRw1eMI7aJjsO3R8kPSI3fUFXnIOfdQe86sIIVtWDL7h//Ok6vj8vwDk08NEcI8zz7OhBy+WwalzZeZ4+0XniRfst9pAJqQHDGLzVQ2pheZnnv1OWhwO43/AgcvAEXEVVpa4db9sGvNK8wjaENHkfFQ4Ci5i7dqnQlPoLQrHXZDvO3BIXZbJOBrOaEbML6sFL798I4FhKihjHMsPjBUZYCMFr6nvaArxqXPn4lCa+cHfSa2cP27g3Z3ziYTRrcbQNGLQmGF3F3cBdzzzX7AILx0IB9rbwn9kx2G1FW3Inic+ZLIsVvKR8Zwfj0l1fkqo8LWY1M3IX14OX3r9RKTIO+d9XzAI8qRPGPn/4NC2n6o4rN8XJ82TOIvuVA8zLKUHRFgBCetlDZlqR1gLKjS39xoE7Bt8UvA6BxuEDjU3tFsEijgA+615tmZkXKqiEENrh41iLDDZNq4pKTWR3LZfnos81LOuNa15cD956vLMsJd1rqYp51gDUQqMYm2XsxnUhD2jg1DM7SeuJxxgrmpfISSXVIJIS5qJJSvJPEQ49DQTVIbYWJ9QWa/E2+c/oPK1drmC7WSfJRNKBO5Yjvcp7Gc3dmmI/Xh1kDTEuiSnWqQf37h+fTMhGnDf6dsS8SQfQWlqqwXXGlc/PEZ/SC5mtzIV0nAshlQdM/LvUtYutrEZ/Y+EAFtq1k28zQhOwLr1AIeANzhF8t9qzTdZf2qRKO6MWE9ohBYwibbOmrFtNmg3mcS+tB28xv2uKd/agYCvOP+GkSc+0lr7RXzyufL7QbkUpjLjEWFLqOIkAGu2B0tNlO9Eau2W1qcOUvVRgKzypKIQZ5KI3q0MLzqTNRYqiZOqmtqloIRlmkBHVpHmRYV6/HixbO6UC47KOFJnoMrVyr7wYz+SlW6GUaghYbY1I6kkxA2W1fSJokUdSh2LQ1GAimRGm0MT+uu57H5l7QgOWxERpO9moLRPgTtquWCfFlGlIjQaRly9odmzMOWY+IBO5tB4sW/0+VWGUh32qYk79EidWKrjWuiLpiVNGFWFRJVktyeXWmbgBBzVl8anPuXyNJlBJOlKLTgAbi/EYHVHxWiDaVR06GnHQNpJcWcK2jJtiCfG2sEHLzuI66sGrMK47nPIInPnu799935aOK2cvmvubrE38ZzZjrELCmXM2hM7UcpXD2oC3+ECVp7xtIuxptJ0jUr3sBmBS47TVxlvJ1Sqb/E0uLdvLj0lLr29ypdd/eMX3f6lrxGlKwKQxEGvw0qHbkbwrF3uHKwVENbIV2wZ13kNEF6zD+x24aLNMfDTCbDPnEikZFyTNttxWBXDaBuM8KtI2rmaMdUY7cXcUPstqTGvBGSrFWIpNMfbdea990bvAOC1YX0qbc6smDS1mPxSJoW4fwEXvjMmhlijDRq6qale6aJEuFGoppYDoBELQzLBuh/mZNx7jkinv0EtnUp50lO9hbNK57lZaMAWuWR5Yo9/kYwcYI0t4gWM47Umnl3YmpeBPqSyNp3K7s2DSAS/39KRuEN2bS4xvowV3dFRMx/VFcp2Yp8w2nTO9hCXtHG1kF1L4KlrJr2wKfyq77R7MKpFKzWlY9UkhYxyHWW6nBWPaudvEAl3CGcNpSXPZ6R9BbBtIl6cHL3gIBi+42CYXqCx1gfGWe7Ap0h3luyXdt1MKy4YUT9xSF01G16YEdWsouW9mgDHd3veyA97H+Ya47ZmEbqMY72oPztCGvK0onL44AvgC49saZKkWRz4veWljE1FHjbRJaWv6ZKKtl875h4CziFCZhG5rx7tefsl0aRT1bMHZjm8dwL/6u7wCRysaQblQoG5yAQN5zpatMNY/+yf8z+GLcH/Qn0iX2W2oEfXP4GvwQHuIL9AYGnaO3zqAX6946nkgqZNnUhx43DIdQtMFeOPrgy/y3Yd85HlJWwjLFkU3kFwq28xPnuPhMWeS+tDLV9Otllq7pQCf3uXJDN9wFDiUTgefHaiYbdfi3b3u8+iY6TnzhgehI1LTe8lcd7s1wJSzKbahCRxKKztTLXstGAiu3a6rPuQs5pk9TWAan5f0BZmGf7Ylxzzk/A7PAs4QPPPAHeFQ2hbFHszlgZuKZsJcUmbDC40sEU403cEjczstOEypa+YxevL4QBC8oRYqWdK6b7sK25tfE+oDZgtOQ2Jg8T41HGcBE6fTWHn4JtHcu9S7uYgU5KSCkl/mcnq+5/YBXOEr6lCUCwOTOM1taOI8mSxx1NsCXBEmLKbMAg5MkwbLmpBaFOPrNSlO2HnLiEqW3tHEwd8AeiQLmn+2gxjC3k6AxREqvKcJbTEzlpLiw4rNZK6oJdidbMMGX9FULKr0AkW+2qDEPBNNm5QAt2Ik2nftNWHetubosHLo2nG4vQA7GkcVCgVCgaDixHqo9UUn1A6OshapaNR/LPRYFV8siT1cCtJE0k/3WtaNSuUZYKPnsVIW0xXWnMUxq5+En4Kvw/MqQmVXnAXj9Z+9zM98zM/Agy7F/qqj2Nh67b8HjFnPP3iBn/tkpdzwEJX/whIcQUXOaikeliCRGUk7tiwF0rItwMEhjkZ309hikFoRAmLTpEXWuHS6y+am/KB/fM50aLEhGnSMwkpxzOov4H0AvgovwJ1iGzDLtJn/9BU+fAINfwUe6FHSLhu83viV/+/HrOePX+STT2B9uWGbrMHHLldRBlhS/CJQmcRxJFqZica01XixAZsYiH1uolZxLrR/SgxVIJjkpQP4PE9sE59LKLr7kltSBogS5tyszzH8Fvw8/AS8rNOg0xUS9fIaHwb+6et8Q/gyvKRjf5OusOzGx8evA/BP4IP11uN/grca5O0lcsPLJ5YjwI4QkJBOHa0WdMZYGxPbh2W2nR9v3WxEWqgp/G3+6VZbRLSAAZ3BhdhAaUL33VUSw9yjEsvbaQ9u4A/gGXwZXoEHOuU1GSj2chf+Mo+f8IcfcAxfIKVmyunRbYQVnoevwgfw3TXXcw++xNuP4fhyueEUNttEduRVaDttddoP0eSxLe2LENk6itYxlrxBNBYrNNKSQmeaLcm9c8UsaB5WyO6675yyQIAWSDpBVoA/gxmcwEvwoDv0m58UE7gHn+fJOa8/Ywan8EKRfjsopF83eCglX/Sfr7OeaRoQfvt1CGvIDccH5BCvw1sWIzRGC/66t0VTcLZQZtm6PlAasbOJ9iwWtUo7biktTSIPxnR24jxP1ZKaqq+2RcXM9OrBAm/AAs7hDJ5bNmGb+KIfwCs8a3jnjBrOFeMjHSCdbKr+2uOLfnOd9eiA8Hvvwwq54VbP2OqwkB48Ytc4YEOiH2vTXqodabfWEOzso4qxdbqD5L6tbtNPECqbhnA708DZH4QOJUXqScmUlks7Ot6FBuZw3n2mEbaUX7kDzxHOOQk8nKWMzAzu6ZZ8sOFw4RK+6PcuXo9tB4SbMz58ApfKDXf3szjNIIbGpD5TKTRxGkEMLjLl+K3wlWXBsCUxIDU+jbOiysESqAy1MGUJpXgwbTWzNOVEziIXZrJ+VIztl1PUBxTSo0dwn2bOmfDRPD3TRTGlfbCJvO9KvuhL1hMHhB9wPuPRLGHcdOWG2xc0U+5bQtAJT0nRTewXL1pgk2+rZAdeWmz3jxAqfNQQdzTlbF8uJ5ecEIWvTkevAHpwz7w78QujlD/Lr491bD8/1vhM2yrUQRrWXNQY4fGilfctMWYjL72UL/qS9eiA8EmN88nbNdour+PBbbAjOjIa4iBhfFg6rxeKdEGcL6p3EWR1Qq2Qkhs2DrnkRnmN9tG2EAqmgPw6hoL7Oza7B+3SCrR9tRftko+Lsf2F/mkTndN2LmzuMcKTuj/mX2+4Va3ki16+nnJY+S7MefpkidxwnV+4wkXH8TKnX0tsYzYp29DOOoSW1nf7nTh2akYiWmcJOuTidSaqESrTYpwjJJNVGQr+rLI7WsqerHW6Kp/oM2pKuV7T1QY9gjqlZp41/WfKpl56FV/0kvXQFRyeQ83xaTu5E8p5dNP3dUF34ihyI3GSpeCsywSh22ZJdWto9winhqifb7VRvgktxp13vyjrS0EjvrRfZ62uyqddSWaWYlwTPAtJZ2oZ3j/Sgi/mi+6vpzesfAcWNA0n8xVyw90GVFGuZjTXEQy+6GfLGLMLL523f5E0OmxVjDoOuRiH91RKU+vtoCtH7TgmvBLvtFXWLW15H9GTdVw8ow4IlRLeHECN9ym1e9K0I+Cbnhgv4Yu+aD2HaQJ80XDqOzSGAV4+4yCqBxrsJAX6ZTIoX36QnvzhhzzMfFW2dZVLOJfo0zbce5OvwXMFaZ81mOnlTVXpDZsQNuoYWveketKb5+6JOOsgX+NTm7H49fUTlx+WLuWL7qxnOFh4BxpmJx0p2gDzA/BUARuS6phR+pUsY7MMboAHx5xNsSVfVZcYSwqCKrqon7zM+8ecCkeS4nm3rINuaWvVNnMRI1IRpxTqx8PZUZ0Br/UEduo3B3hNvmgZfs9gQPj8vIOxd2kndir3awvJ6BLvoUuOfFWNYB0LR1OQJoUySKb9IlOBx74q1+ADC2G6rOdmFdJcD8BkfualA+BdjOOzP9uUhGUEX/TwhZsUduwRr8wNuXKurCixLBgpQI0mDbJr9dIqUuV+92ngkJZ7xduCk2yZKbfWrH1VBiTg9VdzsgRjW3CVXCvAwDd+c1z9dWw9+B+8MJL/eY15ZQ/HqvTwVdsZn5WQsgRRnMaWaecu3jFvMBEmgg+FJFZsnSl0zjB9OqPYaBD7qmoVyImFvzi41usesV0julaAR9dfR15Xzv9sEruRDyk1nb+QaLU67T885GTls6YgcY+UiMa25M/pwGrbCfzkvR3e0jjtuaFtnwuagHTSb5y7boBH119HXhvwP487jJLsLJ4XnUkHX5sLbS61dpiAXRoZSCrFJ+EjpeU3puVfitngYNo6PJrAigKktmwjyQdZpfq30mmtulaAx9Zfx15Xzv+cyeuiBFUs9zq8Kq+XB9a4PVvph3GV4E3y8HENJrN55H1X2p8VyqSKwVusJDKzXOZzplWdzBUFK9e+B4+uv468xvI/b5xtSAkBHQaPvtqWzllVvEOxPbuiE6+j2pvjcKsbvI7txnRErgfH7LdXqjq0IokKzga14GzQ23SSbCQvO6r+Or7SMIr/efOkkqSdMnj9mBx2DRsiY29Uj6+qK9ZrssCKaptR6HKURdwUYeUWA2kPzVKQO8ku2nU3Anhs/XWkBx3F/7wJtCTTTIKftthue1ty9xvNYLY/zo5KSbIuKbXpbEdSyeRyYdAIwKY2neyoc3+k1XUaufYga3T9daMUx/r8z1s10ITknIO0kuoMt+TB8jK0lpayqqjsJ2qtXAYwBU932zinimgmd6mTRDnQfr88q36NAI+tv24E8Pr8zxtasBqx0+xHH9HhlrwsxxNUfKOHQaZBITNf0uccj8GXiVmXAuPEAKSdN/4GLHhs/XWj92dN/uetNuBMnVR+XWDc25JLjo5Mg5IZIq226tmCsip2zZliL213YrTlL2hcFjpCduyim3M7/eB16q/blQsv5X/esDRbtJeabLIosWy3ycavwLhtxdWzbMmHiBTiVjJo6lCLjXZsi7p9PEPnsq6X6wd4bP11i0rD5fzPm/0A6brrIsllenZs0lCJlU4abakR59enZKrKe3BZihbTxlyZ2zl1+g0wvgmA166/bhwDrcn/7Ddz0eWZuJvfSESug6NzZsox3Z04FIxz0mUjMwVOOVTq1CQ0AhdbBGVdjG/CgsfUX7esJl3K/7ytWHRv683praW/8iDOCqWLLhpljDY1ZpzK75QiaZoOTpLKl60auHS/97oBXrv+umU9+FL+5+NtLFgjqVLCdbmj7pY5zPCPLOHNCwXGOcLquOhi8CmCWvbcuO73XmMUPab+ug3A6/A/78Bwe0bcS2+tgHn4J5pyS2WbOck0F51Vq3LcjhLvZ67p1ABbaL2H67bg78BfjKi/jr3+T/ABV3ilLmNXTI2SpvxWBtt6/Z//D0z/FXaGbSBgylzlsEGp+5//xrd4/ae4d8DUUjlslfIYS3t06HZpvfQtvv0N7AHWqtjP2pW08QD/FLy//da38vo8PNlKHf5y37Dxdfe/oj4kVIgFq3koLReSR76W/bx//n9k8jonZxzWTANVwEniDsg87sOSd/z7//PvMp3jQiptGVWFX2caezzAXwfgtzYUvbr0iozs32c3Uge7varH+CNE6cvEYmzbPZ9hMaYDdjK4V2iecf6EcEbdUDVUARda2KzO/JtCuDbNQB/iTeL0EG1JSO1jbXS+nLxtPMDPw1fh5+EPrgSEKE/8Gry5A73ui87AmxwdatyMEBCPNOCSKUeRZ2P6Myb5MRvgCHmA9ywsMifU+AYXcB6Xa5GibUC5TSyerxyh0j6QgLVpdyhfArRTTLqQjwe4HOD9s92D4Ap54odXAPBWLAwB02igG5Kkc+piN4lvODIFGAZgT+EO4Si1s7fjSR7vcQETUkRm9O+MXyo9OYhfe4xt9STQ2pcZRLayCV90b4D3jR0DYAfyxJ+eywg2IL7NTMXna7S/RpQ63JhWEM8U41ZyQGjwsVS0QBrEKLu8xwZsbi4wLcCT+OGidPIOCe1PiSc9Qt+go+vYqB7cG+B9d8cAD+WJPz0Am2gxXgU9IneOqDpAAXOsOltVuMzpdakJXrdPCzXiNVUpCeOos5cxnpQT39G+XVLhs1osQVvJKPZyNq8HDwd4d7pNDuWJPxVX7MSzqUDU6gfadKiNlUFTzLeFHHDlzO4kpa7aiKhBPGKwOqxsBAmYkOIpipyXcQSPlRTf+Tii0U3EJGaZsDER2qoB3h2hu0qe+NNwUooYU8y5mILbJe6OuX+2FTKy7bieTDAemaQyQ0CPthljSWO+xmFDIYiESjM5xKd6Ik5lvLq5GrQ3aCMLvmCA9wowLuWJb9xF59hVVP6O0CrBi3ZjZSNOvRy+I6klNVRJYRBaEzdN+imiUXQ8iVF8fsp+W4JXw7WISW7fDh7lptWkCwZ4d7QTXyBPfJMYK7SijjFppGnlIVJBJBYj7eUwtiP1IBXGI1XCsjNpbjENVpSAJ2hq2LTywEly3hUYazt31J8w2+aiLx3g3fohXixPfOMYm6zCGs9LVo9MoW3MCJE7R5u/WsOIjrqBoHUO0bJE9vxBpbhsd3+Nb4/vtPCZ4oZYCitNeYuC/8UDvDvy0qvkiW/cgqNqRyzqSZa/s0mqNGjtKOoTm14zZpUauiQgVfqtQiZjq7Q27JNaSK5ExRcrGCXO1FJYh6jR6CFqK7bZdQZ4t8g0rSlPfP1RdBtqaa9diqtzJkQ9duSryi2brQXbxDwbRUpFMBHjRj8+Nt7GDKgvph9okW7LX47gu0SpGnnFQ1S1lYldOsC7hYteR574ZuKs7Ei1lBsfdz7IZoxzzCVmmVqaSySzQbBVAWDek+N4jh9E/4VqZrJjPwiv9BC1XcvOWgO8275CVyBPvAtTVlDJfZkaZGU7NpqBogAj/xEHkeAuJihWYCxGN6e8+9JtSegFXF1TrhhLGP1fak3pebgPz192/8gB4d/6WT7+GdYnpH7hH/DJzzFiYPn/vjW0SgNpTNuPIZoAEZv8tlGw4+RLxy+ZjnKa5NdFoC7UaW0aduoYse6+bXg1DLg6UfRYwmhGEjqPvF75U558SANrElK/+MdpXvmqBpaXOa/MTZaa1DOcSiLaw9j0NNNst3c+63c7EKTpkvKHzu6bPbP0RkuHAVcbRY8ijP46MIbQeeT1mhA+5PV/inyDdQipf8LTvMXbwvoDy7IruDNVZKTfV4CTSRUYdybUCnGU7KUTDxLgCknqUm5aAW6/1p6eMsOYsphLzsHrE0Y/P5bQedx1F/4yPHnMB3/IOoTU9+BL8PhtjuFKBpZXnYNJxTuv+2XqolKR2UQgHhS5novuxVySJhBNRF3SoKK1XZbbXjVwWNyOjlqWJjrWJIy+P5bQedyldNScP+HZ61xKSK3jyrz+NiHG1hcOLL/+P+PDF2gOkekKGiNWKgJ+8Z/x8Iv4DdQHzcpZyF4v19I27w9/yPGDFQvmEpKtqv/TLiWMfn4sofMm9eAH8Ao0zzh7h4sJqYtxZd5/D7hkYPneDzl5idlzNHcIB0jVlQ+8ULzw/nc5/ojzl2juE0apD7LRnJxe04dMz2iOCFNtGFpTuXA5AhcTRo8mdN4kz30nVjEC4YTZQy4gpC7GlTlrePKhGsKKgeXpCYeO0MAd/GH7yKQUlXPLOasOH3FnSphjHuDvEu4gB8g66oNbtr6eMbFIA4fIBJkgayoXriw2XEDQPJrQeROAlY6aeYOcMf+IVYTU3XFlZufMHinGywaW3YLpObVBAsbjF4QJMsVUSayjk4voPsHJOQfPWDhCgDnmDl6XIRerD24HsGtw86RMHOLvVSHrKBdeVE26gKB5NKHzaIwLOmrqBWJYZDLhASG16c0Tn+CdRhWDgWXnqRZUTnPIHuMJTfLVpkoYy5CzylHVTGZMTwkGAo2HBlkQplrJX6U+uF1wZz2uwS1SQ12IqWaPuO4baZaEFBdukksJmkcTOm+YJSvoqPFzxFA/YUhIvWxcmSdPWTWwbAKVp6rxTtPFUZfKIwpzm4IoMfaYQLWgmlG5FME2gdBgm+J7J+rtS/XBbaVLsR7bpPQnpMFlo2doWaVceHk9+MkyguZNCJ1He+kuHTWyQAzNM5YSUg/GlTk9ZunAsg1qELVOhUSAK0LABIJHLKbqaEbHZLL1VA3VgqoiOKXYiS+HRyaEKgsfIqX64HYWbLRXy/qWoylIV9gudL1OWBNgBgTNmxA6b4txDT4gi3Ri7xFSLxtXpmmYnzAcWDZgY8d503LFogz5sbonDgkKcxGsWsE1OI+rcQtlgBBCSOKD1mtqYpIU8cTvBmAT0yZe+zUzeY92fYjTtGipXLhuR0ePoHk0ofNWBX+lo8Z7pAZDk8mEw5L7dVyZZoE/pTewbI6SNbiAL5xeygW4xPRuLCGbhcO4RIeTMFYHEJkYyEO9HmJfXMDEj/LaH781wHHZEtqSQ/69UnGpzH7LKIAZEDSPJnTesJTUa+rwTepI9dLJEawYV+ZkRn9g+QirD8vF8Mq0jFQ29js6kCS3E1+jZIhgPNanHdHFqFvPJLHqFwQqbIA4jhDxcNsOCCQLDomaL/dr5lyJaJU6FxPFjO3JOh3kVMcROo8u+C+jo05GjMF3P3/FuDLn5x2M04xXULPwaS6hBYki+MrMdZJSgPHlcB7nCR5bJ9Kr5ACUn9jk5kivdd8tk95SOGrtqu9lr2IhK65ZtEl7ZKrp7DrqwZfRUSN1el7+7NJxZbywOC8neNKTch5vsTEMNsoCCqHBCqIPRjIPkm0BjvFODGtto99rCl+d3wmHkW0FPdpZtC7MMcVtGFQjJLX5bdQ2+x9ypdc313uj8xlsrfuLgWXz1cRhZvJYX0iNVBRcVcmCXZs6aEf3RQF2WI/TcCbKmGU3IOoDJGDdDub0+hYckt6PlGu2BcxmhbTdj/klhccLGJMcqRjMJP1jW2ETqLSWJ/29MAoORluJ+6LPffBZbi5gqi5h6catQpmOT7/OFf5UorRpLzCqcMltBLhwd1are3kztrSzXO0LUbXRQcdLh/RdSZ+swRm819REDrtqzC4es6Gw4JCKlSnjYVpo0xeq33PrADbFLL3RuCmObVmPN+24kfa+AojDuM4umKe2QwCf6EN906HwjujaitDs5o0s1y+k3lgbT2W2i7FJdnwbLXhJUBq/9liTctSmFC/0OqUinb0QddTWamtjbHRFuWJJ6NpqZ8vO3fZJ37Db+2GkaPYLGHs7XTTdiFQJ68SkVJFVmY6McR5UycflNCsccHFaV9FNbR4NttLxw4pQ7wJd066Z0ohVbzihaxHVExd/ay04oxUKWt+AsdiQ9OUyZ2krzN19IZIwafSTFgIBnMV73ADj7V/K8u1MaY2sJp2HWm0f41tqwajEvdHWOJs510MaAqN4aoSiPCXtN2KSi46dUxHdaMquar82O1x5jqhDGvqmoE9LfxcY3zqA7/x3HA67r9ZG4O6Cuxu12/+TP+eLP+I+HErqDDCDVmBDO4larujNe7x8om2rMug0MX0rL1+IWwdwfR+p1TNTyNmVJ85ljWzbWuGv8/C7HD/izjkHNZNYlhZcUOKVzKFUxsxxN/kax+8zPWPSFKw80rJr9Tizyj3o1gEsdwgWGoxPezDdZ1TSENE1dLdNvuKL+I84nxKesZgxXVA1VA1OcL49dFlpFV5yJMhzyCmNQ+a4BqusPJ2bB+xo8V9u3x48VVIEPS/mc3DvAbXyoYr6VgDfh5do5hhHOCXMqBZUPhWYbWZECwVJljLgMUWOCB4MUuMaxGNUQDVI50TQ+S3kFgIcu2qKkNSHVoM0SHsgoZxP2d5HH8B9woOk4x5bPkKtAHucZsdykjxuIpbUrSILgrT8G7G5oCW+K0990o7E3T6AdW4TilH5kDjds+H64kS0mz24grtwlzDHBJqI8YJQExotPvoC4JBq0lEjjQkyBZ8oH2LnRsQ4Hu1QsgDTJbO8fQDnllitkxuVskoiKbRF9VwzMDvxHAdwB7mD9yCplhHFEyUWHx3WtwCbSMMTCUCcEmSGlg4gTXkHpZXWQ7kpznK3EmCHiXInqndkQjunG5kxTKEeGye7jWz9cyMR2mGiFQ15ENRBTbCp+Gh86vAyASdgmJq2MC6hoADQ3GosP0QHbnMHjyBQvQqfhy/BUbeHd5WY/G/9LK/8Ka8Jd7UFeNWEZvzPb458Dn8DGLOe3/wGL/4xP+HXlRt+M1PE2iLhR8t+lfgxsuh7AfO2AOf+owWhSZRYQbd622hbpKWKuU+XuvNzP0OseRDa+mObgDHJUSc/pKx31QdKffQ5OIJpt8GWjlgTwMc/w5MPCR/yl1XC2a2Yut54SvOtMev55Of45BOat9aWG27p2ZVORRvnEk1hqWMVUmqa7S2YtvlIpspuF1pt0syuZS2NV14mUidCSfzQzg+KqvIYCMljIx2YK2AO34fX4GWdu5xcIAb8MzTw+j/lyWM+Dw/gjs4GD6ehNgA48kX/AI7XXM/XAN4WHr+9ntywqoCakCqmKP0rmQrJJEErG2Upg1JObr01lKQy4jskWalKYfJ/EDLMpjNSHFEUAde2fltaDgmrNaWQ9+AAb8I5vKjz3L1n1LriB/BXkG/wwR9y/oRX4LlioHA4LzP2inzRx/DWmutRweFjeP3tNeSGlaE1Fde0OS11yOpmbIp2u/jF1n2RRZviJM0yBT3IZl2HWImKjQOxIyeU325b/qWyU9Moj1o07tS0G7qJDoGHg5m8yeCxMoEH8GU45tnrNM84D2l297DQ9t1YP7jki/7RmutRweEA77/HWXOh3HCxkRgldDQkAjNTMl2Iloc1qN5JfJeeTlyTRzxURTdn1Ixv2uKjs12AbdEWlBtmVdk2k7FFwj07PCZ9XAwW3dG+8xKzNFr4EnwBZpy9Qzhh3jDXebBpYcpuo4fQ44u+fD1dweEnHzI7v0xuuOALRUV8rXpFyfSTQYkhd7IHm07jpyhlkCmI0ALYqPTpUxXS+z4jgDj1Pflvmz5ecuItpIBxyTHpSTGWd9g1ApfD/bvwUhL4nT1EzqgX7cxfCcNmb3mPL/qi9SwTHJ49oj5ZLjccbTG3pRmlYi6JCG0mQrAt1+i2UXTZ2dv9IlQpN5naMYtviaXlTrFpoMsl3bOAFEa8sqPj2WCMrx3Yjx99qFwO59Aw/wgx+HlqNz8oZvA3exRDvuhL1jMQHPaOJ0+XyA3fp1OfM3qObEVdhxjvynxNMXQV4+GJyvOEFqeQBaIbbO7i63rpxCltdZShPFxkjM2FPVkn3TG+Rp9pO3l2RzFegGfxGDHIAh8SteR0C4HopXzRF61nheDw6TFN05Ebvq8M3VKKpGjjO6r7nhudTEGMtYM92HTDaR1FDMXJ1eThsbKfywyoWwrzRSXkc51flG3vIid62h29bIcFbTGhfV+faaB+ohj7dPN0C2e2lC96+XouFByen9AsunLDJZ9z7NExiUc0OuoYW6UZkIyx2YUR2z6/TiRjyKMx5GbbjLHvHuf7YmtKghf34LJfx63Yg8vrvN2zC7lY0x0tvKezo4HmGYDU+Gab6dFL+KI761lDcNifcjLrrr9LWZJctG1FfU1uwhoQE22ObjdfkSzY63CbU5hzs21WeTddH2BaL11Gi7lVdlxP1nkxqhnKhVY6knS3EPgVGg1JpN5cP/hivujOelhXcPj8HC/LyI6MkteVjlolBdMmF3a3DbsuAYhL44dxzthWSN065xxUd55Lmf0wRbOYOqH09/o9WbO2VtFdaMb4qBgtFJoT1SqoN8wPXMoXLb3p1PUEhxfnnLzGzBI0Ku7FxrKsNJj/8bn/H8fPIVOd3rfrklUB/DOeO+nkghgSPzrlPxluCMtOnDL4Yml6dK1r3vsgMxgtPOrMFUZbEUbTdIzii5beq72G4PD0DKnwjmBULUVFmy8t+k7fZ3pKc0Q4UC6jpVRqS9Umv8bxw35flZVOU1X7qkjnhZlsMbk24qQ6Hz7QcuL6sDC0iHHki96Uh2UdvmgZnjIvExy2TeJdMDZNSbdZyAHe/Yd1xsQhHiKzjh7GxQ4yqMPaywPkjMamvqrYpmO7Knad+ZQC5msCuAPWUoxrxVhrGv7a+KLXFhyONdTMrZ7ke23qiO40ZJUyzgYyX5XyL0mV7NiUzEs9mjtbMN0dERqwyAJpigad0B3/zRV7s4PIfXSu6YV/MK7+OrYe/JvfGMn/PHJe2fyUdtnFrKRNpXV0Y2559aWPt/G4BlvjTMtXlVIWCnNyA3YQBDmYIodFz41PvXPSa6rq9lWZawZ4dP115HXV/M/tnFkkrBOdzg6aP4pID+MZnTJ1SuuB6iZlyiox4HT2y3YBtkUKWooacBQUDTpjwaDt5poBHl1/HXltwP887lKKXxNUEyPqpGTyA699UqY/lt9yGdlUKra0fFWS+36iylVWrAyd7Uw0CZM0z7xKTOduznLIjG2Hx8cDPLb+OvK6Bv7n1DYci4CxUuRxrjBc0bb4vD3rN5Zz36ntLb83eVJIB8LiIzCmn6SMPjlX+yNlTjvIGjs+QzHPf60Aj62/jrzG8j9vYMFtm1VoRWCJdmw7z9N0t+c8cxZpPeK4aTRicS25QhrVtUp7U578chk4q04Wx4YoQSjFryUlpcQ1AbxZ/XVMknIU//OGl7Q6z9Zpxi0+3yFhSkjUDpnCIUhLWVX23KQ+L9vKvFKI0ZWFQgkDLvBoylrHNVmaw10zwCPrr5tlodfnf94EWnQ0lFRWy8pW9LbkLsyUVDc2NSTHGDtnD1uMtchjbCeb1mpxFP0YbcClhzdLu6lfO8Bj6q+bdT2sz/+8SZCV7VIxtt0DUn9L7r4cLYWDSXnseEpOGFuty0qbOVlS7NNzs5FOGJUqQpl2Q64/yBpZf90sxbE+//PGdZ02HSipCbmD6NItmQ4Lk5XUrGpDMkhbMm2ZVheNYV+VbUWTcv99+2NyX1VoafSuC+AN6q9bFIMv5X/eagNWXZxEa9JjlMwNWb00akGUkSoepp1/yRuuqHGbUn3UdBSTxBU6SEVklzWRUkPndVvw2PrrpjvxOvzPmwHc0hpmq82npi7GRro8dXp0KXnUQmhZbRL7NEVp1uuZmO45vuzKsHrktS3GLWXODVjw+vXXLYx4Hf7njRPd0i3aoAGX6W29GnaV5YdyDj9TFkakje7GHYzDoObfddHtOSpoi2SmzJHrB3hM/XUDDEbxP2/oosszcRlehWXUvzHv4TpBVktHqwenFo8uLVmy4DKLa5d3RtLrmrM3aMFr1183E4sewf+85VWeg1c5ag276NZrM9IJVNcmLEvDNaV62aq+14IAOGFsBt973Ra8Xv11YzXwNfmft7Jg2oS+XOyoC8/cwzi66Dhmgk38kUmP1CUiYWOX1bpD2zWXt2FCp7uq8703APAa9dfNdscR/M/bZLIyouVxqJfeWvG9Je+JVckHQ9+CI9NWxz+blX/KYYvO5n2tAP/vrlZ7+8/h9y+9qeB/Hnt967e5mevX10rALDWK//FaAT5MXdBXdP0C/BAes792c40H+AiAp1e1oH8HgH94g/Lttx1gp63op1eyoM/Bvw5/G/7xFbqJPcCXnmBiwDPb/YKO4FX4OjyCb289db2/Noqicw4i7N6TVtoz8tNwDH+8x/i6Ae7lmaQVENzJFb3Di/BFeAwz+Is9SjeQySpPqbLFlNmyz47z5a/AF+AYFvDmHqibSXTEzoT4Gc3OALaqAP4KPFUJ6n+1x+rGAM6Zd78bgJ0a8QN4GU614vxwD9e1Amy6CcskNrczLx1JIp6HE5UZD/DBHrFr2oNlgG4Odv226BodoryjGJ9q2T/AR3vQrsOCS0ctXZi3ruLlhpFDJYl4HmYtjQCP9rhdn4suySLKDt6wLcC52h8xPlcjju1fn+yhuw4LZsAGUuo2b4Fx2UwQu77uqRHXGtg92aN3tQCbFexc0uk93vhTXbct6y7MulLycoUljx8ngDMBg1tvJjAazpEmOtxlzclvj1vQf1Tx7QlPDpGpqgtdSKz/d9/hdy1vTfFHSmC9dGDZbLiezz7Ac801HirGZsWjydfZyPvHXL/Y8Mjzg8BxTZiuwKz4Eb8sBE9zznszmjvFwHKPIWUnwhqfVRcd4Ck0K6ate48m1oOfrX3/yOtvAsJ8zsPAM89sjnddmuLuDPjX9Bu/L7x7xpMzFk6nWtyQfPg278Gn4Aekz2ZgOmU9eJ37R14vwE/BL8G3aibCiWMWWDQ0ZtkPMnlcGeAu/Ag+8ZyecU5BPuy2ILD+sQqyZhAKmn7XZd+jIMTN9eBL7x95xVLSX4On8EcNlXDqmBlqS13jG4LpmGbkF/0CnOi3H8ETOIXzmnmtb0a16Tzxj1sUvQCBiXZGDtmB3KAefPH94xcUa/6vwRn80GOFyjEXFpba4A1e8KQfFF+259tx5XS4egYn8fQsLGrqGrHbztr+uByTahWuL1NUGbDpsnrwBfePPwHHIf9X4RnM4Z2ABWdxUBlqQ2PwhuDxoS0vvqB1JzS0P4h2nA/QgTrsJFn+Y3AOjs9JFC07CGWX1oNX3T/yHOzgDjwPn1PM3g9Jk9lZrMEpxnlPmBbjyo2+KFXRU52TJM/2ALcY57RUzjObbjqxVw++4P6RAOf58pcVsw9Daje3htriYrpDOonre3CudSe6bfkTEgHBHuDiyu5MCsc7BHhYDx7ePxLjqigXZsw+ijMHFhuwBmtoTPtOxOrTvYJDnC75dnUbhfwu/ZW9AgYd+peL68HD+0emKquiXHhWjJg/UrkJYzuiaL3E9aI/ytrCvAd4GcYZMCkSQxfUg3v3j8c4e90j5ZTPdvmJJGHnOCI2nHS8081X013pHuBlV1gB2MX1YNmWLHqqGN/TWmG0y6clJWthxNUl48q38Bi8vtMKyzzpFdSDhxZ5WBA5ZLt8Jv3895DduBlgbPYAj8C4B8hO68FDkoh5lydC4FiWvBOVqjYdqjiLv92t8yPDjrDaiHdUD15qkSURSGmXJwOMSxWAXYwr3zaAufJ66l+94vv3AO+vPcD7aw/w/toDvL/2AO+vPcD7aw/wHuD9tQd4f+0B3l97gPfXHuD9tQd4f+0B3l97gG8LwP8G/AL8O/A5OCq0Ys2KIdv/qOIXG/4mvFAMF16gZD+2Xvu/B8as5+8bfllWyg0zaNO5bfXj6vfhhwD86/Aq3NfRS9t9WPnhfnvCIw/CT8GLcFTMnpntdF/z9V+PWc/vWoIH+FL3Znv57PitcdGP4R/C34avw5fgRVUInCwbsn1yyA8C8zm/BH8NXoXnVE6wVPjdeCI38kX/3+Ct9dbz1pTmHFRu+Hm4O9Ch3clr99negxfwj+ER/DR8EV6B5+DuQOnTgUw5rnkY+FbNU3gNXh0o/JYTuWOvyBf9FvzX663HH/HejO8LwAl8Hl5YLTd8q7sqA3wbjuExfAFegQdwfyDoSkWY8swzEf6o4Qyewefg+cHNbqMQruSL/u/WWc+E5g7vnnEXgDmcDeSGb/F4cBcCgT+GGRzDU3hZYburAt9TEtHgbM6JoxJ+6NMzzTcf6c2bycv2+KK/f+l6LBzw5IwfqZJhA3M472pWT/ajKxnjv4AFnMEpnBTPND6s2J7qHbPAqcMK74T2mZ4VGB9uJA465It+/eL1WKhYOD7xHOkr1ajK7d0C4+ke4Hy9qXZwpgLr+Znm/uNFw8xQOSy8H9IzjUrd9+BIfenYaylf9FsXr8fBAadnPIEDna8IBcwlxnuA0/Wv6GAWPd7dDIKjMdSWueAsBj4M7TOd06qBbwDwKr7oleuxMOEcTuEZTHWvDYUO7aHqAe0Bbq+HEFRzOz7WVoTDQkVds7A4sIIxfCQdCefFRoIOF/NFL1mPab/nvOakSL/Q1aFtNpUb/nFOVX6gzyg/1nISyDfUhsokIzaBR9Kxm80s5mK+6P56il1jXic7nhQxsxSm3OwBHl4fFdLqi64nDQZvqE2at7cWAp/IVvrN6/BFL1mPhYrGMBfOi4PyjuSGf6wBBh7p/FZTghCNWGgMzlBbrNJoPJX2mW5mwZfyRffXo7OFi5pZcS4qZUrlViptrXtw+GQoyhDPS+ANjcGBNRiLCQDPZPMHuiZfdFpPSTcQwwKYdRNqpkjm7AFeeT0pJzALgo7g8YYGrMHS0iocy+YTm2vyRUvvpXCIpQ5pe666TJrcygnScUf/p0NDs/iAI/nqDHC8TmQT8x3NF91l76oDdQGwu61Z6E0ABv7uO1dbf/37Zlv+Zw/Pbh8f1s4Avur6657/+YYBvur6657/+YYBvur6657/+YYBvur6657/+aYBvuL6657/+VMA8FXWX/f8zzcN8BXXX/f8zzcNMFdbf93zP38KLPiK6697/uebtuArrr/u+Z9vGmCusP6653/+1FjwVdZf9/zPN7oHX339dc//fNMu+irrr3v+50+Bi+Zq6697/uebA/jz8Pudf9ht/fWv517J/XUzAP8C/BAeX9WCDrUpZ3/dEMBxgPcfbtTVvsYV5Yn32u03B3Ac4P3b8I+vxNBKeeL9dRMAlwO83959qGO78sT769oB7g3w/vGVYFzKE++v6wV4OMD7F7tckFkmT7y/rhHgpQO8b+4Y46XyxPvrugBeNcB7BRiX8sT767oAvmCA9woAHsoT76+rBJjLBnh3txOvkifeX1dswZcO8G6N7sXyxPvr6i340gHe3TnqVfLE++uKAb50gHcXLnrX8sR7gNdPRqwzwLu7Y/FO5Yn3AK9jXCMGeHdgxDuVJ75VAI8ljP7PAb3/RfjcZfePHBB+79dpfpH1CanN30d+mT1h9GqAxxJGM5LQeeQ1+Tb+EQJrElLb38VHQ94TRq900aMIo8cSOo+8Dp8QfsB8zpqE1NO3OI9Zrj1h9EV78PqE0WMJnUdeU6E+Jjyk/hbrEFIfeWbvId8H9oTRFwdZaxJGvziW0Hn0gqYB/wyZ0PwRlxJST+BOw9m77Amj14ii1yGM/txYQudN0qDzGe4EqfA/5GJCagsHcPaEPWH0esekSwmjRxM6b5JEcZ4ww50ilvAOFxBSx4yLW+A/YU8YvfY5+ALC6NGEzhtmyZoFZoarwBLeZxUhtY4rc3bKnjB6TKJjFUHzJoTOozF2YBpsjcyxDgzhQ1YRUse8+J4wenwmaylB82hC5w0zoRXUNXaRBmSMQUqiWSWkLsaVqc/ZE0aPTFUuJWgeTei8SfLZQeMxNaZSIzbII4aE1Nmr13P2hNHjc9E9guYNCZ032YlNwESMLcZiLQHkE4aE1BFg0yAR4z1h9AiAGRA0jyZ03tyIxWMajMPWBIsxYJCnlITU5ShiHYdZ94TR4wCmSxg9jtB5KyPGYzymAYexWEMwAPIsAdYdV6aObmNPGD0aYLoEzaMJnTc0Ygs+YDw0GAtqxBjkuP38bMRWCHn73xNGjz75P73WenCEJnhwyVe3AEe8TtKdJcYhBl97wuhNAObK66lvD/9J9NS75v17wuitAN5fe4D31x7g/bUHeH/tAd5fe4D3AO+vPcD7aw/w/toDvL/2AO+vPcD7aw/w/toDvAd4f/24ABzZ8o+KLsSLS+Pv/TqTb3P4hKlQrTGh+fbIBT0Axqznnb+L/V2mb3HkN5Mb/nEHeK7d4IcDld6lmDW/iH9E+AH1MdOw/Jlu2T1xNmY98sv4wHnD7D3uNHu54WUuOsBTbQuvBsPT/UfzNxGYzwkP8c+Yz3C+r/i6DcyRL/rZ+utRwWH5PmfvcvYEt9jLDS/bg0/B64DWKrQM8AL8FPwS9beQCe6EMKNZYJol37jBMy35otdaz0Bw2H/C2Smc7+WGB0HWDELBmOByA3r5QONo4V+DpzR/hFS4U8wMW1PXNB4TOqYz9urxRV++ntWCw/U59Ty9ebdWbrgfRS9AYKKN63ZokZVygr8GZ/gfIhZXIXPsAlNjPOLBby5c1eOLvmQ9lwkOy5x6QV1j5TYqpS05JtUgUHUp5toHGsVfn4NX4RnMCe+AxTpwmApTYxqMxwfCeJGjpXzRF61nbcHhUBPqWze9svwcHJ+S6NPscKrEjug78Dx8Lj3T8D4YxGIdxmJcwhi34fzZUr7olevZCw5vkOhoClq5zBPZAnygD/Tl9EzDh6kl3VhsHYcDEb+hCtJSvuiV69kLDm+WycrOTArHmB5/VYyP6jOVjwgGawk2zQOaTcc1L+aLXrKeveDwZqlKrw8U9Y1p66uK8dEzdYwBeUQAY7DbyYNezBfdWQ97weEtAKYQg2xJIkuveAT3dYeLGH+ShrWNwZgN0b2YL7qznr3g8JYAo5bQBziPjx7BPZ0d9RCQp4UZbnFdzBddor4XHN4KYMrB2qHFRIzzcLAHQZ5the5ovui94PCWAPefaYnxIdzRwdHCbuR4B+tbiy96Lzi8E4D7z7S0mEPd+eqO3cT53Z0Y8SV80XvB4Z0ADJi/f7X113f+7p7/+UYBvur6657/+YYBvur6657/+aYBvuL6657/+aYBvuL6657/+aYBvuL6657/+aYBvuL6657/+VMA8FXWX/f8z58OgK+y/rrnf75RgLna+uue//lTA/CV1V/3/M837aKvvv6653++UQvmauuve/7nTwfAV1N/3fM/fzr24Cuuv+75nz8FFnxl9dc9//MOr/8/glixwRuUfM4AAAAASUVORK5CYII=';\n\n\t}\n\n\tgetSearchTexture() {\n\n\t\treturn 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAAAhCAAAAABIXyLAAAAAOElEQVRIx2NgGAWjYBSMglEwEICREYRgFBZBqDCSLA2MGPUIVQETE9iNUAqLR5gIeoQKRgwXjwAAGn4AtaFeYLEAAAAASUVORK5CYII=';\n\n\t}\n\n\tdispose() {\n\n\t\tthis.edgesRT.dispose();\n\t\tthis.weightsRT.dispose();\n\n\t\tthis.areaTexture.dispose();\n\t\tthis.searchTexture.dispose();\n\n\t\tthis.materialEdges.dispose();\n\t\tthis.materialWeights.dispose();\n\t\tthis.materialBlend.dispose();\n\n\t\tthis.fsQuad.dispose();\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNzM3LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBRWU7O0FBRWY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBLGdCQUFnQixhQUFhO0FBQzdCLGtCQUFrQixXQUFXLDZCQUFPOztBQUVwQyxFQUFFOztBQUVGOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxrRkFBa0Y7QUFDbEYsa0ZBQWtGO0FBQ2xGLGtGQUFrRjtBQUNsRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBLGdCQUFnQixhQUFhO0FBQzdCLGFBQWEsYUFBYTtBQUMxQixlQUFlLGFBQWE7QUFDNUIsa0JBQWtCLFdBQVcsNkJBQU87O0FBRXBDLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSx1RkFBdUY7QUFDdkYseUZBQXlGOztBQUV6RjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsb0JBQW9CLDJCQUEyQixTQUFTO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLHFDQUFxQztBQUNyQzs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsb0JBQW9CLDJCQUEyQixTQUFTO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0IsMkJBQTJCLFNBQVM7QUFDeEQ7QUFDQSwrQ0FBK0M7QUFDL0M7QUFDQTs7QUFFQSxzQ0FBc0M7QUFDdEMsK0JBQStCO0FBQy9CLHFDQUFxQztBQUNyQywrRUFBK0U7O0FBRS9FO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0IsMkJBQTJCLFNBQVM7QUFDeEQ7QUFDQSwrQ0FBK0M7QUFDL0M7QUFDQTs7QUFFQSxzQ0FBc0M7QUFDdEMsK0JBQStCO0FBQy9CLHFDQUFxQztBQUNyQywrRUFBK0U7O0FBRS9FO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsc0JBQXNCO0FBQ3RCOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDhCQUE4QjtBQUM5Qjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG9DQUFvQztBQUNwQzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxzQkFBc0I7QUFDdEI7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLDhCQUE4QjtBQUM5Qjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG9DQUFvQztBQUNwQzs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGdCQUFnQixhQUFhO0FBQzdCLGNBQWMsYUFBYTtBQUMzQixrQkFBa0IsV0FBVyw2QkFBTzs7QUFFcEMsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsaUZBQWlGO0FBQ2pGLGlGQUFpRjtBQUNqRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUM7QUFDdkMsdUNBQXVDOztBQUV2QztBQUNBLDhDQUE4QztBQUM5QztBQUNBLE1BQU07QUFDTjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFK0Q7OztBQ3pjaEQ7QUFDa0M7QUFDVTtBQUNFO0FBQ0Y7O0FBRTNELHVCQUF1QixnQkFBSTs7QUFFM0I7O0FBRUE7O0FBRUE7O0FBRUEscUJBQXFCLHVDQUFpQjtBQUN0QztBQUNBLFNBQVMsbUNBQWE7QUFDdEIsSUFBSTtBQUNKOztBQUVBLHVCQUF1Qix1Q0FBaUI7QUFDeEM7QUFDQSxTQUFTLG1DQUFhO0FBQ3RCLElBQUk7QUFDSjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLHlCQUF5Qiw2QkFBTztBQUNoQztBQUNBO0FBQ0EsK0JBQStCLGtDQUFZO0FBQzNDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsMkJBQTJCLDZCQUFPO0FBQ2xDO0FBQ0E7QUFDQSxpQ0FBaUMsbUNBQWE7QUFDOUMsaUNBQWlDLG1DQUFhO0FBQzlDO0FBQ0E7O0FBRUE7O0FBRUEsdUJBQXVCLG1DQUFhLFFBQVEsZUFBZTs7QUFFM0Q7O0FBRUEsMkJBQTJCLG9DQUFjO0FBQ3pDLDZCQUE2QixFQUFFLGVBQWU7QUFDOUM7QUFDQSxpQkFBaUIsZUFBZTtBQUNoQyxtQkFBbUIsZUFBZTtBQUNsQyxJQUFJOztBQUVKOztBQUVBLHlCQUF5QixtQ0FBYSxRQUFRLGlCQUFpQjs7QUFFL0Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsNkJBQTZCLG9DQUFjO0FBQzNDLDZCQUE2QixFQUFFLGlCQUFpQjtBQUNoRDtBQUNBLGlCQUFpQixpQkFBaUI7QUFDbEMsbUJBQW1CLGlCQUFpQjtBQUNwQyxJQUFJOztBQUVKOztBQUVBLHVCQUF1QixtQ0FBYSxRQUFRLGVBQWU7O0FBRTNEO0FBQ0E7O0FBRUEsMkJBQTJCLG9DQUFjO0FBQ3pDO0FBQ0EsaUJBQWlCLGVBQWU7QUFDaEMsbUJBQW1CLGVBQWU7QUFDbEMsSUFBSTs7QUFFSixvQkFBb0IsMEJBQWM7O0FBRWxDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSx5QkFBeUI7O0FBRXpCOztBQUVBOztBQUVBLHlCQUF5Qjs7QUFFekI7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFb0IiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9zaGFkZXJzL1NNQUFTaGFkZXIuanM/NDdmOSIsIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9wb3N0cHJvY2Vzc2luZy9TTUFBUGFzcy5qcz84YjFmIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG5cdFZlY3RvcjJcbn0gZnJvbSAndGhyZWUnO1xuXG4vKipcbiAqIFdlYkdMIHBvcnQgb2YgU3VicGl4ZWwgTW9ycGhvbG9naWNhbCBBbnRpYWxpYXNpbmcgKFNNQUEpIHYyLjhcbiAqIFByZXNldDogU01BQSAxeCBNZWRpdW0gKHdpdGggY29sb3IgZWRnZSBkZXRlY3Rpb24pXG4gKiBodHRwczovL2dpdGh1Yi5jb20vaXJ5b2t1L3NtYWEvcmVsZWFzZXMvdGFnL3YyLjhcbiAqL1xuXG5jb25zdCBTTUFBRWRnZXNTaGFkZXIgPSB7XG5cblx0bmFtZTogJ1NNQUFFZGdlc1NoYWRlcicsXG5cblx0ZGVmaW5lczoge1xuXG5cdFx0J1NNQUFfVEhSRVNIT0xEJzogJzAuMSdcblxuXHR9LFxuXG5cdHVuaWZvcm1zOiB7XG5cblx0XHQndERpZmZ1c2UnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0J3Jlc29sdXRpb24nOiB7IHZhbHVlOiBuZXcgVmVjdG9yMiggMSAvIDEwMjQsIDEgLyA1MTIgKSB9XG5cblx0fSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR1bmlmb3JtIHZlYzIgcmVzb2x1dGlvbjtcblxuXHRcdHZhcnlpbmcgdmVjMiB2VXY7XG5cdFx0dmFyeWluZyB2ZWM0IHZPZmZzZXRbIDMgXTtcblxuXHRcdHZvaWQgU01BQUVkZ2VEZXRlY3Rpb25WUyggdmVjMiB0ZXhjb29yZCApIHtcblx0XHRcdHZPZmZzZXRbIDAgXSA9IHRleGNvb3JkLnh5eHkgKyByZXNvbHV0aW9uLnh5eHkgKiB2ZWM0KCAtMS4wLCAwLjAsIDAuMCwgIDEuMCApOyAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgc2lnbiBpbiBXIGNvbXBvbmVudFxuXHRcdFx0dk9mZnNldFsgMSBdID0gdGV4Y29vcmQueHl4eSArIHJlc29sdXRpb24ueHl4eSAqIHZlYzQoICAxLjAsIDAuMCwgMC4wLCAtMS4wICk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduIGluIFcgY29tcG9uZW50XG5cdFx0XHR2T2Zmc2V0WyAyIF0gPSB0ZXhjb29yZC54eXh5ICsgcmVzb2x1dGlvbi54eXh5ICogdmVjNCggLTIuMCwgMC4wLCAwLjAsICAyLjAgKTsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHNpZ24gaW4gVyBjb21wb25lbnRcblx0XHR9XG5cblx0XHR2b2lkIG1haW4oKSB7XG5cblx0XHRcdHZVdiA9IHV2O1xuXG5cdFx0XHRTTUFBRWRnZURldGVjdGlvblZTKCB2VXYgKTtcblxuXHRcdFx0Z2xfUG9zaXRpb24gPSBwcm9qZWN0aW9uTWF0cml4ICogbW9kZWxWaWV3TWF0cml4ICogdmVjNCggcG9zaXRpb24sIDEuMCApO1xuXG5cdFx0fWAsXG5cblx0ZnJhZ21lbnRTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR1bmlmb3JtIHNhbXBsZXIyRCB0RGlmZnVzZTtcblxuXHRcdHZhcnlpbmcgdmVjMiB2VXY7XG5cdFx0dmFyeWluZyB2ZWM0IHZPZmZzZXRbIDMgXTtcblxuXHRcdHZlYzQgU01BQUNvbG9yRWRnZURldGVjdGlvblBTKCB2ZWMyIHRleGNvb3JkLCB2ZWM0IG9mZnNldFszXSwgc2FtcGxlcjJEIGNvbG9yVGV4ICkge1xuXHRcdFx0dmVjMiB0aHJlc2hvbGQgPSB2ZWMyKCBTTUFBX1RIUkVTSE9MRCwgU01BQV9USFJFU0hPTEQgKTtcblxuXHRcdFx0Ly8gQ2FsY3VsYXRlIGNvbG9yIGRlbHRhczpcblx0XHRcdHZlYzQgZGVsdGE7XG5cdFx0XHR2ZWMzIEMgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4LCB0ZXhjb29yZCApLnJnYjtcblxuXHRcdFx0dmVjMyBDbGVmdCA9IHRleHR1cmUyRCggY29sb3JUZXgsIG9mZnNldFswXS54eSApLnJnYjtcblx0XHRcdHZlYzMgdCA9IGFicyggQyAtIENsZWZ0ICk7XG5cdFx0XHRkZWx0YS54ID0gbWF4KCBtYXgoIHQuciwgdC5nICksIHQuYiApO1xuXG5cdFx0XHR2ZWMzIEN0b3AgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4LCBvZmZzZXRbMF0uencgKS5yZ2I7XG5cdFx0XHR0ID0gYWJzKCBDIC0gQ3RvcCApO1xuXHRcdFx0ZGVsdGEueSA9IG1heCggbWF4KCB0LnIsIHQuZyApLCB0LmIgKTtcblxuXHRcdFx0Ly8gV2UgZG8gdGhlIHVzdWFsIHRocmVzaG9sZDpcblx0XHRcdHZlYzIgZWRnZXMgPSBzdGVwKCB0aHJlc2hvbGQsIGRlbHRhLnh5ICk7XG5cblx0XHRcdC8vIFRoZW4gZGlzY2FyZCBpZiB0aGVyZSBpcyBubyBlZGdlOlxuXHRcdFx0aWYgKCBkb3QoIGVkZ2VzLCB2ZWMyKCAxLjAsIDEuMCApICkgPT0gMC4wIClcblx0XHRcdFx0ZGlzY2FyZDtcblxuXHRcdFx0Ly8gQ2FsY3VsYXRlIHJpZ2h0IGFuZCBib3R0b20gZGVsdGFzOlxuXHRcdFx0dmVjMyBDcmlnaHQgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4LCBvZmZzZXRbMV0ueHkgKS5yZ2I7XG5cdFx0XHR0ID0gYWJzKCBDIC0gQ3JpZ2h0ICk7XG5cdFx0XHRkZWx0YS56ID0gbWF4KCBtYXgoIHQuciwgdC5nICksIHQuYiApO1xuXG5cdFx0XHR2ZWMzIENib3R0b20gID0gdGV4dHVyZTJEKCBjb2xvclRleCwgb2Zmc2V0WzFdLnp3ICkucmdiO1xuXHRcdFx0dCA9IGFicyggQyAtIENib3R0b20gKTtcblx0XHRcdGRlbHRhLncgPSBtYXgoIG1heCggdC5yLCB0LmcgKSwgdC5iICk7XG5cblx0XHRcdC8vIENhbGN1bGF0ZSB0aGUgbWF4aW11bSBkZWx0YSBpbiB0aGUgZGlyZWN0IG5laWdoYm9yaG9vZDpcblx0XHRcdGZsb2F0IG1heERlbHRhID0gbWF4KCBtYXgoIG1heCggZGVsdGEueCwgZGVsdGEueSApLCBkZWx0YS56ICksIGRlbHRhLncgKTtcblxuXHRcdFx0Ly8gQ2FsY3VsYXRlIGxlZnQtbGVmdCBhbmQgdG9wLXRvcCBkZWx0YXM6XG5cdFx0XHR2ZWMzIENsZWZ0bGVmdCAgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4LCBvZmZzZXRbMl0ueHkgKS5yZ2I7XG5cdFx0XHR0ID0gYWJzKCBDIC0gQ2xlZnRsZWZ0ICk7XG5cdFx0XHRkZWx0YS56ID0gbWF4KCBtYXgoIHQuciwgdC5nICksIHQuYiApO1xuXG5cdFx0XHR2ZWMzIEN0b3B0b3AgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4LCBvZmZzZXRbMl0uencgKS5yZ2I7XG5cdFx0XHR0ID0gYWJzKCBDIC0gQ3RvcHRvcCApO1xuXHRcdFx0ZGVsdGEudyA9IG1heCggbWF4KCB0LnIsIHQuZyApLCB0LmIgKTtcblxuXHRcdFx0Ly8gQ2FsY3VsYXRlIHRoZSBmaW5hbCBtYXhpbXVtIGRlbHRhOlxuXHRcdFx0bWF4RGVsdGEgPSBtYXgoIG1heCggbWF4RGVsdGEsIGRlbHRhLnogKSwgZGVsdGEudyApO1xuXG5cdFx0XHQvLyBMb2NhbCBjb250cmFzdCBhZGFwdGF0aW9uIGluIGFjdGlvbjpcblx0XHRcdGVkZ2VzLnh5ICo9IHN0ZXAoIDAuNSAqIG1heERlbHRhLCBkZWx0YS54eSApO1xuXG5cdFx0XHRyZXR1cm4gdmVjNCggZWRnZXMsIDAuMCwgMC4wICk7XG5cdFx0fVxuXG5cdFx0dm9pZCBtYWluKCkge1xuXG5cdFx0XHRnbF9GcmFnQ29sb3IgPSBTTUFBQ29sb3JFZGdlRGV0ZWN0aW9uUFMoIHZVdiwgdk9mZnNldCwgdERpZmZ1c2UgKTtcblxuXHRcdH1gXG5cbn07XG5cbmNvbnN0IFNNQUFXZWlnaHRzU2hhZGVyID0ge1xuXG5cdG5hbWU6ICdTTUFBV2VpZ2h0c1NoYWRlcicsXG5cblx0ZGVmaW5lczoge1xuXG5cdFx0J1NNQUFfTUFYX1NFQVJDSF9TVEVQUyc6ICc4Jyxcblx0XHQnU01BQV9BUkVBVEVYX01BWF9ESVNUQU5DRSc6ICcxNicsXG5cdFx0J1NNQUFfQVJFQVRFWF9QSVhFTF9TSVpFJzogJyggMS4wIC8gdmVjMiggMTYwLjAsIDU2MC4wICkgKScsXG5cdFx0J1NNQUFfQVJFQVRFWF9TVUJURVhfU0laRSc6ICcoIDEuMCAvIDcuMCApJ1xuXG5cdH0sXG5cblx0dW5pZm9ybXM6IHtcblxuXHRcdCd0RGlmZnVzZSc6IHsgdmFsdWU6IG51bGwgfSxcblx0XHQndEFyZWEnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0J3RTZWFyY2gnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0J3Jlc29sdXRpb24nOiB7IHZhbHVlOiBuZXcgVmVjdG9yMiggMSAvIDEwMjQsIDEgLyA1MTIgKSB9XG5cblx0fSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR1bmlmb3JtIHZlYzIgcmVzb2x1dGlvbjtcblxuXHRcdHZhcnlpbmcgdmVjMiB2VXY7XG5cdFx0dmFyeWluZyB2ZWM0IHZPZmZzZXRbIDMgXTtcblx0XHR2YXJ5aW5nIHZlYzIgdlBpeGNvb3JkO1xuXG5cdFx0dm9pZCBTTUFBQmxlbmRpbmdXZWlnaHRDYWxjdWxhdGlvblZTKCB2ZWMyIHRleGNvb3JkICkge1xuXHRcdFx0dlBpeGNvb3JkID0gdGV4Y29vcmQgLyByZXNvbHV0aW9uO1xuXG5cdFx0XHQvLyBXZSB3aWxsIHVzZSB0aGVzZSBvZmZzZXRzIGZvciB0aGUgc2VhcmNoZXMgbGF0ZXIgb24gKHNlZSBAUFNFVURPX0dBVEhFUjQpOlxuXHRcdFx0dk9mZnNldFsgMCBdID0gdGV4Y29vcmQueHl4eSArIHJlc29sdXRpb24ueHl4eSAqIHZlYzQoIC0wLjI1LCAwLjEyNSwgMS4yNSwgMC4xMjUgKTsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHNpZ24gaW4gWSBhbmQgVyBjb21wb25lbnRzXG5cdFx0XHR2T2Zmc2V0WyAxIF0gPSB0ZXhjb29yZC54eXh5ICsgcmVzb2x1dGlvbi54eXh5ICogdmVjNCggLTAuMTI1LCAwLjI1LCAtMC4xMjUsIC0xLjI1ICk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduIGluIFkgYW5kIFcgY29tcG9uZW50c1xuXG5cdFx0XHQvLyBBbmQgdGhlc2UgZm9yIHRoZSBzZWFyY2hlcywgdGhleSBpbmRpY2F0ZSB0aGUgZW5kcyBvZiB0aGUgbG9vcHM6XG5cdFx0XHR2T2Zmc2V0WyAyIF0gPSB2ZWM0KCB2T2Zmc2V0WyAwIF0ueHosIHZPZmZzZXRbIDEgXS55dyApICsgdmVjNCggLTIuMCwgMi4wLCAtMi4wLCAyLjAgKSAqIHJlc29sdXRpb24ueHh5eSAqIGZsb2F0KCBTTUFBX01BWF9TRUFSQ0hfU1RFUFMgKTtcblxuXHRcdH1cblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0dlV2ID0gdXY7XG5cblx0XHRcdFNNQUFCbGVuZGluZ1dlaWdodENhbGN1bGF0aW9uVlMoIHZVdiApO1xuXG5cdFx0XHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XG5cblx0XHR9YCxcblxuXHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2BcblxuXHRcdCNkZWZpbmUgU01BQVNhbXBsZUxldmVsWmVyb09mZnNldCggdGV4LCBjb29yZCwgb2Zmc2V0ICkgdGV4dHVyZTJEKCB0ZXgsIGNvb3JkICsgZmxvYXQoIG9mZnNldCApICogcmVzb2x1dGlvbiwgMC4wIClcblxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHREaWZmdXNlO1xuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHRBcmVhO1xuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHRTZWFyY2g7XG5cdFx0dW5pZm9ybSB2ZWMyIHJlc29sdXRpb247XG5cblx0XHR2YXJ5aW5nIHZlYzIgdlV2O1xuXHRcdHZhcnlpbmcgdmVjNCB2T2Zmc2V0WzNdO1xuXHRcdHZhcnlpbmcgdmVjMiB2UGl4Y29vcmQ7XG5cblx0XHQjaWYgX19WRVJTSU9OX18gPT0gMTAwXG5cdFx0dmVjMiByb3VuZCggdmVjMiB4ICkge1xuXHRcdFx0cmV0dXJuIHNpZ24oIHggKSAqIGZsb29yKCBhYnMoIHggKSArIDAuNSApO1xuXHRcdH1cblx0XHQjZW5kaWZcblxuXHRcdGZsb2F0IFNNQUFTZWFyY2hMZW5ndGgoIHNhbXBsZXIyRCBzZWFyY2hUZXgsIHZlYzIgZSwgZmxvYXQgYmlhcywgZmxvYXQgc2NhbGUgKSB7XG5cdFx0XHQvLyBOb3QgcmVxdWlyZWQgaWYgc2VhcmNoVGV4IGFjY2Vzc2VzIGFyZSBzZXQgdG8gcG9pbnQ6XG5cdFx0XHQvLyBmbG9hdDIgU0VBUkNIX1RFWF9QSVhFTF9TSVpFID0gMS4wIC8gZmxvYXQyKDY2LjAsIDMzLjApO1xuXHRcdFx0Ly8gZSA9IGZsb2F0MihiaWFzLCAwLjApICsgMC41ICogU0VBUkNIX1RFWF9QSVhFTF9TSVpFICtcblx0XHRcdC8vICAgICBlICogZmxvYXQyKHNjYWxlLCAxLjApICogZmxvYXQyKDY0LjAsIDMyLjApICogU0VBUkNIX1RFWF9QSVhFTF9TSVpFO1xuXHRcdFx0ZS5yID0gYmlhcyArIGUuciAqIHNjYWxlO1xuXHRcdFx0cmV0dXJuIDI1NS4wICogdGV4dHVyZTJEKCBzZWFyY2hUZXgsIGUsIDAuMCApLnI7XG5cdFx0fVxuXG5cdFx0ZmxvYXQgU01BQVNlYXJjaFhMZWZ0KCBzYW1wbGVyMkQgZWRnZXNUZXgsIHNhbXBsZXIyRCBzZWFyY2hUZXgsIHZlYzIgdGV4Y29vcmQsIGZsb2F0IGVuZCApIHtcblx0XHRcdC8qKlxuXHRcdFx0XHQqIEBQU0VVRE9fR0FUSEVSNFxuXHRcdFx0XHQqIFRoaXMgdGV4Y29vcmQgaGFzIGJlZW4gb2Zmc2V0IGJ5ICgtMC4yNSwgLTAuMTI1KSBpbiB0aGUgdmVydGV4IHNoYWRlciB0b1xuXHRcdFx0XHQqIHNhbXBsZSBiZXR3ZWVuIGVkZ2UsIHRodXMgZmV0Y2hpbmcgZm91ciBlZGdlcyBpbiBhIHJvdy5cblx0XHRcdFx0KiBTYW1wbGluZyB3aXRoIGRpZmZlcmVudCBvZmZzZXRzIGluIGVhY2ggZGlyZWN0aW9uIGFsbG93cyB0byBkaXNhbWJpZ3VhdGVcblx0XHRcdFx0KiB3aGljaCBlZGdlcyBhcmUgYWN0aXZlIGZyb20gdGhlIGZvdXIgZmV0Y2hlZCBvbmVzLlxuXHRcdFx0XHQqL1xuXHRcdFx0dmVjMiBlID0gdmVjMiggMC4wLCAxLjAgKTtcblxuXHRcdFx0Zm9yICggaW50IGkgPSAwOyBpIDwgU01BQV9NQVhfU0VBUkNIX1NURVBTOyBpICsrICkgeyAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgd2hpbGUgdG8gZm9yXG5cdFx0XHRcdGUgPSB0ZXh0dXJlMkQoIGVkZ2VzVGV4LCB0ZXhjb29yZCwgMC4wICkucmc7XG5cdFx0XHRcdHRleGNvb3JkIC09IHZlYzIoIDIuMCwgMC4wICkgKiByZXNvbHV0aW9uO1xuXHRcdFx0XHRpZiAoICEgKCB0ZXhjb29yZC54ID4gZW5kICYmIGUuZyA+IDAuODI4MSAmJiBlLnIgPT0gMC4wICkgKSBicmVhaztcblx0XHRcdH1cblxuXHRcdFx0Ly8gV2UgY29ycmVjdCB0aGUgcHJldmlvdXMgKC0wLjI1LCAtMC4xMjUpIG9mZnNldCB3ZSBhcHBsaWVkOlxuXHRcdFx0dGV4Y29vcmQueCArPSAwLjI1ICogcmVzb2x1dGlvbi54O1xuXG5cdFx0XHQvLyBUaGUgc2VhcmNoZXMgYXJlIGJpYXMgYnkgMSwgc28gYWRqdXN0IHRoZSBjb29yZHMgYWNjb3JkaW5nbHk6XG5cdFx0XHR0ZXhjb29yZC54ICs9IHJlc29sdXRpb24ueDtcblxuXHRcdFx0Ly8gRGlzYW1iaWd1YXRlIHRoZSBsZW5ndGggYWRkZWQgYnkgdGhlIGxhc3Qgc3RlcDpcblx0XHRcdHRleGNvb3JkLnggKz0gMi4wICogcmVzb2x1dGlvbi54OyAvLyBVbmRvIGxhc3Qgc3RlcFxuXHRcdFx0dGV4Y29vcmQueCAtPSByZXNvbHV0aW9uLnggKiBTTUFBU2VhcmNoTGVuZ3RoKHNlYXJjaFRleCwgZSwgMC4wLCAwLjUpO1xuXG5cdFx0XHRyZXR1cm4gdGV4Y29vcmQueDtcblx0XHR9XG5cblx0XHRmbG9hdCBTTUFBU2VhcmNoWFJpZ2h0KCBzYW1wbGVyMkQgZWRnZXNUZXgsIHNhbXBsZXIyRCBzZWFyY2hUZXgsIHZlYzIgdGV4Y29vcmQsIGZsb2F0IGVuZCApIHtcblx0XHRcdHZlYzIgZSA9IHZlYzIoIDAuMCwgMS4wICk7XG5cblx0XHRcdGZvciAoIGludCBpID0gMDsgaSA8IFNNQUFfTUFYX1NFQVJDSF9TVEVQUzsgaSArKyApIHsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHdoaWxlIHRvIGZvclxuXHRcdFx0XHRlID0gdGV4dHVyZTJEKCBlZGdlc1RleCwgdGV4Y29vcmQsIDAuMCApLnJnO1xuXHRcdFx0XHR0ZXhjb29yZCArPSB2ZWMyKCAyLjAsIDAuMCApICogcmVzb2x1dGlvbjtcblx0XHRcdFx0aWYgKCAhICggdGV4Y29vcmQueCA8IGVuZCAmJiBlLmcgPiAwLjgyODEgJiYgZS5yID09IDAuMCApICkgYnJlYWs7XG5cdFx0XHR9XG5cblx0XHRcdHRleGNvb3JkLnggLT0gMC4yNSAqIHJlc29sdXRpb24ueDtcblx0XHRcdHRleGNvb3JkLnggLT0gcmVzb2x1dGlvbi54O1xuXHRcdFx0dGV4Y29vcmQueCAtPSAyLjAgKiByZXNvbHV0aW9uLng7XG5cdFx0XHR0ZXhjb29yZC54ICs9IHJlc29sdXRpb24ueCAqIFNNQUFTZWFyY2hMZW5ndGgoIHNlYXJjaFRleCwgZSwgMC41LCAwLjUgKTtcblxuXHRcdFx0cmV0dXJuIHRleGNvb3JkLng7XG5cdFx0fVxuXG5cdFx0ZmxvYXQgU01BQVNlYXJjaFlVcCggc2FtcGxlcjJEIGVkZ2VzVGV4LCBzYW1wbGVyMkQgc2VhcmNoVGV4LCB2ZWMyIHRleGNvb3JkLCBmbG9hdCBlbmQgKSB7XG5cdFx0XHR2ZWMyIGUgPSB2ZWMyKCAxLjAsIDAuMCApO1xuXG5cdFx0XHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBTTUFBX01BWF9TRUFSQ0hfU1RFUFM7IGkgKysgKSB7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCB3aGlsZSB0byBmb3Jcblx0XHRcdFx0ZSA9IHRleHR1cmUyRCggZWRnZXNUZXgsIHRleGNvb3JkLCAwLjAgKS5yZztcblx0XHRcdFx0dGV4Y29vcmQgKz0gdmVjMiggMC4wLCAyLjAgKSAqIHJlc29sdXRpb247IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cdFx0XHRcdGlmICggISAoIHRleGNvb3JkLnkgPiBlbmQgJiYgZS5yID4gMC44MjgxICYmIGUuZyA9PSAwLjAgKSApIGJyZWFrO1xuXHRcdFx0fVxuXG5cdFx0XHR0ZXhjb29yZC55IC09IDAuMjUgKiByZXNvbHV0aW9uLnk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cdFx0XHR0ZXhjb29yZC55IC09IHJlc29sdXRpb24ueTsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHNpZ25cblx0XHRcdHRleGNvb3JkLnkgLT0gMi4wICogcmVzb2x1dGlvbi55OyAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgc2lnblxuXHRcdFx0dGV4Y29vcmQueSArPSByZXNvbHV0aW9uLnkgKiBTTUFBU2VhcmNoTGVuZ3RoKCBzZWFyY2hUZXgsIGUuZ3IsIDAuMCwgMC41ICk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cblx0XHRcdHJldHVybiB0ZXhjb29yZC55O1xuXHRcdH1cblxuXHRcdGZsb2F0IFNNQUFTZWFyY2hZRG93biggc2FtcGxlcjJEIGVkZ2VzVGV4LCBzYW1wbGVyMkQgc2VhcmNoVGV4LCB2ZWMyIHRleGNvb3JkLCBmbG9hdCBlbmQgKSB7XG5cdFx0XHR2ZWMyIGUgPSB2ZWMyKCAxLjAsIDAuMCApO1xuXG5cdFx0XHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBTTUFBX01BWF9TRUFSQ0hfU1RFUFM7IGkgKysgKSB7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCB3aGlsZSB0byBmb3Jcblx0XHRcdFx0ZSA9IHRleHR1cmUyRCggZWRnZXNUZXgsIHRleGNvb3JkLCAwLjAgKS5yZztcblx0XHRcdFx0dGV4Y29vcmQgLT0gdmVjMiggMC4wLCAyLjAgKSAqIHJlc29sdXRpb247IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cdFx0XHRcdGlmICggISAoIHRleGNvb3JkLnkgPCBlbmQgJiYgZS5yID4gMC44MjgxICYmIGUuZyA9PSAwLjAgKSApIGJyZWFrO1xuXHRcdFx0fVxuXG5cdFx0XHR0ZXhjb29yZC55ICs9IDAuMjUgKiByZXNvbHV0aW9uLnk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cdFx0XHR0ZXhjb29yZC55ICs9IHJlc29sdXRpb24ueTsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHNpZ25cblx0XHRcdHRleGNvb3JkLnkgKz0gMi4wICogcmVzb2x1dGlvbi55OyAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgc2lnblxuXHRcdFx0dGV4Y29vcmQueSAtPSByZXNvbHV0aW9uLnkgKiBTTUFBU2VhcmNoTGVuZ3RoKCBzZWFyY2hUZXgsIGUuZ3IsIDAuNSwgMC41ICk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cblx0XHRcdHJldHVybiB0ZXhjb29yZC55O1xuXHRcdH1cblxuXHRcdHZlYzIgU01BQUFyZWEoIHNhbXBsZXIyRCBhcmVhVGV4LCB2ZWMyIGRpc3QsIGZsb2F0IGUxLCBmbG9hdCBlMiwgZmxvYXQgb2Zmc2V0ICkge1xuXHRcdFx0Ly8gUm91bmRpbmcgcHJldmVudHMgcHJlY2lzaW9uIGVycm9ycyBvZiBiaWxpbmVhciBmaWx0ZXJpbmc6XG5cdFx0XHR2ZWMyIHRleGNvb3JkID0gZmxvYXQoIFNNQUFfQVJFQVRFWF9NQVhfRElTVEFOQ0UgKSAqIHJvdW5kKCA0LjAgKiB2ZWMyKCBlMSwgZTIgKSApICsgZGlzdDtcblxuXHRcdFx0Ly8gV2UgZG8gYSBzY2FsZSBhbmQgYmlhcyBmb3IgbWFwcGluZyB0byB0ZXhlbCBzcGFjZTpcblx0XHRcdHRleGNvb3JkID0gU01BQV9BUkVBVEVYX1BJWEVMX1NJWkUgKiB0ZXhjb29yZCArICggMC41ICogU01BQV9BUkVBVEVYX1BJWEVMX1NJWkUgKTtcblxuXHRcdFx0Ly8gTW92ZSB0byBwcm9wZXIgcGxhY2UsIGFjY29yZGluZyB0byB0aGUgc3VicGl4ZWwgb2Zmc2V0OlxuXHRcdFx0dGV4Y29vcmQueSArPSBTTUFBX0FSRUFURVhfU1VCVEVYX1NJWkUgKiBvZmZzZXQ7XG5cblx0XHRcdHJldHVybiB0ZXh0dXJlMkQoIGFyZWFUZXgsIHRleGNvb3JkLCAwLjAgKS5yZztcblx0XHR9XG5cblx0XHR2ZWM0IFNNQUFCbGVuZGluZ1dlaWdodENhbGN1bGF0aW9uUFMoIHZlYzIgdGV4Y29vcmQsIHZlYzIgcGl4Y29vcmQsIHZlYzQgb2Zmc2V0WyAzIF0sIHNhbXBsZXIyRCBlZGdlc1RleCwgc2FtcGxlcjJEIGFyZWFUZXgsIHNhbXBsZXIyRCBzZWFyY2hUZXgsIGl2ZWM0IHN1YnNhbXBsZUluZGljZXMgKSB7XG5cdFx0XHR2ZWM0IHdlaWdodHMgPSB2ZWM0KCAwLjAsIDAuMCwgMC4wLCAwLjAgKTtcblxuXHRcdFx0dmVjMiBlID0gdGV4dHVyZTJEKCBlZGdlc1RleCwgdGV4Y29vcmQgKS5yZztcblxuXHRcdFx0aWYgKCBlLmcgPiAwLjAgKSB7IC8vIEVkZ2UgYXQgbm9ydGhcblx0XHRcdFx0dmVjMiBkO1xuXG5cdFx0XHRcdC8vIEZpbmQgdGhlIGRpc3RhbmNlIHRvIHRoZSBsZWZ0OlxuXHRcdFx0XHR2ZWMyIGNvb3Jkcztcblx0XHRcdFx0Y29vcmRzLnggPSBTTUFBU2VhcmNoWExlZnQoIGVkZ2VzVGV4LCBzZWFyY2hUZXgsIG9mZnNldFsgMCBdLnh5LCBvZmZzZXRbIDIgXS54ICk7XG5cdFx0XHRcdGNvb3Jkcy55ID0gb2Zmc2V0WyAxIF0ueTsgLy8gb2Zmc2V0WzFdLnkgPSB0ZXhjb29yZC55IC0gMC4yNSAqIHJlc29sdXRpb24ueSAoQENST1NTSU5HX09GRlNFVClcblx0XHRcdFx0ZC54ID0gY29vcmRzLng7XG5cblx0XHRcdFx0Ly8gTm93IGZldGNoIHRoZSBsZWZ0IGNyb3NzaW5nIGVkZ2VzLCB0d28gYXQgYSB0aW1lIHVzaW5nIGJpbGluZWFyXG5cdFx0XHRcdC8vIGZpbHRlcmluZy4gU2FtcGxpbmcgYXQgLTAuMjUgKHNlZSBAQ1JPU1NJTkdfT0ZGU0VUKSBlbmFibGVzIHRvXG5cdFx0XHRcdC8vIGRpc2Nlcm4gd2hhdCB2YWx1ZSBlYWNoIGVkZ2UgaGFzOlxuXHRcdFx0XHRmbG9hdCBlMSA9IHRleHR1cmUyRCggZWRnZXNUZXgsIGNvb3JkcywgMC4wICkucjtcblxuXHRcdFx0XHQvLyBGaW5kIHRoZSBkaXN0YW5jZSB0byB0aGUgcmlnaHQ6XG5cdFx0XHRcdGNvb3Jkcy54ID0gU01BQVNlYXJjaFhSaWdodCggZWRnZXNUZXgsIHNlYXJjaFRleCwgb2Zmc2V0WyAwIF0uencsIG9mZnNldFsgMiBdLnkgKTtcblx0XHRcdFx0ZC55ID0gY29vcmRzLng7XG5cblx0XHRcdFx0Ly8gV2Ugd2FudCB0aGUgZGlzdGFuY2VzIHRvIGJlIGluIHBpeGVsIHVuaXRzIChkb2luZyB0aGlzIGhlcmUgYWxsb3cgdG9cblx0XHRcdFx0Ly8gYmV0dGVyIGludGVybGVhdmUgYXJpdGhtZXRpYyBhbmQgbWVtb3J5IGFjY2Vzc2VzKTpcblx0XHRcdFx0ZCA9IGQgLyByZXNvbHV0aW9uLnggLSBwaXhjb29yZC54O1xuXG5cdFx0XHRcdC8vIFNNQUFBcmVhIGJlbG93IG5lZWRzIGEgc3FydCwgYXMgdGhlIGFyZWFzIHRleHR1cmUgaXMgY29tcHJlc3NlZFxuXHRcdFx0XHQvLyBxdWFkcmF0aWNhbGx5OlxuXHRcdFx0XHR2ZWMyIHNxcnRfZCA9IHNxcnQoIGFicyggZCApICk7XG5cblx0XHRcdFx0Ly8gRmV0Y2ggdGhlIHJpZ2h0IGNyb3NzaW5nIGVkZ2VzOlxuXHRcdFx0XHRjb29yZHMueSAtPSAxLjAgKiByZXNvbHV0aW9uLnk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQWRkZWRcblx0XHRcdFx0ZmxvYXQgZTIgPSBTTUFBU2FtcGxlTGV2ZWxaZXJvT2Zmc2V0KCBlZGdlc1RleCwgY29vcmRzLCBpdmVjMiggMSwgMCApICkucjtcblxuXHRcdFx0XHQvLyBPaywgd2Uga25vdyBob3cgdGhpcyBwYXR0ZXJuIGxvb2tzIGxpa2UsIG5vdyBpdCBpcyB0aW1lIGZvciBnZXR0aW5nXG5cdFx0XHRcdC8vIHRoZSBhY3R1YWwgYXJlYTpcblx0XHRcdFx0d2VpZ2h0cy5yZyA9IFNNQUFBcmVhKCBhcmVhVGV4LCBzcXJ0X2QsIGUxLCBlMiwgZmxvYXQoIHN1YnNhbXBsZUluZGljZXMueSApICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggZS5yID4gMC4wICkgeyAvLyBFZGdlIGF0IHdlc3Rcblx0XHRcdFx0dmVjMiBkO1xuXG5cdFx0XHRcdC8vIEZpbmQgdGhlIGRpc3RhbmNlIHRvIHRoZSB0b3A6XG5cdFx0XHRcdHZlYzIgY29vcmRzO1xuXG5cdFx0XHRcdGNvb3Jkcy55ID0gU01BQVNlYXJjaFlVcCggZWRnZXNUZXgsIHNlYXJjaFRleCwgb2Zmc2V0WyAxIF0ueHksIG9mZnNldFsgMiBdLnogKTtcblx0XHRcdFx0Y29vcmRzLnggPSBvZmZzZXRbIDAgXS54OyAvLyBvZmZzZXRbMV0ueCA9IHRleGNvb3JkLnggLSAwLjI1ICogcmVzb2x1dGlvbi54O1xuXHRcdFx0XHRkLnggPSBjb29yZHMueTtcblxuXHRcdFx0XHQvLyBGZXRjaCB0aGUgdG9wIGNyb3NzaW5nIGVkZ2VzOlxuXHRcdFx0XHRmbG9hdCBlMSA9IHRleHR1cmUyRCggZWRnZXNUZXgsIGNvb3JkcywgMC4wICkuZztcblxuXHRcdFx0XHQvLyBGaW5kIHRoZSBkaXN0YW5jZSB0byB0aGUgYm90dG9tOlxuXHRcdFx0XHRjb29yZHMueSA9IFNNQUFTZWFyY2hZRG93biggZWRnZXNUZXgsIHNlYXJjaFRleCwgb2Zmc2V0WyAxIF0uencsIG9mZnNldFsgMiBdLncgKTtcblx0XHRcdFx0ZC55ID0gY29vcmRzLnk7XG5cblx0XHRcdFx0Ly8gV2Ugd2FudCB0aGUgZGlzdGFuY2VzIHRvIGJlIGluIHBpeGVsIHVuaXRzOlxuXHRcdFx0XHRkID0gZCAvIHJlc29sdXRpb24ueSAtIHBpeGNvb3JkLnk7XG5cblx0XHRcdFx0Ly8gU01BQUFyZWEgYmVsb3cgbmVlZHMgYSBzcXJ0LCBhcyB0aGUgYXJlYXMgdGV4dHVyZSBpcyBjb21wcmVzc2VkXG5cdFx0XHRcdC8vIHF1YWRyYXRpY2FsbHk6XG5cdFx0XHRcdHZlYzIgc3FydF9kID0gc3FydCggYWJzKCBkICkgKTtcblxuXHRcdFx0XHQvLyBGZXRjaCB0aGUgYm90dG9tIGNyb3NzaW5nIGVkZ2VzOlxuXHRcdFx0XHRjb29yZHMueSAtPSAxLjAgKiByZXNvbHV0aW9uLnk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQWRkZWRcblx0XHRcdFx0ZmxvYXQgZTIgPSBTTUFBU2FtcGxlTGV2ZWxaZXJvT2Zmc2V0KCBlZGdlc1RleCwgY29vcmRzLCBpdmVjMiggMCwgMSApICkuZztcblxuXHRcdFx0XHQvLyBHZXQgdGhlIGFyZWEgZm9yIHRoaXMgZGlyZWN0aW9uOlxuXHRcdFx0XHR3ZWlnaHRzLmJhID0gU01BQUFyZWEoIGFyZWFUZXgsIHNxcnRfZCwgZTEsIGUyLCBmbG9hdCggc3Vic2FtcGxlSW5kaWNlcy54ICkgKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHdlaWdodHM7XG5cdFx0fVxuXG5cdFx0dm9pZCBtYWluKCkge1xuXG5cdFx0XHRnbF9GcmFnQ29sb3IgPSBTTUFBQmxlbmRpbmdXZWlnaHRDYWxjdWxhdGlvblBTKCB2VXYsIHZQaXhjb29yZCwgdk9mZnNldCwgdERpZmZ1c2UsIHRBcmVhLCB0U2VhcmNoLCBpdmVjNCggMC4wICkgKTtcblxuXHRcdH1gXG5cbn07XG5cbmNvbnN0IFNNQUFCbGVuZFNoYWRlciA9IHtcblxuXHRuYW1lOiAnU01BQUJsZW5kU2hhZGVyJyxcblxuXHR1bmlmb3Jtczoge1xuXG5cdFx0J3REaWZmdXNlJzogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdCd0Q29sb3InOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0J3Jlc29sdXRpb24nOiB7IHZhbHVlOiBuZXcgVmVjdG9yMiggMSAvIDEwMjQsIDEgLyA1MTIgKSB9XG5cblx0fSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR1bmlmb3JtIHZlYzIgcmVzb2x1dGlvbjtcblxuXHRcdHZhcnlpbmcgdmVjMiB2VXY7XG5cdFx0dmFyeWluZyB2ZWM0IHZPZmZzZXRbIDIgXTtcblxuXHRcdHZvaWQgU01BQU5laWdoYm9yaG9vZEJsZW5kaW5nVlMoIHZlYzIgdGV4Y29vcmQgKSB7XG5cdFx0XHR2T2Zmc2V0WyAwIF0gPSB0ZXhjb29yZC54eXh5ICsgcmVzb2x1dGlvbi54eXh5ICogdmVjNCggLTEuMCwgMC4wLCAwLjAsIDEuMCApOyAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgc2lnbiBpbiBXIGNvbXBvbmVudFxuXHRcdFx0dk9mZnNldFsgMSBdID0gdGV4Y29vcmQueHl4eSArIHJlc29sdXRpb24ueHl4eSAqIHZlYzQoIDEuMCwgMC4wLCAwLjAsIC0xLjAgKTsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHNpZ24gaW4gVyBjb21wb25lbnRcblx0XHR9XG5cblx0XHR2b2lkIG1haW4oKSB7XG5cblx0XHRcdHZVdiA9IHV2O1xuXG5cdFx0XHRTTUFBTmVpZ2hib3Job29kQmxlbmRpbmdWUyggdlV2ICk7XG5cblx0XHRcdGdsX1Bvc2l0aW9uID0gcHJvamVjdGlvbk1hdHJpeCAqIG1vZGVsVmlld01hdHJpeCAqIHZlYzQoIHBvc2l0aW9uLCAxLjAgKTtcblxuXHRcdH1gLFxuXG5cdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxuXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgdERpZmZ1c2U7XG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgdENvbG9yO1xuXHRcdHVuaWZvcm0gdmVjMiByZXNvbHV0aW9uO1xuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblx0XHR2YXJ5aW5nIHZlYzQgdk9mZnNldFsgMiBdO1xuXG5cdFx0dmVjNCBTTUFBTmVpZ2hib3Job29kQmxlbmRpbmdQUyggdmVjMiB0ZXhjb29yZCwgdmVjNCBvZmZzZXRbIDIgXSwgc2FtcGxlcjJEIGNvbG9yVGV4LCBzYW1wbGVyMkQgYmxlbmRUZXggKSB7XG5cdFx0XHQvLyBGZXRjaCB0aGUgYmxlbmRpbmcgd2VpZ2h0cyBmb3IgY3VycmVudCBwaXhlbDpcblx0XHRcdHZlYzQgYTtcblx0XHRcdGEueHogPSB0ZXh0dXJlMkQoIGJsZW5kVGV4LCB0ZXhjb29yZCApLnh6O1xuXHRcdFx0YS55ID0gdGV4dHVyZTJEKCBibGVuZFRleCwgb2Zmc2V0WyAxIF0uencgKS5nO1xuXHRcdFx0YS53ID0gdGV4dHVyZTJEKCBibGVuZFRleCwgb2Zmc2V0WyAxIF0ueHkgKS5hO1xuXG5cdFx0XHQvLyBJcyB0aGVyZSBhbnkgYmxlbmRpbmcgd2VpZ2h0IHdpdGggYSB2YWx1ZSBncmVhdGVyIHRoYW4gMC4wP1xuXHRcdFx0aWYgKCBkb3QoYSwgdmVjNCggMS4wLCAxLjAsIDEuMCwgMS4wICkpIDwgMWUtNSApIHtcblx0XHRcdFx0cmV0dXJuIHRleHR1cmUyRCggY29sb3JUZXgsIHRleGNvb3JkLCAwLjAgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vIFVwIHRvIDQgbGluZXMgY2FuIGJlIGNyb3NzaW5nIGEgcGl4ZWwgKG9uZSB0aHJvdWdoIGVhY2ggZWRnZSkuIFdlXG5cdFx0XHRcdC8vIGZhdm9yIGJsZW5kaW5nIGJ5IGNob29zaW5nIHRoZSBsaW5lIHdpdGggdGhlIG1heGltdW0gd2VpZ2h0IGZvciBlYWNoXG5cdFx0XHRcdC8vIGRpcmVjdGlvbjpcblx0XHRcdFx0dmVjMiBvZmZzZXQ7XG5cdFx0XHRcdG9mZnNldC54ID0gYS5hID4gYS5iID8gYS5hIDogLWEuYjsgLy8gbGVmdCB2cy4gcmlnaHRcblx0XHRcdFx0b2Zmc2V0LnkgPSBhLmcgPiBhLnIgPyAtYS5nIDogYS5yOyAvLyB0b3AgdnMuIGJvdHRvbSAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgc2lnbnNcblxuXHRcdFx0XHQvLyBUaGVuIHdlIGdvIGluIHRoZSBkaXJlY3Rpb24gdGhhdCBoYXMgdGhlIG1heGltdW0gd2VpZ2h0OlxuXHRcdFx0XHRpZiAoIGFicyggb2Zmc2V0LnggKSA+IGFicyggb2Zmc2V0LnkgKSkgeyAvLyBob3Jpem9udGFsIHZzLiB2ZXJ0aWNhbFxuXHRcdFx0XHRcdG9mZnNldC55ID0gMC4wO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdG9mZnNldC54ID0gMC4wO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gRmV0Y2ggdGhlIG9wcG9zaXRlIGNvbG9yIGFuZCBsZXJwIGJ5IGhhbmQ6XG5cdFx0XHRcdHZlYzQgQyA9IHRleHR1cmUyRCggY29sb3JUZXgsIHRleGNvb3JkLCAwLjAgKTtcblx0XHRcdFx0dGV4Y29vcmQgKz0gc2lnbiggb2Zmc2V0ICkgKiByZXNvbHV0aW9uO1xuXHRcdFx0XHR2ZWM0IENvcCA9IHRleHR1cmUyRCggY29sb3JUZXgsIHRleGNvb3JkLCAwLjAgKTtcblx0XHRcdFx0ZmxvYXQgcyA9IGFicyggb2Zmc2V0LnggKSA+IGFicyggb2Zmc2V0LnkgKSA/IGFicyggb2Zmc2V0LnggKSA6IGFicyggb2Zmc2V0LnkgKTtcblxuXHRcdFx0XHQvLyBXZWJHTCBwb3J0IG5vdGU6IEFkZGVkIGdhbW1hIGNvcnJlY3Rpb25cblx0XHRcdFx0Qy54eXogPSBwb3coQy54eXosIHZlYzMoMi4yKSk7XG5cdFx0XHRcdENvcC54eXogPSBwb3coQ29wLnh5eiwgdmVjMygyLjIpKTtcblx0XHRcdFx0dmVjNCBtaXhlZCA9IG1peChDLCBDb3AsIHMpO1xuXHRcdFx0XHRtaXhlZC54eXogPSBwb3cobWl4ZWQueHl6LCB2ZWMzKDEuMCAvIDIuMikpO1xuXG5cdFx0XHRcdHJldHVybiBtaXhlZDtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR2b2lkIG1haW4oKSB7XG5cblx0XHRcdGdsX0ZyYWdDb2xvciA9IFNNQUFOZWlnaGJvcmhvb2RCbGVuZGluZ1BTKCB2VXYsIHZPZmZzZXQsIHRDb2xvciwgdERpZmZ1c2UgKTtcblxuXHRcdH1gXG5cbn07XG5cbmV4cG9ydCB7IFNNQUFFZGdlc1NoYWRlciwgU01BQVdlaWdodHNTaGFkZXIsIFNNQUFCbGVuZFNoYWRlciB9O1xuIiwiaW1wb3J0IHtcblx0SGFsZkZsb2F0VHlwZSxcblx0TGluZWFyRmlsdGVyLFxuXHROZWFyZXN0RmlsdGVyLFxuXHRTaGFkZXJNYXRlcmlhbCxcblx0VGV4dHVyZSxcblx0VW5pZm9ybXNVdGlscyxcblx0V2ViR0xSZW5kZXJUYXJnZXRcbn0gZnJvbSAndGhyZWUnO1xuaW1wb3J0IHsgUGFzcywgRnVsbFNjcmVlblF1YWQgfSBmcm9tICcuL1Bhc3MuanMnO1xuaW1wb3J0IHsgU01BQUVkZ2VzU2hhZGVyIH0gZnJvbSAnLi4vc2hhZGVycy9TTUFBU2hhZGVyLmpzJztcbmltcG9ydCB7IFNNQUFXZWlnaHRzU2hhZGVyIH0gZnJvbSAnLi4vc2hhZGVycy9TTUFBU2hhZGVyLmpzJztcbmltcG9ydCB7IFNNQUFCbGVuZFNoYWRlciB9IGZyb20gJy4uL3NoYWRlcnMvU01BQVNoYWRlci5qcyc7XG5cbmNsYXNzIFNNQUFQYXNzIGV4dGVuZHMgUGFzcyB7XG5cblx0Y29uc3RydWN0b3IoIHdpZHRoLCBoZWlnaHQgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0Ly8gcmVuZGVyIHRhcmdldHNcblxuXHRcdHRoaXMuZWRnZXNSVCA9IG5ldyBXZWJHTFJlbmRlclRhcmdldCggd2lkdGgsIGhlaWdodCwge1xuXHRcdFx0ZGVwdGhCdWZmZXI6IGZhbHNlLFxuXHRcdFx0dHlwZTogSGFsZkZsb2F0VHlwZVxuXHRcdH0gKTtcblx0XHR0aGlzLmVkZ2VzUlQudGV4dHVyZS5uYW1lID0gJ1NNQUFQYXNzLmVkZ2VzJztcblxuXHRcdHRoaXMud2VpZ2h0c1JUID0gbmV3IFdlYkdMUmVuZGVyVGFyZ2V0KCB3aWR0aCwgaGVpZ2h0LCB7XG5cdFx0XHRkZXB0aEJ1ZmZlcjogZmFsc2UsXG5cdFx0XHR0eXBlOiBIYWxmRmxvYXRUeXBlXG5cdFx0fSApO1xuXHRcdHRoaXMud2VpZ2h0c1JULnRleHR1cmUubmFtZSA9ICdTTUFBUGFzcy53ZWlnaHRzJztcblxuXHRcdC8vIHRleHR1cmVzXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0Y29uc3QgYXJlYVRleHR1cmVJbWFnZSA9IG5ldyBJbWFnZSgpO1xuXHRcdGFyZWFUZXh0dXJlSW1hZ2Uuc3JjID0gdGhpcy5nZXRBcmVhVGV4dHVyZSgpO1xuXHRcdGFyZWFUZXh0dXJlSW1hZ2Uub25sb2FkID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHQvLyBhc3NpZ25pbmcgZGF0YSB0byBIVE1MSW1hZ2VFbGVtZW50LnNyYyBpcyBhc3luY2hyb25vdXMgKHNlZSAjMTUxNjIpXG5cdFx0XHRzY29wZS5hcmVhVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5hcmVhVGV4dHVyZSA9IG5ldyBUZXh0dXJlKCk7XG5cdFx0dGhpcy5hcmVhVGV4dHVyZS5uYW1lID0gJ1NNQUFQYXNzLmFyZWEnO1xuXHRcdHRoaXMuYXJlYVRleHR1cmUuaW1hZ2UgPSBhcmVhVGV4dHVyZUltYWdlO1xuXHRcdHRoaXMuYXJlYVRleHR1cmUubWluRmlsdGVyID0gTGluZWFyRmlsdGVyO1xuXHRcdHRoaXMuYXJlYVRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XG5cdFx0dGhpcy5hcmVhVGV4dHVyZS5mbGlwWSA9IGZhbHNlO1xuXG5cdFx0Y29uc3Qgc2VhcmNoVGV4dHVyZUltYWdlID0gbmV3IEltYWdlKCk7XG5cdFx0c2VhcmNoVGV4dHVyZUltYWdlLnNyYyA9IHRoaXMuZ2V0U2VhcmNoVGV4dHVyZSgpO1xuXHRcdHNlYXJjaFRleHR1cmVJbWFnZS5vbmxvYWQgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdC8vIGFzc2lnbmluZyBkYXRhIHRvIEhUTUxJbWFnZUVsZW1lbnQuc3JjIGlzIGFzeW5jaHJvbm91cyAoc2VlICMxNTE2Milcblx0XHRcdHNjb3BlLnNlYXJjaFRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2VhcmNoVGV4dHVyZSA9IG5ldyBUZXh0dXJlKCk7XG5cdFx0dGhpcy5zZWFyY2hUZXh0dXJlLm5hbWUgPSAnU01BQVBhc3Muc2VhcmNoJztcblx0XHR0aGlzLnNlYXJjaFRleHR1cmUuaW1hZ2UgPSBzZWFyY2hUZXh0dXJlSW1hZ2U7XG5cdFx0dGhpcy5zZWFyY2hUZXh0dXJlLm1hZ0ZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XG5cdFx0dGhpcy5zZWFyY2hUZXh0dXJlLm1pbkZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XG5cdFx0dGhpcy5zZWFyY2hUZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXHRcdHRoaXMuc2VhcmNoVGV4dHVyZS5mbGlwWSA9IGZhbHNlO1xuXG5cdFx0Ly8gbWF0ZXJpYWxzIC0gcGFzcyAxXG5cblx0XHR0aGlzLnVuaWZvcm1zRWRnZXMgPSBVbmlmb3Jtc1V0aWxzLmNsb25lKCBTTUFBRWRnZXNTaGFkZXIudW5pZm9ybXMgKTtcblxuXHRcdHRoaXMudW5pZm9ybXNFZGdlc1sgJ3Jlc29sdXRpb24nIF0udmFsdWUuc2V0KCAxIC8gd2lkdGgsIDEgLyBoZWlnaHQgKTtcblxuXHRcdHRoaXMubWF0ZXJpYWxFZGdlcyA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xuXHRcdFx0ZGVmaW5lczogT2JqZWN0LmFzc2lnbigge30sIFNNQUFFZGdlc1NoYWRlci5kZWZpbmVzICksXG5cdFx0XHR1bmlmb3JtczogdGhpcy51bmlmb3Jtc0VkZ2VzLFxuXHRcdFx0dmVydGV4U2hhZGVyOiBTTUFBRWRnZXNTaGFkZXIudmVydGV4U2hhZGVyLFxuXHRcdFx0ZnJhZ21lbnRTaGFkZXI6IFNNQUFFZGdlc1NoYWRlci5mcmFnbWVudFNoYWRlclxuXHRcdH0gKTtcblxuXHRcdC8vIG1hdGVyaWFscyAtIHBhc3MgMlxuXG5cdFx0dGhpcy51bmlmb3Jtc1dlaWdodHMgPSBVbmlmb3Jtc1V0aWxzLmNsb25lKCBTTUFBV2VpZ2h0c1NoYWRlci51bmlmb3JtcyApO1xuXG5cdFx0dGhpcy51bmlmb3Jtc1dlaWdodHNbICdyZXNvbHV0aW9uJyBdLnZhbHVlLnNldCggMSAvIHdpZHRoLCAxIC8gaGVpZ2h0ICk7XG5cdFx0dGhpcy51bmlmb3Jtc1dlaWdodHNbICd0RGlmZnVzZScgXS52YWx1ZSA9IHRoaXMuZWRnZXNSVC50ZXh0dXJlO1xuXHRcdHRoaXMudW5pZm9ybXNXZWlnaHRzWyAndEFyZWEnIF0udmFsdWUgPSB0aGlzLmFyZWFUZXh0dXJlO1xuXHRcdHRoaXMudW5pZm9ybXNXZWlnaHRzWyAndFNlYXJjaCcgXS52YWx1ZSA9IHRoaXMuc2VhcmNoVGV4dHVyZTtcblxuXHRcdHRoaXMubWF0ZXJpYWxXZWlnaHRzID0gbmV3IFNoYWRlck1hdGVyaWFsKCB7XG5cdFx0XHRkZWZpbmVzOiBPYmplY3QuYXNzaWduKCB7fSwgU01BQVdlaWdodHNTaGFkZXIuZGVmaW5lcyApLFxuXHRcdFx0dW5pZm9ybXM6IHRoaXMudW5pZm9ybXNXZWlnaHRzLFxuXHRcdFx0dmVydGV4U2hhZGVyOiBTTUFBV2VpZ2h0c1NoYWRlci52ZXJ0ZXhTaGFkZXIsXG5cdFx0XHRmcmFnbWVudFNoYWRlcjogU01BQVdlaWdodHNTaGFkZXIuZnJhZ21lbnRTaGFkZXJcblx0XHR9ICk7XG5cblx0XHQvLyBtYXRlcmlhbHMgLSBwYXNzIDNcblxuXHRcdHRoaXMudW5pZm9ybXNCbGVuZCA9IFVuaWZvcm1zVXRpbHMuY2xvbmUoIFNNQUFCbGVuZFNoYWRlci51bmlmb3JtcyApO1xuXG5cdFx0dGhpcy51bmlmb3Jtc0JsZW5kWyAncmVzb2x1dGlvbicgXS52YWx1ZS5zZXQoIDEgLyB3aWR0aCwgMSAvIGhlaWdodCApO1xuXHRcdHRoaXMudW5pZm9ybXNCbGVuZFsgJ3REaWZmdXNlJyBdLnZhbHVlID0gdGhpcy53ZWlnaHRzUlQudGV4dHVyZTtcblxuXHRcdHRoaXMubWF0ZXJpYWxCbGVuZCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xuXHRcdFx0dW5pZm9ybXM6IHRoaXMudW5pZm9ybXNCbGVuZCxcblx0XHRcdHZlcnRleFNoYWRlcjogU01BQUJsZW5kU2hhZGVyLnZlcnRleFNoYWRlcixcblx0XHRcdGZyYWdtZW50U2hhZGVyOiBTTUFBQmxlbmRTaGFkZXIuZnJhZ21lbnRTaGFkZXJcblx0XHR9ICk7XG5cblx0XHR0aGlzLmZzUXVhZCA9IG5ldyBGdWxsU2NyZWVuUXVhZCggbnVsbCApO1xuXG5cdH1cblxuXHRyZW5kZXIoIHJlbmRlcmVyLCB3cml0ZUJ1ZmZlciwgcmVhZEJ1ZmZlci8qLCBkZWx0YVRpbWUsIG1hc2tBY3RpdmUqLyApIHtcblxuXHRcdC8vIHBhc3MgMVxuXG5cdFx0dGhpcy51bmlmb3Jtc0VkZ2VzWyAndERpZmZ1c2UnIF0udmFsdWUgPSByZWFkQnVmZmVyLnRleHR1cmU7XG5cblx0XHR0aGlzLmZzUXVhZC5tYXRlcmlhbCA9IHRoaXMubWF0ZXJpYWxFZGdlcztcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggdGhpcy5lZGdlc1JUICk7XG5cdFx0aWYgKCB0aGlzLmNsZWFyICkgcmVuZGVyZXIuY2xlYXIoKTtcblx0XHR0aGlzLmZzUXVhZC5yZW5kZXIoIHJlbmRlcmVyICk7XG5cblx0XHQvLyBwYXNzIDJcblxuXHRcdHRoaXMuZnNRdWFkLm1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbFdlaWdodHM7XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHRoaXMud2VpZ2h0c1JUICk7XG5cdFx0aWYgKCB0aGlzLmNsZWFyICkgcmVuZGVyZXIuY2xlYXIoKTtcblx0XHR0aGlzLmZzUXVhZC5yZW5kZXIoIHJlbmRlcmVyICk7XG5cblx0XHQvLyBwYXNzIDNcblxuXHRcdHRoaXMudW5pZm9ybXNCbGVuZFsgJ3RDb2xvcicgXS52YWx1ZSA9IHJlYWRCdWZmZXIudGV4dHVyZTtcblxuXHRcdHRoaXMuZnNRdWFkLm1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbEJsZW5kO1xuXG5cdFx0aWYgKCB0aGlzLnJlbmRlclRvU2NyZWVuICkge1xuXG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIG51bGwgKTtcblx0XHRcdHRoaXMuZnNRdWFkLnJlbmRlciggcmVuZGVyZXIgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggd3JpdGVCdWZmZXIgKTtcblx0XHRcdGlmICggdGhpcy5jbGVhciApIHJlbmRlcmVyLmNsZWFyKCk7XG5cdFx0XHR0aGlzLmZzUXVhZC5yZW5kZXIoIHJlbmRlcmVyICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHNldFNpemUoIHdpZHRoLCBoZWlnaHQgKSB7XG5cblx0XHR0aGlzLmVkZ2VzUlQuc2V0U2l6ZSggd2lkdGgsIGhlaWdodCApO1xuXHRcdHRoaXMud2VpZ2h0c1JULnNldFNpemUoIHdpZHRoLCBoZWlnaHQgKTtcblxuXHRcdHRoaXMubWF0ZXJpYWxFZGdlcy51bmlmb3Jtc1sgJ3Jlc29sdXRpb24nIF0udmFsdWUuc2V0KCAxIC8gd2lkdGgsIDEgLyBoZWlnaHQgKTtcblx0XHR0aGlzLm1hdGVyaWFsV2VpZ2h0cy51bmlmb3Jtc1sgJ3Jlc29sdXRpb24nIF0udmFsdWUuc2V0KCAxIC8gd2lkdGgsIDEgLyBoZWlnaHQgKTtcblx0XHR0aGlzLm1hdGVyaWFsQmxlbmQudW5pZm9ybXNbICdyZXNvbHV0aW9uJyBdLnZhbHVlLnNldCggMSAvIHdpZHRoLCAxIC8gaGVpZ2h0ICk7XG5cblx0fVxuXG5cdGdldEFyZWFUZXh0dXJlKCkge1xuXG5cdFx0cmV0dXJuICdkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUtBQUFBSXdDQUlBQUFDT1ZQY1FBQUNCZWtsRVFWUjQydTM5VzR4bFdYcm5oLzNXV3Z1Y2lJek1yS3hyVjgvMHJXYlkwK1NRRktjYjRvd0lrU0lGQ2pZOUFDMUJUL0xZQm96UmkrRVgrY1YrOElNc1lBYUN3UmNCd2p6TWl3MmpBV3Rnd0M4V1I1UThtREZIWkxOSFRhclpHckxKSmxsdDFXMnFLcnN1bVpXWmNUdm43TDNXNTRlMXZyWFgzdnVjaUxQUE9SRlIxWEUyRW9tb3JCMG5WdXovL3I3MXJlL3kvMWVNdmI0Q2IzTjExeFYvUFAvMnY0VUJBd0pHLzdIOHVyeDYvMjUvR2Y4TzVoeXBNUTBFRUVRd0FxTGZvTi9aKzk3Zi9TVysvTnZjZ1FrNHNHQkpLNkg3TjRQRlZMK0srZTBOMTF5TmZrS3Z3VWR3ZGxVQVhQSEhMMzhvYTE1Zi9pLzQ2SWg2U3VNU1BtTEFZQXd5UktuN2RmTUdIOTdqYU1GQllDSlVnb3RJQzJZQWR1K0x5Vzl2dnVieEFQOGtBTDhIL2tvQXVPS1AzK3E2K3hHbmQ1a2RZQ2VFQ25HSUpWaXdHSk1Ba1FLZkR2QjNXWnhqTEtHaDhWU0NDemh3RVdCcE1jNS9rQmJqYXdUNEhud0pmaHIrcFBCSXU3dXUrT09Ubzl2c210UWNuaU1CR2tLRmQ0akRXTVNDUlVwTGpKWU5Ka00rSVJ6UStQUXZJZUFNVHJCUzJMRWlhaVI5Yi81UHVUNkFwL0FjZkFGTzRZM2RBM0RGSDcvVlMrTThrNGJhRUFRZk1JNFFmYlZEREdJUmc3R0thSVk1MnFBalRBZ1R2R0JBUEdJSWdoT0NZQVVyR0ZOZ3pBN1EzUWhnQ3dmd0Fud2U1dkRlamdHNDRvL2ZibTFDNVpsWVF2UURBUlBBSVFHeENXQk0rd1dsMzdaUUVTYjRnSW1leEdNRG91aEdMeDFDc3QwU2FhNGI0QXFPNEhrNGd4byszREhBVi9ueDI3cDNKemlQTTJwVmdvaWlhNU1kRXpDR1VMcHJJTjdnRUVlUTVJUXhFQkJCUW54aHNEYjVhdUdtQUFZY0hNQTllQUF6OFBCb2w4L3hpajkrQzREamxpbTRnSmpXY3daQmhDQmdNSUlZeEdBVklrSDNadGNCdUxkdFJGTVdzUEdvWTlyTitIb0JqaTlWQllkd0QyWlFnNGNuTzdPU3EvejRyVTVLS2R3VmJGQWpOb2pDUXpUbENMUEZTeHRhbXdoMmpNVWNFZ2cyV20vNlhnRXJJQmhCY2tRdEdOM0N6YlZhY0VSZ0NuZmdMc3dobnZxZjdReUFxL3o0clJabTFZZ2xZRTNhZmZHSVRhWnNkSWUyRm1NSXBuT0NhcDI1STZqdDJrQ3dDVzBEMXVBRDlzWmN0TkdYY1FJSENrSU5EUWdjNzhhQ3Iremp0dzNCVS9pamRwdzN6aEN3Y2FPTndCdmRlUzJZWktrSk5Kc01QZjJKS0V2QzI4Ulh4eEkwQVNKeXpRQ2pDRVFyTzRRN3NGQXJFempaaGFGYzRjZHYrL0pGZEtVTE00cHgwRGZVQkkyaElzeTA2QnFMaEdUUUVWZGJmQUlaWFlNUGVzcTZWb0NISUN6VXlqd0luTzRZNDExLy9MWUxzNlREYTl3dmcyQ0MyckVsZ0FucFRCemlUaHhhTDIyTVloemZrZ2h6NkdBczJWSGJiZE05MVZadTFNRUVwdXBNTXdLeVZUYjVpajkrdTRWSkcvNUVnRU1NbUZGMDFjRmFpM2lzUmJLYnpiK1lhVS9NUWJBbTJYU01vVVBBbXZaemJ1S1lSSUZBcGJ0bHJmRnVVR2Q2dnEyaFhObkg3OFpMaC9pRmhzUUczVDREMWliN2s1Q0M2dlkwRENidHJvaGdMRUlDbFhpR3RsMTB6YzBDbkVHSWhoYXRMQnZhN05QNThUdncwcUU4eVdoQVJMUThoNCtBaFFTUCtJNEY1eG9VK1ZpbEdSSnM2d25TN3J1dGkvNEt2QVkvQ2ZkZ3Fqc015NHBmOGZvZFFPOC9nbnVYM2YvM3hpM29tMS9oN1RIcitjbzN4OTNQUDkrRkJVZmJOVWpjakVtaGNya1QrOEs3bWw3VjEwSm8wNW1wSUVGeTFObUNKV3g5U0lLS3QrRWpBTDRFejhFQlZPQjZoYXZ1VC9yQnlQdkhYSys5elVjZmNiYjI1NCs5ZnlkSmtuWW5ScjFvR2ZkYWlBZ3B4dTFSeC9SZWs4S0lTZnR4M0wrRGZzTFdBQU5uOEh2dzAvQUZlQUdPOURGVjNjNkQrQ2NXYkw4RGo5ZTdmK1QxazhBWnYvZDcrUFhXTS9aK1Z2ZENySXZ1QUtPMDlScEVFUUpNMENpNitCNHhoVFdyNGNaTk92aGt0YWJ3MHRhMHJTSm1xejNZdzUvQUtYd2Vub2Q3Y0FoVG1CU1BLZjZKQmR2SDhJUDE3aDk1cFhxdzUwLytCRm5qODhmZXY0TmNoeWFLNDdPUGhodEk4UkZTdkFmRFNOaDBDazBwMmdMeEdraWI1TkpqL0pXQ3I5MEVXUUp2d0J6TzRBSGNnenR3QUZOMWV2SFBVVkd3ZlhPTiswZGViVDFZZUdPTjlZeTkvNjNYK09ndWl3bWhJaFFoRDdsNHNNcWxHM0Q4NlN1YzNxV1o0cldqSTFYN3UwWXR3NngzcklNZUlPUERwcmZlMlh6Tmd5ajZQYWhoQmpPNEMzZTZwdURnWHJkZysvNWw5NDh2RjNicXdaZXRaK3o5Ung5emRJWTVwSW5QSzROazB0K2w1MnhkSzJCNDVRZDg3bk04ZnNENUVmVWhJY0pjRVJ3NFJkcXFIN1lkZTVWN20xdmhObXRlZGt6NkVEelVNRi8yakpZV2JDKzRmenpBL1krLzhQUEgzajlkY0JBUElSUDhKTFhkNUJwQXUwM2F6aU9MM1ZWSFp6ejNDWFdEUFdkK1NIMkFueElxUW9UWnBvOUNrYzZISXJGYkFiek5tbGNnOEFnOE5GRERBaGJKdlRCWlhiQzk0UDd0NjhFWGZ2Nm8rMjFnVXRQRVRVN2Jia0x4dk5LUkZHMitLWHp2dE9ib25QUDRyQnZzZ21hS2o0MDREbHNoRm9sZTFHbGZoMDJmRTdiWVI3ZFo4Mm9UZXdJQkduMU1kNkNHNllVRjI2WDM3Nm9ldk9Meng5NXZoVW1nYmxJNkxCWndUQ0RZN3ZNcTBvcDVXVlhnc09iT1hKKzF4M3FhQmw5ajFGZUx4YmhVOXcxRitXaWJhNnMxWC9UQnoxTG5VZnVZRGk0cjJDNjlmMWYxNEJXZlArcCtXMkdGS3VDOXBoY0VMTVlSUkx1cjlERVpUVWRFSCtpRXFXZGFNN1g0V09vUEdJK1pZRDIrd2NRK3kraW9IVVo5ZFREYkFyenhtaS9iSkk5Qk5EMFluZDZsQmR2ZS9idXRCdzgrZi9UOUQzQUJhM0FHOFczVlBYNGhCaW4rYmo4ZE1NbVNwcDVwZzdmSjZ4ckJGRTJXUVFFV25WOFFnM0ZiQVd6WWZNMXJSRUVubXZrTjJvMSthY0cyZC85dTY4R0R6eDkxdjNtQWpiMXprcHFUMjFPaXBQS08wYjlUTzVXMG5UZE9tQVFtMFRPYnRzM2FCS2d3QVJ0b1BEaUNUMGdIZ3duYkFyenhtdGNMYzA4SGdGMWFzTjBDNE1zL2Z2RDVJKzdQaGZxeVhFL2I3UmJickd5UlFSVDlBUlpjd0FVbWdkb3owZWhKOUZuN1FBaFVqaERBUVN3MGJWM1QzV2JOYTU5anptaVA2R3NXYkdYRFgyeXRqeTgrZjlUOTdmaUJQcTlZZUxkQm15dWl6WkhhcVhJVG5YaU1VRUVWY0o3SzRqM0JGUHVydEI0Yml4Vzh3VHB3ZUw4REM5NXN6V01PcXVjRllHc1diR1U3cDNUeHh4ZWZQK3Irb1RWa3R4WTB2NWhicTNLaU9LWW5ZOGRkSlZTQnh1TU1WZmZOYnh3SU9FUlNoc3Q3M0haNzhEWnJIcG1KbUgzSzZzR3owZmUzVVVqMGV5UnJTQ0dUVGMrcmpWTm9Hek5TdjA1c3JBeFVCaDhJaHFDaGlRZ1ZOSUlCSDNBVlBucnNuWFFaYkxUbThhbW12OGVWWG4vdldwYVRlbTVJWFJsdCtVL0xBMjF6aFNiOWN5ZTZqY09mQ25Pd2hJQVlYQU1WVFVOVjBRaFZoYTl4amdBMjdPREpiTGJtaXR0M3RSTjgwbHFHNk4va2hnb3Q0WlZsT3lPNFdOZzNPSU16aElaUXBVRUhpZWcyaW02RjkxaEIzSTJ0dWJxbDZCWU5OOUhqNVM3RzBHMnRhaHNsQldLRG5PaUl2dUFFRHpha0RRS0RORlFUNmdibjhFMnk0QkJ1Yk0yMzBZSXBCbkRiTWEreTNkeDBuMVMwQnR1RzYybENDWHdjWTBGNzJUMVZSUjN0Mk9OY3NtRGpibXpOdDlSRnMyTE8yaFFOeWIwMjJKaXNhSThyQVd1dzRISTNGdUFJaFpkT0dJY2RqTEp2dk9icWxwcXZXVEpublFieWkvMU05TzhVeFdoQnMvL0g0MkkwcTFZYi9YUEdPTnpjbW0rcmkxNzJtSEt2WkJwSGtKYU5KejZ2OWp4cWlrbERqM1U0Q0EydWdwQWFZTVdxTlhzZFhibUpOZDllZ0NuSkVzcGhYTk0rTW5LM20wRkNKNVMxa21KcGEzRGdQVmJuUW5QR1dJRHNwVzlvemJjTzRLLzlMa2ZhUU8yS0h1cWxmRlhTYmROemNFY3dvcU5FRkU5emNJWHU5LzZuL3ltL0JDL0MzYUpMekVLUHVZVmxiRm5maFo4a2NXeFYzZGJ2NGJLbDI4NTY2d0QrOEM1M2F3NDlsVEFCcDlQV2JzQitrbmZjL0xpM2VWaXpmNXZ2L3htdm5QS2c1aWh3S0V3bHJjSHF1Y3VWY1ZPeEV2OGFIMzdFM1pxcFp5cFV1bHJIRXRJV0tVcit0eEhnK29qWkRHbHducW1rR2x6Y1ZpMWRMaU5TSmlIamZiUk5PUHdLcHg5VFZkVG4zSzA1REJ4NHBzSWs0RWk4YUNrSmFoUmdmZms0WW5FWGUwN1Q0SDJSUjF1MjdFNndmUXNCRG9mVWdqRlVGbndDMkFpVnRBKzA1SjJ6cGlESzJPYTBjNWZtQWVjTjFpSnptcHFGWnhxWUJDWWhGVENzVU5FbVVuSWNaNmFFQTVyUVZoRXl3RzZ3N0hTVzAyWGZPb0JsUW1qd3VsT0ZRQWc2NlN2SmJsclRFWDFZdEozdUcxNVQvQkgxT2ZPUWV1UjhnL2MwZ2RwVDVmeDJTS2JzOUVmSFRLZE04QTFHYUpSSExWSXdoY0d5eWRac2JpZkFGVktsNUVNS05VMkhyeW8rMDZCZVRncW54ellqVGhWeVNEaWtidEpQaWVjbzc1bFlmS0FKT01FWkJUam9JVHVXSFhYWlZoY1VESVMyaHBpWEhWOUt1NHU0NGJONU9ZTERPa0pvOHcreEpTTWJoQlJIRWRFczlKWlVDa1FyUE1BdmFIeUxreGdrRUh4aU5reC94MllCMG1Hc1E4RVVXai9zdFc1WUxodFM1U011Ky9ZQmJOUERDa0dUVXliTjhrclJMQkdQbFprVk9BMGorYTErcmt5UUtXR2FQSFBMWk9rSmhpb1FZblZaMmhTM3pWeE10Z0M0Nkt1UndiSk5kOW5WMlBIZ2IzNkYxOTRlY2YvWWV1MnZBRmU1bm0vYlJCRnJuWTRCYXVFOEVSbVpSRlVuMGs4aGJmdGlWWVNLTUVtZTJkSkNKU0NHWUFsTnFoODdiWE9QZFVrR3kyNFA2ZDFsbDIxTUJxcXg0OEZ2djhaSEg4SFpGWTdqL3VBcTF4TUpVRnFDU1VsSlBtTmJJaU5zbXd1TXMvcTlDTXRzWnNGTzZTcHJ6Q1MxWjdRTDh4Q1FDbEVlbHBqVGR1RE1zbVdEOFMxUFQxNTJCdHZtSUd2VWVEQS95Um44M3UveDAvNHF4b1BIangrUFhZOXBxWDliZ012aC9OejlrcFA0cE9lMS9mWWYzYXhVaU1kSExsUHBaQ05qZ3RORkFoY0hFRHhUdW1OT05oSHJCZHVXK3ZPeVkrKzcwV1duUFhqOThlQTRrT3QvbWovNUUwNWw5K080bzhlUHg2N0hGcXlDK3FTU255c2VscWpaR2FWSzJUYWRiRkxQV0FRNE5CaEhxRENDVjdPVHBvMzRBbFNTeWxQdElkZDJBSlpseXpZUXJESjVsY1dHTmNlRDgwQ3VuUExHR3pzZkQrN3dSYjk1TmV2Skk1ZG9jUTN0Z0N5cjViR255YVBSbG13TnNGRUxWaU9PeDlsb2ViR05xMm1vRE9LcEhMVlA1YWwyY3ltV0hia2Z6R1hMN2tmUmw0NEg5d1p5MzN0dnQrUEIvWG5mOTNlK25oNVpsVTE4d0NpUlVhOW03a2liOUxZdU9rK2h1ZFFOYnh3bTBBUXFiZmxvaW1hQjJsTTVmQ2hleCt5bE13dVRiZm1YUXRtV2xlblpsamJkWFRMdU94akkvZkRESFk0SGp4OC9IcnNlMHpYZlBGeGJVTjFrS3FTQ0NTazUwbTBBanR4M3ViOVhIQktIWEVTYjhpTzZFK3FHeXRGNG5PME9HM1NYemJKbGh4Qm5LdEt5bDBOd3lianZZQ0QzMGFNZGpnZVBIejhldTU2U1ZUQmJneEpNbGlRM09hdXdnMFFIeFhFMkV6L0VJUmVMZFFqNDJHemI0Q0xTMFlKRDl4VXg3YnNpMHZKaTVtVWJXMVF6TDBoMFBGazE3cnRpSVBmSms1Mk1CNDhmUHg2N25wSkp3eXJCYTJSQ0NRUlRiR1pTUEN4VFBPaU5ENEcycFl5T1E0aDRqSU5JSmg1d0ZVMU5GWnQrSXNaNTlMU25EcUJqWjJhd2JPa3UreUludW5MY2Q4VkE3ck5uT3hrUEhqOStQR1k5QjBNV0pKTm96T0ptbGdsdkRNWERFb3pkaFFXYmdzL1U2b0Jhbkd6THJkU05OblpGak9rbWJpNWJOdDFsWDdKTExobjN2WEFnOS9oNHkvSGc4ZVBISTlkelFNRWtXQ2dkUmZZeWtZS25rUDdENHJJdWpzdWphS1BCc0I1NHZFMlRTMDBjY3ZGWS9UdGg3SlhlcTFoeitxZ1Z5MDRzQUphd1Rzdk9rbkhmQ3dkeVQwNjJIQThlUDM0OFpqMHZkb1hGNHBpbEthMkJST2VkKzlmeXc5cldSWGVURlhFU01PYW52RFpmSnVKYVNYb3VRZE1kREpadGVrWmNMTHZFZUswNGQ4bTQ3NFVEdWFlblc0NEhqeDgvWG5zOVlZcVpwc3pHV0IzQU4vNFZIdytrN1dTRnRKM1FpY3VxYi9ObFZtZ1hXc3hoNTcweGcyVXd4VXczV2ZPNkI1bk91TzhhQTdsblp4dVBCNDhmUHg2em5tMWk0YnNmY2JhcHRGM3pOVDc4ZUZQdHdpMU9hQ05PcXAxeDN6VUdjcy9QTisrQUdEMStmTVhyU1ZtMmJhVHRQaFBhaGJQaEE3MXdJSGQyYlh6UmE2OW5HKzNDcmFUdFBpdmFoVi81NXRYV2c4ZnlSWS85QWRzWThWYlNkcDhWN2NLcnJnZGZNLy96NklMUUZ0SjJueEh0d211b0I0L2tmNzQrZ0xlUnR2dk1hQmRlU3ozNCt2aWZ4MFlHMjBqYmZUYTBDNit0SHJ3ZS8vTm1PRzBMOEViU2RwOFI3Y0xyclFlLzk5Nk8rYWkzdWpRT3NrcFROVUxhN2pPalhYajk5ZUNkOGxIdm9GaXdzYlRkWjBhNzhQcnJ3VHZsbzk2NnBMdVJ0QjJmRmUzQ202b0hQOWtOSC9XMkZyeXh0TjFuVEx2d1J1ckJPK0tqM3BXWEhpZHR4MmRGdS9CbTY4RmI4MUh2eWt1UGxyYjdMR2tYM213OWVHcys2aDFZOE1iU2RqZWdYY2d1UUxqbWV2RHBUUUxNeHRKMk42TmR5Qlp1OUFicndWdndVVytMYnRlVUxVcENkcW0wSFRlbFhiaE5QZThHNjhHYjhsRnZWZllmU051eHZyVGRUV29YYm96QXpkYURaemZrb3JPajFveFZ4bElNbHBTSWxwTHJ0OEQ0aHJRTDE3eitjM2g2aFUvd3Y0US91dHBzNCtibSs2UC9oSWNmMEp3UTVvUUdQQkwwZUtQVFlFWFRXK2VMLzJES243M0o5QlRYWUFORzU3aHoxY0VNdmlWZi80dGY1Yi82QzVwVFFrTUlXb0FxN2hUcE9KanRBTTRweEt1NXZnNXZYZVVydEkwOS9Nby81SCs0eitNcDV4VUxoN2NFbTJRYlJQMnRGSUtSN1dNM2ZQZi9qWjNTV0NxTE0ybDROeElENXpCNzJIUVh2M2pqLzhtTFI1eFhOQTV2OEViRlFFejdQcFJmbDErTUIvaGxBTjY1cWdEbjN3VGdIMTNoSzdUNTlibVArTkl4MVNISFU4NG5MT0lUdDNpVno4bU5PK2xQcmpHQW5CRnFtaW9ObjFtVHlrMXRhNDdSNmQ0TXJYN3Rqcm5qWVVwZFVidjJyVnI2WXBWZnNHRzU4QUc4QWg5ZXlVTjhDWDRXZmdWK0c4TFZXUERHYitaZDRjVTU4NEN0cVNiTUt4YXV4VGcrZHluL0xrVmdBK0lSOEtIdGVqZUZLUnRUbUxMcHhONm1ZVkxqWXh3WGY1eDJWb2ZpWmNwL2x3S2s0d0dPcFlEbm9JWlBkZy9BQWJ3TWZ4MCtnZTlkZ1p2WWp1cUtlNEhuR255a1lvNVR2SmJHMFZqMTJKYWdSaHdLYTQ0SDk1U2hrWmE1UnlMR0dkZll2RzdhdzFUc0Y2aWFwUEFTMjltTlMzTm1zVFFaQ21nVHpGd2dMM3VwQ1RndEJUUnd2R01BS3JnTG40ZXZ3aW44K2FmSlJjZmYrOGl6VUdVTTYzR09PdUFzM3RKa3c3SjRreW9OcmVxcnBPNmNZTFFlRlVkN1RUcHI1WU9UTGM5UlVVb2dVT1ZKUTFHWUphRkxBVzBvVG1LeVlTNDZab29QNFM0RU9OM3hRNXpDOC9DWDRDbk00YzFQRThBcGV4cG9ZdXpxbFAzZDRTM09KUDhaREs3Y0tXTmFUbHFtZ0RpaUh3bDFZc0U0MXcxelQ0aVJUbTNEQnF4dk9Vc2JNS0tEYS9FSHhhZ3RudGEwNzJlamMzRE9JaDVvanZoOGwzdGsxSkYvQVY2RlU2amgzVThId0VhekxnZENMWVNRK01ZaUFJMmx0b21renR0VWIwZ0dIZFNVVWdzSVlqVHpMRzNtT2JYNEZCUmFZdHBEVk5acmloOVRnVGVZT0J4c0VuTjFnT0NUTThCc3cvaWVNYzc1dzlrdUFUNkErL0FpSEd2Ti8rR240S1JraXV6cE5ORFloREdGbmRXUnBFNlNWZm04VTVieG5TZ1ZWMmpyZzZKQ0ttbmVxZXk4Vk1GZ3EyK0FNL2k0TDRSVWJmU2kyN2xOWFo3UjdXOVJUY3EvcTlmazRYdzNBTVFkNEk1aWZBWno4RmNWdG05U0FvbS9keU40bGN6SlFXL2tDNDJackhnY0NvSWYxb1ZNS2tWSXRtTUJpOWNPZU5IR0xxT1prK1FxUW1yYmM1WW1ZZ3hFTFVVTjM1ejJpb2hzdGdmTElGbWNNVjdzNENGbUk3NEw5K0VGbUdzaSt0R25BT0Q0WWs5Z0lwbzAxWTRjQTQzQldHeWdNZHI0WVpla0czT0JJVVhYTnVrdkpTOHRxYTA2ZStsU0RDdG5xcU1GdTZoV0hYQ0YrV2FZdDY0bTlRQm1OeGk3SW95N0QrZmExeUh3K0ZNQWNQdDdTeXNGTHRvRzRQWEFrN0pPQTNhQXhCUnFVaUFkVTlZcDVsSzNITFNSRnRPaW0wc2E4ZXVFdDA4eHZLallqemVKMkdVN1lhd2V4cm5LSTl0bW9iSW5qRlhDZXdwd3JpWTkrUlI0YWFlekZoTWhHQ3BwS3dvbTBDaHJnRmxLenlQS2tHbFRXMVlRckU5SEpxdThoS0dnTWM2aFZpNVFScTBQWnhOZnJZTmdFNjR1dG1SdjZLS0hScHhmNlZEVWFPdk5QNWpDRXg1cTE4NU15LzdSS3o2OVVRdTJpbTVrNC9lb3ducHhaeE5Md2laMUFaVE8yWmpXamtVOXVhQjJIRm42UTN1MEpjc1N4L3FWOWhURUFwUnplQkxESlFYeFltVG5xN2JkTGEzK3VxRnJ4TEo1dzFUZWhuTkh4NUVDdkNoMmcyYzNoSEg1WXNmZGFTS2RkenRmalE2aW1LRkdTeUZ3bEx6eEVHUHA2cjVJZXZWamsxQU14M3dNcWkxTnhEVmpMQmlQczl0YnNDa0lZNXdlNS9NTDIyenJDU2NGeG5OdHpzcjlXY2MzQ25EK3BZTys0VlhYaURFMG9jL3ZRUS9mREszb1BFU0pNWVhObUphL0R1bG9KWmtjVHBjWUU4bElIOER6OERKTWl5bk5DODZNYjJsTmFhcVAvK0w3ZjJmY0UveVA3L0xkZTh4ZmdTT2RNeHZPaXhaZi85cDMrTTRoVDErRit6QXB4ZzlYZlV2WWpjOHFYMmxmT09wSzJnTlJ0QjRmbHBGdTlGVEtDcDJYSlJnWG5YNm9scDF6eVlqVEtKU2tHbUxFMk5qVXIxYnhGTTRBZUFBSEJVRkllU0xxWFIrTnZIL005Zk9uZkh6T0QydkNTeVFKS3pmZ3NDaCt5aS9NbWMzNUYyZlVydzdtaVczM1c5aEJEMXZwdVVvakZwaEl5dmc3YVRlb3ltRGtJa2VXM1hMSG1ndU16YklBSmVqTjZCNU1EcmhpcEUyeTZTb0ZSTy9BSy9BY0hIWkhOSWZpV3JFZS9DNmNyM2YveU92clFLQit6TU01NS9HUWRMRHNSK2lmcjVGaXV1Ky95K003OEx6T0U1ZHNOdVhDM1BZdllXZDhOWHZwaExTa0pJYXNybEQyL0hPcVErUmpjUmRqS1RHV1loaFZVbTR5eGx5aUdQdU1zWlI3c01DSFVCZVR1TldBN2lmK2lmWGdjL2hvdmZ0SFhzL0RWK0Z2d2UrZjhzaHpNaU1jd2VGZ0JseTMvL3Z3SmZnNUFONDQ1MGZuMUhkMVJtMWFCTHUyMkR5M3kzSDIrT3FNZW1rYkdaNGpvemNEakpmNjU5NnhPTHBDMGVNVEhiS254THhIMjd1Wi9iTVRHczJqT2FNT1k0bTg3Q2ZRd0YwZHc1M29hMWs4MEpSdXovWGdTKzhmWDNOOUFmNHFQSU1mektnQ3A0SDVUREdlOUdHZUZQelNzWno4MFNsUFR4WGpnd0ptQzQ1bmp6Z3QydmJRNGI0T0FkVUs0L3ZXaE84ZDh2NkVFOGZNVXNmYWtYYlBwRkplTHMydWJNL3FkbS9sYTNXUDkxdVdoeFhIam9XaHlSVXEyaUovKzVtQTczendJSW8rTG9aL1NndklSakFkMUlNdnZuOThQZmdPdkFKZmhobThzY0FLVldEdWFSYUs4YVE5Zjd2dVBESDZCajQ3WlhhdTdycVlKNjZtVER3RURVNmxMYkNqQ0swcVRYeWw1bW5Eb2VOUnhhbmozRkpiYWtzVGswZmFYeEh4THJzc2dQa1dCOUxuQS9NRmxlWGNKb3p6andzVXZVRzBYL1FDdmU1MXFrTURYcDltdGN5T3kzcndCZmR2VkpLN0Q2L0FDU3pnM1JvcnVJcTVVRGVFU2ZFbVZjbER4bm5pVTgydnhNTHRjZUQwaEdaV3pCTlBNTS9qU1BuZTJPVmF0aVRLVXBZNXZZN2djMExkVUFXZVdNNXRIK08ySTY2QU9Xdzl4VDJCdXlSVkxHZG9ESFVzVlJYT28vYytaZFJYdkZmbnhXeUlWNHVwRkxDbDllQUw3aDhadjBRSDhSeThwQTJjSHpRcEdlc2N0VkEzN1p0a2xCVGdIanl2ZFNlS1kvUlp3L2tKTWswWTI1Y1NOUldTaWdRdGxVTFBUdytrenVKUGVZRWtYalFScG9HWm9iWXNMRjc5cHlkMWRNUkhJbmJnRlRacU5MaERxaUlzVE5wb2V4MldMY3kwL1g2ckhjZE1NUXZGU2Q1ZFdBKys0UDd4djg5ZGVBQ25tcjM2dUdsTDY5YlJDTDZCU1pzUzZjMFRVMlRLSzVndFdDemdBT093UWN1cnFrOWo4d2h2emlaU01MY3E1aGJ1d0JFc1lqb3BVQmtxdzF5WUJHcExBOTdTUkVsRW14NU1DSW5CWTV2Z0xrOTRpS3FTV21oSUdta0o0Qmk5bTRMNjQ1SjY4THlZNHdzRllCZlVnNWZlUC82Z1dXbTU4SUVtS1FNODlocTdLc1pOYUt0UDVUeHhyVVpaVmtObU1KdGpiS3JHeExORWJIUEp4aHF5N2xBbWJDMzJacWVGNmxUYWtuUldjWWFGcGZMVUJoL3J3YVF5Y0NDSm1XMTVLc3R2NmpSSHlKRnJ5MkMxYWhra0lXMExPNzVzNjErb3d4SzF5M1hxd2VYOW01WUxNMkRQRmVPam4vaWlxQ0tKK3lLWEY4dDVZbC9rTnNxYVNDcnl4UHE1eFdURklhUDhLU1cwUll4cXVwYVVmMFJjVE5TU2RKWkdjS1lkWUE2a2R0cnRteUJja2ZLWHdxazBwSHBVSGx3V2FmZmpOUkJZRlBVRFdhOGUzTHQvbzBSMENkaXNLRE04OWNYMHB2UkhFZk04Y2E0dDBzMlh4NGtnbzkxTVBRSi8wYzlNUVlxMGNvOE1CaDdiejFmaW8wVVVITFI0YUFJT3ZPbW9ZTzZrd2xFVk9EU1NUbGlXdE90SDZzUGtydGN0RjladEo5R0llckJza3ZoZFZTNWNGTnY5czFCVTBBYmRVZ2RLNEZHK2RSbmpGbURUem5pUk1kWk8xUWh6TUszNTV2aWdiZGtwejlQNnFqVUdFNUoycUFjWG13SjIwY1pVaUFEMHorcEdNeDZ4a3pKa21FZjQwSHI0cVpmVmcyWHpGOVlPeW9WNUJqelZrVUpuZ0tmOGxnTll3S0VDRUhyQ05Ecldaek1sZmxTM3lCaHIvSW55b1VnQmMvbEtUNHB4VnJyQzZnMVl3Y2NlSzNCbU54WmNBdHozajVFSXBxZ3VoOUg2d2MwMTFZTjc1Y0tETHBGRHh1d2tyUFFtVXdXNEtUYmo5bVpUd0J3THE0YVFNVVpiSG0xcnlsSjQ2ZHpSMGR1YTJuM1JZQ1dac2lIUk9leXd5SkdSN21YS2xwcnl5Q2lvdVk1NnNGa0JXRW5rRUIvcmFlaC9TdzQxNjJLZXVBeE1RcEVrenk1YWxNWTV3YW1Nc1dLS3J0VzJXcEVXTm5SZVpXT05LV2pyZHNLWmFycEZqcUNzbHE3NzNQTG1FaE00NDhQYzMrRktyMSs5NHZ2L3JmdzR0RWN1K2xLVEJlNGtaU2RpakJyeWt3djl2YkNNUGNMUVR5Z0JqelZja1NMUFJWR3NscWR1bndKNG9lZ3RGT1liNFN3eE5nV0xDbUQ3VDlrVmpUdjVZRGdwbzBYQm1OMzRaL3JFSHAwc2d5ejdsbmdzcm00bHZNbTJNcjF6Tk9KWUo1Y3V4dVF4d01HSnEvVFA1ZW1sYjhmc1FCWnZpSzR0OGhGTCt6Ymh0bHB3YVJTeFFSV2ZlRVRqdWF1UHNkR3hzQlZkTzdubVA0eHZ6U29UMjlwUmw3a0dxeitrMjZCM095MFlOVitTWGJiUWFzMWN0Qy9HYXJza1JkRnBLY3pWQUYxWlhuTGNwYU11elZlNmxaMmcvMW5kY3ZPVmdSRzNzZFVBWTFiS0Q2YWNoaWpNUGRNeFY0bXVLVm9yU3BpREhpdHVIN3JTVHM3bi80eTVEaFJYbzRGVkJONHZPL3piQWN4aEVOekdiSEN6VS85OE1jeDVlN2EzMWtXanc5RkNlL3pOZVl5UWpac1diMXVjN1UzM3BONE1qaTZoQ0xoaXZxZmE5U3M2eExnMDMxQWdmZXNBL2w5OW05Zmd2bmFGOUpvRTZiWUtta0dOSzNhUGJIQjk2dzMrRG54Rm00aHMwZHJMc2s3VThrZi9OL0N2d1FOdGxsbmEwcmpxNjFzSDhMODBIQXV2d0gxdHZCeTJDaHFXU0NhWVRhR04xOXNUdmxmekZENm4raUtUYnZ0YXlmcmZlOXVlV2g2R0pGb3hMZHI3VjcyYTVacHZIY0NQRHptYTB3VE80RWdiTHllZHhzdE84MW41N0xZQk9Cenlmc09oVUtzVzFKMUJCNXZyL3R6OFJ5cU9GeWxRUDlUdnN0MkpBTHNDNWxzSDhQeVE0MERWNEFOellhNGRlZE5pS05SMXMreDJ3d2JSN3E0LzRjVHhxRWs0TFdEZWJmaXN1bzM2SlhMaVdGak90THJsTldoM0sxclJTNHh2SGNETmxGbk5tV0JCQWw1U1dhTDNvUE9mbnZicjVwZGpWbkVhZUJKU1lqdUxFa3lMTHNXaEtjY2FkbU9waFprT1BnVmRhbGoyUXBTbWZPc0FEaE1XRTJaQnU0K0VFSkk0d0tUQXVDb0M0eHdRYldYQmx0cHhiamtYSnRLeHhhYm85ZTd0eWhsZ2I2Z05sU2JVcE1oK2wvRmFxelZ3ZXdHdThCVzFaeDdwVHBRREpVamI4dHNVVFc2K0dEWGJNbjNtTGJYbFhKaUdkZ2d4RkFvVXJ0UFMzd0U0TmswMlVaRzJPT3psazdmUnM3aTk1UUNMbzNFMGp0cmpuTTdTUjN1UzFwNHF0UzJuSjVPd3RRVkhnT3ZBckxCRmlqWlVWOVF0U2w4ZEFZNWQwRTBoTTB3M0hTMkRwSWVCNm0vQTErSGZoSmNHVXE0c094SCt4M2Y1K1ZPK0RzOXJZTkk3elBYT1lXUHJ0ZjhiWU14NmZ1T0FYNWp6TlIwUGRzdU9OK1gxZjdFRVJ4TUpKb1U2R2tURVdCdlZvbFZsYjVsaDN0S0NnNld4MUliYU1EZEorOXNVQ2M1S0M0NmhLR0NrM0lWT1M0VENxZEJOZlVzN0tkNGlYZjJSam5UL0xMeXNKeTNYRGNITGgvdmRlM3g4RG9Hdndnc2E2N3ZCazkxRzVQZS9IYk9lN3h3eW0wTlhidGl1dURrR08ySUpEaDlvUXZKNGNZNHZkb3FMRHVvSDlabDJGL29mc2Vrbjhsa3VoSWxoUWNmZlV0U2p5dEZ5cCsrcDZOaUU3UnF4L2xvZGdLVm9jZUVwL0NQNEZmanJxdVphVHRqMkF2SDVLL3l3cG43TTM0Sy9Tc29ZREFkSU40NDhJMS8wL3d2ZVcyODlUMS9sWDV4QnpjOE41SWFIcjBYTU9RZEhzSWtEdUpGaWZqMjBwQm01anp3VXY5ZTJGaHdSc3ZoQWJhbENJdUl3M2JoSmloWTNwNm5URkZJWmdpU1lqZlRmM2FYdU9qbWVHbjRiUG9HdndsK0NGelRSY3pCSXVIQkVlSW1IYzM3L2xHZndaUjBjWHpWRE92YUtmTkh2d2Urc3VaNzcxSy95L1hjQmxzb045OTZKcEJob0UydG9ZeE96bk5FT1M1VEpjNklkNUdFWExqcldvK0xFV0dOcFBEVTRXQXdzSVJST3UrMXZNKzBvVzM3ei9NQk45a3FIblNBcndQZmdGSjdDcS9BaTNJZTdnN25jbUkwOXY4c2p6dzltek9BRVhvSUh4VVJ1ZWFBY2U1VjgwZi9ET3V1WndITTh2c01iNXdCek9GV003d3ltVFhQQUV2bTR2Y0ZwWjJ1dDBWWlJqa2lQMk1sbUxkNkRJcGJHU2lIT2pkblVITjkwaFJZbWhUbm12aHpwMWlLRE5qK2I3dDVoaTc5bFdHd1ErSE45UnNmRk15MEZYYkV3aGZ1Y3pLZ0NieXhZd0JtY0ZoaHZvLzdhNDR2K2kzWFdjd0RQODZQenBHUVlkV2g3Y3NQNWRCdloxak56ZHhDOHBCR3V4cVNXNXZ3NDBuQnBqNUpoTXd2T3pOMFJXcUVSSE1yNEx2MWtXWDg0eExSODMwRzNqNnlxWjFhOFVzdFRsVytxSlBPWitzWjd4WlBLVEpMaGlOT0FGZDZ0aytqclRIMzFuY0xPeGlkOCtuelJiMTI4SGhVY3J1L3kwV242aVQyNTRZUEM2RnRWU0lNb1cyc2s3MjdBaHZUdHJXS1pUdmdzbWNrZlhZWldlTlJYeC8zWVEyT1V4TERyYkh0TjExSXdyZ1hUNmM4ZEFURHdMbmlZd3h6TzRSenVRcVRLU0M1Z0FvZk1aMVFCSzN6UTRKV29iRmJjdkptODdGSys2SlhyS2FoTG41NG0zcCtNY1h6ell0UDhWRi9RcEp1aDFPd2llRWxFb0kxcFJ4UFMwOUZCcmtxMnRXQ1U1OStIZGhOdFRJcUttOEVCcncyUlRPRURwRzNJS28yWTdtRmRMbTNaZVZqWXdWdzExby9vem5jZU12ZTRDZ01mTnltL3V0QS9kL0lMTVI3Z3BYelJ5OWVEc2dMY2diczhPMlZhMUwwenpJZHdHR2VtVEJ1d1JPSGVvTVNoa1VjN1ArSVNZM0tINVpaZVdxTzhtRlR4UVllWFROdXp2dks1RkdQZFFmdXUwMER3WUZZOWR5aGN0RXQrT0pEZG51Y2ZwbXloelVKemZzSmpyMjlsOFMwYlhCZndSUzlaVDI2dG1NSWRadWNjaDVaYm9NejNOaW8zbklPc1lIQ0dvRFQ0a1VBOU1pWEVwOVhzdWkxUzh0aC9rYldJck1CeERHTG9kV1VRSVdjdm5YeSs5TTIzeFBpU01PaVJQcU0rWU1Ya1VOM2dYRnJaSndYR3pVYU1wSmZ5UlM5WlQwbFBlOFRwU2N1UmxiTUhlVW1sYUtEb051eTYyaVdOVFdORllqb3hGenVKczhvUitSaFJ4N080U1ZOU1hwYTBaSlEwSzFMQUhEUStEOUllcGtNWHBjc3E1RVZDdkNsQlVJekRoRG95S3dEdzFMYzU5R2JUZU9SaXZ1Z3cxSWN1YUVPYUdXZE5tK1BzNWZRNy90bTBEak1lZ3EzeU0zdmI1ajEycVVJZDVVWkQyb3hEU0VXT1pNU3FGbC9XKzVveW5XRGEvYUkwNHRKUlEyZVRYdXNnODZTUVZ1L253U1l3cFc2d0xqbHFJendMdXhHSXZvQXZ1bDBQUytaTnowL2FrcC9wbmlPLzhKRG5HeWFDa3piaGw2WWNxbUsvNjlwcnhQcXRweDIrS205YWw5c2pMK3J3TWdIdzRqRS9DOC9IUTNtMXZCdUwxZmxkYnpkOG1PdWVWSjkyc3lxZEVZNEtKalNDZGUzbWNSdzJUQTZzenhlZG4rendoWk1wczBYcnFFc2lVam5DMWh3MFRFTEMyRWs3dUFBZHpjaGVYdjFCWUxhZ3NweHB6U0FvWlpVc0l6SXEzNU1uRlE5RE9ybE5CMzBqcTNMNHBraGNjS1VBQTgvb2N2TjFSeng5UXlPdEVSczRDVnNKUksvREY3MWtQWXJ4WXNHc202Uk1oNGNwczVnMURPbU01NEx5MWlpMEhkM1kvQk1rOFZXRmdCVm1ocXJrSkNQQkhBb2x3WmFXekxSOVZiN2JjV2RYOU55VVlFK3VCMkJLZnVhZUJVY2pEbGpiWVZZNERkdHNWV3Z6UlpkV255VXpEcGpObDFEdTNhbG9BalZKVE5EcGNJT1ZWaHJIRkY2NmxMZkpMMXpKcjlQUTJuRkpTQmFLb0RlK3NBdkx1ZlpWSFZ6WWg3VzBoL2M2QUFaKzdUdmo2cTlqNjhHL2NUQ1MvM24xdkxLSFp3TmkrUCtwUzBXa1pOTUJNVWwrTERMdWlFNG9tWnk3MXIzVUZNd05KVitWSi9HQzVpeFZVa0JTdHNUNGdHS2gwR200T3kzcXZxN0xibXEyNG5QZER1RFI5ZGVSMTFYelA0dkZ1M1RZemZuSXlpU1ZtZ2l6VVlHcWtJWE5kS1RZOXBnYjlEMkl4NXQwK05Ia1Z6Q2RVMDNzdVdra1ZaQW9DT05DbjBUMzVnQWVXMzhkZTQzbWY5N3NNT3BTdmo0YWExS1lVbTU4VVNJN1d4eGVzMDNiQVpkUnprNlV0YnpNYUNRNkl4TzBkeTdYK1hzam9EMTZocHNCZUd6OWRmekhqK1IvSHA4bkN4WlJxa0VEVGFDS0NTeXdqaWFvTUoxVElURTllZzdKcW5xOEhMNmdEd2laYjB1MFYwUnIvcm12cWp4S3VhTENYN1pXWFR2QVkrdXZtM3o4Q1A3bnpWcG5ncXJKcFpLd1duQ1VqSXZpWVZsaXJsR096UExJM1NNVnlwL2VsdkJVampEa05ocnR1ZkZGRXJROHBtZFNsYksxNnRvQkhsdC9IVjh1SE1YL3ZFR0FMa1YzUkpSRWlTbG9weHdkTVhPWlBMWitpeCtrQUhwTUtJazhVdEUxeWd0cXV0dHd4TmhwaHJJWjFJQnpqR0YzSUlHeEdjQmo2cThiSEpCRzhUOXZkc29XclRGRXVlYkVadVZ4aGhDbEg2UDVabzg5T0c5ZndITmp0TlFUcEQwVEc5UEpMRVlxdkVZNlJseHkrWlpHZkwwQWo2Mi9iblFDWHAvL2VlTTRLemZRVkpiZ01RYlVqbE1GSW02VHBjZldsWmplN05CU1Y2SXNFVm11bVdJYmppbG9VelFYOU96WWRvOEwxd2p3MlBycnBpbU9OZm1mTnl6S2tscmduRWtTelQ1UVdZUVc0MFlTaHl6cXNSbU1YYnZWeEt0R3VZeU1LYVUxdWdlbkxEbTVJbHk0aVQxNGZQMTFNeCt4SnYrelozTXZuZmRGcXhVM2ExVy9GVEI0bTNRZnN5YzFYVWNkVmhEZVVEWlhTRkhITFFqL1k1anRDN1pxTTBDWEd3QjRiUDExaTNMaE92elBHeWdZdGlVQml3UVYvNHdGTzBtYWppakdzYWZIeVJMdTB5RzZxMzVjTDFyT3BWeHIyczVjTTJqSllNQ2RjMTBBajZxL2JsUnBXSi8vK2RtbTVwc01sMEtBMitBRlJ4OWpNZTJXYkM0alF4bmlrZDREVThUd1VqUlZhY2dkbGhtcjNicGRkenVKOXpYcXIyeG54SmZ6UDI5UmV4ZHRqRFZacXprcWE2UHl2Y29qR3Jma1hpSjhTRXRtbC9uWXNraWN2MGl2bHhicWplbXdVak13NWV2ZGc4ZlVYOW5PaUMvbGY5NFEyaTdNVVJrOW5XMU1TajVqOGVBeVY2eTVDTjJTNnFibnczdmRBMUl3cStYT1NDbDY2M3VkTjNJekxucnQrdXMyNWNJMStaODNTWFFVbGRxUXEwYjVYT1QxN2JHcExkNnNzTjFWTVBmOGMrakc4TDNOZUNuTWRGK1JhM2ZSYTlkZnQzOS9MdVovM3Z3SG9IcnFHbVFGYWZtaVF3NmV5ek14UzA1SzRiTDl1QStTS1VRekNuU0RrcU9Hb2tYeUp2YmdKL0JISStxdlk2OS8vNHJsMjBOc21LMm91MmRUc3lJQUx2LzkxLzhuM1AyQWFvNzFXRkdpOEtLdjFmUkM1K0o2N1EvNTA3L0UvU09zaHFONVRzbVlJalZ0K2tjakF4OThpei80U2FvamJJVjFyZXhFNy9DMjlIY1lEL0RYNGEwckJPRjVWVHU3b21zYjExTC9BV2NWbGNWWkhTc3FHdVhMTHA5aGE4SS8vdzNNditUNEV3N25UQnNtZ2Fwb0NyTkZPYkljTjRwZi9PYi9tcnZIVEdxcWdBdXBMOHFXaldQUzltLzMxakFlNERqQSs0K3VDb1FvVC96T3psck5kM3FkNFNkcGhGeHNVdll3R1diVFd0SVNjM3dOT1dIK2tIQk1mYzZrcG1wd1BnSFd3cWFTVUcyWldXaGVZT0dRR2FIQitlUS9rbjZiM3BPZ0xWK09EU245NHdEdnI4QnZiNzAvTEx1aVBQRXI4T0dWV2ZEbXI0NVBaeWNjRW1zVlhaR2UxcFJOWDlTVTUrQVZRa05USVZQQ0hGL2pHbXlEQzlqNFI5TGZXY1F2ZmlFVG1nTU1VQ01OMXVOQ2Fra3dlWnNvd2RZb2JpTVNsbktBOTN1N056VFhsU2ZlK1NWYmZuUFFYbWc5THBZQVF4cHdFdE9OeUV5YXVlV000RlBqanlqRzN1T2FGbUJUV0ROZ0JYR0VpUXBzYVdobkFxSWlqQjA3RGxzeTNmVUdlUDk4OXhiV2t5ZitGRjJTTkV0VDFFMGY0RFlZVmx4RmxiYVNNUElSTWsvM2lNVTVwTUUyU0lXSnZqY2tjaWVia1F1SVJSeWhVdmtIZy9pVWxqRzVrelZvZzVoVjd2SWxDdUJybWxodmdQZk5IUU04bENmK0ZFR3NZYk1JQkMwcUM5YTB1dXkyd0xYVmJMQmFQNWtqSG9rQ1J4YXBrUXl6STRRRWN3Z1lIUlpCcCtYRUZUcVhGdU5Wek10alhMSmdYNGdBaWQyNEhqd2M0TjNkdFZTZStOTml3VHJ6SDRXVlVPbERvYlVxcjFGdUFnWWxsYzhwbXpvVnJFTFJIU0lXOFZpUHhOeTR4d2pCcHlSNTVJNkoyMjBxUVRaWVI0Z3V2VUlDSmlTcHI5Z0ZGbGU0UmNGL09NQjdCUmlYOHNTZmhwTlNPM2x2RVpDUWZMVVZUS1Q3OEVrMUxSTGhXTit5THlUbnA4cVdVWjQ2YjZ2eGRSR1hmSFZxeDNlSTc1WWFMYTRpTk5pSzROT1c3d1BXNmxoYlNPRjkvTTlxdzhlL2FvQjNkMTU2cVR6eHA4cFh4NUJLQXNZU1RPSUlpUGtwNjhHbVRxN3NadHZ5ekJRYVJMTnhJWitwYW96SFdvTEZlRXhJaFJCcldpdEhDQUhyQ0Y3L3RoaEQ4SmhZejg0d2c5M1FSVjg4d0x1TFk4ekY4c1EzNnFGMUo0NTViT2xnbkVMZnNoS1Z4WU9YS1Z1S3gwamFqMjJzY3pUUXFQcXRWL1hEZ3Bzd21HVFdXTVNEdzNzc3lVdW5MTHJWUEdqWVJzSDVnZ0hlSFNXaVY4a1QzM3ljRlNmTWdrb09LOGFwQ3llMEo2Vlc2R09ZdmZmZ1U5UldzdWtFaTJrVVYybmw0ZE9ZVXpSaWs5cDdiY0E0Z2dkSjUzTHhLY0VlMTdCMVI4ZXFBZDdkT2VwVjhzVFhmNWxoZWpvTDg1aFVkaERka25QdEtIRmhsak9UK2JkcTBoeGJtMzVwMm5jOCtKYTFJdyt0SnlrZ3AwRVd1QUFaWXdNVndhYzVLellNc2xodmdIZEhScnhLbnZoVFljZktzeFR4dFRFVGtqSE83cnIzempvVjI1bEFRSHJxcFY3YlRpeTJhWE1tVWhUQm5LUzkxamh0UjNHRW9GMG9MbldoV05uWWd0Y2M0TjBGeGxjZ1Q3eXozVGdOSUtrc2N4OWp0VjFaS3BXVytVYjF0YzFlT3Y1dWNkZ3B4K0ZKeTlwZ2JMRTd4RHlYYi9mK2hMSFZHZWl0SE9pNkE3eWJvM3NGOHNTN3c3Y2dkazBuSmFPbjNoTGozdXlEMFpwNXBhekZJVVhVcHVUVFUxOGQxRVBrRG9YOFNrbVdUblZJb3pFZGJUY1pqb3F4aE5IZjFKclNTL0FjdkhqWi9TTUhoTC83aTV6K1BPc1RVaC84QnZOZllNVEE4bit5VS9NbFRaeFNKRFJTdHF2RXVMUUtXd0RjdE1UUW9nVUR5UVJvVFFHNUtjNm9RUkUxeVYxakNBN3JpN2pkWnlLMHNZVFJqQ1IwSG5uZCt5N25IeE5nVFVMcXcrOHdqMG1RS3hwWXZoam05dVNVeGcrVFR5N3MyR3RMVUdjeXdoWFNLWk4yNzVHc3FsY2xYOTBKNmJSSTFhb3V4bWdMN1EwTmVuNXppTTgwU3FNSW84Y1NPbys4WHBsVC81REhOV3NTVXIvNmxMTi9RUTNyRHl6THJ1RVc1ZW5wZjdLcVpvU2hFZHV1U0ZPVjdETFg3WWUrR21YYjYvaG5OTnFLc1ZYdU1ERnBiOVk5ZUgzQzZOR0V6dU91STNncE1IL0k2ZSt6RGlIMWZYaTE1dDN2QTFjenNMd3MwVEdFdG1QRUpkaWlGUHdsd0tiZ0xIQUZrNFA2WnlQZHltWVlIR0UwZHV0c0NoUUJsMkpjQkZsckVrWS9ONWJRZVhRMThnanVudU1mTWZzQmx4SlN4M25pTzQ4NWZ3TzRmR0Q1VC8rM2ZQUXFrbmVXVmR3bncvM2JNUGtXOVdicWcraUM3NjVaayt4Y1Q5OGliS1pjMkVkZ0hjTG9GOGNTT28vT2M4ZlMrT3lFVUxGNGc0c0pxWFZjbWZNZnNjN0E4djEveWZHWG1MOUk2Rm41cFJ3WmhzUHYwVHhGTmxBZlpDdkcrT29oaTgyVUM1Zi8ySXNKbzBjVE9tOVlyRG9LaEZQRVVyL0xCWVRVTmh0OXplbEhYRHF3ZlBDSXc0b3dwM21PY0lRY0x0dFdYRmUzVlovajVIM2NJYzBHNm9QYkNSKzZZMnhGMkVDNWNHVW02d0tDNXRHRXpoc1dxdzVoTmlkVWlLWDVnRldFMUdYaDQvUXBsdzRzVnpPbXg5UXhVNzhnM0VGNnduWmxFTjRGekoxUVBTTEVaejFLZlhDN3ZkOHNzR2RJYk5VWXBWeDRVYXB5RlVIekpvVE9vMU1jU2tlTm4xTTVNRFFmczRxUXVoaFg1dlFaRnc4c3V3V1RjeVlUZ2lvSVNrMllkbWtoZWhHNFBrRTd3NTFpbnlBR0dhVSt1Q1hBRGFiR3pKUjFmbjNsd2t0eTBhc0lvOGNST205VnkxZzB5RHh4dFB2SERBbXB1K1BLbk04SXgxd3dzR3c5MVlKcWh0ZWFXZ2pZQm1tUWllYm1TcHdLS3pFMTloeDdqa3pTV09tNjZvUGJ6WjhZajZreFZTcFlqVkF1dkx6WU1DUm8zb1RRZWNPT2pqZ2kzTlE0bDlLNS9oT0doTlRkY1dWT1RybGdZTmtFWElOYnBDa0JSeXFocCtMZFJCM2cwT1U2ck1mVzJIUENGRk1WOW5TcCt1QjJ3b2VwZGJMQnVKUXlhdy9aRnlzWHJsWHdIeEkwYjBMb3ZFa2lPcFhHQTFJamFnZitLVU5DNnJLTmE5YlFuTEZxWU5rRW5NYzF1SnJnMnU2NEVMUEJIcGtnV2Jtd0twSm9EaE13TmJiR3pBcDdZZzMxd1MyVDVyR3R6aXQ1OVByS2hlc1dHNTUwQ1pwSEV6cHYyTkdSYXhsTmpiTXFwbUVJenlnSnFRZmp5cHljczJwZzJjUzJSWTlyOEhVcWtxZEVnS1RXdFdUS29Sdk9CUERZQmx0amEyU08wUkdqeTlVSHR4d1JqQTExdWpiS0YrdGk1Y0lSOWVDbnhVZzZvd2lkdHlvVTV0SzROTGppNVEzSEN0aXlGMklxTEdZc0hWaU9YVFhPWXh1Y0RxRzBIeXR0cVlBS3FZbzNLVFkxZWt5RFhSQW0yQVdoOUptc1ZoL2NjZzlXSjJFOFlqRzIwMXNQcTVVTHh4WDhuM1hMWHVNSW5iZnQybWs4MHJSR2pDR2N0SjgvR0ZkbUVROVVnNEZsRTFsbDFZN2p0aXJhcW01RmUwNFZWOGx2U1ZCTDhoaVByZkZWZDgrN1FIM1FidTJpcFRWaThjdlNHaXZjOWNqOHl2SDExWU1IZE5TRVJ0dU9zbE05N2ZlWUZPUEt6R2NzSTR6VzBZR0FiVEFPYXhDbnhkZmlZVW1WV3NseGlJYmxDZUFZcjlWWVIxZ003R21vUHJpbHVuU3h4ZVQzRE4vMmVCUTlIMTErbmsxYWRuNlZLNzErNStKZmN0NC9lbDEwLzdLQlpmTnJ5VXVuV1NDUHhQRUNrMXJkT3YxV1ZTclFtcEMrVGw0NllEM2lrUVljcHVuU1FnelZCMlZIRmh4SFZHS0RnTUVZNUdMbFFuUDdGTUR6dzdJYWNBV25PNnNCcjEydStYYW5XMkFPMHdROHBrbm5GaHNMN0tZSXFoa0VQbUVYRmt3YU41S1FwaGJrVW1HNzJ3Z3c3V1NtOVJpTDlRVDkyNWhramlWSUlocGhGUzlIS0k2LzhRQWpscFhxZzlXMkMwYXB5YVZEd0tRd3J3TFkzajZBRFIxM1p5VU5CeVFYSFF1NlJZMDlIdTZ6TXFYUmFOWkdTL0tFSnMwY0pFZTlWSDFRZHZCU0p2OWgwOWVpUm15MFYydUpjcUhjU2hjZHZiU05nNWZ4a2Vua1ZwclhNOXJEVm5YMjQveTlNVnRuY3ZiS1k3MDZhbk5sM0FTbGw5YTQzVWlhY1ZxdVhHaHZxNHMyRlA2Mk5HS2ZRTElRWXU5cTFXbWRNZm1VckRHdDhlRFMwY1hvekgvZmptVUg2SnJ1dm01MGhCRFNhRVUvMlJ1MkxFTi9kbDAwNlRTYy9nN3RmSkVSeEdNc2dEVUVyMTA0cGZXSDlsUWFOK000S1dRandaYlZjMnJaVk5Ic3lIYWwyM3dadElzMkpKcXRJYy9XTFhYUkZDcEprZkU5anZXbGZGYnNOUTlwUDVaQlMwektoNFIwYU1GajFJalRjVG52aTBaejJydDdOZHZRYjJtZ2JqdTFwbHNIOE1tYm5FazdLYkswYit3QzJpeTNhWDNzelc4eGVadkR3RVQ2aFdaWXdxVFhTU0crd01FVEt1bTBEcS9xK3g2Mmd0MnVhMnBwQW8zMDlUUms5VFBhemZWM3FMOUg4ejd1aEdxR3F4TlZnL0ZLeDBIQmw5T1ZVT1JuOFE4Sng5Z0Z0dEdRVURyM3R6Y1hYOXhHZ04wRXB6TjltZFozR0FUdFBoTCtDanhGRG1rZUVVNng1NmtxWlJ1c0x6QUxYVnFrQ043ek1FY3F3am15d0RRNk9oeVVlMFhhbzFRcHluY3JnNndLcDlYZldEc2FacGxFbHZRL2Izc2R3ZWVnaG9yd0JEbEh6Z2sxSm1NYy93aUVSSUNWeTJWSkZkTWpGdUxRU3AzUzBXMytzbmd0Mm5qd05nTHNzRkdWUWRKMHR1MEtINGt5MUxXNHlyYmt1YUE2SXk5b3ovcUVNTVhNTURXeUlIaHNBeUZaYzJwZVY5aGM3a2lLdmZVTHhDbDlpZGRmUksxZjhrazlxdmJkT29CdE9nN1prT1o1TXNHclNIc29rZ0xYVXA5eTg4c21uaXdXeXVGU0lSVm1qcGxnYTN5RDhVaWo1UVMxWmlNNFUzUXc1UWxTbTJiWGpGZTZqenpCRnRwZysvWUJiTEFXRzdPUHluTmpsQ3c2NWZ1a0dOZGtKUmY3eU0xZk94VnpieE9KVm9jRm9ZSWFHd0gyMm1JUWtydnUxRTJuR3VlYnhJZ1c5VTlUU2l1a1BHVStMdCsrYzNESlBLaHloRUViWENRTFVwYWUyZXhpS3k2dE1QZTltRFJCRkNFTVRXcnR3eE44cXZ1R250Nk1vaWhLV1M1TlN5QmhiSDhTdFhvQXo4UExPclJnTHRPVC8rNHZjdSs3dkRMbnFOdnp0T3E3Zm1kOHNNbVk5WHpuMXpqOERxOCtYVmR1Mk52MElJeVNnRWRRbzN4VkhwczNRNWkzZkxGc1Y0YWlxekFpQmhiZ01ERWQxdWg4cVpaK2x3aGprZ29ra09JdjR4TkpteW5jZGZVVXpnQjRvRk1CdGl1NzFYdW1wei9QK2NmVVArU2x3RkV4d1dXNjJyN2IrTFNQeHF4bi9ndk1aNXo5QzE2dDE1VWJObHEramJHSnRjbzdwOHdiWWxMNGFsU3lmV2RldXUwajdKQTNKRk51VkF3dHN0N0Y3RmhXQmJQRk5LSVVPUm5kV3RMcmFGTG1NdTdLRlZERE96cWtlYWlOMzNZQVcvcjc2d1I0WEROL3lOMXo3aGVqUGF1MDZFZGRrUy82WFRoZmN6MWZJLzRLNzM2Zk80OHZseHQyUFhKWUZhZVVrRlM4VTE1WEUzNDI4eGR0bjJrYzhHUWxmMXZrSWFOUlJuT012TFRXclpiRWxFSGVMV2kxbzBkbEtQQWgxTVZnYmJWcXVQSjUrQ3I4TFU1L0gvK0kyUWxISVUyQ2xYTTlHOHY3UnI3b2MvaG96ZlVVZ3NQbmIzRCtJKzdXRjhrTk85MkdZMFNOdnV4aUUrMkJ0OHByVkpUa3pFNjRzZk9zdHh1d2Z4VVVveWs4VmpjVGxzcWUycUlUU0ZvU2o2RXBkNEtzVDZCWk9XbXRnRTNoQmZpcjhJelpEd2dWNFpUWnZEOFZ2UEhFUm84dit2TDFEQVNIVHovaTlPbEt1ZUhEaks1Um54L0pCMVZiMWlvWGRCcmExNmRtdDdkZ2lrMTB5QS9Gd0pTVlk2WGpBM295NFNxTTJmcnFEUFBTUk1leDlxczNYUXRvV3hNajcvRXI4R1dZc1hnamFWejRPWXVtUDIrOWtieHZueS82a3ZXc0VCdytmY2I1YkluYzhBUGRocE9TczAxdEVxSWtvaVpqYkFxS01ydUxiSllkZEh1SEZSSXlKY2JkRWRibDJzVkxheVN5Z3VudXRCZzk2WTIvSmpLUkNkeUhWK0FFRnRUdklwYktJWE9hbWtuWVNpQjZLVi8wSmV0WklUZ2Nqams1WmRhc2tCdFdPODZVRjBhcDZvekdYSmsyV05pUlVsQ1BGaXI2Nmx6ZG0vU0xTdUs3RVVkUHo4ZjF6MjlTa3E2RjFmWGc4KzVVVlI2YnN6bmNQNFRuNEtVa2tkSjhVRkNZMXpSMWk4Um1ML3FRTDNybGVpNFRIRzdPT0RsbktrbzRvSTAxa2QzQ2FNMDhJYTE4a0MzR05vVmFPOWlEaCtoV3hTeVRYRkFCWG9hdTdRNnE5T3hZZy9PVkVNdzZqZGJ0U3JKOWNCY2V3R21hWm1nK2J2a1VuVVVhR3IrWmZuTUg0NUl2ZXZsNjFoTWNYc3hZTEZUdTFoVG0yelZpQ3A3dTBvNWwrMlBTVWg5YkRqNkZnWXlwdWZCRGhxSzIrb1hraXVIRkhSM3pmais5UHRBOG9SMHhucVg4cW4rc3gzYkZPRFNiYkYwWDhFVXZXUThqQkljam81YlJtTE9sakROdGNxTnRPZTc1NmgzbDBWaEthOWhEZDJsMWVxbXNuaDBNTk1UL0Nxbng2QkludW1oTFQ4bHVsanpRNTNSaUplQS8wZHhlNU5LMG8yZkExK0dMWHI2ZU5RV0hOVU9Kc3NRYVRSbEdwTEhLTDlmRCtJclF6VE9NWlM5Zk5RRDRBblJOVnh2VGRqQytmSmRjRERXUWN5QjAwQjB0OUJEd1R4WGdhQWZ6RFovREJYelJuZldNRlJ3dU5xb2NPbVg2T0tOa1k2M2g1bi9mRmNCMjhNY1ZIcW5YWlZJMjdLMGk0ckRMTkU5bERLVi9yVCt1ZFZiRDhkRkZ1MkdHWjhtT3Qwa0FYY29YM1prSVdWdHcrTU5mNU5qUjJGYml2Uk9IbWhWMS9wajJlZ3YvZk1HSU9XVElXclYzQXY4TjlpbVY5SVdtbDM2SDZjVWpxRVdOdjlhTmMrdmViMnNINDZQUmFIU3VNQnh2dFcrdHd4Y3RxMHorUXNIaHV4OFE3ckNZNEN0OGxxc3g3YzZTeTBkbDVUODlySWVFdVpLb1ZjdElrMWhOcGZhdkVSNnl5SDFWdm0zTWJzVUh5NGFiNGhXci9PWlBjc1JCcGhuYVY2NS9aY2RZUE5Od3NqTi9kamxmOU5xQ3c5VTVFeENQY2RoS3hVZ0xTbWZST3BMcDRXU1VyOG9qZHdibmNidkNmK2EvWXpSYUVjNlFPdlhjR08yNTZUWGM1TGFiOVBPdkIrQVdZN1BpZ1dZanpoaWZib3Z1dW56UmF3c08yNFpxUVFBcWd1QnRtcG1QQjd5c1hKZnlERGFWL2FQR2lsbGd6MU1kUWc0dTVNWWFFdEJOTkhGamtSbFNwZDY1bHA0aGQyQVZQVGZiVjdGR3B5SU9mbU5jL1hWc1BmZzd2emFTLzNua3ZMTDU5M0FOTHZNdVJNR3BRSWhpRjdrVUVXOVFEcEFVYlRXWUJjYnA0V3BhY0hIWTFhYWNxUXlqR1pTOUhJM3lDQlQ5a1VaSmhWT0QrelVEdkVIOWRkUjExZnpQY1REUTVUbGdCMEt3cWRYU2F2azlCQzBwS3AwV21jdW93U3cwN1ZYbVhDNWd1elNhNHAwVXZSdzJsYkRpWVV4MEV4SkpSeld6aTZHbThjbkVrZlhYc2RjRy9NL2pBSmEwK2JtQ2dkbVE5Q1lsTmxTWVpPS2l4bVJzZ2lGeGtybVc0bDNLZEZLdjFETTh0azZXeFBZSlpoVVV6Y2Q4S2R0Z3J3L2drZlhYRFQ3K2F2bWZWYWszMnFodGtnNk5WZFVTNXdna3J1MVl6SWtTZHVUVzFGRHdWV1YzSlFWSlZ1aWVUYzB5NGlEcEZ3YzcvQnZTYWx2S2RRTThzdjY2MmNldnovKzhzUVZualZBVDBXMndMbGx3MUppTWhKUnhnRGpDakxRc096U0ZTZ1pxeDdsQVcxSlcwZTAzeUFEM2FzQytHRDNOYlFoYmUrbU41R1hIMUY4M0tET000bi9lNUpJdUg0TnBkUUFSckZQQlZwdFVOY2pqNGNWTWNGU1JURTJOcFIxTEVZYllNbWZXcFhnUDlLZWphUHNMVWh1dkxDc1ZYem5BRzlkZng5U1IxdWQvM2haZENMSGIxR01kUHFSSmdxRG1tNzZtSGJ2T1hEdGlPMlFQVWNLby9UV2tRMGkySkZYcEJvbzd2aWoxaTFMcDNBREFvK3F2RzNWMHJNLy92Rm5uVEU0aHhkNUthL0NvcjVZRWRzTFZKeUt0RGdWb0hndFcxMXBXU2pvbFBOTW5ybHJWajlGdjJRbjYwdHdNd0tQcXIrTi93dnI4ejV0WmNEc0RydjA2dGtxeXpFU004NVljdjZYQldBMmJpcmxOQ1hySTZWYkQybHgyTDB2UU8wUVZUVlZMSDRTRTY3ZmdzZlZYdjhuN3N6Ny84NVo3Y010YkU2ZjA4OHdTYVI0a0NrQ20xMHM2cEtiSmhmcWlVTkdMcSswZ0xXQzZlVUFaRlBuTGp3cXRLZDhFd0d2V1g1OXQ3aVBXNFgvZUFOMXN2Z1JWU1k5OTBZWmcwNkJEMW9oTE10eUZUSTRwS1RKc1M5eFJFcTlFT2FQV2lPMmdwbXM3Mzk3eDZuUUprYmgrRnoycS9ycVJST1g2L004YkpycWxWVzRsNkpFcHRLZVVGdU1ZVWJ0Q1E3Q0l0dHBHYzZNWTkzeDFyMXZnQW5SWHZZNWN2d1dQcWI5dVdRbStsUDk1UXhkTk1lV2hPcTF4MERiNTVDN0djVXYyWlV1TjZuOGlLenN2T3hpYkMvL1lmczlOYThyMlJsejAydlhYRFQ1N0ZQL3pKaTY2L0VKU21zSkthOFF4bm9xVzNWTFEralpWVXRKd0o4UE5YMU5RQ3dmTmdkaGhIRDlvbjdQZFJkcmRHUEYyOHJKcjFGKzNMQmRleXYrOHlZZkxvTVlldDF2WDR1cE5BalZ2d09VV25sTlhKWGxrems1SWw2a3Flb2lMMEMwN3FubysvQ1lCWHEvK3V0bG5zejcvTXp2eTB0bUk0em00YWcyM1BSTjN0L0NXcnlvVVZKR20rNStLOFJKMFY4SGM4OC9YSFVYL0hmaUFxN3QrQkgreDZ2OHQ0MzhlbldtZEp3RkE2WklOcmlMR0t2Lzk1ZjhsVDkvRm55QTFOTVZFdlF5YVh1dStnejM2Zi9ERDczRTRwd3FwTGN2bS9vMFZsZTc4bi8vK0wvTlB2b2VmcDFwVEp5ZTZlNEEvRDA4MkZFUmE1L29wZUg5enB2aDEzY05tMTkvNHYvTERlNXhNV1RpOEkwVGEwcUtsSzI3QVMvdjMvcisveC8yR085SzJjN2tWTW9uRHBxNy8vamM1UEtDeGVOUHBGVnphUnIwMXdGOEM0UHU3NmhYdVgxOEg0TGR1VHI3OWd1dUZEM241QkhmSStaUkZoWTh3MjlUWWhiYkxpL2J2QmRxS0U0ZlVnZzFwQktuVjNGRWFDV09XeUErbTNXcE9SWnIvais5VEtKdFc4eUJURjIvWkVPREk5L1FhdkhrVmRHRnAvUGpuNFErdTVoWGFwc1A1c09IK09YWEExTGlLdXFKeGlNTmJoVGtiZEpUQ3k0bGxFdDZObnFSVDRkaGcxVjNuYmRybTZkWU1lY0ExeVRPTDRQV1RFOUw1VnpQRmxMQkN2bEc1OEFoZWhuTjR1SHNBWWlueUorQVovTmtWdkVMYmZPQlV1T081c3lCSUV0aXFIVTFrOVhlSVNYNWJzaW1ya1VVaG5HRHhvdXJOOFNnVXNDWlZ0S3lHYnlHekhYZGpPaHNBdk9Bc3dTUnlJQmRkUmRFWldQNkdaaE5LL3lqd2V3OWVoQm8rM2pFQUR1N0F5Mm44bURjK1RTN2F3VUhnME9NelIwTEFCaHFMRDRoSkVoL0JFR3lCZEdsU0pvWFlYdHIrM0hTNGlqelZwZ2kwcGFXWHRkcnVHVGtuWEJ6KzExcVQxUTJpbnhhVHpRQ080NlAzbGZMcHlTNGZvdTJQSC9QdXB3WmdDeE5oR2xqNEl2VXVXRXNUa3FNV202aTR4Q1NNYzlOMVJEUW9DVmN1R0l0Si9NUldlZmFpcyszc3lub3dpL2RFU2dKamtpbG5XbkJUR3ZSV21hdzhvUjE1MjU3dDdDSG1DZjhIT243Y3dJOCtOUUJYTUJFbUFhOFBNUmVtck5DRWhMR0VoRFFLY0daV1MzMTlCWDlQRkJFd0dUYlJCaExiRGNhVjNkckZjRHFrNWtDVGQySkYxV3AwSHJhcUJ4OFUwd3dCVG5icENhZHdCQS9nVEgvQ0RyY0NzOTNMVjhFMFlsbW1jeVFSUW5qQmE4SkVTbUdVZklqSy83ZmthREpwbUQyUXB0Rk5WSlUxYmJ0SUFqaldRaXplcE9LcHRSamJ6UjlLYWc2eFptTUxMakhPdGNMVDNUeDlvLzBFY1RUMVhOM0U0NXUyNEFpd0V5cERKWGloS2pReGpMcHJFd2NtUktjbGFETlpDVnFyL1Y4bVlXeUZBRGJ1c2lZNWh2Z0ZvVTJ2aW80OVJnSkxuNU9zUmVSRk42dGFiZWV0aWl5MFY3S0ZIVDNIeVpMeDQ5MXU5NXNuNEsxUVFTUEtNOWhOVDB3TVZ2QVdiekRTVmRyS3c0elJqWk15SklIa2ZxMVZBVkNEbC9iVWhOS2xHcTB6R3IwNStZQWNlWFZQQ3R0Vmswb3FqVndNUHQrQkJlZng0eVB0R1ZrVXNxWTNDSERQaUNNNW5ndXBVd0NkYmtwZDhrYlByQ1dIaGttdElLTEVldEYyNDk5ZVMxalpsSVBHWW5sY1BYZU0yS0Q5dkxTMGJXM2t0WU5xVWxscEtMbjVacnN4bEl6eHZEdTVlSHh6R0xjdGtaTEVZNFBnU09nMklVVlZjVU9OelVEQkVwUmFNb1hObVVjMHRGWnJUWnF1aUx5S3hyU20zRHZJVzlGaWwrQWtoWHU1UGhFUHg5bVVOd3F5cER2WldkS2xoSUpRWTd2bjJPc25tQmVPV25ZWjBtMWl3YmJ3MVU2MGJ5NW9tNDdpSFJWNmZPZ3pqTWYvREFacmxQNDBaN3N5eHBMSzBsSjBncWFBSzFjMktRS3U3dGFiVFhrTEZ6MHNDZnR1d1grK015TmVObjY4azVCdXEyM1lRaFVoMFNOVEphMWlvUTBwNG5VRzJ5MFhpbEYxSnFPRHFkSW1sb1BTNEJwMTExREVXVDBqSmpWdjk1dVg5QkJWN2VCM2JVV2N1MGFjU1ZNMjNZWmRkOFI4VWJRVXhKOXdkdTNvTXVoZHQ5MjlNRSttaDZKWEo4ZGkyUnhiVGk2VGJyRHF1cVY0YVVLUjJpd1Q2YVpieU93RVhOM0RVc1dyOEhuNEVod055SHVYSGg3L3BkYVVqdFI3dm5EaC9kOGM5eEQvczVmNTAxZVExK0N1RGlDdkdoazFBTi80VGY3NFJmeFB3RDN0b0xhclIwek50c25Qem1TNjRLSVJrODYxZE1XQ1U4QXJhc0c5VDlIMFpCcHNER25qdEFPTTIrL0x1SWIyaUlVR1hOZ2w1Wm1LRC9UdzhUbGFBdWloYUZQNXlydzE4djR4MTg5OHpJZFArRERBWDFiTTNHQU12UGdSUC9jSm4zekNXMDEzbnJoSGtySVR5dll1d09Va2NIdUtsUlNXNUM2cnpJZFk0cHBuRjdKOGFBSmJRZXBnYkpZQmpDWTl1c0dYREtReHE3UlpmaDllZzVkMVVITVZBVFJhRC80QkhLOTMvMWlBZ1laLytqcVBuOERuNFVFeG1XcnBhMytaT0s2TXZNM2Jqd2Z6eE5XQTJkaHM4KzUxWEhTUEppYUFoR1NwV2V2RXM1eEhMWGNFR0ZYWWlDT055U0gzZlBXcTkzSklzQmlTV3ZXeWMzQ0FOK0VjWG9UN3JDU0FObG9QUG9hMzFydC81UFVBL2dwOFEvakREM2h5cmp6bFI4VmthbmZPdkIxWFB1YnQxN3Z6eEFmZFNWYkQxcHpBbmZneUYzeWNhZE9UT1RYaHBFVW9MQzFIWnlOR1czZHRtamVYZ3IycjU2Sk5tUndkTk5XYVFWQmRkZDZyaDRNaHZpRUI5RUZSRC83Ukd2ZVB2Q2J3QUw0TXgvRDZNNTQxaEhPNEQzZTdnNlBhZmRjWlZ3Njg5ejdOR1R3bzVvbTdBOHNQaGNjVDZxS2NsOU5KbDlhTS85a1grZTU5SGgxeVBxR3VDQ1p4dUlUY3NtTmFKNUY3ZDBxNkozSDQ4VE8xLytNNTcwODVxMmljZHUyVStXMzZMZGxsejlBZ2l2NFlHbGpvRU45MDhFenZET3JCRjk4L3Z0SndDQy9CRjJBRzc1eHhFbWptTUljanhiam9heHFPSzMvNGhQT1p6aE1QQnBZUEc0NENNMGRUVm0xTGpMdFVXV1Z6MUJjZjh0RXgwenM4TzJBMllWSFJ4S1lPaXkvYU9Wb0FhTXUwaTd1YnU0M25qam1kNGliTUhVMXNJREhhUU5LclpORC9GWllkazU0b0NYZXRqcTdFN0lWbDllQUw3dCtvSG53WFh0THg0NGN6em9SRkhCenRZVnd0SDFkK05PTWt1cFo1TVRNK2dVbXE5MFgrQmg5empSbG1hUSttN1lNcVVML3ZlZW1jZWNBdE9KMHlxMUpuVmxOMjdkaTJFMCtLbHAxdEFKNEtSdzFlTUk3YUpqc08zUjhrUFNJM2ZVRlhuSU9mZFFlODZzSUlWdFdETDdoLy9PazZ2ajh2d0RrMDhORWNJOHp6N09oQnkrV3dhbHpaZVo0KzBYbmlSZnN0OXBBSnFRSERHTHpWUTJwaGVabm52MU9XaHdPNDMvQWdjdkFFWEVWVnBhNGRiOXNHdk5LOHdqYUVOSGtmRlE0Q2k1aTdkcW5RbFBvTFFySFhaRHZPM0JJWFpiSk9Cck9hRWJNTDZzRkw3OThJNEZoS2loakhNc1BqQlVaWUNNRnI2bnZhQXJ4cVhQbjRsQ2ErY0hmU2EyY1AyN2czWjN6aVlUUnJjYlFOR0xRbUdGM0YzY0Jkenp6WDdBSUx4MElCOXJid245a3gyRzFGVzNJbmljK1pMSXNWdktSOFp3ZmowbDFma3FvOExXWTFNM0lYMTRPWDNyOVJLVElPK2Q5WHpBSThxUlBHUG4vNE5DMm42bzRyTjhYSjgyVE9JdnVWQTh6TEtVSFJGZ0JDZXRsRFpscVIxZ0xLalMzOXhvRTdCdDhVdkE2Qnh1RURqVTN0RnNFaWpnQSs2MTV0bVprWEtxaUVFTnJoNDFpTEREWk5xNHBLVFdSM0xaZm5vczgxTE91TmExNWNEOTU2dkxNc0pkMXJxWXA1MWdEVVFxTVltMlhzeG5VaEQyamcxRE03U2V1Snh4Z3JtcGZJU1NYVklKSVM1cUpKU3ZKUEVRNDlEUVRWSWJZV0o5UVdhL0UyK2Mvb1BLMWRybUM3V1NmSlJOS0JPNVlqdmNwN0djM2RtbUkvWGgxa0RURXVpU25XcVFmMzdoK2ZUTWhHbkRmNmRzUzhTUWZRV2xxcXdYWEdsYy9QRVovU0M1bXR6SVYwbkFzaGxRZE0vTHZVdFl1dHJFWi9ZK0VBRnRxMWsyOHpRaE93THIxQUllQU56aEY4dDlxelRkWmYycVJLTzZNV0U5b2hCWXdpYmJPbXJGdE5tZzNtY1MrdEIyOHh2MnVLZC9hZ1lDdk9QK0drU2MrMGxyN1JYenl1Zkw3UWJrVXBqTGpFV0ZMcU9Ja0FHdTJCMHRObE85RWF1MlcxcWNPVXZWUmdLenlwS0lRWjVLSTNxME1MenFUTlJZcWlaT3FtdHFsb0lSbG1rQkhWcEhtUllWNi9IaXhiTzZVQzQ3S09GSm5vTXJWeXI3d1l6K1NsVzZHVWFnaFliWTFJNmtreEEyVzFmU0pva1VkU2gyTFExR0FpbVJHbTBNVCt1dTU3SDVsN1FnT1d4RVJwTzltb0xSUGdUdHF1V0NmRmxHbElqUWFSbHk5b2Rtek1PV1krSUJPNXRCNHNXLzArVldHVWgzMnFZazc5RWlkV0tyald1aUxwaVZOR0ZXRlJKVmt0eWVYV21iZ0JCelZsOGFuUHVYeU5KbEJKT2xLTFRnQWJpL0VZSFZIeFdpRGFWUjA2R25IUU5wSmNXY0syakp0aUNmRzJzRUhMenVJNjZzR3JNSzQ3blBJSW5QbnU3OTk5MzVhT0syY3ZtdnVickUzOFp6WmpyRUxDbVhNMmhNN1VjcFhEMm9DMytFQ1ZwN3h0SXV4cHRKMGpVcjNzQm1CUzQ3VFZ4bHZKMVNxYi9FMHVMZHZMajBsTHIyOXlwZGQvZU1YM2Y2bHJ4R2xLd0tReEVHdncwcUhia2J3ckYzdUhLd1ZFTmJJVjJ3WjEza05FRjZ6RCt4MjRhTE5NZkRUQ2JEUG5FaWtaRnlUTnR0eFdCWERhQnVNOEt0STJybWFNZFVZN2NYY1VQc3RxVEd2QkdTckZXSXBOTWZiZGVhOTkwYnZBT0MxWVgwcWJjNnNtRFMxbVB4U0pvVzRmd0VYdmpNbWhsaWpEUnE2cWFsZTZhSkV1RkdvcHBZRG9CRUxRekxCdWgvbVpOeDdqa2ludjBFdG5VcDUwbE85aGJOSzU3bFphTUFXdVdSNVlvOS9rWXdjWUkwdDRnV000N1VtbmwzWW1wZUJQcVN5TnAzSzdzMkRTQVMvMzlLUnVFTjJiUzR4dm93VjNkRlJNeC9WRmNwMllwOHcyblRPOWhDWHRIRzFrRjFMNEtsckpyMndLZnlxNzdSN01LcEZLeldsWTlVa2hZeHlIV1c2bkJXUGF1ZHZFQWwzQ0djTnBTWFBaNlI5QmJCdElsNmNITDNnSUJpKzQyQ1lYcUN4MWdmR1dlN0FwMGgzbHV5WGR0MU1LeTRZVVQ5eFNGMDFHMTZZRWRXc291VzltZ0RIZDN2ZXlBOTdIK1lhNDdabUVicU1ZNzJvUHp0Q0d2SzBvbkw0NEF2Z0M0OXNhWktrV1J6NHZlV2xqRTFGSGpiUkphV3Y2WktLdGw4NzVoNEN6aUZDWmhHNXJ4N3RlZnNsMGFSVDFiTUhaam04ZHdMLzZ1N3dDUnlzYVFibFFvRzV5QVFONXpwYXRNTlkvK3lmOHorR0xjSC9RbjBpWDJXMm9FZlhQNEd2d1FIdUlMOUFZR25hTzN6cUFYNjk0Nm5rZ3FaTm5VaHg0M0RJZFF0TUZlT1ByZ3kveTNZZDg1SGxKV3dqTEZrVTNrRndxMjh4UG51UGhNV2VTK3RETFY5T3RsbHE3cFFDZjN1WEpETjl3RkRpVVRnZWZIYWlZYmRmaTNiM3U4K2lZNlRuemhnZWhJMUxUZThsY2Q3czF3SlN6S2JhaENSeEtLenRUTFhzdEdBaXUzYTZyUHVRczVwazlUV0FhbjVmMEJabUdmN1lseHp6ay9BN1BBczRRUFBQQUhlRlEyaGJGSHN6bGdadUtac0pjVW1iREM0MHNFVTQwM2NFamN6c3RPRXlwYStZeGV2TDRRQkM4b1JZcVdkSzZiN3NLMjV0ZkUrb0RaZ3RPUTJKZzhUNDFIR2NCRTZmVFdIbjRKdEhjdTlTN3VZZ1U1S1NDa2wvbWNucSs1L1lCWE9FcjZsQ1VDd09UT00xdGFPSThtU3h4MU5zQ1hCRW1MS2JNQWc1TWt3YkxtcEJhRk9Qck5TbE8ySG5MaUVxVzN0SEV3ZDhBZWlRTG1uKzJneGpDM2s2QXhSRXF2S2NKYlRFemxwTGl3NHJOWks2b0pkaWRiTU1HWDlGVUxLcjBBa1crMnFERVBCTk5tNVFBdDJJazJuZnROV0hldHVib3NITG8ybkc0dlFBN0drY1ZDZ1ZDZ2FEaXhIcW85VVVuMUE2T3NoYXBhTlIvTFBSWUZWOHNpVDFjQ3RKRTBrLzNXdGFOU3VVWllLUG5zVklXMHhYV25NVXhxNStFbjRLdncvTXFRbVZYbkFYajlaKzl6TTk4ek0vQWd5N0YvcXFqMk5oNjdiOEhqRm5QUDNpQm4vdGtwZHp3RUpYL3doSWNRVVhPYWlrZWxpQ1JHVWs3dGl3RjBySXR3TUVoamtaMzA5aGlrRm9SQW1MVHBFWFd1SFM2eSthbS9LQi9mTTUwYUxFaEduU013a3B4ek9vdjRIMEF2Z292d0oxaUd6REx0Sm4vOUJVK2ZBSU5md1VlNkZIU0xodTgzdmlWLysvSHJPZVBYK1NUVDJCOXVXR2JyTUhITGxkUkJsaFMvQ0pRbWNSeEpGcVppY2EwMVhpeEFac1lpSDF1b2xaeExyUi9TZ3hWSUpqa3BRUDRQRTlzRTU5TEtMcjdrbHRTQm9nUzV0eXN6ekg4RnZ3OC9BUzhyTk9nMHhVUzlmSWFId2IrNmV0OFEvZ3l2S1JqZjVPdXNPekd4OGV2QS9CUDRJUDExdU4vZ3JjYTVPMGxjc1BMSjVZandJNFFrSkJPSGEwV2RNWllHeFBiaDJXMm5SOXYzV3hFV3FncC9HMys2VlpiUkxTQUFaM0JoZGhBYVVMMzNWVVN3OXlqRXN2YmFROXU0QS9nR1h3WlhvRUhPdVUxR1NqMmNoZitNbytmOEljZmNBeGZJS1ZteXVuUmJZUVZub2V2d2dmdzNUWFhjdysreE51UDRmaHl1ZUVVTnR0RWR1UlZhRHR0ZGRvUDBlU3hMZTJMRU5rNml0WXhscnhCTkJZck5OS1NRbWVhTGNtOWM4VXNhQjVXeU82Njc1eXlRSUFXU0RwQlZvQS9neG1jd0V2d29EdjBtNThVRTdnSG4rZkpPYTgvWXdhbjhFS1JmanNvcEY4M2VDZ2xYL1NmcjdPZWFSb1FmdnQxQ0d2SURjY0g1QkN2dzFzV0l6UkdDLzY2dDBWVGNMWlFadG02UGxBYXNiT0o5aXdXdFVvN2Jpa3RUU0lQeG5SMjRqeFAxWkthcXErMlJjWE05T3JCQW0vQUFzN2hESjViTm1HYitLSWZ3Q3M4YTNqbmpCck9GZU1qSFNDZGJLcisydU9MZm5PZDllaUE4SHZ2d3dxNTRWYlAyT3F3a0I0OFl0YzRZRU9pSDJ2VFhxb2RhYmZXRU96c280cXhkYnFENUw2dGJ0TlBFQ3FiaG5BNzA4RFpINFFPSlVYcVNjbVVsa3M3T3Q2RkJ1WnczbjJtRWJhVVg3a0R6eEhPT1FrOG5LV016QXp1NlpaOHNPRnc0UksrNlBjdVhvOXRCNFNiTXo1OEFwZktEWGYzc3pqTklJYkdwRDVUS1RSeEdrRU1MakxsK0szd2xXWEJzQ1V4SURVK2piT2l5c0VTcUF5MU1HVUpwWGd3YlRXek5PVkV6aUlYWnJKK1ZJenRsMVBVQnhUU28wZHduMmJPbWZEUlBEM1RSVEdsZmJDSnZPOUt2dWhMMWhNSGhCOXdQdVBSTEdIY2RPV0cyeGMwVSs1YlF0QUpUMG5SVGV3WEwxcGdrMityWkFkZVdtejNqeEFxZk5RUWR6VGxiRjh1SjVlY0VJV3ZUa2V2QUhwd3o3dzc4UXVqbEQvTHI0OTFiRDgvMXZoTTJ5clVRUnJXWE5RWTRmR2lsZmN0TVdZakw3MlVML3FTOWVpQThFbU44OG5iTmRvdXIrUEJiYkFqT2pJYTRpQmhmRmc2cnhlS2RFR2NMNnAzRVdSMVFxMlFraHMyRHJua1JubU45dEcyRUFxbWdQdzZob0w3T3phN0IrM1NDclI5dFJmdGtvK0xzZjJGL21rVG5kTjJMbXp1TWNLVHVqL21YMis0VmEza2kxNitubkpZK1M3TWVmcGtpZHh3blYrNHdrWEg4VEtuWDB0c1l6WXAyOURPT29TVzFuZjduVGgyYWtZaVdtY0pPdVRpZFNhcUVTclRZcHdqSkpOVkdRcityTEk3V3NxZXJIVzZLcC9vTTJwS3VWN1QxUVk5Z2pxbFpwNDEvV2ZLcGw1NkZWLzBrdlhRRlJ5ZVE4M3hhVHU1RThwNWROUDNkVUYzNGloeUkzR1NwZUNzeXdTaDIyWkpkV3RvOXdpbmhxaWZiN1ZSdmdrdHhwMTN2eWpyUzBFanZyUmZaNjJ1eXFkZFNXYVdZbHdUUEF0Sloyb1ozai9TZ2kvbWkrNnZwemVzZkFjV05BMG44eFZ5dzkwR1ZGR3VaalRYRVF5KzZHZkxHTE1MTDUyM2Y1RTBPbXhWakRvT3VSaUg5MVJLVSt2dG9DdEg3VGdtdkJMdnRGWFdMVzE1SDlHVGRWdzhvdzRJbFJMZUhFQ045eW0xZTlLMEkrQ2JuaGd2NFl1K2FEMkhhUUo4MFhEcU96U0dBVjQrNHlDcUJ4cnNKQVg2WlRJb1gzNlFudnpoaHp6TWZGVzJkWlZMT0pmbzB6YmNlNU92d1hNRmFaODFtT25sVFZYcERac1FOdW9ZV3Zla2V0S2I1KzZKT09zZ1grTlRtN0g0OWZVVGx4K1dMdVdMN3F4bk9GaDRCeHBtSngwcDJnRHpBL0JVQVJ1UzZwaFIrcFVzWTdNTWJvQUh4NXhOc1NWZlZaY1lTd3FDS3Jxb243ek0rOGVjQ2tlUzRubTNySU51YVd2Vk5uTVJJMUlScHhUcXg4UFpVWjBCci9VRWR1bzNCM2hOdm1nWmZzOWdRUGo4dklPeGQya25kaXIzYXd2SjZCTHZvVXVPZkZXTllCMExSMU9RSm9VeVNLYjlJbE9CeDc0cTErQURDMkc2ck9kbUZkSmNEOEJrZnVhbEErQmRqT096UDl1VWhHVUVYL1R3aFpzVWR1d1JyOHdOdVhLdXJDaXhMQmdwUUkwbURiSnI5ZElxVXVWKzkybmdrSlo3eGR1Q2syeVpLYmZXckgxVkJpVGc5VmR6c2dSalczQ1ZYQ3ZBd0RkK2MxejlkV3c5K0IrOE1KTC9lWTE1WlEvSHF2VHdWZHNabjVXUXNnUlJuTWFXYWVjdTNqRnZNQkVtZ2crRkpGWnNuU2wwempCOU9xUFlhQkQ3cW1vVnlJbUZ2emk0MXVzZXNWMGp1bGFBUjlkZlIxNVh6djlzRXJ1UkR5azFuYitRYUxVNjdUODg1R1RsczZZZ2NZK1VpTWEyNU0vcHdHcmJDZnprdlIzZTBqanR1YUZ0bnd1YWdIVFNiNXk3Ym9CSDExOUhYaHZ3UDQ4N2pKTHNMSjRYblVrSFg1c0xiUzYxZHBpQVhSb1pTQ3JGSitFanBlVTNwdVZmaXRuZ1lObzZQSnJBaWdLa3Rtd2p5UWRacGZxMzBtbXR1bGFBeDlaZngxNVh6ditjeWV1aUJGVXM5enE4S3ErWEI5YTRQVnZwaDNHVjRFM3k4SEVOSnJONTVIMVgycDhWeXFTS3dWdXNKREt6WE9aenBsV2R6QlVGSzllK0I0K3V2NDY4eHZJL2I1eHRTQWtCSFFhUHZ0cVd6bGxWdkVPeFBidWlFNitqMnB2amNLc2J2STd0eG5SRXJnZkg3TGRYcWpxMElva0t6Z2ExNEd6UTIzU1NiQ1F2TzZyK09yN1NNSXIvZWZPa2txU2RNbmo5bUJ4MkRSc2lZMjlVajYrcUs5WnJzc0NLYXB0UjZIS1VSZHdVWWVVV0Eya1B6VktRTzhrdTJuVTNBbmhzL1hXa0J4M0YvN3dKdENUVFRJS2Z0dGh1ZTF0eTl4dk5ZTFkvem81S1NiSXVLYlhwYkVkU3llUnlZZEFJd0tZMm5leW9jMytrMVhVYXVmWWdhM1Q5ZGFNVXgvcjh6MXMxMElUa25JTzBrdW9NdCtUQjhqSzBscGF5cXFqc0oycXRYQVl3QlU5MzJ6aW5pbWdtZDZtVFJEblFmcjg4cTM2TkFJK3R2MjRFOFByOHp4dGFzQnF4MCt4SEg5SGhscndzeHhOVWZLT0hRYVpCSVROZjB1Y2NqOEdYaVZtWEF1UEVBS1NkTi80R0xIaHMvWFdqOTJkTi91ZXROdUJNblZSK1hXRGMyNUpMam81TWc1SVpJcTIyNnRtQ3NpcDJ6WmxpTDIxM1lyVGxMMmhjRmpwQ2R1eWltM003L2VCMTZxL2JsUXN2NVgvZXNEUmJ0SmVhYkxJb3NXeTN5Y2F2d0xodHhkV3piTW1IaUJUaVZqSm82bENMalhac2k3cDlQRVBuc3E2WDZ3ZDRiUDExaTByRDVmelBtLzBBNmJycklzbGxlblpzMGxDSmxVNGFiYWtSNTllblpLcktlM0JaaWhiVHhseVoyemwxK2cwd3ZnbUExNjYvYmh3RHJjbi83RGR6MGVXWnVKdmZTRVN1ZzZOelpzb3gzWjA0Rkl4ejBtVWpNd1ZPT1ZUcTFDUTBBaGRiQkdWZGpHL0Nnc2ZVWDdlc0psM0svN3l0V0hSdjY4M3ByYVcvOGlET0NxV0xMaHBsakRZMVpweks3NVFpYVpvT1RwTEtsNjBhdUhTLzk3b0JYcnYrdW1VOStGTCs1K050TEZnanFWTENkYm1qN3BZNXpQQ1BMT0hOQ3dYR09jTHF1T2hpOENtQ1d2YmN1TzczWG1NVVBhYit1ZzNBNi9BLzc4QndlMGJjUzIrdGdIbjRKNXB5UzJXYk9jazBGNTFWcTNMY2poTHZaNjdwMUFCYmFMMkg2N2JnNzhCZmpLaS9qcjMrVC9BQlYzaWxMbU5YVEkyU3B2eFdCdHQ2L1ovL0Qwei9GWGFHYlNCZ3lsemxzRUdwKzUvL3hyZDQvYWU0ZDhEVVVqbHNsZklZUzN0MDZIWnB2ZlF0dnYwTjdBSFdxdGpQMnBXMDhRRC9GTHkvL2RhMzh2bzhQTmxLSGY1eTM3RHhkZmUvb2o0a1ZJZ0ZxM2tvTFJlU1I3NlcvYngvL245azhqb25aeHpXVEFOVndFbmlEc2c4N3NPU2QvejcvL1B2TXAzalFpcHRHVldGWDJjYWV6ekFYd2ZndHpZVXZicjBpb3pzMzJjM1VnZTd2YXJIK0NORTZjdkVZbXpiUFo5aE1hWURkaks0VjJpZWNmNkVjRWJkVURWVUFSZGEyS3pPL0p0Q3VEYk5RQi9pVGVMMEVHMUpTTzFqYlhTK25MeHRQTURQdzFmaDUrRVByZ1NFS0UvOEdyeTVBNzN1aTg3QW14d2RhdHlNRUJDUE5PQ1NLVWVSWjJQNk15YjVNUnZnQ0htQTl5d3NNaWZVK0FZWGNCNlhhNUdpYlVDNVRTeWVyeHloMGo2UWdMVnBkeWhmQXJSVFRMcVFqd2U0SE9EOXM5MkQ0QXA1NG9kWEFQQldMQXdCMDJpZ0c1S2tjK3BpTjRsdk9ESUZHQVpnVCtFTzRTaTFzN2ZqU1I3dmNRRVRVa1JtOU8rTVh5bzlPWWhmZTR4dDlTVFEycGNaUkxheUNWOTBiNEQzalIwRFlBZnl4SitleXdnMklMN05UTVhuYTdTL1JwUTYzSmhXRU04VTQxWnlRR2p3c1ZTMFFCckVLTHU4eHdac2JpNHdMY0NUK09HaWRQSU9DZTFQaVNjOVF0K2dvK3ZZcUI3Y0crQjlkOGNBRCtXSlB6MEFtMmd4WGdVOUluZU9xRHBBQVhPc09sdFZ1TXpwZGFrSlhyZFBDelhpTlZVcENlT29zNWN4bnBRVDM5RytYVkxoczFvc1FWdkpLUFp5TnE4SER3ZDRkN3BORHVXSlB4Vlg3TVN6cVVEVTZnZmFkS2lObFVGVHpMZUZISERsek80a3BhN2FpS2hCUEdLd09xeHNCQW1Za09JcGlweVhjUVNQbFJUZitUaWkwVTNFSkdhWnNERVIycW9CM2gyaHUwcWUrTk53VW9vWVU4eTVtSUxiSmU2T3VYKzJGVEt5N2JpZVREQWVtYVF5UTBDUHRobGpTV08reG1GRElZaUVTak01eEtkNklrNWx2THE1R3JRM2FDTUx2bUNBOXdvd0x1V0piOXhGNTloVlZQNk8wQ3JCaTNaalpTTk92UnkrSTZrbE5WUkpZUkJhRXpkTitpbWlVWFE4aVZGOGZzcCtXNEpYdzdXSVNXN2ZEaDdscHRXa0N3WjRkN1FUWHlCUGZKTVlLN1NpampGcHBHbmxJVkpCSkJZajdlVXd0aVAxSUJYR0kxWENzak5wYmpFTlZwU0FKMmhxMkxUeXdFbHkzaFVZYXp0MzFKOHcyK2FpTHgzZzNmb2hYaXhQZk9NWW02ekNHczlMVm85TW9XM01DSkU3UjV1L1dzT0lqcnFCb0hVTzBiSkU5dnhCcGJoc2QzK05iNC92dFBDWjRvWllDaXROZVl1Qy84VUR2RHZ5MHF2a2lXL2NncU5xUnl6cVNaYS9zMG1xTkdqdEtPb1RtMTR6WnBVYXVpUWdWZnF0UWlaanE3UTI3Sk5hU0s1RXhSY3JHQ1hPMUZKWWg2alI2Q0ZxSzdiWmRRWjR0OGcwclNsUGZQMVJkQnRxYWE5ZGlxdHpKa1E5ZHVTcnlpMmJyUVhieER3YlJVcEZNQkhqUmo4K050N0dES2d2cGg5b2tXN0xYNDdndTBTcEdubkZRMVMxbFlsZE9zQzdoWXRlUjU3NFp1S3M3RWkxbEJzZmR6N0lab3h6ekNWbW1WcWFTeVN6UWJCVkFXRGVrK040amg5RS80VnFackpqUHdpdjlCQzFYY3ZPV2dPODI3NUNWeUJQdkF0VFZsREpmWmthWkdVN05wcUJvZ0FqL3hFSGtlQXVKaWhXWUN4R042ZTgrOUp0U2VnRlhGMVRyaGhMR1AxZmFrM3BlYmdQejE5Mi84Z0I0ZC82V1Q3K0dkWW5wSDdoSC9ESnp6RmlZUG4vdmpXMFNnTnBUTnVQSVpvQUVadjh0bEd3NCtSTHh5K1pqbkthNU5kRm9DN1VhVzBhZHVvWXNlNitiWGcxRExnNlVmUll3bWhHRWpxUHZGNzVVNTU4U0FOckVsSy8rTWRwWHZtcUJwYVhPYS9NVFphYTFET2NTaUxhdzlqME5OTnN0M2MrNjNjN0VLVHBrdktIenU2YlBiUDBSa3VIQVZjYlJZOGlqUDQ2TUliUWVlVDFtaEErNVBWL2lueURkUWlwZjhMVHZNWGJ3dm9EeTdJcnVETlZaS1RmVjRDVFNSVVlkeWJVQ25HVTdLVVREeExnQ2tucVVtNWFBVzYvMXA2ZU1zT1lzcGhMenNIckUwWS9QNWJRZWR4MUYvNHlQSG5NQjMvSU9vVFU5K0JMOFBodGp1RktCcFpYbllOSnhUdXYrMlhxb2xLUjJVUWdIaFM1bm92dXhWeVNKaEJOUkYzU29LSzFYWmJiWGpWd1dOeU9qbHFXSmpyV0pJeStQNWJRZWR5bGROU2NQK0haNjF4S1NLM2p5cnorTmlIRzFoY09MTC8rUCtQREYyZ09rZWtLR2lOV0tnSis4Wi94OEl2NERkUUh6Y3BaeUY0djE5STI3dzkveVBHREZRdm1FcEt0cXYvVExpV01mbjRzb2ZNbTllQUg4QW8wenpoN2g0c0pxWXR4WmQ1L0Q3aGtZUG5lRHpsNWlkbHpOSGNJQjBqVmxRKzhVTHp3L25jNS9vanpsMmp1RTBhcEQ3TFJuSnhlMDRkTXoyaU9DRk50R0ZwVHVYQTVBaGNUUm84bWRONGt6MzBuVmpFQzRZVFpReTRncEM3R2xUbHJlUEtoR3NLS2dlWHBDWWVPME1BZC9HSDd5S1FVbFhQTE9hc09IM0ZuU3Boakh1RHZFdTRnQjhnNjZvTmJ0cjZlTWJGSUE0ZklCSmtnYXlvWHJpdzJYRURRUEpyUWVST0FsWTZhZVlPY01mK0lWWVRVM1hGbFp1Zk1IaW5HeXdhVzNZTHBPYlZCQXNiakY0UUpNc1ZVU2F5ams0dm9Qc0hKT1FmUFdEaENnRG5tRGw2WElSZXJEMjRIc0d0dzg2Uk1IT0x2VlNIcktCZGVWRTI2Z0tCNU5LSHphSXdMT21ycUJXSllaRExoQVNHMTZjMFRuK0NkUmhXRGdXWG5xUlpVVG5QSUh1TUpUZkxWcGtvWXk1Q3p5bEhWVEdaTVR3a0dBbzJIQmxrUXBsckpYNlUrdUYxd1p6MnV3UzFTUTEySXFXYVB1TzRiYVphRUZCZHVra3NKbWtjVE9tK1lKU3ZvcVBGenhGQS9ZVWhJdld4Y21TZFBXVFd3YkFLVnA2cnhUdFBGVVpmS0l3cHptNElvTWZhWVFMV2dtbEc1Rk1FMmdkQmdtK0o3SitydFMvWEJiYVZMc1I3YnBQUW5wTUZsbzJkb1dhVmNlSGs5K01reWd1Wk5DSjFIZStrdUhUV3lRQXpOTTVZU1VnL0dsVGs5WnVuQXNnMXFFTFZPaFVTQUswTEFCSUpITEticWFFYkhaTEwxVkEzVmdxb2lPS1hZaVMrSFJ5YUVLZ3NmSXFYNjRIWVdiTFJYeS9xV295bElWOWd1ZEwxT1dCTmdCZ1RObXhBNmI0dHhEVDRnaTNSaTd4RlNMeHRYcG1tWW56QWNXRFpnWThkNTAzTEZvZ3o1c2JvbkRna0tjeEdzV3NFMU9JK3JjUXRsZ0JCQ1NPS0QxbXRxWXBJVThjVHZCbUFUMHlaZSt6VXplWTkyZllqVHRHaXBYTGh1UjBlUG9IazBvZk5XQlgrbG84WjdwQVpEazhtRXc1TDdkVnlaWm9FL3BUZXdiSTZTTmJpQUw1eGV5Z1c0eFBSdUxDR2JoY080UkllVE1GWUhFSmtZeUVPOUhtSmZYTURFai9MYUg3ODF3SEhaRXRxU1EvNjlVbkdwekg3TEtJQVpFRFNQSm5UZXNKVFVhK3J3VGVwSTlkTEpFYXdZVitaa1JuOWcrUWlyRDh2RjhNcTBqRlEyOWpzNmtDUzNFMStqWkloZ1BOYW5IZEhGcUZ2UEpMSHFGd1FxYklBNGpoRHhjTnNPQ0NRTERvbWFML2RyNWx5SmFKVTZGeFBGak8zSk9oM2tWTWNST284dStDK2pvMDVHak1GM1AzL0Z1RExuNXgyTTA0eFhVTFB3YVM2aEJZa2krTXJNZFpKU2dQSGxjQjduQ1I1Yko5S3I1QUNVbjlqazVraXZkZDh0azk1U09HcnRxdTlscjJJaEs2NVp0RWw3WktycDdEcnF3WmZSVVNOMWVsNys3Tkp4WmJ5d09DOG5lTktUY2g1dnNURU1Oc29DQ3FIQkNxSVBSaklQa20wQmp2Rk9ER3R0bzk5ckNsK2Qzd21Ia1cwRlBkcFp0QzdNTWNWdEdGUWpKTFg1YmRRMit4OXlwZGMzMTN1ajh4bHNyZnVMZ1dYejFjUmhadkpZWDBpTlZCUmNWY21DWFpzNmFFZjNSUUYyV0kvVGNDYkttR1UzSU9vREpHRGREdWIwK2hZY2t0NlBsR3UyQmN4bWhiVGRqL2tsaGNjTEdKTWNxUmpNSlAxalcyRVRxTFNXSi8yOU1Bb09SbHVKKzZMUGZmQlpiaTVncWk1aDZjYXRRcG1PVDcvT0ZmNVVvclJwTHpDcWNNbHRCTGh3ZDFhcmUza3p0clN6WE8wTFViWFJRY2RMaC9SZFNaK3N3Um04MTlSRURydHF6QzRlczZHdzRKQ0tsU25qWVZwbzB4ZXEzM1ByQURiRkxMM1J1Q21PYlZtUE4rMjRrZmErQW9qRHVNNHVtS2UyUXdDZjZFTjkwNkh3anVqYWl0RHM1bzBzMXkrazNsZ2JUMlcyaTdGSmRud2JMWGhKVUJxLzlsaVRjdFNtRkMvME9xVWluYjBRZGRUV2FtdGpiSFJGdVdKSjZOcHFaOHZPM2ZaSjM3RGIrMkdrYVBZTEdIczdYVFRkaUZRSjY4U2tWSkZWbVk2TWNSNVV5Y2ZsTkNzY2NIRmFWOUZOYlI0TnR0THh3NHBRN3dKZDA2Nlowb2hWYnppaGF4SFZFeGQvYXkwNG94VUtXdCtBc2RpUTlPVXlaMmtyek4xOUlaSXdhZlNURmdJQm5NVjczQURqN1YvSzh1MU1hWTJzSnAySFdtMGY0MXRxd2FqRXZkSFdPSnM1MTBNYUFxTjRhb1NpUENYdE4yS1NpNDZkVXhIZGFNcXVhcjgyTzF4NWpxaERHdnFtb0U5TGZ4Y1kzenFBNy94M0hBNjdyOVpHNE82Q3V4dTEyLytUUCtlTFArSStIRXJxRERDRFZtQkRPNGxhcnVqTmU3eDhvbTJyTXVnME1YMHJMMStJV3dkd2ZSK3AxVE5UeU5tVko4NWxqV3piV3VHdjgvQzdIRC9pemprSE5aTllsaFpjVU9LVnpLRlV4c3h4Ti9rYXgrOHpQV1BTRkt3ODBySnI5VGl6eWozbzFnRXNkd2dXR294UGV6RGRaMVRTRU5FMWRMZE52dUtMK0k4NG54S2VzWmd4WFZBMVZBMU9jTDQ5ZEZscEZWNXlKTWh6eUNtTlErYTRCcXVzUEoyYkIreG84Vjl1M3g0OFZWSUVQUy9tYzNEdkFiWHlvWXI2VmdEZmg1ZG81aGhIT0NYTXFCWlVQaFdZYldaRUN3VkpsakxnTVVXT0NCNE1VdU1heEdOVVFEVkk1MFRRK1Mza0ZnSWN1MnFLa05TSFZvTTBTSHNnb1p4UDJkNUhIOEI5d29PazR4NWJQa0t0QUh1Y1pzZHlranh1SXBiVXJTSUxnclQ4RzdHNW9DVytLMDk5MG83RTNUNkFkVzRUaWxINWtEamRzK0g2NGtTMG16MjRncnR3bHpESEJKcUk4WUpRRXhvdFB2b0M0SkJxMGxFampRa3lCWjhvSDJMblJzUTRIdTFRc2dEVEpiTzhmUURubGxpdGt4dVZza29pS2JSRjlWd3pNRHZ4SEFkd0I3bUQ5eUNwbGhIRkV5VVdIeDNXdHdDYlNNTVRDVUNjRW1TR2xnNGdUWGtIcFpYV1E3a3B6bkszRW1DSGlYSW5xbmRrUWp1bkc1a3hUS0VlR3llN2pXejljeU1SMm1HaUZRMTVFTlJCVGJDcCtHaDg2dkF5QVNkZ21KcTJNQzZob0FEUTNHb3NQMFFIYm5NSGp5QlF2UXFmaHkvQlViZUhkNVdZL0cvOUxLLzhLYThKZDdVRmVOV0VadnpQYjQ1OERuOERHTE9lMy93R0wvNHhQK0hYbFJ0K00xUEUyaUxoUjh0K2xmZ3hzdWg3QWZPMkFPZitvd1doU1pSWVFiZDYyMmhicEtXS3VVK1h1dk56UDBPc2VSRGErbU9iZ0RISlVTYy9wS3gzMVFkS2ZmUTVPSUpwdDhHV2psZ1R3TWMvdzVNUENSL3lsMVhDMmEyWXV0NTRTdk90TWV2NTVPZjQ1Qk9hdDlhV0cyN3AyWlZPUlJ2bkVrMWhxV01WVW1xYTdTMll0dmxJcHNwdUYxcHQwc3l1WlMyTlYxNG1VaWRDU2Z6UXpnK0txdklZQ01sakl4MllLMkFPMzRmWDRHV2R1NXhjSUFiOE16VHcrai9seVdNK0R3L2dqczRHRDZlaE5nQTQ4a1gvQUk3WFhNL1hBTjRXSHIrOW50eXdxb0Nha0NxbUtQMHJtUXJKSkVFckcyVXBnMUpPYnIwMWxLUXk0anNrV2FsS1lmSi9FRExNcGpOU0hGRVVBZGUyZmx0YURnbXJOYVdROStBQWI4STV2S2p6M0wxbjFMcmlCL0JYa0cvd3dSOXkvb1JYNExsaW9IQTRMelAyaW56UngvRFdtdXRSd2VGamVQM3ROZVNHbGFFMUZkZTBPUzExeU9wbWJJcDJ1L2pGMW4yUlJadmlKTTB5QlQzSVpsMkhXSW1LalFPeEl5ZVUzMjViL3FXeVU5TW9qMW8wN3RTMEc3cUpEb0dIZzVtOHllQ3hNb0VIOEdVNDV0bnJOTTg0RDJsMjk3RFE5dDFZUDdqa2kvN1JtdXRSd2VFQTc3L0hXWE9oM0hDeGtSZ2xkRFFrQWpOVE1sMklsb2MxcU41SmZKZWVUbHlUUnp4VVJUZG4xSXh2MnVLanMxMkFiZEVXbEJ0bVZkazJrN0ZGd2owN1BDWjlYQXdXM2RHKzh4S3pORnI0RW53QlpweTlRemhoM2pEWGViQnBZY3B1bzRmUTQ0dStmRDFkd2VFbkh6STd2MHh1dU9BTFJVVjhyWHBGeWZTVFFZa2hkN0lIbTA3anB5aGxrQ21JMEFMWXFQVHBVeFhTK3o0amdEajFQZmx2bXo1ZWN1SXRwSUJ4eVRIcFNUR1dkOWcxQXBmRC9idndVaEw0blQxRXpxZ1g3Y3hmQ2NObWIzbVBML3FpOVN3VEhKNDlvajVaTGpjY2JURzNwUm1sWWk2SkNHMG1RckF0MStpMlVYVFoyZHY5SWxRcE41bmFNWXR2aWFYbFRyRnBvTXNsM2JPQUZFYThzcVBqMldDTXJ4M1lqeDk5cUZ3TzU5QXcvd2d4K0hscU56OG9adkEzZXhSRHZ1aEwxak1RSFBhT0owK1h5QTNmcDFPZk0zcU9iRVZkaHhqdnlueE5NWFFWNCtHSnl2T0VGcWVRQmFJYmJPN2k2M3JweENsdGRaU2hQRnhrak0yRlBWa24zVEcrUnA5cE8zbDJSekZlZ0dmeEdESElBaDhTdGVSMEM0SG9wWHpSRjYxbmhlRHc2VEZOMDVFYnZxOE0zVktLcEdqak82cjduaHVkVEVHTXRZTTkySFREYVIxRkRNWEoxZVRoc2JLZnl3eW9Xd3J6UlNYa2M1MWZsRzN2SWlkNjJoMjliSWNGYlRHaGZWK2ZhYUIrb2hqN2RQTjBDMmUybEM5NitYb3VGQnllbjlBc3VuTERKWjl6N05FeGlVYzBPdW9ZVzZVWmtJeXgyWVVSMno2L1RpUmp5S014NUdiYmpMSHZIdWY3WW10S2doZjM0TEpmeDYzWWc4dnJ2TjJ6QzdsWTB4MHR2S2V6bzRIbUdZRFUrR2FiNmRGTCtLSTc2MWxEY05pZmNqTHJycjlMV1pKY3RHMUZmVTF1d2hvUUUyMk9iamRma1N6WTYzQ2JVNWh6czIxV2VUZGRIMkJhTDExR2k3bFZkbHhQMW5reHFobktoVlk2a25TM0VQZ1ZHZzFKcE41Y1AvaGl2dWpPZWxoWGNQajhIQy9MeUk2TWt0ZVZqbG9sQmRNbUYzYTNEYnN1QVloTDQ0ZHh6dGhXU04wNjV4eFVkNTVMbWYwd1JiT1lPcUgwOS9vOVdiTzJWdEZkYU1iNHFCZ3RGSm9UMVNxb044d1BYTW9YTGIzcDFQVUVoeGZubkx6R3pCSTBLdTdGeHJLc05Kai84Ym4vSDhmUElWT2QzcmZya2xVQi9ET2VPK25rZ2hnU1B6cmxQeGx1Q010T25ETDRZbWw2ZEsxcjN2c2dNeGd0UE9yTUZVWmJFVWJUZEl6aWk1YmVxNzJHNFBEMERLbndqbUJVTFVWRm15OHQrazdmWjNwS2MwUTRVQzZqcFZScVM5VW12OGJ4dzM1ZmxaVk9VMVg3cWtqbmhabHNNYmsyNHFRNkh6N1FjdUw2c0RDMGlISGtpOTZVaDJVZHZtZ1puakl2RXh5MlRlSmRNRFpOU2JkWnlBSGUvWWQxeHNRaEhpS3pqaDdHeFE0eXFNUGF5d1Brak1hbXZxcllwbU83S25hZCtaUUM1bXNDdUFQV1VveHJ4VmhyR3Y3YStLTFhGaHlPTmRUTXJaN2tlMjNxaU80MFpKVXl6Z1l5WDVYeUwwbVY3TmlVekVzOW1qdGJNTjBkRVJxd3lBSnBpZ2FkMEIzL3pSVjdzNFBJZlhTdTZZVi9NSzcrT3JZZS9KdmZHTW4vUEhKZTJmeVVkdG5GcktSTnBYVjBZMjU1OWFXUHQvRzRCbHZqVE10WGxWSVdDbk55QTNZUUJEbVlJb2RGejQxUHZYUFNhNnJxOWxXWmF3WjRkUDExNUhYVi9NL3RuRmtrckJPZHpnNmFQNHBJRCtNWm5USjFTdXVCNmlabHlpb3g0SFQyeTNZQnRrVUtXb29hY0JRVURUcGp3YUR0NXBvQkhsMS9IWGx0d1A4ODdsS0tYeE5VRXlQcXBHVHlBNjk5VXFZL2x0OXlHZGxVS3JhMGZGV1MrMzZpeWxWV3JBeWQ3VXcwQ1pNMHo3eEtUT2R1em5MSWpHMkh4OGNEUExiK092SzZCdjduMURZY2k0Q3hVdVJ4cmpCYzBiYjR2RDNyTjVaejM2bnRMYjgzZVZKSUI4TGlJekNtbjZTTVBqbFgreU5sVGp2SUdqcytRekhQZjYwQWo2Mi9qcnpHOGo5dllNRnRtMVZvUldDSmRtdzd6OU4wdCtjOGN4WnBQZUs0YVRSaWNTMjVRaHJWdFVwN1U1NzhjaGs0cTA0V3g0WW9RU2pGcnlVbHBjUTFBYnhaL1hWTWtuSVUvL09HbDdRNno5WnB4aTArM3lGaFNralVEcG5DSVVoTFdWWDIzS1ErTDl2S3ZGS0kwWldGUWdrREx2Qm95bHJITlZtYXcxMHp3Q1BycjV0bG9kZm5mOTRFV25RMGxGUld5OHBXOUxia0xzeVVWRGMyTlNUSEdEdG5EMXVNdGNoamJDZWIxbXB4RlAwWWJjQ2xoemRMdTZsZk84Qmo2cStiZFQyc3ovKzhTWkNWN1ZJeHR0MERVbjlMN3I0Y0xZV0RTWG5zZUVwT0dGdXR5MHFiT1ZsUzdOTnpzNUZPR0pVcVFwbDJRNjQveUJwWmY5MHN4YkUrLy9QR2RaMDJIU2lwQ2JtRDZOSXRtUTRMazVYVXJHcERNa2hiTW0yWlZoZU5ZVitWYlVXVGN2OTkrMk55WDFWb2FmU3VDK0FONnE5YkZJTXY1WC9lYWdOV1haeEVhOUpqbE13TldiMDBha0dVa1NvZXBwMS95UnV1cUhHYlVuM1VkQlNUeEJVNlNFVmtseldSVWtQbmRWdncyUHJycGp2eE92elBtd0hjMGhwbXE4Mm5waTdHUnJvOGRYcDBLWG5VUW1oWmJSTDdORVZwMXV1Wm1PNDV2dXpLc0hya3RTM0dMV1hPRFZqdyt2WFhMWXg0SGY3bmpSUGQwaTNhb0FHWDZXMjlHbmFWNVlkeURqOVRGa2FramU3R0hZekRvT2JmZGRIdE9TcG9pMlNtekpIckIzaE0vWFVEREVieFAyL29vc3N6Y1JsZWhXWFV2ekh2NFRwQlZrdEhxd2VuRm84dUxWbXk0REtMYTVkM1J0THJtck0zYU1GcjExODNFNHNld2YrODVWV2VnMWM1YWcyNzZOWnJNOUlKVk5jbUxFdkROYVY2MmFxKzE0SUFPR0ZzQnQ5NzNSYThYdjExWXpYd05mbWZ0N0pnMm9TK1hPeW9DOC9jd3ppNjZEaG1nazM4a1VtUDFDVWlZV09YMWJwRDJ6V1h0MkZDcDd1cTg3MDNBUEFhOWRmTmRzY1IvTS9iWkxJeW91VnhxSmZlV3ZHOUplK0pWY2tIUTkrQ0k5Tld4eitibFgvS1lZdk81bjJ0QVAvdnJsWjcrOC9oOXkrOXFlQi9IbnQ5NjdlNW1ldlgxMHJBTERXSy8vRmFBVDVNWGRCWGRQMEMvQkFlczc5MmM0MEgrQWlBcDFlMW9IOEhnSDk0Zy9MdHR4MWdwNjNvcDFleW9NL0J2dzUvRy83eEZicUpQY0NYbm1CaXdEUGIvWUtPNEZYNE9qeUNiMjg5ZGIyL05vcWljdzRpN042VFZ0b3o4dE53REgrOHgvaTZBZTdsbWFRVkVOekpGYjNEaS9CRmVBd3orSXM5U2plUXlTcFBxYkxGbE5teXo0N3o1YS9BRitBWUZ2RG1IcWliU1hURXpvVDRHYzNPQUxhcUFQNEtQRlVKNm4rMXgrckdBTTZaZDc4YmdKMGE4UU40R1U2MTR2eHdEOWUxQW15NkNjc2tOcmN6THgxSklwNkhFNVVaRC9EQkhyRnIyb05sZ0c0T2R2MjI2Qm9kb3J5akdKOXEyVC9BUjN2UXJzT0NTMGN0WFppM3J1TGxocEZESllsNEhtWXRqUUNQOXJoZG40c3V5U0xLRHQ2d0xjQzUyaDh4UGxjamp1MWZuK3lodXc0TFpzQUdVdW8yYjRGeDJVd1F1Nzd1cVJIWEd0ZzkyYU4zdFFDYkZleGMwdWs5M3ZoVFhiY3Q2eTdNdWxMeWNvVWxqeDhuZ0RNQmcxdHZKakFhenBFbU90eGx6Y2x2ajF2UWYxVHg3UWxQRHBHcHFndGRTS3ovZDkvaGR5MXZUZkZIU21DOWRHRFpiTGlleno3QWM4MDFIaXJHWnNXanlkZlp5UHZIWEwvWThNanpnOEJ4VFppdXdLejRFYjhzQkU5enpuc3ptanZGd0hLUElXVW53aHFmVlJjZDRDazBLNmF0ZTQ4bTFvT2ZyWDMveU90dkFzSjh6c1BBTTg5c2puZGRtdUx1RFBqWDlCdS9MN3g3eHBNekZrNm5XdHlRZlBnMjc4R240QWVrejJaZ09tVTllSjM3UjE0dndFL0JMOEczYWliQ2lXTVdXRFEwWnRrUE1ubGNHZUF1L0FnKzhaeWVjVTVCUHV5MklMRCtzUXF5WmhBS21uN1haZCtqSU1UTjllQkw3eDk1eFZMU1g0T244RWNObFhEcW1CbHFTMTNqRzRMcG1HYmtGLzBDbk9pM0g4RVRPSVh6bW5tdGIwYTE2VHp4ajFzVXZRQ0JpWFpHRHRtQjNLQWVmUEg5NHhjVWEvNnZ3Um44MEdPRnlqRVhGcGJhNEExZThLUWZGRisyNTl0eDVYUzRlZ1luOGZRc0xHcnFHckhienRyK3VCeVRhaFd1TDFOVUdiRHBzbnJ3QmZlUFB3SEhJZjlYNFJuTTRaMkFCV2R4VUJscVEyUHdodUR4b1MwdnZxQjFKelMwUDRoMm5BL1FnVHJzSkZuK1kzQU9qczlKRkMwN0NHV1gxb05YM1QveUhPemdEandQbjFQTTNnOUprOWxack1FcHhubFBtQmJqeW8yK0tGWFJVNTJUSk0vMkFMY1k1N1JVempPYmJqcXhWdysrNFA2UkFPZjU4cGNWc3c5RGFqZTNodHJpWXJwRE9vbnJlM0N1ZFNlNmJma1RFZ0hCSHVEaXl1NU1Dc2M3QkhoWUR4N2VQeExqcWlnWFpzdytpak1IRmh1d0JtdG9UUHRPeE9yVHZZSkRuQzc1ZG5VYmhmd3UvWlc5QWdZZCtwZUw2OEhEKzBlbUtxdWlYSGhXakpnL1Vya0pZenVpYUwzRTlhSS95dHJDdkFkNEdjWVpNQ2tTUXhmVWczdjNqOGM0ZTkwajVaVFBkdm1KSkdIbk9DSTJuSFM4MDgxWDAxM3BIdUJsVjFnQjJNWDFZTm1XTEhxcUdOL1RXbUcweTZjbEpXdGh4TlVsNDhxMzhCaTh2dE1LeXp6cEZkU0RoeFo1V0JBNVpMdDhKdjM4OTVEZHVCbGdiUFlBajhDNEI4aE82OEZEa29oNWx5ZEM0RmlXdkJPVnFqWWRxamlMdjkydDh5UERqckRhaUhkVUQxNXFrU1VSU0dtWEp3T01TeFdBWFl3cjN6YUF1Zko2NmwrOTR2djNBTyt2UGNEN2F3L3cvdG9EdkwvMkFPK3ZQY0Q3YXcvd0h1RDl0UWQ0ZiswQjNsOTdnUGZYSHVEOXRRZDRmKzBCM2w5N2dHOEx3UDhHL0FMOE8vQTVPQ3EwWXMyS0lkdi9xT0lYRy80bXZGQU1GMTZnWkQrMlh2dS9COGFzNSs4YmZsbFd5ZzB6YU5PNWJmWGo2dmZoaHdEODYvQXEzTmZSUzl0OVdQbmhmbnZDSXcvQ1Q4R0xjRlRNbnBudGRGL3o5VitQV2MvdldvSUgrRkwzWm52NTdQaXRjZEdQNFIvQzM0YXZ3NWZnUlZVSW5Dd2JzbjF5eUE4Qzh6bS9CSDhOWG9YblZFNndWUGpkZUNJMzhrWC8zK0N0OWRiejFwVG1IRlJ1K0htNE85Q2gzY2xyOTluZWd4ZndqK0VSL0RSOEVWNkI1K0R1UU9uVGdVdzVybmtZK0ZiTlUzZ05YaDBvL0pZVHVXT3Z5QmY5RnZ6WDY2M0hIL0hlak84THdBbDhIbDVZTFRkOHE3c3FBM3dianVFeGZBRmVnUWR3ZnlEb1NrV1k4c3d6RWY2bzRReWV3ZWZnK2NITmJxTVFydVNML3UvV1djK0U1Zzd2bm5FWGdEbWNEZVNHYi9GNGNCY0NnVCtHR1J6RFUzaFpZYnVyQXQ5VEV0SGdiTTZKb3hKKzZOTXp6VGNmNmMyYnljdjIrS0svZitsNkxCenc1SXdmcVpKaEEzTTQ3MnBXVC9hakt4bmp2NEFGbk1FcG5CVFBORDZzMko3cUhiUEFxY01LNzRUMm1aNFZHQjl1SkE0NjVJdCsvZUwxV0toWU9EN3hIT2tyMWFqSzdkMEM0K2tlNEh5OXFYWndwZ0xyK1pubS91TkZ3OHhRT1N5OEg5SXpqVXJkOStCSWZlbllheWxmOUZzWHI4ZkJBYWRuUElFRG5hOElCY3dseG51QTAvV3Y2R0FXUGQ3ZERJS2pNZFNXdWVBc0JqNE03VE9kMDZxQmJ3RHdLcjdvbGV1eE1PRWNUdUVaVEhXdkRZVU83YUhxQWUwQmJxK0hFRlJ6T3o3V1ZvVERRa1ZkczdBNHNJSXhmQ1FkQ2VmRlJvSU9GL05GTDFtUGFiL252T2FrU0wvUTFhRnROcFViL25GT1ZYNmd6eWcvMW5JU3lEZlVoc29rSXphQlI5S3htODBzNW1LKzZQNTZpbDFqWGljN25oUXhzeFNtM093QkhsNGZGZExxaTY0bkRRWnZxRTJhdDdjV0FwL0lWdnJONi9CRkwxbVBoWXJHTUJmT2k0UHlqdVNHZjZ3QkJoN3AvRlpUZ2hDTldHZ016bEJick5Kb1BKWDJtVzVtd1pmeVJmZlhvN09GaTVwWmNTNHFaVXJsVmlwdHJYdHcrR1FveWhEUFMrQU5qY0dCTlJpTENRRFBaUE1IdWlaZmRGcFBTVGNRd3dLWWRSTnFwa2ptN0FGZWVUMHBKekFMZ283ZzhZWUdyTUhTMGlvY3krWVRtMnZ5UlV2dnBYQ0lwUTVwZTY2NlRKcmN5Z25TY1VmL3AwTkRzL2lBSS9ucURIQzhUbVFUOHgzTkY5MWw3Nm9EZFFHd3U2MVo2RTBBQnY3dU8xZGJmLzM3Wmx2K1p3L1BiaDhmMXM0QXZ1cjY2NTcvK1lZQnZ1cjY2NTcvK1lZQnZ1cjY2NTcvK1lZQnZ1cjY2NTcvK2FZQnZ1TDY2NTcvK1ZNQThGWFdYL2Y4enpjTjhCWFhYL2Y4enpjTk1GZGJmOTN6UDM4S0xQaUs2Njk3L3VlYnR1QXJyci91K1o5dkdtQ3VzUDY2NTMvKzFGandWZFpmOS96UE43b0hYMzM5ZGMvL2ZOTXUraXJycjN2KzUwK0JpK1pxNjY5Ny91ZWJBL2p6OFB1ZGY5aHQvZld2NTE3Si9YVXpBUDhDL0JBZVg5V0NEclVwWjMvZEVNQnhnUGNmYnRUVnZzWVY1WW4zMnUwM0IzQWM0UDNiOEkrdnhOQktlZUw5ZFJNQWx3TzgzOTU5cUdPNzhzVDc2OW9CN2czdy92R1ZZRnpLRSsrdjZ3VjRPTUQ3Rjd0Y2tGa21UN3kvcmhIZ3BRTzhiKzRZNDZYeXhQdnJ1Z0JlTmNCN0JSaVg4c1Q3NjdvQXZtQ0E5d29BSHNvVDc2K3JCSmpMQm5oM3R4T3ZraWZlWDFkc3daY084RzZON3NYeXhQdnI2aTM0MGdIZTNUbnFWZkxFKyt1S0FiNTBnSGNYTG5yWDhzUjdnTmRQUnF3endMdTdZL0ZPNVluM0FLOWpYQ01HZUhkZ3hEdVZKNzVWQUk4bGpQN1BBYjMvUmZqY1pmZVBIQkIrNzlkcGZwSDFDYW5OMzBkK21UMWg5R3FBeHhKR001TFFlZVExK1RiK0VRSnJFbExiMzhWSFE5NFRScTkwMGFNSW84Y1NPbys4RHA4UWZzQjh6cHFFMU5PM09JOVpyajFoOUVWNzhQcUUwV01KblVkZVU2RStKanlrL2hickVGSWZlV2J2SWQ4SDlvVFJGd2RaYXhKR3Z6aVcwSG4wZ3FZQi93eVowUHdSbHhKU1QrQk93OW03N0FtajE0aWkxeUdNL3R4WVF1ZE4wcUR6R2U0RXFmQS81R0pDYWdzSGNQYUVQV0gwZXNla1N3bWpSeE02YjVKRWNaNHd3NTBpbHZBT0Z4QlN4NHlMVytBL1lVOFl2Zlk1K0FMQzZOR0V6aHRteVpvRlpvYXJ3QkxlWnhVaHRZNHJjM2JLbmpCNlRLSmpGVUh6Sm9UT296RjJZQnBzamN5eERnemhRMVlSVXNlOCtKNHdlbndtYXlsQjgyaEM1dzB6b1JYVU5YYVJCbVNNUVVxaVdTV2tMc2FWcWMvWkUwYVBURlV1SldnZVRlaThTZkxaUWVNeE5hWlNJemJJSTRhRTFObXIxM1AyaE5IamM5RTlndVlOQ1owMzJZbE53RVNNTGNaaUxRSGtFNGFFMUJGZzB5QVI0ejFoOUFpQUdSQTBqeVowM3R5SXhXTWFqTVBXQklzeFlKQ25sSVRVNVNoaUhZZFo5NFRSNHdDbVN4ZzlqdEI1S3lQR1l6eW1BWWV4V0VNd0FQSXNBZFlkVjZhT2JtTlBHRDBhWUxvRXphTUpuVGMwWWdzK1lEdzBHQXRxeEJqa3VQMzhiTVJXQ0huNzN4Tkdqejc1UDczV2VuQ0VKbmh3eVZlM0FFZThUdEtkSmNZaEJsOTd3dWhOQU9iSzY2bHZELzlKOU5TNzV2MTd3dWl0QU41ZmU0RDMxeDdnL2JVSGVIL3RBZDVmZTREM0FPK3ZQY0Q3YXcvdy90b0R2TC8yQU8rdlBjRDdhdy93L3RvRHZBZDRmLzI0QUJ6WjhvK0tMc1NMUytQdi9UcVRiM1A0aEtsUXJUR2grZmJJQlQwQXhxem5uYitML1YybWIzSGtONU1iL25FSGVLN2Q0SWNEbGQ2bG1EVy9pSDlFK0FIMU1kT3cvSmx1MlQxeE5tWTk4c3Y0d0huRDdEM3VOSHU1NFdVdU9zQlRiUXV2QnNQVC9VZnpOeEdZendrUDhjK1l6M0Mrci9pNkRjeVJML3JaK3V0UndXSDVQbWZ2Y3ZZRXQ5akxEUy9iZzAvQjY0RFdLclFNOEFMOEZQd1M5YmVRQ2U2RU1LTlpZSm9sMzdqQk15MzVvdGRhejBCdzJIL0MyU21jNytXR0IwSFdERUxCbU9CeUEzcjVRT05vNFYrRHB6Ui9oRlM0VTh3TVcxUFhOQjRUT3FZejl1cnhSVisrbnRXQ3cvVTU5VHk5ZWJkV2JyZ2ZSUzlBWUtLTjYzWm9rWlZ5Z3I4R1ovZ2ZJaFpYSVhQc0FsTmpQT0xCYnk1YzFlT0x2bVE5bHdrT3k1eDZRVjFqNVRZcXBTMDVKdFVnVUhVcDV0b0hHc1ZmbjROWDRSbk1DZStBeFRwd21BcFRZeHFNeHdmQ2VKR2pwWHpSRjYxbmJjSGhVQlBxV3plOXN2d2NISitTNk5Qc2NLckVqdWc3OER4OExqM1Q4RDRZeEdJZHhtSmN3aGkzNGZ6WlVyN29sZXZaQ3c1dmtPaG9DbHE1ekJQWkFueWdEL1RsOUV6RGg2a2wzVmhzSFljREViK2hDdEpTdnVpVjY5a0xEbStXeWNyT1RBckhtQjUvVll5UDZqT1Zqd2dHYXdrMnpRT2FUY2MxTCthTFhyS2V2ZUR3WnFsS3J3OFU5WTFwNjZ1SzhkRXpkWXdCZVVRQVk3RGJ5WU5lekJmZFdROTd3ZUV0QUtZUWcyeEpJa3V2ZUFUM2RZZUxHSCtTaHJXTndaZ04wYjJZTDdxem5yM2c4SllBbzViUUJ6aVBqeDdCUFowZDlSQ1FwNFVaYm5GZHpCZGRvcjRYSE40S1lNckIycUhGUkl6emNMQUhRWjV0aGU1b3Z1aTk0UENXQVBlZmFZbnhJZHpSd2RIQ2J1UjRCK3RiaXk5Nkx6aThFNEQ3ejdTMG1FUGQrZXFPM2NUNTNaMFk4U1Y4MFh2QjRaMEFESmkvZjdYMTEzZis3cDcvK1VZQnZ1cjY2NTcvK1lZQnZ1cjY2NTcvK2FZQnZ1TDY2NTcvK2FZQnZ1TDY2NTcvK2FZQnZ1TDY2NTcvK2FZQnZ1TDY2NTcvK1ZNQThGWFdYL2Y4ejU4T2dLK3kvcnJuZjc1UmdMbmErdXVlLy9sVEEvQ1YxVi8zL004MzdhS3Z2djY2NTMrK1VRdm1hdXV2ZS83blR3ZkFWMU4vM2ZNL2Z6cjI0Q3V1dis3NW56OEZGbnhsOWRjOS8vTU9yLzgvZ2xpeHdSdVVmTTRBQUFBQVNVVk9SSzVDWUlJPSc7XG5cblx0fVxuXG5cdGdldFNlYXJjaFRleHR1cmUoKSB7XG5cblx0XHRyZXR1cm4gJ2RhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBRUlBQUFBaENBQUFBQUJJWHlMQUFBQUFPRWxFUVZSSXgyTmdHQVdqWUJTTWdsRXdFSUNSRVlSZ0ZCWkJxRENTTEEyTUdQVUlWUUVURTlpTlVBcUxSNWdJZW9RS1Jnd1hqd0FBR240QXRhRmVZTEVBQUFBQVNVVk9SSzVDWUlJPSc7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLmVkZ2VzUlQuZGlzcG9zZSgpO1xuXHRcdHRoaXMud2VpZ2h0c1JULmRpc3Bvc2UoKTtcblxuXHRcdHRoaXMuYXJlYVRleHR1cmUuZGlzcG9zZSgpO1xuXHRcdHRoaXMuc2VhcmNoVGV4dHVyZS5kaXNwb3NlKCk7XG5cblx0XHR0aGlzLm1hdGVyaWFsRWRnZXMuZGlzcG9zZSgpO1xuXHRcdHRoaXMubWF0ZXJpYWxXZWlnaHRzLmRpc3Bvc2UoKTtcblx0XHR0aGlzLm1hdGVyaWFsQmxlbmQuZGlzcG9zZSgpO1xuXG5cdFx0dGhpcy5mc1F1YWQuZGlzcG9zZSgpO1xuXG5cdH1cblxufVxuXG5leHBvcnQgeyBTTUFBUGFzcyB9O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///737\n")},45:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ p: () => (/* binding */ ShaderPass)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(753);\n/* harmony import */ var _Pass_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(844);\n\n\n\nclass ShaderPass extends _Pass_js__WEBPACK_IMPORTED_MODULE_0__/* .Pass */ .o {\n\n\tconstructor( shader, textureID ) {\n\n\t\tsuper();\n\n\t\tthis.textureID = ( textureID !== undefined ) ? textureID : 'tDiffuse';\n\n\t\tif ( shader instanceof three__WEBPACK_IMPORTED_MODULE_1__/* .ShaderMaterial */ .BKk ) {\n\n\t\t\tthis.uniforms = shader.uniforms;\n\n\t\t\tthis.material = shader;\n\n\t\t} else if ( shader ) {\n\n\t\t\tthis.uniforms = three__WEBPACK_IMPORTED_MODULE_1__/* .UniformsUtils */ .LlO.clone( shader.uniforms );\n\n\t\t\tthis.material = new three__WEBPACK_IMPORTED_MODULE_1__/* .ShaderMaterial */ .BKk( {\n\n\t\t\t\tname: ( shader.name !== undefined ) ? shader.name : 'unspecified',\n\t\t\t\tdefines: Object.assign( {}, shader.defines ),\n\t\t\t\tuniforms: this.uniforms,\n\t\t\t\tvertexShader: shader.vertexShader,\n\t\t\t\tfragmentShader: shader.fragmentShader\n\n\t\t\t} );\n\n\t\t}\n\n\t\tthis.fsQuad = new _Pass_js__WEBPACK_IMPORTED_MODULE_0__/* .FullScreenQuad */ .F( this.material );\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {\n\n\t\tif ( this.uniforms[ this.textureID ] ) {\n\n\t\t\tthis.uniforms[ this.textureID ].value = readBuffer.texture;\n\n\t\t}\n\n\t\tthis.fsQuad.material = this.material;\n\n\t\tif ( this.renderToScreen ) {\n\n\t\t\trenderer.setRenderTarget( null );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t} else {\n\n\t\t\trenderer.setRenderTarget( writeBuffer );\n\t\t\t// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600\n\t\t\tif ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t}\n\n\t}\n\n\tdispose() {\n\n\t\tthis.material.dispose();\n\n\t\tthis.fsQuad.dispose();\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNDUuanMiLCJtYXBwaW5ncyI6Ijs7Ozs7QUFHZTtBQUNrQzs7QUFFakQseUJBQXlCLG1EQUFJOztBQUU3Qjs7QUFFQTs7QUFFQTs7QUFFQSx5QkFBeUIsNERBQWM7O0FBRXZDOztBQUVBOztBQUVBLElBQUk7O0FBRUosbUJBQW1CLDJEQUFhOztBQUVoQyx1QkFBdUIsNERBQWM7O0FBRXJDO0FBQ0EsOEJBQThCO0FBQzlCO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLG9CQUFvQiw2REFBYzs7QUFFbEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVzQiIsInNvdXJjZXMiOlsid2VicGFjazovL3RocmVlanMtcG9zdHByb2Nlc3MvLi9ub2RlX21vZHVsZXMvdGhyZWUvZXhhbXBsZXMvanNtL3Bvc3Rwcm9jZXNzaW5nL1NoYWRlclBhc3MuanM/ODM0MyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuXHRTaGFkZXJNYXRlcmlhbCxcblx0VW5pZm9ybXNVdGlsc1xufSBmcm9tICd0aHJlZSc7XG5pbXBvcnQgeyBQYXNzLCBGdWxsU2NyZWVuUXVhZCB9IGZyb20gJy4vUGFzcy5qcyc7XG5cbmNsYXNzIFNoYWRlclBhc3MgZXh0ZW5kcyBQYXNzIHtcblxuXHRjb25zdHJ1Y3Rvciggc2hhZGVyLCB0ZXh0dXJlSUQgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50ZXh0dXJlSUQgPSAoIHRleHR1cmVJRCAhPT0gdW5kZWZpbmVkICkgPyB0ZXh0dXJlSUQgOiAndERpZmZ1c2UnO1xuXG5cdFx0aWYgKCBzaGFkZXIgaW5zdGFuY2VvZiBTaGFkZXJNYXRlcmlhbCApIHtcblxuXHRcdFx0dGhpcy51bmlmb3JtcyA9IHNoYWRlci51bmlmb3JtcztcblxuXHRcdFx0dGhpcy5tYXRlcmlhbCA9IHNoYWRlcjtcblxuXHRcdH0gZWxzZSBpZiAoIHNoYWRlciApIHtcblxuXHRcdFx0dGhpcy51bmlmb3JtcyA9IFVuaWZvcm1zVXRpbHMuY2xvbmUoIHNoYWRlci51bmlmb3JtcyApO1xuXG5cdFx0XHR0aGlzLm1hdGVyaWFsID0gbmV3IFNoYWRlck1hdGVyaWFsKCB7XG5cblx0XHRcdFx0bmFtZTogKCBzaGFkZXIubmFtZSAhPT0gdW5kZWZpbmVkICkgPyBzaGFkZXIubmFtZSA6ICd1bnNwZWNpZmllZCcsXG5cdFx0XHRcdGRlZmluZXM6IE9iamVjdC5hc3NpZ24oIHt9LCBzaGFkZXIuZGVmaW5lcyApLFxuXHRcdFx0XHR1bmlmb3JtczogdGhpcy51bmlmb3Jtcyxcblx0XHRcdFx0dmVydGV4U2hhZGVyOiBzaGFkZXIudmVydGV4U2hhZGVyLFxuXHRcdFx0XHRmcmFnbWVudFNoYWRlcjogc2hhZGVyLmZyYWdtZW50U2hhZGVyXG5cblx0XHRcdH0gKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuZnNRdWFkID0gbmV3IEZ1bGxTY3JlZW5RdWFkKCB0aGlzLm1hdGVyaWFsICk7XG5cblx0fVxuXG5cdHJlbmRlciggcmVuZGVyZXIsIHdyaXRlQnVmZmVyLCByZWFkQnVmZmVyIC8qLCBkZWx0YVRpbWUsIG1hc2tBY3RpdmUgKi8gKSB7XG5cblx0XHRpZiAoIHRoaXMudW5pZm9ybXNbIHRoaXMudGV4dHVyZUlEIF0gKSB7XG5cblx0XHRcdHRoaXMudW5pZm9ybXNbIHRoaXMudGV4dHVyZUlEIF0udmFsdWUgPSByZWFkQnVmZmVyLnRleHR1cmU7XG5cblx0XHR9XG5cblx0XHR0aGlzLmZzUXVhZC5tYXRlcmlhbCA9IHRoaXMubWF0ZXJpYWw7XG5cblx0XHRpZiAoIHRoaXMucmVuZGVyVG9TY3JlZW4gKSB7XG5cblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggbnVsbCApO1xuXHRcdFx0dGhpcy5mc1F1YWQucmVuZGVyKCByZW5kZXJlciApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCB3cml0ZUJ1ZmZlciApO1xuXHRcdFx0Ly8gVE9ETzogQXZvaWQgdXNpbmcgYXV0b0NsZWFyIHByb3BlcnRpZXMsIHNlZSBodHRwczovL2dpdGh1Yi5jb20vbXJkb29iL3RocmVlLmpzL3B1bGwvMTU1NzEjaXNzdWVjb21tZW50LTQ2NTY2OTYwMFxuXHRcdFx0aWYgKCB0aGlzLmNsZWFyICkgcmVuZGVyZXIuY2xlYXIoIHJlbmRlcmVyLmF1dG9DbGVhckNvbG9yLCByZW5kZXJlci5hdXRvQ2xlYXJEZXB0aCwgcmVuZGVyZXIuYXV0b0NsZWFyU3RlbmNpbCApO1xuXHRcdFx0dGhpcy5mc1F1YWQucmVuZGVyKCByZW5kZXJlciApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0XHR0aGlzLmZzUXVhZC5kaXNwb3NlKCk7XG5cblx0fVxuXG59XG5cbmV4cG9ydCB7IFNoYWRlclBhc3MgfTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///45\n")},208:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n C: () => (/* binding */ UnrealBloomPass)\n});\n\n// EXTERNAL MODULE: ./node_modules/three/build/three.module.js\nvar three_module = __webpack_require__(753);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/postprocessing/Pass.js\nvar Pass = __webpack_require__(844);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/shaders/CopyShader.js\nvar CopyShader = __webpack_require__(364);\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/shaders/LuminosityHighPassShader.js\n\n\n/**\n * Luminosity\n * http://en.wikipedia.org/wiki/Luminosity\n */\n\nconst LuminosityHighPassShader = {\n\n\tname: 'LuminosityHighPassShader',\n\n\tshaderID: 'luminosityHighPass',\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'luminosityThreshold': { value: 1.0 },\n\t\t'smoothWidth': { value: 1.0 },\n\t\t'defaultColor': { value: new three_module/* Color */.Q1f( 0x000000 ) },\n\t\t'defaultOpacity': { value: 0.0 }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\n\t\tuniform sampler2D tDiffuse;\n\t\tuniform vec3 defaultColor;\n\t\tuniform float defaultOpacity;\n\t\tuniform float luminosityThreshold;\n\t\tuniform float smoothWidth;\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvec4 texel = texture2D( tDiffuse, vUv );\n\n\t\t\tvec3 luma = vec3( 0.299, 0.587, 0.114 );\n\n\t\t\tfloat v = dot( texel.xyz, luma );\n\n\t\t\tvec4 outputColor = vec4( defaultColor.rgb, defaultOpacity );\n\n\t\t\tfloat alpha = smoothstep( luminosityThreshold, luminosityThreshold + smoothWidth, v );\n\n\t\t\tgl_FragColor = mix( outputColor, texel, alpha );\n\n\t\t}`\n\n};\n\n\n\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/postprocessing/UnrealBloomPass.js\n\n\n\n\n\n/**\n * UnrealBloomPass is inspired by the bloom pass of Unreal Engine. It creates a\n * mip map chain of bloom textures and blurs them with different radii. Because\n * of the weighted combination of mips, and because larger blurs are done on\n * higher mips, this effect provides good quality and performance.\n *\n * Reference:\n * - https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/\n */\nclass UnrealBloomPass extends Pass/* Pass */.o {\n\n\tconstructor( resolution, strength, radius, threshold ) {\n\n\t\tsuper();\n\n\t\tthis.strength = ( strength !== undefined ) ? strength : 1;\n\t\tthis.radius = radius;\n\t\tthis.threshold = threshold;\n\t\tthis.resolution = ( resolution !== undefined ) ? new three_module/* Vector2 */.I9Y( resolution.x, resolution.y ) : new three_module/* Vector2 */.I9Y( 256, 256 );\n\n\t\t// create color only once here, reuse it later inside the render function\n\t\tthis.clearColor = new three_module/* Color */.Q1f( 0, 0, 0 );\n\n\t\t// render targets\n\t\tthis.renderTargetsHorizontal = [];\n\t\tthis.renderTargetsVertical = [];\n\t\tthis.nMips = 5;\n\t\tlet resx = Math.round( this.resolution.x / 2 );\n\t\tlet resy = Math.round( this.resolution.y / 2 );\n\n\t\tthis.renderTargetBright = new three_module/* WebGLRenderTarget */.nWS( resx, resy, { type: three_module/* HalfFloatType */.ix0 } );\n\t\tthis.renderTargetBright.texture.name = 'UnrealBloomPass.bright';\n\t\tthis.renderTargetBright.texture.generateMipmaps = false;\n\n\t\tfor ( let i = 0; i < this.nMips; i ++ ) {\n\n\t\t\tconst renderTargetHorizonal = new three_module/* WebGLRenderTarget */.nWS( resx, resy, { type: three_module/* HalfFloatType */.ix0 } );\n\n\t\t\trenderTargetHorizonal.texture.name = 'UnrealBloomPass.h' + i;\n\t\t\trenderTargetHorizonal.texture.generateMipmaps = false;\n\n\t\t\tthis.renderTargetsHorizontal.push( renderTargetHorizonal );\n\n\t\t\tconst renderTargetVertical = new three_module/* WebGLRenderTarget */.nWS( resx, resy, { type: three_module/* HalfFloatType */.ix0 } );\n\n\t\t\trenderTargetVertical.texture.name = 'UnrealBloomPass.v' + i;\n\t\t\trenderTargetVertical.texture.generateMipmaps = false;\n\n\t\t\tthis.renderTargetsVertical.push( renderTargetVertical );\n\n\t\t\tresx = Math.round( resx / 2 );\n\n\t\t\tresy = Math.round( resy / 2 );\n\n\t\t}\n\n\t\t// luminosity high pass material\n\n\t\tconst highPassShader = LuminosityHighPassShader;\n\t\tthis.highPassUniforms = three_module/* UniformsUtils */.LlO.clone( highPassShader.uniforms );\n\n\t\tthis.highPassUniforms[ 'luminosityThreshold' ].value = threshold;\n\t\tthis.highPassUniforms[ 'smoothWidth' ].value = 0.01;\n\n\t\tthis.materialHighPassFilter = new three_module/* ShaderMaterial */.BKk( {\n\t\t\tuniforms: this.highPassUniforms,\n\t\t\tvertexShader: highPassShader.vertexShader,\n\t\t\tfragmentShader: highPassShader.fragmentShader\n\t\t} );\n\n\t\t// gaussian blur materials\n\n\t\tthis.separableBlurMaterials = [];\n\t\tconst kernelSizeArray = [ 3, 5, 7, 9, 11 ];\n\t\tresx = Math.round( this.resolution.x / 2 );\n\t\tresy = Math.round( this.resolution.y / 2 );\n\n\t\tfor ( let i = 0; i < this.nMips; i ++ ) {\n\n\t\t\tthis.separableBlurMaterials.push( this.getSeperableBlurMaterial( kernelSizeArray[ i ] ) );\n\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'invSize' ].value = new three_module/* Vector2 */.I9Y( 1 / resx, 1 / resy );\n\n\t\t\tresx = Math.round( resx / 2 );\n\n\t\t\tresy = Math.round( resy / 2 );\n\n\t\t}\n\n\t\t// composite material\n\n\t\tthis.compositeMaterial = this.getCompositeMaterial( this.nMips );\n\t\tthis.compositeMaterial.uniforms[ 'blurTexture1' ].value = this.renderTargetsVertical[ 0 ].texture;\n\t\tthis.compositeMaterial.uniforms[ 'blurTexture2' ].value = this.renderTargetsVertical[ 1 ].texture;\n\t\tthis.compositeMaterial.uniforms[ 'blurTexture3' ].value = this.renderTargetsVertical[ 2 ].texture;\n\t\tthis.compositeMaterial.uniforms[ 'blurTexture4' ].value = this.renderTargetsVertical[ 3 ].texture;\n\t\tthis.compositeMaterial.uniforms[ 'blurTexture5' ].value = this.renderTargetsVertical[ 4 ].texture;\n\t\tthis.compositeMaterial.uniforms[ 'bloomStrength' ].value = strength;\n\t\tthis.compositeMaterial.uniforms[ 'bloomRadius' ].value = 0.1;\n\n\t\tconst bloomFactors = [ 1.0, 0.8, 0.6, 0.4, 0.2 ];\n\t\tthis.compositeMaterial.uniforms[ 'bloomFactors' ].value = bloomFactors;\n\t\tthis.bloomTintColors = [ new three_module/* Vector3 */.Pq0( 1, 1, 1 ), new three_module/* Vector3 */.Pq0( 1, 1, 1 ), new three_module/* Vector3 */.Pq0( 1, 1, 1 ), new three_module/* Vector3 */.Pq0( 1, 1, 1 ), new three_module/* Vector3 */.Pq0( 1, 1, 1 ) ];\n\t\tthis.compositeMaterial.uniforms[ 'bloomTintColors' ].value = this.bloomTintColors;\n\n\t\t// blend material\n\n\t\tconst copyShader = CopyShader/* CopyShader */.Z;\n\n\t\tthis.copyUniforms = three_module/* UniformsUtils */.LlO.clone( copyShader.uniforms );\n\n\t\tthis.blendMaterial = new three_module/* ShaderMaterial */.BKk( {\n\t\t\tuniforms: this.copyUniforms,\n\t\t\tvertexShader: copyShader.vertexShader,\n\t\t\tfragmentShader: copyShader.fragmentShader,\n\t\t\tblending: three_module/* AdditiveBlending */.EZo,\n\t\t\tdepthTest: false,\n\t\t\tdepthWrite: false,\n\t\t\ttransparent: true\n\t\t} );\n\n\t\tthis.enabled = true;\n\t\tthis.needsSwap = false;\n\n\t\tthis._oldClearColor = new three_module/* Color */.Q1f();\n\t\tthis.oldClearAlpha = 1;\n\n\t\tthis.basic = new three_module/* MeshBasicMaterial */.V9B();\n\n\t\tthis.fsQuad = new Pass/* FullScreenQuad */.F( null );\n\n\t}\n\n\tdispose() {\n\n\t\tfor ( let i = 0; i < this.renderTargetsHorizontal.length; i ++ ) {\n\n\t\t\tthis.renderTargetsHorizontal[ i ].dispose();\n\n\t\t}\n\n\t\tfor ( let i = 0; i < this.renderTargetsVertical.length; i ++ ) {\n\n\t\t\tthis.renderTargetsVertical[ i ].dispose();\n\n\t\t}\n\n\t\tthis.renderTargetBright.dispose();\n\n\t\t//\n\n\t\tfor ( let i = 0; i < this.separableBlurMaterials.length; i ++ ) {\n\n\t\t\tthis.separableBlurMaterials[ i ].dispose();\n\n\t\t}\n\n\t\tthis.compositeMaterial.dispose();\n\t\tthis.blendMaterial.dispose();\n\t\tthis.basic.dispose();\n\n\t\t//\n\n\t\tthis.fsQuad.dispose();\n\n\t}\n\n\tsetSize( width, height ) {\n\n\t\tlet resx = Math.round( width / 2 );\n\t\tlet resy = Math.round( height / 2 );\n\n\t\tthis.renderTargetBright.setSize( resx, resy );\n\n\t\tfor ( let i = 0; i < this.nMips; i ++ ) {\n\n\t\t\tthis.renderTargetsHorizontal[ i ].setSize( resx, resy );\n\t\t\tthis.renderTargetsVertical[ i ].setSize( resx, resy );\n\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'invSize' ].value = new three_module/* Vector2 */.I9Y( 1 / resx, 1 / resy );\n\n\t\t\tresx = Math.round( resx / 2 );\n\t\t\tresy = Math.round( resy / 2 );\n\n\t\t}\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {\n\n\t\trenderer.getClearColor( this._oldClearColor );\n\t\tthis.oldClearAlpha = renderer.getClearAlpha();\n\t\tconst oldAutoClear = renderer.autoClear;\n\t\trenderer.autoClear = false;\n\n\t\trenderer.setClearColor( this.clearColor, 0 );\n\n\t\tif ( maskActive ) renderer.state.buffers.stencil.setTest( false );\n\n\t\t// Render input to screen\n\n\t\tif ( this.renderToScreen ) {\n\n\t\t\tthis.fsQuad.material = this.basic;\n\t\t\tthis.basic.map = readBuffer.texture;\n\n\t\t\trenderer.setRenderTarget( null );\n\t\t\trenderer.clear();\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t}\n\n\t\t// 1. Extract Bright Areas\n\n\t\tthis.highPassUniforms[ 'tDiffuse' ].value = readBuffer.texture;\n\t\tthis.highPassUniforms[ 'luminosityThreshold' ].value = this.threshold;\n\t\tthis.fsQuad.material = this.materialHighPassFilter;\n\n\t\trenderer.setRenderTarget( this.renderTargetBright );\n\t\trenderer.clear();\n\t\tthis.fsQuad.render( renderer );\n\n\t\t// 2. Blur All the mips progressively\n\n\t\tlet inputRenderTarget = this.renderTargetBright;\n\n\t\tfor ( let i = 0; i < this.nMips; i ++ ) {\n\n\t\t\tthis.fsQuad.material = this.separableBlurMaterials[ i ];\n\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'colorTexture' ].value = inputRenderTarget.texture;\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'direction' ].value = UnrealBloomPass.BlurDirectionX;\n\t\t\trenderer.setRenderTarget( this.renderTargetsHorizontal[ i ] );\n\t\t\trenderer.clear();\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'colorTexture' ].value = this.renderTargetsHorizontal[ i ].texture;\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'direction' ].value = UnrealBloomPass.BlurDirectionY;\n\t\t\trenderer.setRenderTarget( this.renderTargetsVertical[ i ] );\n\t\t\trenderer.clear();\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t\tinputRenderTarget = this.renderTargetsVertical[ i ];\n\n\t\t}\n\n\t\t// Composite All the mips\n\n\t\tthis.fsQuad.material = this.compositeMaterial;\n\t\tthis.compositeMaterial.uniforms[ 'bloomStrength' ].value = this.strength;\n\t\tthis.compositeMaterial.uniforms[ 'bloomRadius' ].value = this.radius;\n\t\tthis.compositeMaterial.uniforms[ 'bloomTintColors' ].value = this.bloomTintColors;\n\n\t\trenderer.setRenderTarget( this.renderTargetsHorizontal[ 0 ] );\n\t\trenderer.clear();\n\t\tthis.fsQuad.render( renderer );\n\n\t\t// Blend it additively over the input texture\n\n\t\tthis.fsQuad.material = this.blendMaterial;\n\t\tthis.copyUniforms[ 'tDiffuse' ].value = this.renderTargetsHorizontal[ 0 ].texture;\n\n\t\tif ( maskActive ) renderer.state.buffers.stencil.setTest( true );\n\n\t\tif ( this.renderToScreen ) {\n\n\t\t\trenderer.setRenderTarget( null );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t} else {\n\n\t\t\trenderer.setRenderTarget( readBuffer );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t}\n\n\t\t// Restore renderer settings\n\n\t\trenderer.setClearColor( this._oldClearColor, this.oldClearAlpha );\n\t\trenderer.autoClear = oldAutoClear;\n\n\t}\n\n\tgetSeperableBlurMaterial( kernelRadius ) {\n\n\t\tconst coefficients = [];\n\n\t\tfor ( let i = 0; i < kernelRadius; i ++ ) {\n\n\t\t\tcoefficients.push( 0.39894 * Math.exp( - 0.5 * i * i / ( kernelRadius * kernelRadius ) ) / kernelRadius );\n\n\t\t}\n\n\t\treturn new three_module/* ShaderMaterial */.BKk( {\n\n\t\t\tdefines: {\n\t\t\t\t'KERNEL_RADIUS': kernelRadius\n\t\t\t},\n\n\t\t\tuniforms: {\n\t\t\t\t'colorTexture': { value: null },\n\t\t\t\t'invSize': { value: new three_module/* Vector2 */.I9Y( 0.5, 0.5 ) }, // inverse texture size\n\t\t\t\t'direction': { value: new three_module/* Vector2 */.I9Y( 0.5, 0.5 ) },\n\t\t\t\t'gaussianCoefficients': { value: coefficients } // precomputed Gaussian coefficients\n\t\t\t},\n\n\t\t\tvertexShader:\n\t\t\t\t`varying vec2 vUv;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvUv = uv;\n\t\t\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\t\t\t\t}`,\n\n\t\t\tfragmentShader:\n\t\t\t\t`#include \n\t\t\t\tvarying vec2 vUv;\n\t\t\t\tuniform sampler2D colorTexture;\n\t\t\t\tuniform vec2 invSize;\n\t\t\t\tuniform vec2 direction;\n\t\t\t\tuniform float gaussianCoefficients[KERNEL_RADIUS];\n\n\t\t\t\tvoid main() {\n\t\t\t\t\tfloat weightSum = gaussianCoefficients[0];\n\t\t\t\t\tvec3 diffuseSum = texture2D( colorTexture, vUv ).rgb * weightSum;\n\t\t\t\t\tfor( int i = 1; i < KERNEL_RADIUS; i ++ ) {\n\t\t\t\t\t\tfloat x = float(i);\n\t\t\t\t\t\tfloat w = gaussianCoefficients[i];\n\t\t\t\t\t\tvec2 uvOffset = direction * invSize * x;\n\t\t\t\t\t\tvec3 sample1 = texture2D( colorTexture, vUv + uvOffset ).rgb;\n\t\t\t\t\t\tvec3 sample2 = texture2D( colorTexture, vUv - uvOffset ).rgb;\n\t\t\t\t\t\tdiffuseSum += (sample1 + sample2) * w;\n\t\t\t\t\t\tweightSum += 2.0 * w;\n\t\t\t\t\t}\n\t\t\t\t\tgl_FragColor = vec4(diffuseSum/weightSum, 1.0);\n\t\t\t\t}`\n\t\t} );\n\n\t}\n\n\tgetCompositeMaterial( nMips ) {\n\n\t\treturn new three_module/* ShaderMaterial */.BKk( {\n\n\t\t\tdefines: {\n\t\t\t\t'NUM_MIPS': nMips\n\t\t\t},\n\n\t\t\tuniforms: {\n\t\t\t\t'blurTexture1': { value: null },\n\t\t\t\t'blurTexture2': { value: null },\n\t\t\t\t'blurTexture3': { value: null },\n\t\t\t\t'blurTexture4': { value: null },\n\t\t\t\t'blurTexture5': { value: null },\n\t\t\t\t'bloomStrength': { value: 1.0 },\n\t\t\t\t'bloomFactors': { value: null },\n\t\t\t\t'bloomTintColors': { value: null },\n\t\t\t\t'bloomRadius': { value: 0.0 }\n\t\t\t},\n\n\t\t\tvertexShader:\n\t\t\t\t`varying vec2 vUv;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvUv = uv;\n\t\t\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\t\t\t\t}`,\n\n\t\t\tfragmentShader:\n\t\t\t\t`varying vec2 vUv;\n\t\t\t\tuniform sampler2D blurTexture1;\n\t\t\t\tuniform sampler2D blurTexture2;\n\t\t\t\tuniform sampler2D blurTexture3;\n\t\t\t\tuniform sampler2D blurTexture4;\n\t\t\t\tuniform sampler2D blurTexture5;\n\t\t\t\tuniform float bloomStrength;\n\t\t\t\tuniform float bloomRadius;\n\t\t\t\tuniform float bloomFactors[NUM_MIPS];\n\t\t\t\tuniform vec3 bloomTintColors[NUM_MIPS];\n\n\t\t\t\tfloat lerpBloomFactor(const in float factor) {\n\t\t\t\t\tfloat mirrorFactor = 1.2 - factor;\n\t\t\t\t\treturn mix(factor, mirrorFactor, bloomRadius);\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\t\t\t\t\tgl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) +\n\t\t\t\t\t\tlerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) +\n\t\t\t\t\t\tlerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) +\n\t\t\t\t\t\tlerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) +\n\t\t\t\t\t\tlerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) );\n\t\t\t\t}`\n\t\t} );\n\n\t}\n\n}\n\nUnrealBloomPass.BlurDirectionX = new three_module/* Vector2 */.I9Y( 1.0, 0.0 );\nUnrealBloomPass.BlurDirectionY = new three_module/* Vector2 */.I9Y( 0.0, 1.0 );\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMjA4LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7QUFFZTs7QUFFZjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxnQkFBZ0IsYUFBYTtBQUM3QiwyQkFBMkIsWUFBWTtBQUN2QyxtQkFBbUIsWUFBWTtBQUMvQixvQkFBb0IsV0FBVywyQkFBSyxjQUFjO0FBQ2xELHNCQUFzQjs7QUFFdEIsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFb0M7OztBQ3ZEckI7QUFDa0M7QUFDSztBQUM0Qjs7QUFFbEY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOEJBQThCLGdCQUFJOztBQUVsQzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSx1REFBdUQsNkJBQU8scUNBQXFDLDZCQUFPOztBQUUxRztBQUNBLHdCQUF3QiwyQkFBSzs7QUFFN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdDQUFnQyx1Q0FBaUIsZ0JBQWdCLE1BQU0sbUNBQWEsR0FBRztBQUN2RjtBQUNBOztBQUVBLG1CQUFtQixnQkFBZ0I7O0FBRW5DLHFDQUFxQyx1Q0FBaUIsZ0JBQWdCLE1BQU0sbUNBQWEsR0FBRzs7QUFFNUY7QUFDQTs7QUFFQTs7QUFFQSxvQ0FBb0MsdUNBQWlCLGdCQUFnQixNQUFNLG1DQUFhLEdBQUc7O0FBRTNGO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseUJBQXlCLHdCQUF3QjtBQUNqRCwwQkFBMEIsbUNBQWE7O0FBRXZDO0FBQ0E7O0FBRUEsb0NBQW9DLG9DQUFjO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsbUJBQW1CLGdCQUFnQjs7QUFFbkM7O0FBRUEsc0VBQXNFLDZCQUFPOztBQUU3RTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSwrQkFBK0IsNkJBQU8saUJBQWlCLDZCQUFPLGlCQUFpQiw2QkFBTyxpQkFBaUIsNkJBQU8saUJBQWlCLDZCQUFPO0FBQ3RJOztBQUVBOztBQUVBLHFCQUFxQiw0QkFBVTs7QUFFL0Isc0JBQXNCLG1DQUFhOztBQUVuQywyQkFBMkIsb0NBQWM7QUFDekM7QUFDQTtBQUNBO0FBQ0EsYUFBYSxzQ0FBZ0I7QUFDN0I7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBOztBQUVBLDRCQUE0QiwyQkFBSztBQUNqQzs7QUFFQSxtQkFBbUIsdUNBQWlCOztBQUVwQyxvQkFBb0IsMEJBQWM7O0FBRWxDOztBQUVBOztBQUVBLG1CQUFtQix5Q0FBeUM7O0FBRTVEOztBQUVBOztBQUVBLG1CQUFtQix1Q0FBdUM7O0FBRTFEOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQix3Q0FBd0M7O0FBRTNEOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLG1CQUFtQixnQkFBZ0I7O0FBRW5DO0FBQ0E7O0FBRUEsc0VBQXNFLDZCQUFPOztBQUU3RTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGdCQUFnQjs7QUFFbkM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGtCQUFrQjs7QUFFckM7O0FBRUE7O0FBRUEsYUFBYSxvQ0FBYzs7QUFFM0I7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQSxzQkFBc0IsYUFBYTtBQUNuQyxpQkFBaUIsV0FBVyw2QkFBTyxjQUFjO0FBQ2pELG1CQUFtQixXQUFXLDZCQUFPLGNBQWM7QUFDbkQsOEJBQThCLHNCQUFzQjtBQUNwRCxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQixtQkFBbUI7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEsYUFBYSxvQ0FBYzs7QUFFM0I7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQSxzQkFBc0IsYUFBYTtBQUNuQyxzQkFBc0IsYUFBYTtBQUNuQyxzQkFBc0IsYUFBYTtBQUNuQyxzQkFBc0IsYUFBYTtBQUNuQyxzQkFBc0IsYUFBYTtBQUNuQyx1QkFBdUIsWUFBWTtBQUNuQyxzQkFBc0IsYUFBYTtBQUNuQyx5QkFBeUIsYUFBYTtBQUN0QyxxQkFBcUI7QUFDckIsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJOztBQUVKOztBQUVBOztBQUVBLHFDQUFxQyw2QkFBTztBQUM1QyxxQ0FBcUMsNkJBQU87O0FBRWpCIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy90aHJlZS9leGFtcGxlcy9qc20vc2hhZGVycy9MdW1pbm9zaXR5SGlnaFBhc3NTaGFkZXIuanM/NzhiYSIsIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9wb3N0cHJvY2Vzc2luZy9VbnJlYWxCbG9vbVBhc3MuanM/YTJiMSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuXHRDb2xvclxufSBmcm9tICd0aHJlZSc7XG5cbi8qKlxuICogTHVtaW5vc2l0eVxuICogaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9MdW1pbm9zaXR5XG4gKi9cblxuY29uc3QgTHVtaW5vc2l0eUhpZ2hQYXNzU2hhZGVyID0ge1xuXG5cdG5hbWU6ICdMdW1pbm9zaXR5SGlnaFBhc3NTaGFkZXInLFxuXG5cdHNoYWRlcklEOiAnbHVtaW5vc2l0eUhpZ2hQYXNzJyxcblxuXHR1bmlmb3Jtczoge1xuXG5cdFx0J3REaWZmdXNlJzogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdCdsdW1pbm9zaXR5VGhyZXNob2xkJzogeyB2YWx1ZTogMS4wIH0sXG5cdFx0J3Ntb290aFdpZHRoJzogeyB2YWx1ZTogMS4wIH0sXG5cdFx0J2RlZmF1bHRDb2xvcic6IHsgdmFsdWU6IG5ldyBDb2xvciggMHgwMDAwMDAgKSB9LFxuXHRcdCdkZWZhdWx0T3BhY2l0eSc6IHsgdmFsdWU6IDAuMCB9XG5cblx0fSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR2YXJ5aW5nIHZlYzIgdlV2O1xuXG5cdFx0dm9pZCBtYWluKCkge1xuXG5cdFx0XHR2VXYgPSB1djtcblxuXHRcdFx0Z2xfUG9zaXRpb24gPSBwcm9qZWN0aW9uTWF0cml4ICogbW9kZWxWaWV3TWF0cml4ICogdmVjNCggcG9zaXRpb24sIDEuMCApO1xuXG5cdFx0fWAsXG5cblx0ZnJhZ21lbnRTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR1bmlmb3JtIHNhbXBsZXIyRCB0RGlmZnVzZTtcblx0XHR1bmlmb3JtIHZlYzMgZGVmYXVsdENvbG9yO1xuXHRcdHVuaWZvcm0gZmxvYXQgZGVmYXVsdE9wYWNpdHk7XG5cdFx0dW5pZm9ybSBmbG9hdCBsdW1pbm9zaXR5VGhyZXNob2xkO1xuXHRcdHVuaWZvcm0gZmxvYXQgc21vb3RoV2lkdGg7XG5cblx0XHR2YXJ5aW5nIHZlYzIgdlV2O1xuXG5cdFx0dm9pZCBtYWluKCkge1xuXG5cdFx0XHR2ZWM0IHRleGVsID0gdGV4dHVyZTJEKCB0RGlmZnVzZSwgdlV2ICk7XG5cblx0XHRcdHZlYzMgbHVtYSA9IHZlYzMoIDAuMjk5LCAwLjU4NywgMC4xMTQgKTtcblxuXHRcdFx0ZmxvYXQgdiA9IGRvdCggdGV4ZWwueHl6LCBsdW1hICk7XG5cblx0XHRcdHZlYzQgb3V0cHV0Q29sb3IgPSB2ZWM0KCBkZWZhdWx0Q29sb3IucmdiLCBkZWZhdWx0T3BhY2l0eSApO1xuXG5cdFx0XHRmbG9hdCBhbHBoYSA9IHNtb290aHN0ZXAoIGx1bWlub3NpdHlUaHJlc2hvbGQsIGx1bWlub3NpdHlUaHJlc2hvbGQgKyBzbW9vdGhXaWR0aCwgdiApO1xuXG5cdFx0XHRnbF9GcmFnQ29sb3IgPSBtaXgoIG91dHB1dENvbG9yLCB0ZXhlbCwgYWxwaGEgKTtcblxuXHRcdH1gXG5cbn07XG5cbmV4cG9ydCB7IEx1bWlub3NpdHlIaWdoUGFzc1NoYWRlciB9O1xuIiwiaW1wb3J0IHtcblx0QWRkaXRpdmVCbGVuZGluZyxcblx0Q29sb3IsXG5cdEhhbGZGbG9hdFR5cGUsXG5cdE1lc2hCYXNpY01hdGVyaWFsLFxuXHRTaGFkZXJNYXRlcmlhbCxcblx0VW5pZm9ybXNVdGlscyxcblx0VmVjdG9yMixcblx0VmVjdG9yMyxcblx0V2ViR0xSZW5kZXJUYXJnZXRcbn0gZnJvbSAndGhyZWUnO1xuaW1wb3J0IHsgUGFzcywgRnVsbFNjcmVlblF1YWQgfSBmcm9tICcuL1Bhc3MuanMnO1xuaW1wb3J0IHsgQ29weVNoYWRlciB9IGZyb20gJy4uL3NoYWRlcnMvQ29weVNoYWRlci5qcyc7XG5pbXBvcnQgeyBMdW1pbm9zaXR5SGlnaFBhc3NTaGFkZXIgfSBmcm9tICcuLi9zaGFkZXJzL0x1bWlub3NpdHlIaWdoUGFzc1NoYWRlci5qcyc7XG5cbi8qKlxuICogVW5yZWFsQmxvb21QYXNzIGlzIGluc3BpcmVkIGJ5IHRoZSBibG9vbSBwYXNzIG9mIFVucmVhbCBFbmdpbmUuIEl0IGNyZWF0ZXMgYVxuICogbWlwIG1hcCBjaGFpbiBvZiBibG9vbSB0ZXh0dXJlcyBhbmQgYmx1cnMgdGhlbSB3aXRoIGRpZmZlcmVudCByYWRpaS4gQmVjYXVzZVxuICogb2YgdGhlIHdlaWdodGVkIGNvbWJpbmF0aW9uIG9mIG1pcHMsIGFuZCBiZWNhdXNlIGxhcmdlciBibHVycyBhcmUgZG9uZSBvblxuICogaGlnaGVyIG1pcHMsIHRoaXMgZWZmZWN0IHByb3ZpZGVzIGdvb2QgcXVhbGl0eSBhbmQgcGVyZm9ybWFuY2UuXG4gKlxuICogUmVmZXJlbmNlOlxuICogLSBodHRwczovL2RvY3MudW5yZWFsZW5naW5lLmNvbS9sYXRlc3QvSU5UL0VuZ2luZS9SZW5kZXJpbmcvUG9zdFByb2Nlc3NFZmZlY3RzL0Jsb29tL1xuICovXG5jbGFzcyBVbnJlYWxCbG9vbVBhc3MgZXh0ZW5kcyBQYXNzIHtcblxuXHRjb25zdHJ1Y3RvciggcmVzb2x1dGlvbiwgc3RyZW5ndGgsIHJhZGl1cywgdGhyZXNob2xkICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuc3RyZW5ndGggPSAoIHN0cmVuZ3RoICE9PSB1bmRlZmluZWQgKSA/IHN0cmVuZ3RoIDogMTtcblx0XHR0aGlzLnJhZGl1cyA9IHJhZGl1cztcblx0XHR0aGlzLnRocmVzaG9sZCA9IHRocmVzaG9sZDtcblx0XHR0aGlzLnJlc29sdXRpb24gPSAoIHJlc29sdXRpb24gIT09IHVuZGVmaW5lZCApID8gbmV3IFZlY3RvcjIoIHJlc29sdXRpb24ueCwgcmVzb2x1dGlvbi55ICkgOiBuZXcgVmVjdG9yMiggMjU2LCAyNTYgKTtcblxuXHRcdC8vIGNyZWF0ZSBjb2xvciBvbmx5IG9uY2UgaGVyZSwgcmV1c2UgaXQgbGF0ZXIgaW5zaWRlIHRoZSByZW5kZXIgZnVuY3Rpb25cblx0XHR0aGlzLmNsZWFyQ29sb3IgPSBuZXcgQ29sb3IoIDAsIDAsIDAgKTtcblxuXHRcdC8vIHJlbmRlciB0YXJnZXRzXG5cdFx0dGhpcy5yZW5kZXJUYXJnZXRzSG9yaXpvbnRhbCA9IFtdO1xuXHRcdHRoaXMucmVuZGVyVGFyZ2V0c1ZlcnRpY2FsID0gW107XG5cdFx0dGhpcy5uTWlwcyA9IDU7XG5cdFx0bGV0IHJlc3ggPSBNYXRoLnJvdW5kKCB0aGlzLnJlc29sdXRpb24ueCAvIDIgKTtcblx0XHRsZXQgcmVzeSA9IE1hdGgucm91bmQoIHRoaXMucmVzb2x1dGlvbi55IC8gMiApO1xuXG5cdFx0dGhpcy5yZW5kZXJUYXJnZXRCcmlnaHQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoIHJlc3gsIHJlc3ksIHsgdHlwZTogSGFsZkZsb2F0VHlwZSB9ICk7XG5cdFx0dGhpcy5yZW5kZXJUYXJnZXRCcmlnaHQudGV4dHVyZS5uYW1lID0gJ1VucmVhbEJsb29tUGFzcy5icmlnaHQnO1xuXHRcdHRoaXMucmVuZGVyVGFyZ2V0QnJpZ2h0LnRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLm5NaXBzOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCByZW5kZXJUYXJnZXRIb3Jpem9uYWwgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoIHJlc3gsIHJlc3ksIHsgdHlwZTogSGFsZkZsb2F0VHlwZSB9ICk7XG5cblx0XHRcdHJlbmRlclRhcmdldEhvcml6b25hbC50ZXh0dXJlLm5hbWUgPSAnVW5yZWFsQmxvb21QYXNzLmgnICsgaTtcblx0XHRcdHJlbmRlclRhcmdldEhvcml6b25hbC50ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXG5cdFx0XHR0aGlzLnJlbmRlclRhcmdldHNIb3Jpem9udGFsLnB1c2goIHJlbmRlclRhcmdldEhvcml6b25hbCApO1xuXG5cdFx0XHRjb25zdCByZW5kZXJUYXJnZXRWZXJ0aWNhbCA9IG5ldyBXZWJHTFJlbmRlclRhcmdldCggcmVzeCwgcmVzeSwgeyB0eXBlOiBIYWxmRmxvYXRUeXBlIH0gKTtcblxuXHRcdFx0cmVuZGVyVGFyZ2V0VmVydGljYWwudGV4dHVyZS5uYW1lID0gJ1VucmVhbEJsb29tUGFzcy52JyArIGk7XG5cdFx0XHRyZW5kZXJUYXJnZXRWZXJ0aWNhbC50ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXG5cdFx0XHR0aGlzLnJlbmRlclRhcmdldHNWZXJ0aWNhbC5wdXNoKCByZW5kZXJUYXJnZXRWZXJ0aWNhbCApO1xuXG5cdFx0XHRyZXN4ID0gTWF0aC5yb3VuZCggcmVzeCAvIDIgKTtcblxuXHRcdFx0cmVzeSA9IE1hdGgucm91bmQoIHJlc3kgLyAyICk7XG5cblx0XHR9XG5cblx0XHQvLyBsdW1pbm9zaXR5IGhpZ2ggcGFzcyBtYXRlcmlhbFxuXG5cdFx0Y29uc3QgaGlnaFBhc3NTaGFkZXIgPSBMdW1pbm9zaXR5SGlnaFBhc3NTaGFkZXI7XG5cdFx0dGhpcy5oaWdoUGFzc1VuaWZvcm1zID0gVW5pZm9ybXNVdGlscy5jbG9uZSggaGlnaFBhc3NTaGFkZXIudW5pZm9ybXMgKTtcblxuXHRcdHRoaXMuaGlnaFBhc3NVbmlmb3Jtc1sgJ2x1bWlub3NpdHlUaHJlc2hvbGQnIF0udmFsdWUgPSB0aHJlc2hvbGQ7XG5cdFx0dGhpcy5oaWdoUGFzc1VuaWZvcm1zWyAnc21vb3RoV2lkdGgnIF0udmFsdWUgPSAwLjAxO1xuXG5cdFx0dGhpcy5tYXRlcmlhbEhpZ2hQYXNzRmlsdGVyID0gbmV3IFNoYWRlck1hdGVyaWFsKCB7XG5cdFx0XHR1bmlmb3JtczogdGhpcy5oaWdoUGFzc1VuaWZvcm1zLFxuXHRcdFx0dmVydGV4U2hhZGVyOiBoaWdoUGFzc1NoYWRlci52ZXJ0ZXhTaGFkZXIsXG5cdFx0XHRmcmFnbWVudFNoYWRlcjogaGlnaFBhc3NTaGFkZXIuZnJhZ21lbnRTaGFkZXJcblx0XHR9ICk7XG5cblx0XHQvLyBnYXVzc2lhbiBibHVyIG1hdGVyaWFsc1xuXG5cdFx0dGhpcy5zZXBhcmFibGVCbHVyTWF0ZXJpYWxzID0gW107XG5cdFx0Y29uc3Qga2VybmVsU2l6ZUFycmF5ID0gWyAzLCA1LCA3LCA5LCAxMSBdO1xuXHRcdHJlc3ggPSBNYXRoLnJvdW5kKCB0aGlzLnJlc29sdXRpb24ueCAvIDIgKTtcblx0XHRyZXN5ID0gTWF0aC5yb3VuZCggdGhpcy5yZXNvbHV0aW9uLnkgLyAyICk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLm5NaXBzOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLnNlcGFyYWJsZUJsdXJNYXRlcmlhbHMucHVzaCggdGhpcy5nZXRTZXBlcmFibGVCbHVyTWF0ZXJpYWwoIGtlcm5lbFNpemVBcnJheVsgaSBdICkgKTtcblxuXHRcdFx0dGhpcy5zZXBhcmFibGVCbHVyTWF0ZXJpYWxzWyBpIF0udW5pZm9ybXNbICdpbnZTaXplJyBdLnZhbHVlID0gbmV3IFZlY3RvcjIoIDEgLyByZXN4LCAxIC8gcmVzeSApO1xuXG5cdFx0XHRyZXN4ID0gTWF0aC5yb3VuZCggcmVzeCAvIDIgKTtcblxuXHRcdFx0cmVzeSA9IE1hdGgucm91bmQoIHJlc3kgLyAyICk7XG5cblx0XHR9XG5cblx0XHQvLyBjb21wb3NpdGUgbWF0ZXJpYWxcblxuXHRcdHRoaXMuY29tcG9zaXRlTWF0ZXJpYWwgPSB0aGlzLmdldENvbXBvc2l0ZU1hdGVyaWFsKCB0aGlzLm5NaXBzICk7XG5cdFx0dGhpcy5jb21wb3NpdGVNYXRlcmlhbC51bmlmb3Jtc1sgJ2JsdXJUZXh0dXJlMScgXS52YWx1ZSA9IHRoaXMucmVuZGVyVGFyZ2V0c1ZlcnRpY2FsWyAwIF0udGV4dHVyZTtcblx0XHR0aGlzLmNvbXBvc2l0ZU1hdGVyaWFsLnVuaWZvcm1zWyAnYmx1clRleHR1cmUyJyBdLnZhbHVlID0gdGhpcy5yZW5kZXJUYXJnZXRzVmVydGljYWxbIDEgXS50ZXh0dXJlO1xuXHRcdHRoaXMuY29tcG9zaXRlTWF0ZXJpYWwudW5pZm9ybXNbICdibHVyVGV4dHVyZTMnIF0udmFsdWUgPSB0aGlzLnJlbmRlclRhcmdldHNWZXJ0aWNhbFsgMiBdLnRleHR1cmU7XG5cdFx0dGhpcy5jb21wb3NpdGVNYXRlcmlhbC51bmlmb3Jtc1sgJ2JsdXJUZXh0dXJlNCcgXS52YWx1ZSA9IHRoaXMucmVuZGVyVGFyZ2V0c1ZlcnRpY2FsWyAzIF0udGV4dHVyZTtcblx0XHR0aGlzLmNvbXBvc2l0ZU1hdGVyaWFsLnVuaWZvcm1zWyAnYmx1clRleHR1cmU1JyBdLnZhbHVlID0gdGhpcy5yZW5kZXJUYXJnZXRzVmVydGljYWxbIDQgXS50ZXh0dXJlO1xuXHRcdHRoaXMuY29tcG9zaXRlTWF0ZXJpYWwudW5pZm9ybXNbICdibG9vbVN0cmVuZ3RoJyBdLnZhbHVlID0gc3RyZW5ndGg7XG5cdFx0dGhpcy5jb21wb3NpdGVNYXRlcmlhbC51bmlmb3Jtc1sgJ2Jsb29tUmFkaXVzJyBdLnZhbHVlID0gMC4xO1xuXG5cdFx0Y29uc3QgYmxvb21GYWN0b3JzID0gWyAxLjAsIDAuOCwgMC42LCAwLjQsIDAuMiBdO1xuXHRcdHRoaXMuY29tcG9zaXRlTWF0ZXJpYWwudW5pZm9ybXNbICdibG9vbUZhY3RvcnMnIF0udmFsdWUgPSBibG9vbUZhY3RvcnM7XG5cdFx0dGhpcy5ibG9vbVRpbnRDb2xvcnMgPSBbIG5ldyBWZWN0b3IzKCAxLCAxLCAxICksIG5ldyBWZWN0b3IzKCAxLCAxLCAxICksIG5ldyBWZWN0b3IzKCAxLCAxLCAxICksIG5ldyBWZWN0b3IzKCAxLCAxLCAxICksIG5ldyBWZWN0b3IzKCAxLCAxLCAxICkgXTtcblx0XHR0aGlzLmNvbXBvc2l0ZU1hdGVyaWFsLnVuaWZvcm1zWyAnYmxvb21UaW50Q29sb3JzJyBdLnZhbHVlID0gdGhpcy5ibG9vbVRpbnRDb2xvcnM7XG5cblx0XHQvLyBibGVuZCBtYXRlcmlhbFxuXG5cdFx0Y29uc3QgY29weVNoYWRlciA9IENvcHlTaGFkZXI7XG5cblx0XHR0aGlzLmNvcHlVbmlmb3JtcyA9IFVuaWZvcm1zVXRpbHMuY2xvbmUoIGNvcHlTaGFkZXIudW5pZm9ybXMgKTtcblxuXHRcdHRoaXMuYmxlbmRNYXRlcmlhbCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xuXHRcdFx0dW5pZm9ybXM6IHRoaXMuY29weVVuaWZvcm1zLFxuXHRcdFx0dmVydGV4U2hhZGVyOiBjb3B5U2hhZGVyLnZlcnRleFNoYWRlcixcblx0XHRcdGZyYWdtZW50U2hhZGVyOiBjb3B5U2hhZGVyLmZyYWdtZW50U2hhZGVyLFxuXHRcdFx0YmxlbmRpbmc6IEFkZGl0aXZlQmxlbmRpbmcsXG5cdFx0XHRkZXB0aFRlc3Q6IGZhbHNlLFxuXHRcdFx0ZGVwdGhXcml0ZTogZmFsc2UsXG5cdFx0XHR0cmFuc3BhcmVudDogdHJ1ZVxuXHRcdH0gKTtcblxuXHRcdHRoaXMuZW5hYmxlZCA9IHRydWU7XG5cdFx0dGhpcy5uZWVkc1N3YXAgPSBmYWxzZTtcblxuXHRcdHRoaXMuX29sZENsZWFyQ29sb3IgPSBuZXcgQ29sb3IoKTtcblx0XHR0aGlzLm9sZENsZWFyQWxwaGEgPSAxO1xuXG5cdFx0dGhpcy5iYXNpYyA9IG5ldyBNZXNoQmFzaWNNYXRlcmlhbCgpO1xuXG5cdFx0dGhpcy5mc1F1YWQgPSBuZXcgRnVsbFNjcmVlblF1YWQoIG51bGwgKTtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMucmVuZGVyVGFyZ2V0c0hvcml6b250YWwubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLnJlbmRlclRhcmdldHNIb3Jpem9udGFsWyBpIF0uZGlzcG9zZSgpO1xuXG5cdFx0fVxuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy5yZW5kZXJUYXJnZXRzVmVydGljYWwubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLnJlbmRlclRhcmdldHNWZXJ0aWNhbFsgaSBdLmRpc3Bvc2UoKTtcblxuXHRcdH1cblxuXHRcdHRoaXMucmVuZGVyVGFyZ2V0QnJpZ2h0LmRpc3Bvc2UoKTtcblxuXHRcdC8vXG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLnNlcGFyYWJsZUJsdXJNYXRlcmlhbHMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLnNlcGFyYWJsZUJsdXJNYXRlcmlhbHNbIGkgXS5kaXNwb3NlKCk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmNvbXBvc2l0ZU1hdGVyaWFsLmRpc3Bvc2UoKTtcblx0XHR0aGlzLmJsZW5kTWF0ZXJpYWwuZGlzcG9zZSgpO1xuXHRcdHRoaXMuYmFzaWMuZGlzcG9zZSgpO1xuXG5cdFx0Ly9cblxuXHRcdHRoaXMuZnNRdWFkLmRpc3Bvc2UoKTtcblxuXHR9XG5cblx0c2V0U2l6ZSggd2lkdGgsIGhlaWdodCApIHtcblxuXHRcdGxldCByZXN4ID0gTWF0aC5yb3VuZCggd2lkdGggLyAyICk7XG5cdFx0bGV0IHJlc3kgPSBNYXRoLnJvdW5kKCBoZWlnaHQgLyAyICk7XG5cblx0XHR0aGlzLnJlbmRlclRhcmdldEJyaWdodC5zZXRTaXplKCByZXN4LCByZXN5ICk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLm5NaXBzOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLnJlbmRlclRhcmdldHNIb3Jpem9udGFsWyBpIF0uc2V0U2l6ZSggcmVzeCwgcmVzeSApO1xuXHRcdFx0dGhpcy5yZW5kZXJUYXJnZXRzVmVydGljYWxbIGkgXS5zZXRTaXplKCByZXN4LCByZXN5ICk7XG5cblx0XHRcdHRoaXMuc2VwYXJhYmxlQmx1ck1hdGVyaWFsc1sgaSBdLnVuaWZvcm1zWyAnaW52U2l6ZScgXS52YWx1ZSA9IG5ldyBWZWN0b3IyKCAxIC8gcmVzeCwgMSAvIHJlc3kgKTtcblxuXHRcdFx0cmVzeCA9IE1hdGgucm91bmQoIHJlc3ggLyAyICk7XG5cdFx0XHRyZXN5ID0gTWF0aC5yb3VuZCggcmVzeSAvIDIgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0cmVuZGVyKCByZW5kZXJlciwgd3JpdGVCdWZmZXIsIHJlYWRCdWZmZXIsIGRlbHRhVGltZSwgbWFza0FjdGl2ZSApIHtcblxuXHRcdHJlbmRlcmVyLmdldENsZWFyQ29sb3IoIHRoaXMuX29sZENsZWFyQ29sb3IgKTtcblx0XHR0aGlzLm9sZENsZWFyQWxwaGEgPSByZW5kZXJlci5nZXRDbGVhckFscGhhKCk7XG5cdFx0Y29uc3Qgb2xkQXV0b0NsZWFyID0gcmVuZGVyZXIuYXV0b0NsZWFyO1xuXHRcdHJlbmRlcmVyLmF1dG9DbGVhciA9IGZhbHNlO1xuXG5cdFx0cmVuZGVyZXIuc2V0Q2xlYXJDb2xvciggdGhpcy5jbGVhckNvbG9yLCAwICk7XG5cblx0XHRpZiAoIG1hc2tBY3RpdmUgKSByZW5kZXJlci5zdGF0ZS5idWZmZXJzLnN0ZW5jaWwuc2V0VGVzdCggZmFsc2UgKTtcblxuXHRcdC8vIFJlbmRlciBpbnB1dCB0byBzY3JlZW5cblxuXHRcdGlmICggdGhpcy5yZW5kZXJUb1NjcmVlbiApIHtcblxuXHRcdFx0dGhpcy5mc1F1YWQubWF0ZXJpYWwgPSB0aGlzLmJhc2ljO1xuXHRcdFx0dGhpcy5iYXNpYy5tYXAgPSByZWFkQnVmZmVyLnRleHR1cmU7XG5cblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggbnVsbCApO1xuXHRcdFx0cmVuZGVyZXIuY2xlYXIoKTtcblx0XHRcdHRoaXMuZnNRdWFkLnJlbmRlciggcmVuZGVyZXIgKTtcblxuXHRcdH1cblxuXHRcdC8vIDEuIEV4dHJhY3QgQnJpZ2h0IEFyZWFzXG5cblx0XHR0aGlzLmhpZ2hQYXNzVW5pZm9ybXNbICd0RGlmZnVzZScgXS52YWx1ZSA9IHJlYWRCdWZmZXIudGV4dHVyZTtcblx0XHR0aGlzLmhpZ2hQYXNzVW5pZm9ybXNbICdsdW1pbm9zaXR5VGhyZXNob2xkJyBdLnZhbHVlID0gdGhpcy50aHJlc2hvbGQ7XG5cdFx0dGhpcy5mc1F1YWQubWF0ZXJpYWwgPSB0aGlzLm1hdGVyaWFsSGlnaFBhc3NGaWx0ZXI7XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHRoaXMucmVuZGVyVGFyZ2V0QnJpZ2h0ICk7XG5cdFx0cmVuZGVyZXIuY2xlYXIoKTtcblx0XHR0aGlzLmZzUXVhZC5yZW5kZXIoIHJlbmRlcmVyICk7XG5cblx0XHQvLyAyLiBCbHVyIEFsbCB0aGUgbWlwcyBwcm9ncmVzc2l2ZWx5XG5cblx0XHRsZXQgaW5wdXRSZW5kZXJUYXJnZXQgPSB0aGlzLnJlbmRlclRhcmdldEJyaWdodDtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMubk1pcHM7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuZnNRdWFkLm1hdGVyaWFsID0gdGhpcy5zZXBhcmFibGVCbHVyTWF0ZXJpYWxzWyBpIF07XG5cblx0XHRcdHRoaXMuc2VwYXJhYmxlQmx1ck1hdGVyaWFsc1sgaSBdLnVuaWZvcm1zWyAnY29sb3JUZXh0dXJlJyBdLnZhbHVlID0gaW5wdXRSZW5kZXJUYXJnZXQudGV4dHVyZTtcblx0XHRcdHRoaXMuc2VwYXJhYmxlQmx1ck1hdGVyaWFsc1sgaSBdLnVuaWZvcm1zWyAnZGlyZWN0aW9uJyBdLnZhbHVlID0gVW5yZWFsQmxvb21QYXNzLkJsdXJEaXJlY3Rpb25YO1xuXHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCB0aGlzLnJlbmRlclRhcmdldHNIb3Jpem9udGFsWyBpIF0gKTtcblx0XHRcdHJlbmRlcmVyLmNsZWFyKCk7XG5cdFx0XHR0aGlzLmZzUXVhZC5yZW5kZXIoIHJlbmRlcmVyICk7XG5cblx0XHRcdHRoaXMuc2VwYXJhYmxlQmx1ck1hdGVyaWFsc1sgaSBdLnVuaWZvcm1zWyAnY29sb3JUZXh0dXJlJyBdLnZhbHVlID0gdGhpcy5yZW5kZXJUYXJnZXRzSG9yaXpvbnRhbFsgaSBdLnRleHR1cmU7XG5cdFx0XHR0aGlzLnNlcGFyYWJsZUJsdXJNYXRlcmlhbHNbIGkgXS51bmlmb3Jtc1sgJ2RpcmVjdGlvbicgXS52YWx1ZSA9IFVucmVhbEJsb29tUGFzcy5CbHVyRGlyZWN0aW9uWTtcblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggdGhpcy5yZW5kZXJUYXJnZXRzVmVydGljYWxbIGkgXSApO1xuXHRcdFx0cmVuZGVyZXIuY2xlYXIoKTtcblx0XHRcdHRoaXMuZnNRdWFkLnJlbmRlciggcmVuZGVyZXIgKTtcblxuXHRcdFx0aW5wdXRSZW5kZXJUYXJnZXQgPSB0aGlzLnJlbmRlclRhcmdldHNWZXJ0aWNhbFsgaSBdO1xuXG5cdFx0fVxuXG5cdFx0Ly8gQ29tcG9zaXRlIEFsbCB0aGUgbWlwc1xuXG5cdFx0dGhpcy5mc1F1YWQubWF0ZXJpYWwgPSB0aGlzLmNvbXBvc2l0ZU1hdGVyaWFsO1xuXHRcdHRoaXMuY29tcG9zaXRlTWF0ZXJpYWwudW5pZm9ybXNbICdibG9vbVN0cmVuZ3RoJyBdLnZhbHVlID0gdGhpcy5zdHJlbmd0aDtcblx0XHR0aGlzLmNvbXBvc2l0ZU1hdGVyaWFsLnVuaWZvcm1zWyAnYmxvb21SYWRpdXMnIF0udmFsdWUgPSB0aGlzLnJhZGl1cztcblx0XHR0aGlzLmNvbXBvc2l0ZU1hdGVyaWFsLnVuaWZvcm1zWyAnYmxvb21UaW50Q29sb3JzJyBdLnZhbHVlID0gdGhpcy5ibG9vbVRpbnRDb2xvcnM7XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHRoaXMucmVuZGVyVGFyZ2V0c0hvcml6b250YWxbIDAgXSApO1xuXHRcdHJlbmRlcmVyLmNsZWFyKCk7XG5cdFx0dGhpcy5mc1F1YWQucmVuZGVyKCByZW5kZXJlciApO1xuXG5cdFx0Ly8gQmxlbmQgaXQgYWRkaXRpdmVseSBvdmVyIHRoZSBpbnB1dCB0ZXh0dXJlXG5cblx0XHR0aGlzLmZzUXVhZC5tYXRlcmlhbCA9IHRoaXMuYmxlbmRNYXRlcmlhbDtcblx0XHR0aGlzLmNvcHlVbmlmb3Jtc1sgJ3REaWZmdXNlJyBdLnZhbHVlID0gdGhpcy5yZW5kZXJUYXJnZXRzSG9yaXpvbnRhbFsgMCBdLnRleHR1cmU7XG5cblx0XHRpZiAoIG1hc2tBY3RpdmUgKSByZW5kZXJlci5zdGF0ZS5idWZmZXJzLnN0ZW5jaWwuc2V0VGVzdCggdHJ1ZSApO1xuXG5cdFx0aWYgKCB0aGlzLnJlbmRlclRvU2NyZWVuICkge1xuXG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIG51bGwgKTtcblx0XHRcdHRoaXMuZnNRdWFkLnJlbmRlciggcmVuZGVyZXIgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVhZEJ1ZmZlciApO1xuXHRcdFx0dGhpcy5mc1F1YWQucmVuZGVyKCByZW5kZXJlciApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gUmVzdG9yZSByZW5kZXJlciBzZXR0aW5nc1xuXG5cdFx0cmVuZGVyZXIuc2V0Q2xlYXJDb2xvciggdGhpcy5fb2xkQ2xlYXJDb2xvciwgdGhpcy5vbGRDbGVhckFscGhhICk7XG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gb2xkQXV0b0NsZWFyO1xuXG5cdH1cblxuXHRnZXRTZXBlcmFibGVCbHVyTWF0ZXJpYWwoIGtlcm5lbFJhZGl1cyApIHtcblxuXHRcdGNvbnN0IGNvZWZmaWNpZW50cyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwga2VybmVsUmFkaXVzOyBpICsrICkge1xuXG5cdFx0XHRjb2VmZmljaWVudHMucHVzaCggMC4zOTg5NCAqIE1hdGguZXhwKCAtIDAuNSAqIGkgKiBpIC8gKCBrZXJuZWxSYWRpdXMgKiBrZXJuZWxSYWRpdXMgKSApIC8ga2VybmVsUmFkaXVzICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gbmV3IFNoYWRlck1hdGVyaWFsKCB7XG5cblx0XHRcdGRlZmluZXM6IHtcblx0XHRcdFx0J0tFUk5FTF9SQURJVVMnOiBrZXJuZWxSYWRpdXNcblx0XHRcdH0sXG5cblx0XHRcdHVuaWZvcm1zOiB7XG5cdFx0XHRcdCdjb2xvclRleHR1cmUnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRcdCdpbnZTaXplJzogeyB2YWx1ZTogbmV3IFZlY3RvcjIoIDAuNSwgMC41ICkgfSwgLy8gaW52ZXJzZSB0ZXh0dXJlIHNpemVcblx0XHRcdFx0J2RpcmVjdGlvbic6IHsgdmFsdWU6IG5ldyBWZWN0b3IyKCAwLjUsIDAuNSApIH0sXG5cdFx0XHRcdCdnYXVzc2lhbkNvZWZmaWNpZW50cyc6IHsgdmFsdWU6IGNvZWZmaWNpZW50cyB9IC8vIHByZWNvbXB1dGVkIEdhdXNzaWFuIGNvZWZmaWNpZW50c1xuXHRcdFx0fSxcblxuXHRcdFx0dmVydGV4U2hhZGVyOlxuXHRcdFx0XHRgdmFyeWluZyB2ZWMyIHZVdjtcblx0XHRcdFx0dm9pZCBtYWluKCkge1xuXHRcdFx0XHRcdHZVdiA9IHV2O1xuXHRcdFx0XHRcdGdsX1Bvc2l0aW9uID0gcHJvamVjdGlvbk1hdHJpeCAqIG1vZGVsVmlld01hdHJpeCAqIHZlYzQoIHBvc2l0aW9uLCAxLjAgKTtcblx0XHRcdFx0fWAsXG5cblx0XHRcdGZyYWdtZW50U2hhZGVyOlxuXHRcdFx0XHRgI2luY2x1ZGUgPGNvbW1vbj5cblx0XHRcdFx0dmFyeWluZyB2ZWMyIHZVdjtcblx0XHRcdFx0dW5pZm9ybSBzYW1wbGVyMkQgY29sb3JUZXh0dXJlO1xuXHRcdFx0XHR1bmlmb3JtIHZlYzIgaW52U2l6ZTtcblx0XHRcdFx0dW5pZm9ybSB2ZWMyIGRpcmVjdGlvbjtcblx0XHRcdFx0dW5pZm9ybSBmbG9hdCBnYXVzc2lhbkNvZWZmaWNpZW50c1tLRVJORUxfUkFESVVTXTtcblxuXHRcdFx0XHR2b2lkIG1haW4oKSB7XG5cdFx0XHRcdFx0ZmxvYXQgd2VpZ2h0U3VtID0gZ2F1c3NpYW5Db2VmZmljaWVudHNbMF07XG5cdFx0XHRcdFx0dmVjMyBkaWZmdXNlU3VtID0gdGV4dHVyZTJEKCBjb2xvclRleHR1cmUsIHZVdiApLnJnYiAqIHdlaWdodFN1bTtcblx0XHRcdFx0XHRmb3IoIGludCBpID0gMTsgaSA8IEtFUk5FTF9SQURJVVM7IGkgKysgKSB7XG5cdFx0XHRcdFx0XHRmbG9hdCB4ID0gZmxvYXQoaSk7XG5cdFx0XHRcdFx0XHRmbG9hdCB3ID0gZ2F1c3NpYW5Db2VmZmljaWVudHNbaV07XG5cdFx0XHRcdFx0XHR2ZWMyIHV2T2Zmc2V0ID0gZGlyZWN0aW9uICogaW52U2l6ZSAqIHg7XG5cdFx0XHRcdFx0XHR2ZWMzIHNhbXBsZTEgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4dHVyZSwgdlV2ICsgdXZPZmZzZXQgKS5yZ2I7XG5cdFx0XHRcdFx0XHR2ZWMzIHNhbXBsZTIgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4dHVyZSwgdlV2IC0gdXZPZmZzZXQgKS5yZ2I7XG5cdFx0XHRcdFx0XHRkaWZmdXNlU3VtICs9IChzYW1wbGUxICsgc2FtcGxlMikgKiB3O1xuXHRcdFx0XHRcdFx0d2VpZ2h0U3VtICs9IDIuMCAqIHc7XG5cdFx0XHRcdFx0fVxuXHRcdFx0XHRcdGdsX0ZyYWdDb2xvciA9IHZlYzQoZGlmZnVzZVN1bS93ZWlnaHRTdW0sIDEuMCk7XG5cdFx0XHRcdH1gXG5cdFx0fSApO1xuXG5cdH1cblxuXHRnZXRDb21wb3NpdGVNYXRlcmlhbCggbk1pcHMgKSB7XG5cblx0XHRyZXR1cm4gbmV3IFNoYWRlck1hdGVyaWFsKCB7XG5cblx0XHRcdGRlZmluZXM6IHtcblx0XHRcdFx0J05VTV9NSVBTJzogbk1pcHNcblx0XHRcdH0sXG5cblx0XHRcdHVuaWZvcm1zOiB7XG5cdFx0XHRcdCdibHVyVGV4dHVyZTEnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRcdCdibHVyVGV4dHVyZTInOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRcdCdibHVyVGV4dHVyZTMnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRcdCdibHVyVGV4dHVyZTQnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRcdCdibHVyVGV4dHVyZTUnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRcdCdibG9vbVN0cmVuZ3RoJzogeyB2YWx1ZTogMS4wIH0sXG5cdFx0XHRcdCdibG9vbUZhY3RvcnMnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRcdCdibG9vbVRpbnRDb2xvcnMnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRcdCdibG9vbVJhZGl1cyc6IHsgdmFsdWU6IDAuMCB9XG5cdFx0XHR9LFxuXG5cdFx0XHR2ZXJ0ZXhTaGFkZXI6XG5cdFx0XHRcdGB2YXJ5aW5nIHZlYzIgdlV2O1xuXHRcdFx0XHR2b2lkIG1haW4oKSB7XG5cdFx0XHRcdFx0dlV2ID0gdXY7XG5cdFx0XHRcdFx0Z2xfUG9zaXRpb24gPSBwcm9qZWN0aW9uTWF0cml4ICogbW9kZWxWaWV3TWF0cml4ICogdmVjNCggcG9zaXRpb24sIDEuMCApO1xuXHRcdFx0XHR9YCxcblxuXHRcdFx0ZnJhZ21lbnRTaGFkZXI6XG5cdFx0XHRcdGB2YXJ5aW5nIHZlYzIgdlV2O1xuXHRcdFx0XHR1bmlmb3JtIHNhbXBsZXIyRCBibHVyVGV4dHVyZTE7XG5cdFx0XHRcdHVuaWZvcm0gc2FtcGxlcjJEIGJsdXJUZXh0dXJlMjtcblx0XHRcdFx0dW5pZm9ybSBzYW1wbGVyMkQgYmx1clRleHR1cmUzO1xuXHRcdFx0XHR1bmlmb3JtIHNhbXBsZXIyRCBibHVyVGV4dHVyZTQ7XG5cdFx0XHRcdHVuaWZvcm0gc2FtcGxlcjJEIGJsdXJUZXh0dXJlNTtcblx0XHRcdFx0dW5pZm9ybSBmbG9hdCBibG9vbVN0cmVuZ3RoO1xuXHRcdFx0XHR1bmlmb3JtIGZsb2F0IGJsb29tUmFkaXVzO1xuXHRcdFx0XHR1bmlmb3JtIGZsb2F0IGJsb29tRmFjdG9yc1tOVU1fTUlQU107XG5cdFx0XHRcdHVuaWZvcm0gdmVjMyBibG9vbVRpbnRDb2xvcnNbTlVNX01JUFNdO1xuXG5cdFx0XHRcdGZsb2F0IGxlcnBCbG9vbUZhY3Rvcihjb25zdCBpbiBmbG9hdCBmYWN0b3IpIHtcblx0XHRcdFx0XHRmbG9hdCBtaXJyb3JGYWN0b3IgPSAxLjIgLSBmYWN0b3I7XG5cdFx0XHRcdFx0cmV0dXJuIG1peChmYWN0b3IsIG1pcnJvckZhY3RvciwgYmxvb21SYWRpdXMpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0dm9pZCBtYWluKCkge1xuXHRcdFx0XHRcdGdsX0ZyYWdDb2xvciA9IGJsb29tU3RyZW5ndGggKiAoIGxlcnBCbG9vbUZhY3RvcihibG9vbUZhY3RvcnNbMF0pICogdmVjNChibG9vbVRpbnRDb2xvcnNbMF0sIDEuMCkgKiB0ZXh0dXJlMkQoYmx1clRleHR1cmUxLCB2VXYpICtcblx0XHRcdFx0XHRcdGxlcnBCbG9vbUZhY3RvcihibG9vbUZhY3RvcnNbMV0pICogdmVjNChibG9vbVRpbnRDb2xvcnNbMV0sIDEuMCkgKiB0ZXh0dXJlMkQoYmx1clRleHR1cmUyLCB2VXYpICtcblx0XHRcdFx0XHRcdGxlcnBCbG9vbUZhY3RvcihibG9vbUZhY3RvcnNbMl0pICogdmVjNChibG9vbVRpbnRDb2xvcnNbMl0sIDEuMCkgKiB0ZXh0dXJlMkQoYmx1clRleHR1cmUzLCB2VXYpICtcblx0XHRcdFx0XHRcdGxlcnBCbG9vbUZhY3RvcihibG9vbUZhY3RvcnNbM10pICogdmVjNChibG9vbVRpbnRDb2xvcnNbM10sIDEuMCkgKiB0ZXh0dXJlMkQoYmx1clRleHR1cmU0LCB2VXYpICtcblx0XHRcdFx0XHRcdGxlcnBCbG9vbUZhY3RvcihibG9vbUZhY3RvcnNbNF0pICogdmVjNChibG9vbVRpbnRDb2xvcnNbNF0sIDEuMCkgKiB0ZXh0dXJlMkQoYmx1clRleHR1cmU1LCB2VXYpICk7XG5cdFx0XHRcdH1gXG5cdFx0fSApO1xuXG5cdH1cblxufVxuXG5VbnJlYWxCbG9vbVBhc3MuQmx1ckRpcmVjdGlvblggPSBuZXcgVmVjdG9yMiggMS4wLCAwLjAgKTtcblVucmVhbEJsb29tUGFzcy5CbHVyRGlyZWN0aW9uWSA9IG5ldyBWZWN0b3IyKCAwLjAsIDEuMCApO1xuXG5leHBvcnQgeyBVbnJlYWxCbG9vbVBhc3MgfTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///208\n")},364:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Z: () => (/* binding */ CopyShader)\n/* harmony export */ });\n/**\n * Full-screen textured quad shader\n */\n\nconst CopyShader = {\n\n\tname: 'CopyShader',\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'opacity': { value: 1.0 }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\n\t\tuniform float opacity;\n\n\t\tuniform sampler2D tDiffuse;\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvec4 texel = texture2D( tDiffuse, vUv );\n\t\t\tgl_FragColor = opacity * texel;\n\n\n\t\t}`\n\n};\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMzY0LmpzIiwibWFwcGluZ3MiOiI7OztBQUFBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxnQkFBZ0IsYUFBYTtBQUM3QixlQUFlOztBQUVmLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7OztBQUdBLEdBQUc7O0FBRUg7O0FBRXNCIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy90aHJlZS9leGFtcGxlcy9qc20vc2hhZGVycy9Db3B5U2hhZGVyLmpzPzE4ODciXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBGdWxsLXNjcmVlbiB0ZXh0dXJlZCBxdWFkIHNoYWRlclxuICovXG5cbmNvbnN0IENvcHlTaGFkZXIgPSB7XG5cblx0bmFtZTogJ0NvcHlTaGFkZXInLFxuXG5cdHVuaWZvcm1zOiB7XG5cblx0XHQndERpZmZ1c2UnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0J29wYWNpdHknOiB7IHZhbHVlOiAxLjAgfVxuXG5cdH0sXG5cblx0dmVydGV4U2hhZGVyOiAvKiBnbHNsICovYFxuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0dlV2ID0gdXY7XG5cdFx0XHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XG5cblx0XHR9YCxcblxuXHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2BcblxuXHRcdHVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcblxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHREaWZmdXNlO1xuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0dmVjNCB0ZXhlbCA9IHRleHR1cmUyRCggdERpZmZ1c2UsIHZVdiApO1xuXHRcdFx0Z2xfRnJhZ0NvbG9yID0gb3BhY2l0eSAqIHRleGVsO1xuXG5cblx0XHR9YFxuXG59O1xuXG5leHBvcnQgeyBDb3B5U2hhZGVyIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///364\n")},161:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ o: () => (/* binding */ FXAAShader)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(753);\n\n\n/**\n * NVIDIA FXAA by Timothy Lottes\n * https://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf\n * - WebGL port by @supereggbert\n * http://www.glge.org/demos/fxaa/\n * Further improved by Daniel Sturk\n */\n\nconst FXAAShader = {\n\n\tname: 'FXAAShader',\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'resolution': { value: new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y( 1 / 1024, 1 / 512 ) }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\t\tprecision highp float;\n\n\t\tuniform sampler2D tDiffuse;\n\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\n\t\t// FXAA 3.11 implementation by NVIDIA, ported to WebGL by Agost Biro (biro@archilogic.com)\n\n\t\t//----------------------------------------------------------------------------------\n\t\t// File: es3-kepler\\FXAA\\assets\\shaders/FXAA_DefaultES.frag\n\t\t// SDK Version: v3.00\n\t\t// Email: gameworks@nvidia.com\n\t\t// Site: http://developer.nvidia.com/\n\t\t//\n\t\t// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.\n\t\t//\n\t\t// Redistribution and use in source and binary forms, with or without\n\t\t// modification, are permitted provided that the following conditions\n\t\t// are met:\n\t\t// * Redistributions of source code must retain the above copyright\n\t\t// notice, this list of conditions and the following disclaimer.\n\t\t// * Redistributions in binary form must reproduce the above copyright\n\t\t// notice, this list of conditions and the following disclaimer in the\n\t\t// documentation and/or other materials provided with the distribution.\n\t\t// * Neither the name of NVIDIA CORPORATION nor the names of its\n\t\t// contributors may be used to endorse or promote products derived\n\t\t// from this software without specific prior written permission.\n\t\t//\n\t\t// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY\n\t\t// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n\t\t// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n\t\t// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n\t\t// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n\t\t// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n\t\t// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n\t\t// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n\t\t// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n\t\t// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n\t\t// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\t\t//\n\t\t//----------------------------------------------------------------------------------\n\n\t\t#ifndef FXAA_DISCARD\n\t\t\t//\n\t\t\t// Only valid for PC OpenGL currently.\n\t\t\t// Probably will not work when FXAA_GREEN_AS_LUMA = 1.\n\t\t\t//\n\t\t\t// 1 = Use discard on pixels which don't need AA.\n\t\t\t// For APIs which enable concurrent TEX+ROP from same surface.\n\t\t\t// 0 = Return unchanged color on pixels which don't need AA.\n\t\t\t//\n\t\t\t#define FXAA_DISCARD 0\n\t\t#endif\n\n\t\t/*--------------------------------------------------------------------------*/\n\t\t#define FxaaTexTop(t, p) texture2D(t, p, -100.0)\n\t\t#define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), -100.0)\n\t\t/*--------------------------------------------------------------------------*/\n\n\t\t#define NUM_SAMPLES 5\n\n\t\t// assumes colors have premultipliedAlpha, so that the calculated color contrast is scaled by alpha\n\t\tfloat contrast( vec4 a, vec4 b ) {\n\t\t\tvec4 diff = abs( a - b );\n\t\t\treturn max( max( max( diff.r, diff.g ), diff.b ), diff.a );\n\t\t}\n\n\t\t/*============================================================================\n\n\t\t\t\t\t\t\t\t\tFXAA3 QUALITY - PC\n\n\t\t============================================================================*/\n\n\t\t/*--------------------------------------------------------------------------*/\n\t\tvec4 FxaaPixelShader(\n\t\t\tvec2 posM,\n\t\t\tsampler2D tex,\n\t\t\tvec2 fxaaQualityRcpFrame,\n\t\t\tfloat fxaaQualityEdgeThreshold,\n\t\t\tfloat fxaaQualityinvEdgeThreshold\n\t\t) {\n\t\t\tvec4 rgbaM = FxaaTexTop(tex, posM);\n\t\t\tvec4 rgbaS = FxaaTexOff(tex, posM, vec2( 0.0, 1.0), fxaaQualityRcpFrame.xy);\n\t\t\tvec4 rgbaE = FxaaTexOff(tex, posM, vec2( 1.0, 0.0), fxaaQualityRcpFrame.xy);\n\t\t\tvec4 rgbaN = FxaaTexOff(tex, posM, vec2( 0.0,-1.0), fxaaQualityRcpFrame.xy);\n\t\t\tvec4 rgbaW = FxaaTexOff(tex, posM, vec2(-1.0, 0.0), fxaaQualityRcpFrame.xy);\n\t\t\t// . S .\n\t\t\t// W M E\n\t\t\t// . N .\n\n\t\t\tbool earlyExit = max( max( max(\n\t\t\t\t\tcontrast( rgbaM, rgbaN ),\n\t\t\t\t\tcontrast( rgbaM, rgbaS ) ),\n\t\t\t\t\tcontrast( rgbaM, rgbaE ) ),\n\t\t\t\t\tcontrast( rgbaM, rgbaW ) )\n\t\t\t\t\t< fxaaQualityEdgeThreshold;\n\t\t\t// . 0 .\n\t\t\t// 0 0 0\n\t\t\t// . 0 .\n\n\t\t\t#if (FXAA_DISCARD == 1)\n\t\t\t\tif(earlyExit) FxaaDiscard;\n\t\t\t#else\n\t\t\t\tif(earlyExit) return rgbaM;\n\t\t\t#endif\n\n\t\t\tfloat contrastN = contrast( rgbaM, rgbaN );\n\t\t\tfloat contrastS = contrast( rgbaM, rgbaS );\n\t\t\tfloat contrastE = contrast( rgbaM, rgbaE );\n\t\t\tfloat contrastW = contrast( rgbaM, rgbaW );\n\n\t\t\tfloat relativeVContrast = ( contrastN + contrastS ) - ( contrastE + contrastW );\n\t\t\trelativeVContrast *= fxaaQualityinvEdgeThreshold;\n\n\t\t\tbool horzSpan = relativeVContrast > 0.;\n\t\t\t// . 1 .\n\t\t\t// 0 0 0\n\t\t\t// . 1 .\n\n\t\t\t// 45 deg edge detection and corners of objects, aka V/H contrast is too similar\n\t\t\tif( abs( relativeVContrast ) < .3 ) {\n\t\t\t\t// locate the edge\n\t\t\t\tvec2 dirToEdge;\n\t\t\t\tdirToEdge.x = contrastE > contrastW ? 1. : -1.;\n\t\t\t\tdirToEdge.y = contrastS > contrastN ? 1. : -1.;\n\t\t\t\t// . 2 . . 1 .\n\t\t\t\t// 1 0 2 ~= 0 0 1\n\t\t\t\t// . 1 . . 0 .\n\n\t\t\t\t// tap 2 pixels and see which ones are \"outside\" the edge, to\n\t\t\t\t// determine if the edge is vertical or horizontal\n\n\t\t\t\tvec4 rgbaAlongH = FxaaTexOff(tex, posM, vec2( dirToEdge.x, -dirToEdge.y ), fxaaQualityRcpFrame.xy);\n\t\t\t\tfloat matchAlongH = contrast( rgbaM, rgbaAlongH );\n\t\t\t\t// . 1 .\n\t\t\t\t// 0 0 1\n\t\t\t\t// . 0 H\n\n\t\t\t\tvec4 rgbaAlongV = FxaaTexOff(tex, posM, vec2( -dirToEdge.x, dirToEdge.y ), fxaaQualityRcpFrame.xy);\n\t\t\t\tfloat matchAlongV = contrast( rgbaM, rgbaAlongV );\n\t\t\t\t// V 1 .\n\t\t\t\t// 0 0 1\n\t\t\t\t// . 0 .\n\n\t\t\t\trelativeVContrast = matchAlongV - matchAlongH;\n\t\t\t\trelativeVContrast *= fxaaQualityinvEdgeThreshold;\n\n\t\t\t\tif( abs( relativeVContrast ) < .3 ) { // 45 deg edge\n\t\t\t\t\t// 1 1 .\n\t\t\t\t\t// 0 0 1\n\t\t\t\t\t// . 0 1\n\n\t\t\t\t\t// do a simple blur\n\t\t\t\t\treturn mix(\n\t\t\t\t\t\trgbaM,\n\t\t\t\t\t\t(rgbaN + rgbaS + rgbaE + rgbaW) * .25,\n\t\t\t\t\t\t.4\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\thorzSpan = relativeVContrast > 0.;\n\t\t\t}\n\n\t\t\tif(!horzSpan) rgbaN = rgbaW;\n\t\t\tif(!horzSpan) rgbaS = rgbaE;\n\t\t\t// . 0 . 1\n\t\t\t// 1 0 1 -> 0\n\t\t\t// . 0 . 1\n\n\t\t\tbool pairN = contrast( rgbaM, rgbaN ) > contrast( rgbaM, rgbaS );\n\t\t\tif(!pairN) rgbaN = rgbaS;\n\n\t\t\tvec2 offNP;\n\t\t\toffNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;\n\t\t\toffNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;\n\n\t\t\tbool doneN = false;\n\t\t\tbool doneP = false;\n\n\t\t\tfloat nDist = 0.;\n\t\t\tfloat pDist = 0.;\n\n\t\t\tvec2 posN = posM;\n\t\t\tvec2 posP = posM;\n\n\t\t\tint iterationsUsed = 0;\n\t\t\tint iterationsUsedN = 0;\n\t\t\tint iterationsUsedP = 0;\n\t\t\tfor( int i = 0; i < NUM_SAMPLES; i++ ) {\n\t\t\t\titerationsUsed = i;\n\n\t\t\t\tfloat increment = float(i + 1);\n\n\t\t\t\tif(!doneN) {\n\t\t\t\t\tnDist += increment;\n\t\t\t\t\tposN = posM + offNP * nDist;\n\t\t\t\t\tvec4 rgbaEndN = FxaaTexTop(tex, posN.xy);\n\t\t\t\t\tdoneN = contrast( rgbaEndN, rgbaM ) > contrast( rgbaEndN, rgbaN );\n\t\t\t\t\titerationsUsedN = i;\n\t\t\t\t}\n\n\t\t\t\tif(!doneP) {\n\t\t\t\t\tpDist += increment;\n\t\t\t\t\tposP = posM - offNP * pDist;\n\t\t\t\t\tvec4 rgbaEndP = FxaaTexTop(tex, posP.xy);\n\t\t\t\t\tdoneP = contrast( rgbaEndP, rgbaM ) > contrast( rgbaEndP, rgbaN );\n\t\t\t\t\titerationsUsedP = i;\n\t\t\t\t}\n\n\t\t\t\tif(doneN || doneP) break;\n\t\t\t}\n\n\n\t\t\tif ( !doneP && !doneN ) return rgbaM; // failed to find end of edge\n\n\t\t\tfloat dist = min(\n\t\t\t\tdoneN ? float( iterationsUsedN ) / float( NUM_SAMPLES - 1 ) : 1.,\n\t\t\t\tdoneP ? float( iterationsUsedP ) / float( NUM_SAMPLES - 1 ) : 1.\n\t\t\t);\n\n\t\t\t// hacky way of reduces blurriness of mostly diagonal edges\n\t\t\t// but reduces AA quality\n\t\t\tdist = pow(dist, .5);\n\n\t\t\tdist = 1. - dist;\n\n\t\t\treturn mix(\n\t\t\t\trgbaM,\n\t\t\t\trgbaN,\n\t\t\t\tdist * .5\n\t\t\t);\n\t\t}\n\n\t\tvoid main() {\n\t\t\tconst float edgeDetectionQuality = .2;\n\t\t\tconst float invEdgeDetectionQuality = 1. / edgeDetectionQuality;\n\n\t\t\tgl_FragColor = FxaaPixelShader(\n\t\t\t\tvUv,\n\t\t\t\ttDiffuse,\n\t\t\t\tresolution,\n\t\t\t\tedgeDetectionQuality, // [0,1] contrast needed, otherwise early discard\n\t\t\t\tinvEdgeDetectionQuality\n\t\t\t);\n\n\t\t}\n\t`\n\n};\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTYxLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFFZTs7QUFFZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxnQkFBZ0IsYUFBYTtBQUM3QixrQkFBa0IsV0FBVyxxREFBTzs7QUFFcEMsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0RBQWtEO0FBQ2xELGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLDBDQUEwQztBQUMxQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLG1CQUFtQixpQkFBaUI7QUFDcEM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7O0FBR0EseUNBQXlDOztBQUV6QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVzQiIsInNvdXJjZXMiOlsid2VicGFjazovL3RocmVlanMtcG9zdHByb2Nlc3MvLi9ub2RlX21vZHVsZXMvdGhyZWUvZXhhbXBsZXMvanNtL3NoYWRlcnMvRlhBQVNoYWRlci5qcz81ZjA4Il0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG5cdFZlY3RvcjJcbn0gZnJvbSAndGhyZWUnO1xuXG4vKipcbiAqIE5WSURJQSBGWEFBIGJ5IFRpbW90aHkgTG90dGVzXG4gKiBodHRwczovL2RldmVsb3Blci5kb3dubG9hZC5udmlkaWEuY29tL2Fzc2V0cy9nYW1lZGV2L2ZpbGVzL3Nkay8xMS9GWEFBX1doaXRlUGFwZXIucGRmXG4gKiAtIFdlYkdMIHBvcnQgYnkgQHN1cGVyZWdnYmVydFxuICogaHR0cDovL3d3dy5nbGdlLm9yZy9kZW1vcy9meGFhL1xuICogRnVydGhlciBpbXByb3ZlZCBieSBEYW5pZWwgU3R1cmtcbiAqL1xuXG5jb25zdCBGWEFBU2hhZGVyID0ge1xuXG5cdG5hbWU6ICdGWEFBU2hhZGVyJyxcblxuXHR1bmlmb3Jtczoge1xuXG5cdFx0J3REaWZmdXNlJzogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdCdyZXNvbHV0aW9uJzogeyB2YWx1ZTogbmV3IFZlY3RvcjIoIDEgLyAxMDI0LCAxIC8gNTEyICkgfVxuXG5cdH0sXG5cblx0dmVydGV4U2hhZGVyOiAvKiBnbHNsICovYFxuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0dlV2ID0gdXY7XG5cdFx0XHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XG5cblx0XHR9YCxcblxuXHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2Bcblx0XHRwcmVjaXNpb24gaGlnaHAgZmxvYXQ7XG5cblx0XHR1bmlmb3JtIHNhbXBsZXIyRCB0RGlmZnVzZTtcblxuXHRcdHVuaWZvcm0gdmVjMiByZXNvbHV0aW9uO1xuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblxuXHRcdC8vIEZYQUEgMy4xMSBpbXBsZW1lbnRhdGlvbiBieSBOVklESUEsIHBvcnRlZCB0byBXZWJHTCBieSBBZ29zdCBCaXJvIChiaXJvQGFyY2hpbG9naWMuY29tKVxuXG5cdFx0Ly8tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cdFx0Ly8gRmlsZTogICAgICAgIGVzMy1rZXBsZXJcXEZYQUFcXGFzc2V0c1xcc2hhZGVycy9GWEFBX0RlZmF1bHRFUy5mcmFnXG5cdFx0Ly8gU0RLIFZlcnNpb246IHYzLjAwXG5cdFx0Ly8gRW1haWw6ICAgICAgIGdhbWV3b3Jrc0BudmlkaWEuY29tXG5cdFx0Ly8gU2l0ZTogICAgICAgIGh0dHA6Ly9kZXZlbG9wZXIubnZpZGlhLmNvbS9cblx0XHQvL1xuXHRcdC8vIENvcHlyaWdodCAoYykgMjAxNC0yMDE1LCBOVklESUEgQ09SUE9SQVRJT04uIEFsbCByaWdodHMgcmVzZXJ2ZWQuXG5cdFx0Ly9cblx0XHQvLyBSZWRpc3RyaWJ1dGlvbiBhbmQgdXNlIGluIHNvdXJjZSBhbmQgYmluYXJ5IGZvcm1zLCB3aXRoIG9yIHdpdGhvdXRcblx0XHQvLyBtb2RpZmljYXRpb24sIGFyZSBwZXJtaXR0ZWQgcHJvdmlkZWQgdGhhdCB0aGUgZm9sbG93aW5nIGNvbmRpdGlvbnNcblx0XHQvLyBhcmUgbWV0OlxuXHRcdC8vICAqIFJlZGlzdHJpYnV0aW9ucyBvZiBzb3VyY2UgY29kZSBtdXN0IHJldGFpbiB0aGUgYWJvdmUgY29weXJpZ2h0XG5cdFx0Ly8gICAgbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyLlxuXHRcdC8vICAqIFJlZGlzdHJpYnV0aW9ucyBpbiBiaW5hcnkgZm9ybSBtdXN0IHJlcHJvZHVjZSB0aGUgYWJvdmUgY29weXJpZ2h0XG5cdFx0Ly8gICAgbm90aWNlLCB0aGlzIGxpc3Qgb2YgY29uZGl0aW9ucyBhbmQgdGhlIGZvbGxvd2luZyBkaXNjbGFpbWVyIGluIHRoZVxuXHRcdC8vICAgIGRvY3VtZW50YXRpb24gYW5kL29yIG90aGVyIG1hdGVyaWFscyBwcm92aWRlZCB3aXRoIHRoZSBkaXN0cmlidXRpb24uXG5cdFx0Ly8gICogTmVpdGhlciB0aGUgbmFtZSBvZiBOVklESUEgQ09SUE9SQVRJT04gbm9yIHRoZSBuYW1lcyBvZiBpdHNcblx0XHQvLyAgICBjb250cmlidXRvcnMgbWF5IGJlIHVzZWQgdG8gZW5kb3JzZSBvciBwcm9tb3RlIHByb2R1Y3RzIGRlcml2ZWRcblx0XHQvLyAgICBmcm9tIHRoaXMgc29mdHdhcmUgd2l0aG91dCBzcGVjaWZpYyBwcmlvciB3cml0dGVuIHBlcm1pc3Npb24uXG5cdFx0Ly9cblx0XHQvLyBUSElTIFNPRlRXQVJFIElTIFBST1ZJREVEIEJZIFRIRSBDT1BZUklHSFQgSE9MREVSUyAnJ0FTIElTJycgQU5EIEFOWVxuXHRcdC8vIEVYUFJFU1MgT1IgSU1QTElFRCBXQVJSQU5USUVTLCBJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTywgVEhFXG5cdFx0Ly8gSU1QTElFRCBXQVJSQU5USUVTIE9GIE1FUkNIQU5UQUJJTElUWSBBTkQgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSXG5cdFx0Ly8gUFVSUE9TRSBBUkUgRElTQ0xBSU1FRC4gIElOIE5PIEVWRU5UIFNIQUxMIFRIRSBDT1BZUklHSFQgT1dORVIgT1Jcblx0XHQvLyBDT05UUklCVVRPUlMgQkUgTElBQkxFIEZPUiBBTlkgRElSRUNULCBJTkRJUkVDVCwgSU5DSURFTlRBTCwgU1BFQ0lBTCxcblx0XHQvLyBFWEVNUExBUlksIE9SIENPTlNFUVVFTlRJQUwgREFNQUdFUyAoSU5DTFVESU5HLCBCVVQgTk9UIExJTUlURUQgVE8sXG5cdFx0Ly8gUFJPQ1VSRU1FTlQgT0YgU1VCU1RJVFVURSBHT09EUyBPUiBTRVJWSUNFUzsgTE9TUyBPRiBVU0UsIERBVEEsIE9SXG5cdFx0Ly8gUFJPRklUUzsgT1IgQlVTSU5FU1MgSU5URVJSVVBUSU9OKSBIT1dFVkVSIENBVVNFRCBBTkQgT04gQU5ZIFRIRU9SWVxuXHRcdC8vIE9GIExJQUJJTElUWSwgV0hFVEhFUiBJTiBDT05UUkFDVCwgU1RSSUNUIExJQUJJTElUWSwgT1IgVE9SVFxuXHRcdC8vIChJTkNMVURJTkcgTkVHTElHRU5DRSBPUiBPVEhFUldJU0UpIEFSSVNJTkcgSU4gQU5ZIFdBWSBPVVQgT0YgVEhFIFVTRVxuXHRcdC8vIE9GIFRISVMgU09GVFdBUkUsIEVWRU4gSUYgQURWSVNFRCBPRiBUSEUgUE9TU0lCSUxJVFkgT0YgU1VDSCBEQU1BR0UuXG5cdFx0Ly9cblx0XHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRcdCNpZm5kZWYgRlhBQV9ESVNDQVJEXG5cdFx0XHQvL1xuXHRcdFx0Ly8gT25seSB2YWxpZCBmb3IgUEMgT3BlbkdMIGN1cnJlbnRseS5cblx0XHRcdC8vIFByb2JhYmx5IHdpbGwgbm90IHdvcmsgd2hlbiBGWEFBX0dSRUVOX0FTX0xVTUEgPSAxLlxuXHRcdFx0Ly9cblx0XHRcdC8vIDEgPSBVc2UgZGlzY2FyZCBvbiBwaXhlbHMgd2hpY2ggZG9uJ3QgbmVlZCBBQS5cblx0XHRcdC8vICAgICBGb3IgQVBJcyB3aGljaCBlbmFibGUgY29uY3VycmVudCBURVgrUk9QIGZyb20gc2FtZSBzdXJmYWNlLlxuXHRcdFx0Ly8gMCA9IFJldHVybiB1bmNoYW5nZWQgY29sb3Igb24gcGl4ZWxzIHdoaWNoIGRvbid0IG5lZWQgQUEuXG5cdFx0XHQvL1xuXHRcdFx0I2RlZmluZSBGWEFBX0RJU0NBUkQgMFxuXHRcdCNlbmRpZlxuXG5cdFx0LyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cdFx0I2RlZmluZSBGeGFhVGV4VG9wKHQsIHApIHRleHR1cmUyRCh0LCBwLCAtMTAwLjApXG5cdFx0I2RlZmluZSBGeGFhVGV4T2ZmKHQsIHAsIG8sIHIpIHRleHR1cmUyRCh0LCBwICsgKG8gKiByKSwgLTEwMC4wKVxuXHRcdC8qLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0qL1xuXG5cdFx0I2RlZmluZSBOVU1fU0FNUExFUyA1XG5cblx0XHQvLyBhc3N1bWVzIGNvbG9ycyBoYXZlIHByZW11bHRpcGxpZWRBbHBoYSwgc28gdGhhdCB0aGUgY2FsY3VsYXRlZCBjb2xvciBjb250cmFzdCBpcyBzY2FsZWQgYnkgYWxwaGFcblx0XHRmbG9hdCBjb250cmFzdCggdmVjNCBhLCB2ZWM0IGIgKSB7XG5cdFx0XHR2ZWM0IGRpZmYgPSBhYnMoIGEgLSBiICk7XG5cdFx0XHRyZXR1cm4gbWF4KCBtYXgoIG1heCggZGlmZi5yLCBkaWZmLmcgKSwgZGlmZi5iICksIGRpZmYuYSApO1xuXHRcdH1cblxuXHRcdC8qPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5cdFx0XHRcdFx0XHRcdFx0XHRGWEFBMyBRVUFMSVRZIC0gUENcblxuXHRcdD09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT0qL1xuXG5cdFx0LyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cdFx0dmVjNCBGeGFhUGl4ZWxTaGFkZXIoXG5cdFx0XHR2ZWMyIHBvc00sXG5cdFx0XHRzYW1wbGVyMkQgdGV4LFxuXHRcdFx0dmVjMiBmeGFhUXVhbGl0eVJjcEZyYW1lLFxuXHRcdFx0ZmxvYXQgZnhhYVF1YWxpdHlFZGdlVGhyZXNob2xkLFxuXHRcdFx0ZmxvYXQgZnhhYVF1YWxpdHlpbnZFZGdlVGhyZXNob2xkXG5cdFx0KSB7XG5cdFx0XHR2ZWM0IHJnYmFNID0gRnhhYVRleFRvcCh0ZXgsIHBvc00pO1xuXHRcdFx0dmVjNCByZ2JhUyA9IEZ4YWFUZXhPZmYodGV4LCBwb3NNLCB2ZWMyKCAwLjAsIDEuMCksIGZ4YWFRdWFsaXR5UmNwRnJhbWUueHkpO1xuXHRcdFx0dmVjNCByZ2JhRSA9IEZ4YWFUZXhPZmYodGV4LCBwb3NNLCB2ZWMyKCAxLjAsIDAuMCksIGZ4YWFRdWFsaXR5UmNwRnJhbWUueHkpO1xuXHRcdFx0dmVjNCByZ2JhTiA9IEZ4YWFUZXhPZmYodGV4LCBwb3NNLCB2ZWMyKCAwLjAsLTEuMCksIGZ4YWFRdWFsaXR5UmNwRnJhbWUueHkpO1xuXHRcdFx0dmVjNCByZ2JhVyA9IEZ4YWFUZXhPZmYodGV4LCBwb3NNLCB2ZWMyKC0xLjAsIDAuMCksIGZ4YWFRdWFsaXR5UmNwRnJhbWUueHkpO1xuXHRcdFx0Ly8gLiBTIC5cblx0XHRcdC8vIFcgTSBFXG5cdFx0XHQvLyAuIE4gLlxuXG5cdFx0XHRib29sIGVhcmx5RXhpdCA9IG1heCggbWF4KCBtYXgoXG5cdFx0XHRcdFx0Y29udHJhc3QoIHJnYmFNLCByZ2JhTiApLFxuXHRcdFx0XHRcdGNvbnRyYXN0KCByZ2JhTSwgcmdiYVMgKSApLFxuXHRcdFx0XHRcdGNvbnRyYXN0KCByZ2JhTSwgcmdiYUUgKSApLFxuXHRcdFx0XHRcdGNvbnRyYXN0KCByZ2JhTSwgcmdiYVcgKSApXG5cdFx0XHRcdFx0PCBmeGFhUXVhbGl0eUVkZ2VUaHJlc2hvbGQ7XG5cdFx0XHQvLyAuIDAgLlxuXHRcdFx0Ly8gMCAwIDBcblx0XHRcdC8vIC4gMCAuXG5cblx0XHRcdCNpZiAoRlhBQV9ESVNDQVJEID09IDEpXG5cdFx0XHRcdGlmKGVhcmx5RXhpdCkgRnhhYURpc2NhcmQ7XG5cdFx0XHQjZWxzZVxuXHRcdFx0XHRpZihlYXJseUV4aXQpIHJldHVybiByZ2JhTTtcblx0XHRcdCNlbmRpZlxuXG5cdFx0XHRmbG9hdCBjb250cmFzdE4gPSBjb250cmFzdCggcmdiYU0sIHJnYmFOICk7XG5cdFx0XHRmbG9hdCBjb250cmFzdFMgPSBjb250cmFzdCggcmdiYU0sIHJnYmFTICk7XG5cdFx0XHRmbG9hdCBjb250cmFzdEUgPSBjb250cmFzdCggcmdiYU0sIHJnYmFFICk7XG5cdFx0XHRmbG9hdCBjb250cmFzdFcgPSBjb250cmFzdCggcmdiYU0sIHJnYmFXICk7XG5cblx0XHRcdGZsb2F0IHJlbGF0aXZlVkNvbnRyYXN0ID0gKCBjb250cmFzdE4gKyBjb250cmFzdFMgKSAtICggY29udHJhc3RFICsgY29udHJhc3RXICk7XG5cdFx0XHRyZWxhdGl2ZVZDb250cmFzdCAqPSBmeGFhUXVhbGl0eWludkVkZ2VUaHJlc2hvbGQ7XG5cblx0XHRcdGJvb2wgaG9yelNwYW4gPSByZWxhdGl2ZVZDb250cmFzdCA+IDAuO1xuXHRcdFx0Ly8gLiAxIC5cblx0XHRcdC8vIDAgMCAwXG5cdFx0XHQvLyAuIDEgLlxuXG5cdFx0XHQvLyA0NSBkZWcgZWRnZSBkZXRlY3Rpb24gYW5kIGNvcm5lcnMgb2Ygb2JqZWN0cywgYWthIFYvSCBjb250cmFzdCBpcyB0b28gc2ltaWxhclxuXHRcdFx0aWYoIGFicyggcmVsYXRpdmVWQ29udHJhc3QgKSA8IC4zICkge1xuXHRcdFx0XHQvLyBsb2NhdGUgdGhlIGVkZ2Vcblx0XHRcdFx0dmVjMiBkaXJUb0VkZ2U7XG5cdFx0XHRcdGRpclRvRWRnZS54ID0gY29udHJhc3RFID4gY29udHJhc3RXID8gMS4gOiAtMS47XG5cdFx0XHRcdGRpclRvRWRnZS55ID0gY29udHJhc3RTID4gY29udHJhc3ROID8gMS4gOiAtMS47XG5cdFx0XHRcdC8vIC4gMiAuICAgICAgLiAxIC5cblx0XHRcdFx0Ly8gMSAwIDIgIH49ICAwIDAgMVxuXHRcdFx0XHQvLyAuIDEgLiAgICAgIC4gMCAuXG5cblx0XHRcdFx0Ly8gdGFwIDIgcGl4ZWxzIGFuZCBzZWUgd2hpY2ggb25lcyBhcmUgXCJvdXRzaWRlXCIgdGhlIGVkZ2UsIHRvXG5cdFx0XHRcdC8vIGRldGVybWluZSBpZiB0aGUgZWRnZSBpcyB2ZXJ0aWNhbCBvciBob3Jpem9udGFsXG5cblx0XHRcdFx0dmVjNCByZ2JhQWxvbmdIID0gRnhhYVRleE9mZih0ZXgsIHBvc00sIHZlYzIoIGRpclRvRWRnZS54LCAtZGlyVG9FZGdlLnkgKSwgZnhhYVF1YWxpdHlSY3BGcmFtZS54eSk7XG5cdFx0XHRcdGZsb2F0IG1hdGNoQWxvbmdIID0gY29udHJhc3QoIHJnYmFNLCByZ2JhQWxvbmdIICk7XG5cdFx0XHRcdC8vIC4gMSAuXG5cdFx0XHRcdC8vIDAgMCAxXG5cdFx0XHRcdC8vIC4gMCBIXG5cblx0XHRcdFx0dmVjNCByZ2JhQWxvbmdWID0gRnhhYVRleE9mZih0ZXgsIHBvc00sIHZlYzIoIC1kaXJUb0VkZ2UueCwgZGlyVG9FZGdlLnkgKSwgZnhhYVF1YWxpdHlSY3BGcmFtZS54eSk7XG5cdFx0XHRcdGZsb2F0IG1hdGNoQWxvbmdWID0gY29udHJhc3QoIHJnYmFNLCByZ2JhQWxvbmdWICk7XG5cdFx0XHRcdC8vIFYgMSAuXG5cdFx0XHRcdC8vIDAgMCAxXG5cdFx0XHRcdC8vIC4gMCAuXG5cblx0XHRcdFx0cmVsYXRpdmVWQ29udHJhc3QgPSBtYXRjaEFsb25nViAtIG1hdGNoQWxvbmdIO1xuXHRcdFx0XHRyZWxhdGl2ZVZDb250cmFzdCAqPSBmeGFhUXVhbGl0eWludkVkZ2VUaHJlc2hvbGQ7XG5cblx0XHRcdFx0aWYoIGFicyggcmVsYXRpdmVWQ29udHJhc3QgKSA8IC4zICkgeyAvLyA0NSBkZWcgZWRnZVxuXHRcdFx0XHRcdC8vIDEgMSAuXG5cdFx0XHRcdFx0Ly8gMCAwIDFcblx0XHRcdFx0XHQvLyAuIDAgMVxuXG5cdFx0XHRcdFx0Ly8gZG8gYSBzaW1wbGUgYmx1clxuXHRcdFx0XHRcdHJldHVybiBtaXgoXG5cdFx0XHRcdFx0XHRyZ2JhTSxcblx0XHRcdFx0XHRcdChyZ2JhTiArIHJnYmFTICsgcmdiYUUgKyByZ2JhVykgKiAuMjUsXG5cdFx0XHRcdFx0XHQuNFxuXHRcdFx0XHRcdCk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRob3J6U3BhbiA9IHJlbGF0aXZlVkNvbnRyYXN0ID4gMC47XG5cdFx0XHR9XG5cblx0XHRcdGlmKCFob3J6U3BhbikgcmdiYU4gPSByZ2JhVztcblx0XHRcdGlmKCFob3J6U3BhbikgcmdiYVMgPSByZ2JhRTtcblx0XHRcdC8vIC4gMCAuICAgICAgMVxuXHRcdFx0Ly8gMSAwIDEgIC0+ICAwXG5cdFx0XHQvLyAuIDAgLiAgICAgIDFcblxuXHRcdFx0Ym9vbCBwYWlyTiA9IGNvbnRyYXN0KCByZ2JhTSwgcmdiYU4gKSA+IGNvbnRyYXN0KCByZ2JhTSwgcmdiYVMgKTtcblx0XHRcdGlmKCFwYWlyTikgcmdiYU4gPSByZ2JhUztcblxuXHRcdFx0dmVjMiBvZmZOUDtcblx0XHRcdG9mZk5QLnggPSAoIWhvcnpTcGFuKSA/IDAuMCA6IGZ4YWFRdWFsaXR5UmNwRnJhbWUueDtcblx0XHRcdG9mZk5QLnkgPSAoIGhvcnpTcGFuKSA/IDAuMCA6IGZ4YWFRdWFsaXR5UmNwRnJhbWUueTtcblxuXHRcdFx0Ym9vbCBkb25lTiA9IGZhbHNlO1xuXHRcdFx0Ym9vbCBkb25lUCA9IGZhbHNlO1xuXG5cdFx0XHRmbG9hdCBuRGlzdCA9IDAuO1xuXHRcdFx0ZmxvYXQgcERpc3QgPSAwLjtcblxuXHRcdFx0dmVjMiBwb3NOID0gcG9zTTtcblx0XHRcdHZlYzIgcG9zUCA9IHBvc007XG5cblx0XHRcdGludCBpdGVyYXRpb25zVXNlZCA9IDA7XG5cdFx0XHRpbnQgaXRlcmF0aW9uc1VzZWROID0gMDtcblx0XHRcdGludCBpdGVyYXRpb25zVXNlZFAgPSAwO1xuXHRcdFx0Zm9yKCBpbnQgaSA9IDA7IGkgPCBOVU1fU0FNUExFUzsgaSsrICkge1xuXHRcdFx0XHRpdGVyYXRpb25zVXNlZCA9IGk7XG5cblx0XHRcdFx0ZmxvYXQgaW5jcmVtZW50ID0gZmxvYXQoaSArIDEpO1xuXG5cdFx0XHRcdGlmKCFkb25lTikge1xuXHRcdFx0XHRcdG5EaXN0ICs9IGluY3JlbWVudDtcblx0XHRcdFx0XHRwb3NOID0gcG9zTSArIG9mZk5QICogbkRpc3Q7XG5cdFx0XHRcdFx0dmVjNCByZ2JhRW5kTiA9IEZ4YWFUZXhUb3AodGV4LCBwb3NOLnh5KTtcblx0XHRcdFx0XHRkb25lTiA9IGNvbnRyYXN0KCByZ2JhRW5kTiwgcmdiYU0gKSA+IGNvbnRyYXN0KCByZ2JhRW5kTiwgcmdiYU4gKTtcblx0XHRcdFx0XHRpdGVyYXRpb25zVXNlZE4gPSBpO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYoIWRvbmVQKSB7XG5cdFx0XHRcdFx0cERpc3QgKz0gaW5jcmVtZW50O1xuXHRcdFx0XHRcdHBvc1AgPSBwb3NNIC0gb2ZmTlAgKiBwRGlzdDtcblx0XHRcdFx0XHR2ZWM0IHJnYmFFbmRQID0gRnhhYVRleFRvcCh0ZXgsIHBvc1AueHkpO1xuXHRcdFx0XHRcdGRvbmVQID0gY29udHJhc3QoIHJnYmFFbmRQLCByZ2JhTSApID4gY29udHJhc3QoIHJnYmFFbmRQLCByZ2JhTiApO1xuXHRcdFx0XHRcdGl0ZXJhdGlvbnNVc2VkUCA9IGk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZihkb25lTiB8fCBkb25lUCkgYnJlYWs7XG5cdFx0XHR9XG5cblxuXHRcdFx0aWYgKCAhZG9uZVAgJiYgIWRvbmVOICkgcmV0dXJuIHJnYmFNOyAvLyBmYWlsZWQgdG8gZmluZCBlbmQgb2YgZWRnZVxuXG5cdFx0XHRmbG9hdCBkaXN0ID0gbWluKFxuXHRcdFx0XHRkb25lTiA/IGZsb2F0KCBpdGVyYXRpb25zVXNlZE4gKSAvIGZsb2F0KCBOVU1fU0FNUExFUyAtIDEgKSA6IDEuLFxuXHRcdFx0XHRkb25lUCA/IGZsb2F0KCBpdGVyYXRpb25zVXNlZFAgKSAvIGZsb2F0KCBOVU1fU0FNUExFUyAtIDEgKSA6IDEuXG5cdFx0XHQpO1xuXG5cdFx0XHQvLyBoYWNreSB3YXkgb2YgcmVkdWNlcyBibHVycmluZXNzIG9mIG1vc3RseSBkaWFnb25hbCBlZGdlc1xuXHRcdFx0Ly8gYnV0IHJlZHVjZXMgQUEgcXVhbGl0eVxuXHRcdFx0ZGlzdCA9IHBvdyhkaXN0LCAuNSk7XG5cblx0XHRcdGRpc3QgPSAxLiAtIGRpc3Q7XG5cblx0XHRcdHJldHVybiBtaXgoXG5cdFx0XHRcdHJnYmFNLFxuXHRcdFx0XHRyZ2JhTixcblx0XHRcdFx0ZGlzdCAqIC41XG5cdFx0XHQpO1xuXHRcdH1cblxuXHRcdHZvaWQgbWFpbigpIHtcblx0XHRcdGNvbnN0IGZsb2F0IGVkZ2VEZXRlY3Rpb25RdWFsaXR5ID0gLjI7XG5cdFx0XHRjb25zdCBmbG9hdCBpbnZFZGdlRGV0ZWN0aW9uUXVhbGl0eSA9IDEuIC8gZWRnZURldGVjdGlvblF1YWxpdHk7XG5cblx0XHRcdGdsX0ZyYWdDb2xvciA9IEZ4YWFQaXhlbFNoYWRlcihcblx0XHRcdFx0dlV2LFxuXHRcdFx0XHR0RGlmZnVzZSxcblx0XHRcdFx0cmVzb2x1dGlvbixcblx0XHRcdFx0ZWRnZURldGVjdGlvblF1YWxpdHksIC8vIFswLDFdIGNvbnRyYXN0IG5lZWRlZCwgb3RoZXJ3aXNlIGVhcmx5IGRpc2NhcmRcblx0XHRcdFx0aW52RWRnZURldGVjdGlvblF1YWxpdHlcblx0XHRcdCk7XG5cblx0XHR9XG5cdGBcblxufTtcblxuZXhwb3J0IHsgRlhBQVNoYWRlciB9O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///161\n")}}]); \ No newline at end of file +"use strict";(self.webpackChunkthreejs_postprocess=self.webpackChunkthreejs_postprocess||[]).push([[121],{418:module=>{eval("\n\nvar has = Object.prototype.hasOwnProperty\n , prefix = '~';\n\n/**\n * Constructor to create a storage for our `EE` objects.\n * An `Events` instance is a plain object whose properties are event names.\n *\n * @constructor\n * @private\n */\nfunction Events() {}\n\n//\n// We try to not inherit from `Object.prototype`. In some engines creating an\n// instance in this way is faster than calling `Object.create(null)` directly.\n// If `Object.create(null)` is not supported we prefix the event names with a\n// character to make sure that the built-in object properties are not\n// overridden or used as an attack vector.\n//\nif (Object.create) {\n Events.prototype = Object.create(null);\n\n //\n // This hack is needed because the `__proto__` property is still inherited in\n // some old browsers like Android 4, iPhone 5.1, Opera 11 and Safari 5.\n //\n if (!new Events().__proto__) prefix = false;\n}\n\n/**\n * Representation of a single event listener.\n *\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} [once=false] Specify if the listener is a one-time listener.\n * @constructor\n * @private\n */\nfunction EE(fn, context, once) {\n this.fn = fn;\n this.context = context;\n this.once = once || false;\n}\n\n/**\n * Add a listener for a given event.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} context The context to invoke the listener with.\n * @param {Boolean} once Specify if the listener is a one-time listener.\n * @returns {EventEmitter}\n * @private\n */\nfunction addListener(emitter, event, fn, context, once) {\n if (typeof fn !== 'function') {\n throw new TypeError('The listener must be a function');\n }\n\n var listener = new EE(fn, context || emitter, once)\n , evt = prefix ? prefix + event : event;\n\n if (!emitter._events[evt]) emitter._events[evt] = listener, emitter._eventsCount++;\n else if (!emitter._events[evt].fn) emitter._events[evt].push(listener);\n else emitter._events[evt] = [emitter._events[evt], listener];\n\n return emitter;\n}\n\n/**\n * Clear event by name.\n *\n * @param {EventEmitter} emitter Reference to the `EventEmitter` instance.\n * @param {(String|Symbol)} evt The Event name.\n * @private\n */\nfunction clearEvent(emitter, evt) {\n if (--emitter._eventsCount === 0) emitter._events = new Events();\n else delete emitter._events[evt];\n}\n\n/**\n * Minimal `EventEmitter` interface that is molded against the Node.js\n * `EventEmitter` interface.\n *\n * @constructor\n * @public\n */\nfunction EventEmitter() {\n this._events = new Events();\n this._eventsCount = 0;\n}\n\n/**\n * Return an array listing the events for which the emitter has registered\n * listeners.\n *\n * @returns {Array}\n * @public\n */\nEventEmitter.prototype.eventNames = function eventNames() {\n var names = []\n , events\n , name;\n\n if (this._eventsCount === 0) return names;\n\n for (name in (events = this._events)) {\n if (has.call(events, name)) names.push(prefix ? name.slice(1) : name);\n }\n\n if (Object.getOwnPropertySymbols) {\n return names.concat(Object.getOwnPropertySymbols(events));\n }\n\n return names;\n};\n\n/**\n * Return the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Array} The registered listeners.\n * @public\n */\nEventEmitter.prototype.listeners = function listeners(event) {\n var evt = prefix ? prefix + event : event\n , handlers = this._events[evt];\n\n if (!handlers) return [];\n if (handlers.fn) return [handlers.fn];\n\n for (var i = 0, l = handlers.length, ee = new Array(l); i < l; i++) {\n ee[i] = handlers[i].fn;\n }\n\n return ee;\n};\n\n/**\n * Return the number of listeners listening to a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Number} The number of listeners.\n * @public\n */\nEventEmitter.prototype.listenerCount = function listenerCount(event) {\n var evt = prefix ? prefix + event : event\n , listeners = this._events[evt];\n\n if (!listeners) return 0;\n if (listeners.fn) return 1;\n return listeners.length;\n};\n\n/**\n * Calls each of the listeners registered for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @returns {Boolean} `true` if the event had listeners, else `false`.\n * @public\n */\nEventEmitter.prototype.emit = function emit(event, a1, a2, a3, a4, a5) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return false;\n\n var listeners = this._events[evt]\n , len = arguments.length\n , args\n , i;\n\n if (listeners.fn) {\n if (listeners.once) this.removeListener(event, listeners.fn, undefined, true);\n\n switch (len) {\n case 1: return listeners.fn.call(listeners.context), true;\n case 2: return listeners.fn.call(listeners.context, a1), true;\n case 3: return listeners.fn.call(listeners.context, a1, a2), true;\n case 4: return listeners.fn.call(listeners.context, a1, a2, a3), true;\n case 5: return listeners.fn.call(listeners.context, a1, a2, a3, a4), true;\n case 6: return listeners.fn.call(listeners.context, a1, a2, a3, a4, a5), true;\n }\n\n for (i = 1, args = new Array(len -1); i < len; i++) {\n args[i - 1] = arguments[i];\n }\n\n listeners.fn.apply(listeners.context, args);\n } else {\n var length = listeners.length\n , j;\n\n for (i = 0; i < length; i++) {\n if (listeners[i].once) this.removeListener(event, listeners[i].fn, undefined, true);\n\n switch (len) {\n case 1: listeners[i].fn.call(listeners[i].context); break;\n case 2: listeners[i].fn.call(listeners[i].context, a1); break;\n case 3: listeners[i].fn.call(listeners[i].context, a1, a2); break;\n case 4: listeners[i].fn.call(listeners[i].context, a1, a2, a3); break;\n default:\n if (!args) for (j = 1, args = new Array(len -1); j < len; j++) {\n args[j - 1] = arguments[j];\n }\n\n listeners[i].fn.apply(listeners[i].context, args);\n }\n }\n }\n\n return true;\n};\n\n/**\n * Add a listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.on = function on(event, fn, context) {\n return addListener(this, event, fn, context, false);\n};\n\n/**\n * Add a one-time listener for a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn The listener function.\n * @param {*} [context=this] The context to invoke the listener with.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.once = function once(event, fn, context) {\n return addListener(this, event, fn, context, true);\n};\n\n/**\n * Remove the listeners of a given event.\n *\n * @param {(String|Symbol)} event The event name.\n * @param {Function} fn Only remove the listeners that match this function.\n * @param {*} context Only remove the listeners that have this context.\n * @param {Boolean} once Only remove one-time listeners.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeListener = function removeListener(event, fn, context, once) {\n var evt = prefix ? prefix + event : event;\n\n if (!this._events[evt]) return this;\n if (!fn) {\n clearEvent(this, evt);\n return this;\n }\n\n var listeners = this._events[evt];\n\n if (listeners.fn) {\n if (\n listeners.fn === fn &&\n (!once || listeners.once) &&\n (!context || listeners.context === context)\n ) {\n clearEvent(this, evt);\n }\n } else {\n for (var i = 0, events = [], length = listeners.length; i < length; i++) {\n if (\n listeners[i].fn !== fn ||\n (once && !listeners[i].once) ||\n (context && listeners[i].context !== context)\n ) {\n events.push(listeners[i]);\n }\n }\n\n //\n // Reset the array, or remove it completely if we have no more listeners.\n //\n if (events.length) this._events[evt] = events.length === 1 ? events[0] : events;\n else clearEvent(this, evt);\n }\n\n return this;\n};\n\n/**\n * Remove all listeners, or those of the specified event.\n *\n * @param {(String|Symbol)} [event] The event name.\n * @returns {EventEmitter} `this`.\n * @public\n */\nEventEmitter.prototype.removeAllListeners = function removeAllListeners(event) {\n var evt;\n\n if (event) {\n evt = prefix ? prefix + event : event;\n if (this._events[evt]) clearEvent(this, evt);\n } else {\n this._events = new Events();\n this._eventsCount = 0;\n }\n\n return this;\n};\n\n//\n// Alias methods names because people roll like that.\n//\nEventEmitter.prototype.off = EventEmitter.prototype.removeListener;\nEventEmitter.prototype.addListener = EventEmitter.prototype.on;\n\n//\n// Expose the prefix.\n//\nEventEmitter.prefixed = prefix;\n\n//\n// Allow `EventEmitter` to be imported as module namespace.\n//\nEventEmitter.EventEmitter = EventEmitter;\n\n//\n// Expose the module.\n//\nif (true) {\n module.exports = EventEmitter;\n}\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNDE4LmpzIiwibWFwcGluZ3MiOiJBQUFhOztBQUViO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsVUFBVTtBQUNyQixXQUFXLEdBQUc7QUFDZCxXQUFXLFNBQVM7QUFDcEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGNBQWM7QUFDekIsV0FBVyxpQkFBaUI7QUFDNUIsV0FBVyxVQUFVO0FBQ3JCLFdBQVcsR0FBRztBQUNkLFdBQVcsU0FBUztBQUNwQixhQUFhO0FBQ2I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxjQUFjO0FBQ3pCLFdBQVcsaUJBQWlCO0FBQzVCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUIsYUFBYSxPQUFPO0FBQ3BCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSwwREFBMEQsT0FBTztBQUNqRTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUIsYUFBYSxRQUFRO0FBQ3JCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUIsYUFBYSxTQUFTO0FBQ3RCO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSwwQ0FBMEMsU0FBUztBQUNuRDtBQUNBOztBQUVBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUEsZ0JBQWdCLFlBQVk7QUFDNUI7O0FBRUE7QUFDQSw0REFBNEQ7QUFDNUQsZ0VBQWdFO0FBQ2hFLG9FQUFvRTtBQUNwRSx3RUFBd0U7QUFDeEU7QUFDQSwyREFBMkQsU0FBUztBQUNwRTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsV0FBVyxpQkFBaUI7QUFDNUIsV0FBVyxVQUFVO0FBQ3JCLFdBQVcsR0FBRztBQUNkLGFBQWEsY0FBYztBQUMzQjtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFdBQVcsaUJBQWlCO0FBQzVCLFdBQVcsVUFBVTtBQUNyQixXQUFXLEdBQUc7QUFDZCxhQUFhLGNBQWM7QUFDM0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGlCQUFpQjtBQUM1QixXQUFXLFVBQVU7QUFDckIsV0FBVyxHQUFHO0FBQ2QsV0FBVyxTQUFTO0FBQ3BCLGFBQWEsY0FBYztBQUMzQjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0osNERBQTRELFlBQVk7QUFDeEU7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxXQUFXLGlCQUFpQjtBQUM1QixhQUFhLGNBQWM7QUFDM0I7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSSxJQUE2QjtBQUNqQztBQUNBIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy9ldmVudGVtaXR0ZXIzL2luZGV4LmpzPzcwMmUiXSwic291cmNlc0NvbnRlbnQiOlsiJ3VzZSBzdHJpY3QnO1xuXG52YXIgaGFzID0gT2JqZWN0LnByb3RvdHlwZS5oYXNPd25Qcm9wZXJ0eVxuICAsIHByZWZpeCA9ICd+JztcblxuLyoqXG4gKiBDb25zdHJ1Y3RvciB0byBjcmVhdGUgYSBzdG9yYWdlIGZvciBvdXIgYEVFYCBvYmplY3RzLlxuICogQW4gYEV2ZW50c2AgaW5zdGFuY2UgaXMgYSBwbGFpbiBvYmplY3Qgd2hvc2UgcHJvcGVydGllcyBhcmUgZXZlbnQgbmFtZXMuXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBFdmVudHMoKSB7fVxuXG4vL1xuLy8gV2UgdHJ5IHRvIG5vdCBpbmhlcml0IGZyb20gYE9iamVjdC5wcm90b3R5cGVgLiBJbiBzb21lIGVuZ2luZXMgY3JlYXRpbmcgYW5cbi8vIGluc3RhbmNlIGluIHRoaXMgd2F5IGlzIGZhc3RlciB0aGFuIGNhbGxpbmcgYE9iamVjdC5jcmVhdGUobnVsbClgIGRpcmVjdGx5LlxuLy8gSWYgYE9iamVjdC5jcmVhdGUobnVsbClgIGlzIG5vdCBzdXBwb3J0ZWQgd2UgcHJlZml4IHRoZSBldmVudCBuYW1lcyB3aXRoIGFcbi8vIGNoYXJhY3RlciB0byBtYWtlIHN1cmUgdGhhdCB0aGUgYnVpbHQtaW4gb2JqZWN0IHByb3BlcnRpZXMgYXJlIG5vdFxuLy8gb3ZlcnJpZGRlbiBvciB1c2VkIGFzIGFuIGF0dGFjayB2ZWN0b3IuXG4vL1xuaWYgKE9iamVjdC5jcmVhdGUpIHtcbiAgRXZlbnRzLnByb3RvdHlwZSA9IE9iamVjdC5jcmVhdGUobnVsbCk7XG5cbiAgLy9cbiAgLy8gVGhpcyBoYWNrIGlzIG5lZWRlZCBiZWNhdXNlIHRoZSBgX19wcm90b19fYCBwcm9wZXJ0eSBpcyBzdGlsbCBpbmhlcml0ZWQgaW5cbiAgLy8gc29tZSBvbGQgYnJvd3NlcnMgbGlrZSBBbmRyb2lkIDQsIGlQaG9uZSA1LjEsIE9wZXJhIDExIGFuZCBTYWZhcmkgNS5cbiAgLy9cbiAgaWYgKCFuZXcgRXZlbnRzKCkuX19wcm90b19fKSBwcmVmaXggPSBmYWxzZTtcbn1cblxuLyoqXG4gKiBSZXByZXNlbnRhdGlvbiBvZiBhIHNpbmdsZSBldmVudCBsaXN0ZW5lci5cbiAqXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBUaGUgbGlzdGVuZXIgZnVuY3Rpb24uXG4gKiBAcGFyYW0geyp9IGNvbnRleHQgVGhlIGNvbnRleHQgdG8gaW52b2tlIHRoZSBsaXN0ZW5lciB3aXRoLlxuICogQHBhcmFtIHtCb29sZWFufSBbb25jZT1mYWxzZV0gU3BlY2lmeSBpZiB0aGUgbGlzdGVuZXIgaXMgYSBvbmUtdGltZSBsaXN0ZW5lci5cbiAqIEBjb25zdHJ1Y3RvclxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gRUUoZm4sIGNvbnRleHQsIG9uY2UpIHtcbiAgdGhpcy5mbiA9IGZuO1xuICB0aGlzLmNvbnRleHQgPSBjb250ZXh0O1xuICB0aGlzLm9uY2UgPSBvbmNlIHx8IGZhbHNlO1xufVxuXG4vKipcbiAqIEFkZCBhIGxpc3RlbmVyIGZvciBhIGdpdmVuIGV2ZW50LlxuICpcbiAqIEBwYXJhbSB7RXZlbnRFbWl0dGVyfSBlbWl0dGVyIFJlZmVyZW5jZSB0byB0aGUgYEV2ZW50RW1pdHRlcmAgaW5zdGFuY2UuXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZlbnQgVGhlIGV2ZW50IG5hbWUuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBUaGUgbGlzdGVuZXIgZnVuY3Rpb24uXG4gKiBAcGFyYW0geyp9IGNvbnRleHQgVGhlIGNvbnRleHQgdG8gaW52b2tlIHRoZSBsaXN0ZW5lciB3aXRoLlxuICogQHBhcmFtIHtCb29sZWFufSBvbmNlIFNwZWNpZnkgaWYgdGhlIGxpc3RlbmVyIGlzIGEgb25lLXRpbWUgbGlzdGVuZXIuXG4gKiBAcmV0dXJucyB7RXZlbnRFbWl0dGVyfVxuICogQHByaXZhdGVcbiAqL1xuZnVuY3Rpb24gYWRkTGlzdGVuZXIoZW1pdHRlciwgZXZlbnQsIGZuLCBjb250ZXh0LCBvbmNlKSB7XG4gIGlmICh0eXBlb2YgZm4gIT09ICdmdW5jdGlvbicpIHtcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKCdUaGUgbGlzdGVuZXIgbXVzdCBiZSBhIGZ1bmN0aW9uJyk7XG4gIH1cblxuICB2YXIgbGlzdGVuZXIgPSBuZXcgRUUoZm4sIGNvbnRleHQgfHwgZW1pdHRlciwgb25jZSlcbiAgICAsIGV2dCA9IHByZWZpeCA/IHByZWZpeCArIGV2ZW50IDogZXZlbnQ7XG5cbiAgaWYgKCFlbWl0dGVyLl9ldmVudHNbZXZ0XSkgZW1pdHRlci5fZXZlbnRzW2V2dF0gPSBsaXN0ZW5lciwgZW1pdHRlci5fZXZlbnRzQ291bnQrKztcbiAgZWxzZSBpZiAoIWVtaXR0ZXIuX2V2ZW50c1tldnRdLmZuKSBlbWl0dGVyLl9ldmVudHNbZXZ0XS5wdXNoKGxpc3RlbmVyKTtcbiAgZWxzZSBlbWl0dGVyLl9ldmVudHNbZXZ0XSA9IFtlbWl0dGVyLl9ldmVudHNbZXZ0XSwgbGlzdGVuZXJdO1xuXG4gIHJldHVybiBlbWl0dGVyO1xufVxuXG4vKipcbiAqIENsZWFyIGV2ZW50IGJ5IG5hbWUuXG4gKlxuICogQHBhcmFtIHtFdmVudEVtaXR0ZXJ9IGVtaXR0ZXIgUmVmZXJlbmNlIHRvIHRoZSBgRXZlbnRFbWl0dGVyYCBpbnN0YW5jZS5cbiAqIEBwYXJhbSB7KFN0cmluZ3xTeW1ib2wpfSBldnQgVGhlIEV2ZW50IG5hbWUuXG4gKiBAcHJpdmF0ZVxuICovXG5mdW5jdGlvbiBjbGVhckV2ZW50KGVtaXR0ZXIsIGV2dCkge1xuICBpZiAoLS1lbWl0dGVyLl9ldmVudHNDb3VudCA9PT0gMCkgZW1pdHRlci5fZXZlbnRzID0gbmV3IEV2ZW50cygpO1xuICBlbHNlIGRlbGV0ZSBlbWl0dGVyLl9ldmVudHNbZXZ0XTtcbn1cblxuLyoqXG4gKiBNaW5pbWFsIGBFdmVudEVtaXR0ZXJgIGludGVyZmFjZSB0aGF0IGlzIG1vbGRlZCBhZ2FpbnN0IHRoZSBOb2RlLmpzXG4gKiBgRXZlbnRFbWl0dGVyYCBpbnRlcmZhY2UuXG4gKlxuICogQGNvbnN0cnVjdG9yXG4gKiBAcHVibGljXG4gKi9cbmZ1bmN0aW9uIEV2ZW50RW1pdHRlcigpIHtcbiAgdGhpcy5fZXZlbnRzID0gbmV3IEV2ZW50cygpO1xuICB0aGlzLl9ldmVudHNDb3VudCA9IDA7XG59XG5cbi8qKlxuICogUmV0dXJuIGFuIGFycmF5IGxpc3RpbmcgdGhlIGV2ZW50cyBmb3Igd2hpY2ggdGhlIGVtaXR0ZXIgaGFzIHJlZ2lzdGVyZWRcbiAqIGxpc3RlbmVycy5cbiAqXG4gKiBAcmV0dXJucyB7QXJyYXl9XG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuZXZlbnROYW1lcyA9IGZ1bmN0aW9uIGV2ZW50TmFtZXMoKSB7XG4gIHZhciBuYW1lcyA9IFtdXG4gICAgLCBldmVudHNcbiAgICAsIG5hbWU7XG5cbiAgaWYgKHRoaXMuX2V2ZW50c0NvdW50ID09PSAwKSByZXR1cm4gbmFtZXM7XG5cbiAgZm9yIChuYW1lIGluIChldmVudHMgPSB0aGlzLl9ldmVudHMpKSB7XG4gICAgaWYgKGhhcy5jYWxsKGV2ZW50cywgbmFtZSkpIG5hbWVzLnB1c2gocHJlZml4ID8gbmFtZS5zbGljZSgxKSA6IG5hbWUpO1xuICB9XG5cbiAgaWYgKE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMpIHtcbiAgICByZXR1cm4gbmFtZXMuY29uY2F0KE9iamVjdC5nZXRPd25Qcm9wZXJ0eVN5bWJvbHMoZXZlbnRzKSk7XG4gIH1cblxuICByZXR1cm4gbmFtZXM7XG59O1xuXG4vKipcbiAqIFJldHVybiB0aGUgbGlzdGVuZXJzIHJlZ2lzdGVyZWQgZm9yIGEgZ2l2ZW4gZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHJldHVybnMge0FycmF5fSBUaGUgcmVnaXN0ZXJlZCBsaXN0ZW5lcnMuXG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUubGlzdGVuZXJzID0gZnVuY3Rpb24gbGlzdGVuZXJzKGV2ZW50KSB7XG4gIHZhciBldnQgPSBwcmVmaXggPyBwcmVmaXggKyBldmVudCA6IGV2ZW50XG4gICAgLCBoYW5kbGVycyA9IHRoaXMuX2V2ZW50c1tldnRdO1xuXG4gIGlmICghaGFuZGxlcnMpIHJldHVybiBbXTtcbiAgaWYgKGhhbmRsZXJzLmZuKSByZXR1cm4gW2hhbmRsZXJzLmZuXTtcblxuICBmb3IgKHZhciBpID0gMCwgbCA9IGhhbmRsZXJzLmxlbmd0aCwgZWUgPSBuZXcgQXJyYXkobCk7IGkgPCBsOyBpKyspIHtcbiAgICBlZVtpXSA9IGhhbmRsZXJzW2ldLmZuO1xuICB9XG5cbiAgcmV0dXJuIGVlO1xufTtcblxuLyoqXG4gKiBSZXR1cm4gdGhlIG51bWJlciBvZiBsaXN0ZW5lcnMgbGlzdGVuaW5nIHRvIGEgZ2l2ZW4gZXZlbnQuXG4gKlxuICogQHBhcmFtIHsoU3RyaW5nfFN5bWJvbCl9IGV2ZW50IFRoZSBldmVudCBuYW1lLlxuICogQHJldHVybnMge051bWJlcn0gVGhlIG51bWJlciBvZiBsaXN0ZW5lcnMuXG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUubGlzdGVuZXJDb3VudCA9IGZ1bmN0aW9uIGxpc3RlbmVyQ291bnQoZXZlbnQpIHtcbiAgdmFyIGV2dCA9IHByZWZpeCA/IHByZWZpeCArIGV2ZW50IDogZXZlbnRcbiAgICAsIGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50c1tldnRdO1xuXG4gIGlmICghbGlzdGVuZXJzKSByZXR1cm4gMDtcbiAgaWYgKGxpc3RlbmVycy5mbikgcmV0dXJuIDE7XG4gIHJldHVybiBsaXN0ZW5lcnMubGVuZ3RoO1xufTtcblxuLyoqXG4gKiBDYWxscyBlYWNoIG9mIHRoZSBsaXN0ZW5lcnMgcmVnaXN0ZXJlZCBmb3IgYSBnaXZlbiBldmVudC5cbiAqXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZlbnQgVGhlIGV2ZW50IG5hbWUuXG4gKiBAcmV0dXJucyB7Qm9vbGVhbn0gYHRydWVgIGlmIHRoZSBldmVudCBoYWQgbGlzdGVuZXJzLCBlbHNlIGBmYWxzZWAuXG4gKiBAcHVibGljXG4gKi9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuZW1pdCA9IGZ1bmN0aW9uIGVtaXQoZXZlbnQsIGExLCBhMiwgYTMsIGE0LCBhNSkge1xuICB2YXIgZXZ0ID0gcHJlZml4ID8gcHJlZml4ICsgZXZlbnQgOiBldmVudDtcblxuICBpZiAoIXRoaXMuX2V2ZW50c1tldnRdKSByZXR1cm4gZmFsc2U7XG5cbiAgdmFyIGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50c1tldnRdXG4gICAgLCBsZW4gPSBhcmd1bWVudHMubGVuZ3RoXG4gICAgLCBhcmdzXG4gICAgLCBpO1xuXG4gIGlmIChsaXN0ZW5lcnMuZm4pIHtcbiAgICBpZiAobGlzdGVuZXJzLm9uY2UpIHRoaXMucmVtb3ZlTGlzdGVuZXIoZXZlbnQsIGxpc3RlbmVycy5mbiwgdW5kZWZpbmVkLCB0cnVlKTtcblxuICAgIHN3aXRjaCAobGVuKSB7XG4gICAgICBjYXNlIDE6IHJldHVybiBsaXN0ZW5lcnMuZm4uY2FsbChsaXN0ZW5lcnMuY29udGV4dCksIHRydWU7XG4gICAgICBjYXNlIDI6IHJldHVybiBsaXN0ZW5lcnMuZm4uY2FsbChsaXN0ZW5lcnMuY29udGV4dCwgYTEpLCB0cnVlO1xuICAgICAgY2FzZSAzOiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQsIGExLCBhMiksIHRydWU7XG4gICAgICBjYXNlIDQ6IHJldHVybiBsaXN0ZW5lcnMuZm4uY2FsbChsaXN0ZW5lcnMuY29udGV4dCwgYTEsIGEyLCBhMyksIHRydWU7XG4gICAgICBjYXNlIDU6IHJldHVybiBsaXN0ZW5lcnMuZm4uY2FsbChsaXN0ZW5lcnMuY29udGV4dCwgYTEsIGEyLCBhMywgYTQpLCB0cnVlO1xuICAgICAgY2FzZSA2OiByZXR1cm4gbGlzdGVuZXJzLmZuLmNhbGwobGlzdGVuZXJzLmNvbnRleHQsIGExLCBhMiwgYTMsIGE0LCBhNSksIHRydWU7XG4gICAgfVxuXG4gICAgZm9yIChpID0gMSwgYXJncyA9IG5ldyBBcnJheShsZW4gLTEpOyBpIDwgbGVuOyBpKyspIHtcbiAgICAgIGFyZ3NbaSAtIDFdID0gYXJndW1lbnRzW2ldO1xuICAgIH1cblxuICAgIGxpc3RlbmVycy5mbi5hcHBseShsaXN0ZW5lcnMuY29udGV4dCwgYXJncyk7XG4gIH0gZWxzZSB7XG4gICAgdmFyIGxlbmd0aCA9IGxpc3RlbmVycy5sZW5ndGhcbiAgICAgICwgajtcblxuICAgIGZvciAoaSA9IDA7IGkgPCBsZW5ndGg7IGkrKykge1xuICAgICAgaWYgKGxpc3RlbmVyc1tpXS5vbmNlKSB0aGlzLnJlbW92ZUxpc3RlbmVyKGV2ZW50LCBsaXN0ZW5lcnNbaV0uZm4sIHVuZGVmaW5lZCwgdHJ1ZSk7XG5cbiAgICAgIHN3aXRjaCAobGVuKSB7XG4gICAgICAgIGNhc2UgMTogbGlzdGVuZXJzW2ldLmZuLmNhbGwobGlzdGVuZXJzW2ldLmNvbnRleHQpOyBicmVhaztcbiAgICAgICAgY2FzZSAyOiBsaXN0ZW5lcnNbaV0uZm4uY2FsbChsaXN0ZW5lcnNbaV0uY29udGV4dCwgYTEpOyBicmVhaztcbiAgICAgICAgY2FzZSAzOiBsaXN0ZW5lcnNbaV0uZm4uY2FsbChsaXN0ZW5lcnNbaV0uY29udGV4dCwgYTEsIGEyKTsgYnJlYWs7XG4gICAgICAgIGNhc2UgNDogbGlzdGVuZXJzW2ldLmZuLmNhbGwobGlzdGVuZXJzW2ldLmNvbnRleHQsIGExLCBhMiwgYTMpOyBicmVhaztcbiAgICAgICAgZGVmYXVsdDpcbiAgICAgICAgICBpZiAoIWFyZ3MpIGZvciAoaiA9IDEsIGFyZ3MgPSBuZXcgQXJyYXkobGVuIC0xKTsgaiA8IGxlbjsgaisrKSB7XG4gICAgICAgICAgICBhcmdzW2ogLSAxXSA9IGFyZ3VtZW50c1tqXTtcbiAgICAgICAgICB9XG5cbiAgICAgICAgICBsaXN0ZW5lcnNbaV0uZm4uYXBwbHkobGlzdGVuZXJzW2ldLmNvbnRleHQsIGFyZ3MpO1xuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHJldHVybiB0cnVlO1xufTtcblxuLyoqXG4gKiBBZGQgYSBsaXN0ZW5lciBmb3IgYSBnaXZlbiBldmVudC5cbiAqXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZlbnQgVGhlIGV2ZW50IG5hbWUuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBUaGUgbGlzdGVuZXIgZnVuY3Rpb24uXG4gKiBAcGFyYW0geyp9IFtjb250ZXh0PXRoaXNdIFRoZSBjb250ZXh0IHRvIGludm9rZSB0aGUgbGlzdGVuZXIgd2l0aC5cbiAqIEByZXR1cm5zIHtFdmVudEVtaXR0ZXJ9IGB0aGlzYC5cbiAqIEBwdWJsaWNcbiAqL1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5vbiA9IGZ1bmN0aW9uIG9uKGV2ZW50LCBmbiwgY29udGV4dCkge1xuICByZXR1cm4gYWRkTGlzdGVuZXIodGhpcywgZXZlbnQsIGZuLCBjb250ZXh0LCBmYWxzZSk7XG59O1xuXG4vKipcbiAqIEFkZCBhIG9uZS10aW1lIGxpc3RlbmVyIGZvciBhIGdpdmVuIGV2ZW50LlxuICpcbiAqIEBwYXJhbSB7KFN0cmluZ3xTeW1ib2wpfSBldmVudCBUaGUgZXZlbnQgbmFtZS5cbiAqIEBwYXJhbSB7RnVuY3Rpb259IGZuIFRoZSBsaXN0ZW5lciBmdW5jdGlvbi5cbiAqIEBwYXJhbSB7Kn0gW2NvbnRleHQ9dGhpc10gVGhlIGNvbnRleHQgdG8gaW52b2tlIHRoZSBsaXN0ZW5lciB3aXRoLlxuICogQHJldHVybnMge0V2ZW50RW1pdHRlcn0gYHRoaXNgLlxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLm9uY2UgPSBmdW5jdGlvbiBvbmNlKGV2ZW50LCBmbiwgY29udGV4dCkge1xuICByZXR1cm4gYWRkTGlzdGVuZXIodGhpcywgZXZlbnQsIGZuLCBjb250ZXh0LCB0cnVlKTtcbn07XG5cbi8qKlxuICogUmVtb3ZlIHRoZSBsaXN0ZW5lcnMgb2YgYSBnaXZlbiBldmVudC5cbiAqXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gZXZlbnQgVGhlIGV2ZW50IG5hbWUuXG4gKiBAcGFyYW0ge0Z1bmN0aW9ufSBmbiBPbmx5IHJlbW92ZSB0aGUgbGlzdGVuZXJzIHRoYXQgbWF0Y2ggdGhpcyBmdW5jdGlvbi5cbiAqIEBwYXJhbSB7Kn0gY29udGV4dCBPbmx5IHJlbW92ZSB0aGUgbGlzdGVuZXJzIHRoYXQgaGF2ZSB0aGlzIGNvbnRleHQuXG4gKiBAcGFyYW0ge0Jvb2xlYW59IG9uY2UgT25seSByZW1vdmUgb25lLXRpbWUgbGlzdGVuZXJzLlxuICogQHJldHVybnMge0V2ZW50RW1pdHRlcn0gYHRoaXNgLlxuICogQHB1YmxpY1xuICovXG5FdmVudEVtaXR0ZXIucHJvdG90eXBlLnJlbW92ZUxpc3RlbmVyID0gZnVuY3Rpb24gcmVtb3ZlTGlzdGVuZXIoZXZlbnQsIGZuLCBjb250ZXh0LCBvbmNlKSB7XG4gIHZhciBldnQgPSBwcmVmaXggPyBwcmVmaXggKyBldmVudCA6IGV2ZW50O1xuXG4gIGlmICghdGhpcy5fZXZlbnRzW2V2dF0pIHJldHVybiB0aGlzO1xuICBpZiAoIWZuKSB7XG4gICAgY2xlYXJFdmVudCh0aGlzLCBldnQpO1xuICAgIHJldHVybiB0aGlzO1xuICB9XG5cbiAgdmFyIGxpc3RlbmVycyA9IHRoaXMuX2V2ZW50c1tldnRdO1xuXG4gIGlmIChsaXN0ZW5lcnMuZm4pIHtcbiAgICBpZiAoXG4gICAgICBsaXN0ZW5lcnMuZm4gPT09IGZuICYmXG4gICAgICAoIW9uY2UgfHwgbGlzdGVuZXJzLm9uY2UpICYmXG4gICAgICAoIWNvbnRleHQgfHwgbGlzdGVuZXJzLmNvbnRleHQgPT09IGNvbnRleHQpXG4gICAgKSB7XG4gICAgICBjbGVhckV2ZW50KHRoaXMsIGV2dCk7XG4gICAgfVxuICB9IGVsc2Uge1xuICAgIGZvciAodmFyIGkgPSAwLCBldmVudHMgPSBbXSwgbGVuZ3RoID0gbGlzdGVuZXJzLmxlbmd0aDsgaSA8IGxlbmd0aDsgaSsrKSB7XG4gICAgICBpZiAoXG4gICAgICAgIGxpc3RlbmVyc1tpXS5mbiAhPT0gZm4gfHxcbiAgICAgICAgKG9uY2UgJiYgIWxpc3RlbmVyc1tpXS5vbmNlKSB8fFxuICAgICAgICAoY29udGV4dCAmJiBsaXN0ZW5lcnNbaV0uY29udGV4dCAhPT0gY29udGV4dClcbiAgICAgICkge1xuICAgICAgICBldmVudHMucHVzaChsaXN0ZW5lcnNbaV0pO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vXG4gICAgLy8gUmVzZXQgdGhlIGFycmF5LCBvciByZW1vdmUgaXQgY29tcGxldGVseSBpZiB3ZSBoYXZlIG5vIG1vcmUgbGlzdGVuZXJzLlxuICAgIC8vXG4gICAgaWYgKGV2ZW50cy5sZW5ndGgpIHRoaXMuX2V2ZW50c1tldnRdID0gZXZlbnRzLmxlbmd0aCA9PT0gMSA/IGV2ZW50c1swXSA6IGV2ZW50cztcbiAgICBlbHNlIGNsZWFyRXZlbnQodGhpcywgZXZ0KTtcbiAgfVxuXG4gIHJldHVybiB0aGlzO1xufTtcblxuLyoqXG4gKiBSZW1vdmUgYWxsIGxpc3RlbmVycywgb3IgdGhvc2Ugb2YgdGhlIHNwZWNpZmllZCBldmVudC5cbiAqXG4gKiBAcGFyYW0geyhTdHJpbmd8U3ltYm9sKX0gW2V2ZW50XSBUaGUgZXZlbnQgbmFtZS5cbiAqIEByZXR1cm5zIHtFdmVudEVtaXR0ZXJ9IGB0aGlzYC5cbiAqIEBwdWJsaWNcbiAqL1xuRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVBbGxMaXN0ZW5lcnMgPSBmdW5jdGlvbiByZW1vdmVBbGxMaXN0ZW5lcnMoZXZlbnQpIHtcbiAgdmFyIGV2dDtcblxuICBpZiAoZXZlbnQpIHtcbiAgICBldnQgPSBwcmVmaXggPyBwcmVmaXggKyBldmVudCA6IGV2ZW50O1xuICAgIGlmICh0aGlzLl9ldmVudHNbZXZ0XSkgY2xlYXJFdmVudCh0aGlzLCBldnQpO1xuICB9IGVsc2Uge1xuICAgIHRoaXMuX2V2ZW50cyA9IG5ldyBFdmVudHMoKTtcbiAgICB0aGlzLl9ldmVudHNDb3VudCA9IDA7XG4gIH1cblxuICByZXR1cm4gdGhpcztcbn07XG5cbi8vXG4vLyBBbGlhcyBtZXRob2RzIG5hbWVzIGJlY2F1c2UgcGVvcGxlIHJvbGwgbGlrZSB0aGF0LlxuLy9cbkV2ZW50RW1pdHRlci5wcm90b3R5cGUub2ZmID0gRXZlbnRFbWl0dGVyLnByb3RvdHlwZS5yZW1vdmVMaXN0ZW5lcjtcbkV2ZW50RW1pdHRlci5wcm90b3R5cGUuYWRkTGlzdGVuZXIgPSBFdmVudEVtaXR0ZXIucHJvdG90eXBlLm9uO1xuXG4vL1xuLy8gRXhwb3NlIHRoZSBwcmVmaXguXG4vL1xuRXZlbnRFbWl0dGVyLnByZWZpeGVkID0gcHJlZml4O1xuXG4vL1xuLy8gQWxsb3cgYEV2ZW50RW1pdHRlcmAgdG8gYmUgaW1wb3J0ZWQgYXMgbW9kdWxlIG5hbWVzcGFjZS5cbi8vXG5FdmVudEVtaXR0ZXIuRXZlbnRFbWl0dGVyID0gRXZlbnRFbWl0dGVyO1xuXG4vL1xuLy8gRXhwb3NlIHRoZSBtb2R1bGUuXG4vL1xuaWYgKCd1bmRlZmluZWQnICE9PSB0eXBlb2YgbW9kdWxlKSB7XG4gIG1vZHVsZS5leHBvcnRzID0gRXZlbnRFbWl0dGVyO1xufVxuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///418\n")},993:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval('\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n w: () => (/* reexport */ RAFTicker),\n J: () => (/* reexport */ RAFTickerEventContext)\n});\n\n// EXTERNAL MODULE: ./node_modules/eventemitter3/index.js\nvar eventemitter3 = __webpack_require__(418);\n;// CONCATENATED MODULE: ./node_modules/eventemitter3/index.mjs\n\n\n\n/* harmony default export */ const node_modules_eventemitter3 = ((/* unused pure expression or super */ null && (EventEmitter)));\n\n;// CONCATENATED MODULE: ./node_modules/@masatomakino/raf-ticker/esm/RAFTickerEvent.js\nclass RAFTickerEventContext {\n constructor(timestamp, delta) {\n this.timestamp = timestamp;\n this.delta = delta;\n }\n}\n\n;// CONCATENATED MODULE: ./node_modules/@masatomakino/raf-ticker/esm/RAFTicker.js\nvar _a;\n\n\nclass RAFTicker {\n static initialize() {\n if (this._dispatcher == null) {\n this._dispatcher = new eventemitter3();\n }\n this.start();\n }\n static reset() {\n this._dispatcher.removeAllListeners();\n this.stop();\n this.start();\n }\n static start() {\n if (!_a._id) {\n this._lastUpdateTimestamp = undefined;\n _a.onTick(performance.now());\n }\n }\n static stop() {\n cancelAnimationFrame(_a._id);\n this._id = undefined;\n this._lastUpdateTimestamp = undefined;\n }\n static addListener(type, listener) {\n this._dispatcher.on(type, listener);\n }\n /**\n *\n * @param type\n * @param listener\n */\n static hasListener(type, listener) {\n const listeners = this._dispatcher.listeners(type);\n return listeners.includes(listener);\n }\n /**\n * Removes the specified listener\n *\n * @param type\n * @param listener\n */\n static removeListener(type, listener) {\n this._dispatcher.removeListener(type, listener);\n }\n /**\n * イベントを発効する。\n * この関数はアプリケーションから利用することはなく、主に単体テストのために使用する。\n *\n * @param type\n * @param event\n */\n static emit(type, event) {\n this._dispatcher.emit(type, event);\n }\n static emitTickEvent(timestamp) {\n if (_a._lastUpdateTimestamp == null) {\n _a._lastUpdateTimestamp = timestamp;\n }\n const delta = timestamp - _a._lastUpdateTimestamp;\n this._dispatcher.emit("onBeforeTick", new RAFTickerEventContext(timestamp, delta));\n this._dispatcher.emit("tick", new RAFTickerEventContext(timestamp, delta));\n this._dispatcher.emit("onAfterTick", new RAFTickerEventContext(timestamp, delta));\n _a._lastUpdateTimestamp = timestamp;\n }\n}\n_a = RAFTicker;\n/**\n * Alias for addListener\n *\n * @param type\n * @param listener\n */\nRAFTicker.on = _a.addListener;\n/**\n * Alias for removeListener\n *\n * @param type\n * @param listener\n */\nRAFTicker.off = _a.removeListener;\nRAFTicker.onTick = (timestamp) => {\n _a.emitTickEvent(timestamp);\n _a._id = requestAnimationFrame(_a.onTick);\n};\nRAFTicker.initialize();\n\n;// CONCATENATED MODULE: ./node_modules/@masatomakino/raf-ticker/esm/index.js\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiOTkzLmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7QUFBcUM7O0FBRWQ7QUFDdkIsaUVBQWUsNERBQVk7OztBQ0hwQjtBQUNQO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7OztBQ0xBO0FBQzZDO0FBQ2U7QUFDckQ7QUFDUDtBQUNBO0FBQ0EsbUNBQW1DLGFBQVk7QUFDL0M7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrREFBa0QscUJBQXFCO0FBQ3ZFLDBDQUEwQyxxQkFBcUI7QUFDL0QsaURBQWlELHFCQUFxQjtBQUN0RTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUN2RitCO0FBQ0siLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL2V2ZW50ZW1pdHRlcjMvaW5kZXgubWpzP2U2Y2MiLCJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy9AbWFzYXRvbWFraW5vL3JhZi10aWNrZXIvZXNtL1JBRlRpY2tlckV2ZW50LmpzPzk1YTciLCJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy9AbWFzYXRvbWFraW5vL3JhZi10aWNrZXIvZXNtL1JBRlRpY2tlci5qcz9iOTg4Iiwid2VicGFjazovL3RocmVlanMtcG9zdHByb2Nlc3MvLi9ub2RlX21vZHVsZXMvQG1hc2F0b21ha2luby9yYWYtdGlja2VyL2VzbS9pbmRleC5qcz9mYmNkIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCBFdmVudEVtaXR0ZXIgZnJvbSAnLi9pbmRleC5qcydcblxuZXhwb3J0IHsgRXZlbnRFbWl0dGVyIH1cbmV4cG9ydCBkZWZhdWx0IEV2ZW50RW1pdHRlclxuIiwiZXhwb3J0IGNsYXNzIFJBRlRpY2tlckV2ZW50Q29udGV4dCB7XG4gICAgY29uc3RydWN0b3IodGltZXN0YW1wLCBkZWx0YSkge1xuICAgICAgICB0aGlzLnRpbWVzdGFtcCA9IHRpbWVzdGFtcDtcbiAgICAgICAgdGhpcy5kZWx0YSA9IGRlbHRhO1xuICAgIH1cbn1cbiIsInZhciBfYTtcbmltcG9ydCB7IEV2ZW50RW1pdHRlciB9IGZyb20gXCJldmVudGVtaXR0ZXIzXCI7XG5pbXBvcnQgeyBSQUZUaWNrZXJFdmVudENvbnRleHQgfSBmcm9tIFwiLi9SQUZUaWNrZXJFdmVudC5qc1wiO1xuZXhwb3J0IGNsYXNzIFJBRlRpY2tlciB7XG4gICAgc3RhdGljIGluaXRpYWxpemUoKSB7XG4gICAgICAgIGlmICh0aGlzLl9kaXNwYXRjaGVyID09IG51bGwpIHtcbiAgICAgICAgICAgIHRoaXMuX2Rpc3BhdGNoZXIgPSBuZXcgRXZlbnRFbWl0dGVyKCk7XG4gICAgICAgIH1cbiAgICAgICAgdGhpcy5zdGFydCgpO1xuICAgIH1cbiAgICBzdGF0aWMgcmVzZXQoKSB7XG4gICAgICAgIHRoaXMuX2Rpc3BhdGNoZXIucmVtb3ZlQWxsTGlzdGVuZXJzKCk7XG4gICAgICAgIHRoaXMuc3RvcCgpO1xuICAgICAgICB0aGlzLnN0YXJ0KCk7XG4gICAgfVxuICAgIHN0YXRpYyBzdGFydCgpIHtcbiAgICAgICAgaWYgKCFfYS5faWQpIHtcbiAgICAgICAgICAgIHRoaXMuX2xhc3RVcGRhdGVUaW1lc3RhbXAgPSB1bmRlZmluZWQ7XG4gICAgICAgICAgICBfYS5vblRpY2socGVyZm9ybWFuY2Uubm93KCkpO1xuICAgICAgICB9XG4gICAgfVxuICAgIHN0YXRpYyBzdG9wKCkge1xuICAgICAgICBjYW5jZWxBbmltYXRpb25GcmFtZShfYS5faWQpO1xuICAgICAgICB0aGlzLl9pZCA9IHVuZGVmaW5lZDtcbiAgICAgICAgdGhpcy5fbGFzdFVwZGF0ZVRpbWVzdGFtcCA9IHVuZGVmaW5lZDtcbiAgICB9XG4gICAgc3RhdGljIGFkZExpc3RlbmVyKHR5cGUsIGxpc3RlbmVyKSB7XG4gICAgICAgIHRoaXMuX2Rpc3BhdGNoZXIub24odHlwZSwgbGlzdGVuZXIpO1xuICAgIH1cbiAgICAvKipcbiAgICAgKlxuICAgICAqIEBwYXJhbSB0eXBlXG4gICAgICogQHBhcmFtIGxpc3RlbmVyXG4gICAgICovXG4gICAgc3RhdGljIGhhc0xpc3RlbmVyKHR5cGUsIGxpc3RlbmVyKSB7XG4gICAgICAgIGNvbnN0IGxpc3RlbmVycyA9IHRoaXMuX2Rpc3BhdGNoZXIubGlzdGVuZXJzKHR5cGUpO1xuICAgICAgICByZXR1cm4gbGlzdGVuZXJzLmluY2x1ZGVzKGxpc3RlbmVyKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICogUmVtb3ZlcyB0aGUgc3BlY2lmaWVkIGxpc3RlbmVyXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdHlwZVxuICAgICAqIEBwYXJhbSBsaXN0ZW5lclxuICAgICAqL1xuICAgIHN0YXRpYyByZW1vdmVMaXN0ZW5lcih0eXBlLCBsaXN0ZW5lcikge1xuICAgICAgICB0aGlzLl9kaXNwYXRjaGVyLnJlbW92ZUxpc3RlbmVyKHR5cGUsIGxpc3RlbmVyKTtcbiAgICB9XG4gICAgLyoqXG4gICAgICog44Kk44OZ44Oz44OI44KS55m65Yq544GZ44KL44CCXG4gICAgICog44GT44Gu6Zai5pWw44Gv44Ki44OX44Oq44Kx44O844K344On44Oz44GL44KJ5Yip55So44GZ44KL44GT44Go44Gv44Gq44GP44CB5Li744Gr5Y2Y5L2T44OG44K544OI44Gu44Gf44KB44Gr5L2/55So44GZ44KL44CCXG4gICAgICpcbiAgICAgKiBAcGFyYW0gdHlwZVxuICAgICAqIEBwYXJhbSBldmVudFxuICAgICAqL1xuICAgIHN0YXRpYyBlbWl0KHR5cGUsIGV2ZW50KSB7XG4gICAgICAgIHRoaXMuX2Rpc3BhdGNoZXIuZW1pdCh0eXBlLCBldmVudCk7XG4gICAgfVxuICAgIHN0YXRpYyBlbWl0VGlja0V2ZW50KHRpbWVzdGFtcCkge1xuICAgICAgICBpZiAoX2EuX2xhc3RVcGRhdGVUaW1lc3RhbXAgPT0gbnVsbCkge1xuICAgICAgICAgICAgX2EuX2xhc3RVcGRhdGVUaW1lc3RhbXAgPSB0aW1lc3RhbXA7XG4gICAgICAgIH1cbiAgICAgICAgY29uc3QgZGVsdGEgPSB0aW1lc3RhbXAgLSBfYS5fbGFzdFVwZGF0ZVRpbWVzdGFtcDtcbiAgICAgICAgdGhpcy5fZGlzcGF0Y2hlci5lbWl0KFwib25CZWZvcmVUaWNrXCIsIG5ldyBSQUZUaWNrZXJFdmVudENvbnRleHQodGltZXN0YW1wLCBkZWx0YSkpO1xuICAgICAgICB0aGlzLl9kaXNwYXRjaGVyLmVtaXQoXCJ0aWNrXCIsIG5ldyBSQUZUaWNrZXJFdmVudENvbnRleHQodGltZXN0YW1wLCBkZWx0YSkpO1xuICAgICAgICB0aGlzLl9kaXNwYXRjaGVyLmVtaXQoXCJvbkFmdGVyVGlja1wiLCBuZXcgUkFGVGlja2VyRXZlbnRDb250ZXh0KHRpbWVzdGFtcCwgZGVsdGEpKTtcbiAgICAgICAgX2EuX2xhc3RVcGRhdGVUaW1lc3RhbXAgPSB0aW1lc3RhbXA7XG4gICAgfVxufVxuX2EgPSBSQUZUaWNrZXI7XG4vKipcbiAqIEFsaWFzIGZvciBhZGRMaXN0ZW5lclxuICpcbiAqIEBwYXJhbSB0eXBlXG4gKiBAcGFyYW0gbGlzdGVuZXJcbiAqL1xuUkFGVGlja2VyLm9uID0gX2EuYWRkTGlzdGVuZXI7XG4vKipcbiAqIEFsaWFzIGZvciByZW1vdmVMaXN0ZW5lclxuICpcbiAqIEBwYXJhbSB0eXBlXG4gKiBAcGFyYW0gbGlzdGVuZXJcbiAqL1xuUkFGVGlja2VyLm9mZiA9IF9hLnJlbW92ZUxpc3RlbmVyO1xuUkFGVGlja2VyLm9uVGljayA9ICh0aW1lc3RhbXApID0+IHtcbiAgICBfYS5lbWl0VGlja0V2ZW50KHRpbWVzdGFtcCk7XG4gICAgX2EuX2lkID0gcmVxdWVzdEFuaW1hdGlvbkZyYW1lKF9hLm9uVGljayk7XG59O1xuUkFGVGlja2VyLmluaXRpYWxpemUoKTtcbiIsImV4cG9ydCAqIGZyb20gXCIuL1JBRlRpY2tlci5qc1wiO1xuZXhwb3J0ICogZnJvbSBcIi4vUkFGVGlja2VyRXZlbnQuanNcIjtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///993\n')},638:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Ay: () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* unused harmony exports BooleanController, ColorController, Controller, FunctionController, GUI, NumberController, OptionController, StringController */\n/**\n * lil-gui\n * https://lil-gui.georgealways.com\n * @version 0.19.2\n * @author George Michael Brower\n * @license MIT\n */\n\n/**\n * Base class for all controllers.\n */\nclass Controller {\n\n\tconstructor( parent, object, property, className, elementType = 'div' ) {\n\n\t\t/**\n\t\t * The GUI that contains this controller.\n\t\t * @type {GUI}\n\t\t */\n\t\tthis.parent = parent;\n\n\t\t/**\n\t\t * The object this controller will modify.\n\t\t * @type {object}\n\t\t */\n\t\tthis.object = object;\n\n\t\t/**\n\t\t * The name of the property to control.\n\t\t * @type {string}\n\t\t */\n\t\tthis.property = property;\n\n\t\t/**\n\t\t * Used to determine if the controller is disabled.\n\t\t * Use `controller.disable( true|false )` to modify this value.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._disabled = false;\n\n\t\t/**\n\t\t * Used to determine if the Controller is hidden.\n\t\t * Use `controller.show()` or `controller.hide()` to change this.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._hidden = false;\n\n\t\t/**\n\t\t * The value of `object[ property ]` when the controller was created.\n\t\t * @type {any}\n\t\t */\n\t\tthis.initialValue = this.getValue();\n\n\t\t/**\n\t\t * The outermost container DOM element for this controller.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.domElement = document.createElement( elementType );\n\t\tthis.domElement.classList.add( 'controller' );\n\t\tthis.domElement.classList.add( className );\n\n\t\t/**\n\t\t * The DOM element that contains the controller's name.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$name = document.createElement( 'div' );\n\t\tthis.$name.classList.add( 'name' );\n\n\t\tController.nextNameID = Controller.nextNameID || 0;\n\t\tthis.$name.id = `lil-gui-name-${++Controller.nextNameID}`;\n\n\t\t/**\n\t\t * The DOM element that contains the controller's \"widget\" (which differs by controller type).\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$widget = document.createElement( 'div' );\n\t\tthis.$widget.classList.add( 'widget' );\n\n\t\t/**\n\t\t * The DOM element that receives the disabled attribute when using disable().\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$disable = this.$widget;\n\n\t\tthis.domElement.appendChild( this.$name );\n\t\tthis.domElement.appendChild( this.$widget );\n\n\t\t// Don't fire global key events while typing in a controller\n\t\tthis.domElement.addEventListener( 'keydown', e => e.stopPropagation() );\n\t\tthis.domElement.addEventListener( 'keyup', e => e.stopPropagation() );\n\n\t\tthis.parent.children.push( this );\n\t\tthis.parent.controllers.push( this );\n\n\t\tthis.parent.$children.appendChild( this.domElement );\n\n\t\tthis._listenCallback = this._listenCallback.bind( this );\n\n\t\tthis.name( property );\n\n\t}\n\n\t/**\n\t * Sets the name of the controller and its label in the GUI.\n\t * @param {string} name\n\t * @returns {this}\n\t */\n\tname( name ) {\n\t\t/**\n\t\t * The controller's name. Use `controller.name( 'Name' )` to modify this value.\n\t\t * @type {string}\n\t\t */\n\t\tthis._name = name;\n\t\tthis.$name.textContent = name;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Pass a function to be called whenever the value is modified by this controller.\n\t * The function receives the new value as its first parameter. The value of `this` will be the\n\t * controller.\n\t *\n\t * For function controllers, the `onChange` callback will be fired on click, after the function\n\t * executes.\n\t * @param {Function} callback\n\t * @returns {this}\n\t * @example\n\t * const controller = gui.add( object, 'property' );\n\t *\n\t * controller.onChange( function( v ) {\n\t * \tconsole.log( 'The value is now ' + v );\n\t * \tconsole.assert( this === controller );\n\t * } );\n\t */\n\tonChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onChange` events. Don't modify this value directly.\n\t\t * Use the `controller.onChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onChange = callback;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Calls the onChange methods of this controller and its parent GUI.\n\t * @protected\n\t */\n\t_callOnChange() {\n\n\t\tthis.parent._callOnChange( this );\n\n\t\tif ( this._onChange !== undefined ) {\n\t\t\tthis._onChange.call( this, this.getValue() );\n\t\t}\n\n\t\tthis._changed = true;\n\n\t}\n\n\t/**\n\t * Pass a function to be called after this controller has been modified and loses focus.\n\t * @param {Function} callback\n\t * @returns {this}\n\t * @example\n\t * const controller = gui.add( object, 'property' );\n\t *\n\t * controller.onFinishChange( function( v ) {\n\t * \tconsole.log( 'Changes complete: ' + v );\n\t * \tconsole.assert( this === controller );\n\t * } );\n\t */\n\tonFinishChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onFinishChange` events. Don't modify this value\n\t\t * directly. Use the `controller.onFinishChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onFinishChange = callback;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Should be called by Controller when its widgets lose focus.\n\t * @protected\n\t */\n\t_callOnFinishChange() {\n\n\t\tif ( this._changed ) {\n\n\t\t\tthis.parent._callOnFinishChange( this );\n\n\t\t\tif ( this._onFinishChange !== undefined ) {\n\t\t\t\tthis._onFinishChange.call( this, this.getValue() );\n\t\t\t}\n\n\t\t}\n\n\t\tthis._changed = false;\n\n\t}\n\n\t/**\n\t * Sets the controller back to its initial value.\n\t * @returns {this}\n\t */\n\treset() {\n\t\tthis.setValue( this.initialValue );\n\t\tthis._callOnFinishChange();\n\t\treturn this;\n\t}\n\n\t/**\n\t * Enables this controller.\n\t * @param {boolean} enabled\n\t * @returns {this}\n\t * @example\n\t * controller.enable();\n\t * controller.enable( false ); // disable\n\t * controller.enable( controller._disabled ); // toggle\n\t */\n\tenable( enabled = true ) {\n\t\treturn this.disable( !enabled );\n\t}\n\n\t/**\n\t * Disables this controller.\n\t * @param {boolean} disabled\n\t * @returns {this}\n\t * @example\n\t * controller.disable();\n\t * controller.disable( false ); // enable\n\t * controller.disable( !controller._disabled ); // toggle\n\t */\n\tdisable( disabled = true ) {\n\n\t\tif ( disabled === this._disabled ) return this;\n\n\t\tthis._disabled = disabled;\n\n\t\tthis.domElement.classList.toggle( 'disabled', disabled );\n\t\tthis.$disable.toggleAttribute( 'disabled', disabled );\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Shows the Controller after it's been hidden.\n\t * @param {boolean} show\n\t * @returns {this}\n\t * @example\n\t * controller.show();\n\t * controller.show( false ); // hide\n\t * controller.show( controller._hidden ); // toggle\n\t */\n\tshow( show = true ) {\n\n\t\tthis._hidden = !show;\n\n\t\tthis.domElement.style.display = this._hidden ? 'none' : '';\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Hides the Controller.\n\t * @returns {this}\n\t */\n\thide() {\n\t\treturn this.show( false );\n\t}\n\n\t/**\n\t * Changes this controller into a dropdown of options.\n\t *\n\t * Calling this method on an option controller will simply update the options. However, if this\n\t * controller was not already an option controller, old references to this controller are\n\t * destroyed, and a new controller is added to the end of the GUI.\n\t * @example\n\t * // safe usage\n\t *\n\t * gui.add( obj, 'prop1' ).options( [ 'a', 'b', 'c' ] );\n\t * gui.add( obj, 'prop2' ).options( { Big: 10, Small: 1 } );\n\t * gui.add( obj, 'prop3' );\n\t *\n\t * // danger\n\t *\n\t * const ctrl1 = gui.add( obj, 'prop1' );\n\t * gui.add( obj, 'prop2' );\n\t *\n\t * // calling options out of order adds a new controller to the end...\n\t * const ctrl2 = ctrl1.options( [ 'a', 'b', 'c' ] );\n\t *\n\t * // ...and ctrl1 now references a controller that doesn't exist\n\t * assert( ctrl2 !== ctrl1 )\n\t * @param {object|Array} options\n\t * @returns {Controller}\n\t */\n\toptions( options ) {\n\t\tconst controller = this.parent.add( this.object, this.property, options );\n\t\tcontroller.name( this._name );\n\t\tthis.destroy();\n\t\treturn controller;\n\t}\n\n\t/**\n\t * Sets the minimum value. Only works on number controllers.\n\t * @param {number} min\n\t * @returns {this}\n\t */\n\tmin( min ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Sets the maximum value. Only works on number controllers.\n\t * @param {number} max\n\t * @returns {this}\n\t */\n\tmax( max ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Values set by this controller will be rounded to multiples of `step`. Only works on number\n\t * controllers.\n\t * @param {number} step\n\t * @returns {this}\n\t */\n\tstep( step ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Rounds the displayed value to a fixed number of decimals, without affecting the actual value\n\t * like `step()`. Only works on number controllers.\n\t * @example\n\t * gui.add( object, 'property' ).listen().decimals( 4 );\n\t * @param {number} decimals\n\t * @returns {this}\n\t */\n\tdecimals( decimals ) {\n\t\treturn this;\n\t}\n\n\t/**\n\t * Calls `updateDisplay()` every animation frame. Pass `false` to stop listening.\n\t * @param {boolean} listen\n\t * @returns {this}\n\t */\n\tlisten( listen = true ) {\n\n\t\t/**\n\t\t * Used to determine if the controller is currently listening. Don't modify this value\n\t\t * directly. Use the `controller.listen( true|false )` method instead.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._listening = listen;\n\n\t\tif ( this._listenCallbackID !== undefined ) {\n\t\t\tcancelAnimationFrame( this._listenCallbackID );\n\t\t\tthis._listenCallbackID = undefined;\n\t\t}\n\n\t\tif ( this._listening ) {\n\t\t\tthis._listenCallback();\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t_listenCallback() {\n\n\t\tthis._listenCallbackID = requestAnimationFrame( this._listenCallback );\n\n\t\t// To prevent framerate loss, make sure the value has changed before updating the display.\n\t\t// Note: save() is used here instead of getValue() only because of ColorController. The !== operator\n\t\t// won't work for color objects or arrays, but ColorController.save() always returns a string.\n\n\t\tconst curValue = this.save();\n\n\t\tif ( curValue !== this._listenPrevValue ) {\n\t\t\tthis.updateDisplay();\n\t\t}\n\n\t\tthis._listenPrevValue = curValue;\n\n\t}\n\n\t/**\n\t * Returns `object[ property ]`.\n\t * @returns {any}\n\t */\n\tgetValue() {\n\t\treturn this.object[ this.property ];\n\t}\n\n\t/**\n\t * Sets the value of `object[ property ]`, invokes any `onChange` handlers and updates the display.\n\t * @param {any} value\n\t * @returns {this}\n\t */\n\tsetValue( value ) {\n\n\t\tif ( this.getValue() !== value ) {\n\n\t\t\tthis.object[ this.property ] = value;\n\t\t\tthis._callOnChange();\n\t\t\tthis.updateDisplay();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Updates the display to keep it in sync with the current value. Useful for updating your\n\t * controllers when their values have been modified outside of the GUI.\n\t * @returns {this}\n\t */\n\tupdateDisplay() {\n\t\treturn this;\n\t}\n\n\tload( value ) {\n\t\tthis.setValue( value );\n\t\tthis._callOnFinishChange();\n\t\treturn this;\n\t}\n\n\tsave() {\n\t\treturn this.getValue();\n\t}\n\n\t/**\n\t * Destroys this controller and removes it from the parent GUI.\n\t */\n\tdestroy() {\n\t\tthis.listen( false );\n\t\tthis.parent.children.splice( this.parent.children.indexOf( this ), 1 );\n\t\tthis.parent.controllers.splice( this.parent.controllers.indexOf( this ), 1 );\n\t\tthis.parent.$children.removeChild( this.domElement );\n\t}\n\n}\n\nclass BooleanController extends Controller {\n\n\tconstructor( parent, object, property ) {\n\n\t\tsuper( parent, object, property, 'boolean', 'label' );\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'checkbox' );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$widget.appendChild( this.$input );\n\n\t\tthis.$input.addEventListener( 'change', () => {\n\t\t\tthis.setValue( this.$input.checked );\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$disable = this.$input;\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\tupdateDisplay() {\n\t\tthis.$input.checked = this.getValue();\n\t\treturn this;\n\t}\n\n}\n\nfunction normalizeColorString( string ) {\n\n\tlet match, result;\n\n\tif ( match = string.match( /(#|0x)?([a-f0-9]{6})/i ) ) {\n\n\t\tresult = match[ 2 ];\n\n\t} else if ( match = string.match( /rgb\\(\\s*(\\d*)\\s*,\\s*(\\d*)\\s*,\\s*(\\d*)\\s*\\)/ ) ) {\n\n\t\tresult = parseInt( match[ 1 ] ).toString( 16 ).padStart( 2, 0 )\n\t\t\t+ parseInt( match[ 2 ] ).toString( 16 ).padStart( 2, 0 )\n\t\t\t+ parseInt( match[ 3 ] ).toString( 16 ).padStart( 2, 0 );\n\n\t} else if ( match = string.match( /^#?([a-f0-9])([a-f0-9])([a-f0-9])$/i ) ) {\n\n\t\tresult = match[ 1 ] + match[ 1 ] + match[ 2 ] + match[ 2 ] + match[ 3 ] + match[ 3 ];\n\n\t}\n\n\tif ( result ) {\n\t\treturn '#' + result;\n\t}\n\n\treturn false;\n\n}\n\nconst STRING = {\n\tisPrimitive: true,\n\tmatch: v => typeof v === 'string',\n\tfromHexString: normalizeColorString,\n\ttoHexString: normalizeColorString\n};\n\nconst INT = {\n\tisPrimitive: true,\n\tmatch: v => typeof v === 'number',\n\tfromHexString: string => parseInt( string.substring( 1 ), 16 ),\n\ttoHexString: value => '#' + value.toString( 16 ).padStart( 6, 0 )\n};\n\nconst ARRAY = {\n\tisPrimitive: false,\n\n\t// The arrow function is here to appease tree shakers like esbuild or webpack.\n\t// See https://esbuild.github.io/api/#tree-shaking\n\tmatch: v => Array.isArray( v ),\n\n\tfromHexString( string, target, rgbScale = 1 ) {\n\n\t\tconst int = INT.fromHexString( string );\n\n\t\ttarget[ 0 ] = ( int >> 16 & 255 ) / 255 * rgbScale;\n\t\ttarget[ 1 ] = ( int >> 8 & 255 ) / 255 * rgbScale;\n\t\ttarget[ 2 ] = ( int & 255 ) / 255 * rgbScale;\n\n\t},\n\ttoHexString( [ r, g, b ], rgbScale = 1 ) {\n\n\t\trgbScale = 255 / rgbScale;\n\n\t\tconst int = ( r * rgbScale ) << 16 ^\n\t\t\t( g * rgbScale ) << 8 ^\n\t\t\t( b * rgbScale ) << 0;\n\n\t\treturn INT.toHexString( int );\n\n\t}\n};\n\nconst OBJECT = {\n\tisPrimitive: false,\n\tmatch: v => Object( v ) === v,\n\tfromHexString( string, target, rgbScale = 1 ) {\n\n\t\tconst int = INT.fromHexString( string );\n\n\t\ttarget.r = ( int >> 16 & 255 ) / 255 * rgbScale;\n\t\ttarget.g = ( int >> 8 & 255 ) / 255 * rgbScale;\n\t\ttarget.b = ( int & 255 ) / 255 * rgbScale;\n\n\t},\n\ttoHexString( { r, g, b }, rgbScale = 1 ) {\n\n\t\trgbScale = 255 / rgbScale;\n\n\t\tconst int = ( r * rgbScale ) << 16 ^\n\t\t\t( g * rgbScale ) << 8 ^\n\t\t\t( b * rgbScale ) << 0;\n\n\t\treturn INT.toHexString( int );\n\n\t}\n};\n\nconst FORMATS = [ STRING, INT, ARRAY, OBJECT ];\n\nfunction getColorFormat( value ) {\n\treturn FORMATS.find( format => format.match( value ) );\n}\n\nclass ColorController extends Controller {\n\n\tconstructor( parent, object, property, rgbScale ) {\n\n\t\tsuper( parent, object, property, 'color' );\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'color' );\n\t\tthis.$input.setAttribute( 'tabindex', -1 );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$text = document.createElement( 'input' );\n\t\tthis.$text.setAttribute( 'type', 'text' );\n\t\tthis.$text.setAttribute( 'spellcheck', 'false' );\n\t\tthis.$text.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$display = document.createElement( 'div' );\n\t\tthis.$display.classList.add( 'display' );\n\n\t\tthis.$display.appendChild( this.$input );\n\t\tthis.$widget.appendChild( this.$display );\n\t\tthis.$widget.appendChild( this.$text );\n\n\t\tthis._format = getColorFormat( this.initialValue );\n\t\tthis._rgbScale = rgbScale;\n\n\t\tthis._initialValueHexString = this.save();\n\t\tthis._textFocused = false;\n\n\t\tthis.$input.addEventListener( 'input', () => {\n\t\t\tthis._setValueFromHexString( this.$input.value );\n\t\t} );\n\n\t\tthis.$input.addEventListener( 'blur', () => {\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$text.addEventListener( 'input', () => {\n\t\t\tconst tryParse = normalizeColorString( this.$text.value );\n\t\t\tif ( tryParse ) {\n\t\t\t\tthis._setValueFromHexString( tryParse );\n\t\t\t}\n\t\t} );\n\n\t\tthis.$text.addEventListener( 'focus', () => {\n\t\t\tthis._textFocused = true;\n\t\t\tthis.$text.select();\n\t\t} );\n\n\t\tthis.$text.addEventListener( 'blur', () => {\n\t\t\tthis._textFocused = false;\n\t\t\tthis.updateDisplay();\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$disable = this.$text;\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\treset() {\n\t\tthis._setValueFromHexString( this._initialValueHexString );\n\t\treturn this;\n\t}\n\n\t_setValueFromHexString( value ) {\n\n\t\tif ( this._format.isPrimitive ) {\n\n\t\t\tconst newValue = this._format.fromHexString( value );\n\t\t\tthis.setValue( newValue );\n\n\t\t} else {\n\n\t\t\tthis._format.fromHexString( value, this.getValue(), this._rgbScale );\n\t\t\tthis._callOnChange();\n\t\t\tthis.updateDisplay();\n\n\t\t}\n\n\t}\n\n\tsave() {\n\t\treturn this._format.toHexString( this.getValue(), this._rgbScale );\n\t}\n\n\tload( value ) {\n\t\tthis._setValueFromHexString( value );\n\t\tthis._callOnFinishChange();\n\t\treturn this;\n\t}\n\n\tupdateDisplay() {\n\t\tthis.$input.value = this._format.toHexString( this.getValue(), this._rgbScale );\n\t\tif ( !this._textFocused ) {\n\t\t\tthis.$text.value = this.$input.value.substring( 1 );\n\t\t}\n\t\tthis.$display.style.backgroundColor = this.$input.value;\n\t\treturn this;\n\t}\n\n}\n\nclass FunctionController extends Controller {\n\n\tconstructor( parent, object, property ) {\n\n\t\tsuper( parent, object, property, 'function' );\n\n\t\t// Buttons are the only case where widget contains name\n\t\tthis.$button = document.createElement( 'button' );\n\t\tthis.$button.appendChild( this.$name );\n\t\tthis.$widget.appendChild( this.$button );\n\n\t\tthis.$button.addEventListener( 'click', e => {\n\t\t\te.preventDefault();\n\t\t\tthis.getValue().call( this.object );\n\t\t\tthis._callOnChange();\n\t\t} );\n\n\t\t// enables :active pseudo class on mobile\n\t\tthis.$button.addEventListener( 'touchstart', () => {}, { passive: true } );\n\n\t\tthis.$disable = this.$button;\n\n\t}\n\n}\n\nclass NumberController extends Controller {\n\n\tconstructor( parent, object, property, min, max, step ) {\n\n\t\tsuper( parent, object, property, 'number' );\n\n\t\tthis._initInput();\n\n\t\tthis.min( min );\n\t\tthis.max( max );\n\n\t\tconst stepExplicit = step !== undefined;\n\t\tthis.step( stepExplicit ? step : this._getImplicitStep(), stepExplicit );\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\tdecimals( decimals ) {\n\t\tthis._decimals = decimals;\n\t\tthis.updateDisplay();\n\t\treturn this;\n\t}\n\n\tmin( min ) {\n\t\tthis._min = min;\n\t\tthis._onUpdateMinMax();\n\t\treturn this;\n\t}\n\n\tmax( max ) {\n\t\tthis._max = max;\n\t\tthis._onUpdateMinMax();\n\t\treturn this;\n\t}\n\n\tstep( step, explicit = true ) {\n\t\tthis._step = step;\n\t\tthis._stepExplicit = explicit;\n\t\treturn this;\n\t}\n\n\tupdateDisplay() {\n\n\t\tconst value = this.getValue();\n\n\t\tif ( this._hasSlider ) {\n\n\t\t\tlet percent = ( value - this._min ) / ( this._max - this._min );\n\t\t\tpercent = Math.max( 0, Math.min( percent, 1 ) );\n\n\t\t\tthis.$fill.style.width = percent * 100 + '%';\n\n\t\t}\n\n\t\tif ( !this._inputFocused ) {\n\t\t\tthis.$input.value = this._decimals === undefined ? value : value.toFixed( this._decimals );\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t_initInput() {\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'text' );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\t// On touch devices only, use input[type=number] to force a numeric keyboard.\n\t\t// Ideally we could use one input type everywhere, but [type=number] has quirks\n\t\t// on desktop, and [inputmode=decimal] has quirks on iOS.\n\t\t// See https://github.com/georgealways/lil-gui/pull/16\n\n\t\tconst isTouch = window.matchMedia( '(pointer: coarse)' ).matches;\n\n\t\tif ( isTouch ) {\n\t\t\tthis.$input.setAttribute( 'type', 'number' );\n\t\t\tthis.$input.setAttribute( 'step', 'any' );\n\t\t}\n\n\t\tthis.$widget.appendChild( this.$input );\n\n\t\tthis.$disable = this.$input;\n\n\t\tconst onInput = () => {\n\n\t\t\tlet value = parseFloat( this.$input.value );\n\n\t\t\tif ( isNaN( value ) ) return;\n\n\t\t\tif ( this._stepExplicit ) {\n\t\t\t\tvalue = this._snap( value );\n\t\t\t}\n\n\t\t\tthis.setValue( this._clamp( value ) );\n\n\t\t};\n\n\t\t// Keys & mouse wheel\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst increment = delta => {\n\n\t\t\tconst value = parseFloat( this.$input.value );\n\n\t\t\tif ( isNaN( value ) ) return;\n\n\t\t\tthis._snapClampSetValue( value + delta );\n\n\t\t\t// Force the input to updateDisplay when it's focused\n\t\t\tthis.$input.value = this.getValue();\n\n\t\t};\n\n\t\tconst onKeyDown = e => {\n\t\t\t// Using `e.key` instead of `e.code` also catches NumpadEnter\n\t\t\tif ( e.key === 'Enter' ) {\n\t\t\t\tthis.$input.blur();\n\t\t\t}\n\t\t\tif ( e.code === 'ArrowUp' ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tincrement( this._step * this._arrowKeyMultiplier( e ) );\n\t\t\t}\n\t\t\tif ( e.code === 'ArrowDown' ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tincrement( this._step * this._arrowKeyMultiplier( e ) * -1 );\n\t\t\t}\n\t\t};\n\n\t\tconst onWheel = e => {\n\t\t\tif ( this._inputFocused ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tincrement( this._step * this._normalizeMouseWheel( e ) );\n\t\t\t}\n\t\t};\n\n\t\t// Vertical drag\n\t\t// ---------------------------------------------------------------------\n\n\t\tlet testingForVerticalDrag = false,\n\t\t\tinitClientX,\n\t\t\tinitClientY,\n\t\t\tprevClientY,\n\t\t\tinitValue,\n\t\t\tdragDelta;\n\n\t\t// Once the mouse is dragged more than DRAG_THRESH px on any axis, we decide\n\t\t// on the user's intent: horizontal means highlight, vertical means drag.\n\t\tconst DRAG_THRESH = 5;\n\n\t\tconst onMouseDown = e => {\n\n\t\t\tinitClientX = e.clientX;\n\t\t\tinitClientY = prevClientY = e.clientY;\n\t\t\ttestingForVerticalDrag = true;\n\n\t\t\tinitValue = this.getValue();\n\t\t\tdragDelta = 0;\n\n\t\t\twindow.addEventListener( 'mousemove', onMouseMove );\n\t\t\twindow.addEventListener( 'mouseup', onMouseUp );\n\n\t\t};\n\n\t\tconst onMouseMove = e => {\n\n\t\t\tif ( testingForVerticalDrag ) {\n\n\t\t\t\tconst dx = e.clientX - initClientX;\n\t\t\t\tconst dy = e.clientY - initClientY;\n\n\t\t\t\tif ( Math.abs( dy ) > DRAG_THRESH ) {\n\n\t\t\t\t\te.preventDefault();\n\t\t\t\t\tthis.$input.blur();\n\t\t\t\t\ttestingForVerticalDrag = false;\n\t\t\t\t\tthis._setDraggingStyle( true, 'vertical' );\n\n\t\t\t\t} else if ( Math.abs( dx ) > DRAG_THRESH ) {\n\n\t\t\t\t\tonMouseUp();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// This isn't an else so that the first move counts towards dragDelta\n\t\t\tif ( !testingForVerticalDrag ) {\n\n\t\t\t\tconst dy = e.clientY - prevClientY;\n\n\t\t\t\tdragDelta -= dy * this._step * this._arrowKeyMultiplier( e );\n\n\t\t\t\t// Clamp dragDelta so we don't have 'dead space' after dragging past bounds.\n\t\t\t\t// We're okay with the fact that bounds can be undefined here.\n\t\t\t\tif ( initValue + dragDelta > this._max ) {\n\t\t\t\t\tdragDelta = this._max - initValue;\n\t\t\t\t} else if ( initValue + dragDelta < this._min ) {\n\t\t\t\t\tdragDelta = this._min - initValue;\n\t\t\t\t}\n\n\t\t\t\tthis._snapClampSetValue( initValue + dragDelta );\n\n\t\t\t}\n\n\t\t\tprevClientY = e.clientY;\n\n\t\t};\n\n\t\tconst onMouseUp = () => {\n\t\t\tthis._setDraggingStyle( false, 'vertical' );\n\t\t\tthis._callOnFinishChange();\n\t\t\twindow.removeEventListener( 'mousemove', onMouseMove );\n\t\t\twindow.removeEventListener( 'mouseup', onMouseUp );\n\t\t};\n\n\t\t// Focus state & onFinishChange\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst onFocus = () => {\n\t\t\tthis._inputFocused = true;\n\t\t};\n\n\t\tconst onBlur = () => {\n\t\t\tthis._inputFocused = false;\n\t\t\tthis.updateDisplay();\n\t\t\tthis._callOnFinishChange();\n\t\t};\n\n\t\tthis.$input.addEventListener( 'input', onInput );\n\t\tthis.$input.addEventListener( 'keydown', onKeyDown );\n\t\tthis.$input.addEventListener( 'wheel', onWheel, { passive: false } );\n\t\tthis.$input.addEventListener( 'mousedown', onMouseDown );\n\t\tthis.$input.addEventListener( 'focus', onFocus );\n\t\tthis.$input.addEventListener( 'blur', onBlur );\n\n\t}\n\n\t_initSlider() {\n\n\t\tthis._hasSlider = true;\n\n\t\t// Build DOM\n\t\t// ---------------------------------------------------------------------\n\n\t\tthis.$slider = document.createElement( 'div' );\n\t\tthis.$slider.classList.add( 'slider' );\n\n\t\tthis.$fill = document.createElement( 'div' );\n\t\tthis.$fill.classList.add( 'fill' );\n\n\t\tthis.$slider.appendChild( this.$fill );\n\t\tthis.$widget.insertBefore( this.$slider, this.$input );\n\n\t\tthis.domElement.classList.add( 'hasSlider' );\n\n\t\t// Map clientX to value\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst map = ( v, a, b, c, d ) => {\n\t\t\treturn ( v - a ) / ( b - a ) * ( d - c ) + c;\n\t\t};\n\n\t\tconst setValueFromX = clientX => {\n\t\t\tconst rect = this.$slider.getBoundingClientRect();\n\t\t\tlet value = map( clientX, rect.left, rect.right, this._min, this._max );\n\t\t\tthis._snapClampSetValue( value );\n\t\t};\n\n\t\t// Mouse drag\n\t\t// ---------------------------------------------------------------------\n\n\t\tconst mouseDown = e => {\n\t\t\tthis._setDraggingStyle( true );\n\t\t\tsetValueFromX( e.clientX );\n\t\t\twindow.addEventListener( 'mousemove', mouseMove );\n\t\t\twindow.addEventListener( 'mouseup', mouseUp );\n\t\t};\n\n\t\tconst mouseMove = e => {\n\t\t\tsetValueFromX( e.clientX );\n\t\t};\n\n\t\tconst mouseUp = () => {\n\t\t\tthis._callOnFinishChange();\n\t\t\tthis._setDraggingStyle( false );\n\t\t\twindow.removeEventListener( 'mousemove', mouseMove );\n\t\t\twindow.removeEventListener( 'mouseup', mouseUp );\n\t\t};\n\n\t\t// Touch drag\n\t\t// ---------------------------------------------------------------------\n\n\t\tlet testingForScroll = false, prevClientX, prevClientY;\n\n\t\tconst beginTouchDrag = e => {\n\t\t\te.preventDefault();\n\t\t\tthis._setDraggingStyle( true );\n\t\t\tsetValueFromX( e.touches[ 0 ].clientX );\n\t\t\ttestingForScroll = false;\n\t\t};\n\n\t\tconst onTouchStart = e => {\n\n\t\t\tif ( e.touches.length > 1 ) return;\n\n\t\t\t// If we're in a scrollable container, we should wait for the first\n\t\t\t// touchmove to see if the user is trying to slide or scroll.\n\t\t\tif ( this._hasScrollBar ) {\n\n\t\t\t\tprevClientX = e.touches[ 0 ].clientX;\n\t\t\t\tprevClientY = e.touches[ 0 ].clientY;\n\t\t\t\ttestingForScroll = true;\n\n\t\t\t} else {\n\n\t\t\t\t// Otherwise, we can set the value straight away on touchstart.\n\t\t\t\tbeginTouchDrag( e );\n\n\t\t\t}\n\n\t\t\twindow.addEventListener( 'touchmove', onTouchMove, { passive: false } );\n\t\t\twindow.addEventListener( 'touchend', onTouchEnd );\n\n\t\t};\n\n\t\tconst onTouchMove = e => {\n\n\t\t\tif ( testingForScroll ) {\n\n\t\t\t\tconst dx = e.touches[ 0 ].clientX - prevClientX;\n\t\t\t\tconst dy = e.touches[ 0 ].clientY - prevClientY;\n\n\t\t\t\tif ( Math.abs( dx ) > Math.abs( dy ) ) {\n\n\t\t\t\t\t// We moved horizontally, set the value and stop checking.\n\t\t\t\t\tbeginTouchDrag( e );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// This was, in fact, an attempt to scroll. Abort.\n\t\t\t\t\twindow.removeEventListener( 'touchmove', onTouchMove );\n\t\t\t\t\twindow.removeEventListener( 'touchend', onTouchEnd );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\te.preventDefault();\n\t\t\t\tsetValueFromX( e.touches[ 0 ].clientX );\n\n\t\t\t}\n\n\t\t};\n\n\t\tconst onTouchEnd = () => {\n\t\t\tthis._callOnFinishChange();\n\t\t\tthis._setDraggingStyle( false );\n\t\t\twindow.removeEventListener( 'touchmove', onTouchMove );\n\t\t\twindow.removeEventListener( 'touchend', onTouchEnd );\n\t\t};\n\n\t\t// Mouse wheel\n\t\t// ---------------------------------------------------------------------\n\n\t\t// We have to use a debounced function to call onFinishChange because\n\t\t// there's no way to tell when the user is \"done\" mouse-wheeling.\n\t\tconst callOnFinishChange = this._callOnFinishChange.bind( this );\n\t\tconst WHEEL_DEBOUNCE_TIME = 400;\n\t\tlet wheelFinishChangeTimeout;\n\n\t\tconst onWheel = e => {\n\n\t\t\t// ignore vertical wheels if there's a scrollbar\n\t\t\tconst isVertical = Math.abs( e.deltaX ) < Math.abs( e.deltaY );\n\t\t\tif ( isVertical && this._hasScrollBar ) return;\n\n\t\t\te.preventDefault();\n\n\t\t\t// set value\n\t\t\tconst delta = this._normalizeMouseWheel( e ) * this._step;\n\t\t\tthis._snapClampSetValue( this.getValue() + delta );\n\n\t\t\t// force the input to updateDisplay when it's focused\n\t\t\tthis.$input.value = this.getValue();\n\n\t\t\t// debounce onFinishChange\n\t\t\tclearTimeout( wheelFinishChangeTimeout );\n\t\t\twheelFinishChangeTimeout = setTimeout( callOnFinishChange, WHEEL_DEBOUNCE_TIME );\n\n\t\t};\n\n\t\tthis.$slider.addEventListener( 'mousedown', mouseDown );\n\t\tthis.$slider.addEventListener( 'touchstart', onTouchStart, { passive: false } );\n\t\tthis.$slider.addEventListener( 'wheel', onWheel, { passive: false } );\n\n\t}\n\n\t_setDraggingStyle( active, axis = 'horizontal' ) {\n\t\tif ( this.$slider ) {\n\t\t\tthis.$slider.classList.toggle( 'active', active );\n\t\t}\n\t\tdocument.body.classList.toggle( 'lil-gui-dragging', active );\n\t\tdocument.body.classList.toggle( `lil-gui-${axis}`, active );\n\t}\n\n\t_getImplicitStep() {\n\n\t\tif ( this._hasMin && this._hasMax ) {\n\t\t\treturn ( this._max - this._min ) / 1000;\n\t\t}\n\n\t\treturn 0.1;\n\n\t}\n\n\t_onUpdateMinMax() {\n\n\t\tif ( !this._hasSlider && this._hasMin && this._hasMax ) {\n\n\t\t\t// If this is the first time we're hearing about min and max\n\t\t\t// and we haven't explicitly stated what our step is, let's\n\t\t\t// update that too.\n\t\t\tif ( !this._stepExplicit ) {\n\t\t\t\tthis.step( this._getImplicitStep(), false );\n\t\t\t}\n\n\t\t\tthis._initSlider();\n\t\t\tthis.updateDisplay();\n\n\t\t}\n\n\t}\n\n\t_normalizeMouseWheel( e ) {\n\n\t\tlet { deltaX, deltaY } = e;\n\n\t\t// Safari and Chrome report weird non-integral values for a notched wheel,\n\t\t// but still expose actual lines scrolled via wheelDelta. Notched wheels\n\t\t// should behave the same way as arrow keys.\n\t\tif ( Math.floor( e.deltaY ) !== e.deltaY && e.wheelDelta ) {\n\t\t\tdeltaX = 0;\n\t\t\tdeltaY = -e.wheelDelta / 120;\n\t\t\tdeltaY *= this._stepExplicit ? 1 : 10;\n\t\t}\n\n\t\tconst wheel = deltaX + -deltaY;\n\n\t\treturn wheel;\n\n\t}\n\n\t_arrowKeyMultiplier( e ) {\n\n\t\tlet mult = this._stepExplicit ? 1 : 10;\n\n\t\tif ( e.shiftKey ) {\n\t\t\tmult *= 10;\n\t\t} else if ( e.altKey ) {\n\t\t\tmult /= 10;\n\t\t}\n\n\t\treturn mult;\n\n\t}\n\n\t_snap( value ) {\n\n\t\t// This would be the logical way to do things, but floating point errors.\n\t\t// return Math.round( value / this._step ) * this._step;\n\n\t\t// Using inverse step solves a lot of them, but not all\n\t\t// const inverseStep = 1 / this._step;\n\t\t// return Math.round( value * inverseStep ) / inverseStep;\n\n\t\t// Not happy about this, but haven't seen it break.\n\t\tconst r = Math.round( value / this._step ) * this._step;\n\t\treturn parseFloat( r.toPrecision( 15 ) );\n\n\t}\n\n\t_clamp( value ) {\n\t\t// either condition is false if min or max is undefined\n\t\tif ( value < this._min ) value = this._min;\n\t\tif ( value > this._max ) value = this._max;\n\t\treturn value;\n\t}\n\n\t_snapClampSetValue( value ) {\n\t\tthis.setValue( this._clamp( this._snap( value ) ) );\n\t}\n\n\tget _hasScrollBar() {\n\t\tconst root = this.parent.root.$children;\n\t\treturn root.scrollHeight > root.clientHeight;\n\t}\n\n\tget _hasMin() {\n\t\treturn this._min !== undefined;\n\t}\n\n\tget _hasMax() {\n\t\treturn this._max !== undefined;\n\t}\n\n}\n\nclass OptionController extends Controller {\n\n\tconstructor( parent, object, property, options ) {\n\n\t\tsuper( parent, object, property, 'option' );\n\n\t\tthis.$select = document.createElement( 'select' );\n\t\tthis.$select.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$display = document.createElement( 'div' );\n\t\tthis.$display.classList.add( 'display' );\n\n\t\tthis.$select.addEventListener( 'change', () => {\n\t\t\tthis.setValue( this._values[ this.$select.selectedIndex ] );\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$select.addEventListener( 'focus', () => {\n\t\t\tthis.$display.classList.add( 'focus' );\n\t\t} );\n\n\t\tthis.$select.addEventListener( 'blur', () => {\n\t\t\tthis.$display.classList.remove( 'focus' );\n\t\t} );\n\n\t\tthis.$widget.appendChild( this.$select );\n\t\tthis.$widget.appendChild( this.$display );\n\n\t\tthis.$disable = this.$select;\n\n\t\tthis.options( options );\n\n\t}\n\n\toptions( options ) {\n\n\t\tthis._values = Array.isArray( options ) ? options : Object.values( options );\n\t\tthis._names = Array.isArray( options ) ? options : Object.keys( options );\n\n\t\tthis.$select.replaceChildren();\n\n\t\tthis._names.forEach( name => {\n\t\t\tconst $option = document.createElement( 'option' );\n\t\t\t$option.textContent = name;\n\t\t\tthis.$select.appendChild( $option );\n\t\t} );\n\n\t\tthis.updateDisplay();\n\n\t\treturn this;\n\n\t}\n\n\tupdateDisplay() {\n\t\tconst value = this.getValue();\n\t\tconst index = this._values.indexOf( value );\n\t\tthis.$select.selectedIndex = index;\n\t\tthis.$display.textContent = index === -1 ? value : this._names[ index ];\n\t\treturn this;\n\t}\n\n}\n\nclass StringController extends Controller {\n\n\tconstructor( parent, object, property ) {\n\n\t\tsuper( parent, object, property, 'string' );\n\n\t\tthis.$input = document.createElement( 'input' );\n\t\tthis.$input.setAttribute( 'type', 'text' );\n\t\tthis.$input.setAttribute( 'spellcheck', 'false' );\n\t\tthis.$input.setAttribute( 'aria-labelledby', this.$name.id );\n\n\t\tthis.$input.addEventListener( 'input', () => {\n\t\t\tthis.setValue( this.$input.value );\n\t\t} );\n\n\t\tthis.$input.addEventListener( 'keydown', e => {\n\t\t\tif ( e.code === 'Enter' ) {\n\t\t\t\tthis.$input.blur();\n\t\t\t}\n\t\t} );\n\n\t\tthis.$input.addEventListener( 'blur', () => {\n\t\t\tthis._callOnFinishChange();\n\t\t} );\n\n\t\tthis.$widget.appendChild( this.$input );\n\n\t\tthis.$disable = this.$input;\n\n\t\tthis.updateDisplay();\n\n\t}\n\n\tupdateDisplay() {\n\t\tthis.$input.value = this.getValue();\n\t\treturn this;\n\t}\n\n}\n\nconst stylesheet = `.lil-gui {\n font-family: var(--font-family);\n font-size: var(--font-size);\n line-height: 1;\n font-weight: normal;\n font-style: normal;\n text-align: left;\n color: var(--text-color);\n user-select: none;\n -webkit-user-select: none;\n touch-action: manipulation;\n --background-color: #1f1f1f;\n --text-color: #ebebeb;\n --title-background-color: #111111;\n --title-text-color: #ebebeb;\n --widget-color: #424242;\n --hover-color: #4f4f4f;\n --focus-color: #595959;\n --number-color: #2cc9ff;\n --string-color: #a2db3c;\n --font-size: 11px;\n --input-font-size: 11px;\n --font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Arial, sans-serif;\n --font-family-mono: Menlo, Monaco, Consolas, \"Droid Sans Mono\", monospace;\n --padding: 4px;\n --spacing: 4px;\n --widget-height: 20px;\n --title-height: calc(var(--widget-height) + var(--spacing) * 1.25);\n --name-width: 45%;\n --slider-knob-width: 2px;\n --slider-input-width: 27%;\n --color-input-width: 27%;\n --slider-input-min-width: 45px;\n --color-input-min-width: 45px;\n --folder-indent: 7px;\n --widget-padding: 0 0 0 3px;\n --widget-border-radius: 2px;\n --checkbox-size: calc(0.75 * var(--widget-height));\n --scrollbar-width: 5px;\n}\n.lil-gui, .lil-gui * {\n box-sizing: border-box;\n margin: 0;\n padding: 0;\n}\n.lil-gui.root {\n width: var(--width, 245px);\n display: flex;\n flex-direction: column;\n background: var(--background-color);\n}\n.lil-gui.root > .title {\n background: var(--title-background-color);\n color: var(--title-text-color);\n}\n.lil-gui.root > .children {\n overflow-x: hidden;\n overflow-y: auto;\n}\n.lil-gui.root > .children::-webkit-scrollbar {\n width: var(--scrollbar-width);\n height: var(--scrollbar-width);\n background: var(--background-color);\n}\n.lil-gui.root > .children::-webkit-scrollbar-thumb {\n border-radius: var(--scrollbar-width);\n background: var(--focus-color);\n}\n@media (pointer: coarse) {\n .lil-gui.allow-touch-styles, .lil-gui.allow-touch-styles .lil-gui {\n --widget-height: 28px;\n --padding: 6px;\n --spacing: 6px;\n --font-size: 13px;\n --input-font-size: 16px;\n --folder-indent: 10px;\n --scrollbar-width: 7px;\n --slider-input-min-width: 50px;\n --color-input-min-width: 65px;\n }\n}\n.lil-gui.force-touch-styles, .lil-gui.force-touch-styles .lil-gui {\n --widget-height: 28px;\n --padding: 6px;\n --spacing: 6px;\n --font-size: 13px;\n --input-font-size: 16px;\n --folder-indent: 10px;\n --scrollbar-width: 7px;\n --slider-input-min-width: 50px;\n --color-input-min-width: 65px;\n}\n.lil-gui.autoPlace {\n max-height: 100%;\n position: fixed;\n top: 0;\n right: 15px;\n z-index: 1001;\n}\n\n.lil-gui .controller {\n display: flex;\n align-items: center;\n padding: 0 var(--padding);\n margin: var(--spacing) 0;\n}\n.lil-gui .controller.disabled {\n opacity: 0.5;\n}\n.lil-gui .controller.disabled, .lil-gui .controller.disabled * {\n pointer-events: none !important;\n}\n.lil-gui .controller > .name {\n min-width: var(--name-width);\n flex-shrink: 0;\n white-space: pre;\n padding-right: var(--spacing);\n line-height: var(--widget-height);\n}\n.lil-gui .controller .widget {\n position: relative;\n display: flex;\n align-items: center;\n width: 100%;\n min-height: var(--widget-height);\n}\n.lil-gui .controller.string input {\n color: var(--string-color);\n}\n.lil-gui .controller.boolean {\n cursor: pointer;\n}\n.lil-gui .controller.color .display {\n width: 100%;\n height: var(--widget-height);\n border-radius: var(--widget-border-radius);\n position: relative;\n}\n@media (hover: hover) {\n .lil-gui .controller.color .display:hover:before {\n content: \" \";\n display: block;\n position: absolute;\n border-radius: var(--widget-border-radius);\n border: 1px solid #fff9;\n top: 0;\n right: 0;\n bottom: 0;\n left: 0;\n }\n}\n.lil-gui .controller.color input[type=color] {\n opacity: 0;\n width: 100%;\n height: 100%;\n cursor: pointer;\n}\n.lil-gui .controller.color input[type=text] {\n margin-left: var(--spacing);\n font-family: var(--font-family-mono);\n min-width: var(--color-input-min-width);\n width: var(--color-input-width);\n flex-shrink: 0;\n}\n.lil-gui .controller.option select {\n opacity: 0;\n position: absolute;\n width: 100%;\n max-width: 100%;\n}\n.lil-gui .controller.option .display {\n position: relative;\n pointer-events: none;\n border-radius: var(--widget-border-radius);\n height: var(--widget-height);\n line-height: var(--widget-height);\n max-width: 100%;\n overflow: hidden;\n word-break: break-all;\n padding-left: 0.55em;\n padding-right: 1.75em;\n background: var(--widget-color);\n}\n@media (hover: hover) {\n .lil-gui .controller.option .display.focus {\n background: var(--focus-color);\n }\n}\n.lil-gui .controller.option .display.active {\n background: var(--focus-color);\n}\n.lil-gui .controller.option .display:after {\n font-family: \"lil-gui\";\n content: \"↕\";\n position: absolute;\n top: 0;\n right: 0;\n bottom: 0;\n padding-right: 0.375em;\n}\n.lil-gui .controller.option .widget,\n.lil-gui .controller.option select {\n cursor: pointer;\n}\n@media (hover: hover) {\n .lil-gui .controller.option .widget:hover .display {\n background: var(--hover-color);\n }\n}\n.lil-gui .controller.number input {\n color: var(--number-color);\n}\n.lil-gui .controller.number.hasSlider input {\n margin-left: var(--spacing);\n width: var(--slider-input-width);\n min-width: var(--slider-input-min-width);\n flex-shrink: 0;\n}\n.lil-gui .controller.number .slider {\n width: 100%;\n height: var(--widget-height);\n background: var(--widget-color);\n border-radius: var(--widget-border-radius);\n padding-right: var(--slider-knob-width);\n overflow: hidden;\n cursor: ew-resize;\n touch-action: pan-y;\n}\n@media (hover: hover) {\n .lil-gui .controller.number .slider:hover {\n background: var(--hover-color);\n }\n}\n.lil-gui .controller.number .slider.active {\n background: var(--focus-color);\n}\n.lil-gui .controller.number .slider.active .fill {\n opacity: 0.95;\n}\n.lil-gui .controller.number .fill {\n height: 100%;\n border-right: var(--slider-knob-width) solid var(--number-color);\n box-sizing: content-box;\n}\n\n.lil-gui-dragging .lil-gui {\n --hover-color: var(--widget-color);\n}\n.lil-gui-dragging * {\n cursor: ew-resize !important;\n}\n\n.lil-gui-dragging.lil-gui-vertical * {\n cursor: ns-resize !important;\n}\n\n.lil-gui .title {\n height: var(--title-height);\n line-height: calc(var(--title-height) - 4px);\n font-weight: 600;\n padding: 0 var(--padding);\n -webkit-tap-highlight-color: transparent;\n cursor: pointer;\n outline: none;\n text-decoration-skip: objects;\n}\n.lil-gui .title:before {\n font-family: \"lil-gui\";\n content: \"▾\";\n padding-right: 2px;\n display: inline-block;\n}\n.lil-gui .title:active {\n background: var(--title-background-color);\n opacity: 0.75;\n}\n@media (hover: hover) {\n body:not(.lil-gui-dragging) .lil-gui .title:hover {\n background: var(--title-background-color);\n opacity: 0.85;\n }\n .lil-gui .title:focus {\n text-decoration: underline var(--focus-color);\n }\n}\n.lil-gui.root > .title:focus {\n text-decoration: none !important;\n}\n.lil-gui.closed > .title:before {\n content: \"▸\";\n}\n.lil-gui.closed > .children {\n transform: translateY(-7px);\n opacity: 0;\n}\n.lil-gui.closed:not(.transition) > .children {\n display: none;\n}\n.lil-gui.transition > .children {\n transition-duration: 300ms;\n transition-property: height, opacity, transform;\n transition-timing-function: cubic-bezier(0.2, 0.6, 0.35, 1);\n overflow: hidden;\n pointer-events: none;\n}\n.lil-gui .children:empty:before {\n content: \"Empty\";\n padding: 0 var(--padding);\n margin: var(--spacing) 0;\n display: block;\n height: var(--widget-height);\n font-style: italic;\n line-height: var(--widget-height);\n opacity: 0.5;\n}\n.lil-gui.root > .children > .lil-gui > .title {\n border: 0 solid var(--widget-color);\n border-width: 1px 0;\n transition: border-color 300ms;\n}\n.lil-gui.root > .children > .lil-gui.closed > .title {\n border-bottom-color: transparent;\n}\n.lil-gui + .controller {\n border-top: 1px solid var(--widget-color);\n margin-top: 0;\n padding-top: var(--spacing);\n}\n.lil-gui .lil-gui .lil-gui > .title {\n border: none;\n}\n.lil-gui .lil-gui .lil-gui > .children {\n border: none;\n margin-left: var(--folder-indent);\n border-left: 2px solid var(--widget-color);\n}\n.lil-gui .lil-gui .controller {\n border: none;\n}\n\n.lil-gui label, .lil-gui input, .lil-gui button {\n -webkit-tap-highlight-color: transparent;\n}\n.lil-gui input {\n border: 0;\n outline: none;\n font-family: var(--font-family);\n font-size: var(--input-font-size);\n border-radius: var(--widget-border-radius);\n height: var(--widget-height);\n background: var(--widget-color);\n color: var(--text-color);\n width: 100%;\n}\n@media (hover: hover) {\n .lil-gui input:hover {\n background: var(--hover-color);\n }\n .lil-gui input:active {\n background: var(--focus-color);\n }\n}\n.lil-gui input:disabled {\n opacity: 1;\n}\n.lil-gui input[type=text],\n.lil-gui input[type=number] {\n padding: var(--widget-padding);\n -moz-appearance: textfield;\n}\n.lil-gui input[type=text]:focus,\n.lil-gui input[type=number]:focus {\n background: var(--focus-color);\n}\n.lil-gui input[type=checkbox] {\n appearance: none;\n width: var(--checkbox-size);\n height: var(--checkbox-size);\n border-radius: var(--widget-border-radius);\n text-align: center;\n cursor: pointer;\n}\n.lil-gui input[type=checkbox]:checked:before {\n font-family: \"lil-gui\";\n content: \"✓\";\n font-size: var(--checkbox-size);\n line-height: var(--checkbox-size);\n}\n@media (hover: hover) {\n .lil-gui input[type=checkbox]:focus {\n box-shadow: inset 0 0 0 1px var(--focus-color);\n }\n}\n.lil-gui button {\n outline: none;\n cursor: pointer;\n font-family: var(--font-family);\n font-size: var(--font-size);\n color: var(--text-color);\n width: 100%;\n height: var(--widget-height);\n text-transform: none;\n background: var(--widget-color);\n border-radius: var(--widget-border-radius);\n border: none;\n}\n@media (hover: hover) {\n .lil-gui button:hover {\n background: var(--hover-color);\n }\n .lil-gui button:focus {\n box-shadow: inset 0 0 0 1px var(--focus-color);\n }\n}\n.lil-gui button:active {\n background: var(--focus-color);\n}\n\n@font-face {\n font-family: \"lil-gui\";\n src: url(\"data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAAUsAAsAAAAACJwAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABCAAAAH4AAADAImwmYE9TLzIAAAGIAAAAPwAAAGBKqH5SY21hcAAAAcgAAAD0AAACrukyyJBnbHlmAAACvAAAAF8AAACEIZpWH2hlYWQAAAMcAAAAJwAAADZfcj2zaGhlYQAAA0QAAAAYAAAAJAC5AHhobXR4AAADXAAAABAAAABMAZAAAGxvY2EAAANsAAAAFAAAACgCEgIybWF4cAAAA4AAAAAeAAAAIAEfABJuYW1lAAADoAAAASIAAAIK9SUU/XBvc3QAAATEAAAAZgAAAJCTcMc2eJxVjbEOgjAURU+hFRBK1dGRL+ALnAiToyMLEzFpnPz/eAshwSa97517c/MwwJmeB9kwPl+0cf5+uGPZXsqPu4nvZabcSZldZ6kfyWnomFY/eScKqZNWupKJO6kXN3K9uCVoL7iInPr1X5baXs3tjuMqCtzEuagm/AAlzQgPAAB4nGNgYRBlnMDAysDAYM/gBiT5oLQBAwuDJAMDEwMrMwNWEJDmmsJwgCFeXZghBcjlZMgFCzOiKOIFAB71Bb8AeJy1kjFuwkAQRZ+DwRAwBtNQRUGKQ8OdKCAWUhAgKLhIuAsVSpWz5Bbkj3dEgYiUIszqWdpZe+Z7/wB1oCYmIoboiwiLT2WjKl/jscrHfGg/pKdMkyklC5Zs2LEfHYpjcRoPzme9MWWmk3dWbK9ObkWkikOetJ554fWyoEsmdSlt+uR0pCJR34b6t/TVg1SY3sYvdf8vuiKrpyaDXDISiegp17p7579Gp3p++y7HPAiY9pmTibljrr85qSidtlg4+l25GLCaS8e6rRxNBmsnERunKbaOObRz7N72ju5vdAjYpBXHgJylOAVsMseDAPEP8LYoUHicY2BiAAEfhiAGJgZWBgZ7RnFRdnVJELCQlBSRlATJMoLV2DK4glSYs6ubq5vbKrJLSbGrgEmovDuDJVhe3VzcXFwNLCOILB/C4IuQ1xTn5FPilBTj5FPmBAB4WwoqAHicY2BkYGAA4sk1sR/j+W2+MnAzpDBgAyEMQUCSg4EJxAEAwUgFHgB4nGNgZGBgSGFggJMhDIwMqEAYAByHATJ4nGNgAIIUNEwmAABl3AGReJxjYAACIQYlBiMGJ3wQAEcQBEV4nGNgZGBgEGZgY2BiAAEQyQWEDAz/wXwGAAsPATIAAHicXdBNSsNAHAXwl35iA0UQXYnMShfS9GPZA7T7LgIu03SSpkwzYTIt1BN4Ak/gKTyAeCxfw39jZkjymzcvAwmAW/wgwHUEGDb36+jQQ3GXGot79L24jxCP4gHzF/EIr4jEIe7wxhOC3g2TMYy4Q7+Lu/SHuEd/ivt4wJd4wPxbPEKMX3GI5+DJFGaSn4qNzk8mcbKSR6xdXdhSzaOZJGtdapd4vVPbi6rP+cL7TGXOHtXKll4bY1Xl7EGnPtp7Xy2n00zyKLVHfkHBa4IcJ2oD3cgggWvt/V/FbDrUlEUJhTn/0azVWbNTNr0Ens8de1tceK9xZmfB1CPjOmPH4kitmvOubcNpmVTN3oFJyjzCvnmrwhJTzqzVj9jiSX911FjeAAB4nG3HMRKCMBBA0f0giiKi4DU8k0V2GWbIZDOh4PoWWvq6J5V8If9NVNQcaDhyouXMhY4rPTcG7jwYmXhKq8Wz+p762aNaeYXom2n3m2dLTVgsrCgFJ7OTmIkYbwIbC6vIB7WmFfAAAA==\") format(\"woff\");\n}`;\n\nfunction _injectStyles( cssContent ) {\n\tconst injected = document.createElement( 'style' );\n\tinjected.innerHTML = cssContent;\n\tconst before = document.querySelector( 'head link[rel=stylesheet], head style' );\n\tif ( before ) {\n\t\tdocument.head.insertBefore( injected, before );\n\t} else {\n\t\tdocument.head.appendChild( injected );\n\t}\n}\n\nlet stylesInjected = false;\n\nclass GUI {\n\n\t/**\n\t * Creates a panel that holds controllers.\n\t * @example\n\t * new GUI();\n\t * new GUI( { container: document.getElementById( 'custom' ) } );\n\t *\n\t * @param {object} [options]\n\t * @param {boolean} [options.autoPlace=true]\n\t * Adds the GUI to `document.body` and fixes it to the top right of the page.\n\t *\n\t * @param {HTMLElement} [options.container]\n\t * Adds the GUI to this DOM element. Overrides `autoPlace`.\n\t *\n\t * @param {number} [options.width=245]\n\t * Width of the GUI in pixels, usually set when name labels become too long. Note that you can make\n\t * name labels wider in CSS with `.lil‑gui { ‑‑name‑width: 55% }`.\n\t *\n\t * @param {string} [options.title=Controls]\n\t * Name to display in the title bar.\n\t *\n\t * @param {boolean} [options.closeFolders=false]\n\t * Pass `true` to close all folders in this GUI by default.\n\t *\n\t * @param {boolean} [options.injectStyles=true]\n\t * Injects the default stylesheet into the page if this is the first GUI.\n\t * Pass `false` to use your own stylesheet.\n\t *\n\t * @param {number} [options.touchStyles=true]\n\t * Makes controllers larger on touch devices. Pass `false` to disable touch styles.\n\t *\n\t * @param {GUI} [options.parent]\n\t * Adds this GUI as a child in another GUI. Usually this is done for you by `addFolder()`.\n\t *\n\t */\n\tconstructor( {\n\t\tparent,\n\t\tautoPlace = parent === undefined,\n\t\tcontainer,\n\t\twidth,\n\t\ttitle = 'Controls',\n\t\tcloseFolders = false,\n\t\tinjectStyles = true,\n\t\ttouchStyles = true\n\t} = {} ) {\n\n\t\t/**\n\t\t * The GUI containing this folder, or `undefined` if this is the root GUI.\n\t\t * @type {GUI}\n\t\t */\n\t\tthis.parent = parent;\n\n\t\t/**\n\t\t * The top level GUI containing this folder, or `this` if this is the root GUI.\n\t\t * @type {GUI}\n\t\t */\n\t\tthis.root = parent ? parent.root : this;\n\n\t\t/**\n\t\t * The list of controllers and folders contained by this GUI.\n\t\t * @type {Array}\n\t\t */\n\t\tthis.children = [];\n\n\t\t/**\n\t\t * The list of controllers contained by this GUI.\n\t\t * @type {Array}\n\t\t */\n\t\tthis.controllers = [];\n\n\t\t/**\n\t\t * The list of folders contained by this GUI.\n\t\t * @type {Array}\n\t\t */\n\t\tthis.folders = [];\n\n\t\t/**\n\t\t * Used to determine if the GUI is closed. Use `gui.open()` or `gui.close()` to change this.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._closed = false;\n\n\t\t/**\n\t\t * Used to determine if the GUI is hidden. Use `gui.show()` or `gui.hide()` to change this.\n\t\t * @type {boolean}\n\t\t */\n\t\tthis._hidden = false;\n\n\t\t/**\n\t\t * The outermost container element.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.domElement = document.createElement( 'div' );\n\t\tthis.domElement.classList.add( 'lil-gui' );\n\n\t\t/**\n\t\t * The DOM element that contains the title.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$title = document.createElement( 'div' );\n\t\tthis.$title.classList.add( 'title' );\n\t\tthis.$title.setAttribute( 'role', 'button' );\n\t\tthis.$title.setAttribute( 'aria-expanded', true );\n\t\tthis.$title.setAttribute( 'tabindex', 0 );\n\n\t\tthis.$title.addEventListener( 'click', () => this.openAnimated( this._closed ) );\n\t\tthis.$title.addEventListener( 'keydown', e => {\n\t\t\tif ( e.code === 'Enter' || e.code === 'Space' ) {\n\t\t\t\te.preventDefault();\n\t\t\t\tthis.$title.click();\n\t\t\t}\n\t\t} );\n\n\t\t// enables :active pseudo class on mobile\n\t\tthis.$title.addEventListener( 'touchstart', () => {}, { passive: true } );\n\n\t\t/**\n\t\t * The DOM element that contains children.\n\t\t * @type {HTMLElement}\n\t\t */\n\t\tthis.$children = document.createElement( 'div' );\n\t\tthis.$children.classList.add( 'children' );\n\n\t\tthis.domElement.appendChild( this.$title );\n\t\tthis.domElement.appendChild( this.$children );\n\n\t\tthis.title( title );\n\n\t\tif ( this.parent ) {\n\n\t\t\tthis.parent.children.push( this );\n\t\t\tthis.parent.folders.push( this );\n\n\t\t\tthis.parent.$children.appendChild( this.domElement );\n\n\t\t\t// Stop the constructor early, everything onward only applies to root GUI's\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.domElement.classList.add( 'root' );\n\n\t\tif ( touchStyles ) {\n\t\t\tthis.domElement.classList.add( 'allow-touch-styles' );\n\t\t}\n\n\t\t// Inject stylesheet if we haven't done that yet\n\t\tif ( !stylesInjected && injectStyles ) {\n\t\t\t_injectStyles( stylesheet );\n\t\t\tstylesInjected = true;\n\t\t}\n\n\t\tif ( container ) {\n\n\t\t\tcontainer.appendChild( this.domElement );\n\n\t\t} else if ( autoPlace ) {\n\n\t\t\tthis.domElement.classList.add( 'autoPlace' );\n\t\t\tdocument.body.appendChild( this.domElement );\n\n\t\t}\n\n\t\tif ( width ) {\n\t\t\tthis.domElement.style.setProperty( '--width', width + 'px' );\n\t\t}\n\n\t\tthis._closeFolders = closeFolders;\n\n\t}\n\n\t/**\n\t * Adds a controller to the GUI, inferring controller type using the `typeof` operator.\n\t * @example\n\t * gui.add( object, 'property' );\n\t * gui.add( object, 'number', 0, 100, 1 );\n\t * gui.add( object, 'options', [ 1, 2, 3 ] );\n\t *\n\t * @param {object} object The object the controller will modify.\n\t * @param {string} property Name of the property to control.\n\t * @param {number|object|Array} [$1] Minimum value for number controllers, or the set of\n\t * selectable values for a dropdown.\n\t * @param {number} [max] Maximum value for number controllers.\n\t * @param {number} [step] Step value for number controllers.\n\t * @returns {Controller}\n\t */\n\tadd( object, property, $1, max, step ) {\n\n\t\tif ( Object( $1 ) === $1 ) {\n\n\t\t\treturn new OptionController( this, object, property, $1 );\n\n\t\t}\n\n\t\tconst initialValue = object[ property ];\n\n\t\tswitch ( typeof initialValue ) {\n\n\t\t\tcase 'number':\n\n\t\t\t\treturn new NumberController( this, object, property, $1, max, step );\n\n\t\t\tcase 'boolean':\n\n\t\t\t\treturn new BooleanController( this, object, property );\n\n\t\t\tcase 'string':\n\n\t\t\t\treturn new StringController( this, object, property );\n\n\t\t\tcase 'function':\n\n\t\t\t\treturn new FunctionController( this, object, property );\n\n\t\t}\n\n\t\tconsole.error( `gui.add failed\n\tproperty:`, property, `\n\tobject:`, object, `\n\tvalue:`, initialValue );\n\n\t}\n\n\t/**\n\t * Adds a color controller to the GUI.\n\t * @example\n\t * params = {\n\t * \tcssColor: '#ff00ff',\n\t * \trgbColor: { r: 0, g: 0.2, b: 0.4 },\n\t * \tcustomRange: [ 0, 127, 255 ],\n\t * };\n\t *\n\t * gui.addColor( params, 'cssColor' );\n\t * gui.addColor( params, 'rgbColor' );\n\t * gui.addColor( params, 'customRange', 255 );\n\t *\n\t * @param {object} object The object the controller will modify.\n\t * @param {string} property Name of the property to control.\n\t * @param {number} rgbScale Maximum value for a color channel when using an RGB color. You may\n\t * need to set this to 255 if your colors are too bright.\n\t * @returns {Controller}\n\t */\n\taddColor( object, property, rgbScale = 1 ) {\n\t\treturn new ColorController( this, object, property, rgbScale );\n\t}\n\n\t/**\n\t * Adds a folder to the GUI, which is just another GUI. This method returns\n\t * the nested GUI so you can add controllers to it.\n\t * @example\n\t * const folder = gui.addFolder( 'Position' );\n\t * folder.add( position, 'x' );\n\t * folder.add( position, 'y' );\n\t * folder.add( position, 'z' );\n\t *\n\t * @param {string} title Name to display in the folder's title bar.\n\t * @returns {GUI}\n\t */\n\taddFolder( title ) {\n\t\tconst folder = new GUI( { parent: this, title } );\n\t\tif ( this.root._closeFolders ) folder.close();\n\t\treturn folder;\n\t}\n\n\t/**\n\t * Recalls values that were saved with `gui.save()`.\n\t * @param {object} obj\n\t * @param {boolean} recursive Pass false to exclude folders descending from this GUI.\n\t * @returns {this}\n\t */\n\tload( obj, recursive = true ) {\n\n\t\tif ( obj.controllers ) {\n\n\t\t\tthis.controllers.forEach( c => {\n\n\t\t\t\tif ( c instanceof FunctionController ) return;\n\n\t\t\t\tif ( c._name in obj.controllers ) {\n\t\t\t\t\tc.load( obj.controllers[ c._name ] );\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t}\n\n\t\tif ( recursive && obj.folders ) {\n\n\t\t\tthis.folders.forEach( f => {\n\n\t\t\t\tif ( f._title in obj.folders ) {\n\t\t\t\t\tf.load( obj.folders[ f._title ] );\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Returns an object mapping controller names to values. The object can be passed to `gui.load()` to\n\t * recall these values.\n\t * @example\n\t * {\n\t * \tcontrollers: {\n\t * \t\tprop1: 1,\n\t * \t\tprop2: 'value',\n\t * \t\t...\n\t * \t},\n\t * \tfolders: {\n\t * \t\tfolderName1: { controllers, folders },\n\t * \t\tfolderName2: { controllers, folders }\n\t * \t\t...\n\t * \t}\n\t * }\n\t *\n\t * @param {boolean} recursive Pass false to exclude folders descending from this GUI.\n\t * @returns {object}\n\t */\n\tsave( recursive = true ) {\n\n\t\tconst obj = {\n\t\t\tcontrollers: {},\n\t\t\tfolders: {}\n\t\t};\n\n\t\tthis.controllers.forEach( c => {\n\n\t\t\tif ( c instanceof FunctionController ) return;\n\n\t\t\tif ( c._name in obj.controllers ) {\n\t\t\t\tthrow new Error( `Cannot save GUI with duplicate property \"${c._name}\"` );\n\t\t\t}\n\n\t\t\tobj.controllers[ c._name ] = c.save();\n\n\t\t} );\n\n\t\tif ( recursive ) {\n\n\t\t\tthis.folders.forEach( f => {\n\n\t\t\t\tif ( f._title in obj.folders ) {\n\t\t\t\t\tthrow new Error( `Cannot save GUI with duplicate folder \"${f._title}\"` );\n\t\t\t\t}\n\n\t\t\t\tobj.folders[ f._title ] = f.save();\n\n\t\t\t} );\n\n\t\t}\n\n\t\treturn obj;\n\n\t}\n\n\t/**\n\t * Opens a GUI or folder. GUI and folders are open by default.\n\t * @param {boolean} open Pass false to close.\n\t * @returns {this}\n\t * @example\n\t * gui.open(); // open\n\t * gui.open( false ); // close\n\t * gui.open( gui._closed ); // toggle\n\t */\n\topen( open = true ) {\n\n\t\tthis._setClosed( !open );\n\n\t\tthis.$title.setAttribute( 'aria-expanded', !this._closed );\n\t\tthis.domElement.classList.toggle( 'closed', this._closed );\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Closes the GUI.\n\t * @returns {this}\n\t */\n\tclose() {\n\t\treturn this.open( false );\n\t}\n\n\t_setClosed( closed ) {\n\t\tif ( this._closed === closed ) return;\n\t\tthis._closed = closed;\n\t\tthis._callOnOpenClose( this );\n\t}\n\n\t/**\n\t * Shows the GUI after it's been hidden.\n\t * @param {boolean} show\n\t * @returns {this}\n\t * @example\n\t * gui.show();\n\t * gui.show( false ); // hide\n\t * gui.show( gui._hidden ); // toggle\n\t */\n\tshow( show = true ) {\n\n\t\tthis._hidden = !show;\n\n\t\tthis.domElement.style.display = this._hidden ? 'none' : '';\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Hides the GUI.\n\t * @returns {this}\n\t */\n\thide() {\n\t\treturn this.show( false );\n\t}\n\n\topenAnimated( open = true ) {\n\n\t\t// set state immediately\n\t\tthis._setClosed( !open );\n\n\t\tthis.$title.setAttribute( 'aria-expanded', !this._closed );\n\n\t\t// wait for next frame to measure $children\n\t\trequestAnimationFrame( () => {\n\n\t\t\t// explicitly set initial height for transition\n\t\t\tconst initialHeight = this.$children.clientHeight;\n\t\t\tthis.$children.style.height = initialHeight + 'px';\n\n\t\t\tthis.domElement.classList.add( 'transition' );\n\n\t\t\tconst onTransitionEnd = e => {\n\t\t\t\tif ( e.target !== this.$children ) return;\n\t\t\t\tthis.$children.style.height = '';\n\t\t\t\tthis.domElement.classList.remove( 'transition' );\n\t\t\t\tthis.$children.removeEventListener( 'transitionend', onTransitionEnd );\n\t\t\t};\n\n\t\t\tthis.$children.addEventListener( 'transitionend', onTransitionEnd );\n\n\t\t\t// todo: this is wrong if children's scrollHeight makes for a gui taller than maxHeight\n\t\t\tconst targetHeight = !open ? 0 : this.$children.scrollHeight;\n\n\t\t\tthis.domElement.classList.toggle( 'closed', !open );\n\n\t\t\trequestAnimationFrame( () => {\n\t\t\t\tthis.$children.style.height = targetHeight + 'px';\n\t\t\t} );\n\n\t\t} );\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Change the title of this GUI.\n\t * @param {string} title\n\t * @returns {this}\n\t */\n\ttitle( title ) {\n\t\t/**\n\t\t * Current title of the GUI. Use `gui.title( 'Title' )` to modify this value.\n\t\t * @type {string}\n\t\t */\n\t\tthis._title = title;\n\t\tthis.$title.textContent = title;\n\t\treturn this;\n\t}\n\n\t/**\n\t * Resets all controllers to their initial values.\n\t * @param {boolean} recursive Pass false to exclude folders descending from this GUI.\n\t * @returns {this}\n\t */\n\treset( recursive = true ) {\n\t\tconst controllers = recursive ? this.controllersRecursive() : this.controllers;\n\t\tcontrollers.forEach( c => c.reset() );\n\t\treturn this;\n\t}\n\n\t/**\n\t * Pass a function to be called whenever a controller in this GUI changes.\n\t * @param {function({object:object, property:string, value:any, controller:Controller})} callback\n\t * @returns {this}\n\t * @example\n\t * gui.onChange( event => {\n\t * \tevent.object // object that was modified\n\t * \tevent.property // string, name of property\n\t * \tevent.value // new value of controller\n\t * \tevent.controller // controller that was modified\n\t * } );\n\t */\n\tonChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onChange` events. Don't modify this value\n\t\t * directly. Use the `gui.onChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onChange = callback;\n\t\treturn this;\n\t}\n\n\t_callOnChange( controller ) {\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._callOnChange( controller );\n\t\t}\n\n\t\tif ( this._onChange !== undefined ) {\n\t\t\tthis._onChange.call( this, {\n\t\t\t\tobject: controller.object,\n\t\t\t\tproperty: controller.property,\n\t\t\t\tvalue: controller.getValue(),\n\t\t\t\tcontroller\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Pass a function to be called whenever a controller in this GUI has finished changing.\n\t * @param {function({object:object, property:string, value:any, controller:Controller})} callback\n\t * @returns {this}\n\t * @example\n\t * gui.onFinishChange( event => {\n\t * \tevent.object // object that was modified\n\t * \tevent.property // string, name of property\n\t * \tevent.value // new value of controller\n\t * \tevent.controller // controller that was modified\n\t * } );\n\t */\n\tonFinishChange( callback ) {\n\t\t/**\n\t\t * Used to access the function bound to `onFinishChange` events. Don't modify this value\n\t\t * directly. Use the `gui.onFinishChange( callback )` method instead.\n\t\t * @type {Function}\n\t\t */\n\t\tthis._onFinishChange = callback;\n\t\treturn this;\n\t}\n\n\t_callOnFinishChange( controller ) {\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._callOnFinishChange( controller );\n\t\t}\n\n\t\tif ( this._onFinishChange !== undefined ) {\n\t\t\tthis._onFinishChange.call( this, {\n\t\t\t\tobject: controller.object,\n\t\t\t\tproperty: controller.property,\n\t\t\t\tvalue: controller.getValue(),\n\t\t\t\tcontroller\n\t\t\t} );\n\t\t}\n\t}\n\n\t/**\n\t * Pass a function to be called when this GUI or its descendants are opened or closed.\n\t * @param {function(GUI)} callback\n\t * @returns {this}\n\t * @example\n\t * gui.onOpenClose( changedGUI => {\n\t * \tconsole.log( changedGUI._closed );\n\t * } );\n\t */\n\tonOpenClose( callback ) {\n\t\tthis._onOpenClose = callback;\n\t\treturn this;\n\t}\n\n\t_callOnOpenClose( changedGUI ) {\n\t\tif ( this.parent ) {\n\t\t\tthis.parent._callOnOpenClose( changedGUI );\n\t\t}\n\n\t\tif ( this._onOpenClose !== undefined ) {\n\t\t\tthis._onOpenClose.call( this, changedGUI );\n\t\t}\n\t}\n\n\t/**\n\t * Destroys all DOM elements and event listeners associated with this GUI.\n\t */\n\tdestroy() {\n\n\t\tif ( this.parent ) {\n\t\t\tthis.parent.children.splice( this.parent.children.indexOf( this ), 1 );\n\t\t\tthis.parent.folders.splice( this.parent.folders.indexOf( this ), 1 );\n\t\t}\n\n\t\tif ( this.domElement.parentElement ) {\n\t\t\tthis.domElement.parentElement.removeChild( this.domElement );\n\t\t}\n\n\t\tArray.from( this.children ).forEach( c => c.destroy() );\n\n\t}\n\n\t/**\n\t * Returns an array of controllers contained by this GUI and its descendents.\n\t * @returns {Controller[]}\n\t */\n\tcontrollersRecursive() {\n\t\tlet controllers = Array.from( this.controllers );\n\t\tthis.folders.forEach( f => {\n\t\t\tcontrollers = controllers.concat( f.controllersRecursive() );\n\t\t} );\n\t\treturn controllers;\n\t}\n\n\t/**\n\t * Returns an array of folders contained by this GUI and its descendents.\n\t * @returns {GUI[]}\n\t */\n\tfoldersRecursive() {\n\t\tlet folders = Array.from( this.folders );\n\t\tthis.folders.forEach( f => {\n\t\t\tfolders = folders.concat( f.foldersRecursive() );\n\t\t} );\n\t\treturn folders;\n\t}\n\n}\n\n/* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (GUI);\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNjM4LmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFBQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLGtDQUFrQyx3QkFBd0I7O0FBRTFEO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFVBQVU7QUFDdEIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFVBQVU7QUFDdEIsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckIsY0FBYztBQUNkO0FBQ0E7QUFDQSxnQ0FBZ0M7QUFDaEMsK0NBQStDO0FBQy9DO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckIsY0FBYztBQUNkO0FBQ0E7QUFDQSxpQ0FBaUM7QUFDakMsaURBQWlEO0FBQ2pEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCLGNBQWM7QUFDZDtBQUNBO0FBQ0EsOEJBQThCO0FBQzlCLDJDQUEyQztBQUMzQztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUMsb0JBQW9CO0FBQzNEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksY0FBYztBQUMxQixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVksUUFBUTtBQUNwQixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVksUUFBUTtBQUNwQixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCLGNBQWM7QUFDZDtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVksS0FBSztBQUNqQixjQUFjO0FBQ2Q7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw4Q0FBOEMsRUFBRTs7QUFFaEQ7O0FBRUEsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsRUFBRTtBQUNGOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFO0FBQ0YsZ0JBQWdCLFNBQVM7O0FBRXpCOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBLHVEQUF1RCxJQUFJLGdCQUFnQjs7QUFFM0U7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esb0RBQW9ELGlCQUFpQjtBQUNyRTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUEsd0RBQXdELGlCQUFpQjtBQUN6RTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLCtEQUErRCxpQkFBaUI7QUFDaEYscURBQXFELGlCQUFpQjs7QUFFdEU7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLDZDQUE2QyxLQUFLO0FBQ2xEOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxRQUFRLGlCQUFpQjs7QUFFekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0EsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSx1Q0FBdUMsY0FBYztBQUNyRCxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxlQUFlLGlEQUFpRDtBQUNoRTtBQUNBLFlBQVksUUFBUTtBQUNwQixZQUFZLFNBQVM7QUFDckI7QUFDQTtBQUNBLFlBQVksYUFBYTtBQUN6QjtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCO0FBQ0EsOENBQThDLG1CQUFtQjtBQUNqRTtBQUNBLFlBQVksUUFBUTtBQUNwQjtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckI7QUFDQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCO0FBQ0E7QUFDQSxZQUFZLEtBQUs7QUFDakI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRyxLQUFLOztBQUVSO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0Esc0RBQXNELElBQUksZ0JBQWdCOztBQUUxRTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCLFlBQVksUUFBUTtBQUNwQixZQUFZLHFCQUFxQjtBQUNqQztBQUNBLFlBQVksUUFBUTtBQUNwQixZQUFZLFFBQVE7QUFDcEIsY0FBYztBQUNkO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLGlCQUFpQixzQkFBc0I7QUFDdkM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsWUFBWSxRQUFRO0FBQ3BCLFlBQVksUUFBUTtBQUNwQjtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsY0FBYztBQUNkO0FBQ0E7QUFDQSw0QkFBNEIsc0JBQXNCO0FBQ2xEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxRQUFRO0FBQ3BCLFlBQVksU0FBUztBQUNyQixjQUFjO0FBQ2Q7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQSxxQkFBcUIsc0JBQXNCO0FBQzNDLHFCQUFxQjtBQUNyQjtBQUNBO0FBQ0E7QUFDQTtBQUNBLFlBQVksU0FBUztBQUNyQixjQUFjO0FBQ2Q7QUFDQTs7QUFFQTtBQUNBLGtCQUFrQjtBQUNsQjtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsaUVBQWlFLFFBQVE7QUFDekU7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBLGdFQUFnRSxTQUFTO0FBQ3pFOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLFlBQVksU0FBUztBQUNyQixjQUFjO0FBQ2Q7QUFDQSxnQkFBZ0I7QUFDaEIsdUJBQXVCO0FBQ3ZCLDZCQUE2QjtBQUM3QjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFNBQVM7QUFDckIsY0FBYztBQUNkO0FBQ0E7QUFDQSx1QkFBdUI7QUFDdkIsNkJBQTZCO0FBQzdCO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQSxLQUFLOztBQUVMLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLFlBQVksUUFBUTtBQUNwQixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxTQUFTO0FBQ3JCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLFlBQVksVUFBVSxpRUFBaUUsR0FBRztBQUMxRixjQUFjO0FBQ2Q7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsTUFBTTtBQUNOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZO0FBQ1o7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTDtBQUNBOztBQUVBO0FBQ0E7QUFDQSxZQUFZLFVBQVUsaUVBQWlFLEdBQUc7QUFDMUYsY0FBYztBQUNkO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07QUFDTjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWSxlQUFlO0FBQzNCLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQSxNQUFNO0FBQ047QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7O0FBRUEsaUVBQWUsR0FBRyxFQUFDO0FBQ3NIIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy9saWwtZ3VpL2Rpc3QvbGlsLWd1aS5lc20uanM/YWZiMyJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIGxpbC1ndWlcbiAqIGh0dHBzOi8vbGlsLWd1aS5nZW9yZ2VhbHdheXMuY29tXG4gKiBAdmVyc2lvbiAwLjE5LjJcbiAqIEBhdXRob3IgR2VvcmdlIE1pY2hhZWwgQnJvd2VyXG4gKiBAbGljZW5zZSBNSVRcbiAqL1xuXG4vKipcbiAqIEJhc2UgY2xhc3MgZm9yIGFsbCBjb250cm9sbGVycy5cbiAqL1xuY2xhc3MgQ29udHJvbGxlciB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSwgY2xhc3NOYW1lLCBlbGVtZW50VHlwZSA9ICdkaXYnICkge1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIEdVSSB0aGF0IGNvbnRhaW5zIHRoaXMgY29udHJvbGxlci5cblx0XHQgKiBAdHlwZSB7R1VJfVxuXHRcdCAqL1xuXHRcdHRoaXMucGFyZW50ID0gcGFyZW50O1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIG9iamVjdCB0aGlzIGNvbnRyb2xsZXIgd2lsbCBtb2RpZnkuXG5cdFx0ICogQHR5cGUge29iamVjdH1cblx0XHQgKi9cblx0XHR0aGlzLm9iamVjdCA9IG9iamVjdDtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBuYW1lIG9mIHRoZSBwcm9wZXJ0eSB0byBjb250cm9sLlxuXHRcdCAqIEB0eXBlIHtzdHJpbmd9XG5cdFx0ICovXG5cdFx0dGhpcy5wcm9wZXJ0eSA9IHByb3BlcnR5O1xuXG5cdFx0LyoqXG5cdFx0ICogVXNlZCB0byBkZXRlcm1pbmUgaWYgdGhlIGNvbnRyb2xsZXIgaXMgZGlzYWJsZWQuXG5cdFx0ICogVXNlIGBjb250cm9sbGVyLmRpc2FibGUoIHRydWV8ZmFsc2UgKWAgdG8gbW9kaWZ5IHRoaXMgdmFsdWUuXG5cdFx0ICogQHR5cGUge2Jvb2xlYW59XG5cdFx0ICovXG5cdFx0dGhpcy5fZGlzYWJsZWQgPSBmYWxzZTtcblxuXHRcdC8qKlxuXHRcdCAqIFVzZWQgdG8gZGV0ZXJtaW5lIGlmIHRoZSBDb250cm9sbGVyIGlzIGhpZGRlbi5cblx0XHQgKiBVc2UgYGNvbnRyb2xsZXIuc2hvdygpYCBvciBgY29udHJvbGxlci5oaWRlKClgIHRvIGNoYW5nZSB0aGlzLlxuXHRcdCAqIEB0eXBlIHtib29sZWFufVxuXHRcdCAqL1xuXHRcdHRoaXMuX2hpZGRlbiA9IGZhbHNlO1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIHZhbHVlIG9mIGBvYmplY3RbIHByb3BlcnR5IF1gIHdoZW4gdGhlIGNvbnRyb2xsZXIgd2FzIGNyZWF0ZWQuXG5cdFx0ICogQHR5cGUge2FueX1cblx0XHQgKi9cblx0XHR0aGlzLmluaXRpYWxWYWx1ZSA9IHRoaXMuZ2V0VmFsdWUoKTtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBvdXRlcm1vc3QgY29udGFpbmVyIERPTSBlbGVtZW50IGZvciB0aGlzIGNvbnRyb2xsZXIuXG5cdFx0ICogQHR5cGUge0hUTUxFbGVtZW50fVxuXHRcdCAqL1xuXHRcdHRoaXMuZG9tRWxlbWVudCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoIGVsZW1lbnRUeXBlICk7XG5cdFx0dGhpcy5kb21FbGVtZW50LmNsYXNzTGlzdC5hZGQoICdjb250cm9sbGVyJyApO1xuXHRcdHRoaXMuZG9tRWxlbWVudC5jbGFzc0xpc3QuYWRkKCBjbGFzc05hbWUgKTtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBET00gZWxlbWVudCB0aGF0IGNvbnRhaW5zIHRoZSBjb250cm9sbGVyJ3MgbmFtZS5cblx0XHQgKiBAdHlwZSB7SFRNTEVsZW1lbnR9XG5cdFx0ICovXG5cdFx0dGhpcy4kbmFtZSA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdkaXYnICk7XG5cdFx0dGhpcy4kbmFtZS5jbGFzc0xpc3QuYWRkKCAnbmFtZScgKTtcblxuXHRcdENvbnRyb2xsZXIubmV4dE5hbWVJRCA9IENvbnRyb2xsZXIubmV4dE5hbWVJRCB8fCAwO1xuXHRcdHRoaXMuJG5hbWUuaWQgPSBgbGlsLWd1aS1uYW1lLSR7KytDb250cm9sbGVyLm5leHROYW1lSUR9YDtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBET00gZWxlbWVudCB0aGF0IGNvbnRhaW5zIHRoZSBjb250cm9sbGVyJ3MgXCJ3aWRnZXRcIiAod2hpY2ggZGlmZmVycyBieSBjb250cm9sbGVyIHR5cGUpLlxuXHRcdCAqIEB0eXBlIHtIVE1MRWxlbWVudH1cblx0XHQgKi9cblx0XHR0aGlzLiR3aWRnZXQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnZGl2JyApO1xuXHRcdHRoaXMuJHdpZGdldC5jbGFzc0xpc3QuYWRkKCAnd2lkZ2V0JyApO1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIERPTSBlbGVtZW50IHRoYXQgcmVjZWl2ZXMgdGhlIGRpc2FibGVkIGF0dHJpYnV0ZSB3aGVuIHVzaW5nIGRpc2FibGUoKS5cblx0XHQgKiBAdHlwZSB7SFRNTEVsZW1lbnR9XG5cdFx0ICovXG5cdFx0dGhpcy4kZGlzYWJsZSA9IHRoaXMuJHdpZGdldDtcblxuXHRcdHRoaXMuZG9tRWxlbWVudC5hcHBlbmRDaGlsZCggdGhpcy4kbmFtZSApO1xuXHRcdHRoaXMuZG9tRWxlbWVudC5hcHBlbmRDaGlsZCggdGhpcy4kd2lkZ2V0ICk7XG5cblx0XHQvLyBEb24ndCBmaXJlIGdsb2JhbCBrZXkgZXZlbnRzIHdoaWxlIHR5cGluZyBpbiBhIGNvbnRyb2xsZXJcblx0XHR0aGlzLmRvbUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCBlID0+IGUuc3RvcFByb3BhZ2F0aW9uKCkgKTtcblx0XHR0aGlzLmRvbUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ2tleXVwJywgZSA9PiBlLnN0b3BQcm9wYWdhdGlvbigpICk7XG5cblx0XHR0aGlzLnBhcmVudC5jaGlsZHJlbi5wdXNoKCB0aGlzICk7XG5cdFx0dGhpcy5wYXJlbnQuY29udHJvbGxlcnMucHVzaCggdGhpcyApO1xuXG5cdFx0dGhpcy5wYXJlbnQuJGNoaWxkcmVuLmFwcGVuZENoaWxkKCB0aGlzLmRvbUVsZW1lbnQgKTtcblxuXHRcdHRoaXMuX2xpc3RlbkNhbGxiYWNrID0gdGhpcy5fbGlzdGVuQ2FsbGJhY2suYmluZCggdGhpcyApO1xuXG5cdFx0dGhpcy5uYW1lKCBwcm9wZXJ0eSApO1xuXG5cdH1cblxuXHQvKipcblx0ICogU2V0cyB0aGUgbmFtZSBvZiB0aGUgY29udHJvbGxlciBhbmQgaXRzIGxhYmVsIGluIHRoZSBHVUkuXG5cdCAqIEBwYXJhbSB7c3RyaW5nfSBuYW1lXG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKi9cblx0bmFtZSggbmFtZSApIHtcblx0XHQvKipcblx0XHQgKiBUaGUgY29udHJvbGxlcidzIG5hbWUuIFVzZSBgY29udHJvbGxlci5uYW1lKCAnTmFtZScgKWAgdG8gbW9kaWZ5IHRoaXMgdmFsdWUuXG5cdFx0ICogQHR5cGUge3N0cmluZ31cblx0XHQgKi9cblx0XHR0aGlzLl9uYW1lID0gbmFtZTtcblx0XHR0aGlzLiRuYW1lLnRleHRDb250ZW50ID0gbmFtZTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBQYXNzIGEgZnVuY3Rpb24gdG8gYmUgY2FsbGVkIHdoZW5ldmVyIHRoZSB2YWx1ZSBpcyBtb2RpZmllZCBieSB0aGlzIGNvbnRyb2xsZXIuXG5cdCAqIFRoZSBmdW5jdGlvbiByZWNlaXZlcyB0aGUgbmV3IHZhbHVlIGFzIGl0cyBmaXJzdCBwYXJhbWV0ZXIuIFRoZSB2YWx1ZSBvZiBgdGhpc2Agd2lsbCBiZSB0aGVcblx0ICogY29udHJvbGxlci5cblx0ICpcblx0ICogRm9yIGZ1bmN0aW9uIGNvbnRyb2xsZXJzLCB0aGUgYG9uQ2hhbmdlYCBjYWxsYmFjayB3aWxsIGJlIGZpcmVkIG9uIGNsaWNrLCBhZnRlciB0aGUgZnVuY3Rpb25cblx0ICogZXhlY3V0ZXMuXG5cdCAqIEBwYXJhbSB7RnVuY3Rpb259IGNhbGxiYWNrXG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKiBAZXhhbXBsZVxuXHQgKiBjb25zdCBjb250cm9sbGVyID0gZ3VpLmFkZCggb2JqZWN0LCAncHJvcGVydHknICk7XG5cdCAqXG5cdCAqIGNvbnRyb2xsZXIub25DaGFuZ2UoIGZ1bmN0aW9uKCB2ICkge1xuXHQgKiBcdGNvbnNvbGUubG9nKCAnVGhlIHZhbHVlIGlzIG5vdyAnICsgdiApO1xuXHQgKiBcdGNvbnNvbGUuYXNzZXJ0KCB0aGlzID09PSBjb250cm9sbGVyICk7XG5cdCAqIH0gKTtcblx0ICovXG5cdG9uQ2hhbmdlKCBjYWxsYmFjayApIHtcblx0XHQvKipcblx0XHQgKiBVc2VkIHRvIGFjY2VzcyB0aGUgZnVuY3Rpb24gYm91bmQgdG8gYG9uQ2hhbmdlYCBldmVudHMuIERvbid0IG1vZGlmeSB0aGlzIHZhbHVlIGRpcmVjdGx5LlxuXHRcdCAqIFVzZSB0aGUgYGNvbnRyb2xsZXIub25DaGFuZ2UoIGNhbGxiYWNrIClgIG1ldGhvZCBpbnN0ZWFkLlxuXHRcdCAqIEB0eXBlIHtGdW5jdGlvbn1cblx0XHQgKi9cblx0XHR0aGlzLl9vbkNoYW5nZSA9IGNhbGxiYWNrO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIENhbGxzIHRoZSBvbkNoYW5nZSBtZXRob2RzIG9mIHRoaXMgY29udHJvbGxlciBhbmQgaXRzIHBhcmVudCBHVUkuXG5cdCAqIEBwcm90ZWN0ZWRcblx0ICovXG5cdF9jYWxsT25DaGFuZ2UoKSB7XG5cblx0XHR0aGlzLnBhcmVudC5fY2FsbE9uQ2hhbmdlKCB0aGlzICk7XG5cblx0XHRpZiAoIHRoaXMuX29uQ2hhbmdlICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHR0aGlzLl9vbkNoYW5nZS5jYWxsKCB0aGlzLCB0aGlzLmdldFZhbHVlKCkgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9jaGFuZ2VkID0gdHJ1ZTtcblxuXHR9XG5cblx0LyoqXG5cdCAqIFBhc3MgYSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgYWZ0ZXIgdGhpcyBjb250cm9sbGVyIGhhcyBiZWVuIG1vZGlmaWVkIGFuZCBsb3NlcyBmb2N1cy5cblx0ICogQHBhcmFtIHtGdW5jdGlvbn0gY2FsbGJhY2tcblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqIEBleGFtcGxlXG5cdCAqIGNvbnN0IGNvbnRyb2xsZXIgPSBndWkuYWRkKCBvYmplY3QsICdwcm9wZXJ0eScgKTtcblx0ICpcblx0ICogY29udHJvbGxlci5vbkZpbmlzaENoYW5nZSggZnVuY3Rpb24oIHYgKSB7XG5cdCAqIFx0Y29uc29sZS5sb2coICdDaGFuZ2VzIGNvbXBsZXRlOiAnICsgdiApO1xuXHQgKiBcdGNvbnNvbGUuYXNzZXJ0KCB0aGlzID09PSBjb250cm9sbGVyICk7XG5cdCAqIH0gKTtcblx0ICovXG5cdG9uRmluaXNoQ2hhbmdlKCBjYWxsYmFjayApIHtcblx0XHQvKipcblx0XHQgKiBVc2VkIHRvIGFjY2VzcyB0aGUgZnVuY3Rpb24gYm91bmQgdG8gYG9uRmluaXNoQ2hhbmdlYCBldmVudHMuIERvbid0IG1vZGlmeSB0aGlzIHZhbHVlXG5cdFx0ICogZGlyZWN0bHkuIFVzZSB0aGUgYGNvbnRyb2xsZXIub25GaW5pc2hDaGFuZ2UoIGNhbGxiYWNrIClgIG1ldGhvZCBpbnN0ZWFkLlxuXHRcdCAqIEB0eXBlIHtGdW5jdGlvbn1cblx0XHQgKi9cblx0XHR0aGlzLl9vbkZpbmlzaENoYW5nZSA9IGNhbGxiYWNrO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNob3VsZCBiZSBjYWxsZWQgYnkgQ29udHJvbGxlciB3aGVuIGl0cyB3aWRnZXRzIGxvc2UgZm9jdXMuXG5cdCAqIEBwcm90ZWN0ZWRcblx0ICovXG5cdF9jYWxsT25GaW5pc2hDaGFuZ2UoKSB7XG5cblx0XHRpZiAoIHRoaXMuX2NoYW5nZWQgKSB7XG5cblx0XHRcdHRoaXMucGFyZW50Ll9jYWxsT25GaW5pc2hDaGFuZ2UoIHRoaXMgKTtcblxuXHRcdFx0aWYgKCB0aGlzLl9vbkZpbmlzaENoYW5nZSAhPT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHR0aGlzLl9vbkZpbmlzaENoYW5nZS5jYWxsKCB0aGlzLCB0aGlzLmdldFZhbHVlKCkgKTtcblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHRoaXMuX2NoYW5nZWQgPSBmYWxzZTtcblxuXHR9XG5cblx0LyoqXG5cdCAqIFNldHMgdGhlIGNvbnRyb2xsZXIgYmFjayB0byBpdHMgaW5pdGlhbCB2YWx1ZS5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRyZXNldCgpIHtcblx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLmluaXRpYWxWYWx1ZSApO1xuXHRcdHRoaXMuX2NhbGxPbkZpbmlzaENoYW5nZSgpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIEVuYWJsZXMgdGhpcyBjb250cm9sbGVyLlxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IGVuYWJsZWRcblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqIEBleGFtcGxlXG5cdCAqIGNvbnRyb2xsZXIuZW5hYmxlKCk7XG5cdCAqIGNvbnRyb2xsZXIuZW5hYmxlKCBmYWxzZSApOyAvLyBkaXNhYmxlXG5cdCAqIGNvbnRyb2xsZXIuZW5hYmxlKCBjb250cm9sbGVyLl9kaXNhYmxlZCApOyAvLyB0b2dnbGVcblx0ICovXG5cdGVuYWJsZSggZW5hYmxlZCA9IHRydWUgKSB7XG5cdFx0cmV0dXJuIHRoaXMuZGlzYWJsZSggIWVuYWJsZWQgKTtcblx0fVxuXG5cdC8qKlxuXHQgKiBEaXNhYmxlcyB0aGlzIGNvbnRyb2xsZXIuXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gZGlzYWJsZWRcblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqIEBleGFtcGxlXG5cdCAqIGNvbnRyb2xsZXIuZGlzYWJsZSgpO1xuXHQgKiBjb250cm9sbGVyLmRpc2FibGUoIGZhbHNlICk7IC8vIGVuYWJsZVxuXHQgKiBjb250cm9sbGVyLmRpc2FibGUoICFjb250cm9sbGVyLl9kaXNhYmxlZCApOyAvLyB0b2dnbGVcblx0ICovXG5cdGRpc2FibGUoIGRpc2FibGVkID0gdHJ1ZSApIHtcblxuXHRcdGlmICggZGlzYWJsZWQgPT09IHRoaXMuX2Rpc2FibGVkICkgcmV0dXJuIHRoaXM7XG5cblx0XHR0aGlzLl9kaXNhYmxlZCA9IGRpc2FibGVkO1xuXG5cdFx0dGhpcy5kb21FbGVtZW50LmNsYXNzTGlzdC50b2dnbGUoICdkaXNhYmxlZCcsIGRpc2FibGVkICk7XG5cdFx0dGhpcy4kZGlzYWJsZS50b2dnbGVBdHRyaWJ1dGUoICdkaXNhYmxlZCcsIGRpc2FibGVkICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0LyoqXG5cdCAqIFNob3dzIHRoZSBDb250cm9sbGVyIGFmdGVyIGl0J3MgYmVlbiBoaWRkZW4uXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gc2hvd1xuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICogQGV4YW1wbGVcblx0ICogY29udHJvbGxlci5zaG93KCk7XG5cdCAqIGNvbnRyb2xsZXIuc2hvdyggZmFsc2UgKTsgLy8gaGlkZVxuXHQgKiBjb250cm9sbGVyLnNob3coIGNvbnRyb2xsZXIuX2hpZGRlbiApOyAvLyB0b2dnbGVcblx0ICovXG5cdHNob3coIHNob3cgPSB0cnVlICkge1xuXG5cdFx0dGhpcy5faGlkZGVuID0gIXNob3c7XG5cblx0XHR0aGlzLmRvbUVsZW1lbnQuc3R5bGUuZGlzcGxheSA9IHRoaXMuX2hpZGRlbiA/ICdub25lJyA6ICcnO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBIaWRlcyB0aGUgQ29udHJvbGxlci5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRoaWRlKCkge1xuXHRcdHJldHVybiB0aGlzLnNob3coIGZhbHNlICk7XG5cdH1cblxuXHQvKipcblx0ICogQ2hhbmdlcyB0aGlzIGNvbnRyb2xsZXIgaW50byBhIGRyb3Bkb3duIG9mIG9wdGlvbnMuXG5cdCAqXG5cdCAqIENhbGxpbmcgdGhpcyBtZXRob2Qgb24gYW4gb3B0aW9uIGNvbnRyb2xsZXIgd2lsbCBzaW1wbHkgdXBkYXRlIHRoZSBvcHRpb25zLiBIb3dldmVyLCBpZiB0aGlzXG5cdCAqIGNvbnRyb2xsZXIgd2FzIG5vdCBhbHJlYWR5IGFuIG9wdGlvbiBjb250cm9sbGVyLCBvbGQgcmVmZXJlbmNlcyB0byB0aGlzIGNvbnRyb2xsZXIgYXJlXG5cdCAqIGRlc3Ryb3llZCwgYW5kIGEgbmV3IGNvbnRyb2xsZXIgaXMgYWRkZWQgdG8gdGhlIGVuZCBvZiB0aGUgR1VJLlxuXHQgKiBAZXhhbXBsZVxuXHQgKiAvLyBzYWZlIHVzYWdlXG5cdCAqXG5cdCAqIGd1aS5hZGQoIG9iaiwgJ3Byb3AxJyApLm9wdGlvbnMoIFsgJ2EnLCAnYicsICdjJyBdICk7XG5cdCAqIGd1aS5hZGQoIG9iaiwgJ3Byb3AyJyApLm9wdGlvbnMoIHsgQmlnOiAxMCwgU21hbGw6IDEgfSApO1xuXHQgKiBndWkuYWRkKCBvYmosICdwcm9wMycgKTtcblx0ICpcblx0ICogLy8gZGFuZ2VyXG5cdCAqXG5cdCAqIGNvbnN0IGN0cmwxID0gZ3VpLmFkZCggb2JqLCAncHJvcDEnICk7XG5cdCAqIGd1aS5hZGQoIG9iaiwgJ3Byb3AyJyApO1xuXHQgKlxuXHQgKiAvLyBjYWxsaW5nIG9wdGlvbnMgb3V0IG9mIG9yZGVyIGFkZHMgYSBuZXcgY29udHJvbGxlciB0byB0aGUgZW5kLi4uXG5cdCAqIGNvbnN0IGN0cmwyID0gY3RybDEub3B0aW9ucyggWyAnYScsICdiJywgJ2MnIF0gKTtcblx0ICpcblx0ICogLy8gLi4uYW5kIGN0cmwxIG5vdyByZWZlcmVuY2VzIGEgY29udHJvbGxlciB0aGF0IGRvZXNuJ3QgZXhpc3Rcblx0ICogYXNzZXJ0KCBjdHJsMiAhPT0gY3RybDEgKVxuXHQgKiBAcGFyYW0ge29iamVjdHxBcnJheX0gb3B0aW9uc1xuXHQgKiBAcmV0dXJucyB7Q29udHJvbGxlcn1cblx0ICovXG5cdG9wdGlvbnMoIG9wdGlvbnMgKSB7XG5cdFx0Y29uc3QgY29udHJvbGxlciA9IHRoaXMucGFyZW50LmFkZCggdGhpcy5vYmplY3QsIHRoaXMucHJvcGVydHksIG9wdGlvbnMgKTtcblx0XHRjb250cm9sbGVyLm5hbWUoIHRoaXMuX25hbWUgKTtcblx0XHR0aGlzLmRlc3Ryb3koKTtcblx0XHRyZXR1cm4gY29udHJvbGxlcjtcblx0fVxuXG5cdC8qKlxuXHQgKiBTZXRzIHRoZSBtaW5pbXVtIHZhbHVlLiBPbmx5IHdvcmtzIG9uIG51bWJlciBjb250cm9sbGVycy5cblx0ICogQHBhcmFtIHtudW1iZXJ9IG1pblxuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICovXG5cdG1pbiggbWluICkge1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNldHMgdGhlIG1heGltdW0gdmFsdWUuIE9ubHkgd29ya3Mgb24gbnVtYmVyIGNvbnRyb2xsZXJzLlxuXHQgKiBAcGFyYW0ge251bWJlcn0gbWF4XG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKi9cblx0bWF4KCBtYXggKSB7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogVmFsdWVzIHNldCBieSB0aGlzIGNvbnRyb2xsZXIgd2lsbCBiZSByb3VuZGVkIHRvIG11bHRpcGxlcyBvZiBgc3RlcGAuIE9ubHkgd29ya3Mgb24gbnVtYmVyXG5cdCAqIGNvbnRyb2xsZXJzLlxuXHQgKiBAcGFyYW0ge251bWJlcn0gc3RlcFxuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICovXG5cdHN0ZXAoIHN0ZXAgKSB7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogUm91bmRzIHRoZSBkaXNwbGF5ZWQgdmFsdWUgdG8gYSBmaXhlZCBudW1iZXIgb2YgZGVjaW1hbHMsIHdpdGhvdXQgYWZmZWN0aW5nIHRoZSBhY3R1YWwgdmFsdWVcblx0ICogbGlrZSBgc3RlcCgpYC4gT25seSB3b3JrcyBvbiBudW1iZXIgY29udHJvbGxlcnMuXG5cdCAqIEBleGFtcGxlXG5cdCAqIGd1aS5hZGQoIG9iamVjdCwgJ3Byb3BlcnR5JyApLmxpc3RlbigpLmRlY2ltYWxzKCA0ICk7XG5cdCAqIEBwYXJhbSB7bnVtYmVyfSBkZWNpbWFsc1xuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICovXG5cdGRlY2ltYWxzKCBkZWNpbWFscyApIHtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdC8qKlxuXHQgKiBDYWxscyBgdXBkYXRlRGlzcGxheSgpYCBldmVyeSBhbmltYXRpb24gZnJhbWUuIFBhc3MgYGZhbHNlYCB0byBzdG9wIGxpc3RlbmluZy5cblx0ICogQHBhcmFtIHtib29sZWFufSBsaXN0ZW5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRsaXN0ZW4oIGxpc3RlbiA9IHRydWUgKSB7XG5cblx0XHQvKipcblx0XHQgKiBVc2VkIHRvIGRldGVybWluZSBpZiB0aGUgY29udHJvbGxlciBpcyBjdXJyZW50bHkgbGlzdGVuaW5nLiBEb24ndCBtb2RpZnkgdGhpcyB2YWx1ZVxuXHRcdCAqIGRpcmVjdGx5LiBVc2UgdGhlIGBjb250cm9sbGVyLmxpc3RlbiggdHJ1ZXxmYWxzZSApYCBtZXRob2QgaW5zdGVhZC5cblx0XHQgKiBAdHlwZSB7Ym9vbGVhbn1cblx0XHQgKi9cblx0XHR0aGlzLl9saXN0ZW5pbmcgPSBsaXN0ZW47XG5cblx0XHRpZiAoIHRoaXMuX2xpc3RlbkNhbGxiYWNrSUQgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdGNhbmNlbEFuaW1hdGlvbkZyYW1lKCB0aGlzLl9saXN0ZW5DYWxsYmFja0lEICk7XG5cdFx0XHR0aGlzLl9saXN0ZW5DYWxsYmFja0lEID0gdW5kZWZpbmVkO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fbGlzdGVuaW5nICkge1xuXHRcdFx0dGhpcy5fbGlzdGVuQ2FsbGJhY2soKTtcblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0X2xpc3RlbkNhbGxiYWNrKCkge1xuXG5cdFx0dGhpcy5fbGlzdGVuQ2FsbGJhY2tJRCA9IHJlcXVlc3RBbmltYXRpb25GcmFtZSggdGhpcy5fbGlzdGVuQ2FsbGJhY2sgKTtcblxuXHRcdC8vIFRvIHByZXZlbnQgZnJhbWVyYXRlIGxvc3MsIG1ha2Ugc3VyZSB0aGUgdmFsdWUgaGFzIGNoYW5nZWQgYmVmb3JlIHVwZGF0aW5nIHRoZSBkaXNwbGF5LlxuXHRcdC8vIE5vdGU6IHNhdmUoKSBpcyB1c2VkIGhlcmUgaW5zdGVhZCBvZiBnZXRWYWx1ZSgpIG9ubHkgYmVjYXVzZSBvZiBDb2xvckNvbnRyb2xsZXIuIFRoZSAhPT0gb3BlcmF0b3Jcblx0XHQvLyB3b24ndCB3b3JrIGZvciBjb2xvciBvYmplY3RzIG9yIGFycmF5cywgYnV0IENvbG9yQ29udHJvbGxlci5zYXZlKCkgYWx3YXlzIHJldHVybnMgYSBzdHJpbmcuXG5cblx0XHRjb25zdCBjdXJWYWx1ZSA9IHRoaXMuc2F2ZSgpO1xuXG5cdFx0aWYgKCBjdXJWYWx1ZSAhPT0gdGhpcy5fbGlzdGVuUHJldlZhbHVlICkge1xuXHRcdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cdFx0fVxuXG5cdFx0dGhpcy5fbGlzdGVuUHJldlZhbHVlID0gY3VyVmFsdWU7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBSZXR1cm5zIGBvYmplY3RbIHByb3BlcnR5IF1gLlxuXHQgKiBAcmV0dXJucyB7YW55fVxuXHQgKi9cblx0Z2V0VmFsdWUoKSB7XG5cdFx0cmV0dXJuIHRoaXMub2JqZWN0WyB0aGlzLnByb3BlcnR5IF07XG5cdH1cblxuXHQvKipcblx0ICogU2V0cyB0aGUgdmFsdWUgb2YgYG9iamVjdFsgcHJvcGVydHkgXWAsIGludm9rZXMgYW55IGBvbkNoYW5nZWAgaGFuZGxlcnMgYW5kIHVwZGF0ZXMgdGhlIGRpc3BsYXkuXG5cdCAqIEBwYXJhbSB7YW55fSB2YWx1ZVxuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICovXG5cdHNldFZhbHVlKCB2YWx1ZSApIHtcblxuXHRcdGlmICggdGhpcy5nZXRWYWx1ZSgpICE9PSB2YWx1ZSApIHtcblxuXHRcdFx0dGhpcy5vYmplY3RbIHRoaXMucHJvcGVydHkgXSA9IHZhbHVlO1xuXHRcdFx0dGhpcy5fY2FsbE9uQ2hhbmdlKCk7XG5cdFx0XHR0aGlzLnVwZGF0ZURpc3BsYXkoKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvKipcblx0ICogVXBkYXRlcyB0aGUgZGlzcGxheSB0byBrZWVwIGl0IGluIHN5bmMgd2l0aCB0aGUgY3VycmVudCB2YWx1ZS4gVXNlZnVsIGZvciB1cGRhdGluZyB5b3VyXG5cdCAqIGNvbnRyb2xsZXJzIHdoZW4gdGhlaXIgdmFsdWVzIGhhdmUgYmVlbiBtb2RpZmllZCBvdXRzaWRlIG9mIHRoZSBHVUkuXG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKi9cblx0dXBkYXRlRGlzcGxheSgpIHtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdGxvYWQoIHZhbHVlICkge1xuXHRcdHRoaXMuc2V0VmFsdWUoIHZhbHVlICk7XG5cdFx0dGhpcy5fY2FsbE9uRmluaXNoQ2hhbmdlKCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRzYXZlKCkge1xuXHRcdHJldHVybiB0aGlzLmdldFZhbHVlKCk7XG5cdH1cblxuXHQvKipcblx0ICogRGVzdHJveXMgdGhpcyBjb250cm9sbGVyIGFuZCByZW1vdmVzIGl0IGZyb20gdGhlIHBhcmVudCBHVUkuXG5cdCAqL1xuXHRkZXN0cm95KCkge1xuXHRcdHRoaXMubGlzdGVuKCBmYWxzZSApO1xuXHRcdHRoaXMucGFyZW50LmNoaWxkcmVuLnNwbGljZSggdGhpcy5wYXJlbnQuY2hpbGRyZW4uaW5kZXhPZiggdGhpcyApLCAxICk7XG5cdFx0dGhpcy5wYXJlbnQuY29udHJvbGxlcnMuc3BsaWNlKCB0aGlzLnBhcmVudC5jb250cm9sbGVycy5pbmRleE9mKCB0aGlzICksIDEgKTtcblx0XHR0aGlzLnBhcmVudC4kY2hpbGRyZW4ucmVtb3ZlQ2hpbGQoIHRoaXMuZG9tRWxlbWVudCApO1xuXHR9XG5cbn1cblxuY2xhc3MgQm9vbGVhbkNvbnRyb2xsZXIgZXh0ZW5kcyBDb250cm9sbGVyIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyZW50LCBvYmplY3QsIHByb3BlcnR5ICkge1xuXG5cdFx0c3VwZXIoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSwgJ2Jvb2xlYW4nLCAnbGFiZWwnICk7XG5cblx0XHR0aGlzLiRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdpbnB1dCcgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICd0eXBlJywgJ2NoZWNrYm94JyApO1xuXHRcdHRoaXMuJGlucHV0LnNldEF0dHJpYnV0ZSggJ2FyaWEtbGFiZWxsZWRieScsIHRoaXMuJG5hbWUuaWQgKTtcblxuXHRcdHRoaXMuJHdpZGdldC5hcHBlbmRDaGlsZCggdGhpcy4kaW5wdXQgKTtcblxuXHRcdHRoaXMuJGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoICdjaGFuZ2UnLCAoKSA9PiB7XG5cdFx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLiRpbnB1dC5jaGVja2VkICk7XG5cdFx0XHR0aGlzLl9jYWxsT25GaW5pc2hDaGFuZ2UoKTtcblx0XHR9ICk7XG5cblx0XHR0aGlzLiRkaXNhYmxlID0gdGhpcy4kaW5wdXQ7XG5cblx0XHR0aGlzLnVwZGF0ZURpc3BsYXkoKTtcblxuXHR9XG5cblx0dXBkYXRlRGlzcGxheSgpIHtcblx0XHR0aGlzLiRpbnB1dC5jaGVja2VkID0gdGhpcy5nZXRWYWx1ZSgpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cbn1cblxuZnVuY3Rpb24gbm9ybWFsaXplQ29sb3JTdHJpbmcoIHN0cmluZyApIHtcblxuXHRsZXQgbWF0Y2gsIHJlc3VsdDtcblxuXHRpZiAoIG1hdGNoID0gc3RyaW5nLm1hdGNoKCAvKCN8MHgpPyhbYS1mMC05XXs2fSkvaSApICkge1xuXG5cdFx0cmVzdWx0ID0gbWF0Y2hbIDIgXTtcblxuXHR9IGVsc2UgaWYgKCBtYXRjaCA9IHN0cmluZy5tYXRjaCggL3JnYlxcKFxccyooXFxkKilcXHMqLFxccyooXFxkKilcXHMqLFxccyooXFxkKilcXHMqXFwpLyApICkge1xuXG5cdFx0cmVzdWx0ID0gcGFyc2VJbnQoIG1hdGNoWyAxIF0gKS50b1N0cmluZyggMTYgKS5wYWRTdGFydCggMiwgMCApXG5cdFx0XHQrIHBhcnNlSW50KCBtYXRjaFsgMiBdICkudG9TdHJpbmcoIDE2ICkucGFkU3RhcnQoIDIsIDAgKVxuXHRcdFx0KyBwYXJzZUludCggbWF0Y2hbIDMgXSApLnRvU3RyaW5nKCAxNiApLnBhZFN0YXJ0KCAyLCAwICk7XG5cblx0fSBlbHNlIGlmICggbWF0Y2ggPSBzdHJpbmcubWF0Y2goIC9eIz8oW2EtZjAtOV0pKFthLWYwLTldKShbYS1mMC05XSkkL2kgKSApIHtcblxuXHRcdHJlc3VsdCA9IG1hdGNoWyAxIF0gKyBtYXRjaFsgMSBdICsgbWF0Y2hbIDIgXSArIG1hdGNoWyAyIF0gKyBtYXRjaFsgMyBdICsgbWF0Y2hbIDMgXTtcblxuXHR9XG5cblx0aWYgKCByZXN1bHQgKSB7XG5cdFx0cmV0dXJuICcjJyArIHJlc3VsdDtcblx0fVxuXG5cdHJldHVybiBmYWxzZTtcblxufVxuXG5jb25zdCBTVFJJTkcgPSB7XG5cdGlzUHJpbWl0aXZlOiB0cnVlLFxuXHRtYXRjaDogdiA9PiB0eXBlb2YgdiA9PT0gJ3N0cmluZycsXG5cdGZyb21IZXhTdHJpbmc6IG5vcm1hbGl6ZUNvbG9yU3RyaW5nLFxuXHR0b0hleFN0cmluZzogbm9ybWFsaXplQ29sb3JTdHJpbmdcbn07XG5cbmNvbnN0IElOVCA9IHtcblx0aXNQcmltaXRpdmU6IHRydWUsXG5cdG1hdGNoOiB2ID0+IHR5cGVvZiB2ID09PSAnbnVtYmVyJyxcblx0ZnJvbUhleFN0cmluZzogc3RyaW5nID0+IHBhcnNlSW50KCBzdHJpbmcuc3Vic3RyaW5nKCAxICksIDE2ICksXG5cdHRvSGV4U3RyaW5nOiB2YWx1ZSA9PiAnIycgKyB2YWx1ZS50b1N0cmluZyggMTYgKS5wYWRTdGFydCggNiwgMCApXG59O1xuXG5jb25zdCBBUlJBWSA9IHtcblx0aXNQcmltaXRpdmU6IGZhbHNlLFxuXG5cdC8vIFRoZSBhcnJvdyBmdW5jdGlvbiBpcyBoZXJlIHRvIGFwcGVhc2UgdHJlZSBzaGFrZXJzIGxpa2UgZXNidWlsZCBvciB3ZWJwYWNrLlxuXHQvLyBTZWUgaHR0cHM6Ly9lc2J1aWxkLmdpdGh1Yi5pby9hcGkvI3RyZWUtc2hha2luZ1xuXHRtYXRjaDogdiA9PiBBcnJheS5pc0FycmF5KCB2ICksXG5cblx0ZnJvbUhleFN0cmluZyggc3RyaW5nLCB0YXJnZXQsIHJnYlNjYWxlID0gMSApIHtcblxuXHRcdGNvbnN0IGludCA9IElOVC5mcm9tSGV4U3RyaW5nKCBzdHJpbmcgKTtcblxuXHRcdHRhcmdldFsgMCBdID0gKCBpbnQgPj4gMTYgJiAyNTUgKSAvIDI1NSAqIHJnYlNjYWxlO1xuXHRcdHRhcmdldFsgMSBdID0gKCBpbnQgPj4gOCAmIDI1NSApIC8gMjU1ICogcmdiU2NhbGU7XG5cdFx0dGFyZ2V0WyAyIF0gPSAoIGludCAmIDI1NSApIC8gMjU1ICogcmdiU2NhbGU7XG5cblx0fSxcblx0dG9IZXhTdHJpbmcoIFsgciwgZywgYiBdLCByZ2JTY2FsZSA9IDEgKSB7XG5cblx0XHRyZ2JTY2FsZSA9IDI1NSAvIHJnYlNjYWxlO1xuXG5cdFx0Y29uc3QgaW50ID0gKCByICogcmdiU2NhbGUgKSA8PCAxNiBeXG5cdFx0XHQoIGcgKiByZ2JTY2FsZSApIDw8IDggXlxuXHRcdFx0KCBiICogcmdiU2NhbGUgKSA8PCAwO1xuXG5cdFx0cmV0dXJuIElOVC50b0hleFN0cmluZyggaW50ICk7XG5cblx0fVxufTtcblxuY29uc3QgT0JKRUNUID0ge1xuXHRpc1ByaW1pdGl2ZTogZmFsc2UsXG5cdG1hdGNoOiB2ID0+IE9iamVjdCggdiApID09PSB2LFxuXHRmcm9tSGV4U3RyaW5nKCBzdHJpbmcsIHRhcmdldCwgcmdiU2NhbGUgPSAxICkge1xuXG5cdFx0Y29uc3QgaW50ID0gSU5ULmZyb21IZXhTdHJpbmcoIHN0cmluZyApO1xuXG5cdFx0dGFyZ2V0LnIgPSAoIGludCA+PiAxNiAmIDI1NSApIC8gMjU1ICogcmdiU2NhbGU7XG5cdFx0dGFyZ2V0LmcgPSAoIGludCA+PiA4ICYgMjU1ICkgLyAyNTUgKiByZ2JTY2FsZTtcblx0XHR0YXJnZXQuYiA9ICggaW50ICYgMjU1ICkgLyAyNTUgKiByZ2JTY2FsZTtcblxuXHR9LFxuXHR0b0hleFN0cmluZyggeyByLCBnLCBiIH0sIHJnYlNjYWxlID0gMSApIHtcblxuXHRcdHJnYlNjYWxlID0gMjU1IC8gcmdiU2NhbGU7XG5cblx0XHRjb25zdCBpbnQgPSAoIHIgKiByZ2JTY2FsZSApIDw8IDE2IF5cblx0XHRcdCggZyAqIHJnYlNjYWxlICkgPDwgOCBeXG5cdFx0XHQoIGIgKiByZ2JTY2FsZSApIDw8IDA7XG5cblx0XHRyZXR1cm4gSU5ULnRvSGV4U3RyaW5nKCBpbnQgKTtcblxuXHR9XG59O1xuXG5jb25zdCBGT1JNQVRTID0gWyBTVFJJTkcsIElOVCwgQVJSQVksIE9CSkVDVCBdO1xuXG5mdW5jdGlvbiBnZXRDb2xvckZvcm1hdCggdmFsdWUgKSB7XG5cdHJldHVybiBGT1JNQVRTLmZpbmQoIGZvcm1hdCA9PiBmb3JtYXQubWF0Y2goIHZhbHVlICkgKTtcbn1cblxuY2xhc3MgQ29sb3JDb250cm9sbGVyIGV4dGVuZHMgQ29udHJvbGxlciB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSwgcmdiU2NhbGUgKSB7XG5cblx0XHRzdXBlciggcGFyZW50LCBvYmplY3QsIHByb3BlcnR5LCAnY29sb3InICk7XG5cblx0XHR0aGlzLiRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdpbnB1dCcgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICd0eXBlJywgJ2NvbG9yJyApO1xuXHRcdHRoaXMuJGlucHV0LnNldEF0dHJpYnV0ZSggJ3RhYmluZGV4JywgLTEgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICdhcmlhLWxhYmVsbGVkYnknLCB0aGlzLiRuYW1lLmlkICk7XG5cblx0XHR0aGlzLiR0ZXh0ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggJ2lucHV0JyApO1xuXHRcdHRoaXMuJHRleHQuc2V0QXR0cmlidXRlKCAndHlwZScsICd0ZXh0JyApO1xuXHRcdHRoaXMuJHRleHQuc2V0QXR0cmlidXRlKCAnc3BlbGxjaGVjaycsICdmYWxzZScgKTtcblx0XHR0aGlzLiR0ZXh0LnNldEF0dHJpYnV0ZSggJ2FyaWEtbGFiZWxsZWRieScsIHRoaXMuJG5hbWUuaWQgKTtcblxuXHRcdHRoaXMuJGRpc3BsYXkgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnZGl2JyApO1xuXHRcdHRoaXMuJGRpc3BsYXkuY2xhc3NMaXN0LmFkZCggJ2Rpc3BsYXknICk7XG5cblx0XHR0aGlzLiRkaXNwbGF5LmFwcGVuZENoaWxkKCB0aGlzLiRpbnB1dCApO1xuXHRcdHRoaXMuJHdpZGdldC5hcHBlbmRDaGlsZCggdGhpcy4kZGlzcGxheSApO1xuXHRcdHRoaXMuJHdpZGdldC5hcHBlbmRDaGlsZCggdGhpcy4kdGV4dCApO1xuXG5cdFx0dGhpcy5fZm9ybWF0ID0gZ2V0Q29sb3JGb3JtYXQoIHRoaXMuaW5pdGlhbFZhbHVlICk7XG5cdFx0dGhpcy5fcmdiU2NhbGUgPSByZ2JTY2FsZTtcblxuXHRcdHRoaXMuX2luaXRpYWxWYWx1ZUhleFN0cmluZyA9IHRoaXMuc2F2ZSgpO1xuXHRcdHRoaXMuX3RleHRGb2N1c2VkID0gZmFsc2U7XG5cblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnaW5wdXQnLCAoKSA9PiB7XG5cdFx0XHR0aGlzLl9zZXRWYWx1ZUZyb21IZXhTdHJpbmcoIHRoaXMuJGlucHV0LnZhbHVlICk7XG5cdFx0fSApO1xuXG5cdFx0dGhpcy4kaW5wdXQuYWRkRXZlbnRMaXN0ZW5lciggJ2JsdXInLCAoKSA9PiB7XG5cdFx0XHR0aGlzLl9jYWxsT25GaW5pc2hDaGFuZ2UoKTtcblx0XHR9ICk7XG5cblx0XHR0aGlzLiR0ZXh0LmFkZEV2ZW50TGlzdGVuZXIoICdpbnB1dCcsICgpID0+IHtcblx0XHRcdGNvbnN0IHRyeVBhcnNlID0gbm9ybWFsaXplQ29sb3JTdHJpbmcoIHRoaXMuJHRleHQudmFsdWUgKTtcblx0XHRcdGlmICggdHJ5UGFyc2UgKSB7XG5cdFx0XHRcdHRoaXMuX3NldFZhbHVlRnJvbUhleFN0cmluZyggdHJ5UGFyc2UgKTtcblx0XHRcdH1cblx0XHR9ICk7XG5cblx0XHR0aGlzLiR0ZXh0LmFkZEV2ZW50TGlzdGVuZXIoICdmb2N1cycsICgpID0+IHtcblx0XHRcdHRoaXMuX3RleHRGb2N1c2VkID0gdHJ1ZTtcblx0XHRcdHRoaXMuJHRleHQuc2VsZWN0KCk7XG5cdFx0fSApO1xuXG5cdFx0dGhpcy4kdGV4dC5hZGRFdmVudExpc3RlbmVyKCAnYmx1cicsICgpID0+IHtcblx0XHRcdHRoaXMuX3RleHRGb2N1c2VkID0gZmFsc2U7XG5cdFx0XHR0aGlzLnVwZGF0ZURpc3BsYXkoKTtcblx0XHRcdHRoaXMuX2NhbGxPbkZpbmlzaENoYW5nZSgpO1xuXHRcdH0gKTtcblxuXHRcdHRoaXMuJGRpc2FibGUgPSB0aGlzLiR0ZXh0O1xuXG5cdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cblx0fVxuXG5cdHJlc2V0KCkge1xuXHRcdHRoaXMuX3NldFZhbHVlRnJvbUhleFN0cmluZyggdGhpcy5faW5pdGlhbFZhbHVlSGV4U3RyaW5nICk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRfc2V0VmFsdWVGcm9tSGV4U3RyaW5nKCB2YWx1ZSApIHtcblxuXHRcdGlmICggdGhpcy5fZm9ybWF0LmlzUHJpbWl0aXZlICkge1xuXG5cdFx0XHRjb25zdCBuZXdWYWx1ZSA9IHRoaXMuX2Zvcm1hdC5mcm9tSGV4U3RyaW5nKCB2YWx1ZSApO1xuXHRcdFx0dGhpcy5zZXRWYWx1ZSggbmV3VmFsdWUgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuX2Zvcm1hdC5mcm9tSGV4U3RyaW5nKCB2YWx1ZSwgdGhpcy5nZXRWYWx1ZSgpLCB0aGlzLl9yZ2JTY2FsZSApO1xuXHRcdFx0dGhpcy5fY2FsbE9uQ2hhbmdlKCk7XG5cdFx0XHR0aGlzLnVwZGF0ZURpc3BsYXkoKTtcblxuXHRcdH1cblxuXHR9XG5cblx0c2F2ZSgpIHtcblx0XHRyZXR1cm4gdGhpcy5fZm9ybWF0LnRvSGV4U3RyaW5nKCB0aGlzLmdldFZhbHVlKCksIHRoaXMuX3JnYlNjYWxlICk7XG5cdH1cblxuXHRsb2FkKCB2YWx1ZSApIHtcblx0XHR0aGlzLl9zZXRWYWx1ZUZyb21IZXhTdHJpbmcoIHZhbHVlICk7XG5cdFx0dGhpcy5fY2FsbE9uRmluaXNoQ2hhbmdlKCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHR1cGRhdGVEaXNwbGF5KCkge1xuXHRcdHRoaXMuJGlucHV0LnZhbHVlID0gdGhpcy5fZm9ybWF0LnRvSGV4U3RyaW5nKCB0aGlzLmdldFZhbHVlKCksIHRoaXMuX3JnYlNjYWxlICk7XG5cdFx0aWYgKCAhdGhpcy5fdGV4dEZvY3VzZWQgKSB7XG5cdFx0XHR0aGlzLiR0ZXh0LnZhbHVlID0gdGhpcy4kaW5wdXQudmFsdWUuc3Vic3RyaW5nKCAxICk7XG5cdFx0fVxuXHRcdHRoaXMuJGRpc3BsYXkuc3R5bGUuYmFja2dyb3VuZENvbG9yID0gdGhpcy4kaW5wdXQudmFsdWU7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxufVxuXG5jbGFzcyBGdW5jdGlvbkNvbnRyb2xsZXIgZXh0ZW5kcyBDb250cm9sbGVyIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyZW50LCBvYmplY3QsIHByb3BlcnR5ICkge1xuXG5cdFx0c3VwZXIoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSwgJ2Z1bmN0aW9uJyApO1xuXG5cdFx0Ly8gQnV0dG9ucyBhcmUgdGhlIG9ubHkgY2FzZSB3aGVyZSB3aWRnZXQgY29udGFpbnMgbmFtZVxuXHRcdHRoaXMuJGJ1dHRvbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdidXR0b24nICk7XG5cdFx0dGhpcy4kYnV0dG9uLmFwcGVuZENoaWxkKCB0aGlzLiRuYW1lICk7XG5cdFx0dGhpcy4kd2lkZ2V0LmFwcGVuZENoaWxkKCB0aGlzLiRidXR0b24gKTtcblxuXHRcdHRoaXMuJGJ1dHRvbi5hZGRFdmVudExpc3RlbmVyKCAnY2xpY2snLCBlID0+IHtcblx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdHRoaXMuZ2V0VmFsdWUoKS5jYWxsKCB0aGlzLm9iamVjdCApO1xuXHRcdFx0dGhpcy5fY2FsbE9uQ2hhbmdlKCk7XG5cdFx0fSApO1xuXG5cdFx0Ly8gZW5hYmxlcyA6YWN0aXZlIHBzZXVkbyBjbGFzcyBvbiBtb2JpbGVcblx0XHR0aGlzLiRidXR0b24uYWRkRXZlbnRMaXN0ZW5lciggJ3RvdWNoc3RhcnQnLCAoKSA9PiB7fSwgeyBwYXNzaXZlOiB0cnVlIH0gKTtcblxuXHRcdHRoaXMuJGRpc2FibGUgPSB0aGlzLiRidXR0b247XG5cblx0fVxuXG59XG5cbmNsYXNzIE51bWJlckNvbnRyb2xsZXIgZXh0ZW5kcyBDb250cm9sbGVyIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyZW50LCBvYmplY3QsIHByb3BlcnR5LCBtaW4sIG1heCwgc3RlcCApIHtcblxuXHRcdHN1cGVyKCBwYXJlbnQsIG9iamVjdCwgcHJvcGVydHksICdudW1iZXInICk7XG5cblx0XHR0aGlzLl9pbml0SW5wdXQoKTtcblxuXHRcdHRoaXMubWluKCBtaW4gKTtcblx0XHR0aGlzLm1heCggbWF4ICk7XG5cblx0XHRjb25zdCBzdGVwRXhwbGljaXQgPSBzdGVwICE9PSB1bmRlZmluZWQ7XG5cdFx0dGhpcy5zdGVwKCBzdGVwRXhwbGljaXQgPyBzdGVwIDogdGhpcy5fZ2V0SW1wbGljaXRTdGVwKCksIHN0ZXBFeHBsaWNpdCApO1xuXG5cdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cblx0fVxuXG5cdGRlY2ltYWxzKCBkZWNpbWFscyApIHtcblx0XHR0aGlzLl9kZWNpbWFscyA9IGRlY2ltYWxzO1xuXHRcdHRoaXMudXBkYXRlRGlzcGxheSgpO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0bWluKCBtaW4gKSB7XG5cdFx0dGhpcy5fbWluID0gbWluO1xuXHRcdHRoaXMuX29uVXBkYXRlTWluTWF4KCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRtYXgoIG1heCApIHtcblx0XHR0aGlzLl9tYXggPSBtYXg7XG5cdFx0dGhpcy5fb25VcGRhdGVNaW5NYXgoKTtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdHN0ZXAoIHN0ZXAsIGV4cGxpY2l0ID0gdHJ1ZSApIHtcblx0XHR0aGlzLl9zdGVwID0gc3RlcDtcblx0XHR0aGlzLl9zdGVwRXhwbGljaXQgPSBleHBsaWNpdDtcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdHVwZGF0ZURpc3BsYXkoKSB7XG5cblx0XHRjb25zdCB2YWx1ZSA9IHRoaXMuZ2V0VmFsdWUoKTtcblxuXHRcdGlmICggdGhpcy5faGFzU2xpZGVyICkge1xuXG5cdFx0XHRsZXQgcGVyY2VudCA9ICggdmFsdWUgLSB0aGlzLl9taW4gKSAvICggdGhpcy5fbWF4IC0gdGhpcy5fbWluICk7XG5cdFx0XHRwZXJjZW50ID0gTWF0aC5tYXgoIDAsIE1hdGgubWluKCBwZXJjZW50LCAxICkgKTtcblxuXHRcdFx0dGhpcy4kZmlsbC5zdHlsZS53aWR0aCA9IHBlcmNlbnQgKiAxMDAgKyAnJSc7XG5cblx0XHR9XG5cblx0XHRpZiAoICF0aGlzLl9pbnB1dEZvY3VzZWQgKSB7XG5cdFx0XHR0aGlzLiRpbnB1dC52YWx1ZSA9IHRoaXMuX2RlY2ltYWxzID09PSB1bmRlZmluZWQgPyB2YWx1ZSA6IHZhbHVlLnRvRml4ZWQoIHRoaXMuX2RlY2ltYWxzICk7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdF9pbml0SW5wdXQoKSB7XG5cblx0XHR0aGlzLiRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdpbnB1dCcgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICd0eXBlJywgJ3RleHQnICk7XG5cdFx0dGhpcy4kaW5wdXQuc2V0QXR0cmlidXRlKCAnYXJpYS1sYWJlbGxlZGJ5JywgdGhpcy4kbmFtZS5pZCApO1xuXG5cdFx0Ly8gT24gdG91Y2ggZGV2aWNlcyBvbmx5LCB1c2UgaW5wdXRbdHlwZT1udW1iZXJdIHRvIGZvcmNlIGEgbnVtZXJpYyBrZXlib2FyZC5cblx0XHQvLyBJZGVhbGx5IHdlIGNvdWxkIHVzZSBvbmUgaW5wdXQgdHlwZSBldmVyeXdoZXJlLCBidXQgW3R5cGU9bnVtYmVyXSBoYXMgcXVpcmtzXG5cdFx0Ly8gb24gZGVza3RvcCwgYW5kIFtpbnB1dG1vZGU9ZGVjaW1hbF0gaGFzIHF1aXJrcyBvbiBpT1MuXG5cdFx0Ly8gU2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9nZW9yZ2VhbHdheXMvbGlsLWd1aS9wdWxsLzE2XG5cblx0XHRjb25zdCBpc1RvdWNoID0gd2luZG93Lm1hdGNoTWVkaWEoICcocG9pbnRlcjogY29hcnNlKScgKS5tYXRjaGVzO1xuXG5cdFx0aWYgKCBpc1RvdWNoICkge1xuXHRcdFx0dGhpcy4kaW5wdXQuc2V0QXR0cmlidXRlKCAndHlwZScsICdudW1iZXInICk7XG5cdFx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICdzdGVwJywgJ2FueScgKTtcblx0XHR9XG5cblx0XHR0aGlzLiR3aWRnZXQuYXBwZW5kQ2hpbGQoIHRoaXMuJGlucHV0ICk7XG5cblx0XHR0aGlzLiRkaXNhYmxlID0gdGhpcy4kaW5wdXQ7XG5cblx0XHRjb25zdCBvbklucHV0ID0gKCkgPT4ge1xuXG5cdFx0XHRsZXQgdmFsdWUgPSBwYXJzZUZsb2F0KCB0aGlzLiRpbnB1dC52YWx1ZSApO1xuXG5cdFx0XHRpZiAoIGlzTmFOKCB2YWx1ZSApICkgcmV0dXJuO1xuXG5cdFx0XHRpZiAoIHRoaXMuX3N0ZXBFeHBsaWNpdCApIHtcblx0XHRcdFx0dmFsdWUgPSB0aGlzLl9zbmFwKCB2YWx1ZSApO1xuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLl9jbGFtcCggdmFsdWUgKSApO1xuXG5cdFx0fTtcblxuXHRcdC8vIEtleXMgJiBtb3VzZSB3aGVlbFxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0Y29uc3QgaW5jcmVtZW50ID0gZGVsdGEgPT4ge1xuXG5cdFx0XHRjb25zdCB2YWx1ZSA9IHBhcnNlRmxvYXQoIHRoaXMuJGlucHV0LnZhbHVlICk7XG5cblx0XHRcdGlmICggaXNOYU4oIHZhbHVlICkgKSByZXR1cm47XG5cblx0XHRcdHRoaXMuX3NuYXBDbGFtcFNldFZhbHVlKCB2YWx1ZSArIGRlbHRhICk7XG5cblx0XHRcdC8vIEZvcmNlIHRoZSBpbnB1dCB0byB1cGRhdGVEaXNwbGF5IHdoZW4gaXQncyBmb2N1c2VkXG5cdFx0XHR0aGlzLiRpbnB1dC52YWx1ZSA9IHRoaXMuZ2V0VmFsdWUoKTtcblxuXHRcdH07XG5cblx0XHRjb25zdCBvbktleURvd24gPSBlID0+IHtcblx0XHRcdC8vIFVzaW5nIGBlLmtleWAgaW5zdGVhZCBvZiBgZS5jb2RlYCBhbHNvIGNhdGNoZXMgTnVtcGFkRW50ZXJcblx0XHRcdGlmICggZS5rZXkgPT09ICdFbnRlcicgKSB7XG5cdFx0XHRcdHRoaXMuJGlucHV0LmJsdXIoKTtcblx0XHRcdH1cblx0XHRcdGlmICggZS5jb2RlID09PSAnQXJyb3dVcCcgKSB7XG5cdFx0XHRcdGUucHJldmVudERlZmF1bHQoKTtcblx0XHRcdFx0aW5jcmVtZW50KCB0aGlzLl9zdGVwICogdGhpcy5fYXJyb3dLZXlNdWx0aXBsaWVyKCBlICkgKTtcblx0XHRcdH1cblx0XHRcdGlmICggZS5jb2RlID09PSAnQXJyb3dEb3duJyApIHtcblx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRpbmNyZW1lbnQoIHRoaXMuX3N0ZXAgKiB0aGlzLl9hcnJvd0tleU11bHRpcGxpZXIoIGUgKSAqIC0xICk7XG5cdFx0XHR9XG5cdFx0fTtcblxuXHRcdGNvbnN0IG9uV2hlZWwgPSBlID0+IHtcblx0XHRcdGlmICggdGhpcy5faW5wdXRGb2N1c2VkICkge1xuXHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdGluY3JlbWVudCggdGhpcy5fc3RlcCAqIHRoaXMuX25vcm1hbGl6ZU1vdXNlV2hlZWwoIGUgKSApO1xuXHRcdFx0fVxuXHRcdH07XG5cblx0XHQvLyBWZXJ0aWNhbCBkcmFnXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0XHRsZXQgdGVzdGluZ0ZvclZlcnRpY2FsRHJhZyA9IGZhbHNlLFxuXHRcdFx0aW5pdENsaWVudFgsXG5cdFx0XHRpbml0Q2xpZW50WSxcblx0XHRcdHByZXZDbGllbnRZLFxuXHRcdFx0aW5pdFZhbHVlLFxuXHRcdFx0ZHJhZ0RlbHRhO1xuXG5cdFx0Ly8gT25jZSB0aGUgbW91c2UgaXMgZHJhZ2dlZCBtb3JlIHRoYW4gRFJBR19USFJFU0ggcHggb24gYW55IGF4aXMsIHdlIGRlY2lkZVxuXHRcdC8vIG9uIHRoZSB1c2VyJ3MgaW50ZW50OiBob3Jpem9udGFsIG1lYW5zIGhpZ2hsaWdodCwgdmVydGljYWwgbWVhbnMgZHJhZy5cblx0XHRjb25zdCBEUkFHX1RIUkVTSCA9IDU7XG5cblx0XHRjb25zdCBvbk1vdXNlRG93biA9IGUgPT4ge1xuXG5cdFx0XHRpbml0Q2xpZW50WCA9IGUuY2xpZW50WDtcblx0XHRcdGluaXRDbGllbnRZID0gcHJldkNsaWVudFkgPSBlLmNsaWVudFk7XG5cdFx0XHR0ZXN0aW5nRm9yVmVydGljYWxEcmFnID0gdHJ1ZTtcblxuXHRcdFx0aW5pdFZhbHVlID0gdGhpcy5nZXRWYWx1ZSgpO1xuXHRcdFx0ZHJhZ0RlbHRhID0gMDtcblxuXHRcdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoICdtb3VzZW1vdmUnLCBvbk1vdXNlTW92ZSApO1xuXHRcdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoICdtb3VzZXVwJywgb25Nb3VzZVVwICk7XG5cblx0XHR9O1xuXG5cdFx0Y29uc3Qgb25Nb3VzZU1vdmUgPSBlID0+IHtcblxuXHRcdFx0aWYgKCB0ZXN0aW5nRm9yVmVydGljYWxEcmFnICkge1xuXG5cdFx0XHRcdGNvbnN0IGR4ID0gZS5jbGllbnRYIC0gaW5pdENsaWVudFg7XG5cdFx0XHRcdGNvbnN0IGR5ID0gZS5jbGllbnRZIC0gaW5pdENsaWVudFk7XG5cblx0XHRcdFx0aWYgKCBNYXRoLmFicyggZHkgKSA+IERSQUdfVEhSRVNIICkge1xuXG5cdFx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHRcdHRoaXMuJGlucHV0LmJsdXIoKTtcblx0XHRcdFx0XHR0ZXN0aW5nRm9yVmVydGljYWxEcmFnID0gZmFsc2U7XG5cdFx0XHRcdFx0dGhpcy5fc2V0RHJhZ2dpbmdTdHlsZSggdHJ1ZSwgJ3ZlcnRpY2FsJyApO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIE1hdGguYWJzKCBkeCApID4gRFJBR19USFJFU0ggKSB7XG5cblx0XHRcdFx0XHRvbk1vdXNlVXAoKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gVGhpcyBpc24ndCBhbiBlbHNlIHNvIHRoYXQgdGhlIGZpcnN0IG1vdmUgY291bnRzIHRvd2FyZHMgZHJhZ0RlbHRhXG5cdFx0XHRpZiAoICF0ZXN0aW5nRm9yVmVydGljYWxEcmFnICkge1xuXG5cdFx0XHRcdGNvbnN0IGR5ID0gZS5jbGllbnRZIC0gcHJldkNsaWVudFk7XG5cblx0XHRcdFx0ZHJhZ0RlbHRhIC09IGR5ICogdGhpcy5fc3RlcCAqIHRoaXMuX2Fycm93S2V5TXVsdGlwbGllciggZSApO1xuXG5cdFx0XHRcdC8vIENsYW1wIGRyYWdEZWx0YSBzbyB3ZSBkb24ndCBoYXZlICdkZWFkIHNwYWNlJyBhZnRlciBkcmFnZ2luZyBwYXN0IGJvdW5kcy5cblx0XHRcdFx0Ly8gV2UncmUgb2theSB3aXRoIHRoZSBmYWN0IHRoYXQgYm91bmRzIGNhbiBiZSB1bmRlZmluZWQgaGVyZS5cblx0XHRcdFx0aWYgKCBpbml0VmFsdWUgKyBkcmFnRGVsdGEgPiB0aGlzLl9tYXggKSB7XG5cdFx0XHRcdFx0ZHJhZ0RlbHRhID0gdGhpcy5fbWF4IC0gaW5pdFZhbHVlO1xuXHRcdFx0XHR9IGVsc2UgaWYgKCBpbml0VmFsdWUgKyBkcmFnRGVsdGEgPCB0aGlzLl9taW4gKSB7XG5cdFx0XHRcdFx0ZHJhZ0RlbHRhID0gdGhpcy5fbWluIC0gaW5pdFZhbHVlO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0dGhpcy5fc25hcENsYW1wU2V0VmFsdWUoIGluaXRWYWx1ZSArIGRyYWdEZWx0YSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHByZXZDbGllbnRZID0gZS5jbGllbnRZO1xuXG5cdFx0fTtcblxuXHRcdGNvbnN0IG9uTW91c2VVcCA9ICgpID0+IHtcblx0XHRcdHRoaXMuX3NldERyYWdnaW5nU3R5bGUoIGZhbHNlLCAndmVydGljYWwnICk7XG5cdFx0XHR0aGlzLl9jYWxsT25GaW5pc2hDaGFuZ2UoKTtcblx0XHRcdHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCAnbW91c2Vtb3ZlJywgb25Nb3VzZU1vdmUgKTtcblx0XHRcdHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCAnbW91c2V1cCcsIG9uTW91c2VVcCApO1xuXHRcdH07XG5cblx0XHQvLyBGb2N1cyBzdGF0ZSAmIG9uRmluaXNoQ2hhbmdlXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0XHRjb25zdCBvbkZvY3VzID0gKCkgPT4ge1xuXHRcdFx0dGhpcy5faW5wdXRGb2N1c2VkID0gdHJ1ZTtcblx0XHR9O1xuXG5cdFx0Y29uc3Qgb25CbHVyID0gKCkgPT4ge1xuXHRcdFx0dGhpcy5faW5wdXRGb2N1c2VkID0gZmFsc2U7XG5cdFx0XHR0aGlzLnVwZGF0ZURpc3BsYXkoKTtcblx0XHRcdHRoaXMuX2NhbGxPbkZpbmlzaENoYW5nZSgpO1xuXHRcdH07XG5cblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnaW5wdXQnLCBvbklucHV0ICk7XG5cdFx0dGhpcy4kaW5wdXQuYWRkRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCBvbktleURvd24gKTtcblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnd2hlZWwnLCBvbldoZWVsLCB7IHBhc3NpdmU6IGZhbHNlIH0gKTtcblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnbW91c2Vkb3duJywgb25Nb3VzZURvd24gKTtcblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnZm9jdXMnLCBvbkZvY3VzICk7XG5cdFx0dGhpcy4kaW5wdXQuYWRkRXZlbnRMaXN0ZW5lciggJ2JsdXInLCBvbkJsdXIgKTtcblxuXHR9XG5cblx0X2luaXRTbGlkZXIoKSB7XG5cblx0XHR0aGlzLl9oYXNTbGlkZXIgPSB0cnVlO1xuXG5cdFx0Ly8gQnVpbGQgRE9NXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0XHR0aGlzLiRzbGlkZXIgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnZGl2JyApO1xuXHRcdHRoaXMuJHNsaWRlci5jbGFzc0xpc3QuYWRkKCAnc2xpZGVyJyApO1xuXG5cdFx0dGhpcy4kZmlsbCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdkaXYnICk7XG5cdFx0dGhpcy4kZmlsbC5jbGFzc0xpc3QuYWRkKCAnZmlsbCcgKTtcblxuXHRcdHRoaXMuJHNsaWRlci5hcHBlbmRDaGlsZCggdGhpcy4kZmlsbCApO1xuXHRcdHRoaXMuJHdpZGdldC5pbnNlcnRCZWZvcmUoIHRoaXMuJHNsaWRlciwgdGhpcy4kaW5wdXQgKTtcblxuXHRcdHRoaXMuZG9tRWxlbWVudC5jbGFzc0xpc3QuYWRkKCAnaGFzU2xpZGVyJyApO1xuXG5cdFx0Ly8gTWFwIGNsaWVudFggdG8gdmFsdWVcblx0XHQvLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuXHRcdGNvbnN0IG1hcCA9ICggdiwgYSwgYiwgYywgZCApID0+IHtcblx0XHRcdHJldHVybiAoIHYgLSBhICkgLyAoIGIgLSBhICkgKiAoIGQgLSBjICkgKyBjO1xuXHRcdH07XG5cblx0XHRjb25zdCBzZXRWYWx1ZUZyb21YID0gY2xpZW50WCA9PiB7XG5cdFx0XHRjb25zdCByZWN0ID0gdGhpcy4kc2xpZGVyLmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXHRcdFx0bGV0IHZhbHVlID0gbWFwKCBjbGllbnRYLCByZWN0LmxlZnQsIHJlY3QucmlnaHQsIHRoaXMuX21pbiwgdGhpcy5fbWF4ICk7XG5cdFx0XHR0aGlzLl9zbmFwQ2xhbXBTZXRWYWx1ZSggdmFsdWUgKTtcblx0XHR9O1xuXG5cdFx0Ly8gTW91c2UgZHJhZ1xuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0Y29uc3QgbW91c2VEb3duID0gZSA9PiB7XG5cdFx0XHR0aGlzLl9zZXREcmFnZ2luZ1N0eWxlKCB0cnVlICk7XG5cdFx0XHRzZXRWYWx1ZUZyb21YKCBlLmNsaWVudFggKTtcblx0XHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCAnbW91c2Vtb3ZlJywgbW91c2VNb3ZlICk7XG5cdFx0XHR3aW5kb3cuYWRkRXZlbnRMaXN0ZW5lciggJ21vdXNldXAnLCBtb3VzZVVwICk7XG5cdFx0fTtcblxuXHRcdGNvbnN0IG1vdXNlTW92ZSA9IGUgPT4ge1xuXHRcdFx0c2V0VmFsdWVGcm9tWCggZS5jbGllbnRYICk7XG5cdFx0fTtcblxuXHRcdGNvbnN0IG1vdXNlVXAgPSAoKSA9PiB7XG5cdFx0XHR0aGlzLl9jYWxsT25GaW5pc2hDaGFuZ2UoKTtcblx0XHRcdHRoaXMuX3NldERyYWdnaW5nU3R5bGUoIGZhbHNlICk7XG5cdFx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ21vdXNlbW92ZScsIG1vdXNlTW92ZSApO1xuXHRcdFx0d2luZG93LnJlbW92ZUV2ZW50TGlzdGVuZXIoICdtb3VzZXVwJywgbW91c2VVcCApO1xuXHRcdH07XG5cblx0XHQvLyBUb3VjaCBkcmFnXG5cdFx0Ly8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cblx0XHRsZXQgdGVzdGluZ0ZvclNjcm9sbCA9IGZhbHNlLCBwcmV2Q2xpZW50WCwgcHJldkNsaWVudFk7XG5cblx0XHRjb25zdCBiZWdpblRvdWNoRHJhZyA9IGUgPT4ge1xuXHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0dGhpcy5fc2V0RHJhZ2dpbmdTdHlsZSggdHJ1ZSApO1xuXHRcdFx0c2V0VmFsdWVGcm9tWCggZS50b3VjaGVzWyAwIF0uY2xpZW50WCApO1xuXHRcdFx0dGVzdGluZ0ZvclNjcm9sbCA9IGZhbHNlO1xuXHRcdH07XG5cblx0XHRjb25zdCBvblRvdWNoU3RhcnQgPSBlID0+IHtcblxuXHRcdFx0aWYgKCBlLnRvdWNoZXMubGVuZ3RoID4gMSApIHJldHVybjtcblxuXHRcdFx0Ly8gSWYgd2UncmUgaW4gYSBzY3JvbGxhYmxlIGNvbnRhaW5lciwgd2Ugc2hvdWxkIHdhaXQgZm9yIHRoZSBmaXJzdFxuXHRcdFx0Ly8gdG91Y2htb3ZlIHRvIHNlZSBpZiB0aGUgdXNlciBpcyB0cnlpbmcgdG8gc2xpZGUgb3Igc2Nyb2xsLlxuXHRcdFx0aWYgKCB0aGlzLl9oYXNTY3JvbGxCYXIgKSB7XG5cblx0XHRcdFx0cHJldkNsaWVudFggPSBlLnRvdWNoZXNbIDAgXS5jbGllbnRYO1xuXHRcdFx0XHRwcmV2Q2xpZW50WSA9IGUudG91Y2hlc1sgMCBdLmNsaWVudFk7XG5cdFx0XHRcdHRlc3RpbmdGb3JTY3JvbGwgPSB0cnVlO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIE90aGVyd2lzZSwgd2UgY2FuIHNldCB0aGUgdmFsdWUgc3RyYWlnaHQgYXdheSBvbiB0b3VjaHN0YXJ0LlxuXHRcdFx0XHRiZWdpblRvdWNoRHJhZyggZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHdpbmRvdy5hZGRFdmVudExpc3RlbmVyKCAndG91Y2htb3ZlJywgb25Ub3VjaE1vdmUsIHsgcGFzc2l2ZTogZmFsc2UgfSApO1xuXHRcdFx0d2luZG93LmFkZEV2ZW50TGlzdGVuZXIoICd0b3VjaGVuZCcsIG9uVG91Y2hFbmQgKTtcblxuXHRcdH07XG5cblx0XHRjb25zdCBvblRvdWNoTW92ZSA9IGUgPT4ge1xuXG5cdFx0XHRpZiAoIHRlc3RpbmdGb3JTY3JvbGwgKSB7XG5cblx0XHRcdFx0Y29uc3QgZHggPSBlLnRvdWNoZXNbIDAgXS5jbGllbnRYIC0gcHJldkNsaWVudFg7XG5cdFx0XHRcdGNvbnN0IGR5ID0gZS50b3VjaGVzWyAwIF0uY2xpZW50WSAtIHByZXZDbGllbnRZO1xuXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIGR4ICkgPiBNYXRoLmFicyggZHkgKSApIHtcblxuXHRcdFx0XHRcdC8vIFdlIG1vdmVkIGhvcml6b250YWxseSwgc2V0IHRoZSB2YWx1ZSBhbmQgc3RvcCBjaGVja2luZy5cblx0XHRcdFx0XHRiZWdpblRvdWNoRHJhZyggZSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBUaGlzIHdhcywgaW4gZmFjdCwgYW4gYXR0ZW1wdCB0byBzY3JvbGwuIEFib3J0LlxuXHRcdFx0XHRcdHdpbmRvdy5yZW1vdmVFdmVudExpc3RlbmVyKCAndG91Y2htb3ZlJywgb25Ub3VjaE1vdmUgKTtcblx0XHRcdFx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3RvdWNoZW5kJywgb25Ub3VjaEVuZCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRlLnByZXZlbnREZWZhdWx0KCk7XG5cdFx0XHRcdHNldFZhbHVlRnJvbVgoIGUudG91Y2hlc1sgMCBdLmNsaWVudFggKTtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdGNvbnN0IG9uVG91Y2hFbmQgPSAoKSA9PiB7XG5cdFx0XHR0aGlzLl9jYWxsT25GaW5pc2hDaGFuZ2UoKTtcblx0XHRcdHRoaXMuX3NldERyYWdnaW5nU3R5bGUoIGZhbHNlICk7XG5cdFx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3RvdWNobW92ZScsIG9uVG91Y2hNb3ZlICk7XG5cdFx0XHR3aW5kb3cucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3RvdWNoZW5kJywgb25Ub3VjaEVuZCApO1xuXHRcdH07XG5cblx0XHQvLyBNb3VzZSB3aGVlbFxuXHRcdC8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0Ly8gV2UgaGF2ZSB0byB1c2UgYSBkZWJvdW5jZWQgZnVuY3Rpb24gdG8gY2FsbCBvbkZpbmlzaENoYW5nZSBiZWNhdXNlXG5cdFx0Ly8gdGhlcmUncyBubyB3YXkgdG8gdGVsbCB3aGVuIHRoZSB1c2VyIGlzIFwiZG9uZVwiIG1vdXNlLXdoZWVsaW5nLlxuXHRcdGNvbnN0IGNhbGxPbkZpbmlzaENoYW5nZSA9IHRoaXMuX2NhbGxPbkZpbmlzaENoYW5nZS5iaW5kKCB0aGlzICk7XG5cdFx0Y29uc3QgV0hFRUxfREVCT1VOQ0VfVElNRSA9IDQwMDtcblx0XHRsZXQgd2hlZWxGaW5pc2hDaGFuZ2VUaW1lb3V0O1xuXG5cdFx0Y29uc3Qgb25XaGVlbCA9IGUgPT4ge1xuXG5cdFx0XHQvLyBpZ25vcmUgdmVydGljYWwgd2hlZWxzIGlmIHRoZXJlJ3MgYSBzY3JvbGxiYXJcblx0XHRcdGNvbnN0IGlzVmVydGljYWwgPSBNYXRoLmFicyggZS5kZWx0YVggKSA8IE1hdGguYWJzKCBlLmRlbHRhWSApO1xuXHRcdFx0aWYgKCBpc1ZlcnRpY2FsICYmIHRoaXMuX2hhc1Njcm9sbEJhciApIHJldHVybjtcblxuXHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHQvLyBzZXQgdmFsdWVcblx0XHRcdGNvbnN0IGRlbHRhID0gdGhpcy5fbm9ybWFsaXplTW91c2VXaGVlbCggZSApICogdGhpcy5fc3RlcDtcblx0XHRcdHRoaXMuX3NuYXBDbGFtcFNldFZhbHVlKCB0aGlzLmdldFZhbHVlKCkgKyBkZWx0YSApO1xuXG5cdFx0XHQvLyBmb3JjZSB0aGUgaW5wdXQgdG8gdXBkYXRlRGlzcGxheSB3aGVuIGl0J3MgZm9jdXNlZFxuXHRcdFx0dGhpcy4kaW5wdXQudmFsdWUgPSB0aGlzLmdldFZhbHVlKCk7XG5cblx0XHRcdC8vIGRlYm91bmNlIG9uRmluaXNoQ2hhbmdlXG5cdFx0XHRjbGVhclRpbWVvdXQoIHdoZWVsRmluaXNoQ2hhbmdlVGltZW91dCApO1xuXHRcdFx0d2hlZWxGaW5pc2hDaGFuZ2VUaW1lb3V0ID0gc2V0VGltZW91dCggY2FsbE9uRmluaXNoQ2hhbmdlLCBXSEVFTF9ERUJPVU5DRV9USU1FICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy4kc2xpZGVyLmFkZEV2ZW50TGlzdGVuZXIoICdtb3VzZWRvd24nLCBtb3VzZURvd24gKTtcblx0XHR0aGlzLiRzbGlkZXIuYWRkRXZlbnRMaXN0ZW5lciggJ3RvdWNoc3RhcnQnLCBvblRvdWNoU3RhcnQsIHsgcGFzc2l2ZTogZmFsc2UgfSApO1xuXHRcdHRoaXMuJHNsaWRlci5hZGRFdmVudExpc3RlbmVyKCAnd2hlZWwnLCBvbldoZWVsLCB7IHBhc3NpdmU6IGZhbHNlIH0gKTtcblxuXHR9XG5cblx0X3NldERyYWdnaW5nU3R5bGUoIGFjdGl2ZSwgYXhpcyA9ICdob3Jpem9udGFsJyApIHtcblx0XHRpZiAoIHRoaXMuJHNsaWRlciApIHtcblx0XHRcdHRoaXMuJHNsaWRlci5jbGFzc0xpc3QudG9nZ2xlKCAnYWN0aXZlJywgYWN0aXZlICk7XG5cdFx0fVxuXHRcdGRvY3VtZW50LmJvZHkuY2xhc3NMaXN0LnRvZ2dsZSggJ2xpbC1ndWktZHJhZ2dpbmcnLCBhY3RpdmUgKTtcblx0XHRkb2N1bWVudC5ib2R5LmNsYXNzTGlzdC50b2dnbGUoIGBsaWwtZ3VpLSR7YXhpc31gLCBhY3RpdmUgKTtcblx0fVxuXG5cdF9nZXRJbXBsaWNpdFN0ZXAoKSB7XG5cblx0XHRpZiAoIHRoaXMuX2hhc01pbiAmJiB0aGlzLl9oYXNNYXggKSB7XG5cdFx0XHRyZXR1cm4gKCB0aGlzLl9tYXggLSB0aGlzLl9taW4gKSAvIDEwMDA7XG5cdFx0fVxuXG5cdFx0cmV0dXJuIDAuMTtcblxuXHR9XG5cblx0X29uVXBkYXRlTWluTWF4KCkge1xuXG5cdFx0aWYgKCAhdGhpcy5faGFzU2xpZGVyICYmIHRoaXMuX2hhc01pbiAmJiB0aGlzLl9oYXNNYXggKSB7XG5cblx0XHRcdC8vIElmIHRoaXMgaXMgdGhlIGZpcnN0IHRpbWUgd2UncmUgaGVhcmluZyBhYm91dCBtaW4gYW5kIG1heFxuXHRcdFx0Ly8gYW5kIHdlIGhhdmVuJ3QgZXhwbGljaXRseSBzdGF0ZWQgd2hhdCBvdXIgc3RlcCBpcywgbGV0J3Ncblx0XHRcdC8vIHVwZGF0ZSB0aGF0IHRvby5cblx0XHRcdGlmICggIXRoaXMuX3N0ZXBFeHBsaWNpdCApIHtcblx0XHRcdFx0dGhpcy5zdGVwKCB0aGlzLl9nZXRJbXBsaWNpdFN0ZXAoKSwgZmFsc2UgKTtcblx0XHRcdH1cblxuXHRcdFx0dGhpcy5faW5pdFNsaWRlcigpO1xuXHRcdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cblx0XHR9XG5cblx0fVxuXG5cdF9ub3JtYWxpemVNb3VzZVdoZWVsKCBlICkge1xuXG5cdFx0bGV0IHsgZGVsdGFYLCBkZWx0YVkgfSA9IGU7XG5cblx0XHQvLyBTYWZhcmkgYW5kIENocm9tZSByZXBvcnQgd2VpcmQgbm9uLWludGVncmFsIHZhbHVlcyBmb3IgYSBub3RjaGVkIHdoZWVsLFxuXHRcdC8vIGJ1dCBzdGlsbCBleHBvc2UgYWN0dWFsIGxpbmVzIHNjcm9sbGVkIHZpYSB3aGVlbERlbHRhLiBOb3RjaGVkIHdoZWVsc1xuXHRcdC8vIHNob3VsZCBiZWhhdmUgdGhlIHNhbWUgd2F5IGFzIGFycm93IGtleXMuXG5cdFx0aWYgKCBNYXRoLmZsb29yKCBlLmRlbHRhWSApICE9PSBlLmRlbHRhWSAmJiBlLndoZWVsRGVsdGEgKSB7XG5cdFx0XHRkZWx0YVggPSAwO1xuXHRcdFx0ZGVsdGFZID0gLWUud2hlZWxEZWx0YSAvIDEyMDtcblx0XHRcdGRlbHRhWSAqPSB0aGlzLl9zdGVwRXhwbGljaXQgPyAxIDogMTA7XG5cdFx0fVxuXG5cdFx0Y29uc3Qgd2hlZWwgPSBkZWx0YVggKyAtZGVsdGFZO1xuXG5cdFx0cmV0dXJuIHdoZWVsO1xuXG5cdH1cblxuXHRfYXJyb3dLZXlNdWx0aXBsaWVyKCBlICkge1xuXG5cdFx0bGV0IG11bHQgPSB0aGlzLl9zdGVwRXhwbGljaXQgPyAxIDogMTA7XG5cblx0XHRpZiAoIGUuc2hpZnRLZXkgKSB7XG5cdFx0XHRtdWx0ICo9IDEwO1xuXHRcdH0gZWxzZSBpZiAoIGUuYWx0S2V5ICkge1xuXHRcdFx0bXVsdCAvPSAxMDtcblx0XHR9XG5cblx0XHRyZXR1cm4gbXVsdDtcblxuXHR9XG5cblx0X3NuYXAoIHZhbHVlICkge1xuXG5cdFx0Ly8gVGhpcyB3b3VsZCBiZSB0aGUgbG9naWNhbCB3YXkgdG8gZG8gdGhpbmdzLCBidXQgZmxvYXRpbmcgcG9pbnQgZXJyb3JzLlxuXHRcdC8vIHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAvIHRoaXMuX3N0ZXAgKSAqIHRoaXMuX3N0ZXA7XG5cblx0XHQvLyBVc2luZyBpbnZlcnNlIHN0ZXAgc29sdmVzIGEgbG90IG9mIHRoZW0sIGJ1dCBub3QgYWxsXG5cdFx0Ly8gY29uc3QgaW52ZXJzZVN0ZXAgPSAxIC8gdGhpcy5fc3RlcDtcblx0XHQvLyByZXR1cm4gTWF0aC5yb3VuZCggdmFsdWUgKiBpbnZlcnNlU3RlcCApIC8gaW52ZXJzZVN0ZXA7XG5cblx0XHQvLyBOb3QgaGFwcHkgYWJvdXQgdGhpcywgYnV0IGhhdmVuJ3Qgc2VlbiBpdCBicmVhay5cblx0XHRjb25zdCByID0gTWF0aC5yb3VuZCggdmFsdWUgLyB0aGlzLl9zdGVwICkgKiB0aGlzLl9zdGVwO1xuXHRcdHJldHVybiBwYXJzZUZsb2F0KCByLnRvUHJlY2lzaW9uKCAxNSApICk7XG5cblx0fVxuXG5cdF9jbGFtcCggdmFsdWUgKSB7XG5cdFx0Ly8gZWl0aGVyIGNvbmRpdGlvbiBpcyBmYWxzZSBpZiBtaW4gb3IgbWF4IGlzIHVuZGVmaW5lZFxuXHRcdGlmICggdmFsdWUgPCB0aGlzLl9taW4gKSB2YWx1ZSA9IHRoaXMuX21pbjtcblx0XHRpZiAoIHZhbHVlID4gdGhpcy5fbWF4ICkgdmFsdWUgPSB0aGlzLl9tYXg7XG5cdFx0cmV0dXJuIHZhbHVlO1xuXHR9XG5cblx0X3NuYXBDbGFtcFNldFZhbHVlKCB2YWx1ZSApIHtcblx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLl9jbGFtcCggdGhpcy5fc25hcCggdmFsdWUgKSApICk7XG5cdH1cblxuXHRnZXQgX2hhc1Njcm9sbEJhcigpIHtcblx0XHRjb25zdCByb290ID0gdGhpcy5wYXJlbnQucm9vdC4kY2hpbGRyZW47XG5cdFx0cmV0dXJuIHJvb3Quc2Nyb2xsSGVpZ2h0ID4gcm9vdC5jbGllbnRIZWlnaHQ7XG5cdH1cblxuXHRnZXQgX2hhc01pbigpIHtcblx0XHRyZXR1cm4gdGhpcy5fbWluICE9PSB1bmRlZmluZWQ7XG5cdH1cblxuXHRnZXQgX2hhc01heCgpIHtcblx0XHRyZXR1cm4gdGhpcy5fbWF4ICE9PSB1bmRlZmluZWQ7XG5cdH1cblxufVxuXG5jbGFzcyBPcHRpb25Db250cm9sbGVyIGV4dGVuZHMgQ29udHJvbGxlciB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSwgb3B0aW9ucyApIHtcblxuXHRcdHN1cGVyKCBwYXJlbnQsIG9iamVjdCwgcHJvcGVydHksICdvcHRpb24nICk7XG5cblx0XHR0aGlzLiRzZWxlY3QgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnc2VsZWN0JyApO1xuXHRcdHRoaXMuJHNlbGVjdC5zZXRBdHRyaWJ1dGUoICdhcmlhLWxhYmVsbGVkYnknLCB0aGlzLiRuYW1lLmlkICk7XG5cblx0XHR0aGlzLiRkaXNwbGF5ID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggJ2RpdicgKTtcblx0XHR0aGlzLiRkaXNwbGF5LmNsYXNzTGlzdC5hZGQoICdkaXNwbGF5JyApO1xuXG5cdFx0dGhpcy4kc2VsZWN0LmFkZEV2ZW50TGlzdGVuZXIoICdjaGFuZ2UnLCAoKSA9PiB7XG5cdFx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLl92YWx1ZXNbIHRoaXMuJHNlbGVjdC5zZWxlY3RlZEluZGV4IF0gKTtcblx0XHRcdHRoaXMuX2NhbGxPbkZpbmlzaENoYW5nZSgpO1xuXHRcdH0gKTtcblxuXHRcdHRoaXMuJHNlbGVjdC5hZGRFdmVudExpc3RlbmVyKCAnZm9jdXMnLCAoKSA9PiB7XG5cdFx0XHR0aGlzLiRkaXNwbGF5LmNsYXNzTGlzdC5hZGQoICdmb2N1cycgKTtcblx0XHR9ICk7XG5cblx0XHR0aGlzLiRzZWxlY3QuYWRkRXZlbnRMaXN0ZW5lciggJ2JsdXInLCAoKSA9PiB7XG5cdFx0XHR0aGlzLiRkaXNwbGF5LmNsYXNzTGlzdC5yZW1vdmUoICdmb2N1cycgKTtcblx0XHR9ICk7XG5cblx0XHR0aGlzLiR3aWRnZXQuYXBwZW5kQ2hpbGQoIHRoaXMuJHNlbGVjdCApO1xuXHRcdHRoaXMuJHdpZGdldC5hcHBlbmRDaGlsZCggdGhpcy4kZGlzcGxheSApO1xuXG5cdFx0dGhpcy4kZGlzYWJsZSA9IHRoaXMuJHNlbGVjdDtcblxuXHRcdHRoaXMub3B0aW9ucyggb3B0aW9ucyApO1xuXG5cdH1cblxuXHRvcHRpb25zKCBvcHRpb25zICkge1xuXG5cdFx0dGhpcy5fdmFsdWVzID0gQXJyYXkuaXNBcnJheSggb3B0aW9ucyApID8gb3B0aW9ucyA6IE9iamVjdC52YWx1ZXMoIG9wdGlvbnMgKTtcblx0XHR0aGlzLl9uYW1lcyA9IEFycmF5LmlzQXJyYXkoIG9wdGlvbnMgKSA/IG9wdGlvbnMgOiBPYmplY3Qua2V5cyggb3B0aW9ucyApO1xuXG5cdFx0dGhpcy4kc2VsZWN0LnJlcGxhY2VDaGlsZHJlbigpO1xuXG5cdFx0dGhpcy5fbmFtZXMuZm9yRWFjaCggbmFtZSA9PiB7XG5cdFx0XHRjb25zdCAkb3B0aW9uID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCggJ29wdGlvbicgKTtcblx0XHRcdCRvcHRpb24udGV4dENvbnRlbnQgPSBuYW1lO1xuXHRcdFx0dGhpcy4kc2VsZWN0LmFwcGVuZENoaWxkKCAkb3B0aW9uICk7XG5cdFx0fSApO1xuXG5cdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dXBkYXRlRGlzcGxheSgpIHtcblx0XHRjb25zdCB2YWx1ZSA9IHRoaXMuZ2V0VmFsdWUoKTtcblx0XHRjb25zdCBpbmRleCA9IHRoaXMuX3ZhbHVlcy5pbmRleE9mKCB2YWx1ZSApO1xuXHRcdHRoaXMuJHNlbGVjdC5zZWxlY3RlZEluZGV4ID0gaW5kZXg7XG5cdFx0dGhpcy4kZGlzcGxheS50ZXh0Q29udGVudCA9IGluZGV4ID09PSAtMSA/IHZhbHVlIDogdGhpcy5fbmFtZXNbIGluZGV4IF07XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxufVxuXG5jbGFzcyBTdHJpbmdDb250cm9sbGVyIGV4dGVuZHMgQ29udHJvbGxlciB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmVudCwgb2JqZWN0LCBwcm9wZXJ0eSApIHtcblxuXHRcdHN1cGVyKCBwYXJlbnQsIG9iamVjdCwgcHJvcGVydHksICdzdHJpbmcnICk7XG5cblx0XHR0aGlzLiRpbnB1dCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdpbnB1dCcgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICd0eXBlJywgJ3RleHQnICk7XG5cdFx0dGhpcy4kaW5wdXQuc2V0QXR0cmlidXRlKCAnc3BlbGxjaGVjaycsICdmYWxzZScgKTtcblx0XHR0aGlzLiRpbnB1dC5zZXRBdHRyaWJ1dGUoICdhcmlhLWxhYmVsbGVkYnknLCB0aGlzLiRuYW1lLmlkICk7XG5cblx0XHR0aGlzLiRpbnB1dC5hZGRFdmVudExpc3RlbmVyKCAnaW5wdXQnLCAoKSA9PiB7XG5cdFx0XHR0aGlzLnNldFZhbHVlKCB0aGlzLiRpbnB1dC52YWx1ZSApO1xuXHRcdH0gKTtcblxuXHRcdHRoaXMuJGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoICdrZXlkb3duJywgZSA9PiB7XG5cdFx0XHRpZiAoIGUuY29kZSA9PT0gJ0VudGVyJyApIHtcblx0XHRcdFx0dGhpcy4kaW5wdXQuYmx1cigpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdHRoaXMuJGlucHV0LmFkZEV2ZW50TGlzdGVuZXIoICdibHVyJywgKCkgPT4ge1xuXHRcdFx0dGhpcy5fY2FsbE9uRmluaXNoQ2hhbmdlKCk7XG5cdFx0fSApO1xuXG5cdFx0dGhpcy4kd2lkZ2V0LmFwcGVuZENoaWxkKCB0aGlzLiRpbnB1dCApO1xuXG5cdFx0dGhpcy4kZGlzYWJsZSA9IHRoaXMuJGlucHV0O1xuXG5cdFx0dGhpcy51cGRhdGVEaXNwbGF5KCk7XG5cblx0fVxuXG5cdHVwZGF0ZURpc3BsYXkoKSB7XG5cdFx0dGhpcy4kaW5wdXQudmFsdWUgPSB0aGlzLmdldFZhbHVlKCk7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxufVxuXG5jb25zdCBzdHlsZXNoZWV0ID0gYC5saWwtZ3VpIHtcbiAgZm9udC1mYW1pbHk6IHZhcigtLWZvbnQtZmFtaWx5KTtcbiAgZm9udC1zaXplOiB2YXIoLS1mb250LXNpemUpO1xuICBsaW5lLWhlaWdodDogMTtcbiAgZm9udC13ZWlnaHQ6IG5vcm1hbDtcbiAgZm9udC1zdHlsZTogbm9ybWFsO1xuICB0ZXh0LWFsaWduOiBsZWZ0O1xuICBjb2xvcjogdmFyKC0tdGV4dC1jb2xvcik7XG4gIHVzZXItc2VsZWN0OiBub25lO1xuICAtd2Via2l0LXVzZXItc2VsZWN0OiBub25lO1xuICB0b3VjaC1hY3Rpb246IG1hbmlwdWxhdGlvbjtcbiAgLS1iYWNrZ3JvdW5kLWNvbG9yOiAjMWYxZjFmO1xuICAtLXRleHQtY29sb3I6ICNlYmViZWI7XG4gIC0tdGl0bGUtYmFja2dyb3VuZC1jb2xvcjogIzExMTExMTtcbiAgLS10aXRsZS10ZXh0LWNvbG9yOiAjZWJlYmViO1xuICAtLXdpZGdldC1jb2xvcjogIzQyNDI0MjtcbiAgLS1ob3Zlci1jb2xvcjogIzRmNGY0ZjtcbiAgLS1mb2N1cy1jb2xvcjogIzU5NTk1OTtcbiAgLS1udW1iZXItY29sb3I6ICMyY2M5ZmY7XG4gIC0tc3RyaW5nLWNvbG9yOiAjYTJkYjNjO1xuICAtLWZvbnQtc2l6ZTogMTFweDtcbiAgLS1pbnB1dC1mb250LXNpemU6IDExcHg7XG4gIC0tZm9udC1mYW1pbHk6IC1hcHBsZS1zeXN0ZW0sIEJsaW5rTWFjU3lzdGVtRm9udCwgXCJTZWdvZSBVSVwiLCBSb2JvdG8sIEFyaWFsLCBzYW5zLXNlcmlmO1xuICAtLWZvbnQtZmFtaWx5LW1vbm86IE1lbmxvLCBNb25hY28sIENvbnNvbGFzLCBcIkRyb2lkIFNhbnMgTW9ub1wiLCBtb25vc3BhY2U7XG4gIC0tcGFkZGluZzogNHB4O1xuICAtLXNwYWNpbmc6IDRweDtcbiAgLS13aWRnZXQtaGVpZ2h0OiAyMHB4O1xuICAtLXRpdGxlLWhlaWdodDogY2FsYyh2YXIoLS13aWRnZXQtaGVpZ2h0KSArIHZhcigtLXNwYWNpbmcpICogMS4yNSk7XG4gIC0tbmFtZS13aWR0aDogNDUlO1xuICAtLXNsaWRlci1rbm9iLXdpZHRoOiAycHg7XG4gIC0tc2xpZGVyLWlucHV0LXdpZHRoOiAyNyU7XG4gIC0tY29sb3ItaW5wdXQtd2lkdGg6IDI3JTtcbiAgLS1zbGlkZXItaW5wdXQtbWluLXdpZHRoOiA0NXB4O1xuICAtLWNvbG9yLWlucHV0LW1pbi13aWR0aDogNDVweDtcbiAgLS1mb2xkZXItaW5kZW50OiA3cHg7XG4gIC0td2lkZ2V0LXBhZGRpbmc6IDAgMCAwIDNweDtcbiAgLS13aWRnZXQtYm9yZGVyLXJhZGl1czogMnB4O1xuICAtLWNoZWNrYm94LXNpemU6IGNhbGMoMC43NSAqIHZhcigtLXdpZGdldC1oZWlnaHQpKTtcbiAgLS1zY3JvbGxiYXItd2lkdGg6IDVweDtcbn1cbi5saWwtZ3VpLCAubGlsLWd1aSAqIHtcbiAgYm94LXNpemluZzogYm9yZGVyLWJveDtcbiAgbWFyZ2luOiAwO1xuICBwYWRkaW5nOiAwO1xufVxuLmxpbC1ndWkucm9vdCB7XG4gIHdpZHRoOiB2YXIoLS13aWR0aCwgMjQ1cHgpO1xuICBkaXNwbGF5OiBmbGV4O1xuICBmbGV4LWRpcmVjdGlvbjogY29sdW1uO1xuICBiYWNrZ3JvdW5kOiB2YXIoLS1iYWNrZ3JvdW5kLWNvbG9yKTtcbn1cbi5saWwtZ3VpLnJvb3QgPiAudGl0bGUge1xuICBiYWNrZ3JvdW5kOiB2YXIoLS10aXRsZS1iYWNrZ3JvdW5kLWNvbG9yKTtcbiAgY29sb3I6IHZhcigtLXRpdGxlLXRleHQtY29sb3IpO1xufVxuLmxpbC1ndWkucm9vdCA+IC5jaGlsZHJlbiB7XG4gIG92ZXJmbG93LXg6IGhpZGRlbjtcbiAgb3ZlcmZsb3cteTogYXV0bztcbn1cbi5saWwtZ3VpLnJvb3QgPiAuY2hpbGRyZW46Oi13ZWJraXQtc2Nyb2xsYmFyIHtcbiAgd2lkdGg6IHZhcigtLXNjcm9sbGJhci13aWR0aCk7XG4gIGhlaWdodDogdmFyKC0tc2Nyb2xsYmFyLXdpZHRoKTtcbiAgYmFja2dyb3VuZDogdmFyKC0tYmFja2dyb3VuZC1jb2xvcik7XG59XG4ubGlsLWd1aS5yb290ID4gLmNoaWxkcmVuOjotd2Via2l0LXNjcm9sbGJhci10aHVtYiB7XG4gIGJvcmRlci1yYWRpdXM6IHZhcigtLXNjcm9sbGJhci13aWR0aCk7XG4gIGJhY2tncm91bmQ6IHZhcigtLWZvY3VzLWNvbG9yKTtcbn1cbkBtZWRpYSAocG9pbnRlcjogY29hcnNlKSB7XG4gIC5saWwtZ3VpLmFsbG93LXRvdWNoLXN0eWxlcywgLmxpbC1ndWkuYWxsb3ctdG91Y2gtc3R5bGVzIC5saWwtZ3VpIHtcbiAgICAtLXdpZGdldC1oZWlnaHQ6IDI4cHg7XG4gICAgLS1wYWRkaW5nOiA2cHg7XG4gICAgLS1zcGFjaW5nOiA2cHg7XG4gICAgLS1mb250LXNpemU6IDEzcHg7XG4gICAgLS1pbnB1dC1mb250LXNpemU6IDE2cHg7XG4gICAgLS1mb2xkZXItaW5kZW50OiAxMHB4O1xuICAgIC0tc2Nyb2xsYmFyLXdpZHRoOiA3cHg7XG4gICAgLS1zbGlkZXItaW5wdXQtbWluLXdpZHRoOiA1MHB4O1xuICAgIC0tY29sb3ItaW5wdXQtbWluLXdpZHRoOiA2NXB4O1xuICB9XG59XG4ubGlsLWd1aS5mb3JjZS10b3VjaC1zdHlsZXMsIC5saWwtZ3VpLmZvcmNlLXRvdWNoLXN0eWxlcyAubGlsLWd1aSB7XG4gIC0td2lkZ2V0LWhlaWdodDogMjhweDtcbiAgLS1wYWRkaW5nOiA2cHg7XG4gIC0tc3BhY2luZzogNnB4O1xuICAtLWZvbnQtc2l6ZTogMTNweDtcbiAgLS1pbnB1dC1mb250LXNpemU6IDE2cHg7XG4gIC0tZm9sZGVyLWluZGVudDogMTBweDtcbiAgLS1zY3JvbGxiYXItd2lkdGg6IDdweDtcbiAgLS1zbGlkZXItaW5wdXQtbWluLXdpZHRoOiA1MHB4O1xuICAtLWNvbG9yLWlucHV0LW1pbi13aWR0aDogNjVweDtcbn1cbi5saWwtZ3VpLmF1dG9QbGFjZSB7XG4gIG1heC1oZWlnaHQ6IDEwMCU7XG4gIHBvc2l0aW9uOiBmaXhlZDtcbiAgdG9wOiAwO1xuICByaWdodDogMTVweDtcbiAgei1pbmRleDogMTAwMTtcbn1cblxuLmxpbC1ndWkgLmNvbnRyb2xsZXIge1xuICBkaXNwbGF5OiBmbGV4O1xuICBhbGlnbi1pdGVtczogY2VudGVyO1xuICBwYWRkaW5nOiAwIHZhcigtLXBhZGRpbmcpO1xuICBtYXJnaW46IHZhcigtLXNwYWNpbmcpIDA7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5kaXNhYmxlZCB7XG4gIG9wYWNpdHk6IDAuNTtcbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyLmRpc2FibGVkLCAubGlsLWd1aSAuY29udHJvbGxlci5kaXNhYmxlZCAqIHtcbiAgcG9pbnRlci1ldmVudHM6IG5vbmUgIWltcG9ydGFudDtcbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyID4gLm5hbWUge1xuICBtaW4td2lkdGg6IHZhcigtLW5hbWUtd2lkdGgpO1xuICBmbGV4LXNocmluazogMDtcbiAgd2hpdGUtc3BhY2U6IHByZTtcbiAgcGFkZGluZy1yaWdodDogdmFyKC0tc3BhY2luZyk7XG4gIGxpbmUtaGVpZ2h0OiB2YXIoLS13aWRnZXQtaGVpZ2h0KTtcbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyIC53aWRnZXQge1xuICBwb3NpdGlvbjogcmVsYXRpdmU7XG4gIGRpc3BsYXk6IGZsZXg7XG4gIGFsaWduLWl0ZW1zOiBjZW50ZXI7XG4gIHdpZHRoOiAxMDAlO1xuICBtaW4taGVpZ2h0OiB2YXIoLS13aWRnZXQtaGVpZ2h0KTtcbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyLnN0cmluZyBpbnB1dCB7XG4gIGNvbG9yOiB2YXIoLS1zdHJpbmctY29sb3IpO1xufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIuYm9vbGVhbiB7XG4gIGN1cnNvcjogcG9pbnRlcjtcbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyLmNvbG9yIC5kaXNwbGF5IHtcbiAgd2lkdGg6IDEwMCU7XG4gIGhlaWdodDogdmFyKC0td2lkZ2V0LWhlaWdodCk7XG4gIGJvcmRlci1yYWRpdXM6IHZhcigtLXdpZGdldC1ib3JkZXItcmFkaXVzKTtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xufVxuQG1lZGlhIChob3ZlcjogaG92ZXIpIHtcbiAgLmxpbC1ndWkgLmNvbnRyb2xsZXIuY29sb3IgLmRpc3BsYXk6aG92ZXI6YmVmb3JlIHtcbiAgICBjb250ZW50OiBcIiBcIjtcbiAgICBkaXNwbGF5OiBibG9jaztcbiAgICBwb3NpdGlvbjogYWJzb2x1dGU7XG4gICAgYm9yZGVyLXJhZGl1czogdmFyKC0td2lkZ2V0LWJvcmRlci1yYWRpdXMpO1xuICAgIGJvcmRlcjogMXB4IHNvbGlkICNmZmY5O1xuICAgIHRvcDogMDtcbiAgICByaWdodDogMDtcbiAgICBib3R0b206IDA7XG4gICAgbGVmdDogMDtcbiAgfVxufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIuY29sb3IgaW5wdXRbdHlwZT1jb2xvcl0ge1xuICBvcGFjaXR5OiAwO1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiAxMDAlO1xuICBjdXJzb3I6IHBvaW50ZXI7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5jb2xvciBpbnB1dFt0eXBlPXRleHRdIHtcbiAgbWFyZ2luLWxlZnQ6IHZhcigtLXNwYWNpbmcpO1xuICBmb250LWZhbWlseTogdmFyKC0tZm9udC1mYW1pbHktbW9ubyk7XG4gIG1pbi13aWR0aDogdmFyKC0tY29sb3ItaW5wdXQtbWluLXdpZHRoKTtcbiAgd2lkdGg6IHZhcigtLWNvbG9yLWlucHV0LXdpZHRoKTtcbiAgZmxleC1zaHJpbms6IDA7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5vcHRpb24gc2VsZWN0IHtcbiAgb3BhY2l0eTogMDtcbiAgcG9zaXRpb246IGFic29sdXRlO1xuICB3aWR0aDogMTAwJTtcbiAgbWF4LXdpZHRoOiAxMDAlO1xufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIub3B0aW9uIC5kaXNwbGF5IHtcbiAgcG9zaXRpb246IHJlbGF0aXZlO1xuICBwb2ludGVyLWV2ZW50czogbm9uZTtcbiAgYm9yZGVyLXJhZGl1czogdmFyKC0td2lkZ2V0LWJvcmRlci1yYWRpdXMpO1xuICBoZWlnaHQ6IHZhcigtLXdpZGdldC1oZWlnaHQpO1xuICBsaW5lLWhlaWdodDogdmFyKC0td2lkZ2V0LWhlaWdodCk7XG4gIG1heC13aWR0aDogMTAwJTtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgd29yZC1icmVhazogYnJlYWstYWxsO1xuICBwYWRkaW5nLWxlZnQ6IDAuNTVlbTtcbiAgcGFkZGluZy1yaWdodDogMS43NWVtO1xuICBiYWNrZ3JvdW5kOiB2YXIoLS13aWRnZXQtY29sb3IpO1xufVxuQG1lZGlhIChob3ZlcjogaG92ZXIpIHtcbiAgLmxpbC1ndWkgLmNvbnRyb2xsZXIub3B0aW9uIC5kaXNwbGF5LmZvY3VzIHtcbiAgICBiYWNrZ3JvdW5kOiB2YXIoLS1mb2N1cy1jb2xvcik7XG4gIH1cbn1cbi5saWwtZ3VpIC5jb250cm9sbGVyLm9wdGlvbiAuZGlzcGxheS5hY3RpdmUge1xuICBiYWNrZ3JvdW5kOiB2YXIoLS1mb2N1cy1jb2xvcik7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5vcHRpb24gLmRpc3BsYXk6YWZ0ZXIge1xuICBmb250LWZhbWlseTogXCJsaWwtZ3VpXCI7XG4gIGNvbnRlbnQ6IFwi4oaVXCI7XG4gIHBvc2l0aW9uOiBhYnNvbHV0ZTtcbiAgdG9wOiAwO1xuICByaWdodDogMDtcbiAgYm90dG9tOiAwO1xuICBwYWRkaW5nLXJpZ2h0OiAwLjM3NWVtO1xufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIub3B0aW9uIC53aWRnZXQsXG4ubGlsLWd1aSAuY29udHJvbGxlci5vcHRpb24gc2VsZWN0IHtcbiAgY3Vyc29yOiBwb2ludGVyO1xufVxuQG1lZGlhIChob3ZlcjogaG92ZXIpIHtcbiAgLmxpbC1ndWkgLmNvbnRyb2xsZXIub3B0aW9uIC53aWRnZXQ6aG92ZXIgLmRpc3BsYXkge1xuICAgIGJhY2tncm91bmQ6IHZhcigtLWhvdmVyLWNvbG9yKTtcbiAgfVxufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIubnVtYmVyIGlucHV0IHtcbiAgY29sb3I6IHZhcigtLW51bWJlci1jb2xvcik7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5udW1iZXIuaGFzU2xpZGVyIGlucHV0IHtcbiAgbWFyZ2luLWxlZnQ6IHZhcigtLXNwYWNpbmcpO1xuICB3aWR0aDogdmFyKC0tc2xpZGVyLWlucHV0LXdpZHRoKTtcbiAgbWluLXdpZHRoOiB2YXIoLS1zbGlkZXItaW5wdXQtbWluLXdpZHRoKTtcbiAgZmxleC1zaHJpbms6IDA7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5udW1iZXIgLnNsaWRlciB7XG4gIHdpZHRoOiAxMDAlO1xuICBoZWlnaHQ6IHZhcigtLXdpZGdldC1oZWlnaHQpO1xuICBiYWNrZ3JvdW5kOiB2YXIoLS13aWRnZXQtY29sb3IpO1xuICBib3JkZXItcmFkaXVzOiB2YXIoLS13aWRnZXQtYm9yZGVyLXJhZGl1cyk7XG4gIHBhZGRpbmctcmlnaHQ6IHZhcigtLXNsaWRlci1rbm9iLXdpZHRoKTtcbiAgb3ZlcmZsb3c6IGhpZGRlbjtcbiAgY3Vyc29yOiBldy1yZXNpemU7XG4gIHRvdWNoLWFjdGlvbjogcGFuLXk7XG59XG5AbWVkaWEgKGhvdmVyOiBob3Zlcikge1xuICAubGlsLWd1aSAuY29udHJvbGxlci5udW1iZXIgLnNsaWRlcjpob3ZlciB7XG4gICAgYmFja2dyb3VuZDogdmFyKC0taG92ZXItY29sb3IpO1xuICB9XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5udW1iZXIgLnNsaWRlci5hY3RpdmUge1xuICBiYWNrZ3JvdW5kOiB2YXIoLS1mb2N1cy1jb2xvcik7XG59XG4ubGlsLWd1aSAuY29udHJvbGxlci5udW1iZXIgLnNsaWRlci5hY3RpdmUgLmZpbGwge1xuICBvcGFjaXR5OiAwLjk1O1xufVxuLmxpbC1ndWkgLmNvbnRyb2xsZXIubnVtYmVyIC5maWxsIHtcbiAgaGVpZ2h0OiAxMDAlO1xuICBib3JkZXItcmlnaHQ6IHZhcigtLXNsaWRlci1rbm9iLXdpZHRoKSBzb2xpZCB2YXIoLS1udW1iZXItY29sb3IpO1xuICBib3gtc2l6aW5nOiBjb250ZW50LWJveDtcbn1cblxuLmxpbC1ndWktZHJhZ2dpbmcgLmxpbC1ndWkge1xuICAtLWhvdmVyLWNvbG9yOiB2YXIoLS13aWRnZXQtY29sb3IpO1xufVxuLmxpbC1ndWktZHJhZ2dpbmcgKiB7XG4gIGN1cnNvcjogZXctcmVzaXplICFpbXBvcnRhbnQ7XG59XG5cbi5saWwtZ3VpLWRyYWdnaW5nLmxpbC1ndWktdmVydGljYWwgKiB7XG4gIGN1cnNvcjogbnMtcmVzaXplICFpbXBvcnRhbnQ7XG59XG5cbi5saWwtZ3VpIC50aXRsZSB7XG4gIGhlaWdodDogdmFyKC0tdGl0bGUtaGVpZ2h0KTtcbiAgbGluZS1oZWlnaHQ6IGNhbGModmFyKC0tdGl0bGUtaGVpZ2h0KSAtIDRweCk7XG4gIGZvbnQtd2VpZ2h0OiA2MDA7XG4gIHBhZGRpbmc6IDAgdmFyKC0tcGFkZGluZyk7XG4gIC13ZWJraXQtdGFwLWhpZ2hsaWdodC1jb2xvcjogdHJhbnNwYXJlbnQ7XG4gIGN1cnNvcjogcG9pbnRlcjtcbiAgb3V0bGluZTogbm9uZTtcbiAgdGV4dC1kZWNvcmF0aW9uLXNraXA6IG9iamVjdHM7XG59XG4ubGlsLWd1aSAudGl0bGU6YmVmb3JlIHtcbiAgZm9udC1mYW1pbHk6IFwibGlsLWd1aVwiO1xuICBjb250ZW50OiBcIuKWvlwiO1xuICBwYWRkaW5nLXJpZ2h0OiAycHg7XG4gIGRpc3BsYXk6IGlubGluZS1ibG9jaztcbn1cbi5saWwtZ3VpIC50aXRsZTphY3RpdmUge1xuICBiYWNrZ3JvdW5kOiB2YXIoLS10aXRsZS1iYWNrZ3JvdW5kLWNvbG9yKTtcbiAgb3BhY2l0eTogMC43NTtcbn1cbkBtZWRpYSAoaG92ZXI6IGhvdmVyKSB7XG4gIGJvZHk6bm90KC5saWwtZ3VpLWRyYWdnaW5nKSAubGlsLWd1aSAudGl0bGU6aG92ZXIge1xuICAgIGJhY2tncm91bmQ6IHZhcigtLXRpdGxlLWJhY2tncm91bmQtY29sb3IpO1xuICAgIG9wYWNpdHk6IDAuODU7XG4gIH1cbiAgLmxpbC1ndWkgLnRpdGxlOmZvY3VzIHtcbiAgICB0ZXh0LWRlY29yYXRpb246IHVuZGVybGluZSB2YXIoLS1mb2N1cy1jb2xvcik7XG4gIH1cbn1cbi5saWwtZ3VpLnJvb3QgPiAudGl0bGU6Zm9jdXMge1xuICB0ZXh0LWRlY29yYXRpb246IG5vbmUgIWltcG9ydGFudDtcbn1cbi5saWwtZ3VpLmNsb3NlZCA+IC50aXRsZTpiZWZvcmUge1xuICBjb250ZW50OiBcIuKWuFwiO1xufVxuLmxpbC1ndWkuY2xvc2VkID4gLmNoaWxkcmVuIHtcbiAgdHJhbnNmb3JtOiB0cmFuc2xhdGVZKC03cHgpO1xuICBvcGFjaXR5OiAwO1xufVxuLmxpbC1ndWkuY2xvc2VkOm5vdCgudHJhbnNpdGlvbikgPiAuY2hpbGRyZW4ge1xuICBkaXNwbGF5OiBub25lO1xufVxuLmxpbC1ndWkudHJhbnNpdGlvbiA+IC5jaGlsZHJlbiB7XG4gIHRyYW5zaXRpb24tZHVyYXRpb246IDMwMG1zO1xuICB0cmFuc2l0aW9uLXByb3BlcnR5OiBoZWlnaHQsIG9wYWNpdHksIHRyYW5zZm9ybTtcbiAgdHJhbnNpdGlvbi10aW1pbmctZnVuY3Rpb246IGN1YmljLWJlemllcigwLjIsIDAuNiwgMC4zNSwgMSk7XG4gIG92ZXJmbG93OiBoaWRkZW47XG4gIHBvaW50ZXItZXZlbnRzOiBub25lO1xufVxuLmxpbC1ndWkgLmNoaWxkcmVuOmVtcHR5OmJlZm9yZSB7XG4gIGNvbnRlbnQ6IFwiRW1wdHlcIjtcbiAgcGFkZGluZzogMCB2YXIoLS1wYWRkaW5nKTtcbiAgbWFyZ2luOiB2YXIoLS1zcGFjaW5nKSAwO1xuICBkaXNwbGF5OiBibG9jaztcbiAgaGVpZ2h0OiB2YXIoLS13aWRnZXQtaGVpZ2h0KTtcbiAgZm9udC1zdHlsZTogaXRhbGljO1xuICBsaW5lLWhlaWdodDogdmFyKC0td2lkZ2V0LWhlaWdodCk7XG4gIG9wYWNpdHk6IDAuNTtcbn1cbi5saWwtZ3VpLnJvb3QgPiAuY2hpbGRyZW4gPiAubGlsLWd1aSA+IC50aXRsZSB7XG4gIGJvcmRlcjogMCBzb2xpZCB2YXIoLS13aWRnZXQtY29sb3IpO1xuICBib3JkZXItd2lkdGg6IDFweCAwO1xuICB0cmFuc2l0aW9uOiBib3JkZXItY29sb3IgMzAwbXM7XG59XG4ubGlsLWd1aS5yb290ID4gLmNoaWxkcmVuID4gLmxpbC1ndWkuY2xvc2VkID4gLnRpdGxlIHtcbiAgYm9yZGVyLWJvdHRvbS1jb2xvcjogdHJhbnNwYXJlbnQ7XG59XG4ubGlsLWd1aSArIC5jb250cm9sbGVyIHtcbiAgYm9yZGVyLXRvcDogMXB4IHNvbGlkIHZhcigtLXdpZGdldC1jb2xvcik7XG4gIG1hcmdpbi10b3A6IDA7XG4gIHBhZGRpbmctdG9wOiB2YXIoLS1zcGFjaW5nKTtcbn1cbi5saWwtZ3VpIC5saWwtZ3VpIC5saWwtZ3VpID4gLnRpdGxlIHtcbiAgYm9yZGVyOiBub25lO1xufVxuLmxpbC1ndWkgLmxpbC1ndWkgLmxpbC1ndWkgPiAuY2hpbGRyZW4ge1xuICBib3JkZXI6IG5vbmU7XG4gIG1hcmdpbi1sZWZ0OiB2YXIoLS1mb2xkZXItaW5kZW50KTtcbiAgYm9yZGVyLWxlZnQ6IDJweCBzb2xpZCB2YXIoLS13aWRnZXQtY29sb3IpO1xufVxuLmxpbC1ndWkgLmxpbC1ndWkgLmNvbnRyb2xsZXIge1xuICBib3JkZXI6IG5vbmU7XG59XG5cbi5saWwtZ3VpIGxhYmVsLCAubGlsLWd1aSBpbnB1dCwgLmxpbC1ndWkgYnV0dG9uIHtcbiAgLXdlYmtpdC10YXAtaGlnaGxpZ2h0LWNvbG9yOiB0cmFuc3BhcmVudDtcbn1cbi5saWwtZ3VpIGlucHV0IHtcbiAgYm9yZGVyOiAwO1xuICBvdXRsaW5lOiBub25lO1xuICBmb250LWZhbWlseTogdmFyKC0tZm9udC1mYW1pbHkpO1xuICBmb250LXNpemU6IHZhcigtLWlucHV0LWZvbnQtc2l6ZSk7XG4gIGJvcmRlci1yYWRpdXM6IHZhcigtLXdpZGdldC1ib3JkZXItcmFkaXVzKTtcbiAgaGVpZ2h0OiB2YXIoLS13aWRnZXQtaGVpZ2h0KTtcbiAgYmFja2dyb3VuZDogdmFyKC0td2lkZ2V0LWNvbG9yKTtcbiAgY29sb3I6IHZhcigtLXRleHQtY29sb3IpO1xuICB3aWR0aDogMTAwJTtcbn1cbkBtZWRpYSAoaG92ZXI6IGhvdmVyKSB7XG4gIC5saWwtZ3VpIGlucHV0OmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kOiB2YXIoLS1ob3Zlci1jb2xvcik7XG4gIH1cbiAgLmxpbC1ndWkgaW5wdXQ6YWN0aXZlIHtcbiAgICBiYWNrZ3JvdW5kOiB2YXIoLS1mb2N1cy1jb2xvcik7XG4gIH1cbn1cbi5saWwtZ3VpIGlucHV0OmRpc2FibGVkIHtcbiAgb3BhY2l0eTogMTtcbn1cbi5saWwtZ3VpIGlucHV0W3R5cGU9dGV4dF0sXG4ubGlsLWd1aSBpbnB1dFt0eXBlPW51bWJlcl0ge1xuICBwYWRkaW5nOiB2YXIoLS13aWRnZXQtcGFkZGluZyk7XG4gIC1tb3otYXBwZWFyYW5jZTogdGV4dGZpZWxkO1xufVxuLmxpbC1ndWkgaW5wdXRbdHlwZT10ZXh0XTpmb2N1cyxcbi5saWwtZ3VpIGlucHV0W3R5cGU9bnVtYmVyXTpmb2N1cyB7XG4gIGJhY2tncm91bmQ6IHZhcigtLWZvY3VzLWNvbG9yKTtcbn1cbi5saWwtZ3VpIGlucHV0W3R5cGU9Y2hlY2tib3hdIHtcbiAgYXBwZWFyYW5jZTogbm9uZTtcbiAgd2lkdGg6IHZhcigtLWNoZWNrYm94LXNpemUpO1xuICBoZWlnaHQ6IHZhcigtLWNoZWNrYm94LXNpemUpO1xuICBib3JkZXItcmFkaXVzOiB2YXIoLS13aWRnZXQtYm9yZGVyLXJhZGl1cyk7XG4gIHRleHQtYWxpZ246IGNlbnRlcjtcbiAgY3Vyc29yOiBwb2ludGVyO1xufVxuLmxpbC1ndWkgaW5wdXRbdHlwZT1jaGVja2JveF06Y2hlY2tlZDpiZWZvcmUge1xuICBmb250LWZhbWlseTogXCJsaWwtZ3VpXCI7XG4gIGNvbnRlbnQ6IFwi4pyTXCI7XG4gIGZvbnQtc2l6ZTogdmFyKC0tY2hlY2tib3gtc2l6ZSk7XG4gIGxpbmUtaGVpZ2h0OiB2YXIoLS1jaGVja2JveC1zaXplKTtcbn1cbkBtZWRpYSAoaG92ZXI6IGhvdmVyKSB7XG4gIC5saWwtZ3VpIGlucHV0W3R5cGU9Y2hlY2tib3hdOmZvY3VzIHtcbiAgICBib3gtc2hhZG93OiBpbnNldCAwIDAgMCAxcHggdmFyKC0tZm9jdXMtY29sb3IpO1xuICB9XG59XG4ubGlsLWd1aSBidXR0b24ge1xuICBvdXRsaW5lOiBub25lO1xuICBjdXJzb3I6IHBvaW50ZXI7XG4gIGZvbnQtZmFtaWx5OiB2YXIoLS1mb250LWZhbWlseSk7XG4gIGZvbnQtc2l6ZTogdmFyKC0tZm9udC1zaXplKTtcbiAgY29sb3I6IHZhcigtLXRleHQtY29sb3IpO1xuICB3aWR0aDogMTAwJTtcbiAgaGVpZ2h0OiB2YXIoLS13aWRnZXQtaGVpZ2h0KTtcbiAgdGV4dC10cmFuc2Zvcm06IG5vbmU7XG4gIGJhY2tncm91bmQ6IHZhcigtLXdpZGdldC1jb2xvcik7XG4gIGJvcmRlci1yYWRpdXM6IHZhcigtLXdpZGdldC1ib3JkZXItcmFkaXVzKTtcbiAgYm9yZGVyOiBub25lO1xufVxuQG1lZGlhIChob3ZlcjogaG92ZXIpIHtcbiAgLmxpbC1ndWkgYnV0dG9uOmhvdmVyIHtcbiAgICBiYWNrZ3JvdW5kOiB2YXIoLS1ob3Zlci1jb2xvcik7XG4gIH1cbiAgLmxpbC1ndWkgYnV0dG9uOmZvY3VzIHtcbiAgICBib3gtc2hhZG93OiBpbnNldCAwIDAgMCAxcHggdmFyKC0tZm9jdXMtY29sb3IpO1xuICB9XG59XG4ubGlsLWd1aSBidXR0b246YWN0aXZlIHtcbiAgYmFja2dyb3VuZDogdmFyKC0tZm9jdXMtY29sb3IpO1xufVxuXG5AZm9udC1mYWNlIHtcbiAgZm9udC1mYW1pbHk6IFwibGlsLWd1aVwiO1xuICBzcmM6IHVybChcImRhdGE6YXBwbGljYXRpb24vZm9udC13b2ZmO2NoYXJzZXQ9dXRmLTg7YmFzZTY0LGQwOUdSZ0FCQUFBQUFBVXNBQXNBQUFBQUNKd0FBUUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFCSFUxVkNBQUFCQ0FBQUFINEFBQURBSW13bVlFOVRMeklBQUFHSUFBQUFQd0FBQUdCS3FINVNZMjFoY0FBQUFjZ0FBQUQwQUFBQ3J1a3l5SkJuYkhsbUFBQUN2QUFBQUY4QUFBQ0VJWnBXSDJobFlXUUFBQU1jQUFBQUp3QUFBRFpmY2oyemFHaGxZUUFBQTBRQUFBQVlBQUFBSkFDNUFIaG9iWFI0QUFBRFhBQUFBQkFBQUFCTUFaQUFBR3h2WTJFQUFBTnNBQUFBRkFBQUFDZ0NFZ0l5YldGNGNBQUFBNEFBQUFBZUFBQUFJQUVmQUJKdVlXMWxBQUFEb0FBQUFTSUFBQUlLOVNVVS9YQnZjM1FBQUFURUFBQUFaZ0FBQUpDVGNNYzJlSnhWamJFT2dqQVVSVStoRlJCSzFkR1JMK0FMbkFpVG95TUxFekZwblB6L2VBc2h3U2E5NzUxN2MvTXd3Sm1lQjlrd1BsKzBjZjUrdUdQWlhzcVB1NG52WmFiY1NabGRaNmtmeVdub21GWS9lU2NLcVpOV3VwS0pPNmtYTjNLOXVDVm9MN2lJblByMVg1YmFYczN0anVNcUN0ekV1YWdtL0FBbHpRZ1BBQUI0bkdOZ1lSQmxuTURBeXNEQVlNL2dCaVQ1b0xRQkF3dURKQU1ERXdNck13TldFSkRtbXNKd2dDRmVYWmdoQmNqbFpNZ0ZDek9pS09JRkFCNzFCYjhBZUp5MWtqRnV3a0FRUlorRHdSQXdCdE5RUlVHS1E4T2RLQ0FXVWhBZ0tMaEl1QXNWU3BXejVCYmtqM2RFZ1lpVUlzenFXZHBaZStaNy93QjFvQ1ltSW9ib2l3aUxUMldqS2wvanNjckhmR2cvcEtkTWt5a2xDNVpzMkxFZkhZcGpjUm9Qem1lOU1XV21rM2RXYks5T2JrV2tpa09ldEo1NTRmV3lvRXNtZFNsdCt1UjBwQ0pSMzRiNnQvVFZnMVNZM3NZdmRmOHZ1aUtycHlhRFhESVNpZWdwMTdwNzU3OUdwM3ArK3k3SFBBaVk5cG1UaWJsanJyODVxU2lkdGxnNCtsMjVHTENhUzhlNnJSeE5CbXNuRVJ1bktiYU9PYlJ6N043Mmp1NXZkQWpZcEJYSGdKeWxPQVZzTXNlREFQRVA4TFlvVUhpY1kyQmlBQUVmaGlBR0pnWldCZ1o3Um5GUmRuVkpFTENRbEJTUmxBVEpNb0xWMkRLNGdsU1lzNnVicTV2YktySkxTYkdyZ0Vtb3ZEdURKVmhlM1Z6Y1hGd05MQ09JTEIvQzRJdVExeFRuNUZQaWxCVGo1RlBtQkFCNFd3b3FBSGljWTJCa1lHQUE0c2sxc1IvaitXMitNbkF6cERCZ0F5RU1RVUNTZzRFSnhBRUF3VWdGSGdCNG5HTmdaR0JnU0dGZ2dKTWhESXdNcUVBWUFCeUhBVEo0bkdOZ0FJSVVORXdtQUFCbDNBR1JlSnhqWUFBQ0lRWWxCaU1HSjN3UUFFY1FCRVY0bkdOZ1pHQmdFR1pnWTJCaUFBRVF5UVdFREF6L3dYd0dBQXNQQVRJQUFIaWNYZEJOU3NOQUhBWHdsMzVpQTBVUVhZbk1TaGZTOUdQWkE3VDdMZ0l1MDNTU3Brd3pZVEl0MUJONEFrL2dLVHlBZUN4ZnczOWpaa2p5bXpjdkF3bUFXL3dnd0hVRUdEYjM2K2pRUTNHWEdvdDc5TDI0anhDUDRnSHpGL0VJcjRqRUllN3d4aE9DM2cyVE1ZeTRRNytMdS9TSHVFZC9pdnQ0d0pkNHdQeGJQRUtNWDNHSTUrREpGR2FTbjRxTnprOG1jYktTUjZ4ZFhkaFN6YU9aSkd0ZGFwZDR2VlBiaTZyUCtjTDdUR1hPSHRYS2xsNGJZMVhsN0VHblB0cDdYeTJuMDB6eUtMVkhma0hCYTRJY0oyb0QzY2dnZ1d2dC9WL0ZiRHJVbEVVSmhUbi8wYXpWV2JOVE5yMEVuczhkZTF0Y2VLOXhabWZCMUNQak9tUEg0a2l0bXZPdWJjTnBtVlROM29GSnlqekN2bm1yd2hKVHpxelZqOWppU1g5MTFGamVBQUI0bkczSE1SS0NNQkJBMGYwZ2lpS2k0RFU4azBWMkdXYklaRE9oNFBvV1d2cTZKNVY4SWY5TlZOUWNhRGh5b3VYTWhZNHJQVGNHN2p3WW1YaEtxOFd6K3A3NjJhTmFlWVhvbTJuM20yZExUVmdzckNnRko3T1RtSWtZYndJYkM2dklCN1dtRmZBQUFBPT1cIikgZm9ybWF0KFwid29mZlwiKTtcbn1gO1xuXG5mdW5jdGlvbiBfaW5qZWN0U3R5bGVzKCBjc3NDb250ZW50ICkge1xuXHRjb25zdCBpbmplY3RlZCA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdzdHlsZScgKTtcblx0aW5qZWN0ZWQuaW5uZXJIVE1MID0gY3NzQ29udGVudDtcblx0Y29uc3QgYmVmb3JlID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvciggJ2hlYWQgbGlua1tyZWw9c3R5bGVzaGVldF0sIGhlYWQgc3R5bGUnICk7XG5cdGlmICggYmVmb3JlICkge1xuXHRcdGRvY3VtZW50LmhlYWQuaW5zZXJ0QmVmb3JlKCBpbmplY3RlZCwgYmVmb3JlICk7XG5cdH0gZWxzZSB7XG5cdFx0ZG9jdW1lbnQuaGVhZC5hcHBlbmRDaGlsZCggaW5qZWN0ZWQgKTtcblx0fVxufVxuXG5sZXQgc3R5bGVzSW5qZWN0ZWQgPSBmYWxzZTtcblxuY2xhc3MgR1VJIHtcblxuXHQvKipcblx0ICogQ3JlYXRlcyBhIHBhbmVsIHRoYXQgaG9sZHMgY29udHJvbGxlcnMuXG5cdCAqIEBleGFtcGxlXG5cdCAqIG5ldyBHVUkoKTtcblx0ICogbmV3IEdVSSggeyBjb250YWluZXI6IGRvY3VtZW50LmdldEVsZW1lbnRCeUlkKCAnY3VzdG9tJyApIH0gKTtcblx0ICpcblx0ICogQHBhcmFtIHtvYmplY3R9IFtvcHRpb25zXVxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmF1dG9QbGFjZT10cnVlXVxuXHQgKiBBZGRzIHRoZSBHVUkgdG8gYGRvY3VtZW50LmJvZHlgIGFuZCBmaXhlcyBpdCB0byB0aGUgdG9wIHJpZ2h0IG9mIHRoZSBwYWdlLlxuXHQgKlxuXHQgKiBAcGFyYW0ge0hUTUxFbGVtZW50fSBbb3B0aW9ucy5jb250YWluZXJdXG5cdCAqIEFkZHMgdGhlIEdVSSB0byB0aGlzIERPTSBlbGVtZW50LiBPdmVycmlkZXMgYGF1dG9QbGFjZWAuXG5cdCAqXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy53aWR0aD0yNDVdXG5cdCAqIFdpZHRoIG9mIHRoZSBHVUkgaW4gcGl4ZWxzLCB1c3VhbGx5IHNldCB3aGVuIG5hbWUgbGFiZWxzIGJlY29tZSB0b28gbG9uZy4gTm90ZSB0aGF0IHlvdSBjYW4gbWFrZVxuXHQgKiBuYW1lIGxhYmVscyB3aWRlciBpbiBDU1Mgd2l0aCBgLmxpbOKAkWd1aSB7IOKAkeKAkW5hbWXigJF3aWR0aDogNTUlIH1gLlxuXHQgKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gW29wdGlvbnMudGl0bGU9Q29udHJvbHNdXG5cdCAqIE5hbWUgdG8gZGlzcGxheSBpbiB0aGUgdGl0bGUgYmFyLlxuXHQgKlxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmNsb3NlRm9sZGVycz1mYWxzZV1cblx0ICogUGFzcyBgdHJ1ZWAgdG8gY2xvc2UgYWxsIGZvbGRlcnMgaW4gdGhpcyBHVUkgYnkgZGVmYXVsdC5cblx0ICpcblx0ICogQHBhcmFtIHtib29sZWFufSBbb3B0aW9ucy5pbmplY3RTdHlsZXM9dHJ1ZV1cblx0ICogSW5qZWN0cyB0aGUgZGVmYXVsdCBzdHlsZXNoZWV0IGludG8gdGhlIHBhZ2UgaWYgdGhpcyBpcyB0aGUgZmlyc3QgR1VJLlxuXHQgKiBQYXNzIGBmYWxzZWAgdG8gdXNlIHlvdXIgb3duIHN0eWxlc2hlZXQuXG5cdCAqXG5cdCAqIEBwYXJhbSB7bnVtYmVyfSBbb3B0aW9ucy50b3VjaFN0eWxlcz10cnVlXVxuXHQgKiBNYWtlcyBjb250cm9sbGVycyBsYXJnZXIgb24gdG91Y2ggZGV2aWNlcy4gUGFzcyBgZmFsc2VgIHRvIGRpc2FibGUgdG91Y2ggc3R5bGVzLlxuXHQgKlxuXHQgKiBAcGFyYW0ge0dVSX0gW29wdGlvbnMucGFyZW50XVxuXHQgKiBBZGRzIHRoaXMgR1VJIGFzIGEgY2hpbGQgaW4gYW5vdGhlciBHVUkuIFVzdWFsbHkgdGhpcyBpcyBkb25lIGZvciB5b3UgYnkgYGFkZEZvbGRlcigpYC5cblx0ICpcblx0ICovXG5cdGNvbnN0cnVjdG9yKCB7XG5cdFx0cGFyZW50LFxuXHRcdGF1dG9QbGFjZSA9IHBhcmVudCA9PT0gdW5kZWZpbmVkLFxuXHRcdGNvbnRhaW5lcixcblx0XHR3aWR0aCxcblx0XHR0aXRsZSA9ICdDb250cm9scycsXG5cdFx0Y2xvc2VGb2xkZXJzID0gZmFsc2UsXG5cdFx0aW5qZWN0U3R5bGVzID0gdHJ1ZSxcblx0XHR0b3VjaFN0eWxlcyA9IHRydWVcblx0fSA9IHt9ICkge1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIEdVSSBjb250YWluaW5nIHRoaXMgZm9sZGVyLCBvciBgdW5kZWZpbmVkYCBpZiB0aGlzIGlzIHRoZSByb290IEdVSS5cblx0XHQgKiBAdHlwZSB7R1VJfVxuXHRcdCAqL1xuXHRcdHRoaXMucGFyZW50ID0gcGFyZW50O1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIHRvcCBsZXZlbCBHVUkgY29udGFpbmluZyB0aGlzIGZvbGRlciwgb3IgYHRoaXNgIGlmIHRoaXMgaXMgdGhlIHJvb3QgR1VJLlxuXHRcdCAqIEB0eXBlIHtHVUl9XG5cdFx0ICovXG5cdFx0dGhpcy5yb290ID0gcGFyZW50ID8gcGFyZW50LnJvb3QgOiB0aGlzO1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIGxpc3Qgb2YgY29udHJvbGxlcnMgYW5kIGZvbGRlcnMgY29udGFpbmVkIGJ5IHRoaXMgR1VJLlxuXHRcdCAqIEB0eXBlIHtBcnJheTxHVUl8Q29udHJvbGxlcj59XG5cdFx0ICovXG5cdFx0dGhpcy5jaGlsZHJlbiA9IFtdO1xuXG5cdFx0LyoqXG5cdFx0ICogVGhlIGxpc3Qgb2YgY29udHJvbGxlcnMgY29udGFpbmVkIGJ5IHRoaXMgR1VJLlxuXHRcdCAqIEB0eXBlIHtBcnJheTxDb250cm9sbGVyPn1cblx0XHQgKi9cblx0XHR0aGlzLmNvbnRyb2xsZXJzID0gW107XG5cblx0XHQvKipcblx0XHQgKiBUaGUgbGlzdCBvZiBmb2xkZXJzIGNvbnRhaW5lZCBieSB0aGlzIEdVSS5cblx0XHQgKiBAdHlwZSB7QXJyYXk8R1VJPn1cblx0XHQgKi9cblx0XHR0aGlzLmZvbGRlcnMgPSBbXTtcblxuXHRcdC8qKlxuXHRcdCAqIFVzZWQgdG8gZGV0ZXJtaW5lIGlmIHRoZSBHVUkgaXMgY2xvc2VkLiBVc2UgYGd1aS5vcGVuKClgIG9yIGBndWkuY2xvc2UoKWAgdG8gY2hhbmdlIHRoaXMuXG5cdFx0ICogQHR5cGUge2Jvb2xlYW59XG5cdFx0ICovXG5cdFx0dGhpcy5fY2xvc2VkID0gZmFsc2U7XG5cblx0XHQvKipcblx0XHQgKiBVc2VkIHRvIGRldGVybWluZSBpZiB0aGUgR1VJIGlzIGhpZGRlbi4gVXNlIGBndWkuc2hvdygpYCBvciBgZ3VpLmhpZGUoKWAgdG8gY2hhbmdlIHRoaXMuXG5cdFx0ICogQHR5cGUge2Jvb2xlYW59XG5cdFx0ICovXG5cdFx0dGhpcy5faGlkZGVuID0gZmFsc2U7XG5cblx0XHQvKipcblx0XHQgKiBUaGUgb3V0ZXJtb3N0IGNvbnRhaW5lciBlbGVtZW50LlxuXHRcdCAqIEB0eXBlIHtIVE1MRWxlbWVudH1cblx0XHQgKi9cblx0XHR0aGlzLmRvbUVsZW1lbnQgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnZGl2JyApO1xuXHRcdHRoaXMuZG9tRWxlbWVudC5jbGFzc0xpc3QuYWRkKCAnbGlsLWd1aScgKTtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBET00gZWxlbWVudCB0aGF0IGNvbnRhaW5zIHRoZSB0aXRsZS5cblx0XHQgKiBAdHlwZSB7SFRNTEVsZW1lbnR9XG5cdFx0ICovXG5cdFx0dGhpcy4kdGl0bGUgPSBkb2N1bWVudC5jcmVhdGVFbGVtZW50KCAnZGl2JyApO1xuXHRcdHRoaXMuJHRpdGxlLmNsYXNzTGlzdC5hZGQoICd0aXRsZScgKTtcblx0XHR0aGlzLiR0aXRsZS5zZXRBdHRyaWJ1dGUoICdyb2xlJywgJ2J1dHRvbicgKTtcblx0XHR0aGlzLiR0aXRsZS5zZXRBdHRyaWJ1dGUoICdhcmlhLWV4cGFuZGVkJywgdHJ1ZSApO1xuXHRcdHRoaXMuJHRpdGxlLnNldEF0dHJpYnV0ZSggJ3RhYmluZGV4JywgMCApO1xuXG5cdFx0dGhpcy4kdGl0bGUuYWRkRXZlbnRMaXN0ZW5lciggJ2NsaWNrJywgKCkgPT4gdGhpcy5vcGVuQW5pbWF0ZWQoIHRoaXMuX2Nsb3NlZCApICk7XG5cdFx0dGhpcy4kdGl0bGUuYWRkRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCBlID0+IHtcblx0XHRcdGlmICggZS5jb2RlID09PSAnRW50ZXInIHx8IGUuY29kZSA9PT0gJ1NwYWNlJyApIHtcblx0XHRcdFx0ZS5wcmV2ZW50RGVmYXVsdCgpO1xuXHRcdFx0XHR0aGlzLiR0aXRsZS5jbGljaygpO1xuXHRcdFx0fVxuXHRcdH0gKTtcblxuXHRcdC8vIGVuYWJsZXMgOmFjdGl2ZSBwc2V1ZG8gY2xhc3Mgb24gbW9iaWxlXG5cdFx0dGhpcy4kdGl0bGUuYWRkRXZlbnRMaXN0ZW5lciggJ3RvdWNoc3RhcnQnLCAoKSA9PiB7fSwgeyBwYXNzaXZlOiB0cnVlIH0gKTtcblxuXHRcdC8qKlxuXHRcdCAqIFRoZSBET00gZWxlbWVudCB0aGF0IGNvbnRhaW5zIGNoaWxkcmVuLlxuXHRcdCAqIEB0eXBlIHtIVE1MRWxlbWVudH1cblx0XHQgKi9cblx0XHR0aGlzLiRjaGlsZHJlbiA9IGRvY3VtZW50LmNyZWF0ZUVsZW1lbnQoICdkaXYnICk7XG5cdFx0dGhpcy4kY2hpbGRyZW4uY2xhc3NMaXN0LmFkZCggJ2NoaWxkcmVuJyApO1xuXG5cdFx0dGhpcy5kb21FbGVtZW50LmFwcGVuZENoaWxkKCB0aGlzLiR0aXRsZSApO1xuXHRcdHRoaXMuZG9tRWxlbWVudC5hcHBlbmRDaGlsZCggdGhpcy4kY2hpbGRyZW4gKTtcblxuXHRcdHRoaXMudGl0bGUoIHRpdGxlICk7XG5cblx0XHRpZiAoIHRoaXMucGFyZW50ICkge1xuXG5cdFx0XHR0aGlzLnBhcmVudC5jaGlsZHJlbi5wdXNoKCB0aGlzICk7XG5cdFx0XHR0aGlzLnBhcmVudC5mb2xkZXJzLnB1c2goIHRoaXMgKTtcblxuXHRcdFx0dGhpcy5wYXJlbnQuJGNoaWxkcmVuLmFwcGVuZENoaWxkKCB0aGlzLmRvbUVsZW1lbnQgKTtcblxuXHRcdFx0Ly8gU3RvcCB0aGUgY29uc3RydWN0b3IgZWFybHksIGV2ZXJ5dGhpbmcgb253YXJkIG9ubHkgYXBwbGllcyB0byByb290IEdVSSdzXG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHR0aGlzLmRvbUVsZW1lbnQuY2xhc3NMaXN0LmFkZCggJ3Jvb3QnICk7XG5cblx0XHRpZiAoIHRvdWNoU3R5bGVzICkge1xuXHRcdFx0dGhpcy5kb21FbGVtZW50LmNsYXNzTGlzdC5hZGQoICdhbGxvdy10b3VjaC1zdHlsZXMnICk7XG5cdFx0fVxuXG5cdFx0Ly8gSW5qZWN0IHN0eWxlc2hlZXQgaWYgd2UgaGF2ZW4ndCBkb25lIHRoYXQgeWV0XG5cdFx0aWYgKCAhc3R5bGVzSW5qZWN0ZWQgJiYgaW5qZWN0U3R5bGVzICkge1xuXHRcdFx0X2luamVjdFN0eWxlcyggc3R5bGVzaGVldCApO1xuXHRcdFx0c3R5bGVzSW5qZWN0ZWQgPSB0cnVlO1xuXHRcdH1cblxuXHRcdGlmICggY29udGFpbmVyICkge1xuXG5cdFx0XHRjb250YWluZXIuYXBwZW5kQ2hpbGQoIHRoaXMuZG9tRWxlbWVudCApO1xuXG5cdFx0fSBlbHNlIGlmICggYXV0b1BsYWNlICkge1xuXG5cdFx0XHR0aGlzLmRvbUVsZW1lbnQuY2xhc3NMaXN0LmFkZCggJ2F1dG9QbGFjZScgKTtcblx0XHRcdGRvY3VtZW50LmJvZHkuYXBwZW5kQ2hpbGQoIHRoaXMuZG9tRWxlbWVudCApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB3aWR0aCApIHtcblx0XHRcdHRoaXMuZG9tRWxlbWVudC5zdHlsZS5zZXRQcm9wZXJ0eSggJy0td2lkdGgnLCB3aWR0aCArICdweCcgKTtcblx0XHR9XG5cblx0XHR0aGlzLl9jbG9zZUZvbGRlcnMgPSBjbG9zZUZvbGRlcnM7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBBZGRzIGEgY29udHJvbGxlciB0byB0aGUgR1VJLCBpbmZlcnJpbmcgY29udHJvbGxlciB0eXBlIHVzaW5nIHRoZSBgdHlwZW9mYCBvcGVyYXRvci5cblx0ICogQGV4YW1wbGVcblx0ICogZ3VpLmFkZCggb2JqZWN0LCAncHJvcGVydHknICk7XG5cdCAqIGd1aS5hZGQoIG9iamVjdCwgJ251bWJlcicsIDAsIDEwMCwgMSApO1xuXHQgKiBndWkuYWRkKCBvYmplY3QsICdvcHRpb25zJywgWyAxLCAyLCAzIF0gKTtcblx0ICpcblx0ICogQHBhcmFtIHtvYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRoZSBjb250cm9sbGVyIHdpbGwgbW9kaWZ5LlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgTmFtZSBvZiB0aGUgcHJvcGVydHkgdG8gY29udHJvbC5cblx0ICogQHBhcmFtIHtudW1iZXJ8b2JqZWN0fEFycmF5fSBbJDFdIE1pbmltdW0gdmFsdWUgZm9yIG51bWJlciBjb250cm9sbGVycywgb3IgdGhlIHNldCBvZlxuXHQgKiBzZWxlY3RhYmxlIHZhbHVlcyBmb3IgYSBkcm9wZG93bi5cblx0ICogQHBhcmFtIHtudW1iZXJ9IFttYXhdIE1heGltdW0gdmFsdWUgZm9yIG51bWJlciBjb250cm9sbGVycy5cblx0ICogQHBhcmFtIHtudW1iZXJ9IFtzdGVwXSBTdGVwIHZhbHVlIGZvciBudW1iZXIgY29udHJvbGxlcnMuXG5cdCAqIEByZXR1cm5zIHtDb250cm9sbGVyfVxuXHQgKi9cblx0YWRkKCBvYmplY3QsIHByb3BlcnR5LCAkMSwgbWF4LCBzdGVwICkge1xuXG5cdFx0aWYgKCBPYmplY3QoICQxICkgPT09ICQxICkge1xuXG5cdFx0XHRyZXR1cm4gbmV3IE9wdGlvbkNvbnRyb2xsZXIoIHRoaXMsIG9iamVjdCwgcHJvcGVydHksICQxICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBpbml0aWFsVmFsdWUgPSBvYmplY3RbIHByb3BlcnR5IF07XG5cblx0XHRzd2l0Y2ggKCB0eXBlb2YgaW5pdGlhbFZhbHVlICkge1xuXG5cdFx0XHRjYXNlICdudW1iZXInOlxuXG5cdFx0XHRcdHJldHVybiBuZXcgTnVtYmVyQ29udHJvbGxlciggdGhpcywgb2JqZWN0LCBwcm9wZXJ0eSwgJDEsIG1heCwgc3RlcCApO1xuXG5cdFx0XHRjYXNlICdib29sZWFuJzpcblxuXHRcdFx0XHRyZXR1cm4gbmV3IEJvb2xlYW5Db250cm9sbGVyKCB0aGlzLCBvYmplY3QsIHByb3BlcnR5ICk7XG5cblx0XHRcdGNhc2UgJ3N0cmluZyc6XG5cblx0XHRcdFx0cmV0dXJuIG5ldyBTdHJpbmdDb250cm9sbGVyKCB0aGlzLCBvYmplY3QsIHByb3BlcnR5ICk7XG5cblx0XHRcdGNhc2UgJ2Z1bmN0aW9uJzpcblxuXHRcdFx0XHRyZXR1cm4gbmV3IEZ1bmN0aW9uQ29udHJvbGxlciggdGhpcywgb2JqZWN0LCBwcm9wZXJ0eSApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc29sZS5lcnJvciggYGd1aS5hZGQgZmFpbGVkXG5cdHByb3BlcnR5OmAsIHByb3BlcnR5LCBgXG5cdG9iamVjdDpgLCBvYmplY3QsIGBcblx0dmFsdWU6YCwgaW5pdGlhbFZhbHVlICk7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBBZGRzIGEgY29sb3IgY29udHJvbGxlciB0byB0aGUgR1VJLlxuXHQgKiBAZXhhbXBsZVxuXHQgKiBwYXJhbXMgPSB7XG5cdCAqIFx0Y3NzQ29sb3I6ICcjZmYwMGZmJyxcblx0ICogXHRyZ2JDb2xvcjogeyByOiAwLCBnOiAwLjIsIGI6IDAuNCB9LFxuXHQgKiBcdGN1c3RvbVJhbmdlOiBbIDAsIDEyNywgMjU1IF0sXG5cdCAqIH07XG5cdCAqXG5cdCAqIGd1aS5hZGRDb2xvciggcGFyYW1zLCAnY3NzQ29sb3InICk7XG5cdCAqIGd1aS5hZGRDb2xvciggcGFyYW1zLCAncmdiQ29sb3InICk7XG5cdCAqIGd1aS5hZGRDb2xvciggcGFyYW1zLCAnY3VzdG9tUmFuZ2UnLCAyNTUgKTtcblx0ICpcblx0ICogQHBhcmFtIHtvYmplY3R9IG9iamVjdCBUaGUgb2JqZWN0IHRoZSBjb250cm9sbGVyIHdpbGwgbW9kaWZ5LlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gcHJvcGVydHkgTmFtZSBvZiB0aGUgcHJvcGVydHkgdG8gY29udHJvbC5cblx0ICogQHBhcmFtIHtudW1iZXJ9IHJnYlNjYWxlIE1heGltdW0gdmFsdWUgZm9yIGEgY29sb3IgY2hhbm5lbCB3aGVuIHVzaW5nIGFuIFJHQiBjb2xvci4gWW91IG1heVxuXHQgKiBuZWVkIHRvIHNldCB0aGlzIHRvIDI1NSBpZiB5b3VyIGNvbG9ycyBhcmUgdG9vIGJyaWdodC5cblx0ICogQHJldHVybnMge0NvbnRyb2xsZXJ9XG5cdCAqL1xuXHRhZGRDb2xvciggb2JqZWN0LCBwcm9wZXJ0eSwgcmdiU2NhbGUgPSAxICkge1xuXHRcdHJldHVybiBuZXcgQ29sb3JDb250cm9sbGVyKCB0aGlzLCBvYmplY3QsIHByb3BlcnR5LCByZ2JTY2FsZSApO1xuXHR9XG5cblx0LyoqXG5cdCAqIEFkZHMgYSBmb2xkZXIgdG8gdGhlIEdVSSwgd2hpY2ggaXMganVzdCBhbm90aGVyIEdVSS4gVGhpcyBtZXRob2QgcmV0dXJuc1xuXHQgKiB0aGUgbmVzdGVkIEdVSSBzbyB5b3UgY2FuIGFkZCBjb250cm9sbGVycyB0byBpdC5cblx0ICogQGV4YW1wbGVcblx0ICogY29uc3QgZm9sZGVyID0gZ3VpLmFkZEZvbGRlciggJ1Bvc2l0aW9uJyApO1xuXHQgKiBmb2xkZXIuYWRkKCBwb3NpdGlvbiwgJ3gnICk7XG5cdCAqIGZvbGRlci5hZGQoIHBvc2l0aW9uLCAneScgKTtcblx0ICogZm9sZGVyLmFkZCggcG9zaXRpb24sICd6JyApO1xuXHQgKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gdGl0bGUgTmFtZSB0byBkaXNwbGF5IGluIHRoZSBmb2xkZXIncyB0aXRsZSBiYXIuXG5cdCAqIEByZXR1cm5zIHtHVUl9XG5cdCAqL1xuXHRhZGRGb2xkZXIoIHRpdGxlICkge1xuXHRcdGNvbnN0IGZvbGRlciA9IG5ldyBHVUkoIHsgcGFyZW50OiB0aGlzLCB0aXRsZSB9ICk7XG5cdFx0aWYgKCB0aGlzLnJvb3QuX2Nsb3NlRm9sZGVycyApIGZvbGRlci5jbG9zZSgpO1xuXHRcdHJldHVybiBmb2xkZXI7XG5cdH1cblxuXHQvKipcblx0ICogUmVjYWxscyB2YWx1ZXMgdGhhdCB3ZXJlIHNhdmVkIHdpdGggYGd1aS5zYXZlKClgLlxuXHQgKiBAcGFyYW0ge29iamVjdH0gb2JqXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gcmVjdXJzaXZlIFBhc3MgZmFsc2UgdG8gZXhjbHVkZSBmb2xkZXJzIGRlc2NlbmRpbmcgZnJvbSB0aGlzIEdVSS5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRsb2FkKCBvYmosIHJlY3Vyc2l2ZSA9IHRydWUgKSB7XG5cblx0XHRpZiAoIG9iai5jb250cm9sbGVycyApIHtcblxuXHRcdFx0dGhpcy5jb250cm9sbGVycy5mb3JFYWNoKCBjID0+IHtcblxuXHRcdFx0XHRpZiAoIGMgaW5zdGFuY2VvZiBGdW5jdGlvbkNvbnRyb2xsZXIgKSByZXR1cm47XG5cblx0XHRcdFx0aWYgKCBjLl9uYW1lIGluIG9iai5jb250cm9sbGVycyApIHtcblx0XHRcdFx0XHRjLmxvYWQoIG9iai5jb250cm9sbGVyc1sgYy5fbmFtZSBdICk7XG5cdFx0XHRcdH1cblxuXHRcdFx0fSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCByZWN1cnNpdmUgJiYgb2JqLmZvbGRlcnMgKSB7XG5cblx0XHRcdHRoaXMuZm9sZGVycy5mb3JFYWNoKCBmID0+IHtcblxuXHRcdFx0XHRpZiAoIGYuX3RpdGxlIGluIG9iai5mb2xkZXJzICkge1xuXHRcdFx0XHRcdGYubG9hZCggb2JqLmZvbGRlcnNbIGYuX3RpdGxlIF0gKTtcblx0XHRcdFx0fVxuXG5cdFx0XHR9ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybnMgYW4gb2JqZWN0IG1hcHBpbmcgY29udHJvbGxlciBuYW1lcyB0byB2YWx1ZXMuIFRoZSBvYmplY3QgY2FuIGJlIHBhc3NlZCB0byBgZ3VpLmxvYWQoKWAgdG9cblx0ICogcmVjYWxsIHRoZXNlIHZhbHVlcy5cblx0ICogQGV4YW1wbGVcblx0ICoge1xuXHQgKiBcdGNvbnRyb2xsZXJzOiB7XG5cdCAqIFx0XHRwcm9wMTogMSxcblx0ICogXHRcdHByb3AyOiAndmFsdWUnLFxuXHQgKiBcdFx0Li4uXG5cdCAqIFx0fSxcblx0ICogXHRmb2xkZXJzOiB7XG5cdCAqIFx0XHRmb2xkZXJOYW1lMTogeyBjb250cm9sbGVycywgZm9sZGVycyB9LFxuXHQgKiBcdFx0Zm9sZGVyTmFtZTI6IHsgY29udHJvbGxlcnMsIGZvbGRlcnMgfVxuXHQgKiBcdFx0Li4uXG5cdCAqIFx0fVxuXHQgKiB9XG5cdCAqXG5cdCAqIEBwYXJhbSB7Ym9vbGVhbn0gcmVjdXJzaXZlIFBhc3MgZmFsc2UgdG8gZXhjbHVkZSBmb2xkZXJzIGRlc2NlbmRpbmcgZnJvbSB0aGlzIEdVSS5cblx0ICogQHJldHVybnMge29iamVjdH1cblx0ICovXG5cdHNhdmUoIHJlY3Vyc2l2ZSA9IHRydWUgKSB7XG5cblx0XHRjb25zdCBvYmogPSB7XG5cdFx0XHRjb250cm9sbGVyczoge30sXG5cdFx0XHRmb2xkZXJzOiB7fVxuXHRcdH07XG5cblx0XHR0aGlzLmNvbnRyb2xsZXJzLmZvckVhY2goIGMgPT4ge1xuXG5cdFx0XHRpZiAoIGMgaW5zdGFuY2VvZiBGdW5jdGlvbkNvbnRyb2xsZXIgKSByZXR1cm47XG5cblx0XHRcdGlmICggYy5fbmFtZSBpbiBvYmouY29udHJvbGxlcnMgKSB7XG5cdFx0XHRcdHRocm93IG5ldyBFcnJvciggYENhbm5vdCBzYXZlIEdVSSB3aXRoIGR1cGxpY2F0ZSBwcm9wZXJ0eSBcIiR7Yy5fbmFtZX1cImAgKTtcblx0XHRcdH1cblxuXHRcdFx0b2JqLmNvbnRyb2xsZXJzWyBjLl9uYW1lIF0gPSBjLnNhdmUoKTtcblxuXHRcdH0gKTtcblxuXHRcdGlmICggcmVjdXJzaXZlICkge1xuXG5cdFx0XHR0aGlzLmZvbGRlcnMuZm9yRWFjaCggZiA9PiB7XG5cblx0XHRcdFx0aWYgKCBmLl90aXRsZSBpbiBvYmouZm9sZGVycyApIHtcblx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoIGBDYW5ub3Qgc2F2ZSBHVUkgd2l0aCBkdXBsaWNhdGUgZm9sZGVyIFwiJHtmLl90aXRsZX1cImAgKTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdG9iai5mb2xkZXJzWyBmLl90aXRsZSBdID0gZi5zYXZlKCk7XG5cblx0XHRcdH0gKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBvYmo7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBPcGVucyBhIEdVSSBvciBmb2xkZXIuIEdVSSBhbmQgZm9sZGVycyBhcmUgb3BlbiBieSBkZWZhdWx0LlxuXHQgKiBAcGFyYW0ge2Jvb2xlYW59IG9wZW4gUGFzcyBmYWxzZSB0byBjbG9zZS5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqIEBleGFtcGxlXG5cdCAqIGd1aS5vcGVuKCk7IC8vIG9wZW5cblx0ICogZ3VpLm9wZW4oIGZhbHNlICk7IC8vIGNsb3NlXG5cdCAqIGd1aS5vcGVuKCBndWkuX2Nsb3NlZCApOyAvLyB0b2dnbGVcblx0ICovXG5cdG9wZW4oIG9wZW4gPSB0cnVlICkge1xuXG5cdFx0dGhpcy5fc2V0Q2xvc2VkKCAhb3BlbiApO1xuXG5cdFx0dGhpcy4kdGl0bGUuc2V0QXR0cmlidXRlKCAnYXJpYS1leHBhbmRlZCcsICF0aGlzLl9jbG9zZWQgKTtcblx0XHR0aGlzLmRvbUVsZW1lbnQuY2xhc3NMaXN0LnRvZ2dsZSggJ2Nsb3NlZCcsIHRoaXMuX2Nsb3NlZCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBDbG9zZXMgdGhlIEdVSS5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRjbG9zZSgpIHtcblx0XHRyZXR1cm4gdGhpcy5vcGVuKCBmYWxzZSApO1xuXHR9XG5cblx0X3NldENsb3NlZCggY2xvc2VkICkge1xuXHRcdGlmICggdGhpcy5fY2xvc2VkID09PSBjbG9zZWQgKSByZXR1cm47XG5cdFx0dGhpcy5fY2xvc2VkID0gY2xvc2VkO1xuXHRcdHRoaXMuX2NhbGxPbk9wZW5DbG9zZSggdGhpcyApO1xuXHR9XG5cblx0LyoqXG5cdCAqIFNob3dzIHRoZSBHVUkgYWZ0ZXIgaXQncyBiZWVuIGhpZGRlbi5cblx0ICogQHBhcmFtIHtib29sZWFufSBzaG93XG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKiBAZXhhbXBsZVxuXHQgKiBndWkuc2hvdygpO1xuXHQgKiBndWkuc2hvdyggZmFsc2UgKTsgLy8gaGlkZVxuXHQgKiBndWkuc2hvdyggZ3VpLl9oaWRkZW4gKTsgLy8gdG9nZ2xlXG5cdCAqL1xuXHRzaG93KCBzaG93ID0gdHJ1ZSApIHtcblxuXHRcdHRoaXMuX2hpZGRlbiA9ICFzaG93O1xuXG5cdFx0dGhpcy5kb21FbGVtZW50LnN0eWxlLmRpc3BsYXkgPSB0aGlzLl9oaWRkZW4gPyAnbm9uZScgOiAnJztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvKipcblx0ICogSGlkZXMgdGhlIEdVSS5cblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqL1xuXHRoaWRlKCkge1xuXHRcdHJldHVybiB0aGlzLnNob3coIGZhbHNlICk7XG5cdH1cblxuXHRvcGVuQW5pbWF0ZWQoIG9wZW4gPSB0cnVlICkge1xuXG5cdFx0Ly8gc2V0IHN0YXRlIGltbWVkaWF0ZWx5XG5cdFx0dGhpcy5fc2V0Q2xvc2VkKCAhb3BlbiApO1xuXG5cdFx0dGhpcy4kdGl0bGUuc2V0QXR0cmlidXRlKCAnYXJpYS1leHBhbmRlZCcsICF0aGlzLl9jbG9zZWQgKTtcblxuXHRcdC8vIHdhaXQgZm9yIG5leHQgZnJhbWUgdG8gbWVhc3VyZSAkY2hpbGRyZW5cblx0XHRyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoICgpID0+IHtcblxuXHRcdFx0Ly8gZXhwbGljaXRseSBzZXQgaW5pdGlhbCBoZWlnaHQgZm9yIHRyYW5zaXRpb25cblx0XHRcdGNvbnN0IGluaXRpYWxIZWlnaHQgPSB0aGlzLiRjaGlsZHJlbi5jbGllbnRIZWlnaHQ7XG5cdFx0XHR0aGlzLiRjaGlsZHJlbi5zdHlsZS5oZWlnaHQgPSBpbml0aWFsSGVpZ2h0ICsgJ3B4JztcblxuXHRcdFx0dGhpcy5kb21FbGVtZW50LmNsYXNzTGlzdC5hZGQoICd0cmFuc2l0aW9uJyApO1xuXG5cdFx0XHRjb25zdCBvblRyYW5zaXRpb25FbmQgPSBlID0+IHtcblx0XHRcdFx0aWYgKCBlLnRhcmdldCAhPT0gdGhpcy4kY2hpbGRyZW4gKSByZXR1cm47XG5cdFx0XHRcdHRoaXMuJGNoaWxkcmVuLnN0eWxlLmhlaWdodCA9ICcnO1xuXHRcdFx0XHR0aGlzLmRvbUVsZW1lbnQuY2xhc3NMaXN0LnJlbW92ZSggJ3RyYW5zaXRpb24nICk7XG5cdFx0XHRcdHRoaXMuJGNoaWxkcmVuLnJlbW92ZUV2ZW50TGlzdGVuZXIoICd0cmFuc2l0aW9uZW5kJywgb25UcmFuc2l0aW9uRW5kICk7XG5cdFx0XHR9O1xuXG5cdFx0XHR0aGlzLiRjaGlsZHJlbi5hZGRFdmVudExpc3RlbmVyKCAndHJhbnNpdGlvbmVuZCcsIG9uVHJhbnNpdGlvbkVuZCApO1xuXG5cdFx0XHQvLyB0b2RvOiB0aGlzIGlzIHdyb25nIGlmIGNoaWxkcmVuJ3Mgc2Nyb2xsSGVpZ2h0IG1ha2VzIGZvciBhIGd1aSB0YWxsZXIgdGhhbiBtYXhIZWlnaHRcblx0XHRcdGNvbnN0IHRhcmdldEhlaWdodCA9ICFvcGVuID8gMCA6IHRoaXMuJGNoaWxkcmVuLnNjcm9sbEhlaWdodDtcblxuXHRcdFx0dGhpcy5kb21FbGVtZW50LmNsYXNzTGlzdC50b2dnbGUoICdjbG9zZWQnLCAhb3BlbiApO1xuXG5cdFx0XHRyZXF1ZXN0QW5pbWF0aW9uRnJhbWUoICgpID0+IHtcblx0XHRcdFx0dGhpcy4kY2hpbGRyZW4uc3R5bGUuaGVpZ2h0ID0gdGFyZ2V0SGVpZ2h0ICsgJ3B4Jztcblx0XHRcdH0gKTtcblxuXHRcdH0gKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvKipcblx0ICogQ2hhbmdlIHRoZSB0aXRsZSBvZiB0aGlzIEdVSS5cblx0ICogQHBhcmFtIHtzdHJpbmd9IHRpdGxlXG5cdCAqIEByZXR1cm5zIHt0aGlzfVxuXHQgKi9cblx0dGl0bGUoIHRpdGxlICkge1xuXHRcdC8qKlxuXHRcdCAqIEN1cnJlbnQgdGl0bGUgb2YgdGhlIEdVSS4gVXNlIGBndWkudGl0bGUoICdUaXRsZScgKWAgdG8gbW9kaWZ5IHRoaXMgdmFsdWUuXG5cdFx0ICogQHR5cGUge3N0cmluZ31cblx0XHQgKi9cblx0XHR0aGlzLl90aXRsZSA9IHRpdGxlO1xuXHRcdHRoaXMuJHRpdGxlLnRleHRDb250ZW50ID0gdGl0bGU7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHQvKipcblx0ICogUmVzZXRzIGFsbCBjb250cm9sbGVycyB0byB0aGVpciBpbml0aWFsIHZhbHVlcy5cblx0ICogQHBhcmFtIHtib29sZWFufSByZWN1cnNpdmUgUGFzcyBmYWxzZSB0byBleGNsdWRlIGZvbGRlcnMgZGVzY2VuZGluZyBmcm9tIHRoaXMgR1VJLlxuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICovXG5cdHJlc2V0KCByZWN1cnNpdmUgPSB0cnVlICkge1xuXHRcdGNvbnN0IGNvbnRyb2xsZXJzID0gcmVjdXJzaXZlID8gdGhpcy5jb250cm9sbGVyc1JlY3Vyc2l2ZSgpIDogdGhpcy5jb250cm9sbGVycztcblx0XHRjb250cm9sbGVycy5mb3JFYWNoKCBjID0+IGMucmVzZXQoKSApO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0LyoqXG5cdCAqIFBhc3MgYSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgd2hlbmV2ZXIgYSBjb250cm9sbGVyIGluIHRoaXMgR1VJIGNoYW5nZXMuXG5cdCAqIEBwYXJhbSB7ZnVuY3Rpb24oe29iamVjdDpvYmplY3QsIHByb3BlcnR5OnN0cmluZywgdmFsdWU6YW55LCBjb250cm9sbGVyOkNvbnRyb2xsZXJ9KX0gY2FsbGJhY2tcblx0ICogQHJldHVybnMge3RoaXN9XG5cdCAqIEBleGFtcGxlXG5cdCAqIGd1aS5vbkNoYW5nZSggZXZlbnQgPT4ge1xuXHQgKiBcdGV2ZW50Lm9iamVjdCAgICAgLy8gb2JqZWN0IHRoYXQgd2FzIG1vZGlmaWVkXG5cdCAqIFx0ZXZlbnQucHJvcGVydHkgICAvLyBzdHJpbmcsIG5hbWUgb2YgcHJvcGVydHlcblx0ICogXHRldmVudC52YWx1ZSAgICAgIC8vIG5ldyB2YWx1ZSBvZiBjb250cm9sbGVyXG5cdCAqIFx0ZXZlbnQuY29udHJvbGxlciAvLyBjb250cm9sbGVyIHRoYXQgd2FzIG1vZGlmaWVkXG5cdCAqIH0gKTtcblx0ICovXG5cdG9uQ2hhbmdlKCBjYWxsYmFjayApIHtcblx0XHQvKipcblx0XHQgKiBVc2VkIHRvIGFjY2VzcyB0aGUgZnVuY3Rpb24gYm91bmQgdG8gYG9uQ2hhbmdlYCBldmVudHMuIERvbid0IG1vZGlmeSB0aGlzIHZhbHVlXG5cdFx0ICogZGlyZWN0bHkuIFVzZSB0aGUgYGd1aS5vbkNoYW5nZSggY2FsbGJhY2sgKWAgbWV0aG9kIGluc3RlYWQuXG5cdFx0ICogQHR5cGUge0Z1bmN0aW9ufVxuXHRcdCAqL1xuXHRcdHRoaXMuX29uQ2hhbmdlID0gY2FsbGJhY2s7XG5cdFx0cmV0dXJuIHRoaXM7XG5cdH1cblxuXHRfY2FsbE9uQ2hhbmdlKCBjb250cm9sbGVyICkge1xuXG5cdFx0aWYgKCB0aGlzLnBhcmVudCApIHtcblx0XHRcdHRoaXMucGFyZW50Ll9jYWxsT25DaGFuZ2UoIGNvbnRyb2xsZXIgKTtcblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX29uQ2hhbmdlICE9PSB1bmRlZmluZWQgKSB7XG5cdFx0XHR0aGlzLl9vbkNoYW5nZS5jYWxsKCB0aGlzLCB7XG5cdFx0XHRcdG9iamVjdDogY29udHJvbGxlci5vYmplY3QsXG5cdFx0XHRcdHByb3BlcnR5OiBjb250cm9sbGVyLnByb3BlcnR5LFxuXHRcdFx0XHR2YWx1ZTogY29udHJvbGxlci5nZXRWYWx1ZSgpLFxuXHRcdFx0XHRjb250cm9sbGVyXG5cdFx0XHR9ICk7XG5cdFx0fVxuXHR9XG5cblx0LyoqXG5cdCAqIFBhc3MgYSBmdW5jdGlvbiB0byBiZSBjYWxsZWQgd2hlbmV2ZXIgYSBjb250cm9sbGVyIGluIHRoaXMgR1VJIGhhcyBmaW5pc2hlZCBjaGFuZ2luZy5cblx0ICogQHBhcmFtIHtmdW5jdGlvbih7b2JqZWN0Om9iamVjdCwgcHJvcGVydHk6c3RyaW5nLCB2YWx1ZTphbnksIGNvbnRyb2xsZXI6Q29udHJvbGxlcn0pfSBjYWxsYmFja1xuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICogQGV4YW1wbGVcblx0ICogZ3VpLm9uRmluaXNoQ2hhbmdlKCBldmVudCA9PiB7XG5cdCAqIFx0ZXZlbnQub2JqZWN0ICAgICAvLyBvYmplY3QgdGhhdCB3YXMgbW9kaWZpZWRcblx0ICogXHRldmVudC5wcm9wZXJ0eSAgIC8vIHN0cmluZywgbmFtZSBvZiBwcm9wZXJ0eVxuXHQgKiBcdGV2ZW50LnZhbHVlICAgICAgLy8gbmV3IHZhbHVlIG9mIGNvbnRyb2xsZXJcblx0ICogXHRldmVudC5jb250cm9sbGVyIC8vIGNvbnRyb2xsZXIgdGhhdCB3YXMgbW9kaWZpZWRcblx0ICogfSApO1xuXHQgKi9cblx0b25GaW5pc2hDaGFuZ2UoIGNhbGxiYWNrICkge1xuXHRcdC8qKlxuXHRcdCAqIFVzZWQgdG8gYWNjZXNzIHRoZSBmdW5jdGlvbiBib3VuZCB0byBgb25GaW5pc2hDaGFuZ2VgIGV2ZW50cy4gRG9uJ3QgbW9kaWZ5IHRoaXMgdmFsdWVcblx0XHQgKiBkaXJlY3RseS4gVXNlIHRoZSBgZ3VpLm9uRmluaXNoQ2hhbmdlKCBjYWxsYmFjayApYCBtZXRob2QgaW5zdGVhZC5cblx0XHQgKiBAdHlwZSB7RnVuY3Rpb259XG5cdFx0ICovXG5cdFx0dGhpcy5fb25GaW5pc2hDaGFuZ2UgPSBjYWxsYmFjaztcblx0XHRyZXR1cm4gdGhpcztcblx0fVxuXG5cdF9jYWxsT25GaW5pc2hDaGFuZ2UoIGNvbnRyb2xsZXIgKSB7XG5cblx0XHRpZiAoIHRoaXMucGFyZW50ICkge1xuXHRcdFx0dGhpcy5wYXJlbnQuX2NhbGxPbkZpbmlzaENoYW5nZSggY29udHJvbGxlciApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fb25GaW5pc2hDaGFuZ2UgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuX29uRmluaXNoQ2hhbmdlLmNhbGwoIHRoaXMsIHtcblx0XHRcdFx0b2JqZWN0OiBjb250cm9sbGVyLm9iamVjdCxcblx0XHRcdFx0cHJvcGVydHk6IGNvbnRyb2xsZXIucHJvcGVydHksXG5cdFx0XHRcdHZhbHVlOiBjb250cm9sbGVyLmdldFZhbHVlKCksXG5cdFx0XHRcdGNvbnRyb2xsZXJcblx0XHRcdH0gKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogUGFzcyBhIGZ1bmN0aW9uIHRvIGJlIGNhbGxlZCB3aGVuIHRoaXMgR1VJIG9yIGl0cyBkZXNjZW5kYW50cyBhcmUgb3BlbmVkIG9yIGNsb3NlZC5cblx0ICogQHBhcmFtIHtmdW5jdGlvbihHVUkpfSBjYWxsYmFja1xuXHQgKiBAcmV0dXJucyB7dGhpc31cblx0ICogQGV4YW1wbGVcblx0ICogZ3VpLm9uT3BlbkNsb3NlKCBjaGFuZ2VkR1VJID0+IHtcblx0ICogXHRjb25zb2xlLmxvZyggY2hhbmdlZEdVSS5fY2xvc2VkICk7XG5cdCAqIH0gKTtcblx0ICovXG5cdG9uT3BlbkNsb3NlKCBjYWxsYmFjayApIHtcblx0XHR0aGlzLl9vbk9wZW5DbG9zZSA9IGNhbGxiYWNrO1xuXHRcdHJldHVybiB0aGlzO1xuXHR9XG5cblx0X2NhbGxPbk9wZW5DbG9zZSggY2hhbmdlZEdVSSApIHtcblx0XHRpZiAoIHRoaXMucGFyZW50ICkge1xuXHRcdFx0dGhpcy5wYXJlbnQuX2NhbGxPbk9wZW5DbG9zZSggY2hhbmdlZEdVSSApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fb25PcGVuQ2xvc2UgIT09IHVuZGVmaW5lZCApIHtcblx0XHRcdHRoaXMuX29uT3BlbkNsb3NlLmNhbGwoIHRoaXMsIGNoYW5nZWRHVUkgKTtcblx0XHR9XG5cdH1cblxuXHQvKipcblx0ICogRGVzdHJveXMgYWxsIERPTSBlbGVtZW50cyBhbmQgZXZlbnQgbGlzdGVuZXJzIGFzc29jaWF0ZWQgd2l0aCB0aGlzIEdVSS5cblx0ICovXG5cdGRlc3Ryb3koKSB7XG5cblx0XHRpZiAoIHRoaXMucGFyZW50ICkge1xuXHRcdFx0dGhpcy5wYXJlbnQuY2hpbGRyZW4uc3BsaWNlKCB0aGlzLnBhcmVudC5jaGlsZHJlbi5pbmRleE9mKCB0aGlzICksIDEgKTtcblx0XHRcdHRoaXMucGFyZW50LmZvbGRlcnMuc3BsaWNlKCB0aGlzLnBhcmVudC5mb2xkZXJzLmluZGV4T2YoIHRoaXMgKSwgMSApO1xuXHRcdH1cblxuXHRcdGlmICggdGhpcy5kb21FbGVtZW50LnBhcmVudEVsZW1lbnQgKSB7XG5cdFx0XHR0aGlzLmRvbUVsZW1lbnQucGFyZW50RWxlbWVudC5yZW1vdmVDaGlsZCggdGhpcy5kb21FbGVtZW50ICk7XG5cdFx0fVxuXG5cdFx0QXJyYXkuZnJvbSggdGhpcy5jaGlsZHJlbiApLmZvckVhY2goIGMgPT4gYy5kZXN0cm95KCkgKTtcblxuXHR9XG5cblx0LyoqXG5cdCAqIFJldHVybnMgYW4gYXJyYXkgb2YgY29udHJvbGxlcnMgY29udGFpbmVkIGJ5IHRoaXMgR1VJIGFuZCBpdHMgZGVzY2VuZGVudHMuXG5cdCAqIEByZXR1cm5zIHtDb250cm9sbGVyW119XG5cdCAqL1xuXHRjb250cm9sbGVyc1JlY3Vyc2l2ZSgpIHtcblx0XHRsZXQgY29udHJvbGxlcnMgPSBBcnJheS5mcm9tKCB0aGlzLmNvbnRyb2xsZXJzICk7XG5cdFx0dGhpcy5mb2xkZXJzLmZvckVhY2goIGYgPT4ge1xuXHRcdFx0Y29udHJvbGxlcnMgPSBjb250cm9sbGVycy5jb25jYXQoIGYuY29udHJvbGxlcnNSZWN1cnNpdmUoKSApO1xuXHRcdH0gKTtcblx0XHRyZXR1cm4gY29udHJvbGxlcnM7XG5cdH1cblxuXHQvKipcblx0ICogUmV0dXJucyBhbiBhcnJheSBvZiBmb2xkZXJzIGNvbnRhaW5lZCBieSB0aGlzIEdVSSBhbmQgaXRzIGRlc2NlbmRlbnRzLlxuXHQgKiBAcmV0dXJucyB7R1VJW119XG5cdCAqL1xuXHRmb2xkZXJzUmVjdXJzaXZlKCkge1xuXHRcdGxldCBmb2xkZXJzID0gQXJyYXkuZnJvbSggdGhpcy5mb2xkZXJzICk7XG5cdFx0dGhpcy5mb2xkZXJzLmZvckVhY2goIGYgPT4ge1xuXHRcdFx0Zm9sZGVycyA9IGZvbGRlcnMuY29uY2F0KCBmLmZvbGRlcnNSZWN1cnNpdmUoKSApO1xuXHRcdH0gKTtcblx0XHRyZXR1cm4gZm9sZGVycztcblx0fVxuXG59XG5cbmV4cG9ydCBkZWZhdWx0IEdVSTtcbmV4cG9ydCB7IEJvb2xlYW5Db250cm9sbGVyLCBDb2xvckNvbnRyb2xsZXIsIENvbnRyb2xsZXIsIEZ1bmN0aW9uQ29udHJvbGxlciwgR1VJLCBOdW1iZXJDb250cm9sbGVyLCBPcHRpb25Db250cm9sbGVyLCBTdHJpbmdDb250cm9sbGVyIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///638\n")},753:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ $p8: () => (/* binding */ AmbientLight),\n/* harmony export */ BKk: () => (/* binding */ ShaderMaterial),\n/* harmony export */ D$Q: () => (/* binding */ RawShaderMaterial),\n/* harmony export */ EZo: () => (/* binding */ AdditiveBlending),\n/* harmony export */ F1l: () => (/* binding */ PointLightHelper),\n/* harmony export */ FV: () => (/* binding */ ACESFilmicToneMapping),\n/* harmony export */ G_z: () => (/* binding */ MeshLambertMaterial),\n/* harmony export */ Gu$: () => (/* binding */ SphereGeometry),\n/* harmony export */ HiM: () => (/* binding */ PointLight),\n/* harmony export */ I9Y: () => (/* binding */ Vector2),\n/* harmony export */ IzY: () => (/* binding */ AxesHelper),\n/* harmony export */ JeP: () => (/* binding */ WebGLRenderer),\n/* harmony export */ KLL: () => (/* binding */ SRGBTransfer),\n/* harmony export */ LAk: () => (/* binding */ AgXToneMapping),\n/* harmony export */ LlO: () => (/* binding */ UniformsUtils),\n/* harmony export */ LoY: () => (/* binding */ BufferGeometry),\n/* harmony export */ Mjd: () => (/* binding */ ReinhardToneMapping),\n/* harmony export */ PTz: () => (/* binding */ Quaternion),\n/* harmony export */ Pq0: () => (/* binding */ Vector3),\n/* harmony export */ Q1f: () => (/* binding */ Color),\n/* harmony export */ Qev: () => (/* binding */ EventDispatcher),\n/* harmony export */ RlV: () => (/* binding */ Ray),\n/* harmony export */ Tap: () => (/* binding */ TextureLoader),\n/* harmony export */ V9B: () => (/* binding */ MeshBasicMaterial),\n/* harmony export */ XIg: () => (/* binding */ NoBlending),\n/* harmony export */ YHV: () => (/* binding */ Spherical),\n/* harmony export */ Z58: () => (/* binding */ Scene),\n/* harmony export */ Zcv: () => (/* binding */ Plane),\n/* harmony export */ aJ8: () => (/* binding */ NeutralToneMapping),\n/* harmony export */ cj9: () => (/* binding */ MathUtils),\n/* harmony export */ eaF: () => (/* binding */ Mesh),\n/* harmony export */ gPd: () => (/* binding */ Texture),\n/* harmony export */ hxR: () => (/* binding */ NearestFilter),\n/* harmony export */ ix0: () => (/* binding */ HalfFloatType),\n/* harmony export */ jUj: () => (/* binding */ Fog),\n/* harmony export */ k6q: () => (/* binding */ LinearFilter),\n/* harmony export */ kBv: () => (/* binding */ MOUSE),\n/* harmony export */ kyO: () => (/* binding */ LinearToneMapping),\n/* harmony export */ nNL: () => (/* binding */ CineonToneMapping),\n/* harmony export */ nWS: () => (/* binding */ WebGLRenderTarget),\n/* harmony export */ ppV: () => (/* binding */ ColorManagement),\n/* harmony export */ qUd: () => (/* binding */ OrthographicCamera),\n/* harmony export */ qtW: () => (/* binding */ Float32BufferAttribute),\n/* harmony export */ ubm: () => (/* binding */ PerspectiveCamera),\n/* harmony export */ wtR: () => (/* binding */ TOUCH),\n/* harmony export */ zD7: () => (/* binding */ Clock),\n/* harmony export */ zgK: () => (/* binding */ Layers)\n/* harmony export */ });\n/* unused harmony exports AddEquation, AddOperation, AdditiveAnimationBlendMode, AlphaFormat, AlwaysCompare, AlwaysDepth, AlwaysStencilFunc, AnimationAction, AnimationClip, AnimationLoader, AnimationMixer, AnimationObjectGroup, AnimationUtils, ArcCurve, ArrayCamera, ArrowHelper, AttachedBindMode, Audio, AudioAnalyser, AudioContext, AudioListener, AudioLoader, BackSide, BasicDepthPacking, BasicShadowMap, BatchedMesh, Bone, BooleanKeyframeTrack, Box2, Box3, Box3Helper, BoxGeometry, BoxHelper, BufferAttribute, BufferGeometryLoader, ByteType, Cache, Camera, CameraHelper, CanvasTexture, CapsuleGeometry, CatmullRomCurve3, CircleGeometry, ClampToEdgeWrapping, ColorKeyframeTrack, 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, ExtrudeGeometry, FileLoader, Float16BufferAttribute, FloatType, FogExp2, FramebufferTexture, FrontSide, Frustum, GLBufferAttribute, GLSL1, GLSL3, GreaterCompare, GreaterDepth, GreaterEqualCompare, GreaterEqualDepth, GreaterEqualStencilFunc, GreaterStencilFunc, GridHelper, Group, 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, LessCompare, LessDepth, LessEqualCompare, LessEqualDepth, LessEqualStencilFunc, LessStencilFunc, Light, LightProbe, Line, Line3, LineBasicMaterial, LineCurve, LineCurve3, LineDashedMaterial, LineLoop, LineSegments, LinearDisplayP3ColorSpace, LinearInterpolant, LinearMipMapLinearFilter, LinearMipMapNearestFilter, LinearMipmapLinearFilter, LinearMipmapNearestFilter, LinearSRGBColorSpace, LinearTransfer, Loader, LoaderUtils, LoadingManager, LoopOnce, LoopPingPong, LoopRepeat, LuminanceAlphaFormat, LuminanceFormat, Material, MaterialLoader, Matrix2, Matrix3, Matrix4, MaxEquation, MeshDepthMaterial, MeshDistanceMaterial, MeshMatcapMaterial, MeshNormalMaterial, MeshPhongMaterial, MeshPhysicalMaterial, MeshStandardMaterial, MeshToonMaterial, MinEquation, MirroredRepeatWrapping, MixOperation, MultiplyBlending, MultiplyOperation, NearestMipMapLinearFilter, NearestMipMapNearestFilter, NearestMipmapLinearFilter, NearestMipmapNearestFilter, NeverCompare, NeverDepth, NeverStencilFunc, NoColorSpace, NoToneMapping, NormalAnimationBlendMode, NormalBlending, NotEqualCompare, NotEqualDepth, NotEqualStencilFunc, NumberKeyframeTrack, Object3D, ObjectLoader, ObjectSpaceNormalMap, OctahedronGeometry, OneFactor, OneMinusConstantAlphaFactor, OneMinusConstantColorFactor, OneMinusDstAlphaFactor, OneMinusDstColorFactor, OneMinusSrcAlphaFactor, OneMinusSrcColorFactor, P3Primaries, PCFShadowMap, PCFSoftShadowMap, PMREMGenerator, Path, PlaneGeometry, PlaneHelper, Points, PointsMaterial, PolarGridHelper, PolyhedronGeometry, PositionalAudio, PropertyBinding, PropertyMixer, QuadraticBezierCurve, QuadraticBezierCurve3, 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, RGBDepthPacking, RGBFormat, RGBIntegerFormat, 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, RGDepthPacking, RGFormat, RGIntegerFormat, Raycaster, Rec709Primaries, RectAreaLight, RedFormat, RedIntegerFormat, RenderTarget, RepeatWrapping, ReplaceStencilOp, ReverseSubtractEquation, RingGeometry, SIGNED_RED_GREEN_RGTC2_Format, SIGNED_RED_RGTC1_Format, SRGBColorSpace, ShaderChunk, ShaderLib, ShadowMaterial, Shape, ShapeGeometry, ShapePath, ShapeUtils, ShortType, Skeleton, SkeletonHelper, SkinnedMesh, Source, Sphere, SphericalHarmonics3, SplineCurve, SpotLight, SpotLightHelper, Sprite, SpriteMaterial, SrcAlphaFactor, SrcAlphaSaturateFactor, SrcColorFactor, StaticCopyUsage, StaticDrawUsage, StaticReadUsage, StereoCamera, StreamCopyUsage, StreamDrawUsage, StreamReadUsage, StringKeyframeTrack, SubtractEquation, SubtractiveBlending, TangentSpaceNormalMap, TetrahedronGeometry, TextureUtils, TorusGeometry, TorusKnotGeometry, Triangle, TriangleFanDrawMode, TriangleStripDrawMode, TrianglesDrawMode, TubeGeometry, UVMapping, Uint16BufferAttribute, Uint32BufferAttribute, Uint8BufferAttribute, Uint8ClampedBufferAttribute, Uniform, UniformsGroup, UniformsLib, UnsignedByteType, UnsignedInt248Type, UnsignedInt5999Type, UnsignedIntType, UnsignedShort4444Type, UnsignedShort5551Type, UnsignedShortType, VSMShadowMap, Vector4, VectorKeyframeTrack, VideoTexture, WebGL3DRenderTarget, WebGLArrayRenderTarget, WebGLCoordinateSystem, WebGLCubeRenderTarget, WebGLMultipleRenderTargets, WebGLUtils, WebGPUCoordinateSystem, WireframeGeometry, WrapAroundEnding, ZeroCurvatureEnding, ZeroFactor, ZeroSlopeEnding, ZeroStencilOp, createCanvasElement */\n/**\n * @license\n * Copyright 2010-2024 Three.js Authors\n * SPDX-License-Identifier: MIT\n */\nconst REVISION = '167';\n\nconst MOUSE = { LEFT: 0, MIDDLE: 1, RIGHT: 2, ROTATE: 0, DOLLY: 1, PAN: 2 };\nconst TOUCH = { ROTATE: 0, PAN: 1, DOLLY_PAN: 2, DOLLY_ROTATE: 3 };\nconst CullFaceNone = 0;\nconst CullFaceBack = 1;\nconst CullFaceFront = 2;\nconst CullFaceFrontBack = 3;\nconst BasicShadowMap = 0;\nconst PCFShadowMap = 1;\nconst PCFSoftShadowMap = 2;\nconst VSMShadowMap = 3;\nconst FrontSide = 0;\nconst BackSide = 1;\nconst DoubleSide = 2;\nconst NoBlending = 0;\nconst NormalBlending = 1;\nconst AdditiveBlending = 2;\nconst SubtractiveBlending = 3;\nconst MultiplyBlending = 4;\nconst CustomBlending = 5;\nconst AddEquation = 100;\nconst SubtractEquation = 101;\nconst ReverseSubtractEquation = 102;\nconst MinEquation = 103;\nconst MaxEquation = 104;\nconst ZeroFactor = 200;\nconst OneFactor = 201;\nconst SrcColorFactor = 202;\nconst OneMinusSrcColorFactor = 203;\nconst SrcAlphaFactor = 204;\nconst OneMinusSrcAlphaFactor = 205;\nconst DstAlphaFactor = 206;\nconst OneMinusDstAlphaFactor = 207;\nconst DstColorFactor = 208;\nconst OneMinusDstColorFactor = 209;\nconst SrcAlphaSaturateFactor = 210;\nconst ConstantColorFactor = 211;\nconst OneMinusConstantColorFactor = 212;\nconst ConstantAlphaFactor = 213;\nconst OneMinusConstantAlphaFactor = 214;\nconst NeverDepth = 0;\nconst AlwaysDepth = 1;\nconst LessDepth = 2;\nconst LessEqualDepth = 3;\nconst EqualDepth = 4;\nconst GreaterEqualDepth = 5;\nconst GreaterDepth = 6;\nconst NotEqualDepth = 7;\nconst MultiplyOperation = 0;\nconst MixOperation = 1;\nconst AddOperation = 2;\nconst NoToneMapping = 0;\nconst LinearToneMapping = 1;\nconst ReinhardToneMapping = 2;\nconst CineonToneMapping = 3;\nconst ACESFilmicToneMapping = 4;\nconst CustomToneMapping = 5;\nconst AgXToneMapping = 6;\nconst NeutralToneMapping = 7;\nconst AttachedBindMode = 'attached';\nconst DetachedBindMode = 'detached';\n\nconst UVMapping = 300;\nconst CubeReflectionMapping = 301;\nconst CubeRefractionMapping = 302;\nconst EquirectangularReflectionMapping = 303;\nconst EquirectangularRefractionMapping = 304;\nconst CubeUVReflectionMapping = 306;\nconst RepeatWrapping = 1000;\nconst ClampToEdgeWrapping = 1001;\nconst MirroredRepeatWrapping = 1002;\nconst NearestFilter = 1003;\nconst NearestMipmapNearestFilter = 1004;\nconst NearestMipMapNearestFilter = 1004;\nconst NearestMipmapLinearFilter = 1005;\nconst NearestMipMapLinearFilter = 1005;\nconst LinearFilter = 1006;\nconst LinearMipmapNearestFilter = 1007;\nconst LinearMipMapNearestFilter = 1007;\nconst LinearMipmapLinearFilter = 1008;\nconst LinearMipMapLinearFilter = 1008;\nconst UnsignedByteType = 1009;\nconst ByteType = 1010;\nconst ShortType = 1011;\nconst UnsignedShortType = 1012;\nconst IntType = 1013;\nconst UnsignedIntType = 1014;\nconst FloatType = 1015;\nconst HalfFloatType = 1016;\nconst UnsignedShort4444Type = 1017;\nconst UnsignedShort5551Type = 1018;\nconst UnsignedInt248Type = 1020;\nconst UnsignedInt5999Type = 35902;\nconst AlphaFormat = 1021;\nconst RGBFormat = 1022;\nconst RGBAFormat = 1023;\nconst LuminanceFormat = 1024;\nconst LuminanceAlphaFormat = 1025;\nconst DepthFormat = 1026;\nconst DepthStencilFormat = 1027;\nconst RedFormat = 1028;\nconst RedIntegerFormat = 1029;\nconst RGFormat = 1030;\nconst RGIntegerFormat = 1031;\nconst RGBIntegerFormat = 1032;\nconst RGBAIntegerFormat = 1033;\n\nconst RGB_S3TC_DXT1_Format = 33776;\nconst RGBA_S3TC_DXT1_Format = 33777;\nconst RGBA_S3TC_DXT3_Format = 33778;\nconst RGBA_S3TC_DXT5_Format = 33779;\nconst RGB_PVRTC_4BPPV1_Format = 35840;\nconst RGB_PVRTC_2BPPV1_Format = 35841;\nconst RGBA_PVRTC_4BPPV1_Format = 35842;\nconst RGBA_PVRTC_2BPPV1_Format = 35843;\nconst RGB_ETC1_Format = 36196;\nconst RGB_ETC2_Format = 37492;\nconst RGBA_ETC2_EAC_Format = 37496;\nconst RGBA_ASTC_4x4_Format = 37808;\nconst RGBA_ASTC_5x4_Format = 37809;\nconst RGBA_ASTC_5x5_Format = 37810;\nconst RGBA_ASTC_6x5_Format = 37811;\nconst RGBA_ASTC_6x6_Format = 37812;\nconst RGBA_ASTC_8x5_Format = 37813;\nconst RGBA_ASTC_8x6_Format = 37814;\nconst RGBA_ASTC_8x8_Format = 37815;\nconst RGBA_ASTC_10x5_Format = 37816;\nconst RGBA_ASTC_10x6_Format = 37817;\nconst RGBA_ASTC_10x8_Format = 37818;\nconst RGBA_ASTC_10x10_Format = 37819;\nconst RGBA_ASTC_12x10_Format = 37820;\nconst RGBA_ASTC_12x12_Format = 37821;\nconst RGBA_BPTC_Format = 36492;\nconst RGB_BPTC_SIGNED_Format = 36494;\nconst RGB_BPTC_UNSIGNED_Format = 36495;\nconst RED_RGTC1_Format = 36283;\nconst SIGNED_RED_RGTC1_Format = 36284;\nconst RED_GREEN_RGTC2_Format = 36285;\nconst SIGNED_RED_GREEN_RGTC2_Format = 36286;\nconst LoopOnce = 2200;\nconst LoopRepeat = 2201;\nconst LoopPingPong = 2202;\nconst InterpolateDiscrete = 2300;\nconst InterpolateLinear = 2301;\nconst InterpolateSmooth = 2302;\nconst ZeroCurvatureEnding = 2400;\nconst ZeroSlopeEnding = 2401;\nconst WrapAroundEnding = 2402;\nconst NormalAnimationBlendMode = 2500;\nconst AdditiveAnimationBlendMode = 2501;\nconst TrianglesDrawMode = 0;\nconst TriangleStripDrawMode = 1;\nconst TriangleFanDrawMode = 2;\nconst BasicDepthPacking = 3200;\nconst RGBADepthPacking = 3201;\nconst RGBDepthPacking = 3202;\nconst RGDepthPacking = 3203;\nconst TangentSpaceNormalMap = 0;\nconst ObjectSpaceNormalMap = 1;\n\n// Color space string identifiers, matching CSS Color Module Level 4 and WebGPU names where available.\nconst NoColorSpace = '';\nconst SRGBColorSpace = 'srgb';\nconst LinearSRGBColorSpace = 'srgb-linear';\nconst DisplayP3ColorSpace = 'display-p3';\nconst LinearDisplayP3ColorSpace = 'display-p3-linear';\n\nconst LinearTransfer = 'linear';\nconst SRGBTransfer = 'srgb';\n\nconst Rec709Primaries = 'rec709';\nconst P3Primaries = 'p3';\n\nconst ZeroStencilOp = 0;\nconst KeepStencilOp = 7680;\nconst ReplaceStencilOp = 7681;\nconst IncrementStencilOp = 7682;\nconst DecrementStencilOp = 7683;\nconst IncrementWrapStencilOp = 34055;\nconst DecrementWrapStencilOp = 34056;\nconst InvertStencilOp = 5386;\n\nconst NeverStencilFunc = 512;\nconst LessStencilFunc = 513;\nconst EqualStencilFunc = 514;\nconst LessEqualStencilFunc = 515;\nconst GreaterStencilFunc = 516;\nconst NotEqualStencilFunc = 517;\nconst GreaterEqualStencilFunc = 518;\nconst AlwaysStencilFunc = 519;\n\nconst NeverCompare = 512;\nconst LessCompare = 513;\nconst EqualCompare = 514;\nconst LessEqualCompare = 515;\nconst GreaterCompare = 516;\nconst NotEqualCompare = 517;\nconst GreaterEqualCompare = 518;\nconst AlwaysCompare = 519;\n\nconst StaticDrawUsage = 35044;\nconst DynamicDrawUsage = 35048;\nconst StreamDrawUsage = 35040;\nconst StaticReadUsage = 35045;\nconst DynamicReadUsage = 35049;\nconst StreamReadUsage = 35041;\nconst StaticCopyUsage = 35046;\nconst DynamicCopyUsage = 35050;\nconst StreamCopyUsage = 35042;\n\nconst GLSL1 = '100';\nconst GLSL3 = '300 es';\n\nconst WebGLCoordinateSystem = 2000;\nconst WebGPUCoordinateSystem = 2001;\n\n/**\n * https://github.com/mrdoob/eventdispatcher.js/\n */\n\nclass EventDispatcher {\n\n\taddEventListener( type, listener ) {\n\n\t\tif ( this._listeners === undefined ) this._listeners = {};\n\n\t\tconst listeners = this._listeners;\n\n\t\tif ( listeners[ type ] === undefined ) {\n\n\t\t\tlisteners[ type ] = [];\n\n\t\t}\n\n\t\tif ( listeners[ type ].indexOf( listener ) === - 1 ) {\n\n\t\t\tlisteners[ type ].push( listener );\n\n\t\t}\n\n\t}\n\n\thasEventListener( type, listener ) {\n\n\t\tif ( this._listeners === undefined ) return false;\n\n\t\tconst listeners = this._listeners;\n\n\t\treturn listeners[ type ] !== undefined && listeners[ type ].indexOf( listener ) !== - 1;\n\n\t}\n\n\tremoveEventListener( type, listener ) {\n\n\t\tif ( this._listeners === undefined ) return;\n\n\t\tconst listeners = this._listeners;\n\t\tconst listenerArray = listeners[ type ];\n\n\t\tif ( listenerArray !== undefined ) {\n\n\t\t\tconst index = listenerArray.indexOf( listener );\n\n\t\t\tif ( index !== - 1 ) {\n\n\t\t\t\tlistenerArray.splice( index, 1 );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tdispatchEvent( event ) {\n\n\t\tif ( this._listeners === undefined ) return;\n\n\t\tconst listeners = this._listeners;\n\t\tconst listenerArray = listeners[ event.type ];\n\n\t\tif ( listenerArray !== undefined ) {\n\n\t\t\tevent.target = this;\n\n\t\t\t// Make a copy, in case listeners are removed while iterating.\n\t\t\tconst array = listenerArray.slice( 0 );\n\n\t\t\tfor ( let i = 0, l = array.length; i < l; i ++ ) {\n\n\t\t\t\tarray[ i ].call( this, event );\n\n\t\t\t}\n\n\t\t\tevent.target = null;\n\n\t\t}\n\n\t}\n\n}\n\nconst _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' ];\n\nlet _seed = 1234567;\n\n\nconst DEG2RAD = Math.PI / 180;\nconst RAD2DEG = 180 / Math.PI;\n\n// http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/21963136#21963136\nfunction generateUUID() {\n\n\tconst d0 = Math.random() * 0xffffffff | 0;\n\tconst d1 = Math.random() * 0xffffffff | 0;\n\tconst d2 = Math.random() * 0xffffffff | 0;\n\tconst d3 = Math.random() * 0xffffffff | 0;\n\tconst uuid = _lut[ d0 & 0xff ] + _lut[ d0 >> 8 & 0xff ] + _lut[ d0 >> 16 & 0xff ] + _lut[ d0 >> 24 & 0xff ] + '-' +\n\t\t\t_lut[ d1 & 0xff ] + _lut[ d1 >> 8 & 0xff ] + '-' + _lut[ d1 >> 16 & 0x0f | 0x40 ] + _lut[ d1 >> 24 & 0xff ] + '-' +\n\t\t\t_lut[ d2 & 0x3f | 0x80 ] + _lut[ d2 >> 8 & 0xff ] + '-' + _lut[ d2 >> 16 & 0xff ] + _lut[ d2 >> 24 & 0xff ] +\n\t\t\t_lut[ d3 & 0xff ] + _lut[ d3 >> 8 & 0xff ] + _lut[ d3 >> 16 & 0xff ] + _lut[ d3 >> 24 & 0xff ];\n\n\t// .toLowerCase() here flattens concatenated strings to save heap memory space.\n\treturn uuid.toLowerCase();\n\n}\n\nfunction clamp( value, min, max ) {\n\n\treturn Math.max( min, Math.min( max, value ) );\n\n}\n\n// compute euclidean modulo of m % n\n// https://en.wikipedia.org/wiki/Modulo_operation\nfunction euclideanModulo( n, m ) {\n\n\treturn ( ( n % m ) + m ) % m;\n\n}\n\n// Linear mapping from range to range \nfunction mapLinear( x, a1, a2, b1, b2 ) {\n\n\treturn b1 + ( x - a1 ) * ( b2 - b1 ) / ( a2 - a1 );\n\n}\n\n// https://www.gamedev.net/tutorials/programming/general-and-gameplay-programming/inverse-lerp-a-super-useful-yet-often-overlooked-function-r5230/\nfunction inverseLerp( x, y, value ) {\n\n\tif ( x !== y ) {\n\n\t\treturn ( value - x ) / ( y - x );\n\n\t} else {\n\n\t\treturn 0;\n\n\t}\n\n}\n\n// https://en.wikipedia.org/wiki/Linear_interpolation\nfunction lerp( x, y, t ) {\n\n\treturn ( 1 - t ) * x + t * y;\n\n}\n\n// http://www.rorydriscoll.com/2016/03/07/frame-rate-independent-damping-using-lerp/\nfunction damp( x, y, lambda, dt ) {\n\n\treturn lerp( x, y, 1 - Math.exp( - lambda * dt ) );\n\n}\n\n// https://www.desmos.com/calculator/vcsjnyz7x4\nfunction pingpong( x, length = 1 ) {\n\n\treturn length - Math.abs( euclideanModulo( x, length * 2 ) - length );\n\n}\n\n// http://en.wikipedia.org/wiki/Smoothstep\nfunction smoothstep( x, min, max ) {\n\n\tif ( x <= min ) return 0;\n\tif ( x >= max ) return 1;\n\n\tx = ( x - min ) / ( max - min );\n\n\treturn x * x * ( 3 - 2 * x );\n\n}\n\nfunction smootherstep( x, min, max ) {\n\n\tif ( x <= min ) return 0;\n\tif ( x >= max ) return 1;\n\n\tx = ( x - min ) / ( max - min );\n\n\treturn x * x * x * ( x * ( x * 6 - 15 ) + 10 );\n\n}\n\n// Random integer from interval\nfunction randInt( low, high ) {\n\n\treturn low + Math.floor( Math.random() * ( high - low + 1 ) );\n\n}\n\n// Random float from interval\nfunction randFloat( low, high ) {\n\n\treturn low + Math.random() * ( high - low );\n\n}\n\n// Random float from <-range/2, range/2> interval\nfunction randFloatSpread( range ) {\n\n\treturn range * ( 0.5 - Math.random() );\n\n}\n\n// Deterministic pseudo-random float in the interval [ 0, 1 ]\nfunction seededRandom( s ) {\n\n\tif ( s !== undefined ) _seed = s;\n\n\t// Mulberry32 generator\n\n\tlet t = _seed += 0x6D2B79F5;\n\n\tt = Math.imul( t ^ t >>> 15, t | 1 );\n\n\tt ^= t + Math.imul( t ^ t >>> 7, t | 61 );\n\n\treturn ( ( t ^ t >>> 14 ) >>> 0 ) / 4294967296;\n\n}\n\nfunction degToRad( degrees ) {\n\n\treturn degrees * DEG2RAD;\n\n}\n\nfunction radToDeg( radians ) {\n\n\treturn radians * RAD2DEG;\n\n}\n\nfunction isPowerOfTwo( value ) {\n\n\treturn ( value & ( value - 1 ) ) === 0 && value !== 0;\n\n}\n\nfunction ceilPowerOfTwo( value ) {\n\n\treturn Math.pow( 2, Math.ceil( Math.log( value ) / Math.LN2 ) );\n\n}\n\nfunction floorPowerOfTwo( value ) {\n\n\treturn Math.pow( 2, Math.floor( Math.log( value ) / Math.LN2 ) );\n\n}\n\nfunction setQuaternionFromProperEuler( q, a, b, c, order ) {\n\n\t// Intrinsic Proper Euler Angles - see https://en.wikipedia.org/wiki/Euler_angles\n\n\t// rotations are applied to the axes in the order specified by 'order'\n\t// rotation by angle 'a' is applied first, then by angle 'b', then by angle 'c'\n\t// angles are in radians\n\n\tconst cos = Math.cos;\n\tconst sin = Math.sin;\n\n\tconst c2 = cos( b / 2 );\n\tconst s2 = sin( b / 2 );\n\n\tconst c13 = cos( ( a + c ) / 2 );\n\tconst s13 = sin( ( a + c ) / 2 );\n\n\tconst c1_3 = cos( ( a - c ) / 2 );\n\tconst s1_3 = sin( ( a - c ) / 2 );\n\n\tconst c3_1 = cos( ( c - a ) / 2 );\n\tconst s3_1 = sin( ( c - a ) / 2 );\n\n\tswitch ( order ) {\n\n\t\tcase 'XYX':\n\t\t\tq.set( c2 * s13, s2 * c1_3, s2 * s1_3, c2 * c13 );\n\t\t\tbreak;\n\n\t\tcase 'YZY':\n\t\t\tq.set( s2 * s1_3, c2 * s13, s2 * c1_3, c2 * c13 );\n\t\t\tbreak;\n\n\t\tcase 'ZXZ':\n\t\t\tq.set( s2 * c1_3, s2 * s1_3, c2 * s13, c2 * c13 );\n\t\t\tbreak;\n\n\t\tcase 'XZX':\n\t\t\tq.set( c2 * s13, s2 * s3_1, s2 * c3_1, c2 * c13 );\n\t\t\tbreak;\n\n\t\tcase 'YXY':\n\t\t\tq.set( s2 * c3_1, c2 * s13, s2 * s3_1, c2 * c13 );\n\t\t\tbreak;\n\n\t\tcase 'ZYZ':\n\t\t\tq.set( s2 * s3_1, s2 * c3_1, c2 * s13, c2 * c13 );\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tconsole.warn( 'THREE.MathUtils: .setQuaternionFromProperEuler() encountered an unknown order: ' + order );\n\n\t}\n\n}\n\nfunction denormalize( value, array ) {\n\n\tswitch ( array.constructor ) {\n\n\t\tcase Float32Array:\n\n\t\t\treturn value;\n\n\t\tcase Uint32Array:\n\n\t\t\treturn value / 4294967295.0;\n\n\t\tcase Uint16Array:\n\n\t\t\treturn value / 65535.0;\n\n\t\tcase Uint8Array:\n\n\t\t\treturn value / 255.0;\n\n\t\tcase Int32Array:\n\n\t\t\treturn Math.max( value / 2147483647.0, - 1.0 );\n\n\t\tcase Int16Array:\n\n\t\t\treturn Math.max( value / 32767.0, - 1.0 );\n\n\t\tcase Int8Array:\n\n\t\t\treturn Math.max( value / 127.0, - 1.0 );\n\n\t\tdefault:\n\n\t\t\tthrow new Error( 'Invalid component type.' );\n\n\t}\n\n}\n\nfunction normalize( value, array ) {\n\n\tswitch ( array.constructor ) {\n\n\t\tcase Float32Array:\n\n\t\t\treturn value;\n\n\t\tcase Uint32Array:\n\n\t\t\treturn Math.round( value * 4294967295.0 );\n\n\t\tcase Uint16Array:\n\n\t\t\treturn Math.round( value * 65535.0 );\n\n\t\tcase Uint8Array:\n\n\t\t\treturn Math.round( value * 255.0 );\n\n\t\tcase Int32Array:\n\n\t\t\treturn Math.round( value * 2147483647.0 );\n\n\t\tcase Int16Array:\n\n\t\t\treturn Math.round( value * 32767.0 );\n\n\t\tcase Int8Array:\n\n\t\t\treturn Math.round( value * 127.0 );\n\n\t\tdefault:\n\n\t\t\tthrow new Error( 'Invalid component type.' );\n\n\t}\n\n}\n\nconst MathUtils = {\n\tDEG2RAD: DEG2RAD,\n\tRAD2DEG: RAD2DEG,\n\tgenerateUUID: generateUUID,\n\tclamp: clamp,\n\teuclideanModulo: euclideanModulo,\n\tmapLinear: mapLinear,\n\tinverseLerp: inverseLerp,\n\tlerp: lerp,\n\tdamp: damp,\n\tpingpong: pingpong,\n\tsmoothstep: smoothstep,\n\tsmootherstep: smootherstep,\n\trandInt: randInt,\n\trandFloat: randFloat,\n\trandFloatSpread: randFloatSpread,\n\tseededRandom: seededRandom,\n\tdegToRad: degToRad,\n\tradToDeg: radToDeg,\n\tisPowerOfTwo: isPowerOfTwo,\n\tceilPowerOfTwo: ceilPowerOfTwo,\n\tfloorPowerOfTwo: floorPowerOfTwo,\n\tsetQuaternionFromProperEuler: setQuaternionFromProperEuler,\n\tnormalize: normalize,\n\tdenormalize: denormalize\n};\n\nclass Vector2 {\n\n\tconstructor( x = 0, y = 0 ) {\n\n\t\tVector2.prototype.isVector2 = true;\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\n\t}\n\n\tget width() {\n\n\t\treturn this.x;\n\n\t}\n\n\tset width( value ) {\n\n\t\tthis.x = value;\n\n\t}\n\n\tget height() {\n\n\t\treturn this.y;\n\n\t}\n\n\tset height( value ) {\n\n\t\tthis.y = value;\n\n\t}\n\n\tset( x, y ) {\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetScalar( scalar ) {\n\n\t\tthis.x = scalar;\n\t\tthis.y = scalar;\n\n\t\treturn this;\n\n\t}\n\n\tsetX( x ) {\n\n\t\tthis.x = x;\n\n\t\treturn this;\n\n\t}\n\n\tsetY( y ) {\n\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetComponent( index, value ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: this.x = value; break;\n\t\t\tcase 1: this.y = value; break;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetComponent( index ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: return this.x;\n\t\t\tcase 1: return this.y;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.x, this.y );\n\n\t}\n\n\tcopy( v ) {\n\n\t\tthis.x = v.x;\n\t\tthis.y = v.y;\n\n\t\treturn this;\n\n\t}\n\n\tadd( v ) {\n\n\t\tthis.x += v.x;\n\t\tthis.y += v.y;\n\n\t\treturn this;\n\n\t}\n\n\taddScalar( s ) {\n\n\t\tthis.x += s;\n\t\tthis.y += s;\n\n\t\treturn this;\n\n\t}\n\n\taddVectors( a, b ) {\n\n\t\tthis.x = a.x + b.x;\n\t\tthis.y = a.y + b.y;\n\n\t\treturn this;\n\n\t}\n\n\taddScaledVector( v, s ) {\n\n\t\tthis.x += v.x * s;\n\t\tthis.y += v.y * s;\n\n\t\treturn this;\n\n\t}\n\n\tsub( v ) {\n\n\t\tthis.x -= v.x;\n\t\tthis.y -= v.y;\n\n\t\treturn this;\n\n\t}\n\n\tsubScalar( s ) {\n\n\t\tthis.x -= s;\n\t\tthis.y -= s;\n\n\t\treturn this;\n\n\t}\n\n\tsubVectors( a, b ) {\n\n\t\tthis.x = a.x - b.x;\n\t\tthis.y = a.y - b.y;\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( v ) {\n\n\t\tthis.x *= v.x;\n\t\tthis.y *= v.y;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( scalar ) {\n\n\t\tthis.x *= scalar;\n\t\tthis.y *= scalar;\n\n\t\treturn this;\n\n\t}\n\n\tdivide( v ) {\n\n\t\tthis.x /= v.x;\n\t\tthis.y /= v.y;\n\n\t\treturn this;\n\n\t}\n\n\tdivideScalar( scalar ) {\n\n\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t}\n\n\tapplyMatrix3( m ) {\n\n\t\tconst x = this.x, y = this.y;\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ];\n\t\tthis.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ];\n\n\t\treturn this;\n\n\t}\n\n\tmin( v ) {\n\n\t\tthis.x = Math.min( this.x, v.x );\n\t\tthis.y = Math.min( this.y, v.y );\n\n\t\treturn this;\n\n\t}\n\n\tmax( v ) {\n\n\t\tthis.x = Math.max( this.x, v.x );\n\t\tthis.y = Math.max( this.y, v.y );\n\n\t\treturn this;\n\n\t}\n\n\tclamp( min, max ) {\n\n\t\t// assumes min < max, componentwise\n\n\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampScalar( minVal, maxVal ) {\n\n\t\tthis.x = Math.max( minVal, Math.min( maxVal, this.x ) );\n\t\tthis.y = Math.max( minVal, Math.min( maxVal, this.y ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampLength( min, max ) {\n\n\t\tconst length = this.length();\n\n\t\treturn this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );\n\n\t}\n\n\tfloor() {\n\n\t\tthis.x = Math.floor( this.x );\n\t\tthis.y = Math.floor( this.y );\n\n\t\treturn this;\n\n\t}\n\n\tceil() {\n\n\t\tthis.x = Math.ceil( this.x );\n\t\tthis.y = Math.ceil( this.y );\n\n\t\treturn this;\n\n\t}\n\n\tround() {\n\n\t\tthis.x = Math.round( this.x );\n\t\tthis.y = Math.round( this.y );\n\n\t\treturn this;\n\n\t}\n\n\troundToZero() {\n\n\t\tthis.x = Math.trunc( this.x );\n\t\tthis.y = Math.trunc( this.y );\n\n\t\treturn this;\n\n\t}\n\n\tnegate() {\n\n\t\tthis.x = - this.x;\n\t\tthis.y = - this.y;\n\n\t\treturn this;\n\n\t}\n\n\tdot( v ) {\n\n\t\treturn this.x * v.x + this.y * v.y;\n\n\t}\n\n\tcross( v ) {\n\n\t\treturn this.x * v.y - this.y * v.x;\n\n\t}\n\n\tlengthSq() {\n\n\t\treturn this.x * this.x + this.y * this.y;\n\n\t}\n\n\tlength() {\n\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y );\n\n\t}\n\n\tmanhattanLength() {\n\n\t\treturn Math.abs( this.x ) + Math.abs( this.y );\n\n\t}\n\n\tnormalize() {\n\n\t\treturn this.divideScalar( this.length() || 1 );\n\n\t}\n\n\tangle() {\n\n\t\t// computes the angle in radians with respect to the positive x-axis\n\n\t\tconst angle = Math.atan2( - this.y, - this.x ) + Math.PI;\n\n\t\treturn angle;\n\n\t}\n\n\tangleTo( v ) {\n\n\t\tconst denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );\n\n\t\tif ( denominator === 0 ) return Math.PI / 2;\n\n\t\tconst theta = this.dot( v ) / denominator;\n\n\t\t// clamp, to handle numerical problems\n\n\t\treturn Math.acos( clamp( theta, - 1, 1 ) );\n\n\t}\n\n\tdistanceTo( v ) {\n\n\t\treturn Math.sqrt( this.distanceToSquared( v ) );\n\n\t}\n\n\tdistanceToSquared( v ) {\n\n\t\tconst dx = this.x - v.x, dy = this.y - v.y;\n\t\treturn dx * dx + dy * dy;\n\n\t}\n\n\tmanhattanDistanceTo( v ) {\n\n\t\treturn Math.abs( this.x - v.x ) + Math.abs( this.y - v.y );\n\n\t}\n\n\tsetLength( length ) {\n\n\t\treturn this.normalize().multiplyScalar( length );\n\n\t}\n\n\tlerp( v, alpha ) {\n\n\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\tthis.y += ( v.y - this.y ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tlerpVectors( v1, v2, alpha ) {\n\n\t\tthis.x = v1.x + ( v2.x - v1.x ) * alpha;\n\t\tthis.y = v1.y + ( v2.y - v1.y ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tequals( v ) {\n\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tthis.x = array[ offset ];\n\t\tthis.y = array[ offset + 1 ];\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this.x;\n\t\tarray[ offset + 1 ] = this.y;\n\n\t\treturn array;\n\n\t}\n\n\tfromBufferAttribute( attribute, index ) {\n\n\t\tthis.x = attribute.getX( index );\n\t\tthis.y = attribute.getY( index );\n\n\t\treturn this;\n\n\t}\n\n\trotateAround( center, angle ) {\n\n\t\tconst c = Math.cos( angle ), s = Math.sin( angle );\n\n\t\tconst x = this.x - center.x;\n\t\tconst y = this.y - center.y;\n\n\t\tthis.x = x * c - y * s + center.x;\n\t\tthis.y = x * s + y * c + center.y;\n\n\t\treturn this;\n\n\t}\n\n\trandom() {\n\n\t\tthis.x = Math.random();\n\t\tthis.y = Math.random();\n\n\t\treturn this;\n\n\t}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this.x;\n\t\tyield this.y;\n\n\t}\n\n}\n\nclass Matrix3 {\n\n\tconstructor( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {\n\n\t\tMatrix3.prototype.isMatrix3 = true;\n\n\t\tthis.elements = [\n\n\t\t\t1, 0, 0,\n\t\t\t0, 1, 0,\n\t\t\t0, 0, 1\n\n\t\t];\n\n\t\tif ( n11 !== undefined ) {\n\n\t\t\tthis.set( n11, n12, n13, n21, n22, n23, n31, n32, n33 );\n\n\t\t}\n\n\t}\n\n\tset( n11, n12, n13, n21, n22, n23, n31, n32, n33 ) {\n\n\t\tconst te = this.elements;\n\n\t\tte[ 0 ] = n11; te[ 1 ] = n21; te[ 2 ] = n31;\n\t\tte[ 3 ] = n12; te[ 4 ] = n22; te[ 5 ] = n32;\n\t\tte[ 6 ] = n13; te[ 7 ] = n23; te[ 8 ] = n33;\n\n\t\treturn this;\n\n\t}\n\n\tidentity() {\n\n\t\tthis.set(\n\n\t\t\t1, 0, 0,\n\t\t\t0, 1, 0,\n\t\t\t0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tcopy( m ) {\n\n\t\tconst te = this.elements;\n\t\tconst me = m.elements;\n\n\t\tte[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ];\n\t\tte[ 3 ] = me[ 3 ]; te[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ];\n\t\tte[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ]; te[ 8 ] = me[ 8 ];\n\n\t\treturn this;\n\n\t}\n\n\textractBasis( xAxis, yAxis, zAxis ) {\n\n\t\txAxis.setFromMatrix3Column( this, 0 );\n\t\tyAxis.setFromMatrix3Column( this, 1 );\n\t\tzAxis.setFromMatrix3Column( this, 2 );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrix4( m ) {\n\n\t\tconst me = m.elements;\n\n\t\tthis.set(\n\n\t\t\tme[ 0 ], me[ 4 ], me[ 8 ],\n\t\t\tme[ 1 ], me[ 5 ], me[ 9 ],\n\t\t\tme[ 2 ], me[ 6 ], me[ 10 ]\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( m ) {\n\n\t\treturn this.multiplyMatrices( this, m );\n\n\t}\n\n\tpremultiply( m ) {\n\n\t\treturn this.multiplyMatrices( m, this );\n\n\t}\n\n\tmultiplyMatrices( a, b ) {\n\n\t\tconst ae = a.elements;\n\t\tconst be = b.elements;\n\t\tconst te = this.elements;\n\n\t\tconst a11 = ae[ 0 ], a12 = ae[ 3 ], a13 = ae[ 6 ];\n\t\tconst a21 = ae[ 1 ], a22 = ae[ 4 ], a23 = ae[ 7 ];\n\t\tconst a31 = ae[ 2 ], a32 = ae[ 5 ], a33 = ae[ 8 ];\n\n\t\tconst b11 = be[ 0 ], b12 = be[ 3 ], b13 = be[ 6 ];\n\t\tconst b21 = be[ 1 ], b22 = be[ 4 ], b23 = be[ 7 ];\n\t\tconst b31 = be[ 2 ], b32 = be[ 5 ], b33 = be[ 8 ];\n\n\t\tte[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31;\n\t\tte[ 3 ] = a11 * b12 + a12 * b22 + a13 * b32;\n\t\tte[ 6 ] = a11 * b13 + a12 * b23 + a13 * b33;\n\n\t\tte[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31;\n\t\tte[ 4 ] = a21 * b12 + a22 * b22 + a23 * b32;\n\t\tte[ 7 ] = a21 * b13 + a22 * b23 + a23 * b33;\n\n\t\tte[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31;\n\t\tte[ 5 ] = a31 * b12 + a32 * b22 + a33 * b32;\n\t\tte[ 8 ] = a31 * b13 + a32 * b23 + a33 * b33;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( s ) {\n\n\t\tconst te = this.elements;\n\n\t\tte[ 0 ] *= s; te[ 3 ] *= s; te[ 6 ] *= s;\n\t\tte[ 1 ] *= s; te[ 4 ] *= s; te[ 7 ] *= s;\n\t\tte[ 2 ] *= s; te[ 5 ] *= s; te[ 8 ] *= s;\n\n\t\treturn this;\n\n\t}\n\n\tdeterminant() {\n\n\t\tconst te = this.elements;\n\n\t\tconst a = te[ 0 ], b = te[ 1 ], c = te[ 2 ],\n\t\t\td = te[ 3 ], e = te[ 4 ], f = te[ 5 ],\n\t\t\tg = te[ 6 ], h = te[ 7 ], i = te[ 8 ];\n\n\t\treturn a * e * i - a * f * h - b * d * i + b * f * g + c * d * h - c * e * g;\n\n\t}\n\n\tinvert() {\n\n\t\tconst te = this.elements,\n\n\t\t\tn11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ],\n\t\t\tn12 = te[ 3 ], n22 = te[ 4 ], n32 = te[ 5 ],\n\t\t\tn13 = te[ 6 ], n23 = te[ 7 ], n33 = te[ 8 ],\n\n\t\t\tt11 = n33 * n22 - n32 * n23,\n\t\t\tt12 = n32 * n13 - n33 * n12,\n\t\t\tt13 = n23 * n12 - n22 * n13,\n\n\t\t\tdet = n11 * t11 + n21 * t12 + n31 * t13;\n\n\t\tif ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0 );\n\n\t\tconst detInv = 1 / det;\n\n\t\tte[ 0 ] = t11 * detInv;\n\t\tte[ 1 ] = ( n31 * n23 - n33 * n21 ) * detInv;\n\t\tte[ 2 ] = ( n32 * n21 - n31 * n22 ) * detInv;\n\n\t\tte[ 3 ] = t12 * detInv;\n\t\tte[ 4 ] = ( n33 * n11 - n31 * n13 ) * detInv;\n\t\tte[ 5 ] = ( n31 * n12 - n32 * n11 ) * detInv;\n\n\t\tte[ 6 ] = t13 * detInv;\n\t\tte[ 7 ] = ( n21 * n13 - n23 * n11 ) * detInv;\n\t\tte[ 8 ] = ( n22 * n11 - n21 * n12 ) * detInv;\n\n\t\treturn this;\n\n\t}\n\n\ttranspose() {\n\n\t\tlet tmp;\n\t\tconst m = this.elements;\n\n\t\ttmp = m[ 1 ]; m[ 1 ] = m[ 3 ]; m[ 3 ] = tmp;\n\t\ttmp = m[ 2 ]; m[ 2 ] = m[ 6 ]; m[ 6 ] = tmp;\n\t\ttmp = m[ 5 ]; m[ 5 ] = m[ 7 ]; m[ 7 ] = tmp;\n\n\t\treturn this;\n\n\t}\n\n\tgetNormalMatrix( matrix4 ) {\n\n\t\treturn this.setFromMatrix4( matrix4 ).invert().transpose();\n\n\t}\n\n\ttransposeIntoArray( r ) {\n\n\t\tconst m = this.elements;\n\n\t\tr[ 0 ] = m[ 0 ];\n\t\tr[ 1 ] = m[ 3 ];\n\t\tr[ 2 ] = m[ 6 ];\n\t\tr[ 3 ] = m[ 1 ];\n\t\tr[ 4 ] = m[ 4 ];\n\t\tr[ 5 ] = m[ 7 ];\n\t\tr[ 6 ] = m[ 2 ];\n\t\tr[ 7 ] = m[ 5 ];\n\t\tr[ 8 ] = m[ 8 ];\n\n\t\treturn this;\n\n\t}\n\n\tsetUvTransform( tx, ty, sx, sy, rotation, cx, cy ) {\n\n\t\tconst c = Math.cos( rotation );\n\t\tconst s = Math.sin( rotation );\n\n\t\tthis.set(\n\t\t\tsx * c, sx * s, - sx * ( c * cx + s * cy ) + cx + tx,\n\t\t\t- sy * s, sy * c, - sy * ( - s * cx + c * cy ) + cy + ty,\n\t\t\t0, 0, 1\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\t//\n\n\tscale( sx, sy ) {\n\n\t\tthis.premultiply( _m3.makeScale( sx, sy ) );\n\n\t\treturn this;\n\n\t}\n\n\trotate( theta ) {\n\n\t\tthis.premultiply( _m3.makeRotation( - theta ) );\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( tx, ty ) {\n\n\t\tthis.premultiply( _m3.makeTranslation( tx, ty ) );\n\n\t\treturn this;\n\n\t}\n\n\t// for 2D Transforms\n\n\tmakeTranslation( x, y ) {\n\n\t\tif ( x.isVector2 ) {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0, x.x,\n\t\t\t\t0, 1, x.y,\n\t\t\t\t0, 0, 1\n\n\t\t\t);\n\n\t\t} else {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0, x,\n\t\t\t\t0, 1, y,\n\t\t\t\t0, 0, 1\n\n\t\t\t);\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotation( theta ) {\n\n\t\t// counterclockwise\n\n\t\tconst c = Math.cos( theta );\n\t\tconst s = Math.sin( theta );\n\n\t\tthis.set(\n\n\t\t\tc, - s, 0,\n\t\t\ts, c, 0,\n\t\t\t0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeScale( x, y ) {\n\n\t\tthis.set(\n\n\t\t\tx, 0, 0,\n\t\t\t0, y, 0,\n\t\t\t0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\t//\n\n\tequals( matrix ) {\n\n\t\tconst te = this.elements;\n\t\tconst me = matrix.elements;\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tif ( te[ i ] !== me[ i ] ) return false;\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.elements[ i ] = array[ i + offset ];\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tconst te = this.elements;\n\n\t\tarray[ offset ] = te[ 0 ];\n\t\tarray[ offset + 1 ] = te[ 1 ];\n\t\tarray[ offset + 2 ] = te[ 2 ];\n\n\t\tarray[ offset + 3 ] = te[ 3 ];\n\t\tarray[ offset + 4 ] = te[ 4 ];\n\t\tarray[ offset + 5 ] = te[ 5 ];\n\n\t\tarray[ offset + 6 ] = te[ 6 ];\n\t\tarray[ offset + 7 ] = te[ 7 ];\n\t\tarray[ offset + 8 ] = te[ 8 ];\n\n\t\treturn array;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().fromArray( this.elements );\n\n\t}\n\n}\n\nconst _m3 = /*@__PURE__*/ new Matrix3();\n\nfunction arrayNeedsUint32( array ) {\n\n\t// assumes larger values usually on last\n\n\tfor ( let i = array.length - 1; i >= 0; -- i ) {\n\n\t\tif ( array[ i ] >= 65535 ) return true; // account for PRIMITIVE_RESTART_FIXED_INDEX, #24565\n\n\t}\n\n\treturn false;\n\n}\n\nconst TYPED_ARRAYS = {\n\tInt8Array: Int8Array,\n\tUint8Array: Uint8Array,\n\tUint8ClampedArray: Uint8ClampedArray,\n\tInt16Array: Int16Array,\n\tUint16Array: Uint16Array,\n\tInt32Array: Int32Array,\n\tUint32Array: Uint32Array,\n\tFloat32Array: Float32Array,\n\tFloat64Array: Float64Array\n};\n\nfunction getTypedArray( type, buffer ) {\n\n\treturn new TYPED_ARRAYS[ type ]( buffer );\n\n}\n\nfunction createElementNS( name ) {\n\n\treturn document.createElementNS( 'http://www.w3.org/1999/xhtml', name );\n\n}\n\nfunction createCanvasElement() {\n\n\tconst canvas = createElementNS( 'canvas' );\n\tcanvas.style.display = 'block';\n\treturn canvas;\n\n}\n\nconst _cache = {};\n\nfunction warnOnce( message ) {\n\n\tif ( message in _cache ) return;\n\n\t_cache[ message ] = true;\n\n\tconsole.warn( message );\n\n}\n\nfunction probeAsync( gl, sync, interval ) {\n\n\treturn new Promise( function ( resolve, reject ) {\n\n\t\tfunction probe() {\n\n\t\t\tswitch ( gl.clientWaitSync( sync, gl.SYNC_FLUSH_COMMANDS_BIT, 0 ) ) {\n\n\t\t\t\tcase gl.WAIT_FAILED:\n\t\t\t\t\treject();\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase gl.TIMEOUT_EXPIRED:\n\t\t\t\t\tsetTimeout( probe, interval );\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\t\t\t\t\tresolve();\n\n\t\t\t}\n\n\t\t}\n\n\t\tsetTimeout( probe, interval );\n\n\t} );\n\n}\n\n/**\n * Matrices converting P3 <-> Rec. 709 primaries, without gamut mapping\n * or clipping. Based on W3C specifications for sRGB and Display P3,\n * and ICC specifications for the D50 connection space. Values in/out\n * are _linear_ sRGB and _linear_ Display P3.\n *\n * Note that both sRGB and Display P3 use the sRGB transfer functions.\n *\n * Reference:\n * - http://www.russellcottrell.com/photo/matrixCalculator.htm\n */\n\nconst LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 = /*@__PURE__*/ new Matrix3().set(\n\t0.8224621, 0.177538, 0.0,\n\t0.0331941, 0.9668058, 0.0,\n\t0.0170827, 0.0723974, 0.9105199,\n);\n\nconst LINEAR_DISPLAY_P3_TO_LINEAR_SRGB = /*@__PURE__*/ new Matrix3().set(\n\t1.2249401, - 0.2249404, 0.0,\n\t- 0.0420569, 1.0420571, 0.0,\n\t- 0.0196376, - 0.0786361, 1.0982735\n);\n\n/**\n * Defines supported color spaces by transfer function and primaries,\n * and provides conversions to/from the Linear-sRGB reference space.\n */\nconst COLOR_SPACES = {\n\t[ LinearSRGBColorSpace ]: {\n\t\ttransfer: LinearTransfer,\n\t\tprimaries: Rec709Primaries,\n\t\tluminanceCoefficients: [ 0.2126, 0.7152, 0.0722 ],\n\t\ttoReference: ( color ) => color,\n\t\tfromReference: ( color ) => color,\n\t},\n\t[ SRGBColorSpace ]: {\n\t\ttransfer: SRGBTransfer,\n\t\tprimaries: Rec709Primaries,\n\t\tluminanceCoefficients: [ 0.2126, 0.7152, 0.0722 ],\n\t\ttoReference: ( color ) => color.convertSRGBToLinear(),\n\t\tfromReference: ( color ) => color.convertLinearToSRGB(),\n\t},\n\t[ LinearDisplayP3ColorSpace ]: {\n\t\ttransfer: LinearTransfer,\n\t\tprimaries: P3Primaries,\n\t\tluminanceCoefficients: [ 0.2289, 0.6917, 0.0793 ],\n\t\ttoReference: ( color ) => color.applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ),\n\t\tfromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ),\n\t},\n\t[ DisplayP3ColorSpace ]: {\n\t\ttransfer: SRGBTransfer,\n\t\tprimaries: P3Primaries,\n\t\tluminanceCoefficients: [ 0.2289, 0.6917, 0.0793 ],\n\t\ttoReference: ( color ) => color.convertSRGBToLinear().applyMatrix3( LINEAR_DISPLAY_P3_TO_LINEAR_SRGB ),\n\t\tfromReference: ( color ) => color.applyMatrix3( LINEAR_SRGB_TO_LINEAR_DISPLAY_P3 ).convertLinearToSRGB(),\n\t},\n};\n\nconst SUPPORTED_WORKING_COLOR_SPACES = new Set( [ LinearSRGBColorSpace, LinearDisplayP3ColorSpace ] );\n\nconst ColorManagement = {\n\n\tenabled: true,\n\n\t_workingColorSpace: LinearSRGBColorSpace,\n\n\tget workingColorSpace() {\n\n\t\treturn this._workingColorSpace;\n\n\t},\n\n\tset workingColorSpace( colorSpace ) {\n\n\t\tif ( ! SUPPORTED_WORKING_COLOR_SPACES.has( colorSpace ) ) {\n\n\t\t\tthrow new Error( `Unsupported working color space, \"${ colorSpace }\".` );\n\n\t\t}\n\n\t\tthis._workingColorSpace = colorSpace;\n\n\t},\n\n\tconvert: function ( color, sourceColorSpace, targetColorSpace ) {\n\n\t\tif ( this.enabled === false || sourceColorSpace === targetColorSpace || ! sourceColorSpace || ! targetColorSpace ) {\n\n\t\t\treturn color;\n\n\t\t}\n\n\t\tconst sourceToReference = COLOR_SPACES[ sourceColorSpace ].toReference;\n\t\tconst targetFromReference = COLOR_SPACES[ targetColorSpace ].fromReference;\n\n\t\treturn targetFromReference( sourceToReference( color ) );\n\n\t},\n\n\tfromWorkingColorSpace: function ( color, targetColorSpace ) {\n\n\t\treturn this.convert( color, this._workingColorSpace, targetColorSpace );\n\n\t},\n\n\ttoWorkingColorSpace: function ( color, sourceColorSpace ) {\n\n\t\treturn this.convert( color, sourceColorSpace, this._workingColorSpace );\n\n\t},\n\n\tgetPrimaries: function ( colorSpace ) {\n\n\t\treturn COLOR_SPACES[ colorSpace ].primaries;\n\n\t},\n\n\tgetTransfer: function ( colorSpace ) {\n\n\t\tif ( colorSpace === NoColorSpace ) return LinearTransfer;\n\n\t\treturn COLOR_SPACES[ colorSpace ].transfer;\n\n\t},\n\n\tgetLuminanceCoefficients: function ( target, colorSpace = this._workingColorSpace ) {\n\n\t\treturn target.fromArray( COLOR_SPACES[ colorSpace ].luminanceCoefficients );\n\n\t},\n\n};\n\n\nfunction SRGBToLinear( c ) {\n\n\treturn ( c < 0.04045 ) ? c * 0.0773993808 : Math.pow( c * 0.9478672986 + 0.0521327014, 2.4 );\n\n}\n\nfunction LinearToSRGB( c ) {\n\n\treturn ( c < 0.0031308 ) ? c * 12.92 : 1.055 * ( Math.pow( c, 0.41666 ) ) - 0.055;\n\n}\n\nlet _canvas;\n\nclass ImageUtils {\n\n\tstatic getDataURL( image ) {\n\n\t\tif ( /^data:/i.test( image.src ) ) {\n\n\t\t\treturn image.src;\n\n\t\t}\n\n\t\tif ( typeof HTMLCanvasElement === 'undefined' ) {\n\n\t\t\treturn image.src;\n\n\t\t}\n\n\t\tlet canvas;\n\n\t\tif ( image instanceof HTMLCanvasElement ) {\n\n\t\t\tcanvas = image;\n\n\t\t} else {\n\n\t\t\tif ( _canvas === undefined ) _canvas = createElementNS( 'canvas' );\n\n\t\t\t_canvas.width = image.width;\n\t\t\t_canvas.height = image.height;\n\n\t\t\tconst context = _canvas.getContext( '2d' );\n\n\t\t\tif ( image instanceof ImageData ) {\n\n\t\t\t\tcontext.putImageData( image, 0, 0 );\n\n\t\t\t} else {\n\n\t\t\t\tcontext.drawImage( image, 0, 0, image.width, image.height );\n\n\t\t\t}\n\n\t\t\tcanvas = _canvas;\n\n\t\t}\n\n\t\tif ( canvas.width > 2048 || canvas.height > 2048 ) {\n\n\t\t\tconsole.warn( 'THREE.ImageUtils.getDataURL: Image converted to jpg for performance reasons', image );\n\n\t\t\treturn canvas.toDataURL( 'image/jpeg', 0.6 );\n\n\t\t} else {\n\n\t\t\treturn canvas.toDataURL( 'image/png' );\n\n\t\t}\n\n\t}\n\n\tstatic sRGBToLinear( image ) {\n\n\t\tif ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||\n\t\t\t( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||\n\t\t\t( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {\n\n\t\t\tconst canvas = createElementNS( 'canvas' );\n\n\t\t\tcanvas.width = image.width;\n\t\t\tcanvas.height = image.height;\n\n\t\t\tconst context = canvas.getContext( '2d' );\n\t\t\tcontext.drawImage( image, 0, 0, image.width, image.height );\n\n\t\t\tconst imageData = context.getImageData( 0, 0, image.width, image.height );\n\t\t\tconst data = imageData.data;\n\n\t\t\tfor ( let i = 0; i < data.length; i ++ ) {\n\n\t\t\t\tdata[ i ] = SRGBToLinear( data[ i ] / 255 ) * 255;\n\n\t\t\t}\n\n\t\t\tcontext.putImageData( imageData, 0, 0 );\n\n\t\t\treturn canvas;\n\n\t\t} else if ( image.data ) {\n\n\t\t\tconst data = image.data.slice( 0 );\n\n\t\t\tfor ( let i = 0; i < data.length; i ++ ) {\n\n\t\t\t\tif ( data instanceof Uint8Array || data instanceof Uint8ClampedArray ) {\n\n\t\t\t\t\tdata[ i ] = Math.floor( SRGBToLinear( data[ i ] / 255 ) * 255 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// assuming float\n\n\t\t\t\t\tdata[ i ] = SRGBToLinear( data[ i ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tdata: data,\n\t\t\t\twidth: image.width,\n\t\t\t\theight: image.height\n\t\t\t};\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.ImageUtils.sRGBToLinear(): Unsupported image type. No color space conversion applied.' );\n\t\t\treturn image;\n\n\t\t}\n\n\t}\n\n}\n\nlet _sourceId = 0;\n\nclass Source {\n\n\tconstructor( data = null ) {\n\n\t\tthis.isSource = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _sourceId ++ } );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.data = data;\n\t\tthis.dataReady = true;\n\n\t\tthis.version = 0;\n\n\t}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst isRootObject = ( meta === undefined || typeof meta === 'string' );\n\n\t\tif ( ! isRootObject && meta.images[ this.uuid ] !== undefined ) {\n\n\t\t\treturn meta.images[ this.uuid ];\n\n\t\t}\n\n\t\tconst output = {\n\t\t\tuuid: this.uuid,\n\t\t\turl: ''\n\t\t};\n\n\t\tconst data = this.data;\n\n\t\tif ( data !== null ) {\n\n\t\t\tlet url;\n\n\t\t\tif ( Array.isArray( data ) ) {\n\n\t\t\t\t// cube texture\n\n\t\t\t\turl = [];\n\n\t\t\t\tfor ( let i = 0, l = data.length; i < l; i ++ ) {\n\n\t\t\t\t\tif ( data[ i ].isDataTexture ) {\n\n\t\t\t\t\t\turl.push( serializeImage( data[ i ].image ) );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\turl.push( serializeImage( data[ i ] ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// texture\n\n\t\t\t\turl = serializeImage( data );\n\n\t\t\t}\n\n\t\t\toutput.url = url;\n\n\t\t}\n\n\t\tif ( ! isRootObject ) {\n\n\t\t\tmeta.images[ this.uuid ] = output;\n\n\t\t}\n\n\t\treturn output;\n\n\t}\n\n}\n\nfunction serializeImage( image ) {\n\n\tif ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||\n\t\t( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||\n\t\t( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ) {\n\n\t\t// default images\n\n\t\treturn ImageUtils.getDataURL( image );\n\n\t} else {\n\n\t\tif ( image.data ) {\n\n\t\t\t// images of DataTexture\n\n\t\t\treturn {\n\t\t\t\tdata: Array.from( image.data ),\n\t\t\t\twidth: image.width,\n\t\t\t\theight: image.height,\n\t\t\t\ttype: image.data.constructor.name\n\t\t\t};\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.Texture: Unable to serialize Texture.' );\n\t\t\treturn {};\n\n\t\t}\n\n\t}\n\n}\n\nlet _textureId = 0;\n\nclass Texture extends EventDispatcher {\n\n\tconstructor( 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 ) {\n\n\t\tsuper();\n\n\t\tthis.isTexture = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _textureId ++ } );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.name = '';\n\n\t\tthis.source = new Source( image );\n\t\tthis.mipmaps = [];\n\n\t\tthis.mapping = mapping;\n\t\tthis.channel = 0;\n\n\t\tthis.wrapS = wrapS;\n\t\tthis.wrapT = wrapT;\n\n\t\tthis.magFilter = magFilter;\n\t\tthis.minFilter = minFilter;\n\n\t\tthis.anisotropy = anisotropy;\n\n\t\tthis.format = format;\n\t\tthis.internalFormat = null;\n\t\tthis.type = type;\n\n\t\tthis.offset = new Vector2( 0, 0 );\n\t\tthis.repeat = new Vector2( 1, 1 );\n\t\tthis.center = new Vector2( 0, 0 );\n\t\tthis.rotation = 0;\n\n\t\tthis.matrixAutoUpdate = true;\n\t\tthis.matrix = new Matrix3();\n\n\t\tthis.generateMipmaps = true;\n\t\tthis.premultiplyAlpha = false;\n\t\tthis.flipY = true;\n\t\tthis.unpackAlignment = 4;\t// valid values: 1, 2, 4, 8 (see http://www.khronos.org/opengles/sdk/docs/man/xhtml/glPixelStorei.xml)\n\n\t\tthis.colorSpace = colorSpace;\n\n\t\tthis.userData = {};\n\n\t\tthis.version = 0;\n\t\tthis.onUpdate = null;\n\n\t\tthis.isRenderTargetTexture = false; // indicates whether a texture belongs to a render target or not\n\t\tthis.pmremVersion = 0; // indicates whether this texture should be processed by PMREMGenerator or not (only relevant for render target textures)\n\n\t}\n\n\tget image() {\n\n\t\treturn this.source.data;\n\n\t}\n\n\tset image( value = null ) {\n\n\t\tthis.source.data = value;\n\n\t}\n\n\tupdateMatrix() {\n\n\t\tthis.matrix.setUvTransform( this.offset.x, this.offset.y, this.repeat.x, this.repeat.y, this.rotation, this.center.x, this.center.y );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.name = source.name;\n\n\t\tthis.source = source.source;\n\t\tthis.mipmaps = source.mipmaps.slice( 0 );\n\n\t\tthis.mapping = source.mapping;\n\t\tthis.channel = source.channel;\n\n\t\tthis.wrapS = source.wrapS;\n\t\tthis.wrapT = source.wrapT;\n\n\t\tthis.magFilter = source.magFilter;\n\t\tthis.minFilter = source.minFilter;\n\n\t\tthis.anisotropy = source.anisotropy;\n\n\t\tthis.format = source.format;\n\t\tthis.internalFormat = source.internalFormat;\n\t\tthis.type = source.type;\n\n\t\tthis.offset.copy( source.offset );\n\t\tthis.repeat.copy( source.repeat );\n\t\tthis.center.copy( source.center );\n\t\tthis.rotation = source.rotation;\n\n\t\tthis.matrixAutoUpdate = source.matrixAutoUpdate;\n\t\tthis.matrix.copy( source.matrix );\n\n\t\tthis.generateMipmaps = source.generateMipmaps;\n\t\tthis.premultiplyAlpha = source.premultiplyAlpha;\n\t\tthis.flipY = source.flipY;\n\t\tthis.unpackAlignment = source.unpackAlignment;\n\t\tthis.colorSpace = source.colorSpace;\n\n\t\tthis.userData = JSON.parse( JSON.stringify( source.userData ) );\n\n\t\tthis.needsUpdate = true;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst isRootObject = ( meta === undefined || typeof meta === 'string' );\n\n\t\tif ( ! isRootObject && meta.textures[ this.uuid ] !== undefined ) {\n\n\t\t\treturn meta.textures[ this.uuid ];\n\n\t\t}\n\n\t\tconst output = {\n\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'Texture',\n\t\t\t\tgenerator: 'Texture.toJSON'\n\t\t\t},\n\n\t\t\tuuid: this.uuid,\n\t\t\tname: this.name,\n\n\t\t\timage: this.source.toJSON( meta ).uuid,\n\n\t\t\tmapping: this.mapping,\n\t\t\tchannel: this.channel,\n\n\t\t\trepeat: [ this.repeat.x, this.repeat.y ],\n\t\t\toffset: [ this.offset.x, this.offset.y ],\n\t\t\tcenter: [ this.center.x, this.center.y ],\n\t\t\trotation: this.rotation,\n\n\t\t\twrap: [ this.wrapS, this.wrapT ],\n\n\t\t\tformat: this.format,\n\t\t\tinternalFormat: this.internalFormat,\n\t\t\ttype: this.type,\n\t\t\tcolorSpace: this.colorSpace,\n\n\t\t\tminFilter: this.minFilter,\n\t\t\tmagFilter: this.magFilter,\n\t\t\tanisotropy: this.anisotropy,\n\n\t\t\tflipY: this.flipY,\n\n\t\t\tgenerateMipmaps: this.generateMipmaps,\n\t\t\tpremultiplyAlpha: this.premultiplyAlpha,\n\t\t\tunpackAlignment: this.unpackAlignment\n\n\t\t};\n\n\t\tif ( Object.keys( this.userData ).length > 0 ) output.userData = this.userData;\n\n\t\tif ( ! isRootObject ) {\n\n\t\t\tmeta.textures[ this.uuid ] = output;\n\n\t\t}\n\n\t\treturn output;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n\ttransformUv( uv ) {\n\n\t\tif ( this.mapping !== UVMapping ) return uv;\n\n\t\tuv.applyMatrix3( this.matrix );\n\n\t\tif ( uv.x < 0 || uv.x > 1 ) {\n\n\t\t\tswitch ( this.wrapS ) {\n\n\t\t\t\tcase RepeatWrapping:\n\n\t\t\t\t\tuv.x = uv.x - Math.floor( uv.x );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ClampToEdgeWrapping:\n\n\t\t\t\t\tuv.x = uv.x < 0 ? 0 : 1;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MirroredRepeatWrapping:\n\n\t\t\t\t\tif ( Math.abs( Math.floor( uv.x ) % 2 ) === 1 ) {\n\n\t\t\t\t\t\tuv.x = Math.ceil( uv.x ) - uv.x;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tuv.x = uv.x - Math.floor( uv.x );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( uv.y < 0 || uv.y > 1 ) {\n\n\t\t\tswitch ( this.wrapT ) {\n\n\t\t\t\tcase RepeatWrapping:\n\n\t\t\t\t\tuv.y = uv.y - Math.floor( uv.y );\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ClampToEdgeWrapping:\n\n\t\t\t\t\tuv.y = uv.y < 0 ? 0 : 1;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase MirroredRepeatWrapping:\n\n\t\t\t\t\tif ( Math.abs( Math.floor( uv.y ) % 2 ) === 1 ) {\n\n\t\t\t\t\t\tuv.y = Math.ceil( uv.y ) - uv.y;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tuv.y = uv.y - Math.floor( uv.y );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.flipY ) {\n\n\t\t\tuv.y = 1 - uv.y;\n\n\t\t}\n\n\t\treturn uv;\n\n\t}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) {\n\n\t\t\tthis.version ++;\n\t\t\tthis.source.needsUpdate = true;\n\n\t\t}\n\n\t}\n\n\tset needsPMREMUpdate( value ) {\n\n\t\tif ( value === true ) {\n\n\t\t\tthis.pmremVersion ++;\n\n\t\t}\n\n\t}\n\n}\n\nTexture.DEFAULT_IMAGE = null;\nTexture.DEFAULT_MAPPING = UVMapping;\nTexture.DEFAULT_ANISOTROPY = 1;\n\nclass Vector4 {\n\n\tconstructor( x = 0, y = 0, z = 0, w = 1 ) {\n\n\t\tVector4.prototype.isVector4 = true;\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.z = z;\n\t\tthis.w = w;\n\n\t}\n\n\tget width() {\n\n\t\treturn this.z;\n\n\t}\n\n\tset width( value ) {\n\n\t\tthis.z = value;\n\n\t}\n\n\tget height() {\n\n\t\treturn this.w;\n\n\t}\n\n\tset height( value ) {\n\n\t\tthis.w = value;\n\n\t}\n\n\tset( x, y, z, w ) {\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.z = z;\n\t\tthis.w = w;\n\n\t\treturn this;\n\n\t}\n\n\tsetScalar( scalar ) {\n\n\t\tthis.x = scalar;\n\t\tthis.y = scalar;\n\t\tthis.z = scalar;\n\t\tthis.w = scalar;\n\n\t\treturn this;\n\n\t}\n\n\tsetX( x ) {\n\n\t\tthis.x = x;\n\n\t\treturn this;\n\n\t}\n\n\tsetY( y ) {\n\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetZ( z ) {\n\n\t\tthis.z = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetW( w ) {\n\n\t\tthis.w = w;\n\n\t\treturn this;\n\n\t}\n\n\tsetComponent( index, value ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: this.x = value; break;\n\t\t\tcase 1: this.y = value; break;\n\t\t\tcase 2: this.z = value; break;\n\t\t\tcase 3: this.w = value; break;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetComponent( index ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: return this.x;\n\t\t\tcase 1: return this.y;\n\t\t\tcase 2: return this.z;\n\t\t\tcase 3: return this.w;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.x, this.y, this.z, this.w );\n\n\t}\n\n\tcopy( v ) {\n\n\t\tthis.x = v.x;\n\t\tthis.y = v.y;\n\t\tthis.z = v.z;\n\t\tthis.w = ( v.w !== undefined ) ? v.w : 1;\n\n\t\treturn this;\n\n\t}\n\n\tadd( v ) {\n\n\t\tthis.x += v.x;\n\t\tthis.y += v.y;\n\t\tthis.z += v.z;\n\t\tthis.w += v.w;\n\n\t\treturn this;\n\n\t}\n\n\taddScalar( s ) {\n\n\t\tthis.x += s;\n\t\tthis.y += s;\n\t\tthis.z += s;\n\t\tthis.w += s;\n\n\t\treturn this;\n\n\t}\n\n\taddVectors( a, b ) {\n\n\t\tthis.x = a.x + b.x;\n\t\tthis.y = a.y + b.y;\n\t\tthis.z = a.z + b.z;\n\t\tthis.w = a.w + b.w;\n\n\t\treturn this;\n\n\t}\n\n\taddScaledVector( v, s ) {\n\n\t\tthis.x += v.x * s;\n\t\tthis.y += v.y * s;\n\t\tthis.z += v.z * s;\n\t\tthis.w += v.w * s;\n\n\t\treturn this;\n\n\t}\n\n\tsub( v ) {\n\n\t\tthis.x -= v.x;\n\t\tthis.y -= v.y;\n\t\tthis.z -= v.z;\n\t\tthis.w -= v.w;\n\n\t\treturn this;\n\n\t}\n\n\tsubScalar( s ) {\n\n\t\tthis.x -= s;\n\t\tthis.y -= s;\n\t\tthis.z -= s;\n\t\tthis.w -= s;\n\n\t\treturn this;\n\n\t}\n\n\tsubVectors( a, b ) {\n\n\t\tthis.x = a.x - b.x;\n\t\tthis.y = a.y - b.y;\n\t\tthis.z = a.z - b.z;\n\t\tthis.w = a.w - b.w;\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( v ) {\n\n\t\tthis.x *= v.x;\n\t\tthis.y *= v.y;\n\t\tthis.z *= v.z;\n\t\tthis.w *= v.w;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( scalar ) {\n\n\t\tthis.x *= scalar;\n\t\tthis.y *= scalar;\n\t\tthis.z *= scalar;\n\t\tthis.w *= scalar;\n\n\t\treturn this;\n\n\t}\n\n\tapplyMatrix4( m ) {\n\n\t\tconst x = this.x, y = this.y, z = this.z, w = this.w;\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] * w;\n\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] * w;\n\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] * w;\n\t\tthis.w = e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] * w;\n\n\t\treturn this;\n\n\t}\n\n\tdivideScalar( scalar ) {\n\n\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t}\n\n\tsetAxisAngleFromQuaternion( q ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/quaternionToAngle/index.htm\n\n\t\t// q is assumed to be normalized\n\n\t\tthis.w = 2 * Math.acos( q.w );\n\n\t\tconst s = Math.sqrt( 1 - q.w * q.w );\n\n\t\tif ( s < 0.0001 ) {\n\n\t\t\tthis.x = 1;\n\t\t\tthis.y = 0;\n\t\t\tthis.z = 0;\n\n\t\t} else {\n\n\t\t\tthis.x = q.x / s;\n\t\t\tthis.y = q.y / s;\n\t\t\tthis.z = q.z / s;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetAxisAngleFromRotationMatrix( m ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToAngle/index.htm\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tlet angle, x, y, z; // variables for result\n\t\tconst epsilon = 0.01,\t\t// margin to allow for rounding errors\n\t\t\tepsilon2 = 0.1,\t\t// margin to distinguish between 0 and 180 degrees\n\n\t\t\tte = m.elements,\n\n\t\t\tm11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],\n\t\t\tm21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],\n\t\t\tm31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];\n\n\t\tif ( ( Math.abs( m12 - m21 ) < epsilon ) &&\n\t\t ( Math.abs( m13 - m31 ) < epsilon ) &&\n\t\t ( Math.abs( m23 - m32 ) < epsilon ) ) {\n\n\t\t\t// singularity found\n\t\t\t// first check for identity matrix which must have +1 for all terms\n\t\t\t// in leading diagonal and zero in other terms\n\n\t\t\tif ( ( Math.abs( m12 + m21 ) < epsilon2 ) &&\n\t\t\t ( Math.abs( m13 + m31 ) < epsilon2 ) &&\n\t\t\t ( Math.abs( m23 + m32 ) < epsilon2 ) &&\n\t\t\t ( Math.abs( m11 + m22 + m33 - 3 ) < epsilon2 ) ) {\n\n\t\t\t\t// this singularity is identity matrix so angle = 0\n\n\t\t\t\tthis.set( 1, 0, 0, 0 );\n\n\t\t\t\treturn this; // zero angle, arbitrary axis\n\n\t\t\t}\n\n\t\t\t// otherwise this singularity is angle = 180\n\n\t\t\tangle = Math.PI;\n\n\t\t\tconst xx = ( m11 + 1 ) / 2;\n\t\t\tconst yy = ( m22 + 1 ) / 2;\n\t\t\tconst zz = ( m33 + 1 ) / 2;\n\t\t\tconst xy = ( m12 + m21 ) / 4;\n\t\t\tconst xz = ( m13 + m31 ) / 4;\n\t\t\tconst yz = ( m23 + m32 ) / 4;\n\n\t\t\tif ( ( xx > yy ) && ( xx > zz ) ) {\n\n\t\t\t\t// m11 is the largest diagonal term\n\n\t\t\t\tif ( xx < epsilon ) {\n\n\t\t\t\t\tx = 0;\n\t\t\t\t\ty = 0.707106781;\n\t\t\t\t\tz = 0.707106781;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tx = Math.sqrt( xx );\n\t\t\t\t\ty = xy / x;\n\t\t\t\t\tz = xz / x;\n\n\t\t\t\t}\n\n\t\t\t} else if ( yy > zz ) {\n\n\t\t\t\t// m22 is the largest diagonal term\n\n\t\t\t\tif ( yy < epsilon ) {\n\n\t\t\t\t\tx = 0.707106781;\n\t\t\t\t\ty = 0;\n\t\t\t\t\tz = 0.707106781;\n\n\t\t\t\t} else {\n\n\t\t\t\t\ty = Math.sqrt( yy );\n\t\t\t\t\tx = xy / y;\n\t\t\t\t\tz = yz / y;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// m33 is the largest diagonal term so base result on this\n\n\t\t\t\tif ( zz < epsilon ) {\n\n\t\t\t\t\tx = 0.707106781;\n\t\t\t\t\ty = 0.707106781;\n\t\t\t\t\tz = 0;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tz = Math.sqrt( zz );\n\t\t\t\t\tx = xz / z;\n\t\t\t\t\ty = yz / z;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.set( x, y, z, angle );\n\n\t\t\treturn this; // return 180 deg rotation\n\n\t\t}\n\n\t\t// as we have reached here there are no singularities so we can handle normally\n\n\t\tlet s = Math.sqrt( ( m32 - m23 ) * ( m32 - m23 ) +\n\t\t\t( m13 - m31 ) * ( m13 - m31 ) +\n\t\t\t( m21 - m12 ) * ( m21 - m12 ) ); // used to normalize\n\n\t\tif ( Math.abs( s ) < 0.001 ) s = 1;\n\n\t\t// prevent divide by zero, should not happen if matrix is orthogonal and should be\n\t\t// caught by singularity test above, but I've left it in just in case\n\n\t\tthis.x = ( m32 - m23 ) / s;\n\t\tthis.y = ( m13 - m31 ) / s;\n\t\tthis.z = ( m21 - m12 ) / s;\n\t\tthis.w = Math.acos( ( m11 + m22 + m33 - 1 ) / 2 );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrixPosition( m ) {\n\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 12 ];\n\t\tthis.y = e[ 13 ];\n\t\tthis.z = e[ 14 ];\n\t\tthis.w = e[ 15 ];\n\n\t\treturn this;\n\n\t}\n\n\tmin( v ) {\n\n\t\tthis.x = Math.min( this.x, v.x );\n\t\tthis.y = Math.min( this.y, v.y );\n\t\tthis.z = Math.min( this.z, v.z );\n\t\tthis.w = Math.min( this.w, v.w );\n\n\t\treturn this;\n\n\t}\n\n\tmax( v ) {\n\n\t\tthis.x = Math.max( this.x, v.x );\n\t\tthis.y = Math.max( this.y, v.y );\n\t\tthis.z = Math.max( this.z, v.z );\n\t\tthis.w = Math.max( this.w, v.w );\n\n\t\treturn this;\n\n\t}\n\n\tclamp( min, max ) {\n\n\t\t// assumes min < max, componentwise\n\n\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\t\tthis.z = Math.max( min.z, Math.min( max.z, this.z ) );\n\t\tthis.w = Math.max( min.w, Math.min( max.w, this.w ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampScalar( minVal, maxVal ) {\n\n\t\tthis.x = Math.max( minVal, Math.min( maxVal, this.x ) );\n\t\tthis.y = Math.max( minVal, Math.min( maxVal, this.y ) );\n\t\tthis.z = Math.max( minVal, Math.min( maxVal, this.z ) );\n\t\tthis.w = Math.max( minVal, Math.min( maxVal, this.w ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampLength( min, max ) {\n\n\t\tconst length = this.length();\n\n\t\treturn this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );\n\n\t}\n\n\tfloor() {\n\n\t\tthis.x = Math.floor( this.x );\n\t\tthis.y = Math.floor( this.y );\n\t\tthis.z = Math.floor( this.z );\n\t\tthis.w = Math.floor( this.w );\n\n\t\treturn this;\n\n\t}\n\n\tceil() {\n\n\t\tthis.x = Math.ceil( this.x );\n\t\tthis.y = Math.ceil( this.y );\n\t\tthis.z = Math.ceil( this.z );\n\t\tthis.w = Math.ceil( this.w );\n\n\t\treturn this;\n\n\t}\n\n\tround() {\n\n\t\tthis.x = Math.round( this.x );\n\t\tthis.y = Math.round( this.y );\n\t\tthis.z = Math.round( this.z );\n\t\tthis.w = Math.round( this.w );\n\n\t\treturn this;\n\n\t}\n\n\troundToZero() {\n\n\t\tthis.x = Math.trunc( this.x );\n\t\tthis.y = Math.trunc( this.y );\n\t\tthis.z = Math.trunc( this.z );\n\t\tthis.w = Math.trunc( this.w );\n\n\t\treturn this;\n\n\t}\n\n\tnegate() {\n\n\t\tthis.x = - this.x;\n\t\tthis.y = - this.y;\n\t\tthis.z = - this.z;\n\t\tthis.w = - this.w;\n\n\t\treturn this;\n\n\t}\n\n\tdot( v ) {\n\n\t\treturn this.x * v.x + this.y * v.y + this.z * v.z + this.w * v.w;\n\n\t}\n\n\tlengthSq() {\n\n\t\treturn this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w;\n\n\t}\n\n\tlength() {\n\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z + this.w * this.w );\n\n\t}\n\n\tmanhattanLength() {\n\n\t\treturn Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z ) + Math.abs( this.w );\n\n\t}\n\n\tnormalize() {\n\n\t\treturn this.divideScalar( this.length() || 1 );\n\n\t}\n\n\tsetLength( length ) {\n\n\t\treturn this.normalize().multiplyScalar( length );\n\n\t}\n\n\tlerp( v, alpha ) {\n\n\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\tthis.y += ( v.y - this.y ) * alpha;\n\t\tthis.z += ( v.z - this.z ) * alpha;\n\t\tthis.w += ( v.w - this.w ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tlerpVectors( v1, v2, alpha ) {\n\n\t\tthis.x = v1.x + ( v2.x - v1.x ) * alpha;\n\t\tthis.y = v1.y + ( v2.y - v1.y ) * alpha;\n\t\tthis.z = v1.z + ( v2.z - v1.z ) * alpha;\n\t\tthis.w = v1.w + ( v2.w - v1.w ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tequals( v ) {\n\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) && ( v.w === this.w ) );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tthis.x = array[ offset ];\n\t\tthis.y = array[ offset + 1 ];\n\t\tthis.z = array[ offset + 2 ];\n\t\tthis.w = array[ offset + 3 ];\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this.x;\n\t\tarray[ offset + 1 ] = this.y;\n\t\tarray[ offset + 2 ] = this.z;\n\t\tarray[ offset + 3 ] = this.w;\n\n\t\treturn array;\n\n\t}\n\n\tfromBufferAttribute( attribute, index ) {\n\n\t\tthis.x = attribute.getX( index );\n\t\tthis.y = attribute.getY( index );\n\t\tthis.z = attribute.getZ( index );\n\t\tthis.w = attribute.getW( index );\n\n\t\treturn this;\n\n\t}\n\n\trandom() {\n\n\t\tthis.x = Math.random();\n\t\tthis.y = Math.random();\n\t\tthis.z = Math.random();\n\t\tthis.w = Math.random();\n\n\t\treturn this;\n\n\t}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this.x;\n\t\tyield this.y;\n\t\tyield this.z;\n\t\tyield this.w;\n\n\t}\n\n}\n\n/*\n In options, we can specify:\n * Texture parameters for an auto-generated target texture\n * depthBuffer/stencilBuffer: Booleans to indicate if we should generate these buffers\n*/\nclass RenderTarget extends EventDispatcher {\n\n\tconstructor( width = 1, height = 1, options = {} ) {\n\n\t\tsuper();\n\n\t\tthis.isRenderTarget = true;\n\n\t\tthis.width = width;\n\t\tthis.height = height;\n\t\tthis.depth = 1;\n\n\t\tthis.scissor = new Vector4( 0, 0, width, height );\n\t\tthis.scissorTest = false;\n\n\t\tthis.viewport = new Vector4( 0, 0, width, height );\n\n\t\tconst image = { width: width, height: height, depth: 1 };\n\n\t\toptions = Object.assign( {\n\t\t\tgenerateMipmaps: false,\n\t\t\tinternalFormat: null,\n\t\t\tminFilter: LinearFilter,\n\t\t\tdepthBuffer: true,\n\t\t\tstencilBuffer: false,\n\t\t\tresolveDepthBuffer: true,\n\t\t\tresolveStencilBuffer: true,\n\t\t\tdepthTexture: null,\n\t\t\tsamples: 0,\n\t\t\tcount: 1\n\t\t}, options );\n\n\t\tconst texture = new Texture( image, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace );\n\n\t\ttexture.flipY = false;\n\t\ttexture.generateMipmaps = options.generateMipmaps;\n\t\ttexture.internalFormat = options.internalFormat;\n\n\t\tthis.textures = [];\n\n\t\tconst count = options.count;\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tthis.textures[ i ] = texture.clone();\n\t\t\tthis.textures[ i ].isRenderTargetTexture = true;\n\n\t\t}\n\n\t\tthis.depthBuffer = options.depthBuffer;\n\t\tthis.stencilBuffer = options.stencilBuffer;\n\n\t\tthis.resolveDepthBuffer = options.resolveDepthBuffer;\n\t\tthis.resolveStencilBuffer = options.resolveStencilBuffer;\n\n\t\tthis.depthTexture = options.depthTexture;\n\n\t\tthis.samples = options.samples;\n\n\t}\n\n\tget texture() {\n\n\t\treturn this.textures[ 0 ];\n\n\t}\n\n\tset texture( value ) {\n\n\t\tthis.textures[ 0 ] = value;\n\n\t}\n\n\tsetSize( width, height, depth = 1 ) {\n\n\t\tif ( this.width !== width || this.height !== height || this.depth !== depth ) {\n\n\t\t\tthis.width = width;\n\t\t\tthis.height = height;\n\t\t\tthis.depth = depth;\n\n\t\t\tfor ( let i = 0, il = this.textures.length; i < il; i ++ ) {\n\n\t\t\t\tthis.textures[ i ].image.width = width;\n\t\t\t\tthis.textures[ i ].image.height = height;\n\t\t\t\tthis.textures[ i ].image.depth = depth;\n\n\t\t\t}\n\n\t\t\tthis.dispose();\n\n\t\t}\n\n\t\tthis.viewport.set( 0, 0, width, height );\n\t\tthis.scissor.set( 0, 0, width, height );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.width = source.width;\n\t\tthis.height = source.height;\n\t\tthis.depth = source.depth;\n\n\t\tthis.scissor.copy( source.scissor );\n\t\tthis.scissorTest = source.scissorTest;\n\n\t\tthis.viewport.copy( source.viewport );\n\n\t\tthis.textures.length = 0;\n\n\t\tfor ( let i = 0, il = source.textures.length; i < il; i ++ ) {\n\n\t\t\tthis.textures[ i ] = source.textures[ i ].clone();\n\t\t\tthis.textures[ i ].isRenderTargetTexture = true;\n\n\t\t}\n\n\t\t// ensure image object is not shared, see #20328\n\n\t\tconst image = Object.assign( {}, source.texture.image );\n\t\tthis.texture.source = new Source( image );\n\n\t\tthis.depthBuffer = source.depthBuffer;\n\t\tthis.stencilBuffer = source.stencilBuffer;\n\n\t\tthis.resolveDepthBuffer = source.resolveDepthBuffer;\n\t\tthis.resolveStencilBuffer = source.resolveStencilBuffer;\n\n\t\tif ( source.depthTexture !== null ) this.depthTexture = source.depthTexture.clone();\n\n\t\tthis.samples = source.samples;\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n}\n\nclass WebGLRenderTarget extends RenderTarget {\n\n\tconstructor( width = 1, height = 1, options = {} ) {\n\n\t\tsuper( width, height, options );\n\n\t\tthis.isWebGLRenderTarget = true;\n\n\t}\n\n}\n\nclass DataArrayTexture extends Texture {\n\n\tconstructor( data = null, width = 1, height = 1, depth = 1 ) {\n\n\t\tsuper( null );\n\n\t\tthis.isDataArrayTexture = true;\n\n\t\tthis.image = { data, width, height, depth };\n\n\t\tthis.magFilter = NearestFilter;\n\t\tthis.minFilter = NearestFilter;\n\n\t\tthis.wrapR = ClampToEdgeWrapping;\n\n\t\tthis.generateMipmaps = false;\n\t\tthis.flipY = false;\n\t\tthis.unpackAlignment = 1;\n\n\t\tthis.layerUpdates = new Set();\n\n\t}\n\n\taddLayerUpdate( layerIndex ) {\n\n\t\tthis.layerUpdates.add( layerIndex );\n\n\t}\n\n\tclearLayerUpdates() {\n\n\t\tthis.layerUpdates.clear();\n\n\t}\n\n}\n\nclass WebGLArrayRenderTarget extends WebGLRenderTarget {\n\n\tconstructor( width = 1, height = 1, depth = 1, options = {} ) {\n\n\t\tsuper( width, height, options );\n\n\t\tthis.isWebGLArrayRenderTarget = true;\n\n\t\tthis.depth = depth;\n\n\t\tthis.texture = new DataArrayTexture( null, width, height, depth );\n\n\t\tthis.texture.isRenderTargetTexture = true;\n\n\t}\n\n}\n\nclass Data3DTexture extends Texture {\n\n\tconstructor( data = null, width = 1, height = 1, depth = 1 ) {\n\n\t\t// We're going to add .setXXX() methods for setting properties later.\n\t\t// Users can still set in DataTexture3D directly.\n\t\t//\n\t\t//\tconst texture = new THREE.DataTexture3D( data, width, height, depth );\n\t\t// \ttexture.anisotropy = 16;\n\t\t//\n\t\t// See #14839\n\n\t\tsuper( null );\n\n\t\tthis.isData3DTexture = true;\n\n\t\tthis.image = { data, width, height, depth };\n\n\t\tthis.magFilter = NearestFilter;\n\t\tthis.minFilter = NearestFilter;\n\n\t\tthis.wrapR = ClampToEdgeWrapping;\n\n\t\tthis.generateMipmaps = false;\n\t\tthis.flipY = false;\n\t\tthis.unpackAlignment = 1;\n\n\t}\n\n}\n\nclass WebGL3DRenderTarget extends WebGLRenderTarget {\n\n\tconstructor( width = 1, height = 1, depth = 1, options = {} ) {\n\n\t\tsuper( width, height, options );\n\n\t\tthis.isWebGL3DRenderTarget = true;\n\n\t\tthis.depth = depth;\n\n\t\tthis.texture = new Data3DTexture( null, width, height, depth );\n\n\t\tthis.texture.isRenderTargetTexture = true;\n\n\t}\n\n}\n\nclass Quaternion {\n\n\tconstructor( x = 0, y = 0, z = 0, w = 1 ) {\n\n\t\tthis.isQuaternion = true;\n\n\t\tthis._x = x;\n\t\tthis._y = y;\n\t\tthis._z = z;\n\t\tthis._w = w;\n\n\t}\n\n\tstatic slerpFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1, t ) {\n\n\t\t// fuzz-free, array-based Quaternion SLERP operation\n\n\t\tlet x0 = src0[ srcOffset0 + 0 ],\n\t\t\ty0 = src0[ srcOffset0 + 1 ],\n\t\t\tz0 = src0[ srcOffset0 + 2 ],\n\t\t\tw0 = src0[ srcOffset0 + 3 ];\n\n\t\tconst x1 = src1[ srcOffset1 + 0 ],\n\t\t\ty1 = src1[ srcOffset1 + 1 ],\n\t\t\tz1 = src1[ srcOffset1 + 2 ],\n\t\t\tw1 = src1[ srcOffset1 + 3 ];\n\n\t\tif ( t === 0 ) {\n\n\t\t\tdst[ dstOffset + 0 ] = x0;\n\t\t\tdst[ dstOffset + 1 ] = y0;\n\t\t\tdst[ dstOffset + 2 ] = z0;\n\t\t\tdst[ dstOffset + 3 ] = w0;\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( t === 1 ) {\n\n\t\t\tdst[ dstOffset + 0 ] = x1;\n\t\t\tdst[ dstOffset + 1 ] = y1;\n\t\t\tdst[ dstOffset + 2 ] = z1;\n\t\t\tdst[ dstOffset + 3 ] = w1;\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( w0 !== w1 || x0 !== x1 || y0 !== y1 || z0 !== z1 ) {\n\n\t\t\tlet s = 1 - t;\n\t\t\tconst cos = x0 * x1 + y0 * y1 + z0 * z1 + w0 * w1,\n\t\t\t\tdir = ( cos >= 0 ? 1 : - 1 ),\n\t\t\t\tsqrSin = 1 - cos * cos;\n\n\t\t\t// Skip the Slerp for tiny steps to avoid numeric problems:\n\t\t\tif ( sqrSin > Number.EPSILON ) {\n\n\t\t\t\tconst sin = Math.sqrt( sqrSin ),\n\t\t\t\t\tlen = Math.atan2( sin, cos * dir );\n\n\t\t\t\ts = Math.sin( s * len ) / sin;\n\t\t\t\tt = Math.sin( t * len ) / sin;\n\n\t\t\t}\n\n\t\t\tconst tDir = t * dir;\n\n\t\t\tx0 = x0 * s + x1 * tDir;\n\t\t\ty0 = y0 * s + y1 * tDir;\n\t\t\tz0 = z0 * s + z1 * tDir;\n\t\t\tw0 = w0 * s + w1 * tDir;\n\n\t\t\t// Normalize in case we just did a lerp:\n\t\t\tif ( s === 1 - t ) {\n\n\t\t\t\tconst f = 1 / Math.sqrt( x0 * x0 + y0 * y0 + z0 * z0 + w0 * w0 );\n\n\t\t\t\tx0 *= f;\n\t\t\t\ty0 *= f;\n\t\t\t\tz0 *= f;\n\t\t\t\tw0 *= f;\n\n\t\t\t}\n\n\t\t}\n\n\t\tdst[ dstOffset ] = x0;\n\t\tdst[ dstOffset + 1 ] = y0;\n\t\tdst[ dstOffset + 2 ] = z0;\n\t\tdst[ dstOffset + 3 ] = w0;\n\n\t}\n\n\tstatic multiplyQuaternionsFlat( dst, dstOffset, src0, srcOffset0, src1, srcOffset1 ) {\n\n\t\tconst x0 = src0[ srcOffset0 ];\n\t\tconst y0 = src0[ srcOffset0 + 1 ];\n\t\tconst z0 = src0[ srcOffset0 + 2 ];\n\t\tconst w0 = src0[ srcOffset0 + 3 ];\n\n\t\tconst x1 = src1[ srcOffset1 ];\n\t\tconst y1 = src1[ srcOffset1 + 1 ];\n\t\tconst z1 = src1[ srcOffset1 + 2 ];\n\t\tconst w1 = src1[ srcOffset1 + 3 ];\n\n\t\tdst[ dstOffset ] = x0 * w1 + w0 * x1 + y0 * z1 - z0 * y1;\n\t\tdst[ dstOffset + 1 ] = y0 * w1 + w0 * y1 + z0 * x1 - x0 * z1;\n\t\tdst[ dstOffset + 2 ] = z0 * w1 + w0 * z1 + x0 * y1 - y0 * x1;\n\t\tdst[ dstOffset + 3 ] = w0 * w1 - x0 * x1 - y0 * y1 - z0 * z1;\n\n\t\treturn dst;\n\n\t}\n\n\tget x() {\n\n\t\treturn this._x;\n\n\t}\n\n\tset x( value ) {\n\n\t\tthis._x = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget y() {\n\n\t\treturn this._y;\n\n\t}\n\n\tset y( value ) {\n\n\t\tthis._y = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget z() {\n\n\t\treturn this._z;\n\n\t}\n\n\tset z( value ) {\n\n\t\tthis._z = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget w() {\n\n\t\treturn this._w;\n\n\t}\n\n\tset w( value ) {\n\n\t\tthis._w = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tset( x, y, z, w ) {\n\n\t\tthis._x = x;\n\t\tthis._y = y;\n\t\tthis._z = z;\n\t\tthis._w = w;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this._x, this._y, this._z, this._w );\n\n\t}\n\n\tcopy( quaternion ) {\n\n\t\tthis._x = quaternion.x;\n\t\tthis._y = quaternion.y;\n\t\tthis._z = quaternion.z;\n\t\tthis._w = quaternion.w;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromEuler( euler, update = true ) {\n\n\t\tconst x = euler._x, y = euler._y, z = euler._z, order = euler._order;\n\n\t\t// http://www.mathworks.com/matlabcentral/fileexchange/\n\t\t// \t20696-function-to-convert-between-dcm-euler-angles-quaternions-and-euler-vectors/\n\t\t//\tcontent/SpinCalc.m\n\n\t\tconst cos = Math.cos;\n\t\tconst sin = Math.sin;\n\n\t\tconst c1 = cos( x / 2 );\n\t\tconst c2 = cos( y / 2 );\n\t\tconst c3 = cos( z / 2 );\n\n\t\tconst s1 = sin( x / 2 );\n\t\tconst s2 = sin( y / 2 );\n\t\tconst s3 = sin( z / 2 );\n\n\t\tswitch ( order ) {\n\n\t\t\tcase 'XYZ':\n\t\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tcase 'YXZ':\n\t\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tcase 'ZXY':\n\t\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tcase 'ZYX':\n\t\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tcase 'YZX':\n\t\t\t\tthis._x = s1 * c2 * c3 + c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 + s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 - s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 - s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tcase 'XZY':\n\t\t\t\tthis._x = s1 * c2 * c3 - c1 * s2 * s3;\n\t\t\t\tthis._y = c1 * s2 * c3 - s1 * c2 * s3;\n\t\t\t\tthis._z = c1 * c2 * s3 + s1 * s2 * c3;\n\t\t\t\tthis._w = c1 * c2 * c3 + s1 * s2 * s3;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tconsole.warn( 'THREE.Quaternion: .setFromEuler() encountered an unknown order: ' + order );\n\n\t\t}\n\n\t\tif ( update === true ) this._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromAxisAngle( axis, angle ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/angleToQuaternion/index.htm\n\n\t\t// assumes axis is normalized\n\n\t\tconst halfAngle = angle / 2, s = Math.sin( halfAngle );\n\n\t\tthis._x = axis.x * s;\n\t\tthis._y = axis.y * s;\n\t\tthis._z = axis.z * s;\n\t\tthis._w = Math.cos( halfAngle );\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromRotationMatrix( m ) {\n\n\t\t// http://www.euclideanspace.com/maths/geometry/rotations/conversions/matrixToQuaternion/index.htm\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tconst te = m.elements,\n\n\t\t\tm11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ],\n\t\t\tm21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ],\n\t\t\tm31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ],\n\n\t\t\ttrace = m11 + m22 + m33;\n\n\t\tif ( trace > 0 ) {\n\n\t\t\tconst s = 0.5 / Math.sqrt( trace + 1.0 );\n\n\t\t\tthis._w = 0.25 / s;\n\t\t\tthis._x = ( m32 - m23 ) * s;\n\t\t\tthis._y = ( m13 - m31 ) * s;\n\t\t\tthis._z = ( m21 - m12 ) * s;\n\n\t\t} else if ( m11 > m22 && m11 > m33 ) {\n\n\t\t\tconst s = 2.0 * Math.sqrt( 1.0 + m11 - m22 - m33 );\n\n\t\t\tthis._w = ( m32 - m23 ) / s;\n\t\t\tthis._x = 0.25 * s;\n\t\t\tthis._y = ( m12 + m21 ) / s;\n\t\t\tthis._z = ( m13 + m31 ) / s;\n\n\t\t} else if ( m22 > m33 ) {\n\n\t\t\tconst s = 2.0 * Math.sqrt( 1.0 + m22 - m11 - m33 );\n\n\t\t\tthis._w = ( m13 - m31 ) / s;\n\t\t\tthis._x = ( m12 + m21 ) / s;\n\t\t\tthis._y = 0.25 * s;\n\t\t\tthis._z = ( m23 + m32 ) / s;\n\n\t\t} else {\n\n\t\t\tconst s = 2.0 * Math.sqrt( 1.0 + m33 - m11 - m22 );\n\n\t\t\tthis._w = ( m21 - m12 ) / s;\n\t\t\tthis._x = ( m13 + m31 ) / s;\n\t\t\tthis._y = ( m23 + m32 ) / s;\n\t\t\tthis._z = 0.25 * s;\n\n\t\t}\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromUnitVectors( vFrom, vTo ) {\n\n\t\t// assumes direction vectors vFrom and vTo are normalized\n\n\t\tlet r = vFrom.dot( vTo ) + 1;\n\n\t\tif ( r < Number.EPSILON ) {\n\n\t\t\t// vFrom and vTo point in opposite directions\n\n\t\t\tr = 0;\n\n\t\t\tif ( Math.abs( vFrom.x ) > Math.abs( vFrom.z ) ) {\n\n\t\t\t\tthis._x = - vFrom.y;\n\t\t\t\tthis._y = vFrom.x;\n\t\t\t\tthis._z = 0;\n\t\t\t\tthis._w = r;\n\n\t\t\t} else {\n\n\t\t\t\tthis._x = 0;\n\t\t\t\tthis._y = - vFrom.z;\n\t\t\t\tthis._z = vFrom.y;\n\t\t\t\tthis._w = r;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// crossVectors( vFrom, vTo ); // inlined to avoid cyclic dependency on Vector3\n\n\t\t\tthis._x = vFrom.y * vTo.z - vFrom.z * vTo.y;\n\t\t\tthis._y = vFrom.z * vTo.x - vFrom.x * vTo.z;\n\t\t\tthis._z = vFrom.x * vTo.y - vFrom.y * vTo.x;\n\t\t\tthis._w = r;\n\n\t\t}\n\n\t\treturn this.normalize();\n\n\t}\n\n\tangleTo( q ) {\n\n\t\treturn 2 * Math.acos( Math.abs( clamp( this.dot( q ), - 1, 1 ) ) );\n\n\t}\n\n\trotateTowards( q, step ) {\n\n\t\tconst angle = this.angleTo( q );\n\n\t\tif ( angle === 0 ) return this;\n\n\t\tconst t = Math.min( 1, step / angle );\n\n\t\tthis.slerp( q, t );\n\n\t\treturn this;\n\n\t}\n\n\tidentity() {\n\n\t\treturn this.set( 0, 0, 0, 1 );\n\n\t}\n\n\tinvert() {\n\n\t\t// quaternion is assumed to have unit length\n\n\t\treturn this.conjugate();\n\n\t}\n\n\tconjugate() {\n\n\t\tthis._x *= - 1;\n\t\tthis._y *= - 1;\n\t\tthis._z *= - 1;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tdot( v ) {\n\n\t\treturn this._x * v._x + this._y * v._y + this._z * v._z + this._w * v._w;\n\n\t}\n\n\tlengthSq() {\n\n\t\treturn this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w;\n\n\t}\n\n\tlength() {\n\n\t\treturn Math.sqrt( this._x * this._x + this._y * this._y + this._z * this._z + this._w * this._w );\n\n\t}\n\n\tnormalize() {\n\n\t\tlet l = this.length();\n\n\t\tif ( l === 0 ) {\n\n\t\t\tthis._x = 0;\n\t\t\tthis._y = 0;\n\t\t\tthis._z = 0;\n\t\t\tthis._w = 1;\n\n\t\t} else {\n\n\t\t\tl = 1 / l;\n\n\t\t\tthis._x = this._x * l;\n\t\t\tthis._y = this._y * l;\n\t\t\tthis._z = this._z * l;\n\t\t\tthis._w = this._w * l;\n\n\t\t}\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( q ) {\n\n\t\treturn this.multiplyQuaternions( this, q );\n\n\t}\n\n\tpremultiply( q ) {\n\n\t\treturn this.multiplyQuaternions( q, this );\n\n\t}\n\n\tmultiplyQuaternions( a, b ) {\n\n\t\t// from http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/code/index.htm\n\n\t\tconst qax = a._x, qay = a._y, qaz = a._z, qaw = a._w;\n\t\tconst qbx = b._x, qby = b._y, qbz = b._z, qbw = b._w;\n\n\t\tthis._x = qax * qbw + qaw * qbx + qay * qbz - qaz * qby;\n\t\tthis._y = qay * qbw + qaw * qby + qaz * qbx - qax * qbz;\n\t\tthis._z = qaz * qbw + qaw * qbz + qax * qby - qay * qbx;\n\t\tthis._w = qaw * qbw - qax * qbx - qay * qby - qaz * qbz;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tslerp( qb, t ) {\n\n\t\tif ( t === 0 ) return this;\n\t\tif ( t === 1 ) return this.copy( qb );\n\n\t\tconst x = this._x, y = this._y, z = this._z, w = this._w;\n\n\t\t// http://www.euclideanspace.com/maths/algebra/realNormedAlgebra/quaternions/slerp/\n\n\t\tlet cosHalfTheta = w * qb._w + x * qb._x + y * qb._y + z * qb._z;\n\n\t\tif ( cosHalfTheta < 0 ) {\n\n\t\t\tthis._w = - qb._w;\n\t\t\tthis._x = - qb._x;\n\t\t\tthis._y = - qb._y;\n\t\t\tthis._z = - qb._z;\n\n\t\t\tcosHalfTheta = - cosHalfTheta;\n\n\t\t} else {\n\n\t\t\tthis.copy( qb );\n\n\t\t}\n\n\t\tif ( cosHalfTheta >= 1.0 ) {\n\n\t\t\tthis._w = w;\n\t\t\tthis._x = x;\n\t\t\tthis._y = y;\n\t\t\tthis._z = z;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tconst sqrSinHalfTheta = 1.0 - cosHalfTheta * cosHalfTheta;\n\n\t\tif ( sqrSinHalfTheta <= Number.EPSILON ) {\n\n\t\t\tconst s = 1 - t;\n\t\t\tthis._w = s * w + t * this._w;\n\t\t\tthis._x = s * x + t * this._x;\n\t\t\tthis._y = s * y + t * this._y;\n\t\t\tthis._z = s * z + t * this._z;\n\n\t\t\tthis.normalize(); // normalize calls _onChangeCallback()\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tconst sinHalfTheta = Math.sqrt( sqrSinHalfTheta );\n\t\tconst halfTheta = Math.atan2( sinHalfTheta, cosHalfTheta );\n\t\tconst ratioA = Math.sin( ( 1 - t ) * halfTheta ) / sinHalfTheta,\n\t\t\tratioB = Math.sin( t * halfTheta ) / sinHalfTheta;\n\n\t\tthis._w = ( w * ratioA + this._w * ratioB );\n\t\tthis._x = ( x * ratioA + this._x * ratioB );\n\t\tthis._y = ( y * ratioA + this._y * ratioB );\n\t\tthis._z = ( z * ratioA + this._z * ratioB );\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tslerpQuaternions( qa, qb, t ) {\n\n\t\treturn this.copy( qa ).slerp( qb, t );\n\n\t}\n\n\trandom() {\n\n\t\t// sets this quaternion to a uniform random unit quaternnion\n\n\t\t// Ken Shoemake\n\t\t// Uniform random rotations\n\t\t// D. Kirk, editor, Graphics Gems III, pages 124-132. Academic Press, New York, 1992.\n\n\t\tconst theta1 = 2 * Math.PI * Math.random();\n\t\tconst theta2 = 2 * Math.PI * Math.random();\n\n\t\tconst x0 = Math.random();\n\t\tconst r1 = Math.sqrt( 1 - x0 );\n\t\tconst r2 = Math.sqrt( x0 );\n\n\t\treturn this.set(\n\t\t\tr1 * Math.sin( theta1 ),\n\t\t\tr1 * Math.cos( theta1 ),\n\t\t\tr2 * Math.sin( theta2 ),\n\t\t\tr2 * Math.cos( theta2 ),\n\t\t);\n\n\t}\n\n\tequals( quaternion ) {\n\n\t\treturn ( quaternion._x === this._x ) && ( quaternion._y === this._y ) && ( quaternion._z === this._z ) && ( quaternion._w === this._w );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tthis._x = array[ offset ];\n\t\tthis._y = array[ offset + 1 ];\n\t\tthis._z = array[ offset + 2 ];\n\t\tthis._w = array[ offset + 3 ];\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this._x;\n\t\tarray[ offset + 1 ] = this._y;\n\t\tarray[ offset + 2 ] = this._z;\n\t\tarray[ offset + 3 ] = this._w;\n\n\t\treturn array;\n\n\t}\n\n\tfromBufferAttribute( attribute, index ) {\n\n\t\tthis._x = attribute.getX( index );\n\t\tthis._y = attribute.getY( index );\n\t\tthis._z = attribute.getZ( index );\n\t\tthis._w = attribute.getW( index );\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\treturn this.toArray();\n\n\t}\n\n\t_onChange( callback ) {\n\n\t\tthis._onChangeCallback = callback;\n\n\t\treturn this;\n\n\t}\n\n\t_onChangeCallback() {}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this._x;\n\t\tyield this._y;\n\t\tyield this._z;\n\t\tyield this._w;\n\n\t}\n\n}\n\nclass Vector3 {\n\n\tconstructor( x = 0, y = 0, z = 0 ) {\n\n\t\tVector3.prototype.isVector3 = true;\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.z = z;\n\n\t}\n\n\tset( x, y, z ) {\n\n\t\tif ( z === undefined ) z = this.z; // sprite.scale.set(x,y)\n\n\t\tthis.x = x;\n\t\tthis.y = y;\n\t\tthis.z = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetScalar( scalar ) {\n\n\t\tthis.x = scalar;\n\t\tthis.y = scalar;\n\t\tthis.z = scalar;\n\n\t\treturn this;\n\n\t}\n\n\tsetX( x ) {\n\n\t\tthis.x = x;\n\n\t\treturn this;\n\n\t}\n\n\tsetY( y ) {\n\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetZ( z ) {\n\n\t\tthis.z = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetComponent( index, value ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: this.x = value; break;\n\t\t\tcase 1: this.y = value; break;\n\t\t\tcase 2: this.z = value; break;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetComponent( index ) {\n\n\t\tswitch ( index ) {\n\n\t\t\tcase 0: return this.x;\n\t\t\tcase 1: return this.y;\n\t\t\tcase 2: return this.z;\n\t\t\tdefault: throw new Error( 'index is out of range: ' + index );\n\n\t\t}\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.x, this.y, this.z );\n\n\t}\n\n\tcopy( v ) {\n\n\t\tthis.x = v.x;\n\t\tthis.y = v.y;\n\t\tthis.z = v.z;\n\n\t\treturn this;\n\n\t}\n\n\tadd( v ) {\n\n\t\tthis.x += v.x;\n\t\tthis.y += v.y;\n\t\tthis.z += v.z;\n\n\t\treturn this;\n\n\t}\n\n\taddScalar( s ) {\n\n\t\tthis.x += s;\n\t\tthis.y += s;\n\t\tthis.z += s;\n\n\t\treturn this;\n\n\t}\n\n\taddVectors( a, b ) {\n\n\t\tthis.x = a.x + b.x;\n\t\tthis.y = a.y + b.y;\n\t\tthis.z = a.z + b.z;\n\n\t\treturn this;\n\n\t}\n\n\taddScaledVector( v, s ) {\n\n\t\tthis.x += v.x * s;\n\t\tthis.y += v.y * s;\n\t\tthis.z += v.z * s;\n\n\t\treturn this;\n\n\t}\n\n\tsub( v ) {\n\n\t\tthis.x -= v.x;\n\t\tthis.y -= v.y;\n\t\tthis.z -= v.z;\n\n\t\treturn this;\n\n\t}\n\n\tsubScalar( s ) {\n\n\t\tthis.x -= s;\n\t\tthis.y -= s;\n\t\tthis.z -= s;\n\n\t\treturn this;\n\n\t}\n\n\tsubVectors( a, b ) {\n\n\t\tthis.x = a.x - b.x;\n\t\tthis.y = a.y - b.y;\n\t\tthis.z = a.z - b.z;\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( v ) {\n\n\t\tthis.x *= v.x;\n\t\tthis.y *= v.y;\n\t\tthis.z *= v.z;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( scalar ) {\n\n\t\tthis.x *= scalar;\n\t\tthis.y *= scalar;\n\t\tthis.z *= scalar;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyVectors( a, b ) {\n\n\t\tthis.x = a.x * b.x;\n\t\tthis.y = a.y * b.y;\n\t\tthis.z = a.z * b.z;\n\n\t\treturn this;\n\n\t}\n\n\tapplyEuler( euler ) {\n\n\t\treturn this.applyQuaternion( _quaternion$4.setFromEuler( euler ) );\n\n\t}\n\n\tapplyAxisAngle( axis, angle ) {\n\n\t\treturn this.applyQuaternion( _quaternion$4.setFromAxisAngle( axis, angle ) );\n\n\t}\n\n\tapplyMatrix3( m ) {\n\n\t\tconst x = this.x, y = this.y, z = this.z;\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 3 ] * y + e[ 6 ] * z;\n\t\tthis.y = e[ 1 ] * x + e[ 4 ] * y + e[ 7 ] * z;\n\t\tthis.z = e[ 2 ] * x + e[ 5 ] * y + e[ 8 ] * z;\n\n\t\treturn this;\n\n\t}\n\n\tapplyNormalMatrix( m ) {\n\n\t\treturn this.applyMatrix3( m ).normalize();\n\n\t}\n\n\tapplyMatrix4( m ) {\n\n\t\tconst x = this.x, y = this.y, z = this.z;\n\t\tconst e = m.elements;\n\n\t\tconst w = 1 / ( e[ 3 ] * x + e[ 7 ] * y + e[ 11 ] * z + e[ 15 ] );\n\n\t\tthis.x = ( e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z + e[ 12 ] ) * w;\n\t\tthis.y = ( e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z + e[ 13 ] ) * w;\n\t\tthis.z = ( e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z + e[ 14 ] ) * w;\n\n\t\treturn this;\n\n\t}\n\n\tapplyQuaternion( q ) {\n\n\t\t// quaternion q is assumed to have unit length\n\n\t\tconst vx = this.x, vy = this.y, vz = this.z;\n\t\tconst qx = q.x, qy = q.y, qz = q.z, qw = q.w;\n\n\t\t// t = 2 * cross( q.xyz, v );\n\t\tconst tx = 2 * ( qy * vz - qz * vy );\n\t\tconst ty = 2 * ( qz * vx - qx * vz );\n\t\tconst tz = 2 * ( qx * vy - qy * vx );\n\n\t\t// v + q.w * t + cross( q.xyz, t );\n\t\tthis.x = vx + qw * tx + qy * tz - qz * ty;\n\t\tthis.y = vy + qw * ty + qz * tx - qx * tz;\n\t\tthis.z = vz + qw * tz + qx * ty - qy * tx;\n\n\t\treturn this;\n\n\t}\n\n\tproject( camera ) {\n\n\t\treturn this.applyMatrix4( camera.matrixWorldInverse ).applyMatrix4( camera.projectionMatrix );\n\n\t}\n\n\tunproject( camera ) {\n\n\t\treturn this.applyMatrix4( camera.projectionMatrixInverse ).applyMatrix4( camera.matrixWorld );\n\n\t}\n\n\ttransformDirection( m ) {\n\n\t\t// input: THREE.Matrix4 affine matrix\n\t\t// vector interpreted as a direction\n\n\t\tconst x = this.x, y = this.y, z = this.z;\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 0 ] * x + e[ 4 ] * y + e[ 8 ] * z;\n\t\tthis.y = e[ 1 ] * x + e[ 5 ] * y + e[ 9 ] * z;\n\t\tthis.z = e[ 2 ] * x + e[ 6 ] * y + e[ 10 ] * z;\n\n\t\treturn this.normalize();\n\n\t}\n\n\tdivide( v ) {\n\n\t\tthis.x /= v.x;\n\t\tthis.y /= v.y;\n\t\tthis.z /= v.z;\n\n\t\treturn this;\n\n\t}\n\n\tdivideScalar( scalar ) {\n\n\t\treturn this.multiplyScalar( 1 / scalar );\n\n\t}\n\n\tmin( v ) {\n\n\t\tthis.x = Math.min( this.x, v.x );\n\t\tthis.y = Math.min( this.y, v.y );\n\t\tthis.z = Math.min( this.z, v.z );\n\n\t\treturn this;\n\n\t}\n\n\tmax( v ) {\n\n\t\tthis.x = Math.max( this.x, v.x );\n\t\tthis.y = Math.max( this.y, v.y );\n\t\tthis.z = Math.max( this.z, v.z );\n\n\t\treturn this;\n\n\t}\n\n\tclamp( min, max ) {\n\n\t\t// assumes min < max, componentwise\n\n\t\tthis.x = Math.max( min.x, Math.min( max.x, this.x ) );\n\t\tthis.y = Math.max( min.y, Math.min( max.y, this.y ) );\n\t\tthis.z = Math.max( min.z, Math.min( max.z, this.z ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampScalar( minVal, maxVal ) {\n\n\t\tthis.x = Math.max( minVal, Math.min( maxVal, this.x ) );\n\t\tthis.y = Math.max( minVal, Math.min( maxVal, this.y ) );\n\t\tthis.z = Math.max( minVal, Math.min( maxVal, this.z ) );\n\n\t\treturn this;\n\n\t}\n\n\tclampLength( min, max ) {\n\n\t\tconst length = this.length();\n\n\t\treturn this.divideScalar( length || 1 ).multiplyScalar( Math.max( min, Math.min( max, length ) ) );\n\n\t}\n\n\tfloor() {\n\n\t\tthis.x = Math.floor( this.x );\n\t\tthis.y = Math.floor( this.y );\n\t\tthis.z = Math.floor( this.z );\n\n\t\treturn this;\n\n\t}\n\n\tceil() {\n\n\t\tthis.x = Math.ceil( this.x );\n\t\tthis.y = Math.ceil( this.y );\n\t\tthis.z = Math.ceil( this.z );\n\n\t\treturn this;\n\n\t}\n\n\tround() {\n\n\t\tthis.x = Math.round( this.x );\n\t\tthis.y = Math.round( this.y );\n\t\tthis.z = Math.round( this.z );\n\n\t\treturn this;\n\n\t}\n\n\troundToZero() {\n\n\t\tthis.x = Math.trunc( this.x );\n\t\tthis.y = Math.trunc( this.y );\n\t\tthis.z = Math.trunc( this.z );\n\n\t\treturn this;\n\n\t}\n\n\tnegate() {\n\n\t\tthis.x = - this.x;\n\t\tthis.y = - this.y;\n\t\tthis.z = - this.z;\n\n\t\treturn this;\n\n\t}\n\n\tdot( v ) {\n\n\t\treturn this.x * v.x + this.y * v.y + this.z * v.z;\n\n\t}\n\n\t// TODO lengthSquared?\n\n\tlengthSq() {\n\n\t\treturn this.x * this.x + this.y * this.y + this.z * this.z;\n\n\t}\n\n\tlength() {\n\n\t\treturn Math.sqrt( this.x * this.x + this.y * this.y + this.z * this.z );\n\n\t}\n\n\tmanhattanLength() {\n\n\t\treturn Math.abs( this.x ) + Math.abs( this.y ) + Math.abs( this.z );\n\n\t}\n\n\tnormalize() {\n\n\t\treturn this.divideScalar( this.length() || 1 );\n\n\t}\n\n\tsetLength( length ) {\n\n\t\treturn this.normalize().multiplyScalar( length );\n\n\t}\n\n\tlerp( v, alpha ) {\n\n\t\tthis.x += ( v.x - this.x ) * alpha;\n\t\tthis.y += ( v.y - this.y ) * alpha;\n\t\tthis.z += ( v.z - this.z ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tlerpVectors( v1, v2, alpha ) {\n\n\t\tthis.x = v1.x + ( v2.x - v1.x ) * alpha;\n\t\tthis.y = v1.y + ( v2.y - v1.y ) * alpha;\n\t\tthis.z = v1.z + ( v2.z - v1.z ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tcross( v ) {\n\n\t\treturn this.crossVectors( this, v );\n\n\t}\n\n\tcrossVectors( a, b ) {\n\n\t\tconst ax = a.x, ay = a.y, az = a.z;\n\t\tconst bx = b.x, by = b.y, bz = b.z;\n\n\t\tthis.x = ay * bz - az * by;\n\t\tthis.y = az * bx - ax * bz;\n\t\tthis.z = ax * by - ay * bx;\n\n\t\treturn this;\n\n\t}\n\n\tprojectOnVector( v ) {\n\n\t\tconst denominator = v.lengthSq();\n\n\t\tif ( denominator === 0 ) return this.set( 0, 0, 0 );\n\n\t\tconst scalar = v.dot( this ) / denominator;\n\n\t\treturn this.copy( v ).multiplyScalar( scalar );\n\n\t}\n\n\tprojectOnPlane( planeNormal ) {\n\n\t\t_vector$c.copy( this ).projectOnVector( planeNormal );\n\n\t\treturn this.sub( _vector$c );\n\n\t}\n\n\treflect( normal ) {\n\n\t\t// reflect incident vector off plane orthogonal to normal\n\t\t// normal is assumed to have unit length\n\n\t\treturn this.sub( _vector$c.copy( normal ).multiplyScalar( 2 * this.dot( normal ) ) );\n\n\t}\n\n\tangleTo( v ) {\n\n\t\tconst denominator = Math.sqrt( this.lengthSq() * v.lengthSq() );\n\n\t\tif ( denominator === 0 ) return Math.PI / 2;\n\n\t\tconst theta = this.dot( v ) / denominator;\n\n\t\t// clamp, to handle numerical problems\n\n\t\treturn Math.acos( clamp( theta, - 1, 1 ) );\n\n\t}\n\n\tdistanceTo( v ) {\n\n\t\treturn Math.sqrt( this.distanceToSquared( v ) );\n\n\t}\n\n\tdistanceToSquared( v ) {\n\n\t\tconst dx = this.x - v.x, dy = this.y - v.y, dz = this.z - v.z;\n\n\t\treturn dx * dx + dy * dy + dz * dz;\n\n\t}\n\n\tmanhattanDistanceTo( v ) {\n\n\t\treturn Math.abs( this.x - v.x ) + Math.abs( this.y - v.y ) + Math.abs( this.z - v.z );\n\n\t}\n\n\tsetFromSpherical( s ) {\n\n\t\treturn this.setFromSphericalCoords( s.radius, s.phi, s.theta );\n\n\t}\n\n\tsetFromSphericalCoords( radius, phi, theta ) {\n\n\t\tconst sinPhiRadius = Math.sin( phi ) * radius;\n\n\t\tthis.x = sinPhiRadius * Math.sin( theta );\n\t\tthis.y = Math.cos( phi ) * radius;\n\t\tthis.z = sinPhiRadius * Math.cos( theta );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromCylindrical( c ) {\n\n\t\treturn this.setFromCylindricalCoords( c.radius, c.theta, c.y );\n\n\t}\n\n\tsetFromCylindricalCoords( radius, theta, y ) {\n\n\t\tthis.x = radius * Math.sin( theta );\n\t\tthis.y = y;\n\t\tthis.z = radius * Math.cos( theta );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrixPosition( m ) {\n\n\t\tconst e = m.elements;\n\n\t\tthis.x = e[ 12 ];\n\t\tthis.y = e[ 13 ];\n\t\tthis.z = e[ 14 ];\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrixScale( m ) {\n\n\t\tconst sx = this.setFromMatrixColumn( m, 0 ).length();\n\t\tconst sy = this.setFromMatrixColumn( m, 1 ).length();\n\t\tconst sz = this.setFromMatrixColumn( m, 2 ).length();\n\n\t\tthis.x = sx;\n\t\tthis.y = sy;\n\t\tthis.z = sz;\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrixColumn( m, index ) {\n\n\t\treturn this.fromArray( m.elements, index * 4 );\n\n\t}\n\n\tsetFromMatrix3Column( m, index ) {\n\n\t\treturn this.fromArray( m.elements, index * 3 );\n\n\t}\n\n\tsetFromEuler( e ) {\n\n\t\tthis.x = e._x;\n\t\tthis.y = e._y;\n\t\tthis.z = e._z;\n\n\t\treturn this;\n\n\t}\n\n\tsetFromColor( c ) {\n\n\t\tthis.x = c.r;\n\t\tthis.y = c.g;\n\t\tthis.z = c.b;\n\n\t\treturn this;\n\n\t}\n\n\tequals( v ) {\n\n\t\treturn ( ( v.x === this.x ) && ( v.y === this.y ) && ( v.z === this.z ) );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tthis.x = array[ offset ];\n\t\tthis.y = array[ offset + 1 ];\n\t\tthis.z = array[ offset + 2 ];\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this.x;\n\t\tarray[ offset + 1 ] = this.y;\n\t\tarray[ offset + 2 ] = this.z;\n\n\t\treturn array;\n\n\t}\n\n\tfromBufferAttribute( attribute, index ) {\n\n\t\tthis.x = attribute.getX( index );\n\t\tthis.y = attribute.getY( index );\n\t\tthis.z = attribute.getZ( index );\n\n\t\treturn this;\n\n\t}\n\n\trandom() {\n\n\t\tthis.x = Math.random();\n\t\tthis.y = Math.random();\n\t\tthis.z = Math.random();\n\n\t\treturn this;\n\n\t}\n\n\trandomDirection() {\n\n\t\t// https://mathworld.wolfram.com/SpherePointPicking.html\n\n\t\tconst theta = Math.random() * Math.PI * 2;\n\t\tconst u = Math.random() * 2 - 1;\n\t\tconst c = Math.sqrt( 1 - u * u );\n\n\t\tthis.x = c * Math.cos( theta );\n\t\tthis.y = u;\n\t\tthis.z = c * Math.sin( theta );\n\n\t\treturn this;\n\n\t}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this.x;\n\t\tyield this.y;\n\t\tyield this.z;\n\n\t}\n\n}\n\nconst _vector$c = /*@__PURE__*/ new Vector3();\nconst _quaternion$4 = /*@__PURE__*/ new Quaternion();\n\nclass Box3 {\n\n\tconstructor( min = new Vector3( + Infinity, + Infinity, + Infinity ), max = new Vector3( - Infinity, - Infinity, - Infinity ) ) {\n\n\t\tthis.isBox3 = true;\n\n\t\tthis.min = min;\n\t\tthis.max = max;\n\n\t}\n\n\tset( min, max ) {\n\n\t\tthis.min.copy( min );\n\t\tthis.max.copy( max );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromArray( array ) {\n\n\t\tthis.makeEmpty();\n\n\t\tfor ( let i = 0, il = array.length; i < il; i += 3 ) {\n\n\t\t\tthis.expandByPoint( _vector$b.fromArray( array, i ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetFromBufferAttribute( attribute ) {\n\n\t\tthis.makeEmpty();\n\n\t\tfor ( let i = 0, il = attribute.count; i < il; i ++ ) {\n\n\t\t\tthis.expandByPoint( _vector$b.fromBufferAttribute( attribute, i ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetFromPoints( points ) {\n\n\t\tthis.makeEmpty();\n\n\t\tfor ( let i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\tthis.expandByPoint( points[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetFromCenterAndSize( center, size ) {\n\n\t\tconst halfSize = _vector$b.copy( size ).multiplyScalar( 0.5 );\n\n\t\tthis.min.copy( center ).sub( halfSize );\n\t\tthis.max.copy( center ).add( halfSize );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromObject( object, precise = false ) {\n\n\t\tthis.makeEmpty();\n\n\t\treturn this.expandByObject( object, precise );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( box ) {\n\n\t\tthis.min.copy( box.min );\n\t\tthis.max.copy( box.max );\n\n\t\treturn this;\n\n\t}\n\n\tmakeEmpty() {\n\n\t\tthis.min.x = this.min.y = this.min.z = + Infinity;\n\t\tthis.max.x = this.max.y = this.max.z = - Infinity;\n\n\t\treturn this;\n\n\t}\n\n\tisEmpty() {\n\n\t\t// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes\n\n\t\treturn ( this.max.x < this.min.x ) || ( this.max.y < this.min.y ) || ( this.max.z < this.min.z );\n\n\t}\n\n\tgetCenter( target ) {\n\n\t\treturn this.isEmpty() ? target.set( 0, 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );\n\n\t}\n\n\tgetSize( target ) {\n\n\t\treturn this.isEmpty() ? target.set( 0, 0, 0 ) : target.subVectors( this.max, this.min );\n\n\t}\n\n\texpandByPoint( point ) {\n\n\t\tthis.min.min( point );\n\t\tthis.max.max( point );\n\n\t\treturn this;\n\n\t}\n\n\texpandByVector( vector ) {\n\n\t\tthis.min.sub( vector );\n\t\tthis.max.add( vector );\n\n\t\treturn this;\n\n\t}\n\n\texpandByScalar( scalar ) {\n\n\t\tthis.min.addScalar( - scalar );\n\t\tthis.max.addScalar( scalar );\n\n\t\treturn this;\n\n\t}\n\n\texpandByObject( object, precise = false ) {\n\n\t\t// Computes the world-axis-aligned bounding box of an object (including its children),\n\t\t// accounting for both the object's, and children's, world transforms\n\n\t\tobject.updateWorldMatrix( false, false );\n\n\t\tconst geometry = object.geometry;\n\n\t\tif ( geometry !== undefined ) {\n\n\t\t\tconst positionAttribute = geometry.getAttribute( 'position' );\n\n\t\t\t// precise AABB computation based on vertex data requires at least a position attribute.\n\t\t\t// instancing isn't supported so far and uses the normal (conservative) code path.\n\n\t\t\tif ( precise === true && positionAttribute !== undefined && object.isInstancedMesh !== true ) {\n\n\t\t\t\tfor ( let i = 0, l = positionAttribute.count; i < l; i ++ ) {\n\n\t\t\t\t\tif ( object.isMesh === true ) {\n\n\t\t\t\t\t\tobject.getVertexPosition( i, _vector$b );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t_vector$b.fromBufferAttribute( positionAttribute, i );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t_vector$b.applyMatrix4( object.matrixWorld );\n\t\t\t\t\tthis.expandByPoint( _vector$b );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( object.boundingBox !== undefined ) {\n\n\t\t\t\t\t// object-level bounding box\n\n\t\t\t\t\tif ( object.boundingBox === null ) {\n\n\t\t\t\t\t\tobject.computeBoundingBox();\n\n\t\t\t\t\t}\n\n\t\t\t\t\t_box$4.copy( object.boundingBox );\n\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// geometry-level bounding box\n\n\t\t\t\t\tif ( geometry.boundingBox === null ) {\n\n\t\t\t\t\t\tgeometry.computeBoundingBox();\n\n\t\t\t\t\t}\n\n\t\t\t\t\t_box$4.copy( geometry.boundingBox );\n\n\t\t\t\t}\n\n\t\t\t\t_box$4.applyMatrix4( object.matrixWorld );\n\n\t\t\t\tthis.union( _box$4 );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst children = object.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tthis.expandByObject( children[ i ], precise );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tcontainsPoint( point ) {\n\n\t\treturn point.x >= this.min.x && point.x <= this.max.x &&\n\t\t\tpoint.y >= this.min.y && point.y <= this.max.y &&\n\t\t\tpoint.z >= this.min.z && point.z <= this.max.z;\n\n\t}\n\n\tcontainsBox( box ) {\n\n\t\treturn this.min.x <= box.min.x && box.max.x <= this.max.x &&\n\t\t\tthis.min.y <= box.min.y && box.max.y <= this.max.y &&\n\t\t\tthis.min.z <= box.min.z && box.max.z <= this.max.z;\n\n\t}\n\n\tgetParameter( point, target ) {\n\n\t\t// This can potentially have a divide by zero if the box\n\t\t// has a size dimension of 0.\n\n\t\treturn target.set(\n\t\t\t( point.x - this.min.x ) / ( this.max.x - this.min.x ),\n\t\t\t( point.y - this.min.y ) / ( this.max.y - this.min.y ),\n\t\t\t( point.z - this.min.z ) / ( this.max.z - this.min.z )\n\t\t);\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\t// using 6 splitting planes to rule out intersections.\n\t\treturn box.max.x >= this.min.x && box.min.x <= this.max.x &&\n\t\t\tbox.max.y >= this.min.y && box.min.y <= this.max.y &&\n\t\t\tbox.max.z >= this.min.z && box.min.z <= this.max.z;\n\n\t}\n\n\tintersectsSphere( sphere ) {\n\n\t\t// Find the point on the AABB closest to the sphere center.\n\t\tthis.clampPoint( sphere.center, _vector$b );\n\n\t\t// If that point is inside the sphere, the AABB and sphere intersect.\n\t\treturn _vector$b.distanceToSquared( sphere.center ) <= ( sphere.radius * sphere.radius );\n\n\t}\n\n\tintersectsPlane( plane ) {\n\n\t\t// We compute the minimum and maximum dot product values. If those values\n\t\t// are on the same side (back or front) of the plane, then there is no intersection.\n\n\t\tlet min, max;\n\n\t\tif ( plane.normal.x > 0 ) {\n\n\t\t\tmin = plane.normal.x * this.min.x;\n\t\t\tmax = plane.normal.x * this.max.x;\n\n\t\t} else {\n\n\t\t\tmin = plane.normal.x * this.max.x;\n\t\t\tmax = plane.normal.x * this.min.x;\n\n\t\t}\n\n\t\tif ( plane.normal.y > 0 ) {\n\n\t\t\tmin += plane.normal.y * this.min.y;\n\t\t\tmax += plane.normal.y * this.max.y;\n\n\t\t} else {\n\n\t\t\tmin += plane.normal.y * this.max.y;\n\t\t\tmax += plane.normal.y * this.min.y;\n\n\t\t}\n\n\t\tif ( plane.normal.z > 0 ) {\n\n\t\t\tmin += plane.normal.z * this.min.z;\n\t\t\tmax += plane.normal.z * this.max.z;\n\n\t\t} else {\n\n\t\t\tmin += plane.normal.z * this.max.z;\n\t\t\tmax += plane.normal.z * this.min.z;\n\n\t\t}\n\n\t\treturn ( min <= - plane.constant && max >= - plane.constant );\n\n\t}\n\n\tintersectsTriangle( triangle ) {\n\n\t\tif ( this.isEmpty() ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\t// compute box center and extents\n\t\tthis.getCenter( _center );\n\t\t_extents.subVectors( this.max, _center );\n\n\t\t// translate triangle to aabb origin\n\t\t_v0$3.subVectors( triangle.a, _center );\n\t\t_v1$7.subVectors( triangle.b, _center );\n\t\t_v2$4.subVectors( triangle.c, _center );\n\n\t\t// compute edge vectors for triangle\n\t\t_f0.subVectors( _v1$7, _v0$3 );\n\t\t_f1.subVectors( _v2$4, _v1$7 );\n\t\t_f2.subVectors( _v0$3, _v2$4 );\n\n\t\t// test against axes that are given by cross product combinations of the edges of the triangle and the edges of the aabb\n\t\t// 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\n\t\t// axis_ij = u_i x f_j (u0, u1, u2 = face normals of aabb = x,y,z axes vectors since aabb is axis aligned)\n\t\tlet axes = [\n\t\t\t0, - _f0.z, _f0.y, 0, - _f1.z, _f1.y, 0, - _f2.z, _f2.y,\n\t\t\t_f0.z, 0, - _f0.x, _f1.z, 0, - _f1.x, _f2.z, 0, - _f2.x,\n\t\t\t- _f0.y, _f0.x, 0, - _f1.y, _f1.x, 0, - _f2.y, _f2.x, 0\n\t\t];\n\t\tif ( ! satForAxes( axes, _v0$3, _v1$7, _v2$4, _extents ) ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\t// test 3 face normals from the aabb\n\t\taxes = [ 1, 0, 0, 0, 1, 0, 0, 0, 1 ];\n\t\tif ( ! satForAxes( axes, _v0$3, _v1$7, _v2$4, _extents ) ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\t// finally testing the face normal of the triangle\n\t\t// use already existing triangle edge vectors here\n\t\t_triangleNormal.crossVectors( _f0, _f1 );\n\t\taxes = [ _triangleNormal.x, _triangleNormal.y, _triangleNormal.z ];\n\n\t\treturn satForAxes( axes, _v0$3, _v1$7, _v2$4, _extents );\n\n\t}\n\n\tclampPoint( point, target ) {\n\n\t\treturn target.copy( point ).clamp( this.min, this.max );\n\n\t}\n\n\tdistanceToPoint( point ) {\n\n\t\treturn this.clampPoint( point, _vector$b ).distanceTo( point );\n\n\t}\n\n\tgetBoundingSphere( target ) {\n\n\t\tif ( this.isEmpty() ) {\n\n\t\t\ttarget.makeEmpty();\n\n\t\t} else {\n\n\t\t\tthis.getCenter( target.center );\n\n\t\t\ttarget.radius = this.getSize( _vector$b ).length() * 0.5;\n\n\t\t}\n\n\t\treturn target;\n\n\t}\n\n\tintersect( box ) {\n\n\t\tthis.min.max( box.min );\n\t\tthis.max.min( box.max );\n\n\t\t// 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.\n\t\tif ( this.isEmpty() ) this.makeEmpty();\n\n\t\treturn this;\n\n\t}\n\n\tunion( box ) {\n\n\t\tthis.min.min( box.min );\n\t\tthis.max.max( box.max );\n\n\t\treturn this;\n\n\t}\n\n\tapplyMatrix4( matrix ) {\n\n\t\t// transform of empty box is an empty box.\n\t\tif ( this.isEmpty() ) return this;\n\n\t\t// NOTE: I am using a binary pattern to specify all 2^3 combinations below\n\t\t_points[ 0 ].set( this.min.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 000\n\t\t_points[ 1 ].set( this.min.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 001\n\t\t_points[ 2 ].set( this.min.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 010\n\t\t_points[ 3 ].set( this.min.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 011\n\t\t_points[ 4 ].set( this.max.x, this.min.y, this.min.z ).applyMatrix4( matrix ); // 100\n\t\t_points[ 5 ].set( this.max.x, this.min.y, this.max.z ).applyMatrix4( matrix ); // 101\n\t\t_points[ 6 ].set( this.max.x, this.max.y, this.min.z ).applyMatrix4( matrix ); // 110\n\t\t_points[ 7 ].set( this.max.x, this.max.y, this.max.z ).applyMatrix4( matrix ); // 111\n\n\t\tthis.setFromPoints( _points );\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( offset ) {\n\n\t\tthis.min.add( offset );\n\t\tthis.max.add( offset );\n\n\t\treturn this;\n\n\t}\n\n\tequals( box ) {\n\n\t\treturn box.min.equals( this.min ) && box.max.equals( this.max );\n\n\t}\n\n}\n\nconst _points = [\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3(),\n\t/*@__PURE__*/ new Vector3()\n];\n\nconst _vector$b = /*@__PURE__*/ new Vector3();\n\nconst _box$4 = /*@__PURE__*/ new Box3();\n\n// triangle centered vertices\n\nconst _v0$3 = /*@__PURE__*/ new Vector3();\nconst _v1$7 = /*@__PURE__*/ new Vector3();\nconst _v2$4 = /*@__PURE__*/ new Vector3();\n\n// triangle edge vectors\n\nconst _f0 = /*@__PURE__*/ new Vector3();\nconst _f1 = /*@__PURE__*/ new Vector3();\nconst _f2 = /*@__PURE__*/ new Vector3();\n\nconst _center = /*@__PURE__*/ new Vector3();\nconst _extents = /*@__PURE__*/ new Vector3();\nconst _triangleNormal = /*@__PURE__*/ new Vector3();\nconst _testAxis = /*@__PURE__*/ new Vector3();\n\nfunction satForAxes( axes, v0, v1, v2, extents ) {\n\n\tfor ( let i = 0, j = axes.length - 3; i <= j; i += 3 ) {\n\n\t\t_testAxis.fromArray( axes, i );\n\t\t// project the aabb onto the separating axis\n\t\tconst r = extents.x * Math.abs( _testAxis.x ) + extents.y * Math.abs( _testAxis.y ) + extents.z * Math.abs( _testAxis.z );\n\t\t// project all 3 vertices of the triangle onto the separating axis\n\t\tconst p0 = v0.dot( _testAxis );\n\t\tconst p1 = v1.dot( _testAxis );\n\t\tconst p2 = v2.dot( _testAxis );\n\t\t// actual test, basically see if either of the most extreme of the triangle points intersects r\n\t\tif ( Math.max( - Math.max( p0, p1, p2 ), Math.min( p0, p1, p2 ) ) > r ) {\n\n\t\t\t// points of the projected triangle are outside the projected half-length of the aabb\n\t\t\t// the axis is separating and we can exit\n\t\t\treturn false;\n\n\t\t}\n\n\t}\n\n\treturn true;\n\n}\n\nconst _box$3 = /*@__PURE__*/ new Box3();\nconst _v1$6 = /*@__PURE__*/ new Vector3();\nconst _v2$3 = /*@__PURE__*/ new Vector3();\n\nclass Sphere {\n\n\tconstructor( center = new Vector3(), radius = - 1 ) {\n\n\t\tthis.isSphere = true;\n\n\t\tthis.center = center;\n\t\tthis.radius = radius;\n\n\t}\n\n\tset( center, radius ) {\n\n\t\tthis.center.copy( center );\n\t\tthis.radius = radius;\n\n\t\treturn this;\n\n\t}\n\n\tsetFromPoints( points, optionalCenter ) {\n\n\t\tconst center = this.center;\n\n\t\tif ( optionalCenter !== undefined ) {\n\n\t\t\tcenter.copy( optionalCenter );\n\n\t\t} else {\n\n\t\t\t_box$3.setFromPoints( points ).getCenter( center );\n\n\t\t}\n\n\t\tlet maxRadiusSq = 0;\n\n\t\tfor ( let i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( points[ i ] ) );\n\n\t\t}\n\n\t\tthis.radius = Math.sqrt( maxRadiusSq );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( sphere ) {\n\n\t\tthis.center.copy( sphere.center );\n\t\tthis.radius = sphere.radius;\n\n\t\treturn this;\n\n\t}\n\n\tisEmpty() {\n\n\t\treturn ( this.radius < 0 );\n\n\t}\n\n\tmakeEmpty() {\n\n\t\tthis.center.set( 0, 0, 0 );\n\t\tthis.radius = - 1;\n\n\t\treturn this;\n\n\t}\n\n\tcontainsPoint( point ) {\n\n\t\treturn ( point.distanceToSquared( this.center ) <= ( this.radius * this.radius ) );\n\n\t}\n\n\tdistanceToPoint( point ) {\n\n\t\treturn ( point.distanceTo( this.center ) - this.radius );\n\n\t}\n\n\tintersectsSphere( sphere ) {\n\n\t\tconst radiusSum = this.radius + sphere.radius;\n\n\t\treturn sphere.center.distanceToSquared( this.center ) <= ( radiusSum * radiusSum );\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\treturn box.intersectsSphere( this );\n\n\t}\n\n\tintersectsPlane( plane ) {\n\n\t\treturn Math.abs( plane.distanceToPoint( this.center ) ) <= this.radius;\n\n\t}\n\n\tclampPoint( point, target ) {\n\n\t\tconst deltaLengthSq = this.center.distanceToSquared( point );\n\n\t\ttarget.copy( point );\n\n\t\tif ( deltaLengthSq > ( this.radius * this.radius ) ) {\n\n\t\t\ttarget.sub( this.center ).normalize();\n\t\t\ttarget.multiplyScalar( this.radius ).add( this.center );\n\n\t\t}\n\n\t\treturn target;\n\n\t}\n\n\tgetBoundingBox( target ) {\n\n\t\tif ( this.isEmpty() ) {\n\n\t\t\t// Empty sphere produces empty bounding box\n\t\t\ttarget.makeEmpty();\n\t\t\treturn target;\n\n\t\t}\n\n\t\ttarget.set( this.center, this.center );\n\t\ttarget.expandByScalar( this.radius );\n\n\t\treturn target;\n\n\t}\n\n\tapplyMatrix4( matrix ) {\n\n\t\tthis.center.applyMatrix4( matrix );\n\t\tthis.radius = this.radius * matrix.getMaxScaleOnAxis();\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( offset ) {\n\n\t\tthis.center.add( offset );\n\n\t\treturn this;\n\n\t}\n\n\texpandByPoint( point ) {\n\n\t\tif ( this.isEmpty() ) {\n\n\t\t\tthis.center.copy( point );\n\n\t\t\tthis.radius = 0;\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\t_v1$6.subVectors( point, this.center );\n\n\t\tconst lengthSq = _v1$6.lengthSq();\n\n\t\tif ( lengthSq > ( this.radius * this.radius ) ) {\n\n\t\t\t// calculate the minimal sphere\n\n\t\t\tconst length = Math.sqrt( lengthSq );\n\n\t\t\tconst delta = ( length - this.radius ) * 0.5;\n\n\t\t\tthis.center.addScaledVector( _v1$6, delta / length );\n\n\t\t\tthis.radius += delta;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tunion( sphere ) {\n\n\t\tif ( sphere.isEmpty() ) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( this.isEmpty() ) {\n\n\t\t\tthis.copy( sphere );\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( this.center.equals( sphere.center ) === true ) {\n\n\t\t\t this.radius = Math.max( this.radius, sphere.radius );\n\n\t\t} else {\n\n\t\t\t_v2$3.subVectors( sphere.center, this.center ).setLength( sphere.radius );\n\n\t\t\tthis.expandByPoint( _v1$6.copy( sphere.center ).add( _v2$3 ) );\n\n\t\t\tthis.expandByPoint( _v1$6.copy( sphere.center ).sub( _v2$3 ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tequals( sphere ) {\n\n\t\treturn sphere.center.equals( this.center ) && ( sphere.radius === this.radius );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nconst _vector$a = /*@__PURE__*/ new Vector3();\nconst _segCenter = /*@__PURE__*/ new Vector3();\nconst _segDir = /*@__PURE__*/ new Vector3();\nconst _diff = /*@__PURE__*/ new Vector3();\n\nconst _edge1 = /*@__PURE__*/ new Vector3();\nconst _edge2 = /*@__PURE__*/ new Vector3();\nconst _normal$1 = /*@__PURE__*/ new Vector3();\n\nclass Ray {\n\n\tconstructor( origin = new Vector3(), direction = new Vector3( 0, 0, - 1 ) ) {\n\n\t\tthis.origin = origin;\n\t\tthis.direction = direction;\n\n\t}\n\n\tset( origin, direction ) {\n\n\t\tthis.origin.copy( origin );\n\t\tthis.direction.copy( direction );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( ray ) {\n\n\t\tthis.origin.copy( ray.origin );\n\t\tthis.direction.copy( ray.direction );\n\n\t\treturn this;\n\n\t}\n\n\tat( t, target ) {\n\n\t\treturn target.copy( this.origin ).addScaledVector( this.direction, t );\n\n\t}\n\n\tlookAt( v ) {\n\n\t\tthis.direction.copy( v ).sub( this.origin ).normalize();\n\n\t\treturn this;\n\n\t}\n\n\trecast( t ) {\n\n\t\tthis.origin.copy( this.at( t, _vector$a ) );\n\n\t\treturn this;\n\n\t}\n\n\tclosestPointToPoint( point, target ) {\n\n\t\ttarget.subVectors( point, this.origin );\n\n\t\tconst directionDistance = target.dot( this.direction );\n\n\t\tif ( directionDistance < 0 ) {\n\n\t\t\treturn target.copy( this.origin );\n\n\t\t}\n\n\t\treturn target.copy( this.origin ).addScaledVector( this.direction, directionDistance );\n\n\t}\n\n\tdistanceToPoint( point ) {\n\n\t\treturn Math.sqrt( this.distanceSqToPoint( point ) );\n\n\t}\n\n\tdistanceSqToPoint( point ) {\n\n\t\tconst directionDistance = _vector$a.subVectors( point, this.origin ).dot( this.direction );\n\n\t\t// point behind the ray\n\n\t\tif ( directionDistance < 0 ) {\n\n\t\t\treturn this.origin.distanceToSquared( point );\n\n\t\t}\n\n\t\t_vector$a.copy( this.origin ).addScaledVector( this.direction, directionDistance );\n\n\t\treturn _vector$a.distanceToSquared( point );\n\n\t}\n\n\tdistanceSqToSegment( v0, v1, optionalPointOnRay, optionalPointOnSegment ) {\n\n\t\t// from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteDistRaySegment.h\n\t\t// It returns the min distance between the ray and the segment\n\t\t// defined by v0 and v1\n\t\t// It can also set two optional targets :\n\t\t// - The closest point on the ray\n\t\t// - The closest point on the segment\n\n\t\t_segCenter.copy( v0 ).add( v1 ).multiplyScalar( 0.5 );\n\t\t_segDir.copy( v1 ).sub( v0 ).normalize();\n\t\t_diff.copy( this.origin ).sub( _segCenter );\n\n\t\tconst segExtent = v0.distanceTo( v1 ) * 0.5;\n\t\tconst a01 = - this.direction.dot( _segDir );\n\t\tconst b0 = _diff.dot( this.direction );\n\t\tconst b1 = - _diff.dot( _segDir );\n\t\tconst c = _diff.lengthSq();\n\t\tconst det = Math.abs( 1 - a01 * a01 );\n\t\tlet s0, s1, sqrDist, extDet;\n\n\t\tif ( det > 0 ) {\n\n\t\t\t// The ray and segment are not parallel.\n\n\t\t\ts0 = a01 * b1 - b0;\n\t\t\ts1 = a01 * b0 - b1;\n\t\t\textDet = segExtent * det;\n\n\t\t\tif ( s0 >= 0 ) {\n\n\t\t\t\tif ( s1 >= - extDet ) {\n\n\t\t\t\t\tif ( s1 <= extDet ) {\n\n\t\t\t\t\t\t// region 0\n\t\t\t\t\t\t// Minimum at interior points of ray and segment.\n\n\t\t\t\t\t\tconst invDet = 1 / det;\n\t\t\t\t\t\ts0 *= invDet;\n\t\t\t\t\t\ts1 *= invDet;\n\t\t\t\t\t\tsqrDist = s0 * ( s0 + a01 * s1 + 2 * b0 ) + s1 * ( a01 * s0 + s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// region 1\n\n\t\t\t\t\t\ts1 = segExtent;\n\t\t\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// region 5\n\n\t\t\t\t\ts1 = - segExtent;\n\t\t\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( s1 <= - extDet ) {\n\n\t\t\t\t\t// region 4\n\n\t\t\t\t\ts0 = Math.max( 0, - ( - a01 * segExtent + b0 ) );\n\t\t\t\t\ts1 = ( s0 > 0 ) ? - segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t} else if ( s1 <= extDet ) {\n\n\t\t\t\t\t// region 3\n\n\t\t\t\t\ts0 = 0;\n\t\t\t\t\ts1 = Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\tsqrDist = s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// region 2\n\n\t\t\t\t\ts0 = Math.max( 0, - ( a01 * segExtent + b0 ) );\n\t\t\t\t\ts1 = ( s0 > 0 ) ? segExtent : Math.min( Math.max( - segExtent, - b1 ), segExtent );\n\t\t\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// Ray and segment are parallel.\n\n\t\t\ts1 = ( a01 > 0 ) ? - segExtent : segExtent;\n\t\t\ts0 = Math.max( 0, - ( a01 * s1 + b0 ) );\n\t\t\tsqrDist = - s0 * s0 + s1 * ( s1 + 2 * b1 ) + c;\n\n\t\t}\n\n\t\tif ( optionalPointOnRay ) {\n\n\t\t\toptionalPointOnRay.copy( this.origin ).addScaledVector( this.direction, s0 );\n\n\t\t}\n\n\t\tif ( optionalPointOnSegment ) {\n\n\t\t\toptionalPointOnSegment.copy( _segCenter ).addScaledVector( _segDir, s1 );\n\n\t\t}\n\n\t\treturn sqrDist;\n\n\t}\n\n\tintersectSphere( sphere, target ) {\n\n\t\t_vector$a.subVectors( sphere.center, this.origin );\n\t\tconst tca = _vector$a.dot( this.direction );\n\t\tconst d2 = _vector$a.dot( _vector$a ) - tca * tca;\n\t\tconst radius2 = sphere.radius * sphere.radius;\n\n\t\tif ( d2 > radius2 ) return null;\n\n\t\tconst thc = Math.sqrt( radius2 - d2 );\n\n\t\t// t0 = first intersect point - entrance on front of sphere\n\t\tconst t0 = tca - thc;\n\n\t\t// t1 = second intersect point - exit point on back of sphere\n\t\tconst t1 = tca + thc;\n\n\t\t// test to see if t1 is behind the ray - if so, return null\n\t\tif ( t1 < 0 ) return null;\n\n\t\t// test to see if t0 is behind the ray:\n\t\t// if it is, the ray is inside the sphere, so return the second exit point scaled by t1,\n\t\t// in order to always return an intersect point that is in front of the ray.\n\t\tif ( t0 < 0 ) return this.at( t1, target );\n\n\t\t// else t0 is in front of the ray, so return the first collision point scaled by t0\n\t\treturn this.at( t0, target );\n\n\t}\n\n\tintersectsSphere( sphere ) {\n\n\t\treturn this.distanceSqToPoint( sphere.center ) <= ( sphere.radius * sphere.radius );\n\n\t}\n\n\tdistanceToPlane( plane ) {\n\n\t\tconst denominator = plane.normal.dot( this.direction );\n\n\t\tif ( denominator === 0 ) {\n\n\t\t\t// line is coplanar, return origin\n\t\t\tif ( plane.distanceToPoint( this.origin ) === 0 ) {\n\n\t\t\t\treturn 0;\n\n\t\t\t}\n\n\t\t\t// Null is preferable to undefined since undefined means.... it is undefined\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst t = - ( this.origin.dot( plane.normal ) + plane.constant ) / denominator;\n\n\t\t// Return if the ray never intersects the plane\n\n\t\treturn t >= 0 ? t : null;\n\n\t}\n\n\tintersectPlane( plane, target ) {\n\n\t\tconst t = this.distanceToPlane( plane );\n\n\t\tif ( t === null ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\treturn this.at( t, target );\n\n\t}\n\n\tintersectsPlane( plane ) {\n\n\t\t// check if the ray lies on the plane first\n\n\t\tconst distToPoint = plane.distanceToPoint( this.origin );\n\n\t\tif ( distToPoint === 0 ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\tconst denominator = plane.normal.dot( this.direction );\n\n\t\tif ( denominator * distToPoint < 0 ) {\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\t// ray origin is behind the plane (and is pointing behind it)\n\n\t\treturn false;\n\n\t}\n\n\tintersectBox( box, target ) {\n\n\t\tlet tmin, tmax, tymin, tymax, tzmin, tzmax;\n\n\t\tconst invdirx = 1 / this.direction.x,\n\t\t\tinvdiry = 1 / this.direction.y,\n\t\t\tinvdirz = 1 / this.direction.z;\n\n\t\tconst origin = this.origin;\n\n\t\tif ( invdirx >= 0 ) {\n\n\t\t\ttmin = ( box.min.x - origin.x ) * invdirx;\n\t\t\ttmax = ( box.max.x - origin.x ) * invdirx;\n\n\t\t} else {\n\n\t\t\ttmin = ( box.max.x - origin.x ) * invdirx;\n\t\t\ttmax = ( box.min.x - origin.x ) * invdirx;\n\n\t\t}\n\n\t\tif ( invdiry >= 0 ) {\n\n\t\t\ttymin = ( box.min.y - origin.y ) * invdiry;\n\t\t\ttymax = ( box.max.y - origin.y ) * invdiry;\n\n\t\t} else {\n\n\t\t\ttymin = ( box.max.y - origin.y ) * invdiry;\n\t\t\ttymax = ( box.min.y - origin.y ) * invdiry;\n\n\t\t}\n\n\t\tif ( ( tmin > tymax ) || ( tymin > tmax ) ) return null;\n\n\t\tif ( tymin > tmin || isNaN( tmin ) ) tmin = tymin;\n\n\t\tif ( tymax < tmax || isNaN( tmax ) ) tmax = tymax;\n\n\t\tif ( invdirz >= 0 ) {\n\n\t\t\ttzmin = ( box.min.z - origin.z ) * invdirz;\n\t\t\ttzmax = ( box.max.z - origin.z ) * invdirz;\n\n\t\t} else {\n\n\t\t\ttzmin = ( box.max.z - origin.z ) * invdirz;\n\t\t\ttzmax = ( box.min.z - origin.z ) * invdirz;\n\n\t\t}\n\n\t\tif ( ( tmin > tzmax ) || ( tzmin > tmax ) ) return null;\n\n\t\tif ( tzmin > tmin || tmin !== tmin ) tmin = tzmin;\n\n\t\tif ( tzmax < tmax || tmax !== tmax ) tmax = tzmax;\n\n\t\t//return point closest to the ray (positive side)\n\n\t\tif ( tmax < 0 ) return null;\n\n\t\treturn this.at( tmin >= 0 ? tmin : tmax, target );\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\treturn this.intersectBox( box, _vector$a ) !== null;\n\n\t}\n\n\tintersectTriangle( a, b, c, backfaceCulling, target ) {\n\n\t\t// Compute the offset origin, edges, and normal.\n\n\t\t// from https://github.com/pmjoniak/GeometricTools/blob/master/GTEngine/Include/Mathematics/GteIntrRay3Triangle3.h\n\n\t\t_edge1.subVectors( b, a );\n\t\t_edge2.subVectors( c, a );\n\t\t_normal$1.crossVectors( _edge1, _edge2 );\n\n\t\t// Solve Q + t*D = b1*E1 + b2*E2 (Q = kDiff, D = ray direction,\n\t\t// E1 = kEdge1, E2 = kEdge2, N = Cross(E1,E2)) by\n\t\t// |Dot(D,N)|*b1 = sign(Dot(D,N))*Dot(D,Cross(Q,E2))\n\t\t// |Dot(D,N)|*b2 = sign(Dot(D,N))*Dot(D,Cross(E1,Q))\n\t\t// |Dot(D,N)|*t = -sign(Dot(D,N))*Dot(Q,N)\n\t\tlet DdN = this.direction.dot( _normal$1 );\n\t\tlet sign;\n\n\t\tif ( DdN > 0 ) {\n\n\t\t\tif ( backfaceCulling ) return null;\n\t\t\tsign = 1;\n\n\t\t} else if ( DdN < 0 ) {\n\n\t\t\tsign = - 1;\n\t\t\tDdN = - DdN;\n\n\t\t} else {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t_diff.subVectors( this.origin, a );\n\t\tconst DdQxE2 = sign * this.direction.dot( _edge2.crossVectors( _diff, _edge2 ) );\n\n\t\t// b1 < 0, no intersection\n\t\tif ( DdQxE2 < 0 ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst DdE1xQ = sign * this.direction.dot( _edge1.cross( _diff ) );\n\n\t\t// b2 < 0, no intersection\n\t\tif ( DdE1xQ < 0 ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// b1+b2 > 1, no intersection\n\t\tif ( DdQxE2 + DdE1xQ > DdN ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// Line intersects triangle, check if ray does.\n\t\tconst QdN = - sign * _diff.dot( _normal$1 );\n\n\t\t// t < 0, no intersection\n\t\tif ( QdN < 0 ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// Ray intersects triangle.\n\t\treturn this.at( QdN / DdN, target );\n\n\t}\n\n\tapplyMatrix4( matrix4 ) {\n\n\t\tthis.origin.applyMatrix4( matrix4 );\n\t\tthis.direction.transformDirection( matrix4 );\n\n\t\treturn this;\n\n\t}\n\n\tequals( ray ) {\n\n\t\treturn ray.origin.equals( this.origin ) && ray.direction.equals( this.direction );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nclass Matrix4 {\n\n\tconstructor( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {\n\n\t\tMatrix4.prototype.isMatrix4 = true;\n\n\t\tthis.elements = [\n\n\t\t\t1, 0, 0, 0,\n\t\t\t0, 1, 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t];\n\n\t\tif ( n11 !== undefined ) {\n\n\t\t\tthis.set( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 );\n\n\t\t}\n\n\t}\n\n\tset( n11, n12, n13, n14, n21, n22, n23, n24, n31, n32, n33, n34, n41, n42, n43, n44 ) {\n\n\t\tconst te = this.elements;\n\n\t\tte[ 0 ] = n11; te[ 4 ] = n12; te[ 8 ] = n13; te[ 12 ] = n14;\n\t\tte[ 1 ] = n21; te[ 5 ] = n22; te[ 9 ] = n23; te[ 13 ] = n24;\n\t\tte[ 2 ] = n31; te[ 6 ] = n32; te[ 10 ] = n33; te[ 14 ] = n34;\n\t\tte[ 3 ] = n41; te[ 7 ] = n42; te[ 11 ] = n43; te[ 15 ] = n44;\n\n\t\treturn this;\n\n\t}\n\n\tidentity() {\n\n\t\tthis.set(\n\n\t\t\t1, 0, 0, 0,\n\t\t\t0, 1, 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new Matrix4().fromArray( this.elements );\n\n\t}\n\n\tcopy( m ) {\n\n\t\tconst te = this.elements;\n\t\tconst me = m.elements;\n\n\t\tte[ 0 ] = me[ 0 ]; te[ 1 ] = me[ 1 ]; te[ 2 ] = me[ 2 ]; te[ 3 ] = me[ 3 ];\n\t\tte[ 4 ] = me[ 4 ]; te[ 5 ] = me[ 5 ]; te[ 6 ] = me[ 6 ]; te[ 7 ] = me[ 7 ];\n\t\tte[ 8 ] = me[ 8 ]; te[ 9 ] = me[ 9 ]; te[ 10 ] = me[ 10 ]; te[ 11 ] = me[ 11 ];\n\t\tte[ 12 ] = me[ 12 ]; te[ 13 ] = me[ 13 ]; te[ 14 ] = me[ 14 ]; te[ 15 ] = me[ 15 ];\n\n\t\treturn this;\n\n\t}\n\n\tcopyPosition( m ) {\n\n\t\tconst te = this.elements, me = m.elements;\n\n\t\tte[ 12 ] = me[ 12 ];\n\t\tte[ 13 ] = me[ 13 ];\n\t\tte[ 14 ] = me[ 14 ];\n\n\t\treturn this;\n\n\t}\n\n\tsetFromMatrix3( m ) {\n\n\t\tconst me = m.elements;\n\n\t\tthis.set(\n\n\t\t\tme[ 0 ], me[ 3 ], me[ 6 ], 0,\n\t\t\tme[ 1 ], me[ 4 ], me[ 7 ], 0,\n\t\t\tme[ 2 ], me[ 5 ], me[ 8 ], 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\textractBasis( xAxis, yAxis, zAxis ) {\n\n\t\txAxis.setFromMatrixColumn( this, 0 );\n\t\tyAxis.setFromMatrixColumn( this, 1 );\n\t\tzAxis.setFromMatrixColumn( this, 2 );\n\n\t\treturn this;\n\n\t}\n\n\tmakeBasis( xAxis, yAxis, zAxis ) {\n\n\t\tthis.set(\n\t\t\txAxis.x, yAxis.x, zAxis.x, 0,\n\t\t\txAxis.y, yAxis.y, zAxis.y, 0,\n\t\t\txAxis.z, yAxis.z, zAxis.z, 0,\n\t\t\t0, 0, 0, 1\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\textractRotation( m ) {\n\n\t\t// this method does not support reflection matrices\n\n\t\tconst te = this.elements;\n\t\tconst me = m.elements;\n\n\t\tconst scaleX = 1 / _v1$5.setFromMatrixColumn( m, 0 ).length();\n\t\tconst scaleY = 1 / _v1$5.setFromMatrixColumn( m, 1 ).length();\n\t\tconst scaleZ = 1 / _v1$5.setFromMatrixColumn( m, 2 ).length();\n\n\t\tte[ 0 ] = me[ 0 ] * scaleX;\n\t\tte[ 1 ] = me[ 1 ] * scaleX;\n\t\tte[ 2 ] = me[ 2 ] * scaleX;\n\t\tte[ 3 ] = 0;\n\n\t\tte[ 4 ] = me[ 4 ] * scaleY;\n\t\tte[ 5 ] = me[ 5 ] * scaleY;\n\t\tte[ 6 ] = me[ 6 ] * scaleY;\n\t\tte[ 7 ] = 0;\n\n\t\tte[ 8 ] = me[ 8 ] * scaleZ;\n\t\tte[ 9 ] = me[ 9 ] * scaleZ;\n\t\tte[ 10 ] = me[ 10 ] * scaleZ;\n\t\tte[ 11 ] = 0;\n\n\t\tte[ 12 ] = 0;\n\t\tte[ 13 ] = 0;\n\t\tte[ 14 ] = 0;\n\t\tte[ 15 ] = 1;\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationFromEuler( euler ) {\n\n\t\tconst te = this.elements;\n\n\t\tconst x = euler.x, y = euler.y, z = euler.z;\n\t\tconst a = Math.cos( x ), b = Math.sin( x );\n\t\tconst c = Math.cos( y ), d = Math.sin( y );\n\t\tconst e = Math.cos( z ), f = Math.sin( z );\n\n\t\tif ( euler.order === 'XYZ' ) {\n\n\t\t\tconst ae = a * e, af = a * f, be = b * e, bf = b * f;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = - c * f;\n\t\t\tte[ 8 ] = d;\n\n\t\t\tte[ 1 ] = af + be * d;\n\t\t\tte[ 5 ] = ae - bf * d;\n\t\t\tte[ 9 ] = - b * c;\n\n\t\t\tte[ 2 ] = bf - ae * d;\n\t\t\tte[ 6 ] = be + af * d;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'YXZ' ) {\n\n\t\t\tconst ce = c * e, cf = c * f, de = d * e, df = d * f;\n\n\t\t\tte[ 0 ] = ce + df * b;\n\t\t\tte[ 4 ] = de * b - cf;\n\t\t\tte[ 8 ] = a * d;\n\n\t\t\tte[ 1 ] = a * f;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = - b;\n\n\t\t\tte[ 2 ] = cf * b - de;\n\t\t\tte[ 6 ] = df + ce * b;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'ZXY' ) {\n\n\t\t\tconst ce = c * e, cf = c * f, de = d * e, df = d * f;\n\n\t\t\tte[ 0 ] = ce - df * b;\n\t\t\tte[ 4 ] = - a * f;\n\t\t\tte[ 8 ] = de + cf * b;\n\n\t\t\tte[ 1 ] = cf + de * b;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = df - ce * b;\n\n\t\t\tte[ 2 ] = - a * d;\n\t\t\tte[ 6 ] = b;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'ZYX' ) {\n\n\t\t\tconst ae = a * e, af = a * f, be = b * e, bf = b * f;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = be * d - af;\n\t\t\tte[ 8 ] = ae * d + bf;\n\n\t\t\tte[ 1 ] = c * f;\n\t\t\tte[ 5 ] = bf * d + ae;\n\t\t\tte[ 9 ] = af * d - be;\n\n\t\t\tte[ 2 ] = - d;\n\t\t\tte[ 6 ] = b * c;\n\t\t\tte[ 10 ] = a * c;\n\n\t\t} else if ( euler.order === 'YZX' ) {\n\n\t\t\tconst ac = a * c, ad = a * d, bc = b * c, bd = b * d;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = bd - ac * f;\n\t\t\tte[ 8 ] = bc * f + ad;\n\n\t\t\tte[ 1 ] = f;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = - b * e;\n\n\t\t\tte[ 2 ] = - d * e;\n\t\t\tte[ 6 ] = ad * f + bc;\n\t\t\tte[ 10 ] = ac - bd * f;\n\n\t\t} else if ( euler.order === 'XZY' ) {\n\n\t\t\tconst ac = a * c, ad = a * d, bc = b * c, bd = b * d;\n\n\t\t\tte[ 0 ] = c * e;\n\t\t\tte[ 4 ] = - f;\n\t\t\tte[ 8 ] = d * e;\n\n\t\t\tte[ 1 ] = ac * f + bd;\n\t\t\tte[ 5 ] = a * e;\n\t\t\tte[ 9 ] = ad * f - bc;\n\n\t\t\tte[ 2 ] = bc * f - ad;\n\t\t\tte[ 6 ] = b * e;\n\t\t\tte[ 10 ] = bd * f + ac;\n\n\t\t}\n\n\t\t// bottom row\n\t\tte[ 3 ] = 0;\n\t\tte[ 7 ] = 0;\n\t\tte[ 11 ] = 0;\n\n\t\t// last column\n\t\tte[ 12 ] = 0;\n\t\tte[ 13 ] = 0;\n\t\tte[ 14 ] = 0;\n\t\tte[ 15 ] = 1;\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationFromQuaternion( q ) {\n\n\t\treturn this.compose( _zero, q, _one );\n\n\t}\n\n\tlookAt( eye, target, up ) {\n\n\t\tconst te = this.elements;\n\n\t\t_z.subVectors( eye, target );\n\n\t\tif ( _z.lengthSq() === 0 ) {\n\n\t\t\t// eye and target are in the same position\n\n\t\t\t_z.z = 1;\n\n\t\t}\n\n\t\t_z.normalize();\n\t\t_x.crossVectors( up, _z );\n\n\t\tif ( _x.lengthSq() === 0 ) {\n\n\t\t\t// up and z are parallel\n\n\t\t\tif ( Math.abs( up.z ) === 1 ) {\n\n\t\t\t\t_z.x += 0.0001;\n\n\t\t\t} else {\n\n\t\t\t\t_z.z += 0.0001;\n\n\t\t\t}\n\n\t\t\t_z.normalize();\n\t\t\t_x.crossVectors( up, _z );\n\n\t\t}\n\n\t\t_x.normalize();\n\t\t_y.crossVectors( _z, _x );\n\n\t\tte[ 0 ] = _x.x; te[ 4 ] = _y.x; te[ 8 ] = _z.x;\n\t\tte[ 1 ] = _x.y; te[ 5 ] = _y.y; te[ 9 ] = _z.y;\n\t\tte[ 2 ] = _x.z; te[ 6 ] = _y.z; te[ 10 ] = _z.z;\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( m ) {\n\n\t\treturn this.multiplyMatrices( this, m );\n\n\t}\n\n\tpremultiply( m ) {\n\n\t\treturn this.multiplyMatrices( m, this );\n\n\t}\n\n\tmultiplyMatrices( a, b ) {\n\n\t\tconst ae = a.elements;\n\t\tconst be = b.elements;\n\t\tconst te = this.elements;\n\n\t\tconst a11 = ae[ 0 ], a12 = ae[ 4 ], a13 = ae[ 8 ], a14 = ae[ 12 ];\n\t\tconst a21 = ae[ 1 ], a22 = ae[ 5 ], a23 = ae[ 9 ], a24 = ae[ 13 ];\n\t\tconst a31 = ae[ 2 ], a32 = ae[ 6 ], a33 = ae[ 10 ], a34 = ae[ 14 ];\n\t\tconst a41 = ae[ 3 ], a42 = ae[ 7 ], a43 = ae[ 11 ], a44 = ae[ 15 ];\n\n\t\tconst b11 = be[ 0 ], b12 = be[ 4 ], b13 = be[ 8 ], b14 = be[ 12 ];\n\t\tconst b21 = be[ 1 ], b22 = be[ 5 ], b23 = be[ 9 ], b24 = be[ 13 ];\n\t\tconst b31 = be[ 2 ], b32 = be[ 6 ], b33 = be[ 10 ], b34 = be[ 14 ];\n\t\tconst b41 = be[ 3 ], b42 = be[ 7 ], b43 = be[ 11 ], b44 = be[ 15 ];\n\n\t\tte[ 0 ] = a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41;\n\t\tte[ 4 ] = a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42;\n\t\tte[ 8 ] = a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43;\n\t\tte[ 12 ] = a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44;\n\n\t\tte[ 1 ] = a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41;\n\t\tte[ 5 ] = a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42;\n\t\tte[ 9 ] = a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43;\n\t\tte[ 13 ] = a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44;\n\n\t\tte[ 2 ] = a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41;\n\t\tte[ 6 ] = a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42;\n\t\tte[ 10 ] = a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43;\n\t\tte[ 14 ] = a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44;\n\n\t\tte[ 3 ] = a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41;\n\t\tte[ 7 ] = a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42;\n\t\tte[ 11 ] = a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43;\n\t\tte[ 15 ] = a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( s ) {\n\n\t\tconst te = this.elements;\n\n\t\tte[ 0 ] *= s; te[ 4 ] *= s; te[ 8 ] *= s; te[ 12 ] *= s;\n\t\tte[ 1 ] *= s; te[ 5 ] *= s; te[ 9 ] *= s; te[ 13 ] *= s;\n\t\tte[ 2 ] *= s; te[ 6 ] *= s; te[ 10 ] *= s; te[ 14 ] *= s;\n\t\tte[ 3 ] *= s; te[ 7 ] *= s; te[ 11 ] *= s; te[ 15 ] *= s;\n\n\t\treturn this;\n\n\t}\n\n\tdeterminant() {\n\n\t\tconst te = this.elements;\n\n\t\tconst n11 = te[ 0 ], n12 = te[ 4 ], n13 = te[ 8 ], n14 = te[ 12 ];\n\t\tconst n21 = te[ 1 ], n22 = te[ 5 ], n23 = te[ 9 ], n24 = te[ 13 ];\n\t\tconst n31 = te[ 2 ], n32 = te[ 6 ], n33 = te[ 10 ], n34 = te[ 14 ];\n\t\tconst n41 = te[ 3 ], n42 = te[ 7 ], n43 = te[ 11 ], n44 = te[ 15 ];\n\n\t\t//TODO: make this more efficient\n\t\t//( based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm )\n\n\t\treturn (\n\t\t\tn41 * (\n\t\t\t\t+ n14 * n23 * n32\n\t\t\t\t - n13 * n24 * n32\n\t\t\t\t - n14 * n22 * n33\n\t\t\t\t + n12 * n24 * n33\n\t\t\t\t + n13 * n22 * n34\n\t\t\t\t - n12 * n23 * n34\n\t\t\t) +\n\t\t\tn42 * (\n\t\t\t\t+ n11 * n23 * n34\n\t\t\t\t - n11 * n24 * n33\n\t\t\t\t + n14 * n21 * n33\n\t\t\t\t - n13 * n21 * n34\n\t\t\t\t + n13 * n24 * n31\n\t\t\t\t - n14 * n23 * n31\n\t\t\t) +\n\t\t\tn43 * (\n\t\t\t\t+ n11 * n24 * n32\n\t\t\t\t - n11 * n22 * n34\n\t\t\t\t - n14 * n21 * n32\n\t\t\t\t + n12 * n21 * n34\n\t\t\t\t + n14 * n22 * n31\n\t\t\t\t - n12 * n24 * n31\n\t\t\t) +\n\t\t\tn44 * (\n\t\t\t\t- n13 * n22 * n31\n\t\t\t\t - n11 * n23 * n32\n\t\t\t\t + n11 * n22 * n33\n\t\t\t\t + n13 * n21 * n32\n\t\t\t\t - n12 * n21 * n33\n\t\t\t\t + n12 * n23 * n31\n\t\t\t)\n\n\t\t);\n\n\t}\n\n\ttranspose() {\n\n\t\tconst te = this.elements;\n\t\tlet tmp;\n\n\t\ttmp = te[ 1 ]; te[ 1 ] = te[ 4 ]; te[ 4 ] = tmp;\n\t\ttmp = te[ 2 ]; te[ 2 ] = te[ 8 ]; te[ 8 ] = tmp;\n\t\ttmp = te[ 6 ]; te[ 6 ] = te[ 9 ]; te[ 9 ] = tmp;\n\n\t\ttmp = te[ 3 ]; te[ 3 ] = te[ 12 ]; te[ 12 ] = tmp;\n\t\ttmp = te[ 7 ]; te[ 7 ] = te[ 13 ]; te[ 13 ] = tmp;\n\t\ttmp = te[ 11 ]; te[ 11 ] = te[ 14 ]; te[ 14 ] = tmp;\n\n\t\treturn this;\n\n\t}\n\n\tsetPosition( x, y, z ) {\n\n\t\tconst te = this.elements;\n\n\t\tif ( x.isVector3 ) {\n\n\t\t\tte[ 12 ] = x.x;\n\t\t\tte[ 13 ] = x.y;\n\t\t\tte[ 14 ] = x.z;\n\n\t\t} else {\n\n\t\t\tte[ 12 ] = x;\n\t\t\tte[ 13 ] = y;\n\t\t\tte[ 14 ] = z;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tinvert() {\n\n\t\t// based on http://www.euclideanspace.com/maths/algebra/matrix/functions/inverse/fourD/index.htm\n\t\tconst te = this.elements,\n\n\t\t\tn11 = te[ 0 ], n21 = te[ 1 ], n31 = te[ 2 ], n41 = te[ 3 ],\n\t\t\tn12 = te[ 4 ], n22 = te[ 5 ], n32 = te[ 6 ], n42 = te[ 7 ],\n\t\t\tn13 = te[ 8 ], n23 = te[ 9 ], n33 = te[ 10 ], n43 = te[ 11 ],\n\t\t\tn14 = te[ 12 ], n24 = te[ 13 ], n34 = te[ 14 ], n44 = te[ 15 ],\n\n\t\t\tt11 = n23 * n34 * n42 - n24 * n33 * n42 + n24 * n32 * n43 - n22 * n34 * n43 - n23 * n32 * n44 + n22 * n33 * n44,\n\t\t\tt12 = n14 * n33 * n42 - n13 * n34 * n42 - n14 * n32 * n43 + n12 * n34 * n43 + n13 * n32 * n44 - n12 * n33 * n44,\n\t\t\tt13 = n13 * n24 * n42 - n14 * n23 * n42 + n14 * n22 * n43 - n12 * n24 * n43 - n13 * n22 * n44 + n12 * n23 * n44,\n\t\t\tt14 = n14 * n23 * n32 - n13 * n24 * n32 - n14 * n22 * n33 + n12 * n24 * n33 + n13 * n22 * n34 - n12 * n23 * n34;\n\n\t\tconst det = n11 * t11 + n21 * t12 + n31 * t13 + n41 * t14;\n\n\t\tif ( det === 0 ) return this.set( 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 );\n\n\t\tconst detInv = 1 / det;\n\n\t\tte[ 0 ] = t11 * detInv;\n\t\tte[ 1 ] = ( n24 * n33 * n41 - n23 * n34 * n41 - n24 * n31 * n43 + n21 * n34 * n43 + n23 * n31 * n44 - n21 * n33 * n44 ) * detInv;\n\t\tte[ 2 ] = ( n22 * n34 * n41 - n24 * n32 * n41 + n24 * n31 * n42 - n21 * n34 * n42 - n22 * n31 * n44 + n21 * n32 * n44 ) * detInv;\n\t\tte[ 3 ] = ( n23 * n32 * n41 - n22 * n33 * n41 - n23 * n31 * n42 + n21 * n33 * n42 + n22 * n31 * n43 - n21 * n32 * n43 ) * detInv;\n\n\t\tte[ 4 ] = t12 * detInv;\n\t\tte[ 5 ] = ( n13 * n34 * n41 - n14 * n33 * n41 + n14 * n31 * n43 - n11 * n34 * n43 - n13 * n31 * n44 + n11 * n33 * n44 ) * detInv;\n\t\tte[ 6 ] = ( n14 * n32 * n41 - n12 * n34 * n41 - n14 * n31 * n42 + n11 * n34 * n42 + n12 * n31 * n44 - n11 * n32 * n44 ) * detInv;\n\t\tte[ 7 ] = ( n12 * n33 * n41 - n13 * n32 * n41 + n13 * n31 * n42 - n11 * n33 * n42 - n12 * n31 * n43 + n11 * n32 * n43 ) * detInv;\n\n\t\tte[ 8 ] = t13 * detInv;\n\t\tte[ 9 ] = ( n14 * n23 * n41 - n13 * n24 * n41 - n14 * n21 * n43 + n11 * n24 * n43 + n13 * n21 * n44 - n11 * n23 * n44 ) * detInv;\n\t\tte[ 10 ] = ( n12 * n24 * n41 - n14 * n22 * n41 + n14 * n21 * n42 - n11 * n24 * n42 - n12 * n21 * n44 + n11 * n22 * n44 ) * detInv;\n\t\tte[ 11 ] = ( n13 * n22 * n41 - n12 * n23 * n41 - n13 * n21 * n42 + n11 * n23 * n42 + n12 * n21 * n43 - n11 * n22 * n43 ) * detInv;\n\n\t\tte[ 12 ] = t14 * detInv;\n\t\tte[ 13 ] = ( n13 * n24 * n31 - n14 * n23 * n31 + n14 * n21 * n33 - n11 * n24 * n33 - n13 * n21 * n34 + n11 * n23 * n34 ) * detInv;\n\t\tte[ 14 ] = ( n14 * n22 * n31 - n12 * n24 * n31 - n14 * n21 * n32 + n11 * n24 * n32 + n12 * n21 * n34 - n11 * n22 * n34 ) * detInv;\n\t\tte[ 15 ] = ( n12 * n23 * n31 - n13 * n22 * n31 + n13 * n21 * n32 - n11 * n23 * n32 - n12 * n21 * n33 + n11 * n22 * n33 ) * detInv;\n\n\t\treturn this;\n\n\t}\n\n\tscale( v ) {\n\n\t\tconst te = this.elements;\n\t\tconst x = v.x, y = v.y, z = v.z;\n\n\t\tte[ 0 ] *= x; te[ 4 ] *= y; te[ 8 ] *= z;\n\t\tte[ 1 ] *= x; te[ 5 ] *= y; te[ 9 ] *= z;\n\t\tte[ 2 ] *= x; te[ 6 ] *= y; te[ 10 ] *= z;\n\t\tte[ 3 ] *= x; te[ 7 ] *= y; te[ 11 ] *= z;\n\n\t\treturn this;\n\n\t}\n\n\tgetMaxScaleOnAxis() {\n\n\t\tconst te = this.elements;\n\n\t\tconst scaleXSq = te[ 0 ] * te[ 0 ] + te[ 1 ] * te[ 1 ] + te[ 2 ] * te[ 2 ];\n\t\tconst scaleYSq = te[ 4 ] * te[ 4 ] + te[ 5 ] * te[ 5 ] + te[ 6 ] * te[ 6 ];\n\t\tconst scaleZSq = te[ 8 ] * te[ 8 ] + te[ 9 ] * te[ 9 ] + te[ 10 ] * te[ 10 ];\n\n\t\treturn Math.sqrt( Math.max( scaleXSq, scaleYSq, scaleZSq ) );\n\n\t}\n\n\tmakeTranslation( x, y, z ) {\n\n\t\tif ( x.isVector3 ) {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0, 0, x.x,\n\t\t\t\t0, 1, 0, x.y,\n\t\t\t\t0, 0, 1, x.z,\n\t\t\t\t0, 0, 0, 1\n\n\t\t\t);\n\n\t\t} else {\n\n\t\t\tthis.set(\n\n\t\t\t\t1, 0, 0, x,\n\t\t\t\t0, 1, 0, y,\n\t\t\t\t0, 0, 1, z,\n\t\t\t\t0, 0, 0, 1\n\n\t\t\t);\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationX( theta ) {\n\n\t\tconst c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\tthis.set(\n\n\t\t\t1, 0, 0, 0,\n\t\t\t0, c, - s, 0,\n\t\t\t0, s, c, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationY( theta ) {\n\n\t\tconst c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\tthis.set(\n\n\t\t\t c, 0, s, 0,\n\t\t\t 0, 1, 0, 0,\n\t\t\t- s, 0, c, 0,\n\t\t\t 0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationZ( theta ) {\n\n\t\tconst c = Math.cos( theta ), s = Math.sin( theta );\n\n\t\tthis.set(\n\n\t\t\tc, - s, 0, 0,\n\t\t\ts, c, 0, 0,\n\t\t\t0, 0, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeRotationAxis( axis, angle ) {\n\n\t\t// Based on http://www.gamedev.net/reference/articles/article1199.asp\n\n\t\tconst c = Math.cos( angle );\n\t\tconst s = Math.sin( angle );\n\t\tconst t = 1 - c;\n\t\tconst x = axis.x, y = axis.y, z = axis.z;\n\t\tconst tx = t * x, ty = t * y;\n\n\t\tthis.set(\n\n\t\t\ttx * x + c, tx * y - s * z, tx * z + s * y, 0,\n\t\t\ttx * y + s * z, ty * y + c, ty * z - s * x, 0,\n\t\t\ttx * z - s * y, ty * z + s * x, t * z * z + c, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeScale( x, y, z ) {\n\n\t\tthis.set(\n\n\t\t\tx, 0, 0, 0,\n\t\t\t0, y, 0, 0,\n\t\t\t0, 0, z, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tmakeShear( xy, xz, yx, yz, zx, zy ) {\n\n\t\tthis.set(\n\n\t\t\t1, yx, zx, 0,\n\t\t\txy, 1, zy, 0,\n\t\t\txz, yz, 1, 0,\n\t\t\t0, 0, 0, 1\n\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tcompose( position, quaternion, scale ) {\n\n\t\tconst te = this.elements;\n\n\t\tconst x = quaternion._x, y = quaternion._y, z = quaternion._z, w = quaternion._w;\n\t\tconst x2 = x + x,\ty2 = y + y, z2 = z + z;\n\t\tconst xx = x * x2, xy = x * y2, xz = x * z2;\n\t\tconst yy = y * y2, yz = y * z2, zz = z * z2;\n\t\tconst wx = w * x2, wy = w * y2, wz = w * z2;\n\n\t\tconst sx = scale.x, sy = scale.y, sz = scale.z;\n\n\t\tte[ 0 ] = ( 1 - ( yy + zz ) ) * sx;\n\t\tte[ 1 ] = ( xy + wz ) * sx;\n\t\tte[ 2 ] = ( xz - wy ) * sx;\n\t\tte[ 3 ] = 0;\n\n\t\tte[ 4 ] = ( xy - wz ) * sy;\n\t\tte[ 5 ] = ( 1 - ( xx + zz ) ) * sy;\n\t\tte[ 6 ] = ( yz + wx ) * sy;\n\t\tte[ 7 ] = 0;\n\n\t\tte[ 8 ] = ( xz + wy ) * sz;\n\t\tte[ 9 ] = ( yz - wx ) * sz;\n\t\tte[ 10 ] = ( 1 - ( xx + yy ) ) * sz;\n\t\tte[ 11 ] = 0;\n\n\t\tte[ 12 ] = position.x;\n\t\tte[ 13 ] = position.y;\n\t\tte[ 14 ] = position.z;\n\t\tte[ 15 ] = 1;\n\n\t\treturn this;\n\n\t}\n\n\tdecompose( position, quaternion, scale ) {\n\n\t\tconst te = this.elements;\n\n\t\tlet sx = _v1$5.set( te[ 0 ], te[ 1 ], te[ 2 ] ).length();\n\t\tconst sy = _v1$5.set( te[ 4 ], te[ 5 ], te[ 6 ] ).length();\n\t\tconst sz = _v1$5.set( te[ 8 ], te[ 9 ], te[ 10 ] ).length();\n\n\t\t// if determine is negative, we need to invert one scale\n\t\tconst det = this.determinant();\n\t\tif ( det < 0 ) sx = - sx;\n\n\t\tposition.x = te[ 12 ];\n\t\tposition.y = te[ 13 ];\n\t\tposition.z = te[ 14 ];\n\n\t\t// scale the rotation part\n\t\t_m1$4.copy( this );\n\n\t\tconst invSX = 1 / sx;\n\t\tconst invSY = 1 / sy;\n\t\tconst invSZ = 1 / sz;\n\n\t\t_m1$4.elements[ 0 ] *= invSX;\n\t\t_m1$4.elements[ 1 ] *= invSX;\n\t\t_m1$4.elements[ 2 ] *= invSX;\n\n\t\t_m1$4.elements[ 4 ] *= invSY;\n\t\t_m1$4.elements[ 5 ] *= invSY;\n\t\t_m1$4.elements[ 6 ] *= invSY;\n\n\t\t_m1$4.elements[ 8 ] *= invSZ;\n\t\t_m1$4.elements[ 9 ] *= invSZ;\n\t\t_m1$4.elements[ 10 ] *= invSZ;\n\n\t\tquaternion.setFromRotationMatrix( _m1$4 );\n\n\t\tscale.x = sx;\n\t\tscale.y = sy;\n\t\tscale.z = sz;\n\n\t\treturn this;\n\n\t}\n\n\tmakePerspective( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) {\n\n\t\tconst te = this.elements;\n\t\tconst x = 2 * near / ( right - left );\n\t\tconst y = 2 * near / ( top - bottom );\n\n\t\tconst a = ( right + left ) / ( right - left );\n\t\tconst b = ( top + bottom ) / ( top - bottom );\n\n\t\tlet c, d;\n\n\t\tif ( coordinateSystem === WebGLCoordinateSystem ) {\n\n\t\t\tc = - ( far + near ) / ( far - near );\n\t\t\td = ( - 2 * far * near ) / ( far - near );\n\n\t\t} else if ( coordinateSystem === WebGPUCoordinateSystem ) {\n\n\t\t\tc = - far / ( far - near );\n\t\t\td = ( - far * near ) / ( far - near );\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'THREE.Matrix4.makePerspective(): Invalid coordinate system: ' + coordinateSystem );\n\n\t\t}\n\n\t\tte[ 0 ] = x;\tte[ 4 ] = 0;\tte[ 8 ] = a; \tte[ 12 ] = 0;\n\t\tte[ 1 ] = 0;\tte[ 5 ] = y;\tte[ 9 ] = b; \tte[ 13 ] = 0;\n\t\tte[ 2 ] = 0;\tte[ 6 ] = 0;\tte[ 10 ] = c; \tte[ 14 ] = d;\n\t\tte[ 3 ] = 0;\tte[ 7 ] = 0;\tte[ 11 ] = - 1;\tte[ 15 ] = 0;\n\n\t\treturn this;\n\n\t}\n\n\tmakeOrthographic( left, right, top, bottom, near, far, coordinateSystem = WebGLCoordinateSystem ) {\n\n\t\tconst te = this.elements;\n\t\tconst w = 1.0 / ( right - left );\n\t\tconst h = 1.0 / ( top - bottom );\n\t\tconst p = 1.0 / ( far - near );\n\n\t\tconst x = ( right + left ) * w;\n\t\tconst y = ( top + bottom ) * h;\n\n\t\tlet z, zInv;\n\n\t\tif ( coordinateSystem === WebGLCoordinateSystem ) {\n\n\t\t\tz = ( far + near ) * p;\n\t\t\tzInv = - 2 * p;\n\n\t\t} else if ( coordinateSystem === WebGPUCoordinateSystem ) {\n\n\t\t\tz = near * p;\n\t\t\tzInv = - 1 * p;\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'THREE.Matrix4.makeOrthographic(): Invalid coordinate system: ' + coordinateSystem );\n\n\t\t}\n\n\t\tte[ 0 ] = 2 * w;\tte[ 4 ] = 0;\t\tte[ 8 ] = 0; \t\tte[ 12 ] = - x;\n\t\tte[ 1 ] = 0; \t\tte[ 5 ] = 2 * h;\tte[ 9 ] = 0; \t\tte[ 13 ] = - y;\n\t\tte[ 2 ] = 0; \t\tte[ 6 ] = 0;\t\tte[ 10 ] = zInv;\tte[ 14 ] = - z;\n\t\tte[ 3 ] = 0; \t\tte[ 7 ] = 0;\t\tte[ 11 ] = 0;\t\tte[ 15 ] = 1;\n\n\t\treturn this;\n\n\t}\n\n\tequals( matrix ) {\n\n\t\tconst te = this.elements;\n\t\tconst me = matrix.elements;\n\n\t\tfor ( let i = 0; i < 16; i ++ ) {\n\n\t\t\tif ( te[ i ] !== me[ i ] ) return false;\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tfor ( let i = 0; i < 16; i ++ ) {\n\n\t\t\tthis.elements[ i ] = array[ i + offset ];\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tconst te = this.elements;\n\n\t\tarray[ offset ] = te[ 0 ];\n\t\tarray[ offset + 1 ] = te[ 1 ];\n\t\tarray[ offset + 2 ] = te[ 2 ];\n\t\tarray[ offset + 3 ] = te[ 3 ];\n\n\t\tarray[ offset + 4 ] = te[ 4 ];\n\t\tarray[ offset + 5 ] = te[ 5 ];\n\t\tarray[ offset + 6 ] = te[ 6 ];\n\t\tarray[ offset + 7 ] = te[ 7 ];\n\n\t\tarray[ offset + 8 ] = te[ 8 ];\n\t\tarray[ offset + 9 ] = te[ 9 ];\n\t\tarray[ offset + 10 ] = te[ 10 ];\n\t\tarray[ offset + 11 ] = te[ 11 ];\n\n\t\tarray[ offset + 12 ] = te[ 12 ];\n\t\tarray[ offset + 13 ] = te[ 13 ];\n\t\tarray[ offset + 14 ] = te[ 14 ];\n\t\tarray[ offset + 15 ] = te[ 15 ];\n\n\t\treturn array;\n\n\t}\n\n}\n\nconst _v1$5 = /*@__PURE__*/ new Vector3();\nconst _m1$4 = /*@__PURE__*/ new Matrix4();\nconst _zero = /*@__PURE__*/ new Vector3( 0, 0, 0 );\nconst _one = /*@__PURE__*/ new Vector3( 1, 1, 1 );\nconst _x = /*@__PURE__*/ new Vector3();\nconst _y = /*@__PURE__*/ new Vector3();\nconst _z = /*@__PURE__*/ new Vector3();\n\nconst _matrix$2 = /*@__PURE__*/ new Matrix4();\nconst _quaternion$3 = /*@__PURE__*/ new Quaternion();\n\nclass Euler {\n\n\tconstructor( x = 0, y = 0, z = 0, order = Euler.DEFAULT_ORDER ) {\n\n\t\tthis.isEuler = true;\n\n\t\tthis._x = x;\n\t\tthis._y = y;\n\t\tthis._z = z;\n\t\tthis._order = order;\n\n\t}\n\n\tget x() {\n\n\t\treturn this._x;\n\n\t}\n\n\tset x( value ) {\n\n\t\tthis._x = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget y() {\n\n\t\treturn this._y;\n\n\t}\n\n\tset y( value ) {\n\n\t\tthis._y = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget z() {\n\n\t\treturn this._z;\n\n\t}\n\n\tset z( value ) {\n\n\t\tthis._z = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tget order() {\n\n\t\treturn this._order;\n\n\t}\n\n\tset order( value ) {\n\n\t\tthis._order = value;\n\t\tthis._onChangeCallback();\n\n\t}\n\n\tset( x, y, z, order = this._order ) {\n\n\t\tthis._x = x;\n\t\tthis._y = y;\n\t\tthis._z = z;\n\t\tthis._order = order;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this._x, this._y, this._z, this._order );\n\n\t}\n\n\tcopy( euler ) {\n\n\t\tthis._x = euler._x;\n\t\tthis._y = euler._y;\n\t\tthis._z = euler._z;\n\t\tthis._order = euler._order;\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromRotationMatrix( m, order = this._order, update = true ) {\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tconst te = m.elements;\n\t\tconst m11 = te[ 0 ], m12 = te[ 4 ], m13 = te[ 8 ];\n\t\tconst m21 = te[ 1 ], m22 = te[ 5 ], m23 = te[ 9 ];\n\t\tconst m31 = te[ 2 ], m32 = te[ 6 ], m33 = te[ 10 ];\n\n\t\tswitch ( order ) {\n\n\t\t\tcase 'XYZ':\n\n\t\t\t\tthis._y = Math.asin( clamp( m13, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m13 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( - m23, m33 );\n\t\t\t\t\tthis._z = Math.atan2( - m12, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = Math.atan2( m32, m22 );\n\t\t\t\t\tthis._z = 0;\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'YXZ':\n\n\t\t\t\tthis._x = Math.asin( - clamp( m23, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m23 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._y = Math.atan2( m13, m33 );\n\t\t\t\t\tthis._z = Math.atan2( m21, m22 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._y = Math.atan2( - m31, m11 );\n\t\t\t\t\tthis._z = 0;\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'ZXY':\n\n\t\t\t\tthis._x = Math.asin( clamp( m32, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m32 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._y = Math.atan2( - m31, m33 );\n\t\t\t\t\tthis._z = Math.atan2( - m12, m22 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._y = 0;\n\t\t\t\t\tthis._z = Math.atan2( m21, m11 );\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'ZYX':\n\n\t\t\t\tthis._y = Math.asin( - clamp( m31, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m31 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( m32, m33 );\n\t\t\t\t\tthis._z = Math.atan2( m21, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = 0;\n\t\t\t\t\tthis._z = Math.atan2( - m12, m22 );\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'YZX':\n\n\t\t\t\tthis._z = Math.asin( clamp( m21, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m21 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( - m23, m22 );\n\t\t\t\t\tthis._y = Math.atan2( - m31, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = 0;\n\t\t\t\t\tthis._y = Math.atan2( m13, m33 );\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'XZY':\n\n\t\t\t\tthis._z = Math.asin( - clamp( m12, - 1, 1 ) );\n\n\t\t\t\tif ( Math.abs( m12 ) < 0.9999999 ) {\n\n\t\t\t\t\tthis._x = Math.atan2( m32, m22 );\n\t\t\t\t\tthis._y = Math.atan2( m13, m11 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis._x = Math.atan2( - m23, m33 );\n\t\t\t\t\tthis._y = 0;\n\n\t\t\t\t}\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\n\t\t\t\tconsole.warn( 'THREE.Euler: .setFromRotationMatrix() encountered an unknown order: ' + order );\n\n\t\t}\n\n\t\tthis._order = order;\n\n\t\tif ( update === true ) this._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\tsetFromQuaternion( q, order, update ) {\n\n\t\t_matrix$2.makeRotationFromQuaternion( q );\n\n\t\treturn this.setFromRotationMatrix( _matrix$2, order, update );\n\n\t}\n\n\tsetFromVector3( v, order = this._order ) {\n\n\t\treturn this.set( v.x, v.y, v.z, order );\n\n\t}\n\n\treorder( newOrder ) {\n\n\t\t// WARNING: this discards revolution information -bhouston\n\n\t\t_quaternion$3.setFromEuler( this );\n\n\t\treturn this.setFromQuaternion( _quaternion$3, newOrder );\n\n\t}\n\n\tequals( euler ) {\n\n\t\treturn ( euler._x === this._x ) && ( euler._y === this._y ) && ( euler._z === this._z ) && ( euler._order === this._order );\n\n\t}\n\n\tfromArray( array ) {\n\n\t\tthis._x = array[ 0 ];\n\t\tthis._y = array[ 1 ];\n\t\tthis._z = array[ 2 ];\n\t\tif ( array[ 3 ] !== undefined ) this._order = array[ 3 ];\n\n\t\tthis._onChangeCallback();\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this._x;\n\t\tarray[ offset + 1 ] = this._y;\n\t\tarray[ offset + 2 ] = this._z;\n\t\tarray[ offset + 3 ] = this._order;\n\n\t\treturn array;\n\n\t}\n\n\t_onChange( callback ) {\n\n\t\tthis._onChangeCallback = callback;\n\n\t\treturn this;\n\n\t}\n\n\t_onChangeCallback() {}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this._x;\n\t\tyield this._y;\n\t\tyield this._z;\n\t\tyield this._order;\n\n\t}\n\n}\n\nEuler.DEFAULT_ORDER = 'XYZ';\n\nclass Layers {\n\n\tconstructor() {\n\n\t\tthis.mask = 1 | 0;\n\n\t}\n\n\tset( channel ) {\n\n\t\tthis.mask = ( 1 << channel | 0 ) >>> 0;\n\n\t}\n\n\tenable( channel ) {\n\n\t\tthis.mask |= 1 << channel | 0;\n\n\t}\n\n\tenableAll() {\n\n\t\tthis.mask = 0xffffffff | 0;\n\n\t}\n\n\ttoggle( channel ) {\n\n\t\tthis.mask ^= 1 << channel | 0;\n\n\t}\n\n\tdisable( channel ) {\n\n\t\tthis.mask &= ~ ( 1 << channel | 0 );\n\n\t}\n\n\tdisableAll() {\n\n\t\tthis.mask = 0;\n\n\t}\n\n\ttest( layers ) {\n\n\t\treturn ( this.mask & layers.mask ) !== 0;\n\n\t}\n\n\tisEnabled( channel ) {\n\n\t\treturn ( this.mask & ( 1 << channel | 0 ) ) !== 0;\n\n\t}\n\n}\n\nlet _object3DId = 0;\n\nconst _v1$4 = /*@__PURE__*/ new Vector3();\nconst _q1 = /*@__PURE__*/ new Quaternion();\nconst _m1$3 = /*@__PURE__*/ new Matrix4();\nconst _target = /*@__PURE__*/ new Vector3();\n\nconst _position$3 = /*@__PURE__*/ new Vector3();\nconst _scale$2 = /*@__PURE__*/ new Vector3();\nconst _quaternion$2 = /*@__PURE__*/ new Quaternion();\n\nconst _xAxis = /*@__PURE__*/ new Vector3( 1, 0, 0 );\nconst _yAxis = /*@__PURE__*/ new Vector3( 0, 1, 0 );\nconst _zAxis = /*@__PURE__*/ new Vector3( 0, 0, 1 );\n\nconst _addedEvent = { type: 'added' };\nconst _removedEvent = { type: 'removed' };\n\nconst _childaddedEvent = { type: 'childadded', child: null };\nconst _childremovedEvent = { type: 'childremoved', child: null };\n\nclass Object3D extends EventDispatcher {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isObject3D = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _object3DId ++ } );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.name = '';\n\t\tthis.type = 'Object3D';\n\n\t\tthis.parent = null;\n\t\tthis.children = [];\n\n\t\tthis.up = Object3D.DEFAULT_UP.clone();\n\n\t\tconst position = new Vector3();\n\t\tconst rotation = new Euler();\n\t\tconst quaternion = new Quaternion();\n\t\tconst scale = new Vector3( 1, 1, 1 );\n\n\t\tfunction onRotationChange() {\n\n\t\t\tquaternion.setFromEuler( rotation, false );\n\n\t\t}\n\n\t\tfunction onQuaternionChange() {\n\n\t\t\trotation.setFromQuaternion( quaternion, undefined, false );\n\n\t\t}\n\n\t\trotation._onChange( onRotationChange );\n\t\tquaternion._onChange( onQuaternionChange );\n\n\t\tObject.defineProperties( this, {\n\t\t\tposition: {\n\t\t\t\tconfigurable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: position\n\t\t\t},\n\t\t\trotation: {\n\t\t\t\tconfigurable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: rotation\n\t\t\t},\n\t\t\tquaternion: {\n\t\t\t\tconfigurable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: quaternion\n\t\t\t},\n\t\t\tscale: {\n\t\t\t\tconfigurable: true,\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: scale\n\t\t\t},\n\t\t\tmodelViewMatrix: {\n\t\t\t\tvalue: new Matrix4()\n\t\t\t},\n\t\t\tnormalMatrix: {\n\t\t\t\tvalue: new Matrix3()\n\t\t\t}\n\t\t} );\n\n\t\tthis.matrix = new Matrix4();\n\t\tthis.matrixWorld = new Matrix4();\n\n\t\tthis.matrixAutoUpdate = Object3D.DEFAULT_MATRIX_AUTO_UPDATE;\n\n\t\tthis.matrixWorldAutoUpdate = Object3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE; // checked by the renderer\n\t\tthis.matrixWorldNeedsUpdate = false;\n\n\t\tthis.layers = new Layers();\n\t\tthis.visible = true;\n\n\t\tthis.castShadow = false;\n\t\tthis.receiveShadow = false;\n\n\t\tthis.frustumCulled = true;\n\t\tthis.renderOrder = 0;\n\n\t\tthis.animations = [];\n\n\t\tthis.userData = {};\n\n\t}\n\n\tonBeforeShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}\n\n\tonAfterShadow( /* renderer, object, camera, shadowCamera, geometry, depthMaterial, group */ ) {}\n\n\tonBeforeRender( /* renderer, scene, camera, geometry, material, group */ ) {}\n\n\tonAfterRender( /* renderer, scene, camera, geometry, material, group */ ) {}\n\n\tapplyMatrix4( matrix ) {\n\n\t\tif ( this.matrixAutoUpdate ) this.updateMatrix();\n\n\t\tthis.matrix.premultiply( matrix );\n\n\t\tthis.matrix.decompose( this.position, this.quaternion, this.scale );\n\n\t}\n\n\tapplyQuaternion( q ) {\n\n\t\tthis.quaternion.premultiply( q );\n\n\t\treturn this;\n\n\t}\n\n\tsetRotationFromAxisAngle( axis, angle ) {\n\n\t\t// assumes axis is normalized\n\n\t\tthis.quaternion.setFromAxisAngle( axis, angle );\n\n\t}\n\n\tsetRotationFromEuler( euler ) {\n\n\t\tthis.quaternion.setFromEuler( euler, true );\n\n\t}\n\n\tsetRotationFromMatrix( m ) {\n\n\t\t// assumes the upper 3x3 of m is a pure rotation matrix (i.e, unscaled)\n\n\t\tthis.quaternion.setFromRotationMatrix( m );\n\n\t}\n\n\tsetRotationFromQuaternion( q ) {\n\n\t\t// assumes q is normalized\n\n\t\tthis.quaternion.copy( q );\n\n\t}\n\n\trotateOnAxis( axis, angle ) {\n\n\t\t// rotate object on axis in object space\n\t\t// axis is assumed to be normalized\n\n\t\t_q1.setFromAxisAngle( axis, angle );\n\n\t\tthis.quaternion.multiply( _q1 );\n\n\t\treturn this;\n\n\t}\n\n\trotateOnWorldAxis( axis, angle ) {\n\n\t\t// rotate object on axis in world space\n\t\t// axis is assumed to be normalized\n\t\t// method assumes no rotated parent\n\n\t\t_q1.setFromAxisAngle( axis, angle );\n\n\t\tthis.quaternion.premultiply( _q1 );\n\n\t\treturn this;\n\n\t}\n\n\trotateX( angle ) {\n\n\t\treturn this.rotateOnAxis( _xAxis, angle );\n\n\t}\n\n\trotateY( angle ) {\n\n\t\treturn this.rotateOnAxis( _yAxis, angle );\n\n\t}\n\n\trotateZ( angle ) {\n\n\t\treturn this.rotateOnAxis( _zAxis, angle );\n\n\t}\n\n\ttranslateOnAxis( axis, distance ) {\n\n\t\t// translate object by distance along axis in object space\n\t\t// axis is assumed to be normalized\n\n\t\t_v1$4.copy( axis ).applyQuaternion( this.quaternion );\n\n\t\tthis.position.add( _v1$4.multiplyScalar( distance ) );\n\n\t\treturn this;\n\n\t}\n\n\ttranslateX( distance ) {\n\n\t\treturn this.translateOnAxis( _xAxis, distance );\n\n\t}\n\n\ttranslateY( distance ) {\n\n\t\treturn this.translateOnAxis( _yAxis, distance );\n\n\t}\n\n\ttranslateZ( distance ) {\n\n\t\treturn this.translateOnAxis( _zAxis, distance );\n\n\t}\n\n\tlocalToWorld( vector ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\treturn vector.applyMatrix4( this.matrixWorld );\n\n\t}\n\n\tworldToLocal( vector ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\treturn vector.applyMatrix4( _m1$3.copy( this.matrixWorld ).invert() );\n\n\t}\n\n\tlookAt( x, y, z ) {\n\n\t\t// This method does not support objects having non-uniformly-scaled parent(s)\n\n\t\tif ( x.isVector3 ) {\n\n\t\t\t_target.copy( x );\n\n\t\t} else {\n\n\t\t\t_target.set( x, y, z );\n\n\t\t}\n\n\t\tconst parent = this.parent;\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\t_position$3.setFromMatrixPosition( this.matrixWorld );\n\n\t\tif ( this.isCamera || this.isLight ) {\n\n\t\t\t_m1$3.lookAt( _position$3, _target, this.up );\n\n\t\t} else {\n\n\t\t\t_m1$3.lookAt( _target, _position$3, this.up );\n\n\t\t}\n\n\t\tthis.quaternion.setFromRotationMatrix( _m1$3 );\n\n\t\tif ( parent ) {\n\n\t\t\t_m1$3.extractRotation( parent.matrixWorld );\n\t\t\t_q1.setFromRotationMatrix( _m1$3 );\n\t\t\tthis.quaternion.premultiply( _q1.invert() );\n\n\t\t}\n\n\t}\n\n\tadd( object ) {\n\n\t\tif ( arguments.length > 1 ) {\n\n\t\t\tfor ( let i = 0; i < arguments.length; i ++ ) {\n\n\t\t\t\tthis.add( arguments[ i ] );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( object === this ) {\n\n\t\t\tconsole.error( 'THREE.Object3D.add: object can\\'t be added as a child of itself.', object );\n\t\t\treturn this;\n\n\t\t}\n\n\t\tif ( object && object.isObject3D ) {\n\n\t\t\tobject.removeFromParent();\n\t\t\tobject.parent = this;\n\t\t\tthis.children.push( object );\n\n\t\t\tobject.dispatchEvent( _addedEvent );\n\n\t\t\t_childaddedEvent.child = object;\n\t\t\tthis.dispatchEvent( _childaddedEvent );\n\t\t\t_childaddedEvent.child = null;\n\n\t\t} else {\n\n\t\t\tconsole.error( 'THREE.Object3D.add: object not an instance of THREE.Object3D.', object );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tremove( object ) {\n\n\t\tif ( arguments.length > 1 ) {\n\n\t\t\tfor ( let i = 0; i < arguments.length; i ++ ) {\n\n\t\t\t\tthis.remove( arguments[ i ] );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tconst index = this.children.indexOf( object );\n\n\t\tif ( index !== - 1 ) {\n\n\t\t\tobject.parent = null;\n\t\t\tthis.children.splice( index, 1 );\n\n\t\t\tobject.dispatchEvent( _removedEvent );\n\n\t\t\t_childremovedEvent.child = object;\n\t\t\tthis.dispatchEvent( _childremovedEvent );\n\t\t\t_childremovedEvent.child = null;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tremoveFromParent() {\n\n\t\tconst parent = this.parent;\n\n\t\tif ( parent !== null ) {\n\n\t\t\tparent.remove( this );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclear() {\n\n\t\treturn this.remove( ... this.children );\n\n\t}\n\n\tattach( object ) {\n\n\t\t// adds object as a child of this, while maintaining the object's world transform\n\n\t\t// Note: This method does not support scene graphs having non-uniformly-scaled nodes(s)\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\t_m1$3.copy( this.matrixWorld ).invert();\n\n\t\tif ( object.parent !== null ) {\n\n\t\t\tobject.parent.updateWorldMatrix( true, false );\n\n\t\t\t_m1$3.multiply( object.parent.matrixWorld );\n\n\t\t}\n\n\t\tobject.applyMatrix4( _m1$3 );\n\n\t\tobject.removeFromParent();\n\t\tobject.parent = this;\n\t\tthis.children.push( object );\n\n\t\tobject.updateWorldMatrix( false, true );\n\n\t\tobject.dispatchEvent( _addedEvent );\n\n\t\t_childaddedEvent.child = object;\n\t\tthis.dispatchEvent( _childaddedEvent );\n\t\t_childaddedEvent.child = null;\n\n\t\treturn this;\n\n\t}\n\n\tgetObjectById( id ) {\n\n\t\treturn this.getObjectByProperty( 'id', id );\n\n\t}\n\n\tgetObjectByName( name ) {\n\n\t\treturn this.getObjectByProperty( 'name', name );\n\n\t}\n\n\tgetObjectByProperty( name, value ) {\n\n\t\tif ( this[ name ] === value ) return this;\n\n\t\tfor ( let i = 0, l = this.children.length; i < l; i ++ ) {\n\n\t\t\tconst child = this.children[ i ];\n\t\t\tconst object = child.getObjectByProperty( name, value );\n\n\t\t\tif ( object !== undefined ) {\n\n\t\t\t\treturn object;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn undefined;\n\n\t}\n\n\tgetObjectsByProperty( name, value, result = [] ) {\n\n\t\tif ( this[ name ] === value ) result.push( this );\n\n\t\tconst children = this.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tchildren[ i ].getObjectsByProperty( name, value, result );\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\tgetWorldPosition( target ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\treturn target.setFromMatrixPosition( this.matrixWorld );\n\n\t}\n\n\tgetWorldQuaternion( target ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\tthis.matrixWorld.decompose( _position$3, target, _scale$2 );\n\n\t\treturn target;\n\n\t}\n\n\tgetWorldScale( target ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\tthis.matrixWorld.decompose( _position$3, _quaternion$2, target );\n\n\t\treturn target;\n\n\t}\n\n\tgetWorldDirection( target ) {\n\n\t\tthis.updateWorldMatrix( true, false );\n\n\t\tconst e = this.matrixWorld.elements;\n\n\t\treturn target.set( e[ 8 ], e[ 9 ], e[ 10 ] ).normalize();\n\n\t}\n\n\traycast( /* raycaster, intersects */ ) {}\n\n\ttraverse( callback ) {\n\n\t\tcallback( this );\n\n\t\tconst children = this.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tchildren[ i ].traverse( callback );\n\n\t\t}\n\n\t}\n\n\ttraverseVisible( callback ) {\n\n\t\tif ( this.visible === false ) return;\n\n\t\tcallback( this );\n\n\t\tconst children = this.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tchildren[ i ].traverseVisible( callback );\n\n\t\t}\n\n\t}\n\n\ttraverseAncestors( callback ) {\n\n\t\tconst parent = this.parent;\n\n\t\tif ( parent !== null ) {\n\n\t\t\tcallback( parent );\n\n\t\t\tparent.traverseAncestors( callback );\n\n\t\t}\n\n\t}\n\n\tupdateMatrix() {\n\n\t\tthis.matrix.compose( this.position, this.quaternion, this.scale );\n\n\t\tthis.matrixWorldNeedsUpdate = true;\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tif ( this.matrixAutoUpdate ) this.updateMatrix();\n\n\t\tif ( this.matrixWorldNeedsUpdate || force ) {\n\n\t\t\tif ( this.matrixWorldAutoUpdate === true ) {\n\n\t\t\t\tif ( this.parent === null ) {\n\n\t\t\t\t\tthis.matrixWorld.copy( this.matrix );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.matrixWorldNeedsUpdate = false;\n\n\t\t\tforce = true;\n\n\t\t}\n\n\t\t// make sure descendants are updated if required\n\n\t\tconst children = this.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tconst child = children[ i ];\n\n\t\t\tchild.updateMatrixWorld( force );\n\n\t\t}\n\n\t}\n\n\tupdateWorldMatrix( updateParents, updateChildren ) {\n\n\t\tconst parent = this.parent;\n\n\t\tif ( updateParents === true && parent !== null ) {\n\n\t\t\tparent.updateWorldMatrix( true, false );\n\n\t\t}\n\n\t\tif ( this.matrixAutoUpdate ) this.updateMatrix();\n\n\t\tif ( this.matrixWorldAutoUpdate === true ) {\n\n\t\t\tif ( this.parent === null ) {\n\n\t\t\t\tthis.matrixWorld.copy( this.matrix );\n\n\t\t\t} else {\n\n\t\t\t\tthis.matrixWorld.multiplyMatrices( this.parent.matrixWorld, this.matrix );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// make sure descendants are updated\n\n\t\tif ( updateChildren === true ) {\n\n\t\t\tconst children = this.children;\n\n\t\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\t\tconst child = children[ i ];\n\n\t\t\t\tchild.updateWorldMatrix( false, true );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\t// meta is a string when called from JSON.stringify\n\t\tconst isRootObject = ( meta === undefined || typeof meta === 'string' );\n\n\t\tconst output = {};\n\n\t\t// meta is a hash used to collect geometries, materials.\n\t\t// not providing it implies that this is the root object\n\t\t// being serialized.\n\t\tif ( isRootObject ) {\n\n\t\t\t// initialize meta obj\n\t\t\tmeta = {\n\t\t\t\tgeometries: {},\n\t\t\t\tmaterials: {},\n\t\t\t\ttextures: {},\n\t\t\t\timages: {},\n\t\t\t\tshapes: {},\n\t\t\t\tskeletons: {},\n\t\t\t\tanimations: {},\n\t\t\t\tnodes: {}\n\t\t\t};\n\n\t\t\toutput.metadata = {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'Object',\n\t\t\t\tgenerator: 'Object3D.toJSON'\n\t\t\t};\n\n\t\t}\n\n\t\t// standard Object3D serialization\n\n\t\tconst object = {};\n\n\t\tobject.uuid = this.uuid;\n\t\tobject.type = this.type;\n\n\t\tif ( this.name !== '' ) object.name = this.name;\n\t\tif ( this.castShadow === true ) object.castShadow = true;\n\t\tif ( this.receiveShadow === true ) object.receiveShadow = true;\n\t\tif ( this.visible === false ) object.visible = false;\n\t\tif ( this.frustumCulled === false ) object.frustumCulled = false;\n\t\tif ( this.renderOrder !== 0 ) object.renderOrder = this.renderOrder;\n\t\tif ( Object.keys( this.userData ).length > 0 ) object.userData = this.userData;\n\n\t\tobject.layers = this.layers.mask;\n\t\tobject.matrix = this.matrix.toArray();\n\t\tobject.up = this.up.toArray();\n\n\t\tif ( this.matrixAutoUpdate === false ) object.matrixAutoUpdate = false;\n\n\t\t// object specific properties\n\n\t\tif ( this.isInstancedMesh ) {\n\n\t\t\tobject.type = 'InstancedMesh';\n\t\t\tobject.count = this.count;\n\t\t\tobject.instanceMatrix = this.instanceMatrix.toJSON();\n\t\t\tif ( this.instanceColor !== null ) object.instanceColor = this.instanceColor.toJSON();\n\n\t\t}\n\n\t\tif ( this.isBatchedMesh ) {\n\n\t\t\tobject.type = 'BatchedMesh';\n\t\t\tobject.perObjectFrustumCulled = this.perObjectFrustumCulled;\n\t\t\tobject.sortObjects = this.sortObjects;\n\n\t\t\tobject.drawRanges = this._drawRanges;\n\t\t\tobject.reservedRanges = this._reservedRanges;\n\n\t\t\tobject.visibility = this._visibility;\n\t\t\tobject.active = this._active;\n\t\t\tobject.bounds = this._bounds.map( bound => ( {\n\t\t\t\tboxInitialized: bound.boxInitialized,\n\t\t\t\tboxMin: bound.box.min.toArray(),\n\t\t\t\tboxMax: bound.box.max.toArray(),\n\n\t\t\t\tsphereInitialized: bound.sphereInitialized,\n\t\t\t\tsphereRadius: bound.sphere.radius,\n\t\t\t\tsphereCenter: bound.sphere.center.toArray()\n\t\t\t} ) );\n\n\t\t\tobject.maxInstanceCount = this._maxInstanceCount;\n\t\t\tobject.maxVertexCount = this._maxVertexCount;\n\t\t\tobject.maxIndexCount = this._maxIndexCount;\n\n\t\t\tobject.geometryInitialized = this._geometryInitialized;\n\t\t\tobject.geometryCount = this._geometryCount;\n\n\t\t\tobject.matricesTexture = this._matricesTexture.toJSON( meta );\n\n\t\t\tif ( this._colorsTexture !== null ) object.colorsTexture = this._colorsTexture.toJSON( meta );\n\n\t\t\tif ( this.boundingSphere !== null ) {\n\n\t\t\t\tobject.boundingSphere = {\n\t\t\t\t\tcenter: object.boundingSphere.center.toArray(),\n\t\t\t\t\tradius: object.boundingSphere.radius\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t\tif ( this.boundingBox !== null ) {\n\n\t\t\t\tobject.boundingBox = {\n\t\t\t\t\tmin: object.boundingBox.min.toArray(),\n\t\t\t\t\tmax: object.boundingBox.max.toArray()\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tfunction serialize( library, element ) {\n\n\t\t\tif ( library[ element.uuid ] === undefined ) {\n\n\t\t\t\tlibrary[ element.uuid ] = element.toJSON( meta );\n\n\t\t\t}\n\n\t\t\treturn element.uuid;\n\n\t\t}\n\n\t\tif ( this.isScene ) {\n\n\t\t\tif ( this.background ) {\n\n\t\t\t\tif ( this.background.isColor ) {\n\n\t\t\t\t\tobject.background = this.background.toJSON();\n\n\t\t\t\t} else if ( this.background.isTexture ) {\n\n\t\t\t\t\tobject.background = this.background.toJSON( meta ).uuid;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.environment && this.environment.isTexture && this.environment.isRenderTargetTexture !== true ) {\n\n\t\t\t\tobject.environment = this.environment.toJSON( meta ).uuid;\n\n\t\t\t}\n\n\t\t} else if ( this.isMesh || this.isLine || this.isPoints ) {\n\n\t\t\tobject.geometry = serialize( meta.geometries, this.geometry );\n\n\t\t\tconst parameters = this.geometry.parameters;\n\n\t\t\tif ( parameters !== undefined && parameters.shapes !== undefined ) {\n\n\t\t\t\tconst shapes = parameters.shapes;\n\n\t\t\t\tif ( Array.isArray( shapes ) ) {\n\n\t\t\t\t\tfor ( let i = 0, l = shapes.length; i < l; i ++ ) {\n\n\t\t\t\t\t\tconst shape = shapes[ i ];\n\n\t\t\t\t\t\tserialize( meta.shapes, shape );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tserialize( meta.shapes, shapes );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.isSkinnedMesh ) {\n\n\t\t\tobject.bindMode = this.bindMode;\n\t\t\tobject.bindMatrix = this.bindMatrix.toArray();\n\n\t\t\tif ( this.skeleton !== undefined ) {\n\n\t\t\t\tserialize( meta.skeletons, this.skeleton );\n\n\t\t\t\tobject.skeleton = this.skeleton.uuid;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.material !== undefined ) {\n\n\t\t\tif ( Array.isArray( this.material ) ) {\n\n\t\t\t\tconst uuids = [];\n\n\t\t\t\tfor ( let i = 0, l = this.material.length; i < l; i ++ ) {\n\n\t\t\t\t\tuuids.push( serialize( meta.materials, this.material[ i ] ) );\n\n\t\t\t\t}\n\n\t\t\t\tobject.material = uuids;\n\n\t\t\t} else {\n\n\t\t\t\tobject.material = serialize( meta.materials, this.material );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tif ( this.children.length > 0 ) {\n\n\t\t\tobject.children = [];\n\n\t\t\tfor ( let i = 0; i < this.children.length; i ++ ) {\n\n\t\t\t\tobject.children.push( this.children[ i ].toJSON( meta ).object );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tif ( this.animations.length > 0 ) {\n\n\t\t\tobject.animations = [];\n\n\t\t\tfor ( let i = 0; i < this.animations.length; i ++ ) {\n\n\t\t\t\tconst animation = this.animations[ i ];\n\n\t\t\t\tobject.animations.push( serialize( meta.animations, animation ) );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( isRootObject ) {\n\n\t\t\tconst geometries = extractFromCache( meta.geometries );\n\t\t\tconst materials = extractFromCache( meta.materials );\n\t\t\tconst textures = extractFromCache( meta.textures );\n\t\t\tconst images = extractFromCache( meta.images );\n\t\t\tconst shapes = extractFromCache( meta.shapes );\n\t\t\tconst skeletons = extractFromCache( meta.skeletons );\n\t\t\tconst animations = extractFromCache( meta.animations );\n\t\t\tconst nodes = extractFromCache( meta.nodes );\n\n\t\t\tif ( geometries.length > 0 ) output.geometries = geometries;\n\t\t\tif ( materials.length > 0 ) output.materials = materials;\n\t\t\tif ( textures.length > 0 ) output.textures = textures;\n\t\t\tif ( images.length > 0 ) output.images = images;\n\t\t\tif ( shapes.length > 0 ) output.shapes = shapes;\n\t\t\tif ( skeletons.length > 0 ) output.skeletons = skeletons;\n\t\t\tif ( animations.length > 0 ) output.animations = animations;\n\t\t\tif ( nodes.length > 0 ) output.nodes = nodes;\n\n\t\t}\n\n\t\toutput.object = object;\n\n\t\treturn output;\n\n\t\t// extract data from the cache hash\n\t\t// remove metadata on each item\n\t\t// and return as array\n\t\tfunction extractFromCache( cache ) {\n\n\t\t\tconst values = [];\n\t\t\tfor ( const key in cache ) {\n\n\t\t\t\tconst data = cache[ key ];\n\t\t\t\tdelete data.metadata;\n\t\t\t\tvalues.push( data );\n\n\t\t\t}\n\n\t\t\treturn values;\n\n\t\t}\n\n\t}\n\n\tclone( recursive ) {\n\n\t\treturn new this.constructor().copy( this, recursive );\n\n\t}\n\n\tcopy( source, recursive = true ) {\n\n\t\tthis.name = source.name;\n\n\t\tthis.up.copy( source.up );\n\n\t\tthis.position.copy( source.position );\n\t\tthis.rotation.order = source.rotation.order;\n\t\tthis.quaternion.copy( source.quaternion );\n\t\tthis.scale.copy( source.scale );\n\n\t\tthis.matrix.copy( source.matrix );\n\t\tthis.matrixWorld.copy( source.matrixWorld );\n\n\t\tthis.matrixAutoUpdate = source.matrixAutoUpdate;\n\n\t\tthis.matrixWorldAutoUpdate = source.matrixWorldAutoUpdate;\n\t\tthis.matrixWorldNeedsUpdate = source.matrixWorldNeedsUpdate;\n\n\t\tthis.layers.mask = source.layers.mask;\n\t\tthis.visible = source.visible;\n\n\t\tthis.castShadow = source.castShadow;\n\t\tthis.receiveShadow = source.receiveShadow;\n\n\t\tthis.frustumCulled = source.frustumCulled;\n\t\tthis.renderOrder = source.renderOrder;\n\n\t\tthis.animations = source.animations.slice();\n\n\t\tthis.userData = JSON.parse( JSON.stringify( source.userData ) );\n\n\t\tif ( recursive === true ) {\n\n\t\t\tfor ( let i = 0; i < source.children.length; i ++ ) {\n\n\t\t\t\tconst child = source.children[ i ];\n\t\t\t\tthis.add( child.clone() );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\nObject3D.DEFAULT_UP = /*@__PURE__*/ new Vector3( 0, 1, 0 );\nObject3D.DEFAULT_MATRIX_AUTO_UPDATE = true;\nObject3D.DEFAULT_MATRIX_WORLD_AUTO_UPDATE = true;\n\nconst _v0$2 = /*@__PURE__*/ new Vector3();\nconst _v1$3 = /*@__PURE__*/ new Vector3();\nconst _v2$2 = /*@__PURE__*/ new Vector3();\nconst _v3$2 = /*@__PURE__*/ new Vector3();\n\nconst _vab = /*@__PURE__*/ new Vector3();\nconst _vac = /*@__PURE__*/ new Vector3();\nconst _vbc = /*@__PURE__*/ new Vector3();\nconst _vap = /*@__PURE__*/ new Vector3();\nconst _vbp = /*@__PURE__*/ new Vector3();\nconst _vcp = /*@__PURE__*/ new Vector3();\n\nclass Triangle {\n\n\tconstructor( a = new Vector3(), b = new Vector3(), c = new Vector3() ) {\n\n\t\tthis.a = a;\n\t\tthis.b = b;\n\t\tthis.c = c;\n\n\t}\n\n\tstatic getNormal( a, b, c, target ) {\n\n\t\ttarget.subVectors( c, b );\n\t\t_v0$2.subVectors( a, b );\n\t\ttarget.cross( _v0$2 );\n\n\t\tconst targetLengthSq = target.lengthSq();\n\t\tif ( targetLengthSq > 0 ) {\n\n\t\t\treturn target.multiplyScalar( 1 / Math.sqrt( targetLengthSq ) );\n\n\t\t}\n\n\t\treturn target.set( 0, 0, 0 );\n\n\t}\n\n\t// static/instance method to calculate barycentric coordinates\n\t// based on: http://www.blackpawn.com/texts/pointinpoly/default.html\n\tstatic getBarycoord( point, a, b, c, target ) {\n\n\t\t_v0$2.subVectors( c, a );\n\t\t_v1$3.subVectors( b, a );\n\t\t_v2$2.subVectors( point, a );\n\n\t\tconst dot00 = _v0$2.dot( _v0$2 );\n\t\tconst dot01 = _v0$2.dot( _v1$3 );\n\t\tconst dot02 = _v0$2.dot( _v2$2 );\n\t\tconst dot11 = _v1$3.dot( _v1$3 );\n\t\tconst dot12 = _v1$3.dot( _v2$2 );\n\n\t\tconst denom = ( dot00 * dot11 - dot01 * dot01 );\n\n\t\t// collinear or singular triangle\n\t\tif ( denom === 0 ) {\n\n\t\t\ttarget.set( 0, 0, 0 );\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst invDenom = 1 / denom;\n\t\tconst u = ( dot11 * dot02 - dot01 * dot12 ) * invDenom;\n\t\tconst v = ( dot00 * dot12 - dot01 * dot02 ) * invDenom;\n\n\t\t// barycentric coordinates must always sum to 1\n\t\treturn target.set( 1 - u - v, v, u );\n\n\t}\n\n\tstatic containsPoint( point, a, b, c ) {\n\n\t\t// if the triangle is degenerate then we can't contain a point\n\t\tif ( this.getBarycoord( point, a, b, c, _v3$2 ) === null ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\treturn ( _v3$2.x >= 0 ) && ( _v3$2.y >= 0 ) && ( ( _v3$2.x + _v3$2.y ) <= 1 );\n\n\t}\n\n\tstatic getInterpolation( point, p1, p2, p3, v1, v2, v3, target ) {\n\n\t\tif ( this.getBarycoord( point, p1, p2, p3, _v3$2 ) === null ) {\n\n\t\t\ttarget.x = 0;\n\t\t\ttarget.y = 0;\n\t\t\tif ( 'z' in target ) target.z = 0;\n\t\t\tif ( 'w' in target ) target.w = 0;\n\t\t\treturn null;\n\n\t\t}\n\n\t\ttarget.setScalar( 0 );\n\t\ttarget.addScaledVector( v1, _v3$2.x );\n\t\ttarget.addScaledVector( v2, _v3$2.y );\n\t\ttarget.addScaledVector( v3, _v3$2.z );\n\n\t\treturn target;\n\n\t}\n\n\tstatic isFrontFacing( a, b, c, direction ) {\n\n\t\t_v0$2.subVectors( c, b );\n\t\t_v1$3.subVectors( a, b );\n\n\t\t// strictly front facing\n\t\treturn ( _v0$2.cross( _v1$3 ).dot( direction ) < 0 ) ? true : false;\n\n\t}\n\n\tset( a, b, c ) {\n\n\t\tthis.a.copy( a );\n\t\tthis.b.copy( b );\n\t\tthis.c.copy( c );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromPointsAndIndices( points, i0, i1, i2 ) {\n\n\t\tthis.a.copy( points[ i0 ] );\n\t\tthis.b.copy( points[ i1 ] );\n\t\tthis.c.copy( points[ i2 ] );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromAttributeAndIndices( attribute, i0, i1, i2 ) {\n\n\t\tthis.a.fromBufferAttribute( attribute, i0 );\n\t\tthis.b.fromBufferAttribute( attribute, i1 );\n\t\tthis.c.fromBufferAttribute( attribute, i2 );\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( triangle ) {\n\n\t\tthis.a.copy( triangle.a );\n\t\tthis.b.copy( triangle.b );\n\t\tthis.c.copy( triangle.c );\n\n\t\treturn this;\n\n\t}\n\n\tgetArea() {\n\n\t\t_v0$2.subVectors( this.c, this.b );\n\t\t_v1$3.subVectors( this.a, this.b );\n\n\t\treturn _v0$2.cross( _v1$3 ).length() * 0.5;\n\n\t}\n\n\tgetMidpoint( target ) {\n\n\t\treturn target.addVectors( this.a, this.b ).add( this.c ).multiplyScalar( 1 / 3 );\n\n\t}\n\n\tgetNormal( target ) {\n\n\t\treturn Triangle.getNormal( this.a, this.b, this.c, target );\n\n\t}\n\n\tgetPlane( target ) {\n\n\t\treturn target.setFromCoplanarPoints( this.a, this.b, this.c );\n\n\t}\n\n\tgetBarycoord( point, target ) {\n\n\t\treturn Triangle.getBarycoord( point, this.a, this.b, this.c, target );\n\n\t}\n\n\tgetInterpolation( point, v1, v2, v3, target ) {\n\n\t\treturn Triangle.getInterpolation( point, this.a, this.b, this.c, v1, v2, v3, target );\n\n\t}\n\n\tcontainsPoint( point ) {\n\n\t\treturn Triangle.containsPoint( point, this.a, this.b, this.c );\n\n\t}\n\n\tisFrontFacing( direction ) {\n\n\t\treturn Triangle.isFrontFacing( this.a, this.b, this.c, direction );\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\treturn box.intersectsTriangle( this );\n\n\t}\n\n\tclosestPointToPoint( p, target ) {\n\n\t\tconst a = this.a, b = this.b, c = this.c;\n\t\tlet v, w;\n\n\t\t// algorithm thanks to Real-Time Collision Detection by Christer Ericson,\n\t\t// published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc.,\n\t\t// under the accompanying license; see chapter 5.1.5 for detailed explanation.\n\t\t// basically, we're distinguishing which of the voronoi regions of the triangle\n\t\t// the point lies in with the minimum amount of redundant computation.\n\n\t\t_vab.subVectors( b, a );\n\t\t_vac.subVectors( c, a );\n\t\t_vap.subVectors( p, a );\n\t\tconst d1 = _vab.dot( _vap );\n\t\tconst d2 = _vac.dot( _vap );\n\t\tif ( d1 <= 0 && d2 <= 0 ) {\n\n\t\t\t// vertex region of A; barycentric coords (1, 0, 0)\n\t\t\treturn target.copy( a );\n\n\t\t}\n\n\t\t_vbp.subVectors( p, b );\n\t\tconst d3 = _vab.dot( _vbp );\n\t\tconst d4 = _vac.dot( _vbp );\n\t\tif ( d3 >= 0 && d4 <= d3 ) {\n\n\t\t\t// vertex region of B; barycentric coords (0, 1, 0)\n\t\t\treturn target.copy( b );\n\n\t\t}\n\n\t\tconst vc = d1 * d4 - d3 * d2;\n\t\tif ( vc <= 0 && d1 >= 0 && d3 <= 0 ) {\n\n\t\t\tv = d1 / ( d1 - d3 );\n\t\t\t// edge region of AB; barycentric coords (1-v, v, 0)\n\t\t\treturn target.copy( a ).addScaledVector( _vab, v );\n\n\t\t}\n\n\t\t_vcp.subVectors( p, c );\n\t\tconst d5 = _vab.dot( _vcp );\n\t\tconst d6 = _vac.dot( _vcp );\n\t\tif ( d6 >= 0 && d5 <= d6 ) {\n\n\t\t\t// vertex region of C; barycentric coords (0, 0, 1)\n\t\t\treturn target.copy( c );\n\n\t\t}\n\n\t\tconst vb = d5 * d2 - d1 * d6;\n\t\tif ( vb <= 0 && d2 >= 0 && d6 <= 0 ) {\n\n\t\t\tw = d2 / ( d2 - d6 );\n\t\t\t// edge region of AC; barycentric coords (1-w, 0, w)\n\t\t\treturn target.copy( a ).addScaledVector( _vac, w );\n\n\t\t}\n\n\t\tconst va = d3 * d6 - d5 * d4;\n\t\tif ( va <= 0 && ( d4 - d3 ) >= 0 && ( d5 - d6 ) >= 0 ) {\n\n\t\t\t_vbc.subVectors( c, b );\n\t\t\tw = ( d4 - d3 ) / ( ( d4 - d3 ) + ( d5 - d6 ) );\n\t\t\t// edge region of BC; barycentric coords (0, 1-w, w)\n\t\t\treturn target.copy( b ).addScaledVector( _vbc, w ); // edge region of BC\n\n\t\t}\n\n\t\t// face region\n\t\tconst denom = 1 / ( va + vb + vc );\n\t\t// u = va * denom\n\t\tv = vb * denom;\n\t\tw = vc * denom;\n\n\t\treturn target.copy( a ).addScaledVector( _vab, v ).addScaledVector( _vac, w );\n\n\t}\n\n\tequals( triangle ) {\n\n\t\treturn triangle.a.equals( this.a ) && triangle.b.equals( this.b ) && triangle.c.equals( this.c );\n\n\t}\n\n}\n\nconst _colorKeywords = { 'aliceblue': 0xF0F8FF, 'antiquewhite': 0xFAEBD7, 'aqua': 0x00FFFF, 'aquamarine': 0x7FFFD4, 'azure': 0xF0FFFF,\n\t'beige': 0xF5F5DC, 'bisque': 0xFFE4C4, 'black': 0x000000, 'blanchedalmond': 0xFFEBCD, 'blue': 0x0000FF, 'blueviolet': 0x8A2BE2,\n\t'brown': 0xA52A2A, 'burlywood': 0xDEB887, 'cadetblue': 0x5F9EA0, 'chartreuse': 0x7FFF00, 'chocolate': 0xD2691E, 'coral': 0xFF7F50,\n\t'cornflowerblue': 0x6495ED, 'cornsilk': 0xFFF8DC, 'crimson': 0xDC143C, 'cyan': 0x00FFFF, 'darkblue': 0x00008B, 'darkcyan': 0x008B8B,\n\t'darkgoldenrod': 0xB8860B, 'darkgray': 0xA9A9A9, 'darkgreen': 0x006400, 'darkgrey': 0xA9A9A9, 'darkkhaki': 0xBDB76B, 'darkmagenta': 0x8B008B,\n\t'darkolivegreen': 0x556B2F, 'darkorange': 0xFF8C00, 'darkorchid': 0x9932CC, 'darkred': 0x8B0000, 'darksalmon': 0xE9967A, 'darkseagreen': 0x8FBC8F,\n\t'darkslateblue': 0x483D8B, 'darkslategray': 0x2F4F4F, 'darkslategrey': 0x2F4F4F, 'darkturquoise': 0x00CED1, 'darkviolet': 0x9400D3,\n\t'deeppink': 0xFF1493, 'deepskyblue': 0x00BFFF, 'dimgray': 0x696969, 'dimgrey': 0x696969, 'dodgerblue': 0x1E90FF, 'firebrick': 0xB22222,\n\t'floralwhite': 0xFFFAF0, 'forestgreen': 0x228B22, 'fuchsia': 0xFF00FF, 'gainsboro': 0xDCDCDC, 'ghostwhite': 0xF8F8FF, 'gold': 0xFFD700,\n\t'goldenrod': 0xDAA520, 'gray': 0x808080, 'green': 0x008000, 'greenyellow': 0xADFF2F, 'grey': 0x808080, 'honeydew': 0xF0FFF0, 'hotpink': 0xFF69B4,\n\t'indianred': 0xCD5C5C, 'indigo': 0x4B0082, 'ivory': 0xFFFFF0, 'khaki': 0xF0E68C, 'lavender': 0xE6E6FA, 'lavenderblush': 0xFFF0F5, 'lawngreen': 0x7CFC00,\n\t'lemonchiffon': 0xFFFACD, 'lightblue': 0xADD8E6, 'lightcoral': 0xF08080, 'lightcyan': 0xE0FFFF, 'lightgoldenrodyellow': 0xFAFAD2, 'lightgray': 0xD3D3D3,\n\t'lightgreen': 0x90EE90, 'lightgrey': 0xD3D3D3, 'lightpink': 0xFFB6C1, 'lightsalmon': 0xFFA07A, 'lightseagreen': 0x20B2AA, 'lightskyblue': 0x87CEFA,\n\t'lightslategray': 0x778899, 'lightslategrey': 0x778899, 'lightsteelblue': 0xB0C4DE, 'lightyellow': 0xFFFFE0, 'lime': 0x00FF00, 'limegreen': 0x32CD32,\n\t'linen': 0xFAF0E6, 'magenta': 0xFF00FF, 'maroon': 0x800000, 'mediumaquamarine': 0x66CDAA, 'mediumblue': 0x0000CD, 'mediumorchid': 0xBA55D3,\n\t'mediumpurple': 0x9370DB, 'mediumseagreen': 0x3CB371, 'mediumslateblue': 0x7B68EE, 'mediumspringgreen': 0x00FA9A, 'mediumturquoise': 0x48D1CC,\n\t'mediumvioletred': 0xC71585, 'midnightblue': 0x191970, 'mintcream': 0xF5FFFA, 'mistyrose': 0xFFE4E1, 'moccasin': 0xFFE4B5, 'navajowhite': 0xFFDEAD,\n\t'navy': 0x000080, 'oldlace': 0xFDF5E6, 'olive': 0x808000, 'olivedrab': 0x6B8E23, 'orange': 0xFFA500, 'orangered': 0xFF4500, 'orchid': 0xDA70D6,\n\t'palegoldenrod': 0xEEE8AA, 'palegreen': 0x98FB98, 'paleturquoise': 0xAFEEEE, 'palevioletred': 0xDB7093, 'papayawhip': 0xFFEFD5, 'peachpuff': 0xFFDAB9,\n\t'peru': 0xCD853F, 'pink': 0xFFC0CB, 'plum': 0xDDA0DD, 'powderblue': 0xB0E0E6, 'purple': 0x800080, 'rebeccapurple': 0x663399, 'red': 0xFF0000, 'rosybrown': 0xBC8F8F,\n\t'royalblue': 0x4169E1, 'saddlebrown': 0x8B4513, 'salmon': 0xFA8072, 'sandybrown': 0xF4A460, 'seagreen': 0x2E8B57, 'seashell': 0xFFF5EE,\n\t'sienna': 0xA0522D, 'silver': 0xC0C0C0, 'skyblue': 0x87CEEB, 'slateblue': 0x6A5ACD, 'slategray': 0x708090, 'slategrey': 0x708090, 'snow': 0xFFFAFA,\n\t'springgreen': 0x00FF7F, 'steelblue': 0x4682B4, 'tan': 0xD2B48C, 'teal': 0x008080, 'thistle': 0xD8BFD8, 'tomato': 0xFF6347, 'turquoise': 0x40E0D0,\n\t'violet': 0xEE82EE, 'wheat': 0xF5DEB3, 'white': 0xFFFFFF, 'whitesmoke': 0xF5F5F5, 'yellow': 0xFFFF00, 'yellowgreen': 0x9ACD32 };\n\nconst _hslA = { h: 0, s: 0, l: 0 };\nconst _hslB = { h: 0, s: 0, l: 0 };\n\nfunction hue2rgb( p, q, t ) {\n\n\tif ( t < 0 ) t += 1;\n\tif ( t > 1 ) t -= 1;\n\tif ( t < 1 / 6 ) return p + ( q - p ) * 6 * t;\n\tif ( t < 1 / 2 ) return q;\n\tif ( t < 2 / 3 ) return p + ( q - p ) * 6 * ( 2 / 3 - t );\n\treturn p;\n\n}\n\nclass Color {\n\n\tconstructor( r, g, b ) {\n\n\t\tthis.isColor = true;\n\n\t\tthis.r = 1;\n\t\tthis.g = 1;\n\t\tthis.b = 1;\n\n\t\treturn this.set( r, g, b );\n\n\t}\n\n\tset( r, g, b ) {\n\n\t\tif ( g === undefined && b === undefined ) {\n\n\t\t\t// r is THREE.Color, hex or string\n\n\t\t\tconst value = r;\n\n\t\t\tif ( value && value.isColor ) {\n\n\t\t\t\tthis.copy( value );\n\n\t\t\t} else if ( typeof value === 'number' ) {\n\n\t\t\t\tthis.setHex( value );\n\n\t\t\t} else if ( typeof value === 'string' ) {\n\n\t\t\t\tthis.setStyle( value );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tthis.setRGB( r, g, b );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetScalar( scalar ) {\n\n\t\tthis.r = scalar;\n\t\tthis.g = scalar;\n\t\tthis.b = scalar;\n\n\t\treturn this;\n\n\t}\n\n\tsetHex( hex, colorSpace = SRGBColorSpace ) {\n\n\t\thex = Math.floor( hex );\n\n\t\tthis.r = ( hex >> 16 & 255 ) / 255;\n\t\tthis.g = ( hex >> 8 & 255 ) / 255;\n\t\tthis.b = ( hex & 255 ) / 255;\n\n\t\tColorManagement.toWorkingColorSpace( this, colorSpace );\n\n\t\treturn this;\n\n\t}\n\n\tsetRGB( r, g, b, colorSpace = ColorManagement.workingColorSpace ) {\n\n\t\tthis.r = r;\n\t\tthis.g = g;\n\t\tthis.b = b;\n\n\t\tColorManagement.toWorkingColorSpace( this, colorSpace );\n\n\t\treturn this;\n\n\t}\n\n\tsetHSL( h, s, l, colorSpace = ColorManagement.workingColorSpace ) {\n\n\t\t// h,s,l ranges are in 0.0 - 1.0\n\t\th = euclideanModulo( h, 1 );\n\t\ts = clamp( s, 0, 1 );\n\t\tl = clamp( l, 0, 1 );\n\n\t\tif ( s === 0 ) {\n\n\t\t\tthis.r = this.g = this.b = l;\n\n\t\t} else {\n\n\t\t\tconst p = l <= 0.5 ? l * ( 1 + s ) : l + s - ( l * s );\n\t\t\tconst q = ( 2 * l ) - p;\n\n\t\t\tthis.r = hue2rgb( q, p, h + 1 / 3 );\n\t\t\tthis.g = hue2rgb( q, p, h );\n\t\t\tthis.b = hue2rgb( q, p, h - 1 / 3 );\n\n\t\t}\n\n\t\tColorManagement.toWorkingColorSpace( this, colorSpace );\n\n\t\treturn this;\n\n\t}\n\n\tsetStyle( style, colorSpace = SRGBColorSpace ) {\n\n\t\tfunction handleAlpha( string ) {\n\n\t\t\tif ( string === undefined ) return;\n\n\t\t\tif ( parseFloat( string ) < 1 ) {\n\n\t\t\t\tconsole.warn( 'THREE.Color: Alpha component of ' + style + ' will be ignored.' );\n\n\t\t\t}\n\n\t\t}\n\n\n\t\tlet m;\n\n\t\tif ( m = /^(\\w+)\\(([^\\)]*)\\)/.exec( style ) ) {\n\n\t\t\t// rgb / hsl\n\n\t\t\tlet color;\n\t\t\tconst name = m[ 1 ];\n\t\t\tconst components = m[ 2 ];\n\n\t\t\tswitch ( name ) {\n\n\t\t\t\tcase 'rgb':\n\t\t\t\tcase 'rgba':\n\n\t\t\t\t\tif ( color = /^\\s*(\\d+)\\s*,\\s*(\\d+)\\s*,\\s*(\\d+)\\s*(?:,\\s*(\\d*\\.?\\d+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t// rgb(255,0,0) rgba(255,0,0,0.5)\n\n\t\t\t\t\t\thandleAlpha( color[ 4 ] );\n\n\t\t\t\t\t\treturn this.setRGB(\n\t\t\t\t\t\t\tMath.min( 255, parseInt( color[ 1 ], 10 ) ) / 255,\n\t\t\t\t\t\t\tMath.min( 255, parseInt( color[ 2 ], 10 ) ) / 255,\n\t\t\t\t\t\t\tMath.min( 255, parseInt( color[ 3 ], 10 ) ) / 255,\n\t\t\t\t\t\t\tcolorSpace\n\t\t\t\t\t\t);\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( color = /^\\s*(\\d+)\\%\\s*,\\s*(\\d+)\\%\\s*,\\s*(\\d+)\\%\\s*(?:,\\s*(\\d*\\.?\\d+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t// rgb(100%,0%,0%) rgba(100%,0%,0%,0.5)\n\n\t\t\t\t\t\thandleAlpha( color[ 4 ] );\n\n\t\t\t\t\t\treturn this.setRGB(\n\t\t\t\t\t\t\tMath.min( 100, parseInt( color[ 1 ], 10 ) ) / 100,\n\t\t\t\t\t\t\tMath.min( 100, parseInt( color[ 2 ], 10 ) ) / 100,\n\t\t\t\t\t\t\tMath.min( 100, parseInt( color[ 3 ], 10 ) ) / 100,\n\t\t\t\t\t\t\tcolorSpace\n\t\t\t\t\t\t);\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'hsl':\n\t\t\t\tcase 'hsla':\n\n\t\t\t\t\tif ( color = /^\\s*(\\d*\\.?\\d+)\\s*,\\s*(\\d*\\.?\\d+)\\%\\s*,\\s*(\\d*\\.?\\d+)\\%\\s*(?:,\\s*(\\d*\\.?\\d+)\\s*)?$/.exec( components ) ) {\n\n\t\t\t\t\t\t// hsl(120,50%,50%) hsla(120,50%,50%,0.5)\n\n\t\t\t\t\t\thandleAlpha( color[ 4 ] );\n\n\t\t\t\t\t\treturn this.setHSL(\n\t\t\t\t\t\t\tparseFloat( color[ 1 ] ) / 360,\n\t\t\t\t\t\t\tparseFloat( color[ 2 ] ) / 100,\n\t\t\t\t\t\t\tparseFloat( color[ 3 ] ) / 100,\n\t\t\t\t\t\t\tcolorSpace\n\t\t\t\t\t\t);\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tconsole.warn( 'THREE.Color: Unknown color model ' + style );\n\n\t\t\t}\n\n\t\t} else if ( m = /^\\#([A-Fa-f\\d]+)$/.exec( style ) ) {\n\n\t\t\t// hex color\n\n\t\t\tconst hex = m[ 1 ];\n\t\t\tconst size = hex.length;\n\n\t\t\tif ( size === 3 ) {\n\n\t\t\t\t// #ff0\n\t\t\t\treturn this.setRGB(\n\t\t\t\t\tparseInt( hex.charAt( 0 ), 16 ) / 15,\n\t\t\t\t\tparseInt( hex.charAt( 1 ), 16 ) / 15,\n\t\t\t\t\tparseInt( hex.charAt( 2 ), 16 ) / 15,\n\t\t\t\t\tcolorSpace\n\t\t\t\t);\n\n\t\t\t} else if ( size === 6 ) {\n\n\t\t\t\t// #ff0000\n\t\t\t\treturn this.setHex( parseInt( hex, 16 ), colorSpace );\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'THREE.Color: Invalid hex color ' + style );\n\n\t\t\t}\n\n\t\t} else if ( style && style.length > 0 ) {\n\n\t\t\treturn this.setColorName( style, colorSpace );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetColorName( style, colorSpace = SRGBColorSpace ) {\n\n\t\t// color keywords\n\t\tconst hex = _colorKeywords[ style.toLowerCase() ];\n\n\t\tif ( hex !== undefined ) {\n\n\t\t\t// red\n\t\t\tthis.setHex( hex, colorSpace );\n\n\t\t} else {\n\n\t\t\t// unknown color\n\t\t\tconsole.warn( 'THREE.Color: Unknown color ' + style );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.r, this.g, this.b );\n\n\t}\n\n\tcopy( color ) {\n\n\t\tthis.r = color.r;\n\t\tthis.g = color.g;\n\t\tthis.b = color.b;\n\n\t\treturn this;\n\n\t}\n\n\tcopySRGBToLinear( color ) {\n\n\t\tthis.r = SRGBToLinear( color.r );\n\t\tthis.g = SRGBToLinear( color.g );\n\t\tthis.b = SRGBToLinear( color.b );\n\n\t\treturn this;\n\n\t}\n\n\tcopyLinearToSRGB( color ) {\n\n\t\tthis.r = LinearToSRGB( color.r );\n\t\tthis.g = LinearToSRGB( color.g );\n\t\tthis.b = LinearToSRGB( color.b );\n\n\t\treturn this;\n\n\t}\n\n\tconvertSRGBToLinear() {\n\n\t\tthis.copySRGBToLinear( this );\n\n\t\treturn this;\n\n\t}\n\n\tconvertLinearToSRGB() {\n\n\t\tthis.copyLinearToSRGB( this );\n\n\t\treturn this;\n\n\t}\n\n\tgetHex( colorSpace = SRGBColorSpace ) {\n\n\t\tColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );\n\n\t\treturn 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 ) );\n\n\t}\n\n\tgetHexString( colorSpace = SRGBColorSpace ) {\n\n\t\treturn ( '000000' + this.getHex( colorSpace ).toString( 16 ) ).slice( - 6 );\n\n\t}\n\n\tgetHSL( target, colorSpace = ColorManagement.workingColorSpace ) {\n\n\t\t// h,s,l ranges are in 0.0 - 1.0\n\n\t\tColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );\n\n\t\tconst r = _color.r, g = _color.g, b = _color.b;\n\n\t\tconst max = Math.max( r, g, b );\n\t\tconst min = Math.min( r, g, b );\n\n\t\tlet hue, saturation;\n\t\tconst lightness = ( min + max ) / 2.0;\n\n\t\tif ( min === max ) {\n\n\t\t\thue = 0;\n\t\t\tsaturation = 0;\n\n\t\t} else {\n\n\t\t\tconst delta = max - min;\n\n\t\t\tsaturation = lightness <= 0.5 ? delta / ( max + min ) : delta / ( 2 - max - min );\n\n\t\t\tswitch ( max ) {\n\n\t\t\t\tcase r: hue = ( g - b ) / delta + ( g < b ? 6 : 0 ); break;\n\t\t\t\tcase g: hue = ( b - r ) / delta + 2; break;\n\t\t\t\tcase b: hue = ( r - g ) / delta + 4; break;\n\n\t\t\t}\n\n\t\t\thue /= 6;\n\n\t\t}\n\n\t\ttarget.h = hue;\n\t\ttarget.s = saturation;\n\t\ttarget.l = lightness;\n\n\t\treturn target;\n\n\t}\n\n\tgetRGB( target, colorSpace = ColorManagement.workingColorSpace ) {\n\n\t\tColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );\n\n\t\ttarget.r = _color.r;\n\t\ttarget.g = _color.g;\n\t\ttarget.b = _color.b;\n\n\t\treturn target;\n\n\t}\n\n\tgetStyle( colorSpace = SRGBColorSpace ) {\n\n\t\tColorManagement.fromWorkingColorSpace( _color.copy( this ), colorSpace );\n\n\t\tconst r = _color.r, g = _color.g, b = _color.b;\n\n\t\tif ( colorSpace !== SRGBColorSpace ) {\n\n\t\t\t// Requires CSS Color Module Level 4 (https://www.w3.org/TR/css-color-4/).\n\t\t\treturn `color(${ colorSpace } ${ r.toFixed( 3 ) } ${ g.toFixed( 3 ) } ${ b.toFixed( 3 ) })`;\n\n\t\t}\n\n\t\treturn `rgb(${ Math.round( r * 255 ) },${ Math.round( g * 255 ) },${ Math.round( b * 255 ) })`;\n\n\t}\n\n\toffsetHSL( h, s, l ) {\n\n\t\tthis.getHSL( _hslA );\n\n\t\treturn this.setHSL( _hslA.h + h, _hslA.s + s, _hslA.l + l );\n\n\t}\n\n\tadd( color ) {\n\n\t\tthis.r += color.r;\n\t\tthis.g += color.g;\n\t\tthis.b += color.b;\n\n\t\treturn this;\n\n\t}\n\n\taddColors( color1, color2 ) {\n\n\t\tthis.r = color1.r + color2.r;\n\t\tthis.g = color1.g + color2.g;\n\t\tthis.b = color1.b + color2.b;\n\n\t\treturn this;\n\n\t}\n\n\taddScalar( s ) {\n\n\t\tthis.r += s;\n\t\tthis.g += s;\n\t\tthis.b += s;\n\n\t\treturn this;\n\n\t}\n\n\tsub( color ) {\n\n\t\tthis.r = Math.max( 0, this.r - color.r );\n\t\tthis.g = Math.max( 0, this.g - color.g );\n\t\tthis.b = Math.max( 0, this.b - color.b );\n\n\t\treturn this;\n\n\t}\n\n\tmultiply( color ) {\n\n\t\tthis.r *= color.r;\n\t\tthis.g *= color.g;\n\t\tthis.b *= color.b;\n\n\t\treturn this;\n\n\t}\n\n\tmultiplyScalar( s ) {\n\n\t\tthis.r *= s;\n\t\tthis.g *= s;\n\t\tthis.b *= s;\n\n\t\treturn this;\n\n\t}\n\n\tlerp( color, alpha ) {\n\n\t\tthis.r += ( color.r - this.r ) * alpha;\n\t\tthis.g += ( color.g - this.g ) * alpha;\n\t\tthis.b += ( color.b - this.b ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tlerpColors( color1, color2, alpha ) {\n\n\t\tthis.r = color1.r + ( color2.r - color1.r ) * alpha;\n\t\tthis.g = color1.g + ( color2.g - color1.g ) * alpha;\n\t\tthis.b = color1.b + ( color2.b - color1.b ) * alpha;\n\n\t\treturn this;\n\n\t}\n\n\tlerpHSL( color, alpha ) {\n\n\t\tthis.getHSL( _hslA );\n\t\tcolor.getHSL( _hslB );\n\n\t\tconst h = lerp( _hslA.h, _hslB.h, alpha );\n\t\tconst s = lerp( _hslA.s, _hslB.s, alpha );\n\t\tconst l = lerp( _hslA.l, _hslB.l, alpha );\n\n\t\tthis.setHSL( h, s, l );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromVector3( v ) {\n\n\t\tthis.r = v.x;\n\t\tthis.g = v.y;\n\t\tthis.b = v.z;\n\n\t\treturn this;\n\n\t}\n\n\tapplyMatrix3( m ) {\n\n\t\tconst r = this.r, g = this.g, b = this.b;\n\t\tconst e = m.elements;\n\n\t\tthis.r = e[ 0 ] * r + e[ 3 ] * g + e[ 6 ] * b;\n\t\tthis.g = e[ 1 ] * r + e[ 4 ] * g + e[ 7 ] * b;\n\t\tthis.b = e[ 2 ] * r + e[ 5 ] * g + e[ 8 ] * b;\n\n\t\treturn this;\n\n\t}\n\n\tequals( c ) {\n\n\t\treturn ( c.r === this.r ) && ( c.g === this.g ) && ( c.b === this.b );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tthis.r = array[ offset ];\n\t\tthis.g = array[ offset + 1 ];\n\t\tthis.b = array[ offset + 2 ];\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tarray[ offset ] = this.r;\n\t\tarray[ offset + 1 ] = this.g;\n\t\tarray[ offset + 2 ] = this.b;\n\n\t\treturn array;\n\n\t}\n\n\tfromBufferAttribute( attribute, index ) {\n\n\t\tthis.r = attribute.getX( index );\n\t\tthis.g = attribute.getY( index );\n\t\tthis.b = attribute.getZ( index );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\treturn this.getHex();\n\n\t}\n\n\t*[ Symbol.iterator ]() {\n\n\t\tyield this.r;\n\t\tyield this.g;\n\t\tyield this.b;\n\n\t}\n\n}\n\nconst _color = /*@__PURE__*/ new Color();\n\nColor.NAMES = _colorKeywords;\n\nlet _materialId = 0;\n\nclass Material extends EventDispatcher {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isMaterial = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _materialId ++ } );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.name = '';\n\t\tthis.type = 'Material';\n\n\t\tthis.blending = NormalBlending;\n\t\tthis.side = FrontSide;\n\t\tthis.vertexColors = false;\n\n\t\tthis.opacity = 1;\n\t\tthis.transparent = false;\n\t\tthis.alphaHash = false;\n\n\t\tthis.blendSrc = SrcAlphaFactor;\n\t\tthis.blendDst = OneMinusSrcAlphaFactor;\n\t\tthis.blendEquation = AddEquation;\n\t\tthis.blendSrcAlpha = null;\n\t\tthis.blendDstAlpha = null;\n\t\tthis.blendEquationAlpha = null;\n\t\tthis.blendColor = new Color( 0, 0, 0 );\n\t\tthis.blendAlpha = 0;\n\n\t\tthis.depthFunc = LessEqualDepth;\n\t\tthis.depthTest = true;\n\t\tthis.depthWrite = true;\n\n\t\tthis.stencilWriteMask = 0xff;\n\t\tthis.stencilFunc = AlwaysStencilFunc;\n\t\tthis.stencilRef = 0;\n\t\tthis.stencilFuncMask = 0xff;\n\t\tthis.stencilFail = KeepStencilOp;\n\t\tthis.stencilZFail = KeepStencilOp;\n\t\tthis.stencilZPass = KeepStencilOp;\n\t\tthis.stencilWrite = false;\n\n\t\tthis.clippingPlanes = null;\n\t\tthis.clipIntersection = false;\n\t\tthis.clipShadows = false;\n\n\t\tthis.shadowSide = null;\n\n\t\tthis.colorWrite = true;\n\n\t\tthis.precision = null; // override the renderer's default precision for this material\n\n\t\tthis.polygonOffset = false;\n\t\tthis.polygonOffsetFactor = 0;\n\t\tthis.polygonOffsetUnits = 0;\n\n\t\tthis.dithering = false;\n\n\t\tthis.alphaToCoverage = false;\n\t\tthis.premultipliedAlpha = false;\n\t\tthis.forceSinglePass = false;\n\n\t\tthis.visible = true;\n\n\t\tthis.toneMapped = true;\n\n\t\tthis.userData = {};\n\n\t\tthis.version = 0;\n\n\t\tthis._alphaTest = 0;\n\n\t}\n\n\tget alphaTest() {\n\n\t\treturn this._alphaTest;\n\n\t}\n\n\tset alphaTest( value ) {\n\n\t\tif ( this._alphaTest > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._alphaTest = value;\n\n\t}\n\n\tonBeforeCompile( /* shaderobject, renderer */ ) {}\n\n\tcustomProgramCacheKey() {\n\n\t\treturn this.onBeforeCompile.toString();\n\n\t}\n\n\tsetValues( values ) {\n\n\t\tif ( values === undefined ) return;\n\n\t\tfor ( const key in values ) {\n\n\t\t\tconst newValue = values[ key ];\n\n\t\t\tif ( newValue === undefined ) {\n\n\t\t\t\tconsole.warn( `THREE.Material: parameter '${ key }' has value of undefined.` );\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tconst currentValue = this[ key ];\n\n\t\t\tif ( currentValue === undefined ) {\n\n\t\t\t\tconsole.warn( `THREE.Material: '${ key }' is not a property of THREE.${ this.type }.` );\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tif ( currentValue && currentValue.isColor ) {\n\n\t\t\t\tcurrentValue.set( newValue );\n\n\t\t\t} else if ( ( currentValue && currentValue.isVector3 ) && ( newValue && newValue.isVector3 ) ) {\n\n\t\t\t\tcurrentValue.copy( newValue );\n\n\t\t\t} else {\n\n\t\t\t\tthis[ key ] = newValue;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst isRootObject = ( meta === undefined || typeof meta === 'string' );\n\n\t\tif ( isRootObject ) {\n\n\t\t\tmeta = {\n\t\t\t\ttextures: {},\n\t\t\t\timages: {}\n\t\t\t};\n\n\t\t}\n\n\t\tconst data = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'Material',\n\t\t\t\tgenerator: 'Material.toJSON'\n\t\t\t}\n\t\t};\n\n\t\t// standard Material serialization\n\t\tdata.uuid = this.uuid;\n\t\tdata.type = this.type;\n\n\t\tif ( this.name !== '' ) data.name = this.name;\n\n\t\tif ( this.color && this.color.isColor ) data.color = this.color.getHex();\n\n\t\tif ( this.roughness !== undefined ) data.roughness = this.roughness;\n\t\tif ( this.metalness !== undefined ) data.metalness = this.metalness;\n\n\t\tif ( this.sheen !== undefined ) data.sheen = this.sheen;\n\t\tif ( this.sheenColor && this.sheenColor.isColor ) data.sheenColor = this.sheenColor.getHex();\n\t\tif ( this.sheenRoughness !== undefined ) data.sheenRoughness = this.sheenRoughness;\n\t\tif ( this.emissive && this.emissive.isColor ) data.emissive = this.emissive.getHex();\n\t\tif ( this.emissiveIntensity !== undefined && this.emissiveIntensity !== 1 ) data.emissiveIntensity = this.emissiveIntensity;\n\n\t\tif ( this.specular && this.specular.isColor ) data.specular = this.specular.getHex();\n\t\tif ( this.specularIntensity !== undefined ) data.specularIntensity = this.specularIntensity;\n\t\tif ( this.specularColor && this.specularColor.isColor ) data.specularColor = this.specularColor.getHex();\n\t\tif ( this.shininess !== undefined ) data.shininess = this.shininess;\n\t\tif ( this.clearcoat !== undefined ) data.clearcoat = this.clearcoat;\n\t\tif ( this.clearcoatRoughness !== undefined ) data.clearcoatRoughness = this.clearcoatRoughness;\n\n\t\tif ( this.clearcoatMap && this.clearcoatMap.isTexture ) {\n\n\t\t\tdata.clearcoatMap = this.clearcoatMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.clearcoatRoughnessMap && this.clearcoatRoughnessMap.isTexture ) {\n\n\t\t\tdata.clearcoatRoughnessMap = this.clearcoatRoughnessMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.clearcoatNormalMap && this.clearcoatNormalMap.isTexture ) {\n\n\t\t\tdata.clearcoatNormalMap = this.clearcoatNormalMap.toJSON( meta ).uuid;\n\t\t\tdata.clearcoatNormalScale = this.clearcoatNormalScale.toArray();\n\n\t\t}\n\n\t\tif ( this.dispersion !== undefined ) data.dispersion = this.dispersion;\n\n\t\tif ( this.iridescence !== undefined ) data.iridescence = this.iridescence;\n\t\tif ( this.iridescenceIOR !== undefined ) data.iridescenceIOR = this.iridescenceIOR;\n\t\tif ( this.iridescenceThicknessRange !== undefined ) data.iridescenceThicknessRange = this.iridescenceThicknessRange;\n\n\t\tif ( this.iridescenceMap && this.iridescenceMap.isTexture ) {\n\n\t\t\tdata.iridescenceMap = this.iridescenceMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.iridescenceThicknessMap && this.iridescenceThicknessMap.isTexture ) {\n\n\t\t\tdata.iridescenceThicknessMap = this.iridescenceThicknessMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.anisotropy !== undefined ) data.anisotropy = this.anisotropy;\n\t\tif ( this.anisotropyRotation !== undefined ) data.anisotropyRotation = this.anisotropyRotation;\n\n\t\tif ( this.anisotropyMap && this.anisotropyMap.isTexture ) {\n\n\t\t\tdata.anisotropyMap = this.anisotropyMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.map && this.map.isTexture ) data.map = this.map.toJSON( meta ).uuid;\n\t\tif ( this.matcap && this.matcap.isTexture ) data.matcap = this.matcap.toJSON( meta ).uuid;\n\t\tif ( this.alphaMap && this.alphaMap.isTexture ) data.alphaMap = this.alphaMap.toJSON( meta ).uuid;\n\n\t\tif ( this.lightMap && this.lightMap.isTexture ) {\n\n\t\t\tdata.lightMap = this.lightMap.toJSON( meta ).uuid;\n\t\t\tdata.lightMapIntensity = this.lightMapIntensity;\n\n\t\t}\n\n\t\tif ( this.aoMap && this.aoMap.isTexture ) {\n\n\t\t\tdata.aoMap = this.aoMap.toJSON( meta ).uuid;\n\t\t\tdata.aoMapIntensity = this.aoMapIntensity;\n\n\t\t}\n\n\t\tif ( this.bumpMap && this.bumpMap.isTexture ) {\n\n\t\t\tdata.bumpMap = this.bumpMap.toJSON( meta ).uuid;\n\t\t\tdata.bumpScale = this.bumpScale;\n\n\t\t}\n\n\t\tif ( this.normalMap && this.normalMap.isTexture ) {\n\n\t\t\tdata.normalMap = this.normalMap.toJSON( meta ).uuid;\n\t\t\tdata.normalMapType = this.normalMapType;\n\t\t\tdata.normalScale = this.normalScale.toArray();\n\n\t\t}\n\n\t\tif ( this.displacementMap && this.displacementMap.isTexture ) {\n\n\t\t\tdata.displacementMap = this.displacementMap.toJSON( meta ).uuid;\n\t\t\tdata.displacementScale = this.displacementScale;\n\t\t\tdata.displacementBias = this.displacementBias;\n\n\t\t}\n\n\t\tif ( this.roughnessMap && this.roughnessMap.isTexture ) data.roughnessMap = this.roughnessMap.toJSON( meta ).uuid;\n\t\tif ( this.metalnessMap && this.metalnessMap.isTexture ) data.metalnessMap = this.metalnessMap.toJSON( meta ).uuid;\n\n\t\tif ( this.emissiveMap && this.emissiveMap.isTexture ) data.emissiveMap = this.emissiveMap.toJSON( meta ).uuid;\n\t\tif ( this.specularMap && this.specularMap.isTexture ) data.specularMap = this.specularMap.toJSON( meta ).uuid;\n\t\tif ( this.specularIntensityMap && this.specularIntensityMap.isTexture ) data.specularIntensityMap = this.specularIntensityMap.toJSON( meta ).uuid;\n\t\tif ( this.specularColorMap && this.specularColorMap.isTexture ) data.specularColorMap = this.specularColorMap.toJSON( meta ).uuid;\n\n\t\tif ( this.envMap && this.envMap.isTexture ) {\n\n\t\t\tdata.envMap = this.envMap.toJSON( meta ).uuid;\n\n\t\t\tif ( this.combine !== undefined ) data.combine = this.combine;\n\n\t\t}\n\n\t\tif ( this.envMapRotation !== undefined ) data.envMapRotation = this.envMapRotation.toArray();\n\t\tif ( this.envMapIntensity !== undefined ) data.envMapIntensity = this.envMapIntensity;\n\t\tif ( this.reflectivity !== undefined ) data.reflectivity = this.reflectivity;\n\t\tif ( this.refractionRatio !== undefined ) data.refractionRatio = this.refractionRatio;\n\n\t\tif ( this.gradientMap && this.gradientMap.isTexture ) {\n\n\t\t\tdata.gradientMap = this.gradientMap.toJSON( meta ).uuid;\n\n\t\t}\n\n\t\tif ( this.transmission !== undefined ) data.transmission = this.transmission;\n\t\tif ( this.transmissionMap && this.transmissionMap.isTexture ) data.transmissionMap = this.transmissionMap.toJSON( meta ).uuid;\n\t\tif ( this.thickness !== undefined ) data.thickness = this.thickness;\n\t\tif ( this.thicknessMap && this.thicknessMap.isTexture ) data.thicknessMap = this.thicknessMap.toJSON( meta ).uuid;\n\t\tif ( this.attenuationDistance !== undefined && this.attenuationDistance !== Infinity ) data.attenuationDistance = this.attenuationDistance;\n\t\tif ( this.attenuationColor !== undefined ) data.attenuationColor = this.attenuationColor.getHex();\n\n\t\tif ( this.size !== undefined ) data.size = this.size;\n\t\tif ( this.shadowSide !== null ) data.shadowSide = this.shadowSide;\n\t\tif ( this.sizeAttenuation !== undefined ) data.sizeAttenuation = this.sizeAttenuation;\n\n\t\tif ( this.blending !== NormalBlending ) data.blending = this.blending;\n\t\tif ( this.side !== FrontSide ) data.side = this.side;\n\t\tif ( this.vertexColors === true ) data.vertexColors = true;\n\n\t\tif ( this.opacity < 1 ) data.opacity = this.opacity;\n\t\tif ( this.transparent === true ) data.transparent = true;\n\n\t\tif ( this.blendSrc !== SrcAlphaFactor ) data.blendSrc = this.blendSrc;\n\t\tif ( this.blendDst !== OneMinusSrcAlphaFactor ) data.blendDst = this.blendDst;\n\t\tif ( this.blendEquation !== AddEquation ) data.blendEquation = this.blendEquation;\n\t\tif ( this.blendSrcAlpha !== null ) data.blendSrcAlpha = this.blendSrcAlpha;\n\t\tif ( this.blendDstAlpha !== null ) data.blendDstAlpha = this.blendDstAlpha;\n\t\tif ( this.blendEquationAlpha !== null ) data.blendEquationAlpha = this.blendEquationAlpha;\n\t\tif ( this.blendColor && this.blendColor.isColor ) data.blendColor = this.blendColor.getHex();\n\t\tif ( this.blendAlpha !== 0 ) data.blendAlpha = this.blendAlpha;\n\n\t\tif ( this.depthFunc !== LessEqualDepth ) data.depthFunc = this.depthFunc;\n\t\tif ( this.depthTest === false ) data.depthTest = this.depthTest;\n\t\tif ( this.depthWrite === false ) data.depthWrite = this.depthWrite;\n\t\tif ( this.colorWrite === false ) data.colorWrite = this.colorWrite;\n\n\t\tif ( this.stencilWriteMask !== 0xff ) data.stencilWriteMask = this.stencilWriteMask;\n\t\tif ( this.stencilFunc !== AlwaysStencilFunc ) data.stencilFunc = this.stencilFunc;\n\t\tif ( this.stencilRef !== 0 ) data.stencilRef = this.stencilRef;\n\t\tif ( this.stencilFuncMask !== 0xff ) data.stencilFuncMask = this.stencilFuncMask;\n\t\tif ( this.stencilFail !== KeepStencilOp ) data.stencilFail = this.stencilFail;\n\t\tif ( this.stencilZFail !== KeepStencilOp ) data.stencilZFail = this.stencilZFail;\n\t\tif ( this.stencilZPass !== KeepStencilOp ) data.stencilZPass = this.stencilZPass;\n\t\tif ( this.stencilWrite === true ) data.stencilWrite = this.stencilWrite;\n\n\t\t// rotation (SpriteMaterial)\n\t\tif ( this.rotation !== undefined && this.rotation !== 0 ) data.rotation = this.rotation;\n\n\t\tif ( this.polygonOffset === true ) data.polygonOffset = true;\n\t\tif ( this.polygonOffsetFactor !== 0 ) data.polygonOffsetFactor = this.polygonOffsetFactor;\n\t\tif ( this.polygonOffsetUnits !== 0 ) data.polygonOffsetUnits = this.polygonOffsetUnits;\n\n\t\tif ( this.linewidth !== undefined && this.linewidth !== 1 ) data.linewidth = this.linewidth;\n\t\tif ( this.dashSize !== undefined ) data.dashSize = this.dashSize;\n\t\tif ( this.gapSize !== undefined ) data.gapSize = this.gapSize;\n\t\tif ( this.scale !== undefined ) data.scale = this.scale;\n\n\t\tif ( this.dithering === true ) data.dithering = true;\n\n\t\tif ( this.alphaTest > 0 ) data.alphaTest = this.alphaTest;\n\t\tif ( this.alphaHash === true ) data.alphaHash = true;\n\t\tif ( this.alphaToCoverage === true ) data.alphaToCoverage = true;\n\t\tif ( this.premultipliedAlpha === true ) data.premultipliedAlpha = true;\n\t\tif ( this.forceSinglePass === true ) data.forceSinglePass = true;\n\n\t\tif ( this.wireframe === true ) data.wireframe = true;\n\t\tif ( this.wireframeLinewidth > 1 ) data.wireframeLinewidth = this.wireframeLinewidth;\n\t\tif ( this.wireframeLinecap !== 'round' ) data.wireframeLinecap = this.wireframeLinecap;\n\t\tif ( this.wireframeLinejoin !== 'round' ) data.wireframeLinejoin = this.wireframeLinejoin;\n\n\t\tif ( this.flatShading === true ) data.flatShading = true;\n\n\t\tif ( this.visible === false ) data.visible = false;\n\n\t\tif ( this.toneMapped === false ) data.toneMapped = false;\n\n\t\tif ( this.fog === false ) data.fog = false;\n\n\t\tif ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;\n\n\t\t// TODO: Copied from Object3D.toJSON\n\n\t\tfunction extractFromCache( cache ) {\n\n\t\t\tconst values = [];\n\n\t\t\tfor ( const key in cache ) {\n\n\t\t\t\tconst data = cache[ key ];\n\t\t\t\tdelete data.metadata;\n\t\t\t\tvalues.push( data );\n\n\t\t\t}\n\n\t\t\treturn values;\n\n\t\t}\n\n\t\tif ( isRootObject ) {\n\n\t\t\tconst textures = extractFromCache( meta.textures );\n\t\t\tconst images = extractFromCache( meta.images );\n\n\t\t\tif ( textures.length > 0 ) data.textures = textures;\n\t\t\tif ( images.length > 0 ) data.images = images;\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.name = source.name;\n\n\t\tthis.blending = source.blending;\n\t\tthis.side = source.side;\n\t\tthis.vertexColors = source.vertexColors;\n\n\t\tthis.opacity = source.opacity;\n\t\tthis.transparent = source.transparent;\n\n\t\tthis.blendSrc = source.blendSrc;\n\t\tthis.blendDst = source.blendDst;\n\t\tthis.blendEquation = source.blendEquation;\n\t\tthis.blendSrcAlpha = source.blendSrcAlpha;\n\t\tthis.blendDstAlpha = source.blendDstAlpha;\n\t\tthis.blendEquationAlpha = source.blendEquationAlpha;\n\t\tthis.blendColor.copy( source.blendColor );\n\t\tthis.blendAlpha = source.blendAlpha;\n\n\t\tthis.depthFunc = source.depthFunc;\n\t\tthis.depthTest = source.depthTest;\n\t\tthis.depthWrite = source.depthWrite;\n\n\t\tthis.stencilWriteMask = source.stencilWriteMask;\n\t\tthis.stencilFunc = source.stencilFunc;\n\t\tthis.stencilRef = source.stencilRef;\n\t\tthis.stencilFuncMask = source.stencilFuncMask;\n\t\tthis.stencilFail = source.stencilFail;\n\t\tthis.stencilZFail = source.stencilZFail;\n\t\tthis.stencilZPass = source.stencilZPass;\n\t\tthis.stencilWrite = source.stencilWrite;\n\n\t\tconst srcPlanes = source.clippingPlanes;\n\t\tlet dstPlanes = null;\n\n\t\tif ( srcPlanes !== null ) {\n\n\t\t\tconst n = srcPlanes.length;\n\t\t\tdstPlanes = new Array( n );\n\n\t\t\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\t\t\tdstPlanes[ i ] = srcPlanes[ i ].clone();\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.clippingPlanes = dstPlanes;\n\t\tthis.clipIntersection = source.clipIntersection;\n\t\tthis.clipShadows = source.clipShadows;\n\n\t\tthis.shadowSide = source.shadowSide;\n\n\t\tthis.colorWrite = source.colorWrite;\n\n\t\tthis.precision = source.precision;\n\n\t\tthis.polygonOffset = source.polygonOffset;\n\t\tthis.polygonOffsetFactor = source.polygonOffsetFactor;\n\t\tthis.polygonOffsetUnits = source.polygonOffsetUnits;\n\n\t\tthis.dithering = source.dithering;\n\n\t\tthis.alphaTest = source.alphaTest;\n\t\tthis.alphaHash = source.alphaHash;\n\t\tthis.alphaToCoverage = source.alphaToCoverage;\n\t\tthis.premultipliedAlpha = source.premultipliedAlpha;\n\t\tthis.forceSinglePass = source.forceSinglePass;\n\n\t\tthis.visible = source.visible;\n\n\t\tthis.toneMapped = source.toneMapped;\n\n\t\tthis.userData = JSON.parse( JSON.stringify( source.userData ) );\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t}\n\n\tonBuild( /* shaderobject, renderer */ ) {\n\n\t\tconsole.warn( 'Material: onBuild() has been removed.' ); // @deprecated, r166\n\n\t}\n\n\tonBeforeRender( /* renderer, scene, camera, geometry, object, group */ ) {\n\n\t\tconsole.warn( 'Material: onBeforeRender() has been removed.' ); // @deprecated, r166\n\n\t}\n\n\n}\n\nclass MeshBasicMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshBasicMaterial = true;\n\n\t\tthis.type = 'MeshBasicMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // emissive\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.specularMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.envMapRotation = new Euler();\n\t\tthis.combine = MultiplyOperation;\n\t\tthis.reflectivity = 1;\n\t\tthis.refractionRatio = 0.98;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.specularMap = source.specularMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.envMapRotation.copy( source.envMapRotation );\n\t\tthis.combine = source.combine;\n\t\tthis.reflectivity = source.reflectivity;\n\t\tthis.refractionRatio = source.refractionRatio;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\n// Fast Half Float Conversions, http://www.fox-toolkit.org/ftp/fasthalffloatconversion.pdf\n\nconst _tables = /*@__PURE__*/ _generateTables();\n\nfunction _generateTables() {\n\n\t// float32 to float16 helpers\n\n\tconst buffer = new ArrayBuffer( 4 );\n\tconst floatView = new Float32Array( buffer );\n\tconst uint32View = new Uint32Array( buffer );\n\n\tconst baseTable = new Uint32Array( 512 );\n\tconst shiftTable = new Uint32Array( 512 );\n\n\tfor ( let i = 0; i < 256; ++ i ) {\n\n\t\tconst e = i - 127;\n\n\t\t// very small number (0, -0)\n\n\t\tif ( e < - 27 ) {\n\n\t\t\tbaseTable[ i ] = 0x0000;\n\t\t\tbaseTable[ i | 0x100 ] = 0x8000;\n\t\t\tshiftTable[ i ] = 24;\n\t\t\tshiftTable[ i | 0x100 ] = 24;\n\n\t\t\t// small number (denorm)\n\n\t\t} else if ( e < - 14 ) {\n\n\t\t\tbaseTable[ i ] = 0x0400 >> ( - e - 14 );\n\t\t\tbaseTable[ i | 0x100 ] = ( 0x0400 >> ( - e - 14 ) ) | 0x8000;\n\t\t\tshiftTable[ i ] = - e - 1;\n\t\t\tshiftTable[ i | 0x100 ] = - e - 1;\n\n\t\t\t// normal number\n\n\t\t} else if ( e <= 15 ) {\n\n\t\t\tbaseTable[ i ] = ( e + 15 ) << 10;\n\t\t\tbaseTable[ i | 0x100 ] = ( ( e + 15 ) << 10 ) | 0x8000;\n\t\t\tshiftTable[ i ] = 13;\n\t\t\tshiftTable[ i | 0x100 ] = 13;\n\n\t\t\t// large number (Infinity, -Infinity)\n\n\t\t} else if ( e < 128 ) {\n\n\t\t\tbaseTable[ i ] = 0x7c00;\n\t\t\tbaseTable[ i | 0x100 ] = 0xfc00;\n\t\t\tshiftTable[ i ] = 24;\n\t\t\tshiftTable[ i | 0x100 ] = 24;\n\n\t\t\t// stay (NaN, Infinity, -Infinity)\n\n\t\t} else {\n\n\t\t\tbaseTable[ i ] = 0x7c00;\n\t\t\tbaseTable[ i | 0x100 ] = 0xfc00;\n\t\t\tshiftTable[ i ] = 13;\n\t\t\tshiftTable[ i | 0x100 ] = 13;\n\n\t\t}\n\n\t}\n\n\t// float16 to float32 helpers\n\n\tconst mantissaTable = new Uint32Array( 2048 );\n\tconst exponentTable = new Uint32Array( 64 );\n\tconst offsetTable = new Uint32Array( 64 );\n\n\tfor ( let i = 1; i < 1024; ++ i ) {\n\n\t\tlet m = i << 13; // zero pad mantissa bits\n\t\tlet e = 0; // zero exponent\n\n\t\t// normalized\n\t\twhile ( ( m & 0x00800000 ) === 0 ) {\n\n\t\t\tm <<= 1;\n\t\t\te -= 0x00800000; // decrement exponent\n\n\t\t}\n\n\t\tm &= ~ 0x00800000; // clear leading 1 bit\n\t\te += 0x38800000; // adjust bias\n\n\t\tmantissaTable[ i ] = m | e;\n\n\t}\n\n\tfor ( let i = 1024; i < 2048; ++ i ) {\n\n\t\tmantissaTable[ i ] = 0x38000000 + ( ( i - 1024 ) << 13 );\n\n\t}\n\n\tfor ( let i = 1; i < 31; ++ i ) {\n\n\t\texponentTable[ i ] = i << 23;\n\n\t}\n\n\texponentTable[ 31 ] = 0x47800000;\n\texponentTable[ 32 ] = 0x80000000;\n\n\tfor ( let i = 33; i < 63; ++ i ) {\n\n\t\texponentTable[ i ] = 0x80000000 + ( ( i - 32 ) << 23 );\n\n\t}\n\n\texponentTable[ 63 ] = 0xc7800000;\n\n\tfor ( let i = 1; i < 64; ++ i ) {\n\n\t\tif ( i !== 32 ) {\n\n\t\t\toffsetTable[ i ] = 1024;\n\n\t\t}\n\n\t}\n\n\treturn {\n\t\tfloatView: floatView,\n\t\tuint32View: uint32View,\n\t\tbaseTable: baseTable,\n\t\tshiftTable: shiftTable,\n\t\tmantissaTable: mantissaTable,\n\t\texponentTable: exponentTable,\n\t\toffsetTable: offsetTable\n\t};\n\n}\n\n// float32 to float16\n\nfunction toHalfFloat( val ) {\n\n\tif ( Math.abs( val ) > 65504 ) console.warn( 'THREE.DataUtils.toHalfFloat(): Value out of range.' );\n\n\tval = clamp( val, - 65504, 65504 );\n\n\t_tables.floatView[ 0 ] = val;\n\tconst f = _tables.uint32View[ 0 ];\n\tconst e = ( f >> 23 ) & 0x1ff;\n\treturn _tables.baseTable[ e ] + ( ( f & 0x007fffff ) >> _tables.shiftTable[ e ] );\n\n}\n\n// float16 to float32\n\nfunction fromHalfFloat( val ) {\n\n\tconst m = val >> 10;\n\t_tables.uint32View[ 0 ] = _tables.mantissaTable[ _tables.offsetTable[ m ] + ( val & 0x3ff ) ] + _tables.exponentTable[ m ];\n\treturn _tables.floatView[ 0 ];\n\n}\n\nconst DataUtils = {\n\ttoHalfFloat: toHalfFloat,\n\tfromHalfFloat: fromHalfFloat,\n};\n\nconst _vector$9 = /*@__PURE__*/ new Vector3();\nconst _vector2$1 = /*@__PURE__*/ new Vector2();\n\nclass BufferAttribute {\n\n\tconstructor( array, itemSize, normalized = false ) {\n\n\t\tif ( Array.isArray( array ) ) {\n\n\t\t\tthrow new TypeError( 'THREE.BufferAttribute: array should be a Typed Array.' );\n\n\t\t}\n\n\t\tthis.isBufferAttribute = true;\n\n\t\tthis.name = '';\n\n\t\tthis.array = array;\n\t\tthis.itemSize = itemSize;\n\t\tthis.count = array !== undefined ? array.length / itemSize : 0;\n\t\tthis.normalized = normalized;\n\n\t\tthis.usage = StaticDrawUsage;\n\t\tthis._updateRange = { offset: 0, count: - 1 };\n\t\tthis.updateRanges = [];\n\t\tthis.gpuType = FloatType;\n\n\t\tthis.version = 0;\n\n\t}\n\n\tonUploadCallback() {}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t}\n\n\tget updateRange() {\n\n\t\twarnOnce( 'THREE.BufferAttribute: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159\n\t\treturn this._updateRange;\n\n\t}\n\n\tsetUsage( value ) {\n\n\t\tthis.usage = value;\n\n\t\treturn this;\n\n\t}\n\n\taddUpdateRange( start, count ) {\n\n\t\tthis.updateRanges.push( { start, count } );\n\n\t}\n\n\tclearUpdateRanges() {\n\n\t\tthis.updateRanges.length = 0;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.name = source.name;\n\t\tthis.array = new source.array.constructor( source.array );\n\t\tthis.itemSize = source.itemSize;\n\t\tthis.count = source.count;\n\t\tthis.normalized = source.normalized;\n\n\t\tthis.usage = source.usage;\n\t\tthis.gpuType = source.gpuType;\n\n\t\treturn this;\n\n\t}\n\n\tcopyAt( index1, attribute, index2 ) {\n\n\t\tindex1 *= this.itemSize;\n\t\tindex2 *= attribute.itemSize;\n\n\t\tfor ( let i = 0, l = this.itemSize; i < l; i ++ ) {\n\n\t\t\tthis.array[ index1 + i ] = attribute.array[ index2 + i ];\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tcopyArray( array ) {\n\n\t\tthis.array.set( array );\n\n\t\treturn this;\n\n\t}\n\n\tapplyMatrix3( m ) {\n\n\t\tif ( this.itemSize === 2 ) {\n\n\t\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t\t_vector2$1.fromBufferAttribute( this, i );\n\t\t\t\t_vector2$1.applyMatrix3( m );\n\n\t\t\t\tthis.setXY( i, _vector2$1.x, _vector2$1.y );\n\n\t\t\t}\n\n\t\t} else if ( this.itemSize === 3 ) {\n\n\t\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t\t_vector$9.fromBufferAttribute( this, i );\n\t\t\t\t_vector$9.applyMatrix3( m );\n\n\t\t\t\tthis.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tapplyMatrix4( m ) {\n\n\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t_vector$9.fromBufferAttribute( this, i );\n\n\t\t\t_vector$9.applyMatrix4( m );\n\n\t\t\tthis.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tapplyNormalMatrix( m ) {\n\n\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t_vector$9.fromBufferAttribute( this, i );\n\n\t\t\t_vector$9.applyNormalMatrix( m );\n\n\t\t\tthis.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttransformDirection( m ) {\n\n\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t_vector$9.fromBufferAttribute( this, i );\n\n\t\t\t_vector$9.transformDirection( m );\n\n\t\t\tthis.setXYZ( i, _vector$9.x, _vector$9.y, _vector$9.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tset( value, offset = 0 ) {\n\n\t\t// Matching BufferAttribute constructor, do not normalize the array.\n\t\tthis.array.set( value, offset );\n\n\t\treturn this;\n\n\t}\n\n\tgetComponent( index, component ) {\n\n\t\tlet value = this.array[ index * this.itemSize + component ];\n\n\t\tif ( this.normalized ) value = denormalize( value, this.array );\n\n\t\treturn value;\n\n\t}\n\n\tsetComponent( index, component, value ) {\n\n\t\tif ( this.normalized ) value = normalize( value, this.array );\n\n\t\tthis.array[ index * this.itemSize + component ] = value;\n\n\t\treturn this;\n\n\t}\n\n\tgetX( index ) {\n\n\t\tlet x = this.array[ index * this.itemSize ];\n\n\t\tif ( this.normalized ) x = denormalize( x, this.array );\n\n\t\treturn x;\n\n\t}\n\n\tsetX( index, x ) {\n\n\t\tif ( this.normalized ) x = normalize( x, this.array );\n\n\t\tthis.array[ index * this.itemSize ] = x;\n\n\t\treturn this;\n\n\t}\n\n\tgetY( index ) {\n\n\t\tlet y = this.array[ index * this.itemSize + 1 ];\n\n\t\tif ( this.normalized ) y = denormalize( y, this.array );\n\n\t\treturn y;\n\n\t}\n\n\tsetY( index, y ) {\n\n\t\tif ( this.normalized ) y = normalize( y, this.array );\n\n\t\tthis.array[ index * this.itemSize + 1 ] = y;\n\n\t\treturn this;\n\n\t}\n\n\tgetZ( index ) {\n\n\t\tlet z = this.array[ index * this.itemSize + 2 ];\n\n\t\tif ( this.normalized ) z = denormalize( z, this.array );\n\n\t\treturn z;\n\n\t}\n\n\tsetZ( index, z ) {\n\n\t\tif ( this.normalized ) z = normalize( z, this.array );\n\n\t\tthis.array[ index * this.itemSize + 2 ] = z;\n\n\t\treturn this;\n\n\t}\n\n\tgetW( index ) {\n\n\t\tlet w = this.array[ index * this.itemSize + 3 ];\n\n\t\tif ( this.normalized ) w = denormalize( w, this.array );\n\n\t\treturn w;\n\n\t}\n\n\tsetW( index, w ) {\n\n\t\tif ( this.normalized ) w = normalize( w, this.array );\n\n\t\tthis.array[ index * this.itemSize + 3 ] = w;\n\n\t\treturn this;\n\n\t}\n\n\tsetXY( index, x, y ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = x;\n\t\tthis.array[ index + 1 ] = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZ( index, x, y, z ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = x;\n\t\tthis.array[ index + 1 ] = y;\n\t\tthis.array[ index + 2 ] = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZW( index, x, y, z, w ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\t\t\tw = normalize( w, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = x;\n\t\tthis.array[ index + 1 ] = y;\n\t\tthis.array[ index + 2 ] = z;\n\t\tthis.array[ index + 3 ] = w;\n\n\t\treturn this;\n\n\t}\n\n\tonUpload( callback ) {\n\n\t\tthis.onUploadCallback = callback;\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.array, this.itemSize ).copy( this );\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = {\n\t\t\titemSize: this.itemSize,\n\t\t\ttype: this.array.constructor.name,\n\t\t\tarray: Array.from( this.array ),\n\t\t\tnormalized: this.normalized\n\t\t};\n\n\t\tif ( this.name !== '' ) data.name = this.name;\n\t\tif ( this.usage !== StaticDrawUsage ) data.usage = this.usage;\n\n\t\treturn data;\n\n\t}\n\n}\n\n//\n\nclass Int8BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Int8Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Uint8BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Uint8Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Uint8ClampedBufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Uint8ClampedArray( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Int16BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Int16Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Uint16BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Uint16Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Int32BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Int32Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Uint32BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Uint32Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nclass Float16BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Uint16Array( array ), itemSize, normalized );\n\n\t\tthis.isFloat16BufferAttribute = true;\n\n\t}\n\n\tgetX( index ) {\n\n\t\tlet x = fromHalfFloat( this.array[ index * this.itemSize ] );\n\n\t\tif ( this.normalized ) x = denormalize( x, this.array );\n\n\t\treturn x;\n\n\t}\n\n\tsetX( index, x ) {\n\n\t\tif ( this.normalized ) x = normalize( x, this.array );\n\n\t\tthis.array[ index * this.itemSize ] = toHalfFloat( x );\n\n\t\treturn this;\n\n\t}\n\n\tgetY( index ) {\n\n\t\tlet y = fromHalfFloat( this.array[ index * this.itemSize + 1 ] );\n\n\t\tif ( this.normalized ) y = denormalize( y, this.array );\n\n\t\treturn y;\n\n\t}\n\n\tsetY( index, y ) {\n\n\t\tif ( this.normalized ) y = normalize( y, this.array );\n\n\t\tthis.array[ index * this.itemSize + 1 ] = toHalfFloat( y );\n\n\t\treturn this;\n\n\t}\n\n\tgetZ( index ) {\n\n\t\tlet z = fromHalfFloat( this.array[ index * this.itemSize + 2 ] );\n\n\t\tif ( this.normalized ) z = denormalize( z, this.array );\n\n\t\treturn z;\n\n\t}\n\n\tsetZ( index, z ) {\n\n\t\tif ( this.normalized ) z = normalize( z, this.array );\n\n\t\tthis.array[ index * this.itemSize + 2 ] = toHalfFloat( z );\n\n\t\treturn this;\n\n\t}\n\n\tgetW( index ) {\n\n\t\tlet w = fromHalfFloat( this.array[ index * this.itemSize + 3 ] );\n\n\t\tif ( this.normalized ) w = denormalize( w, this.array );\n\n\t\treturn w;\n\n\t}\n\n\tsetW( index, w ) {\n\n\t\tif ( this.normalized ) w = normalize( w, this.array );\n\n\t\tthis.array[ index * this.itemSize + 3 ] = toHalfFloat( w );\n\n\t\treturn this;\n\n\t}\n\n\tsetXY( index, x, y ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = toHalfFloat( x );\n\t\tthis.array[ index + 1 ] = toHalfFloat( y );\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZ( index, x, y, z ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = toHalfFloat( x );\n\t\tthis.array[ index + 1 ] = toHalfFloat( y );\n\t\tthis.array[ index + 2 ] = toHalfFloat( z );\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZW( index, x, y, z, w ) {\n\n\t\tindex *= this.itemSize;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\t\t\tw = normalize( w, this.array );\n\n\t\t}\n\n\t\tthis.array[ index + 0 ] = toHalfFloat( x );\n\t\tthis.array[ index + 1 ] = toHalfFloat( y );\n\t\tthis.array[ index + 2 ] = toHalfFloat( z );\n\t\tthis.array[ index + 3 ] = toHalfFloat( w );\n\n\t\treturn this;\n\n\t}\n\n}\n\n\nclass Float32BufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized ) {\n\n\t\tsuper( new Float32Array( array ), itemSize, normalized );\n\n\t}\n\n}\n\nlet _id$2 = 0;\n\nconst _m1$2 = /*@__PURE__*/ new Matrix4();\nconst _obj = /*@__PURE__*/ new Object3D();\nconst _offset = /*@__PURE__*/ new Vector3();\nconst _box$2 = /*@__PURE__*/ new Box3();\nconst _boxMorphTargets = /*@__PURE__*/ new Box3();\nconst _vector$8 = /*@__PURE__*/ new Vector3();\n\nclass BufferGeometry extends EventDispatcher {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isBufferGeometry = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _id$2 ++ } );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.name = '';\n\t\tthis.type = 'BufferGeometry';\n\n\t\tthis.index = null;\n\t\tthis.attributes = {};\n\n\t\tthis.morphAttributes = {};\n\t\tthis.morphTargetsRelative = false;\n\n\t\tthis.groups = [];\n\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t\tthis.drawRange = { start: 0, count: Infinity };\n\n\t\tthis.userData = {};\n\n\t}\n\n\tgetIndex() {\n\n\t\treturn this.index;\n\n\t}\n\n\tsetIndex( index ) {\n\n\t\tif ( Array.isArray( index ) ) {\n\n\t\t\tthis.index = new ( arrayNeedsUint32( index ) ? Uint32BufferAttribute : Uint16BufferAttribute )( index, 1 );\n\n\t\t} else {\n\n\t\t\tthis.index = index;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetAttribute( name ) {\n\n\t\treturn this.attributes[ name ];\n\n\t}\n\n\tsetAttribute( name, attribute ) {\n\n\t\tthis.attributes[ name ] = attribute;\n\n\t\treturn this;\n\n\t}\n\n\tdeleteAttribute( name ) {\n\n\t\tdelete this.attributes[ name ];\n\n\t\treturn this;\n\n\t}\n\n\thasAttribute( name ) {\n\n\t\treturn this.attributes[ name ] !== undefined;\n\n\t}\n\n\taddGroup( start, count, materialIndex = 0 ) {\n\n\t\tthis.groups.push( {\n\n\t\t\tstart: start,\n\t\t\tcount: count,\n\t\t\tmaterialIndex: materialIndex\n\n\t\t} );\n\n\t}\n\n\tclearGroups() {\n\n\t\tthis.groups = [];\n\n\t}\n\n\tsetDrawRange( start, count ) {\n\n\t\tthis.drawRange.start = start;\n\t\tthis.drawRange.count = count;\n\n\t}\n\n\tapplyMatrix4( matrix ) {\n\n\t\tconst position = this.attributes.position;\n\n\t\tif ( position !== undefined ) {\n\n\t\t\tposition.applyMatrix4( matrix );\n\n\t\t\tposition.needsUpdate = true;\n\n\t\t}\n\n\t\tconst normal = this.attributes.normal;\n\n\t\tif ( normal !== undefined ) {\n\n\t\t\tconst normalMatrix = new Matrix3().getNormalMatrix( matrix );\n\n\t\t\tnormal.applyNormalMatrix( normalMatrix );\n\n\t\t\tnormal.needsUpdate = true;\n\n\t\t}\n\n\t\tconst tangent = this.attributes.tangent;\n\n\t\tif ( tangent !== undefined ) {\n\n\t\t\ttangent.transformDirection( matrix );\n\n\t\t\ttangent.needsUpdate = true;\n\n\t\t}\n\n\t\tif ( this.boundingBox !== null ) {\n\n\t\t\tthis.computeBoundingBox();\n\n\t\t}\n\n\t\tif ( this.boundingSphere !== null ) {\n\n\t\t\tthis.computeBoundingSphere();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tapplyQuaternion( q ) {\n\n\t\t_m1$2.makeRotationFromQuaternion( q );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\trotateX( angle ) {\n\n\t\t// rotate geometry around world x-axis\n\n\t\t_m1$2.makeRotationX( angle );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\trotateY( angle ) {\n\n\t\t// rotate geometry around world y-axis\n\n\t\t_m1$2.makeRotationY( angle );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\trotateZ( angle ) {\n\n\t\t// rotate geometry around world z-axis\n\n\t\t_m1$2.makeRotationZ( angle );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( x, y, z ) {\n\n\t\t// translate geometry\n\n\t\t_m1$2.makeTranslation( x, y, z );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\tscale( x, y, z ) {\n\n\t\t// scale geometry\n\n\t\t_m1$2.makeScale( x, y, z );\n\n\t\tthis.applyMatrix4( _m1$2 );\n\n\t\treturn this;\n\n\t}\n\n\tlookAt( vector ) {\n\n\t\t_obj.lookAt( vector );\n\n\t\t_obj.updateMatrix();\n\n\t\tthis.applyMatrix4( _obj.matrix );\n\n\t\treturn this;\n\n\t}\n\n\tcenter() {\n\n\t\tthis.computeBoundingBox();\n\n\t\tthis.boundingBox.getCenter( _offset ).negate();\n\n\t\tthis.translate( _offset.x, _offset.y, _offset.z );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromPoints( points ) {\n\n\t\tconst position = [];\n\n\t\tfor ( let i = 0, l = points.length; i < l; i ++ ) {\n\n\t\t\tconst point = points[ i ];\n\t\t\tposition.push( point.x, point.y, point.z || 0 );\n\n\t\t}\n\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( position, 3 ) );\n\n\t\treturn this;\n\n\t}\n\n\tcomputeBoundingBox() {\n\n\t\tif ( this.boundingBox === null ) {\n\n\t\t\tthis.boundingBox = new Box3();\n\n\t\t}\n\n\t\tconst position = this.attributes.position;\n\t\tconst morphAttributesPosition = this.morphAttributes.position;\n\n\t\tif ( position && position.isGLBufferAttribute ) {\n\n\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingBox(): GLBufferAttribute requires a manual bounding box.', this );\n\n\t\t\tthis.boundingBox.set(\n\t\t\t\tnew Vector3( - Infinity, - Infinity, - Infinity ),\n\t\t\t\tnew Vector3( + Infinity, + Infinity, + Infinity )\n\t\t\t);\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( position !== undefined ) {\n\n\t\t\tthis.boundingBox.setFromBufferAttribute( position );\n\n\t\t\t// process morph attributes if present\n\n\t\t\tif ( morphAttributesPosition ) {\n\n\t\t\t\tfor ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst morphAttribute = morphAttributesPosition[ i ];\n\t\t\t\t\t_box$2.setFromBufferAttribute( morphAttribute );\n\n\t\t\t\t\tif ( this.morphTargetsRelative ) {\n\n\t\t\t\t\t\t_vector$8.addVectors( this.boundingBox.min, _box$2.min );\n\t\t\t\t\t\tthis.boundingBox.expandByPoint( _vector$8 );\n\n\t\t\t\t\t\t_vector$8.addVectors( this.boundingBox.max, _box$2.max );\n\t\t\t\t\t\tthis.boundingBox.expandByPoint( _vector$8 );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tthis.boundingBox.expandByPoint( _box$2.min );\n\t\t\t\t\t\tthis.boundingBox.expandByPoint( _box$2.max );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tthis.boundingBox.makeEmpty();\n\n\t\t}\n\n\t\tif ( isNaN( this.boundingBox.min.x ) || isNaN( this.boundingBox.min.y ) || isNaN( this.boundingBox.min.z ) ) {\n\n\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingBox(): Computed min/max have NaN values. The \"position\" attribute is likely to have NaN values.', this );\n\n\t\t}\n\n\t}\n\n\tcomputeBoundingSphere() {\n\n\t\tif ( this.boundingSphere === null ) {\n\n\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\tconst position = this.attributes.position;\n\t\tconst morphAttributesPosition = this.morphAttributes.position;\n\n\t\tif ( position && position.isGLBufferAttribute ) {\n\n\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingSphere(): GLBufferAttribute requires a manual bounding sphere.', this );\n\n\t\t\tthis.boundingSphere.set( new Vector3(), Infinity );\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( position ) {\n\n\t\t\t// first, find the center of the bounding sphere\n\n\t\t\tconst center = this.boundingSphere.center;\n\n\t\t\t_box$2.setFromBufferAttribute( position );\n\n\t\t\t// process morph attributes if present\n\n\t\t\tif ( morphAttributesPosition ) {\n\n\t\t\t\tfor ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst morphAttribute = morphAttributesPosition[ i ];\n\t\t\t\t\t_boxMorphTargets.setFromBufferAttribute( morphAttribute );\n\n\t\t\t\t\tif ( this.morphTargetsRelative ) {\n\n\t\t\t\t\t\t_vector$8.addVectors( _box$2.min, _boxMorphTargets.min );\n\t\t\t\t\t\t_box$2.expandByPoint( _vector$8 );\n\n\t\t\t\t\t\t_vector$8.addVectors( _box$2.max, _boxMorphTargets.max );\n\t\t\t\t\t\t_box$2.expandByPoint( _vector$8 );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t_box$2.expandByPoint( _boxMorphTargets.min );\n\t\t\t\t\t\t_box$2.expandByPoint( _boxMorphTargets.max );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_box$2.getCenter( center );\n\n\t\t\t// second, try to find a boundingSphere with a radius smaller than the\n\t\t\t// boundingSphere of the boundingBox: sqrt(3) smaller in the best case\n\n\t\t\tlet maxRadiusSq = 0;\n\n\t\t\tfor ( let i = 0, il = position.count; i < il; i ++ ) {\n\n\t\t\t\t_vector$8.fromBufferAttribute( position, i );\n\n\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );\n\n\t\t\t}\n\n\t\t\t// process morph attributes if present\n\n\t\t\tif ( morphAttributesPosition ) {\n\n\t\t\t\tfor ( let i = 0, il = morphAttributesPosition.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst morphAttribute = morphAttributesPosition[ i ];\n\t\t\t\t\tconst morphTargetsRelative = this.morphTargetsRelative;\n\n\t\t\t\t\tfor ( let j = 0, jl = morphAttribute.count; j < jl; j ++ ) {\n\n\t\t\t\t\t\t_vector$8.fromBufferAttribute( morphAttribute, j );\n\n\t\t\t\t\t\tif ( morphTargetsRelative ) {\n\n\t\t\t\t\t\t\t_offset.fromBufferAttribute( position, j );\n\t\t\t\t\t\t\t_vector$8.add( _offset );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, center.distanceToSquared( _vector$8 ) );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.boundingSphere.radius = Math.sqrt( maxRadiusSq );\n\n\t\t\tif ( isNaN( this.boundingSphere.radius ) ) {\n\n\t\t\t\tconsole.error( 'THREE.BufferGeometry.computeBoundingSphere(): Computed radius is NaN. The \"position\" attribute is likely to have NaN values.', this );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcomputeTangents() {\n\n\t\tconst index = this.index;\n\t\tconst attributes = this.attributes;\n\n\t\t// based on http://www.terathon.com/code/tangent.html\n\t\t// (per vertex tangents)\n\n\t\tif ( index === null ||\n\t\t\t attributes.position === undefined ||\n\t\t\t attributes.normal === undefined ||\n\t\t\t attributes.uv === undefined ) {\n\n\t\t\tconsole.error( 'THREE.BufferGeometry: .computeTangents() failed. Missing required attributes (index, position, normal or uv)' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst positionAttribute = attributes.position;\n\t\tconst normalAttribute = attributes.normal;\n\t\tconst uvAttribute = attributes.uv;\n\n\t\tif ( this.hasAttribute( 'tangent' ) === false ) {\n\n\t\t\tthis.setAttribute( 'tangent', new BufferAttribute( new Float32Array( 4 * positionAttribute.count ), 4 ) );\n\n\t\t}\n\n\t\tconst tangentAttribute = this.getAttribute( 'tangent' );\n\n\t\tconst tan1 = [], tan2 = [];\n\n\t\tfor ( let i = 0; i < positionAttribute.count; i ++ ) {\n\n\t\t\ttan1[ i ] = new Vector3();\n\t\t\ttan2[ i ] = new Vector3();\n\n\t\t}\n\n\t\tconst vA = new Vector3(),\n\t\t\tvB = new Vector3(),\n\t\t\tvC = new Vector3(),\n\n\t\t\tuvA = new Vector2(),\n\t\t\tuvB = new Vector2(),\n\t\t\tuvC = new Vector2(),\n\n\t\t\tsdir = new Vector3(),\n\t\t\ttdir = new Vector3();\n\n\t\tfunction handleTriangle( a, b, c ) {\n\n\t\t\tvA.fromBufferAttribute( positionAttribute, a );\n\t\t\tvB.fromBufferAttribute( positionAttribute, b );\n\t\t\tvC.fromBufferAttribute( positionAttribute, c );\n\n\t\t\tuvA.fromBufferAttribute( uvAttribute, a );\n\t\t\tuvB.fromBufferAttribute( uvAttribute, b );\n\t\t\tuvC.fromBufferAttribute( uvAttribute, c );\n\n\t\t\tvB.sub( vA );\n\t\t\tvC.sub( vA );\n\n\t\t\tuvB.sub( uvA );\n\t\t\tuvC.sub( uvA );\n\n\t\t\tconst r = 1.0 / ( uvB.x * uvC.y - uvC.x * uvB.y );\n\n\t\t\t// silently ignore degenerate uv triangles having coincident or colinear vertices\n\n\t\t\tif ( ! isFinite( r ) ) return;\n\n\t\t\tsdir.copy( vB ).multiplyScalar( uvC.y ).addScaledVector( vC, - uvB.y ).multiplyScalar( r );\n\t\t\ttdir.copy( vC ).multiplyScalar( uvB.x ).addScaledVector( vB, - uvC.x ).multiplyScalar( r );\n\n\t\t\ttan1[ a ].add( sdir );\n\t\t\ttan1[ b ].add( sdir );\n\t\t\ttan1[ c ].add( sdir );\n\n\t\t\ttan2[ a ].add( tdir );\n\t\t\ttan2[ b ].add( tdir );\n\t\t\ttan2[ c ].add( tdir );\n\n\t\t}\n\n\t\tlet groups = this.groups;\n\n\t\tif ( groups.length === 0 ) {\n\n\t\t\tgroups = [ {\n\t\t\t\tstart: 0,\n\t\t\t\tcount: index.count\n\t\t\t} ];\n\n\t\t}\n\n\t\tfor ( let i = 0, il = groups.length; i < il; ++ i ) {\n\n\t\t\tconst group = groups[ i ];\n\n\t\t\tconst start = group.start;\n\t\t\tconst count = group.count;\n\n\t\t\tfor ( let j = start, jl = start + count; j < jl; j += 3 ) {\n\n\t\t\t\thandleTriangle(\n\t\t\t\t\tindex.getX( j + 0 ),\n\t\t\t\t\tindex.getX( j + 1 ),\n\t\t\t\t\tindex.getX( j + 2 )\n\t\t\t\t);\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst tmp = new Vector3(), tmp2 = new Vector3();\n\t\tconst n = new Vector3(), n2 = new Vector3();\n\n\t\tfunction handleVertex( v ) {\n\n\t\t\tn.fromBufferAttribute( normalAttribute, v );\n\t\t\tn2.copy( n );\n\n\t\t\tconst t = tan1[ v ];\n\n\t\t\t// Gram-Schmidt orthogonalize\n\n\t\t\ttmp.copy( t );\n\t\t\ttmp.sub( n.multiplyScalar( n.dot( t ) ) ).normalize();\n\n\t\t\t// Calculate handedness\n\n\t\t\ttmp2.crossVectors( n2, t );\n\t\t\tconst test = tmp2.dot( tan2[ v ] );\n\t\t\tconst w = ( test < 0.0 ) ? - 1.0 : 1.0;\n\n\t\t\ttangentAttribute.setXYZW( v, tmp.x, tmp.y, tmp.z, w );\n\n\t\t}\n\n\t\tfor ( let i = 0, il = groups.length; i < il; ++ i ) {\n\n\t\t\tconst group = groups[ i ];\n\n\t\t\tconst start = group.start;\n\t\t\tconst count = group.count;\n\n\t\t\tfor ( let j = start, jl = start + count; j < jl; j += 3 ) {\n\n\t\t\t\thandleVertex( index.getX( j + 0 ) );\n\t\t\t\thandleVertex( index.getX( j + 1 ) );\n\t\t\t\thandleVertex( index.getX( j + 2 ) );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcomputeVertexNormals() {\n\n\t\tconst index = this.index;\n\t\tconst positionAttribute = this.getAttribute( 'position' );\n\n\t\tif ( positionAttribute !== undefined ) {\n\n\t\t\tlet normalAttribute = this.getAttribute( 'normal' );\n\n\t\t\tif ( normalAttribute === undefined ) {\n\n\t\t\t\tnormalAttribute = new BufferAttribute( new Float32Array( positionAttribute.count * 3 ), 3 );\n\t\t\t\tthis.setAttribute( 'normal', normalAttribute );\n\n\t\t\t} else {\n\n\t\t\t\t// reset existing normals to zero\n\n\t\t\t\tfor ( let i = 0, il = normalAttribute.count; i < il; i ++ ) {\n\n\t\t\t\t\tnormalAttribute.setXYZ( i, 0, 0, 0 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst pA = new Vector3(), pB = new Vector3(), pC = new Vector3();\n\t\t\tconst nA = new Vector3(), nB = new Vector3(), nC = new Vector3();\n\t\t\tconst cb = new Vector3(), ab = new Vector3();\n\n\t\t\t// indexed elements\n\n\t\t\tif ( index ) {\n\n\t\t\t\tfor ( let i = 0, il = index.count; i < il; i += 3 ) {\n\n\t\t\t\t\tconst vA = index.getX( i + 0 );\n\t\t\t\t\tconst vB = index.getX( i + 1 );\n\t\t\t\t\tconst vC = index.getX( i + 2 );\n\n\t\t\t\t\tpA.fromBufferAttribute( positionAttribute, vA );\n\t\t\t\t\tpB.fromBufferAttribute( positionAttribute, vB );\n\t\t\t\t\tpC.fromBufferAttribute( positionAttribute, vC );\n\n\t\t\t\t\tcb.subVectors( pC, pB );\n\t\t\t\t\tab.subVectors( pA, pB );\n\t\t\t\t\tcb.cross( ab );\n\n\t\t\t\t\tnA.fromBufferAttribute( normalAttribute, vA );\n\t\t\t\t\tnB.fromBufferAttribute( normalAttribute, vB );\n\t\t\t\t\tnC.fromBufferAttribute( normalAttribute, vC );\n\n\t\t\t\t\tnA.add( cb );\n\t\t\t\t\tnB.add( cb );\n\t\t\t\t\tnC.add( cb );\n\n\t\t\t\t\tnormalAttribute.setXYZ( vA, nA.x, nA.y, nA.z );\n\t\t\t\t\tnormalAttribute.setXYZ( vB, nB.x, nB.y, nB.z );\n\t\t\t\t\tnormalAttribute.setXYZ( vC, nC.x, nC.y, nC.z );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// non-indexed elements (unconnected triangle soup)\n\n\t\t\t\tfor ( let i = 0, il = positionAttribute.count; i < il; i += 3 ) {\n\n\t\t\t\t\tpA.fromBufferAttribute( positionAttribute, i + 0 );\n\t\t\t\t\tpB.fromBufferAttribute( positionAttribute, i + 1 );\n\t\t\t\t\tpC.fromBufferAttribute( positionAttribute, i + 2 );\n\n\t\t\t\t\tcb.subVectors( pC, pB );\n\t\t\t\t\tab.subVectors( pA, pB );\n\t\t\t\t\tcb.cross( ab );\n\n\t\t\t\t\tnormalAttribute.setXYZ( i + 0, cb.x, cb.y, cb.z );\n\t\t\t\t\tnormalAttribute.setXYZ( i + 1, cb.x, cb.y, cb.z );\n\t\t\t\t\tnormalAttribute.setXYZ( i + 2, cb.x, cb.y, cb.z );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.normalizeNormals();\n\n\t\t\tnormalAttribute.needsUpdate = true;\n\n\t\t}\n\n\t}\n\n\tnormalizeNormals() {\n\n\t\tconst normals = this.attributes.normal;\n\n\t\tfor ( let i = 0, il = normals.count; i < il; i ++ ) {\n\n\t\t\t_vector$8.fromBufferAttribute( normals, i );\n\n\t\t\t_vector$8.normalize();\n\n\t\t\tnormals.setXYZ( i, _vector$8.x, _vector$8.y, _vector$8.z );\n\n\t\t}\n\n\t}\n\n\ttoNonIndexed() {\n\n\t\tfunction convertBufferAttribute( attribute, indices ) {\n\n\t\t\tconst array = attribute.array;\n\t\t\tconst itemSize = attribute.itemSize;\n\t\t\tconst normalized = attribute.normalized;\n\n\t\t\tconst array2 = new array.constructor( indices.length * itemSize );\n\n\t\t\tlet index = 0, index2 = 0;\n\n\t\t\tfor ( let i = 0, l = indices.length; i < l; i ++ ) {\n\n\t\t\t\tif ( attribute.isInterleavedBufferAttribute ) {\n\n\t\t\t\t\tindex = indices[ i ] * attribute.data.stride + attribute.offset;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tindex = indices[ i ] * itemSize;\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let j = 0; j < itemSize; j ++ ) {\n\n\t\t\t\t\tarray2[ index2 ++ ] = array[ index ++ ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn new BufferAttribute( array2, itemSize, normalized );\n\n\t\t}\n\n\t\t//\n\n\t\tif ( this.index === null ) {\n\n\t\t\tconsole.warn( 'THREE.BufferGeometry.toNonIndexed(): BufferGeometry is already non-indexed.' );\n\t\t\treturn this;\n\n\t\t}\n\n\t\tconst geometry2 = new BufferGeometry();\n\n\t\tconst indices = this.index.array;\n\t\tconst attributes = this.attributes;\n\n\t\t// attributes\n\n\t\tfor ( const name in attributes ) {\n\n\t\t\tconst attribute = attributes[ name ];\n\n\t\t\tconst newAttribute = convertBufferAttribute( attribute, indices );\n\n\t\t\tgeometry2.setAttribute( name, newAttribute );\n\n\t\t}\n\n\t\t// morph attributes\n\n\t\tconst morphAttributes = this.morphAttributes;\n\n\t\tfor ( const name in morphAttributes ) {\n\n\t\t\tconst morphArray = [];\n\t\t\tconst morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes\n\n\t\t\tfor ( let i = 0, il = morphAttribute.length; i < il; i ++ ) {\n\n\t\t\t\tconst attribute = morphAttribute[ i ];\n\n\t\t\t\tconst newAttribute = convertBufferAttribute( attribute, indices );\n\n\t\t\t\tmorphArray.push( newAttribute );\n\n\t\t\t}\n\n\t\t\tgeometry2.morphAttributes[ name ] = morphArray;\n\n\t\t}\n\n\t\tgeometry2.morphTargetsRelative = this.morphTargetsRelative;\n\n\t\t// groups\n\n\t\tconst groups = this.groups;\n\n\t\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\tconst group = groups[ i ];\n\t\t\tgeometry2.addGroup( group.start, group.count, group.materialIndex );\n\n\t\t}\n\n\t\treturn geometry2;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'BufferGeometry',\n\t\t\t\tgenerator: 'BufferGeometry.toJSON'\n\t\t\t}\n\t\t};\n\n\t\t// standard BufferGeometry serialization\n\n\t\tdata.uuid = this.uuid;\n\t\tdata.type = this.type;\n\t\tif ( this.name !== '' ) data.name = this.name;\n\t\tif ( Object.keys( this.userData ).length > 0 ) data.userData = this.userData;\n\n\t\tif ( this.parameters !== undefined ) {\n\n\t\t\tconst parameters = this.parameters;\n\n\t\t\tfor ( const key in parameters ) {\n\n\t\t\t\tif ( parameters[ key ] !== undefined ) data[ key ] = parameters[ key ];\n\n\t\t\t}\n\n\t\t\treturn data;\n\n\t\t}\n\n\t\t// for simplicity the code assumes attributes are not shared across geometries, see #15811\n\n\t\tdata.data = { attributes: {} };\n\n\t\tconst index = this.index;\n\n\t\tif ( index !== null ) {\n\n\t\t\tdata.data.index = {\n\t\t\t\ttype: index.array.constructor.name,\n\t\t\t\tarray: Array.prototype.slice.call( index.array )\n\t\t\t};\n\n\t\t}\n\n\t\tconst attributes = this.attributes;\n\n\t\tfor ( const key in attributes ) {\n\n\t\t\tconst attribute = attributes[ key ];\n\n\t\t\tdata.data.attributes[ key ] = attribute.toJSON( data.data );\n\n\t\t}\n\n\t\tconst morphAttributes = {};\n\t\tlet hasMorphAttributes = false;\n\n\t\tfor ( const key in this.morphAttributes ) {\n\n\t\t\tconst attributeArray = this.morphAttributes[ key ];\n\n\t\t\tconst array = [];\n\n\t\t\tfor ( let i = 0, il = attributeArray.length; i < il; i ++ ) {\n\n\t\t\t\tconst attribute = attributeArray[ i ];\n\n\t\t\t\tarray.push( attribute.toJSON( data.data ) );\n\n\t\t\t}\n\n\t\t\tif ( array.length > 0 ) {\n\n\t\t\t\tmorphAttributes[ key ] = array;\n\n\t\t\t\thasMorphAttributes = true;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( hasMorphAttributes ) {\n\n\t\t\tdata.data.morphAttributes = morphAttributes;\n\t\t\tdata.data.morphTargetsRelative = this.morphTargetsRelative;\n\n\t\t}\n\n\t\tconst groups = this.groups;\n\n\t\tif ( groups.length > 0 ) {\n\n\t\t\tdata.data.groups = JSON.parse( JSON.stringify( groups ) );\n\n\t\t}\n\n\t\tconst boundingSphere = this.boundingSphere;\n\n\t\tif ( boundingSphere !== null ) {\n\n\t\t\tdata.data.boundingSphere = {\n\t\t\t\tcenter: boundingSphere.center.toArray(),\n\t\t\t\tradius: boundingSphere.radius\n\t\t\t};\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( source ) {\n\n\t\t// reset\n\n\t\tthis.index = null;\n\t\tthis.attributes = {};\n\t\tthis.morphAttributes = {};\n\t\tthis.groups = [];\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t\t// used for storing cloned, shared data\n\n\t\tconst data = {};\n\n\t\t// name\n\n\t\tthis.name = source.name;\n\n\t\t// index\n\n\t\tconst index = source.index;\n\n\t\tif ( index !== null ) {\n\n\t\t\tthis.setIndex( index.clone( data ) );\n\n\t\t}\n\n\t\t// attributes\n\n\t\tconst attributes = source.attributes;\n\n\t\tfor ( const name in attributes ) {\n\n\t\t\tconst attribute = attributes[ name ];\n\t\t\tthis.setAttribute( name, attribute.clone( data ) );\n\n\t\t}\n\n\t\t// morph attributes\n\n\t\tconst morphAttributes = source.morphAttributes;\n\n\t\tfor ( const name in morphAttributes ) {\n\n\t\t\tconst array = [];\n\t\t\tconst morphAttribute = morphAttributes[ name ]; // morphAttribute: array of Float32BufferAttributes\n\n\t\t\tfor ( let i = 0, l = morphAttribute.length; i < l; i ++ ) {\n\n\t\t\t\tarray.push( morphAttribute[ i ].clone( data ) );\n\n\t\t\t}\n\n\t\t\tthis.morphAttributes[ name ] = array;\n\n\t\t}\n\n\t\tthis.morphTargetsRelative = source.morphTargetsRelative;\n\n\t\t// groups\n\n\t\tconst groups = source.groups;\n\n\t\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\tconst group = groups[ i ];\n\t\t\tthis.addGroup( group.start, group.count, group.materialIndex );\n\n\t\t}\n\n\t\t// bounding box\n\n\t\tconst boundingBox = source.boundingBox;\n\n\t\tif ( boundingBox !== null ) {\n\n\t\t\tthis.boundingBox = boundingBox.clone();\n\n\t\t}\n\n\t\t// bounding sphere\n\n\t\tconst boundingSphere = source.boundingSphere;\n\n\t\tif ( boundingSphere !== null ) {\n\n\t\t\tthis.boundingSphere = boundingSphere.clone();\n\n\t\t}\n\n\t\t// draw range\n\n\t\tthis.drawRange.start = source.drawRange.start;\n\t\tthis.drawRange.count = source.drawRange.count;\n\n\t\t// user data\n\n\t\tthis.userData = source.userData;\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t}\n\n}\n\nconst _inverseMatrix$3 = /*@__PURE__*/ new Matrix4();\nconst _ray$3 = /*@__PURE__*/ new Ray();\nconst _sphere$6 = /*@__PURE__*/ new Sphere();\nconst _sphereHitAt = /*@__PURE__*/ new Vector3();\n\nconst _vA$1 = /*@__PURE__*/ new Vector3();\nconst _vB$1 = /*@__PURE__*/ new Vector3();\nconst _vC$1 = /*@__PURE__*/ new Vector3();\n\nconst _tempA = /*@__PURE__*/ new Vector3();\nconst _morphA = /*@__PURE__*/ new Vector3();\n\nconst _uvA$1 = /*@__PURE__*/ new Vector2();\nconst _uvB$1 = /*@__PURE__*/ new Vector2();\nconst _uvC$1 = /*@__PURE__*/ new Vector2();\n\nconst _normalA = /*@__PURE__*/ new Vector3();\nconst _normalB = /*@__PURE__*/ new Vector3();\nconst _normalC = /*@__PURE__*/ new Vector3();\n\nconst _intersectionPoint = /*@__PURE__*/ new Vector3();\nconst _intersectionPointWorld = /*@__PURE__*/ new Vector3();\n\nclass Mesh extends Object3D {\n\n\tconstructor( geometry = new BufferGeometry(), material = new MeshBasicMaterial() ) {\n\n\t\tsuper();\n\n\t\tthis.isMesh = true;\n\n\t\tthis.type = 'Mesh';\n\n\t\tthis.geometry = geometry;\n\t\tthis.material = material;\n\n\t\tthis.updateMorphTargets();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tif ( source.morphTargetInfluences !== undefined ) {\n\n\t\t\tthis.morphTargetInfluences = source.morphTargetInfluences.slice();\n\n\t\t}\n\n\t\tif ( source.morphTargetDictionary !== undefined ) {\n\n\t\t\tthis.morphTargetDictionary = Object.assign( {}, source.morphTargetDictionary );\n\n\t\t}\n\n\t\tthis.material = Array.isArray( source.material ) ? source.material.slice() : source.material;\n\t\tthis.geometry = source.geometry;\n\n\t\treturn this;\n\n\t}\n\n\tupdateMorphTargets() {\n\n\t\tconst geometry = this.geometry;\n\n\t\tconst morphAttributes = geometry.morphAttributes;\n\t\tconst keys = Object.keys( morphAttributes );\n\n\t\tif ( keys.length > 0 ) {\n\n\t\t\tconst morphAttribute = morphAttributes[ keys[ 0 ] ];\n\n\t\t\tif ( morphAttribute !== undefined ) {\n\n\t\t\t\tthis.morphTargetInfluences = [];\n\t\t\t\tthis.morphTargetDictionary = {};\n\n\t\t\t\tfor ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {\n\n\t\t\t\t\tconst name = morphAttribute[ m ].name || String( m );\n\n\t\t\t\t\tthis.morphTargetInfluences.push( 0 );\n\t\t\t\t\tthis.morphTargetDictionary[ name ] = m;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tgetVertexPosition( index, target ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst position = geometry.attributes.position;\n\t\tconst morphPosition = geometry.morphAttributes.position;\n\t\tconst morphTargetsRelative = geometry.morphTargetsRelative;\n\n\t\ttarget.fromBufferAttribute( position, index );\n\n\t\tconst morphInfluences = this.morphTargetInfluences;\n\n\t\tif ( morphPosition && morphInfluences ) {\n\n\t\t\t_morphA.set( 0, 0, 0 );\n\n\t\t\tfor ( let i = 0, il = morphPosition.length; i < il; i ++ ) {\n\n\t\t\t\tconst influence = morphInfluences[ i ];\n\t\t\t\tconst morphAttribute = morphPosition[ i ];\n\n\t\t\t\tif ( influence === 0 ) continue;\n\n\t\t\t\t_tempA.fromBufferAttribute( morphAttribute, index );\n\n\t\t\t\tif ( morphTargetsRelative ) {\n\n\t\t\t\t\t_morphA.addScaledVector( _tempA, influence );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_morphA.addScaledVector( _tempA.sub( target ), influence );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\ttarget.add( _morphA );\n\n\t\t}\n\n\t\treturn target;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst material = this.material;\n\t\tconst matrixWorld = this.matrixWorld;\n\n\t\tif ( material === undefined ) return;\n\n\t\t// test with bounding sphere in world space\n\n\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t_sphere$6.copy( geometry.boundingSphere );\n\t\t_sphere$6.applyMatrix4( matrixWorld );\n\n\t\t// check distance from ray origin to bounding sphere\n\n\t\t_ray$3.copy( raycaster.ray ).recast( raycaster.near );\n\n\t\tif ( _sphere$6.containsPoint( _ray$3.origin ) === false ) {\n\n\t\t\tif ( _ray$3.intersectSphere( _sphere$6, _sphereHitAt ) === null ) return;\n\n\t\t\tif ( _ray$3.origin.distanceToSquared( _sphereHitAt ) > ( raycaster.far - raycaster.near ) ** 2 ) return;\n\n\t\t}\n\n\t\t// convert ray to local space of mesh\n\n\t\t_inverseMatrix$3.copy( matrixWorld ).invert();\n\t\t_ray$3.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$3 );\n\n\t\t// test with bounding box in local space\n\n\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\tif ( _ray$3.intersectsBox( geometry.boundingBox ) === false ) return;\n\n\t\t}\n\n\t\t// test for intersections with geometry\n\n\t\tthis._computeIntersections( raycaster, intersects, _ray$3 );\n\n\t}\n\n\t_computeIntersections( raycaster, intersects, rayLocalSpace ) {\n\n\t\tlet intersection;\n\n\t\tconst geometry = this.geometry;\n\t\tconst material = this.material;\n\n\t\tconst index = geometry.index;\n\t\tconst position = geometry.attributes.position;\n\t\tconst uv = geometry.attributes.uv;\n\t\tconst uv1 = geometry.attributes.uv1;\n\t\tconst normal = geometry.attributes.normal;\n\t\tconst groups = geometry.groups;\n\t\tconst drawRange = geometry.drawRange;\n\n\t\tif ( index !== null ) {\n\n\t\t\t// indexed buffer geometry\n\n\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\tfor ( let i = 0, il = groups.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst group = groups[ i ];\n\t\t\t\t\tconst groupMaterial = material[ group.materialIndex ];\n\n\t\t\t\t\tconst start = Math.max( group.start, drawRange.start );\n\t\t\t\t\tconst end = Math.min( index.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );\n\n\t\t\t\t\tfor ( let j = start, jl = end; j < jl; j += 3 ) {\n\n\t\t\t\t\t\tconst a = index.getX( j );\n\t\t\t\t\t\tconst b = index.getX( j + 1 );\n\t\t\t\t\t\tconst c = index.getX( j + 2 );\n\n\t\t\t\t\t\tintersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );\n\n\t\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\t\tintersection.faceIndex = Math.floor( j / 3 ); // triangle number in indexed buffer semantics\n\t\t\t\t\t\t\tintersection.face.materialIndex = group.materialIndex;\n\t\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\t\tconst end = Math.min( index.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\t\tfor ( let i = start, il = end; i < il; i += 3 ) {\n\n\t\t\t\t\tconst a = index.getX( i );\n\t\t\t\t\tconst b = index.getX( i + 1 );\n\t\t\t\t\tconst c = index.getX( i + 2 );\n\n\t\t\t\t\tintersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );\n\n\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\tintersection.faceIndex = Math.floor( i / 3 ); // triangle number in indexed buffer semantics\n\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else if ( position !== undefined ) {\n\n\t\t\t// non-indexed buffer geometry\n\n\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\tfor ( let i = 0, il = groups.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst group = groups[ i ];\n\t\t\t\t\tconst groupMaterial = material[ group.materialIndex ];\n\n\t\t\t\t\tconst start = Math.max( group.start, drawRange.start );\n\t\t\t\t\tconst end = Math.min( position.count, Math.min( ( group.start + group.count ), ( drawRange.start + drawRange.count ) ) );\n\n\t\t\t\t\tfor ( let j = start, jl = end; j < jl; j += 3 ) {\n\n\t\t\t\t\t\tconst a = j;\n\t\t\t\t\t\tconst b = j + 1;\n\t\t\t\t\t\tconst c = j + 2;\n\n\t\t\t\t\t\tintersection = checkGeometryIntersection( this, groupMaterial, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );\n\n\t\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\t\tintersection.faceIndex = Math.floor( j / 3 ); // triangle number in non-indexed buffer semantics\n\t\t\t\t\t\t\tintersection.face.materialIndex = group.materialIndex;\n\t\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\t\tconst end = Math.min( position.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\t\tfor ( let i = start, il = end; i < il; i += 3 ) {\n\n\t\t\t\t\tconst a = i;\n\t\t\t\t\tconst b = i + 1;\n\t\t\t\t\tconst c = i + 2;\n\n\t\t\t\t\tintersection = checkGeometryIntersection( this, material, raycaster, rayLocalSpace, uv, uv1, normal, a, b, c );\n\n\t\t\t\t\tif ( intersection ) {\n\n\t\t\t\t\t\tintersection.faceIndex = Math.floor( i / 3 ); // triangle number in non-indexed buffer semantics\n\t\t\t\t\t\tintersects.push( intersection );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nfunction checkIntersection$1( object, material, raycaster, ray, pA, pB, pC, point ) {\n\n\tlet intersect;\n\n\tif ( material.side === BackSide ) {\n\n\t\tintersect = ray.intersectTriangle( pC, pB, pA, true, point );\n\n\t} else {\n\n\t\tintersect = ray.intersectTriangle( pA, pB, pC, ( material.side === FrontSide ), point );\n\n\t}\n\n\tif ( intersect === null ) return null;\n\n\t_intersectionPointWorld.copy( point );\n\t_intersectionPointWorld.applyMatrix4( object.matrixWorld );\n\n\tconst distance = raycaster.ray.origin.distanceTo( _intersectionPointWorld );\n\n\tif ( distance < raycaster.near || distance > raycaster.far ) return null;\n\n\treturn {\n\t\tdistance: distance,\n\t\tpoint: _intersectionPointWorld.clone(),\n\t\tobject: object\n\t};\n\n}\n\nfunction checkGeometryIntersection( object, material, raycaster, ray, uv, uv1, normal, a, b, c ) {\n\n\tobject.getVertexPosition( a, _vA$1 );\n\tobject.getVertexPosition( b, _vB$1 );\n\tobject.getVertexPosition( c, _vC$1 );\n\n\tconst intersection = checkIntersection$1( object, material, raycaster, ray, _vA$1, _vB$1, _vC$1, _intersectionPoint );\n\n\tif ( intersection ) {\n\n\t\tif ( uv ) {\n\n\t\t\t_uvA$1.fromBufferAttribute( uv, a );\n\t\t\t_uvB$1.fromBufferAttribute( uv, b );\n\t\t\t_uvC$1.fromBufferAttribute( uv, c );\n\n\t\t\tintersection.uv = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );\n\n\t\t}\n\n\t\tif ( uv1 ) {\n\n\t\t\t_uvA$1.fromBufferAttribute( uv1, a );\n\t\t\t_uvB$1.fromBufferAttribute( uv1, b );\n\t\t\t_uvC$1.fromBufferAttribute( uv1, c );\n\n\t\t\tintersection.uv1 = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _uvA$1, _uvB$1, _uvC$1, new Vector2() );\n\n\t\t}\n\n\t\tif ( normal ) {\n\n\t\t\t_normalA.fromBufferAttribute( normal, a );\n\t\t\t_normalB.fromBufferAttribute( normal, b );\n\t\t\t_normalC.fromBufferAttribute( normal, c );\n\n\t\t\tintersection.normal = Triangle.getInterpolation( _intersectionPoint, _vA$1, _vB$1, _vC$1, _normalA, _normalB, _normalC, new Vector3() );\n\n\t\t\tif ( intersection.normal.dot( ray.direction ) > 0 ) {\n\n\t\t\t\tintersection.normal.multiplyScalar( - 1 );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst face = {\n\t\t\ta: a,\n\t\t\tb: b,\n\t\t\tc: c,\n\t\t\tnormal: new Vector3(),\n\t\t\tmaterialIndex: 0\n\t\t};\n\n\t\tTriangle.getNormal( _vA$1, _vB$1, _vC$1, face.normal );\n\n\t\tintersection.face = face;\n\n\t}\n\n\treturn intersection;\n\n}\n\nclass BoxGeometry extends BufferGeometry {\n\n\tconstructor( width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'BoxGeometry';\n\n\t\tthis.parameters = {\n\t\t\twidth: width,\n\t\t\theight: height,\n\t\t\tdepth: depth,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\tdepthSegments: depthSegments\n\t\t};\n\n\t\tconst scope = this;\n\n\t\t// segments\n\n\t\twidthSegments = Math.floor( widthSegments );\n\t\theightSegments = Math.floor( heightSegments );\n\t\tdepthSegments = Math.floor( depthSegments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tlet numberOfVertices = 0;\n\t\tlet groupStart = 0;\n\n\t\t// build each side of the box geometry\n\n\t\tbuildPlane( 'z', 'y', 'x', - 1, - 1, depth, height, width, depthSegments, heightSegments, 0 ); // px\n\t\tbuildPlane( 'z', 'y', 'x', 1, - 1, depth, height, - width, depthSegments, heightSegments, 1 ); // nx\n\t\tbuildPlane( 'x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2 ); // py\n\t\tbuildPlane( 'x', 'z', 'y', 1, - 1, width, depth, - height, widthSegments, depthSegments, 3 ); // ny\n\t\tbuildPlane( 'x', 'y', 'z', 1, - 1, width, height, depth, widthSegments, heightSegments, 4 ); // pz\n\t\tbuildPlane( 'x', 'y', 'z', - 1, - 1, width, height, - depth, widthSegments, heightSegments, 5 ); // nz\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\tfunction buildPlane( u, v, w, udir, vdir, width, height, depth, gridX, gridY, materialIndex ) {\n\n\t\t\tconst segmentWidth = width / gridX;\n\t\t\tconst segmentHeight = height / gridY;\n\n\t\t\tconst widthHalf = width / 2;\n\t\t\tconst heightHalf = height / 2;\n\t\t\tconst depthHalf = depth / 2;\n\n\t\t\tconst gridX1 = gridX + 1;\n\t\t\tconst gridY1 = gridY + 1;\n\n\t\t\tlet vertexCounter = 0;\n\t\t\tlet groupCount = 0;\n\n\t\t\tconst vector = new Vector3();\n\n\t\t\t// generate vertices, normals and uvs\n\n\t\t\tfor ( let iy = 0; iy < gridY1; iy ++ ) {\n\n\t\t\t\tconst y = iy * segmentHeight - heightHalf;\n\n\t\t\t\tfor ( let ix = 0; ix < gridX1; ix ++ ) {\n\n\t\t\t\t\tconst x = ix * segmentWidth - widthHalf;\n\n\t\t\t\t\t// set values to correct vector component\n\n\t\t\t\t\tvector[ u ] = x * udir;\n\t\t\t\t\tvector[ v ] = y * vdir;\n\t\t\t\t\tvector[ w ] = depthHalf;\n\n\t\t\t\t\t// now apply vector to vertex buffer\n\n\t\t\t\t\tvertices.push( vector.x, vector.y, vector.z );\n\n\t\t\t\t\t// set values to correct vector component\n\n\t\t\t\t\tvector[ u ] = 0;\n\t\t\t\t\tvector[ v ] = 0;\n\t\t\t\t\tvector[ w ] = depth > 0 ? 1 : - 1;\n\n\t\t\t\t\t// now apply vector to normal buffer\n\n\t\t\t\t\tnormals.push( vector.x, vector.y, vector.z );\n\n\t\t\t\t\t// uvs\n\n\t\t\t\t\tuvs.push( ix / gridX );\n\t\t\t\t\tuvs.push( 1 - ( iy / gridY ) );\n\n\t\t\t\t\t// counters\n\n\t\t\t\t\tvertexCounter += 1;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// indices\n\n\t\t\t// 1. you need three indices to draw a single face\n\t\t\t// 2. a single segment consists of two faces\n\t\t\t// 3. so we need to generate six (2*3) indices per segment\n\n\t\t\tfor ( let iy = 0; iy < gridY; iy ++ ) {\n\n\t\t\t\tfor ( let ix = 0; ix < gridX; ix ++ ) {\n\n\t\t\t\t\tconst a = numberOfVertices + ix + gridX1 * iy;\n\t\t\t\t\tconst b = numberOfVertices + ix + gridX1 * ( iy + 1 );\n\t\t\t\t\tconst c = numberOfVertices + ( ix + 1 ) + gridX1 * ( iy + 1 );\n\t\t\t\t\tconst d = numberOfVertices + ( ix + 1 ) + gridX1 * iy;\n\n\t\t\t\t\t// faces\n\n\t\t\t\t\tindices.push( a, b, d );\n\t\t\t\t\tindices.push( b, c, d );\n\n\t\t\t\t\t// increase counter\n\n\t\t\t\t\tgroupCount += 6;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\t\tscope.addGroup( groupStart, groupCount, materialIndex );\n\n\t\t\t// calculate new start value for groups\n\n\t\t\tgroupStart += groupCount;\n\n\t\t\t// update total number of vertices\n\n\t\t\tnumberOfVertices += vertexCounter;\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new BoxGeometry( data.width, data.height, data.depth, data.widthSegments, data.heightSegments, data.depthSegments );\n\n\t}\n\n}\n\n/**\n * Uniform Utilities\n */\n\nfunction cloneUniforms( src ) {\n\n\tconst dst = {};\n\n\tfor ( const u in src ) {\n\n\t\tdst[ u ] = {};\n\n\t\tfor ( const p in src[ u ] ) {\n\n\t\t\tconst property = src[ u ][ p ];\n\n\t\t\tif ( property && ( property.isColor ||\n\t\t\t\tproperty.isMatrix3 || property.isMatrix4 ||\n\t\t\t\tproperty.isVector2 || property.isVector3 || property.isVector4 ||\n\t\t\t\tproperty.isTexture || property.isQuaternion ) ) {\n\n\t\t\t\tif ( property.isRenderTargetTexture ) {\n\n\t\t\t\t\tconsole.warn( 'UniformsUtils: Textures of render targets cannot be cloned via cloneUniforms() or mergeUniforms().' );\n\t\t\t\t\tdst[ u ][ p ] = null;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tdst[ u ][ p ] = property.clone();\n\n\t\t\t\t}\n\n\t\t\t} else if ( Array.isArray( property ) ) {\n\n\t\t\t\tdst[ u ][ p ] = property.slice();\n\n\t\t\t} else {\n\n\t\t\t\tdst[ u ][ p ] = property;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn dst;\n\n}\n\nfunction mergeUniforms( uniforms ) {\n\n\tconst merged = {};\n\n\tfor ( let u = 0; u < uniforms.length; u ++ ) {\n\n\t\tconst tmp = cloneUniforms( uniforms[ u ] );\n\n\t\tfor ( const p in tmp ) {\n\n\t\t\tmerged[ p ] = tmp[ p ];\n\n\t\t}\n\n\t}\n\n\treturn merged;\n\n}\n\nfunction cloneUniformsGroups( src ) {\n\n\tconst dst = [];\n\n\tfor ( let u = 0; u < src.length; u ++ ) {\n\n\t\tdst.push( src[ u ].clone() );\n\n\t}\n\n\treturn dst;\n\n}\n\nfunction getUnlitUniformColorSpace( renderer ) {\n\n\tconst currentRenderTarget = renderer.getRenderTarget();\n\n\tif ( currentRenderTarget === null ) {\n\n\t\t// https://github.com/mrdoob/three.js/pull/23937#issuecomment-1111067398\n\t\treturn renderer.outputColorSpace;\n\n\t}\n\n\t// https://github.com/mrdoob/three.js/issues/27868\n\tif ( currentRenderTarget.isXRRenderTarget === true ) {\n\n\t\treturn currentRenderTarget.texture.colorSpace;\n\n\t}\n\n\treturn ColorManagement.workingColorSpace;\n\n}\n\n// Legacy\n\nconst UniformsUtils = { clone: cloneUniforms, merge: mergeUniforms };\n\nvar default_vertex = \"void main() {\\n\\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\\n}\";\n\nvar default_fragment = \"void main() {\\n\\tgl_FragColor = vec4( 1.0, 0.0, 0.0, 1.0 );\\n}\";\n\nclass ShaderMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isShaderMaterial = true;\n\n\t\tthis.type = 'ShaderMaterial';\n\n\t\tthis.defines = {};\n\t\tthis.uniforms = {};\n\t\tthis.uniformsGroups = [];\n\n\t\tthis.vertexShader = default_vertex;\n\t\tthis.fragmentShader = default_fragment;\n\n\t\tthis.linewidth = 1;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\n\t\tthis.fog = false; // set to use scene fog\n\t\tthis.lights = false; // set to use scene lights\n\t\tthis.clipping = false; // set to use user-defined clipping planes\n\n\t\tthis.forceSinglePass = true;\n\n\t\tthis.extensions = {\n\t\t\tclipCullDistance: false, // set to use vertex shader clipping\n\t\t\tmultiDraw: false // set to use vertex shader multi_draw / enable gl_DrawID\n\t\t};\n\n\t\t// When rendered geometry doesn't include these attributes but the material does,\n\t\t// use these default values in WebGL. This avoids errors when buffer data is missing.\n\t\tthis.defaultAttributeValues = {\n\t\t\t'color': [ 1, 1, 1 ],\n\t\t\t'uv': [ 0, 0 ],\n\t\t\t'uv1': [ 0, 0 ]\n\t\t};\n\n\t\tthis.index0AttributeName = undefined;\n\t\tthis.uniformsNeedUpdate = false;\n\n\t\tthis.glslVersion = null;\n\n\t\tif ( parameters !== undefined ) {\n\n\t\t\tthis.setValues( parameters );\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.fragmentShader = source.fragmentShader;\n\t\tthis.vertexShader = source.vertexShader;\n\n\t\tthis.uniforms = cloneUniforms( source.uniforms );\n\t\tthis.uniformsGroups = cloneUniformsGroups( source.uniformsGroups );\n\n\t\tthis.defines = Object.assign( {}, source.defines );\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\t\tthis.fog = source.fog;\n\t\tthis.lights = source.lights;\n\t\tthis.clipping = source.clipping;\n\n\t\tthis.extensions = Object.assign( {}, source.extensions );\n\n\t\tthis.glslVersion = source.glslVersion;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.glslVersion = this.glslVersion;\n\t\tdata.uniforms = {};\n\n\t\tfor ( const name in this.uniforms ) {\n\n\t\t\tconst uniform = this.uniforms[ name ];\n\t\t\tconst value = uniform.value;\n\n\t\t\tif ( value && value.isTexture ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 't',\n\t\t\t\t\tvalue: value.toJSON( meta ).uuid\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isColor ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'c',\n\t\t\t\t\tvalue: value.getHex()\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isVector2 ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'v2',\n\t\t\t\t\tvalue: value.toArray()\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isVector3 ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'v3',\n\t\t\t\t\tvalue: value.toArray()\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isVector4 ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'v4',\n\t\t\t\t\tvalue: value.toArray()\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isMatrix3 ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'm3',\n\t\t\t\t\tvalue: value.toArray()\n\t\t\t\t};\n\n\t\t\t} else if ( value && value.isMatrix4 ) {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\ttype: 'm4',\n\t\t\t\t\tvalue: value.toArray()\n\t\t\t\t};\n\n\t\t\t} else {\n\n\t\t\t\tdata.uniforms[ name ] = {\n\t\t\t\t\tvalue: value\n\t\t\t\t};\n\n\t\t\t\t// note: the array variants v2v, v3v, v4v, m4v and tv are not supported so far\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( Object.keys( this.defines ).length > 0 ) data.defines = this.defines;\n\n\t\tdata.vertexShader = this.vertexShader;\n\t\tdata.fragmentShader = this.fragmentShader;\n\n\t\tdata.lights = this.lights;\n\t\tdata.clipping = this.clipping;\n\n\t\tconst extensions = {};\n\n\t\tfor ( const key in this.extensions ) {\n\n\t\t\tif ( this.extensions[ key ] === true ) extensions[ key ] = true;\n\n\t\t}\n\n\t\tif ( Object.keys( extensions ).length > 0 ) data.extensions = extensions;\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass Camera extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isCamera = true;\n\n\t\tthis.type = 'Camera';\n\n\t\tthis.matrixWorldInverse = new Matrix4();\n\n\t\tthis.projectionMatrix = new Matrix4();\n\t\tthis.projectionMatrixInverse = new Matrix4();\n\n\t\tthis.coordinateSystem = WebGLCoordinateSystem;\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.matrixWorldInverse.copy( source.matrixWorldInverse );\n\n\t\tthis.projectionMatrix.copy( source.projectionMatrix );\n\t\tthis.projectionMatrixInverse.copy( source.projectionMatrixInverse );\n\n\t\tthis.coordinateSystem = source.coordinateSystem;\n\n\t\treturn this;\n\n\t}\n\n\tgetWorldDirection( target ) {\n\n\t\treturn super.getWorldDirection( target ).negate();\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t\tthis.matrixWorldInverse.copy( this.matrixWorld ).invert();\n\n\t}\n\n\tupdateWorldMatrix( updateParents, updateChildren ) {\n\n\t\tsuper.updateWorldMatrix( updateParents, updateChildren );\n\n\t\tthis.matrixWorldInverse.copy( this.matrixWorld ).invert();\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nconst _v3$1 = /*@__PURE__*/ new Vector3();\nconst _minTarget = /*@__PURE__*/ new Vector2();\nconst _maxTarget = /*@__PURE__*/ new Vector2();\n\n\nclass PerspectiveCamera extends Camera {\n\n\tconstructor( fov = 50, aspect = 1, near = 0.1, far = 2000 ) {\n\n\t\tsuper();\n\n\t\tthis.isPerspectiveCamera = true;\n\n\t\tthis.type = 'PerspectiveCamera';\n\n\t\tthis.fov = fov;\n\t\tthis.zoom = 1;\n\n\t\tthis.near = near;\n\t\tthis.far = far;\n\t\tthis.focus = 10;\n\n\t\tthis.aspect = aspect;\n\t\tthis.view = null;\n\n\t\tthis.filmGauge = 35;\t// width of the film (default in millimeters)\n\t\tthis.filmOffset = 0;\t// horizontal film offset (same unit as gauge)\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.fov = source.fov;\n\t\tthis.zoom = source.zoom;\n\n\t\tthis.near = source.near;\n\t\tthis.far = source.far;\n\t\tthis.focus = source.focus;\n\n\t\tthis.aspect = source.aspect;\n\t\tthis.view = source.view === null ? null : Object.assign( {}, source.view );\n\n\t\tthis.filmGauge = source.filmGauge;\n\t\tthis.filmOffset = source.filmOffset;\n\n\t\treturn this;\n\n\t}\n\n\t/**\n\t * Sets the FOV by focal length in respect to the current .filmGauge.\n\t *\n\t * The default film gauge is 35, so that the focal length can be specified for\n\t * a 35mm (full frame) camera.\n\t *\n\t * Values for focal length and film gauge must have the same unit.\n\t */\n\tsetFocalLength( focalLength ) {\n\n\t\t/** see {@link http://www.bobatkins.com/photography/technical/field_of_view.html} */\n\t\tconst vExtentSlope = 0.5 * this.getFilmHeight() / focalLength;\n\n\t\tthis.fov = RAD2DEG * 2 * Math.atan( vExtentSlope );\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\t/**\n\t * Calculates the focal length from the current .fov and .filmGauge.\n\t */\n\tgetFocalLength() {\n\n\t\tconst vExtentSlope = Math.tan( DEG2RAD * 0.5 * this.fov );\n\n\t\treturn 0.5 * this.getFilmHeight() / vExtentSlope;\n\n\t}\n\n\tgetEffectiveFOV() {\n\n\t\treturn RAD2DEG * 2 * Math.atan(\n\t\t\tMath.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom );\n\n\t}\n\n\tgetFilmWidth() {\n\n\t\t// film not completely covered in portrait format (aspect < 1)\n\t\treturn this.filmGauge * Math.min( this.aspect, 1 );\n\n\t}\n\n\tgetFilmHeight() {\n\n\t\t// film not completely covered in landscape format (aspect > 1)\n\t\treturn this.filmGauge / Math.max( this.aspect, 1 );\n\n\t}\n\n\t/**\n\t * Computes the 2D bounds of the camera's viewable rectangle at a given distance along the viewing direction.\n\t * Sets minTarget and maxTarget to the coordinates of the lower-left and upper-right corners of the view rectangle.\n\t */\n\tgetViewBounds( distance, minTarget, maxTarget ) {\n\n\t\t_v3$1.set( - 1, - 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse );\n\n\t\tminTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z );\n\n\t\t_v3$1.set( 1, 1, 0.5 ).applyMatrix4( this.projectionMatrixInverse );\n\n\t\tmaxTarget.set( _v3$1.x, _v3$1.y ).multiplyScalar( - distance / _v3$1.z );\n\n\t}\n\n\t/**\n\t * Computes the width and height of the camera's viewable rectangle at a given distance along the viewing direction.\n\t * Copies the result into the target Vector2, where x is width and y is height.\n\t */\n\tgetViewSize( distance, target ) {\n\n\t\tthis.getViewBounds( distance, _minTarget, _maxTarget );\n\n\t\treturn target.subVectors( _maxTarget, _minTarget );\n\n\t}\n\n\t/**\n\t * Sets an offset in a larger frustum. This is useful for multi-window or\n\t * multi-monitor/multi-machine setups.\n\t *\n\t * For example, if you have 3x2 monitors and each monitor is 1920x1080 and\n\t * the monitors are in grid like this\n\t *\n\t * +---+---+---+\n\t * | A | B | C |\n\t * +---+---+---+\n\t * | D | E | F |\n\t * +---+---+---+\n\t *\n\t * then for each monitor you would call it like this\n\t *\n\t * const w = 1920;\n\t * const h = 1080;\n\t * const fullWidth = w * 3;\n\t * const fullHeight = h * 2;\n\t *\n\t * --A--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 0, w, h );\n\t * --B--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 0, w, h );\n\t * --C--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 0, w, h );\n\t * --D--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 0, h * 1, w, h );\n\t * --E--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 1, h * 1, w, h );\n\t * --F--\n\t * camera.setViewOffset( fullWidth, fullHeight, w * 2, h * 1, w, h );\n\t *\n\t * Note there is no reason monitors have to be the same size or in a grid.\n\t */\n\tsetViewOffset( fullWidth, fullHeight, x, y, width, height ) {\n\n\t\tthis.aspect = fullWidth / fullHeight;\n\n\t\tif ( this.view === null ) {\n\n\t\t\tthis.view = {\n\t\t\t\tenabled: true,\n\t\t\t\tfullWidth: 1,\n\t\t\t\tfullHeight: 1,\n\t\t\t\toffsetX: 0,\n\t\t\t\toffsetY: 0,\n\t\t\t\twidth: 1,\n\t\t\t\theight: 1\n\t\t\t};\n\n\t\t}\n\n\t\tthis.view.enabled = true;\n\t\tthis.view.fullWidth = fullWidth;\n\t\tthis.view.fullHeight = fullHeight;\n\t\tthis.view.offsetX = x;\n\t\tthis.view.offsetY = y;\n\t\tthis.view.width = width;\n\t\tthis.view.height = height;\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tclearViewOffset() {\n\n\t\tif ( this.view !== null ) {\n\n\t\t\tthis.view.enabled = false;\n\n\t\t}\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tupdateProjectionMatrix() {\n\n\t\tconst near = this.near;\n\t\tlet top = near * Math.tan( DEG2RAD * 0.5 * this.fov ) / this.zoom;\n\t\tlet height = 2 * top;\n\t\tlet width = this.aspect * height;\n\t\tlet left = - 0.5 * width;\n\t\tconst view = this.view;\n\n\t\tif ( this.view !== null && this.view.enabled ) {\n\n\t\t\tconst fullWidth = view.fullWidth,\n\t\t\t\tfullHeight = view.fullHeight;\n\n\t\t\tleft += view.offsetX * width / fullWidth;\n\t\t\ttop -= view.offsetY * height / fullHeight;\n\t\t\twidth *= view.width / fullWidth;\n\t\t\theight *= view.height / fullHeight;\n\n\t\t}\n\n\t\tconst skew = this.filmOffset;\n\t\tif ( skew !== 0 ) left += near * skew / this.getFilmWidth();\n\n\t\tthis.projectionMatrix.makePerspective( left, left + width, top, top - height, near, this.far, this.coordinateSystem );\n\n\t\tthis.projectionMatrixInverse.copy( this.projectionMatrix ).invert();\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.object.fov = this.fov;\n\t\tdata.object.zoom = this.zoom;\n\n\t\tdata.object.near = this.near;\n\t\tdata.object.far = this.far;\n\t\tdata.object.focus = this.focus;\n\n\t\tdata.object.aspect = this.aspect;\n\n\t\tif ( this.view !== null ) data.object.view = Object.assign( {}, this.view );\n\n\t\tdata.object.filmGauge = this.filmGauge;\n\t\tdata.object.filmOffset = this.filmOffset;\n\n\t\treturn data;\n\n\t}\n\n}\n\nconst fov = - 90; // negative fov is not an error\nconst aspect = 1;\n\nclass CubeCamera extends Object3D {\n\n\tconstructor( near, far, renderTarget ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'CubeCamera';\n\n\t\tthis.renderTarget = renderTarget;\n\t\tthis.coordinateSystem = null;\n\t\tthis.activeMipmapLevel = 0;\n\n\t\tconst cameraPX = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraPX.layers = this.layers;\n\t\tthis.add( cameraPX );\n\n\t\tconst cameraNX = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraNX.layers = this.layers;\n\t\tthis.add( cameraNX );\n\n\t\tconst cameraPY = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraPY.layers = this.layers;\n\t\tthis.add( cameraPY );\n\n\t\tconst cameraNY = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraNY.layers = this.layers;\n\t\tthis.add( cameraNY );\n\n\t\tconst cameraPZ = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraPZ.layers = this.layers;\n\t\tthis.add( cameraPZ );\n\n\t\tconst cameraNZ = new PerspectiveCamera( fov, aspect, near, far );\n\t\tcameraNZ.layers = this.layers;\n\t\tthis.add( cameraNZ );\n\n\t}\n\n\tupdateCoordinateSystem() {\n\n\t\tconst coordinateSystem = this.coordinateSystem;\n\n\t\tconst cameras = this.children.concat();\n\n\t\tconst [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = cameras;\n\n\t\tfor ( const camera of cameras ) this.remove( camera );\n\n\t\tif ( coordinateSystem === WebGLCoordinateSystem ) {\n\n\t\t\tcameraPX.up.set( 0, 1, 0 );\n\t\t\tcameraPX.lookAt( 1, 0, 0 );\n\n\t\t\tcameraNX.up.set( 0, 1, 0 );\n\t\t\tcameraNX.lookAt( - 1, 0, 0 );\n\n\t\t\tcameraPY.up.set( 0, 0, - 1 );\n\t\t\tcameraPY.lookAt( 0, 1, 0 );\n\n\t\t\tcameraNY.up.set( 0, 0, 1 );\n\t\t\tcameraNY.lookAt( 0, - 1, 0 );\n\n\t\t\tcameraPZ.up.set( 0, 1, 0 );\n\t\t\tcameraPZ.lookAt( 0, 0, 1 );\n\n\t\t\tcameraNZ.up.set( 0, 1, 0 );\n\t\t\tcameraNZ.lookAt( 0, 0, - 1 );\n\n\t\t} else if ( coordinateSystem === WebGPUCoordinateSystem ) {\n\n\t\t\tcameraPX.up.set( 0, - 1, 0 );\n\t\t\tcameraPX.lookAt( - 1, 0, 0 );\n\n\t\t\tcameraNX.up.set( 0, - 1, 0 );\n\t\t\tcameraNX.lookAt( 1, 0, 0 );\n\n\t\t\tcameraPY.up.set( 0, 0, 1 );\n\t\t\tcameraPY.lookAt( 0, 1, 0 );\n\n\t\t\tcameraNY.up.set( 0, 0, - 1 );\n\t\t\tcameraNY.lookAt( 0, - 1, 0 );\n\n\t\t\tcameraPZ.up.set( 0, - 1, 0 );\n\t\t\tcameraPZ.lookAt( 0, 0, 1 );\n\n\t\t\tcameraNZ.up.set( 0, - 1, 0 );\n\t\t\tcameraNZ.lookAt( 0, 0, - 1 );\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'THREE.CubeCamera.updateCoordinateSystem(): Invalid coordinate system: ' + coordinateSystem );\n\n\t\t}\n\n\t\tfor ( const camera of cameras ) {\n\n\t\t\tthis.add( camera );\n\n\t\t\tcamera.updateMatrixWorld();\n\n\t\t}\n\n\t}\n\n\tupdate( renderer, scene ) {\n\n\t\tif ( this.parent === null ) this.updateMatrixWorld();\n\n\t\tconst { renderTarget, activeMipmapLevel } = this;\n\n\t\tif ( this.coordinateSystem !== renderer.coordinateSystem ) {\n\n\t\t\tthis.coordinateSystem = renderer.coordinateSystem;\n\n\t\t\tthis.updateCoordinateSystem();\n\n\t\t}\n\n\t\tconst [ cameraPX, cameraNX, cameraPY, cameraNY, cameraPZ, cameraNZ ] = this.children;\n\n\t\tconst currentRenderTarget = renderer.getRenderTarget();\n\t\tconst currentActiveCubeFace = renderer.getActiveCubeFace();\n\t\tconst currentActiveMipmapLevel = renderer.getActiveMipmapLevel();\n\n\t\tconst currentXrEnabled = renderer.xr.enabled;\n\n\t\trenderer.xr.enabled = false;\n\n\t\tconst generateMipmaps = renderTarget.texture.generateMipmaps;\n\n\t\trenderTarget.texture.generateMipmaps = false;\n\n\t\trenderer.setRenderTarget( renderTarget, 0, activeMipmapLevel );\n\t\trenderer.render( scene, cameraPX );\n\n\t\trenderer.setRenderTarget( renderTarget, 1, activeMipmapLevel );\n\t\trenderer.render( scene, cameraNX );\n\n\t\trenderer.setRenderTarget( renderTarget, 2, activeMipmapLevel );\n\t\trenderer.render( scene, cameraPY );\n\n\t\trenderer.setRenderTarget( renderTarget, 3, activeMipmapLevel );\n\t\trenderer.render( scene, cameraNY );\n\n\t\trenderer.setRenderTarget( renderTarget, 4, activeMipmapLevel );\n\t\trenderer.render( scene, cameraPZ );\n\n\t\t// mipmaps are generated during the last call of render()\n\t\t// at this point, all sides of the cube render target are defined\n\n\t\trenderTarget.texture.generateMipmaps = generateMipmaps;\n\n\t\trenderer.setRenderTarget( renderTarget, 5, activeMipmapLevel );\n\t\trenderer.render( scene, cameraNZ );\n\n\t\trenderer.setRenderTarget( currentRenderTarget, currentActiveCubeFace, currentActiveMipmapLevel );\n\n\t\trenderer.xr.enabled = currentXrEnabled;\n\n\t\trenderTarget.texture.needsPMREMUpdate = true;\n\n\t}\n\n}\n\nclass CubeTexture extends Texture {\n\n\tconstructor( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace ) {\n\n\t\timages = images !== undefined ? images : [];\n\t\tmapping = mapping !== undefined ? mapping : CubeReflectionMapping;\n\n\t\tsuper( images, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );\n\n\t\tthis.isCubeTexture = true;\n\n\t\tthis.flipY = false;\n\n\t}\n\n\tget images() {\n\n\t\treturn this.image;\n\n\t}\n\n\tset images( value ) {\n\n\t\tthis.image = value;\n\n\t}\n\n}\n\nclass WebGLCubeRenderTarget extends WebGLRenderTarget {\n\n\tconstructor( size = 1, options = {} ) {\n\n\t\tsuper( size, size, options );\n\n\t\tthis.isWebGLCubeRenderTarget = true;\n\n\t\tconst image = { width: size, height: size, depth: 1 };\n\t\tconst images = [ image, image, image, image, image, image ];\n\n\t\tthis.texture = new CubeTexture( images, options.mapping, options.wrapS, options.wrapT, options.magFilter, options.minFilter, options.format, options.type, options.anisotropy, options.colorSpace );\n\n\t\t// By convention -- likely based on the RenderMan spec from the 1990's -- cube maps are specified by WebGL (and three.js)\n\t\t// in a coordinate system in which positive-x is to the right when looking up the positive-z axis -- in other words,\n\t\t// in a left-handed coordinate system. By continuing this convention, preexisting cube maps continued to render correctly.\n\n\t\t// three.js uses a right-handed coordinate system. So environment maps used in three.js appear to have px and nx swapped\n\t\t// and the flag isRenderTargetTexture controls this conversion. The flip is not required when using WebGLCubeRenderTarget.texture\n\t\t// as a cube texture (this is detected when isRenderTargetTexture is set to true for cube textures).\n\n\t\tthis.texture.isRenderTargetTexture = true;\n\n\t\tthis.texture.generateMipmaps = options.generateMipmaps !== undefined ? options.generateMipmaps : false;\n\t\tthis.texture.minFilter = options.minFilter !== undefined ? options.minFilter : LinearFilter;\n\n\t}\n\n\tfromEquirectangularTexture( renderer, texture ) {\n\n\t\tthis.texture.type = texture.type;\n\t\tthis.texture.colorSpace = texture.colorSpace;\n\n\t\tthis.texture.generateMipmaps = texture.generateMipmaps;\n\t\tthis.texture.minFilter = texture.minFilter;\n\t\tthis.texture.magFilter = texture.magFilter;\n\n\t\tconst shader = {\n\n\t\t\tuniforms: {\n\t\t\t\ttEquirect: { value: null },\n\t\t\t},\n\n\t\t\tvertexShader: /* glsl */`\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`,\n\n\t\t\tfragmentShader: /* glsl */`\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`\n\t\t};\n\n\t\tconst geometry = new BoxGeometry( 5, 5, 5 );\n\n\t\tconst material = new ShaderMaterial( {\n\n\t\t\tname: 'CubemapFromEquirect',\n\n\t\t\tuniforms: cloneUniforms( shader.uniforms ),\n\t\t\tvertexShader: shader.vertexShader,\n\t\t\tfragmentShader: shader.fragmentShader,\n\t\t\tside: BackSide,\n\t\t\tblending: NoBlending\n\n\t\t} );\n\n\t\tmaterial.uniforms.tEquirect.value = texture;\n\n\t\tconst mesh = new Mesh( geometry, material );\n\n\t\tconst currentMinFilter = texture.minFilter;\n\n\t\t// Avoid blurred poles\n\t\tif ( texture.minFilter === LinearMipmapLinearFilter ) texture.minFilter = LinearFilter;\n\n\t\tconst camera = new CubeCamera( 1, 10, this );\n\t\tcamera.update( renderer, mesh );\n\n\t\ttexture.minFilter = currentMinFilter;\n\n\t\tmesh.geometry.dispose();\n\t\tmesh.material.dispose();\n\n\t\treturn this;\n\n\t}\n\n\tclear( renderer, color, depth, stencil ) {\n\n\t\tconst currentRenderTarget = renderer.getRenderTarget();\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\trenderer.setRenderTarget( this, i );\n\n\t\t\trenderer.clear( color, depth, stencil );\n\n\t\t}\n\n\t\trenderer.setRenderTarget( currentRenderTarget );\n\n\t}\n\n}\n\nconst _vector1 = /*@__PURE__*/ new Vector3();\nconst _vector2 = /*@__PURE__*/ new Vector3();\nconst _normalMatrix = /*@__PURE__*/ new Matrix3();\n\nclass Plane {\n\n\tconstructor( normal = new Vector3( 1, 0, 0 ), constant = 0 ) {\n\n\t\tthis.isPlane = true;\n\n\t\t// normal is assumed to be normalized\n\n\t\tthis.normal = normal;\n\t\tthis.constant = constant;\n\n\t}\n\n\tset( normal, constant ) {\n\n\t\tthis.normal.copy( normal );\n\t\tthis.constant = constant;\n\n\t\treturn this;\n\n\t}\n\n\tsetComponents( x, y, z, w ) {\n\n\t\tthis.normal.set( x, y, z );\n\t\tthis.constant = w;\n\n\t\treturn this;\n\n\t}\n\n\tsetFromNormalAndCoplanarPoint( normal, point ) {\n\n\t\tthis.normal.copy( normal );\n\t\tthis.constant = - point.dot( this.normal );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromCoplanarPoints( a, b, c ) {\n\n\t\tconst normal = _vector1.subVectors( c, b ).cross( _vector2.subVectors( a, b ) ).normalize();\n\n\t\t// Q: should an error be thrown if normal is zero (e.g. degenerate plane)?\n\n\t\tthis.setFromNormalAndCoplanarPoint( normal, a );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( plane ) {\n\n\t\tthis.normal.copy( plane.normal );\n\t\tthis.constant = plane.constant;\n\n\t\treturn this;\n\n\t}\n\n\tnormalize() {\n\n\t\t// Note: will lead to a divide by zero if the plane is invalid.\n\n\t\tconst inverseNormalLength = 1.0 / this.normal.length();\n\t\tthis.normal.multiplyScalar( inverseNormalLength );\n\t\tthis.constant *= inverseNormalLength;\n\n\t\treturn this;\n\n\t}\n\n\tnegate() {\n\n\t\tthis.constant *= - 1;\n\t\tthis.normal.negate();\n\n\t\treturn this;\n\n\t}\n\n\tdistanceToPoint( point ) {\n\n\t\treturn this.normal.dot( point ) + this.constant;\n\n\t}\n\n\tdistanceToSphere( sphere ) {\n\n\t\treturn this.distanceToPoint( sphere.center ) - sphere.radius;\n\n\t}\n\n\tprojectPoint( point, target ) {\n\n\t\treturn target.copy( point ).addScaledVector( this.normal, - this.distanceToPoint( point ) );\n\n\t}\n\n\tintersectLine( line, target ) {\n\n\t\tconst direction = line.delta( _vector1 );\n\n\t\tconst denominator = this.normal.dot( direction );\n\n\t\tif ( denominator === 0 ) {\n\n\t\t\t// line is coplanar, return origin\n\t\t\tif ( this.distanceToPoint( line.start ) === 0 ) {\n\n\t\t\t\treturn target.copy( line.start );\n\n\t\t\t}\n\n\t\t\t// Unsure if this is the correct method to handle this case.\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst t = - ( line.start.dot( this.normal ) + this.constant ) / denominator;\n\n\t\tif ( t < 0 || t > 1 ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\treturn target.copy( line.start ).addScaledVector( direction, t );\n\n\t}\n\n\tintersectsLine( line ) {\n\n\t\t// Note: this tests if a line intersects the plane, not whether it (or its end-points) are coplanar with it.\n\n\t\tconst startSign = this.distanceToPoint( line.start );\n\t\tconst endSign = this.distanceToPoint( line.end );\n\n\t\treturn ( startSign < 0 && endSign > 0 ) || ( endSign < 0 && startSign > 0 );\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\treturn box.intersectsPlane( this );\n\n\t}\n\n\tintersectsSphere( sphere ) {\n\n\t\treturn sphere.intersectsPlane( this );\n\n\t}\n\n\tcoplanarPoint( target ) {\n\n\t\treturn target.copy( this.normal ).multiplyScalar( - this.constant );\n\n\t}\n\n\tapplyMatrix4( matrix, optionalNormalMatrix ) {\n\n\t\tconst normalMatrix = optionalNormalMatrix || _normalMatrix.getNormalMatrix( matrix );\n\n\t\tconst referencePoint = this.coplanarPoint( _vector1 ).applyMatrix4( matrix );\n\n\t\tconst normal = this.normal.applyMatrix3( normalMatrix ).normalize();\n\n\t\tthis.constant = - referencePoint.dot( normal );\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( offset ) {\n\n\t\tthis.constant -= offset.dot( this.normal );\n\n\t\treturn this;\n\n\t}\n\n\tequals( plane ) {\n\n\t\treturn plane.normal.equals( this.normal ) && ( plane.constant === this.constant );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nconst _sphere$5 = /*@__PURE__*/ new Sphere();\nconst _vector$7 = /*@__PURE__*/ new Vector3();\n\nclass Frustum {\n\n\tconstructor( p0 = new Plane(), p1 = new Plane(), p2 = new Plane(), p3 = new Plane(), p4 = new Plane(), p5 = new Plane() ) {\n\n\t\tthis.planes = [ p0, p1, p2, p3, p4, p5 ];\n\n\t}\n\n\tset( p0, p1, p2, p3, p4, p5 ) {\n\n\t\tconst planes = this.planes;\n\n\t\tplanes[ 0 ].copy( p0 );\n\t\tplanes[ 1 ].copy( p1 );\n\t\tplanes[ 2 ].copy( p2 );\n\t\tplanes[ 3 ].copy( p3 );\n\t\tplanes[ 4 ].copy( p4 );\n\t\tplanes[ 5 ].copy( p5 );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( frustum ) {\n\n\t\tconst planes = this.planes;\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\tplanes[ i ].copy( frustum.planes[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetFromProjectionMatrix( m, coordinateSystem = WebGLCoordinateSystem ) {\n\n\t\tconst planes = this.planes;\n\t\tconst me = m.elements;\n\t\tconst me0 = me[ 0 ], me1 = me[ 1 ], me2 = me[ 2 ], me3 = me[ 3 ];\n\t\tconst me4 = me[ 4 ], me5 = me[ 5 ], me6 = me[ 6 ], me7 = me[ 7 ];\n\t\tconst me8 = me[ 8 ], me9 = me[ 9 ], me10 = me[ 10 ], me11 = me[ 11 ];\n\t\tconst me12 = me[ 12 ], me13 = me[ 13 ], me14 = me[ 14 ], me15 = me[ 15 ];\n\n\t\tplanes[ 0 ].setComponents( me3 - me0, me7 - me4, me11 - me8, me15 - me12 ).normalize();\n\t\tplanes[ 1 ].setComponents( me3 + me0, me7 + me4, me11 + me8, me15 + me12 ).normalize();\n\t\tplanes[ 2 ].setComponents( me3 + me1, me7 + me5, me11 + me9, me15 + me13 ).normalize();\n\t\tplanes[ 3 ].setComponents( me3 - me1, me7 - me5, me11 - me9, me15 - me13 ).normalize();\n\t\tplanes[ 4 ].setComponents( me3 - me2, me7 - me6, me11 - me10, me15 - me14 ).normalize();\n\n\t\tif ( coordinateSystem === WebGLCoordinateSystem ) {\n\n\t\t\tplanes[ 5 ].setComponents( me3 + me2, me7 + me6, me11 + me10, me15 + me14 ).normalize();\n\n\t\t} else if ( coordinateSystem === WebGPUCoordinateSystem ) {\n\n\t\t\tplanes[ 5 ].setComponents( me2, me6, me10, me14 ).normalize();\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'THREE.Frustum.setFromProjectionMatrix(): Invalid coordinate system: ' + coordinateSystem );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tintersectsObject( object ) {\n\n\t\tif ( object.boundingSphere !== undefined ) {\n\n\t\t\tif ( object.boundingSphere === null ) object.computeBoundingSphere();\n\n\t\t\t_sphere$5.copy( object.boundingSphere ).applyMatrix4( object.matrixWorld );\n\n\t\t} else {\n\n\t\t\tconst geometry = object.geometry;\n\n\t\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t\t_sphere$5.copy( geometry.boundingSphere ).applyMatrix4( object.matrixWorld );\n\n\t\t}\n\n\t\treturn this.intersectsSphere( _sphere$5 );\n\n\t}\n\n\tintersectsSprite( sprite ) {\n\n\t\t_sphere$5.center.set( 0, 0, 0 );\n\t\t_sphere$5.radius = 0.7071067811865476;\n\t\t_sphere$5.applyMatrix4( sprite.matrixWorld );\n\n\t\treturn this.intersectsSphere( _sphere$5 );\n\n\t}\n\n\tintersectsSphere( sphere ) {\n\n\t\tconst planes = this.planes;\n\t\tconst center = sphere.center;\n\t\tconst negRadius = - sphere.radius;\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\tconst distance = planes[ i ].distanceToPoint( center );\n\n\t\t\tif ( distance < negRadius ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\tconst planes = this.planes;\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\tconst plane = planes[ i ];\n\n\t\t\t// corner at max distance\n\n\t\t\t_vector$7.x = plane.normal.x > 0 ? box.max.x : box.min.x;\n\t\t\t_vector$7.y = plane.normal.y > 0 ? box.max.y : box.min.y;\n\t\t\t_vector$7.z = plane.normal.z > 0 ? box.max.z : box.min.z;\n\n\t\t\tif ( plane.distanceToPoint( _vector$7 ) < 0 ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tcontainsPoint( point ) {\n\n\t\tconst planes = this.planes;\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\tif ( planes[ i ].distanceToPoint( point ) < 0 ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nfunction WebGLAnimation() {\n\n\tlet context = null;\n\tlet isAnimating = false;\n\tlet animationLoop = null;\n\tlet requestId = null;\n\n\tfunction onAnimationFrame( time, frame ) {\n\n\t\tanimationLoop( time, frame );\n\n\t\trequestId = context.requestAnimationFrame( onAnimationFrame );\n\n\t}\n\n\treturn {\n\n\t\tstart: function () {\n\n\t\t\tif ( isAnimating === true ) return;\n\t\t\tif ( animationLoop === null ) return;\n\n\t\t\trequestId = context.requestAnimationFrame( onAnimationFrame );\n\n\t\t\tisAnimating = true;\n\n\t\t},\n\n\t\tstop: function () {\n\n\t\t\tcontext.cancelAnimationFrame( requestId );\n\n\t\t\tisAnimating = false;\n\n\t\t},\n\n\t\tsetAnimationLoop: function ( callback ) {\n\n\t\t\tanimationLoop = callback;\n\n\t\t},\n\n\t\tsetContext: function ( value ) {\n\n\t\t\tcontext = value;\n\n\t\t}\n\n\t};\n\n}\n\nfunction WebGLAttributes( gl ) {\n\n\tconst buffers = new WeakMap();\n\n\tfunction createBuffer( attribute, bufferType ) {\n\n\t\tconst array = attribute.array;\n\t\tconst usage = attribute.usage;\n\t\tconst size = array.byteLength;\n\n\t\tconst buffer = gl.createBuffer();\n\n\t\tgl.bindBuffer( bufferType, buffer );\n\t\tgl.bufferData( bufferType, array, usage );\n\n\t\tattribute.onUploadCallback();\n\n\t\tlet type;\n\n\t\tif ( array instanceof Float32Array ) {\n\n\t\t\ttype = gl.FLOAT;\n\n\t\t} else if ( array instanceof Uint16Array ) {\n\n\t\t\tif ( attribute.isFloat16BufferAttribute ) {\n\n\t\t\t\ttype = gl.HALF_FLOAT;\n\n\t\t\t} else {\n\n\t\t\t\ttype = gl.UNSIGNED_SHORT;\n\n\t\t\t}\n\n\t\t} else if ( array instanceof Int16Array ) {\n\n\t\t\ttype = gl.SHORT;\n\n\t\t} else if ( array instanceof Uint32Array ) {\n\n\t\t\ttype = gl.UNSIGNED_INT;\n\n\t\t} else if ( array instanceof Int32Array ) {\n\n\t\t\ttype = gl.INT;\n\n\t\t} else if ( array instanceof Int8Array ) {\n\n\t\t\ttype = gl.BYTE;\n\n\t\t} else if ( array instanceof Uint8Array ) {\n\n\t\t\ttype = gl.UNSIGNED_BYTE;\n\n\t\t} else if ( array instanceof Uint8ClampedArray ) {\n\n\t\t\ttype = gl.UNSIGNED_BYTE;\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'THREE.WebGLAttributes: Unsupported buffer data format: ' + array );\n\n\t\t}\n\n\t\treturn {\n\t\t\tbuffer: buffer,\n\t\t\ttype: type,\n\t\t\tbytesPerElement: array.BYTES_PER_ELEMENT,\n\t\t\tversion: attribute.version,\n\t\t\tsize: size\n\t\t};\n\n\t}\n\n\tfunction updateBuffer( buffer, attribute, bufferType ) {\n\n\t\tconst array = attribute.array;\n\t\tconst updateRange = attribute._updateRange; // @deprecated, r159\n\t\tconst updateRanges = attribute.updateRanges;\n\n\t\tgl.bindBuffer( bufferType, buffer );\n\n\t\tif ( updateRange.count === - 1 && updateRanges.length === 0 ) {\n\n\t\t\t// Not using update ranges\n\t\t\tgl.bufferSubData( bufferType, 0, array );\n\n\t\t}\n\n\t\tif ( updateRanges.length !== 0 ) {\n\n\t\t\tfor ( let i = 0, l = updateRanges.length; i < l; i ++ ) {\n\n\t\t\t\tconst range = updateRanges[ i ];\n\n\t\t\t\tgl.bufferSubData( bufferType, range.start * array.BYTES_PER_ELEMENT,\n\t\t\t\t\tarray, range.start, range.count );\n\n\t\t\t}\n\n\t\t\tattribute.clearUpdateRanges();\n\n\t\t}\n\n\t\t// @deprecated, r159\n\t\tif ( updateRange.count !== - 1 ) {\n\n\t\t\tgl.bufferSubData( bufferType, updateRange.offset * array.BYTES_PER_ELEMENT,\n\t\t\t\tarray, updateRange.offset, updateRange.count );\n\n\t\t\tupdateRange.count = - 1; // reset range\n\n\t\t}\n\n\t\tattribute.onUploadCallback();\n\n\t}\n\n\t//\n\n\tfunction get( attribute ) {\n\n\t\tif ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;\n\n\t\treturn buffers.get( attribute );\n\n\t}\n\n\tfunction remove( attribute ) {\n\n\t\tif ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;\n\n\t\tconst data = buffers.get( attribute );\n\n\t\tif ( data ) {\n\n\t\t\tgl.deleteBuffer( data.buffer );\n\n\t\t\tbuffers.delete( attribute );\n\n\t\t}\n\n\t}\n\n\tfunction update( attribute, bufferType ) {\n\n\t\tif ( attribute.isInterleavedBufferAttribute ) attribute = attribute.data;\n\n\t\tif ( attribute.isGLBufferAttribute ) {\n\n\t\t\tconst cached = buffers.get( attribute );\n\n\t\t\tif ( ! cached || cached.version < attribute.version ) {\n\n\t\t\t\tbuffers.set( attribute, {\n\t\t\t\t\tbuffer: attribute.buffer,\n\t\t\t\t\ttype: attribute.type,\n\t\t\t\t\tbytesPerElement: attribute.elementSize,\n\t\t\t\t\tversion: attribute.version\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst data = buffers.get( attribute );\n\n\t\tif ( data === undefined ) {\n\n\t\t\tbuffers.set( attribute, createBuffer( attribute, bufferType ) );\n\n\t\t} else if ( data.version < attribute.version ) {\n\n\t\t\tif ( data.size !== attribute.array.byteLength ) {\n\n\t\t\t\tthrow 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.' );\n\n\t\t\t}\n\n\t\t\tupdateBuffer( data.buffer, attribute, bufferType );\n\n\t\t\tdata.version = attribute.version;\n\n\t\t}\n\n\t}\n\n\treturn {\n\n\t\tget: get,\n\t\tremove: remove,\n\t\tupdate: update\n\n\t};\n\n}\n\nclass PlaneGeometry extends BufferGeometry {\n\n\tconstructor( width = 1, height = 1, widthSegments = 1, heightSegments = 1 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'PlaneGeometry';\n\n\t\tthis.parameters = {\n\t\t\twidth: width,\n\t\t\theight: height,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments\n\t\t};\n\n\t\tconst width_half = width / 2;\n\t\tconst height_half = height / 2;\n\n\t\tconst gridX = Math.floor( widthSegments );\n\t\tconst gridY = Math.floor( heightSegments );\n\n\t\tconst gridX1 = gridX + 1;\n\t\tconst gridY1 = gridY + 1;\n\n\t\tconst segment_width = width / gridX;\n\t\tconst segment_height = height / gridY;\n\n\t\t//\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\tfor ( let iy = 0; iy < gridY1; iy ++ ) {\n\n\t\t\tconst y = iy * segment_height - height_half;\n\n\t\t\tfor ( let ix = 0; ix < gridX1; ix ++ ) {\n\n\t\t\t\tconst x = ix * segment_width - width_half;\n\n\t\t\t\tvertices.push( x, - y, 0 );\n\n\t\t\t\tnormals.push( 0, 0, 1 );\n\n\t\t\t\tuvs.push( ix / gridX );\n\t\t\t\tuvs.push( 1 - ( iy / gridY ) );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( let iy = 0; iy < gridY; iy ++ ) {\n\n\t\t\tfor ( let ix = 0; ix < gridX; ix ++ ) {\n\n\t\t\t\tconst a = ix + gridX1 * iy;\n\t\t\t\tconst b = ix + gridX1 * ( iy + 1 );\n\t\t\t\tconst c = ( ix + 1 ) + gridX1 * ( iy + 1 );\n\t\t\t\tconst d = ( ix + 1 ) + gridX1 * iy;\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new PlaneGeometry( data.width, data.height, data.widthSegments, data.heightSegments );\n\n\t}\n\n}\n\nvar alphahash_fragment = \"#ifdef USE_ALPHAHASH\\n\\tif ( diffuseColor.a < getAlphaHashThreshold( vPosition ) ) discard;\\n#endif\";\n\nvar 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\";\n\nvar alphamap_fragment = \"#ifdef USE_ALPHAMAP\\n\\tdiffuseColor.a *= texture2D( alphaMap, vAlphaMapUv ).g;\\n#endif\";\n\nvar alphamap_pars_fragment = \"#ifdef USE_ALPHAMAP\\n\\tuniform sampler2D alphaMap;\\n#endif\";\n\nvar 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\";\n\nvar alphatest_pars_fragment = \"#ifdef USE_ALPHATEST\\n\\tuniform float alphaTest;\\n#endif\";\n\nvar 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\";\n\nvar aomap_pars_fragment = \"#ifdef USE_AOMAP\\n\\tuniform sampler2D aoMap;\\n\\tuniform float aoMapIntensity;\\n#endif\";\n\nvar batching_pars_vertex = \"#ifdef USE_BATCHING\\n\\t#if ! defined( GL_ANGLE_multi_draw )\\n\\t#define gl_DrawID _gl_DrawID\\n\\tuniform int _gl_DrawID;\\n\\t#endif\\n\\tuniform highp sampler2D batchingTexture;\\n\\tuniform highp usampler2D batchingIdTexture;\\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\\tfloat getIndirectIndex( const in int i ) {\\n\\t\\tint size = textureSize( batchingIdTexture, 0 ).x;\\n\\t\\tint x = i % size;\\n\\t\\tint y = i / size;\\n\\t\\treturn float( texelFetch( batchingIdTexture, ivec2( x, y ), 0 ).r );\\n\\t}\\n#endif\\n#ifdef USE_BATCHING_COLOR\\n\\tuniform sampler2D batchingColorTexture;\\n\\tvec3 getBatchingColor( const in float i ) {\\n\\t\\tint size = textureSize( batchingColorTexture, 0 ).x;\\n\\t\\tint j = int( i );\\n\\t\\tint x = j % size;\\n\\t\\tint y = j / size;\\n\\t\\treturn texelFetch( batchingColorTexture, ivec2( x, y ), 0 ).rgb;\\n\\t}\\n#endif\";\n\nvar batching_vertex = \"#ifdef USE_BATCHING\\n\\tmat4 batchingMatrix = getBatchingMatrix( getIndirectIndex( gl_DrawID ) );\\n#endif\";\n\nvar begin_vertex = \"vec3 transformed = vec3( position );\\n#ifdef USE_ALPHAHASH\\n\\tvPosition = vec3( position );\\n#endif\";\n\nvar beginnormal_vertex = \"vec3 objectNormal = vec3( normal );\\n#ifdef USE_TANGENT\\n\\tvec3 objectTangent = vec3( tangent.xyz );\\n#endif\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar clipping_planes_pars_fragment = \"#if NUM_CLIPPING_PLANES > 0\\n\\tvarying vec3 vClipPosition;\\n\\tuniform vec4 clippingPlanes[ NUM_CLIPPING_PLANES ];\\n#endif\";\n\nvar clipping_planes_pars_vertex = \"#if NUM_CLIPPING_PLANES > 0\\n\\tvarying vec3 vClipPosition;\\n#endif\";\n\nvar clipping_planes_vertex = \"#if NUM_CLIPPING_PLANES > 0\\n\\tvClipPosition = - mvPosition.xyz;\\n#endif\";\n\nvar color_fragment = \"#if defined( USE_COLOR_ALPHA )\\n\\tdiffuseColor *= vColor;\\n#elif defined( USE_COLOR )\\n\\tdiffuseColor.rgb *= vColor;\\n#endif\";\n\nvar color_pars_fragment = \"#if defined( USE_COLOR_ALPHA )\\n\\tvarying vec4 vColor;\\n#elif defined( USE_COLOR )\\n\\tvarying vec3 vColor;\\n#endif\";\n\nvar color_pars_vertex = \"#if defined( USE_COLOR_ALPHA )\\n\\tvarying vec4 vColor;\\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_COLOR )\\n\\tvarying vec3 vColor;\\n#endif\";\n\nvar color_vertex = \"#if defined( USE_COLOR_ALPHA )\\n\\tvColor = vec4( 1.0 );\\n#elif defined( USE_COLOR ) || defined( USE_INSTANCING_COLOR ) || defined( USE_BATCHING_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\\n#ifdef USE_BATCHING_COLOR\\n\\tvec3 batchingColor = getBatchingColor( getIndirectIndex( gl_DrawID ) );\\n\\tvColor.xyz *= batchingColor.xyz;\\n#endif\";\n\nvar 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}\\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\";\n\nvar 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\";\n\nvar 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\";\n\nvar displacementmap_pars_vertex = \"#ifdef USE_DISPLACEMENTMAP\\n\\tuniform sampler2D displacementMap;\\n\\tuniform float displacementScale;\\n\\tuniform float displacementBias;\\n#endif\";\n\nvar displacementmap_vertex = \"#ifdef USE_DISPLACEMENTMAP\\n\\ttransformed += normalize( objectNormal ) * ( texture2D( displacementMap, vDisplacementMapUv ).x * displacementScale + displacementBias );\\n#endif\";\n\nvar emissivemap_fragment = \"#ifdef USE_EMISSIVEMAP\\n\\tvec4 emissiveColor = texture2D( emissiveMap, vEmissiveMapUv );\\n\\ttotalEmissiveRadiance *= emissiveColor.rgb;\\n#endif\";\n\nvar emissivemap_pars_fragment = \"#ifdef USE_EMISSIVEMAP\\n\\tuniform sampler2D emissiveMap;\\n#endif\";\n\nvar colorspace_fragment = \"gl_FragColor = linearToOutputTexel( gl_FragColor );\";\n\nvar 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}\";\n\nvar 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, envMapRotation * 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\";\n\nvar envmap_common_pars_fragment = \"#ifdef USE_ENVMAP\\n\\tuniform float envMapIntensity;\\n\\tuniform float flipEnvMap;\\n\\tuniform mat3 envMapRotation;\\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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar fog_vertex = \"#ifdef USE_FOG\\n\\tvFogDepth = - mvPosition.z;\\n#endif\";\n\nvar fog_pars_vertex = \"#ifdef USE_FOG\\n\\tvarying float vFogDepth;\\n#endif\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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}\";\n\nvar lightmap_pars_fragment = \"#ifdef USE_LIGHTMAP\\n\\tuniform sampler2D lightMap;\\n\\tuniform float lightMapIntensity;\\n#endif\";\n\nvar lights_lambert_fragment = \"LambertMaterial material;\\nmaterial.diffuseColor = diffuseColor.rgb;\\nmaterial.specularStrength = specularStrength;\";\n\nvar 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\";\n\nvar 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\\tfloat distanceFalloff = 1.0 / max( pow( lightDistance, decayExponent ), 0.01 );\\n\\tif ( cutoffDistance > 0.0 ) {\\n\\t\\tdistanceFalloff *= pow2( saturate( 1.0 - pow4( lightDistance / cutoffDistance ) ) );\\n\\t}\\n\\treturn distanceFalloff;\\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\";\n\nvar 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, envMapRotation * 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, envMapRotation * 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\";\n\nvar lights_toon_fragment = \"ToonMaterial material;\\nmaterial.diffuseColor = diffuseColor.rgb;\";\n\nvar 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\";\n\nvar lights_phong_fragment = \"BlinnPhongMaterial material;\\nmaterial.diffuseColor = diffuseColor.rgb;\\nmaterial.specularColor = specular;\\nmaterial.specularShininess = shininess;\\nmaterial.specularStrength = specularStrength;\";\n\nvar 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\";\n\nvar 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_DISPERSION\\n\\tmaterial.dispersion = dispersion;\\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\";\n\nvar lights_physical_pars_fragment = \"struct PhysicalMaterial {\\n\\tvec3 diffuseColor;\\n\\tfloat roughness;\\n\\tvec3 specularColor;\\n\\tfloat specularF90;\\n\\tfloat dispersion;\\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}\";\n\nvar 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.shadowIntensity, 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.shadowIntensity, 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.shadowIntensity, 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar logdepthbuf_fragment = \"#if defined( USE_LOGDEPTHBUF )\\n\\tgl_FragDepth = vIsPerspective == 0.0 ? gl_FragCoord.z : log2( vFragDepth ) * logDepthBufFC * 0.5;\\n#endif\";\n\nvar logdepthbuf_pars_fragment = \"#if defined( USE_LOGDEPTHBUF )\\n\\tuniform float logDepthBufFC;\\n\\tvarying float vFragDepth;\\n\\tvarying float vIsPerspective;\\n#endif\";\n\nvar logdepthbuf_pars_vertex = \"#ifdef USE_LOGDEPTHBUF\\n\\tvarying float vFragDepth;\\n\\tvarying float vIsPerspective;\\n#endif\";\n\nvar logdepthbuf_vertex = \"#ifdef USE_LOGDEPTHBUF\\n\\tvFragDepth = 1.0 + gl_Position.w;\\n\\tvIsPerspective = float( isPerspectiveMatrix( projectionMatrix ) );\\n#endif\";\n\nvar 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\";\n\nvar map_pars_fragment = \"#ifdef USE_MAP\\n\\tuniform sampler2D map;\\n#endif\";\n\nvar 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\";\n\nvar 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\";\n\nvar metalnessmap_fragment = \"float metalnessFactor = metalness;\\n#ifdef USE_METALNESSMAP\\n\\tvec4 texelMetalness = texture2D( metalnessMap, vMetalnessMapUv );\\n\\tmetalnessFactor *= texelMetalness.b;\\n#endif\";\n\nvar metalnessmap_pars_fragment = \"#ifdef USE_METALNESSMAP\\n\\tuniform sampler2D metalnessMap;\\n#endif\";\n\nvar morphinstance_vertex = \"#ifdef USE_INSTANCING_MORPH\\n\\tfloat morphTargetInfluences[ MORPHTARGETS_COUNT ];\\n\\tfloat morphTargetBaseInfluence = texelFetch( morphTexture, ivec2( 0, gl_InstanceID ), 0 ).r;\\n\\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\\n\\t\\tmorphTargetInfluences[i] = texelFetch( morphTexture, ivec2( i + 1, gl_InstanceID ), 0 ).r;\\n\\t}\\n#endif\";\n\nvar morphcolor_vertex = \"#if defined( USE_MORPHCOLORS )\\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\";\n\nvar morphnormal_vertex = \"#ifdef USE_MORPHNORMALS\\n\\tobjectNormal *= morphTargetBaseInfluence;\\n\\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\\n\\t\\tif ( morphTargetInfluences[ i ] != 0.0 ) objectNormal += getMorph( gl_VertexID, i, 1 ).xyz * morphTargetInfluences[ i ];\\n\\t}\\n#endif\";\n\nvar morphtarget_pars_vertex = \"#ifdef USE_MORPHTARGETS\\n\\t#ifndef USE_INSTANCING_MORPH\\n\\t\\tuniform float morphTargetBaseInfluence;\\n\\t\\tuniform float morphTargetInfluences[ MORPHTARGETS_COUNT ];\\n\\t#endif\\n\\tuniform sampler2DArray morphTargetsTexture;\\n\\tuniform ivec2 morphTargetsTextureSize;\\n\\tvec4 getMorph( const in int vertexIndex, const in int morphTargetIndex, const in int offset ) {\\n\\t\\tint texelIndex = vertexIndex * MORPHTARGETS_TEXTURE_STRIDE + offset;\\n\\t\\tint y = texelIndex / morphTargetsTextureSize.x;\\n\\t\\tint x = texelIndex - y * morphTargetsTextureSize.x;\\n\\t\\tivec3 morphUV = ivec3( x, y, morphTargetIndex );\\n\\t\\treturn texelFetch( morphTargetsTexture, morphUV, 0 );\\n\\t}\\n#endif\";\n\nvar morphtarget_vertex = \"#ifdef USE_MORPHTARGETS\\n\\ttransformed *= morphTargetBaseInfluence;\\n\\tfor ( int i = 0; i < MORPHTARGETS_COUNT; i ++ ) {\\n\\t\\tif ( morphTargetInfluences[ i ] != 0.0 ) transformed += getMorph( gl_VertexID, i, 0 ).xyz * morphTargetInfluences[ i ];\\n\\t}\\n#endif\";\n\nvar 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;\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar clearcoat_normal_fragment_begin = \"#ifdef USE_CLEARCOAT\\n\\tvec3 clearcoatNormal = nonPerturbedNormal;\\n#endif\";\n\nvar 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\";\n\nvar 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\";\n\nvar iridescence_pars_fragment = \"#ifdef USE_IRIDESCENCEMAP\\n\\tuniform sampler2D iridescenceMap;\\n#endif\\n#ifdef USE_IRIDESCENCE_THICKNESSMAP\\n\\tuniform sampler2D iridescenceThicknessMap;\\n#endif\";\n\nvar 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 );\";\n\nvar 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.;const float ShiftRight8 = 1. / 256.;\\nconst float Inv255 = 1. / 255.;\\nconst vec4 PackFactors = vec4( 1.0, 256.0, 256.0 * 256.0, 256.0 * 256.0 * 256.0 );\\nconst vec2 UnpackFactors2 = vec2( UnpackDownscale, 1.0 / PackFactors.g );\\nconst vec3 UnpackFactors3 = vec3( UnpackDownscale / PackFactors.rg, 1.0 / PackFactors.b );\\nconst vec4 UnpackFactors4 = vec4( UnpackDownscale / PackFactors.rgb, 1.0 / PackFactors.a );\\nvec4 packDepthToRGBA( const in float v ) {\\n\\tif( v <= 0.0 )\\n\\t\\treturn vec4( 0., 0., 0., 0. );\\n\\tif( v >= 1.0 )\\n\\t\\treturn vec4( 1., 1., 1., 1. );\\n\\tfloat vuf;\\n\\tfloat af = modf( v * PackFactors.a, vuf );\\n\\tfloat bf = modf( vuf * ShiftRight8, vuf );\\n\\tfloat gf = modf( vuf * ShiftRight8, vuf );\\n\\treturn vec4( vuf * Inv255, gf * PackUpscale, bf * PackUpscale, af );\\n}\\nvec3 packDepthToRGB( const in float v ) {\\n\\tif( v <= 0.0 )\\n\\t\\treturn vec3( 0., 0., 0. );\\n\\tif( v >= 1.0 )\\n\\t\\treturn vec3( 1., 1., 1. );\\n\\tfloat vuf;\\n\\tfloat bf = modf( v * PackFactors.b, vuf );\\n\\tfloat gf = modf( vuf * ShiftRight8, vuf );\\n\\treturn vec3( vuf * Inv255, gf * PackUpscale, bf );\\n}\\nvec2 packDepthToRG( const in float v ) {\\n\\tif( v <= 0.0 )\\n\\t\\treturn vec2( 0., 0. );\\n\\tif( v >= 1.0 )\\n\\t\\treturn vec2( 1., 1. );\\n\\tfloat vuf;\\n\\tfloat gf = modf( v * 256., vuf );\\n\\treturn vec2( vuf * Inv255, gf );\\n}\\nfloat unpackRGBAToDepth( const in vec4 v ) {\\n\\treturn dot( v, UnpackFactors4 );\\n}\\nfloat unpackRGBToDepth( const in vec3 v ) {\\n\\treturn dot( v, UnpackFactors3 );\\n}\\nfloat unpackRGToDepth( const in vec2 v ) {\\n\\treturn v.r * UnpackFactors2.r + v.g * UnpackFactors2.g;\\n}\\nvec4 pack2HalfToRGBA( const in 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( const in 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}\";\n\nvar premultiplied_alpha_fragment = \"#ifdef PREMULTIPLIED_ALPHA\\n\\tgl_FragColor.rgb *= gl_FragColor.a;\\n#endif\";\n\nvar 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;\";\n\nvar dithering_fragment = \"#ifdef DITHERING\\n\\tgl_FragColor.rgb = dithering( gl_FragColor.rgb );\\n#endif\";\n\nvar 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\";\n\nvar roughnessmap_fragment = \"float roughnessFactor = roughness;\\n#ifdef USE_ROUGHNESSMAP\\n\\tvec4 texelRoughness = texture2D( roughnessMap, vRoughnessMapUv );\\n\\troughnessFactor *= texelRoughness.g;\\n#endif\";\n\nvar roughnessmap_pars_fragment = \"#ifdef USE_ROUGHNESSMAP\\n\\tuniform sampler2D roughnessMap;\\n#endif\";\n\nvar 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 shadowIntensity;\\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 shadowIntensity;\\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 shadowIntensity;\\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 shadowIntensity, 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 mix( 1.0, shadow, shadowIntensity );\\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 shadowIntensity, float shadowBias, float shadowRadius, vec4 shadowCoord, float shadowCameraNear, float shadowCameraFar ) {\\n\\t\\tfloat shadow = 1.0;\\n\\t\\tvec3 lightToPosition = shadowCoord.xyz;\\n\\t\\t\\n\\t\\tfloat lightToPositionLength = length( lightToPosition );\\n\\t\\tif ( lightToPositionLength - shadowCameraFar <= 0.0 && lightToPositionLength - shadowCameraNear >= 0.0 ) {\\n\\t\\t\\tfloat dp = ( lightToPositionLength - shadowCameraNear ) / ( shadowCameraFar - shadowCameraNear );\\t\\t\\tdp += shadowBias;\\n\\t\\t\\tvec3 bd3D = normalize( lightToPosition );\\n\\t\\t\\tvec2 texelSize = vec2( 1.0 ) / ( shadowMapSize * vec2( 4.0, 2.0 ) );\\n\\t\\t\\t#if defined( SHADOWMAP_TYPE_PCF ) || defined( SHADOWMAP_TYPE_PCF_SOFT ) || defined( SHADOWMAP_TYPE_VSM )\\n\\t\\t\\t\\tvec2 offset = vec2( - 1, 1 ) * shadowRadius * texelSize.y;\\n\\t\\t\\t\\tshadow = (\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyy, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyy, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xyx, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yyx, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxy, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxy, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.xxx, texelSize.y ), dp ) +\\n\\t\\t\\t\\t\\ttexture2DCompare( shadowMap, cubeToUV( bd3D + offset.yxx, texelSize.y ), dp )\\n\\t\\t\\t\\t) * ( 1.0 / 9.0 );\\n\\t\\t\\t#else\\n\\t\\t\\t\\tshadow = texture2DCompare( shadowMap, cubeToUV( bd3D, texelSize.y ), dp );\\n\\t\\t\\t#endif\\n\\t\\t}\\n\\t\\treturn mix( 1.0, shadow, shadowIntensity );\\n\\t}\\n#endif\";\n\nvar 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 shadowIntensity;\\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 shadowIntensity;\\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 shadowIntensity;\\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\";\n\nvar 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\";\n\nvar 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.shadowIntensity, 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.shadowIntensity, 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.shadowIntensity, 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}\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar specularmap_pars_fragment = \"#ifdef USE_SPECULARMAP\\n\\tuniform sampler2D specularMap;\\n#endif\";\n\nvar tonemapping_fragment = \"#if defined( TONE_MAPPING )\\n\\tgl_FragColor.rgb = toneMapping( gl_FragColor.rgb );\\n#endif\";\n\nvar 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 NeutralToneMapping( vec3 color ) {\\n\\tconst float StartCompression = 0.8 - 0.04;\\n\\tconst float Desaturation = 0.15;\\n\\tcolor *= toneMappingExposure;\\n\\tfloat x = min( color.r, min( color.g, color.b ) );\\n\\tfloat offset = x < 0.08 ? x - 6.25 * x * x : 0.04;\\n\\tcolor -= offset;\\n\\tfloat peak = max( color.r, max( color.g, color.b ) );\\n\\tif ( peak < StartCompression ) return color;\\n\\tfloat d = 1. - StartCompression;\\n\\tfloat newPeak = 1. - d * d / ( peak + d - StartCompression );\\n\\tcolor *= newPeak / peak;\\n\\tfloat g = 1. - 1. / ( Desaturation * ( peak - newPeak ) + 1. );\\n\\treturn mix( color, vec3( newPeak ), g );\\n}\\nvec3 CustomToneMapping( vec3 color ) { return color; }\";\n\nvar 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.dispersion, 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\";\n\nvar 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 dispersion, const in float ior, const in float thickness,\\n\\t\\tconst in vec3 attenuationColor, const in float attenuationDistance ) {\\n\\t\\tvec4 transmittedLight;\\n\\t\\tvec3 transmittance;\\n\\t\\t#ifdef USE_DISPERSION\\n\\t\\t\\tfloat halfSpread = ( ior - 1.0 ) * 0.025 * dispersion;\\n\\t\\t\\tvec3 iors = vec3( ior - halfSpread, ior, ior + halfSpread );\\n\\t\\t\\tfor ( int i = 0; i < 3; i ++ ) {\\n\\t\\t\\t\\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, iors[ i ], modelMatrix );\\n\\t\\t\\t\\tvec3 refractedRayExit = position + transmissionRay;\\n\\t\\t\\n\\t\\t\\t\\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\\n\\t\\t\\t\\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\\n\\t\\t\\t\\trefractionCoords += 1.0;\\n\\t\\t\\t\\trefractionCoords /= 2.0;\\n\\t\\t\\n\\t\\t\\t\\tvec4 transmissionSample = getTransmissionSample( refractionCoords, roughness, iors[ i ] );\\n\\t\\t\\t\\ttransmittedLight[ i ] = transmissionSample[ i ];\\n\\t\\t\\t\\ttransmittedLight.a += transmissionSample.a;\\n\\t\\t\\t\\ttransmittance[ i ] = diffuseColor[ i ] * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance )[ i ];\\n\\t\\t\\t}\\n\\t\\t\\ttransmittedLight.a /= 3.0;\\n\\t\\t\\n\\t\\t#else\\n\\t\\t\\n\\t\\t\\tvec3 transmissionRay = getVolumeTransmissionRay( n, v, thickness, ior, modelMatrix );\\n\\t\\t\\tvec3 refractedRayExit = position + transmissionRay;\\n\\t\\t\\tvec4 ndcPos = projMatrix * viewMatrix * vec4( refractedRayExit, 1.0 );\\n\\t\\t\\tvec2 refractionCoords = ndcPos.xy / ndcPos.w;\\n\\t\\t\\trefractionCoords += 1.0;\\n\\t\\t\\trefractionCoords /= 2.0;\\n\\t\\t\\ttransmittedLight = getTransmissionSample( refractionCoords, roughness, ior );\\n\\t\\t\\ttransmittance = diffuseColor * volumeAttenuation( length( transmissionRay ), attenuationColor, attenuationDistance );\\n\\t\\t\\n\\t\\t#endif\\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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nvar 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\";\n\nconst 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}\";\n\nconst 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}\";\n\nconst 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}\";\n\nconst 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;\\nuniform mat3 backgroundRotation;\\nvarying vec3 vWorldDirection;\\n#include \\nvoid main() {\\n\\t#ifdef ENVMAP_TYPE_CUBE\\n\\t\\tvec4 texColor = textureCube( envMap, backgroundRotation * vec3( flipEnvMap * vWorldDirection.x, vWorldDirection.yz ) );\\n\\t#elif defined( ENVMAP_TYPE_CUBE_UV )\\n\\t\\tvec4 texColor = textureCubeUV( envMap, backgroundRotation * 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}\";\n\nconst 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}\";\n\nconst 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}\";\n\nconst 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#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}\";\n\nconst 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#elif DEPTH_PACKING == 3202\\n\\t\\tgl_FragColor = vec4( packDepthToRGB( fragCoordZ ), 1.0 );\\n\\t#elif DEPTH_PACKING == 3203\\n\\t\\tgl_FragColor = vec4( packDepthToRG( fragCoordZ ), 0.0, 1.0 );\\n\\t#endif\\n}\";\n\nconst 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#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}\";\n\nconst 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}\";\n\nconst vertex$c = \"varying vec3 vWorldDirection;\\n#include \\nvoid main() {\\n\\tvWorldDirection = transformDirection( position, modelMatrix );\\n\\t#include \\n\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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#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}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n\\tvViewPosition = - mvPosition.xyz;\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n\\tvViewPosition = - mvPosition.xyz;\\n}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n#if defined( FLAT_SHADED ) || defined( USE_BUMPMAP ) || defined( USE_NORMALMAP_TANGENTSPACE )\\n\\tvViewPosition = - mvPosition.xyz;\\n#endif\\n}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n\\tvViewPosition = - mvPosition.xyz;\\n\\t#include \\n\\t#include \\n\\t#include \\n\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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\\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}\";\n\nconst 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_DISPERSION\\n\\tuniform float dispersion;\\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}\";\n\nconst 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\\t#include \\n\\tvViewPosition = - mvPosition.xyz;\\n\\t#include \\n\\t#include \\n\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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\\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}\";\n\nconst 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}\";\n\nconst 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\\t#include \\n}\";\n\nconst 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}\";\n\nconst 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}\";\n\nconst 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}\";\n\nconst ShaderChunk = {\n\talphahash_fragment: alphahash_fragment,\n\talphahash_pars_fragment: alphahash_pars_fragment,\n\talphamap_fragment: alphamap_fragment,\n\talphamap_pars_fragment: alphamap_pars_fragment,\n\talphatest_fragment: alphatest_fragment,\n\talphatest_pars_fragment: alphatest_pars_fragment,\n\taomap_fragment: aomap_fragment,\n\taomap_pars_fragment: aomap_pars_fragment,\n\tbatching_pars_vertex: batching_pars_vertex,\n\tbatching_vertex: batching_vertex,\n\tbegin_vertex: begin_vertex,\n\tbeginnormal_vertex: beginnormal_vertex,\n\tbsdfs: bsdfs,\n\tiridescence_fragment: iridescence_fragment,\n\tbumpmap_pars_fragment: bumpmap_pars_fragment,\n\tclipping_planes_fragment: clipping_planes_fragment,\n\tclipping_planes_pars_fragment: clipping_planes_pars_fragment,\n\tclipping_planes_pars_vertex: clipping_planes_pars_vertex,\n\tclipping_planes_vertex: clipping_planes_vertex,\n\tcolor_fragment: color_fragment,\n\tcolor_pars_fragment: color_pars_fragment,\n\tcolor_pars_vertex: color_pars_vertex,\n\tcolor_vertex: color_vertex,\n\tcommon: common,\n\tcube_uv_reflection_fragment: cube_uv_reflection_fragment,\n\tdefaultnormal_vertex: defaultnormal_vertex,\n\tdisplacementmap_pars_vertex: displacementmap_pars_vertex,\n\tdisplacementmap_vertex: displacementmap_vertex,\n\temissivemap_fragment: emissivemap_fragment,\n\temissivemap_pars_fragment: emissivemap_pars_fragment,\n\tcolorspace_fragment: colorspace_fragment,\n\tcolorspace_pars_fragment: colorspace_pars_fragment,\n\tenvmap_fragment: envmap_fragment,\n\tenvmap_common_pars_fragment: envmap_common_pars_fragment,\n\tenvmap_pars_fragment: envmap_pars_fragment,\n\tenvmap_pars_vertex: envmap_pars_vertex,\n\tenvmap_physical_pars_fragment: envmap_physical_pars_fragment,\n\tenvmap_vertex: envmap_vertex,\n\tfog_vertex: fog_vertex,\n\tfog_pars_vertex: fog_pars_vertex,\n\tfog_fragment: fog_fragment,\n\tfog_pars_fragment: fog_pars_fragment,\n\tgradientmap_pars_fragment: gradientmap_pars_fragment,\n\tlightmap_pars_fragment: lightmap_pars_fragment,\n\tlights_lambert_fragment: lights_lambert_fragment,\n\tlights_lambert_pars_fragment: lights_lambert_pars_fragment,\n\tlights_pars_begin: lights_pars_begin,\n\tlights_toon_fragment: lights_toon_fragment,\n\tlights_toon_pars_fragment: lights_toon_pars_fragment,\n\tlights_phong_fragment: lights_phong_fragment,\n\tlights_phong_pars_fragment: lights_phong_pars_fragment,\n\tlights_physical_fragment: lights_physical_fragment,\n\tlights_physical_pars_fragment: lights_physical_pars_fragment,\n\tlights_fragment_begin: lights_fragment_begin,\n\tlights_fragment_maps: lights_fragment_maps,\n\tlights_fragment_end: lights_fragment_end,\n\tlogdepthbuf_fragment: logdepthbuf_fragment,\n\tlogdepthbuf_pars_fragment: logdepthbuf_pars_fragment,\n\tlogdepthbuf_pars_vertex: logdepthbuf_pars_vertex,\n\tlogdepthbuf_vertex: logdepthbuf_vertex,\n\tmap_fragment: map_fragment,\n\tmap_pars_fragment: map_pars_fragment,\n\tmap_particle_fragment: map_particle_fragment,\n\tmap_particle_pars_fragment: map_particle_pars_fragment,\n\tmetalnessmap_fragment: metalnessmap_fragment,\n\tmetalnessmap_pars_fragment: metalnessmap_pars_fragment,\n\tmorphinstance_vertex: morphinstance_vertex,\n\tmorphcolor_vertex: morphcolor_vertex,\n\tmorphnormal_vertex: morphnormal_vertex,\n\tmorphtarget_pars_vertex: morphtarget_pars_vertex,\n\tmorphtarget_vertex: morphtarget_vertex,\n\tnormal_fragment_begin: normal_fragment_begin,\n\tnormal_fragment_maps: normal_fragment_maps,\n\tnormal_pars_fragment: normal_pars_fragment,\n\tnormal_pars_vertex: normal_pars_vertex,\n\tnormal_vertex: normal_vertex,\n\tnormalmap_pars_fragment: normalmap_pars_fragment,\n\tclearcoat_normal_fragment_begin: clearcoat_normal_fragment_begin,\n\tclearcoat_normal_fragment_maps: clearcoat_normal_fragment_maps,\n\tclearcoat_pars_fragment: clearcoat_pars_fragment,\n\tiridescence_pars_fragment: iridescence_pars_fragment,\n\topaque_fragment: opaque_fragment,\n\tpacking: packing,\n\tpremultiplied_alpha_fragment: premultiplied_alpha_fragment,\n\tproject_vertex: project_vertex,\n\tdithering_fragment: dithering_fragment,\n\tdithering_pars_fragment: dithering_pars_fragment,\n\troughnessmap_fragment: roughnessmap_fragment,\n\troughnessmap_pars_fragment: roughnessmap_pars_fragment,\n\tshadowmap_pars_fragment: shadowmap_pars_fragment,\n\tshadowmap_pars_vertex: shadowmap_pars_vertex,\n\tshadowmap_vertex: shadowmap_vertex,\n\tshadowmask_pars_fragment: shadowmask_pars_fragment,\n\tskinbase_vertex: skinbase_vertex,\n\tskinning_pars_vertex: skinning_pars_vertex,\n\tskinning_vertex: skinning_vertex,\n\tskinnormal_vertex: skinnormal_vertex,\n\tspecularmap_fragment: specularmap_fragment,\n\tspecularmap_pars_fragment: specularmap_pars_fragment,\n\ttonemapping_fragment: tonemapping_fragment,\n\ttonemapping_pars_fragment: tonemapping_pars_fragment,\n\ttransmission_fragment: transmission_fragment,\n\ttransmission_pars_fragment: transmission_pars_fragment,\n\tuv_pars_fragment: uv_pars_fragment,\n\tuv_pars_vertex: uv_pars_vertex,\n\tuv_vertex: uv_vertex,\n\tworldpos_vertex: worldpos_vertex,\n\n\tbackground_vert: vertex$h,\n\tbackground_frag: fragment$h,\n\tbackgroundCube_vert: vertex$g,\n\tbackgroundCube_frag: fragment$g,\n\tcube_vert: vertex$f,\n\tcube_frag: fragment$f,\n\tdepth_vert: vertex$e,\n\tdepth_frag: fragment$e,\n\tdistanceRGBA_vert: vertex$d,\n\tdistanceRGBA_frag: fragment$d,\n\tequirect_vert: vertex$c,\n\tequirect_frag: fragment$c,\n\tlinedashed_vert: vertex$b,\n\tlinedashed_frag: fragment$b,\n\tmeshbasic_vert: vertex$a,\n\tmeshbasic_frag: fragment$a,\n\tmeshlambert_vert: vertex$9,\n\tmeshlambert_frag: fragment$9,\n\tmeshmatcap_vert: vertex$8,\n\tmeshmatcap_frag: fragment$8,\n\tmeshnormal_vert: vertex$7,\n\tmeshnormal_frag: fragment$7,\n\tmeshphong_vert: vertex$6,\n\tmeshphong_frag: fragment$6,\n\tmeshphysical_vert: vertex$5,\n\tmeshphysical_frag: fragment$5,\n\tmeshtoon_vert: vertex$4,\n\tmeshtoon_frag: fragment$4,\n\tpoints_vert: vertex$3,\n\tpoints_frag: fragment$3,\n\tshadow_vert: vertex$2,\n\tshadow_frag: fragment$2,\n\tsprite_vert: vertex$1,\n\tsprite_frag: fragment$1\n};\n\n/**\n * Uniforms library for shared webgl shaders\n */\n\nconst UniformsLib = {\n\n\tcommon: {\n\n\t\tdiffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },\n\t\topacity: { value: 1.0 },\n\n\t\tmap: { value: null },\n\t\tmapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\n\t\talphaMap: { value: null },\n\t\talphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\n\t\talphaTest: { value: 0 }\n\n\t},\n\n\tspecularmap: {\n\n\t\tspecularMap: { value: null },\n\t\tspecularMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tenvmap: {\n\n\t\tenvMap: { value: null },\n\t\tenvMapRotation: { value: /*@__PURE__*/ new Matrix3() },\n\t\tflipEnvMap: { value: - 1 },\n\t\treflectivity: { value: 1.0 }, // basic, lambert, phong\n\t\tior: { value: 1.5 }, // physical\n\t\trefractionRatio: { value: 0.98 }, // basic, lambert, phong\n\n\t},\n\n\taomap: {\n\n\t\taoMap: { value: null },\n\t\taoMapIntensity: { value: 1 },\n\t\taoMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tlightmap: {\n\n\t\tlightMap: { value: null },\n\t\tlightMapIntensity: { value: 1 },\n\t\tlightMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tbumpmap: {\n\n\t\tbumpMap: { value: null },\n\t\tbumpMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\tbumpScale: { value: 1 }\n\n\t},\n\n\tnormalmap: {\n\n\t\tnormalMap: { value: null },\n\t\tnormalMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\tnormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) }\n\n\t},\n\n\tdisplacementmap: {\n\n\t\tdisplacementMap: { value: null },\n\t\tdisplacementMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\tdisplacementScale: { value: 1 },\n\t\tdisplacementBias: { value: 0 }\n\n\t},\n\n\temissivemap: {\n\n\t\temissiveMap: { value: null },\n\t\temissiveMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tmetalnessmap: {\n\n\t\tmetalnessMap: { value: null },\n\t\tmetalnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\troughnessmap: {\n\n\t\troughnessMap: { value: null },\n\t\troughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tgradientmap: {\n\n\t\tgradientMap: { value: null }\n\n\t},\n\n\tfog: {\n\n\t\tfogDensity: { value: 0.00025 },\n\t\tfogNear: { value: 1 },\n\t\tfogFar: { value: 2000 },\n\t\tfogColor: { value: /*@__PURE__*/ new Color( 0xffffff ) }\n\n\t},\n\n\tlights: {\n\n\t\tambientLightColor: { value: [] },\n\n\t\tlightProbe: { value: [] },\n\n\t\tdirectionalLights: { value: [], properties: {\n\t\t\tdirection: {},\n\t\t\tcolor: {}\n\t\t} },\n\n\t\tdirectionalLightShadows: { value: [], properties: {\n\t\t\tshadowIntensity: 1,\n\t\t\tshadowBias: {},\n\t\t\tshadowNormalBias: {},\n\t\t\tshadowRadius: {},\n\t\t\tshadowMapSize: {}\n\t\t} },\n\n\t\tdirectionalShadowMap: { value: [] },\n\t\tdirectionalShadowMatrix: { value: [] },\n\n\t\tspotLights: { value: [], properties: {\n\t\t\tcolor: {},\n\t\t\tposition: {},\n\t\t\tdirection: {},\n\t\t\tdistance: {},\n\t\t\tconeCos: {},\n\t\t\tpenumbraCos: {},\n\t\t\tdecay: {}\n\t\t} },\n\n\t\tspotLightShadows: { value: [], properties: {\n\t\t\tshadowIntensity: 1,\n\t\t\tshadowBias: {},\n\t\t\tshadowNormalBias: {},\n\t\t\tshadowRadius: {},\n\t\t\tshadowMapSize: {}\n\t\t} },\n\n\t\tspotLightMap: { value: [] },\n\t\tspotShadowMap: { value: [] },\n\t\tspotLightMatrix: { value: [] },\n\n\t\tpointLights: { value: [], properties: {\n\t\t\tcolor: {},\n\t\t\tposition: {},\n\t\t\tdecay: {},\n\t\t\tdistance: {}\n\t\t} },\n\n\t\tpointLightShadows: { value: [], properties: {\n\t\t\tshadowIntensity: 1,\n\t\t\tshadowBias: {},\n\t\t\tshadowNormalBias: {},\n\t\t\tshadowRadius: {},\n\t\t\tshadowMapSize: {},\n\t\t\tshadowCameraNear: {},\n\t\t\tshadowCameraFar: {}\n\t\t} },\n\n\t\tpointShadowMap: { value: [] },\n\t\tpointShadowMatrix: { value: [] },\n\n\t\themisphereLights: { value: [], properties: {\n\t\t\tdirection: {},\n\t\t\tskyColor: {},\n\t\t\tgroundColor: {}\n\t\t} },\n\n\t\t// TODO (abelnation): RectAreaLight BRDF data needs to be moved from example to main src\n\t\trectAreaLights: { value: [], properties: {\n\t\t\tcolor: {},\n\t\t\tposition: {},\n\t\t\twidth: {},\n\t\t\theight: {}\n\t\t} },\n\n\t\tltc_1: { value: null },\n\t\tltc_2: { value: null }\n\n\t},\n\n\tpoints: {\n\n\t\tdiffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },\n\t\topacity: { value: 1.0 },\n\t\tsize: { value: 1.0 },\n\t\tscale: { value: 1.0 },\n\t\tmap: { value: null },\n\t\talphaMap: { value: null },\n\t\talphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\talphaTest: { value: 0 },\n\t\tuvTransform: { value: /*@__PURE__*/ new Matrix3() }\n\n\t},\n\n\tsprite: {\n\n\t\tdiffuse: { value: /*@__PURE__*/ new Color( 0xffffff ) },\n\t\topacity: { value: 1.0 },\n\t\tcenter: { value: /*@__PURE__*/ new Vector2( 0.5, 0.5 ) },\n\t\trotation: { value: 0.0 },\n\t\tmap: { value: null },\n\t\tmapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\talphaMap: { value: null },\n\t\talphaMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\talphaTest: { value: 0 }\n\n\t}\n\n};\n\nconst ShaderLib = {\n\n\tbasic: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.specularmap,\n\t\t\tUniformsLib.envmap,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.fog\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshbasic_vert,\n\t\tfragmentShader: ShaderChunk.meshbasic_frag\n\n\t},\n\n\tlambert: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.specularmap,\n\t\t\tUniformsLib.envmap,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.emissivemap,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.fog,\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\temissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshlambert_vert,\n\t\tfragmentShader: ShaderChunk.meshlambert_frag\n\n\t},\n\n\tphong: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.specularmap,\n\t\t\tUniformsLib.envmap,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.emissivemap,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.fog,\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\temissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },\n\t\t\t\tspecular: { value: /*@__PURE__*/ new Color( 0x111111 ) },\n\t\t\t\tshininess: { value: 30 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshphong_vert,\n\t\tfragmentShader: ShaderChunk.meshphong_frag\n\n\t},\n\n\tstandard: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.envmap,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.emissivemap,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.roughnessmap,\n\t\t\tUniformsLib.metalnessmap,\n\t\t\tUniformsLib.fog,\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\temissive: { value: /*@__PURE__*/ new Color( 0x000000 ) },\n\t\t\t\troughness: { value: 1.0 },\n\t\t\t\tmetalness: { value: 0.0 },\n\t\t\t\tenvMapIntensity: { value: 1 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshphysical_vert,\n\t\tfragmentShader: ShaderChunk.meshphysical_frag\n\n\t},\n\n\ttoon: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.aomap,\n\t\t\tUniformsLib.lightmap,\n\t\t\tUniformsLib.emissivemap,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.gradientmap,\n\t\t\tUniformsLib.fog,\n\t\t\tUniformsLib.lights,\n\t\t\t{\n\t\t\t\temissive: { value: /*@__PURE__*/ new Color( 0x000000 ) }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshtoon_vert,\n\t\tfragmentShader: ShaderChunk.meshtoon_frag\n\n\t},\n\n\tmatcap: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\tUniformsLib.fog,\n\t\t\t{\n\t\t\t\tmatcap: { value: null }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshmatcap_vert,\n\t\tfragmentShader: ShaderChunk.meshmatcap_frag\n\n\t},\n\n\tpoints: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.points,\n\t\t\tUniformsLib.fog\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.points_vert,\n\t\tfragmentShader: ShaderChunk.points_frag\n\n\t},\n\n\tdashed: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.fog,\n\t\t\t{\n\t\t\t\tscale: { value: 1 },\n\t\t\t\tdashSize: { value: 1 },\n\t\t\t\ttotalSize: { value: 2 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.linedashed_vert,\n\t\tfragmentShader: ShaderChunk.linedashed_frag\n\n\t},\n\n\tdepth: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.displacementmap\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.depth_vert,\n\t\tfragmentShader: ShaderChunk.depth_frag\n\n\t},\n\n\tnormal: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.bumpmap,\n\t\t\tUniformsLib.normalmap,\n\t\t\tUniformsLib.displacementmap,\n\t\t\t{\n\t\t\t\topacity: { value: 1.0 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.meshnormal_vert,\n\t\tfragmentShader: ShaderChunk.meshnormal_frag\n\n\t},\n\n\tsprite: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.sprite,\n\t\t\tUniformsLib.fog\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.sprite_vert,\n\t\tfragmentShader: ShaderChunk.sprite_frag\n\n\t},\n\n\tbackground: {\n\n\t\tuniforms: {\n\t\t\tuvTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tt2D: { value: null },\n\t\t\tbackgroundIntensity: { value: 1 }\n\t\t},\n\n\t\tvertexShader: ShaderChunk.background_vert,\n\t\tfragmentShader: ShaderChunk.background_frag\n\n\t},\n\n\tbackgroundCube: {\n\n\t\tuniforms: {\n\t\t\tenvMap: { value: null },\n\t\t\tflipEnvMap: { value: - 1 },\n\t\t\tbackgroundBlurriness: { value: 0 },\n\t\t\tbackgroundIntensity: { value: 1 },\n\t\t\tbackgroundRotation: { value: /*@__PURE__*/ new Matrix3() }\n\t\t},\n\n\t\tvertexShader: ShaderChunk.backgroundCube_vert,\n\t\tfragmentShader: ShaderChunk.backgroundCube_frag\n\n\t},\n\n\tcube: {\n\n\t\tuniforms: {\n\t\t\ttCube: { value: null },\n\t\t\ttFlip: { value: - 1 },\n\t\t\topacity: { value: 1.0 }\n\t\t},\n\n\t\tvertexShader: ShaderChunk.cube_vert,\n\t\tfragmentShader: ShaderChunk.cube_frag\n\n\t},\n\n\tequirect: {\n\n\t\tuniforms: {\n\t\t\ttEquirect: { value: null },\n\t\t},\n\n\t\tvertexShader: ShaderChunk.equirect_vert,\n\t\tfragmentShader: ShaderChunk.equirect_frag\n\n\t},\n\n\tdistanceRGBA: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.common,\n\t\t\tUniformsLib.displacementmap,\n\t\t\t{\n\t\t\t\treferencePosition: { value: /*@__PURE__*/ new Vector3() },\n\t\t\t\tnearDistance: { value: 1 },\n\t\t\t\tfarDistance: { value: 1000 }\n\t\t\t}\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.distanceRGBA_vert,\n\t\tfragmentShader: ShaderChunk.distanceRGBA_frag\n\n\t},\n\n\tshadow: {\n\n\t\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\t\tUniformsLib.lights,\n\t\t\tUniformsLib.fog,\n\t\t\t{\n\t\t\t\tcolor: { value: /*@__PURE__*/ new Color( 0x00000 ) },\n\t\t\t\topacity: { value: 1.0 }\n\t\t\t},\n\t\t] ),\n\n\t\tvertexShader: ShaderChunk.shadow_vert,\n\t\tfragmentShader: ShaderChunk.shadow_frag\n\n\t}\n\n};\n\nShaderLib.physical = {\n\n\tuniforms: /*@__PURE__*/ mergeUniforms( [\n\t\tShaderLib.standard.uniforms,\n\t\t{\n\t\t\tclearcoat: { value: 0 },\n\t\t\tclearcoatMap: { value: null },\n\t\t\tclearcoatMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tclearcoatNormalMap: { value: null },\n\t\t\tclearcoatNormalMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tclearcoatNormalScale: { value: /*@__PURE__*/ new Vector2( 1, 1 ) },\n\t\t\tclearcoatRoughness: { value: 0 },\n\t\t\tclearcoatRoughnessMap: { value: null },\n\t\t\tclearcoatRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tdispersion: { value: 0 },\n\t\t\tiridescence: { value: 0 },\n\t\t\tiridescenceMap: { value: null },\n\t\t\tiridescenceMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tiridescenceIOR: { value: 1.3 },\n\t\t\tiridescenceThicknessMinimum: { value: 100 },\n\t\t\tiridescenceThicknessMaximum: { value: 400 },\n\t\t\tiridescenceThicknessMap: { value: null },\n\t\t\tiridescenceThicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tsheen: { value: 0 },\n\t\t\tsheenColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },\n\t\t\tsheenColorMap: { value: null },\n\t\t\tsheenColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tsheenRoughness: { value: 1 },\n\t\t\tsheenRoughnessMap: { value: null },\n\t\t\tsheenRoughnessMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\ttransmission: { value: 0 },\n\t\t\ttransmissionMap: { value: null },\n\t\t\ttransmissionMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\ttransmissionSamplerSize: { value: /*@__PURE__*/ new Vector2() },\n\t\t\ttransmissionSamplerMap: { value: null },\n\t\t\tthickness: { value: 0 },\n\t\t\tthicknessMap: { value: null },\n\t\t\tthicknessMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tattenuationDistance: { value: 0 },\n\t\t\tattenuationColor: { value: /*@__PURE__*/ new Color( 0x000000 ) },\n\t\t\tspecularColor: { value: /*@__PURE__*/ new Color( 1, 1, 1 ) },\n\t\t\tspecularColorMap: { value: null },\n\t\t\tspecularColorMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tspecularIntensity: { value: 1 },\n\t\t\tspecularIntensityMap: { value: null },\n\t\t\tspecularIntensityMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t\tanisotropyVector: { value: /*@__PURE__*/ new Vector2() },\n\t\t\tanisotropyMap: { value: null },\n\t\t\tanisotropyMapTransform: { value: /*@__PURE__*/ new Matrix3() },\n\t\t}\n\t] ),\n\n\tvertexShader: ShaderChunk.meshphysical_vert,\n\tfragmentShader: ShaderChunk.meshphysical_frag\n\n};\n\nconst _rgb = { r: 0, b: 0, g: 0 };\nconst _e1$1 = /*@__PURE__*/ new Euler();\nconst _m1$1 = /*@__PURE__*/ new Matrix4();\n\nfunction WebGLBackground( renderer, cubemaps, cubeuvmaps, state, objects, alpha, premultipliedAlpha ) {\n\n\tconst clearColor = new Color( 0x000000 );\n\tlet clearAlpha = alpha === true ? 0 : 1;\n\n\tlet planeMesh;\n\tlet boxMesh;\n\n\tlet currentBackground = null;\n\tlet currentBackgroundVersion = 0;\n\tlet currentTonemapping = null;\n\n\tfunction getBackground( scene ) {\n\n\t\tlet background = scene.isScene === true ? scene.background : null;\n\n\t\tif ( background && background.isTexture ) {\n\n\t\t\tconst usePMREM = scene.backgroundBlurriness > 0; // use PMREM if the user wants to blur the background\n\t\t\tbackground = ( usePMREM ? cubeuvmaps : cubemaps ).get( background );\n\n\t\t}\n\n\t\treturn background;\n\n\t}\n\n\tfunction render( scene ) {\n\n\t\tlet forceClear = false;\n\t\tconst background = getBackground( scene );\n\n\t\tif ( background === null ) {\n\n\t\t\tsetClear( clearColor, clearAlpha );\n\n\t\t} else if ( background && background.isColor ) {\n\n\t\t\tsetClear( background, 1 );\n\t\t\tforceClear = true;\n\n\t\t}\n\n\t\tconst environmentBlendMode = renderer.xr.getEnvironmentBlendMode();\n\n\t\tif ( environmentBlendMode === 'additive' ) {\n\n\t\t\tstate.buffers.color.setClear( 0, 0, 0, 1, premultipliedAlpha );\n\n\t\t} else if ( environmentBlendMode === 'alpha-blend' ) {\n\n\t\t\tstate.buffers.color.setClear( 0, 0, 0, 0, premultipliedAlpha );\n\n\t\t}\n\n\t\tif ( renderer.autoClear || forceClear ) {\n\n\t\t\t// buffers might not be writable which is required to ensure a correct clear\n\n\t\t\tstate.buffers.depth.setTest( true );\n\t\t\tstate.buffers.depth.setMask( true );\n\t\t\tstate.buffers.color.setMask( true );\n\n\t\t\trenderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );\n\n\t\t}\n\n\t}\n\n\tfunction addToRenderList( renderList, scene ) {\n\n\t\tconst background = getBackground( scene );\n\n\t\tif ( background && ( background.isCubeTexture || background.mapping === CubeUVReflectionMapping ) ) {\n\n\t\t\tif ( boxMesh === undefined ) {\n\n\t\t\t\tboxMesh = new Mesh(\n\t\t\t\t\tnew BoxGeometry( 1, 1, 1 ),\n\t\t\t\t\tnew ShaderMaterial( {\n\t\t\t\t\t\tname: 'BackgroundCubeMaterial',\n\t\t\t\t\t\tuniforms: cloneUniforms( ShaderLib.backgroundCube.uniforms ),\n\t\t\t\t\t\tvertexShader: ShaderLib.backgroundCube.vertexShader,\n\t\t\t\t\t\tfragmentShader: ShaderLib.backgroundCube.fragmentShader,\n\t\t\t\t\t\tside: BackSide,\n\t\t\t\t\t\tdepthTest: false,\n\t\t\t\t\t\tdepthWrite: false,\n\t\t\t\t\t\tfog: false\n\t\t\t\t\t} )\n\t\t\t\t);\n\n\t\t\t\tboxMesh.geometry.deleteAttribute( 'normal' );\n\t\t\t\tboxMesh.geometry.deleteAttribute( 'uv' );\n\n\t\t\t\tboxMesh.onBeforeRender = function ( renderer, scene, camera ) {\n\n\t\t\t\t\tthis.matrixWorld.copyPosition( camera.matrixWorld );\n\n\t\t\t\t};\n\n\t\t\t\t// add \"envMap\" material property so the renderer can evaluate it like for built-in materials\n\t\t\t\tObject.defineProperty( boxMesh.material, 'envMap', {\n\n\t\t\t\t\tget: function () {\n\n\t\t\t\t\t\treturn this.uniforms.envMap.value;\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t\tobjects.update( boxMesh );\n\n\t\t\t}\n\n\t\t\t_e1$1.copy( scene.backgroundRotation );\n\n\t\t\t// accommodate left-handed frame\n\t\t\t_e1$1.x *= - 1; _e1$1.y *= - 1; _e1$1.z *= - 1;\n\n\t\t\tif ( background.isCubeTexture && background.isRenderTargetTexture === false ) {\n\n\t\t\t\t// environment maps which are not cube render targets or PMREMs follow a different convention\n\t\t\t\t_e1$1.y *= - 1;\n\t\t\t\t_e1$1.z *= - 1;\n\n\t\t\t}\n\n\t\t\tboxMesh.material.uniforms.envMap.value = background;\n\t\t\tboxMesh.material.uniforms.flipEnvMap.value = ( background.isCubeTexture && background.isRenderTargetTexture === false ) ? - 1 : 1;\n\t\t\tboxMesh.material.uniforms.backgroundBlurriness.value = scene.backgroundBlurriness;\n\t\t\tboxMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;\n\t\t\tboxMesh.material.uniforms.backgroundRotation.value.setFromMatrix4( _m1$1.makeRotationFromEuler( _e1$1 ) );\n\t\t\tboxMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;\n\n\t\t\tif ( currentBackground !== background ||\n\t\t\t\tcurrentBackgroundVersion !== background.version ||\n\t\t\t\tcurrentTonemapping !== renderer.toneMapping ) {\n\n\t\t\t\tboxMesh.material.needsUpdate = true;\n\n\t\t\t\tcurrentBackground = background;\n\t\t\t\tcurrentBackgroundVersion = background.version;\n\t\t\t\tcurrentTonemapping = renderer.toneMapping;\n\n\t\t\t}\n\n\t\t\tboxMesh.layers.enableAll();\n\n\t\t\t// push to the pre-sorted opaque render list\n\t\t\trenderList.unshift( boxMesh, boxMesh.geometry, boxMesh.material, 0, 0, null );\n\n\t\t} else if ( background && background.isTexture ) {\n\n\t\t\tif ( planeMesh === undefined ) {\n\n\t\t\t\tplaneMesh = new Mesh(\n\t\t\t\t\tnew PlaneGeometry( 2, 2 ),\n\t\t\t\t\tnew ShaderMaterial( {\n\t\t\t\t\t\tname: 'BackgroundMaterial',\n\t\t\t\t\t\tuniforms: cloneUniforms( ShaderLib.background.uniforms ),\n\t\t\t\t\t\tvertexShader: ShaderLib.background.vertexShader,\n\t\t\t\t\t\tfragmentShader: ShaderLib.background.fragmentShader,\n\t\t\t\t\t\tside: FrontSide,\n\t\t\t\t\t\tdepthTest: false,\n\t\t\t\t\t\tdepthWrite: false,\n\t\t\t\t\t\tfog: false\n\t\t\t\t\t} )\n\t\t\t\t);\n\n\t\t\t\tplaneMesh.geometry.deleteAttribute( 'normal' );\n\n\t\t\t\t// add \"map\" material property so the renderer can evaluate it like for built-in materials\n\t\t\t\tObject.defineProperty( planeMesh.material, 'map', {\n\n\t\t\t\t\tget: function () {\n\n\t\t\t\t\t\treturn this.uniforms.t2D.value;\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t\tobjects.update( planeMesh );\n\n\t\t\t}\n\n\t\t\tplaneMesh.material.uniforms.t2D.value = background;\n\t\t\tplaneMesh.material.uniforms.backgroundIntensity.value = scene.backgroundIntensity;\n\t\t\tplaneMesh.material.toneMapped = ColorManagement.getTransfer( background.colorSpace ) !== SRGBTransfer;\n\n\t\t\tif ( background.matrixAutoUpdate === true ) {\n\n\t\t\t\tbackground.updateMatrix();\n\n\t\t\t}\n\n\t\t\tplaneMesh.material.uniforms.uvTransform.value.copy( background.matrix );\n\n\t\t\tif ( currentBackground !== background ||\n\t\t\t\tcurrentBackgroundVersion !== background.version ||\n\t\t\t\tcurrentTonemapping !== renderer.toneMapping ) {\n\n\t\t\t\tplaneMesh.material.needsUpdate = true;\n\n\t\t\t\tcurrentBackground = background;\n\t\t\t\tcurrentBackgroundVersion = background.version;\n\t\t\t\tcurrentTonemapping = renderer.toneMapping;\n\n\t\t\t}\n\n\t\t\tplaneMesh.layers.enableAll();\n\n\t\t\t// push to the pre-sorted opaque render list\n\t\t\trenderList.unshift( planeMesh, planeMesh.geometry, planeMesh.material, 0, 0, null );\n\n\t\t}\n\n\t}\n\n\tfunction setClear( color, alpha ) {\n\n\t\tcolor.getRGB( _rgb, getUnlitUniformColorSpace( renderer ) );\n\n\t\tstate.buffers.color.setClear( _rgb.r, _rgb.g, _rgb.b, alpha, premultipliedAlpha );\n\n\t}\n\n\treturn {\n\n\t\tgetClearColor: function () {\n\n\t\t\treturn clearColor;\n\n\t\t},\n\t\tsetClearColor: function ( color, alpha = 1 ) {\n\n\t\t\tclearColor.set( color );\n\t\t\tclearAlpha = alpha;\n\t\t\tsetClear( clearColor, clearAlpha );\n\n\t\t},\n\t\tgetClearAlpha: function () {\n\n\t\t\treturn clearAlpha;\n\n\t\t},\n\t\tsetClearAlpha: function ( alpha ) {\n\n\t\t\tclearAlpha = alpha;\n\t\t\tsetClear( clearColor, clearAlpha );\n\n\t\t},\n\t\trender: render,\n\t\taddToRenderList: addToRenderList\n\n\t};\n\n}\n\nfunction WebGLBindingStates( gl, attributes ) {\n\n\tconst maxVertexAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );\n\n\tconst bindingStates = {};\n\n\tconst defaultState = createBindingState( null );\n\tlet currentState = defaultState;\n\tlet forceUpdate = false;\n\n\tfunction setup( object, material, program, geometry, index ) {\n\n\t\tlet updateBuffers = false;\n\n\t\tconst state = getBindingState( geometry, program, material );\n\n\t\tif ( currentState !== state ) {\n\n\t\t\tcurrentState = state;\n\t\t\tbindVertexArrayObject( currentState.object );\n\n\t\t}\n\n\t\tupdateBuffers = needsUpdate( object, geometry, program, index );\n\n\t\tif ( updateBuffers ) saveCache( object, geometry, program, index );\n\n\t\tif ( index !== null ) {\n\n\t\t\tattributes.update( index, gl.ELEMENT_ARRAY_BUFFER );\n\n\t\t}\n\n\t\tif ( updateBuffers || forceUpdate ) {\n\n\t\t\tforceUpdate = false;\n\n\t\t\tsetupVertexAttributes( object, material, program, geometry );\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tgl.bindBuffer( gl.ELEMENT_ARRAY_BUFFER, attributes.get( index ).buffer );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction createVertexArrayObject() {\n\n\t\treturn gl.createVertexArray();\n\n\t}\n\n\tfunction bindVertexArrayObject( vao ) {\n\n\t\treturn gl.bindVertexArray( vao );\n\n\t}\n\n\tfunction deleteVertexArrayObject( vao ) {\n\n\t\treturn gl.deleteVertexArray( vao );\n\n\t}\n\n\tfunction getBindingState( geometry, program, material ) {\n\n\t\tconst wireframe = ( material.wireframe === true );\n\n\t\tlet programMap = bindingStates[ geometry.id ];\n\n\t\tif ( programMap === undefined ) {\n\n\t\t\tprogramMap = {};\n\t\t\tbindingStates[ geometry.id ] = programMap;\n\n\t\t}\n\n\t\tlet stateMap = programMap[ program.id ];\n\n\t\tif ( stateMap === undefined ) {\n\n\t\t\tstateMap = {};\n\t\t\tprogramMap[ program.id ] = stateMap;\n\n\t\t}\n\n\t\tlet state = stateMap[ wireframe ];\n\n\t\tif ( state === undefined ) {\n\n\t\t\tstate = createBindingState( createVertexArrayObject() );\n\t\t\tstateMap[ wireframe ] = state;\n\n\t\t}\n\n\t\treturn state;\n\n\t}\n\n\tfunction createBindingState( vao ) {\n\n\t\tconst newAttributes = [];\n\t\tconst enabledAttributes = [];\n\t\tconst attributeDivisors = [];\n\n\t\tfor ( let i = 0; i < maxVertexAttributes; i ++ ) {\n\n\t\t\tnewAttributes[ i ] = 0;\n\t\t\tenabledAttributes[ i ] = 0;\n\t\t\tattributeDivisors[ i ] = 0;\n\n\t\t}\n\n\t\treturn {\n\n\t\t\t// for backward compatibility on non-VAO support browser\n\t\t\tgeometry: null,\n\t\t\tprogram: null,\n\t\t\twireframe: false,\n\n\t\t\tnewAttributes: newAttributes,\n\t\t\tenabledAttributes: enabledAttributes,\n\t\t\tattributeDivisors: attributeDivisors,\n\t\t\tobject: vao,\n\t\t\tattributes: {},\n\t\t\tindex: null\n\n\t\t};\n\n\t}\n\n\tfunction needsUpdate( object, geometry, program, index ) {\n\n\t\tconst cachedAttributes = currentState.attributes;\n\t\tconst geometryAttributes = geometry.attributes;\n\n\t\tlet attributesNum = 0;\n\n\t\tconst programAttributes = program.getAttributes();\n\n\t\tfor ( const name in programAttributes ) {\n\n\t\t\tconst programAttribute = programAttributes[ name ];\n\n\t\t\tif ( programAttribute.location >= 0 ) {\n\n\t\t\t\tconst cachedAttribute = cachedAttributes[ name ];\n\t\t\t\tlet geometryAttribute = geometryAttributes[ name ];\n\n\t\t\t\tif ( geometryAttribute === undefined ) {\n\n\t\t\t\t\tif ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;\n\t\t\t\t\tif ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;\n\n\t\t\t\t}\n\n\t\t\t\tif ( cachedAttribute === undefined ) return true;\n\n\t\t\t\tif ( cachedAttribute.attribute !== geometryAttribute ) return true;\n\n\t\t\t\tif ( geometryAttribute && cachedAttribute.data !== geometryAttribute.data ) return true;\n\n\t\t\t\tattributesNum ++;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( currentState.attributesNum !== attributesNum ) return true;\n\n\t\tif ( currentState.index !== index ) return true;\n\n\t\treturn false;\n\n\t}\n\n\tfunction saveCache( object, geometry, program, index ) {\n\n\t\tconst cache = {};\n\t\tconst attributes = geometry.attributes;\n\t\tlet attributesNum = 0;\n\n\t\tconst programAttributes = program.getAttributes();\n\n\t\tfor ( const name in programAttributes ) {\n\n\t\t\tconst programAttribute = programAttributes[ name ];\n\n\t\t\tif ( programAttribute.location >= 0 ) {\n\n\t\t\t\tlet attribute = attributes[ name ];\n\n\t\t\t\tif ( attribute === undefined ) {\n\n\t\t\t\t\tif ( name === 'instanceMatrix' && object.instanceMatrix ) attribute = object.instanceMatrix;\n\t\t\t\t\tif ( name === 'instanceColor' && object.instanceColor ) attribute = object.instanceColor;\n\n\t\t\t\t}\n\n\t\t\t\tconst data = {};\n\t\t\t\tdata.attribute = attribute;\n\n\t\t\t\tif ( attribute && attribute.data ) {\n\n\t\t\t\t\tdata.data = attribute.data;\n\n\t\t\t\t}\n\n\t\t\t\tcache[ name ] = data;\n\n\t\t\t\tattributesNum ++;\n\n\t\t\t}\n\n\t\t}\n\n\t\tcurrentState.attributes = cache;\n\t\tcurrentState.attributesNum = attributesNum;\n\n\t\tcurrentState.index = index;\n\n\t}\n\n\tfunction initAttributes() {\n\n\t\tconst newAttributes = currentState.newAttributes;\n\n\t\tfor ( let i = 0, il = newAttributes.length; i < il; i ++ ) {\n\n\t\t\tnewAttributes[ i ] = 0;\n\n\t\t}\n\n\t}\n\n\tfunction enableAttribute( attribute ) {\n\n\t\tenableAttributeAndDivisor( attribute, 0 );\n\n\t}\n\n\tfunction enableAttributeAndDivisor( attribute, meshPerAttribute ) {\n\n\t\tconst newAttributes = currentState.newAttributes;\n\t\tconst enabledAttributes = currentState.enabledAttributes;\n\t\tconst attributeDivisors = currentState.attributeDivisors;\n\n\t\tnewAttributes[ attribute ] = 1;\n\n\t\tif ( enabledAttributes[ attribute ] === 0 ) {\n\n\t\t\tgl.enableVertexAttribArray( attribute );\n\t\t\tenabledAttributes[ attribute ] = 1;\n\n\t\t}\n\n\t\tif ( attributeDivisors[ attribute ] !== meshPerAttribute ) {\n\n\t\t\tgl.vertexAttribDivisor( attribute, meshPerAttribute );\n\t\t\tattributeDivisors[ attribute ] = meshPerAttribute;\n\n\t\t}\n\n\t}\n\n\tfunction disableUnusedAttributes() {\n\n\t\tconst newAttributes = currentState.newAttributes;\n\t\tconst enabledAttributes = currentState.enabledAttributes;\n\n\t\tfor ( let i = 0, il = enabledAttributes.length; i < il; i ++ ) {\n\n\t\t\tif ( enabledAttributes[ i ] !== newAttributes[ i ] ) {\n\n\t\t\t\tgl.disableVertexAttribArray( i );\n\t\t\t\tenabledAttributes[ i ] = 0;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction vertexAttribPointer( index, size, type, normalized, stride, offset, integer ) {\n\n\t\tif ( integer === true ) {\n\n\t\t\tgl.vertexAttribIPointer( index, size, type, stride, offset );\n\n\t\t} else {\n\n\t\t\tgl.vertexAttribPointer( index, size, type, normalized, stride, offset );\n\n\t\t}\n\n\t}\n\n\tfunction setupVertexAttributes( object, material, program, geometry ) {\n\n\t\tinitAttributes();\n\n\t\tconst geometryAttributes = geometry.attributes;\n\n\t\tconst programAttributes = program.getAttributes();\n\n\t\tconst materialDefaultAttributeValues = material.defaultAttributeValues;\n\n\t\tfor ( const name in programAttributes ) {\n\n\t\t\tconst programAttribute = programAttributes[ name ];\n\n\t\t\tif ( programAttribute.location >= 0 ) {\n\n\t\t\t\tlet geometryAttribute = geometryAttributes[ name ];\n\n\t\t\t\tif ( geometryAttribute === undefined ) {\n\n\t\t\t\t\tif ( name === 'instanceMatrix' && object.instanceMatrix ) geometryAttribute = object.instanceMatrix;\n\t\t\t\t\tif ( name === 'instanceColor' && object.instanceColor ) geometryAttribute = object.instanceColor;\n\n\t\t\t\t}\n\n\t\t\t\tif ( geometryAttribute !== undefined ) {\n\n\t\t\t\t\tconst normalized = geometryAttribute.normalized;\n\t\t\t\t\tconst size = geometryAttribute.itemSize;\n\n\t\t\t\t\tconst attribute = attributes.get( geometryAttribute );\n\n\t\t\t\t\t// TODO Attribute may not be available on context restore\n\n\t\t\t\t\tif ( attribute === undefined ) continue;\n\n\t\t\t\t\tconst buffer = attribute.buffer;\n\t\t\t\t\tconst type = attribute.type;\n\t\t\t\t\tconst bytesPerElement = attribute.bytesPerElement;\n\n\t\t\t\t\t// check for integer attributes\n\n\t\t\t\t\tconst integer = ( type === gl.INT || type === gl.UNSIGNED_INT || geometryAttribute.gpuType === IntType );\n\n\t\t\t\t\tif ( geometryAttribute.isInterleavedBufferAttribute ) {\n\n\t\t\t\t\t\tconst data = geometryAttribute.data;\n\t\t\t\t\t\tconst stride = data.stride;\n\t\t\t\t\t\tconst offset = geometryAttribute.offset;\n\n\t\t\t\t\t\tif ( data.isInstancedInterleavedBuffer ) {\n\n\t\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\t\tenableAttributeAndDivisor( programAttribute.location + i, data.meshPerAttribute );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {\n\n\t\t\t\t\t\t\t\tgeometry._maxInstanceCount = data.meshPerAttribute * data.count;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\t\tenableAttribute( programAttribute.location + i );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgl.bindBuffer( gl.ARRAY_BUFFER, buffer );\n\n\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\tvertexAttribPointer(\n\t\t\t\t\t\t\t\tprogramAttribute.location + i,\n\t\t\t\t\t\t\t\tsize / programAttribute.locationSize,\n\t\t\t\t\t\t\t\ttype,\n\t\t\t\t\t\t\t\tnormalized,\n\t\t\t\t\t\t\t\tstride * bytesPerElement,\n\t\t\t\t\t\t\t\t( offset + ( size / programAttribute.locationSize ) * i ) * bytesPerElement,\n\t\t\t\t\t\t\t\tinteger\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( geometryAttribute.isInstancedBufferAttribute ) {\n\n\t\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\t\tenableAttributeAndDivisor( programAttribute.location + i, geometryAttribute.meshPerAttribute );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( object.isInstancedMesh !== true && geometry._maxInstanceCount === undefined ) {\n\n\t\t\t\t\t\t\t\tgeometry._maxInstanceCount = geometryAttribute.meshPerAttribute * geometryAttribute.count;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\t\tenableAttribute( programAttribute.location + i );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tgl.bindBuffer( gl.ARRAY_BUFFER, buffer );\n\n\t\t\t\t\t\tfor ( let i = 0; i < programAttribute.locationSize; i ++ ) {\n\n\t\t\t\t\t\t\tvertexAttribPointer(\n\t\t\t\t\t\t\t\tprogramAttribute.location + i,\n\t\t\t\t\t\t\t\tsize / programAttribute.locationSize,\n\t\t\t\t\t\t\t\ttype,\n\t\t\t\t\t\t\t\tnormalized,\n\t\t\t\t\t\t\t\tsize * bytesPerElement,\n\t\t\t\t\t\t\t\t( size / programAttribute.locationSize ) * i * bytesPerElement,\n\t\t\t\t\t\t\t\tinteger\n\t\t\t\t\t\t\t);\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( materialDefaultAttributeValues !== undefined ) {\n\n\t\t\t\t\tconst value = materialDefaultAttributeValues[ name ];\n\n\t\t\t\t\tif ( value !== undefined ) {\n\n\t\t\t\t\t\tswitch ( value.length ) {\n\n\t\t\t\t\t\t\tcase 2:\n\t\t\t\t\t\t\t\tgl.vertexAttrib2fv( programAttribute.location, value );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 3:\n\t\t\t\t\t\t\t\tgl.vertexAttrib3fv( programAttribute.location, value );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tcase 4:\n\t\t\t\t\t\t\t\tgl.vertexAttrib4fv( programAttribute.location, value );\n\t\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\t\tgl.vertexAttrib1fv( programAttribute.location, value );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tdisableUnusedAttributes();\n\n\t}\n\n\tfunction dispose() {\n\n\t\treset();\n\n\t\tfor ( const geometryId in bindingStates ) {\n\n\t\t\tconst programMap = bindingStates[ geometryId ];\n\n\t\t\tfor ( const programId in programMap ) {\n\n\t\t\t\tconst stateMap = programMap[ programId ];\n\n\t\t\t\tfor ( const wireframe in stateMap ) {\n\n\t\t\t\t\tdeleteVertexArrayObject( stateMap[ wireframe ].object );\n\n\t\t\t\t\tdelete stateMap[ wireframe ];\n\n\t\t\t\t}\n\n\t\t\t\tdelete programMap[ programId ];\n\n\t\t\t}\n\n\t\t\tdelete bindingStates[ geometryId ];\n\n\t\t}\n\n\t}\n\n\tfunction releaseStatesOfGeometry( geometry ) {\n\n\t\tif ( bindingStates[ geometry.id ] === undefined ) return;\n\n\t\tconst programMap = bindingStates[ geometry.id ];\n\n\t\tfor ( const programId in programMap ) {\n\n\t\t\tconst stateMap = programMap[ programId ];\n\n\t\t\tfor ( const wireframe in stateMap ) {\n\n\t\t\t\tdeleteVertexArrayObject( stateMap[ wireframe ].object );\n\n\t\t\t\tdelete stateMap[ wireframe ];\n\n\t\t\t}\n\n\t\t\tdelete programMap[ programId ];\n\n\t\t}\n\n\t\tdelete bindingStates[ geometry.id ];\n\n\t}\n\n\tfunction releaseStatesOfProgram( program ) {\n\n\t\tfor ( const geometryId in bindingStates ) {\n\n\t\t\tconst programMap = bindingStates[ geometryId ];\n\n\t\t\tif ( programMap[ program.id ] === undefined ) continue;\n\n\t\t\tconst stateMap = programMap[ program.id ];\n\n\t\t\tfor ( const wireframe in stateMap ) {\n\n\t\t\t\tdeleteVertexArrayObject( stateMap[ wireframe ].object );\n\n\t\t\t\tdelete stateMap[ wireframe ];\n\n\t\t\t}\n\n\t\t\tdelete programMap[ program.id ];\n\n\t\t}\n\n\t}\n\n\tfunction reset() {\n\n\t\tresetDefaultState();\n\t\tforceUpdate = true;\n\n\t\tif ( currentState === defaultState ) return;\n\n\t\tcurrentState = defaultState;\n\t\tbindVertexArrayObject( currentState.object );\n\n\t}\n\n\t// for backward-compatibility\n\n\tfunction resetDefaultState() {\n\n\t\tdefaultState.geometry = null;\n\t\tdefaultState.program = null;\n\t\tdefaultState.wireframe = false;\n\n\t}\n\n\treturn {\n\n\t\tsetup: setup,\n\t\treset: reset,\n\t\tresetDefaultState: resetDefaultState,\n\t\tdispose: dispose,\n\t\treleaseStatesOfGeometry: releaseStatesOfGeometry,\n\t\treleaseStatesOfProgram: releaseStatesOfProgram,\n\n\t\tinitAttributes: initAttributes,\n\t\tenableAttribute: enableAttribute,\n\t\tdisableUnusedAttributes: disableUnusedAttributes\n\n\t};\n\n}\n\nfunction WebGLBufferRenderer( gl, extensions, info ) {\n\n\tlet mode;\n\n\tfunction setMode( value ) {\n\n\t\tmode = value;\n\n\t}\n\n\tfunction render( start, count ) {\n\n\t\tgl.drawArrays( mode, start, count );\n\n\t\tinfo.update( count, mode, 1 );\n\n\t}\n\n\tfunction renderInstances( start, count, primcount ) {\n\n\t\tif ( primcount === 0 ) return;\n\n\t\tgl.drawArraysInstanced( mode, start, count, primcount );\n\n\t\tinfo.update( count, mode, primcount );\n\n\t}\n\n\tfunction renderMultiDraw( starts, counts, drawCount ) {\n\n\t\tif ( drawCount === 0 ) return;\n\n\t\tconst extension = extensions.get( 'WEBGL_multi_draw' );\n\t\textension.multiDrawArraysWEBGL( mode, starts, 0, counts, 0, drawCount );\n\n\t\tlet elementCount = 0;\n\t\tfor ( let i = 0; i < drawCount; i ++ ) {\n\n\t\t\telementCount += counts[ i ];\n\n\t\t}\n\n\t\tinfo.update( elementCount, mode, 1 );\n\n\t}\n\n\tfunction renderMultiDrawInstances( starts, counts, drawCount, primcount ) {\n\n\t\tif ( drawCount === 0 ) return;\n\n\t\tconst extension = extensions.get( 'WEBGL_multi_draw' );\n\n\t\tif ( extension === null ) {\n\n\t\t\tfor ( let i = 0; i < starts.length; i ++ ) {\n\n\t\t\t\trenderInstances( starts[ i ], counts[ i ], primcount[ i ] );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\textension.multiDrawArraysInstancedWEBGL( mode, starts, 0, counts, 0, primcount, 0, drawCount );\n\n\t\t\tlet elementCount = 0;\n\t\t\tfor ( let i = 0; i < drawCount; i ++ ) {\n\n\t\t\t\telementCount += counts[ i ];\n\n\t\t\t}\n\n\t\t\tfor ( let i = 0; i < primcount.length; i ++ ) {\n\n\t\t\t\tinfo.update( elementCount, mode, primcount[ i ] );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t//\n\n\tthis.setMode = setMode;\n\tthis.render = render;\n\tthis.renderInstances = renderInstances;\n\tthis.renderMultiDraw = renderMultiDraw;\n\tthis.renderMultiDrawInstances = renderMultiDrawInstances;\n\n}\n\nfunction WebGLCapabilities( gl, extensions, parameters, utils ) {\n\n\tlet maxAnisotropy;\n\n\tfunction getMaxAnisotropy() {\n\n\t\tif ( maxAnisotropy !== undefined ) return maxAnisotropy;\n\n\t\tif ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {\n\n\t\t\tconst extension = extensions.get( 'EXT_texture_filter_anisotropic' );\n\n\t\t\tmaxAnisotropy = gl.getParameter( extension.MAX_TEXTURE_MAX_ANISOTROPY_EXT );\n\n\t\t} else {\n\n\t\t\tmaxAnisotropy = 0;\n\n\t\t}\n\n\t\treturn maxAnisotropy;\n\n\t}\n\n\tfunction textureFormatReadable( textureFormat ) {\n\n\t\tif ( textureFormat !== RGBAFormat && utils.convert( textureFormat ) !== gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_FORMAT ) ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tfunction textureTypeReadable( textureType ) {\n\n\t\tconst halfFloatSupportedByExt = ( textureType === HalfFloatType ) && ( extensions.has( 'EXT_color_buffer_half_float' ) || extensions.has( 'EXT_color_buffer_float' ) );\n\n\t\tif ( textureType !== UnsignedByteType && utils.convert( textureType ) !== gl.getParameter( gl.IMPLEMENTATION_COLOR_READ_TYPE ) && // Edge and Chrome Mac < 52 (#9513)\n\t\t\ttextureType !== FloatType && ! halfFloatSupportedByExt ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tfunction getMaxPrecision( precision ) {\n\n\t\tif ( precision === 'highp' ) {\n\n\t\t\tif ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.HIGH_FLOAT ).precision > 0 &&\n\t\t\t\tgl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.HIGH_FLOAT ).precision > 0 ) {\n\n\t\t\t\treturn 'highp';\n\n\t\t\t}\n\n\t\t\tprecision = 'mediump';\n\n\t\t}\n\n\t\tif ( precision === 'mediump' ) {\n\n\t\t\tif ( gl.getShaderPrecisionFormat( gl.VERTEX_SHADER, gl.MEDIUM_FLOAT ).precision > 0 &&\n\t\t\t\tgl.getShaderPrecisionFormat( gl.FRAGMENT_SHADER, gl.MEDIUM_FLOAT ).precision > 0 ) {\n\n\t\t\t\treturn 'mediump';\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn 'lowp';\n\n\t}\n\n\tlet precision = parameters.precision !== undefined ? parameters.precision : 'highp';\n\tconst maxPrecision = getMaxPrecision( precision );\n\n\tif ( maxPrecision !== precision ) {\n\n\t\tconsole.warn( 'THREE.WebGLRenderer:', precision, 'not supported, using', maxPrecision, 'instead.' );\n\t\tprecision = maxPrecision;\n\n\t}\n\n\tconst logarithmicDepthBuffer = parameters.logarithmicDepthBuffer === true;\n\n\tconst maxTextures = gl.getParameter( gl.MAX_TEXTURE_IMAGE_UNITS );\n\tconst maxVertexTextures = gl.getParameter( gl.MAX_VERTEX_TEXTURE_IMAGE_UNITS );\n\tconst maxTextureSize = gl.getParameter( gl.MAX_TEXTURE_SIZE );\n\tconst maxCubemapSize = gl.getParameter( gl.MAX_CUBE_MAP_TEXTURE_SIZE );\n\n\tconst maxAttributes = gl.getParameter( gl.MAX_VERTEX_ATTRIBS );\n\tconst maxVertexUniforms = gl.getParameter( gl.MAX_VERTEX_UNIFORM_VECTORS );\n\tconst maxVaryings = gl.getParameter( gl.MAX_VARYING_VECTORS );\n\tconst maxFragmentUniforms = gl.getParameter( gl.MAX_FRAGMENT_UNIFORM_VECTORS );\n\n\tconst vertexTextures = maxVertexTextures > 0;\n\n\tconst maxSamples = gl.getParameter( gl.MAX_SAMPLES );\n\n\treturn {\n\n\t\tisWebGL2: true, // keeping this for backwards compatibility\n\n\t\tgetMaxAnisotropy: getMaxAnisotropy,\n\t\tgetMaxPrecision: getMaxPrecision,\n\n\t\ttextureFormatReadable: textureFormatReadable,\n\t\ttextureTypeReadable: textureTypeReadable,\n\n\t\tprecision: precision,\n\t\tlogarithmicDepthBuffer: logarithmicDepthBuffer,\n\n\t\tmaxTextures: maxTextures,\n\t\tmaxVertexTextures: maxVertexTextures,\n\t\tmaxTextureSize: maxTextureSize,\n\t\tmaxCubemapSize: maxCubemapSize,\n\n\t\tmaxAttributes: maxAttributes,\n\t\tmaxVertexUniforms: maxVertexUniforms,\n\t\tmaxVaryings: maxVaryings,\n\t\tmaxFragmentUniforms: maxFragmentUniforms,\n\n\t\tvertexTextures: vertexTextures,\n\n\t\tmaxSamples: maxSamples\n\n\t};\n\n}\n\nfunction WebGLClipping( properties ) {\n\n\tconst scope = this;\n\n\tlet globalState = null,\n\t\tnumGlobalPlanes = 0,\n\t\tlocalClippingEnabled = false,\n\t\trenderingShadows = false;\n\n\tconst plane = new Plane(),\n\t\tviewNormalMatrix = new Matrix3(),\n\n\t\tuniform = { value: null, needsUpdate: false };\n\n\tthis.uniform = uniform;\n\tthis.numPlanes = 0;\n\tthis.numIntersection = 0;\n\n\tthis.init = function ( planes, enableLocalClipping ) {\n\n\t\tconst enabled =\n\t\t\tplanes.length !== 0 ||\n\t\t\tenableLocalClipping ||\n\t\t\t// enable state of previous frame - the clipping code has to\n\t\t\t// run another frame in order to reset the state:\n\t\t\tnumGlobalPlanes !== 0 ||\n\t\t\tlocalClippingEnabled;\n\n\t\tlocalClippingEnabled = enableLocalClipping;\n\n\t\tnumGlobalPlanes = planes.length;\n\n\t\treturn enabled;\n\n\t};\n\n\tthis.beginShadows = function () {\n\n\t\trenderingShadows = true;\n\t\tprojectPlanes( null );\n\n\t};\n\n\tthis.endShadows = function () {\n\n\t\trenderingShadows = false;\n\n\t};\n\n\tthis.setGlobalState = function ( planes, camera ) {\n\n\t\tglobalState = projectPlanes( planes, camera, 0 );\n\n\t};\n\n\tthis.setState = function ( material, camera, useCache ) {\n\n\t\tconst planes = material.clippingPlanes,\n\t\t\tclipIntersection = material.clipIntersection,\n\t\t\tclipShadows = material.clipShadows;\n\n\t\tconst materialProperties = properties.get( material );\n\n\t\tif ( ! localClippingEnabled || planes === null || planes.length === 0 || renderingShadows && ! clipShadows ) {\n\n\t\t\t// there's no local clipping\n\n\t\t\tif ( renderingShadows ) {\n\n\t\t\t\t// there's no global clipping\n\n\t\t\t\tprojectPlanes( null );\n\n\t\t\t} else {\n\n\t\t\t\tresetGlobalState();\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconst nGlobal = renderingShadows ? 0 : numGlobalPlanes,\n\t\t\t\tlGlobal = nGlobal * 4;\n\n\t\t\tlet dstArray = materialProperties.clippingState || null;\n\n\t\t\tuniform.value = dstArray; // ensure unique state\n\n\t\t\tdstArray = projectPlanes( planes, camera, lGlobal, useCache );\n\n\t\t\tfor ( let i = 0; i !== lGlobal; ++ i ) {\n\n\t\t\t\tdstArray[ i ] = globalState[ i ];\n\n\t\t\t}\n\n\t\t\tmaterialProperties.clippingState = dstArray;\n\t\t\tthis.numIntersection = clipIntersection ? this.numPlanes : 0;\n\t\t\tthis.numPlanes += nGlobal;\n\n\t\t}\n\n\n\t};\n\n\tfunction resetGlobalState() {\n\n\t\tif ( uniform.value !== globalState ) {\n\n\t\t\tuniform.value = globalState;\n\t\t\tuniform.needsUpdate = numGlobalPlanes > 0;\n\n\t\t}\n\n\t\tscope.numPlanes = numGlobalPlanes;\n\t\tscope.numIntersection = 0;\n\n\t}\n\n\tfunction projectPlanes( planes, camera, dstOffset, skipTransform ) {\n\n\t\tconst nPlanes = planes !== null ? planes.length : 0;\n\t\tlet dstArray = null;\n\n\t\tif ( nPlanes !== 0 ) {\n\n\t\t\tdstArray = uniform.value;\n\n\t\t\tif ( skipTransform !== true || dstArray === null ) {\n\n\t\t\t\tconst flatSize = dstOffset + nPlanes * 4,\n\t\t\t\t\tviewMatrix = camera.matrixWorldInverse;\n\n\t\t\t\tviewNormalMatrix.getNormalMatrix( viewMatrix );\n\n\t\t\t\tif ( dstArray === null || dstArray.length < flatSize ) {\n\n\t\t\t\t\tdstArray = new Float32Array( flatSize );\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let i = 0, i4 = dstOffset; i !== nPlanes; ++ i, i4 += 4 ) {\n\n\t\t\t\t\tplane.copy( planes[ i ] ).applyMatrix4( viewMatrix, viewNormalMatrix );\n\n\t\t\t\t\tplane.normal.toArray( dstArray, i4 );\n\t\t\t\t\tdstArray[ i4 + 3 ] = plane.constant;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tuniform.value = dstArray;\n\t\t\tuniform.needsUpdate = true;\n\n\t\t}\n\n\t\tscope.numPlanes = nPlanes;\n\t\tscope.numIntersection = 0;\n\n\t\treturn dstArray;\n\n\t}\n\n}\n\nfunction WebGLCubeMaps( renderer ) {\n\n\tlet cubemaps = new WeakMap();\n\n\tfunction mapTextureMapping( texture, mapping ) {\n\n\t\tif ( mapping === EquirectangularReflectionMapping ) {\n\n\t\t\ttexture.mapping = CubeReflectionMapping;\n\n\t\t} else if ( mapping === EquirectangularRefractionMapping ) {\n\n\t\t\ttexture.mapping = CubeRefractionMapping;\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n\tfunction get( texture ) {\n\n\t\tif ( texture && texture.isTexture ) {\n\n\t\t\tconst mapping = texture.mapping;\n\n\t\t\tif ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping ) {\n\n\t\t\t\tif ( cubemaps.has( texture ) ) {\n\n\t\t\t\t\tconst cubemap = cubemaps.get( texture ).texture;\n\t\t\t\t\treturn mapTextureMapping( cubemap, texture.mapping );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconst image = texture.image;\n\n\t\t\t\t\tif ( image && image.height > 0 ) {\n\n\t\t\t\t\t\tconst renderTarget = new WebGLCubeRenderTarget( image.height );\n\t\t\t\t\t\trenderTarget.fromEquirectangularTexture( renderer, texture );\n\t\t\t\t\t\tcubemaps.set( texture, renderTarget );\n\n\t\t\t\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\n\n\t\t\t\t\t\treturn mapTextureMapping( renderTarget.texture, texture.mapping );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// image not yet ready. try the conversion next frame\n\n\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n\tfunction onTextureDispose( event ) {\n\n\t\tconst texture = event.target;\n\n\t\ttexture.removeEventListener( 'dispose', onTextureDispose );\n\n\t\tconst cubemap = cubemaps.get( texture );\n\n\t\tif ( cubemap !== undefined ) {\n\n\t\t\tcubemaps.delete( texture );\n\t\t\tcubemap.dispose();\n\n\t\t}\n\n\t}\n\n\tfunction dispose() {\n\n\t\tcubemaps = new WeakMap();\n\n\t}\n\n\treturn {\n\t\tget: get,\n\t\tdispose: dispose\n\t};\n\n}\n\nclass OrthographicCamera extends Camera {\n\n\tconstructor( left = - 1, right = 1, top = 1, bottom = - 1, near = 0.1, far = 2000 ) {\n\n\t\tsuper();\n\n\t\tthis.isOrthographicCamera = true;\n\n\t\tthis.type = 'OrthographicCamera';\n\n\t\tthis.zoom = 1;\n\t\tthis.view = null;\n\n\t\tthis.left = left;\n\t\tthis.right = right;\n\t\tthis.top = top;\n\t\tthis.bottom = bottom;\n\n\t\tthis.near = near;\n\t\tthis.far = far;\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.left = source.left;\n\t\tthis.right = source.right;\n\t\tthis.top = source.top;\n\t\tthis.bottom = source.bottom;\n\t\tthis.near = source.near;\n\t\tthis.far = source.far;\n\n\t\tthis.zoom = source.zoom;\n\t\tthis.view = source.view === null ? null : Object.assign( {}, source.view );\n\n\t\treturn this;\n\n\t}\n\n\tsetViewOffset( fullWidth, fullHeight, x, y, width, height ) {\n\n\t\tif ( this.view === null ) {\n\n\t\t\tthis.view = {\n\t\t\t\tenabled: true,\n\t\t\t\tfullWidth: 1,\n\t\t\t\tfullHeight: 1,\n\t\t\t\toffsetX: 0,\n\t\t\t\toffsetY: 0,\n\t\t\t\twidth: 1,\n\t\t\t\theight: 1\n\t\t\t};\n\n\t\t}\n\n\t\tthis.view.enabled = true;\n\t\tthis.view.fullWidth = fullWidth;\n\t\tthis.view.fullHeight = fullHeight;\n\t\tthis.view.offsetX = x;\n\t\tthis.view.offsetY = y;\n\t\tthis.view.width = width;\n\t\tthis.view.height = height;\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tclearViewOffset() {\n\n\t\tif ( this.view !== null ) {\n\n\t\t\tthis.view.enabled = false;\n\n\t\t}\n\n\t\tthis.updateProjectionMatrix();\n\n\t}\n\n\tupdateProjectionMatrix() {\n\n\t\tconst dx = ( this.right - this.left ) / ( 2 * this.zoom );\n\t\tconst dy = ( this.top - this.bottom ) / ( 2 * this.zoom );\n\t\tconst cx = ( this.right + this.left ) / 2;\n\t\tconst cy = ( this.top + this.bottom ) / 2;\n\n\t\tlet left = cx - dx;\n\t\tlet right = cx + dx;\n\t\tlet top = cy + dy;\n\t\tlet bottom = cy - dy;\n\n\t\tif ( this.view !== null && this.view.enabled ) {\n\n\t\t\tconst scaleW = ( this.right - this.left ) / this.view.fullWidth / this.zoom;\n\t\t\tconst scaleH = ( this.top - this.bottom ) / this.view.fullHeight / this.zoom;\n\n\t\t\tleft += scaleW * this.view.offsetX;\n\t\t\tright = left + scaleW * this.view.width;\n\t\t\ttop -= scaleH * this.view.offsetY;\n\t\t\tbottom = top - scaleH * this.view.height;\n\n\t\t}\n\n\t\tthis.projectionMatrix.makeOrthographic( left, right, top, bottom, this.near, this.far, this.coordinateSystem );\n\n\t\tthis.projectionMatrixInverse.copy( this.projectionMatrix ).invert();\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.object.zoom = this.zoom;\n\t\tdata.object.left = this.left;\n\t\tdata.object.right = this.right;\n\t\tdata.object.top = this.top;\n\t\tdata.object.bottom = this.bottom;\n\t\tdata.object.near = this.near;\n\t\tdata.object.far = this.far;\n\n\t\tif ( this.view !== null ) data.object.view = Object.assign( {}, this.view );\n\n\t\treturn data;\n\n\t}\n\n}\n\nconst LOD_MIN = 4;\n\n// The standard deviations (radians) associated with the extra mips. These are\n// chosen to approximate a Trowbridge-Reitz distribution function times the\n// geometric shadowing function. These sigma values squared must match the\n// variance #defines in cube_uv_reflection_fragment.glsl.js.\nconst EXTRA_LOD_SIGMA = [ 0.125, 0.215, 0.35, 0.446, 0.526, 0.582 ];\n\n// The maximum length of the blur for loop. Smaller sigmas will use fewer\n// samples and exit early, but not recompile the shader.\nconst MAX_SAMPLES = 20;\n\nconst _flatCamera = /*@__PURE__*/ new OrthographicCamera();\nconst _clearColor = /*@__PURE__*/ new Color();\nlet _oldTarget = null;\nlet _oldActiveCubeFace = 0;\nlet _oldActiveMipmapLevel = 0;\nlet _oldXrEnabled = false;\n\n// Golden Ratio\nconst PHI = ( 1 + Math.sqrt( 5 ) ) / 2;\nconst INV_PHI = 1 / PHI;\n\n// Vertices of a dodecahedron (except the opposites, which represent the\n// same axis), used as axis directions evenly spread on a sphere.\nconst _axisDirections = [\n\t/*@__PURE__*/ new Vector3( - PHI, INV_PHI, 0 ),\n\t/*@__PURE__*/ new Vector3( PHI, INV_PHI, 0 ),\n\t/*@__PURE__*/ new Vector3( - INV_PHI, 0, PHI ),\n\t/*@__PURE__*/ new Vector3( INV_PHI, 0, PHI ),\n\t/*@__PURE__*/ new Vector3( 0, PHI, - INV_PHI ),\n\t/*@__PURE__*/ new Vector3( 0, PHI, INV_PHI ),\n\t/*@__PURE__*/ new Vector3( - 1, 1, - 1 ),\n\t/*@__PURE__*/ new Vector3( 1, 1, - 1 ),\n\t/*@__PURE__*/ new Vector3( - 1, 1, 1 ),\n\t/*@__PURE__*/ new Vector3( 1, 1, 1 ) ];\n\n/**\n * This class generates a Prefiltered, Mipmapped Radiance Environment Map\n * (PMREM) from a cubeMap environment texture. This allows different levels of\n * blur to be quickly accessed based on material roughness. It is packed into a\n * special CubeUV format that allows us to perform custom interpolation so that\n * we can support nonlinear formats such as RGBE. Unlike a traditional mipmap\n * chain, it only goes down to the LOD_MIN level (above), and then creates extra\n * even more filtered 'mips' at the same LOD_MIN resolution, associated with\n * higher roughness levels. In this way we maintain resolution to smoothly\n * interpolate diffuse lighting while limiting sampling computation.\n *\n * Paper: Fast, Accurate Image-Based Lighting\n * https://drive.google.com/file/d/15y8r_UpKlU9SvV4ILb0C3qCPecS8pvLz/view\n*/\n\nclass PMREMGenerator {\n\n\tconstructor( renderer ) {\n\n\t\tthis._renderer = renderer;\n\t\tthis._pingPongRenderTarget = null;\n\n\t\tthis._lodMax = 0;\n\t\tthis._cubeSize = 0;\n\t\tthis._lodPlanes = [];\n\t\tthis._sizeLods = [];\n\t\tthis._sigmas = [];\n\n\t\tthis._blurMaterial = null;\n\t\tthis._cubemapMaterial = null;\n\t\tthis._equirectMaterial = null;\n\n\t\tthis._compileMaterial( this._blurMaterial );\n\n\t}\n\n\t/**\n\t * Generates a PMREM from a supplied Scene, which can be faster than using an\n\t * image if networking bandwidth is low. Optional sigma specifies a blur radius\n\t * in radians to be applied to the scene before PMREM generation. Optional near\n\t * and far planes ensure the scene is rendered in its entirety (the cubeCamera\n\t * is placed at the origin).\n\t */\n\tfromScene( scene, sigma = 0, near = 0.1, far = 100 ) {\n\n\t\t_oldTarget = this._renderer.getRenderTarget();\n\t\t_oldActiveCubeFace = this._renderer.getActiveCubeFace();\n\t\t_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();\n\t\t_oldXrEnabled = this._renderer.xr.enabled;\n\n\t\tthis._renderer.xr.enabled = false;\n\n\t\tthis._setSize( 256 );\n\n\t\tconst cubeUVRenderTarget = this._allocateTargets();\n\t\tcubeUVRenderTarget.depthBuffer = true;\n\n\t\tthis._sceneToCubeUV( scene, near, far, cubeUVRenderTarget );\n\n\t\tif ( sigma > 0 ) {\n\n\t\t\tthis._blur( cubeUVRenderTarget, 0, 0, sigma );\n\n\t\t}\n\n\t\tthis._applyPMREM( cubeUVRenderTarget );\n\t\tthis._cleanup( cubeUVRenderTarget );\n\n\t\treturn cubeUVRenderTarget;\n\n\t}\n\n\t/**\n\t * Generates a PMREM from an equirectangular texture, which can be either LDR\n\t * or HDR. The ideal input image size is 1k (1024 x 512),\n\t * as this matches best with the 256 x 256 cubemap output.\n\t * The smallest supported equirectangular image size is 64 x 32.\n\t */\n\tfromEquirectangular( equirectangular, renderTarget = null ) {\n\n\t\treturn this._fromTexture( equirectangular, renderTarget );\n\n\t}\n\n\t/**\n\t * Generates a PMREM from an cubemap texture, which can be either LDR\n\t * or HDR. The ideal input cube size is 256 x 256,\n\t * as this matches best with the 256 x 256 cubemap output.\n\t * The smallest supported cube size is 16 x 16.\n\t */\n\tfromCubemap( cubemap, renderTarget = null ) {\n\n\t\treturn this._fromTexture( cubemap, renderTarget );\n\n\t}\n\n\t/**\n\t * Pre-compiles the cubemap shader. You can get faster start-up by invoking this method during\n\t * your texture's network fetch for increased concurrency.\n\t */\n\tcompileCubemapShader() {\n\n\t\tif ( this._cubemapMaterial === null ) {\n\n\t\t\tthis._cubemapMaterial = _getCubemapMaterial();\n\t\t\tthis._compileMaterial( this._cubemapMaterial );\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Pre-compiles the equirectangular shader. You can get faster start-up by invoking this method during\n\t * your texture's network fetch for increased concurrency.\n\t */\n\tcompileEquirectangularShader() {\n\n\t\tif ( this._equirectMaterial === null ) {\n\n\t\t\tthis._equirectMaterial = _getEquirectMaterial();\n\t\t\tthis._compileMaterial( this._equirectMaterial );\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Disposes of the PMREMGenerator's internal memory. Note that PMREMGenerator is a static class,\n\t * so you should not need more than one PMREMGenerator object. If you do, calling dispose() on\n\t * one of them will cause any others to also become unusable.\n\t */\n\tdispose() {\n\n\t\tthis._dispose();\n\n\t\tif ( this._cubemapMaterial !== null ) this._cubemapMaterial.dispose();\n\t\tif ( this._equirectMaterial !== null ) this._equirectMaterial.dispose();\n\n\t}\n\n\t// private interface\n\n\t_setSize( cubeSize ) {\n\n\t\tthis._lodMax = Math.floor( Math.log2( cubeSize ) );\n\t\tthis._cubeSize = Math.pow( 2, this._lodMax );\n\n\t}\n\n\t_dispose() {\n\n\t\tif ( this._blurMaterial !== null ) this._blurMaterial.dispose();\n\n\t\tif ( this._pingPongRenderTarget !== null ) this._pingPongRenderTarget.dispose();\n\n\t\tfor ( let i = 0; i < this._lodPlanes.length; i ++ ) {\n\n\t\t\tthis._lodPlanes[ i ].dispose();\n\n\t\t}\n\n\t}\n\n\t_cleanup( outputTarget ) {\n\n\t\tthis._renderer.setRenderTarget( _oldTarget, _oldActiveCubeFace, _oldActiveMipmapLevel );\n\t\tthis._renderer.xr.enabled = _oldXrEnabled;\n\n\t\toutputTarget.scissorTest = false;\n\t\t_setViewport( outputTarget, 0, 0, outputTarget.width, outputTarget.height );\n\n\t}\n\n\t_fromTexture( texture, renderTarget ) {\n\n\t\tif ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping ) {\n\n\t\t\tthis._setSize( texture.image.length === 0 ? 16 : ( texture.image[ 0 ].width || texture.image[ 0 ].image.width ) );\n\n\t\t} else { // Equirectangular\n\n\t\t\tthis._setSize( texture.image.width / 4 );\n\n\t\t}\n\n\t\t_oldTarget = this._renderer.getRenderTarget();\n\t\t_oldActiveCubeFace = this._renderer.getActiveCubeFace();\n\t\t_oldActiveMipmapLevel = this._renderer.getActiveMipmapLevel();\n\t\t_oldXrEnabled = this._renderer.xr.enabled;\n\n\t\tthis._renderer.xr.enabled = false;\n\n\t\tconst cubeUVRenderTarget = renderTarget || this._allocateTargets();\n\t\tthis._textureToCubeUV( texture, cubeUVRenderTarget );\n\t\tthis._applyPMREM( cubeUVRenderTarget );\n\t\tthis._cleanup( cubeUVRenderTarget );\n\n\t\treturn cubeUVRenderTarget;\n\n\t}\n\n\t_allocateTargets() {\n\n\t\tconst width = 3 * Math.max( this._cubeSize, 16 * 7 );\n\t\tconst height = 4 * this._cubeSize;\n\n\t\tconst params = {\n\t\t\tmagFilter: LinearFilter,\n\t\t\tminFilter: LinearFilter,\n\t\t\tgenerateMipmaps: false,\n\t\t\ttype: HalfFloatType,\n\t\t\tformat: RGBAFormat,\n\t\t\tcolorSpace: LinearSRGBColorSpace,\n\t\t\tdepthBuffer: false\n\t\t};\n\n\t\tconst cubeUVRenderTarget = _createRenderTarget( width, height, params );\n\n\t\tif ( this._pingPongRenderTarget === null || this._pingPongRenderTarget.width !== width || this._pingPongRenderTarget.height !== height ) {\n\n\t\t\tif ( this._pingPongRenderTarget !== null ) {\n\n\t\t\t\tthis._dispose();\n\n\t\t\t}\n\n\t\t\tthis._pingPongRenderTarget = _createRenderTarget( width, height, params );\n\n\t\t\tconst { _lodMax } = this;\n\t\t\t( { sizeLods: this._sizeLods, lodPlanes: this._lodPlanes, sigmas: this._sigmas } = _createPlanes( _lodMax ) );\n\n\t\t\tthis._blurMaterial = _getBlurShader( _lodMax, width, height );\n\n\t\t}\n\n\t\treturn cubeUVRenderTarget;\n\n\t}\n\n\t_compileMaterial( material ) {\n\n\t\tconst tmpMesh = new Mesh( this._lodPlanes[ 0 ], material );\n\t\tthis._renderer.compile( tmpMesh, _flatCamera );\n\n\t}\n\n\t_sceneToCubeUV( scene, near, far, cubeUVRenderTarget ) {\n\n\t\tconst fov = 90;\n\t\tconst aspect = 1;\n\t\tconst cubeCamera = new PerspectiveCamera( fov, aspect, near, far );\n\t\tconst upSign = [ 1, - 1, 1, 1, 1, 1 ];\n\t\tconst forwardSign = [ 1, 1, 1, - 1, - 1, - 1 ];\n\t\tconst renderer = this._renderer;\n\n\t\tconst originalAutoClear = renderer.autoClear;\n\t\tconst toneMapping = renderer.toneMapping;\n\t\trenderer.getClearColor( _clearColor );\n\n\t\trenderer.toneMapping = NoToneMapping;\n\t\trenderer.autoClear = false;\n\n\t\tconst backgroundMaterial = new MeshBasicMaterial( {\n\t\t\tname: 'PMREM.Background',\n\t\t\tside: BackSide,\n\t\t\tdepthWrite: false,\n\t\t\tdepthTest: false,\n\t\t} );\n\n\t\tconst backgroundBox = new Mesh( new BoxGeometry(), backgroundMaterial );\n\n\t\tlet useSolidColor = false;\n\t\tconst background = scene.background;\n\n\t\tif ( background ) {\n\n\t\t\tif ( background.isColor ) {\n\n\t\t\t\tbackgroundMaterial.color.copy( background );\n\t\t\t\tscene.background = null;\n\t\t\t\tuseSolidColor = true;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tbackgroundMaterial.color.copy( _clearColor );\n\t\t\tuseSolidColor = true;\n\n\t\t}\n\n\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\tconst col = i % 3;\n\n\t\t\tif ( col === 0 ) {\n\n\t\t\t\tcubeCamera.up.set( 0, upSign[ i ], 0 );\n\t\t\t\tcubeCamera.lookAt( forwardSign[ i ], 0, 0 );\n\n\t\t\t} else if ( col === 1 ) {\n\n\t\t\t\tcubeCamera.up.set( 0, 0, upSign[ i ] );\n\t\t\t\tcubeCamera.lookAt( 0, forwardSign[ i ], 0 );\n\n\t\t\t} else {\n\n\t\t\t\tcubeCamera.up.set( 0, upSign[ i ], 0 );\n\t\t\t\tcubeCamera.lookAt( 0, 0, forwardSign[ i ] );\n\n\t\t\t}\n\n\t\t\tconst size = this._cubeSize;\n\n\t\t\t_setViewport( cubeUVRenderTarget, col * size, i > 2 ? size : 0, size, size );\n\n\t\t\trenderer.setRenderTarget( cubeUVRenderTarget );\n\n\t\t\tif ( useSolidColor ) {\n\n\t\t\t\trenderer.render( backgroundBox, cubeCamera );\n\n\t\t\t}\n\n\t\t\trenderer.render( scene, cubeCamera );\n\n\t\t}\n\n\t\tbackgroundBox.geometry.dispose();\n\t\tbackgroundBox.material.dispose();\n\n\t\trenderer.toneMapping = toneMapping;\n\t\trenderer.autoClear = originalAutoClear;\n\t\tscene.background = background;\n\n\t}\n\n\t_textureToCubeUV( texture, cubeUVRenderTarget ) {\n\n\t\tconst renderer = this._renderer;\n\n\t\tconst isCubeTexture = ( texture.mapping === CubeReflectionMapping || texture.mapping === CubeRefractionMapping );\n\n\t\tif ( isCubeTexture ) {\n\n\t\t\tif ( this._cubemapMaterial === null ) {\n\n\t\t\t\tthis._cubemapMaterial = _getCubemapMaterial();\n\n\t\t\t}\n\n\t\t\tthis._cubemapMaterial.uniforms.flipEnvMap.value = ( texture.isRenderTargetTexture === false ) ? - 1 : 1;\n\n\t\t} else {\n\n\t\t\tif ( this._equirectMaterial === null ) {\n\n\t\t\t\tthis._equirectMaterial = _getEquirectMaterial();\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst material = isCubeTexture ? this._cubemapMaterial : this._equirectMaterial;\n\t\tconst mesh = new Mesh( this._lodPlanes[ 0 ], material );\n\n\t\tconst uniforms = material.uniforms;\n\n\t\tuniforms[ 'envMap' ].value = texture;\n\n\t\tconst size = this._cubeSize;\n\n\t\t_setViewport( cubeUVRenderTarget, 0, 0, 3 * size, 2 * size );\n\n\t\trenderer.setRenderTarget( cubeUVRenderTarget );\n\t\trenderer.render( mesh, _flatCamera );\n\n\t}\n\n\t_applyPMREM( cubeUVRenderTarget ) {\n\n\t\tconst renderer = this._renderer;\n\t\tconst autoClear = renderer.autoClear;\n\t\trenderer.autoClear = false;\n\t\tconst n = this._lodPlanes.length;\n\n\t\tfor ( let i = 1; i < n; i ++ ) {\n\n\t\t\tconst sigma = Math.sqrt( this._sigmas[ i ] * this._sigmas[ i ] - this._sigmas[ i - 1 ] * this._sigmas[ i - 1 ] );\n\n\t\t\tconst poleAxis = _axisDirections[ ( n - i - 1 ) % _axisDirections.length ];\n\n\t\t\tthis._blur( cubeUVRenderTarget, i - 1, i, sigma, poleAxis );\n\n\t\t}\n\n\t\trenderer.autoClear = autoClear;\n\n\t}\n\n\t/**\n\t * This is a two-pass Gaussian blur for a cubemap. Normally this is done\n\t * vertically and horizontally, but this breaks down on a cube. Here we apply\n\t * the blur latitudinally (around the poles), and then longitudinally (towards\n\t * the poles) to approximate the orthogonally-separable blur. It is least\n\t * accurate at the poles, but still does a decent job.\n\t */\n\t_blur( cubeUVRenderTarget, lodIn, lodOut, sigma, poleAxis ) {\n\n\t\tconst pingPongRenderTarget = this._pingPongRenderTarget;\n\n\t\tthis._halfBlur(\n\t\t\tcubeUVRenderTarget,\n\t\t\tpingPongRenderTarget,\n\t\t\tlodIn,\n\t\t\tlodOut,\n\t\t\tsigma,\n\t\t\t'latitudinal',\n\t\t\tpoleAxis );\n\n\t\tthis._halfBlur(\n\t\t\tpingPongRenderTarget,\n\t\t\tcubeUVRenderTarget,\n\t\t\tlodOut,\n\t\t\tlodOut,\n\t\t\tsigma,\n\t\t\t'longitudinal',\n\t\t\tpoleAxis );\n\n\t}\n\n\t_halfBlur( targetIn, targetOut, lodIn, lodOut, sigmaRadians, direction, poleAxis ) {\n\n\t\tconst renderer = this._renderer;\n\t\tconst blurMaterial = this._blurMaterial;\n\n\t\tif ( direction !== 'latitudinal' && direction !== 'longitudinal' ) {\n\n\t\t\tconsole.error(\n\t\t\t\t'blur direction must be either latitudinal or longitudinal!' );\n\n\t\t}\n\n\t\t// Number of standard deviations at which to cut off the discrete approximation.\n\t\tconst STANDARD_DEVIATIONS = 3;\n\n\t\tconst blurMesh = new Mesh( this._lodPlanes[ lodOut ], blurMaterial );\n\t\tconst blurUniforms = blurMaterial.uniforms;\n\n\t\tconst pixels = this._sizeLods[ lodIn ] - 1;\n\t\tconst radiansPerPixel = isFinite( sigmaRadians ) ? Math.PI / ( 2 * pixels ) : 2 * Math.PI / ( 2 * MAX_SAMPLES - 1 );\n\t\tconst sigmaPixels = sigmaRadians / radiansPerPixel;\n\t\tconst samples = isFinite( sigmaRadians ) ? 1 + Math.floor( STANDARD_DEVIATIONS * sigmaPixels ) : MAX_SAMPLES;\n\n\t\tif ( samples > MAX_SAMPLES ) {\n\n\t\t\tconsole.warn( `sigmaRadians, ${\n\t\t\t\tsigmaRadians}, is too large and will clip, as it requested ${\n\t\t\t\tsamples} samples when the maximum is set to ${MAX_SAMPLES}` );\n\n\t\t}\n\n\t\tconst weights = [];\n\t\tlet sum = 0;\n\n\t\tfor ( let i = 0; i < MAX_SAMPLES; ++ i ) {\n\n\t\t\tconst x = i / sigmaPixels;\n\t\t\tconst weight = Math.exp( - x * x / 2 );\n\t\t\tweights.push( weight );\n\n\t\t\tif ( i === 0 ) {\n\n\t\t\t\tsum += weight;\n\n\t\t\t} else if ( i < samples ) {\n\n\t\t\t\tsum += 2 * weight;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfor ( let i = 0; i < weights.length; i ++ ) {\n\n\t\t\tweights[ i ] = weights[ i ] / sum;\n\n\t\t}\n\n\t\tblurUniforms[ 'envMap' ].value = targetIn.texture;\n\t\tblurUniforms[ 'samples' ].value = samples;\n\t\tblurUniforms[ 'weights' ].value = weights;\n\t\tblurUniforms[ 'latitudinal' ].value = direction === 'latitudinal';\n\n\t\tif ( poleAxis ) {\n\n\t\t\tblurUniforms[ 'poleAxis' ].value = poleAxis;\n\n\t\t}\n\n\t\tconst { _lodMax } = this;\n\t\tblurUniforms[ 'dTheta' ].value = radiansPerPixel;\n\t\tblurUniforms[ 'mipInt' ].value = _lodMax - lodIn;\n\n\t\tconst outputSize = this._sizeLods[ lodOut ];\n\t\tconst x = 3 * outputSize * ( lodOut > _lodMax - LOD_MIN ? lodOut - _lodMax + LOD_MIN : 0 );\n\t\tconst y = 4 * ( this._cubeSize - outputSize );\n\n\t\t_setViewport( targetOut, x, y, 3 * outputSize, 2 * outputSize );\n\t\trenderer.setRenderTarget( targetOut );\n\t\trenderer.render( blurMesh, _flatCamera );\n\n\t}\n\n}\n\n\n\nfunction _createPlanes( lodMax ) {\n\n\tconst lodPlanes = [];\n\tconst sizeLods = [];\n\tconst sigmas = [];\n\n\tlet lod = lodMax;\n\n\tconst totalLods = lodMax - LOD_MIN + 1 + EXTRA_LOD_SIGMA.length;\n\n\tfor ( let i = 0; i < totalLods; i ++ ) {\n\n\t\tconst sizeLod = Math.pow( 2, lod );\n\t\tsizeLods.push( sizeLod );\n\t\tlet sigma = 1.0 / sizeLod;\n\n\t\tif ( i > lodMax - LOD_MIN ) {\n\n\t\t\tsigma = EXTRA_LOD_SIGMA[ i - lodMax + LOD_MIN - 1 ];\n\n\t\t} else if ( i === 0 ) {\n\n\t\t\tsigma = 0;\n\n\t\t}\n\n\t\tsigmas.push( sigma );\n\n\t\tconst texelSize = 1.0 / ( sizeLod - 2 );\n\t\tconst min = - texelSize;\n\t\tconst max = 1 + texelSize;\n\t\tconst uv1 = [ min, min, max, min, max, max, min, min, max, max, min, max ];\n\n\t\tconst cubeFaces = 6;\n\t\tconst vertices = 6;\n\t\tconst positionSize = 3;\n\t\tconst uvSize = 2;\n\t\tconst faceIndexSize = 1;\n\n\t\tconst position = new Float32Array( positionSize * vertices * cubeFaces );\n\t\tconst uv = new Float32Array( uvSize * vertices * cubeFaces );\n\t\tconst faceIndex = new Float32Array( faceIndexSize * vertices * cubeFaces );\n\n\t\tfor ( let face = 0; face < cubeFaces; face ++ ) {\n\n\t\t\tconst x = ( face % 3 ) * 2 / 3 - 1;\n\t\t\tconst y = face > 2 ? 0 : - 1;\n\t\t\tconst coordinates = [\n\t\t\t\tx, y, 0,\n\t\t\t\tx + 2 / 3, y, 0,\n\t\t\t\tx + 2 / 3, y + 1, 0,\n\t\t\t\tx, y, 0,\n\t\t\t\tx + 2 / 3, y + 1, 0,\n\t\t\t\tx, y + 1, 0\n\t\t\t];\n\t\t\tposition.set( coordinates, positionSize * vertices * face );\n\t\t\tuv.set( uv1, uvSize * vertices * face );\n\t\t\tconst fill = [ face, face, face, face, face, face ];\n\t\t\tfaceIndex.set( fill, faceIndexSize * vertices * face );\n\n\t\t}\n\n\t\tconst planes = new BufferGeometry();\n\t\tplanes.setAttribute( 'position', new BufferAttribute( position, positionSize ) );\n\t\tplanes.setAttribute( 'uv', new BufferAttribute( uv, uvSize ) );\n\t\tplanes.setAttribute( 'faceIndex', new BufferAttribute( faceIndex, faceIndexSize ) );\n\t\tlodPlanes.push( planes );\n\n\t\tif ( lod > LOD_MIN ) {\n\n\t\t\tlod --;\n\n\t\t}\n\n\t}\n\n\treturn { lodPlanes, sizeLods, sigmas };\n\n}\n\nfunction _createRenderTarget( width, height, params ) {\n\n\tconst cubeUVRenderTarget = new WebGLRenderTarget( width, height, params );\n\tcubeUVRenderTarget.texture.mapping = CubeUVReflectionMapping;\n\tcubeUVRenderTarget.texture.name = 'PMREM.cubeUv';\n\tcubeUVRenderTarget.scissorTest = true;\n\treturn cubeUVRenderTarget;\n\n}\n\nfunction _setViewport( target, x, y, width, height ) {\n\n\ttarget.viewport.set( x, y, width, height );\n\ttarget.scissor.set( x, y, width, height );\n\n}\n\nfunction _getBlurShader( lodMax, width, height ) {\n\n\tconst weights = new Float32Array( MAX_SAMPLES );\n\tconst poleAxis = new Vector3( 0, 1, 0 );\n\tconst shaderMaterial = new ShaderMaterial( {\n\n\t\tname: 'SphericalGaussianBlur',\n\n\t\tdefines: {\n\t\t\t'n': MAX_SAMPLES,\n\t\t\t'CUBEUV_TEXEL_WIDTH': 1.0 / width,\n\t\t\t'CUBEUV_TEXEL_HEIGHT': 1.0 / height,\n\t\t\t'CUBEUV_MAX_MIP': `${lodMax}.0`,\n\t\t},\n\n\t\tuniforms: {\n\t\t\t'envMap': { value: null },\n\t\t\t'samples': { value: 1 },\n\t\t\t'weights': { value: weights },\n\t\t\t'latitudinal': { value: false },\n\t\t\t'dTheta': { value: 0 },\n\t\t\t'mipInt': { value: 0 },\n\t\t\t'poleAxis': { value: poleAxis }\n\t\t},\n\n\t\tvertexShader: _getCommonVertexShader(),\n\n\t\tfragmentShader: /* glsl */`\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`,\n\n\t\tblending: NoBlending,\n\t\tdepthTest: false,\n\t\tdepthWrite: false\n\n\t} );\n\n\treturn shaderMaterial;\n\n}\n\nfunction _getEquirectMaterial() {\n\n\treturn new ShaderMaterial( {\n\n\t\tname: 'EquirectangularToCubeUV',\n\n\t\tuniforms: {\n\t\t\t'envMap': { value: null }\n\t\t},\n\n\t\tvertexShader: _getCommonVertexShader(),\n\n\t\tfragmentShader: /* glsl */`\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`,\n\n\t\tblending: NoBlending,\n\t\tdepthTest: false,\n\t\tdepthWrite: false\n\n\t} );\n\n}\n\nfunction _getCubemapMaterial() {\n\n\treturn new ShaderMaterial( {\n\n\t\tname: 'CubemapToCubeUV',\n\n\t\tuniforms: {\n\t\t\t'envMap': { value: null },\n\t\t\t'flipEnvMap': { value: - 1 }\n\t\t},\n\n\t\tvertexShader: _getCommonVertexShader(),\n\n\t\tfragmentShader: /* glsl */`\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`,\n\n\t\tblending: NoBlending,\n\t\tdepthTest: false,\n\t\tdepthWrite: false\n\n\t} );\n\n}\n\nfunction _getCommonVertexShader() {\n\n\treturn /* glsl */`\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`;\n\n}\n\nfunction WebGLCubeUVMaps( renderer ) {\n\n\tlet cubeUVmaps = new WeakMap();\n\n\tlet pmremGenerator = null;\n\n\tfunction get( texture ) {\n\n\t\tif ( texture && texture.isTexture ) {\n\n\t\t\tconst mapping = texture.mapping;\n\n\t\t\tconst isEquirectMap = ( mapping === EquirectangularReflectionMapping || mapping === EquirectangularRefractionMapping );\n\t\t\tconst isCubeMap = ( mapping === CubeReflectionMapping || mapping === CubeRefractionMapping );\n\n\t\t\t// equirect/cube map to cubeUV conversion\n\n\t\t\tif ( isEquirectMap || isCubeMap ) {\n\n\t\t\t\tlet renderTarget = cubeUVmaps.get( texture );\n\n\t\t\t\tconst currentPMREMVersion = renderTarget !== undefined ? renderTarget.texture.pmremVersion : 0;\n\n\t\t\t\tif ( texture.isRenderTargetTexture && texture.pmremVersion !== currentPMREMVersion ) {\n\n\t\t\t\t\tif ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );\n\n\t\t\t\t\trenderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture, renderTarget ) : pmremGenerator.fromCubemap( texture, renderTarget );\n\t\t\t\t\trenderTarget.texture.pmremVersion = texture.pmremVersion;\n\n\t\t\t\t\tcubeUVmaps.set( texture, renderTarget );\n\n\t\t\t\t\treturn renderTarget.texture;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( renderTarget !== undefined ) {\n\n\t\t\t\t\t\treturn renderTarget.texture;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconst image = texture.image;\n\n\t\t\t\t\t\tif ( ( isEquirectMap && image && image.height > 0 ) || ( isCubeMap && image && isCubeTextureComplete( image ) ) ) {\n\n\t\t\t\t\t\t\tif ( pmremGenerator === null ) pmremGenerator = new PMREMGenerator( renderer );\n\n\t\t\t\t\t\t\trenderTarget = isEquirectMap ? pmremGenerator.fromEquirectangular( texture ) : pmremGenerator.fromCubemap( texture );\n\t\t\t\t\t\t\trenderTarget.texture.pmremVersion = texture.pmremVersion;\n\n\t\t\t\t\t\t\tcubeUVmaps.set( texture, renderTarget );\n\n\t\t\t\t\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\n\n\t\t\t\t\t\t\treturn renderTarget.texture;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// image not yet ready. try the conversion next frame\n\n\t\t\t\t\t\t\treturn null;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n\tfunction isCubeTextureComplete( image ) {\n\n\t\tlet count = 0;\n\t\tconst length = 6;\n\n\t\tfor ( let i = 0; i < length; i ++ ) {\n\n\t\t\tif ( image[ i ] !== undefined ) count ++;\n\n\t\t}\n\n\t\treturn count === length;\n\n\n\t}\n\n\tfunction onTextureDispose( event ) {\n\n\t\tconst texture = event.target;\n\n\t\ttexture.removeEventListener( 'dispose', onTextureDispose );\n\n\t\tconst cubemapUV = cubeUVmaps.get( texture );\n\n\t\tif ( cubemapUV !== undefined ) {\n\n\t\t\tcubeUVmaps.delete( texture );\n\t\t\tcubemapUV.dispose();\n\n\t\t}\n\n\t}\n\n\tfunction dispose() {\n\n\t\tcubeUVmaps = new WeakMap();\n\n\t\tif ( pmremGenerator !== null ) {\n\n\t\t\tpmremGenerator.dispose();\n\t\t\tpmremGenerator = null;\n\n\t\t}\n\n\t}\n\n\treturn {\n\t\tget: get,\n\t\tdispose: dispose\n\t};\n\n}\n\nfunction WebGLExtensions( gl ) {\n\n\tconst extensions = {};\n\n\tfunction getExtension( name ) {\n\n\t\tif ( extensions[ name ] !== undefined ) {\n\n\t\t\treturn extensions[ name ];\n\n\t\t}\n\n\t\tlet extension;\n\n\t\tswitch ( name ) {\n\n\t\t\tcase 'WEBGL_depth_texture':\n\t\t\t\textension = gl.getExtension( 'WEBGL_depth_texture' ) || gl.getExtension( 'MOZ_WEBGL_depth_texture' ) || gl.getExtension( 'WEBKIT_WEBGL_depth_texture' );\n\t\t\t\tbreak;\n\n\t\t\tcase 'EXT_texture_filter_anisotropic':\n\t\t\t\textension = gl.getExtension( 'EXT_texture_filter_anisotropic' ) || gl.getExtension( 'MOZ_EXT_texture_filter_anisotropic' ) || gl.getExtension( 'WEBKIT_EXT_texture_filter_anisotropic' );\n\t\t\t\tbreak;\n\n\t\t\tcase 'WEBGL_compressed_texture_s3tc':\n\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'MOZ_WEBGL_compressed_texture_s3tc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_s3tc' );\n\t\t\t\tbreak;\n\n\t\t\tcase 'WEBGL_compressed_texture_pvrtc':\n\t\t\t\textension = gl.getExtension( 'WEBGL_compressed_texture_pvrtc' ) || gl.getExtension( 'WEBKIT_WEBGL_compressed_texture_pvrtc' );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\textension = gl.getExtension( name );\n\n\t\t}\n\n\t\textensions[ name ] = extension;\n\n\t\treturn extension;\n\n\t}\n\n\treturn {\n\n\t\thas: function ( name ) {\n\n\t\t\treturn getExtension( name ) !== null;\n\n\t\t},\n\n\t\tinit: function () {\n\n\t\t\tgetExtension( 'EXT_color_buffer_float' );\n\t\t\tgetExtension( 'WEBGL_clip_cull_distance' );\n\t\t\tgetExtension( 'OES_texture_float_linear' );\n\t\t\tgetExtension( 'EXT_color_buffer_half_float' );\n\t\t\tgetExtension( 'WEBGL_multisampled_render_to_texture' );\n\t\t\tgetExtension( 'WEBGL_render_shared_exponent' );\n\n\t\t},\n\n\t\tget: function ( name ) {\n\n\t\t\tconst extension = getExtension( name );\n\n\t\t\tif ( extension === null ) {\n\n\t\t\t\twarnOnce( 'THREE.WebGLRenderer: ' + name + ' extension not supported.' );\n\n\t\t\t}\n\n\t\t\treturn extension;\n\n\t\t}\n\n\t};\n\n}\n\nfunction WebGLGeometries( gl, attributes, info, bindingStates ) {\n\n\tconst geometries = {};\n\tconst wireframeAttributes = new WeakMap();\n\n\tfunction onGeometryDispose( event ) {\n\n\t\tconst geometry = event.target;\n\n\t\tif ( geometry.index !== null ) {\n\n\t\t\tattributes.remove( geometry.index );\n\n\t\t}\n\n\t\tfor ( const name in geometry.attributes ) {\n\n\t\t\tattributes.remove( geometry.attributes[ name ] );\n\n\t\t}\n\n\t\tfor ( const name in geometry.morphAttributes ) {\n\n\t\t\tconst array = geometry.morphAttributes[ name ];\n\n\t\t\tfor ( let i = 0, l = array.length; i < l; i ++ ) {\n\n\t\t\t\tattributes.remove( array[ i ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tgeometry.removeEventListener( 'dispose', onGeometryDispose );\n\n\t\tdelete geometries[ geometry.id ];\n\n\t\tconst attribute = wireframeAttributes.get( geometry );\n\n\t\tif ( attribute ) {\n\n\t\t\tattributes.remove( attribute );\n\t\t\twireframeAttributes.delete( geometry );\n\n\t\t}\n\n\t\tbindingStates.releaseStatesOfGeometry( geometry );\n\n\t\tif ( geometry.isInstancedBufferGeometry === true ) {\n\n\t\t\tdelete geometry._maxInstanceCount;\n\n\t\t}\n\n\t\t//\n\n\t\tinfo.memory.geometries --;\n\n\t}\n\n\tfunction get( object, geometry ) {\n\n\t\tif ( geometries[ geometry.id ] === true ) return geometry;\n\n\t\tgeometry.addEventListener( 'dispose', onGeometryDispose );\n\n\t\tgeometries[ geometry.id ] = true;\n\n\t\tinfo.memory.geometries ++;\n\n\t\treturn geometry;\n\n\t}\n\n\tfunction update( geometry ) {\n\n\t\tconst geometryAttributes = geometry.attributes;\n\n\t\t// Updating index buffer in VAO now. See WebGLBindingStates.\n\n\t\tfor ( const name in geometryAttributes ) {\n\n\t\t\tattributes.update( geometryAttributes[ name ], gl.ARRAY_BUFFER );\n\n\t\t}\n\n\t\t// morph targets\n\n\t\tconst morphAttributes = geometry.morphAttributes;\n\n\t\tfor ( const name in morphAttributes ) {\n\n\t\t\tconst array = morphAttributes[ name ];\n\n\t\t\tfor ( let i = 0, l = array.length; i < l; i ++ ) {\n\n\t\t\t\tattributes.update( array[ i ], gl.ARRAY_BUFFER );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction updateWireframeAttribute( geometry ) {\n\n\t\tconst indices = [];\n\n\t\tconst geometryIndex = geometry.index;\n\t\tconst geometryPosition = geometry.attributes.position;\n\t\tlet version = 0;\n\n\t\tif ( geometryIndex !== null ) {\n\n\t\t\tconst array = geometryIndex.array;\n\t\t\tversion = geometryIndex.version;\n\n\t\t\tfor ( let i = 0, l = array.length; i < l; i += 3 ) {\n\n\t\t\t\tconst a = array[ i + 0 ];\n\t\t\t\tconst b = array[ i + 1 ];\n\t\t\t\tconst c = array[ i + 2 ];\n\n\t\t\t\tindices.push( a, b, b, c, c, a );\n\n\t\t\t}\n\n\t\t} else if ( geometryPosition !== undefined ) {\n\n\t\t\tconst array = geometryPosition.array;\n\t\t\tversion = geometryPosition.version;\n\n\t\t\tfor ( let i = 0, l = ( array.length / 3 ) - 1; i < l; i += 3 ) {\n\n\t\t\t\tconst a = i + 0;\n\t\t\t\tconst b = i + 1;\n\t\t\t\tconst c = i + 2;\n\n\t\t\t\tindices.push( a, b, b, c, c, a );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst attribute = new ( arrayNeedsUint32( indices ) ? Uint32BufferAttribute : Uint16BufferAttribute )( indices, 1 );\n\t\tattribute.version = version;\n\n\t\t// Updating index buffer in VAO now. See WebGLBindingStates\n\n\t\t//\n\n\t\tconst previousAttribute = wireframeAttributes.get( geometry );\n\n\t\tif ( previousAttribute ) attributes.remove( previousAttribute );\n\n\t\t//\n\n\t\twireframeAttributes.set( geometry, attribute );\n\n\t}\n\n\tfunction getWireframeAttribute( geometry ) {\n\n\t\tconst currentAttribute = wireframeAttributes.get( geometry );\n\n\t\tif ( currentAttribute ) {\n\n\t\t\tconst geometryIndex = geometry.index;\n\n\t\t\tif ( geometryIndex !== null ) {\n\n\t\t\t\t// if the attribute is obsolete, create a new one\n\n\t\t\t\tif ( currentAttribute.version < geometryIndex.version ) {\n\n\t\t\t\t\tupdateWireframeAttribute( geometry );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tupdateWireframeAttribute( geometry );\n\n\t\t}\n\n\t\treturn wireframeAttributes.get( geometry );\n\n\t}\n\n\treturn {\n\n\t\tget: get,\n\t\tupdate: update,\n\n\t\tgetWireframeAttribute: getWireframeAttribute\n\n\t};\n\n}\n\nfunction WebGLIndexedBufferRenderer( gl, extensions, info ) {\n\n\tlet mode;\n\n\tfunction setMode( value ) {\n\n\t\tmode = value;\n\n\t}\n\n\tlet type, bytesPerElement;\n\n\tfunction setIndex( value ) {\n\n\t\ttype = value.type;\n\t\tbytesPerElement = value.bytesPerElement;\n\n\t}\n\n\tfunction render( start, count ) {\n\n\t\tgl.drawElements( mode, count, type, start * bytesPerElement );\n\n\t\tinfo.update( count, mode, 1 );\n\n\t}\n\n\tfunction renderInstances( start, count, primcount ) {\n\n\t\tif ( primcount === 0 ) return;\n\n\t\tgl.drawElementsInstanced( mode, count, type, start * bytesPerElement, primcount );\n\n\t\tinfo.update( count, mode, primcount );\n\n\t}\n\n\tfunction renderMultiDraw( starts, counts, drawCount ) {\n\n\t\tif ( drawCount === 0 ) return;\n\n\t\tconst extension = extensions.get( 'WEBGL_multi_draw' );\n\t\textension.multiDrawElementsWEBGL( mode, counts, 0, type, starts, 0, drawCount );\n\n\t\tlet elementCount = 0;\n\t\tfor ( let i = 0; i < drawCount; i ++ ) {\n\n\t\t\telementCount += counts[ i ];\n\n\t\t}\n\n\t\tinfo.update( elementCount, mode, 1 );\n\n\n\t}\n\n\tfunction renderMultiDrawInstances( starts, counts, drawCount, primcount ) {\n\n\t\tif ( drawCount === 0 ) return;\n\n\t\tconst extension = extensions.get( 'WEBGL_multi_draw' );\n\n\t\tif ( extension === null ) {\n\n\t\t\tfor ( let i = 0; i < starts.length; i ++ ) {\n\n\t\t\t\trenderInstances( starts[ i ] / bytesPerElement, counts[ i ], primcount[ i ] );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\textension.multiDrawElementsInstancedWEBGL( mode, counts, 0, type, starts, 0, primcount, 0, drawCount );\n\n\t\t\tlet elementCount = 0;\n\t\t\tfor ( let i = 0; i < drawCount; i ++ ) {\n\n\t\t\t\telementCount += counts[ i ];\n\n\t\t\t}\n\n\t\t\tfor ( let i = 0; i < primcount.length; i ++ ) {\n\n\t\t\t\tinfo.update( elementCount, mode, primcount[ i ] );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t//\n\n\tthis.setMode = setMode;\n\tthis.setIndex = setIndex;\n\tthis.render = render;\n\tthis.renderInstances = renderInstances;\n\tthis.renderMultiDraw = renderMultiDraw;\n\tthis.renderMultiDrawInstances = renderMultiDrawInstances;\n\n}\n\nfunction WebGLInfo( gl ) {\n\n\tconst memory = {\n\t\tgeometries: 0,\n\t\ttextures: 0\n\t};\n\n\tconst render = {\n\t\tframe: 0,\n\t\tcalls: 0,\n\t\ttriangles: 0,\n\t\tpoints: 0,\n\t\tlines: 0\n\t};\n\n\tfunction update( count, mode, instanceCount ) {\n\n\t\trender.calls ++;\n\n\t\tswitch ( mode ) {\n\n\t\t\tcase gl.TRIANGLES:\n\t\t\t\trender.triangles += instanceCount * ( count / 3 );\n\t\t\t\tbreak;\n\n\t\t\tcase gl.LINES:\n\t\t\t\trender.lines += instanceCount * ( count / 2 );\n\t\t\t\tbreak;\n\n\t\t\tcase gl.LINE_STRIP:\n\t\t\t\trender.lines += instanceCount * ( count - 1 );\n\t\t\t\tbreak;\n\n\t\t\tcase gl.LINE_LOOP:\n\t\t\t\trender.lines += instanceCount * count;\n\t\t\t\tbreak;\n\n\t\t\tcase gl.POINTS:\n\t\t\t\trender.points += instanceCount * count;\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tconsole.error( 'THREE.WebGLInfo: Unknown draw mode:', mode );\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\tfunction reset() {\n\n\t\trender.calls = 0;\n\t\trender.triangles = 0;\n\t\trender.points = 0;\n\t\trender.lines = 0;\n\n\t}\n\n\treturn {\n\t\tmemory: memory,\n\t\trender: render,\n\t\tprograms: null,\n\t\tautoReset: true,\n\t\treset: reset,\n\t\tupdate: update\n\t};\n\n}\n\nfunction WebGLMorphtargets( gl, capabilities, textures ) {\n\n\tconst morphTextures = new WeakMap();\n\tconst morph = new Vector4();\n\n\tfunction update( object, geometry, program ) {\n\n\t\tconst objectInfluences = object.morphTargetInfluences;\n\n\t\t// the following encodes morph targets into an array of data textures. Each layer represents a single morph target.\n\n\t\tconst morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;\n\t\tconst morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;\n\n\t\tlet entry = morphTextures.get( geometry );\n\n\t\tif ( entry === undefined || entry.count !== morphTargetsCount ) {\n\n\t\t\tif ( entry !== undefined ) entry.texture.dispose();\n\n\t\t\tconst hasMorphPosition = geometry.morphAttributes.position !== undefined;\n\t\t\tconst hasMorphNormals = geometry.morphAttributes.normal !== undefined;\n\t\t\tconst hasMorphColors = geometry.morphAttributes.color !== undefined;\n\n\t\t\tconst morphTargets = geometry.morphAttributes.position || [];\n\t\t\tconst morphNormals = geometry.morphAttributes.normal || [];\n\t\t\tconst morphColors = geometry.morphAttributes.color || [];\n\n\t\t\tlet vertexDataCount = 0;\n\n\t\t\tif ( hasMorphPosition === true ) vertexDataCount = 1;\n\t\t\tif ( hasMorphNormals === true ) vertexDataCount = 2;\n\t\t\tif ( hasMorphColors === true ) vertexDataCount = 3;\n\n\t\t\tlet width = geometry.attributes.position.count * vertexDataCount;\n\t\t\tlet height = 1;\n\n\t\t\tif ( width > capabilities.maxTextureSize ) {\n\n\t\t\t\theight = Math.ceil( width / capabilities.maxTextureSize );\n\t\t\t\twidth = capabilities.maxTextureSize;\n\n\t\t\t}\n\n\t\t\tconst buffer = new Float32Array( width * height * 4 * morphTargetsCount );\n\n\t\t\tconst texture = new DataArrayTexture( buffer, width, height, morphTargetsCount );\n\t\t\ttexture.type = FloatType;\n\t\t\ttexture.needsUpdate = true;\n\n\t\t\t// fill buffer\n\n\t\t\tconst vertexDataStride = vertexDataCount * 4;\n\n\t\t\tfor ( let i = 0; i < morphTargetsCount; i ++ ) {\n\n\t\t\t\tconst morphTarget = morphTargets[ i ];\n\t\t\t\tconst morphNormal = morphNormals[ i ];\n\t\t\t\tconst morphColor = morphColors[ i ];\n\n\t\t\t\tconst offset = width * height * 4 * i;\n\n\t\t\t\tfor ( let j = 0; j < morphTarget.count; j ++ ) {\n\n\t\t\t\t\tconst stride = j * vertexDataStride;\n\n\t\t\t\t\tif ( hasMorphPosition === true ) {\n\n\t\t\t\t\t\tmorph.fromBufferAttribute( morphTarget, j );\n\n\t\t\t\t\t\tbuffer[ offset + stride + 0 ] = morph.x;\n\t\t\t\t\t\tbuffer[ offset + stride + 1 ] = morph.y;\n\t\t\t\t\t\tbuffer[ offset + stride + 2 ] = morph.z;\n\t\t\t\t\t\tbuffer[ offset + stride + 3 ] = 0;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( hasMorphNormals === true ) {\n\n\t\t\t\t\t\tmorph.fromBufferAttribute( morphNormal, j );\n\n\t\t\t\t\t\tbuffer[ offset + stride + 4 ] = morph.x;\n\t\t\t\t\t\tbuffer[ offset + stride + 5 ] = morph.y;\n\t\t\t\t\t\tbuffer[ offset + stride + 6 ] = morph.z;\n\t\t\t\t\t\tbuffer[ offset + stride + 7 ] = 0;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( hasMorphColors === true ) {\n\n\t\t\t\t\t\tmorph.fromBufferAttribute( morphColor, j );\n\n\t\t\t\t\t\tbuffer[ offset + stride + 8 ] = morph.x;\n\t\t\t\t\t\tbuffer[ offset + stride + 9 ] = morph.y;\n\t\t\t\t\t\tbuffer[ offset + stride + 10 ] = morph.z;\n\t\t\t\t\t\tbuffer[ offset + stride + 11 ] = ( morphColor.itemSize === 4 ) ? morph.w : 1;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tentry = {\n\t\t\t\tcount: morphTargetsCount,\n\t\t\t\ttexture: texture,\n\t\t\t\tsize: new Vector2( width, height )\n\t\t\t};\n\n\t\t\tmorphTextures.set( geometry, entry );\n\n\t\t\tfunction disposeTexture() {\n\n\t\t\t\ttexture.dispose();\n\n\t\t\t\tmorphTextures.delete( geometry );\n\n\t\t\t\tgeometry.removeEventListener( 'dispose', disposeTexture );\n\n\t\t\t}\n\n\t\t\tgeometry.addEventListener( 'dispose', disposeTexture );\n\n\t\t}\n\n\t\t//\n\t\tif ( object.isInstancedMesh === true && object.morphTexture !== null ) {\n\n\t\t\tprogram.getUniforms().setValue( gl, 'morphTexture', object.morphTexture, textures );\n\n\t\t} else {\n\n\t\t\tlet morphInfluencesSum = 0;\n\n\t\t\tfor ( let i = 0; i < objectInfluences.length; i ++ ) {\n\n\t\t\t\tmorphInfluencesSum += objectInfluences[ i ];\n\n\t\t\t}\n\n\t\t\tconst morphBaseInfluence = geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;\n\n\n\t\t\tprogram.getUniforms().setValue( gl, 'morphTargetBaseInfluence', morphBaseInfluence );\n\t\t\tprogram.getUniforms().setValue( gl, 'morphTargetInfluences', objectInfluences );\n\n\t\t}\n\n\t\tprogram.getUniforms().setValue( gl, 'morphTargetsTexture', entry.texture, textures );\n\t\tprogram.getUniforms().setValue( gl, 'morphTargetsTextureSize', entry.size );\n\n\t}\n\n\treturn {\n\n\t\tupdate: update\n\n\t};\n\n}\n\nfunction WebGLObjects( gl, geometries, attributes, info ) {\n\n\tlet updateMap = new WeakMap();\n\n\tfunction update( object ) {\n\n\t\tconst frame = info.render.frame;\n\n\t\tconst geometry = object.geometry;\n\t\tconst buffergeometry = geometries.get( object, geometry );\n\n\t\t// Update once per frame\n\n\t\tif ( updateMap.get( buffergeometry ) !== frame ) {\n\n\t\t\tgeometries.update( buffergeometry );\n\n\t\t\tupdateMap.set( buffergeometry, frame );\n\n\t\t}\n\n\t\tif ( object.isInstancedMesh ) {\n\n\t\t\tif ( object.hasEventListener( 'dispose', onInstancedMeshDispose ) === false ) {\n\n\t\t\t\tobject.addEventListener( 'dispose', onInstancedMeshDispose );\n\n\t\t\t}\n\n\t\t\tif ( updateMap.get( object ) !== frame ) {\n\n\t\t\t\tattributes.update( object.instanceMatrix, gl.ARRAY_BUFFER );\n\n\t\t\t\tif ( object.instanceColor !== null ) {\n\n\t\t\t\t\tattributes.update( object.instanceColor, gl.ARRAY_BUFFER );\n\n\t\t\t\t}\n\n\t\t\t\tupdateMap.set( object, frame );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( object.isSkinnedMesh ) {\n\n\t\t\tconst skeleton = object.skeleton;\n\n\t\t\tif ( updateMap.get( skeleton ) !== frame ) {\n\n\t\t\t\tskeleton.update();\n\n\t\t\t\tupdateMap.set( skeleton, frame );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn buffergeometry;\n\n\t}\n\n\tfunction dispose() {\n\n\t\tupdateMap = new WeakMap();\n\n\t}\n\n\tfunction onInstancedMeshDispose( event ) {\n\n\t\tconst instancedMesh = event.target;\n\n\t\tinstancedMesh.removeEventListener( 'dispose', onInstancedMeshDispose );\n\n\t\tattributes.remove( instancedMesh.instanceMatrix );\n\n\t\tif ( instancedMesh.instanceColor !== null ) attributes.remove( instancedMesh.instanceColor );\n\n\t}\n\n\treturn {\n\n\t\tupdate: update,\n\t\tdispose: dispose\n\n\t};\n\n}\n\nclass DepthTexture extends Texture {\n\n\tconstructor( width, height, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, format = DepthFormat ) {\n\n\t\tif ( format !== DepthFormat && format !== DepthStencilFormat ) {\n\n\t\t\tthrow new Error( 'DepthTexture format must be either THREE.DepthFormat or THREE.DepthStencilFormat' );\n\n\t\t}\n\n\t\tif ( type === undefined && format === DepthFormat ) type = UnsignedIntType;\n\t\tif ( type === undefined && format === DepthStencilFormat ) type = UnsignedInt248Type;\n\n\t\tsuper( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\t\tthis.isDepthTexture = true;\n\n\t\tthis.image = { width: width, height: height };\n\n\t\tthis.magFilter = magFilter !== undefined ? magFilter : NearestFilter;\n\t\tthis.minFilter = minFilter !== undefined ? minFilter : NearestFilter;\n\n\t\tthis.flipY = false;\n\t\tthis.generateMipmaps = false;\n\n\t\tthis.compareFunction = null;\n\n\t}\n\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.compareFunction = source.compareFunction;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tif ( this.compareFunction !== null ) data.compareFunction = this.compareFunction;\n\n\t\treturn data;\n\n\t}\n\n}\n\n/**\n * Uniforms of a program.\n * Those form a tree structure with a special top-level container for the root,\n * which you get by calling 'new WebGLUniforms( gl, program )'.\n *\n *\n * Properties of inner nodes including the top-level container:\n *\n * .seq - array of nested uniforms\n * .map - nested uniforms by name\n *\n *\n * Methods of all nodes except the top-level container:\n *\n * .setValue( gl, value, [textures] )\n *\n * \t\tuploads a uniform value(s)\n * \tthe 'textures' parameter is needed for sampler uniforms\n *\n *\n * Static methods of the top-level container (textures factorizations):\n *\n * .upload( gl, seq, values, textures )\n *\n * \t\tsets uniforms in 'seq' to 'values[id].value'\n *\n * .seqWithValue( seq, values ) : filteredSeq\n *\n * \t\tfilters 'seq' entries with corresponding entry in values\n *\n *\n * Methods of the top-level container (textures factorizations):\n *\n * .setValue( gl, name, value, textures )\n *\n * \t\tsets uniform with name 'name' to 'value'\n *\n * .setOptional( gl, obj, prop )\n *\n * \t\tlike .set for an optional property of the object\n *\n */\n\n\nconst emptyTexture = /*@__PURE__*/ new Texture();\n\nconst emptyShadowTexture = /*@__PURE__*/ new DepthTexture( 1, 1 );\n\nconst emptyArrayTexture = /*@__PURE__*/ new DataArrayTexture();\nconst empty3dTexture = /*@__PURE__*/ new Data3DTexture();\nconst emptyCubeTexture = /*@__PURE__*/ new CubeTexture();\n\n// --- Utilities ---\n\n// Array Caches (provide typed arrays for temporary by size)\n\nconst arrayCacheF32 = [];\nconst arrayCacheI32 = [];\n\n// Float32Array caches used for uploading Matrix uniforms\n\nconst mat4array = new Float32Array( 16 );\nconst mat3array = new Float32Array( 9 );\nconst mat2array = new Float32Array( 4 );\n\n// Flattening for arrays of vectors and matrices\n\nfunction flatten( array, nBlocks, blockSize ) {\n\n\tconst firstElem = array[ 0 ];\n\n\tif ( firstElem <= 0 || firstElem > 0 ) return array;\n\t// unoptimized: ! isNaN( firstElem )\n\t// see http://jacksondunstan.com/articles/983\n\n\tconst n = nBlocks * blockSize;\n\tlet r = arrayCacheF32[ n ];\n\n\tif ( r === undefined ) {\n\n\t\tr = new Float32Array( n );\n\t\tarrayCacheF32[ n ] = r;\n\n\t}\n\n\tif ( nBlocks !== 0 ) {\n\n\t\tfirstElem.toArray( r, 0 );\n\n\t\tfor ( let i = 1, offset = 0; i !== nBlocks; ++ i ) {\n\n\t\t\toffset += blockSize;\n\t\t\tarray[ i ].toArray( r, offset );\n\n\t\t}\n\n\t}\n\n\treturn r;\n\n}\n\nfunction arraysEqual( a, b ) {\n\n\tif ( a.length !== b.length ) return false;\n\n\tfor ( let i = 0, l = a.length; i < l; i ++ ) {\n\n\t\tif ( a[ i ] !== b[ i ] ) return false;\n\n\t}\n\n\treturn true;\n\n}\n\nfunction copyArray( a, b ) {\n\n\tfor ( let i = 0, l = b.length; i < l; i ++ ) {\n\n\t\ta[ i ] = b[ i ];\n\n\t}\n\n}\n\n// Texture unit allocation\n\nfunction allocTexUnits( textures, n ) {\n\n\tlet r = arrayCacheI32[ n ];\n\n\tif ( r === undefined ) {\n\n\t\tr = new Int32Array( n );\n\t\tarrayCacheI32[ n ] = r;\n\n\t}\n\n\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\tr[ i ] = textures.allocateTextureUnit();\n\n\t}\n\n\treturn r;\n\n}\n\n// --- Setters ---\n\n// Note: Defining these methods externally, because they come in a bunch\n// and this way their names minify.\n\n// Single scalar\n\nfunction setValueV1f( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( cache[ 0 ] === v ) return;\n\n\tgl.uniform1f( this.addr, v );\n\n\tcache[ 0 ] = v;\n\n}\n\n// Single float vector (from flat array or THREE.VectorN)\n\nfunction setValueV2f( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {\n\n\t\t\tgl.uniform2f( this.addr, v.x, v.y );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform2fv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV3f( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {\n\n\t\t\tgl.uniform3f( this.addr, v.x, v.y, v.z );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\n\t\t}\n\n\t} else if ( v.r !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.r || cache[ 1 ] !== v.g || cache[ 2 ] !== v.b ) {\n\n\t\t\tgl.uniform3f( this.addr, v.r, v.g, v.b );\n\n\t\t\tcache[ 0 ] = v.r;\n\t\t\tcache[ 1 ] = v.g;\n\t\t\tcache[ 2 ] = v.b;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform3fv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV4f( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {\n\n\t\t\tgl.uniform4f( this.addr, v.x, v.y, v.z, v.w );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\t\t\tcache[ 3 ] = v.w;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform4fv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\n// Single matrix (from flat array or THREE.MatrixN)\n\nfunction setValueM2( gl, v ) {\n\n\tconst cache = this.cache;\n\tconst elements = v.elements;\n\n\tif ( elements === undefined ) {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniformMatrix2fv( this.addr, false, v );\n\n\t\tcopyArray( cache, v );\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, elements ) ) return;\n\n\t\tmat2array.set( elements );\n\n\t\tgl.uniformMatrix2fv( this.addr, false, mat2array );\n\n\t\tcopyArray( cache, elements );\n\n\t}\n\n}\n\nfunction setValueM3( gl, v ) {\n\n\tconst cache = this.cache;\n\tconst elements = v.elements;\n\n\tif ( elements === undefined ) {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniformMatrix3fv( this.addr, false, v );\n\n\t\tcopyArray( cache, v );\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, elements ) ) return;\n\n\t\tmat3array.set( elements );\n\n\t\tgl.uniformMatrix3fv( this.addr, false, mat3array );\n\n\t\tcopyArray( cache, elements );\n\n\t}\n\n}\n\nfunction setValueM4( gl, v ) {\n\n\tconst cache = this.cache;\n\tconst elements = v.elements;\n\n\tif ( elements === undefined ) {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniformMatrix4fv( this.addr, false, v );\n\n\t\tcopyArray( cache, v );\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, elements ) ) return;\n\n\t\tmat4array.set( elements );\n\n\t\tgl.uniformMatrix4fv( this.addr, false, mat4array );\n\n\t\tcopyArray( cache, elements );\n\n\t}\n\n}\n\n// Single integer / boolean\n\nfunction setValueV1i( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( cache[ 0 ] === v ) return;\n\n\tgl.uniform1i( this.addr, v );\n\n\tcache[ 0 ] = v;\n\n}\n\n// Single integer / boolean vector (from flat array or THREE.VectorN)\n\nfunction setValueV2i( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {\n\n\t\t\tgl.uniform2i( this.addr, v.x, v.y );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform2iv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV3i( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {\n\n\t\t\tgl.uniform3i( this.addr, v.x, v.y, v.z );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform3iv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV4i( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {\n\n\t\t\tgl.uniform4i( this.addr, v.x, v.y, v.z, v.w );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\t\t\tcache[ 3 ] = v.w;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform4iv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\n// Single unsigned integer\n\nfunction setValueV1ui( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( cache[ 0 ] === v ) return;\n\n\tgl.uniform1ui( this.addr, v );\n\n\tcache[ 0 ] = v;\n\n}\n\n// Single unsigned integer vector (from flat array or THREE.VectorN)\n\nfunction setValueV2ui( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y ) {\n\n\t\t\tgl.uniform2ui( this.addr, v.x, v.y );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform2uiv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV3ui( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z ) {\n\n\t\t\tgl.uniform3ui( this.addr, v.x, v.y, v.z );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform3uiv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\nfunction setValueV4ui( gl, v ) {\n\n\tconst cache = this.cache;\n\n\tif ( v.x !== undefined ) {\n\n\t\tif ( cache[ 0 ] !== v.x || cache[ 1 ] !== v.y || cache[ 2 ] !== v.z || cache[ 3 ] !== v.w ) {\n\n\t\t\tgl.uniform4ui( this.addr, v.x, v.y, v.z, v.w );\n\n\t\t\tcache[ 0 ] = v.x;\n\t\t\tcache[ 1 ] = v.y;\n\t\t\tcache[ 2 ] = v.z;\n\t\t\tcache[ 3 ] = v.w;\n\n\t\t}\n\n\t} else {\n\n\t\tif ( arraysEqual( cache, v ) ) return;\n\n\t\tgl.uniform4uiv( this.addr, v );\n\n\t\tcopyArray( cache, v );\n\n\t}\n\n}\n\n\n// Single texture (2D / Cube)\n\nfunction setValueT1( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\tconst unit = textures.allocateTextureUnit();\n\n\tif ( cache[ 0 ] !== unit ) {\n\n\t\tgl.uniform1i( this.addr, unit );\n\t\tcache[ 0 ] = unit;\n\n\t}\n\n\tlet emptyTexture2D;\n\n\tif ( this.type === gl.SAMPLER_2D_SHADOW ) {\n\n\t\temptyShadowTexture.compareFunction = LessEqualCompare; // #28670\n\t\temptyTexture2D = emptyShadowTexture;\n\n\t} else {\n\n\t\temptyTexture2D = emptyTexture;\n\n\t}\n\n\ttextures.setTexture2D( v || emptyTexture2D, unit );\n\n}\n\nfunction setValueT3D1( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\tconst unit = textures.allocateTextureUnit();\n\n\tif ( cache[ 0 ] !== unit ) {\n\n\t\tgl.uniform1i( this.addr, unit );\n\t\tcache[ 0 ] = unit;\n\n\t}\n\n\ttextures.setTexture3D( v || empty3dTexture, unit );\n\n}\n\nfunction setValueT6( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\tconst unit = textures.allocateTextureUnit();\n\n\tif ( cache[ 0 ] !== unit ) {\n\n\t\tgl.uniform1i( this.addr, unit );\n\t\tcache[ 0 ] = unit;\n\n\t}\n\n\ttextures.setTextureCube( v || emptyCubeTexture, unit );\n\n}\n\nfunction setValueT2DArray1( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\tconst unit = textures.allocateTextureUnit();\n\n\tif ( cache[ 0 ] !== unit ) {\n\n\t\tgl.uniform1i( this.addr, unit );\n\t\tcache[ 0 ] = unit;\n\n\t}\n\n\ttextures.setTexture2DArray( v || emptyArrayTexture, unit );\n\n}\n\n// Helper to pick the right setter for the singular case\n\nfunction getSingularSetter( type ) {\n\n\tswitch ( type ) {\n\n\t\tcase 0x1406: return setValueV1f; // FLOAT\n\t\tcase 0x8b50: return setValueV2f; // _VEC2\n\t\tcase 0x8b51: return setValueV3f; // _VEC3\n\t\tcase 0x8b52: return setValueV4f; // _VEC4\n\n\t\tcase 0x8b5a: return setValueM2; // _MAT2\n\t\tcase 0x8b5b: return setValueM3; // _MAT3\n\t\tcase 0x8b5c: return setValueM4; // _MAT4\n\n\t\tcase 0x1404: case 0x8b56: return setValueV1i; // INT, BOOL\n\t\tcase 0x8b53: case 0x8b57: return setValueV2i; // _VEC2\n\t\tcase 0x8b54: case 0x8b58: return setValueV3i; // _VEC3\n\t\tcase 0x8b55: case 0x8b59: return setValueV4i; // _VEC4\n\n\t\tcase 0x1405: return setValueV1ui; // UINT\n\t\tcase 0x8dc6: return setValueV2ui; // _VEC2\n\t\tcase 0x8dc7: return setValueV3ui; // _VEC3\n\t\tcase 0x8dc8: return setValueV4ui; // _VEC4\n\n\t\tcase 0x8b5e: // SAMPLER_2D\n\t\tcase 0x8d66: // SAMPLER_EXTERNAL_OES\n\t\tcase 0x8dca: // INT_SAMPLER_2D\n\t\tcase 0x8dd2: // UNSIGNED_INT_SAMPLER_2D\n\t\tcase 0x8b62: // SAMPLER_2D_SHADOW\n\t\t\treturn setValueT1;\n\n\t\tcase 0x8b5f: // SAMPLER_3D\n\t\tcase 0x8dcb: // INT_SAMPLER_3D\n\t\tcase 0x8dd3: // UNSIGNED_INT_SAMPLER_3D\n\t\t\treturn setValueT3D1;\n\n\t\tcase 0x8b60: // SAMPLER_CUBE\n\t\tcase 0x8dcc: // INT_SAMPLER_CUBE\n\t\tcase 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE\n\t\tcase 0x8dc5: // SAMPLER_CUBE_SHADOW\n\t\t\treturn setValueT6;\n\n\t\tcase 0x8dc1: // SAMPLER_2D_ARRAY\n\t\tcase 0x8dcf: // INT_SAMPLER_2D_ARRAY\n\t\tcase 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY\n\t\tcase 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW\n\t\t\treturn setValueT2DArray1;\n\n\t}\n\n}\n\n\n// Array of scalars\n\nfunction setValueV1fArray( gl, v ) {\n\n\tgl.uniform1fv( this.addr, v );\n\n}\n\n// Array of vectors (from flat array or array of THREE.VectorN)\n\nfunction setValueV2fArray( gl, v ) {\n\n\tconst data = flatten( v, this.size, 2 );\n\n\tgl.uniform2fv( this.addr, data );\n\n}\n\nfunction setValueV3fArray( gl, v ) {\n\n\tconst data = flatten( v, this.size, 3 );\n\n\tgl.uniform3fv( this.addr, data );\n\n}\n\nfunction setValueV4fArray( gl, v ) {\n\n\tconst data = flatten( v, this.size, 4 );\n\n\tgl.uniform4fv( this.addr, data );\n\n}\n\n// Array of matrices (from flat array or array of THREE.MatrixN)\n\nfunction setValueM2Array( gl, v ) {\n\n\tconst data = flatten( v, this.size, 4 );\n\n\tgl.uniformMatrix2fv( this.addr, false, data );\n\n}\n\nfunction setValueM3Array( gl, v ) {\n\n\tconst data = flatten( v, this.size, 9 );\n\n\tgl.uniformMatrix3fv( this.addr, false, data );\n\n}\n\nfunction setValueM4Array( gl, v ) {\n\n\tconst data = flatten( v, this.size, 16 );\n\n\tgl.uniformMatrix4fv( this.addr, false, data );\n\n}\n\n// Array of integer / boolean\n\nfunction setValueV1iArray( gl, v ) {\n\n\tgl.uniform1iv( this.addr, v );\n\n}\n\n// Array of integer / boolean vectors (from flat array)\n\nfunction setValueV2iArray( gl, v ) {\n\n\tgl.uniform2iv( this.addr, v );\n\n}\n\nfunction setValueV3iArray( gl, v ) {\n\n\tgl.uniform3iv( this.addr, v );\n\n}\n\nfunction setValueV4iArray( gl, v ) {\n\n\tgl.uniform4iv( this.addr, v );\n\n}\n\n// Array of unsigned integer\n\nfunction setValueV1uiArray( gl, v ) {\n\n\tgl.uniform1uiv( this.addr, v );\n\n}\n\n// Array of unsigned integer vectors (from flat array)\n\nfunction setValueV2uiArray( gl, v ) {\n\n\tgl.uniform2uiv( this.addr, v );\n\n}\n\nfunction setValueV3uiArray( gl, v ) {\n\n\tgl.uniform3uiv( this.addr, v );\n\n}\n\nfunction setValueV4uiArray( gl, v ) {\n\n\tgl.uniform4uiv( this.addr, v );\n\n}\n\n\n// Array of textures (2D / 3D / Cube / 2DArray)\n\nfunction setValueT1Array( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\n\tconst n = v.length;\n\n\tconst units = allocTexUnits( textures, n );\n\n\tif ( ! arraysEqual( cache, units ) ) {\n\n\t\tgl.uniform1iv( this.addr, units );\n\n\t\tcopyArray( cache, units );\n\n\t}\n\n\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\ttextures.setTexture2D( v[ i ] || emptyTexture, units[ i ] );\n\n\t}\n\n}\n\nfunction setValueT3DArray( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\n\tconst n = v.length;\n\n\tconst units = allocTexUnits( textures, n );\n\n\tif ( ! arraysEqual( cache, units ) ) {\n\n\t\tgl.uniform1iv( this.addr, units );\n\n\t\tcopyArray( cache, units );\n\n\t}\n\n\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\ttextures.setTexture3D( v[ i ] || empty3dTexture, units[ i ] );\n\n\t}\n\n}\n\nfunction setValueT6Array( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\n\tconst n = v.length;\n\n\tconst units = allocTexUnits( textures, n );\n\n\tif ( ! arraysEqual( cache, units ) ) {\n\n\t\tgl.uniform1iv( this.addr, units );\n\n\t\tcopyArray( cache, units );\n\n\t}\n\n\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\ttextures.setTextureCube( v[ i ] || emptyCubeTexture, units[ i ] );\n\n\t}\n\n}\n\nfunction setValueT2DArrayArray( gl, v, textures ) {\n\n\tconst cache = this.cache;\n\n\tconst n = v.length;\n\n\tconst units = allocTexUnits( textures, n );\n\n\tif ( ! arraysEqual( cache, units ) ) {\n\n\t\tgl.uniform1iv( this.addr, units );\n\n\t\tcopyArray( cache, units );\n\n\t}\n\n\tfor ( let i = 0; i !== n; ++ i ) {\n\n\t\ttextures.setTexture2DArray( v[ i ] || emptyArrayTexture, units[ i ] );\n\n\t}\n\n}\n\n\n// Helper to pick the right setter for a pure (bottom-level) array\n\nfunction getPureArraySetter( type ) {\n\n\tswitch ( type ) {\n\n\t\tcase 0x1406: return setValueV1fArray; // FLOAT\n\t\tcase 0x8b50: return setValueV2fArray; // _VEC2\n\t\tcase 0x8b51: return setValueV3fArray; // _VEC3\n\t\tcase 0x8b52: return setValueV4fArray; // _VEC4\n\n\t\tcase 0x8b5a: return setValueM2Array; // _MAT2\n\t\tcase 0x8b5b: return setValueM3Array; // _MAT3\n\t\tcase 0x8b5c: return setValueM4Array; // _MAT4\n\n\t\tcase 0x1404: case 0x8b56: return setValueV1iArray; // INT, BOOL\n\t\tcase 0x8b53: case 0x8b57: return setValueV2iArray; // _VEC2\n\t\tcase 0x8b54: case 0x8b58: return setValueV3iArray; // _VEC3\n\t\tcase 0x8b55: case 0x8b59: return setValueV4iArray; // _VEC4\n\n\t\tcase 0x1405: return setValueV1uiArray; // UINT\n\t\tcase 0x8dc6: return setValueV2uiArray; // _VEC2\n\t\tcase 0x8dc7: return setValueV3uiArray; // _VEC3\n\t\tcase 0x8dc8: return setValueV4uiArray; // _VEC4\n\n\t\tcase 0x8b5e: // SAMPLER_2D\n\t\tcase 0x8d66: // SAMPLER_EXTERNAL_OES\n\t\tcase 0x8dca: // INT_SAMPLER_2D\n\t\tcase 0x8dd2: // UNSIGNED_INT_SAMPLER_2D\n\t\tcase 0x8b62: // SAMPLER_2D_SHADOW\n\t\t\treturn setValueT1Array;\n\n\t\tcase 0x8b5f: // SAMPLER_3D\n\t\tcase 0x8dcb: // INT_SAMPLER_3D\n\t\tcase 0x8dd3: // UNSIGNED_INT_SAMPLER_3D\n\t\t\treturn setValueT3DArray;\n\n\t\tcase 0x8b60: // SAMPLER_CUBE\n\t\tcase 0x8dcc: // INT_SAMPLER_CUBE\n\t\tcase 0x8dd4: // UNSIGNED_INT_SAMPLER_CUBE\n\t\tcase 0x8dc5: // SAMPLER_CUBE_SHADOW\n\t\t\treturn setValueT6Array;\n\n\t\tcase 0x8dc1: // SAMPLER_2D_ARRAY\n\t\tcase 0x8dcf: // INT_SAMPLER_2D_ARRAY\n\t\tcase 0x8dd7: // UNSIGNED_INT_SAMPLER_2D_ARRAY\n\t\tcase 0x8dc4: // SAMPLER_2D_ARRAY_SHADOW\n\t\t\treturn setValueT2DArrayArray;\n\n\t}\n\n}\n\n// --- Uniform Classes ---\n\nclass SingleUniform {\n\n\tconstructor( id, activeInfo, addr ) {\n\n\t\tthis.id = id;\n\t\tthis.addr = addr;\n\t\tthis.cache = [];\n\t\tthis.type = activeInfo.type;\n\t\tthis.setValue = getSingularSetter( activeInfo.type );\n\n\t\t// this.path = activeInfo.name; // DEBUG\n\n\t}\n\n}\n\nclass PureArrayUniform {\n\n\tconstructor( id, activeInfo, addr ) {\n\n\t\tthis.id = id;\n\t\tthis.addr = addr;\n\t\tthis.cache = [];\n\t\tthis.type = activeInfo.type;\n\t\tthis.size = activeInfo.size;\n\t\tthis.setValue = getPureArraySetter( activeInfo.type );\n\n\t\t// this.path = activeInfo.name; // DEBUG\n\n\t}\n\n}\n\nclass StructuredUniform {\n\n\tconstructor( id ) {\n\n\t\tthis.id = id;\n\n\t\tthis.seq = [];\n\t\tthis.map = {};\n\n\t}\n\n\tsetValue( gl, value, textures ) {\n\n\t\tconst seq = this.seq;\n\n\t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\t\tconst u = seq[ i ];\n\t\t\tu.setValue( gl, value[ u.id ], textures );\n\n\t\t}\n\n\t}\n\n}\n\n// --- Top-level ---\n\n// Parser - builds up the property tree from the path strings\n\nconst RePathPart = /(\\w+)(\\])?(\\[|\\.)?/g;\n\n// extracts\n// \t- the identifier (member name or array index)\n// - followed by an optional right bracket (found when array index)\n// - followed by an optional left bracket or dot (type of subscript)\n//\n// Note: These portions can be read in a non-overlapping fashion and\n// allow straightforward parsing of the hierarchy that WebGL encodes\n// in the uniform names.\n\nfunction addUniform( container, uniformObject ) {\n\n\tcontainer.seq.push( uniformObject );\n\tcontainer.map[ uniformObject.id ] = uniformObject;\n\n}\n\nfunction parseUniform( activeInfo, addr, container ) {\n\n\tconst path = activeInfo.name,\n\t\tpathLength = path.length;\n\n\t// reset RegExp object, because of the early exit of a previous run\n\tRePathPart.lastIndex = 0;\n\n\twhile ( true ) {\n\n\t\tconst match = RePathPart.exec( path ),\n\t\t\tmatchEnd = RePathPart.lastIndex;\n\n\t\tlet id = match[ 1 ];\n\t\tconst idIsIndex = match[ 2 ] === ']',\n\t\t\tsubscript = match[ 3 ];\n\n\t\tif ( idIsIndex ) id = id | 0; // convert to integer\n\n\t\tif ( subscript === undefined || subscript === '[' && matchEnd + 2 === pathLength ) {\n\n\t\t\t// bare name or \"pure\" bottom-level array \"[0]\" suffix\n\n\t\t\taddUniform( container, subscript === undefined ?\n\t\t\t\tnew SingleUniform( id, activeInfo, addr ) :\n\t\t\t\tnew PureArrayUniform( id, activeInfo, addr ) );\n\n\t\t\tbreak;\n\n\t\t} else {\n\n\t\t\t// step into inner node / create it in case it doesn't exist\n\n\t\t\tconst map = container.map;\n\t\t\tlet next = map[ id ];\n\n\t\t\tif ( next === undefined ) {\n\n\t\t\t\tnext = new StructuredUniform( id );\n\t\t\t\taddUniform( container, next );\n\n\t\t\t}\n\n\t\t\tcontainer = next;\n\n\t\t}\n\n\t}\n\n}\n\n// Root Container\n\nclass WebGLUniforms {\n\n\tconstructor( gl, program ) {\n\n\t\tthis.seq = [];\n\t\tthis.map = {};\n\n\t\tconst n = gl.getProgramParameter( program, gl.ACTIVE_UNIFORMS );\n\n\t\tfor ( let i = 0; i < n; ++ i ) {\n\n\t\t\tconst info = gl.getActiveUniform( program, i ),\n\t\t\t\taddr = gl.getUniformLocation( program, info.name );\n\n\t\t\tparseUniform( info, addr, this );\n\n\t\t}\n\n\t}\n\n\tsetValue( gl, name, value, textures ) {\n\n\t\tconst u = this.map[ name ];\n\n\t\tif ( u !== undefined ) u.setValue( gl, value, textures );\n\n\t}\n\n\tsetOptional( gl, object, name ) {\n\n\t\tconst v = object[ name ];\n\n\t\tif ( v !== undefined ) this.setValue( gl, name, v );\n\n\t}\n\n\tstatic upload( gl, seq, values, textures ) {\n\n\t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\t\tconst u = seq[ i ],\n\t\t\t\tv = values[ u.id ];\n\n\t\t\tif ( v.needsUpdate !== false ) {\n\n\t\t\t\t// note: always updating when .needsUpdate is undefined\n\t\t\t\tu.setValue( gl, v.value, textures );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tstatic seqWithValue( seq, values ) {\n\n\t\tconst r = [];\n\n\t\tfor ( let i = 0, n = seq.length; i !== n; ++ i ) {\n\n\t\t\tconst u = seq[ i ];\n\t\t\tif ( u.id in values ) r.push( u );\n\n\t\t}\n\n\t\treturn r;\n\n\t}\n\n}\n\nfunction WebGLShader( gl, type, string ) {\n\n\tconst shader = gl.createShader( type );\n\n\tgl.shaderSource( shader, string );\n\tgl.compileShader( shader );\n\n\treturn shader;\n\n}\n\n// From https://www.khronos.org/registry/webgl/extensions/KHR_parallel_shader_compile/\nconst COMPLETION_STATUS_KHR = 0x91B1;\n\nlet programIdCount = 0;\n\nfunction handleSource( string, errorLine ) {\n\n\tconst lines = string.split( '\\n' );\n\tconst lines2 = [];\n\n\tconst from = Math.max( errorLine - 6, 0 );\n\tconst to = Math.min( errorLine + 6, lines.length );\n\n\tfor ( let i = from; i < to; i ++ ) {\n\n\t\tconst line = i + 1;\n\t\tlines2.push( `${line === errorLine ? '>' : ' '} ${line}: ${lines[ i ]}` );\n\n\t}\n\n\treturn lines2.join( '\\n' );\n\n}\n\nfunction getEncodingComponents( colorSpace ) {\n\n\tconst workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );\n\tconst encodingPrimaries = ColorManagement.getPrimaries( colorSpace );\n\n\tlet gamutMapping;\n\n\tif ( workingPrimaries === encodingPrimaries ) {\n\n\t\tgamutMapping = '';\n\n\t} else if ( workingPrimaries === P3Primaries && encodingPrimaries === Rec709Primaries ) {\n\n\t\tgamutMapping = 'LinearDisplayP3ToLinearSRGB';\n\n\t} else if ( workingPrimaries === Rec709Primaries && encodingPrimaries === P3Primaries ) {\n\n\t\tgamutMapping = 'LinearSRGBToLinearDisplayP3';\n\n\t}\n\n\tswitch ( colorSpace ) {\n\n\t\tcase LinearSRGBColorSpace:\n\t\tcase LinearDisplayP3ColorSpace:\n\t\t\treturn [ gamutMapping, 'LinearTransferOETF' ];\n\n\t\tcase SRGBColorSpace:\n\t\tcase DisplayP3ColorSpace:\n\t\t\treturn [ gamutMapping, 'sRGBTransferOETF' ];\n\n\t\tdefault:\n\t\t\tconsole.warn( 'THREE.WebGLProgram: Unsupported color space:', colorSpace );\n\t\t\treturn [ gamutMapping, 'LinearTransferOETF' ];\n\n\t}\n\n}\n\nfunction getShaderErrors( gl, shader, type ) {\n\n\tconst status = gl.getShaderParameter( shader, gl.COMPILE_STATUS );\n\tconst errors = gl.getShaderInfoLog( shader ).trim();\n\n\tif ( status && errors === '' ) return '';\n\n\tconst errorMatches = /ERROR: 0:(\\d+)/.exec( errors );\n\tif ( errorMatches ) {\n\n\t\t// --enable-privileged-webgl-extension\n\t\t// console.log( '**' + type + '**', gl.getExtension( 'WEBGL_debug_shaders' ).getTranslatedShaderSource( shader ) );\n\n\t\tconst errorLine = parseInt( errorMatches[ 1 ] );\n\t\treturn type.toUpperCase() + '\\n\\n' + errors + '\\n\\n' + handleSource( gl.getShaderSource( shader ), errorLine );\n\n\t} else {\n\n\t\treturn errors;\n\n\t}\n\n}\n\nfunction getTexelEncodingFunction( functionName, colorSpace ) {\n\n\tconst components = getEncodingComponents( colorSpace );\n\treturn `vec4 ${functionName}( vec4 value ) { return ${components[ 0 ]}( ${components[ 1 ]}( value ) ); }`;\n\n}\n\nfunction getToneMappingFunction( functionName, toneMapping ) {\n\n\tlet toneMappingName;\n\n\tswitch ( toneMapping ) {\n\n\t\tcase LinearToneMapping:\n\t\t\ttoneMappingName = 'Linear';\n\t\t\tbreak;\n\n\t\tcase ReinhardToneMapping:\n\t\t\ttoneMappingName = 'Reinhard';\n\t\t\tbreak;\n\n\t\tcase CineonToneMapping:\n\t\t\ttoneMappingName = 'OptimizedCineon';\n\t\t\tbreak;\n\n\t\tcase ACESFilmicToneMapping:\n\t\t\ttoneMappingName = 'ACESFilmic';\n\t\t\tbreak;\n\n\t\tcase AgXToneMapping:\n\t\t\ttoneMappingName = 'AgX';\n\t\t\tbreak;\n\n\t\tcase NeutralToneMapping:\n\t\t\ttoneMappingName = 'Neutral';\n\t\t\tbreak;\n\n\t\tcase CustomToneMapping:\n\t\t\ttoneMappingName = 'Custom';\n\t\t\tbreak;\n\n\t\tdefault:\n\t\t\tconsole.warn( 'THREE.WebGLProgram: Unsupported toneMapping:', toneMapping );\n\t\t\ttoneMappingName = 'Linear';\n\n\t}\n\n\treturn 'vec3 ' + functionName + '( vec3 color ) { return ' + toneMappingName + 'ToneMapping( color ); }';\n\n}\n\nconst _v0$1 = /*@__PURE__*/ new Vector3();\n\nfunction getLuminanceFunction() {\n\n\tColorManagement.getLuminanceCoefficients( _v0$1 );\n\n\tconst r = _v0$1.x.toFixed( 4 );\n\tconst g = _v0$1.y.toFixed( 4 );\n\tconst b = _v0$1.z.toFixed( 4 );\n\n\treturn [\n\n\t\t'float luminance( const in vec3 rgb ) {',\n\n\t\t`\tconst vec3 weights = vec3( ${ r }, ${ g }, ${ b } );`,\n\n\t\t'\treturn dot( weights, rgb );',\n\n\t\t'}'\n\n\t].join( '\\n' );\n\n}\n\nfunction generateVertexExtensions( parameters ) {\n\n\tconst chunks = [\n\t\tparameters.extensionClipCullDistance ? '#extension GL_ANGLE_clip_cull_distance : require' : '',\n\t\tparameters.extensionMultiDraw ? '#extension GL_ANGLE_multi_draw : require' : '',\n\t];\n\n\treturn chunks.filter( filterEmptyLine ).join( '\\n' );\n\n}\n\nfunction generateDefines( defines ) {\n\n\tconst chunks = [];\n\n\tfor ( const name in defines ) {\n\n\t\tconst value = defines[ name ];\n\n\t\tif ( value === false ) continue;\n\n\t\tchunks.push( '#define ' + name + ' ' + value );\n\n\t}\n\n\treturn chunks.join( '\\n' );\n\n}\n\nfunction fetchAttributeLocations( gl, program ) {\n\n\tconst attributes = {};\n\n\tconst n = gl.getProgramParameter( program, gl.ACTIVE_ATTRIBUTES );\n\n\tfor ( let i = 0; i < n; i ++ ) {\n\n\t\tconst info = gl.getActiveAttrib( program, i );\n\t\tconst name = info.name;\n\n\t\tlet locationSize = 1;\n\t\tif ( info.type === gl.FLOAT_MAT2 ) locationSize = 2;\n\t\tif ( info.type === gl.FLOAT_MAT3 ) locationSize = 3;\n\t\tif ( info.type === gl.FLOAT_MAT4 ) locationSize = 4;\n\n\t\t// console.log( 'THREE.WebGLProgram: ACTIVE VERTEX ATTRIBUTE:', name, i );\n\n\t\tattributes[ name ] = {\n\t\t\ttype: info.type,\n\t\t\tlocation: gl.getAttribLocation( program, name ),\n\t\t\tlocationSize: locationSize\n\t\t};\n\n\t}\n\n\treturn attributes;\n\n}\n\nfunction filterEmptyLine( string ) {\n\n\treturn string !== '';\n\n}\n\nfunction replaceLightNums( string, parameters ) {\n\n\tconst numSpotLightCoords = parameters.numSpotLightShadows + parameters.numSpotLightMaps - parameters.numSpotLightShadowsWithMaps;\n\n\treturn string\n\t\t.replace( /NUM_DIR_LIGHTS/g, parameters.numDirLights )\n\t\t.replace( /NUM_SPOT_LIGHTS/g, parameters.numSpotLights )\n\t\t.replace( /NUM_SPOT_LIGHT_MAPS/g, parameters.numSpotLightMaps )\n\t\t.replace( /NUM_SPOT_LIGHT_COORDS/g, numSpotLightCoords )\n\t\t.replace( /NUM_RECT_AREA_LIGHTS/g, parameters.numRectAreaLights )\n\t\t.replace( /NUM_POINT_LIGHTS/g, parameters.numPointLights )\n\t\t.replace( /NUM_HEMI_LIGHTS/g, parameters.numHemiLights )\n\t\t.replace( /NUM_DIR_LIGHT_SHADOWS/g, parameters.numDirLightShadows )\n\t\t.replace( /NUM_SPOT_LIGHT_SHADOWS_WITH_MAPS/g, parameters.numSpotLightShadowsWithMaps )\n\t\t.replace( /NUM_SPOT_LIGHT_SHADOWS/g, parameters.numSpotLightShadows )\n\t\t.replace( /NUM_POINT_LIGHT_SHADOWS/g, parameters.numPointLightShadows );\n\n}\n\nfunction replaceClippingPlaneNums( string, parameters ) {\n\n\treturn string\n\t\t.replace( /NUM_CLIPPING_PLANES/g, parameters.numClippingPlanes )\n\t\t.replace( /UNION_CLIPPING_PLANES/g, ( parameters.numClippingPlanes - parameters.numClipIntersection ) );\n\n}\n\n// Resolve Includes\n\nconst includePattern = /^[ \\t]*#include +<([\\w\\d./]+)>/gm;\n\nfunction resolveIncludes( string ) {\n\n\treturn string.replace( includePattern, includeReplacer );\n\n}\n\nconst shaderChunkMap = new Map();\n\nfunction includeReplacer( match, include ) {\n\n\tlet string = ShaderChunk[ include ];\n\n\tif ( string === undefined ) {\n\n\t\tconst newInclude = shaderChunkMap.get( include );\n\n\t\tif ( newInclude !== undefined ) {\n\n\t\t\tstring = ShaderChunk[ newInclude ];\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: Shader chunk \"%s\" has been deprecated. Use \"%s\" instead.', include, newInclude );\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'Can not resolve #include <' + include + '>' );\n\n\t\t}\n\n\t}\n\n\treturn resolveIncludes( string );\n\n}\n\n// Unroll Loops\n\nconst 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;\n\nfunction unrollLoops( string ) {\n\n\treturn string.replace( unrollLoopPattern, loopReplacer );\n\n}\n\nfunction loopReplacer( match, start, end, snippet ) {\n\n\tlet string = '';\n\n\tfor ( let i = parseInt( start ); i < parseInt( end ); i ++ ) {\n\n\t\tstring += snippet\n\t\t\t.replace( /\\[\\s*i\\s*\\]/g, '[ ' + i + ' ]' )\n\t\t\t.replace( /UNROLLED_LOOP_INDEX/g, i );\n\n\t}\n\n\treturn string;\n\n}\n\n//\n\nfunction generatePrecision( parameters ) {\n\n\tlet precisionstring = `precision ${parameters.precision} float;\n\tprecision ${parameters.precision} int;\n\tprecision ${parameters.precision} sampler2D;\n\tprecision ${parameters.precision} samplerCube;\n\tprecision ${parameters.precision} sampler3D;\n\tprecision ${parameters.precision} sampler2DArray;\n\tprecision ${parameters.precision} sampler2DShadow;\n\tprecision ${parameters.precision} samplerCubeShadow;\n\tprecision ${parameters.precision} sampler2DArrayShadow;\n\tprecision ${parameters.precision} isampler2D;\n\tprecision ${parameters.precision} isampler3D;\n\tprecision ${parameters.precision} isamplerCube;\n\tprecision ${parameters.precision} isampler2DArray;\n\tprecision ${parameters.precision} usampler2D;\n\tprecision ${parameters.precision} usampler3D;\n\tprecision ${parameters.precision} usamplerCube;\n\tprecision ${parameters.precision} usampler2DArray;\n\t`;\n\n\tif ( parameters.precision === 'highp' ) {\n\n\t\tprecisionstring += '\\n#define HIGH_PRECISION';\n\n\t} else if ( parameters.precision === 'mediump' ) {\n\n\t\tprecisionstring += '\\n#define MEDIUM_PRECISION';\n\n\t} else if ( parameters.precision === 'lowp' ) {\n\n\t\tprecisionstring += '\\n#define LOW_PRECISION';\n\n\t}\n\n\treturn precisionstring;\n\n}\n\nfunction generateShadowMapTypeDefine( parameters ) {\n\n\tlet shadowMapTypeDefine = 'SHADOWMAP_TYPE_BASIC';\n\n\tif ( parameters.shadowMapType === PCFShadowMap ) {\n\n\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF';\n\n\t} else if ( parameters.shadowMapType === PCFSoftShadowMap ) {\n\n\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_PCF_SOFT';\n\n\t} else if ( parameters.shadowMapType === VSMShadowMap ) {\n\n\t\tshadowMapTypeDefine = 'SHADOWMAP_TYPE_VSM';\n\n\t}\n\n\treturn shadowMapTypeDefine;\n\n}\n\nfunction generateEnvMapTypeDefine( parameters ) {\n\n\tlet envMapTypeDefine = 'ENVMAP_TYPE_CUBE';\n\n\tif ( parameters.envMap ) {\n\n\t\tswitch ( parameters.envMapMode ) {\n\n\t\t\tcase CubeReflectionMapping:\n\t\t\tcase CubeRefractionMapping:\n\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_CUBE';\n\t\t\t\tbreak;\n\n\t\t\tcase CubeUVReflectionMapping:\n\t\t\t\tenvMapTypeDefine = 'ENVMAP_TYPE_CUBE_UV';\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\treturn envMapTypeDefine;\n\n}\n\nfunction generateEnvMapModeDefine( parameters ) {\n\n\tlet envMapModeDefine = 'ENVMAP_MODE_REFLECTION';\n\n\tif ( parameters.envMap ) {\n\n\t\tswitch ( parameters.envMapMode ) {\n\n\t\t\tcase CubeRefractionMapping:\n\n\t\t\t\tenvMapModeDefine = 'ENVMAP_MODE_REFRACTION';\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\treturn envMapModeDefine;\n\n}\n\nfunction generateEnvMapBlendingDefine( parameters ) {\n\n\tlet envMapBlendingDefine = 'ENVMAP_BLENDING_NONE';\n\n\tif ( parameters.envMap ) {\n\n\t\tswitch ( parameters.combine ) {\n\n\t\t\tcase MultiplyOperation:\n\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_MULTIPLY';\n\t\t\t\tbreak;\n\n\t\t\tcase MixOperation:\n\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_MIX';\n\t\t\t\tbreak;\n\n\t\t\tcase AddOperation:\n\t\t\t\tenvMapBlendingDefine = 'ENVMAP_BLENDING_ADD';\n\t\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n\treturn envMapBlendingDefine;\n\n}\n\nfunction generateCubeUVSize( parameters ) {\n\n\tconst imageHeight = parameters.envMapCubeUVHeight;\n\n\tif ( imageHeight === null ) return null;\n\n\tconst maxMip = Math.log2( imageHeight ) - 2;\n\n\tconst texelHeight = 1.0 / imageHeight;\n\n\tconst texelWidth = 1.0 / ( 3 * Math.max( Math.pow( 2, maxMip ), 7 * 16 ) );\n\n\treturn { texelWidth, texelHeight, maxMip };\n\n}\n\nfunction WebGLProgram( renderer, cacheKey, parameters, bindingStates ) {\n\n\t// TODO Send this event to Three.js DevTools\n\t// console.log( 'WebGLProgram', cacheKey );\n\n\tconst gl = renderer.getContext();\n\n\tconst defines = parameters.defines;\n\n\tlet vertexShader = parameters.vertexShader;\n\tlet fragmentShader = parameters.fragmentShader;\n\n\tconst shadowMapTypeDefine = generateShadowMapTypeDefine( parameters );\n\tconst envMapTypeDefine = generateEnvMapTypeDefine( parameters );\n\tconst envMapModeDefine = generateEnvMapModeDefine( parameters );\n\tconst envMapBlendingDefine = generateEnvMapBlendingDefine( parameters );\n\tconst envMapCubeUVSize = generateCubeUVSize( parameters );\n\n\tconst customVertexExtensions = generateVertexExtensions( parameters );\n\n\tconst customDefines = generateDefines( defines );\n\n\tconst program = gl.createProgram();\n\n\tlet prefixVertex, prefixFragment;\n\tlet versionString = parameters.glslVersion ? '#version ' + parameters.glslVersion + '\\n' : '';\n\n\tif ( parameters.isRawShaderMaterial ) {\n\n\t\tprefixVertex = [\n\n\t\t\t'#define SHADER_TYPE ' + parameters.shaderType,\n\t\t\t'#define SHADER_NAME ' + parameters.shaderName,\n\n\t\t\tcustomDefines\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\tif ( prefixVertex.length > 0 ) {\n\n\t\t\tprefixVertex += '\\n';\n\n\t\t}\n\n\t\tprefixFragment = [\n\n\t\t\t'#define SHADER_TYPE ' + parameters.shaderType,\n\t\t\t'#define SHADER_NAME ' + parameters.shaderName,\n\n\t\t\tcustomDefines\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\tif ( prefixFragment.length > 0 ) {\n\n\t\t\tprefixFragment += '\\n';\n\n\t\t}\n\n\t} else {\n\n\t\tprefixVertex = [\n\n\t\t\tgeneratePrecision( parameters ),\n\n\t\t\t'#define SHADER_TYPE ' + parameters.shaderType,\n\t\t\t'#define SHADER_NAME ' + parameters.shaderName,\n\n\t\t\tcustomDefines,\n\n\t\t\tparameters.extensionClipCullDistance ? '#define USE_CLIP_DISTANCE' : '',\n\t\t\tparameters.batching ? '#define USE_BATCHING' : '',\n\t\t\tparameters.batchingColor ? '#define USE_BATCHING_COLOR' : '',\n\t\t\tparameters.instancing ? '#define USE_INSTANCING' : '',\n\t\t\tparameters.instancingColor ? '#define USE_INSTANCING_COLOR' : '',\n\t\t\tparameters.instancingMorph ? '#define USE_INSTANCING_MORPH' : '',\n\n\t\t\tparameters.useFog && parameters.fog ? '#define USE_FOG' : '',\n\t\t\tparameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',\n\n\t\t\tparameters.map ? '#define USE_MAP' : '',\n\t\t\tparameters.envMap ? '#define USE_ENVMAP' : '',\n\t\t\tparameters.envMap ? '#define ' + envMapModeDefine : '',\n\t\t\tparameters.lightMap ? '#define USE_LIGHTMAP' : '',\n\t\t\tparameters.aoMap ? '#define USE_AOMAP' : '',\n\t\t\tparameters.bumpMap ? '#define USE_BUMPMAP' : '',\n\t\t\tparameters.normalMap ? '#define USE_NORMALMAP' : '',\n\t\t\tparameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',\n\t\t\tparameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',\n\t\t\tparameters.displacementMap ? '#define USE_DISPLACEMENTMAP' : '',\n\t\t\tparameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',\n\n\t\t\tparameters.anisotropy ? '#define USE_ANISOTROPY' : '',\n\t\t\tparameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',\n\n\t\t\tparameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',\n\t\t\tparameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',\n\t\t\tparameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',\n\n\t\t\tparameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',\n\t\t\tparameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',\n\n\t\t\tparameters.specularMap ? '#define USE_SPECULARMAP' : '',\n\t\t\tparameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',\n\t\t\tparameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',\n\n\t\t\tparameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',\n\t\t\tparameters.metalnessMap ? '#define USE_METALNESSMAP' : '',\n\t\t\tparameters.alphaMap ? '#define USE_ALPHAMAP' : '',\n\t\t\tparameters.alphaHash ? '#define USE_ALPHAHASH' : '',\n\n\t\t\tparameters.transmission ? '#define USE_TRANSMISSION' : '',\n\t\t\tparameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',\n\t\t\tparameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',\n\n\t\t\tparameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',\n\t\t\tparameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',\n\n\t\t\t//\n\n\t\t\tparameters.mapUv ? '#define MAP_UV ' + parameters.mapUv : '',\n\t\t\tparameters.alphaMapUv ? '#define ALPHAMAP_UV ' + parameters.alphaMapUv : '',\n\t\t\tparameters.lightMapUv ? '#define LIGHTMAP_UV ' + parameters.lightMapUv : '',\n\t\t\tparameters.aoMapUv ? '#define AOMAP_UV ' + parameters.aoMapUv : '',\n\t\t\tparameters.emissiveMapUv ? '#define EMISSIVEMAP_UV ' + parameters.emissiveMapUv : '',\n\t\t\tparameters.bumpMapUv ? '#define BUMPMAP_UV ' + parameters.bumpMapUv : '',\n\t\t\tparameters.normalMapUv ? '#define NORMALMAP_UV ' + parameters.normalMapUv : '',\n\t\t\tparameters.displacementMapUv ? '#define DISPLACEMENTMAP_UV ' + parameters.displacementMapUv : '',\n\n\t\t\tparameters.metalnessMapUv ? '#define METALNESSMAP_UV ' + parameters.metalnessMapUv : '',\n\t\t\tparameters.roughnessMapUv ? '#define ROUGHNESSMAP_UV ' + parameters.roughnessMapUv : '',\n\n\t\t\tparameters.anisotropyMapUv ? '#define ANISOTROPYMAP_UV ' + parameters.anisotropyMapUv : '',\n\n\t\t\tparameters.clearcoatMapUv ? '#define CLEARCOATMAP_UV ' + parameters.clearcoatMapUv : '',\n\t\t\tparameters.clearcoatNormalMapUv ? '#define CLEARCOAT_NORMALMAP_UV ' + parameters.clearcoatNormalMapUv : '',\n\t\t\tparameters.clearcoatRoughnessMapUv ? '#define CLEARCOAT_ROUGHNESSMAP_UV ' + parameters.clearcoatRoughnessMapUv : '',\n\n\t\t\tparameters.iridescenceMapUv ? '#define IRIDESCENCEMAP_UV ' + parameters.iridescenceMapUv : '',\n\t\t\tparameters.iridescenceThicknessMapUv ? '#define IRIDESCENCE_THICKNESSMAP_UV ' + parameters.iridescenceThicknessMapUv : '',\n\n\t\t\tparameters.sheenColorMapUv ? '#define SHEEN_COLORMAP_UV ' + parameters.sheenColorMapUv : '',\n\t\t\tparameters.sheenRoughnessMapUv ? '#define SHEEN_ROUGHNESSMAP_UV ' + parameters.sheenRoughnessMapUv : '',\n\n\t\t\tparameters.specularMapUv ? '#define SPECULARMAP_UV ' + parameters.specularMapUv : '',\n\t\t\tparameters.specularColorMapUv ? '#define SPECULAR_COLORMAP_UV ' + parameters.specularColorMapUv : '',\n\t\t\tparameters.specularIntensityMapUv ? '#define SPECULAR_INTENSITYMAP_UV ' + parameters.specularIntensityMapUv : '',\n\n\t\t\tparameters.transmissionMapUv ? '#define TRANSMISSIONMAP_UV ' + parameters.transmissionMapUv : '',\n\t\t\tparameters.thicknessMapUv ? '#define THICKNESSMAP_UV ' + parameters.thicknessMapUv : '',\n\n\t\t\t//\n\n\t\t\tparameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',\n\t\t\tparameters.vertexColors ? '#define USE_COLOR' : '',\n\t\t\tparameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',\n\t\t\tparameters.vertexUv1s ? '#define USE_UV1' : '',\n\t\t\tparameters.vertexUv2s ? '#define USE_UV2' : '',\n\t\t\tparameters.vertexUv3s ? '#define USE_UV3' : '',\n\n\t\t\tparameters.pointsUvs ? '#define USE_POINTS_UV' : '',\n\n\t\t\tparameters.flatShading ? '#define FLAT_SHADED' : '',\n\n\t\t\tparameters.skinning ? '#define USE_SKINNING' : '',\n\n\t\t\tparameters.morphTargets ? '#define USE_MORPHTARGETS' : '',\n\t\t\tparameters.morphNormals && parameters.flatShading === false ? '#define USE_MORPHNORMALS' : '',\n\t\t\t( parameters.morphColors ) ? '#define USE_MORPHCOLORS' : '',\n\t\t\t( parameters.morphTargetsCount > 0 ) ? '#define MORPHTARGETS_TEXTURE_STRIDE ' + parameters.morphTextureStride : '',\n\t\t\t( parameters.morphTargetsCount > 0 ) ? '#define MORPHTARGETS_COUNT ' + parameters.morphTargetsCount : '',\n\t\t\tparameters.doubleSided ? '#define DOUBLE_SIDED' : '',\n\t\t\tparameters.flipSided ? '#define FLIP_SIDED' : '',\n\n\t\t\tparameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',\n\t\t\tparameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',\n\n\t\t\tparameters.sizeAttenuation ? '#define USE_SIZEATTENUATION' : '',\n\n\t\t\tparameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',\n\n\t\t\tparameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',\n\n\t\t\t'uniform mat4 modelMatrix;',\n\t\t\t'uniform mat4 modelViewMatrix;',\n\t\t\t'uniform mat4 projectionMatrix;',\n\t\t\t'uniform mat4 viewMatrix;',\n\t\t\t'uniform mat3 normalMatrix;',\n\t\t\t'uniform vec3 cameraPosition;',\n\t\t\t'uniform bool isOrthographic;',\n\n\t\t\t'#ifdef USE_INSTANCING',\n\n\t\t\t'\tattribute mat4 instanceMatrix;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_INSTANCING_COLOR',\n\n\t\t\t'\tattribute vec3 instanceColor;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_INSTANCING_MORPH',\n\n\t\t\t'\tuniform sampler2D morphTexture;',\n\n\t\t\t'#endif',\n\n\t\t\t'attribute vec3 position;',\n\t\t\t'attribute vec3 normal;',\n\t\t\t'attribute vec2 uv;',\n\n\t\t\t'#ifdef USE_UV1',\n\n\t\t\t'\tattribute vec2 uv1;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_UV2',\n\n\t\t\t'\tattribute vec2 uv2;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_UV3',\n\n\t\t\t'\tattribute vec2 uv3;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_TANGENT',\n\n\t\t\t'\tattribute vec4 tangent;',\n\n\t\t\t'#endif',\n\n\t\t\t'#if defined( USE_COLOR_ALPHA )',\n\n\t\t\t'\tattribute vec4 color;',\n\n\t\t\t'#elif defined( USE_COLOR )',\n\n\t\t\t'\tattribute vec3 color;',\n\n\t\t\t'#endif',\n\n\t\t\t'#ifdef USE_SKINNING',\n\n\t\t\t'\tattribute vec4 skinIndex;',\n\t\t\t'\tattribute vec4 skinWeight;',\n\n\t\t\t'#endif',\n\n\t\t\t'\\n'\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t\tprefixFragment = [\n\n\t\t\tgeneratePrecision( parameters ),\n\n\t\t\t'#define SHADER_TYPE ' + parameters.shaderType,\n\t\t\t'#define SHADER_NAME ' + parameters.shaderName,\n\n\t\t\tcustomDefines,\n\n\t\t\tparameters.useFog && parameters.fog ? '#define USE_FOG' : '',\n\t\t\tparameters.useFog && parameters.fogExp2 ? '#define FOG_EXP2' : '',\n\n\t\t\tparameters.alphaToCoverage ? '#define ALPHA_TO_COVERAGE' : '',\n\t\t\tparameters.map ? '#define USE_MAP' : '',\n\t\t\tparameters.matcap ? '#define USE_MATCAP' : '',\n\t\t\tparameters.envMap ? '#define USE_ENVMAP' : '',\n\t\t\tparameters.envMap ? '#define ' + envMapTypeDefine : '',\n\t\t\tparameters.envMap ? '#define ' + envMapModeDefine : '',\n\t\t\tparameters.envMap ? '#define ' + envMapBlendingDefine : '',\n\t\t\tenvMapCubeUVSize ? '#define CUBEUV_TEXEL_WIDTH ' + envMapCubeUVSize.texelWidth : '',\n\t\t\tenvMapCubeUVSize ? '#define CUBEUV_TEXEL_HEIGHT ' + envMapCubeUVSize.texelHeight : '',\n\t\t\tenvMapCubeUVSize ? '#define CUBEUV_MAX_MIP ' + envMapCubeUVSize.maxMip + '.0' : '',\n\t\t\tparameters.lightMap ? '#define USE_LIGHTMAP' : '',\n\t\t\tparameters.aoMap ? '#define USE_AOMAP' : '',\n\t\t\tparameters.bumpMap ? '#define USE_BUMPMAP' : '',\n\t\t\tparameters.normalMap ? '#define USE_NORMALMAP' : '',\n\t\t\tparameters.normalMapObjectSpace ? '#define USE_NORMALMAP_OBJECTSPACE' : '',\n\t\t\tparameters.normalMapTangentSpace ? '#define USE_NORMALMAP_TANGENTSPACE' : '',\n\t\t\tparameters.emissiveMap ? '#define USE_EMISSIVEMAP' : '',\n\n\t\t\tparameters.anisotropy ? '#define USE_ANISOTROPY' : '',\n\t\t\tparameters.anisotropyMap ? '#define USE_ANISOTROPYMAP' : '',\n\n\t\t\tparameters.clearcoat ? '#define USE_CLEARCOAT' : '',\n\t\t\tparameters.clearcoatMap ? '#define USE_CLEARCOATMAP' : '',\n\t\t\tparameters.clearcoatRoughnessMap ? '#define USE_CLEARCOAT_ROUGHNESSMAP' : '',\n\t\t\tparameters.clearcoatNormalMap ? '#define USE_CLEARCOAT_NORMALMAP' : '',\n\n\t\t\tparameters.dispersion ? '#define USE_DISPERSION' : '',\n\n\t\t\tparameters.iridescence ? '#define USE_IRIDESCENCE' : '',\n\t\t\tparameters.iridescenceMap ? '#define USE_IRIDESCENCEMAP' : '',\n\t\t\tparameters.iridescenceThicknessMap ? '#define USE_IRIDESCENCE_THICKNESSMAP' : '',\n\n\t\t\tparameters.specularMap ? '#define USE_SPECULARMAP' : '',\n\t\t\tparameters.specularColorMap ? '#define USE_SPECULAR_COLORMAP' : '',\n\t\t\tparameters.specularIntensityMap ? '#define USE_SPECULAR_INTENSITYMAP' : '',\n\n\t\t\tparameters.roughnessMap ? '#define USE_ROUGHNESSMAP' : '',\n\t\t\tparameters.metalnessMap ? '#define USE_METALNESSMAP' : '',\n\n\t\t\tparameters.alphaMap ? '#define USE_ALPHAMAP' : '',\n\t\t\tparameters.alphaTest ? '#define USE_ALPHATEST' : '',\n\t\t\tparameters.alphaHash ? '#define USE_ALPHAHASH' : '',\n\n\t\t\tparameters.sheen ? '#define USE_SHEEN' : '',\n\t\t\tparameters.sheenColorMap ? '#define USE_SHEEN_COLORMAP' : '',\n\t\t\tparameters.sheenRoughnessMap ? '#define USE_SHEEN_ROUGHNESSMAP' : '',\n\n\t\t\tparameters.transmission ? '#define USE_TRANSMISSION' : '',\n\t\t\tparameters.transmissionMap ? '#define USE_TRANSMISSIONMAP' : '',\n\t\t\tparameters.thicknessMap ? '#define USE_THICKNESSMAP' : '',\n\n\t\t\tparameters.vertexTangents && parameters.flatShading === false ? '#define USE_TANGENT' : '',\n\t\t\tparameters.vertexColors || parameters.instancingColor || parameters.batchingColor ? '#define USE_COLOR' : '',\n\t\t\tparameters.vertexAlphas ? '#define USE_COLOR_ALPHA' : '',\n\t\t\tparameters.vertexUv1s ? '#define USE_UV1' : '',\n\t\t\tparameters.vertexUv2s ? '#define USE_UV2' : '',\n\t\t\tparameters.vertexUv3s ? '#define USE_UV3' : '',\n\n\t\t\tparameters.pointsUvs ? '#define USE_POINTS_UV' : '',\n\n\t\t\tparameters.gradientMap ? '#define USE_GRADIENTMAP' : '',\n\n\t\t\tparameters.flatShading ? '#define FLAT_SHADED' : '',\n\n\t\t\tparameters.doubleSided ? '#define DOUBLE_SIDED' : '',\n\t\t\tparameters.flipSided ? '#define FLIP_SIDED' : '',\n\n\t\t\tparameters.shadowMapEnabled ? '#define USE_SHADOWMAP' : '',\n\t\t\tparameters.shadowMapEnabled ? '#define ' + shadowMapTypeDefine : '',\n\n\t\t\tparameters.premultipliedAlpha ? '#define PREMULTIPLIED_ALPHA' : '',\n\n\t\t\tparameters.numLightProbes > 0 ? '#define USE_LIGHT_PROBES' : '',\n\n\t\t\tparameters.decodeVideoTexture ? '#define DECODE_VIDEO_TEXTURE' : '',\n\n\t\t\tparameters.logarithmicDepthBuffer ? '#define USE_LOGDEPTHBUF' : '',\n\n\t\t\t'uniform mat4 viewMatrix;',\n\t\t\t'uniform vec3 cameraPosition;',\n\t\t\t'uniform bool isOrthographic;',\n\n\t\t\t( parameters.toneMapping !== NoToneMapping ) ? '#define TONE_MAPPING' : '',\n\t\t\t( parameters.toneMapping !== NoToneMapping ) ? ShaderChunk[ 'tonemapping_pars_fragment' ] : '', // this code is required here because it is used by the toneMapping() function defined below\n\t\t\t( parameters.toneMapping !== NoToneMapping ) ? getToneMappingFunction( 'toneMapping', parameters.toneMapping ) : '',\n\n\t\t\tparameters.dithering ? '#define DITHERING' : '',\n\t\t\tparameters.opaque ? '#define OPAQUE' : '',\n\n\t\t\tShaderChunk[ 'colorspace_pars_fragment' ], // this code is required here because it is used by the various encoding/decoding function defined below\n\t\t\tgetTexelEncodingFunction( 'linearToOutputTexel', parameters.outputColorSpace ),\n\t\t\tgetLuminanceFunction(),\n\n\t\t\tparameters.useDepthPacking ? '#define DEPTH_PACKING ' + parameters.depthPacking : '',\n\n\t\t\t'\\n'\n\n\t\t].filter( filterEmptyLine ).join( '\\n' );\n\n\t}\n\n\tvertexShader = resolveIncludes( vertexShader );\n\tvertexShader = replaceLightNums( vertexShader, parameters );\n\tvertexShader = replaceClippingPlaneNums( vertexShader, parameters );\n\n\tfragmentShader = resolveIncludes( fragmentShader );\n\tfragmentShader = replaceLightNums( fragmentShader, parameters );\n\tfragmentShader = replaceClippingPlaneNums( fragmentShader, parameters );\n\n\tvertexShader = unrollLoops( vertexShader );\n\tfragmentShader = unrollLoops( fragmentShader );\n\n\tif ( parameters.isRawShaderMaterial !== true ) {\n\n\t\t// GLSL 3.0 conversion for built-in materials and ShaderMaterial\n\n\t\tversionString = '#version 300 es\\n';\n\n\t\tprefixVertex = [\n\t\t\tcustomVertexExtensions,\n\t\t\t'#define attribute in',\n\t\t\t'#define varying out',\n\t\t\t'#define texture2D texture'\n\t\t].join( '\\n' ) + '\\n' + prefixVertex;\n\n\t\tprefixFragment = [\n\t\t\t'#define varying in',\n\t\t\t( parameters.glslVersion === GLSL3 ) ? '' : 'layout(location = 0) out highp vec4 pc_fragColor;',\n\t\t\t( parameters.glslVersion === GLSL3 ) ? '' : '#define gl_FragColor pc_fragColor',\n\t\t\t'#define gl_FragDepthEXT gl_FragDepth',\n\t\t\t'#define texture2D texture',\n\t\t\t'#define textureCube texture',\n\t\t\t'#define texture2DProj textureProj',\n\t\t\t'#define texture2DLodEXT textureLod',\n\t\t\t'#define texture2DProjLodEXT textureProjLod',\n\t\t\t'#define textureCubeLodEXT textureLod',\n\t\t\t'#define texture2DGradEXT textureGrad',\n\t\t\t'#define texture2DProjGradEXT textureProjGrad',\n\t\t\t'#define textureCubeGradEXT textureGrad'\n\t\t].join( '\\n' ) + '\\n' + prefixFragment;\n\n\t}\n\n\tconst vertexGlsl = versionString + prefixVertex + vertexShader;\n\tconst fragmentGlsl = versionString + prefixFragment + fragmentShader;\n\n\t// console.log( '*VERTEX*', vertexGlsl );\n\t// console.log( '*FRAGMENT*', fragmentGlsl );\n\n\tconst glVertexShader = WebGLShader( gl, gl.VERTEX_SHADER, vertexGlsl );\n\tconst glFragmentShader = WebGLShader( gl, gl.FRAGMENT_SHADER, fragmentGlsl );\n\n\tgl.attachShader( program, glVertexShader );\n\tgl.attachShader( program, glFragmentShader );\n\n\t// Force a particular attribute to index 0.\n\n\tif ( parameters.index0AttributeName !== undefined ) {\n\n\t\tgl.bindAttribLocation( program, 0, parameters.index0AttributeName );\n\n\t} else if ( parameters.morphTargets === true ) {\n\n\t\t// programs with morphTargets displace position out of attribute 0\n\t\tgl.bindAttribLocation( program, 0, 'position' );\n\n\t}\n\n\tgl.linkProgram( program );\n\n\tfunction onFirstUse( self ) {\n\n\t\t// check for link errors\n\t\tif ( renderer.debug.checkShaderErrors ) {\n\n\t\t\tconst programLog = gl.getProgramInfoLog( program ).trim();\n\t\t\tconst vertexLog = gl.getShaderInfoLog( glVertexShader ).trim();\n\t\t\tconst fragmentLog = gl.getShaderInfoLog( glFragmentShader ).trim();\n\n\t\t\tlet runnable = true;\n\t\t\tlet haveDiagnostics = true;\n\n\t\t\tif ( gl.getProgramParameter( program, gl.LINK_STATUS ) === false ) {\n\n\t\t\t\trunnable = false;\n\n\t\t\t\tif ( typeof renderer.debug.onShaderError === 'function' ) {\n\n\t\t\t\t\trenderer.debug.onShaderError( gl, program, glVertexShader, glFragmentShader );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// default error reporting\n\n\t\t\t\t\tconst vertexErrors = getShaderErrors( gl, glVertexShader, 'vertex' );\n\t\t\t\t\tconst fragmentErrors = getShaderErrors( gl, glFragmentShader, 'fragment' );\n\n\t\t\t\t\tconsole.error(\n\t\t\t\t\t\t'THREE.WebGLProgram: Shader Error ' + gl.getError() + ' - ' +\n\t\t\t\t\t\t'VALIDATE_STATUS ' + gl.getProgramParameter( program, gl.VALIDATE_STATUS ) + '\\n\\n' +\n\t\t\t\t\t\t'Material Name: ' + self.name + '\\n' +\n\t\t\t\t\t\t'Material Type: ' + self.type + '\\n\\n' +\n\t\t\t\t\t\t'Program Info Log: ' + programLog + '\\n' +\n\t\t\t\t\t\tvertexErrors + '\\n' +\n\t\t\t\t\t\tfragmentErrors\n\t\t\t\t\t);\n\n\t\t\t\t}\n\n\t\t\t} else if ( programLog !== '' ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLProgram: Program Info Log:', programLog );\n\n\t\t\t} else if ( vertexLog === '' || fragmentLog === '' ) {\n\n\t\t\t\thaveDiagnostics = false;\n\n\t\t\t}\n\n\t\t\tif ( haveDiagnostics ) {\n\n\t\t\t\tself.diagnostics = {\n\n\t\t\t\t\trunnable: runnable,\n\n\t\t\t\t\tprogramLog: programLog,\n\n\t\t\t\t\tvertexShader: {\n\n\t\t\t\t\t\tlog: vertexLog,\n\t\t\t\t\t\tprefix: prefixVertex\n\n\t\t\t\t\t},\n\n\t\t\t\t\tfragmentShader: {\n\n\t\t\t\t\t\tlog: fragmentLog,\n\t\t\t\t\t\tprefix: prefixFragment\n\n\t\t\t\t\t}\n\n\t\t\t\t};\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Clean up\n\n\t\t// Crashes in iOS9 and iOS10. #18402\n\t\t// gl.detachShader( program, glVertexShader );\n\t\t// gl.detachShader( program, glFragmentShader );\n\n\t\tgl.deleteShader( glVertexShader );\n\t\tgl.deleteShader( glFragmentShader );\n\n\t\tcachedUniforms = new WebGLUniforms( gl, program );\n\t\tcachedAttributes = fetchAttributeLocations( gl, program );\n\n\t}\n\n\t// set up caching for uniform locations\n\n\tlet cachedUniforms;\n\n\tthis.getUniforms = function () {\n\n\t\tif ( cachedUniforms === undefined ) {\n\n\t\t\t// Populates cachedUniforms and cachedAttributes\n\t\t\tonFirstUse( this );\n\n\t\t}\n\n\t\treturn cachedUniforms;\n\n\t};\n\n\t// set up caching for attribute locations\n\n\tlet cachedAttributes;\n\n\tthis.getAttributes = function () {\n\n\t\tif ( cachedAttributes === undefined ) {\n\n\t\t\t// Populates cachedAttributes and cachedUniforms\n\t\t\tonFirstUse( this );\n\n\t\t}\n\n\t\treturn cachedAttributes;\n\n\t};\n\n\t// indicate when the program is ready to be used. if the KHR_parallel_shader_compile extension isn't supported,\n\t// flag the program as ready immediately. It may cause a stall when it's first used.\n\n\tlet programReady = ( parameters.rendererExtensionParallelShaderCompile === false );\n\n\tthis.isReady = function () {\n\n\t\tif ( programReady === false ) {\n\n\t\t\tprogramReady = gl.getProgramParameter( program, COMPLETION_STATUS_KHR );\n\n\t\t}\n\n\t\treturn programReady;\n\n\t};\n\n\t// free resource\n\n\tthis.destroy = function () {\n\n\t\tbindingStates.releaseStatesOfProgram( this );\n\n\t\tgl.deleteProgram( program );\n\t\tthis.program = undefined;\n\n\t};\n\n\t//\n\n\tthis.type = parameters.shaderType;\n\tthis.name = parameters.shaderName;\n\tthis.id = programIdCount ++;\n\tthis.cacheKey = cacheKey;\n\tthis.usedTimes = 1;\n\tthis.program = program;\n\tthis.vertexShader = glVertexShader;\n\tthis.fragmentShader = glFragmentShader;\n\n\treturn this;\n\n}\n\nlet _id$1 = 0;\n\nclass WebGLShaderCache {\n\n\tconstructor() {\n\n\t\tthis.shaderCache = new Map();\n\t\tthis.materialCache = new Map();\n\n\t}\n\n\tupdate( material ) {\n\n\t\tconst vertexShader = material.vertexShader;\n\t\tconst fragmentShader = material.fragmentShader;\n\n\t\tconst vertexShaderStage = this._getShaderStage( vertexShader );\n\t\tconst fragmentShaderStage = this._getShaderStage( fragmentShader );\n\n\t\tconst materialShaders = this._getShaderCacheForMaterial( material );\n\n\t\tif ( materialShaders.has( vertexShaderStage ) === false ) {\n\n\t\t\tmaterialShaders.add( vertexShaderStage );\n\t\t\tvertexShaderStage.usedTimes ++;\n\n\t\t}\n\n\t\tif ( materialShaders.has( fragmentShaderStage ) === false ) {\n\n\t\t\tmaterialShaders.add( fragmentShaderStage );\n\t\t\tfragmentShaderStage.usedTimes ++;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tremove( material ) {\n\n\t\tconst materialShaders = this.materialCache.get( material );\n\n\t\tfor ( const shaderStage of materialShaders ) {\n\n\t\t\tshaderStage.usedTimes --;\n\n\t\t\tif ( shaderStage.usedTimes === 0 ) this.shaderCache.delete( shaderStage.code );\n\n\t\t}\n\n\t\tthis.materialCache.delete( material );\n\n\t\treturn this;\n\n\t}\n\n\tgetVertexShaderID( material ) {\n\n\t\treturn this._getShaderStage( material.vertexShader ).id;\n\n\t}\n\n\tgetFragmentShaderID( material ) {\n\n\t\treturn this._getShaderStage( material.fragmentShader ).id;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.shaderCache.clear();\n\t\tthis.materialCache.clear();\n\n\t}\n\n\t_getShaderCacheForMaterial( material ) {\n\n\t\tconst cache = this.materialCache;\n\t\tlet set = cache.get( material );\n\n\t\tif ( set === undefined ) {\n\n\t\t\tset = new Set();\n\t\t\tcache.set( material, set );\n\n\t\t}\n\n\t\treturn set;\n\n\t}\n\n\t_getShaderStage( code ) {\n\n\t\tconst cache = this.shaderCache;\n\t\tlet stage = cache.get( code );\n\n\t\tif ( stage === undefined ) {\n\n\t\t\tstage = new WebGLShaderStage( code );\n\t\t\tcache.set( code, stage );\n\n\t\t}\n\n\t\treturn stage;\n\n\t}\n\n}\n\nclass WebGLShaderStage {\n\n\tconstructor( code ) {\n\n\t\tthis.id = _id$1 ++;\n\n\t\tthis.code = code;\n\t\tthis.usedTimes = 0;\n\n\t}\n\n}\n\nfunction WebGLPrograms( renderer, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping ) {\n\n\tconst _programLayers = new Layers();\n\tconst _customShaders = new WebGLShaderCache();\n\tconst _activeChannels = new Set();\n\tconst programs = [];\n\n\tconst logarithmicDepthBuffer = capabilities.logarithmicDepthBuffer;\n\tconst SUPPORTS_VERTEX_TEXTURES = capabilities.vertexTextures;\n\n\tlet precision = capabilities.precision;\n\n\tconst shaderIDs = {\n\t\tMeshDepthMaterial: 'depth',\n\t\tMeshDistanceMaterial: 'distanceRGBA',\n\t\tMeshNormalMaterial: 'normal',\n\t\tMeshBasicMaterial: 'basic',\n\t\tMeshLambertMaterial: 'lambert',\n\t\tMeshPhongMaterial: 'phong',\n\t\tMeshToonMaterial: 'toon',\n\t\tMeshStandardMaterial: 'physical',\n\t\tMeshPhysicalMaterial: 'physical',\n\t\tMeshMatcapMaterial: 'matcap',\n\t\tLineBasicMaterial: 'basic',\n\t\tLineDashedMaterial: 'dashed',\n\t\tPointsMaterial: 'points',\n\t\tShadowMaterial: 'shadow',\n\t\tSpriteMaterial: 'sprite'\n\t};\n\n\tfunction getChannel( value ) {\n\n\t\t_activeChannels.add( value );\n\n\t\tif ( value === 0 ) return 'uv';\n\n\t\treturn `uv${ value }`;\n\n\t}\n\n\tfunction getParameters( material, lights, shadows, scene, object ) {\n\n\t\tconst fog = scene.fog;\n\t\tconst geometry = object.geometry;\n\t\tconst environment = material.isMeshStandardMaterial ? scene.environment : null;\n\n\t\tconst envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );\n\t\tconst envMapCubeUVHeight = ( !! envMap ) && ( envMap.mapping === CubeUVReflectionMapping ) ? envMap.image.height : null;\n\n\t\tconst shaderID = shaderIDs[ material.type ];\n\n\t\t// heuristics to create shader parameters according to lights in the scene\n\t\t// (not to blow over maxLights budget)\n\n\t\tif ( material.precision !== null ) {\n\n\t\t\tprecision = capabilities.getMaxPrecision( material.precision );\n\n\t\t\tif ( precision !== material.precision ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLProgram.getParameters:', material.precision, 'not supported, using', precision, 'instead.' );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tconst morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;\n\t\tconst morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;\n\n\t\tlet morphTextureStride = 0;\n\n\t\tif ( geometry.morphAttributes.position !== undefined ) morphTextureStride = 1;\n\t\tif ( geometry.morphAttributes.normal !== undefined ) morphTextureStride = 2;\n\t\tif ( geometry.morphAttributes.color !== undefined ) morphTextureStride = 3;\n\n\t\t//\n\n\t\tlet vertexShader, fragmentShader;\n\t\tlet customVertexShaderID, customFragmentShaderID;\n\n\t\tif ( shaderID ) {\n\n\t\t\tconst shader = ShaderLib[ shaderID ];\n\n\t\t\tvertexShader = shader.vertexShader;\n\t\t\tfragmentShader = shader.fragmentShader;\n\n\t\t} else {\n\n\t\t\tvertexShader = material.vertexShader;\n\t\t\tfragmentShader = material.fragmentShader;\n\n\t\t\t_customShaders.update( material );\n\n\t\t\tcustomVertexShaderID = _customShaders.getVertexShaderID( material );\n\t\t\tcustomFragmentShaderID = _customShaders.getFragmentShaderID( material );\n\n\t\t}\n\n\t\tconst currentRenderTarget = renderer.getRenderTarget();\n\n\t\tconst IS_INSTANCEDMESH = object.isInstancedMesh === true;\n\t\tconst IS_BATCHEDMESH = object.isBatchedMesh === true;\n\n\t\tconst HAS_MAP = !! material.map;\n\t\tconst HAS_MATCAP = !! material.matcap;\n\t\tconst HAS_ENVMAP = !! envMap;\n\t\tconst HAS_AOMAP = !! material.aoMap;\n\t\tconst HAS_LIGHTMAP = !! material.lightMap;\n\t\tconst HAS_BUMPMAP = !! material.bumpMap;\n\t\tconst HAS_NORMALMAP = !! material.normalMap;\n\t\tconst HAS_DISPLACEMENTMAP = !! material.displacementMap;\n\t\tconst HAS_EMISSIVEMAP = !! material.emissiveMap;\n\n\t\tconst HAS_METALNESSMAP = !! material.metalnessMap;\n\t\tconst HAS_ROUGHNESSMAP = !! material.roughnessMap;\n\n\t\tconst HAS_ANISOTROPY = material.anisotropy > 0;\n\t\tconst HAS_CLEARCOAT = material.clearcoat > 0;\n\t\tconst HAS_DISPERSION = material.dispersion > 0;\n\t\tconst HAS_IRIDESCENCE = material.iridescence > 0;\n\t\tconst HAS_SHEEN = material.sheen > 0;\n\t\tconst HAS_TRANSMISSION = material.transmission > 0;\n\n\t\tconst HAS_ANISOTROPYMAP = HAS_ANISOTROPY && !! material.anisotropyMap;\n\n\t\tconst HAS_CLEARCOATMAP = HAS_CLEARCOAT && !! material.clearcoatMap;\n\t\tconst HAS_CLEARCOAT_NORMALMAP = HAS_CLEARCOAT && !! material.clearcoatNormalMap;\n\t\tconst HAS_CLEARCOAT_ROUGHNESSMAP = HAS_CLEARCOAT && !! material.clearcoatRoughnessMap;\n\n\t\tconst HAS_IRIDESCENCEMAP = HAS_IRIDESCENCE && !! material.iridescenceMap;\n\t\tconst HAS_IRIDESCENCE_THICKNESSMAP = HAS_IRIDESCENCE && !! material.iridescenceThicknessMap;\n\n\t\tconst HAS_SHEEN_COLORMAP = HAS_SHEEN && !! material.sheenColorMap;\n\t\tconst HAS_SHEEN_ROUGHNESSMAP = HAS_SHEEN && !! material.sheenRoughnessMap;\n\n\t\tconst HAS_SPECULARMAP = !! material.specularMap;\n\t\tconst HAS_SPECULAR_COLORMAP = !! material.specularColorMap;\n\t\tconst HAS_SPECULAR_INTENSITYMAP = !! material.specularIntensityMap;\n\n\t\tconst HAS_TRANSMISSIONMAP = HAS_TRANSMISSION && !! material.transmissionMap;\n\t\tconst HAS_THICKNESSMAP = HAS_TRANSMISSION && !! material.thicknessMap;\n\n\t\tconst HAS_GRADIENTMAP = !! material.gradientMap;\n\n\t\tconst HAS_ALPHAMAP = !! material.alphaMap;\n\n\t\tconst HAS_ALPHATEST = material.alphaTest > 0;\n\n\t\tconst HAS_ALPHAHASH = !! material.alphaHash;\n\n\t\tconst HAS_EXTENSIONS = !! material.extensions;\n\n\t\tlet toneMapping = NoToneMapping;\n\n\t\tif ( material.toneMapped ) {\n\n\t\t\tif ( currentRenderTarget === null || currentRenderTarget.isXRRenderTarget === true ) {\n\n\t\t\t\ttoneMapping = renderer.toneMapping;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst parameters = {\n\n\t\t\tshaderID: shaderID,\n\t\t\tshaderType: material.type,\n\t\t\tshaderName: material.name,\n\n\t\t\tvertexShader: vertexShader,\n\t\t\tfragmentShader: fragmentShader,\n\t\t\tdefines: material.defines,\n\n\t\t\tcustomVertexShaderID: customVertexShaderID,\n\t\t\tcustomFragmentShaderID: customFragmentShaderID,\n\n\t\t\tisRawShaderMaterial: material.isRawShaderMaterial === true,\n\t\t\tglslVersion: material.glslVersion,\n\n\t\t\tprecision: precision,\n\n\t\t\tbatching: IS_BATCHEDMESH,\n\t\t\tbatchingColor: IS_BATCHEDMESH && object._colorsTexture !== null,\n\t\t\tinstancing: IS_INSTANCEDMESH,\n\t\t\tinstancingColor: IS_INSTANCEDMESH && object.instanceColor !== null,\n\t\t\tinstancingMorph: IS_INSTANCEDMESH && object.morphTexture !== null,\n\n\t\t\tsupportsVertexTextures: SUPPORTS_VERTEX_TEXTURES,\n\t\t\toutputColorSpace: ( currentRenderTarget === null ) ? renderer.outputColorSpace : ( currentRenderTarget.isXRRenderTarget === true ? currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace ),\n\t\t\talphaToCoverage: !! material.alphaToCoverage,\n\n\t\t\tmap: HAS_MAP,\n\t\t\tmatcap: HAS_MATCAP,\n\t\t\tenvMap: HAS_ENVMAP,\n\t\t\tenvMapMode: HAS_ENVMAP && envMap.mapping,\n\t\t\tenvMapCubeUVHeight: envMapCubeUVHeight,\n\t\t\taoMap: HAS_AOMAP,\n\t\t\tlightMap: HAS_LIGHTMAP,\n\t\t\tbumpMap: HAS_BUMPMAP,\n\t\t\tnormalMap: HAS_NORMALMAP,\n\t\t\tdisplacementMap: SUPPORTS_VERTEX_TEXTURES && HAS_DISPLACEMENTMAP,\n\t\t\temissiveMap: HAS_EMISSIVEMAP,\n\n\t\t\tnormalMapObjectSpace: HAS_NORMALMAP && material.normalMapType === ObjectSpaceNormalMap,\n\t\t\tnormalMapTangentSpace: HAS_NORMALMAP && material.normalMapType === TangentSpaceNormalMap,\n\n\t\t\tmetalnessMap: HAS_METALNESSMAP,\n\t\t\troughnessMap: HAS_ROUGHNESSMAP,\n\n\t\t\tanisotropy: HAS_ANISOTROPY,\n\t\t\tanisotropyMap: HAS_ANISOTROPYMAP,\n\n\t\t\tclearcoat: HAS_CLEARCOAT,\n\t\t\tclearcoatMap: HAS_CLEARCOATMAP,\n\t\t\tclearcoatNormalMap: HAS_CLEARCOAT_NORMALMAP,\n\t\t\tclearcoatRoughnessMap: HAS_CLEARCOAT_ROUGHNESSMAP,\n\n\t\t\tdispersion: HAS_DISPERSION,\n\n\t\t\tiridescence: HAS_IRIDESCENCE,\n\t\t\tiridescenceMap: HAS_IRIDESCENCEMAP,\n\t\t\tiridescenceThicknessMap: HAS_IRIDESCENCE_THICKNESSMAP,\n\n\t\t\tsheen: HAS_SHEEN,\n\t\t\tsheenColorMap: HAS_SHEEN_COLORMAP,\n\t\t\tsheenRoughnessMap: HAS_SHEEN_ROUGHNESSMAP,\n\n\t\t\tspecularMap: HAS_SPECULARMAP,\n\t\t\tspecularColorMap: HAS_SPECULAR_COLORMAP,\n\t\t\tspecularIntensityMap: HAS_SPECULAR_INTENSITYMAP,\n\n\t\t\ttransmission: HAS_TRANSMISSION,\n\t\t\ttransmissionMap: HAS_TRANSMISSIONMAP,\n\t\t\tthicknessMap: HAS_THICKNESSMAP,\n\n\t\t\tgradientMap: HAS_GRADIENTMAP,\n\n\t\t\topaque: material.transparent === false && material.blending === NormalBlending && material.alphaToCoverage === false,\n\n\t\t\talphaMap: HAS_ALPHAMAP,\n\t\t\talphaTest: HAS_ALPHATEST,\n\t\t\talphaHash: HAS_ALPHAHASH,\n\n\t\t\tcombine: material.combine,\n\n\t\t\t//\n\n\t\t\tmapUv: HAS_MAP && getChannel( material.map.channel ),\n\t\t\taoMapUv: HAS_AOMAP && getChannel( material.aoMap.channel ),\n\t\t\tlightMapUv: HAS_LIGHTMAP && getChannel( material.lightMap.channel ),\n\t\t\tbumpMapUv: HAS_BUMPMAP && getChannel( material.bumpMap.channel ),\n\t\t\tnormalMapUv: HAS_NORMALMAP && getChannel( material.normalMap.channel ),\n\t\t\tdisplacementMapUv: HAS_DISPLACEMENTMAP && getChannel( material.displacementMap.channel ),\n\t\t\temissiveMapUv: HAS_EMISSIVEMAP && getChannel( material.emissiveMap.channel ),\n\n\t\t\tmetalnessMapUv: HAS_METALNESSMAP && getChannel( material.metalnessMap.channel ),\n\t\t\troughnessMapUv: HAS_ROUGHNESSMAP && getChannel( material.roughnessMap.channel ),\n\n\t\t\tanisotropyMapUv: HAS_ANISOTROPYMAP && getChannel( material.anisotropyMap.channel ),\n\n\t\t\tclearcoatMapUv: HAS_CLEARCOATMAP && getChannel( material.clearcoatMap.channel ),\n\t\t\tclearcoatNormalMapUv: HAS_CLEARCOAT_NORMALMAP && getChannel( material.clearcoatNormalMap.channel ),\n\t\t\tclearcoatRoughnessMapUv: HAS_CLEARCOAT_ROUGHNESSMAP && getChannel( material.clearcoatRoughnessMap.channel ),\n\n\t\t\tiridescenceMapUv: HAS_IRIDESCENCEMAP && getChannel( material.iridescenceMap.channel ),\n\t\t\tiridescenceThicknessMapUv: HAS_IRIDESCENCE_THICKNESSMAP && getChannel( material.iridescenceThicknessMap.channel ),\n\n\t\t\tsheenColorMapUv: HAS_SHEEN_COLORMAP && getChannel( material.sheenColorMap.channel ),\n\t\t\tsheenRoughnessMapUv: HAS_SHEEN_ROUGHNESSMAP && getChannel( material.sheenRoughnessMap.channel ),\n\n\t\t\tspecularMapUv: HAS_SPECULARMAP && getChannel( material.specularMap.channel ),\n\t\t\tspecularColorMapUv: HAS_SPECULAR_COLORMAP && getChannel( material.specularColorMap.channel ),\n\t\t\tspecularIntensityMapUv: HAS_SPECULAR_INTENSITYMAP && getChannel( material.specularIntensityMap.channel ),\n\n\t\t\ttransmissionMapUv: HAS_TRANSMISSIONMAP && getChannel( material.transmissionMap.channel ),\n\t\t\tthicknessMapUv: HAS_THICKNESSMAP && getChannel( material.thicknessMap.channel ),\n\n\t\t\talphaMapUv: HAS_ALPHAMAP && getChannel( material.alphaMap.channel ),\n\n\t\t\t//\n\n\t\t\tvertexTangents: !! geometry.attributes.tangent && ( HAS_NORMALMAP || HAS_ANISOTROPY ),\n\t\t\tvertexColors: material.vertexColors,\n\t\t\tvertexAlphas: material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4,\n\n\t\t\tpointsUvs: object.isPoints === true && !! geometry.attributes.uv && ( HAS_MAP || HAS_ALPHAMAP ),\n\n\t\t\tfog: !! fog,\n\t\t\tuseFog: material.fog === true,\n\t\t\tfogExp2: ( !! fog && fog.isFogExp2 ),\n\n\t\t\tflatShading: material.flatShading === true,\n\n\t\t\tsizeAttenuation: material.sizeAttenuation === true,\n\t\t\tlogarithmicDepthBuffer: logarithmicDepthBuffer,\n\n\t\t\tskinning: object.isSkinnedMesh === true,\n\n\t\t\tmorphTargets: geometry.morphAttributes.position !== undefined,\n\t\t\tmorphNormals: geometry.morphAttributes.normal !== undefined,\n\t\t\tmorphColors: geometry.morphAttributes.color !== undefined,\n\t\t\tmorphTargetsCount: morphTargetsCount,\n\t\t\tmorphTextureStride: morphTextureStride,\n\n\t\t\tnumDirLights: lights.directional.length,\n\t\t\tnumPointLights: lights.point.length,\n\t\t\tnumSpotLights: lights.spot.length,\n\t\t\tnumSpotLightMaps: lights.spotLightMap.length,\n\t\t\tnumRectAreaLights: lights.rectArea.length,\n\t\t\tnumHemiLights: lights.hemi.length,\n\n\t\t\tnumDirLightShadows: lights.directionalShadowMap.length,\n\t\t\tnumPointLightShadows: lights.pointShadowMap.length,\n\t\t\tnumSpotLightShadows: lights.spotShadowMap.length,\n\t\t\tnumSpotLightShadowsWithMaps: lights.numSpotLightShadowsWithMaps,\n\n\t\t\tnumLightProbes: lights.numLightProbes,\n\n\t\t\tnumClippingPlanes: clipping.numPlanes,\n\t\t\tnumClipIntersection: clipping.numIntersection,\n\n\t\t\tdithering: material.dithering,\n\n\t\t\tshadowMapEnabled: renderer.shadowMap.enabled && shadows.length > 0,\n\t\t\tshadowMapType: renderer.shadowMap.type,\n\n\t\t\ttoneMapping: toneMapping,\n\n\t\t\tdecodeVideoTexture: HAS_MAP && ( material.map.isVideoTexture === true ) && ( ColorManagement.getTransfer( material.map.colorSpace ) === SRGBTransfer ),\n\n\t\t\tpremultipliedAlpha: material.premultipliedAlpha,\n\n\t\t\tdoubleSided: material.side === DoubleSide,\n\t\t\tflipSided: material.side === BackSide,\n\n\t\t\tuseDepthPacking: material.depthPacking >= 0,\n\t\t\tdepthPacking: material.depthPacking || 0,\n\n\t\t\tindex0AttributeName: material.index0AttributeName,\n\n\t\t\textensionClipCullDistance: HAS_EXTENSIONS && material.extensions.clipCullDistance === true && extensions.has( 'WEBGL_clip_cull_distance' ),\n\t\t\textensionMultiDraw: ( HAS_EXTENSIONS && material.extensions.multiDraw === true || IS_BATCHEDMESH ) && extensions.has( 'WEBGL_multi_draw' ),\n\n\t\t\trendererExtensionParallelShaderCompile: extensions.has( 'KHR_parallel_shader_compile' ),\n\n\t\t\tcustomProgramCacheKey: material.customProgramCacheKey()\n\n\t\t};\n\n\t\t// the usage of getChannel() determines the active texture channels for this shader\n\n\t\tparameters.vertexUv1s = _activeChannels.has( 1 );\n\t\tparameters.vertexUv2s = _activeChannels.has( 2 );\n\t\tparameters.vertexUv3s = _activeChannels.has( 3 );\n\n\t\t_activeChannels.clear();\n\n\t\treturn parameters;\n\n\t}\n\n\tfunction getProgramCacheKey( parameters ) {\n\n\t\tconst array = [];\n\n\t\tif ( parameters.shaderID ) {\n\n\t\t\tarray.push( parameters.shaderID );\n\n\t\t} else {\n\n\t\t\tarray.push( parameters.customVertexShaderID );\n\t\t\tarray.push( parameters.customFragmentShaderID );\n\n\t\t}\n\n\t\tif ( parameters.defines !== undefined ) {\n\n\t\t\tfor ( const name in parameters.defines ) {\n\n\t\t\t\tarray.push( name );\n\t\t\t\tarray.push( parameters.defines[ name ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( parameters.isRawShaderMaterial === false ) {\n\n\t\t\tgetProgramCacheKeyParameters( array, parameters );\n\t\t\tgetProgramCacheKeyBooleans( array, parameters );\n\t\t\tarray.push( renderer.outputColorSpace );\n\n\t\t}\n\n\t\tarray.push( parameters.customProgramCacheKey );\n\n\t\treturn array.join();\n\n\t}\n\n\tfunction getProgramCacheKeyParameters( array, parameters ) {\n\n\t\tarray.push( parameters.precision );\n\t\tarray.push( parameters.outputColorSpace );\n\t\tarray.push( parameters.envMapMode );\n\t\tarray.push( parameters.envMapCubeUVHeight );\n\t\tarray.push( parameters.mapUv );\n\t\tarray.push( parameters.alphaMapUv );\n\t\tarray.push( parameters.lightMapUv );\n\t\tarray.push( parameters.aoMapUv );\n\t\tarray.push( parameters.bumpMapUv );\n\t\tarray.push( parameters.normalMapUv );\n\t\tarray.push( parameters.displacementMapUv );\n\t\tarray.push( parameters.emissiveMapUv );\n\t\tarray.push( parameters.metalnessMapUv );\n\t\tarray.push( parameters.roughnessMapUv );\n\t\tarray.push( parameters.anisotropyMapUv );\n\t\tarray.push( parameters.clearcoatMapUv );\n\t\tarray.push( parameters.clearcoatNormalMapUv );\n\t\tarray.push( parameters.clearcoatRoughnessMapUv );\n\t\tarray.push( parameters.iridescenceMapUv );\n\t\tarray.push( parameters.iridescenceThicknessMapUv );\n\t\tarray.push( parameters.sheenColorMapUv );\n\t\tarray.push( parameters.sheenRoughnessMapUv );\n\t\tarray.push( parameters.specularMapUv );\n\t\tarray.push( parameters.specularColorMapUv );\n\t\tarray.push( parameters.specularIntensityMapUv );\n\t\tarray.push( parameters.transmissionMapUv );\n\t\tarray.push( parameters.thicknessMapUv );\n\t\tarray.push( parameters.combine );\n\t\tarray.push( parameters.fogExp2 );\n\t\tarray.push( parameters.sizeAttenuation );\n\t\tarray.push( parameters.morphTargetsCount );\n\t\tarray.push( parameters.morphAttributeCount );\n\t\tarray.push( parameters.numDirLights );\n\t\tarray.push( parameters.numPointLights );\n\t\tarray.push( parameters.numSpotLights );\n\t\tarray.push( parameters.numSpotLightMaps );\n\t\tarray.push( parameters.numHemiLights );\n\t\tarray.push( parameters.numRectAreaLights );\n\t\tarray.push( parameters.numDirLightShadows );\n\t\tarray.push( parameters.numPointLightShadows );\n\t\tarray.push( parameters.numSpotLightShadows );\n\t\tarray.push( parameters.numSpotLightShadowsWithMaps );\n\t\tarray.push( parameters.numLightProbes );\n\t\tarray.push( parameters.shadowMapType );\n\t\tarray.push( parameters.toneMapping );\n\t\tarray.push( parameters.numClippingPlanes );\n\t\tarray.push( parameters.numClipIntersection );\n\t\tarray.push( parameters.depthPacking );\n\n\t}\n\n\tfunction getProgramCacheKeyBooleans( array, parameters ) {\n\n\t\t_programLayers.disableAll();\n\n\t\tif ( parameters.supportsVertexTextures )\n\t\t\t_programLayers.enable( 0 );\n\t\tif ( parameters.instancing )\n\t\t\t_programLayers.enable( 1 );\n\t\tif ( parameters.instancingColor )\n\t\t\t_programLayers.enable( 2 );\n\t\tif ( parameters.instancingMorph )\n\t\t\t_programLayers.enable( 3 );\n\t\tif ( parameters.matcap )\n\t\t\t_programLayers.enable( 4 );\n\t\tif ( parameters.envMap )\n\t\t\t_programLayers.enable( 5 );\n\t\tif ( parameters.normalMapObjectSpace )\n\t\t\t_programLayers.enable( 6 );\n\t\tif ( parameters.normalMapTangentSpace )\n\t\t\t_programLayers.enable( 7 );\n\t\tif ( parameters.clearcoat )\n\t\t\t_programLayers.enable( 8 );\n\t\tif ( parameters.iridescence )\n\t\t\t_programLayers.enable( 9 );\n\t\tif ( parameters.alphaTest )\n\t\t\t_programLayers.enable( 10 );\n\t\tif ( parameters.vertexColors )\n\t\t\t_programLayers.enable( 11 );\n\t\tif ( parameters.vertexAlphas )\n\t\t\t_programLayers.enable( 12 );\n\t\tif ( parameters.vertexUv1s )\n\t\t\t_programLayers.enable( 13 );\n\t\tif ( parameters.vertexUv2s )\n\t\t\t_programLayers.enable( 14 );\n\t\tif ( parameters.vertexUv3s )\n\t\t\t_programLayers.enable( 15 );\n\t\tif ( parameters.vertexTangents )\n\t\t\t_programLayers.enable( 16 );\n\t\tif ( parameters.anisotropy )\n\t\t\t_programLayers.enable( 17 );\n\t\tif ( parameters.alphaHash )\n\t\t\t_programLayers.enable( 18 );\n\t\tif ( parameters.batching )\n\t\t\t_programLayers.enable( 19 );\n\t\tif ( parameters.dispersion )\n\t\t\t_programLayers.enable( 20 );\n\t\tif ( parameters.batchingColor )\n\t\t\t_programLayers.enable( 21 );\n\n\t\tarray.push( _programLayers.mask );\n\t\t_programLayers.disableAll();\n\n\t\tif ( parameters.fog )\n\t\t\t_programLayers.enable( 0 );\n\t\tif ( parameters.useFog )\n\t\t\t_programLayers.enable( 1 );\n\t\tif ( parameters.flatShading )\n\t\t\t_programLayers.enable( 2 );\n\t\tif ( parameters.logarithmicDepthBuffer )\n\t\t\t_programLayers.enable( 3 );\n\t\tif ( parameters.skinning )\n\t\t\t_programLayers.enable( 4 );\n\t\tif ( parameters.morphTargets )\n\t\t\t_programLayers.enable( 5 );\n\t\tif ( parameters.morphNormals )\n\t\t\t_programLayers.enable( 6 );\n\t\tif ( parameters.morphColors )\n\t\t\t_programLayers.enable( 7 );\n\t\tif ( parameters.premultipliedAlpha )\n\t\t\t_programLayers.enable( 8 );\n\t\tif ( parameters.shadowMapEnabled )\n\t\t\t_programLayers.enable( 9 );\n\t\tif ( parameters.doubleSided )\n\t\t\t_programLayers.enable( 10 );\n\t\tif ( parameters.flipSided )\n\t\t\t_programLayers.enable( 11 );\n\t\tif ( parameters.useDepthPacking )\n\t\t\t_programLayers.enable( 12 );\n\t\tif ( parameters.dithering )\n\t\t\t_programLayers.enable( 13 );\n\t\tif ( parameters.transmission )\n\t\t\t_programLayers.enable( 14 );\n\t\tif ( parameters.sheen )\n\t\t\t_programLayers.enable( 15 );\n\t\tif ( parameters.opaque )\n\t\t\t_programLayers.enable( 16 );\n\t\tif ( parameters.pointsUvs )\n\t\t\t_programLayers.enable( 17 );\n\t\tif ( parameters.decodeVideoTexture )\n\t\t\t_programLayers.enable( 18 );\n\t\tif ( parameters.alphaToCoverage )\n\t\t\t_programLayers.enable( 19 );\n\n\t\tarray.push( _programLayers.mask );\n\n\t}\n\n\tfunction getUniforms( material ) {\n\n\t\tconst shaderID = shaderIDs[ material.type ];\n\t\tlet uniforms;\n\n\t\tif ( shaderID ) {\n\n\t\t\tconst shader = ShaderLib[ shaderID ];\n\t\t\tuniforms = UniformsUtils.clone( shader.uniforms );\n\n\t\t} else {\n\n\t\t\tuniforms = material.uniforms;\n\n\t\t}\n\n\t\treturn uniforms;\n\n\t}\n\n\tfunction acquireProgram( parameters, cacheKey ) {\n\n\t\tlet program;\n\n\t\t// Check if code has been already compiled\n\t\tfor ( let p = 0, pl = programs.length; p < pl; p ++ ) {\n\n\t\t\tconst preexistingProgram = programs[ p ];\n\n\t\t\tif ( preexistingProgram.cacheKey === cacheKey ) {\n\n\t\t\t\tprogram = preexistingProgram;\n\t\t\t\t++ program.usedTimes;\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( program === undefined ) {\n\n\t\t\tprogram = new WebGLProgram( renderer, cacheKey, parameters, bindingStates );\n\t\t\tprograms.push( program );\n\n\t\t}\n\n\t\treturn program;\n\n\t}\n\n\tfunction releaseProgram( program ) {\n\n\t\tif ( -- program.usedTimes === 0 ) {\n\n\t\t\t// Remove from unordered set\n\t\t\tconst i = programs.indexOf( program );\n\t\t\tprograms[ i ] = programs[ programs.length - 1 ];\n\t\t\tprograms.pop();\n\n\t\t\t// Free WebGL resources\n\t\t\tprogram.destroy();\n\n\t\t}\n\n\t}\n\n\tfunction releaseShaderCache( material ) {\n\n\t\t_customShaders.remove( material );\n\n\t}\n\n\tfunction dispose() {\n\n\t\t_customShaders.dispose();\n\n\t}\n\n\treturn {\n\t\tgetParameters: getParameters,\n\t\tgetProgramCacheKey: getProgramCacheKey,\n\t\tgetUniforms: getUniforms,\n\t\tacquireProgram: acquireProgram,\n\t\treleaseProgram: releaseProgram,\n\t\treleaseShaderCache: releaseShaderCache,\n\t\t// Exposed for resource monitoring & error feedback via renderer.info:\n\t\tprograms: programs,\n\t\tdispose: dispose\n\t};\n\n}\n\nfunction WebGLProperties() {\n\n\tlet properties = new WeakMap();\n\n\tfunction get( object ) {\n\n\t\tlet map = properties.get( object );\n\n\t\tif ( map === undefined ) {\n\n\t\t\tmap = {};\n\t\t\tproperties.set( object, map );\n\n\t\t}\n\n\t\treturn map;\n\n\t}\n\n\tfunction remove( object ) {\n\n\t\tproperties.delete( object );\n\n\t}\n\n\tfunction update( object, key, value ) {\n\n\t\tproperties.get( object )[ key ] = value;\n\n\t}\n\n\tfunction dispose() {\n\n\t\tproperties = new WeakMap();\n\n\t}\n\n\treturn {\n\t\tget: get,\n\t\tremove: remove,\n\t\tupdate: update,\n\t\tdispose: dispose\n\t};\n\n}\n\nfunction painterSortStable( a, b ) {\n\n\tif ( a.groupOrder !== b.groupOrder ) {\n\n\t\treturn a.groupOrder - b.groupOrder;\n\n\t} else if ( a.renderOrder !== b.renderOrder ) {\n\n\t\treturn a.renderOrder - b.renderOrder;\n\n\t} else if ( a.material.id !== b.material.id ) {\n\n\t\treturn a.material.id - b.material.id;\n\n\t} else if ( a.z !== b.z ) {\n\n\t\treturn a.z - b.z;\n\n\t} else {\n\n\t\treturn a.id - b.id;\n\n\t}\n\n}\n\nfunction reversePainterSortStable( a, b ) {\n\n\tif ( a.groupOrder !== b.groupOrder ) {\n\n\t\treturn a.groupOrder - b.groupOrder;\n\n\t} else if ( a.renderOrder !== b.renderOrder ) {\n\n\t\treturn a.renderOrder - b.renderOrder;\n\n\t} else if ( a.z !== b.z ) {\n\n\t\treturn b.z - a.z;\n\n\t} else {\n\n\t\treturn a.id - b.id;\n\n\t}\n\n}\n\n\nfunction WebGLRenderList() {\n\n\tconst renderItems = [];\n\tlet renderItemsIndex = 0;\n\n\tconst opaque = [];\n\tconst transmissive = [];\n\tconst transparent = [];\n\n\tfunction init() {\n\n\t\trenderItemsIndex = 0;\n\n\t\topaque.length = 0;\n\t\ttransmissive.length = 0;\n\t\ttransparent.length = 0;\n\n\t}\n\n\tfunction getNextRenderItem( object, geometry, material, groupOrder, z, group ) {\n\n\t\tlet renderItem = renderItems[ renderItemsIndex ];\n\n\t\tif ( renderItem === undefined ) {\n\n\t\t\trenderItem = {\n\t\t\t\tid: object.id,\n\t\t\t\tobject: object,\n\t\t\t\tgeometry: geometry,\n\t\t\t\tmaterial: material,\n\t\t\t\tgroupOrder: groupOrder,\n\t\t\t\trenderOrder: object.renderOrder,\n\t\t\t\tz: z,\n\t\t\t\tgroup: group\n\t\t\t};\n\n\t\t\trenderItems[ renderItemsIndex ] = renderItem;\n\n\t\t} else {\n\n\t\t\trenderItem.id = object.id;\n\t\t\trenderItem.object = object;\n\t\t\trenderItem.geometry = geometry;\n\t\t\trenderItem.material = material;\n\t\t\trenderItem.groupOrder = groupOrder;\n\t\t\trenderItem.renderOrder = object.renderOrder;\n\t\t\trenderItem.z = z;\n\t\t\trenderItem.group = group;\n\n\t\t}\n\n\t\trenderItemsIndex ++;\n\n\t\treturn renderItem;\n\n\t}\n\n\tfunction push( object, geometry, material, groupOrder, z, group ) {\n\n\t\tconst renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );\n\n\t\tif ( material.transmission > 0.0 ) {\n\n\t\t\ttransmissive.push( renderItem );\n\n\t\t} else if ( material.transparent === true ) {\n\n\t\t\ttransparent.push( renderItem );\n\n\t\t} else {\n\n\t\t\topaque.push( renderItem );\n\n\t\t}\n\n\t}\n\n\tfunction unshift( object, geometry, material, groupOrder, z, group ) {\n\n\t\tconst renderItem = getNextRenderItem( object, geometry, material, groupOrder, z, group );\n\n\t\tif ( material.transmission > 0.0 ) {\n\n\t\t\ttransmissive.unshift( renderItem );\n\n\t\t} else if ( material.transparent === true ) {\n\n\t\t\ttransparent.unshift( renderItem );\n\n\t\t} else {\n\n\t\t\topaque.unshift( renderItem );\n\n\t\t}\n\n\t}\n\n\tfunction sort( customOpaqueSort, customTransparentSort ) {\n\n\t\tif ( opaque.length > 1 ) opaque.sort( customOpaqueSort || painterSortStable );\n\t\tif ( transmissive.length > 1 ) transmissive.sort( customTransparentSort || reversePainterSortStable );\n\t\tif ( transparent.length > 1 ) transparent.sort( customTransparentSort || reversePainterSortStable );\n\n\t}\n\n\tfunction finish() {\n\n\t\t// Clear references from inactive renderItems in the list\n\n\t\tfor ( let i = renderItemsIndex, il = renderItems.length; i < il; i ++ ) {\n\n\t\t\tconst renderItem = renderItems[ i ];\n\n\t\t\tif ( renderItem.id === null ) break;\n\n\t\t\trenderItem.id = null;\n\t\t\trenderItem.object = null;\n\t\t\trenderItem.geometry = null;\n\t\t\trenderItem.material = null;\n\t\t\trenderItem.group = null;\n\n\t\t}\n\n\t}\n\n\treturn {\n\n\t\topaque: opaque,\n\t\ttransmissive: transmissive,\n\t\ttransparent: transparent,\n\n\t\tinit: init,\n\t\tpush: push,\n\t\tunshift: unshift,\n\t\tfinish: finish,\n\n\t\tsort: sort\n\t};\n\n}\n\nfunction WebGLRenderLists() {\n\n\tlet lists = new WeakMap();\n\n\tfunction get( scene, renderCallDepth ) {\n\n\t\tconst listArray = lists.get( scene );\n\t\tlet list;\n\n\t\tif ( listArray === undefined ) {\n\n\t\t\tlist = new WebGLRenderList();\n\t\t\tlists.set( scene, [ list ] );\n\n\t\t} else {\n\n\t\t\tif ( renderCallDepth >= listArray.length ) {\n\n\t\t\t\tlist = new WebGLRenderList();\n\t\t\t\tlistArray.push( list );\n\n\t\t\t} else {\n\n\t\t\t\tlist = listArray[ renderCallDepth ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn list;\n\n\t}\n\n\tfunction dispose() {\n\n\t\tlists = new WeakMap();\n\n\t}\n\n\treturn {\n\t\tget: get,\n\t\tdispose: dispose\n\t};\n\n}\n\nfunction UniformsCache() {\n\n\tconst lights = {};\n\n\treturn {\n\n\t\tget: function ( light ) {\n\n\t\t\tif ( lights[ light.id ] !== undefined ) {\n\n\t\t\t\treturn lights[ light.id ];\n\n\t\t\t}\n\n\t\t\tlet uniforms;\n\n\t\t\tswitch ( light.type ) {\n\n\t\t\t\tcase 'DirectionalLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\tcolor: new Color()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'SpotLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\tdistance: 0,\n\t\t\t\t\t\tconeCos: 0,\n\t\t\t\t\t\tpenumbraCos: 0,\n\t\t\t\t\t\tdecay: 0\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'PointLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\tdistance: 0,\n\t\t\t\t\t\tdecay: 0\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'HemisphereLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tdirection: new Vector3(),\n\t\t\t\t\t\tskyColor: new Color(),\n\t\t\t\t\t\tgroundColor: new Color()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'RectAreaLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tcolor: new Color(),\n\t\t\t\t\t\tposition: new Vector3(),\n\t\t\t\t\t\thalfWidth: new Vector3(),\n\t\t\t\t\t\thalfHeight: new Vector3()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tlights[ light.id ] = uniforms;\n\n\t\t\treturn uniforms;\n\n\t\t}\n\n\t};\n\n}\n\nfunction ShadowUniformsCache() {\n\n\tconst lights = {};\n\n\treturn {\n\n\t\tget: function ( light ) {\n\n\t\t\tif ( lights[ light.id ] !== undefined ) {\n\n\t\t\t\treturn lights[ light.id ];\n\n\t\t\t}\n\n\t\t\tlet uniforms;\n\n\t\t\tswitch ( light.type ) {\n\n\t\t\t\tcase 'DirectionalLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tshadowIntensity: 1,\n\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\tshadowNormalBias: 0,\n\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\tshadowMapSize: new Vector2()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'SpotLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tshadowIntensity: 1,\n\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\tshadowNormalBias: 0,\n\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\tshadowMapSize: new Vector2()\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'PointLight':\n\t\t\t\t\tuniforms = {\n\t\t\t\t\t\tshadowIntensity: 1,\n\t\t\t\t\t\tshadowBias: 0,\n\t\t\t\t\t\tshadowNormalBias: 0,\n\t\t\t\t\t\tshadowRadius: 1,\n\t\t\t\t\t\tshadowMapSize: new Vector2(),\n\t\t\t\t\t\tshadowCameraNear: 1,\n\t\t\t\t\t\tshadowCameraFar: 1000\n\t\t\t\t\t};\n\t\t\t\t\tbreak;\n\n\t\t\t\t// TODO (abelnation): set RectAreaLight shadow uniforms\n\n\t\t\t}\n\n\t\t\tlights[ light.id ] = uniforms;\n\n\t\t\treturn uniforms;\n\n\t\t}\n\n\t};\n\n}\n\n\n\nlet nextVersion = 0;\n\nfunction shadowCastingAndTexturingLightsFirst( lightA, lightB ) {\n\n\treturn ( lightB.castShadow ? 2 : 0 ) - ( lightA.castShadow ? 2 : 0 ) + ( lightB.map ? 1 : 0 ) - ( lightA.map ? 1 : 0 );\n\n}\n\nfunction WebGLLights( extensions ) {\n\n\tconst cache = new UniformsCache();\n\n\tconst shadowCache = ShadowUniformsCache();\n\n\tconst state = {\n\n\t\tversion: 0,\n\n\t\thash: {\n\t\t\tdirectionalLength: - 1,\n\t\t\tpointLength: - 1,\n\t\t\tspotLength: - 1,\n\t\t\trectAreaLength: - 1,\n\t\t\themiLength: - 1,\n\n\t\t\tnumDirectionalShadows: - 1,\n\t\t\tnumPointShadows: - 1,\n\t\t\tnumSpotShadows: - 1,\n\t\t\tnumSpotMaps: - 1,\n\n\t\t\tnumLightProbes: - 1\n\t\t},\n\n\t\tambient: [ 0, 0, 0 ],\n\t\tprobe: [],\n\t\tdirectional: [],\n\t\tdirectionalShadow: [],\n\t\tdirectionalShadowMap: [],\n\t\tdirectionalShadowMatrix: [],\n\t\tspot: [],\n\t\tspotLightMap: [],\n\t\tspotShadow: [],\n\t\tspotShadowMap: [],\n\t\tspotLightMatrix: [],\n\t\trectArea: [],\n\t\trectAreaLTC1: null,\n\t\trectAreaLTC2: null,\n\t\tpoint: [],\n\t\tpointShadow: [],\n\t\tpointShadowMap: [],\n\t\tpointShadowMatrix: [],\n\t\themi: [],\n\t\tnumSpotLightShadowsWithMaps: 0,\n\t\tnumLightProbes: 0\n\n\t};\n\n\tfor ( let i = 0; i < 9; i ++ ) state.probe.push( new Vector3() );\n\n\tconst vector3 = new Vector3();\n\tconst matrix4 = new Matrix4();\n\tconst matrix42 = new Matrix4();\n\n\tfunction setup( lights ) {\n\n\t\tlet r = 0, g = 0, b = 0;\n\n\t\tfor ( let i = 0; i < 9; i ++ ) state.probe[ i ].set( 0, 0, 0 );\n\n\t\tlet directionalLength = 0;\n\t\tlet pointLength = 0;\n\t\tlet spotLength = 0;\n\t\tlet rectAreaLength = 0;\n\t\tlet hemiLength = 0;\n\n\t\tlet numDirectionalShadows = 0;\n\t\tlet numPointShadows = 0;\n\t\tlet numSpotShadows = 0;\n\t\tlet numSpotMaps = 0;\n\t\tlet numSpotShadowsWithMaps = 0;\n\n\t\tlet numLightProbes = 0;\n\n\t\t// ordering : [shadow casting + map texturing, map texturing, shadow casting, none ]\n\t\tlights.sort( shadowCastingAndTexturingLightsFirst );\n\n\t\tfor ( let i = 0, l = lights.length; i < l; i ++ ) {\n\n\t\t\tconst light = lights[ i ];\n\n\t\t\tconst color = light.color;\n\t\t\tconst intensity = light.intensity;\n\t\t\tconst distance = light.distance;\n\n\t\t\tconst shadowMap = ( light.shadow && light.shadow.map ) ? light.shadow.map.texture : null;\n\n\t\t\tif ( light.isAmbientLight ) {\n\n\t\t\t\tr += color.r * intensity;\n\t\t\t\tg += color.g * intensity;\n\t\t\t\tb += color.b * intensity;\n\n\t\t\t} else if ( light.isLightProbe ) {\n\n\t\t\t\tfor ( let j = 0; j < 9; j ++ ) {\n\n\t\t\t\t\tstate.probe[ j ].addScaledVector( light.sh.coefficients[ j ], intensity );\n\n\t\t\t\t}\n\n\t\t\t\tnumLightProbes ++;\n\n\t\t\t} else if ( light.isDirectionalLight ) {\n\n\t\t\t\tconst uniforms = cache.get( light );\n\n\t\t\t\tuniforms.color.copy( light.color ).multiplyScalar( light.intensity );\n\n\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\tconst shadow = light.shadow;\n\n\t\t\t\t\tconst shadowUniforms = shadowCache.get( light );\n\n\t\t\t\t\tshadowUniforms.shadowIntensity = shadow.intensity;\n\t\t\t\t\tshadowUniforms.shadowBias = shadow.bias;\n\t\t\t\t\tshadowUniforms.shadowNormalBias = shadow.normalBias;\n\t\t\t\t\tshadowUniforms.shadowRadius = shadow.radius;\n\t\t\t\t\tshadowUniforms.shadowMapSize = shadow.mapSize;\n\n\t\t\t\t\tstate.directionalShadow[ directionalLength ] = shadowUniforms;\n\t\t\t\t\tstate.directionalShadowMap[ directionalLength ] = shadowMap;\n\t\t\t\t\tstate.directionalShadowMatrix[ directionalLength ] = light.shadow.matrix;\n\n\t\t\t\t\tnumDirectionalShadows ++;\n\n\t\t\t\t}\n\n\t\t\t\tstate.directional[ directionalLength ] = uniforms;\n\n\t\t\t\tdirectionalLength ++;\n\n\t\t\t} else if ( light.isSpotLight ) {\n\n\t\t\t\tconst uniforms = cache.get( light );\n\n\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\n\t\t\t\tuniforms.color.copy( color ).multiplyScalar( intensity );\n\t\t\t\tuniforms.distance = distance;\n\n\t\t\t\tuniforms.coneCos = Math.cos( light.angle );\n\t\t\t\tuniforms.penumbraCos = Math.cos( light.angle * ( 1 - light.penumbra ) );\n\t\t\t\tuniforms.decay = light.decay;\n\n\t\t\t\tstate.spot[ spotLength ] = uniforms;\n\n\t\t\t\tconst shadow = light.shadow;\n\n\t\t\t\tif ( light.map ) {\n\n\t\t\t\t\tstate.spotLightMap[ numSpotMaps ] = light.map;\n\t\t\t\t\tnumSpotMaps ++;\n\n\t\t\t\t\t// make sure the lightMatrix is up to date\n\t\t\t\t\t// TODO : do it if required only\n\t\t\t\t\tshadow.updateMatrices( light );\n\n\t\t\t\t\tif ( light.castShadow ) numSpotShadowsWithMaps ++;\n\n\t\t\t\t}\n\n\t\t\t\tstate.spotLightMatrix[ spotLength ] = shadow.matrix;\n\n\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\tconst shadowUniforms = shadowCache.get( light );\n\n\t\t\t\t\tshadowUniforms.shadowIntensity = shadow.intensity;\n\t\t\t\t\tshadowUniforms.shadowBias = shadow.bias;\n\t\t\t\t\tshadowUniforms.shadowNormalBias = shadow.normalBias;\n\t\t\t\t\tshadowUniforms.shadowRadius = shadow.radius;\n\t\t\t\t\tshadowUniforms.shadowMapSize = shadow.mapSize;\n\n\t\t\t\t\tstate.spotShadow[ spotLength ] = shadowUniforms;\n\t\t\t\t\tstate.spotShadowMap[ spotLength ] = shadowMap;\n\n\t\t\t\t\tnumSpotShadows ++;\n\n\t\t\t\t}\n\n\t\t\t\tspotLength ++;\n\n\t\t\t} else if ( light.isRectAreaLight ) {\n\n\t\t\t\tconst uniforms = cache.get( light );\n\n\t\t\t\tuniforms.color.copy( color ).multiplyScalar( intensity );\n\n\t\t\t\tuniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );\n\t\t\t\tuniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );\n\n\t\t\t\tstate.rectArea[ rectAreaLength ] = uniforms;\n\n\t\t\t\trectAreaLength ++;\n\n\t\t\t} else if ( light.isPointLight ) {\n\n\t\t\t\tconst uniforms = cache.get( light );\n\n\t\t\t\tuniforms.color.copy( light.color ).multiplyScalar( light.intensity );\n\t\t\t\tuniforms.distance = light.distance;\n\t\t\t\tuniforms.decay = light.decay;\n\n\t\t\t\tif ( light.castShadow ) {\n\n\t\t\t\t\tconst shadow = light.shadow;\n\n\t\t\t\t\tconst shadowUniforms = shadowCache.get( light );\n\n\t\t\t\t\tshadowUniforms.shadowIntensity = shadow.intensity;\n\t\t\t\t\tshadowUniforms.shadowBias = shadow.bias;\n\t\t\t\t\tshadowUniforms.shadowNormalBias = shadow.normalBias;\n\t\t\t\t\tshadowUniforms.shadowRadius = shadow.radius;\n\t\t\t\t\tshadowUniforms.shadowMapSize = shadow.mapSize;\n\t\t\t\t\tshadowUniforms.shadowCameraNear = shadow.camera.near;\n\t\t\t\t\tshadowUniforms.shadowCameraFar = shadow.camera.far;\n\n\t\t\t\t\tstate.pointShadow[ pointLength ] = shadowUniforms;\n\t\t\t\t\tstate.pointShadowMap[ pointLength ] = shadowMap;\n\t\t\t\t\tstate.pointShadowMatrix[ pointLength ] = light.shadow.matrix;\n\n\t\t\t\t\tnumPointShadows ++;\n\n\t\t\t\t}\n\n\t\t\t\tstate.point[ pointLength ] = uniforms;\n\n\t\t\t\tpointLength ++;\n\n\t\t\t} else if ( light.isHemisphereLight ) {\n\n\t\t\t\tconst uniforms = cache.get( light );\n\n\t\t\t\tuniforms.skyColor.copy( light.color ).multiplyScalar( intensity );\n\t\t\t\tuniforms.groundColor.copy( light.groundColor ).multiplyScalar( intensity );\n\n\t\t\t\tstate.hemi[ hemiLength ] = uniforms;\n\n\t\t\t\themiLength ++;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( rectAreaLength > 0 ) {\n\n\t\t\tif ( extensions.has( 'OES_texture_float_linear' ) === true ) {\n\n\t\t\t\tstate.rectAreaLTC1 = UniformsLib.LTC_FLOAT_1;\n\t\t\t\tstate.rectAreaLTC2 = UniformsLib.LTC_FLOAT_2;\n\n\t\t\t} else {\n\n\t\t\t\tstate.rectAreaLTC1 = UniformsLib.LTC_HALF_1;\n\t\t\t\tstate.rectAreaLTC2 = UniformsLib.LTC_HALF_2;\n\n\t\t\t}\n\n\t\t}\n\n\t\tstate.ambient[ 0 ] = r;\n\t\tstate.ambient[ 1 ] = g;\n\t\tstate.ambient[ 2 ] = b;\n\n\t\tconst hash = state.hash;\n\n\t\tif ( hash.directionalLength !== directionalLength ||\n\t\t\thash.pointLength !== pointLength ||\n\t\t\thash.spotLength !== spotLength ||\n\t\t\thash.rectAreaLength !== rectAreaLength ||\n\t\t\thash.hemiLength !== hemiLength ||\n\t\t\thash.numDirectionalShadows !== numDirectionalShadows ||\n\t\t\thash.numPointShadows !== numPointShadows ||\n\t\t\thash.numSpotShadows !== numSpotShadows ||\n\t\t\thash.numSpotMaps !== numSpotMaps ||\n\t\t\thash.numLightProbes !== numLightProbes ) {\n\n\t\t\tstate.directional.length = directionalLength;\n\t\t\tstate.spot.length = spotLength;\n\t\t\tstate.rectArea.length = rectAreaLength;\n\t\t\tstate.point.length = pointLength;\n\t\t\tstate.hemi.length = hemiLength;\n\n\t\t\tstate.directionalShadow.length = numDirectionalShadows;\n\t\t\tstate.directionalShadowMap.length = numDirectionalShadows;\n\t\t\tstate.pointShadow.length = numPointShadows;\n\t\t\tstate.pointShadowMap.length = numPointShadows;\n\t\t\tstate.spotShadow.length = numSpotShadows;\n\t\t\tstate.spotShadowMap.length = numSpotShadows;\n\t\t\tstate.directionalShadowMatrix.length = numDirectionalShadows;\n\t\t\tstate.pointShadowMatrix.length = numPointShadows;\n\t\t\tstate.spotLightMatrix.length = numSpotShadows + numSpotMaps - numSpotShadowsWithMaps;\n\t\t\tstate.spotLightMap.length = numSpotMaps;\n\t\t\tstate.numSpotLightShadowsWithMaps = numSpotShadowsWithMaps;\n\t\t\tstate.numLightProbes = numLightProbes;\n\n\t\t\thash.directionalLength = directionalLength;\n\t\t\thash.pointLength = pointLength;\n\t\t\thash.spotLength = spotLength;\n\t\t\thash.rectAreaLength = rectAreaLength;\n\t\t\thash.hemiLength = hemiLength;\n\n\t\t\thash.numDirectionalShadows = numDirectionalShadows;\n\t\t\thash.numPointShadows = numPointShadows;\n\t\t\thash.numSpotShadows = numSpotShadows;\n\t\t\thash.numSpotMaps = numSpotMaps;\n\n\t\t\thash.numLightProbes = numLightProbes;\n\n\t\t\tstate.version = nextVersion ++;\n\n\t\t}\n\n\t}\n\n\tfunction setupView( lights, camera ) {\n\n\t\tlet directionalLength = 0;\n\t\tlet pointLength = 0;\n\t\tlet spotLength = 0;\n\t\tlet rectAreaLength = 0;\n\t\tlet hemiLength = 0;\n\n\t\tconst viewMatrix = camera.matrixWorldInverse;\n\n\t\tfor ( let i = 0, l = lights.length; i < l; i ++ ) {\n\n\t\t\tconst light = lights[ i ];\n\n\t\t\tif ( light.isDirectionalLight ) {\n\n\t\t\t\tconst uniforms = state.directional[ directionalLength ];\n\n\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tvector3.setFromMatrixPosition( light.target.matrixWorld );\n\t\t\t\tuniforms.direction.sub( vector3 );\n\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\n\t\t\t\tdirectionalLength ++;\n\n\t\t\t} else if ( light.isSpotLight ) {\n\n\t\t\t\tconst uniforms = state.spot[ spotLength ];\n\n\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tvector3.setFromMatrixPosition( light.target.matrixWorld );\n\t\t\t\tuniforms.direction.sub( vector3 );\n\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\n\t\t\t\tspotLength ++;\n\n\t\t\t} else if ( light.isRectAreaLight ) {\n\n\t\t\t\tconst uniforms = state.rectArea[ rectAreaLength ];\n\n\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\t// extract local rotation of light to derive width/height half vectors\n\t\t\t\tmatrix42.identity();\n\t\t\t\tmatrix4.copy( light.matrixWorld );\n\t\t\t\tmatrix4.premultiply( viewMatrix );\n\t\t\t\tmatrix42.extractRotation( matrix4 );\n\n\t\t\t\tuniforms.halfWidth.set( light.width * 0.5, 0.0, 0.0 );\n\t\t\t\tuniforms.halfHeight.set( 0.0, light.height * 0.5, 0.0 );\n\n\t\t\t\tuniforms.halfWidth.applyMatrix4( matrix42 );\n\t\t\t\tuniforms.halfHeight.applyMatrix4( matrix42 );\n\n\t\t\t\trectAreaLength ++;\n\n\t\t\t} else if ( light.isPointLight ) {\n\n\t\t\t\tconst uniforms = state.point[ pointLength ];\n\n\t\t\t\tuniforms.position.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.position.applyMatrix4( viewMatrix );\n\n\t\t\t\tpointLength ++;\n\n\t\t\t} else if ( light.isHemisphereLight ) {\n\n\t\t\t\tconst uniforms = state.hemi[ hemiLength ];\n\n\t\t\t\tuniforms.direction.setFromMatrixPosition( light.matrixWorld );\n\t\t\t\tuniforms.direction.transformDirection( viewMatrix );\n\n\t\t\t\themiLength ++;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\treturn {\n\t\tsetup: setup,\n\t\tsetupView: setupView,\n\t\tstate: state\n\t};\n\n}\n\nfunction WebGLRenderState( extensions ) {\n\n\tconst lights = new WebGLLights( extensions );\n\n\tconst lightsArray = [];\n\tconst shadowsArray = [];\n\n\tfunction init( camera ) {\n\n\t\tstate.camera = camera;\n\n\t\tlightsArray.length = 0;\n\t\tshadowsArray.length = 0;\n\n\t}\n\n\tfunction pushLight( light ) {\n\n\t\tlightsArray.push( light );\n\n\t}\n\n\tfunction pushShadow( shadowLight ) {\n\n\t\tshadowsArray.push( shadowLight );\n\n\t}\n\n\tfunction setupLights() {\n\n\t\tlights.setup( lightsArray );\n\n\t}\n\n\tfunction setupLightsView( camera ) {\n\n\t\tlights.setupView( lightsArray, camera );\n\n\t}\n\n\tconst state = {\n\t\tlightsArray: lightsArray,\n\t\tshadowsArray: shadowsArray,\n\n\t\tcamera: null,\n\n\t\tlights: lights,\n\n\t\ttransmissionRenderTarget: {}\n\t};\n\n\treturn {\n\t\tinit: init,\n\t\tstate: state,\n\t\tsetupLights: setupLights,\n\t\tsetupLightsView: setupLightsView,\n\n\t\tpushLight: pushLight,\n\t\tpushShadow: pushShadow\n\t};\n\n}\n\nfunction WebGLRenderStates( extensions ) {\n\n\tlet renderStates = new WeakMap();\n\n\tfunction get( scene, renderCallDepth = 0 ) {\n\n\t\tconst renderStateArray = renderStates.get( scene );\n\t\tlet renderState;\n\n\t\tif ( renderStateArray === undefined ) {\n\n\t\t\trenderState = new WebGLRenderState( extensions );\n\t\t\trenderStates.set( scene, [ renderState ] );\n\n\t\t} else {\n\n\t\t\tif ( renderCallDepth >= renderStateArray.length ) {\n\n\t\t\t\trenderState = new WebGLRenderState( extensions );\n\t\t\t\trenderStateArray.push( renderState );\n\n\t\t\t} else {\n\n\t\t\t\trenderState = renderStateArray[ renderCallDepth ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn renderState;\n\n\t}\n\n\tfunction dispose() {\n\n\t\trenderStates = new WeakMap();\n\n\t}\n\n\treturn {\n\t\tget: get,\n\t\tdispose: dispose\n\t};\n\n}\n\nclass MeshDepthMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshDepthMaterial = true;\n\n\t\tthis.type = 'MeshDepthMaterial';\n\n\t\tthis.depthPacking = BasicDepthPacking;\n\n\t\tthis.map = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.depthPacking = source.depthPacking;\n\n\t\tthis.map = source.map;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshDistanceMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshDistanceMaterial = true;\n\n\t\tthis.type = 'MeshDistanceMaterial';\n\n\t\tthis.map = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.map = source.map;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst vertex = \"void main() {\\n\\tgl_Position = vec4( position, 1.0 );\\n}\";\n\nconst 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}\";\n\nfunction WebGLShadowMap( renderer, objects, capabilities ) {\n\n\tlet _frustum = new Frustum();\n\n\tconst _shadowMapSize = new Vector2(),\n\t\t_viewportSize = new Vector2(),\n\n\t\t_viewport = new Vector4(),\n\n\t\t_depthMaterial = new MeshDepthMaterial( { depthPacking: RGBADepthPacking } ),\n\t\t_distanceMaterial = new MeshDistanceMaterial(),\n\n\t\t_materialCache = {},\n\n\t\t_maxTextureSize = capabilities.maxTextureSize;\n\n\tconst shadowSide = { [ FrontSide ]: BackSide, [ BackSide ]: FrontSide, [ DoubleSide ]: DoubleSide };\n\n\tconst shadowMaterialVertical = new ShaderMaterial( {\n\t\tdefines: {\n\t\t\tVSM_SAMPLES: 8\n\t\t},\n\t\tuniforms: {\n\t\t\tshadow_pass: { value: null },\n\t\t\tresolution: { value: new Vector2() },\n\t\t\tradius: { value: 4.0 }\n\t\t},\n\n\t\tvertexShader: vertex,\n\t\tfragmentShader: fragment\n\n\t} );\n\n\tconst shadowMaterialHorizontal = shadowMaterialVertical.clone();\n\tshadowMaterialHorizontal.defines.HORIZONTAL_PASS = 1;\n\n\tconst fullScreenTri = new BufferGeometry();\n\tfullScreenTri.setAttribute(\n\t\t'position',\n\t\tnew BufferAttribute(\n\t\t\tnew Float32Array( [ - 1, - 1, 0.5, 3, - 1, 0.5, - 1, 3, 0.5 ] ),\n\t\t\t3\n\t\t)\n\t);\n\n\tconst fullScreenMesh = new Mesh( fullScreenTri, shadowMaterialVertical );\n\n\tconst scope = this;\n\n\tthis.enabled = false;\n\n\tthis.autoUpdate = true;\n\tthis.needsUpdate = false;\n\n\tthis.type = PCFShadowMap;\n\tlet _previousType = this.type;\n\n\tthis.render = function ( lights, scene, camera ) {\n\n\t\tif ( scope.enabled === false ) return;\n\t\tif ( scope.autoUpdate === false && scope.needsUpdate === false ) return;\n\n\t\tif ( lights.length === 0 ) return;\n\n\t\tconst currentRenderTarget = renderer.getRenderTarget();\n\t\tconst activeCubeFace = renderer.getActiveCubeFace();\n\t\tconst activeMipmapLevel = renderer.getActiveMipmapLevel();\n\n\t\tconst _state = renderer.state;\n\n\t\t// Set GL state for depth map.\n\t\t_state.setBlending( NoBlending );\n\t\t_state.buffers.color.setClear( 1, 1, 1, 1 );\n\t\t_state.buffers.depth.setTest( true );\n\t\t_state.setScissorTest( false );\n\n\t\t// check for shadow map type changes\n\n\t\tconst toVSM = ( _previousType !== VSMShadowMap && this.type === VSMShadowMap );\n\t\tconst fromVSM = ( _previousType === VSMShadowMap && this.type !== VSMShadowMap );\n\n\t\t// render depth map\n\n\t\tfor ( let i = 0, il = lights.length; i < il; i ++ ) {\n\n\t\t\tconst light = lights[ i ];\n\t\t\tconst shadow = light.shadow;\n\n\t\t\tif ( shadow === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLShadowMap:', light, 'has no shadow.' );\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tif ( shadow.autoUpdate === false && shadow.needsUpdate === false ) continue;\n\n\t\t\t_shadowMapSize.copy( shadow.mapSize );\n\n\t\t\tconst shadowFrameExtents = shadow.getFrameExtents();\n\n\t\t\t_shadowMapSize.multiply( shadowFrameExtents );\n\n\t\t\t_viewportSize.copy( shadow.mapSize );\n\n\t\t\tif ( _shadowMapSize.x > _maxTextureSize || _shadowMapSize.y > _maxTextureSize ) {\n\n\t\t\t\tif ( _shadowMapSize.x > _maxTextureSize ) {\n\n\t\t\t\t\t_viewportSize.x = Math.floor( _maxTextureSize / shadowFrameExtents.x );\n\t\t\t\t\t_shadowMapSize.x = _viewportSize.x * shadowFrameExtents.x;\n\t\t\t\t\tshadow.mapSize.x = _viewportSize.x;\n\n\t\t\t\t}\n\n\t\t\t\tif ( _shadowMapSize.y > _maxTextureSize ) {\n\n\t\t\t\t\t_viewportSize.y = Math.floor( _maxTextureSize / shadowFrameExtents.y );\n\t\t\t\t\t_shadowMapSize.y = _viewportSize.y * shadowFrameExtents.y;\n\t\t\t\t\tshadow.mapSize.y = _viewportSize.y;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( shadow.map === null || toVSM === true || fromVSM === true ) {\n\n\t\t\t\tconst pars = ( this.type !== VSMShadowMap ) ? { minFilter: NearestFilter, magFilter: NearestFilter } : {};\n\n\t\t\t\tif ( shadow.map !== null ) {\n\n\t\t\t\t\tshadow.map.dispose();\n\n\t\t\t\t}\n\n\t\t\t\tshadow.map = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y, pars );\n\t\t\t\tshadow.map.texture.name = light.name + '.shadowMap';\n\n\t\t\t\tshadow.camera.updateProjectionMatrix();\n\n\t\t\t}\n\n\t\t\trenderer.setRenderTarget( shadow.map );\n\t\t\trenderer.clear();\n\n\t\t\tconst viewportCount = shadow.getViewportCount();\n\n\t\t\tfor ( let vp = 0; vp < viewportCount; vp ++ ) {\n\n\t\t\t\tconst viewport = shadow.getViewport( vp );\n\n\t\t\t\t_viewport.set(\n\t\t\t\t\t_viewportSize.x * viewport.x,\n\t\t\t\t\t_viewportSize.y * viewport.y,\n\t\t\t\t\t_viewportSize.x * viewport.z,\n\t\t\t\t\t_viewportSize.y * viewport.w\n\t\t\t\t);\n\n\t\t\t\t_state.viewport( _viewport );\n\n\t\t\t\tshadow.updateMatrices( light, vp );\n\n\t\t\t\t_frustum = shadow.getFrustum();\n\n\t\t\t\trenderObject( scene, camera, shadow.camera, light, this.type );\n\n\t\t\t}\n\n\t\t\t// do blur pass for VSM\n\n\t\t\tif ( shadow.isPointLightShadow !== true && this.type === VSMShadowMap ) {\n\n\t\t\t\tVSMPass( shadow, camera );\n\n\t\t\t}\n\n\t\t\tshadow.needsUpdate = false;\n\n\t\t}\n\n\t\t_previousType = this.type;\n\n\t\tscope.needsUpdate = false;\n\n\t\trenderer.setRenderTarget( currentRenderTarget, activeCubeFace, activeMipmapLevel );\n\n\t};\n\n\tfunction VSMPass( shadow, camera ) {\n\n\t\tconst geometry = objects.update( fullScreenMesh );\n\n\t\tif ( shadowMaterialVertical.defines.VSM_SAMPLES !== shadow.blurSamples ) {\n\n\t\t\tshadowMaterialVertical.defines.VSM_SAMPLES = shadow.blurSamples;\n\t\t\tshadowMaterialHorizontal.defines.VSM_SAMPLES = shadow.blurSamples;\n\n\t\t\tshadowMaterialVertical.needsUpdate = true;\n\t\t\tshadowMaterialHorizontal.needsUpdate = true;\n\n\t\t}\n\n\t\tif ( shadow.mapPass === null ) {\n\n\t\t\tshadow.mapPass = new WebGLRenderTarget( _shadowMapSize.x, _shadowMapSize.y );\n\n\t\t}\n\n\t\t// vertical pass\n\n\t\tshadowMaterialVertical.uniforms.shadow_pass.value = shadow.map.texture;\n\t\tshadowMaterialVertical.uniforms.resolution.value = shadow.mapSize;\n\t\tshadowMaterialVertical.uniforms.radius.value = shadow.radius;\n\t\trenderer.setRenderTarget( shadow.mapPass );\n\t\trenderer.clear();\n\t\trenderer.renderBufferDirect( camera, null, geometry, shadowMaterialVertical, fullScreenMesh, null );\n\n\t\t// horizontal pass\n\n\t\tshadowMaterialHorizontal.uniforms.shadow_pass.value = shadow.mapPass.texture;\n\t\tshadowMaterialHorizontal.uniforms.resolution.value = shadow.mapSize;\n\t\tshadowMaterialHorizontal.uniforms.radius.value = shadow.radius;\n\t\trenderer.setRenderTarget( shadow.map );\n\t\trenderer.clear();\n\t\trenderer.renderBufferDirect( camera, null, geometry, shadowMaterialHorizontal, fullScreenMesh, null );\n\n\t}\n\n\tfunction getDepthMaterial( object, material, light, type ) {\n\n\t\tlet result = null;\n\n\t\tconst customMaterial = ( light.isPointLight === true ) ? object.customDistanceMaterial : object.customDepthMaterial;\n\n\t\tif ( customMaterial !== undefined ) {\n\n\t\t\tresult = customMaterial;\n\n\t\t} else {\n\n\t\t\tresult = ( light.isPointLight === true ) ? _distanceMaterial : _depthMaterial;\n\n\t\t\tif ( ( renderer.localClippingEnabled && material.clipShadows === true && Array.isArray( material.clippingPlanes ) && material.clippingPlanes.length !== 0 ) ||\n\t\t\t\t( material.displacementMap && material.displacementScale !== 0 ) ||\n\t\t\t\t( material.alphaMap && material.alphaTest > 0 ) ||\n\t\t\t\t( material.map && material.alphaTest > 0 ) ) {\n\n\t\t\t\t// in this case we need a unique material instance reflecting the\n\t\t\t\t// appropriate state\n\n\t\t\t\tconst keyA = result.uuid, keyB = material.uuid;\n\n\t\t\t\tlet materialsForVariant = _materialCache[ keyA ];\n\n\t\t\t\tif ( materialsForVariant === undefined ) {\n\n\t\t\t\t\tmaterialsForVariant = {};\n\t\t\t\t\t_materialCache[ keyA ] = materialsForVariant;\n\n\t\t\t\t}\n\n\t\t\t\tlet cachedMaterial = materialsForVariant[ keyB ];\n\n\t\t\t\tif ( cachedMaterial === undefined ) {\n\n\t\t\t\t\tcachedMaterial = result.clone();\n\t\t\t\t\tmaterialsForVariant[ keyB ] = cachedMaterial;\n\t\t\t\t\tmaterial.addEventListener( 'dispose', onMaterialDispose );\n\n\t\t\t\t}\n\n\t\t\t\tresult = cachedMaterial;\n\n\t\t\t}\n\n\t\t}\n\n\t\tresult.visible = material.visible;\n\t\tresult.wireframe = material.wireframe;\n\n\t\tif ( type === VSMShadowMap ) {\n\n\t\t\tresult.side = ( material.shadowSide !== null ) ? material.shadowSide : material.side;\n\n\t\t} else {\n\n\t\t\tresult.side = ( material.shadowSide !== null ) ? material.shadowSide : shadowSide[ material.side ];\n\n\t\t}\n\n\t\tresult.alphaMap = material.alphaMap;\n\t\tresult.alphaTest = material.alphaTest;\n\t\tresult.map = material.map;\n\n\t\tresult.clipShadows = material.clipShadows;\n\t\tresult.clippingPlanes = material.clippingPlanes;\n\t\tresult.clipIntersection = material.clipIntersection;\n\n\t\tresult.displacementMap = material.displacementMap;\n\t\tresult.displacementScale = material.displacementScale;\n\t\tresult.displacementBias = material.displacementBias;\n\n\t\tresult.wireframeLinewidth = material.wireframeLinewidth;\n\t\tresult.linewidth = material.linewidth;\n\n\t\tif ( light.isPointLight === true && result.isMeshDistanceMaterial === true ) {\n\n\t\t\tconst materialProperties = renderer.properties.get( result );\n\t\t\tmaterialProperties.light = light;\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\tfunction renderObject( object, camera, shadowCamera, light, type ) {\n\n\t\tif ( object.visible === false ) return;\n\n\t\tconst visible = object.layers.test( camera.layers );\n\n\t\tif ( visible && ( object.isMesh || object.isLine || object.isPoints ) ) {\n\n\t\t\tif ( ( object.castShadow || ( object.receiveShadow && type === VSMShadowMap ) ) && ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) ) {\n\n\t\t\t\tobject.modelViewMatrix.multiplyMatrices( shadowCamera.matrixWorldInverse, object.matrixWorld );\n\n\t\t\t\tconst geometry = objects.update( object );\n\t\t\t\tconst material = object.material;\n\n\t\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\t\tconst groups = geometry.groups;\n\n\t\t\t\t\tfor ( let k = 0, kl = groups.length; k < kl; k ++ ) {\n\n\t\t\t\t\t\tconst group = groups[ k ];\n\t\t\t\t\t\tconst groupMaterial = material[ group.materialIndex ];\n\n\t\t\t\t\t\tif ( groupMaterial && groupMaterial.visible ) {\n\n\t\t\t\t\t\t\tconst depthMaterial = getDepthMaterial( object, groupMaterial, light, type );\n\n\t\t\t\t\t\t\tobject.onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, group );\n\n\t\t\t\t\t\t\trenderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, group );\n\n\t\t\t\t\t\t\tobject.onAfterShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, group );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( material.visible ) {\n\n\t\t\t\t\tconst depthMaterial = getDepthMaterial( object, material, light, type );\n\n\t\t\t\t\tobject.onBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, null );\n\n\t\t\t\t\trenderer.renderBufferDirect( shadowCamera, null, geometry, depthMaterial, object, null );\n\n\t\t\t\t\tobject.onAfterShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial, null );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst children = object.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\trenderObject( children[ i ], camera, shadowCamera, light, type );\n\n\t\t}\n\n\t}\n\n\tfunction onMaterialDispose( event ) {\n\n\t\tconst material = event.target;\n\n\t\tmaterial.removeEventListener( 'dispose', onMaterialDispose );\n\n\t\t// make sure to remove the unique distance/depth materials used for shadow map rendering\n\n\t\tfor ( const id in _materialCache ) {\n\n\t\t\tconst cache = _materialCache[ id ];\n\n\t\t\tconst uuid = event.target.uuid;\n\n\t\t\tif ( uuid in cache ) {\n\n\t\t\t\tconst shadowMaterial = cache[ uuid ];\n\t\t\t\tshadowMaterial.dispose();\n\t\t\t\tdelete cache[ uuid ];\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nfunction WebGLState( gl ) {\n\n\tfunction ColorBuffer() {\n\n\t\tlet locked = false;\n\n\t\tconst color = new Vector4();\n\t\tlet currentColorMask = null;\n\t\tconst currentColorClear = new Vector4( 0, 0, 0, 0 );\n\n\t\treturn {\n\n\t\t\tsetMask: function ( colorMask ) {\n\n\t\t\t\tif ( currentColorMask !== colorMask && ! locked ) {\n\n\t\t\t\t\tgl.colorMask( colorMask, colorMask, colorMask, colorMask );\n\t\t\t\t\tcurrentColorMask = colorMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\tlocked = lock;\n\n\t\t\t},\n\n\t\t\tsetClear: function ( r, g, b, a, premultipliedAlpha ) {\n\n\t\t\t\tif ( premultipliedAlpha === true ) {\n\n\t\t\t\t\tr *= a; g *= a; b *= a;\n\n\t\t\t\t}\n\n\t\t\t\tcolor.set( r, g, b, a );\n\n\t\t\t\tif ( currentColorClear.equals( color ) === false ) {\n\n\t\t\t\t\tgl.clearColor( r, g, b, a );\n\t\t\t\t\tcurrentColorClear.copy( color );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\treset: function () {\n\n\t\t\t\tlocked = false;\n\n\t\t\t\tcurrentColorMask = null;\n\t\t\t\tcurrentColorClear.set( - 1, 0, 0, 0 ); // set to invalid state\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\tfunction DepthBuffer() {\n\n\t\tlet locked = false;\n\n\t\tlet currentDepthMask = null;\n\t\tlet currentDepthFunc = null;\n\t\tlet currentDepthClear = null;\n\n\t\treturn {\n\n\t\t\tsetTest: function ( depthTest ) {\n\n\t\t\t\tif ( depthTest ) {\n\n\t\t\t\t\tenable( gl.DEPTH_TEST );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tdisable( gl.DEPTH_TEST );\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetMask: function ( depthMask ) {\n\n\t\t\t\tif ( currentDepthMask !== depthMask && ! locked ) {\n\n\t\t\t\t\tgl.depthMask( depthMask );\n\t\t\t\t\tcurrentDepthMask = depthMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetFunc: function ( depthFunc ) {\n\n\t\t\t\tif ( currentDepthFunc !== depthFunc ) {\n\n\t\t\t\t\tswitch ( depthFunc ) {\n\n\t\t\t\t\t\tcase NeverDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.NEVER );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase AlwaysDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.ALWAYS );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase LessDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.LESS );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase LessEqualDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.LEQUAL );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase EqualDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.EQUAL );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase GreaterEqualDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.GEQUAL );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase GreaterDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.GREATER );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase NotEqualDepth:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.NOTEQUAL );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tgl.depthFunc( gl.LEQUAL );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tcurrentDepthFunc = depthFunc;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\tlocked = lock;\n\n\t\t\t},\n\n\t\t\tsetClear: function ( depth ) {\n\n\t\t\t\tif ( currentDepthClear !== depth ) {\n\n\t\t\t\t\tgl.clearDepth( depth );\n\t\t\t\t\tcurrentDepthClear = depth;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\treset: function () {\n\n\t\t\t\tlocked = false;\n\n\t\t\t\tcurrentDepthMask = null;\n\t\t\t\tcurrentDepthFunc = null;\n\t\t\t\tcurrentDepthClear = null;\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\tfunction StencilBuffer() {\n\n\t\tlet locked = false;\n\n\t\tlet currentStencilMask = null;\n\t\tlet currentStencilFunc = null;\n\t\tlet currentStencilRef = null;\n\t\tlet currentStencilFuncMask = null;\n\t\tlet currentStencilFail = null;\n\t\tlet currentStencilZFail = null;\n\t\tlet currentStencilZPass = null;\n\t\tlet currentStencilClear = null;\n\n\t\treturn {\n\n\t\t\tsetTest: function ( stencilTest ) {\n\n\t\t\t\tif ( ! locked ) {\n\n\t\t\t\t\tif ( stencilTest ) {\n\n\t\t\t\t\t\tenable( gl.STENCIL_TEST );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tdisable( gl.STENCIL_TEST );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetMask: function ( stencilMask ) {\n\n\t\t\t\tif ( currentStencilMask !== stencilMask && ! locked ) {\n\n\t\t\t\t\tgl.stencilMask( stencilMask );\n\t\t\t\t\tcurrentStencilMask = stencilMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetFunc: function ( stencilFunc, stencilRef, stencilMask ) {\n\n\t\t\t\tif ( currentStencilFunc !== stencilFunc ||\n\t\t\t\t currentStencilRef !== stencilRef ||\n\t\t\t\t currentStencilFuncMask !== stencilMask ) {\n\n\t\t\t\t\tgl.stencilFunc( stencilFunc, stencilRef, stencilMask );\n\n\t\t\t\t\tcurrentStencilFunc = stencilFunc;\n\t\t\t\t\tcurrentStencilRef = stencilRef;\n\t\t\t\t\tcurrentStencilFuncMask = stencilMask;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetOp: function ( stencilFail, stencilZFail, stencilZPass ) {\n\n\t\t\t\tif ( currentStencilFail !== stencilFail ||\n\t\t\t\t currentStencilZFail !== stencilZFail ||\n\t\t\t\t currentStencilZPass !== stencilZPass ) {\n\n\t\t\t\t\tgl.stencilOp( stencilFail, stencilZFail, stencilZPass );\n\n\t\t\t\t\tcurrentStencilFail = stencilFail;\n\t\t\t\t\tcurrentStencilZFail = stencilZFail;\n\t\t\t\t\tcurrentStencilZPass = stencilZPass;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\tsetLocked: function ( lock ) {\n\n\t\t\t\tlocked = lock;\n\n\t\t\t},\n\n\t\t\tsetClear: function ( stencil ) {\n\n\t\t\t\tif ( currentStencilClear !== stencil ) {\n\n\t\t\t\t\tgl.clearStencil( stencil );\n\t\t\t\t\tcurrentStencilClear = stencil;\n\n\t\t\t\t}\n\n\t\t\t},\n\n\t\t\treset: function () {\n\n\t\t\t\tlocked = false;\n\n\t\t\t\tcurrentStencilMask = null;\n\t\t\t\tcurrentStencilFunc = null;\n\t\t\t\tcurrentStencilRef = null;\n\t\t\t\tcurrentStencilFuncMask = null;\n\t\t\t\tcurrentStencilFail = null;\n\t\t\t\tcurrentStencilZFail = null;\n\t\t\t\tcurrentStencilZPass = null;\n\t\t\t\tcurrentStencilClear = null;\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\t//\n\n\tconst colorBuffer = new ColorBuffer();\n\tconst depthBuffer = new DepthBuffer();\n\tconst stencilBuffer = new StencilBuffer();\n\n\tconst uboBindings = new WeakMap();\n\tconst uboProgramMap = new WeakMap();\n\n\tlet enabledCapabilities = {};\n\n\tlet currentBoundFramebuffers = {};\n\tlet currentDrawbuffers = new WeakMap();\n\tlet defaultDrawbuffers = [];\n\n\tlet currentProgram = null;\n\n\tlet currentBlendingEnabled = false;\n\tlet currentBlending = null;\n\tlet currentBlendEquation = null;\n\tlet currentBlendSrc = null;\n\tlet currentBlendDst = null;\n\tlet currentBlendEquationAlpha = null;\n\tlet currentBlendSrcAlpha = null;\n\tlet currentBlendDstAlpha = null;\n\tlet currentBlendColor = new Color( 0, 0, 0 );\n\tlet currentBlendAlpha = 0;\n\tlet currentPremultipledAlpha = false;\n\n\tlet currentFlipSided = null;\n\tlet currentCullFace = null;\n\n\tlet currentLineWidth = null;\n\n\tlet currentPolygonOffsetFactor = null;\n\tlet currentPolygonOffsetUnits = null;\n\n\tconst maxTextures = gl.getParameter( gl.MAX_COMBINED_TEXTURE_IMAGE_UNITS );\n\n\tlet lineWidthAvailable = false;\n\tlet version = 0;\n\tconst glVersion = gl.getParameter( gl.VERSION );\n\n\tif ( glVersion.indexOf( 'WebGL' ) !== - 1 ) {\n\n\t\tversion = parseFloat( /^WebGL (\\d)/.exec( glVersion )[ 1 ] );\n\t\tlineWidthAvailable = ( version >= 1.0 );\n\n\t} else if ( glVersion.indexOf( 'OpenGL ES' ) !== - 1 ) {\n\n\t\tversion = parseFloat( /^OpenGL ES (\\d)/.exec( glVersion )[ 1 ] );\n\t\tlineWidthAvailable = ( version >= 2.0 );\n\n\t}\n\n\tlet currentTextureSlot = null;\n\tlet currentBoundTextures = {};\n\n\tconst scissorParam = gl.getParameter( gl.SCISSOR_BOX );\n\tconst viewportParam = gl.getParameter( gl.VIEWPORT );\n\n\tconst currentScissor = new Vector4().fromArray( scissorParam );\n\tconst currentViewport = new Vector4().fromArray( viewportParam );\n\n\tfunction createTexture( type, target, count, dimensions ) {\n\n\t\tconst data = new Uint8Array( 4 ); // 4 is required to match default unpack alignment of 4.\n\t\tconst texture = gl.createTexture();\n\n\t\tgl.bindTexture( type, texture );\n\t\tgl.texParameteri( type, gl.TEXTURE_MIN_FILTER, gl.NEAREST );\n\t\tgl.texParameteri( type, gl.TEXTURE_MAG_FILTER, gl.NEAREST );\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tif ( type === gl.TEXTURE_3D || type === gl.TEXTURE_2D_ARRAY ) {\n\n\t\t\t\tgl.texImage3D( target, 0, gl.RGBA, 1, 1, dimensions, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );\n\n\t\t\t} else {\n\n\t\t\t\tgl.texImage2D( target + i, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, data );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n\tconst emptyTextures = {};\n\temptyTextures[ gl.TEXTURE_2D ] = createTexture( gl.TEXTURE_2D, gl.TEXTURE_2D, 1 );\n\temptyTextures[ gl.TEXTURE_CUBE_MAP ] = createTexture( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_CUBE_MAP_POSITIVE_X, 6 );\n\temptyTextures[ gl.TEXTURE_2D_ARRAY ] = createTexture( gl.TEXTURE_2D_ARRAY, gl.TEXTURE_2D_ARRAY, 1, 1 );\n\temptyTextures[ gl.TEXTURE_3D ] = createTexture( gl.TEXTURE_3D, gl.TEXTURE_3D, 1, 1 );\n\n\t// init\n\n\tcolorBuffer.setClear( 0, 0, 0, 1 );\n\tdepthBuffer.setClear( 1 );\n\tstencilBuffer.setClear( 0 );\n\n\tenable( gl.DEPTH_TEST );\n\tdepthBuffer.setFunc( LessEqualDepth );\n\n\tsetFlipSided( false );\n\tsetCullFace( CullFaceBack );\n\tenable( gl.CULL_FACE );\n\n\tsetBlending( NoBlending );\n\n\t//\n\n\tfunction enable( id ) {\n\n\t\tif ( enabledCapabilities[ id ] !== true ) {\n\n\t\t\tgl.enable( id );\n\t\t\tenabledCapabilities[ id ] = true;\n\n\t\t}\n\n\t}\n\n\tfunction disable( id ) {\n\n\t\tif ( enabledCapabilities[ id ] !== false ) {\n\n\t\t\tgl.disable( id );\n\t\t\tenabledCapabilities[ id ] = false;\n\n\t\t}\n\n\t}\n\n\tfunction bindFramebuffer( target, framebuffer ) {\n\n\t\tif ( currentBoundFramebuffers[ target ] !== framebuffer ) {\n\n\t\t\tgl.bindFramebuffer( target, framebuffer );\n\n\t\t\tcurrentBoundFramebuffers[ target ] = framebuffer;\n\n\t\t\t// gl.DRAW_FRAMEBUFFER is equivalent to gl.FRAMEBUFFER\n\n\t\t\tif ( target === gl.DRAW_FRAMEBUFFER ) {\n\n\t\t\t\tcurrentBoundFramebuffers[ gl.FRAMEBUFFER ] = framebuffer;\n\n\t\t\t}\n\n\t\t\tif ( target === gl.FRAMEBUFFER ) {\n\n\t\t\t\tcurrentBoundFramebuffers[ gl.DRAW_FRAMEBUFFER ] = framebuffer;\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\treturn false;\n\n\t}\n\n\tfunction drawBuffers( renderTarget, framebuffer ) {\n\n\t\tlet drawBuffers = defaultDrawbuffers;\n\n\t\tlet needsUpdate = false;\n\n\t\tif ( renderTarget ) {\n\n\t\t\tdrawBuffers = currentDrawbuffers.get( framebuffer );\n\n\t\t\tif ( drawBuffers === undefined ) {\n\n\t\t\t\tdrawBuffers = [];\n\t\t\t\tcurrentDrawbuffers.set( framebuffer, drawBuffers );\n\n\t\t\t}\n\n\t\t\tconst textures = renderTarget.textures;\n\n\t\t\tif ( drawBuffers.length !== textures.length || drawBuffers[ 0 ] !== gl.COLOR_ATTACHMENT0 ) {\n\n\t\t\t\tfor ( let i = 0, il = textures.length; i < il; i ++ ) {\n\n\t\t\t\t\tdrawBuffers[ i ] = gl.COLOR_ATTACHMENT0 + i;\n\n\t\t\t\t}\n\n\t\t\t\tdrawBuffers.length = textures.length;\n\n\t\t\t\tneedsUpdate = true;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif ( drawBuffers[ 0 ] !== gl.BACK ) {\n\n\t\t\t\tdrawBuffers[ 0 ] = gl.BACK;\n\n\t\t\t\tneedsUpdate = true;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( needsUpdate ) {\n\n\t\t\tgl.drawBuffers( drawBuffers );\n\n\t\t}\n\n\t}\n\n\tfunction useProgram( program ) {\n\n\t\tif ( currentProgram !== program ) {\n\n\t\t\tgl.useProgram( program );\n\n\t\t\tcurrentProgram = program;\n\n\t\t\treturn true;\n\n\t\t}\n\n\t\treturn false;\n\n\t}\n\n\tconst equationToGL = {\n\t\t[ AddEquation ]: gl.FUNC_ADD,\n\t\t[ SubtractEquation ]: gl.FUNC_SUBTRACT,\n\t\t[ ReverseSubtractEquation ]: gl.FUNC_REVERSE_SUBTRACT\n\t};\n\n\tequationToGL[ MinEquation ] = gl.MIN;\n\tequationToGL[ MaxEquation ] = gl.MAX;\n\n\tconst factorToGL = {\n\t\t[ ZeroFactor ]: gl.ZERO,\n\t\t[ OneFactor ]: gl.ONE,\n\t\t[ SrcColorFactor ]: gl.SRC_COLOR,\n\t\t[ SrcAlphaFactor ]: gl.SRC_ALPHA,\n\t\t[ SrcAlphaSaturateFactor ]: gl.SRC_ALPHA_SATURATE,\n\t\t[ DstColorFactor ]: gl.DST_COLOR,\n\t\t[ DstAlphaFactor ]: gl.DST_ALPHA,\n\t\t[ OneMinusSrcColorFactor ]: gl.ONE_MINUS_SRC_COLOR,\n\t\t[ OneMinusSrcAlphaFactor ]: gl.ONE_MINUS_SRC_ALPHA,\n\t\t[ OneMinusDstColorFactor ]: gl.ONE_MINUS_DST_COLOR,\n\t\t[ OneMinusDstAlphaFactor ]: gl.ONE_MINUS_DST_ALPHA,\n\t\t[ ConstantColorFactor ]: gl.CONSTANT_COLOR,\n\t\t[ OneMinusConstantColorFactor ]: gl.ONE_MINUS_CONSTANT_COLOR,\n\t\t[ ConstantAlphaFactor ]: gl.CONSTANT_ALPHA,\n\t\t[ OneMinusConstantAlphaFactor ]: gl.ONE_MINUS_CONSTANT_ALPHA\n\t};\n\n\tfunction setBlending( blending, blendEquation, blendSrc, blendDst, blendEquationAlpha, blendSrcAlpha, blendDstAlpha, blendColor, blendAlpha, premultipliedAlpha ) {\n\n\t\tif ( blending === NoBlending ) {\n\n\t\t\tif ( currentBlendingEnabled === true ) {\n\n\t\t\t\tdisable( gl.BLEND );\n\t\t\t\tcurrentBlendingEnabled = false;\n\n\t\t\t}\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( currentBlendingEnabled === false ) {\n\n\t\t\tenable( gl.BLEND );\n\t\t\tcurrentBlendingEnabled = true;\n\n\t\t}\n\n\t\tif ( blending !== CustomBlending ) {\n\n\t\t\tif ( blending !== currentBlending || premultipliedAlpha !== currentPremultipledAlpha ) {\n\n\t\t\t\tif ( currentBlendEquation !== AddEquation || currentBlendEquationAlpha !== AddEquation ) {\n\n\t\t\t\t\tgl.blendEquation( gl.FUNC_ADD );\n\n\t\t\t\t\tcurrentBlendEquation = AddEquation;\n\t\t\t\t\tcurrentBlendEquationAlpha = AddEquation;\n\n\t\t\t\t}\n\n\t\t\t\tif ( premultipliedAlpha ) {\n\n\t\t\t\t\tswitch ( blending ) {\n\n\t\t\t\t\t\tcase NormalBlending:\n\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ONE, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase AdditiveBlending:\n\t\t\t\t\t\t\tgl.blendFunc( gl.ONE, gl.ONE );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase SubtractiveBlending:\n\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase MultiplyBlending:\n\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ZERO, gl.SRC_COLOR, gl.ZERO, gl.SRC_ALPHA );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tconsole.error( 'THREE.WebGLState: Invalid blending: ', blending );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tswitch ( blending ) {\n\n\t\t\t\t\t\tcase NormalBlending:\n\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA, gl.ONE, gl.ONE_MINUS_SRC_ALPHA );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase AdditiveBlending:\n\t\t\t\t\t\t\tgl.blendFunc( gl.SRC_ALPHA, gl.ONE );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase SubtractiveBlending:\n\t\t\t\t\t\t\tgl.blendFuncSeparate( gl.ZERO, gl.ONE_MINUS_SRC_COLOR, gl.ZERO, gl.ONE );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase MultiplyBlending:\n\t\t\t\t\t\t\tgl.blendFunc( gl.ZERO, gl.SRC_COLOR );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\t\t\t\t\t\t\tconsole.error( 'THREE.WebGLState: Invalid blending: ', blending );\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tcurrentBlendSrc = null;\n\t\t\t\tcurrentBlendDst = null;\n\t\t\t\tcurrentBlendSrcAlpha = null;\n\t\t\t\tcurrentBlendDstAlpha = null;\n\t\t\t\tcurrentBlendColor.set( 0, 0, 0 );\n\t\t\t\tcurrentBlendAlpha = 0;\n\n\t\t\t\tcurrentBlending = blending;\n\t\t\t\tcurrentPremultipledAlpha = premultipliedAlpha;\n\n\t\t\t}\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t// custom blending\n\n\t\tblendEquationAlpha = blendEquationAlpha || blendEquation;\n\t\tblendSrcAlpha = blendSrcAlpha || blendSrc;\n\t\tblendDstAlpha = blendDstAlpha || blendDst;\n\n\t\tif ( blendEquation !== currentBlendEquation || blendEquationAlpha !== currentBlendEquationAlpha ) {\n\n\t\t\tgl.blendEquationSeparate( equationToGL[ blendEquation ], equationToGL[ blendEquationAlpha ] );\n\n\t\t\tcurrentBlendEquation = blendEquation;\n\t\t\tcurrentBlendEquationAlpha = blendEquationAlpha;\n\n\t\t}\n\n\t\tif ( blendSrc !== currentBlendSrc || blendDst !== currentBlendDst || blendSrcAlpha !== currentBlendSrcAlpha || blendDstAlpha !== currentBlendDstAlpha ) {\n\n\t\t\tgl.blendFuncSeparate( factorToGL[ blendSrc ], factorToGL[ blendDst ], factorToGL[ blendSrcAlpha ], factorToGL[ blendDstAlpha ] );\n\n\t\t\tcurrentBlendSrc = blendSrc;\n\t\t\tcurrentBlendDst = blendDst;\n\t\t\tcurrentBlendSrcAlpha = blendSrcAlpha;\n\t\t\tcurrentBlendDstAlpha = blendDstAlpha;\n\n\t\t}\n\n\t\tif ( blendColor.equals( currentBlendColor ) === false || blendAlpha !== currentBlendAlpha ) {\n\n\t\t\tgl.blendColor( blendColor.r, blendColor.g, blendColor.b, blendAlpha );\n\n\t\t\tcurrentBlendColor.copy( blendColor );\n\t\t\tcurrentBlendAlpha = blendAlpha;\n\n\t\t}\n\n\t\tcurrentBlending = blending;\n\t\tcurrentPremultipledAlpha = false;\n\n\t}\n\n\tfunction setMaterial( material, frontFaceCW ) {\n\n\t\tmaterial.side === DoubleSide\n\t\t\t? disable( gl.CULL_FACE )\n\t\t\t: enable( gl.CULL_FACE );\n\n\t\tlet flipSided = ( material.side === BackSide );\n\t\tif ( frontFaceCW ) flipSided = ! flipSided;\n\n\t\tsetFlipSided( flipSided );\n\n\t\t( material.blending === NormalBlending && material.transparent === false )\n\t\t\t? setBlending( NoBlending )\n\t\t\t: setBlending( material.blending, material.blendEquation, material.blendSrc, material.blendDst, material.blendEquationAlpha, material.blendSrcAlpha, material.blendDstAlpha, material.blendColor, material.blendAlpha, material.premultipliedAlpha );\n\n\t\tdepthBuffer.setFunc( material.depthFunc );\n\t\tdepthBuffer.setTest( material.depthTest );\n\t\tdepthBuffer.setMask( material.depthWrite );\n\t\tcolorBuffer.setMask( material.colorWrite );\n\n\t\tconst stencilWrite = material.stencilWrite;\n\t\tstencilBuffer.setTest( stencilWrite );\n\t\tif ( stencilWrite ) {\n\n\t\t\tstencilBuffer.setMask( material.stencilWriteMask );\n\t\t\tstencilBuffer.setFunc( material.stencilFunc, material.stencilRef, material.stencilFuncMask );\n\t\t\tstencilBuffer.setOp( material.stencilFail, material.stencilZFail, material.stencilZPass );\n\n\t\t}\n\n\t\tsetPolygonOffset( material.polygonOffset, material.polygonOffsetFactor, material.polygonOffsetUnits );\n\n\t\tmaterial.alphaToCoverage === true\n\t\t\t? enable( gl.SAMPLE_ALPHA_TO_COVERAGE )\n\t\t\t: disable( gl.SAMPLE_ALPHA_TO_COVERAGE );\n\n\t}\n\n\t//\n\n\tfunction setFlipSided( flipSided ) {\n\n\t\tif ( currentFlipSided !== flipSided ) {\n\n\t\t\tif ( flipSided ) {\n\n\t\t\t\tgl.frontFace( gl.CW );\n\n\t\t\t} else {\n\n\t\t\t\tgl.frontFace( gl.CCW );\n\n\t\t\t}\n\n\t\t\tcurrentFlipSided = flipSided;\n\n\t\t}\n\n\t}\n\n\tfunction setCullFace( cullFace ) {\n\n\t\tif ( cullFace !== CullFaceNone ) {\n\n\t\t\tenable( gl.CULL_FACE );\n\n\t\t\tif ( cullFace !== currentCullFace ) {\n\n\t\t\t\tif ( cullFace === CullFaceBack ) {\n\n\t\t\t\t\tgl.cullFace( gl.BACK );\n\n\t\t\t\t} else if ( cullFace === CullFaceFront ) {\n\n\t\t\t\t\tgl.cullFace( gl.FRONT );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tgl.cullFace( gl.FRONT_AND_BACK );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tdisable( gl.CULL_FACE );\n\n\t\t}\n\n\t\tcurrentCullFace = cullFace;\n\n\t}\n\n\tfunction setLineWidth( width ) {\n\n\t\tif ( width !== currentLineWidth ) {\n\n\t\t\tif ( lineWidthAvailable ) gl.lineWidth( width );\n\n\t\t\tcurrentLineWidth = width;\n\n\t\t}\n\n\t}\n\n\tfunction setPolygonOffset( polygonOffset, factor, units ) {\n\n\t\tif ( polygonOffset ) {\n\n\t\t\tenable( gl.POLYGON_OFFSET_FILL );\n\n\t\t\tif ( currentPolygonOffsetFactor !== factor || currentPolygonOffsetUnits !== units ) {\n\n\t\t\t\tgl.polygonOffset( factor, units );\n\n\t\t\t\tcurrentPolygonOffsetFactor = factor;\n\t\t\t\tcurrentPolygonOffsetUnits = units;\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tdisable( gl.POLYGON_OFFSET_FILL );\n\n\t\t}\n\n\t}\n\n\tfunction setScissorTest( scissorTest ) {\n\n\t\tif ( scissorTest ) {\n\n\t\t\tenable( gl.SCISSOR_TEST );\n\n\t\t} else {\n\n\t\t\tdisable( gl.SCISSOR_TEST );\n\n\t\t}\n\n\t}\n\n\t// texture\n\n\tfunction activeTexture( webglSlot ) {\n\n\t\tif ( webglSlot === undefined ) webglSlot = gl.TEXTURE0 + maxTextures - 1;\n\n\t\tif ( currentTextureSlot !== webglSlot ) {\n\n\t\t\tgl.activeTexture( webglSlot );\n\t\t\tcurrentTextureSlot = webglSlot;\n\n\t\t}\n\n\t}\n\n\tfunction bindTexture( webglType, webglTexture, webglSlot ) {\n\n\t\tif ( webglSlot === undefined ) {\n\n\t\t\tif ( currentTextureSlot === null ) {\n\n\t\t\t\twebglSlot = gl.TEXTURE0 + maxTextures - 1;\n\n\t\t\t} else {\n\n\t\t\t\twebglSlot = currentTextureSlot;\n\n\t\t\t}\n\n\t\t}\n\n\t\tlet boundTexture = currentBoundTextures[ webglSlot ];\n\n\t\tif ( boundTexture === undefined ) {\n\n\t\t\tboundTexture = { type: undefined, texture: undefined };\n\t\t\tcurrentBoundTextures[ webglSlot ] = boundTexture;\n\n\t\t}\n\n\t\tif ( boundTexture.type !== webglType || boundTexture.texture !== webglTexture ) {\n\n\t\t\tif ( currentTextureSlot !== webglSlot ) {\n\n\t\t\t\tgl.activeTexture( webglSlot );\n\t\t\t\tcurrentTextureSlot = webglSlot;\n\n\t\t\t}\n\n\t\t\tgl.bindTexture( webglType, webglTexture || emptyTextures[ webglType ] );\n\n\t\t\tboundTexture.type = webglType;\n\t\t\tboundTexture.texture = webglTexture;\n\n\t\t}\n\n\t}\n\n\tfunction unbindTexture() {\n\n\t\tconst boundTexture = currentBoundTextures[ currentTextureSlot ];\n\n\t\tif ( boundTexture !== undefined && boundTexture.type !== undefined ) {\n\n\t\t\tgl.bindTexture( boundTexture.type, null );\n\n\t\t\tboundTexture.type = undefined;\n\t\t\tboundTexture.texture = undefined;\n\n\t\t}\n\n\t}\n\n\tfunction compressedTexImage2D() {\n\n\t\ttry {\n\n\t\t\tgl.compressedTexImage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction compressedTexImage3D() {\n\n\t\ttry {\n\n\t\t\tgl.compressedTexImage3D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texSubImage2D() {\n\n\t\ttry {\n\n\t\t\tgl.texSubImage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texSubImage3D() {\n\n\t\ttry {\n\n\t\t\tgl.texSubImage3D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction compressedTexSubImage2D() {\n\n\t\ttry {\n\n\t\t\tgl.compressedTexSubImage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction compressedTexSubImage3D() {\n\n\t\ttry {\n\n\t\t\tgl.compressedTexSubImage3D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texStorage2D() {\n\n\t\ttry {\n\n\t\t\tgl.texStorage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texStorage3D() {\n\n\t\ttry {\n\n\t\t\tgl.texStorage3D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texImage2D() {\n\n\t\ttry {\n\n\t\t\tgl.texImage2D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\tfunction texImage3D() {\n\n\t\ttry {\n\n\t\t\tgl.texImage3D.apply( gl, arguments );\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLState:', error );\n\n\t\t}\n\n\t}\n\n\t//\n\n\tfunction scissor( scissor ) {\n\n\t\tif ( currentScissor.equals( scissor ) === false ) {\n\n\t\t\tgl.scissor( scissor.x, scissor.y, scissor.z, scissor.w );\n\t\t\tcurrentScissor.copy( scissor );\n\n\t\t}\n\n\t}\n\n\tfunction viewport( viewport ) {\n\n\t\tif ( currentViewport.equals( viewport ) === false ) {\n\n\t\t\tgl.viewport( viewport.x, viewport.y, viewport.z, viewport.w );\n\t\t\tcurrentViewport.copy( viewport );\n\n\t\t}\n\n\t}\n\n\tfunction updateUBOMapping( uniformsGroup, program ) {\n\n\t\tlet mapping = uboProgramMap.get( program );\n\n\t\tif ( mapping === undefined ) {\n\n\t\t\tmapping = new WeakMap();\n\n\t\t\tuboProgramMap.set( program, mapping );\n\n\t\t}\n\n\t\tlet blockIndex = mapping.get( uniformsGroup );\n\n\t\tif ( blockIndex === undefined ) {\n\n\t\t\tblockIndex = gl.getUniformBlockIndex( program, uniformsGroup.name );\n\n\t\t\tmapping.set( uniformsGroup, blockIndex );\n\n\t\t}\n\n\t}\n\n\tfunction uniformBlockBinding( uniformsGroup, program ) {\n\n\t\tconst mapping = uboProgramMap.get( program );\n\t\tconst blockIndex = mapping.get( uniformsGroup );\n\n\t\tif ( uboBindings.get( program ) !== blockIndex ) {\n\n\t\t\t// bind shader specific block index to global block point\n\t\t\tgl.uniformBlockBinding( program, blockIndex, uniformsGroup.__bindingPointIndex );\n\n\t\t\tuboBindings.set( program, blockIndex );\n\n\t\t}\n\n\t}\n\n\t//\n\n\tfunction reset() {\n\n\t\t// reset state\n\n\t\tgl.disable( gl.BLEND );\n\t\tgl.disable( gl.CULL_FACE );\n\t\tgl.disable( gl.DEPTH_TEST );\n\t\tgl.disable( gl.POLYGON_OFFSET_FILL );\n\t\tgl.disable( gl.SCISSOR_TEST );\n\t\tgl.disable( gl.STENCIL_TEST );\n\t\tgl.disable( gl.SAMPLE_ALPHA_TO_COVERAGE );\n\n\t\tgl.blendEquation( gl.FUNC_ADD );\n\t\tgl.blendFunc( gl.ONE, gl.ZERO );\n\t\tgl.blendFuncSeparate( gl.ONE, gl.ZERO, gl.ONE, gl.ZERO );\n\t\tgl.blendColor( 0, 0, 0, 0 );\n\n\t\tgl.colorMask( true, true, true, true );\n\t\tgl.clearColor( 0, 0, 0, 0 );\n\n\t\tgl.depthMask( true );\n\t\tgl.depthFunc( gl.LESS );\n\t\tgl.clearDepth( 1 );\n\n\t\tgl.stencilMask( 0xffffffff );\n\t\tgl.stencilFunc( gl.ALWAYS, 0, 0xffffffff );\n\t\tgl.stencilOp( gl.KEEP, gl.KEEP, gl.KEEP );\n\t\tgl.clearStencil( 0 );\n\n\t\tgl.cullFace( gl.BACK );\n\t\tgl.frontFace( gl.CCW );\n\n\t\tgl.polygonOffset( 0, 0 );\n\n\t\tgl.activeTexture( gl.TEXTURE0 );\n\n\t\tgl.bindFramebuffer( gl.FRAMEBUFFER, null );\n\t\tgl.bindFramebuffer( gl.DRAW_FRAMEBUFFER, null );\n\t\tgl.bindFramebuffer( gl.READ_FRAMEBUFFER, null );\n\n\t\tgl.useProgram( null );\n\n\t\tgl.lineWidth( 1 );\n\n\t\tgl.scissor( 0, 0, gl.canvas.width, gl.canvas.height );\n\t\tgl.viewport( 0, 0, gl.canvas.width, gl.canvas.height );\n\n\t\t// reset internals\n\n\t\tenabledCapabilities = {};\n\n\t\tcurrentTextureSlot = null;\n\t\tcurrentBoundTextures = {};\n\n\t\tcurrentBoundFramebuffers = {};\n\t\tcurrentDrawbuffers = new WeakMap();\n\t\tdefaultDrawbuffers = [];\n\n\t\tcurrentProgram = null;\n\n\t\tcurrentBlendingEnabled = false;\n\t\tcurrentBlending = null;\n\t\tcurrentBlendEquation = null;\n\t\tcurrentBlendSrc = null;\n\t\tcurrentBlendDst = null;\n\t\tcurrentBlendEquationAlpha = null;\n\t\tcurrentBlendSrcAlpha = null;\n\t\tcurrentBlendDstAlpha = null;\n\t\tcurrentBlendColor = new Color( 0, 0, 0 );\n\t\tcurrentBlendAlpha = 0;\n\t\tcurrentPremultipledAlpha = false;\n\n\t\tcurrentFlipSided = null;\n\t\tcurrentCullFace = null;\n\n\t\tcurrentLineWidth = null;\n\n\t\tcurrentPolygonOffsetFactor = null;\n\t\tcurrentPolygonOffsetUnits = null;\n\n\t\tcurrentScissor.set( 0, 0, gl.canvas.width, gl.canvas.height );\n\t\tcurrentViewport.set( 0, 0, gl.canvas.width, gl.canvas.height );\n\n\t\tcolorBuffer.reset();\n\t\tdepthBuffer.reset();\n\t\tstencilBuffer.reset();\n\n\t}\n\n\treturn {\n\n\t\tbuffers: {\n\t\t\tcolor: colorBuffer,\n\t\t\tdepth: depthBuffer,\n\t\t\tstencil: stencilBuffer\n\t\t},\n\n\t\tenable: enable,\n\t\tdisable: disable,\n\n\t\tbindFramebuffer: bindFramebuffer,\n\t\tdrawBuffers: drawBuffers,\n\n\t\tuseProgram: useProgram,\n\n\t\tsetBlending: setBlending,\n\t\tsetMaterial: setMaterial,\n\n\t\tsetFlipSided: setFlipSided,\n\t\tsetCullFace: setCullFace,\n\n\t\tsetLineWidth: setLineWidth,\n\t\tsetPolygonOffset: setPolygonOffset,\n\n\t\tsetScissorTest: setScissorTest,\n\n\t\tactiveTexture: activeTexture,\n\t\tbindTexture: bindTexture,\n\t\tunbindTexture: unbindTexture,\n\t\tcompressedTexImage2D: compressedTexImage2D,\n\t\tcompressedTexImage3D: compressedTexImage3D,\n\t\ttexImage2D: texImage2D,\n\t\ttexImage3D: texImage3D,\n\n\t\tupdateUBOMapping: updateUBOMapping,\n\t\tuniformBlockBinding: uniformBlockBinding,\n\n\t\ttexStorage2D: texStorage2D,\n\t\ttexStorage3D: texStorage3D,\n\t\ttexSubImage2D: texSubImage2D,\n\t\ttexSubImage3D: texSubImage3D,\n\t\tcompressedTexSubImage2D: compressedTexSubImage2D,\n\t\tcompressedTexSubImage3D: compressedTexSubImage3D,\n\n\t\tscissor: scissor,\n\t\tviewport: viewport,\n\n\t\treset: reset\n\n\t};\n\n}\n\nfunction contain( texture, aspect ) {\n\n\tconst imageAspect = ( texture.image && texture.image.width ) ? texture.image.width / texture.image.height : 1;\n\n\tif ( imageAspect > aspect ) {\n\n\t\ttexture.repeat.x = 1;\n\t\ttexture.repeat.y = imageAspect / aspect;\n\n\t\ttexture.offset.x = 0;\n\t\ttexture.offset.y = ( 1 - texture.repeat.y ) / 2;\n\n\t} else {\n\n\t\ttexture.repeat.x = aspect / imageAspect;\n\t\ttexture.repeat.y = 1;\n\n\t\ttexture.offset.x = ( 1 - texture.repeat.x ) / 2;\n\t\ttexture.offset.y = 0;\n\n\t}\n\n\treturn texture;\n\n}\n\nfunction cover( texture, aspect ) {\n\n\tconst imageAspect = ( texture.image && texture.image.width ) ? texture.image.width / texture.image.height : 1;\n\n\tif ( imageAspect > aspect ) {\n\n\t\ttexture.repeat.x = aspect / imageAspect;\n\t\ttexture.repeat.y = 1;\n\n\t\ttexture.offset.x = ( 1 - texture.repeat.x ) / 2;\n\t\ttexture.offset.y = 0;\n\n\t} else {\n\n\t\ttexture.repeat.x = 1;\n\t\ttexture.repeat.y = imageAspect / aspect;\n\n\t\ttexture.offset.x = 0;\n\t\ttexture.offset.y = ( 1 - texture.repeat.y ) / 2;\n\n\t}\n\n\treturn texture;\n\n}\n\nfunction fill( texture ) {\n\n\ttexture.repeat.x = 1;\n\ttexture.repeat.y = 1;\n\n\ttexture.offset.x = 0;\n\ttexture.offset.y = 0;\n\n\treturn texture;\n\n}\n\n\n\n/**\n * Given the width, height, format, and type of a texture. Determines how many\n * bytes must be used to represent the texture.\n */\nfunction getByteLength( width, height, format, type ) {\n\n\tconst typeByteLength = getTextureTypeByteLength( type );\n\n\tswitch ( format ) {\n\n\t\t// https://registry.khronos.org/OpenGL-Refpages/es3.0/html/glTexImage2D.xhtml\n\t\tcase AlphaFormat:\n\t\t\treturn width * height;\n\t\tcase LuminanceFormat:\n\t\t\treturn width * height;\n\t\tcase LuminanceAlphaFormat:\n\t\t\treturn width * height * 2;\n\t\tcase RedFormat:\n\t\t\treturn ( ( width * height ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RedIntegerFormat:\n\t\t\treturn ( ( width * height ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RGFormat:\n\t\t\treturn ( ( width * height * 2 ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RGIntegerFormat:\n\t\t\treturn ( ( width * height * 2 ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RGBFormat:\n\t\t\treturn ( ( width * height * 3 ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RGBAFormat:\n\t\t\treturn ( ( width * height * 4 ) / typeByteLength.components ) * typeByteLength.byteLength;\n\t\tcase RGBAIntegerFormat:\n\t\t\treturn ( ( width * height * 4 ) / typeByteLength.components ) * typeByteLength.byteLength;\n\n\t\t// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_s3tc_srgb/\n\t\tcase RGB_S3TC_DXT1_Format:\n\t\tcase RGBA_S3TC_DXT1_Format:\n\t\t\treturn Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 8;\n\t\tcase RGBA_S3TC_DXT3_Format:\n\t\tcase RGBA_S3TC_DXT5_Format:\n\t\t\treturn Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16;\n\n\t\t// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_pvrtc/\n\t\tcase RGB_PVRTC_2BPPV1_Format:\n\t\tcase RGBA_PVRTC_2BPPV1_Format:\n\t\t\treturn ( Math.max( width, 16 ) * Math.max( height, 8 ) ) / 4;\n\t\tcase RGB_PVRTC_4BPPV1_Format:\n\t\tcase RGBA_PVRTC_4BPPV1_Format:\n\t\t\treturn ( Math.max( width, 8 ) * Math.max( height, 8 ) ) / 2;\n\n\t\t// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_etc/\n\t\tcase RGB_ETC1_Format:\n\t\tcase RGB_ETC2_Format:\n\t\t\treturn Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 8;\n\t\tcase RGBA_ETC2_EAC_Format:\n\t\t\treturn Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16;\n\n\t\t// https://registry.khronos.org/webgl/extensions/WEBGL_compressed_texture_astc/\n\t\tcase RGBA_ASTC_4x4_Format:\n\t\t\treturn Math.floor( ( width + 3 ) / 4 ) * Math.floor( ( height + 3 ) / 4 ) * 16;\n\t\tcase RGBA_ASTC_5x4_Format:\n\t\t\treturn Math.floor( ( width + 4 ) / 5 ) * Math.floor( ( height + 3 ) / 4 ) * 16;\n\t\tcase RGBA_ASTC_5x5_Format:\n\t\t\treturn Math.floor( ( width + 4 ) / 5 ) * Math.floor( ( height + 4 ) / 5 ) * 16;\n\t\tcase RGBA_ASTC_6x5_Format:\n\t\t\treturn Math.floor( ( width + 5 ) / 6 ) * Math.floor( ( height + 4 ) / 5 ) * 16;\n\t\tcase RGBA_ASTC_6x6_Format:\n\t\t\treturn Math.floor( ( width + 5 ) / 6 ) * Math.floor( ( height + 5 ) / 6 ) * 16;\n\t\tcase RGBA_ASTC_8x5_Format:\n\t\t\treturn Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 4 ) / 5 ) * 16;\n\t\tcase RGBA_ASTC_8x6_Format:\n\t\t\treturn Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 5 ) / 6 ) * 16;\n\t\tcase RGBA_ASTC_8x8_Format:\n\t\t\treturn Math.floor( ( width + 7 ) / 8 ) * Math.floor( ( height + 7 ) / 8 ) * 16;\n\t\tcase RGBA_ASTC_10x5_Format:\n\t\t\treturn Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 4 ) / 5 ) * 16;\n\t\tcase RGBA_ASTC_10x6_Format:\n\t\t\treturn Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 5 ) / 6 ) * 16;\n\t\tcase RGBA_ASTC_10x8_Format:\n\t\t\treturn Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 7 ) / 8 ) * 16;\n\t\tcase RGBA_ASTC_10x10_Format:\n\t\t\treturn Math.floor( ( width + 9 ) / 10 ) * Math.floor( ( height + 9 ) / 10 ) * 16;\n\t\tcase RGBA_ASTC_12x10_Format:\n\t\t\treturn Math.floor( ( width + 11 ) / 12 ) * Math.floor( ( height + 9 ) / 10 ) * 16;\n\t\tcase RGBA_ASTC_12x12_Format:\n\t\t\treturn Math.floor( ( width + 11 ) / 12 ) * Math.floor( ( height + 11 ) / 12 ) * 16;\n\n\t\t// https://registry.khronos.org/webgl/extensions/EXT_texture_compression_bptc/\n\t\tcase RGBA_BPTC_Format:\n\t\tcase RGB_BPTC_SIGNED_Format:\n\t\tcase RGB_BPTC_UNSIGNED_Format:\n\t\t\treturn Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 16;\n\n\t\t// https://registry.khronos.org/webgl/extensions/EXT_texture_compression_rgtc/\n\t\tcase RED_RGTC1_Format:\n\t\tcase SIGNED_RED_RGTC1_Format:\n\t\t\treturn Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 8;\n\t\tcase RED_GREEN_RGTC2_Format:\n\t\tcase SIGNED_RED_GREEN_RGTC2_Format:\n\t\t\treturn Math.ceil( width / 4 ) * Math.ceil( height / 4 ) * 16;\n\n\t}\n\n\tthrow new Error(\n\t\t`Unable to determine texture byte length for ${format} format.`,\n\t);\n\n}\n\nfunction getTextureTypeByteLength( type ) {\n\n\tswitch ( type ) {\n\n\t\tcase UnsignedByteType:\n\t\tcase ByteType:\n\t\t\treturn { byteLength: 1, components: 1 };\n\t\tcase UnsignedShortType:\n\t\tcase ShortType:\n\t\tcase HalfFloatType:\n\t\t\treturn { byteLength: 2, components: 1 };\n\t\tcase UnsignedShort4444Type:\n\t\tcase UnsignedShort5551Type:\n\t\t\treturn { byteLength: 2, components: 4 };\n\t\tcase UnsignedIntType:\n\t\tcase IntType:\n\t\tcase FloatType:\n\t\t\treturn { byteLength: 4, components: 1 };\n\t\tcase UnsignedInt5999Type:\n\t\t\treturn { byteLength: 4, components: 3 };\n\n\t}\n\n\tthrow new Error( `Unknown texture type ${type}.` );\n\n}\n\nconst TextureUtils = {\n\tcontain,\n\tcover,\n\tfill,\n\tgetByteLength\n};\n\nfunction WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info ) {\n\n\tconst multisampledRTTExt = extensions.has( 'WEBGL_multisampled_render_to_texture' ) ? extensions.get( 'WEBGL_multisampled_render_to_texture' ) : null;\n\tconst supportsInvalidateFramebuffer = typeof navigator === 'undefined' ? false : /OculusBrowser/g.test( navigator.userAgent );\n\n\tconst _imageDimensions = new Vector2();\n\tconst _videoTextures = new WeakMap();\n\tlet _canvas;\n\n\tconst _sources = new WeakMap(); // maps WebglTexture objects to instances of Source\n\n\t// cordova iOS (as of 5.0) still uses UIWebView, which provides OffscreenCanvas,\n\t// also OffscreenCanvas.getContext(\"webgl\"), but not OffscreenCanvas.getContext(\"2d\")!\n\t// Some implementations may only implement OffscreenCanvas partially (e.g. lacking 2d).\n\n\tlet useOffscreenCanvas = false;\n\n\ttry {\n\n\t\tuseOffscreenCanvas = typeof OffscreenCanvas !== 'undefined'\n\t\t\t// eslint-disable-next-line compat/compat\n\t\t\t&& ( new OffscreenCanvas( 1, 1 ).getContext( '2d' ) ) !== null;\n\n\t} catch ( err ) {\n\n\t\t// Ignore any errors\n\n\t}\n\n\tfunction createCanvas( width, height ) {\n\n\t\t// Use OffscreenCanvas when available. Specially needed in web workers\n\n\t\treturn useOffscreenCanvas ?\n\t\t\t// eslint-disable-next-line compat/compat\n\t\t\tnew OffscreenCanvas( width, height ) : createElementNS( 'canvas' );\n\n\t}\n\n\tfunction resizeImage( image, needsNewCanvas, maxSize ) {\n\n\t\tlet scale = 1;\n\n\t\tconst dimensions = getDimensions( image );\n\n\t\t// handle case if texture exceeds max size\n\n\t\tif ( dimensions.width > maxSize || dimensions.height > maxSize ) {\n\n\t\t\tscale = maxSize / Math.max( dimensions.width, dimensions.height );\n\n\t\t}\n\n\t\t// only perform resize if necessary\n\n\t\tif ( scale < 1 ) {\n\n\t\t\t// only perform resize for certain image types\n\n\t\t\tif ( ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) ||\n\t\t\t\t( typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement ) ||\n\t\t\t\t( typeof ImageBitmap !== 'undefined' && image instanceof ImageBitmap ) ||\n\t\t\t\t( typeof VideoFrame !== 'undefined' && image instanceof VideoFrame ) ) {\n\n\t\t\t\tconst width = Math.floor( scale * dimensions.width );\n\t\t\t\tconst height = Math.floor( scale * dimensions.height );\n\n\t\t\t\tif ( _canvas === undefined ) _canvas = createCanvas( width, height );\n\n\t\t\t\t// cube textures can't reuse the same canvas\n\n\t\t\t\tconst canvas = needsNewCanvas ? createCanvas( width, height ) : _canvas;\n\n\t\t\t\tcanvas.width = width;\n\t\t\t\tcanvas.height = height;\n\n\t\t\t\tconst context = canvas.getContext( '2d' );\n\t\t\t\tcontext.drawImage( image, 0, 0, width, height );\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture has been resized from (' + dimensions.width + 'x' + dimensions.height + ') to (' + width + 'x' + height + ').' );\n\n\t\t\t\treturn canvas;\n\n\t\t\t} else {\n\n\t\t\t\tif ( 'data' in image ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Image in DataTexture is too big (' + dimensions.width + 'x' + dimensions.height + ').' );\n\n\t\t\t\t}\n\n\t\t\t\treturn image;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn image;\n\n\t}\n\n\tfunction textureNeedsGenerateMipmaps( texture ) {\n\n\t\treturn texture.generateMipmaps && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter;\n\n\t}\n\n\tfunction generateMipmap( target ) {\n\n\t\t_gl.generateMipmap( target );\n\n\t}\n\n\tfunction getInternalFormat( internalFormatName, glFormat, glType, colorSpace, forceLinearTransfer = false ) {\n\n\t\tif ( internalFormatName !== null ) {\n\n\t\t\tif ( _gl[ internalFormatName ] !== undefined ) return _gl[ internalFormatName ];\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: Attempt to use non-existing WebGL internal format \\'' + internalFormatName + '\\'' );\n\n\t\t}\n\n\t\tlet internalFormat = glFormat;\n\n\t\tif ( glFormat === _gl.RED ) {\n\n\t\t\tif ( glType === _gl.FLOAT ) internalFormat = _gl.R32F;\n\t\t\tif ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.R16F;\n\t\t\tif ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8;\n\n\t\t}\n\n\t\tif ( glFormat === _gl.RED_INTEGER ) {\n\n\t\t\tif ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.R8UI;\n\t\t\tif ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.R16UI;\n\t\t\tif ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.R32UI;\n\t\t\tif ( glType === _gl.BYTE ) internalFormat = _gl.R8I;\n\t\t\tif ( glType === _gl.SHORT ) internalFormat = _gl.R16I;\n\t\t\tif ( glType === _gl.INT ) internalFormat = _gl.R32I;\n\n\t\t}\n\n\t\tif ( glFormat === _gl.RG ) {\n\n\t\t\tif ( glType === _gl.FLOAT ) internalFormat = _gl.RG32F;\n\t\t\tif ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RG16F;\n\t\t\tif ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8;\n\n\t\t}\n\n\t\tif ( glFormat === _gl.RG_INTEGER ) {\n\n\t\t\tif ( glType === _gl.UNSIGNED_BYTE ) internalFormat = _gl.RG8UI;\n\t\t\tif ( glType === _gl.UNSIGNED_SHORT ) internalFormat = _gl.RG16UI;\n\t\t\tif ( glType === _gl.UNSIGNED_INT ) internalFormat = _gl.RG32UI;\n\t\t\tif ( glType === _gl.BYTE ) internalFormat = _gl.RG8I;\n\t\t\tif ( glType === _gl.SHORT ) internalFormat = _gl.RG16I;\n\t\t\tif ( glType === _gl.INT ) internalFormat = _gl.RG32I;\n\n\t\t}\n\n\t\tif ( glFormat === _gl.RGB ) {\n\n\t\t\tif ( glType === _gl.UNSIGNED_INT_5_9_9_9_REV ) internalFormat = _gl.RGB9_E5;\n\n\t\t}\n\n\t\tif ( glFormat === _gl.RGBA ) {\n\n\t\t\tconst transfer = forceLinearTransfer ? LinearTransfer : ColorManagement.getTransfer( colorSpace );\n\n\t\t\tif ( glType === _gl.FLOAT ) internalFormat = _gl.RGBA32F;\n\t\t\tif ( glType === _gl.HALF_FLOAT ) internalFormat = _gl.RGBA16F;\n\t\t\tif ( glType === _gl.UNSIGNED_BYTE ) internalFormat = ( transfer === SRGBTransfer ) ? _gl.SRGB8_ALPHA8 : _gl.RGBA8;\n\t\t\tif ( glType === _gl.UNSIGNED_SHORT_4_4_4_4 ) internalFormat = _gl.RGBA4;\n\t\t\tif ( glType === _gl.UNSIGNED_SHORT_5_5_5_1 ) internalFormat = _gl.RGB5_A1;\n\n\t\t}\n\n\t\tif ( internalFormat === _gl.R16F || internalFormat === _gl.R32F ||\n\t\t\tinternalFormat === _gl.RG16F || internalFormat === _gl.RG32F ||\n\t\t\tinternalFormat === _gl.RGBA16F || internalFormat === _gl.RGBA32F ) {\n\n\t\t\textensions.get( 'EXT_color_buffer_float' );\n\n\t\t}\n\n\t\treturn internalFormat;\n\n\t}\n\n\tfunction getInternalDepthFormat( useStencil, depthType ) {\n\n\t\tlet glInternalFormat;\n\t\tif ( useStencil ) {\n\n\t\t\tif ( depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH24_STENCIL8;\n\n\t\t\t} else if ( depthType === FloatType ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH32F_STENCIL8;\n\n\t\t\t} else if ( depthType === UnsignedShortType ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH24_STENCIL8;\n\t\t\t\tconsole.warn( 'DepthTexture: 16 bit depth attachment is not supported with stencil. Using 24-bit attachment.' );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif ( depthType === null || depthType === UnsignedIntType || depthType === UnsignedInt248Type ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH_COMPONENT24;\n\n\t\t\t} else if ( depthType === FloatType ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH_COMPONENT32F;\n\n\t\t\t} else if ( depthType === UnsignedShortType ) {\n\n\t\t\t\tglInternalFormat = _gl.DEPTH_COMPONENT16;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn glInternalFormat;\n\n\t}\n\n\tfunction getMipLevels( texture, image ) {\n\n\t\tif ( textureNeedsGenerateMipmaps( texture ) === true || ( texture.isFramebufferTexture && texture.minFilter !== NearestFilter && texture.minFilter !== LinearFilter ) ) {\n\n\t\t\treturn Math.log2( Math.max( image.width, image.height ) ) + 1;\n\n\t\t} else if ( texture.mipmaps !== undefined && texture.mipmaps.length > 0 ) {\n\n\t\t\t// user-defined mipmaps\n\n\t\t\treturn texture.mipmaps.length;\n\n\t\t} else if ( texture.isCompressedTexture && Array.isArray( texture.image ) ) {\n\n\t\t\treturn image.mipmaps.length;\n\n\t\t} else {\n\n\t\t\t// texture without mipmaps (only base level)\n\n\t\t\treturn 1;\n\n\t\t}\n\n\t}\n\n\t//\n\n\tfunction onTextureDispose( event ) {\n\n\t\tconst texture = event.target;\n\n\t\ttexture.removeEventListener( 'dispose', onTextureDispose );\n\n\t\tdeallocateTexture( texture );\n\n\t\tif ( texture.isVideoTexture ) {\n\n\t\t\t_videoTextures.delete( texture );\n\n\t\t}\n\n\t}\n\n\tfunction onRenderTargetDispose( event ) {\n\n\t\tconst renderTarget = event.target;\n\n\t\trenderTarget.removeEventListener( 'dispose', onRenderTargetDispose );\n\n\t\tdeallocateRenderTarget( renderTarget );\n\n\t}\n\n\t//\n\n\tfunction deallocateTexture( texture ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\n\t\tif ( textureProperties.__webglInit === undefined ) return;\n\n\t\t// check if it's necessary to remove the WebGLTexture object\n\n\t\tconst source = texture.source;\n\t\tconst webglTextures = _sources.get( source );\n\n\t\tif ( webglTextures ) {\n\n\t\t\tconst webglTexture = webglTextures[ textureProperties.__cacheKey ];\n\t\t\twebglTexture.usedTimes --;\n\n\t\t\t// the WebGLTexture object is not used anymore, remove it\n\n\t\t\tif ( webglTexture.usedTimes === 0 ) {\n\n\t\t\t\tdeleteTexture( texture );\n\n\t\t\t}\n\n\t\t\t// remove the weak map entry if no WebGLTexture uses the source anymore\n\n\t\t\tif ( Object.keys( webglTextures ).length === 0 ) {\n\n\t\t\t\t_sources.delete( source );\n\n\t\t\t}\n\n\t\t}\n\n\t\tproperties.remove( texture );\n\n\t}\n\n\tfunction deleteTexture( texture ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\t\t_gl.deleteTexture( textureProperties.__webglTexture );\n\n\t\tconst source = texture.source;\n\t\tconst webglTextures = _sources.get( source );\n\t\tdelete webglTextures[ textureProperties.__cacheKey ];\n\n\t\tinfo.memory.textures --;\n\n\t}\n\n\tfunction deallocateRenderTarget( renderTarget ) {\n\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\n\t\tif ( renderTarget.depthTexture ) {\n\n\t\t\trenderTarget.depthTexture.dispose();\n\n\t\t}\n\n\t\tif ( renderTarget.isWebGLCubeRenderTarget ) {\n\n\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\tif ( Array.isArray( renderTargetProperties.__webglFramebuffer[ i ] ) ) {\n\n\t\t\t\t\tfor ( let level = 0; level < renderTargetProperties.__webglFramebuffer[ i ].length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ][ level ] );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ i ] );\n\n\t\t\t\t}\n\n\t\t\t\tif ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer[ i ] );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif ( Array.isArray( renderTargetProperties.__webglFramebuffer ) ) {\n\n\t\t\t\tfor ( let level = 0; level < renderTargetProperties.__webglFramebuffer.length; level ++ ) _gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer[ level ] );\n\n\t\t\t} else {\n\n\t\t\t\t_gl.deleteFramebuffer( renderTargetProperties.__webglFramebuffer );\n\n\t\t\t}\n\n\t\t\tif ( renderTargetProperties.__webglDepthbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthbuffer );\n\t\t\tif ( renderTargetProperties.__webglMultisampledFramebuffer ) _gl.deleteFramebuffer( renderTargetProperties.__webglMultisampledFramebuffer );\n\n\t\t\tif ( renderTargetProperties.__webglColorRenderbuffer ) {\n\n\t\t\t\tfor ( let i = 0; i < renderTargetProperties.__webglColorRenderbuffer.length; i ++ ) {\n\n\t\t\t\t\tif ( renderTargetProperties.__webglColorRenderbuffer[ i ] ) _gl.deleteRenderbuffer( renderTargetProperties.__webglColorRenderbuffer[ i ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( renderTargetProperties.__webglDepthRenderbuffer ) _gl.deleteRenderbuffer( renderTargetProperties.__webglDepthRenderbuffer );\n\n\t\t}\n\n\t\tconst textures = renderTarget.textures;\n\n\t\tfor ( let i = 0, il = textures.length; i < il; i ++ ) {\n\n\t\t\tconst attachmentProperties = properties.get( textures[ i ] );\n\n\t\t\tif ( attachmentProperties.__webglTexture ) {\n\n\t\t\t\t_gl.deleteTexture( attachmentProperties.__webglTexture );\n\n\t\t\t\tinfo.memory.textures --;\n\n\t\t\t}\n\n\t\t\tproperties.remove( textures[ i ] );\n\n\t\t}\n\n\t\tproperties.remove( renderTarget );\n\n\t}\n\n\t//\n\n\tlet textureUnits = 0;\n\n\tfunction resetTextureUnits() {\n\n\t\ttextureUnits = 0;\n\n\t}\n\n\tfunction allocateTextureUnit() {\n\n\t\tconst textureUnit = textureUnits;\n\n\t\tif ( textureUnit >= capabilities.maxTextures ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLTextures: Trying to use ' + textureUnit + ' texture units while this GPU supports only ' + capabilities.maxTextures );\n\n\t\t}\n\n\t\ttextureUnits += 1;\n\n\t\treturn textureUnit;\n\n\t}\n\n\tfunction getTextureCacheKey( texture ) {\n\n\t\tconst array = [];\n\n\t\tarray.push( texture.wrapS );\n\t\tarray.push( texture.wrapT );\n\t\tarray.push( texture.wrapR || 0 );\n\t\tarray.push( texture.magFilter );\n\t\tarray.push( texture.minFilter );\n\t\tarray.push( texture.anisotropy );\n\t\tarray.push( texture.internalFormat );\n\t\tarray.push( texture.format );\n\t\tarray.push( texture.type );\n\t\tarray.push( texture.generateMipmaps );\n\t\tarray.push( texture.premultiplyAlpha );\n\t\tarray.push( texture.flipY );\n\t\tarray.push( texture.unpackAlignment );\n\t\tarray.push( texture.colorSpace );\n\n\t\treturn array.join();\n\n\t}\n\n\t//\n\n\tfunction setTexture2D( texture, slot ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\n\t\tif ( texture.isVideoTexture ) updateVideoTexture( texture );\n\n\t\tif ( texture.isRenderTargetTexture === false && texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\tconst image = texture.image;\n\n\t\t\tif ( image === null ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture marked for update but no image data found.' );\n\n\t\t\t} else if ( image.complete === false ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture marked for update but image is incomplete' );\n\n\t\t\t} else {\n\n\t\t\t\tuploadTexture( textureProperties, texture, slot );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t}\n\n\t\tstate.bindTexture( _gl.TEXTURE_2D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t}\n\n\tfunction setTexture2DArray( texture, slot ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\n\t\tif ( texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\tuploadTexture( textureProperties, texture, slot );\n\t\t\treturn;\n\n\t\t}\n\n\t\tstate.bindTexture( _gl.TEXTURE_2D_ARRAY, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t}\n\n\tfunction setTexture3D( texture, slot ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\n\t\tif ( texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\tuploadTexture( textureProperties, texture, slot );\n\t\t\treturn;\n\n\t\t}\n\n\t\tstate.bindTexture( _gl.TEXTURE_3D, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t}\n\n\tfunction setTextureCube( texture, slot ) {\n\n\t\tconst textureProperties = properties.get( texture );\n\n\t\tif ( texture.version > 0 && textureProperties.__version !== texture.version ) {\n\n\t\t\tuploadCubeTexture( textureProperties, texture, slot );\n\t\t\treturn;\n\n\t\t}\n\n\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t}\n\n\tconst wrappingToGL = {\n\t\t[ RepeatWrapping ]: _gl.REPEAT,\n\t\t[ ClampToEdgeWrapping ]: _gl.CLAMP_TO_EDGE,\n\t\t[ MirroredRepeatWrapping ]: _gl.MIRRORED_REPEAT\n\t};\n\n\tconst filterToGL = {\n\t\t[ NearestFilter ]: _gl.NEAREST,\n\t\t[ NearestMipmapNearestFilter ]: _gl.NEAREST_MIPMAP_NEAREST,\n\t\t[ NearestMipmapLinearFilter ]: _gl.NEAREST_MIPMAP_LINEAR,\n\n\t\t[ LinearFilter ]: _gl.LINEAR,\n\t\t[ LinearMipmapNearestFilter ]: _gl.LINEAR_MIPMAP_NEAREST,\n\t\t[ LinearMipmapLinearFilter ]: _gl.LINEAR_MIPMAP_LINEAR\n\t};\n\n\tconst compareToGL = {\n\t\t[ NeverCompare ]: _gl.NEVER,\n\t\t[ AlwaysCompare ]: _gl.ALWAYS,\n\t\t[ LessCompare ]: _gl.LESS,\n\t\t[ LessEqualCompare ]: _gl.LEQUAL,\n\t\t[ EqualCompare ]: _gl.EQUAL,\n\t\t[ GreaterEqualCompare ]: _gl.GEQUAL,\n\t\t[ GreaterCompare ]: _gl.GREATER,\n\t\t[ NotEqualCompare ]: _gl.NOTEQUAL\n\t};\n\n\tfunction setTextureParameters( textureType, texture ) {\n\n\t\tif ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false &&\n\t\t\t( texture.magFilter === LinearFilter || texture.magFilter === LinearMipmapNearestFilter || texture.magFilter === NearestMipmapLinearFilter || texture.magFilter === LinearMipmapLinearFilter ||\n\t\t\ttexture.minFilter === LinearFilter || texture.minFilter === LinearMipmapNearestFilter || texture.minFilter === NearestMipmapLinearFilter || texture.minFilter === LinearMipmapLinearFilter ) ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: Unable to use linear filtering with floating point textures. OES_texture_float_linear not supported on this device.' );\n\n\t\t}\n\n\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_S, wrappingToGL[ texture.wrapS ] );\n\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_T, wrappingToGL[ texture.wrapT ] );\n\n\t\tif ( textureType === _gl.TEXTURE_3D || textureType === _gl.TEXTURE_2D_ARRAY ) {\n\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_WRAP_R, wrappingToGL[ texture.wrapR ] );\n\n\t\t}\n\n\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MAG_FILTER, filterToGL[ texture.magFilter ] );\n\t\t_gl.texParameteri( textureType, _gl.TEXTURE_MIN_FILTER, filterToGL[ texture.minFilter ] );\n\n\t\tif ( texture.compareFunction ) {\n\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_MODE, _gl.COMPARE_REF_TO_TEXTURE );\n\t\t\t_gl.texParameteri( textureType, _gl.TEXTURE_COMPARE_FUNC, compareToGL[ texture.compareFunction ] );\n\n\t\t}\n\n\t\tif ( extensions.has( 'EXT_texture_filter_anisotropic' ) === true ) {\n\n\t\t\tif ( texture.magFilter === NearestFilter ) return;\n\t\t\tif ( texture.minFilter !== NearestMipmapLinearFilter && texture.minFilter !== LinearMipmapLinearFilter ) return;\n\t\t\tif ( texture.type === FloatType && extensions.has( 'OES_texture_float_linear' ) === false ) return; // verify extension\n\n\t\t\tif ( texture.anisotropy > 1 || properties.get( texture ).__currentAnisotropy ) {\n\n\t\t\t\tconst extension = extensions.get( 'EXT_texture_filter_anisotropic' );\n\t\t\t\t_gl.texParameterf( textureType, extension.TEXTURE_MAX_ANISOTROPY_EXT, Math.min( texture.anisotropy, capabilities.getMaxAnisotropy() ) );\n\t\t\t\tproperties.get( texture ).__currentAnisotropy = texture.anisotropy;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction initTexture( textureProperties, texture ) {\n\n\t\tlet forceUpload = false;\n\n\t\tif ( textureProperties.__webglInit === undefined ) {\n\n\t\t\ttextureProperties.__webglInit = true;\n\n\t\t\ttexture.addEventListener( 'dispose', onTextureDispose );\n\n\t\t}\n\n\t\t// create Source <-> WebGLTextures mapping if necessary\n\n\t\tconst source = texture.source;\n\t\tlet webglTextures = _sources.get( source );\n\n\t\tif ( webglTextures === undefined ) {\n\n\t\t\twebglTextures = {};\n\t\t\t_sources.set( source, webglTextures );\n\n\t\t}\n\n\t\t// check if there is already a WebGLTexture object for the given texture parameters\n\n\t\tconst textureCacheKey = getTextureCacheKey( texture );\n\n\t\tif ( textureCacheKey !== textureProperties.__cacheKey ) {\n\n\t\t\t// if not, create a new instance of WebGLTexture\n\n\t\t\tif ( webglTextures[ textureCacheKey ] === undefined ) {\n\n\t\t\t\t// create new entry\n\n\t\t\t\twebglTextures[ textureCacheKey ] = {\n\t\t\t\t\ttexture: _gl.createTexture(),\n\t\t\t\t\tusedTimes: 0\n\t\t\t\t};\n\n\t\t\t\tinfo.memory.textures ++;\n\n\t\t\t\t// when a new instance of WebGLTexture was created, a texture upload is required\n\t\t\t\t// even if the image contents are identical\n\n\t\t\t\tforceUpload = true;\n\n\t\t\t}\n\n\t\t\twebglTextures[ textureCacheKey ].usedTimes ++;\n\n\t\t\t// every time the texture cache key changes, it's necessary to check if an instance of\n\t\t\t// WebGLTexture can be deleted in order to avoid a memory leak.\n\n\t\t\tconst webglTexture = webglTextures[ textureProperties.__cacheKey ];\n\n\t\t\tif ( webglTexture !== undefined ) {\n\n\t\t\t\twebglTextures[ textureProperties.__cacheKey ].usedTimes --;\n\n\t\t\t\tif ( webglTexture.usedTimes === 0 ) {\n\n\t\t\t\t\tdeleteTexture( texture );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// store references to cache key and WebGLTexture object\n\n\t\t\ttextureProperties.__cacheKey = textureCacheKey;\n\t\t\ttextureProperties.__webglTexture = webglTextures[ textureCacheKey ].texture;\n\n\t\t}\n\n\t\treturn forceUpload;\n\n\t}\n\n\tfunction uploadTexture( textureProperties, texture, slot ) {\n\n\t\tlet textureType = _gl.TEXTURE_2D;\n\n\t\tif ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) textureType = _gl.TEXTURE_2D_ARRAY;\n\t\tif ( texture.isData3DTexture ) textureType = _gl.TEXTURE_3D;\n\n\t\tconst forceUpload = initTexture( textureProperties, texture );\n\t\tconst source = texture.source;\n\n\t\tstate.bindTexture( textureType, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t\tconst sourceProperties = properties.get( source );\n\n\t\tif ( source.version !== sourceProperties.__version || forceUpload === true ) {\n\n\t\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\n\t\t\tconst workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );\n\t\t\tconst texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );\n\t\t\tconst unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );\n\n\t\t\tlet image = resizeImage( texture.image, false, capabilities.maxTextureSize );\n\t\t\timage = verifyColorSpace( texture, image );\n\n\t\t\tconst glFormat = utils.convert( texture.format, texture.colorSpace );\n\n\t\t\tconst glType = utils.convert( texture.type );\n\t\t\tlet glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, texture.isVideoTexture );\n\n\t\t\tsetTextureParameters( textureType, texture );\n\n\t\t\tlet mipmap;\n\t\t\tconst mipmaps = texture.mipmaps;\n\n\t\t\tconst useTexStorage = ( texture.isVideoTexture !== true );\n\t\t\tconst allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );\n\t\t\tconst dataReady = source.dataReady;\n\t\t\tconst levels = getMipLevels( texture, image );\n\n\t\t\tif ( texture.isDepthTexture ) {\n\n\t\t\t\tglInternalFormat = getInternalDepthFormat( texture.format === DepthStencilFormat, texture.type );\n\n\t\t\t\t//\n\n\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, 1, glInternalFormat, image.width, image.height );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, null );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( texture.isDataTexture ) {\n\n\t\t\t\t// use manually created mipmaps if available\n\t\t\t\t// if there are no manual mipmaps\n\t\t\t\t// set 0 level mipmap and then use GL to generate other mipmap levels\n\n\t\t\t\tif ( mipmaps.length > 0 ) {\n\n\t\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( let i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tmipmap = mipmaps[ i ];\n\n\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture.generateMipmaps = false;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, image.width, image.height, glFormat, glType, image.data );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, image.width, image.height, 0, glFormat, glType, image.data );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( texture.isCompressedTexture ) {\n\n\t\t\t\tif ( texture.isCompressedArrayTexture ) {\n\n\t\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\t\tstate.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height, image.depth );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( let i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tmipmap = mipmaps[ i ];\n\n\t\t\t\t\t\tif ( texture.format !== RGBAFormat ) {\n\n\t\t\t\t\t\t\tif ( glFormat !== null ) {\n\n\t\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\t\tif ( texture.layerUpdates.size > 0 ) {\n\n\t\t\t\t\t\t\t\t\t\t\tconst layerByteLength = getByteLength( mipmap.width, mipmap.height, texture.format, texture.type );\n\n\t\t\t\t\t\t\t\t\t\t\tfor ( const layerIndex of texture.layerUpdates ) {\n\n\t\t\t\t\t\t\t\t\t\t\t\tconst layerData = mipmap.data.subarray(\n\t\t\t\t\t\t\t\t\t\t\t\t\tlayerIndex * layerByteLength / mipmap.data.BYTES_PER_ELEMENT,\n\t\t\t\t\t\t\t\t\t\t\t\t\t( layerIndex + 1 ) * layerByteLength / mipmap.data.BYTES_PER_ELEMENT\n\t\t\t\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t\t\t\t\tstate.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, layerIndex, mipmap.width, mipmap.height, 1, glFormat, layerData, 0, 0 );\n\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\ttexture.clearLayerUpdates();\n\n\t\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\t\tstate.compressedTexSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, mipmap.data, 0, 0 );\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\tstate.compressedTexImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, mipmap.data, 0, 0 );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\tstate.texSubImage3D( _gl.TEXTURE_2D_ARRAY, i, 0, 0, 0, mipmap.width, mipmap.height, image.depth, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage3D( _gl.TEXTURE_2D_ARRAY, i, glInternalFormat, mipmap.width, mipmap.height, image.depth, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, mipmaps[ 0 ].width, mipmaps[ 0 ].height );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( let i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tmipmap = mipmaps[ i ];\n\n\t\t\t\t\t\tif ( texture.format !== RGBAFormat ) {\n\n\t\t\t\t\t\t\tif ( glFormat !== null ) {\n\n\t\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\t\tstate.compressedTexSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\tstate.compressedTexImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .uploadTexture()' );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( texture.isDataArrayTexture ) {\n\n\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\t\tstate.texStorage3D( _gl.TEXTURE_2D_ARRAY, levels, glInternalFormat, image.width, image.height, image.depth );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\tif ( texture.layerUpdates.size > 0 ) {\n\n\t\t\t\t\t\t\tconst layerByteLength = getByteLength( image.width, image.height, texture.format, texture.type );\n\n\t\t\t\t\t\t\tfor ( const layerIndex of texture.layerUpdates ) {\n\n\t\t\t\t\t\t\t\tconst layerData = image.data.subarray(\n\t\t\t\t\t\t\t\t\tlayerIndex * layerByteLength / image.data.BYTES_PER_ELEMENT,\n\t\t\t\t\t\t\t\t\t( layerIndex + 1 ) * layerByteLength / image.data.BYTES_PER_ELEMENT\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\tstate.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, layerIndex, image.width, image.height, 1, glFormat, glType, layerData );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\ttexture.clearLayerUpdates();\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.texSubImage3D( _gl.TEXTURE_2D_ARRAY, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tstate.texImage3D( _gl.TEXTURE_2D_ARRAY, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );\n\n\t\t\t\t}\n\n\t\t\t} else if ( texture.isData3DTexture ) {\n\n\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\t\tstate.texStorage3D( _gl.TEXTURE_3D, levels, glInternalFormat, image.width, image.height, image.depth );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\tstate.texSubImage3D( _gl.TEXTURE_3D, 0, 0, 0, 0, image.width, image.height, image.depth, glFormat, glType, image.data );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tstate.texImage3D( _gl.TEXTURE_3D, 0, glInternalFormat, image.width, image.height, image.depth, 0, glFormat, glType, image.data );\n\n\t\t\t\t}\n\n\t\t\t} else if ( texture.isFramebufferTexture ) {\n\n\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, image.width, image.height );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tlet width = image.width, height = image.height;\n\n\t\t\t\t\t\tfor ( let i = 0; i < levels; i ++ ) {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, width, height, 0, glFormat, glType, null );\n\n\t\t\t\t\t\t\twidth >>= 1;\n\t\t\t\t\t\t\theight >>= 1;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// regular Texture (image, video, canvas)\n\n\t\t\t\t// use manually created mipmaps if available\n\t\t\t\t// if there are no manual mipmaps\n\t\t\t\t// set 0 level mipmap and then use GL to generate other mipmap levels\n\n\t\t\t\tif ( mipmaps.length > 0 ) {\n\n\t\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\t\tconst dimensions = getDimensions( mipmaps[ 0 ] );\n\n\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tfor ( let i = 0, il = mipmaps.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tmipmap = mipmaps[ i ];\n\n\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_2D, i, 0, 0, glFormat, glType, mipmap );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, i, glInternalFormat, glFormat, glType, mipmap );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture.generateMipmaps = false;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\tif ( allocateMemory ) {\n\n\t\t\t\t\t\t\tconst dimensions = getDimensions( image );\n\n\t\t\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_2D, levels, glInternalFormat, dimensions.width, dimensions.height );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_2D, 0, 0, 0, glFormat, glType, image );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_2D, 0, glInternalFormat, glFormat, glType, image );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture ) ) {\n\n\t\t\t\tgenerateMipmap( textureType );\n\n\t\t\t}\n\n\t\t\tsourceProperties.__version = source.version;\n\n\t\t\tif ( texture.onUpdate ) texture.onUpdate( texture );\n\n\t\t}\n\n\t\ttextureProperties.__version = texture.version;\n\n\t}\n\n\tfunction uploadCubeTexture( textureProperties, texture, slot ) {\n\n\t\tif ( texture.image.length !== 6 ) return;\n\n\t\tconst forceUpload = initTexture( textureProperties, texture );\n\t\tconst source = texture.source;\n\n\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture, _gl.TEXTURE0 + slot );\n\n\t\tconst sourceProperties = properties.get( source );\n\n\t\tif ( source.version !== sourceProperties.__version || forceUpload === true ) {\n\n\t\t\tstate.activeTexture( _gl.TEXTURE0 + slot );\n\n\t\t\tconst workingPrimaries = ColorManagement.getPrimaries( ColorManagement.workingColorSpace );\n\t\t\tconst texturePrimaries = texture.colorSpace === NoColorSpace ? null : ColorManagement.getPrimaries( texture.colorSpace );\n\t\t\tconst unpackConversion = texture.colorSpace === NoColorSpace || workingPrimaries === texturePrimaries ? _gl.NONE : _gl.BROWSER_DEFAULT_WEBGL;\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, texture.flipY );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, texture.premultiplyAlpha );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, texture.unpackAlignment );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_COLORSPACE_CONVERSION_WEBGL, unpackConversion );\n\n\t\t\tconst isCompressed = ( texture.isCompressedTexture || texture.image[ 0 ].isCompressedTexture );\n\t\t\tconst isDataTexture = ( texture.image[ 0 ] && texture.image[ 0 ].isDataTexture );\n\n\t\t\tconst cubeImage = [];\n\n\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\tif ( ! isCompressed && ! isDataTexture ) {\n\n\t\t\t\t\tcubeImage[ i ] = resizeImage( texture.image[ i ], true, capabilities.maxCubemapSize );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tcubeImage[ i ] = isDataTexture ? texture.image[ i ].image : texture.image[ i ];\n\n\t\t\t\t}\n\n\t\t\t\tcubeImage[ i ] = verifyColorSpace( texture, cubeImage[ i ] );\n\n\t\t\t}\n\n\t\t\tconst image = cubeImage[ 0 ],\n\t\t\t\tglFormat = utils.convert( texture.format, texture.colorSpace ),\n\t\t\t\tglType = utils.convert( texture.type ),\n\t\t\t\tglInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );\n\n\t\t\tconst useTexStorage = ( texture.isVideoTexture !== true );\n\t\t\tconst allocateMemory = ( sourceProperties.__version === undefined ) || ( forceUpload === true );\n\t\t\tconst dataReady = source.dataReady;\n\t\t\tlet levels = getMipLevels( texture, image );\n\n\t\t\tsetTextureParameters( _gl.TEXTURE_CUBE_MAP, texture );\n\n\t\t\tlet mipmaps;\n\n\t\t\tif ( isCompressed ) {\n\n\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, image.width, image.height );\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\tmipmaps = cubeImage[ i ].mipmaps;\n\n\t\t\t\t\tfor ( let j = 0; j < mipmaps.length; j ++ ) {\n\n\t\t\t\t\t\tconst mipmap = mipmaps[ j ];\n\n\t\t\t\t\t\tif ( texture.format !== RGBAFormat ) {\n\n\t\t\t\t\t\t\tif ( glFormat !== null ) {\n\n\t\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\t\tstate.compressedTexSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, mipmap.data );\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\tstate.compressedTexImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, mipmap.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Attempt to load unsupported compressed texture format in .setTextureCube()' );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, 0, 0, mipmap.width, mipmap.height, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j, glInternalFormat, mipmap.width, mipmap.height, 0, glFormat, glType, mipmap.data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tmipmaps = texture.mipmaps;\n\n\t\t\t\tif ( useTexStorage && allocateMemory ) {\n\n\t\t\t\t\t// TODO: Uniformly handle mipmap definitions\n\t\t\t\t\t// Normal textures and compressed cube textures define base level + mips with their mipmap array\n\t\t\t\t\t// Uncompressed cube textures use their mipmap array only for mips (no base level)\n\n\t\t\t\t\tif ( mipmaps.length > 0 ) levels ++;\n\n\t\t\t\t\tconst dimensions = getDimensions( cubeImage[ 0 ] );\n\n\t\t\t\t\tstate.texStorage2D( _gl.TEXTURE_CUBE_MAP, levels, glInternalFormat, dimensions.width, dimensions.height );\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\tif ( isDataTexture ) {\n\n\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, cubeImage[ i ].width, cubeImage[ i ].height, glFormat, glType, cubeImage[ i ].data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, cubeImage[ i ].width, cubeImage[ i ].height, 0, glFormat, glType, cubeImage[ i ].data );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor ( let j = 0; j < mipmaps.length; j ++ ) {\n\n\t\t\t\t\t\t\tconst mipmap = mipmaps[ j ];\n\t\t\t\t\t\t\tconst mipmapImage = mipmap.image[ i ].image;\n\n\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, mipmapImage.width, mipmapImage.height, glFormat, glType, mipmapImage.data );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, mipmapImage.width, mipmapImage.height, 0, glFormat, glType, mipmapImage.data );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, 0, 0, glFormat, glType, cubeImage[ i ] );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, glInternalFormat, glFormat, glType, cubeImage[ i ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tfor ( let j = 0; j < mipmaps.length; j ++ ) {\n\n\t\t\t\t\t\t\tconst mipmap = mipmaps[ j ];\n\n\t\t\t\t\t\t\tif ( useTexStorage ) {\n\n\t\t\t\t\t\t\t\tif ( dataReady ) {\n\n\t\t\t\t\t\t\t\t\tstate.texSubImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, 0, 0, glFormat, glType, mipmap.image[ i ] );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tstate.texImage2D( _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, j + 1, glInternalFormat, glFormat, glType, mipmap.image[ i ] );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture ) ) {\n\n\t\t\t\t// We assume images for cube map have the same size.\n\t\t\t\tgenerateMipmap( _gl.TEXTURE_CUBE_MAP );\n\n\t\t\t}\n\n\t\t\tsourceProperties.__version = source.version;\n\n\t\t\tif ( texture.onUpdate ) texture.onUpdate( texture );\n\n\t\t}\n\n\t\ttextureProperties.__version = texture.version;\n\n\t}\n\n\t// Render targets\n\n\t// Setup storage for target texture and bind it to correct framebuffer\n\tfunction setupFrameBufferTexture( framebuffer, renderTarget, texture, attachment, textureTarget, level ) {\n\n\t\tconst glFormat = utils.convert( texture.format, texture.colorSpace );\n\t\tconst glType = utils.convert( texture.type );\n\t\tconst glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\n\t\tif ( ! renderTargetProperties.__hasExternalTextures ) {\n\n\t\t\tconst width = Math.max( 1, renderTarget.width >> level );\n\t\t\tconst height = Math.max( 1, renderTarget.height >> level );\n\n\t\t\tif ( textureTarget === _gl.TEXTURE_3D || textureTarget === _gl.TEXTURE_2D_ARRAY ) {\n\n\t\t\t\tstate.texImage3D( textureTarget, level, glInternalFormat, width, height, renderTarget.depth, 0, glFormat, glType, null );\n\n\t\t\t} else {\n\n\t\t\t\tstate.texImage2D( textureTarget, level, glInternalFormat, width, height, 0, glFormat, glType, null );\n\n\t\t\t}\n\n\t\t}\n\n\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\tif ( useMultisampledRTT( renderTarget ) ) {\n\n\t\t\tmultisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, 0, getRenderTargetSamples( renderTarget ) );\n\n\t\t} else if ( textureTarget === _gl.TEXTURE_2D || ( textureTarget >= _gl.TEXTURE_CUBE_MAP_POSITIVE_X && textureTarget <= _gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ) ) { // see #24753\n\n\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, attachment, textureTarget, properties.get( texture ).__webglTexture, level );\n\n\t\t}\n\n\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\n\t}\n\n\t// Setup storage for internal depth/stencil buffers and bind to correct framebuffer\n\tfunction setupRenderBufferStorage( renderbuffer, renderTarget, isMultisample ) {\n\n\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderbuffer );\n\n\t\tif ( renderTarget.depthBuffer ) {\n\n\t\t\t// retrieve the depth attachment types\n\t\t\tconst depthTexture = renderTarget.depthTexture;\n\t\t\tconst depthType = depthTexture && depthTexture.isDepthTexture ? depthTexture.type : null;\n\t\t\tconst glInternalFormat = getInternalDepthFormat( renderTarget.stencilBuffer, depthType );\n\t\t\tconst glAttachmentType = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;\n\n\t\t\t// set up the attachment\n\t\t\tconst samples = getRenderTargetSamples( renderTarget );\n\t\t\tconst isUseMultisampledRTT = useMultisampledRTT( renderTarget );\n\t\t\tif ( isUseMultisampledRTT ) {\n\n\t\t\t\tmultisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t} else if ( isMultisample ) {\n\n\t\t\t\t_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t} else {\n\n\t\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t}\n\n\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, glAttachmentType, _gl.RENDERBUFFER, renderbuffer );\n\n\t\t} else {\n\n\t\t\tconst textures = renderTarget.textures;\n\n\t\t\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\t\t\tconst texture = textures[ i ];\n\n\t\t\t\tconst glFormat = utils.convert( texture.format, texture.colorSpace );\n\t\t\t\tconst glType = utils.convert( texture.type );\n\t\t\t\tconst glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace );\n\t\t\t\tconst samples = getRenderTargetSamples( renderTarget );\n\n\t\t\t\tif ( isMultisample && useMultisampledRTT( renderTarget ) === false ) {\n\n\t\t\t\t\t_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t\t} else if ( useMultisampledRTT( renderTarget ) ) {\n\n\t\t\t\t\tmultisampledRTTExt.renderbufferStorageMultisampleEXT( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_gl.renderbufferStorage( _gl.RENDERBUFFER, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );\n\n\t}\n\n\t// Setup resources for a Depth Texture for a FBO (needs an extension)\n\tfunction setupDepthTexture( framebuffer, renderTarget ) {\n\n\t\tconst isCube = ( renderTarget && renderTarget.isWebGLCubeRenderTarget );\n\t\tif ( isCube ) throw new Error( 'Depth Texture with cube render targets is not supported' );\n\n\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\tif ( ! ( renderTarget.depthTexture && renderTarget.depthTexture.isDepthTexture ) ) {\n\n\t\t\tthrow new Error( 'renderTarget.depthTexture must be an instance of THREE.DepthTexture' );\n\n\t\t}\n\n\t\t// upload an empty depth texture with framebuffer size\n\t\tif ( ! properties.get( renderTarget.depthTexture ).__webglTexture ||\n\t\t\t\trenderTarget.depthTexture.image.width !== renderTarget.width ||\n\t\t\t\trenderTarget.depthTexture.image.height !== renderTarget.height ) {\n\n\t\t\trenderTarget.depthTexture.image.width = renderTarget.width;\n\t\t\trenderTarget.depthTexture.image.height = renderTarget.height;\n\t\t\trenderTarget.depthTexture.needsUpdate = true;\n\n\t\t}\n\n\t\tsetTexture2D( renderTarget.depthTexture, 0 );\n\n\t\tconst webglDepthTexture = properties.get( renderTarget.depthTexture ).__webglTexture;\n\t\tconst samples = getRenderTargetSamples( renderTarget );\n\n\t\tif ( renderTarget.depthTexture.format === DepthFormat ) {\n\n\t\t\tif ( useMultisampledRTT( renderTarget ) ) {\n\n\t\t\t\tmultisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );\n\n\t\t\t} else {\n\n\t\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );\n\n\t\t\t}\n\n\t\t} else if ( renderTarget.depthTexture.format === DepthStencilFormat ) {\n\n\t\t\tif ( useMultisampledRTT( renderTarget ) ) {\n\n\t\t\t\tmultisampledRTTExt.framebufferTexture2DMultisampleEXT( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0, samples );\n\n\t\t\t} else {\n\n\t\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.DEPTH_STENCIL_ATTACHMENT, _gl.TEXTURE_2D, webglDepthTexture, 0 );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tthrow new Error( 'Unknown depthTexture format' );\n\n\t\t}\n\n\t}\n\n\t// Setup GL resources for a non-texture depth buffer\n\tfunction setupDepthRenderbuffer( renderTarget ) {\n\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\t\tconst isCube = ( renderTarget.isWebGLCubeRenderTarget === true );\n\n\t\tif ( renderTarget.depthTexture && ! renderTargetProperties.__autoAllocateDepthBuffer ) {\n\n\t\t\tif ( isCube ) throw new Error( 'target.depthTexture not supported in Cube render targets' );\n\n\t\t\tsetupDepthTexture( renderTargetProperties.__webglFramebuffer, renderTarget );\n\n\t\t} else {\n\n\t\t\tif ( isCube ) {\n\n\t\t\t\trenderTargetProperties.__webglDepthbuffer = [];\n\n\t\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer[ i ] );\n\t\t\t\t\trenderTargetProperties.__webglDepthbuffer[ i ] = _gl.createRenderbuffer();\n\t\t\t\t\tsetupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer[ i ], renderTarget, false );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );\n\t\t\t\trenderTargetProperties.__webglDepthbuffer = _gl.createRenderbuffer();\n\t\t\t\tsetupRenderBufferStorage( renderTargetProperties.__webglDepthbuffer, renderTarget, false );\n\n\t\t\t}\n\n\t\t}\n\n\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\n\t}\n\n\t// rebind framebuffer with external textures\n\tfunction rebindTextures( renderTarget, colorTexture, depthTexture ) {\n\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\n\t\tif ( colorTexture !== undefined ) {\n\n\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, renderTarget.texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, 0 );\n\n\t\t}\n\n\t\tif ( depthTexture !== undefined ) {\n\n\t\t\tsetupDepthRenderbuffer( renderTarget );\n\n\t\t}\n\n\t}\n\n\t// Set up GL resources for the render target\n\tfunction setupRenderTarget( renderTarget ) {\n\n\t\tconst texture = renderTarget.texture;\n\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\t\tconst textureProperties = properties.get( texture );\n\n\t\trenderTarget.addEventListener( 'dispose', onRenderTargetDispose );\n\n\t\tconst textures = renderTarget.textures;\n\n\t\tconst isCube = ( renderTarget.isWebGLCubeRenderTarget === true );\n\t\tconst isMultipleRenderTargets = ( textures.length > 1 );\n\n\t\tif ( ! isMultipleRenderTargets ) {\n\n\t\t\tif ( textureProperties.__webglTexture === undefined ) {\n\n\t\t\t\ttextureProperties.__webglTexture = _gl.createTexture();\n\n\t\t\t}\n\n\t\t\ttextureProperties.__version = texture.version;\n\t\t\tinfo.memory.textures ++;\n\n\t\t}\n\n\t\t// Setup framebuffer\n\n\t\tif ( isCube ) {\n\n\t\t\trenderTargetProperties.__webglFramebuffer = [];\n\n\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\tif ( texture.mipmaps && texture.mipmaps.length > 0 ) {\n\n\t\t\t\t\trenderTargetProperties.__webglFramebuffer[ i ] = [];\n\n\t\t\t\t\tfor ( let level = 0; level < texture.mipmaps.length; level ++ ) {\n\n\t\t\t\t\t\trenderTargetProperties.__webglFramebuffer[ i ][ level ] = _gl.createFramebuffer();\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\trenderTargetProperties.__webglFramebuffer[ i ] = _gl.createFramebuffer();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tif ( texture.mipmaps && texture.mipmaps.length > 0 ) {\n\n\t\t\t\trenderTargetProperties.__webglFramebuffer = [];\n\n\t\t\t\tfor ( let level = 0; level < texture.mipmaps.length; level ++ ) {\n\n\t\t\t\t\trenderTargetProperties.__webglFramebuffer[ level ] = _gl.createFramebuffer();\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\trenderTargetProperties.__webglFramebuffer = _gl.createFramebuffer();\n\n\t\t\t}\n\n\t\t\tif ( isMultipleRenderTargets ) {\n\n\t\t\t\tfor ( let i = 0, il = textures.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst attachmentProperties = properties.get( textures[ i ] );\n\n\t\t\t\t\tif ( attachmentProperties.__webglTexture === undefined ) {\n\n\t\t\t\t\t\tattachmentProperties.__webglTexture = _gl.createTexture();\n\n\t\t\t\t\t\tinfo.memory.textures ++;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( ( renderTarget.samples > 0 ) && useMultisampledRTT( renderTarget ) === false ) {\n\n\t\t\t\trenderTargetProperties.__webglMultisampledFramebuffer = _gl.createFramebuffer();\n\t\t\t\trenderTargetProperties.__webglColorRenderbuffer = [];\n\n\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );\n\n\t\t\t\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\t\t\t\tconst texture = textures[ i ];\n\t\t\t\t\trenderTargetProperties.__webglColorRenderbuffer[ i ] = _gl.createRenderbuffer();\n\n\t\t\t\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );\n\n\t\t\t\t\tconst glFormat = utils.convert( texture.format, texture.colorSpace );\n\t\t\t\t\tconst glType = utils.convert( texture.type );\n\t\t\t\t\tconst glInternalFormat = getInternalFormat( texture.internalFormat, glFormat, glType, texture.colorSpace, renderTarget.isXRRenderTarget === true );\n\t\t\t\t\tconst samples = getRenderTargetSamples( renderTarget );\n\t\t\t\t\t_gl.renderbufferStorageMultisample( _gl.RENDERBUFFER, samples, glInternalFormat, renderTarget.width, renderTarget.height );\n\n\t\t\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );\n\n\t\t\t\t}\n\n\t\t\t\t_gl.bindRenderbuffer( _gl.RENDERBUFFER, null );\n\n\t\t\t\tif ( renderTarget.depthBuffer ) {\n\n\t\t\t\t\trenderTargetProperties.__webglDepthRenderbuffer = _gl.createRenderbuffer();\n\t\t\t\t\tsetupRenderBufferStorage( renderTargetProperties.__webglDepthRenderbuffer, renderTarget, true );\n\n\t\t\t\t}\n\n\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Setup color buffer\n\n\t\tif ( isCube ) {\n\n\t\t\tstate.bindTexture( _gl.TEXTURE_CUBE_MAP, textureProperties.__webglTexture );\n\t\t\tsetTextureParameters( _gl.TEXTURE_CUBE_MAP, texture );\n\n\t\t\tfor ( let i = 0; i < 6; i ++ ) {\n\n\t\t\t\tif ( texture.mipmaps && texture.mipmaps.length > 0 ) {\n\n\t\t\t\t\tfor ( let level = 0; level < texture.mipmaps.length; level ++ ) {\n\n\t\t\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ][ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, level );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ i ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + i, 0 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture ) ) {\n\n\t\t\t\tgenerateMipmap( _gl.TEXTURE_CUBE_MAP );\n\n\t\t\t}\n\n\t\t\tstate.unbindTexture();\n\n\t\t} else if ( isMultipleRenderTargets ) {\n\n\t\t\tfor ( let i = 0, il = textures.length; i < il; i ++ ) {\n\n\t\t\t\tconst attachment = textures[ i ];\n\t\t\t\tconst attachmentProperties = properties.get( attachment );\n\n\t\t\t\tstate.bindTexture( _gl.TEXTURE_2D, attachmentProperties.__webglTexture );\n\t\t\t\tsetTextureParameters( _gl.TEXTURE_2D, attachment );\n\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, attachment, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, 0 );\n\n\t\t\t\tif ( textureNeedsGenerateMipmaps( attachment ) ) {\n\n\t\t\t\t\tgenerateMipmap( _gl.TEXTURE_2D );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tstate.unbindTexture();\n\n\t\t} else {\n\n\t\t\tlet glTextureType = _gl.TEXTURE_2D;\n\n\t\t\tif ( renderTarget.isWebGL3DRenderTarget || renderTarget.isWebGLArrayRenderTarget ) {\n\n\t\t\t\tglTextureType = renderTarget.isWebGL3DRenderTarget ? _gl.TEXTURE_3D : _gl.TEXTURE_2D_ARRAY;\n\n\t\t\t}\n\n\t\t\tstate.bindTexture( glTextureType, textureProperties.__webglTexture );\n\t\t\tsetTextureParameters( glTextureType, texture );\n\n\t\t\tif ( texture.mipmaps && texture.mipmaps.length > 0 ) {\n\n\t\t\t\tfor ( let level = 0; level < texture.mipmaps.length; level ++ ) {\n\n\t\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer[ level ], renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, level );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tsetupFrameBufferTexture( renderTargetProperties.__webglFramebuffer, renderTarget, texture, _gl.COLOR_ATTACHMENT0, glTextureType, 0 );\n\n\t\t\t}\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture ) ) {\n\n\t\t\t\tgenerateMipmap( glTextureType );\n\n\t\t\t}\n\n\t\t\tstate.unbindTexture();\n\n\t\t}\n\n\t\t// Setup depth and stencil buffers\n\n\t\tif ( renderTarget.depthBuffer ) {\n\n\t\t\tsetupDepthRenderbuffer( renderTarget );\n\n\t\t}\n\n\t}\n\n\tfunction updateRenderTargetMipmap( renderTarget ) {\n\n\t\tconst textures = renderTarget.textures;\n\n\t\tfor ( let i = 0, il = textures.length; i < il; i ++ ) {\n\n\t\t\tconst texture = textures[ i ];\n\n\t\t\tif ( textureNeedsGenerateMipmaps( texture ) ) {\n\n\t\t\t\tconst target = renderTarget.isWebGLCubeRenderTarget ? _gl.TEXTURE_CUBE_MAP : _gl.TEXTURE_2D;\n\t\t\t\tconst webglTexture = properties.get( texture ).__webglTexture;\n\n\t\t\t\tstate.bindTexture( target, webglTexture );\n\t\t\t\tgenerateMipmap( target );\n\t\t\t\tstate.unbindTexture();\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tconst invalidationArrayRead = [];\n\tconst invalidationArrayDraw = [];\n\n\tfunction updateMultisampleRenderTarget( renderTarget ) {\n\n\t\tif ( renderTarget.samples > 0 ) {\n\n\t\t\tif ( useMultisampledRTT( renderTarget ) === false ) {\n\n\t\t\t\tconst textures = renderTarget.textures;\n\t\t\t\tconst width = renderTarget.width;\n\t\t\t\tconst height = renderTarget.height;\n\t\t\t\tlet mask = _gl.COLOR_BUFFER_BIT;\n\t\t\t\tconst depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;\n\t\t\t\tconst renderTargetProperties = properties.get( renderTarget );\n\t\t\t\tconst isMultipleRenderTargets = ( textures.length > 1 );\n\n\t\t\t\t// If MRT we need to remove FBO attachments\n\t\t\t\tif ( isMultipleRenderTargets ) {\n\n\t\t\t\t\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );\n\t\t\t\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, null );\n\n\t\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );\n\t\t\t\t\t\t_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, null, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tstate.bindFramebuffer( _gl.READ_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );\n\t\t\t\tstate.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );\n\n\t\t\t\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\t\t\t\tif ( renderTarget.resolveDepthBuffer ) {\n\n\t\t\t\t\t\tif ( renderTarget.depthBuffer ) mask |= _gl.DEPTH_BUFFER_BIT;\n\n\t\t\t\t\t\t// resolving stencil is slow with a D3D backend. disable it for all transmission render targets (see #27799)\n\n\t\t\t\t\t\tif ( renderTarget.stencilBuffer && renderTarget.resolveStencilBuffer ) mask |= _gl.STENCIL_BUFFER_BIT;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( isMultipleRenderTargets ) {\n\n\t\t\t\t\t\t_gl.framebufferRenderbuffer( _gl.READ_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );\n\n\t\t\t\t\t\tconst webglTexture = properties.get( textures[ i ] ).__webglTexture;\n\t\t\t\t\t\t_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_2D, webglTexture, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t_gl.blitFramebuffer( 0, 0, width, height, 0, 0, width, height, mask, _gl.NEAREST );\n\n\t\t\t\t\tif ( supportsInvalidateFramebuffer === true ) {\n\n\t\t\t\t\t\tinvalidationArrayRead.length = 0;\n\t\t\t\t\t\tinvalidationArrayDraw.length = 0;\n\n\t\t\t\t\t\tinvalidationArrayRead.push( _gl.COLOR_ATTACHMENT0 + i );\n\n\t\t\t\t\t\tif ( renderTarget.depthBuffer && renderTarget.resolveDepthBuffer === false ) {\n\n\t\t\t\t\t\t\tinvalidationArrayRead.push( depthStyle );\n\t\t\t\t\t\t\tinvalidationArrayDraw.push( depthStyle );\n\n\t\t\t\t\t\t\t_gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, invalidationArrayDraw );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t_gl.invalidateFramebuffer( _gl.READ_FRAMEBUFFER, invalidationArrayRead );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tstate.bindFramebuffer( _gl.READ_FRAMEBUFFER, null );\n\t\t\t\tstate.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, null );\n\n\t\t\t\t// If MRT since pre-blit we removed the FBO we need to reconstruct the attachments\n\t\t\t\tif ( isMultipleRenderTargets ) {\n\n\t\t\t\t\tfor ( let i = 0; i < textures.length; i ++ ) {\n\n\t\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );\n\t\t\t\t\t\t_gl.framebufferRenderbuffer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.RENDERBUFFER, renderTargetProperties.__webglColorRenderbuffer[ i ] );\n\n\t\t\t\t\t\tconst webglTexture = properties.get( textures[ i ] ).__webglTexture;\n\n\t\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, renderTargetProperties.__webglFramebuffer );\n\t\t\t\t\t\t_gl.framebufferTexture2D( _gl.DRAW_FRAMEBUFFER, _gl.COLOR_ATTACHMENT0 + i, _gl.TEXTURE_2D, webglTexture, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tstate.bindFramebuffer( _gl.DRAW_FRAMEBUFFER, renderTargetProperties.__webglMultisampledFramebuffer );\n\n\t\t\t} else {\n\n\t\t\t\tif ( renderTarget.depthBuffer && renderTarget.resolveDepthBuffer === false && supportsInvalidateFramebuffer ) {\n\n\t\t\t\t\tconst depthStyle = renderTarget.stencilBuffer ? _gl.DEPTH_STENCIL_ATTACHMENT : _gl.DEPTH_ATTACHMENT;\n\n\t\t\t\t\t_gl.invalidateFramebuffer( _gl.DRAW_FRAMEBUFFER, [ depthStyle ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tfunction getRenderTargetSamples( renderTarget ) {\n\n\t\treturn Math.min( capabilities.maxSamples, renderTarget.samples );\n\n\t}\n\n\tfunction useMultisampledRTT( renderTarget ) {\n\n\t\tconst renderTargetProperties = properties.get( renderTarget );\n\n\t\treturn renderTarget.samples > 0 && extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true && renderTargetProperties.__useRenderToTexture !== false;\n\n\t}\n\n\tfunction updateVideoTexture( texture ) {\n\n\t\tconst frame = info.render.frame;\n\n\t\t// Check the last frame we updated the VideoTexture\n\n\t\tif ( _videoTextures.get( texture ) !== frame ) {\n\n\t\t\t_videoTextures.set( texture, frame );\n\t\t\ttexture.update();\n\n\t\t}\n\n\t}\n\n\tfunction verifyColorSpace( texture, image ) {\n\n\t\tconst colorSpace = texture.colorSpace;\n\t\tconst format = texture.format;\n\t\tconst type = texture.type;\n\n\t\tif ( texture.isCompressedTexture === true || texture.isVideoTexture === true ) return image;\n\n\t\tif ( colorSpace !== LinearSRGBColorSpace && colorSpace !== NoColorSpace ) {\n\n\t\t\t// sRGB\n\n\t\t\tif ( ColorManagement.getTransfer( colorSpace ) === SRGBTransfer ) {\n\n\t\t\t\t// in WebGL 2 uncompressed textures can only be sRGB encoded if they have the RGBA8 format\n\n\t\t\t\tif ( format !== RGBAFormat || type !== UnsignedByteType ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLTextures: sRGB encoded textures have to use RGBAFormat and UnsignedByteType.' );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tconsole.error( 'THREE.WebGLTextures: Unsupported texture color space:', colorSpace );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn image;\n\n\t}\n\n\tfunction getDimensions( image ) {\n\n\t\tif ( typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement ) {\n\n\t\t\t// if intrinsic data are not available, fallback to width/height\n\n\t\t\t_imageDimensions.width = image.naturalWidth || image.width;\n\t\t\t_imageDimensions.height = image.naturalHeight || image.height;\n\n\t\t} else if ( typeof VideoFrame !== 'undefined' && image instanceof VideoFrame ) {\n\n\t\t\t_imageDimensions.width = image.displayWidth;\n\t\t\t_imageDimensions.height = image.displayHeight;\n\n\t\t} else {\n\n\t\t\t_imageDimensions.width = image.width;\n\t\t\t_imageDimensions.height = image.height;\n\n\t\t}\n\n\t\treturn _imageDimensions;\n\n\t}\n\n\t//\n\n\tthis.allocateTextureUnit = allocateTextureUnit;\n\tthis.resetTextureUnits = resetTextureUnits;\n\n\tthis.setTexture2D = setTexture2D;\n\tthis.setTexture2DArray = setTexture2DArray;\n\tthis.setTexture3D = setTexture3D;\n\tthis.setTextureCube = setTextureCube;\n\tthis.rebindTextures = rebindTextures;\n\tthis.setupRenderTarget = setupRenderTarget;\n\tthis.updateRenderTargetMipmap = updateRenderTargetMipmap;\n\tthis.updateMultisampleRenderTarget = updateMultisampleRenderTarget;\n\tthis.setupDepthRenderbuffer = setupDepthRenderbuffer;\n\tthis.setupFrameBufferTexture = setupFrameBufferTexture;\n\tthis.useMultisampledRTT = useMultisampledRTT;\n\n}\n\nfunction WebGLUtils( gl, extensions ) {\n\n\tfunction convert( p, colorSpace = NoColorSpace ) {\n\n\t\tlet extension;\n\n\t\tconst transfer = ColorManagement.getTransfer( colorSpace );\n\n\t\tif ( p === UnsignedByteType ) return gl.UNSIGNED_BYTE;\n\t\tif ( p === UnsignedShort4444Type ) return gl.UNSIGNED_SHORT_4_4_4_4;\n\t\tif ( p === UnsignedShort5551Type ) return gl.UNSIGNED_SHORT_5_5_5_1;\n\t\tif ( p === UnsignedInt5999Type ) return gl.UNSIGNED_INT_5_9_9_9_REV;\n\n\t\tif ( p === ByteType ) return gl.BYTE;\n\t\tif ( p === ShortType ) return gl.SHORT;\n\t\tif ( p === UnsignedShortType ) return gl.UNSIGNED_SHORT;\n\t\tif ( p === IntType ) return gl.INT;\n\t\tif ( p === UnsignedIntType ) return gl.UNSIGNED_INT;\n\t\tif ( p === FloatType ) return gl.FLOAT;\n\t\tif ( p === HalfFloatType ) return gl.HALF_FLOAT;\n\n\t\tif ( p === AlphaFormat ) return gl.ALPHA;\n\t\tif ( p === RGBFormat ) return gl.RGB;\n\t\tif ( p === RGBAFormat ) return gl.RGBA;\n\t\tif ( p === LuminanceFormat ) return gl.LUMINANCE;\n\t\tif ( p === LuminanceAlphaFormat ) return gl.LUMINANCE_ALPHA;\n\t\tif ( p === DepthFormat ) return gl.DEPTH_COMPONENT;\n\t\tif ( p === DepthStencilFormat ) return gl.DEPTH_STENCIL;\n\n\t\t// WebGL2 formats.\n\n\t\tif ( p === RedFormat ) return gl.RED;\n\t\tif ( p === RedIntegerFormat ) return gl.RED_INTEGER;\n\t\tif ( p === RGFormat ) return gl.RG;\n\t\tif ( p === RGIntegerFormat ) return gl.RG_INTEGER;\n\t\tif ( p === RGBAIntegerFormat ) return gl.RGBA_INTEGER;\n\n\t\t// S3TC\n\n\t\tif ( p === RGB_S3TC_DXT1_Format || p === RGBA_S3TC_DXT1_Format || p === RGBA_S3TC_DXT3_Format || p === RGBA_S3TC_DXT5_Format ) {\n\n\t\t\tif ( transfer === SRGBTransfer ) {\n\n\t\t\t\textension = extensions.get( 'WEBGL_compressed_texture_s3tc_srgb' );\n\n\t\t\t\tif ( extension !== null ) {\n\n\t\t\t\t\tif ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_S3TC_DXT1_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\textension = extensions.get( 'WEBGL_compressed_texture_s3tc' );\n\n\t\t\t\tif ( extension !== null ) {\n\n\t\t\t\t\tif ( p === RGB_S3TC_DXT1_Format ) return extension.COMPRESSED_RGB_S3TC_DXT1_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT1_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT1_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT3_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT3_EXT;\n\t\t\t\t\tif ( p === RGBA_S3TC_DXT5_Format ) return extension.COMPRESSED_RGBA_S3TC_DXT5_EXT;\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// PVRTC\n\n\t\tif ( p === RGB_PVRTC_4BPPV1_Format || p === RGB_PVRTC_2BPPV1_Format || p === RGBA_PVRTC_4BPPV1_Format || p === RGBA_PVRTC_2BPPV1_Format ) {\n\n\t\t\textension = extensions.get( 'WEBGL_compressed_texture_pvrtc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGB_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_4BPPV1_IMG;\n\t\t\t\tif ( p === RGB_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGB_PVRTC_2BPPV1_IMG;\n\t\t\t\tif ( p === RGBA_PVRTC_4BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;\n\t\t\t\tif ( p === RGBA_PVRTC_2BPPV1_Format ) return extension.COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;\n\n\t\t\t} else {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// ETC\n\n\t\tif ( p === RGB_ETC1_Format || p === RGB_ETC2_Format || p === RGBA_ETC2_EAC_Format ) {\n\n\t\t\textension = extensions.get( 'WEBGL_compressed_texture_etc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGB_ETC1_Format || p === RGB_ETC2_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ETC2 : extension.COMPRESSED_RGB8_ETC2;\n\t\t\t\tif ( p === RGBA_ETC2_EAC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : extension.COMPRESSED_RGBA8_ETC2_EAC;\n\n\t\t\t} else {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// ASTC\n\n\t\tif ( p === RGBA_ASTC_4x4_Format || p === RGBA_ASTC_5x4_Format || p === RGBA_ASTC_5x5_Format ||\n\t\t\tp === RGBA_ASTC_6x5_Format || p === RGBA_ASTC_6x6_Format || p === RGBA_ASTC_8x5_Format ||\n\t\t\tp === RGBA_ASTC_8x6_Format || p === RGBA_ASTC_8x8_Format || p === RGBA_ASTC_10x5_Format ||\n\t\t\tp === RGBA_ASTC_10x6_Format || p === RGBA_ASTC_10x8_Format || p === RGBA_ASTC_10x10_Format ||\n\t\t\tp === RGBA_ASTC_12x10_Format || p === RGBA_ASTC_12x12_Format ) {\n\n\t\t\textension = extensions.get( 'WEBGL_compressed_texture_astc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGBA_ASTC_4x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : extension.COMPRESSED_RGBA_ASTC_4x4_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_5x4_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : extension.COMPRESSED_RGBA_ASTC_5x4_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_5x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : extension.COMPRESSED_RGBA_ASTC_5x5_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_6x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : extension.COMPRESSED_RGBA_ASTC_6x5_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_6x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : extension.COMPRESSED_RGBA_ASTC_6x6_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_8x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : extension.COMPRESSED_RGBA_ASTC_8x5_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_8x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : extension.COMPRESSED_RGBA_ASTC_8x6_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_8x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : extension.COMPRESSED_RGBA_ASTC_8x8_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_10x5_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : extension.COMPRESSED_RGBA_ASTC_10x5_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_10x6_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : extension.COMPRESSED_RGBA_ASTC_10x6_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_10x8_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : extension.COMPRESSED_RGBA_ASTC_10x8_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_10x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : extension.COMPRESSED_RGBA_ASTC_10x10_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_12x10_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : extension.COMPRESSED_RGBA_ASTC_12x10_KHR;\n\t\t\t\tif ( p === RGBA_ASTC_12x12_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : extension.COMPRESSED_RGBA_ASTC_12x12_KHR;\n\n\t\t\t} else {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// BPTC\n\n\t\tif ( p === RGBA_BPTC_Format || p === RGB_BPTC_SIGNED_Format || p === RGB_BPTC_UNSIGNED_Format ) {\n\n\t\t\textension = extensions.get( 'EXT_texture_compression_bptc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGBA_BPTC_Format ) return ( transfer === SRGBTransfer ) ? extension.COMPRESSED_SRGB_ALPHA_BPTC_UNORM_EXT : extension.COMPRESSED_RGBA_BPTC_UNORM_EXT;\n\t\t\t\tif ( p === RGB_BPTC_SIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_SIGNED_FLOAT_EXT;\n\t\t\t\tif ( p === RGB_BPTC_UNSIGNED_Format ) return extension.COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_EXT;\n\n\t\t\t} else {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// RGTC\n\n\t\tif ( p === RED_RGTC1_Format || p === SIGNED_RED_RGTC1_Format || p === RED_GREEN_RGTC2_Format || p === SIGNED_RED_GREEN_RGTC2_Format ) {\n\n\t\t\textension = extensions.get( 'EXT_texture_compression_rgtc' );\n\n\t\t\tif ( extension !== null ) {\n\n\t\t\t\tif ( p === RGBA_BPTC_Format ) return extension.COMPRESSED_RED_RGTC1_EXT;\n\t\t\t\tif ( p === SIGNED_RED_RGTC1_Format ) return extension.COMPRESSED_SIGNED_RED_RGTC1_EXT;\n\t\t\t\tif ( p === RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_RED_GREEN_RGTC2_EXT;\n\t\t\t\tif ( p === SIGNED_RED_GREEN_RGTC2_Format ) return extension.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT;\n\n\t\t\t} else {\n\n\t\t\t\treturn null;\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tif ( p === UnsignedInt248Type ) return gl.UNSIGNED_INT_24_8;\n\n\t\t// if \"p\" can't be resolved, assume the user defines a WebGL constant as a string (fallback/workaround for packed RGB formats)\n\n\t\treturn ( gl[ p ] !== undefined ) ? gl[ p ] : null;\n\n\t}\n\n\treturn { convert: convert };\n\n}\n\nclass ArrayCamera extends PerspectiveCamera {\n\n\tconstructor( array = [] ) {\n\n\t\tsuper();\n\n\t\tthis.isArrayCamera = true;\n\n\t\tthis.cameras = array;\n\n\t}\n\n}\n\nclass Group extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isGroup = true;\n\n\t\tthis.type = 'Group';\n\n\t}\n\n}\n\nconst _moveEvent = { type: 'move' };\n\nclass WebXRController {\n\n\tconstructor() {\n\n\t\tthis._targetRay = null;\n\t\tthis._grip = null;\n\t\tthis._hand = null;\n\n\t}\n\n\tgetHandSpace() {\n\n\t\tif ( this._hand === null ) {\n\n\t\t\tthis._hand = new Group();\n\t\t\tthis._hand.matrixAutoUpdate = false;\n\t\t\tthis._hand.visible = false;\n\n\t\t\tthis._hand.joints = {};\n\t\t\tthis._hand.inputState = { pinching: false };\n\n\t\t}\n\n\t\treturn this._hand;\n\n\t}\n\n\tgetTargetRaySpace() {\n\n\t\tif ( this._targetRay === null ) {\n\n\t\t\tthis._targetRay = new Group();\n\t\t\tthis._targetRay.matrixAutoUpdate = false;\n\t\t\tthis._targetRay.visible = false;\n\t\t\tthis._targetRay.hasLinearVelocity = false;\n\t\t\tthis._targetRay.linearVelocity = new Vector3();\n\t\t\tthis._targetRay.hasAngularVelocity = false;\n\t\t\tthis._targetRay.angularVelocity = new Vector3();\n\n\t\t}\n\n\t\treturn this._targetRay;\n\n\t}\n\n\tgetGripSpace() {\n\n\t\tif ( this._grip === null ) {\n\n\t\t\tthis._grip = new Group();\n\t\t\tthis._grip.matrixAutoUpdate = false;\n\t\t\tthis._grip.visible = false;\n\t\t\tthis._grip.hasLinearVelocity = false;\n\t\t\tthis._grip.linearVelocity = new Vector3();\n\t\t\tthis._grip.hasAngularVelocity = false;\n\t\t\tthis._grip.angularVelocity = new Vector3();\n\n\t\t}\n\n\t\treturn this._grip;\n\n\t}\n\n\tdispatchEvent( event ) {\n\n\t\tif ( this._targetRay !== null ) {\n\n\t\t\tthis._targetRay.dispatchEvent( event );\n\n\t\t}\n\n\t\tif ( this._grip !== null ) {\n\n\t\t\tthis._grip.dispatchEvent( event );\n\n\t\t}\n\n\t\tif ( this._hand !== null ) {\n\n\t\t\tthis._hand.dispatchEvent( event );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tconnect( inputSource ) {\n\n\t\tif ( inputSource && inputSource.hand ) {\n\n\t\t\tconst hand = this._hand;\n\n\t\t\tif ( hand ) {\n\n\t\t\t\tfor ( const inputjoint of inputSource.hand.values() ) {\n\n\t\t\t\t\t// Initialize hand with joints when connected\n\t\t\t\t\tthis._getHandJoint( hand, inputjoint );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.dispatchEvent( { type: 'connected', data: inputSource } );\n\n\t\treturn this;\n\n\t}\n\n\tdisconnect( inputSource ) {\n\n\t\tthis.dispatchEvent( { type: 'disconnected', data: inputSource } );\n\n\t\tif ( this._targetRay !== null ) {\n\n\t\t\tthis._targetRay.visible = false;\n\n\t\t}\n\n\t\tif ( this._grip !== null ) {\n\n\t\t\tthis._grip.visible = false;\n\n\t\t}\n\n\t\tif ( this._hand !== null ) {\n\n\t\t\tthis._hand.visible = false;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tupdate( inputSource, frame, referenceSpace ) {\n\n\t\tlet inputPose = null;\n\t\tlet gripPose = null;\n\t\tlet handPose = null;\n\n\t\tconst targetRay = this._targetRay;\n\t\tconst grip = this._grip;\n\t\tconst hand = this._hand;\n\n\t\tif ( inputSource && frame.session.visibilityState !== 'visible-blurred' ) {\n\n\t\t\tif ( hand && inputSource.hand ) {\n\n\t\t\t\thandPose = true;\n\n\t\t\t\tfor ( const inputjoint of inputSource.hand.values() ) {\n\n\t\t\t\t\t// Update the joints groups with the XRJoint poses\n\t\t\t\t\tconst jointPose = frame.getJointPose( inputjoint, referenceSpace );\n\n\t\t\t\t\t// The transform of this joint will be updated with the joint pose on each frame\n\t\t\t\t\tconst joint = this._getHandJoint( hand, inputjoint );\n\n\t\t\t\t\tif ( jointPose !== null ) {\n\n\t\t\t\t\t\tjoint.matrix.fromArray( jointPose.transform.matrix );\n\t\t\t\t\t\tjoint.matrix.decompose( joint.position, joint.rotation, joint.scale );\n\t\t\t\t\t\tjoint.matrixWorldNeedsUpdate = true;\n\t\t\t\t\t\tjoint.jointRadius = jointPose.radius;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tjoint.visible = jointPose !== null;\n\n\t\t\t\t}\n\n\t\t\t\t// Custom events\n\n\t\t\t\t// Check pinchz\n\t\t\t\tconst indexTip = hand.joints[ 'index-finger-tip' ];\n\t\t\t\tconst thumbTip = hand.joints[ 'thumb-tip' ];\n\t\t\t\tconst distance = indexTip.position.distanceTo( thumbTip.position );\n\n\t\t\t\tconst distanceToPinch = 0.02;\n\t\t\t\tconst threshold = 0.005;\n\n\t\t\t\tif ( hand.inputState.pinching && distance > distanceToPinch + threshold ) {\n\n\t\t\t\t\thand.inputState.pinching = false;\n\t\t\t\t\tthis.dispatchEvent( {\n\t\t\t\t\t\ttype: 'pinchend',\n\t\t\t\t\t\thandedness: inputSource.handedness,\n\t\t\t\t\t\ttarget: this\n\t\t\t\t\t} );\n\n\t\t\t\t} else if ( ! hand.inputState.pinching && distance <= distanceToPinch - threshold ) {\n\n\t\t\t\t\thand.inputState.pinching = true;\n\t\t\t\t\tthis.dispatchEvent( {\n\t\t\t\t\t\ttype: 'pinchstart',\n\t\t\t\t\t\thandedness: inputSource.handedness,\n\t\t\t\t\t\ttarget: this\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( grip !== null && inputSource.gripSpace ) {\n\n\t\t\t\t\tgripPose = frame.getPose( inputSource.gripSpace, referenceSpace );\n\n\t\t\t\t\tif ( gripPose !== null ) {\n\n\t\t\t\t\t\tgrip.matrix.fromArray( gripPose.transform.matrix );\n\t\t\t\t\t\tgrip.matrix.decompose( grip.position, grip.rotation, grip.scale );\n\t\t\t\t\t\tgrip.matrixWorldNeedsUpdate = true;\n\n\t\t\t\t\t\tif ( gripPose.linearVelocity ) {\n\n\t\t\t\t\t\t\tgrip.hasLinearVelocity = true;\n\t\t\t\t\t\t\tgrip.linearVelocity.copy( gripPose.linearVelocity );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tgrip.hasLinearVelocity = false;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( gripPose.angularVelocity ) {\n\n\t\t\t\t\t\t\tgrip.hasAngularVelocity = true;\n\t\t\t\t\t\t\tgrip.angularVelocity.copy( gripPose.angularVelocity );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tgrip.hasAngularVelocity = false;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( targetRay !== null ) {\n\n\t\t\t\tinputPose = frame.getPose( inputSource.targetRaySpace, referenceSpace );\n\n\t\t\t\t// Some runtimes (namely Vive Cosmos with Vive OpenXR Runtime) have only grip space and ray space is equal to it\n\t\t\t\tif ( inputPose === null && gripPose !== null ) {\n\n\t\t\t\t\tinputPose = gripPose;\n\n\t\t\t\t}\n\n\t\t\t\tif ( inputPose !== null ) {\n\n\t\t\t\t\ttargetRay.matrix.fromArray( inputPose.transform.matrix );\n\t\t\t\t\ttargetRay.matrix.decompose( targetRay.position, targetRay.rotation, targetRay.scale );\n\t\t\t\t\ttargetRay.matrixWorldNeedsUpdate = true;\n\n\t\t\t\t\tif ( inputPose.linearVelocity ) {\n\n\t\t\t\t\t\ttargetRay.hasLinearVelocity = true;\n\t\t\t\t\t\ttargetRay.linearVelocity.copy( inputPose.linearVelocity );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ttargetRay.hasLinearVelocity = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( inputPose.angularVelocity ) {\n\n\t\t\t\t\t\ttargetRay.hasAngularVelocity = true;\n\t\t\t\t\t\ttargetRay.angularVelocity.copy( inputPose.angularVelocity );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ttargetRay.hasAngularVelocity = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tthis.dispatchEvent( _moveEvent );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t}\n\n\t\tif ( targetRay !== null ) {\n\n\t\t\ttargetRay.visible = ( inputPose !== null );\n\n\t\t}\n\n\t\tif ( grip !== null ) {\n\n\t\t\tgrip.visible = ( gripPose !== null );\n\n\t\t}\n\n\t\tif ( hand !== null ) {\n\n\t\t\thand.visible = ( handPose !== null );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// private method\n\n\t_getHandJoint( hand, inputjoint ) {\n\n\t\tif ( hand.joints[ inputjoint.jointName ] === undefined ) {\n\n\t\t\tconst joint = new Group();\n\t\t\tjoint.matrixAutoUpdate = false;\n\t\t\tjoint.visible = false;\n\t\t\thand.joints[ inputjoint.jointName ] = joint;\n\n\t\t\thand.add( joint );\n\n\t\t}\n\n\t\treturn hand.joints[ inputjoint.jointName ];\n\n\t}\n\n}\n\nconst _occlusion_vertex = `\nvoid main() {\n\n\tgl_Position = vec4( position, 1.0 );\n\n}`;\n\nconst _occlusion_fragment = `\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_FragDepth = texture( depthColor, vec3( coord.x - 1.0, coord.y, 1 ) ).r;\n\n\t} else {\n\n\t\tgl_FragDepth = texture( depthColor, vec3( coord.x, coord.y, 0 ) ).r;\n\n\t}\n\n}`;\n\nclass WebXRDepthSensing {\n\n\tconstructor() {\n\n\t\tthis.texture = null;\n\t\tthis.mesh = null;\n\n\t\tthis.depthNear = 0;\n\t\tthis.depthFar = 0;\n\n\t}\n\n\tinit( renderer, depthData, renderState ) {\n\n\t\tif ( this.texture === null ) {\n\n\t\t\tconst texture = new Texture();\n\n\t\t\tconst texProps = renderer.properties.get( texture );\n\t\t\ttexProps.__webglTexture = depthData.texture;\n\n\t\t\tif ( ( depthData.depthNear != renderState.depthNear ) || ( depthData.depthFar != renderState.depthFar ) ) {\n\n\t\t\t\tthis.depthNear = depthData.depthNear;\n\t\t\t\tthis.depthFar = depthData.depthFar;\n\n\t\t\t}\n\n\t\t\tthis.texture = texture;\n\n\t\t}\n\n\t}\n\n\tgetMesh( cameraXR ) {\n\n\t\tif ( this.texture !== null ) {\n\n\t\t\tif ( this.mesh === null ) {\n\n\t\t\t\tconst viewport = cameraXR.cameras[ 0 ].viewport;\n\t\t\t\tconst material = new ShaderMaterial( {\n\t\t\t\t\tvertexShader: _occlusion_vertex,\n\t\t\t\t\tfragmentShader: _occlusion_fragment,\n\t\t\t\t\tuniforms: {\n\t\t\t\t\t\tdepthColor: { value: this.texture },\n\t\t\t\t\t\tdepthWidth: { value: viewport.z },\n\t\t\t\t\t\tdepthHeight: { value: viewport.w }\n\t\t\t\t\t}\n\t\t\t\t} );\n\n\t\t\t\tthis.mesh = new Mesh( new PlaneGeometry( 20, 20 ), material );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this.mesh;\n\n\t}\n\n\treset() {\n\n\t\tthis.texture = null;\n\t\tthis.mesh = null;\n\n\t}\n\n\tgetDepthTexture() {\n\n\t\treturn this.texture;\n\n\t}\n\n}\n\nclass WebXRManager extends EventDispatcher {\n\n\tconstructor( renderer, gl ) {\n\n\t\tsuper();\n\n\t\tconst scope = this;\n\n\t\tlet session = null;\n\n\t\tlet framebufferScaleFactor = 1.0;\n\n\t\tlet referenceSpace = null;\n\t\tlet referenceSpaceType = 'local-floor';\n\t\t// Set default foveation to maximum.\n\t\tlet foveation = 1.0;\n\t\tlet customReferenceSpace = null;\n\n\t\tlet pose = null;\n\t\tlet glBinding = null;\n\t\tlet glProjLayer = null;\n\t\tlet glBaseLayer = null;\n\t\tlet xrFrame = null;\n\n\t\tconst depthSensing = new WebXRDepthSensing();\n\t\tconst attributes = gl.getContextAttributes();\n\n\t\tlet initialRenderTarget = null;\n\t\tlet newRenderTarget = null;\n\n\t\tconst controllers = [];\n\t\tconst controllerInputSources = [];\n\n\t\tconst currentSize = new Vector2();\n\t\tlet currentPixelRatio = null;\n\n\t\t//\n\n\t\tconst cameraL = new PerspectiveCamera();\n\t\tcameraL.layers.enable( 1 );\n\t\tcameraL.viewport = new Vector4();\n\n\t\tconst cameraR = new PerspectiveCamera();\n\t\tcameraR.layers.enable( 2 );\n\t\tcameraR.viewport = new Vector4();\n\n\t\tconst cameras = [ cameraL, cameraR ];\n\n\t\tconst cameraXR = new ArrayCamera();\n\t\tcameraXR.layers.enable( 1 );\n\t\tcameraXR.layers.enable( 2 );\n\n\t\tlet _currentDepthNear = null;\n\t\tlet _currentDepthFar = null;\n\n\t\t//\n\n\t\tthis.cameraAutoUpdate = true;\n\t\tthis.enabled = false;\n\n\t\tthis.isPresenting = false;\n\n\t\tthis.getController = function ( index ) {\n\n\t\t\tlet controller = controllers[ index ];\n\n\t\t\tif ( controller === undefined ) {\n\n\t\t\t\tcontroller = new WebXRController();\n\t\t\t\tcontrollers[ index ] = controller;\n\n\t\t\t}\n\n\t\t\treturn controller.getTargetRaySpace();\n\n\t\t};\n\n\t\tthis.getControllerGrip = function ( index ) {\n\n\t\t\tlet controller = controllers[ index ];\n\n\t\t\tif ( controller === undefined ) {\n\n\t\t\t\tcontroller = new WebXRController();\n\t\t\t\tcontrollers[ index ] = controller;\n\n\t\t\t}\n\n\t\t\treturn controller.getGripSpace();\n\n\t\t};\n\n\t\tthis.getHand = function ( index ) {\n\n\t\t\tlet controller = controllers[ index ];\n\n\t\t\tif ( controller === undefined ) {\n\n\t\t\t\tcontroller = new WebXRController();\n\t\t\t\tcontrollers[ index ] = controller;\n\n\t\t\t}\n\n\t\t\treturn controller.getHandSpace();\n\n\t\t};\n\n\t\t//\n\n\t\tfunction onSessionEvent( event ) {\n\n\t\t\tconst controllerIndex = controllerInputSources.indexOf( event.inputSource );\n\n\t\t\tif ( controllerIndex === - 1 ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tconst controller = controllers[ controllerIndex ];\n\n\t\t\tif ( controller !== undefined ) {\n\n\t\t\t\tcontroller.update( event.inputSource, event.frame, customReferenceSpace || referenceSpace );\n\t\t\t\tcontroller.dispatchEvent( { type: event.type, data: event.inputSource } );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onSessionEnd() {\n\n\t\t\tsession.removeEventListener( 'select', onSessionEvent );\n\t\t\tsession.removeEventListener( 'selectstart', onSessionEvent );\n\t\t\tsession.removeEventListener( 'selectend', onSessionEvent );\n\t\t\tsession.removeEventListener( 'squeeze', onSessionEvent );\n\t\t\tsession.removeEventListener( 'squeezestart', onSessionEvent );\n\t\t\tsession.removeEventListener( 'squeezeend', onSessionEvent );\n\t\t\tsession.removeEventListener( 'end', onSessionEnd );\n\t\t\tsession.removeEventListener( 'inputsourceschange', onInputSourcesChange );\n\n\t\t\tfor ( let i = 0; i < controllers.length; i ++ ) {\n\n\t\t\t\tconst inputSource = controllerInputSources[ i ];\n\n\t\t\t\tif ( inputSource === null ) continue;\n\n\t\t\t\tcontrollerInputSources[ i ] = null;\n\n\t\t\t\tcontrollers[ i ].disconnect( inputSource );\n\n\t\t\t}\n\n\t\t\t_currentDepthNear = null;\n\t\t\t_currentDepthFar = null;\n\n\t\t\tdepthSensing.reset();\n\n\t\t\t// restore framebuffer/rendering state\n\n\t\t\trenderer.setRenderTarget( initialRenderTarget );\n\n\t\t\tglBaseLayer = null;\n\t\t\tglProjLayer = null;\n\t\t\tglBinding = null;\n\t\t\tsession = null;\n\t\t\tnewRenderTarget = null;\n\n\t\t\t//\n\n\t\t\tanimation.stop();\n\n\t\t\tscope.isPresenting = false;\n\n\t\t\trenderer.setPixelRatio( currentPixelRatio );\n\t\t\trenderer.setSize( currentSize.width, currentSize.height, false );\n\n\t\t\tscope.dispatchEvent( { type: 'sessionend' } );\n\n\t\t}\n\n\t\tthis.setFramebufferScaleFactor = function ( value ) {\n\n\t\t\tframebufferScaleFactor = value;\n\n\t\t\tif ( scope.isPresenting === true ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebXRManager: Cannot change framebuffer scale while presenting.' );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.setReferenceSpaceType = function ( value ) {\n\n\t\t\treferenceSpaceType = value;\n\n\t\t\tif ( scope.isPresenting === true ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebXRManager: Cannot change reference space type while presenting.' );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.getReferenceSpace = function () {\n\n\t\t\treturn customReferenceSpace || referenceSpace;\n\n\t\t};\n\n\t\tthis.setReferenceSpace = function ( space ) {\n\n\t\t\tcustomReferenceSpace = space;\n\n\t\t};\n\n\t\tthis.getBaseLayer = function () {\n\n\t\t\treturn glProjLayer !== null ? glProjLayer : glBaseLayer;\n\n\t\t};\n\n\t\tthis.getBinding = function () {\n\n\t\t\treturn glBinding;\n\n\t\t};\n\n\t\tthis.getFrame = function () {\n\n\t\t\treturn xrFrame;\n\n\t\t};\n\n\t\tthis.getSession = function () {\n\n\t\t\treturn session;\n\n\t\t};\n\n\t\tthis.setSession = async function ( value ) {\n\n\t\t\tsession = value;\n\n\t\t\tif ( session !== null ) {\n\n\t\t\t\tinitialRenderTarget = renderer.getRenderTarget();\n\n\t\t\t\tsession.addEventListener( 'select', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'selectstart', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'selectend', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'squeeze', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'squeezestart', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'squeezeend', onSessionEvent );\n\t\t\t\tsession.addEventListener( 'end', onSessionEnd );\n\t\t\t\tsession.addEventListener( 'inputsourceschange', onInputSourcesChange );\n\n\t\t\t\tif ( attributes.xrCompatible !== true ) {\n\n\t\t\t\t\tawait gl.makeXRCompatible();\n\n\t\t\t\t}\n\n\t\t\t\tcurrentPixelRatio = renderer.getPixelRatio();\n\t\t\t\trenderer.getSize( currentSize );\n\n\t\t\t\tif ( session.renderState.layers === undefined ) {\n\n\t\t\t\t\tconst layerInit = {\n\t\t\t\t\t\tantialias: attributes.antialias,\n\t\t\t\t\t\talpha: true,\n\t\t\t\t\t\tdepth: attributes.depth,\n\t\t\t\t\t\tstencil: attributes.stencil,\n\t\t\t\t\t\tframebufferScaleFactor: framebufferScaleFactor\n\t\t\t\t\t};\n\n\t\t\t\t\tglBaseLayer = new XRWebGLLayer( session, gl, layerInit );\n\n\t\t\t\t\tsession.updateRenderState( { baseLayer: glBaseLayer } );\n\n\t\t\t\t\trenderer.setPixelRatio( 1 );\n\t\t\t\t\trenderer.setSize( glBaseLayer.framebufferWidth, glBaseLayer.framebufferHeight, false );\n\n\t\t\t\t\tnewRenderTarget = new WebGLRenderTarget(\n\t\t\t\t\t\tglBaseLayer.framebufferWidth,\n\t\t\t\t\t\tglBaseLayer.framebufferHeight,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tformat: RGBAFormat,\n\t\t\t\t\t\t\ttype: UnsignedByteType,\n\t\t\t\t\t\t\tcolorSpace: renderer.outputColorSpace,\n\t\t\t\t\t\t\tstencilBuffer: attributes.stencil\n\t\t\t\t\t\t}\n\t\t\t\t\t);\n\n\t\t\t\t} else {\n\n\t\t\t\t\tlet depthFormat = null;\n\t\t\t\t\tlet depthType = null;\n\t\t\t\t\tlet glDepthFormat = null;\n\n\t\t\t\t\tif ( attributes.depth ) {\n\n\t\t\t\t\t\tglDepthFormat = attributes.stencil ? gl.DEPTH24_STENCIL8 : gl.DEPTH_COMPONENT24;\n\t\t\t\t\t\tdepthFormat = attributes.stencil ? DepthStencilFormat : DepthFormat;\n\t\t\t\t\t\tdepthType = attributes.stencil ? UnsignedInt248Type : UnsignedIntType;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst projectionlayerInit = {\n\t\t\t\t\t\tcolorFormat: gl.RGBA8,\n\t\t\t\t\t\tdepthFormat: glDepthFormat,\n\t\t\t\t\t\tscaleFactor: framebufferScaleFactor\n\t\t\t\t\t};\n\n\t\t\t\t\tglBinding = new XRWebGLBinding( session, gl );\n\n\t\t\t\t\tglProjLayer = glBinding.createProjectionLayer( projectionlayerInit );\n\n\t\t\t\t\tsession.updateRenderState( { layers: [ glProjLayer ] } );\n\n\t\t\t\t\trenderer.setPixelRatio( 1 );\n\t\t\t\t\trenderer.setSize( glProjLayer.textureWidth, glProjLayer.textureHeight, false );\n\n\t\t\t\t\tnewRenderTarget = new WebGLRenderTarget(\n\t\t\t\t\t\tglProjLayer.textureWidth,\n\t\t\t\t\t\tglProjLayer.textureHeight,\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\tformat: RGBAFormat,\n\t\t\t\t\t\t\ttype: UnsignedByteType,\n\t\t\t\t\t\t\tdepthTexture: new DepthTexture( glProjLayer.textureWidth, glProjLayer.textureHeight, depthType, undefined, undefined, undefined, undefined, undefined, undefined, depthFormat ),\n\t\t\t\t\t\t\tstencilBuffer: attributes.stencil,\n\t\t\t\t\t\t\tcolorSpace: renderer.outputColorSpace,\n\t\t\t\t\t\t\tsamples: attributes.antialias ? 4 : 0,\n\t\t\t\t\t\t\tresolveDepthBuffer: ( glProjLayer.ignoreDepthValues === false )\n\t\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t\tnewRenderTarget.isXRRenderTarget = true; // TODO Remove this when possible, see #23278\n\n\t\t\t\tthis.setFoveation( foveation );\n\n\t\t\t\tcustomReferenceSpace = null;\n\t\t\t\treferenceSpace = await session.requestReferenceSpace( referenceSpaceType );\n\n\t\t\t\tanimation.setContext( session );\n\t\t\t\tanimation.start();\n\n\t\t\t\tscope.isPresenting = true;\n\n\t\t\t\tscope.dispatchEvent( { type: 'sessionstart' } );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.getEnvironmentBlendMode = function () {\n\n\t\t\tif ( session !== null ) {\n\n\t\t\t\treturn session.environmentBlendMode;\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.getDepthTexture = function () {\n\n\t\t\treturn depthSensing.getDepthTexture();\n\n\t\t};\n\n\t\tfunction onInputSourcesChange( event ) {\n\n\t\t\t// Notify disconnected\n\n\t\t\tfor ( let i = 0; i < event.removed.length; i ++ ) {\n\n\t\t\t\tconst inputSource = event.removed[ i ];\n\t\t\t\tconst index = controllerInputSources.indexOf( inputSource );\n\n\t\t\t\tif ( index >= 0 ) {\n\n\t\t\t\t\tcontrollerInputSources[ index ] = null;\n\t\t\t\t\tcontrollers[ index ].disconnect( inputSource );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// Notify connected\n\n\t\t\tfor ( let i = 0; i < event.added.length; i ++ ) {\n\n\t\t\t\tconst inputSource = event.added[ i ];\n\n\t\t\t\tlet controllerIndex = controllerInputSources.indexOf( inputSource );\n\n\t\t\t\tif ( controllerIndex === - 1 ) {\n\n\t\t\t\t\t// Assign input source a controller that currently has no input source\n\n\t\t\t\t\tfor ( let i = 0; i < controllers.length; i ++ ) {\n\n\t\t\t\t\t\tif ( i >= controllerInputSources.length ) {\n\n\t\t\t\t\t\t\tcontrollerInputSources.push( inputSource );\n\t\t\t\t\t\t\tcontrollerIndex = i;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t} else if ( controllerInputSources[ i ] === null ) {\n\n\t\t\t\t\t\t\tcontrollerInputSources[ i ] = inputSource;\n\t\t\t\t\t\t\tcontrollerIndex = i;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// If all controllers do currently receive input we ignore new ones\n\n\t\t\t\t\tif ( controllerIndex === - 1 ) break;\n\n\t\t\t\t}\n\n\t\t\t\tconst controller = controllers[ controllerIndex ];\n\n\t\t\t\tif ( controller ) {\n\n\t\t\t\t\tcontroller.connect( inputSource );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t//\n\n\t\tconst cameraLPos = new Vector3();\n\t\tconst cameraRPos = new Vector3();\n\n\t\t/**\n\t\t * Assumes 2 cameras that are parallel and share an X-axis, and that\n\t\t * the cameras' projection and world matrices have already been set.\n\t\t * And that near and far planes are identical for both cameras.\n\t\t * Visualization of this technique: https://computergraphics.stackexchange.com/a/4765\n\t\t */\n\t\tfunction setProjectionFromUnion( camera, cameraL, cameraR ) {\n\n\t\t\tcameraLPos.setFromMatrixPosition( cameraL.matrixWorld );\n\t\t\tcameraRPos.setFromMatrixPosition( cameraR.matrixWorld );\n\n\t\t\tconst ipd = cameraLPos.distanceTo( cameraRPos );\n\n\t\t\tconst projL = cameraL.projectionMatrix.elements;\n\t\t\tconst projR = cameraR.projectionMatrix.elements;\n\n\t\t\t// VR systems will have identical far and near planes, and\n\t\t\t// most likely identical top and bottom frustum extents.\n\t\t\t// Use the left camera for these values.\n\t\t\tconst near = projL[ 14 ] / ( projL[ 10 ] - 1 );\n\t\t\tconst far = projL[ 14 ] / ( projL[ 10 ] + 1 );\n\t\t\tconst topFov = ( projL[ 9 ] + 1 ) / projL[ 5 ];\n\t\t\tconst bottomFov = ( projL[ 9 ] - 1 ) / projL[ 5 ];\n\n\t\t\tconst leftFov = ( projL[ 8 ] - 1 ) / projL[ 0 ];\n\t\t\tconst rightFov = ( projR[ 8 ] + 1 ) / projR[ 0 ];\n\t\t\tconst left = near * leftFov;\n\t\t\tconst right = near * rightFov;\n\n\t\t\t// Calculate the new camera's position offset from the\n\t\t\t// left camera. xOffset should be roughly half `ipd`.\n\t\t\tconst zOffset = ipd / ( - leftFov + rightFov );\n\t\t\tconst xOffset = zOffset * - leftFov;\n\n\t\t\t// TODO: Better way to apply this offset?\n\t\t\tcameraL.matrixWorld.decompose( camera.position, camera.quaternion, camera.scale );\n\t\t\tcamera.translateX( xOffset );\n\t\t\tcamera.translateZ( zOffset );\n\t\t\tcamera.matrixWorld.compose( camera.position, camera.quaternion, camera.scale );\n\t\t\tcamera.matrixWorldInverse.copy( camera.matrixWorld ).invert();\n\n\t\t\t// Find the union of the frustum values of the cameras and scale\n\t\t\t// the values so that the near plane's position does not change in world space,\n\t\t\t// although must now be relative to the new union camera.\n\t\t\tconst near2 = near + zOffset;\n\t\t\tconst far2 = far + zOffset;\n\t\t\tconst left2 = left - xOffset;\n\t\t\tconst right2 = right + ( ipd - xOffset );\n\t\t\tconst top2 = topFov * far / far2 * near2;\n\t\t\tconst bottom2 = bottomFov * far / far2 * near2;\n\n\t\t\tcamera.projectionMatrix.makePerspective( left2, right2, top2, bottom2, near2, far2 );\n\t\t\tcamera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();\n\n\t\t}\n\n\t\tfunction updateCamera( camera, parent ) {\n\n\t\t\tif ( parent === null ) {\n\n\t\t\t\tcamera.matrixWorld.copy( camera.matrix );\n\n\t\t\t} else {\n\n\t\t\t\tcamera.matrixWorld.multiplyMatrices( parent.matrixWorld, camera.matrix );\n\n\t\t\t}\n\n\t\t\tcamera.matrixWorldInverse.copy( camera.matrixWorld ).invert();\n\n\t\t}\n\n\t\tthis.updateCamera = function ( camera ) {\n\n\t\t\tif ( session === null ) return;\n\n\t\t\tif ( depthSensing.texture !== null ) {\n\n\t\t\t\tcamera.near = depthSensing.depthNear;\n\t\t\t\tcamera.far = depthSensing.depthFar;\n\n\t\t\t}\n\n\t\t\tcameraXR.near = cameraR.near = cameraL.near = camera.near;\n\t\t\tcameraXR.far = cameraR.far = cameraL.far = camera.far;\n\n\t\t\tif ( _currentDepthNear !== cameraXR.near || _currentDepthFar !== cameraXR.far ) {\n\n\t\t\t\t// Note that the new renderState won't apply until the next frame. See #18320\n\n\t\t\t\tsession.updateRenderState( {\n\t\t\t\t\tdepthNear: cameraXR.near,\n\t\t\t\t\tdepthFar: cameraXR.far\n\t\t\t\t} );\n\n\t\t\t\t_currentDepthNear = cameraXR.near;\n\t\t\t\t_currentDepthFar = cameraXR.far;\n\n\t\t\t\tcameraL.near = _currentDepthNear;\n\t\t\t\tcameraL.far = _currentDepthFar;\n\t\t\t\tcameraR.near = _currentDepthNear;\n\t\t\t\tcameraR.far = _currentDepthFar;\n\n\t\t\t\tcameraL.updateProjectionMatrix();\n\t\t\t\tcameraR.updateProjectionMatrix();\n\t\t\t\tcamera.updateProjectionMatrix();\n\n\t\t\t}\n\n\t\t\tconst parent = camera.parent;\n\t\t\tconst cameras = cameraXR.cameras;\n\n\t\t\tupdateCamera( cameraXR, parent );\n\n\t\t\tfor ( let i = 0; i < cameras.length; i ++ ) {\n\n\t\t\t\tupdateCamera( cameras[ i ], parent );\n\n\t\t\t}\n\n\t\t\t// update projection matrix for proper view frustum culling\n\n\t\t\tif ( cameras.length === 2 ) {\n\n\t\t\t\tsetProjectionFromUnion( cameraXR, cameraL, cameraR );\n\n\t\t\t} else {\n\n\t\t\t\t// assume single camera setup (AR)\n\n\t\t\t\tcameraXR.projectionMatrix.copy( cameraL.projectionMatrix );\n\n\t\t\t}\n\n\t\t\t// update user camera and its children\n\n\t\t\tupdateUserCamera( camera, cameraXR, parent );\n\n\t\t};\n\n\t\tfunction updateUserCamera( camera, cameraXR, parent ) {\n\n\t\t\tif ( parent === null ) {\n\n\t\t\t\tcamera.matrix.copy( cameraXR.matrixWorld );\n\n\t\t\t} else {\n\n\t\t\t\tcamera.matrix.copy( parent.matrixWorld );\n\t\t\t\tcamera.matrix.invert();\n\t\t\t\tcamera.matrix.multiply( cameraXR.matrixWorld );\n\n\t\t\t}\n\n\t\t\tcamera.matrix.decompose( camera.position, camera.quaternion, camera.scale );\n\t\t\tcamera.updateMatrixWorld( true );\n\n\t\t\tcamera.projectionMatrix.copy( cameraXR.projectionMatrix );\n\t\t\tcamera.projectionMatrixInverse.copy( cameraXR.projectionMatrixInverse );\n\n\t\t\tif ( camera.isPerspectiveCamera ) {\n\n\t\t\t\tcamera.fov = RAD2DEG * 2 * Math.atan( 1 / camera.projectionMatrix.elements[ 5 ] );\n\t\t\t\tcamera.zoom = 1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.getCamera = function () {\n\n\t\t\treturn cameraXR;\n\n\t\t};\n\n\t\tthis.getFoveation = function () {\n\n\t\t\tif ( glProjLayer === null && glBaseLayer === null ) {\n\n\t\t\t\treturn undefined;\n\n\t\t\t}\n\n\t\t\treturn foveation;\n\n\t\t};\n\n\t\tthis.setFoveation = function ( value ) {\n\n\t\t\t// 0 = no foveation = full resolution\n\t\t\t// 1 = maximum foveation = the edges render at lower resolution\n\n\t\t\tfoveation = value;\n\n\t\t\tif ( glProjLayer !== null ) {\n\n\t\t\t\tglProjLayer.fixedFoveation = value;\n\n\t\t\t}\n\n\t\t\tif ( glBaseLayer !== null && glBaseLayer.fixedFoveation !== undefined ) {\n\n\t\t\t\tglBaseLayer.fixedFoveation = value;\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.hasDepthSensing = function () {\n\n\t\t\treturn depthSensing.texture !== null;\n\n\t\t};\n\n\t\tthis.getDepthSensingMesh = function () {\n\n\t\t\treturn depthSensing.getMesh( cameraXR );\n\n\t\t};\n\n\t\t// Animation Loop\n\n\t\tlet onAnimationFrameCallback = null;\n\n\t\tfunction onAnimationFrame( time, frame ) {\n\n\t\t\tpose = frame.getViewerPose( customReferenceSpace || referenceSpace );\n\t\t\txrFrame = frame;\n\n\t\t\tif ( pose !== null ) {\n\n\t\t\t\tconst views = pose.views;\n\n\t\t\t\tif ( glBaseLayer !== null ) {\n\n\t\t\t\t\trenderer.setRenderTargetFramebuffer( newRenderTarget, glBaseLayer.framebuffer );\n\t\t\t\t\trenderer.setRenderTarget( newRenderTarget );\n\n\t\t\t\t}\n\n\t\t\t\tlet cameraXRNeedsUpdate = false;\n\n\t\t\t\t// check if it's necessary to rebuild cameraXR's camera list\n\n\t\t\t\tif ( views.length !== cameraXR.cameras.length ) {\n\n\t\t\t\t\tcameraXR.cameras.length = 0;\n\t\t\t\t\tcameraXRNeedsUpdate = true;\n\n\t\t\t\t}\n\n\t\t\t\tfor ( let i = 0; i < views.length; i ++ ) {\n\n\t\t\t\t\tconst view = views[ i ];\n\n\t\t\t\t\tlet viewport = null;\n\n\t\t\t\t\tif ( glBaseLayer !== null ) {\n\n\t\t\t\t\t\tviewport = glBaseLayer.getViewport( view );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconst glSubImage = glBinding.getViewSubImage( glProjLayer, view );\n\t\t\t\t\t\tviewport = glSubImage.viewport;\n\n\t\t\t\t\t\t// For side-by-side projection, we only produce a single texture for both eyes.\n\t\t\t\t\t\tif ( i === 0 ) {\n\n\t\t\t\t\t\t\trenderer.setRenderTargetTextures(\n\t\t\t\t\t\t\t\tnewRenderTarget,\n\t\t\t\t\t\t\t\tglSubImage.colorTexture,\n\t\t\t\t\t\t\t\tglProjLayer.ignoreDepthValues ? undefined : glSubImage.depthStencilTexture );\n\n\t\t\t\t\t\t\trenderer.setRenderTarget( newRenderTarget );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlet camera = cameras[ i ];\n\n\t\t\t\t\tif ( camera === undefined ) {\n\n\t\t\t\t\t\tcamera = new PerspectiveCamera();\n\t\t\t\t\t\tcamera.layers.enable( i );\n\t\t\t\t\t\tcamera.viewport = new Vector4();\n\t\t\t\t\t\tcameras[ i ] = camera;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tcamera.matrix.fromArray( view.transform.matrix );\n\t\t\t\t\tcamera.matrix.decompose( camera.position, camera.quaternion, camera.scale );\n\t\t\t\t\tcamera.projectionMatrix.fromArray( view.projectionMatrix );\n\t\t\t\t\tcamera.projectionMatrixInverse.copy( camera.projectionMatrix ).invert();\n\t\t\t\t\tcamera.viewport.set( viewport.x, viewport.y, viewport.width, viewport.height );\n\n\t\t\t\t\tif ( i === 0 ) {\n\n\t\t\t\t\t\tcameraXR.matrix.copy( camera.matrix );\n\t\t\t\t\t\tcameraXR.matrix.decompose( cameraXR.position, cameraXR.quaternion, cameraXR.scale );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( cameraXRNeedsUpdate === true ) {\n\n\t\t\t\t\t\tcameraXR.cameras.push( camera );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t//\n\n\t\t\t\tconst enabledFeatures = session.enabledFeatures;\n\n\t\t\t\tif ( enabledFeatures && enabledFeatures.includes( 'depth-sensing' ) ) {\n\n\t\t\t\t\tconst depthData = glBinding.getDepthInformation( views[ 0 ] );\n\n\t\t\t\t\tif ( depthData && depthData.isValid && depthData.texture ) {\n\n\t\t\t\t\t\tdepthSensing.init( renderer, depthData, session.renderState );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tfor ( let i = 0; i < controllers.length; i ++ ) {\n\n\t\t\t\tconst inputSource = controllerInputSources[ i ];\n\t\t\t\tconst controller = controllers[ i ];\n\n\t\t\t\tif ( inputSource !== null && controller !== undefined ) {\n\n\t\t\t\t\tcontroller.update( inputSource, frame, customReferenceSpace || referenceSpace );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( onAnimationFrameCallback ) onAnimationFrameCallback( time, frame );\n\n\t\t\tif ( frame.detectedPlanes ) {\n\n\t\t\t\tscope.dispatchEvent( { type: 'planesdetected', data: frame } );\n\n\t\t\t}\n\n\t\t\txrFrame = null;\n\n\t\t}\n\n\t\tconst animation = new WebGLAnimation();\n\n\t\tanimation.setAnimationLoop( onAnimationFrame );\n\n\t\tthis.setAnimationLoop = function ( callback ) {\n\n\t\t\tonAnimationFrameCallback = callback;\n\n\t\t};\n\n\t\tthis.dispose = function () {};\n\n\t}\n\n}\n\nconst _e1 = /*@__PURE__*/ new Euler();\nconst _m1 = /*@__PURE__*/ new Matrix4();\n\nfunction WebGLMaterials( renderer, properties ) {\n\n\tfunction refreshTransformUniform( map, uniform ) {\n\n\t\tif ( map.matrixAutoUpdate === true ) {\n\n\t\t\tmap.updateMatrix();\n\n\t\t}\n\n\t\tuniform.value.copy( map.matrix );\n\n\t}\n\n\tfunction refreshFogUniforms( uniforms, fog ) {\n\n\t\tfog.color.getRGB( uniforms.fogColor.value, getUnlitUniformColorSpace( renderer ) );\n\n\t\tif ( fog.isFog ) {\n\n\t\t\tuniforms.fogNear.value = fog.near;\n\t\t\tuniforms.fogFar.value = fog.far;\n\n\t\t} else if ( fog.isFogExp2 ) {\n\n\t\t\tuniforms.fogDensity.value = fog.density;\n\n\t\t}\n\n\t}\n\n\tfunction refreshMaterialUniforms( uniforms, material, pixelRatio, height, transmissionRenderTarget ) {\n\n\t\tif ( material.isMeshBasicMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\n\t\t} else if ( material.isMeshLambertMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\n\t\t} else if ( material.isMeshToonMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\t\t\trefreshUniformsToon( uniforms, material );\n\n\t\t} else if ( material.isMeshPhongMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\t\t\trefreshUniformsPhong( uniforms, material );\n\n\t\t} else if ( material.isMeshStandardMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\t\t\trefreshUniformsStandard( uniforms, material );\n\n\t\t\tif ( material.isMeshPhysicalMaterial ) {\n\n\t\t\t\trefreshUniformsPhysical( uniforms, material, transmissionRenderTarget );\n\n\t\t\t}\n\n\t\t} else if ( material.isMeshMatcapMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\t\t\trefreshUniformsMatcap( uniforms, material );\n\n\t\t} else if ( material.isMeshDepthMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\n\t\t} else if ( material.isMeshDistanceMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\t\t\trefreshUniformsDistance( uniforms, material );\n\n\t\t} else if ( material.isMeshNormalMaterial ) {\n\n\t\t\trefreshUniformsCommon( uniforms, material );\n\n\t\t} else if ( material.isLineBasicMaterial ) {\n\n\t\t\trefreshUniformsLine( uniforms, material );\n\n\t\t\tif ( material.isLineDashedMaterial ) {\n\n\t\t\t\trefreshUniformsDash( uniforms, material );\n\n\t\t\t}\n\n\t\t} else if ( material.isPointsMaterial ) {\n\n\t\t\trefreshUniformsPoints( uniforms, material, pixelRatio, height );\n\n\t\t} else if ( material.isSpriteMaterial ) {\n\n\t\t\trefreshUniformsSprites( uniforms, material );\n\n\t\t} else if ( material.isShadowMaterial ) {\n\n\t\t\tuniforms.color.value.copy( material.color );\n\t\t\tuniforms.opacity.value = material.opacity;\n\n\t\t} else if ( material.isShaderMaterial ) {\n\n\t\t\tmaterial.uniformsNeedUpdate = false; // #15581\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsCommon( uniforms, material ) {\n\n\t\tuniforms.opacity.value = material.opacity;\n\n\t\tif ( material.color ) {\n\n\t\t\tuniforms.diffuse.value.copy( material.color );\n\n\t\t}\n\n\t\tif ( material.emissive ) {\n\n\t\t\tuniforms.emissive.value.copy( material.emissive ).multiplyScalar( material.emissiveIntensity );\n\n\t\t}\n\n\t\tif ( material.map ) {\n\n\t\t\tuniforms.map.value = material.map;\n\n\t\t\trefreshTransformUniform( material.map, uniforms.mapTransform );\n\n\t\t}\n\n\t\tif ( material.alphaMap ) {\n\n\t\t\tuniforms.alphaMap.value = material.alphaMap;\n\n\t\t\trefreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );\n\n\t\t}\n\n\t\tif ( material.bumpMap ) {\n\n\t\t\tuniforms.bumpMap.value = material.bumpMap;\n\n\t\t\trefreshTransformUniform( material.bumpMap, uniforms.bumpMapTransform );\n\n\t\t\tuniforms.bumpScale.value = material.bumpScale;\n\n\t\t\tif ( material.side === BackSide ) {\n\n\t\t\t\tuniforms.bumpScale.value *= - 1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.normalMap ) {\n\n\t\t\tuniforms.normalMap.value = material.normalMap;\n\n\t\t\trefreshTransformUniform( material.normalMap, uniforms.normalMapTransform );\n\n\t\t\tuniforms.normalScale.value.copy( material.normalScale );\n\n\t\t\tif ( material.side === BackSide ) {\n\n\t\t\t\tuniforms.normalScale.value.negate();\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.displacementMap ) {\n\n\t\t\tuniforms.displacementMap.value = material.displacementMap;\n\n\t\t\trefreshTransformUniform( material.displacementMap, uniforms.displacementMapTransform );\n\n\t\t\tuniforms.displacementScale.value = material.displacementScale;\n\t\t\tuniforms.displacementBias.value = material.displacementBias;\n\n\t\t}\n\n\t\tif ( material.emissiveMap ) {\n\n\t\t\tuniforms.emissiveMap.value = material.emissiveMap;\n\n\t\t\trefreshTransformUniform( material.emissiveMap, uniforms.emissiveMapTransform );\n\n\t\t}\n\n\t\tif ( material.specularMap ) {\n\n\t\t\tuniforms.specularMap.value = material.specularMap;\n\n\t\t\trefreshTransformUniform( material.specularMap, uniforms.specularMapTransform );\n\n\t\t}\n\n\t\tif ( material.alphaTest > 0 ) {\n\n\t\t\tuniforms.alphaTest.value = material.alphaTest;\n\n\t\t}\n\n\t\tconst materialProperties = properties.get( material );\n\n\t\tconst envMap = materialProperties.envMap;\n\t\tconst envMapRotation = materialProperties.envMapRotation;\n\n\t\tif ( envMap ) {\n\n\t\t\tuniforms.envMap.value = envMap;\n\n\t\t\t_e1.copy( envMapRotation );\n\n\t\t\t// accommodate left-handed frame\n\t\t\t_e1.x *= - 1; _e1.y *= - 1; _e1.z *= - 1;\n\n\t\t\tif ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) {\n\n\t\t\t\t// environment maps which are not cube render targets or PMREMs follow a different convention\n\t\t\t\t_e1.y *= - 1;\n\t\t\t\t_e1.z *= - 1;\n\n\t\t\t}\n\n\t\t\tuniforms.envMapRotation.value.setFromMatrix4( _m1.makeRotationFromEuler( _e1 ) );\n\n\t\t\tuniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;\n\n\t\t\tuniforms.reflectivity.value = material.reflectivity;\n\t\t\tuniforms.ior.value = material.ior;\n\t\t\tuniforms.refractionRatio.value = material.refractionRatio;\n\n\t\t}\n\n\t\tif ( material.lightMap ) {\n\n\t\t\tuniforms.lightMap.value = material.lightMap;\n\t\t\tuniforms.lightMapIntensity.value = material.lightMapIntensity;\n\n\t\t\trefreshTransformUniform( material.lightMap, uniforms.lightMapTransform );\n\n\t\t}\n\n\t\tif ( material.aoMap ) {\n\n\t\t\tuniforms.aoMap.value = material.aoMap;\n\t\t\tuniforms.aoMapIntensity.value = material.aoMapIntensity;\n\n\t\t\trefreshTransformUniform( material.aoMap, uniforms.aoMapTransform );\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsLine( uniforms, material ) {\n\n\t\tuniforms.diffuse.value.copy( material.color );\n\t\tuniforms.opacity.value = material.opacity;\n\n\t\tif ( material.map ) {\n\n\t\t\tuniforms.map.value = material.map;\n\n\t\t\trefreshTransformUniform( material.map, uniforms.mapTransform );\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsDash( uniforms, material ) {\n\n\t\tuniforms.dashSize.value = material.dashSize;\n\t\tuniforms.totalSize.value = material.dashSize + material.gapSize;\n\t\tuniforms.scale.value = material.scale;\n\n\t}\n\n\tfunction refreshUniformsPoints( uniforms, material, pixelRatio, height ) {\n\n\t\tuniforms.diffuse.value.copy( material.color );\n\t\tuniforms.opacity.value = material.opacity;\n\t\tuniforms.size.value = material.size * pixelRatio;\n\t\tuniforms.scale.value = height * 0.5;\n\n\t\tif ( material.map ) {\n\n\t\t\tuniforms.map.value = material.map;\n\n\t\t\trefreshTransformUniform( material.map, uniforms.uvTransform );\n\n\t\t}\n\n\t\tif ( material.alphaMap ) {\n\n\t\t\tuniforms.alphaMap.value = material.alphaMap;\n\n\t\t\trefreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );\n\n\t\t}\n\n\t\tif ( material.alphaTest > 0 ) {\n\n\t\t\tuniforms.alphaTest.value = material.alphaTest;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsSprites( uniforms, material ) {\n\n\t\tuniforms.diffuse.value.copy( material.color );\n\t\tuniforms.opacity.value = material.opacity;\n\t\tuniforms.rotation.value = material.rotation;\n\n\t\tif ( material.map ) {\n\n\t\t\tuniforms.map.value = material.map;\n\n\t\t\trefreshTransformUniform( material.map, uniforms.mapTransform );\n\n\t\t}\n\n\t\tif ( material.alphaMap ) {\n\n\t\t\tuniforms.alphaMap.value = material.alphaMap;\n\n\t\t\trefreshTransformUniform( material.alphaMap, uniforms.alphaMapTransform );\n\n\t\t}\n\n\t\tif ( material.alphaTest > 0 ) {\n\n\t\t\tuniforms.alphaTest.value = material.alphaTest;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsPhong( uniforms, material ) {\n\n\t\tuniforms.specular.value.copy( material.specular );\n\t\tuniforms.shininess.value = Math.max( material.shininess, 1e-4 ); // to prevent pow( 0.0, 0.0 )\n\n\t}\n\n\tfunction refreshUniformsToon( uniforms, material ) {\n\n\t\tif ( material.gradientMap ) {\n\n\t\t\tuniforms.gradientMap.value = material.gradientMap;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsStandard( uniforms, material ) {\n\n\t\tuniforms.metalness.value = material.metalness;\n\n\t\tif ( material.metalnessMap ) {\n\n\t\t\tuniforms.metalnessMap.value = material.metalnessMap;\n\n\t\t\trefreshTransformUniform( material.metalnessMap, uniforms.metalnessMapTransform );\n\n\t\t}\n\n\t\tuniforms.roughness.value = material.roughness;\n\n\t\tif ( material.roughnessMap ) {\n\n\t\t\tuniforms.roughnessMap.value = material.roughnessMap;\n\n\t\t\trefreshTransformUniform( material.roughnessMap, uniforms.roughnessMapTransform );\n\n\t\t}\n\n\t\tif ( material.envMap ) {\n\n\t\t\t//uniforms.envMap.value = material.envMap; // part of uniforms common\n\n\t\t\tuniforms.envMapIntensity.value = material.envMapIntensity;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsPhysical( uniforms, material, transmissionRenderTarget ) {\n\n\t\tuniforms.ior.value = material.ior; // also part of uniforms common\n\n\t\tif ( material.sheen > 0 ) {\n\n\t\t\tuniforms.sheenColor.value.copy( material.sheenColor ).multiplyScalar( material.sheen );\n\n\t\t\tuniforms.sheenRoughness.value = material.sheenRoughness;\n\n\t\t\tif ( material.sheenColorMap ) {\n\n\t\t\t\tuniforms.sheenColorMap.value = material.sheenColorMap;\n\n\t\t\t\trefreshTransformUniform( material.sheenColorMap, uniforms.sheenColorMapTransform );\n\n\t\t\t}\n\n\t\t\tif ( material.sheenRoughnessMap ) {\n\n\t\t\t\tuniforms.sheenRoughnessMap.value = material.sheenRoughnessMap;\n\n\t\t\t\trefreshTransformUniform( material.sheenRoughnessMap, uniforms.sheenRoughnessMapTransform );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.clearcoat > 0 ) {\n\n\t\t\tuniforms.clearcoat.value = material.clearcoat;\n\t\t\tuniforms.clearcoatRoughness.value = material.clearcoatRoughness;\n\n\t\t\tif ( material.clearcoatMap ) {\n\n\t\t\t\tuniforms.clearcoatMap.value = material.clearcoatMap;\n\n\t\t\t\trefreshTransformUniform( material.clearcoatMap, uniforms.clearcoatMapTransform );\n\n\t\t\t}\n\n\t\t\tif ( material.clearcoatRoughnessMap ) {\n\n\t\t\t\tuniforms.clearcoatRoughnessMap.value = material.clearcoatRoughnessMap;\n\n\t\t\t\trefreshTransformUniform( material.clearcoatRoughnessMap, uniforms.clearcoatRoughnessMapTransform );\n\n\t\t\t}\n\n\t\t\tif ( material.clearcoatNormalMap ) {\n\n\t\t\t\tuniforms.clearcoatNormalMap.value = material.clearcoatNormalMap;\n\n\t\t\t\trefreshTransformUniform( material.clearcoatNormalMap, uniforms.clearcoatNormalMapTransform );\n\n\t\t\t\tuniforms.clearcoatNormalScale.value.copy( material.clearcoatNormalScale );\n\n\t\t\t\tif ( material.side === BackSide ) {\n\n\t\t\t\t\tuniforms.clearcoatNormalScale.value.negate();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.dispersion > 0 ) {\n\n\t\t\tuniforms.dispersion.value = material.dispersion;\n\n\t\t}\n\n\t\tif ( material.iridescence > 0 ) {\n\n\t\t\tuniforms.iridescence.value = material.iridescence;\n\t\t\tuniforms.iridescenceIOR.value = material.iridescenceIOR;\n\t\t\tuniforms.iridescenceThicknessMinimum.value = material.iridescenceThicknessRange[ 0 ];\n\t\t\tuniforms.iridescenceThicknessMaximum.value = material.iridescenceThicknessRange[ 1 ];\n\n\t\t\tif ( material.iridescenceMap ) {\n\n\t\t\t\tuniforms.iridescenceMap.value = material.iridescenceMap;\n\n\t\t\t\trefreshTransformUniform( material.iridescenceMap, uniforms.iridescenceMapTransform );\n\n\t\t\t}\n\n\t\t\tif ( material.iridescenceThicknessMap ) {\n\n\t\t\t\tuniforms.iridescenceThicknessMap.value = material.iridescenceThicknessMap;\n\n\t\t\t\trefreshTransformUniform( material.iridescenceThicknessMap, uniforms.iridescenceThicknessMapTransform );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( material.transmission > 0 ) {\n\n\t\t\tuniforms.transmission.value = material.transmission;\n\t\t\tuniforms.transmissionSamplerMap.value = transmissionRenderTarget.texture;\n\t\t\tuniforms.transmissionSamplerSize.value.set( transmissionRenderTarget.width, transmissionRenderTarget.height );\n\n\t\t\tif ( material.transmissionMap ) {\n\n\t\t\t\tuniforms.transmissionMap.value = material.transmissionMap;\n\n\t\t\t\trefreshTransformUniform( material.transmissionMap, uniforms.transmissionMapTransform );\n\n\t\t\t}\n\n\t\t\tuniforms.thickness.value = material.thickness;\n\n\t\t\tif ( material.thicknessMap ) {\n\n\t\t\t\tuniforms.thicknessMap.value = material.thicknessMap;\n\n\t\t\t\trefreshTransformUniform( material.thicknessMap, uniforms.thicknessMapTransform );\n\n\t\t\t}\n\n\t\t\tuniforms.attenuationDistance.value = material.attenuationDistance;\n\t\t\tuniforms.attenuationColor.value.copy( material.attenuationColor );\n\n\t\t}\n\n\t\tif ( material.anisotropy > 0 ) {\n\n\t\t\tuniforms.anisotropyVector.value.set( material.anisotropy * Math.cos( material.anisotropyRotation ), material.anisotropy * Math.sin( material.anisotropyRotation ) );\n\n\t\t\tif ( material.anisotropyMap ) {\n\n\t\t\t\tuniforms.anisotropyMap.value = material.anisotropyMap;\n\n\t\t\t\trefreshTransformUniform( material.anisotropyMap, uniforms.anisotropyMapTransform );\n\n\t\t\t}\n\n\t\t}\n\n\t\tuniforms.specularIntensity.value = material.specularIntensity;\n\t\tuniforms.specularColor.value.copy( material.specularColor );\n\n\t\tif ( material.specularColorMap ) {\n\n\t\t\tuniforms.specularColorMap.value = material.specularColorMap;\n\n\t\t\trefreshTransformUniform( material.specularColorMap, uniforms.specularColorMapTransform );\n\n\t\t}\n\n\t\tif ( material.specularIntensityMap ) {\n\n\t\t\tuniforms.specularIntensityMap.value = material.specularIntensityMap;\n\n\t\t\trefreshTransformUniform( material.specularIntensityMap, uniforms.specularIntensityMapTransform );\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsMatcap( uniforms, material ) {\n\n\t\tif ( material.matcap ) {\n\n\t\t\tuniforms.matcap.value = material.matcap;\n\n\t\t}\n\n\t}\n\n\tfunction refreshUniformsDistance( uniforms, material ) {\n\n\t\tconst light = properties.get( material ).light;\n\n\t\tuniforms.referencePosition.value.setFromMatrixPosition( light.matrixWorld );\n\t\tuniforms.nearDistance.value = light.shadow.camera.near;\n\t\tuniforms.farDistance.value = light.shadow.camera.far;\n\n\t}\n\n\treturn {\n\t\trefreshFogUniforms: refreshFogUniforms,\n\t\trefreshMaterialUniforms: refreshMaterialUniforms\n\t};\n\n}\n\nfunction WebGLUniformsGroups( gl, info, capabilities, state ) {\n\n\tlet buffers = {};\n\tlet updateList = {};\n\tlet allocatedBindingPoints = [];\n\n\tconst maxBindingPoints = gl.getParameter( gl.MAX_UNIFORM_BUFFER_BINDINGS ); // binding points are global whereas block indices are per shader program\n\n\tfunction bind( uniformsGroup, program ) {\n\n\t\tconst webglProgram = program.program;\n\t\tstate.uniformBlockBinding( uniformsGroup, webglProgram );\n\n\t}\n\n\tfunction update( uniformsGroup, program ) {\n\n\t\tlet buffer = buffers[ uniformsGroup.id ];\n\n\t\tif ( buffer === undefined ) {\n\n\t\t\tprepareUniformsGroup( uniformsGroup );\n\n\t\t\tbuffer = createBuffer( uniformsGroup );\n\t\t\tbuffers[ uniformsGroup.id ] = buffer;\n\n\t\t\tuniformsGroup.addEventListener( 'dispose', onUniformsGroupsDispose );\n\n\t\t}\n\n\t\t// ensure to update the binding points/block indices mapping for this program\n\n\t\tconst webglProgram = program.program;\n\t\tstate.updateUBOMapping( uniformsGroup, webglProgram );\n\n\t\t// update UBO once per frame\n\n\t\tconst frame = info.render.frame;\n\n\t\tif ( updateList[ uniformsGroup.id ] !== frame ) {\n\n\t\t\tupdateBufferData( uniformsGroup );\n\n\t\t\tupdateList[ uniformsGroup.id ] = frame;\n\n\t\t}\n\n\t}\n\n\tfunction createBuffer( uniformsGroup ) {\n\n\t\t// the setup of an UBO is independent of a particular shader program but global\n\n\t\tconst bindingPointIndex = allocateBindingPointIndex();\n\t\tuniformsGroup.__bindingPointIndex = bindingPointIndex;\n\n\t\tconst buffer = gl.createBuffer();\n\t\tconst size = uniformsGroup.__size;\n\t\tconst usage = uniformsGroup.usage;\n\n\t\tgl.bindBuffer( gl.UNIFORM_BUFFER, buffer );\n\t\tgl.bufferData( gl.UNIFORM_BUFFER, size, usage );\n\t\tgl.bindBuffer( gl.UNIFORM_BUFFER, null );\n\t\tgl.bindBufferBase( gl.UNIFORM_BUFFER, bindingPointIndex, buffer );\n\n\t\treturn buffer;\n\n\t}\n\n\tfunction allocateBindingPointIndex() {\n\n\t\tfor ( let i = 0; i < maxBindingPoints; i ++ ) {\n\n\t\t\tif ( allocatedBindingPoints.indexOf( i ) === - 1 ) {\n\n\t\t\t\tallocatedBindingPoints.push( i );\n\t\t\t\treturn i;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconsole.error( 'THREE.WebGLRenderer: Maximum number of simultaneously usable uniforms groups reached.' );\n\n\t\treturn 0;\n\n\t}\n\n\tfunction updateBufferData( uniformsGroup ) {\n\n\t\tconst buffer = buffers[ uniformsGroup.id ];\n\t\tconst uniforms = uniformsGroup.uniforms;\n\t\tconst cache = uniformsGroup.__cache;\n\n\t\tgl.bindBuffer( gl.UNIFORM_BUFFER, buffer );\n\n\t\tfor ( let i = 0, il = uniforms.length; i < il; i ++ ) {\n\n\t\t\tconst uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];\n\n\t\t\tfor ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {\n\n\t\t\t\tconst uniform = uniformArray[ j ];\n\n\t\t\t\tif ( hasUniformChanged( uniform, i, j, cache ) === true ) {\n\n\t\t\t\t\tconst offset = uniform.__offset;\n\n\t\t\t\t\tconst values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];\n\n\t\t\t\t\tlet arrayOffset = 0;\n\n\t\t\t\t\tfor ( let k = 0; k < values.length; k ++ ) {\n\n\t\t\t\t\t\tconst value = values[ k ];\n\n\t\t\t\t\t\tconst info = getUniformSize( value );\n\n\t\t\t\t\t\t// TODO add integer and struct support\n\t\t\t\t\t\tif ( typeof value === 'number' || typeof value === 'boolean' ) {\n\n\t\t\t\t\t\t\tuniform.__data[ 0 ] = value;\n\t\t\t\t\t\t\tgl.bufferSubData( gl.UNIFORM_BUFFER, offset + arrayOffset, uniform.__data );\n\n\t\t\t\t\t\t} else if ( value.isMatrix3 ) {\n\n\t\t\t\t\t\t\t// manually converting 3x3 to 3x4\n\n\t\t\t\t\t\t\tuniform.__data[ 0 ] = value.elements[ 0 ];\n\t\t\t\t\t\t\tuniform.__data[ 1 ] = value.elements[ 1 ];\n\t\t\t\t\t\t\tuniform.__data[ 2 ] = value.elements[ 2 ];\n\t\t\t\t\t\t\tuniform.__data[ 3 ] = 0;\n\t\t\t\t\t\t\tuniform.__data[ 4 ] = value.elements[ 3 ];\n\t\t\t\t\t\t\tuniform.__data[ 5 ] = value.elements[ 4 ];\n\t\t\t\t\t\t\tuniform.__data[ 6 ] = value.elements[ 5 ];\n\t\t\t\t\t\t\tuniform.__data[ 7 ] = 0;\n\t\t\t\t\t\t\tuniform.__data[ 8 ] = value.elements[ 6 ];\n\t\t\t\t\t\t\tuniform.__data[ 9 ] = value.elements[ 7 ];\n\t\t\t\t\t\t\tuniform.__data[ 10 ] = value.elements[ 8 ];\n\t\t\t\t\t\t\tuniform.__data[ 11 ] = 0;\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tvalue.toArray( uniform.__data, arrayOffset );\n\n\t\t\t\t\t\t\tarrayOffset += info.storage / Float32Array.BYTES_PER_ELEMENT;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tgl.bufferSubData( gl.UNIFORM_BUFFER, offset, uniform.__data );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tgl.bindBuffer( gl.UNIFORM_BUFFER, null );\n\n\t}\n\n\tfunction hasUniformChanged( uniform, index, indexArray, cache ) {\n\n\t\tconst value = uniform.value;\n\t\tconst indexString = index + '_' + indexArray;\n\n\t\tif ( cache[ indexString ] === undefined ) {\n\n\t\t\t// cache entry does not exist so far\n\n\t\t\tif ( typeof value === 'number' || typeof value === 'boolean' ) {\n\n\t\t\t\tcache[ indexString ] = value;\n\n\t\t\t} else {\n\n\t\t\t\tcache[ indexString ] = value.clone();\n\n\t\t\t}\n\n\t\t\treturn true;\n\n\t\t} else {\n\n\t\t\tconst cachedObject = cache[ indexString ];\n\n\t\t\t// compare current value with cached entry\n\n\t\t\tif ( typeof value === 'number' || typeof value === 'boolean' ) {\n\n\t\t\t\tif ( cachedObject !== value ) {\n\n\t\t\t\t\tcache[ indexString ] = value;\n\t\t\t\t\treturn true;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( cachedObject.equals( value ) === false ) {\n\n\t\t\t\t\tcachedObject.copy( value );\n\t\t\t\t\treturn true;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn false;\n\n\t}\n\n\tfunction prepareUniformsGroup( uniformsGroup ) {\n\n\t\t// determine total buffer size according to the STD140 layout\n\t\t// Hint: STD140 is the only supported layout in WebGL 2\n\n\t\tconst uniforms = uniformsGroup.uniforms;\n\n\t\tlet offset = 0; // global buffer offset in bytes\n\t\tconst chunkSize = 16; // size of a chunk in bytes\n\n\t\tfor ( let i = 0, l = uniforms.length; i < l; i ++ ) {\n\n\t\t\tconst uniformArray = Array.isArray( uniforms[ i ] ) ? uniforms[ i ] : [ uniforms[ i ] ];\n\n\t\t\tfor ( let j = 0, jl = uniformArray.length; j < jl; j ++ ) {\n\n\t\t\t\tconst uniform = uniformArray[ j ];\n\n\t\t\t\tconst values = Array.isArray( uniform.value ) ? uniform.value : [ uniform.value ];\n\n\t\t\t\tfor ( let k = 0, kl = values.length; k < kl; k ++ ) {\n\n\t\t\t\t\tconst value = values[ k ];\n\n\t\t\t\t\tconst info = getUniformSize( value );\n\n\t\t\t\t\tconst chunkOffset = offset % chunkSize; // offset in the current chunk\n\t\t\t\t\tconst chunkPadding = chunkOffset % info.boundary; // required padding to match boundary\n\t\t\t\t\tconst chunkStart = chunkOffset + chunkPadding; // the start position in the current chunk for the data\n\n\t\t\t\t\toffset += chunkPadding;\n\n\t\t\t\t\t// Check for chunk overflow\n\t\t\t\t\tif ( chunkStart !== 0 && ( chunkSize - chunkStart ) < info.storage ) {\n\n\t\t\t\t\t\t// Add padding and adjust offset\n\t\t\t\t\t\toffset += ( chunkSize - chunkStart );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// the following two properties will be used for partial buffer updates\n\t\t\t\t\tuniform.__data = new Float32Array( info.storage / Float32Array.BYTES_PER_ELEMENT );\n\t\t\t\t\tuniform.__offset = offset;\n\n\t\t\t\t\t// Update the global offset\n\t\t\t\t\toffset += info.storage;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// ensure correct final padding\n\n\t\tconst chunkOffset = offset % chunkSize;\n\n\t\tif ( chunkOffset > 0 ) offset += ( chunkSize - chunkOffset );\n\n\t\t//\n\n\t\tuniformsGroup.__size = offset;\n\t\tuniformsGroup.__cache = {};\n\n\t\treturn this;\n\n\t}\n\n\tfunction getUniformSize( value ) {\n\n\t\tconst info = {\n\t\t\tboundary: 0, // bytes\n\t\t\tstorage: 0 // bytes\n\t\t};\n\n\t\t// determine sizes according to STD140\n\n\t\tif ( typeof value === 'number' || typeof value === 'boolean' ) {\n\n\t\t\t// float/int/bool\n\n\t\t\tinfo.boundary = 4;\n\t\t\tinfo.storage = 4;\n\n\t\t} else if ( value.isVector2 ) {\n\n\t\t\t// vec2\n\n\t\t\tinfo.boundary = 8;\n\t\t\tinfo.storage = 8;\n\n\t\t} else if ( value.isVector3 || value.isColor ) {\n\n\t\t\t// vec3\n\n\t\t\tinfo.boundary = 16;\n\t\t\tinfo.storage = 12; // evil: vec3 must start on a 16-byte boundary but it only consumes 12 bytes\n\n\t\t} else if ( value.isVector4 ) {\n\n\t\t\t// vec4\n\n\t\t\tinfo.boundary = 16;\n\t\t\tinfo.storage = 16;\n\n\t\t} else if ( value.isMatrix3 ) {\n\n\t\t\t// mat3 (in STD140 a 3x3 matrix is represented as 3x4)\n\n\t\t\tinfo.boundary = 48;\n\t\t\tinfo.storage = 48;\n\n\t\t} else if ( value.isMatrix4 ) {\n\n\t\t\t// mat4\n\n\t\t\tinfo.boundary = 64;\n\t\t\tinfo.storage = 64;\n\n\t\t} else if ( value.isTexture ) {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: Texture samplers can not be part of an uniforms group.' );\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.WebGLRenderer: Unsupported uniform value type.', value );\n\n\t\t}\n\n\t\treturn info;\n\n\t}\n\n\tfunction onUniformsGroupsDispose( event ) {\n\n\t\tconst uniformsGroup = event.target;\n\n\t\tuniformsGroup.removeEventListener( 'dispose', onUniformsGroupsDispose );\n\n\t\tconst index = allocatedBindingPoints.indexOf( uniformsGroup.__bindingPointIndex );\n\t\tallocatedBindingPoints.splice( index, 1 );\n\n\t\tgl.deleteBuffer( buffers[ uniformsGroup.id ] );\n\n\t\tdelete buffers[ uniformsGroup.id ];\n\t\tdelete updateList[ uniformsGroup.id ];\n\n\t}\n\n\tfunction dispose() {\n\n\t\tfor ( const id in buffers ) {\n\n\t\t\tgl.deleteBuffer( buffers[ id ] );\n\n\t\t}\n\n\t\tallocatedBindingPoints = [];\n\t\tbuffers = {};\n\t\tupdateList = {};\n\n\t}\n\n\treturn {\n\n\t\tbind: bind,\n\t\tupdate: update,\n\n\t\tdispose: dispose\n\n\t};\n\n}\n\nclass WebGLRenderer {\n\n\tconstructor( parameters = {} ) {\n\n\t\tconst {\n\t\t\tcanvas = createCanvasElement(),\n\t\t\tcontext = null,\n\t\t\tdepth = true,\n\t\t\tstencil = false,\n\t\t\talpha = false,\n\t\t\tantialias = false,\n\t\t\tpremultipliedAlpha = true,\n\t\t\tpreserveDrawingBuffer = false,\n\t\t\tpowerPreference = 'default',\n\t\t\tfailIfMajorPerformanceCaveat = false,\n\t\t} = parameters;\n\n\t\tthis.isWebGLRenderer = true;\n\n\t\tlet _alpha;\n\n\t\tif ( context !== null ) {\n\n\t\t\tif ( typeof WebGLRenderingContext !== 'undefined' && context instanceof WebGLRenderingContext ) {\n\n\t\t\t\tthrow new Error( 'THREE.WebGLRenderer: WebGL 1 is not supported since r163.' );\n\n\t\t\t}\n\n\t\t\t_alpha = context.getContextAttributes().alpha;\n\n\t\t} else {\n\n\t\t\t_alpha = alpha;\n\n\t\t}\n\n\t\tconst uintClearColor = new Uint32Array( 4 );\n\t\tconst intClearColor = new Int32Array( 4 );\n\n\t\tlet currentRenderList = null;\n\t\tlet currentRenderState = null;\n\n\t\t// render() can be called from within a callback triggered by another render.\n\t\t// We track this so that the nested render call gets its list and state isolated from the parent render call.\n\n\t\tconst renderListStack = [];\n\t\tconst renderStateStack = [];\n\n\t\t// public properties\n\n\t\tthis.domElement = canvas;\n\n\t\t// Debug configuration container\n\t\tthis.debug = {\n\n\t\t\t/**\n\t\t\t * Enables error checking and reporting when shader programs are being compiled\n\t\t\t * @type {boolean}\n\t\t\t */\n\t\t\tcheckShaderErrors: true,\n\t\t\t/**\n\t\t\t * Callback for custom error reporting.\n\t\t\t * @type {?Function}\n\t\t\t */\n\t\t\tonShaderError: null\n\t\t};\n\n\t\t// clearing\n\n\t\tthis.autoClear = true;\n\t\tthis.autoClearColor = true;\n\t\tthis.autoClearDepth = true;\n\t\tthis.autoClearStencil = true;\n\n\t\t// scene graph\n\n\t\tthis.sortObjects = true;\n\n\t\t// user-defined clipping\n\n\t\tthis.clippingPlanes = [];\n\t\tthis.localClippingEnabled = false;\n\n\t\t// physically based shading\n\n\t\tthis._outputColorSpace = SRGBColorSpace;\n\n\t\t// tone mapping\n\n\t\tthis.toneMapping = NoToneMapping;\n\t\tthis.toneMappingExposure = 1.0;\n\n\t\t// internal properties\n\n\t\tconst _this = this;\n\n\t\tlet _isContextLost = false;\n\n\t\t// internal state cache\n\n\t\tlet _currentActiveCubeFace = 0;\n\t\tlet _currentActiveMipmapLevel = 0;\n\t\tlet _currentRenderTarget = null;\n\t\tlet _currentMaterialId = - 1;\n\n\t\tlet _currentCamera = null;\n\n\t\tconst _currentViewport = new Vector4();\n\t\tconst _currentScissor = new Vector4();\n\t\tlet _currentScissorTest = null;\n\n\t\tconst _currentClearColor = new Color( 0x000000 );\n\t\tlet _currentClearAlpha = 0;\n\n\t\t//\n\n\t\tlet _width = canvas.width;\n\t\tlet _height = canvas.height;\n\n\t\tlet _pixelRatio = 1;\n\t\tlet _opaqueSort = null;\n\t\tlet _transparentSort = null;\n\n\t\tconst _viewport = new Vector4( 0, 0, _width, _height );\n\t\tconst _scissor = new Vector4( 0, 0, _width, _height );\n\t\tlet _scissorTest = false;\n\n\t\t// frustum\n\n\t\tconst _frustum = new Frustum();\n\n\t\t// clipping\n\n\t\tlet _clippingEnabled = false;\n\t\tlet _localClippingEnabled = false;\n\n\t\t// camera matrices cache\n\n\t\tconst _projScreenMatrix = new Matrix4();\n\n\t\tconst _vector3 = new Vector3();\n\n\t\tconst _vector4 = new Vector4();\n\n\t\tconst _emptyScene = { background: null, fog: null, environment: null, overrideMaterial: null, isScene: true };\n\n\t\tlet _renderBackground = false;\n\n\t\tfunction getTargetPixelRatio() {\n\n\t\t\treturn _currentRenderTarget === null ? _pixelRatio : 1;\n\n\t\t}\n\n\t\t// initialize\n\n\t\tlet _gl = context;\n\n\t\tfunction getContext( contextName, contextAttributes ) {\n\n\t\t\treturn canvas.getContext( contextName, contextAttributes );\n\n\t\t}\n\n\t\ttry {\n\n\t\t\tconst contextAttributes = {\n\t\t\t\talpha: true,\n\t\t\t\tdepth,\n\t\t\t\tstencil,\n\t\t\t\tantialias,\n\t\t\t\tpremultipliedAlpha,\n\t\t\t\tpreserveDrawingBuffer,\n\t\t\t\tpowerPreference,\n\t\t\t\tfailIfMajorPerformanceCaveat,\n\t\t\t};\n\n\t\t\t// OffscreenCanvas does not have setAttribute, see #22811\n\t\t\tif ( 'setAttribute' in canvas ) canvas.setAttribute( 'data-engine', `three.js r${REVISION}` );\n\n\t\t\t// event listeners must be registered before WebGL context is created, see #12753\n\t\t\tcanvas.addEventListener( 'webglcontextlost', onContextLost, false );\n\t\t\tcanvas.addEventListener( 'webglcontextrestored', onContextRestore, false );\n\t\t\tcanvas.addEventListener( 'webglcontextcreationerror', onContextCreationError, false );\n\n\t\t\tif ( _gl === null ) {\n\n\t\t\t\tconst contextName = 'webgl2';\n\n\t\t\t\t_gl = getContext( contextName, contextAttributes );\n\n\t\t\t\tif ( _gl === null ) {\n\n\t\t\t\t\tif ( getContext( contextName ) ) {\n\n\t\t\t\t\t\tthrow new Error( 'Error creating WebGL context with your selected attributes.' );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tthrow new Error( 'Error creating WebGL context.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} catch ( error ) {\n\n\t\t\tconsole.error( 'THREE.WebGLRenderer: ' + error.message );\n\t\t\tthrow error;\n\n\t\t}\n\n\t\tlet extensions, capabilities, state, info;\n\t\tlet properties, textures, cubemaps, cubeuvmaps, attributes, geometries, objects;\n\t\tlet programCache, materials, renderLists, renderStates, clipping, shadowMap;\n\n\t\tlet background, morphtargets, bufferRenderer, indexedBufferRenderer;\n\n\t\tlet utils, bindingStates, uniformsGroups;\n\n\t\tfunction initGLContext() {\n\n\t\t\textensions = new WebGLExtensions( _gl );\n\t\t\textensions.init();\n\n\t\t\tutils = new WebGLUtils( _gl, extensions );\n\n\t\t\tcapabilities = new WebGLCapabilities( _gl, extensions, parameters, utils );\n\n\t\t\tstate = new WebGLState( _gl );\n\n\t\t\tinfo = new WebGLInfo( _gl );\n\t\t\tproperties = new WebGLProperties();\n\t\t\ttextures = new WebGLTextures( _gl, extensions, state, properties, capabilities, utils, info );\n\t\t\tcubemaps = new WebGLCubeMaps( _this );\n\t\t\tcubeuvmaps = new WebGLCubeUVMaps( _this );\n\t\t\tattributes = new WebGLAttributes( _gl );\n\t\t\tbindingStates = new WebGLBindingStates( _gl, attributes );\n\t\t\tgeometries = new WebGLGeometries( _gl, attributes, info, bindingStates );\n\t\t\tobjects = new WebGLObjects( _gl, geometries, attributes, info );\n\t\t\tmorphtargets = new WebGLMorphtargets( _gl, capabilities, textures );\n\t\t\tclipping = new WebGLClipping( properties );\n\t\t\tprogramCache = new WebGLPrograms( _this, cubemaps, cubeuvmaps, extensions, capabilities, bindingStates, clipping );\n\t\t\tmaterials = new WebGLMaterials( _this, properties );\n\t\t\trenderLists = new WebGLRenderLists();\n\t\t\trenderStates = new WebGLRenderStates( extensions );\n\t\t\tbackground = new WebGLBackground( _this, cubemaps, cubeuvmaps, state, objects, _alpha, premultipliedAlpha );\n\t\t\tshadowMap = new WebGLShadowMap( _this, objects, capabilities );\n\t\t\tuniformsGroups = new WebGLUniformsGroups( _gl, info, capabilities, state );\n\n\t\t\tbufferRenderer = new WebGLBufferRenderer( _gl, extensions, info );\n\t\t\tindexedBufferRenderer = new WebGLIndexedBufferRenderer( _gl, extensions, info );\n\n\t\t\tinfo.programs = programCache.programs;\n\n\t\t\t_this.capabilities = capabilities;\n\t\t\t_this.extensions = extensions;\n\t\t\t_this.properties = properties;\n\t\t\t_this.renderLists = renderLists;\n\t\t\t_this.shadowMap = shadowMap;\n\t\t\t_this.state = state;\n\t\t\t_this.info = info;\n\n\t\t}\n\n\t\tinitGLContext();\n\n\t\t// xr\n\n\t\tconst xr = new WebXRManager( _this, _gl );\n\n\t\tthis.xr = xr;\n\n\t\t// API\n\n\t\tthis.getContext = function () {\n\n\t\t\treturn _gl;\n\n\t\t};\n\n\t\tthis.getContextAttributes = function () {\n\n\t\t\treturn _gl.getContextAttributes();\n\n\t\t};\n\n\t\tthis.forceContextLoss = function () {\n\n\t\t\tconst extension = extensions.get( 'WEBGL_lose_context' );\n\t\t\tif ( extension ) extension.loseContext();\n\n\t\t};\n\n\t\tthis.forceContextRestore = function () {\n\n\t\t\tconst extension = extensions.get( 'WEBGL_lose_context' );\n\t\t\tif ( extension ) extension.restoreContext();\n\n\t\t};\n\n\t\tthis.getPixelRatio = function () {\n\n\t\t\treturn _pixelRatio;\n\n\t\t};\n\n\t\tthis.setPixelRatio = function ( value ) {\n\n\t\t\tif ( value === undefined ) return;\n\n\t\t\t_pixelRatio = value;\n\n\t\t\tthis.setSize( _width, _height, false );\n\n\t\t};\n\n\t\tthis.getSize = function ( target ) {\n\n\t\t\treturn target.set( _width, _height );\n\n\t\t};\n\n\t\tthis.setSize = function ( width, height, updateStyle = true ) {\n\n\t\t\tif ( xr.isPresenting ) {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Can\\'t change size while VR device is presenting.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\t_width = width;\n\t\t\t_height = height;\n\n\t\t\tcanvas.width = Math.floor( width * _pixelRatio );\n\t\t\tcanvas.height = Math.floor( height * _pixelRatio );\n\n\t\t\tif ( updateStyle === true ) {\n\n\t\t\t\tcanvas.style.width = width + 'px';\n\t\t\t\tcanvas.style.height = height + 'px';\n\n\t\t\t}\n\n\t\t\tthis.setViewport( 0, 0, width, height );\n\n\t\t};\n\n\t\tthis.getDrawingBufferSize = function ( target ) {\n\n\t\t\treturn target.set( _width * _pixelRatio, _height * _pixelRatio ).floor();\n\n\t\t};\n\n\t\tthis.setDrawingBufferSize = function ( width, height, pixelRatio ) {\n\n\t\t\t_width = width;\n\t\t\t_height = height;\n\n\t\t\t_pixelRatio = pixelRatio;\n\n\t\t\tcanvas.width = Math.floor( width * pixelRatio );\n\t\t\tcanvas.height = Math.floor( height * pixelRatio );\n\n\t\t\tthis.setViewport( 0, 0, width, height );\n\n\t\t};\n\n\t\tthis.getCurrentViewport = function ( target ) {\n\n\t\t\treturn target.copy( _currentViewport );\n\n\t\t};\n\n\t\tthis.getViewport = function ( target ) {\n\n\t\t\treturn target.copy( _viewport );\n\n\t\t};\n\n\t\tthis.setViewport = function ( x, y, width, height ) {\n\n\t\t\tif ( x.isVector4 ) {\n\n\t\t\t\t_viewport.set( x.x, x.y, x.z, x.w );\n\n\t\t\t} else {\n\n\t\t\t\t_viewport.set( x, y, width, height );\n\n\t\t\t}\n\n\t\t\tstate.viewport( _currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).round() );\n\n\t\t};\n\n\t\tthis.getScissor = function ( target ) {\n\n\t\t\treturn target.copy( _scissor );\n\n\t\t};\n\n\t\tthis.setScissor = function ( x, y, width, height ) {\n\n\t\t\tif ( x.isVector4 ) {\n\n\t\t\t\t_scissor.set( x.x, x.y, x.z, x.w );\n\n\t\t\t} else {\n\n\t\t\t\t_scissor.set( x, y, width, height );\n\n\t\t\t}\n\n\t\t\tstate.scissor( _currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).round() );\n\n\t\t};\n\n\t\tthis.getScissorTest = function () {\n\n\t\t\treturn _scissorTest;\n\n\t\t};\n\n\t\tthis.setScissorTest = function ( boolean ) {\n\n\t\t\tstate.setScissorTest( _scissorTest = boolean );\n\n\t\t};\n\n\t\tthis.setOpaqueSort = function ( method ) {\n\n\t\t\t_opaqueSort = method;\n\n\t\t};\n\n\t\tthis.setTransparentSort = function ( method ) {\n\n\t\t\t_transparentSort = method;\n\n\t\t};\n\n\t\t// Clearing\n\n\t\tthis.getClearColor = function ( target ) {\n\n\t\t\treturn target.copy( background.getClearColor() );\n\n\t\t};\n\n\t\tthis.setClearColor = function () {\n\n\t\t\tbackground.setClearColor.apply( background, arguments );\n\n\t\t};\n\n\t\tthis.getClearAlpha = function () {\n\n\t\t\treturn background.getClearAlpha();\n\n\t\t};\n\n\t\tthis.setClearAlpha = function () {\n\n\t\t\tbackground.setClearAlpha.apply( background, arguments );\n\n\t\t};\n\n\t\tthis.clear = function ( color = true, depth = true, stencil = true ) {\n\n\t\t\tlet bits = 0;\n\n\t\t\tif ( color ) {\n\n\t\t\t\t// check if we're trying to clear an integer target\n\t\t\t\tlet isIntegerFormat = false;\n\t\t\t\tif ( _currentRenderTarget !== null ) {\n\n\t\t\t\t\tconst targetFormat = _currentRenderTarget.texture.format;\n\t\t\t\t\tisIntegerFormat = targetFormat === RGBAIntegerFormat ||\n\t\t\t\t\t\ttargetFormat === RGIntegerFormat ||\n\t\t\t\t\t\ttargetFormat === RedIntegerFormat;\n\n\t\t\t\t}\n\n\t\t\t\t// use the appropriate clear functions to clear the target if it's a signed\n\t\t\t\t// or unsigned integer target\n\t\t\t\tif ( isIntegerFormat ) {\n\n\t\t\t\t\tconst targetType = _currentRenderTarget.texture.type;\n\t\t\t\t\tconst isUnsignedType = targetType === UnsignedByteType ||\n\t\t\t\t\t\ttargetType === UnsignedIntType ||\n\t\t\t\t\t\ttargetType === UnsignedShortType ||\n\t\t\t\t\t\ttargetType === UnsignedInt248Type ||\n\t\t\t\t\t\ttargetType === UnsignedShort4444Type ||\n\t\t\t\t\t\ttargetType === UnsignedShort5551Type;\n\n\t\t\t\t\tconst clearColor = background.getClearColor();\n\t\t\t\t\tconst a = background.getClearAlpha();\n\t\t\t\t\tconst r = clearColor.r;\n\t\t\t\t\tconst g = clearColor.g;\n\t\t\t\t\tconst b = clearColor.b;\n\n\t\t\t\t\tif ( isUnsignedType ) {\n\n\t\t\t\t\t\tuintClearColor[ 0 ] = r;\n\t\t\t\t\t\tuintClearColor[ 1 ] = g;\n\t\t\t\t\t\tuintClearColor[ 2 ] = b;\n\t\t\t\t\t\tuintClearColor[ 3 ] = a;\n\t\t\t\t\t\t_gl.clearBufferuiv( _gl.COLOR, 0, uintClearColor );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tintClearColor[ 0 ] = r;\n\t\t\t\t\t\tintClearColor[ 1 ] = g;\n\t\t\t\t\t\tintClearColor[ 2 ] = b;\n\t\t\t\t\t\tintClearColor[ 3 ] = a;\n\t\t\t\t\t\t_gl.clearBufferiv( _gl.COLOR, 0, intClearColor );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tbits |= _gl.COLOR_BUFFER_BIT;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( depth ) bits |= _gl.DEPTH_BUFFER_BIT;\n\t\t\tif ( stencil ) {\n\n\t\t\t\tbits |= _gl.STENCIL_BUFFER_BIT;\n\t\t\t\tthis.state.buffers.stencil.setMask( 0xffffffff );\n\n\t\t\t}\n\n\t\t\t_gl.clear( bits );\n\n\t\t};\n\n\t\tthis.clearColor = function () {\n\n\t\t\tthis.clear( true, false, false );\n\n\t\t};\n\n\t\tthis.clearDepth = function () {\n\n\t\t\tthis.clear( false, true, false );\n\n\t\t};\n\n\t\tthis.clearStencil = function () {\n\n\t\t\tthis.clear( false, false, true );\n\n\t\t};\n\n\t\t//\n\n\t\tthis.dispose = function () {\n\n\t\t\tcanvas.removeEventListener( 'webglcontextlost', onContextLost, false );\n\t\t\tcanvas.removeEventListener( 'webglcontextrestored', onContextRestore, false );\n\t\t\tcanvas.removeEventListener( 'webglcontextcreationerror', onContextCreationError, false );\n\n\t\t\trenderLists.dispose();\n\t\t\trenderStates.dispose();\n\t\t\tproperties.dispose();\n\t\t\tcubemaps.dispose();\n\t\t\tcubeuvmaps.dispose();\n\t\t\tobjects.dispose();\n\t\t\tbindingStates.dispose();\n\t\t\tuniformsGroups.dispose();\n\t\t\tprogramCache.dispose();\n\n\t\t\txr.dispose();\n\n\t\t\txr.removeEventListener( 'sessionstart', onXRSessionStart );\n\t\t\txr.removeEventListener( 'sessionend', onXRSessionEnd );\n\n\t\t\tanimation.stop();\n\n\t\t};\n\n\t\t// Events\n\n\t\tfunction onContextLost( event ) {\n\n\t\t\tevent.preventDefault();\n\n\t\t\tconsole.log( 'THREE.WebGLRenderer: Context Lost.' );\n\n\t\t\t_isContextLost = true;\n\n\t\t}\n\n\t\tfunction onContextRestore( /* event */ ) {\n\n\t\t\tconsole.log( 'THREE.WebGLRenderer: Context Restored.' );\n\n\t\t\t_isContextLost = false;\n\n\t\t\tconst infoAutoReset = info.autoReset;\n\t\t\tconst shadowMapEnabled = shadowMap.enabled;\n\t\t\tconst shadowMapAutoUpdate = shadowMap.autoUpdate;\n\t\t\tconst shadowMapNeedsUpdate = shadowMap.needsUpdate;\n\t\t\tconst shadowMapType = shadowMap.type;\n\n\t\t\tinitGLContext();\n\n\t\t\tinfo.autoReset = infoAutoReset;\n\t\t\tshadowMap.enabled = shadowMapEnabled;\n\t\t\tshadowMap.autoUpdate = shadowMapAutoUpdate;\n\t\t\tshadowMap.needsUpdate = shadowMapNeedsUpdate;\n\t\t\tshadowMap.type = shadowMapType;\n\n\t\t}\n\n\t\tfunction onContextCreationError( event ) {\n\n\t\t\tconsole.error( 'THREE.WebGLRenderer: A WebGL context could not be created. Reason: ', event.statusMessage );\n\n\t\t}\n\n\t\tfunction onMaterialDispose( event ) {\n\n\t\t\tconst material = event.target;\n\n\t\t\tmaterial.removeEventListener( 'dispose', onMaterialDispose );\n\n\t\t\tdeallocateMaterial( material );\n\n\t\t}\n\n\t\t// Buffer deallocation\n\n\t\tfunction deallocateMaterial( material ) {\n\n\t\t\treleaseMaterialProgramReferences( material );\n\n\t\t\tproperties.remove( material );\n\n\t\t}\n\n\n\t\tfunction releaseMaterialProgramReferences( material ) {\n\n\t\t\tconst programs = properties.get( material ).programs;\n\n\t\t\tif ( programs !== undefined ) {\n\n\t\t\t\tprograms.forEach( function ( program ) {\n\n\t\t\t\t\tprogramCache.releaseProgram( program );\n\n\t\t\t\t} );\n\n\t\t\t\tif ( material.isShaderMaterial ) {\n\n\t\t\t\t\tprogramCache.releaseShaderCache( material );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Buffer rendering\n\n\t\tthis.renderBufferDirect = function ( camera, scene, geometry, material, object, group ) {\n\n\t\t\tif ( scene === null ) scene = _emptyScene; // renderBufferDirect second parameter used to be fog (could be null)\n\n\t\t\tconst frontFaceCW = ( object.isMesh && object.matrixWorld.determinant() < 0 );\n\n\t\t\tconst program = setProgram( camera, scene, geometry, material, object );\n\n\t\t\tstate.setMaterial( material, frontFaceCW );\n\n\t\t\t//\n\n\t\t\tlet index = geometry.index;\n\t\t\tlet rangeFactor = 1;\n\n\t\t\tif ( material.wireframe === true ) {\n\n\t\t\t\tindex = geometries.getWireframeAttribute( geometry );\n\n\t\t\t\tif ( index === undefined ) return;\n\n\t\t\t\trangeFactor = 2;\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tconst drawRange = geometry.drawRange;\n\t\t\tconst position = geometry.attributes.position;\n\n\t\t\tlet drawStart = drawRange.start * rangeFactor;\n\t\t\tlet drawEnd = ( drawRange.start + drawRange.count ) * rangeFactor;\n\n\t\t\tif ( group !== null ) {\n\n\t\t\t\tdrawStart = Math.max( drawStart, group.start * rangeFactor );\n\t\t\t\tdrawEnd = Math.min( drawEnd, ( group.start + group.count ) * rangeFactor );\n\n\t\t\t}\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tdrawStart = Math.max( drawStart, 0 );\n\t\t\t\tdrawEnd = Math.min( drawEnd, index.count );\n\n\t\t\t} else if ( position !== undefined && position !== null ) {\n\n\t\t\t\tdrawStart = Math.max( drawStart, 0 );\n\t\t\t\tdrawEnd = Math.min( drawEnd, position.count );\n\n\t\t\t}\n\n\t\t\tconst drawCount = drawEnd - drawStart;\n\n\t\t\tif ( drawCount < 0 || drawCount === Infinity ) return;\n\n\t\t\t//\n\n\t\t\tbindingStates.setup( object, material, program, geometry, index );\n\n\t\t\tlet attribute;\n\t\t\tlet renderer = bufferRenderer;\n\n\t\t\tif ( index !== null ) {\n\n\t\t\t\tattribute = attributes.get( index );\n\n\t\t\t\trenderer = indexedBufferRenderer;\n\t\t\t\trenderer.setIndex( attribute );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( object.isMesh ) {\n\n\t\t\t\tif ( material.wireframe === true ) {\n\n\t\t\t\t\tstate.setLineWidth( material.wireframeLinewidth * getTargetPixelRatio() );\n\t\t\t\t\trenderer.setMode( _gl.LINES );\n\n\t\t\t\t} else {\n\n\t\t\t\t\trenderer.setMode( _gl.TRIANGLES );\n\n\t\t\t\t}\n\n\t\t\t} else if ( object.isLine ) {\n\n\t\t\t\tlet lineWidth = material.linewidth;\n\n\t\t\t\tif ( lineWidth === undefined ) lineWidth = 1; // Not using Line*Material\n\n\t\t\t\tstate.setLineWidth( lineWidth * getTargetPixelRatio() );\n\n\t\t\t\tif ( object.isLineSegments ) {\n\n\t\t\t\t\trenderer.setMode( _gl.LINES );\n\n\t\t\t\t} else if ( object.isLineLoop ) {\n\n\t\t\t\t\trenderer.setMode( _gl.LINE_LOOP );\n\n\t\t\t\t} else {\n\n\t\t\t\t\trenderer.setMode( _gl.LINE_STRIP );\n\n\t\t\t\t}\n\n\t\t\t} else if ( object.isPoints ) {\n\n\t\t\t\trenderer.setMode( _gl.POINTS );\n\n\t\t\t} else if ( object.isSprite ) {\n\n\t\t\t\trenderer.setMode( _gl.TRIANGLES );\n\n\t\t\t}\n\n\t\t\tif ( object.isBatchedMesh ) {\n\n\t\t\t\tif ( object._multiDrawInstances !== null ) {\n\n\t\t\t\t\trenderer.renderMultiDrawInstances( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount, object._multiDrawInstances );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( ! extensions.get( 'WEBGL_multi_draw' ) ) {\n\n\t\t\t\t\t\tconst starts = object._multiDrawStarts;\n\t\t\t\t\t\tconst counts = object._multiDrawCounts;\n\t\t\t\t\t\tconst drawCount = object._multiDrawCount;\n\t\t\t\t\t\tconst bytesPerElement = index ? attributes.get( index ).bytesPerElement : 1;\n\t\t\t\t\t\tconst uniforms = properties.get( material ).currentProgram.getUniforms();\n\t\t\t\t\t\tfor ( let i = 0; i < drawCount; i ++ ) {\n\n\t\t\t\t\t\t\tuniforms.setValue( _gl, '_gl_DrawID', i );\n\t\t\t\t\t\t\trenderer.render( starts[ i ] / bytesPerElement, counts[ i ] );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\trenderer.renderMultiDraw( object._multiDrawStarts, object._multiDrawCounts, object._multiDrawCount );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else if ( object.isInstancedMesh ) {\n\n\t\t\t\trenderer.renderInstances( drawStart, drawCount, object.count );\n\n\t\t\t} else if ( geometry.isInstancedBufferGeometry ) {\n\n\t\t\t\tconst maxInstanceCount = geometry._maxInstanceCount !== undefined ? geometry._maxInstanceCount : Infinity;\n\t\t\t\tconst instanceCount = Math.min( geometry.instanceCount, maxInstanceCount );\n\n\t\t\t\trenderer.renderInstances( drawStart, drawCount, instanceCount );\n\n\t\t\t} else {\n\n\t\t\t\trenderer.render( drawStart, drawCount );\n\n\t\t\t}\n\n\t\t};\n\n\t\t// Compile\n\n\t\tfunction prepareMaterial( material, scene, object ) {\n\n\t\t\tif ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {\n\n\t\t\t\tmaterial.side = BackSide;\n\t\t\t\tmaterial.needsUpdate = true;\n\t\t\t\tgetProgram( material, scene, object );\n\n\t\t\t\tmaterial.side = FrontSide;\n\t\t\t\tmaterial.needsUpdate = true;\n\t\t\t\tgetProgram( material, scene, object );\n\n\t\t\t\tmaterial.side = DoubleSide;\n\n\t\t\t} else {\n\n\t\t\t\tgetProgram( material, scene, object );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.compile = function ( scene, camera, targetScene = null ) {\n\n\t\t\tif ( targetScene === null ) targetScene = scene;\n\n\t\t\tcurrentRenderState = renderStates.get( targetScene );\n\t\t\tcurrentRenderState.init( camera );\n\n\t\t\trenderStateStack.push( currentRenderState );\n\n\t\t\t// gather lights from both the target scene and the new object that will be added to the scene.\n\n\t\t\ttargetScene.traverseVisible( function ( object ) {\n\n\t\t\t\tif ( object.isLight && object.layers.test( camera.layers ) ) {\n\n\t\t\t\t\tcurrentRenderState.pushLight( object );\n\n\t\t\t\t\tif ( object.castShadow ) {\n\n\t\t\t\t\t\tcurrentRenderState.pushShadow( object );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\tif ( scene !== targetScene ) {\n\n\t\t\t\tscene.traverseVisible( function ( object ) {\n\n\t\t\t\t\tif ( object.isLight && object.layers.test( camera.layers ) ) {\n\n\t\t\t\t\t\tcurrentRenderState.pushLight( object );\n\n\t\t\t\t\t\tif ( object.castShadow ) {\n\n\t\t\t\t\t\t\tcurrentRenderState.pushShadow( object );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t\tcurrentRenderState.setupLights();\n\n\t\t\t// Only initialize materials in the new scene, not the targetScene.\n\n\t\t\tconst materials = new Set();\n\n\t\t\tscene.traverse( function ( object ) {\n\n\t\t\t\tconst material = object.material;\n\n\t\t\t\tif ( material ) {\n\n\t\t\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\t\t\tfor ( let i = 0; i < material.length; i ++ ) {\n\n\t\t\t\t\t\t\tconst material2 = material[ i ];\n\n\t\t\t\t\t\t\tprepareMaterial( material2, targetScene, object );\n\t\t\t\t\t\t\tmaterials.add( material2 );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tprepareMaterial( material, targetScene, object );\n\t\t\t\t\t\tmaterials.add( material );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t\trenderStateStack.pop();\n\t\t\tcurrentRenderState = null;\n\n\t\t\treturn materials;\n\n\t\t};\n\n\t\t// compileAsync\n\n\t\tthis.compileAsync = function ( scene, camera, targetScene = null ) {\n\n\t\t\tconst materials = this.compile( scene, camera, targetScene );\n\n\t\t\t// Wait for all the materials in the new object to indicate that they're\n\t\t\t// ready to be used before resolving the promise.\n\n\t\t\treturn new Promise( ( resolve ) => {\n\n\t\t\t\tfunction checkMaterialsReady() {\n\n\t\t\t\t\tmaterials.forEach( function ( material ) {\n\n\t\t\t\t\t\tconst materialProperties = properties.get( material );\n\t\t\t\t\t\tconst program = materialProperties.currentProgram;\n\n\t\t\t\t\t\tif ( program.isReady() ) {\n\n\t\t\t\t\t\t\t// remove any programs that report they're ready to use from the list\n\t\t\t\t\t\t\tmaterials.delete( material );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} );\n\n\t\t\t\t\t// once the list of compiling materials is empty, call the callback\n\n\t\t\t\t\tif ( materials.size === 0 ) {\n\n\t\t\t\t\t\tresolve( scene );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// if some materials are still not ready, wait a bit and check again\n\n\t\t\t\t\tsetTimeout( checkMaterialsReady, 10 );\n\n\t\t\t\t}\n\n\t\t\t\tif ( extensions.get( 'KHR_parallel_shader_compile' ) !== null ) {\n\n\t\t\t\t\t// If we can check the compilation status of the materials without\n\t\t\t\t\t// blocking then do so right away.\n\n\t\t\t\t\tcheckMaterialsReady();\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// Otherwise start by waiting a bit to give the materials we just\n\t\t\t\t\t// initialized a chance to finish.\n\n\t\t\t\t\tsetTimeout( checkMaterialsReady, 10 );\n\n\t\t\t\t}\n\n\t\t\t} );\n\n\t\t};\n\n\t\t// Animation Loop\n\n\t\tlet onAnimationFrameCallback = null;\n\n\t\tfunction onAnimationFrame( time ) {\n\n\t\t\tif ( onAnimationFrameCallback ) onAnimationFrameCallback( time );\n\n\t\t}\n\n\t\tfunction onXRSessionStart() {\n\n\t\t\tanimation.stop();\n\n\t\t}\n\n\t\tfunction onXRSessionEnd() {\n\n\t\t\tanimation.start();\n\n\t\t}\n\n\t\tconst animation = new WebGLAnimation();\n\t\tanimation.setAnimationLoop( onAnimationFrame );\n\n\t\tif ( typeof self !== 'undefined' ) animation.setContext( self );\n\n\t\tthis.setAnimationLoop = function ( callback ) {\n\n\t\t\tonAnimationFrameCallback = callback;\n\t\t\txr.setAnimationLoop( callback );\n\n\t\t\t( callback === null ) ? animation.stop() : animation.start();\n\n\t\t};\n\n\t\txr.addEventListener( 'sessionstart', onXRSessionStart );\n\t\txr.addEventListener( 'sessionend', onXRSessionEnd );\n\n\t\t// Rendering\n\n\t\tthis.render = function ( scene, camera ) {\n\n\t\t\tif ( camera !== undefined && camera.isCamera !== true ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLRenderer.render: camera is not an instance of THREE.Camera.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( _isContextLost === true ) return;\n\n\t\t\t// update scene graph\n\n\t\t\tif ( scene.matrixWorldAutoUpdate === true ) scene.updateMatrixWorld();\n\n\t\t\t// update camera matrices and frustum\n\n\t\t\tif ( camera.parent === null && camera.matrixWorldAutoUpdate === true ) camera.updateMatrixWorld();\n\n\t\t\tif ( xr.enabled === true && xr.isPresenting === true ) {\n\n\t\t\t\tif ( xr.cameraAutoUpdate === true ) xr.updateCamera( camera );\n\n\t\t\t\tcamera = xr.getCamera(); // use XR camera for rendering\n\n\t\t\t}\n\n\t\t\t//\n\t\t\tif ( scene.isScene === true ) scene.onBeforeRender( _this, scene, camera, _currentRenderTarget );\n\n\t\t\tcurrentRenderState = renderStates.get( scene, renderStateStack.length );\n\t\t\tcurrentRenderState.init( camera );\n\n\t\t\trenderStateStack.push( currentRenderState );\n\n\t\t\t_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );\n\t\t\t_frustum.setFromProjectionMatrix( _projScreenMatrix );\n\n\t\t\t_localClippingEnabled = this.localClippingEnabled;\n\t\t\t_clippingEnabled = clipping.init( this.clippingPlanes, _localClippingEnabled );\n\n\t\t\tcurrentRenderList = renderLists.get( scene, renderListStack.length );\n\t\t\tcurrentRenderList.init();\n\n\t\t\trenderListStack.push( currentRenderList );\n\n\t\t\tif ( xr.enabled === true && xr.isPresenting === true ) {\n\n\t\t\t\tconst depthSensingMesh = _this.xr.getDepthSensingMesh();\n\n\t\t\t\tif ( depthSensingMesh !== null ) {\n\n\t\t\t\t\tprojectObject( depthSensingMesh, camera, - Infinity, _this.sortObjects );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tprojectObject( scene, camera, 0, _this.sortObjects );\n\n\t\t\tcurrentRenderList.finish();\n\n\t\t\tif ( _this.sortObjects === true ) {\n\n\t\t\t\tcurrentRenderList.sort( _opaqueSort, _transparentSort );\n\n\t\t\t}\n\n\t\t\t_renderBackground = xr.enabled === false || xr.isPresenting === false || xr.hasDepthSensing() === false;\n\t\t\tif ( _renderBackground ) {\n\n\t\t\t\tbackground.addToRenderList( currentRenderList, scene );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tthis.info.render.frame ++;\n\n\t\t\tif ( _clippingEnabled === true ) clipping.beginShadows();\n\n\t\t\tconst shadowsArray = currentRenderState.state.shadowsArray;\n\n\t\t\tshadowMap.render( shadowsArray, scene, camera );\n\n\t\t\tif ( _clippingEnabled === true ) clipping.endShadows();\n\n\t\t\t//\n\n\t\t\tif ( this.info.autoReset === true ) this.info.reset();\n\n\t\t\t// render scene\n\n\t\t\tconst opaqueObjects = currentRenderList.opaque;\n\t\t\tconst transmissiveObjects = currentRenderList.transmissive;\n\n\t\t\tcurrentRenderState.setupLights();\n\n\t\t\tif ( camera.isArrayCamera ) {\n\n\t\t\t\tconst cameras = camera.cameras;\n\n\t\t\t\tif ( transmissiveObjects.length > 0 ) {\n\n\t\t\t\t\tfor ( let i = 0, l = cameras.length; i < l; i ++ ) {\n\n\t\t\t\t\t\tconst camera2 = cameras[ i ];\n\n\t\t\t\t\t\trenderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( _renderBackground ) background.render( scene );\n\n\t\t\t\tfor ( let i = 0, l = cameras.length; i < l; i ++ ) {\n\n\t\t\t\t\tconst camera2 = cameras[ i ];\n\n\t\t\t\t\trenderScene( currentRenderList, scene, camera2, camera2.viewport );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tif ( transmissiveObjects.length > 0 ) renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera );\n\n\t\t\t\tif ( _renderBackground ) background.render( scene );\n\n\t\t\t\trenderScene( currentRenderList, scene, camera );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( _currentRenderTarget !== null ) {\n\n\t\t\t\t// resolve multisample renderbuffers to a single-sample texture if necessary\n\n\t\t\t\ttextures.updateMultisampleRenderTarget( _currentRenderTarget );\n\n\t\t\t\t// Generate mipmap if we're using any kind of mipmap filtering\n\n\t\t\t\ttextures.updateRenderTargetMipmap( _currentRenderTarget );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( scene.isScene === true ) scene.onAfterRender( _this, scene, camera );\n\n\t\t\t// _gl.finish();\n\n\t\t\tbindingStates.resetDefaultState();\n\t\t\t_currentMaterialId = - 1;\n\t\t\t_currentCamera = null;\n\n\t\t\trenderStateStack.pop();\n\n\t\t\tif ( renderStateStack.length > 0 ) {\n\n\t\t\t\tcurrentRenderState = renderStateStack[ renderStateStack.length - 1 ];\n\n\t\t\t\tif ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, currentRenderState.state.camera );\n\n\t\t\t} else {\n\n\t\t\t\tcurrentRenderState = null;\n\n\t\t\t}\n\n\t\t\trenderListStack.pop();\n\n\t\t\tif ( renderListStack.length > 0 ) {\n\n\t\t\t\tcurrentRenderList = renderListStack[ renderListStack.length - 1 ];\n\n\t\t\t} else {\n\n\t\t\t\tcurrentRenderList = null;\n\n\t\t\t}\n\n\t\t};\n\n\t\tfunction projectObject( object, camera, groupOrder, sortObjects ) {\n\n\t\t\tif ( object.visible === false ) return;\n\n\t\t\tconst visible = object.layers.test( camera.layers );\n\n\t\t\tif ( visible ) {\n\n\t\t\t\tif ( object.isGroup ) {\n\n\t\t\t\t\tgroupOrder = object.renderOrder;\n\n\t\t\t\t} else if ( object.isLOD ) {\n\n\t\t\t\t\tif ( object.autoUpdate === true ) object.update( camera );\n\n\t\t\t\t} else if ( object.isLight ) {\n\n\t\t\t\t\tcurrentRenderState.pushLight( object );\n\n\t\t\t\t\tif ( object.castShadow ) {\n\n\t\t\t\t\t\tcurrentRenderState.pushShadow( object );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( object.isSprite ) {\n\n\t\t\t\t\tif ( ! object.frustumCulled || _frustum.intersectsSprite( object ) ) {\n\n\t\t\t\t\t\tif ( sortObjects ) {\n\n\t\t\t\t\t\t\t_vector4.setFromMatrixPosition( object.matrixWorld )\n\t\t\t\t\t\t\t\t.applyMatrix4( _projScreenMatrix );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tconst geometry = objects.update( object );\n\t\t\t\t\t\tconst material = object.material;\n\n\t\t\t\t\t\tif ( material.visible ) {\n\n\t\t\t\t\t\t\tcurrentRenderList.push( object, geometry, material, groupOrder, _vector4.z, null );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( object.isMesh || object.isLine || object.isPoints ) {\n\n\t\t\t\t\tif ( ! object.frustumCulled || _frustum.intersectsObject( object ) ) {\n\n\t\t\t\t\t\tconst geometry = objects.update( object );\n\t\t\t\t\t\tconst material = object.material;\n\n\t\t\t\t\t\tif ( sortObjects ) {\n\n\t\t\t\t\t\t\tif ( object.boundingSphere !== undefined ) {\n\n\t\t\t\t\t\t\t\tif ( object.boundingSphere === null ) object.computeBoundingSphere();\n\t\t\t\t\t\t\t\t_vector4.copy( object.boundingSphere.center );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\t\t\t\t\t\t\t\t_vector4.copy( geometry.boundingSphere.center );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t_vector4\n\t\t\t\t\t\t\t\t.applyMatrix4( object.matrixWorld )\n\t\t\t\t\t\t\t\t.applyMatrix4( _projScreenMatrix );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tif ( Array.isArray( material ) ) {\n\n\t\t\t\t\t\t\tconst groups = geometry.groups;\n\n\t\t\t\t\t\t\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\t\t\t\t\t\tconst group = groups[ i ];\n\t\t\t\t\t\t\t\tconst groupMaterial = material[ group.materialIndex ];\n\n\t\t\t\t\t\t\t\tif ( groupMaterial && groupMaterial.visible ) {\n\n\t\t\t\t\t\t\t\t\tcurrentRenderList.push( object, geometry, groupMaterial, groupOrder, _vector4.z, group );\n\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else if ( material.visible ) {\n\n\t\t\t\t\t\t\tcurrentRenderList.push( object, geometry, material, groupOrder, _vector4.z, null );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst children = object.children;\n\n\t\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\t\tprojectObject( children[ i ], camera, groupOrder, sortObjects );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction renderScene( currentRenderList, scene, camera, viewport ) {\n\n\t\t\tconst opaqueObjects = currentRenderList.opaque;\n\t\t\tconst transmissiveObjects = currentRenderList.transmissive;\n\t\t\tconst transparentObjects = currentRenderList.transparent;\n\n\t\t\tcurrentRenderState.setupLightsView( camera );\n\n\t\t\tif ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );\n\n\t\t\tif ( viewport ) state.viewport( _currentViewport.copy( viewport ) );\n\n\t\t\tif ( opaqueObjects.length > 0 ) renderObjects( opaqueObjects, scene, camera );\n\t\t\tif ( transmissiveObjects.length > 0 ) renderObjects( transmissiveObjects, scene, camera );\n\t\t\tif ( transparentObjects.length > 0 ) renderObjects( transparentObjects, scene, camera );\n\n\t\t\t// Ensure depth buffer writing is enabled so it can be cleared on next render\n\n\t\t\tstate.buffers.depth.setTest( true );\n\t\t\tstate.buffers.depth.setMask( true );\n\t\t\tstate.buffers.color.setMask( true );\n\n\t\t\tstate.setPolygonOffset( false );\n\n\t\t}\n\n\t\tfunction renderTransmissionPass( opaqueObjects, transmissiveObjects, scene, camera ) {\n\n\t\t\tconst overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;\n\n\t\t\tif ( overrideMaterial !== null ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tif ( currentRenderState.state.transmissionRenderTarget[ camera.id ] === undefined ) {\n\n\t\t\t\tcurrentRenderState.state.transmissionRenderTarget[ camera.id ] = new WebGLRenderTarget( 1, 1, {\n\t\t\t\t\tgenerateMipmaps: true,\n\t\t\t\t\ttype: ( extensions.has( 'EXT_color_buffer_half_float' ) || extensions.has( 'EXT_color_buffer_float' ) ) ? HalfFloatType : UnsignedByteType,\n\t\t\t\t\tminFilter: LinearMipmapLinearFilter,\n\t\t\t\t\tsamples: 4,\n\t\t\t\t\tstencilBuffer: stencil,\n\t\t\t\t\tresolveDepthBuffer: false,\n\t\t\t\t\tresolveStencilBuffer: false,\n\t\t\t\t\tcolorSpace: ColorManagement.workingColorSpace,\n\t\t\t\t} );\n\n\t\t\t\t// debug\n\n\t\t\t\t/*\n\t\t\t\tconst geometry = new PlaneGeometry();\n\t\t\t\tconst material = new MeshBasicMaterial( { map: _transmissionRenderTarget.texture } );\n\n\t\t\t\tconst mesh = new Mesh( geometry, material );\n\t\t\t\tscene.add( mesh );\n\t\t\t\t*/\n\n\t\t\t}\n\n\t\t\tconst transmissionRenderTarget = currentRenderState.state.transmissionRenderTarget[ camera.id ];\n\n\t\t\tconst activeViewport = camera.viewport || _currentViewport;\n\t\t\ttransmissionRenderTarget.setSize( activeViewport.z, activeViewport.w );\n\n\t\t\t//\n\n\t\t\tconst currentRenderTarget = _this.getRenderTarget();\n\t\t\t_this.setRenderTarget( transmissionRenderTarget );\n\n\t\t\t_this.getClearColor( _currentClearColor );\n\t\t\t_currentClearAlpha = _this.getClearAlpha();\n\t\t\tif ( _currentClearAlpha < 1 ) _this.setClearColor( 0xffffff, 0.5 );\n\n\t\t\t_this.clear();\n\n\t\t\tif ( _renderBackground ) background.render( scene );\n\n\t\t\t// Turn off the features which can affect the frag color for opaque objects pass.\n\t\t\t// Otherwise they are applied twice in opaque objects pass and transmission objects pass.\n\t\t\tconst currentToneMapping = _this.toneMapping;\n\t\t\t_this.toneMapping = NoToneMapping;\n\n\t\t\t// Remove viewport from camera to avoid nested render calls resetting viewport to it (e.g Reflector).\n\t\t\t// Transmission render pass requires viewport to match the transmissionRenderTarget.\n\t\t\tconst currentCameraViewport = camera.viewport;\n\t\t\tif ( camera.viewport !== undefined ) camera.viewport = undefined;\n\n\t\t\tcurrentRenderState.setupLightsView( camera );\n\n\t\t\tif ( _clippingEnabled === true ) clipping.setGlobalState( _this.clippingPlanes, camera );\n\n\t\t\trenderObjects( opaqueObjects, scene, camera );\n\n\t\t\ttextures.updateMultisampleRenderTarget( transmissionRenderTarget );\n\t\t\ttextures.updateRenderTargetMipmap( transmissionRenderTarget );\n\n\t\t\tif ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === false ) { // see #28131\n\n\t\t\t\tlet renderTargetNeedsUpdate = false;\n\n\t\t\t\tfor ( let i = 0, l = transmissiveObjects.length; i < l; i ++ ) {\n\n\t\t\t\t\tconst renderItem = transmissiveObjects[ i ];\n\n\t\t\t\t\tconst object = renderItem.object;\n\t\t\t\t\tconst geometry = renderItem.geometry;\n\t\t\t\t\tconst material = renderItem.material;\n\t\t\t\t\tconst group = renderItem.group;\n\n\t\t\t\t\tif ( material.side === DoubleSide && object.layers.test( camera.layers ) ) {\n\n\t\t\t\t\t\tconst currentSide = material.side;\n\n\t\t\t\t\t\tmaterial.side = BackSide;\n\t\t\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t\t\t\trenderObject( object, scene, camera, geometry, material, group );\n\n\t\t\t\t\t\tmaterial.side = currentSide;\n\t\t\t\t\t\tmaterial.needsUpdate = true;\n\n\t\t\t\t\t\trenderTargetNeedsUpdate = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( renderTargetNeedsUpdate === true ) {\n\n\t\t\t\t\ttextures.updateMultisampleRenderTarget( transmissionRenderTarget );\n\t\t\t\t\ttextures.updateRenderTargetMipmap( transmissionRenderTarget );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_this.setRenderTarget( currentRenderTarget );\n\n\t\t\t_this.setClearColor( _currentClearColor, _currentClearAlpha );\n\n\t\t\tif ( currentCameraViewport !== undefined ) camera.viewport = currentCameraViewport;\n\n\t\t\t_this.toneMapping = currentToneMapping;\n\n\t\t}\n\n\t\tfunction renderObjects( renderList, scene, camera ) {\n\n\t\t\tconst overrideMaterial = scene.isScene === true ? scene.overrideMaterial : null;\n\n\t\t\tfor ( let i = 0, l = renderList.length; i < l; i ++ ) {\n\n\t\t\t\tconst renderItem = renderList[ i ];\n\n\t\t\t\tconst object = renderItem.object;\n\t\t\t\tconst geometry = renderItem.geometry;\n\t\t\t\tconst material = overrideMaterial === null ? renderItem.material : overrideMaterial;\n\t\t\t\tconst group = renderItem.group;\n\n\t\t\t\tif ( object.layers.test( camera.layers ) ) {\n\n\t\t\t\t\trenderObject( object, scene, camera, geometry, material, group );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction renderObject( object, scene, camera, geometry, material, group ) {\n\n\t\t\tobject.onBeforeRender( _this, scene, camera, geometry, material, group );\n\n\t\t\tobject.modelViewMatrix.multiplyMatrices( camera.matrixWorldInverse, object.matrixWorld );\n\t\t\tobject.normalMatrix.getNormalMatrix( object.modelViewMatrix );\n\n\t\t\tif ( material.transparent === true && material.side === DoubleSide && material.forceSinglePass === false ) {\n\n\t\t\t\tmaterial.side = BackSide;\n\t\t\t\tmaterial.needsUpdate = true;\n\t\t\t\t_this.renderBufferDirect( camera, scene, geometry, material, object, group );\n\n\t\t\t\tmaterial.side = FrontSide;\n\t\t\t\tmaterial.needsUpdate = true;\n\t\t\t\t_this.renderBufferDirect( camera, scene, geometry, material, object, group );\n\n\t\t\t\tmaterial.side = DoubleSide;\n\n\t\t\t} else {\n\n\t\t\t\t_this.renderBufferDirect( camera, scene, geometry, material, object, group );\n\n\t\t\t}\n\n\t\t\tobject.onAfterRender( _this, scene, camera, geometry, material, group );\n\n\t\t}\n\n\t\tfunction getProgram( material, scene, object ) {\n\n\t\t\tif ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...\n\n\t\t\tconst materialProperties = properties.get( material );\n\n\t\t\tconst lights = currentRenderState.state.lights;\n\t\t\tconst shadowsArray = currentRenderState.state.shadowsArray;\n\n\t\t\tconst lightsStateVersion = lights.state.version;\n\n\t\t\tconst parameters = programCache.getParameters( material, lights.state, shadowsArray, scene, object );\n\t\t\tconst programCacheKey = programCache.getProgramCacheKey( parameters );\n\n\t\t\tlet programs = materialProperties.programs;\n\n\t\t\t// always update environment and fog - changing these trigger an getProgram call, but it's possible that the program doesn't change\n\n\t\t\tmaterialProperties.environment = material.isMeshStandardMaterial ? scene.environment : null;\n\t\t\tmaterialProperties.fog = scene.fog;\n\t\t\tmaterialProperties.envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || materialProperties.environment );\n\t\t\tmaterialProperties.envMapRotation = ( materialProperties.environment !== null && material.envMap === null ) ? scene.environmentRotation : material.envMapRotation;\n\n\t\t\tif ( programs === undefined ) {\n\n\t\t\t\t// new material\n\n\t\t\t\tmaterial.addEventListener( 'dispose', onMaterialDispose );\n\n\t\t\t\tprograms = new Map();\n\t\t\t\tmaterialProperties.programs = programs;\n\n\t\t\t}\n\n\t\t\tlet program = programs.get( programCacheKey );\n\n\t\t\tif ( program !== undefined ) {\n\n\t\t\t\t// early out if program and light state is identical\n\n\t\t\t\tif ( materialProperties.currentProgram === program && materialProperties.lightsStateVersion === lightsStateVersion ) {\n\n\t\t\t\t\tupdateCommonMaterialProperties( material, parameters );\n\n\t\t\t\t\treturn program;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tparameters.uniforms = programCache.getUniforms( material );\n\n\t\t\t\tmaterial.onBeforeCompile( parameters, _this );\n\n\t\t\t\tprogram = programCache.acquireProgram( parameters, programCacheKey );\n\t\t\t\tprograms.set( programCacheKey, program );\n\n\t\t\t\tmaterialProperties.uniforms = parameters.uniforms;\n\n\t\t\t}\n\n\t\t\tconst uniforms = materialProperties.uniforms;\n\n\t\t\tif ( ( ! material.isShaderMaterial && ! material.isRawShaderMaterial ) || material.clipping === true ) {\n\n\t\t\t\tuniforms.clippingPlanes = clipping.uniform;\n\n\t\t\t}\n\n\t\t\tupdateCommonMaterialProperties( material, parameters );\n\n\t\t\t// store the light setup it was created for\n\n\t\t\tmaterialProperties.needsLights = materialNeedsLights( material );\n\t\t\tmaterialProperties.lightsStateVersion = lightsStateVersion;\n\n\t\t\tif ( materialProperties.needsLights ) {\n\n\t\t\t\t// wire up the material to this renderer's lighting state\n\n\t\t\t\tuniforms.ambientLightColor.value = lights.state.ambient;\n\t\t\t\tuniforms.lightProbe.value = lights.state.probe;\n\t\t\t\tuniforms.directionalLights.value = lights.state.directional;\n\t\t\t\tuniforms.directionalLightShadows.value = lights.state.directionalShadow;\n\t\t\t\tuniforms.spotLights.value = lights.state.spot;\n\t\t\t\tuniforms.spotLightShadows.value = lights.state.spotShadow;\n\t\t\t\tuniforms.rectAreaLights.value = lights.state.rectArea;\n\t\t\t\tuniforms.ltc_1.value = lights.state.rectAreaLTC1;\n\t\t\t\tuniforms.ltc_2.value = lights.state.rectAreaLTC2;\n\t\t\t\tuniforms.pointLights.value = lights.state.point;\n\t\t\t\tuniforms.pointLightShadows.value = lights.state.pointShadow;\n\t\t\t\tuniforms.hemisphereLights.value = lights.state.hemi;\n\n\t\t\t\tuniforms.directionalShadowMap.value = lights.state.directionalShadowMap;\n\t\t\t\tuniforms.directionalShadowMatrix.value = lights.state.directionalShadowMatrix;\n\t\t\t\tuniforms.spotShadowMap.value = lights.state.spotShadowMap;\n\t\t\t\tuniforms.spotLightMatrix.value = lights.state.spotLightMatrix;\n\t\t\t\tuniforms.spotLightMap.value = lights.state.spotLightMap;\n\t\t\t\tuniforms.pointShadowMap.value = lights.state.pointShadowMap;\n\t\t\t\tuniforms.pointShadowMatrix.value = lights.state.pointShadowMatrix;\n\t\t\t\t// TODO (abelnation): add area lights shadow info to uniforms\n\n\t\t\t}\n\n\t\t\tmaterialProperties.currentProgram = program;\n\t\t\tmaterialProperties.uniformsList = null;\n\n\t\t\treturn program;\n\n\t\t}\n\n\t\tfunction getUniformList( materialProperties ) {\n\n\t\t\tif ( materialProperties.uniformsList === null ) {\n\n\t\t\t\tconst progUniforms = materialProperties.currentProgram.getUniforms();\n\t\t\t\tmaterialProperties.uniformsList = WebGLUniforms.seqWithValue( progUniforms.seq, materialProperties.uniforms );\n\n\t\t\t}\n\n\t\t\treturn materialProperties.uniformsList;\n\n\t\t}\n\n\t\tfunction updateCommonMaterialProperties( material, parameters ) {\n\n\t\t\tconst materialProperties = properties.get( material );\n\n\t\t\tmaterialProperties.outputColorSpace = parameters.outputColorSpace;\n\t\t\tmaterialProperties.batching = parameters.batching;\n\t\t\tmaterialProperties.batchingColor = parameters.batchingColor;\n\t\t\tmaterialProperties.instancing = parameters.instancing;\n\t\t\tmaterialProperties.instancingColor = parameters.instancingColor;\n\t\t\tmaterialProperties.instancingMorph = parameters.instancingMorph;\n\t\t\tmaterialProperties.skinning = parameters.skinning;\n\t\t\tmaterialProperties.morphTargets = parameters.morphTargets;\n\t\t\tmaterialProperties.morphNormals = parameters.morphNormals;\n\t\t\tmaterialProperties.morphColors = parameters.morphColors;\n\t\t\tmaterialProperties.morphTargetsCount = parameters.morphTargetsCount;\n\t\t\tmaterialProperties.numClippingPlanes = parameters.numClippingPlanes;\n\t\t\tmaterialProperties.numIntersection = parameters.numClipIntersection;\n\t\t\tmaterialProperties.vertexAlphas = parameters.vertexAlphas;\n\t\t\tmaterialProperties.vertexTangents = parameters.vertexTangents;\n\t\t\tmaterialProperties.toneMapping = parameters.toneMapping;\n\n\t\t}\n\n\t\tfunction setProgram( camera, scene, geometry, material, object ) {\n\n\t\t\tif ( scene.isScene !== true ) scene = _emptyScene; // scene could be a Mesh, Line, Points, ...\n\n\t\t\ttextures.resetTextureUnits();\n\n\t\t\tconst fog = scene.fog;\n\t\t\tconst environment = material.isMeshStandardMaterial ? scene.environment : null;\n\t\t\tconst colorSpace = ( _currentRenderTarget === null ) ? _this.outputColorSpace : ( _currentRenderTarget.isXRRenderTarget === true ? _currentRenderTarget.texture.colorSpace : LinearSRGBColorSpace );\n\t\t\tconst envMap = ( material.isMeshStandardMaterial ? cubeuvmaps : cubemaps ).get( material.envMap || environment );\n\t\t\tconst vertexAlphas = material.vertexColors === true && !! geometry.attributes.color && geometry.attributes.color.itemSize === 4;\n\t\t\tconst vertexTangents = !! geometry.attributes.tangent && ( !! material.normalMap || material.anisotropy > 0 );\n\t\t\tconst morphTargets = !! geometry.morphAttributes.position;\n\t\t\tconst morphNormals = !! geometry.morphAttributes.normal;\n\t\t\tconst morphColors = !! geometry.morphAttributes.color;\n\n\t\t\tlet toneMapping = NoToneMapping;\n\n\t\t\tif ( material.toneMapped ) {\n\n\t\t\t\tif ( _currentRenderTarget === null || _currentRenderTarget.isXRRenderTarget === true ) {\n\n\t\t\t\t\ttoneMapping = _this.toneMapping;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst morphAttribute = geometry.morphAttributes.position || geometry.morphAttributes.normal || geometry.morphAttributes.color;\n\t\t\tconst morphTargetsCount = ( morphAttribute !== undefined ) ? morphAttribute.length : 0;\n\n\t\t\tconst materialProperties = properties.get( material );\n\t\t\tconst lights = currentRenderState.state.lights;\n\n\t\t\tif ( _clippingEnabled === true ) {\n\n\t\t\t\tif ( _localClippingEnabled === true || camera !== _currentCamera ) {\n\n\t\t\t\t\tconst useCache =\n\t\t\t\t\t\tcamera === _currentCamera &&\n\t\t\t\t\t\tmaterial.id === _currentMaterialId;\n\n\t\t\t\t\t// we might want to call this function with some ClippingGroup\n\t\t\t\t\t// object instead of the material, once it becomes feasible\n\t\t\t\t\t// (#8465, #8379)\n\t\t\t\t\tclipping.setState( material, camera, useCache );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tlet needsProgramChange = false;\n\n\t\t\tif ( material.version === materialProperties.__version ) {\n\n\t\t\t\tif ( materialProperties.needsLights && ( materialProperties.lightsStateVersion !== lights.state.version ) ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.outputColorSpace !== colorSpace ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isBatchedMesh && materialProperties.batching === false ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( ! object.isBatchedMesh && materialProperties.batching === true ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isBatchedMesh && materialProperties.batchingColor === true && object.colorTexture === null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isBatchedMesh && materialProperties.batchingColor === false && object.colorTexture !== null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isInstancedMesh && materialProperties.instancing === false ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( ! object.isInstancedMesh && materialProperties.instancing === true ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isSkinnedMesh && materialProperties.skinning === false ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( ! object.isSkinnedMesh && materialProperties.skinning === true ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isInstancedMesh && materialProperties.instancingColor === true && object.instanceColor === null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isInstancedMesh && materialProperties.instancingColor === false && object.instanceColor !== null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isInstancedMesh && materialProperties.instancingMorph === true && object.morphTexture === null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( object.isInstancedMesh && materialProperties.instancingMorph === false && object.morphTexture !== null ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.envMap !== envMap ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( material.fog === true && materialProperties.fog !== fog ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.numClippingPlanes !== undefined &&\n\t\t\t\t\t( materialProperties.numClippingPlanes !== clipping.numPlanes ||\n\t\t\t\t\tmaterialProperties.numIntersection !== clipping.numIntersection ) ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.vertexAlphas !== vertexAlphas ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.vertexTangents !== vertexTangents ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.morphTargets !== morphTargets ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.morphNormals !== morphNormals ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.morphColors !== morphColors ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.toneMapping !== toneMapping ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t} else if ( materialProperties.morphTargetsCount !== morphTargetsCount ) {\n\n\t\t\t\t\tneedsProgramChange = true;\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tneedsProgramChange = true;\n\t\t\t\tmaterialProperties.__version = material.version;\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tlet program = materialProperties.currentProgram;\n\n\t\t\tif ( needsProgramChange === true ) {\n\n\t\t\t\tprogram = getProgram( material, scene, object );\n\n\t\t\t}\n\n\t\t\tlet refreshProgram = false;\n\t\t\tlet refreshMaterial = false;\n\t\t\tlet refreshLights = false;\n\n\t\t\tconst p_uniforms = program.getUniforms(),\n\t\t\t\tm_uniforms = materialProperties.uniforms;\n\n\t\t\tif ( state.useProgram( program.program ) ) {\n\n\t\t\t\trefreshProgram = true;\n\t\t\t\trefreshMaterial = true;\n\t\t\t\trefreshLights = true;\n\n\t\t\t}\n\n\t\t\tif ( material.id !== _currentMaterialId ) {\n\n\t\t\t\t_currentMaterialId = material.id;\n\n\t\t\t\trefreshMaterial = true;\n\n\t\t\t}\n\n\t\t\tif ( refreshProgram || _currentCamera !== camera ) {\n\n\t\t\t\t// common camera uniforms\n\n\t\t\t\tp_uniforms.setValue( _gl, 'projectionMatrix', camera.projectionMatrix );\n\t\t\t\tp_uniforms.setValue( _gl, 'viewMatrix', camera.matrixWorldInverse );\n\n\t\t\t\tconst uCamPos = p_uniforms.map.cameraPosition;\n\n\t\t\t\tif ( uCamPos !== undefined ) {\n\n\t\t\t\t\tuCamPos.setValue( _gl, _vector3.setFromMatrixPosition( camera.matrixWorld ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( capabilities.logarithmicDepthBuffer ) {\n\n\t\t\t\t\tp_uniforms.setValue( _gl, 'logDepthBufFC',\n\t\t\t\t\t\t2.0 / ( Math.log( camera.far + 1.0 ) / Math.LN2 ) );\n\n\t\t\t\t}\n\n\t\t\t\t// consider moving isOrthographic to UniformLib and WebGLMaterials, see https://github.com/mrdoob/three.js/pull/26467#issuecomment-1645185067\n\n\t\t\t\tif ( material.isMeshPhongMaterial ||\n\t\t\t\t\tmaterial.isMeshToonMaterial ||\n\t\t\t\t\tmaterial.isMeshLambertMaterial ||\n\t\t\t\t\tmaterial.isMeshBasicMaterial ||\n\t\t\t\t\tmaterial.isMeshStandardMaterial ||\n\t\t\t\t\tmaterial.isShaderMaterial ) {\n\n\t\t\t\t\tp_uniforms.setValue( _gl, 'isOrthographic', camera.isOrthographicCamera === true );\n\n\t\t\t\t}\n\n\t\t\t\tif ( _currentCamera !== camera ) {\n\n\t\t\t\t\t_currentCamera = camera;\n\n\t\t\t\t\t// lighting uniforms depend on the camera so enforce an update\n\t\t\t\t\t// now, in case this material supports lights - or later, when\n\t\t\t\t\t// the next material that does gets activated:\n\n\t\t\t\t\trefreshMaterial = true;\t\t// set to true on material change\n\t\t\t\t\trefreshLights = true;\t\t// remains set until update done\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// skinning and morph target uniforms must be set even if material didn't change\n\t\t\t// auto-setting of texture unit for bone and morph texture must go before other textures\n\t\t\t// otherwise textures used for skinning and morphing can take over texture units reserved for other material textures\n\n\t\t\tif ( object.isSkinnedMesh ) {\n\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'bindMatrix' );\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'bindMatrixInverse' );\n\n\t\t\t\tconst skeleton = object.skeleton;\n\n\t\t\t\tif ( skeleton ) {\n\n\t\t\t\t\tif ( skeleton.boneTexture === null ) skeleton.computeBoneTexture();\n\n\t\t\t\t\tp_uniforms.setValue( _gl, 'boneTexture', skeleton.boneTexture, textures );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( object.isBatchedMesh ) {\n\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'batchingTexture' );\n\t\t\t\tp_uniforms.setValue( _gl, 'batchingTexture', object._matricesTexture, textures );\n\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'batchingIdTexture' );\n\t\t\t\tp_uniforms.setValue( _gl, 'batchingIdTexture', object._indirectTexture, textures );\n\n\t\t\t\tp_uniforms.setOptional( _gl, object, 'batchingColorTexture' );\n\t\t\t\tif ( object._colorsTexture !== null ) {\n\n\t\t\t\t\tp_uniforms.setValue( _gl, 'batchingColorTexture', object._colorsTexture, textures );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst morphAttributes = geometry.morphAttributes;\n\n\t\t\tif ( morphAttributes.position !== undefined || morphAttributes.normal !== undefined || ( morphAttributes.color !== undefined ) ) {\n\n\t\t\t\tmorphtargets.update( object, geometry, program );\n\n\t\t\t}\n\n\t\t\tif ( refreshMaterial || materialProperties.receiveShadow !== object.receiveShadow ) {\n\n\t\t\t\tmaterialProperties.receiveShadow = object.receiveShadow;\n\t\t\t\tp_uniforms.setValue( _gl, 'receiveShadow', object.receiveShadow );\n\n\t\t\t}\n\n\t\t\t// https://github.com/mrdoob/three.js/pull/24467#issuecomment-1209031512\n\n\t\t\tif ( material.isMeshGouraudMaterial && material.envMap !== null ) {\n\n\t\t\t\tm_uniforms.envMap.value = envMap;\n\n\t\t\t\tm_uniforms.flipEnvMap.value = ( envMap.isCubeTexture && envMap.isRenderTargetTexture === false ) ? - 1 : 1;\n\n\t\t\t}\n\n\t\t\tif ( material.isMeshStandardMaterial && material.envMap === null && scene.environment !== null ) {\n\n\t\t\t\tm_uniforms.envMapIntensity.value = scene.environmentIntensity;\n\n\t\t\t}\n\n\t\t\tif ( refreshMaterial ) {\n\n\t\t\t\tp_uniforms.setValue( _gl, 'toneMappingExposure', _this.toneMappingExposure );\n\n\t\t\t\tif ( materialProperties.needsLights ) {\n\n\t\t\t\t\t// the current material requires lighting info\n\n\t\t\t\t\t// note: all lighting uniforms are always set correctly\n\t\t\t\t\t// they simply reference the renderer's state for their\n\t\t\t\t\t// values\n\t\t\t\t\t//\n\t\t\t\t\t// use the current material's .needsUpdate flags to set\n\t\t\t\t\t// the GL state when required\n\n\t\t\t\t\tmarkUniformsLightsNeedsUpdate( m_uniforms, refreshLights );\n\n\t\t\t\t}\n\n\t\t\t\t// refresh uniforms common to several materials\n\n\t\t\t\tif ( fog && material.fog === true ) {\n\n\t\t\t\t\tmaterials.refreshFogUniforms( m_uniforms, fog );\n\n\t\t\t\t}\n\n\t\t\t\tmaterials.refreshMaterialUniforms( m_uniforms, material, _pixelRatio, _height, currentRenderState.state.transmissionRenderTarget[ camera.id ] );\n\n\t\t\t\tWebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );\n\n\t\t\t}\n\n\t\t\tif ( material.isShaderMaterial && material.uniformsNeedUpdate === true ) {\n\n\t\t\t\tWebGLUniforms.upload( _gl, getUniformList( materialProperties ), m_uniforms, textures );\n\t\t\t\tmaterial.uniformsNeedUpdate = false;\n\n\t\t\t}\n\n\t\t\tif ( material.isSpriteMaterial ) {\n\n\t\t\t\tp_uniforms.setValue( _gl, 'center', object.center );\n\n\t\t\t}\n\n\t\t\t// common matrices\n\n\t\t\tp_uniforms.setValue( _gl, 'modelViewMatrix', object.modelViewMatrix );\n\t\t\tp_uniforms.setValue( _gl, 'normalMatrix', object.normalMatrix );\n\t\t\tp_uniforms.setValue( _gl, 'modelMatrix', object.matrixWorld );\n\n\t\t\t// UBOs\n\n\t\t\tif ( material.isShaderMaterial || material.isRawShaderMaterial ) {\n\n\t\t\t\tconst groups = material.uniformsGroups;\n\n\t\t\t\tfor ( let i = 0, l = groups.length; i < l; i ++ ) {\n\n\t\t\t\t\tconst group = groups[ i ];\n\n\t\t\t\t\tuniformsGroups.update( group, program );\n\t\t\t\t\tuniformsGroups.bind( group, program );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn program;\n\n\t\t}\n\n\t\t// If uniforms are marked as clean, they don't need to be loaded to the GPU.\n\n\t\tfunction markUniformsLightsNeedsUpdate( uniforms, value ) {\n\n\t\t\tuniforms.ambientLightColor.needsUpdate = value;\n\t\t\tuniforms.lightProbe.needsUpdate = value;\n\n\t\t\tuniforms.directionalLights.needsUpdate = value;\n\t\t\tuniforms.directionalLightShadows.needsUpdate = value;\n\t\t\tuniforms.pointLights.needsUpdate = value;\n\t\t\tuniforms.pointLightShadows.needsUpdate = value;\n\t\t\tuniforms.spotLights.needsUpdate = value;\n\t\t\tuniforms.spotLightShadows.needsUpdate = value;\n\t\t\tuniforms.rectAreaLights.needsUpdate = value;\n\t\t\tuniforms.hemisphereLights.needsUpdate = value;\n\n\t\t}\n\n\t\tfunction materialNeedsLights( material ) {\n\n\t\t\treturn material.isMeshLambertMaterial || material.isMeshToonMaterial || material.isMeshPhongMaterial ||\n\t\t\t\tmaterial.isMeshStandardMaterial || material.isShadowMaterial ||\n\t\t\t\t( material.isShaderMaterial && material.lights === true );\n\n\t\t}\n\n\t\tthis.getActiveCubeFace = function () {\n\n\t\t\treturn _currentActiveCubeFace;\n\n\t\t};\n\n\t\tthis.getActiveMipmapLevel = function () {\n\n\t\t\treturn _currentActiveMipmapLevel;\n\n\t\t};\n\n\t\tthis.getRenderTarget = function () {\n\n\t\t\treturn _currentRenderTarget;\n\n\t\t};\n\n\t\tthis.setRenderTargetTextures = function ( renderTarget, colorTexture, depthTexture ) {\n\n\t\t\tproperties.get( renderTarget.texture ).__webglTexture = colorTexture;\n\t\t\tproperties.get( renderTarget.depthTexture ).__webglTexture = depthTexture;\n\n\t\t\tconst renderTargetProperties = properties.get( renderTarget );\n\t\t\trenderTargetProperties.__hasExternalTextures = true;\n\n\t\t\trenderTargetProperties.__autoAllocateDepthBuffer = depthTexture === undefined;\n\n\t\t\tif ( ! renderTargetProperties.__autoAllocateDepthBuffer ) {\n\n\t\t\t\t// The multisample_render_to_texture extension doesn't work properly if there\n\t\t\t\t// are midframe flushes and an external depth buffer. Disable use of the extension.\n\t\t\t\tif ( extensions.has( 'WEBGL_multisampled_render_to_texture' ) === true ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.WebGLRenderer: Render-to-texture extension was disabled because an external texture was provided' );\n\t\t\t\t\trenderTargetProperties.__useRenderToTexture = false;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.setRenderTargetFramebuffer = function ( renderTarget, defaultFramebuffer ) {\n\n\t\t\tconst renderTargetProperties = properties.get( renderTarget );\n\t\t\trenderTargetProperties.__webglFramebuffer = defaultFramebuffer;\n\t\t\trenderTargetProperties.__useDefaultFramebuffer = defaultFramebuffer === undefined;\n\n\t\t};\n\n\t\tthis.setRenderTarget = function ( renderTarget, activeCubeFace = 0, activeMipmapLevel = 0 ) {\n\n\t\t\t_currentRenderTarget = renderTarget;\n\t\t\t_currentActiveCubeFace = activeCubeFace;\n\t\t\t_currentActiveMipmapLevel = activeMipmapLevel;\n\n\t\t\tlet useDefaultFramebuffer = true;\n\t\t\tlet framebuffer = null;\n\t\t\tlet isCube = false;\n\t\t\tlet isRenderTarget3D = false;\n\n\t\t\tif ( renderTarget ) {\n\n\t\t\t\tconst renderTargetProperties = properties.get( renderTarget );\n\n\t\t\t\tif ( renderTargetProperties.__useDefaultFramebuffer !== undefined ) {\n\n\t\t\t\t\t// We need to make sure to rebind the framebuffer.\n\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, null );\n\t\t\t\t\tuseDefaultFramebuffer = false;\n\n\t\t\t\t} else if ( renderTargetProperties.__webglFramebuffer === undefined ) {\n\n\t\t\t\t\ttextures.setupRenderTarget( renderTarget );\n\n\t\t\t\t} else if ( renderTargetProperties.__hasExternalTextures ) {\n\n\t\t\t\t\t// Color and depth texture must be rebound in order for the swapchain to update.\n\t\t\t\t\ttextures.rebindTextures( renderTarget, properties.get( renderTarget.texture ).__webglTexture, properties.get( renderTarget.depthTexture ).__webglTexture );\n\n\t\t\t\t}\n\n\t\t\t\tconst texture = renderTarget.texture;\n\n\t\t\t\tif ( texture.isData3DTexture || texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {\n\n\t\t\t\t\tisRenderTarget3D = true;\n\n\t\t\t\t}\n\n\t\t\t\tconst __webglFramebuffer = properties.get( renderTarget ).__webglFramebuffer;\n\n\t\t\t\tif ( renderTarget.isWebGLCubeRenderTarget ) {\n\n\t\t\t\t\tif ( Array.isArray( __webglFramebuffer[ activeCubeFace ] ) ) {\n\n\t\t\t\t\t\tframebuffer = __webglFramebuffer[ activeCubeFace ][ activeMipmapLevel ];\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tframebuffer = __webglFramebuffer[ activeCubeFace ];\n\n\t\t\t\t\t}\n\n\t\t\t\t\tisCube = true;\n\n\t\t\t\t} else if ( ( renderTarget.samples > 0 ) && textures.useMultisampledRTT( renderTarget ) === false ) {\n\n\t\t\t\t\tframebuffer = properties.get( renderTarget ).__webglMultisampledFramebuffer;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( Array.isArray( __webglFramebuffer ) ) {\n\n\t\t\t\t\t\tframebuffer = __webglFramebuffer[ activeMipmapLevel ];\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tframebuffer = __webglFramebuffer;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t_currentViewport.copy( renderTarget.viewport );\n\t\t\t\t_currentScissor.copy( renderTarget.scissor );\n\t\t\t\t_currentScissorTest = renderTarget.scissorTest;\n\n\t\t\t} else {\n\n\t\t\t\t_currentViewport.copy( _viewport ).multiplyScalar( _pixelRatio ).floor();\n\t\t\t\t_currentScissor.copy( _scissor ).multiplyScalar( _pixelRatio ).floor();\n\t\t\t\t_currentScissorTest = _scissorTest;\n\n\t\t\t}\n\n\t\t\tconst framebufferBound = state.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\tif ( framebufferBound && useDefaultFramebuffer ) {\n\n\t\t\t\tstate.drawBuffers( renderTarget, framebuffer );\n\n\t\t\t}\n\n\t\t\tstate.viewport( _currentViewport );\n\t\t\tstate.scissor( _currentScissor );\n\t\t\tstate.setScissorTest( _currentScissorTest );\n\n\t\t\tif ( isCube ) {\n\n\t\t\t\tconst textureProperties = properties.get( renderTarget.texture );\n\t\t\t\t_gl.framebufferTexture2D( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, _gl.TEXTURE_CUBE_MAP_POSITIVE_X + activeCubeFace, textureProperties.__webglTexture, activeMipmapLevel );\n\n\t\t\t} else if ( isRenderTarget3D ) {\n\n\t\t\t\tconst textureProperties = properties.get( renderTarget.texture );\n\t\t\t\tconst layer = activeCubeFace || 0;\n\t\t\t\t_gl.framebufferTextureLayer( _gl.FRAMEBUFFER, _gl.COLOR_ATTACHMENT0, textureProperties.__webglTexture, activeMipmapLevel || 0, layer );\n\n\t\t\t}\n\n\t\t\t_currentMaterialId = - 1; // reset current material to ensure correct uniform bindings\n\n\t\t};\n\n\t\tthis.readRenderTargetPixels = function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {\n\n\t\t\tif ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {\n\n\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tlet framebuffer = properties.get( renderTarget ).__webglFramebuffer;\n\n\t\t\tif ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {\n\n\t\t\t\tframebuffer = framebuffer[ activeCubeFaceIndex ];\n\n\t\t\t}\n\n\t\t\tif ( framebuffer ) {\n\n\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\t\ttry {\n\n\t\t\t\t\tconst texture = renderTarget.texture;\n\t\t\t\t\tconst textureFormat = texture.format;\n\t\t\t\t\tconst textureType = texture.type;\n\n\t\t\t\t\tif ( ! capabilities.textureFormatReadable( textureFormat ) ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in RGBA or implementation defined format.' );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! capabilities.textureTypeReadable( textureType ) ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not in UnsignedByteType or implementation defined type.' );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)\n\n\t\t\t\t\tif ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {\n\n\t\t\t\t\t\t_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), buffer );\n\n\t\t\t\t\t}\n\n\t\t\t\t} finally {\n\n\t\t\t\t\t// restore framebuffer of current render target if necessary\n\n\t\t\t\t\tconst framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;\n\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.readRenderTargetPixelsAsync = async function ( renderTarget, x, y, width, height, buffer, activeCubeFaceIndex ) {\n\n\t\t\tif ( ! ( renderTarget && renderTarget.isWebGLRenderTarget ) ) {\n\n\t\t\t\tthrow new Error( 'THREE.WebGLRenderer.readRenderTargetPixels: renderTarget is not THREE.WebGLRenderTarget.' );\n\n\t\t\t}\n\n\t\t\tlet framebuffer = properties.get( renderTarget ).__webglFramebuffer;\n\t\t\tif ( renderTarget.isWebGLCubeRenderTarget && activeCubeFaceIndex !== undefined ) {\n\n\t\t\t\tframebuffer = framebuffer[ activeCubeFaceIndex ];\n\n\t\t\t}\n\n\t\t\tif ( framebuffer ) {\n\n\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\t\ttry {\n\n\t\t\t\t\tconst texture = renderTarget.texture;\n\t\t\t\t\tconst textureFormat = texture.format;\n\t\t\t\t\tconst textureType = texture.type;\n\n\t\t\t\t\tif ( ! capabilities.textureFormatReadable( textureFormat ) ) {\n\n\t\t\t\t\t\tthrow new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in RGBA or implementation defined format.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! capabilities.textureTypeReadable( textureType ) ) {\n\n\t\t\t\t\t\tthrow new Error( 'THREE.WebGLRenderer.readRenderTargetPixelsAsync: renderTarget is not in UnsignedByteType or implementation defined type.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// the following if statement ensures valid read requests (no out-of-bounds pixels, see #8604)\n\t\t\t\t\tif ( ( x >= 0 && x <= ( renderTarget.width - width ) ) && ( y >= 0 && y <= ( renderTarget.height - height ) ) ) {\n\n\t\t\t\t\t\tconst glBuffer = _gl.createBuffer();\n\t\t\t\t\t\t_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );\n\t\t\t\t\t\t_gl.bufferData( _gl.PIXEL_PACK_BUFFER, buffer.byteLength, _gl.STREAM_READ );\n\t\t\t\t\t\t_gl.readPixels( x, y, width, height, utils.convert( textureFormat ), utils.convert( textureType ), 0 );\n\t\t\t\t\t\t_gl.flush();\n\n\t\t\t\t\t\t// check if the commands have finished every 8 ms\n\t\t\t\t\t\tconst sync = _gl.fenceSync( _gl.SYNC_GPU_COMMANDS_COMPLETE, 0 );\n\t\t\t\t\t\tawait probeAsync( _gl, sync, 4 );\n\n\t\t\t\t\t\ttry {\n\n\t\t\t\t\t\t\t_gl.bindBuffer( _gl.PIXEL_PACK_BUFFER, glBuffer );\n\t\t\t\t\t\t\t_gl.getBufferSubData( _gl.PIXEL_PACK_BUFFER, 0, buffer );\n\n\t\t\t\t\t\t} finally {\n\n\t\t\t\t\t\t\t_gl.deleteBuffer( glBuffer );\n\t\t\t\t\t\t\t_gl.deleteSync( sync );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\treturn buffer;\n\n\t\t\t\t\t}\n\n\t\t\t\t} finally {\n\n\t\t\t\t\t// restore framebuffer of current render target if necessary\n\n\t\t\t\t\tconst framebuffer = ( _currentRenderTarget !== null ) ? properties.get( _currentRenderTarget ).__webglFramebuffer : null;\n\t\t\t\t\tstate.bindFramebuffer( _gl.FRAMEBUFFER, framebuffer );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.copyFramebufferToTexture = function ( texture, position = null, level = 0 ) {\n\n\t\t\t// support previous signature with position first\n\t\t\tif ( texture.isTexture !== true ) {\n\n\t\t\t\t// @deprecated, r165\n\t\t\t\twarnOnce( 'WebGLRenderer: copyFramebufferToTexture function signature has changed.' );\n\n\t\t\t\tposition = arguments[ 0 ] || null;\n\t\t\t\ttexture = arguments[ 1 ];\n\n\t\t\t}\n\n\t\t\tconst levelScale = Math.pow( 2, - level );\n\t\t\tconst width = Math.floor( texture.image.width * levelScale );\n\t\t\tconst height = Math.floor( texture.image.height * levelScale );\n\n\t\t\tconst x = position !== null ? position.x : 0;\n\t\t\tconst y = position !== null ? position.y : 0;\n\n\t\t\ttextures.setTexture2D( texture, 0 );\n\n\t\t\t_gl.copyTexSubImage2D( _gl.TEXTURE_2D, level, 0, 0, x, y, width, height );\n\n\t\t\tstate.unbindTexture();\n\n\t\t};\n\n\t\tthis.copyTextureToTexture = function ( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {\n\n\t\t\t// support previous signature with dstPosition first\n\t\t\tif ( srcTexture.isTexture !== true ) {\n\n\t\t\t\t// @deprecated, r165\n\t\t\t\twarnOnce( 'WebGLRenderer: copyTextureToTexture function signature has changed.' );\n\n\t\t\t\tdstPosition = arguments[ 0 ] || null;\n\t\t\t\tsrcTexture = arguments[ 1 ];\n\t\t\t\tdstTexture = arguments[ 2 ];\n\t\t\t\tlevel = arguments[ 3 ] || 0;\n\t\t\t\tsrcRegion = null;\n\n\t\t\t}\n\n\t\t\tlet width, height, minX, minY;\n\t\t\tlet dstX, dstY;\n\t\t\tif ( srcRegion !== null ) {\n\n\t\t\t\twidth = srcRegion.max.x - srcRegion.min.x;\n\t\t\t\theight = srcRegion.max.y - srcRegion.min.y;\n\t\t\t\tminX = srcRegion.min.x;\n\t\t\t\tminY = srcRegion.min.y;\n\n\t\t\t} else {\n\n\t\t\t\twidth = srcTexture.image.width;\n\t\t\t\theight = srcTexture.image.height;\n\t\t\t\tminX = 0;\n\t\t\t\tminY = 0;\n\n\t\t\t}\n\n\t\t\tif ( dstPosition !== null ) {\n\n\t\t\t\tdstX = dstPosition.x;\n\t\t\t\tdstY = dstPosition.y;\n\n\t\t\t} else {\n\n\t\t\t\tdstX = 0;\n\t\t\t\tdstY = 0;\n\n\t\t\t}\n\n\t\t\tconst glFormat = utils.convert( dstTexture.format );\n\t\t\tconst glType = utils.convert( dstTexture.type );\n\n\t\t\ttextures.setTexture2D( dstTexture, 0 );\n\n\t\t\t// As another texture upload may have changed pixelStorei\n\t\t\t// parameters, make sure they are correct for the dstTexture\n\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );\n\n\t\t\tconst currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );\n\t\t\tconst currentUnpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );\n\t\t\tconst currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );\n\t\t\tconst currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );\n\t\t\tconst currentUnpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );\n\n\t\t\tconst image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, minX );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY );\n\n\t\t\tif ( srcTexture.isDataTexture ) {\n\n\t\t\t\t_gl.texSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image.data );\n\n\t\t\t} else {\n\n\t\t\t\tif ( srcTexture.isCompressedTexture ) {\n\n\t\t\t\t\t_gl.compressedTexSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, image.width, image.height, glFormat, image.data );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_gl.texSubImage2D( _gl.TEXTURE_2D, level, dstX, dstY, width, height, glFormat, glType, image );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages );\n\n\t\t\t// Generate mipmaps only when copying level 0\n\t\t\tif ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( _gl.TEXTURE_2D );\n\n\t\t\tstate.unbindTexture();\n\n\t\t};\n\n\t\tthis.copyTextureToTexture3D = function ( srcTexture, dstTexture, srcRegion = null, dstPosition = null, level = 0 ) {\n\n\t\t\t// support previous signature with source box first\n\t\t\tif ( srcTexture.isTexture !== true ) {\n\n\t\t\t\t// @deprecated, r165\n\t\t\t\twarnOnce( 'WebGLRenderer: copyTextureToTexture3D function signature has changed.' );\n\n\t\t\t\tsrcRegion = arguments[ 0 ] || null;\n\t\t\t\tdstPosition = arguments[ 1 ] || null;\n\t\t\t\tsrcTexture = arguments[ 2 ];\n\t\t\t\tdstTexture = arguments[ 3 ];\n\t\t\t\tlevel = arguments[ 4 ] || 0;\n\n\t\t\t}\n\n\t\t\tlet width, height, depth, minX, minY, minZ;\n\t\t\tlet dstX, dstY, dstZ;\n\t\t\tconst image = srcTexture.isCompressedTexture ? srcTexture.mipmaps[ level ] : srcTexture.image;\n\t\t\tif ( srcRegion !== null ) {\n\n\t\t\t\twidth = srcRegion.max.x - srcRegion.min.x;\n\t\t\t\theight = srcRegion.max.y - srcRegion.min.y;\n\t\t\t\tdepth = srcRegion.max.z - srcRegion.min.z;\n\t\t\t\tminX = srcRegion.min.x;\n\t\t\t\tminY = srcRegion.min.y;\n\t\t\t\tminZ = srcRegion.min.z;\n\n\t\t\t} else {\n\n\t\t\t\twidth = image.width;\n\t\t\t\theight = image.height;\n\t\t\t\tdepth = image.depth;\n\t\t\t\tminX = 0;\n\t\t\t\tminY = 0;\n\t\t\t\tminZ = 0;\n\n\t\t\t}\n\n\t\t\tif ( dstPosition !== null ) {\n\n\t\t\t\tdstX = dstPosition.x;\n\t\t\t\tdstY = dstPosition.y;\n\t\t\t\tdstZ = dstPosition.z;\n\n\t\t\t} else {\n\n\t\t\t\tdstX = 0;\n\t\t\t\tdstY = 0;\n\t\t\t\tdstZ = 0;\n\n\t\t\t}\n\n\t\t\tconst glFormat = utils.convert( dstTexture.format );\n\t\t\tconst glType = utils.convert( dstTexture.type );\n\t\t\tlet glTarget;\n\n\t\t\tif ( dstTexture.isData3DTexture ) {\n\n\t\t\t\ttextures.setTexture3D( dstTexture, 0 );\n\t\t\t\tglTarget = _gl.TEXTURE_3D;\n\n\t\t\t} else if ( dstTexture.isDataArrayTexture || dstTexture.isCompressedArrayTexture ) {\n\n\t\t\t\ttextures.setTexture2DArray( dstTexture, 0 );\n\t\t\t\tglTarget = _gl.TEXTURE_2D_ARRAY;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'THREE.WebGLRenderer.copyTextureToTexture3D: only supports THREE.DataTexture3D and THREE.DataTexture2DArray.' );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_FLIP_Y_WEBGL, dstTexture.flipY );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, dstTexture.premultiplyAlpha );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ALIGNMENT, dstTexture.unpackAlignment );\n\n\t\t\tconst currentUnpackRowLen = _gl.getParameter( _gl.UNPACK_ROW_LENGTH );\n\t\t\tconst currentUnpackImageHeight = _gl.getParameter( _gl.UNPACK_IMAGE_HEIGHT );\n\t\t\tconst currentUnpackSkipPixels = _gl.getParameter( _gl.UNPACK_SKIP_PIXELS );\n\t\t\tconst currentUnpackSkipRows = _gl.getParameter( _gl.UNPACK_SKIP_ROWS );\n\t\t\tconst currentUnpackSkipImages = _gl.getParameter( _gl.UNPACK_SKIP_IMAGES );\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, image.width );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, image.height );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, minX );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, minY );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, minZ );\n\n\t\t\tif ( srcTexture.isDataTexture || srcTexture.isData3DTexture ) {\n\n\t\t\t\t_gl.texSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image.data );\n\n\t\t\t} else {\n\n\t\t\t\tif ( dstTexture.isCompressedArrayTexture ) {\n\n\t\t\t\t\t_gl.compressedTexSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, image.data );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t_gl.texSubImage3D( glTarget, level, dstX, dstY, dstZ, width, height, depth, glFormat, glType, image );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t_gl.pixelStorei( _gl.UNPACK_ROW_LENGTH, currentUnpackRowLen );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_IMAGE_HEIGHT, currentUnpackImageHeight );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_PIXELS, currentUnpackSkipPixels );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_ROWS, currentUnpackSkipRows );\n\t\t\t_gl.pixelStorei( _gl.UNPACK_SKIP_IMAGES, currentUnpackSkipImages );\n\n\t\t\t// Generate mipmaps only when copying level 0\n\t\t\tif ( level === 0 && dstTexture.generateMipmaps ) _gl.generateMipmap( glTarget );\n\n\t\t\tstate.unbindTexture();\n\n\t\t};\n\n\t\tthis.initRenderTarget = function ( target ) {\n\n\t\t\tif ( properties.get( target ).__webglFramebuffer === undefined ) {\n\n\t\t\t\ttextures.setupRenderTarget( target );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.initTexture = function ( texture ) {\n\n\t\t\tif ( texture.isCubeTexture ) {\n\n\t\t\t\ttextures.setTextureCube( texture, 0 );\n\n\t\t\t} else if ( texture.isData3DTexture ) {\n\n\t\t\t\ttextures.setTexture3D( texture, 0 );\n\n\t\t\t} else if ( texture.isDataArrayTexture || texture.isCompressedArrayTexture ) {\n\n\t\t\t\ttextures.setTexture2DArray( texture, 0 );\n\n\t\t\t} else {\n\n\t\t\t\ttextures.setTexture2D( texture, 0 );\n\n\t\t\t}\n\n\t\t\tstate.unbindTexture();\n\n\t\t};\n\n\t\tthis.resetState = function () {\n\n\t\t\t_currentActiveCubeFace = 0;\n\t\t\t_currentActiveMipmapLevel = 0;\n\t\t\t_currentRenderTarget = null;\n\n\t\t\tstate.reset();\n\t\t\tbindingStates.reset();\n\n\t\t};\n\n\t\tif ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {\n\n\t\t\t__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );\n\n\t\t}\n\n\t}\n\n\tget coordinateSystem() {\n\n\t\treturn WebGLCoordinateSystem;\n\n\t}\n\n\tget outputColorSpace() {\n\n\t\treturn this._outputColorSpace;\n\n\t}\n\n\tset outputColorSpace( colorSpace ) {\n\n\t\tthis._outputColorSpace = colorSpace;\n\n\t\tconst gl = this.getContext();\n\t\tgl.drawingBufferColorSpace = colorSpace === DisplayP3ColorSpace ? 'display-p3' : 'srgb';\n\t\tgl.unpackColorSpace = ColorManagement.workingColorSpace === LinearDisplayP3ColorSpace ? 'display-p3' : 'srgb';\n\n\t}\n\n}\n\nclass FogExp2 {\n\n\tconstructor( color, density = 0.00025 ) {\n\n\t\tthis.isFogExp2 = true;\n\n\t\tthis.name = '';\n\n\t\tthis.color = new Color( color );\n\t\tthis.density = density;\n\n\t}\n\n\tclone() {\n\n\t\treturn new FogExp2( this.color, this.density );\n\n\t}\n\n\ttoJSON( /* meta */ ) {\n\n\t\treturn {\n\t\t\ttype: 'FogExp2',\n\t\t\tname: this.name,\n\t\t\tcolor: this.color.getHex(),\n\t\t\tdensity: this.density\n\t\t};\n\n\t}\n\n}\n\nclass Fog {\n\n\tconstructor( color, near = 1, far = 1000 ) {\n\n\t\tthis.isFog = true;\n\n\t\tthis.name = '';\n\n\t\tthis.color = new Color( color );\n\n\t\tthis.near = near;\n\t\tthis.far = far;\n\n\t}\n\n\tclone() {\n\n\t\treturn new Fog( this.color, this.near, this.far );\n\n\t}\n\n\ttoJSON( /* meta */ ) {\n\n\t\treturn {\n\t\t\ttype: 'Fog',\n\t\t\tname: this.name,\n\t\t\tcolor: this.color.getHex(),\n\t\t\tnear: this.near,\n\t\t\tfar: this.far\n\t\t};\n\n\t}\n\n}\n\nclass Scene extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isScene = true;\n\n\t\tthis.type = 'Scene';\n\n\t\tthis.background = null;\n\t\tthis.environment = null;\n\t\tthis.fog = null;\n\n\t\tthis.backgroundBlurriness = 0;\n\t\tthis.backgroundIntensity = 1;\n\t\tthis.backgroundRotation = new Euler();\n\n\t\tthis.environmentIntensity = 1;\n\t\tthis.environmentRotation = new Euler();\n\n\t\tthis.overrideMaterial = null;\n\n\t\tif ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {\n\n\t\t\t__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'observe', { detail: this } ) );\n\n\t\t}\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tif ( source.background !== null ) this.background = source.background.clone();\n\t\tif ( source.environment !== null ) this.environment = source.environment.clone();\n\t\tif ( source.fog !== null ) this.fog = source.fog.clone();\n\n\t\tthis.backgroundBlurriness = source.backgroundBlurriness;\n\t\tthis.backgroundIntensity = source.backgroundIntensity;\n\t\tthis.backgroundRotation.copy( source.backgroundRotation );\n\n\t\tthis.environmentIntensity = source.environmentIntensity;\n\t\tthis.environmentRotation.copy( source.environmentRotation );\n\n\t\tif ( source.overrideMaterial !== null ) this.overrideMaterial = source.overrideMaterial.clone();\n\n\t\tthis.matrixAutoUpdate = source.matrixAutoUpdate;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tif ( this.fog !== null ) data.object.fog = this.fog.toJSON();\n\n\t\tif ( this.backgroundBlurriness > 0 ) data.object.backgroundBlurriness = this.backgroundBlurriness;\n\t\tif ( this.backgroundIntensity !== 1 ) data.object.backgroundIntensity = this.backgroundIntensity;\n\t\tdata.object.backgroundRotation = this.backgroundRotation.toArray();\n\n\t\tif ( this.environmentIntensity !== 1 ) data.object.environmentIntensity = this.environmentIntensity;\n\t\tdata.object.environmentRotation = this.environmentRotation.toArray();\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass InterleavedBuffer {\n\n\tconstructor( array, stride ) {\n\n\t\tthis.isInterleavedBuffer = true;\n\n\t\tthis.array = array;\n\t\tthis.stride = stride;\n\t\tthis.count = array !== undefined ? array.length / stride : 0;\n\n\t\tthis.usage = StaticDrawUsage;\n\t\tthis._updateRange = { offset: 0, count: - 1 };\n\t\tthis.updateRanges = [];\n\n\t\tthis.version = 0;\n\n\t\tthis.uuid = generateUUID();\n\n\t}\n\n\tonUploadCallback() {}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t}\n\n\tget updateRange() {\n\n\t\twarnOnce( 'THREE.InterleavedBuffer: updateRange() is deprecated and will be removed in r169. Use addUpdateRange() instead.' ); // @deprecated, r159\n\t\treturn this._updateRange;\n\n\t}\n\n\tsetUsage( value ) {\n\n\t\tthis.usage = value;\n\n\t\treturn this;\n\n\t}\n\n\taddUpdateRange( start, count ) {\n\n\t\tthis.updateRanges.push( { start, count } );\n\n\t}\n\n\tclearUpdateRanges() {\n\n\t\tthis.updateRanges.length = 0;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.array = new source.array.constructor( source.array );\n\t\tthis.count = source.count;\n\t\tthis.stride = source.stride;\n\t\tthis.usage = source.usage;\n\n\t\treturn this;\n\n\t}\n\n\tcopyAt( index1, attribute, index2 ) {\n\n\t\tindex1 *= this.stride;\n\t\tindex2 *= attribute.stride;\n\n\t\tfor ( let i = 0, l = this.stride; i < l; i ++ ) {\n\n\t\t\tthis.array[ index1 + i ] = attribute.array[ index2 + i ];\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tset( value, offset = 0 ) {\n\n\t\tthis.array.set( value, offset );\n\n\t\treturn this;\n\n\t}\n\n\tclone( data ) {\n\n\t\tif ( data.arrayBuffers === undefined ) {\n\n\t\t\tdata.arrayBuffers = {};\n\n\t\t}\n\n\t\tif ( this.array.buffer._uuid === undefined ) {\n\n\t\t\tthis.array.buffer._uuid = generateUUID();\n\n\t\t}\n\n\t\tif ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {\n\n\t\t\tdata.arrayBuffers[ this.array.buffer._uuid ] = this.array.slice( 0 ).buffer;\n\n\t\t}\n\n\t\tconst array = new this.array.constructor( data.arrayBuffers[ this.array.buffer._uuid ] );\n\n\t\tconst ib = new this.constructor( array, this.stride );\n\t\tib.setUsage( this.usage );\n\n\t\treturn ib;\n\n\t}\n\n\tonUpload( callback ) {\n\n\t\tthis.onUploadCallback = callback;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( data ) {\n\n\t\tif ( data.arrayBuffers === undefined ) {\n\n\t\t\tdata.arrayBuffers = {};\n\n\t\t}\n\n\t\t// generate UUID for array buffer if necessary\n\n\t\tif ( this.array.buffer._uuid === undefined ) {\n\n\t\t\tthis.array.buffer._uuid = generateUUID();\n\n\t\t}\n\n\t\tif ( data.arrayBuffers[ this.array.buffer._uuid ] === undefined ) {\n\n\t\t\tdata.arrayBuffers[ this.array.buffer._uuid ] = Array.from( new Uint32Array( this.array.buffer ) );\n\n\t\t}\n\n\t\t//\n\n\t\treturn {\n\t\t\tuuid: this.uuid,\n\t\t\tbuffer: this.array.buffer._uuid,\n\t\t\ttype: this.array.constructor.name,\n\t\t\tstride: this.stride\n\t\t};\n\n\t}\n\n}\n\nconst _vector$6 = /*@__PURE__*/ new Vector3();\n\nclass InterleavedBufferAttribute {\n\n\tconstructor( interleavedBuffer, itemSize, offset, normalized = false ) {\n\n\t\tthis.isInterleavedBufferAttribute = true;\n\n\t\tthis.name = '';\n\n\t\tthis.data = interleavedBuffer;\n\t\tthis.itemSize = itemSize;\n\t\tthis.offset = offset;\n\n\t\tthis.normalized = normalized;\n\n\t}\n\n\tget count() {\n\n\t\treturn this.data.count;\n\n\t}\n\n\tget array() {\n\n\t\treturn this.data.array;\n\n\t}\n\n\tset needsUpdate( value ) {\n\n\t\tthis.data.needsUpdate = value;\n\n\t}\n\n\tapplyMatrix4( m ) {\n\n\t\tfor ( let i = 0, l = this.data.count; i < l; i ++ ) {\n\n\t\t\t_vector$6.fromBufferAttribute( this, i );\n\n\t\t\t_vector$6.applyMatrix4( m );\n\n\t\t\tthis.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tapplyNormalMatrix( m ) {\n\n\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t_vector$6.fromBufferAttribute( this, i );\n\n\t\t\t_vector$6.applyNormalMatrix( m );\n\n\t\t\tthis.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttransformDirection( m ) {\n\n\t\tfor ( let i = 0, l = this.count; i < l; i ++ ) {\n\n\t\t\t_vector$6.fromBufferAttribute( this, i );\n\n\t\t\t_vector$6.transformDirection( m );\n\n\t\t\tthis.setXYZ( i, _vector$6.x, _vector$6.y, _vector$6.z );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetComponent( index, component ) {\n\n\t\tlet value = this.array[ index * this.data.stride + this.offset + component ];\n\n\t\tif ( this.normalized ) value = denormalize( value, this.array );\n\n\t\treturn value;\n\n\t}\n\n\tsetComponent( index, component, value ) {\n\n\t\tif ( this.normalized ) value = normalize( value, this.array );\n\n\t\tthis.data.array[ index * this.data.stride + this.offset + component ] = value;\n\n\t\treturn this;\n\n\t}\n\n\tsetX( index, x ) {\n\n\t\tif ( this.normalized ) x = normalize( x, this.array );\n\n\t\tthis.data.array[ index * this.data.stride + this.offset ] = x;\n\n\t\treturn this;\n\n\t}\n\n\tsetY( index, y ) {\n\n\t\tif ( this.normalized ) y = normalize( y, this.array );\n\n\t\tthis.data.array[ index * this.data.stride + this.offset + 1 ] = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetZ( index, z ) {\n\n\t\tif ( this.normalized ) z = normalize( z, this.array );\n\n\t\tthis.data.array[ index * this.data.stride + this.offset + 2 ] = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetW( index, w ) {\n\n\t\tif ( this.normalized ) w = normalize( w, this.array );\n\n\t\tthis.data.array[ index * this.data.stride + this.offset + 3 ] = w;\n\n\t\treturn this;\n\n\t}\n\n\tgetX( index ) {\n\n\t\tlet x = this.data.array[ index * this.data.stride + this.offset ];\n\n\t\tif ( this.normalized ) x = denormalize( x, this.array );\n\n\t\treturn x;\n\n\t}\n\n\tgetY( index ) {\n\n\t\tlet y = this.data.array[ index * this.data.stride + this.offset + 1 ];\n\n\t\tif ( this.normalized ) y = denormalize( y, this.array );\n\n\t\treturn y;\n\n\t}\n\n\tgetZ( index ) {\n\n\t\tlet z = this.data.array[ index * this.data.stride + this.offset + 2 ];\n\n\t\tif ( this.normalized ) z = denormalize( z, this.array );\n\n\t\treturn z;\n\n\t}\n\n\tgetW( index ) {\n\n\t\tlet w = this.data.array[ index * this.data.stride + this.offset + 3 ];\n\n\t\tif ( this.normalized ) w = denormalize( w, this.array );\n\n\t\treturn w;\n\n\t}\n\n\tsetXY( index, x, y ) {\n\n\t\tindex = index * this.data.stride + this.offset;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\n\t\t}\n\n\t\tthis.data.array[ index + 0 ] = x;\n\t\tthis.data.array[ index + 1 ] = y;\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZ( index, x, y, z ) {\n\n\t\tindex = index * this.data.stride + this.offset;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\n\t\t}\n\n\t\tthis.data.array[ index + 0 ] = x;\n\t\tthis.data.array[ index + 1 ] = y;\n\t\tthis.data.array[ index + 2 ] = z;\n\n\t\treturn this;\n\n\t}\n\n\tsetXYZW( index, x, y, z, w ) {\n\n\t\tindex = index * this.data.stride + this.offset;\n\n\t\tif ( this.normalized ) {\n\n\t\t\tx = normalize( x, this.array );\n\t\t\ty = normalize( y, this.array );\n\t\t\tz = normalize( z, this.array );\n\t\t\tw = normalize( w, this.array );\n\n\t\t}\n\n\t\tthis.data.array[ index + 0 ] = x;\n\t\tthis.data.array[ index + 1 ] = y;\n\t\tthis.data.array[ index + 2 ] = z;\n\t\tthis.data.array[ index + 3 ] = w;\n\n\t\treturn this;\n\n\t}\n\n\tclone( data ) {\n\n\t\tif ( data === undefined ) {\n\n\t\t\tconsole.log( 'THREE.InterleavedBufferAttribute.clone(): Cloning an interleaved buffer attribute will de-interleave buffer data.' );\n\n\t\t\tconst array = [];\n\n\t\t\tfor ( let i = 0; i < this.count; i ++ ) {\n\n\t\t\t\tconst index = i * this.data.stride + this.offset;\n\n\t\t\t\tfor ( let j = 0; j < this.itemSize; j ++ ) {\n\n\t\t\t\t\tarray.push( this.data.array[ index + j ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn new BufferAttribute( new this.array.constructor( array ), this.itemSize, this.normalized );\n\n\t\t} else {\n\n\t\t\tif ( data.interleavedBuffers === undefined ) {\n\n\t\t\t\tdata.interleavedBuffers = {};\n\n\t\t\t}\n\n\t\t\tif ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {\n\n\t\t\t\tdata.interleavedBuffers[ this.data.uuid ] = this.data.clone( data );\n\n\t\t\t}\n\n\t\t\treturn new InterleavedBufferAttribute( data.interleavedBuffers[ this.data.uuid ], this.itemSize, this.offset, this.normalized );\n\n\t\t}\n\n\t}\n\n\ttoJSON( data ) {\n\n\t\tif ( data === undefined ) {\n\n\t\t\tconsole.log( 'THREE.InterleavedBufferAttribute.toJSON(): Serializing an interleaved buffer attribute will de-interleave buffer data.' );\n\n\t\t\tconst array = [];\n\n\t\t\tfor ( let i = 0; i < this.count; i ++ ) {\n\n\t\t\t\tconst index = i * this.data.stride + this.offset;\n\n\t\t\t\tfor ( let j = 0; j < this.itemSize; j ++ ) {\n\n\t\t\t\t\tarray.push( this.data.array[ index + j ] );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// de-interleave data and save it as an ordinary buffer attribute for now\n\n\t\t\treturn {\n\t\t\t\titemSize: this.itemSize,\n\t\t\t\ttype: this.array.constructor.name,\n\t\t\t\tarray: array,\n\t\t\t\tnormalized: this.normalized\n\t\t\t};\n\n\t\t} else {\n\n\t\t\t// save as true interleaved attribute\n\n\t\t\tif ( data.interleavedBuffers === undefined ) {\n\n\t\t\t\tdata.interleavedBuffers = {};\n\n\t\t\t}\n\n\t\t\tif ( data.interleavedBuffers[ this.data.uuid ] === undefined ) {\n\n\t\t\t\tdata.interleavedBuffers[ this.data.uuid ] = this.data.toJSON( data );\n\n\t\t\t}\n\n\t\t\treturn {\n\t\t\t\tisInterleavedBufferAttribute: true,\n\t\t\t\titemSize: this.itemSize,\n\t\t\t\tdata: this.data.uuid,\n\t\t\t\toffset: this.offset,\n\t\t\t\tnormalized: this.normalized\n\t\t\t};\n\n\t\t}\n\n\t}\n\n}\n\nclass SpriteMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isSpriteMaterial = true;\n\n\t\tthis.type = 'SpriteMaterial';\n\n\t\tthis.color = new Color( 0xffffff );\n\n\t\tthis.map = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.rotation = 0;\n\n\t\tthis.sizeAttenuation = true;\n\n\t\tthis.transparent = true;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.rotation = source.rotation;\n\n\t\tthis.sizeAttenuation = source.sizeAttenuation;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nlet _geometry;\n\nconst _intersectPoint = /*@__PURE__*/ new Vector3();\nconst _worldScale = /*@__PURE__*/ new Vector3();\nconst _mvPosition = /*@__PURE__*/ new Vector3();\n\nconst _alignedPosition = /*@__PURE__*/ new Vector2();\nconst _rotatedPosition = /*@__PURE__*/ new Vector2();\nconst _viewWorldMatrix = /*@__PURE__*/ new Matrix4();\n\nconst _vA = /*@__PURE__*/ new Vector3();\nconst _vB = /*@__PURE__*/ new Vector3();\nconst _vC = /*@__PURE__*/ new Vector3();\n\nconst _uvA = /*@__PURE__*/ new Vector2();\nconst _uvB = /*@__PURE__*/ new Vector2();\nconst _uvC = /*@__PURE__*/ new Vector2();\n\nclass Sprite extends Object3D {\n\n\tconstructor( material = new SpriteMaterial() ) {\n\n\t\tsuper();\n\n\t\tthis.isSprite = true;\n\n\t\tthis.type = 'Sprite';\n\n\t\tif ( _geometry === undefined ) {\n\n\t\t\t_geometry = new BufferGeometry();\n\n\t\t\tconst float32Array = new Float32Array( [\n\t\t\t\t- 0.5, - 0.5, 0, 0, 0,\n\t\t\t\t0.5, - 0.5, 0, 1, 0,\n\t\t\t\t0.5, 0.5, 0, 1, 1,\n\t\t\t\t- 0.5, 0.5, 0, 0, 1\n\t\t\t] );\n\n\t\t\tconst interleavedBuffer = new InterleavedBuffer( float32Array, 5 );\n\n\t\t\t_geometry.setIndex( [ 0, 1, 2,\t0, 2, 3 ] );\n\t\t\t_geometry.setAttribute( 'position', new InterleavedBufferAttribute( interleavedBuffer, 3, 0, false ) );\n\t\t\t_geometry.setAttribute( 'uv', new InterleavedBufferAttribute( interleavedBuffer, 2, 3, false ) );\n\n\t\t}\n\n\t\tthis.geometry = _geometry;\n\t\tthis.material = material;\n\n\t\tthis.center = new Vector2( 0.5, 0.5 );\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tif ( raycaster.camera === null ) {\n\n\t\t\tconsole.error( 'THREE.Sprite: \"Raycaster.camera\" needs to be set in order to raycast against sprites.' );\n\n\t\t}\n\n\t\t_worldScale.setFromMatrixScale( this.matrixWorld );\n\n\t\t_viewWorldMatrix.copy( raycaster.camera.matrixWorld );\n\t\tthis.modelViewMatrix.multiplyMatrices( raycaster.camera.matrixWorldInverse, this.matrixWorld );\n\n\t\t_mvPosition.setFromMatrixPosition( this.modelViewMatrix );\n\n\t\tif ( raycaster.camera.isPerspectiveCamera && this.material.sizeAttenuation === false ) {\n\n\t\t\t_worldScale.multiplyScalar( - _mvPosition.z );\n\n\t\t}\n\n\t\tconst rotation = this.material.rotation;\n\t\tlet sin, cos;\n\n\t\tif ( rotation !== 0 ) {\n\n\t\t\tcos = Math.cos( rotation );\n\t\t\tsin = Math.sin( rotation );\n\n\t\t}\n\n\t\tconst center = this.center;\n\n\t\ttransformVertex( _vA.set( - 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );\n\t\ttransformVertex( _vB.set( 0.5, - 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );\n\t\ttransformVertex( _vC.set( 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );\n\n\t\t_uvA.set( 0, 0 );\n\t\t_uvB.set( 1, 0 );\n\t\t_uvC.set( 1, 1 );\n\n\t\t// check first triangle\n\t\tlet intersect = raycaster.ray.intersectTriangle( _vA, _vB, _vC, false, _intersectPoint );\n\n\t\tif ( intersect === null ) {\n\n\t\t\t// check second triangle\n\t\t\ttransformVertex( _vB.set( - 0.5, 0.5, 0 ), _mvPosition, center, _worldScale, sin, cos );\n\t\t\t_uvB.set( 0, 1 );\n\n\t\t\tintersect = raycaster.ray.intersectTriangle( _vA, _vC, _vB, false, _intersectPoint );\n\t\t\tif ( intersect === null ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst distance = raycaster.ray.origin.distanceTo( _intersectPoint );\n\n\t\tif ( distance < raycaster.near || distance > raycaster.far ) return;\n\n\t\tintersects.push( {\n\n\t\t\tdistance: distance,\n\t\t\tpoint: _intersectPoint.clone(),\n\t\t\tuv: Triangle.getInterpolation( _intersectPoint, _vA, _vB, _vC, _uvA, _uvB, _uvC, new Vector2() ),\n\t\t\tface: null,\n\t\t\tobject: this\n\n\t\t} );\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tif ( source.center !== undefined ) this.center.copy( source.center );\n\n\t\tthis.material = source.material;\n\n\t\treturn this;\n\n\t}\n\n}\n\nfunction transformVertex( vertexPosition, mvPosition, center, scale, sin, cos ) {\n\n\t// compute position in camera space\n\t_alignedPosition.subVectors( vertexPosition, center ).addScalar( 0.5 ).multiply( scale );\n\n\t// to check if rotation is not zero\n\tif ( sin !== undefined ) {\n\n\t\t_rotatedPosition.x = ( cos * _alignedPosition.x ) - ( sin * _alignedPosition.y );\n\t\t_rotatedPosition.y = ( sin * _alignedPosition.x ) + ( cos * _alignedPosition.y );\n\n\t} else {\n\n\t\t_rotatedPosition.copy( _alignedPosition );\n\n\t}\n\n\n\tvertexPosition.copy( mvPosition );\n\tvertexPosition.x += _rotatedPosition.x;\n\tvertexPosition.y += _rotatedPosition.y;\n\n\t// transform to world space\n\tvertexPosition.applyMatrix4( _viewWorldMatrix );\n\n}\n\nconst _v1$2 = /*@__PURE__*/ new Vector3();\nconst _v2$1 = /*@__PURE__*/ new Vector3();\n\nclass LOD extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis._currentLevel = 0;\n\n\t\tthis.type = 'LOD';\n\n\t\tObject.defineProperties( this, {\n\t\t\tlevels: {\n\t\t\t\tenumerable: true,\n\t\t\t\tvalue: []\n\t\t\t},\n\t\t\tisLOD: {\n\t\t\t\tvalue: true,\n\t\t\t}\n\t\t} );\n\n\t\tthis.autoUpdate = true;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source, false );\n\n\t\tconst levels = source.levels;\n\n\t\tfor ( let i = 0, l = levels.length; i < l; i ++ ) {\n\n\t\t\tconst level = levels[ i ];\n\n\t\t\tthis.addLevel( level.object.clone(), level.distance, level.hysteresis );\n\n\t\t}\n\n\t\tthis.autoUpdate = source.autoUpdate;\n\n\t\treturn this;\n\n\t}\n\n\taddLevel( object, distance = 0, hysteresis = 0 ) {\n\n\t\tdistance = Math.abs( distance );\n\n\t\tconst levels = this.levels;\n\n\t\tlet l;\n\n\t\tfor ( l = 0; l < levels.length; l ++ ) {\n\n\t\t\tif ( distance < levels[ l ].distance ) {\n\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tlevels.splice( l, 0, { distance: distance, hysteresis: hysteresis, object: object } );\n\n\t\tthis.add( object );\n\n\t\treturn this;\n\n\t}\n\n\tgetCurrentLevel() {\n\n\t\treturn this._currentLevel;\n\n\t}\n\n\n\n\tgetObjectForDistance( distance ) {\n\n\t\tconst levels = this.levels;\n\n\t\tif ( levels.length > 0 ) {\n\n\t\t\tlet i, l;\n\n\t\t\tfor ( i = 1, l = levels.length; i < l; i ++ ) {\n\n\t\t\t\tlet levelDistance = levels[ i ].distance;\n\n\t\t\t\tif ( levels[ i ].object.visible ) {\n\n\t\t\t\t\tlevelDistance -= levelDistance * levels[ i ].hysteresis;\n\n\t\t\t\t}\n\n\t\t\t\tif ( distance < levelDistance ) {\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn levels[ i - 1 ].object;\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst levels = this.levels;\n\n\t\tif ( levels.length > 0 ) {\n\n\t\t\t_v1$2.setFromMatrixPosition( this.matrixWorld );\n\n\t\t\tconst distance = raycaster.ray.origin.distanceTo( _v1$2 );\n\n\t\t\tthis.getObjectForDistance( distance ).raycast( raycaster, intersects );\n\n\t\t}\n\n\t}\n\n\tupdate( camera ) {\n\n\t\tconst levels = this.levels;\n\n\t\tif ( levels.length > 1 ) {\n\n\t\t\t_v1$2.setFromMatrixPosition( camera.matrixWorld );\n\t\t\t_v2$1.setFromMatrixPosition( this.matrixWorld );\n\n\t\t\tconst distance = _v1$2.distanceTo( _v2$1 ) / camera.zoom;\n\n\t\t\tlevels[ 0 ].object.visible = true;\n\n\t\t\tlet i, l;\n\n\t\t\tfor ( i = 1, l = levels.length; i < l; i ++ ) {\n\n\t\t\t\tlet levelDistance = levels[ i ].distance;\n\n\t\t\t\tif ( levels[ i ].object.visible ) {\n\n\t\t\t\t\tlevelDistance -= levelDistance * levels[ i ].hysteresis;\n\n\t\t\t\t}\n\n\t\t\t\tif ( distance >= levelDistance ) {\n\n\t\t\t\t\tlevels[ i - 1 ].object.visible = false;\n\t\t\t\t\tlevels[ i ].object.visible = true;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis._currentLevel = i - 1;\n\n\t\t\tfor ( ; i < l; i ++ ) {\n\n\t\t\t\tlevels[ i ].object.visible = false;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tif ( this.autoUpdate === false ) data.object.autoUpdate = false;\n\n\t\tdata.object.levels = [];\n\n\t\tconst levels = this.levels;\n\n\t\tfor ( let i = 0, l = levels.length; i < l; i ++ ) {\n\n\t\t\tconst level = levels[ i ];\n\n\t\t\tdata.object.levels.push( {\n\t\t\t\tobject: level.object.uuid,\n\t\t\t\tdistance: level.distance,\n\t\t\t\thysteresis: level.hysteresis\n\t\t\t} );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n}\n\nconst _basePosition = /*@__PURE__*/ new Vector3();\n\nconst _skinIndex = /*@__PURE__*/ new Vector4();\nconst _skinWeight = /*@__PURE__*/ new Vector4();\n\nconst _vector3 = /*@__PURE__*/ new Vector3();\nconst _matrix4 = /*@__PURE__*/ new Matrix4();\nconst _vertex = /*@__PURE__*/ new Vector3();\n\nconst _sphere$4 = /*@__PURE__*/ new Sphere();\nconst _inverseMatrix$2 = /*@__PURE__*/ new Matrix4();\nconst _ray$2 = /*@__PURE__*/ new Ray();\n\nclass SkinnedMesh extends Mesh {\n\n\tconstructor( geometry, material ) {\n\n\t\tsuper( geometry, material );\n\n\t\tthis.isSkinnedMesh = true;\n\n\t\tthis.type = 'SkinnedMesh';\n\n\t\tthis.bindMode = AttachedBindMode;\n\t\tthis.bindMatrix = new Matrix4();\n\t\tthis.bindMatrixInverse = new Matrix4();\n\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t}\n\n\tcomputeBoundingBox() {\n\n\t\tconst geometry = this.geometry;\n\n\t\tif ( this.boundingBox === null ) {\n\n\t\t\tthis.boundingBox = new Box3();\n\n\t\t}\n\n\t\tthis.boundingBox.makeEmpty();\n\n\t\tconst positionAttribute = geometry.getAttribute( 'position' );\n\n\t\tfor ( let i = 0; i < positionAttribute.count; i ++ ) {\n\n\t\t\tthis.getVertexPosition( i, _vertex );\n\t\t\tthis.boundingBox.expandByPoint( _vertex );\n\n\t\t}\n\n\t}\n\n\tcomputeBoundingSphere() {\n\n\t\tconst geometry = this.geometry;\n\n\t\tif ( this.boundingSphere === null ) {\n\n\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\tthis.boundingSphere.makeEmpty();\n\n\t\tconst positionAttribute = geometry.getAttribute( 'position' );\n\n\t\tfor ( let i = 0; i < positionAttribute.count; i ++ ) {\n\n\t\t\tthis.getVertexPosition( i, _vertex );\n\t\t\tthis.boundingSphere.expandByPoint( _vertex );\n\n\t\t}\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.bindMode = source.bindMode;\n\t\tthis.bindMatrix.copy( source.bindMatrix );\n\t\tthis.bindMatrixInverse.copy( source.bindMatrixInverse );\n\n\t\tthis.skeleton = source.skeleton;\n\n\t\tif ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone();\n\t\tif ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone();\n\n\t\treturn this;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst material = this.material;\n\t\tconst matrixWorld = this.matrixWorld;\n\n\t\tif ( material === undefined ) return;\n\n\t\t// test with bounding sphere in world space\n\n\t\tif ( this.boundingSphere === null ) this.computeBoundingSphere();\n\n\t\t_sphere$4.copy( this.boundingSphere );\n\t\t_sphere$4.applyMatrix4( matrixWorld );\n\n\t\tif ( raycaster.ray.intersectsSphere( _sphere$4 ) === false ) return;\n\n\t\t// convert ray to local space of skinned mesh\n\n\t\t_inverseMatrix$2.copy( matrixWorld ).invert();\n\t\t_ray$2.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$2 );\n\n\t\t// test with bounding box in local space\n\n\t\tif ( this.boundingBox !== null ) {\n\n\t\t\tif ( _ray$2.intersectsBox( this.boundingBox ) === false ) return;\n\n\t\t}\n\n\t\t// test for intersections with geometry\n\n\t\tthis._computeIntersections( raycaster, intersects, _ray$2 );\n\n\t}\n\n\tgetVertexPosition( index, target ) {\n\n\t\tsuper.getVertexPosition( index, target );\n\n\t\tthis.applyBoneTransform( index, target );\n\n\t\treturn target;\n\n\t}\n\n\tbind( skeleton, bindMatrix ) {\n\n\t\tthis.skeleton = skeleton;\n\n\t\tif ( bindMatrix === undefined ) {\n\n\t\t\tthis.updateMatrixWorld( true );\n\n\t\t\tthis.skeleton.calculateInverses();\n\n\t\t\tbindMatrix = this.matrixWorld;\n\n\t\t}\n\n\t\tthis.bindMatrix.copy( bindMatrix );\n\t\tthis.bindMatrixInverse.copy( bindMatrix ).invert();\n\n\t}\n\n\tpose() {\n\n\t\tthis.skeleton.pose();\n\n\t}\n\n\tnormalizeSkinWeights() {\n\n\t\tconst vector = new Vector4();\n\n\t\tconst skinWeight = this.geometry.attributes.skinWeight;\n\n\t\tfor ( let i = 0, l = skinWeight.count; i < l; i ++ ) {\n\n\t\t\tvector.fromBufferAttribute( skinWeight, i );\n\n\t\t\tconst scale = 1.0 / vector.manhattanLength();\n\n\t\t\tif ( scale !== Infinity ) {\n\n\t\t\t\tvector.multiplyScalar( scale );\n\n\t\t\t} else {\n\n\t\t\t\tvector.set( 1, 0, 0, 0 ); // do something reasonable\n\n\t\t\t}\n\n\t\t\tskinWeight.setXYZW( i, vector.x, vector.y, vector.z, vector.w );\n\n\t\t}\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t\tif ( this.bindMode === AttachedBindMode ) {\n\n\t\t\tthis.bindMatrixInverse.copy( this.matrixWorld ).invert();\n\n\t\t} else if ( this.bindMode === DetachedBindMode ) {\n\n\t\t\tthis.bindMatrixInverse.copy( this.bindMatrix ).invert();\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.SkinnedMesh: Unrecognized bindMode: ' + this.bindMode );\n\n\t\t}\n\n\t}\n\n\tapplyBoneTransform( index, vector ) {\n\n\t\tconst skeleton = this.skeleton;\n\t\tconst geometry = this.geometry;\n\n\t\t_skinIndex.fromBufferAttribute( geometry.attributes.skinIndex, index );\n\t\t_skinWeight.fromBufferAttribute( geometry.attributes.skinWeight, index );\n\n\t\t_basePosition.copy( vector ).applyMatrix4( this.bindMatrix );\n\n\t\tvector.set( 0, 0, 0 );\n\n\t\tfor ( let i = 0; i < 4; i ++ ) {\n\n\t\t\tconst weight = _skinWeight.getComponent( i );\n\n\t\t\tif ( weight !== 0 ) {\n\n\t\t\t\tconst boneIndex = _skinIndex.getComponent( i );\n\n\t\t\t\t_matrix4.multiplyMatrices( skeleton.bones[ boneIndex ].matrixWorld, skeleton.boneInverses[ boneIndex ] );\n\n\t\t\t\tvector.addScaledVector( _vector3.copy( _basePosition ).applyMatrix4( _matrix4 ), weight );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn vector.applyMatrix4( this.bindMatrixInverse );\n\n\t}\n\n}\n\nclass Bone extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isBone = true;\n\n\t\tthis.type = 'Bone';\n\n\t}\n\n}\n\nclass DataTexture extends Texture {\n\n\tconstructor( data = null, width = 1, height = 1, format, type, mapping, wrapS, wrapT, magFilter = NearestFilter, minFilter = NearestFilter, anisotropy, colorSpace ) {\n\n\t\tsuper( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );\n\n\t\tthis.isDataTexture = true;\n\n\t\tthis.image = { data: data, width: width, height: height };\n\n\t\tthis.generateMipmaps = false;\n\t\tthis.flipY = false;\n\t\tthis.unpackAlignment = 1;\n\n\t}\n\n}\n\nconst _offsetMatrix = /*@__PURE__*/ new Matrix4();\nconst _identityMatrix$1 = /*@__PURE__*/ new Matrix4();\n\nclass Skeleton {\n\n\tconstructor( bones = [], boneInverses = [] ) {\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.bones = bones.slice( 0 );\n\t\tthis.boneInverses = boneInverses;\n\t\tthis.boneMatrices = null;\n\n\t\tthis.boneTexture = null;\n\n\t\tthis.init();\n\n\t}\n\n\tinit() {\n\n\t\tconst bones = this.bones;\n\t\tconst boneInverses = this.boneInverses;\n\n\t\tthis.boneMatrices = new Float32Array( bones.length * 16 );\n\n\t\t// calculate inverse bone matrices if necessary\n\n\t\tif ( boneInverses.length === 0 ) {\n\n\t\t\tthis.calculateInverses();\n\n\t\t} else {\n\n\t\t\t// handle special case\n\n\t\t\tif ( bones.length !== boneInverses.length ) {\n\n\t\t\t\tconsole.warn( 'THREE.Skeleton: Number of inverse bone matrices does not match amount of bones.' );\n\n\t\t\t\tthis.boneInverses = [];\n\n\t\t\t\tfor ( let i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\t\t\tthis.boneInverses.push( new Matrix4() );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcalculateInverses() {\n\n\t\tthis.boneInverses.length = 0;\n\n\t\tfor ( let i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\tconst inverse = new Matrix4();\n\n\t\t\tif ( this.bones[ i ] ) {\n\n\t\t\t\tinverse.copy( this.bones[ i ].matrixWorld ).invert();\n\n\t\t\t}\n\n\t\t\tthis.boneInverses.push( inverse );\n\n\t\t}\n\n\t}\n\n\tpose() {\n\n\t\t// recover the bind-time world matrices\n\n\t\tfor ( let i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\tconst bone = this.bones[ i ];\n\n\t\t\tif ( bone ) {\n\n\t\t\t\tbone.matrixWorld.copy( this.boneInverses[ i ] ).invert();\n\n\t\t\t}\n\n\t\t}\n\n\t\t// compute the local matrices, positions, rotations and scales\n\n\t\tfor ( let i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\tconst bone = this.bones[ i ];\n\n\t\t\tif ( bone ) {\n\n\t\t\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\t\t\tbone.matrix.copy( bone.parent.matrixWorld ).invert();\n\t\t\t\t\tbone.matrix.multiply( bone.matrixWorld );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tbone.matrix.copy( bone.matrixWorld );\n\n\t\t\t\t}\n\n\t\t\t\tbone.matrix.decompose( bone.position, bone.quaternion, bone.scale );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tupdate() {\n\n\t\tconst bones = this.bones;\n\t\tconst boneInverses = this.boneInverses;\n\t\tconst boneMatrices = this.boneMatrices;\n\t\tconst boneTexture = this.boneTexture;\n\n\t\t// flatten bone matrices to array\n\n\t\tfor ( let i = 0, il = bones.length; i < il; i ++ ) {\n\n\t\t\t// compute the offset between the current and the original transform\n\n\t\t\tconst matrix = bones[ i ] ? bones[ i ].matrixWorld : _identityMatrix$1;\n\n\t\t\t_offsetMatrix.multiplyMatrices( matrix, boneInverses[ i ] );\n\t\t\t_offsetMatrix.toArray( boneMatrices, i * 16 );\n\n\t\t}\n\n\t\tif ( boneTexture !== null ) {\n\n\t\t\tboneTexture.needsUpdate = true;\n\n\t\t}\n\n\t}\n\n\tclone() {\n\n\t\treturn new Skeleton( this.bones, this.boneInverses );\n\n\t}\n\n\tcomputeBoneTexture() {\n\n\t\t// layout (1 matrix = 4 pixels)\n\t\t// RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)\n\t\t// with 8x8 pixel texture max 16 bones * 4 pixels = (8 * 8)\n\t\t// 16x16 pixel texture max 64 bones * 4 pixels = (16 * 16)\n\t\t// 32x32 pixel texture max 256 bones * 4 pixels = (32 * 32)\n\t\t// 64x64 pixel texture max 1024 bones * 4 pixels = (64 * 64)\n\n\t\tlet size = Math.sqrt( this.bones.length * 4 ); // 4 pixels needed for 1 matrix\n\t\tsize = Math.ceil( size / 4 ) * 4;\n\t\tsize = Math.max( size, 4 );\n\n\t\tconst boneMatrices = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel\n\t\tboneMatrices.set( this.boneMatrices ); // copy current values\n\n\t\tconst boneTexture = new DataTexture( boneMatrices, size, size, RGBAFormat, FloatType );\n\t\tboneTexture.needsUpdate = true;\n\n\t\tthis.boneMatrices = boneMatrices;\n\t\tthis.boneTexture = boneTexture;\n\n\t\treturn this;\n\n\t}\n\n\tgetBoneByName( name ) {\n\n\t\tfor ( let i = 0, il = this.bones.length; i < il; i ++ ) {\n\n\t\t\tconst bone = this.bones[ i ];\n\n\t\t\tif ( bone.name === name ) {\n\n\t\t\t\treturn bone;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn undefined;\n\n\t}\n\n\tdispose( ) {\n\n\t\tif ( this.boneTexture !== null ) {\n\n\t\t\tthis.boneTexture.dispose();\n\n\t\t\tthis.boneTexture = null;\n\n\t\t}\n\n\t}\n\n\tfromJSON( json, bones ) {\n\n\t\tthis.uuid = json.uuid;\n\n\t\tfor ( let i = 0, l = json.bones.length; i < l; i ++ ) {\n\n\t\t\tconst uuid = json.bones[ i ];\n\t\t\tlet bone = bones[ uuid ];\n\n\t\t\tif ( bone === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.Skeleton: No bone found with UUID:', uuid );\n\t\t\t\tbone = new Bone();\n\n\t\t\t}\n\n\t\t\tthis.bones.push( bone );\n\t\t\tthis.boneInverses.push( new Matrix4().fromArray( json.boneInverses[ i ] ) );\n\n\t\t}\n\n\t\tthis.init();\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'Skeleton',\n\t\t\t\tgenerator: 'Skeleton.toJSON'\n\t\t\t},\n\t\t\tbones: [],\n\t\t\tboneInverses: []\n\t\t};\n\n\t\tdata.uuid = this.uuid;\n\n\t\tconst bones = this.bones;\n\t\tconst boneInverses = this.boneInverses;\n\n\t\tfor ( let i = 0, l = bones.length; i < l; i ++ ) {\n\n\t\t\tconst bone = bones[ i ];\n\t\t\tdata.bones.push( bone.uuid );\n\n\t\t\tconst boneInverse = boneInverses[ i ];\n\t\t\tdata.boneInverses.push( boneInverse.toArray() );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass InstancedBufferAttribute extends BufferAttribute {\n\n\tconstructor( array, itemSize, normalized, meshPerAttribute = 1 ) {\n\n\t\tsuper( array, itemSize, normalized );\n\n\t\tthis.isInstancedBufferAttribute = true;\n\n\t\tthis.meshPerAttribute = meshPerAttribute;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.meshPerAttribute = source.meshPerAttribute;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.meshPerAttribute = this.meshPerAttribute;\n\n\t\tdata.isInstancedBufferAttribute = true;\n\n\t\treturn data;\n\n\t}\n\n}\n\nconst _instanceLocalMatrix = /*@__PURE__*/ new Matrix4();\nconst _instanceWorldMatrix = /*@__PURE__*/ new Matrix4();\n\nconst _instanceIntersects = [];\n\nconst _box3 = /*@__PURE__*/ new Box3();\nconst _identity = /*@__PURE__*/ new Matrix4();\nconst _mesh$1 = /*@__PURE__*/ new Mesh();\nconst _sphere$3 = /*@__PURE__*/ new Sphere();\n\nclass InstancedMesh extends Mesh {\n\n\tconstructor( geometry, material, count ) {\n\n\t\tsuper( geometry, material );\n\n\t\tthis.isInstancedMesh = true;\n\n\t\tthis.instanceMatrix = new InstancedBufferAttribute( new Float32Array( count * 16 ), 16 );\n\t\tthis.instanceColor = null;\n\t\tthis.morphTexture = null;\n\n\t\tthis.count = count;\n\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tthis.setMatrixAt( i, _identity );\n\n\t\t}\n\n\t}\n\n\tcomputeBoundingBox() {\n\n\t\tconst geometry = this.geometry;\n\t\tconst count = this.count;\n\n\t\tif ( this.boundingBox === null ) {\n\n\t\t\tthis.boundingBox = new Box3();\n\n\t\t}\n\n\t\tif ( geometry.boundingBox === null ) {\n\n\t\t\tgeometry.computeBoundingBox();\n\n\t\t}\n\n\t\tthis.boundingBox.makeEmpty();\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tthis.getMatrixAt( i, _instanceLocalMatrix );\n\n\t\t\t_box3.copy( geometry.boundingBox ).applyMatrix4( _instanceLocalMatrix );\n\n\t\t\tthis.boundingBox.union( _box3 );\n\n\t\t}\n\n\t}\n\n\tcomputeBoundingSphere() {\n\n\t\tconst geometry = this.geometry;\n\t\tconst count = this.count;\n\n\t\tif ( this.boundingSphere === null ) {\n\n\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\tif ( geometry.boundingSphere === null ) {\n\n\t\t\tgeometry.computeBoundingSphere();\n\n\t\t}\n\n\t\tthis.boundingSphere.makeEmpty();\n\n\t\tfor ( let i = 0; i < count; i ++ ) {\n\n\t\t\tthis.getMatrixAt( i, _instanceLocalMatrix );\n\n\t\t\t_sphere$3.copy( geometry.boundingSphere ).applyMatrix4( _instanceLocalMatrix );\n\n\t\t\tthis.boundingSphere.union( _sphere$3 );\n\n\t\t}\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.instanceMatrix.copy( source.instanceMatrix );\n\n\t\tif ( source.morphTexture !== null ) this.morphTexture = source.morphTexture.clone();\n\t\tif ( source.instanceColor !== null ) this.instanceColor = source.instanceColor.clone();\n\n\t\tthis.count = source.count;\n\n\t\tif ( source.boundingBox !== null ) this.boundingBox = source.boundingBox.clone();\n\t\tif ( source.boundingSphere !== null ) this.boundingSphere = source.boundingSphere.clone();\n\n\t\treturn this;\n\n\t}\n\n\tgetColorAt( index, color ) {\n\n\t\tcolor.fromArray( this.instanceColor.array, index * 3 );\n\n\t}\n\n\tgetMatrixAt( index, matrix ) {\n\n\t\tmatrix.fromArray( this.instanceMatrix.array, index * 16 );\n\n\t}\n\n\tgetMorphAt( index, object ) {\n\n\t\tconst objectInfluences = object.morphTargetInfluences;\n\n\t\tconst array = this.morphTexture.source.data.data;\n\n\t\tconst len = objectInfluences.length + 1; // All influences + the baseInfluenceSum\n\n\t\tconst dataIndex = index * len + 1; // Skip the baseInfluenceSum at the beginning\n\n\t\tfor ( let i = 0; i < objectInfluences.length; i ++ ) {\n\n\t\t\tobjectInfluences[ i ] = array[ dataIndex + i ];\n\n\t\t}\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst matrixWorld = this.matrixWorld;\n\t\tconst raycastTimes = this.count;\n\n\t\t_mesh$1.geometry = this.geometry;\n\t\t_mesh$1.material = this.material;\n\n\t\tif ( _mesh$1.material === undefined ) return;\n\n\t\t// test with bounding sphere first\n\n\t\tif ( this.boundingSphere === null ) this.computeBoundingSphere();\n\n\t\t_sphere$3.copy( this.boundingSphere );\n\t\t_sphere$3.applyMatrix4( matrixWorld );\n\n\t\tif ( raycaster.ray.intersectsSphere( _sphere$3 ) === false ) return;\n\n\t\t// now test each instance\n\n\t\tfor ( let instanceId = 0; instanceId < raycastTimes; instanceId ++ ) {\n\n\t\t\t// calculate the world matrix for each instance\n\n\t\t\tthis.getMatrixAt( instanceId, _instanceLocalMatrix );\n\n\t\t\t_instanceWorldMatrix.multiplyMatrices( matrixWorld, _instanceLocalMatrix );\n\n\t\t\t// the mesh represents this single instance\n\n\t\t\t_mesh$1.matrixWorld = _instanceWorldMatrix;\n\n\t\t\t_mesh$1.raycast( raycaster, _instanceIntersects );\n\n\t\t\t// process the result of raycast\n\n\t\t\tfor ( let i = 0, l = _instanceIntersects.length; i < l; i ++ ) {\n\n\t\t\t\tconst intersect = _instanceIntersects[ i ];\n\t\t\t\tintersect.instanceId = instanceId;\n\t\t\t\tintersect.object = this;\n\t\t\t\tintersects.push( intersect );\n\n\t\t\t}\n\n\t\t\t_instanceIntersects.length = 0;\n\n\t\t}\n\n\t}\n\n\tsetColorAt( index, color ) {\n\n\t\tif ( this.instanceColor === null ) {\n\n\t\t\tthis.instanceColor = new InstancedBufferAttribute( new Float32Array( this.instanceMatrix.count * 3 ).fill( 1 ), 3 );\n\n\t\t}\n\n\t\tcolor.toArray( this.instanceColor.array, index * 3 );\n\n\t}\n\n\tsetMatrixAt( index, matrix ) {\n\n\t\tmatrix.toArray( this.instanceMatrix.array, index * 16 );\n\n\t}\n\n\tsetMorphAt( index, object ) {\n\n\t\tconst objectInfluences = object.morphTargetInfluences;\n\n\t\tconst len = objectInfluences.length + 1; // morphBaseInfluence + all influences\n\n\t\tif ( this.morphTexture === null ) {\n\n\t\t\tthis.morphTexture = new DataTexture( new Float32Array( len * this.count ), len, this.count, RedFormat, FloatType );\n\n\t\t}\n\n\t\tconst array = this.morphTexture.source.data.data;\n\n\t\tlet morphInfluencesSum = 0;\n\n\t\tfor ( let i = 0; i < objectInfluences.length; i ++ ) {\n\n\t\t\tmorphInfluencesSum += objectInfluences[ i ];\n\n\t\t}\n\n\t\tconst morphBaseInfluence = this.geometry.morphTargetsRelative ? 1 : 1 - morphInfluencesSum;\n\n\t\tconst dataIndex = len * index;\n\n\t\tarray[ dataIndex ] = morphBaseInfluence;\n\n\t\tarray.set( objectInfluences, dataIndex + 1 );\n\n\t}\n\n\tupdateMorphTargets() {\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t\tif ( this.morphTexture !== null ) {\n\n\t\t\tthis.morphTexture.dispose();\n\t\t\tthis.morphTexture = null;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\nfunction sortOpaque( a, b ) {\n\n\treturn a.z - b.z;\n\n}\n\nfunction sortTransparent( a, b ) {\n\n\treturn b.z - a.z;\n\n}\n\nclass MultiDrawRenderList {\n\n\tconstructor() {\n\n\t\tthis.index = 0;\n\t\tthis.pool = [];\n\t\tthis.list = [];\n\n\t}\n\n\tpush( drawRange, z, index ) {\n\n\t\tconst pool = this.pool;\n\t\tconst list = this.list;\n\t\tif ( this.index >= pool.length ) {\n\n\t\t\tpool.push( {\n\n\t\t\t\tstart: - 1,\n\t\t\t\tcount: - 1,\n\t\t\t\tz: - 1,\n\t\t\t\tindex: - 1,\n\n\t\t\t} );\n\n\t\t}\n\n\t\tconst item = pool[ this.index ];\n\t\tlist.push( item );\n\t\tthis.index ++;\n\n\t\titem.start = drawRange.start;\n\t\titem.count = drawRange.count;\n\t\titem.z = z;\n\t\titem.index = index;\n\n\t}\n\n\treset() {\n\n\t\tthis.list.length = 0;\n\t\tthis.index = 0;\n\n\t}\n\n}\n\nconst _matrix$1 = /*@__PURE__*/ new Matrix4();\nconst _invMatrixWorld = /*@__PURE__*/ new Matrix4();\nconst _identityMatrix = /*@__PURE__*/ new Matrix4();\nconst _whiteColor = /*@__PURE__*/ new Color( 1, 1, 1 );\nconst _projScreenMatrix$2 = /*@__PURE__*/ new Matrix4();\nconst _frustum = /*@__PURE__*/ new Frustum();\nconst _box$1 = /*@__PURE__*/ new Box3();\nconst _sphere$2 = /*@__PURE__*/ new Sphere();\nconst _vector$5 = /*@__PURE__*/ new Vector3();\nconst _forward = /*@__PURE__*/ new Vector3();\nconst _temp = /*@__PURE__*/ new Vector3();\nconst _renderList = /*@__PURE__*/ new MultiDrawRenderList();\nconst _mesh = /*@__PURE__*/ new Mesh();\nconst _batchIntersects = [];\n\n// @TODO: SkinnedMesh support?\n// @TODO: geometry.groups support?\n// @TODO: geometry.drawRange support?\n// @TODO: geometry.morphAttributes support?\n// @TODO: Support uniform parameter per geometry\n// @TODO: Add an \"optimize\" function to pack geometry and remove data gaps\n\n// copies data from attribute \"src\" into \"target\" starting at \"targetOffset\"\nfunction copyAttributeData( src, target, targetOffset = 0 ) {\n\n\tconst itemSize = target.itemSize;\n\tif ( src.isInterleavedBufferAttribute || src.array.constructor !== target.array.constructor ) {\n\n\t\t// use the component getters and setters if the array data cannot\n\t\t// be copied directly\n\t\tconst vertexCount = src.count;\n\t\tfor ( let i = 0; i < vertexCount; i ++ ) {\n\n\t\t\tfor ( let c = 0; c < itemSize; c ++ ) {\n\n\t\t\t\ttarget.setComponent( i + targetOffset, c, src.getComponent( i, c ) );\n\n\t\t\t}\n\n\t\t}\n\n\t} else {\n\n\t\t// faster copy approach using typed array set function\n\t\ttarget.array.set( src.array, targetOffset * itemSize );\n\n\t}\n\n\ttarget.needsUpdate = true;\n\n}\n\nclass BatchedMesh extends Mesh {\n\n\tget maxInstanceCount() {\n\n\t\treturn this._maxInstanceCount;\n\n\t}\n\n\tconstructor( maxInstanceCount, maxVertexCount, maxIndexCount = maxVertexCount * 2, material ) {\n\n\t\tsuper( new BufferGeometry(), material );\n\n\t\tthis.isBatchedMesh = true;\n\t\tthis.perObjectFrustumCulled = true;\n\t\tthis.sortObjects = true;\n\t\tthis.boundingBox = null;\n\t\tthis.boundingSphere = null;\n\t\tthis.customSort = null;\n\n\t\t// stores visible, active, and geometry id per object\n\t\tthis._drawInfo = [];\n\n\t\t// geometry information\n\t\tthis._drawRanges = [];\n\t\tthis._reservedRanges = [];\n\t\tthis._bounds = [];\n\n\t\tthis._maxInstanceCount = maxInstanceCount;\n\t\tthis._maxVertexCount = maxVertexCount;\n\t\tthis._maxIndexCount = maxIndexCount;\n\n\t\tthis._geometryInitialized = false;\n\t\tthis._geometryCount = 0;\n\t\tthis._multiDrawCounts = new Int32Array( maxInstanceCount );\n\t\tthis._multiDrawStarts = new Int32Array( maxInstanceCount );\n\t\tthis._multiDrawCount = 0;\n\t\tthis._multiDrawInstances = null;\n\t\tthis._visibilityChanged = true;\n\n\t\t// Local matrix per geometry by using data texture\n\t\tthis._matricesTexture = null;\n\t\tthis._indirectTexture = null;\n\t\tthis._colorsTexture = null;\n\n\t\tthis._initMatricesTexture();\n\t\tthis._initIndirectTexture();\n\n\t}\n\n\t_initMatricesTexture() {\n\n\t\t// layout (1 matrix = 4 pixels)\n\t\t// RGBA RGBA RGBA RGBA (=> column1, column2, column3, column4)\n\t\t// with 8x8 pixel texture max 16 matrices * 4 pixels = (8 * 8)\n\t\t// 16x16 pixel texture max 64 matrices * 4 pixels = (16 * 16)\n\t\t// 32x32 pixel texture max 256 matrices * 4 pixels = (32 * 32)\n\t\t// 64x64 pixel texture max 1024 matrices * 4 pixels = (64 * 64)\n\n\t\tlet size = Math.sqrt( this._maxInstanceCount * 4 ); // 4 pixels needed for 1 matrix\n\t\tsize = Math.ceil( size / 4 ) * 4;\n\t\tsize = Math.max( size, 4 );\n\n\t\tconst matricesArray = new Float32Array( size * size * 4 ); // 4 floats per RGBA pixel\n\t\tconst matricesTexture = new DataTexture( matricesArray, size, size, RGBAFormat, FloatType );\n\n\t\tthis._matricesTexture = matricesTexture;\n\n\t}\n\n\t_initIndirectTexture() {\n\n\t\tlet size = Math.sqrt( this._maxInstanceCount );\n\t\tsize = Math.ceil( size );\n\n\t\tconst indirectArray = new Uint32Array( size * size );\n\t\tconst indirectTexture = new DataTexture( indirectArray, size, size, RedIntegerFormat, UnsignedIntType );\n\n\t\tthis._indirectTexture = indirectTexture;\n\n\t}\n\n\t_initColorsTexture() {\n\n\t\tlet size = Math.sqrt( this._maxIndexCount );\n\t\tsize = Math.ceil( size );\n\n\t\t// 4 floats per RGBA pixel initialized to white\n\t\tconst colorsArray = new Float32Array( size * size * 4 ).fill( 1 );\n\t\tconst colorsTexture = new DataTexture( colorsArray, size, size, RGBAFormat, FloatType );\n\t\tcolorsTexture.colorSpace = ColorManagement.workingColorSpace;\n\n\t\tthis._colorsTexture = colorsTexture;\n\n\t}\n\n\t_initializeGeometry( reference ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst maxVertexCount = this._maxVertexCount;\n\t\tconst maxIndexCount = this._maxIndexCount;\n\t\tif ( this._geometryInitialized === false ) {\n\n\t\t\tfor ( const attributeName in reference.attributes ) {\n\n\t\t\t\tconst srcAttribute = reference.getAttribute( attributeName );\n\t\t\t\tconst { array, itemSize, normalized } = srcAttribute;\n\n\t\t\t\tconst dstArray = new array.constructor( maxVertexCount * itemSize );\n\t\t\t\tconst dstAttribute = new BufferAttribute( dstArray, itemSize, normalized );\n\n\t\t\t\tgeometry.setAttribute( attributeName, dstAttribute );\n\n\t\t\t}\n\n\t\t\tif ( reference.getIndex() !== null ) {\n\n\t\t\t\t// Reserve last u16 index for primitive restart.\n\t\t\t\tconst indexArray = maxVertexCount > 65535\n\t\t\t\t\t? new Uint32Array( maxIndexCount )\n\t\t\t\t\t: new Uint16Array( maxIndexCount );\n\n\t\t\t\tgeometry.setIndex( new BufferAttribute( indexArray, 1 ) );\n\n\t\t\t}\n\n\t\t\tthis._geometryInitialized = true;\n\n\t\t}\n\n\t}\n\n\t// Make sure the geometry is compatible with the existing combined geometry attributes\n\t_validateGeometry( geometry ) {\n\n\t\t// check to ensure the geometries are using consistent attributes and indices\n\t\tconst batchGeometry = this.geometry;\n\t\tif ( Boolean( geometry.getIndex() ) !== Boolean( batchGeometry.getIndex() ) ) {\n\n\t\t\tthrow new Error( 'BatchedMesh: All geometries must consistently have \"index\".' );\n\n\t\t}\n\n\t\tfor ( const attributeName in batchGeometry.attributes ) {\n\n\t\t\tif ( ! geometry.hasAttribute( attributeName ) ) {\n\n\t\t\t\tthrow new Error( `BatchedMesh: Added geometry missing \"${ attributeName }\". All geometries must have consistent attributes.` );\n\n\t\t\t}\n\n\t\t\tconst srcAttribute = geometry.getAttribute( attributeName );\n\t\t\tconst dstAttribute = batchGeometry.getAttribute( attributeName );\n\t\t\tif ( srcAttribute.itemSize !== dstAttribute.itemSize || srcAttribute.normalized !== dstAttribute.normalized ) {\n\n\t\t\t\tthrow new Error( 'BatchedMesh: All attributes must have a consistent itemSize and normalized value.' );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tsetCustomSort( func ) {\n\n\t\tthis.customSort = func;\n\t\treturn this;\n\n\t}\n\n\tcomputeBoundingBox() {\n\n\t\tif ( this.boundingBox === null ) {\n\n\t\t\tthis.boundingBox = new Box3();\n\n\t\t}\n\n\t\tconst geometryCount = this._geometryCount;\n\t\tconst boundingBox = this.boundingBox;\n\t\tconst drawInfo = this._drawInfo;\n\n\t\tboundingBox.makeEmpty();\n\t\tfor ( let i = 0; i < geometryCount; i ++ ) {\n\n\t\t\tif ( drawInfo[ i ].active === false ) continue;\n\n\t\t\tconst geometryId = drawInfo[ i ].geometryIndex;\n\t\t\tthis.getMatrixAt( i, _matrix$1 );\n\t\t\tthis.getBoundingBoxAt( geometryId, _box$1 ).applyMatrix4( _matrix$1 );\n\t\t\tboundingBox.union( _box$1 );\n\n\t\t}\n\n\t}\n\n\tcomputeBoundingSphere() {\n\n\t\tif ( this.boundingSphere === null ) {\n\n\t\t\tthis.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\tconst boundingSphere = this.boundingSphere;\n\t\tconst drawInfo = this._drawInfo;\n\n\t\tboundingSphere.makeEmpty();\n\t\tfor ( let i = 0, l = drawInfo.length; i < l; i ++ ) {\n\n\t\t\tif ( drawInfo[ i ].active === false ) continue;\n\n\t\t\tconst geometryId = drawInfo[ i ].geometryIndex;\n\t\t\tthis.getMatrixAt( i, _matrix$1 );\n\t\t\tthis.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 );\n\t\t\tboundingSphere.union( _sphere$2 );\n\n\t\t}\n\n\t}\n\n\taddInstance( geometryId ) {\n\n\t\t// ensure we're not over geometry\n\t\tif ( this._drawInfo.length >= this._maxInstanceCount ) {\n\n\t\t\tthrow new Error( 'BatchedMesh: Maximum item count reached.' );\n\n\t\t}\n\n\t\tthis._drawInfo.push( {\n\n\t\t\tvisible: true,\n\t\t\tactive: true,\n\t\t\tgeometryIndex: geometryId,\n\n\t\t} );\n\n\t\t// initialize the matrix\n\t\tconst drawId = this._drawInfo.length - 1;\n\t\tconst matricesTexture = this._matricesTexture;\n\t\tconst matricesArray = matricesTexture.image.data;\n\t\t_identityMatrix.toArray( matricesArray, drawId * 16 );\n\t\tmatricesTexture.needsUpdate = true;\n\n\t\tconst colorsTexture = this._colorsTexture;\n\t\tif ( colorsTexture ) {\n\n\t\t\t_whiteColor.toArray( colorsTexture.image.data, drawId * 4 );\n\t\t\tcolorsTexture.needsUpdate = true;\n\n\t\t}\n\n\t\treturn drawId;\n\n\t}\n\n\taddGeometry( geometry, vertexCount = - 1, indexCount = - 1 ) {\n\n\t\tthis._initializeGeometry( geometry );\n\n\t\tthis._validateGeometry( geometry );\n\n\t\t// ensure we're not over geometry\n\t\tif ( this._drawInfo.length >= this._maxInstanceCount ) {\n\n\t\t\tthrow new Error( 'BatchedMesh: Maximum item count reached.' );\n\n\t\t}\n\n\t\t// get the necessary range fo the geometry\n\t\tconst reservedRange = {\n\t\t\tvertexStart: - 1,\n\t\t\tvertexCount: - 1,\n\t\t\tindexStart: - 1,\n\t\t\tindexCount: - 1,\n\t\t};\n\n\t\tlet lastRange = null;\n\t\tconst reservedRanges = this._reservedRanges;\n\t\tconst drawRanges = this._drawRanges;\n\t\tconst bounds = this._bounds;\n\t\tif ( this._geometryCount !== 0 ) {\n\n\t\t\tlastRange = reservedRanges[ reservedRanges.length - 1 ];\n\n\t\t}\n\n\t\tif ( vertexCount === - 1 ) {\n\n\t\t\treservedRange.vertexCount = geometry.getAttribute( 'position' ).count;\n\n\t\t} else {\n\n\t\t\treservedRange.vertexCount = vertexCount;\n\n\t\t}\n\n\t\tif ( lastRange === null ) {\n\n\t\t\treservedRange.vertexStart = 0;\n\n\t\t} else {\n\n\t\t\treservedRange.vertexStart = lastRange.vertexStart + lastRange.vertexCount;\n\n\t\t}\n\n\t\tconst index = geometry.getIndex();\n\t\tconst hasIndex = index !== null;\n\t\tif ( hasIndex ) {\n\n\t\t\tif ( indexCount\t=== - 1 ) {\n\n\t\t\t\treservedRange.indexCount = index.count;\n\n\t\t\t} else {\n\n\t\t\t\treservedRange.indexCount = indexCount;\n\n\t\t\t}\n\n\t\t\tif ( lastRange === null ) {\n\n\t\t\t\treservedRange.indexStart = 0;\n\n\t\t\t} else {\n\n\t\t\t\treservedRange.indexStart = lastRange.indexStart + lastRange.indexCount;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif (\n\t\t\treservedRange.indexStart !== - 1 &&\n\t\t\treservedRange.indexStart + reservedRange.indexCount > this._maxIndexCount ||\n\t\t\treservedRange.vertexStart + reservedRange.vertexCount > this._maxVertexCount\n\t\t) {\n\n\t\t\tthrow new Error( 'BatchedMesh: Reserved space request exceeds the maximum buffer size.' );\n\n\t\t}\n\n\t\t// update id\n\t\tconst geometryId = this._geometryCount;\n\t\tthis._geometryCount ++;\n\n\t\t// add the reserved range and draw range objects\n\t\treservedRanges.push( reservedRange );\n\t\tdrawRanges.push( {\n\t\t\tstart: hasIndex ? reservedRange.indexStart : reservedRange.vertexStart,\n\t\t\tcount: - 1\n\t\t} );\n\t\tbounds.push( {\n\t\t\tboxInitialized: false,\n\t\t\tbox: new Box3(),\n\n\t\t\tsphereInitialized: false,\n\t\t\tsphere: new Sphere()\n\t\t} );\n\n\t\t// update the geometry\n\t\tthis.setGeometryAt( geometryId, geometry );\n\n\t\treturn geometryId;\n\n\t}\n\n\tsetGeometryAt( geometryId, geometry ) {\n\n\t\tif ( geometryId >= this._geometryCount ) {\n\n\t\t\tthrow new Error( 'BatchedMesh: Maximum geometry count reached.' );\n\n\t\t}\n\n\t\tthis._validateGeometry( geometry );\n\n\t\tconst batchGeometry = this.geometry;\n\t\tconst hasIndex = batchGeometry.getIndex() !== null;\n\t\tconst dstIndex = batchGeometry.getIndex();\n\t\tconst srcIndex = geometry.getIndex();\n\t\tconst reservedRange = this._reservedRanges[ geometryId ];\n\t\tif (\n\t\t\thasIndex &&\n\t\t\tsrcIndex.count > reservedRange.indexCount ||\n\t\t\tgeometry.attributes.position.count > reservedRange.vertexCount\n\t\t) {\n\n\t\t\tthrow new Error( 'BatchedMesh: Reserved space not large enough for provided geometry.' );\n\n\t\t}\n\n\t\t// copy geometry over\n\t\tconst vertexStart = reservedRange.vertexStart;\n\t\tconst vertexCount = reservedRange.vertexCount;\n\t\tfor ( const attributeName in batchGeometry.attributes ) {\n\n\t\t\t// copy attribute data\n\t\t\tconst srcAttribute = geometry.getAttribute( attributeName );\n\t\t\tconst dstAttribute = batchGeometry.getAttribute( attributeName );\n\t\t\tcopyAttributeData( srcAttribute, dstAttribute, vertexStart );\n\n\t\t\t// fill the rest in with zeroes\n\t\t\tconst itemSize = srcAttribute.itemSize;\n\t\t\tfor ( let i = srcAttribute.count, l = vertexCount; i < l; i ++ ) {\n\n\t\t\t\tconst index = vertexStart + i;\n\t\t\t\tfor ( let c = 0; c < itemSize; c ++ ) {\n\n\t\t\t\t\tdstAttribute.setComponent( index, c, 0 );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tdstAttribute.needsUpdate = true;\n\t\t\tdstAttribute.addUpdateRange( vertexStart * itemSize, vertexCount * itemSize );\n\n\t\t}\n\n\t\t// copy index\n\t\tif ( hasIndex ) {\n\n\t\t\tconst indexStart = reservedRange.indexStart;\n\n\t\t\t// copy index data over\n\t\t\tfor ( let i = 0; i < srcIndex.count; i ++ ) {\n\n\t\t\t\tdstIndex.setX( indexStart + i, vertexStart + srcIndex.getX( i ) );\n\n\t\t\t}\n\n\t\t\t// fill the rest in with zeroes\n\t\t\tfor ( let i = srcIndex.count, l = reservedRange.indexCount; i < l; i ++ ) {\n\n\t\t\t\tdstIndex.setX( indexStart + i, vertexStart );\n\n\t\t\t}\n\n\t\t\tdstIndex.needsUpdate = true;\n\t\t\tdstIndex.addUpdateRange( indexStart, reservedRange.indexCount );\n\n\t\t}\n\n\t\t// store the bounding boxes\n\t\tconst bound = this._bounds[ geometryId ];\n\t\tif ( geometry.boundingBox !== null ) {\n\n\t\t\tbound.box.copy( geometry.boundingBox );\n\t\t\tbound.boxInitialized = true;\n\n\t\t} else {\n\n\t\t\tbound.boxInitialized = false;\n\n\t\t}\n\n\t\tif ( geometry.boundingSphere !== null ) {\n\n\t\t\tbound.sphere.copy( geometry.boundingSphere );\n\t\t\tbound.sphereInitialized = true;\n\n\t\t} else {\n\n\t\t\tbound.sphereInitialized = false;\n\n\t\t}\n\n\t\t// set drawRange count\n\t\tconst drawRange = this._drawRanges[ geometryId ];\n\t\tconst posAttr = geometry.getAttribute( 'position' );\n\t\tdrawRange.count = hasIndex ? srcIndex.count : posAttr.count;\n\t\tthis._visibilityChanged = true;\n\n\t\treturn geometryId;\n\n\t}\n\n\t/*\n\tdeleteGeometry( geometryId ) {\n\n\t\t// TODO: delete geometry and associated instances\n\n\t}\n\t*/\n\n\t/*\n\tdeleteInstance( instanceId ) {\n\n\t\t// Note: User needs to call optimize() afterward to pack the data.\n\n\t\tconst drawInfo = this._drawInfo;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tdrawInfo[ instanceId ].active = false;\n\t\tthis._visibilityChanged = true;\n\n\t\treturn this;\n\n\t}\n\t*/\n\n\t// get bounding box and compute it if it doesn't exist\n\tgetBoundingBoxAt( geometryId, target ) {\n\n\t\tif ( geometryId >= this._geometryCount ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// compute bounding box\n\t\tconst bound = this._bounds[ geometryId ];\n\t\tconst box = bound.box;\n\t\tconst geometry = this.geometry;\n\t\tif ( bound.boxInitialized === false ) {\n\n\t\t\tbox.makeEmpty();\n\n\t\t\tconst index = geometry.index;\n\t\t\tconst position = geometry.attributes.position;\n\t\t\tconst drawRange = this._drawRanges[ geometryId ];\n\t\t\tfor ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {\n\n\t\t\t\tlet iv = i;\n\t\t\t\tif ( index ) {\n\n\t\t\t\t\tiv = index.getX( iv );\n\n\t\t\t\t}\n\n\t\t\t\tbox.expandByPoint( _vector$5.fromBufferAttribute( position, iv ) );\n\n\t\t\t}\n\n\t\t\tbound.boxInitialized = true;\n\n\t\t}\n\n\t\ttarget.copy( box );\n\t\treturn target;\n\n\t}\n\n\t// get bounding sphere and compute it if it doesn't exist\n\tgetBoundingSphereAt( geometryId, target ) {\n\n\t\tif ( geometryId >= this._geometryCount ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\t// compute bounding sphere\n\t\tconst bound = this._bounds[ geometryId ];\n\t\tconst sphere = bound.sphere;\n\t\tconst geometry = this.geometry;\n\t\tif ( bound.sphereInitialized === false ) {\n\n\t\t\tsphere.makeEmpty();\n\n\t\t\tthis.getBoundingBoxAt( geometryId, _box$1 );\n\t\t\t_box$1.getCenter( sphere.center );\n\n\t\t\tconst index = geometry.index;\n\t\t\tconst position = geometry.attributes.position;\n\t\t\tconst drawRange = this._drawRanges[ geometryId ];\n\n\t\t\tlet maxRadiusSq = 0;\n\t\t\tfor ( let i = drawRange.start, l = drawRange.start + drawRange.count; i < l; i ++ ) {\n\n\t\t\t\tlet iv = i;\n\t\t\t\tif ( index ) {\n\n\t\t\t\t\tiv = index.getX( iv );\n\n\t\t\t\t}\n\n\t\t\t\t_vector$5.fromBufferAttribute( position, iv );\n\t\t\t\tmaxRadiusSq = Math.max( maxRadiusSq, sphere.center.distanceToSquared( _vector$5 ) );\n\n\t\t\t}\n\n\t\t\tsphere.radius = Math.sqrt( maxRadiusSq );\n\t\t\tbound.sphereInitialized = true;\n\n\t\t}\n\n\t\ttarget.copy( sphere );\n\t\treturn target;\n\n\t}\n\n\tsetMatrixAt( instanceId, matrix ) {\n\n\t\t// @TODO: Map geometryId to index of the arrays because\n\t\t// optimize() can make geometryId mismatch the index\n\n\t\tconst drawInfo = this._drawInfo;\n\t\tconst matricesTexture = this._matricesTexture;\n\t\tconst matricesArray = this._matricesTexture.image.data;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tmatrix.toArray( matricesArray, instanceId * 16 );\n\t\tmatricesTexture.needsUpdate = true;\n\n\t\treturn this;\n\n\t}\n\n\tgetMatrixAt( instanceId, matrix ) {\n\n\t\tconst drawInfo = this._drawInfo;\n\t\tconst matricesArray = this._matricesTexture.image.data;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\treturn matrix.fromArray( matricesArray, instanceId * 16 );\n\n\t}\n\n\tsetColorAt( instanceId, color ) {\n\n\t\tif ( this._colorsTexture === null ) {\n\n\t\t\tthis._initColorsTexture();\n\n\t\t}\n\n\t\t// @TODO: Map id to index of the arrays because\n\t\t// optimize() can make id mismatch the index\n\n\t\tconst colorsTexture = this._colorsTexture;\n\t\tconst colorsArray = this._colorsTexture.image.data;\n\t\tconst drawInfo = this._drawInfo;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tcolor.toArray( colorsArray, instanceId * 4 );\n\t\tcolorsTexture.needsUpdate = true;\n\n\t\treturn this;\n\n\t}\n\n\tgetColorAt( instanceId, color ) {\n\n\t\tconst colorsArray = this._colorsTexture.image.data;\n\t\tconst drawInfo = this._drawInfo;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\treturn color.fromArray( colorsArray, instanceId * 4 );\n\n\t}\n\n\tsetVisibleAt( instanceId, value ) {\n\n\t\t// if the geometry is out of range, not active, or visibility state\n\t\t// does not change then return early\n\t\tconst drawInfo = this._drawInfo;\n\t\tif (\n\t\t\tinstanceId >= drawInfo.length ||\n\t\t\tdrawInfo[ instanceId ].active === false ||\n\t\t\tdrawInfo[ instanceId ].visible === value\n\t\t) {\n\n\t\t\treturn this;\n\n\t\t}\n\n\t\tdrawInfo[ instanceId ].visible = value;\n\t\tthis._visibilityChanged = true;\n\n\t\treturn this;\n\n\t}\n\n\tgetVisibleAt( instanceId ) {\n\n\t\t// return early if the geometry is out of range or not active\n\t\tconst drawInfo = this._drawInfo;\n\t\tif ( instanceId >= drawInfo.length || drawInfo[ instanceId ].active === false ) {\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\treturn drawInfo[ instanceId ].visible;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst drawInfo = this._drawInfo;\n\t\tconst drawRanges = this._drawRanges;\n\t\tconst matrixWorld = this.matrixWorld;\n\t\tconst batchGeometry = this.geometry;\n\n\t\t// iterate over each geometry\n\t\t_mesh.material = this.material;\n\t\t_mesh.geometry.index = batchGeometry.index;\n\t\t_mesh.geometry.attributes = batchGeometry.attributes;\n\t\tif ( _mesh.geometry.boundingBox === null ) {\n\n\t\t\t_mesh.geometry.boundingBox = new Box3();\n\n\t\t}\n\n\t\tif ( _mesh.geometry.boundingSphere === null ) {\n\n\t\t\t_mesh.geometry.boundingSphere = new Sphere();\n\n\t\t}\n\n\t\tfor ( let i = 0, l = drawInfo.length; i < l; i ++ ) {\n\n\t\t\tif ( ! drawInfo[ i ].visible || ! drawInfo[ i ].active ) {\n\n\t\t\t\tcontinue;\n\n\t\t\t}\n\n\t\t\tconst geometryId = drawInfo[ i ].geometryIndex;\n\t\t\tconst drawRange = drawRanges[ geometryId ];\n\t\t\t_mesh.geometry.setDrawRange( drawRange.start, drawRange.count );\n\n\t\t\t// ge the intersects\n\t\t\tthis.getMatrixAt( i, _mesh.matrixWorld ).premultiply( matrixWorld );\n\t\t\tthis.getBoundingBoxAt( geometryId, _mesh.geometry.boundingBox );\n\t\t\tthis.getBoundingSphereAt( geometryId, _mesh.geometry.boundingSphere );\n\t\t\t_mesh.raycast( raycaster, _batchIntersects );\n\n\t\t\t// add batch id to the intersects\n\t\t\tfor ( let j = 0, l = _batchIntersects.length; j < l; j ++ ) {\n\n\t\t\t\tconst intersect = _batchIntersects[ j ];\n\t\t\t\tintersect.object = this;\n\t\t\t\tintersect.batchId = i;\n\t\t\t\tintersects.push( intersect );\n\n\t\t\t}\n\n\t\t\t_batchIntersects.length = 0;\n\n\t\t}\n\n\t\t_mesh.material = null;\n\t\t_mesh.geometry.index = null;\n\t\t_mesh.geometry.attributes = {};\n\t\t_mesh.geometry.setDrawRange( 0, Infinity );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.geometry = source.geometry.clone();\n\t\tthis.perObjectFrustumCulled = source.perObjectFrustumCulled;\n\t\tthis.sortObjects = source.sortObjects;\n\t\tthis.boundingBox = source.boundingBox !== null ? source.boundingBox.clone() : null;\n\t\tthis.boundingSphere = source.boundingSphere !== null ? source.boundingSphere.clone() : null;\n\n\t\tthis._drawRanges = source._drawRanges.map( range => ( { ...range } ) );\n\t\tthis._reservedRanges = source._reservedRanges.map( range => ( { ...range } ) );\n\n\t\tthis._drawInfo = source._drawInfo.map( inf => ( { ...inf } ) );\n\t\tthis._bounds = source._bounds.map( bound => ( {\n\t\t\tboxInitialized: bound.boxInitialized,\n\t\t\tbox: bound.box.clone(),\n\n\t\t\tsphereInitialized: bound.sphereInitialized,\n\t\t\tsphere: bound.sphere.clone()\n\t\t} ) );\n\n\t\tthis._maxInstanceCount = source._maxInstanceCount;\n\t\tthis._maxVertexCount = source._maxVertexCount;\n\t\tthis._maxIndexCount = source._maxIndexCount;\n\n\t\tthis._geometryInitialized = source._geometryInitialized;\n\t\tthis._geometryCount = source._geometryCount;\n\t\tthis._multiDrawCounts = source._multiDrawCounts.slice();\n\t\tthis._multiDrawStarts = source._multiDrawStarts.slice();\n\n\t\tthis._matricesTexture = source._matricesTexture.clone();\n\t\tthis._matricesTexture.image.data = this._matricesTexture.image.data.slice();\n\n\t\tif ( this._colorsTexture !== null ) {\n\n\t\t\tthis._colorsTexture = source._colorsTexture.clone();\n\t\t\tthis._colorsTexture.image.data = this._colorsTexture.image.data.slice();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\t// Assuming the geometry is not shared with other meshes\n\t\tthis.geometry.dispose();\n\n\t\tthis._matricesTexture.dispose();\n\t\tthis._matricesTexture = null;\n\n\t\tthis._indirectTexture.dispose();\n\t\tthis._indirectTexture = null;\n\n\t\tif ( this._colorsTexture !== null ) {\n\n\t\t\tthis._colorsTexture.dispose();\n\t\t\tthis._colorsTexture = null;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tonBeforeRender( renderer, scene, camera, geometry, material/*, _group*/ ) {\n\n\t\t// if visibility has not changed and frustum culling and object sorting is not required\n\t\t// then skip iterating over all items\n\t\tif ( ! this._visibilityChanged && ! this.perObjectFrustumCulled && ! this.sortObjects ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t// the indexed version of the multi draw function requires specifying the start\n\t\t// offset in bytes.\n\t\tconst index = geometry.getIndex();\n\t\tconst bytesPerElement = index === null ? 1 : index.array.BYTES_PER_ELEMENT;\n\n\t\tconst drawInfo = this._drawInfo;\n\t\tconst multiDrawStarts = this._multiDrawStarts;\n\t\tconst multiDrawCounts = this._multiDrawCounts;\n\t\tconst drawRanges = this._drawRanges;\n\t\tconst perObjectFrustumCulled = this.perObjectFrustumCulled;\n\t\tconst indirectTexture = this._indirectTexture;\n\t\tconst indirectArray = indirectTexture.image.data;\n\n\t\t// prepare the frustum in the local frame\n\t\tif ( perObjectFrustumCulled ) {\n\n\t\t\t_projScreenMatrix$2\n\t\t\t\t.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse )\n\t\t\t\t.multiply( this.matrixWorld );\n\t\t\t_frustum.setFromProjectionMatrix(\n\t\t\t\t_projScreenMatrix$2,\n\t\t\t\trenderer.coordinateSystem\n\t\t\t);\n\n\t\t}\n\n\t\tlet count = 0;\n\t\tif ( this.sortObjects ) {\n\n\t\t\t// get the camera position in the local frame\n\t\t\t_invMatrixWorld.copy( this.matrixWorld ).invert();\n\t\t\t_vector$5.setFromMatrixPosition( camera.matrixWorld ).applyMatrix4( _invMatrixWorld );\n\t\t\t_forward.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld ).transformDirection( _invMatrixWorld );\n\n\t\t\tfor ( let i = 0, l = drawInfo.length; i < l; i ++ ) {\n\n\t\t\t\tif ( drawInfo[ i ].visible && drawInfo[ i ].active ) {\n\n\t\t\t\t\tconst geometryId = drawInfo[ i ].geometryIndex;\n\n\t\t\t\t\t// get the bounds in world space\n\t\t\t\t\tthis.getMatrixAt( i, _matrix$1 );\n\t\t\t\t\tthis.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 );\n\n\t\t\t\t\t// determine whether the batched geometry is within the frustum\n\t\t\t\t\tlet culled = false;\n\t\t\t\t\tif ( perObjectFrustumCulled ) {\n\n\t\t\t\t\t\tculled = ! _frustum.intersectsSphere( _sphere$2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! culled ) {\n\n\t\t\t\t\t\t// get the distance from camera used for sorting\n\t\t\t\t\t\tconst z = _temp.subVectors( _sphere$2.center, _vector$5 ).dot( _forward );\n\t\t\t\t\t\t_renderList.push( drawRanges[ geometryId ], z, i );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// Sort the draw ranges and prep for rendering\n\t\t\tconst list = _renderList.list;\n\t\t\tconst customSort = this.customSort;\n\t\t\tif ( customSort === null ) {\n\n\t\t\t\tlist.sort( material.transparent ? sortTransparent : sortOpaque );\n\n\t\t\t} else {\n\n\t\t\t\tcustomSort.call( this, list, camera );\n\n\t\t\t}\n\n\t\t\tfor ( let i = 0, l = list.length; i < l; i ++ ) {\n\n\t\t\t\tconst item = list[ i ];\n\t\t\t\tmultiDrawStarts[ count ] = item.start * bytesPerElement;\n\t\t\t\tmultiDrawCounts[ count ] = item.count;\n\t\t\t\tindirectArray[ count ] = item.index;\n\t\t\t\tcount ++;\n\n\t\t\t}\n\n\t\t\t_renderList.reset();\n\n\t\t} else {\n\n\t\t\tfor ( let i = 0, l = drawInfo.length; i < l; i ++ ) {\n\n\t\t\t\tif ( drawInfo[ i ].visible && drawInfo[ i ].active ) {\n\n\t\t\t\t\tconst geometryId = drawInfo[ i ].geometryIndex;\n\n\t\t\t\t\t// determine whether the batched geometry is within the frustum\n\t\t\t\t\tlet culled = false;\n\t\t\t\t\tif ( perObjectFrustumCulled ) {\n\n\t\t\t\t\t\t// get the bounds in world space\n\t\t\t\t\t\tthis.getMatrixAt( i, _matrix$1 );\n\t\t\t\t\t\tthis.getBoundingSphereAt( geometryId, _sphere$2 ).applyMatrix4( _matrix$1 );\n\t\t\t\t\t\tculled = ! _frustum.intersectsSphere( _sphere$2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! culled ) {\n\n\t\t\t\t\t\tconst range = drawRanges[ geometryId ];\n\t\t\t\t\t\tmultiDrawStarts[ count ] = range.start * bytesPerElement;\n\t\t\t\t\t\tmultiDrawCounts[ count ] = range.count;\n\t\t\t\t\t\tindirectArray[ count ] = i;\n\t\t\t\t\t\tcount ++;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tindirectTexture.needsUpdate = true;\n\t\tthis._multiDrawCount = count;\n\t\tthis._visibilityChanged = false;\n\n\t}\n\n\tonBeforeShadow( renderer, object, camera, shadowCamera, geometry, depthMaterial/* , group */ ) {\n\n\t\tthis.onBeforeRender( renderer, null, shadowCamera, geometry, depthMaterial );\n\n\t}\n\n}\n\nclass LineBasicMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isLineBasicMaterial = true;\n\n\t\tthis.type = 'LineBasicMaterial';\n\n\t\tthis.color = new Color( 0xffffff );\n\n\t\tthis.map = null;\n\n\t\tthis.linewidth = 1;\n\t\tthis.linecap = 'round';\n\t\tthis.linejoin = 'round';\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.linewidth = source.linewidth;\n\t\tthis.linecap = source.linecap;\n\t\tthis.linejoin = source.linejoin;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _vStart = /*@__PURE__*/ new Vector3();\nconst _vEnd = /*@__PURE__*/ new Vector3();\n\nconst _inverseMatrix$1 = /*@__PURE__*/ new Matrix4();\nconst _ray$1 = /*@__PURE__*/ new Ray();\nconst _sphere$1 = /*@__PURE__*/ new Sphere();\n\nconst _intersectPointOnRay = /*@__PURE__*/ new Vector3();\nconst _intersectPointOnSegment = /*@__PURE__*/ new Vector3();\n\nclass Line extends Object3D {\n\n\tconstructor( geometry = new BufferGeometry(), material = new LineBasicMaterial() ) {\n\n\t\tsuper();\n\n\t\tthis.isLine = true;\n\n\t\tthis.type = 'Line';\n\n\t\tthis.geometry = geometry;\n\t\tthis.material = material;\n\n\t\tthis.updateMorphTargets();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.material = Array.isArray( source.material ) ? source.material.slice() : source.material;\n\t\tthis.geometry = source.geometry;\n\n\t\treturn this;\n\n\t}\n\n\tcomputeLineDistances() {\n\n\t\tconst geometry = this.geometry;\n\n\t\t// we assume non-indexed geometry\n\n\t\tif ( geometry.index === null ) {\n\n\t\t\tconst positionAttribute = geometry.attributes.position;\n\t\t\tconst lineDistances = [ 0 ];\n\n\t\t\tfor ( let i = 1, l = positionAttribute.count; i < l; i ++ ) {\n\n\t\t\t\t_vStart.fromBufferAttribute( positionAttribute, i - 1 );\n\t\t\t\t_vEnd.fromBufferAttribute( positionAttribute, i );\n\n\t\t\t\tlineDistances[ i ] = lineDistances[ i - 1 ];\n\t\t\t\tlineDistances[ i ] += _vStart.distanceTo( _vEnd );\n\n\t\t\t}\n\n\t\t\tgeometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.Line.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst matrixWorld = this.matrixWorld;\n\t\tconst threshold = raycaster.params.Line.threshold;\n\t\tconst drawRange = geometry.drawRange;\n\n\t\t// Checking boundingSphere distance to ray\n\n\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t_sphere$1.copy( geometry.boundingSphere );\n\t\t_sphere$1.applyMatrix4( matrixWorld );\n\t\t_sphere$1.radius += threshold;\n\n\t\tif ( raycaster.ray.intersectsSphere( _sphere$1 ) === false ) return;\n\n\t\t//\n\n\t\t_inverseMatrix$1.copy( matrixWorld ).invert();\n\t\t_ray$1.copy( raycaster.ray ).applyMatrix4( _inverseMatrix$1 );\n\n\t\tconst localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );\n\t\tconst localThresholdSq = localThreshold * localThreshold;\n\n\t\tconst step = this.isLineSegments ? 2 : 1;\n\n\t\tconst index = geometry.index;\n\t\tconst attributes = geometry.attributes;\n\t\tconst positionAttribute = attributes.position;\n\n\t\tif ( index !== null ) {\n\n\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\tconst end = Math.min( index.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\tfor ( let i = start, l = end - 1; i < l; i += step ) {\n\n\t\t\t\tconst a = index.getX( i );\n\t\t\t\tconst b = index.getX( i + 1 );\n\n\t\t\t\tconst intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b );\n\n\t\t\t\tif ( intersect ) {\n\n\t\t\t\t\tintersects.push( intersect );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.isLineLoop ) {\n\n\t\t\t\tconst a = index.getX( end - 1 );\n\t\t\t\tconst b = index.getX( start );\n\n\t\t\t\tconst intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, a, b );\n\n\t\t\t\tif ( intersect ) {\n\n\t\t\t\t\tintersects.push( intersect );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\tconst end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\tfor ( let i = start, l = end - 1; i < l; i += step ) {\n\n\t\t\t\tconst intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, i, i + 1 );\n\n\t\t\t\tif ( intersect ) {\n\n\t\t\t\t\tintersects.push( intersect );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( this.isLineLoop ) {\n\n\t\t\t\tconst intersect = checkIntersection( this, raycaster, _ray$1, localThresholdSq, end - 1, start );\n\n\t\t\t\tif ( intersect ) {\n\n\t\t\t\t\tintersects.push( intersect );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tupdateMorphTargets() {\n\n\t\tconst geometry = this.geometry;\n\n\t\tconst morphAttributes = geometry.morphAttributes;\n\t\tconst keys = Object.keys( morphAttributes );\n\n\t\tif ( keys.length > 0 ) {\n\n\t\t\tconst morphAttribute = morphAttributes[ keys[ 0 ] ];\n\n\t\t\tif ( morphAttribute !== undefined ) {\n\n\t\t\t\tthis.morphTargetInfluences = [];\n\t\t\t\tthis.morphTargetDictionary = {};\n\n\t\t\t\tfor ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {\n\n\t\t\t\t\tconst name = morphAttribute[ m ].name || String( m );\n\n\t\t\t\t\tthis.morphTargetInfluences.push( 0 );\n\t\t\t\t\tthis.morphTargetDictionary[ name ] = m;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nfunction checkIntersection( object, raycaster, ray, thresholdSq, a, b ) {\n\n\tconst positionAttribute = object.geometry.attributes.position;\n\n\t_vStart.fromBufferAttribute( positionAttribute, a );\n\t_vEnd.fromBufferAttribute( positionAttribute, b );\n\n\tconst distSq = ray.distanceSqToSegment( _vStart, _vEnd, _intersectPointOnRay, _intersectPointOnSegment );\n\n\tif ( distSq > thresholdSq ) return;\n\n\t_intersectPointOnRay.applyMatrix4( object.matrixWorld ); // Move back to world space for distance calculation\n\n\tconst distance = raycaster.ray.origin.distanceTo( _intersectPointOnRay );\n\n\tif ( distance < raycaster.near || distance > raycaster.far ) return;\n\n\treturn {\n\n\t\tdistance: distance,\n\t\t// What do we want? intersection point on the ray or on the segment??\n\t\t// point: raycaster.ray.at( distance ),\n\t\tpoint: _intersectPointOnSegment.clone().applyMatrix4( object.matrixWorld ),\n\t\tindex: a,\n\t\tface: null,\n\t\tfaceIndex: null,\n\t\tobject: object\n\n\t};\n\n}\n\nconst _start = /*@__PURE__*/ new Vector3();\nconst _end = /*@__PURE__*/ new Vector3();\n\nclass LineSegments extends Line {\n\n\tconstructor( geometry, material ) {\n\n\t\tsuper( geometry, material );\n\n\t\tthis.isLineSegments = true;\n\n\t\tthis.type = 'LineSegments';\n\n\t}\n\n\tcomputeLineDistances() {\n\n\t\tconst geometry = this.geometry;\n\n\t\t// we assume non-indexed geometry\n\n\t\tif ( geometry.index === null ) {\n\n\t\t\tconst positionAttribute = geometry.attributes.position;\n\t\t\tconst lineDistances = [];\n\n\t\t\tfor ( let i = 0, l = positionAttribute.count; i < l; i += 2 ) {\n\n\t\t\t\t_start.fromBufferAttribute( positionAttribute, i );\n\t\t\t\t_end.fromBufferAttribute( positionAttribute, i + 1 );\n\n\t\t\t\tlineDistances[ i ] = ( i === 0 ) ? 0 : lineDistances[ i - 1 ];\n\t\t\t\tlineDistances[ i + 1 ] = lineDistances[ i ] + _start.distanceTo( _end );\n\n\t\t\t}\n\n\t\t\tgeometry.setAttribute( 'lineDistance', new Float32BufferAttribute( lineDistances, 1 ) );\n\n\t\t} else {\n\n\t\t\tconsole.warn( 'THREE.LineSegments.computeLineDistances(): Computation only possible with non-indexed BufferGeometry.' );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass LineLoop extends Line {\n\n\tconstructor( geometry, material ) {\n\n\t\tsuper( geometry, material );\n\n\t\tthis.isLineLoop = true;\n\n\t\tthis.type = 'LineLoop';\n\n\t}\n\n}\n\nclass PointsMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isPointsMaterial = true;\n\n\t\tthis.type = 'PointsMaterial';\n\n\t\tthis.color = new Color( 0xffffff );\n\n\t\tthis.map = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.size = 1;\n\t\tthis.sizeAttenuation = true;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.size = source.size;\n\t\tthis.sizeAttenuation = source.sizeAttenuation;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _inverseMatrix = /*@__PURE__*/ new Matrix4();\nconst _ray = /*@__PURE__*/ new Ray();\nconst _sphere = /*@__PURE__*/ new Sphere();\nconst _position$2 = /*@__PURE__*/ new Vector3();\n\nclass Points extends Object3D {\n\n\tconstructor( geometry = new BufferGeometry(), material = new PointsMaterial() ) {\n\n\t\tsuper();\n\n\t\tthis.isPoints = true;\n\n\t\tthis.type = 'Points';\n\n\t\tthis.geometry = geometry;\n\t\tthis.material = material;\n\n\t\tthis.updateMorphTargets();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.material = Array.isArray( source.material ) ? source.material.slice() : source.material;\n\t\tthis.geometry = source.geometry;\n\n\t\treturn this;\n\n\t}\n\n\traycast( raycaster, intersects ) {\n\n\t\tconst geometry = this.geometry;\n\t\tconst matrixWorld = this.matrixWorld;\n\t\tconst threshold = raycaster.params.Points.threshold;\n\t\tconst drawRange = geometry.drawRange;\n\n\t\t// Checking boundingSphere distance to ray\n\n\t\tif ( geometry.boundingSphere === null ) geometry.computeBoundingSphere();\n\n\t\t_sphere.copy( geometry.boundingSphere );\n\t\t_sphere.applyMatrix4( matrixWorld );\n\t\t_sphere.radius += threshold;\n\n\t\tif ( raycaster.ray.intersectsSphere( _sphere ) === false ) return;\n\n\t\t//\n\n\t\t_inverseMatrix.copy( matrixWorld ).invert();\n\t\t_ray.copy( raycaster.ray ).applyMatrix4( _inverseMatrix );\n\n\t\tconst localThreshold = threshold / ( ( this.scale.x + this.scale.y + this.scale.z ) / 3 );\n\t\tconst localThresholdSq = localThreshold * localThreshold;\n\n\t\tconst index = geometry.index;\n\t\tconst attributes = geometry.attributes;\n\t\tconst positionAttribute = attributes.position;\n\n\t\tif ( index !== null ) {\n\n\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\tconst end = Math.min( index.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\tfor ( let i = start, il = end; i < il; i ++ ) {\n\n\t\t\t\tconst a = index.getX( i );\n\n\t\t\t\t_position$2.fromBufferAttribute( positionAttribute, a );\n\n\t\t\t\ttestPoint( _position$2, a, localThresholdSq, matrixWorld, raycaster, intersects, this );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\tconst start = Math.max( 0, drawRange.start );\n\t\t\tconst end = Math.min( positionAttribute.count, ( drawRange.start + drawRange.count ) );\n\n\t\t\tfor ( let i = start, l = end; i < l; i ++ ) {\n\n\t\t\t\t_position$2.fromBufferAttribute( positionAttribute, i );\n\n\t\t\t\ttestPoint( _position$2, i, localThresholdSq, matrixWorld, raycaster, intersects, this );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tupdateMorphTargets() {\n\n\t\tconst geometry = this.geometry;\n\n\t\tconst morphAttributes = geometry.morphAttributes;\n\t\tconst keys = Object.keys( morphAttributes );\n\n\t\tif ( keys.length > 0 ) {\n\n\t\t\tconst morphAttribute = morphAttributes[ keys[ 0 ] ];\n\n\t\t\tif ( morphAttribute !== undefined ) {\n\n\t\t\t\tthis.morphTargetInfluences = [];\n\t\t\t\tthis.morphTargetDictionary = {};\n\n\t\t\t\tfor ( let m = 0, ml = morphAttribute.length; m < ml; m ++ ) {\n\n\t\t\t\t\tconst name = morphAttribute[ m ].name || String( m );\n\n\t\t\t\t\tthis.morphTargetInfluences.push( 0 );\n\t\t\t\t\tthis.morphTargetDictionary[ name ] = m;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n}\n\nfunction testPoint( point, index, localThresholdSq, matrixWorld, raycaster, intersects, object ) {\n\n\tconst rayPointDistanceSq = _ray.distanceSqToPoint( point );\n\n\tif ( rayPointDistanceSq < localThresholdSq ) {\n\n\t\tconst intersectPoint = new Vector3();\n\n\t\t_ray.closestPointToPoint( point, intersectPoint );\n\t\tintersectPoint.applyMatrix4( matrixWorld );\n\n\t\tconst distance = raycaster.ray.origin.distanceTo( intersectPoint );\n\n\t\tif ( distance < raycaster.near || distance > raycaster.far ) return;\n\n\t\tintersects.push( {\n\n\t\t\tdistance: distance,\n\t\t\tdistanceToRay: Math.sqrt( rayPointDistanceSq ),\n\t\t\tpoint: intersectPoint,\n\t\t\tindex: index,\n\t\t\tface: null,\n\t\t\tobject: object\n\n\t\t} );\n\n\t}\n\n}\n\nclass VideoTexture extends Texture {\n\n\tconstructor( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {\n\n\t\tsuper( video, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\t\tthis.isVideoTexture = true;\n\n\t\tthis.minFilter = minFilter !== undefined ? minFilter : LinearFilter;\n\t\tthis.magFilter = magFilter !== undefined ? magFilter : LinearFilter;\n\n\t\tthis.generateMipmaps = false;\n\n\t\tconst scope = this;\n\n\t\tfunction updateVideo() {\n\n\t\t\tscope.needsUpdate = true;\n\t\t\tvideo.requestVideoFrameCallback( updateVideo );\n\n\t\t}\n\n\t\tif ( 'requestVideoFrameCallback' in video ) {\n\n\t\t\tvideo.requestVideoFrameCallback( updateVideo );\n\n\t\t}\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor( this.image ).copy( this );\n\n\t}\n\n\tupdate() {\n\n\t\tconst video = this.image;\n\t\tconst hasVideoFrameCallback = 'requestVideoFrameCallback' in video;\n\n\t\tif ( hasVideoFrameCallback === false && video.readyState >= video.HAVE_CURRENT_DATA ) {\n\n\t\t\tthis.needsUpdate = true;\n\n\t\t}\n\n\t}\n\n}\n\nclass FramebufferTexture extends Texture {\n\n\tconstructor( width, height ) {\n\n\t\tsuper( { width, height } );\n\n\t\tthis.isFramebufferTexture = true;\n\n\t\tthis.magFilter = NearestFilter;\n\t\tthis.minFilter = NearestFilter;\n\n\t\tthis.generateMipmaps = false;\n\n\t\tthis.needsUpdate = true;\n\n\t}\n\n}\n\nclass CompressedTexture extends Texture {\n\n\tconstructor( mipmaps, width, height, format, type, mapping, wrapS, wrapT, magFilter, minFilter, anisotropy, colorSpace ) {\n\n\t\tsuper( null, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy, colorSpace );\n\n\t\tthis.isCompressedTexture = true;\n\n\t\tthis.image = { width: width, height: height };\n\t\tthis.mipmaps = mipmaps;\n\n\t\t// no flipping for cube textures\n\t\t// (also flipping doesn't work for compressed textures )\n\n\t\tthis.flipY = false;\n\n\t\t// can't generate mipmaps for compressed textures\n\t\t// mips must be embedded in DDS files\n\n\t\tthis.generateMipmaps = false;\n\n\t}\n\n}\n\nclass CompressedArrayTexture extends CompressedTexture {\n\n\tconstructor( mipmaps, width, height, depth, format, type ) {\n\n\t\tsuper( mipmaps, width, height, format, type );\n\n\t\tthis.isCompressedArrayTexture = true;\n\t\tthis.image.depth = depth;\n\t\tthis.wrapR = ClampToEdgeWrapping;\n\n\t\tthis.layerUpdates = new Set();\n\n\t}\n\n\taddLayerUpdate( layerIndex ) {\n\n\t\tthis.layerUpdates.add( layerIndex );\n\n\t}\n\n\tclearLayerUpdates() {\n\n\t\tthis.layerUpdates.clear();\n\n\t}\n\n}\n\nclass CompressedCubeTexture extends CompressedTexture {\n\n\tconstructor( images, format, type ) {\n\n\t\tsuper( undefined, images[ 0 ].width, images[ 0 ].height, format, type, CubeReflectionMapping );\n\n\t\tthis.isCompressedCubeTexture = true;\n\t\tthis.isCubeTexture = true;\n\n\t\tthis.image = images;\n\n\t}\n\n}\n\nclass CanvasTexture extends Texture {\n\n\tconstructor( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy ) {\n\n\t\tsuper( canvas, mapping, wrapS, wrapT, magFilter, minFilter, format, type, anisotropy );\n\n\t\tthis.isCanvasTexture = true;\n\n\t\tthis.needsUpdate = true;\n\n\t}\n\n}\n\n/**\n * Extensible curve object.\n *\n * Some common of curve methods:\n * .getPoint( t, optionalTarget ), .getTangent( t, optionalTarget )\n * .getPointAt( u, optionalTarget ), .getTangentAt( u, optionalTarget )\n * .getPoints(), .getSpacedPoints()\n * .getLength()\n * .updateArcLengths()\n *\n * This following curves inherit from THREE.Curve:\n *\n * -- 2D curves --\n * THREE.ArcCurve\n * THREE.CubicBezierCurve\n * THREE.EllipseCurve\n * THREE.LineCurve\n * THREE.QuadraticBezierCurve\n * THREE.SplineCurve\n *\n * -- 3D curves --\n * THREE.CatmullRomCurve3\n * THREE.CubicBezierCurve3\n * THREE.LineCurve3\n * THREE.QuadraticBezierCurve3\n *\n * A series of curves can be represented as a THREE.CurvePath.\n *\n **/\n\nclass Curve {\n\n\tconstructor() {\n\n\t\tthis.type = 'Curve';\n\n\t\tthis.arcLengthDivisions = 200;\n\n\t}\n\n\t// Virtual base class method to overwrite and implement in subclasses\n\t//\t- t [0 .. 1]\n\n\tgetPoint( /* t, optionalTarget */ ) {\n\n\t\tconsole.warn( 'THREE.Curve: .getPoint() not implemented.' );\n\t\treturn null;\n\n\t}\n\n\t// Get point at relative position in curve according to arc length\n\t// - u [0 .. 1]\n\n\tgetPointAt( u, optionalTarget ) {\n\n\t\tconst t = this.getUtoTmapping( u );\n\t\treturn this.getPoint( t, optionalTarget );\n\n\t}\n\n\t// Get sequence of points using getPoint( t )\n\n\tgetPoints( divisions = 5 ) {\n\n\t\tconst points = [];\n\n\t\tfor ( let d = 0; d <= divisions; d ++ ) {\n\n\t\t\tpoints.push( this.getPoint( d / divisions ) );\n\n\t\t}\n\n\t\treturn points;\n\n\t}\n\n\t// Get sequence of points using getPointAt( u )\n\n\tgetSpacedPoints( divisions = 5 ) {\n\n\t\tconst points = [];\n\n\t\tfor ( let d = 0; d <= divisions; d ++ ) {\n\n\t\t\tpoints.push( this.getPointAt( d / divisions ) );\n\n\t\t}\n\n\t\treturn points;\n\n\t}\n\n\t// Get total curve arc length\n\n\tgetLength() {\n\n\t\tconst lengths = this.getLengths();\n\t\treturn lengths[ lengths.length - 1 ];\n\n\t}\n\n\t// Get list of cumulative segment lengths\n\n\tgetLengths( divisions = this.arcLengthDivisions ) {\n\n\t\tif ( this.cacheArcLengths &&\n\t\t\t( this.cacheArcLengths.length === divisions + 1 ) &&\n\t\t\t! this.needsUpdate ) {\n\n\t\t\treturn this.cacheArcLengths;\n\n\t\t}\n\n\t\tthis.needsUpdate = false;\n\n\t\tconst cache = [];\n\t\tlet current, last = this.getPoint( 0 );\n\t\tlet sum = 0;\n\n\t\tcache.push( 0 );\n\n\t\tfor ( let p = 1; p <= divisions; p ++ ) {\n\n\t\t\tcurrent = this.getPoint( p / divisions );\n\t\t\tsum += current.distanceTo( last );\n\t\t\tcache.push( sum );\n\t\t\tlast = current;\n\n\t\t}\n\n\t\tthis.cacheArcLengths = cache;\n\n\t\treturn cache; // { sums: cache, sum: sum }; Sum is in the last element.\n\n\t}\n\n\tupdateArcLengths() {\n\n\t\tthis.needsUpdate = true;\n\t\tthis.getLengths();\n\n\t}\n\n\t// Given u ( 0 .. 1 ), get a t to find p. This gives you points which are equidistant\n\n\tgetUtoTmapping( u, distance ) {\n\n\t\tconst arcLengths = this.getLengths();\n\n\t\tlet i = 0;\n\t\tconst il = arcLengths.length;\n\n\t\tlet targetArcLength; // The targeted u distance value to get\n\n\t\tif ( distance ) {\n\n\t\t\ttargetArcLength = distance;\n\n\t\t} else {\n\n\t\t\ttargetArcLength = u * arcLengths[ il - 1 ];\n\n\t\t}\n\n\t\t// binary search for the index with largest value smaller than target u distance\n\n\t\tlet low = 0, high = il - 1, comparison;\n\n\t\twhile ( low <= high ) {\n\n\t\t\ti = 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\n\n\t\t\tcomparison = arcLengths[ i ] - targetArcLength;\n\n\t\t\tif ( comparison < 0 ) {\n\n\t\t\t\tlow = i + 1;\n\n\t\t\t} else if ( comparison > 0 ) {\n\n\t\t\t\thigh = i - 1;\n\n\t\t\t} else {\n\n\t\t\t\thigh = i;\n\t\t\t\tbreak;\n\n\t\t\t\t// DONE\n\n\t\t\t}\n\n\t\t}\n\n\t\ti = high;\n\n\t\tif ( arcLengths[ i ] === targetArcLength ) {\n\n\t\t\treturn i / ( il - 1 );\n\n\t\t}\n\n\t\t// we could get finer grain at lengths, or use simple interpolation between two points\n\n\t\tconst lengthBefore = arcLengths[ i ];\n\t\tconst lengthAfter = arcLengths[ i + 1 ];\n\n\t\tconst segmentLength = lengthAfter - lengthBefore;\n\n\t\t// determine where we are between the 'before' and 'after' points\n\n\t\tconst segmentFraction = ( targetArcLength - lengthBefore ) / segmentLength;\n\n\t\t// add that fractional amount to t\n\n\t\tconst t = ( i + segmentFraction ) / ( il - 1 );\n\n\t\treturn t;\n\n\t}\n\n\t// Returns a unit vector tangent at t\n\t// In case any sub curve does not implement its tangent derivation,\n\t// 2 points a small delta apart will be used to find its gradient\n\t// which seems to give a reasonable approximation\n\n\tgetTangent( t, optionalTarget ) {\n\n\t\tconst delta = 0.0001;\n\t\tlet t1 = t - delta;\n\t\tlet t2 = t + delta;\n\n\t\t// Capping in case of danger\n\n\t\tif ( t1 < 0 ) t1 = 0;\n\t\tif ( t2 > 1 ) t2 = 1;\n\n\t\tconst pt1 = this.getPoint( t1 );\n\t\tconst pt2 = this.getPoint( t2 );\n\n\t\tconst tangent = optionalTarget || ( ( pt1.isVector2 ) ? new Vector2() : new Vector3() );\n\n\t\ttangent.copy( pt2 ).sub( pt1 ).normalize();\n\n\t\treturn tangent;\n\n\t}\n\n\tgetTangentAt( u, optionalTarget ) {\n\n\t\tconst t = this.getUtoTmapping( u );\n\t\treturn this.getTangent( t, optionalTarget );\n\n\t}\n\n\tcomputeFrenetFrames( segments, closed ) {\n\n\t\t// see http://www.cs.indiana.edu/pub/techreports/TR425.pdf\n\n\t\tconst normal = new Vector3();\n\n\t\tconst tangents = [];\n\t\tconst normals = [];\n\t\tconst binormals = [];\n\n\t\tconst vec = new Vector3();\n\t\tconst mat = new Matrix4();\n\n\t\t// compute the tangent vectors for each segment on the curve\n\n\t\tfor ( let i = 0; i <= segments; i ++ ) {\n\n\t\t\tconst u = i / segments;\n\n\t\t\ttangents[ i ] = this.getTangentAt( u, new Vector3() );\n\n\t\t}\n\n\t\t// select an initial normal vector perpendicular to the first tangent vector,\n\t\t// and in the direction of the minimum tangent xyz component\n\n\t\tnormals[ 0 ] = new Vector3();\n\t\tbinormals[ 0 ] = new Vector3();\n\t\tlet min = Number.MAX_VALUE;\n\t\tconst tx = Math.abs( tangents[ 0 ].x );\n\t\tconst ty = Math.abs( tangents[ 0 ].y );\n\t\tconst tz = Math.abs( tangents[ 0 ].z );\n\n\t\tif ( tx <= min ) {\n\n\t\t\tmin = tx;\n\t\t\tnormal.set( 1, 0, 0 );\n\n\t\t}\n\n\t\tif ( ty <= min ) {\n\n\t\t\tmin = ty;\n\t\t\tnormal.set( 0, 1, 0 );\n\n\t\t}\n\n\t\tif ( tz <= min ) {\n\n\t\t\tnormal.set( 0, 0, 1 );\n\n\t\t}\n\n\t\tvec.crossVectors( tangents[ 0 ], normal ).normalize();\n\n\t\tnormals[ 0 ].crossVectors( tangents[ 0 ], vec );\n\t\tbinormals[ 0 ].crossVectors( tangents[ 0 ], normals[ 0 ] );\n\n\n\t\t// compute the slowly-varying normal and binormal vectors for each segment on the curve\n\n\t\tfor ( let i = 1; i <= segments; i ++ ) {\n\n\t\t\tnormals[ i ] = normals[ i - 1 ].clone();\n\n\t\t\tbinormals[ i ] = binormals[ i - 1 ].clone();\n\n\t\t\tvec.crossVectors( tangents[ i - 1 ], tangents[ i ] );\n\n\t\t\tif ( vec.length() > Number.EPSILON ) {\n\n\t\t\t\tvec.normalize();\n\n\t\t\t\tconst theta = Math.acos( clamp( tangents[ i - 1 ].dot( tangents[ i ] ), - 1, 1 ) ); // clamp for floating pt errors\n\n\t\t\t\tnormals[ i ].applyMatrix4( mat.makeRotationAxis( vec, theta ) );\n\n\t\t\t}\n\n\t\t\tbinormals[ i ].crossVectors( tangents[ i ], normals[ i ] );\n\n\t\t}\n\n\t\t// if the curve is closed, postprocess the vectors so the first and last normal vectors are the same\n\n\t\tif ( closed === true ) {\n\n\t\t\tlet theta = Math.acos( clamp( normals[ 0 ].dot( normals[ segments ] ), - 1, 1 ) );\n\t\t\ttheta /= segments;\n\n\t\t\tif ( tangents[ 0 ].dot( vec.crossVectors( normals[ 0 ], normals[ segments ] ) ) > 0 ) {\n\n\t\t\t\ttheta = - theta;\n\n\t\t\t}\n\n\t\t\tfor ( let i = 1; i <= segments; i ++ ) {\n\n\t\t\t\t// twist a little...\n\t\t\t\tnormals[ i ].applyMatrix4( mat.makeRotationAxis( tangents[ i ], theta * i ) );\n\t\t\t\tbinormals[ i ].crossVectors( tangents[ i ], normals[ i ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn {\n\t\t\ttangents: tangents,\n\t\t\tnormals: normals,\n\t\t\tbinormals: binormals\n\t\t};\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.arcLengthDivisions = source.arcLengthDivisions;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = {\n\t\t\tmetadata: {\n\t\t\t\tversion: 4.6,\n\t\t\t\ttype: 'Curve',\n\t\t\t\tgenerator: 'Curve.toJSON'\n\t\t\t}\n\t\t};\n\n\t\tdata.arcLengthDivisions = this.arcLengthDivisions;\n\t\tdata.type = this.type;\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tthis.arcLengthDivisions = json.arcLengthDivisions;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass EllipseCurve extends Curve {\n\n\tconstructor( aX = 0, aY = 0, xRadius = 1, yRadius = 1, aStartAngle = 0, aEndAngle = Math.PI * 2, aClockwise = false, aRotation = 0 ) {\n\n\t\tsuper();\n\n\t\tthis.isEllipseCurve = true;\n\n\t\tthis.type = 'EllipseCurve';\n\n\t\tthis.aX = aX;\n\t\tthis.aY = aY;\n\n\t\tthis.xRadius = xRadius;\n\t\tthis.yRadius = yRadius;\n\n\t\tthis.aStartAngle = aStartAngle;\n\t\tthis.aEndAngle = aEndAngle;\n\n\t\tthis.aClockwise = aClockwise;\n\n\t\tthis.aRotation = aRotation;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector2() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst twoPi = Math.PI * 2;\n\t\tlet deltaAngle = this.aEndAngle - this.aStartAngle;\n\t\tconst samePoints = Math.abs( deltaAngle ) < Number.EPSILON;\n\n\t\t// ensures that deltaAngle is 0 .. 2 PI\n\t\twhile ( deltaAngle < 0 ) deltaAngle += twoPi;\n\t\twhile ( deltaAngle > twoPi ) deltaAngle -= twoPi;\n\n\t\tif ( deltaAngle < Number.EPSILON ) {\n\n\t\t\tif ( samePoints ) {\n\n\t\t\t\tdeltaAngle = 0;\n\n\t\t\t} else {\n\n\t\t\t\tdeltaAngle = twoPi;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( this.aClockwise === true && ! samePoints ) {\n\n\t\t\tif ( deltaAngle === twoPi ) {\n\n\t\t\t\tdeltaAngle = - twoPi;\n\n\t\t\t} else {\n\n\t\t\t\tdeltaAngle = deltaAngle - twoPi;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst angle = this.aStartAngle + t * deltaAngle;\n\t\tlet x = this.aX + this.xRadius * Math.cos( angle );\n\t\tlet y = this.aY + this.yRadius * Math.sin( angle );\n\n\t\tif ( this.aRotation !== 0 ) {\n\n\t\t\tconst cos = Math.cos( this.aRotation );\n\t\t\tconst sin = Math.sin( this.aRotation );\n\n\t\t\tconst tx = x - this.aX;\n\t\t\tconst ty = y - this.aY;\n\n\t\t\t// Rotate the point about the center of the ellipse.\n\t\t\tx = tx * cos - ty * sin + this.aX;\n\t\t\ty = tx * sin + ty * cos + this.aY;\n\n\t\t}\n\n\t\treturn point.set( x, y );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.aX = source.aX;\n\t\tthis.aY = source.aY;\n\n\t\tthis.xRadius = source.xRadius;\n\t\tthis.yRadius = source.yRadius;\n\n\t\tthis.aStartAngle = source.aStartAngle;\n\t\tthis.aEndAngle = source.aEndAngle;\n\n\t\tthis.aClockwise = source.aClockwise;\n\n\t\tthis.aRotation = source.aRotation;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.aX = this.aX;\n\t\tdata.aY = this.aY;\n\n\t\tdata.xRadius = this.xRadius;\n\t\tdata.yRadius = this.yRadius;\n\n\t\tdata.aStartAngle = this.aStartAngle;\n\t\tdata.aEndAngle = this.aEndAngle;\n\n\t\tdata.aClockwise = this.aClockwise;\n\n\t\tdata.aRotation = this.aRotation;\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.aX = json.aX;\n\t\tthis.aY = json.aY;\n\n\t\tthis.xRadius = json.xRadius;\n\t\tthis.yRadius = json.yRadius;\n\n\t\tthis.aStartAngle = json.aStartAngle;\n\t\tthis.aEndAngle = json.aEndAngle;\n\n\t\tthis.aClockwise = json.aClockwise;\n\n\t\tthis.aRotation = json.aRotation;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass ArcCurve extends EllipseCurve {\n\n\tconstructor( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\t\tsuper( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );\n\n\t\tthis.isArcCurve = true;\n\n\t\tthis.type = 'ArcCurve';\n\n\t}\n\n}\n\n/**\n * Centripetal CatmullRom Curve - which is useful for avoiding\n * cusps and self-intersections in non-uniform catmull rom curves.\n * http://www.cemyuksel.com/research/catmullrom_param/catmullrom.pdf\n *\n * curve.type accepts centripetal(default), chordal and catmullrom\n * curve.tension is used for catmullrom which defaults to 0.5\n */\n\n\n/*\nBased on an optimized c++ solution in\n - http://stackoverflow.com/questions/9489736/catmull-rom-curve-with-no-cusps-and-no-self-intersections/\n - http://ideone.com/NoEbVM\n\nThis CubicPoly class could be used for reusing some variables and calculations,\nbut for three.js curve use, it could be possible inlined and flatten into a single function call\nwhich can be placed in CurveUtils.\n*/\n\nfunction CubicPoly() {\n\n\tlet c0 = 0, c1 = 0, c2 = 0, c3 = 0;\n\n\t/*\n\t * Compute coefficients for a cubic polynomial\n\t * p(s) = c0 + c1*s + c2*s^2 + c3*s^3\n\t * such that\n\t * p(0) = x0, p(1) = x1\n\t * and\n\t * p'(0) = t0, p'(1) = t1.\n\t */\n\tfunction init( x0, x1, t0, t1 ) {\n\n\t\tc0 = x0;\n\t\tc1 = t0;\n\t\tc2 = - 3 * x0 + 3 * x1 - 2 * t0 - t1;\n\t\tc3 = 2 * x0 - 2 * x1 + t0 + t1;\n\n\t}\n\n\treturn {\n\n\t\tinitCatmullRom: function ( x0, x1, x2, x3, tension ) {\n\n\t\t\tinit( x1, x2, tension * ( x2 - x0 ), tension * ( x3 - x1 ) );\n\n\t\t},\n\n\t\tinitNonuniformCatmullRom: function ( x0, x1, x2, x3, dt0, dt1, dt2 ) {\n\n\t\t\t// compute tangents when parameterized in [t1,t2]\n\t\t\tlet t1 = ( x1 - x0 ) / dt0 - ( x2 - x0 ) / ( dt0 + dt1 ) + ( x2 - x1 ) / dt1;\n\t\t\tlet t2 = ( x2 - x1 ) / dt1 - ( x3 - x1 ) / ( dt1 + dt2 ) + ( x3 - x2 ) / dt2;\n\n\t\t\t// rescale tangents for parametrization in [0,1]\n\t\t\tt1 *= dt1;\n\t\t\tt2 *= dt1;\n\n\t\t\tinit( x1, x2, t1, t2 );\n\n\t\t},\n\n\t\tcalc: function ( t ) {\n\n\t\t\tconst t2 = t * t;\n\t\t\tconst t3 = t2 * t;\n\t\t\treturn c0 + c1 * t + c2 * t2 + c3 * t3;\n\n\t\t}\n\n\t};\n\n}\n\n//\n\nconst tmp = /*@__PURE__*/ new Vector3();\nconst px = /*@__PURE__*/ new CubicPoly();\nconst py = /*@__PURE__*/ new CubicPoly();\nconst pz = /*@__PURE__*/ new CubicPoly();\n\nclass CatmullRomCurve3 extends Curve {\n\n\tconstructor( points = [], closed = false, curveType = 'centripetal', tension = 0.5 ) {\n\n\t\tsuper();\n\n\t\tthis.isCatmullRomCurve3 = true;\n\n\t\tthis.type = 'CatmullRomCurve3';\n\n\t\tthis.points = points;\n\t\tthis.closed = closed;\n\t\tthis.curveType = curveType;\n\t\tthis.tension = tension;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector3() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst points = this.points;\n\t\tconst l = points.length;\n\n\t\tconst p = ( l - ( this.closed ? 0 : 1 ) ) * t;\n\t\tlet intPoint = Math.floor( p );\n\t\tlet weight = p - intPoint;\n\n\t\tif ( this.closed ) {\n\n\t\t\tintPoint += intPoint > 0 ? 0 : ( Math.floor( Math.abs( intPoint ) / l ) + 1 ) * l;\n\n\t\t} else if ( weight === 0 && intPoint === l - 1 ) {\n\n\t\t\tintPoint = l - 2;\n\t\t\tweight = 1;\n\n\t\t}\n\n\t\tlet p0, p3; // 4 points (p1 & p2 defined below)\n\n\t\tif ( this.closed || intPoint > 0 ) {\n\n\t\t\tp0 = points[ ( intPoint - 1 ) % l ];\n\n\t\t} else {\n\n\t\t\t// extrapolate first point\n\t\t\ttmp.subVectors( points[ 0 ], points[ 1 ] ).add( points[ 0 ] );\n\t\t\tp0 = tmp;\n\n\t\t}\n\n\t\tconst p1 = points[ intPoint % l ];\n\t\tconst p2 = points[ ( intPoint + 1 ) % l ];\n\n\t\tif ( this.closed || intPoint + 2 < l ) {\n\n\t\t\tp3 = points[ ( intPoint + 2 ) % l ];\n\n\t\t} else {\n\n\t\t\t// extrapolate last point\n\t\t\ttmp.subVectors( points[ l - 1 ], points[ l - 2 ] ).add( points[ l - 1 ] );\n\t\t\tp3 = tmp;\n\n\t\t}\n\n\t\tif ( this.curveType === 'centripetal' || this.curveType === 'chordal' ) {\n\n\t\t\t// init Centripetal / Chordal Catmull-Rom\n\t\t\tconst pow = this.curveType === 'chordal' ? 0.5 : 0.25;\n\t\t\tlet dt0 = Math.pow( p0.distanceToSquared( p1 ), pow );\n\t\t\tlet dt1 = Math.pow( p1.distanceToSquared( p2 ), pow );\n\t\t\tlet dt2 = Math.pow( p2.distanceToSquared( p3 ), pow );\n\n\t\t\t// safety check for repeated points\n\t\t\tif ( dt1 < 1e-4 ) dt1 = 1.0;\n\t\t\tif ( dt0 < 1e-4 ) dt0 = dt1;\n\t\t\tif ( dt2 < 1e-4 ) dt2 = dt1;\n\n\t\t\tpx.initNonuniformCatmullRom( p0.x, p1.x, p2.x, p3.x, dt0, dt1, dt2 );\n\t\t\tpy.initNonuniformCatmullRom( p0.y, p1.y, p2.y, p3.y, dt0, dt1, dt2 );\n\t\t\tpz.initNonuniformCatmullRom( p0.z, p1.z, p2.z, p3.z, dt0, dt1, dt2 );\n\n\t\t} else if ( this.curveType === 'catmullrom' ) {\n\n\t\t\tpx.initCatmullRom( p0.x, p1.x, p2.x, p3.x, this.tension );\n\t\t\tpy.initCatmullRom( p0.y, p1.y, p2.y, p3.y, this.tension );\n\t\t\tpz.initCatmullRom( p0.z, p1.z, p2.z, p3.z, this.tension );\n\n\t\t}\n\n\t\tpoint.set(\n\t\t\tpx.calc( weight ),\n\t\t\tpy.calc( weight ),\n\t\t\tpz.calc( weight )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.points = [];\n\n\t\tfor ( let i = 0, l = source.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = source.points[ i ];\n\n\t\t\tthis.points.push( point.clone() );\n\n\t\t}\n\n\t\tthis.closed = source.closed;\n\t\tthis.curveType = source.curveType;\n\t\tthis.tension = source.tension;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.points = [];\n\n\t\tfor ( let i = 0, l = this.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = this.points[ i ];\n\t\t\tdata.points.push( point.toArray() );\n\n\t\t}\n\n\t\tdata.closed = this.closed;\n\t\tdata.curveType = this.curveType;\n\t\tdata.tension = this.tension;\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.points = [];\n\n\t\tfor ( let i = 0, l = json.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = json.points[ i ];\n\t\t\tthis.points.push( new Vector3().fromArray( point ) );\n\n\t\t}\n\n\t\tthis.closed = json.closed;\n\t\tthis.curveType = json.curveType;\n\t\tthis.tension = json.tension;\n\n\t\treturn this;\n\n\t}\n\n}\n\n/**\n * Bezier Curves formulas obtained from\n * https://en.wikipedia.org/wiki/B%C3%A9zier_curve\n */\n\nfunction CatmullRom( t, p0, p1, p2, p3 ) {\n\n\tconst v0 = ( p2 - p0 ) * 0.5;\n\tconst v1 = ( p3 - p1 ) * 0.5;\n\tconst t2 = t * t;\n\tconst t3 = t * t2;\n\treturn ( 2 * p1 - 2 * p2 + v0 + v1 ) * t3 + ( - 3 * p1 + 3 * p2 - 2 * v0 - v1 ) * t2 + v0 * t + p1;\n\n}\n\n//\n\nfunction QuadraticBezierP0( t, p ) {\n\n\tconst k = 1 - t;\n\treturn k * k * p;\n\n}\n\nfunction QuadraticBezierP1( t, p ) {\n\n\treturn 2 * ( 1 - t ) * t * p;\n\n}\n\nfunction QuadraticBezierP2( t, p ) {\n\n\treturn t * t * p;\n\n}\n\nfunction QuadraticBezier( t, p0, p1, p2 ) {\n\n\treturn QuadraticBezierP0( t, p0 ) + QuadraticBezierP1( t, p1 ) +\n\t\tQuadraticBezierP2( t, p2 );\n\n}\n\n//\n\nfunction CubicBezierP0( t, p ) {\n\n\tconst k = 1 - t;\n\treturn k * k * k * p;\n\n}\n\nfunction CubicBezierP1( t, p ) {\n\n\tconst k = 1 - t;\n\treturn 3 * k * k * t * p;\n\n}\n\nfunction CubicBezierP2( t, p ) {\n\n\treturn 3 * ( 1 - t ) * t * t * p;\n\n}\n\nfunction CubicBezierP3( t, p ) {\n\n\treturn t * t * t * p;\n\n}\n\nfunction CubicBezier( t, p0, p1, p2, p3 ) {\n\n\treturn CubicBezierP0( t, p0 ) + CubicBezierP1( t, p1 ) + CubicBezierP2( t, p2 ) +\n\t\tCubicBezierP3( t, p3 );\n\n}\n\nclass CubicBezierCurve extends Curve {\n\n\tconstructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2(), v3 = new Vector2() ) {\n\n\t\tsuper();\n\n\t\tthis.isCubicBezierCurve = true;\n\n\t\tthis.type = 'CubicBezierCurve';\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\t\tthis.v3 = v3;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector2() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;\n\n\t\tpoint.set(\n\t\t\tCubicBezier( t, v0.x, v1.x, v2.x, v3.x ),\n\t\t\tCubicBezier( t, v0.y, v1.y, v2.y, v3.y )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v0.copy( source.v0 );\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\t\tthis.v3.copy( source.v3 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v0 = this.v0.toArray();\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\t\tdata.v3 = this.v3.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v0.fromArray( json.v0 );\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\t\tthis.v3.fromArray( json.v3 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass CubicBezierCurve3 extends Curve {\n\n\tconstructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3(), v3 = new Vector3() ) {\n\n\t\tsuper();\n\n\t\tthis.isCubicBezierCurve3 = true;\n\n\t\tthis.type = 'CubicBezierCurve3';\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\t\tthis.v3 = v3;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector3() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst v0 = this.v0, v1 = this.v1, v2 = this.v2, v3 = this.v3;\n\n\t\tpoint.set(\n\t\t\tCubicBezier( t, v0.x, v1.x, v2.x, v3.x ),\n\t\t\tCubicBezier( t, v0.y, v1.y, v2.y, v3.y ),\n\t\t\tCubicBezier( t, v0.z, v1.z, v2.z, v3.z )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v0.copy( source.v0 );\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\t\tthis.v3.copy( source.v3 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v0 = this.v0.toArray();\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\t\tdata.v3 = this.v3.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v0.fromArray( json.v0 );\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\t\tthis.v3.fromArray( json.v3 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass LineCurve extends Curve {\n\n\tconstructor( v1 = new Vector2(), v2 = new Vector2() ) {\n\n\t\tsuper();\n\n\t\tthis.isLineCurve = true;\n\n\t\tthis.type = 'LineCurve';\n\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector2() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tif ( t === 1 ) {\n\n\t\t\tpoint.copy( this.v2 );\n\n\t\t} else {\n\n\t\t\tpoint.copy( this.v2 ).sub( this.v1 );\n\t\t\tpoint.multiplyScalar( t ).add( this.v1 );\n\n\t\t}\n\n\t\treturn point;\n\n\t}\n\n\t// Line curve is linear, so we can overwrite default getPointAt\n\tgetPointAt( u, optionalTarget ) {\n\n\t\treturn this.getPoint( u, optionalTarget );\n\n\t}\n\n\tgetTangent( t, optionalTarget = new Vector2() ) {\n\n\t\treturn optionalTarget.subVectors( this.v2, this.v1 ).normalize();\n\n\t}\n\n\tgetTangentAt( u, optionalTarget ) {\n\n\t\treturn this.getTangent( u, optionalTarget );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass LineCurve3 extends Curve {\n\n\tconstructor( v1 = new Vector3(), v2 = new Vector3() ) {\n\n\t\tsuper();\n\n\t\tthis.isLineCurve3 = true;\n\n\t\tthis.type = 'LineCurve3';\n\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector3() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tif ( t === 1 ) {\n\n\t\t\tpoint.copy( this.v2 );\n\n\t\t} else {\n\n\t\t\tpoint.copy( this.v2 ).sub( this.v1 );\n\t\t\tpoint.multiplyScalar( t ).add( this.v1 );\n\n\t\t}\n\n\t\treturn point;\n\n\t}\n\n\t// Line curve is linear, so we can overwrite default getPointAt\n\tgetPointAt( u, optionalTarget ) {\n\n\t\treturn this.getPoint( u, optionalTarget );\n\n\t}\n\n\tgetTangent( t, optionalTarget = new Vector3() ) {\n\n\t\treturn optionalTarget.subVectors( this.v2, this.v1 ).normalize();\n\n\t}\n\n\tgetTangentAt( u, optionalTarget ) {\n\n\t\treturn this.getTangent( u, optionalTarget );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass QuadraticBezierCurve extends Curve {\n\n\tconstructor( v0 = new Vector2(), v1 = new Vector2(), v2 = new Vector2() ) {\n\n\t\tsuper();\n\n\t\tthis.isQuadraticBezierCurve = true;\n\n\t\tthis.type = 'QuadraticBezierCurve';\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector2() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst v0 = this.v0, v1 = this.v1, v2 = this.v2;\n\n\t\tpoint.set(\n\t\t\tQuadraticBezier( t, v0.x, v1.x, v2.x ),\n\t\t\tQuadraticBezier( t, v0.y, v1.y, v2.y )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v0.copy( source.v0 );\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v0 = this.v0.toArray();\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v0.fromArray( json.v0 );\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass QuadraticBezierCurve3 extends Curve {\n\n\tconstructor( v0 = new Vector3(), v1 = new Vector3(), v2 = new Vector3() ) {\n\n\t\tsuper();\n\n\t\tthis.isQuadraticBezierCurve3 = true;\n\n\t\tthis.type = 'QuadraticBezierCurve3';\n\n\t\tthis.v0 = v0;\n\t\tthis.v1 = v1;\n\t\tthis.v2 = v2;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector3() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst v0 = this.v0, v1 = this.v1, v2 = this.v2;\n\n\t\tpoint.set(\n\t\t\tQuadraticBezier( t, v0.x, v1.x, v2.x ),\n\t\t\tQuadraticBezier( t, v0.y, v1.y, v2.y ),\n\t\t\tQuadraticBezier( t, v0.z, v1.z, v2.z )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.v0.copy( source.v0 );\n\t\tthis.v1.copy( source.v1 );\n\t\tthis.v2.copy( source.v2 );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.v0 = this.v0.toArray();\n\t\tdata.v1 = this.v1.toArray();\n\t\tdata.v2 = this.v2.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.v0.fromArray( json.v0 );\n\t\tthis.v1.fromArray( json.v1 );\n\t\tthis.v2.fromArray( json.v2 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass SplineCurve extends Curve {\n\n\tconstructor( points = [] ) {\n\n\t\tsuper();\n\n\t\tthis.isSplineCurve = true;\n\n\t\tthis.type = 'SplineCurve';\n\n\t\tthis.points = points;\n\n\t}\n\n\tgetPoint( t, optionalTarget = new Vector2() ) {\n\n\t\tconst point = optionalTarget;\n\n\t\tconst points = this.points;\n\t\tconst p = ( points.length - 1 ) * t;\n\n\t\tconst intPoint = Math.floor( p );\n\t\tconst weight = p - intPoint;\n\n\t\tconst p0 = points[ intPoint === 0 ? intPoint : intPoint - 1 ];\n\t\tconst p1 = points[ intPoint ];\n\t\tconst p2 = points[ intPoint > points.length - 2 ? points.length - 1 : intPoint + 1 ];\n\t\tconst p3 = points[ intPoint > points.length - 3 ? points.length - 1 : intPoint + 2 ];\n\n\t\tpoint.set(\n\t\t\tCatmullRom( weight, p0.x, p1.x, p2.x, p3.x ),\n\t\t\tCatmullRom( weight, p0.y, p1.y, p2.y, p3.y )\n\t\t);\n\n\t\treturn point;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.points = [];\n\n\t\tfor ( let i = 0, l = source.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = source.points[ i ];\n\n\t\t\tthis.points.push( point.clone() );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.points = [];\n\n\t\tfor ( let i = 0, l = this.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = this.points[ i ];\n\t\t\tdata.points.push( point.toArray() );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.points = [];\n\n\t\tfor ( let i = 0, l = json.points.length; i < l; i ++ ) {\n\n\t\t\tconst point = json.points[ i ];\n\t\t\tthis.points.push( new Vector2().fromArray( point ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\nvar Curves = /*#__PURE__*/Object.freeze({\n\t__proto__: null,\n\tArcCurve: ArcCurve,\n\tCatmullRomCurve3: CatmullRomCurve3,\n\tCubicBezierCurve: CubicBezierCurve,\n\tCubicBezierCurve3: CubicBezierCurve3,\n\tEllipseCurve: EllipseCurve,\n\tLineCurve: LineCurve,\n\tLineCurve3: LineCurve3,\n\tQuadraticBezierCurve: QuadraticBezierCurve,\n\tQuadraticBezierCurve3: QuadraticBezierCurve3,\n\tSplineCurve: SplineCurve\n});\n\n/**************************************************************\n *\tCurved Path - a curve path is simply a array of connected\n * curves, but retains the api of a curve\n **************************************************************/\n\nclass CurvePath extends Curve {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.type = 'CurvePath';\n\n\t\tthis.curves = [];\n\t\tthis.autoClose = false; // Automatically closes the path\n\n\t}\n\n\tadd( curve ) {\n\n\t\tthis.curves.push( curve );\n\n\t}\n\n\tclosePath() {\n\n\t\t// Add a line curve if start and end of lines are not connected\n\t\tconst startPoint = this.curves[ 0 ].getPoint( 0 );\n\t\tconst endPoint = this.curves[ this.curves.length - 1 ].getPoint( 1 );\n\n\t\tif ( ! startPoint.equals( endPoint ) ) {\n\n\t\t\tconst lineType = ( startPoint.isVector2 === true ) ? 'LineCurve' : 'LineCurve3';\n\t\t\tthis.curves.push( new Curves[ lineType ]( endPoint, startPoint ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// To get accurate point with reference to\n\t// entire path distance at time t,\n\t// following has to be done:\n\n\t// 1. Length of each sub path have to be known\n\t// 2. Locate and identify type of curve\n\t// 3. Get t for the curve\n\t// 4. Return curve.getPointAt(t')\n\n\tgetPoint( t, optionalTarget ) {\n\n\t\tconst d = t * this.getLength();\n\t\tconst curveLengths = this.getCurveLengths();\n\t\tlet i = 0;\n\n\t\t// To think about boundaries points.\n\n\t\twhile ( i < curveLengths.length ) {\n\n\t\t\tif ( curveLengths[ i ] >= d ) {\n\n\t\t\t\tconst diff = curveLengths[ i ] - d;\n\t\t\t\tconst curve = this.curves[ i ];\n\n\t\t\t\tconst segmentLength = curve.getLength();\n\t\t\t\tconst u = segmentLength === 0 ? 0 : 1 - diff / segmentLength;\n\n\t\t\t\treturn curve.getPointAt( u, optionalTarget );\n\n\t\t\t}\n\n\t\t\ti ++;\n\n\t\t}\n\n\t\treturn null;\n\n\t\t// loop where sum != 0, sum > d , sum+1 1 && ! points[ points.length - 1 ].equals( points[ 0 ] ) ) {\n\n\t\t\tpoints.push( points[ 0 ] );\n\n\t\t}\n\n\t\treturn points;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.curves = [];\n\n\t\tfor ( let i = 0, l = source.curves.length; i < l; i ++ ) {\n\n\t\t\tconst curve = source.curves[ i ];\n\n\t\t\tthis.curves.push( curve.clone() );\n\n\t\t}\n\n\t\tthis.autoClose = source.autoClose;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.autoClose = this.autoClose;\n\t\tdata.curves = [];\n\n\t\tfor ( let i = 0, l = this.curves.length; i < l; i ++ ) {\n\n\t\t\tconst curve = this.curves[ i ];\n\t\t\tdata.curves.push( curve.toJSON() );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.autoClose = json.autoClose;\n\t\tthis.curves = [];\n\n\t\tfor ( let i = 0, l = json.curves.length; i < l; i ++ ) {\n\n\t\t\tconst curve = json.curves[ i ];\n\t\t\tthis.curves.push( new Curves[ curve.type ]().fromJSON( curve ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass Path extends CurvePath {\n\n\tconstructor( points ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'Path';\n\n\t\tthis.currentPoint = new Vector2();\n\n\t\tif ( points ) {\n\n\t\t\tthis.setFromPoints( points );\n\n\t\t}\n\n\t}\n\n\tsetFromPoints( points ) {\n\n\t\tthis.moveTo( points[ 0 ].x, points[ 0 ].y );\n\n\t\tfor ( let i = 1, l = points.length; i < l; i ++ ) {\n\n\t\t\tthis.lineTo( points[ i ].x, points[ i ].y );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tmoveTo( x, y ) {\n\n\t\tthis.currentPoint.set( x, y ); // TODO consider referencing vectors instead of copying?\n\n\t\treturn this;\n\n\t}\n\n\tlineTo( x, y ) {\n\n\t\tconst curve = new LineCurve( this.currentPoint.clone(), new Vector2( x, y ) );\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.set( x, y );\n\n\t\treturn this;\n\n\t}\n\n\tquadraticCurveTo( aCPx, aCPy, aX, aY ) {\n\n\t\tconst curve = new QuadraticBezierCurve(\n\t\t\tthis.currentPoint.clone(),\n\t\t\tnew Vector2( aCPx, aCPy ),\n\t\t\tnew Vector2( aX, aY )\n\t\t);\n\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.set( aX, aY );\n\n\t\treturn this;\n\n\t}\n\n\tbezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {\n\n\t\tconst curve = new CubicBezierCurve(\n\t\t\tthis.currentPoint.clone(),\n\t\t\tnew Vector2( aCP1x, aCP1y ),\n\t\t\tnew Vector2( aCP2x, aCP2y ),\n\t\t\tnew Vector2( aX, aY )\n\t\t);\n\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.set( aX, aY );\n\n\t\treturn this;\n\n\t}\n\n\tsplineThru( pts /*Array of Vector*/ ) {\n\n\t\tconst npts = [ this.currentPoint.clone() ].concat( pts );\n\n\t\tconst curve = new SplineCurve( npts );\n\t\tthis.curves.push( curve );\n\n\t\tthis.currentPoint.copy( pts[ pts.length - 1 ] );\n\n\t\treturn this;\n\n\t}\n\n\tarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\t\tconst x0 = this.currentPoint.x;\n\t\tconst y0 = this.currentPoint.y;\n\n\t\tthis.absarc( aX + x0, aY + y0, aRadius,\n\t\t\taStartAngle, aEndAngle, aClockwise );\n\n\t\treturn this;\n\n\t}\n\n\tabsarc( aX, aY, aRadius, aStartAngle, aEndAngle, aClockwise ) {\n\n\t\tthis.absellipse( aX, aY, aRadius, aRadius, aStartAngle, aEndAngle, aClockwise );\n\n\t\treturn this;\n\n\t}\n\n\tellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {\n\n\t\tconst x0 = this.currentPoint.x;\n\t\tconst y0 = this.currentPoint.y;\n\n\t\tthis.absellipse( aX + x0, aY + y0, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );\n\n\t\treturn this;\n\n\t}\n\n\tabsellipse( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation ) {\n\n\t\tconst curve = new EllipseCurve( aX, aY, xRadius, yRadius, aStartAngle, aEndAngle, aClockwise, aRotation );\n\n\t\tif ( this.curves.length > 0 ) {\n\n\t\t\t// if a previous curve is present, attempt to join\n\t\t\tconst firstPoint = curve.getPoint( 0 );\n\n\t\t\tif ( ! firstPoint.equals( this.currentPoint ) ) {\n\n\t\t\t\tthis.lineTo( firstPoint.x, firstPoint.y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.curves.push( curve );\n\n\t\tconst lastPoint = curve.getPoint( 1 );\n\t\tthis.currentPoint.copy( lastPoint );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.currentPoint.copy( source.currentPoint );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.currentPoint = this.currentPoint.toArray();\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.currentPoint.fromArray( json.currentPoint );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass LatheGeometry extends BufferGeometry {\n\n\tconstructor( points = [ new Vector2( 0, - 0.5 ), new Vector2( 0.5, 0 ), new Vector2( 0, 0.5 ) ], segments = 12, phiStart = 0, phiLength = Math.PI * 2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'LatheGeometry';\n\n\t\tthis.parameters = {\n\t\t\tpoints: points,\n\t\t\tsegments: segments,\n\t\t\tphiStart: phiStart,\n\t\t\tphiLength: phiLength\n\t\t};\n\n\t\tsegments = Math.floor( segments );\n\n\t\t// clamp phiLength so it's in range of [ 0, 2PI ]\n\n\t\tphiLength = clamp( phiLength, 0, Math.PI * 2 );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst uvs = [];\n\t\tconst initNormals = [];\n\t\tconst normals = [];\n\n\t\t// helper variables\n\n\t\tconst inverseSegments = 1.0 / segments;\n\t\tconst vertex = new Vector3();\n\t\tconst uv = new Vector2();\n\t\tconst normal = new Vector3();\n\t\tconst curNormal = new Vector3();\n\t\tconst prevNormal = new Vector3();\n\t\tlet dx = 0;\n\t\tlet dy = 0;\n\n\t\t// pre-compute normals for initial \"meridian\"\n\n\t\tfor ( let j = 0; j <= ( points.length - 1 ); j ++ ) {\n\n\t\t\tswitch ( j ) {\n\n\t\t\t\tcase 0:\t\t\t\t// special handling for 1st vertex on path\n\n\t\t\t\t\tdx = points[ j + 1 ].x - points[ j ].x;\n\t\t\t\t\tdy = points[ j + 1 ].y - points[ j ].y;\n\n\t\t\t\t\tnormal.x = dy * 1.0;\n\t\t\t\t\tnormal.y = - dx;\n\t\t\t\t\tnormal.z = dy * 0.0;\n\n\t\t\t\t\tprevNormal.copy( normal );\n\n\t\t\t\t\tnormal.normalize();\n\n\t\t\t\t\tinitNormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase ( points.length - 1 ):\t// special handling for last Vertex on path\n\n\t\t\t\t\tinitNormals.push( prevNormal.x, prevNormal.y, prevNormal.z );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\t\t\t// default handling for all vertices in between\n\n\t\t\t\t\tdx = points[ j + 1 ].x - points[ j ].x;\n\t\t\t\t\tdy = points[ j + 1 ].y - points[ j ].y;\n\n\t\t\t\t\tnormal.x = dy * 1.0;\n\t\t\t\t\tnormal.y = - dx;\n\t\t\t\t\tnormal.z = dy * 0.0;\n\n\t\t\t\t\tcurNormal.copy( normal );\n\n\t\t\t\t\tnormal.x += prevNormal.x;\n\t\t\t\t\tnormal.y += prevNormal.y;\n\t\t\t\t\tnormal.z += prevNormal.z;\n\n\t\t\t\t\tnormal.normalize();\n\n\t\t\t\t\tinitNormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t\tprevNormal.copy( curNormal );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate vertices, uvs and normals\n\n\t\tfor ( let i = 0; i <= segments; i ++ ) {\n\n\t\t\tconst phi = phiStart + i * inverseSegments * phiLength;\n\n\t\t\tconst sin = Math.sin( phi );\n\t\t\tconst cos = Math.cos( phi );\n\n\t\t\tfor ( let j = 0; j <= ( points.length - 1 ); j ++ ) {\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = points[ j ].x * sin;\n\t\t\t\tvertex.y = points[ j ].y;\n\t\t\t\tvertex.z = points[ j ].x * cos;\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuv.x = i / segments;\n\t\t\t\tuv.y = j / ( points.length - 1 );\n\n\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t\t// normal\n\n\t\t\t\tconst x = initNormals[ 3 * j + 0 ] * sin;\n\t\t\t\tconst y = initNormals[ 3 * j + 1 ];\n\t\t\t\tconst z = initNormals[ 3 * j + 0 ] * cos;\n\n\t\t\t\tnormals.push( x, y, z );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( let i = 0; i < segments; i ++ ) {\n\n\t\t\tfor ( let j = 0; j < ( points.length - 1 ); j ++ ) {\n\n\t\t\t\tconst base = j + i * points.length;\n\n\t\t\t\tconst a = base;\n\t\t\t\tconst b = base + points.length;\n\t\t\t\tconst c = base + points.length + 1;\n\t\t\t\tconst d = base + 1;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( c, d, b );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new LatheGeometry( data.points, data.segments, data.phiStart, data.phiLength );\n\n\t}\n\n}\n\nclass CapsuleGeometry extends LatheGeometry {\n\n\tconstructor( radius = 1, length = 1, capSegments = 4, radialSegments = 8 ) {\n\n\t\tconst path = new Path();\n\t\tpath.absarc( 0, - length / 2, radius, Math.PI * 1.5, 0 );\n\t\tpath.absarc( 0, length / 2, radius, 0, Math.PI * 0.5 );\n\n\t\tsuper( path.getPoints( capSegments ), radialSegments );\n\n\t\tthis.type = 'CapsuleGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tlength: length,\n\t\t\tcapSegments: capSegments,\n\t\t\tradialSegments: radialSegments,\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new CapsuleGeometry( data.radius, data.length, data.capSegments, data.radialSegments );\n\n\t}\n\n}\n\nclass CircleGeometry extends BufferGeometry {\n\n\tconstructor( radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'CircleGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tsegments: segments,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tsegments = Math.max( 3, segments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tconst vertex = new Vector3();\n\t\tconst uv = new Vector2();\n\n\t\t// center point\n\n\t\tvertices.push( 0, 0, 0 );\n\t\tnormals.push( 0, 0, 1 );\n\t\tuvs.push( 0.5, 0.5 );\n\n\t\tfor ( let s = 0, i = 3; s <= segments; s ++, i += 3 ) {\n\n\t\t\tconst segment = thetaStart + s / segments * thetaLength;\n\n\t\t\t// vertex\n\n\t\t\tvertex.x = radius * Math.cos( segment );\n\t\t\tvertex.y = radius * Math.sin( segment );\n\n\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t// normal\n\n\t\t\tnormals.push( 0, 0, 1 );\n\n\t\t\t// uvs\n\n\t\t\tuv.x = ( vertices[ i ] / radius + 1 ) / 2;\n\t\t\tuv.y = ( vertices[ i + 1 ] / radius + 1 ) / 2;\n\n\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( let i = 1; i <= segments; i ++ ) {\n\n\t\t\tindices.push( i, i + 1, 0 );\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new CircleGeometry( data.radius, data.segments, data.thetaStart, data.thetaLength );\n\n\t}\n\n}\n\nclass CylinderGeometry extends BufferGeometry {\n\n\tconstructor( radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'CylinderGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradiusTop: radiusTop,\n\t\t\tradiusBottom: radiusBottom,\n\t\t\theight: height,\n\t\t\tradialSegments: radialSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\topenEnded: openEnded,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tconst scope = this;\n\n\t\tradialSegments = Math.floor( radialSegments );\n\t\theightSegments = Math.floor( heightSegments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tlet index = 0;\n\t\tconst indexArray = [];\n\t\tconst halfHeight = height / 2;\n\t\tlet groupStart = 0;\n\n\t\t// generate geometry\n\n\t\tgenerateTorso();\n\n\t\tif ( openEnded === false ) {\n\n\t\t\tif ( radiusTop > 0 ) generateCap( true );\n\t\t\tif ( radiusBottom > 0 ) generateCap( false );\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\tfunction generateTorso() {\n\n\t\t\tconst normal = new Vector3();\n\t\t\tconst vertex = new Vector3();\n\n\t\t\tlet groupCount = 0;\n\n\t\t\t// this will be used to calculate the normal\n\t\t\tconst slope = ( radiusBottom - radiusTop ) / height;\n\n\t\t\t// generate vertices, normals and uvs\n\n\t\t\tfor ( let y = 0; y <= heightSegments; y ++ ) {\n\n\t\t\t\tconst indexRow = [];\n\n\t\t\t\tconst v = y / heightSegments;\n\n\t\t\t\t// calculate the radius of the current row\n\n\t\t\t\tconst radius = v * ( radiusBottom - radiusTop ) + radiusTop;\n\n\t\t\t\tfor ( let x = 0; x <= radialSegments; x ++ ) {\n\n\t\t\t\t\tconst u = x / radialSegments;\n\n\t\t\t\t\tconst theta = u * thetaLength + thetaStart;\n\n\t\t\t\t\tconst sinTheta = Math.sin( theta );\n\t\t\t\t\tconst cosTheta = Math.cos( theta );\n\n\t\t\t\t\t// vertex\n\n\t\t\t\t\tvertex.x = radius * sinTheta;\n\t\t\t\t\tvertex.y = - v * height + halfHeight;\n\t\t\t\t\tvertex.z = radius * cosTheta;\n\t\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t\t// normal\n\n\t\t\t\t\tnormal.set( sinTheta, slope, cosTheta ).normalize();\n\t\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t\t// uv\n\n\t\t\t\t\tuvs.push( u, 1 - v );\n\n\t\t\t\t\t// save index of vertex in respective row\n\n\t\t\t\t\tindexRow.push( index ++ );\n\n\t\t\t\t}\n\n\t\t\t\t// now save vertices of the row in our index array\n\n\t\t\t\tindexArray.push( indexRow );\n\n\t\t\t}\n\n\t\t\t// generate indices\n\n\t\t\tfor ( let x = 0; x < radialSegments; x ++ ) {\n\n\t\t\t\tfor ( let y = 0; y < heightSegments; y ++ ) {\n\n\t\t\t\t\t// we use the index array to access the correct indices\n\n\t\t\t\t\tconst a = indexArray[ y ][ x ];\n\t\t\t\t\tconst b = indexArray[ y + 1 ][ x ];\n\t\t\t\t\tconst c = indexArray[ y + 1 ][ x + 1 ];\n\t\t\t\t\tconst d = indexArray[ y ][ x + 1 ];\n\n\t\t\t\t\t// faces\n\n\t\t\t\t\tindices.push( a, b, d );\n\t\t\t\t\tindices.push( b, c, d );\n\n\t\t\t\t\t// update group counter\n\n\t\t\t\t\tgroupCount += 6;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\t\tscope.addGroup( groupStart, groupCount, 0 );\n\n\t\t\t// calculate new start value for groups\n\n\t\t\tgroupStart += groupCount;\n\n\t\t}\n\n\t\tfunction generateCap( top ) {\n\n\t\t\t// save the index of the first center vertex\n\t\t\tconst centerIndexStart = index;\n\n\t\t\tconst uv = new Vector2();\n\t\t\tconst vertex = new Vector3();\n\n\t\t\tlet groupCount = 0;\n\n\t\t\tconst radius = ( top === true ) ? radiusTop : radiusBottom;\n\t\t\tconst sign = ( top === true ) ? 1 : - 1;\n\n\t\t\t// first we generate the center vertex data of the cap.\n\t\t\t// because the geometry needs one set of uvs per face,\n\t\t\t// we must generate a center vertex per face/segment\n\n\t\t\tfor ( let x = 1; x <= radialSegments; x ++ ) {\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertices.push( 0, halfHeight * sign, 0 );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormals.push( 0, sign, 0 );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( 0.5, 0.5 );\n\n\t\t\t\t// increase index\n\n\t\t\t\tindex ++;\n\n\t\t\t}\n\n\t\t\t// save the index of the last center vertex\n\t\t\tconst centerIndexEnd = index;\n\n\t\t\t// now we generate the surrounding vertices, normals and uvs\n\n\t\t\tfor ( let x = 0; x <= radialSegments; x ++ ) {\n\n\t\t\t\tconst u = x / radialSegments;\n\t\t\t\tconst theta = u * thetaLength + thetaStart;\n\n\t\t\t\tconst cosTheta = Math.cos( theta );\n\t\t\t\tconst sinTheta = Math.sin( theta );\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = radius * sinTheta;\n\t\t\t\tvertex.y = halfHeight * sign;\n\t\t\t\tvertex.z = radius * cosTheta;\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormals.push( 0, sign, 0 );\n\n\t\t\t\t// uv\n\n\t\t\t\tuv.x = ( cosTheta * 0.5 ) + 0.5;\n\t\t\t\tuv.y = ( sinTheta * 0.5 * sign ) + 0.5;\n\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t\t// increase index\n\n\t\t\t\tindex ++;\n\n\t\t\t}\n\n\t\t\t// generate indices\n\n\t\t\tfor ( let x = 0; x < radialSegments; x ++ ) {\n\n\t\t\t\tconst c = centerIndexStart + x;\n\t\t\t\tconst i = centerIndexEnd + x;\n\n\t\t\t\tif ( top === true ) {\n\n\t\t\t\t\t// face top\n\n\t\t\t\t\tindices.push( i, i + 1, c );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// face bottom\n\n\t\t\t\t\tindices.push( i + 1, i, c );\n\n\t\t\t\t}\n\n\t\t\t\tgroupCount += 3;\n\n\t\t\t}\n\n\t\t\t// add a group to the geometry. this will ensure multi material support\n\n\t\t\tscope.addGroup( groupStart, groupCount, top === true ? 1 : 2 );\n\n\t\t\t// calculate new start value for groups\n\n\t\t\tgroupStart += groupCount;\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new CylinderGeometry( data.radiusTop, data.radiusBottom, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );\n\n\t}\n\n}\n\nclass ConeGeometry extends CylinderGeometry {\n\n\tconstructor( radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2 ) {\n\n\t\tsuper( 0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength );\n\n\t\tthis.type = 'ConeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\theight: height,\n\t\t\tradialSegments: radialSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\topenEnded: openEnded,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new ConeGeometry( data.radius, data.height, data.radialSegments, data.heightSegments, data.openEnded, data.thetaStart, data.thetaLength );\n\n\t}\n\n}\n\nclass PolyhedronGeometry extends BufferGeometry {\n\n\tconstructor( vertices = [], indices = [], radius = 1, detail = 0 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'PolyhedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tvertices: vertices,\n\t\t\tindices: indices,\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t\t// default buffer data\n\n\t\tconst vertexBuffer = [];\n\t\tconst uvBuffer = [];\n\n\t\t// the subdivision creates the vertex buffer data\n\n\t\tsubdivide( detail );\n\n\t\t// all vertices should lie on a conceptual sphere with a given radius\n\n\t\tapplyRadius( radius );\n\n\t\t// finally, create the uv data\n\n\t\tgenerateUVs();\n\n\t\t// build non-indexed geometry\n\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertexBuffer, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( vertexBuffer.slice(), 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvBuffer, 2 ) );\n\n\t\tif ( detail === 0 ) {\n\n\t\t\tthis.computeVertexNormals(); // flat normals\n\n\t\t} else {\n\n\t\t\tthis.normalizeNormals(); // smooth normals\n\n\t\t}\n\n\t\t// helper functions\n\n\t\tfunction subdivide( detail ) {\n\n\t\t\tconst a = new Vector3();\n\t\t\tconst b = new Vector3();\n\t\t\tconst c = new Vector3();\n\n\t\t\t// iterate over all faces and apply a subdivision with the given detail value\n\n\t\t\tfor ( let i = 0; i < indices.length; i += 3 ) {\n\n\t\t\t\t// get the vertices of the face\n\n\t\t\t\tgetVertexByIndex( indices[ i + 0 ], a );\n\t\t\t\tgetVertexByIndex( indices[ i + 1 ], b );\n\t\t\t\tgetVertexByIndex( indices[ i + 2 ], c );\n\n\t\t\t\t// perform subdivision\n\n\t\t\t\tsubdivideFace( a, b, c, detail );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction subdivideFace( a, b, c, detail ) {\n\n\t\t\tconst cols = detail + 1;\n\n\t\t\t// we use this multidimensional array as a data structure for creating the subdivision\n\n\t\t\tconst v = [];\n\n\t\t\t// construct all of the vertices for this subdivision\n\n\t\t\tfor ( let i = 0; i <= cols; i ++ ) {\n\n\t\t\t\tv[ i ] = [];\n\n\t\t\t\tconst aj = a.clone().lerp( c, i / cols );\n\t\t\t\tconst bj = b.clone().lerp( c, i / cols );\n\n\t\t\t\tconst rows = cols - i;\n\n\t\t\t\tfor ( let j = 0; j <= rows; j ++ ) {\n\n\t\t\t\t\tif ( j === 0 && i === cols ) {\n\n\t\t\t\t\t\tv[ i ][ j ] = aj;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tv[ i ][ j ] = aj.clone().lerp( bj, j / rows );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// construct all of the faces\n\n\t\t\tfor ( let i = 0; i < cols; i ++ ) {\n\n\t\t\t\tfor ( let j = 0; j < 2 * ( cols - i ) - 1; j ++ ) {\n\n\t\t\t\t\tconst k = Math.floor( j / 2 );\n\n\t\t\t\t\tif ( j % 2 === 0 ) {\n\n\t\t\t\t\t\tpushVertex( v[ i ][ k + 1 ] );\n\t\t\t\t\t\tpushVertex( v[ i + 1 ][ k ] );\n\t\t\t\t\t\tpushVertex( v[ i ][ k ] );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpushVertex( v[ i ][ k + 1 ] );\n\t\t\t\t\t\tpushVertex( v[ i + 1 ][ k + 1 ] );\n\t\t\t\t\t\tpushVertex( v[ i + 1 ][ k ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction applyRadius( radius ) {\n\n\t\t\tconst vertex = new Vector3();\n\n\t\t\t// iterate over the entire buffer and apply the radius to each vertex\n\n\t\t\tfor ( let i = 0; i < vertexBuffer.length; i += 3 ) {\n\n\t\t\t\tvertex.x = vertexBuffer[ i + 0 ];\n\t\t\t\tvertex.y = vertexBuffer[ i + 1 ];\n\t\t\t\tvertex.z = vertexBuffer[ i + 2 ];\n\n\t\t\t\tvertex.normalize().multiplyScalar( radius );\n\n\t\t\t\tvertexBuffer[ i + 0 ] = vertex.x;\n\t\t\t\tvertexBuffer[ i + 1 ] = vertex.y;\n\t\t\t\tvertexBuffer[ i + 2 ] = vertex.z;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction generateUVs() {\n\n\t\t\tconst vertex = new Vector3();\n\n\t\t\tfor ( let i = 0; i < vertexBuffer.length; i += 3 ) {\n\n\t\t\t\tvertex.x = vertexBuffer[ i + 0 ];\n\t\t\t\tvertex.y = vertexBuffer[ i + 1 ];\n\t\t\t\tvertex.z = vertexBuffer[ i + 2 ];\n\n\t\t\t\tconst u = azimuth( vertex ) / 2 / Math.PI + 0.5;\n\t\t\t\tconst v = inclination( vertex ) / Math.PI + 0.5;\n\t\t\t\tuvBuffer.push( u, 1 - v );\n\n\t\t\t}\n\n\t\t\tcorrectUVs();\n\n\t\t\tcorrectSeam();\n\n\t\t}\n\n\t\tfunction correctSeam() {\n\n\t\t\t// handle case when face straddles the seam, see #3269\n\n\t\t\tfor ( let i = 0; i < uvBuffer.length; i += 6 ) {\n\n\t\t\t\t// uv data of a single face\n\n\t\t\t\tconst x0 = uvBuffer[ i + 0 ];\n\t\t\t\tconst x1 = uvBuffer[ i + 2 ];\n\t\t\t\tconst x2 = uvBuffer[ i + 4 ];\n\n\t\t\t\tconst max = Math.max( x0, x1, x2 );\n\t\t\t\tconst min = Math.min( x0, x1, x2 );\n\n\t\t\t\t// 0.9 is somewhat arbitrary\n\n\t\t\t\tif ( max > 0.9 && min < 0.1 ) {\n\n\t\t\t\t\tif ( x0 < 0.2 ) uvBuffer[ i + 0 ] += 1;\n\t\t\t\t\tif ( x1 < 0.2 ) uvBuffer[ i + 2 ] += 1;\n\t\t\t\t\tif ( x2 < 0.2 ) uvBuffer[ i + 4 ] += 1;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction pushVertex( vertex ) {\n\n\t\t\tvertexBuffer.push( vertex.x, vertex.y, vertex.z );\n\n\t\t}\n\n\t\tfunction getVertexByIndex( index, vertex ) {\n\n\t\t\tconst stride = index * 3;\n\n\t\t\tvertex.x = vertices[ stride + 0 ];\n\t\t\tvertex.y = vertices[ stride + 1 ];\n\t\t\tvertex.z = vertices[ stride + 2 ];\n\n\t\t}\n\n\t\tfunction correctUVs() {\n\n\t\t\tconst a = new Vector3();\n\t\t\tconst b = new Vector3();\n\t\t\tconst c = new Vector3();\n\n\t\t\tconst centroid = new Vector3();\n\n\t\t\tconst uvA = new Vector2();\n\t\t\tconst uvB = new Vector2();\n\t\t\tconst uvC = new Vector2();\n\n\t\t\tfor ( let i = 0, j = 0; i < vertexBuffer.length; i += 9, j += 6 ) {\n\n\t\t\t\ta.set( vertexBuffer[ i + 0 ], vertexBuffer[ i + 1 ], vertexBuffer[ i + 2 ] );\n\t\t\t\tb.set( vertexBuffer[ i + 3 ], vertexBuffer[ i + 4 ], vertexBuffer[ i + 5 ] );\n\t\t\t\tc.set( vertexBuffer[ i + 6 ], vertexBuffer[ i + 7 ], vertexBuffer[ i + 8 ] );\n\n\t\t\t\tuvA.set( uvBuffer[ j + 0 ], uvBuffer[ j + 1 ] );\n\t\t\t\tuvB.set( uvBuffer[ j + 2 ], uvBuffer[ j + 3 ] );\n\t\t\t\tuvC.set( uvBuffer[ j + 4 ], uvBuffer[ j + 5 ] );\n\n\t\t\t\tcentroid.copy( a ).add( b ).add( c ).divideScalar( 3 );\n\n\t\t\t\tconst azi = azimuth( centroid );\n\n\t\t\t\tcorrectUV( uvA, j + 0, a, azi );\n\t\t\t\tcorrectUV( uvB, j + 2, b, azi );\n\t\t\t\tcorrectUV( uvC, j + 4, c, azi );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction correctUV( uv, stride, vector, azimuth ) {\n\n\t\t\tif ( ( azimuth < 0 ) && ( uv.x === 1 ) ) {\n\n\t\t\t\tuvBuffer[ stride ] = uv.x - 1;\n\n\t\t\t}\n\n\t\t\tif ( ( vector.x === 0 ) && ( vector.z === 0 ) ) {\n\n\t\t\t\tuvBuffer[ stride ] = azimuth / 2 / Math.PI + 0.5;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Angle around the Y axis, counter-clockwise when looking from above.\n\n\t\tfunction azimuth( vector ) {\n\n\t\t\treturn Math.atan2( vector.z, - vector.x );\n\n\t\t}\n\n\n\t\t// Angle above the XZ plane.\n\n\t\tfunction inclination( vector ) {\n\n\t\t\treturn Math.atan2( - vector.y, Math.sqrt( ( vector.x * vector.x ) + ( vector.z * vector.z ) ) );\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new PolyhedronGeometry( data.vertices, data.indices, data.radius, data.details );\n\n\t}\n\n}\n\nclass DodecahedronGeometry extends PolyhedronGeometry {\n\n\tconstructor( radius = 1, detail = 0 ) {\n\n\t\tconst t = ( 1 + Math.sqrt( 5 ) ) / 2;\n\t\tconst r = 1 / t;\n\n\t\tconst vertices = [\n\n\t\t\t// (±1, ±1, ±1)\n\t\t\t- 1, - 1, - 1,\t- 1, - 1, 1,\n\t\t\t- 1, 1, - 1, - 1, 1, 1,\n\t\t\t1, - 1, - 1, 1, - 1, 1,\n\t\t\t1, 1, - 1, 1, 1, 1,\n\n\t\t\t// (0, ±1/φ, ±φ)\n\t\t\t0, - r, - t, 0, - r, t,\n\t\t\t0, r, - t, 0, r, t,\n\n\t\t\t// (±1/φ, ±φ, 0)\n\t\t\t- r, - t, 0, - r, t, 0,\n\t\t\tr, - t, 0, r, t, 0,\n\n\t\t\t// (±φ, 0, ±1/φ)\n\t\t\t- t, 0, - r, t, 0, - r,\n\t\t\t- t, 0, r, t, 0, r\n\t\t];\n\n\t\tconst indices = [\n\t\t\t3, 11, 7, \t3, 7, 15, \t3, 15, 13,\n\t\t\t7, 19, 17, \t7, 17, 6, \t7, 6, 15,\n\t\t\t17, 4, 8, \t17, 8, 10, \t17, 10, 6,\n\t\t\t8, 0, 16, \t8, 16, 2, \t8, 2, 10,\n\t\t\t0, 12, 1, \t0, 1, 18, \t0, 18, 16,\n\t\t\t6, 10, 2, \t6, 2, 13, \t6, 13, 15,\n\t\t\t2, 16, 18, \t2, 18, 3, \t2, 3, 13,\n\t\t\t18, 1, 9, \t18, 9, 11, \t18, 11, 3,\n\t\t\t4, 14, 12, \t4, 12, 0, \t4, 0, 8,\n\t\t\t11, 9, 5, \t11, 5, 19, \t11, 19, 7,\n\t\t\t19, 5, 14, \t19, 14, 4, \t19, 4, 17,\n\t\t\t1, 12, 14, \t1, 14, 5, \t1, 5, 9\n\t\t];\n\n\t\tsuper( vertices, indices, radius, detail );\n\n\t\tthis.type = 'DodecahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new DodecahedronGeometry( data.radius, data.detail );\n\n\t}\n\n}\n\nconst _v0 = /*@__PURE__*/ new Vector3();\nconst _v1$1 = /*@__PURE__*/ new Vector3();\nconst _normal = /*@__PURE__*/ new Vector3();\nconst _triangle = /*@__PURE__*/ new Triangle();\n\nclass EdgesGeometry extends BufferGeometry {\n\n\tconstructor( geometry = null, thresholdAngle = 1 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'EdgesGeometry';\n\n\t\tthis.parameters = {\n\t\t\tgeometry: geometry,\n\t\t\tthresholdAngle: thresholdAngle\n\t\t};\n\n\t\tif ( geometry !== null ) {\n\n\t\t\tconst precisionPoints = 4;\n\t\t\tconst precision = Math.pow( 10, precisionPoints );\n\t\t\tconst thresholdDot = Math.cos( DEG2RAD * thresholdAngle );\n\n\t\t\tconst indexAttr = geometry.getIndex();\n\t\t\tconst positionAttr = geometry.getAttribute( 'position' );\n\t\t\tconst indexCount = indexAttr ? indexAttr.count : positionAttr.count;\n\n\t\t\tconst indexArr = [ 0, 0, 0 ];\n\t\t\tconst vertKeys = [ 'a', 'b', 'c' ];\n\t\t\tconst hashes = new Array( 3 );\n\n\t\t\tconst edgeData = {};\n\t\t\tconst vertices = [];\n\t\t\tfor ( let i = 0; i < indexCount; i += 3 ) {\n\n\t\t\t\tif ( indexAttr ) {\n\n\t\t\t\t\tindexArr[ 0 ] = indexAttr.getX( i );\n\t\t\t\t\tindexArr[ 1 ] = indexAttr.getX( i + 1 );\n\t\t\t\t\tindexArr[ 2 ] = indexAttr.getX( i + 2 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tindexArr[ 0 ] = i;\n\t\t\t\t\tindexArr[ 1 ] = i + 1;\n\t\t\t\t\tindexArr[ 2 ] = i + 2;\n\n\t\t\t\t}\n\n\t\t\t\tconst { a, b, c } = _triangle;\n\t\t\t\ta.fromBufferAttribute( positionAttr, indexArr[ 0 ] );\n\t\t\t\tb.fromBufferAttribute( positionAttr, indexArr[ 1 ] );\n\t\t\t\tc.fromBufferAttribute( positionAttr, indexArr[ 2 ] );\n\t\t\t\t_triangle.getNormal( _normal );\n\n\t\t\t\t// create hashes for the edge from the vertices\n\t\t\t\thashes[ 0 ] = `${ Math.round( a.x * precision ) },${ Math.round( a.y * precision ) },${ Math.round( a.z * precision ) }`;\n\t\t\t\thashes[ 1 ] = `${ Math.round( b.x * precision ) },${ Math.round( b.y * precision ) },${ Math.round( b.z * precision ) }`;\n\t\t\t\thashes[ 2 ] = `${ Math.round( c.x * precision ) },${ Math.round( c.y * precision ) },${ Math.round( c.z * precision ) }`;\n\n\t\t\t\t// skip degenerate triangles\n\t\t\t\tif ( hashes[ 0 ] === hashes[ 1 ] || hashes[ 1 ] === hashes[ 2 ] || hashes[ 2 ] === hashes[ 0 ] ) {\n\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\t// iterate over every edge\n\t\t\t\tfor ( let j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t// get the first and next vertex making up the edge\n\t\t\t\t\tconst jNext = ( j + 1 ) % 3;\n\t\t\t\t\tconst vecHash0 = hashes[ j ];\n\t\t\t\t\tconst vecHash1 = hashes[ jNext ];\n\t\t\t\t\tconst v0 = _triangle[ vertKeys[ j ] ];\n\t\t\t\t\tconst v1 = _triangle[ vertKeys[ jNext ] ];\n\n\t\t\t\t\tconst hash = `${ vecHash0 }_${ vecHash1 }`;\n\t\t\t\t\tconst reverseHash = `${ vecHash1 }_${ vecHash0 }`;\n\n\t\t\t\t\tif ( reverseHash in edgeData && edgeData[ reverseHash ] ) {\n\n\t\t\t\t\t\t// if we found a sibling edge add it into the vertex array if\n\t\t\t\t\t\t// it meets the angle threshold and delete the edge from the map.\n\t\t\t\t\t\tif ( _normal.dot( edgeData[ reverseHash ].normal ) <= thresholdDot ) {\n\n\t\t\t\t\t\t\tvertices.push( v0.x, v0.y, v0.z );\n\t\t\t\t\t\t\tvertices.push( v1.x, v1.y, v1.z );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tedgeData[ reverseHash ] = null;\n\n\t\t\t\t\t} else if ( ! ( hash in edgeData ) ) {\n\n\t\t\t\t\t\t// if we've already got an edge here then skip adding a new one\n\t\t\t\t\t\tedgeData[ hash ] = {\n\n\t\t\t\t\t\t\tindex0: indexArr[ j ],\n\t\t\t\t\t\t\tindex1: indexArr[ jNext ],\n\t\t\t\t\t\t\tnormal: _normal.clone(),\n\n\t\t\t\t\t\t};\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// iterate over all remaining, unmatched edges and add them to the vertex array\n\t\t\tfor ( const key in edgeData ) {\n\n\t\t\t\tif ( edgeData[ key ] ) {\n\n\t\t\t\t\tconst { index0, index1 } = edgeData[ key ];\n\t\t\t\t\t_v0.fromBufferAttribute( positionAttr, index0 );\n\t\t\t\t\t_v1$1.fromBufferAttribute( positionAttr, index1 );\n\n\t\t\t\t\tvertices.push( _v0.x, _v0.y, _v0.z );\n\t\t\t\t\tvertices.push( _v1$1.x, _v1$1.y, _v1$1.z );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass Shape extends Path {\n\n\tconstructor( points ) {\n\n\t\tsuper( points );\n\n\t\tthis.uuid = generateUUID();\n\n\t\tthis.type = 'Shape';\n\n\t\tthis.holes = [];\n\n\t}\n\n\tgetPointsHoles( divisions ) {\n\n\t\tconst holesPts = [];\n\n\t\tfor ( let i = 0, l = this.holes.length; i < l; i ++ ) {\n\n\t\t\tholesPts[ i ] = this.holes[ i ].getPoints( divisions );\n\n\t\t}\n\n\t\treturn holesPts;\n\n\t}\n\n\t// get points of shape and holes (keypoints based on segments parameter)\n\n\textractPoints( divisions ) {\n\n\t\treturn {\n\n\t\t\tshape: this.getPoints( divisions ),\n\t\t\tholes: this.getPointsHoles( divisions )\n\n\t\t};\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.holes = [];\n\n\t\tfor ( let i = 0, l = source.holes.length; i < l; i ++ ) {\n\n\t\t\tconst hole = source.holes[ i ];\n\n\t\t\tthis.holes.push( hole.clone() );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.uuid = this.uuid;\n\t\tdata.holes = [];\n\n\t\tfor ( let i = 0, l = this.holes.length; i < l; i ++ ) {\n\n\t\t\tconst hole = this.holes[ i ];\n\t\t\tdata.holes.push( hole.toJSON() );\n\n\t\t}\n\n\t\treturn data;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tsuper.fromJSON( json );\n\n\t\tthis.uuid = json.uuid;\n\t\tthis.holes = [];\n\n\t\tfor ( let i = 0, l = json.holes.length; i < l; i ++ ) {\n\n\t\t\tconst hole = json.holes[ i ];\n\t\t\tthis.holes.push( new Path().fromJSON( hole ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n}\n\n/**\n * Port from https://github.com/mapbox/earcut (v2.2.4)\n */\n\nconst Earcut = {\n\n\ttriangulate: function ( data, holeIndices, dim = 2 ) {\n\n\t\tconst hasHoles = holeIndices && holeIndices.length;\n\t\tconst outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;\n\t\tlet outerNode = linkedList( data, 0, outerLen, dim, true );\n\t\tconst triangles = [];\n\n\t\tif ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;\n\n\t\tlet minX, minY, maxX, maxY, x, y, invSize;\n\n\t\tif ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim );\n\n\t\t// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox\n\t\tif ( data.length > 80 * dim ) {\n\n\t\t\tminX = maxX = data[ 0 ];\n\t\t\tminY = maxY = data[ 1 ];\n\n\t\t\tfor ( let i = dim; i < outerLen; i += dim ) {\n\n\t\t\t\tx = data[ i ];\n\t\t\t\ty = data[ i + 1 ];\n\t\t\t\tif ( x < minX ) minX = x;\n\t\t\t\tif ( y < minY ) minY = y;\n\t\t\t\tif ( x > maxX ) maxX = x;\n\t\t\t\tif ( y > maxY ) maxY = y;\n\n\t\t\t}\n\n\t\t\t// minX, minY and invSize are later used to transform coords into integers for z-order calculation\n\t\t\tinvSize = Math.max( maxX - minX, maxY - minY );\n\t\t\tinvSize = invSize !== 0 ? 32767 / invSize : 0;\n\n\t\t}\n\n\t\tearcutLinked( outerNode, triangles, dim, minX, minY, invSize, 0 );\n\n\t\treturn triangles;\n\n\t}\n\n};\n\n// create a circular doubly linked list from polygon points in the specified winding order\nfunction linkedList( data, start, end, dim, clockwise ) {\n\n\tlet i, last;\n\n\tif ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) {\n\n\t\tfor ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );\n\n\t} else {\n\n\t\tfor ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );\n\n\t}\n\n\tif ( last && equals( last, last.next ) ) {\n\n\t\tremoveNode( last );\n\t\tlast = last.next;\n\n\t}\n\n\treturn last;\n\n}\n\n// eliminate colinear or duplicate points\nfunction filterPoints( start, end ) {\n\n\tif ( ! start ) return start;\n\tif ( ! end ) end = start;\n\n\tlet p = start,\n\t\tagain;\n\tdo {\n\n\t\tagain = false;\n\n\t\tif ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) {\n\n\t\t\tremoveNode( p );\n\t\t\tp = end = p.prev;\n\t\t\tif ( p === p.next ) break;\n\t\t\tagain = true;\n\n\t\t} else {\n\n\t\t\tp = p.next;\n\n\t\t}\n\n\t} while ( again || p !== end );\n\n\treturn end;\n\n}\n\n// main ear slicing loop which triangulates a polygon (given as a linked list)\nfunction earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {\n\n\tif ( ! ear ) return;\n\n\t// interlink polygon nodes in z-order\n\tif ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize );\n\n\tlet stop = ear,\n\t\tprev, next;\n\n\t// iterate through ears, slicing them one by one\n\twhile ( ear.prev !== ear.next ) {\n\n\t\tprev = ear.prev;\n\t\tnext = ear.next;\n\n\t\tif ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) {\n\n\t\t\t// cut off the triangle\n\t\t\ttriangles.push( prev.i / dim | 0 );\n\t\t\ttriangles.push( ear.i / dim | 0 );\n\t\t\ttriangles.push( next.i / dim | 0 );\n\n\t\t\tremoveNode( ear );\n\n\t\t\t// skipping the next vertex leads to less sliver triangles\n\t\t\tear = next.next;\n\t\t\tstop = next.next;\n\n\t\t\tcontinue;\n\n\t\t}\n\n\t\tear = next;\n\n\t\t// if we looped through the whole remaining polygon and can't find any more ears\n\t\tif ( ear === stop ) {\n\n\t\t\t// try filtering points and slicing again\n\t\t\tif ( ! pass ) {\n\n\t\t\t\tearcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 );\n\n\t\t\t\t// if this didn't work, try curing all small self-intersections locally\n\n\t\t\t} else if ( pass === 1 ) {\n\n\t\t\t\tear = cureLocalIntersections( filterPoints( ear ), triangles, dim );\n\t\t\t\tearcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );\n\n\t\t\t\t// as a last resort, try splitting the remaining polygon into two\n\n\t\t\t} else if ( pass === 2 ) {\n\n\t\t\t\tsplitEarcut( ear, triangles, dim, minX, minY, invSize );\n\n\t\t\t}\n\n\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n}\n\n// check whether a polygon node forms a valid ear with adjacent nodes\nfunction isEar( ear ) {\n\n\tconst a = ear.prev,\n\t\tb = ear,\n\t\tc = ear.next;\n\n\tif ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear\n\n\t// now make sure we don't have other points inside the potential ear\n\tconst ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;\n\n\t// triangle bbox; min & max are calculated like this for speed\n\tconst x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),\n\t\ty0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),\n\t\tx1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),\n\t\ty1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );\n\n\tlet p = c.next;\n\twhile ( p !== a ) {\n\n\t\tif ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) &&\n\t\t\tarea( p.prev, p, p.next ) >= 0 ) return false;\n\t\tp = p.next;\n\n\t}\n\n\treturn true;\n\n}\n\nfunction isEarHashed( ear, minX, minY, invSize ) {\n\n\tconst a = ear.prev,\n\t\tb = ear,\n\t\tc = ear.next;\n\n\tif ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear\n\n\tconst ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;\n\n\t// triangle bbox; min & max are calculated like this for speed\n\tconst x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),\n\t\ty0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),\n\t\tx1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),\n\t\ty1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );\n\n\t// z-order range for the current triangle bbox;\n\tconst minZ = zOrder( x0, y0, minX, minY, invSize ),\n\t\tmaxZ = zOrder( x1, y1, minX, minY, invSize );\n\n\tlet p = ear.prevZ,\n\t\tn = ear.nextZ;\n\n\t// look for points inside the triangle in both directions\n\twhile ( p && p.z >= minZ && n && n.z <= maxZ ) {\n\n\t\tif ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;\n\t\tp = p.prevZ;\n\n\t\tif ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;\n\t\tn = n.nextZ;\n\n\t}\n\n\t// look for remaining points in decreasing z-order\n\twhile ( p && p.z >= minZ ) {\n\n\t\tif ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;\n\t\tp = p.prevZ;\n\n\t}\n\n\t// look for remaining points in increasing z-order\n\twhile ( n && n.z <= maxZ ) {\n\n\t\tif ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;\n\t\tn = n.nextZ;\n\n\t}\n\n\treturn true;\n\n}\n\n// go through all polygon nodes and cure small local self-intersections\nfunction cureLocalIntersections( start, triangles, dim ) {\n\n\tlet p = start;\n\tdo {\n\n\t\tconst a = p.prev,\n\t\t\tb = p.next.next;\n\n\t\tif ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {\n\n\t\t\ttriangles.push( a.i / dim | 0 );\n\t\t\ttriangles.push( p.i / dim | 0 );\n\t\t\ttriangles.push( b.i / dim | 0 );\n\n\t\t\t// remove two nodes involved\n\t\t\tremoveNode( p );\n\t\t\tremoveNode( p.next );\n\n\t\t\tp = start = b;\n\n\t\t}\n\n\t\tp = p.next;\n\n\t} while ( p !== start );\n\n\treturn filterPoints( p );\n\n}\n\n// try splitting polygon into two and triangulate them independently\nfunction splitEarcut( start, triangles, dim, minX, minY, invSize ) {\n\n\t// look for a valid diagonal that divides the polygon into two\n\tlet a = start;\n\tdo {\n\n\t\tlet b = a.next.next;\n\t\twhile ( b !== a.prev ) {\n\n\t\t\tif ( a.i !== b.i && isValidDiagonal( a, b ) ) {\n\n\t\t\t\t// split the polygon in two by the diagonal\n\t\t\t\tlet c = splitPolygon( a, b );\n\n\t\t\t\t// filter colinear points around the cuts\n\t\t\t\ta = filterPoints( a, a.next );\n\t\t\t\tc = filterPoints( c, c.next );\n\n\t\t\t\t// run earcut on each half\n\t\t\t\tearcutLinked( a, triangles, dim, minX, minY, invSize, 0 );\n\t\t\t\tearcutLinked( c, triangles, dim, minX, minY, invSize, 0 );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tb = b.next;\n\n\t\t}\n\n\t\ta = a.next;\n\n\t} while ( a !== start );\n\n}\n\n// link every hole into the outer loop, producing a single-ring polygon without holes\nfunction eliminateHoles( data, holeIndices, outerNode, dim ) {\n\n\tconst queue = [];\n\tlet i, len, start, end, list;\n\n\tfor ( i = 0, len = holeIndices.length; i < len; i ++ ) {\n\n\t\tstart = holeIndices[ i ] * dim;\n\t\tend = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;\n\t\tlist = linkedList( data, start, end, dim, false );\n\t\tif ( list === list.next ) list.steiner = true;\n\t\tqueue.push( getLeftmost( list ) );\n\n\t}\n\n\tqueue.sort( compareX );\n\n\t// process holes from left to right\n\tfor ( i = 0; i < queue.length; i ++ ) {\n\n\t\touterNode = eliminateHole( queue[ i ], outerNode );\n\n\t}\n\n\treturn outerNode;\n\n}\n\nfunction compareX( a, b ) {\n\n\treturn a.x - b.x;\n\n}\n\n// find a bridge between vertices that connects hole with an outer ring and link it\nfunction eliminateHole( hole, outerNode ) {\n\n\tconst bridge = findHoleBridge( hole, outerNode );\n\tif ( ! bridge ) {\n\n\t\treturn outerNode;\n\n\t}\n\n\tconst bridgeReverse = splitPolygon( bridge, hole );\n\n\t// filter collinear points around the cuts\n\tfilterPoints( bridgeReverse, bridgeReverse.next );\n\treturn filterPoints( bridge, bridge.next );\n\n}\n\n// David Eberly's algorithm for finding a bridge between hole and outer polygon\nfunction findHoleBridge( hole, outerNode ) {\n\n\tlet p = outerNode,\n\t\tqx = - Infinity,\n\t\tm;\n\n\tconst hx = hole.x, hy = hole.y;\n\n\t// find a segment intersected by a ray from the hole's leftmost point to the left;\n\t// segment's endpoint with lesser x will be potential connection point\n\tdo {\n\n\t\tif ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {\n\n\t\t\tconst x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );\n\t\t\tif ( x <= hx && x > qx ) {\n\n\t\t\t\tqx = x;\n\t\t\t\tm = p.x < p.next.x ? p : p.next;\n\t\t\t\tif ( x === hx ) return m; // hole touches outer segment; pick leftmost endpoint\n\n\t\t\t}\n\n\t\t}\n\n\t\tp = p.next;\n\n\t} while ( p !== outerNode );\n\n\tif ( ! m ) return null;\n\n\t// look for points inside the triangle of hole point, segment intersection and endpoint;\n\t// if there are no points found, we have a valid connection;\n\t// otherwise choose the point of the minimum angle with the ray as connection point\n\n\tconst stop = m,\n\t\tmx = m.x,\n\t\tmy = m.y;\n\tlet tanMin = Infinity, tan;\n\n\tp = m;\n\n\tdo {\n\n\t\tif ( hx >= p.x && p.x >= mx && hx !== p.x &&\n\t\t\t\tpointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {\n\n\t\t\ttan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential\n\n\t\t\tif ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) {\n\n\t\t\t\tm = p;\n\t\t\t\ttanMin = tan;\n\n\t\t\t}\n\n\t\t}\n\n\t\tp = p.next;\n\n\t} while ( p !== stop );\n\n\treturn m;\n\n}\n\n// whether sector in vertex m contains sector in vertex p in the same coordinates\nfunction sectorContainsSector( m, p ) {\n\n\treturn area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;\n\n}\n\n// interlink polygon nodes in z-order\nfunction indexCurve( start, minX, minY, invSize ) {\n\n\tlet p = start;\n\tdo {\n\n\t\tif ( p.z === 0 ) p.z = zOrder( p.x, p.y, minX, minY, invSize );\n\t\tp.prevZ = p.prev;\n\t\tp.nextZ = p.next;\n\t\tp = p.next;\n\n\t} while ( p !== start );\n\n\tp.prevZ.nextZ = null;\n\tp.prevZ = null;\n\n\tsortLinked( p );\n\n}\n\n// Simon Tatham's linked list merge sort algorithm\n// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html\nfunction sortLinked( list ) {\n\n\tlet i, p, q, e, tail, numMerges, pSize, qSize,\n\t\tinSize = 1;\n\n\tdo {\n\n\t\tp = list;\n\t\tlist = null;\n\t\ttail = null;\n\t\tnumMerges = 0;\n\n\t\twhile ( p ) {\n\n\t\t\tnumMerges ++;\n\t\t\tq = p;\n\t\t\tpSize = 0;\n\t\t\tfor ( i = 0; i < inSize; i ++ ) {\n\n\t\t\t\tpSize ++;\n\t\t\t\tq = q.nextZ;\n\t\t\t\tif ( ! q ) break;\n\n\t\t\t}\n\n\t\t\tqSize = inSize;\n\n\t\t\twhile ( pSize > 0 || ( qSize > 0 && q ) ) {\n\n\t\t\t\tif ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {\n\n\t\t\t\t\te = p;\n\t\t\t\t\tp = p.nextZ;\n\t\t\t\t\tpSize --;\n\n\t\t\t\t} else {\n\n\t\t\t\t\te = q;\n\t\t\t\t\tq = q.nextZ;\n\t\t\t\t\tqSize --;\n\n\t\t\t\t}\n\n\t\t\t\tif ( tail ) tail.nextZ = e;\n\t\t\t\telse list = e;\n\n\t\t\t\te.prevZ = tail;\n\t\t\t\ttail = e;\n\n\t\t\t}\n\n\t\t\tp = q;\n\n\t\t}\n\n\t\ttail.nextZ = null;\n\t\tinSize *= 2;\n\n\t} while ( numMerges > 1 );\n\n\treturn list;\n\n}\n\n// z-order of a point given coords and inverse of the longer side of data bbox\nfunction zOrder( x, y, minX, minY, invSize ) {\n\n\t// coords are transformed into non-negative 15-bit integer range\n\tx = ( x - minX ) * invSize | 0;\n\ty = ( y - minY ) * invSize | 0;\n\n\tx = ( x | ( x << 8 ) ) & 0x00FF00FF;\n\tx = ( x | ( x << 4 ) ) & 0x0F0F0F0F;\n\tx = ( x | ( x << 2 ) ) & 0x33333333;\n\tx = ( x | ( x << 1 ) ) & 0x55555555;\n\n\ty = ( y | ( y << 8 ) ) & 0x00FF00FF;\n\ty = ( y | ( y << 4 ) ) & 0x0F0F0F0F;\n\ty = ( y | ( y << 2 ) ) & 0x33333333;\n\ty = ( y | ( y << 1 ) ) & 0x55555555;\n\n\treturn x | ( y << 1 );\n\n}\n\n// find the leftmost node of a polygon ring\nfunction getLeftmost( start ) {\n\n\tlet p = start,\n\t\tleftmost = start;\n\tdo {\n\n\t\tif ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;\n\t\tp = p.next;\n\n\t} while ( p !== start );\n\n\treturn leftmost;\n\n}\n\n// check if a point lies within a convex triangle\nfunction pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {\n\n\treturn ( cx - px ) * ( ay - py ) >= ( ax - px ) * ( cy - py ) &&\n ( ax - px ) * ( by - py ) >= ( bx - px ) * ( ay - py ) &&\n ( bx - px ) * ( cy - py ) >= ( cx - px ) * ( by - py );\n\n}\n\n// check if a diagonal between two polygon nodes is valid (lies in polygon interior)\nfunction isValidDiagonal( a, b ) {\n\n\treturn a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges\n ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible\n ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors\n equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case\n\n}\n\n// signed area of a triangle\nfunction area( p, q, r ) {\n\n\treturn ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );\n\n}\n\n// check if two points are equal\nfunction equals( p1, p2 ) {\n\n\treturn p1.x === p2.x && p1.y === p2.y;\n\n}\n\n// check if two segments intersect\nfunction intersects( p1, q1, p2, q2 ) {\n\n\tconst o1 = sign( area( p1, q1, p2 ) );\n\tconst o2 = sign( area( p1, q1, q2 ) );\n\tconst o3 = sign( area( p2, q2, p1 ) );\n\tconst o4 = sign( area( p2, q2, q1 ) );\n\n\tif ( o1 !== o2 && o3 !== o4 ) return true; // general case\n\n\tif ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1\n\tif ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1\n\tif ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2\n\tif ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2\n\n\treturn false;\n\n}\n\n// for collinear points p, q, r, check if point q lies on segment pr\nfunction onSegment( p, q, r ) {\n\n\treturn 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 );\n\n}\n\nfunction sign( num ) {\n\n\treturn num > 0 ? 1 : num < 0 ? - 1 : 0;\n\n}\n\n// check if a polygon diagonal intersects any polygon segments\nfunction intersectsPolygon( a, b ) {\n\n\tlet p = a;\n\tdo {\n\n\t\tif ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&\n\t\t\tintersects( p, p.next, a, b ) ) return true;\n\t\tp = p.next;\n\n\t} while ( p !== a );\n\n\treturn false;\n\n}\n\n// check if a polygon diagonal is locally inside the polygon\nfunction locallyInside( a, b ) {\n\n\treturn area( a.prev, a, a.next ) < 0 ?\n\t\tarea( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 :\n\t\tarea( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0;\n\n}\n\n// check if the middle point of a polygon diagonal is inside the polygon\nfunction middleInside( a, b ) {\n\n\tlet p = a,\n\t\tinside = false;\n\tconst px = ( a.x + b.x ) / 2,\n\t\tpy = ( a.y + b.y ) / 2;\n\tdo {\n\n\t\tif ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&\n\t\t\t( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )\n\t\t\tinside = ! inside;\n\t\tp = p.next;\n\n\t} while ( p !== a );\n\n\treturn inside;\n\n}\n\n// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;\n// if one belongs to the outer ring and another to a hole, it merges it into a single ring\nfunction splitPolygon( a, b ) {\n\n\tconst a2 = new Node( a.i, a.x, a.y ),\n\t\tb2 = new Node( b.i, b.x, b.y ),\n\t\tan = a.next,\n\t\tbp = b.prev;\n\n\ta.next = b;\n\tb.prev = a;\n\n\ta2.next = an;\n\tan.prev = a2;\n\n\tb2.next = a2;\n\ta2.prev = b2;\n\n\tbp.next = b2;\n\tb2.prev = bp;\n\n\treturn b2;\n\n}\n\n// create a node and optionally link it with previous one (in a circular doubly linked list)\nfunction insertNode( i, x, y, last ) {\n\n\tconst p = new Node( i, x, y );\n\n\tif ( ! last ) {\n\n\t\tp.prev = p;\n\t\tp.next = p;\n\n\t} else {\n\n\t\tp.next = last.next;\n\t\tp.prev = last;\n\t\tlast.next.prev = p;\n\t\tlast.next = p;\n\n\t}\n\n\treturn p;\n\n}\n\nfunction removeNode( p ) {\n\n\tp.next.prev = p.prev;\n\tp.prev.next = p.next;\n\n\tif ( p.prevZ ) p.prevZ.nextZ = p.nextZ;\n\tif ( p.nextZ ) p.nextZ.prevZ = p.prevZ;\n\n}\n\nfunction Node( i, x, y ) {\n\n\t// vertex index in coordinates array\n\tthis.i = i;\n\n\t// vertex coordinates\n\tthis.x = x;\n\tthis.y = y;\n\n\t// previous and next vertex nodes in a polygon ring\n\tthis.prev = null;\n\tthis.next = null;\n\n\t// z-order curve value\n\tthis.z = 0;\n\n\t// previous and next nodes in z-order\n\tthis.prevZ = null;\n\tthis.nextZ = null;\n\n\t// indicates whether this is a steiner point\n\tthis.steiner = false;\n\n}\n\nfunction signedArea( data, start, end, dim ) {\n\n\tlet sum = 0;\n\tfor ( let i = start, j = end - dim; i < end; i += dim ) {\n\n\t\tsum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );\n\t\tj = i;\n\n\t}\n\n\treturn sum;\n\n}\n\nclass ShapeUtils {\n\n\t// calculate area of the contour polygon\n\n\tstatic area( contour ) {\n\n\t\tconst n = contour.length;\n\t\tlet a = 0.0;\n\n\t\tfor ( let p = n - 1, q = 0; q < n; p = q ++ ) {\n\n\t\t\ta += contour[ p ].x * contour[ q ].y - contour[ q ].x * contour[ p ].y;\n\n\t\t}\n\n\t\treturn a * 0.5;\n\n\t}\n\n\tstatic isClockWise( pts ) {\n\n\t\treturn ShapeUtils.area( pts ) < 0;\n\n\t}\n\n\tstatic triangulateShape( contour, holes ) {\n\n\t\tconst vertices = []; // flat array of vertices like [ x0,y0, x1,y1, x2,y2, ... ]\n\t\tconst holeIndices = []; // array of hole indices\n\t\tconst faces = []; // final array of vertex indices like [ [ a,b,d ], [ b,c,d ] ]\n\n\t\tremoveDupEndPts( contour );\n\t\taddContour( vertices, contour );\n\n\t\t//\n\n\t\tlet holeIndex = contour.length;\n\n\t\tholes.forEach( removeDupEndPts );\n\n\t\tfor ( let i = 0; i < holes.length; i ++ ) {\n\n\t\t\tholeIndices.push( holeIndex );\n\t\t\tholeIndex += holes[ i ].length;\n\t\t\taddContour( vertices, holes[ i ] );\n\n\t\t}\n\n\t\t//\n\n\t\tconst triangles = Earcut.triangulate( vertices, holeIndices );\n\n\t\t//\n\n\t\tfor ( let i = 0; i < triangles.length; i += 3 ) {\n\n\t\t\tfaces.push( triangles.slice( i, i + 3 ) );\n\n\t\t}\n\n\t\treturn faces;\n\n\t}\n\n}\n\nfunction removeDupEndPts( points ) {\n\n\tconst l = points.length;\n\n\tif ( l > 2 && points[ l - 1 ].equals( points[ 0 ] ) ) {\n\n\t\tpoints.pop();\n\n\t}\n\n}\n\nfunction addContour( vertices, contour ) {\n\n\tfor ( let i = 0; i < contour.length; i ++ ) {\n\n\t\tvertices.push( contour[ i ].x );\n\t\tvertices.push( contour[ i ].y );\n\n\t}\n\n}\n\n/**\n * Creates extruded geometry from a path shape.\n *\n * parameters = {\n *\n * curveSegments: , // number of points on the curves\n * steps: , // number of points for z-side extrusions / used for subdividing segments of extrude spline too\n * depth: , // Depth to extrude the shape\n *\n * bevelEnabled: , // turn on bevel\n * bevelThickness: , // how deep into the original shape bevel goes\n * bevelSize: , // how far from shape outline (including bevelOffset) is bevel\n * bevelOffset: , // how far from shape outline does bevel start\n * bevelSegments: , // number of bevel layers\n *\n * extrudePath: // curve to extrude shape along\n *\n * UVGenerator: // object that provides UV generator functions\n *\n * }\n */\n\n\nclass ExtrudeGeometry extends BufferGeometry {\n\n\tconstructor( 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 = {} ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'ExtrudeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tshapes: shapes,\n\t\t\toptions: options\n\t\t};\n\n\t\tshapes = Array.isArray( shapes ) ? shapes : [ shapes ];\n\n\t\tconst scope = this;\n\n\t\tconst verticesArray = [];\n\t\tconst uvArray = [];\n\n\t\tfor ( let i = 0, l = shapes.length; i < l; i ++ ) {\n\n\t\t\tconst shape = shapes[ i ];\n\t\t\taddShape( shape );\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( verticesArray, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvArray, 2 ) );\n\n\t\tthis.computeVertexNormals();\n\n\t\t// functions\n\n\t\tfunction addShape( shape ) {\n\n\t\t\tconst placeholder = [];\n\n\t\t\t// options\n\n\t\t\tconst curveSegments = options.curveSegments !== undefined ? options.curveSegments : 12;\n\t\t\tconst steps = options.steps !== undefined ? options.steps : 1;\n\t\t\tconst depth = options.depth !== undefined ? options.depth : 1;\n\n\t\t\tlet bevelEnabled = options.bevelEnabled !== undefined ? options.bevelEnabled : true;\n\t\t\tlet bevelThickness = options.bevelThickness !== undefined ? options.bevelThickness : 0.2;\n\t\t\tlet bevelSize = options.bevelSize !== undefined ? options.bevelSize : bevelThickness - 0.1;\n\t\t\tlet bevelOffset = options.bevelOffset !== undefined ? options.bevelOffset : 0;\n\t\t\tlet bevelSegments = options.bevelSegments !== undefined ? options.bevelSegments : 3;\n\n\t\t\tconst extrudePath = options.extrudePath;\n\n\t\t\tconst uvgen = options.UVGenerator !== undefined ? options.UVGenerator : WorldUVGenerator;\n\n\t\t\t//\n\n\t\t\tlet extrudePts, extrudeByPath = false;\n\t\t\tlet splineTube, binormal, normal, position2;\n\n\t\t\tif ( extrudePath ) {\n\n\t\t\t\textrudePts = extrudePath.getSpacedPoints( steps );\n\n\t\t\t\textrudeByPath = true;\n\t\t\t\tbevelEnabled = false; // bevels not supported for path extrusion\n\n\t\t\t\t// SETUP TNB variables\n\n\t\t\t\t// TODO1 - have a .isClosed in spline?\n\n\t\t\t\tsplineTube = extrudePath.computeFrenetFrames( steps, false );\n\n\t\t\t\t// console.log(splineTube, 'splineTube', splineTube.normals.length, 'steps', steps, 'extrudePts', extrudePts.length);\n\n\t\t\t\tbinormal = new Vector3();\n\t\t\t\tnormal = new Vector3();\n\t\t\t\tposition2 = new Vector3();\n\n\t\t\t}\n\n\t\t\t// Safeguards if bevels are not enabled\n\n\t\t\tif ( ! bevelEnabled ) {\n\n\t\t\t\tbevelSegments = 0;\n\t\t\t\tbevelThickness = 0;\n\t\t\t\tbevelSize = 0;\n\t\t\t\tbevelOffset = 0;\n\n\t\t\t}\n\n\t\t\t// Variables initialization\n\n\t\t\tconst shapePoints = shape.extractPoints( curveSegments );\n\n\t\t\tlet vertices = shapePoints.shape;\n\t\t\tconst holes = shapePoints.holes;\n\n\t\t\tconst reverse = ! ShapeUtils.isClockWise( vertices );\n\n\t\t\tif ( reverse ) {\n\n\t\t\t\tvertices = vertices.reverse();\n\n\t\t\t\t// Maybe we should also check if holes are in the opposite direction, just to be safe ...\n\n\t\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\t\tconst ahole = holes[ h ];\n\n\t\t\t\t\tif ( ShapeUtils.isClockWise( ahole ) ) {\n\n\t\t\t\t\t\tholes[ h ] = ahole.reverse();\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t\tconst faces = ShapeUtils.triangulateShape( vertices, holes );\n\n\t\t\t/* Vertices */\n\n\t\t\tconst contour = vertices; // vertices has all points but contour has only points of circumference\n\n\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\tconst ahole = holes[ h ];\n\n\t\t\t\tvertices = vertices.concat( ahole );\n\n\t\t\t}\n\n\n\t\t\tfunction scalePt2( pt, vec, size ) {\n\n\t\t\t\tif ( ! vec ) console.error( 'THREE.ExtrudeGeometry: vec does not exist' );\n\n\t\t\t\treturn pt.clone().addScaledVector( vec, size );\n\n\t\t\t}\n\n\t\t\tconst vlen = vertices.length, flen = faces.length;\n\n\n\t\t\t// Find directions for point movement\n\n\n\t\t\tfunction getBevelVec( inPt, inPrev, inNext ) {\n\n\t\t\t\t// computes for inPt the corresponding point inPt' on a new contour\n\t\t\t\t// shifted by 1 unit (length of normalized vector) to the left\n\t\t\t\t// if we walk along contour clockwise, this new contour is outside the old one\n\t\t\t\t//\n\t\t\t\t// inPt' is the intersection of the two lines parallel to the two\n\t\t\t\t// adjacent edges of inPt at a distance of 1 unit on the left side.\n\n\t\t\t\tlet v_trans_x, v_trans_y, shrink_by; // resulting translation vector for inPt\n\n\t\t\t\t// good reading for geometry algorithms (here: line-line intersection)\n\t\t\t\t// http://geomalgorithms.com/a05-_intersect-1.html\n\n\t\t\t\tconst v_prev_x = inPt.x - inPrev.x,\n\t\t\t\t\tv_prev_y = inPt.y - inPrev.y;\n\t\t\t\tconst v_next_x = inNext.x - inPt.x,\n\t\t\t\t\tv_next_y = inNext.y - inPt.y;\n\n\t\t\t\tconst v_prev_lensq = ( v_prev_x * v_prev_x + v_prev_y * v_prev_y );\n\n\t\t\t\t// check for collinear edges\n\t\t\t\tconst collinear0 = ( v_prev_x * v_next_y - v_prev_y * v_next_x );\n\n\t\t\t\tif ( Math.abs( collinear0 ) > Number.EPSILON ) {\n\n\t\t\t\t\t// not collinear\n\n\t\t\t\t\t// length of vectors for normalizing\n\n\t\t\t\t\tconst v_prev_len = Math.sqrt( v_prev_lensq );\n\t\t\t\t\tconst v_next_len = Math.sqrt( v_next_x * v_next_x + v_next_y * v_next_y );\n\n\t\t\t\t\t// shift adjacent points by unit vectors to the left\n\n\t\t\t\t\tconst ptPrevShift_x = ( inPrev.x - v_prev_y / v_prev_len );\n\t\t\t\t\tconst ptPrevShift_y = ( inPrev.y + v_prev_x / v_prev_len );\n\n\t\t\t\t\tconst ptNextShift_x = ( inNext.x - v_next_y / v_next_len );\n\t\t\t\t\tconst ptNextShift_y = ( inNext.y + v_next_x / v_next_len );\n\n\t\t\t\t\t// scaling factor for v_prev to intersection point\n\n\t\t\t\t\tconst sf = ( ( ptNextShift_x - ptPrevShift_x ) * v_next_y -\n\t\t\t\t\t\t\t( ptNextShift_y - ptPrevShift_y ) * v_next_x ) /\n\t\t\t\t\t\t( v_prev_x * v_next_y - v_prev_y * v_next_x );\n\n\t\t\t\t\t// vector from inPt to intersection point\n\n\t\t\t\t\tv_trans_x = ( ptPrevShift_x + v_prev_x * sf - inPt.x );\n\t\t\t\t\tv_trans_y = ( ptPrevShift_y + v_prev_y * sf - inPt.y );\n\n\t\t\t\t\t// Don't normalize!, otherwise sharp corners become ugly\n\t\t\t\t\t// but prevent crazy spikes\n\t\t\t\t\tconst v_trans_lensq = ( v_trans_x * v_trans_x + v_trans_y * v_trans_y );\n\t\t\t\t\tif ( v_trans_lensq <= 2 ) {\n\n\t\t\t\t\t\treturn new Vector2( v_trans_x, v_trans_y );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tshrink_by = Math.sqrt( v_trans_lensq / 2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// handle special case of collinear edges\n\n\t\t\t\t\tlet direction_eq = false; // assumes: opposite\n\n\t\t\t\t\tif ( v_prev_x > Number.EPSILON ) {\n\n\t\t\t\t\t\tif ( v_next_x > Number.EPSILON ) {\n\n\t\t\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( v_prev_x < - Number.EPSILON ) {\n\n\t\t\t\t\t\t\tif ( v_next_x < - Number.EPSILON ) {\n\n\t\t\t\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tif ( Math.sign( v_prev_y ) === Math.sign( v_next_y ) ) {\n\n\t\t\t\t\t\t\t\tdirection_eq = true;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( direction_eq ) {\n\n\t\t\t\t\t\t// console.log(\"Warning: lines are a straight sequence\");\n\t\t\t\t\t\tv_trans_x = - v_prev_y;\n\t\t\t\t\t\tv_trans_y = v_prev_x;\n\t\t\t\t\t\tshrink_by = Math.sqrt( v_prev_lensq );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// console.log(\"Warning: lines are a straight spike\");\n\t\t\t\t\t\tv_trans_x = v_prev_x;\n\t\t\t\t\t\tv_trans_y = v_prev_y;\n\t\t\t\t\t\tshrink_by = Math.sqrt( v_prev_lensq / 2 );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\treturn new Vector2( v_trans_x / shrink_by, v_trans_y / shrink_by );\n\n\t\t\t}\n\n\n\t\t\tconst contourMovements = [];\n\n\t\t\tfor ( let i = 0, il = contour.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {\n\n\t\t\t\tif ( j === il ) j = 0;\n\t\t\t\tif ( k === il ) k = 0;\n\n\t\t\t\t// (j)---(i)---(k)\n\t\t\t\t// console.log('i,j,k', i, j , k)\n\n\t\t\t\tcontourMovements[ i ] = getBevelVec( contour[ i ], contour[ j ], contour[ k ] );\n\n\t\t\t}\n\n\t\t\tconst holesMovements = [];\n\t\t\tlet oneHoleMovements, verticesMovements = contourMovements.concat();\n\n\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\tconst ahole = holes[ h ];\n\n\t\t\t\toneHoleMovements = [];\n\n\t\t\t\tfor ( let i = 0, il = ahole.length, j = il - 1, k = i + 1; i < il; i ++, j ++, k ++ ) {\n\n\t\t\t\t\tif ( j === il ) j = 0;\n\t\t\t\t\tif ( k === il ) k = 0;\n\n\t\t\t\t\t// (j)---(i)---(k)\n\t\t\t\t\toneHoleMovements[ i ] = getBevelVec( ahole[ i ], ahole[ j ], ahole[ k ] );\n\n\t\t\t\t}\n\n\t\t\t\tholesMovements.push( oneHoleMovements );\n\t\t\t\tverticesMovements = verticesMovements.concat( oneHoleMovements );\n\n\t\t\t}\n\n\n\t\t\t// Loop bevelSegments, 1 for the front, 1 for the back\n\n\t\t\tfor ( let b = 0; b < bevelSegments; b ++ ) {\n\n\t\t\t\t//for ( b = bevelSegments; b > 0; b -- ) {\n\n\t\t\t\tconst t = b / bevelSegments;\n\t\t\t\tconst z = bevelThickness * Math.cos( t * Math.PI / 2 );\n\t\t\t\tconst bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;\n\n\t\t\t\t// contract shape\n\n\t\t\t\tfor ( let i = 0, il = contour.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst vert = scalePt2( contour[ i ], contourMovements[ i ], bs );\n\n\t\t\t\t\tv( vert.x, vert.y, - z );\n\n\t\t\t\t}\n\n\t\t\t\t// expand holes\n\n\t\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\t\tconst ahole = holes[ h ];\n\t\t\t\t\toneHoleMovements = holesMovements[ h ];\n\n\t\t\t\t\tfor ( let i = 0, il = ahole.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tconst vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );\n\n\t\t\t\t\t\tv( vert.x, vert.y, - z );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst bs = bevelSize + bevelOffset;\n\n\t\t\t// Back facing vertices\n\n\t\t\tfor ( let i = 0; i < vlen; i ++ ) {\n\n\t\t\t\tconst vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];\n\n\t\t\t\tif ( ! extrudeByPath ) {\n\n\t\t\t\t\tv( vert.x, vert.y, 0 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// v( vert.x, vert.y + extrudePts[ 0 ].y, extrudePts[ 0 ].x );\n\n\t\t\t\t\tnormal.copy( splineTube.normals[ 0 ] ).multiplyScalar( vert.x );\n\t\t\t\t\tbinormal.copy( splineTube.binormals[ 0 ] ).multiplyScalar( vert.y );\n\n\t\t\t\t\tposition2.copy( extrudePts[ 0 ] ).add( normal ).add( binormal );\n\n\t\t\t\t\tv( position2.x, position2.y, position2.z );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// Add stepped vertices...\n\t\t\t// Including front facing vertices\n\n\t\t\tfor ( let s = 1; s <= steps; s ++ ) {\n\n\t\t\t\tfor ( let i = 0; i < vlen; i ++ ) {\n\n\t\t\t\t\tconst vert = bevelEnabled ? scalePt2( vertices[ i ], verticesMovements[ i ], bs ) : vertices[ i ];\n\n\t\t\t\t\tif ( ! extrudeByPath ) {\n\n\t\t\t\t\t\tv( vert.x, vert.y, depth / steps * s );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// v( vert.x, vert.y + extrudePts[ s - 1 ].y, extrudePts[ s - 1 ].x );\n\n\t\t\t\t\t\tnormal.copy( splineTube.normals[ s ] ).multiplyScalar( vert.x );\n\t\t\t\t\t\tbinormal.copy( splineTube.binormals[ s ] ).multiplyScalar( vert.y );\n\n\t\t\t\t\t\tposition2.copy( extrudePts[ s ] ).add( normal ).add( binormal );\n\n\t\t\t\t\t\tv( position2.x, position2.y, position2.z );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\n\t\t\t// Add bevel segments planes\n\n\t\t\t//for ( b = 1; b <= bevelSegments; b ++ ) {\n\t\t\tfor ( let b = bevelSegments - 1; b >= 0; b -- ) {\n\n\t\t\t\tconst t = b / bevelSegments;\n\t\t\t\tconst z = bevelThickness * Math.cos( t * Math.PI / 2 );\n\t\t\t\tconst bs = bevelSize * Math.sin( t * Math.PI / 2 ) + bevelOffset;\n\n\t\t\t\t// contract shape\n\n\t\t\t\tfor ( let i = 0, il = contour.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst vert = scalePt2( contour[ i ], contourMovements[ i ], bs );\n\t\t\t\t\tv( vert.x, vert.y, depth + z );\n\n\t\t\t\t}\n\n\t\t\t\t// expand holes\n\n\t\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\t\tconst ahole = holes[ h ];\n\t\t\t\t\toneHoleMovements = holesMovements[ h ];\n\n\t\t\t\t\tfor ( let i = 0, il = ahole.length; i < il; i ++ ) {\n\n\t\t\t\t\t\tconst vert = scalePt2( ahole[ i ], oneHoleMovements[ i ], bs );\n\n\t\t\t\t\t\tif ( ! extrudeByPath ) {\n\n\t\t\t\t\t\t\tv( vert.x, vert.y, depth + z );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tv( vert.x, vert.y + extrudePts[ steps - 1 ].y, extrudePts[ steps - 1 ].x + z );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t/* Faces */\n\n\t\t\t// Top and bottom faces\n\n\t\t\tbuildLidFaces();\n\n\t\t\t// Sides faces\n\n\t\t\tbuildSideFaces();\n\n\n\t\t\t///// Internal functions\n\n\t\t\tfunction buildLidFaces() {\n\n\t\t\t\tconst start = verticesArray.length / 3;\n\n\t\t\t\tif ( bevelEnabled ) {\n\n\t\t\t\t\tlet layer = 0; // steps + 1\n\t\t\t\t\tlet offset = vlen * layer;\n\n\t\t\t\t\t// Bottom faces\n\n\t\t\t\t\tfor ( let i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\t\tconst face = faces[ i ];\n\t\t\t\t\t\tf3( face[ 2 ] + offset, face[ 1 ] + offset, face[ 0 ] + offset );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tlayer = steps + bevelSegments * 2;\n\t\t\t\t\toffset = vlen * layer;\n\n\t\t\t\t\t// Top faces\n\n\t\t\t\t\tfor ( let i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\t\tconst face = faces[ i ];\n\t\t\t\t\t\tf3( face[ 0 ] + offset, face[ 1 ] + offset, face[ 2 ] + offset );\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// Bottom faces\n\n\t\t\t\t\tfor ( let i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\t\tconst face = faces[ i ];\n\t\t\t\t\t\tf3( face[ 2 ], face[ 1 ], face[ 0 ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// Top faces\n\n\t\t\t\t\tfor ( let i = 0; i < flen; i ++ ) {\n\n\t\t\t\t\t\tconst face = faces[ i ];\n\t\t\t\t\t\tf3( face[ 0 ] + vlen * steps, face[ 1 ] + vlen * steps, face[ 2 ] + vlen * steps );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tscope.addGroup( start, verticesArray.length / 3 - start, 0 );\n\n\t\t\t}\n\n\t\t\t// Create faces for the z-sides of the shape\n\n\t\t\tfunction buildSideFaces() {\n\n\t\t\t\tconst start = verticesArray.length / 3;\n\t\t\t\tlet layeroffset = 0;\n\t\t\t\tsidewalls( contour, layeroffset );\n\t\t\t\tlayeroffset += contour.length;\n\n\t\t\t\tfor ( let h = 0, hl = holes.length; h < hl; h ++ ) {\n\n\t\t\t\t\tconst ahole = holes[ h ];\n\t\t\t\t\tsidewalls( ahole, layeroffset );\n\n\t\t\t\t\t//, true\n\t\t\t\t\tlayeroffset += ahole.length;\n\n\t\t\t\t}\n\n\n\t\t\t\tscope.addGroup( start, verticesArray.length / 3 - start, 1 );\n\n\n\t\t\t}\n\n\t\t\tfunction sidewalls( contour, layeroffset ) {\n\n\t\t\t\tlet i = contour.length;\n\n\t\t\t\twhile ( -- i >= 0 ) {\n\n\t\t\t\t\tconst j = i;\n\t\t\t\t\tlet k = i - 1;\n\t\t\t\t\tif ( k < 0 ) k = contour.length - 1;\n\n\t\t\t\t\t//console.log('b', i,j, i-1, k,vertices.length);\n\n\t\t\t\t\tfor ( let s = 0, sl = ( steps + bevelSegments * 2 ); s < sl; s ++ ) {\n\n\t\t\t\t\t\tconst slen1 = vlen * s;\n\t\t\t\t\t\tconst slen2 = vlen * ( s + 1 );\n\n\t\t\t\t\t\tconst a = layeroffset + j + slen1,\n\t\t\t\t\t\t\tb = layeroffset + k + slen1,\n\t\t\t\t\t\t\tc = layeroffset + k + slen2,\n\t\t\t\t\t\t\td = layeroffset + j + slen2;\n\n\t\t\t\t\t\tf4( a, b, c, d );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tfunction v( x, y, z ) {\n\n\t\t\t\tplaceholder.push( x );\n\t\t\t\tplaceholder.push( y );\n\t\t\t\tplaceholder.push( z );\n\n\t\t\t}\n\n\n\t\t\tfunction f3( a, b, c ) {\n\n\t\t\t\taddVertex( a );\n\t\t\t\taddVertex( b );\n\t\t\t\taddVertex( c );\n\n\t\t\t\tconst nextIndex = verticesArray.length / 3;\n\t\t\t\tconst uvs = uvgen.generateTopUV( scope, verticesArray, nextIndex - 3, nextIndex - 2, nextIndex - 1 );\n\n\t\t\t\taddUV( uvs[ 0 ] );\n\t\t\t\taddUV( uvs[ 1 ] );\n\t\t\t\taddUV( uvs[ 2 ] );\n\n\t\t\t}\n\n\t\t\tfunction f4( a, b, c, d ) {\n\n\t\t\t\taddVertex( a );\n\t\t\t\taddVertex( b );\n\t\t\t\taddVertex( d );\n\n\t\t\t\taddVertex( b );\n\t\t\t\taddVertex( c );\n\t\t\t\taddVertex( d );\n\n\n\t\t\t\tconst nextIndex = verticesArray.length / 3;\n\t\t\t\tconst uvs = uvgen.generateSideWallUV( scope, verticesArray, nextIndex - 6, nextIndex - 3, nextIndex - 2, nextIndex - 1 );\n\n\t\t\t\taddUV( uvs[ 0 ] );\n\t\t\t\taddUV( uvs[ 1 ] );\n\t\t\t\taddUV( uvs[ 3 ] );\n\n\t\t\t\taddUV( uvs[ 1 ] );\n\t\t\t\taddUV( uvs[ 2 ] );\n\t\t\t\taddUV( uvs[ 3 ] );\n\n\t\t\t}\n\n\t\t\tfunction addVertex( index ) {\n\n\t\t\t\tverticesArray.push( placeholder[ index * 3 + 0 ] );\n\t\t\t\tverticesArray.push( placeholder[ index * 3 + 1 ] );\n\t\t\t\tverticesArray.push( placeholder[ index * 3 + 2 ] );\n\n\t\t\t}\n\n\n\t\t\tfunction addUV( vector2 ) {\n\n\t\t\t\tuvArray.push( vector2.x );\n\t\t\t\tuvArray.push( vector2.y );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tconst shapes = this.parameters.shapes;\n\t\tconst options = this.parameters.options;\n\n\t\treturn toJSON$1( shapes, options, data );\n\n\t}\n\n\tstatic fromJSON( data, shapes ) {\n\n\t\tconst geometryShapes = [];\n\n\t\tfor ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {\n\n\t\t\tconst shape = shapes[ data.shapes[ j ] ];\n\n\t\t\tgeometryShapes.push( shape );\n\n\t\t}\n\n\t\tconst extrudePath = data.options.extrudePath;\n\n\t\tif ( extrudePath !== undefined ) {\n\n\t\t\tdata.options.extrudePath = new Curves[ extrudePath.type ]().fromJSON( extrudePath );\n\n\t\t}\n\n\t\treturn new ExtrudeGeometry( geometryShapes, data.options );\n\n\t}\n\n}\n\nconst WorldUVGenerator = {\n\n\tgenerateTopUV: function ( geometry, vertices, indexA, indexB, indexC ) {\n\n\t\tconst a_x = vertices[ indexA * 3 ];\n\t\tconst a_y = vertices[ indexA * 3 + 1 ];\n\t\tconst b_x = vertices[ indexB * 3 ];\n\t\tconst b_y = vertices[ indexB * 3 + 1 ];\n\t\tconst c_x = vertices[ indexC * 3 ];\n\t\tconst c_y = vertices[ indexC * 3 + 1 ];\n\n\t\treturn [\n\t\t\tnew Vector2( a_x, a_y ),\n\t\t\tnew Vector2( b_x, b_y ),\n\t\t\tnew Vector2( c_x, c_y )\n\t\t];\n\n\t},\n\n\tgenerateSideWallUV: function ( geometry, vertices, indexA, indexB, indexC, indexD ) {\n\n\t\tconst a_x = vertices[ indexA * 3 ];\n\t\tconst a_y = vertices[ indexA * 3 + 1 ];\n\t\tconst a_z = vertices[ indexA * 3 + 2 ];\n\t\tconst b_x = vertices[ indexB * 3 ];\n\t\tconst b_y = vertices[ indexB * 3 + 1 ];\n\t\tconst b_z = vertices[ indexB * 3 + 2 ];\n\t\tconst c_x = vertices[ indexC * 3 ];\n\t\tconst c_y = vertices[ indexC * 3 + 1 ];\n\t\tconst c_z = vertices[ indexC * 3 + 2 ];\n\t\tconst d_x = vertices[ indexD * 3 ];\n\t\tconst d_y = vertices[ indexD * 3 + 1 ];\n\t\tconst d_z = vertices[ indexD * 3 + 2 ];\n\n\t\tif ( Math.abs( a_y - b_y ) < Math.abs( a_x - b_x ) ) {\n\n\t\t\treturn [\n\t\t\t\tnew Vector2( a_x, 1 - a_z ),\n\t\t\t\tnew Vector2( b_x, 1 - b_z ),\n\t\t\t\tnew Vector2( c_x, 1 - c_z ),\n\t\t\t\tnew Vector2( d_x, 1 - d_z )\n\t\t\t];\n\n\t\t} else {\n\n\t\t\treturn [\n\t\t\t\tnew Vector2( a_y, 1 - a_z ),\n\t\t\t\tnew Vector2( b_y, 1 - b_z ),\n\t\t\t\tnew Vector2( c_y, 1 - c_z ),\n\t\t\t\tnew Vector2( d_y, 1 - d_z )\n\t\t\t];\n\n\t\t}\n\n\t}\n\n};\n\nfunction toJSON$1( shapes, options, data ) {\n\n\tdata.shapes = [];\n\n\tif ( Array.isArray( shapes ) ) {\n\n\t\tfor ( let i = 0, l = shapes.length; i < l; i ++ ) {\n\n\t\t\tconst shape = shapes[ i ];\n\n\t\t\tdata.shapes.push( shape.uuid );\n\n\t\t}\n\n\t} else {\n\n\t\tdata.shapes.push( shapes.uuid );\n\n\t}\n\n\tdata.options = Object.assign( {}, options );\n\n\tif ( options.extrudePath !== undefined ) data.options.extrudePath = options.extrudePath.toJSON();\n\n\treturn data;\n\n}\n\nclass IcosahedronGeometry extends PolyhedronGeometry {\n\n\tconstructor( radius = 1, detail = 0 ) {\n\n\t\tconst t = ( 1 + Math.sqrt( 5 ) ) / 2;\n\n\t\tconst vertices = [\n\t\t\t- 1, t, 0, \t1, t, 0, \t- 1, - t, 0, \t1, - t, 0,\n\t\t\t0, - 1, t, \t0, 1, t,\t0, - 1, - t, \t0, 1, - t,\n\t\t\tt, 0, - 1, \tt, 0, 1, \t- t, 0, - 1, \t- t, 0, 1\n\t\t];\n\n\t\tconst indices = [\n\t\t\t0, 11, 5, \t0, 5, 1, \t0, 1, 7, \t0, 7, 10, \t0, 10, 11,\n\t\t\t1, 5, 9, \t5, 11, 4,\t11, 10, 2,\t10, 7, 6,\t7, 1, 8,\n\t\t\t3, 9, 4, \t3, 4, 2,\t3, 2, 6,\t3, 6, 8,\t3, 8, 9,\n\t\t\t4, 9, 5, \t2, 4, 11,\t6, 2, 10,\t8, 6, 7,\t9, 8, 1\n\t\t];\n\n\t\tsuper( vertices, indices, radius, detail );\n\n\t\tthis.type = 'IcosahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new IcosahedronGeometry( data.radius, data.detail );\n\n\t}\n\n}\n\nclass OctahedronGeometry extends PolyhedronGeometry {\n\n\tconstructor( radius = 1, detail = 0 ) {\n\n\t\tconst vertices = [\n\t\t\t1, 0, 0, \t- 1, 0, 0,\t0, 1, 0,\n\t\t\t0, - 1, 0, \t0, 0, 1,\t0, 0, - 1\n\t\t];\n\n\t\tconst indices = [\n\t\t\t0, 2, 4,\t0, 4, 3,\t0, 3, 5,\n\t\t\t0, 5, 2,\t1, 2, 5,\t1, 5, 3,\n\t\t\t1, 3, 4,\t1, 4, 2\n\t\t];\n\n\t\tsuper( vertices, indices, radius, detail );\n\n\t\tthis.type = 'OctahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new OctahedronGeometry( data.radius, data.detail );\n\n\t}\n\n}\n\nclass RingGeometry extends BufferGeometry {\n\n\tconstructor( innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'RingGeometry';\n\n\t\tthis.parameters = {\n\t\t\tinnerRadius: innerRadius,\n\t\t\touterRadius: outerRadius,\n\t\t\tthetaSegments: thetaSegments,\n\t\t\tphiSegments: phiSegments,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\tthetaSegments = Math.max( 3, thetaSegments );\n\t\tphiSegments = Math.max( 1, phiSegments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// some helper variables\n\n\t\tlet radius = innerRadius;\n\t\tconst radiusStep = ( ( outerRadius - innerRadius ) / phiSegments );\n\t\tconst vertex = new Vector3();\n\t\tconst uv = new Vector2();\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( let j = 0; j <= phiSegments; j ++ ) {\n\n\t\t\tfor ( let i = 0; i <= thetaSegments; i ++ ) {\n\n\t\t\t\t// values are generate from the inside of the ring to the outside\n\n\t\t\t\tconst segment = thetaStart + i / thetaSegments * thetaLength;\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = radius * Math.cos( segment );\n\t\t\t\tvertex.y = radius * Math.sin( segment );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormals.push( 0, 0, 1 );\n\n\t\t\t\t// uv\n\n\t\t\t\tuv.x = ( vertex.x / outerRadius + 1 ) / 2;\n\t\t\t\tuv.y = ( vertex.y / outerRadius + 1 ) / 2;\n\n\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t}\n\n\t\t\t// increase the radius for next row of vertices\n\n\t\t\tradius += radiusStep;\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( let j = 0; j < phiSegments; j ++ ) {\n\n\t\t\tconst thetaSegmentLevel = j * ( thetaSegments + 1 );\n\n\t\t\tfor ( let i = 0; i < thetaSegments; i ++ ) {\n\n\t\t\t\tconst segment = i + thetaSegmentLevel;\n\n\t\t\t\tconst a = segment;\n\t\t\t\tconst b = segment + thetaSegments + 1;\n\t\t\t\tconst c = segment + thetaSegments + 2;\n\t\t\t\tconst d = segment + 1;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new RingGeometry( data.innerRadius, data.outerRadius, data.thetaSegments, data.phiSegments, data.thetaStart, data.thetaLength );\n\n\t}\n\n}\n\nclass ShapeGeometry extends BufferGeometry {\n\n\tconstructor( shapes = new Shape( [ new Vector2( 0, 0.5 ), new Vector2( - 0.5, - 0.5 ), new Vector2( 0.5, - 0.5 ) ] ), curveSegments = 12 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'ShapeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tshapes: shapes,\n\t\t\tcurveSegments: curveSegments\n\t\t};\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tlet groupStart = 0;\n\t\tlet groupCount = 0;\n\n\t\t// allow single and array values for \"shapes\" parameter\n\n\t\tif ( Array.isArray( shapes ) === false ) {\n\n\t\t\taddShape( shapes );\n\n\t\t} else {\n\n\t\t\tfor ( let i = 0; i < shapes.length; i ++ ) {\n\n\t\t\t\taddShape( shapes[ i ] );\n\n\t\t\t\tthis.addGroup( groupStart, groupCount, i ); // enables MultiMaterial support\n\n\t\t\t\tgroupStart += groupCount;\n\t\t\t\tgroupCount = 0;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\n\t\t// helper functions\n\n\t\tfunction addShape( shape ) {\n\n\t\t\tconst indexOffset = vertices.length / 3;\n\t\t\tconst points = shape.extractPoints( curveSegments );\n\n\t\t\tlet shapeVertices = points.shape;\n\t\t\tconst shapeHoles = points.holes;\n\n\t\t\t// check direction of vertices\n\n\t\t\tif ( ShapeUtils.isClockWise( shapeVertices ) === false ) {\n\n\t\t\t\tshapeVertices = shapeVertices.reverse();\n\n\t\t\t}\n\n\t\t\tfor ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {\n\n\t\t\t\tconst shapeHole = shapeHoles[ i ];\n\n\t\t\t\tif ( ShapeUtils.isClockWise( shapeHole ) === true ) {\n\n\t\t\t\t\tshapeHoles[ i ] = shapeHole.reverse();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconst faces = ShapeUtils.triangulateShape( shapeVertices, shapeHoles );\n\n\t\t\t// join vertices of inner and outer paths to a single array\n\n\t\t\tfor ( let i = 0, l = shapeHoles.length; i < l; i ++ ) {\n\n\t\t\t\tconst shapeHole = shapeHoles[ i ];\n\t\t\t\tshapeVertices = shapeVertices.concat( shapeHole );\n\n\t\t\t}\n\n\t\t\t// vertices, normals, uvs\n\n\t\t\tfor ( let i = 0, l = shapeVertices.length; i < l; i ++ ) {\n\n\t\t\t\tconst vertex = shapeVertices[ i ];\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, 0 );\n\t\t\t\tnormals.push( 0, 0, 1 );\n\t\t\t\tuvs.push( vertex.x, vertex.y ); // world uvs\n\n\t\t\t}\n\n\t\t\t// indices\n\n\t\t\tfor ( let i = 0, l = faces.length; i < l; i ++ ) {\n\n\t\t\t\tconst face = faces[ i ];\n\n\t\t\t\tconst a = face[ 0 ] + indexOffset;\n\t\t\t\tconst b = face[ 1 ] + indexOffset;\n\t\t\t\tconst c = face[ 2 ] + indexOffset;\n\n\t\t\t\tindices.push( a, b, c );\n\t\t\t\tgroupCount += 3;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tconst shapes = this.parameters.shapes;\n\n\t\treturn toJSON( shapes, data );\n\n\t}\n\n\tstatic fromJSON( data, shapes ) {\n\n\t\tconst geometryShapes = [];\n\n\t\tfor ( let j = 0, jl = data.shapes.length; j < jl; j ++ ) {\n\n\t\t\tconst shape = shapes[ data.shapes[ j ] ];\n\n\t\t\tgeometryShapes.push( shape );\n\n\t\t}\n\n\t\treturn new ShapeGeometry( geometryShapes, data.curveSegments );\n\n\t}\n\n}\n\nfunction toJSON( shapes, data ) {\n\n\tdata.shapes = [];\n\n\tif ( Array.isArray( shapes ) ) {\n\n\t\tfor ( let i = 0, l = shapes.length; i < l; i ++ ) {\n\n\t\t\tconst shape = shapes[ i ];\n\n\t\t\tdata.shapes.push( shape.uuid );\n\n\t\t}\n\n\t} else {\n\n\t\tdata.shapes.push( shapes.uuid );\n\n\t}\n\n\treturn data;\n\n}\n\nclass SphereGeometry extends BufferGeometry {\n\n\tconstructor( radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'SphereGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\twidthSegments: widthSegments,\n\t\t\theightSegments: heightSegments,\n\t\t\tphiStart: phiStart,\n\t\t\tphiLength: phiLength,\n\t\t\tthetaStart: thetaStart,\n\t\t\tthetaLength: thetaLength\n\t\t};\n\n\t\twidthSegments = Math.max( 3, Math.floor( widthSegments ) );\n\t\theightSegments = Math.max( 2, Math.floor( heightSegments ) );\n\n\t\tconst thetaEnd = Math.min( thetaStart + thetaLength, Math.PI );\n\n\t\tlet index = 0;\n\t\tconst grid = [];\n\n\t\tconst vertex = new Vector3();\n\t\tconst normal = new Vector3();\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( let iy = 0; iy <= heightSegments; iy ++ ) {\n\n\t\t\tconst verticesRow = [];\n\n\t\t\tconst v = iy / heightSegments;\n\n\t\t\t// special case for the poles\n\n\t\t\tlet uOffset = 0;\n\n\t\t\tif ( iy === 0 && thetaStart === 0 ) {\n\n\t\t\t\tuOffset = 0.5 / widthSegments;\n\n\t\t\t} else if ( iy === heightSegments && thetaEnd === Math.PI ) {\n\n\t\t\t\tuOffset = - 0.5 / widthSegments;\n\n\t\t\t}\n\n\t\t\tfor ( let ix = 0; ix <= widthSegments; ix ++ ) {\n\n\t\t\t\tconst u = ix / widthSegments;\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = - radius * Math.cos( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );\n\t\t\t\tvertex.y = radius * Math.cos( thetaStart + v * thetaLength );\n\t\t\t\tvertex.z = radius * Math.sin( phiStart + u * phiLength ) * Math.sin( thetaStart + v * thetaLength );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormal.copy( vertex ).normalize();\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( u + uOffset, 1 - v );\n\n\t\t\t\tverticesRow.push( index ++ );\n\n\t\t\t}\n\n\t\t\tgrid.push( verticesRow );\n\n\t\t}\n\n\t\t// indices\n\n\t\tfor ( let iy = 0; iy < heightSegments; iy ++ ) {\n\n\t\t\tfor ( let ix = 0; ix < widthSegments; ix ++ ) {\n\n\t\t\t\tconst a = grid[ iy ][ ix + 1 ];\n\t\t\t\tconst b = grid[ iy ][ ix ];\n\t\t\t\tconst c = grid[ iy + 1 ][ ix ];\n\t\t\t\tconst d = grid[ iy + 1 ][ ix + 1 ];\n\n\t\t\t\tif ( iy !== 0 || thetaStart > 0 ) indices.push( a, b, d );\n\t\t\t\tif ( iy !== heightSegments - 1 || thetaEnd < Math.PI ) indices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new SphereGeometry( data.radius, data.widthSegments, data.heightSegments, data.phiStart, data.phiLength, data.thetaStart, data.thetaLength );\n\n\t}\n\n}\n\nclass TetrahedronGeometry extends PolyhedronGeometry {\n\n\tconstructor( radius = 1, detail = 0 ) {\n\n\t\tconst vertices = [\n\t\t\t1, 1, 1, \t- 1, - 1, 1, \t- 1, 1, - 1, \t1, - 1, - 1\n\t\t];\n\n\t\tconst indices = [\n\t\t\t2, 1, 0, \t0, 3, 2,\t1, 3, 0,\t2, 3, 1\n\t\t];\n\n\t\tsuper( vertices, indices, radius, detail );\n\n\t\tthis.type = 'TetrahedronGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\tdetail: detail\n\t\t};\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new TetrahedronGeometry( data.radius, data.detail );\n\n\t}\n\n}\n\nclass TorusGeometry extends BufferGeometry {\n\n\tconstructor( radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'TorusGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\ttube: tube,\n\t\t\tradialSegments: radialSegments,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tarc: arc\n\t\t};\n\n\t\tradialSegments = Math.floor( radialSegments );\n\t\ttubularSegments = Math.floor( tubularSegments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tconst center = new Vector3();\n\t\tconst vertex = new Vector3();\n\t\tconst normal = new Vector3();\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( let j = 0; j <= radialSegments; j ++ ) {\n\n\t\t\tfor ( let i = 0; i <= tubularSegments; i ++ ) {\n\n\t\t\t\tconst u = i / tubularSegments * arc;\n\t\t\t\tconst v = j / radialSegments * Math.PI * 2;\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = ( radius + tube * Math.cos( v ) ) * Math.cos( u );\n\t\t\t\tvertex.y = ( radius + tube * Math.cos( v ) ) * Math.sin( u );\n\t\t\t\tvertex.z = tube * Math.sin( v );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal\n\n\t\t\t\tcenter.x = radius * Math.cos( u );\n\t\t\t\tcenter.y = radius * Math.sin( u );\n\t\t\t\tnormal.subVectors( vertex, center ).normalize();\n\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( i / tubularSegments );\n\t\t\t\tuvs.push( j / radialSegments );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate indices\n\n\t\tfor ( let j = 1; j <= radialSegments; j ++ ) {\n\n\t\t\tfor ( let i = 1; i <= tubularSegments; i ++ ) {\n\n\t\t\t\t// indices\n\n\t\t\t\tconst a = ( tubularSegments + 1 ) * j + i - 1;\n\t\t\t\tconst b = ( tubularSegments + 1 ) * ( j - 1 ) + i - 1;\n\t\t\t\tconst c = ( tubularSegments + 1 ) * ( j - 1 ) + i;\n\t\t\t\tconst d = ( tubularSegments + 1 ) * j + i;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new TorusGeometry( data.radius, data.tube, data.radialSegments, data.tubularSegments, data.arc );\n\n\t}\n\n}\n\nclass TorusKnotGeometry extends BufferGeometry {\n\n\tconstructor( radius = 1, tube = 0.4, tubularSegments = 64, radialSegments = 8, p = 2, q = 3 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'TorusKnotGeometry';\n\n\t\tthis.parameters = {\n\t\t\tradius: radius,\n\t\t\ttube: tube,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tradialSegments: radialSegments,\n\t\t\tp: p,\n\t\t\tq: q\n\t\t};\n\n\t\ttubularSegments = Math.floor( tubularSegments );\n\t\tradialSegments = Math.floor( radialSegments );\n\n\t\t// buffers\n\n\t\tconst indices = [];\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\n\t\t// helper variables\n\n\t\tconst vertex = new Vector3();\n\t\tconst normal = new Vector3();\n\n\t\tconst P1 = new Vector3();\n\t\tconst P2 = new Vector3();\n\n\t\tconst B = new Vector3();\n\t\tconst T = new Vector3();\n\t\tconst N = new Vector3();\n\n\t\t// generate vertices, normals and uvs\n\n\t\tfor ( let i = 0; i <= tubularSegments; ++ i ) {\n\n\t\t\t// the radian \"u\" is used to calculate the position on the torus curve of the current tubular segment\n\n\t\t\tconst u = i / tubularSegments * p * Math.PI * 2;\n\n\t\t\t// now we calculate two points. P1 is our current position on the curve, P2 is a little farther ahead.\n\t\t\t// these points are used to create a special \"coordinate space\", which is necessary to calculate the correct vertex positions\n\n\t\t\tcalculatePositionOnCurve( u, p, q, radius, P1 );\n\t\t\tcalculatePositionOnCurve( u + 0.01, p, q, radius, P2 );\n\n\t\t\t// calculate orthonormal basis\n\n\t\t\tT.subVectors( P2, P1 );\n\t\t\tN.addVectors( P2, P1 );\n\t\t\tB.crossVectors( T, N );\n\t\t\tN.crossVectors( B, T );\n\n\t\t\t// normalize B, N. T can be ignored, we don't use it\n\n\t\t\tB.normalize();\n\t\t\tN.normalize();\n\n\t\t\tfor ( let j = 0; j <= radialSegments; ++ j ) {\n\n\t\t\t\t// now calculate the vertices. they are nothing more than an extrusion of the torus curve.\n\t\t\t\t// because we extrude a shape in the xy-plane, there is no need to calculate a z-value.\n\n\t\t\t\tconst v = j / radialSegments * Math.PI * 2;\n\t\t\t\tconst cx = - tube * Math.cos( v );\n\t\t\t\tconst cy = tube * Math.sin( v );\n\n\t\t\t\t// now calculate the final vertex position.\n\t\t\t\t// first we orient the extrusion with our basis vectors, then we add it to the current position on the curve\n\n\t\t\t\tvertex.x = P1.x + ( cx * N.x + cy * B.x );\n\t\t\t\tvertex.y = P1.y + ( cx * N.y + cy * B.y );\n\t\t\t\tvertex.z = P1.z + ( cx * N.z + cy * B.z );\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t\t// normal (P1 is always the center/origin of the extrusion, thus we can use it to calculate the normal)\n\n\t\t\t\tnormal.subVectors( vertex, P1 ).normalize();\n\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// uv\n\n\t\t\t\tuvs.push( i / tubularSegments );\n\t\t\t\tuvs.push( j / radialSegments );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// generate indices\n\n\t\tfor ( let j = 1; j <= tubularSegments; j ++ ) {\n\n\t\t\tfor ( let i = 1; i <= radialSegments; i ++ ) {\n\n\t\t\t\t// indices\n\n\t\t\t\tconst a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );\n\t\t\t\tconst b = ( radialSegments + 1 ) * j + ( i - 1 );\n\t\t\t\tconst c = ( radialSegments + 1 ) * j + i;\n\t\t\t\tconst d = ( radialSegments + 1 ) * ( j - 1 ) + i;\n\n\t\t\t\t// faces\n\n\t\t\t\tindices.push( a, b, d );\n\t\t\t\tindices.push( b, c, d );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\t// this function calculates the current position on the torus curve\n\n\t\tfunction calculatePositionOnCurve( u, p, q, radius, position ) {\n\n\t\t\tconst cu = Math.cos( u );\n\t\t\tconst su = Math.sin( u );\n\t\t\tconst quOverP = q / p * u;\n\t\t\tconst cs = Math.cos( quOverP );\n\n\t\t\tposition.x = radius * ( 2 + cs ) * 0.5 * cu;\n\t\t\tposition.y = radius * ( 2 + cs ) * su * 0.5;\n\t\t\tposition.z = radius * Math.sin( quOverP ) * 0.5;\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\treturn new TorusKnotGeometry( data.radius, data.tube, data.tubularSegments, data.radialSegments, data.p, data.q );\n\n\t}\n\n}\n\nclass TubeGeometry extends BufferGeometry {\n\n\tconstructor( 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 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'TubeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tpath: path,\n\t\t\ttubularSegments: tubularSegments,\n\t\t\tradius: radius,\n\t\t\tradialSegments: radialSegments,\n\t\t\tclosed: closed\n\t\t};\n\n\t\tconst frames = path.computeFrenetFrames( tubularSegments, closed );\n\n\t\t// expose internals\n\n\t\tthis.tangents = frames.tangents;\n\t\tthis.normals = frames.normals;\n\t\tthis.binormals = frames.binormals;\n\n\t\t// helper variables\n\n\t\tconst vertex = new Vector3();\n\t\tconst normal = new Vector3();\n\t\tconst uv = new Vector2();\n\t\tlet P = new Vector3();\n\n\t\t// buffer\n\n\t\tconst vertices = [];\n\t\tconst normals = [];\n\t\tconst uvs = [];\n\t\tconst indices = [];\n\n\t\t// create buffer data\n\n\t\tgenerateBufferData();\n\n\t\t// build geometry\n\n\t\tthis.setIndex( indices );\n\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tthis.setAttribute( 'normal', new Float32BufferAttribute( normals, 3 ) );\n\t\tthis.setAttribute( 'uv', new Float32BufferAttribute( uvs, 2 ) );\n\n\t\t// functions\n\n\t\tfunction generateBufferData() {\n\n\t\t\tfor ( let i = 0; i < tubularSegments; i ++ ) {\n\n\t\t\t\tgenerateSegment( i );\n\n\t\t\t}\n\n\t\t\t// if the geometry is not closed, generate the last row of vertices and normals\n\t\t\t// at the regular position on the given path\n\t\t\t//\n\t\t\t// if the geometry is closed, duplicate the first row of vertices and normals (uvs will differ)\n\n\t\t\tgenerateSegment( ( closed === false ) ? tubularSegments : 0 );\n\n\t\t\t// uvs are generated in a separate function.\n\t\t\t// this makes it easy compute correct values for closed geometries\n\n\t\t\tgenerateUVs();\n\n\t\t\t// finally create faces\n\n\t\t\tgenerateIndices();\n\n\t\t}\n\n\t\tfunction generateSegment( i ) {\n\n\t\t\t// we use getPointAt to sample evenly distributed points from the given path\n\n\t\t\tP = path.getPointAt( i / tubularSegments, P );\n\n\t\t\t// retrieve corresponding normal and binormal\n\n\t\t\tconst N = frames.normals[ i ];\n\t\t\tconst B = frames.binormals[ i ];\n\n\t\t\t// generate normals and vertices for the current segment\n\n\t\t\tfor ( let j = 0; j <= radialSegments; j ++ ) {\n\n\t\t\t\tconst v = j / radialSegments * Math.PI * 2;\n\n\t\t\t\tconst sin = Math.sin( v );\n\t\t\t\tconst cos = - Math.cos( v );\n\n\t\t\t\t// normal\n\n\t\t\t\tnormal.x = ( cos * N.x + sin * B.x );\n\t\t\t\tnormal.y = ( cos * N.y + sin * B.y );\n\t\t\t\tnormal.z = ( cos * N.z + sin * B.z );\n\t\t\t\tnormal.normalize();\n\n\t\t\t\tnormals.push( normal.x, normal.y, normal.z );\n\n\t\t\t\t// vertex\n\n\t\t\t\tvertex.x = P.x + radius * normal.x;\n\t\t\t\tvertex.y = P.y + radius * normal.y;\n\t\t\t\tvertex.z = P.z + radius * normal.z;\n\n\t\t\t\tvertices.push( vertex.x, vertex.y, vertex.z );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction generateIndices() {\n\n\t\t\tfor ( let j = 1; j <= tubularSegments; j ++ ) {\n\n\t\t\t\tfor ( let i = 1; i <= radialSegments; i ++ ) {\n\n\t\t\t\t\tconst a = ( radialSegments + 1 ) * ( j - 1 ) + ( i - 1 );\n\t\t\t\t\tconst b = ( radialSegments + 1 ) * j + ( i - 1 );\n\t\t\t\t\tconst c = ( radialSegments + 1 ) * j + i;\n\t\t\t\t\tconst d = ( radialSegments + 1 ) * ( j - 1 ) + i;\n\n\t\t\t\t\t// faces\n\n\t\t\t\t\tindices.push( a, b, d );\n\t\t\t\t\tindices.push( b, c, d );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction generateUVs() {\n\n\t\t\tfor ( let i = 0; i <= tubularSegments; i ++ ) {\n\n\t\t\t\tfor ( let j = 0; j <= radialSegments; j ++ ) {\n\n\t\t\t\t\tuv.x = i / tubularSegments;\n\t\t\t\t\tuv.y = j / radialSegments;\n\n\t\t\t\t\tuvs.push( uv.x, uv.y );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.path = this.parameters.path.toJSON();\n\n\t\treturn data;\n\n\t}\n\n\tstatic fromJSON( data ) {\n\n\t\t// This only works for built-in curves (e.g. CatmullRomCurve3).\n\t\t// User defined curves or instances of CurvePath will not be deserialized.\n\t\treturn new TubeGeometry(\n\t\t\tnew Curves[ data.path.type ]().fromJSON( data.path ),\n\t\t\tdata.tubularSegments,\n\t\t\tdata.radius,\n\t\t\tdata.radialSegments,\n\t\t\tdata.closed\n\t\t);\n\n\t}\n\n}\n\nclass WireframeGeometry extends BufferGeometry {\n\n\tconstructor( geometry = null ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'WireframeGeometry';\n\n\t\tthis.parameters = {\n\t\t\tgeometry: geometry\n\t\t};\n\n\t\tif ( geometry !== null ) {\n\n\t\t\t// buffer\n\n\t\t\tconst vertices = [];\n\t\t\tconst edges = new Set();\n\n\t\t\t// helper variables\n\n\t\t\tconst start = new Vector3();\n\t\t\tconst end = new Vector3();\n\n\t\t\tif ( geometry.index !== null ) {\n\n\t\t\t\t// indexed BufferGeometry\n\n\t\t\t\tconst position = geometry.attributes.position;\n\t\t\t\tconst indices = geometry.index;\n\t\t\t\tlet groups = geometry.groups;\n\n\t\t\t\tif ( groups.length === 0 ) {\n\n\t\t\t\t\tgroups = [ { start: 0, count: indices.count, materialIndex: 0 } ];\n\n\t\t\t\t}\n\n\t\t\t\t// create a data structure that contains all edges without duplicates\n\n\t\t\t\tfor ( let o = 0, ol = groups.length; o < ol; ++ o ) {\n\n\t\t\t\t\tconst group = groups[ o ];\n\n\t\t\t\t\tconst groupStart = group.start;\n\t\t\t\t\tconst groupCount = group.count;\n\n\t\t\t\t\tfor ( let i = groupStart, l = ( groupStart + groupCount ); i < l; i += 3 ) {\n\n\t\t\t\t\t\tfor ( let j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t\t\tconst index1 = indices.getX( i + j );\n\t\t\t\t\t\t\tconst index2 = indices.getX( i + ( j + 1 ) % 3 );\n\n\t\t\t\t\t\t\tstart.fromBufferAttribute( position, index1 );\n\t\t\t\t\t\t\tend.fromBufferAttribute( position, index2 );\n\n\t\t\t\t\t\t\tif ( isUniqueEdge( start, end, edges ) === true ) {\n\n\t\t\t\t\t\t\t\tvertices.push( start.x, start.y, start.z );\n\t\t\t\t\t\t\t\tvertices.push( end.x, end.y, end.z );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\t// non-indexed BufferGeometry\n\n\t\t\t\tconst position = geometry.attributes.position;\n\n\t\t\t\tfor ( let i = 0, l = ( position.count / 3 ); i < l; i ++ ) {\n\n\t\t\t\t\tfor ( let j = 0; j < 3; j ++ ) {\n\n\t\t\t\t\t\t// three edges per triangle, an edge is represented as (index1, index2)\n\t\t\t\t\t\t// e.g. the first triangle has the following edges: (0,1),(1,2),(2,0)\n\n\t\t\t\t\t\tconst index1 = 3 * i + j;\n\t\t\t\t\t\tconst index2 = 3 * i + ( ( j + 1 ) % 3 );\n\n\t\t\t\t\t\tstart.fromBufferAttribute( position, index1 );\n\t\t\t\t\t\tend.fromBufferAttribute( position, index2 );\n\n\t\t\t\t\t\tif ( isUniqueEdge( start, end, edges ) === true ) {\n\n\t\t\t\t\t\t\tvertices.push( start.x, start.y, start.z );\n\t\t\t\t\t\t\tvertices.push( end.x, end.y, end.z );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// build geometry\n\n\t\t\tthis.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.parameters = Object.assign( {}, source.parameters );\n\n\t\treturn this;\n\n\t}\n\n}\n\nfunction isUniqueEdge( start, end, edges ) {\n\n\tconst hash1 = `${start.x},${start.y},${start.z}-${end.x},${end.y},${end.z}`;\n\tconst hash2 = `${end.x},${end.y},${end.z}-${start.x},${start.y},${start.z}`; // coincident edge\n\n\tif ( edges.has( hash1 ) === true || edges.has( hash2 ) === true ) {\n\n\t\treturn false;\n\n\t} else {\n\n\t\tedges.add( hash1 );\n\t\tedges.add( hash2 );\n\t\treturn true;\n\n\t}\n\n}\n\nvar Geometries = /*#__PURE__*/Object.freeze({\n\t__proto__: null,\n\tBoxGeometry: BoxGeometry,\n\tCapsuleGeometry: CapsuleGeometry,\n\tCircleGeometry: CircleGeometry,\n\tConeGeometry: ConeGeometry,\n\tCylinderGeometry: CylinderGeometry,\n\tDodecahedronGeometry: DodecahedronGeometry,\n\tEdgesGeometry: EdgesGeometry,\n\tExtrudeGeometry: ExtrudeGeometry,\n\tIcosahedronGeometry: IcosahedronGeometry,\n\tLatheGeometry: LatheGeometry,\n\tOctahedronGeometry: OctahedronGeometry,\n\tPlaneGeometry: PlaneGeometry,\n\tPolyhedronGeometry: PolyhedronGeometry,\n\tRingGeometry: RingGeometry,\n\tShapeGeometry: ShapeGeometry,\n\tSphereGeometry: SphereGeometry,\n\tTetrahedronGeometry: TetrahedronGeometry,\n\tTorusGeometry: TorusGeometry,\n\tTorusKnotGeometry: TorusKnotGeometry,\n\tTubeGeometry: TubeGeometry,\n\tWireframeGeometry: WireframeGeometry\n});\n\nclass ShadowMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isShadowMaterial = true;\n\n\t\tthis.type = 'ShadowMaterial';\n\n\t\tthis.color = new Color( 0x000000 );\n\t\tthis.transparent = true;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass RawShaderMaterial extends ShaderMaterial {\n\n\tconstructor( parameters ) {\n\n\t\tsuper( parameters );\n\n\t\tthis.isRawShaderMaterial = true;\n\n\t\tthis.type = 'RawShaderMaterial';\n\n\t}\n\n}\n\nclass MeshStandardMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshStandardMaterial = true;\n\n\t\tthis.defines = { 'STANDARD': '' };\n\n\t\tthis.type = 'MeshStandardMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // diffuse\n\t\tthis.roughness = 1.0;\n\t\tthis.metalness = 0.0;\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.emissive = new Color( 0x000000 );\n\t\tthis.emissiveIntensity = 1.0;\n\t\tthis.emissiveMap = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.roughnessMap = null;\n\n\t\tthis.metalnessMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.envMapRotation = new Euler();\n\t\tthis.envMapIntensity = 1.0;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.flatShading = false;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.defines = { 'STANDARD': '' };\n\n\t\tthis.color.copy( source.color );\n\t\tthis.roughness = source.roughness;\n\t\tthis.metalness = source.metalness;\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.emissive.copy( source.emissive );\n\t\tthis.emissiveMap = source.emissiveMap;\n\t\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.roughnessMap = source.roughnessMap;\n\n\t\tthis.metalnessMap = source.metalnessMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.envMapRotation.copy( source.envMapRotation );\n\t\tthis.envMapIntensity = source.envMapIntensity;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.flatShading = source.flatShading;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshPhysicalMaterial extends MeshStandardMaterial {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshPhysicalMaterial = true;\n\n\t\tthis.defines = {\n\n\t\t\t'STANDARD': '',\n\t\t\t'PHYSICAL': ''\n\n\t\t};\n\n\t\tthis.type = 'MeshPhysicalMaterial';\n\n\t\tthis.anisotropyRotation = 0;\n\t\tthis.anisotropyMap = null;\n\n\t\tthis.clearcoatMap = null;\n\t\tthis.clearcoatRoughness = 0.0;\n\t\tthis.clearcoatRoughnessMap = null;\n\t\tthis.clearcoatNormalScale = new Vector2( 1, 1 );\n\t\tthis.clearcoatNormalMap = null;\n\n\t\tthis.ior = 1.5;\n\n\t\tObject.defineProperty( this, 'reflectivity', {\n\t\t\tget: function () {\n\n\t\t\t\treturn ( clamp( 2.5 * ( this.ior - 1 ) / ( this.ior + 1 ), 0, 1 ) );\n\n\t\t\t},\n\t\t\tset: function ( reflectivity ) {\n\n\t\t\t\tthis.ior = ( 1 + 0.4 * reflectivity ) / ( 1 - 0.4 * reflectivity );\n\n\t\t\t}\n\t\t} );\n\n\t\tthis.iridescenceMap = null;\n\t\tthis.iridescenceIOR = 1.3;\n\t\tthis.iridescenceThicknessRange = [ 100, 400 ];\n\t\tthis.iridescenceThicknessMap = null;\n\n\t\tthis.sheenColor = new Color( 0x000000 );\n\t\tthis.sheenColorMap = null;\n\t\tthis.sheenRoughness = 1.0;\n\t\tthis.sheenRoughnessMap = null;\n\n\t\tthis.transmissionMap = null;\n\n\t\tthis.thickness = 0;\n\t\tthis.thicknessMap = null;\n\t\tthis.attenuationDistance = Infinity;\n\t\tthis.attenuationColor = new Color( 1, 1, 1 );\n\n\t\tthis.specularIntensity = 1.0;\n\t\tthis.specularIntensityMap = null;\n\t\tthis.specularColor = new Color( 1, 1, 1 );\n\t\tthis.specularColorMap = null;\n\n\t\tthis._anisotropy = 0;\n\t\tthis._clearcoat = 0;\n\t\tthis._dispersion = 0;\n\t\tthis._iridescence = 0;\n\t\tthis._sheen = 0.0;\n\t\tthis._transmission = 0;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tget anisotropy() {\n\n\t\treturn this._anisotropy;\n\n\t}\n\n\tset anisotropy( value ) {\n\n\t\tif ( this._anisotropy > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._anisotropy = value;\n\n\t}\n\n\tget clearcoat() {\n\n\t\treturn this._clearcoat;\n\n\t}\n\n\tset clearcoat( value ) {\n\n\t\tif ( this._clearcoat > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._clearcoat = value;\n\n\t}\n\n\tget iridescence() {\n\n\t\treturn this._iridescence;\n\n\t}\n\n\tset iridescence( value ) {\n\n\t\tif ( this._iridescence > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._iridescence = value;\n\n\t}\n\n\tget dispersion() {\n\n\t\treturn this._dispersion;\n\n\t}\n\n\tset dispersion( value ) {\n\n\t\tif ( this._dispersion > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._dispersion = value;\n\n\t}\n\n\tget sheen() {\n\n\t\treturn this._sheen;\n\n\t}\n\n\tset sheen( value ) {\n\n\t\tif ( this._sheen > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._sheen = value;\n\n\t}\n\n\tget transmission() {\n\n\t\treturn this._transmission;\n\n\t}\n\n\tset transmission( value ) {\n\n\t\tif ( this._transmission > 0 !== value > 0 ) {\n\n\t\t\tthis.version ++;\n\n\t\t}\n\n\t\tthis._transmission = value;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.defines = {\n\n\t\t\t'STANDARD': '',\n\t\t\t'PHYSICAL': ''\n\n\t\t};\n\n\t\tthis.anisotropy = source.anisotropy;\n\t\tthis.anisotropyRotation = source.anisotropyRotation;\n\t\tthis.anisotropyMap = source.anisotropyMap;\n\n\t\tthis.clearcoat = source.clearcoat;\n\t\tthis.clearcoatMap = source.clearcoatMap;\n\t\tthis.clearcoatRoughness = source.clearcoatRoughness;\n\t\tthis.clearcoatRoughnessMap = source.clearcoatRoughnessMap;\n\t\tthis.clearcoatNormalMap = source.clearcoatNormalMap;\n\t\tthis.clearcoatNormalScale.copy( source.clearcoatNormalScale );\n\n\t\tthis.dispersion = source.dispersion;\n\t\tthis.ior = source.ior;\n\n\t\tthis.iridescence = source.iridescence;\n\t\tthis.iridescenceMap = source.iridescenceMap;\n\t\tthis.iridescenceIOR = source.iridescenceIOR;\n\t\tthis.iridescenceThicknessRange = [ ...source.iridescenceThicknessRange ];\n\t\tthis.iridescenceThicknessMap = source.iridescenceThicknessMap;\n\n\t\tthis.sheen = source.sheen;\n\t\tthis.sheenColor.copy( source.sheenColor );\n\t\tthis.sheenColorMap = source.sheenColorMap;\n\t\tthis.sheenRoughness = source.sheenRoughness;\n\t\tthis.sheenRoughnessMap = source.sheenRoughnessMap;\n\n\t\tthis.transmission = source.transmission;\n\t\tthis.transmissionMap = source.transmissionMap;\n\n\t\tthis.thickness = source.thickness;\n\t\tthis.thicknessMap = source.thicknessMap;\n\t\tthis.attenuationDistance = source.attenuationDistance;\n\t\tthis.attenuationColor.copy( source.attenuationColor );\n\n\t\tthis.specularIntensity = source.specularIntensity;\n\t\tthis.specularIntensityMap = source.specularIntensityMap;\n\t\tthis.specularColor.copy( source.specularColor );\n\t\tthis.specularColorMap = source.specularColorMap;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshPhongMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshPhongMaterial = true;\n\n\t\tthis.type = 'MeshPhongMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // diffuse\n\t\tthis.specular = new Color( 0x111111 );\n\t\tthis.shininess = 30;\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.emissive = new Color( 0x000000 );\n\t\tthis.emissiveIntensity = 1.0;\n\t\tthis.emissiveMap = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.specularMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.envMapRotation = new Euler();\n\t\tthis.combine = MultiplyOperation;\n\t\tthis.reflectivity = 1;\n\t\tthis.refractionRatio = 0.98;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.flatShading = false;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\t\tthis.specular.copy( source.specular );\n\t\tthis.shininess = source.shininess;\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.emissive.copy( source.emissive );\n\t\tthis.emissiveMap = source.emissiveMap;\n\t\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.specularMap = source.specularMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.envMapRotation.copy( source.envMapRotation );\n\t\tthis.combine = source.combine;\n\t\tthis.reflectivity = source.reflectivity;\n\t\tthis.refractionRatio = source.refractionRatio;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.flatShading = source.flatShading;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshToonMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshToonMaterial = true;\n\n\t\tthis.defines = { 'TOON': '' };\n\n\t\tthis.type = 'MeshToonMaterial';\n\n\t\tthis.color = new Color( 0xffffff );\n\n\t\tthis.map = null;\n\t\tthis.gradientMap = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.emissive = new Color( 0x000000 );\n\t\tthis.emissiveIntensity = 1.0;\n\t\tthis.emissiveMap = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\t\tthis.gradientMap = source.gradientMap;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.emissive.copy( source.emissive );\n\t\tthis.emissiveMap = source.emissiveMap;\n\t\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshNormalMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshNormalMaterial = true;\n\n\t\tthis.type = 'MeshNormalMaterial';\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\n\t\tthis.flatShading = false;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\n\t\tthis.flatShading = source.flatShading;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshLambertMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshLambertMaterial = true;\n\n\t\tthis.type = 'MeshLambertMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // diffuse\n\n\t\tthis.map = null;\n\n\t\tthis.lightMap = null;\n\t\tthis.lightMapIntensity = 1.0;\n\n\t\tthis.aoMap = null;\n\t\tthis.aoMapIntensity = 1.0;\n\n\t\tthis.emissive = new Color( 0x000000 );\n\t\tthis.emissiveIntensity = 1.0;\n\t\tthis.emissiveMap = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.specularMap = null;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.envMap = null;\n\t\tthis.envMapRotation = new Euler();\n\t\tthis.combine = MultiplyOperation;\n\t\tthis.reflectivity = 1;\n\t\tthis.refractionRatio = 0.98;\n\n\t\tthis.wireframe = false;\n\t\tthis.wireframeLinewidth = 1;\n\t\tthis.wireframeLinecap = 'round';\n\t\tthis.wireframeLinejoin = 'round';\n\n\t\tthis.flatShading = false;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.map = source.map;\n\n\t\tthis.lightMap = source.lightMap;\n\t\tthis.lightMapIntensity = source.lightMapIntensity;\n\n\t\tthis.aoMap = source.aoMap;\n\t\tthis.aoMapIntensity = source.aoMapIntensity;\n\n\t\tthis.emissive.copy( source.emissive );\n\t\tthis.emissiveMap = source.emissiveMap;\n\t\tthis.emissiveIntensity = source.emissiveIntensity;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.specularMap = source.specularMap;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.envMap = source.envMap;\n\t\tthis.envMapRotation.copy( source.envMapRotation );\n\t\tthis.combine = source.combine;\n\t\tthis.reflectivity = source.reflectivity;\n\t\tthis.refractionRatio = source.refractionRatio;\n\n\t\tthis.wireframe = source.wireframe;\n\t\tthis.wireframeLinewidth = source.wireframeLinewidth;\n\t\tthis.wireframeLinecap = source.wireframeLinecap;\n\t\tthis.wireframeLinejoin = source.wireframeLinejoin;\n\n\t\tthis.flatShading = source.flatShading;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass MeshMatcapMaterial extends Material {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isMeshMatcapMaterial = true;\n\n\t\tthis.defines = { 'MATCAP': '' };\n\n\t\tthis.type = 'MeshMatcapMaterial';\n\n\t\tthis.color = new Color( 0xffffff ); // diffuse\n\n\t\tthis.matcap = null;\n\n\t\tthis.map = null;\n\n\t\tthis.bumpMap = null;\n\t\tthis.bumpScale = 1;\n\n\t\tthis.normalMap = null;\n\t\tthis.normalMapType = TangentSpaceNormalMap;\n\t\tthis.normalScale = new Vector2( 1, 1 );\n\n\t\tthis.displacementMap = null;\n\t\tthis.displacementScale = 1;\n\t\tthis.displacementBias = 0;\n\n\t\tthis.alphaMap = null;\n\n\t\tthis.flatShading = false;\n\n\t\tthis.fog = true;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.defines = { 'MATCAP': '' };\n\n\t\tthis.color.copy( source.color );\n\n\t\tthis.matcap = source.matcap;\n\n\t\tthis.map = source.map;\n\n\t\tthis.bumpMap = source.bumpMap;\n\t\tthis.bumpScale = source.bumpScale;\n\n\t\tthis.normalMap = source.normalMap;\n\t\tthis.normalMapType = source.normalMapType;\n\t\tthis.normalScale.copy( source.normalScale );\n\n\t\tthis.displacementMap = source.displacementMap;\n\t\tthis.displacementScale = source.displacementScale;\n\t\tthis.displacementBias = source.displacementBias;\n\n\t\tthis.alphaMap = source.alphaMap;\n\n\t\tthis.flatShading = source.flatShading;\n\n\t\tthis.fog = source.fog;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass LineDashedMaterial extends LineBasicMaterial {\n\n\tconstructor( parameters ) {\n\n\t\tsuper();\n\n\t\tthis.isLineDashedMaterial = true;\n\n\t\tthis.type = 'LineDashedMaterial';\n\n\t\tthis.scale = 1;\n\t\tthis.dashSize = 3;\n\t\tthis.gapSize = 1;\n\n\t\tthis.setValues( parameters );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.scale = source.scale;\n\t\tthis.dashSize = source.dashSize;\n\t\tthis.gapSize = source.gapSize;\n\n\t\treturn this;\n\n\t}\n\n}\n\n// converts an array to a specific type\nfunction convertArray( array, type, forceClone ) {\n\n\tif ( ! array || // let 'undefined' and 'null' pass\n\t\t! forceClone && array.constructor === type ) return array;\n\n\tif ( typeof type.BYTES_PER_ELEMENT === 'number' ) {\n\n\t\treturn new type( array ); // create typed array\n\n\t}\n\n\treturn Array.prototype.slice.call( array ); // create Array\n\n}\n\nfunction isTypedArray( object ) {\n\n\treturn ArrayBuffer.isView( object ) &&\n\t\t! ( object instanceof DataView );\n\n}\n\n// returns an array by which times and values can be sorted\nfunction getKeyframeOrder( times ) {\n\n\tfunction compareTime( i, j ) {\n\n\t\treturn times[ i ] - times[ j ];\n\n\t}\n\n\tconst n = times.length;\n\tconst result = new Array( n );\n\tfor ( let i = 0; i !== n; ++ i ) result[ i ] = i;\n\n\tresult.sort( compareTime );\n\n\treturn result;\n\n}\n\n// uses the array previously returned by 'getKeyframeOrder' to sort data\nfunction sortedArray( values, stride, order ) {\n\n\tconst nValues = values.length;\n\tconst result = new values.constructor( nValues );\n\n\tfor ( let i = 0, dstOffset = 0; dstOffset !== nValues; ++ i ) {\n\n\t\tconst srcOffset = order[ i ] * stride;\n\n\t\tfor ( let j = 0; j !== stride; ++ j ) {\n\n\t\t\tresult[ dstOffset ++ ] = values[ srcOffset + j ];\n\n\t\t}\n\n\t}\n\n\treturn result;\n\n}\n\n// function for parsing AOS keyframe formats\nfunction flattenJSON( jsonKeys, times, values, valuePropertyName ) {\n\n\tlet i = 1, key = jsonKeys[ 0 ];\n\n\twhile ( key !== undefined && key[ valuePropertyName ] === undefined ) {\n\n\t\tkey = jsonKeys[ i ++ ];\n\n\t}\n\n\tif ( key === undefined ) return; // no data\n\n\tlet value = key[ valuePropertyName ];\n\tif ( value === undefined ) return; // no data\n\n\tif ( Array.isArray( value ) ) {\n\n\t\tdo {\n\n\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\tif ( value !== undefined ) {\n\n\t\t\t\ttimes.push( key.time );\n\t\t\t\tvalues.push.apply( values, value ); // push all elements\n\n\t\t\t}\n\n\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t} while ( key !== undefined );\n\n\t} else if ( value.toArray !== undefined ) {\n\n\t\t// ...assume THREE.Math-ish\n\n\t\tdo {\n\n\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\tif ( value !== undefined ) {\n\n\t\t\t\ttimes.push( key.time );\n\t\t\t\tvalue.toArray( values, values.length );\n\n\t\t\t}\n\n\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t} while ( key !== undefined );\n\n\t} else {\n\n\t\t// otherwise push as-is\n\n\t\tdo {\n\n\t\t\tvalue = key[ valuePropertyName ];\n\n\t\t\tif ( value !== undefined ) {\n\n\t\t\t\ttimes.push( key.time );\n\t\t\t\tvalues.push( value );\n\n\t\t\t}\n\n\t\t\tkey = jsonKeys[ i ++ ];\n\n\t\t} while ( key !== undefined );\n\n\t}\n\n}\n\nfunction subclip( sourceClip, name, startFrame, endFrame, fps = 30 ) {\n\n\tconst clip = sourceClip.clone();\n\n\tclip.name = name;\n\n\tconst tracks = [];\n\n\tfor ( let i = 0; i < clip.tracks.length; ++ i ) {\n\n\t\tconst track = clip.tracks[ i ];\n\t\tconst valueSize = track.getValueSize();\n\n\t\tconst times = [];\n\t\tconst values = [];\n\n\t\tfor ( let j = 0; j < track.times.length; ++ j ) {\n\n\t\t\tconst frame = track.times[ j ] * fps;\n\n\t\t\tif ( frame < startFrame || frame >= endFrame ) continue;\n\n\t\t\ttimes.push( track.times[ j ] );\n\n\t\t\tfor ( let k = 0; k < valueSize; ++ k ) {\n\n\t\t\t\tvalues.push( track.values[ j * valueSize + k ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( times.length === 0 ) continue;\n\n\t\ttrack.times = convertArray( times, track.times.constructor );\n\t\ttrack.values = convertArray( values, track.values.constructor );\n\n\t\ttracks.push( track );\n\n\t}\n\n\tclip.tracks = tracks;\n\n\t// find minimum .times value across all tracks in the trimmed clip\n\n\tlet minStartTime = Infinity;\n\n\tfor ( let i = 0; i < clip.tracks.length; ++ i ) {\n\n\t\tif ( minStartTime > clip.tracks[ i ].times[ 0 ] ) {\n\n\t\t\tminStartTime = clip.tracks[ i ].times[ 0 ];\n\n\t\t}\n\n\t}\n\n\t// shift all tracks such that clip begins at t=0\n\n\tfor ( let i = 0; i < clip.tracks.length; ++ i ) {\n\n\t\tclip.tracks[ i ].shift( - 1 * minStartTime );\n\n\t}\n\n\tclip.resetDuration();\n\n\treturn clip;\n\n}\n\nfunction makeClipAdditive( targetClip, referenceFrame = 0, referenceClip = targetClip, fps = 30 ) {\n\n\tif ( fps <= 0 ) fps = 30;\n\n\tconst numTracks = referenceClip.tracks.length;\n\tconst referenceTime = referenceFrame / fps;\n\n\t// Make each track's values relative to the values at the reference frame\n\tfor ( let i = 0; i < numTracks; ++ i ) {\n\n\t\tconst referenceTrack = referenceClip.tracks[ i ];\n\t\tconst referenceTrackType = referenceTrack.ValueTypeName;\n\n\t\t// Skip this track if it's non-numeric\n\t\tif ( referenceTrackType === 'bool' || referenceTrackType === 'string' ) continue;\n\n\t\t// Find the track in the target clip whose name and type matches the reference track\n\t\tconst targetTrack = targetClip.tracks.find( function ( track ) {\n\n\t\t\treturn track.name === referenceTrack.name\n\t\t\t\t&& track.ValueTypeName === referenceTrackType;\n\n\t\t} );\n\n\t\tif ( targetTrack === undefined ) continue;\n\n\t\tlet referenceOffset = 0;\n\t\tconst referenceValueSize = referenceTrack.getValueSize();\n\n\t\tif ( referenceTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {\n\n\t\t\treferenceOffset = referenceValueSize / 3;\n\n\t\t}\n\n\t\tlet targetOffset = 0;\n\t\tconst targetValueSize = targetTrack.getValueSize();\n\n\t\tif ( targetTrack.createInterpolant.isInterpolantFactoryMethodGLTFCubicSpline ) {\n\n\t\t\ttargetOffset = targetValueSize / 3;\n\n\t\t}\n\n\t\tconst lastIndex = referenceTrack.times.length - 1;\n\t\tlet referenceValue;\n\n\t\t// Find the value to subtract out of the track\n\t\tif ( referenceTime <= referenceTrack.times[ 0 ] ) {\n\n\t\t\t// Reference frame is earlier than the first keyframe, so just use the first keyframe\n\t\t\tconst startIndex = referenceOffset;\n\t\t\tconst endIndex = referenceValueSize - referenceOffset;\n\t\t\treferenceValue = referenceTrack.values.slice( startIndex, endIndex );\n\n\t\t} else if ( referenceTime >= referenceTrack.times[ lastIndex ] ) {\n\n\t\t\t// Reference frame is after the last keyframe, so just use the last keyframe\n\t\t\tconst startIndex = lastIndex * referenceValueSize + referenceOffset;\n\t\t\tconst endIndex = startIndex + referenceValueSize - referenceOffset;\n\t\t\treferenceValue = referenceTrack.values.slice( startIndex, endIndex );\n\n\t\t} else {\n\n\t\t\t// Interpolate to the reference value\n\t\t\tconst interpolant = referenceTrack.createInterpolant();\n\t\t\tconst startIndex = referenceOffset;\n\t\t\tconst endIndex = referenceValueSize - referenceOffset;\n\t\t\tinterpolant.evaluate( referenceTime );\n\t\t\treferenceValue = interpolant.resultBuffer.slice( startIndex, endIndex );\n\n\t\t}\n\n\t\t// Conjugate the quaternion\n\t\tif ( referenceTrackType === 'quaternion' ) {\n\n\t\t\tconst referenceQuat = new Quaternion().fromArray( referenceValue ).normalize().conjugate();\n\t\t\treferenceQuat.toArray( referenceValue );\n\n\t\t}\n\n\t\t// Subtract the reference value from all of the track values\n\n\t\tconst numTimes = targetTrack.times.length;\n\t\tfor ( let j = 0; j < numTimes; ++ j ) {\n\n\t\t\tconst valueStart = j * targetValueSize + targetOffset;\n\n\t\t\tif ( referenceTrackType === 'quaternion' ) {\n\n\t\t\t\t// Multiply the conjugate for quaternion track types\n\t\t\t\tQuaternion.multiplyQuaternionsFlat(\n\t\t\t\t\ttargetTrack.values,\n\t\t\t\t\tvalueStart,\n\t\t\t\t\treferenceValue,\n\t\t\t\t\t0,\n\t\t\t\t\ttargetTrack.values,\n\t\t\t\t\tvalueStart\n\t\t\t\t);\n\n\t\t\t} else {\n\n\t\t\t\tconst valueEnd = targetValueSize - targetOffset * 2;\n\n\t\t\t\t// Subtract each value for all other numeric track types\n\t\t\t\tfor ( let k = 0; k < valueEnd; ++ k ) {\n\n\t\t\t\t\ttargetTrack.values[ valueStart + k ] -= referenceValue[ k ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\ttargetClip.blendMode = AdditiveAnimationBlendMode;\n\n\treturn targetClip;\n\n}\n\nconst AnimationUtils = {\n\tconvertArray: convertArray,\n\tisTypedArray: isTypedArray,\n\tgetKeyframeOrder: getKeyframeOrder,\n\tsortedArray: sortedArray,\n\tflattenJSON: flattenJSON,\n\tsubclip: subclip,\n\tmakeClipAdditive: makeClipAdditive\n};\n\n/**\n * Abstract base class of interpolants over parametric samples.\n *\n * The parameter domain is one dimensional, typically the time or a path\n * along a curve defined by the data.\n *\n * The sample values can have any dimensionality and derived classes may\n * apply special interpretations to the data.\n *\n * This class provides the interval seek in a Template Method, deferring\n * the actual interpolation to derived classes.\n *\n * Time complexity is O(1) for linear access crossing at most two points\n * and O(log N) for random access, where N is the number of positions.\n *\n * References:\n *\n * \t\thttp://www.oodesign.com/template-method-pattern.html\n *\n */\n\nclass Interpolant {\n\n\tconstructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tthis.parameterPositions = parameterPositions;\n\t\tthis._cachedIndex = 0;\n\n\t\tthis.resultBuffer = resultBuffer !== undefined ?\n\t\t\tresultBuffer : new sampleValues.constructor( sampleSize );\n\t\tthis.sampleValues = sampleValues;\n\t\tthis.valueSize = sampleSize;\n\n\t\tthis.settings = null;\n\t\tthis.DefaultSettings_ = {};\n\n\t}\n\n\tevaluate( t ) {\n\n\t\tconst pp = this.parameterPositions;\n\t\tlet i1 = this._cachedIndex,\n\t\t\tt1 = pp[ i1 ],\n\t\t\tt0 = pp[ i1 - 1 ];\n\n\t\tvalidate_interval: {\n\n\t\t\tseek: {\n\n\t\t\t\tlet right;\n\n\t\t\t\tlinear_scan: {\n\n\t\t\t\t\t//- See http://jsperf.com/comparison-to-undefined/3\n\t\t\t\t\t//- slower code:\n\t\t\t\t\t//-\n\t\t\t\t\t//- \t\t\t\tif ( t >= t1 || t1 === undefined ) {\n\t\t\t\t\tforward_scan: if ( ! ( t < t1 ) ) {\n\n\t\t\t\t\t\tfor ( let giveUpAt = i1 + 2; ; ) {\n\n\t\t\t\t\t\t\tif ( t1 === undefined ) {\n\n\t\t\t\t\t\t\t\tif ( t < t0 ) break forward_scan;\n\n\t\t\t\t\t\t\t\t// after end\n\n\t\t\t\t\t\t\t\ti1 = pp.length;\n\t\t\t\t\t\t\t\tthis._cachedIndex = i1;\n\t\t\t\t\t\t\t\treturn this.copySampleValue_( i1 - 1 );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( i1 === giveUpAt ) break; // this loop\n\n\t\t\t\t\t\t\tt0 = t1;\n\t\t\t\t\t\t\tt1 = pp[ ++ i1 ];\n\n\t\t\t\t\t\t\tif ( t < t1 ) {\n\n\t\t\t\t\t\t\t\t// we have arrived at the sought interval\n\t\t\t\t\t\t\t\tbreak seek;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// prepare binary search on the right side of the index\n\t\t\t\t\t\tright = pp.length;\n\t\t\t\t\t\tbreak linear_scan;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t//- slower code:\n\t\t\t\t\t//-\t\t\t\t\tif ( t < t0 || t0 === undefined ) {\n\t\t\t\t\tif ( ! ( t >= t0 ) ) {\n\n\t\t\t\t\t\t// looping?\n\n\t\t\t\t\t\tconst t1global = pp[ 1 ];\n\n\t\t\t\t\t\tif ( t < t1global ) {\n\n\t\t\t\t\t\t\ti1 = 2; // + 1, using the scan for the details\n\t\t\t\t\t\t\tt0 = t1global;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// linear reverse scan\n\n\t\t\t\t\t\tfor ( let giveUpAt = i1 - 2; ; ) {\n\n\t\t\t\t\t\t\tif ( t0 === undefined ) {\n\n\t\t\t\t\t\t\t\t// before start\n\n\t\t\t\t\t\t\t\tthis._cachedIndex = 0;\n\t\t\t\t\t\t\t\treturn this.copySampleValue_( 0 );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tif ( i1 === giveUpAt ) break; // this loop\n\n\t\t\t\t\t\t\tt1 = t0;\n\t\t\t\t\t\t\tt0 = pp[ -- i1 - 1 ];\n\n\t\t\t\t\t\t\tif ( t >= t0 ) {\n\n\t\t\t\t\t\t\t\t// we have arrived at the sought interval\n\t\t\t\t\t\t\t\tbreak seek;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\t// prepare binary search on the left side of the index\n\t\t\t\t\t\tright = i1;\n\t\t\t\t\t\ti1 = 0;\n\t\t\t\t\t\tbreak linear_scan;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// the interval is valid\n\n\t\t\t\t\tbreak validate_interval;\n\n\t\t\t\t} // linear scan\n\n\t\t\t\t// binary search\n\n\t\t\t\twhile ( i1 < right ) {\n\n\t\t\t\t\tconst mid = ( i1 + right ) >>> 1;\n\n\t\t\t\t\tif ( t < pp[ mid ] ) {\n\n\t\t\t\t\t\tright = mid;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ti1 = mid + 1;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tt1 = pp[ i1 ];\n\t\t\t\tt0 = pp[ i1 - 1 ];\n\n\t\t\t\t// check boundary cases, again\n\n\t\t\t\tif ( t0 === undefined ) {\n\n\t\t\t\t\tthis._cachedIndex = 0;\n\t\t\t\t\treturn this.copySampleValue_( 0 );\n\n\t\t\t\t}\n\n\t\t\t\tif ( t1 === undefined ) {\n\n\t\t\t\t\ti1 = pp.length;\n\t\t\t\t\tthis._cachedIndex = i1;\n\t\t\t\t\treturn this.copySampleValue_( i1 - 1 );\n\n\t\t\t\t}\n\n\t\t\t} // seek\n\n\t\t\tthis._cachedIndex = i1;\n\n\t\t\tthis.intervalChanged_( i1, t0, t1 );\n\n\t\t} // validate_interval\n\n\t\treturn this.interpolate_( i1, t0, t, t1 );\n\n\t}\n\n\tgetSettings_() {\n\n\t\treturn this.settings || this.DefaultSettings_;\n\n\t}\n\n\tcopySampleValue_( index ) {\n\n\t\t// copies a sample value to the result buffer\n\n\t\tconst result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\t\t\toffset = index * stride;\n\n\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\tresult[ i ] = values[ offset + i ];\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n\t// Template methods for derived classes:\n\n\tinterpolate_( /* i1, t0, t, t1 */ ) {\n\n\t\tthrow new Error( 'call to abstract method' );\n\t\t// implementations shall return this.resultBuffer\n\n\t}\n\n\tintervalChanged_( /* i1, t0, t1 */ ) {\n\n\t\t// empty\n\n\t}\n\n}\n\n/**\n * Fast and simple cubic spline interpolant.\n *\n * It was derived from a Hermitian construction setting the first derivative\n * at each sample position to the linear slope between neighboring positions\n * over their parameter interval.\n */\n\nclass CubicInterpolant extends Interpolant {\n\n\tconstructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tsuper( parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t\tthis._weightPrev = - 0;\n\t\tthis._offsetPrev = - 0;\n\t\tthis._weightNext = - 0;\n\t\tthis._offsetNext = - 0;\n\n\t\tthis.DefaultSettings_ = {\n\n\t\t\tendingStart: ZeroCurvatureEnding,\n\t\t\tendingEnd: ZeroCurvatureEnding\n\n\t\t};\n\n\t}\n\n\tintervalChanged_( i1, t0, t1 ) {\n\n\t\tconst pp = this.parameterPositions;\n\t\tlet iPrev = i1 - 2,\n\t\t\tiNext = i1 + 1,\n\n\t\t\ttPrev = pp[ iPrev ],\n\t\t\ttNext = pp[ iNext ];\n\n\t\tif ( tPrev === undefined ) {\n\n\t\t\tswitch ( this.getSettings_().endingStart ) {\n\n\t\t\t\tcase ZeroSlopeEnding:\n\n\t\t\t\t\t// f'(t0) = 0\n\t\t\t\t\tiPrev = i1;\n\t\t\t\t\ttPrev = 2 * t0 - t1;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase WrapAroundEnding:\n\n\t\t\t\t\t// use the other end of the curve\n\t\t\t\t\tiPrev = pp.length - 2;\n\t\t\t\t\ttPrev = t0 + pp[ iPrev ] - pp[ iPrev + 1 ];\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault: // ZeroCurvatureEnding\n\n\t\t\t\t\t// f''(t0) = 0 a.k.a. Natural Spline\n\t\t\t\t\tiPrev = i1;\n\t\t\t\t\ttPrev = t1;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( tNext === undefined ) {\n\n\t\t\tswitch ( this.getSettings_().endingEnd ) {\n\n\t\t\t\tcase ZeroSlopeEnding:\n\n\t\t\t\t\t// f'(tN) = 0\n\t\t\t\t\tiNext = i1;\n\t\t\t\t\ttNext = 2 * t1 - t0;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase WrapAroundEnding:\n\n\t\t\t\t\t// use the other end of the curve\n\t\t\t\t\tiNext = 1;\n\t\t\t\t\ttNext = t1 + pp[ 1 ] - pp[ 0 ];\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault: // ZeroCurvatureEnding\n\n\t\t\t\t\t// f''(tN) = 0, a.k.a. Natural Spline\n\t\t\t\t\tiNext = i1 - 1;\n\t\t\t\t\ttNext = t0;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst halfDt = ( t1 - t0 ) * 0.5,\n\t\t\tstride = this.valueSize;\n\n\t\tthis._weightPrev = halfDt / ( t0 - tPrev );\n\t\tthis._weightNext = halfDt / ( tNext - t1 );\n\t\tthis._offsetPrev = iPrev * stride;\n\t\tthis._offsetNext = iNext * stride;\n\n\t}\n\n\tinterpolate_( i1, t0, t, t1 ) {\n\n\t\tconst result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\n\t\t\to1 = i1 * stride,\t\to0 = o1 - stride,\n\t\t\toP = this._offsetPrev, \toN = this._offsetNext,\n\t\t\twP = this._weightPrev,\twN = this._weightNext,\n\n\t\t\tp = ( t - t0 ) / ( t1 - t0 ),\n\t\t\tpp = p * p,\n\t\t\tppp = pp * p;\n\n\t\t// evaluate polynomials\n\n\t\tconst sP = - wP * ppp + 2 * wP * pp - wP * p;\n\t\tconst s0 = ( 1 + wP ) * ppp + ( - 1.5 - 2 * wP ) * pp + ( - 0.5 + wP ) * p + 1;\n\t\tconst s1 = ( - 1 - wN ) * ppp + ( 1.5 + wN ) * pp + 0.5 * p;\n\t\tconst sN = wN * ppp - wN * pp;\n\n\t\t// combine data linearly\n\n\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\tresult[ i ] =\n\t\t\t\t\tsP * values[ oP + i ] +\n\t\t\t\t\ts0 * values[ o0 + i ] +\n\t\t\t\t\ts1 * values[ o1 + i ] +\n\t\t\t\t\tsN * values[ oN + i ];\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n}\n\nclass LinearInterpolant extends Interpolant {\n\n\tconstructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tsuper( parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t}\n\n\tinterpolate_( i1, t0, t, t1 ) {\n\n\t\tconst result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\n\t\t\toffset1 = i1 * stride,\n\t\t\toffset0 = offset1 - stride,\n\n\t\t\tweight1 = ( t - t0 ) / ( t1 - t0 ),\n\t\t\tweight0 = 1 - weight1;\n\n\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\tresult[ i ] =\n\t\t\t\t\tvalues[ offset0 + i ] * weight0 +\n\t\t\t\t\tvalues[ offset1 + i ] * weight1;\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n}\n\n/**\n *\n * Interpolant that evaluates to the sample value at the position preceding\n * the parameter.\n */\n\nclass DiscreteInterpolant extends Interpolant {\n\n\tconstructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tsuper( parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t}\n\n\tinterpolate_( i1 /*, t0, t, t1 */ ) {\n\n\t\treturn this.copySampleValue_( i1 - 1 );\n\n\t}\n\n}\n\nclass KeyframeTrack {\n\n\tconstructor( name, times, values, interpolation ) {\n\n\t\tif ( name === undefined ) throw new Error( 'THREE.KeyframeTrack: track name is undefined' );\n\t\tif ( times === undefined || times.length === 0 ) throw new Error( 'THREE.KeyframeTrack: no keyframes in track named ' + name );\n\n\t\tthis.name = name;\n\n\t\tthis.times = convertArray( times, this.TimeBufferType );\n\t\tthis.values = convertArray( values, this.ValueBufferType );\n\n\t\tthis.setInterpolation( interpolation || this.DefaultInterpolation );\n\n\t}\n\n\t// Serialization (in static context, because of constructor invocation\n\t// and automatic invocation of .toJSON):\n\n\tstatic toJSON( track ) {\n\n\t\tconst trackType = track.constructor;\n\n\t\tlet json;\n\n\t\t// derived classes can define a static toJSON method\n\t\tif ( trackType.toJSON !== this.toJSON ) {\n\n\t\t\tjson = trackType.toJSON( track );\n\n\t\t} else {\n\n\t\t\t// by default, we assume the data can be serialized as-is\n\t\t\tjson = {\n\n\t\t\t\t'name': track.name,\n\t\t\t\t'times': convertArray( track.times, Array ),\n\t\t\t\t'values': convertArray( track.values, Array )\n\n\t\t\t};\n\n\t\t\tconst interpolation = track.getInterpolation();\n\n\t\t\tif ( interpolation !== track.DefaultInterpolation ) {\n\n\t\t\t\tjson.interpolation = interpolation;\n\n\t\t\t}\n\n\t\t}\n\n\t\tjson.type = track.ValueTypeName; // mandatory\n\n\t\treturn json;\n\n\t}\n\n\tInterpolantFactoryMethodDiscrete( result ) {\n\n\t\treturn new DiscreteInterpolant( this.times, this.values, this.getValueSize(), result );\n\n\t}\n\n\tInterpolantFactoryMethodLinear( result ) {\n\n\t\treturn new LinearInterpolant( this.times, this.values, this.getValueSize(), result );\n\n\t}\n\n\tInterpolantFactoryMethodSmooth( result ) {\n\n\t\treturn new CubicInterpolant( this.times, this.values, this.getValueSize(), result );\n\n\t}\n\n\tsetInterpolation( interpolation ) {\n\n\t\tlet factoryMethod;\n\n\t\tswitch ( interpolation ) {\n\n\t\t\tcase InterpolateDiscrete:\n\n\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodDiscrete;\n\n\t\t\t\tbreak;\n\n\t\t\tcase InterpolateLinear:\n\n\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodLinear;\n\n\t\t\t\tbreak;\n\n\t\t\tcase InterpolateSmooth:\n\n\t\t\t\tfactoryMethod = this.InterpolantFactoryMethodSmooth;\n\n\t\t\t\tbreak;\n\n\t\t}\n\n\t\tif ( factoryMethod === undefined ) {\n\n\t\t\tconst message = 'unsupported interpolation for ' +\n\t\t\t\tthis.ValueTypeName + ' keyframe track named ' + this.name;\n\n\t\t\tif ( this.createInterpolant === undefined ) {\n\n\t\t\t\t// fall back to default, unless the default itself is messed up\n\t\t\t\tif ( interpolation !== this.DefaultInterpolation ) {\n\n\t\t\t\t\tthis.setInterpolation( this.DefaultInterpolation );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthrow new Error( message ); // fatal, in this case\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tconsole.warn( 'THREE.KeyframeTrack:', message );\n\t\t\treturn this;\n\n\t\t}\n\n\t\tthis.createInterpolant = factoryMethod;\n\n\t\treturn this;\n\n\t}\n\n\tgetInterpolation() {\n\n\t\tswitch ( this.createInterpolant ) {\n\n\t\t\tcase this.InterpolantFactoryMethodDiscrete:\n\n\t\t\t\treturn InterpolateDiscrete;\n\n\t\t\tcase this.InterpolantFactoryMethodLinear:\n\n\t\t\t\treturn InterpolateLinear;\n\n\t\t\tcase this.InterpolantFactoryMethodSmooth:\n\n\t\t\t\treturn InterpolateSmooth;\n\n\t\t}\n\n\t}\n\n\tgetValueSize() {\n\n\t\treturn this.values.length / this.times.length;\n\n\t}\n\n\t// move all keyframes either forwards or backwards in time\n\tshift( timeOffset ) {\n\n\t\tif ( timeOffset !== 0.0 ) {\n\n\t\t\tconst times = this.times;\n\n\t\t\tfor ( let i = 0, n = times.length; i !== n; ++ i ) {\n\n\t\t\t\ttimes[ i ] += timeOffset;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// scale all keyframe times by a factor (useful for frame <-> seconds conversions)\n\tscale( timeScale ) {\n\n\t\tif ( timeScale !== 1.0 ) {\n\n\t\t\tconst times = this.times;\n\n\t\t\tfor ( let i = 0, n = times.length; i !== n; ++ i ) {\n\n\t\t\t\ttimes[ i ] *= timeScale;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// removes keyframes before and after animation without changing any values within the range [startTime, endTime].\n\t// IMPORTANT: We do not shift around keys to the start of the track time, because for interpolated keys this will change their values\n\ttrim( startTime, endTime ) {\n\n\t\tconst times = this.times,\n\t\t\tnKeys = times.length;\n\n\t\tlet from = 0,\n\t\t\tto = nKeys - 1;\n\n\t\twhile ( from !== nKeys && times[ from ] < startTime ) {\n\n\t\t\t++ from;\n\n\t\t}\n\n\t\twhile ( to !== - 1 && times[ to ] > endTime ) {\n\n\t\t\t-- to;\n\n\t\t}\n\n\t\t++ to; // inclusive -> exclusive bound\n\n\t\tif ( from !== 0 || to !== nKeys ) {\n\n\t\t\t// empty tracks are forbidden, so keep at least one keyframe\n\t\t\tif ( from >= to ) {\n\n\t\t\t\tto = Math.max( to, 1 );\n\t\t\t\tfrom = to - 1;\n\n\t\t\t}\n\n\t\t\tconst stride = this.getValueSize();\n\t\t\tthis.times = times.slice( from, to );\n\t\t\tthis.values = this.values.slice( from * stride, to * stride );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// ensure we do not get a GarbageInGarbageOut situation, make sure tracks are at least minimally viable\n\tvalidate() {\n\n\t\tlet valid = true;\n\n\t\tconst valueSize = this.getValueSize();\n\t\tif ( valueSize - Math.floor( valueSize ) !== 0 ) {\n\n\t\t\tconsole.error( 'THREE.KeyframeTrack: Invalid value size in track.', this );\n\t\t\tvalid = false;\n\n\t\t}\n\n\t\tconst times = this.times,\n\t\t\tvalues = this.values,\n\n\t\t\tnKeys = times.length;\n\n\t\tif ( nKeys === 0 ) {\n\n\t\t\tconsole.error( 'THREE.KeyframeTrack: Track is empty.', this );\n\t\t\tvalid = false;\n\n\t\t}\n\n\t\tlet prevTime = null;\n\n\t\tfor ( let i = 0; i !== nKeys; i ++ ) {\n\n\t\t\tconst currTime = times[ i ];\n\n\t\t\tif ( typeof currTime === 'number' && isNaN( currTime ) ) {\n\n\t\t\t\tconsole.error( 'THREE.KeyframeTrack: Time is not a valid number.', this, i, currTime );\n\t\t\t\tvalid = false;\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( prevTime !== null && prevTime > currTime ) {\n\n\t\t\t\tconsole.error( 'THREE.KeyframeTrack: Out of order keys.', this, i, currTime, prevTime );\n\t\t\t\tvalid = false;\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tprevTime = currTime;\n\n\t\t}\n\n\t\tif ( values !== undefined ) {\n\n\t\t\tif ( isTypedArray( values ) ) {\n\n\t\t\t\tfor ( let i = 0, n = values.length; i !== n; ++ i ) {\n\n\t\t\t\t\tconst value = values[ i ];\n\n\t\t\t\t\tif ( isNaN( value ) ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.KeyframeTrack: Value is not a valid number.', this, i, value );\n\t\t\t\t\t\tvalid = false;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn valid;\n\n\t}\n\n\t// removes equivalent sequential keys as common in morph target sequences\n\t// (0,0,0,0,1,1,1,0,0,0,0,0,0,0) --\x3e (0,0,1,1,0,0)\n\toptimize() {\n\n\t\t// times or values may be shared with other tracks, so overwriting is unsafe\n\t\tconst times = this.times.slice(),\n\t\t\tvalues = this.values.slice(),\n\t\t\tstride = this.getValueSize(),\n\n\t\t\tsmoothInterpolation = this.getInterpolation() === InterpolateSmooth,\n\n\t\t\tlastIndex = times.length - 1;\n\n\t\tlet writeIndex = 1;\n\n\t\tfor ( let i = 1; i < lastIndex; ++ i ) {\n\n\t\t\tlet keep = false;\n\n\t\t\tconst time = times[ i ];\n\t\t\tconst timeNext = times[ i + 1 ];\n\n\t\t\t// remove adjacent keyframes scheduled at the same time\n\n\t\t\tif ( time !== timeNext && ( i !== 1 || time !== times[ 0 ] ) ) {\n\n\t\t\t\tif ( ! smoothInterpolation ) {\n\n\t\t\t\t\t// remove unnecessary keyframes same as their neighbors\n\n\t\t\t\t\tconst offset = i * stride,\n\t\t\t\t\t\toffsetP = offset - stride,\n\t\t\t\t\t\toffsetN = offset + stride;\n\n\t\t\t\t\tfor ( let j = 0; j !== stride; ++ j ) {\n\n\t\t\t\t\t\tconst value = values[ offset + j ];\n\n\t\t\t\t\t\tif ( value !== values[ offsetP + j ] ||\n\t\t\t\t\t\t\tvalue !== values[ offsetN + j ] ) {\n\n\t\t\t\t\t\t\tkeep = true;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\tkeep = true;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\t// in-place compaction\n\n\t\t\tif ( keep ) {\n\n\t\t\t\tif ( i !== writeIndex ) {\n\n\t\t\t\t\ttimes[ writeIndex ] = times[ i ];\n\n\t\t\t\t\tconst readOffset = i * stride,\n\t\t\t\t\t\twriteOffset = writeIndex * stride;\n\n\t\t\t\t\tfor ( let j = 0; j !== stride; ++ j ) {\n\n\t\t\t\t\t\tvalues[ writeOffset + j ] = values[ readOffset + j ];\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t++ writeIndex;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// flush last keyframe (compaction looks ahead)\n\n\t\tif ( lastIndex > 0 ) {\n\n\t\t\ttimes[ writeIndex ] = times[ lastIndex ];\n\n\t\t\tfor ( let readOffset = lastIndex * stride, writeOffset = writeIndex * stride, j = 0; j !== stride; ++ j ) {\n\n\t\t\t\tvalues[ writeOffset + j ] = values[ readOffset + j ];\n\n\t\t\t}\n\n\t\t\t++ writeIndex;\n\n\t\t}\n\n\t\tif ( writeIndex !== times.length ) {\n\n\t\t\tthis.times = times.slice( 0, writeIndex );\n\t\t\tthis.values = values.slice( 0, writeIndex * stride );\n\n\t\t} else {\n\n\t\t\tthis.times = times;\n\t\t\tthis.values = values;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\tconst times = this.times.slice();\n\t\tconst values = this.values.slice();\n\n\t\tconst TypedKeyframeTrack = this.constructor;\n\t\tconst track = new TypedKeyframeTrack( this.name, times, values );\n\n\t\t// Interpolant argument to constructor is not saved, so copy the factory method directly.\n\t\ttrack.createInterpolant = this.createInterpolant;\n\n\t\treturn track;\n\n\t}\n\n}\n\nKeyframeTrack.prototype.TimeBufferType = Float32Array;\nKeyframeTrack.prototype.ValueBufferType = Float32Array;\nKeyframeTrack.prototype.DefaultInterpolation = InterpolateLinear;\n\n/**\n * A Track of Boolean keyframe values.\n */\nclass BooleanKeyframeTrack extends KeyframeTrack {\n\n\t// No interpolation parameter because only InterpolateDiscrete is valid.\n\tconstructor( name, times, values ) {\n\n\t\tsuper( name, times, values );\n\n\t}\n\n}\n\nBooleanKeyframeTrack.prototype.ValueTypeName = 'bool';\nBooleanKeyframeTrack.prototype.ValueBufferType = Array;\nBooleanKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;\nBooleanKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;\nBooleanKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;\n\n/**\n * A Track of keyframe values that represent color.\n */\nclass ColorKeyframeTrack extends KeyframeTrack {}\n\nColorKeyframeTrack.prototype.ValueTypeName = 'color';\n\n/**\n * A Track of numeric keyframe values.\n */\nclass NumberKeyframeTrack extends KeyframeTrack {}\n\nNumberKeyframeTrack.prototype.ValueTypeName = 'number';\n\n/**\n * Spherical linear unit quaternion interpolant.\n */\n\nclass QuaternionLinearInterpolant extends Interpolant {\n\n\tconstructor( parameterPositions, sampleValues, sampleSize, resultBuffer ) {\n\n\t\tsuper( parameterPositions, sampleValues, sampleSize, resultBuffer );\n\n\t}\n\n\tinterpolate_( i1, t0, t, t1 ) {\n\n\t\tconst result = this.resultBuffer,\n\t\t\tvalues = this.sampleValues,\n\t\t\tstride = this.valueSize,\n\n\t\t\talpha = ( t - t0 ) / ( t1 - t0 );\n\n\t\tlet offset = i1 * stride;\n\n\t\tfor ( let end = offset + stride; offset !== end; offset += 4 ) {\n\n\t\t\tQuaternion.slerpFlat( result, 0, values, offset - stride, values, offset, alpha );\n\n\t\t}\n\n\t\treturn result;\n\n\t}\n\n}\n\n/**\n * A Track of quaternion keyframe values.\n */\nclass QuaternionKeyframeTrack extends KeyframeTrack {\n\n\tInterpolantFactoryMethodLinear( result ) {\n\n\t\treturn new QuaternionLinearInterpolant( this.times, this.values, this.getValueSize(), result );\n\n\t}\n\n}\n\nQuaternionKeyframeTrack.prototype.ValueTypeName = 'quaternion';\n// ValueBufferType is inherited\n// DefaultInterpolation is inherited;\nQuaternionKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;\n\n/**\n * A Track that interpolates Strings\n */\nclass StringKeyframeTrack extends KeyframeTrack {\n\n\t// No interpolation parameter because only InterpolateDiscrete is valid.\n\tconstructor( name, times, values ) {\n\n\t\tsuper( name, times, values );\n\n\t}\n\n}\n\nStringKeyframeTrack.prototype.ValueTypeName = 'string';\nStringKeyframeTrack.prototype.ValueBufferType = Array;\nStringKeyframeTrack.prototype.DefaultInterpolation = InterpolateDiscrete;\nStringKeyframeTrack.prototype.InterpolantFactoryMethodLinear = undefined;\nStringKeyframeTrack.prototype.InterpolantFactoryMethodSmooth = undefined;\n\n/**\n * A Track of vectored keyframe values.\n */\nclass VectorKeyframeTrack extends KeyframeTrack {}\n\nVectorKeyframeTrack.prototype.ValueTypeName = 'vector';\n\nclass AnimationClip {\n\n\tconstructor( name = '', duration = - 1, tracks = [], blendMode = NormalAnimationBlendMode ) {\n\n\t\tthis.name = name;\n\t\tthis.tracks = tracks;\n\t\tthis.duration = duration;\n\t\tthis.blendMode = blendMode;\n\n\t\tthis.uuid = generateUUID();\n\n\t\t// this means it should figure out its duration by scanning the tracks\n\t\tif ( this.duration < 0 ) {\n\n\t\t\tthis.resetDuration();\n\n\t\t}\n\n\t}\n\n\n\tstatic parse( json ) {\n\n\t\tconst tracks = [],\n\t\t\tjsonTracks = json.tracks,\n\t\t\tframeTime = 1.0 / ( json.fps || 1.0 );\n\n\t\tfor ( let i = 0, n = jsonTracks.length; i !== n; ++ i ) {\n\n\t\t\ttracks.push( parseKeyframeTrack( jsonTracks[ i ] ).scale( frameTime ) );\n\n\t\t}\n\n\t\tconst clip = new this( json.name, json.duration, tracks, json.blendMode );\n\t\tclip.uuid = json.uuid;\n\n\t\treturn clip;\n\n\t}\n\n\tstatic toJSON( clip ) {\n\n\t\tconst tracks = [],\n\t\t\tclipTracks = clip.tracks;\n\n\t\tconst json = {\n\n\t\t\t'name': clip.name,\n\t\t\t'duration': clip.duration,\n\t\t\t'tracks': tracks,\n\t\t\t'uuid': clip.uuid,\n\t\t\t'blendMode': clip.blendMode\n\n\t\t};\n\n\t\tfor ( let i = 0, n = clipTracks.length; i !== n; ++ i ) {\n\n\t\t\ttracks.push( KeyframeTrack.toJSON( clipTracks[ i ] ) );\n\n\t\t}\n\n\t\treturn json;\n\n\t}\n\n\tstatic CreateFromMorphTargetSequence( name, morphTargetSequence, fps, noLoop ) {\n\n\t\tconst numMorphTargets = morphTargetSequence.length;\n\t\tconst tracks = [];\n\n\t\tfor ( let i = 0; i < numMorphTargets; i ++ ) {\n\n\t\t\tlet times = [];\n\t\t\tlet values = [];\n\n\t\t\ttimes.push(\n\t\t\t\t( i + numMorphTargets - 1 ) % numMorphTargets,\n\t\t\t\ti,\n\t\t\t\t( i + 1 ) % numMorphTargets );\n\n\t\t\tvalues.push( 0, 1, 0 );\n\n\t\t\tconst order = getKeyframeOrder( times );\n\t\t\ttimes = sortedArray( times, 1, order );\n\t\t\tvalues = sortedArray( values, 1, order );\n\n\t\t\t// if there is a key at the first frame, duplicate it as the\n\t\t\t// last frame as well for perfect loop.\n\t\t\tif ( ! noLoop && times[ 0 ] === 0 ) {\n\n\t\t\t\ttimes.push( numMorphTargets );\n\t\t\t\tvalues.push( values[ 0 ] );\n\n\t\t\t}\n\n\t\t\ttracks.push(\n\t\t\t\tnew NumberKeyframeTrack(\n\t\t\t\t\t'.morphTargetInfluences[' + morphTargetSequence[ i ].name + ']',\n\t\t\t\t\ttimes, values\n\t\t\t\t).scale( 1.0 / fps ) );\n\n\t\t}\n\n\t\treturn new this( name, - 1, tracks );\n\n\t}\n\n\tstatic findByName( objectOrClipArray, name ) {\n\n\t\tlet clipArray = objectOrClipArray;\n\n\t\tif ( ! Array.isArray( objectOrClipArray ) ) {\n\n\t\t\tconst o = objectOrClipArray;\n\t\t\tclipArray = o.geometry && o.geometry.animations || o.animations;\n\n\t\t}\n\n\t\tfor ( let i = 0; i < clipArray.length; i ++ ) {\n\n\t\t\tif ( clipArray[ i ].name === name ) {\n\n\t\t\t\treturn clipArray[ i ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n\tstatic CreateClipsFromMorphTargetSequences( morphTargets, fps, noLoop ) {\n\n\t\tconst animationToMorphTargets = {};\n\n\t\t// tested with https://regex101.com/ on trick sequences\n\t\t// such flamingo_flyA_003, flamingo_run1_003, crdeath0059\n\t\tconst pattern = /^([\\w-]*?)([\\d]+)$/;\n\n\t\t// sort morph target names into animation groups based\n\t\t// patterns like Walk_001, Walk_002, Run_001, Run_002\n\t\tfor ( let i = 0, il = morphTargets.length; i < il; i ++ ) {\n\n\t\t\tconst morphTarget = morphTargets[ i ];\n\t\t\tconst parts = morphTarget.name.match( pattern );\n\n\t\t\tif ( parts && parts.length > 1 ) {\n\n\t\t\t\tconst name = parts[ 1 ];\n\n\t\t\t\tlet animationMorphTargets = animationToMorphTargets[ name ];\n\n\t\t\t\tif ( ! animationMorphTargets ) {\n\n\t\t\t\t\tanimationToMorphTargets[ name ] = animationMorphTargets = [];\n\n\t\t\t\t}\n\n\t\t\t\tanimationMorphTargets.push( morphTarget );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst clips = [];\n\n\t\tfor ( const name in animationToMorphTargets ) {\n\n\t\t\tclips.push( this.CreateFromMorphTargetSequence( name, animationToMorphTargets[ name ], fps, noLoop ) );\n\n\t\t}\n\n\t\treturn clips;\n\n\t}\n\n\t// parse the animation.hierarchy format\n\tstatic parseAnimation( animation, bones ) {\n\n\t\tif ( ! animation ) {\n\n\t\t\tconsole.error( 'THREE.AnimationClip: No animation in JSONLoader data.' );\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst addNonemptyTrack = function ( trackType, trackName, animationKeys, propertyName, destTracks ) {\n\n\t\t\t// only return track if there are actually keys.\n\t\t\tif ( animationKeys.length !== 0 ) {\n\n\t\t\t\tconst times = [];\n\t\t\t\tconst values = [];\n\n\t\t\t\tflattenJSON( animationKeys, times, values, propertyName );\n\n\t\t\t\t// empty keys are filtered out, so check again\n\t\t\t\tif ( times.length !== 0 ) {\n\n\t\t\t\t\tdestTracks.push( new trackType( trackName, times, values ) );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tconst tracks = [];\n\n\t\tconst clipName = animation.name || 'default';\n\t\tconst fps = animation.fps || 30;\n\t\tconst blendMode = animation.blendMode;\n\n\t\t// automatic length determination in AnimationClip.\n\t\tlet duration = animation.length || - 1;\n\n\t\tconst hierarchyTracks = animation.hierarchy || [];\n\n\t\tfor ( let h = 0; h < hierarchyTracks.length; h ++ ) {\n\n\t\t\tconst animationKeys = hierarchyTracks[ h ].keys;\n\n\t\t\t// skip empty tracks\n\t\t\tif ( ! animationKeys || animationKeys.length === 0 ) continue;\n\n\t\t\t// process morph targets\n\t\t\tif ( animationKeys[ 0 ].morphTargets ) {\n\n\t\t\t\t// figure out all morph targets used in this track\n\t\t\t\tconst morphTargetNames = {};\n\n\t\t\t\tlet k;\n\n\t\t\t\tfor ( k = 0; k < animationKeys.length; k ++ ) {\n\n\t\t\t\t\tif ( animationKeys[ k ].morphTargets ) {\n\n\t\t\t\t\t\tfor ( let m = 0; m < animationKeys[ k ].morphTargets.length; m ++ ) {\n\n\t\t\t\t\t\t\tmorphTargetNames[ animationKeys[ k ].morphTargets[ m ] ] = - 1;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// create a track for each morph target with all zero\n\t\t\t\t// morphTargetInfluences except for the keys in which\n\t\t\t\t// the morphTarget is named.\n\t\t\t\tfor ( const morphTargetName in morphTargetNames ) {\n\n\t\t\t\t\tconst times = [];\n\t\t\t\t\tconst values = [];\n\n\t\t\t\t\tfor ( let m = 0; m !== animationKeys[ k ].morphTargets.length; ++ m ) {\n\n\t\t\t\t\t\tconst animationKey = animationKeys[ k ];\n\n\t\t\t\t\t\ttimes.push( animationKey.time );\n\t\t\t\t\t\tvalues.push( ( animationKey.morphTarget === morphTargetName ) ? 1 : 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttracks.push( new NumberKeyframeTrack( '.morphTargetInfluence[' + morphTargetName + ']', times, values ) );\n\n\t\t\t\t}\n\n\t\t\t\tduration = morphTargetNames.length * fps;\n\n\t\t\t} else {\n\n\t\t\t\t// ...assume skeletal animation\n\n\t\t\t\tconst boneName = '.bones[' + bones[ h ].name + ']';\n\n\t\t\t\taddNonemptyTrack(\n\t\t\t\t\tVectorKeyframeTrack, boneName + '.position',\n\t\t\t\t\tanimationKeys, 'pos', tracks );\n\n\t\t\t\taddNonemptyTrack(\n\t\t\t\t\tQuaternionKeyframeTrack, boneName + '.quaternion',\n\t\t\t\t\tanimationKeys, 'rot', tracks );\n\n\t\t\t\taddNonemptyTrack(\n\t\t\t\t\tVectorKeyframeTrack, boneName + '.scale',\n\t\t\t\t\tanimationKeys, 'scl', tracks );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( tracks.length === 0 ) {\n\n\t\t\treturn null;\n\n\t\t}\n\n\t\tconst clip = new this( clipName, duration, tracks, blendMode );\n\n\t\treturn clip;\n\n\t}\n\n\tresetDuration() {\n\n\t\tconst tracks = this.tracks;\n\t\tlet duration = 0;\n\n\t\tfor ( let i = 0, n = tracks.length; i !== n; ++ i ) {\n\n\t\t\tconst track = this.tracks[ i ];\n\n\t\t\tduration = Math.max( duration, track.times[ track.times.length - 1 ] );\n\n\t\t}\n\n\t\tthis.duration = duration;\n\n\t\treturn this;\n\n\t}\n\n\ttrim() {\n\n\t\tfor ( let i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\tthis.tracks[ i ].trim( 0, this.duration );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tvalidate() {\n\n\t\tlet valid = true;\n\n\t\tfor ( let i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\tvalid = valid && this.tracks[ i ].validate();\n\n\t\t}\n\n\t\treturn valid;\n\n\t}\n\n\toptimize() {\n\n\t\tfor ( let i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\tthis.tracks[ i ].optimize();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\tconst tracks = [];\n\n\t\tfor ( let i = 0; i < this.tracks.length; i ++ ) {\n\n\t\t\ttracks.push( this.tracks[ i ].clone() );\n\n\t\t}\n\n\t\treturn new this.constructor( this.name, this.duration, tracks, this.blendMode );\n\n\t}\n\n\ttoJSON() {\n\n\t\treturn this.constructor.toJSON( this );\n\n\t}\n\n}\n\nfunction getTrackTypeForValueTypeName( typeName ) {\n\n\tswitch ( typeName.toLowerCase() ) {\n\n\t\tcase 'scalar':\n\t\tcase 'double':\n\t\tcase 'float':\n\t\tcase 'number':\n\t\tcase 'integer':\n\n\t\t\treturn NumberKeyframeTrack;\n\n\t\tcase 'vector':\n\t\tcase 'vector2':\n\t\tcase 'vector3':\n\t\tcase 'vector4':\n\n\t\t\treturn VectorKeyframeTrack;\n\n\t\tcase 'color':\n\n\t\t\treturn ColorKeyframeTrack;\n\n\t\tcase 'quaternion':\n\n\t\t\treturn QuaternionKeyframeTrack;\n\n\t\tcase 'bool':\n\t\tcase 'boolean':\n\n\t\t\treturn BooleanKeyframeTrack;\n\n\t\tcase 'string':\n\n\t\t\treturn StringKeyframeTrack;\n\n\t}\n\n\tthrow new Error( 'THREE.KeyframeTrack: Unsupported typeName: ' + typeName );\n\n}\n\nfunction parseKeyframeTrack( json ) {\n\n\tif ( json.type === undefined ) {\n\n\t\tthrow new Error( 'THREE.KeyframeTrack: track type undefined, can not parse' );\n\n\t}\n\n\tconst trackType = getTrackTypeForValueTypeName( json.type );\n\n\tif ( json.times === undefined ) {\n\n\t\tconst times = [], values = [];\n\n\t\tflattenJSON( json.keys, times, values, 'value' );\n\n\t\tjson.times = times;\n\t\tjson.values = values;\n\n\t}\n\n\t// derived classes can define a static parse method\n\tif ( trackType.parse !== undefined ) {\n\n\t\treturn trackType.parse( json );\n\n\t} else {\n\n\t\t// by default, we assume a constructor compatible with the base\n\t\treturn new trackType( json.name, json.times, json.values, json.interpolation );\n\n\t}\n\n}\n\nconst Cache = {\n\n\tenabled: false,\n\n\tfiles: {},\n\n\tadd: function ( key, file ) {\n\n\t\tif ( this.enabled === false ) return;\n\n\t\t// console.log( 'THREE.Cache', 'Adding key:', key );\n\n\t\tthis.files[ key ] = file;\n\n\t},\n\n\tget: function ( key ) {\n\n\t\tif ( this.enabled === false ) return;\n\n\t\t// console.log( 'THREE.Cache', 'Checking key:', key );\n\n\t\treturn this.files[ key ];\n\n\t},\n\n\tremove: function ( key ) {\n\n\t\tdelete this.files[ key ];\n\n\t},\n\n\tclear: function () {\n\n\t\tthis.files = {};\n\n\t}\n\n};\n\nclass LoadingManager {\n\n\tconstructor( onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tlet isLoading = false;\n\t\tlet itemsLoaded = 0;\n\t\tlet itemsTotal = 0;\n\t\tlet urlModifier = undefined;\n\t\tconst handlers = [];\n\n\t\t// Refer to #5689 for the reason why we don't set .onStart\n\t\t// in the constructor\n\n\t\tthis.onStart = undefined;\n\t\tthis.onLoad = onLoad;\n\t\tthis.onProgress = onProgress;\n\t\tthis.onError = onError;\n\n\t\tthis.itemStart = function ( url ) {\n\n\t\t\titemsTotal ++;\n\n\t\t\tif ( isLoading === false ) {\n\n\t\t\t\tif ( scope.onStart !== undefined ) {\n\n\t\t\t\t\tscope.onStart( url, itemsLoaded, itemsTotal );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tisLoading = true;\n\n\t\t};\n\n\t\tthis.itemEnd = function ( url ) {\n\n\t\t\titemsLoaded ++;\n\n\t\t\tif ( scope.onProgress !== undefined ) {\n\n\t\t\t\tscope.onProgress( url, itemsLoaded, itemsTotal );\n\n\t\t\t}\n\n\t\t\tif ( itemsLoaded === itemsTotal ) {\n\n\t\t\t\tisLoading = false;\n\n\t\t\t\tif ( scope.onLoad !== undefined ) {\n\n\t\t\t\t\tscope.onLoad();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.itemError = function ( url ) {\n\n\t\t\tif ( scope.onError !== undefined ) {\n\n\t\t\t\tscope.onError( url );\n\n\t\t\t}\n\n\t\t};\n\n\t\tthis.resolveURL = function ( url ) {\n\n\t\t\tif ( urlModifier ) {\n\n\t\t\t\treturn urlModifier( url );\n\n\t\t\t}\n\n\t\t\treturn url;\n\n\t\t};\n\n\t\tthis.setURLModifier = function ( transform ) {\n\n\t\t\turlModifier = transform;\n\n\t\t\treturn this;\n\n\t\t};\n\n\t\tthis.addHandler = function ( regex, loader ) {\n\n\t\t\thandlers.push( regex, loader );\n\n\t\t\treturn this;\n\n\t\t};\n\n\t\tthis.removeHandler = function ( regex ) {\n\n\t\t\tconst index = handlers.indexOf( regex );\n\n\t\t\tif ( index !== - 1 ) {\n\n\t\t\t\thandlers.splice( index, 2 );\n\n\t\t\t}\n\n\t\t\treturn this;\n\n\t\t};\n\n\t\tthis.getHandler = function ( file ) {\n\n\t\t\tfor ( let i = 0, l = handlers.length; i < l; i += 2 ) {\n\n\t\t\t\tconst regex = handlers[ i ];\n\t\t\t\tconst loader = handlers[ i + 1 ];\n\n\t\t\t\tif ( regex.global ) regex.lastIndex = 0; // see #17920\n\n\t\t\t\tif ( regex.test( file ) ) {\n\n\t\t\t\t\treturn loader;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn null;\n\n\t\t};\n\n\t}\n\n}\n\nconst DefaultLoadingManager = /*@__PURE__*/ new LoadingManager();\n\nclass Loader {\n\n\tconstructor( manager ) {\n\n\t\tthis.manager = ( manager !== undefined ) ? manager : DefaultLoadingManager;\n\n\t\tthis.crossOrigin = 'anonymous';\n\t\tthis.withCredentials = false;\n\t\tthis.path = '';\n\t\tthis.resourcePath = '';\n\t\tthis.requestHeader = {};\n\n\t}\n\n\tload( /* url, onLoad, onProgress, onError */ ) {}\n\n\tloadAsync( url, onProgress ) {\n\n\t\tconst scope = this;\n\n\t\treturn new Promise( function ( resolve, reject ) {\n\n\t\t\tscope.load( url, resolve, onProgress, reject );\n\n\t\t} );\n\n\t}\n\n\tparse( /* data */ ) {}\n\n\tsetCrossOrigin( crossOrigin ) {\n\n\t\tthis.crossOrigin = crossOrigin;\n\t\treturn this;\n\n\t}\n\n\tsetWithCredentials( value ) {\n\n\t\tthis.withCredentials = value;\n\t\treturn this;\n\n\t}\n\n\tsetPath( path ) {\n\n\t\tthis.path = path;\n\t\treturn this;\n\n\t}\n\n\tsetResourcePath( resourcePath ) {\n\n\t\tthis.resourcePath = resourcePath;\n\t\treturn this;\n\n\t}\n\n\tsetRequestHeader( requestHeader ) {\n\n\t\tthis.requestHeader = requestHeader;\n\t\treturn this;\n\n\t}\n\n}\n\nLoader.DEFAULT_MATERIAL_NAME = '__DEFAULT';\n\nconst loading = {};\n\nclass HttpError extends Error {\n\n\tconstructor( message, response ) {\n\n\t\tsuper( message );\n\t\tthis.response = response;\n\n\t}\n\n}\n\nclass FileLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tif ( url === undefined ) url = '';\n\n\t\tif ( this.path !== undefined ) url = this.path + url;\n\n\t\turl = this.manager.resolveURL( url );\n\n\t\tconst cached = Cache.get( url );\n\n\t\tif ( cached !== undefined ) {\n\n\t\t\tthis.manager.itemStart( url );\n\n\t\t\tsetTimeout( () => {\n\n\t\t\t\tif ( onLoad ) onLoad( cached );\n\n\t\t\t\tthis.manager.itemEnd( url );\n\n\t\t\t}, 0 );\n\n\t\t\treturn cached;\n\n\t\t}\n\n\t\t// Check if request is duplicate\n\n\t\tif ( loading[ url ] !== undefined ) {\n\n\t\t\tloading[ url ].push( {\n\n\t\t\t\tonLoad: onLoad,\n\t\t\t\tonProgress: onProgress,\n\t\t\t\tonError: onError\n\n\t\t\t} );\n\n\t\t\treturn;\n\n\t\t}\n\n\t\t// Initialise array for duplicate requests\n\t\tloading[ url ] = [];\n\n\t\tloading[ url ].push( {\n\t\t\tonLoad: onLoad,\n\t\t\tonProgress: onProgress,\n\t\t\tonError: onError,\n\t\t} );\n\n\t\t// create request\n\t\tconst req = new Request( url, {\n\t\t\theaders: new Headers( this.requestHeader ),\n\t\t\tcredentials: this.withCredentials ? 'include' : 'same-origin',\n\t\t\t// An abort controller could be added within a future PR\n\t\t} );\n\n\t\t// record states ( avoid data race )\n\t\tconst mimeType = this.mimeType;\n\t\tconst responseType = this.responseType;\n\n\t\t// start the fetch\n\t\tfetch( req )\n\t\t\t.then( response => {\n\n\t\t\t\tif ( response.status === 200 || response.status === 0 ) {\n\n\t\t\t\t\t// Some browsers return HTTP Status 0 when using non-http protocol\n\t\t\t\t\t// e.g. 'file://' or 'data://'. Handle as success.\n\n\t\t\t\t\tif ( response.status === 0 ) {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.FileLoader: HTTP Status 0 received.' );\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// Workaround: Checking if response.body === undefined for Alipay browser #23548\n\n\t\t\t\t\tif ( typeof ReadableStream === 'undefined' || response.body === undefined || response.body.getReader === undefined ) {\n\n\t\t\t\t\t\treturn response;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst callbacks = loading[ url ];\n\t\t\t\t\tconst reader = response.body.getReader();\n\n\t\t\t\t\t// Nginx needs X-File-Size check\n\t\t\t\t\t// https://serverfault.com/questions/482875/why-does-nginx-remove-content-length-header-for-chunked-content\n\t\t\t\t\tconst contentLength = response.headers.get( 'X-File-Size' ) || response.headers.get( 'Content-Length' );\n\t\t\t\t\tconst total = contentLength ? parseInt( contentLength ) : 0;\n\t\t\t\t\tconst lengthComputable = total !== 0;\n\t\t\t\t\tlet loaded = 0;\n\n\t\t\t\t\t// periodically read data into the new stream tracking while download progress\n\t\t\t\t\tconst stream = new ReadableStream( {\n\t\t\t\t\t\tstart( controller ) {\n\n\t\t\t\t\t\t\treadData();\n\n\t\t\t\t\t\t\tfunction readData() {\n\n\t\t\t\t\t\t\t\treader.read().then( ( { done, value } ) => {\n\n\t\t\t\t\t\t\t\t\tif ( done ) {\n\n\t\t\t\t\t\t\t\t\t\tcontroller.close();\n\n\t\t\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t\t\tloaded += value.byteLength;\n\n\t\t\t\t\t\t\t\t\t\tconst event = new ProgressEvent( 'progress', { lengthComputable, loaded, total } );\n\t\t\t\t\t\t\t\t\t\tfor ( let i = 0, il = callbacks.length; i < il; i ++ ) {\n\n\t\t\t\t\t\t\t\t\t\t\tconst callback = callbacks[ i ];\n\t\t\t\t\t\t\t\t\t\t\tif ( callback.onProgress ) callback.onProgress( event );\n\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tcontroller.enqueue( value );\n\t\t\t\t\t\t\t\t\t\treadData();\n\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t}, ( e ) => {\n\n\t\t\t\t\t\t\t\t\tcontroller.error( e );\n\n\t\t\t\t\t\t\t\t} );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t} );\n\n\t\t\t\t\treturn new Response( stream );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthrow new HttpError( `fetch for \"${response.url}\" responded with ${response.status}: ${response.statusText}`, response );\n\n\t\t\t\t}\n\n\t\t\t} )\n\t\t\t.then( response => {\n\n\t\t\t\tswitch ( responseType ) {\n\n\t\t\t\t\tcase 'arraybuffer':\n\n\t\t\t\t\t\treturn response.arrayBuffer();\n\n\t\t\t\t\tcase 'blob':\n\n\t\t\t\t\t\treturn response.blob();\n\n\t\t\t\t\tcase 'document':\n\n\t\t\t\t\t\treturn response.text()\n\t\t\t\t\t\t\t.then( text => {\n\n\t\t\t\t\t\t\t\tconst parser = new DOMParser();\n\t\t\t\t\t\t\t\treturn parser.parseFromString( text, mimeType );\n\n\t\t\t\t\t\t\t} );\n\n\t\t\t\t\tcase 'json':\n\n\t\t\t\t\t\treturn response.json();\n\n\t\t\t\t\tdefault:\n\n\t\t\t\t\t\tif ( mimeType === undefined ) {\n\n\t\t\t\t\t\t\treturn response.text();\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// sniff encoding\n\t\t\t\t\t\t\tconst re = /charset=\"?([^;\"\\s]*)\"?/i;\n\t\t\t\t\t\t\tconst exec = re.exec( mimeType );\n\t\t\t\t\t\t\tconst label = exec && exec[ 1 ] ? exec[ 1 ].toLowerCase() : undefined;\n\t\t\t\t\t\t\tconst decoder = new TextDecoder( label );\n\t\t\t\t\t\t\treturn response.arrayBuffer().then( ab => decoder.decode( ab ) );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t} )\n\t\t\t.then( data => {\n\n\t\t\t\t// Add to cache only on HTTP success, so that we do not cache\n\t\t\t\t// error response bodies as proper responses to requests.\n\t\t\t\tCache.add( url, data );\n\n\t\t\t\tconst callbacks = loading[ url ];\n\t\t\t\tdelete loading[ url ];\n\n\t\t\t\tfor ( let i = 0, il = callbacks.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst callback = callbacks[ i ];\n\t\t\t\t\tif ( callback.onLoad ) callback.onLoad( data );\n\n\t\t\t\t}\n\n\t\t\t} )\n\t\t\t.catch( err => {\n\n\t\t\t\t// Abort errors and other errors are handled the same\n\n\t\t\t\tconst callbacks = loading[ url ];\n\n\t\t\t\tif ( callbacks === undefined ) {\n\n\t\t\t\t\t// When onLoad was called and url was deleted in `loading`\n\t\t\t\t\tthis.manager.itemError( url );\n\t\t\t\t\tthrow err;\n\n\t\t\t\t}\n\n\t\t\t\tdelete loading[ url ];\n\n\t\t\t\tfor ( let i = 0, il = callbacks.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst callback = callbacks[ i ];\n\t\t\t\t\tif ( callback.onError ) callback.onError( err );\n\n\t\t\t\t}\n\n\t\t\t\tthis.manager.itemError( url );\n\n\t\t\t} )\n\t\t\t.finally( () => {\n\n\t\t\t\tthis.manager.itemEnd( url );\n\n\t\t\t} );\n\n\t\tthis.manager.itemStart( url );\n\n\t}\n\n\tsetResponseType( value ) {\n\n\t\tthis.responseType = value;\n\t\treturn this;\n\n\t}\n\n\tsetMimeType( value ) {\n\n\t\tthis.mimeType = value;\n\t\treturn this;\n\n\t}\n\n}\n\nclass AnimationLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setPath( this.path );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setWithCredentials( this.withCredentials );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\ttry {\n\n\t\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\n\n\t\t\t} catch ( e ) {\n\n\t\t\t\tif ( onError ) {\n\n\t\t\t\t\tonError( e );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( e );\n\n\t\t\t\t}\n\n\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t}\n\n\tparse( json ) {\n\n\t\tconst animations = [];\n\n\t\tfor ( let i = 0; i < json.length; i ++ ) {\n\n\t\t\tconst clip = AnimationClip.parse( json[ i ] );\n\n\t\t\tanimations.push( clip );\n\n\t\t}\n\n\t\treturn animations;\n\n\t}\n\n}\n\n/**\n * Abstract Base class to block based textures loader (dds, pvr, ...)\n *\n * Sub classes have to implement the parse() method which will be used in load().\n */\n\nclass CompressedTextureLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst images = [];\n\n\t\tconst texture = new CompressedTexture();\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setPath( this.path );\n\t\tloader.setResponseType( 'arraybuffer' );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setWithCredentials( scope.withCredentials );\n\n\t\tlet loaded = 0;\n\n\t\tfunction loadTexture( i ) {\n\n\t\t\tloader.load( url[ i ], function ( buffer ) {\n\n\t\t\t\tconst texDatas = scope.parse( buffer, true );\n\n\t\t\t\timages[ i ] = {\n\t\t\t\t\twidth: texDatas.width,\n\t\t\t\t\theight: texDatas.height,\n\t\t\t\t\tformat: texDatas.format,\n\t\t\t\t\tmipmaps: texDatas.mipmaps\n\t\t\t\t};\n\n\t\t\t\tloaded += 1;\n\n\t\t\t\tif ( loaded === 6 ) {\n\n\t\t\t\t\tif ( texDatas.mipmapCount === 1 ) texture.minFilter = LinearFilter;\n\n\t\t\t\t\ttexture.image = images;\n\t\t\t\t\ttexture.format = texDatas.format;\n\t\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t\t}\n\n\t\t\t}, onProgress, onError );\n\n\t\t}\n\n\t\tif ( Array.isArray( url ) ) {\n\n\t\t\tfor ( let i = 0, il = url.length; i < il; ++ i ) {\n\n\t\t\t\tloadTexture( i );\n\n\t\t\t}\n\n\t\t} else {\n\n\t\t\t// compressed cubemap texture stored in a single DDS file\n\n\t\t\tloader.load( url, function ( buffer ) {\n\n\t\t\t\tconst texDatas = scope.parse( buffer, true );\n\n\t\t\t\tif ( texDatas.isCubemap ) {\n\n\t\t\t\t\tconst faces = texDatas.mipmaps.length / texDatas.mipmapCount;\n\n\t\t\t\t\tfor ( let f = 0; f < faces; f ++ ) {\n\n\t\t\t\t\t\timages[ f ] = { mipmaps: [] };\n\n\t\t\t\t\t\tfor ( let i = 0; i < texDatas.mipmapCount; i ++ ) {\n\n\t\t\t\t\t\t\timages[ f ].mipmaps.push( texDatas.mipmaps[ f * texDatas.mipmapCount + i ] );\n\t\t\t\t\t\t\timages[ f ].format = texDatas.format;\n\t\t\t\t\t\t\timages[ f ].width = texDatas.width;\n\t\t\t\t\t\t\timages[ f ].height = texDatas.height;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttexture.image = images;\n\n\t\t\t\t} else {\n\n\t\t\t\t\ttexture.image.width = texDatas.width;\n\t\t\t\t\ttexture.image.height = texDatas.height;\n\t\t\t\t\ttexture.mipmaps = texDatas.mipmaps;\n\n\t\t\t\t}\n\n\t\t\t\tif ( texDatas.mipmapCount === 1 ) {\n\n\t\t\t\t\ttexture.minFilter = LinearFilter;\n\n\t\t\t\t}\n\n\t\t\t\ttexture.format = texDatas.format;\n\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t}, onProgress, onError );\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n}\n\nclass ImageLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tif ( this.path !== undefined ) url = this.path + url;\n\n\t\turl = this.manager.resolveURL( url );\n\n\t\tconst scope = this;\n\n\t\tconst cached = Cache.get( url );\n\n\t\tif ( cached !== undefined ) {\n\n\t\t\tscope.manager.itemStart( url );\n\n\t\t\tsetTimeout( function () {\n\n\t\t\t\tif ( onLoad ) onLoad( cached );\n\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t}, 0 );\n\n\t\t\treturn cached;\n\n\t\t}\n\n\t\tconst image = createElementNS( 'img' );\n\n\t\tfunction onImageLoad() {\n\n\t\t\tremoveEventListeners();\n\n\t\t\tCache.add( url, this );\n\n\t\t\tif ( onLoad ) onLoad( this );\n\n\t\t\tscope.manager.itemEnd( url );\n\n\t\t}\n\n\t\tfunction onImageError( event ) {\n\n\t\t\tremoveEventListeners();\n\n\t\t\tif ( onError ) onError( event );\n\n\t\t\tscope.manager.itemError( url );\n\t\t\tscope.manager.itemEnd( url );\n\n\t\t}\n\n\t\tfunction removeEventListeners() {\n\n\t\t\timage.removeEventListener( 'load', onImageLoad, false );\n\t\t\timage.removeEventListener( 'error', onImageError, false );\n\n\t\t}\n\n\t\timage.addEventListener( 'load', onImageLoad, false );\n\t\timage.addEventListener( 'error', onImageError, false );\n\n\t\tif ( url.slice( 0, 5 ) !== 'data:' ) {\n\n\t\t\tif ( this.crossOrigin !== undefined ) image.crossOrigin = this.crossOrigin;\n\n\t\t}\n\n\t\tscope.manager.itemStart( url );\n\n\t\timage.src = url;\n\n\t\treturn image;\n\n\t}\n\n}\n\nclass CubeTextureLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( urls, onLoad, onProgress, onError ) {\n\n\t\tconst texture = new CubeTexture();\n\t\ttexture.colorSpace = SRGBColorSpace;\n\n\t\tconst loader = new ImageLoader( this.manager );\n\t\tloader.setCrossOrigin( this.crossOrigin );\n\t\tloader.setPath( this.path );\n\n\t\tlet loaded = 0;\n\n\t\tfunction loadTexture( i ) {\n\n\t\t\tloader.load( urls[ i ], function ( image ) {\n\n\t\t\t\ttexture.images[ i ] = image;\n\n\t\t\t\tloaded ++;\n\n\t\t\t\tif ( loaded === 6 ) {\n\n\t\t\t\t\ttexture.needsUpdate = true;\n\n\t\t\t\t\tif ( onLoad ) onLoad( texture );\n\n\t\t\t\t}\n\n\t\t\t}, undefined, onError );\n\n\t\t}\n\n\t\tfor ( let i = 0; i < urls.length; ++ i ) {\n\n\t\t\tloadTexture( i );\n\n\t\t}\n\n\t\treturn texture;\n\n\t}\n\n}\n\n/**\n * Abstract Base class to load generic binary textures formats (rgbe, hdr, ...)\n *\n * Sub classes have to implement the parse() method which will be used in load().\n */\n\nclass DataTextureLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst texture = new DataTexture();\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setResponseType( 'arraybuffer' );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setPath( this.path );\n\t\tloader.setWithCredentials( scope.withCredentials );\n\t\tloader.load( url, function ( buffer ) {\n\n\t\t\tlet texData;\n\n\t\t\ttry {\n\n\t\t\t\ttexData = scope.parse( buffer );\n\n\t\t\t} catch ( error ) {\n\n\t\t\t\tif ( onError !== undefined ) {\n\n\t\t\t\t\tonError( error );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( error );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( texData.image !== undefined ) {\n\n\t\t\t\ttexture.image = texData.image;\n\n\t\t\t} else if ( texData.data !== undefined ) {\n\n\t\t\t\ttexture.image.width = texData.width;\n\t\t\t\ttexture.image.height = texData.height;\n\t\t\t\ttexture.image.data = texData.data;\n\n\t\t\t}\n\n\t\t\ttexture.wrapS = texData.wrapS !== undefined ? texData.wrapS : ClampToEdgeWrapping;\n\t\t\ttexture.wrapT = texData.wrapT !== undefined ? texData.wrapT : ClampToEdgeWrapping;\n\n\t\t\ttexture.magFilter = texData.magFilter !== undefined ? texData.magFilter : LinearFilter;\n\t\t\ttexture.minFilter = texData.minFilter !== undefined ? texData.minFilter : LinearFilter;\n\n\t\t\ttexture.anisotropy = texData.anisotropy !== undefined ? texData.anisotropy : 1;\n\n\t\t\tif ( texData.colorSpace !== undefined ) {\n\n\t\t\t\ttexture.colorSpace = texData.colorSpace;\n\n\t\t\t}\n\n\t\t\tif ( texData.flipY !== undefined ) {\n\n\t\t\t\ttexture.flipY = texData.flipY;\n\n\t\t\t}\n\n\t\t\tif ( texData.format !== undefined ) {\n\n\t\t\t\ttexture.format = texData.format;\n\n\t\t\t}\n\n\t\t\tif ( texData.type !== undefined ) {\n\n\t\t\t\ttexture.type = texData.type;\n\n\t\t\t}\n\n\t\t\tif ( texData.mipmaps !== undefined ) {\n\n\t\t\t\ttexture.mipmaps = texData.mipmaps;\n\t\t\t\ttexture.minFilter = LinearMipmapLinearFilter; // presumably...\n\n\t\t\t}\n\n\t\t\tif ( texData.mipmapCount === 1 ) {\n\n\t\t\t\ttexture.minFilter = LinearFilter;\n\n\t\t\t}\n\n\t\t\tif ( texData.generateMipmaps !== undefined ) {\n\n\t\t\t\ttexture.generateMipmaps = texData.generateMipmaps;\n\n\t\t\t}\n\n\t\t\ttexture.needsUpdate = true;\n\n\t\t\tif ( onLoad ) onLoad( texture, texData );\n\n\t\t}, onProgress, onError );\n\n\n\t\treturn texture;\n\n\t}\n\n}\n\nclass TextureLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst texture = new Texture();\n\n\t\tconst loader = new ImageLoader( this.manager );\n\t\tloader.setCrossOrigin( this.crossOrigin );\n\t\tloader.setPath( this.path );\n\n\t\tloader.load( url, function ( image ) {\n\n\t\t\ttexture.image = image;\n\t\t\ttexture.needsUpdate = true;\n\n\t\t\tif ( onLoad !== undefined ) {\n\n\t\t\t\tonLoad( texture );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t\treturn texture;\n\n\t}\n\n}\n\nclass Light extends Object3D {\n\n\tconstructor( color, intensity = 1 ) {\n\n\t\tsuper();\n\n\t\tthis.isLight = true;\n\n\t\tthis.type = 'Light';\n\n\t\tthis.color = new Color( color );\n\t\tthis.intensity = intensity;\n\n\t}\n\n\tdispose() {\n\n\t\t// Empty here in base class; some subclasses override.\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.color.copy( source.color );\n\t\tthis.intensity = source.intensity;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.object.color = this.color.getHex();\n\t\tdata.object.intensity = this.intensity;\n\n\t\tif ( this.groundColor !== undefined ) data.object.groundColor = this.groundColor.getHex();\n\n\t\tif ( this.distance !== undefined ) data.object.distance = this.distance;\n\t\tif ( this.angle !== undefined ) data.object.angle = this.angle;\n\t\tif ( this.decay !== undefined ) data.object.decay = this.decay;\n\t\tif ( this.penumbra !== undefined ) data.object.penumbra = this.penumbra;\n\n\t\tif ( this.shadow !== undefined ) data.object.shadow = this.shadow.toJSON();\n\t\tif ( this.target !== undefined ) data.object.target = this.target.uuid;\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass HemisphereLight extends Light {\n\n\tconstructor( skyColor, groundColor, intensity ) {\n\n\t\tsuper( skyColor, intensity );\n\n\t\tthis.isHemisphereLight = true;\n\n\t\tthis.type = 'HemisphereLight';\n\n\t\tthis.position.copy( Object3D.DEFAULT_UP );\n\t\tthis.updateMatrix();\n\n\t\tthis.groundColor = new Color( groundColor );\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.groundColor.copy( source.groundColor );\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _projScreenMatrix$1 = /*@__PURE__*/ new Matrix4();\nconst _lightPositionWorld$1 = /*@__PURE__*/ new Vector3();\nconst _lookTarget$1 = /*@__PURE__*/ new Vector3();\n\nclass LightShadow {\n\n\tconstructor( camera ) {\n\n\t\tthis.camera = camera;\n\n\t\tthis.intensity = 1;\n\n\t\tthis.bias = 0;\n\t\tthis.normalBias = 0;\n\t\tthis.radius = 1;\n\t\tthis.blurSamples = 8;\n\n\t\tthis.mapSize = new Vector2( 512, 512 );\n\n\t\tthis.map = null;\n\t\tthis.mapPass = null;\n\t\tthis.matrix = new Matrix4();\n\n\t\tthis.autoUpdate = true;\n\t\tthis.needsUpdate = false;\n\n\t\tthis._frustum = new Frustum();\n\t\tthis._frameExtents = new Vector2( 1, 1 );\n\n\t\tthis._viewportCount = 1;\n\n\t\tthis._viewports = [\n\n\t\t\tnew Vector4( 0, 0, 1, 1 )\n\n\t\t];\n\n\t}\n\n\tgetViewportCount() {\n\n\t\treturn this._viewportCount;\n\n\t}\n\n\tgetFrustum() {\n\n\t\treturn this._frustum;\n\n\t}\n\n\tupdateMatrices( light ) {\n\n\t\tconst shadowCamera = this.camera;\n\t\tconst shadowMatrix = this.matrix;\n\n\t\t_lightPositionWorld$1.setFromMatrixPosition( light.matrixWorld );\n\t\tshadowCamera.position.copy( _lightPositionWorld$1 );\n\n\t\t_lookTarget$1.setFromMatrixPosition( light.target.matrixWorld );\n\t\tshadowCamera.lookAt( _lookTarget$1 );\n\t\tshadowCamera.updateMatrixWorld();\n\n\t\t_projScreenMatrix$1.multiplyMatrices( shadowCamera.projectionMatrix, shadowCamera.matrixWorldInverse );\n\t\tthis._frustum.setFromProjectionMatrix( _projScreenMatrix$1 );\n\n\t\tshadowMatrix.set(\n\t\t\t0.5, 0.0, 0.0, 0.5,\n\t\t\t0.0, 0.5, 0.0, 0.5,\n\t\t\t0.0, 0.0, 0.5, 0.5,\n\t\t\t0.0, 0.0, 0.0, 1.0\n\t\t);\n\n\t\tshadowMatrix.multiply( _projScreenMatrix$1 );\n\n\t}\n\n\tgetViewport( viewportIndex ) {\n\n\t\treturn this._viewports[ viewportIndex ];\n\n\t}\n\n\tgetFrameExtents() {\n\n\t\treturn this._frameExtents;\n\n\t}\n\n\tdispose() {\n\n\t\tif ( this.map ) {\n\n\t\t\tthis.map.dispose();\n\n\t\t}\n\n\t\tif ( this.mapPass ) {\n\n\t\t\tthis.mapPass.dispose();\n\n\t\t}\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.camera = source.camera.clone();\n\n\t\tthis.intensity = source.intensity;\n\n\t\tthis.bias = source.bias;\n\t\tthis.radius = source.radius;\n\n\t\tthis.mapSize.copy( source.mapSize );\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst object = {};\n\n\t\tif ( this.intensity !== 1 ) object.intensity = this.intensity;\n\t\tif ( this.bias !== 0 ) object.bias = this.bias;\n\t\tif ( this.normalBias !== 0 ) object.normalBias = this.normalBias;\n\t\tif ( this.radius !== 1 ) object.radius = this.radius;\n\t\tif ( this.mapSize.x !== 512 || this.mapSize.y !== 512 ) object.mapSize = this.mapSize.toArray();\n\n\t\tobject.camera = this.camera.toJSON( false ).object;\n\t\tdelete object.camera.matrix;\n\n\t\treturn object;\n\n\t}\n\n}\n\nclass SpotLightShadow extends LightShadow {\n\n\tconstructor() {\n\n\t\tsuper( new PerspectiveCamera( 50, 1, 0.5, 500 ) );\n\n\t\tthis.isSpotLightShadow = true;\n\n\t\tthis.focus = 1;\n\n\t}\n\n\tupdateMatrices( light ) {\n\n\t\tconst camera = this.camera;\n\n\t\tconst fov = RAD2DEG * 2 * light.angle * this.focus;\n\t\tconst aspect = this.mapSize.width / this.mapSize.height;\n\t\tconst far = light.distance || camera.far;\n\n\t\tif ( fov !== camera.fov || aspect !== camera.aspect || far !== camera.far ) {\n\n\t\t\tcamera.fov = fov;\n\t\t\tcamera.aspect = aspect;\n\t\t\tcamera.far = far;\n\t\t\tcamera.updateProjectionMatrix();\n\n\t\t}\n\n\t\tsuper.updateMatrices( light );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.focus = source.focus;\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass SpotLight extends Light {\n\n\tconstructor( color, intensity, distance = 0, angle = Math.PI / 3, penumbra = 0, decay = 2 ) {\n\n\t\tsuper( color, intensity );\n\n\t\tthis.isSpotLight = true;\n\n\t\tthis.type = 'SpotLight';\n\n\t\tthis.position.copy( Object3D.DEFAULT_UP );\n\t\tthis.updateMatrix();\n\n\t\tthis.target = new Object3D();\n\n\t\tthis.distance = distance;\n\t\tthis.angle = angle;\n\t\tthis.penumbra = penumbra;\n\t\tthis.decay = decay;\n\n\t\tthis.map = null;\n\n\t\tthis.shadow = new SpotLightShadow();\n\n\t}\n\n\tget power() {\n\n\t\t// compute the light's luminous power (in lumens) from its intensity (in candela)\n\t\t// by convention for a spotlight, luminous power (lm) = π * luminous intensity (cd)\n\t\treturn this.intensity * Math.PI;\n\n\t}\n\n\tset power( power ) {\n\n\t\t// set the light's intensity (in candela) from the desired luminous power (in lumens)\n\t\tthis.intensity = power / Math.PI;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.shadow.dispose();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.distance = source.distance;\n\t\tthis.angle = source.angle;\n\t\tthis.penumbra = source.penumbra;\n\t\tthis.decay = source.decay;\n\n\t\tthis.target = source.target.clone();\n\n\t\tthis.shadow = source.shadow.clone();\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _projScreenMatrix = /*@__PURE__*/ new Matrix4();\nconst _lightPositionWorld = /*@__PURE__*/ new Vector3();\nconst _lookTarget = /*@__PURE__*/ new Vector3();\n\nclass PointLightShadow extends LightShadow {\n\n\tconstructor() {\n\n\t\tsuper( new PerspectiveCamera( 90, 1, 0.5, 500 ) );\n\n\t\tthis.isPointLightShadow = true;\n\n\t\tthis._frameExtents = new Vector2( 4, 2 );\n\n\t\tthis._viewportCount = 6;\n\n\t\tthis._viewports = [\n\t\t\t// These viewports map a cube-map onto a 2D texture with the\n\t\t\t// following orientation:\n\t\t\t//\n\t\t\t// xzXZ\n\t\t\t// y Y\n\t\t\t//\n\t\t\t// X - Positive x direction\n\t\t\t// x - Negative x direction\n\t\t\t// Y - Positive y direction\n\t\t\t// y - Negative y direction\n\t\t\t// Z - Positive z direction\n\t\t\t// z - Negative z direction\n\n\t\t\t// positive X\n\t\t\tnew Vector4( 2, 1, 1, 1 ),\n\t\t\t// negative X\n\t\t\tnew Vector4( 0, 1, 1, 1 ),\n\t\t\t// positive Z\n\t\t\tnew Vector4( 3, 1, 1, 1 ),\n\t\t\t// negative Z\n\t\t\tnew Vector4( 1, 1, 1, 1 ),\n\t\t\t// positive Y\n\t\t\tnew Vector4( 3, 0, 1, 1 ),\n\t\t\t// negative Y\n\t\t\tnew Vector4( 1, 0, 1, 1 )\n\t\t];\n\n\t\tthis._cubeDirections = [\n\t\t\tnew Vector3( 1, 0, 0 ), new Vector3( - 1, 0, 0 ), new Vector3( 0, 0, 1 ),\n\t\t\tnew Vector3( 0, 0, - 1 ), new Vector3( 0, 1, 0 ), new Vector3( 0, - 1, 0 )\n\t\t];\n\n\t\tthis._cubeUps = [\n\t\t\tnew Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ), new Vector3( 0, 1, 0 ),\n\t\t\tnew Vector3( 0, 1, 0 ), new Vector3( 0, 0, 1 ),\tnew Vector3( 0, 0, - 1 )\n\t\t];\n\n\t}\n\n\tupdateMatrices( light, viewportIndex = 0 ) {\n\n\t\tconst camera = this.camera;\n\t\tconst shadowMatrix = this.matrix;\n\n\t\tconst far = light.distance || camera.far;\n\n\t\tif ( far !== camera.far ) {\n\n\t\t\tcamera.far = far;\n\t\t\tcamera.updateProjectionMatrix();\n\n\t\t}\n\n\t\t_lightPositionWorld.setFromMatrixPosition( light.matrixWorld );\n\t\tcamera.position.copy( _lightPositionWorld );\n\n\t\t_lookTarget.copy( camera.position );\n\t\t_lookTarget.add( this._cubeDirections[ viewportIndex ] );\n\t\tcamera.up.copy( this._cubeUps[ viewportIndex ] );\n\t\tcamera.lookAt( _lookTarget );\n\t\tcamera.updateMatrixWorld();\n\n\t\tshadowMatrix.makeTranslation( - _lightPositionWorld.x, - _lightPositionWorld.y, - _lightPositionWorld.z );\n\n\t\t_projScreenMatrix.multiplyMatrices( camera.projectionMatrix, camera.matrixWorldInverse );\n\t\tthis._frustum.setFromProjectionMatrix( _projScreenMatrix );\n\n\t}\n\n}\n\nclass PointLight extends Light {\n\n\tconstructor( color, intensity, distance = 0, decay = 2 ) {\n\n\t\tsuper( color, intensity );\n\n\t\tthis.isPointLight = true;\n\n\t\tthis.type = 'PointLight';\n\n\t\tthis.distance = distance;\n\t\tthis.decay = decay;\n\n\t\tthis.shadow = new PointLightShadow();\n\n\t}\n\n\tget power() {\n\n\t\t// compute the light's luminous power (in lumens) from its intensity (in candela)\n\t\t// for an isotropic light source, luminous power (lm) = 4 π luminous intensity (cd)\n\t\treturn this.intensity * 4 * Math.PI;\n\n\t}\n\n\tset power( power ) {\n\n\t\t// set the light's intensity (in candela) from the desired luminous power (in lumens)\n\t\tthis.intensity = power / ( 4 * Math.PI );\n\n\t}\n\n\tdispose() {\n\n\t\tthis.shadow.dispose();\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.distance = source.distance;\n\t\tthis.decay = source.decay;\n\n\t\tthis.shadow = source.shadow.clone();\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass DirectionalLightShadow extends LightShadow {\n\n\tconstructor() {\n\n\t\tsuper( new OrthographicCamera( - 5, 5, 5, - 5, 0.5, 500 ) );\n\n\t\tthis.isDirectionalLightShadow = true;\n\n\t}\n\n}\n\nclass DirectionalLight extends Light {\n\n\tconstructor( color, intensity ) {\n\n\t\tsuper( color, intensity );\n\n\t\tthis.isDirectionalLight = true;\n\n\t\tthis.type = 'DirectionalLight';\n\n\t\tthis.position.copy( Object3D.DEFAULT_UP );\n\t\tthis.updateMatrix();\n\n\t\tthis.target = new Object3D();\n\n\t\tthis.shadow = new DirectionalLightShadow();\n\n\t}\n\n\tdispose() {\n\n\t\tthis.shadow.dispose();\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.target = source.target.clone();\n\t\tthis.shadow = source.shadow.clone();\n\n\t\treturn this;\n\n\t}\n\n}\n\nclass AmbientLight extends Light {\n\n\tconstructor( color, intensity ) {\n\n\t\tsuper( color, intensity );\n\n\t\tthis.isAmbientLight = true;\n\n\t\tthis.type = 'AmbientLight';\n\n\t}\n\n}\n\nclass RectAreaLight extends Light {\n\n\tconstructor( color, intensity, width = 10, height = 10 ) {\n\n\t\tsuper( color, intensity );\n\n\t\tthis.isRectAreaLight = true;\n\n\t\tthis.type = 'RectAreaLight';\n\n\t\tthis.width = width;\n\t\tthis.height = height;\n\n\t}\n\n\tget power() {\n\n\t\t// compute the light's luminous power (in lumens) from its intensity (in nits)\n\t\treturn this.intensity * this.width * this.height * Math.PI;\n\n\t}\n\n\tset power( power ) {\n\n\t\t// set the light's intensity (in nits) from the desired luminous power (in lumens)\n\t\tthis.intensity = power / ( this.width * this.height * Math.PI );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.width = source.width;\n\t\tthis.height = source.height;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.object.width = this.width;\n\t\tdata.object.height = this.height;\n\n\t\treturn data;\n\n\t}\n\n}\n\n/**\n * Primary reference:\n * https://graphics.stanford.edu/papers/envmap/envmap.pdf\n *\n * Secondary reference:\n * https://www.ppsloan.org/publications/StupidSH36.pdf\n */\n\n// 3-band SH defined by 9 coefficients\n\nclass SphericalHarmonics3 {\n\n\tconstructor() {\n\n\t\tthis.isSphericalHarmonics3 = true;\n\n\t\tthis.coefficients = [];\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients.push( new Vector3() );\n\n\t\t}\n\n\t}\n\n\tset( coefficients ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].copy( coefficients[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tzero() {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].set( 0, 0, 0 );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// get the radiance in the direction of the normal\n\t// target is a Vector3\n\tgetAt( normal, target ) {\n\n\t\t// normal is assumed to be unit length\n\n\t\tconst x = normal.x, y = normal.y, z = normal.z;\n\n\t\tconst coeff = this.coefficients;\n\n\t\t// band 0\n\t\ttarget.copy( coeff[ 0 ] ).multiplyScalar( 0.282095 );\n\n\t\t// band 1\n\t\ttarget.addScaledVector( coeff[ 1 ], 0.488603 * y );\n\t\ttarget.addScaledVector( coeff[ 2 ], 0.488603 * z );\n\t\ttarget.addScaledVector( coeff[ 3 ], 0.488603 * x );\n\n\t\t// band 2\n\t\ttarget.addScaledVector( coeff[ 4 ], 1.092548 * ( x * y ) );\n\t\ttarget.addScaledVector( coeff[ 5 ], 1.092548 * ( y * z ) );\n\t\ttarget.addScaledVector( coeff[ 6 ], 0.315392 * ( 3.0 * z * z - 1.0 ) );\n\t\ttarget.addScaledVector( coeff[ 7 ], 1.092548 * ( x * z ) );\n\t\ttarget.addScaledVector( coeff[ 8 ], 0.546274 * ( x * x - y * y ) );\n\n\t\treturn target;\n\n\t}\n\n\t// get the irradiance (radiance convolved with cosine lobe) in the direction of the normal\n\t// target is a Vector3\n\t// https://graphics.stanford.edu/papers/envmap/envmap.pdf\n\tgetIrradianceAt( normal, target ) {\n\n\t\t// normal is assumed to be unit length\n\n\t\tconst x = normal.x, y = normal.y, z = normal.z;\n\n\t\tconst coeff = this.coefficients;\n\n\t\t// band 0\n\t\ttarget.copy( coeff[ 0 ] ).multiplyScalar( 0.886227 ); // π * 0.282095\n\n\t\t// band 1\n\t\ttarget.addScaledVector( coeff[ 1 ], 2.0 * 0.511664 * y ); // ( 2 * π / 3 ) * 0.488603\n\t\ttarget.addScaledVector( coeff[ 2 ], 2.0 * 0.511664 * z );\n\t\ttarget.addScaledVector( coeff[ 3 ], 2.0 * 0.511664 * x );\n\n\t\t// band 2\n\t\ttarget.addScaledVector( coeff[ 4 ], 2.0 * 0.429043 * x * y ); // ( π / 4 ) * 1.092548\n\t\ttarget.addScaledVector( coeff[ 5 ], 2.0 * 0.429043 * y * z );\n\t\ttarget.addScaledVector( coeff[ 6 ], 0.743125 * z * z - 0.247708 ); // ( π / 4 ) * 0.315392 * 3\n\t\ttarget.addScaledVector( coeff[ 7 ], 2.0 * 0.429043 * x * z );\n\t\ttarget.addScaledVector( coeff[ 8 ], 0.429043 * ( x * x - y * y ) ); // ( π / 4 ) * 0.546274\n\n\t\treturn target;\n\n\t}\n\n\tadd( sh ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].add( sh.coefficients[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\taddScaledSH( sh, s ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].addScaledVector( sh.coefficients[ i ], s );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tscale( s ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].multiplyScalar( s );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tlerp( sh, alpha ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tthis.coefficients[ i ].lerp( sh.coefficients[ i ], alpha );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tequals( sh ) {\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tif ( ! this.coefficients[ i ].equals( sh.coefficients[ i ] ) ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\tcopy( sh ) {\n\n\t\treturn this.set( sh.coefficients );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tconst coefficients = this.coefficients;\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tcoefficients[ i ].fromArray( array, offset + ( i * 3 ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\ttoArray( array = [], offset = 0 ) {\n\n\t\tconst coefficients = this.coefficients;\n\n\t\tfor ( let i = 0; i < 9; i ++ ) {\n\n\t\t\tcoefficients[ i ].toArray( array, offset + ( i * 3 ) );\n\n\t\t}\n\n\t\treturn array;\n\n\t}\n\n\t// evaluate the basis functions\n\t// shBasis is an Array[ 9 ]\n\tstatic getBasisAt( normal, shBasis ) {\n\n\t\t// normal is assumed to be unit length\n\n\t\tconst x = normal.x, y = normal.y, z = normal.z;\n\n\t\t// band 0\n\t\tshBasis[ 0 ] = 0.282095;\n\n\t\t// band 1\n\t\tshBasis[ 1 ] = 0.488603 * y;\n\t\tshBasis[ 2 ] = 0.488603 * z;\n\t\tshBasis[ 3 ] = 0.488603 * x;\n\n\t\t// band 2\n\t\tshBasis[ 4 ] = 1.092548 * x * y;\n\t\tshBasis[ 5 ] = 1.092548 * y * z;\n\t\tshBasis[ 6 ] = 0.315392 * ( 3 * z * z - 1 );\n\t\tshBasis[ 7 ] = 1.092548 * x * z;\n\t\tshBasis[ 8 ] = 0.546274 * ( x * x - y * y );\n\n\t}\n\n}\n\nclass LightProbe extends Light {\n\n\tconstructor( sh = new SphericalHarmonics3(), intensity = 1 ) {\n\n\t\tsuper( undefined, intensity );\n\n\t\tthis.isLightProbe = true;\n\n\t\tthis.sh = sh;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.sh.copy( source.sh );\n\n\t\treturn this;\n\n\t}\n\n\tfromJSON( json ) {\n\n\t\tthis.intensity = json.intensity; // TODO: Move this bit to Light.fromJSON();\n\t\tthis.sh.fromArray( json.sh );\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON( meta ) {\n\n\t\tconst data = super.toJSON( meta );\n\n\t\tdata.object.sh = this.sh.toArray();\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass MaterialLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\t\tthis.textures = {};\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst loader = new FileLoader( scope.manager );\n\t\tloader.setPath( scope.path );\n\t\tloader.setRequestHeader( scope.requestHeader );\n\t\tloader.setWithCredentials( scope.withCredentials );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\ttry {\n\n\t\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\n\n\t\t\t} catch ( e ) {\n\n\t\t\t\tif ( onError ) {\n\n\t\t\t\t\tonError( e );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( e );\n\n\t\t\t\t}\n\n\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t}\n\n\tparse( json ) {\n\n\t\tconst textures = this.textures;\n\n\t\tfunction getTexture( name ) {\n\n\t\t\tif ( textures[ name ] === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.MaterialLoader: Undefined texture', name );\n\n\t\t\t}\n\n\t\t\treturn textures[ name ];\n\n\t\t}\n\n\t\tconst material = MaterialLoader.createMaterialFromType( json.type );\n\n\t\tif ( json.uuid !== undefined ) material.uuid = json.uuid;\n\t\tif ( json.name !== undefined ) material.name = json.name;\n\t\tif ( json.color !== undefined && material.color !== undefined ) material.color.setHex( json.color );\n\t\tif ( json.roughness !== undefined ) material.roughness = json.roughness;\n\t\tif ( json.metalness !== undefined ) material.metalness = json.metalness;\n\t\tif ( json.sheen !== undefined ) material.sheen = json.sheen;\n\t\tif ( json.sheenColor !== undefined ) material.sheenColor = new Color().setHex( json.sheenColor );\n\t\tif ( json.sheenRoughness !== undefined ) material.sheenRoughness = json.sheenRoughness;\n\t\tif ( json.emissive !== undefined && material.emissive !== undefined ) material.emissive.setHex( json.emissive );\n\t\tif ( json.specular !== undefined && material.specular !== undefined ) material.specular.setHex( json.specular );\n\t\tif ( json.specularIntensity !== undefined ) material.specularIntensity = json.specularIntensity;\n\t\tif ( json.specularColor !== undefined && material.specularColor !== undefined ) material.specularColor.setHex( json.specularColor );\n\t\tif ( json.shininess !== undefined ) material.shininess = json.shininess;\n\t\tif ( json.clearcoat !== undefined ) material.clearcoat = json.clearcoat;\n\t\tif ( json.clearcoatRoughness !== undefined ) material.clearcoatRoughness = json.clearcoatRoughness;\n\t\tif ( json.dispersion !== undefined ) material.dispersion = json.dispersion;\n\t\tif ( json.iridescence !== undefined ) material.iridescence = json.iridescence;\n\t\tif ( json.iridescenceIOR !== undefined ) material.iridescenceIOR = json.iridescenceIOR;\n\t\tif ( json.iridescenceThicknessRange !== undefined ) material.iridescenceThicknessRange = json.iridescenceThicknessRange;\n\t\tif ( json.transmission !== undefined ) material.transmission = json.transmission;\n\t\tif ( json.thickness !== undefined ) material.thickness = json.thickness;\n\t\tif ( json.attenuationDistance !== undefined ) material.attenuationDistance = json.attenuationDistance;\n\t\tif ( json.attenuationColor !== undefined && material.attenuationColor !== undefined ) material.attenuationColor.setHex( json.attenuationColor );\n\t\tif ( json.anisotropy !== undefined ) material.anisotropy = json.anisotropy;\n\t\tif ( json.anisotropyRotation !== undefined ) material.anisotropyRotation = json.anisotropyRotation;\n\t\tif ( json.fog !== undefined ) material.fog = json.fog;\n\t\tif ( json.flatShading !== undefined ) material.flatShading = json.flatShading;\n\t\tif ( json.blending !== undefined ) material.blending = json.blending;\n\t\tif ( json.combine !== undefined ) material.combine = json.combine;\n\t\tif ( json.side !== undefined ) material.side = json.side;\n\t\tif ( json.shadowSide !== undefined ) material.shadowSide = json.shadowSide;\n\t\tif ( json.opacity !== undefined ) material.opacity = json.opacity;\n\t\tif ( json.transparent !== undefined ) material.transparent = json.transparent;\n\t\tif ( json.alphaTest !== undefined ) material.alphaTest = json.alphaTest;\n\t\tif ( json.alphaHash !== undefined ) material.alphaHash = json.alphaHash;\n\t\tif ( json.depthFunc !== undefined ) material.depthFunc = json.depthFunc;\n\t\tif ( json.depthTest !== undefined ) material.depthTest = json.depthTest;\n\t\tif ( json.depthWrite !== undefined ) material.depthWrite = json.depthWrite;\n\t\tif ( json.colorWrite !== undefined ) material.colorWrite = json.colorWrite;\n\t\tif ( json.blendSrc !== undefined ) material.blendSrc = json.blendSrc;\n\t\tif ( json.blendDst !== undefined ) material.blendDst = json.blendDst;\n\t\tif ( json.blendEquation !== undefined ) material.blendEquation = json.blendEquation;\n\t\tif ( json.blendSrcAlpha !== undefined ) material.blendSrcAlpha = json.blendSrcAlpha;\n\t\tif ( json.blendDstAlpha !== undefined ) material.blendDstAlpha = json.blendDstAlpha;\n\t\tif ( json.blendEquationAlpha !== undefined ) material.blendEquationAlpha = json.blendEquationAlpha;\n\t\tif ( json.blendColor !== undefined && material.blendColor !== undefined ) material.blendColor.setHex( json.blendColor );\n\t\tif ( json.blendAlpha !== undefined ) material.blendAlpha = json.blendAlpha;\n\t\tif ( json.stencilWriteMask !== undefined ) material.stencilWriteMask = json.stencilWriteMask;\n\t\tif ( json.stencilFunc !== undefined ) material.stencilFunc = json.stencilFunc;\n\t\tif ( json.stencilRef !== undefined ) material.stencilRef = json.stencilRef;\n\t\tif ( json.stencilFuncMask !== undefined ) material.stencilFuncMask = json.stencilFuncMask;\n\t\tif ( json.stencilFail !== undefined ) material.stencilFail = json.stencilFail;\n\t\tif ( json.stencilZFail !== undefined ) material.stencilZFail = json.stencilZFail;\n\t\tif ( json.stencilZPass !== undefined ) material.stencilZPass = json.stencilZPass;\n\t\tif ( json.stencilWrite !== undefined ) material.stencilWrite = json.stencilWrite;\n\n\t\tif ( json.wireframe !== undefined ) material.wireframe = json.wireframe;\n\t\tif ( json.wireframeLinewidth !== undefined ) material.wireframeLinewidth = json.wireframeLinewidth;\n\t\tif ( json.wireframeLinecap !== undefined ) material.wireframeLinecap = json.wireframeLinecap;\n\t\tif ( json.wireframeLinejoin !== undefined ) material.wireframeLinejoin = json.wireframeLinejoin;\n\n\t\tif ( json.rotation !== undefined ) material.rotation = json.rotation;\n\n\t\tif ( json.linewidth !== undefined ) material.linewidth = json.linewidth;\n\t\tif ( json.dashSize !== undefined ) material.dashSize = json.dashSize;\n\t\tif ( json.gapSize !== undefined ) material.gapSize = json.gapSize;\n\t\tif ( json.scale !== undefined ) material.scale = json.scale;\n\n\t\tif ( json.polygonOffset !== undefined ) material.polygonOffset = json.polygonOffset;\n\t\tif ( json.polygonOffsetFactor !== undefined ) material.polygonOffsetFactor = json.polygonOffsetFactor;\n\t\tif ( json.polygonOffsetUnits !== undefined ) material.polygonOffsetUnits = json.polygonOffsetUnits;\n\n\t\tif ( json.dithering !== undefined ) material.dithering = json.dithering;\n\n\t\tif ( json.alphaToCoverage !== undefined ) material.alphaToCoverage = json.alphaToCoverage;\n\t\tif ( json.premultipliedAlpha !== undefined ) material.premultipliedAlpha = json.premultipliedAlpha;\n\t\tif ( json.forceSinglePass !== undefined ) material.forceSinglePass = json.forceSinglePass;\n\n\t\tif ( json.visible !== undefined ) material.visible = json.visible;\n\n\t\tif ( json.toneMapped !== undefined ) material.toneMapped = json.toneMapped;\n\n\t\tif ( json.userData !== undefined ) material.userData = json.userData;\n\n\t\tif ( json.vertexColors !== undefined ) {\n\n\t\t\tif ( typeof json.vertexColors === 'number' ) {\n\n\t\t\t\tmaterial.vertexColors = ( json.vertexColors > 0 ) ? true : false;\n\n\t\t\t} else {\n\n\t\t\t\tmaterial.vertexColors = json.vertexColors;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// Shader Material\n\n\t\tif ( json.uniforms !== undefined ) {\n\n\t\t\tfor ( const name in json.uniforms ) {\n\n\t\t\t\tconst uniform = json.uniforms[ name ];\n\n\t\t\t\tmaterial.uniforms[ name ] = {};\n\n\t\t\t\tswitch ( uniform.type ) {\n\n\t\t\t\t\tcase 't':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = getTexture( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'c':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Color().setHex( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'v2':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Vector2().fromArray( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'v3':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Vector3().fromArray( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'v4':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Vector4().fromArray( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'm3':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Matrix3().fromArray( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tcase 'm4':\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = new Matrix4().fromArray( uniform.value );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\t\t\t\t\t\tmaterial.uniforms[ name ].value = uniform.value;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( json.defines !== undefined ) material.defines = json.defines;\n\t\tif ( json.vertexShader !== undefined ) material.vertexShader = json.vertexShader;\n\t\tif ( json.fragmentShader !== undefined ) material.fragmentShader = json.fragmentShader;\n\t\tif ( json.glslVersion !== undefined ) material.glslVersion = json.glslVersion;\n\n\t\tif ( json.extensions !== undefined ) {\n\n\t\t\tfor ( const key in json.extensions ) {\n\n\t\t\t\tmaterial.extensions[ key ] = json.extensions[ key ];\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( json.lights !== undefined ) material.lights = json.lights;\n\t\tif ( json.clipping !== undefined ) material.clipping = json.clipping;\n\n\t\t// for PointsMaterial\n\n\t\tif ( json.size !== undefined ) material.size = json.size;\n\t\tif ( json.sizeAttenuation !== undefined ) material.sizeAttenuation = json.sizeAttenuation;\n\n\t\t// maps\n\n\t\tif ( json.map !== undefined ) material.map = getTexture( json.map );\n\t\tif ( json.matcap !== undefined ) material.matcap = getTexture( json.matcap );\n\n\t\tif ( json.alphaMap !== undefined ) material.alphaMap = getTexture( json.alphaMap );\n\n\t\tif ( json.bumpMap !== undefined ) material.bumpMap = getTexture( json.bumpMap );\n\t\tif ( json.bumpScale !== undefined ) material.bumpScale = json.bumpScale;\n\n\t\tif ( json.normalMap !== undefined ) material.normalMap = getTexture( json.normalMap );\n\t\tif ( json.normalMapType !== undefined ) material.normalMapType = json.normalMapType;\n\t\tif ( json.normalScale !== undefined ) {\n\n\t\t\tlet normalScale = json.normalScale;\n\n\t\t\tif ( Array.isArray( normalScale ) === false ) {\n\n\t\t\t\t// Blender exporter used to export a scalar. See #7459\n\n\t\t\t\tnormalScale = [ normalScale, normalScale ];\n\n\t\t\t}\n\n\t\t\tmaterial.normalScale = new Vector2().fromArray( normalScale );\n\n\t\t}\n\n\t\tif ( json.displacementMap !== undefined ) material.displacementMap = getTexture( json.displacementMap );\n\t\tif ( json.displacementScale !== undefined ) material.displacementScale = json.displacementScale;\n\t\tif ( json.displacementBias !== undefined ) material.displacementBias = json.displacementBias;\n\n\t\tif ( json.roughnessMap !== undefined ) material.roughnessMap = getTexture( json.roughnessMap );\n\t\tif ( json.metalnessMap !== undefined ) material.metalnessMap = getTexture( json.metalnessMap );\n\n\t\tif ( json.emissiveMap !== undefined ) material.emissiveMap = getTexture( json.emissiveMap );\n\t\tif ( json.emissiveIntensity !== undefined ) material.emissiveIntensity = json.emissiveIntensity;\n\n\t\tif ( json.specularMap !== undefined ) material.specularMap = getTexture( json.specularMap );\n\t\tif ( json.specularIntensityMap !== undefined ) material.specularIntensityMap = getTexture( json.specularIntensityMap );\n\t\tif ( json.specularColorMap !== undefined ) material.specularColorMap = getTexture( json.specularColorMap );\n\n\t\tif ( json.envMap !== undefined ) material.envMap = getTexture( json.envMap );\n\t\tif ( json.envMapRotation !== undefined ) material.envMapRotation.fromArray( json.envMapRotation );\n\t\tif ( json.envMapIntensity !== undefined ) material.envMapIntensity = json.envMapIntensity;\n\n\t\tif ( json.reflectivity !== undefined ) material.reflectivity = json.reflectivity;\n\t\tif ( json.refractionRatio !== undefined ) material.refractionRatio = json.refractionRatio;\n\n\t\tif ( json.lightMap !== undefined ) material.lightMap = getTexture( json.lightMap );\n\t\tif ( json.lightMapIntensity !== undefined ) material.lightMapIntensity = json.lightMapIntensity;\n\n\t\tif ( json.aoMap !== undefined ) material.aoMap = getTexture( json.aoMap );\n\t\tif ( json.aoMapIntensity !== undefined ) material.aoMapIntensity = json.aoMapIntensity;\n\n\t\tif ( json.gradientMap !== undefined ) material.gradientMap = getTexture( json.gradientMap );\n\n\t\tif ( json.clearcoatMap !== undefined ) material.clearcoatMap = getTexture( json.clearcoatMap );\n\t\tif ( json.clearcoatRoughnessMap !== undefined ) material.clearcoatRoughnessMap = getTexture( json.clearcoatRoughnessMap );\n\t\tif ( json.clearcoatNormalMap !== undefined ) material.clearcoatNormalMap = getTexture( json.clearcoatNormalMap );\n\t\tif ( json.clearcoatNormalScale !== undefined ) material.clearcoatNormalScale = new Vector2().fromArray( json.clearcoatNormalScale );\n\n\t\tif ( json.iridescenceMap !== undefined ) material.iridescenceMap = getTexture( json.iridescenceMap );\n\t\tif ( json.iridescenceThicknessMap !== undefined ) material.iridescenceThicknessMap = getTexture( json.iridescenceThicknessMap );\n\n\t\tif ( json.transmissionMap !== undefined ) material.transmissionMap = getTexture( json.transmissionMap );\n\t\tif ( json.thicknessMap !== undefined ) material.thicknessMap = getTexture( json.thicknessMap );\n\n\t\tif ( json.anisotropyMap !== undefined ) material.anisotropyMap = getTexture( json.anisotropyMap );\n\n\t\tif ( json.sheenColorMap !== undefined ) material.sheenColorMap = getTexture( json.sheenColorMap );\n\t\tif ( json.sheenRoughnessMap !== undefined ) material.sheenRoughnessMap = getTexture( json.sheenRoughnessMap );\n\n\t\treturn material;\n\n\t}\n\n\tsetTextures( value ) {\n\n\t\tthis.textures = value;\n\t\treturn this;\n\n\t}\n\n\tstatic createMaterialFromType( type ) {\n\n\t\tconst materialLib = {\n\t\t\tShadowMaterial,\n\t\t\tSpriteMaterial,\n\t\t\tRawShaderMaterial,\n\t\t\tShaderMaterial,\n\t\t\tPointsMaterial,\n\t\t\tMeshPhysicalMaterial,\n\t\t\tMeshStandardMaterial,\n\t\t\tMeshPhongMaterial,\n\t\t\tMeshToonMaterial,\n\t\t\tMeshNormalMaterial,\n\t\t\tMeshLambertMaterial,\n\t\t\tMeshDepthMaterial,\n\t\t\tMeshDistanceMaterial,\n\t\t\tMeshBasicMaterial,\n\t\t\tMeshMatcapMaterial,\n\t\t\tLineDashedMaterial,\n\t\t\tLineBasicMaterial,\n\t\t\tMaterial\n\t\t};\n\n\t\treturn new materialLib[ type ]();\n\n\t}\n\n}\n\nclass LoaderUtils {\n\n\tstatic decodeText( array ) { // @deprecated, r165\n\n\t\tconsole.warn( 'THREE.LoaderUtils: decodeText() has been deprecated with r165 and will be removed with r175. Use TextDecoder instead.' );\n\n\t\tif ( typeof TextDecoder !== 'undefined' ) {\n\n\t\t\treturn new TextDecoder().decode( array );\n\n\t\t}\n\n\t\t// Avoid the String.fromCharCode.apply(null, array) shortcut, which\n\t\t// throws a \"maximum call stack size exceeded\" error for large arrays.\n\n\t\tlet s = '';\n\n\t\tfor ( let i = 0, il = array.length; i < il; i ++ ) {\n\n\t\t\t// Implicitly assumes little-endian.\n\t\t\ts += String.fromCharCode( array[ i ] );\n\n\t\t}\n\n\t\ttry {\n\n\t\t\t// merges multi-byte utf-8 characters.\n\n\t\t\treturn decodeURIComponent( escape( s ) );\n\n\t\t} catch ( e ) { // see #16358\n\n\t\t\treturn s;\n\n\t\t}\n\n\t}\n\n\tstatic extractUrlBase( url ) {\n\n\t\tconst index = url.lastIndexOf( '/' );\n\n\t\tif ( index === - 1 ) return './';\n\n\t\treturn url.slice( 0, index + 1 );\n\n\t}\n\n\tstatic resolveURL( url, path ) {\n\n\t\t// Invalid URL\n\t\tif ( typeof url !== 'string' || url === '' ) return '';\n\n\t\t// Host Relative URL\n\t\tif ( /^https?:\\/\\//i.test( path ) && /^\\//.test( url ) ) {\n\n\t\t\tpath = path.replace( /(^https?:\\/\\/[^\\/]+).*/i, '$1' );\n\n\t\t}\n\n\t\t// Absolute URL http://,https://,//\n\t\tif ( /^(https?:)?\\/\\//i.test( url ) ) return url;\n\n\t\t// Data URI\n\t\tif ( /^data:.*,.*$/i.test( url ) ) return url;\n\n\t\t// Blob URL\n\t\tif ( /^blob:.*$/i.test( url ) ) return url;\n\n\t\t// Relative URL\n\t\treturn path + url;\n\n\t}\n\n}\n\nclass InstancedBufferGeometry extends BufferGeometry {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isInstancedBufferGeometry = true;\n\n\t\tthis.type = 'InstancedBufferGeometry';\n\t\tthis.instanceCount = Infinity;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.instanceCount = source.instanceCount;\n\n\t\treturn this;\n\n\t}\n\n\ttoJSON() {\n\n\t\tconst data = super.toJSON();\n\n\t\tdata.instanceCount = this.instanceCount;\n\n\t\tdata.isInstancedBufferGeometry = true;\n\n\t\treturn data;\n\n\t}\n\n}\n\nclass BufferGeometryLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst loader = new FileLoader( scope.manager );\n\t\tloader.setPath( scope.path );\n\t\tloader.setRequestHeader( scope.requestHeader );\n\t\tloader.setWithCredentials( scope.withCredentials );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\ttry {\n\n\t\t\t\tonLoad( scope.parse( JSON.parse( text ) ) );\n\n\t\t\t} catch ( e ) {\n\n\t\t\t\tif ( onError ) {\n\n\t\t\t\t\tonError( e );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconsole.error( e );\n\n\t\t\t\t}\n\n\t\t\t\tscope.manager.itemError( url );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t}\n\n\tparse( json ) {\n\n\t\tconst interleavedBufferMap = {};\n\t\tconst arrayBufferMap = {};\n\n\t\tfunction getInterleavedBuffer( json, uuid ) {\n\n\t\t\tif ( interleavedBufferMap[ uuid ] !== undefined ) return interleavedBufferMap[ uuid ];\n\n\t\t\tconst interleavedBuffers = json.interleavedBuffers;\n\t\t\tconst interleavedBuffer = interleavedBuffers[ uuid ];\n\n\t\t\tconst buffer = getArrayBuffer( json, interleavedBuffer.buffer );\n\n\t\t\tconst array = getTypedArray( interleavedBuffer.type, buffer );\n\t\t\tconst ib = new InterleavedBuffer( array, interleavedBuffer.stride );\n\t\t\tib.uuid = interleavedBuffer.uuid;\n\n\t\t\tinterleavedBufferMap[ uuid ] = ib;\n\n\t\t\treturn ib;\n\n\t\t}\n\n\t\tfunction getArrayBuffer( json, uuid ) {\n\n\t\t\tif ( arrayBufferMap[ uuid ] !== undefined ) return arrayBufferMap[ uuid ];\n\n\t\t\tconst arrayBuffers = json.arrayBuffers;\n\t\t\tconst arrayBuffer = arrayBuffers[ uuid ];\n\n\t\t\tconst ab = new Uint32Array( arrayBuffer ).buffer;\n\n\t\t\tarrayBufferMap[ uuid ] = ab;\n\n\t\t\treturn ab;\n\n\t\t}\n\n\t\tconst geometry = json.isInstancedBufferGeometry ? new InstancedBufferGeometry() : new BufferGeometry();\n\n\t\tconst index = json.data.index;\n\n\t\tif ( index !== undefined ) {\n\n\t\t\tconst typedArray = getTypedArray( index.type, index.array );\n\t\t\tgeometry.setIndex( new BufferAttribute( typedArray, 1 ) );\n\n\t\t}\n\n\t\tconst attributes = json.data.attributes;\n\n\t\tfor ( const key in attributes ) {\n\n\t\t\tconst attribute = attributes[ key ];\n\t\t\tlet bufferAttribute;\n\n\t\t\tif ( attribute.isInterleavedBufferAttribute ) {\n\n\t\t\t\tconst interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );\n\t\t\t\tbufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );\n\n\t\t\t} else {\n\n\t\t\t\tconst typedArray = getTypedArray( attribute.type, attribute.array );\n\t\t\t\tconst bufferAttributeConstr = attribute.isInstancedBufferAttribute ? InstancedBufferAttribute : BufferAttribute;\n\t\t\t\tbufferAttribute = new bufferAttributeConstr( typedArray, attribute.itemSize, attribute.normalized );\n\n\t\t\t}\n\n\t\t\tif ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;\n\t\t\tif ( attribute.usage !== undefined ) bufferAttribute.setUsage( attribute.usage );\n\n\t\t\tgeometry.setAttribute( key, bufferAttribute );\n\n\t\t}\n\n\t\tconst morphAttributes = json.data.morphAttributes;\n\n\t\tif ( morphAttributes ) {\n\n\t\t\tfor ( const key in morphAttributes ) {\n\n\t\t\t\tconst attributeArray = morphAttributes[ key ];\n\n\t\t\t\tconst array = [];\n\n\t\t\t\tfor ( let i = 0, il = attributeArray.length; i < il; i ++ ) {\n\n\t\t\t\t\tconst attribute = attributeArray[ i ];\n\t\t\t\t\tlet bufferAttribute;\n\n\t\t\t\t\tif ( attribute.isInterleavedBufferAttribute ) {\n\n\t\t\t\t\t\tconst interleavedBuffer = getInterleavedBuffer( json.data, attribute.data );\n\t\t\t\t\t\tbufferAttribute = new InterleavedBufferAttribute( interleavedBuffer, attribute.itemSize, attribute.offset, attribute.normalized );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconst typedArray = getTypedArray( attribute.type, attribute.array );\n\t\t\t\t\t\tbufferAttribute = new BufferAttribute( typedArray, attribute.itemSize, attribute.normalized );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( attribute.name !== undefined ) bufferAttribute.name = attribute.name;\n\t\t\t\t\tarray.push( bufferAttribute );\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.morphAttributes[ key ] = array;\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst morphTargetsRelative = json.data.morphTargetsRelative;\n\n\t\tif ( morphTargetsRelative ) {\n\n\t\t\tgeometry.morphTargetsRelative = true;\n\n\t\t}\n\n\t\tconst groups = json.data.groups || json.data.drawcalls || json.data.offsets;\n\n\t\tif ( groups !== undefined ) {\n\n\t\t\tfor ( let i = 0, n = groups.length; i !== n; ++ i ) {\n\n\t\t\t\tconst group = groups[ i ];\n\n\t\t\t\tgeometry.addGroup( group.start, group.count, group.materialIndex );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst boundingSphere = json.data.boundingSphere;\n\n\t\tif ( boundingSphere !== undefined ) {\n\n\t\t\tconst center = new Vector3();\n\n\t\t\tif ( boundingSphere.center !== undefined ) {\n\n\t\t\t\tcenter.fromArray( boundingSphere.center );\n\n\t\t\t}\n\n\t\t\tgeometry.boundingSphere = new Sphere( center, boundingSphere.radius );\n\n\t\t}\n\n\t\tif ( json.name ) geometry.name = json.name;\n\t\tif ( json.userData ) geometry.userData = json.userData;\n\n\t\treturn geometry;\n\n\t}\n\n}\n\nclass ObjectLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;\n\t\tthis.resourcePath = this.resourcePath || path;\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setPath( this.path );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setWithCredentials( this.withCredentials );\n\t\tloader.load( url, function ( text ) {\n\n\t\t\tlet json = null;\n\n\t\t\ttry {\n\n\t\t\t\tjson = JSON.parse( text );\n\n\t\t\t} catch ( error ) {\n\n\t\t\t\tif ( onError !== undefined ) onError( error );\n\n\t\t\t\tconsole.error( 'THREE:ObjectLoader: Can\\'t parse ' + url + '.', error.message );\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tconst metadata = json.metadata;\n\n\t\t\tif ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {\n\n\t\t\t\tif ( onError !== undefined ) onError( new Error( 'THREE.ObjectLoader: Can\\'t load ' + url ) );\n\n\t\t\t\tconsole.error( 'THREE.ObjectLoader: Can\\'t load ' + url );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tscope.parse( json, onLoad );\n\n\t\t}, onProgress, onError );\n\n\t}\n\n\tasync loadAsync( url, onProgress ) {\n\n\t\tconst scope = this;\n\n\t\tconst path = ( this.path === '' ) ? LoaderUtils.extractUrlBase( url ) : this.path;\n\t\tthis.resourcePath = this.resourcePath || path;\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setPath( this.path );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setWithCredentials( this.withCredentials );\n\n\t\tconst text = await loader.loadAsync( url, onProgress );\n\n\t\tconst json = JSON.parse( text );\n\n\t\tconst metadata = json.metadata;\n\n\t\tif ( metadata === undefined || metadata.type === undefined || metadata.type.toLowerCase() === 'geometry' ) {\n\n\t\t\tthrow new Error( 'THREE.ObjectLoader: Can\\'t load ' + url );\n\n\t\t}\n\n\t\treturn await scope.parseAsync( json );\n\n\t}\n\n\tparse( json, onLoad ) {\n\n\t\tconst animations = this.parseAnimations( json.animations );\n\t\tconst shapes = this.parseShapes( json.shapes );\n\t\tconst geometries = this.parseGeometries( json.geometries, shapes );\n\n\t\tconst images = this.parseImages( json.images, function () {\n\n\t\t\tif ( onLoad !== undefined ) onLoad( object );\n\n\t\t} );\n\n\t\tconst textures = this.parseTextures( json.textures, images );\n\t\tconst materials = this.parseMaterials( json.materials, textures );\n\n\t\tconst object = this.parseObject( json.object, geometries, materials, textures, animations );\n\t\tconst skeletons = this.parseSkeletons( json.skeletons, object );\n\n\t\tthis.bindSkeletons( object, skeletons );\n\t\tthis.bindLightTargets( object );\n\n\t\t//\n\n\t\tif ( onLoad !== undefined ) {\n\n\t\t\tlet hasImages = false;\n\n\t\t\tfor ( const uuid in images ) {\n\n\t\t\t\tif ( images[ uuid ].data instanceof HTMLImageElement ) {\n\n\t\t\t\t\thasImages = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( hasImages === false ) onLoad( object );\n\n\t\t}\n\n\t\treturn object;\n\n\t}\n\n\tasync parseAsync( json ) {\n\n\t\tconst animations = this.parseAnimations( json.animations );\n\t\tconst shapes = this.parseShapes( json.shapes );\n\t\tconst geometries = this.parseGeometries( json.geometries, shapes );\n\n\t\tconst images = await this.parseImagesAsync( json.images );\n\n\t\tconst textures = this.parseTextures( json.textures, images );\n\t\tconst materials = this.parseMaterials( json.materials, textures );\n\n\t\tconst object = this.parseObject( json.object, geometries, materials, textures, animations );\n\t\tconst skeletons = this.parseSkeletons( json.skeletons, object );\n\n\t\tthis.bindSkeletons( object, skeletons );\n\t\tthis.bindLightTargets( object );\n\n\t\treturn object;\n\n\t}\n\n\tparseShapes( json ) {\n\n\t\tconst shapes = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tfor ( let i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tconst shape = new Shape().fromJSON( json[ i ] );\n\n\t\t\t\tshapes[ shape.uuid ] = shape;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn shapes;\n\n\t}\n\n\tparseSkeletons( json, object ) {\n\n\t\tconst skeletons = {};\n\t\tconst bones = {};\n\n\t\t// generate bone lookup table\n\n\t\tobject.traverse( function ( child ) {\n\n\t\t\tif ( child.isBone ) bones[ child.uuid ] = child;\n\n\t\t} );\n\n\t\t// create skeletons\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tfor ( let i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tconst skeleton = new Skeleton().fromJSON( json[ i ], bones );\n\n\t\t\t\tskeletons[ skeleton.uuid ] = skeleton;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn skeletons;\n\n\t}\n\n\tparseGeometries( json, shapes ) {\n\n\t\tconst geometries = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tconst bufferGeometryLoader = new BufferGeometryLoader();\n\n\t\t\tfor ( let i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tlet geometry;\n\t\t\t\tconst data = json[ i ];\n\n\t\t\t\tswitch ( data.type ) {\n\n\t\t\t\t\tcase 'BufferGeometry':\n\t\t\t\t\tcase 'InstancedBufferGeometry':\n\n\t\t\t\t\t\tgeometry = bufferGeometryLoader.parse( data );\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\tdefault:\n\n\t\t\t\t\t\tif ( data.type in Geometries ) {\n\n\t\t\t\t\t\t\tgeometry = Geometries[ data.type ].fromJSON( data, shapes );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\tconsole.warn( `THREE.ObjectLoader: Unsupported geometry type \"${ data.type }\"` );\n\n\t\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tgeometry.uuid = data.uuid;\n\n\t\t\t\tif ( data.name !== undefined ) geometry.name = data.name;\n\t\t\t\tif ( data.userData !== undefined ) geometry.userData = data.userData;\n\n\t\t\t\tgeometries[ data.uuid ] = geometry;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn geometries;\n\n\t}\n\n\tparseMaterials( json, textures ) {\n\n\t\tconst cache = {}; // MultiMaterial\n\t\tconst materials = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tconst loader = new MaterialLoader();\n\t\t\tloader.setTextures( textures );\n\n\t\t\tfor ( let i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tconst data = json[ i ];\n\n\t\t\t\tif ( cache[ data.uuid ] === undefined ) {\n\n\t\t\t\t\tcache[ data.uuid ] = loader.parse( data );\n\n\t\t\t\t}\n\n\t\t\t\tmaterials[ data.uuid ] = cache[ data.uuid ];\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn materials;\n\n\t}\n\n\tparseAnimations( json ) {\n\n\t\tconst animations = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tfor ( let i = 0; i < json.length; i ++ ) {\n\n\t\t\t\tconst data = json[ i ];\n\n\t\t\t\tconst clip = AnimationClip.parse( data );\n\n\t\t\t\tanimations[ clip.uuid ] = clip;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn animations;\n\n\t}\n\n\tparseImages( json, onLoad ) {\n\n\t\tconst scope = this;\n\t\tconst images = {};\n\n\t\tlet loader;\n\n\t\tfunction loadImage( url ) {\n\n\t\t\tscope.manager.itemStart( url );\n\n\t\t\treturn loader.load( url, function () {\n\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t}, undefined, function () {\n\n\t\t\t\tscope.manager.itemError( url );\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t} );\n\n\t\t}\n\n\t\tfunction deserializeImage( image ) {\n\n\t\t\tif ( typeof image === 'string' ) {\n\n\t\t\t\tconst url = image;\n\n\t\t\t\tconst path = /^(\\/\\/)|([a-z]+:(\\/\\/)?)/i.test( url ) ? url : scope.resourcePath + url;\n\n\t\t\t\treturn loadImage( path );\n\n\t\t\t} else {\n\n\t\t\t\tif ( image.data ) {\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdata: getTypedArray( image.type, image.data ),\n\t\t\t\t\t\twidth: image.width,\n\t\t\t\t\t\theight: image.height\n\t\t\t\t\t};\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( json !== undefined && json.length > 0 ) {\n\n\t\t\tconst manager = new LoadingManager( onLoad );\n\n\t\t\tloader = new ImageLoader( manager );\n\t\t\tloader.setCrossOrigin( this.crossOrigin );\n\n\t\t\tfor ( let i = 0, il = json.length; i < il; i ++ ) {\n\n\t\t\t\tconst image = json[ i ];\n\t\t\t\tconst url = image.url;\n\n\t\t\t\tif ( Array.isArray( url ) ) {\n\n\t\t\t\t\t// load array of images e.g CubeTexture\n\n\t\t\t\t\tconst imageArray = [];\n\n\t\t\t\t\tfor ( let j = 0, jl = url.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tconst currentUrl = url[ j ];\n\n\t\t\t\t\t\tconst deserializedImage = deserializeImage( currentUrl );\n\n\t\t\t\t\t\tif ( deserializedImage !== null ) {\n\n\t\t\t\t\t\t\tif ( deserializedImage instanceof HTMLImageElement ) {\n\n\t\t\t\t\t\t\t\timageArray.push( deserializedImage );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// special case: handle array of data textures for cube textures\n\n\t\t\t\t\t\t\t\timageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\timages[ image.uuid ] = new Source( imageArray );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// load single image\n\n\t\t\t\t\tconst deserializedImage = deserializeImage( image.url );\n\t\t\t\t\timages[ image.uuid ] = new Source( deserializedImage );\n\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn images;\n\n\t}\n\n\tasync parseImagesAsync( json ) {\n\n\t\tconst scope = this;\n\t\tconst images = {};\n\n\t\tlet loader;\n\n\t\tasync function deserializeImage( image ) {\n\n\t\t\tif ( typeof image === 'string' ) {\n\n\t\t\t\tconst url = image;\n\n\t\t\t\tconst path = /^(\\/\\/)|([a-z]+:(\\/\\/)?)/i.test( url ) ? url : scope.resourcePath + url;\n\n\t\t\t\treturn await loader.loadAsync( path );\n\n\t\t\t} else {\n\n\t\t\t\tif ( image.data ) {\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tdata: getTypedArray( image.type, image.data ),\n\t\t\t\t\t\twidth: image.width,\n\t\t\t\t\t\theight: image.height\n\t\t\t\t\t};\n\n\t\t\t\t} else {\n\n\t\t\t\t\treturn null;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( json !== undefined && json.length > 0 ) {\n\n\t\t\tloader = new ImageLoader( this.manager );\n\t\t\tloader.setCrossOrigin( this.crossOrigin );\n\n\t\t\tfor ( let i = 0, il = json.length; i < il; i ++ ) {\n\n\t\t\t\tconst image = json[ i ];\n\t\t\t\tconst url = image.url;\n\n\t\t\t\tif ( Array.isArray( url ) ) {\n\n\t\t\t\t\t// load array of images e.g CubeTexture\n\n\t\t\t\t\tconst imageArray = [];\n\n\t\t\t\t\tfor ( let j = 0, jl = url.length; j < jl; j ++ ) {\n\n\t\t\t\t\t\tconst currentUrl = url[ j ];\n\n\t\t\t\t\t\tconst deserializedImage = await deserializeImage( currentUrl );\n\n\t\t\t\t\t\tif ( deserializedImage !== null ) {\n\n\t\t\t\t\t\t\tif ( deserializedImage instanceof HTMLImageElement ) {\n\n\t\t\t\t\t\t\t\timageArray.push( deserializedImage );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t// special case: handle array of data textures for cube textures\n\n\t\t\t\t\t\t\t\timageArray.push( new DataTexture( deserializedImage.data, deserializedImage.width, deserializedImage.height ) );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\timages[ image.uuid ] = new Source( imageArray );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// load single image\n\n\t\t\t\t\tconst deserializedImage = await deserializeImage( image.url );\n\t\t\t\t\timages[ image.uuid ] = new Source( deserializedImage );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn images;\n\n\t}\n\n\tparseTextures( json, images ) {\n\n\t\tfunction parseConstant( value, type ) {\n\n\t\t\tif ( typeof value === 'number' ) return value;\n\n\t\t\tconsole.warn( 'THREE.ObjectLoader.parseTexture: Constant should be in numeric form.', value );\n\n\t\t\treturn type[ value ];\n\n\t\t}\n\n\t\tconst textures = {};\n\n\t\tif ( json !== undefined ) {\n\n\t\t\tfor ( let i = 0, l = json.length; i < l; i ++ ) {\n\n\t\t\t\tconst data = json[ i ];\n\n\t\t\t\tif ( data.image === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: No \"image\" specified for', data.uuid );\n\n\t\t\t\t}\n\n\t\t\t\tif ( images[ data.image ] === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined image', data.image );\n\n\t\t\t\t}\n\n\t\t\t\tconst source = images[ data.image ];\n\t\t\t\tconst image = source.data;\n\n\t\t\t\tlet texture;\n\n\t\t\t\tif ( Array.isArray( image ) ) {\n\n\t\t\t\t\ttexture = new CubeTexture();\n\n\t\t\t\t\tif ( image.length === 6 ) texture.needsUpdate = true;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tif ( image && image.data ) {\n\n\t\t\t\t\t\ttexture = new DataTexture();\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\ttexture = new Texture();\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( image ) texture.needsUpdate = true; // textures can have undefined image data\n\n\t\t\t\t}\n\n\t\t\t\ttexture.source = source;\n\n\t\t\t\ttexture.uuid = data.uuid;\n\n\t\t\t\tif ( data.name !== undefined ) texture.name = data.name;\n\n\t\t\t\tif ( data.mapping !== undefined ) texture.mapping = parseConstant( data.mapping, TEXTURE_MAPPING );\n\t\t\t\tif ( data.channel !== undefined ) texture.channel = data.channel;\n\n\t\t\t\tif ( data.offset !== undefined ) texture.offset.fromArray( data.offset );\n\t\t\t\tif ( data.repeat !== undefined ) texture.repeat.fromArray( data.repeat );\n\t\t\t\tif ( data.center !== undefined ) texture.center.fromArray( data.center );\n\t\t\t\tif ( data.rotation !== undefined ) texture.rotation = data.rotation;\n\n\t\t\t\tif ( data.wrap !== undefined ) {\n\n\t\t\t\t\ttexture.wrapS = parseConstant( data.wrap[ 0 ], TEXTURE_WRAPPING );\n\t\t\t\t\ttexture.wrapT = parseConstant( data.wrap[ 1 ], TEXTURE_WRAPPING );\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.format !== undefined ) texture.format = data.format;\n\t\t\t\tif ( data.internalFormat !== undefined ) texture.internalFormat = data.internalFormat;\n\t\t\t\tif ( data.type !== undefined ) texture.type = data.type;\n\t\t\t\tif ( data.colorSpace !== undefined ) texture.colorSpace = data.colorSpace;\n\n\t\t\t\tif ( data.minFilter !== undefined ) texture.minFilter = parseConstant( data.minFilter, TEXTURE_FILTER );\n\t\t\t\tif ( data.magFilter !== undefined ) texture.magFilter = parseConstant( data.magFilter, TEXTURE_FILTER );\n\t\t\t\tif ( data.anisotropy !== undefined ) texture.anisotropy = data.anisotropy;\n\n\t\t\t\tif ( data.flipY !== undefined ) texture.flipY = data.flipY;\n\n\t\t\t\tif ( data.generateMipmaps !== undefined ) texture.generateMipmaps = data.generateMipmaps;\n\t\t\t\tif ( data.premultiplyAlpha !== undefined ) texture.premultiplyAlpha = data.premultiplyAlpha;\n\t\t\t\tif ( data.unpackAlignment !== undefined ) texture.unpackAlignment = data.unpackAlignment;\n\t\t\t\tif ( data.compareFunction !== undefined ) texture.compareFunction = data.compareFunction;\n\n\t\t\t\tif ( data.userData !== undefined ) texture.userData = data.userData;\n\n\t\t\t\ttextures[ data.uuid ] = texture;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn textures;\n\n\t}\n\n\tparseObject( data, geometries, materials, textures, animations ) {\n\n\t\tlet object;\n\n\t\tfunction getGeometry( name ) {\n\n\t\t\tif ( geometries[ name ] === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined geometry', name );\n\n\t\t\t}\n\n\t\t\treturn geometries[ name ];\n\n\t\t}\n\n\t\tfunction getMaterial( name ) {\n\n\t\t\tif ( name === undefined ) return undefined;\n\n\t\t\tif ( Array.isArray( name ) ) {\n\n\t\t\t\tconst array = [];\n\n\t\t\t\tfor ( let i = 0, l = name.length; i < l; i ++ ) {\n\n\t\t\t\t\tconst uuid = name[ i ];\n\n\t\t\t\t\tif ( materials[ uuid ] === undefined ) {\n\n\t\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined material', uuid );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tarray.push( materials[ uuid ] );\n\n\t\t\t\t}\n\n\t\t\t\treturn array;\n\n\t\t\t}\n\n\t\t\tif ( materials[ name ] === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined material', name );\n\n\t\t\t}\n\n\t\t\treturn materials[ name ];\n\n\t\t}\n\n\t\tfunction getTexture( uuid ) {\n\n\t\t\tif ( textures[ uuid ] === undefined ) {\n\n\t\t\t\tconsole.warn( 'THREE.ObjectLoader: Undefined texture', uuid );\n\n\t\t\t}\n\n\t\t\treturn textures[ uuid ];\n\n\t\t}\n\n\t\tlet geometry, material;\n\n\t\tswitch ( data.type ) {\n\n\t\t\tcase 'Scene':\n\n\t\t\t\tobject = new Scene();\n\n\t\t\t\tif ( data.background !== undefined ) {\n\n\t\t\t\t\tif ( Number.isInteger( data.background ) ) {\n\n\t\t\t\t\t\tobject.background = new Color( data.background );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tobject.background = getTexture( data.background );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.environment !== undefined ) {\n\n\t\t\t\t\tobject.environment = getTexture( data.environment );\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.fog !== undefined ) {\n\n\t\t\t\t\tif ( data.fog.type === 'Fog' ) {\n\n\t\t\t\t\t\tobject.fog = new Fog( data.fog.color, data.fog.near, data.fog.far );\n\n\t\t\t\t\t} else if ( data.fog.type === 'FogExp2' ) {\n\n\t\t\t\t\t\tobject.fog = new FogExp2( data.fog.color, data.fog.density );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( data.fog.name !== '' ) {\n\n\t\t\t\t\t\tobject.fog.name = data.fog.name;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tif ( data.backgroundBlurriness !== undefined ) object.backgroundBlurriness = data.backgroundBlurriness;\n\t\t\t\tif ( data.backgroundIntensity !== undefined ) object.backgroundIntensity = data.backgroundIntensity;\n\t\t\t\tif ( data.backgroundRotation !== undefined ) object.backgroundRotation.fromArray( data.backgroundRotation );\n\n\t\t\t\tif ( data.environmentIntensity !== undefined ) object.environmentIntensity = data.environmentIntensity;\n\t\t\t\tif ( data.environmentRotation !== undefined ) object.environmentRotation.fromArray( data.environmentRotation );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'PerspectiveCamera':\n\n\t\t\t\tobject = new PerspectiveCamera( data.fov, data.aspect, data.near, data.far );\n\n\t\t\t\tif ( data.focus !== undefined ) object.focus = data.focus;\n\t\t\t\tif ( data.zoom !== undefined ) object.zoom = data.zoom;\n\t\t\t\tif ( data.filmGauge !== undefined ) object.filmGauge = data.filmGauge;\n\t\t\t\tif ( data.filmOffset !== undefined ) object.filmOffset = data.filmOffset;\n\t\t\t\tif ( data.view !== undefined ) object.view = Object.assign( {}, data.view );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'OrthographicCamera':\n\n\t\t\t\tobject = new OrthographicCamera( data.left, data.right, data.top, data.bottom, data.near, data.far );\n\n\t\t\t\tif ( data.zoom !== undefined ) object.zoom = data.zoom;\n\t\t\t\tif ( data.view !== undefined ) object.view = Object.assign( {}, data.view );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'AmbientLight':\n\n\t\t\t\tobject = new AmbientLight( data.color, data.intensity );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'DirectionalLight':\n\n\t\t\t\tobject = new DirectionalLight( data.color, data.intensity );\n\t\t\t\tobject.target = data.target || '';\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'PointLight':\n\n\t\t\t\tobject = new PointLight( data.color, data.intensity, data.distance, data.decay );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'RectAreaLight':\n\n\t\t\t\tobject = new RectAreaLight( data.color, data.intensity, data.width, data.height );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'SpotLight':\n\n\t\t\t\tobject = new SpotLight( data.color, data.intensity, data.distance, data.angle, data.penumbra, data.decay );\n\t\t\t\tobject.target = data.target || '';\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'HemisphereLight':\n\n\t\t\t\tobject = new HemisphereLight( data.color, data.groundColor, data.intensity );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'LightProbe':\n\n\t\t\t\tobject = new LightProbe().fromJSON( data );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'SkinnedMesh':\n\n\t\t\t\tgeometry = getGeometry( data.geometry );\n\t\t\t \tmaterial = getMaterial( data.material );\n\n\t\t\t\tobject = new SkinnedMesh( geometry, material );\n\n\t\t\t\tif ( data.bindMode !== undefined ) object.bindMode = data.bindMode;\n\t\t\t\tif ( data.bindMatrix !== undefined ) object.bindMatrix.fromArray( data.bindMatrix );\n\t\t\t\tif ( data.skeleton !== undefined ) object.skeleton = data.skeleton;\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'Mesh':\n\n\t\t\t\tgeometry = getGeometry( data.geometry );\n\t\t\t\tmaterial = getMaterial( data.material );\n\n\t\t\t\tobject = new Mesh( geometry, material );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'InstancedMesh':\n\n\t\t\t\tgeometry = getGeometry( data.geometry );\n\t\t\t\tmaterial = getMaterial( data.material );\n\t\t\t\tconst count = data.count;\n\t\t\t\tconst instanceMatrix = data.instanceMatrix;\n\t\t\t\tconst instanceColor = data.instanceColor;\n\n\t\t\t\tobject = new InstancedMesh( geometry, material, count );\n\t\t\t\tobject.instanceMatrix = new InstancedBufferAttribute( new Float32Array( instanceMatrix.array ), 16 );\n\t\t\t\tif ( instanceColor !== undefined ) object.instanceColor = new InstancedBufferAttribute( new Float32Array( instanceColor.array ), instanceColor.itemSize );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'BatchedMesh':\n\n\t\t\t\tgeometry = getGeometry( data.geometry );\n\t\t\t\tmaterial = getMaterial( data.material );\n\n\t\t\t\tobject = new BatchedMesh( data.maxInstanceCount, data.maxVertexCount, data.maxIndexCount, material );\n\t\t\t\tobject.geometry = geometry;\n\t\t\t\tobject.perObjectFrustumCulled = data.perObjectFrustumCulled;\n\t\t\t\tobject.sortObjects = data.sortObjects;\n\n\t\t\t\tobject._drawRanges = data.drawRanges;\n\t\t\t\tobject._reservedRanges = data.reservedRanges;\n\n\t\t\t\tobject._visibility = data.visibility;\n\t\t\t\tobject._active = data.active;\n\t\t\t\tobject._bounds = data.bounds.map( bound => {\n\n\t\t\t\t\tconst box = new Box3();\n\t\t\t\t\tbox.min.fromArray( bound.boxMin );\n\t\t\t\t\tbox.max.fromArray( bound.boxMax );\n\n\t\t\t\t\tconst sphere = new Sphere();\n\t\t\t\t\tsphere.radius = bound.sphereRadius;\n\t\t\t\t\tsphere.center.fromArray( bound.sphereCenter );\n\n\t\t\t\t\treturn {\n\t\t\t\t\t\tboxInitialized: bound.boxInitialized,\n\t\t\t\t\t\tbox: box,\n\n\t\t\t\t\t\tsphereInitialized: bound.sphereInitialized,\n\t\t\t\t\t\tsphere: sphere\n\t\t\t\t\t};\n\n\t\t\t\t} );\n\n\t\t\t\tobject._maxInstanceCount = data.maxInstanceCount;\n\t\t\t\tobject._maxVertexCount = data.maxVertexCount;\n\t\t\t\tobject._maxIndexCount = data.maxIndexCount;\n\n\t\t\t\tobject._geometryInitialized = data.geometryInitialized;\n\t\t\t\tobject._geometryCount = data.geometryCount;\n\n\t\t\t\tobject._matricesTexture = getTexture( data.matricesTexture.uuid );\n\t\t\t\tif ( data.colorsTexture !== undefined ) object._colorsTexture = getTexture( data.colorsTexture.uuid );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'LOD':\n\n\t\t\t\tobject = new LOD();\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'Line':\n\n\t\t\t\tobject = new Line( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'LineLoop':\n\n\t\t\t\tobject = new LineLoop( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'LineSegments':\n\n\t\t\t\tobject = new LineSegments( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'PointCloud':\n\t\t\tcase 'Points':\n\n\t\t\t\tobject = new Points( getGeometry( data.geometry ), getMaterial( data.material ) );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'Sprite':\n\n\t\t\t\tobject = new Sprite( getMaterial( data.material ) );\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'Group':\n\n\t\t\t\tobject = new Group();\n\n\t\t\t\tbreak;\n\n\t\t\tcase 'Bone':\n\n\t\t\t\tobject = new Bone();\n\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\n\t\t\t\tobject = new Object3D();\n\n\t\t}\n\n\t\tobject.uuid = data.uuid;\n\n\t\tif ( data.name !== undefined ) object.name = data.name;\n\n\t\tif ( data.matrix !== undefined ) {\n\n\t\t\tobject.matrix.fromArray( data.matrix );\n\n\t\t\tif ( data.matrixAutoUpdate !== undefined ) object.matrixAutoUpdate = data.matrixAutoUpdate;\n\t\t\tif ( object.matrixAutoUpdate ) object.matrix.decompose( object.position, object.quaternion, object.scale );\n\n\t\t} else {\n\n\t\t\tif ( data.position !== undefined ) object.position.fromArray( data.position );\n\t\t\tif ( data.rotation !== undefined ) object.rotation.fromArray( data.rotation );\n\t\t\tif ( data.quaternion !== undefined ) object.quaternion.fromArray( data.quaternion );\n\t\t\tif ( data.scale !== undefined ) object.scale.fromArray( data.scale );\n\n\t\t}\n\n\t\tif ( data.up !== undefined ) object.up.fromArray( data.up );\n\n\t\tif ( data.castShadow !== undefined ) object.castShadow = data.castShadow;\n\t\tif ( data.receiveShadow !== undefined ) object.receiveShadow = data.receiveShadow;\n\n\t\tif ( data.shadow ) {\n\n\t\t\tif ( data.shadow.intensity !== undefined ) object.shadow.intensity = data.shadow.intensity;\n\t\t\tif ( data.shadow.bias !== undefined ) object.shadow.bias = data.shadow.bias;\n\t\t\tif ( data.shadow.normalBias !== undefined ) object.shadow.normalBias = data.shadow.normalBias;\n\t\t\tif ( data.shadow.radius !== undefined ) object.shadow.radius = data.shadow.radius;\n\t\t\tif ( data.shadow.mapSize !== undefined ) object.shadow.mapSize.fromArray( data.shadow.mapSize );\n\t\t\tif ( data.shadow.camera !== undefined ) object.shadow.camera = this.parseObject( data.shadow.camera );\n\n\t\t}\n\n\t\tif ( data.visible !== undefined ) object.visible = data.visible;\n\t\tif ( data.frustumCulled !== undefined ) object.frustumCulled = data.frustumCulled;\n\t\tif ( data.renderOrder !== undefined ) object.renderOrder = data.renderOrder;\n\t\tif ( data.userData !== undefined ) object.userData = data.userData;\n\t\tif ( data.layers !== undefined ) object.layers.mask = data.layers;\n\n\t\tif ( data.children !== undefined ) {\n\n\t\t\tconst children = data.children;\n\n\t\t\tfor ( let i = 0; i < children.length; i ++ ) {\n\n\t\t\t\tobject.add( this.parseObject( children[ i ], geometries, materials, textures, animations ) );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( data.animations !== undefined ) {\n\n\t\t\tconst objectAnimations = data.animations;\n\n\t\t\tfor ( let i = 0; i < objectAnimations.length; i ++ ) {\n\n\t\t\t\tconst uuid = objectAnimations[ i ];\n\n\t\t\t\tobject.animations.push( animations[ uuid ] );\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( data.type === 'LOD' ) {\n\n\t\t\tif ( data.autoUpdate !== undefined ) object.autoUpdate = data.autoUpdate;\n\n\t\t\tconst levels = data.levels;\n\n\t\t\tfor ( let l = 0; l < levels.length; l ++ ) {\n\n\t\t\t\tconst level = levels[ l ];\n\t\t\t\tconst child = object.getObjectByProperty( 'uuid', level.object );\n\n\t\t\t\tif ( child !== undefined ) {\n\n\t\t\t\t\tobject.addLevel( child, level.distance, level.hysteresis );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn object;\n\n\t}\n\n\tbindSkeletons( object, skeletons ) {\n\n\t\tif ( Object.keys( skeletons ).length === 0 ) return;\n\n\t\tobject.traverse( function ( child ) {\n\n\t\t\tif ( child.isSkinnedMesh === true && child.skeleton !== undefined ) {\n\n\t\t\t\tconst skeleton = skeletons[ child.skeleton ];\n\n\t\t\t\tif ( skeleton === undefined ) {\n\n\t\t\t\t\tconsole.warn( 'THREE.ObjectLoader: No skeleton found with UUID:', child.skeleton );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tchild.bind( skeleton, child.bindMatrix );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} );\n\n\t}\n\n\tbindLightTargets( object ) {\n\n\t\tobject.traverse( function ( child ) {\n\n\t\t\tif ( child.isDirectionalLight || child.isSpotLight ) {\n\n\t\t\t\tconst uuid = child.target;\n\n\t\t\t\tconst target = object.getObjectByProperty( 'uuid', uuid );\n\n\t\t\t\tif ( target !== undefined ) {\n\n\t\t\t\t\tchild.target = target;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tchild.target = new Object3D();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} );\n\n\t}\n\n}\n\nconst TEXTURE_MAPPING = {\n\tUVMapping: UVMapping,\n\tCubeReflectionMapping: CubeReflectionMapping,\n\tCubeRefractionMapping: CubeRefractionMapping,\n\tEquirectangularReflectionMapping: EquirectangularReflectionMapping,\n\tEquirectangularRefractionMapping: EquirectangularRefractionMapping,\n\tCubeUVReflectionMapping: CubeUVReflectionMapping\n};\n\nconst TEXTURE_WRAPPING = {\n\tRepeatWrapping: RepeatWrapping,\n\tClampToEdgeWrapping: ClampToEdgeWrapping,\n\tMirroredRepeatWrapping: MirroredRepeatWrapping\n};\n\nconst TEXTURE_FILTER = {\n\tNearestFilter: NearestFilter,\n\tNearestMipmapNearestFilter: NearestMipmapNearestFilter,\n\tNearestMipmapLinearFilter: NearestMipmapLinearFilter,\n\tLinearFilter: LinearFilter,\n\tLinearMipmapNearestFilter: LinearMipmapNearestFilter,\n\tLinearMipmapLinearFilter: LinearMipmapLinearFilter\n};\n\nclass ImageBitmapLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t\tthis.isImageBitmapLoader = true;\n\n\t\tif ( typeof createImageBitmap === 'undefined' ) {\n\n\t\t\tconsole.warn( 'THREE.ImageBitmapLoader: createImageBitmap() not supported.' );\n\n\t\t}\n\n\t\tif ( typeof fetch === 'undefined' ) {\n\n\t\t\tconsole.warn( 'THREE.ImageBitmapLoader: fetch() not supported.' );\n\n\t\t}\n\n\t\tthis.options = { premultiplyAlpha: 'none' };\n\n\t}\n\n\tsetOptions( options ) {\n\n\t\tthis.options = options;\n\n\t\treturn this;\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tif ( url === undefined ) url = '';\n\n\t\tif ( this.path !== undefined ) url = this.path + url;\n\n\t\turl = this.manager.resolveURL( url );\n\n\t\tconst scope = this;\n\n\t\tconst cached = Cache.get( url );\n\n\t\tif ( cached !== undefined ) {\n\n\t\t\tscope.manager.itemStart( url );\n\n\t\t\t// If cached is a promise, wait for it to resolve\n\t\t\tif ( cached.then ) {\n\n\t\t\t\tcached.then( imageBitmap => {\n\n\t\t\t\t\tif ( onLoad ) onLoad( imageBitmap );\n\n\t\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t\t} ).catch( e => {\n\n\t\t\t\t\tif ( onError ) onError( e );\n\n\t\t\t\t} );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\t// If cached is not a promise (i.e., it's already an imageBitmap)\n\t\t\tsetTimeout( function () {\n\n\t\t\t\tif ( onLoad ) onLoad( cached );\n\n\t\t\t\tscope.manager.itemEnd( url );\n\n\t\t\t}, 0 );\n\n\t\t\treturn cached;\n\n\t\t}\n\n\t\tconst fetchOptions = {};\n\t\tfetchOptions.credentials = ( this.crossOrigin === 'anonymous' ) ? 'same-origin' : 'include';\n\t\tfetchOptions.headers = this.requestHeader;\n\n\t\tconst promise = fetch( url, fetchOptions ).then( function ( res ) {\n\n\t\t\treturn res.blob();\n\n\t\t} ).then( function ( blob ) {\n\n\t\t\treturn createImageBitmap( blob, Object.assign( scope.options, { colorSpaceConversion: 'none' } ) );\n\n\t\t} ).then( function ( imageBitmap ) {\n\n\t\t\tCache.add( url, imageBitmap );\n\n\t\t\tif ( onLoad ) onLoad( imageBitmap );\n\n\t\t\tscope.manager.itemEnd( url );\n\n\t\t\treturn imageBitmap;\n\n\t\t} ).catch( function ( e ) {\n\n\t\t\tif ( onError ) onError( e );\n\n\t\t\tCache.remove( url );\n\n\t\t\tscope.manager.itemError( url );\n\t\t\tscope.manager.itemEnd( url );\n\n\t\t} );\n\n\t\tCache.add( url, promise );\n\t\tscope.manager.itemStart( url );\n\n\t}\n\n}\n\nlet _context;\n\nclass AudioContext {\n\n\tstatic getContext() {\n\n\t\tif ( _context === undefined ) {\n\n\t\t\t_context = new ( window.AudioContext || window.webkitAudioContext )();\n\n\t\t}\n\n\t\treturn _context;\n\n\t}\n\n\tstatic setContext( value ) {\n\n\t\t_context = value;\n\n\t}\n\n}\n\nclass AudioLoader extends Loader {\n\n\tconstructor( manager ) {\n\n\t\tsuper( manager );\n\n\t}\n\n\tload( url, onLoad, onProgress, onError ) {\n\n\t\tconst scope = this;\n\n\t\tconst loader = new FileLoader( this.manager );\n\t\tloader.setResponseType( 'arraybuffer' );\n\t\tloader.setPath( this.path );\n\t\tloader.setRequestHeader( this.requestHeader );\n\t\tloader.setWithCredentials( this.withCredentials );\n\t\tloader.load( url, function ( buffer ) {\n\n\t\t\ttry {\n\n\t\t\t\t// Create a copy of the buffer. The `decodeAudioData` method\n\t\t\t\t// detaches the buffer when complete, preventing reuse.\n\t\t\t\tconst bufferCopy = buffer.slice( 0 );\n\n\t\t\t\tconst context = AudioContext.getContext();\n\t\t\t\tcontext.decodeAudioData( bufferCopy, function ( audioBuffer ) {\n\n\t\t\t\t\tonLoad( audioBuffer );\n\n\t\t\t\t} ).catch( handleError );\n\n\t\t\t} catch ( e ) {\n\n\t\t\t\thandleError( e );\n\n\t\t\t}\n\n\t\t}, onProgress, onError );\n\n\t\tfunction handleError( e ) {\n\n\t\t\tif ( onError ) {\n\n\t\t\t\tonError( e );\n\n\t\t\t} else {\n\n\t\t\t\tconsole.error( e );\n\n\t\t\t}\n\n\t\t\tscope.manager.itemError( url );\n\n\t\t}\n\n\t}\n\n}\n\nconst _eyeRight = /*@__PURE__*/ new Matrix4();\nconst _eyeLeft = /*@__PURE__*/ new Matrix4();\nconst _projectionMatrix = /*@__PURE__*/ new Matrix4();\n\nclass StereoCamera {\n\n\tconstructor() {\n\n\t\tthis.type = 'StereoCamera';\n\n\t\tthis.aspect = 1;\n\n\t\tthis.eyeSep = 0.064;\n\n\t\tthis.cameraL = new PerspectiveCamera();\n\t\tthis.cameraL.layers.enable( 1 );\n\t\tthis.cameraL.matrixAutoUpdate = false;\n\n\t\tthis.cameraR = new PerspectiveCamera();\n\t\tthis.cameraR.layers.enable( 2 );\n\t\tthis.cameraR.matrixAutoUpdate = false;\n\n\t\tthis._cache = {\n\t\t\tfocus: null,\n\t\t\tfov: null,\n\t\t\taspect: null,\n\t\t\tnear: null,\n\t\t\tfar: null,\n\t\t\tzoom: null,\n\t\t\teyeSep: null\n\t\t};\n\n\t}\n\n\tupdate( camera ) {\n\n\t\tconst cache = this._cache;\n\n\t\tconst needsUpdate = cache.focus !== camera.focus || cache.fov !== camera.fov ||\n\t\t\tcache.aspect !== camera.aspect * this.aspect || cache.near !== camera.near ||\n\t\t\tcache.far !== camera.far || cache.zoom !== camera.zoom || cache.eyeSep !== this.eyeSep;\n\n\t\tif ( needsUpdate ) {\n\n\t\t\tcache.focus = camera.focus;\n\t\t\tcache.fov = camera.fov;\n\t\t\tcache.aspect = camera.aspect * this.aspect;\n\t\t\tcache.near = camera.near;\n\t\t\tcache.far = camera.far;\n\t\t\tcache.zoom = camera.zoom;\n\t\t\tcache.eyeSep = this.eyeSep;\n\n\t\t\t// Off-axis stereoscopic effect based on\n\t\t\t// http://paulbourke.net/stereographics/stereorender/\n\n\t\t\t_projectionMatrix.copy( camera.projectionMatrix );\n\t\t\tconst eyeSepHalf = cache.eyeSep / 2;\n\t\t\tconst eyeSepOnProjection = eyeSepHalf * cache.near / cache.focus;\n\t\t\tconst ymax = ( cache.near * Math.tan( DEG2RAD * cache.fov * 0.5 ) ) / cache.zoom;\n\t\t\tlet xmin, xmax;\n\n\t\t\t// translate xOffset\n\n\t\t\t_eyeLeft.elements[ 12 ] = - eyeSepHalf;\n\t\t\t_eyeRight.elements[ 12 ] = eyeSepHalf;\n\n\t\t\t// for left eye\n\n\t\t\txmin = - ymax * cache.aspect + eyeSepOnProjection;\n\t\t\txmax = ymax * cache.aspect + eyeSepOnProjection;\n\n\t\t\t_projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );\n\t\t\t_projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );\n\n\t\t\tthis.cameraL.projectionMatrix.copy( _projectionMatrix );\n\n\t\t\t// for right eye\n\n\t\t\txmin = - ymax * cache.aspect - eyeSepOnProjection;\n\t\t\txmax = ymax * cache.aspect - eyeSepOnProjection;\n\n\t\t\t_projectionMatrix.elements[ 0 ] = 2 * cache.near / ( xmax - xmin );\n\t\t\t_projectionMatrix.elements[ 8 ] = ( xmax + xmin ) / ( xmax - xmin );\n\n\t\t\tthis.cameraR.projectionMatrix.copy( _projectionMatrix );\n\n\t\t}\n\n\t\tthis.cameraL.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeLeft );\n\t\tthis.cameraR.matrixWorld.copy( camera.matrixWorld ).multiply( _eyeRight );\n\n\t}\n\n}\n\nclass Clock {\n\n\tconstructor( autoStart = true ) {\n\n\t\tthis.autoStart = autoStart;\n\n\t\tthis.startTime = 0;\n\t\tthis.oldTime = 0;\n\t\tthis.elapsedTime = 0;\n\n\t\tthis.running = false;\n\n\t}\n\n\tstart() {\n\n\t\tthis.startTime = now();\n\n\t\tthis.oldTime = this.startTime;\n\t\tthis.elapsedTime = 0;\n\t\tthis.running = true;\n\n\t}\n\n\tstop() {\n\n\t\tthis.getElapsedTime();\n\t\tthis.running = false;\n\t\tthis.autoStart = false;\n\n\t}\n\n\tgetElapsedTime() {\n\n\t\tthis.getDelta();\n\t\treturn this.elapsedTime;\n\n\t}\n\n\tgetDelta() {\n\n\t\tlet diff = 0;\n\n\t\tif ( this.autoStart && ! this.running ) {\n\n\t\t\tthis.start();\n\t\t\treturn 0;\n\n\t\t}\n\n\t\tif ( this.running ) {\n\n\t\t\tconst newTime = now();\n\n\t\t\tdiff = ( newTime - this.oldTime ) / 1000;\n\t\t\tthis.oldTime = newTime;\n\n\t\t\tthis.elapsedTime += diff;\n\n\t\t}\n\n\t\treturn diff;\n\n\t}\n\n}\n\nfunction now() {\n\n\treturn ( typeof performance === 'undefined' ? Date : performance ).now(); // see #10732\n\n}\n\nconst _position$1 = /*@__PURE__*/ new Vector3();\nconst _quaternion$1 = /*@__PURE__*/ new Quaternion();\nconst _scale$1 = /*@__PURE__*/ new Vector3();\nconst _orientation$1 = /*@__PURE__*/ new Vector3();\n\nclass AudioListener extends Object3D {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.type = 'AudioListener';\n\n\t\tthis.context = AudioContext.getContext();\n\n\t\tthis.gain = this.context.createGain();\n\t\tthis.gain.connect( this.context.destination );\n\n\t\tthis.filter = null;\n\n\t\tthis.timeDelta = 0;\n\n\t\t// private\n\n\t\tthis._clock = new Clock();\n\n\t}\n\n\tgetInput() {\n\n\t\treturn this.gain;\n\n\t}\n\n\tremoveFilter() {\n\n\t\tif ( this.filter !== null ) {\n\n\t\t\tthis.gain.disconnect( this.filter );\n\t\t\tthis.filter.disconnect( this.context.destination );\n\t\t\tthis.gain.connect( this.context.destination );\n\t\t\tthis.filter = null;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetFilter() {\n\n\t\treturn this.filter;\n\n\t}\n\n\tsetFilter( value ) {\n\n\t\tif ( this.filter !== null ) {\n\n\t\t\tthis.gain.disconnect( this.filter );\n\t\t\tthis.filter.disconnect( this.context.destination );\n\n\t\t} else {\n\n\t\t\tthis.gain.disconnect( this.context.destination );\n\n\t\t}\n\n\t\tthis.filter = value;\n\t\tthis.gain.connect( this.filter );\n\t\tthis.filter.connect( this.context.destination );\n\n\t\treturn this;\n\n\t}\n\n\tgetMasterVolume() {\n\n\t\treturn this.gain.gain.value;\n\n\t}\n\n\tsetMasterVolume( value ) {\n\n\t\tthis.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );\n\n\t\treturn this;\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t\tconst listener = this.context.listener;\n\t\tconst up = this.up;\n\n\t\tthis.timeDelta = this._clock.getDelta();\n\n\t\tthis.matrixWorld.decompose( _position$1, _quaternion$1, _scale$1 );\n\n\t\t_orientation$1.set( 0, 0, - 1 ).applyQuaternion( _quaternion$1 );\n\n\t\tif ( listener.positionX ) {\n\n\t\t\t// code path for Chrome (see #14393)\n\n\t\t\tconst endTime = this.context.currentTime + this.timeDelta;\n\n\t\t\tlistener.positionX.linearRampToValueAtTime( _position$1.x, endTime );\n\t\t\tlistener.positionY.linearRampToValueAtTime( _position$1.y, endTime );\n\t\t\tlistener.positionZ.linearRampToValueAtTime( _position$1.z, endTime );\n\t\t\tlistener.forwardX.linearRampToValueAtTime( _orientation$1.x, endTime );\n\t\t\tlistener.forwardY.linearRampToValueAtTime( _orientation$1.y, endTime );\n\t\t\tlistener.forwardZ.linearRampToValueAtTime( _orientation$1.z, endTime );\n\t\t\tlistener.upX.linearRampToValueAtTime( up.x, endTime );\n\t\t\tlistener.upY.linearRampToValueAtTime( up.y, endTime );\n\t\t\tlistener.upZ.linearRampToValueAtTime( up.z, endTime );\n\n\t\t} else {\n\n\t\t\tlistener.setPosition( _position$1.x, _position$1.y, _position$1.z );\n\t\t\tlistener.setOrientation( _orientation$1.x, _orientation$1.y, _orientation$1.z, up.x, up.y, up.z );\n\n\t\t}\n\n\t}\n\n}\n\nclass Audio extends Object3D {\n\n\tconstructor( listener ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'Audio';\n\n\t\tthis.listener = listener;\n\t\tthis.context = listener.context;\n\n\t\tthis.gain = this.context.createGain();\n\t\tthis.gain.connect( listener.getInput() );\n\n\t\tthis.autoplay = false;\n\n\t\tthis.buffer = null;\n\t\tthis.detune = 0;\n\t\tthis.loop = false;\n\t\tthis.loopStart = 0;\n\t\tthis.loopEnd = 0;\n\t\tthis.offset = 0;\n\t\tthis.duration = undefined;\n\t\tthis.playbackRate = 1;\n\t\tthis.isPlaying = false;\n\t\tthis.hasPlaybackControl = true;\n\t\tthis.source = null;\n\t\tthis.sourceType = 'empty';\n\n\t\tthis._startedAt = 0;\n\t\tthis._progress = 0;\n\t\tthis._connected = false;\n\n\t\tthis.filters = [];\n\n\t}\n\n\tgetOutput() {\n\n\t\treturn this.gain;\n\n\t}\n\n\tsetNodeSource( audioNode ) {\n\n\t\tthis.hasPlaybackControl = false;\n\t\tthis.sourceType = 'audioNode';\n\t\tthis.source = audioNode;\n\t\tthis.connect();\n\n\t\treturn this;\n\n\t}\n\n\tsetMediaElementSource( mediaElement ) {\n\n\t\tthis.hasPlaybackControl = false;\n\t\tthis.sourceType = 'mediaNode';\n\t\tthis.source = this.context.createMediaElementSource( mediaElement );\n\t\tthis.connect();\n\n\t\treturn this;\n\n\t}\n\n\tsetMediaStreamSource( mediaStream ) {\n\n\t\tthis.hasPlaybackControl = false;\n\t\tthis.sourceType = 'mediaStreamNode';\n\t\tthis.source = this.context.createMediaStreamSource( mediaStream );\n\t\tthis.connect();\n\n\t\treturn this;\n\n\t}\n\n\tsetBuffer( audioBuffer ) {\n\n\t\tthis.buffer = audioBuffer;\n\t\tthis.sourceType = 'buffer';\n\n\t\tif ( this.autoplay ) this.play();\n\n\t\treturn this;\n\n\t}\n\n\tplay( delay = 0 ) {\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: Audio is already playing.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis._startedAt = this.context.currentTime + delay;\n\n\t\tconst source = this.context.createBufferSource();\n\t\tsource.buffer = this.buffer;\n\t\tsource.loop = this.loop;\n\t\tsource.loopStart = this.loopStart;\n\t\tsource.loopEnd = this.loopEnd;\n\t\tsource.onended = this.onEnded.bind( this );\n\t\tsource.start( this._startedAt, this._progress + this.offset, this.duration );\n\n\t\tthis.isPlaying = true;\n\n\t\tthis.source = source;\n\n\t\tthis.setDetune( this.detune );\n\t\tthis.setPlaybackRate( this.playbackRate );\n\n\t\treturn this.connect();\n\n\t}\n\n\tpause() {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\t// update current progress\n\n\t\t\tthis._progress += Math.max( this.context.currentTime - this._startedAt, 0 ) * this.playbackRate;\n\n\t\t\tif ( this.loop === true ) {\n\n\t\t\t\t// ensure _progress does not exceed duration with looped audios\n\n\t\t\t\tthis._progress = this._progress % ( this.duration || this.buffer.duration );\n\n\t\t\t}\n\n\t\t\tthis.source.stop();\n\t\t\tthis.source.onended = null;\n\n\t\t\tthis.isPlaying = false;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tstop() {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis._progress = 0;\n\n\t\tif ( this.source !== null ) {\n\n\t\t\tthis.source.stop();\n\t\t\tthis.source.onended = null;\n\n\t\t}\n\n\t\tthis.isPlaying = false;\n\n\t\treturn this;\n\n\t}\n\n\tconnect() {\n\n\t\tif ( this.filters.length > 0 ) {\n\n\t\t\tthis.source.connect( this.filters[ 0 ] );\n\n\t\t\tfor ( let i = 1, l = this.filters.length; i < l; i ++ ) {\n\n\t\t\t\tthis.filters[ i - 1 ].connect( this.filters[ i ] );\n\n\t\t\t}\n\n\t\t\tthis.filters[ this.filters.length - 1 ].connect( this.getOutput() );\n\n\t\t} else {\n\n\t\t\tthis.source.connect( this.getOutput() );\n\n\t\t}\n\n\t\tthis._connected = true;\n\n\t\treturn this;\n\n\t}\n\n\tdisconnect() {\n\n\t\tif ( this._connected === false ) {\n\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( this.filters.length > 0 ) {\n\n\t\t\tthis.source.disconnect( this.filters[ 0 ] );\n\n\t\t\tfor ( let i = 1, l = this.filters.length; i < l; i ++ ) {\n\n\t\t\t\tthis.filters[ i - 1 ].disconnect( this.filters[ i ] );\n\n\t\t\t}\n\n\t\t\tthis.filters[ this.filters.length - 1 ].disconnect( this.getOutput() );\n\n\t\t} else {\n\n\t\t\tthis.source.disconnect( this.getOutput() );\n\n\t\t}\n\n\t\tthis._connected = false;\n\n\t\treturn this;\n\n\t}\n\n\tgetFilters() {\n\n\t\treturn this.filters;\n\n\t}\n\n\tsetFilters( value ) {\n\n\t\tif ( ! value ) value = [];\n\n\t\tif ( this._connected === true ) {\n\n\t\t\tthis.disconnect();\n\t\t\tthis.filters = value.slice();\n\t\t\tthis.connect();\n\n\t\t} else {\n\n\t\t\tthis.filters = value.slice();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetDetune( value ) {\n\n\t\tthis.detune = value;\n\n\t\tif ( this.isPlaying === true && this.source.detune !== undefined ) {\n\n\t\t\tthis.source.detune.setTargetAtTime( this.detune, this.context.currentTime, 0.01 );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetDetune() {\n\n\t\treturn this.detune;\n\n\t}\n\n\tgetFilter() {\n\n\t\treturn this.getFilters()[ 0 ];\n\n\t}\n\n\tsetFilter( filter ) {\n\n\t\treturn this.setFilters( filter ? [ filter ] : [] );\n\n\t}\n\n\tsetPlaybackRate( value ) {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.playbackRate = value;\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\tthis.source.playbackRate.setTargetAtTime( this.playbackRate, this.context.currentTime, 0.01 );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tgetPlaybackRate() {\n\n\t\treturn this.playbackRate;\n\n\t}\n\n\tonEnded() {\n\n\t\tthis.isPlaying = false;\n\n\t}\n\n\tgetLoop() {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn false;\n\n\t\t}\n\n\t\treturn this.loop;\n\n\t}\n\n\tsetLoop( value ) {\n\n\t\tif ( this.hasPlaybackControl === false ) {\n\n\t\t\tconsole.warn( 'THREE.Audio: this Audio has no playback control.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tthis.loop = value;\n\n\t\tif ( this.isPlaying === true ) {\n\n\t\t\tthis.source.loop = this.loop;\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetLoopStart( value ) {\n\n\t\tthis.loopStart = value;\n\n\t\treturn this;\n\n\t}\n\n\tsetLoopEnd( value ) {\n\n\t\tthis.loopEnd = value;\n\n\t\treturn this;\n\n\t}\n\n\tgetVolume() {\n\n\t\treturn this.gain.gain.value;\n\n\t}\n\n\tsetVolume( value ) {\n\n\t\tthis.gain.gain.setTargetAtTime( value, this.context.currentTime, 0.01 );\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _position = /*@__PURE__*/ new Vector3();\nconst _quaternion = /*@__PURE__*/ new Quaternion();\nconst _scale = /*@__PURE__*/ new Vector3();\nconst _orientation = /*@__PURE__*/ new Vector3();\n\nclass PositionalAudio extends Audio {\n\n\tconstructor( listener ) {\n\n\t\tsuper( listener );\n\n\t\tthis.panner = this.context.createPanner();\n\t\tthis.panner.panningModel = 'HRTF';\n\t\tthis.panner.connect( this.gain );\n\n\t}\n\n\tconnect() {\n\n\t\tsuper.connect();\n\n\t\tthis.panner.connect( this.gain );\n\n\t}\n\n\tdisconnect() {\n\n\t\tsuper.disconnect();\n\n\t\tthis.panner.disconnect( this.gain );\n\n\t}\n\n\tgetOutput() {\n\n\t\treturn this.panner;\n\n\t}\n\n\tgetRefDistance() {\n\n\t\treturn this.panner.refDistance;\n\n\t}\n\n\tsetRefDistance( value ) {\n\n\t\tthis.panner.refDistance = value;\n\n\t\treturn this;\n\n\t}\n\n\tgetRolloffFactor() {\n\n\t\treturn this.panner.rolloffFactor;\n\n\t}\n\n\tsetRolloffFactor( value ) {\n\n\t\tthis.panner.rolloffFactor = value;\n\n\t\treturn this;\n\n\t}\n\n\tgetDistanceModel() {\n\n\t\treturn this.panner.distanceModel;\n\n\t}\n\n\tsetDistanceModel( value ) {\n\n\t\tthis.panner.distanceModel = value;\n\n\t\treturn this;\n\n\t}\n\n\tgetMaxDistance() {\n\n\t\treturn this.panner.maxDistance;\n\n\t}\n\n\tsetMaxDistance( value ) {\n\n\t\tthis.panner.maxDistance = value;\n\n\t\treturn this;\n\n\t}\n\n\tsetDirectionalCone( coneInnerAngle, coneOuterAngle, coneOuterGain ) {\n\n\t\tthis.panner.coneInnerAngle = coneInnerAngle;\n\t\tthis.panner.coneOuterAngle = coneOuterAngle;\n\t\tthis.panner.coneOuterGain = coneOuterGain;\n\n\t\treturn this;\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t\tif ( this.hasPlaybackControl === true && this.isPlaying === false ) return;\n\n\t\tthis.matrixWorld.decompose( _position, _quaternion, _scale );\n\n\t\t_orientation.set( 0, 0, 1 ).applyQuaternion( _quaternion );\n\n\t\tconst panner = this.panner;\n\n\t\tif ( panner.positionX ) {\n\n\t\t\t// code path for Chrome and Firefox (see #14393)\n\n\t\t\tconst endTime = this.context.currentTime + this.listener.timeDelta;\n\n\t\t\tpanner.positionX.linearRampToValueAtTime( _position.x, endTime );\n\t\t\tpanner.positionY.linearRampToValueAtTime( _position.y, endTime );\n\t\t\tpanner.positionZ.linearRampToValueAtTime( _position.z, endTime );\n\t\t\tpanner.orientationX.linearRampToValueAtTime( _orientation.x, endTime );\n\t\t\tpanner.orientationY.linearRampToValueAtTime( _orientation.y, endTime );\n\t\t\tpanner.orientationZ.linearRampToValueAtTime( _orientation.z, endTime );\n\n\t\t} else {\n\n\t\t\tpanner.setPosition( _position.x, _position.y, _position.z );\n\t\t\tpanner.setOrientation( _orientation.x, _orientation.y, _orientation.z );\n\n\t\t}\n\n\t}\n\n}\n\nclass AudioAnalyser {\n\n\tconstructor( audio, fftSize = 2048 ) {\n\n\t\tthis.analyser = audio.context.createAnalyser();\n\t\tthis.analyser.fftSize = fftSize;\n\n\t\tthis.data = new Uint8Array( this.analyser.frequencyBinCount );\n\n\t\taudio.getOutput().connect( this.analyser );\n\n\t}\n\n\n\tgetFrequencyData() {\n\n\t\tthis.analyser.getByteFrequencyData( this.data );\n\n\t\treturn this.data;\n\n\t}\n\n\tgetAverageFrequency() {\n\n\t\tlet value = 0;\n\t\tconst data = this.getFrequencyData();\n\n\t\tfor ( let i = 0; i < data.length; i ++ ) {\n\n\t\t\tvalue += data[ i ];\n\n\t\t}\n\n\t\treturn value / data.length;\n\n\t}\n\n}\n\nclass PropertyMixer {\n\n\tconstructor( binding, typeName, valueSize ) {\n\n\t\tthis.binding = binding;\n\t\tthis.valueSize = valueSize;\n\n\t\tlet mixFunction,\n\t\t\tmixFunctionAdditive,\n\t\t\tsetIdentity;\n\n\t\t// buffer layout: [ incoming | accu0 | accu1 | orig | addAccu | (optional work) ]\n\t\t//\n\t\t// interpolators can use .buffer as their .result\n\t\t// the data then goes to 'incoming'\n\t\t//\n\t\t// 'accu0' and 'accu1' are used frame-interleaved for\n\t\t// the cumulative result and are compared to detect\n\t\t// changes\n\t\t//\n\t\t// 'orig' stores the original state of the property\n\t\t//\n\t\t// 'add' is used for additive cumulative results\n\t\t//\n\t\t// 'work' is optional and is only present for quaternion types. It is used\n\t\t// to store intermediate quaternion multiplication results\n\n\t\tswitch ( typeName ) {\n\n\t\t\tcase 'quaternion':\n\t\t\t\tmixFunction = this._slerp;\n\t\t\t\tmixFunctionAdditive = this._slerpAdditive;\n\t\t\t\tsetIdentity = this._setAdditiveIdentityQuaternion;\n\n\t\t\t\tthis.buffer = new Float64Array( valueSize * 6 );\n\t\t\t\tthis._workIndex = 5;\n\t\t\t\tbreak;\n\n\t\t\tcase 'string':\n\t\t\tcase 'bool':\n\t\t\t\tmixFunction = this._select;\n\n\t\t\t\t// Use the regular mix function and for additive on these types,\n\t\t\t\t// additive is not relevant for non-numeric types\n\t\t\t\tmixFunctionAdditive = this._select;\n\n\t\t\t\tsetIdentity = this._setAdditiveIdentityOther;\n\n\t\t\t\tthis.buffer = new Array( valueSize * 5 );\n\t\t\t\tbreak;\n\n\t\t\tdefault:\n\t\t\t\tmixFunction = this._lerp;\n\t\t\t\tmixFunctionAdditive = this._lerpAdditive;\n\t\t\t\tsetIdentity = this._setAdditiveIdentityNumeric;\n\n\t\t\t\tthis.buffer = new Float64Array( valueSize * 5 );\n\n\t\t}\n\n\t\tthis._mixBufferRegion = mixFunction;\n\t\tthis._mixBufferRegionAdditive = mixFunctionAdditive;\n\t\tthis._setIdentity = setIdentity;\n\t\tthis._origIndex = 3;\n\t\tthis._addIndex = 4;\n\n\t\tthis.cumulativeWeight = 0;\n\t\tthis.cumulativeWeightAdditive = 0;\n\n\t\tthis.useCount = 0;\n\t\tthis.referenceCount = 0;\n\n\t}\n\n\t// accumulate data in the 'incoming' region into 'accu'\n\taccumulate( accuIndex, weight ) {\n\n\t\t// note: happily accumulating nothing when weight = 0, the caller knows\n\t\t// the weight and shouldn't have made the call in the first place\n\n\t\tconst buffer = this.buffer,\n\t\t\tstride = this.valueSize,\n\t\t\toffset = accuIndex * stride + stride;\n\n\t\tlet currentWeight = this.cumulativeWeight;\n\n\t\tif ( currentWeight === 0 ) {\n\n\t\t\t// accuN := incoming * weight\n\n\t\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\t\tbuffer[ offset + i ] = buffer[ i ];\n\n\t\t\t}\n\n\t\t\tcurrentWeight = weight;\n\n\t\t} else {\n\n\t\t\t// accuN := accuN + incoming * weight\n\n\t\t\tcurrentWeight += weight;\n\t\t\tconst mix = weight / currentWeight;\n\t\t\tthis._mixBufferRegion( buffer, offset, 0, mix, stride );\n\n\t\t}\n\n\t\tthis.cumulativeWeight = currentWeight;\n\n\t}\n\n\t// accumulate data in the 'incoming' region into 'add'\n\taccumulateAdditive( weight ) {\n\n\t\tconst buffer = this.buffer,\n\t\t\tstride = this.valueSize,\n\t\t\toffset = stride * this._addIndex;\n\n\t\tif ( this.cumulativeWeightAdditive === 0 ) {\n\n\t\t\t// add = identity\n\n\t\t\tthis._setIdentity();\n\n\t\t}\n\n\t\t// add := add + incoming * weight\n\n\t\tthis._mixBufferRegionAdditive( buffer, offset, 0, weight, stride );\n\t\tthis.cumulativeWeightAdditive += weight;\n\n\t}\n\n\t// apply the state of 'accu' to the binding when accus differ\n\tapply( accuIndex ) {\n\n\t\tconst stride = this.valueSize,\n\t\t\tbuffer = this.buffer,\n\t\t\toffset = accuIndex * stride + stride,\n\n\t\t\tweight = this.cumulativeWeight,\n\t\t\tweightAdditive = this.cumulativeWeightAdditive,\n\n\t\t\tbinding = this.binding;\n\n\t\tthis.cumulativeWeight = 0;\n\t\tthis.cumulativeWeightAdditive = 0;\n\n\t\tif ( weight < 1 ) {\n\n\t\t\t// accuN := accuN + original * ( 1 - cumulativeWeight )\n\n\t\t\tconst originalValueOffset = stride * this._origIndex;\n\n\t\t\tthis._mixBufferRegion(\n\t\t\t\tbuffer, offset, originalValueOffset, 1 - weight, stride );\n\n\t\t}\n\n\t\tif ( weightAdditive > 0 ) {\n\n\t\t\t// accuN := accuN + additive accuN\n\n\t\t\tthis._mixBufferRegionAdditive( buffer, offset, this._addIndex * stride, 1, stride );\n\n\t\t}\n\n\t\tfor ( let i = stride, e = stride + stride; i !== e; ++ i ) {\n\n\t\t\tif ( buffer[ i ] !== buffer[ i + stride ] ) {\n\n\t\t\t\t// value has changed -> update scene graph\n\n\t\t\t\tbinding.setValue( buffer, offset );\n\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// remember the state of the bound property and copy it to both accus\n\tsaveOriginalState() {\n\n\t\tconst binding = this.binding;\n\n\t\tconst buffer = this.buffer,\n\t\t\tstride = this.valueSize,\n\n\t\t\toriginalValueOffset = stride * this._origIndex;\n\n\t\tbinding.getValue( buffer, originalValueOffset );\n\n\t\t// accu[0..1] := orig -- initially detect changes against the original\n\t\tfor ( let i = stride, e = originalValueOffset; i !== e; ++ i ) {\n\n\t\t\tbuffer[ i ] = buffer[ originalValueOffset + ( i % stride ) ];\n\n\t\t}\n\n\t\t// Add to identity for additive\n\t\tthis._setIdentity();\n\n\t\tthis.cumulativeWeight = 0;\n\t\tthis.cumulativeWeightAdditive = 0;\n\n\t}\n\n\t// apply the state previously taken via 'saveOriginalState' to the binding\n\trestoreOriginalState() {\n\n\t\tconst originalValueOffset = this.valueSize * 3;\n\t\tthis.binding.setValue( this.buffer, originalValueOffset );\n\n\t}\n\n\t_setAdditiveIdentityNumeric() {\n\n\t\tconst startIndex = this._addIndex * this.valueSize;\n\t\tconst endIndex = startIndex + this.valueSize;\n\n\t\tfor ( let i = startIndex; i < endIndex; i ++ ) {\n\n\t\t\tthis.buffer[ i ] = 0;\n\n\t\t}\n\n\t}\n\n\t_setAdditiveIdentityQuaternion() {\n\n\t\tthis._setAdditiveIdentityNumeric();\n\t\tthis.buffer[ this._addIndex * this.valueSize + 3 ] = 1;\n\n\t}\n\n\t_setAdditiveIdentityOther() {\n\n\t\tconst startIndex = this._origIndex * this.valueSize;\n\t\tconst targetIndex = this._addIndex * this.valueSize;\n\n\t\tfor ( let i = 0; i < this.valueSize; i ++ ) {\n\n\t\t\tthis.buffer[ targetIndex + i ] = this.buffer[ startIndex + i ];\n\n\t\t}\n\n\t}\n\n\n\t// mix functions\n\n\t_select( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\tif ( t >= 0.5 ) {\n\n\t\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\t\tbuffer[ dstOffset + i ] = buffer[ srcOffset + i ];\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_slerp( buffer, dstOffset, srcOffset, t ) {\n\n\t\tQuaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, srcOffset, t );\n\n\t}\n\n\t_slerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\tconst workOffset = this._workIndex * stride;\n\n\t\t// Store result in intermediate buffer offset\n\t\tQuaternion.multiplyQuaternionsFlat( buffer, workOffset, buffer, dstOffset, buffer, srcOffset );\n\n\t\t// Slerp to the intermediate result\n\t\tQuaternion.slerpFlat( buffer, dstOffset, buffer, dstOffset, buffer, workOffset, t );\n\n\t}\n\n\t_lerp( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\tconst s = 1 - t;\n\n\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\tconst j = dstOffset + i;\n\n\t\t\tbuffer[ j ] = buffer[ j ] * s + buffer[ srcOffset + i ] * t;\n\n\t\t}\n\n\t}\n\n\t_lerpAdditive( buffer, dstOffset, srcOffset, t, stride ) {\n\n\t\tfor ( let i = 0; i !== stride; ++ i ) {\n\n\t\t\tconst j = dstOffset + i;\n\n\t\t\tbuffer[ j ] = buffer[ j ] + buffer[ srcOffset + i ] * t;\n\n\t\t}\n\n\t}\n\n}\n\n// Characters [].:/ are reserved for track binding syntax.\nconst _RESERVED_CHARS_RE = '\\\\[\\\\]\\\\.:\\\\/';\nconst _reservedRe = new RegExp( '[' + _RESERVED_CHARS_RE + ']', 'g' );\n\n// Attempts to allow node names from any language. ES5's `\\w` regexp matches\n// only latin characters, and the unicode \\p{L} is not yet supported. So\n// instead, we exclude reserved characters and match everything else.\nconst _wordChar = '[^' + _RESERVED_CHARS_RE + ']';\nconst _wordCharOrDot = '[^' + _RESERVED_CHARS_RE.replace( '\\\\.', '' ) + ']';\n\n// Parent directories, delimited by '/' or ':'. Currently unused, but must\n// be matched to parse the rest of the track name.\nconst _directoryRe = /*@__PURE__*/ /((?:WC+[\\/:])*)/.source.replace( 'WC', _wordChar );\n\n// Target node. May contain word characters (a-zA-Z0-9_) and '.' or '-'.\nconst _nodeRe = /*@__PURE__*/ /(WCOD+)?/.source.replace( 'WCOD', _wordCharOrDot );\n\n// Object on target node, and accessor. May not contain reserved\n// characters. Accessor may contain any character except closing bracket.\nconst _objectRe = /*@__PURE__*/ /(?:\\.(WC+)(?:\\[(.+)\\])?)?/.source.replace( 'WC', _wordChar );\n\n// Property and accessor. May not contain reserved characters. Accessor may\n// contain any non-bracket characters.\nconst _propertyRe = /*@__PURE__*/ /\\.(WC+)(?:\\[(.+)\\])?/.source.replace( 'WC', _wordChar );\n\nconst _trackRe = new RegExp( ''\n\t+ '^'\n\t+ _directoryRe\n\t+ _nodeRe\n\t+ _objectRe\n\t+ _propertyRe\n\t+ '$'\n);\n\nconst _supportedObjectNames = [ 'material', 'materials', 'bones', 'map' ];\n\nclass Composite {\n\n\tconstructor( targetGroup, path, optionalParsedPath ) {\n\n\t\tconst parsedPath = optionalParsedPath || PropertyBinding.parseTrackName( path );\n\n\t\tthis._targetGroup = targetGroup;\n\t\tthis._bindings = targetGroup.subscribe_( path, parsedPath );\n\n\t}\n\n\tgetValue( array, offset ) {\n\n\t\tthis.bind(); // bind all binding\n\n\t\tconst firstValidIndex = this._targetGroup.nCachedObjects_,\n\t\t\tbinding = this._bindings[ firstValidIndex ];\n\n\t\t// and only call .getValue on the first\n\t\tif ( binding !== undefined ) binding.getValue( array, offset );\n\n\t}\n\n\tsetValue( array, offset ) {\n\n\t\tconst bindings = this._bindings;\n\n\t\tfor ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\tbindings[ i ].setValue( array, offset );\n\n\t\t}\n\n\t}\n\n\tbind() {\n\n\t\tconst bindings = this._bindings;\n\n\t\tfor ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\tbindings[ i ].bind();\n\n\t\t}\n\n\t}\n\n\tunbind() {\n\n\t\tconst bindings = this._bindings;\n\n\t\tfor ( let i = this._targetGroup.nCachedObjects_, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\tbindings[ i ].unbind();\n\n\t\t}\n\n\t}\n\n}\n\n// Note: This class uses a State pattern on a per-method basis:\n// 'bind' sets 'this.getValue' / 'setValue' and shadows the\n// prototype version of these methods with one that represents\n// the bound state. When the property is not found, the methods\n// become no-ops.\nclass PropertyBinding {\n\n\tconstructor( rootNode, path, parsedPath ) {\n\n\t\tthis.path = path;\n\t\tthis.parsedPath = parsedPath || PropertyBinding.parseTrackName( path );\n\n\t\tthis.node = PropertyBinding.findNode( rootNode, this.parsedPath.nodeName );\n\n\t\tthis.rootNode = rootNode;\n\n\t\t// initial state of these methods that calls 'bind'\n\t\tthis.getValue = this._getValue_unbound;\n\t\tthis.setValue = this._setValue_unbound;\n\n\t}\n\n\n\tstatic create( root, path, parsedPath ) {\n\n\t\tif ( ! ( root && root.isAnimationObjectGroup ) ) {\n\n\t\t\treturn new PropertyBinding( root, path, parsedPath );\n\n\t\t} else {\n\n\t\t\treturn new PropertyBinding.Composite( root, path, parsedPath );\n\n\t\t}\n\n\t}\n\n\t/**\n\t * Replaces spaces with underscores and removes unsupported characters from\n\t * node names, to ensure compatibility with parseTrackName().\n\t *\n\t * @param {string} name Node name to be sanitized.\n\t * @return {string}\n\t */\n\tstatic sanitizeNodeName( name ) {\n\n\t\treturn name.replace( /\\s/g, '_' ).replace( _reservedRe, '' );\n\n\t}\n\n\tstatic parseTrackName( trackName ) {\n\n\t\tconst matches = _trackRe.exec( trackName );\n\n\t\tif ( matches === null ) {\n\n\t\t\tthrow new Error( 'PropertyBinding: Cannot parse trackName: ' + trackName );\n\n\t\t}\n\n\t\tconst results = {\n\t\t\t// directoryName: matches[ 1 ], // (tschw) currently unused\n\t\t\tnodeName: matches[ 2 ],\n\t\t\tobjectName: matches[ 3 ],\n\t\t\tobjectIndex: matches[ 4 ],\n\t\t\tpropertyName: matches[ 5 ], // required\n\t\t\tpropertyIndex: matches[ 6 ]\n\t\t};\n\n\t\tconst lastDot = results.nodeName && results.nodeName.lastIndexOf( '.' );\n\n\t\tif ( lastDot !== undefined && lastDot !== - 1 ) {\n\n\t\t\tconst objectName = results.nodeName.substring( lastDot + 1 );\n\n\t\t\t// Object names must be checked against an allowlist. Otherwise, there\n\t\t\t// is no way to parse 'foo.bar.baz': 'baz' must be a property, but\n\t\t\t// 'bar' could be the objectName, or part of a nodeName (which can\n\t\t\t// include '.' characters).\n\t\t\tif ( _supportedObjectNames.indexOf( objectName ) !== - 1 ) {\n\n\t\t\t\tresults.nodeName = results.nodeName.substring( 0, lastDot );\n\t\t\t\tresults.objectName = objectName;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( results.propertyName === null || results.propertyName.length === 0 ) {\n\n\t\t\tthrow new Error( 'PropertyBinding: can not parse propertyName from trackName: ' + trackName );\n\n\t\t}\n\n\t\treturn results;\n\n\t}\n\n\tstatic findNode( root, nodeName ) {\n\n\t\tif ( nodeName === undefined || nodeName === '' || nodeName === '.' || nodeName === - 1 || nodeName === root.name || nodeName === root.uuid ) {\n\n\t\t\treturn root;\n\n\t\t}\n\n\t\t// search into skeleton bones.\n\t\tif ( root.skeleton ) {\n\n\t\t\tconst bone = root.skeleton.getBoneByName( nodeName );\n\n\t\t\tif ( bone !== undefined ) {\n\n\t\t\t\treturn bone;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// search into node subtree.\n\t\tif ( root.children ) {\n\n\t\t\tconst searchNodeSubtree = function ( children ) {\n\n\t\t\t\tfor ( let i = 0; i < children.length; i ++ ) {\n\n\t\t\t\t\tconst childNode = children[ i ];\n\n\t\t\t\t\tif ( childNode.name === nodeName || childNode.uuid === nodeName ) {\n\n\t\t\t\t\t\treturn childNode;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tconst result = searchNodeSubtree( childNode.children );\n\n\t\t\t\t\tif ( result ) return result;\n\n\t\t\t\t}\n\n\t\t\t\treturn null;\n\n\t\t\t};\n\n\t\t\tconst subTreeNode = searchNodeSubtree( root.children );\n\n\t\t\tif ( subTreeNode ) {\n\n\t\t\t\treturn subTreeNode;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n\t// these are used to \"bind\" a nonexistent property\n\t_getValue_unavailable() {}\n\t_setValue_unavailable() {}\n\n\t// Getters\n\n\t_getValue_direct( buffer, offset ) {\n\n\t\tbuffer[ offset ] = this.targetObject[ this.propertyName ];\n\n\t}\n\n\t_getValue_array( buffer, offset ) {\n\n\t\tconst source = this.resolvedProperty;\n\n\t\tfor ( let i = 0, n = source.length; i !== n; ++ i ) {\n\n\t\t\tbuffer[ offset ++ ] = source[ i ];\n\n\t\t}\n\n\t}\n\n\t_getValue_arrayElement( buffer, offset ) {\n\n\t\tbuffer[ offset ] = this.resolvedProperty[ this.propertyIndex ];\n\n\t}\n\n\t_getValue_toArray( buffer, offset ) {\n\n\t\tthis.resolvedProperty.toArray( buffer, offset );\n\n\t}\n\n\t// Direct\n\n\t_setValue_direct( buffer, offset ) {\n\n\t\tthis.targetObject[ this.propertyName ] = buffer[ offset ];\n\n\t}\n\n\t_setValue_direct_setNeedsUpdate( buffer, offset ) {\n\n\t\tthis.targetObject[ this.propertyName ] = buffer[ offset ];\n\t\tthis.targetObject.needsUpdate = true;\n\n\t}\n\n\t_setValue_direct_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\tthis.targetObject[ this.propertyName ] = buffer[ offset ];\n\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t}\n\n\t// EntireArray\n\n\t_setValue_array( buffer, offset ) {\n\n\t\tconst dest = this.resolvedProperty;\n\n\t\tfor ( let i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t}\n\n\t}\n\n\t_setValue_array_setNeedsUpdate( buffer, offset ) {\n\n\t\tconst dest = this.resolvedProperty;\n\n\t\tfor ( let i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t}\n\n\t\tthis.targetObject.needsUpdate = true;\n\n\t}\n\n\t_setValue_array_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\tconst dest = this.resolvedProperty;\n\n\t\tfor ( let i = 0, n = dest.length; i !== n; ++ i ) {\n\n\t\t\tdest[ i ] = buffer[ offset ++ ];\n\n\t\t}\n\n\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t}\n\n\t// ArrayElement\n\n\t_setValue_arrayElement( buffer, offset ) {\n\n\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\n\t}\n\n\t_setValue_arrayElement_setNeedsUpdate( buffer, offset ) {\n\n\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\t\tthis.targetObject.needsUpdate = true;\n\n\t}\n\n\t_setValue_arrayElement_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\tthis.resolvedProperty[ this.propertyIndex ] = buffer[ offset ];\n\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t}\n\n\t// HasToFromArray\n\n\t_setValue_fromArray( buffer, offset ) {\n\n\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\n\t}\n\n\t_setValue_fromArray_setNeedsUpdate( buffer, offset ) {\n\n\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\t\tthis.targetObject.needsUpdate = true;\n\n\t}\n\n\t_setValue_fromArray_setMatrixWorldNeedsUpdate( buffer, offset ) {\n\n\t\tthis.resolvedProperty.fromArray( buffer, offset );\n\t\tthis.targetObject.matrixWorldNeedsUpdate = true;\n\n\t}\n\n\t_getValue_unbound( targetArray, offset ) {\n\n\t\tthis.bind();\n\t\tthis.getValue( targetArray, offset );\n\n\t}\n\n\t_setValue_unbound( sourceArray, offset ) {\n\n\t\tthis.bind();\n\t\tthis.setValue( sourceArray, offset );\n\n\t}\n\n\t// create getter / setter pair for a property in the scene graph\n\tbind() {\n\n\t\tlet targetObject = this.node;\n\t\tconst parsedPath = this.parsedPath;\n\n\t\tconst objectName = parsedPath.objectName;\n\t\tconst propertyName = parsedPath.propertyName;\n\t\tlet propertyIndex = parsedPath.propertyIndex;\n\n\t\tif ( ! targetObject ) {\n\n\t\t\ttargetObject = PropertyBinding.findNode( this.rootNode, parsedPath.nodeName );\n\n\t\t\tthis.node = targetObject;\n\n\t\t}\n\n\t\t// set fail state so we can just 'return' on error\n\t\tthis.getValue = this._getValue_unavailable;\n\t\tthis.setValue = this._setValue_unavailable;\n\n\t\t// ensure there is a value node\n\t\tif ( ! targetObject ) {\n\n\t\t\tconsole.warn( 'THREE.PropertyBinding: No target node found for track: ' + this.path + '.' );\n\t\t\treturn;\n\n\t\t}\n\n\t\tif ( objectName ) {\n\n\t\t\tlet objectIndex = parsedPath.objectIndex;\n\n\t\t\t// special cases were we need to reach deeper into the hierarchy to get the face materials....\n\t\t\tswitch ( objectName ) {\n\n\t\t\t\tcase 'materials':\n\n\t\t\t\t\tif ( ! targetObject.material ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! targetObject.material.materials ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to material.materials as node.material does not have a materials array.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttargetObject = targetObject.material.materials;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'bones':\n\n\t\t\t\t\tif ( ! targetObject.skeleton ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to bones as node does not have a skeleton.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// potential future optimization: skip this if propertyIndex is already an integer\n\t\t\t\t\t// and convert the integer string to a true integer.\n\n\t\t\t\t\ttargetObject = targetObject.skeleton.bones;\n\n\t\t\t\t\t// support resolving morphTarget names into indices.\n\t\t\t\t\tfor ( let i = 0; i < targetObject.length; i ++ ) {\n\n\t\t\t\t\t\tif ( targetObject[ i ].name === objectIndex ) {\n\n\t\t\t\t\t\t\tobjectIndex = i;\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 'map':\n\n\t\t\t\t\tif ( 'map' in targetObject ) {\n\n\t\t\t\t\t\ttargetObject = targetObject.map;\n\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! targetObject.material ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to material as node does not have a material.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ! targetObject.material.map ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to material.map as node.material does not have a map.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttargetObject = targetObject.material.map;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tif ( targetObject[ objectName ] === undefined ) {\n\n\t\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to objectName of node undefined.', this );\n\t\t\t\t\t\treturn;\n\n\t\t\t\t\t}\n\n\t\t\t\t\ttargetObject = targetObject[ objectName ];\n\n\t\t\t}\n\n\n\t\t\tif ( objectIndex !== undefined ) {\n\n\t\t\t\tif ( targetObject[ objectIndex ] === undefined ) {\n\n\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Trying to bind to objectIndex of objectName, but is undefined.', this, targetObject );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\ttargetObject = targetObject[ objectIndex ];\n\n\t\t\t}\n\n\t\t}\n\n\t\t// resolve property\n\t\tconst nodeProperty = targetObject[ propertyName ];\n\n\t\tif ( nodeProperty === undefined ) {\n\n\t\t\tconst nodeName = parsedPath.nodeName;\n\n\t\t\tconsole.error( 'THREE.PropertyBinding: Trying to update property for track: ' + nodeName +\n\t\t\t\t'.' + propertyName + ' but it wasn\\'t found.', targetObject );\n\t\t\treturn;\n\n\t\t}\n\n\t\t// determine versioning scheme\n\t\tlet versioning = this.Versioning.None;\n\n\t\tthis.targetObject = targetObject;\n\n\t\tif ( targetObject.needsUpdate !== undefined ) { // material\n\n\t\t\tversioning = this.Versioning.NeedsUpdate;\n\n\t\t} else if ( targetObject.matrixWorldNeedsUpdate !== undefined ) { // node transform\n\n\t\t\tversioning = this.Versioning.MatrixWorldNeedsUpdate;\n\n\t\t}\n\n\t\t// determine how the property gets bound\n\t\tlet bindingType = this.BindingType.Direct;\n\n\t\tif ( propertyIndex !== undefined ) {\n\n\t\t\t// access a sub element of the property array (only primitives are supported right now)\n\n\t\t\tif ( propertyName === 'morphTargetInfluences' ) {\n\n\t\t\t\t// potential optimization, skip this if propertyIndex is already an integer, and convert the integer string to a true integer.\n\n\t\t\t\t// support resolving morphTarget names into indices.\n\t\t\t\tif ( ! targetObject.geometry ) {\n\n\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.', this );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tif ( ! targetObject.geometry.morphAttributes ) {\n\n\t\t\t\t\tconsole.error( 'THREE.PropertyBinding: Can not bind to morphTargetInfluences because node does not have a geometry.morphAttributes.', this );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t\tif ( targetObject.morphTargetDictionary[ propertyIndex ] !== undefined ) {\n\n\t\t\t\t\tpropertyIndex = targetObject.morphTargetDictionary[ propertyIndex ];\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tbindingType = this.BindingType.ArrayElement;\n\n\t\t\tthis.resolvedProperty = nodeProperty;\n\t\t\tthis.propertyIndex = propertyIndex;\n\n\t\t} else if ( nodeProperty.fromArray !== undefined && nodeProperty.toArray !== undefined ) {\n\n\t\t\t// must use copy for Object3D.Euler/Quaternion\n\n\t\t\tbindingType = this.BindingType.HasFromToArray;\n\n\t\t\tthis.resolvedProperty = nodeProperty;\n\n\t\t} else if ( Array.isArray( nodeProperty ) ) {\n\n\t\t\tbindingType = this.BindingType.EntireArray;\n\n\t\t\tthis.resolvedProperty = nodeProperty;\n\n\t\t} else {\n\n\t\t\tthis.propertyName = propertyName;\n\n\t\t}\n\n\t\t// select getter / setter\n\t\tthis.getValue = this.GetterByBindingType[ bindingType ];\n\t\tthis.setValue = this.SetterByBindingTypeAndVersioning[ bindingType ][ versioning ];\n\n\t}\n\n\tunbind() {\n\n\t\tthis.node = null;\n\n\t\t// back to the prototype version of getValue / setValue\n\t\t// note: avoiding to mutate the shape of 'this' via 'delete'\n\t\tthis.getValue = this._getValue_unbound;\n\t\tthis.setValue = this._setValue_unbound;\n\n\t}\n\n}\n\nPropertyBinding.Composite = Composite;\n\nPropertyBinding.prototype.BindingType = {\n\tDirect: 0,\n\tEntireArray: 1,\n\tArrayElement: 2,\n\tHasFromToArray: 3\n};\n\nPropertyBinding.prototype.Versioning = {\n\tNone: 0,\n\tNeedsUpdate: 1,\n\tMatrixWorldNeedsUpdate: 2\n};\n\nPropertyBinding.prototype.GetterByBindingType = [\n\n\tPropertyBinding.prototype._getValue_direct,\n\tPropertyBinding.prototype._getValue_array,\n\tPropertyBinding.prototype._getValue_arrayElement,\n\tPropertyBinding.prototype._getValue_toArray,\n\n];\n\nPropertyBinding.prototype.SetterByBindingTypeAndVersioning = [\n\n\t[\n\t\t// Direct\n\t\tPropertyBinding.prototype._setValue_direct,\n\t\tPropertyBinding.prototype._setValue_direct_setNeedsUpdate,\n\t\tPropertyBinding.prototype._setValue_direct_setMatrixWorldNeedsUpdate,\n\n\t], [\n\n\t\t// EntireArray\n\n\t\tPropertyBinding.prototype._setValue_array,\n\t\tPropertyBinding.prototype._setValue_array_setNeedsUpdate,\n\t\tPropertyBinding.prototype._setValue_array_setMatrixWorldNeedsUpdate,\n\n\t], [\n\n\t\t// ArrayElement\n\t\tPropertyBinding.prototype._setValue_arrayElement,\n\t\tPropertyBinding.prototype._setValue_arrayElement_setNeedsUpdate,\n\t\tPropertyBinding.prototype._setValue_arrayElement_setMatrixWorldNeedsUpdate,\n\n\t], [\n\n\t\t// HasToFromArray\n\t\tPropertyBinding.prototype._setValue_fromArray,\n\t\tPropertyBinding.prototype._setValue_fromArray_setNeedsUpdate,\n\t\tPropertyBinding.prototype._setValue_fromArray_setMatrixWorldNeedsUpdate,\n\n\t]\n\n];\n\n/**\n *\n * A group of objects that receives a shared animation state.\n *\n * Usage:\n *\n * - Add objects you would otherwise pass as 'root' to the\n * constructor or the .clipAction method of AnimationMixer.\n *\n * - Instead pass this object as 'root'.\n *\n * - You can also add and remove objects later when the mixer\n * is running.\n *\n * Note:\n *\n * Objects of this class appear as one object to the mixer,\n * so cache control of the individual objects must be done\n * on the group.\n *\n * Limitation:\n *\n * - The animated properties must be compatible among the\n * all objects in the group.\n *\n * - A single property can either be controlled through a\n * target group or directly, but not both.\n */\n\nclass AnimationObjectGroup {\n\n\tconstructor() {\n\n\t\tthis.isAnimationObjectGroup = true;\n\n\t\tthis.uuid = generateUUID();\n\n\t\t// cached objects followed by the active ones\n\t\tthis._objects = Array.prototype.slice.call( arguments );\n\n\t\tthis.nCachedObjects_ = 0; // threshold\n\t\t// note: read by PropertyBinding.Composite\n\n\t\tconst indices = {};\n\t\tthis._indicesByUUID = indices; // for bookkeeping\n\n\t\tfor ( let i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tindices[ arguments[ i ].uuid ] = i;\n\n\t\t}\n\n\t\tthis._paths = []; // inside: string\n\t\tthis._parsedPaths = []; // inside: { we don't care, here }\n\t\tthis._bindings = []; // inside: Array< PropertyBinding >\n\t\tthis._bindingsIndicesByPath = {}; // inside: indices in these arrays\n\n\t\tconst scope = this;\n\n\t\tthis.stats = {\n\n\t\t\tobjects: {\n\t\t\t\tget total() {\n\n\t\t\t\t\treturn scope._objects.length;\n\n\t\t\t\t},\n\t\t\t\tget inUse() {\n\n\t\t\t\t\treturn this.total - scope.nCachedObjects_;\n\n\t\t\t\t}\n\t\t\t},\n\t\t\tget bindingsPerObject() {\n\n\t\t\t\treturn scope._bindings.length;\n\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\tadd() {\n\n\t\tconst objects = this._objects,\n\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\tpaths = this._paths,\n\t\t\tparsedPaths = this._parsedPaths,\n\t\t\tbindings = this._bindings,\n\t\t\tnBindings = bindings.length;\n\n\t\tlet knownObject = undefined,\n\t\t\tnObjects = objects.length,\n\t\t\tnCachedObjects = this.nCachedObjects_;\n\n\t\tfor ( let i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tconst object = arguments[ i ],\n\t\t\t\tuuid = object.uuid;\n\t\t\tlet index = indicesByUUID[ uuid ];\n\n\t\t\tif ( index === undefined ) {\n\n\t\t\t\t// unknown object -> add it to the ACTIVE region\n\n\t\t\t\tindex = nObjects ++;\n\t\t\t\tindicesByUUID[ uuid ] = index;\n\t\t\t\tobjects.push( object );\n\n\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\tfor ( let j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\tbindings[ j ].push( new PropertyBinding( object, paths[ j ], parsedPaths[ j ] ) );\n\n\t\t\t\t}\n\n\t\t\t} else if ( index < nCachedObjects ) {\n\n\t\t\t\tknownObject = objects[ index ];\n\n\t\t\t\t// move existing object to the ACTIVE region\n\n\t\t\t\tconst firstActiveIndex = -- nCachedObjects,\n\t\t\t\t\tlastCachedObject = objects[ firstActiveIndex ];\n\n\t\t\t\tindicesByUUID[ lastCachedObject.uuid ] = index;\n\t\t\t\tobjects[ index ] = lastCachedObject;\n\n\t\t\t\tindicesByUUID[ uuid ] = firstActiveIndex;\n\t\t\t\tobjects[ firstActiveIndex ] = object;\n\n\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\tfor ( let j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\tconst bindingsForPath = bindings[ j ],\n\t\t\t\t\t\tlastCached = bindingsForPath[ firstActiveIndex ];\n\n\t\t\t\t\tlet binding = bindingsForPath[ index ];\n\n\t\t\t\t\tbindingsForPath[ index ] = lastCached;\n\n\t\t\t\t\tif ( binding === undefined ) {\n\n\t\t\t\t\t\t// since we do not bother to create new bindings\n\t\t\t\t\t\t// for objects that are cached, the binding may\n\t\t\t\t\t\t// or may not exist\n\n\t\t\t\t\t\tbinding = new PropertyBinding( object, paths[ j ], parsedPaths[ j ] );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbindingsForPath[ firstActiveIndex ] = binding;\n\n\t\t\t\t}\n\n\t\t\t} else if ( objects[ index ] !== knownObject ) {\n\n\t\t\t\tconsole.error( 'THREE.AnimationObjectGroup: Different objects with the same UUID ' +\n\t\t\t\t\t'detected. Clean the caches or recreate your infrastructure when reloading scenes.' );\n\n\t\t\t} // else the object is already where we want it to be\n\n\t\t} // for arguments\n\n\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t}\n\n\tremove() {\n\n\t\tconst objects = this._objects,\n\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\tbindings = this._bindings,\n\t\t\tnBindings = bindings.length;\n\n\t\tlet nCachedObjects = this.nCachedObjects_;\n\n\t\tfor ( let i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tconst object = arguments[ i ],\n\t\t\t\tuuid = object.uuid,\n\t\t\t\tindex = indicesByUUID[ uuid ];\n\n\t\t\tif ( index !== undefined && index >= nCachedObjects ) {\n\n\t\t\t\t// move existing object into the CACHED region\n\n\t\t\t\tconst lastCachedIndex = nCachedObjects ++,\n\t\t\t\t\tfirstActiveObject = objects[ lastCachedIndex ];\n\n\t\t\t\tindicesByUUID[ firstActiveObject.uuid ] = index;\n\t\t\t\tobjects[ index ] = firstActiveObject;\n\n\t\t\t\tindicesByUUID[ uuid ] = lastCachedIndex;\n\t\t\t\tobjects[ lastCachedIndex ] = object;\n\n\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\tfor ( let j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\tconst bindingsForPath = bindings[ j ],\n\t\t\t\t\t\tfirstActive = bindingsForPath[ lastCachedIndex ],\n\t\t\t\t\t\tbinding = bindingsForPath[ index ];\n\n\t\t\t\t\tbindingsForPath[ index ] = firstActive;\n\t\t\t\t\tbindingsForPath[ lastCachedIndex ] = binding;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t} // for arguments\n\n\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t}\n\n\t// remove & forget\n\tuncache() {\n\n\t\tconst objects = this._objects,\n\t\t\tindicesByUUID = this._indicesByUUID,\n\t\t\tbindings = this._bindings,\n\t\t\tnBindings = bindings.length;\n\n\t\tlet nCachedObjects = this.nCachedObjects_,\n\t\t\tnObjects = objects.length;\n\n\t\tfor ( let i = 0, n = arguments.length; i !== n; ++ i ) {\n\n\t\t\tconst object = arguments[ i ],\n\t\t\t\tuuid = object.uuid,\n\t\t\t\tindex = indicesByUUID[ uuid ];\n\n\t\t\tif ( index !== undefined ) {\n\n\t\t\t\tdelete indicesByUUID[ uuid ];\n\n\t\t\t\tif ( index < nCachedObjects ) {\n\n\t\t\t\t\t// object is cached, shrink the CACHED region\n\n\t\t\t\t\tconst firstActiveIndex = -- nCachedObjects,\n\t\t\t\t\t\tlastCachedObject = objects[ firstActiveIndex ],\n\t\t\t\t\t\tlastIndex = -- nObjects,\n\t\t\t\t\t\tlastObject = objects[ lastIndex ];\n\n\t\t\t\t\t// last cached object takes this object's place\n\t\t\t\t\tindicesByUUID[ lastCachedObject.uuid ] = index;\n\t\t\t\t\tobjects[ index ] = lastCachedObject;\n\n\t\t\t\t\t// last object goes to the activated slot and pop\n\t\t\t\t\tindicesByUUID[ lastObject.uuid ] = firstActiveIndex;\n\t\t\t\t\tobjects[ firstActiveIndex ] = lastObject;\n\t\t\t\t\tobjects.pop();\n\n\t\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\t\tfor ( let j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\t\tconst bindingsForPath = bindings[ j ],\n\t\t\t\t\t\t\tlastCached = bindingsForPath[ firstActiveIndex ],\n\t\t\t\t\t\t\tlast = bindingsForPath[ lastIndex ];\n\n\t\t\t\t\t\tbindingsForPath[ index ] = lastCached;\n\t\t\t\t\t\tbindingsForPath[ firstActiveIndex ] = last;\n\t\t\t\t\t\tbindingsForPath.pop();\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// object is active, just swap with the last and pop\n\n\t\t\t\t\tconst lastIndex = -- nObjects,\n\t\t\t\t\t\tlastObject = objects[ lastIndex ];\n\n\t\t\t\t\tif ( lastIndex > 0 ) {\n\n\t\t\t\t\t\tindicesByUUID[ lastObject.uuid ] = index;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tobjects[ index ] = lastObject;\n\t\t\t\t\tobjects.pop();\n\n\t\t\t\t\t// accounting is done, now do the same for all bindings\n\n\t\t\t\t\tfor ( let j = 0, m = nBindings; j !== m; ++ j ) {\n\n\t\t\t\t\t\tconst bindingsForPath = bindings[ j ];\n\n\t\t\t\t\t\tbindingsForPath[ index ] = bindingsForPath[ lastIndex ];\n\t\t\t\t\t\tbindingsForPath.pop();\n\n\t\t\t\t\t}\n\n\t\t\t\t} // cached or active\n\n\t\t\t} // if object is known\n\n\t\t} // for arguments\n\n\t\tthis.nCachedObjects_ = nCachedObjects;\n\n\t}\n\n\t// Internal interface used by befriended PropertyBinding.Composite:\n\n\tsubscribe_( path, parsedPath ) {\n\n\t\t// returns an array of bindings for the given path that is changed\n\t\t// according to the contained objects in the group\n\n\t\tconst indicesByPath = this._bindingsIndicesByPath;\n\t\tlet index = indicesByPath[ path ];\n\t\tconst bindings = this._bindings;\n\n\t\tif ( index !== undefined ) return bindings[ index ];\n\n\t\tconst paths = this._paths,\n\t\t\tparsedPaths = this._parsedPaths,\n\t\t\tobjects = this._objects,\n\t\t\tnObjects = objects.length,\n\t\t\tnCachedObjects = this.nCachedObjects_,\n\t\t\tbindingsForPath = new Array( nObjects );\n\n\t\tindex = bindings.length;\n\n\t\tindicesByPath[ path ] = index;\n\n\t\tpaths.push( path );\n\t\tparsedPaths.push( parsedPath );\n\t\tbindings.push( bindingsForPath );\n\n\t\tfor ( let i = nCachedObjects, n = objects.length; i !== n; ++ i ) {\n\n\t\t\tconst object = objects[ i ];\n\t\t\tbindingsForPath[ i ] = new PropertyBinding( object, path, parsedPath );\n\n\t\t}\n\n\t\treturn bindingsForPath;\n\n\t}\n\n\tunsubscribe_( path ) {\n\n\t\t// tells the group to forget about a property path and no longer\n\t\t// update the array previously obtained with 'subscribe_'\n\n\t\tconst indicesByPath = this._bindingsIndicesByPath,\n\t\t\tindex = indicesByPath[ path ];\n\n\t\tif ( index !== undefined ) {\n\n\t\t\tconst paths = this._paths,\n\t\t\t\tparsedPaths = this._parsedPaths,\n\t\t\t\tbindings = this._bindings,\n\t\t\t\tlastBindingsIndex = bindings.length - 1,\n\t\t\t\tlastBindings = bindings[ lastBindingsIndex ],\n\t\t\t\tlastBindingsPath = path[ lastBindingsIndex ];\n\n\t\t\tindicesByPath[ lastBindingsPath ] = index;\n\n\t\t\tbindings[ index ] = lastBindings;\n\t\t\tbindings.pop();\n\n\t\t\tparsedPaths[ index ] = parsedPaths[ lastBindingsIndex ];\n\t\t\tparsedPaths.pop();\n\n\t\t\tpaths[ index ] = paths[ lastBindingsIndex ];\n\t\t\tpaths.pop();\n\n\t\t}\n\n\t}\n\n}\n\nclass AnimationAction {\n\n\tconstructor( mixer, clip, localRoot = null, blendMode = clip.blendMode ) {\n\n\t\tthis._mixer = mixer;\n\t\tthis._clip = clip;\n\t\tthis._localRoot = localRoot;\n\t\tthis.blendMode = blendMode;\n\n\t\tconst tracks = clip.tracks,\n\t\t\tnTracks = tracks.length,\n\t\t\tinterpolants = new Array( nTracks );\n\n\t\tconst interpolantSettings = {\n\t\t\tendingStart: ZeroCurvatureEnding,\n\t\t\tendingEnd: ZeroCurvatureEnding\n\t\t};\n\n\t\tfor ( let i = 0; i !== nTracks; ++ i ) {\n\n\t\t\tconst interpolant = tracks[ i ].createInterpolant( null );\n\t\t\tinterpolants[ i ] = interpolant;\n\t\t\tinterpolant.settings = interpolantSettings;\n\n\t\t}\n\n\t\tthis._interpolantSettings = interpolantSettings;\n\n\t\tthis._interpolants = interpolants; // bound by the mixer\n\n\t\t// inside: PropertyMixer (managed by the mixer)\n\t\tthis._propertyBindings = new Array( nTracks );\n\n\t\tthis._cacheIndex = null; // for the memory manager\n\t\tthis._byClipCacheIndex = null; // for the memory manager\n\n\t\tthis._timeScaleInterpolant = null;\n\t\tthis._weightInterpolant = null;\n\n\t\tthis.loop = LoopRepeat;\n\t\tthis._loopCount = - 1;\n\n\t\t// global mixer time when the action is to be started\n\t\t// it's set back to 'null' upon start of the action\n\t\tthis._startTime = null;\n\n\t\t// scaled local time of the action\n\t\t// gets clamped or wrapped to 0..clip.duration according to loop\n\t\tthis.time = 0;\n\n\t\tthis.timeScale = 1;\n\t\tthis._effectiveTimeScale = 1;\n\n\t\tthis.weight = 1;\n\t\tthis._effectiveWeight = 1;\n\n\t\tthis.repetitions = Infinity; // no. of repetitions when looping\n\n\t\tthis.paused = false; // true -> zero effective time scale\n\t\tthis.enabled = true; // false -> zero effective weight\n\n\t\tthis.clampWhenFinished = false;// keep feeding the last frame?\n\n\t\tthis.zeroSlopeAtStart = true;// for smooth interpolation w/o separate\n\t\tthis.zeroSlopeAtEnd = true;// clips for start, loop and end\n\n\t}\n\n\t// State & Scheduling\n\n\tplay() {\n\n\t\tthis._mixer._activateAction( this );\n\n\t\treturn this;\n\n\t}\n\n\tstop() {\n\n\t\tthis._mixer._deactivateAction( this );\n\n\t\treturn this.reset();\n\n\t}\n\n\treset() {\n\n\t\tthis.paused = false;\n\t\tthis.enabled = true;\n\n\t\tthis.time = 0; // restart clip\n\t\tthis._loopCount = - 1;// forget previous loops\n\t\tthis._startTime = null;// forget scheduling\n\n\t\treturn this.stopFading().stopWarping();\n\n\t}\n\n\tisRunning() {\n\n\t\treturn this.enabled && ! this.paused && this.timeScale !== 0 &&\n\t\t\tthis._startTime === null && this._mixer._isActiveAction( this );\n\n\t}\n\n\t// return true when play has been called\n\tisScheduled() {\n\n\t\treturn this._mixer._isActiveAction( this );\n\n\t}\n\n\tstartAt( time ) {\n\n\t\tthis._startTime = time;\n\n\t\treturn this;\n\n\t}\n\n\tsetLoop( mode, repetitions ) {\n\n\t\tthis.loop = mode;\n\t\tthis.repetitions = repetitions;\n\n\t\treturn this;\n\n\t}\n\n\t// Weight\n\n\t// set the weight stopping any scheduled fading\n\t// although .enabled = false yields an effective weight of zero, this\n\t// method does *not* change .enabled, because it would be confusing\n\tsetEffectiveWeight( weight ) {\n\n\t\tthis.weight = weight;\n\n\t\t// note: same logic as when updated at runtime\n\t\tthis._effectiveWeight = this.enabled ? weight : 0;\n\n\t\treturn this.stopFading();\n\n\t}\n\n\t// return the weight considering fading and .enabled\n\tgetEffectiveWeight() {\n\n\t\treturn this._effectiveWeight;\n\n\t}\n\n\tfadeIn( duration ) {\n\n\t\treturn this._scheduleFading( duration, 0, 1 );\n\n\t}\n\n\tfadeOut( duration ) {\n\n\t\treturn this._scheduleFading( duration, 1, 0 );\n\n\t}\n\n\tcrossFadeFrom( fadeOutAction, duration, warp ) {\n\n\t\tfadeOutAction.fadeOut( duration );\n\t\tthis.fadeIn( duration );\n\n\t\tif ( warp ) {\n\n\t\t\tconst fadeInDuration = this._clip.duration,\n\t\t\t\tfadeOutDuration = fadeOutAction._clip.duration,\n\n\t\t\t\tstartEndRatio = fadeOutDuration / fadeInDuration,\n\t\t\t\tendStartRatio = fadeInDuration / fadeOutDuration;\n\n\t\t\tfadeOutAction.warp( 1.0, startEndRatio, duration );\n\t\t\tthis.warp( endStartRatio, 1.0, duration );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tcrossFadeTo( fadeInAction, duration, warp ) {\n\n\t\treturn fadeInAction.crossFadeFrom( this, duration, warp );\n\n\t}\n\n\tstopFading() {\n\n\t\tconst weightInterpolant = this._weightInterpolant;\n\n\t\tif ( weightInterpolant !== null ) {\n\n\t\t\tthis._weightInterpolant = null;\n\t\t\tthis._mixer._takeBackControlInterpolant( weightInterpolant );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// Time Scale Control\n\n\t// set the time scale stopping any scheduled warping\n\t// although .paused = true yields an effective time scale of zero, this\n\t// method does *not* change .paused, because it would be confusing\n\tsetEffectiveTimeScale( timeScale ) {\n\n\t\tthis.timeScale = timeScale;\n\t\tthis._effectiveTimeScale = this.paused ? 0 : timeScale;\n\n\t\treturn this.stopWarping();\n\n\t}\n\n\t// return the time scale considering warping and .paused\n\tgetEffectiveTimeScale() {\n\n\t\treturn this._effectiveTimeScale;\n\n\t}\n\n\tsetDuration( duration ) {\n\n\t\tthis.timeScale = this._clip.duration / duration;\n\n\t\treturn this.stopWarping();\n\n\t}\n\n\tsyncWith( action ) {\n\n\t\tthis.time = action.time;\n\t\tthis.timeScale = action.timeScale;\n\n\t\treturn this.stopWarping();\n\n\t}\n\n\thalt( duration ) {\n\n\t\treturn this.warp( this._effectiveTimeScale, 0, duration );\n\n\t}\n\n\twarp( startTimeScale, endTimeScale, duration ) {\n\n\t\tconst mixer = this._mixer,\n\t\t\tnow = mixer.time,\n\t\t\ttimeScale = this.timeScale;\n\n\t\tlet interpolant = this._timeScaleInterpolant;\n\n\t\tif ( interpolant === null ) {\n\n\t\t\tinterpolant = mixer._lendControlInterpolant();\n\t\t\tthis._timeScaleInterpolant = interpolant;\n\n\t\t}\n\n\t\tconst times = interpolant.parameterPositions,\n\t\t\tvalues = interpolant.sampleValues;\n\n\t\ttimes[ 0 ] = now;\n\t\ttimes[ 1 ] = now + duration;\n\n\t\tvalues[ 0 ] = startTimeScale / timeScale;\n\t\tvalues[ 1 ] = endTimeScale / timeScale;\n\n\t\treturn this;\n\n\t}\n\n\tstopWarping() {\n\n\t\tconst timeScaleInterpolant = this._timeScaleInterpolant;\n\n\t\tif ( timeScaleInterpolant !== null ) {\n\n\t\t\tthis._timeScaleInterpolant = null;\n\t\t\tthis._mixer._takeBackControlInterpolant( timeScaleInterpolant );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// Object Accessors\n\n\tgetMixer() {\n\n\t\treturn this._mixer;\n\n\t}\n\n\tgetClip() {\n\n\t\treturn this._clip;\n\n\t}\n\n\tgetRoot() {\n\n\t\treturn this._localRoot || this._mixer._root;\n\n\t}\n\n\t// Interna\n\n\t_update( time, deltaTime, timeDirection, accuIndex ) {\n\n\t\t// called by the mixer\n\n\t\tif ( ! this.enabled ) {\n\n\t\t\t// call ._updateWeight() to update ._effectiveWeight\n\n\t\t\tthis._updateWeight( time );\n\t\t\treturn;\n\n\t\t}\n\n\t\tconst startTime = this._startTime;\n\n\t\tif ( startTime !== null ) {\n\n\t\t\t// check for scheduled start of action\n\n\t\t\tconst timeRunning = ( time - startTime ) * timeDirection;\n\t\t\tif ( timeRunning < 0 || timeDirection === 0 ) {\n\n\t\t\t\tdeltaTime = 0;\n\n\t\t\t} else {\n\n\n\t\t\t\tthis._startTime = null; // unschedule\n\t\t\t\tdeltaTime = timeDirection * timeRunning;\n\n\t\t\t}\n\n\t\t}\n\n\t\t// apply time scale and advance time\n\n\t\tdeltaTime *= this._updateTimeScale( time );\n\t\tconst clipTime = this._updateTime( deltaTime );\n\n\t\t// note: _updateTime may disable the action resulting in\n\t\t// an effective weight of 0\n\n\t\tconst weight = this._updateWeight( time );\n\n\t\tif ( weight > 0 ) {\n\n\t\t\tconst interpolants = this._interpolants;\n\t\t\tconst propertyMixers = this._propertyBindings;\n\n\t\t\tswitch ( this.blendMode ) {\n\n\t\t\t\tcase AdditiveAnimationBlendMode:\n\n\t\t\t\t\tfor ( let j = 0, m = interpolants.length; j !== m; ++ j ) {\n\n\t\t\t\t\t\tinterpolants[ j ].evaluate( clipTime );\n\t\t\t\t\t\tpropertyMixers[ j ].accumulateAdditive( weight );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase NormalAnimationBlendMode:\n\t\t\t\tdefault:\n\n\t\t\t\t\tfor ( let j = 0, m = interpolants.length; j !== m; ++ j ) {\n\n\t\t\t\t\t\tinterpolants[ j ].evaluate( clipTime );\n\t\t\t\t\t\tpropertyMixers[ j ].accumulate( accuIndex, weight );\n\n\t\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_updateWeight( time ) {\n\n\t\tlet weight = 0;\n\n\t\tif ( this.enabled ) {\n\n\t\t\tweight = this.weight;\n\t\t\tconst interpolant = this._weightInterpolant;\n\n\t\t\tif ( interpolant !== null ) {\n\n\t\t\t\tconst interpolantValue = interpolant.evaluate( time )[ 0 ];\n\n\t\t\t\tweight *= interpolantValue;\n\n\t\t\t\tif ( time > interpolant.parameterPositions[ 1 ] ) {\n\n\t\t\t\t\tthis.stopFading();\n\n\t\t\t\t\tif ( interpolantValue === 0 ) {\n\n\t\t\t\t\t\t// faded out, disable\n\t\t\t\t\t\tthis.enabled = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis._effectiveWeight = weight;\n\t\treturn weight;\n\n\t}\n\n\t_updateTimeScale( time ) {\n\n\t\tlet timeScale = 0;\n\n\t\tif ( ! this.paused ) {\n\n\t\t\ttimeScale = this.timeScale;\n\n\t\t\tconst interpolant = this._timeScaleInterpolant;\n\n\t\t\tif ( interpolant !== null ) {\n\n\t\t\t\tconst interpolantValue = interpolant.evaluate( time )[ 0 ];\n\n\t\t\t\ttimeScale *= interpolantValue;\n\n\t\t\t\tif ( time > interpolant.parameterPositions[ 1 ] ) {\n\n\t\t\t\t\tthis.stopWarping();\n\n\t\t\t\t\tif ( timeScale === 0 ) {\n\n\t\t\t\t\t\t// motion has halted, pause\n\t\t\t\t\t\tthis.paused = true;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\t// warp done - apply final time scale\n\t\t\t\t\t\tthis.timeScale = timeScale;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis._effectiveTimeScale = timeScale;\n\t\treturn timeScale;\n\n\t}\n\n\t_updateTime( deltaTime ) {\n\n\t\tconst duration = this._clip.duration;\n\t\tconst loop = this.loop;\n\n\t\tlet time = this.time + deltaTime;\n\t\tlet loopCount = this._loopCount;\n\n\t\tconst pingPong = ( loop === LoopPingPong );\n\n\t\tif ( deltaTime === 0 ) {\n\n\t\t\tif ( loopCount === - 1 ) return time;\n\n\t\t\treturn ( pingPong && ( loopCount & 1 ) === 1 ) ? duration - time : time;\n\n\t\t}\n\n\t\tif ( loop === LoopOnce ) {\n\n\t\t\tif ( loopCount === - 1 ) {\n\n\t\t\t\t// just started\n\n\t\t\t\tthis._loopCount = 0;\n\t\t\t\tthis._setEndings( true, true, false );\n\n\t\t\t}\n\n\t\t\thandle_stop: {\n\n\t\t\t\tif ( time >= duration ) {\n\n\t\t\t\t\ttime = duration;\n\n\t\t\t\t} else if ( time < 0 ) {\n\n\t\t\t\t\ttime = 0;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tthis.time = time;\n\n\t\t\t\t\tbreak handle_stop;\n\n\t\t\t\t}\n\n\t\t\t\tif ( this.clampWhenFinished ) this.paused = true;\n\t\t\t\telse this.enabled = false;\n\n\t\t\t\tthis.time = time;\n\n\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\ttype: 'finished', action: this,\n\t\t\t\t\tdirection: deltaTime < 0 ? - 1 : 1\n\t\t\t\t} );\n\n\t\t\t}\n\n\t\t} else { // repetitive Repeat or PingPong\n\n\t\t\tif ( loopCount === - 1 ) {\n\n\t\t\t\t// just started\n\n\t\t\t\tif ( deltaTime >= 0 ) {\n\n\t\t\t\t\tloopCount = 0;\n\n\t\t\t\t\tthis._setEndings( true, this.repetitions === 0, pingPong );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// when looping in reverse direction, the initial\n\t\t\t\t\t// transition through zero counts as a repetition,\n\t\t\t\t\t// so leave loopCount at -1\n\n\t\t\t\t\tthis._setEndings( this.repetitions === 0, true, pingPong );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( time >= duration || time < 0 ) {\n\n\t\t\t\t// wrap around\n\n\t\t\t\tconst loopDelta = Math.floor( time / duration ); // signed\n\t\t\t\ttime -= duration * loopDelta;\n\n\t\t\t\tloopCount += Math.abs( loopDelta );\n\n\t\t\t\tconst pending = this.repetitions - loopCount;\n\n\t\t\t\tif ( pending <= 0 ) {\n\n\t\t\t\t\t// have to stop (switch state, clamp time, fire event)\n\n\t\t\t\t\tif ( this.clampWhenFinished ) this.paused = true;\n\t\t\t\t\telse this.enabled = false;\n\n\t\t\t\t\ttime = deltaTime > 0 ? duration : 0;\n\n\t\t\t\t\tthis.time = time;\n\n\t\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\t\ttype: 'finished', action: this,\n\t\t\t\t\t\tdirection: deltaTime > 0 ? 1 : - 1\n\t\t\t\t\t} );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// keep running\n\n\t\t\t\t\tif ( pending === 1 ) {\n\n\t\t\t\t\t\t// entering the last round\n\n\t\t\t\t\t\tconst atStart = deltaTime < 0;\n\t\t\t\t\t\tthis._setEndings( atStart, ! atStart, pingPong );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tthis._setEndings( false, false, pingPong );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tthis._loopCount = loopCount;\n\n\t\t\t\t\tthis.time = time;\n\n\t\t\t\t\tthis._mixer.dispatchEvent( {\n\t\t\t\t\t\ttype: 'loop', action: this, loopDelta: loopDelta\n\t\t\t\t\t} );\n\n\t\t\t\t}\n\n\t\t\t} else {\n\n\t\t\t\tthis.time = time;\n\n\t\t\t}\n\n\t\t\tif ( pingPong && ( loopCount & 1 ) === 1 ) {\n\n\t\t\t\t// invert time for the \"pong round\"\n\n\t\t\t\treturn duration - time;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn time;\n\n\t}\n\n\t_setEndings( atStart, atEnd, pingPong ) {\n\n\t\tconst settings = this._interpolantSettings;\n\n\t\tif ( pingPong ) {\n\n\t\t\tsettings.endingStart = ZeroSlopeEnding;\n\t\t\tsettings.endingEnd = ZeroSlopeEnding;\n\n\t\t} else {\n\n\t\t\t// assuming for LoopOnce atStart == atEnd == true\n\n\t\t\tif ( atStart ) {\n\n\t\t\t\tsettings.endingStart = this.zeroSlopeAtStart ? ZeroSlopeEnding : ZeroCurvatureEnding;\n\n\t\t\t} else {\n\n\t\t\t\tsettings.endingStart = WrapAroundEnding;\n\n\t\t\t}\n\n\t\t\tif ( atEnd ) {\n\n\t\t\t\tsettings.endingEnd = this.zeroSlopeAtEnd ? ZeroSlopeEnding : ZeroCurvatureEnding;\n\n\t\t\t} else {\n\n\t\t\t\tsettings.endingEnd \t = WrapAroundEnding;\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_scheduleFading( duration, weightNow, weightThen ) {\n\n\t\tconst mixer = this._mixer, now = mixer.time;\n\t\tlet interpolant = this._weightInterpolant;\n\n\t\tif ( interpolant === null ) {\n\n\t\t\tinterpolant = mixer._lendControlInterpolant();\n\t\t\tthis._weightInterpolant = interpolant;\n\n\t\t}\n\n\t\tconst times = interpolant.parameterPositions,\n\t\t\tvalues = interpolant.sampleValues;\n\n\t\ttimes[ 0 ] = now;\n\t\tvalues[ 0 ] = weightNow;\n\t\ttimes[ 1 ] = now + duration;\n\t\tvalues[ 1 ] = weightThen;\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _controlInterpolantsResultBuffer = new Float32Array( 1 );\n\n\nclass AnimationMixer extends EventDispatcher {\n\n\tconstructor( root ) {\n\n\t\tsuper();\n\n\t\tthis._root = root;\n\t\tthis._initMemoryManager();\n\t\tthis._accuIndex = 0;\n\t\tthis.time = 0;\n\t\tthis.timeScale = 1.0;\n\n\t}\n\n\t_bindAction( action, prototypeAction ) {\n\n\t\tconst root = action._localRoot || this._root,\n\t\t\ttracks = action._clip.tracks,\n\t\t\tnTracks = tracks.length,\n\t\t\tbindings = action._propertyBindings,\n\t\t\tinterpolants = action._interpolants,\n\t\t\trootUuid = root.uuid,\n\t\t\tbindingsByRoot = this._bindingsByRootAndName;\n\n\t\tlet bindingsByName = bindingsByRoot[ rootUuid ];\n\n\t\tif ( bindingsByName === undefined ) {\n\n\t\t\tbindingsByName = {};\n\t\t\tbindingsByRoot[ rootUuid ] = bindingsByName;\n\n\t\t}\n\n\t\tfor ( let i = 0; i !== nTracks; ++ i ) {\n\n\t\t\tconst track = tracks[ i ],\n\t\t\t\ttrackName = track.name;\n\n\t\t\tlet binding = bindingsByName[ trackName ];\n\n\t\t\tif ( binding !== undefined ) {\n\n\t\t\t\t++ binding.referenceCount;\n\t\t\t\tbindings[ i ] = binding;\n\n\t\t\t} else {\n\n\t\t\t\tbinding = bindings[ i ];\n\n\t\t\t\tif ( binding !== undefined ) {\n\n\t\t\t\t\t// existing binding, make sure the cache knows\n\n\t\t\t\t\tif ( binding._cacheIndex === null ) {\n\n\t\t\t\t\t\t++ binding.referenceCount;\n\t\t\t\t\t\tthis._addInactiveBinding( binding, rootUuid, trackName );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tcontinue;\n\n\t\t\t\t}\n\n\t\t\t\tconst path = prototypeAction && prototypeAction.\n\t\t\t\t\t_propertyBindings[ i ].binding.parsedPath;\n\n\t\t\t\tbinding = new PropertyMixer(\n\t\t\t\t\tPropertyBinding.create( root, trackName, path ),\n\t\t\t\t\ttrack.ValueTypeName, track.getValueSize() );\n\n\t\t\t\t++ binding.referenceCount;\n\t\t\t\tthis._addInactiveBinding( binding, rootUuid, trackName );\n\n\t\t\t\tbindings[ i ] = binding;\n\n\t\t\t}\n\n\t\t\tinterpolants[ i ].resultBuffer = binding.buffer;\n\n\t\t}\n\n\t}\n\n\t_activateAction( action ) {\n\n\t\tif ( ! this._isActiveAction( action ) ) {\n\n\t\t\tif ( action._cacheIndex === null ) {\n\n\t\t\t\t// this action has been forgotten by the cache, but the user\n\t\t\t\t// appears to be still using it -> rebind\n\n\t\t\t\tconst rootUuid = ( action._localRoot || this._root ).uuid,\n\t\t\t\t\tclipUuid = action._clip.uuid,\n\t\t\t\t\tactionsForClip = this._actionsByClip[ clipUuid ];\n\n\t\t\t\tthis._bindAction( action,\n\t\t\t\t\tactionsForClip && actionsForClip.knownActions[ 0 ] );\n\n\t\t\t\tthis._addInactiveAction( action, clipUuid, rootUuid );\n\n\t\t\t}\n\n\t\t\tconst bindings = action._propertyBindings;\n\n\t\t\t// increment reference counts / sort out state\n\t\t\tfor ( let i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\tconst binding = bindings[ i ];\n\n\t\t\t\tif ( binding.useCount ++ === 0 ) {\n\n\t\t\t\t\tthis._lendBinding( binding );\n\t\t\t\t\tbinding.saveOriginalState();\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis._lendAction( action );\n\n\t\t}\n\n\t}\n\n\t_deactivateAction( action ) {\n\n\t\tif ( this._isActiveAction( action ) ) {\n\n\t\t\tconst bindings = action._propertyBindings;\n\n\t\t\t// decrement reference counts / sort out state\n\t\t\tfor ( let i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\t\tconst binding = bindings[ i ];\n\n\t\t\t\tif ( -- binding.useCount === 0 ) {\n\n\t\t\t\t\tbinding.restoreOriginalState();\n\t\t\t\t\tthis._takeBackBinding( binding );\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tthis._takeBackAction( action );\n\n\t\t}\n\n\t}\n\n\t// Memory manager\n\n\t_initMemoryManager() {\n\n\t\tthis._actions = []; // 'nActiveActions' followed by inactive ones\n\t\tthis._nActiveActions = 0;\n\n\t\tthis._actionsByClip = {};\n\t\t// inside:\n\t\t// {\n\t\t// \tknownActions: Array< AnimationAction > - used as prototypes\n\t\t// \tactionByRoot: AnimationAction - lookup\n\t\t// }\n\n\n\t\tthis._bindings = []; // 'nActiveBindings' followed by inactive ones\n\t\tthis._nActiveBindings = 0;\n\n\t\tthis._bindingsByRootAndName = {}; // inside: Map< name, PropertyMixer >\n\n\n\t\tthis._controlInterpolants = []; // same game as above\n\t\tthis._nActiveControlInterpolants = 0;\n\n\t\tconst scope = this;\n\n\t\tthis.stats = {\n\n\t\t\tactions: {\n\t\t\t\tget total() {\n\n\t\t\t\t\treturn scope._actions.length;\n\n\t\t\t\t},\n\t\t\t\tget inUse() {\n\n\t\t\t\t\treturn scope._nActiveActions;\n\n\t\t\t\t}\n\t\t\t},\n\t\t\tbindings: {\n\t\t\t\tget total() {\n\n\t\t\t\t\treturn scope._bindings.length;\n\n\t\t\t\t},\n\t\t\t\tget inUse() {\n\n\t\t\t\t\treturn scope._nActiveBindings;\n\n\t\t\t\t}\n\t\t\t},\n\t\t\tcontrolInterpolants: {\n\t\t\t\tget total() {\n\n\t\t\t\t\treturn scope._controlInterpolants.length;\n\n\t\t\t\t},\n\t\t\t\tget inUse() {\n\n\t\t\t\t\treturn scope._nActiveControlInterpolants;\n\n\t\t\t\t}\n\t\t\t}\n\n\t\t};\n\n\t}\n\n\t// Memory management for AnimationAction objects\n\n\t_isActiveAction( action ) {\n\n\t\tconst index = action._cacheIndex;\n\t\treturn index !== null && index < this._nActiveActions;\n\n\t}\n\n\t_addInactiveAction( action, clipUuid, rootUuid ) {\n\n\t\tconst actions = this._actions,\n\t\t\tactionsByClip = this._actionsByClip;\n\n\t\tlet actionsForClip = actionsByClip[ clipUuid ];\n\n\t\tif ( actionsForClip === undefined ) {\n\n\t\t\tactionsForClip = {\n\n\t\t\t\tknownActions: [ action ],\n\t\t\t\tactionByRoot: {}\n\n\t\t\t};\n\n\t\t\taction._byClipCacheIndex = 0;\n\n\t\t\tactionsByClip[ clipUuid ] = actionsForClip;\n\n\t\t} else {\n\n\t\t\tconst knownActions = actionsForClip.knownActions;\n\n\t\t\taction._byClipCacheIndex = knownActions.length;\n\t\t\tknownActions.push( action );\n\n\t\t}\n\n\t\taction._cacheIndex = actions.length;\n\t\tactions.push( action );\n\n\t\tactionsForClip.actionByRoot[ rootUuid ] = action;\n\n\t}\n\n\t_removeInactiveAction( action ) {\n\n\t\tconst actions = this._actions,\n\t\t\tlastInactiveAction = actions[ actions.length - 1 ],\n\t\t\tcacheIndex = action._cacheIndex;\n\n\t\tlastInactiveAction._cacheIndex = cacheIndex;\n\t\tactions[ cacheIndex ] = lastInactiveAction;\n\t\tactions.pop();\n\n\t\taction._cacheIndex = null;\n\n\n\t\tconst clipUuid = action._clip.uuid,\n\t\t\tactionsByClip = this._actionsByClip,\n\t\t\tactionsForClip = actionsByClip[ clipUuid ],\n\t\t\tknownActionsForClip = actionsForClip.knownActions,\n\n\t\t\tlastKnownAction =\n\t\t\t\tknownActionsForClip[ knownActionsForClip.length - 1 ],\n\n\t\t\tbyClipCacheIndex = action._byClipCacheIndex;\n\n\t\tlastKnownAction._byClipCacheIndex = byClipCacheIndex;\n\t\tknownActionsForClip[ byClipCacheIndex ] = lastKnownAction;\n\t\tknownActionsForClip.pop();\n\n\t\taction._byClipCacheIndex = null;\n\n\n\t\tconst actionByRoot = actionsForClip.actionByRoot,\n\t\t\trootUuid = ( action._localRoot || this._root ).uuid;\n\n\t\tdelete actionByRoot[ rootUuid ];\n\n\t\tif ( knownActionsForClip.length === 0 ) {\n\n\t\t\tdelete actionsByClip[ clipUuid ];\n\n\t\t}\n\n\t\tthis._removeInactiveBindingsForAction( action );\n\n\t}\n\n\t_removeInactiveBindingsForAction( action ) {\n\n\t\tconst bindings = action._propertyBindings;\n\n\t\tfor ( let i = 0, n = bindings.length; i !== n; ++ i ) {\n\n\t\t\tconst binding = bindings[ i ];\n\n\t\t\tif ( -- binding.referenceCount === 0 ) {\n\n\t\t\t\tthis._removeInactiveBinding( binding );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t_lendAction( action ) {\n\n\t\t// [ active actions | inactive actions ]\n\t\t// [ active actions >| inactive actions ]\n\t\t// s a\n\t\t// <-swap->\n\t\t// a s\n\n\t\tconst actions = this._actions,\n\t\t\tprevIndex = action._cacheIndex,\n\n\t\t\tlastActiveIndex = this._nActiveActions ++,\n\n\t\t\tfirstInactiveAction = actions[ lastActiveIndex ];\n\n\t\taction._cacheIndex = lastActiveIndex;\n\t\tactions[ lastActiveIndex ] = action;\n\n\t\tfirstInactiveAction._cacheIndex = prevIndex;\n\t\tactions[ prevIndex ] = firstInactiveAction;\n\n\t}\n\n\t_takeBackAction( action ) {\n\n\t\t// [ active actions | inactive actions ]\n\t\t// [ active actions |< inactive actions ]\n\t\t// a s\n\t\t// <-swap->\n\t\t// s a\n\n\t\tconst actions = this._actions,\n\t\t\tprevIndex = action._cacheIndex,\n\n\t\t\tfirstInactiveIndex = -- this._nActiveActions,\n\n\t\t\tlastActiveAction = actions[ firstInactiveIndex ];\n\n\t\taction._cacheIndex = firstInactiveIndex;\n\t\tactions[ firstInactiveIndex ] = action;\n\n\t\tlastActiveAction._cacheIndex = prevIndex;\n\t\tactions[ prevIndex ] = lastActiveAction;\n\n\t}\n\n\t// Memory management for PropertyMixer objects\n\n\t_addInactiveBinding( binding, rootUuid, trackName ) {\n\n\t\tconst bindingsByRoot = this._bindingsByRootAndName,\n\t\t\tbindings = this._bindings;\n\n\t\tlet bindingByName = bindingsByRoot[ rootUuid ];\n\n\t\tif ( bindingByName === undefined ) {\n\n\t\t\tbindingByName = {};\n\t\t\tbindingsByRoot[ rootUuid ] = bindingByName;\n\n\t\t}\n\n\t\tbindingByName[ trackName ] = binding;\n\n\t\tbinding._cacheIndex = bindings.length;\n\t\tbindings.push( binding );\n\n\t}\n\n\t_removeInactiveBinding( binding ) {\n\n\t\tconst bindings = this._bindings,\n\t\t\tpropBinding = binding.binding,\n\t\t\trootUuid = propBinding.rootNode.uuid,\n\t\t\ttrackName = propBinding.path,\n\t\t\tbindingsByRoot = this._bindingsByRootAndName,\n\t\t\tbindingByName = bindingsByRoot[ rootUuid ],\n\n\t\t\tlastInactiveBinding = bindings[ bindings.length - 1 ],\n\t\t\tcacheIndex = binding._cacheIndex;\n\n\t\tlastInactiveBinding._cacheIndex = cacheIndex;\n\t\tbindings[ cacheIndex ] = lastInactiveBinding;\n\t\tbindings.pop();\n\n\t\tdelete bindingByName[ trackName ];\n\n\t\tif ( Object.keys( bindingByName ).length === 0 ) {\n\n\t\t\tdelete bindingsByRoot[ rootUuid ];\n\n\t\t}\n\n\t}\n\n\t_lendBinding( binding ) {\n\n\t\tconst bindings = this._bindings,\n\t\t\tprevIndex = binding._cacheIndex,\n\n\t\t\tlastActiveIndex = this._nActiveBindings ++,\n\n\t\t\tfirstInactiveBinding = bindings[ lastActiveIndex ];\n\n\t\tbinding._cacheIndex = lastActiveIndex;\n\t\tbindings[ lastActiveIndex ] = binding;\n\n\t\tfirstInactiveBinding._cacheIndex = prevIndex;\n\t\tbindings[ prevIndex ] = firstInactiveBinding;\n\n\t}\n\n\t_takeBackBinding( binding ) {\n\n\t\tconst bindings = this._bindings,\n\t\t\tprevIndex = binding._cacheIndex,\n\n\t\t\tfirstInactiveIndex = -- this._nActiveBindings,\n\n\t\t\tlastActiveBinding = bindings[ firstInactiveIndex ];\n\n\t\tbinding._cacheIndex = firstInactiveIndex;\n\t\tbindings[ firstInactiveIndex ] = binding;\n\n\t\tlastActiveBinding._cacheIndex = prevIndex;\n\t\tbindings[ prevIndex ] = lastActiveBinding;\n\n\t}\n\n\n\t// Memory management of Interpolants for weight and time scale\n\n\t_lendControlInterpolant() {\n\n\t\tconst interpolants = this._controlInterpolants,\n\t\t\tlastActiveIndex = this._nActiveControlInterpolants ++;\n\n\t\tlet interpolant = interpolants[ lastActiveIndex ];\n\n\t\tif ( interpolant === undefined ) {\n\n\t\t\tinterpolant = new LinearInterpolant(\n\t\t\t\tnew Float32Array( 2 ), new Float32Array( 2 ),\n\t\t\t\t1, _controlInterpolantsResultBuffer );\n\n\t\t\tinterpolant.__cacheIndex = lastActiveIndex;\n\t\t\tinterpolants[ lastActiveIndex ] = interpolant;\n\n\t\t}\n\n\t\treturn interpolant;\n\n\t}\n\n\t_takeBackControlInterpolant( interpolant ) {\n\n\t\tconst interpolants = this._controlInterpolants,\n\t\t\tprevIndex = interpolant.__cacheIndex,\n\n\t\t\tfirstInactiveIndex = -- this._nActiveControlInterpolants,\n\n\t\t\tlastActiveInterpolant = interpolants[ firstInactiveIndex ];\n\n\t\tinterpolant.__cacheIndex = firstInactiveIndex;\n\t\tinterpolants[ firstInactiveIndex ] = interpolant;\n\n\t\tlastActiveInterpolant.__cacheIndex = prevIndex;\n\t\tinterpolants[ prevIndex ] = lastActiveInterpolant;\n\n\t}\n\n\t// return an action for a clip optionally using a custom root target\n\t// object (this method allocates a lot of dynamic memory in case a\n\t// previously unknown clip/root combination is specified)\n\tclipAction( clip, optionalRoot, blendMode ) {\n\n\t\tconst root = optionalRoot || this._root,\n\t\t\trootUuid = root.uuid;\n\n\t\tlet clipObject = typeof clip === 'string' ? AnimationClip.findByName( root, clip ) : clip;\n\n\t\tconst clipUuid = clipObject !== null ? clipObject.uuid : clip;\n\n\t\tconst actionsForClip = this._actionsByClip[ clipUuid ];\n\t\tlet prototypeAction = null;\n\n\t\tif ( blendMode === undefined ) {\n\n\t\t\tif ( clipObject !== null ) {\n\n\t\t\t\tblendMode = clipObject.blendMode;\n\n\t\t\t} else {\n\n\t\t\t\tblendMode = NormalAnimationBlendMode;\n\n\t\t\t}\n\n\t\t}\n\n\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\tconst existingAction = actionsForClip.actionByRoot[ rootUuid ];\n\n\t\t\tif ( existingAction !== undefined && existingAction.blendMode === blendMode ) {\n\n\t\t\t\treturn existingAction;\n\n\t\t\t}\n\n\t\t\t// we know the clip, so we don't have to parse all\n\t\t\t// the bindings again but can just copy\n\t\t\tprototypeAction = actionsForClip.knownActions[ 0 ];\n\n\t\t\t// also, take the clip from the prototype action\n\t\t\tif ( clipObject === null )\n\t\t\t\tclipObject = prototypeAction._clip;\n\n\t\t}\n\n\t\t// clip must be known when specified via string\n\t\tif ( clipObject === null ) return null;\n\n\t\t// allocate all resources required to run it\n\t\tconst newAction = new AnimationAction( this, clipObject, optionalRoot, blendMode );\n\n\t\tthis._bindAction( newAction, prototypeAction );\n\n\t\t// and make the action known to the memory manager\n\t\tthis._addInactiveAction( newAction, clipUuid, rootUuid );\n\n\t\treturn newAction;\n\n\t}\n\n\t// get an existing action\n\texistingAction( clip, optionalRoot ) {\n\n\t\tconst root = optionalRoot || this._root,\n\t\t\trootUuid = root.uuid,\n\n\t\t\tclipObject = typeof clip === 'string' ?\n\t\t\t\tAnimationClip.findByName( root, clip ) : clip,\n\n\t\t\tclipUuid = clipObject ? clipObject.uuid : clip,\n\n\t\t\tactionsForClip = this._actionsByClip[ clipUuid ];\n\n\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\treturn actionsForClip.actionByRoot[ rootUuid ] || null;\n\n\t\t}\n\n\t\treturn null;\n\n\t}\n\n\t// deactivates all previously scheduled actions\n\tstopAllAction() {\n\n\t\tconst actions = this._actions,\n\t\t\tnActions = this._nActiveActions;\n\n\t\tfor ( let i = nActions - 1; i >= 0; -- i ) {\n\n\t\t\tactions[ i ].stop();\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// advance the time and update apply the animation\n\tupdate( deltaTime ) {\n\n\t\tdeltaTime *= this.timeScale;\n\n\t\tconst actions = this._actions,\n\t\t\tnActions = this._nActiveActions,\n\n\t\t\ttime = this.time += deltaTime,\n\t\t\ttimeDirection = Math.sign( deltaTime ),\n\n\t\t\taccuIndex = this._accuIndex ^= 1;\n\n\t\t// run active actions\n\n\t\tfor ( let i = 0; i !== nActions; ++ i ) {\n\n\t\t\tconst action = actions[ i ];\n\n\t\t\taction._update( time, deltaTime, timeDirection, accuIndex );\n\n\t\t}\n\n\t\t// update scene graph\n\n\t\tconst bindings = this._bindings,\n\t\t\tnBindings = this._nActiveBindings;\n\n\t\tfor ( let i = 0; i !== nBindings; ++ i ) {\n\n\t\t\tbindings[ i ].apply( accuIndex );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\t// Allows you to seek to a specific time in an animation.\n\tsetTime( timeInSeconds ) {\n\n\t\tthis.time = 0; // Zero out time attribute for AnimationMixer object;\n\t\tfor ( let i = 0; i < this._actions.length; i ++ ) {\n\n\t\t\tthis._actions[ i ].time = 0; // Zero out time attribute for all associated AnimationAction objects.\n\n\t\t}\n\n\t\treturn this.update( timeInSeconds ); // Update used to set exact time. Returns \"this\" AnimationMixer object.\n\n\t}\n\n\t// return this mixer's root target object\n\tgetRoot() {\n\n\t\treturn this._root;\n\n\t}\n\n\t// free all resources specific to a particular clip\n\tuncacheClip( clip ) {\n\n\t\tconst actions = this._actions,\n\t\t\tclipUuid = clip.uuid,\n\t\t\tactionsByClip = this._actionsByClip,\n\t\t\tactionsForClip = actionsByClip[ clipUuid ];\n\n\t\tif ( actionsForClip !== undefined ) {\n\n\t\t\t// note: just calling _removeInactiveAction would mess up the\n\t\t\t// iteration state and also require updating the state we can\n\t\t\t// just throw away\n\n\t\t\tconst actionsToRemove = actionsForClip.knownActions;\n\n\t\t\tfor ( let i = 0, n = actionsToRemove.length; i !== n; ++ i ) {\n\n\t\t\t\tconst action = actionsToRemove[ i ];\n\n\t\t\t\tthis._deactivateAction( action );\n\n\t\t\t\tconst cacheIndex = action._cacheIndex,\n\t\t\t\t\tlastInactiveAction = actions[ actions.length - 1 ];\n\n\t\t\t\taction._cacheIndex = null;\n\t\t\t\taction._byClipCacheIndex = null;\n\n\t\t\t\tlastInactiveAction._cacheIndex = cacheIndex;\n\t\t\t\tactions[ cacheIndex ] = lastInactiveAction;\n\t\t\t\tactions.pop();\n\n\t\t\t\tthis._removeInactiveBindingsForAction( action );\n\n\t\t\t}\n\n\t\t\tdelete actionsByClip[ clipUuid ];\n\n\t\t}\n\n\t}\n\n\t// free all resources specific to a particular root target object\n\tuncacheRoot( root ) {\n\n\t\tconst rootUuid = root.uuid,\n\t\t\tactionsByClip = this._actionsByClip;\n\n\t\tfor ( const clipUuid in actionsByClip ) {\n\n\t\t\tconst actionByRoot = actionsByClip[ clipUuid ].actionByRoot,\n\t\t\t\taction = actionByRoot[ rootUuid ];\n\n\t\t\tif ( action !== undefined ) {\n\n\t\t\t\tthis._deactivateAction( action );\n\t\t\t\tthis._removeInactiveAction( action );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst bindingsByRoot = this._bindingsByRootAndName,\n\t\t\tbindingByName = bindingsByRoot[ rootUuid ];\n\n\t\tif ( bindingByName !== undefined ) {\n\n\t\t\tfor ( const trackName in bindingByName ) {\n\n\t\t\t\tconst binding = bindingByName[ trackName ];\n\t\t\t\tbinding.restoreOriginalState();\n\t\t\t\tthis._removeInactiveBinding( binding );\n\n\t\t\t}\n\n\t\t}\n\n\t}\n\n\t// remove a targeted clip from the cache\n\tuncacheAction( clip, optionalRoot ) {\n\n\t\tconst action = this.existingAction( clip, optionalRoot );\n\n\t\tif ( action !== null ) {\n\n\t\t\tthis._deactivateAction( action );\n\t\t\tthis._removeInactiveAction( action );\n\n\t\t}\n\n\t}\n\n}\n\nclass Uniform {\n\n\tconstructor( value ) {\n\n\t\tthis.value = value;\n\n\t}\n\n\tclone() {\n\n\t\treturn new Uniform( this.value.clone === undefined ? this.value : this.value.clone() );\n\n\t}\n\n}\n\nlet _id = 0;\n\nclass UniformsGroup extends EventDispatcher {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.isUniformsGroup = true;\n\n\t\tObject.defineProperty( this, 'id', { value: _id ++ } );\n\n\t\tthis.name = '';\n\n\t\tthis.usage = StaticDrawUsage;\n\t\tthis.uniforms = [];\n\n\t}\n\n\tadd( uniform ) {\n\n\t\tthis.uniforms.push( uniform );\n\n\t\treturn this;\n\n\t}\n\n\tremove( uniform ) {\n\n\t\tconst index = this.uniforms.indexOf( uniform );\n\n\t\tif ( index !== - 1 ) this.uniforms.splice( index, 1 );\n\n\t\treturn this;\n\n\t}\n\n\tsetName( name ) {\n\n\t\tthis.name = name;\n\n\t\treturn this;\n\n\t}\n\n\tsetUsage( value ) {\n\n\t\tthis.usage = value;\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.dispatchEvent( { type: 'dispose' } );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tthis.name = source.name;\n\t\tthis.usage = source.usage;\n\n\t\tconst uniformsSource = source.uniforms;\n\n\t\tthis.uniforms.length = 0;\n\n\t\tfor ( let i = 0, l = uniformsSource.length; i < l; i ++ ) {\n\n\t\t\tconst uniforms = Array.isArray( uniformsSource[ i ] ) ? uniformsSource[ i ] : [ uniformsSource[ i ] ];\n\n\t\t\tfor ( let j = 0; j < uniforms.length; j ++ ) {\n\n\t\t\t\tthis.uniforms.push( uniforms[ j ].clone() );\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nclass InstancedInterleavedBuffer extends InterleavedBuffer {\n\n\tconstructor( array, stride, meshPerAttribute = 1 ) {\n\n\t\tsuper( array, stride );\n\n\t\tthis.isInstancedInterleavedBuffer = true;\n\n\t\tthis.meshPerAttribute = meshPerAttribute;\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source );\n\n\t\tthis.meshPerAttribute = source.meshPerAttribute;\n\n\t\treturn this;\n\n\t}\n\n\tclone( data ) {\n\n\t\tconst ib = super.clone( data );\n\n\t\tib.meshPerAttribute = this.meshPerAttribute;\n\n\t\treturn ib;\n\n\t}\n\n\ttoJSON( data ) {\n\n\t\tconst json = super.toJSON( data );\n\n\t\tjson.isInstancedInterleavedBuffer = true;\n\t\tjson.meshPerAttribute = this.meshPerAttribute;\n\n\t\treturn json;\n\n\t}\n\n}\n\nclass GLBufferAttribute {\n\n\tconstructor( buffer, type, itemSize, elementSize, count ) {\n\n\t\tthis.isGLBufferAttribute = true;\n\n\t\tthis.name = '';\n\n\t\tthis.buffer = buffer;\n\t\tthis.type = type;\n\t\tthis.itemSize = itemSize;\n\t\tthis.elementSize = elementSize;\n\t\tthis.count = count;\n\n\t\tthis.version = 0;\n\n\t}\n\n\tset needsUpdate( value ) {\n\n\t\tif ( value === true ) this.version ++;\n\n\t}\n\n\tsetBuffer( buffer ) {\n\n\t\tthis.buffer = buffer;\n\n\t\treturn this;\n\n\t}\n\n\tsetType( type, elementSize ) {\n\n\t\tthis.type = type;\n\t\tthis.elementSize = elementSize;\n\n\t\treturn this;\n\n\t}\n\n\tsetItemSize( itemSize ) {\n\n\t\tthis.itemSize = itemSize;\n\n\t\treturn this;\n\n\t}\n\n\tsetCount( count ) {\n\n\t\tthis.count = count;\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _matrix = /*@__PURE__*/ new Matrix4();\n\nclass Raycaster {\n\n\tconstructor( origin, direction, near = 0, far = Infinity ) {\n\n\t\tthis.ray = new Ray( origin, direction );\n\t\t// direction is assumed to be normalized (for accurate distance calculations)\n\n\t\tthis.near = near;\n\t\tthis.far = far;\n\t\tthis.camera = null;\n\t\tthis.layers = new Layers();\n\n\t\tthis.params = {\n\t\t\tMesh: {},\n\t\t\tLine: { threshold: 1 },\n\t\t\tLOD: {},\n\t\t\tPoints: { threshold: 1 },\n\t\t\tSprite: {}\n\t\t};\n\n\t}\n\n\tset( origin, direction ) {\n\n\t\t// direction is assumed to be normalized (for accurate distance calculations)\n\n\t\tthis.ray.set( origin, direction );\n\n\t}\n\n\tsetFromCamera( coords, camera ) {\n\n\t\tif ( camera.isPerspectiveCamera ) {\n\n\t\t\tthis.ray.origin.setFromMatrixPosition( camera.matrixWorld );\n\t\t\tthis.ray.direction.set( coords.x, coords.y, 0.5 ).unproject( camera ).sub( this.ray.origin ).normalize();\n\t\t\tthis.camera = camera;\n\n\t\t} else if ( camera.isOrthographicCamera ) {\n\n\t\t\tthis.ray.origin.set( coords.x, coords.y, ( camera.near + camera.far ) / ( camera.near - camera.far ) ).unproject( camera ); // set origin in plane of camera\n\t\t\tthis.ray.direction.set( 0, 0, - 1 ).transformDirection( camera.matrixWorld );\n\t\t\tthis.camera = camera;\n\n\t\t} else {\n\n\t\t\tconsole.error( 'THREE.Raycaster: Unsupported camera type: ' + camera.type );\n\n\t\t}\n\n\t}\n\n\tsetFromXRController( controller ) {\n\n\t\t_matrix.identity().extractRotation( controller.matrixWorld );\n\n\t\tthis.ray.origin.setFromMatrixPosition( controller.matrixWorld );\n\t\tthis.ray.direction.set( 0, 0, - 1 ).applyMatrix4( _matrix );\n\n\t\treturn this;\n\n\t}\n\n\tintersectObject( object, recursive = true, intersects = [] ) {\n\n\t\tintersect( object, this, intersects, recursive );\n\n\t\tintersects.sort( ascSort );\n\n\t\treturn intersects;\n\n\t}\n\n\tintersectObjects( objects, recursive = true, intersects = [] ) {\n\n\t\tfor ( let i = 0, l = objects.length; i < l; i ++ ) {\n\n\t\t\tintersect( objects[ i ], this, intersects, recursive );\n\n\t\t}\n\n\t\tintersects.sort( ascSort );\n\n\t\treturn intersects;\n\n\t}\n\n}\n\nfunction ascSort( a, b ) {\n\n\treturn a.distance - b.distance;\n\n}\n\nfunction intersect( object, raycaster, intersects, recursive ) {\n\n\tlet propagate = true;\n\n\tif ( object.layers.test( raycaster.layers ) ) {\n\n\t\tconst result = object.raycast( raycaster, intersects );\n\n\t\tif ( result === false ) propagate = false;\n\n\t}\n\n\tif ( propagate === true && recursive === true ) {\n\n\t\tconst children = object.children;\n\n\t\tfor ( let i = 0, l = children.length; i < l; i ++ ) {\n\n\t\t\tintersect( children[ i ], raycaster, intersects, true );\n\n\t\t}\n\n\t}\n\n}\n\n/**\n * Ref: https://en.wikipedia.org/wiki/Spherical_coordinate_system\n *\n * phi (the polar angle) is measured from the positive y-axis. The positive y-axis is up.\n * theta (the azimuthal angle) is measured from the positive z-axis.\n */\nclass Spherical {\n\n\tconstructor( radius = 1, phi = 0, theta = 0 ) {\n\n\t\tthis.radius = radius;\n\t\tthis.phi = phi; // polar angle\n\t\tthis.theta = theta; // azimuthal angle\n\n\t\treturn this;\n\n\t}\n\n\tset( radius, phi, theta ) {\n\n\t\tthis.radius = radius;\n\t\tthis.phi = phi;\n\t\tthis.theta = theta;\n\n\t\treturn this;\n\n\t}\n\n\tcopy( other ) {\n\n\t\tthis.radius = other.radius;\n\t\tthis.phi = other.phi;\n\t\tthis.theta = other.theta;\n\n\t\treturn this;\n\n\t}\n\n\t// restrict phi to be between EPS and PI-EPS\n\tmakeSafe() {\n\n\t\tconst EPS = 0.000001;\n\t\tthis.phi = Math.max( EPS, Math.min( Math.PI - EPS, this.phi ) );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromVector3( v ) {\n\n\t\treturn this.setFromCartesianCoords( v.x, v.y, v.z );\n\n\t}\n\n\tsetFromCartesianCoords( x, y, z ) {\n\n\t\tthis.radius = Math.sqrt( x * x + y * y + z * z );\n\n\t\tif ( this.radius === 0 ) {\n\n\t\t\tthis.theta = 0;\n\t\t\tthis.phi = 0;\n\n\t\t} else {\n\n\t\t\tthis.theta = Math.atan2( x, z );\n\t\t\tthis.phi = Math.acos( clamp( y / this.radius, - 1, 1 ) );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\n/**\n * Ref: https://en.wikipedia.org/wiki/Cylindrical_coordinate_system\n */\n\nclass Cylindrical {\n\n\tconstructor( radius = 1, theta = 0, y = 0 ) {\n\n\t\tthis.radius = radius; // distance from the origin to a point in the x-z plane\n\t\tthis.theta = theta; // counterclockwise angle in the x-z plane measured in radians from the positive z-axis\n\t\tthis.y = y; // height above the x-z plane\n\n\t\treturn this;\n\n\t}\n\n\tset( radius, theta, y ) {\n\n\t\tthis.radius = radius;\n\t\tthis.theta = theta;\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tcopy( other ) {\n\n\t\tthis.radius = other.radius;\n\t\tthis.theta = other.theta;\n\t\tthis.y = other.y;\n\n\t\treturn this;\n\n\t}\n\n\tsetFromVector3( v ) {\n\n\t\treturn this.setFromCartesianCoords( v.x, v.y, v.z );\n\n\t}\n\n\tsetFromCartesianCoords( x, y, z ) {\n\n\t\tthis.radius = Math.sqrt( x * x + z * z );\n\t\tthis.theta = Math.atan2( x, z );\n\t\tthis.y = y;\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nclass Matrix2 {\n\n\tconstructor( n11, n12, n21, n22 ) {\n\n\t\tMatrix2.prototype.isMatrix2 = true;\n\n\t\tthis.elements = [\n\t\t\t1, 0,\n\t\t\t0, 1,\n\t\t];\n\n\t\tif ( n11 !== undefined ) {\n\n\t\t\tthis.set( n11, n12, n21, n22 );\n\n\t\t}\n\n\t}\n\n\tidentity() {\n\n\t\tthis.set(\n\t\t\t1, 0,\n\t\t\t0, 1,\n\t\t);\n\n\t\treturn this;\n\n\t}\n\n\tfromArray( array, offset = 0 ) {\n\n\t\tfor ( let i = 0; i < 4; i ++ ) {\n\n\t\t\tthis.elements[ i ] = array[ i + offset ];\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tset( n11, n12, n21, n22 ) {\n\n\t\tconst te = this.elements;\n\n\t\tte[ 0 ] = n11; te[ 2 ] = n12;\n\t\tte[ 1 ] = n21; te[ 3 ] = n22;\n\n\t\treturn this;\n\n\t}\n\n}\n\nconst _vector$4 = /*@__PURE__*/ new Vector2();\n\nclass Box2 {\n\n\tconstructor( min = new Vector2( + Infinity, + Infinity ), max = new Vector2( - Infinity, - Infinity ) ) {\n\n\t\tthis.isBox2 = true;\n\n\t\tthis.min = min;\n\t\tthis.max = max;\n\n\t}\n\n\tset( min, max ) {\n\n\t\tthis.min.copy( min );\n\t\tthis.max.copy( max );\n\n\t\treturn this;\n\n\t}\n\n\tsetFromPoints( points ) {\n\n\t\tthis.makeEmpty();\n\n\t\tfor ( let i = 0, il = points.length; i < il; i ++ ) {\n\n\t\t\tthis.expandByPoint( points[ i ] );\n\n\t\t}\n\n\t\treturn this;\n\n\t}\n\n\tsetFromCenterAndSize( center, size ) {\n\n\t\tconst halfSize = _vector$4.copy( size ).multiplyScalar( 0.5 );\n\t\tthis.min.copy( center ).sub( halfSize );\n\t\tthis.max.copy( center ).add( halfSize );\n\n\t\treturn this;\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n\tcopy( box ) {\n\n\t\tthis.min.copy( box.min );\n\t\tthis.max.copy( box.max );\n\n\t\treturn this;\n\n\t}\n\n\tmakeEmpty() {\n\n\t\tthis.min.x = this.min.y = + Infinity;\n\t\tthis.max.x = this.max.y = - Infinity;\n\n\t\treturn this;\n\n\t}\n\n\tisEmpty() {\n\n\t\t// this is a more robust check for empty than ( volume <= 0 ) because volume can get positive with two negative axes\n\n\t\treturn ( this.max.x < this.min.x ) || ( this.max.y < this.min.y );\n\n\t}\n\n\tgetCenter( target ) {\n\n\t\treturn this.isEmpty() ? target.set( 0, 0 ) : target.addVectors( this.min, this.max ).multiplyScalar( 0.5 );\n\n\t}\n\n\tgetSize( target ) {\n\n\t\treturn this.isEmpty() ? target.set( 0, 0 ) : target.subVectors( this.max, this.min );\n\n\t}\n\n\texpandByPoint( point ) {\n\n\t\tthis.min.min( point );\n\t\tthis.max.max( point );\n\n\t\treturn this;\n\n\t}\n\n\texpandByVector( vector ) {\n\n\t\tthis.min.sub( vector );\n\t\tthis.max.add( vector );\n\n\t\treturn this;\n\n\t}\n\n\texpandByScalar( scalar ) {\n\n\t\tthis.min.addScalar( - scalar );\n\t\tthis.max.addScalar( scalar );\n\n\t\treturn this;\n\n\t}\n\n\tcontainsPoint( point ) {\n\n\t\treturn point.x >= this.min.x && point.x <= this.max.x &&\n\t\t\tpoint.y >= this.min.y && point.y <= this.max.y;\n\n\t}\n\n\tcontainsBox( box ) {\n\n\t\treturn this.min.x <= box.min.x && box.max.x <= this.max.x &&\n\t\t\tthis.min.y <= box.min.y && box.max.y <= this.max.y;\n\n\t}\n\n\tgetParameter( point, target ) {\n\n\t\t// This can potentially have a divide by zero if the box\n\t\t// has a size dimension of 0.\n\n\t\treturn target.set(\n\t\t\t( point.x - this.min.x ) / ( this.max.x - this.min.x ),\n\t\t\t( point.y - this.min.y ) / ( this.max.y - this.min.y )\n\t\t);\n\n\t}\n\n\tintersectsBox( box ) {\n\n\t\t// using 4 splitting planes to rule out intersections\n\n\t\treturn box.max.x >= this.min.x && box.min.x <= this.max.x &&\n\t\t\tbox.max.y >= this.min.y && box.min.y <= this.max.y;\n\n\t}\n\n\tclampPoint( point, target ) {\n\n\t\treturn target.copy( point ).clamp( this.min, this.max );\n\n\t}\n\n\tdistanceToPoint( point ) {\n\n\t\treturn this.clampPoint( point, _vector$4 ).distanceTo( point );\n\n\t}\n\n\tintersect( box ) {\n\n\t\tthis.min.max( box.min );\n\t\tthis.max.min( box.max );\n\n\t\tif ( this.isEmpty() ) this.makeEmpty();\n\n\t\treturn this;\n\n\t}\n\n\tunion( box ) {\n\n\t\tthis.min.min( box.min );\n\t\tthis.max.max( box.max );\n\n\t\treturn this;\n\n\t}\n\n\ttranslate( offset ) {\n\n\t\tthis.min.add( offset );\n\t\tthis.max.add( offset );\n\n\t\treturn this;\n\n\t}\n\n\tequals( box ) {\n\n\t\treturn box.min.equals( this.min ) && box.max.equals( this.max );\n\n\t}\n\n}\n\nconst _startP = /*@__PURE__*/ new Vector3();\nconst _startEnd = /*@__PURE__*/ new Vector3();\n\nclass Line3 {\n\n\tconstructor( start = new Vector3(), end = new Vector3() ) {\n\n\t\tthis.start = start;\n\t\tthis.end = end;\n\n\t}\n\n\tset( start, end ) {\n\n\t\tthis.start.copy( start );\n\t\tthis.end.copy( end );\n\n\t\treturn this;\n\n\t}\n\n\tcopy( line ) {\n\n\t\tthis.start.copy( line.start );\n\t\tthis.end.copy( line.end );\n\n\t\treturn this;\n\n\t}\n\n\tgetCenter( target ) {\n\n\t\treturn target.addVectors( this.start, this.end ).multiplyScalar( 0.5 );\n\n\t}\n\n\tdelta( target ) {\n\n\t\treturn target.subVectors( this.end, this.start );\n\n\t}\n\n\tdistanceSq() {\n\n\t\treturn this.start.distanceToSquared( this.end );\n\n\t}\n\n\tdistance() {\n\n\t\treturn this.start.distanceTo( this.end );\n\n\t}\n\n\tat( t, target ) {\n\n\t\treturn this.delta( target ).multiplyScalar( t ).add( this.start );\n\n\t}\n\n\tclosestPointToPointParameter( point, clampToLine ) {\n\n\t\t_startP.subVectors( point, this.start );\n\t\t_startEnd.subVectors( this.end, this.start );\n\n\t\tconst startEnd2 = _startEnd.dot( _startEnd );\n\t\tconst startEnd_startP = _startEnd.dot( _startP );\n\n\t\tlet t = startEnd_startP / startEnd2;\n\n\t\tif ( clampToLine ) {\n\n\t\t\tt = clamp( t, 0, 1 );\n\n\t\t}\n\n\t\treturn t;\n\n\t}\n\n\tclosestPointToPoint( point, clampToLine, target ) {\n\n\t\tconst t = this.closestPointToPointParameter( point, clampToLine );\n\n\t\treturn this.delta( target ).multiplyScalar( t ).add( this.start );\n\n\t}\n\n\tapplyMatrix4( matrix ) {\n\n\t\tthis.start.applyMatrix4( matrix );\n\t\tthis.end.applyMatrix4( matrix );\n\n\t\treturn this;\n\n\t}\n\n\tequals( line ) {\n\n\t\treturn line.start.equals( this.start ) && line.end.equals( this.end );\n\n\t}\n\n\tclone() {\n\n\t\treturn new this.constructor().copy( this );\n\n\t}\n\n}\n\nconst _vector$3 = /*@__PURE__*/ new Vector3();\n\nclass SpotLightHelper extends Object3D {\n\n\tconstructor( light, color ) {\n\n\t\tsuper();\n\n\t\tthis.light = light;\n\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.color = color;\n\n\t\tthis.type = 'SpotLightHelper';\n\n\t\tconst geometry = new BufferGeometry();\n\n\t\tconst positions = [\n\t\t\t0, 0, 0, \t0, 0, 1,\n\t\t\t0, 0, 0, \t1, 0, 1,\n\t\t\t0, 0, 0,\t- 1, 0, 1,\n\t\t\t0, 0, 0, \t0, 1, 1,\n\t\t\t0, 0, 0, \t0, - 1, 1\n\t\t];\n\n\t\tfor ( let i = 0, j = 1, l = 32; i < l; i ++, j ++ ) {\n\n\t\t\tconst p1 = ( i / l ) * Math.PI * 2;\n\t\t\tconst p2 = ( j / l ) * Math.PI * 2;\n\n\t\t\tpositions.push(\n\t\t\t\tMath.cos( p1 ), Math.sin( p1 ), 1,\n\t\t\t\tMath.cos( p2 ), Math.sin( p2 ), 1\n\t\t\t);\n\n\t\t}\n\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { fog: false, toneMapped: false } );\n\n\t\tthis.cone = new LineSegments( geometry, material );\n\t\tthis.add( this.cone );\n\n\t\tthis.update();\n\n\t}\n\n\tdispose() {\n\n\t\tthis.cone.geometry.dispose();\n\t\tthis.cone.material.dispose();\n\n\t}\n\n\tupdate() {\n\n\t\tthis.light.updateWorldMatrix( true, false );\n\t\tthis.light.target.updateWorldMatrix( true, false );\n\n\t\t// update the local matrix based on the parent and light target transforms\n\t\tif ( this.parent ) {\n\n\t\t\tthis.parent.updateWorldMatrix( true );\n\n\t\t\tthis.matrix\n\t\t\t\t.copy( this.parent.matrixWorld )\n\t\t\t\t.invert()\n\t\t\t\t.multiply( this.light.matrixWorld );\n\n\t\t} else {\n\n\t\t\tthis.matrix.copy( this.light.matrixWorld );\n\n\t\t}\n\n\t\tthis.matrixWorld.copy( this.light.matrixWorld );\n\n\t\tconst coneLength = this.light.distance ? this.light.distance : 1000;\n\t\tconst coneWidth = coneLength * Math.tan( this.light.angle );\n\n\t\tthis.cone.scale.set( coneWidth, coneWidth, coneLength );\n\n\t\t_vector$3.setFromMatrixPosition( this.light.target.matrixWorld );\n\n\t\tthis.cone.lookAt( _vector$3 );\n\n\t\tif ( this.color !== undefined ) {\n\n\t\t\tthis.cone.material.color.set( this.color );\n\n\t\t} else {\n\n\t\t\tthis.cone.material.color.copy( this.light.color );\n\n\t\t}\n\n\t}\n\n}\n\nconst _vector$2 = /*@__PURE__*/ new Vector3();\nconst _boneMatrix = /*@__PURE__*/ new Matrix4();\nconst _matrixWorldInv = /*@__PURE__*/ new Matrix4();\n\n\nclass SkeletonHelper extends LineSegments {\n\n\tconstructor( object ) {\n\n\t\tconst bones = getBoneList( object );\n\n\t\tconst geometry = new BufferGeometry();\n\n\t\tconst vertices = [];\n\t\tconst colors = [];\n\n\t\tconst color1 = new Color( 0, 0, 1 );\n\t\tconst color2 = new Color( 0, 1, 0 );\n\n\t\tfor ( let i = 0; i < bones.length; i ++ ) {\n\n\t\t\tconst bone = bones[ i ];\n\n\t\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\t\tvertices.push( 0, 0, 0 );\n\t\t\t\tvertices.push( 0, 0, 0 );\n\t\t\t\tcolors.push( color1.r, color1.g, color1.b );\n\t\t\t\tcolors.push( color2.r, color2.g, color2.b );\n\n\t\t\t}\n\n\t\t}\n\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { vertexColors: true, depthTest: false, depthWrite: false, toneMapped: false, transparent: true } );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.isSkeletonHelper = true;\n\n\t\tthis.type = 'SkeletonHelper';\n\n\t\tthis.root = object;\n\t\tthis.bones = bones;\n\n\t\tthis.matrix = object.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tconst bones = this.bones;\n\n\t\tconst geometry = this.geometry;\n\t\tconst position = geometry.getAttribute( 'position' );\n\n\t\t_matrixWorldInv.copy( this.root.matrixWorld ).invert();\n\n\t\tfor ( let i = 0, j = 0; i < bones.length; i ++ ) {\n\n\t\t\tconst bone = bones[ i ];\n\n\t\t\tif ( bone.parent && bone.parent.isBone ) {\n\n\t\t\t\t_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.matrixWorld );\n\t\t\t\t_vector$2.setFromMatrixPosition( _boneMatrix );\n\t\t\t\tposition.setXYZ( j, _vector$2.x, _vector$2.y, _vector$2.z );\n\n\t\t\t\t_boneMatrix.multiplyMatrices( _matrixWorldInv, bone.parent.matrixWorld );\n\t\t\t\t_vector$2.setFromMatrixPosition( _boneMatrix );\n\t\t\t\tposition.setXYZ( j + 1, _vector$2.x, _vector$2.y, _vector$2.z );\n\n\t\t\t\tj += 2;\n\n\t\t\t}\n\n\t\t}\n\n\t\tgeometry.getAttribute( 'position' ).needsUpdate = true;\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\n\nfunction getBoneList( object ) {\n\n\tconst boneList = [];\n\n\tif ( object.isBone === true ) {\n\n\t\tboneList.push( object );\n\n\t}\n\n\tfor ( let i = 0; i < object.children.length; i ++ ) {\n\n\t\tboneList.push.apply( boneList, getBoneList( object.children[ i ] ) );\n\n\t}\n\n\treturn boneList;\n\n}\n\nclass PointLightHelper extends Mesh {\n\n\tconstructor( light, sphereSize, color ) {\n\n\t\tconst geometry = new SphereGeometry( sphereSize, 4, 2 );\n\t\tconst material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.light = light;\n\n\t\tthis.color = color;\n\n\t\tthis.type = 'PointLightHelper';\n\n\t\tthis.matrix = this.light.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.update();\n\n\n\t\t/*\n\t// TODO: delete this comment?\n\tconst distanceGeometry = new THREE.IcosahedronGeometry( 1, 2 );\n\tconst distanceMaterial = new THREE.MeshBasicMaterial( { color: hexColor, fog: false, wireframe: true, opacity: 0.1, transparent: true } );\n\n\tthis.lightSphere = new THREE.Mesh( bulbGeometry, bulbMaterial );\n\tthis.lightDistance = new THREE.Mesh( distanceGeometry, distanceMaterial );\n\n\tconst d = light.distance;\n\n\tif ( d === 0.0 ) {\n\n\t\tthis.lightDistance.visible = false;\n\n\t} else {\n\n\t\tthis.lightDistance.scale.set( d, d, d );\n\n\t}\n\n\tthis.add( this.lightDistance );\n\t*/\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n\tupdate() {\n\n\t\tthis.light.updateWorldMatrix( true, false );\n\n\t\tif ( this.color !== undefined ) {\n\n\t\t\tthis.material.color.set( this.color );\n\n\t\t} else {\n\n\t\t\tthis.material.color.copy( this.light.color );\n\n\t\t}\n\n\t\t/*\n\t\tconst d = this.light.distance;\n\n\t\tif ( d === 0.0 ) {\n\n\t\t\tthis.lightDistance.visible = false;\n\n\t\t} else {\n\n\t\t\tthis.lightDistance.visible = true;\n\t\t\tthis.lightDistance.scale.set( d, d, d );\n\n\t\t}\n\t\t*/\n\n\t}\n\n}\n\nconst _vector$1 = /*@__PURE__*/ new Vector3();\nconst _color1 = /*@__PURE__*/ new Color();\nconst _color2 = /*@__PURE__*/ new Color();\n\nclass HemisphereLightHelper extends Object3D {\n\n\tconstructor( light, size, color ) {\n\n\t\tsuper();\n\n\t\tthis.light = light;\n\n\t\tthis.matrix = light.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.color = color;\n\n\t\tthis.type = 'HemisphereLightHelper';\n\n\t\tconst geometry = new OctahedronGeometry( size );\n\t\tgeometry.rotateY( Math.PI * 0.5 );\n\n\t\tthis.material = new MeshBasicMaterial( { wireframe: true, fog: false, toneMapped: false } );\n\t\tif ( this.color === undefined ) this.material.vertexColors = true;\n\n\t\tconst position = geometry.getAttribute( 'position' );\n\t\tconst colors = new Float32Array( position.count * 3 );\n\n\t\tgeometry.setAttribute( 'color', new BufferAttribute( colors, 3 ) );\n\n\t\tthis.add( new Mesh( geometry, this.material ) );\n\n\t\tthis.update();\n\n\t}\n\n\tdispose() {\n\n\t\tthis.children[ 0 ].geometry.dispose();\n\t\tthis.children[ 0 ].material.dispose();\n\n\t}\n\n\tupdate() {\n\n\t\tconst mesh = this.children[ 0 ];\n\n\t\tif ( this.color !== undefined ) {\n\n\t\t\tthis.material.color.set( this.color );\n\n\t\t} else {\n\n\t\t\tconst colors = mesh.geometry.getAttribute( 'color' );\n\n\t\t\t_color1.copy( this.light.color );\n\t\t\t_color2.copy( this.light.groundColor );\n\n\t\t\tfor ( let i = 0, l = colors.count; i < l; i ++ ) {\n\n\t\t\t\tconst color = ( i < ( l / 2 ) ) ? _color1 : _color2;\n\n\t\t\t\tcolors.setXYZ( i, color.r, color.g, color.b );\n\n\t\t\t}\n\n\t\t\tcolors.needsUpdate = true;\n\n\t\t}\n\n\t\tthis.light.updateWorldMatrix( true, false );\n\n\t\tmesh.lookAt( _vector$1.setFromMatrixPosition( this.light.matrixWorld ).negate() );\n\n\t}\n\n}\n\nclass GridHelper extends LineSegments {\n\n\tconstructor( size = 10, divisions = 10, color1 = 0x444444, color2 = 0x888888 ) {\n\n\t\tcolor1 = new Color( color1 );\n\t\tcolor2 = new Color( color2 );\n\n\t\tconst center = divisions / 2;\n\t\tconst step = size / divisions;\n\t\tconst halfSize = size / 2;\n\n\t\tconst vertices = [], colors = [];\n\n\t\tfor ( let i = 0, j = 0, k = - halfSize; i <= divisions; i ++, k += step ) {\n\n\t\t\tvertices.push( - halfSize, 0, k, halfSize, 0, k );\n\t\t\tvertices.push( k, 0, - halfSize, k, 0, halfSize );\n\n\t\t\tconst color = i === center ? color1 : color2;\n\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\t\t\tcolor.toArray( colors, j ); j += 3;\n\n\t\t}\n\n\t\tconst geometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.type = 'GridHelper';\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\nclass PolarGridHelper extends LineSegments {\n\n\tconstructor( radius = 10, sectors = 16, rings = 8, divisions = 64, color1 = 0x444444, color2 = 0x888888 ) {\n\n\t\tcolor1 = new Color( color1 );\n\t\tcolor2 = new Color( color2 );\n\n\t\tconst vertices = [];\n\t\tconst colors = [];\n\n\t\t// create the sectors\n\n\t\tif ( sectors > 1 ) {\n\n\t\t\tfor ( let i = 0; i < sectors; i ++ ) {\n\n\t\t\t\tconst v = ( i / sectors ) * ( Math.PI * 2 );\n\n\t\t\t\tconst x = Math.sin( v ) * radius;\n\t\t\t\tconst z = Math.cos( v ) * radius;\n\n\t\t\t\tvertices.push( 0, 0, 0 );\n\t\t\t\tvertices.push( x, 0, z );\n\n\t\t\t\tconst color = ( i & 1 ) ? color1 : color2;\n\n\t\t\t\tcolors.push( color.r, color.g, color.b );\n\t\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t\t}\n\n\t\t}\n\n\t\t// create the rings\n\n\t\tfor ( let i = 0; i < rings; i ++ ) {\n\n\t\t\tconst color = ( i & 1 ) ? color1 : color2;\n\n\t\t\tconst r = radius - ( radius / rings * i );\n\n\t\t\tfor ( let j = 0; j < divisions; j ++ ) {\n\n\t\t\t\t// first vertex\n\n\t\t\t\tlet v = ( j / divisions ) * ( Math.PI * 2 );\n\n\t\t\t\tlet x = Math.sin( v ) * r;\n\t\t\t\tlet z = Math.cos( v ) * r;\n\n\t\t\t\tvertices.push( x, 0, z );\n\t\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t\t\t// second vertex\n\n\t\t\t\tv = ( ( j + 1 ) / divisions ) * ( Math.PI * 2 );\n\n\t\t\t\tx = Math.sin( v ) * r;\n\t\t\t\tz = Math.cos( v ) * r;\n\n\t\t\t\tvertices.push( x, 0, z );\n\t\t\t\tcolors.push( color.r, color.g, color.b );\n\n\t\t\t}\n\n\t\t}\n\n\t\tconst geometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.type = 'PolarGridHelper';\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\nconst _v1 = /*@__PURE__*/ new Vector3();\nconst _v2 = /*@__PURE__*/ new Vector3();\nconst _v3 = /*@__PURE__*/ new Vector3();\n\nclass DirectionalLightHelper extends Object3D {\n\n\tconstructor( light, size, color ) {\n\n\t\tsuper();\n\n\t\tthis.light = light;\n\n\t\tthis.matrix = light.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.color = color;\n\n\t\tthis.type = 'DirectionalLightHelper';\n\n\t\tif ( size === undefined ) size = 1;\n\n\t\tlet geometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( [\n\t\t\t- size, size, 0,\n\t\t\tsize, size, 0,\n\t\t\tsize, - size, 0,\n\t\t\t- size, - size, 0,\n\t\t\t- size, size, 0\n\t\t], 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { fog: false, toneMapped: false } );\n\n\t\tthis.lightPlane = new Line( geometry, material );\n\t\tthis.add( this.lightPlane );\n\n\t\tgeometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 0, 1 ], 3 ) );\n\n\t\tthis.targetLine = new Line( geometry, material );\n\t\tthis.add( this.targetLine );\n\n\t\tthis.update();\n\n\t}\n\n\tdispose() {\n\n\t\tthis.lightPlane.geometry.dispose();\n\t\tthis.lightPlane.material.dispose();\n\t\tthis.targetLine.geometry.dispose();\n\t\tthis.targetLine.material.dispose();\n\n\t}\n\n\tupdate() {\n\n\t\tthis.light.updateWorldMatrix( true, false );\n\t\tthis.light.target.updateWorldMatrix( true, false );\n\n\t\t_v1.setFromMatrixPosition( this.light.matrixWorld );\n\t\t_v2.setFromMatrixPosition( this.light.target.matrixWorld );\n\t\t_v3.subVectors( _v2, _v1 );\n\n\t\tthis.lightPlane.lookAt( _v2 );\n\n\t\tif ( this.color !== undefined ) {\n\n\t\t\tthis.lightPlane.material.color.set( this.color );\n\t\t\tthis.targetLine.material.color.set( this.color );\n\n\t\t} else {\n\n\t\t\tthis.lightPlane.material.color.copy( this.light.color );\n\t\t\tthis.targetLine.material.color.copy( this.light.color );\n\n\t\t}\n\n\t\tthis.targetLine.lookAt( _v2 );\n\t\tthis.targetLine.scale.z = _v3.length();\n\n\t}\n\n}\n\nconst _vector = /*@__PURE__*/ new Vector3();\nconst _camera = /*@__PURE__*/ new Camera();\n\n/**\n *\t- shows frustum, line of sight and up of the camera\n *\t- suitable for fast updates\n * \t- based on frustum visualization in lightgl.js shadowmap example\n *\t\thttps://github.com/evanw/lightgl.js/blob/master/tests/shadowmap.html\n */\n\nclass CameraHelper extends LineSegments {\n\n\tconstructor( camera ) {\n\n\t\tconst geometry = new BufferGeometry();\n\t\tconst material = new LineBasicMaterial( { color: 0xffffff, vertexColors: true, toneMapped: false } );\n\n\t\tconst vertices = [];\n\t\tconst colors = [];\n\n\t\tconst pointMap = {};\n\n\t\t// near\n\n\t\taddLine( 'n1', 'n2' );\n\t\taddLine( 'n2', 'n4' );\n\t\taddLine( 'n4', 'n3' );\n\t\taddLine( 'n3', 'n1' );\n\n\t\t// far\n\n\t\taddLine( 'f1', 'f2' );\n\t\taddLine( 'f2', 'f4' );\n\t\taddLine( 'f4', 'f3' );\n\t\taddLine( 'f3', 'f1' );\n\n\t\t// sides\n\n\t\taddLine( 'n1', 'f1' );\n\t\taddLine( 'n2', 'f2' );\n\t\taddLine( 'n3', 'f3' );\n\t\taddLine( 'n4', 'f4' );\n\n\t\t// cone\n\n\t\taddLine( 'p', 'n1' );\n\t\taddLine( 'p', 'n2' );\n\t\taddLine( 'p', 'n3' );\n\t\taddLine( 'p', 'n4' );\n\n\t\t// up\n\n\t\taddLine( 'u1', 'u2' );\n\t\taddLine( 'u2', 'u3' );\n\t\taddLine( 'u3', 'u1' );\n\n\t\t// target\n\n\t\taddLine( 'c', 't' );\n\t\taddLine( 'p', 'c' );\n\n\t\t// cross\n\n\t\taddLine( 'cn1', 'cn2' );\n\t\taddLine( 'cn3', 'cn4' );\n\n\t\taddLine( 'cf1', 'cf2' );\n\t\taddLine( 'cf3', 'cf4' );\n\n\t\tfunction addLine( a, b ) {\n\n\t\t\taddPoint( a );\n\t\t\taddPoint( b );\n\n\t\t}\n\n\t\tfunction addPoint( id ) {\n\n\t\t\tvertices.push( 0, 0, 0 );\n\t\t\tcolors.push( 0, 0, 0 );\n\n\t\t\tif ( pointMap[ id ] === undefined ) {\n\n\t\t\t\tpointMap[ id ] = [];\n\n\t\t\t}\n\n\t\t\tpointMap[ id ].push( ( vertices.length / 3 ) - 1 );\n\n\t\t}\n\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.type = 'CameraHelper';\n\n\t\tthis.camera = camera;\n\t\tif ( this.camera.updateProjectionMatrix ) this.camera.updateProjectionMatrix();\n\n\t\tthis.matrix = camera.matrixWorld;\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.pointMap = pointMap;\n\n\t\tthis.update();\n\n\t\t// colors\n\n\t\tconst colorFrustum = new Color( 0xffaa00 );\n\t\tconst colorCone = new Color( 0xff0000 );\n\t\tconst colorUp = new Color( 0x00aaff );\n\t\tconst colorTarget = new Color( 0xffffff );\n\t\tconst colorCross = new Color( 0x333333 );\n\n\t\tthis.setColors( colorFrustum, colorCone, colorUp, colorTarget, colorCross );\n\n\t}\n\n\tsetColors( frustum, cone, up, target, cross ) {\n\n\t\tconst geometry = this.geometry;\n\n\t\tconst colorAttribute = geometry.getAttribute( 'color' );\n\n\t\t// near\n\n\t\tcolorAttribute.setXYZ( 0, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 1, frustum.r, frustum.g, frustum.b ); // n1, n2\n\t\tcolorAttribute.setXYZ( 2, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 3, frustum.r, frustum.g, frustum.b ); // n2, n4\n\t\tcolorAttribute.setXYZ( 4, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 5, frustum.r, frustum.g, frustum.b ); // n4, n3\n\t\tcolorAttribute.setXYZ( 6, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 7, frustum.r, frustum.g, frustum.b ); // n3, n1\n\n\t\t// far\n\n\t\tcolorAttribute.setXYZ( 8, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 9, frustum.r, frustum.g, frustum.b ); // f1, f2\n\t\tcolorAttribute.setXYZ( 10, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 11, frustum.r, frustum.g, frustum.b ); // f2, f4\n\t\tcolorAttribute.setXYZ( 12, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 13, frustum.r, frustum.g, frustum.b ); // f4, f3\n\t\tcolorAttribute.setXYZ( 14, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 15, frustum.r, frustum.g, frustum.b ); // f3, f1\n\n\t\t// sides\n\n\t\tcolorAttribute.setXYZ( 16, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 17, frustum.r, frustum.g, frustum.b ); // n1, f1\n\t\tcolorAttribute.setXYZ( 18, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 19, frustum.r, frustum.g, frustum.b ); // n2, f2\n\t\tcolorAttribute.setXYZ( 20, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 21, frustum.r, frustum.g, frustum.b ); // n3, f3\n\t\tcolorAttribute.setXYZ( 22, frustum.r, frustum.g, frustum.b ); colorAttribute.setXYZ( 23, frustum.r, frustum.g, frustum.b ); // n4, f4\n\n\t\t// cone\n\n\t\tcolorAttribute.setXYZ( 24, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 25, cone.r, cone.g, cone.b ); // p, n1\n\t\tcolorAttribute.setXYZ( 26, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 27, cone.r, cone.g, cone.b ); // p, n2\n\t\tcolorAttribute.setXYZ( 28, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 29, cone.r, cone.g, cone.b ); // p, n3\n\t\tcolorAttribute.setXYZ( 30, cone.r, cone.g, cone.b ); colorAttribute.setXYZ( 31, cone.r, cone.g, cone.b ); // p, n4\n\n\t\t// up\n\n\t\tcolorAttribute.setXYZ( 32, up.r, up.g, up.b ); colorAttribute.setXYZ( 33, up.r, up.g, up.b ); // u1, u2\n\t\tcolorAttribute.setXYZ( 34, up.r, up.g, up.b ); colorAttribute.setXYZ( 35, up.r, up.g, up.b ); // u2, u3\n\t\tcolorAttribute.setXYZ( 36, up.r, up.g, up.b ); colorAttribute.setXYZ( 37, up.r, up.g, up.b ); // u3, u1\n\n\t\t// target\n\n\t\tcolorAttribute.setXYZ( 38, target.r, target.g, target.b ); colorAttribute.setXYZ( 39, target.r, target.g, target.b ); // c, t\n\t\tcolorAttribute.setXYZ( 40, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 41, cross.r, cross.g, cross.b ); // p, c\n\n\t\t// cross\n\n\t\tcolorAttribute.setXYZ( 42, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 43, cross.r, cross.g, cross.b ); // cn1, cn2\n\t\tcolorAttribute.setXYZ( 44, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 45, cross.r, cross.g, cross.b ); // cn3, cn4\n\n\t\tcolorAttribute.setXYZ( 46, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 47, cross.r, cross.g, cross.b ); // cf1, cf2\n\t\tcolorAttribute.setXYZ( 48, cross.r, cross.g, cross.b ); colorAttribute.setXYZ( 49, cross.r, cross.g, cross.b ); // cf3, cf4\n\n\t\tcolorAttribute.needsUpdate = true;\n\n\t}\n\n\tupdate() {\n\n\t\tconst geometry = this.geometry;\n\t\tconst pointMap = this.pointMap;\n\n\t\tconst w = 1, h = 1;\n\n\t\t// we need just camera projection matrix inverse\n\t\t// world matrix must be identity\n\n\t\t_camera.projectionMatrixInverse.copy( this.camera.projectionMatrixInverse );\n\n\t\t// center / target\n\n\t\tsetPoint( 'c', pointMap, geometry, _camera, 0, 0, - 1 );\n\t\tsetPoint( 't', pointMap, geometry, _camera, 0, 0, 1 );\n\n\t\t// near\n\n\t\tsetPoint( 'n1', pointMap, geometry, _camera, - w, - h, - 1 );\n\t\tsetPoint( 'n2', pointMap, geometry, _camera, w, - h, - 1 );\n\t\tsetPoint( 'n3', pointMap, geometry, _camera, - w, h, - 1 );\n\t\tsetPoint( 'n4', pointMap, geometry, _camera, w, h, - 1 );\n\n\t\t// far\n\n\t\tsetPoint( 'f1', pointMap, geometry, _camera, - w, - h, 1 );\n\t\tsetPoint( 'f2', pointMap, geometry, _camera, w, - h, 1 );\n\t\tsetPoint( 'f3', pointMap, geometry, _camera, - w, h, 1 );\n\t\tsetPoint( 'f4', pointMap, geometry, _camera, w, h, 1 );\n\n\t\t// up\n\n\t\tsetPoint( 'u1', pointMap, geometry, _camera, w * 0.7, h * 1.1, - 1 );\n\t\tsetPoint( 'u2', pointMap, geometry, _camera, - w * 0.7, h * 1.1, - 1 );\n\t\tsetPoint( 'u3', pointMap, geometry, _camera, 0, h * 2, - 1 );\n\n\t\t// cross\n\n\t\tsetPoint( 'cf1', pointMap, geometry, _camera, - w, 0, 1 );\n\t\tsetPoint( 'cf2', pointMap, geometry, _camera, w, 0, 1 );\n\t\tsetPoint( 'cf3', pointMap, geometry, _camera, 0, - h, 1 );\n\t\tsetPoint( 'cf4', pointMap, geometry, _camera, 0, h, 1 );\n\n\t\tsetPoint( 'cn1', pointMap, geometry, _camera, - w, 0, - 1 );\n\t\tsetPoint( 'cn2', pointMap, geometry, _camera, w, 0, - 1 );\n\t\tsetPoint( 'cn3', pointMap, geometry, _camera, 0, - h, - 1 );\n\t\tsetPoint( 'cn4', pointMap, geometry, _camera, 0, h, - 1 );\n\n\t\tgeometry.getAttribute( 'position' ).needsUpdate = true;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\n\nfunction setPoint( point, pointMap, geometry, camera, x, y, z ) {\n\n\t_vector.set( x, y, z ).unproject( camera );\n\n\tconst points = pointMap[ point ];\n\n\tif ( points !== undefined ) {\n\n\t\tconst position = geometry.getAttribute( 'position' );\n\n\t\tfor ( let i = 0, l = points.length; i < l; i ++ ) {\n\n\t\t\tposition.setXYZ( points[ i ], _vector.x, _vector.y, _vector.z );\n\n\t\t}\n\n\t}\n\n}\n\nconst _box = /*@__PURE__*/ new Box3();\n\nclass BoxHelper extends LineSegments {\n\n\tconstructor( object, color = 0xffff00 ) {\n\n\t\tconst 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 ] );\n\t\tconst positions = new Float32Array( 8 * 3 );\n\n\t\tconst geometry = new BufferGeometry();\n\t\tgeometry.setIndex( new BufferAttribute( indices, 1 ) );\n\t\tgeometry.setAttribute( 'position', new BufferAttribute( positions, 3 ) );\n\n\t\tsuper( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );\n\n\t\tthis.object = object;\n\t\tthis.type = 'BoxHelper';\n\n\t\tthis.matrixAutoUpdate = false;\n\n\t\tthis.update();\n\n\t}\n\n\tupdate( object ) {\n\n\t\tif ( object !== undefined ) {\n\n\t\t\tconsole.warn( 'THREE.BoxHelper: .update() has no longer arguments.' );\n\n\t\t}\n\n\t\tif ( this.object !== undefined ) {\n\n\t\t\t_box.setFromObject( this.object );\n\n\t\t}\n\n\t\tif ( _box.isEmpty() ) return;\n\n\t\tconst min = _box.min;\n\t\tconst max = _box.max;\n\n\t\t/*\n\t\t\t5____4\n\t\t1/___0/|\n\t\t| 6__|_7\n\t\t2/___3/\n\n\t\t0: max.x, max.y, max.z\n\t\t1: min.x, max.y, max.z\n\t\t2: min.x, min.y, max.z\n\t\t3: max.x, min.y, max.z\n\t\t4: max.x, max.y, min.z\n\t\t5: min.x, max.y, min.z\n\t\t6: min.x, min.y, min.z\n\t\t7: max.x, min.y, min.z\n\t\t*/\n\n\t\tconst position = this.geometry.attributes.position;\n\t\tconst array = position.array;\n\n\t\tarray[ 0 ] = max.x; array[ 1 ] = max.y; array[ 2 ] = max.z;\n\t\tarray[ 3 ] = min.x; array[ 4 ] = max.y; array[ 5 ] = max.z;\n\t\tarray[ 6 ] = min.x; array[ 7 ] = min.y; array[ 8 ] = max.z;\n\t\tarray[ 9 ] = max.x; array[ 10 ] = min.y; array[ 11 ] = max.z;\n\t\tarray[ 12 ] = max.x; array[ 13 ] = max.y; array[ 14 ] = min.z;\n\t\tarray[ 15 ] = min.x; array[ 16 ] = max.y; array[ 17 ] = min.z;\n\t\tarray[ 18 ] = min.x; array[ 19 ] = min.y; array[ 20 ] = min.z;\n\t\tarray[ 21 ] = max.x; array[ 22 ] = min.y; array[ 23 ] = min.z;\n\n\t\tposition.needsUpdate = true;\n\n\t\tthis.geometry.computeBoundingSphere();\n\n\t}\n\n\tsetFromObject( object ) {\n\n\t\tthis.object = object;\n\t\tthis.update();\n\n\t\treturn this;\n\n\t}\n\n\tcopy( source, recursive ) {\n\n\t\tsuper.copy( source, recursive );\n\n\t\tthis.object = source.object;\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\nclass Box3Helper extends LineSegments {\n\n\tconstructor( box, color = 0xffff00 ) {\n\n\t\tconst 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 ] );\n\n\t\tconst 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 ];\n\n\t\tconst geometry = new BufferGeometry();\n\n\t\tgeometry.setIndex( new BufferAttribute( indices, 1 ) );\n\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );\n\n\t\tsuper( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );\n\n\t\tthis.box = box;\n\n\t\tthis.type = 'Box3Helper';\n\n\t\tthis.geometry.computeBoundingSphere();\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tconst box = this.box;\n\n\t\tif ( box.isEmpty() ) return;\n\n\t\tbox.getCenter( this.position );\n\n\t\tbox.getSize( this.scale );\n\n\t\tthis.scale.multiplyScalar( 0.5 );\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\nclass PlaneHelper extends Line {\n\n\tconstructor( plane, size = 1, hex = 0xffff00 ) {\n\n\t\tconst color = hex;\n\n\t\tconst 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 ];\n\n\t\tconst geometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( positions, 3 ) );\n\t\tgeometry.computeBoundingSphere();\n\n\t\tsuper( geometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );\n\n\t\tthis.type = 'PlaneHelper';\n\n\t\tthis.plane = plane;\n\n\t\tthis.size = size;\n\n\t\tconst positions2 = [ 1, 1, 0, - 1, 1, 0, - 1, - 1, 0, 1, 1, 0, - 1, - 1, 0, 1, - 1, 0 ];\n\n\t\tconst geometry2 = new BufferGeometry();\n\t\tgeometry2.setAttribute( 'position', new Float32BufferAttribute( positions2, 3 ) );\n\t\tgeometry2.computeBoundingSphere();\n\n\t\tthis.add( new Mesh( geometry2, new MeshBasicMaterial( { color: color, opacity: 0.2, transparent: true, depthWrite: false, toneMapped: false } ) ) );\n\n\t}\n\n\tupdateMatrixWorld( force ) {\n\n\t\tthis.position.set( 0, 0, 0 );\n\n\t\tthis.scale.set( 0.5 * this.size, 0.5 * this.size, 1 );\n\n\t\tthis.lookAt( this.plane.normal );\n\n\t\tthis.translateZ( - this.plane.constant );\n\n\t\tsuper.updateMatrixWorld( force );\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\t\tthis.children[ 0 ].geometry.dispose();\n\t\tthis.children[ 0 ].material.dispose();\n\n\t}\n\n}\n\nconst _axis = /*@__PURE__*/ new Vector3();\nlet _lineGeometry, _coneGeometry;\n\nclass ArrowHelper extends Object3D {\n\n\t// dir is assumed to be normalized\n\n\tconstructor( dir = new Vector3( 0, 0, 1 ), origin = new Vector3( 0, 0, 0 ), length = 1, color = 0xffff00, headLength = length * 0.2, headWidth = headLength * 0.2 ) {\n\n\t\tsuper();\n\n\t\tthis.type = 'ArrowHelper';\n\n\t\tif ( _lineGeometry === undefined ) {\n\n\t\t\t_lineGeometry = new BufferGeometry();\n\t\t\t_lineGeometry.setAttribute( 'position', new Float32BufferAttribute( [ 0, 0, 0, 0, 1, 0 ], 3 ) );\n\n\t\t\t_coneGeometry = new CylinderGeometry( 0, 0.5, 1, 5, 1 );\n\t\t\t_coneGeometry.translate( 0, - 0.5, 0 );\n\n\t\t}\n\n\t\tthis.position.copy( origin );\n\n\t\tthis.line = new Line( _lineGeometry, new LineBasicMaterial( { color: color, toneMapped: false } ) );\n\t\tthis.line.matrixAutoUpdate = false;\n\t\tthis.add( this.line );\n\n\t\tthis.cone = new Mesh( _coneGeometry, new MeshBasicMaterial( { color: color, toneMapped: false } ) );\n\t\tthis.cone.matrixAutoUpdate = false;\n\t\tthis.add( this.cone );\n\n\t\tthis.setDirection( dir );\n\t\tthis.setLength( length, headLength, headWidth );\n\n\t}\n\n\tsetDirection( dir ) {\n\n\t\t// dir is assumed to be normalized\n\n\t\tif ( dir.y > 0.99999 ) {\n\n\t\t\tthis.quaternion.set( 0, 0, 0, 1 );\n\n\t\t} else if ( dir.y < - 0.99999 ) {\n\n\t\t\tthis.quaternion.set( 1, 0, 0, 0 );\n\n\t\t} else {\n\n\t\t\t_axis.set( dir.z, 0, - dir.x ).normalize();\n\n\t\t\tconst radians = Math.acos( dir.y );\n\n\t\t\tthis.quaternion.setFromAxisAngle( _axis, radians );\n\n\t\t}\n\n\t}\n\n\tsetLength( length, headLength = length * 0.2, headWidth = headLength * 0.2 ) {\n\n\t\tthis.line.scale.set( 1, Math.max( 0.0001, length - headLength ), 1 ); // see #17458\n\t\tthis.line.updateMatrix();\n\n\t\tthis.cone.scale.set( headWidth, headLength, headWidth );\n\t\tthis.cone.position.y = length;\n\t\tthis.cone.updateMatrix();\n\n\t}\n\n\tsetColor( color ) {\n\n\t\tthis.line.material.color.set( color );\n\t\tthis.cone.material.color.set( color );\n\n\t}\n\n\tcopy( source ) {\n\n\t\tsuper.copy( source, false );\n\n\t\tthis.line.copy( source.line );\n\t\tthis.cone.copy( source.cone );\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.line.geometry.dispose();\n\t\tthis.line.material.dispose();\n\t\tthis.cone.geometry.dispose();\n\t\tthis.cone.material.dispose();\n\n\t}\n\n}\n\nclass AxesHelper extends LineSegments {\n\n\tconstructor( size = 1 ) {\n\n\t\tconst vertices = [\n\t\t\t0, 0, 0,\tsize, 0, 0,\n\t\t\t0, 0, 0,\t0, size, 0,\n\t\t\t0, 0, 0,\t0, 0, size\n\t\t];\n\n\t\tconst colors = [\n\t\t\t1, 0, 0,\t1, 0.6, 0,\n\t\t\t0, 1, 0,\t0.6, 1, 0,\n\t\t\t0, 0, 1,\t0, 0.6, 1\n\t\t];\n\n\t\tconst geometry = new BufferGeometry();\n\t\tgeometry.setAttribute( 'position', new Float32BufferAttribute( vertices, 3 ) );\n\t\tgeometry.setAttribute( 'color', new Float32BufferAttribute( colors, 3 ) );\n\n\t\tconst material = new LineBasicMaterial( { vertexColors: true, toneMapped: false } );\n\n\t\tsuper( geometry, material );\n\n\t\tthis.type = 'AxesHelper';\n\n\t}\n\n\tsetColors( xAxisColor, yAxisColor, zAxisColor ) {\n\n\t\tconst color = new Color();\n\t\tconst array = this.geometry.attributes.color.array;\n\n\t\tcolor.set( xAxisColor );\n\t\tcolor.toArray( array, 0 );\n\t\tcolor.toArray( array, 3 );\n\n\t\tcolor.set( yAxisColor );\n\t\tcolor.toArray( array, 6 );\n\t\tcolor.toArray( array, 9 );\n\n\t\tcolor.set( zAxisColor );\n\t\tcolor.toArray( array, 12 );\n\t\tcolor.toArray( array, 15 );\n\n\t\tthis.geometry.attributes.color.needsUpdate = true;\n\n\t\treturn this;\n\n\t}\n\n\tdispose() {\n\n\t\tthis.geometry.dispose();\n\t\tthis.material.dispose();\n\n\t}\n\n}\n\nclass ShapePath {\n\n\tconstructor() {\n\n\t\tthis.type = 'ShapePath';\n\n\t\tthis.color = new Color();\n\n\t\tthis.subPaths = [];\n\t\tthis.currentPath = null;\n\n\t}\n\n\tmoveTo( x, y ) {\n\n\t\tthis.currentPath = new Path();\n\t\tthis.subPaths.push( this.currentPath );\n\t\tthis.currentPath.moveTo( x, y );\n\n\t\treturn this;\n\n\t}\n\n\tlineTo( x, y ) {\n\n\t\tthis.currentPath.lineTo( x, y );\n\n\t\treturn this;\n\n\t}\n\n\tquadraticCurveTo( aCPx, aCPy, aX, aY ) {\n\n\t\tthis.currentPath.quadraticCurveTo( aCPx, aCPy, aX, aY );\n\n\t\treturn this;\n\n\t}\n\n\tbezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY ) {\n\n\t\tthis.currentPath.bezierCurveTo( aCP1x, aCP1y, aCP2x, aCP2y, aX, aY );\n\n\t\treturn this;\n\n\t}\n\n\tsplineThru( pts ) {\n\n\t\tthis.currentPath.splineThru( pts );\n\n\t\treturn this;\n\n\t}\n\n\ttoShapes( isCCW ) {\n\n\t\tfunction toShapesNoHoles( inSubpaths ) {\n\n\t\t\tconst shapes = [];\n\n\t\t\tfor ( let i = 0, l = inSubpaths.length; i < l; i ++ ) {\n\n\t\t\t\tconst tmpPath = inSubpaths[ i ];\n\n\t\t\t\tconst tmpShape = new Shape();\n\t\t\t\ttmpShape.curves = tmpPath.curves;\n\n\t\t\t\tshapes.push( tmpShape );\n\n\t\t\t}\n\n\t\t\treturn shapes;\n\n\t\t}\n\n\t\tfunction isPointInsidePolygon( inPt, inPolygon ) {\n\n\t\t\tconst polyLen = inPolygon.length;\n\n\t\t\t// inPt on polygon contour => immediate success or\n\t\t\t// toggling of inside/outside at every single! intersection point of an edge\n\t\t\t// with the horizontal line through inPt, left of inPt\n\t\t\t// not counting lowerY endpoints of edges and whole edges on that line\n\t\t\tlet inside = false;\n\t\t\tfor ( let p = polyLen - 1, q = 0; q < polyLen; p = q ++ ) {\n\n\t\t\t\tlet edgeLowPt = inPolygon[ p ];\n\t\t\t\tlet edgeHighPt = inPolygon[ q ];\n\n\t\t\t\tlet edgeDx = edgeHighPt.x - edgeLowPt.x;\n\t\t\t\tlet edgeDy = edgeHighPt.y - edgeLowPt.y;\n\n\t\t\t\tif ( Math.abs( edgeDy ) > Number.EPSILON ) {\n\n\t\t\t\t\t// not parallel\n\t\t\t\t\tif ( edgeDy < 0 ) {\n\n\t\t\t\t\t\tedgeLowPt = inPolygon[ q ]; edgeDx = - edgeDx;\n\t\t\t\t\t\tedgeHighPt = inPolygon[ p ]; edgeDy = - edgeDy;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( ( inPt.y < edgeLowPt.y ) || ( inPt.y > edgeHighPt.y ) ) \t\tcontinue;\n\n\t\t\t\t\tif ( inPt.y === edgeLowPt.y ) {\n\n\t\t\t\t\t\tif ( inPt.x === edgeLowPt.x )\t\treturn\ttrue;\t\t// inPt is on contour ?\n\t\t\t\t\t\t// continue;\t\t\t\t// no intersection or edgeLowPt => doesn't count !!!\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconst perpEdge = edgeDy * ( inPt.x - edgeLowPt.x ) - edgeDx * ( inPt.y - edgeLowPt.y );\n\t\t\t\t\t\tif ( perpEdge === 0 )\t\t\t\treturn\ttrue;\t\t// inPt is on contour ?\n\t\t\t\t\t\tif ( perpEdge < 0 ) \t\t\t\tcontinue;\n\t\t\t\t\t\tinside = ! inside;\t\t// true intersection left of inPt\n\n\t\t\t\t\t}\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// parallel or collinear\n\t\t\t\t\tif ( inPt.y !== edgeLowPt.y ) \t\tcontinue;\t\t\t// parallel\n\t\t\t\t\t// edge lies on the same horizontal line as inPt\n\t\t\t\t\tif ( ( ( edgeHighPt.x <= inPt.x ) && ( inPt.x <= edgeLowPt.x ) ) ||\n\t\t\t\t\t\t ( ( edgeLowPt.x <= inPt.x ) && ( inPt.x <= edgeHighPt.x ) ) )\t\treturn\ttrue;\t// inPt: Point on contour !\n\t\t\t\t\t// continue;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\treturn\tinside;\n\n\t\t}\n\n\t\tconst isClockWise = ShapeUtils.isClockWise;\n\n\t\tconst subPaths = this.subPaths;\n\t\tif ( subPaths.length === 0 ) return [];\n\n\t\tlet solid, tmpPath, tmpShape;\n\t\tconst shapes = [];\n\n\t\tif ( subPaths.length === 1 ) {\n\n\t\t\ttmpPath = subPaths[ 0 ];\n\t\t\ttmpShape = new Shape();\n\t\t\ttmpShape.curves = tmpPath.curves;\n\t\t\tshapes.push( tmpShape );\n\t\t\treturn shapes;\n\n\t\t}\n\n\t\tlet holesFirst = ! isClockWise( subPaths[ 0 ].getPoints() );\n\t\tholesFirst = isCCW ? ! holesFirst : holesFirst;\n\n\t\t// console.log(\"Holes first\", holesFirst);\n\n\t\tconst betterShapeHoles = [];\n\t\tconst newShapes = [];\n\t\tlet newShapeHoles = [];\n\t\tlet mainIdx = 0;\n\t\tlet tmpPoints;\n\n\t\tnewShapes[ mainIdx ] = undefined;\n\t\tnewShapeHoles[ mainIdx ] = [];\n\n\t\tfor ( let i = 0, l = subPaths.length; i < l; i ++ ) {\n\n\t\t\ttmpPath = subPaths[ i ];\n\t\t\ttmpPoints = tmpPath.getPoints();\n\t\t\tsolid = isClockWise( tmpPoints );\n\t\t\tsolid = isCCW ? ! solid : solid;\n\n\t\t\tif ( solid ) {\n\n\t\t\t\tif ( ( ! holesFirst ) && ( newShapes[ mainIdx ] ) )\tmainIdx ++;\n\n\t\t\t\tnewShapes[ mainIdx ] = { s: new Shape(), p: tmpPoints };\n\t\t\t\tnewShapes[ mainIdx ].s.curves = tmpPath.curves;\n\n\t\t\t\tif ( holesFirst )\tmainIdx ++;\n\t\t\t\tnewShapeHoles[ mainIdx ] = [];\n\n\t\t\t\t//console.log('cw', i);\n\n\t\t\t} else {\n\n\t\t\t\tnewShapeHoles[ mainIdx ].push( { h: tmpPath, p: tmpPoints[ 0 ] } );\n\n\t\t\t\t//console.log('ccw', i);\n\n\t\t\t}\n\n\t\t}\n\n\t\t// only Holes? -> probably all Shapes with wrong orientation\n\t\tif ( ! newShapes[ 0 ] )\treturn\ttoShapesNoHoles( subPaths );\n\n\n\t\tif ( newShapes.length > 1 ) {\n\n\t\t\tlet ambiguous = false;\n\t\t\tlet toChange = 0;\n\n\t\t\tfor ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {\n\n\t\t\t\tbetterShapeHoles[ sIdx ] = [];\n\n\t\t\t}\n\n\t\t\tfor ( let sIdx = 0, sLen = newShapes.length; sIdx < sLen; sIdx ++ ) {\n\n\t\t\t\tconst sho = newShapeHoles[ sIdx ];\n\n\t\t\t\tfor ( let hIdx = 0; hIdx < sho.length; hIdx ++ ) {\n\n\t\t\t\t\tconst ho = sho[ hIdx ];\n\t\t\t\t\tlet hole_unassigned = true;\n\n\t\t\t\t\tfor ( let s2Idx = 0; s2Idx < newShapes.length; s2Idx ++ ) {\n\n\t\t\t\t\t\tif ( isPointInsidePolygon( ho.p, newShapes[ s2Idx ].p ) ) {\n\n\t\t\t\t\t\t\tif ( sIdx !== s2Idx )\ttoChange ++;\n\n\t\t\t\t\t\t\tif ( hole_unassigned ) {\n\n\t\t\t\t\t\t\t\thole_unassigned = false;\n\t\t\t\t\t\t\t\tbetterShapeHoles[ s2Idx ].push( ho );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\tambiguous = true;\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t\tif ( hole_unassigned ) {\n\n\t\t\t\t\t\tbetterShapeHoles[ sIdx ].push( ho );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t\tif ( toChange > 0 && ambiguous === false ) {\n\n\t\t\t\tnewShapeHoles = betterShapeHoles;\n\n\t\t\t}\n\n\t\t}\n\n\t\tlet tmpHoles;\n\n\t\tfor ( let i = 0, il = newShapes.length; i < il; i ++ ) {\n\n\t\t\ttmpShape = newShapes[ i ].s;\n\t\t\tshapes.push( tmpShape );\n\t\t\ttmpHoles = newShapeHoles[ i ];\n\n\t\t\tfor ( let j = 0, jl = tmpHoles.length; j < jl; j ++ ) {\n\n\t\t\t\ttmpShape.holes.push( tmpHoles[ j ].h );\n\n\t\t\t}\n\n\t\t}\n\n\t\t//console.log(\"shape\", shapes);\n\n\t\treturn shapes;\n\n\t}\n\n}\n\nclass WebGLMultipleRenderTargets extends WebGLRenderTarget { // @deprecated, r162\n\n\tconstructor( width = 1, height = 1, count = 1, options = {} ) {\n\n\t\tconsole.warn( 'THREE.WebGLMultipleRenderTargets has been deprecated and will be removed in r172. Use THREE.WebGLRenderTarget and set the \"count\" parameter to enable MRT.' );\n\n\t\tsuper( width, height, { ...options, count } );\n\n\t\tthis.isWebGLMultipleRenderTargets = true;\n\n\t}\n\n\tget texture() {\n\n\t\treturn this.textures;\n\n\t}\n\n}\n\nif ( typeof __THREE_DEVTOOLS__ !== 'undefined' ) {\n\n\t__THREE_DEVTOOLS__.dispatchEvent( new CustomEvent( 'register', { detail: {\n\t\trevision: REVISION,\n\t} } ) );\n\n}\n\nif ( typeof window !== 'undefined' ) {\n\n\tif ( window.__THREE__ ) {\n\n\t\tconsole.warn( 'WARNING: Multiple instances of Three.js being imported.' );\n\n\t} else {\n\n\t\twindow.__THREE__ = REVISION;\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNzUzLmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0FBQUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdCQUFnQjtBQUNoQixnQkFBZ0I7QUFDaEI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQkFBMkI7QUFDM0IsMkJBQTJCO0FBQzNCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGlCQUFpQixlQUFlO0FBQ2hDLGlCQUFpQixlQUFlO0FBQ2hDLGlCQUFpQixlQUFlOztBQUVoQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxxQkFBcUIsbUJBQW1CO0FBQ3hDLHFCQUFxQixtQkFBbUI7QUFDeEMscUJBQXFCLG1CQUFtQjs7QUFFeEM7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxnQkFBZ0IsY0FBYztBQUM5QixnQkFBZ0IsY0FBYztBQUM5QixnQkFBZ0IsY0FBYzs7QUFFOUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxnQkFBZ0IsaUJBQWlCO0FBQ2pDLGdCQUFnQixpQkFBaUI7QUFDakMsZ0JBQWdCLGlCQUFpQjs7QUFFakM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsbUJBQW1CLE9BQU87O0FBRTFCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxpQ0FBaUMsUUFBUTs7QUFFekMsMENBQTBDOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEVBQUU7QUFDRjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxFQUFFO0FBQ0Y7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsRUFBRTtBQUNGOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUEsMERBQTBELFlBQVk7O0FBRXRFOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUEsRUFBRTs7QUFFRjs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsb0JBQW9CLGlCQUFpQjs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQSxvQkFBb0IsaUJBQWlCOztBQUVyQzs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1QyxzQkFBc0I7O0FBRTdEOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1Qyx1QkFBdUI7O0FBRTlEOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsNEJBQTRCOztBQUU1Qjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHNDQUFzQztBQUN0Qyx5QkFBeUI7O0FBRXpCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0JBQXdCLGtCQUFrQjs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkJBQTJCO0FBQzNCLDJCQUEyQjtBQUMzQiwyQkFBMkI7QUFDM0IsMkJBQTJCO0FBQzNCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0JBQXNCO0FBQ3RCO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsaUJBQWlCOztBQUVqQjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGdCQUFnQjs7QUFFaEI7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLG9DQUFvQzs7QUFFcEM7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsa0RBQWtEOztBQUVsRDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxrQkFBa0I7O0FBRWxCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLG1CQUFtQixXQUFXOztBQUU5QjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsK0NBQStDLFFBQVE7O0FBRXZEO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLGdEQUFnRCxRQUFROztBQUV4RDtBQUNBOztBQUVBOztBQUVBOztBQUVBLGlDQUFpQztBQUNqQzs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0JBQXdCLGtCQUFrQjs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUEsa0RBQWtEOztBQUVsRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxpQkFBaUI7O0FBRWpCO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDZEQUE2RDs7QUFFN0Q7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsaUJBQWlCOztBQUVqQjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw2REFBNkQ7O0FBRTdEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUosa0NBQWtDOztBQUVsQztBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLHFCQUFxQjs7QUFFckI7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQztBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJCQUEyQjtBQUMzQiwyQkFBMkI7QUFDM0IsMkJBQTJCO0FBQzNCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0MsUUFBUTs7QUFFOUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseUNBQXlDLFFBQVE7O0FBRWpEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1QyxRQUFROztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsa0RBQWtELE9BQU87O0FBRXpEOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdDQUF3QyxPQUFPOztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxpRkFBaUY7QUFDakYsaUZBQWlGO0FBQ2pGLGlGQUFpRjtBQUNqRixpRkFBaUY7QUFDakYsaUZBQWlGO0FBQ2pGLGlGQUFpRjtBQUNqRixpRkFBaUY7QUFDakYsaUZBQWlGOztBQUVqRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsdUNBQXVDLFFBQVE7O0FBRS9DO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBLHVDQUF1QyxRQUFROztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsaUJBQWlCLGVBQWUsZUFBZTtBQUMvQyxpQkFBaUIsZUFBZSxlQUFlO0FBQy9DLGlCQUFpQixlQUFlLGdCQUFnQjtBQUNoRCxpQkFBaUIsZUFBZSxnQkFBZ0I7O0FBRWhEOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEscUJBQXFCLG1CQUFtQixtQkFBbUI7QUFDM0QscUJBQXFCLG1CQUFtQixtQkFBbUI7QUFDM0QscUJBQXFCLG1CQUFtQixxQkFBcUI7QUFDN0QsdUJBQXVCLHFCQUFxQixxQkFBcUI7O0FBRWpFOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsa0JBQWtCLGdCQUFnQjtBQUNsQyxrQkFBa0IsZ0JBQWdCO0FBQ2xDLGtCQUFrQixnQkFBZ0I7O0FBRWxDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxnQkFBZ0IsY0FBYyxjQUFjO0FBQzVDLGdCQUFnQixjQUFjLGNBQWM7QUFDNUMsZ0JBQWdCLGNBQWMsZUFBZTtBQUM3QyxnQkFBZ0IsY0FBYyxlQUFlOztBQUU3Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLGlCQUFpQixtQkFBbUI7QUFDcEMsaUJBQWlCLG1CQUFtQjtBQUNwQyxpQkFBaUIsbUJBQW1COztBQUVwQyxpQkFBaUIsb0JBQW9CO0FBQ3JDLGlCQUFpQixvQkFBb0I7QUFDckMsa0JBQWtCLHFCQUFxQjs7QUFFdkM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxnQkFBZ0IsY0FBYztBQUM5QixnQkFBZ0IsY0FBYztBQUM5QixnQkFBZ0IsY0FBYztBQUM5QixnQkFBZ0IsY0FBYzs7QUFFOUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLGVBQWUsYUFBYSxjQUFjO0FBQzFDLGVBQWUsYUFBYSxjQUFjO0FBQzFDLGVBQWUsYUFBYSxlQUFlO0FBQzNDLGVBQWUsYUFBYSxnQkFBZ0I7O0FBRTVDOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQSxtQkFBbUIsY0FBYyxlQUFlO0FBQ2hELGlCQUFpQixpQkFBaUIsZUFBZTtBQUNqRCxpQkFBaUIsY0FBYyxpQkFBaUI7QUFDaEQsaUJBQWlCLGNBQWMsZUFBZTs7QUFFOUM7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUIsUUFBUTs7QUFFM0I7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLFFBQVE7O0FBRTNCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLHNCQUFzQjtBQUN0Qix3QkFBd0I7O0FBRXhCLDJCQUEyQjtBQUMzQiw2QkFBNkI7O0FBRTdCOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1Qyx3QkFBd0I7O0FBRS9EOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJO0FBQ0o7QUFDQTtBQUNBLElBQUk7QUFDSjtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUEsMEVBQTBFO0FBQzFFOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0Isc0JBQXNCOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0Isc0JBQXNCOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDZDQUE2QyxPQUFPOztBQUVwRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdDQUF3QyxPQUFPOztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsT0FBTzs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0NBQXdDLE9BQU87O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0NBQXdDLE9BQU87O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseUNBQXlDLE9BQU87O0FBRWhEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLGtCQUFrQjtBQUNsQixpQkFBaUI7QUFDakIsZ0JBQWdCO0FBQ2hCLGNBQWM7QUFDZCxjQUFjO0FBQ2QsaUJBQWlCO0FBQ2pCLGtCQUFrQjtBQUNsQjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHlDQUF5QyxPQUFPOztBQUVoRDs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsK0NBQStDLE9BQU87O0FBRXREOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLDBCQUEwQjs7QUFFOUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLDRCQUE0Qjs7QUFFaEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsNEJBQTRCOztBQUVoRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxxQ0FBcUM7QUFDckM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsMEJBQTBCO0FBQzFCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDBCQUEwQjtBQUMxQjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EseUJBQXlCO0FBQ3pCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDBCQUEwQjtBQUMxQjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EseUJBQXlCO0FBQ3pCOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBLHlCQUF5QjtBQUN6Qix1REFBdUQ7O0FBRXZEOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseUJBQXlCO0FBQ3pCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsZ0JBQWdCO0FBQ2hCLGdCQUFnQjs7QUFFaEI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQSx5REFBeUQ7QUFDekQseUNBQXlDO0FBQ3pDLHlDQUF5Qzs7QUFFekM7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLG9CQUFvQixhQUFhLEdBQUcsaUJBQWlCLEdBQUcsaUJBQWlCLEdBQUcsZ0JBQWdCOztBQUU1Rjs7QUFFQSxpQkFBaUIsdUJBQXVCLElBQUksdUJBQXVCLElBQUksdUJBQXVCOztBQUU5Rjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUNBQXVDLHdCQUF3Qjs7QUFFL0Q7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLHlCQUF5Qjs7QUFFekI7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxpREFBaUQsS0FBSztBQUN0RDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx1Q0FBdUMsS0FBSyxnQ0FBZ0MsV0FBVztBQUN2Rjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLG9CQUFvQixTQUFTOztBQUU3Qjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0JBQXdCLGtCQUFrQjs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkRBQTJEOztBQUUzRDs7QUFFQTs7QUFFQSxrRUFBa0U7O0FBRWxFOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0M7O0FBRXRDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLGtCQUFrQixTQUFTOztBQUUzQjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxrQkFBa0IsVUFBVTs7QUFFNUIsbUJBQW1CO0FBQ25CLGFBQWE7O0FBRWI7QUFDQTs7QUFFQTtBQUNBLG9CQUFvQjs7QUFFcEI7O0FBRUEscUJBQXFCO0FBQ3JCLG1CQUFtQjs7QUFFbkI7O0FBRUE7O0FBRUEscUJBQXFCLFVBQVU7O0FBRS9COztBQUVBOztBQUVBLGtCQUFrQixRQUFROztBQUUxQjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLG1CQUFtQixRQUFROztBQUUzQjs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsUUFBUTs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0Esd0JBQXdCO0FBQ3hCO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsK0hBQStIO0FBQy9IOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDRCQUE0QixlQUFlOztBQUUzQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxzQ0FBc0MsT0FBTzs7QUFFN0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0NBQW9DLE9BQU87O0FBRTNDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSixvQ0FBb0MsT0FBTzs7QUFFM0M7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQ0FBbUMsT0FBTzs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUNBQW1DLE9BQU87O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQyxPQUFPOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUNBQXVDLGtCQUFrQjs7QUFFekQ7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxxQkFBcUI7O0FBRXJCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0MsT0FBTzs7QUFFN0M7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDBEQUEwRCxRQUFROztBQUVsRTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDBEQUEwRCxRQUFROztBQUVsRTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSx5Q0FBeUMsUUFBUTs7QUFFakQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMERBQTBELFFBQVE7O0FBRWxFO0FBQ0E7O0FBRUEsaURBQWlELFFBQVE7O0FBRXpEOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQiw2QkFBNkI7O0FBRWhEO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMOztBQUVBLHVDQUF1QyxRQUFROztBQUUvQzs7QUFFQTtBQUNBOztBQUVBLDRDQUE0QyxRQUFROztBQUVwRDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSx1Q0FBdUMsUUFBUTs7QUFFL0M7O0FBRUE7QUFDQTs7QUFFQSw0Q0FBNEMsUUFBUTs7QUFFcEQ7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLGlEQUFpRCxRQUFROztBQUV6RDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsdUNBQXVDLFFBQVE7O0FBRS9DO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUEsbURBQW1ELFFBQVE7O0FBRTNEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1QyxRQUFROztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsd0NBQXdDLE9BQU87O0FBRS9DOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUEscUJBQXFCLGNBQWM7O0FBRW5DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLG1EQUFtRDs7QUFFbkQsZ0RBQWdELFFBQVE7O0FBRXhEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGdCQUFnQjs7QUFFaEI7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxnREFBZ0QsUUFBUTs7QUFFeEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLG1EQUFtRDs7QUFFbkQsK0NBQStDLE9BQU87O0FBRXREOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0JBQXdCLGtCQUFrQjs7QUFFMUM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsaURBQWlEOztBQUVqRDs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxpREFBaUQsUUFBUTs7QUFFekQ7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwrQ0FBK0MsUUFBUTs7QUFFdkQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx5Q0FBeUMsUUFBUTs7QUFFakQ7QUFDQTs7QUFFQTtBQUNBOztBQUVBLG9DQUFvQyxRQUFROztBQUU1QztBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEscURBQXFEO0FBQ3JEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBLG1DQUFtQyxRQUFROztBQUUzQztBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsb0RBQW9EO0FBQ3BEOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEseUNBQXlDLFFBQVE7O0FBRWpEO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxvQ0FBb0MsUUFBUTs7QUFFNUM7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLHFEQUFxRDtBQUNyRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQSxtQ0FBbUMsUUFBUTs7QUFFM0M7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLG9EQUFvRDtBQUNwRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxpR0FBaUc7QUFDakcsaUdBQWlHO0FBQ2pHLDRGQUE0RjtBQUM1RixnR0FBZ0c7QUFDaEcsK0ZBQStGO0FBQy9GLG1HQUFtRzs7QUFFbkc7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLHFCQUFxQixhQUFhOztBQUVsQzs7QUFFQSxzQkFBc0IsYUFBYTs7QUFFbkM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxxQkFBcUIsWUFBWTs7QUFFakMsc0JBQXNCLFlBQVk7O0FBRWxDO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IscUJBQXFCOztBQUV2Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsZ0JBQWdCOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0JBQXdCOztBQUV4QixtQ0FBbUMsNkVBQTZFLEdBQUc7O0FBRW5ILHFDQUFxQyw4Q0FBOEMsR0FBRzs7QUFFdEY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0I7QUFDcEIsdUJBQXVCO0FBQ3ZCLHlCQUF5Qjs7QUFFekI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsa0NBQWtDOztBQUVsQztBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSx1QkFBdUI7QUFDdkIsdUJBQXVCOztBQUV2Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDZEQUE2RDs7QUFFN0Q7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsV0FBVyx5RUFBeUU7QUFDcEY7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLGdFQUFnRTs7QUFFaEU7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0I7QUFDbEI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxVQUFVLGtDQUFrQzs7QUFFNUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBLGtCQUFrQjtBQUNsQjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxpQkFBaUIsYUFBYTtBQUM5QixJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsOENBQThDO0FBQzlDOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsNkNBQTZDLE9BQU87O0FBRXBEOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLDRCQUE0Qjs7QUFFNUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsb0JBQW9CLGFBQWE7O0FBRWpDOztBQUVBLHFCQUFxQixhQUFhOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixZQUFZOztBQUVoQyxxQkFBcUIsWUFBWTs7QUFFakM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFIQUFxSDs7QUFFckgsMkZBQTJGLGdDQUFnQyx1SEFBdUgsS0FBSyxnQ0FBZ0MsMkRBQTJELEtBQUssa0RBQWtELGdIQUFnSCw2REFBNkQsc0hBQXNILDJJQUEySSxtREFBbUQsc0VBQXNFLG9EQUFvRCx1TEFBdUwsd0dBQXdHLDhDQUE4QyxLQUFLOztBQUV0ekMsdUdBQXVHOztBQUV2RyxnRkFBZ0Y7O0FBRWhGLDZLQUE2Syx5Q0FBeUMsdURBQXVEOztBQUU3USwrRUFBK0U7O0FBRS9FLG1JQUFtSSx1REFBdUQscUZBQXFGLHVGQUF1RixxSUFBcUksaUhBQWlIOztBQUU1bEIsdUVBQXVFLGlDQUFpQzs7QUFFeEcsa0pBQWtKLHNEQUFzRCwrQ0FBK0MsZ0RBQWdELHFEQUFxRCwyQkFBMkIsdUJBQXVCLHVCQUF1QixnRUFBZ0Usb0VBQW9FLG9FQUFvRSxvRUFBb0Usb0NBQW9DLEtBQUssOENBQThDLHVEQUF1RCx1QkFBdUIsdUJBQXVCLDBFQUEwRSxLQUFLLDhFQUE4RSwrQ0FBK0MsMERBQTBELHVCQUF1Qix1QkFBdUIsdUJBQXVCLHNFQUFzRSxLQUFLOztBQUVud0MsdUhBQXVIOztBQUV2SCx3REFBd0QsdURBQXVEOztBQUUvRyw2REFBNkQsaUVBQWlFOztBQUU5SCw2Q0FBNkMsZ0JBQWdCLEdBQUcsd0VBQXdFLCtFQUErRSxHQUFHLHNKQUFzSixtREFBbUQscURBQXFELHNEQUFzRCxvREFBb0QsdUNBQXVDLCtDQUErQyx5QkFBeUIsSUFBSTs7QUFFcnJCLHNOQUFzTix5Q0FBeUMscUNBQXFDLGlFQUFpRSxLQUFLLGtFQUFrRSx5R0FBeUcsS0FBSyxvRUFBb0Usd0ZBQXdGLEtBQUssbURBQW1ELDRDQUE0Qyw0REFBNEQsNERBQTRELDREQUE0RCwwR0FBMEcseUlBQXlJLHVCQUF1QixxQ0FBcUMsaUJBQWlCLEtBQUssaUhBQWlILGFBQWEsaUdBQWlHLDRGQUE0Riw0Q0FBNEMsZ0NBQWdDLDJCQUEyQixPQUFPLDRDQUE0Qyw2REFBNkQsa0RBQWtELDZCQUE2Qix3QkFBd0Isb0RBQW9ELCtCQUErQixtRUFBbUUsdURBQXVELGlEQUFpRCwrQkFBK0IsMkRBQTJELDJEQUEyRCwyREFBMkQsdUVBQXVFLHVDQUF1QyxtREFBbUQsK0JBQStCLDREQUE0RCx5QkFBeUIsYUFBYSwwQkFBMEIsdUJBQXVCLFFBQVEsUUFBUSxtQkFBbUIsOEVBQThFLHFCQUFxQixPQUFPLG1DQUFtQyxLQUFLOztBQUVsMkYsNkVBQTZFLDRCQUE0QixzQkFBc0Isc0NBQXNDLHNDQUFzQyxpRUFBaUUsK0VBQStFLCtFQUErRSw4QkFBOEIsS0FBSyw2RkFBNkYsdURBQXVELHVEQUF1RCwwQkFBMEIscUNBQXFDLHFDQUFxQyxzREFBc0Qsa0VBQWtFLDBEQUEwRCxLQUFLOztBQUVuN0IsMEVBQTBFLDBFQUEwRSw4QkFBOEIsc0RBQXNELDJCQUEyQixRQUFRLG9DQUFvQyxzRUFBc0UsMkRBQTJELDJGQUEyRiwwQ0FBMEMsT0FBTyx1SEFBdUgsOEVBQThFLHlCQUF5QixRQUFRLHNDQUFzQyx3RUFBd0UsNkRBQTZELHdHQUF3RyxTQUFTLDZFQUE2RSxnREFBZ0QsMkNBQTJDLCtEQUErRCwyQkFBMkIsUUFBUSxvQ0FBb0MsaUVBQWlFLE9BQU8sOEdBQThHLDhFQUE4RSx5QkFBeUIsUUFBUSxzQ0FBc0MsNkVBQTZFLFNBQVMsOERBQThEOztBQUUzMEQsK0ZBQStGLHVEQUF1RDs7QUFFdEosNkZBQTZGOztBQUU3Riw4RkFBOEY7O0FBRTlGLCtFQUErRSwyREFBMkQ7O0FBRTFJLGlGQUFpRixvREFBb0Q7O0FBRXJJLCtFQUErRSx3SEFBd0g7O0FBRXZNLDJFQUEyRSx5SEFBeUgsOENBQThDLHlFQUF5RSw4R0FBOEcsb0NBQW9DOztBQUU3Yyx3WEFBd1gsYUFBYSxpQ0FBaUMsYUFBYSxtQ0FBbUMsZUFBZSxtQ0FBbUMsZ0JBQWdCLGVBQWUsa0NBQWtDLHFDQUFxQyxxQ0FBcUMscUNBQXFDLHdDQUF3Qyw4REFBOEQsbUVBQW1FLGtDQUFrQyxHQUFHLGlFQUFpRSxxQkFBcUIsZ0RBQWdELDRDQUE0Qyx1REFBdUQsS0FBSyxnQ0FBZ0MsZUFBZSxtQkFBbUIsaUJBQWlCLElBQUkseUJBQXlCLHVCQUF1Qix3QkFBd0IseUJBQXlCLDBCQUEwQixJQUFJLGlEQUFpRCxrRUFBa0UsMERBQTBELEdBQUcsaUVBQWlFLDBEQUEwRCxHQUFHLHlDQUF5QyxhQUFhLG9EQUFvRCxvREFBb0Qsb0RBQW9ELGVBQWUsR0FBRyxzQ0FBc0MsZ0NBQWdDLEdBQUcsa0NBQWtDLDBEQUEwRCx1RUFBdUUsd0JBQXdCLEdBQUcsbURBQW1ELHdDQUF3QyxHQUFHLGdGQUFnRixvRUFBb0Usc0RBQXNELEdBQUcsa0ZBQWtGLG9FQUFvRSxzREFBc0QsSUFBSTs7QUFFOWxGLHVLQUF1SywyQ0FBMkMseUJBQXlCLDhDQUE4Qyw2RkFBNkYsMkRBQTJELFFBQVEsTUFBTSw2RkFBNkYsMkRBQTJELE9BQU8sa0JBQWtCLEtBQUssOENBQThDLGNBQWMsMEJBQTBCLG1FQUFtRSxRQUFRLHlCQUF5Qix1RUFBdUUsUUFBUSx5QkFBeUIscUVBQXFFLFFBQVEseUJBQXlCLHFFQUFxRSxRQUFRLHlCQUF5QixxRUFBcUUsUUFBUSxNQUFNLG1FQUFtRSxPQUFPLGdDQUFnQyxLQUFLLDJFQUEyRSx3Q0FBd0MsZ0VBQWdFLGlEQUFpRCxzQ0FBc0MsMEVBQTBFLHlCQUF5Qix5QkFBeUIsb0JBQW9CLE9BQU8sOEJBQThCLG1EQUFtRCwwREFBMEQsaUNBQWlDLGtDQUFrQyx5R0FBeUcsc0RBQXNELGlCQUFpQiw4U0FBOFMsc0JBQXNCLHFDQUFxQyw0R0FBNEcsUUFBUSxvQ0FBb0MsNEdBQTRHLFFBQVEsb0NBQW9DLDRHQUE0RyxRQUFRLG9DQUFvQyw0R0FBNEcsUUFBUSxNQUFNLCtDQUErQyxLQUFLLGlCQUFpQixLQUFLLDZFQUE2RSxrRkFBa0YsZ0NBQWdDLGtDQUFrQyxnRUFBZ0UsMEJBQTBCLG1DQUFtQyxRQUFRLE1BQU0sd0VBQXdFLHdEQUF3RCxPQUFPLEtBQUs7O0FBRWpqSCxrRUFBa0UsZ0VBQWdFLGtFQUFrRSwyR0FBMkcsK0NBQStDLHlFQUF5RSw4RUFBOEUsMkdBQTJHLCtDQUErQyx5RUFBeUUseUVBQXlFLCtEQUErRCwrR0FBK0cscUVBQXFFOztBQUVwaEMsbUdBQW1HLG9DQUFvQyxtQ0FBbUM7O0FBRTFLLHFNQUFxTTs7QUFFck0sb0hBQW9ILCtDQUErQzs7QUFFbksseUZBQXlGOztBQUV6Riw4RUFBOEU7O0FBRTlFLCtNQUErTSx3TEFBd0wscURBQXFELHlFQUF5RSxHQUFHLHFEQUFxRCx5RUFBeUUsR0FBRyw0Q0FBNEMsaUJBQWlCLEdBQUcsMENBQTBDLHVLQUF1SyxHQUFHOztBQUU3NUIsdUZBQXVGLDZCQUE2QixtSEFBbUgsUUFBUSxNQUFNLG9FQUFvRSxPQUFPLHlFQUF5RSxrR0FBa0csMkZBQTJGLHNEQUFzRCxvSkFBb0osMkNBQTJDLHVKQUF1SixrSUFBa0ksOEdBQThHOztBQUVsc0Msc0ZBQXNGLDZCQUE2QixnQ0FBZ0MsNERBQTRELHdDQUF3Qzs7QUFFdlAsNEVBQTRFLGlNQUFpTSxvQ0FBb0MscUNBQXFDOztBQUV0VixrUEFBa1AscUNBQXFDLG9DQUFvQzs7QUFFM1Qsc0dBQXNHLG1DQUFtQyw2QkFBNkIscUhBQXFILFFBQVEsTUFBTSx5RUFBeUUsT0FBTyxvRkFBb0YsNkZBQTZGLHNGQUFzRjs7QUFFaG9CLCtEQUErRDs7QUFFL0QsaUVBQWlFOztBQUVqRSw0SUFBNEksMEVBQTBFLDhFQUE4RTs7QUFFcFMsaUVBQWlFLDRCQUE0QixrREFBa0QscUNBQXFDLDJCQUEyQjs7QUFFL00seUZBQXlGLDBFQUEwRSxnREFBZ0QsZ0RBQWdELGlGQUFpRiwrQ0FBK0MsNEZBQTRGLGFBQWE7O0FBRTVlLGdGQUFnRixvQ0FBb0M7O0FBRXBILHdEQUF3RCwyQ0FBMkMsK0NBQStDOztBQUVsSiwrREFBK0QsMEJBQTBCLHNCQUFzQiwyQkFBMkIsSUFBSSw0UUFBNFEsMkVBQTJFLGdEQUFnRCx1RkFBdUYsR0FBRywyUUFBMlEseUZBQXlGLEdBQUc7O0FBRXQ5QixvREFBb0QsaUNBQWlDLGtFQUFrRSxpRkFBaUYsbURBQW1ELGlEQUFpRCx1REFBdUQsdURBQXVELHVEQUF1RCwyREFBMkQsMkRBQTJELG9FQUFvRSwyREFBMkQsaUVBQWlFLGtCQUFrQixHQUFHLHVGQUF1Rix1RUFBdUUsbUVBQW1FLHNCQUFzQixHQUFHLHFFQUFxRSx3Q0FBd0Msc0JBQXNCLEdBQUcsNkhBQTZILG1GQUFtRixpQ0FBaUMsMEZBQTBGLEtBQUssMkJBQTJCLEdBQUcsb0hBQW9ILGlFQUFpRSxHQUFHLHFEQUFxRCxxQkFBcUIsaUJBQWlCLE1BQU0saUVBQWlFLHlHQUF5RywyQ0FBMkMsbURBQW1ELDJCQUEyQixLQUFLLHlEQUF5RCxvQkFBb0IsaUJBQWlCLHFCQUFxQixrQkFBa0IsTUFBTSx1REFBdUQsdUhBQXVILDREQUE0RCw2Q0FBNkMsOENBQThDLHFDQUFxQyxvR0FBb0cscURBQXFELEtBQUssdURBQXVELG9CQUFvQixxQkFBcUIsaUJBQWlCLHFCQUFxQixrQkFBa0Isb0JBQW9CLHdCQUF3QixNQUFNLG9EQUFvRCxvSEFBb0gsMkRBQTJELDZDQUE2QyxtRUFBbUUsdUdBQXVHLG9DQUFvQyxnREFBZ0Qsd0RBQXdELG9HQUFvRyx1REFBdUQsUUFBUSxNQUFNLGtDQUFrQyw4QkFBOEIsT0FBTyxLQUFLLGdFQUFnRSxpQkFBaUIsb0JBQW9CLHFCQUFxQixzQkFBc0IsTUFBTSw0QkFBNEIsMEJBQTBCLGlFQUFpRSw2REFBNkQscUJBQXFCLG9CQUFvQix1QkFBdUIsTUFBTSxnRUFBZ0UsbUdBQW1HLHVEQUF1RCxrREFBa0QsNEZBQTRGLHdCQUF3QixLQUFLOztBQUV4aEoseUdBQXlHLDJHQUEyRyxzRkFBc0Ysc0RBQXNELHNDQUFzQyxpQkFBaUIsa0dBQWtHLHVGQUF1RixrRkFBa0YseUVBQXlFLDJGQUEyRixpREFBaUQsc0NBQXNDLGlCQUFpQiwyTEFBMkwsMEZBQTBGLG1FQUFtRSxzSEFBc0gsa0VBQWtFLDBDQUEwQyxxQkFBcUI7O0FBRTcvQyxrREFBa0QsMkNBQTJDOztBQUU3Riw0REFBNEQsdUJBQXVCLHNCQUFzQixJQUFJLHNRQUFzUSx5R0FBeUcsdUZBQXVGLEdBQUcscVFBQXFRLHlGQUF5RixHQUFHOztBQUV2NUIseURBQXlELDJDQUEyQyxvQ0FBb0MseUNBQXlDLCtDQUErQzs7QUFFaE8sNkRBQTZELDZCQUE2QixzQkFBc0IsdUJBQXVCLDRCQUE0QiwyQkFBMkIsSUFBSSxrUkFBa1IsMkVBQTJFLGdEQUFnRCx1RkFBdUYsNE1BQTRNLEdBQUcsaVJBQWlSLHlGQUF5RixHQUFHOztBQUVsdUMsMERBQTBELHVFQUF1RSx5RkFBeUYsOERBQThELHNEQUFzRCx3Q0FBd0Msc0RBQXNELG1DQUFtQywrRUFBK0UsK0NBQStDLHdIQUF3SCxrSkFBa0osOEZBQThGLG1EQUFtRCw2Q0FBNkMsaUNBQWlDLDZNQUE2TSwyRkFBMkYsK0JBQStCLGlFQUFpRSxxREFBcUQsd0NBQXdDLGdDQUFnQyxvR0FBb0csbUpBQW1KLGtFQUFrRSwyRUFBMkUscURBQXFELDBFQUEwRSxvRUFBb0UsdUVBQXVFLDZDQUE2Qyw0R0FBNEcsc1BBQXNQLDJFQUEyRSx5RUFBeUUsMkdBQTJHLDJFQUEyRSx5SEFBeUgseUxBQXlMLDhFQUE4RSxpSEFBaUgsbURBQW1ELDBEQUEwRCxzQ0FBc0MscUNBQXFDLE1BQU0sTUFBTSx5Q0FBeUMsNERBQTRELEtBQUssMEZBQTBGLCtFQUErRSwrRUFBK0U7O0FBRXo3SCw4REFBOEQsc0JBQXNCLG9CQUFvQix1QkFBdUIsc0JBQXNCLHFCQUFxQiw4Q0FBOEMsK0JBQStCLHVCQUF1Qix5QkFBeUIsNERBQTRELDJCQUEyQixpQ0FBaUMsOEJBQThCLHlCQUF5QixvREFBb0QsMkJBQTJCLHdDQUF3Qyw4REFBOEQsOEJBQThCLHNCQUFzQixnQ0FBZ0MsNEJBQTRCLDBEQUEwRCxtQkFBbUIsdUJBQXVCLHVCQUF1QixjQUFjLDZDQUE2QywrQ0FBK0MseUNBQXlDLDBDQUEwQyxtRkFBbUYsK0NBQStDLHVCQUF1QixtREFBbUQscURBQXFELEdBQUcsbUdBQW1HLDZCQUE2QixpRUFBaUUsaUVBQWlFLHlDQUF5QyxHQUFHLDZEQUE2RCw2QkFBNkIscURBQXFELDhDQUE4QyxHQUFHLHdQQUF3UCxpRkFBaUYsaUZBQWlGLGtDQUFrQyx5QkFBeUIsS0FBSywrSUFBK0ksaUNBQWlDLHdFQUF3RSxtQ0FBbUMseUJBQXlCLDhDQUE4QyxLQUFLLHFLQUFxSyxxQ0FBcUMsd0NBQXdDLG9EQUFvRCxzQ0FBc0MscURBQXFELHdEQUF3RCx1REFBdUQsdURBQXVELHdEQUF3RCwyQ0FBMkMsNkRBQTZELHNDQUFzQywyQkFBMkIsS0FBSyxvSUFBb0kscUNBQXFDLHFDQUFxQyx5Q0FBeUMsb0NBQW9DLG1EQUFtRCxzREFBc0QscURBQXFELHFEQUFxRCxzREFBc0QseUNBQXlDLGdHQUFnRyw2RkFBNkYseURBQXlELHlEQUF5RCwwREFBMEQseURBQXlELHlEQUF5RCxzSEFBc0gsaUZBQWlGLHNFQUFzRSxzQ0FBc0MsbUNBQW1DLEdBQUcsNkVBQTZFLGdDQUFnQywwREFBMEQsMENBQTBDLDBDQUEwQyxxREFBcUQsbUNBQW1DLGNBQWMsR0FBRyx3REFBd0QsMEJBQTBCLHFEQUFxRCxHQUFHLHVFQUF1RSw0QkFBNEIsdUJBQXVCLDREQUE0RCxnREFBZ0Qsb0JBQW9CLCtGQUErRiw0Q0FBNEMsR0FBRyw2SEFBNkgsZ0RBQWdELGdEQUFnRCx1Q0FBdUMsMkVBQTJFLGdCQUFnQiwwQ0FBMEMsMEJBQTBCLHlEQUF5RCxxQkFBcUIsZ0RBQWdELGdEQUFnRCxnREFBZ0QsZ0RBQWdELDJDQUEyQywyQ0FBMkMsMkNBQTJDLDJDQUEyQyx3Q0FBd0MsNkVBQTZFLDZFQUE2RSw2RUFBNkUsNkVBQTZFLG1FQUFtRSwwQkFBMEIsR0FBRyw2RUFBNkUsb0NBQW9DLGlDQUFpQyxnQ0FBZ0MsZ0RBQWdELDRFQUE0RSxHQUFHLCtDQUErQyx5RUFBeUUsR0FBRywwSUFBMEksbURBQW1ELHNEQUFzRCxxREFBcUQscURBQXFELGlEQUFpRCx3Q0FBd0Msa0NBQWtDLEdBQUcsdUdBQXVHLHFEQUFxRCxxQ0FBcUMsK0dBQStHLDJHQUEyRyw4RkFBOEYsMENBQTBDLEdBQUcsMkZBQTJGLHFEQUFxRCwwREFBMEQsb0RBQW9ELGlDQUFpQyxzRUFBc0Usa0RBQWtELGVBQWUsR0FBRywwSkFBMEosdURBQXVELHVEQUF1RCxHQUFHLGdUQUFnVCwyTkFBMk4sK0RBQStELDJGQUEyRix1Q0FBdUMsNkRBQTZELDhCQUE4QiwwQkFBMEIsNkNBQTZDLGtEQUFrRCw0QkFBNEIsOEJBQThCLEdBQUcseVRBQXlULG1DQUFtQyxxQ0FBcUMsdUNBQXVDLDZDQUE2QywrQ0FBK0MsaURBQWlELDRDQUE0QywyQ0FBMkMsMkJBQTJCLDBEQUEwRCx3REFBd0QsMERBQTBELDBEQUEwRCxxREFBcUQsdUNBQXVDLHVDQUF1Qyx3SEFBd0gseUdBQXlHLDBIQUEwSCw4SUFBOEksS0FBSyxzUkFBc1IsMkVBQTJFLGdEQUFnRCxnSEFBZ0gsc0RBQXNELGdKQUFnSiwyTEFBMkwseUlBQXlJLHVGQUF1RixHQUFHLDZRQUE2USx5RkFBeUYsR0FBRyxzVUFBc1UscU5BQXFOLHlLQUF5SyxrREFBa0QsdUNBQXVDLCtEQUErRCw2UEFBNlAsOEtBQThLLHdFQUF3RSwySEFBMkgsbUVBQW1FLGtGQUFrRix5RUFBeUUsR0FBRyxxVkFBcVYsa0hBQWtILEdBQUc7O0FBRWxnZSx1RUFBdUUsK0JBQStCLDJGQUEyRiw2Q0FBNkMsb0VBQW9FLDhGQUE4RixpREFBaUQsaUNBQWlDLE1BQU0sTUFBTSw4REFBOEQsS0FBSyx1Q0FBdUMsbUpBQW1KLHlGQUF5RixLQUFLLG9DQUFvQyxnRkFBZ0YscUdBQXFHLDREQUE0RCxzQkFBc0IsUUFBUSxvQ0FBb0MscUVBQXFFLHVJQUF1SSw2VUFBNlUsaUpBQWlKLEtBQUssZ0hBQWdILG1CQUFtQix3QkFBd0Isd0JBQXdCLGtHQUFrRyw0REFBNEQscUJBQXFCLFFBQVEsa0NBQWtDLG1FQUFtRSw0ZkFBNGYseUZBQXlGLHlGQUF5RixtR0FBbUcsaUxBQWlMLDRQQUE0UCxpSkFBaUosS0FBSyw2SEFBNkgsK0dBQStHLDREQUE0RCxvQkFBb0IsUUFBUSxnREFBZ0QsK0RBQStELGlKQUFpSix1U0FBdVMsaUpBQWlKLEtBQUssc0lBQXNJLGtEQUFrRCwwQkFBMEIsUUFBUSwwQ0FBMEMsZ0pBQWdKLEtBQUssMkdBQTJHLHFFQUFxRSw2R0FBNkcsK0ZBQStGLHFCQUFxQixRQUFRLDRGQUE0RixPQUFPLG1IQUFtSCx5Q0FBeUM7O0FBRXhxTCxrSkFBa0osc0VBQXNFLHVDQUF1QywwSkFBMEoscVBBQXFQLGlHQUFpRyxxSkFBcUo7O0FBRXA0Qix1TUFBdU0sd05BQXdOOztBQUUvWiwrSkFBK0o7O0FBRS9KLCtGQUErRiw2QkFBNkIsaUNBQWlDOztBQUU3SixrRkFBa0YsaUNBQWlDOztBQUVuSCxxRkFBcUYsc0VBQXNFOztBQUUzSiwwRkFBMEYsOFJBQThSLHNEQUFzRDs7QUFFOWEsaUVBQWlFOztBQUVqRSxrSUFBa0ksZ0dBQWdHLDJFQUEyRSwrRUFBK0U7O0FBRTVYLG1GQUFtRiwyRkFBMkYsNERBQTRELDREQUE0RDs7QUFFdFMsK0RBQStELDhGQUE4Rix3Q0FBd0M7O0FBRXJNLDRGQUE0Rjs7QUFFNUYsNkdBQTZHLGdHQUFnRyxxQkFBcUIsd0JBQXdCLFFBQVEsaUdBQWlHLEtBQUs7O0FBRXhXLDhGQUE4RixxQkFBcUIsd0JBQXdCLFFBQVEsMEpBQTBKLDBKQUEwSixpQkFBaUI7O0FBRXhkLDhGQUE4RixxQkFBcUIsd0JBQXdCLFFBQVEsOEhBQThILEtBQUs7O0FBRXRSLG1JQUFtSSxnRUFBZ0UseURBQXlELDBDQUEwQyxtR0FBbUcsMEVBQTBFLHFEQUFxRCx5REFBeUQsc0RBQXNELDJEQUEyRCxLQUFLOztBQUV2ckIsNkZBQTZGLHFCQUFxQix3QkFBd0IsUUFBUSw2SEFBNkgsS0FBSzs7QUFFcFIsZ0ZBQWdGLHlEQUF5RCxxQ0FBcUMsaURBQWlELDhDQUE4QyxxREFBcUQsc09BQXNPLDhPQUE4TyxtR0FBbUcsOEJBQThCLHlKQUF5Siw2RkFBNkYsb0dBQW9HLCtCQUErQixxREFBcUQ7O0FBRXIwQyw4SEFBOEgsNkNBQTZDLHVFQUF1RSwwREFBMEQsa0hBQWtILDJCQUEyQixxQ0FBcUMsbUhBQW1IOztBQUVqbEIsd0VBQXdFLGtEQUFrRCw4QkFBOEI7O0FBRXhKLHNFQUFzRSxrREFBa0QsOEJBQThCOztBQUV0SixxRkFBcUYsdUVBQXVFLHVFQUF1RTs7QUFFbk8sbUZBQW1GLDZCQUE2Qix3RUFBd0UsNE5BQTROLG9DQUFvQyxvQ0FBb0MsK0JBQStCLCtCQUErQix5QkFBeUIsbUNBQW1DLG1DQUFtQywrQ0FBK0MsK0NBQStDLGtEQUFrRCw4REFBOEQsNkNBQTZDLEtBQUs7O0FBRXozQix5R0FBeUc7O0FBRXpHLG9LQUFvSyw2Q0FBNkMsd0RBQXdEOztBQUV6USx5RkFBeUYsaUZBQWlGLHNDQUFzQyx1RkFBdUY7O0FBRXZTLCtGQUErRiwyRkFBMkY7O0FBRTFMLDJEQUEyRCxnRkFBZ0YsK0RBQStEOztBQUUxTSw2REFBNkQsMkNBQTJDLEdBQUcsK0NBQStDLCtCQUErQixHQUFHLHdDQUF3QywwQ0FBMEMsb0NBQW9DLGlDQUFpQyxvRkFBb0YsMkVBQTJFLDRGQUE0Riw2RkFBNkYsNENBQTRDLHNEQUFzRCxzREFBc0QsY0FBYyw4Q0FBOEMsOENBQThDLDhDQUE4Qyx3RUFBd0UsR0FBRywyQ0FBMkMsa0RBQWtELGtEQUFrRCxjQUFjLDhDQUE4Qyw4Q0FBOEMsc0RBQXNELEdBQUcsMENBQTBDLDhDQUE4Qyw4Q0FBOEMsY0FBYyxxQ0FBcUMsb0NBQW9DLEdBQUcsOENBQThDLG9DQUFvQyxHQUFHLDZDQUE2QyxvQ0FBb0MsR0FBRyw0Q0FBNEMsMkRBQTJELEdBQUcsMkNBQTJDLDBFQUEwRSxrRUFBa0UsR0FBRyw2Q0FBNkMsZ0VBQWdFLEdBQUcsbUdBQW1HLDZDQUE2QyxHQUFHLG1HQUFtRyx5Q0FBeUMsR0FBRyxrR0FBa0csbUVBQW1FLEdBQUcsa0dBQWtHLDZEQUE2RCxHQUFHOztBQUVqdUYscUdBQXFHOztBQUVyRyxpRUFBaUUsa0VBQWtFLDRFQUE0RSxvREFBb0QsOENBQThDOztBQUVqVCwrRkFBK0Y7O0FBRS9GLGlGQUFpRixvREFBb0QsZ0ZBQWdGLCtGQUErRixzQ0FBc0MsS0FBSzs7QUFFL1YsK0RBQStELDhGQUE4Rix3Q0FBd0M7O0FBRXJNLDRGQUE0Rjs7QUFFNUYsc0hBQXNILCtGQUErRixxSUFBcUksb0VBQW9FLHFDQUFxQyw4QkFBOEIseUJBQXlCLCtCQUErQiwyQkFBMkIsMkJBQTJCLFFBQVEsc0ZBQXNGLDRHQUE0Ryw4QkFBOEIsOEJBQThCLHlCQUF5QiwrQkFBK0IsMkJBQTJCLDJCQUEyQixRQUFRLHlFQUF5RSwrR0FBK0csZ0VBQWdFLCtCQUErQiw4QkFBOEIseUJBQXlCLCtCQUErQiwyQkFBMkIsMkJBQTJCLCtCQUErQiw4QkFBOEIsUUFBUSw0RUFBNEUsa0ZBQWtGLDJFQUEyRSxLQUFLLDZEQUE2RCwwREFBMEQsS0FBSyxnRUFBZ0UsNEJBQTRCLDhEQUE4RCwyREFBMkQsZ0NBQWdDLG1EQUFtRCx5RUFBeUUsa0ZBQWtGLGdHQUFnRyw4RUFBOEUsT0FBTyx1QkFBdUIsS0FBSywrSUFBK0kseUJBQXlCLHVDQUF1QyxrQ0FBa0Msb0hBQW9ILDJEQUEyRCwwQkFBMEIsNEZBQTRGLGlEQUFpRCxpREFBaUQsaURBQWlELGlEQUFpRCw4QkFBOEIsOEJBQThCLDhCQUE4Qiw4QkFBOEIsbWlEQUFtaUQsbUdBQW1HLCtCQUErQiwrQkFBK0IsaUNBQWlDLG1EQUFtRCw0QkFBNEIsbytDQUFvK0MsZ0hBQWdILHlGQUF5RixtQkFBbUIsaURBQWlELEtBQUssK0NBQStDLDJCQUEyQixxRUFBcUUsMEJBQTBCLG9EQUFvRCx5QkFBeUIsNENBQTRDLDJDQUEyQyxrQ0FBa0MsdURBQXVELFFBQVEsaUNBQWlDLGtDQUFrQyw2Q0FBNkMsUUFBUSxpQ0FBaUMsa0NBQWtDLDJDQUEyQyxxQ0FBcUMsT0FBTyxnRUFBZ0UsS0FBSyxtTUFBbU0seUJBQXlCLDZDQUE2QyxvRUFBb0UsZ0hBQWdILHlHQUF5Ryx1QkFBdUIsaURBQWlELDRFQUE0RSxvTEFBb0wsbzFCQUFvMUIsaUdBQWlHLHFCQUFxQixpREFBaUQsS0FBSzs7QUFFaDZTLG9IQUFvSCwwREFBMEQsbUlBQW1JLG9FQUFvRSxxQ0FBcUMsOEJBQThCLHlCQUF5QiwrQkFBK0IsMkJBQTJCLDJCQUEyQixRQUFRLHNGQUFzRiwwRUFBMEUsOEJBQThCLHlCQUF5QiwrQkFBK0IsMkJBQTJCLDJCQUEyQixRQUFRLHlFQUF5RSw2R0FBNkcsZ0VBQWdFLCtCQUErQiw4QkFBOEIseUJBQXlCLCtCQUErQiwyQkFBMkIsMkJBQTJCLCtCQUErQiw4QkFBOEIsUUFBUSw0RUFBNEU7O0FBRXA1QyxpUEFBaVAsNkJBQTZCLDZIQUE2SCwyQkFBMkIsUUFBUSwySEFBMkgsMEZBQTBGLE9BQU8sZ0lBQWdJLDZCQUE2QixRQUFRLHFIQUFxSCw4RUFBOEUsT0FBTyxnSUFBZ0ksMkJBQTJCLFFBQVEsMENBQTBDLG9MQUFvTCxvRkFBb0YsS0FBSzs7QUFFbjlDLHVEQUF1RCx1QkFBdUIscUdBQXFHLGtEQUFrRCwyQkFBMkIsUUFBUSxzREFBc0QseU9BQXlPLEtBQUsscUdBQXFHLGtEQUFrRCw0QkFBNEIsUUFBUSx3Q0FBd0MsOExBQThMLEtBQUssd0dBQXdHLGtEQUFrRCw2QkFBNkIsUUFBUSwwQ0FBMEMsbVFBQW1RLEtBQUssaUVBQWlFLEdBQUc7O0FBRXZnRCwyRkFBMkYsaURBQWlELGlEQUFpRCxpREFBaUQ7O0FBRTlPLDJFQUEyRSxtQ0FBbUMsd0NBQXdDLDRDQUE0QyxpREFBaUQsMkJBQTJCLHVCQUF1Qix1QkFBdUIsNERBQTRELGdFQUFnRSxnRUFBZ0UsZ0VBQWdFLG9DQUFvQyxLQUFLOztBQUVqbUIsc0dBQXNHLCtCQUErQixvREFBb0Qsb0RBQW9ELG9EQUFvRCxvREFBb0Qsc0RBQXNEOztBQUUzWSw4RUFBOEUsMENBQTBDLDBDQUEwQywwQ0FBMEMsMENBQTBDLDZEQUE2RCxzRUFBc0UsZ0dBQWdHOztBQUV6ZCxtREFBbUQsMEZBQTBGLHVDQUF1QyxrQ0FBa0M7O0FBRXROLHlGQUF5Rjs7QUFFekYsOEdBQThHOztBQUU5Ryx5SUFBeUksd0NBQXdDLG1EQUFtRCxHQUFHLDBDQUEwQyxpQ0FBaUMsdURBQXVELEdBQUcsaURBQWlELGlDQUFpQyw4Q0FBOEMsNEdBQTRHLEdBQUcsK0JBQStCLGlEQUFpRCx5REFBeUQsaUJBQWlCLEdBQUcsNENBQTRDLDhKQUE4Six3S0FBd0ssdUNBQXVDLGlDQUFpQyxrQ0FBa0Msa0NBQWtDLDZCQUE2QixHQUFHLDBLQUEwSyw4SkFBOEosMkNBQTJDLG9CQUFvQixzQkFBc0IsOElBQThJLEdBQUcscUNBQXFDLDhQQUE4UCx3UkFBd1Isc0NBQXNDLGtDQUFrQyxpQ0FBaUMsa0RBQWtELG1DQUFtQyxnQ0FBZ0Msd0JBQXdCLDJEQUEyRCxxQ0FBcUMsOENBQThDLG9DQUFvQywwREFBMEQsa0RBQWtELHFDQUFxQyxpQkFBaUIsR0FBRyx5Q0FBeUMsOENBQThDLG9DQUFvQyxpQ0FBaUMsc0RBQXNELHNEQUFzRCxvQkFBb0IseURBQXlELGdEQUFnRCxvQ0FBb0MsaUVBQWlFLDRCQUE0QixtRUFBbUUsNENBQTRDLEdBQUcseUNBQXlDLGVBQWU7O0FBRTVuSCw2RkFBNkYscUNBQXFDLG1DQUFtQyx1REFBdUQsaURBQWlELGdIQUFnSCw4R0FBOEcsd0NBQXdDLCtDQUErQyw2REFBNkQsOFRBQThULHlHQUF5RywrRUFBK0U7O0FBRXJuQyx3RkFBd0YsNEJBQTRCLHNDQUFzQyxrQ0FBa0Msc0VBQXNFLDBFQUEwRSxtREFBbUQsNkNBQTZDLDZCQUE2QixrQ0FBa0MsZ0NBQWdDLHlCQUF5Qix1RUFBdUUsS0FBSyx5QkFBeUIsa0VBQWtFLEtBQUssd0JBQXdCLDZFQUE2RSxLQUFLLHlCQUF5QiwyQ0FBMkMsS0FBSyx5QkFBeUIsK0JBQStCLEtBQUsseUJBQXlCLCtCQUErQixLQUFLLHlCQUF5QixxREFBcUQsS0FBSyx5QkFBeUIsbURBQW1ELEtBQUssdUVBQXVFLG1DQUFtQyw2QkFBNkIsNkJBQTZCLDhCQUE4Qiw4QkFBOEIsOEJBQThCLDhCQUE4Qiw4QkFBOEIsOEJBQThCLDBFQUEwRSwwRUFBMEUsMEVBQTBFLDBFQUEwRSxrTUFBa00sS0FBSyxrRUFBa0UsaUVBQWlFLHVFQUF1RSx3Q0FBd0Msd0NBQXdDLHlGQUF5Rix3RkFBd0YsbURBQW1ELEtBQUssZ0pBQWdKLHdFQUF3RSxzQkFBc0IsNERBQTRELDREQUE0RCw0REFBNEQsb0VBQW9FLEtBQUssK0VBQStFLDREQUE0RCxLQUFLLHlHQUF5Ryw0RkFBNEYseUVBQXlFLEtBQUssdUlBQXVJLDJDQUEyQywyQkFBMkIsUUFBUSxNQUFNLHFGQUFxRixvRkFBb0YsMkJBQTJCLE9BQU8sS0FBSyx1YkFBdWIsNEJBQTRCLHlCQUF5Qix5RkFBeUYsb0VBQW9FLHlCQUF5QixPQUFPLFFBQVEscUdBQXFHLDZEQUE2RCxzRkFBc0YsdURBQXVELGtDQUFrQyxrQ0FBa0MsMEdBQTBHLDBEQUEwRCxxREFBcUQsOElBQThJLFNBQVMsa0NBQWtDLG9IQUFvSCwyREFBMkQsOEVBQThFLHFEQUFxRCxnQ0FBZ0MsZ0NBQWdDLHFGQUFxRiw2SEFBNkgsb0ZBQW9GLDhFQUE4RSxnR0FBZ0csNkdBQTZHLEtBQUs7O0FBRWxwTSwrRkFBK0YsZ0RBQWdELDBEQUEwRCwwREFBMEQsb0RBQW9ELHdEQUF3RCw0REFBNEQsZ0VBQWdFLGtFQUFrRSxrRUFBa0Usb0VBQW9FLGtFQUFrRSwrRUFBK0UscUZBQXFGLHNFQUFzRSx5RkFBeUYscUVBQXFFLDZFQUE2RSxnRUFBZ0UsMkVBQTJFLG1GQUFtRiw4RUFBOEUsb0NBQW9DLHdFQUF3RSxpQ0FBaUM7O0FBRW5vRCw2RkFBNkYsc0RBQXNELHdCQUF3QixnRUFBZ0UsNkJBQTZCLGdFQUFnRSw2QkFBNkIsMERBQTBELDBCQUEwQiw4REFBOEQsNEJBQTRCLGtFQUFrRSw4QkFBOEIsOEVBQThFLG9DQUFvQyxzRUFBc0UsZ0NBQWdDLHdFQUF3RSxpQ0FBaUMsd0VBQXdFLGlDQUFpQywwRUFBMEUsa0NBQWtDLHdFQUF3RSxpQ0FBaUMscUZBQXFGLHVDQUF1QywyRkFBMkYsMENBQTBDLDJFQUEyRSxrQ0FBa0MsbUZBQW1GLHNDQUFzQyw0RUFBNEUsbUNBQW1DLCtGQUErRiw0Q0FBNEMsc0VBQXNFLGdDQUFnQyxpRkFBaUYscUNBQXFDLHlGQUF5Rix5Q0FBeUMsOEVBQThFLG9DQUFvQyx3RUFBd0UsaUNBQWlDOztBQUU1Z0YsOEZBQThGLDZFQUE2RSxpR0FBaUcsaUdBQWlHLHFGQUFxRiw2RkFBNkYscUdBQXFHLDZIQUE2SCw2R0FBNkcsaUhBQWlILGlIQUFpSCxxSEFBcUgsaUhBQWlILDJJQUEySSx1SkFBdUoseUhBQXlILCtKQUErSix1SEFBdUgsdUlBQXVJLDZHQUE2RyxtSUFBbUksbUpBQW1KLDZIQUE2SCxpSEFBaUg7O0FBRS90RixtTkFBbU4sNEVBQTRFLHdGQUF3RiwwREFBMEQ7O0FBRWpiLG1DQUFtQywyQkFBMkIsZUFBZSw2Q0FBNkMsZ0RBQWdELEdBQUc7O0FBRTdLLDBDQUEwQyxvQ0FBb0MsbUJBQW1CLGVBQWUsMENBQTBDLHVPQUF1TyxrREFBa0QsNEJBQTRCLHdFQUF3RTs7QUFFdmhCLCtDQUErQyxrQ0FBa0Msa0VBQWtFLDBGQUEwRixHQUFHOztBQUVoUCwwRUFBMEUsbUVBQW1FLG1DQUFtQyxxQ0FBcUMsb0NBQW9DLGtDQUFrQywrQkFBK0IsdURBQXVELHdKQUF3SixrSkFBa0osMERBQTBELGtEQUFrRCw0QkFBNEIsd0VBQXdFOztBQUUzMkIsK0NBQStDLGtDQUFrQyxrRUFBa0UsMEZBQTBGLEdBQUc7O0FBRWhQLDhDQUE4QyxzQkFBc0Isd0JBQXdCLCtCQUErQixlQUFlLGdHQUFnRyw0QkFBNEIsOEJBQThCLHdFQUF3RTs7QUFFNVcsd1RBQXdULGVBQWUsK2dCQUErZ0IsR0FBRzs7QUFFejFCLHVFQUF1RSxxVUFBcVUsZUFBZSxvQ0FBb0MsbUdBQW1HLHVQQUF1UCw0RkFBNEYsa0ZBQWtGLDhGQUE4RixrR0FBa0csYUFBYTs7QUFFcHBDLGdFQUFnRSxtUEFBbVAsNmdCQUE2Z0IsR0FBRzs7QUFFbjBCLHFFQUFxRSw2QkFBNkIsNEJBQTRCLDhCQUE4Qix1UUFBdVEsb0NBQW9DLGtPQUFrTyxvRUFBb0UsNEJBQTRCLDJDQUEyQyxHQUFHOztBQUV2ekIsK0NBQStDLGtDQUFrQyxrRUFBa0UsMkRBQTJEOztBQUU5TSxnREFBZ0QsK0JBQStCLGtDQUFrQyxrREFBa0QsNENBQTRDLG9EQUFvRCx3RUFBd0U7O0FBRTNVLHNDQUFzQywrQkFBK0IsOEJBQThCLHVPQUF1Tyx5Q0FBeUMsaVRBQWlUOztBQUVwcUIseUNBQXlDLHdCQUF3Qix5QkFBeUIsMEJBQTBCLDhCQUE4QiwyT0FBMk8saURBQWlELDhGQUE4RixjQUFjLEtBQUsscUNBQXFDLGdJQUFnSSw0S0FBNEs7O0FBRWgzQix3VkFBd1Ysd3BCQUF3cEI7O0FBRWgvQix5Q0FBeUMsd0JBQXdCLDhDQUE4QyxvakJBQW9qQixpREFBaUQsZ1hBQWdYLHFGQUFxRiw4RkFBOEYsNkRBQTZELDhGQUE4Rix3REFBd0QsMk9BQTJPOztBQUVyckQsOERBQThELGliQUFpYiwwbEJBQTBsQixxSEFBcUg7O0FBRTlyQywwREFBMEQsd0JBQXdCLHdCQUF3QiwwMEJBQTAwQixpREFBaUQsZ0pBQWdKLDBDQUEwQyxxbUJBQXFtQiwyT0FBMk87O0FBRS8rRCw2REFBNkQsZ1hBQWdYLG1uQkFBbW5CLEdBQUc7O0FBRW5pQyx5REFBeUQsd0JBQXdCLDJCQUEyQiw2QkFBNkIsaWVBQWllLGlEQUFpRCx5VkFBeVYsOERBQThELGlDQUFpQyx1RUFBdUUsc0VBQXNFLDZFQUE2RSxzRUFBc0UsNk1BQTZNOztBQUVoa0QsOEpBQThKLDhUQUE4VCw4bkJBQThuQixXQUFXOztBQUVybUMsMERBQTBELDhIQUE4SCwrUEFBK1AsdURBQXVELHNOQUFzTiw0Q0FBNEMsYUFBYTs7QUFFN3ZCLDREQUE0RCxpYkFBaWIsMGxCQUEwbEIscUhBQXFIOztBQUU1ckMsd0RBQXdELHdCQUF3Qix3QkFBd0IsMEJBQTBCLHdCQUF3Qix3MEJBQXcwQixpREFBaUQsZ0pBQWdKLDBDQUEwQyxxcUJBQXFxQiwyT0FBMk87O0FBRTdsRSwrREFBK0QseURBQXlELDBaQUEwWiwwbEJBQTBsQixzSkFBc0osV0FBVzs7QUFFN3dDLDJIQUEySCx3QkFBd0IsMEJBQTBCLDBCQUEwQix3QkFBd0Isa0NBQWtDLGlFQUFpRSwrQkFBK0IseUVBQXlFLDJGQUEyRixvRUFBb0UscUNBQXFDLDREQUE0RCw4REFBOEQsaUNBQWlDLDhDQUE4Qyw4Q0FBOEMsc0RBQXNELGlDQUFpQyxtRUFBbUUscUZBQXFGLDJFQUEyRSxrRUFBa0UsK0NBQStDLG9pQ0FBb2lDLGlEQUFpRCxnSkFBZ0osMENBQTBDLDZzQkFBNnNCLHlGQUF5RixrSEFBa0gsNEZBQTRGLG9HQUFvRyxvSEFBb0gsbUZBQW1GLHdKQUF3Six1TkFBdU47O0FBRTdxSSwyREFBMkQsa1pBQWtaLDBsQkFBMGxCLHlGQUF5Rjs7QUFFaG9DLHVEQUF1RCx3QkFBd0Isd0JBQXdCLDh2QkFBOHZCLGlEQUFpRCxnSkFBZ0osMENBQTBDLCtqQkFBK2pCLDZNQUE2TTs7QUFFNTFELHFDQUFxQyxzQkFBc0Isd09BQXdPLDZCQUE2Qix1QkFBdUIsdUVBQXVFLHlOQUF5TixpR0FBaUcsc0VBQXNFLDBJQUEwSTs7QUFFeDZCLHlDQUF5Qyx3QkFBd0IsK1JBQStSLGlEQUFpRCw0RUFBNEUsMk1BQTJNLDRLQUE0Szs7QUFFcDFCLDBQQUEwUCxxZEFBcWQ7O0FBRS9zQix1Q0FBdUMsd0JBQXdCLG1QQUFtUCx5R0FBeUcsbUdBQW1HOztBQUU5Zix5Q0FBeUMsc0JBQXNCLHFLQUFxSywyRkFBMkYsZUFBZSwyRkFBMkYsMkZBQTJGLGtHQUFrRyxtREFBbUQsd0ZBQXdGLHlCQUF5QixrR0FBa0csa0dBQWtHLHFDQUFxQyxnREFBZ0Qsa0dBQWtHOztBQUVyb0MseUNBQXlDLHdCQUF3QixzVEFBc1QsaURBQWlELDRFQUE0RSxxTUFBcU0saUlBQWlJOztBQUUxekI7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLGFBQWEsNENBQTRDO0FBQ3pELGFBQWEsWUFBWTs7QUFFekIsU0FBUyxhQUFhO0FBQ3RCLGtCQUFrQixvQ0FBb0M7O0FBRXRELGNBQWMsYUFBYTtBQUMzQix1QkFBdUIsb0NBQW9DOztBQUUzRCxlQUFlOztBQUVmLEVBQUU7O0FBRUY7O0FBRUEsaUJBQWlCLGFBQWE7QUFDOUIsMEJBQTBCOztBQUUxQixFQUFFOztBQUVGOztBQUVBLFlBQVksYUFBYTtBQUN6QixvQkFBb0Isb0NBQW9DO0FBQ3hELGdCQUFnQixZQUFZO0FBQzVCLGtCQUFrQixZQUFZO0FBQzlCLFNBQVMsWUFBWTtBQUNyQixxQkFBcUIsYUFBYTs7QUFFbEMsRUFBRTs7QUFFRjs7QUFFQSxXQUFXLGFBQWE7QUFDeEIsb0JBQW9CLFVBQVU7QUFDOUIsb0JBQW9COztBQUVwQixFQUFFOztBQUVGOztBQUVBLGNBQWMsYUFBYTtBQUMzQix1QkFBdUIsVUFBVTtBQUNqQyx1QkFBdUI7O0FBRXZCLEVBQUU7O0FBRUY7O0FBRUEsYUFBYSxhQUFhO0FBQzFCLHNCQUFzQixvQ0FBb0M7QUFDMUQsZUFBZTs7QUFFZixFQUFFOztBQUVGOztBQUVBLGVBQWUsYUFBYTtBQUM1Qix3QkFBd0Isb0NBQW9DO0FBQzVELGlCQUFpQjs7QUFFakIsRUFBRTs7QUFFRjs7QUFFQSxxQkFBcUIsYUFBYTtBQUNsQyw4QkFBOEIsb0NBQW9DO0FBQ2xFLHVCQUF1QixVQUFVO0FBQ2pDLHNCQUFzQjs7QUFFdEIsRUFBRTs7QUFFRjs7QUFFQSxpQkFBaUIsYUFBYTtBQUM5QiwwQkFBMEI7O0FBRTFCLEVBQUU7O0FBRUY7O0FBRUEsa0JBQWtCLGFBQWE7QUFDL0IsMkJBQTJCOztBQUUzQixFQUFFOztBQUVGOztBQUVBLGtCQUFrQixhQUFhO0FBQy9CLDJCQUEyQjs7QUFFM0IsRUFBRTs7QUFFRjs7QUFFQSxpQkFBaUI7O0FBRWpCLEVBQUU7O0FBRUY7O0FBRUEsZ0JBQWdCLGdCQUFnQjtBQUNoQyxhQUFhLFVBQVU7QUFDdkIsWUFBWSxhQUFhO0FBQ3pCLGNBQWM7O0FBRWQsRUFBRTs7QUFFRjs7QUFFQSx1QkFBdUIsV0FBVzs7QUFFbEMsZ0JBQWdCLFdBQVc7O0FBRTNCLHVCQUF1QjtBQUN2QixnQkFBZ0I7QUFDaEI7QUFDQSxLQUFLOztBQUVMLDZCQUE2QjtBQUM3QjtBQUNBLGlCQUFpQjtBQUNqQix1QkFBdUI7QUFDdkIsbUJBQW1CO0FBQ25CO0FBQ0EsS0FBSzs7QUFFTCwwQkFBMEIsV0FBVztBQUNyQyw2QkFBNkIsV0FBVzs7QUFFeEMsZ0JBQWdCO0FBQ2hCLFlBQVk7QUFDWixlQUFlO0FBQ2YsZ0JBQWdCO0FBQ2hCLGVBQWU7QUFDZixjQUFjO0FBQ2Qsa0JBQWtCO0FBQ2xCO0FBQ0EsS0FBSzs7QUFFTCxzQkFBc0I7QUFDdEI7QUFDQSxpQkFBaUI7QUFDakIsdUJBQXVCO0FBQ3ZCLG1CQUFtQjtBQUNuQjtBQUNBLEtBQUs7O0FBRUwsa0JBQWtCLFdBQVc7QUFDN0IsbUJBQW1CLFdBQVc7QUFDOUIscUJBQXFCLFdBQVc7O0FBRWhDLGlCQUFpQjtBQUNqQixZQUFZO0FBQ1osZUFBZTtBQUNmLFlBQVk7QUFDWjtBQUNBLEtBQUs7O0FBRUwsdUJBQXVCO0FBQ3ZCO0FBQ0EsaUJBQWlCO0FBQ2pCLHVCQUF1QjtBQUN2QixtQkFBbUI7QUFDbkIsb0JBQW9CO0FBQ3BCLHVCQUF1QjtBQUN2QjtBQUNBLEtBQUs7O0FBRUwsb0JBQW9CLFdBQVc7QUFDL0IsdUJBQXVCLFdBQVc7O0FBRWxDLHNCQUFzQjtBQUN0QixnQkFBZ0I7QUFDaEIsZUFBZTtBQUNmO0FBQ0EsS0FBSzs7QUFFTDtBQUNBLG9CQUFvQjtBQUNwQixZQUFZO0FBQ1osZUFBZTtBQUNmLFlBQVk7QUFDWjtBQUNBLEtBQUs7O0FBRUwsV0FBVyxhQUFhO0FBQ3hCLFdBQVc7O0FBRVgsRUFBRTs7QUFFRjs7QUFFQSxhQUFhLDRDQUE0QztBQUN6RCxhQUFhLFlBQVk7QUFDekIsVUFBVSxZQUFZO0FBQ3RCLFdBQVcsWUFBWTtBQUN2QixTQUFTLGFBQWE7QUFDdEIsY0FBYyxhQUFhO0FBQzNCLHVCQUF1QixvQ0FBb0M7QUFDM0QsZUFBZSxVQUFVO0FBQ3pCLGlCQUFpQjs7QUFFakIsRUFBRTs7QUFFRjs7QUFFQSxhQUFhLDRDQUE0QztBQUN6RCxhQUFhLFlBQVk7QUFDekIsWUFBWSw4Q0FBOEM7QUFDMUQsY0FBYyxZQUFZO0FBQzFCLFNBQVMsYUFBYTtBQUN0QixrQkFBa0Isb0NBQW9DO0FBQ3RELGNBQWMsYUFBYTtBQUMzQix1QkFBdUIsb0NBQW9DO0FBQzNELGVBQWU7O0FBRWY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsNENBQTRDO0FBQzVELGdCQUFnQiw0Q0FBNEM7QUFDNUQsaUJBQWlCO0FBQ2pCO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsNENBQTRDO0FBQzVELGlCQUFpQixZQUFZO0FBQzdCLGlCQUFpQixZQUFZO0FBQzdCLHVCQUF1QjtBQUN2QjtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0I7QUFDaEI7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxjQUFjO0FBQ2Q7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYSxVQUFVO0FBQ3ZCLGdCQUFnQixVQUFVO0FBQzFCLGlCQUFpQjtBQUNqQjtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsZUFBZTtBQUNmO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBLGtCQUFrQixvQ0FBb0M7QUFDdEQsVUFBVSxhQUFhO0FBQ3ZCLDBCQUEwQjtBQUMxQixHQUFHOztBQUVIO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBLGFBQWEsYUFBYTtBQUMxQixpQkFBaUIsWUFBWTtBQUM3QiwyQkFBMkIsVUFBVTtBQUNyQywwQkFBMEIsVUFBVTtBQUNwQyx5QkFBeUI7QUFDekIsR0FBRzs7QUFFSDtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQSxZQUFZLGFBQWE7QUFDekIsWUFBWSxZQUFZO0FBQ3hCLGNBQWM7QUFDZCxHQUFHOztBQUVIO0FBQ0E7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTtBQUNBLGdCQUFnQixhQUFhO0FBQzdCLEdBQUc7O0FBRUg7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EseUJBQXlCLG9DQUFvQztBQUM3RCxvQkFBb0IsVUFBVTtBQUM5QixtQkFBbUI7QUFDbkI7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxhQUFhLDJDQUEyQztBQUN4RCxlQUFlO0FBQ2YsSUFBSTtBQUNKOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsZ0JBQWdCLFVBQVU7QUFDMUIsbUJBQW1CLGFBQWE7QUFDaEMsNEJBQTRCLG9DQUFvQztBQUNoRSx5QkFBeUIsYUFBYTtBQUN0QyxrQ0FBa0Msb0NBQW9DO0FBQ3RFLDJCQUEyQiwwQ0FBMEM7QUFDckUseUJBQXlCLFVBQVU7QUFDbkMsNEJBQTRCLGFBQWE7QUFDekMscUNBQXFDLG9DQUFvQztBQUN6RSxpQkFBaUIsVUFBVTtBQUMzQixrQkFBa0IsVUFBVTtBQUM1QixxQkFBcUIsYUFBYTtBQUNsQyw4QkFBOEIsb0NBQW9DO0FBQ2xFLHFCQUFxQixZQUFZO0FBQ2pDLGtDQUFrQyxZQUFZO0FBQzlDLGtDQUFrQyxZQUFZO0FBQzlDLDhCQUE4QixhQUFhO0FBQzNDLHVDQUF1QyxvQ0FBb0M7QUFDM0UsWUFBWSxVQUFVO0FBQ3RCLGlCQUFpQiw0Q0FBNEM7QUFDN0Qsb0JBQW9CLGFBQWE7QUFDakMsNkJBQTZCLG9DQUFvQztBQUNqRSxxQkFBcUIsVUFBVTtBQUMvQix3QkFBd0IsYUFBYTtBQUNyQyxpQ0FBaUMsb0NBQW9DO0FBQ3JFLG1CQUFtQixVQUFVO0FBQzdCLHNCQUFzQixhQUFhO0FBQ25DLCtCQUErQixvQ0FBb0M7QUFDbkUsOEJBQThCLG9DQUFvQztBQUNsRSw2QkFBNkIsYUFBYTtBQUMxQyxnQkFBZ0IsVUFBVTtBQUMxQixtQkFBbUIsYUFBYTtBQUNoQyw0QkFBNEIsb0NBQW9DO0FBQ2hFLDBCQUEwQixVQUFVO0FBQ3BDLHVCQUF1Qiw0Q0FBNEM7QUFDbkUsb0JBQW9CLDJDQUEyQztBQUMvRCx1QkFBdUIsYUFBYTtBQUNwQyxnQ0FBZ0Msb0NBQW9DO0FBQ3BFLHdCQUF3QixVQUFVO0FBQ2xDLDJCQUEyQixhQUFhO0FBQ3hDLG9DQUFvQyxvQ0FBb0M7QUFDeEUsdUJBQXVCLG9DQUFvQztBQUMzRCxvQkFBb0IsYUFBYTtBQUNqQyw2QkFBNkIsb0NBQW9DO0FBQ2pFO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxlQUFlO0FBQ2Y7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9EQUFvRDtBQUNwRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsbUJBQW1CLGdCQUFnQjs7QUFFbkM7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTztBQUNQOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7QUFDSDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsR0FBRztBQUNIOztBQUVBOztBQUVBLEdBQUc7QUFDSDs7QUFFQTtBQUNBOztBQUVBLEdBQUc7QUFDSDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxtQkFBbUIseUJBQXlCOztBQUU1QztBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxpQkFBaUI7QUFDakI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDhDQUE4QyxRQUFROztBQUV0RDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsa0RBQWtELFFBQVE7O0FBRTFEOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSx3QkFBd0IsbUNBQW1DOztBQUUzRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxRQUFROztBQUVSLHdCQUF3QixtQ0FBbUM7O0FBRTNEOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVCQUF1QixtQ0FBbUM7O0FBRTFEO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBLHdCQUF3QixtQ0FBbUM7O0FBRTNEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFFBQVE7O0FBRVIsd0JBQXdCLG1DQUFtQzs7QUFFM0Q7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUJBQXVCLG1DQUFtQzs7QUFFMUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLG1CQUFtQixlQUFlOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsbUJBQW1COztBQUV2Qzs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0Esb0JBQW9CLGVBQWU7O0FBRW5DOztBQUVBOztBQUVBLG9CQUFvQixzQkFBc0I7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxjQUFjOztBQUVkO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQSw2QkFBNkI7O0FBRTdCOztBQUVBLG9CQUFvQixlQUFlOztBQUVuQzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDLGVBQWU7O0FBRXBEOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDZEQUE2RDs7QUFFN0Q7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsZ0VBQWdFOztBQUVoRTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLDRCQUE0Qjs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUksT0FBTzs7QUFFWDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxXQUFXLFVBQVU7QUFDckIsT0FBTyw2RUFBNkU7O0FBRXBGOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsaUJBQWlCO0FBQ2pCLGFBQWEscUNBQXFDLFlBQVk7O0FBRTlEOztBQUVBO0FBQ0E7O0FBRUEsbUJBQW1CLGlCQUFpQjs7QUFFcEM7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLG9CQUFvQjs7QUFFdkM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsVUFBVSxVQUFVO0FBQ3BCO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7OztBQUlBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsZUFBZTs7QUFFakM7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsc0JBQXNCLGtCQUFrQjs7QUFFeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFVBQVU7O0FBRVY7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHdCQUF3QixPQUFPO0FBQy9CLEdBQUc7O0FBRUg7QUFDQSxlQUFlLGFBQWE7QUFDNUIsZ0JBQWdCLFVBQVU7QUFDMUIsZ0JBQWdCLGdCQUFnQjtBQUNoQyxvQkFBb0IsY0FBYztBQUNsQyxlQUFlLFVBQVU7QUFDekIsZUFBZSxVQUFVO0FBQ3pCLGlCQUFpQjtBQUNqQixHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEscUJBQXFCLE9BQU87O0FBRTVCOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsZUFBZTtBQUNmLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxlQUFlLGFBQWE7QUFDNUIsbUJBQW1CO0FBQ25CLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsMkJBQTJCO0FBQzNCOztBQUVBOztBQUVBOztBQUVBOztBQUVBLCtCQUErQjs7QUFFL0IsS0FBSzs7QUFFTDtBQUNBLDBCQUEwQjs7QUFFMUIsS0FBSzs7QUFFTCx5QkFBeUI7O0FBRXpCLEtBQUs7O0FBRUw7QUFDQSwwQkFBMEI7O0FBRTFCLEtBQUs7O0FBRUw7QUFDQSwwQkFBMEI7O0FBRTFCLEtBQUs7O0FBRUwseUJBQXlCOztBQUV6Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUIsWUFBWTs7QUFFL0I7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3QztBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBLGtEQUFrRCxPQUFPOztBQUV6RDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxtQkFBbUIsZUFBZTs7QUFFbEM7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixtQkFBbUI7O0FBRXZDOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQSxvQkFBb0IsZUFBZTs7QUFFbkM7O0FBRUE7O0FBRUEsb0JBQW9CLHNCQUFzQjs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHVCQUF1Qjs7QUFFM0M7QUFDQTtBQUNBOztBQUVBOztBQUVBLHFCQUFxQix1QkFBdUI7O0FBRTVDOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLG9CQUFvQiw2QkFBNkI7O0FBRWpEOztBQUVBOztBQUVBOzs7QUFHQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsaUJBQWlCOztBQUVqQjtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsK0JBQStCLGVBQWU7O0FBRTlDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsZ0NBQWdDLE9BQU87O0FBRXZDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGdDQUFnQyxPQUFPOztBQUV2Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLGtCQUFrQixTQUFTOztBQUUzQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseURBQXlEO0FBQ3pEOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUNBQW1DO0FBQ25DLG1DQUFtQztBQUNuQyxtQ0FBbUM7QUFDbkMsbUNBQW1DOztBQUVuQyxrQ0FBa0M7QUFDbEMsa0NBQWtDO0FBQ2xDLGtDQUFrQzs7QUFFbEMsZ0RBQWdEO0FBQ2hELGdEQUFnRDtBQUNoRCxnREFBZ0Q7QUFDaEQsZ0RBQWdEOztBQUVoRCxvQ0FBb0M7QUFDcEMsb0NBQW9DO0FBQ3BDLG9DQUFvQztBQUNwQyxvQ0FBb0M7O0FBRXBDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsU0FBUzs7QUFFM0I7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsa0JBQWtCLFNBQVM7O0FBRTNCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGtCQUFrQixTQUFTOztBQUUzQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsU0FBUzs7QUFFM0I7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBLHdDQUF3QztBQUN4Qyx3Q0FBd0M7QUFDeEMsd0NBQXdDO0FBQ3hDLHdDQUF3Qzs7QUFFeEMsdUNBQXVDO0FBQ3ZDLHVDQUF1QztBQUN2Qyx1Q0FBdUM7O0FBRXZDLHFEQUFxRDtBQUNyRCxxREFBcUQ7QUFDckQscURBQXFEO0FBQ3JELHFEQUFxRDs7QUFFckQseUNBQXlDO0FBQ3pDLHlDQUF5QztBQUN6Qyx5Q0FBeUM7QUFDekMseUNBQXlDOztBQUV6QztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsa0NBQWtDOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsa0NBQWtDOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQyxTQUFTOztBQUU1QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsZ0NBQWdDOztBQUVoQzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQ0FBbUMsU0FBUzs7QUFFNUM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQyxTQUFTOztBQUU1QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEscUJBQXFCLFFBQVE7O0FBRTdCO0FBQ0Esa0JBQWtCLGdDQUFnQyxFQUFFLEtBQUssSUFBSSxXQUFXOztBQUV4RTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxnQkFBZ0IsYUFBYSxpQkFBaUIsU0FBUyxnQkFBZ0IsSUFBSSxnQkFBZ0IsY0FBYzs7QUFFekc7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxtREFBbUQscURBQXFEOztBQUV4Rzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEseUNBQXlDOztBQUV6QyxrQ0FBa0MsR0FBRyxLQUFLLEdBQUcsS0FBSyxJQUFJLEVBQUU7O0FBRXhELCtCQUErQjs7QUFFL0IsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsT0FBTzs7QUFFekI7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHlGQUF5RixvQkFBb0Isb0JBQW9CLFdBQVc7O0FBRTVJOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGtDQUFrQyxxQkFBcUI7O0FBRXZEO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQ0FBb0Msc0JBQXNCO0FBQzFELGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DLGFBQWEsc0JBQXNCO0FBQ25DOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsVUFBVTs7QUFFVjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw2QkFBNkI7QUFDN0IsaUNBQWlDO0FBQ2pDLGtDQUFrQztBQUNsQyw0QkFBNEI7QUFDNUIsOEJBQThCO0FBQzlCLGdDQUFnQztBQUNoQyxnQ0FBZ0M7O0FBRWhDOztBQUVBLG1DQUFtQzs7QUFFbkM7O0FBRUE7O0FBRUEsa0NBQWtDOztBQUVsQzs7QUFFQTs7QUFFQSxvQ0FBb0M7O0FBRXBDOztBQUVBLDRCQUE0QjtBQUM1QiwwQkFBMEI7QUFDMUIsc0JBQXNCOztBQUV0Qjs7QUFFQSx3QkFBd0I7O0FBRXhCOztBQUVBOztBQUVBLHdCQUF3Qjs7QUFFeEI7O0FBRUE7O0FBRUEsd0JBQXdCOztBQUV4Qjs7QUFFQTs7QUFFQSw0QkFBNEI7O0FBRTVCOztBQUVBOztBQUVBLDBCQUEwQjs7QUFFMUI7O0FBRUEsMEJBQTBCOztBQUUxQjs7QUFFQTs7QUFFQSw4QkFBOEI7QUFDOUIsK0JBQStCOztBQUUvQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDRCQUE0QjtBQUM1QixnQ0FBZ0M7QUFDaEMsZ0NBQWdDOztBQUVoQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsaUdBQWlHO0FBQ2pHO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsZUFBZSxPQUFPOztBQUV0Qjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSx5Q0FBeUMsUUFBUTs7QUFFakQ7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBLEdBQUc7O0FBRUg7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJEQUEyRCxRQUFROztBQUVuRTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7O0FBSUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsa0JBQWtCLE9BQU87O0FBRXpCO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTCxxQkFBcUIsT0FBTzs7QUFFNUI7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3Qzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNkJBQTZCLHdDQUF3QyxHQUFHOztBQUV4RSxnREFBZ0QsMEJBQTBCLHVCQUF1QixtQ0FBbUMsK0NBQStDLHFCQUFxQiw2QkFBNkIsb0VBQW9FLGlEQUFpRCx5QkFBeUIsYUFBYSxRQUFRLDhDQUE4Qyx5S0FBeUssK0JBQStCLDBGQUEwRixrSkFBa0osc0JBQXNCLHNDQUFzQyxpQkFBaUIsMEJBQTBCLDBDQUEwQyx1REFBdUQsNERBQTRELEdBQUc7O0FBRWpuQzs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLDRDQUE0QyxpQ0FBaUM7QUFDN0U7O0FBRUEscUJBQXFCOztBQUVyQjs7QUFFQSxzQkFBc0I7O0FBRXRCO0FBQ0E7QUFDQTtBQUNBLEdBQUc7QUFDSDtBQUNBLGtCQUFrQixhQUFhO0FBQy9CLGlCQUFpQixzQkFBc0I7QUFDdkMsYUFBYTtBQUNiLEdBQUc7O0FBRUg7QUFDQTs7QUFFQSxHQUFHOztBQUVIO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLHVDQUF1QyxRQUFROztBQUUvQztBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvREFBb0QscURBQXFEOztBQUV6Rzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEscUJBQXFCLG9CQUFvQjs7QUFFekM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsMENBQTBDLFFBQVE7O0FBRWxEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsT0FBTzs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQSxhQUFhLFFBQVE7O0FBRXJCOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBLDJDQUEyQzs7QUFFM0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxvQ0FBb0M7QUFDcEM7O0FBRUE7QUFDQTtBQUNBOztBQUVBLG1CQUFtQixXQUFXOztBQUU5Qjs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxRQUFROztBQUVuRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CO0FBQ3BCOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsR0FBRzs7QUFFSDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7OztBQUlBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxpREFBaUQsUUFBUTtBQUN6RDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBO0FBQ0EsWUFBWTtBQUNaO0FBQ0E7QUFDQTtBQUNBLFlBQVk7QUFDWjtBQUNBLFlBQVk7O0FBRVo7O0FBRUEsMENBQTBDLEtBQUs7O0FBRS9DOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxpQ0FBaUM7O0FBRWpDO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLE9BQU87O0FBRTNCOztBQUVBLDBCQUEwQiwrREFBK0Q7O0FBRXpGLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQSx5QkFBeUIsMERBQTBEOztBQUVuRixLQUFLOztBQUVMOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEscUJBQXFCLDREQUE0RDs7QUFFakY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseUNBQXlDLFFBQVE7O0FBRWpEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLHVHQUF1Rzs7QUFFdkc7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLFFBQVE7O0FBRW5EOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLFFBQVE7O0FBRW5EOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsWUFBWTs7QUFFWjs7QUFFQTs7QUFFQTs7QUFFQSxVQUFVOztBQUVWOztBQUVBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUE7O0FBRUEsUUFBUTs7QUFFUjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxTQUFTOztBQUVUOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLFFBQVE7O0FBRW5EOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFVBQVU7O0FBRVY7O0FBRUE7O0FBRUEsU0FBUzs7QUFFVDs7QUFFQTs7QUFFQSxRQUFROztBQUVSOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBLHVCQUF1QixZQUFZOztBQUVuQzs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxRQUFROztBQUVuRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxRQUFROztBQUVSOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLG9CQUFvQixPQUFPOztBQUUzQjs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFCQUFxQixPQUFPOztBQUU1Qjs7QUFFQSxzQkFBc0Isb0JBQW9COztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxVQUFVOztBQUVWOztBQUVBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUE7O0FBRUEsUUFBUTs7QUFFUjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxTQUFTOztBQUVUOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFCQUFxQixPQUFPOztBQUU1Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxRQUFROztBQUVSOztBQUVBOztBQUVBLHVCQUF1QixvQkFBb0I7O0FBRTNDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsU0FBUzs7QUFFVDs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUEsdUJBQXVCLG9CQUFvQjs7QUFFM0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsU0FBUzs7QUFFVDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUksMkpBQTJKOztBQUUvSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsb0JBQW9CLHFCQUFxQjs7QUFFekM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLHFCQUFxQixPQUFPOztBQUU1QjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixPQUFPOztBQUUzQjs7QUFFQTs7QUFFQSwwQkFBMEIsZ0NBQWdDOztBQUUxRDs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEseUJBQXlCLGdDQUFnQzs7QUFFekQ7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQSwyQ0FBMkMsUUFBUTs7QUFFbkQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxxQkFBcUIscUJBQXFCOztBQUUxQztBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLG9CQUFvQixPQUFPOztBQUUzQjs7QUFFQSwwQkFBMEIsZ0NBQWdDOztBQUUxRDs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUosMENBQTBDLFFBQVE7O0FBRWxEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSx5QkFBeUIsZ0NBQWdDOztBQUV6RDs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHlDQUF5QyxRQUFROztBQUVqRDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsc0JBQXNCLHFCQUFxQjs7QUFFM0M7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEscUJBQXFCLHFCQUFxQjs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLHNCQUFzQixxQkFBcUI7O0FBRTNDO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsVUFBVTs7QUFFVjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQkFBcUI7O0FBRXJCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQSw2QkFBNkI7O0FBRTdCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0JBQXdCLHVDQUF1Qzs7QUFFL0Q7O0FBRUE7O0FBRUE7O0FBRUEsd0JBQXdCLDBDQUEwQzs7QUFFbEU7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTzs7QUFFUCxNQUFNOztBQUVOO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxPQUFPOztBQUVQOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsUUFBUTs7QUFFUjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxDQUFDOztBQUVEO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUEsQ0FBQzs7QUFFRDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxvQkFBb0IscUJBQXFCO0FBQ3pDLG9CQUFvQixtQkFBbUI7QUFDdkMscUJBQXFCO0FBQ3JCO0FBQ0EsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLGdDQUFnQyw0Q0FBNEM7O0FBRTVFOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsb0JBQW9CLHdCQUF3Qjs7QUFFNUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsMEJBQTBCLHFCQUFxQjs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLGtDQUFrQyx5QkFBeUI7O0FBRTNEO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsa0NBQWtDLDBCQUEwQjs7QUFFNUQ7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsUUFBUTs7QUFFUjs7QUFFQSw2Q0FBNkM7O0FBRTdDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSwyQkFBMkIsdUJBQXVCOztBQUVsRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsMEJBQTBCOztBQUU5QztBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHdCQUF3Qjs7QUFFNUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0JBQXNCLHdCQUF3Qjs7QUFFOUM7O0FBRUE7QUFDQTtBQUNBOztBQUVBLFFBQVE7O0FBRVI7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxNQUFNOztBQUVOO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsb0JBQW9CLG9CQUFvQjs7QUFFeEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLHFCQUFxQixrQkFBa0I7O0FBRXZDOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0Isd0JBQXdCOztBQUU1QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJCQUEyQixzQ0FBc0M7O0FBRWpFOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBLElBQUk7O0FBRUosd0NBQXdDOztBQUV4Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxpQkFBaUIsY0FBYzs7QUFFL0I7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsbUVBQW1FOztBQUVuRTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw4Q0FBOEM7O0FBRTlDOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsNkVBQTZFOztBQUU3RTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsc0JBQXNCOztBQUV6Qzs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSx5Q0FBeUMsUUFBUTs7QUFFakQ7O0FBRUEsOENBQThDLFFBQVE7O0FBRXREOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNCQUFzQixtQkFBbUI7O0FBRXpDOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxRQUFROztBQUVSOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxRQUFROztBQUVSOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsa0JBQWtCO0FBQ2xCLHdCQUF3Qjs7QUFFeEIsd0NBQXdDLE9BQU87O0FBRS9DOztBQUVBLDhDQUE4QyxRQUFROztBQUV0RDs7QUFFQTs7QUFFQSx5Q0FBeUMsUUFBUTs7QUFFakQ7O0FBRUE7O0FBRUEsNkNBQTZDO0FBQzdDLHVEQUF1RDtBQUN2RCxvREFBb0Q7O0FBRXBEOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7QUFDQSxzQkFBc0I7O0FBRXRCLElBQUk7O0FBRUo7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsOEJBQThCOztBQUU5QjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsYUFBYTtBQUNiO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0JBQXdCOztBQUV4Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG9GQUFvRixTQUFTOztBQUU3RjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLE9BQU87O0FBRVA7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDhDQUE4Qzs7QUFFOUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUEsa0RBQWtEOztBQUVsRDs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLHVCQUF1QixlQUFlOztBQUV0QztBQUNBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUJBQXVCLHFCQUFxQjs7QUFFNUM7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU47QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNkJBQTZCOztBQUU3Qjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDBDQUEwQyxPQUFPOztBQUVqRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx5Q0FBeUMsT0FBTzs7QUFFaEQ7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxTQUFTOztBQUVUO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxPQUFPOztBQUVsRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseUNBQXlDLE9BQU87O0FBRWhEOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLE1BQU07O0FBRU47O0FBRUE7QUFDQTtBQUNBLDhDQUE4Qyx5Q0FBeUM7O0FBRXZGO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsK0VBQStFOztBQUUvRTs7QUFFQSxxREFBcUQsT0FBTzs7QUFFNUQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLE9BQU87O0FBRWxEOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNEQUFzRDs7QUFFdEQ7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLHNEQUFzRDs7QUFFdEQ7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTtBQUNOO0FBQ0E7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDhCQUE4QjtBQUM5Qiw0QkFBNEI7O0FBRTVCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdDQUF3QyxPQUFPOztBQUUvQzs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBLDZCQUE2Qjs7QUFFN0I7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsUUFBUTs7QUFFUjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQSxLQUFLOztBQUVMOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsbUVBQW1FLGVBQWU7O0FBRWxGOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxtRUFBbUUsZUFBZTs7QUFFbEY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHdCQUF3QjtBQUN4Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxpSUFBaUk7QUFDakk7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNEJBQTRCLGVBQWU7O0FBRTNDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsb0NBQW9DLE9BQU87O0FBRTNDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsT0FBTzs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUNBQW1DLE9BQU87O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQyxPQUFPOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsZ0JBQWdCOztBQUVwQzs7QUFFQSxxQkFBcUIsbUJBQW1COztBQUV4Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixnQkFBZ0I7O0FBRXBDOztBQUVBLHFCQUFxQixtQkFBbUI7O0FBRXhDOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOzs7QUFHQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGVBQWUsbUJBQW1COztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx5QkFBeUIsNkRBQTZEOztBQUV0Rjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7OztBQUlBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQyxPQUFPOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQyxPQUFPOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsV0FBVyxPQUFPOztBQUVsQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0MsT0FBTzs7QUFFN0M7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsNkJBQTZCOztBQUVoRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQiw2QkFBNkI7O0FBRWhEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx5Q0FBeUMsT0FBTzs7QUFFaEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTCw4QkFBOEI7O0FBRTlCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLE9BQU87O0FBRTFCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGlCQUFpQjs7QUFFakI7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw2Q0FBNkMsUUFBUTs7QUFFckQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLFFBQVE7O0FBRW5EOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxRQUFROztBQUVuRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQ0FBMkMsUUFBUTs7QUFFbkQ7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBLHNDQUFzQyxRQUFROztBQUU5Qzs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxpREFBaUQ7QUFDakQ7QUFDQTs7QUFFQSw0REFBNEQ7QUFDNUQseUNBQXlDOztBQUV6QztBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLFFBQVE7O0FBRW5EOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDBDQUEwQyxPQUFPOztBQUVqRDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHFDQUFxQyxPQUFPOztBQUU1QztBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUIsV0FBVzs7QUFFOUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsV0FBVzs7QUFFOUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsV0FBVzs7QUFFOUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQzs7QUFFM0MscUNBQXFDOztBQUVyQyxtQkFBbUIsNkJBQTZCOztBQUVoRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSw0QkFBNEIsMkJBQTJCOztBQUV2RDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvREFBb0QsT0FBTzs7QUFFM0Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDOztBQUUzQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsNkJBQTZCOztBQUVoRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3QkFBd0Isa0JBQWtCOztBQUUxQzs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0EsbUJBQW1CLGlCQUFpQjs7QUFFcEMsb0JBQW9CLGNBQWM7O0FBRWxDOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsc0RBQXNEO0FBQ3REO0FBQ0E7O0FBRUEsNkRBQTZEO0FBQzdEOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0EsWUFBWSw4QkFBOEI7O0FBRTFDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsOERBQThELGVBQWU7O0FBRTdFOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG1CQUFtQixtQkFBbUI7O0FBRXRDOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSx3Q0FBd0MsT0FBTzs7QUFFL0M7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxzREFBc0QsT0FBTzs7QUFFN0Q7QUFDQSxxQkFBcUIsY0FBYzs7QUFFbkM7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0Esb0JBQW9CLG9CQUFvQjs7QUFFeEM7O0FBRUE7O0FBRUE7QUFDQSwrREFBK0QsT0FBTzs7QUFFdEU7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSx5RUFBeUUsT0FBTzs7QUFFaEY7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHlFQUF5RSxPQUFPOztBQUVoRjtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0NBQXdDLE9BQU87O0FBRS9DOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsaURBQWlELE9BQU87O0FBRXhEO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsMERBQTBELFdBQVc7QUFDckUsa0VBQWtFLFdBQVc7O0FBRTdFLG9EQUFvRCxTQUFTO0FBQzdEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx5Q0FBeUMsT0FBTzs7QUFFaEQ7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxxQ0FBcUMsT0FBTzs7QUFFNUM7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKLHlDQUF5QyxPQUFPOztBQUVoRDs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxpREFBaUQsT0FBTzs7QUFFeEQ7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxxQ0FBcUMsT0FBTzs7QUFFNUM7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQSxxQ0FBcUMsT0FBTzs7QUFFNUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLGlEQUFpRCxRQUFROztBQUV6RDs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsMERBQTBEOztBQUUxRDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxpREFBaUQsT0FBTzs7QUFFeEQ7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLGtDQUFrQyxRQUFROztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUEsaUNBQWlDLE9BQU87O0FBRXhDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxpREFBaUQsUUFBUTs7QUFFekQ7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFdBQVcsZ0JBQWdCOztBQUUzQjs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGlCQUFpQjtBQUNqQjs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixnQkFBZ0I7O0FBRW5DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixnQkFBZ0I7O0FBRW5DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxtQkFBbUIsZ0JBQWdCOztBQUVuQztBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxnQkFBZ0IsS0FBSyx5QkFBeUI7O0FBRTlDOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSx1QkFBdUI7O0FBRXZCOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsK0NBQStDOztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxtQkFBbUIsZUFBZTs7QUFFbEM7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7OztBQUdBOztBQUVBLG1CQUFtQixlQUFlOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3RkFBd0Y7O0FBRXhGOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLGVBQWU7O0FBRW5DO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUEsY0FBYzs7QUFFZDs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNkNBQTZDLE9BQU87O0FBRXBEOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQ0FBMkMsT0FBTzs7QUFFbEQ7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLE9BQU87O0FBRWxEO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNkNBQTZDLE9BQU87O0FBRXBEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxPQUFPOztBQUVsRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDJDQUEyQyxPQUFPOztBQUVsRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSwwQkFBMEI7O0FBRTFCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLDJDQUEyQyxPQUFPOztBQUVsRDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixnQkFBZ0I7O0FBRW5DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEseUNBQXlDLG1CQUFtQjs7QUFFNUQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxvQkFBb0IsZ0JBQWdCOztBQUVwQzs7QUFFQSxrREFBa0Q7O0FBRWxEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNkNBQTZDLE9BQU87O0FBRXBEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsMkNBQTJDLE9BQU87O0FBRWxEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSwyQ0FBMkMsT0FBTzs7QUFFbEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0MsT0FBTzs7QUFFN0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsaUNBQWlDOztBQUVqQzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsbUJBQW1CLDRCQUE0Qjs7QUFFL0M7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixlQUFlOztBQUVsQzs7QUFFQTtBQUNBOztBQUVBLG9CQUFvQiw0QkFBNEI7O0FBRWhEOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsY0FBYzs7QUFFakMsb0JBQW9CLDJCQUEyQjs7QUFFL0M7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDBCQUEwQixlQUFlOztBQUV6Qzs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGVBQWU7O0FBRWxDOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxvQkFBb0IscUJBQXFCOztBQUV6Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQkFBcUIscUJBQXFCOztBQUUxQzs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLG9CQUFvQjs7QUFFeEMscUJBQXFCLG9CQUFvQjs7QUFFekM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsb0JBQW9CLHFCQUFxQjs7QUFFekM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxvQkFBb0IscUJBQXFCOztBQUV6QztBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixvQkFBb0I7O0FBRXhDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsZ0NBQWdDOztBQUVoQyxJQUFJOztBQUVKLDRCQUE0Qjs7QUFFNUI7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLG9CQUFvQixvQkFBb0I7O0FBRXhDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsV0FBVzs7QUFFL0I7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxxQkFBcUIsV0FBVzs7QUFFaEM7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsVUFBVTs7QUFFOUIscUJBQXFCLDBCQUEwQjs7QUFFL0M7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLE9BQU87O0FBRVA7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQix5QkFBeUI7O0FBRTdDO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHlCQUF5Qjs7QUFFN0M7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IscUJBQXFCOztBQUV6Qzs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsMkJBQTJCLHlCQUF5Qjs7QUFFcEQ7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0Esb0JBQW9CLGdCQUFnQjs7QUFFcEM7O0FBRUE7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBOztBQUVBLFlBQVksVUFBVTtBQUN0QjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLHNCQUFzQiwrQkFBK0IsSUFBSSwrQkFBK0IsSUFBSSwrQkFBK0I7QUFDM0gsc0JBQXNCLCtCQUErQixJQUFJLCtCQUErQixJQUFJLCtCQUErQjtBQUMzSCxzQkFBc0IsK0JBQStCLElBQUksK0JBQStCLElBQUksK0JBQStCOztBQUUzSDtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EscUJBQXFCLE9BQU87O0FBRTVCO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxzQkFBc0IsVUFBVSxJQUFJLFVBQVU7QUFDOUMsNkJBQTZCLFVBQVUsSUFBSSxVQUFVOztBQUVyRDs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsYUFBYSxpQkFBaUI7QUFDOUI7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMENBQTBDLE9BQU87O0FBRWpEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNENBQTRDLE9BQU87O0FBRW5EOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsMENBQTBDLE9BQU87O0FBRWpEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSwwQ0FBMEMsT0FBTzs7QUFFakQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseUVBQXlFO0FBQ3pFOztBQUVBO0FBQ0E7O0FBRUEsc0JBQXNCLGNBQWM7O0FBRXBDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsU0FBUzs7QUFFNUIsR0FBRzs7QUFFSCx1QkFBdUIsWUFBWTs7QUFFbkM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSwyQ0FBMkM7O0FBRTNDO0FBQ0E7O0FBRUEsbUJBQW1CO0FBQ25CO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDJDQUEyQzs7QUFFM0M7O0FBRUEsbUJBQW1CO0FBQ25CO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSx3Q0FBd0MsU0FBUzs7QUFFakQ7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLGNBQWMsa0JBQWtCOztBQUVoQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSw4QkFBOEIsK0JBQStCOztBQUU3RDs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLDhDQUE4Qzs7QUFFOUM7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxnQkFBZ0IsWUFBWTs7QUFFNUI7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLGdHQUFnRzs7QUFFaEc7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsNENBQTRDOztBQUU1Qyx5REFBeUQ7QUFDekQseURBQXlEO0FBQ3pELHlEQUF5RDtBQUN6RCx5REFBeUQ7O0FBRXpEOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBLDRDQUE0QztBQUM1QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EscUNBQXFDLFNBQVM7O0FBRTlDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSw4QkFBOEIsT0FBTzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUJBQXVCO0FBQ3ZCLDBCQUEwQjtBQUMxQixvQkFBb0I7O0FBRXBCO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGtCQUFrQjs7QUFFckM7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixzQkFBc0I7O0FBRXpDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGtCQUFrQixvQkFBb0I7O0FBRXRDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQTs7QUFFQSxpS0FBaUs7O0FBRWpLOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsMEJBQTBCOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsUUFBUTs7QUFFaEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBLDZCQUE2Qjs7QUFFN0IsdUNBQXVDLFFBQVE7O0FBRS9DOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0E7OztBQUdBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx5Q0FBeUM7O0FBRXpDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUEsK0JBQStCOztBQUUvQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFFBQVE7O0FBRVI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsT0FBTzs7QUFFUDtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0E7O0FBRUEsZ0VBQWdFLFFBQVE7O0FBRXhFO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHVDQUF1QyxRQUFROztBQUUvQzs7QUFFQTs7QUFFQSwrREFBK0QsUUFBUTs7QUFFdkU7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7OztBQUdBOztBQUVBLG9CQUFvQixtQkFBbUI7O0FBRXZDLCtCQUErQixPQUFPOztBQUV0QztBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsMENBQTBDLFFBQVE7O0FBRWxEOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdDQUF3QyxRQUFROztBQUVoRDtBQUNBOztBQUVBLHlDQUF5QyxRQUFROztBQUVqRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsVUFBVTs7QUFFOUI7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsb0JBQW9CLFlBQVk7O0FBRWhDLHFCQUFxQixVQUFVOztBQUUvQjs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBLGtCQUFrQixvQkFBb0I7QUFDdEMsb0NBQW9DLFFBQVE7O0FBRTVDO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSwwQ0FBMEMsUUFBUTs7QUFFbEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsUUFBUTs7QUFFaEQ7QUFDQTs7QUFFQSx5Q0FBeUMsUUFBUTs7QUFFakQ7O0FBRUE7O0FBRUE7O0FBRUEsUUFBUTs7QUFFUjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CO0FBQ3BCOztBQUVBOztBQUVBLHNCQUFzQixVQUFVOztBQUVoQztBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsc0JBQXNCLFVBQVU7O0FBRWhDO0FBQ0E7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQSxzQkFBc0IsVUFBVTs7QUFFaEM7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxzQkFBc0IsVUFBVTs7QUFFaEM7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSx3Q0FBd0MsUUFBUTs7QUFFaEQ7QUFDQTs7QUFFQTtBQUNBOztBQUVBOzs7QUFHQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLDBEQUEwRCxRQUFROztBQUVsRTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7O0FBR0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7OztBQUdBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7OztBQUdBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDRDQUE0QyxRQUFROztBQUVwRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUEsaUNBQWlDOztBQUVqQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxtQkFBbUIsa0JBQWtCOztBQUVyQyxvQkFBb0Isb0JBQW9COztBQUV4Qzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGlCQUFpQjs7QUFFcEM7O0FBRUEsb0JBQW9CLG1CQUFtQjs7QUFFdkM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSixvQkFBb0IsbUJBQW1COztBQUV2Qzs7QUFFQSxnREFBZ0Q7O0FBRWhEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7OztBQUdBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQ0FBMkMsT0FBTzs7QUFFbEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLE9BQU87O0FBRWxEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsOENBQThDLE9BQU87O0FBRXJEOztBQUVBO0FBQ0E7QUFDQSxvQ0FBb0M7O0FBRXBDOztBQUVBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3Qzs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDRDQUE0QyxRQUFROztBQUVwRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0MsT0FBTzs7QUFFN0M7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsb0JBQW9CLHNCQUFzQjs7QUFFMUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxxQkFBcUIscUJBQXFCOztBQUUxQzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IscUJBQXFCOztBQUV6QyxxQkFBcUIsb0JBQW9COztBQUV6QztBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxtQkFBbUIscUJBQXFCOztBQUV4QyxvQkFBb0Isc0JBQXNCOztBQUUxQztBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIscUJBQXFCOztBQUV4QyxvQkFBb0Isc0JBQXNCOztBQUUxQzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsbUJBQW1CLHNCQUFzQjs7QUFFekM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsb0JBQW9CLHFCQUFxQjs7QUFFekM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsc0JBQXNCOztBQUV6QyxvQkFBb0IscUJBQXFCOztBQUV6Qzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUM7O0FBRXJDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IscUJBQXFCOztBQUV6Qzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsb0JBQW9CLHFCQUFxQjs7QUFFekM7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLHNCQUFzQjs7QUFFMUMscUJBQXFCLHFCQUFxQjs7QUFFMUM7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0Isc0JBQXNCOztBQUUxQyxxQkFBcUIscUJBQXFCOztBQUUxQztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLGtCQUFrQixtREFBbUQ7O0FBRXJFOztBQUVBOztBQUVBLHlDQUF5QyxRQUFROztBQUVqRDs7QUFFQTtBQUNBOztBQUVBLGdFQUFnRSxPQUFPOztBQUV2RSx1QkFBdUIsT0FBTzs7QUFFOUI7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxpREFBaUQsT0FBTzs7QUFFeEQsc0JBQXNCLE9BQU87O0FBRTdCO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxrQkFBa0IsUUFBUSxHQUFHLFFBQVEsR0FBRyxRQUFRLEdBQUcsTUFBTSxHQUFHLE1BQU0sR0FBRyxNQUFNO0FBQzNFLGtCQUFrQixNQUFNLEdBQUcsTUFBTSxHQUFHLE1BQU0sR0FBRyxRQUFRLEdBQUcsUUFBUSxHQUFHLFFBQVEsR0FBRzs7QUFFOUU7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLENBQUM7O0FBRUQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUI7O0FBRW5COztBQUVBLHNDQUFzQztBQUN0QztBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUI7O0FBRW5CO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxJQUFJO0FBQ0o7O0FBRUE7O0FBRUE7QUFDQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0M7QUFDdEM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQjs7QUFFbkI7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQzs7QUFFdEM7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQjs7QUFFbkI7O0FBRUEsc0NBQXNDOztBQUV0Qzs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBLG1CQUFtQjs7QUFFbkI7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLDRCQUE0Qjs7QUFFNUI7O0FBRUEsNkNBQTZDOztBQUU3Qzs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLGtCQUFrQixTQUFTOztBQUUzQjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsaUNBQWlDLHVCQUF1Qjs7QUFFeEQ7O0FBRUEsbUJBQW1CLGNBQWM7O0FBRWpDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsa0NBQWtDOztBQUVsQztBQUNBLG9DQUFvQzs7QUFFcEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSx3Q0FBd0M7O0FBRXhDOztBQUVBOztBQUVBLElBQUk7O0FBRUosR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUosR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsa0JBQWtCLHdCQUF3Qjs7QUFFMUM7QUFDQTs7QUFFQTtBQUNBOztBQUVBLG1CQUFtQix3QkFBd0I7O0FBRTNDOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixlQUFlOztBQUVuQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGtCQUFrQix3QkFBd0I7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGtCQUFrQix3QkFBd0I7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxrQkFBa0IsZUFBZTs7QUFFakM7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSxtQkFBbUIsY0FBYzs7QUFFakM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQSxxQkFBcUIsY0FBYzs7QUFFbkM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQztBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxlQUFlO0FBQ2Y7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQzs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLHFDQUFxQzs7QUFFckM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxtQkFBbUIsY0FBYzs7QUFFakM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsbUJBQW1CLGNBQWM7O0FBRWpDO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUIsY0FBYzs7QUFFakM7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1DQUFtQzs7QUFFbkM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU4saUNBQWlDOztBQUVqQzs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLFNBQVM7O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsc0NBQXNDLFNBQVM7O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsU0FBUzs7QUFFVDs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsYUFBYTs7QUFFaEM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsU0FBUzs7QUFFakQ7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsZUFBZTs7QUFFbEM7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsc0JBQXNCLGNBQWM7O0FBRXBDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsc0JBQXNCLGNBQWM7O0FBRXBDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdGQUF3RixjQUFjOztBQUV0Rzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsbUNBQW1DLGdCQUFnQjs7QUFFbkQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSwwQ0FBMEMsU0FBUzs7QUFFbkQ7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsMENBQTBDLFNBQVM7O0FBRW5EOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsbUJBQW1CLHFCQUFxQjs7QUFFeEM7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLG1CQUFtQixzQkFBc0I7O0FBRXpDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0EsNkNBQTZDLFFBQVE7O0FBRXJEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLG1CQUFtQiw0QkFBNEI7O0FBRS9DOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLGlCQUFpQiwwQkFBMEI7O0FBRTNDOztBQUVBLHVCQUF1Qiw0Q0FBNEM7O0FBRW5FOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsc0JBQXNCLDhDQUE4Qzs7QUFFcEU7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsc0NBQXNDLFNBQVM7O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQix3QkFBd0I7O0FBRTNDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQix3QkFBd0I7O0FBRTNDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQix3QkFBd0I7O0FBRTNDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQix3QkFBd0I7O0FBRTNDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFVBQVU7O0FBRVY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBOztBQUVBLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHlDQUF5QyxPQUFPOztBQUVoRDtBQUNBOztBQUVBLDZDQUE2Qzs7QUFFN0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxnQ0FBZ0MsY0FBYzs7QUFFOUM7O0FBRUE7O0FBRUEsV0FBVzs7QUFFWDs7QUFFQSx5REFBeUQsa0NBQWtDO0FBQzNGLGtEQUFrRCxRQUFROztBQUUxRDtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsU0FBUzs7QUFFVDs7QUFFQSxVQUFVOztBQUVWOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUEsTUFBTTs7QUFFTix3Q0FBd0MsYUFBYSxtQkFBbUIsZ0JBQWdCLElBQUksb0JBQW9COztBQUVoSDs7QUFFQSxLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsUUFBUTs7QUFFUjtBQUNBLGlDQUFpQztBQUNqQztBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLO0FBQ0w7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsNENBQTRDLFFBQVE7O0FBRXBEO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSztBQUNMOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSw0Q0FBNEMsUUFBUTs7QUFFcEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLO0FBQ0w7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsaUJBQWlCOztBQUVwQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLHFDQUFxQyxRQUFROztBQUU3Qzs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNCQUFzQixXQUFXOztBQUVqQyxzQkFBc0I7O0FBRXRCLHVCQUF1QiwwQkFBMEI7O0FBRWpEO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsbUJBQW1CLGlCQUFpQjs7QUFFcEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0Esa0RBQWtEOztBQUVsRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOzs7QUFHSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsK0JBQStCOztBQUUvQjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLE9BQU87O0FBRTFCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSx3REFBd0Q7O0FBRXhEO0FBQ0EsNERBQTREO0FBQzVEO0FBQ0E7O0FBRUE7QUFDQSxnRUFBZ0U7QUFDaEU7QUFDQSxxRUFBcUU7QUFDckU7QUFDQSxzRUFBc0U7O0FBRXRFOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLE9BQU87O0FBRTFCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsT0FBTzs7QUFFMUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLE9BQU87O0FBRTFCOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUNBQW1DO0FBQ25DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw4QkFBOEI7O0FBRTlCOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsc0NBQXNDLFFBQVE7O0FBRTlDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSSxjQUFjOztBQUVsQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsaURBQWlELFFBQVE7O0FBRXpEO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx1Q0FBdUMsU0FBUzs7QUFFaEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUMsT0FBTzs7QUFFNUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBLHFDQUFxQyxPQUFPOztBQUU1Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUMsT0FBTzs7QUFFNUM7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsUUFBUTs7QUFFUix3RUFBd0UsV0FBVzs7QUFFbkY7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0I7QUFDcEI7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxxQ0FBcUMsT0FBTzs7QUFFNUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLGlCQUFpQjs7QUFFckM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHNDQUFzQyxRQUFROztBQUU5QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1QyxRQUFROztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxTQUFTOztBQUVUOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLHNDQUFzQyxRQUFROztBQUU5QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1QyxRQUFROztBQUUvQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxTQUFTOztBQUVUOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxxQ0FBcUMsT0FBTzs7QUFFNUM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUEsOENBQThDOztBQUU5Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxrRUFBa0U7O0FBRWxFOztBQUVBOztBQUVBOztBQUVBO0FBQ0Esa0VBQWtFOztBQUVsRTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSxNQUFNOztBQUVOO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IscUJBQXFCOztBQUV6Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsNkJBQTZCOztBQUVqRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsbUJBQW1COztBQUV2QztBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1COztBQUVuQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTtBQUNOOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSixtRUFBbUUsK0JBQStCOztBQUVsRyxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU4sS0FBSzs7QUFFTDs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkVBQTJFOztBQUUzRTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw2Q0FBNkMsT0FBTzs7QUFFcEQ7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw2Q0FBNkMsT0FBTzs7QUFFcEQ7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUIsaUJBQWlCOztBQUVwQzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixjQUFjOztBQUVsQzs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLDZDQUE2QyxTQUFTOztBQUV0RDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBLGlEQUFpRCxTQUFTOztBQUUxRDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsNEJBQTRCLGNBQWM7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxtQkFBbUIsb0JBQW9COztBQUV2Qzs7QUFFQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLGNBQWM7O0FBRWxDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxtQkFBbUIsY0FBYzs7QUFFakM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGNBQWM7O0FBRWpDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLDZDQUE2QyxHQUFHO0FBQ2hEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxlQUFlOztBQUVmO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3RUFBd0UsU0FBUzs7QUFFakY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0VBQXdFLFNBQVM7O0FBRWpGOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHdFQUF3RSxTQUFTOztBQUVqRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQSxZQUFZLFFBQVE7QUFDcEIsYUFBYTtBQUNiO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLHFCQUFxQixxQkFBcUI7O0FBRTFDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQ0FBc0MsU0FBUzs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9DQUFvQyxTQUFTOztBQUU3Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQ0FBb0MsU0FBUzs7QUFFN0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsb0NBQW9DLFNBQVM7O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxzQkFBc0IseUJBQXlCOztBQUUvQzs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLGtEQUFrRDs7QUFFbEQ7O0FBRUEsSUFBSSxnRUFBZ0U7O0FBRXBFOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSw0QkFBNEI7QUFDNUI7O0FBRUE7QUFDQSxpQ0FBaUM7O0FBRWpDLHlDQUF5QyxTQUFTOztBQUVsRDs7QUFFQTs7QUFFQSxvQkFBb0I7QUFDcEIsMEJBQTBCLGFBQWE7QUFDdkMsdUJBQXVCO0FBQ3ZCLG9DQUFvQzs7QUFFcEM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxLQUFLO0FBQ0w7O0FBRUE7O0FBRUE7QUFDQSxJQUFJO0FBQ0o7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSx5Q0FBeUMsU0FBUzs7QUFFbEQ7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxvQ0FBb0MsU0FBUzs7QUFFN0M7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxvQ0FBb0MsU0FBUzs7QUFFN0M7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBLEtBQUs7O0FBRUwsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSx5Q0FBeUMsU0FBUzs7QUFFbEQ7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLG9DQUFvQyxTQUFTOztBQUU3QztBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSx5Q0FBeUMsU0FBUzs7QUFFbEQ7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxxQ0FBcUMsU0FBUzs7QUFFOUM7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxxQ0FBcUMsU0FBUzs7QUFFOUM7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxNQUFNOztBQUVOLEtBQUs7O0FBRUwsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLG9EQUFvRCxTQUFTOztBQUU3RDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLG1CQUFtQixlQUFlOztBQUVsQztBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEscUNBQXFDOztBQUVyQztBQUNBOztBQUVBLDJCQUEyQjtBQUMzQixpQ0FBaUM7O0FBRWpDO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSwrQkFBK0I7O0FBRS9CLHVCQUF1QjtBQUN2Qix1QkFBdUI7O0FBRXZCLGlDQUFpQzs7QUFFakMsK0JBQStCO0FBQy9CLDZCQUE2Qjs7QUFFN0I7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxpQkFBaUI7QUFDakIsd0JBQXdCO0FBQ3hCLHlCQUF5Qjs7QUFFekI7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxLQUFLOzs7QUFHTCw0QkFBNEI7QUFDNUI7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsK0NBQStDLFNBQVM7O0FBRXhEO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSwrQ0FBK0MsU0FBUzs7QUFFeEQ7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE9BQU87O0FBRVA7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUEsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE1BQU07O0FBRU47O0FBRUEsSUFBSSxPQUFPOztBQUVYOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHFEQUFxRDtBQUNyRDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLE9BQU87O0FBRVAsTUFBTTs7QUFFTjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLE9BQU87O0FBRVA7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsbUJBQW1CLGVBQWU7O0FBRWxDO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EseUNBQXlDLFNBQVM7O0FBRWxEOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSx5Q0FBeUMsU0FBUzs7QUFFbEQ7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxzQkFBc0I7QUFDdEI7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOzs7QUFHQSx1QkFBdUI7QUFDdkI7O0FBRUEsb0NBQW9DOzs7QUFHcEMsa0NBQWtDO0FBQ2xDOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSztBQUNMOztBQUVBOztBQUVBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSztBQUNMOztBQUVBOztBQUVBO0FBQ0EsSUFBSTtBQUNKO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSztBQUNMOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7OztBQUdBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsd0NBQXdDLFNBQVM7O0FBRWpEOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsOEJBQThCLFFBQVE7O0FBRXRDOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixnQkFBZ0I7O0FBRW5DOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsbUJBQW1CLGlCQUFpQjs7QUFFcEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxpQkFBaUI7QUFDakIsbUJBQW1CLDBCQUEwQjs7QUFFN0MsZ0NBQWdDOztBQUVoQzs7QUFFQSx1Q0FBdUM7O0FBRXZDOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsZ0RBQWdELFNBQVM7O0FBRXpEOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUNBQXVDLGdCQUFnQjs7QUFFdkQ7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3QkFBd0Isa0JBQWtCOztBQUUxQzs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLDhDQUE4QyxPQUFPOztBQUVyRDs7QUFFQSxvQkFBb0IscUJBQXFCOztBQUV6Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0EsV0FBVztBQUNYLFdBQVcsY0FBYztBQUN6QixVQUFVO0FBQ1YsYUFBYSxjQUFjO0FBQzNCO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBLElBQUk7O0FBRUosK0hBQStIO0FBQy9IO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHVDQUF1QyxPQUFPOztBQUU5Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3Q0FBd0MsT0FBTzs7QUFFL0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQSxrQkFBa0I7QUFDbEIsc0JBQXNCOztBQUV0Qjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLElBQUk7O0FBRUo7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsd0JBQXdCO0FBQ3hCLHNCQUFzQjtBQUN0QixjQUFjOztBQUVkOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixPQUFPOztBQUUxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxpQkFBaUI7QUFDakIsaUJBQWlCOztBQUVqQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsdUNBQXVDLFFBQVE7O0FBRS9DOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGtDQUFrQyxPQUFPOztBQUV6QztBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLDRDQUE0QyxnQ0FBZ0M7O0FBRTVFO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOzs7QUFHQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsbUJBQW1CLGtCQUFrQjs7QUFFckM7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSw0Q0FBNEMsZ0dBQWdHOztBQUU1STs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSwwQkFBMEIsa0JBQWtCOztBQUU1Qzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGtCQUFrQiw0QkFBNEI7O0FBRTlDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0EsNENBQTRDLGlEQUFpRDs7QUFFN0Y7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7O0FBR0E7QUFDQTtBQUNBO0FBQ0EseURBQXlELGdGQUFnRjs7QUFFekk7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSwyQ0FBMkMsaURBQWlEO0FBQzVGOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxJQUFJOztBQUVKOztBQUVBO0FBQ0E7O0FBRUEsc0NBQXNDLE9BQU87O0FBRTdDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBLDBDQUEwQyxnQkFBZ0I7O0FBRTFEO0FBQ0E7O0FBRUE7O0FBRUEsK0JBQStCO0FBQy9CLCtCQUErQjtBQUMvQiwrQkFBK0I7QUFDL0IsK0JBQStCOztBQUUvQjs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsNENBQTRDLHdDQUF3Qzs7QUFFcEY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsb0JBQW9CLGFBQWE7O0FBRWpDOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixXQUFXOztBQUU5Qjs7QUFFQTs7QUFFQSxvQkFBb0IsZUFBZTs7QUFFbkM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsNENBQTRDLHdDQUF3Qzs7QUFFcEY7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLDRDQUE0QyxnQ0FBZ0M7O0FBRTVFO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQSw0Q0FBNEMseURBQXlEOztBQUVyRztBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwrREFBK0QsNkRBQTZEO0FBQzVILCtEQUErRCw2REFBNkQ7QUFDNUgsK0RBQStELDZEQUE2RDtBQUM1SCwrREFBK0QsNkRBQTZEOztBQUU1SDs7QUFFQSwrREFBK0QsNkRBQTZEO0FBQzVILGdFQUFnRSw4REFBOEQ7QUFDOUgsZ0VBQWdFLDhEQUE4RDtBQUM5SCxnRUFBZ0UsOERBQThEOztBQUU5SDs7QUFFQSxnRUFBZ0UsOERBQThEO0FBQzlILGdFQUFnRSw4REFBOEQ7QUFDOUgsZ0VBQWdFLDhEQUE4RDtBQUM5SCxnRUFBZ0UsOERBQThEOztBQUU5SDs7QUFFQSx1REFBdUQscURBQXFEO0FBQzVHLHVEQUF1RCxxREFBcUQ7QUFDNUcsdURBQXVELHFEQUFxRDtBQUM1Ryx1REFBdUQscURBQXFEOztBQUU1Rzs7QUFFQSxpREFBaUQsK0NBQStDO0FBQ2hHLGlEQUFpRCwrQ0FBK0M7QUFDaEcsaURBQWlELCtDQUErQzs7QUFFaEc7O0FBRUEsNkRBQTZELDJEQUEyRDtBQUN4SCwwREFBMEQsd0RBQXdEOztBQUVsSDs7QUFFQSwwREFBMEQsd0RBQXdEO0FBQ2xILDBEQUEwRCx3REFBd0Q7O0FBRWxILDBEQUEwRCx3REFBd0Q7QUFDbEgsMERBQTBELHdEQUF3RDs7QUFFbEg7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyxPQUFPOztBQUU3Qzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSw0Q0FBNEMsa0NBQWtDOztBQUU5RTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxzQkFBc0Isb0JBQW9CO0FBQzFDLHNCQUFzQixvQkFBb0I7QUFDMUMsc0JBQXNCLG9CQUFvQjtBQUMxQyxzQkFBc0IscUJBQXFCO0FBQzNDLHVCQUF1QixxQkFBcUI7QUFDNUMsdUJBQXVCLHFCQUFxQjtBQUM1Qyx1QkFBdUIscUJBQXFCO0FBQzVDLHVCQUF1QixxQkFBcUI7O0FBRTVDOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSw0Q0FBNEMsa0NBQWtDOztBQUU5RTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQSw0Q0FBNEMsa0NBQWtDOztBQUU5RTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUEsMERBQTBELHNGQUFzRjs7QUFFaEo7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsZ0VBQWdFLGtDQUFrQztBQUNsRztBQUNBOztBQUVBLGdFQUFnRSxrQ0FBa0M7QUFDbEc7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLElBQUk7O0FBRUo7O0FBRUEsSUFBSTs7QUFFSjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSx3RUFBd0U7QUFDeEU7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLDRDQUE0Qyx3Q0FBd0M7O0FBRXBGOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSwyQ0FBMkMsT0FBTzs7QUFFbEQ7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EscUNBQXFDLGFBQWE7O0FBRWxEO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLGtDQUFrQztBQUNsQyxtQ0FBbUM7O0FBRW5DOztBQUVBOztBQUVBOztBQUVBLG1EQUFtRDtBQUNuRCxzQkFBc0I7O0FBRXRCLE9BQU87O0FBRVA7QUFDQSw2Q0FBNkM7QUFDN0M7QUFDQSwwQkFBMEI7O0FBRTFCOztBQUVBLE1BQU07O0FBRU47QUFDQSxpREFBaUQ7QUFDakQ7QUFDQTtBQUNBLG1GQUFtRjtBQUNuRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSx3Q0FBd0MsT0FBTzs7QUFFL0M7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsNkJBQTZCO0FBQzdCOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTCxxQ0FBcUMsZ0NBQWdDOztBQUVyRTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOzs7QUFHQTs7QUFFQTtBQUNBOztBQUVBLGdEQUFnRCxhQUFhOztBQUU3RDs7QUFFQTs7QUFFQSxnREFBZ0QsYUFBYTs7QUFFN0Q7O0FBRUEsd0JBQXdCLG1CQUFtQjs7QUFFM0M7QUFDQTs7QUFFQSwwQkFBMEIsMEJBQTBCOztBQUVwRDs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLFNBQVM7O0FBRVQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMENBQTBDLFFBQVE7O0FBRWxEO0FBQ0E7QUFDQTs7QUFFQSwwQ0FBMEMsUUFBUTs7QUFFbEQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNkRBQTZEOztBQUU3RCw2REFBNkQ7O0FBRTdEOztBQUVBLDBCQUEwQixvQkFBb0I7O0FBRTlDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGtFQUFrRTtBQUNsRTtBQUNBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFZzlOIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy90aHJlZS9idWlsZC90aHJlZS5tb2R1bGUuanM/OWE5MCJdLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEBsaWNlbnNlXG4gKiBDb3B5cmlnaHQgMjAxMC0yMDI0IFRocmVlLmpzIEF1dGhvcnNcbiAqIFNQRFgtTGljZW5zZS1JZGVudGlmaWVyOiBNSVRcbiAqL1xuY29uc3QgUkVWSVNJT04gPSAnMTY3JztcblxuY29uc3QgTU9VU0UgPSB7IExFRlQ6IDAsIE1JRERMRTogMSwgUklHSFQ6IDIsIFJPVEFURTogMCwgRE9MTFk6IDEsIFBBTjogMiB9O1xuY29uc3QgVE9VQ0ggPSB7IFJPVEFURTogMCwgUEFOOiAxLCBET0xMWV9QQU46IDIsIERPTExZX1JPVEFURTogMyB9O1xuY29uc3QgQ3VsbEZhY2VOb25lID0gMDtcbmNvbnN0IEN1bGxGYWNlQmFjayA9IDE7XG5jb25zdCBDdWxsRmFjZUZyb250ID0gMjtcbmNvbnN0IEN1bGxGYWNlRnJvbnRCYWNrID0gMztcbmNvbnN0IEJhc2ljU2hhZG93TWFwID0gMDtcbmNvbnN0IFBDRlNoYWRvd01hcCA9IDE7XG5jb25zdCBQQ0ZTb2Z0U2hhZG93TWFwID0gMjtcbmNvbnN0IFZTTVNoYWRvd01hcCA9IDM7XG5jb25zdCBGcm9udFNpZGUgPSAwO1xuY29uc3QgQmFja1NpZGUgPSAxO1xuY29uc3QgRG91YmxlU2lkZSA9IDI7XG5jb25zdCBOb0JsZW5kaW5nID0gMDtcbmNvbnN0IE5vcm1hbEJsZW5kaW5nID0gMTtcbmNvbnN0IEFkZGl0aXZlQmxlbmRpbmcgPSAyO1xuY29uc3QgU3VidHJhY3RpdmVCbGVuZGluZyA9IDM7XG5jb25zdCBNdWx0aXBseUJsZW5kaW5nID0gNDtcbmNvbnN0IEN1c3RvbUJsZW5kaW5nID0gNTtcbmNvbnN0IEFkZEVxdWF0aW9uID0gMTAwO1xuY29uc3QgU3VidHJhY3RFcXVhdGlvbiA9IDEwMTtcbmNvbnN0IFJldmVyc2VTdWJ0cmFjdEVxdWF0aW9uID0gMTAyO1xuY29uc3QgTWluRXF1YXRpb24gPSAxMDM7XG5jb25zdCBNYXhFcXVhdGlvbiA9IDEwNDtcbmNvbnN0IFplcm9GYWN0b3IgPSAyMDA7XG5jb25zdCBPbmVGYWN0b3IgPSAyMDE7XG5jb25zdCBTcmNDb2xvckZhY3RvciA9IDIwMjtcbmNvbnN0IE9uZU1pbnVzU3JjQ29sb3JGYWN0b3IgPSAyMDM7XG5jb25zdCBTcmNBbHBoYUZhY3RvciA9IDIwNDtcbmNvbnN0IE9uZU1pbnVzU3JjQWxwaGFGYWN0b3IgPSAyMDU7XG5jb25zdCBEc3RBbHBoYUZhY3RvciA9IDIwNjtcbmNvbnN0IE9uZU1pbnVzRHN0QWxwaGFGYWN0b3IgPSAyMDc7XG5jb25zdCBEc3RDb2xvckZhY3RvciA9IDIwODtcbmNvbnN0IE9uZU1pbnVzRHN0Q29sb3JGYWN0b3IgPSAyMDk7XG5jb25zdCBTcmNBbHBoYVNhdHVyYXRlRmFjdG9yID0gMjEwO1xuY29uc3QgQ29uc3RhbnRDb2xvckZhY3RvciA9IDIxMTtcbmNvbnN0IE9uZU1pbnVzQ29uc3RhbnRDb2xvckZhY3RvciA9IDIxMjtcbmNvbnN0IENvbnN0YW50QWxwaGFGYWN0b3IgPSAyMTM7XG5jb25zdCBPbmVNaW51c0NvbnN0YW50QWxwaGFGYWN0b3IgPSAyMTQ7XG5jb25zdCBOZXZlckRlcHRoID0gMDtcbmNvbnN0IEFsd2F5c0RlcHRoID0gMTtcbmNvbnN0IExlc3NEZXB0aCA9IDI7XG5jb25zdCBMZXNzRXF1YWxEZXB0aCA9IDM7XG5jb25zdCBFcXVhbERlcHRoID0gNDtcbmNvbnN0IEdyZWF0ZXJFcXVhbERlcHRoID0gNTtcbmNvbnN0IEdyZWF0ZXJEZXB0aCA9IDY7XG5jb25zdCBOb3RFcXVhbERlcHRoID0gNztcbmNvbnN0IE11bHRpcGx5T3BlcmF0aW9uID0gMDtcbmNvbnN0IE1peE9wZXJhdGlvbiA9IDE7XG5jb25zdCBBZGRPcGVyYXRpb24gPSAyO1xuY29uc3QgTm9Ub25lTWFwcGluZyA9IDA7XG5jb25zdCBMaW5lYXJUb25lTWFwcGluZyA9IDE7XG5jb25zdCBSZWluaGFyZFRvbmVNYXBwaW5nID0gMjtcbmNvbnN0IENpbmVvblRvbmVNYXBwaW5nID0gMztcbmNvbnN0IEFDRVNGaWxtaWNUb25lTWFwcGluZyA9IDQ7XG5jb25zdCBDdXN0b21Ub25lTWFwcGluZyA9IDU7XG5jb25zdCBBZ1hUb25lTWFwcGluZyA9IDY7XG5jb25zdCBOZXV0cmFsVG9uZU1hcHBpbmcgPSA3O1xuY29uc3QgQXR0YWNoZWRCaW5kTW9kZSA9ICdhdHRhY2hlZCc7XG5jb25zdCBEZXRhY2hlZEJpbmRNb2RlID0gJ2RldGFjaGVkJztcblxuY29uc3QgVVZNYXBwaW5nID0gMzAwO1xuY29uc3QgQ3ViZVJlZmxlY3Rpb25NYXBwaW5nID0gMzAxO1xuY29uc3QgQ3ViZVJlZnJhY3Rpb25NYXBwaW5nID0gMzAyO1xuY29uc3QgRXF1aXJlY3Rhbmd1bGFyUmVmbGVjdGlvbk1hcHBpbmcgPSAzMDM7XG5jb25zdCBFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZyA9IDMwNDtcbmNvbnN0IEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nID0gMzA2O1xuY29uc3QgUmVwZWF0V3JhcHBpbmcgPSAxMDAwO1xuY29uc3QgQ2xhbXBUb0VkZ2VXcmFwcGluZyA9IDEwMDE7XG5jb25zdCBNaXJyb3JlZFJlcGVhdFdyYXBwaW5nID0gMTAwMjtcbmNvbnN0IE5lYXJlc3RGaWx0ZXIgPSAxMDAzO1xuY29uc3QgTmVhcmVzdE1pcG1hcE5lYXJlc3RGaWx0ZXIgPSAxMDA0O1xuY29uc3QgTmVhcmVzdE1pcE1hcE5lYXJlc3RGaWx0ZXIgPSAxMDA0O1xuY29uc3QgTmVhcmVzdE1pcG1hcExpbmVhckZpbHRlciA9IDEwMDU7XG5jb25zdCBOZWFyZXN0TWlwTWFwTGluZWFyRmlsdGVyID0gMTAwNTtcbmNvbnN0IExpbmVhckZpbHRlciA9IDEwMDY7XG5jb25zdCBMaW5lYXJNaXBtYXBOZWFyZXN0RmlsdGVyID0gMTAwNztcbmNvbnN0IExpbmVhck1pcE1hcE5lYXJlc3RGaWx0ZXIgPSAxMDA3O1xuY29uc3QgTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyID0gMTAwODtcbmNvbnN0IExpbmVhck1pcE1hcExpbmVhckZpbHRlciA9IDEwMDg7XG5jb25zdCBVbnNpZ25lZEJ5dGVUeXBlID0gMTAwOTtcbmNvbnN0IEJ5dGVUeXBlID0gMTAxMDtcbmNvbnN0IFNob3J0VHlwZSA9IDEwMTE7XG5jb25zdCBVbnNpZ25lZFNob3J0VHlwZSA9IDEwMTI7XG5jb25zdCBJbnRUeXBlID0gMTAxMztcbmNvbnN0IFVuc2lnbmVkSW50VHlwZSA9IDEwMTQ7XG5jb25zdCBGbG9hdFR5cGUgPSAxMDE1O1xuY29uc3QgSGFsZkZsb2F0VHlwZSA9IDEwMTY7XG5jb25zdCBVbnNpZ25lZFNob3J0NDQ0NFR5cGUgPSAxMDE3O1xuY29uc3QgVW5zaWduZWRTaG9ydDU1NTFUeXBlID0gMTAxODtcbmNvbnN0IFVuc2lnbmVkSW50MjQ4VHlwZSA9IDEwMjA7XG5jb25zdCBVbnNpZ25lZEludDU5OTlUeXBlID0gMzU5MDI7XG5jb25zdCBBbHBoYUZvcm1hdCA9IDEwMjE7XG5jb25zdCBSR0JGb3JtYXQgPSAxMDIyO1xuY29uc3QgUkdCQUZvcm1hdCA9IDEwMjM7XG5jb25zdCBMdW1pbmFuY2VGb3JtYXQgPSAxMDI0O1xuY29uc3QgTHVtaW5hbmNlQWxwaGFGb3JtYXQgPSAxMDI1O1xuY29uc3QgRGVwdGhGb3JtYXQgPSAxMDI2O1xuY29uc3QgRGVwdGhTdGVuY2lsRm9ybWF0ID0gMTAyNztcbmNvbnN0IFJlZEZvcm1hdCA9IDEwMjg7XG5jb25zdCBSZWRJbnRlZ2VyRm9ybWF0ID0gMTAyOTtcbmNvbnN0IFJHRm9ybWF0ID0gMTAzMDtcbmNvbnN0IFJHSW50ZWdlckZvcm1hdCA9IDEwMzE7XG5jb25zdCBSR0JJbnRlZ2VyRm9ybWF0ID0gMTAzMjtcbmNvbnN0IFJHQkFJbnRlZ2VyRm9ybWF0ID0gMTAzMztcblxuY29uc3QgUkdCX1MzVENfRFhUMV9Gb3JtYXQgPSAzMzc3NjtcbmNvbnN0IFJHQkFfUzNUQ19EWFQxX0Zvcm1hdCA9IDMzNzc3O1xuY29uc3QgUkdCQV9TM1RDX0RYVDNfRm9ybWF0ID0gMzM3Nzg7XG5jb25zdCBSR0JBX1MzVENfRFhUNV9Gb3JtYXQgPSAzMzc3OTtcbmNvbnN0IFJHQl9QVlJUQ180QlBQVjFfRm9ybWF0ID0gMzU4NDA7XG5jb25zdCBSR0JfUFZSVENfMkJQUFYxX0Zvcm1hdCA9IDM1ODQxO1xuY29uc3QgUkdCQV9QVlJUQ180QlBQVjFfRm9ybWF0ID0gMzU4NDI7XG5jb25zdCBSR0JBX1BWUlRDXzJCUFBWMV9Gb3JtYXQgPSAzNTg0MztcbmNvbnN0IFJHQl9FVEMxX0Zvcm1hdCA9IDM2MTk2O1xuY29uc3QgUkdCX0VUQzJfRm9ybWF0ID0gMzc0OTI7XG5jb25zdCBSR0JBX0VUQzJfRUFDX0Zvcm1hdCA9IDM3NDk2O1xuY29uc3QgUkdCQV9BU1RDXzR4NF9Gb3JtYXQgPSAzNzgwODtcbmNvbnN0IFJHQkFfQVNUQ181eDRfRm9ybWF0ID0gMzc4MDk7XG5jb25zdCBSR0JBX0FTVENfNXg1X0Zvcm1hdCA9IDM3ODEwO1xuY29uc3QgUkdCQV9BU1RDXzZ4NV9Gb3JtYXQgPSAzNzgxMTtcbmNvbnN0IFJHQkFfQVNUQ182eDZfRm9ybWF0ID0gMzc4MTI7XG5jb25zdCBSR0JBX0FTVENfOHg1X0Zvcm1hdCA9IDM3ODEzO1xuY29uc3QgUkdCQV9BU1RDXzh4Nl9Gb3JtYXQgPSAzNzgxNDtcbmNvbnN0IFJHQkFfQVNUQ184eDhfRm9ybWF0ID0gMzc4MTU7XG5jb25zdCBSR0JBX0FTVENfMTB4NV9Gb3JtYXQgPSAzNzgxNjtcbmNvbnN0IFJHQkFfQVNUQ18xMHg2X0Zvcm1hdCA9IDM3ODE3O1xuY29uc3QgUkdCQV9BU1RDXzEweDhfRm9ybWF0ID0gMzc4MTg7XG5jb25zdCBSR0JBX0FTVENfMTB4MTBfRm9ybWF0ID0gMzc4MTk7XG5jb25zdCBSR0JBX0FTVENfMTJ4MTBfRm9ybWF0ID0gMzc4MjA7XG5jb25zdCBSR0JBX0FTVENfMTJ4MTJfRm9ybWF0ID0gMzc4MjE7XG5jb25zdCBSR0JBX0JQVENfRm9ybWF0ID0gMzY0OTI7XG5jb25zdCBSR0JfQlBUQ19TSUdORURfRm9ybWF0ID0gMzY0OTQ7XG5jb25zdCBSR0JfQlBUQ19VTlNJR05FRF9Gb3JtYXQgPSAzNjQ5NTtcbmNvbnN0IFJFRF9SR1RDMV9Gb3JtYXQgPSAzNjI4MztcbmNvbnN0IFNJR05FRF9SRURfUkdUQzFfRm9ybWF0ID0gMzYyODQ7XG5jb25zdCBSRURfR1JFRU5fUkdUQzJfRm9ybWF0ID0gMzYyODU7XG5jb25zdCBTSUdORURfUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCA9IDM2Mjg2O1xuY29uc3QgTG9vcE9uY2UgPSAyMjAwO1xuY29uc3QgTG9vcFJlcGVhdCA9IDIyMDE7XG5jb25zdCBMb29wUGluZ1BvbmcgPSAyMjAyO1xuY29uc3QgSW50ZXJwb2xhdGVEaXNjcmV0ZSA9IDIzMDA7XG5jb25zdCBJbnRlcnBvbGF0ZUxpbmVhciA9IDIzMDE7XG5jb25zdCBJbnRlcnBvbGF0ZVNtb290aCA9IDIzMDI7XG5jb25zdCBaZXJvQ3VydmF0dXJlRW5kaW5nID0gMjQwMDtcbmNvbnN0IFplcm9TbG9wZUVuZGluZyA9IDI0MDE7XG5jb25zdCBXcmFwQXJvdW5kRW5kaW5nID0gMjQwMjtcbmNvbnN0IE5vcm1hbEFuaW1hdGlvbkJsZW5kTW9kZSA9IDI1MDA7XG5jb25zdCBBZGRpdGl2ZUFuaW1hdGlvbkJsZW5kTW9kZSA9IDI1MDE7XG5jb25zdCBUcmlhbmdsZXNEcmF3TW9kZSA9IDA7XG5jb25zdCBUcmlhbmdsZVN0cmlwRHJhd01vZGUgPSAxO1xuY29uc3QgVHJpYW5nbGVGYW5EcmF3TW9kZSA9IDI7XG5jb25zdCBCYXNpY0RlcHRoUGFja2luZyA9IDMyMDA7XG5jb25zdCBSR0JBRGVwdGhQYWNraW5nID0gMzIwMTtcbmNvbnN0IFJHQkRlcHRoUGFja2luZyA9IDMyMDI7XG5jb25zdCBSR0RlcHRoUGFja2luZyA9IDMyMDM7XG5jb25zdCBUYW5nZW50U3BhY2VOb3JtYWxNYXAgPSAwO1xuY29uc3QgT2JqZWN0U3BhY2VOb3JtYWxNYXAgPSAxO1xuXG4vLyBDb2xvciBzcGFjZSBzdHJpbmcgaWRlbnRpZmllcnMsIG1hdGNoaW5nIENTUyBDb2xvciBNb2R1bGUgTGV2ZWwgNCBhbmQgV2ViR1BVIG5hbWVzIHdoZXJlIGF2YWlsYWJsZS5cbmNvbnN0IE5vQ29sb3JTcGFjZSA9ICcnO1xuY29uc3QgU1JHQkNvbG9yU3BhY2UgPSAnc3JnYic7XG5jb25zdCBMaW5lYXJTUkdCQ29sb3JTcGFjZSA9ICdzcmdiLWxpbmVhcic7XG5jb25zdCBEaXNwbGF5UDNDb2xvclNwYWNlID0gJ2Rpc3BsYXktcDMnO1xuY29uc3QgTGluZWFyRGlzcGxheVAzQ29sb3JTcGFjZSA9ICdkaXNwbGF5LXAzLWxpbmVhcic7XG5cbmNvbnN0IExpbmVhclRyYW5zZmVyID0gJ2xpbmVhcic7XG5jb25zdCBTUkdCVHJhbnNmZXIgPSAnc3JnYic7XG5cbmNvbnN0IFJlYzcwOVByaW1hcmllcyA9ICdyZWM3MDknO1xuY29uc3QgUDNQcmltYXJpZXMgPSAncDMnO1xuXG5jb25zdCBaZXJvU3RlbmNpbE9wID0gMDtcbmNvbnN0IEtlZXBTdGVuY2lsT3AgPSA3NjgwO1xuY29uc3QgUmVwbGFjZVN0ZW5jaWxPcCA9IDc2ODE7XG5jb25zdCBJbmNyZW1lbnRTdGVuY2lsT3AgPSA3NjgyO1xuY29uc3QgRGVjcmVtZW50U3RlbmNpbE9wID0gNzY4MztcbmNvbnN0IEluY3JlbWVudFdyYXBTdGVuY2lsT3AgPSAzNDA1NTtcbmNvbnN0IERlY3JlbWVudFdyYXBTdGVuY2lsT3AgPSAzNDA1NjtcbmNvbnN0IEludmVydFN0ZW5jaWxPcCA9IDUzODY7XG5cbmNvbnN0IE5ldmVyU3RlbmNpbEZ1bmMgPSA1MTI7XG5jb25zdCBMZXNzU3RlbmNpbEZ1bmMgPSA1MTM7XG5jb25zdCBFcXVhbFN0ZW5jaWxGdW5jID0gNTE0O1xuY29uc3QgTGVzc0VxdWFsU3RlbmNpbEZ1bmMgPSA1MTU7XG5jb25zdCBHcmVhdGVyU3RlbmNpbEZ1bmMgPSA1MTY7XG5jb25zdCBOb3RFcXVhbFN0ZW5jaWxGdW5jID0gNTE3O1xuY29uc3QgR3JlYXRlckVxdWFsU3RlbmNpbEZ1bmMgPSA1MTg7XG5jb25zdCBBbHdheXNTdGVuY2lsRnVuYyA9IDUxOTtcblxuY29uc3QgTmV2ZXJDb21wYXJlID0gNTEyO1xuY29uc3QgTGVzc0NvbXBhcmUgPSA1MTM7XG5jb25zdCBFcXVhbENvbXBhcmUgPSA1MTQ7XG5jb25zdCBMZXNzRXF1YWxDb21wYXJlID0gNTE1O1xuY29uc3QgR3JlYXRlckNvbXBhcmUgPSA1MTY7XG5jb25zdCBOb3RFcXVhbENvbXBhcmUgPSA1MTc7XG5jb25zdCBHcmVhdGVyRXF1YWxDb21wYXJlID0gNTE4O1xuY29uc3QgQWx3YXlzQ29tcGFyZSA9IDUxOTtcblxuY29uc3QgU3RhdGljRHJhd1VzYWdlID0gMzUwNDQ7XG5jb25zdCBEeW5hbWljRHJhd1VzYWdlID0gMzUwNDg7XG5jb25zdCBTdHJlYW1EcmF3VXNhZ2UgPSAzNTA0MDtcbmNvbnN0IFN0YXRpY1JlYWRVc2FnZSA9IDM1MDQ1O1xuY29uc3QgRHluYW1pY1JlYWRVc2FnZSA9IDM1MDQ5O1xuY29uc3QgU3RyZWFtUmVhZFVzYWdlID0gMzUwNDE7XG5jb25zdCBTdGF0aWNDb3B5VXNhZ2UgPSAzNTA0NjtcbmNvbnN0IER5bmFtaWNDb3B5VXNhZ2UgPSAzNTA1MDtcbmNvbnN0IFN0cmVhbUNvcHlVc2FnZSA9IDM1MDQyO1xuXG5jb25zdCBHTFNMMSA9ICcxMDAnO1xuY29uc3QgR0xTTDMgPSAnMzAwIGVzJztcblxuY29uc3QgV2ViR0xDb29yZGluYXRlU3lzdGVtID0gMjAwMDtcbmNvbnN0IFdlYkdQVUNvb3JkaW5hdGVTeXN0ZW0gPSAyMDAxO1xuXG4vKipcbiAqIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvZXZlbnRkaXNwYXRjaGVyLmpzL1xuICovXG5cbmNsYXNzIEV2ZW50RGlzcGF0Y2hlciB7XG5cblx0YWRkRXZlbnRMaXN0ZW5lciggdHlwZSwgbGlzdGVuZXIgKSB7XG5cblx0XHRpZiAoIHRoaXMuX2xpc3RlbmVycyA9PT0gdW5kZWZpbmVkICkgdGhpcy5fbGlzdGVuZXJzID0ge307XG5cblx0XHRjb25zdCBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnM7XG5cblx0XHRpZiAoIGxpc3RlbmVyc1sgdHlwZSBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGxpc3RlbmVyc1sgdHlwZSBdID0gW107XG5cblx0XHR9XG5cblx0XHRpZiAoIGxpc3RlbmVyc1sgdHlwZSBdLmluZGV4T2YoIGxpc3RlbmVyICkgPT09IC0gMSApIHtcblxuXHRcdFx0bGlzdGVuZXJzWyB0eXBlIF0ucHVzaCggbGlzdGVuZXIgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0aGFzRXZlbnRMaXN0ZW5lciggdHlwZSwgbGlzdGVuZXIgKSB7XG5cblx0XHRpZiAoIHRoaXMuX2xpc3RlbmVycyA9PT0gdW5kZWZpbmVkICkgcmV0dXJuIGZhbHNlO1xuXG5cdFx0Y29uc3QgbGlzdGVuZXJzID0gdGhpcy5fbGlzdGVuZXJzO1xuXG5cdFx0cmV0dXJuIGxpc3RlbmVyc1sgdHlwZSBdICE9PSB1bmRlZmluZWQgJiYgbGlzdGVuZXJzWyB0eXBlIF0uaW5kZXhPZiggbGlzdGVuZXIgKSAhPT0gLSAxO1xuXG5cdH1cblxuXHRyZW1vdmVFdmVudExpc3RlbmVyKCB0eXBlLCBsaXN0ZW5lciApIHtcblxuXHRcdGlmICggdGhpcy5fbGlzdGVuZXJzID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHRjb25zdCBsaXN0ZW5lcnMgPSB0aGlzLl9saXN0ZW5lcnM7XG5cdFx0Y29uc3QgbGlzdGVuZXJBcnJheSA9IGxpc3RlbmVyc1sgdHlwZSBdO1xuXG5cdFx0aWYgKCBsaXN0ZW5lckFycmF5ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IGluZGV4ID0gbGlzdGVuZXJBcnJheS5pbmRleE9mKCBsaXN0ZW5lciApO1xuXG5cdFx0XHRpZiAoIGluZGV4ICE9PSAtIDEgKSB7XG5cblx0XHRcdFx0bGlzdGVuZXJBcnJheS5zcGxpY2UoIGluZGV4LCAxICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0ZGlzcGF0Y2hFdmVudCggZXZlbnQgKSB7XG5cblx0XHRpZiAoIHRoaXMuX2xpc3RlbmVycyA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xuXG5cdFx0Y29uc3QgbGlzdGVuZXJzID0gdGhpcy5fbGlzdGVuZXJzO1xuXHRcdGNvbnN0IGxpc3RlbmVyQXJyYXkgPSBsaXN0ZW5lcnNbIGV2ZW50LnR5cGUgXTtcblxuXHRcdGlmICggbGlzdGVuZXJBcnJheSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRldmVudC50YXJnZXQgPSB0aGlzO1xuXG5cdFx0XHQvLyBNYWtlIGEgY29weSwgaW4gY2FzZSBsaXN0ZW5lcnMgYXJlIHJlbW92ZWQgd2hpbGUgaXRlcmF0aW5nLlxuXHRcdFx0Y29uc3QgYXJyYXkgPSBsaXN0ZW5lckFycmF5LnNsaWNlKCAwICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGFycmF5Lmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0YXJyYXlbIGkgXS5jYWxsKCB0aGlzLCBldmVudCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGV2ZW50LnRhcmdldCA9IG51bGw7XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbmNvbnN0IF9sdXQgPSBbICcwMCcsICcwMScsICcwMicsICcwMycsICcwNCcsICcwNScsICcwNicsICcwNycsICcwOCcsICcwOScsICcwYScsICcwYicsICcwYycsICcwZCcsICcwZScsICcwZicsICcxMCcsICcxMScsICcxMicsICcxMycsICcxNCcsICcxNScsICcxNicsICcxNycsICcxOCcsICcxOScsICcxYScsICcxYicsICcxYycsICcxZCcsICcxZScsICcxZicsICcyMCcsICcyMScsICcyMicsICcyMycsICcyNCcsICcyNScsICcyNicsICcyNycsICcyOCcsICcyOScsICcyYScsICcyYicsICcyYycsICcyZCcsICcyZScsICcyZicsICczMCcsICczMScsICczMicsICczMycsICczNCcsICczNScsICczNicsICczNycsICczOCcsICczOScsICczYScsICczYicsICczYycsICczZCcsICczZScsICczZicsICc0MCcsICc0MScsICc0MicsICc0MycsICc0NCcsICc0NScsICc0NicsICc0NycsICc0OCcsICc0OScsICc0YScsICc0YicsICc0YycsICc0ZCcsICc0ZScsICc0ZicsICc1MCcsICc1MScsICc1MicsICc1MycsICc1NCcsICc1NScsICc1NicsICc1NycsICc1OCcsICc1OScsICc1YScsICc1YicsICc1YycsICc1ZCcsICc1ZScsICc1ZicsICc2MCcsICc2MScsICc2MicsICc2MycsICc2NCcsICc2NScsICc2NicsICc2NycsICc2OCcsICc2OScsICc2YScsICc2YicsICc2YycsICc2ZCcsICc2ZScsICc2ZicsICc3MCcsICc3MScsICc3MicsICc3MycsICc3NCcsICc3NScsICc3NicsICc3NycsICc3OCcsICc3OScsICc3YScsICc3YicsICc3YycsICc3ZCcsICc3ZScsICc3ZicsICc4MCcsICc4MScsICc4MicsICc4MycsICc4NCcsICc4NScsICc4NicsICc4NycsICc4OCcsICc4OScsICc4YScsICc4YicsICc4YycsICc4ZCcsICc4ZScsICc4ZicsICc5MCcsICc5MScsICc5MicsICc5MycsICc5NCcsICc5NScsICc5NicsICc5NycsICc5OCcsICc5OScsICc5YScsICc5YicsICc5YycsICc5ZCcsICc5ZScsICc5ZicsICdhMCcsICdhMScsICdhMicsICdhMycsICdhNCcsICdhNScsICdhNicsICdhNycsICdhOCcsICdhOScsICdhYScsICdhYicsICdhYycsICdhZCcsICdhZScsICdhZicsICdiMCcsICdiMScsICdiMicsICdiMycsICdiNCcsICdiNScsICdiNicsICdiNycsICdiOCcsICdiOScsICdiYScsICdiYicsICdiYycsICdiZCcsICdiZScsICdiZicsICdjMCcsICdjMScsICdjMicsICdjMycsICdjNCcsICdjNScsICdjNicsICdjNycsICdjOCcsICdjOScsICdjYScsICdjYicsICdjYycsICdjZCcsICdjZScsICdjZicsICdkMCcsICdkMScsICdkMicsICdkMycsICdkNCcsICdkNScsICdkNicsICdkNycsICdkOCcsICdkOScsICdkYScsICdkYicsICdkYycsICdkZCcsICdkZScsICdkZicsICdlMCcsICdlMScsICdlMicsICdlMycsICdlNCcsICdlNScsICdlNicsICdlNycsICdlOCcsICdlOScsICdlYScsICdlYicsICdlYycsICdlZCcsICdlZScsICdlZicsICdmMCcsICdmMScsICdmMicsICdmMycsICdmNCcsICdmNScsICdmNicsICdmNycsICdmOCcsICdmOScsICdmYScsICdmYicsICdmYycsICdmZCcsICdmZScsICdmZicgXTtcblxubGV0IF9zZWVkID0gMTIzNDU2NztcblxuXG5jb25zdCBERUcyUkFEID0gTWF0aC5QSSAvIDE4MDtcbmNvbnN0IFJBRDJERUcgPSAxODAgLyBNYXRoLlBJO1xuXG4vLyBodHRwOi8vc3RhY2tvdmVyZmxvdy5jb20vcXVlc3Rpb25zLzEwNTAzNC9ob3ctdG8tY3JlYXRlLWEtZ3VpZC11dWlkLWluLWphdmFzY3JpcHQvMjE5NjMxMzYjMjE5NjMxMzZcbmZ1bmN0aW9uIGdlbmVyYXRlVVVJRCgpIHtcblxuXHRjb25zdCBkMCA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcblx0Y29uc3QgZDEgPSBNYXRoLnJhbmRvbSgpICogMHhmZmZmZmZmZiB8IDA7XG5cdGNvbnN0IGQyID0gTWF0aC5yYW5kb20oKSAqIDB4ZmZmZmZmZmYgfCAwO1xuXHRjb25zdCBkMyA9IE1hdGgucmFuZG9tKCkgKiAweGZmZmZmZmZmIHwgMDtcblx0Y29uc3QgdXVpZCA9IF9sdXRbIGQwICYgMHhmZiBdICsgX2x1dFsgZDAgPj4gOCAmIDB4ZmYgXSArIF9sdXRbIGQwID4+IDE2ICYgMHhmZiBdICsgX2x1dFsgZDAgPj4gMjQgJiAweGZmIF0gKyAnLScgK1xuXHRcdFx0X2x1dFsgZDEgJiAweGZmIF0gKyBfbHV0WyBkMSA+PiA4ICYgMHhmZiBdICsgJy0nICsgX2x1dFsgZDEgPj4gMTYgJiAweDBmIHwgMHg0MCBdICsgX2x1dFsgZDEgPj4gMjQgJiAweGZmIF0gKyAnLScgK1xuXHRcdFx0X2x1dFsgZDIgJiAweDNmIHwgMHg4MCBdICsgX2x1dFsgZDIgPj4gOCAmIDB4ZmYgXSArICctJyArIF9sdXRbIGQyID4+IDE2ICYgMHhmZiBdICsgX2x1dFsgZDIgPj4gMjQgJiAweGZmIF0gK1xuXHRcdFx0X2x1dFsgZDMgJiAweGZmIF0gKyBfbHV0WyBkMyA+PiA4ICYgMHhmZiBdICsgX2x1dFsgZDMgPj4gMTYgJiAweGZmIF0gKyBfbHV0WyBkMyA+PiAyNCAmIDB4ZmYgXTtcblxuXHQvLyAudG9Mb3dlckNhc2UoKSBoZXJlIGZsYXR0ZW5zIGNvbmNhdGVuYXRlZCBzdHJpbmdzIHRvIHNhdmUgaGVhcCBtZW1vcnkgc3BhY2UuXG5cdHJldHVybiB1dWlkLnRvTG93ZXJDYXNlKCk7XG5cbn1cblxuZnVuY3Rpb24gY2xhbXAoIHZhbHVlLCBtaW4sIG1heCApIHtcblxuXHRyZXR1cm4gTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgdmFsdWUgKSApO1xuXG59XG5cbi8vIGNvbXB1dGUgZXVjbGlkZWFuIG1vZHVsbyBvZiBtICUgblxuLy8gaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTW9kdWxvX29wZXJhdGlvblxuZnVuY3Rpb24gZXVjbGlkZWFuTW9kdWxvKCBuLCBtICkge1xuXG5cdHJldHVybiAoICggbiAlIG0gKSArIG0gKSAlIG07XG5cbn1cblxuLy8gTGluZWFyIG1hcHBpbmcgZnJvbSByYW5nZSA8YTEsIGEyPiB0byByYW5nZSA8YjEsIGIyPlxuZnVuY3Rpb24gbWFwTGluZWFyKCB4LCBhMSwgYTIsIGIxLCBiMiApIHtcblxuXHRyZXR1cm4gYjEgKyAoIHggLSBhMSApICogKCBiMiAtIGIxICkgLyAoIGEyIC0gYTEgKTtcblxufVxuXG4vLyBodHRwczovL3d3dy5nYW1lZGV2Lm5ldC90dXRvcmlhbHMvcHJvZ3JhbW1pbmcvZ2VuZXJhbC1hbmQtZ2FtZXBsYXktcHJvZ3JhbW1pbmcvaW52ZXJzZS1sZXJwLWEtc3VwZXItdXNlZnVsLXlldC1vZnRlbi1vdmVybG9va2VkLWZ1bmN0aW9uLXI1MjMwL1xuZnVuY3Rpb24gaW52ZXJzZUxlcnAoIHgsIHksIHZhbHVlICkge1xuXG5cdGlmICggeCAhPT0geSApIHtcblxuXHRcdHJldHVybiAoIHZhbHVlIC0geCApIC8gKCB5IC0geCApO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRyZXR1cm4gMDtcblxuXHR9XG5cbn1cblxuLy8gaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvTGluZWFyX2ludGVycG9sYXRpb25cbmZ1bmN0aW9uIGxlcnAoIHgsIHksIHQgKSB7XG5cblx0cmV0dXJuICggMSAtIHQgKSAqIHggKyB0ICogeTtcblxufVxuXG4vLyBodHRwOi8vd3d3LnJvcnlkcmlzY29sbC5jb20vMjAxNi8wMy8wNy9mcmFtZS1yYXRlLWluZGVwZW5kZW50LWRhbXBpbmctdXNpbmctbGVycC9cbmZ1bmN0aW9uIGRhbXAoIHgsIHksIGxhbWJkYSwgZHQgKSB7XG5cblx0cmV0dXJuIGxlcnAoIHgsIHksIDEgLSBNYXRoLmV4cCggLSBsYW1iZGEgKiBkdCApICk7XG5cbn1cblxuLy8gaHR0cHM6Ly93d3cuZGVzbW9zLmNvbS9jYWxjdWxhdG9yL3Zjc2pueXo3eDRcbmZ1bmN0aW9uIHBpbmdwb25nKCB4LCBsZW5ndGggPSAxICkge1xuXG5cdHJldHVybiBsZW5ndGggLSBNYXRoLmFicyggZXVjbGlkZWFuTW9kdWxvKCB4LCBsZW5ndGggKiAyICkgLSBsZW5ndGggKTtcblxufVxuXG4vLyBodHRwOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1Ntb290aHN0ZXBcbmZ1bmN0aW9uIHNtb290aHN0ZXAoIHgsIG1pbiwgbWF4ICkge1xuXG5cdGlmICggeCA8PSBtaW4gKSByZXR1cm4gMDtcblx0aWYgKCB4ID49IG1heCApIHJldHVybiAxO1xuXG5cdHggPSAoIHggLSBtaW4gKSAvICggbWF4IC0gbWluICk7XG5cblx0cmV0dXJuIHggKiB4ICogKCAzIC0gMiAqIHggKTtcblxufVxuXG5mdW5jdGlvbiBzbW9vdGhlcnN0ZXAoIHgsIG1pbiwgbWF4ICkge1xuXG5cdGlmICggeCA8PSBtaW4gKSByZXR1cm4gMDtcblx0aWYgKCB4ID49IG1heCApIHJldHVybiAxO1xuXG5cdHggPSAoIHggLSBtaW4gKSAvICggbWF4IC0gbWluICk7XG5cblx0cmV0dXJuIHggKiB4ICogeCAqICggeCAqICggeCAqIDYgLSAxNSApICsgMTAgKTtcblxufVxuXG4vLyBSYW5kb20gaW50ZWdlciBmcm9tIDxsb3csIGhpZ2g+IGludGVydmFsXG5mdW5jdGlvbiByYW5kSW50KCBsb3csIGhpZ2ggKSB7XG5cblx0cmV0dXJuIGxvdyArIE1hdGguZmxvb3IoIE1hdGgucmFuZG9tKCkgKiAoIGhpZ2ggLSBsb3cgKyAxICkgKTtcblxufVxuXG4vLyBSYW5kb20gZmxvYXQgZnJvbSA8bG93LCBoaWdoPiBpbnRlcnZhbFxuZnVuY3Rpb24gcmFuZEZsb2F0KCBsb3csIGhpZ2ggKSB7XG5cblx0cmV0dXJuIGxvdyArIE1hdGgucmFuZG9tKCkgKiAoIGhpZ2ggLSBsb3cgKTtcblxufVxuXG4vLyBSYW5kb20gZmxvYXQgZnJvbSA8LXJhbmdlLzIsIHJhbmdlLzI+IGludGVydmFsXG5mdW5jdGlvbiByYW5kRmxvYXRTcHJlYWQoIHJhbmdlICkge1xuXG5cdHJldHVybiByYW5nZSAqICggMC41IC0gTWF0aC5yYW5kb20oKSApO1xuXG59XG5cbi8vIERldGVybWluaXN0aWMgcHNldWRvLXJhbmRvbSBmbG9hdCBpbiB0aGUgaW50ZXJ2YWwgWyAwLCAxIF1cbmZ1bmN0aW9uIHNlZWRlZFJhbmRvbSggcyApIHtcblxuXHRpZiAoIHMgIT09IHVuZGVmaW5lZCApIF9zZWVkID0gcztcblxuXHQvLyBNdWxiZXJyeTMyIGdlbmVyYXRvclxuXG5cdGxldCB0ID0gX3NlZWQgKz0gMHg2RDJCNzlGNTtcblxuXHR0ID0gTWF0aC5pbXVsKCB0IF4gdCA+Pj4gMTUsIHQgfCAxICk7XG5cblx0dCBePSB0ICsgTWF0aC5pbXVsKCB0IF4gdCA+Pj4gNywgdCB8IDYxICk7XG5cblx0cmV0dXJuICggKCB0IF4gdCA+Pj4gMTQgKSA+Pj4gMCApIC8gNDI5NDk2NzI5NjtcblxufVxuXG5mdW5jdGlvbiBkZWdUb1JhZCggZGVncmVlcyApIHtcblxuXHRyZXR1cm4gZGVncmVlcyAqIERFRzJSQUQ7XG5cbn1cblxuZnVuY3Rpb24gcmFkVG9EZWcoIHJhZGlhbnMgKSB7XG5cblx0cmV0dXJuIHJhZGlhbnMgKiBSQUQyREVHO1xuXG59XG5cbmZ1bmN0aW9uIGlzUG93ZXJPZlR3byggdmFsdWUgKSB7XG5cblx0cmV0dXJuICggdmFsdWUgJiAoIHZhbHVlIC0gMSApICkgPT09IDAgJiYgdmFsdWUgIT09IDA7XG5cbn1cblxuZnVuY3Rpb24gY2VpbFBvd2VyT2ZUd28oIHZhbHVlICkge1xuXG5cdHJldHVybiBNYXRoLnBvdyggMiwgTWF0aC5jZWlsKCBNYXRoLmxvZyggdmFsdWUgKSAvIE1hdGguTE4yICkgKTtcblxufVxuXG5mdW5jdGlvbiBmbG9vclBvd2VyT2ZUd28oIHZhbHVlICkge1xuXG5cdHJldHVybiBNYXRoLnBvdyggMiwgTWF0aC5mbG9vciggTWF0aC5sb2coIHZhbHVlICkgLyBNYXRoLkxOMiApICk7XG5cbn1cblxuZnVuY3Rpb24gc2V0UXVhdGVybmlvbkZyb21Qcm9wZXJFdWxlciggcSwgYSwgYiwgYywgb3JkZXIgKSB7XG5cblx0Ly8gSW50cmluc2ljIFByb3BlciBFdWxlciBBbmdsZXMgLSBzZWUgaHR0cHM6Ly9lbi53aWtpcGVkaWEub3JnL3dpa2kvRXVsZXJfYW5nbGVzXG5cblx0Ly8gcm90YXRpb25zIGFyZSBhcHBsaWVkIHRvIHRoZSBheGVzIGluIHRoZSBvcmRlciBzcGVjaWZpZWQgYnkgJ29yZGVyJ1xuXHQvLyByb3RhdGlvbiBieSBhbmdsZSAnYScgaXMgYXBwbGllZCBmaXJzdCwgdGhlbiBieSBhbmdsZSAnYicsIHRoZW4gYnkgYW5nbGUgJ2MnXG5cdC8vIGFuZ2xlcyBhcmUgaW4gcmFkaWFuc1xuXG5cdGNvbnN0IGNvcyA9IE1hdGguY29zO1xuXHRjb25zdCBzaW4gPSBNYXRoLnNpbjtcblxuXHRjb25zdCBjMiA9IGNvcyggYiAvIDIgKTtcblx0Y29uc3QgczIgPSBzaW4oIGIgLyAyICk7XG5cblx0Y29uc3QgYzEzID0gY29zKCAoIGEgKyBjICkgLyAyICk7XG5cdGNvbnN0IHMxMyA9IHNpbiggKCBhICsgYyApIC8gMiApO1xuXG5cdGNvbnN0IGMxXzMgPSBjb3MoICggYSAtIGMgKSAvIDIgKTtcblx0Y29uc3QgczFfMyA9IHNpbiggKCBhIC0gYyApIC8gMiApO1xuXG5cdGNvbnN0IGMzXzEgPSBjb3MoICggYyAtIGEgKSAvIDIgKTtcblx0Y29uc3QgczNfMSA9IHNpbiggKCBjIC0gYSApIC8gMiApO1xuXG5cdHN3aXRjaCAoIG9yZGVyICkge1xuXG5cdFx0Y2FzZSAnWFlYJzpcblx0XHRcdHEuc2V0KCBjMiAqIHMxMywgczIgKiBjMV8zLCBzMiAqIHMxXzMsIGMyICogYzEzICk7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgJ1laWSc6XG5cdFx0XHRxLnNldCggczIgKiBzMV8zLCBjMiAqIHMxMywgczIgKiBjMV8zLCBjMiAqIGMxMyApO1xuXHRcdFx0YnJlYWs7XG5cblx0XHRjYXNlICdaWFonOlxuXHRcdFx0cS5zZXQoIHMyICogYzFfMywgczIgKiBzMV8zLCBjMiAqIHMxMywgYzIgKiBjMTMgKTtcblx0XHRcdGJyZWFrO1xuXG5cdFx0Y2FzZSAnWFpYJzpcblx0XHRcdHEuc2V0KCBjMiAqIHMxMywgczIgKiBzM18xLCBzMiAqIGMzXzEsIGMyICogYzEzICk7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgJ1lYWSc6XG5cdFx0XHRxLnNldCggczIgKiBjM18xLCBjMiAqIHMxMywgczIgKiBzM18xLCBjMiAqIGMxMyApO1xuXHRcdFx0YnJlYWs7XG5cblx0XHRjYXNlICdaWVonOlxuXHRcdFx0cS5zZXQoIHMyICogczNfMSwgczIgKiBjM18xLCBjMiAqIHMxMywgYzIgKiBjMTMgKTtcblx0XHRcdGJyZWFrO1xuXG5cdFx0ZGVmYXVsdDpcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLk1hdGhVdGlsczogLnNldFF1YXRlcm5pb25Gcm9tUHJvcGVyRXVsZXIoKSBlbmNvdW50ZXJlZCBhbiB1bmtub3duIG9yZGVyOiAnICsgb3JkZXIgKTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gZGVub3JtYWxpemUoIHZhbHVlLCBhcnJheSApIHtcblxuXHRzd2l0Y2ggKCBhcnJheS5jb25zdHJ1Y3RvciApIHtcblxuXHRcdGNhc2UgRmxvYXQzMkFycmF5OlxuXG5cdFx0XHRyZXR1cm4gdmFsdWU7XG5cblx0XHRjYXNlIFVpbnQzMkFycmF5OlxuXG5cdFx0XHRyZXR1cm4gdmFsdWUgLyA0Mjk0OTY3Mjk1LjA7XG5cblx0XHRjYXNlIFVpbnQxNkFycmF5OlxuXG5cdFx0XHRyZXR1cm4gdmFsdWUgLyA2NTUzNS4wO1xuXG5cdFx0Y2FzZSBVaW50OEFycmF5OlxuXG5cdFx0XHRyZXR1cm4gdmFsdWUgLyAyNTUuMDtcblxuXHRcdGNhc2UgSW50MzJBcnJheTpcblxuXHRcdFx0cmV0dXJuIE1hdGgubWF4KCB2YWx1ZSAvIDIxNDc0ODM2NDcuMCwgLSAxLjAgKTtcblxuXHRcdGNhc2UgSW50MTZBcnJheTpcblxuXHRcdFx0cmV0dXJuIE1hdGgubWF4KCB2YWx1ZSAvIDMyNzY3LjAsIC0gMS4wICk7XG5cblx0XHRjYXNlIEludDhBcnJheTpcblxuXHRcdFx0cmV0dXJuIE1hdGgubWF4KCB2YWx1ZSAvIDEyNy4wLCAtIDEuMCApO1xuXG5cdFx0ZGVmYXVsdDpcblxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnSW52YWxpZCBjb21wb25lbnQgdHlwZS4nICk7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIG5vcm1hbGl6ZSggdmFsdWUsIGFycmF5ICkge1xuXG5cdHN3aXRjaCAoIGFycmF5LmNvbnN0cnVjdG9yICkge1xuXG5cdFx0Y2FzZSBGbG9hdDMyQXJyYXk6XG5cblx0XHRcdHJldHVybiB2YWx1ZTtcblxuXHRcdGNhc2UgVWludDMyQXJyYXk6XG5cblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDQyOTQ5NjcyOTUuMCApO1xuXG5cdFx0Y2FzZSBVaW50MTZBcnJheTpcblxuXHRcdFx0cmV0dXJuIE1hdGgucm91bmQoIHZhbHVlICogNjU1MzUuMCApO1xuXG5cdFx0Y2FzZSBVaW50OEFycmF5OlxuXG5cdFx0XHRyZXR1cm4gTWF0aC5yb3VuZCggdmFsdWUgKiAyNTUuMCApO1xuXG5cdFx0Y2FzZSBJbnQzMkFycmF5OlxuXG5cdFx0XHRyZXR1cm4gTWF0aC5yb3VuZCggdmFsdWUgKiAyMTQ3NDgzNjQ3LjAgKTtcblxuXHRcdGNhc2UgSW50MTZBcnJheTpcblxuXHRcdFx0cmV0dXJuIE1hdGgucm91bmQoIHZhbHVlICogMzI3NjcuMCApO1xuXG5cdFx0Y2FzZSBJbnQ4QXJyYXk6XG5cblx0XHRcdHJldHVybiBNYXRoLnJvdW5kKCB2YWx1ZSAqIDEyNy4wICk7XG5cblx0XHRkZWZhdWx0OlxuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdJbnZhbGlkIGNvbXBvbmVudCB0eXBlLicgKTtcblxuXHR9XG5cbn1cblxuY29uc3QgTWF0aFV0aWxzID0ge1xuXHRERUcyUkFEOiBERUcyUkFELFxuXHRSQUQyREVHOiBSQUQyREVHLFxuXHRnZW5lcmF0ZVVVSUQ6IGdlbmVyYXRlVVVJRCxcblx0Y2xhbXA6IGNsYW1wLFxuXHRldWNsaWRlYW5Nb2R1bG86IGV1Y2xpZGVhbk1vZHVsbyxcblx0bWFwTGluZWFyOiBtYXBMaW5lYXIsXG5cdGludmVyc2VMZXJwOiBpbnZlcnNlTGVycCxcblx0bGVycDogbGVycCxcblx0ZGFtcDogZGFtcCxcblx0cGluZ3Bvbmc6IHBpbmdwb25nLFxuXHRzbW9vdGhzdGVwOiBzbW9vdGhzdGVwLFxuXHRzbW9vdGhlcnN0ZXA6IHNtb290aGVyc3RlcCxcblx0cmFuZEludDogcmFuZEludCxcblx0cmFuZEZsb2F0OiByYW5kRmxvYXQsXG5cdHJhbmRGbG9hdFNwcmVhZDogcmFuZEZsb2F0U3ByZWFkLFxuXHRzZWVkZWRSYW5kb206IHNlZWRlZFJhbmRvbSxcblx0ZGVnVG9SYWQ6IGRlZ1RvUmFkLFxuXHRyYWRUb0RlZzogcmFkVG9EZWcsXG5cdGlzUG93ZXJPZlR3bzogaXNQb3dlck9mVHdvLFxuXHRjZWlsUG93ZXJPZlR3bzogY2VpbFBvd2VyT2ZUd28sXG5cdGZsb29yUG93ZXJPZlR3bzogZmxvb3JQb3dlck9mVHdvLFxuXHRzZXRRdWF0ZXJuaW9uRnJvbVByb3BlckV1bGVyOiBzZXRRdWF0ZXJuaW9uRnJvbVByb3BlckV1bGVyLFxuXHRub3JtYWxpemU6IG5vcm1hbGl6ZSxcblx0ZGVub3JtYWxpemU6IGRlbm9ybWFsaXplXG59O1xuXG5jbGFzcyBWZWN0b3IyIHtcblxuXHRjb25zdHJ1Y3RvciggeCA9IDAsIHkgPSAwICkge1xuXG5cdFx0VmVjdG9yMi5wcm90b3R5cGUuaXNWZWN0b3IyID0gdHJ1ZTtcblxuXHRcdHRoaXMueCA9IHg7XG5cdFx0dGhpcy55ID0geTtcblxuXHR9XG5cblx0Z2V0IHdpZHRoKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMueDtcblxuXHR9XG5cblx0c2V0IHdpZHRoKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMueCA9IHZhbHVlO1xuXG5cdH1cblxuXHRnZXQgaGVpZ2h0KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMueTtcblxuXHR9XG5cblx0c2V0IGhlaWdodCggdmFsdWUgKSB7XG5cblx0XHR0aGlzLnkgPSB2YWx1ZTtcblxuXHR9XG5cblx0c2V0KCB4LCB5ICkge1xuXG5cdFx0dGhpcy54ID0geDtcblx0XHR0aGlzLnkgPSB5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFNjYWxhciggc2NhbGFyICkge1xuXG5cdFx0dGhpcy54ID0gc2NhbGFyO1xuXHRcdHRoaXMueSA9IHNjYWxhcjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRYKCB4ICkge1xuXG5cdFx0dGhpcy54ID0geDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRZKCB5ICkge1xuXG5cdFx0dGhpcy55ID0geTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRDb21wb25lbnQoIGluZGV4LCB2YWx1ZSApIHtcblxuXHRcdHN3aXRjaCAoIGluZGV4ICkge1xuXG5cdFx0XHRjYXNlIDA6IHRoaXMueCA9IHZhbHVlOyBicmVhaztcblx0XHRcdGNhc2UgMTogdGhpcy55ID0gdmFsdWU7IGJyZWFrO1xuXHRcdFx0ZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKCAnaW5kZXggaXMgb3V0IG9mIHJhbmdlOiAnICsgaW5kZXggKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRDb21wb25lbnQoIGluZGV4ICkge1xuXG5cdFx0c3dpdGNoICggaW5kZXggKSB7XG5cblx0XHRcdGNhc2UgMDogcmV0dXJuIHRoaXMueDtcblx0XHRcdGNhc2UgMTogcmV0dXJuIHRoaXMueTtcblx0XHRcdGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvciggJ2luZGV4IGlzIG91dCBvZiByYW5nZTogJyArIGluZGV4ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCB0aGlzLngsIHRoaXMueSApO1xuXG5cdH1cblxuXHRjb3B5KCB2ICkge1xuXG5cdFx0dGhpcy54ID0gdi54O1xuXHRcdHRoaXMueSA9IHYueTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhZGQoIHYgKSB7XG5cblx0XHR0aGlzLnggKz0gdi54O1xuXHRcdHRoaXMueSArPSB2Lnk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkU2NhbGFyKCBzICkge1xuXG5cdFx0dGhpcy54ICs9IHM7XG5cdFx0dGhpcy55ICs9IHM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkVmVjdG9ycyggYSwgYiApIHtcblxuXHRcdHRoaXMueCA9IGEueCArIGIueDtcblx0XHR0aGlzLnkgPSBhLnkgKyBiLnk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkU2NhbGVkVmVjdG9yKCB2LCBzICkge1xuXG5cdFx0dGhpcy54ICs9IHYueCAqIHM7XG5cdFx0dGhpcy55ICs9IHYueSAqIHM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3ViKCB2ICkge1xuXG5cdFx0dGhpcy54IC09IHYueDtcblx0XHR0aGlzLnkgLT0gdi55O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN1YlNjYWxhciggcyApIHtcblxuXHRcdHRoaXMueCAtPSBzO1xuXHRcdHRoaXMueSAtPSBzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN1YlZlY3RvcnMoIGEsIGIgKSB7XG5cblx0XHR0aGlzLnggPSBhLnggLSBiLng7XG5cdFx0dGhpcy55ID0gYS55IC0gYi55O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5KCB2ICkge1xuXG5cdFx0dGhpcy54ICo9IHYueDtcblx0XHR0aGlzLnkgKj0gdi55O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5U2NhbGFyKCBzY2FsYXIgKSB7XG5cblx0XHR0aGlzLnggKj0gc2NhbGFyO1xuXHRcdHRoaXMueSAqPSBzY2FsYXI7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGl2aWRlKCB2ICkge1xuXG5cdFx0dGhpcy54IC89IHYueDtcblx0XHR0aGlzLnkgLz0gdi55O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRpdmlkZVNjYWxhciggc2NhbGFyICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubXVsdGlwbHlTY2FsYXIoIDEgLyBzY2FsYXIgKTtcblxuXHR9XG5cblx0YXBwbHlNYXRyaXgzKCBtICkge1xuXG5cdFx0Y29uc3QgeCA9IHRoaXMueCwgeSA9IHRoaXMueTtcblx0XHRjb25zdCBlID0gbS5lbGVtZW50cztcblxuXHRcdHRoaXMueCA9IGVbIDAgXSAqIHggKyBlWyAzIF0gKiB5ICsgZVsgNiBdO1xuXHRcdHRoaXMueSA9IGVbIDEgXSAqIHggKyBlWyA0IF0gKiB5ICsgZVsgNyBdO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1pbiggdiApIHtcblxuXHRcdHRoaXMueCA9IE1hdGgubWluKCB0aGlzLngsIHYueCApO1xuXHRcdHRoaXMueSA9IE1hdGgubWluKCB0aGlzLnksIHYueSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1heCggdiApIHtcblxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCB0aGlzLngsIHYueCApO1xuXHRcdHRoaXMueSA9IE1hdGgubWF4KCB0aGlzLnksIHYueSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsYW1wKCBtaW4sIG1heCApIHtcblxuXHRcdC8vIGFzc3VtZXMgbWluIDwgbWF4LCBjb21wb25lbnR3aXNlXG5cblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluLngsIE1hdGgubWluKCBtYXgueCwgdGhpcy54ICkgKTtcblx0XHR0aGlzLnkgPSBNYXRoLm1heCggbWluLnksIE1hdGgubWluKCBtYXgueSwgdGhpcy55ICkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbGFtcFNjYWxhciggbWluVmFsLCBtYXhWYWwgKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnggKSApO1xuXHRcdHRoaXMueSA9IE1hdGgubWF4KCBtaW5WYWwsIE1hdGgubWluKCBtYXhWYWwsIHRoaXMueSApICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xhbXBMZW5ndGgoIG1pbiwgbWF4ICkge1xuXG5cdFx0Y29uc3QgbGVuZ3RoID0gdGhpcy5sZW5ndGgoKTtcblxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggbGVuZ3RoIHx8IDEgKS5tdWx0aXBseVNjYWxhciggTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgbGVuZ3RoICkgKSApO1xuXG5cdH1cblxuXHRmbG9vcigpIHtcblxuXHRcdHRoaXMueCA9IE1hdGguZmxvb3IoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGguZmxvb3IoIHRoaXMueSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNlaWwoKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLmNlaWwoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGguY2VpbCggdGhpcy55ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cm91bmQoKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLnJvdW5kKCB0aGlzLnggKTtcblx0XHR0aGlzLnkgPSBNYXRoLnJvdW5kKCB0aGlzLnkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyb3VuZFRvWmVybygpIHtcblxuXHRcdHRoaXMueCA9IE1hdGgudHJ1bmMoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGgudHJ1bmMoIHRoaXMueSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG5lZ2F0ZSgpIHtcblxuXHRcdHRoaXMueCA9IC0gdGhpcy54O1xuXHRcdHRoaXMueSA9IC0gdGhpcy55O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRvdCggdiApIHtcblxuXHRcdHJldHVybiB0aGlzLnggKiB2LnggKyB0aGlzLnkgKiB2Lnk7XG5cblx0fVxuXG5cdGNyb3NzKCB2ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMueCAqIHYueSAtIHRoaXMueSAqIHYueDtcblxuXHR9XG5cblx0bGVuZ3RoU3EoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy54ICogdGhpcy54ICsgdGhpcy55ICogdGhpcy55O1xuXG5cdH1cblxuXHRsZW5ndGgoKSB7XG5cblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCB0aGlzLnggKiB0aGlzLnggKyB0aGlzLnkgKiB0aGlzLnkgKTtcblxuXHR9XG5cblx0bWFuaGF0dGFuTGVuZ3RoKCkge1xuXG5cdFx0cmV0dXJuIE1hdGguYWJzKCB0aGlzLnggKSArIE1hdGguYWJzKCB0aGlzLnkgKTtcblxuXHR9XG5cblx0bm9ybWFsaXplKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZGl2aWRlU2NhbGFyKCB0aGlzLmxlbmd0aCgpIHx8IDEgKTtcblxuXHR9XG5cblx0YW5nbGUoKSB7XG5cblx0XHQvLyBjb21wdXRlcyB0aGUgYW5nbGUgaW4gcmFkaWFucyB3aXRoIHJlc3BlY3QgdG8gdGhlIHBvc2l0aXZlIHgtYXhpc1xuXG5cdFx0Y29uc3QgYW5nbGUgPSBNYXRoLmF0YW4yKCAtIHRoaXMueSwgLSB0aGlzLnggKSArIE1hdGguUEk7XG5cblx0XHRyZXR1cm4gYW5nbGU7XG5cblx0fVxuXG5cdGFuZ2xlVG8oIHYgKSB7XG5cblx0XHRjb25zdCBkZW5vbWluYXRvciA9IE1hdGguc3FydCggdGhpcy5sZW5ndGhTcSgpICogdi5sZW5ndGhTcSgpICk7XG5cblx0XHRpZiAoIGRlbm9taW5hdG9yID09PSAwICkgcmV0dXJuIE1hdGguUEkgLyAyO1xuXG5cdFx0Y29uc3QgdGhldGEgPSB0aGlzLmRvdCggdiApIC8gZGVub21pbmF0b3I7XG5cblx0XHQvLyBjbGFtcCwgdG8gaGFuZGxlIG51bWVyaWNhbCBwcm9ibGVtc1xuXG5cdFx0cmV0dXJuIE1hdGguYWNvcyggY2xhbXAoIHRoZXRhLCAtIDEsIDEgKSApO1xuXG5cdH1cblxuXHRkaXN0YW5jZVRvKCB2ICkge1xuXG5cdFx0cmV0dXJuIE1hdGguc3FydCggdGhpcy5kaXN0YW5jZVRvU3F1YXJlZCggdiApICk7XG5cblx0fVxuXG5cdGRpc3RhbmNlVG9TcXVhcmVkKCB2ICkge1xuXG5cdFx0Y29uc3QgZHggPSB0aGlzLnggLSB2LngsIGR5ID0gdGhpcy55IC0gdi55O1xuXHRcdHJldHVybiBkeCAqIGR4ICsgZHkgKiBkeTtcblxuXHR9XG5cblx0bWFuaGF0dGFuRGlzdGFuY2VUbyggdiApIHtcblxuXHRcdHJldHVybiBNYXRoLmFicyggdGhpcy54IC0gdi54ICkgKyBNYXRoLmFicyggdGhpcy55IC0gdi55ICk7XG5cblx0fVxuXG5cdHNldExlbmd0aCggbGVuZ3RoICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubm9ybWFsaXplKCkubXVsdGlwbHlTY2FsYXIoIGxlbmd0aCApO1xuXG5cdH1cblxuXHRsZXJwKCB2LCBhbHBoYSApIHtcblxuXHRcdHRoaXMueCArPSAoIHYueCAtIHRoaXMueCApICogYWxwaGE7XG5cdFx0dGhpcy55ICs9ICggdi55IC0gdGhpcy55ICkgKiBhbHBoYTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRsZXJwVmVjdG9ycyggdjEsIHYyLCBhbHBoYSApIHtcblxuXHRcdHRoaXMueCA9IHYxLnggKyAoIHYyLnggLSB2MS54ICkgKiBhbHBoYTtcblx0XHR0aGlzLnkgPSB2MS55ICsgKCB2Mi55IC0gdjEueSApICogYWxwaGE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXF1YWxzKCB2ICkge1xuXG5cdFx0cmV0dXJuICggKCB2LnggPT09IHRoaXMueCApICYmICggdi55ID09PSB0aGlzLnkgKSApO1xuXG5cdH1cblxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xuXG5cdFx0dGhpcy54ID0gYXJyYXlbIG9mZnNldCBdO1xuXHRcdHRoaXMueSA9IGFycmF5WyBvZmZzZXQgKyAxIF07XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdGFycmF5WyBvZmZzZXQgXSA9IHRoaXMueDtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy55O1xuXG5cdFx0cmV0dXJuIGFycmF5O1xuXG5cdH1cblxuXHRmcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGluZGV4ICkge1xuXG5cdFx0dGhpcy54ID0gYXR0cmlidXRlLmdldFgoIGluZGV4ICk7XG5cdFx0dGhpcy55ID0gYXR0cmlidXRlLmdldFkoIGluZGV4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cm90YXRlQXJvdW5kKCBjZW50ZXIsIGFuZ2xlICkge1xuXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCBhbmdsZSApLCBzID0gTWF0aC5zaW4oIGFuZ2xlICk7XG5cblx0XHRjb25zdCB4ID0gdGhpcy54IC0gY2VudGVyLng7XG5cdFx0Y29uc3QgeSA9IHRoaXMueSAtIGNlbnRlci55O1xuXG5cdFx0dGhpcy54ID0geCAqIGMgLSB5ICogcyArIGNlbnRlci54O1xuXHRcdHRoaXMueSA9IHggKiBzICsgeSAqIGMgKyBjZW50ZXIueTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyYW5kb20oKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLnJhbmRvbSgpO1xuXHRcdHRoaXMueSA9IE1hdGgucmFuZG9tKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0KlsgU3ltYm9sLml0ZXJhdG9yIF0oKSB7XG5cblx0XHR5aWVsZCB0aGlzLng7XG5cdFx0eWllbGQgdGhpcy55O1xuXG5cdH1cblxufVxuXG5jbGFzcyBNYXRyaXgzIHtcblxuXHRjb25zdHJ1Y3RvciggbjExLCBuMTIsIG4xMywgbjIxLCBuMjIsIG4yMywgbjMxLCBuMzIsIG4zMyApIHtcblxuXHRcdE1hdHJpeDMucHJvdG90eXBlLmlzTWF0cml4MyA9IHRydWU7XG5cblx0XHR0aGlzLmVsZW1lbnRzID0gW1xuXG5cdFx0XHQxLCAwLCAwLFxuXHRcdFx0MCwgMSwgMCxcblx0XHRcdDAsIDAsIDFcblxuXHRcdF07XG5cblx0XHRpZiAoIG4xMSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLnNldCggbjExLCBuMTIsIG4xMywgbjIxLCBuMjIsIG4yMywgbjMxLCBuMzIsIG4zMyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRzZXQoIG4xMSwgbjEyLCBuMTMsIG4yMSwgbjIyLCBuMjMsIG4zMSwgbjMyLCBuMzMgKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cblx0XHR0ZVsgMCBdID0gbjExOyB0ZVsgMSBdID0gbjIxOyB0ZVsgMiBdID0gbjMxO1xuXHRcdHRlWyAzIF0gPSBuMTI7IHRlWyA0IF0gPSBuMjI7IHRlWyA1IF0gPSBuMzI7XG5cdFx0dGVbIDYgXSA9IG4xMzsgdGVbIDcgXSA9IG4yMzsgdGVbIDggXSA9IG4zMztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRpZGVudGl0eSgpIHtcblxuXHRcdHRoaXMuc2V0KFxuXG5cdFx0XHQxLCAwLCAwLFxuXHRcdFx0MCwgMSwgMCxcblx0XHRcdDAsIDAsIDFcblxuXHRcdCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weSggbSApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblx0XHRjb25zdCBtZSA9IG0uZWxlbWVudHM7XG5cblx0XHR0ZVsgMCBdID0gbWVbIDAgXTsgdGVbIDEgXSA9IG1lWyAxIF07IHRlWyAyIF0gPSBtZVsgMiBdO1xuXHRcdHRlWyAzIF0gPSBtZVsgMyBdOyB0ZVsgNCBdID0gbWVbIDQgXTsgdGVbIDUgXSA9IG1lWyA1IF07XG5cdFx0dGVbIDYgXSA9IG1lWyA2IF07IHRlWyA3IF0gPSBtZVsgNyBdOyB0ZVsgOCBdID0gbWVbIDggXTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRleHRyYWN0QmFzaXMoIHhBeGlzLCB5QXhpcywgekF4aXMgKSB7XG5cblx0XHR4QXhpcy5zZXRGcm9tTWF0cml4M0NvbHVtbiggdGhpcywgMCApO1xuXHRcdHlBeGlzLnNldEZyb21NYXRyaXgzQ29sdW1uKCB0aGlzLCAxICk7XG5cdFx0ekF4aXMuc2V0RnJvbU1hdHJpeDNDb2x1bW4oIHRoaXMsIDIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tTWF0cml4NCggbSApIHtcblxuXHRcdGNvbnN0IG1lID0gbS5lbGVtZW50cztcblxuXHRcdHRoaXMuc2V0KFxuXG5cdFx0XHRtZVsgMCBdLCBtZVsgNCBdLCBtZVsgOCBdLFxuXHRcdFx0bWVbIDEgXSwgbWVbIDUgXSwgbWVbIDkgXSxcblx0XHRcdG1lWyAyIF0sIG1lWyA2IF0sIG1lWyAxMCBdXG5cblx0XHQpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5KCBtICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubXVsdGlwbHlNYXRyaWNlcyggdGhpcywgbSApO1xuXG5cdH1cblxuXHRwcmVtdWx0aXBseSggbSApIHtcblxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5TWF0cmljZXMoIG0sIHRoaXMgKTtcblxuXHR9XG5cblx0bXVsdGlwbHlNYXRyaWNlcyggYSwgYiApIHtcblxuXHRcdGNvbnN0IGFlID0gYS5lbGVtZW50cztcblx0XHRjb25zdCBiZSA9IGIuZWxlbWVudHM7XG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0Y29uc3QgYTExID0gYWVbIDAgXSwgYTEyID0gYWVbIDMgXSwgYTEzID0gYWVbIDYgXTtcblx0XHRjb25zdCBhMjEgPSBhZVsgMSBdLCBhMjIgPSBhZVsgNCBdLCBhMjMgPSBhZVsgNyBdO1xuXHRcdGNvbnN0IGEzMSA9IGFlWyAyIF0sIGEzMiA9IGFlWyA1IF0sIGEzMyA9IGFlWyA4IF07XG5cblx0XHRjb25zdCBiMTEgPSBiZVsgMCBdLCBiMTIgPSBiZVsgMyBdLCBiMTMgPSBiZVsgNiBdO1xuXHRcdGNvbnN0IGIyMSA9IGJlWyAxIF0sIGIyMiA9IGJlWyA0IF0sIGIyMyA9IGJlWyA3IF07XG5cdFx0Y29uc3QgYjMxID0gYmVbIDIgXSwgYjMyID0gYmVbIDUgXSwgYjMzID0gYmVbIDggXTtcblxuXHRcdHRlWyAwIF0gPSBhMTEgKiBiMTEgKyBhMTIgKiBiMjEgKyBhMTMgKiBiMzE7XG5cdFx0dGVbIDMgXSA9IGExMSAqIGIxMiArIGExMiAqIGIyMiArIGExMyAqIGIzMjtcblx0XHR0ZVsgNiBdID0gYTExICogYjEzICsgYTEyICogYjIzICsgYTEzICogYjMzO1xuXG5cdFx0dGVbIDEgXSA9IGEyMSAqIGIxMSArIGEyMiAqIGIyMSArIGEyMyAqIGIzMTtcblx0XHR0ZVsgNCBdID0gYTIxICogYjEyICsgYTIyICogYjIyICsgYTIzICogYjMyO1xuXHRcdHRlWyA3IF0gPSBhMjEgKiBiMTMgKyBhMjIgKiBiMjMgKyBhMjMgKiBiMzM7XG5cblx0XHR0ZVsgMiBdID0gYTMxICogYjExICsgYTMyICogYjIxICsgYTMzICogYjMxO1xuXHRcdHRlWyA1IF0gPSBhMzEgKiBiMTIgKyBhMzIgKiBiMjIgKyBhMzMgKiBiMzI7XG5cdFx0dGVbIDggXSA9IGEzMSAqIGIxMyArIGEzMiAqIGIyMyArIGEzMyAqIGIzMztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtdWx0aXBseVNjYWxhciggcyApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdHRlWyAwIF0gKj0gczsgdGVbIDMgXSAqPSBzOyB0ZVsgNiBdICo9IHM7XG5cdFx0dGVbIDEgXSAqPSBzOyB0ZVsgNCBdICo9IHM7IHRlWyA3IF0gKj0gcztcblx0XHR0ZVsgMiBdICo9IHM7IHRlWyA1IF0gKj0gczsgdGVbIDggXSAqPSBzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRldGVybWluYW50KCkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0Y29uc3QgYSA9IHRlWyAwIF0sIGIgPSB0ZVsgMSBdLCBjID0gdGVbIDIgXSxcblx0XHRcdGQgPSB0ZVsgMyBdLCBlID0gdGVbIDQgXSwgZiA9IHRlWyA1IF0sXG5cdFx0XHRnID0gdGVbIDYgXSwgaCA9IHRlWyA3IF0sIGkgPSB0ZVsgOCBdO1xuXG5cdFx0cmV0dXJuIGEgKiBlICogaSAtIGEgKiBmICogaCAtIGIgKiBkICogaSArIGIgKiBmICogZyArIGMgKiBkICogaCAtIGMgKiBlICogZztcblxuXHR9XG5cblx0aW52ZXJ0KCkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzLFxuXG5cdFx0XHRuMTEgPSB0ZVsgMCBdLCBuMjEgPSB0ZVsgMSBdLCBuMzEgPSB0ZVsgMiBdLFxuXHRcdFx0bjEyID0gdGVbIDMgXSwgbjIyID0gdGVbIDQgXSwgbjMyID0gdGVbIDUgXSxcblx0XHRcdG4xMyA9IHRlWyA2IF0sIG4yMyA9IHRlWyA3IF0sIG4zMyA9IHRlWyA4IF0sXG5cblx0XHRcdHQxMSA9IG4zMyAqIG4yMiAtIG4zMiAqIG4yMyxcblx0XHRcdHQxMiA9IG4zMiAqIG4xMyAtIG4zMyAqIG4xMixcblx0XHRcdHQxMyA9IG4yMyAqIG4xMiAtIG4yMiAqIG4xMyxcblxuXHRcdFx0ZGV0ID0gbjExICogdDExICsgbjIxICogdDEyICsgbjMxICogdDEzO1xuXG5cdFx0aWYgKCBkZXQgPT09IDAgKSByZXR1cm4gdGhpcy5zZXQoIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAsIDAgKTtcblxuXHRcdGNvbnN0IGRldEludiA9IDEgLyBkZXQ7XG5cblx0XHR0ZVsgMCBdID0gdDExICogZGV0SW52O1xuXHRcdHRlWyAxIF0gPSAoIG4zMSAqIG4yMyAtIG4zMyAqIG4yMSApICogZGV0SW52O1xuXHRcdHRlWyAyIF0gPSAoIG4zMiAqIG4yMSAtIG4zMSAqIG4yMiApICogZGV0SW52O1xuXG5cdFx0dGVbIDMgXSA9IHQxMiAqIGRldEludjtcblx0XHR0ZVsgNCBdID0gKCBuMzMgKiBuMTEgLSBuMzEgKiBuMTMgKSAqIGRldEludjtcblx0XHR0ZVsgNSBdID0gKCBuMzEgKiBuMTIgLSBuMzIgKiBuMTEgKSAqIGRldEludjtcblxuXHRcdHRlWyA2IF0gPSB0MTMgKiBkZXRJbnY7XG5cdFx0dGVbIDcgXSA9ICggbjIxICogbjEzIC0gbjIzICogbjExICkgKiBkZXRJbnY7XG5cdFx0dGVbIDggXSA9ICggbjIyICogbjExIC0gbjIxICogbjEyICkgKiBkZXRJbnY7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJhbnNwb3NlKCkge1xuXG5cdFx0bGV0IHRtcDtcblx0XHRjb25zdCBtID0gdGhpcy5lbGVtZW50cztcblxuXHRcdHRtcCA9IG1bIDEgXTsgbVsgMSBdID0gbVsgMyBdOyBtWyAzIF0gPSB0bXA7XG5cdFx0dG1wID0gbVsgMiBdOyBtWyAyIF0gPSBtWyA2IF07IG1bIDYgXSA9IHRtcDtcblx0XHR0bXAgPSBtWyA1IF07IG1bIDUgXSA9IG1bIDcgXTsgbVsgNyBdID0gdG1wO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldE5vcm1hbE1hdHJpeCggbWF0cml4NCApIHtcblxuXHRcdHJldHVybiB0aGlzLnNldEZyb21NYXRyaXg0KCBtYXRyaXg0ICkuaW52ZXJ0KCkudHJhbnNwb3NlKCk7XG5cblx0fVxuXG5cdHRyYW5zcG9zZUludG9BcnJheSggciApIHtcblxuXHRcdGNvbnN0IG0gPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0clsgMCBdID0gbVsgMCBdO1xuXHRcdHJbIDEgXSA9IG1bIDMgXTtcblx0XHRyWyAyIF0gPSBtWyA2IF07XG5cdFx0clsgMyBdID0gbVsgMSBdO1xuXHRcdHJbIDQgXSA9IG1bIDQgXTtcblx0XHRyWyA1IF0gPSBtWyA3IF07XG5cdFx0clsgNiBdID0gbVsgMiBdO1xuXHRcdHJbIDcgXSA9IG1bIDUgXTtcblx0XHRyWyA4IF0gPSBtWyA4IF07XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0VXZUcmFuc2Zvcm0oIHR4LCB0eSwgc3gsIHN5LCByb3RhdGlvbiwgY3gsIGN5ICkge1xuXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCByb3RhdGlvbiApO1xuXHRcdGNvbnN0IHMgPSBNYXRoLnNpbiggcm90YXRpb24gKTtcblxuXHRcdHRoaXMuc2V0KFxuXHRcdFx0c3ggKiBjLCBzeCAqIHMsIC0gc3ggKiAoIGMgKiBjeCArIHMgKiBjeSApICsgY3ggKyB0eCxcblx0XHRcdC0gc3kgKiBzLCBzeSAqIGMsIC0gc3kgKiAoIC0gcyAqIGN4ICsgYyAqIGN5ICkgKyBjeSArIHR5LFxuXHRcdFx0MCwgMCwgMVxuXHRcdCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Ly9cblxuXHRzY2FsZSggc3gsIHN5ICkge1xuXG5cdFx0dGhpcy5wcmVtdWx0aXBseSggX20zLm1ha2VTY2FsZSggc3gsIHN5ICkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyb3RhdGUoIHRoZXRhICkge1xuXG5cdFx0dGhpcy5wcmVtdWx0aXBseSggX20zLm1ha2VSb3RhdGlvbiggLSB0aGV0YSApICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJhbnNsYXRlKCB0eCwgdHkgKSB7XG5cblx0XHR0aGlzLnByZW11bHRpcGx5KCBfbTMubWFrZVRyYW5zbGF0aW9uKCB0eCwgdHkgKSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIGZvciAyRCBUcmFuc2Zvcm1zXG5cblx0bWFrZVRyYW5zbGF0aW9uKCB4LCB5ICkge1xuXG5cdFx0aWYgKCB4LmlzVmVjdG9yMiApIHtcblxuXHRcdFx0dGhpcy5zZXQoXG5cblx0XHRcdFx0MSwgMCwgeC54LFxuXHRcdFx0XHQwLCAxLCB4LnksXG5cdFx0XHRcdDAsIDAsIDFcblxuXHRcdFx0KTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuc2V0KFxuXG5cdFx0XHRcdDEsIDAsIHgsXG5cdFx0XHRcdDAsIDEsIHksXG5cdFx0XHRcdDAsIDAsIDFcblxuXHRcdFx0KTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlUm90YXRpb24oIHRoZXRhICkge1xuXG5cdFx0Ly8gY291bnRlcmNsb2Nrd2lzZVxuXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCB0aGV0YSApO1xuXHRcdGNvbnN0IHMgPSBNYXRoLnNpbiggdGhldGEgKTtcblxuXHRcdHRoaXMuc2V0KFxuXG5cdFx0XHRjLCAtIHMsIDAsXG5cdFx0XHRzLCBjLCAwLFxuXHRcdFx0MCwgMCwgMVxuXG5cdFx0KTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlU2NhbGUoIHgsIHkgKSB7XG5cblx0XHR0aGlzLnNldChcblxuXHRcdFx0eCwgMCwgMCxcblx0XHRcdDAsIHksIDAsXG5cdFx0XHQwLCAwLCAxXG5cblx0XHQpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vXG5cblx0ZXF1YWxzKCBtYXRyaXggKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cdFx0Y29uc3QgbWUgPSBtYXRyaXguZWxlbWVudHM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xuXG5cdFx0XHRpZiAoIHRlWyBpIF0gIT09IG1lWyBpIF0gKSByZXR1cm4gZmFsc2U7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9XG5cblx0ZnJvbUFycmF5KCBhcnJheSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuZWxlbWVudHNbIGkgXSA9IGFycmF5WyBpICsgb2Zmc2V0IF07XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdGFycmF5WyBvZmZzZXQgXSA9IHRlWyAwIF07XG5cdFx0YXJyYXlbIG9mZnNldCArIDEgXSA9IHRlWyAxIF07XG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRlWyAyIF07XG5cblx0XHRhcnJheVsgb2Zmc2V0ICsgMyBdID0gdGVbIDMgXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgNCBdID0gdGVbIDQgXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgNSBdID0gdGVbIDUgXTtcblxuXHRcdGFycmF5WyBvZmZzZXQgKyA2IF0gPSB0ZVsgNiBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyA3IF0gPSB0ZVsgNyBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyA4IF0gPSB0ZVsgOCBdO1xuXG5cdFx0cmV0dXJuIGFycmF5O1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmZyb21BcnJheSggdGhpcy5lbGVtZW50cyApO1xuXG5cdH1cblxufVxuXG5jb25zdCBfbTMgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCk7XG5cbmZ1bmN0aW9uIGFycmF5TmVlZHNVaW50MzIoIGFycmF5ICkge1xuXG5cdC8vIGFzc3VtZXMgbGFyZ2VyIHZhbHVlcyB1c3VhbGx5IG9uIGxhc3RcblxuXHRmb3IgKCBsZXQgaSA9IGFycmF5Lmxlbmd0aCAtIDE7IGkgPj0gMDsgLS0gaSApIHtcblxuXHRcdGlmICggYXJyYXlbIGkgXSA+PSA2NTUzNSApIHJldHVybiB0cnVlOyAvLyBhY2NvdW50IGZvciBQUklNSVRJVkVfUkVTVEFSVF9GSVhFRF9JTkRFWCwgIzI0NTY1XG5cblx0fVxuXG5cdHJldHVybiBmYWxzZTtcblxufVxuXG5jb25zdCBUWVBFRF9BUlJBWVMgPSB7XG5cdEludDhBcnJheTogSW50OEFycmF5LFxuXHRVaW50OEFycmF5OiBVaW50OEFycmF5LFxuXHRVaW50OENsYW1wZWRBcnJheTogVWludDhDbGFtcGVkQXJyYXksXG5cdEludDE2QXJyYXk6IEludDE2QXJyYXksXG5cdFVpbnQxNkFycmF5OiBVaW50MTZBcnJheSxcblx0SW50MzJBcnJheTogSW50MzJBcnJheSxcblx0VWludDMyQXJyYXk6IFVpbnQzMkFycmF5LFxuXHRGbG9hdDMyQXJyYXk6IEZsb2F0MzJBcnJheSxcblx0RmxvYXQ2NEFycmF5OiBGbG9hdDY0QXJyYXlcbn07XG5cbmZ1bmN0aW9uIGdldFR5cGVkQXJyYXkoIHR5cGUsIGJ1ZmZlciApIHtcblxuXHRyZXR1cm4gbmV3IFRZUEVEX0FSUkFZU1sgdHlwZSBdKCBidWZmZXIgKTtcblxufVxuXG5mdW5jdGlvbiBjcmVhdGVFbGVtZW50TlMoIG5hbWUgKSB7XG5cblx0cmV0dXJuIGRvY3VtZW50LmNyZWF0ZUVsZW1lbnROUyggJ2h0dHA6Ly93d3cudzMub3JnLzE5OTkveGh0bWwnLCBuYW1lICk7XG5cbn1cblxuZnVuY3Rpb24gY3JlYXRlQ2FudmFzRWxlbWVudCgpIHtcblxuXHRjb25zdCBjYW52YXMgPSBjcmVhdGVFbGVtZW50TlMoICdjYW52YXMnICk7XG5cdGNhbnZhcy5zdHlsZS5kaXNwbGF5ID0gJ2Jsb2NrJztcblx0cmV0dXJuIGNhbnZhcztcblxufVxuXG5jb25zdCBfY2FjaGUgPSB7fTtcblxuZnVuY3Rpb24gd2Fybk9uY2UoIG1lc3NhZ2UgKSB7XG5cblx0aWYgKCBtZXNzYWdlIGluIF9jYWNoZSApIHJldHVybjtcblxuXHRfY2FjaGVbIG1lc3NhZ2UgXSA9IHRydWU7XG5cblx0Y29uc29sZS53YXJuKCBtZXNzYWdlICk7XG5cbn1cblxuZnVuY3Rpb24gcHJvYmVBc3luYyggZ2wsIHN5bmMsIGludGVydmFsICkge1xuXG5cdHJldHVybiBuZXcgUHJvbWlzZSggZnVuY3Rpb24gKCByZXNvbHZlLCByZWplY3QgKSB7XG5cblx0XHRmdW5jdGlvbiBwcm9iZSgpIHtcblxuXHRcdFx0c3dpdGNoICggZ2wuY2xpZW50V2FpdFN5bmMoIHN5bmMsIGdsLlNZTkNfRkxVU0hfQ09NTUFORFNfQklULCAwICkgKSB7XG5cblx0XHRcdFx0Y2FzZSBnbC5XQUlUX0ZBSUxFRDpcblx0XHRcdFx0XHRyZWplY3QoKTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlIGdsLlRJTUVPVVRfRVhQSVJFRDpcblx0XHRcdFx0XHRzZXRUaW1lb3V0KCBwcm9iZSwgaW50ZXJ2YWwgKTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdHJlc29sdmUoKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0c2V0VGltZW91dCggcHJvYmUsIGludGVydmFsICk7XG5cblx0fSApO1xuXG59XG5cbi8qKlxuICogTWF0cmljZXMgY29udmVydGluZyBQMyA8LT4gUmVjLiA3MDkgcHJpbWFyaWVzLCB3aXRob3V0IGdhbXV0IG1hcHBpbmdcbiAqIG9yIGNsaXBwaW5nLiBCYXNlZCBvbiBXM0Mgc3BlY2lmaWNhdGlvbnMgZm9yIHNSR0IgYW5kIERpc3BsYXkgUDMsXG4gKiBhbmQgSUNDIHNwZWNpZmljYXRpb25zIGZvciB0aGUgRDUwIGNvbm5lY3Rpb24gc3BhY2UuIFZhbHVlcyBpbi9vdXRcbiAqIGFyZSBfbGluZWFyXyBzUkdCIGFuZCBfbGluZWFyXyBEaXNwbGF5IFAzLlxuICpcbiAqIE5vdGUgdGhhdCBib3RoIHNSR0IgYW5kIERpc3BsYXkgUDMgdXNlIHRoZSBzUkdCIHRyYW5zZmVyIGZ1bmN0aW9ucy5cbiAqXG4gKiBSZWZlcmVuY2U6XG4gKiAtIGh0dHA6Ly93d3cucnVzc2VsbGNvdHRyZWxsLmNvbS9waG90by9tYXRyaXhDYWxjdWxhdG9yLmh0bVxuICovXG5cbmNvbnN0IExJTkVBUl9TUkdCX1RPX0xJTkVBUl9ESVNQTEFZX1AzID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpLnNldChcblx0MC44MjI0NjIxLCAwLjE3NzUzOCwgMC4wLFxuXHQwLjAzMzE5NDEsIDAuOTY2ODA1OCwgMC4wLFxuXHQwLjAxNzA4MjcsIDAuMDcyMzk3NCwgMC45MTA1MTk5LFxuKTtcblxuY29uc3QgTElORUFSX0RJU1BMQVlfUDNfVE9fTElORUFSX1NSR0IgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkuc2V0KFxuXHQxLjIyNDk0MDEsIC0gMC4yMjQ5NDA0LCAwLjAsXG5cdC0gMC4wNDIwNTY5LCAxLjA0MjA1NzEsIDAuMCxcblx0LSAwLjAxOTYzNzYsIC0gMC4wNzg2MzYxLCAxLjA5ODI3MzVcbik7XG5cbi8qKlxuICogRGVmaW5lcyBzdXBwb3J0ZWQgY29sb3Igc3BhY2VzIGJ5IHRyYW5zZmVyIGZ1bmN0aW9uIGFuZCBwcmltYXJpZXMsXG4gKiBhbmQgcHJvdmlkZXMgY29udmVyc2lvbnMgdG8vZnJvbSB0aGUgTGluZWFyLXNSR0IgcmVmZXJlbmNlIHNwYWNlLlxuICovXG5jb25zdCBDT0xPUl9TUEFDRVMgPSB7XG5cdFsgTGluZWFyU1JHQkNvbG9yU3BhY2UgXToge1xuXHRcdHRyYW5zZmVyOiBMaW5lYXJUcmFuc2Zlcixcblx0XHRwcmltYXJpZXM6IFJlYzcwOVByaW1hcmllcyxcblx0XHRsdW1pbmFuY2VDb2VmZmljaWVudHM6IFsgMC4yMTI2LCAwLjcxNTIsIDAuMDcyMiBdLFxuXHRcdHRvUmVmZXJlbmNlOiAoIGNvbG9yICkgPT4gY29sb3IsXG5cdFx0ZnJvbVJlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLFxuXHR9LFxuXHRbIFNSR0JDb2xvclNwYWNlIF06IHtcblx0XHR0cmFuc2ZlcjogU1JHQlRyYW5zZmVyLFxuXHRcdHByaW1hcmllczogUmVjNzA5UHJpbWFyaWVzLFxuXHRcdGx1bWluYW5jZUNvZWZmaWNpZW50czogWyAwLjIxMjYsIDAuNzE1MiwgMC4wNzIyIF0sXG5cdFx0dG9SZWZlcmVuY2U6ICggY29sb3IgKSA9PiBjb2xvci5jb252ZXJ0U1JHQlRvTGluZWFyKCksXG5cdFx0ZnJvbVJlZmVyZW5jZTogKCBjb2xvciApID0+IGNvbG9yLmNvbnZlcnRMaW5lYXJUb1NSR0IoKSxcblx0fSxcblx0WyBMaW5lYXJEaXNwbGF5UDNDb2xvclNwYWNlIF06IHtcblx0XHR0cmFuc2ZlcjogTGluZWFyVHJhbnNmZXIsXG5cdFx0cHJpbWFyaWVzOiBQM1ByaW1hcmllcyxcblx0XHRsdW1pbmFuY2VDb2VmZmljaWVudHM6IFsgMC4yMjg5LCAwLjY5MTcsIDAuMDc5MyBdLFxuXHRcdHRvUmVmZXJlbmNlOiAoIGNvbG9yICkgPT4gY29sb3IuYXBwbHlNYXRyaXgzKCBMSU5FQVJfRElTUExBWV9QM19UT19MSU5FQVJfU1JHQiApLFxuXHRcdGZyb21SZWZlcmVuY2U6ICggY29sb3IgKSA9PiBjb2xvci5hcHBseU1hdHJpeDMoIExJTkVBUl9TUkdCX1RPX0xJTkVBUl9ESVNQTEFZX1AzICksXG5cdH0sXG5cdFsgRGlzcGxheVAzQ29sb3JTcGFjZSBdOiB7XG5cdFx0dHJhbnNmZXI6IFNSR0JUcmFuc2Zlcixcblx0XHRwcmltYXJpZXM6IFAzUHJpbWFyaWVzLFxuXHRcdGx1bWluYW5jZUNvZWZmaWNpZW50czogWyAwLjIyODksIDAuNjkxNywgMC4wNzkzIF0sXG5cdFx0dG9SZWZlcmVuY2U6ICggY29sb3IgKSA9PiBjb2xvci5jb252ZXJ0U1JHQlRvTGluZWFyKCkuYXBwbHlNYXRyaXgzKCBMSU5FQVJfRElTUExBWV9QM19UT19MSU5FQVJfU1JHQiApLFxuXHRcdGZyb21SZWZlcmVuY2U6ICggY29sb3IgKSA9PiBjb2xvci5hcHBseU1hdHJpeDMoIExJTkVBUl9TUkdCX1RPX0xJTkVBUl9ESVNQTEFZX1AzICkuY29udmVydExpbmVhclRvU1JHQigpLFxuXHR9LFxufTtcblxuY29uc3QgU1VQUE9SVEVEX1dPUktJTkdfQ09MT1JfU1BBQ0VTID0gbmV3IFNldCggWyBMaW5lYXJTUkdCQ29sb3JTcGFjZSwgTGluZWFyRGlzcGxheVAzQ29sb3JTcGFjZSBdICk7XG5cbmNvbnN0IENvbG9yTWFuYWdlbWVudCA9IHtcblxuXHRlbmFibGVkOiB0cnVlLFxuXG5cdF93b3JraW5nQ29sb3JTcGFjZTogTGluZWFyU1JHQkNvbG9yU3BhY2UsXG5cblx0Z2V0IHdvcmtpbmdDb2xvclNwYWNlKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3dvcmtpbmdDb2xvclNwYWNlO1xuXG5cdH0sXG5cblx0c2V0IHdvcmtpbmdDb2xvclNwYWNlKCBjb2xvclNwYWNlICkge1xuXG5cdFx0aWYgKCAhIFNVUFBPUlRFRF9XT1JLSU5HX0NPTE9SX1NQQUNFUy5oYXMoIGNvbG9yU3BhY2UgKSApIHtcblxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCBgVW5zdXBwb3J0ZWQgd29ya2luZyBjb2xvciBzcGFjZSwgXCIkeyBjb2xvclNwYWNlIH1cIi5gICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLl93b3JraW5nQ29sb3JTcGFjZSA9IGNvbG9yU3BhY2U7XG5cblx0fSxcblxuXHRjb252ZXJ0OiBmdW5jdGlvbiAoIGNvbG9yLCBzb3VyY2VDb2xvclNwYWNlLCB0YXJnZXRDb2xvclNwYWNlICkge1xuXG5cdFx0aWYgKCB0aGlzLmVuYWJsZWQgPT09IGZhbHNlIHx8IHNvdXJjZUNvbG9yU3BhY2UgPT09IHRhcmdldENvbG9yU3BhY2UgfHwgISBzb3VyY2VDb2xvclNwYWNlIHx8ICEgdGFyZ2V0Q29sb3JTcGFjZSApIHtcblxuXHRcdFx0cmV0dXJuIGNvbG9yO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3Qgc291cmNlVG9SZWZlcmVuY2UgPSBDT0xPUl9TUEFDRVNbIHNvdXJjZUNvbG9yU3BhY2UgXS50b1JlZmVyZW5jZTtcblx0XHRjb25zdCB0YXJnZXRGcm9tUmVmZXJlbmNlID0gQ09MT1JfU1BBQ0VTWyB0YXJnZXRDb2xvclNwYWNlIF0uZnJvbVJlZmVyZW5jZTtcblxuXHRcdHJldHVybiB0YXJnZXRGcm9tUmVmZXJlbmNlKCBzb3VyY2VUb1JlZmVyZW5jZSggY29sb3IgKSApO1xuXG5cdH0sXG5cblx0ZnJvbVdvcmtpbmdDb2xvclNwYWNlOiBmdW5jdGlvbiAoIGNvbG9yLCB0YXJnZXRDb2xvclNwYWNlICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuY29udmVydCggY29sb3IsIHRoaXMuX3dvcmtpbmdDb2xvclNwYWNlLCB0YXJnZXRDb2xvclNwYWNlICk7XG5cblx0fSxcblxuXHR0b1dvcmtpbmdDb2xvclNwYWNlOiBmdW5jdGlvbiAoIGNvbG9yLCBzb3VyY2VDb2xvclNwYWNlICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuY29udmVydCggY29sb3IsIHNvdXJjZUNvbG9yU3BhY2UsIHRoaXMuX3dvcmtpbmdDb2xvclNwYWNlICk7XG5cblx0fSxcblxuXHRnZXRQcmltYXJpZXM6IGZ1bmN0aW9uICggY29sb3JTcGFjZSApIHtcblxuXHRcdHJldHVybiBDT0xPUl9TUEFDRVNbIGNvbG9yU3BhY2UgXS5wcmltYXJpZXM7XG5cblx0fSxcblxuXHRnZXRUcmFuc2ZlcjogZnVuY3Rpb24gKCBjb2xvclNwYWNlICkge1xuXG5cdFx0aWYgKCBjb2xvclNwYWNlID09PSBOb0NvbG9yU3BhY2UgKSByZXR1cm4gTGluZWFyVHJhbnNmZXI7XG5cblx0XHRyZXR1cm4gQ09MT1JfU1BBQ0VTWyBjb2xvclNwYWNlIF0udHJhbnNmZXI7XG5cblx0fSxcblxuXHRnZXRMdW1pbmFuY2VDb2VmZmljaWVudHM6IGZ1bmN0aW9uICggdGFyZ2V0LCBjb2xvclNwYWNlID0gdGhpcy5fd29ya2luZ0NvbG9yU3BhY2UgKSB7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LmZyb21BcnJheSggQ09MT1JfU1BBQ0VTWyBjb2xvclNwYWNlIF0ubHVtaW5hbmNlQ29lZmZpY2llbnRzICk7XG5cblx0fSxcblxufTtcblxuXG5mdW5jdGlvbiBTUkdCVG9MaW5lYXIoIGMgKSB7XG5cblx0cmV0dXJuICggYyA8IDAuMDQwNDUgKSA/IGMgKiAwLjA3NzM5OTM4MDggOiBNYXRoLnBvdyggYyAqIDAuOTQ3ODY3Mjk4NiArIDAuMDUyMTMyNzAxNCwgMi40ICk7XG5cbn1cblxuZnVuY3Rpb24gTGluZWFyVG9TUkdCKCBjICkge1xuXG5cdHJldHVybiAoIGMgPCAwLjAwMzEzMDggKSA/IGMgKiAxMi45MiA6IDEuMDU1ICogKCBNYXRoLnBvdyggYywgMC40MTY2NiApICkgLSAwLjA1NTtcblxufVxuXG5sZXQgX2NhbnZhcztcblxuY2xhc3MgSW1hZ2VVdGlscyB7XG5cblx0c3RhdGljIGdldERhdGFVUkwoIGltYWdlICkge1xuXG5cdFx0aWYgKCAvXmRhdGE6L2kudGVzdCggaW1hZ2Uuc3JjICkgKSB7XG5cblx0XHRcdHJldHVybiBpbWFnZS5zcmM7XG5cblx0XHR9XG5cblx0XHRpZiAoIHR5cGVvZiBIVE1MQ2FudmFzRWxlbWVudCA9PT0gJ3VuZGVmaW5lZCcgKSB7XG5cblx0XHRcdHJldHVybiBpbWFnZS5zcmM7XG5cblx0XHR9XG5cblx0XHRsZXQgY2FudmFzO1xuXG5cdFx0aWYgKCBpbWFnZSBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50ICkge1xuXG5cdFx0XHRjYW52YXMgPSBpbWFnZTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGlmICggX2NhbnZhcyA9PT0gdW5kZWZpbmVkICkgX2NhbnZhcyA9IGNyZWF0ZUVsZW1lbnROUyggJ2NhbnZhcycgKTtcblxuXHRcdFx0X2NhbnZhcy53aWR0aCA9IGltYWdlLndpZHRoO1xuXHRcdFx0X2NhbnZhcy5oZWlnaHQgPSBpbWFnZS5oZWlnaHQ7XG5cblx0XHRcdGNvbnN0IGNvbnRleHQgPSBfY2FudmFzLmdldENvbnRleHQoICcyZCcgKTtcblxuXHRcdFx0aWYgKCBpbWFnZSBpbnN0YW5jZW9mIEltYWdlRGF0YSApIHtcblxuXHRcdFx0XHRjb250ZXh0LnB1dEltYWdlRGF0YSggaW1hZ2UsIDAsIDAgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb250ZXh0LmRyYXdJbWFnZSggaW1hZ2UsIDAsIDAsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjYW52YXMgPSBfY2FudmFzO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBjYW52YXMud2lkdGggPiAyMDQ4IHx8IGNhbnZhcy5oZWlnaHQgPiAyMDQ4ICkge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5JbWFnZVV0aWxzLmdldERhdGFVUkw6IEltYWdlIGNvbnZlcnRlZCB0byBqcGcgZm9yIHBlcmZvcm1hbmNlIHJlYXNvbnMnLCBpbWFnZSApO1xuXG5cdFx0XHRyZXR1cm4gY2FudmFzLnRvRGF0YVVSTCggJ2ltYWdlL2pwZWcnLCAwLjYgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJldHVybiBjYW52YXMudG9EYXRhVVJMKCAnaW1hZ2UvcG5nJyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRzdGF0aWMgc1JHQlRvTGluZWFyKCBpbWFnZSApIHtcblxuXHRcdGlmICggKCB0eXBlb2YgSFRNTEltYWdlRWxlbWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBIVE1MSW1hZ2VFbGVtZW50ICkgfHxcblx0XHRcdCggdHlwZW9mIEhUTUxDYW52YXNFbGVtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEhUTUxDYW52YXNFbGVtZW50ICkgfHxcblx0XHRcdCggdHlwZW9mIEltYWdlQml0bWFwICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEltYWdlQml0bWFwICkgKSB7XG5cblx0XHRcdGNvbnN0IGNhbnZhcyA9IGNyZWF0ZUVsZW1lbnROUyggJ2NhbnZhcycgKTtcblxuXHRcdFx0Y2FudmFzLndpZHRoID0gaW1hZ2Uud2lkdGg7XG5cdFx0XHRjYW52YXMuaGVpZ2h0ID0gaW1hZ2UuaGVpZ2h0O1xuXG5cdFx0XHRjb25zdCBjb250ZXh0ID0gY2FudmFzLmdldENvbnRleHQoICcyZCcgKTtcblx0XHRcdGNvbnRleHQuZHJhd0ltYWdlKCBpbWFnZSwgMCwgMCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCApO1xuXG5cdFx0XHRjb25zdCBpbWFnZURhdGEgPSBjb250ZXh0LmdldEltYWdlRGF0YSggMCwgMCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCApO1xuXHRcdFx0Y29uc3QgZGF0YSA9IGltYWdlRGF0YS5kYXRhO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRkYXRhWyBpIF0gPSBTUkdCVG9MaW5lYXIoIGRhdGFbIGkgXSAvIDI1NSApICogMjU1O1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnRleHQucHV0SW1hZ2VEYXRhKCBpbWFnZURhdGEsIDAsIDAgKTtcblxuXHRcdFx0cmV0dXJuIGNhbnZhcztcblxuXHRcdH0gZWxzZSBpZiAoIGltYWdlLmRhdGEgKSB7XG5cblx0XHRcdGNvbnN0IGRhdGEgPSBpbWFnZS5kYXRhLnNsaWNlKCAwICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGRhdGEubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGlmICggZGF0YSBpbnN0YW5jZW9mIFVpbnQ4QXJyYXkgfHwgZGF0YSBpbnN0YW5jZW9mIFVpbnQ4Q2xhbXBlZEFycmF5ICkge1xuXG5cdFx0XHRcdFx0ZGF0YVsgaSBdID0gTWF0aC5mbG9vciggU1JHQlRvTGluZWFyKCBkYXRhWyBpIF0gLyAyNTUgKSAqIDI1NSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBhc3N1bWluZyBmbG9hdFxuXG5cdFx0XHRcdFx0ZGF0YVsgaSBdID0gU1JHQlRvTGluZWFyKCBkYXRhWyBpIF0gKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0ZGF0YTogZGF0YSxcblx0XHRcdFx0d2lkdGg6IGltYWdlLndpZHRoLFxuXHRcdFx0XHRoZWlnaHQ6IGltYWdlLmhlaWdodFxuXHRcdFx0fTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkltYWdlVXRpbHMuc1JHQlRvTGluZWFyKCk6IFVuc3VwcG9ydGVkIGltYWdlIHR5cGUuIE5vIGNvbG9yIHNwYWNlIGNvbnZlcnNpb24gYXBwbGllZC4nICk7XG5cdFx0XHRyZXR1cm4gaW1hZ2U7XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbmxldCBfc291cmNlSWQgPSAwO1xuXG5jbGFzcyBTb3VyY2Uge1xuXG5cdGNvbnN0cnVjdG9yKCBkYXRhID0gbnVsbCApIHtcblxuXHRcdHRoaXMuaXNTb3VyY2UgPSB0cnVlO1xuXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfc291cmNlSWQgKysgfSApO1xuXG5cdFx0dGhpcy51dWlkID0gZ2VuZXJhdGVVVUlEKCk7XG5cblx0XHR0aGlzLmRhdGEgPSBkYXRhO1xuXHRcdHRoaXMuZGF0YVJlYWR5ID0gdHJ1ZTtcblxuXHRcdHRoaXMudmVyc2lvbiA9IDA7XG5cblx0fVxuXG5cdHNldCBuZWVkc1VwZGF0ZSggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHZhbHVlID09PSB0cnVlICkgdGhpcy52ZXJzaW9uICsrO1xuXG5cdH1cblxuXHR0b0pTT04oIG1ldGEgKSB7XG5cblx0XHRjb25zdCBpc1Jvb3RPYmplY3QgPSAoIG1ldGEgPT09IHVuZGVmaW5lZCB8fCB0eXBlb2YgbWV0YSA9PT0gJ3N0cmluZycgKTtcblxuXHRcdGlmICggISBpc1Jvb3RPYmplY3QgJiYgbWV0YS5pbWFnZXNbIHRoaXMudXVpZCBdICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHJldHVybiBtZXRhLmltYWdlc1sgdGhpcy51dWlkIF07XG5cblx0XHR9XG5cblx0XHRjb25zdCBvdXRwdXQgPSB7XG5cdFx0XHR1dWlkOiB0aGlzLnV1aWQsXG5cdFx0XHR1cmw6ICcnXG5cdFx0fTtcblxuXHRcdGNvbnN0IGRhdGEgPSB0aGlzLmRhdGE7XG5cblx0XHRpZiAoIGRhdGEgIT09IG51bGwgKSB7XG5cblx0XHRcdGxldCB1cmw7XG5cblx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggZGF0YSApICkge1xuXG5cdFx0XHRcdC8vIGN1YmUgdGV4dHVyZVxuXG5cdFx0XHRcdHVybCA9IFtdO1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGRhdGEubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGlmICggZGF0YVsgaSBdLmlzRGF0YVRleHR1cmUgKSB7XG5cblx0XHRcdFx0XHRcdHVybC5wdXNoKCBzZXJpYWxpemVJbWFnZSggZGF0YVsgaSBdLmltYWdlICkgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHVybC5wdXNoKCBzZXJpYWxpemVJbWFnZSggZGF0YVsgaSBdICkgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gdGV4dHVyZVxuXG5cdFx0XHRcdHVybCA9IHNlcmlhbGl6ZUltYWdlKCBkYXRhICk7XG5cblx0XHRcdH1cblxuXHRcdFx0b3V0cHV0LnVybCA9IHVybDtcblxuXHRcdH1cblxuXHRcdGlmICggISBpc1Jvb3RPYmplY3QgKSB7XG5cblx0XHRcdG1ldGEuaW1hZ2VzWyB0aGlzLnV1aWQgXSA9IG91dHB1dDtcblxuXHRcdH1cblxuXHRcdHJldHVybiBvdXRwdXQ7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHNlcmlhbGl6ZUltYWdlKCBpbWFnZSApIHtcblxuXHRpZiAoICggdHlwZW9mIEhUTUxJbWFnZUVsZW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGltYWdlIGluc3RhbmNlb2YgSFRNTEltYWdlRWxlbWVudCApIHx8XG5cdFx0KCB0eXBlb2YgSFRNTENhbnZhc0VsZW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGltYWdlIGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQgKSB8fFxuXHRcdCggdHlwZW9mIEltYWdlQml0bWFwICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEltYWdlQml0bWFwICkgKSB7XG5cblx0XHQvLyBkZWZhdWx0IGltYWdlc1xuXG5cdFx0cmV0dXJuIEltYWdlVXRpbHMuZ2V0RGF0YVVSTCggaW1hZ2UgKTtcblxuXHR9IGVsc2Uge1xuXG5cdFx0aWYgKCBpbWFnZS5kYXRhICkge1xuXG5cdFx0XHQvLyBpbWFnZXMgb2YgRGF0YVRleHR1cmVcblxuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0ZGF0YTogQXJyYXkuZnJvbSggaW1hZ2UuZGF0YSApLFxuXHRcdFx0XHR3aWR0aDogaW1hZ2Uud2lkdGgsXG5cdFx0XHRcdGhlaWdodDogaW1hZ2UuaGVpZ2h0LFxuXHRcdFx0XHR0eXBlOiBpbWFnZS5kYXRhLmNvbnN0cnVjdG9yLm5hbWVcblx0XHRcdH07XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5UZXh0dXJlOiBVbmFibGUgdG8gc2VyaWFsaXplIFRleHR1cmUuJyApO1xuXHRcdFx0cmV0dXJuIHt9O1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5sZXQgX3RleHR1cmVJZCA9IDA7XG5cbmNsYXNzIFRleHR1cmUgZXh0ZW5kcyBFdmVudERpc3BhdGNoZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBpbWFnZSA9IFRleHR1cmUuREVGQVVMVF9JTUFHRSwgbWFwcGluZyA9IFRleHR1cmUuREVGQVVMVF9NQVBQSU5HLCB3cmFwUyA9IENsYW1wVG9FZGdlV3JhcHBpbmcsIHdyYXBUID0gQ2xhbXBUb0VkZ2VXcmFwcGluZywgbWFnRmlsdGVyID0gTGluZWFyRmlsdGVyLCBtaW5GaWx0ZXIgPSBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXIsIGZvcm1hdCA9IFJHQkFGb3JtYXQsIHR5cGUgPSBVbnNpZ25lZEJ5dGVUeXBlLCBhbmlzb3Ryb3B5ID0gVGV4dHVyZS5ERUZBVUxUX0FOSVNPVFJPUFksIGNvbG9yU3BhY2UgPSBOb0NvbG9yU3BhY2UgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc1RleHR1cmUgPSB0cnVlO1xuXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfdGV4dHVyZUlkICsrIH0gKTtcblxuXHRcdHRoaXMudXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0dGhpcy5uYW1lID0gJyc7XG5cblx0XHR0aGlzLnNvdXJjZSA9IG5ldyBTb3VyY2UoIGltYWdlICk7XG5cdFx0dGhpcy5taXBtYXBzID0gW107XG5cblx0XHR0aGlzLm1hcHBpbmcgPSBtYXBwaW5nO1xuXHRcdHRoaXMuY2hhbm5lbCA9IDA7XG5cblx0XHR0aGlzLndyYXBTID0gd3JhcFM7XG5cdFx0dGhpcy53cmFwVCA9IHdyYXBUO1xuXG5cdFx0dGhpcy5tYWdGaWx0ZXIgPSBtYWdGaWx0ZXI7XG5cdFx0dGhpcy5taW5GaWx0ZXIgPSBtaW5GaWx0ZXI7XG5cblx0XHR0aGlzLmFuaXNvdHJvcHkgPSBhbmlzb3Ryb3B5O1xuXG5cdFx0dGhpcy5mb3JtYXQgPSBmb3JtYXQ7XG5cdFx0dGhpcy5pbnRlcm5hbEZvcm1hdCA9IG51bGw7XG5cdFx0dGhpcy50eXBlID0gdHlwZTtcblxuXHRcdHRoaXMub2Zmc2V0ID0gbmV3IFZlY3RvcjIoIDAsIDAgKTtcblx0XHR0aGlzLnJlcGVhdCA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XG5cdFx0dGhpcy5jZW50ZXIgPSBuZXcgVmVjdG9yMiggMCwgMCApO1xuXHRcdHRoaXMucm90YXRpb24gPSAwO1xuXG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gdHJ1ZTtcblx0XHR0aGlzLm1hdHJpeCA9IG5ldyBNYXRyaXgzKCk7XG5cblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IHRydWU7XG5cdFx0dGhpcy5wcmVtdWx0aXBseUFscGhhID0gZmFsc2U7XG5cdFx0dGhpcy5mbGlwWSA9IHRydWU7XG5cdFx0dGhpcy51bnBhY2tBbGlnbm1lbnQgPSA0O1x0Ly8gdmFsaWQgdmFsdWVzOiAxLCAyLCA0LCA4IChzZWUgaHR0cDovL3d3dy5raHJvbm9zLm9yZy9vcGVuZ2xlcy9zZGsvZG9jcy9tYW4veGh0bWwvZ2xQaXhlbFN0b3JlaS54bWwpXG5cblx0XHR0aGlzLmNvbG9yU3BhY2UgPSBjb2xvclNwYWNlO1xuXG5cdFx0dGhpcy51c2VyRGF0YSA9IHt9O1xuXG5cdFx0dGhpcy52ZXJzaW9uID0gMDtcblx0XHR0aGlzLm9uVXBkYXRlID0gbnVsbDtcblxuXHRcdHRoaXMuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID0gZmFsc2U7IC8vIGluZGljYXRlcyB3aGV0aGVyIGEgdGV4dHVyZSBiZWxvbmdzIHRvIGEgcmVuZGVyIHRhcmdldCBvciBub3Rcblx0XHR0aGlzLnBtcmVtVmVyc2lvbiA9IDA7IC8vIGluZGljYXRlcyB3aGV0aGVyIHRoaXMgdGV4dHVyZSBzaG91bGQgYmUgcHJvY2Vzc2VkIGJ5IFBNUkVNR2VuZXJhdG9yIG9yIG5vdCAob25seSByZWxldmFudCBmb3IgcmVuZGVyIHRhcmdldCB0ZXh0dXJlcylcblxuXHR9XG5cblx0Z2V0IGltYWdlKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuc291cmNlLmRhdGE7XG5cblx0fVxuXG5cdHNldCBpbWFnZSggdmFsdWUgPSBudWxsICkge1xuXG5cdFx0dGhpcy5zb3VyY2UuZGF0YSA9IHZhbHVlO1xuXG5cdH1cblxuXHR1cGRhdGVNYXRyaXgoKSB7XG5cblx0XHR0aGlzLm1hdHJpeC5zZXRVdlRyYW5zZm9ybSggdGhpcy5vZmZzZXQueCwgdGhpcy5vZmZzZXQueSwgdGhpcy5yZXBlYXQueCwgdGhpcy5yZXBlYXQueSwgdGhpcy5yb3RhdGlvbiwgdGhpcy5jZW50ZXIueCwgdGhpcy5jZW50ZXIueSApO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0dGhpcy5uYW1lID0gc291cmNlLm5hbWU7XG5cblx0XHR0aGlzLnNvdXJjZSA9IHNvdXJjZS5zb3VyY2U7XG5cdFx0dGhpcy5taXBtYXBzID0gc291cmNlLm1pcG1hcHMuc2xpY2UoIDAgKTtcblxuXHRcdHRoaXMubWFwcGluZyA9IHNvdXJjZS5tYXBwaW5nO1xuXHRcdHRoaXMuY2hhbm5lbCA9IHNvdXJjZS5jaGFubmVsO1xuXG5cdFx0dGhpcy53cmFwUyA9IHNvdXJjZS53cmFwUztcblx0XHR0aGlzLndyYXBUID0gc291cmNlLndyYXBUO1xuXG5cdFx0dGhpcy5tYWdGaWx0ZXIgPSBzb3VyY2UubWFnRmlsdGVyO1xuXHRcdHRoaXMubWluRmlsdGVyID0gc291cmNlLm1pbkZpbHRlcjtcblxuXHRcdHRoaXMuYW5pc290cm9weSA9IHNvdXJjZS5hbmlzb3Ryb3B5O1xuXG5cdFx0dGhpcy5mb3JtYXQgPSBzb3VyY2UuZm9ybWF0O1xuXHRcdHRoaXMuaW50ZXJuYWxGb3JtYXQgPSBzb3VyY2UuaW50ZXJuYWxGb3JtYXQ7XG5cdFx0dGhpcy50eXBlID0gc291cmNlLnR5cGU7XG5cblx0XHR0aGlzLm9mZnNldC5jb3B5KCBzb3VyY2Uub2Zmc2V0ICk7XG5cdFx0dGhpcy5yZXBlYXQuY29weSggc291cmNlLnJlcGVhdCApO1xuXHRcdHRoaXMuY2VudGVyLmNvcHkoIHNvdXJjZS5jZW50ZXIgKTtcblx0XHR0aGlzLnJvdGF0aW9uID0gc291cmNlLnJvdGF0aW9uO1xuXG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gc291cmNlLm1hdHJpeEF1dG9VcGRhdGU7XG5cdFx0dGhpcy5tYXRyaXguY29weSggc291cmNlLm1hdHJpeCApO1xuXG5cdFx0dGhpcy5nZW5lcmF0ZU1pcG1hcHMgPSBzb3VyY2UuZ2VuZXJhdGVNaXBtYXBzO1xuXHRcdHRoaXMucHJlbXVsdGlwbHlBbHBoYSA9IHNvdXJjZS5wcmVtdWx0aXBseUFscGhhO1xuXHRcdHRoaXMuZmxpcFkgPSBzb3VyY2UuZmxpcFk7XG5cdFx0dGhpcy51bnBhY2tBbGlnbm1lbnQgPSBzb3VyY2UudW5wYWNrQWxpZ25tZW50O1xuXHRcdHRoaXMuY29sb3JTcGFjZSA9IHNvdXJjZS5jb2xvclNwYWNlO1xuXG5cdFx0dGhpcy51c2VyRGF0YSA9IEpTT04ucGFyc2UoIEpTT04uc3RyaW5naWZ5KCBzb3VyY2UudXNlckRhdGEgKSApO1xuXG5cdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCBtZXRhICkge1xuXG5cdFx0Y29uc3QgaXNSb290T2JqZWN0ID0gKCBtZXRhID09PSB1bmRlZmluZWQgfHwgdHlwZW9mIG1ldGEgPT09ICdzdHJpbmcnICk7XG5cblx0XHRpZiAoICEgaXNSb290T2JqZWN0ICYmIG1ldGEudGV4dHVyZXNbIHRoaXMudXVpZCBdICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHJldHVybiBtZXRhLnRleHR1cmVzWyB0aGlzLnV1aWQgXTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IG91dHB1dCA9IHtcblxuXHRcdFx0bWV0YWRhdGE6IHtcblx0XHRcdFx0dmVyc2lvbjogNC42LFxuXHRcdFx0XHR0eXBlOiAnVGV4dHVyZScsXG5cdFx0XHRcdGdlbmVyYXRvcjogJ1RleHR1cmUudG9KU09OJ1xuXHRcdFx0fSxcblxuXHRcdFx0dXVpZDogdGhpcy51dWlkLFxuXHRcdFx0bmFtZTogdGhpcy5uYW1lLFxuXG5cdFx0XHRpbWFnZTogdGhpcy5zb3VyY2UudG9KU09OKCBtZXRhICkudXVpZCxcblxuXHRcdFx0bWFwcGluZzogdGhpcy5tYXBwaW5nLFxuXHRcdFx0Y2hhbm5lbDogdGhpcy5jaGFubmVsLFxuXG5cdFx0XHRyZXBlYXQ6IFsgdGhpcy5yZXBlYXQueCwgdGhpcy5yZXBlYXQueSBdLFxuXHRcdFx0b2Zmc2V0OiBbIHRoaXMub2Zmc2V0LngsIHRoaXMub2Zmc2V0LnkgXSxcblx0XHRcdGNlbnRlcjogWyB0aGlzLmNlbnRlci54LCB0aGlzLmNlbnRlci55IF0sXG5cdFx0XHRyb3RhdGlvbjogdGhpcy5yb3RhdGlvbixcblxuXHRcdFx0d3JhcDogWyB0aGlzLndyYXBTLCB0aGlzLndyYXBUIF0sXG5cblx0XHRcdGZvcm1hdDogdGhpcy5mb3JtYXQsXG5cdFx0XHRpbnRlcm5hbEZvcm1hdDogdGhpcy5pbnRlcm5hbEZvcm1hdCxcblx0XHRcdHR5cGU6IHRoaXMudHlwZSxcblx0XHRcdGNvbG9yU3BhY2U6IHRoaXMuY29sb3JTcGFjZSxcblxuXHRcdFx0bWluRmlsdGVyOiB0aGlzLm1pbkZpbHRlcixcblx0XHRcdG1hZ0ZpbHRlcjogdGhpcy5tYWdGaWx0ZXIsXG5cdFx0XHRhbmlzb3Ryb3B5OiB0aGlzLmFuaXNvdHJvcHksXG5cblx0XHRcdGZsaXBZOiB0aGlzLmZsaXBZLFxuXG5cdFx0XHRnZW5lcmF0ZU1pcG1hcHM6IHRoaXMuZ2VuZXJhdGVNaXBtYXBzLFxuXHRcdFx0cHJlbXVsdGlwbHlBbHBoYTogdGhpcy5wcmVtdWx0aXBseUFscGhhLFxuXHRcdFx0dW5wYWNrQWxpZ25tZW50OiB0aGlzLnVucGFja0FsaWdubWVudFxuXG5cdFx0fTtcblxuXHRcdGlmICggT2JqZWN0LmtleXMoIHRoaXMudXNlckRhdGEgKS5sZW5ndGggPiAwICkgb3V0cHV0LnVzZXJEYXRhID0gdGhpcy51c2VyRGF0YTtcblxuXHRcdGlmICggISBpc1Jvb3RPYmplY3QgKSB7XG5cblx0XHRcdG1ldGEudGV4dHVyZXNbIHRoaXMudXVpZCBdID0gb3V0cHV0O1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG91dHB1dDtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzcG9zZScgfSApO1xuXG5cdH1cblxuXHR0cmFuc2Zvcm1VdiggdXYgKSB7XG5cblx0XHRpZiAoIHRoaXMubWFwcGluZyAhPT0gVVZNYXBwaW5nICkgcmV0dXJuIHV2O1xuXG5cdFx0dXYuYXBwbHlNYXRyaXgzKCB0aGlzLm1hdHJpeCApO1xuXG5cdFx0aWYgKCB1di54IDwgMCB8fCB1di54ID4gMSApIHtcblxuXHRcdFx0c3dpdGNoICggdGhpcy53cmFwUyApIHtcblxuXHRcdFx0XHRjYXNlIFJlcGVhdFdyYXBwaW5nOlxuXG5cdFx0XHRcdFx0dXYueCA9IHV2LnggLSBNYXRoLmZsb29yKCB1di54ICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBDbGFtcFRvRWRnZVdyYXBwaW5nOlxuXG5cdFx0XHRcdFx0dXYueCA9IHV2LnggPCAwID8gMCA6IDE7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBNaXJyb3JlZFJlcGVhdFdyYXBwaW5nOlxuXG5cdFx0XHRcdFx0aWYgKCBNYXRoLmFicyggTWF0aC5mbG9vciggdXYueCApICUgMiApID09PSAxICkge1xuXG5cdFx0XHRcdFx0XHR1di54ID0gTWF0aC5jZWlsKCB1di54ICkgLSB1di54O1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0dXYueCA9IHV2LnggLSBNYXRoLmZsb29yKCB1di54ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCB1di55IDwgMCB8fCB1di55ID4gMSApIHtcblxuXHRcdFx0c3dpdGNoICggdGhpcy53cmFwVCApIHtcblxuXHRcdFx0XHRjYXNlIFJlcGVhdFdyYXBwaW5nOlxuXG5cdFx0XHRcdFx0dXYueSA9IHV2LnkgLSBNYXRoLmZsb29yKCB1di55ICk7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBDbGFtcFRvRWRnZVdyYXBwaW5nOlxuXG5cdFx0XHRcdFx0dXYueSA9IHV2LnkgPCAwID8gMCA6IDE7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBNaXJyb3JlZFJlcGVhdFdyYXBwaW5nOlxuXG5cdFx0XHRcdFx0aWYgKCBNYXRoLmFicyggTWF0aC5mbG9vciggdXYueSApICUgMiApID09PSAxICkge1xuXG5cdFx0XHRcdFx0XHR1di55ID0gTWF0aC5jZWlsKCB1di55ICkgLSB1di55O1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0dXYueSA9IHV2LnkgLSBNYXRoLmZsb29yKCB1di55ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmZsaXBZICkge1xuXG5cdFx0XHR1di55ID0gMSAtIHV2Lnk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdXY7XG5cblx0fVxuXG5cdHNldCBuZWVkc1VwZGF0ZSggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHZhbHVlID09PSB0cnVlICkge1xuXG5cdFx0XHR0aGlzLnZlcnNpb24gKys7XG5cdFx0XHR0aGlzLnNvdXJjZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR9XG5cblx0fVxuXG5cdHNldCBuZWVkc1BNUkVNVXBkYXRlKCB2YWx1ZSApIHtcblxuXHRcdGlmICggdmFsdWUgPT09IHRydWUgKSB7XG5cblx0XHRcdHRoaXMucG1yZW1WZXJzaW9uICsrO1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5UZXh0dXJlLkRFRkFVTFRfSU1BR0UgPSBudWxsO1xuVGV4dHVyZS5ERUZBVUxUX01BUFBJTkcgPSBVVk1hcHBpbmc7XG5UZXh0dXJlLkRFRkFVTFRfQU5JU09UUk9QWSA9IDE7XG5cbmNsYXNzIFZlY3RvcjQge1xuXG5cdGNvbnN0cnVjdG9yKCB4ID0gMCwgeSA9IDAsIHogPSAwLCB3ID0gMSApIHtcblxuXHRcdFZlY3RvcjQucHJvdG90eXBlLmlzVmVjdG9yNCA9IHRydWU7XG5cblx0XHR0aGlzLnggPSB4O1xuXHRcdHRoaXMueSA9IHk7XG5cdFx0dGhpcy56ID0gejtcblx0XHR0aGlzLncgPSB3O1xuXG5cdH1cblxuXHRnZXQgd2lkdGgoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy56O1xuXG5cdH1cblxuXHRzZXQgd2lkdGgoIHZhbHVlICkge1xuXG5cdFx0dGhpcy56ID0gdmFsdWU7XG5cblx0fVxuXG5cdGdldCBoZWlnaHQoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy53O1xuXG5cdH1cblxuXHRzZXQgaGVpZ2h0KCB2YWx1ZSApIHtcblxuXHRcdHRoaXMudyA9IHZhbHVlO1xuXG5cdH1cblxuXHRzZXQoIHgsIHksIHosIHcgKSB7XG5cblx0XHR0aGlzLnggPSB4O1xuXHRcdHRoaXMueSA9IHk7XG5cdFx0dGhpcy56ID0gejtcblx0XHR0aGlzLncgPSB3O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFNjYWxhciggc2NhbGFyICkge1xuXG5cdFx0dGhpcy54ID0gc2NhbGFyO1xuXHRcdHRoaXMueSA9IHNjYWxhcjtcblx0XHR0aGlzLnogPSBzY2FsYXI7XG5cdFx0dGhpcy53ID0gc2NhbGFyO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFgoIHggKSB7XG5cblx0XHR0aGlzLnggPSB4O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFkoIHkgKSB7XG5cblx0XHR0aGlzLnkgPSB5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFooIHogKSB7XG5cblx0XHR0aGlzLnogPSB6O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFcoIHcgKSB7XG5cblx0XHR0aGlzLncgPSB3O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldENvbXBvbmVudCggaW5kZXgsIHZhbHVlICkge1xuXG5cdFx0c3dpdGNoICggaW5kZXggKSB7XG5cblx0XHRcdGNhc2UgMDogdGhpcy54ID0gdmFsdWU7IGJyZWFrO1xuXHRcdFx0Y2FzZSAxOiB0aGlzLnkgPSB2YWx1ZTsgYnJlYWs7XG5cdFx0XHRjYXNlIDI6IHRoaXMueiA9IHZhbHVlOyBicmVhaztcblx0XHRcdGNhc2UgMzogdGhpcy53ID0gdmFsdWU7IGJyZWFrO1xuXHRcdFx0ZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKCAnaW5kZXggaXMgb3V0IG9mIHJhbmdlOiAnICsgaW5kZXggKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRDb21wb25lbnQoIGluZGV4ICkge1xuXG5cdFx0c3dpdGNoICggaW5kZXggKSB7XG5cblx0XHRcdGNhc2UgMDogcmV0dXJuIHRoaXMueDtcblx0XHRcdGNhc2UgMTogcmV0dXJuIHRoaXMueTtcblx0XHRcdGNhc2UgMjogcmV0dXJuIHRoaXMuejtcblx0XHRcdGNhc2UgMzogcmV0dXJuIHRoaXMudztcblx0XHRcdGRlZmF1bHQ6IHRocm93IG5ldyBFcnJvciggJ2luZGV4IGlzIG91dCBvZiByYW5nZTogJyArIGluZGV4ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCB0aGlzLngsIHRoaXMueSwgdGhpcy56LCB0aGlzLncgKTtcblxuXHR9XG5cblx0Y29weSggdiApIHtcblxuXHRcdHRoaXMueCA9IHYueDtcblx0XHR0aGlzLnkgPSB2Lnk7XG5cdFx0dGhpcy56ID0gdi56O1xuXHRcdHRoaXMudyA9ICggdi53ICE9PSB1bmRlZmluZWQgKSA/IHYudyA6IDE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkKCB2ICkge1xuXG5cdFx0dGhpcy54ICs9IHYueDtcblx0XHR0aGlzLnkgKz0gdi55O1xuXHRcdHRoaXMueiArPSB2Lno7XG5cdFx0dGhpcy53ICs9IHYudztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhZGRTY2FsYXIoIHMgKSB7XG5cblx0XHR0aGlzLnggKz0gcztcblx0XHR0aGlzLnkgKz0gcztcblx0XHR0aGlzLnogKz0gcztcblx0XHR0aGlzLncgKz0gcztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhZGRWZWN0b3JzKCBhLCBiICkge1xuXG5cdFx0dGhpcy54ID0gYS54ICsgYi54O1xuXHRcdHRoaXMueSA9IGEueSArIGIueTtcblx0XHR0aGlzLnogPSBhLnogKyBiLno7XG5cdFx0dGhpcy53ID0gYS53ICsgYi53O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFkZFNjYWxlZFZlY3RvciggdiwgcyApIHtcblxuXHRcdHRoaXMueCArPSB2LnggKiBzO1xuXHRcdHRoaXMueSArPSB2LnkgKiBzO1xuXHRcdHRoaXMueiArPSB2LnogKiBzO1xuXHRcdHRoaXMudyArPSB2LncgKiBzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN1YiggdiApIHtcblxuXHRcdHRoaXMueCAtPSB2Lng7XG5cdFx0dGhpcy55IC09IHYueTtcblx0XHR0aGlzLnogLT0gdi56O1xuXHRcdHRoaXMudyAtPSB2Lnc7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3ViU2NhbGFyKCBzICkge1xuXG5cdFx0dGhpcy54IC09IHM7XG5cdFx0dGhpcy55IC09IHM7XG5cdFx0dGhpcy56IC09IHM7XG5cdFx0dGhpcy53IC09IHM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3ViVmVjdG9ycyggYSwgYiApIHtcblxuXHRcdHRoaXMueCA9IGEueCAtIGIueDtcblx0XHR0aGlzLnkgPSBhLnkgLSBiLnk7XG5cdFx0dGhpcy56ID0gYS56IC0gYi56O1xuXHRcdHRoaXMudyA9IGEudyAtIGIudztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtdWx0aXBseSggdiApIHtcblxuXHRcdHRoaXMueCAqPSB2Lng7XG5cdFx0dGhpcy55ICo9IHYueTtcblx0XHR0aGlzLnogKj0gdi56O1xuXHRcdHRoaXMudyAqPSB2Lnc7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bXVsdGlwbHlTY2FsYXIoIHNjYWxhciApIHtcblxuXHRcdHRoaXMueCAqPSBzY2FsYXI7XG5cdFx0dGhpcy55ICo9IHNjYWxhcjtcblx0XHR0aGlzLnogKj0gc2NhbGFyO1xuXHRcdHRoaXMudyAqPSBzY2FsYXI7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXBwbHlNYXRyaXg0KCBtICkge1xuXG5cdFx0Y29uc3QgeCA9IHRoaXMueCwgeSA9IHRoaXMueSwgeiA9IHRoaXMueiwgdyA9IHRoaXMudztcblx0XHRjb25zdCBlID0gbS5lbGVtZW50cztcblxuXHRcdHRoaXMueCA9IGVbIDAgXSAqIHggKyBlWyA0IF0gKiB5ICsgZVsgOCBdICogeiArIGVbIDEyIF0gKiB3O1xuXHRcdHRoaXMueSA9IGVbIDEgXSAqIHggKyBlWyA1IF0gKiB5ICsgZVsgOSBdICogeiArIGVbIDEzIF0gKiB3O1xuXHRcdHRoaXMueiA9IGVbIDIgXSAqIHggKyBlWyA2IF0gKiB5ICsgZVsgMTAgXSAqIHogKyBlWyAxNCBdICogdztcblx0XHR0aGlzLncgPSBlWyAzIF0gKiB4ICsgZVsgNyBdICogeSArIGVbIDExIF0gKiB6ICsgZVsgMTUgXSAqIHc7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGl2aWRlU2NhbGFyKCBzY2FsYXIgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseVNjYWxhciggMSAvIHNjYWxhciApO1xuXG5cdH1cblxuXHRzZXRBeGlzQW5nbGVGcm9tUXVhdGVybmlvbiggcSApIHtcblxuXHRcdC8vIGh0dHA6Ly93d3cuZXVjbGlkZWFuc3BhY2UuY29tL21hdGhzL2dlb21ldHJ5L3JvdGF0aW9ucy9jb252ZXJzaW9ucy9xdWF0ZXJuaW9uVG9BbmdsZS9pbmRleC5odG1cblxuXHRcdC8vIHEgaXMgYXNzdW1lZCB0byBiZSBub3JtYWxpemVkXG5cblx0XHR0aGlzLncgPSAyICogTWF0aC5hY29zKCBxLncgKTtcblxuXHRcdGNvbnN0IHMgPSBNYXRoLnNxcnQoIDEgLSBxLncgKiBxLncgKTtcblxuXHRcdGlmICggcyA8IDAuMDAwMSApIHtcblxuXHRcdFx0dGhpcy54ID0gMTtcblx0XHRcdHRoaXMueSA9IDA7XG5cdFx0XHR0aGlzLnogPSAwO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhpcy54ID0gcS54IC8gcztcblx0XHRcdHRoaXMueSA9IHEueSAvIHM7XG5cdFx0XHR0aGlzLnogPSBxLnogLyBzO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEF4aXNBbmdsZUZyb21Sb3RhdGlvbk1hdHJpeCggbSApIHtcblxuXHRcdC8vIGh0dHA6Ly93d3cuZXVjbGlkZWFuc3BhY2UuY29tL21hdGhzL2dlb21ldHJ5L3JvdGF0aW9ucy9jb252ZXJzaW9ucy9tYXRyaXhUb0FuZ2xlL2luZGV4Lmh0bVxuXG5cdFx0Ly8gYXNzdW1lcyB0aGUgdXBwZXIgM3gzIG9mIG0gaXMgYSBwdXJlIHJvdGF0aW9uIG1hdHJpeCAoaS5lLCB1bnNjYWxlZClcblxuXHRcdGxldCBhbmdsZSwgeCwgeSwgejsgLy8gdmFyaWFibGVzIGZvciByZXN1bHRcblx0XHRjb25zdCBlcHNpbG9uID0gMC4wMSxcdFx0Ly8gbWFyZ2luIHRvIGFsbG93IGZvciByb3VuZGluZyBlcnJvcnNcblx0XHRcdGVwc2lsb24yID0gMC4xLFx0XHQvLyBtYXJnaW4gdG8gZGlzdGluZ3Vpc2ggYmV0d2VlbiAwIGFuZCAxODAgZGVncmVlc1xuXG5cdFx0XHR0ZSA9IG0uZWxlbWVudHMsXG5cblx0XHRcdG0xMSA9IHRlWyAwIF0sIG0xMiA9IHRlWyA0IF0sIG0xMyA9IHRlWyA4IF0sXG5cdFx0XHRtMjEgPSB0ZVsgMSBdLCBtMjIgPSB0ZVsgNSBdLCBtMjMgPSB0ZVsgOSBdLFxuXHRcdFx0bTMxID0gdGVbIDIgXSwgbTMyID0gdGVbIDYgXSwgbTMzID0gdGVbIDEwIF07XG5cblx0XHRpZiAoICggTWF0aC5hYnMoIG0xMiAtIG0yMSApIDwgZXBzaWxvbiApICYmXG5cdFx0ICAgICAoIE1hdGguYWJzKCBtMTMgLSBtMzEgKSA8IGVwc2lsb24gKSAmJlxuXHRcdCAgICAgKCBNYXRoLmFicyggbTIzIC0gbTMyICkgPCBlcHNpbG9uICkgKSB7XG5cblx0XHRcdC8vIHNpbmd1bGFyaXR5IGZvdW5kXG5cdFx0XHQvLyBmaXJzdCBjaGVjayBmb3IgaWRlbnRpdHkgbWF0cml4IHdoaWNoIG11c3QgaGF2ZSArMSBmb3IgYWxsIHRlcm1zXG5cdFx0XHQvLyBpbiBsZWFkaW5nIGRpYWdvbmFsIGFuZCB6ZXJvIGluIG90aGVyIHRlcm1zXG5cblx0XHRcdGlmICggKCBNYXRoLmFicyggbTEyICsgbTIxICkgPCBlcHNpbG9uMiApICYmXG5cdFx0XHQgICAgICggTWF0aC5hYnMoIG0xMyArIG0zMSApIDwgZXBzaWxvbjIgKSAmJlxuXHRcdFx0ICAgICAoIE1hdGguYWJzKCBtMjMgKyBtMzIgKSA8IGVwc2lsb24yICkgJiZcblx0XHRcdCAgICAgKCBNYXRoLmFicyggbTExICsgbTIyICsgbTMzIC0gMyApIDwgZXBzaWxvbjIgKSApIHtcblxuXHRcdFx0XHQvLyB0aGlzIHNpbmd1bGFyaXR5IGlzIGlkZW50aXR5IG1hdHJpeCBzbyBhbmdsZSA9IDBcblxuXHRcdFx0XHR0aGlzLnNldCggMSwgMCwgMCwgMCApO1xuXG5cdFx0XHRcdHJldHVybiB0aGlzOyAvLyB6ZXJvIGFuZ2xlLCBhcmJpdHJhcnkgYXhpc1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIG90aGVyd2lzZSB0aGlzIHNpbmd1bGFyaXR5IGlzIGFuZ2xlID0gMTgwXG5cblx0XHRcdGFuZ2xlID0gTWF0aC5QSTtcblxuXHRcdFx0Y29uc3QgeHggPSAoIG0xMSArIDEgKSAvIDI7XG5cdFx0XHRjb25zdCB5eSA9ICggbTIyICsgMSApIC8gMjtcblx0XHRcdGNvbnN0IHp6ID0gKCBtMzMgKyAxICkgLyAyO1xuXHRcdFx0Y29uc3QgeHkgPSAoIG0xMiArIG0yMSApIC8gNDtcblx0XHRcdGNvbnN0IHh6ID0gKCBtMTMgKyBtMzEgKSAvIDQ7XG5cdFx0XHRjb25zdCB5eiA9ICggbTIzICsgbTMyICkgLyA0O1xuXG5cdFx0XHRpZiAoICggeHggPiB5eSApICYmICggeHggPiB6eiApICkge1xuXG5cdFx0XHRcdC8vIG0xMSBpcyB0aGUgbGFyZ2VzdCBkaWFnb25hbCB0ZXJtXG5cblx0XHRcdFx0aWYgKCB4eCA8IGVwc2lsb24gKSB7XG5cblx0XHRcdFx0XHR4ID0gMDtcblx0XHRcdFx0XHR5ID0gMC43MDcxMDY3ODE7XG5cdFx0XHRcdFx0eiA9IDAuNzA3MTA2NzgxO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHR4ID0gTWF0aC5zcXJ0KCB4eCApO1xuXHRcdFx0XHRcdHkgPSB4eSAvIHg7XG5cdFx0XHRcdFx0eiA9IHh6IC8geDtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSBpZiAoIHl5ID4genogKSB7XG5cblx0XHRcdFx0Ly8gbTIyIGlzIHRoZSBsYXJnZXN0IGRpYWdvbmFsIHRlcm1cblxuXHRcdFx0XHRpZiAoIHl5IDwgZXBzaWxvbiApIHtcblxuXHRcdFx0XHRcdHggPSAwLjcwNzEwNjc4MTtcblx0XHRcdFx0XHR5ID0gMDtcblx0XHRcdFx0XHR6ID0gMC43MDcxMDY3ODE7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHkgPSBNYXRoLnNxcnQoIHl5ICk7XG5cdFx0XHRcdFx0eCA9IHh5IC8geTtcblx0XHRcdFx0XHR6ID0geXogLyB5O1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyBtMzMgaXMgdGhlIGxhcmdlc3QgZGlhZ29uYWwgdGVybSBzbyBiYXNlIHJlc3VsdCBvbiB0aGlzXG5cblx0XHRcdFx0aWYgKCB6eiA8IGVwc2lsb24gKSB7XG5cblx0XHRcdFx0XHR4ID0gMC43MDcxMDY3ODE7XG5cdFx0XHRcdFx0eSA9IDAuNzA3MTA2NzgxO1xuXHRcdFx0XHRcdHogPSAwO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHR6ID0gTWF0aC5zcXJ0KCB6eiApO1xuXHRcdFx0XHRcdHggPSB4eiAvIHo7XG5cdFx0XHRcdFx0eSA9IHl6IC8gejtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5zZXQoIHgsIHksIHosIGFuZ2xlICk7XG5cblx0XHRcdHJldHVybiB0aGlzOyAvLyByZXR1cm4gMTgwIGRlZyByb3RhdGlvblxuXG5cdFx0fVxuXG5cdFx0Ly8gYXMgd2UgaGF2ZSByZWFjaGVkIGhlcmUgdGhlcmUgYXJlIG5vIHNpbmd1bGFyaXRpZXMgc28gd2UgY2FuIGhhbmRsZSBub3JtYWxseVxuXG5cdFx0bGV0IHMgPSBNYXRoLnNxcnQoICggbTMyIC0gbTIzICkgKiAoIG0zMiAtIG0yMyApICtcblx0XHRcdCggbTEzIC0gbTMxICkgKiAoIG0xMyAtIG0zMSApICtcblx0XHRcdCggbTIxIC0gbTEyICkgKiAoIG0yMSAtIG0xMiApICk7IC8vIHVzZWQgdG8gbm9ybWFsaXplXG5cblx0XHRpZiAoIE1hdGguYWJzKCBzICkgPCAwLjAwMSApIHMgPSAxO1xuXG5cdFx0Ly8gcHJldmVudCBkaXZpZGUgYnkgemVybywgc2hvdWxkIG5vdCBoYXBwZW4gaWYgbWF0cml4IGlzIG9ydGhvZ29uYWwgYW5kIHNob3VsZCBiZVxuXHRcdC8vIGNhdWdodCBieSBzaW5ndWxhcml0eSB0ZXN0IGFib3ZlLCBidXQgSSd2ZSBsZWZ0IGl0IGluIGp1c3QgaW4gY2FzZVxuXG5cdFx0dGhpcy54ID0gKCBtMzIgLSBtMjMgKSAvIHM7XG5cdFx0dGhpcy55ID0gKCBtMTMgLSBtMzEgKSAvIHM7XG5cdFx0dGhpcy56ID0gKCBtMjEgLSBtMTIgKSAvIHM7XG5cdFx0dGhpcy53ID0gTWF0aC5hY29zKCAoIG0xMSArIG0yMiArIG0zMyAtIDEgKSAvIDIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tTWF0cml4UG9zaXRpb24oIG0gKSB7XG5cblx0XHRjb25zdCBlID0gbS5lbGVtZW50cztcblxuXHRcdHRoaXMueCA9IGVbIDEyIF07XG5cdFx0dGhpcy55ID0gZVsgMTMgXTtcblx0XHR0aGlzLnogPSBlWyAxNCBdO1xuXHRcdHRoaXMudyA9IGVbIDE1IF07XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bWluKCB2ICkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC5taW4oIHRoaXMueCwgdi54ICk7XG5cdFx0dGhpcy55ID0gTWF0aC5taW4oIHRoaXMueSwgdi55ICk7XG5cdFx0dGhpcy56ID0gTWF0aC5taW4oIHRoaXMueiwgdi56ICk7XG5cdFx0dGhpcy53ID0gTWF0aC5taW4oIHRoaXMudywgdi53ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bWF4KCB2ICkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC5tYXgoIHRoaXMueCwgdi54ICk7XG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIHRoaXMueSwgdi55ICk7XG5cdFx0dGhpcy56ID0gTWF0aC5tYXgoIHRoaXMueiwgdi56ICk7XG5cdFx0dGhpcy53ID0gTWF0aC5tYXgoIHRoaXMudywgdi53ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xhbXAoIG1pbiwgbWF4ICkge1xuXG5cdFx0Ly8gYXNzdW1lcyBtaW4gPCBtYXgsIGNvbXBvbmVudHdpc2VcblxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCBtaW4ueCwgTWF0aC5taW4oIG1heC54LCB0aGlzLnggKSApO1xuXHRcdHRoaXMueSA9IE1hdGgubWF4KCBtaW4ueSwgTWF0aC5taW4oIG1heC55LCB0aGlzLnkgKSApO1xuXHRcdHRoaXMueiA9IE1hdGgubWF4KCBtaW4ueiwgTWF0aC5taW4oIG1heC56LCB0aGlzLnogKSApO1xuXHRcdHRoaXMudyA9IE1hdGgubWF4KCBtaW4udywgTWF0aC5taW4oIG1heC53LCB0aGlzLncgKSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsYW1wU2NhbGFyKCBtaW5WYWwsIG1heFZhbCApIHtcblxuXHRcdHRoaXMueCA9IE1hdGgubWF4KCBtaW5WYWwsIE1hdGgubWluKCBtYXhWYWwsIHRoaXMueCApICk7XG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIG1pblZhbCwgTWF0aC5taW4oIG1heFZhbCwgdGhpcy55ICkgKTtcblx0XHR0aGlzLnogPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnogKSApO1xuXHRcdHRoaXMudyA9IE1hdGgubWF4KCBtaW5WYWwsIE1hdGgubWluKCBtYXhWYWwsIHRoaXMudyApICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xhbXBMZW5ndGgoIG1pbiwgbWF4ICkge1xuXG5cdFx0Y29uc3QgbGVuZ3RoID0gdGhpcy5sZW5ndGgoKTtcblxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggbGVuZ3RoIHx8IDEgKS5tdWx0aXBseVNjYWxhciggTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgbGVuZ3RoICkgKSApO1xuXG5cdH1cblxuXHRmbG9vcigpIHtcblxuXHRcdHRoaXMueCA9IE1hdGguZmxvb3IoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGguZmxvb3IoIHRoaXMueSApO1xuXHRcdHRoaXMueiA9IE1hdGguZmxvb3IoIHRoaXMueiApO1xuXHRcdHRoaXMudyA9IE1hdGguZmxvb3IoIHRoaXMudyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNlaWwoKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLmNlaWwoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGguY2VpbCggdGhpcy55ICk7XG5cdFx0dGhpcy56ID0gTWF0aC5jZWlsKCB0aGlzLnogKTtcblx0XHR0aGlzLncgPSBNYXRoLmNlaWwoIHRoaXMudyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJvdW5kKCkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC5yb3VuZCggdGhpcy54ICk7XG5cdFx0dGhpcy55ID0gTWF0aC5yb3VuZCggdGhpcy55ICk7XG5cdFx0dGhpcy56ID0gTWF0aC5yb3VuZCggdGhpcy56ICk7XG5cdFx0dGhpcy53ID0gTWF0aC5yb3VuZCggdGhpcy53ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cm91bmRUb1plcm8oKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLnRydW5jKCB0aGlzLnggKTtcblx0XHR0aGlzLnkgPSBNYXRoLnRydW5jKCB0aGlzLnkgKTtcblx0XHR0aGlzLnogPSBNYXRoLnRydW5jKCB0aGlzLnogKTtcblx0XHR0aGlzLncgPSBNYXRoLnRydW5jKCB0aGlzLncgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRuZWdhdGUoKSB7XG5cblx0XHR0aGlzLnggPSAtIHRoaXMueDtcblx0XHR0aGlzLnkgPSAtIHRoaXMueTtcblx0XHR0aGlzLnogPSAtIHRoaXMuejtcblx0XHR0aGlzLncgPSAtIHRoaXMudztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkb3QoIHYgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy54ICogdi54ICsgdGhpcy55ICogdi55ICsgdGhpcy56ICogdi56ICsgdGhpcy53ICogdi53O1xuXG5cdH1cblxuXHRsZW5ndGhTcSgpIHtcblxuXHRcdHJldHVybiB0aGlzLnggKiB0aGlzLnggKyB0aGlzLnkgKiB0aGlzLnkgKyB0aGlzLnogKiB0aGlzLnogKyB0aGlzLncgKiB0aGlzLnc7XG5cblx0fVxuXG5cdGxlbmd0aCgpIHtcblxuXHRcdHJldHVybiBNYXRoLnNxcnQoIHRoaXMueCAqIHRoaXMueCArIHRoaXMueSAqIHRoaXMueSArIHRoaXMueiAqIHRoaXMueiArIHRoaXMudyAqIHRoaXMudyApO1xuXG5cdH1cblxuXHRtYW5oYXR0YW5MZW5ndGgoKSB7XG5cblx0XHRyZXR1cm4gTWF0aC5hYnMoIHRoaXMueCApICsgTWF0aC5hYnMoIHRoaXMueSApICsgTWF0aC5hYnMoIHRoaXMueiApICsgTWF0aC5hYnMoIHRoaXMudyApO1xuXG5cdH1cblxuXHRub3JtYWxpemUoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5kaXZpZGVTY2FsYXIoIHRoaXMubGVuZ3RoKCkgfHwgMSApO1xuXG5cdH1cblxuXHRzZXRMZW5ndGgoIGxlbmd0aCApIHtcblxuXHRcdHJldHVybiB0aGlzLm5vcm1hbGl6ZSgpLm11bHRpcGx5U2NhbGFyKCBsZW5ndGggKTtcblxuXHR9XG5cblx0bGVycCggdiwgYWxwaGEgKSB7XG5cblx0XHR0aGlzLnggKz0gKCB2LnggLSB0aGlzLnggKSAqIGFscGhhO1xuXHRcdHRoaXMueSArPSAoIHYueSAtIHRoaXMueSApICogYWxwaGE7XG5cdFx0dGhpcy56ICs9ICggdi56IC0gdGhpcy56ICkgKiBhbHBoYTtcblx0XHR0aGlzLncgKz0gKCB2LncgLSB0aGlzLncgKSAqIGFscGhhO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGxlcnBWZWN0b3JzKCB2MSwgdjIsIGFscGhhICkge1xuXG5cdFx0dGhpcy54ID0gdjEueCArICggdjIueCAtIHYxLnggKSAqIGFscGhhO1xuXHRcdHRoaXMueSA9IHYxLnkgKyAoIHYyLnkgLSB2MS55ICkgKiBhbHBoYTtcblx0XHR0aGlzLnogPSB2MS56ICsgKCB2Mi56IC0gdjEueiApICogYWxwaGE7XG5cdFx0dGhpcy53ID0gdjEudyArICggdjIudyAtIHYxLncgKSAqIGFscGhhO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGVxdWFscyggdiApIHtcblxuXHRcdHJldHVybiAoICggdi54ID09PSB0aGlzLnggKSAmJiAoIHYueSA9PT0gdGhpcy55ICkgJiYgKCB2LnogPT09IHRoaXMueiApICYmICggdi53ID09PSB0aGlzLncgKSApO1xuXG5cdH1cblxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xuXG5cdFx0dGhpcy54ID0gYXJyYXlbIG9mZnNldCBdO1xuXHRcdHRoaXMueSA9IGFycmF5WyBvZmZzZXQgKyAxIF07XG5cdFx0dGhpcy56ID0gYXJyYXlbIG9mZnNldCArIDIgXTtcblx0XHR0aGlzLncgPSBhcnJheVsgb2Zmc2V0ICsgMyBdO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvQXJyYXkoIGFycmF5ID0gW10sIG9mZnNldCA9IDAgKSB7XG5cblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLng7XG5cdFx0YXJyYXlbIG9mZnNldCArIDEgXSA9IHRoaXMueTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMiBdID0gdGhpcy56O1xuXHRcdGFycmF5WyBvZmZzZXQgKyAzIF0gPSB0aGlzLnc7XG5cblx0XHRyZXR1cm4gYXJyYXk7XG5cblx0fVxuXG5cdGZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kZXggKSB7XG5cblx0XHR0aGlzLnggPSBhdHRyaWJ1dGUuZ2V0WCggaW5kZXggKTtcblx0XHR0aGlzLnkgPSBhdHRyaWJ1dGUuZ2V0WSggaW5kZXggKTtcblx0XHR0aGlzLnogPSBhdHRyaWJ1dGUuZ2V0WiggaW5kZXggKTtcblx0XHR0aGlzLncgPSBhdHRyaWJ1dGUuZ2V0VyggaW5kZXggKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyYW5kb20oKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLnJhbmRvbSgpO1xuXHRcdHRoaXMueSA9IE1hdGgucmFuZG9tKCk7XG5cdFx0dGhpcy56ID0gTWF0aC5yYW5kb20oKTtcblx0XHR0aGlzLncgPSBNYXRoLnJhbmRvbSgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdCpbIFN5bWJvbC5pdGVyYXRvciBdKCkge1xuXG5cdFx0eWllbGQgdGhpcy54O1xuXHRcdHlpZWxkIHRoaXMueTtcblx0XHR5aWVsZCB0aGlzLno7XG5cdFx0eWllbGQgdGhpcy53O1xuXG5cdH1cblxufVxuXG4vKlxuIEluIG9wdGlvbnMsIHdlIGNhbiBzcGVjaWZ5OlxuICogVGV4dHVyZSBwYXJhbWV0ZXJzIGZvciBhbiBhdXRvLWdlbmVyYXRlZCB0YXJnZXQgdGV4dHVyZVxuICogZGVwdGhCdWZmZXIvc3RlbmNpbEJ1ZmZlcjogQm9vbGVhbnMgdG8gaW5kaWNhdGUgaWYgd2Ugc2hvdWxkIGdlbmVyYXRlIHRoZXNlIGJ1ZmZlcnNcbiovXG5jbGFzcyBSZW5kZXJUYXJnZXQgZXh0ZW5kcyBFdmVudERpc3BhdGNoZXIge1xuXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCA9IDEsIGhlaWdodCA9IDEsIG9wdGlvbnMgPSB7fSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzUmVuZGVyVGFyZ2V0ID0gdHJ1ZTtcblxuXHRcdHRoaXMud2lkdGggPSB3aWR0aDtcblx0XHR0aGlzLmhlaWdodCA9IGhlaWdodDtcblx0XHR0aGlzLmRlcHRoID0gMTtcblxuXHRcdHRoaXMuc2Npc3NvciA9IG5ldyBWZWN0b3I0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XG5cdFx0dGhpcy5zY2lzc29yVGVzdCA9IGZhbHNlO1xuXG5cdFx0dGhpcy52aWV3cG9ydCA9IG5ldyBWZWN0b3I0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XG5cblx0XHRjb25zdCBpbWFnZSA9IHsgd2lkdGg6IHdpZHRoLCBoZWlnaHQ6IGhlaWdodCwgZGVwdGg6IDEgfTtcblxuXHRcdG9wdGlvbnMgPSBPYmplY3QuYXNzaWduKCB7XG5cdFx0XHRnZW5lcmF0ZU1pcG1hcHM6IGZhbHNlLFxuXHRcdFx0aW50ZXJuYWxGb3JtYXQ6IG51bGwsXG5cdFx0XHRtaW5GaWx0ZXI6IExpbmVhckZpbHRlcixcblx0XHRcdGRlcHRoQnVmZmVyOiB0cnVlLFxuXHRcdFx0c3RlbmNpbEJ1ZmZlcjogZmFsc2UsXG5cdFx0XHRyZXNvbHZlRGVwdGhCdWZmZXI6IHRydWUsXG5cdFx0XHRyZXNvbHZlU3RlbmNpbEJ1ZmZlcjogdHJ1ZSxcblx0XHRcdGRlcHRoVGV4dHVyZTogbnVsbCxcblx0XHRcdHNhbXBsZXM6IDAsXG5cdFx0XHRjb3VudDogMVxuXHRcdH0sIG9wdGlvbnMgKTtcblxuXHRcdGNvbnN0IHRleHR1cmUgPSBuZXcgVGV4dHVyZSggaW1hZ2UsIG9wdGlvbnMubWFwcGluZywgb3B0aW9ucy53cmFwUywgb3B0aW9ucy53cmFwVCwgb3B0aW9ucy5tYWdGaWx0ZXIsIG9wdGlvbnMubWluRmlsdGVyLCBvcHRpb25zLmZvcm1hdCwgb3B0aW9ucy50eXBlLCBvcHRpb25zLmFuaXNvdHJvcHksIG9wdGlvbnMuY29sb3JTcGFjZSApO1xuXG5cdFx0dGV4dHVyZS5mbGlwWSA9IGZhbHNlO1xuXHRcdHRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gb3B0aW9ucy5nZW5lcmF0ZU1pcG1hcHM7XG5cdFx0dGV4dHVyZS5pbnRlcm5hbEZvcm1hdCA9IG9wdGlvbnMuaW50ZXJuYWxGb3JtYXQ7XG5cblx0XHR0aGlzLnRleHR1cmVzID0gW107XG5cblx0XHRjb25zdCBjb3VudCA9IG9wdGlvbnMuY291bnQ7XG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY291bnQ7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMudGV4dHVyZXNbIGkgXSA9IHRleHR1cmUuY2xvbmUoKTtcblx0XHRcdHRoaXMudGV4dHVyZXNbIGkgXS5pc1JlbmRlclRhcmdldFRleHR1cmUgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5kZXB0aEJ1ZmZlciA9IG9wdGlvbnMuZGVwdGhCdWZmZXI7XG5cdFx0dGhpcy5zdGVuY2lsQnVmZmVyID0gb3B0aW9ucy5zdGVuY2lsQnVmZmVyO1xuXG5cdFx0dGhpcy5yZXNvbHZlRGVwdGhCdWZmZXIgPSBvcHRpb25zLnJlc29sdmVEZXB0aEJ1ZmZlcjtcblx0XHR0aGlzLnJlc29sdmVTdGVuY2lsQnVmZmVyID0gb3B0aW9ucy5yZXNvbHZlU3RlbmNpbEJ1ZmZlcjtcblxuXHRcdHRoaXMuZGVwdGhUZXh0dXJlID0gb3B0aW9ucy5kZXB0aFRleHR1cmU7XG5cblx0XHR0aGlzLnNhbXBsZXMgPSBvcHRpb25zLnNhbXBsZXM7XG5cblx0fVxuXG5cdGdldCB0ZXh0dXJlKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMudGV4dHVyZXNbIDAgXTtcblxuXHR9XG5cblx0c2V0IHRleHR1cmUoIHZhbHVlICkge1xuXG5cdFx0dGhpcy50ZXh0dXJlc1sgMCBdID0gdmFsdWU7XG5cblx0fVxuXG5cdHNldFNpemUoIHdpZHRoLCBoZWlnaHQsIGRlcHRoID0gMSApIHtcblxuXHRcdGlmICggdGhpcy53aWR0aCAhPT0gd2lkdGggfHwgdGhpcy5oZWlnaHQgIT09IGhlaWdodCB8fCB0aGlzLmRlcHRoICE9PSBkZXB0aCApIHtcblxuXHRcdFx0dGhpcy53aWR0aCA9IHdpZHRoO1xuXHRcdFx0dGhpcy5oZWlnaHQgPSBoZWlnaHQ7XG5cdFx0XHR0aGlzLmRlcHRoID0gZGVwdGg7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0aGlzLnRleHR1cmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdHRoaXMudGV4dHVyZXNbIGkgXS5pbWFnZS53aWR0aCA9IHdpZHRoO1xuXHRcdFx0XHR0aGlzLnRleHR1cmVzWyBpIF0uaW1hZ2UuaGVpZ2h0ID0gaGVpZ2h0O1xuXHRcdFx0XHR0aGlzLnRleHR1cmVzWyBpIF0uaW1hZ2UuZGVwdGggPSBkZXB0aDtcblxuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLmRpc3Bvc2UoKTtcblxuXHRcdH1cblxuXHRcdHRoaXMudmlld3BvcnQuc2V0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XG5cdFx0dGhpcy5zY2lzc29yLnNldCggMCwgMCwgd2lkdGgsIGhlaWdodCApO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0dGhpcy53aWR0aCA9IHNvdXJjZS53aWR0aDtcblx0XHR0aGlzLmhlaWdodCA9IHNvdXJjZS5oZWlnaHQ7XG5cdFx0dGhpcy5kZXB0aCA9IHNvdXJjZS5kZXB0aDtcblxuXHRcdHRoaXMuc2Npc3Nvci5jb3B5KCBzb3VyY2Uuc2Npc3NvciApO1xuXHRcdHRoaXMuc2Npc3NvclRlc3QgPSBzb3VyY2Uuc2Npc3NvclRlc3Q7XG5cblx0XHR0aGlzLnZpZXdwb3J0LmNvcHkoIHNvdXJjZS52aWV3cG9ydCApO1xuXG5cdFx0dGhpcy50ZXh0dXJlcy5sZW5ndGggPSAwO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHNvdXJjZS50ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0dGhpcy50ZXh0dXJlc1sgaSBdID0gc291cmNlLnRleHR1cmVzWyBpIF0uY2xvbmUoKTtcblx0XHRcdHRoaXMudGV4dHVyZXNbIGkgXS5pc1JlbmRlclRhcmdldFRleHR1cmUgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0Ly8gZW5zdXJlIGltYWdlIG9iamVjdCBpcyBub3Qgc2hhcmVkLCBzZWUgIzIwMzI4XG5cblx0XHRjb25zdCBpbWFnZSA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UudGV4dHVyZS5pbWFnZSApO1xuXHRcdHRoaXMudGV4dHVyZS5zb3VyY2UgPSBuZXcgU291cmNlKCBpbWFnZSApO1xuXG5cdFx0dGhpcy5kZXB0aEJ1ZmZlciA9IHNvdXJjZS5kZXB0aEJ1ZmZlcjtcblx0XHR0aGlzLnN0ZW5jaWxCdWZmZXIgPSBzb3VyY2Uuc3RlbmNpbEJ1ZmZlcjtcblxuXHRcdHRoaXMucmVzb2x2ZURlcHRoQnVmZmVyID0gc291cmNlLnJlc29sdmVEZXB0aEJ1ZmZlcjtcblx0XHR0aGlzLnJlc29sdmVTdGVuY2lsQnVmZmVyID0gc291cmNlLnJlc29sdmVTdGVuY2lsQnVmZmVyO1xuXG5cdFx0aWYgKCBzb3VyY2UuZGVwdGhUZXh0dXJlICE9PSBudWxsICkgdGhpcy5kZXB0aFRleHR1cmUgPSBzb3VyY2UuZGVwdGhUZXh0dXJlLmNsb25lKCk7XG5cblx0XHR0aGlzLnNhbXBsZXMgPSBzb3VyY2Uuc2FtcGxlcztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFdlYkdMUmVuZGVyVGFyZ2V0IGV4dGVuZHMgUmVuZGVyVGFyZ2V0IHtcblxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBvcHRpb25zID0ge30gKSB7XG5cblx0XHRzdXBlciggd2lkdGgsIGhlaWdodCwgb3B0aW9ucyApO1xuXG5cdFx0dGhpcy5pc1dlYkdMUmVuZGVyVGFyZ2V0ID0gdHJ1ZTtcblxuXHR9XG5cbn1cblxuY2xhc3MgRGF0YUFycmF5VGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xuXG5cdGNvbnN0cnVjdG9yKCBkYXRhID0gbnVsbCwgd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBkZXB0aCA9IDEgKSB7XG5cblx0XHRzdXBlciggbnVsbCApO1xuXG5cdFx0dGhpcy5pc0RhdGFBcnJheVRleHR1cmUgPSB0cnVlO1xuXG5cdFx0dGhpcy5pbWFnZSA9IHsgZGF0YSwgd2lkdGgsIGhlaWdodCwgZGVwdGggfTtcblxuXHRcdHRoaXMubWFnRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcblx0XHR0aGlzLm1pbkZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XG5cblx0XHR0aGlzLndyYXBSID0gQ2xhbXBUb0VkZ2VXcmFwcGluZztcblxuXHRcdHRoaXMuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XG5cdFx0dGhpcy5mbGlwWSA9IGZhbHNlO1xuXHRcdHRoaXMudW5wYWNrQWxpZ25tZW50ID0gMTtcblxuXHRcdHRoaXMubGF5ZXJVcGRhdGVzID0gbmV3IFNldCgpO1xuXG5cdH1cblxuXHRhZGRMYXllclVwZGF0ZSggbGF5ZXJJbmRleCApIHtcblxuXHRcdHRoaXMubGF5ZXJVcGRhdGVzLmFkZCggbGF5ZXJJbmRleCApO1xuXG5cdH1cblxuXHRjbGVhckxheWVyVXBkYXRlcygpIHtcblxuXHRcdHRoaXMubGF5ZXJVcGRhdGVzLmNsZWFyKCk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFdlYkdMQXJyYXlSZW5kZXJUYXJnZXQgZXh0ZW5kcyBXZWJHTFJlbmRlclRhcmdldCB7XG5cblx0Y29uc3RydWN0b3IoIHdpZHRoID0gMSwgaGVpZ2h0ID0gMSwgZGVwdGggPSAxLCBvcHRpb25zID0ge30gKSB7XG5cblx0XHRzdXBlciggd2lkdGgsIGhlaWdodCwgb3B0aW9ucyApO1xuXG5cdFx0dGhpcy5pc1dlYkdMQXJyYXlSZW5kZXJUYXJnZXQgPSB0cnVlO1xuXG5cdFx0dGhpcy5kZXB0aCA9IGRlcHRoO1xuXG5cdFx0dGhpcy50ZXh0dXJlID0gbmV3IERhdGFBcnJheVRleHR1cmUoIG51bGwsIHdpZHRoLCBoZWlnaHQsIGRlcHRoICk7XG5cblx0XHR0aGlzLnRleHR1cmUuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID0gdHJ1ZTtcblxuXHR9XG5cbn1cblxuY2xhc3MgRGF0YTNEVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xuXG5cdGNvbnN0cnVjdG9yKCBkYXRhID0gbnVsbCwgd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBkZXB0aCA9IDEgKSB7XG5cblx0XHQvLyBXZSdyZSBnb2luZyB0byBhZGQgLnNldFhYWCgpIG1ldGhvZHMgZm9yIHNldHRpbmcgcHJvcGVydGllcyBsYXRlci5cblx0XHQvLyBVc2VycyBjYW4gc3RpbGwgc2V0IGluIERhdGFUZXh0dXJlM0QgZGlyZWN0bHkuXG5cdFx0Ly9cblx0XHQvL1x0Y29uc3QgdGV4dHVyZSA9IG5ldyBUSFJFRS5EYXRhVGV4dHVyZTNEKCBkYXRhLCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCApO1xuXHRcdC8vIFx0dGV4dHVyZS5hbmlzb3Ryb3B5ID0gMTY7XG5cdFx0Ly9cblx0XHQvLyBTZWUgIzE0ODM5XG5cblx0XHRzdXBlciggbnVsbCApO1xuXG5cdFx0dGhpcy5pc0RhdGEzRFRleHR1cmUgPSB0cnVlO1xuXG5cdFx0dGhpcy5pbWFnZSA9IHsgZGF0YSwgd2lkdGgsIGhlaWdodCwgZGVwdGggfTtcblxuXHRcdHRoaXMubWFnRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcblx0XHR0aGlzLm1pbkZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XG5cblx0XHR0aGlzLndyYXBSID0gQ2xhbXBUb0VkZ2VXcmFwcGluZztcblxuXHRcdHRoaXMuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XG5cdFx0dGhpcy5mbGlwWSA9IGZhbHNlO1xuXHRcdHRoaXMudW5wYWNrQWxpZ25tZW50ID0gMTtcblxuXHR9XG5cbn1cblxuY2xhc3MgV2ViR0wzRFJlbmRlclRhcmdldCBleHRlbmRzIFdlYkdMUmVuZGVyVGFyZ2V0IHtcblxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBkZXB0aCA9IDEsIG9wdGlvbnMgPSB7fSApIHtcblxuXHRcdHN1cGVyKCB3aWR0aCwgaGVpZ2h0LCBvcHRpb25zICk7XG5cblx0XHR0aGlzLmlzV2ViR0wzRFJlbmRlclRhcmdldCA9IHRydWU7XG5cblx0XHR0aGlzLmRlcHRoID0gZGVwdGg7XG5cblx0XHR0aGlzLnRleHR1cmUgPSBuZXcgRGF0YTNEVGV4dHVyZSggbnVsbCwgd2lkdGgsIGhlaWdodCwgZGVwdGggKTtcblxuXHRcdHRoaXMudGV4dHVyZS5pc1JlbmRlclRhcmdldFRleHR1cmUgPSB0cnVlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBRdWF0ZXJuaW9uIHtcblxuXHRjb25zdHJ1Y3RvciggeCA9IDAsIHkgPSAwLCB6ID0gMCwgdyA9IDEgKSB7XG5cblx0XHR0aGlzLmlzUXVhdGVybmlvbiA9IHRydWU7XG5cblx0XHR0aGlzLl94ID0geDtcblx0XHR0aGlzLl95ID0geTtcblx0XHR0aGlzLl96ID0gejtcblx0XHR0aGlzLl93ID0gdztcblxuXHR9XG5cblx0c3RhdGljIHNsZXJwRmxhdCggZHN0LCBkc3RPZmZzZXQsIHNyYzAsIHNyY09mZnNldDAsIHNyYzEsIHNyY09mZnNldDEsIHQgKSB7XG5cblx0XHQvLyBmdXp6LWZyZWUsIGFycmF5LWJhc2VkIFF1YXRlcm5pb24gU0xFUlAgb3BlcmF0aW9uXG5cblx0XHRsZXQgeDAgPSBzcmMwWyBzcmNPZmZzZXQwICsgMCBdLFxuXHRcdFx0eTAgPSBzcmMwWyBzcmNPZmZzZXQwICsgMSBdLFxuXHRcdFx0ejAgPSBzcmMwWyBzcmNPZmZzZXQwICsgMiBdLFxuXHRcdFx0dzAgPSBzcmMwWyBzcmNPZmZzZXQwICsgMyBdO1xuXG5cdFx0Y29uc3QgeDEgPSBzcmMxWyBzcmNPZmZzZXQxICsgMCBdLFxuXHRcdFx0eTEgPSBzcmMxWyBzcmNPZmZzZXQxICsgMSBdLFxuXHRcdFx0ejEgPSBzcmMxWyBzcmNPZmZzZXQxICsgMiBdLFxuXHRcdFx0dzEgPSBzcmMxWyBzcmNPZmZzZXQxICsgMyBdO1xuXG5cdFx0aWYgKCB0ID09PSAwICkge1xuXG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDAgXSA9IHgwO1xuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAxIF0gPSB5MDtcblx0XHRcdGRzdFsgZHN0T2Zmc2V0ICsgMiBdID0gejA7XG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDMgXSA9IHcwO1xuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0ID09PSAxICkge1xuXG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDAgXSA9IHgxO1xuXHRcdFx0ZHN0WyBkc3RPZmZzZXQgKyAxIF0gPSB5MTtcblx0XHRcdGRzdFsgZHN0T2Zmc2V0ICsgMiBdID0gejE7XG5cdFx0XHRkc3RbIGRzdE9mZnNldCArIDMgXSA9IHcxO1xuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB3MCAhPT0gdzEgfHwgeDAgIT09IHgxIHx8IHkwICE9PSB5MSB8fCB6MCAhPT0gejEgKSB7XG5cblx0XHRcdGxldCBzID0gMSAtIHQ7XG5cdFx0XHRjb25zdCBjb3MgPSB4MCAqIHgxICsgeTAgKiB5MSArIHowICogejEgKyB3MCAqIHcxLFxuXHRcdFx0XHRkaXIgPSAoIGNvcyA+PSAwID8gMSA6IC0gMSApLFxuXHRcdFx0XHRzcXJTaW4gPSAxIC0gY29zICogY29zO1xuXG5cdFx0XHQvLyBTa2lwIHRoZSBTbGVycCBmb3IgdGlueSBzdGVwcyB0byBhdm9pZCBudW1lcmljIHByb2JsZW1zOlxuXHRcdFx0aWYgKCBzcXJTaW4gPiBOdW1iZXIuRVBTSUxPTiApIHtcblxuXHRcdFx0XHRjb25zdCBzaW4gPSBNYXRoLnNxcnQoIHNxclNpbiApLFxuXHRcdFx0XHRcdGxlbiA9IE1hdGguYXRhbjIoIHNpbiwgY29zICogZGlyICk7XG5cblx0XHRcdFx0cyA9IE1hdGguc2luKCBzICogbGVuICkgLyBzaW47XG5cdFx0XHRcdHQgPSBNYXRoLnNpbiggdCAqIGxlbiApIC8gc2luO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHREaXIgPSB0ICogZGlyO1xuXG5cdFx0XHR4MCA9IHgwICogcyArIHgxICogdERpcjtcblx0XHRcdHkwID0geTAgKiBzICsgeTEgKiB0RGlyO1xuXHRcdFx0ejAgPSB6MCAqIHMgKyB6MSAqIHREaXI7XG5cdFx0XHR3MCA9IHcwICogcyArIHcxICogdERpcjtcblxuXHRcdFx0Ly8gTm9ybWFsaXplIGluIGNhc2Ugd2UganVzdCBkaWQgYSBsZXJwOlxuXHRcdFx0aWYgKCBzID09PSAxIC0gdCApIHtcblxuXHRcdFx0XHRjb25zdCBmID0gMSAvIE1hdGguc3FydCggeDAgKiB4MCArIHkwICogeTAgKyB6MCAqIHowICsgdzAgKiB3MCApO1xuXG5cdFx0XHRcdHgwICo9IGY7XG5cdFx0XHRcdHkwICo9IGY7XG5cdFx0XHRcdHowICo9IGY7XG5cdFx0XHRcdHcwICo9IGY7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGRzdFsgZHN0T2Zmc2V0IF0gPSB4MDtcblx0XHRkc3RbIGRzdE9mZnNldCArIDEgXSA9IHkwO1xuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMiBdID0gejA7XG5cdFx0ZHN0WyBkc3RPZmZzZXQgKyAzIF0gPSB3MDtcblxuXHR9XG5cblx0c3RhdGljIG11bHRpcGx5UXVhdGVybmlvbnNGbGF0KCBkc3QsIGRzdE9mZnNldCwgc3JjMCwgc3JjT2Zmc2V0MCwgc3JjMSwgc3JjT2Zmc2V0MSApIHtcblxuXHRcdGNvbnN0IHgwID0gc3JjMFsgc3JjT2Zmc2V0MCBdO1xuXHRcdGNvbnN0IHkwID0gc3JjMFsgc3JjT2Zmc2V0MCArIDEgXTtcblx0XHRjb25zdCB6MCA9IHNyYzBbIHNyY09mZnNldDAgKyAyIF07XG5cdFx0Y29uc3QgdzAgPSBzcmMwWyBzcmNPZmZzZXQwICsgMyBdO1xuXG5cdFx0Y29uc3QgeDEgPSBzcmMxWyBzcmNPZmZzZXQxIF07XG5cdFx0Y29uc3QgeTEgPSBzcmMxWyBzcmNPZmZzZXQxICsgMSBdO1xuXHRcdGNvbnN0IHoxID0gc3JjMVsgc3JjT2Zmc2V0MSArIDIgXTtcblx0XHRjb25zdCB3MSA9IHNyYzFbIHNyY09mZnNldDEgKyAzIF07XG5cblx0XHRkc3RbIGRzdE9mZnNldCBdID0geDAgKiB3MSArIHcwICogeDEgKyB5MCAqIHoxIC0gejAgKiB5MTtcblx0XHRkc3RbIGRzdE9mZnNldCArIDEgXSA9IHkwICogdzEgKyB3MCAqIHkxICsgejAgKiB4MSAtIHgwICogejE7XG5cdFx0ZHN0WyBkc3RPZmZzZXQgKyAyIF0gPSB6MCAqIHcxICsgdzAgKiB6MSArIHgwICogeTEgLSB5MCAqIHgxO1xuXHRcdGRzdFsgZHN0T2Zmc2V0ICsgMyBdID0gdzAgKiB3MSAtIHgwICogeDEgLSB5MCAqIHkxIC0gejAgKiB6MTtcblxuXHRcdHJldHVybiBkc3Q7XG5cblx0fVxuXG5cdGdldCB4KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3g7XG5cblx0fVxuXG5cdHNldCB4KCB2YWx1ZSApIHtcblxuXHRcdHRoaXMuX3ggPSB2YWx1ZTtcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0fVxuXG5cdGdldCB5KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3k7XG5cblx0fVxuXG5cdHNldCB5KCB2YWx1ZSApIHtcblxuXHRcdHRoaXMuX3kgPSB2YWx1ZTtcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0fVxuXG5cdGdldCB6KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3o7XG5cblx0fVxuXG5cdHNldCB6KCB2YWx1ZSApIHtcblxuXHRcdHRoaXMuX3ogPSB2YWx1ZTtcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0fVxuXG5cdGdldCB3KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3c7XG5cblx0fVxuXG5cdHNldCB3KCB2YWx1ZSApIHtcblxuXHRcdHRoaXMuX3cgPSB2YWx1ZTtcblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0fVxuXG5cdHNldCggeCwgeSwgeiwgdyApIHtcblxuXHRcdHRoaXMuX3ggPSB4O1xuXHRcdHRoaXMuX3kgPSB5O1xuXHRcdHRoaXMuX3ogPSB6O1xuXHRcdHRoaXMuX3cgPSB3O1xuXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCB0aGlzLl94LCB0aGlzLl95LCB0aGlzLl96LCB0aGlzLl93ICk7XG5cblx0fVxuXG5cdGNvcHkoIHF1YXRlcm5pb24gKSB7XG5cblx0XHR0aGlzLl94ID0gcXVhdGVybmlvbi54O1xuXHRcdHRoaXMuX3kgPSBxdWF0ZXJuaW9uLnk7XG5cdFx0dGhpcy5feiA9IHF1YXRlcm5pb24uejtcblx0XHR0aGlzLl93ID0gcXVhdGVybmlvbi53O1xuXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21FdWxlciggZXVsZXIsIHVwZGF0ZSA9IHRydWUgKSB7XG5cblx0XHRjb25zdCB4ID0gZXVsZXIuX3gsIHkgPSBldWxlci5feSwgeiA9IGV1bGVyLl96LCBvcmRlciA9IGV1bGVyLl9vcmRlcjtcblxuXHRcdC8vIGh0dHA6Ly93d3cubWF0aHdvcmtzLmNvbS9tYXRsYWJjZW50cmFsL2ZpbGVleGNoYW5nZS9cblx0XHQvLyBcdDIwNjk2LWZ1bmN0aW9uLXRvLWNvbnZlcnQtYmV0d2Vlbi1kY20tZXVsZXItYW5nbGVzLXF1YXRlcm5pb25zLWFuZC1ldWxlci12ZWN0b3JzL1xuXHRcdC8vXHRjb250ZW50L1NwaW5DYWxjLm1cblxuXHRcdGNvbnN0IGNvcyA9IE1hdGguY29zO1xuXHRcdGNvbnN0IHNpbiA9IE1hdGguc2luO1xuXG5cdFx0Y29uc3QgYzEgPSBjb3MoIHggLyAyICk7XG5cdFx0Y29uc3QgYzIgPSBjb3MoIHkgLyAyICk7XG5cdFx0Y29uc3QgYzMgPSBjb3MoIHogLyAyICk7XG5cblx0XHRjb25zdCBzMSA9IHNpbiggeCAvIDIgKTtcblx0XHRjb25zdCBzMiA9IHNpbiggeSAvIDIgKTtcblx0XHRjb25zdCBzMyA9IHNpbiggeiAvIDIgKTtcblxuXHRcdHN3aXRjaCAoIG9yZGVyICkge1xuXG5cdFx0XHRjYXNlICdYWVonOlxuXHRcdFx0XHR0aGlzLl94ID0gczEgKiBjMiAqIGMzICsgYzEgKiBzMiAqIHMzO1xuXHRcdFx0XHR0aGlzLl95ID0gYzEgKiBzMiAqIGMzIC0gczEgKiBjMiAqIHMzO1xuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzICsgczEgKiBzMiAqIGMzO1xuXHRcdFx0XHR0aGlzLl93ID0gYzEgKiBjMiAqIGMzIC0gczEgKiBzMiAqIHMzO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnWVhaJzpcblx0XHRcdFx0dGhpcy5feCA9IHMxICogYzIgKiBjMyArIGMxICogczIgKiBzMztcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyAtIHMxICogYzIgKiBzMztcblx0XHRcdFx0dGhpcy5feiA9IGMxICogYzIgKiBzMyAtIHMxICogczIgKiBjMztcblx0XHRcdFx0dGhpcy5fdyA9IGMxICogYzIgKiBjMyArIHMxICogczIgKiBzMztcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1pYWSc6XG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgLSBjMSAqIHMyICogczM7XG5cdFx0XHRcdHRoaXMuX3kgPSBjMSAqIHMyICogYzMgKyBzMSAqIGMyICogczM7XG5cdFx0XHRcdHRoaXMuX3ogPSBjMSAqIGMyICogczMgKyBzMSAqIHMyICogYzM7XG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgLSBzMSAqIHMyICogczM7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdaWVgnOlxuXHRcdFx0XHR0aGlzLl94ID0gczEgKiBjMiAqIGMzIC0gYzEgKiBzMiAqIHMzO1xuXHRcdFx0XHR0aGlzLl95ID0gYzEgKiBzMiAqIGMzICsgczEgKiBjMiAqIHMzO1xuXHRcdFx0XHR0aGlzLl96ID0gYzEgKiBjMiAqIHMzIC0gczEgKiBzMiAqIGMzO1xuXHRcdFx0XHR0aGlzLl93ID0gYzEgKiBjMiAqIGMzICsgczEgKiBzMiAqIHMzO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnWVpYJzpcblx0XHRcdFx0dGhpcy5feCA9IHMxICogYzIgKiBjMyArIGMxICogczIgKiBzMztcblx0XHRcdFx0dGhpcy5feSA9IGMxICogczIgKiBjMyArIHMxICogYzIgKiBzMztcblx0XHRcdFx0dGhpcy5feiA9IGMxICogYzIgKiBzMyAtIHMxICogczIgKiBjMztcblx0XHRcdFx0dGhpcy5fdyA9IGMxICogYzIgKiBjMyAtIHMxICogczIgKiBzMztcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1haWSc6XG5cdFx0XHRcdHRoaXMuX3ggPSBzMSAqIGMyICogYzMgLSBjMSAqIHMyICogczM7XG5cdFx0XHRcdHRoaXMuX3kgPSBjMSAqIHMyICogYzMgLSBzMSAqIGMyICogczM7XG5cdFx0XHRcdHRoaXMuX3ogPSBjMSAqIGMyICogczMgKyBzMSAqIHMyICogYzM7XG5cdFx0XHRcdHRoaXMuX3cgPSBjMSAqIGMyICogYzMgKyBzMSAqIHMyICogczM7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5RdWF0ZXJuaW9uOiAuc2V0RnJvbUV1bGVyKCkgZW5jb3VudGVyZWQgYW4gdW5rbm93biBvcmRlcjogJyArIG9yZGVyICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHVwZGF0ZSA9PT0gdHJ1ZSApIHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tQXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApIHtcblxuXHRcdC8vIGh0dHA6Ly93d3cuZXVjbGlkZWFuc3BhY2UuY29tL21hdGhzL2dlb21ldHJ5L3JvdGF0aW9ucy9jb252ZXJzaW9ucy9hbmdsZVRvUXVhdGVybmlvbi9pbmRleC5odG1cblxuXHRcdC8vIGFzc3VtZXMgYXhpcyBpcyBub3JtYWxpemVkXG5cblx0XHRjb25zdCBoYWxmQW5nbGUgPSBhbmdsZSAvIDIsIHMgPSBNYXRoLnNpbiggaGFsZkFuZ2xlICk7XG5cblx0XHR0aGlzLl94ID0gYXhpcy54ICogcztcblx0XHR0aGlzLl95ID0gYXhpcy55ICogcztcblx0XHR0aGlzLl96ID0gYXhpcy56ICogcztcblx0XHR0aGlzLl93ID0gTWF0aC5jb3MoIGhhbGZBbmdsZSApO1xuXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21Sb3RhdGlvbk1hdHJpeCggbSApIHtcblxuXHRcdC8vIGh0dHA6Ly93d3cuZXVjbGlkZWFuc3BhY2UuY29tL21hdGhzL2dlb21ldHJ5L3JvdGF0aW9ucy9jb252ZXJzaW9ucy9tYXRyaXhUb1F1YXRlcm5pb24vaW5kZXguaHRtXG5cblx0XHQvLyBhc3N1bWVzIHRoZSB1cHBlciAzeDMgb2YgbSBpcyBhIHB1cmUgcm90YXRpb24gbWF0cml4IChpLmUsIHVuc2NhbGVkKVxuXG5cdFx0Y29uc3QgdGUgPSBtLmVsZW1lbnRzLFxuXG5cdFx0XHRtMTEgPSB0ZVsgMCBdLCBtMTIgPSB0ZVsgNCBdLCBtMTMgPSB0ZVsgOCBdLFxuXHRcdFx0bTIxID0gdGVbIDEgXSwgbTIyID0gdGVbIDUgXSwgbTIzID0gdGVbIDkgXSxcblx0XHRcdG0zMSA9IHRlWyAyIF0sIG0zMiA9IHRlWyA2IF0sIG0zMyA9IHRlWyAxMCBdLFxuXG5cdFx0XHR0cmFjZSA9IG0xMSArIG0yMiArIG0zMztcblxuXHRcdGlmICggdHJhY2UgPiAwICkge1xuXG5cdFx0XHRjb25zdCBzID0gMC41IC8gTWF0aC5zcXJ0KCB0cmFjZSArIDEuMCApO1xuXG5cdFx0XHR0aGlzLl93ID0gMC4yNSAvIHM7XG5cdFx0XHR0aGlzLl94ID0gKCBtMzIgLSBtMjMgKSAqIHM7XG5cdFx0XHR0aGlzLl95ID0gKCBtMTMgLSBtMzEgKSAqIHM7XG5cdFx0XHR0aGlzLl96ID0gKCBtMjEgLSBtMTIgKSAqIHM7XG5cblx0XHR9IGVsc2UgaWYgKCBtMTEgPiBtMjIgJiYgbTExID4gbTMzICkge1xuXG5cdFx0XHRjb25zdCBzID0gMi4wICogTWF0aC5zcXJ0KCAxLjAgKyBtMTEgLSBtMjIgLSBtMzMgKTtcblxuXHRcdFx0dGhpcy5fdyA9ICggbTMyIC0gbTIzICkgLyBzO1xuXHRcdFx0dGhpcy5feCA9IDAuMjUgKiBzO1xuXHRcdFx0dGhpcy5feSA9ICggbTEyICsgbTIxICkgLyBzO1xuXHRcdFx0dGhpcy5feiA9ICggbTEzICsgbTMxICkgLyBzO1xuXG5cdFx0fSBlbHNlIGlmICggbTIyID4gbTMzICkge1xuXG5cdFx0XHRjb25zdCBzID0gMi4wICogTWF0aC5zcXJ0KCAxLjAgKyBtMjIgLSBtMTEgLSBtMzMgKTtcblxuXHRcdFx0dGhpcy5fdyA9ICggbTEzIC0gbTMxICkgLyBzO1xuXHRcdFx0dGhpcy5feCA9ICggbTEyICsgbTIxICkgLyBzO1xuXHRcdFx0dGhpcy5feSA9IDAuMjUgKiBzO1xuXHRcdFx0dGhpcy5feiA9ICggbTIzICsgbTMyICkgLyBzO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc3QgcyA9IDIuMCAqIE1hdGguc3FydCggMS4wICsgbTMzIC0gbTExIC0gbTIyICk7XG5cblx0XHRcdHRoaXMuX3cgPSAoIG0yMSAtIG0xMiApIC8gcztcblx0XHRcdHRoaXMuX3ggPSAoIG0xMyArIG0zMSApIC8gcztcblx0XHRcdHRoaXMuX3kgPSAoIG0yMyArIG0zMiApIC8gcztcblx0XHRcdHRoaXMuX3ogPSAwLjI1ICogcztcblxuXHRcdH1cblxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tVW5pdFZlY3RvcnMoIHZGcm9tLCB2VG8gKSB7XG5cblx0XHQvLyBhc3N1bWVzIGRpcmVjdGlvbiB2ZWN0b3JzIHZGcm9tIGFuZCB2VG8gYXJlIG5vcm1hbGl6ZWRcblxuXHRcdGxldCByID0gdkZyb20uZG90KCB2VG8gKSArIDE7XG5cblx0XHRpZiAoIHIgPCBOdW1iZXIuRVBTSUxPTiApIHtcblxuXHRcdFx0Ly8gdkZyb20gYW5kIHZUbyBwb2ludCBpbiBvcHBvc2l0ZSBkaXJlY3Rpb25zXG5cblx0XHRcdHIgPSAwO1xuXG5cdFx0XHRpZiAoIE1hdGguYWJzKCB2RnJvbS54ICkgPiBNYXRoLmFicyggdkZyb20ueiApICkge1xuXG5cdFx0XHRcdHRoaXMuX3ggPSAtIHZGcm9tLnk7XG5cdFx0XHRcdHRoaXMuX3kgPSB2RnJvbS54O1xuXHRcdFx0XHR0aGlzLl96ID0gMDtcblx0XHRcdFx0dGhpcy5fdyA9IHI7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0dGhpcy5feCA9IDA7XG5cdFx0XHRcdHRoaXMuX3kgPSAtIHZGcm9tLno7XG5cdFx0XHRcdHRoaXMuX3ogPSB2RnJvbS55O1xuXHRcdFx0XHR0aGlzLl93ID0gcjtcblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gY3Jvc3NWZWN0b3JzKCB2RnJvbSwgdlRvICk7IC8vIGlubGluZWQgdG8gYXZvaWQgY3ljbGljIGRlcGVuZGVuY3kgb24gVmVjdG9yM1xuXG5cdFx0XHR0aGlzLl94ID0gdkZyb20ueSAqIHZUby56IC0gdkZyb20ueiAqIHZUby55O1xuXHRcdFx0dGhpcy5feSA9IHZGcm9tLnogKiB2VG8ueCAtIHZGcm9tLnggKiB2VG8uejtcblx0XHRcdHRoaXMuX3ogPSB2RnJvbS54ICogdlRvLnkgLSB2RnJvbS55ICogdlRvLng7XG5cdFx0XHR0aGlzLl93ID0gcjtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLm5vcm1hbGl6ZSgpO1xuXG5cdH1cblxuXHRhbmdsZVRvKCBxICkge1xuXG5cdFx0cmV0dXJuIDIgKiBNYXRoLmFjb3MoIE1hdGguYWJzKCBjbGFtcCggdGhpcy5kb3QoIHEgKSwgLSAxLCAxICkgKSApO1xuXG5cdH1cblxuXHRyb3RhdGVUb3dhcmRzKCBxLCBzdGVwICkge1xuXG5cdFx0Y29uc3QgYW5nbGUgPSB0aGlzLmFuZ2xlVG8oIHEgKTtcblxuXHRcdGlmICggYW5nbGUgPT09IDAgKSByZXR1cm4gdGhpcztcblxuXHRcdGNvbnN0IHQgPSBNYXRoLm1pbiggMSwgc3RlcCAvIGFuZ2xlICk7XG5cblx0XHR0aGlzLnNsZXJwKCBxLCB0ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0aWRlbnRpdHkoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5zZXQoIDAsIDAsIDAsIDEgKTtcblxuXHR9XG5cblx0aW52ZXJ0KCkge1xuXG5cdFx0Ly8gcXVhdGVybmlvbiBpcyBhc3N1bWVkIHRvIGhhdmUgdW5pdCBsZW5ndGhcblxuXHRcdHJldHVybiB0aGlzLmNvbmp1Z2F0ZSgpO1xuXG5cdH1cblxuXHRjb25qdWdhdGUoKSB7XG5cblx0XHR0aGlzLl94ICo9IC0gMTtcblx0XHR0aGlzLl95ICo9IC0gMTtcblx0XHR0aGlzLl96ICo9IC0gMTtcblxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkb3QoIHYgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5feCAqIHYuX3ggKyB0aGlzLl95ICogdi5feSArIHRoaXMuX3ogKiB2Ll96ICsgdGhpcy5fdyAqIHYuX3c7XG5cblx0fVxuXG5cdGxlbmd0aFNxKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3ggKiB0aGlzLl94ICsgdGhpcy5feSAqIHRoaXMuX3kgKyB0aGlzLl96ICogdGhpcy5feiArIHRoaXMuX3cgKiB0aGlzLl93O1xuXG5cdH1cblxuXHRsZW5ndGgoKSB7XG5cblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCB0aGlzLl94ICogdGhpcy5feCArIHRoaXMuX3kgKiB0aGlzLl95ICsgdGhpcy5feiAqIHRoaXMuX3ogKyB0aGlzLl93ICogdGhpcy5fdyApO1xuXG5cdH1cblxuXHRub3JtYWxpemUoKSB7XG5cblx0XHRsZXQgbCA9IHRoaXMubGVuZ3RoKCk7XG5cblx0XHRpZiAoIGwgPT09IDAgKSB7XG5cblx0XHRcdHRoaXMuX3ggPSAwO1xuXHRcdFx0dGhpcy5feSA9IDA7XG5cdFx0XHR0aGlzLl96ID0gMDtcblx0XHRcdHRoaXMuX3cgPSAxO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0bCA9IDEgLyBsO1xuXG5cdFx0XHR0aGlzLl94ID0gdGhpcy5feCAqIGw7XG5cdFx0XHR0aGlzLl95ID0gdGhpcy5feSAqIGw7XG5cdFx0XHR0aGlzLl96ID0gdGhpcy5feiAqIGw7XG5cdFx0XHR0aGlzLl93ID0gdGhpcy5fdyAqIGw7XG5cblx0XHR9XG5cblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bXVsdGlwbHkoIHEgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseVF1YXRlcm5pb25zKCB0aGlzLCBxICk7XG5cblx0fVxuXG5cdHByZW11bHRpcGx5KCBxICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubXVsdGlwbHlRdWF0ZXJuaW9ucyggcSwgdGhpcyApO1xuXG5cdH1cblxuXHRtdWx0aXBseVF1YXRlcm5pb25zKCBhLCBiICkge1xuXG5cdFx0Ly8gZnJvbSBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9hbGdlYnJhL3JlYWxOb3JtZWRBbGdlYnJhL3F1YXRlcm5pb25zL2NvZGUvaW5kZXguaHRtXG5cblx0XHRjb25zdCBxYXggPSBhLl94LCBxYXkgPSBhLl95LCBxYXogPSBhLl96LCBxYXcgPSBhLl93O1xuXHRcdGNvbnN0IHFieCA9IGIuX3gsIHFieSA9IGIuX3ksIHFieiA9IGIuX3osIHFidyA9IGIuX3c7XG5cblx0XHR0aGlzLl94ID0gcWF4ICogcWJ3ICsgcWF3ICogcWJ4ICsgcWF5ICogcWJ6IC0gcWF6ICogcWJ5O1xuXHRcdHRoaXMuX3kgPSBxYXkgKiBxYncgKyBxYXcgKiBxYnkgKyBxYXogKiBxYnggLSBxYXggKiBxYno7XG5cdFx0dGhpcy5feiA9IHFheiAqIHFidyArIHFhdyAqIHFieiArIHFheCAqIHFieSAtIHFheSAqIHFieDtcblx0XHR0aGlzLl93ID0gcWF3ICogcWJ3IC0gcWF4ICogcWJ4IC0gcWF5ICogcWJ5IC0gcWF6ICogcWJ6O1xuXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNsZXJwKCBxYiwgdCApIHtcblxuXHRcdGlmICggdCA9PT0gMCApIHJldHVybiB0aGlzO1xuXHRcdGlmICggdCA9PT0gMSApIHJldHVybiB0aGlzLmNvcHkoIHFiICk7XG5cblx0XHRjb25zdCB4ID0gdGhpcy5feCwgeSA9IHRoaXMuX3ksIHogPSB0aGlzLl96LCB3ID0gdGhpcy5fdztcblxuXHRcdC8vIGh0dHA6Ly93d3cuZXVjbGlkZWFuc3BhY2UuY29tL21hdGhzL2FsZ2VicmEvcmVhbE5vcm1lZEFsZ2VicmEvcXVhdGVybmlvbnMvc2xlcnAvXG5cblx0XHRsZXQgY29zSGFsZlRoZXRhID0gdyAqIHFiLl93ICsgeCAqIHFiLl94ICsgeSAqIHFiLl95ICsgeiAqIHFiLl96O1xuXG5cdFx0aWYgKCBjb3NIYWxmVGhldGEgPCAwICkge1xuXG5cdFx0XHR0aGlzLl93ID0gLSBxYi5fdztcblx0XHRcdHRoaXMuX3ggPSAtIHFiLl94O1xuXHRcdFx0dGhpcy5feSA9IC0gcWIuX3k7XG5cdFx0XHR0aGlzLl96ID0gLSBxYi5fejtcblxuXHRcdFx0Y29zSGFsZlRoZXRhID0gLSBjb3NIYWxmVGhldGE7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLmNvcHkoIHFiICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIGNvc0hhbGZUaGV0YSA+PSAxLjAgKSB7XG5cblx0XHRcdHRoaXMuX3cgPSB3O1xuXHRcdFx0dGhpcy5feCA9IHg7XG5cdFx0XHR0aGlzLl95ID0geTtcblx0XHRcdHRoaXMuX3ogPSB6O1xuXG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH1cblxuXHRcdGNvbnN0IHNxclNpbkhhbGZUaGV0YSA9IDEuMCAtIGNvc0hhbGZUaGV0YSAqIGNvc0hhbGZUaGV0YTtcblxuXHRcdGlmICggc3FyU2luSGFsZlRoZXRhIDw9IE51bWJlci5FUFNJTE9OICkge1xuXG5cdFx0XHRjb25zdCBzID0gMSAtIHQ7XG5cdFx0XHR0aGlzLl93ID0gcyAqIHcgKyB0ICogdGhpcy5fdztcblx0XHRcdHRoaXMuX3ggPSBzICogeCArIHQgKiB0aGlzLl94O1xuXHRcdFx0dGhpcy5feSA9IHMgKiB5ICsgdCAqIHRoaXMuX3k7XG5cdFx0XHR0aGlzLl96ID0gcyAqIHogKyB0ICogdGhpcy5fejtcblxuXHRcdFx0dGhpcy5ub3JtYWxpemUoKTsgLy8gbm9ybWFsaXplIGNhbGxzIF9vbkNoYW5nZUNhbGxiYWNrKClcblxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHR9XG5cblx0XHRjb25zdCBzaW5IYWxmVGhldGEgPSBNYXRoLnNxcnQoIHNxclNpbkhhbGZUaGV0YSApO1xuXHRcdGNvbnN0IGhhbGZUaGV0YSA9IE1hdGguYXRhbjIoIHNpbkhhbGZUaGV0YSwgY29zSGFsZlRoZXRhICk7XG5cdFx0Y29uc3QgcmF0aW9BID0gTWF0aC5zaW4oICggMSAtIHQgKSAqIGhhbGZUaGV0YSApIC8gc2luSGFsZlRoZXRhLFxuXHRcdFx0cmF0aW9CID0gTWF0aC5zaW4oIHQgKiBoYWxmVGhldGEgKSAvIHNpbkhhbGZUaGV0YTtcblxuXHRcdHRoaXMuX3cgPSAoIHcgKiByYXRpb0EgKyB0aGlzLl93ICogcmF0aW9CICk7XG5cdFx0dGhpcy5feCA9ICggeCAqIHJhdGlvQSArIHRoaXMuX3ggKiByYXRpb0IgKTtcblx0XHR0aGlzLl95ID0gKCB5ICogcmF0aW9BICsgdGhpcy5feSAqIHJhdGlvQiApO1xuXHRcdHRoaXMuX3ogPSAoIHogKiByYXRpb0EgKyB0aGlzLl96ICogcmF0aW9CICk7XG5cblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2xlcnBRdWF0ZXJuaW9ucyggcWEsIHFiLCB0ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuY29weSggcWEgKS5zbGVycCggcWIsIHQgKTtcblxuXHR9XG5cblx0cmFuZG9tKCkge1xuXG5cdFx0Ly8gc2V0cyB0aGlzIHF1YXRlcm5pb24gdG8gYSB1bmlmb3JtIHJhbmRvbSB1bml0IHF1YXRlcm5uaW9uXG5cblx0XHQvLyBLZW4gU2hvZW1ha2Vcblx0XHQvLyBVbmlmb3JtIHJhbmRvbSByb3RhdGlvbnNcblx0XHQvLyBELiBLaXJrLCBlZGl0b3IsIEdyYXBoaWNzIEdlbXMgSUlJLCBwYWdlcyAxMjQtMTMyLiBBY2FkZW1pYyBQcmVzcywgTmV3IFlvcmssIDE5OTIuXG5cblx0XHRjb25zdCB0aGV0YTEgPSAyICogTWF0aC5QSSAqIE1hdGgucmFuZG9tKCk7XG5cdFx0Y29uc3QgdGhldGEyID0gMiAqIE1hdGguUEkgKiBNYXRoLnJhbmRvbSgpO1xuXG5cdFx0Y29uc3QgeDAgPSBNYXRoLnJhbmRvbSgpO1xuXHRcdGNvbnN0IHIxID0gTWF0aC5zcXJ0KCAxIC0geDAgKTtcblx0XHRjb25zdCByMiA9IE1hdGguc3FydCggeDAgKTtcblxuXHRcdHJldHVybiB0aGlzLnNldChcblx0XHRcdHIxICogTWF0aC5zaW4oIHRoZXRhMSApLFxuXHRcdFx0cjEgKiBNYXRoLmNvcyggdGhldGExICksXG5cdFx0XHRyMiAqIE1hdGguc2luKCB0aGV0YTIgKSxcblx0XHRcdHIyICogTWF0aC5jb3MoIHRoZXRhMiApLFxuXHRcdCk7XG5cblx0fVxuXG5cdGVxdWFscyggcXVhdGVybmlvbiApIHtcblxuXHRcdHJldHVybiAoIHF1YXRlcm5pb24uX3ggPT09IHRoaXMuX3ggKSAmJiAoIHF1YXRlcm5pb24uX3kgPT09IHRoaXMuX3kgKSAmJiAoIHF1YXRlcm5pb24uX3ogPT09IHRoaXMuX3ogKSAmJiAoIHF1YXRlcm5pb24uX3cgPT09IHRoaXMuX3cgKTtcblxuXHR9XG5cblx0ZnJvbUFycmF5KCBhcnJheSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdHRoaXMuX3ggPSBhcnJheVsgb2Zmc2V0IF07XG5cdFx0dGhpcy5feSA9IGFycmF5WyBvZmZzZXQgKyAxIF07XG5cdFx0dGhpcy5feiA9IGFycmF5WyBvZmZzZXQgKyAyIF07XG5cdFx0dGhpcy5fdyA9IGFycmF5WyBvZmZzZXQgKyAzIF07XG5cblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdGFycmF5WyBvZmZzZXQgXSA9IHRoaXMuX3g7XG5cdFx0YXJyYXlbIG9mZnNldCArIDEgXSA9IHRoaXMuX3k7XG5cdFx0YXJyYXlbIG9mZnNldCArIDIgXSA9IHRoaXMuX3o7XG5cdFx0YXJyYXlbIG9mZnNldCArIDMgXSA9IHRoaXMuX3c7XG5cblx0XHRyZXR1cm4gYXJyYXk7XG5cblx0fVxuXG5cdGZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kZXggKSB7XG5cblx0XHR0aGlzLl94ID0gYXR0cmlidXRlLmdldFgoIGluZGV4ICk7XG5cdFx0dGhpcy5feSA9IGF0dHJpYnV0ZS5nZXRZKCBpbmRleCApO1xuXHRcdHRoaXMuX3ogPSBhdHRyaWJ1dGUuZ2V0WiggaW5kZXggKTtcblx0XHR0aGlzLl93ID0gYXR0cmlidXRlLmdldFcoIGluZGV4ICk7XG5cblx0XHR0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMudG9BcnJheSgpO1xuXG5cdH1cblxuXHRfb25DaGFuZ2UoIGNhbGxiYWNrICkge1xuXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjayA9IGNhbGxiYWNrO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdF9vbkNoYW5nZUNhbGxiYWNrKCkge31cblxuXHQqWyBTeW1ib2wuaXRlcmF0b3IgXSgpIHtcblxuXHRcdHlpZWxkIHRoaXMuX3g7XG5cdFx0eWllbGQgdGhpcy5feTtcblx0XHR5aWVsZCB0aGlzLl96O1xuXHRcdHlpZWxkIHRoaXMuX3c7XG5cblx0fVxuXG59XG5cbmNsYXNzIFZlY3RvcjMge1xuXG5cdGNvbnN0cnVjdG9yKCB4ID0gMCwgeSA9IDAsIHogPSAwICkge1xuXG5cdFx0VmVjdG9yMy5wcm90b3R5cGUuaXNWZWN0b3IzID0gdHJ1ZTtcblxuXHRcdHRoaXMueCA9IHg7XG5cdFx0dGhpcy55ID0geTtcblx0XHR0aGlzLnogPSB6O1xuXG5cdH1cblxuXHRzZXQoIHgsIHksIHogKSB7XG5cblx0XHRpZiAoIHogPT09IHVuZGVmaW5lZCApIHogPSB0aGlzLno7IC8vIHNwcml0ZS5zY2FsZS5zZXQoeCx5KVxuXG5cdFx0dGhpcy54ID0geDtcblx0XHR0aGlzLnkgPSB5O1xuXHRcdHRoaXMueiA9IHo7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0U2NhbGFyKCBzY2FsYXIgKSB7XG5cblx0XHR0aGlzLnggPSBzY2FsYXI7XG5cdFx0dGhpcy55ID0gc2NhbGFyO1xuXHRcdHRoaXMueiA9IHNjYWxhcjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRYKCB4ICkge1xuXG5cdFx0dGhpcy54ID0geDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRZKCB5ICkge1xuXG5cdFx0dGhpcy55ID0geTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRaKCB6ICkge1xuXG5cdFx0dGhpcy56ID0gejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRDb21wb25lbnQoIGluZGV4LCB2YWx1ZSApIHtcblxuXHRcdHN3aXRjaCAoIGluZGV4ICkge1xuXG5cdFx0XHRjYXNlIDA6IHRoaXMueCA9IHZhbHVlOyBicmVhaztcblx0XHRcdGNhc2UgMTogdGhpcy55ID0gdmFsdWU7IGJyZWFrO1xuXHRcdFx0Y2FzZSAyOiB0aGlzLnogPSB2YWx1ZTsgYnJlYWs7XG5cdFx0XHRkZWZhdWx0OiB0aHJvdyBuZXcgRXJyb3IoICdpbmRleCBpcyBvdXQgb2YgcmFuZ2U6ICcgKyBpbmRleCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldENvbXBvbmVudCggaW5kZXggKSB7XG5cblx0XHRzd2l0Y2ggKCBpbmRleCApIHtcblxuXHRcdFx0Y2FzZSAwOiByZXR1cm4gdGhpcy54O1xuXHRcdFx0Y2FzZSAxOiByZXR1cm4gdGhpcy55O1xuXHRcdFx0Y2FzZSAyOiByZXR1cm4gdGhpcy56O1xuXHRcdFx0ZGVmYXVsdDogdGhyb3cgbmV3IEVycm9yKCAnaW5kZXggaXMgb3V0IG9mIHJhbmdlOiAnICsgaW5kZXggKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMueCwgdGhpcy55LCB0aGlzLnogKTtcblxuXHR9XG5cblx0Y29weSggdiApIHtcblxuXHRcdHRoaXMueCA9IHYueDtcblx0XHR0aGlzLnkgPSB2Lnk7XG5cdFx0dGhpcy56ID0gdi56O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFkZCggdiApIHtcblxuXHRcdHRoaXMueCArPSB2Lng7XG5cdFx0dGhpcy55ICs9IHYueTtcblx0XHR0aGlzLnogKz0gdi56O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFkZFNjYWxhciggcyApIHtcblxuXHRcdHRoaXMueCArPSBzO1xuXHRcdHRoaXMueSArPSBzO1xuXHRcdHRoaXMueiArPSBzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFkZFZlY3RvcnMoIGEsIGIgKSB7XG5cblx0XHR0aGlzLnggPSBhLnggKyBiLng7XG5cdFx0dGhpcy55ID0gYS55ICsgYi55O1xuXHRcdHRoaXMueiA9IGEueiArIGIuejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhZGRTY2FsZWRWZWN0b3IoIHYsIHMgKSB7XG5cblx0XHR0aGlzLnggKz0gdi54ICogcztcblx0XHR0aGlzLnkgKz0gdi55ICogcztcblx0XHR0aGlzLnogKz0gdi56ICogcztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdWIoIHYgKSB7XG5cblx0XHR0aGlzLnggLT0gdi54O1xuXHRcdHRoaXMueSAtPSB2Lnk7XG5cdFx0dGhpcy56IC09IHYuejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdWJTY2FsYXIoIHMgKSB7XG5cblx0XHR0aGlzLnggLT0gcztcblx0XHR0aGlzLnkgLT0gcztcblx0XHR0aGlzLnogLT0gcztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdWJWZWN0b3JzKCBhLCBiICkge1xuXG5cdFx0dGhpcy54ID0gYS54IC0gYi54O1xuXHRcdHRoaXMueSA9IGEueSAtIGIueTtcblx0XHR0aGlzLnogPSBhLnogLSBiLno7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bXVsdGlwbHkoIHYgKSB7XG5cblx0XHR0aGlzLnggKj0gdi54O1xuXHRcdHRoaXMueSAqPSB2Lnk7XG5cdFx0dGhpcy56ICo9IHYuejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtdWx0aXBseVNjYWxhciggc2NhbGFyICkge1xuXG5cdFx0dGhpcy54ICo9IHNjYWxhcjtcblx0XHR0aGlzLnkgKj0gc2NhbGFyO1xuXHRcdHRoaXMueiAqPSBzY2FsYXI7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bXVsdGlwbHlWZWN0b3JzKCBhLCBiICkge1xuXG5cdFx0dGhpcy54ID0gYS54ICogYi54O1xuXHRcdHRoaXMueSA9IGEueSAqIGIueTtcblx0XHR0aGlzLnogPSBhLnogKiBiLno7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXBwbHlFdWxlciggZXVsZXIgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5hcHBseVF1YXRlcm5pb24oIF9xdWF0ZXJuaW9uJDQuc2V0RnJvbUV1bGVyKCBldWxlciApICk7XG5cblx0fVxuXG5cdGFwcGx5QXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApIHtcblxuXHRcdHJldHVybiB0aGlzLmFwcGx5UXVhdGVybmlvbiggX3F1YXRlcm5pb24kNC5zZXRGcm9tQXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApICk7XG5cblx0fVxuXG5cdGFwcGx5TWF0cml4MyggbSApIHtcblxuXHRcdGNvbnN0IHggPSB0aGlzLngsIHkgPSB0aGlzLnksIHogPSB0aGlzLno7XG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XG5cblx0XHR0aGlzLnggPSBlWyAwIF0gKiB4ICsgZVsgMyBdICogeSArIGVbIDYgXSAqIHo7XG5cdFx0dGhpcy55ID0gZVsgMSBdICogeCArIGVbIDQgXSAqIHkgKyBlWyA3IF0gKiB6O1xuXHRcdHRoaXMueiA9IGVbIDIgXSAqIHggKyBlWyA1IF0gKiB5ICsgZVsgOCBdICogejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhcHBseU5vcm1hbE1hdHJpeCggbSApIHtcblxuXHRcdHJldHVybiB0aGlzLmFwcGx5TWF0cml4MyggbSApLm5vcm1hbGl6ZSgpO1xuXG5cdH1cblxuXHRhcHBseU1hdHJpeDQoIG0gKSB7XG5cblx0XHRjb25zdCB4ID0gdGhpcy54LCB5ID0gdGhpcy55LCB6ID0gdGhpcy56O1xuXHRcdGNvbnN0IGUgPSBtLmVsZW1lbnRzO1xuXG5cdFx0Y29uc3QgdyA9IDEgLyAoIGVbIDMgXSAqIHggKyBlWyA3IF0gKiB5ICsgZVsgMTEgXSAqIHogKyBlWyAxNSBdICk7XG5cblx0XHR0aGlzLnggPSAoIGVbIDAgXSAqIHggKyBlWyA0IF0gKiB5ICsgZVsgOCBdICogeiArIGVbIDEyIF0gKSAqIHc7XG5cdFx0dGhpcy55ID0gKCBlWyAxIF0gKiB4ICsgZVsgNSBdICogeSArIGVbIDkgXSAqIHogKyBlWyAxMyBdICkgKiB3O1xuXHRcdHRoaXMueiA9ICggZVsgMiBdICogeCArIGVbIDYgXSAqIHkgKyBlWyAxMCBdICogeiArIGVbIDE0IF0gKSAqIHc7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXBwbHlRdWF0ZXJuaW9uKCBxICkge1xuXG5cdFx0Ly8gcXVhdGVybmlvbiBxIGlzIGFzc3VtZWQgdG8gaGF2ZSB1bml0IGxlbmd0aFxuXG5cdFx0Y29uc3QgdnggPSB0aGlzLngsIHZ5ID0gdGhpcy55LCB2eiA9IHRoaXMuejtcblx0XHRjb25zdCBxeCA9IHEueCwgcXkgPSBxLnksIHF6ID0gcS56LCBxdyA9IHEudztcblxuXHRcdC8vIHQgPSAyICogY3Jvc3MoIHEueHl6LCB2ICk7XG5cdFx0Y29uc3QgdHggPSAyICogKCBxeSAqIHZ6IC0gcXogKiB2eSApO1xuXHRcdGNvbnN0IHR5ID0gMiAqICggcXogKiB2eCAtIHF4ICogdnogKTtcblx0XHRjb25zdCB0eiA9IDIgKiAoIHF4ICogdnkgLSBxeSAqIHZ4ICk7XG5cblx0XHQvLyB2ICsgcS53ICogdCArIGNyb3NzKCBxLnh5eiwgdCApO1xuXHRcdHRoaXMueCA9IHZ4ICsgcXcgKiB0eCArIHF5ICogdHogLSBxeiAqIHR5O1xuXHRcdHRoaXMueSA9IHZ5ICsgcXcgKiB0eSArIHF6ICogdHggLSBxeCAqIHR6O1xuXHRcdHRoaXMueiA9IHZ6ICsgcXcgKiB0eiArIHF4ICogdHkgLSBxeSAqIHR4O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHByb2plY3QoIGNhbWVyYSApIHtcblxuXHRcdHJldHVybiB0aGlzLmFwcGx5TWF0cml4NCggY2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSApLmFwcGx5TWF0cml4NCggY2FtZXJhLnByb2plY3Rpb25NYXRyaXggKTtcblxuXHR9XG5cblx0dW5wcm9qZWN0KCBjYW1lcmEgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5hcHBseU1hdHJpeDQoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZSApLmFwcGx5TWF0cml4NCggY2FtZXJhLm1hdHJpeFdvcmxkICk7XG5cblx0fVxuXG5cdHRyYW5zZm9ybURpcmVjdGlvbiggbSApIHtcblxuXHRcdC8vIGlucHV0OiBUSFJFRS5NYXRyaXg0IGFmZmluZSBtYXRyaXhcblx0XHQvLyB2ZWN0b3IgaW50ZXJwcmV0ZWQgYXMgYSBkaXJlY3Rpb25cblxuXHRcdGNvbnN0IHggPSB0aGlzLngsIHkgPSB0aGlzLnksIHogPSB0aGlzLno7XG5cdFx0Y29uc3QgZSA9IG0uZWxlbWVudHM7XG5cblx0XHR0aGlzLnggPSBlWyAwIF0gKiB4ICsgZVsgNCBdICogeSArIGVbIDggXSAqIHo7XG5cdFx0dGhpcy55ID0gZVsgMSBdICogeCArIGVbIDUgXSAqIHkgKyBlWyA5IF0gKiB6O1xuXHRcdHRoaXMueiA9IGVbIDIgXSAqIHggKyBlWyA2IF0gKiB5ICsgZVsgMTAgXSAqIHo7XG5cblx0XHRyZXR1cm4gdGhpcy5ub3JtYWxpemUoKTtcblxuXHR9XG5cblx0ZGl2aWRlKCB2ICkge1xuXG5cdFx0dGhpcy54IC89IHYueDtcblx0XHR0aGlzLnkgLz0gdi55O1xuXHRcdHRoaXMueiAvPSB2Lno7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGl2aWRlU2NhbGFyKCBzY2FsYXIgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5tdWx0aXBseVNjYWxhciggMSAvIHNjYWxhciApO1xuXG5cdH1cblxuXHRtaW4oIHYgKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLm1pbiggdGhpcy54LCB2LnggKTtcblx0XHR0aGlzLnkgPSBNYXRoLm1pbiggdGhpcy55LCB2LnkgKTtcblx0XHR0aGlzLnogPSBNYXRoLm1pbiggdGhpcy56LCB2LnogKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYXgoIHYgKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLm1heCggdGhpcy54LCB2LnggKTtcblx0XHR0aGlzLnkgPSBNYXRoLm1heCggdGhpcy55LCB2LnkgKTtcblx0XHR0aGlzLnogPSBNYXRoLm1heCggdGhpcy56LCB2LnogKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbGFtcCggbWluLCBtYXggKSB7XG5cblx0XHQvLyBhc3N1bWVzIG1pbiA8IG1heCwgY29tcG9uZW50d2lzZVxuXG5cdFx0dGhpcy54ID0gTWF0aC5tYXgoIG1pbi54LCBNYXRoLm1pbiggbWF4LngsIHRoaXMueCApICk7XG5cdFx0dGhpcy55ID0gTWF0aC5tYXgoIG1pbi55LCBNYXRoLm1pbiggbWF4LnksIHRoaXMueSApICk7XG5cdFx0dGhpcy56ID0gTWF0aC5tYXgoIG1pbi56LCBNYXRoLm1pbiggbWF4LnosIHRoaXMueiApICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xhbXBTY2FsYXIoIG1pblZhbCwgbWF4VmFsICkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC5tYXgoIG1pblZhbCwgTWF0aC5taW4oIG1heFZhbCwgdGhpcy54ICkgKTtcblx0XHR0aGlzLnkgPSBNYXRoLm1heCggbWluVmFsLCBNYXRoLm1pbiggbWF4VmFsLCB0aGlzLnkgKSApO1xuXHRcdHRoaXMueiA9IE1hdGgubWF4KCBtaW5WYWwsIE1hdGgubWluKCBtYXhWYWwsIHRoaXMueiApICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xhbXBMZW5ndGgoIG1pbiwgbWF4ICkge1xuXG5cdFx0Y29uc3QgbGVuZ3RoID0gdGhpcy5sZW5ndGgoKTtcblxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggbGVuZ3RoIHx8IDEgKS5tdWx0aXBseVNjYWxhciggTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgbGVuZ3RoICkgKSApO1xuXG5cdH1cblxuXHRmbG9vcigpIHtcblxuXHRcdHRoaXMueCA9IE1hdGguZmxvb3IoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGguZmxvb3IoIHRoaXMueSApO1xuXHRcdHRoaXMueiA9IE1hdGguZmxvb3IoIHRoaXMueiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNlaWwoKSB7XG5cblx0XHR0aGlzLnggPSBNYXRoLmNlaWwoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGguY2VpbCggdGhpcy55ICk7XG5cdFx0dGhpcy56ID0gTWF0aC5jZWlsKCB0aGlzLnogKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyb3VuZCgpIHtcblxuXHRcdHRoaXMueCA9IE1hdGgucm91bmQoIHRoaXMueCApO1xuXHRcdHRoaXMueSA9IE1hdGgucm91bmQoIHRoaXMueSApO1xuXHRcdHRoaXMueiA9IE1hdGgucm91bmQoIHRoaXMueiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJvdW5kVG9aZXJvKCkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC50cnVuYyggdGhpcy54ICk7XG5cdFx0dGhpcy55ID0gTWF0aC50cnVuYyggdGhpcy55ICk7XG5cdFx0dGhpcy56ID0gTWF0aC50cnVuYyggdGhpcy56ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bmVnYXRlKCkge1xuXG5cdFx0dGhpcy54ID0gLSB0aGlzLng7XG5cdFx0dGhpcy55ID0gLSB0aGlzLnk7XG5cdFx0dGhpcy56ID0gLSB0aGlzLno7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZG90KCB2ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMueCAqIHYueCArIHRoaXMueSAqIHYueSArIHRoaXMueiAqIHYuejtcblxuXHR9XG5cblx0Ly8gVE9ETyBsZW5ndGhTcXVhcmVkP1xuXG5cdGxlbmd0aFNxKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMueCAqIHRoaXMueCArIHRoaXMueSAqIHRoaXMueSArIHRoaXMueiAqIHRoaXMuejtcblxuXHR9XG5cblx0bGVuZ3RoKCkge1xuXG5cdFx0cmV0dXJuIE1hdGguc3FydCggdGhpcy54ICogdGhpcy54ICsgdGhpcy55ICogdGhpcy55ICsgdGhpcy56ICogdGhpcy56ICk7XG5cblx0fVxuXG5cdG1hbmhhdHRhbkxlbmd0aCgpIHtcblxuXHRcdHJldHVybiBNYXRoLmFicyggdGhpcy54ICkgKyBNYXRoLmFicyggdGhpcy55ICkgKyBNYXRoLmFicyggdGhpcy56ICk7XG5cblx0fVxuXG5cdG5vcm1hbGl6ZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLmRpdmlkZVNjYWxhciggdGhpcy5sZW5ndGgoKSB8fCAxICk7XG5cblx0fVxuXG5cdHNldExlbmd0aCggbGVuZ3RoICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubm9ybWFsaXplKCkubXVsdGlwbHlTY2FsYXIoIGxlbmd0aCApO1xuXG5cdH1cblxuXHRsZXJwKCB2LCBhbHBoYSApIHtcblxuXHRcdHRoaXMueCArPSAoIHYueCAtIHRoaXMueCApICogYWxwaGE7XG5cdFx0dGhpcy55ICs9ICggdi55IC0gdGhpcy55ICkgKiBhbHBoYTtcblx0XHR0aGlzLnogKz0gKCB2LnogLSB0aGlzLnogKSAqIGFscGhhO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGxlcnBWZWN0b3JzKCB2MSwgdjIsIGFscGhhICkge1xuXG5cdFx0dGhpcy54ID0gdjEueCArICggdjIueCAtIHYxLnggKSAqIGFscGhhO1xuXHRcdHRoaXMueSA9IHYxLnkgKyAoIHYyLnkgLSB2MS55ICkgKiBhbHBoYTtcblx0XHR0aGlzLnogPSB2MS56ICsgKCB2Mi56IC0gdjEueiApICogYWxwaGE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y3Jvc3MoIHYgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5jcm9zc1ZlY3RvcnMoIHRoaXMsIHYgKTtcblxuXHR9XG5cblx0Y3Jvc3NWZWN0b3JzKCBhLCBiICkge1xuXG5cdFx0Y29uc3QgYXggPSBhLngsIGF5ID0gYS55LCBheiA9IGEuejtcblx0XHRjb25zdCBieCA9IGIueCwgYnkgPSBiLnksIGJ6ID0gYi56O1xuXG5cdFx0dGhpcy54ID0gYXkgKiBieiAtIGF6ICogYnk7XG5cdFx0dGhpcy55ID0gYXogKiBieCAtIGF4ICogYno7XG5cdFx0dGhpcy56ID0gYXggKiBieSAtIGF5ICogYng7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cHJvamVjdE9uVmVjdG9yKCB2ICkge1xuXG5cdFx0Y29uc3QgZGVub21pbmF0b3IgPSB2Lmxlbmd0aFNxKCk7XG5cblx0XHRpZiAoIGRlbm9taW5hdG9yID09PSAwICkgcmV0dXJuIHRoaXMuc2V0KCAwLCAwLCAwICk7XG5cblx0XHRjb25zdCBzY2FsYXIgPSB2LmRvdCggdGhpcyApIC8gZGVub21pbmF0b3I7XG5cblx0XHRyZXR1cm4gdGhpcy5jb3B5KCB2ICkubXVsdGlwbHlTY2FsYXIoIHNjYWxhciApO1xuXG5cdH1cblxuXHRwcm9qZWN0T25QbGFuZSggcGxhbmVOb3JtYWwgKSB7XG5cblx0XHRfdmVjdG9yJGMuY29weSggdGhpcyApLnByb2plY3RPblZlY3RvciggcGxhbmVOb3JtYWwgKTtcblxuXHRcdHJldHVybiB0aGlzLnN1YiggX3ZlY3RvciRjICk7XG5cblx0fVxuXG5cdHJlZmxlY3QoIG5vcm1hbCApIHtcblxuXHRcdC8vIHJlZmxlY3QgaW5jaWRlbnQgdmVjdG9yIG9mZiBwbGFuZSBvcnRob2dvbmFsIHRvIG5vcm1hbFxuXHRcdC8vIG5vcm1hbCBpcyBhc3N1bWVkIHRvIGhhdmUgdW5pdCBsZW5ndGhcblxuXHRcdHJldHVybiB0aGlzLnN1YiggX3ZlY3RvciRjLmNvcHkoIG5vcm1hbCApLm11bHRpcGx5U2NhbGFyKCAyICogdGhpcy5kb3QoIG5vcm1hbCApICkgKTtcblxuXHR9XG5cblx0YW5nbGVUbyggdiApIHtcblxuXHRcdGNvbnN0IGRlbm9taW5hdG9yID0gTWF0aC5zcXJ0KCB0aGlzLmxlbmd0aFNxKCkgKiB2Lmxlbmd0aFNxKCkgKTtcblxuXHRcdGlmICggZGVub21pbmF0b3IgPT09IDAgKSByZXR1cm4gTWF0aC5QSSAvIDI7XG5cblx0XHRjb25zdCB0aGV0YSA9IHRoaXMuZG90KCB2ICkgLyBkZW5vbWluYXRvcjtcblxuXHRcdC8vIGNsYW1wLCB0byBoYW5kbGUgbnVtZXJpY2FsIHByb2JsZW1zXG5cblx0XHRyZXR1cm4gTWF0aC5hY29zKCBjbGFtcCggdGhldGEsIC0gMSwgMSApICk7XG5cblx0fVxuXG5cdGRpc3RhbmNlVG8oIHYgKSB7XG5cblx0XHRyZXR1cm4gTWF0aC5zcXJ0KCB0aGlzLmRpc3RhbmNlVG9TcXVhcmVkKCB2ICkgKTtcblxuXHR9XG5cblx0ZGlzdGFuY2VUb1NxdWFyZWQoIHYgKSB7XG5cblx0XHRjb25zdCBkeCA9IHRoaXMueCAtIHYueCwgZHkgPSB0aGlzLnkgLSB2LnksIGR6ID0gdGhpcy56IC0gdi56O1xuXG5cdFx0cmV0dXJuIGR4ICogZHggKyBkeSAqIGR5ICsgZHogKiBkejtcblxuXHR9XG5cblx0bWFuaGF0dGFuRGlzdGFuY2VUbyggdiApIHtcblxuXHRcdHJldHVybiBNYXRoLmFicyggdGhpcy54IC0gdi54ICkgKyBNYXRoLmFicyggdGhpcy55IC0gdi55ICkgKyBNYXRoLmFicyggdGhpcy56IC0gdi56ICk7XG5cblx0fVxuXG5cdHNldEZyb21TcGhlcmljYWwoIHMgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5zZXRGcm9tU3BoZXJpY2FsQ29vcmRzKCBzLnJhZGl1cywgcy5waGksIHMudGhldGEgKTtcblxuXHR9XG5cblx0c2V0RnJvbVNwaGVyaWNhbENvb3JkcyggcmFkaXVzLCBwaGksIHRoZXRhICkge1xuXG5cdFx0Y29uc3Qgc2luUGhpUmFkaXVzID0gTWF0aC5zaW4oIHBoaSApICogcmFkaXVzO1xuXG5cdFx0dGhpcy54ID0gc2luUGhpUmFkaXVzICogTWF0aC5zaW4oIHRoZXRhICk7XG5cdFx0dGhpcy55ID0gTWF0aC5jb3MoIHBoaSApICogcmFkaXVzO1xuXHRcdHRoaXMueiA9IHNpblBoaVJhZGl1cyAqIE1hdGguY29zKCB0aGV0YSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21DeWxpbmRyaWNhbCggYyApIHtcblxuXHRcdHJldHVybiB0aGlzLnNldEZyb21DeWxpbmRyaWNhbENvb3JkcyggYy5yYWRpdXMsIGMudGhldGEsIGMueSApO1xuXG5cdH1cblxuXHRzZXRGcm9tQ3lsaW5kcmljYWxDb29yZHMoIHJhZGl1cywgdGhldGEsIHkgKSB7XG5cblx0XHR0aGlzLnggPSByYWRpdXMgKiBNYXRoLnNpbiggdGhldGEgKTtcblx0XHR0aGlzLnkgPSB5O1xuXHRcdHRoaXMueiA9IHJhZGl1cyAqIE1hdGguY29zKCB0aGV0YSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21NYXRyaXhQb3NpdGlvbiggbSApIHtcblxuXHRcdGNvbnN0IGUgPSBtLmVsZW1lbnRzO1xuXG5cdFx0dGhpcy54ID0gZVsgMTIgXTtcblx0XHR0aGlzLnkgPSBlWyAxMyBdO1xuXHRcdHRoaXMueiA9IGVbIDE0IF07XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbU1hdHJpeFNjYWxlKCBtICkge1xuXG5cdFx0Y29uc3Qgc3ggPSB0aGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIG0sIDAgKS5sZW5ndGgoKTtcblx0XHRjb25zdCBzeSA9IHRoaXMuc2V0RnJvbU1hdHJpeENvbHVtbiggbSwgMSApLmxlbmd0aCgpO1xuXHRcdGNvbnN0IHN6ID0gdGhpcy5zZXRGcm9tTWF0cml4Q29sdW1uKCBtLCAyICkubGVuZ3RoKCk7XG5cblx0XHR0aGlzLnggPSBzeDtcblx0XHR0aGlzLnkgPSBzeTtcblx0XHR0aGlzLnogPSBzejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tTWF0cml4Q29sdW1uKCBtLCBpbmRleCApIHtcblxuXHRcdHJldHVybiB0aGlzLmZyb21BcnJheSggbS5lbGVtZW50cywgaW5kZXggKiA0ICk7XG5cblx0fVxuXG5cdHNldEZyb21NYXRyaXgzQ29sdW1uKCBtLCBpbmRleCApIHtcblxuXHRcdHJldHVybiB0aGlzLmZyb21BcnJheSggbS5lbGVtZW50cywgaW5kZXggKiAzICk7XG5cblx0fVxuXG5cdHNldEZyb21FdWxlciggZSApIHtcblxuXHRcdHRoaXMueCA9IGUuX3g7XG5cdFx0dGhpcy55ID0gZS5feTtcblx0XHR0aGlzLnogPSBlLl96O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21Db2xvciggYyApIHtcblxuXHRcdHRoaXMueCA9IGMucjtcblx0XHR0aGlzLnkgPSBjLmc7XG5cdFx0dGhpcy56ID0gYy5iO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGVxdWFscyggdiApIHtcblxuXHRcdHJldHVybiAoICggdi54ID09PSB0aGlzLnggKSAmJiAoIHYueSA9PT0gdGhpcy55ICkgJiYgKCB2LnogPT09IHRoaXMueiApICk7XG5cblx0fVxuXG5cdGZyb21BcnJheSggYXJyYXksIG9mZnNldCA9IDAgKSB7XG5cblx0XHR0aGlzLnggPSBhcnJheVsgb2Zmc2V0IF07XG5cdFx0dGhpcy55ID0gYXJyYXlbIG9mZnNldCArIDEgXTtcblx0XHR0aGlzLnogPSBhcnJheVsgb2Zmc2V0ICsgMiBdO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvQXJyYXkoIGFycmF5ID0gW10sIG9mZnNldCA9IDAgKSB7XG5cblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLng7XG5cdFx0YXJyYXlbIG9mZnNldCArIDEgXSA9IHRoaXMueTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMiBdID0gdGhpcy56O1xuXG5cdFx0cmV0dXJuIGFycmF5O1xuXG5cdH1cblxuXHRmcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGluZGV4ICkge1xuXG5cdFx0dGhpcy54ID0gYXR0cmlidXRlLmdldFgoIGluZGV4ICk7XG5cdFx0dGhpcy55ID0gYXR0cmlidXRlLmdldFkoIGluZGV4ICk7XG5cdFx0dGhpcy56ID0gYXR0cmlidXRlLmdldFooIGluZGV4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cmFuZG9tKCkge1xuXG5cdFx0dGhpcy54ID0gTWF0aC5yYW5kb20oKTtcblx0XHR0aGlzLnkgPSBNYXRoLnJhbmRvbSgpO1xuXHRcdHRoaXMueiA9IE1hdGgucmFuZG9tKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cmFuZG9tRGlyZWN0aW9uKCkge1xuXG5cdFx0Ly8gaHR0cHM6Ly9tYXRod29ybGQud29sZnJhbS5jb20vU3BoZXJlUG9pbnRQaWNraW5nLmh0bWxcblxuXHRcdGNvbnN0IHRoZXRhID0gTWF0aC5yYW5kb20oKSAqIE1hdGguUEkgKiAyO1xuXHRcdGNvbnN0IHUgPSBNYXRoLnJhbmRvbSgpICogMiAtIDE7XG5cdFx0Y29uc3QgYyA9IE1hdGguc3FydCggMSAtIHUgKiB1ICk7XG5cblx0XHR0aGlzLnggPSBjICogTWF0aC5jb3MoIHRoZXRhICk7XG5cdFx0dGhpcy55ID0gdTtcblx0XHR0aGlzLnogPSBjICogTWF0aC5zaW4oIHRoZXRhICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0KlsgU3ltYm9sLml0ZXJhdG9yIF0oKSB7XG5cblx0XHR5aWVsZCB0aGlzLng7XG5cdFx0eWllbGQgdGhpcy55O1xuXHRcdHlpZWxkIHRoaXMuejtcblxuXHR9XG5cbn1cblxuY29uc3QgX3ZlY3RvciRjID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3F1YXRlcm5pb24kNCA9IC8qQF9fUFVSRV9fKi8gbmV3IFF1YXRlcm5pb24oKTtcblxuY2xhc3MgQm94MyB7XG5cblx0Y29uc3RydWN0b3IoIG1pbiA9IG5ldyBWZWN0b3IzKCArIEluZmluaXR5LCArIEluZmluaXR5LCArIEluZmluaXR5ICksIG1heCA9IG5ldyBWZWN0b3IzKCAtIEluZmluaXR5LCAtIEluZmluaXR5LCAtIEluZmluaXR5ICkgKSB7XG5cblx0XHR0aGlzLmlzQm94MyA9IHRydWU7XG5cblx0XHR0aGlzLm1pbiA9IG1pbjtcblx0XHR0aGlzLm1heCA9IG1heDtcblxuXHR9XG5cblx0c2V0KCBtaW4sIG1heCApIHtcblxuXHRcdHRoaXMubWluLmNvcHkoIG1pbiApO1xuXHRcdHRoaXMubWF4LmNvcHkoIG1heCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21BcnJheSggYXJyYXkgKSB7XG5cblx0XHR0aGlzLm1ha2VFbXB0eSgpO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGFycmF5Lmxlbmd0aDsgaSA8IGlsOyBpICs9IDMgKSB7XG5cblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggX3ZlY3RvciRiLmZyb21BcnJheSggYXJyYXksIGkgKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSApIHtcblxuXHRcdHRoaXMubWFrZUVtcHR5KCk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXR0cmlidXRlLmNvdW50OyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggX3ZlY3RvciRiLmZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaSApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbVBvaW50cyggcG9pbnRzICkge1xuXG5cdFx0dGhpcy5tYWtlRW1wdHkoKTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBwb2ludHMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggcG9pbnRzWyBpIF0gKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tQ2VudGVyQW5kU2l6ZSggY2VudGVyLCBzaXplICkge1xuXG5cdFx0Y29uc3QgaGFsZlNpemUgPSBfdmVjdG9yJGIuY29weSggc2l6ZSApLm11bHRpcGx5U2NhbGFyKCAwLjUgKTtcblxuXHRcdHRoaXMubWluLmNvcHkoIGNlbnRlciApLnN1YiggaGFsZlNpemUgKTtcblx0XHR0aGlzLm1heC5jb3B5KCBjZW50ZXIgKS5hZGQoIGhhbGZTaXplICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbU9iamVjdCggb2JqZWN0LCBwcmVjaXNlID0gZmFsc2UgKSB7XG5cblx0XHR0aGlzLm1ha2VFbXB0eSgpO1xuXG5cdFx0cmV0dXJuIHRoaXMuZXhwYW5kQnlPYmplY3QoIG9iamVjdCwgcHJlY2lzZSApO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcblxuXHR9XG5cblx0Y29weSggYm94ICkge1xuXG5cdFx0dGhpcy5taW4uY29weSggYm94Lm1pbiApO1xuXHRcdHRoaXMubWF4LmNvcHkoIGJveC5tYXggKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlRW1wdHkoKSB7XG5cblx0XHR0aGlzLm1pbi54ID0gdGhpcy5taW4ueSA9IHRoaXMubWluLnogPSArIEluZmluaXR5O1xuXHRcdHRoaXMubWF4LnggPSB0aGlzLm1heC55ID0gdGhpcy5tYXgueiA9IC0gSW5maW5pdHk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0aXNFbXB0eSgpIHtcblxuXHRcdC8vIHRoaXMgaXMgYSBtb3JlIHJvYnVzdCBjaGVjayBmb3IgZW1wdHkgdGhhbiAoIHZvbHVtZSA8PSAwICkgYmVjYXVzZSB2b2x1bWUgY2FuIGdldCBwb3NpdGl2ZSB3aXRoIHR3byBuZWdhdGl2ZSBheGVzXG5cblx0XHRyZXR1cm4gKCB0aGlzLm1heC54IDwgdGhpcy5taW4ueCApIHx8ICggdGhpcy5tYXgueSA8IHRoaXMubWluLnkgKSB8fCAoIHRoaXMubWF4LnogPCB0aGlzLm1pbi56ICk7XG5cblx0fVxuXG5cdGdldENlbnRlciggdGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuaXNFbXB0eSgpID8gdGFyZ2V0LnNldCggMCwgMCwgMCApIDogdGFyZ2V0LmFkZFZlY3RvcnMoIHRoaXMubWluLCB0aGlzLm1heCApLm11bHRpcGx5U2NhbGFyKCAwLjUgKTtcblxuXHR9XG5cblx0Z2V0U2l6ZSggdGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuaXNFbXB0eSgpID8gdGFyZ2V0LnNldCggMCwgMCwgMCApIDogdGFyZ2V0LnN1YlZlY3RvcnMoIHRoaXMubWF4LCB0aGlzLm1pbiApO1xuXG5cdH1cblxuXHRleHBhbmRCeVBvaW50KCBwb2ludCApIHtcblxuXHRcdHRoaXMubWluLm1pbiggcG9pbnQgKTtcblx0XHR0aGlzLm1heC5tYXgoIHBvaW50ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXhwYW5kQnlWZWN0b3IoIHZlY3RvciApIHtcblxuXHRcdHRoaXMubWluLnN1YiggdmVjdG9yICk7XG5cdFx0dGhpcy5tYXguYWRkKCB2ZWN0b3IgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRleHBhbmRCeVNjYWxhciggc2NhbGFyICkge1xuXG5cdFx0dGhpcy5taW4uYWRkU2NhbGFyKCAtIHNjYWxhciApO1xuXHRcdHRoaXMubWF4LmFkZFNjYWxhciggc2NhbGFyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXhwYW5kQnlPYmplY3QoIG9iamVjdCwgcHJlY2lzZSA9IGZhbHNlICkge1xuXG5cdFx0Ly8gQ29tcHV0ZXMgdGhlIHdvcmxkLWF4aXMtYWxpZ25lZCBib3VuZGluZyBib3ggb2YgYW4gb2JqZWN0IChpbmNsdWRpbmcgaXRzIGNoaWxkcmVuKSxcblx0XHQvLyBhY2NvdW50aW5nIGZvciBib3RoIHRoZSBvYmplY3QncywgYW5kIGNoaWxkcmVuJ3MsIHdvcmxkIHRyYW5zZm9ybXNcblxuXHRcdG9iamVjdC51cGRhdGVXb3JsZE1hdHJpeCggZmFsc2UsIGZhbHNlICk7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IG9iamVjdC5nZW9tZXRyeTtcblxuXHRcdGlmICggZ2VvbWV0cnkgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3QgcG9zaXRpb25BdHRyaWJ1dGUgPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKTtcblxuXHRcdFx0Ly8gcHJlY2lzZSBBQUJCIGNvbXB1dGF0aW9uIGJhc2VkIG9uIHZlcnRleCBkYXRhIHJlcXVpcmVzIGF0IGxlYXN0IGEgcG9zaXRpb24gYXR0cmlidXRlLlxuXHRcdFx0Ly8gaW5zdGFuY2luZyBpc24ndCBzdXBwb3J0ZWQgc28gZmFyIGFuZCB1c2VzIHRoZSBub3JtYWwgKGNvbnNlcnZhdGl2ZSkgY29kZSBwYXRoLlxuXG5cdFx0XHRpZiAoIHByZWNpc2UgPT09IHRydWUgJiYgcG9zaXRpb25BdHRyaWJ1dGUgIT09IHVuZGVmaW5lZCAmJiBvYmplY3QuaXNJbnN0YW5jZWRNZXNoICE9PSB0cnVlICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHBvc2l0aW9uQXR0cmlidXRlLmNvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGlmICggb2JqZWN0LmlzTWVzaCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdFx0b2JqZWN0LmdldFZlcnRleFBvc2l0aW9uKCBpLCBfdmVjdG9yJGIgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdF92ZWN0b3IkYi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0X3ZlY3RvciRiLmFwcGx5TWF0cml4NCggb2JqZWN0Lm1hdHJpeFdvcmxkICk7XG5cdFx0XHRcdFx0dGhpcy5leHBhbmRCeVBvaW50KCBfdmVjdG9yJGIgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0aWYgKCBvYmplY3QuYm91bmRpbmdCb3ggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdC8vIG9iamVjdC1sZXZlbCBib3VuZGluZyBib3hcblxuXHRcdFx0XHRcdGlmICggb2JqZWN0LmJvdW5kaW5nQm94ID09PSBudWxsICkge1xuXG5cdFx0XHRcdFx0XHRvYmplY3QuY29tcHV0ZUJvdW5kaW5nQm94KCk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRfYm94JDQuY29weSggb2JqZWN0LmJvdW5kaW5nQm94ICk7XG5cblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ly8gZ2VvbWV0cnktbGV2ZWwgYm91bmRpbmcgYm94XG5cblx0XHRcdFx0XHRpZiAoIGdlb21ldHJ5LmJvdW5kaW5nQm94ID09PSBudWxsICkge1xuXG5cdFx0XHRcdFx0XHRnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdCb3goKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdF9ib3gkNC5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ0JveCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRfYm94JDQuYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKTtcblxuXHRcdFx0XHR0aGlzLnVuaW9uKCBfYm94JDQgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Y29uc3QgY2hpbGRyZW4gPSBvYmplY3QuY2hpbGRyZW47XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjaGlsZHJlbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmV4cGFuZEJ5T2JqZWN0KCBjaGlsZHJlblsgaSBdLCBwcmVjaXNlICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29udGFpbnNQb2ludCggcG9pbnQgKSB7XG5cblx0XHRyZXR1cm4gcG9pbnQueCA+PSB0aGlzLm1pbi54ICYmIHBvaW50LnggPD0gdGhpcy5tYXgueCAmJlxuXHRcdFx0cG9pbnQueSA+PSB0aGlzLm1pbi55ICYmIHBvaW50LnkgPD0gdGhpcy5tYXgueSAmJlxuXHRcdFx0cG9pbnQueiA+PSB0aGlzLm1pbi56ICYmIHBvaW50LnogPD0gdGhpcy5tYXguejtcblxuXHR9XG5cblx0Y29udGFpbnNCb3goIGJveCApIHtcblxuXHRcdHJldHVybiB0aGlzLm1pbi54IDw9IGJveC5taW4ueCAmJiBib3gubWF4LnggPD0gdGhpcy5tYXgueCAmJlxuXHRcdFx0dGhpcy5taW4ueSA8PSBib3gubWluLnkgJiYgYm94Lm1heC55IDw9IHRoaXMubWF4LnkgJiZcblx0XHRcdHRoaXMubWluLnogPD0gYm94Lm1pbi56ICYmIGJveC5tYXgueiA8PSB0aGlzLm1heC56O1xuXG5cdH1cblxuXHRnZXRQYXJhbWV0ZXIoIHBvaW50LCB0YXJnZXQgKSB7XG5cblx0XHQvLyBUaGlzIGNhbiBwb3RlbnRpYWxseSBoYXZlIGEgZGl2aWRlIGJ5IHplcm8gaWYgdGhlIGJveFxuXHRcdC8vIGhhcyBhIHNpemUgZGltZW5zaW9uIG9mIDAuXG5cblx0XHRyZXR1cm4gdGFyZ2V0LnNldChcblx0XHRcdCggcG9pbnQueCAtIHRoaXMubWluLnggKSAvICggdGhpcy5tYXgueCAtIHRoaXMubWluLnggKSxcblx0XHRcdCggcG9pbnQueSAtIHRoaXMubWluLnkgKSAvICggdGhpcy5tYXgueSAtIHRoaXMubWluLnkgKSxcblx0XHRcdCggcG9pbnQueiAtIHRoaXMubWluLnogKSAvICggdGhpcy5tYXgueiAtIHRoaXMubWluLnogKVxuXHRcdCk7XG5cblx0fVxuXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcblxuXHRcdC8vIHVzaW5nIDYgc3BsaXR0aW5nIHBsYW5lcyB0byBydWxlIG91dCBpbnRlcnNlY3Rpb25zLlxuXHRcdHJldHVybiBib3gubWF4LnggPj0gdGhpcy5taW4ueCAmJiBib3gubWluLnggPD0gdGhpcy5tYXgueCAmJlxuXHRcdFx0Ym94Lm1heC55ID49IHRoaXMubWluLnkgJiYgYm94Lm1pbi55IDw9IHRoaXMubWF4LnkgJiZcblx0XHRcdGJveC5tYXgueiA+PSB0aGlzLm1pbi56ICYmIGJveC5taW4ueiA8PSB0aGlzLm1heC56O1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzU3BoZXJlKCBzcGhlcmUgKSB7XG5cblx0XHQvLyBGaW5kIHRoZSBwb2ludCBvbiB0aGUgQUFCQiBjbG9zZXN0IHRvIHRoZSBzcGhlcmUgY2VudGVyLlxuXHRcdHRoaXMuY2xhbXBQb2ludCggc3BoZXJlLmNlbnRlciwgX3ZlY3RvciRiICk7XG5cblx0XHQvLyBJZiB0aGF0IHBvaW50IGlzIGluc2lkZSB0aGUgc3BoZXJlLCB0aGUgQUFCQiBhbmQgc3BoZXJlIGludGVyc2VjdC5cblx0XHRyZXR1cm4gX3ZlY3RvciRiLmRpc3RhbmNlVG9TcXVhcmVkKCBzcGhlcmUuY2VudGVyICkgPD0gKCBzcGhlcmUucmFkaXVzICogc3BoZXJlLnJhZGl1cyApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzUGxhbmUoIHBsYW5lICkge1xuXG5cdFx0Ly8gV2UgY29tcHV0ZSB0aGUgbWluaW11bSBhbmQgbWF4aW11bSBkb3QgcHJvZHVjdCB2YWx1ZXMuIElmIHRob3NlIHZhbHVlc1xuXHRcdC8vIGFyZSBvbiB0aGUgc2FtZSBzaWRlIChiYWNrIG9yIGZyb250KSBvZiB0aGUgcGxhbmUsIHRoZW4gdGhlcmUgaXMgbm8gaW50ZXJzZWN0aW9uLlxuXG5cdFx0bGV0IG1pbiwgbWF4O1xuXG5cdFx0aWYgKCBwbGFuZS5ub3JtYWwueCA+IDAgKSB7XG5cblx0XHRcdG1pbiA9IHBsYW5lLm5vcm1hbC54ICogdGhpcy5taW4ueDtcblx0XHRcdG1heCA9IHBsYW5lLm5vcm1hbC54ICogdGhpcy5tYXgueDtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdG1pbiA9IHBsYW5lLm5vcm1hbC54ICogdGhpcy5tYXgueDtcblx0XHRcdG1heCA9IHBsYW5lLm5vcm1hbC54ICogdGhpcy5taW4ueDtcblxuXHRcdH1cblxuXHRcdGlmICggcGxhbmUubm9ybWFsLnkgPiAwICkge1xuXG5cdFx0XHRtaW4gKz0gcGxhbmUubm9ybWFsLnkgKiB0aGlzLm1pbi55O1xuXHRcdFx0bWF4ICs9IHBsYW5lLm5vcm1hbC55ICogdGhpcy5tYXgueTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdG1pbiArPSBwbGFuZS5ub3JtYWwueSAqIHRoaXMubWF4Lnk7XG5cdFx0XHRtYXggKz0gcGxhbmUubm9ybWFsLnkgKiB0aGlzLm1pbi55O1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBwbGFuZS5ub3JtYWwueiA+IDAgKSB7XG5cblx0XHRcdG1pbiArPSBwbGFuZS5ub3JtYWwueiAqIHRoaXMubWluLno7XG5cdFx0XHRtYXggKz0gcGxhbmUubm9ybWFsLnogKiB0aGlzLm1heC56O1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0bWluICs9IHBsYW5lLm5vcm1hbC56ICogdGhpcy5tYXguejtcblx0XHRcdG1heCArPSBwbGFuZS5ub3JtYWwueiAqIHRoaXMubWluLno7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gKCBtaW4gPD0gLSBwbGFuZS5jb25zdGFudCAmJiBtYXggPj0gLSBwbGFuZS5jb25zdGFudCApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzVHJpYW5nbGUoIHRyaWFuZ2xlICkge1xuXG5cdFx0aWYgKCB0aGlzLmlzRW1wdHkoKSApIHtcblxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0Ly8gY29tcHV0ZSBib3ggY2VudGVyIGFuZCBleHRlbnRzXG5cdFx0dGhpcy5nZXRDZW50ZXIoIF9jZW50ZXIgKTtcblx0XHRfZXh0ZW50cy5zdWJWZWN0b3JzKCB0aGlzLm1heCwgX2NlbnRlciApO1xuXG5cdFx0Ly8gdHJhbnNsYXRlIHRyaWFuZ2xlIHRvIGFhYmIgb3JpZ2luXG5cdFx0X3YwJDMuc3ViVmVjdG9ycyggdHJpYW5nbGUuYSwgX2NlbnRlciApO1xuXHRcdF92MSQ3LnN1YlZlY3RvcnMoIHRyaWFuZ2xlLmIsIF9jZW50ZXIgKTtcblx0XHRfdjIkNC5zdWJWZWN0b3JzKCB0cmlhbmdsZS5jLCBfY2VudGVyICk7XG5cblx0XHQvLyBjb21wdXRlIGVkZ2UgdmVjdG9ycyBmb3IgdHJpYW5nbGVcblx0XHRfZjAuc3ViVmVjdG9ycyggX3YxJDcsIF92MCQzICk7XG5cdFx0X2YxLnN1YlZlY3RvcnMoIF92MiQ0LCBfdjEkNyApO1xuXHRcdF9mMi5zdWJWZWN0b3JzKCBfdjAkMywgX3YyJDQgKTtcblxuXHRcdC8vIHRlc3QgYWdhaW5zdCBheGVzIHRoYXQgYXJlIGdpdmVuIGJ5IGNyb3NzIHByb2R1Y3QgY29tYmluYXRpb25zIG9mIHRoZSBlZGdlcyBvZiB0aGUgdHJpYW5nbGUgYW5kIHRoZSBlZGdlcyBvZiB0aGUgYWFiYlxuXHRcdC8vIG1ha2UgYW4gYXhpcyB0ZXN0aW5nIG9mIGVhY2ggb2YgdGhlIDMgc2lkZXMgb2YgdGhlIGFhYmIgYWdhaW5zdCBlYWNoIG9mIHRoZSAzIHNpZGVzIG9mIHRoZSB0cmlhbmdsZSA9IDkgYXhpcyBvZiBzZXBhcmF0aW9uXG5cdFx0Ly8gYXhpc19paiA9IHVfaSB4IGZfaiAodTAsIHUxLCB1MiA9IGZhY2Ugbm9ybWFscyBvZiBhYWJiID0geCx5LHogYXhlcyB2ZWN0b3JzIHNpbmNlIGFhYmIgaXMgYXhpcyBhbGlnbmVkKVxuXHRcdGxldCBheGVzID0gW1xuXHRcdFx0MCwgLSBfZjAueiwgX2YwLnksIDAsIC0gX2YxLnosIF9mMS55LCAwLCAtIF9mMi56LCBfZjIueSxcblx0XHRcdF9mMC56LCAwLCAtIF9mMC54LCBfZjEueiwgMCwgLSBfZjEueCwgX2YyLnosIDAsIC0gX2YyLngsXG5cdFx0XHQtIF9mMC55LCBfZjAueCwgMCwgLSBfZjEueSwgX2YxLngsIDAsIC0gX2YyLnksIF9mMi54LCAwXG5cdFx0XTtcblx0XHRpZiAoICEgc2F0Rm9yQXhlcyggYXhlcywgX3YwJDMsIF92MSQ3LCBfdjIkNCwgX2V4dGVudHMgKSApIHtcblxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0Ly8gdGVzdCAzIGZhY2Ugbm9ybWFscyBmcm9tIHRoZSBhYWJiXG5cdFx0YXhlcyA9IFsgMSwgMCwgMCwgMCwgMSwgMCwgMCwgMCwgMSBdO1xuXHRcdGlmICggISBzYXRGb3JBeGVzKCBheGVzLCBfdjAkMywgX3YxJDcsIF92MiQ0LCBfZXh0ZW50cyApICkge1xuXG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cblx0XHR9XG5cblx0XHQvLyBmaW5hbGx5IHRlc3RpbmcgdGhlIGZhY2Ugbm9ybWFsIG9mIHRoZSB0cmlhbmdsZVxuXHRcdC8vIHVzZSBhbHJlYWR5IGV4aXN0aW5nIHRyaWFuZ2xlIGVkZ2UgdmVjdG9ycyBoZXJlXG5cdFx0X3RyaWFuZ2xlTm9ybWFsLmNyb3NzVmVjdG9ycyggX2YwLCBfZjEgKTtcblx0XHRheGVzID0gWyBfdHJpYW5nbGVOb3JtYWwueCwgX3RyaWFuZ2xlTm9ybWFsLnksIF90cmlhbmdsZU5vcm1hbC56IF07XG5cblx0XHRyZXR1cm4gc2F0Rm9yQXhlcyggYXhlcywgX3YwJDMsIF92MSQ3LCBfdjIkNCwgX2V4dGVudHMgKTtcblxuXHR9XG5cblx0Y2xhbXBQb2ludCggcG9pbnQsIHRhcmdldCApIHtcblxuXHRcdHJldHVybiB0YXJnZXQuY29weSggcG9pbnQgKS5jbGFtcCggdGhpcy5taW4sIHRoaXMubWF4ICk7XG5cblx0fVxuXG5cdGRpc3RhbmNlVG9Qb2ludCggcG9pbnQgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5jbGFtcFBvaW50KCBwb2ludCwgX3ZlY3RvciRiICkuZGlzdGFuY2VUbyggcG9pbnQgKTtcblxuXHR9XG5cblx0Z2V0Qm91bmRpbmdTcGhlcmUoIHRhcmdldCApIHtcblxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB7XG5cblx0XHRcdHRhcmdldC5tYWtlRW1wdHkoKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuZ2V0Q2VudGVyKCB0YXJnZXQuY2VudGVyICk7XG5cblx0XHRcdHRhcmdldC5yYWRpdXMgPSB0aGlzLmdldFNpemUoIF92ZWN0b3IkYiApLmxlbmd0aCgpICogMC41O1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0aW50ZXJzZWN0KCBib3ggKSB7XG5cblx0XHR0aGlzLm1pbi5tYXgoIGJveC5taW4gKTtcblx0XHR0aGlzLm1heC5taW4oIGJveC5tYXggKTtcblxuXHRcdC8vIGVuc3VyZSB0aGF0IGlmIHRoZXJlIGlzIG5vIG92ZXJsYXAsIHRoZSByZXN1bHQgaXMgZnVsbHkgZW1wdHksIG5vdCBzbGlnaHRseSBlbXB0eSB3aXRoIG5vbi1pbmYvK2luZiB2YWx1ZXMgdGhhdCB3aWxsIGNhdXNlIHN1YnNlcXVlbmNlIGludGVyc2VjdHMgdG8gZXJyb25lb3VzbHkgcmV0dXJuIHZhbGlkIHZhbHVlcy5cblx0XHRpZiAoIHRoaXMuaXNFbXB0eSgpICkgdGhpcy5tYWtlRW1wdHkoKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR1bmlvbiggYm94ICkge1xuXG5cdFx0dGhpcy5taW4ubWluKCBib3gubWluICk7XG5cdFx0dGhpcy5tYXgubWF4KCBib3gubWF4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXBwbHlNYXRyaXg0KCBtYXRyaXggKSB7XG5cblx0XHQvLyB0cmFuc2Zvcm0gb2YgZW1wdHkgYm94IGlzIGFuIGVtcHR5IGJveC5cblx0XHRpZiAoIHRoaXMuaXNFbXB0eSgpICkgcmV0dXJuIHRoaXM7XG5cblx0XHQvLyBOT1RFOiBJIGFtIHVzaW5nIGEgYmluYXJ5IHBhdHRlcm4gdG8gc3BlY2lmeSBhbGwgMl4zIGNvbWJpbmF0aW9ucyBiZWxvd1xuXHRcdF9wb2ludHNbIDAgXS5zZXQoIHRoaXMubWluLngsIHRoaXMubWluLnksIHRoaXMubWluLnogKS5hcHBseU1hdHJpeDQoIG1hdHJpeCApOyAvLyAwMDBcblx0XHRfcG9pbnRzWyAxIF0uc2V0KCB0aGlzLm1pbi54LCB0aGlzLm1pbi55LCB0aGlzLm1heC56ICkuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTsgLy8gMDAxXG5cdFx0X3BvaW50c1sgMiBdLnNldCggdGhpcy5taW4ueCwgdGhpcy5tYXgueSwgdGhpcy5taW4ueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDAxMFxuXHRcdF9wb2ludHNbIDMgXS5zZXQoIHRoaXMubWluLngsIHRoaXMubWF4LnksIHRoaXMubWF4LnogKS5hcHBseU1hdHJpeDQoIG1hdHJpeCApOyAvLyAwMTFcblx0XHRfcG9pbnRzWyA0IF0uc2V0KCB0aGlzLm1heC54LCB0aGlzLm1pbi55LCB0aGlzLm1pbi56ICkuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTsgLy8gMTAwXG5cdFx0X3BvaW50c1sgNSBdLnNldCggdGhpcy5tYXgueCwgdGhpcy5taW4ueSwgdGhpcy5tYXgueiApLmFwcGx5TWF0cml4NCggbWF0cml4ICk7IC8vIDEwMVxuXHRcdF9wb2ludHNbIDYgXS5zZXQoIHRoaXMubWF4LngsIHRoaXMubWF4LnksIHRoaXMubWluLnogKS5hcHBseU1hdHJpeDQoIG1hdHJpeCApOyAvLyAxMTBcblx0XHRfcG9pbnRzWyA3IF0uc2V0KCB0aGlzLm1heC54LCB0aGlzLm1heC55LCB0aGlzLm1heC56ICkuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTsgLy8gMTExXG5cblx0XHR0aGlzLnNldEZyb21Qb2ludHMoIF9wb2ludHMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0cmFuc2xhdGUoIG9mZnNldCApIHtcblxuXHRcdHRoaXMubWluLmFkZCggb2Zmc2V0ICk7XG5cdFx0dGhpcy5tYXguYWRkKCBvZmZzZXQgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRlcXVhbHMoIGJveCApIHtcblxuXHRcdHJldHVybiBib3gubWluLmVxdWFscyggdGhpcy5taW4gKSAmJiBib3gubWF4LmVxdWFscyggdGhpcy5tYXggKTtcblxuXHR9XG5cbn1cblxuY29uc3QgX3BvaW50cyA9IFtcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpLFxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCksXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKSxcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpLFxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCksXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKSxcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpLFxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKClcbl07XG5cbmNvbnN0IF92ZWN0b3IkYiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY29uc3QgX2JveCQ0ID0gLypAX19QVVJFX18qLyBuZXcgQm94MygpO1xuXG4vLyB0cmlhbmdsZSBjZW50ZXJlZCB2ZXJ0aWNlc1xuXG5jb25zdCBfdjAkMyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92MSQ3ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3YyJDQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbi8vIHRyaWFuZ2xlIGVkZ2UgdmVjdG9yc1xuXG5jb25zdCBfZjAgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfZjEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfZjIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNvbnN0IF9jZW50ZXIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfZXh0ZW50cyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF90cmlhbmdsZU5vcm1hbCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF90ZXN0QXhpcyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuZnVuY3Rpb24gc2F0Rm9yQXhlcyggYXhlcywgdjAsIHYxLCB2MiwgZXh0ZW50cyApIHtcblxuXHRmb3IgKCBsZXQgaSA9IDAsIGogPSBheGVzLmxlbmd0aCAtIDM7IGkgPD0gajsgaSArPSAzICkge1xuXG5cdFx0X3Rlc3RBeGlzLmZyb21BcnJheSggYXhlcywgaSApO1xuXHRcdC8vIHByb2plY3QgdGhlIGFhYmIgb250byB0aGUgc2VwYXJhdGluZyBheGlzXG5cdFx0Y29uc3QgciA9IGV4dGVudHMueCAqIE1hdGguYWJzKCBfdGVzdEF4aXMueCApICsgZXh0ZW50cy55ICogTWF0aC5hYnMoIF90ZXN0QXhpcy55ICkgKyBleHRlbnRzLnogKiBNYXRoLmFicyggX3Rlc3RBeGlzLnogKTtcblx0XHQvLyBwcm9qZWN0IGFsbCAzIHZlcnRpY2VzIG9mIHRoZSB0cmlhbmdsZSBvbnRvIHRoZSBzZXBhcmF0aW5nIGF4aXNcblx0XHRjb25zdCBwMCA9IHYwLmRvdCggX3Rlc3RBeGlzICk7XG5cdFx0Y29uc3QgcDEgPSB2MS5kb3QoIF90ZXN0QXhpcyApO1xuXHRcdGNvbnN0IHAyID0gdjIuZG90KCBfdGVzdEF4aXMgKTtcblx0XHQvLyBhY3R1YWwgdGVzdCwgYmFzaWNhbGx5IHNlZSBpZiBlaXRoZXIgb2YgdGhlIG1vc3QgZXh0cmVtZSBvZiB0aGUgdHJpYW5nbGUgcG9pbnRzIGludGVyc2VjdHMgclxuXHRcdGlmICggTWF0aC5tYXgoIC0gTWF0aC5tYXgoIHAwLCBwMSwgcDIgKSwgTWF0aC5taW4oIHAwLCBwMSwgcDIgKSApID4gciApIHtcblxuXHRcdFx0Ly8gcG9pbnRzIG9mIHRoZSBwcm9qZWN0ZWQgdHJpYW5nbGUgYXJlIG91dHNpZGUgdGhlIHByb2plY3RlZCBoYWxmLWxlbmd0aCBvZiB0aGUgYWFiYlxuXHRcdFx0Ly8gdGhlIGF4aXMgaXMgc2VwYXJhdGluZyBhbmQgd2UgY2FuIGV4aXRcblx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdH1cblxuXHR9XG5cblx0cmV0dXJuIHRydWU7XG5cbn1cblxuY29uc3QgX2JveCQzID0gLypAX19QVVJFX18qLyBuZXcgQm94MygpO1xuY29uc3QgX3YxJDYgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdjIkMyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgU3BoZXJlIHtcblxuXHRjb25zdHJ1Y3RvciggY2VudGVyID0gbmV3IFZlY3RvcjMoKSwgcmFkaXVzID0gLSAxICkge1xuXG5cdFx0dGhpcy5pc1NwaGVyZSA9IHRydWU7XG5cblx0XHR0aGlzLmNlbnRlciA9IGNlbnRlcjtcblx0XHR0aGlzLnJhZGl1cyA9IHJhZGl1cztcblxuXHR9XG5cblx0c2V0KCBjZW50ZXIsIHJhZGl1cyApIHtcblxuXHRcdHRoaXMuY2VudGVyLmNvcHkoIGNlbnRlciApO1xuXHRcdHRoaXMucmFkaXVzID0gcmFkaXVzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21Qb2ludHMoIHBvaW50cywgb3B0aW9uYWxDZW50ZXIgKSB7XG5cblx0XHRjb25zdCBjZW50ZXIgPSB0aGlzLmNlbnRlcjtcblxuXHRcdGlmICggb3B0aW9uYWxDZW50ZXIgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y2VudGVyLmNvcHkoIG9wdGlvbmFsQ2VudGVyICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRfYm94JDMuc2V0RnJvbVBvaW50cyggcG9pbnRzICkuZ2V0Q2VudGVyKCBjZW50ZXIgKTtcblxuXHRcdH1cblxuXHRcdGxldCBtYXhSYWRpdXNTcSA9IDA7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gcG9pbnRzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRtYXhSYWRpdXNTcSA9IE1hdGgubWF4KCBtYXhSYWRpdXNTcSwgY2VudGVyLmRpc3RhbmNlVG9TcXVhcmVkKCBwb2ludHNbIGkgXSApICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLnJhZGl1cyA9IE1hdGguc3FydCggbWF4UmFkaXVzU3EgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb3B5KCBzcGhlcmUgKSB7XG5cblx0XHR0aGlzLmNlbnRlci5jb3B5KCBzcGhlcmUuY2VudGVyICk7XG5cdFx0dGhpcy5yYWRpdXMgPSBzcGhlcmUucmFkaXVzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGlzRW1wdHkoKSB7XG5cblx0XHRyZXR1cm4gKCB0aGlzLnJhZGl1cyA8IDAgKTtcblxuXHR9XG5cblx0bWFrZUVtcHR5KCkge1xuXG5cdFx0dGhpcy5jZW50ZXIuc2V0KCAwLCAwLCAwICk7XG5cdFx0dGhpcy5yYWRpdXMgPSAtIDE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29udGFpbnNQb2ludCggcG9pbnQgKSB7XG5cblx0XHRyZXR1cm4gKCBwb2ludC5kaXN0YW5jZVRvU3F1YXJlZCggdGhpcy5jZW50ZXIgKSA8PSAoIHRoaXMucmFkaXVzICogdGhpcy5yYWRpdXMgKSApO1xuXG5cdH1cblxuXHRkaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkge1xuXG5cdFx0cmV0dXJuICggcG9pbnQuZGlzdGFuY2VUbyggdGhpcy5jZW50ZXIgKSAtIHRoaXMucmFkaXVzICk7XG5cblx0fVxuXG5cdGludGVyc2VjdHNTcGhlcmUoIHNwaGVyZSApIHtcblxuXHRcdGNvbnN0IHJhZGl1c1N1bSA9IHRoaXMucmFkaXVzICsgc3BoZXJlLnJhZGl1cztcblxuXHRcdHJldHVybiBzcGhlcmUuY2VudGVyLmRpc3RhbmNlVG9TcXVhcmVkKCB0aGlzLmNlbnRlciApIDw9ICggcmFkaXVzU3VtICogcmFkaXVzU3VtICk7XG5cblx0fVxuXG5cdGludGVyc2VjdHNCb3goIGJveCApIHtcblxuXHRcdHJldHVybiBib3guaW50ZXJzZWN0c1NwaGVyZSggdGhpcyApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzUGxhbmUoIHBsYW5lICkge1xuXG5cdFx0cmV0dXJuIE1hdGguYWJzKCBwbGFuZS5kaXN0YW5jZVRvUG9pbnQoIHRoaXMuY2VudGVyICkgKSA8PSB0aGlzLnJhZGl1cztcblxuXHR9XG5cblx0Y2xhbXBQb2ludCggcG9pbnQsIHRhcmdldCApIHtcblxuXHRcdGNvbnN0IGRlbHRhTGVuZ3RoU3EgPSB0aGlzLmNlbnRlci5kaXN0YW5jZVRvU3F1YXJlZCggcG9pbnQgKTtcblxuXHRcdHRhcmdldC5jb3B5KCBwb2ludCApO1xuXG5cdFx0aWYgKCBkZWx0YUxlbmd0aFNxID4gKCB0aGlzLnJhZGl1cyAqIHRoaXMucmFkaXVzICkgKSB7XG5cblx0XHRcdHRhcmdldC5zdWIoIHRoaXMuY2VudGVyICkubm9ybWFsaXplKCk7XG5cdFx0XHR0YXJnZXQubXVsdGlwbHlTY2FsYXIoIHRoaXMucmFkaXVzICkuYWRkKCB0aGlzLmNlbnRlciApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0Z2V0Qm91bmRpbmdCb3goIHRhcmdldCApIHtcblxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB7XG5cblx0XHRcdC8vIEVtcHR5IHNwaGVyZSBwcm9kdWNlcyBlbXB0eSBib3VuZGluZyBib3hcblx0XHRcdHRhcmdldC5tYWtlRW1wdHkoKTtcblx0XHRcdHJldHVybiB0YXJnZXQ7XG5cblx0XHR9XG5cblx0XHR0YXJnZXQuc2V0KCB0aGlzLmNlbnRlciwgdGhpcy5jZW50ZXIgKTtcblx0XHR0YXJnZXQuZXhwYW5kQnlTY2FsYXIoIHRoaXMucmFkaXVzICk7XG5cblx0XHRyZXR1cm4gdGFyZ2V0O1xuXG5cdH1cblxuXHRhcHBseU1hdHJpeDQoIG1hdHJpeCApIHtcblxuXHRcdHRoaXMuY2VudGVyLmFwcGx5TWF0cml4NCggbWF0cml4ICk7XG5cdFx0dGhpcy5yYWRpdXMgPSB0aGlzLnJhZGl1cyAqIG1hdHJpeC5nZXRNYXhTY2FsZU9uQXhpcygpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRyYW5zbGF0ZSggb2Zmc2V0ICkge1xuXG5cdFx0dGhpcy5jZW50ZXIuYWRkKCBvZmZzZXQgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRleHBhbmRCeVBvaW50KCBwb2ludCApIHtcblxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB7XG5cblx0XHRcdHRoaXMuY2VudGVyLmNvcHkoIHBvaW50ICk7XG5cblx0XHRcdHRoaXMucmFkaXVzID0gMDtcblxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHR9XG5cblx0XHRfdjEkNi5zdWJWZWN0b3JzKCBwb2ludCwgdGhpcy5jZW50ZXIgKTtcblxuXHRcdGNvbnN0IGxlbmd0aFNxID0gX3YxJDYubGVuZ3RoU3EoKTtcblxuXHRcdGlmICggbGVuZ3RoU3EgPiAoIHRoaXMucmFkaXVzICogdGhpcy5yYWRpdXMgKSApIHtcblxuXHRcdFx0Ly8gY2FsY3VsYXRlIHRoZSBtaW5pbWFsIHNwaGVyZVxuXG5cdFx0XHRjb25zdCBsZW5ndGggPSBNYXRoLnNxcnQoIGxlbmd0aFNxICk7XG5cblx0XHRcdGNvbnN0IGRlbHRhID0gKCBsZW5ndGggLSB0aGlzLnJhZGl1cyApICogMC41O1xuXG5cdFx0XHR0aGlzLmNlbnRlci5hZGRTY2FsZWRWZWN0b3IoIF92MSQ2LCBkZWx0YSAvIGxlbmd0aCApO1xuXG5cdFx0XHR0aGlzLnJhZGl1cyArPSBkZWx0YTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR1bmlvbiggc3BoZXJlICkge1xuXG5cdFx0aWYgKCBzcGhlcmUuaXNFbXB0eSgpICkge1xuXG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB7XG5cblx0XHRcdHRoaXMuY29weSggc3BoZXJlICk7XG5cblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmNlbnRlci5lcXVhbHMoIHNwaGVyZS5jZW50ZXIgKSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0IHRoaXMucmFkaXVzID0gTWF0aC5tYXgoIHRoaXMucmFkaXVzLCBzcGhlcmUucmFkaXVzICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRfdjIkMy5zdWJWZWN0b3JzKCBzcGhlcmUuY2VudGVyLCB0aGlzLmNlbnRlciApLnNldExlbmd0aCggc3BoZXJlLnJhZGl1cyApO1xuXG5cdFx0XHR0aGlzLmV4cGFuZEJ5UG9pbnQoIF92MSQ2LmNvcHkoIHNwaGVyZS5jZW50ZXIgKS5hZGQoIF92MiQzICkgKTtcblxuXHRcdFx0dGhpcy5leHBhbmRCeVBvaW50KCBfdjEkNi5jb3B5KCBzcGhlcmUuY2VudGVyICkuc3ViKCBfdjIkMyApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXF1YWxzKCBzcGhlcmUgKSB7XG5cblx0XHRyZXR1cm4gc3BoZXJlLmNlbnRlci5lcXVhbHMoIHRoaXMuY2VudGVyICkgJiYgKCBzcGhlcmUucmFkaXVzID09PSB0aGlzLnJhZGl1cyApO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcblxuXHR9XG5cbn1cblxuY29uc3QgX3ZlY3RvciRhID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3NlZ0NlbnRlciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9zZWdEaXIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfZGlmZiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY29uc3QgX2VkZ2UxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2VkZ2UyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX25vcm1hbCQxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jbGFzcyBSYXkge1xuXG5cdGNvbnN0cnVjdG9yKCBvcmlnaW4gPSBuZXcgVmVjdG9yMygpLCBkaXJlY3Rpb24gPSBuZXcgVmVjdG9yMyggMCwgMCwgLSAxICkgKSB7XG5cblx0XHR0aGlzLm9yaWdpbiA9IG9yaWdpbjtcblx0XHR0aGlzLmRpcmVjdGlvbiA9IGRpcmVjdGlvbjtcblxuXHR9XG5cblx0c2V0KCBvcmlnaW4sIGRpcmVjdGlvbiApIHtcblxuXHRcdHRoaXMub3JpZ2luLmNvcHkoIG9yaWdpbiApO1xuXHRcdHRoaXMuZGlyZWN0aW9uLmNvcHkoIGRpcmVjdGlvbiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvcHkoIHJheSApIHtcblxuXHRcdHRoaXMub3JpZ2luLmNvcHkoIHJheS5vcmlnaW4gKTtcblx0XHR0aGlzLmRpcmVjdGlvbi5jb3B5KCByYXkuZGlyZWN0aW9uICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXQoIHQsIHRhcmdldCApIHtcblxuXHRcdHJldHVybiB0YXJnZXQuY29weSggdGhpcy5vcmlnaW4gKS5hZGRTY2FsZWRWZWN0b3IoIHRoaXMuZGlyZWN0aW9uLCB0ICk7XG5cblx0fVxuXG5cdGxvb2tBdCggdiApIHtcblxuXHRcdHRoaXMuZGlyZWN0aW9uLmNvcHkoIHYgKS5zdWIoIHRoaXMub3JpZ2luICkubm9ybWFsaXplKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cmVjYXN0KCB0ICkge1xuXG5cdFx0dGhpcy5vcmlnaW4uY29weSggdGhpcy5hdCggdCwgX3ZlY3RvciRhICkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9zZXN0UG9pbnRUb1BvaW50KCBwb2ludCwgdGFyZ2V0ICkge1xuXG5cdFx0dGFyZ2V0LnN1YlZlY3RvcnMoIHBvaW50LCB0aGlzLm9yaWdpbiApO1xuXG5cdFx0Y29uc3QgZGlyZWN0aW9uRGlzdGFuY2UgPSB0YXJnZXQuZG90KCB0aGlzLmRpcmVjdGlvbiApO1xuXG5cdFx0aWYgKCBkaXJlY3Rpb25EaXN0YW5jZSA8IDAgKSB7XG5cblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggdGhpcy5vcmlnaW4gKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0YXJnZXQuY29weSggdGhpcy5vcmlnaW4gKS5hZGRTY2FsZWRWZWN0b3IoIHRoaXMuZGlyZWN0aW9uLCBkaXJlY3Rpb25EaXN0YW5jZSApO1xuXG5cdH1cblxuXHRkaXN0YW5jZVRvUG9pbnQoIHBvaW50ICkge1xuXG5cdFx0cmV0dXJuIE1hdGguc3FydCggdGhpcy5kaXN0YW5jZVNxVG9Qb2ludCggcG9pbnQgKSApO1xuXG5cdH1cblxuXHRkaXN0YW5jZVNxVG9Qb2ludCggcG9pbnQgKSB7XG5cblx0XHRjb25zdCBkaXJlY3Rpb25EaXN0YW5jZSA9IF92ZWN0b3IkYS5zdWJWZWN0b3JzKCBwb2ludCwgdGhpcy5vcmlnaW4gKS5kb3QoIHRoaXMuZGlyZWN0aW9uICk7XG5cblx0XHQvLyBwb2ludCBiZWhpbmQgdGhlIHJheVxuXG5cdFx0aWYgKCBkaXJlY3Rpb25EaXN0YW5jZSA8IDAgKSB7XG5cblx0XHRcdHJldHVybiB0aGlzLm9yaWdpbi5kaXN0YW5jZVRvU3F1YXJlZCggcG9pbnQgKTtcblxuXHRcdH1cblxuXHRcdF92ZWN0b3IkYS5jb3B5KCB0aGlzLm9yaWdpbiApLmFkZFNjYWxlZFZlY3RvciggdGhpcy5kaXJlY3Rpb24sIGRpcmVjdGlvbkRpc3RhbmNlICk7XG5cblx0XHRyZXR1cm4gX3ZlY3RvciRhLmRpc3RhbmNlVG9TcXVhcmVkKCBwb2ludCApO1xuXG5cdH1cblxuXHRkaXN0YW5jZVNxVG9TZWdtZW50KCB2MCwgdjEsIG9wdGlvbmFsUG9pbnRPblJheSwgb3B0aW9uYWxQb2ludE9uU2VnbWVudCApIHtcblxuXHRcdC8vIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL3Btam9uaWFrL0dlb21ldHJpY1Rvb2xzL2Jsb2IvbWFzdGVyL0dURW5naW5lL0luY2x1ZGUvTWF0aGVtYXRpY3MvR3RlRGlzdFJheVNlZ21lbnQuaFxuXHRcdC8vIEl0IHJldHVybnMgdGhlIG1pbiBkaXN0YW5jZSBiZXR3ZWVuIHRoZSByYXkgYW5kIHRoZSBzZWdtZW50XG5cdFx0Ly8gZGVmaW5lZCBieSB2MCBhbmQgdjFcblx0XHQvLyBJdCBjYW4gYWxzbyBzZXQgdHdvIG9wdGlvbmFsIHRhcmdldHMgOlxuXHRcdC8vIC0gVGhlIGNsb3Nlc3QgcG9pbnQgb24gdGhlIHJheVxuXHRcdC8vIC0gVGhlIGNsb3Nlc3QgcG9pbnQgb24gdGhlIHNlZ21lbnRcblxuXHRcdF9zZWdDZW50ZXIuY29weSggdjAgKS5hZGQoIHYxICkubXVsdGlwbHlTY2FsYXIoIDAuNSApO1xuXHRcdF9zZWdEaXIuY29weSggdjEgKS5zdWIoIHYwICkubm9ybWFsaXplKCk7XG5cdFx0X2RpZmYuY29weSggdGhpcy5vcmlnaW4gKS5zdWIoIF9zZWdDZW50ZXIgKTtcblxuXHRcdGNvbnN0IHNlZ0V4dGVudCA9IHYwLmRpc3RhbmNlVG8oIHYxICkgKiAwLjU7XG5cdFx0Y29uc3QgYTAxID0gLSB0aGlzLmRpcmVjdGlvbi5kb3QoIF9zZWdEaXIgKTtcblx0XHRjb25zdCBiMCA9IF9kaWZmLmRvdCggdGhpcy5kaXJlY3Rpb24gKTtcblx0XHRjb25zdCBiMSA9IC0gX2RpZmYuZG90KCBfc2VnRGlyICk7XG5cdFx0Y29uc3QgYyA9IF9kaWZmLmxlbmd0aFNxKCk7XG5cdFx0Y29uc3QgZGV0ID0gTWF0aC5hYnMoIDEgLSBhMDEgKiBhMDEgKTtcblx0XHRsZXQgczAsIHMxLCBzcXJEaXN0LCBleHREZXQ7XG5cblx0XHRpZiAoIGRldCA+IDAgKSB7XG5cblx0XHRcdC8vIFRoZSByYXkgYW5kIHNlZ21lbnQgYXJlIG5vdCBwYXJhbGxlbC5cblxuXHRcdFx0czAgPSBhMDEgKiBiMSAtIGIwO1xuXHRcdFx0czEgPSBhMDEgKiBiMCAtIGIxO1xuXHRcdFx0ZXh0RGV0ID0gc2VnRXh0ZW50ICogZGV0O1xuXG5cdFx0XHRpZiAoIHMwID49IDAgKSB7XG5cblx0XHRcdFx0aWYgKCBzMSA+PSAtIGV4dERldCApIHtcblxuXHRcdFx0XHRcdGlmICggczEgPD0gZXh0RGV0ICkge1xuXG5cdFx0XHRcdFx0XHQvLyByZWdpb24gMFxuXHRcdFx0XHRcdFx0Ly8gTWluaW11bSBhdCBpbnRlcmlvciBwb2ludHMgb2YgcmF5IGFuZCBzZWdtZW50LlxuXG5cdFx0XHRcdFx0XHRjb25zdCBpbnZEZXQgPSAxIC8gZGV0O1xuXHRcdFx0XHRcdFx0czAgKj0gaW52RGV0O1xuXHRcdFx0XHRcdFx0czEgKj0gaW52RGV0O1xuXHRcdFx0XHRcdFx0c3FyRGlzdCA9IHMwICogKCBzMCArIGEwMSAqIHMxICsgMiAqIGIwICkgKyBzMSAqICggYTAxICogczAgKyBzMSArIDIgKiBiMSApICsgYztcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdC8vIHJlZ2lvbiAxXG5cblx0XHRcdFx0XHRcdHMxID0gc2VnRXh0ZW50O1xuXHRcdFx0XHRcdFx0czAgPSBNYXRoLm1heCggMCwgLSAoIGEwMSAqIHMxICsgYjAgKSApO1xuXHRcdFx0XHRcdFx0c3FyRGlzdCA9IC0gczAgKiBzMCArIHMxICogKCBzMSArIDIgKiBiMSApICsgYztcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ly8gcmVnaW9uIDVcblxuXHRcdFx0XHRcdHMxID0gLSBzZWdFeHRlbnQ7XG5cdFx0XHRcdFx0czAgPSBNYXRoLm1heCggMCwgLSAoIGEwMSAqIHMxICsgYjAgKSApO1xuXHRcdFx0XHRcdHNxckRpc3QgPSAtIHMwICogczAgKyBzMSAqICggczEgKyAyICogYjEgKSArIGM7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGlmICggczEgPD0gLSBleHREZXQgKSB7XG5cblx0XHRcdFx0XHQvLyByZWdpb24gNFxuXG5cdFx0XHRcdFx0czAgPSBNYXRoLm1heCggMCwgLSAoIC0gYTAxICogc2VnRXh0ZW50ICsgYjAgKSApO1xuXHRcdFx0XHRcdHMxID0gKCBzMCA+IDAgKSA/IC0gc2VnRXh0ZW50IDogTWF0aC5taW4oIE1hdGgubWF4KCAtIHNlZ0V4dGVudCwgLSBiMSApLCBzZWdFeHRlbnQgKTtcblx0XHRcdFx0XHRzcXJEaXN0ID0gLSBzMCAqIHMwICsgczEgKiAoIHMxICsgMiAqIGIxICkgKyBjO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHMxIDw9IGV4dERldCApIHtcblxuXHRcdFx0XHRcdC8vIHJlZ2lvbiAzXG5cblx0XHRcdFx0XHRzMCA9IDA7XG5cdFx0XHRcdFx0czEgPSBNYXRoLm1pbiggTWF0aC5tYXgoIC0gc2VnRXh0ZW50LCAtIGIxICksIHNlZ0V4dGVudCApO1xuXHRcdFx0XHRcdHNxckRpc3QgPSBzMSAqICggczEgKyAyICogYjEgKSArIGM7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdC8vIHJlZ2lvbiAyXG5cblx0XHRcdFx0XHRzMCA9IE1hdGgubWF4KCAwLCAtICggYTAxICogc2VnRXh0ZW50ICsgYjAgKSApO1xuXHRcdFx0XHRcdHMxID0gKCBzMCA+IDAgKSA/IHNlZ0V4dGVudCA6IE1hdGgubWluKCBNYXRoLm1heCggLSBzZWdFeHRlbnQsIC0gYjEgKSwgc2VnRXh0ZW50ICk7XG5cdFx0XHRcdFx0c3FyRGlzdCA9IC0gczAgKiBzMCArIHMxICogKCBzMSArIDIgKiBiMSApICsgYztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIFJheSBhbmQgc2VnbWVudCBhcmUgcGFyYWxsZWwuXG5cblx0XHRcdHMxID0gKCBhMDEgPiAwICkgPyAtIHNlZ0V4dGVudCA6IHNlZ0V4dGVudDtcblx0XHRcdHMwID0gTWF0aC5tYXgoIDAsIC0gKCBhMDEgKiBzMSArIGIwICkgKTtcblx0XHRcdHNxckRpc3QgPSAtIHMwICogczAgKyBzMSAqICggczEgKyAyICogYjEgKSArIGM7XG5cblx0XHR9XG5cblx0XHRpZiAoIG9wdGlvbmFsUG9pbnRPblJheSApIHtcblxuXHRcdFx0b3B0aW9uYWxQb2ludE9uUmF5LmNvcHkoIHRoaXMub3JpZ2luICkuYWRkU2NhbGVkVmVjdG9yKCB0aGlzLmRpcmVjdGlvbiwgczAgKTtcblxuXHRcdH1cblxuXHRcdGlmICggb3B0aW9uYWxQb2ludE9uU2VnbWVudCApIHtcblxuXHRcdFx0b3B0aW9uYWxQb2ludE9uU2VnbWVudC5jb3B5KCBfc2VnQ2VudGVyICkuYWRkU2NhbGVkVmVjdG9yKCBfc2VnRGlyLCBzMSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHNxckRpc3Q7XG5cblx0fVxuXG5cdGludGVyc2VjdFNwaGVyZSggc3BoZXJlLCB0YXJnZXQgKSB7XG5cblx0XHRfdmVjdG9yJGEuc3ViVmVjdG9ycyggc3BoZXJlLmNlbnRlciwgdGhpcy5vcmlnaW4gKTtcblx0XHRjb25zdCB0Y2EgPSBfdmVjdG9yJGEuZG90KCB0aGlzLmRpcmVjdGlvbiApO1xuXHRcdGNvbnN0IGQyID0gX3ZlY3RvciRhLmRvdCggX3ZlY3RvciRhICkgLSB0Y2EgKiB0Y2E7XG5cdFx0Y29uc3QgcmFkaXVzMiA9IHNwaGVyZS5yYWRpdXMgKiBzcGhlcmUucmFkaXVzO1xuXG5cdFx0aWYgKCBkMiA+IHJhZGl1czIgKSByZXR1cm4gbnVsbDtcblxuXHRcdGNvbnN0IHRoYyA9IE1hdGguc3FydCggcmFkaXVzMiAtIGQyICk7XG5cblx0XHQvLyB0MCA9IGZpcnN0IGludGVyc2VjdCBwb2ludCAtIGVudHJhbmNlIG9uIGZyb250IG9mIHNwaGVyZVxuXHRcdGNvbnN0IHQwID0gdGNhIC0gdGhjO1xuXG5cdFx0Ly8gdDEgPSBzZWNvbmQgaW50ZXJzZWN0IHBvaW50IC0gZXhpdCBwb2ludCBvbiBiYWNrIG9mIHNwaGVyZVxuXHRcdGNvbnN0IHQxID0gdGNhICsgdGhjO1xuXG5cdFx0Ly8gdGVzdCB0byBzZWUgaWYgdDEgaXMgYmVoaW5kIHRoZSByYXkgLSBpZiBzbywgcmV0dXJuIG51bGxcblx0XHRpZiAoIHQxIDwgMCApIHJldHVybiBudWxsO1xuXG5cdFx0Ly8gdGVzdCB0byBzZWUgaWYgdDAgaXMgYmVoaW5kIHRoZSByYXk6XG5cdFx0Ly8gaWYgaXQgaXMsIHRoZSByYXkgaXMgaW5zaWRlIHRoZSBzcGhlcmUsIHNvIHJldHVybiB0aGUgc2Vjb25kIGV4aXQgcG9pbnQgc2NhbGVkIGJ5IHQxLFxuXHRcdC8vIGluIG9yZGVyIHRvIGFsd2F5cyByZXR1cm4gYW4gaW50ZXJzZWN0IHBvaW50IHRoYXQgaXMgaW4gZnJvbnQgb2YgdGhlIHJheS5cblx0XHRpZiAoIHQwIDwgMCApIHJldHVybiB0aGlzLmF0KCB0MSwgdGFyZ2V0ICk7XG5cblx0XHQvLyBlbHNlIHQwIGlzIGluIGZyb250IG9mIHRoZSByYXksIHNvIHJldHVybiB0aGUgZmlyc3QgY29sbGlzaW9uIHBvaW50IHNjYWxlZCBieSB0MFxuXHRcdHJldHVybiB0aGlzLmF0KCB0MCwgdGFyZ2V0ICk7XG5cblx0fVxuXG5cdGludGVyc2VjdHNTcGhlcmUoIHNwaGVyZSApIHtcblxuXHRcdHJldHVybiB0aGlzLmRpc3RhbmNlU3FUb1BvaW50KCBzcGhlcmUuY2VudGVyICkgPD0gKCBzcGhlcmUucmFkaXVzICogc3BoZXJlLnJhZGl1cyApO1xuXG5cdH1cblxuXHRkaXN0YW5jZVRvUGxhbmUoIHBsYW5lICkge1xuXG5cdFx0Y29uc3QgZGVub21pbmF0b3IgPSBwbGFuZS5ub3JtYWwuZG90KCB0aGlzLmRpcmVjdGlvbiApO1xuXG5cdFx0aWYgKCBkZW5vbWluYXRvciA9PT0gMCApIHtcblxuXHRcdFx0Ly8gbGluZSBpcyBjb3BsYW5hciwgcmV0dXJuIG9yaWdpblxuXHRcdFx0aWYgKCBwbGFuZS5kaXN0YW5jZVRvUG9pbnQoIHRoaXMub3JpZ2luICkgPT09IDAgKSB7XG5cblx0XHRcdFx0cmV0dXJuIDA7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gTnVsbCBpcyBwcmVmZXJhYmxlIHRvIHVuZGVmaW5lZCBzaW5jZSB1bmRlZmluZWQgbWVhbnMuLi4uIGl0IGlzIHVuZGVmaW5lZFxuXG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHQgPSAtICggdGhpcy5vcmlnaW4uZG90KCBwbGFuZS5ub3JtYWwgKSArIHBsYW5lLmNvbnN0YW50ICkgLyBkZW5vbWluYXRvcjtcblxuXHRcdC8vIFJldHVybiBpZiB0aGUgcmF5IG5ldmVyIGludGVyc2VjdHMgdGhlIHBsYW5lXG5cblx0XHRyZXR1cm4gdCA+PSAwID8gdCA6IG51bGw7XG5cblx0fVxuXG5cdGludGVyc2VjdFBsYW5lKCBwbGFuZSwgdGFyZ2V0ICkge1xuXG5cdFx0Y29uc3QgdCA9IHRoaXMuZGlzdGFuY2VUb1BsYW5lKCBwbGFuZSApO1xuXG5cdFx0aWYgKCB0ID09PSBudWxsICkge1xuXG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmF0KCB0LCB0YXJnZXQgKTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c1BsYW5lKCBwbGFuZSApIHtcblxuXHRcdC8vIGNoZWNrIGlmIHRoZSByYXkgbGllcyBvbiB0aGUgcGxhbmUgZmlyc3RcblxuXHRcdGNvbnN0IGRpc3RUb1BvaW50ID0gcGxhbmUuZGlzdGFuY2VUb1BvaW50KCB0aGlzLm9yaWdpbiApO1xuXG5cdFx0aWYgKCBkaXN0VG9Qb2ludCA9PT0gMCApIHtcblxuXHRcdFx0cmV0dXJuIHRydWU7XG5cblx0XHR9XG5cblx0XHRjb25zdCBkZW5vbWluYXRvciA9IHBsYW5lLm5vcm1hbC5kb3QoIHRoaXMuZGlyZWN0aW9uICk7XG5cblx0XHRpZiAoIGRlbm9taW5hdG9yICogZGlzdFRvUG9pbnQgPCAwICkge1xuXG5cdFx0XHRyZXR1cm4gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdC8vIHJheSBvcmlnaW4gaXMgYmVoaW5kIHRoZSBwbGFuZSAoYW5kIGlzIHBvaW50aW5nIGJlaGluZCBpdClcblxuXHRcdHJldHVybiBmYWxzZTtcblxuXHR9XG5cblx0aW50ZXJzZWN0Qm94KCBib3gsIHRhcmdldCApIHtcblxuXHRcdGxldCB0bWluLCB0bWF4LCB0eW1pbiwgdHltYXgsIHR6bWluLCB0em1heDtcblxuXHRcdGNvbnN0IGludmRpcnggPSAxIC8gdGhpcy5kaXJlY3Rpb24ueCxcblx0XHRcdGludmRpcnkgPSAxIC8gdGhpcy5kaXJlY3Rpb24ueSxcblx0XHRcdGludmRpcnogPSAxIC8gdGhpcy5kaXJlY3Rpb24uejtcblxuXHRcdGNvbnN0IG9yaWdpbiA9IHRoaXMub3JpZ2luO1xuXG5cdFx0aWYgKCBpbnZkaXJ4ID49IDAgKSB7XG5cblx0XHRcdHRtaW4gPSAoIGJveC5taW4ueCAtIG9yaWdpbi54ICkgKiBpbnZkaXJ4O1xuXHRcdFx0dG1heCA9ICggYm94Lm1heC54IC0gb3JpZ2luLnggKSAqIGludmRpcng7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0bWluID0gKCBib3gubWF4LnggLSBvcmlnaW4ueCApICogaW52ZGlyeDtcblx0XHRcdHRtYXggPSAoIGJveC5taW4ueCAtIG9yaWdpbi54ICkgKiBpbnZkaXJ4O1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBpbnZkaXJ5ID49IDAgKSB7XG5cblx0XHRcdHR5bWluID0gKCBib3gubWluLnkgLSBvcmlnaW4ueSApICogaW52ZGlyeTtcblx0XHRcdHR5bWF4ID0gKCBib3gubWF4LnkgLSBvcmlnaW4ueSApICogaW52ZGlyeTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHR5bWluID0gKCBib3gubWF4LnkgLSBvcmlnaW4ueSApICogaW52ZGlyeTtcblx0XHRcdHR5bWF4ID0gKCBib3gubWluLnkgLSBvcmlnaW4ueSApICogaW52ZGlyeTtcblxuXHRcdH1cblxuXHRcdGlmICggKCB0bWluID4gdHltYXggKSB8fCAoIHR5bWluID4gdG1heCApICkgcmV0dXJuIG51bGw7XG5cblx0XHRpZiAoIHR5bWluID4gdG1pbiB8fCBpc05hTiggdG1pbiApICkgdG1pbiA9IHR5bWluO1xuXG5cdFx0aWYgKCB0eW1heCA8IHRtYXggfHwgaXNOYU4oIHRtYXggKSApIHRtYXggPSB0eW1heDtcblxuXHRcdGlmICggaW52ZGlyeiA+PSAwICkge1xuXG5cdFx0XHR0em1pbiA9ICggYm94Lm1pbi56IC0gb3JpZ2luLnogKSAqIGludmRpcno7XG5cdFx0XHR0em1heCA9ICggYm94Lm1heC56IC0gb3JpZ2luLnogKSAqIGludmRpcno7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0em1pbiA9ICggYm94Lm1heC56IC0gb3JpZ2luLnogKSAqIGludmRpcno7XG5cdFx0XHR0em1heCA9ICggYm94Lm1pbi56IC0gb3JpZ2luLnogKSAqIGludmRpcno7XG5cblx0XHR9XG5cblx0XHRpZiAoICggdG1pbiA+IHR6bWF4ICkgfHwgKCB0em1pbiA+IHRtYXggKSApIHJldHVybiBudWxsO1xuXG5cdFx0aWYgKCB0em1pbiA+IHRtaW4gfHwgdG1pbiAhPT0gdG1pbiApIHRtaW4gPSB0em1pbjtcblxuXHRcdGlmICggdHptYXggPCB0bWF4IHx8IHRtYXggIT09IHRtYXggKSB0bWF4ID0gdHptYXg7XG5cblx0XHQvL3JldHVybiBwb2ludCBjbG9zZXN0IHRvIHRoZSByYXkgKHBvc2l0aXZlIHNpZGUpXG5cblx0XHRpZiAoIHRtYXggPCAwICkgcmV0dXJuIG51bGw7XG5cblx0XHRyZXR1cm4gdGhpcy5hdCggdG1pbiA+PSAwID8gdG1pbiA6IHRtYXgsIHRhcmdldCApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzQm94KCBib3ggKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5pbnRlcnNlY3RCb3goIGJveCwgX3ZlY3RvciRhICkgIT09IG51bGw7XG5cblx0fVxuXG5cdGludGVyc2VjdFRyaWFuZ2xlKCBhLCBiLCBjLCBiYWNrZmFjZUN1bGxpbmcsIHRhcmdldCApIHtcblxuXHRcdC8vIENvbXB1dGUgdGhlIG9mZnNldCBvcmlnaW4sIGVkZ2VzLCBhbmQgbm9ybWFsLlxuXG5cdFx0Ly8gZnJvbSBodHRwczovL2dpdGh1Yi5jb20vcG1qb25pYWsvR2VvbWV0cmljVG9vbHMvYmxvYi9tYXN0ZXIvR1RFbmdpbmUvSW5jbHVkZS9NYXRoZW1hdGljcy9HdGVJbnRyUmF5M1RyaWFuZ2xlMy5oXG5cblx0XHRfZWRnZTEuc3ViVmVjdG9ycyggYiwgYSApO1xuXHRcdF9lZGdlMi5zdWJWZWN0b3JzKCBjLCBhICk7XG5cdFx0X25vcm1hbCQxLmNyb3NzVmVjdG9ycyggX2VkZ2UxLCBfZWRnZTIgKTtcblxuXHRcdC8vIFNvbHZlIFEgKyB0KkQgPSBiMSpFMSArIGIyKkUyIChRID0ga0RpZmYsIEQgPSByYXkgZGlyZWN0aW9uLFxuXHRcdC8vIEUxID0ga0VkZ2UxLCBFMiA9IGtFZGdlMiwgTiA9IENyb3NzKEUxLEUyKSkgYnlcblx0XHQvLyAgIHxEb3QoRCxOKXwqYjEgPSBzaWduKERvdChELE4pKSpEb3QoRCxDcm9zcyhRLEUyKSlcblx0XHQvLyAgIHxEb3QoRCxOKXwqYjIgPSBzaWduKERvdChELE4pKSpEb3QoRCxDcm9zcyhFMSxRKSlcblx0XHQvLyAgIHxEb3QoRCxOKXwqdCA9IC1zaWduKERvdChELE4pKSpEb3QoUSxOKVxuXHRcdGxldCBEZE4gPSB0aGlzLmRpcmVjdGlvbi5kb3QoIF9ub3JtYWwkMSApO1xuXHRcdGxldCBzaWduO1xuXG5cdFx0aWYgKCBEZE4gPiAwICkge1xuXG5cdFx0XHRpZiAoIGJhY2tmYWNlQ3VsbGluZyApIHJldHVybiBudWxsO1xuXHRcdFx0c2lnbiA9IDE7XG5cblx0XHR9IGVsc2UgaWYgKCBEZE4gPCAwICkge1xuXG5cdFx0XHRzaWduID0gLSAxO1xuXHRcdFx0RGROID0gLSBEZE47XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdF9kaWZmLnN1YlZlY3RvcnMoIHRoaXMub3JpZ2luLCBhICk7XG5cdFx0Y29uc3QgRGRReEUyID0gc2lnbiAqIHRoaXMuZGlyZWN0aW9uLmRvdCggX2VkZ2UyLmNyb3NzVmVjdG9ycyggX2RpZmYsIF9lZGdlMiApICk7XG5cblx0XHQvLyBiMSA8IDAsIG5vIGludGVyc2VjdGlvblxuXHRcdGlmICggRGRReEUyIDwgMCApIHtcblxuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9XG5cblx0XHRjb25zdCBEZEUxeFEgPSBzaWduICogdGhpcy5kaXJlY3Rpb24uZG90KCBfZWRnZTEuY3Jvc3MoIF9kaWZmICkgKTtcblxuXHRcdC8vIGIyIDwgMCwgbm8gaW50ZXJzZWN0aW9uXG5cdFx0aWYgKCBEZEUxeFEgPCAwICkge1xuXG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdC8vIGIxK2IyID4gMSwgbm8gaW50ZXJzZWN0aW9uXG5cdFx0aWYgKCBEZFF4RTIgKyBEZEUxeFEgPiBEZE4gKSB7XG5cblx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0fVxuXG5cdFx0Ly8gTGluZSBpbnRlcnNlY3RzIHRyaWFuZ2xlLCBjaGVjayBpZiByYXkgZG9lcy5cblx0XHRjb25zdCBRZE4gPSAtIHNpZ24gKiBfZGlmZi5kb3QoIF9ub3JtYWwkMSApO1xuXG5cdFx0Ly8gdCA8IDAsIG5vIGludGVyc2VjdGlvblxuXHRcdGlmICggUWROIDwgMCApIHtcblxuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9XG5cblx0XHQvLyBSYXkgaW50ZXJzZWN0cyB0cmlhbmdsZS5cblx0XHRyZXR1cm4gdGhpcy5hdCggUWROIC8gRGROLCB0YXJnZXQgKTtcblxuXHR9XG5cblx0YXBwbHlNYXRyaXg0KCBtYXRyaXg0ICkge1xuXG5cdFx0dGhpcy5vcmlnaW4uYXBwbHlNYXRyaXg0KCBtYXRyaXg0ICk7XG5cdFx0dGhpcy5kaXJlY3Rpb24udHJhbnNmb3JtRGlyZWN0aW9uKCBtYXRyaXg0ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXF1YWxzKCByYXkgKSB7XG5cblx0XHRyZXR1cm4gcmF5Lm9yaWdpbi5lcXVhbHMoIHRoaXMub3JpZ2luICkgJiYgcmF5LmRpcmVjdGlvbi5lcXVhbHMoIHRoaXMuZGlyZWN0aW9uICk7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBNYXRyaXg0IHtcblxuXHRjb25zdHJ1Y3RvciggbjExLCBuMTIsIG4xMywgbjE0LCBuMjEsIG4yMiwgbjIzLCBuMjQsIG4zMSwgbjMyLCBuMzMsIG4zNCwgbjQxLCBuNDIsIG40MywgbjQ0ICkge1xuXG5cdFx0TWF0cml4NC5wcm90b3R5cGUuaXNNYXRyaXg0ID0gdHJ1ZTtcblxuXHRcdHRoaXMuZWxlbWVudHMgPSBbXG5cblx0XHRcdDEsIDAsIDAsIDAsXG5cdFx0XHQwLCAxLCAwLCAwLFxuXHRcdFx0MCwgMCwgMSwgMCxcblx0XHRcdDAsIDAsIDAsIDFcblxuXHRcdF07XG5cblx0XHRpZiAoIG4xMSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLnNldCggbjExLCBuMTIsIG4xMywgbjE0LCBuMjEsIG4yMiwgbjIzLCBuMjQsIG4zMSwgbjMyLCBuMzMsIG4zNCwgbjQxLCBuNDIsIG40MywgbjQ0ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHNldCggbjExLCBuMTIsIG4xMywgbjE0LCBuMjEsIG4yMiwgbjIzLCBuMjQsIG4zMSwgbjMyLCBuMzMsIG4zNCwgbjQxLCBuNDIsIG40MywgbjQ0ICkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0dGVbIDAgXSA9IG4xMTsgdGVbIDQgXSA9IG4xMjsgdGVbIDggXSA9IG4xMzsgdGVbIDEyIF0gPSBuMTQ7XG5cdFx0dGVbIDEgXSA9IG4yMTsgdGVbIDUgXSA9IG4yMjsgdGVbIDkgXSA9IG4yMzsgdGVbIDEzIF0gPSBuMjQ7XG5cdFx0dGVbIDIgXSA9IG4zMTsgdGVbIDYgXSA9IG4zMjsgdGVbIDEwIF0gPSBuMzM7IHRlWyAxNCBdID0gbjM0O1xuXHRcdHRlWyAzIF0gPSBuNDE7IHRlWyA3IF0gPSBuNDI7IHRlWyAxMSBdID0gbjQzOyB0ZVsgMTUgXSA9IG40NDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRpZGVudGl0eSgpIHtcblxuXHRcdHRoaXMuc2V0KFxuXG5cdFx0XHQxLCAwLCAwLCAwLFxuXHRcdFx0MCwgMSwgMCwgMCxcblx0XHRcdDAsIDAsIDEsIDAsXG5cdFx0XHQwLCAwLCAwLCAxXG5cblx0XHQpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyBNYXRyaXg0KCkuZnJvbUFycmF5KCB0aGlzLmVsZW1lbnRzICk7XG5cblx0fVxuXG5cdGNvcHkoIG0gKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cdFx0Y29uc3QgbWUgPSBtLmVsZW1lbnRzO1xuXG5cdFx0dGVbIDAgXSA9IG1lWyAwIF07IHRlWyAxIF0gPSBtZVsgMSBdOyB0ZVsgMiBdID0gbWVbIDIgXTsgdGVbIDMgXSA9IG1lWyAzIF07XG5cdFx0dGVbIDQgXSA9IG1lWyA0IF07IHRlWyA1IF0gPSBtZVsgNSBdOyB0ZVsgNiBdID0gbWVbIDYgXTsgdGVbIDcgXSA9IG1lWyA3IF07XG5cdFx0dGVbIDggXSA9IG1lWyA4IF07IHRlWyA5IF0gPSBtZVsgOSBdOyB0ZVsgMTAgXSA9IG1lWyAxMCBdOyB0ZVsgMTEgXSA9IG1lWyAxMSBdO1xuXHRcdHRlWyAxMiBdID0gbWVbIDEyIF07IHRlWyAxMyBdID0gbWVbIDEzIF07IHRlWyAxNCBdID0gbWVbIDE0IF07IHRlWyAxNSBdID0gbWVbIDE1IF07XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weVBvc2l0aW9uKCBtICkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzLCBtZSA9IG0uZWxlbWVudHM7XG5cblx0XHR0ZVsgMTIgXSA9IG1lWyAxMiBdO1xuXHRcdHRlWyAxMyBdID0gbWVbIDEzIF07XG5cdFx0dGVbIDE0IF0gPSBtZVsgMTQgXTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tTWF0cml4MyggbSApIHtcblxuXHRcdGNvbnN0IG1lID0gbS5lbGVtZW50cztcblxuXHRcdHRoaXMuc2V0KFxuXG5cdFx0XHRtZVsgMCBdLCBtZVsgMyBdLCBtZVsgNiBdLCAwLFxuXHRcdFx0bWVbIDEgXSwgbWVbIDQgXSwgbWVbIDcgXSwgMCxcblx0XHRcdG1lWyAyIF0sIG1lWyA1IF0sIG1lWyA4IF0sIDAsXG5cdFx0XHQwLCAwLCAwLCAxXG5cblx0XHQpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGV4dHJhY3RCYXNpcyggeEF4aXMsIHlBeGlzLCB6QXhpcyApIHtcblxuXHRcdHhBeGlzLnNldEZyb21NYXRyaXhDb2x1bW4oIHRoaXMsIDAgKTtcblx0XHR5QXhpcy5zZXRGcm9tTWF0cml4Q29sdW1uKCB0aGlzLCAxICk7XG5cdFx0ekF4aXMuc2V0RnJvbU1hdHJpeENvbHVtbiggdGhpcywgMiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1ha2VCYXNpcyggeEF4aXMsIHlBeGlzLCB6QXhpcyApIHtcblxuXHRcdHRoaXMuc2V0KFxuXHRcdFx0eEF4aXMueCwgeUF4aXMueCwgekF4aXMueCwgMCxcblx0XHRcdHhBeGlzLnksIHlBeGlzLnksIHpBeGlzLnksIDAsXG5cdFx0XHR4QXhpcy56LCB5QXhpcy56LCB6QXhpcy56LCAwLFxuXHRcdFx0MCwgMCwgMCwgMVxuXHRcdCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXh0cmFjdFJvdGF0aW9uKCBtICkge1xuXG5cdFx0Ly8gdGhpcyBtZXRob2QgZG9lcyBub3Qgc3VwcG9ydCByZWZsZWN0aW9uIG1hdHJpY2VzXG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cdFx0Y29uc3QgbWUgPSBtLmVsZW1lbnRzO1xuXG5cdFx0Y29uc3Qgc2NhbGVYID0gMSAvIF92MSQ1LnNldEZyb21NYXRyaXhDb2x1bW4oIG0sIDAgKS5sZW5ndGgoKTtcblx0XHRjb25zdCBzY2FsZVkgPSAxIC8gX3YxJDUuc2V0RnJvbU1hdHJpeENvbHVtbiggbSwgMSApLmxlbmd0aCgpO1xuXHRcdGNvbnN0IHNjYWxlWiA9IDEgLyBfdjEkNS5zZXRGcm9tTWF0cml4Q29sdW1uKCBtLCAyICkubGVuZ3RoKCk7XG5cblx0XHR0ZVsgMCBdID0gbWVbIDAgXSAqIHNjYWxlWDtcblx0XHR0ZVsgMSBdID0gbWVbIDEgXSAqIHNjYWxlWDtcblx0XHR0ZVsgMiBdID0gbWVbIDIgXSAqIHNjYWxlWDtcblx0XHR0ZVsgMyBdID0gMDtcblxuXHRcdHRlWyA0IF0gPSBtZVsgNCBdICogc2NhbGVZO1xuXHRcdHRlWyA1IF0gPSBtZVsgNSBdICogc2NhbGVZO1xuXHRcdHRlWyA2IF0gPSBtZVsgNiBdICogc2NhbGVZO1xuXHRcdHRlWyA3IF0gPSAwO1xuXG5cdFx0dGVbIDggXSA9IG1lWyA4IF0gKiBzY2FsZVo7XG5cdFx0dGVbIDkgXSA9IG1lWyA5IF0gKiBzY2FsZVo7XG5cdFx0dGVbIDEwIF0gPSBtZVsgMTAgXSAqIHNjYWxlWjtcblx0XHR0ZVsgMTEgXSA9IDA7XG5cblx0XHR0ZVsgMTIgXSA9IDA7XG5cdFx0dGVbIDEzIF0gPSAwO1xuXHRcdHRlWyAxNCBdID0gMDtcblx0XHR0ZVsgMTUgXSA9IDE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bWFrZVJvdGF0aW9uRnJvbUV1bGVyKCBldWxlciApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdGNvbnN0IHggPSBldWxlci54LCB5ID0gZXVsZXIueSwgeiA9IGV1bGVyLno7XG5cdFx0Y29uc3QgYSA9IE1hdGguY29zKCB4ICksIGIgPSBNYXRoLnNpbiggeCApO1xuXHRcdGNvbnN0IGMgPSBNYXRoLmNvcyggeSApLCBkID0gTWF0aC5zaW4oIHkgKTtcblx0XHRjb25zdCBlID0gTWF0aC5jb3MoIHogKSwgZiA9IE1hdGguc2luKCB6ICk7XG5cblx0XHRpZiAoIGV1bGVyLm9yZGVyID09PSAnWFlaJyApIHtcblxuXHRcdFx0Y29uc3QgYWUgPSBhICogZSwgYWYgPSBhICogZiwgYmUgPSBiICogZSwgYmYgPSBiICogZjtcblxuXHRcdFx0dGVbIDAgXSA9IGMgKiBlO1xuXHRcdFx0dGVbIDQgXSA9IC0gYyAqIGY7XG5cdFx0XHR0ZVsgOCBdID0gZDtcblxuXHRcdFx0dGVbIDEgXSA9IGFmICsgYmUgKiBkO1xuXHRcdFx0dGVbIDUgXSA9IGFlIC0gYmYgKiBkO1xuXHRcdFx0dGVbIDkgXSA9IC0gYiAqIGM7XG5cblx0XHRcdHRlWyAyIF0gPSBiZiAtIGFlICogZDtcblx0XHRcdHRlWyA2IF0gPSBiZSArIGFmICogZDtcblx0XHRcdHRlWyAxMCBdID0gYSAqIGM7XG5cblx0XHR9IGVsc2UgaWYgKCBldWxlci5vcmRlciA9PT0gJ1lYWicgKSB7XG5cblx0XHRcdGNvbnN0IGNlID0gYyAqIGUsIGNmID0gYyAqIGYsIGRlID0gZCAqIGUsIGRmID0gZCAqIGY7XG5cblx0XHRcdHRlWyAwIF0gPSBjZSArIGRmICogYjtcblx0XHRcdHRlWyA0IF0gPSBkZSAqIGIgLSBjZjtcblx0XHRcdHRlWyA4IF0gPSBhICogZDtcblxuXHRcdFx0dGVbIDEgXSA9IGEgKiBmO1xuXHRcdFx0dGVbIDUgXSA9IGEgKiBlO1xuXHRcdFx0dGVbIDkgXSA9IC0gYjtcblxuXHRcdFx0dGVbIDIgXSA9IGNmICogYiAtIGRlO1xuXHRcdFx0dGVbIDYgXSA9IGRmICsgY2UgKiBiO1xuXHRcdFx0dGVbIDEwIF0gPSBhICogYztcblxuXHRcdH0gZWxzZSBpZiAoIGV1bGVyLm9yZGVyID09PSAnWlhZJyApIHtcblxuXHRcdFx0Y29uc3QgY2UgPSBjICogZSwgY2YgPSBjICogZiwgZGUgPSBkICogZSwgZGYgPSBkICogZjtcblxuXHRcdFx0dGVbIDAgXSA9IGNlIC0gZGYgKiBiO1xuXHRcdFx0dGVbIDQgXSA9IC0gYSAqIGY7XG5cdFx0XHR0ZVsgOCBdID0gZGUgKyBjZiAqIGI7XG5cblx0XHRcdHRlWyAxIF0gPSBjZiArIGRlICogYjtcblx0XHRcdHRlWyA1IF0gPSBhICogZTtcblx0XHRcdHRlWyA5IF0gPSBkZiAtIGNlICogYjtcblxuXHRcdFx0dGVbIDIgXSA9IC0gYSAqIGQ7XG5cdFx0XHR0ZVsgNiBdID0gYjtcblx0XHRcdHRlWyAxMCBdID0gYSAqIGM7XG5cblx0XHR9IGVsc2UgaWYgKCBldWxlci5vcmRlciA9PT0gJ1pZWCcgKSB7XG5cblx0XHRcdGNvbnN0IGFlID0gYSAqIGUsIGFmID0gYSAqIGYsIGJlID0gYiAqIGUsIGJmID0gYiAqIGY7XG5cblx0XHRcdHRlWyAwIF0gPSBjICogZTtcblx0XHRcdHRlWyA0IF0gPSBiZSAqIGQgLSBhZjtcblx0XHRcdHRlWyA4IF0gPSBhZSAqIGQgKyBiZjtcblxuXHRcdFx0dGVbIDEgXSA9IGMgKiBmO1xuXHRcdFx0dGVbIDUgXSA9IGJmICogZCArIGFlO1xuXHRcdFx0dGVbIDkgXSA9IGFmICogZCAtIGJlO1xuXG5cdFx0XHR0ZVsgMiBdID0gLSBkO1xuXHRcdFx0dGVbIDYgXSA9IGIgKiBjO1xuXHRcdFx0dGVbIDEwIF0gPSBhICogYztcblxuXHRcdH0gZWxzZSBpZiAoIGV1bGVyLm9yZGVyID09PSAnWVpYJyApIHtcblxuXHRcdFx0Y29uc3QgYWMgPSBhICogYywgYWQgPSBhICogZCwgYmMgPSBiICogYywgYmQgPSBiICogZDtcblxuXHRcdFx0dGVbIDAgXSA9IGMgKiBlO1xuXHRcdFx0dGVbIDQgXSA9IGJkIC0gYWMgKiBmO1xuXHRcdFx0dGVbIDggXSA9IGJjICogZiArIGFkO1xuXG5cdFx0XHR0ZVsgMSBdID0gZjtcblx0XHRcdHRlWyA1IF0gPSBhICogZTtcblx0XHRcdHRlWyA5IF0gPSAtIGIgKiBlO1xuXG5cdFx0XHR0ZVsgMiBdID0gLSBkICogZTtcblx0XHRcdHRlWyA2IF0gPSBhZCAqIGYgKyBiYztcblx0XHRcdHRlWyAxMCBdID0gYWMgLSBiZCAqIGY7XG5cblx0XHR9IGVsc2UgaWYgKCBldWxlci5vcmRlciA9PT0gJ1haWScgKSB7XG5cblx0XHRcdGNvbnN0IGFjID0gYSAqIGMsIGFkID0gYSAqIGQsIGJjID0gYiAqIGMsIGJkID0gYiAqIGQ7XG5cblx0XHRcdHRlWyAwIF0gPSBjICogZTtcblx0XHRcdHRlWyA0IF0gPSAtIGY7XG5cdFx0XHR0ZVsgOCBdID0gZCAqIGU7XG5cblx0XHRcdHRlWyAxIF0gPSBhYyAqIGYgKyBiZDtcblx0XHRcdHRlWyA1IF0gPSBhICogZTtcblx0XHRcdHRlWyA5IF0gPSBhZCAqIGYgLSBiYztcblxuXHRcdFx0dGVbIDIgXSA9IGJjICogZiAtIGFkO1xuXHRcdFx0dGVbIDYgXSA9IGIgKiBlO1xuXHRcdFx0dGVbIDEwIF0gPSBiZCAqIGYgKyBhYztcblxuXHRcdH1cblxuXHRcdC8vIGJvdHRvbSByb3dcblx0XHR0ZVsgMyBdID0gMDtcblx0XHR0ZVsgNyBdID0gMDtcblx0XHR0ZVsgMTEgXSA9IDA7XG5cblx0XHQvLyBsYXN0IGNvbHVtblxuXHRcdHRlWyAxMiBdID0gMDtcblx0XHR0ZVsgMTMgXSA9IDA7XG5cdFx0dGVbIDE0IF0gPSAwO1xuXHRcdHRlWyAxNSBdID0gMTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlUm90YXRpb25Gcm9tUXVhdGVybmlvbiggcSApIHtcblxuXHRcdHJldHVybiB0aGlzLmNvbXBvc2UoIF96ZXJvLCBxLCBfb25lICk7XG5cblx0fVxuXG5cdGxvb2tBdCggZXllLCB0YXJnZXQsIHVwICkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0X3ouc3ViVmVjdG9ycyggZXllLCB0YXJnZXQgKTtcblxuXHRcdGlmICggX3oubGVuZ3RoU3EoKSA9PT0gMCApIHtcblxuXHRcdFx0Ly8gZXllIGFuZCB0YXJnZXQgYXJlIGluIHRoZSBzYW1lIHBvc2l0aW9uXG5cblx0XHRcdF96LnogPSAxO1xuXG5cdFx0fVxuXG5cdFx0X3oubm9ybWFsaXplKCk7XG5cdFx0X3guY3Jvc3NWZWN0b3JzKCB1cCwgX3ogKTtcblxuXHRcdGlmICggX3gubGVuZ3RoU3EoKSA9PT0gMCApIHtcblxuXHRcdFx0Ly8gdXAgYW5kIHogYXJlIHBhcmFsbGVsXG5cblx0XHRcdGlmICggTWF0aC5hYnMoIHVwLnogKSA9PT0gMSApIHtcblxuXHRcdFx0XHRfei54ICs9IDAuMDAwMTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRfei56ICs9IDAuMDAwMTtcblxuXHRcdFx0fVxuXG5cdFx0XHRfei5ub3JtYWxpemUoKTtcblx0XHRcdF94LmNyb3NzVmVjdG9ycyggdXAsIF96ICk7XG5cblx0XHR9XG5cblx0XHRfeC5ub3JtYWxpemUoKTtcblx0XHRfeS5jcm9zc1ZlY3RvcnMoIF96LCBfeCApO1xuXG5cdFx0dGVbIDAgXSA9IF94Lng7IHRlWyA0IF0gPSBfeS54OyB0ZVsgOCBdID0gX3oueDtcblx0XHR0ZVsgMSBdID0gX3gueTsgdGVbIDUgXSA9IF95Lnk7IHRlWyA5IF0gPSBfei55O1xuXHRcdHRlWyAyIF0gPSBfeC56OyB0ZVsgNiBdID0gX3kuejsgdGVbIDEwIF0gPSBfei56O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5KCBtICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubXVsdGlwbHlNYXRyaWNlcyggdGhpcywgbSApO1xuXG5cdH1cblxuXHRwcmVtdWx0aXBseSggbSApIHtcblxuXHRcdHJldHVybiB0aGlzLm11bHRpcGx5TWF0cmljZXMoIG0sIHRoaXMgKTtcblxuXHR9XG5cblx0bXVsdGlwbHlNYXRyaWNlcyggYSwgYiApIHtcblxuXHRcdGNvbnN0IGFlID0gYS5lbGVtZW50cztcblx0XHRjb25zdCBiZSA9IGIuZWxlbWVudHM7XG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0Y29uc3QgYTExID0gYWVbIDAgXSwgYTEyID0gYWVbIDQgXSwgYTEzID0gYWVbIDggXSwgYTE0ID0gYWVbIDEyIF07XG5cdFx0Y29uc3QgYTIxID0gYWVbIDEgXSwgYTIyID0gYWVbIDUgXSwgYTIzID0gYWVbIDkgXSwgYTI0ID0gYWVbIDEzIF07XG5cdFx0Y29uc3QgYTMxID0gYWVbIDIgXSwgYTMyID0gYWVbIDYgXSwgYTMzID0gYWVbIDEwIF0sIGEzNCA9IGFlWyAxNCBdO1xuXHRcdGNvbnN0IGE0MSA9IGFlWyAzIF0sIGE0MiA9IGFlWyA3IF0sIGE0MyA9IGFlWyAxMSBdLCBhNDQgPSBhZVsgMTUgXTtcblxuXHRcdGNvbnN0IGIxMSA9IGJlWyAwIF0sIGIxMiA9IGJlWyA0IF0sIGIxMyA9IGJlWyA4IF0sIGIxNCA9IGJlWyAxMiBdO1xuXHRcdGNvbnN0IGIyMSA9IGJlWyAxIF0sIGIyMiA9IGJlWyA1IF0sIGIyMyA9IGJlWyA5IF0sIGIyNCA9IGJlWyAxMyBdO1xuXHRcdGNvbnN0IGIzMSA9IGJlWyAyIF0sIGIzMiA9IGJlWyA2IF0sIGIzMyA9IGJlWyAxMCBdLCBiMzQgPSBiZVsgMTQgXTtcblx0XHRjb25zdCBiNDEgPSBiZVsgMyBdLCBiNDIgPSBiZVsgNyBdLCBiNDMgPSBiZVsgMTEgXSwgYjQ0ID0gYmVbIDE1IF07XG5cblx0XHR0ZVsgMCBdID0gYTExICogYjExICsgYTEyICogYjIxICsgYTEzICogYjMxICsgYTE0ICogYjQxO1xuXHRcdHRlWyA0IF0gPSBhMTEgKiBiMTIgKyBhMTIgKiBiMjIgKyBhMTMgKiBiMzIgKyBhMTQgKiBiNDI7XG5cdFx0dGVbIDggXSA9IGExMSAqIGIxMyArIGExMiAqIGIyMyArIGExMyAqIGIzMyArIGExNCAqIGI0Mztcblx0XHR0ZVsgMTIgXSA9IGExMSAqIGIxNCArIGExMiAqIGIyNCArIGExMyAqIGIzNCArIGExNCAqIGI0NDtcblxuXHRcdHRlWyAxIF0gPSBhMjEgKiBiMTEgKyBhMjIgKiBiMjEgKyBhMjMgKiBiMzEgKyBhMjQgKiBiNDE7XG5cdFx0dGVbIDUgXSA9IGEyMSAqIGIxMiArIGEyMiAqIGIyMiArIGEyMyAqIGIzMiArIGEyNCAqIGI0Mjtcblx0XHR0ZVsgOSBdID0gYTIxICogYjEzICsgYTIyICogYjIzICsgYTIzICogYjMzICsgYTI0ICogYjQzO1xuXHRcdHRlWyAxMyBdID0gYTIxICogYjE0ICsgYTIyICogYjI0ICsgYTIzICogYjM0ICsgYTI0ICogYjQ0O1xuXG5cdFx0dGVbIDIgXSA9IGEzMSAqIGIxMSArIGEzMiAqIGIyMSArIGEzMyAqIGIzMSArIGEzNCAqIGI0MTtcblx0XHR0ZVsgNiBdID0gYTMxICogYjEyICsgYTMyICogYjIyICsgYTMzICogYjMyICsgYTM0ICogYjQyO1xuXHRcdHRlWyAxMCBdID0gYTMxICogYjEzICsgYTMyICogYjIzICsgYTMzICogYjMzICsgYTM0ICogYjQzO1xuXHRcdHRlWyAxNCBdID0gYTMxICogYjE0ICsgYTMyICogYjI0ICsgYTMzICogYjM0ICsgYTM0ICogYjQ0O1xuXG5cdFx0dGVbIDMgXSA9IGE0MSAqIGIxMSArIGE0MiAqIGIyMSArIGE0MyAqIGIzMSArIGE0NCAqIGI0MTtcblx0XHR0ZVsgNyBdID0gYTQxICogYjEyICsgYTQyICogYjIyICsgYTQzICogYjMyICsgYTQ0ICogYjQyO1xuXHRcdHRlWyAxMSBdID0gYTQxICogYjEzICsgYTQyICogYjIzICsgYTQzICogYjMzICsgYTQ0ICogYjQzO1xuXHRcdHRlWyAxNSBdID0gYTQxICogYjE0ICsgYTQyICogYjI0ICsgYTQzICogYjM0ICsgYTQ0ICogYjQ0O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5U2NhbGFyKCBzICkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0dGVbIDAgXSAqPSBzOyB0ZVsgNCBdICo9IHM7IHRlWyA4IF0gKj0gczsgdGVbIDEyIF0gKj0gcztcblx0XHR0ZVsgMSBdICo9IHM7IHRlWyA1IF0gKj0gczsgdGVbIDkgXSAqPSBzOyB0ZVsgMTMgXSAqPSBzO1xuXHRcdHRlWyAyIF0gKj0gczsgdGVbIDYgXSAqPSBzOyB0ZVsgMTAgXSAqPSBzOyB0ZVsgMTQgXSAqPSBzO1xuXHRcdHRlWyAzIF0gKj0gczsgdGVbIDcgXSAqPSBzOyB0ZVsgMTEgXSAqPSBzOyB0ZVsgMTUgXSAqPSBzO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRldGVybWluYW50KCkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0Y29uc3QgbjExID0gdGVbIDAgXSwgbjEyID0gdGVbIDQgXSwgbjEzID0gdGVbIDggXSwgbjE0ID0gdGVbIDEyIF07XG5cdFx0Y29uc3QgbjIxID0gdGVbIDEgXSwgbjIyID0gdGVbIDUgXSwgbjIzID0gdGVbIDkgXSwgbjI0ID0gdGVbIDEzIF07XG5cdFx0Y29uc3QgbjMxID0gdGVbIDIgXSwgbjMyID0gdGVbIDYgXSwgbjMzID0gdGVbIDEwIF0sIG4zNCA9IHRlWyAxNCBdO1xuXHRcdGNvbnN0IG40MSA9IHRlWyAzIF0sIG40MiA9IHRlWyA3IF0sIG40MyA9IHRlWyAxMSBdLCBuNDQgPSB0ZVsgMTUgXTtcblxuXHRcdC8vVE9ETzogbWFrZSB0aGlzIG1vcmUgZWZmaWNpZW50XG5cdFx0Ly8oIGJhc2VkIG9uIGh0dHA6Ly93d3cuZXVjbGlkZWFuc3BhY2UuY29tL21hdGhzL2FsZ2VicmEvbWF0cml4L2Z1bmN0aW9ucy9pbnZlcnNlL2ZvdXJEL2luZGV4Lmh0bSApXG5cblx0XHRyZXR1cm4gKFxuXHRcdFx0bjQxICogKFxuXHRcdFx0XHQrIG4xNCAqIG4yMyAqIG4zMlxuXHRcdFx0XHQgLSBuMTMgKiBuMjQgKiBuMzJcblx0XHRcdFx0IC0gbjE0ICogbjIyICogbjMzXG5cdFx0XHRcdCArIG4xMiAqIG4yNCAqIG4zM1xuXHRcdFx0XHQgKyBuMTMgKiBuMjIgKiBuMzRcblx0XHRcdFx0IC0gbjEyICogbjIzICogbjM0XG5cdFx0XHQpICtcblx0XHRcdG40MiAqIChcblx0XHRcdFx0KyBuMTEgKiBuMjMgKiBuMzRcblx0XHRcdFx0IC0gbjExICogbjI0ICogbjMzXG5cdFx0XHRcdCArIG4xNCAqIG4yMSAqIG4zM1xuXHRcdFx0XHQgLSBuMTMgKiBuMjEgKiBuMzRcblx0XHRcdFx0ICsgbjEzICogbjI0ICogbjMxXG5cdFx0XHRcdCAtIG4xNCAqIG4yMyAqIG4zMVxuXHRcdFx0KSArXG5cdFx0XHRuNDMgKiAoXG5cdFx0XHRcdCsgbjExICogbjI0ICogbjMyXG5cdFx0XHRcdCAtIG4xMSAqIG4yMiAqIG4zNFxuXHRcdFx0XHQgLSBuMTQgKiBuMjEgKiBuMzJcblx0XHRcdFx0ICsgbjEyICogbjIxICogbjM0XG5cdFx0XHRcdCArIG4xNCAqIG4yMiAqIG4zMVxuXHRcdFx0XHQgLSBuMTIgKiBuMjQgKiBuMzFcblx0XHRcdCkgK1xuXHRcdFx0bjQ0ICogKFxuXHRcdFx0XHQtIG4xMyAqIG4yMiAqIG4zMVxuXHRcdFx0XHQgLSBuMTEgKiBuMjMgKiBuMzJcblx0XHRcdFx0ICsgbjExICogbjIyICogbjMzXG5cdFx0XHRcdCArIG4xMyAqIG4yMSAqIG4zMlxuXHRcdFx0XHQgLSBuMTIgKiBuMjEgKiBuMzNcblx0XHRcdFx0ICsgbjEyICogbjIzICogbjMxXG5cdFx0XHQpXG5cblx0XHQpO1xuXG5cdH1cblxuXHR0cmFuc3Bvc2UoKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cdFx0bGV0IHRtcDtcblxuXHRcdHRtcCA9IHRlWyAxIF07IHRlWyAxIF0gPSB0ZVsgNCBdOyB0ZVsgNCBdID0gdG1wO1xuXHRcdHRtcCA9IHRlWyAyIF07IHRlWyAyIF0gPSB0ZVsgOCBdOyB0ZVsgOCBdID0gdG1wO1xuXHRcdHRtcCA9IHRlWyA2IF07IHRlWyA2IF0gPSB0ZVsgOSBdOyB0ZVsgOSBdID0gdG1wO1xuXG5cdFx0dG1wID0gdGVbIDMgXTsgdGVbIDMgXSA9IHRlWyAxMiBdOyB0ZVsgMTIgXSA9IHRtcDtcblx0XHR0bXAgPSB0ZVsgNyBdOyB0ZVsgNyBdID0gdGVbIDEzIF07IHRlWyAxMyBdID0gdG1wO1xuXHRcdHRtcCA9IHRlWyAxMSBdOyB0ZVsgMTEgXSA9IHRlWyAxNCBdOyB0ZVsgMTQgXSA9IHRtcDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRQb3NpdGlvbiggeCwgeSwgeiApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdGlmICggeC5pc1ZlY3RvcjMgKSB7XG5cblx0XHRcdHRlWyAxMiBdID0geC54O1xuXHRcdFx0dGVbIDEzIF0gPSB4Lnk7XG5cdFx0XHR0ZVsgMTQgXSA9IHguejtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRlWyAxMiBdID0geDtcblx0XHRcdHRlWyAxMyBdID0geTtcblx0XHRcdHRlWyAxNCBdID0gejtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRpbnZlcnQoKSB7XG5cblx0XHQvLyBiYXNlZCBvbiBodHRwOi8vd3d3LmV1Y2xpZGVhbnNwYWNlLmNvbS9tYXRocy9hbGdlYnJhL21hdHJpeC9mdW5jdGlvbnMvaW52ZXJzZS9mb3VyRC9pbmRleC5odG1cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHMsXG5cblx0XHRcdG4xMSA9IHRlWyAwIF0sIG4yMSA9IHRlWyAxIF0sIG4zMSA9IHRlWyAyIF0sIG40MSA9IHRlWyAzIF0sXG5cdFx0XHRuMTIgPSB0ZVsgNCBdLCBuMjIgPSB0ZVsgNSBdLCBuMzIgPSB0ZVsgNiBdLCBuNDIgPSB0ZVsgNyBdLFxuXHRcdFx0bjEzID0gdGVbIDggXSwgbjIzID0gdGVbIDkgXSwgbjMzID0gdGVbIDEwIF0sIG40MyA9IHRlWyAxMSBdLFxuXHRcdFx0bjE0ID0gdGVbIDEyIF0sIG4yNCA9IHRlWyAxMyBdLCBuMzQgPSB0ZVsgMTQgXSwgbjQ0ID0gdGVbIDE1IF0sXG5cblx0XHRcdHQxMSA9IG4yMyAqIG4zNCAqIG40MiAtIG4yNCAqIG4zMyAqIG40MiArIG4yNCAqIG4zMiAqIG40MyAtIG4yMiAqIG4zNCAqIG40MyAtIG4yMyAqIG4zMiAqIG40NCArIG4yMiAqIG4zMyAqIG40NCxcblx0XHRcdHQxMiA9IG4xNCAqIG4zMyAqIG40MiAtIG4xMyAqIG4zNCAqIG40MiAtIG4xNCAqIG4zMiAqIG40MyArIG4xMiAqIG4zNCAqIG40MyArIG4xMyAqIG4zMiAqIG40NCAtIG4xMiAqIG4zMyAqIG40NCxcblx0XHRcdHQxMyA9IG4xMyAqIG4yNCAqIG40MiAtIG4xNCAqIG4yMyAqIG40MiArIG4xNCAqIG4yMiAqIG40MyAtIG4xMiAqIG4yNCAqIG40MyAtIG4xMyAqIG4yMiAqIG40NCArIG4xMiAqIG4yMyAqIG40NCxcblx0XHRcdHQxNCA9IG4xNCAqIG4yMyAqIG4zMiAtIG4xMyAqIG4yNCAqIG4zMiAtIG4xNCAqIG4yMiAqIG4zMyArIG4xMiAqIG4yNCAqIG4zMyArIG4xMyAqIG4yMiAqIG4zNCAtIG4xMiAqIG4yMyAqIG4zNDtcblxuXHRcdGNvbnN0IGRldCA9IG4xMSAqIHQxMSArIG4yMSAqIHQxMiArIG4zMSAqIHQxMyArIG40MSAqIHQxNDtcblxuXHRcdGlmICggZGV0ID09PSAwICkgcmV0dXJuIHRoaXMuc2V0KCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwLCAwICk7XG5cblx0XHRjb25zdCBkZXRJbnYgPSAxIC8gZGV0O1xuXG5cdFx0dGVbIDAgXSA9IHQxMSAqIGRldEludjtcblx0XHR0ZVsgMSBdID0gKCBuMjQgKiBuMzMgKiBuNDEgLSBuMjMgKiBuMzQgKiBuNDEgLSBuMjQgKiBuMzEgKiBuNDMgKyBuMjEgKiBuMzQgKiBuNDMgKyBuMjMgKiBuMzEgKiBuNDQgLSBuMjEgKiBuMzMgKiBuNDQgKSAqIGRldEludjtcblx0XHR0ZVsgMiBdID0gKCBuMjIgKiBuMzQgKiBuNDEgLSBuMjQgKiBuMzIgKiBuNDEgKyBuMjQgKiBuMzEgKiBuNDIgLSBuMjEgKiBuMzQgKiBuNDIgLSBuMjIgKiBuMzEgKiBuNDQgKyBuMjEgKiBuMzIgKiBuNDQgKSAqIGRldEludjtcblx0XHR0ZVsgMyBdID0gKCBuMjMgKiBuMzIgKiBuNDEgLSBuMjIgKiBuMzMgKiBuNDEgLSBuMjMgKiBuMzEgKiBuNDIgKyBuMjEgKiBuMzMgKiBuNDIgKyBuMjIgKiBuMzEgKiBuNDMgLSBuMjEgKiBuMzIgKiBuNDMgKSAqIGRldEludjtcblxuXHRcdHRlWyA0IF0gPSB0MTIgKiBkZXRJbnY7XG5cdFx0dGVbIDUgXSA9ICggbjEzICogbjM0ICogbjQxIC0gbjE0ICogbjMzICogbjQxICsgbjE0ICogbjMxICogbjQzIC0gbjExICogbjM0ICogbjQzIC0gbjEzICogbjMxICogbjQ0ICsgbjExICogbjMzICogbjQ0ICkgKiBkZXRJbnY7XG5cdFx0dGVbIDYgXSA9ICggbjE0ICogbjMyICogbjQxIC0gbjEyICogbjM0ICogbjQxIC0gbjE0ICogbjMxICogbjQyICsgbjExICogbjM0ICogbjQyICsgbjEyICogbjMxICogbjQ0IC0gbjExICogbjMyICogbjQ0ICkgKiBkZXRJbnY7XG5cdFx0dGVbIDcgXSA9ICggbjEyICogbjMzICogbjQxIC0gbjEzICogbjMyICogbjQxICsgbjEzICogbjMxICogbjQyIC0gbjExICogbjMzICogbjQyIC0gbjEyICogbjMxICogbjQzICsgbjExICogbjMyICogbjQzICkgKiBkZXRJbnY7XG5cblx0XHR0ZVsgOCBdID0gdDEzICogZGV0SW52O1xuXHRcdHRlWyA5IF0gPSAoIG4xNCAqIG4yMyAqIG40MSAtIG4xMyAqIG4yNCAqIG40MSAtIG4xNCAqIG4yMSAqIG40MyArIG4xMSAqIG4yNCAqIG40MyArIG4xMyAqIG4yMSAqIG40NCAtIG4xMSAqIG4yMyAqIG40NCApICogZGV0SW52O1xuXHRcdHRlWyAxMCBdID0gKCBuMTIgKiBuMjQgKiBuNDEgLSBuMTQgKiBuMjIgKiBuNDEgKyBuMTQgKiBuMjEgKiBuNDIgLSBuMTEgKiBuMjQgKiBuNDIgLSBuMTIgKiBuMjEgKiBuNDQgKyBuMTEgKiBuMjIgKiBuNDQgKSAqIGRldEludjtcblx0XHR0ZVsgMTEgXSA9ICggbjEzICogbjIyICogbjQxIC0gbjEyICogbjIzICogbjQxIC0gbjEzICogbjIxICogbjQyICsgbjExICogbjIzICogbjQyICsgbjEyICogbjIxICogbjQzIC0gbjExICogbjIyICogbjQzICkgKiBkZXRJbnY7XG5cblx0XHR0ZVsgMTIgXSA9IHQxNCAqIGRldEludjtcblx0XHR0ZVsgMTMgXSA9ICggbjEzICogbjI0ICogbjMxIC0gbjE0ICogbjIzICogbjMxICsgbjE0ICogbjIxICogbjMzIC0gbjExICogbjI0ICogbjMzIC0gbjEzICogbjIxICogbjM0ICsgbjExICogbjIzICogbjM0ICkgKiBkZXRJbnY7XG5cdFx0dGVbIDE0IF0gPSAoIG4xNCAqIG4yMiAqIG4zMSAtIG4xMiAqIG4yNCAqIG4zMSAtIG4xNCAqIG4yMSAqIG4zMiArIG4xMSAqIG4yNCAqIG4zMiArIG4xMiAqIG4yMSAqIG4zNCAtIG4xMSAqIG4yMiAqIG4zNCApICogZGV0SW52O1xuXHRcdHRlWyAxNSBdID0gKCBuMTIgKiBuMjMgKiBuMzEgLSBuMTMgKiBuMjIgKiBuMzEgKyBuMTMgKiBuMjEgKiBuMzIgLSBuMTEgKiBuMjMgKiBuMzIgLSBuMTIgKiBuMjEgKiBuMzMgKyBuMTEgKiBuMjIgKiBuMzMgKSAqIGRldEludjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzY2FsZSggdiApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblx0XHRjb25zdCB4ID0gdi54LCB5ID0gdi55LCB6ID0gdi56O1xuXG5cdFx0dGVbIDAgXSAqPSB4OyB0ZVsgNCBdICo9IHk7IHRlWyA4IF0gKj0gejtcblx0XHR0ZVsgMSBdICo9IHg7IHRlWyA1IF0gKj0geTsgdGVbIDkgXSAqPSB6O1xuXHRcdHRlWyAyIF0gKj0geDsgdGVbIDYgXSAqPSB5OyB0ZVsgMTAgXSAqPSB6O1xuXHRcdHRlWyAzIF0gKj0geDsgdGVbIDcgXSAqPSB5OyB0ZVsgMTEgXSAqPSB6O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldE1heFNjYWxlT25BeGlzKCkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXG5cdFx0Y29uc3Qgc2NhbGVYU3EgPSB0ZVsgMCBdICogdGVbIDAgXSArIHRlWyAxIF0gKiB0ZVsgMSBdICsgdGVbIDIgXSAqIHRlWyAyIF07XG5cdFx0Y29uc3Qgc2NhbGVZU3EgPSB0ZVsgNCBdICogdGVbIDQgXSArIHRlWyA1IF0gKiB0ZVsgNSBdICsgdGVbIDYgXSAqIHRlWyA2IF07XG5cdFx0Y29uc3Qgc2NhbGVaU3EgPSB0ZVsgOCBdICogdGVbIDggXSArIHRlWyA5IF0gKiB0ZVsgOSBdICsgdGVbIDEwIF0gKiB0ZVsgMTAgXTtcblxuXHRcdHJldHVybiBNYXRoLnNxcnQoIE1hdGgubWF4KCBzY2FsZVhTcSwgc2NhbGVZU3EsIHNjYWxlWlNxICkgKTtcblxuXHR9XG5cblx0bWFrZVRyYW5zbGF0aW9uKCB4LCB5LCB6ICkge1xuXG5cdFx0aWYgKCB4LmlzVmVjdG9yMyApIHtcblxuXHRcdFx0dGhpcy5zZXQoXG5cblx0XHRcdFx0MSwgMCwgMCwgeC54LFxuXHRcdFx0XHQwLCAxLCAwLCB4LnksXG5cdFx0XHRcdDAsIDAsIDEsIHgueixcblx0XHRcdFx0MCwgMCwgMCwgMVxuXG5cdFx0XHQpO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhpcy5zZXQoXG5cblx0XHRcdFx0MSwgMCwgMCwgeCxcblx0XHRcdFx0MCwgMSwgMCwgeSxcblx0XHRcdFx0MCwgMCwgMSwgeixcblx0XHRcdFx0MCwgMCwgMCwgMVxuXG5cdFx0XHQpO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1ha2VSb3RhdGlvblgoIHRoZXRhICkge1xuXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCB0aGV0YSApLCBzID0gTWF0aC5zaW4oIHRoZXRhICk7XG5cblx0XHR0aGlzLnNldChcblxuXHRcdFx0MSwgMCwgMCwgMCxcblx0XHRcdDAsIGMsIC0gcywgMCxcblx0XHRcdDAsIHMsIGMsIDAsXG5cdFx0XHQwLCAwLCAwLCAxXG5cblx0XHQpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1ha2VSb3RhdGlvblkoIHRoZXRhICkge1xuXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCB0aGV0YSApLCBzID0gTWF0aC5zaW4oIHRoZXRhICk7XG5cblx0XHR0aGlzLnNldChcblxuXHRcdFx0IGMsIDAsIHMsIDAsXG5cdFx0XHQgMCwgMSwgMCwgMCxcblx0XHRcdC0gcywgMCwgYywgMCxcblx0XHRcdCAwLCAwLCAwLCAxXG5cblx0XHQpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1ha2VSb3RhdGlvblooIHRoZXRhICkge1xuXG5cdFx0Y29uc3QgYyA9IE1hdGguY29zKCB0aGV0YSApLCBzID0gTWF0aC5zaW4oIHRoZXRhICk7XG5cblx0XHR0aGlzLnNldChcblxuXHRcdFx0YywgLSBzLCAwLCAwLFxuXHRcdFx0cywgYywgMCwgMCxcblx0XHRcdDAsIDAsIDEsIDAsXG5cdFx0XHQwLCAwLCAwLCAxXG5cblx0XHQpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1ha2VSb3RhdGlvbkF4aXMoIGF4aXMsIGFuZ2xlICkge1xuXG5cdFx0Ly8gQmFzZWQgb24gaHR0cDovL3d3dy5nYW1lZGV2Lm5ldC9yZWZlcmVuY2UvYXJ0aWNsZXMvYXJ0aWNsZTExOTkuYXNwXG5cblx0XHRjb25zdCBjID0gTWF0aC5jb3MoIGFuZ2xlICk7XG5cdFx0Y29uc3QgcyA9IE1hdGguc2luKCBhbmdsZSApO1xuXHRcdGNvbnN0IHQgPSAxIC0gYztcblx0XHRjb25zdCB4ID0gYXhpcy54LCB5ID0gYXhpcy55LCB6ID0gYXhpcy56O1xuXHRcdGNvbnN0IHR4ID0gdCAqIHgsIHR5ID0gdCAqIHk7XG5cblx0XHR0aGlzLnNldChcblxuXHRcdFx0dHggKiB4ICsgYywgdHggKiB5IC0gcyAqIHosIHR4ICogeiArIHMgKiB5LCAwLFxuXHRcdFx0dHggKiB5ICsgcyAqIHosIHR5ICogeSArIGMsIHR5ICogeiAtIHMgKiB4LCAwLFxuXHRcdFx0dHggKiB6IC0gcyAqIHksIHR5ICogeiArIHMgKiB4LCB0ICogeiAqIHogKyBjLCAwLFxuXHRcdFx0MCwgMCwgMCwgMVxuXG5cdFx0KTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlU2NhbGUoIHgsIHksIHogKSB7XG5cblx0XHR0aGlzLnNldChcblxuXHRcdFx0eCwgMCwgMCwgMCxcblx0XHRcdDAsIHksIDAsIDAsXG5cdFx0XHQwLCAwLCB6LCAwLFxuXHRcdFx0MCwgMCwgMCwgMVxuXG5cdFx0KTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlU2hlYXIoIHh5LCB4eiwgeXgsIHl6LCB6eCwgenkgKSB7XG5cblx0XHR0aGlzLnNldChcblxuXHRcdFx0MSwgeXgsIHp4LCAwLFxuXHRcdFx0eHksIDEsIHp5LCAwLFxuXHRcdFx0eHosIHl6LCAxLCAwLFxuXHRcdFx0MCwgMCwgMCwgMVxuXG5cdFx0KTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb21wb3NlKCBwb3NpdGlvbiwgcXVhdGVybmlvbiwgc2NhbGUgKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cblx0XHRjb25zdCB4ID0gcXVhdGVybmlvbi5feCwgeSA9IHF1YXRlcm5pb24uX3ksIHogPSBxdWF0ZXJuaW9uLl96LCB3ID0gcXVhdGVybmlvbi5fdztcblx0XHRjb25zdCB4MiA9IHggKyB4LFx0eTIgPSB5ICsgeSwgejIgPSB6ICsgejtcblx0XHRjb25zdCB4eCA9IHggKiB4MiwgeHkgPSB4ICogeTIsIHh6ID0geCAqIHoyO1xuXHRcdGNvbnN0IHl5ID0geSAqIHkyLCB5eiA9IHkgKiB6MiwgenogPSB6ICogejI7XG5cdFx0Y29uc3Qgd3ggPSB3ICogeDIsIHd5ID0gdyAqIHkyLCB3eiA9IHcgKiB6MjtcblxuXHRcdGNvbnN0IHN4ID0gc2NhbGUueCwgc3kgPSBzY2FsZS55LCBzeiA9IHNjYWxlLno7XG5cblx0XHR0ZVsgMCBdID0gKCAxIC0gKCB5eSArIHp6ICkgKSAqIHN4O1xuXHRcdHRlWyAxIF0gPSAoIHh5ICsgd3ogKSAqIHN4O1xuXHRcdHRlWyAyIF0gPSAoIHh6IC0gd3kgKSAqIHN4O1xuXHRcdHRlWyAzIF0gPSAwO1xuXG5cdFx0dGVbIDQgXSA9ICggeHkgLSB3eiApICogc3k7XG5cdFx0dGVbIDUgXSA9ICggMSAtICggeHggKyB6eiApICkgKiBzeTtcblx0XHR0ZVsgNiBdID0gKCB5eiArIHd4ICkgKiBzeTtcblx0XHR0ZVsgNyBdID0gMDtcblxuXHRcdHRlWyA4IF0gPSAoIHh6ICsgd3kgKSAqIHN6O1xuXHRcdHRlWyA5IF0gPSAoIHl6IC0gd3ggKSAqIHN6O1xuXHRcdHRlWyAxMCBdID0gKCAxIC0gKCB4eCArIHl5ICkgKSAqIHN6O1xuXHRcdHRlWyAxMSBdID0gMDtcblxuXHRcdHRlWyAxMiBdID0gcG9zaXRpb24ueDtcblx0XHR0ZVsgMTMgXSA9IHBvc2l0aW9uLnk7XG5cdFx0dGVbIDE0IF0gPSBwb3NpdGlvbi56O1xuXHRcdHRlWyAxNSBdID0gMTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkZWNvbXBvc2UoIHBvc2l0aW9uLCBxdWF0ZXJuaW9uLCBzY2FsZSApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblxuXHRcdGxldCBzeCA9IF92MSQ1LnNldCggdGVbIDAgXSwgdGVbIDEgXSwgdGVbIDIgXSApLmxlbmd0aCgpO1xuXHRcdGNvbnN0IHN5ID0gX3YxJDUuc2V0KCB0ZVsgNCBdLCB0ZVsgNSBdLCB0ZVsgNiBdICkubGVuZ3RoKCk7XG5cdFx0Y29uc3Qgc3ogPSBfdjEkNS5zZXQoIHRlWyA4IF0sIHRlWyA5IF0sIHRlWyAxMCBdICkubGVuZ3RoKCk7XG5cblx0XHQvLyBpZiBkZXRlcm1pbmUgaXMgbmVnYXRpdmUsIHdlIG5lZWQgdG8gaW52ZXJ0IG9uZSBzY2FsZVxuXHRcdGNvbnN0IGRldCA9IHRoaXMuZGV0ZXJtaW5hbnQoKTtcblx0XHRpZiAoIGRldCA8IDAgKSBzeCA9IC0gc3g7XG5cblx0XHRwb3NpdGlvbi54ID0gdGVbIDEyIF07XG5cdFx0cG9zaXRpb24ueSA9IHRlWyAxMyBdO1xuXHRcdHBvc2l0aW9uLnogPSB0ZVsgMTQgXTtcblxuXHRcdC8vIHNjYWxlIHRoZSByb3RhdGlvbiBwYXJ0XG5cdFx0X20xJDQuY29weSggdGhpcyApO1xuXG5cdFx0Y29uc3QgaW52U1ggPSAxIC8gc3g7XG5cdFx0Y29uc3QgaW52U1kgPSAxIC8gc3k7XG5cdFx0Y29uc3QgaW52U1ogPSAxIC8gc3o7XG5cblx0XHRfbTEkNC5lbGVtZW50c1sgMCBdICo9IGludlNYO1xuXHRcdF9tMSQ0LmVsZW1lbnRzWyAxIF0gKj0gaW52U1g7XG5cdFx0X20xJDQuZWxlbWVudHNbIDIgXSAqPSBpbnZTWDtcblxuXHRcdF9tMSQ0LmVsZW1lbnRzWyA0IF0gKj0gaW52U1k7XG5cdFx0X20xJDQuZWxlbWVudHNbIDUgXSAqPSBpbnZTWTtcblx0XHRfbTEkNC5lbGVtZW50c1sgNiBdICo9IGludlNZO1xuXG5cdFx0X20xJDQuZWxlbWVudHNbIDggXSAqPSBpbnZTWjtcblx0XHRfbTEkNC5lbGVtZW50c1sgOSBdICo9IGludlNaO1xuXHRcdF9tMSQ0LmVsZW1lbnRzWyAxMCBdICo9IGludlNaO1xuXG5cdFx0cXVhdGVybmlvbi5zZXRGcm9tUm90YXRpb25NYXRyaXgoIF9tMSQ0ICk7XG5cblx0XHRzY2FsZS54ID0gc3g7XG5cdFx0c2NhbGUueSA9IHN5O1xuXHRcdHNjYWxlLnogPSBzejtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlUGVyc3BlY3RpdmUoIGxlZnQsIHJpZ2h0LCB0b3AsIGJvdHRvbSwgbmVhciwgZmFyLCBjb29yZGluYXRlU3lzdGVtID0gV2ViR0xDb29yZGluYXRlU3lzdGVtICkge1xuXG5cdFx0Y29uc3QgdGUgPSB0aGlzLmVsZW1lbnRzO1xuXHRcdGNvbnN0IHggPSAyICogbmVhciAvICggcmlnaHQgLSBsZWZ0ICk7XG5cdFx0Y29uc3QgeSA9IDIgKiBuZWFyIC8gKCB0b3AgLSBib3R0b20gKTtcblxuXHRcdGNvbnN0IGEgPSAoIHJpZ2h0ICsgbGVmdCApIC8gKCByaWdodCAtIGxlZnQgKTtcblx0XHRjb25zdCBiID0gKCB0b3AgKyBib3R0b20gKSAvICggdG9wIC0gYm90dG9tICk7XG5cblx0XHRsZXQgYywgZDtcblxuXHRcdGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR0xDb29yZGluYXRlU3lzdGVtICkge1xuXG5cdFx0XHRjID0gLSAoIGZhciArIG5lYXIgKSAvICggZmFyIC0gbmVhciApO1xuXHRcdFx0ZCA9ICggLSAyICogZmFyICogbmVhciApIC8gKCBmYXIgLSBuZWFyICk7XG5cblx0XHR9IGVsc2UgaWYgKCBjb29yZGluYXRlU3lzdGVtID09PSBXZWJHUFVDb29yZGluYXRlU3lzdGVtICkge1xuXG5cdFx0XHRjID0gLSBmYXIgLyAoIGZhciAtIG5lYXIgKTtcblx0XHRcdGQgPSAoIC0gZmFyICogbmVhciApIC8gKCBmYXIgLSBuZWFyICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5NYXRyaXg0Lm1ha2VQZXJzcGVjdGl2ZSgpOiBJbnZhbGlkIGNvb3JkaW5hdGUgc3lzdGVtOiAnICsgY29vcmRpbmF0ZVN5c3RlbSApO1xuXG5cdFx0fVxuXG5cdFx0dGVbIDAgXSA9IHg7XHR0ZVsgNCBdID0gMDtcdHRlWyA4IF0gPSBhOyBcdHRlWyAxMiBdID0gMDtcblx0XHR0ZVsgMSBdID0gMDtcdHRlWyA1IF0gPSB5O1x0dGVbIDkgXSA9IGI7IFx0dGVbIDEzIF0gPSAwO1xuXHRcdHRlWyAyIF0gPSAwO1x0dGVbIDYgXSA9IDA7XHR0ZVsgMTAgXSA9IGM7IFx0dGVbIDE0IF0gPSBkO1xuXHRcdHRlWyAzIF0gPSAwO1x0dGVbIDcgXSA9IDA7XHR0ZVsgMTEgXSA9IC0gMTtcdHRlWyAxNSBdID0gMDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtYWtlT3J0aG9ncmFwaGljKCBsZWZ0LCByaWdodCwgdG9wLCBib3R0b20sIG5lYXIsIGZhciwgY29vcmRpbmF0ZVN5c3RlbSA9IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblx0XHRjb25zdCB3ID0gMS4wIC8gKCByaWdodCAtIGxlZnQgKTtcblx0XHRjb25zdCBoID0gMS4wIC8gKCB0b3AgLSBib3R0b20gKTtcblx0XHRjb25zdCBwID0gMS4wIC8gKCBmYXIgLSBuZWFyICk7XG5cblx0XHRjb25zdCB4ID0gKCByaWdodCArIGxlZnQgKSAqIHc7XG5cdFx0Y29uc3QgeSA9ICggdG9wICsgYm90dG9tICkgKiBoO1xuXG5cdFx0bGV0IHosIHpJbnY7XG5cblx0XHRpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdFx0eiA9ICggZmFyICsgbmVhciApICogcDtcblx0XHRcdHpJbnYgPSAtIDIgKiBwO1xuXG5cdFx0fSBlbHNlIGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR1BVQ29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdFx0eiA9IG5lYXIgKiBwO1xuXHRcdFx0ekludiA9IC0gMSAqIHA7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5NYXRyaXg0Lm1ha2VPcnRob2dyYXBoaWMoKTogSW52YWxpZCBjb29yZGluYXRlIHN5c3RlbTogJyArIGNvb3JkaW5hdGVTeXN0ZW0gKTtcblxuXHRcdH1cblxuXHRcdHRlWyAwIF0gPSAyICogdztcdHRlWyA0IF0gPSAwO1x0XHR0ZVsgOCBdID0gMDsgXHRcdHRlWyAxMiBdID0gLSB4O1xuXHRcdHRlWyAxIF0gPSAwOyBcdFx0dGVbIDUgXSA9IDIgKiBoO1x0dGVbIDkgXSA9IDA7IFx0XHR0ZVsgMTMgXSA9IC0geTtcblx0XHR0ZVsgMiBdID0gMDsgXHRcdHRlWyA2IF0gPSAwO1x0XHR0ZVsgMTAgXSA9IHpJbnY7XHR0ZVsgMTQgXSA9IC0gejtcblx0XHR0ZVsgMyBdID0gMDsgXHRcdHRlWyA3IF0gPSAwO1x0XHR0ZVsgMTEgXSA9IDA7XHRcdHRlWyAxNSBdID0gMTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRlcXVhbHMoIG1hdHJpeCApIHtcblxuXHRcdGNvbnN0IHRlID0gdGhpcy5lbGVtZW50cztcblx0XHRjb25zdCBtZSA9IG1hdHJpeC5lbGVtZW50cztcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDE2OyBpICsrICkge1xuXG5cdFx0XHRpZiAoIHRlWyBpIF0gIT09IG1lWyBpIF0gKSByZXR1cm4gZmFsc2U7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9XG5cblx0ZnJvbUFycmF5KCBhcnJheSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDE2OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmVsZW1lbnRzWyBpIF0gPSBhcnJheVsgaSArIG9mZnNldCBdO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvQXJyYXkoIGFycmF5ID0gW10sIG9mZnNldCA9IDAgKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0ZVsgMCBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyAxIF0gPSB0ZVsgMSBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyAyIF0gPSB0ZVsgMiBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyAzIF0gPSB0ZVsgMyBdO1xuXG5cdFx0YXJyYXlbIG9mZnNldCArIDQgXSA9IHRlWyA0IF07XG5cdFx0YXJyYXlbIG9mZnNldCArIDUgXSA9IHRlWyA1IF07XG5cdFx0YXJyYXlbIG9mZnNldCArIDYgXSA9IHRlWyA2IF07XG5cdFx0YXJyYXlbIG9mZnNldCArIDcgXSA9IHRlWyA3IF07XG5cblx0XHRhcnJheVsgb2Zmc2V0ICsgOCBdID0gdGVbIDggXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgOSBdID0gdGVbIDkgXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMTAgXSA9IHRlWyAxMCBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyAxMSBdID0gdGVbIDExIF07XG5cblx0XHRhcnJheVsgb2Zmc2V0ICsgMTIgXSA9IHRlWyAxMiBdO1xuXHRcdGFycmF5WyBvZmZzZXQgKyAxMyBdID0gdGVbIDEzIF07XG5cdFx0YXJyYXlbIG9mZnNldCArIDE0IF0gPSB0ZVsgMTQgXTtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMTUgXSA9IHRlWyAxNSBdO1xuXG5cdFx0cmV0dXJuIGFycmF5O1xuXG5cdH1cblxufVxuXG5jb25zdCBfdjEkNSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9tMSQ0ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX3plcm8gPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAwLCAwLCAwICk7XG5jb25zdCBfb25lID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMSwgMSwgMSApO1xuY29uc3QgX3ggPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfeSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF96ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jb25zdCBfbWF0cml4JDIgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfcXVhdGVybmlvbiQzID0gLypAX19QVVJFX18qLyBuZXcgUXVhdGVybmlvbigpO1xuXG5jbGFzcyBFdWxlciB7XG5cblx0Y29uc3RydWN0b3IoIHggPSAwLCB5ID0gMCwgeiA9IDAsIG9yZGVyID0gRXVsZXIuREVGQVVMVF9PUkRFUiApIHtcblxuXHRcdHRoaXMuaXNFdWxlciA9IHRydWU7XG5cblx0XHR0aGlzLl94ID0geDtcblx0XHR0aGlzLl95ID0geTtcblx0XHR0aGlzLl96ID0gejtcblx0XHR0aGlzLl9vcmRlciA9IG9yZGVyO1xuXG5cdH1cblxuXHRnZXQgeCgpIHtcblxuXHRcdHJldHVybiB0aGlzLl94O1xuXG5cdH1cblxuXHRzZXQgeCggdmFsdWUgKSB7XG5cblx0XHR0aGlzLl94ID0gdmFsdWU7XG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdH1cblxuXHRnZXQgeSgpIHtcblxuXHRcdHJldHVybiB0aGlzLl95O1xuXG5cdH1cblxuXHRzZXQgeSggdmFsdWUgKSB7XG5cblx0XHR0aGlzLl95ID0gdmFsdWU7XG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdH1cblxuXHRnZXQgeigpIHtcblxuXHRcdHJldHVybiB0aGlzLl96O1xuXG5cdH1cblxuXHRzZXQgeiggdmFsdWUgKSB7XG5cblx0XHR0aGlzLl96ID0gdmFsdWU7XG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdH1cblxuXHRnZXQgb3JkZXIoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fb3JkZXI7XG5cblx0fVxuXG5cdHNldCBvcmRlciggdmFsdWUgKSB7XG5cblx0XHR0aGlzLl9vcmRlciA9IHZhbHVlO1xuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHR9XG5cblx0c2V0KCB4LCB5LCB6LCBvcmRlciA9IHRoaXMuX29yZGVyICkge1xuXG5cdFx0dGhpcy5feCA9IHg7XG5cdFx0dGhpcy5feSA9IHk7XG5cdFx0dGhpcy5feiA9IHo7XG5cdFx0dGhpcy5fb3JkZXIgPSBvcmRlcjtcblxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvciggdGhpcy5feCwgdGhpcy5feSwgdGhpcy5feiwgdGhpcy5fb3JkZXIgKTtcblxuXHR9XG5cblx0Y29weSggZXVsZXIgKSB7XG5cblx0XHR0aGlzLl94ID0gZXVsZXIuX3g7XG5cdFx0dGhpcy5feSA9IGV1bGVyLl95O1xuXHRcdHRoaXMuX3ogPSBldWxlci5fejtcblx0XHR0aGlzLl9vcmRlciA9IGV1bGVyLl9vcmRlcjtcblxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2soKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tUm90YXRpb25NYXRyaXgoIG0sIG9yZGVyID0gdGhpcy5fb3JkZXIsIHVwZGF0ZSA9IHRydWUgKSB7XG5cblx0XHQvLyBhc3N1bWVzIHRoZSB1cHBlciAzeDMgb2YgbSBpcyBhIHB1cmUgcm90YXRpb24gbWF0cml4IChpLmUsIHVuc2NhbGVkKVxuXG5cdFx0Y29uc3QgdGUgPSBtLmVsZW1lbnRzO1xuXHRcdGNvbnN0IG0xMSA9IHRlWyAwIF0sIG0xMiA9IHRlWyA0IF0sIG0xMyA9IHRlWyA4IF07XG5cdFx0Y29uc3QgbTIxID0gdGVbIDEgXSwgbTIyID0gdGVbIDUgXSwgbTIzID0gdGVbIDkgXTtcblx0XHRjb25zdCBtMzEgPSB0ZVsgMiBdLCBtMzIgPSB0ZVsgNiBdLCBtMzMgPSB0ZVsgMTAgXTtcblxuXHRcdHN3aXRjaCAoIG9yZGVyICkge1xuXG5cdFx0XHRjYXNlICdYWVonOlxuXG5cdFx0XHRcdHRoaXMuX3kgPSBNYXRoLmFzaW4oIGNsYW1wKCBtMTMsIC0gMSwgMSApICk7XG5cblx0XHRcdFx0aWYgKCBNYXRoLmFicyggbTEzICkgPCAwLjk5OTk5OTkgKSB7XG5cblx0XHRcdFx0XHR0aGlzLl94ID0gTWF0aC5hdGFuMiggLSBtMjMsIG0zMyApO1xuXHRcdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmF0YW4yKCAtIG0xMiwgbTExICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmF0YW4yKCBtMzIsIG0yMiApO1xuXHRcdFx0XHRcdHRoaXMuX3ogPSAwO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnWVhaJzpcblxuXHRcdFx0XHR0aGlzLl94ID0gTWF0aC5hc2luKCAtIGNsYW1wKCBtMjMsIC0gMSwgMSApICk7XG5cblx0XHRcdFx0aWYgKCBNYXRoLmFicyggbTIzICkgPCAwLjk5OTk5OTkgKSB7XG5cblx0XHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hdGFuMiggbTEzLCBtMzMgKTtcblx0XHRcdFx0XHR0aGlzLl96ID0gTWF0aC5hdGFuMiggbTIxLCBtMjIgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXRhbjIoIC0gbTMxLCBtMTEgKTtcblx0XHRcdFx0XHR0aGlzLl96ID0gMDtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1pYWSc6XG5cblx0XHRcdFx0dGhpcy5feCA9IE1hdGguYXNpbiggY2xhbXAoIG0zMiwgLSAxLCAxICkgKTtcblxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBtMzIgKSA8IDAuOTk5OTk5OSApIHtcblxuXHRcdFx0XHRcdHRoaXMuX3kgPSBNYXRoLmF0YW4yKCAtIG0zMSwgbTMzICk7XG5cdFx0XHRcdFx0dGhpcy5feiA9IE1hdGguYXRhbjIoIC0gbTEyLCBtMjIgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0dGhpcy5feSA9IDA7XG5cdFx0XHRcdFx0dGhpcy5feiA9IE1hdGguYXRhbjIoIG0yMSwgbTExICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdaWVgnOlxuXG5cdFx0XHRcdHRoaXMuX3kgPSBNYXRoLmFzaW4oIC0gY2xhbXAoIG0zMSwgLSAxLCAxICkgKTtcblxuXHRcdFx0XHRpZiAoIE1hdGguYWJzKCBtMzEgKSA8IDAuOTk5OTk5OSApIHtcblxuXHRcdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmF0YW4yKCBtMzIsIG0zMyApO1xuXHRcdFx0XHRcdHRoaXMuX3ogPSBNYXRoLmF0YW4yKCBtMjEsIG0xMSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHR0aGlzLl94ID0gMDtcblx0XHRcdFx0XHR0aGlzLl96ID0gTWF0aC5hdGFuMiggLSBtMTIsIG0yMiApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnWVpYJzpcblxuXHRcdFx0XHR0aGlzLl96ID0gTWF0aC5hc2luKCBjbGFtcCggbTIxLCAtIDEsIDEgKSApO1xuXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIG0yMSApIDwgMC45OTk5OTk5ICkge1xuXG5cdFx0XHRcdFx0dGhpcy5feCA9IE1hdGguYXRhbjIoIC0gbTIzLCBtMjIgKTtcblx0XHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hdGFuMiggLSBtMzEsIG0xMSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHR0aGlzLl94ID0gMDtcblx0XHRcdFx0XHR0aGlzLl95ID0gTWF0aC5hdGFuMiggbTEzLCBtMzMgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1haWSc6XG5cblx0XHRcdFx0dGhpcy5feiA9IE1hdGguYXNpbiggLSBjbGFtcCggbTEyLCAtIDEsIDEgKSApO1xuXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIG0xMiApIDwgMC45OTk5OTk5ICkge1xuXG5cdFx0XHRcdFx0dGhpcy5feCA9IE1hdGguYXRhbjIoIG0zMiwgbTIyICk7XG5cdFx0XHRcdFx0dGhpcy5feSA9IE1hdGguYXRhbjIoIG0xMywgbTExICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHRoaXMuX3ggPSBNYXRoLmF0YW4yKCAtIG0yMywgbTMzICk7XG5cdFx0XHRcdFx0dGhpcy5feSA9IDA7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRkZWZhdWx0OlxuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkV1bGVyOiAuc2V0RnJvbVJvdGF0aW9uTWF0cml4KCkgZW5jb3VudGVyZWQgYW4gdW5rbm93biBvcmRlcjogJyArIG9yZGVyICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLl9vcmRlciA9IG9yZGVyO1xuXG5cdFx0aWYgKCB1cGRhdGUgPT09IHRydWUgKSB0aGlzLl9vbkNoYW5nZUNhbGxiYWNrKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbVF1YXRlcm5pb24oIHEsIG9yZGVyLCB1cGRhdGUgKSB7XG5cblx0XHRfbWF0cml4JDIubWFrZVJvdGF0aW9uRnJvbVF1YXRlcm5pb24oIHEgKTtcblxuXHRcdHJldHVybiB0aGlzLnNldEZyb21Sb3RhdGlvbk1hdHJpeCggX21hdHJpeCQyLCBvcmRlciwgdXBkYXRlICk7XG5cblx0fVxuXG5cdHNldEZyb21WZWN0b3IzKCB2LCBvcmRlciA9IHRoaXMuX29yZGVyICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuc2V0KCB2LngsIHYueSwgdi56LCBvcmRlciApO1xuXG5cdH1cblxuXHRyZW9yZGVyKCBuZXdPcmRlciApIHtcblxuXHRcdC8vIFdBUk5JTkc6IHRoaXMgZGlzY2FyZHMgcmV2b2x1dGlvbiBpbmZvcm1hdGlvbiAtYmhvdXN0b25cblxuXHRcdF9xdWF0ZXJuaW9uJDMuc2V0RnJvbUV1bGVyKCB0aGlzICk7XG5cblx0XHRyZXR1cm4gdGhpcy5zZXRGcm9tUXVhdGVybmlvbiggX3F1YXRlcm5pb24kMywgbmV3T3JkZXIgKTtcblxuXHR9XG5cblx0ZXF1YWxzKCBldWxlciApIHtcblxuXHRcdHJldHVybiAoIGV1bGVyLl94ID09PSB0aGlzLl94ICkgJiYgKCBldWxlci5feSA9PT0gdGhpcy5feSApICYmICggZXVsZXIuX3ogPT09IHRoaXMuX3ogKSAmJiAoIGV1bGVyLl9vcmRlciA9PT0gdGhpcy5fb3JkZXIgKTtcblxuXHR9XG5cblx0ZnJvbUFycmF5KCBhcnJheSApIHtcblxuXHRcdHRoaXMuX3ggPSBhcnJheVsgMCBdO1xuXHRcdHRoaXMuX3kgPSBhcnJheVsgMSBdO1xuXHRcdHRoaXMuX3ogPSBhcnJheVsgMiBdO1xuXHRcdGlmICggYXJyYXlbIDMgXSAhPT0gdW5kZWZpbmVkICkgdGhpcy5fb3JkZXIgPSBhcnJheVsgMyBdO1xuXG5cdFx0dGhpcy5fb25DaGFuZ2VDYWxsYmFjaygpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvQXJyYXkoIGFycmF5ID0gW10sIG9mZnNldCA9IDAgKSB7XG5cblx0XHRhcnJheVsgb2Zmc2V0IF0gPSB0aGlzLl94O1xuXHRcdGFycmF5WyBvZmZzZXQgKyAxIF0gPSB0aGlzLl95O1xuXHRcdGFycmF5WyBvZmZzZXQgKyAyIF0gPSB0aGlzLl96O1xuXHRcdGFycmF5WyBvZmZzZXQgKyAzIF0gPSB0aGlzLl9vcmRlcjtcblxuXHRcdHJldHVybiBhcnJheTtcblxuXHR9XG5cblx0X29uQ2hhbmdlKCBjYWxsYmFjayApIHtcblxuXHRcdHRoaXMuX29uQ2hhbmdlQ2FsbGJhY2sgPSBjYWxsYmFjaztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRfb25DaGFuZ2VDYWxsYmFjaygpIHt9XG5cblx0KlsgU3ltYm9sLml0ZXJhdG9yIF0oKSB7XG5cblx0XHR5aWVsZCB0aGlzLl94O1xuXHRcdHlpZWxkIHRoaXMuX3k7XG5cdFx0eWllbGQgdGhpcy5fejtcblx0XHR5aWVsZCB0aGlzLl9vcmRlcjtcblxuXHR9XG5cbn1cblxuRXVsZXIuREVGQVVMVF9PUkRFUiA9ICdYWVonO1xuXG5jbGFzcyBMYXllcnMge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0dGhpcy5tYXNrID0gMSB8IDA7XG5cblx0fVxuXG5cdHNldCggY2hhbm5lbCApIHtcblxuXHRcdHRoaXMubWFzayA9ICggMSA8PCBjaGFubmVsIHwgMCApID4+PiAwO1xuXG5cdH1cblxuXHRlbmFibGUoIGNoYW5uZWwgKSB7XG5cblx0XHR0aGlzLm1hc2sgfD0gMSA8PCBjaGFubmVsIHwgMDtcblxuXHR9XG5cblx0ZW5hYmxlQWxsKCkge1xuXG5cdFx0dGhpcy5tYXNrID0gMHhmZmZmZmZmZiB8IDA7XG5cblx0fVxuXG5cdHRvZ2dsZSggY2hhbm5lbCApIHtcblxuXHRcdHRoaXMubWFzayBePSAxIDw8IGNoYW5uZWwgfCAwO1xuXG5cdH1cblxuXHRkaXNhYmxlKCBjaGFubmVsICkge1xuXG5cdFx0dGhpcy5tYXNrICY9IH4gKCAxIDw8IGNoYW5uZWwgfCAwICk7XG5cblx0fVxuXG5cdGRpc2FibGVBbGwoKSB7XG5cblx0XHR0aGlzLm1hc2sgPSAwO1xuXG5cdH1cblxuXHR0ZXN0KCBsYXllcnMgKSB7XG5cblx0XHRyZXR1cm4gKCB0aGlzLm1hc2sgJiBsYXllcnMubWFzayApICE9PSAwO1xuXG5cdH1cblxuXHRpc0VuYWJsZWQoIGNoYW5uZWwgKSB7XG5cblx0XHRyZXR1cm4gKCB0aGlzLm1hc2sgJiAoIDEgPDwgY2hhbm5lbCB8IDAgKSApICE9PSAwO1xuXG5cdH1cblxufVxuXG5sZXQgX29iamVjdDNESWQgPSAwO1xuXG5jb25zdCBfdjEkNCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9xMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFF1YXRlcm5pb24oKTtcbmNvbnN0IF9tMSQzID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX3RhcmdldCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY29uc3QgX3Bvc2l0aW9uJDMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfc2NhbGUkMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9xdWF0ZXJuaW9uJDIgPSAvKkBfX1BVUkVfXyovIG5ldyBRdWF0ZXJuaW9uKCk7XG5cbmNvbnN0IF94QXhpcyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDEsIDAsIDAgKTtcbmNvbnN0IF95QXhpcyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDAsIDEsIDAgKTtcbmNvbnN0IF96QXhpcyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDAsIDAsIDEgKTtcblxuY29uc3QgX2FkZGVkRXZlbnQgPSB7IHR5cGU6ICdhZGRlZCcgfTtcbmNvbnN0IF9yZW1vdmVkRXZlbnQgPSB7IHR5cGU6ICdyZW1vdmVkJyB9O1xuXG5jb25zdCBfY2hpbGRhZGRlZEV2ZW50ID0geyB0eXBlOiAnY2hpbGRhZGRlZCcsIGNoaWxkOiBudWxsIH07XG5jb25zdCBfY2hpbGRyZW1vdmVkRXZlbnQgPSB7IHR5cGU6ICdjaGlsZHJlbW92ZWQnLCBjaGlsZDogbnVsbCB9O1xuXG5jbGFzcyBPYmplY3QzRCBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc09iamVjdDNEID0gdHJ1ZTtcblxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggdGhpcywgJ2lkJywgeyB2YWx1ZTogX29iamVjdDNESWQgKysgfSApO1xuXG5cdFx0dGhpcy51dWlkID0gZ2VuZXJhdGVVVUlEKCk7XG5cblx0XHR0aGlzLm5hbWUgPSAnJztcblx0XHR0aGlzLnR5cGUgPSAnT2JqZWN0M0QnO1xuXG5cdFx0dGhpcy5wYXJlbnQgPSBudWxsO1xuXHRcdHRoaXMuY2hpbGRyZW4gPSBbXTtcblxuXHRcdHRoaXMudXAgPSBPYmplY3QzRC5ERUZBVUxUX1VQLmNsb25lKCk7XG5cblx0XHRjb25zdCBwb3NpdGlvbiA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0Y29uc3Qgcm90YXRpb24gPSBuZXcgRXVsZXIoKTtcblx0XHRjb25zdCBxdWF0ZXJuaW9uID0gbmV3IFF1YXRlcm5pb24oKTtcblx0XHRjb25zdCBzY2FsZSA9IG5ldyBWZWN0b3IzKCAxLCAxLCAxICk7XG5cblx0XHRmdW5jdGlvbiBvblJvdGF0aW9uQ2hhbmdlKCkge1xuXG5cdFx0XHRxdWF0ZXJuaW9uLnNldEZyb21FdWxlciggcm90YXRpb24sIGZhbHNlICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBvblF1YXRlcm5pb25DaGFuZ2UoKSB7XG5cblx0XHRcdHJvdGF0aW9uLnNldEZyb21RdWF0ZXJuaW9uKCBxdWF0ZXJuaW9uLCB1bmRlZmluZWQsIGZhbHNlICk7XG5cblx0XHR9XG5cblx0XHRyb3RhdGlvbi5fb25DaGFuZ2UoIG9uUm90YXRpb25DaGFuZ2UgKTtcblx0XHRxdWF0ZXJuaW9uLl9vbkNoYW5nZSggb25RdWF0ZXJuaW9uQ2hhbmdlICk7XG5cblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydGllcyggdGhpcywge1xuXHRcdFx0cG9zaXRpb246IHtcblx0XHRcdFx0Y29uZmlndXJhYmxlOiB0cnVlLFxuXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuXHRcdFx0XHR2YWx1ZTogcG9zaXRpb25cblx0XHRcdH0sXG5cdFx0XHRyb3RhdGlvbjoge1xuXHRcdFx0XHRjb25maWd1cmFibGU6IHRydWUsXG5cdFx0XHRcdGVudW1lcmFibGU6IHRydWUsXG5cdFx0XHRcdHZhbHVlOiByb3RhdGlvblxuXHRcdFx0fSxcblx0XHRcdHF1YXRlcm5pb246IHtcblx0XHRcdFx0Y29uZmlndXJhYmxlOiB0cnVlLFxuXHRcdFx0XHRlbnVtZXJhYmxlOiB0cnVlLFxuXHRcdFx0XHR2YWx1ZTogcXVhdGVybmlvblxuXHRcdFx0fSxcblx0XHRcdHNjYWxlOiB7XG5cdFx0XHRcdGNvbmZpZ3VyYWJsZTogdHJ1ZSxcblx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcblx0XHRcdFx0dmFsdWU6IHNjYWxlXG5cdFx0XHR9LFxuXHRcdFx0bW9kZWxWaWV3TWF0cml4OiB7XG5cdFx0XHRcdHZhbHVlOiBuZXcgTWF0cml4NCgpXG5cdFx0XHR9LFxuXHRcdFx0bm9ybWFsTWF0cml4OiB7XG5cdFx0XHRcdHZhbHVlOiBuZXcgTWF0cml4MygpXG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0dGhpcy5tYXRyaXggPSBuZXcgTWF0cml4NCgpO1xuXHRcdHRoaXMubWF0cml4V29ybGQgPSBuZXcgTWF0cml4NCgpO1xuXG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gT2JqZWN0M0QuREVGQVVMVF9NQVRSSVhfQVVUT19VUERBVEU7XG5cblx0XHR0aGlzLm1hdHJpeFdvcmxkQXV0b1VwZGF0ZSA9IE9iamVjdDNELkRFRkFVTFRfTUFUUklYX1dPUkxEX0FVVE9fVVBEQVRFOyAvLyBjaGVja2VkIGJ5IHRoZSByZW5kZXJlclxuXHRcdHRoaXMubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0dGhpcy5sYXllcnMgPSBuZXcgTGF5ZXJzKCk7XG5cdFx0dGhpcy52aXNpYmxlID0gdHJ1ZTtcblxuXHRcdHRoaXMuY2FzdFNoYWRvdyA9IGZhbHNlO1xuXHRcdHRoaXMucmVjZWl2ZVNoYWRvdyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5mcnVzdHVtQ3VsbGVkID0gdHJ1ZTtcblx0XHR0aGlzLnJlbmRlck9yZGVyID0gMDtcblxuXHRcdHRoaXMuYW5pbWF0aW9ucyA9IFtdO1xuXG5cdFx0dGhpcy51c2VyRGF0YSA9IHt9O1xuXG5cdH1cblxuXHRvbkJlZm9yZVNoYWRvdyggLyogcmVuZGVyZXIsIG9iamVjdCwgY2FtZXJhLCBzaGFkb3dDYW1lcmEsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsLCBncm91cCAqLyApIHt9XG5cblx0b25BZnRlclNoYWRvdyggLyogcmVuZGVyZXIsIG9iamVjdCwgY2FtZXJhLCBzaGFkb3dDYW1lcmEsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsLCBncm91cCAqLyApIHt9XG5cblx0b25CZWZvcmVSZW5kZXIoIC8qIHJlbmRlcmVyLCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwICovICkge31cblxuXHRvbkFmdGVyUmVuZGVyKCAvKiByZW5kZXJlciwgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cCAqLyApIHt9XG5cblx0YXBwbHlNYXRyaXg0KCBtYXRyaXggKSB7XG5cblx0XHRpZiAoIHRoaXMubWF0cml4QXV0b1VwZGF0ZSApIHRoaXMudXBkYXRlTWF0cml4KCk7XG5cblx0XHR0aGlzLm1hdHJpeC5wcmVtdWx0aXBseSggbWF0cml4ICk7XG5cblx0XHR0aGlzLm1hdHJpeC5kZWNvbXBvc2UoIHRoaXMucG9zaXRpb24sIHRoaXMucXVhdGVybmlvbiwgdGhpcy5zY2FsZSApO1xuXG5cdH1cblxuXHRhcHBseVF1YXRlcm5pb24oIHEgKSB7XG5cblx0XHR0aGlzLnF1YXRlcm5pb24ucHJlbXVsdGlwbHkoIHEgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRSb3RhdGlvbkZyb21BeGlzQW5nbGUoIGF4aXMsIGFuZ2xlICkge1xuXG5cdFx0Ly8gYXNzdW1lcyBheGlzIGlzIG5vcm1hbGl6ZWRcblxuXHRcdHRoaXMucXVhdGVybmlvbi5zZXRGcm9tQXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApO1xuXG5cdH1cblxuXHRzZXRSb3RhdGlvbkZyb21FdWxlciggZXVsZXIgKSB7XG5cblx0XHR0aGlzLnF1YXRlcm5pb24uc2V0RnJvbUV1bGVyKCBldWxlciwgdHJ1ZSApO1xuXG5cdH1cblxuXHRzZXRSb3RhdGlvbkZyb21NYXRyaXgoIG0gKSB7XG5cblx0XHQvLyBhc3N1bWVzIHRoZSB1cHBlciAzeDMgb2YgbSBpcyBhIHB1cmUgcm90YXRpb24gbWF0cml4IChpLmUsIHVuc2NhbGVkKVxuXG5cdFx0dGhpcy5xdWF0ZXJuaW9uLnNldEZyb21Sb3RhdGlvbk1hdHJpeCggbSApO1xuXG5cdH1cblxuXHRzZXRSb3RhdGlvbkZyb21RdWF0ZXJuaW9uKCBxICkge1xuXG5cdFx0Ly8gYXNzdW1lcyBxIGlzIG5vcm1hbGl6ZWRcblxuXHRcdHRoaXMucXVhdGVybmlvbi5jb3B5KCBxICk7XG5cblx0fVxuXG5cdHJvdGF0ZU9uQXhpcyggYXhpcywgYW5nbGUgKSB7XG5cblx0XHQvLyByb3RhdGUgb2JqZWN0IG9uIGF4aXMgaW4gb2JqZWN0IHNwYWNlXG5cdFx0Ly8gYXhpcyBpcyBhc3N1bWVkIHRvIGJlIG5vcm1hbGl6ZWRcblxuXHRcdF9xMS5zZXRGcm9tQXhpc0FuZ2xlKCBheGlzLCBhbmdsZSApO1xuXG5cdFx0dGhpcy5xdWF0ZXJuaW9uLm11bHRpcGx5KCBfcTEgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyb3RhdGVPbldvcmxkQXhpcyggYXhpcywgYW5nbGUgKSB7XG5cblx0XHQvLyByb3RhdGUgb2JqZWN0IG9uIGF4aXMgaW4gd29ybGQgc3BhY2Vcblx0XHQvLyBheGlzIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxuXHRcdC8vIG1ldGhvZCBhc3N1bWVzIG5vIHJvdGF0ZWQgcGFyZW50XG5cblx0XHRfcTEuc2V0RnJvbUF4aXNBbmdsZSggYXhpcywgYW5nbGUgKTtcblxuXHRcdHRoaXMucXVhdGVybmlvbi5wcmVtdWx0aXBseSggX3ExICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cm90YXRlWCggYW5nbGUgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5yb3RhdGVPbkF4aXMoIF94QXhpcywgYW5nbGUgKTtcblxuXHR9XG5cblx0cm90YXRlWSggYW5nbGUgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5yb3RhdGVPbkF4aXMoIF95QXhpcywgYW5nbGUgKTtcblxuXHR9XG5cblx0cm90YXRlWiggYW5nbGUgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5yb3RhdGVPbkF4aXMoIF96QXhpcywgYW5nbGUgKTtcblxuXHR9XG5cblx0dHJhbnNsYXRlT25BeGlzKCBheGlzLCBkaXN0YW5jZSApIHtcblxuXHRcdC8vIHRyYW5zbGF0ZSBvYmplY3QgYnkgZGlzdGFuY2UgYWxvbmcgYXhpcyBpbiBvYmplY3Qgc3BhY2Vcblx0XHQvLyBheGlzIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxuXG5cdFx0X3YxJDQuY29weSggYXhpcyApLmFwcGx5UXVhdGVybmlvbiggdGhpcy5xdWF0ZXJuaW9uICk7XG5cblx0XHR0aGlzLnBvc2l0aW9uLmFkZCggX3YxJDQubXVsdGlwbHlTY2FsYXIoIGRpc3RhbmNlICkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0cmFuc2xhdGVYKCBkaXN0YW5jZSApIHtcblxuXHRcdHJldHVybiB0aGlzLnRyYW5zbGF0ZU9uQXhpcyggX3hBeGlzLCBkaXN0YW5jZSApO1xuXG5cdH1cblxuXHR0cmFuc2xhdGVZKCBkaXN0YW5jZSApIHtcblxuXHRcdHJldHVybiB0aGlzLnRyYW5zbGF0ZU9uQXhpcyggX3lBeGlzLCBkaXN0YW5jZSApO1xuXG5cdH1cblxuXHR0cmFuc2xhdGVaKCBkaXN0YW5jZSApIHtcblxuXHRcdHJldHVybiB0aGlzLnRyYW5zbGF0ZU9uQXhpcyggX3pBeGlzLCBkaXN0YW5jZSApO1xuXG5cdH1cblxuXHRsb2NhbFRvV29ybGQoIHZlY3RvciApIHtcblxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XG5cblx0XHRyZXR1cm4gdmVjdG9yLmFwcGx5TWF0cml4NCggdGhpcy5tYXRyaXhXb3JsZCApO1xuXG5cdH1cblxuXHR3b3JsZFRvTG9jYWwoIHZlY3RvciApIHtcblxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XG5cblx0XHRyZXR1cm4gdmVjdG9yLmFwcGx5TWF0cml4NCggX20xJDMuY29weSggdGhpcy5tYXRyaXhXb3JsZCApLmludmVydCgpICk7XG5cblx0fVxuXG5cdGxvb2tBdCggeCwgeSwgeiApIHtcblxuXHRcdC8vIFRoaXMgbWV0aG9kIGRvZXMgbm90IHN1cHBvcnQgb2JqZWN0cyBoYXZpbmcgbm9uLXVuaWZvcm1seS1zY2FsZWQgcGFyZW50KHMpXG5cblx0XHRpZiAoIHguaXNWZWN0b3IzICkge1xuXG5cdFx0XHRfdGFyZ2V0LmNvcHkoIHggKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdF90YXJnZXQuc2V0KCB4LCB5LCB6ICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBwYXJlbnQgPSB0aGlzLnBhcmVudDtcblxuXHRcdHRoaXMudXBkYXRlV29ybGRNYXRyaXgoIHRydWUsIGZhbHNlICk7XG5cblx0XHRfcG9zaXRpb24kMy5zZXRGcm9tTWF0cml4UG9zaXRpb24oIHRoaXMubWF0cml4V29ybGQgKTtcblxuXHRcdGlmICggdGhpcy5pc0NhbWVyYSB8fCB0aGlzLmlzTGlnaHQgKSB7XG5cblx0XHRcdF9tMSQzLmxvb2tBdCggX3Bvc2l0aW9uJDMsIF90YXJnZXQsIHRoaXMudXAgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdF9tMSQzLmxvb2tBdCggX3RhcmdldCwgX3Bvc2l0aW9uJDMsIHRoaXMudXAgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMucXVhdGVybmlvbi5zZXRGcm9tUm90YXRpb25NYXRyaXgoIF9tMSQzICk7XG5cblx0XHRpZiAoIHBhcmVudCApIHtcblxuXHRcdFx0X20xJDMuZXh0cmFjdFJvdGF0aW9uKCBwYXJlbnQubWF0cml4V29ybGQgKTtcblx0XHRcdF9xMS5zZXRGcm9tUm90YXRpb25NYXRyaXgoIF9tMSQzICk7XG5cdFx0XHR0aGlzLnF1YXRlcm5pb24ucHJlbXVsdGlwbHkoIF9xMS5pbnZlcnQoKSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRhZGQoIG9iamVjdCApIHtcblxuXHRcdGlmICggYXJndW1lbnRzLmxlbmd0aCA+IDEgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGFyZ3VtZW50cy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0dGhpcy5hZGQoIGFyZ3VtZW50c1sgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHR9XG5cblx0XHRpZiAoIG9iamVjdCA9PT0gdGhpcyApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLk9iamVjdDNELmFkZDogb2JqZWN0IGNhblxcJ3QgYmUgYWRkZWQgYXMgYSBjaGlsZCBvZiBpdHNlbGYuJywgb2JqZWN0ICk7XG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH1cblxuXHRcdGlmICggb2JqZWN0ICYmIG9iamVjdC5pc09iamVjdDNEICkge1xuXG5cdFx0XHRvYmplY3QucmVtb3ZlRnJvbVBhcmVudCgpO1xuXHRcdFx0b2JqZWN0LnBhcmVudCA9IHRoaXM7XG5cdFx0XHR0aGlzLmNoaWxkcmVuLnB1c2goIG9iamVjdCApO1xuXG5cdFx0XHRvYmplY3QuZGlzcGF0Y2hFdmVudCggX2FkZGVkRXZlbnQgKTtcblxuXHRcdFx0X2NoaWxkYWRkZWRFdmVudC5jaGlsZCA9IG9iamVjdDtcblx0XHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggX2NoaWxkYWRkZWRFdmVudCApO1xuXHRcdFx0X2NoaWxkYWRkZWRFdmVudC5jaGlsZCA9IG51bGw7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuT2JqZWN0M0QuYWRkOiBvYmplY3Qgbm90IGFuIGluc3RhbmNlIG9mIFRIUkVFLk9iamVjdDNELicsIG9iamVjdCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJlbW92ZSggb2JqZWN0ICkge1xuXG5cdFx0aWYgKCBhcmd1bWVudHMubGVuZ3RoID4gMSApIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgYXJndW1lbnRzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHR0aGlzLnJlbW92ZSggYXJndW1lbnRzWyBpIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH1cblxuXHRcdGNvbnN0IGluZGV4ID0gdGhpcy5jaGlsZHJlbi5pbmRleE9mKCBvYmplY3QgKTtcblxuXHRcdGlmICggaW5kZXggIT09IC0gMSApIHtcblxuXHRcdFx0b2JqZWN0LnBhcmVudCA9IG51bGw7XG5cdFx0XHR0aGlzLmNoaWxkcmVuLnNwbGljZSggaW5kZXgsIDEgKTtcblxuXHRcdFx0b2JqZWN0LmRpc3BhdGNoRXZlbnQoIF9yZW1vdmVkRXZlbnQgKTtcblxuXHRcdFx0X2NoaWxkcmVtb3ZlZEV2ZW50LmNoaWxkID0gb2JqZWN0O1xuXHRcdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCBfY2hpbGRyZW1vdmVkRXZlbnQgKTtcblx0XHRcdF9jaGlsZHJlbW92ZWRFdmVudC5jaGlsZCA9IG51bGw7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cmVtb3ZlRnJvbVBhcmVudCgpIHtcblxuXHRcdGNvbnN0IHBhcmVudCA9IHRoaXMucGFyZW50O1xuXG5cdFx0aWYgKCBwYXJlbnQgIT09IG51bGwgKSB7XG5cblx0XHRcdHBhcmVudC5yZW1vdmUoIHRoaXMgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbGVhcigpIHtcblxuXHRcdHJldHVybiB0aGlzLnJlbW92ZSggLi4uIHRoaXMuY2hpbGRyZW4gKTtcblxuXHR9XG5cblx0YXR0YWNoKCBvYmplY3QgKSB7XG5cblx0XHQvLyBhZGRzIG9iamVjdCBhcyBhIGNoaWxkIG9mIHRoaXMsIHdoaWxlIG1haW50YWluaW5nIHRoZSBvYmplY3QncyB3b3JsZCB0cmFuc2Zvcm1cblxuXHRcdC8vIE5vdGU6IFRoaXMgbWV0aG9kIGRvZXMgbm90IHN1cHBvcnQgc2NlbmUgZ3JhcGhzIGhhdmluZyBub24tdW5pZm9ybWx5LXNjYWxlZCBub2RlcyhzKVxuXG5cdFx0dGhpcy51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdF9tMSQzLmNvcHkoIHRoaXMubWF0cml4V29ybGQgKS5pbnZlcnQoKTtcblxuXHRcdGlmICggb2JqZWN0LnBhcmVudCAhPT0gbnVsbCApIHtcblxuXHRcdFx0b2JqZWN0LnBhcmVudC51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdFx0X20xJDMubXVsdGlwbHkoIG9iamVjdC5wYXJlbnQubWF0cml4V29ybGQgKTtcblxuXHRcdH1cblxuXHRcdG9iamVjdC5hcHBseU1hdHJpeDQoIF9tMSQzICk7XG5cblx0XHRvYmplY3QucmVtb3ZlRnJvbVBhcmVudCgpO1xuXHRcdG9iamVjdC5wYXJlbnQgPSB0aGlzO1xuXHRcdHRoaXMuY2hpbGRyZW4ucHVzaCggb2JqZWN0ICk7XG5cblx0XHRvYmplY3QudXBkYXRlV29ybGRNYXRyaXgoIGZhbHNlLCB0cnVlICk7XG5cblx0XHRvYmplY3QuZGlzcGF0Y2hFdmVudCggX2FkZGVkRXZlbnQgKTtcblxuXHRcdF9jaGlsZGFkZGVkRXZlbnQuY2hpbGQgPSBvYmplY3Q7XG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCBfY2hpbGRhZGRlZEV2ZW50ICk7XG5cdFx0X2NoaWxkYWRkZWRFdmVudC5jaGlsZCA9IG51bGw7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0T2JqZWN0QnlJZCggaWQgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5nZXRPYmplY3RCeVByb3BlcnR5KCAnaWQnLCBpZCApO1xuXG5cdH1cblxuXHRnZXRPYmplY3RCeU5hbWUoIG5hbWUgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5nZXRPYmplY3RCeVByb3BlcnR5KCAnbmFtZScsIG5hbWUgKTtcblxuXHR9XG5cblx0Z2V0T2JqZWN0QnlQcm9wZXJ0eSggbmFtZSwgdmFsdWUgKSB7XG5cblx0XHRpZiAoIHRoaXNbIG5hbWUgXSA9PT0gdmFsdWUgKSByZXR1cm4gdGhpcztcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgY2hpbGQgPSB0aGlzLmNoaWxkcmVuWyBpIF07XG5cdFx0XHRjb25zdCBvYmplY3QgPSBjaGlsZC5nZXRPYmplY3RCeVByb3BlcnR5KCBuYW1lLCB2YWx1ZSApO1xuXG5cdFx0XHRpZiAoIG9iamVjdCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHJldHVybiBvYmplY3Q7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB1bmRlZmluZWQ7XG5cblx0fVxuXG5cdGdldE9iamVjdHNCeVByb3BlcnR5KCBuYW1lLCB2YWx1ZSwgcmVzdWx0ID0gW10gKSB7XG5cblx0XHRpZiAoIHRoaXNbIG5hbWUgXSA9PT0gdmFsdWUgKSByZXN1bHQucHVzaCggdGhpcyApO1xuXG5cdFx0Y29uc3QgY2hpbGRyZW4gPSB0aGlzLmNoaWxkcmVuO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y2hpbGRyZW5bIGkgXS5nZXRPYmplY3RzQnlQcm9wZXJ0eSggbmFtZSwgdmFsdWUsIHJlc3VsdCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJlc3VsdDtcblxuXHR9XG5cblx0Z2V0V29ybGRQb3NpdGlvbiggdGFyZ2V0ICkge1xuXG5cdFx0dGhpcy51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdHJldHVybiB0YXJnZXQuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1hdHJpeFdvcmxkICk7XG5cblx0fVxuXG5cdGdldFdvcmxkUXVhdGVybmlvbiggdGFyZ2V0ICkge1xuXG5cdFx0dGhpcy51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdHRoaXMubWF0cml4V29ybGQuZGVjb21wb3NlKCBfcG9zaXRpb24kMywgdGFyZ2V0LCBfc2NhbGUkMiApO1xuXG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0Z2V0V29ybGRTY2FsZSggdGFyZ2V0ICkge1xuXG5cdFx0dGhpcy51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdHRoaXMubWF0cml4V29ybGQuZGVjb21wb3NlKCBfcG9zaXRpb24kMywgX3F1YXRlcm5pb24kMiwgdGFyZ2V0ICk7XG5cblx0XHRyZXR1cm4gdGFyZ2V0O1xuXG5cdH1cblxuXHRnZXRXb3JsZERpcmVjdGlvbiggdGFyZ2V0ICkge1xuXG5cdFx0dGhpcy51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdGNvbnN0IGUgPSB0aGlzLm1hdHJpeFdvcmxkLmVsZW1lbnRzO1xuXG5cdFx0cmV0dXJuIHRhcmdldC5zZXQoIGVbIDggXSwgZVsgOSBdLCBlWyAxMCBdICkubm9ybWFsaXplKCk7XG5cblx0fVxuXG5cdHJheWNhc3QoIC8qIHJheWNhc3RlciwgaW50ZXJzZWN0cyAqLyApIHt9XG5cblx0dHJhdmVyc2UoIGNhbGxiYWNrICkge1xuXG5cdFx0Y2FsbGJhY2soIHRoaXMgKTtcblxuXHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNoaWxkcmVuWyBpIF0udHJhdmVyc2UoIGNhbGxiYWNrICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHRyYXZlcnNlVmlzaWJsZSggY2FsbGJhY2sgKSB7XG5cblx0XHRpZiAoIHRoaXMudmlzaWJsZSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHRjYWxsYmFjayggdGhpcyApO1xuXG5cdFx0Y29uc3QgY2hpbGRyZW4gPSB0aGlzLmNoaWxkcmVuO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y2hpbGRyZW5bIGkgXS50cmF2ZXJzZVZpc2libGUoIGNhbGxiYWNrICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHRyYXZlcnNlQW5jZXN0b3JzKCBjYWxsYmFjayApIHtcblxuXHRcdGNvbnN0IHBhcmVudCA9IHRoaXMucGFyZW50O1xuXG5cdFx0aWYgKCBwYXJlbnQgIT09IG51bGwgKSB7XG5cblx0XHRcdGNhbGxiYWNrKCBwYXJlbnQgKTtcblxuXHRcdFx0cGFyZW50LnRyYXZlcnNlQW5jZXN0b3JzKCBjYWxsYmFjayApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHR1cGRhdGVNYXRyaXgoKSB7XG5cblx0XHR0aGlzLm1hdHJpeC5jb21wb3NlKCB0aGlzLnBvc2l0aW9uLCB0aGlzLnF1YXRlcm5pb24sIHRoaXMuc2NhbGUgKTtcblxuXHRcdHRoaXMubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0fVxuXG5cdHVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApIHtcblxuXHRcdGlmICggdGhpcy5tYXRyaXhBdXRvVXBkYXRlICkgdGhpcy51cGRhdGVNYXRyaXgoKTtcblxuXHRcdGlmICggdGhpcy5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlIHx8IGZvcmNlICkge1xuXG5cdFx0XHRpZiAoIHRoaXMubWF0cml4V29ybGRBdXRvVXBkYXRlID09PSB0cnVlICkge1xuXG5cdFx0XHRcdGlmICggdGhpcy5wYXJlbnQgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHR0aGlzLm1hdHJpeFdvcmxkLmNvcHkoIHRoaXMubWF0cml4ICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHRoaXMubWF0cml4V29ybGQubXVsdGlwbHlNYXRyaWNlcyggdGhpcy5wYXJlbnQubWF0cml4V29ybGQsIHRoaXMubWF0cml4ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0XHRmb3JjZSA9IHRydWU7XG5cblx0XHR9XG5cblx0XHQvLyBtYWtlIHN1cmUgZGVzY2VuZGFudHMgYXJlIHVwZGF0ZWQgaWYgcmVxdWlyZWRcblxuXHRcdGNvbnN0IGNoaWxkcmVuID0gdGhpcy5jaGlsZHJlbjtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGNoaWxkID0gY2hpbGRyZW5bIGkgXTtcblxuXHRcdFx0Y2hpbGQudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHVwZGF0ZVdvcmxkTWF0cml4KCB1cGRhdGVQYXJlbnRzLCB1cGRhdGVDaGlsZHJlbiApIHtcblxuXHRcdGNvbnN0IHBhcmVudCA9IHRoaXMucGFyZW50O1xuXG5cdFx0aWYgKCB1cGRhdGVQYXJlbnRzID09PSB0cnVlICYmIHBhcmVudCAhPT0gbnVsbCApIHtcblxuXHRcdFx0cGFyZW50LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLm1hdHJpeEF1dG9VcGRhdGUgKSB0aGlzLnVwZGF0ZU1hdHJpeCgpO1xuXG5cdFx0aWYgKCB0aGlzLm1hdHJpeFdvcmxkQXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0aWYgKCB0aGlzLnBhcmVudCA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHR0aGlzLm1hdHJpeFdvcmxkLmNvcHkoIHRoaXMubWF0cml4ICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0dGhpcy5tYXRyaXhXb3JsZC5tdWx0aXBseU1hdHJpY2VzKCB0aGlzLnBhcmVudC5tYXRyaXhXb3JsZCwgdGhpcy5tYXRyaXggKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gbWFrZSBzdXJlIGRlc2NlbmRhbnRzIGFyZSB1cGRhdGVkXG5cblx0XHRpZiAoIHVwZGF0ZUNoaWxkcmVuID09PSB0cnVlICkge1xuXG5cdFx0XHRjb25zdCBjaGlsZHJlbiA9IHRoaXMuY2hpbGRyZW47XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgY2hpbGQgPSBjaGlsZHJlblsgaSBdO1xuXG5cdFx0XHRcdGNoaWxkLnVwZGF0ZVdvcmxkTWF0cml4KCBmYWxzZSwgdHJ1ZSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdHRvSlNPTiggbWV0YSApIHtcblxuXHRcdC8vIG1ldGEgaXMgYSBzdHJpbmcgd2hlbiBjYWxsZWQgZnJvbSBKU09OLnN0cmluZ2lmeVxuXHRcdGNvbnN0IGlzUm9vdE9iamVjdCA9ICggbWV0YSA9PT0gdW5kZWZpbmVkIHx8IHR5cGVvZiBtZXRhID09PSAnc3RyaW5nJyApO1xuXG5cdFx0Y29uc3Qgb3V0cHV0ID0ge307XG5cblx0XHQvLyBtZXRhIGlzIGEgaGFzaCB1c2VkIHRvIGNvbGxlY3QgZ2VvbWV0cmllcywgbWF0ZXJpYWxzLlxuXHRcdC8vIG5vdCBwcm92aWRpbmcgaXQgaW1wbGllcyB0aGF0IHRoaXMgaXMgdGhlIHJvb3Qgb2JqZWN0XG5cdFx0Ly8gYmVpbmcgc2VyaWFsaXplZC5cblx0XHRpZiAoIGlzUm9vdE9iamVjdCApIHtcblxuXHRcdFx0Ly8gaW5pdGlhbGl6ZSBtZXRhIG9ialxuXHRcdFx0bWV0YSA9IHtcblx0XHRcdFx0Z2VvbWV0cmllczoge30sXG5cdFx0XHRcdG1hdGVyaWFsczoge30sXG5cdFx0XHRcdHRleHR1cmVzOiB7fSxcblx0XHRcdFx0aW1hZ2VzOiB7fSxcblx0XHRcdFx0c2hhcGVzOiB7fSxcblx0XHRcdFx0c2tlbGV0b25zOiB7fSxcblx0XHRcdFx0YW5pbWF0aW9uczoge30sXG5cdFx0XHRcdG5vZGVzOiB7fVxuXHRcdFx0fTtcblxuXHRcdFx0b3V0cHV0Lm1ldGFkYXRhID0ge1xuXHRcdFx0XHR2ZXJzaW9uOiA0LjYsXG5cdFx0XHRcdHR5cGU6ICdPYmplY3QnLFxuXHRcdFx0XHRnZW5lcmF0b3I6ICdPYmplY3QzRC50b0pTT04nXG5cdFx0XHR9O1xuXG5cdFx0fVxuXG5cdFx0Ly8gc3RhbmRhcmQgT2JqZWN0M0Qgc2VyaWFsaXphdGlvblxuXG5cdFx0Y29uc3Qgb2JqZWN0ID0ge307XG5cblx0XHRvYmplY3QudXVpZCA9IHRoaXMudXVpZDtcblx0XHRvYmplY3QudHlwZSA9IHRoaXMudHlwZTtcblxuXHRcdGlmICggdGhpcy5uYW1lICE9PSAnJyApIG9iamVjdC5uYW1lID0gdGhpcy5uYW1lO1xuXHRcdGlmICggdGhpcy5jYXN0U2hhZG93ID09PSB0cnVlICkgb2JqZWN0LmNhc3RTaGFkb3cgPSB0cnVlO1xuXHRcdGlmICggdGhpcy5yZWNlaXZlU2hhZG93ID09PSB0cnVlICkgb2JqZWN0LnJlY2VpdmVTaGFkb3cgPSB0cnVlO1xuXHRcdGlmICggdGhpcy52aXNpYmxlID09PSBmYWxzZSApIG9iamVjdC52aXNpYmxlID0gZmFsc2U7XG5cdFx0aWYgKCB0aGlzLmZydXN0dW1DdWxsZWQgPT09IGZhbHNlICkgb2JqZWN0LmZydXN0dW1DdWxsZWQgPSBmYWxzZTtcblx0XHRpZiAoIHRoaXMucmVuZGVyT3JkZXIgIT09IDAgKSBvYmplY3QucmVuZGVyT3JkZXIgPSB0aGlzLnJlbmRlck9yZGVyO1xuXHRcdGlmICggT2JqZWN0LmtleXMoIHRoaXMudXNlckRhdGEgKS5sZW5ndGggPiAwICkgb2JqZWN0LnVzZXJEYXRhID0gdGhpcy51c2VyRGF0YTtcblxuXHRcdG9iamVjdC5sYXllcnMgPSB0aGlzLmxheWVycy5tYXNrO1xuXHRcdG9iamVjdC5tYXRyaXggPSB0aGlzLm1hdHJpeC50b0FycmF5KCk7XG5cdFx0b2JqZWN0LnVwID0gdGhpcy51cC50b0FycmF5KCk7XG5cblx0XHRpZiAoIHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9PT0gZmFsc2UgKSBvYmplY3QubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0Ly8gb2JqZWN0IHNwZWNpZmljIHByb3BlcnRpZXNcblxuXHRcdGlmICggdGhpcy5pc0luc3RhbmNlZE1lc2ggKSB7XG5cblx0XHRcdG9iamVjdC50eXBlID0gJ0luc3RhbmNlZE1lc2gnO1xuXHRcdFx0b2JqZWN0LmNvdW50ID0gdGhpcy5jb3VudDtcblx0XHRcdG9iamVjdC5pbnN0YW5jZU1hdHJpeCA9IHRoaXMuaW5zdGFuY2VNYXRyaXgudG9KU09OKCk7XG5cdFx0XHRpZiAoIHRoaXMuaW5zdGFuY2VDb2xvciAhPT0gbnVsbCApIG9iamVjdC5pbnN0YW5jZUNvbG9yID0gdGhpcy5pbnN0YW5jZUNvbG9yLnRvSlNPTigpO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmlzQmF0Y2hlZE1lc2ggKSB7XG5cblx0XHRcdG9iamVjdC50eXBlID0gJ0JhdGNoZWRNZXNoJztcblx0XHRcdG9iamVjdC5wZXJPYmplY3RGcnVzdHVtQ3VsbGVkID0gdGhpcy5wZXJPYmplY3RGcnVzdHVtQ3VsbGVkO1xuXHRcdFx0b2JqZWN0LnNvcnRPYmplY3RzID0gdGhpcy5zb3J0T2JqZWN0cztcblxuXHRcdFx0b2JqZWN0LmRyYXdSYW5nZXMgPSB0aGlzLl9kcmF3UmFuZ2VzO1xuXHRcdFx0b2JqZWN0LnJlc2VydmVkUmFuZ2VzID0gdGhpcy5fcmVzZXJ2ZWRSYW5nZXM7XG5cblx0XHRcdG9iamVjdC52aXNpYmlsaXR5ID0gdGhpcy5fdmlzaWJpbGl0eTtcblx0XHRcdG9iamVjdC5hY3RpdmUgPSB0aGlzLl9hY3RpdmU7XG5cdFx0XHRvYmplY3QuYm91bmRzID0gdGhpcy5fYm91bmRzLm1hcCggYm91bmQgPT4gKCB7XG5cdFx0XHRcdGJveEluaXRpYWxpemVkOiBib3VuZC5ib3hJbml0aWFsaXplZCxcblx0XHRcdFx0Ym94TWluOiBib3VuZC5ib3gubWluLnRvQXJyYXkoKSxcblx0XHRcdFx0Ym94TWF4OiBib3VuZC5ib3gubWF4LnRvQXJyYXkoKSxcblxuXHRcdFx0XHRzcGhlcmVJbml0aWFsaXplZDogYm91bmQuc3BoZXJlSW5pdGlhbGl6ZWQsXG5cdFx0XHRcdHNwaGVyZVJhZGl1czogYm91bmQuc3BoZXJlLnJhZGl1cyxcblx0XHRcdFx0c3BoZXJlQ2VudGVyOiBib3VuZC5zcGhlcmUuY2VudGVyLnRvQXJyYXkoKVxuXHRcdFx0fSApICk7XG5cblx0XHRcdG9iamVjdC5tYXhJbnN0YW5jZUNvdW50ID0gdGhpcy5fbWF4SW5zdGFuY2VDb3VudDtcblx0XHRcdG9iamVjdC5tYXhWZXJ0ZXhDb3VudCA9IHRoaXMuX21heFZlcnRleENvdW50O1xuXHRcdFx0b2JqZWN0Lm1heEluZGV4Q291bnQgPSB0aGlzLl9tYXhJbmRleENvdW50O1xuXG5cdFx0XHRvYmplY3QuZ2VvbWV0cnlJbml0aWFsaXplZCA9IHRoaXMuX2dlb21ldHJ5SW5pdGlhbGl6ZWQ7XG5cdFx0XHRvYmplY3QuZ2VvbWV0cnlDb3VudCA9IHRoaXMuX2dlb21ldHJ5Q291bnQ7XG5cblx0XHRcdG9iamVjdC5tYXRyaWNlc1RleHR1cmUgPSB0aGlzLl9tYXRyaWNlc1RleHR1cmUudG9KU09OKCBtZXRhICk7XG5cblx0XHRcdGlmICggdGhpcy5fY29sb3JzVGV4dHVyZSAhPT0gbnVsbCApIG9iamVjdC5jb2xvcnNUZXh0dXJlID0gdGhpcy5fY29sb3JzVGV4dHVyZS50b0pTT04oIG1ldGEgKTtcblxuXHRcdFx0aWYgKCB0aGlzLmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkge1xuXG5cdFx0XHRcdG9iamVjdC5ib3VuZGluZ1NwaGVyZSA9IHtcblx0XHRcdFx0XHRjZW50ZXI6IG9iamVjdC5ib3VuZGluZ1NwaGVyZS5jZW50ZXIudG9BcnJheSgpLFxuXHRcdFx0XHRcdHJhZGl1czogb2JqZWN0LmJvdW5kaW5nU3BoZXJlLnJhZGl1c1xuXHRcdFx0XHR9O1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGhpcy5ib3VuZGluZ0JveCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRvYmplY3QuYm91bmRpbmdCb3ggPSB7XG5cdFx0XHRcdFx0bWluOiBvYmplY3QuYm91bmRpbmdCb3gubWluLnRvQXJyYXkoKSxcblx0XHRcdFx0XHRtYXg6IG9iamVjdC5ib3VuZGluZ0JveC5tYXgudG9BcnJheSgpXG5cdFx0XHRcdH07XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vXG5cblx0XHRmdW5jdGlvbiBzZXJpYWxpemUoIGxpYnJhcnksIGVsZW1lbnQgKSB7XG5cblx0XHRcdGlmICggbGlicmFyeVsgZWxlbWVudC51dWlkIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRsaWJyYXJ5WyBlbGVtZW50LnV1aWQgXSA9IGVsZW1lbnQudG9KU09OKCBtZXRhICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGVsZW1lbnQudXVpZDtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5pc1NjZW5lICkge1xuXG5cdFx0XHRpZiAoIHRoaXMuYmFja2dyb3VuZCApIHtcblxuXHRcdFx0XHRpZiAoIHRoaXMuYmFja2dyb3VuZC5pc0NvbG9yICkge1xuXG5cdFx0XHRcdFx0b2JqZWN0LmJhY2tncm91bmQgPSB0aGlzLmJhY2tncm91bmQudG9KU09OKCk7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggdGhpcy5iYWNrZ3JvdW5kLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0XHRcdG9iamVjdC5iYWNrZ3JvdW5kID0gdGhpcy5iYWNrZ3JvdW5kLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGhpcy5lbnZpcm9ubWVudCAmJiB0aGlzLmVudmlyb25tZW50LmlzVGV4dHVyZSAmJiB0aGlzLmVudmlyb25tZW50LmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSAhPT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRvYmplY3QuZW52aXJvbm1lbnQgPSB0aGlzLmVudmlyb25tZW50LnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSBpZiAoIHRoaXMuaXNNZXNoIHx8IHRoaXMuaXNMaW5lIHx8IHRoaXMuaXNQb2ludHMgKSB7XG5cblx0XHRcdG9iamVjdC5nZW9tZXRyeSA9IHNlcmlhbGl6ZSggbWV0YS5nZW9tZXRyaWVzLCB0aGlzLmdlb21ldHJ5ICk7XG5cblx0XHRcdGNvbnN0IHBhcmFtZXRlcnMgPSB0aGlzLmdlb21ldHJ5LnBhcmFtZXRlcnM7XG5cblx0XHRcdGlmICggcGFyYW1ldGVycyAhPT0gdW5kZWZpbmVkICYmIHBhcmFtZXRlcnMuc2hhcGVzICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2hhcGVzID0gcGFyYW1ldGVycy5zaGFwZXM7XG5cblx0XHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBzaGFwZXMgKSApIHtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNoYXBlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBzaGFwZSA9IHNoYXBlc1sgaSBdO1xuXG5cdFx0XHRcdFx0XHRzZXJpYWxpemUoIG1ldGEuc2hhcGVzLCBzaGFwZSApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRzZXJpYWxpemUoIG1ldGEuc2hhcGVzLCBzaGFwZXMgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5pc1NraW5uZWRNZXNoICkge1xuXG5cdFx0XHRvYmplY3QuYmluZE1vZGUgPSB0aGlzLmJpbmRNb2RlO1xuXHRcdFx0b2JqZWN0LmJpbmRNYXRyaXggPSB0aGlzLmJpbmRNYXRyaXgudG9BcnJheSgpO1xuXG5cdFx0XHRpZiAoIHRoaXMuc2tlbGV0b24gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRzZXJpYWxpemUoIG1ldGEuc2tlbGV0b25zLCB0aGlzLnNrZWxldG9uICk7XG5cblx0XHRcdFx0b2JqZWN0LnNrZWxldG9uID0gdGhpcy5za2VsZXRvbi51dWlkO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMubWF0ZXJpYWwgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCB0aGlzLm1hdGVyaWFsICkgKSB7XG5cblx0XHRcdFx0Y29uc3QgdXVpZHMgPSBbXTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLm1hdGVyaWFsLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHR1dWlkcy5wdXNoKCBzZXJpYWxpemUoIG1ldGEubWF0ZXJpYWxzLCB0aGlzLm1hdGVyaWFsWyBpIF0gKSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRvYmplY3QubWF0ZXJpYWwgPSB1dWlkcztcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRvYmplY3QubWF0ZXJpYWwgPSBzZXJpYWxpemUoIG1ldGEubWF0ZXJpYWxzLCB0aGlzLm1hdGVyaWFsICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vXG5cblx0XHRpZiAoIHRoaXMuY2hpbGRyZW4ubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0b2JqZWN0LmNoaWxkcmVuID0gW107XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMuY2hpbGRyZW4ubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdG9iamVjdC5jaGlsZHJlbi5wdXNoKCB0aGlzLmNoaWxkcmVuWyBpIF0udG9KU09OKCBtZXRhICkub2JqZWN0ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vXG5cblx0XHRpZiAoIHRoaXMuYW5pbWF0aW9ucy5sZW5ndGggPiAwICkge1xuXG5cdFx0XHRvYmplY3QuYW5pbWF0aW9ucyA9IFtdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLmFuaW1hdGlvbnMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGFuaW1hdGlvbiA9IHRoaXMuYW5pbWF0aW9uc1sgaSBdO1xuXG5cdFx0XHRcdG9iamVjdC5hbmltYXRpb25zLnB1c2goIHNlcmlhbGl6ZSggbWV0YS5hbmltYXRpb25zLCBhbmltYXRpb24gKSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIGlzUm9vdE9iamVjdCApIHtcblxuXHRcdFx0Y29uc3QgZ2VvbWV0cmllcyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEuZ2VvbWV0cmllcyApO1xuXHRcdFx0Y29uc3QgbWF0ZXJpYWxzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS5tYXRlcmlhbHMgKTtcblx0XHRcdGNvbnN0IHRleHR1cmVzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS50ZXh0dXJlcyApO1xuXHRcdFx0Y29uc3QgaW1hZ2VzID0gZXh0cmFjdEZyb21DYWNoZSggbWV0YS5pbWFnZXMgKTtcblx0XHRcdGNvbnN0IHNoYXBlcyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEuc2hhcGVzICk7XG5cdFx0XHRjb25zdCBza2VsZXRvbnMgPSBleHRyYWN0RnJvbUNhY2hlKCBtZXRhLnNrZWxldG9ucyApO1xuXHRcdFx0Y29uc3QgYW5pbWF0aW9ucyA9IGV4dHJhY3RGcm9tQ2FjaGUoIG1ldGEuYW5pbWF0aW9ucyApO1xuXHRcdFx0Y29uc3Qgbm9kZXMgPSBleHRyYWN0RnJvbUNhY2hlKCBtZXRhLm5vZGVzICk7XG5cblx0XHRcdGlmICggZ2VvbWV0cmllcy5sZW5ndGggPiAwICkgb3V0cHV0Lmdlb21ldHJpZXMgPSBnZW9tZXRyaWVzO1xuXHRcdFx0aWYgKCBtYXRlcmlhbHMubGVuZ3RoID4gMCApIG91dHB1dC5tYXRlcmlhbHMgPSBtYXRlcmlhbHM7XG5cdFx0XHRpZiAoIHRleHR1cmVzLmxlbmd0aCA+IDAgKSBvdXRwdXQudGV4dHVyZXMgPSB0ZXh0dXJlcztcblx0XHRcdGlmICggaW1hZ2VzLmxlbmd0aCA+IDAgKSBvdXRwdXQuaW1hZ2VzID0gaW1hZ2VzO1xuXHRcdFx0aWYgKCBzaGFwZXMubGVuZ3RoID4gMCApIG91dHB1dC5zaGFwZXMgPSBzaGFwZXM7XG5cdFx0XHRpZiAoIHNrZWxldG9ucy5sZW5ndGggPiAwICkgb3V0cHV0LnNrZWxldG9ucyA9IHNrZWxldG9ucztcblx0XHRcdGlmICggYW5pbWF0aW9ucy5sZW5ndGggPiAwICkgb3V0cHV0LmFuaW1hdGlvbnMgPSBhbmltYXRpb25zO1xuXHRcdFx0aWYgKCBub2Rlcy5sZW5ndGggPiAwICkgb3V0cHV0Lm5vZGVzID0gbm9kZXM7XG5cblx0XHR9XG5cblx0XHRvdXRwdXQub2JqZWN0ID0gb2JqZWN0O1xuXG5cdFx0cmV0dXJuIG91dHB1dDtcblxuXHRcdC8vIGV4dHJhY3QgZGF0YSBmcm9tIHRoZSBjYWNoZSBoYXNoXG5cdFx0Ly8gcmVtb3ZlIG1ldGFkYXRhIG9uIGVhY2ggaXRlbVxuXHRcdC8vIGFuZCByZXR1cm4gYXMgYXJyYXlcblx0XHRmdW5jdGlvbiBleHRyYWN0RnJvbUNhY2hlKCBjYWNoZSApIHtcblxuXHRcdFx0Y29uc3QgdmFsdWVzID0gW107XG5cdFx0XHRmb3IgKCBjb25zdCBrZXkgaW4gY2FjaGUgKSB7XG5cblx0XHRcdFx0Y29uc3QgZGF0YSA9IGNhY2hlWyBrZXkgXTtcblx0XHRcdFx0ZGVsZXRlIGRhdGEubWV0YWRhdGE7XG5cdFx0XHRcdHZhbHVlcy5wdXNoKCBkYXRhICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHZhbHVlcztcblxuXHRcdH1cblxuXHR9XG5cblx0Y2xvbmUoIHJlY3Vyc2l2ZSApIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMsIHJlY3Vyc2l2ZSApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSA9IHRydWUgKSB7XG5cblx0XHR0aGlzLm5hbWUgPSBzb3VyY2UubmFtZTtcblxuXHRcdHRoaXMudXAuY29weSggc291cmNlLnVwICk7XG5cblx0XHR0aGlzLnBvc2l0aW9uLmNvcHkoIHNvdXJjZS5wb3NpdGlvbiApO1xuXHRcdHRoaXMucm90YXRpb24ub3JkZXIgPSBzb3VyY2Uucm90YXRpb24ub3JkZXI7XG5cdFx0dGhpcy5xdWF0ZXJuaW9uLmNvcHkoIHNvdXJjZS5xdWF0ZXJuaW9uICk7XG5cdFx0dGhpcy5zY2FsZS5jb3B5KCBzb3VyY2Uuc2NhbGUgKTtcblxuXHRcdHRoaXMubWF0cml4LmNvcHkoIHNvdXJjZS5tYXRyaXggKTtcblx0XHR0aGlzLm1hdHJpeFdvcmxkLmNvcHkoIHNvdXJjZS5tYXRyaXhXb3JsZCApO1xuXG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gc291cmNlLm1hdHJpeEF1dG9VcGRhdGU7XG5cblx0XHR0aGlzLm1hdHJpeFdvcmxkQXV0b1VwZGF0ZSA9IHNvdXJjZS5tYXRyaXhXb3JsZEF1dG9VcGRhdGU7XG5cdFx0dGhpcy5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlID0gc291cmNlLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGU7XG5cblx0XHR0aGlzLmxheWVycy5tYXNrID0gc291cmNlLmxheWVycy5tYXNrO1xuXHRcdHRoaXMudmlzaWJsZSA9IHNvdXJjZS52aXNpYmxlO1xuXG5cdFx0dGhpcy5jYXN0U2hhZG93ID0gc291cmNlLmNhc3RTaGFkb3c7XG5cdFx0dGhpcy5yZWNlaXZlU2hhZG93ID0gc291cmNlLnJlY2VpdmVTaGFkb3c7XG5cblx0XHR0aGlzLmZydXN0dW1DdWxsZWQgPSBzb3VyY2UuZnJ1c3R1bUN1bGxlZDtcblx0XHR0aGlzLnJlbmRlck9yZGVyID0gc291cmNlLnJlbmRlck9yZGVyO1xuXG5cdFx0dGhpcy5hbmltYXRpb25zID0gc291cmNlLmFuaW1hdGlvbnMuc2xpY2UoKTtcblxuXHRcdHRoaXMudXNlckRhdGEgPSBKU09OLnBhcnNlKCBKU09OLnN0cmluZ2lmeSggc291cmNlLnVzZXJEYXRhICkgKTtcblxuXHRcdGlmICggcmVjdXJzaXZlID09PSB0cnVlICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzb3VyY2UuY2hpbGRyZW4ubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGNoaWxkID0gc291cmNlLmNoaWxkcmVuWyBpIF07XG5cdFx0XHRcdHRoaXMuYWRkKCBjaGlsZC5jbG9uZSgpICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5PYmplY3QzRC5ERUZBVUxUX1VQID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgMSwgMCApO1xuT2JqZWN0M0QuREVGQVVMVF9NQVRSSVhfQVVUT19VUERBVEUgPSB0cnVlO1xuT2JqZWN0M0QuREVGQVVMVF9NQVRSSVhfV09STERfQVVUT19VUERBVEUgPSB0cnVlO1xuXG5jb25zdCBfdjAkMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92MSQzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3YyJDIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdjMkMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY29uc3QgX3ZhYiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92YWMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdmJjID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3ZhcCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92YnAgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdmNwID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jbGFzcyBUcmlhbmdsZSB7XG5cblx0Y29uc3RydWN0b3IoIGEgPSBuZXcgVmVjdG9yMygpLCBiID0gbmV3IFZlY3RvcjMoKSwgYyA9IG5ldyBWZWN0b3IzKCkgKSB7XG5cblx0XHR0aGlzLmEgPSBhO1xuXHRcdHRoaXMuYiA9IGI7XG5cdFx0dGhpcy5jID0gYztcblxuXHR9XG5cblx0c3RhdGljIGdldE5vcm1hbCggYSwgYiwgYywgdGFyZ2V0ICkge1xuXG5cdFx0dGFyZ2V0LnN1YlZlY3RvcnMoIGMsIGIgKTtcblx0XHRfdjAkMi5zdWJWZWN0b3JzKCBhLCBiICk7XG5cdFx0dGFyZ2V0LmNyb3NzKCBfdjAkMiApO1xuXG5cdFx0Y29uc3QgdGFyZ2V0TGVuZ3RoU3EgPSB0YXJnZXQubGVuZ3RoU3EoKTtcblx0XHRpZiAoIHRhcmdldExlbmd0aFNxID4gMCApIHtcblxuXHRcdFx0cmV0dXJuIHRhcmdldC5tdWx0aXBseVNjYWxhciggMSAvIE1hdGguc3FydCggdGFyZ2V0TGVuZ3RoU3EgKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRhcmdldC5zZXQoIDAsIDAsIDAgKTtcblxuXHR9XG5cblx0Ly8gc3RhdGljL2luc3RhbmNlIG1ldGhvZCB0byBjYWxjdWxhdGUgYmFyeWNlbnRyaWMgY29vcmRpbmF0ZXNcblx0Ly8gYmFzZWQgb246IGh0dHA6Ly93d3cuYmxhY2twYXduLmNvbS90ZXh0cy9wb2ludGlucG9seS9kZWZhdWx0Lmh0bWxcblx0c3RhdGljIGdldEJhcnljb29yZCggcG9pbnQsIGEsIGIsIGMsIHRhcmdldCApIHtcblxuXHRcdF92MCQyLnN1YlZlY3RvcnMoIGMsIGEgKTtcblx0XHRfdjEkMy5zdWJWZWN0b3JzKCBiLCBhICk7XG5cdFx0X3YyJDIuc3ViVmVjdG9ycyggcG9pbnQsIGEgKTtcblxuXHRcdGNvbnN0IGRvdDAwID0gX3YwJDIuZG90KCBfdjAkMiApO1xuXHRcdGNvbnN0IGRvdDAxID0gX3YwJDIuZG90KCBfdjEkMyApO1xuXHRcdGNvbnN0IGRvdDAyID0gX3YwJDIuZG90KCBfdjIkMiApO1xuXHRcdGNvbnN0IGRvdDExID0gX3YxJDMuZG90KCBfdjEkMyApO1xuXHRcdGNvbnN0IGRvdDEyID0gX3YxJDMuZG90KCBfdjIkMiApO1xuXG5cdFx0Y29uc3QgZGVub20gPSAoIGRvdDAwICogZG90MTEgLSBkb3QwMSAqIGRvdDAxICk7XG5cblx0XHQvLyBjb2xsaW5lYXIgb3Igc2luZ3VsYXIgdHJpYW5nbGVcblx0XHRpZiAoIGRlbm9tID09PSAwICkge1xuXG5cdFx0XHR0YXJnZXQuc2V0KCAwLCAwLCAwICk7XG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGludkRlbm9tID0gMSAvIGRlbm9tO1xuXHRcdGNvbnN0IHUgPSAoIGRvdDExICogZG90MDIgLSBkb3QwMSAqIGRvdDEyICkgKiBpbnZEZW5vbTtcblx0XHRjb25zdCB2ID0gKCBkb3QwMCAqIGRvdDEyIC0gZG90MDEgKiBkb3QwMiApICogaW52RGVub207XG5cblx0XHQvLyBiYXJ5Y2VudHJpYyBjb29yZGluYXRlcyBtdXN0IGFsd2F5cyBzdW0gdG8gMVxuXHRcdHJldHVybiB0YXJnZXQuc2V0KCAxIC0gdSAtIHYsIHYsIHUgKTtcblxuXHR9XG5cblx0c3RhdGljIGNvbnRhaW5zUG9pbnQoIHBvaW50LCBhLCBiLCBjICkge1xuXG5cdFx0Ly8gaWYgdGhlIHRyaWFuZ2xlIGlzIGRlZ2VuZXJhdGUgdGhlbiB3ZSBjYW4ndCBjb250YWluIGEgcG9pbnRcblx0XHRpZiAoIHRoaXMuZ2V0QmFyeWNvb3JkKCBwb2ludCwgYSwgYiwgYywgX3YzJDIgKSA9PT0gbnVsbCApIHtcblxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuICggX3YzJDIueCA+PSAwICkgJiYgKCBfdjMkMi55ID49IDAgKSAmJiAoICggX3YzJDIueCArIF92MyQyLnkgKSA8PSAxICk7XG5cblx0fVxuXG5cdHN0YXRpYyBnZXRJbnRlcnBvbGF0aW9uKCBwb2ludCwgcDEsIHAyLCBwMywgdjEsIHYyLCB2MywgdGFyZ2V0ICkge1xuXG5cdFx0aWYgKCB0aGlzLmdldEJhcnljb29yZCggcG9pbnQsIHAxLCBwMiwgcDMsIF92MyQyICkgPT09IG51bGwgKSB7XG5cblx0XHRcdHRhcmdldC54ID0gMDtcblx0XHRcdHRhcmdldC55ID0gMDtcblx0XHRcdGlmICggJ3onIGluIHRhcmdldCApIHRhcmdldC56ID0gMDtcblx0XHRcdGlmICggJ3cnIGluIHRhcmdldCApIHRhcmdldC53ID0gMDtcblx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0fVxuXG5cdFx0dGFyZ2V0LnNldFNjYWxhciggMCApO1xuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIHYxLCBfdjMkMi54ICk7XG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggdjIsIF92MyQyLnkgKTtcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCB2MywgX3YzJDIueiApO1xuXG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0c3RhdGljIGlzRnJvbnRGYWNpbmcoIGEsIGIsIGMsIGRpcmVjdGlvbiApIHtcblxuXHRcdF92MCQyLnN1YlZlY3RvcnMoIGMsIGIgKTtcblx0XHRfdjEkMy5zdWJWZWN0b3JzKCBhLCBiICk7XG5cblx0XHQvLyBzdHJpY3RseSBmcm9udCBmYWNpbmdcblx0XHRyZXR1cm4gKCBfdjAkMi5jcm9zcyggX3YxJDMgKS5kb3QoIGRpcmVjdGlvbiApIDwgMCApID8gdHJ1ZSA6IGZhbHNlO1xuXG5cdH1cblxuXHRzZXQoIGEsIGIsIGMgKSB7XG5cblx0XHR0aGlzLmEuY29weSggYSApO1xuXHRcdHRoaXMuYi5jb3B5KCBiICk7XG5cdFx0dGhpcy5jLmNvcHkoIGMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tUG9pbnRzQW5kSW5kaWNlcyggcG9pbnRzLCBpMCwgaTEsIGkyICkge1xuXG5cdFx0dGhpcy5hLmNvcHkoIHBvaW50c1sgaTAgXSApO1xuXHRcdHRoaXMuYi5jb3B5KCBwb2ludHNbIGkxIF0gKTtcblx0XHR0aGlzLmMuY29weSggcG9pbnRzWyBpMiBdICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbUF0dHJpYnV0ZUFuZEluZGljZXMoIGF0dHJpYnV0ZSwgaTAsIGkxLCBpMiApIHtcblxuXHRcdHRoaXMuYS5mcm9tQnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGkwICk7XG5cdFx0dGhpcy5iLmZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaTEgKTtcblx0XHR0aGlzLmMuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggYXR0cmlidXRlLCBpMiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxuXHRjb3B5KCB0cmlhbmdsZSApIHtcblxuXHRcdHRoaXMuYS5jb3B5KCB0cmlhbmdsZS5hICk7XG5cdFx0dGhpcy5iLmNvcHkoIHRyaWFuZ2xlLmIgKTtcblx0XHR0aGlzLmMuY29weSggdHJpYW5nbGUuYyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldEFyZWEoKSB7XG5cblx0XHRfdjAkMi5zdWJWZWN0b3JzKCB0aGlzLmMsIHRoaXMuYiApO1xuXHRcdF92MSQzLnN1YlZlY3RvcnMoIHRoaXMuYSwgdGhpcy5iICk7XG5cblx0XHRyZXR1cm4gX3YwJDIuY3Jvc3MoIF92MSQzICkubGVuZ3RoKCkgKiAwLjU7XG5cblx0fVxuXG5cdGdldE1pZHBvaW50KCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LmFkZFZlY3RvcnMoIHRoaXMuYSwgdGhpcy5iICkuYWRkKCB0aGlzLmMgKS5tdWx0aXBseVNjYWxhciggMSAvIDMgKTtcblxuXHR9XG5cblx0Z2V0Tm9ybWFsKCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gVHJpYW5nbGUuZ2V0Tm9ybWFsKCB0aGlzLmEsIHRoaXMuYiwgdGhpcy5jLCB0YXJnZXQgKTtcblxuXHR9XG5cblx0Z2V0UGxhbmUoIHRhcmdldCApIHtcblxuXHRcdHJldHVybiB0YXJnZXQuc2V0RnJvbUNvcGxhbmFyUG9pbnRzKCB0aGlzLmEsIHRoaXMuYiwgdGhpcy5jICk7XG5cblx0fVxuXG5cdGdldEJhcnljb29yZCggcG9pbnQsIHRhcmdldCApIHtcblxuXHRcdHJldHVybiBUcmlhbmdsZS5nZXRCYXJ5Y29vcmQoIHBvaW50LCB0aGlzLmEsIHRoaXMuYiwgdGhpcy5jLCB0YXJnZXQgKTtcblxuXHR9XG5cblx0Z2V0SW50ZXJwb2xhdGlvbiggcG9pbnQsIHYxLCB2MiwgdjMsIHRhcmdldCApIHtcblxuXHRcdHJldHVybiBUcmlhbmdsZS5nZXRJbnRlcnBvbGF0aW9uKCBwb2ludCwgdGhpcy5hLCB0aGlzLmIsIHRoaXMuYywgdjEsIHYyLCB2MywgdGFyZ2V0ICk7XG5cblx0fVxuXG5cdGNvbnRhaW5zUG9pbnQoIHBvaW50ICkge1xuXG5cdFx0cmV0dXJuIFRyaWFuZ2xlLmNvbnRhaW5zUG9pbnQoIHBvaW50LCB0aGlzLmEsIHRoaXMuYiwgdGhpcy5jICk7XG5cblx0fVxuXG5cdGlzRnJvbnRGYWNpbmcoIGRpcmVjdGlvbiApIHtcblxuXHRcdHJldHVybiBUcmlhbmdsZS5pc0Zyb250RmFjaW5nKCB0aGlzLmEsIHRoaXMuYiwgdGhpcy5jLCBkaXJlY3Rpb24gKTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c0JveCggYm94ICkge1xuXG5cdFx0cmV0dXJuIGJveC5pbnRlcnNlY3RzVHJpYW5nbGUoIHRoaXMgKTtcblxuXHR9XG5cblx0Y2xvc2VzdFBvaW50VG9Qb2ludCggcCwgdGFyZ2V0ICkge1xuXG5cdFx0Y29uc3QgYSA9IHRoaXMuYSwgYiA9IHRoaXMuYiwgYyA9IHRoaXMuYztcblx0XHRsZXQgdiwgdztcblxuXHRcdC8vIGFsZ29yaXRobSB0aGFua3MgdG8gUmVhbC1UaW1lIENvbGxpc2lvbiBEZXRlY3Rpb24gYnkgQ2hyaXN0ZXIgRXJpY3Nvbixcblx0XHQvLyBwdWJsaXNoZWQgYnkgTW9yZ2FuIEthdWZtYW5uIFB1Ymxpc2hlcnMsIChjKSAyMDA1IEVsc2V2aWVyIEluYy4sXG5cdFx0Ly8gdW5kZXIgdGhlIGFjY29tcGFueWluZyBsaWNlbnNlOyBzZWUgY2hhcHRlciA1LjEuNSBmb3IgZGV0YWlsZWQgZXhwbGFuYXRpb24uXG5cdFx0Ly8gYmFzaWNhbGx5LCB3ZSdyZSBkaXN0aW5ndWlzaGluZyB3aGljaCBvZiB0aGUgdm9yb25vaSByZWdpb25zIG9mIHRoZSB0cmlhbmdsZVxuXHRcdC8vIHRoZSBwb2ludCBsaWVzIGluIHdpdGggdGhlIG1pbmltdW0gYW1vdW50IG9mIHJlZHVuZGFudCBjb21wdXRhdGlvbi5cblxuXHRcdF92YWIuc3ViVmVjdG9ycyggYiwgYSApO1xuXHRcdF92YWMuc3ViVmVjdG9ycyggYywgYSApO1xuXHRcdF92YXAuc3ViVmVjdG9ycyggcCwgYSApO1xuXHRcdGNvbnN0IGQxID0gX3ZhYi5kb3QoIF92YXAgKTtcblx0XHRjb25zdCBkMiA9IF92YWMuZG90KCBfdmFwICk7XG5cdFx0aWYgKCBkMSA8PSAwICYmIGQyIDw9IDAgKSB7XG5cblx0XHRcdC8vIHZlcnRleCByZWdpb24gb2YgQTsgYmFyeWNlbnRyaWMgY29vcmRzICgxLCAwLCAwKVxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBhICk7XG5cblx0XHR9XG5cblx0XHRfdmJwLnN1YlZlY3RvcnMoIHAsIGIgKTtcblx0XHRjb25zdCBkMyA9IF92YWIuZG90KCBfdmJwICk7XG5cdFx0Y29uc3QgZDQgPSBfdmFjLmRvdCggX3ZicCApO1xuXHRcdGlmICggZDMgPj0gMCAmJiBkNCA8PSBkMyApIHtcblxuXHRcdFx0Ly8gdmVydGV4IHJlZ2lvbiBvZiBCOyBiYXJ5Y2VudHJpYyBjb29yZHMgKDAsIDEsIDApXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGIgKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHZjID0gZDEgKiBkNCAtIGQzICogZDI7XG5cdFx0aWYgKCB2YyA8PSAwICYmIGQxID49IDAgJiYgZDMgPD0gMCApIHtcblxuXHRcdFx0diA9IGQxIC8gKCBkMSAtIGQzICk7XG5cdFx0XHQvLyBlZGdlIHJlZ2lvbiBvZiBBQjsgYmFyeWNlbnRyaWMgY29vcmRzICgxLXYsIHYsIDApXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIGEgKS5hZGRTY2FsZWRWZWN0b3IoIF92YWIsIHYgKTtcblxuXHRcdH1cblxuXHRcdF92Y3Auc3ViVmVjdG9ycyggcCwgYyApO1xuXHRcdGNvbnN0IGQ1ID0gX3ZhYi5kb3QoIF92Y3AgKTtcblx0XHRjb25zdCBkNiA9IF92YWMuZG90KCBfdmNwICk7XG5cdFx0aWYgKCBkNiA+PSAwICYmIGQ1IDw9IGQ2ICkge1xuXG5cdFx0XHQvLyB2ZXJ0ZXggcmVnaW9uIG9mIEM7IGJhcnljZW50cmljIGNvb3JkcyAoMCwgMCwgMSlcblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggYyApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgdmIgPSBkNSAqIGQyIC0gZDEgKiBkNjtcblx0XHRpZiAoIHZiIDw9IDAgJiYgZDIgPj0gMCAmJiBkNiA8PSAwICkge1xuXG5cdFx0XHR3ID0gZDIgLyAoIGQyIC0gZDYgKTtcblx0XHRcdC8vIGVkZ2UgcmVnaW9uIG9mIEFDOyBiYXJ5Y2VudHJpYyBjb29yZHMgKDEtdywgMCwgdylcblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggYSApLmFkZFNjYWxlZFZlY3RvciggX3ZhYywgdyApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgdmEgPSBkMyAqIGQ2IC0gZDUgKiBkNDtcblx0XHRpZiAoIHZhIDw9IDAgJiYgKCBkNCAtIGQzICkgPj0gMCAmJiAoIGQ1IC0gZDYgKSA+PSAwICkge1xuXG5cdFx0XHRfdmJjLnN1YlZlY3RvcnMoIGMsIGIgKTtcblx0XHRcdHcgPSAoIGQ0IC0gZDMgKSAvICggKCBkNCAtIGQzICkgKyAoIGQ1IC0gZDYgKSApO1xuXHRcdFx0Ly8gZWRnZSByZWdpb24gb2YgQkM7IGJhcnljZW50cmljIGNvb3JkcyAoMCwgMS13LCB3KVxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBiICkuYWRkU2NhbGVkVmVjdG9yKCBfdmJjLCB3ICk7IC8vIGVkZ2UgcmVnaW9uIG9mIEJDXG5cblx0XHR9XG5cblx0XHQvLyBmYWNlIHJlZ2lvblxuXHRcdGNvbnN0IGRlbm9tID0gMSAvICggdmEgKyB2YiArIHZjICk7XG5cdFx0Ly8gdSA9IHZhICogZGVub21cblx0XHR2ID0gdmIgKiBkZW5vbTtcblx0XHR3ID0gdmMgKiBkZW5vbTtcblxuXHRcdHJldHVybiB0YXJnZXQuY29weSggYSApLmFkZFNjYWxlZFZlY3RvciggX3ZhYiwgdiApLmFkZFNjYWxlZFZlY3RvciggX3ZhYywgdyApO1xuXG5cdH1cblxuXHRlcXVhbHMoIHRyaWFuZ2xlICkge1xuXG5cdFx0cmV0dXJuIHRyaWFuZ2xlLmEuZXF1YWxzKCB0aGlzLmEgKSAmJiB0cmlhbmdsZS5iLmVxdWFscyggdGhpcy5iICkgJiYgdHJpYW5nbGUuYy5lcXVhbHMoIHRoaXMuYyApO1xuXG5cdH1cblxufVxuXG5jb25zdCBfY29sb3JLZXl3b3JkcyA9IHsgJ2FsaWNlYmx1ZSc6IDB4RjBGOEZGLCAnYW50aXF1ZXdoaXRlJzogMHhGQUVCRDcsICdhcXVhJzogMHgwMEZGRkYsICdhcXVhbWFyaW5lJzogMHg3RkZGRDQsICdhenVyZSc6IDB4RjBGRkZGLFxuXHQnYmVpZ2UnOiAweEY1RjVEQywgJ2Jpc3F1ZSc6IDB4RkZFNEM0LCAnYmxhY2snOiAweDAwMDAwMCwgJ2JsYW5jaGVkYWxtb25kJzogMHhGRkVCQ0QsICdibHVlJzogMHgwMDAwRkYsICdibHVldmlvbGV0JzogMHg4QTJCRTIsXG5cdCdicm93bic6IDB4QTUyQTJBLCAnYnVybHl3b29kJzogMHhERUI4ODcsICdjYWRldGJsdWUnOiAweDVGOUVBMCwgJ2NoYXJ0cmV1c2UnOiAweDdGRkYwMCwgJ2Nob2NvbGF0ZSc6IDB4RDI2OTFFLCAnY29yYWwnOiAweEZGN0Y1MCxcblx0J2Nvcm5mbG93ZXJibHVlJzogMHg2NDk1RUQsICdjb3Juc2lsayc6IDB4RkZGOERDLCAnY3JpbXNvbic6IDB4REMxNDNDLCAnY3lhbic6IDB4MDBGRkZGLCAnZGFya2JsdWUnOiAweDAwMDA4QiwgJ2RhcmtjeWFuJzogMHgwMDhCOEIsXG5cdCdkYXJrZ29sZGVucm9kJzogMHhCODg2MEIsICdkYXJrZ3JheSc6IDB4QTlBOUE5LCAnZGFya2dyZWVuJzogMHgwMDY0MDAsICdkYXJrZ3JleSc6IDB4QTlBOUE5LCAnZGFya2toYWtpJzogMHhCREI3NkIsICdkYXJrbWFnZW50YSc6IDB4OEIwMDhCLFxuXHQnZGFya29saXZlZ3JlZW4nOiAweDU1NkIyRiwgJ2RhcmtvcmFuZ2UnOiAweEZGOEMwMCwgJ2RhcmtvcmNoaWQnOiAweDk5MzJDQywgJ2RhcmtyZWQnOiAweDhCMDAwMCwgJ2RhcmtzYWxtb24nOiAweEU5OTY3QSwgJ2RhcmtzZWFncmVlbic6IDB4OEZCQzhGLFxuXHQnZGFya3NsYXRlYmx1ZSc6IDB4NDgzRDhCLCAnZGFya3NsYXRlZ3JheSc6IDB4MkY0RjRGLCAnZGFya3NsYXRlZ3JleSc6IDB4MkY0RjRGLCAnZGFya3R1cnF1b2lzZSc6IDB4MDBDRUQxLCAnZGFya3Zpb2xldCc6IDB4OTQwMEQzLFxuXHQnZGVlcHBpbmsnOiAweEZGMTQ5MywgJ2RlZXBza3libHVlJzogMHgwMEJGRkYsICdkaW1ncmF5JzogMHg2OTY5NjksICdkaW1ncmV5JzogMHg2OTY5NjksICdkb2RnZXJibHVlJzogMHgxRTkwRkYsICdmaXJlYnJpY2snOiAweEIyMjIyMixcblx0J2Zsb3JhbHdoaXRlJzogMHhGRkZBRjAsICdmb3Jlc3RncmVlbic6IDB4MjI4QjIyLCAnZnVjaHNpYSc6IDB4RkYwMEZGLCAnZ2FpbnNib3JvJzogMHhEQ0RDREMsICdnaG9zdHdoaXRlJzogMHhGOEY4RkYsICdnb2xkJzogMHhGRkQ3MDAsXG5cdCdnb2xkZW5yb2QnOiAweERBQTUyMCwgJ2dyYXknOiAweDgwODA4MCwgJ2dyZWVuJzogMHgwMDgwMDAsICdncmVlbnllbGxvdyc6IDB4QURGRjJGLCAnZ3JleSc6IDB4ODA4MDgwLCAnaG9uZXlkZXcnOiAweEYwRkZGMCwgJ2hvdHBpbmsnOiAweEZGNjlCNCxcblx0J2luZGlhbnJlZCc6IDB4Q0Q1QzVDLCAnaW5kaWdvJzogMHg0QjAwODIsICdpdm9yeSc6IDB4RkZGRkYwLCAna2hha2knOiAweEYwRTY4QywgJ2xhdmVuZGVyJzogMHhFNkU2RkEsICdsYXZlbmRlcmJsdXNoJzogMHhGRkYwRjUsICdsYXduZ3JlZW4nOiAweDdDRkMwMCxcblx0J2xlbW9uY2hpZmZvbic6IDB4RkZGQUNELCAnbGlnaHRibHVlJzogMHhBREQ4RTYsICdsaWdodGNvcmFsJzogMHhGMDgwODAsICdsaWdodGN5YW4nOiAweEUwRkZGRiwgJ2xpZ2h0Z29sZGVucm9keWVsbG93JzogMHhGQUZBRDIsICdsaWdodGdyYXknOiAweEQzRDNEMyxcblx0J2xpZ2h0Z3JlZW4nOiAweDkwRUU5MCwgJ2xpZ2h0Z3JleSc6IDB4RDNEM0QzLCAnbGlnaHRwaW5rJzogMHhGRkI2QzEsICdsaWdodHNhbG1vbic6IDB4RkZBMDdBLCAnbGlnaHRzZWFncmVlbic6IDB4MjBCMkFBLCAnbGlnaHRza3libHVlJzogMHg4N0NFRkEsXG5cdCdsaWdodHNsYXRlZ3JheSc6IDB4Nzc4ODk5LCAnbGlnaHRzbGF0ZWdyZXknOiAweDc3ODg5OSwgJ2xpZ2h0c3RlZWxibHVlJzogMHhCMEM0REUsICdsaWdodHllbGxvdyc6IDB4RkZGRkUwLCAnbGltZSc6IDB4MDBGRjAwLCAnbGltZWdyZWVuJzogMHgzMkNEMzIsXG5cdCdsaW5lbic6IDB4RkFGMEU2LCAnbWFnZW50YSc6IDB4RkYwMEZGLCAnbWFyb29uJzogMHg4MDAwMDAsICdtZWRpdW1hcXVhbWFyaW5lJzogMHg2NkNEQUEsICdtZWRpdW1ibHVlJzogMHgwMDAwQ0QsICdtZWRpdW1vcmNoaWQnOiAweEJBNTVEMyxcblx0J21lZGl1bXB1cnBsZSc6IDB4OTM3MERCLCAnbWVkaXVtc2VhZ3JlZW4nOiAweDNDQjM3MSwgJ21lZGl1bXNsYXRlYmx1ZSc6IDB4N0I2OEVFLCAnbWVkaXVtc3ByaW5nZ3JlZW4nOiAweDAwRkE5QSwgJ21lZGl1bXR1cnF1b2lzZSc6IDB4NDhEMUNDLFxuXHQnbWVkaXVtdmlvbGV0cmVkJzogMHhDNzE1ODUsICdtaWRuaWdodGJsdWUnOiAweDE5MTk3MCwgJ21pbnRjcmVhbSc6IDB4RjVGRkZBLCAnbWlzdHlyb3NlJzogMHhGRkU0RTEsICdtb2NjYXNpbic6IDB4RkZFNEI1LCAnbmF2YWpvd2hpdGUnOiAweEZGREVBRCxcblx0J25hdnknOiAweDAwMDA4MCwgJ29sZGxhY2UnOiAweEZERjVFNiwgJ29saXZlJzogMHg4MDgwMDAsICdvbGl2ZWRyYWInOiAweDZCOEUyMywgJ29yYW5nZSc6IDB4RkZBNTAwLCAnb3JhbmdlcmVkJzogMHhGRjQ1MDAsICdvcmNoaWQnOiAweERBNzBENixcblx0J3BhbGVnb2xkZW5yb2QnOiAweEVFRThBQSwgJ3BhbGVncmVlbic6IDB4OThGQjk4LCAncGFsZXR1cnF1b2lzZSc6IDB4QUZFRUVFLCAncGFsZXZpb2xldHJlZCc6IDB4REI3MDkzLCAncGFwYXlhd2hpcCc6IDB4RkZFRkQ1LCAncGVhY2hwdWZmJzogMHhGRkRBQjksXG5cdCdwZXJ1JzogMHhDRDg1M0YsICdwaW5rJzogMHhGRkMwQ0IsICdwbHVtJzogMHhEREEwREQsICdwb3dkZXJibHVlJzogMHhCMEUwRTYsICdwdXJwbGUnOiAweDgwMDA4MCwgJ3JlYmVjY2FwdXJwbGUnOiAweDY2MzM5OSwgJ3JlZCc6IDB4RkYwMDAwLCAncm9zeWJyb3duJzogMHhCQzhGOEYsXG5cdCdyb3lhbGJsdWUnOiAweDQxNjlFMSwgJ3NhZGRsZWJyb3duJzogMHg4QjQ1MTMsICdzYWxtb24nOiAweEZBODA3MiwgJ3NhbmR5YnJvd24nOiAweEY0QTQ2MCwgJ3NlYWdyZWVuJzogMHgyRThCNTcsICdzZWFzaGVsbCc6IDB4RkZGNUVFLFxuXHQnc2llbm5hJzogMHhBMDUyMkQsICdzaWx2ZXInOiAweEMwQzBDMCwgJ3NreWJsdWUnOiAweDg3Q0VFQiwgJ3NsYXRlYmx1ZSc6IDB4NkE1QUNELCAnc2xhdGVncmF5JzogMHg3MDgwOTAsICdzbGF0ZWdyZXknOiAweDcwODA5MCwgJ3Nub3cnOiAweEZGRkFGQSxcblx0J3NwcmluZ2dyZWVuJzogMHgwMEZGN0YsICdzdGVlbGJsdWUnOiAweDQ2ODJCNCwgJ3Rhbic6IDB4RDJCNDhDLCAndGVhbCc6IDB4MDA4MDgwLCAndGhpc3RsZSc6IDB4RDhCRkQ4LCAndG9tYXRvJzogMHhGRjYzNDcsICd0dXJxdW9pc2UnOiAweDQwRTBEMCxcblx0J3Zpb2xldCc6IDB4RUU4MkVFLCAnd2hlYXQnOiAweEY1REVCMywgJ3doaXRlJzogMHhGRkZGRkYsICd3aGl0ZXNtb2tlJzogMHhGNUY1RjUsICd5ZWxsb3cnOiAweEZGRkYwMCwgJ3llbGxvd2dyZWVuJzogMHg5QUNEMzIgfTtcblxuY29uc3QgX2hzbEEgPSB7IGg6IDAsIHM6IDAsIGw6IDAgfTtcbmNvbnN0IF9oc2xCID0geyBoOiAwLCBzOiAwLCBsOiAwIH07XG5cbmZ1bmN0aW9uIGh1ZTJyZ2IoIHAsIHEsIHQgKSB7XG5cblx0aWYgKCB0IDwgMCApIHQgKz0gMTtcblx0aWYgKCB0ID4gMSApIHQgLT0gMTtcblx0aWYgKCB0IDwgMSAvIDYgKSByZXR1cm4gcCArICggcSAtIHAgKSAqIDYgKiB0O1xuXHRpZiAoIHQgPCAxIC8gMiApIHJldHVybiBxO1xuXHRpZiAoIHQgPCAyIC8gMyApIHJldHVybiBwICsgKCBxIC0gcCApICogNiAqICggMiAvIDMgLSB0ICk7XG5cdHJldHVybiBwO1xuXG59XG5cbmNsYXNzIENvbG9yIHtcblxuXHRjb25zdHJ1Y3RvciggciwgZywgYiApIHtcblxuXHRcdHRoaXMuaXNDb2xvciA9IHRydWU7XG5cblx0XHR0aGlzLnIgPSAxO1xuXHRcdHRoaXMuZyA9IDE7XG5cdFx0dGhpcy5iID0gMTtcblxuXHRcdHJldHVybiB0aGlzLnNldCggciwgZywgYiApO1xuXG5cdH1cblxuXHRzZXQoIHIsIGcsIGIgKSB7XG5cblx0XHRpZiAoIGcgPT09IHVuZGVmaW5lZCAmJiBiID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdC8vIHIgaXMgVEhSRUUuQ29sb3IsIGhleCBvciBzdHJpbmdcblxuXHRcdFx0Y29uc3QgdmFsdWUgPSByO1xuXG5cdFx0XHRpZiAoIHZhbHVlICYmIHZhbHVlLmlzQ29sb3IgKSB7XG5cblx0XHRcdFx0dGhpcy5jb3B5KCB2YWx1ZSApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInICkge1xuXG5cdFx0XHRcdHRoaXMuc2V0SGV4KCB2YWx1ZSApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCB0eXBlb2YgdmFsdWUgPT09ICdzdHJpbmcnICkge1xuXG5cdFx0XHRcdHRoaXMuc2V0U3R5bGUoIHZhbHVlICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuc2V0UkdCKCByLCBnLCBiICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0U2NhbGFyKCBzY2FsYXIgKSB7XG5cblx0XHR0aGlzLnIgPSBzY2FsYXI7XG5cdFx0dGhpcy5nID0gc2NhbGFyO1xuXHRcdHRoaXMuYiA9IHNjYWxhcjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRIZXgoIGhleCwgY29sb3JTcGFjZSA9IFNSR0JDb2xvclNwYWNlICkge1xuXG5cdFx0aGV4ID0gTWF0aC5mbG9vciggaGV4ICk7XG5cblx0XHR0aGlzLnIgPSAoIGhleCA+PiAxNiAmIDI1NSApIC8gMjU1O1xuXHRcdHRoaXMuZyA9ICggaGV4ID4+IDggJiAyNTUgKSAvIDI1NTtcblx0XHR0aGlzLmIgPSAoIGhleCAmIDI1NSApIC8gMjU1O1xuXG5cdFx0Q29sb3JNYW5hZ2VtZW50LnRvV29ya2luZ0NvbG9yU3BhY2UoIHRoaXMsIGNvbG9yU3BhY2UgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRSR0IoIHIsIGcsIGIsIGNvbG9yU3BhY2UgPSBDb2xvck1hbmFnZW1lbnQud29ya2luZ0NvbG9yU3BhY2UgKSB7XG5cblx0XHR0aGlzLnIgPSByO1xuXHRcdHRoaXMuZyA9IGc7XG5cdFx0dGhpcy5iID0gYjtcblxuXHRcdENvbG9yTWFuYWdlbWVudC50b1dvcmtpbmdDb2xvclNwYWNlKCB0aGlzLCBjb2xvclNwYWNlICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0SFNMKCBoLCBzLCBsLCBjb2xvclNwYWNlID0gQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlICkge1xuXG5cdFx0Ly8gaCxzLGwgcmFuZ2VzIGFyZSBpbiAwLjAgLSAxLjBcblx0XHRoID0gZXVjbGlkZWFuTW9kdWxvKCBoLCAxICk7XG5cdFx0cyA9IGNsYW1wKCBzLCAwLCAxICk7XG5cdFx0bCA9IGNsYW1wKCBsLCAwLCAxICk7XG5cblx0XHRpZiAoIHMgPT09IDAgKSB7XG5cblx0XHRcdHRoaXMuciA9IHRoaXMuZyA9IHRoaXMuYiA9IGw7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zdCBwID0gbCA8PSAwLjUgPyBsICogKCAxICsgcyApIDogbCArIHMgLSAoIGwgKiBzICk7XG5cdFx0XHRjb25zdCBxID0gKCAyICogbCApIC0gcDtcblxuXHRcdFx0dGhpcy5yID0gaHVlMnJnYiggcSwgcCwgaCArIDEgLyAzICk7XG5cdFx0XHR0aGlzLmcgPSBodWUycmdiKCBxLCBwLCBoICk7XG5cdFx0XHR0aGlzLmIgPSBodWUycmdiKCBxLCBwLCBoIC0gMSAvIDMgKTtcblxuXHRcdH1cblxuXHRcdENvbG9yTWFuYWdlbWVudC50b1dvcmtpbmdDb2xvclNwYWNlKCB0aGlzLCBjb2xvclNwYWNlICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0U3R5bGUoIHN0eWxlLCBjb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2UgKSB7XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVBbHBoYSggc3RyaW5nICkge1xuXG5cdFx0XHRpZiAoIHN0cmluZyA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xuXG5cdFx0XHRpZiAoIHBhcnNlRmxvYXQoIHN0cmluZyApIDwgMSApIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5Db2xvcjogQWxwaGEgY29tcG9uZW50IG9mICcgKyBzdHlsZSArICcgd2lsbCBiZSBpZ25vcmVkLicgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cblx0XHRsZXQgbTtcblxuXHRcdGlmICggbSA9IC9eKFxcdyspXFwoKFteXFwpXSopXFwpLy5leGVjKCBzdHlsZSApICkge1xuXG5cdFx0XHQvLyByZ2IgLyBoc2xcblxuXHRcdFx0bGV0IGNvbG9yO1xuXHRcdFx0Y29uc3QgbmFtZSA9IG1bIDEgXTtcblx0XHRcdGNvbnN0IGNvbXBvbmVudHMgPSBtWyAyIF07XG5cblx0XHRcdHN3aXRjaCAoIG5hbWUgKSB7XG5cblx0XHRcdFx0Y2FzZSAncmdiJzpcblx0XHRcdFx0Y2FzZSAncmdiYSc6XG5cblx0XHRcdFx0XHRpZiAoIGNvbG9yID0gL15cXHMqKFxcZCspXFxzKixcXHMqKFxcZCspXFxzKixcXHMqKFxcZCspXFxzKig/OixcXHMqKFxcZCpcXC4/XFxkKylcXHMqKT8kLy5leGVjKCBjb21wb25lbnRzICkgKSB7XG5cblx0XHRcdFx0XHRcdC8vIHJnYigyNTUsMCwwKSByZ2JhKDI1NSwwLDAsMC41KVxuXG5cdFx0XHRcdFx0XHRoYW5kbGVBbHBoYSggY29sb3JbIDQgXSApO1xuXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy5zZXRSR0IoXG5cdFx0XHRcdFx0XHRcdE1hdGgubWluKCAyNTUsIHBhcnNlSW50KCBjb2xvclsgMSBdLCAxMCApICkgLyAyNTUsXG5cdFx0XHRcdFx0XHRcdE1hdGgubWluKCAyNTUsIHBhcnNlSW50KCBjb2xvclsgMiBdLCAxMCApICkgLyAyNTUsXG5cdFx0XHRcdFx0XHRcdE1hdGgubWluKCAyNTUsIHBhcnNlSW50KCBjb2xvclsgMyBdLCAxMCApICkgLyAyNTUsXG5cdFx0XHRcdFx0XHRcdGNvbG9yU3BhY2Vcblx0XHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoIGNvbG9yID0gL15cXHMqKFxcZCspXFwlXFxzKixcXHMqKFxcZCspXFwlXFxzKixcXHMqKFxcZCspXFwlXFxzKig/OixcXHMqKFxcZCpcXC4/XFxkKylcXHMqKT8kLy5leGVjKCBjb21wb25lbnRzICkgKSB7XG5cblx0XHRcdFx0XHRcdC8vIHJnYigxMDAlLDAlLDAlKSByZ2JhKDEwMCUsMCUsMCUsMC41KVxuXG5cdFx0XHRcdFx0XHRoYW5kbGVBbHBoYSggY29sb3JbIDQgXSApO1xuXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy5zZXRSR0IoXG5cdFx0XHRcdFx0XHRcdE1hdGgubWluKCAxMDAsIHBhcnNlSW50KCBjb2xvclsgMSBdLCAxMCApICkgLyAxMDAsXG5cdFx0XHRcdFx0XHRcdE1hdGgubWluKCAxMDAsIHBhcnNlSW50KCBjb2xvclsgMiBdLCAxMCApICkgLyAxMDAsXG5cdFx0XHRcdFx0XHRcdE1hdGgubWluKCAxMDAsIHBhcnNlSW50KCBjb2xvclsgMyBdLCAxMCApICkgLyAxMDAsXG5cdFx0XHRcdFx0XHRcdGNvbG9yU3BhY2Vcblx0XHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlICdoc2wnOlxuXHRcdFx0XHRjYXNlICdoc2xhJzpcblxuXHRcdFx0XHRcdGlmICggY29sb3IgPSAvXlxccyooXFxkKlxcLj9cXGQrKVxccyosXFxzKihcXGQqXFwuP1xcZCspXFwlXFxzKixcXHMqKFxcZCpcXC4/XFxkKylcXCVcXHMqKD86LFxccyooXFxkKlxcLj9cXGQrKVxccyopPyQvLmV4ZWMoIGNvbXBvbmVudHMgKSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gaHNsKDEyMCw1MCUsNTAlKSBoc2xhKDEyMCw1MCUsNTAlLDAuNSlcblxuXHRcdFx0XHRcdFx0aGFuZGxlQWxwaGEoIGNvbG9yWyA0IF0gKTtcblxuXHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMuc2V0SFNMKFxuXHRcdFx0XHRcdFx0XHRwYXJzZUZsb2F0KCBjb2xvclsgMSBdICkgLyAzNjAsXG5cdFx0XHRcdFx0XHRcdHBhcnNlRmxvYXQoIGNvbG9yWyAyIF0gKSAvIDEwMCxcblx0XHRcdFx0XHRcdFx0cGFyc2VGbG9hdCggY29sb3JbIDMgXSApIC8gMTAwLFxuXHRcdFx0XHRcdFx0XHRjb2xvclNwYWNlXG5cdFx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0ZGVmYXVsdDpcblxuXHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkNvbG9yOiBVbmtub3duIGNvbG9yIG1vZGVsICcgKyBzdHlsZSApO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2UgaWYgKCBtID0gL15cXCMoW0EtRmEtZlxcZF0rKSQvLmV4ZWMoIHN0eWxlICkgKSB7XG5cblx0XHRcdC8vIGhleCBjb2xvclxuXG5cdFx0XHRjb25zdCBoZXggPSBtWyAxIF07XG5cdFx0XHRjb25zdCBzaXplID0gaGV4Lmxlbmd0aDtcblxuXHRcdFx0aWYgKCBzaXplID09PSAzICkge1xuXG5cdFx0XHRcdC8vICNmZjBcblx0XHRcdFx0cmV0dXJuIHRoaXMuc2V0UkdCKFxuXHRcdFx0XHRcdHBhcnNlSW50KCBoZXguY2hhckF0KCAwICksIDE2ICkgLyAxNSxcblx0XHRcdFx0XHRwYXJzZUludCggaGV4LmNoYXJBdCggMSApLCAxNiApIC8gMTUsXG5cdFx0XHRcdFx0cGFyc2VJbnQoIGhleC5jaGFyQXQoIDIgKSwgMTYgKSAvIDE1LFxuXHRcdFx0XHRcdGNvbG9yU3BhY2Vcblx0XHRcdFx0KTtcblxuXHRcdFx0fSBlbHNlIGlmICggc2l6ZSA9PT0gNiApIHtcblxuXHRcdFx0XHQvLyAjZmYwMDAwXG5cdFx0XHRcdHJldHVybiB0aGlzLnNldEhleCggcGFyc2VJbnQoIGhleCwgMTYgKSwgY29sb3JTcGFjZSApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkNvbG9yOiBJbnZhbGlkIGhleCBjb2xvciAnICsgc3R5bGUgKTtcblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIGlmICggc3R5bGUgJiYgc3R5bGUubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0cmV0dXJuIHRoaXMuc2V0Q29sb3JOYW1lKCBzdHlsZSwgY29sb3JTcGFjZSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldENvbG9yTmFtZSggc3R5bGUsIGNvbG9yU3BhY2UgPSBTUkdCQ29sb3JTcGFjZSApIHtcblxuXHRcdC8vIGNvbG9yIGtleXdvcmRzXG5cdFx0Y29uc3QgaGV4ID0gX2NvbG9yS2V5d29yZHNbIHN0eWxlLnRvTG93ZXJDYXNlKCkgXTtcblxuXHRcdGlmICggaGV4ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdC8vIHJlZFxuXHRcdFx0dGhpcy5zZXRIZXgoIGhleCwgY29sb3JTcGFjZSApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gdW5rbm93biBjb2xvclxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQ29sb3I6IFVua25vd24gY29sb3IgJyArIHN0eWxlICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMuciwgdGhpcy5nLCB0aGlzLmIgKTtcblxuXHR9XG5cblx0Y29weSggY29sb3IgKSB7XG5cblx0XHR0aGlzLnIgPSBjb2xvci5yO1xuXHRcdHRoaXMuZyA9IGNvbG9yLmc7XG5cdFx0dGhpcy5iID0gY29sb3IuYjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb3B5U1JHQlRvTGluZWFyKCBjb2xvciApIHtcblxuXHRcdHRoaXMuciA9IFNSR0JUb0xpbmVhciggY29sb3IuciApO1xuXHRcdHRoaXMuZyA9IFNSR0JUb0xpbmVhciggY29sb3IuZyApO1xuXHRcdHRoaXMuYiA9IFNSR0JUb0xpbmVhciggY29sb3IuYiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvcHlMaW5lYXJUb1NSR0IoIGNvbG9yICkge1xuXG5cdFx0dGhpcy5yID0gTGluZWFyVG9TUkdCKCBjb2xvci5yICk7XG5cdFx0dGhpcy5nID0gTGluZWFyVG9TUkdCKCBjb2xvci5nICk7XG5cdFx0dGhpcy5iID0gTGluZWFyVG9TUkdCKCBjb2xvci5iICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29udmVydFNSR0JUb0xpbmVhcigpIHtcblxuXHRcdHRoaXMuY29weVNSR0JUb0xpbmVhciggdGhpcyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvbnZlcnRMaW5lYXJUb1NSR0IoKSB7XG5cblx0XHR0aGlzLmNvcHlMaW5lYXJUb1NSR0IoIHRoaXMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRIZXgoIGNvbG9yU3BhY2UgPSBTUkdCQ29sb3JTcGFjZSApIHtcblxuXHRcdENvbG9yTWFuYWdlbWVudC5mcm9tV29ya2luZ0NvbG9yU3BhY2UoIF9jb2xvci5jb3B5KCB0aGlzICksIGNvbG9yU3BhY2UgKTtcblxuXHRcdHJldHVybiBNYXRoLnJvdW5kKCBjbGFtcCggX2NvbG9yLnIgKiAyNTUsIDAsIDI1NSApICkgKiA2NTUzNiArIE1hdGgucm91bmQoIGNsYW1wKCBfY29sb3IuZyAqIDI1NSwgMCwgMjU1ICkgKSAqIDI1NiArIE1hdGgucm91bmQoIGNsYW1wKCBfY29sb3IuYiAqIDI1NSwgMCwgMjU1ICkgKTtcblxuXHR9XG5cblx0Z2V0SGV4U3RyaW5nKCBjb2xvclNwYWNlID0gU1JHQkNvbG9yU3BhY2UgKSB7XG5cblx0XHRyZXR1cm4gKCAnMDAwMDAwJyArIHRoaXMuZ2V0SGV4KCBjb2xvclNwYWNlICkudG9TdHJpbmcoIDE2ICkgKS5zbGljZSggLSA2ICk7XG5cblx0fVxuXG5cdGdldEhTTCggdGFyZ2V0LCBjb2xvclNwYWNlID0gQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlICkge1xuXG5cdFx0Ly8gaCxzLGwgcmFuZ2VzIGFyZSBpbiAwLjAgLSAxLjBcblxuXHRcdENvbG9yTWFuYWdlbWVudC5mcm9tV29ya2luZ0NvbG9yU3BhY2UoIF9jb2xvci5jb3B5KCB0aGlzICksIGNvbG9yU3BhY2UgKTtcblxuXHRcdGNvbnN0IHIgPSBfY29sb3IuciwgZyA9IF9jb2xvci5nLCBiID0gX2NvbG9yLmI7XG5cblx0XHRjb25zdCBtYXggPSBNYXRoLm1heCggciwgZywgYiApO1xuXHRcdGNvbnN0IG1pbiA9IE1hdGgubWluKCByLCBnLCBiICk7XG5cblx0XHRsZXQgaHVlLCBzYXR1cmF0aW9uO1xuXHRcdGNvbnN0IGxpZ2h0bmVzcyA9ICggbWluICsgbWF4ICkgLyAyLjA7XG5cblx0XHRpZiAoIG1pbiA9PT0gbWF4ICkge1xuXG5cdFx0XHRodWUgPSAwO1xuXHRcdFx0c2F0dXJhdGlvbiA9IDA7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zdCBkZWx0YSA9IG1heCAtIG1pbjtcblxuXHRcdFx0c2F0dXJhdGlvbiA9IGxpZ2h0bmVzcyA8PSAwLjUgPyBkZWx0YSAvICggbWF4ICsgbWluICkgOiBkZWx0YSAvICggMiAtIG1heCAtIG1pbiApO1xuXG5cdFx0XHRzd2l0Y2ggKCBtYXggKSB7XG5cblx0XHRcdFx0Y2FzZSByOiBodWUgPSAoIGcgLSBiICkgLyBkZWx0YSArICggZyA8IGIgPyA2IDogMCApOyBicmVhaztcblx0XHRcdFx0Y2FzZSBnOiBodWUgPSAoIGIgLSByICkgLyBkZWx0YSArIDI7IGJyZWFrO1xuXHRcdFx0XHRjYXNlIGI6IGh1ZSA9ICggciAtIGcgKSAvIGRlbHRhICsgNDsgYnJlYWs7XG5cblx0XHRcdH1cblxuXHRcdFx0aHVlIC89IDY7XG5cblx0XHR9XG5cblx0XHR0YXJnZXQuaCA9IGh1ZTtcblx0XHR0YXJnZXQucyA9IHNhdHVyYXRpb247XG5cdFx0dGFyZ2V0LmwgPSBsaWdodG5lc3M7XG5cblx0XHRyZXR1cm4gdGFyZ2V0O1xuXG5cdH1cblxuXHRnZXRSR0IoIHRhcmdldCwgY29sb3JTcGFjZSA9IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZSApIHtcblxuXHRcdENvbG9yTWFuYWdlbWVudC5mcm9tV29ya2luZ0NvbG9yU3BhY2UoIF9jb2xvci5jb3B5KCB0aGlzICksIGNvbG9yU3BhY2UgKTtcblxuXHRcdHRhcmdldC5yID0gX2NvbG9yLnI7XG5cdFx0dGFyZ2V0LmcgPSBfY29sb3IuZztcblx0XHR0YXJnZXQuYiA9IF9jb2xvci5iO1xuXG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0Z2V0U3R5bGUoIGNvbG9yU3BhY2UgPSBTUkdCQ29sb3JTcGFjZSApIHtcblxuXHRcdENvbG9yTWFuYWdlbWVudC5mcm9tV29ya2luZ0NvbG9yU3BhY2UoIF9jb2xvci5jb3B5KCB0aGlzICksIGNvbG9yU3BhY2UgKTtcblxuXHRcdGNvbnN0IHIgPSBfY29sb3IuciwgZyA9IF9jb2xvci5nLCBiID0gX2NvbG9yLmI7XG5cblx0XHRpZiAoIGNvbG9yU3BhY2UgIT09IFNSR0JDb2xvclNwYWNlICkge1xuXG5cdFx0XHQvLyBSZXF1aXJlcyBDU1MgQ29sb3IgTW9kdWxlIExldmVsIDQgKGh0dHBzOi8vd3d3LnczLm9yZy9UUi9jc3MtY29sb3ItNC8pLlxuXHRcdFx0cmV0dXJuIGBjb2xvcigkeyBjb2xvclNwYWNlIH0gJHsgci50b0ZpeGVkKCAzICkgfSAkeyBnLnRvRml4ZWQoIDMgKSB9ICR7IGIudG9GaXhlZCggMyApIH0pYDtcblxuXHRcdH1cblxuXHRcdHJldHVybiBgcmdiKCR7IE1hdGgucm91bmQoIHIgKiAyNTUgKSB9LCR7IE1hdGgucm91bmQoIGcgKiAyNTUgKSB9LCR7IE1hdGgucm91bmQoIGIgKiAyNTUgKSB9KWA7XG5cblx0fVxuXG5cdG9mZnNldEhTTCggaCwgcywgbCApIHtcblxuXHRcdHRoaXMuZ2V0SFNMKCBfaHNsQSApO1xuXG5cdFx0cmV0dXJuIHRoaXMuc2V0SFNMKCBfaHNsQS5oICsgaCwgX2hzbEEucyArIHMsIF9oc2xBLmwgKyBsICk7XG5cblx0fVxuXG5cdGFkZCggY29sb3IgKSB7XG5cblx0XHR0aGlzLnIgKz0gY29sb3Iucjtcblx0XHR0aGlzLmcgKz0gY29sb3IuZztcblx0XHR0aGlzLmIgKz0gY29sb3IuYjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhZGRDb2xvcnMoIGNvbG9yMSwgY29sb3IyICkge1xuXG5cdFx0dGhpcy5yID0gY29sb3IxLnIgKyBjb2xvcjIucjtcblx0XHR0aGlzLmcgPSBjb2xvcjEuZyArIGNvbG9yMi5nO1xuXHRcdHRoaXMuYiA9IGNvbG9yMS5iICsgY29sb3IyLmI7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkU2NhbGFyKCBzICkge1xuXG5cdFx0dGhpcy5yICs9IHM7XG5cdFx0dGhpcy5nICs9IHM7XG5cdFx0dGhpcy5iICs9IHM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3ViKCBjb2xvciApIHtcblxuXHRcdHRoaXMuciA9IE1hdGgubWF4KCAwLCB0aGlzLnIgLSBjb2xvci5yICk7XG5cdFx0dGhpcy5nID0gTWF0aC5tYXgoIDAsIHRoaXMuZyAtIGNvbG9yLmcgKTtcblx0XHR0aGlzLmIgPSBNYXRoLm1heCggMCwgdGhpcy5iIC0gY29sb3IuYiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5KCBjb2xvciApIHtcblxuXHRcdHRoaXMuciAqPSBjb2xvci5yO1xuXHRcdHRoaXMuZyAqPSBjb2xvci5nO1xuXHRcdHRoaXMuYiAqPSBjb2xvci5iO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG11bHRpcGx5U2NhbGFyKCBzICkge1xuXG5cdFx0dGhpcy5yICo9IHM7XG5cdFx0dGhpcy5nICo9IHM7XG5cdFx0dGhpcy5iICo9IHM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bGVycCggY29sb3IsIGFscGhhICkge1xuXG5cdFx0dGhpcy5yICs9ICggY29sb3IuciAtIHRoaXMuciApICogYWxwaGE7XG5cdFx0dGhpcy5nICs9ICggY29sb3IuZyAtIHRoaXMuZyApICogYWxwaGE7XG5cdFx0dGhpcy5iICs9ICggY29sb3IuYiAtIHRoaXMuYiApICogYWxwaGE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bGVycENvbG9ycyggY29sb3IxLCBjb2xvcjIsIGFscGhhICkge1xuXG5cdFx0dGhpcy5yID0gY29sb3IxLnIgKyAoIGNvbG9yMi5yIC0gY29sb3IxLnIgKSAqIGFscGhhO1xuXHRcdHRoaXMuZyA9IGNvbG9yMS5nICsgKCBjb2xvcjIuZyAtIGNvbG9yMS5nICkgKiBhbHBoYTtcblx0XHR0aGlzLmIgPSBjb2xvcjEuYiArICggY29sb3IyLmIgLSBjb2xvcjEuYiApICogYWxwaGE7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bGVycEhTTCggY29sb3IsIGFscGhhICkge1xuXG5cdFx0dGhpcy5nZXRIU0woIF9oc2xBICk7XG5cdFx0Y29sb3IuZ2V0SFNMKCBfaHNsQiApO1xuXG5cdFx0Y29uc3QgaCA9IGxlcnAoIF9oc2xBLmgsIF9oc2xCLmgsIGFscGhhICk7XG5cdFx0Y29uc3QgcyA9IGxlcnAoIF9oc2xBLnMsIF9oc2xCLnMsIGFscGhhICk7XG5cdFx0Y29uc3QgbCA9IGxlcnAoIF9oc2xBLmwsIF9oc2xCLmwsIGFscGhhICk7XG5cblx0XHR0aGlzLnNldEhTTCggaCwgcywgbCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21WZWN0b3IzKCB2ICkge1xuXG5cdFx0dGhpcy5yID0gdi54O1xuXHRcdHRoaXMuZyA9IHYueTtcblx0XHR0aGlzLmIgPSB2Lno7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXBwbHlNYXRyaXgzKCBtICkge1xuXG5cdFx0Y29uc3QgciA9IHRoaXMuciwgZyA9IHRoaXMuZywgYiA9IHRoaXMuYjtcblx0XHRjb25zdCBlID0gbS5lbGVtZW50cztcblxuXHRcdHRoaXMuciA9IGVbIDAgXSAqIHIgKyBlWyAzIF0gKiBnICsgZVsgNiBdICogYjtcblx0XHR0aGlzLmcgPSBlWyAxIF0gKiByICsgZVsgNCBdICogZyArIGVbIDcgXSAqIGI7XG5cdFx0dGhpcy5iID0gZVsgMiBdICogciArIGVbIDUgXSAqIGcgKyBlWyA4IF0gKiBiO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGVxdWFscyggYyApIHtcblxuXHRcdHJldHVybiAoIGMuciA9PT0gdGhpcy5yICkgJiYgKCBjLmcgPT09IHRoaXMuZyApICYmICggYy5iID09PSB0aGlzLmIgKTtcblxuXHR9XG5cblx0ZnJvbUFycmF5KCBhcnJheSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdHRoaXMuciA9IGFycmF5WyBvZmZzZXQgXTtcblx0XHR0aGlzLmcgPSBhcnJheVsgb2Zmc2V0ICsgMSBdO1xuXHRcdHRoaXMuYiA9IGFycmF5WyBvZmZzZXQgKyAyIF07XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9BcnJheSggYXJyYXkgPSBbXSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdGFycmF5WyBvZmZzZXQgXSA9IHRoaXMucjtcblx0XHRhcnJheVsgb2Zmc2V0ICsgMSBdID0gdGhpcy5nO1xuXHRcdGFycmF5WyBvZmZzZXQgKyAyIF0gPSB0aGlzLmI7XG5cblx0XHRyZXR1cm4gYXJyYXk7XG5cblx0fVxuXG5cdGZyb21CdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kZXggKSB7XG5cblx0XHR0aGlzLnIgPSBhdHRyaWJ1dGUuZ2V0WCggaW5kZXggKTtcblx0XHR0aGlzLmcgPSBhdHRyaWJ1dGUuZ2V0WSggaW5kZXggKTtcblx0XHR0aGlzLmIgPSBhdHRyaWJ1dGUuZ2V0WiggaW5kZXggKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5nZXRIZXgoKTtcblxuXHR9XG5cblx0KlsgU3ltYm9sLml0ZXJhdG9yIF0oKSB7XG5cblx0XHR5aWVsZCB0aGlzLnI7XG5cdFx0eWllbGQgdGhpcy5nO1xuXHRcdHlpZWxkIHRoaXMuYjtcblxuXHR9XG5cbn1cblxuY29uc3QgX2NvbG9yID0gLypAX19QVVJFX18qLyBuZXcgQ29sb3IoKTtcblxuQ29sb3IuTkFNRVMgPSBfY29sb3JLZXl3b3JkcztcblxubGV0IF9tYXRlcmlhbElkID0gMDtcblxuY2xhc3MgTWF0ZXJpYWwgZXh0ZW5kcyBFdmVudERpc3BhdGNoZXIge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNNYXRlcmlhbCA9IHRydWU7XG5cblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoIHRoaXMsICdpZCcsIHsgdmFsdWU6IF9tYXRlcmlhbElkICsrIH0gKTtcblxuXHRcdHRoaXMudXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0dGhpcy5uYW1lID0gJyc7XG5cdFx0dGhpcy50eXBlID0gJ01hdGVyaWFsJztcblxuXHRcdHRoaXMuYmxlbmRpbmcgPSBOb3JtYWxCbGVuZGluZztcblx0XHR0aGlzLnNpZGUgPSBGcm9udFNpZGU7XG5cdFx0dGhpcy52ZXJ0ZXhDb2xvcnMgPSBmYWxzZTtcblxuXHRcdHRoaXMub3BhY2l0eSA9IDE7XG5cdFx0dGhpcy50cmFuc3BhcmVudCA9IGZhbHNlO1xuXHRcdHRoaXMuYWxwaGFIYXNoID0gZmFsc2U7XG5cblx0XHR0aGlzLmJsZW5kU3JjID0gU3JjQWxwaGFGYWN0b3I7XG5cdFx0dGhpcy5ibGVuZERzdCA9IE9uZU1pbnVzU3JjQWxwaGFGYWN0b3I7XG5cdFx0dGhpcy5ibGVuZEVxdWF0aW9uID0gQWRkRXF1YXRpb247XG5cdFx0dGhpcy5ibGVuZFNyY0FscGhhID0gbnVsbDtcblx0XHR0aGlzLmJsZW5kRHN0QWxwaGEgPSBudWxsO1xuXHRcdHRoaXMuYmxlbmRFcXVhdGlvbkFscGhhID0gbnVsbDtcblx0XHR0aGlzLmJsZW5kQ29sb3IgPSBuZXcgQ29sb3IoIDAsIDAsIDAgKTtcblx0XHR0aGlzLmJsZW5kQWxwaGEgPSAwO1xuXG5cdFx0dGhpcy5kZXB0aEZ1bmMgPSBMZXNzRXF1YWxEZXB0aDtcblx0XHR0aGlzLmRlcHRoVGVzdCA9IHRydWU7XG5cdFx0dGhpcy5kZXB0aFdyaXRlID0gdHJ1ZTtcblxuXHRcdHRoaXMuc3RlbmNpbFdyaXRlTWFzayA9IDB4ZmY7XG5cdFx0dGhpcy5zdGVuY2lsRnVuYyA9IEFsd2F5c1N0ZW5jaWxGdW5jO1xuXHRcdHRoaXMuc3RlbmNpbFJlZiA9IDA7XG5cdFx0dGhpcy5zdGVuY2lsRnVuY01hc2sgPSAweGZmO1xuXHRcdHRoaXMuc3RlbmNpbEZhaWwgPSBLZWVwU3RlbmNpbE9wO1xuXHRcdHRoaXMuc3RlbmNpbFpGYWlsID0gS2VlcFN0ZW5jaWxPcDtcblx0XHR0aGlzLnN0ZW5jaWxaUGFzcyA9IEtlZXBTdGVuY2lsT3A7XG5cdFx0dGhpcy5zdGVuY2lsV3JpdGUgPSBmYWxzZTtcblxuXHRcdHRoaXMuY2xpcHBpbmdQbGFuZXMgPSBudWxsO1xuXHRcdHRoaXMuY2xpcEludGVyc2VjdGlvbiA9IGZhbHNlO1xuXHRcdHRoaXMuY2xpcFNoYWRvd3MgPSBmYWxzZTtcblxuXHRcdHRoaXMuc2hhZG93U2lkZSA9IG51bGw7XG5cblx0XHR0aGlzLmNvbG9yV3JpdGUgPSB0cnVlO1xuXG5cdFx0dGhpcy5wcmVjaXNpb24gPSBudWxsOyAvLyBvdmVycmlkZSB0aGUgcmVuZGVyZXIncyBkZWZhdWx0IHByZWNpc2lvbiBmb3IgdGhpcyBtYXRlcmlhbFxuXG5cdFx0dGhpcy5wb2x5Z29uT2Zmc2V0ID0gZmFsc2U7XG5cdFx0dGhpcy5wb2x5Z29uT2Zmc2V0RmFjdG9yID0gMDtcblx0XHR0aGlzLnBvbHlnb25PZmZzZXRVbml0cyA9IDA7XG5cblx0XHR0aGlzLmRpdGhlcmluZyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5hbHBoYVRvQ292ZXJhZ2UgPSBmYWxzZTtcblx0XHR0aGlzLnByZW11bHRpcGxpZWRBbHBoYSA9IGZhbHNlO1xuXHRcdHRoaXMuZm9yY2VTaW5nbGVQYXNzID0gZmFsc2U7XG5cblx0XHR0aGlzLnZpc2libGUgPSB0cnVlO1xuXG5cdFx0dGhpcy50b25lTWFwcGVkID0gdHJ1ZTtcblxuXHRcdHRoaXMudXNlckRhdGEgPSB7fTtcblxuXHRcdHRoaXMudmVyc2lvbiA9IDA7XG5cblx0XHR0aGlzLl9hbHBoYVRlc3QgPSAwO1xuXG5cdH1cblxuXHRnZXQgYWxwaGFUZXN0KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX2FscGhhVGVzdDtcblxuXHR9XG5cblx0c2V0IGFscGhhVGVzdCggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHRoaXMuX2FscGhhVGVzdCA+IDAgIT09IHZhbHVlID4gMCApIHtcblxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5fYWxwaGFUZXN0ID0gdmFsdWU7XG5cblx0fVxuXG5cdG9uQmVmb3JlQ29tcGlsZSggLyogc2hhZGVyb2JqZWN0LCByZW5kZXJlciAqLyApIHt9XG5cblx0Y3VzdG9tUHJvZ3JhbUNhY2hlS2V5KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMub25CZWZvcmVDb21waWxlLnRvU3RyaW5nKCk7XG5cblx0fVxuXG5cdHNldFZhbHVlcyggdmFsdWVzICkge1xuXG5cdFx0aWYgKCB2YWx1ZXMgPT09IHVuZGVmaW5lZCApIHJldHVybjtcblxuXHRcdGZvciAoIGNvbnN0IGtleSBpbiB2YWx1ZXMgKSB7XG5cblx0XHRcdGNvbnN0IG5ld1ZhbHVlID0gdmFsdWVzWyBrZXkgXTtcblxuXHRcdFx0aWYgKCBuZXdWYWx1ZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggYFRIUkVFLk1hdGVyaWFsOiBwYXJhbWV0ZXIgJyR7IGtleSB9JyBoYXMgdmFsdWUgb2YgdW5kZWZpbmVkLmAgKTtcblx0XHRcdFx0Y29udGludWU7XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgY3VycmVudFZhbHVlID0gdGhpc1sga2V5IF07XG5cblx0XHRcdGlmICggY3VycmVudFZhbHVlID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCBgVEhSRUUuTWF0ZXJpYWw6ICckeyBrZXkgfScgaXMgbm90IGEgcHJvcGVydHkgb2YgVEhSRUUuJHsgdGhpcy50eXBlIH0uYCApO1xuXHRcdFx0XHRjb250aW51ZTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGN1cnJlbnRWYWx1ZSAmJiBjdXJyZW50VmFsdWUuaXNDb2xvciApIHtcblxuXHRcdFx0XHRjdXJyZW50VmFsdWUuc2V0KCBuZXdWYWx1ZSApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCAoIGN1cnJlbnRWYWx1ZSAmJiBjdXJyZW50VmFsdWUuaXNWZWN0b3IzICkgJiYgKCBuZXdWYWx1ZSAmJiBuZXdWYWx1ZS5pc1ZlY3RvcjMgKSApIHtcblxuXHRcdFx0XHRjdXJyZW50VmFsdWUuY29weSggbmV3VmFsdWUgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHR0aGlzWyBrZXkgXSA9IG5ld1ZhbHVlO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdHRvSlNPTiggbWV0YSApIHtcblxuXHRcdGNvbnN0IGlzUm9vdE9iamVjdCA9ICggbWV0YSA9PT0gdW5kZWZpbmVkIHx8IHR5cGVvZiBtZXRhID09PSAnc3RyaW5nJyApO1xuXG5cdFx0aWYgKCBpc1Jvb3RPYmplY3QgKSB7XG5cblx0XHRcdG1ldGEgPSB7XG5cdFx0XHRcdHRleHR1cmVzOiB7fSxcblx0XHRcdFx0aW1hZ2VzOiB7fVxuXHRcdFx0fTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGRhdGEgPSB7XG5cdFx0XHRtZXRhZGF0YToge1xuXHRcdFx0XHR2ZXJzaW9uOiA0LjYsXG5cdFx0XHRcdHR5cGU6ICdNYXRlcmlhbCcsXG5cdFx0XHRcdGdlbmVyYXRvcjogJ01hdGVyaWFsLnRvSlNPTidcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0Ly8gc3RhbmRhcmQgTWF0ZXJpYWwgc2VyaWFsaXphdGlvblxuXHRcdGRhdGEudXVpZCA9IHRoaXMudXVpZDtcblx0XHRkYXRhLnR5cGUgPSB0aGlzLnR5cGU7XG5cblx0XHRpZiAoIHRoaXMubmFtZSAhPT0gJycgKSBkYXRhLm5hbWUgPSB0aGlzLm5hbWU7XG5cblx0XHRpZiAoIHRoaXMuY29sb3IgJiYgdGhpcy5jb2xvci5pc0NvbG9yICkgZGF0YS5jb2xvciA9IHRoaXMuY29sb3IuZ2V0SGV4KCk7XG5cblx0XHRpZiAoIHRoaXMucm91Z2huZXNzICE9PSB1bmRlZmluZWQgKSBkYXRhLnJvdWdobmVzcyA9IHRoaXMucm91Z2huZXNzO1xuXHRcdGlmICggdGhpcy5tZXRhbG5lc3MgIT09IHVuZGVmaW5lZCApIGRhdGEubWV0YWxuZXNzID0gdGhpcy5tZXRhbG5lc3M7XG5cblx0XHRpZiAoIHRoaXMuc2hlZW4gIT09IHVuZGVmaW5lZCApIGRhdGEuc2hlZW4gPSB0aGlzLnNoZWVuO1xuXHRcdGlmICggdGhpcy5zaGVlbkNvbG9yICYmIHRoaXMuc2hlZW5Db2xvci5pc0NvbG9yICkgZGF0YS5zaGVlbkNvbG9yID0gdGhpcy5zaGVlbkNvbG9yLmdldEhleCgpO1xuXHRcdGlmICggdGhpcy5zaGVlblJvdWdobmVzcyAhPT0gdW5kZWZpbmVkICkgZGF0YS5zaGVlblJvdWdobmVzcyA9IHRoaXMuc2hlZW5Sb3VnaG5lc3M7XG5cdFx0aWYgKCB0aGlzLmVtaXNzaXZlICYmIHRoaXMuZW1pc3NpdmUuaXNDb2xvciApIGRhdGEuZW1pc3NpdmUgPSB0aGlzLmVtaXNzaXZlLmdldEhleCgpO1xuXHRcdGlmICggdGhpcy5lbWlzc2l2ZUludGVuc2l0eSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgIT09IDEgKSBkYXRhLmVtaXNzaXZlSW50ZW5zaXR5ID0gdGhpcy5lbWlzc2l2ZUludGVuc2l0eTtcblxuXHRcdGlmICggdGhpcy5zcGVjdWxhciAmJiB0aGlzLnNwZWN1bGFyLmlzQ29sb3IgKSBkYXRhLnNwZWN1bGFyID0gdGhpcy5zcGVjdWxhci5nZXRIZXgoKTtcblx0XHRpZiAoIHRoaXMuc3BlY3VsYXJJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCApIGRhdGEuc3BlY3VsYXJJbnRlbnNpdHkgPSB0aGlzLnNwZWN1bGFySW50ZW5zaXR5O1xuXHRcdGlmICggdGhpcy5zcGVjdWxhckNvbG9yICYmIHRoaXMuc3BlY3VsYXJDb2xvci5pc0NvbG9yICkgZGF0YS5zcGVjdWxhckNvbG9yID0gdGhpcy5zcGVjdWxhckNvbG9yLmdldEhleCgpO1xuXHRcdGlmICggdGhpcy5zaGluaW5lc3MgIT09IHVuZGVmaW5lZCApIGRhdGEuc2hpbmluZXNzID0gdGhpcy5zaGluaW5lc3M7XG5cdFx0aWYgKCB0aGlzLmNsZWFyY29hdCAhPT0gdW5kZWZpbmVkICkgZGF0YS5jbGVhcmNvYXQgPSB0aGlzLmNsZWFyY29hdDtcblx0XHRpZiAoIHRoaXMuY2xlYXJjb2F0Um91Z2huZXNzICE9PSB1bmRlZmluZWQgKSBkYXRhLmNsZWFyY29hdFJvdWdobmVzcyA9IHRoaXMuY2xlYXJjb2F0Um91Z2huZXNzO1xuXG5cdFx0aWYgKCB0aGlzLmNsZWFyY29hdE1hcCAmJiB0aGlzLmNsZWFyY29hdE1hcC5pc1RleHR1cmUgKSB7XG5cblx0XHRcdGRhdGEuY2xlYXJjb2F0TWFwID0gdGhpcy5jbGVhcmNvYXRNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgJiYgdGhpcy5jbGVhcmNvYXRSb3VnaG5lc3NNYXAuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRkYXRhLmNsZWFyY29hdFJvdWdobmVzc01hcCA9IHRoaXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuY2xlYXJjb2F0Tm9ybWFsTWFwICYmIHRoaXMuY2xlYXJjb2F0Tm9ybWFsTWFwLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0ZGF0YS5jbGVhcmNvYXROb3JtYWxNYXAgPSB0aGlzLmNsZWFyY29hdE5vcm1hbE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXHRcdFx0ZGF0YS5jbGVhcmNvYXROb3JtYWxTY2FsZSA9IHRoaXMuY2xlYXJjb2F0Tm9ybWFsU2NhbGUudG9BcnJheSgpO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmRpc3BlcnNpb24gIT09IHVuZGVmaW5lZCApIGRhdGEuZGlzcGVyc2lvbiA9IHRoaXMuZGlzcGVyc2lvbjtcblxuXHRcdGlmICggdGhpcy5pcmlkZXNjZW5jZSAhPT0gdW5kZWZpbmVkICkgZGF0YS5pcmlkZXNjZW5jZSA9IHRoaXMuaXJpZGVzY2VuY2U7XG5cdFx0aWYgKCB0aGlzLmlyaWRlc2NlbmNlSU9SICE9PSB1bmRlZmluZWQgKSBkYXRhLmlyaWRlc2NlbmNlSU9SID0gdGhpcy5pcmlkZXNjZW5jZUlPUjtcblx0XHRpZiAoIHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZSAhPT0gdW5kZWZpbmVkICkgZGF0YS5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlID0gdGhpcy5pcmlkZXNjZW5jZVRoaWNrbmVzc1JhbmdlO1xuXG5cdFx0aWYgKCB0aGlzLmlyaWRlc2NlbmNlTWFwICYmIHRoaXMuaXJpZGVzY2VuY2VNYXAuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRkYXRhLmlyaWRlc2NlbmNlTWFwID0gdGhpcy5pcmlkZXNjZW5jZU1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwICYmIHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRkYXRhLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwID0gdGhpcy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmFuaXNvdHJvcHkgIT09IHVuZGVmaW5lZCApIGRhdGEuYW5pc290cm9weSA9IHRoaXMuYW5pc290cm9weTtcblx0XHRpZiAoIHRoaXMuYW5pc290cm9weVJvdGF0aW9uICE9PSB1bmRlZmluZWQgKSBkYXRhLmFuaXNvdHJvcHlSb3RhdGlvbiA9IHRoaXMuYW5pc290cm9weVJvdGF0aW9uO1xuXG5cdFx0aWYgKCB0aGlzLmFuaXNvdHJvcHlNYXAgJiYgdGhpcy5hbmlzb3Ryb3B5TWFwLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0ZGF0YS5hbmlzb3Ryb3B5TWFwID0gdGhpcy5hbmlzb3Ryb3B5TWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMubWFwICYmIHRoaXMubWFwLmlzVGV4dHVyZSApIGRhdGEubWFwID0gdGhpcy5tYXAudG9KU09OKCBtZXRhICkudXVpZDtcblx0XHRpZiAoIHRoaXMubWF0Y2FwICYmIHRoaXMubWF0Y2FwLmlzVGV4dHVyZSApIGRhdGEubWF0Y2FwID0gdGhpcy5tYXRjYXAudG9KU09OKCBtZXRhICkudXVpZDtcblx0XHRpZiAoIHRoaXMuYWxwaGFNYXAgJiYgdGhpcy5hbHBoYU1hcC5pc1RleHR1cmUgKSBkYXRhLmFscGhhTWFwID0gdGhpcy5hbHBoYU1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXG5cdFx0aWYgKCB0aGlzLmxpZ2h0TWFwICYmIHRoaXMubGlnaHRNYXAuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRkYXRhLmxpZ2h0TWFwID0gdGhpcy5saWdodE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXHRcdFx0ZGF0YS5saWdodE1hcEludGVuc2l0eSA9IHRoaXMubGlnaHRNYXBJbnRlbnNpdHk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuYW9NYXAgJiYgdGhpcy5hb01hcC5pc1RleHR1cmUgKSB7XG5cblx0XHRcdGRhdGEuYW9NYXAgPSB0aGlzLmFvTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cdFx0XHRkYXRhLmFvTWFwSW50ZW5zaXR5ID0gdGhpcy5hb01hcEludGVuc2l0eTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5idW1wTWFwICYmIHRoaXMuYnVtcE1hcC5pc1RleHR1cmUgKSB7XG5cblx0XHRcdGRhdGEuYnVtcE1hcCA9IHRoaXMuYnVtcE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXHRcdFx0ZGF0YS5idW1wU2NhbGUgPSB0aGlzLmJ1bXBTY2FsZTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5ub3JtYWxNYXAgJiYgdGhpcy5ub3JtYWxNYXAuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRkYXRhLm5vcm1hbE1hcCA9IHRoaXMubm9ybWFsTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cdFx0XHRkYXRhLm5vcm1hbE1hcFR5cGUgPSB0aGlzLm5vcm1hbE1hcFR5cGU7XG5cdFx0XHRkYXRhLm5vcm1hbFNjYWxlID0gdGhpcy5ub3JtYWxTY2FsZS50b0FycmF5KCk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuZGlzcGxhY2VtZW50TWFwICYmIHRoaXMuZGlzcGxhY2VtZW50TWFwLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0ZGF0YS5kaXNwbGFjZW1lbnRNYXAgPSB0aGlzLmRpc3BsYWNlbWVudE1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXHRcdFx0ZGF0YS5kaXNwbGFjZW1lbnRTY2FsZSA9IHRoaXMuZGlzcGxhY2VtZW50U2NhbGU7XG5cdFx0XHRkYXRhLmRpc3BsYWNlbWVudEJpYXMgPSB0aGlzLmRpc3BsYWNlbWVudEJpYXM7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMucm91Z2huZXNzTWFwICYmIHRoaXMucm91Z2huZXNzTWFwLmlzVGV4dHVyZSApIGRhdGEucm91Z2huZXNzTWFwID0gdGhpcy5yb3VnaG5lc3NNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblx0XHRpZiAoIHRoaXMubWV0YWxuZXNzTWFwICYmIHRoaXMubWV0YWxuZXNzTWFwLmlzVGV4dHVyZSApIGRhdGEubWV0YWxuZXNzTWFwID0gdGhpcy5tZXRhbG5lc3NNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblxuXHRcdGlmICggdGhpcy5lbWlzc2l2ZU1hcCAmJiB0aGlzLmVtaXNzaXZlTWFwLmlzVGV4dHVyZSApIGRhdGEuZW1pc3NpdmVNYXAgPSB0aGlzLmVtaXNzaXZlTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cdFx0aWYgKCB0aGlzLnNwZWN1bGFyTWFwICYmIHRoaXMuc3BlY3VsYXJNYXAuaXNUZXh0dXJlICkgZGF0YS5zcGVjdWxhck1hcCA9IHRoaXMuc3BlY3VsYXJNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblx0XHRpZiAoIHRoaXMuc3BlY3VsYXJJbnRlbnNpdHlNYXAgJiYgdGhpcy5zcGVjdWxhckludGVuc2l0eU1hcC5pc1RleHR1cmUgKSBkYXRhLnNwZWN1bGFySW50ZW5zaXR5TWFwID0gdGhpcy5zcGVjdWxhckludGVuc2l0eU1hcC50b0pTT04oIG1ldGEgKS51dWlkO1xuXHRcdGlmICggdGhpcy5zcGVjdWxhckNvbG9yTWFwICYmIHRoaXMuc3BlY3VsYXJDb2xvck1hcC5pc1RleHR1cmUgKSBkYXRhLnNwZWN1bGFyQ29sb3JNYXAgPSB0aGlzLnNwZWN1bGFyQ29sb3JNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblxuXHRcdGlmICggdGhpcy5lbnZNYXAgJiYgdGhpcy5lbnZNYXAuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRkYXRhLmVudk1hcCA9IHRoaXMuZW52TWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cblx0XHRcdGlmICggdGhpcy5jb21iaW5lICE9PSB1bmRlZmluZWQgKSBkYXRhLmNvbWJpbmUgPSB0aGlzLmNvbWJpbmU7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuZW52TWFwUm90YXRpb24gIT09IHVuZGVmaW5lZCApIGRhdGEuZW52TWFwUm90YXRpb24gPSB0aGlzLmVudk1hcFJvdGF0aW9uLnRvQXJyYXkoKTtcblx0XHRpZiAoIHRoaXMuZW52TWFwSW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBkYXRhLmVudk1hcEludGVuc2l0eSA9IHRoaXMuZW52TWFwSW50ZW5zaXR5O1xuXHRcdGlmICggdGhpcy5yZWZsZWN0aXZpdHkgIT09IHVuZGVmaW5lZCApIGRhdGEucmVmbGVjdGl2aXR5ID0gdGhpcy5yZWZsZWN0aXZpdHk7XG5cdFx0aWYgKCB0aGlzLnJlZnJhY3Rpb25SYXRpbyAhPT0gdW5kZWZpbmVkICkgZGF0YS5yZWZyYWN0aW9uUmF0aW8gPSB0aGlzLnJlZnJhY3Rpb25SYXRpbztcblxuXHRcdGlmICggdGhpcy5ncmFkaWVudE1hcCAmJiB0aGlzLmdyYWRpZW50TWFwLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0ZGF0YS5ncmFkaWVudE1hcCA9IHRoaXMuZ3JhZGllbnRNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy50cmFuc21pc3Npb24gIT09IHVuZGVmaW5lZCApIGRhdGEudHJhbnNtaXNzaW9uID0gdGhpcy50cmFuc21pc3Npb247XG5cdFx0aWYgKCB0aGlzLnRyYW5zbWlzc2lvbk1hcCAmJiB0aGlzLnRyYW5zbWlzc2lvbk1hcC5pc1RleHR1cmUgKSBkYXRhLnRyYW5zbWlzc2lvbk1hcCA9IHRoaXMudHJhbnNtaXNzaW9uTWFwLnRvSlNPTiggbWV0YSApLnV1aWQ7XG5cdFx0aWYgKCB0aGlzLnRoaWNrbmVzcyAhPT0gdW5kZWZpbmVkICkgZGF0YS50aGlja25lc3MgPSB0aGlzLnRoaWNrbmVzcztcblx0XHRpZiAoIHRoaXMudGhpY2tuZXNzTWFwICYmIHRoaXMudGhpY2tuZXNzTWFwLmlzVGV4dHVyZSApIGRhdGEudGhpY2tuZXNzTWFwID0gdGhpcy50aGlja25lc3NNYXAudG9KU09OKCBtZXRhICkudXVpZDtcblx0XHRpZiAoIHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSAhPT0gdW5kZWZpbmVkICYmIHRoaXMuYXR0ZW51YXRpb25EaXN0YW5jZSAhPT0gSW5maW5pdHkgKSBkYXRhLmF0dGVudWF0aW9uRGlzdGFuY2UgPSB0aGlzLmF0dGVudWF0aW9uRGlzdGFuY2U7XG5cdFx0aWYgKCB0aGlzLmF0dGVudWF0aW9uQ29sb3IgIT09IHVuZGVmaW5lZCApIGRhdGEuYXR0ZW51YXRpb25Db2xvciA9IHRoaXMuYXR0ZW51YXRpb25Db2xvci5nZXRIZXgoKTtcblxuXHRcdGlmICggdGhpcy5zaXplICE9PSB1bmRlZmluZWQgKSBkYXRhLnNpemUgPSB0aGlzLnNpemU7XG5cdFx0aWYgKCB0aGlzLnNoYWRvd1NpZGUgIT09IG51bGwgKSBkYXRhLnNoYWRvd1NpZGUgPSB0aGlzLnNoYWRvd1NpZGU7XG5cdFx0aWYgKCB0aGlzLnNpemVBdHRlbnVhdGlvbiAhPT0gdW5kZWZpbmVkICkgZGF0YS5zaXplQXR0ZW51YXRpb24gPSB0aGlzLnNpemVBdHRlbnVhdGlvbjtcblxuXHRcdGlmICggdGhpcy5ibGVuZGluZyAhPT0gTm9ybWFsQmxlbmRpbmcgKSBkYXRhLmJsZW5kaW5nID0gdGhpcy5ibGVuZGluZztcblx0XHRpZiAoIHRoaXMuc2lkZSAhPT0gRnJvbnRTaWRlICkgZGF0YS5zaWRlID0gdGhpcy5zaWRlO1xuXHRcdGlmICggdGhpcy52ZXJ0ZXhDb2xvcnMgPT09IHRydWUgKSBkYXRhLnZlcnRleENvbG9ycyA9IHRydWU7XG5cblx0XHRpZiAoIHRoaXMub3BhY2l0eSA8IDEgKSBkYXRhLm9wYWNpdHkgPSB0aGlzLm9wYWNpdHk7XG5cdFx0aWYgKCB0aGlzLnRyYW5zcGFyZW50ID09PSB0cnVlICkgZGF0YS50cmFuc3BhcmVudCA9IHRydWU7XG5cblx0XHRpZiAoIHRoaXMuYmxlbmRTcmMgIT09IFNyY0FscGhhRmFjdG9yICkgZGF0YS5ibGVuZFNyYyA9IHRoaXMuYmxlbmRTcmM7XG5cdFx0aWYgKCB0aGlzLmJsZW5kRHN0ICE9PSBPbmVNaW51c1NyY0FscGhhRmFjdG9yICkgZGF0YS5ibGVuZERzdCA9IHRoaXMuYmxlbmREc3Q7XG5cdFx0aWYgKCB0aGlzLmJsZW5kRXF1YXRpb24gIT09IEFkZEVxdWF0aW9uICkgZGF0YS5ibGVuZEVxdWF0aW9uID0gdGhpcy5ibGVuZEVxdWF0aW9uO1xuXHRcdGlmICggdGhpcy5ibGVuZFNyY0FscGhhICE9PSBudWxsICkgZGF0YS5ibGVuZFNyY0FscGhhID0gdGhpcy5ibGVuZFNyY0FscGhhO1xuXHRcdGlmICggdGhpcy5ibGVuZERzdEFscGhhICE9PSBudWxsICkgZGF0YS5ibGVuZERzdEFscGhhID0gdGhpcy5ibGVuZERzdEFscGhhO1xuXHRcdGlmICggdGhpcy5ibGVuZEVxdWF0aW9uQWxwaGEgIT09IG51bGwgKSBkYXRhLmJsZW5kRXF1YXRpb25BbHBoYSA9IHRoaXMuYmxlbmRFcXVhdGlvbkFscGhhO1xuXHRcdGlmICggdGhpcy5ibGVuZENvbG9yICYmIHRoaXMuYmxlbmRDb2xvci5pc0NvbG9yICkgZGF0YS5ibGVuZENvbG9yID0gdGhpcy5ibGVuZENvbG9yLmdldEhleCgpO1xuXHRcdGlmICggdGhpcy5ibGVuZEFscGhhICE9PSAwICkgZGF0YS5ibGVuZEFscGhhID0gdGhpcy5ibGVuZEFscGhhO1xuXG5cdFx0aWYgKCB0aGlzLmRlcHRoRnVuYyAhPT0gTGVzc0VxdWFsRGVwdGggKSBkYXRhLmRlcHRoRnVuYyA9IHRoaXMuZGVwdGhGdW5jO1xuXHRcdGlmICggdGhpcy5kZXB0aFRlc3QgPT09IGZhbHNlICkgZGF0YS5kZXB0aFRlc3QgPSB0aGlzLmRlcHRoVGVzdDtcblx0XHRpZiAoIHRoaXMuZGVwdGhXcml0ZSA9PT0gZmFsc2UgKSBkYXRhLmRlcHRoV3JpdGUgPSB0aGlzLmRlcHRoV3JpdGU7XG5cdFx0aWYgKCB0aGlzLmNvbG9yV3JpdGUgPT09IGZhbHNlICkgZGF0YS5jb2xvcldyaXRlID0gdGhpcy5jb2xvcldyaXRlO1xuXG5cdFx0aWYgKCB0aGlzLnN0ZW5jaWxXcml0ZU1hc2sgIT09IDB4ZmYgKSBkYXRhLnN0ZW5jaWxXcml0ZU1hc2sgPSB0aGlzLnN0ZW5jaWxXcml0ZU1hc2s7XG5cdFx0aWYgKCB0aGlzLnN0ZW5jaWxGdW5jICE9PSBBbHdheXNTdGVuY2lsRnVuYyApIGRhdGEuc3RlbmNpbEZ1bmMgPSB0aGlzLnN0ZW5jaWxGdW5jO1xuXHRcdGlmICggdGhpcy5zdGVuY2lsUmVmICE9PSAwICkgZGF0YS5zdGVuY2lsUmVmID0gdGhpcy5zdGVuY2lsUmVmO1xuXHRcdGlmICggdGhpcy5zdGVuY2lsRnVuY01hc2sgIT09IDB4ZmYgKSBkYXRhLnN0ZW5jaWxGdW5jTWFzayA9IHRoaXMuc3RlbmNpbEZ1bmNNYXNrO1xuXHRcdGlmICggdGhpcy5zdGVuY2lsRmFpbCAhPT0gS2VlcFN0ZW5jaWxPcCApIGRhdGEuc3RlbmNpbEZhaWwgPSB0aGlzLnN0ZW5jaWxGYWlsO1xuXHRcdGlmICggdGhpcy5zdGVuY2lsWkZhaWwgIT09IEtlZXBTdGVuY2lsT3AgKSBkYXRhLnN0ZW5jaWxaRmFpbCA9IHRoaXMuc3RlbmNpbFpGYWlsO1xuXHRcdGlmICggdGhpcy5zdGVuY2lsWlBhc3MgIT09IEtlZXBTdGVuY2lsT3AgKSBkYXRhLnN0ZW5jaWxaUGFzcyA9IHRoaXMuc3RlbmNpbFpQYXNzO1xuXHRcdGlmICggdGhpcy5zdGVuY2lsV3JpdGUgPT09IHRydWUgKSBkYXRhLnN0ZW5jaWxXcml0ZSA9IHRoaXMuc3RlbmNpbFdyaXRlO1xuXG5cdFx0Ly8gcm90YXRpb24gKFNwcml0ZU1hdGVyaWFsKVxuXHRcdGlmICggdGhpcy5yb3RhdGlvbiAhPT0gdW5kZWZpbmVkICYmIHRoaXMucm90YXRpb24gIT09IDAgKSBkYXRhLnJvdGF0aW9uID0gdGhpcy5yb3RhdGlvbjtcblxuXHRcdGlmICggdGhpcy5wb2x5Z29uT2Zmc2V0ID09PSB0cnVlICkgZGF0YS5wb2x5Z29uT2Zmc2V0ID0gdHJ1ZTtcblx0XHRpZiAoIHRoaXMucG9seWdvbk9mZnNldEZhY3RvciAhPT0gMCApIGRhdGEucG9seWdvbk9mZnNldEZhY3RvciA9IHRoaXMucG9seWdvbk9mZnNldEZhY3Rvcjtcblx0XHRpZiAoIHRoaXMucG9seWdvbk9mZnNldFVuaXRzICE9PSAwICkgZGF0YS5wb2x5Z29uT2Zmc2V0VW5pdHMgPSB0aGlzLnBvbHlnb25PZmZzZXRVbml0cztcblxuXHRcdGlmICggdGhpcy5saW5ld2lkdGggIT09IHVuZGVmaW5lZCAmJiB0aGlzLmxpbmV3aWR0aCAhPT0gMSApIGRhdGEubGluZXdpZHRoID0gdGhpcy5saW5ld2lkdGg7XG5cdFx0aWYgKCB0aGlzLmRhc2hTaXplICE9PSB1bmRlZmluZWQgKSBkYXRhLmRhc2hTaXplID0gdGhpcy5kYXNoU2l6ZTtcblx0XHRpZiAoIHRoaXMuZ2FwU2l6ZSAhPT0gdW5kZWZpbmVkICkgZGF0YS5nYXBTaXplID0gdGhpcy5nYXBTaXplO1xuXHRcdGlmICggdGhpcy5zY2FsZSAhPT0gdW5kZWZpbmVkICkgZGF0YS5zY2FsZSA9IHRoaXMuc2NhbGU7XG5cblx0XHRpZiAoIHRoaXMuZGl0aGVyaW5nID09PSB0cnVlICkgZGF0YS5kaXRoZXJpbmcgPSB0cnVlO1xuXG5cdFx0aWYgKCB0aGlzLmFscGhhVGVzdCA+IDAgKSBkYXRhLmFscGhhVGVzdCA9IHRoaXMuYWxwaGFUZXN0O1xuXHRcdGlmICggdGhpcy5hbHBoYUhhc2ggPT09IHRydWUgKSBkYXRhLmFscGhhSGFzaCA9IHRydWU7XG5cdFx0aWYgKCB0aGlzLmFscGhhVG9Db3ZlcmFnZSA9PT0gdHJ1ZSApIGRhdGEuYWxwaGFUb0NvdmVyYWdlID0gdHJ1ZTtcblx0XHRpZiAoIHRoaXMucHJlbXVsdGlwbGllZEFscGhhID09PSB0cnVlICkgZGF0YS5wcmVtdWx0aXBsaWVkQWxwaGEgPSB0cnVlO1xuXHRcdGlmICggdGhpcy5mb3JjZVNpbmdsZVBhc3MgPT09IHRydWUgKSBkYXRhLmZvcmNlU2luZ2xlUGFzcyA9IHRydWU7XG5cblx0XHRpZiAoIHRoaXMud2lyZWZyYW1lID09PSB0cnVlICkgZGF0YS53aXJlZnJhbWUgPSB0cnVlO1xuXHRcdGlmICggdGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPiAxICkgZGF0YS53aXJlZnJhbWVMaW5ld2lkdGggPSB0aGlzLndpcmVmcmFtZUxpbmV3aWR0aDtcblx0XHRpZiAoIHRoaXMud2lyZWZyYW1lTGluZWNhcCAhPT0gJ3JvdW5kJyApIGRhdGEud2lyZWZyYW1lTGluZWNhcCA9IHRoaXMud2lyZWZyYW1lTGluZWNhcDtcblx0XHRpZiAoIHRoaXMud2lyZWZyYW1lTGluZWpvaW4gIT09ICdyb3VuZCcgKSBkYXRhLndpcmVmcmFtZUxpbmVqb2luID0gdGhpcy53aXJlZnJhbWVMaW5lam9pbjtcblxuXHRcdGlmICggdGhpcy5mbGF0U2hhZGluZyA9PT0gdHJ1ZSApIGRhdGEuZmxhdFNoYWRpbmcgPSB0cnVlO1xuXG5cdFx0aWYgKCB0aGlzLnZpc2libGUgPT09IGZhbHNlICkgZGF0YS52aXNpYmxlID0gZmFsc2U7XG5cblx0XHRpZiAoIHRoaXMudG9uZU1hcHBlZCA9PT0gZmFsc2UgKSBkYXRhLnRvbmVNYXBwZWQgPSBmYWxzZTtcblxuXHRcdGlmICggdGhpcy5mb2cgPT09IGZhbHNlICkgZGF0YS5mb2cgPSBmYWxzZTtcblxuXHRcdGlmICggT2JqZWN0LmtleXMoIHRoaXMudXNlckRhdGEgKS5sZW5ndGggPiAwICkgZGF0YS51c2VyRGF0YSA9IHRoaXMudXNlckRhdGE7XG5cblx0XHQvLyBUT0RPOiBDb3BpZWQgZnJvbSBPYmplY3QzRC50b0pTT05cblxuXHRcdGZ1bmN0aW9uIGV4dHJhY3RGcm9tQ2FjaGUoIGNhY2hlICkge1xuXG5cdFx0XHRjb25zdCB2YWx1ZXMgPSBbXTtcblxuXHRcdFx0Zm9yICggY29uc3Qga2V5IGluIGNhY2hlICkge1xuXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBjYWNoZVsga2V5IF07XG5cdFx0XHRcdGRlbGV0ZSBkYXRhLm1ldGFkYXRhO1xuXHRcdFx0XHR2YWx1ZXMucHVzaCggZGF0YSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB2YWx1ZXM7XG5cblx0XHR9XG5cblx0XHRpZiAoIGlzUm9vdE9iamVjdCApIHtcblxuXHRcdFx0Y29uc3QgdGV4dHVyZXMgPSBleHRyYWN0RnJvbUNhY2hlKCBtZXRhLnRleHR1cmVzICk7XG5cdFx0XHRjb25zdCBpbWFnZXMgPSBleHRyYWN0RnJvbUNhY2hlKCBtZXRhLmltYWdlcyApO1xuXG5cdFx0XHRpZiAoIHRleHR1cmVzLmxlbmd0aCA+IDAgKSBkYXRhLnRleHR1cmVzID0gdGV4dHVyZXM7XG5cdFx0XHRpZiAoIGltYWdlcy5sZW5ndGggPiAwICkgZGF0YS5pbWFnZXMgPSBpbWFnZXM7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHRoaXMubmFtZSA9IHNvdXJjZS5uYW1lO1xuXG5cdFx0dGhpcy5ibGVuZGluZyA9IHNvdXJjZS5ibGVuZGluZztcblx0XHR0aGlzLnNpZGUgPSBzb3VyY2Uuc2lkZTtcblx0XHR0aGlzLnZlcnRleENvbG9ycyA9IHNvdXJjZS52ZXJ0ZXhDb2xvcnM7XG5cblx0XHR0aGlzLm9wYWNpdHkgPSBzb3VyY2Uub3BhY2l0eTtcblx0XHR0aGlzLnRyYW5zcGFyZW50ID0gc291cmNlLnRyYW5zcGFyZW50O1xuXG5cdFx0dGhpcy5ibGVuZFNyYyA9IHNvdXJjZS5ibGVuZFNyYztcblx0XHR0aGlzLmJsZW5kRHN0ID0gc291cmNlLmJsZW5kRHN0O1xuXHRcdHRoaXMuYmxlbmRFcXVhdGlvbiA9IHNvdXJjZS5ibGVuZEVxdWF0aW9uO1xuXHRcdHRoaXMuYmxlbmRTcmNBbHBoYSA9IHNvdXJjZS5ibGVuZFNyY0FscGhhO1xuXHRcdHRoaXMuYmxlbmREc3RBbHBoYSA9IHNvdXJjZS5ibGVuZERzdEFscGhhO1xuXHRcdHRoaXMuYmxlbmRFcXVhdGlvbkFscGhhID0gc291cmNlLmJsZW5kRXF1YXRpb25BbHBoYTtcblx0XHR0aGlzLmJsZW5kQ29sb3IuY29weSggc291cmNlLmJsZW5kQ29sb3IgKTtcblx0XHR0aGlzLmJsZW5kQWxwaGEgPSBzb3VyY2UuYmxlbmRBbHBoYTtcblxuXHRcdHRoaXMuZGVwdGhGdW5jID0gc291cmNlLmRlcHRoRnVuYztcblx0XHR0aGlzLmRlcHRoVGVzdCA9IHNvdXJjZS5kZXB0aFRlc3Q7XG5cdFx0dGhpcy5kZXB0aFdyaXRlID0gc291cmNlLmRlcHRoV3JpdGU7XG5cblx0XHR0aGlzLnN0ZW5jaWxXcml0ZU1hc2sgPSBzb3VyY2Uuc3RlbmNpbFdyaXRlTWFzaztcblx0XHR0aGlzLnN0ZW5jaWxGdW5jID0gc291cmNlLnN0ZW5jaWxGdW5jO1xuXHRcdHRoaXMuc3RlbmNpbFJlZiA9IHNvdXJjZS5zdGVuY2lsUmVmO1xuXHRcdHRoaXMuc3RlbmNpbEZ1bmNNYXNrID0gc291cmNlLnN0ZW5jaWxGdW5jTWFzaztcblx0XHR0aGlzLnN0ZW5jaWxGYWlsID0gc291cmNlLnN0ZW5jaWxGYWlsO1xuXHRcdHRoaXMuc3RlbmNpbFpGYWlsID0gc291cmNlLnN0ZW5jaWxaRmFpbDtcblx0XHR0aGlzLnN0ZW5jaWxaUGFzcyA9IHNvdXJjZS5zdGVuY2lsWlBhc3M7XG5cdFx0dGhpcy5zdGVuY2lsV3JpdGUgPSBzb3VyY2Uuc3RlbmNpbFdyaXRlO1xuXG5cdFx0Y29uc3Qgc3JjUGxhbmVzID0gc291cmNlLmNsaXBwaW5nUGxhbmVzO1xuXHRcdGxldCBkc3RQbGFuZXMgPSBudWxsO1xuXG5cdFx0aWYgKCBzcmNQbGFuZXMgIT09IG51bGwgKSB7XG5cblx0XHRcdGNvbnN0IG4gPSBzcmNQbGFuZXMubGVuZ3RoO1xuXHRcdFx0ZHN0UGxhbmVzID0gbmV3IEFycmF5KCBuICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0XHRkc3RQbGFuZXNbIGkgXSA9IHNyY1BsYW5lc1sgaSBdLmNsb25lKCk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHRoaXMuY2xpcHBpbmdQbGFuZXMgPSBkc3RQbGFuZXM7XG5cdFx0dGhpcy5jbGlwSW50ZXJzZWN0aW9uID0gc291cmNlLmNsaXBJbnRlcnNlY3Rpb247XG5cdFx0dGhpcy5jbGlwU2hhZG93cyA9IHNvdXJjZS5jbGlwU2hhZG93cztcblxuXHRcdHRoaXMuc2hhZG93U2lkZSA9IHNvdXJjZS5zaGFkb3dTaWRlO1xuXG5cdFx0dGhpcy5jb2xvcldyaXRlID0gc291cmNlLmNvbG9yV3JpdGU7XG5cblx0XHR0aGlzLnByZWNpc2lvbiA9IHNvdXJjZS5wcmVjaXNpb247XG5cblx0XHR0aGlzLnBvbHlnb25PZmZzZXQgPSBzb3VyY2UucG9seWdvbk9mZnNldDtcblx0XHR0aGlzLnBvbHlnb25PZmZzZXRGYWN0b3IgPSBzb3VyY2UucG9seWdvbk9mZnNldEZhY3Rvcjtcblx0XHR0aGlzLnBvbHlnb25PZmZzZXRVbml0cyA9IHNvdXJjZS5wb2x5Z29uT2Zmc2V0VW5pdHM7XG5cblx0XHR0aGlzLmRpdGhlcmluZyA9IHNvdXJjZS5kaXRoZXJpbmc7XG5cblx0XHR0aGlzLmFscGhhVGVzdCA9IHNvdXJjZS5hbHBoYVRlc3Q7XG5cdFx0dGhpcy5hbHBoYUhhc2ggPSBzb3VyY2UuYWxwaGFIYXNoO1xuXHRcdHRoaXMuYWxwaGFUb0NvdmVyYWdlID0gc291cmNlLmFscGhhVG9Db3ZlcmFnZTtcblx0XHR0aGlzLnByZW11bHRpcGxpZWRBbHBoYSA9IHNvdXJjZS5wcmVtdWx0aXBsaWVkQWxwaGE7XG5cdFx0dGhpcy5mb3JjZVNpbmdsZVBhc3MgPSBzb3VyY2UuZm9yY2VTaW5nbGVQYXNzO1xuXG5cdFx0dGhpcy52aXNpYmxlID0gc291cmNlLnZpc2libGU7XG5cblx0XHR0aGlzLnRvbmVNYXBwZWQgPSBzb3VyY2UudG9uZU1hcHBlZDtcblxuXHRcdHRoaXMudXNlckRhdGEgPSBKU09OLnBhcnNlKCBKU09OLnN0cmluZ2lmeSggc291cmNlLnVzZXJEYXRhICkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7XG5cblx0fVxuXG5cdHNldCBuZWVkc1VwZGF0ZSggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHZhbHVlID09PSB0cnVlICkgdGhpcy52ZXJzaW9uICsrO1xuXG5cdH1cblxuXHRvbkJ1aWxkKCAvKiBzaGFkZXJvYmplY3QsIHJlbmRlcmVyICovICkge1xuXG5cdFx0Y29uc29sZS53YXJuKCAnTWF0ZXJpYWw6IG9uQnVpbGQoKSBoYXMgYmVlbiByZW1vdmVkLicgKTsgLy8gQGRlcHJlY2F0ZWQsIHIxNjZcblxuXHR9XG5cblx0b25CZWZvcmVSZW5kZXIoIC8qIHJlbmRlcmVyLCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgb2JqZWN0LCBncm91cCAqLyApIHtcblxuXHRcdGNvbnNvbGUud2FybiggJ01hdGVyaWFsOiBvbkJlZm9yZVJlbmRlcigpIGhhcyBiZWVuIHJlbW92ZWQuJyApOyAvLyBAZGVwcmVjYXRlZCwgcjE2NlxuXG5cdH1cblxuXG59XG5cbmNsYXNzIE1lc2hCYXNpY01hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNNZXNoQmFzaWNNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnTWVzaEJhc2ljTWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHhmZmZmZmYgKTsgLy8gZW1pc3NpdmVcblxuXHRcdHRoaXMubWFwID0gbnVsbDtcblxuXHRcdHRoaXMubGlnaHRNYXAgPSBudWxsO1xuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSAxLjA7XG5cblx0XHR0aGlzLmFvTWFwID0gbnVsbDtcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gMS4wO1xuXG5cdFx0dGhpcy5zcGVjdWxhck1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuZW52TWFwID0gbnVsbDtcblx0XHR0aGlzLmVudk1hcFJvdGF0aW9uID0gbmV3IEV1bGVyKCk7XG5cdFx0dGhpcy5jb21iaW5lID0gTXVsdGlwbHlPcGVyYXRpb247XG5cdFx0dGhpcy5yZWZsZWN0aXZpdHkgPSAxO1xuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gMC45ODtcblxuXHRcdHRoaXMud2lyZWZyYW1lID0gZmFsc2U7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPSAxO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWNhcCA9ICdyb3VuZCc7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9ICdyb3VuZCc7XG5cblx0XHR0aGlzLmZvZyA9IHRydWU7XG5cblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XG5cblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XG5cblx0XHR0aGlzLmxpZ2h0TWFwID0gc291cmNlLmxpZ2h0TWFwO1xuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSBzb3VyY2UubGlnaHRNYXBJbnRlbnNpdHk7XG5cblx0XHR0aGlzLmFvTWFwID0gc291cmNlLmFvTWFwO1xuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSBzb3VyY2UuYW9NYXBJbnRlbnNpdHk7XG5cblx0XHR0aGlzLnNwZWN1bGFyTWFwID0gc291cmNlLnNwZWN1bGFyTWFwO1xuXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcblxuXHRcdHRoaXMuZW52TWFwID0gc291cmNlLmVudk1hcDtcblx0XHR0aGlzLmVudk1hcFJvdGF0aW9uLmNvcHkoIHNvdXJjZS5lbnZNYXBSb3RhdGlvbiApO1xuXHRcdHRoaXMuY29tYmluZSA9IHNvdXJjZS5jb21iaW5lO1xuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gc291cmNlLnJlZmxlY3Rpdml0eTtcblx0XHR0aGlzLnJlZnJhY3Rpb25SYXRpbyA9IHNvdXJjZS5yZWZyYWN0aW9uUmF0aW87XG5cblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPSBzb3VyY2Uud2lyZWZyYW1lTGluZXdpZHRoO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWNhcCA9IHNvdXJjZS53aXJlZnJhbWVMaW5lY2FwO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSBzb3VyY2Uud2lyZWZyYW1lTGluZWpvaW47XG5cblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuLy8gRmFzdCBIYWxmIEZsb2F0IENvbnZlcnNpb25zLCBodHRwOi8vd3d3LmZveC10b29sa2l0Lm9yZy9mdHAvZmFzdGhhbGZmbG9hdGNvbnZlcnNpb24ucGRmXG5cbmNvbnN0IF90YWJsZXMgPSAvKkBfX1BVUkVfXyovIF9nZW5lcmF0ZVRhYmxlcygpO1xuXG5mdW5jdGlvbiBfZ2VuZXJhdGVUYWJsZXMoKSB7XG5cblx0Ly8gZmxvYXQzMiB0byBmbG9hdDE2IGhlbHBlcnNcblxuXHRjb25zdCBidWZmZXIgPSBuZXcgQXJyYXlCdWZmZXIoIDQgKTtcblx0Y29uc3QgZmxvYXRWaWV3ID0gbmV3IEZsb2F0MzJBcnJheSggYnVmZmVyICk7XG5cdGNvbnN0IHVpbnQzMlZpZXcgPSBuZXcgVWludDMyQXJyYXkoIGJ1ZmZlciApO1xuXG5cdGNvbnN0IGJhc2VUYWJsZSA9IG5ldyBVaW50MzJBcnJheSggNTEyICk7XG5cdGNvbnN0IHNoaWZ0VGFibGUgPSBuZXcgVWludDMyQXJyYXkoIDUxMiApO1xuXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IDI1NjsgKysgaSApIHtcblxuXHRcdGNvbnN0IGUgPSBpIC0gMTI3O1xuXG5cdFx0Ly8gdmVyeSBzbWFsbCBudW1iZXIgKDAsIC0wKVxuXG5cdFx0aWYgKCBlIDwgLSAyNyApIHtcblxuXHRcdFx0YmFzZVRhYmxlWyBpIF0gPSAweDAwMDA7XG5cdFx0XHRiYXNlVGFibGVbIGkgfCAweDEwMCBdID0gMHg4MDAwO1xuXHRcdFx0c2hpZnRUYWJsZVsgaSBdID0gMjQ7XG5cdFx0XHRzaGlmdFRhYmxlWyBpIHwgMHgxMDAgXSA9IDI0O1xuXG5cdFx0XHQvLyBzbWFsbCBudW1iZXIgKGRlbm9ybSlcblxuXHRcdH0gZWxzZSBpZiAoIGUgPCAtIDE0ICkge1xuXG5cdFx0XHRiYXNlVGFibGVbIGkgXSA9IDB4MDQwMCA+PiAoIC0gZSAtIDE0ICk7XG5cdFx0XHRiYXNlVGFibGVbIGkgfCAweDEwMCBdID0gKCAweDA0MDAgPj4gKCAtIGUgLSAxNCApICkgfCAweDgwMDA7XG5cdFx0XHRzaGlmdFRhYmxlWyBpIF0gPSAtIGUgLSAxO1xuXHRcdFx0c2hpZnRUYWJsZVsgaSB8IDB4MTAwIF0gPSAtIGUgLSAxO1xuXG5cdFx0XHQvLyBub3JtYWwgbnVtYmVyXG5cblx0XHR9IGVsc2UgaWYgKCBlIDw9IDE1ICkge1xuXG5cdFx0XHRiYXNlVGFibGVbIGkgXSA9ICggZSArIDE1ICkgPDwgMTA7XG5cdFx0XHRiYXNlVGFibGVbIGkgfCAweDEwMCBdID0gKCAoIGUgKyAxNSApIDw8IDEwICkgfCAweDgwMDA7XG5cdFx0XHRzaGlmdFRhYmxlWyBpIF0gPSAxMztcblx0XHRcdHNoaWZ0VGFibGVbIGkgfCAweDEwMCBdID0gMTM7XG5cblx0XHRcdC8vIGxhcmdlIG51bWJlciAoSW5maW5pdHksIC1JbmZpbml0eSlcblxuXHRcdH0gZWxzZSBpZiAoIGUgPCAxMjggKSB7XG5cblx0XHRcdGJhc2VUYWJsZVsgaSBdID0gMHg3YzAwO1xuXHRcdFx0YmFzZVRhYmxlWyBpIHwgMHgxMDAgXSA9IDB4ZmMwMDtcblx0XHRcdHNoaWZ0VGFibGVbIGkgXSA9IDI0O1xuXHRcdFx0c2hpZnRUYWJsZVsgaSB8IDB4MTAwIF0gPSAyNDtcblxuXHRcdFx0Ly8gc3RheSAoTmFOLCBJbmZpbml0eSwgLUluZmluaXR5KVxuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0YmFzZVRhYmxlWyBpIF0gPSAweDdjMDA7XG5cdFx0XHRiYXNlVGFibGVbIGkgfCAweDEwMCBdID0gMHhmYzAwO1xuXHRcdFx0c2hpZnRUYWJsZVsgaSBdID0gMTM7XG5cdFx0XHRzaGlmdFRhYmxlWyBpIHwgMHgxMDAgXSA9IDEzO1xuXG5cdFx0fVxuXG5cdH1cblxuXHQvLyBmbG9hdDE2IHRvIGZsb2F0MzIgaGVscGVyc1xuXG5cdGNvbnN0IG1hbnRpc3NhVGFibGUgPSBuZXcgVWludDMyQXJyYXkoIDIwNDggKTtcblx0Y29uc3QgZXhwb25lbnRUYWJsZSA9IG5ldyBVaW50MzJBcnJheSggNjQgKTtcblx0Y29uc3Qgb2Zmc2V0VGFibGUgPSBuZXcgVWludDMyQXJyYXkoIDY0ICk7XG5cblx0Zm9yICggbGV0IGkgPSAxOyBpIDwgMTAyNDsgKysgaSApIHtcblxuXHRcdGxldCBtID0gaSA8PCAxMzsgLy8gemVybyBwYWQgbWFudGlzc2EgYml0c1xuXHRcdGxldCBlID0gMDsgLy8gemVybyBleHBvbmVudFxuXG5cdFx0Ly8gbm9ybWFsaXplZFxuXHRcdHdoaWxlICggKCBtICYgMHgwMDgwMDAwMCApID09PSAwICkge1xuXG5cdFx0XHRtIDw8PSAxO1xuXHRcdFx0ZSAtPSAweDAwODAwMDAwOyAvLyBkZWNyZW1lbnQgZXhwb25lbnRcblxuXHRcdH1cblxuXHRcdG0gJj0gfiAweDAwODAwMDAwOyAvLyBjbGVhciBsZWFkaW5nIDEgYml0XG5cdFx0ZSArPSAweDM4ODAwMDAwOyAvLyBhZGp1c3QgYmlhc1xuXG5cdFx0bWFudGlzc2FUYWJsZVsgaSBdID0gbSB8IGU7XG5cblx0fVxuXG5cdGZvciAoIGxldCBpID0gMTAyNDsgaSA8IDIwNDg7ICsrIGkgKSB7XG5cblx0XHRtYW50aXNzYVRhYmxlWyBpIF0gPSAweDM4MDAwMDAwICsgKCAoIGkgLSAxMDI0ICkgPDwgMTMgKTtcblxuXHR9XG5cblx0Zm9yICggbGV0IGkgPSAxOyBpIDwgMzE7ICsrIGkgKSB7XG5cblx0XHRleHBvbmVudFRhYmxlWyBpIF0gPSBpIDw8IDIzO1xuXG5cdH1cblxuXHRleHBvbmVudFRhYmxlWyAzMSBdID0gMHg0NzgwMDAwMDtcblx0ZXhwb25lbnRUYWJsZVsgMzIgXSA9IDB4ODAwMDAwMDA7XG5cblx0Zm9yICggbGV0IGkgPSAzMzsgaSA8IDYzOyArKyBpICkge1xuXG5cdFx0ZXhwb25lbnRUYWJsZVsgaSBdID0gMHg4MDAwMDAwMCArICggKCBpIC0gMzIgKSA8PCAyMyApO1xuXG5cdH1cblxuXHRleHBvbmVudFRhYmxlWyA2MyBdID0gMHhjNzgwMDAwMDtcblxuXHRmb3IgKCBsZXQgaSA9IDE7IGkgPCA2NDsgKysgaSApIHtcblxuXHRcdGlmICggaSAhPT0gMzIgKSB7XG5cblx0XHRcdG9mZnNldFRhYmxlWyBpIF0gPSAxMDI0O1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4ge1xuXHRcdGZsb2F0VmlldzogZmxvYXRWaWV3LFxuXHRcdHVpbnQzMlZpZXc6IHVpbnQzMlZpZXcsXG5cdFx0YmFzZVRhYmxlOiBiYXNlVGFibGUsXG5cdFx0c2hpZnRUYWJsZTogc2hpZnRUYWJsZSxcblx0XHRtYW50aXNzYVRhYmxlOiBtYW50aXNzYVRhYmxlLFxuXHRcdGV4cG9uZW50VGFibGU6IGV4cG9uZW50VGFibGUsXG5cdFx0b2Zmc2V0VGFibGU6IG9mZnNldFRhYmxlXG5cdH07XG5cbn1cblxuLy8gZmxvYXQzMiB0byBmbG9hdDE2XG5cbmZ1bmN0aW9uIHRvSGFsZkZsb2F0KCB2YWwgKSB7XG5cblx0aWYgKCBNYXRoLmFicyggdmFsICkgPiA2NTUwNCApIGNvbnNvbGUud2FybiggJ1RIUkVFLkRhdGFVdGlscy50b0hhbGZGbG9hdCgpOiBWYWx1ZSBvdXQgb2YgcmFuZ2UuJyApO1xuXG5cdHZhbCA9IGNsYW1wKCB2YWwsIC0gNjU1MDQsIDY1NTA0ICk7XG5cblx0X3RhYmxlcy5mbG9hdFZpZXdbIDAgXSA9IHZhbDtcblx0Y29uc3QgZiA9IF90YWJsZXMudWludDMyVmlld1sgMCBdO1xuXHRjb25zdCBlID0gKCBmID4+IDIzICkgJiAweDFmZjtcblx0cmV0dXJuIF90YWJsZXMuYmFzZVRhYmxlWyBlIF0gKyAoICggZiAmIDB4MDA3ZmZmZmYgKSA+PiBfdGFibGVzLnNoaWZ0VGFibGVbIGUgXSApO1xuXG59XG5cbi8vIGZsb2F0MTYgdG8gZmxvYXQzMlxuXG5mdW5jdGlvbiBmcm9tSGFsZkZsb2F0KCB2YWwgKSB7XG5cblx0Y29uc3QgbSA9IHZhbCA+PiAxMDtcblx0X3RhYmxlcy51aW50MzJWaWV3WyAwIF0gPSBfdGFibGVzLm1hbnRpc3NhVGFibGVbIF90YWJsZXMub2Zmc2V0VGFibGVbIG0gXSArICggdmFsICYgMHgzZmYgKSBdICsgX3RhYmxlcy5leHBvbmVudFRhYmxlWyBtIF07XG5cdHJldHVybiBfdGFibGVzLmZsb2F0Vmlld1sgMCBdO1xuXG59XG5cbmNvbnN0IERhdGFVdGlscyA9IHtcblx0dG9IYWxmRmxvYXQ6IHRvSGFsZkZsb2F0LFxuXHRmcm9tSGFsZkZsb2F0OiBmcm9tSGFsZkZsb2F0LFxufTtcblxuY29uc3QgX3ZlY3RvciQ5ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3ZlY3RvcjIkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcblxuY2xhc3MgQnVmZmVyQXR0cmlidXRlIHtcblxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkID0gZmFsc2UgKSB7XG5cblx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIGFycmF5ICkgKSB7XG5cblx0XHRcdHRocm93IG5ldyBUeXBlRXJyb3IoICdUSFJFRS5CdWZmZXJBdHRyaWJ1dGU6IGFycmF5IHNob3VsZCBiZSBhIFR5cGVkIEFycmF5LicgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuaXNCdWZmZXJBdHRyaWJ1dGUgPSB0cnVlO1xuXG5cdFx0dGhpcy5uYW1lID0gJyc7XG5cblx0XHR0aGlzLmFycmF5ID0gYXJyYXk7XG5cdFx0dGhpcy5pdGVtU2l6ZSA9IGl0ZW1TaXplO1xuXHRcdHRoaXMuY291bnQgPSBhcnJheSAhPT0gdW5kZWZpbmVkID8gYXJyYXkubGVuZ3RoIC8gaXRlbVNpemUgOiAwO1xuXHRcdHRoaXMubm9ybWFsaXplZCA9IG5vcm1hbGl6ZWQ7XG5cblx0XHR0aGlzLnVzYWdlID0gU3RhdGljRHJhd1VzYWdlO1xuXHRcdHRoaXMuX3VwZGF0ZVJhbmdlID0geyBvZmZzZXQ6IDAsIGNvdW50OiAtIDEgfTtcblx0XHR0aGlzLnVwZGF0ZVJhbmdlcyA9IFtdO1xuXHRcdHRoaXMuZ3B1VHlwZSA9IEZsb2F0VHlwZTtcblxuXHRcdHRoaXMudmVyc2lvbiA9IDA7XG5cblx0fVxuXG5cdG9uVXBsb2FkQ2FsbGJhY2soKSB7fVxuXG5cdHNldCBuZWVkc1VwZGF0ZSggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHZhbHVlID09PSB0cnVlICkgdGhpcy52ZXJzaW9uICsrO1xuXG5cdH1cblxuXHRnZXQgdXBkYXRlUmFuZ2UoKSB7XG5cblx0XHR3YXJuT25jZSggJ1RIUkVFLkJ1ZmZlckF0dHJpYnV0ZTogdXBkYXRlUmFuZ2UoKSBpcyBkZXByZWNhdGVkIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gcjE2OS4gVXNlIGFkZFVwZGF0ZVJhbmdlKCkgaW5zdGVhZC4nICk7IC8vIEBkZXByZWNhdGVkLCByMTU5XG5cdFx0cmV0dXJuIHRoaXMuX3VwZGF0ZVJhbmdlO1xuXG5cdH1cblxuXHRzZXRVc2FnZSggdmFsdWUgKSB7XG5cblx0XHR0aGlzLnVzYWdlID0gdmFsdWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkVXBkYXRlUmFuZ2UoIHN0YXJ0LCBjb3VudCApIHtcblxuXHRcdHRoaXMudXBkYXRlUmFuZ2VzLnB1c2goIHsgc3RhcnQsIGNvdW50IH0gKTtcblxuXHR9XG5cblx0Y2xlYXJVcGRhdGVSYW5nZXMoKSB7XG5cblx0XHR0aGlzLnVwZGF0ZVJhbmdlcy5sZW5ndGggPSAwO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHR0aGlzLm5hbWUgPSBzb3VyY2UubmFtZTtcblx0XHR0aGlzLmFycmF5ID0gbmV3IHNvdXJjZS5hcnJheS5jb25zdHJ1Y3Rvciggc291cmNlLmFycmF5ICk7XG5cdFx0dGhpcy5pdGVtU2l6ZSA9IHNvdXJjZS5pdGVtU2l6ZTtcblx0XHR0aGlzLmNvdW50ID0gc291cmNlLmNvdW50O1xuXHRcdHRoaXMubm9ybWFsaXplZCA9IHNvdXJjZS5ub3JtYWxpemVkO1xuXG5cdFx0dGhpcy51c2FnZSA9IHNvdXJjZS51c2FnZTtcblx0XHR0aGlzLmdwdVR5cGUgPSBzb3VyY2UuZ3B1VHlwZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb3B5QXQoIGluZGV4MSwgYXR0cmlidXRlLCBpbmRleDIgKSB7XG5cblx0XHRpbmRleDEgKj0gdGhpcy5pdGVtU2l6ZTtcblx0XHRpbmRleDIgKj0gYXR0cmlidXRlLml0ZW1TaXplO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5pdGVtU2l6ZTsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuYXJyYXlbIGluZGV4MSArIGkgXSA9IGF0dHJpYnV0ZS5hcnJheVsgaW5kZXgyICsgaSBdO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvcHlBcnJheSggYXJyYXkgKSB7XG5cblx0XHR0aGlzLmFycmF5LnNldCggYXJyYXkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhcHBseU1hdHJpeDMoIG0gKSB7XG5cblx0XHRpZiAoIHRoaXMuaXRlbVNpemUgPT09IDIgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY291bnQ7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdF92ZWN0b3IyJDEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xuXHRcdFx0XHRfdmVjdG9yMiQxLmFwcGx5TWF0cml4MyggbSApO1xuXG5cdFx0XHRcdHRoaXMuc2V0WFkoIGksIF92ZWN0b3IyJDEueCwgX3ZlY3RvcjIkMS55ICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSBpZiAoIHRoaXMuaXRlbVNpemUgPT09IDMgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY291bnQ7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdF92ZWN0b3IkOS5mcm9tQnVmZmVyQXR0cmlidXRlKCB0aGlzLCBpICk7XG5cdFx0XHRcdF92ZWN0b3IkOS5hcHBseU1hdHJpeDMoIG0gKTtcblxuXHRcdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3RvciQ5LngsIF92ZWN0b3IkOS55LCBfdmVjdG9yJDkueiApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXBwbHlNYXRyaXg0KCBtICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5jb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdF92ZWN0b3IkOS5mcm9tQnVmZmVyQXR0cmlidXRlKCB0aGlzLCBpICk7XG5cblx0XHRcdF92ZWN0b3IkOS5hcHBseU1hdHJpeDQoIG0gKTtcblxuXHRcdFx0dGhpcy5zZXRYWVooIGksIF92ZWN0b3IkOS54LCBfdmVjdG9yJDkueSwgX3ZlY3RvciQ5LnogKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRhcHBseU5vcm1hbE1hdHJpeCggbSApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY291bnQ7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRfdmVjdG9yJDkuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xuXG5cdFx0XHRfdmVjdG9yJDkuYXBwbHlOb3JtYWxNYXRyaXgoIG0gKTtcblxuXHRcdFx0dGhpcy5zZXRYWVooIGksIF92ZWN0b3IkOS54LCBfdmVjdG9yJDkueSwgX3ZlY3RvciQ5LnogKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0cmFuc2Zvcm1EaXJlY3Rpb24oIG0gKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0X3ZlY3RvciQ5LmZyb21CdWZmZXJBdHRyaWJ1dGUoIHRoaXMsIGkgKTtcblxuXHRcdFx0X3ZlY3RvciQ5LnRyYW5zZm9ybURpcmVjdGlvbiggbSApO1xuXG5cdFx0XHR0aGlzLnNldFhZWiggaSwgX3ZlY3RvciQ5LngsIF92ZWN0b3IkOS55LCBfdmVjdG9yJDkueiApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldCggdmFsdWUsIG9mZnNldCA9IDAgKSB7XG5cblx0XHQvLyBNYXRjaGluZyBCdWZmZXJBdHRyaWJ1dGUgY29uc3RydWN0b3IsIGRvIG5vdCBub3JtYWxpemUgdGhlIGFycmF5LlxuXHRcdHRoaXMuYXJyYXkuc2V0KCB2YWx1ZSwgb2Zmc2V0ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0Q29tcG9uZW50KCBpbmRleCwgY29tcG9uZW50ICkge1xuXG5cdFx0bGV0IHZhbHVlID0gdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgY29tcG9uZW50IF07XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHZhbHVlID0gZGVub3JtYWxpemUoIHZhbHVlLCB0aGlzLmFycmF5ICk7XG5cblx0XHRyZXR1cm4gdmFsdWU7XG5cblx0fVxuXG5cdHNldENvbXBvbmVudCggaW5kZXgsIGNvbXBvbmVudCwgdmFsdWUgKSB7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHZhbHVlID0gbm9ybWFsaXplKCB2YWx1ZSwgdGhpcy5hcnJheSApO1xuXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgY29tcG9uZW50IF0gPSB2YWx1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRYKCBpbmRleCApIHtcblxuXHRcdGxldCB4ID0gdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplIF07XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHggPSBkZW5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHg7XG5cblx0fVxuXG5cdHNldFgoIGluZGV4LCB4ICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgXSA9IHg7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0WSggaW5kZXggKSB7XG5cblx0XHRsZXQgeSA9IHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDEgXTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IGRlbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cblx0XHRyZXR1cm4geTtcblxuXHR9XG5cblx0c2V0WSggaW5kZXgsIHkgKSB7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcblxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDEgXSA9IHk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0WiggaW5kZXggKSB7XG5cblx0XHRsZXQgeiA9IHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDIgXTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IGRlbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XG5cblx0XHRyZXR1cm4gejtcblxuXHR9XG5cblx0c2V0WiggaW5kZXgsIHogKSB7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHogPSBub3JtYWxpemUoIHosIHRoaXMuYXJyYXkgKTtcblxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDIgXSA9IHo7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0VyggaW5kZXggKSB7XG5cblx0XHRsZXQgdyA9IHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDMgXTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdyA9IGRlbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XG5cblx0XHRyZXR1cm4gdztcblxuXHR9XG5cblx0c2V0VyggaW5kZXgsIHcgKSB7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHcgPSBub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcblxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDMgXSA9IHc7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0WFkoIGluZGV4LCB4LCB5ICkge1xuXG5cdFx0aW5kZXggKj0gdGhpcy5pdGVtU2l6ZTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkge1xuXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDAgXSA9IHg7XG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAxIF0gPSB5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFhZWiggaW5kZXgsIHgsIHksIHogKSB7XG5cblx0XHRpbmRleCAqPSB0aGlzLml0ZW1TaXplO1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XG5cblx0XHRcdHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcblx0XHRcdHogPSBub3JtYWxpemUoIHosIHRoaXMuYXJyYXkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMCBdID0geDtcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDEgXSA9IHk7XG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAyIF0gPSB6O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFhZWlcoIGluZGV4LCB4LCB5LCB6LCB3ICkge1xuXG5cdFx0aW5kZXggKj0gdGhpcy5pdGVtU2l6ZTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkge1xuXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR3ID0gbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDAgXSA9IHg7XG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAxIF0gPSB5O1xuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMiBdID0gejtcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDMgXSA9IHc7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0b25VcGxvYWQoIGNhbGxiYWNrICkge1xuXG5cdFx0dGhpcy5vblVwbG9hZENhbGxiYWNrID0gY2FsbGJhY2s7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMuYXJyYXksIHRoaXMuaXRlbVNpemUgKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSB7XG5cdFx0XHRpdGVtU2l6ZTogdGhpcy5pdGVtU2l6ZSxcblx0XHRcdHR5cGU6IHRoaXMuYXJyYXkuY29uc3RydWN0b3IubmFtZSxcblx0XHRcdGFycmF5OiBBcnJheS5mcm9tKCB0aGlzLmFycmF5ICksXG5cdFx0XHRub3JtYWxpemVkOiB0aGlzLm5vcm1hbGl6ZWRcblx0XHR9O1xuXG5cdFx0aWYgKCB0aGlzLm5hbWUgIT09ICcnICkgZGF0YS5uYW1lID0gdGhpcy5uYW1lO1xuXHRcdGlmICggdGhpcy51c2FnZSAhPT0gU3RhdGljRHJhd1VzYWdlICkgZGF0YS51c2FnZSA9IHRoaXMudXNhZ2U7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cbn1cblxuLy9cblxuY2xhc3MgSW50OEJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XG5cblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcblxuXHRcdHN1cGVyKCBuZXcgSW50OEFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBVaW50OEJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XG5cblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcblxuXHRcdHN1cGVyKCBuZXcgVWludDhBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgVWludDhDbGFtcGVkQnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcblxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xuXG5cdFx0c3VwZXIoIG5ldyBVaW50OENsYW1wZWRBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgSW50MTZCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xuXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKSB7XG5cblx0XHRzdXBlciggbmV3IEludDE2QXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFVpbnQxNkJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XG5cblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApIHtcblxuXHRcdHN1cGVyKCBuZXcgVWludDE2QXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIEludDMyQnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcblxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xuXG5cdFx0c3VwZXIoIG5ldyBJbnQzMkFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBVaW50MzJCdWZmZXJBdHRyaWJ1dGUgZXh0ZW5kcyBCdWZmZXJBdHRyaWJ1dGUge1xuXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKSB7XG5cblx0XHRzdXBlciggbmV3IFVpbnQzMkFycmF5KCBhcnJheSApLCBpdGVtU2l6ZSwgbm9ybWFsaXplZCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBGbG9hdDE2QnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcblxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xuXG5cdFx0c3VwZXIoIG5ldyBVaW50MTZBcnJheSggYXJyYXkgKSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcblxuXHRcdHRoaXMuaXNGbG9hdDE2QnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcblxuXHR9XG5cblx0Z2V0WCggaW5kZXggKSB7XG5cblx0XHRsZXQgeCA9IGZyb21IYWxmRmxvYXQoIHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSBdICk7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHggPSBkZW5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHg7XG5cblx0fVxuXG5cdHNldFgoIGluZGV4LCB4ICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgXSA9IHRvSGFsZkZsb2F0KCB4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0WSggaW5kZXggKSB7XG5cblx0XHRsZXQgeSA9IGZyb21IYWxmRmxvYXQoIHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDEgXSApO1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB5ID0gZGVub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcblxuXHRcdHJldHVybiB5O1xuXG5cdH1cblxuXHRzZXRZKCBpbmRleCwgeSApIHtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xuXG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMSBdID0gdG9IYWxmRmxvYXQoIHkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRaKCBpbmRleCApIHtcblxuXHRcdGxldCB6ID0gZnJvbUhhbGZGbG9hdCggdGhpcy5hcnJheVsgaW5kZXggKiB0aGlzLml0ZW1TaXplICsgMiBdICk7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHogPSBkZW5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHo7XG5cblx0fVxuXG5cdHNldFooIGluZGV4LCB6ICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAyIF0gPSB0b0hhbGZGbG9hdCggeiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldFcoIGluZGV4ICkge1xuXG5cdFx0bGV0IHcgPSBmcm9tSGFsZkZsb2F0KCB0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuaXRlbVNpemUgKyAzIF0gKTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgdyA9IGRlbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XG5cblx0XHRyZXR1cm4gdztcblxuXHR9XG5cblx0c2V0VyggaW5kZXgsIHcgKSB7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHcgPSBub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcblxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICogdGhpcy5pdGVtU2l6ZSArIDMgXSA9IHRvSGFsZkZsb2F0KCB3ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0WFkoIGluZGV4LCB4LCB5ICkge1xuXG5cdFx0aW5kZXggKj0gdGhpcy5pdGVtU2l6ZTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkge1xuXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDAgXSA9IHRvSGFsZkZsb2F0KCB4ICk7XG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAxIF0gPSB0b0hhbGZGbG9hdCggeSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFhZWiggaW5kZXgsIHgsIHksIHogKSB7XG5cblx0XHRpbmRleCAqPSB0aGlzLml0ZW1TaXplO1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XG5cblx0XHRcdHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcblx0XHRcdHogPSBub3JtYWxpemUoIHosIHRoaXMuYXJyYXkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMCBdID0gdG9IYWxmRmxvYXQoIHggKTtcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDEgXSA9IHRvSGFsZkZsb2F0KCB5ICk7XG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAyIF0gPSB0b0hhbGZGbG9hdCggeiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFhZWlcoIGluZGV4LCB4LCB5LCB6LCB3ICkge1xuXG5cdFx0aW5kZXggKj0gdGhpcy5pdGVtU2l6ZTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkge1xuXG5cdFx0XHR4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR6ID0gbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XG5cdFx0XHR3ID0gbm9ybWFsaXplKCB3LCB0aGlzLmFycmF5ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDAgXSA9IHRvSGFsZkZsb2F0KCB4ICk7XG5cdFx0dGhpcy5hcnJheVsgaW5kZXggKyAxIF0gPSB0b0hhbGZGbG9hdCggeSApO1xuXHRcdHRoaXMuYXJyYXlbIGluZGV4ICsgMiBdID0gdG9IYWxmRmxvYXQoIHogKTtcblx0XHR0aGlzLmFycmF5WyBpbmRleCArIDMgXSA9IHRvSGFsZkZsb2F0KCB3ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuXG5jbGFzcyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlIGV4dGVuZHMgQnVmZmVyQXR0cmlidXRlIHtcblxuXHRjb25zdHJ1Y3RvciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICkge1xuXG5cdFx0c3VwZXIoIG5ldyBGbG9hdDMyQXJyYXkoIGFycmF5ICksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XG5cblx0fVxuXG59XG5cbmxldCBfaWQkMiA9IDA7XG5cbmNvbnN0IF9tMSQyID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX29iaiA9IC8qQF9fUFVSRV9fKi8gbmV3IE9iamVjdDNEKCk7XG5jb25zdCBfb2Zmc2V0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2JveCQyID0gLypAX19QVVJFX18qLyBuZXcgQm94MygpO1xuY29uc3QgX2JveE1vcnBoVGFyZ2V0cyA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcbmNvbnN0IF92ZWN0b3IkOCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgQnVmZmVyR2VvbWV0cnkgZXh0ZW5kcyBFdmVudERpc3BhdGNoZXIge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNCdWZmZXJHZW9tZXRyeSA9IHRydWU7XG5cblx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoIHRoaXMsICdpZCcsIHsgdmFsdWU6IF9pZCQyICsrIH0gKTtcblxuXHRcdHRoaXMudXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0dGhpcy5uYW1lID0gJyc7XG5cdFx0dGhpcy50eXBlID0gJ0J1ZmZlckdlb21ldHJ5JztcblxuXHRcdHRoaXMuaW5kZXggPSBudWxsO1xuXHRcdHRoaXMuYXR0cmlidXRlcyA9IHt9O1xuXG5cdFx0dGhpcy5tb3JwaEF0dHJpYnV0ZXMgPSB7fTtcblx0XHR0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlID0gZmFsc2U7XG5cblx0XHR0aGlzLmdyb3VwcyA9IFtdO1xuXG5cdFx0dGhpcy5ib3VuZGluZ0JveCA9IG51bGw7XG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG51bGw7XG5cblx0XHR0aGlzLmRyYXdSYW5nZSA9IHsgc3RhcnQ6IDAsIGNvdW50OiBJbmZpbml0eSB9O1xuXG5cdFx0dGhpcy51c2VyRGF0YSA9IHt9O1xuXG5cdH1cblxuXHRnZXRJbmRleCgpIHtcblxuXHRcdHJldHVybiB0aGlzLmluZGV4O1xuXG5cdH1cblxuXHRzZXRJbmRleCggaW5kZXggKSB7XG5cblx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIGluZGV4ICkgKSB7XG5cblx0XHRcdHRoaXMuaW5kZXggPSBuZXcgKCBhcnJheU5lZWRzVWludDMyKCBpbmRleCApID8gVWludDMyQnVmZmVyQXR0cmlidXRlIDogVWludDE2QnVmZmVyQXR0cmlidXRlICkoIGluZGV4LCAxICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLmluZGV4ID0gaW5kZXg7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0QXR0cmlidXRlKCBuYW1lICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuYXR0cmlidXRlc1sgbmFtZSBdO1xuXG5cdH1cblxuXHRzZXRBdHRyaWJ1dGUoIG5hbWUsIGF0dHJpYnV0ZSApIHtcblxuXHRcdHRoaXMuYXR0cmlidXRlc1sgbmFtZSBdID0gYXR0cmlidXRlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRlbGV0ZUF0dHJpYnV0ZSggbmFtZSApIHtcblxuXHRcdGRlbGV0ZSB0aGlzLmF0dHJpYnV0ZXNbIG5hbWUgXTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRoYXNBdHRyaWJ1dGUoIG5hbWUgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5hdHRyaWJ1dGVzWyBuYW1lIF0gIT09IHVuZGVmaW5lZDtcblxuXHR9XG5cblx0YWRkR3JvdXAoIHN0YXJ0LCBjb3VudCwgbWF0ZXJpYWxJbmRleCA9IDAgKSB7XG5cblx0XHR0aGlzLmdyb3Vwcy5wdXNoKCB7XG5cblx0XHRcdHN0YXJ0OiBzdGFydCxcblx0XHRcdGNvdW50OiBjb3VudCxcblx0XHRcdG1hdGVyaWFsSW5kZXg6IG1hdGVyaWFsSW5kZXhcblxuXHRcdH0gKTtcblxuXHR9XG5cblx0Y2xlYXJHcm91cHMoKSB7XG5cblx0XHR0aGlzLmdyb3VwcyA9IFtdO1xuXG5cdH1cblxuXHRzZXREcmF3UmFuZ2UoIHN0YXJ0LCBjb3VudCApIHtcblxuXHRcdHRoaXMuZHJhd1JhbmdlLnN0YXJ0ID0gc3RhcnQ7XG5cdFx0dGhpcy5kcmF3UmFuZ2UuY291bnQgPSBjb3VudDtcblxuXHR9XG5cblx0YXBwbHlNYXRyaXg0KCBtYXRyaXggKSB7XG5cblx0XHRjb25zdCBwb3NpdGlvbiA9IHRoaXMuYXR0cmlidXRlcy5wb3NpdGlvbjtcblxuXHRcdGlmICggcG9zaXRpb24gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0cG9zaXRpb24uYXBwbHlNYXRyaXg0KCBtYXRyaXggKTtcblxuXHRcdFx0cG9zaXRpb24ubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3Qgbm9ybWFsID0gdGhpcy5hdHRyaWJ1dGVzLm5vcm1hbDtcblxuXHRcdGlmICggbm9ybWFsICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IG5vcm1hbE1hdHJpeCA9IG5ldyBNYXRyaXgzKCkuZ2V0Tm9ybWFsTWF0cml4KCBtYXRyaXggKTtcblxuXHRcdFx0bm9ybWFsLmFwcGx5Tm9ybWFsTWF0cml4KCBub3JtYWxNYXRyaXggKTtcblxuXHRcdFx0bm9ybWFsLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHRhbmdlbnQgPSB0aGlzLmF0dHJpYnV0ZXMudGFuZ2VudDtcblxuXHRcdGlmICggdGFuZ2VudCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0YW5nZW50LnRyYW5zZm9ybURpcmVjdGlvbiggbWF0cml4ICk7XG5cblx0XHRcdHRhbmdlbnQubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nQm94ICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLmNvbXB1dGVCb3VuZGluZ0JveCgpO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFwcGx5UXVhdGVybmlvbiggcSApIHtcblxuXHRcdF9tMSQyLm1ha2VSb3RhdGlvbkZyb21RdWF0ZXJuaW9uKCBxICk7XG5cblx0XHR0aGlzLmFwcGx5TWF0cml4NCggX20xJDIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRyb3RhdGVYKCBhbmdsZSApIHtcblxuXHRcdC8vIHJvdGF0ZSBnZW9tZXRyeSBhcm91bmQgd29ybGQgeC1heGlzXG5cblx0XHRfbTEkMi5tYWtlUm90YXRpb25YKCBhbmdsZSApO1xuXG5cdFx0dGhpcy5hcHBseU1hdHJpeDQoIF9tMSQyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cm90YXRlWSggYW5nbGUgKSB7XG5cblx0XHQvLyByb3RhdGUgZ2VvbWV0cnkgYXJvdW5kIHdvcmxkIHktYXhpc1xuXG5cdFx0X20xJDIubWFrZVJvdGF0aW9uWSggYW5nbGUgKTtcblxuXHRcdHRoaXMuYXBwbHlNYXRyaXg0KCBfbTEkMiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJvdGF0ZVooIGFuZ2xlICkge1xuXG5cdFx0Ly8gcm90YXRlIGdlb21ldHJ5IGFyb3VuZCB3b3JsZCB6LWF4aXNcblxuXHRcdF9tMSQyLm1ha2VSb3RhdGlvblooIGFuZ2xlICk7XG5cblx0XHR0aGlzLmFwcGx5TWF0cml4NCggX20xJDIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0cmFuc2xhdGUoIHgsIHksIHogKSB7XG5cblx0XHQvLyB0cmFuc2xhdGUgZ2VvbWV0cnlcblxuXHRcdF9tMSQyLm1ha2VUcmFuc2xhdGlvbiggeCwgeSwgeiApO1xuXG5cdFx0dGhpcy5hcHBseU1hdHJpeDQoIF9tMSQyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2NhbGUoIHgsIHksIHogKSB7XG5cblx0XHQvLyBzY2FsZSBnZW9tZXRyeVxuXG5cdFx0X20xJDIubWFrZVNjYWxlKCB4LCB5LCB6ICk7XG5cblx0XHR0aGlzLmFwcGx5TWF0cml4NCggX20xJDIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRsb29rQXQoIHZlY3RvciApIHtcblxuXHRcdF9vYmoubG9va0F0KCB2ZWN0b3IgKTtcblxuXHRcdF9vYmoudXBkYXRlTWF0cml4KCk7XG5cblx0XHR0aGlzLmFwcGx5TWF0cml4NCggX29iai5tYXRyaXggKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjZW50ZXIoKSB7XG5cblx0XHR0aGlzLmNvbXB1dGVCb3VuZGluZ0JveCgpO1xuXG5cdFx0dGhpcy5ib3VuZGluZ0JveC5nZXRDZW50ZXIoIF9vZmZzZXQgKS5uZWdhdGUoKTtcblxuXHRcdHRoaXMudHJhbnNsYXRlKCBfb2Zmc2V0LngsIF9vZmZzZXQueSwgX29mZnNldC56ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbVBvaW50cyggcG9pbnRzICkge1xuXG5cdFx0Y29uc3QgcG9zaXRpb24gPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBwb2ludCA9IHBvaW50c1sgaSBdO1xuXHRcdFx0cG9zaXRpb24ucHVzaCggcG9pbnQueCwgcG9pbnQueSwgcG9pbnQueiB8fCAwICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uLCAzICkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb21wdXRlQm91bmRpbmdCb3goKSB7XG5cblx0XHRpZiAoIHRoaXMuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuYm91bmRpbmdCb3ggPSBuZXcgQm94MygpO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgcG9zaXRpb24gPSB0aGlzLmF0dHJpYnV0ZXMucG9zaXRpb247XG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24gPSB0aGlzLm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbjtcblxuXHRcdGlmICggcG9zaXRpb24gJiYgcG9zaXRpb24uaXNHTEJ1ZmZlckF0dHJpYnV0ZSApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLkJ1ZmZlckdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ0JveCgpOiBHTEJ1ZmZlckF0dHJpYnV0ZSByZXF1aXJlcyBhIG1hbnVhbCBib3VuZGluZyBib3guJywgdGhpcyApO1xuXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94LnNldChcblx0XHRcdFx0bmV3IFZlY3RvcjMoIC0gSW5maW5pdHksIC0gSW5maW5pdHksIC0gSW5maW5pdHkgKSxcblx0XHRcdFx0bmV3IFZlY3RvcjMoICsgSW5maW5pdHksICsgSW5maW5pdHksICsgSW5maW5pdHkgKVxuXHRcdFx0KTtcblxuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBwb3NpdGlvbiAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94LnNldEZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uICk7XG5cblx0XHRcdC8vIHByb2Nlc3MgbW9ycGggYXR0cmlidXRlcyBpZiBwcmVzZW50XG5cblx0XHRcdGlmICggbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24gKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvblsgaSBdO1xuXHRcdFx0XHRcdF9ib3gkMi5zZXRGcm9tQnVmZmVyQXR0cmlidXRlKCBtb3JwaEF0dHJpYnV0ZSApO1xuXG5cdFx0XHRcdFx0aWYgKCB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlICkge1xuXG5cdFx0XHRcdFx0XHRfdmVjdG9yJDguYWRkVmVjdG9ycyggdGhpcy5ib3VuZGluZ0JveC5taW4sIF9ib3gkMi5taW4gKTtcblx0XHRcdFx0XHRcdHRoaXMuYm91bmRpbmdCb3guZXhwYW5kQnlQb2ludCggX3ZlY3RvciQ4ICk7XG5cblx0XHRcdFx0XHRcdF92ZWN0b3IkOC5hZGRWZWN0b3JzKCB0aGlzLmJvdW5kaW5nQm94Lm1heCwgX2JveCQyLm1heCApO1xuXHRcdFx0XHRcdFx0dGhpcy5ib3VuZGluZ0JveC5leHBhbmRCeVBvaW50KCBfdmVjdG9yJDggKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHRoaXMuYm91bmRpbmdCb3guZXhwYW5kQnlQb2ludCggX2JveCQyLm1pbiApO1xuXHRcdFx0XHRcdFx0dGhpcy5ib3VuZGluZ0JveC5leHBhbmRCeVBvaW50KCBfYm94JDIubWF4ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94Lm1ha2VFbXB0eSgpO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBpc05hTiggdGhpcy5ib3VuZGluZ0JveC5taW4ueCApIHx8IGlzTmFOKCB0aGlzLmJvdW5kaW5nQm94Lm1pbi55ICkgfHwgaXNOYU4oIHRoaXMuYm91bmRpbmdCb3gubWluLnogKSApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLkJ1ZmZlckdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ0JveCgpOiBDb21wdXRlZCBtaW4vbWF4IGhhdmUgTmFOIHZhbHVlcy4gVGhlIFwicG9zaXRpb25cIiBhdHRyaWJ1dGUgaXMgbGlrZWx5IHRvIGhhdmUgTmFOIHZhbHVlcy4nLCB0aGlzICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpIHtcblxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG5ldyBTcGhlcmUoKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHBvc2l0aW9uID0gdGhpcy5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uID0gdGhpcy5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb247XG5cblx0XHRpZiAoIHBvc2l0aW9uICYmIHBvc2l0aW9uLmlzR0xCdWZmZXJBdHRyaWJ1dGUgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5CdWZmZXJHZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTogR0xCdWZmZXJBdHRyaWJ1dGUgcmVxdWlyZXMgYSBtYW51YWwgYm91bmRpbmcgc3BoZXJlLicsIHRoaXMgKTtcblxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZS5zZXQoIG5ldyBWZWN0b3IzKCksIEluZmluaXR5ICk7XG5cblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdGlmICggcG9zaXRpb24gKSB7XG5cblx0XHRcdC8vIGZpcnN0LCBmaW5kIHRoZSBjZW50ZXIgb2YgdGhlIGJvdW5kaW5nIHNwaGVyZVxuXG5cdFx0XHRjb25zdCBjZW50ZXIgPSB0aGlzLmJvdW5kaW5nU3BoZXJlLmNlbnRlcjtcblxuXHRcdFx0X2JveCQyLnNldEZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uICk7XG5cblx0XHRcdC8vIHByb2Nlc3MgbW9ycGggYXR0cmlidXRlcyBpZiBwcmVzZW50XG5cblx0XHRcdGlmICggbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb24gKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvblsgaSBdO1xuXHRcdFx0XHRcdF9ib3hNb3JwaFRhcmdldHMuc2V0RnJvbUJ1ZmZlckF0dHJpYnV0ZSggbW9ycGhBdHRyaWJ1dGUgKTtcblxuXHRcdFx0XHRcdGlmICggdGhpcy5tb3JwaFRhcmdldHNSZWxhdGl2ZSApIHtcblxuXHRcdFx0XHRcdFx0X3ZlY3RvciQ4LmFkZFZlY3RvcnMoIF9ib3gkMi5taW4sIF9ib3hNb3JwaFRhcmdldHMubWluICk7XG5cdFx0XHRcdFx0XHRfYm94JDIuZXhwYW5kQnlQb2ludCggX3ZlY3RvciQ4ICk7XG5cblx0XHRcdFx0XHRcdF92ZWN0b3IkOC5hZGRWZWN0b3JzKCBfYm94JDIubWF4LCBfYm94TW9ycGhUYXJnZXRzLm1heCApO1xuXHRcdFx0XHRcdFx0X2JveCQyLmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IkOCApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0X2JveCQyLmV4cGFuZEJ5UG9pbnQoIF9ib3hNb3JwaFRhcmdldHMubWluICk7XG5cdFx0XHRcdFx0XHRfYm94JDIuZXhwYW5kQnlQb2ludCggX2JveE1vcnBoVGFyZ2V0cy5tYXggKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0X2JveCQyLmdldENlbnRlciggY2VudGVyICk7XG5cblx0XHRcdC8vIHNlY29uZCwgdHJ5IHRvIGZpbmQgYSBib3VuZGluZ1NwaGVyZSB3aXRoIGEgcmFkaXVzIHNtYWxsZXIgdGhhbiB0aGVcblx0XHRcdC8vIGJvdW5kaW5nU3BoZXJlIG9mIHRoZSBib3VuZGluZ0JveDogc3FydCgzKSBzbWFsbGVyIGluIHRoZSBiZXN0IGNhc2VcblxuXHRcdFx0bGV0IG1heFJhZGl1c1NxID0gMDtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHBvc2l0aW9uLmNvdW50OyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0X3ZlY3RvciQ4LmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uLCBpICk7XG5cblx0XHRcdFx0bWF4UmFkaXVzU3EgPSBNYXRoLm1heCggbWF4UmFkaXVzU3EsIGNlbnRlci5kaXN0YW5jZVRvU3F1YXJlZCggX3ZlY3RvciQ4ICkgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBwcm9jZXNzIG1vcnBoIGF0dHJpYnV0ZXMgaWYgcHJlc2VudFxuXG5cdFx0XHRpZiAoIG1vcnBoQXR0cmlidXRlc1Bvc2l0aW9uICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtb3JwaEF0dHJpYnV0ZXNQb3NpdGlvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gbW9ycGhBdHRyaWJ1dGVzUG9zaXRpb25bIGkgXTtcblx0XHRcdFx0XHRjb25zdCBtb3JwaFRhcmdldHNSZWxhdGl2ZSA9IHRoaXMubW9ycGhUYXJnZXRzUmVsYXRpdmU7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIGpsID0gbW9ycGhBdHRyaWJ1dGUuY291bnQ7IGogPCBqbDsgaiArKyApIHtcblxuXHRcdFx0XHRcdFx0X3ZlY3RvciQ4LmZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoQXR0cmlidXRlLCBqICk7XG5cblx0XHRcdFx0XHRcdGlmICggbW9ycGhUYXJnZXRzUmVsYXRpdmUgKSB7XG5cblx0XHRcdFx0XHRcdFx0X29mZnNldC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaiApO1xuXHRcdFx0XHRcdFx0XHRfdmVjdG9yJDguYWRkKCBfb2Zmc2V0ICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0bWF4UmFkaXVzU3EgPSBNYXRoLm1heCggbWF4UmFkaXVzU3EsIGNlbnRlci5kaXN0YW5jZVRvU3F1YXJlZCggX3ZlY3RvciQ4ICkgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZS5yYWRpdXMgPSBNYXRoLnNxcnQoIG1heFJhZGl1c1NxICk7XG5cblx0XHRcdGlmICggaXNOYU4oIHRoaXMuYm91bmRpbmdTcGhlcmUucmFkaXVzICkgKSB7XG5cblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLkJ1ZmZlckdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpOiBDb21wdXRlZCByYWRpdXMgaXMgTmFOLiBUaGUgXCJwb3NpdGlvblwiIGF0dHJpYnV0ZSBpcyBsaWtlbHkgdG8gaGF2ZSBOYU4gdmFsdWVzLicsIHRoaXMgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRjb21wdXRlVGFuZ2VudHMoKSB7XG5cblx0XHRjb25zdCBpbmRleCA9IHRoaXMuaW5kZXg7XG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IHRoaXMuYXR0cmlidXRlcztcblxuXHRcdC8vIGJhc2VkIG9uIGh0dHA6Ly93d3cudGVyYXRob24uY29tL2NvZGUvdGFuZ2VudC5odG1sXG5cdFx0Ly8gKHBlciB2ZXJ0ZXggdGFuZ2VudHMpXG5cblx0XHRpZiAoIGluZGV4ID09PSBudWxsIHx8XG5cdFx0XHQgYXR0cmlidXRlcy5wb3NpdGlvbiA9PT0gdW5kZWZpbmVkIHx8XG5cdFx0XHQgYXR0cmlidXRlcy5ub3JtYWwgPT09IHVuZGVmaW5lZCB8fFxuXHRcdFx0IGF0dHJpYnV0ZXMudXYgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLkJ1ZmZlckdlb21ldHJ5OiAuY29tcHV0ZVRhbmdlbnRzKCkgZmFpbGVkLiBNaXNzaW5nIHJlcXVpcmVkIGF0dHJpYnV0ZXMgKGluZGV4LCBwb3NpdGlvbiwgbm9ybWFsIG9yIHV2KScgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gYXR0cmlidXRlcy5wb3NpdGlvbjtcblx0XHRjb25zdCBub3JtYWxBdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzLm5vcm1hbDtcblx0XHRjb25zdCB1dkF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXMudXY7XG5cblx0XHRpZiAoIHRoaXMuaGFzQXR0cmlidXRlKCAndGFuZ2VudCcgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndGFuZ2VudCcsIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIG5ldyBGbG9hdDMyQXJyYXkoIDQgKiBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudCApLCA0ICkgKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHRhbmdlbnRBdHRyaWJ1dGUgPSB0aGlzLmdldEF0dHJpYnV0ZSggJ3RhbmdlbnQnICk7XG5cblx0XHRjb25zdCB0YW4xID0gW10sIHRhbjIgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHBvc2l0aW9uQXR0cmlidXRlLmNvdW50OyBpICsrICkge1xuXG5cdFx0XHR0YW4xWyBpIF0gPSBuZXcgVmVjdG9yMygpO1xuXHRcdFx0dGFuMlsgaSBdID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHZBID0gbmV3IFZlY3RvcjMoKSxcblx0XHRcdHZCID0gbmV3IFZlY3RvcjMoKSxcblx0XHRcdHZDID0gbmV3IFZlY3RvcjMoKSxcblxuXHRcdFx0dXZBID0gbmV3IFZlY3RvcjIoKSxcblx0XHRcdHV2QiA9IG5ldyBWZWN0b3IyKCksXG5cdFx0XHR1dkMgPSBuZXcgVmVjdG9yMigpLFxuXG5cdFx0XHRzZGlyID0gbmV3IFZlY3RvcjMoKSxcblx0XHRcdHRkaXIgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlVHJpYW5nbGUoIGEsIGIsIGMgKSB7XG5cblx0XHRcdHZBLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBhICk7XG5cdFx0XHR2Qi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgYiApO1xuXHRcdFx0dkMuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGMgKTtcblxuXHRcdFx0dXZBLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHV2QXR0cmlidXRlLCBhICk7XG5cdFx0XHR1dkIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXZBdHRyaWJ1dGUsIGIgKTtcblx0XHRcdHV2Qy5mcm9tQnVmZmVyQXR0cmlidXRlKCB1dkF0dHJpYnV0ZSwgYyApO1xuXG5cdFx0XHR2Qi5zdWIoIHZBICk7XG5cdFx0XHR2Qy5zdWIoIHZBICk7XG5cblx0XHRcdHV2Qi5zdWIoIHV2QSApO1xuXHRcdFx0dXZDLnN1YiggdXZBICk7XG5cblx0XHRcdGNvbnN0IHIgPSAxLjAgLyAoIHV2Qi54ICogdXZDLnkgLSB1dkMueCAqIHV2Qi55ICk7XG5cblx0XHRcdC8vIHNpbGVudGx5IGlnbm9yZSBkZWdlbmVyYXRlIHV2IHRyaWFuZ2xlcyBoYXZpbmcgY29pbmNpZGVudCBvciBjb2xpbmVhciB2ZXJ0aWNlc1xuXG5cdFx0XHRpZiAoICEgaXNGaW5pdGUoIHIgKSApIHJldHVybjtcblxuXHRcdFx0c2Rpci5jb3B5KCB2QiApLm11bHRpcGx5U2NhbGFyKCB1dkMueSApLmFkZFNjYWxlZFZlY3RvciggdkMsIC0gdXZCLnkgKS5tdWx0aXBseVNjYWxhciggciApO1xuXHRcdFx0dGRpci5jb3B5KCB2QyApLm11bHRpcGx5U2NhbGFyKCB1dkIueCApLmFkZFNjYWxlZFZlY3RvciggdkIsIC0gdXZDLnggKS5tdWx0aXBseVNjYWxhciggciApO1xuXG5cdFx0XHR0YW4xWyBhIF0uYWRkKCBzZGlyICk7XG5cdFx0XHR0YW4xWyBiIF0uYWRkKCBzZGlyICk7XG5cdFx0XHR0YW4xWyBjIF0uYWRkKCBzZGlyICk7XG5cblx0XHRcdHRhbjJbIGEgXS5hZGQoIHRkaXIgKTtcblx0XHRcdHRhbjJbIGIgXS5hZGQoIHRkaXIgKTtcblx0XHRcdHRhbjJbIGMgXS5hZGQoIHRkaXIgKTtcblxuXHRcdH1cblxuXHRcdGxldCBncm91cHMgPSB0aGlzLmdyb3VwcztcblxuXHRcdGlmICggZ3JvdXBzLmxlbmd0aCA9PT0gMCApIHtcblxuXHRcdFx0Z3JvdXBzID0gWyB7XG5cdFx0XHRcdHN0YXJ0OiAwLFxuXHRcdFx0XHRjb3VudDogaW5kZXguY291bnRcblx0XHRcdH0gXTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBncm91cHMubGVuZ3RoOyBpIDwgaWw7ICsrIGkgKSB7XG5cblx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBpIF07XG5cblx0XHRcdGNvbnN0IHN0YXJ0ID0gZ3JvdXAuc3RhcnQ7XG5cdFx0XHRjb25zdCBjb3VudCA9IGdyb3VwLmNvdW50O1xuXG5cdFx0XHRmb3IgKCBsZXQgaiA9IHN0YXJ0LCBqbCA9IHN0YXJ0ICsgY291bnQ7IGogPCBqbDsgaiArPSAzICkge1xuXG5cdFx0XHRcdGhhbmRsZVRyaWFuZ2xlKFxuXHRcdFx0XHRcdGluZGV4LmdldFgoIGogKyAwICksXG5cdFx0XHRcdFx0aW5kZXguZ2V0WCggaiArIDEgKSxcblx0XHRcdFx0XHRpbmRleC5nZXRYKCBqICsgMiApXG5cdFx0XHRcdCk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IHRtcCA9IG5ldyBWZWN0b3IzKCksIHRtcDIgPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IG4gPSBuZXcgVmVjdG9yMygpLCBuMiA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVWZXJ0ZXgoIHYgKSB7XG5cblx0XHRcdG4uZnJvbUJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFsQXR0cmlidXRlLCB2ICk7XG5cdFx0XHRuMi5jb3B5KCBuICk7XG5cblx0XHRcdGNvbnN0IHQgPSB0YW4xWyB2IF07XG5cblx0XHRcdC8vIEdyYW0tU2NobWlkdCBvcnRob2dvbmFsaXplXG5cblx0XHRcdHRtcC5jb3B5KCB0ICk7XG5cdFx0XHR0bXAuc3ViKCBuLm11bHRpcGx5U2NhbGFyKCBuLmRvdCggdCApICkgKS5ub3JtYWxpemUoKTtcblxuXHRcdFx0Ly8gQ2FsY3VsYXRlIGhhbmRlZG5lc3NcblxuXHRcdFx0dG1wMi5jcm9zc1ZlY3RvcnMoIG4yLCB0ICk7XG5cdFx0XHRjb25zdCB0ZXN0ID0gdG1wMi5kb3QoIHRhbjJbIHYgXSApO1xuXHRcdFx0Y29uc3QgdyA9ICggdGVzdCA8IDAuMCApID8gLSAxLjAgOiAxLjA7XG5cblx0XHRcdHRhbmdlbnRBdHRyaWJ1dGUuc2V0WFlaVyggdiwgdG1wLngsIHRtcC55LCB0bXAueiwgdyApO1xuXG5cdFx0fVxuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGdyb3Vwcy5sZW5ndGg7IGkgPCBpbDsgKysgaSApIHtcblxuXHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcblxuXHRcdFx0Y29uc3Qgc3RhcnQgPSBncm91cC5zdGFydDtcblx0XHRcdGNvbnN0IGNvdW50ID0gZ3JvdXAuY291bnQ7XG5cblx0XHRcdGZvciAoIGxldCBqID0gc3RhcnQsIGpsID0gc3RhcnQgKyBjb3VudDsgaiA8IGpsOyBqICs9IDMgKSB7XG5cblx0XHRcdFx0aGFuZGxlVmVydGV4KCBpbmRleC5nZXRYKCBqICsgMCApICk7XG5cdFx0XHRcdGhhbmRsZVZlcnRleCggaW5kZXguZ2V0WCggaiArIDEgKSApO1xuXHRcdFx0XHRoYW5kbGVWZXJ0ZXgoIGluZGV4LmdldFgoIGogKyAyICkgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRjb21wdXRlVmVydGV4Tm9ybWFscygpIHtcblxuXHRcdGNvbnN0IGluZGV4ID0gdGhpcy5pbmRleDtcblx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IHRoaXMuZ2V0QXR0cmlidXRlKCAncG9zaXRpb24nICk7XG5cblx0XHRpZiAoIHBvc2l0aW9uQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGxldCBub3JtYWxBdHRyaWJ1dGUgPSB0aGlzLmdldEF0dHJpYnV0ZSggJ25vcm1hbCcgKTtcblxuXHRcdFx0aWYgKCBub3JtYWxBdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUgPSBuZXcgQnVmZmVyQXR0cmlidXRlKCBuZXcgRmxvYXQzMkFycmF5KCBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudCAqIDMgKSwgMyApO1xuXHRcdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5vcm1hbEF0dHJpYnV0ZSApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIHJlc2V0IGV4aXN0aW5nIG5vcm1hbHMgdG8gemVyb1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBub3JtYWxBdHRyaWJ1dGUuY291bnQ7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdG5vcm1hbEF0dHJpYnV0ZS5zZXRYWVooIGksIDAsIDAsIDAgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgcEEgPSBuZXcgVmVjdG9yMygpLCBwQiA9IG5ldyBWZWN0b3IzKCksIHBDID0gbmV3IFZlY3RvcjMoKTtcblx0XHRcdGNvbnN0IG5BID0gbmV3IFZlY3RvcjMoKSwgbkIgPSBuZXcgVmVjdG9yMygpLCBuQyA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0XHRjb25zdCBjYiA9IG5ldyBWZWN0b3IzKCksIGFiID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdFx0Ly8gaW5kZXhlZCBlbGVtZW50c1xuXG5cdFx0XHRpZiAoIGluZGV4ICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBpbmRleC5jb3VudDsgaSA8IGlsOyBpICs9IDMgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB2QSA9IGluZGV4LmdldFgoIGkgKyAwICk7XG5cdFx0XHRcdFx0Y29uc3QgdkIgPSBpbmRleC5nZXRYKCBpICsgMSApO1xuXHRcdFx0XHRcdGNvbnN0IHZDID0gaW5kZXguZ2V0WCggaSArIDIgKTtcblxuXHRcdFx0XHRcdHBBLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCB2QSApO1xuXHRcdFx0XHRcdHBCLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCB2QiApO1xuXHRcdFx0XHRcdHBDLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCB2QyApO1xuXG5cdFx0XHRcdFx0Y2Iuc3ViVmVjdG9ycyggcEMsIHBCICk7XG5cdFx0XHRcdFx0YWIuc3ViVmVjdG9ycyggcEEsIHBCICk7XG5cdFx0XHRcdFx0Y2IuY3Jvc3MoIGFiICk7XG5cblx0XHRcdFx0XHRuQS5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWxBdHRyaWJ1dGUsIHZBICk7XG5cdFx0XHRcdFx0bkIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFsQXR0cmlidXRlLCB2QiApO1xuXHRcdFx0XHRcdG5DLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbEF0dHJpYnV0ZSwgdkMgKTtcblxuXHRcdFx0XHRcdG5BLmFkZCggY2IgKTtcblx0XHRcdFx0XHRuQi5hZGQoIGNiICk7XG5cdFx0XHRcdFx0bkMuYWRkKCBjYiApO1xuXG5cdFx0XHRcdFx0bm9ybWFsQXR0cmlidXRlLnNldFhZWiggdkEsIG5BLngsIG5BLnksIG5BLnogKTtcblx0XHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUuc2V0WFlaKCB2QiwgbkIueCwgbkIueSwgbkIueiApO1xuXHRcdFx0XHRcdG5vcm1hbEF0dHJpYnV0ZS5zZXRYWVooIHZDLCBuQy54LCBuQy55LCBuQy56ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIG5vbi1pbmRleGVkIGVsZW1lbnRzICh1bmNvbm5lY3RlZCB0cmlhbmdsZSBzb3VwKVxuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBwb3NpdGlvbkF0dHJpYnV0ZS5jb3VudDsgaSA8IGlsOyBpICs9IDMgKSB7XG5cblx0XHRcdFx0XHRwQS5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSArIDAgKTtcblx0XHRcdFx0XHRwQi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSArIDEgKTtcblx0XHRcdFx0XHRwQy5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSArIDIgKTtcblxuXHRcdFx0XHRcdGNiLnN1YlZlY3RvcnMoIHBDLCBwQiApO1xuXHRcdFx0XHRcdGFiLnN1YlZlY3RvcnMoIHBBLCBwQiApO1xuXHRcdFx0XHRcdGNiLmNyb3NzKCBhYiApO1xuXG5cdFx0XHRcdFx0bm9ybWFsQXR0cmlidXRlLnNldFhZWiggaSArIDAsIGNiLngsIGNiLnksIGNiLnogKTtcblx0XHRcdFx0XHRub3JtYWxBdHRyaWJ1dGUuc2V0WFlaKCBpICsgMSwgY2IueCwgY2IueSwgY2IueiApO1xuXHRcdFx0XHRcdG5vcm1hbEF0dHJpYnV0ZS5zZXRYWVooIGkgKyAyLCBjYi54LCBjYi55LCBjYi56ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMubm9ybWFsaXplTm9ybWFscygpO1xuXG5cdFx0XHRub3JtYWxBdHRyaWJ1dGUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRub3JtYWxpemVOb3JtYWxzKCkge1xuXG5cdFx0Y29uc3Qgbm9ybWFscyA9IHRoaXMuYXR0cmlidXRlcy5ub3JtYWw7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbm9ybWFscy5jb3VudDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRfdmVjdG9yJDguZnJvbUJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgaSApO1xuXG5cdFx0XHRfdmVjdG9yJDgubm9ybWFsaXplKCk7XG5cblx0XHRcdG5vcm1hbHMuc2V0WFlaKCBpLCBfdmVjdG9yJDgueCwgX3ZlY3RvciQ4LnksIF92ZWN0b3IkOC56ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHRvTm9uSW5kZXhlZCgpIHtcblxuXHRcdGZ1bmN0aW9uIGNvbnZlcnRCdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kaWNlcyApIHtcblxuXHRcdFx0Y29uc3QgYXJyYXkgPSBhdHRyaWJ1dGUuYXJyYXk7XG5cdFx0XHRjb25zdCBpdGVtU2l6ZSA9IGF0dHJpYnV0ZS5pdGVtU2l6ZTtcblx0XHRcdGNvbnN0IG5vcm1hbGl6ZWQgPSBhdHRyaWJ1dGUubm9ybWFsaXplZDtcblxuXHRcdFx0Y29uc3QgYXJyYXkyID0gbmV3IGFycmF5LmNvbnN0cnVjdG9yKCBpbmRpY2VzLmxlbmd0aCAqIGl0ZW1TaXplICk7XG5cblx0XHRcdGxldCBpbmRleCA9IDAsIGluZGV4MiA9IDA7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGluZGljZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRpZiAoIGF0dHJpYnV0ZS5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlICkge1xuXG5cdFx0XHRcdFx0aW5kZXggPSBpbmRpY2VzWyBpIF0gKiBhdHRyaWJ1dGUuZGF0YS5zdHJpZGUgKyBhdHRyaWJ1dGUub2Zmc2V0O1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRpbmRleCA9IGluZGljZXNbIGkgXSAqIGl0ZW1TaXplO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBpdGVtU2l6ZTsgaiArKyApIHtcblxuXHRcdFx0XHRcdGFycmF5MlsgaW5kZXgyICsrIF0gPSBhcnJheVsgaW5kZXggKysgXTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGFycmF5MiwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcblxuXHRcdH1cblxuXHRcdC8vXG5cblx0XHRpZiAoIHRoaXMuaW5kZXggPT09IG51bGwgKSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkJ1ZmZlckdlb21ldHJ5LnRvTm9uSW5kZXhlZCgpOiBCdWZmZXJHZW9tZXRyeSBpcyBhbHJlYWR5IG5vbi1pbmRleGVkLicgKTtcblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgZ2VvbWV0cnkyID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cblx0XHRjb25zdCBpbmRpY2VzID0gdGhpcy5pbmRleC5hcnJheTtcblx0XHRjb25zdCBhdHRyaWJ1dGVzID0gdGhpcy5hdHRyaWJ1dGVzO1xuXG5cdFx0Ly8gYXR0cmlidXRlc1xuXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBhdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzWyBuYW1lIF07XG5cblx0XHRcdGNvbnN0IG5ld0F0dHJpYnV0ZSA9IGNvbnZlcnRCdWZmZXJBdHRyaWJ1dGUoIGF0dHJpYnV0ZSwgaW5kaWNlcyApO1xuXG5cdFx0XHRnZW9tZXRyeTIuc2V0QXR0cmlidXRlKCBuYW1lLCBuZXdBdHRyaWJ1dGUgKTtcblxuXHRcdH1cblxuXHRcdC8vIG1vcnBoIGF0dHJpYnV0ZXNcblxuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlcyA9IHRoaXMubW9ycGhBdHRyaWJ1dGVzO1xuXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBtb3JwaEF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdGNvbnN0IG1vcnBoQXJyYXkgPSBbXTtcblx0XHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gbW9ycGhBdHRyaWJ1dGVzWyBuYW1lIF07IC8vIG1vcnBoQXR0cmlidXRlOiBhcnJheSBvZiBGbG9hdDMyQnVmZmVyQXR0cmlidXRlc1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbW9ycGhBdHRyaWJ1dGUubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgYXR0cmlidXRlID0gbW9ycGhBdHRyaWJ1dGVbIGkgXTtcblxuXHRcdFx0XHRjb25zdCBuZXdBdHRyaWJ1dGUgPSBjb252ZXJ0QnVmZmVyQXR0cmlidXRlKCBhdHRyaWJ1dGUsIGluZGljZXMgKTtcblxuXHRcdFx0XHRtb3JwaEFycmF5LnB1c2goIG5ld0F0dHJpYnV0ZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGdlb21ldHJ5Mi5tb3JwaEF0dHJpYnV0ZXNbIG5hbWUgXSA9IG1vcnBoQXJyYXk7XG5cblx0XHR9XG5cblx0XHRnZW9tZXRyeTIubW9ycGhUYXJnZXRzUmVsYXRpdmUgPSB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xuXG5cdFx0Ly8gZ3JvdXBzXG5cblx0XHRjb25zdCBncm91cHMgPSB0aGlzLmdyb3VwcztcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGdyb3Vwcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBncm91cCA9IGdyb3Vwc1sgaSBdO1xuXHRcdFx0Z2VvbWV0cnkyLmFkZEdyb3VwKCBncm91cC5zdGFydCwgZ3JvdXAuY291bnQsIGdyb3VwLm1hdGVyaWFsSW5kZXggKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBnZW9tZXRyeTI7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSB7XG5cdFx0XHRtZXRhZGF0YToge1xuXHRcdFx0XHR2ZXJzaW9uOiA0LjYsXG5cdFx0XHRcdHR5cGU6ICdCdWZmZXJHZW9tZXRyeScsXG5cdFx0XHRcdGdlbmVyYXRvcjogJ0J1ZmZlckdlb21ldHJ5LnRvSlNPTidcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0Ly8gc3RhbmRhcmQgQnVmZmVyR2VvbWV0cnkgc2VyaWFsaXphdGlvblxuXG5cdFx0ZGF0YS51dWlkID0gdGhpcy51dWlkO1xuXHRcdGRhdGEudHlwZSA9IHRoaXMudHlwZTtcblx0XHRpZiAoIHRoaXMubmFtZSAhPT0gJycgKSBkYXRhLm5hbWUgPSB0aGlzLm5hbWU7XG5cdFx0aWYgKCBPYmplY3Qua2V5cyggdGhpcy51c2VyRGF0YSApLmxlbmd0aCA+IDAgKSBkYXRhLnVzZXJEYXRhID0gdGhpcy51c2VyRGF0YTtcblxuXHRcdGlmICggdGhpcy5wYXJhbWV0ZXJzICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IHBhcmFtZXRlcnMgPSB0aGlzLnBhcmFtZXRlcnM7XG5cblx0XHRcdGZvciAoIGNvbnN0IGtleSBpbiBwYXJhbWV0ZXJzICkge1xuXG5cdFx0XHRcdGlmICggcGFyYW1ldGVyc1sga2V5IF0gIT09IHVuZGVmaW5lZCApIGRhdGFbIGtleSBdID0gcGFyYW1ldGVyc1sga2V5IF07XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGRhdGE7XG5cblx0XHR9XG5cblx0XHQvLyBmb3Igc2ltcGxpY2l0eSB0aGUgY29kZSBhc3N1bWVzIGF0dHJpYnV0ZXMgYXJlIG5vdCBzaGFyZWQgYWNyb3NzIGdlb21ldHJpZXMsIHNlZSAjMTU4MTFcblxuXHRcdGRhdGEuZGF0YSA9IHsgYXR0cmlidXRlczoge30gfTtcblxuXHRcdGNvbnN0IGluZGV4ID0gdGhpcy5pbmRleDtcblxuXHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XG5cblx0XHRcdGRhdGEuZGF0YS5pbmRleCA9IHtcblx0XHRcdFx0dHlwZTogaW5kZXguYXJyYXkuY29uc3RydWN0b3IubmFtZSxcblx0XHRcdFx0YXJyYXk6IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKCBpbmRleC5hcnJheSApXG5cdFx0XHR9O1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IHRoaXMuYXR0cmlidXRlcztcblxuXHRcdGZvciAoIGNvbnN0IGtleSBpbiBhdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzWyBrZXkgXTtcblxuXHRcdFx0ZGF0YS5kYXRhLmF0dHJpYnV0ZXNbIGtleSBdID0gYXR0cmlidXRlLnRvSlNPTiggZGF0YS5kYXRhICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZXMgPSB7fTtcblx0XHRsZXQgaGFzTW9ycGhBdHRyaWJ1dGVzID0gZmFsc2U7XG5cblx0XHRmb3IgKCBjb25zdCBrZXkgaW4gdGhpcy5tb3JwaEF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdGNvbnN0IGF0dHJpYnV0ZUFycmF5ID0gdGhpcy5tb3JwaEF0dHJpYnV0ZXNbIGtleSBdO1xuXG5cdFx0XHRjb25zdCBhcnJheSA9IFtdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXR0cmlidXRlQXJyYXkubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgYXR0cmlidXRlID0gYXR0cmlidXRlQXJyYXlbIGkgXTtcblxuXHRcdFx0XHRhcnJheS5wdXNoKCBhdHRyaWJ1dGUudG9KU09OKCBkYXRhLmRhdGEgKSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggYXJyYXkubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0XHRtb3JwaEF0dHJpYnV0ZXNbIGtleSBdID0gYXJyYXk7XG5cblx0XHRcdFx0aGFzTW9ycGhBdHRyaWJ1dGVzID0gdHJ1ZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBoYXNNb3JwaEF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdGRhdGEuZGF0YS5tb3JwaEF0dHJpYnV0ZXMgPSBtb3JwaEF0dHJpYnV0ZXM7XG5cdFx0XHRkYXRhLmRhdGEubW9ycGhUYXJnZXRzUmVsYXRpdmUgPSB0aGlzLm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgZ3JvdXBzID0gdGhpcy5ncm91cHM7XG5cblx0XHRpZiAoIGdyb3Vwcy5sZW5ndGggPiAwICkge1xuXG5cdFx0XHRkYXRhLmRhdGEuZ3JvdXBzID0gSlNPTi5wYXJzZSggSlNPTi5zdHJpbmdpZnkoIGdyb3VwcyApICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBib3VuZGluZ1NwaGVyZSA9IHRoaXMuYm91bmRpbmdTcGhlcmU7XG5cblx0XHRpZiAoIGJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkge1xuXG5cdFx0XHRkYXRhLmRhdGEuYm91bmRpbmdTcGhlcmUgPSB7XG5cdFx0XHRcdGNlbnRlcjogYm91bmRpbmdTcGhlcmUuY2VudGVyLnRvQXJyYXkoKSxcblx0XHRcdFx0cmFkaXVzOiBib3VuZGluZ1NwaGVyZS5yYWRpdXNcblx0XHRcdH07XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdC8vIHJlc2V0XG5cblx0XHR0aGlzLmluZGV4ID0gbnVsbDtcblx0XHR0aGlzLmF0dHJpYnV0ZXMgPSB7fTtcblx0XHR0aGlzLm1vcnBoQXR0cmlidXRlcyA9IHt9O1xuXHRcdHRoaXMuZ3JvdXBzID0gW107XG5cdFx0dGhpcy5ib3VuZGluZ0JveCA9IG51bGw7XG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG51bGw7XG5cblx0XHQvLyB1c2VkIGZvciBzdG9yaW5nIGNsb25lZCwgc2hhcmVkIGRhdGFcblxuXHRcdGNvbnN0IGRhdGEgPSB7fTtcblxuXHRcdC8vIG5hbWVcblxuXHRcdHRoaXMubmFtZSA9IHNvdXJjZS5uYW1lO1xuXG5cdFx0Ly8gaW5kZXhcblxuXHRcdGNvbnN0IGluZGV4ID0gc291cmNlLmluZGV4O1xuXG5cdFx0aWYgKCBpbmRleCAhPT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5zZXRJbmRleCggaW5kZXguY2xvbmUoIGRhdGEgKSApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gYXR0cmlidXRlc1xuXG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IHNvdXJjZS5hdHRyaWJ1dGVzO1xuXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBhdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzWyBuYW1lIF07XG5cdFx0XHR0aGlzLnNldEF0dHJpYnV0ZSggbmFtZSwgYXR0cmlidXRlLmNsb25lKCBkYXRhICkgKTtcblxuXHRcdH1cblxuXHRcdC8vIG1vcnBoIGF0dHJpYnV0ZXNcblxuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlcyA9IHNvdXJjZS5tb3JwaEF0dHJpYnV0ZXM7XG5cblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIG1vcnBoQXR0cmlidXRlcyApIHtcblxuXHRcdFx0Y29uc3QgYXJyYXkgPSBbXTtcblx0XHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gbW9ycGhBdHRyaWJ1dGVzWyBuYW1lIF07IC8vIG1vcnBoQXR0cmlidXRlOiBhcnJheSBvZiBGbG9hdDMyQnVmZmVyQXR0cmlidXRlc1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBtb3JwaEF0dHJpYnV0ZS5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGFycmF5LnB1c2goIG1vcnBoQXR0cmlidXRlWyBpIF0uY2xvbmUoIGRhdGEgKSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMubW9ycGhBdHRyaWJ1dGVzWyBuYW1lIF0gPSBhcnJheTtcblxuXHRcdH1cblxuXHRcdHRoaXMubW9ycGhUYXJnZXRzUmVsYXRpdmUgPSBzb3VyY2UubW9ycGhUYXJnZXRzUmVsYXRpdmU7XG5cblx0XHQvLyBncm91cHNcblxuXHRcdGNvbnN0IGdyb3VwcyA9IHNvdXJjZS5ncm91cHM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBncm91cHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcblx0XHRcdHRoaXMuYWRkR3JvdXAoIGdyb3VwLnN0YXJ0LCBncm91cC5jb3VudCwgZ3JvdXAubWF0ZXJpYWxJbmRleCApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gYm91bmRpbmcgYm94XG5cblx0XHRjb25zdCBib3VuZGluZ0JveCA9IHNvdXJjZS5ib3VuZGluZ0JveDtcblxuXHRcdGlmICggYm91bmRpbmdCb3ggIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuYm91bmRpbmdCb3ggPSBib3VuZGluZ0JveC5jbG9uZSgpO1xuXG5cdFx0fVxuXG5cdFx0Ly8gYm91bmRpbmcgc3BoZXJlXG5cblx0XHRjb25zdCBib3VuZGluZ1NwaGVyZSA9IHNvdXJjZS5ib3VuZGluZ1NwaGVyZTtcblxuXHRcdGlmICggYm91bmRpbmdTcGhlcmUgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBib3VuZGluZ1NwaGVyZS5jbG9uZSgpO1xuXG5cdFx0fVxuXG5cdFx0Ly8gZHJhdyByYW5nZVxuXG5cdFx0dGhpcy5kcmF3UmFuZ2Uuc3RhcnQgPSBzb3VyY2UuZHJhd1JhbmdlLnN0YXJ0O1xuXHRcdHRoaXMuZHJhd1JhbmdlLmNvdW50ID0gc291cmNlLmRyYXdSYW5nZS5jb3VudDtcblxuXHRcdC8vIHVzZXIgZGF0YVxuXG5cdFx0dGhpcy51c2VyRGF0YSA9IHNvdXJjZS51c2VyRGF0YTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9pbnZlcnNlTWF0cml4JDMgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfcmF5JDMgPSAvKkBfX1BVUkVfXyovIG5ldyBSYXkoKTtcbmNvbnN0IF9zcGhlcmUkNiA9IC8qQF9fUFVSRV9fKi8gbmV3IFNwaGVyZSgpO1xuY29uc3QgX3NwaGVyZUhpdEF0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jb25zdCBfdkEkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92QiQxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3ZDJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNvbnN0IF90ZW1wQSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9tb3JwaEEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNvbnN0IF91dkEkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcbmNvbnN0IF91dkIkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcbmNvbnN0IF91dkMkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcblxuY29uc3QgX25vcm1hbEEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfbm9ybWFsQiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9ub3JtYWxDID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jb25zdCBfaW50ZXJzZWN0aW9uUG9pbnQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfaW50ZXJzZWN0aW9uUG9pbnRXb3JsZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgTWVzaCBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvciggZ2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKSwgbWF0ZXJpYWwgPSBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoKSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTWVzaCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnTWVzaCc7XG5cblx0XHR0aGlzLmdlb21ldHJ5ID0gZ2VvbWV0cnk7XG5cdFx0dGhpcy5tYXRlcmlhbCA9IG1hdGVyaWFsO1xuXG5cdFx0dGhpcy51cGRhdGVNb3JwaFRhcmdldHMoKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0aWYgKCBzb3VyY2UubW9ycGhUYXJnZXRJbmZsdWVuY2VzICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHRoaXMubW9ycGhUYXJnZXRJbmZsdWVuY2VzID0gc291cmNlLm1vcnBoVGFyZ2V0SW5mbHVlbmNlcy5zbGljZSgpO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBzb3VyY2UubW9ycGhUYXJnZXREaWN0aW9uYXJ5ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5ID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5tb3JwaFRhcmdldERpY3Rpb25hcnkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMubWF0ZXJpYWwgPSBBcnJheS5pc0FycmF5KCBzb3VyY2UubWF0ZXJpYWwgKSA/IHNvdXJjZS5tYXRlcmlhbC5zbGljZSgpIDogc291cmNlLm1hdGVyaWFsO1xuXHRcdHRoaXMuZ2VvbWV0cnkgPSBzb3VyY2UuZ2VvbWV0cnk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dXBkYXRlTW9ycGhUYXJnZXRzKCkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzO1xuXHRcdGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyggbW9ycGhBdHRyaWJ1dGVzICk7XG5cblx0XHRpZiAoIGtleXMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNbIGtleXNbIDAgXSBdO1xuXG5cdFx0XHRpZiAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldEluZmx1ZW5jZXMgPSBbXTtcblx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldERpY3Rpb25hcnkgPSB7fTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgbSA9IDAsIG1sID0gbW9ycGhBdHRyaWJ1dGUubGVuZ3RoOyBtIDwgbWw7IG0gKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBuYW1lID0gbW9ycGhBdHRyaWJ1dGVbIG0gXS5uYW1lIHx8IFN0cmluZyggbSApO1xuXG5cdFx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldEluZmx1ZW5jZXMucHVzaCggMCApO1xuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5WyBuYW1lIF0gPSBtO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRnZXRWZXJ0ZXhQb3NpdGlvbiggaW5kZXgsIHRhcmdldCApIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcblx0XHRjb25zdCBwb3NpdGlvbiA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb247XG5cdFx0Y29uc3QgbW9ycGhQb3NpdGlvbiA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbjtcblx0XHRjb25zdCBtb3JwaFRhcmdldHNSZWxhdGl2ZSA9IGdlb21ldHJ5Lm1vcnBoVGFyZ2V0c1JlbGF0aXZlO1xuXG5cdFx0dGFyZ2V0LmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uLCBpbmRleCApO1xuXG5cdFx0Y29uc3QgbW9ycGhJbmZsdWVuY2VzID0gdGhpcy5tb3JwaFRhcmdldEluZmx1ZW5jZXM7XG5cblx0XHRpZiAoIG1vcnBoUG9zaXRpb24gJiYgbW9ycGhJbmZsdWVuY2VzICkge1xuXG5cdFx0XHRfbW9ycGhBLnNldCggMCwgMCwgMCApO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbW9ycGhQb3NpdGlvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbmZsdWVuY2UgPSBtb3JwaEluZmx1ZW5jZXNbIGkgXTtcblx0XHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaFBvc2l0aW9uWyBpIF07XG5cblx0XHRcdFx0aWYgKCBpbmZsdWVuY2UgPT09IDAgKSBjb250aW51ZTtcblxuXHRcdFx0XHRfdGVtcEEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggbW9ycGhBdHRyaWJ1dGUsIGluZGV4ICk7XG5cblx0XHRcdFx0aWYgKCBtb3JwaFRhcmdldHNSZWxhdGl2ZSApIHtcblxuXHRcdFx0XHRcdF9tb3JwaEEuYWRkU2NhbGVkVmVjdG9yKCBfdGVtcEEsIGluZmx1ZW5jZSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRfbW9ycGhBLmFkZFNjYWxlZFZlY3RvciggX3RlbXBBLnN1YiggdGFyZ2V0ICksIGluZmx1ZW5jZSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHR0YXJnZXQuYWRkKCBfbW9ycGhBICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGFyZ2V0O1xuXG5cdH1cblxuXHRyYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSB0aGlzLm1hdGVyaWFsO1xuXHRcdGNvbnN0IG1hdHJpeFdvcmxkID0gdGhpcy5tYXRyaXhXb3JsZDtcblxuXHRcdGlmICggbWF0ZXJpYWwgPT09IHVuZGVmaW5lZCApIHJldHVybjtcblxuXHRcdC8vIHRlc3Qgd2l0aCBib3VuZGluZyBzcGhlcmUgaW4gd29ybGQgc3BhY2VcblxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSBnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcblxuXHRcdF9zcGhlcmUkNi5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSApO1xuXHRcdF9zcGhlcmUkNi5hcHBseU1hdHJpeDQoIG1hdHJpeFdvcmxkICk7XG5cblx0XHQvLyBjaGVjayBkaXN0YW5jZSBmcm9tIHJheSBvcmlnaW4gdG8gYm91bmRpbmcgc3BoZXJlXG5cblx0XHRfcmF5JDMuY29weSggcmF5Y2FzdGVyLnJheSApLnJlY2FzdCggcmF5Y2FzdGVyLm5lYXIgKTtcblxuXHRcdGlmICggX3NwaGVyZSQ2LmNvbnRhaW5zUG9pbnQoIF9yYXkkMy5vcmlnaW4gKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdGlmICggX3JheSQzLmludGVyc2VjdFNwaGVyZSggX3NwaGVyZSQ2LCBfc3BoZXJlSGl0QXQgKSA9PT0gbnVsbCApIHJldHVybjtcblxuXHRcdFx0aWYgKCBfcmF5JDMub3JpZ2luLmRpc3RhbmNlVG9TcXVhcmVkKCBfc3BoZXJlSGl0QXQgKSA+ICggcmF5Y2FzdGVyLmZhciAtIHJheWNhc3Rlci5uZWFyICkgKiogMiApIHJldHVybjtcblxuXHRcdH1cblxuXHRcdC8vIGNvbnZlcnQgcmF5IHRvIGxvY2FsIHNwYWNlIG9mIG1lc2hcblxuXHRcdF9pbnZlcnNlTWF0cml4JDMuY29weSggbWF0cml4V29ybGQgKS5pbnZlcnQoKTtcblx0XHRfcmF5JDMuY29weSggcmF5Y2FzdGVyLnJheSApLmFwcGx5TWF0cml4NCggX2ludmVyc2VNYXRyaXgkMyApO1xuXG5cdFx0Ly8gdGVzdCB3aXRoIGJvdW5kaW5nIGJveCBpbiBsb2NhbCBzcGFjZVxuXG5cdFx0aWYgKCBnZW9tZXRyeS5ib3VuZGluZ0JveCAhPT0gbnVsbCApIHtcblxuXHRcdFx0aWYgKCBfcmF5JDMuaW50ZXJzZWN0c0JveCggZ2VvbWV0cnkuYm91bmRpbmdCb3ggKSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHR9XG5cblx0XHQvLyB0ZXN0IGZvciBpbnRlcnNlY3Rpb25zIHdpdGggZ2VvbWV0cnlcblxuXHRcdHRoaXMuX2NvbXB1dGVJbnRlcnNlY3Rpb25zKCByYXljYXN0ZXIsIGludGVyc2VjdHMsIF9yYXkkMyApO1xuXG5cdH1cblxuXHRfY29tcHV0ZUludGVyc2VjdGlvbnMoIHJheWNhc3RlciwgaW50ZXJzZWN0cywgcmF5TG9jYWxTcGFjZSApIHtcblxuXHRcdGxldCBpbnRlcnNlY3Rpb247XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSB0aGlzLm1hdGVyaWFsO1xuXG5cdFx0Y29uc3QgaW5kZXggPSBnZW9tZXRyeS5pbmRleDtcblx0XHRjb25zdCBwb3NpdGlvbiA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb247XG5cdFx0Y29uc3QgdXYgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnV2O1xuXHRcdGNvbnN0IHV2MSA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMudXYxO1xuXHRcdGNvbnN0IG5vcm1hbCA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMubm9ybWFsO1xuXHRcdGNvbnN0IGdyb3VwcyA9IGdlb21ldHJ5Lmdyb3Vwcztcblx0XHRjb25zdCBkcmF3UmFuZ2UgPSBnZW9tZXRyeS5kcmF3UmFuZ2U7XG5cblx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xuXG5cdFx0XHQvLyBpbmRleGVkIGJ1ZmZlciBnZW9tZXRyeVxuXG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsICkgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGdyb3Vwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBpIF07XG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXBNYXRlcmlhbCA9IG1hdGVyaWFsWyBncm91cC5tYXRlcmlhbEluZGV4IF07XG5cblx0XHRcdFx0XHRjb25zdCBzdGFydCA9IE1hdGgubWF4KCBncm91cC5zdGFydCwgZHJhd1JhbmdlLnN0YXJ0ICk7XG5cdFx0XHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIGluZGV4LmNvdW50LCBNYXRoLm1pbiggKCBncm91cC5zdGFydCArIGdyb3VwLmNvdW50ICksICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKSApO1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGogPSBzdGFydCwgamwgPSBlbmQ7IGogPCBqbDsgaiArPSAzICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBhID0gaW5kZXguZ2V0WCggaiApO1xuXHRcdFx0XHRcdFx0Y29uc3QgYiA9IGluZGV4LmdldFgoIGogKyAxICk7XG5cdFx0XHRcdFx0XHRjb25zdCBjID0gaW5kZXguZ2V0WCggaiArIDIgKTtcblxuXHRcdFx0XHRcdFx0aW50ZXJzZWN0aW9uID0gY2hlY2tHZW9tZXRyeUludGVyc2VjdGlvbiggdGhpcywgZ3JvdXBNYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXlMb2NhbFNwYWNlLCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKTtcblxuXHRcdFx0XHRcdFx0aWYgKCBpbnRlcnNlY3Rpb24gKSB7XG5cblx0XHRcdFx0XHRcdFx0aW50ZXJzZWN0aW9uLmZhY2VJbmRleCA9IE1hdGguZmxvb3IoIGogLyAzICk7IC8vIHRyaWFuZ2xlIG51bWJlciBpbiBpbmRleGVkIGJ1ZmZlciBzZW1hbnRpY3Ncblx0XHRcdFx0XHRcdFx0aW50ZXJzZWN0aW9uLmZhY2UubWF0ZXJpYWxJbmRleCA9IGdyb3VwLm1hdGVyaWFsSW5kZXg7XG5cdFx0XHRcdFx0XHRcdGludGVyc2VjdHMucHVzaCggaW50ZXJzZWN0aW9uICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggMCwgZHJhd1JhbmdlLnN0YXJ0ICk7XG5cdFx0XHRcdGNvbnN0IGVuZCA9IE1hdGgubWluKCBpbmRleC5jb3VudCwgKCBkcmF3UmFuZ2Uuc3RhcnQgKyBkcmF3UmFuZ2UuY291bnQgKSApO1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gc3RhcnQsIGlsID0gZW5kOyBpIDwgaWw7IGkgKz0gMyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGEgPSBpbmRleC5nZXRYKCBpICk7XG5cdFx0XHRcdFx0Y29uc3QgYiA9IGluZGV4LmdldFgoIGkgKyAxICk7XG5cdFx0XHRcdFx0Y29uc3QgYyA9IGluZGV4LmdldFgoIGkgKyAyICk7XG5cblx0XHRcdFx0XHRpbnRlcnNlY3Rpb24gPSBjaGVja0dlb21ldHJ5SW50ZXJzZWN0aW9uKCB0aGlzLCBtYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXlMb2NhbFNwYWNlLCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKTtcblxuXHRcdFx0XHRcdGlmICggaW50ZXJzZWN0aW9uICkge1xuXG5cdFx0XHRcdFx0XHRpbnRlcnNlY3Rpb24uZmFjZUluZGV4ID0gTWF0aC5mbG9vciggaSAvIDMgKTsgLy8gdHJpYW5nbGUgbnVtYmVyIGluIGluZGV4ZWQgYnVmZmVyIHNlbWFudGljc1xuXHRcdFx0XHRcdFx0aW50ZXJzZWN0cy5wdXNoKCBpbnRlcnNlY3Rpb24gKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSBpZiAoIHBvc2l0aW9uICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdC8vIG5vbi1pbmRleGVkIGJ1ZmZlciBnZW9tZXRyeVxuXG5cdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsICkgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGdyb3Vwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBpIF07XG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXBNYXRlcmlhbCA9IG1hdGVyaWFsWyBncm91cC5tYXRlcmlhbEluZGV4IF07XG5cblx0XHRcdFx0XHRjb25zdCBzdGFydCA9IE1hdGgubWF4KCBncm91cC5zdGFydCwgZHJhd1JhbmdlLnN0YXJ0ICk7XG5cdFx0XHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIHBvc2l0aW9uLmNvdW50LCBNYXRoLm1pbiggKCBncm91cC5zdGFydCArIGdyb3VwLmNvdW50ICksICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKSApO1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGogPSBzdGFydCwgamwgPSBlbmQ7IGogPCBqbDsgaiArPSAzICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBhID0gajtcblx0XHRcdFx0XHRcdGNvbnN0IGIgPSBqICsgMTtcblx0XHRcdFx0XHRcdGNvbnN0IGMgPSBqICsgMjtcblxuXHRcdFx0XHRcdFx0aW50ZXJzZWN0aW9uID0gY2hlY2tHZW9tZXRyeUludGVyc2VjdGlvbiggdGhpcywgZ3JvdXBNYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXlMb2NhbFNwYWNlLCB1diwgdXYxLCBub3JtYWwsIGEsIGIsIGMgKTtcblxuXHRcdFx0XHRcdFx0aWYgKCBpbnRlcnNlY3Rpb24gKSB7XG5cblx0XHRcdFx0XHRcdFx0aW50ZXJzZWN0aW9uLmZhY2VJbmRleCA9IE1hdGguZmxvb3IoIGogLyAzICk7IC8vIHRyaWFuZ2xlIG51bWJlciBpbiBub24taW5kZXhlZCBidWZmZXIgc2VtYW50aWNzXG5cdFx0XHRcdFx0XHRcdGludGVyc2VjdGlvbi5mYWNlLm1hdGVyaWFsSW5kZXggPSBncm91cC5tYXRlcmlhbEluZGV4O1xuXHRcdFx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdGlvbiApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNvbnN0IHN0YXJ0ID0gTWF0aC5tYXgoIDAsIGRyYXdSYW5nZS5zdGFydCApO1xuXHRcdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggcG9zaXRpb24uY291bnQsICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IHN0YXJ0LCBpbCA9IGVuZDsgaSA8IGlsOyBpICs9IDMgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBhID0gaTtcblx0XHRcdFx0XHRjb25zdCBiID0gaSArIDE7XG5cdFx0XHRcdFx0Y29uc3QgYyA9IGkgKyAyO1xuXG5cdFx0XHRcdFx0aW50ZXJzZWN0aW9uID0gY2hlY2tHZW9tZXRyeUludGVyc2VjdGlvbiggdGhpcywgbWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5TG9jYWxTcGFjZSwgdXYsIHV2MSwgbm9ybWFsLCBhLCBiLCBjICk7XG5cblx0XHRcdFx0XHRpZiAoIGludGVyc2VjdGlvbiApIHtcblxuXHRcdFx0XHRcdFx0aW50ZXJzZWN0aW9uLmZhY2VJbmRleCA9IE1hdGguZmxvb3IoIGkgLyAzICk7IC8vIHRyaWFuZ2xlIG51bWJlciBpbiBub24taW5kZXhlZCBidWZmZXIgc2VtYW50aWNzXG5cdFx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdGlvbiApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBjaGVja0ludGVyc2VjdGlvbiQxKCBvYmplY3QsIG1hdGVyaWFsLCByYXljYXN0ZXIsIHJheSwgcEEsIHBCLCBwQywgcG9pbnQgKSB7XG5cblx0bGV0IGludGVyc2VjdDtcblxuXHRpZiAoIG1hdGVyaWFsLnNpZGUgPT09IEJhY2tTaWRlICkge1xuXG5cdFx0aW50ZXJzZWN0ID0gcmF5LmludGVyc2VjdFRyaWFuZ2xlKCBwQywgcEIsIHBBLCB0cnVlLCBwb2ludCApO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRpbnRlcnNlY3QgPSByYXkuaW50ZXJzZWN0VHJpYW5nbGUoIHBBLCBwQiwgcEMsICggbWF0ZXJpYWwuc2lkZSA9PT0gRnJvbnRTaWRlICksIHBvaW50ICk7XG5cblx0fVxuXG5cdGlmICggaW50ZXJzZWN0ID09PSBudWxsICkgcmV0dXJuIG51bGw7XG5cblx0X2ludGVyc2VjdGlvblBvaW50V29ybGQuY29weSggcG9pbnQgKTtcblx0X2ludGVyc2VjdGlvblBvaW50V29ybGQuYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKTtcblxuXHRjb25zdCBkaXN0YW5jZSA9IHJheWNhc3Rlci5yYXkub3JpZ2luLmRpc3RhbmNlVG8oIF9pbnRlcnNlY3Rpb25Qb2ludFdvcmxkICk7XG5cblx0aWYgKCBkaXN0YW5jZSA8IHJheWNhc3Rlci5uZWFyIHx8IGRpc3RhbmNlID4gcmF5Y2FzdGVyLmZhciApIHJldHVybiBudWxsO1xuXG5cdHJldHVybiB7XG5cdFx0ZGlzdGFuY2U6IGRpc3RhbmNlLFxuXHRcdHBvaW50OiBfaW50ZXJzZWN0aW9uUG9pbnRXb3JsZC5jbG9uZSgpLFxuXHRcdG9iamVjdDogb2JqZWN0XG5cdH07XG5cbn1cblxuZnVuY3Rpb24gY2hlY2tHZW9tZXRyeUludGVyc2VjdGlvbiggb2JqZWN0LCBtYXRlcmlhbCwgcmF5Y2FzdGVyLCByYXksIHV2LCB1djEsIG5vcm1hbCwgYSwgYiwgYyApIHtcblxuXHRvYmplY3QuZ2V0VmVydGV4UG9zaXRpb24oIGEsIF92QSQxICk7XG5cdG9iamVjdC5nZXRWZXJ0ZXhQb3NpdGlvbiggYiwgX3ZCJDEgKTtcblx0b2JqZWN0LmdldFZlcnRleFBvc2l0aW9uKCBjLCBfdkMkMSApO1xuXG5cdGNvbnN0IGludGVyc2VjdGlvbiA9IGNoZWNrSW50ZXJzZWN0aW9uJDEoIG9iamVjdCwgbWF0ZXJpYWwsIHJheWNhc3RlciwgcmF5LCBfdkEkMSwgX3ZCJDEsIF92QyQxLCBfaW50ZXJzZWN0aW9uUG9pbnQgKTtcblxuXHRpZiAoIGludGVyc2VjdGlvbiApIHtcblxuXHRcdGlmICggdXYgKSB7XG5cblx0XHRcdF91dkEkMS5mcm9tQnVmZmVyQXR0cmlidXRlKCB1diwgYSApO1xuXHRcdFx0X3V2QiQxLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHV2LCBiICk7XG5cdFx0XHRfdXZDJDEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdXYsIGMgKTtcblxuXHRcdFx0aW50ZXJzZWN0aW9uLnV2ID0gVHJpYW5nbGUuZ2V0SW50ZXJwb2xhdGlvbiggX2ludGVyc2VjdGlvblBvaW50LCBfdkEkMSwgX3ZCJDEsIF92QyQxLCBfdXZBJDEsIF91dkIkMSwgX3V2QyQxLCBuZXcgVmVjdG9yMigpICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHV2MSApIHtcblxuXHRcdFx0X3V2QSQxLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHV2MSwgYSApO1xuXHRcdFx0X3V2QiQxLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHV2MSwgYiApO1xuXHRcdFx0X3V2QyQxLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHV2MSwgYyApO1xuXG5cdFx0XHRpbnRlcnNlY3Rpb24udXYxID0gVHJpYW5nbGUuZ2V0SW50ZXJwb2xhdGlvbiggX2ludGVyc2VjdGlvblBvaW50LCBfdkEkMSwgX3ZCJDEsIF92QyQxLCBfdXZBJDEsIF91dkIkMSwgX3V2QyQxLCBuZXcgVmVjdG9yMigpICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG5vcm1hbCApIHtcblxuXHRcdFx0X25vcm1hbEEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFsLCBhICk7XG5cdFx0XHRfbm9ybWFsQi5mcm9tQnVmZmVyQXR0cmlidXRlKCBub3JtYWwsIGIgKTtcblx0XHRcdF9ub3JtYWxDLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbCwgYyApO1xuXG5cdFx0XHRpbnRlcnNlY3Rpb24ubm9ybWFsID0gVHJpYW5nbGUuZ2V0SW50ZXJwb2xhdGlvbiggX2ludGVyc2VjdGlvblBvaW50LCBfdkEkMSwgX3ZCJDEsIF92QyQxLCBfbm9ybWFsQSwgX25vcm1hbEIsIF9ub3JtYWxDLCBuZXcgVmVjdG9yMygpICk7XG5cblx0XHRcdGlmICggaW50ZXJzZWN0aW9uLm5vcm1hbC5kb3QoIHJheS5kaXJlY3Rpb24gKSA+IDAgKSB7XG5cblx0XHRcdFx0aW50ZXJzZWN0aW9uLm5vcm1hbC5tdWx0aXBseVNjYWxhciggLSAxICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IGZhY2UgPSB7XG5cdFx0XHRhOiBhLFxuXHRcdFx0YjogYixcblx0XHRcdGM6IGMsXG5cdFx0XHRub3JtYWw6IG5ldyBWZWN0b3IzKCksXG5cdFx0XHRtYXRlcmlhbEluZGV4OiAwXG5cdFx0fTtcblxuXHRcdFRyaWFuZ2xlLmdldE5vcm1hbCggX3ZBJDEsIF92QiQxLCBfdkMkMSwgZmFjZS5ub3JtYWwgKTtcblxuXHRcdGludGVyc2VjdGlvbi5mYWNlID0gZmFjZTtcblxuXHR9XG5cblx0cmV0dXJuIGludGVyc2VjdGlvbjtcblxufVxuXG5jbGFzcyBCb3hHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBkZXB0aCA9IDEsIHdpZHRoU2VnbWVudHMgPSAxLCBoZWlnaHRTZWdtZW50cyA9IDEsIGRlcHRoU2VnbWVudHMgPSAxICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdCb3hHZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHR3aWR0aDogd2lkdGgsXG5cdFx0XHRoZWlnaHQ6IGhlaWdodCxcblx0XHRcdGRlcHRoOiBkZXB0aCxcblx0XHRcdHdpZHRoU2VnbWVudHM6IHdpZHRoU2VnbWVudHMsXG5cdFx0XHRoZWlnaHRTZWdtZW50czogaGVpZ2h0U2VnbWVudHMsXG5cdFx0XHRkZXB0aFNlZ21lbnRzOiBkZXB0aFNlZ21lbnRzXG5cdFx0fTtcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdC8vIHNlZ21lbnRzXG5cblx0XHR3aWR0aFNlZ21lbnRzID0gTWF0aC5mbG9vciggd2lkdGhTZWdtZW50cyApO1xuXHRcdGhlaWdodFNlZ21lbnRzID0gTWF0aC5mbG9vciggaGVpZ2h0U2VnbWVudHMgKTtcblx0XHRkZXB0aFNlZ21lbnRzID0gTWF0aC5mbG9vciggZGVwdGhTZWdtZW50cyApO1xuXG5cdFx0Ly8gYnVmZmVyc1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xuXHRcdGNvbnN0IHV2cyA9IFtdO1xuXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xuXG5cdFx0bGV0IG51bWJlck9mVmVydGljZXMgPSAwO1xuXHRcdGxldCBncm91cFN0YXJ0ID0gMDtcblxuXHRcdC8vIGJ1aWxkIGVhY2ggc2lkZSBvZiB0aGUgYm94IGdlb21ldHJ5XG5cblx0XHRidWlsZFBsYW5lKCAneicsICd5JywgJ3gnLCAtIDEsIC0gMSwgZGVwdGgsIGhlaWdodCwgd2lkdGgsIGRlcHRoU2VnbWVudHMsIGhlaWdodFNlZ21lbnRzLCAwICk7IC8vIHB4XG5cdFx0YnVpbGRQbGFuZSggJ3onLCAneScsICd4JywgMSwgLSAxLCBkZXB0aCwgaGVpZ2h0LCAtIHdpZHRoLCBkZXB0aFNlZ21lbnRzLCBoZWlnaHRTZWdtZW50cywgMSApOyAvLyBueFxuXHRcdGJ1aWxkUGxhbmUoICd4JywgJ3onLCAneScsIDEsIDEsIHdpZHRoLCBkZXB0aCwgaGVpZ2h0LCB3aWR0aFNlZ21lbnRzLCBkZXB0aFNlZ21lbnRzLCAyICk7IC8vIHB5XG5cdFx0YnVpbGRQbGFuZSggJ3gnLCAneicsICd5JywgMSwgLSAxLCB3aWR0aCwgZGVwdGgsIC0gaGVpZ2h0LCB3aWR0aFNlZ21lbnRzLCBkZXB0aFNlZ21lbnRzLCAzICk7IC8vIG55XG5cdFx0YnVpbGRQbGFuZSggJ3gnLCAneScsICd6JywgMSwgLSAxLCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCwgd2lkdGhTZWdtZW50cywgaGVpZ2h0U2VnbWVudHMsIDQgKTsgLy8gcHpcblx0XHRidWlsZFBsYW5lKCAneCcsICd5JywgJ3onLCAtIDEsIC0gMSwgd2lkdGgsIGhlaWdodCwgLSBkZXB0aCwgd2lkdGhTZWdtZW50cywgaGVpZ2h0U2VnbWVudHMsIDUgKTsgLy8gbnpcblxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XG5cblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xuXG5cdFx0ZnVuY3Rpb24gYnVpbGRQbGFuZSggdSwgdiwgdywgdWRpciwgdmRpciwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIGdyaWRYLCBncmlkWSwgbWF0ZXJpYWxJbmRleCApIHtcblxuXHRcdFx0Y29uc3Qgc2VnbWVudFdpZHRoID0gd2lkdGggLyBncmlkWDtcblx0XHRcdGNvbnN0IHNlZ21lbnRIZWlnaHQgPSBoZWlnaHQgLyBncmlkWTtcblxuXHRcdFx0Y29uc3Qgd2lkdGhIYWxmID0gd2lkdGggLyAyO1xuXHRcdFx0Y29uc3QgaGVpZ2h0SGFsZiA9IGhlaWdodCAvIDI7XG5cdFx0XHRjb25zdCBkZXB0aEhhbGYgPSBkZXB0aCAvIDI7XG5cblx0XHRcdGNvbnN0IGdyaWRYMSA9IGdyaWRYICsgMTtcblx0XHRcdGNvbnN0IGdyaWRZMSA9IGdyaWRZICsgMTtcblxuXHRcdFx0bGV0IHZlcnRleENvdW50ZXIgPSAwO1xuXHRcdFx0bGV0IGdyb3VwQ291bnQgPSAwO1xuXG5cdFx0XHRjb25zdCB2ZWN0b3IgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHQvLyBnZW5lcmF0ZSB2ZXJ0aWNlcywgbm9ybWFscyBhbmQgdXZzXG5cblx0XHRcdGZvciAoIGxldCBpeSA9IDA7IGl5IDwgZ3JpZFkxOyBpeSArKyApIHtcblxuXHRcdFx0XHRjb25zdCB5ID0gaXkgKiBzZWdtZW50SGVpZ2h0IC0gaGVpZ2h0SGFsZjtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaXggPSAwOyBpeCA8IGdyaWRYMTsgaXggKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB4ID0gaXggKiBzZWdtZW50V2lkdGggLSB3aWR0aEhhbGY7XG5cblx0XHRcdFx0XHQvLyBzZXQgdmFsdWVzIHRvIGNvcnJlY3QgdmVjdG9yIGNvbXBvbmVudFxuXG5cdFx0XHRcdFx0dmVjdG9yWyB1IF0gPSB4ICogdWRpcjtcblx0XHRcdFx0XHR2ZWN0b3JbIHYgXSA9IHkgKiB2ZGlyO1xuXHRcdFx0XHRcdHZlY3RvclsgdyBdID0gZGVwdGhIYWxmO1xuXG5cdFx0XHRcdFx0Ly8gbm93IGFwcGx5IHZlY3RvciB0byB2ZXJ0ZXggYnVmZmVyXG5cblx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZWN0b3IueCwgdmVjdG9yLnksIHZlY3Rvci56ICk7XG5cblx0XHRcdFx0XHQvLyBzZXQgdmFsdWVzIHRvIGNvcnJlY3QgdmVjdG9yIGNvbXBvbmVudFxuXG5cdFx0XHRcdFx0dmVjdG9yWyB1IF0gPSAwO1xuXHRcdFx0XHRcdHZlY3RvclsgdiBdID0gMDtcblx0XHRcdFx0XHR2ZWN0b3JbIHcgXSA9IGRlcHRoID4gMCA/IDEgOiAtIDE7XG5cblx0XHRcdFx0XHQvLyBub3cgYXBwbHkgdmVjdG9yIHRvIG5vcm1hbCBidWZmZXJcblxuXHRcdFx0XHRcdG5vcm1hbHMucHVzaCggdmVjdG9yLngsIHZlY3Rvci55LCB2ZWN0b3IueiApO1xuXG5cdFx0XHRcdFx0Ly8gdXZzXG5cblx0XHRcdFx0XHR1dnMucHVzaCggaXggLyBncmlkWCApO1xuXHRcdFx0XHRcdHV2cy5wdXNoKCAxIC0gKCBpeSAvIGdyaWRZICkgKTtcblxuXHRcdFx0XHRcdC8vIGNvdW50ZXJzXG5cblx0XHRcdFx0XHR2ZXJ0ZXhDb3VudGVyICs9IDE7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGluZGljZXNcblxuXHRcdFx0Ly8gMS4geW91IG5lZWQgdGhyZWUgaW5kaWNlcyB0byBkcmF3IGEgc2luZ2xlIGZhY2Vcblx0XHRcdC8vIDIuIGEgc2luZ2xlIHNlZ21lbnQgY29uc2lzdHMgb2YgdHdvIGZhY2VzXG5cdFx0XHQvLyAzLiBzbyB3ZSBuZWVkIHRvIGdlbmVyYXRlIHNpeCAoMiozKSBpbmRpY2VzIHBlciBzZWdtZW50XG5cblx0XHRcdGZvciAoIGxldCBpeSA9IDA7IGl5IDwgZ3JpZFk7IGl5ICsrICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpeCA9IDA7IGl4IDwgZ3JpZFg7IGl4ICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgYSA9IG51bWJlck9mVmVydGljZXMgKyBpeCArIGdyaWRYMSAqIGl5O1xuXHRcdFx0XHRcdGNvbnN0IGIgPSBudW1iZXJPZlZlcnRpY2VzICsgaXggKyBncmlkWDEgKiAoIGl5ICsgMSApO1xuXHRcdFx0XHRcdGNvbnN0IGMgPSBudW1iZXJPZlZlcnRpY2VzICsgKCBpeCArIDEgKSArIGdyaWRYMSAqICggaXkgKyAxICk7XG5cdFx0XHRcdFx0Y29uc3QgZCA9IG51bWJlck9mVmVydGljZXMgKyAoIGl4ICsgMSApICsgZ3JpZFgxICogaXk7XG5cblx0XHRcdFx0XHQvLyBmYWNlc1xuXG5cdFx0XHRcdFx0aW5kaWNlcy5wdXNoKCBhLCBiLCBkICk7XG5cdFx0XHRcdFx0aW5kaWNlcy5wdXNoKCBiLCBjLCBkICk7XG5cblx0XHRcdFx0XHQvLyBpbmNyZWFzZSBjb3VudGVyXG5cblx0XHRcdFx0XHRncm91cENvdW50ICs9IDY7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGFkZCBhIGdyb3VwIHRvIHRoZSBnZW9tZXRyeS4gdGhpcyB3aWxsIGVuc3VyZSBtdWx0aSBtYXRlcmlhbCBzdXBwb3J0XG5cblx0XHRcdHNjb3BlLmFkZEdyb3VwKCBncm91cFN0YXJ0LCBncm91cENvdW50LCBtYXRlcmlhbEluZGV4ICk7XG5cblx0XHRcdC8vIGNhbGN1bGF0ZSBuZXcgc3RhcnQgdmFsdWUgZm9yIGdyb3Vwc1xuXG5cdFx0XHRncm91cFN0YXJ0ICs9IGdyb3VwQ291bnQ7XG5cblx0XHRcdC8vIHVwZGF0ZSB0b3RhbCBudW1iZXIgb2YgdmVydGljZXNcblxuXHRcdFx0bnVtYmVyT2ZWZXJ0aWNlcyArPSB2ZXJ0ZXhDb3VudGVyO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdHJldHVybiBuZXcgQm94R2VvbWV0cnkoIGRhdGEud2lkdGgsIGRhdGEuaGVpZ2h0LCBkYXRhLmRlcHRoLCBkYXRhLndpZHRoU2VnbWVudHMsIGRhdGEuaGVpZ2h0U2VnbWVudHMsIGRhdGEuZGVwdGhTZWdtZW50cyApO1xuXG5cdH1cblxufVxuXG4vKipcbiAqIFVuaWZvcm0gVXRpbGl0aWVzXG4gKi9cblxuZnVuY3Rpb24gY2xvbmVVbmlmb3Jtcyggc3JjICkge1xuXG5cdGNvbnN0IGRzdCA9IHt9O1xuXG5cdGZvciAoIGNvbnN0IHUgaW4gc3JjICkge1xuXG5cdFx0ZHN0WyB1IF0gPSB7fTtcblxuXHRcdGZvciAoIGNvbnN0IHAgaW4gc3JjWyB1IF0gKSB7XG5cblx0XHRcdGNvbnN0IHByb3BlcnR5ID0gc3JjWyB1IF1bIHAgXTtcblxuXHRcdFx0aWYgKCBwcm9wZXJ0eSAmJiAoIHByb3BlcnR5LmlzQ29sb3IgfHxcblx0XHRcdFx0cHJvcGVydHkuaXNNYXRyaXgzIHx8IHByb3BlcnR5LmlzTWF0cml4NCB8fFxuXHRcdFx0XHRwcm9wZXJ0eS5pc1ZlY3RvcjIgfHwgcHJvcGVydHkuaXNWZWN0b3IzIHx8IHByb3BlcnR5LmlzVmVjdG9yNCB8fFxuXHRcdFx0XHRwcm9wZXJ0eS5pc1RleHR1cmUgfHwgcHJvcGVydHkuaXNRdWF0ZXJuaW9uICkgKSB7XG5cblx0XHRcdFx0aWYgKCBwcm9wZXJ0eS5pc1JlbmRlclRhcmdldFRleHR1cmUgKSB7XG5cblx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdVbmlmb3Jtc1V0aWxzOiBUZXh0dXJlcyBvZiByZW5kZXIgdGFyZ2V0cyBjYW5ub3QgYmUgY2xvbmVkIHZpYSBjbG9uZVVuaWZvcm1zKCkgb3IgbWVyZ2VVbmlmb3JtcygpLicgKTtcblx0XHRcdFx0XHRkc3RbIHUgXVsgcCBdID0gbnVsbDtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0ZHN0WyB1IF1bIHAgXSA9IHByb3BlcnR5LmNsb25lKCk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2UgaWYgKCBBcnJheS5pc0FycmF5KCBwcm9wZXJ0eSApICkge1xuXG5cdFx0XHRcdGRzdFsgdSBdWyBwIF0gPSBwcm9wZXJ0eS5zbGljZSgpO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGRzdFsgdSBdWyBwIF0gPSBwcm9wZXJ0eTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4gZHN0O1xuXG59XG5cbmZ1bmN0aW9uIG1lcmdlVW5pZm9ybXMoIHVuaWZvcm1zICkge1xuXG5cdGNvbnN0IG1lcmdlZCA9IHt9O1xuXG5cdGZvciAoIGxldCB1ID0gMDsgdSA8IHVuaWZvcm1zLmxlbmd0aDsgdSArKyApIHtcblxuXHRcdGNvbnN0IHRtcCA9IGNsb25lVW5pZm9ybXMoIHVuaWZvcm1zWyB1IF0gKTtcblxuXHRcdGZvciAoIGNvbnN0IHAgaW4gdG1wICkge1xuXG5cdFx0XHRtZXJnZWRbIHAgXSA9IHRtcFsgcCBdO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4gbWVyZ2VkO1xuXG59XG5cbmZ1bmN0aW9uIGNsb25lVW5pZm9ybXNHcm91cHMoIHNyYyApIHtcblxuXHRjb25zdCBkc3QgPSBbXTtcblxuXHRmb3IgKCBsZXQgdSA9IDA7IHUgPCBzcmMubGVuZ3RoOyB1ICsrICkge1xuXG5cdFx0ZHN0LnB1c2goIHNyY1sgdSBdLmNsb25lKCkgKTtcblxuXHR9XG5cblx0cmV0dXJuIGRzdDtcblxufVxuXG5mdW5jdGlvbiBnZXRVbmxpdFVuaWZvcm1Db2xvclNwYWNlKCByZW5kZXJlciApIHtcblxuXHRjb25zdCBjdXJyZW50UmVuZGVyVGFyZ2V0ID0gcmVuZGVyZXIuZ2V0UmVuZGVyVGFyZ2V0KCk7XG5cblx0aWYgKCBjdXJyZW50UmVuZGVyVGFyZ2V0ID09PSBudWxsICkge1xuXG5cdFx0Ly8gaHR0cHM6Ly9naXRodWIuY29tL21yZG9vYi90aHJlZS5qcy9wdWxsLzIzOTM3I2lzc3VlY29tbWVudC0xMTExMDY3Mzk4XG5cdFx0cmV0dXJuIHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2U7XG5cblx0fVxuXG5cdC8vIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvaXNzdWVzLzI3ODY4XG5cdGlmICggY3VycmVudFJlbmRlclRhcmdldC5pc1hSUmVuZGVyVGFyZ2V0ID09PSB0cnVlICkge1xuXG5cdFx0cmV0dXJuIGN1cnJlbnRSZW5kZXJUYXJnZXQudGV4dHVyZS5jb2xvclNwYWNlO1xuXG5cdH1cblxuXHRyZXR1cm4gQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlO1xuXG59XG5cbi8vIExlZ2FjeVxuXG5jb25zdCBVbmlmb3Jtc1V0aWxzID0geyBjbG9uZTogY2xvbmVVbmlmb3JtcywgbWVyZ2U6IG1lcmdlVW5pZm9ybXMgfTtcblxudmFyIGRlZmF1bHRfdmVydGV4ID0gXCJ2b2lkIG1haW4oKSB7XFxuXFx0Z2xfUG9zaXRpb24gPSBwcm9qZWN0aW9uTWF0cml4ICogbW9kZWxWaWV3TWF0cml4ICogdmVjNCggcG9zaXRpb24sIDEuMCApO1xcbn1cIjtcblxudmFyIGRlZmF1bHRfZnJhZ21lbnQgPSBcInZvaWQgbWFpbigpIHtcXG5cXHRnbF9GcmFnQ29sb3IgPSB2ZWM0KCAxLjAsIDAuMCwgMC4wLCAxLjAgKTtcXG59XCI7XG5cbmNsYXNzIFNoYWRlck1hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNTaGFkZXJNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnU2hhZGVyTWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5kZWZpbmVzID0ge307XG5cdFx0dGhpcy51bmlmb3JtcyA9IHt9O1xuXHRcdHRoaXMudW5pZm9ybXNHcm91cHMgPSBbXTtcblxuXHRcdHRoaXMudmVydGV4U2hhZGVyID0gZGVmYXVsdF92ZXJ0ZXg7XG5cdFx0dGhpcy5mcmFnbWVudFNoYWRlciA9IGRlZmF1bHRfZnJhZ21lbnQ7XG5cblx0XHR0aGlzLmxpbmV3aWR0aCA9IDE7XG5cblx0XHR0aGlzLndpcmVmcmFtZSA9IGZhbHNlO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gMTtcblxuXHRcdHRoaXMuZm9nID0gZmFsc2U7IC8vIHNldCB0byB1c2Ugc2NlbmUgZm9nXG5cdFx0dGhpcy5saWdodHMgPSBmYWxzZTsgLy8gc2V0IHRvIHVzZSBzY2VuZSBsaWdodHNcblx0XHR0aGlzLmNsaXBwaW5nID0gZmFsc2U7IC8vIHNldCB0byB1c2UgdXNlci1kZWZpbmVkIGNsaXBwaW5nIHBsYW5lc1xuXG5cdFx0dGhpcy5mb3JjZVNpbmdsZVBhc3MgPSB0cnVlO1xuXG5cdFx0dGhpcy5leHRlbnNpb25zID0ge1xuXHRcdFx0Y2xpcEN1bGxEaXN0YW5jZTogZmFsc2UsIC8vIHNldCB0byB1c2UgdmVydGV4IHNoYWRlciBjbGlwcGluZ1xuXHRcdFx0bXVsdGlEcmF3OiBmYWxzZSAvLyBzZXQgdG8gdXNlIHZlcnRleCBzaGFkZXIgbXVsdGlfZHJhdyAvIGVuYWJsZSBnbF9EcmF3SURcblx0XHR9O1xuXG5cdFx0Ly8gV2hlbiByZW5kZXJlZCBnZW9tZXRyeSBkb2Vzbid0IGluY2x1ZGUgdGhlc2UgYXR0cmlidXRlcyBidXQgdGhlIG1hdGVyaWFsIGRvZXMsXG5cdFx0Ly8gdXNlIHRoZXNlIGRlZmF1bHQgdmFsdWVzIGluIFdlYkdMLiBUaGlzIGF2b2lkcyBlcnJvcnMgd2hlbiBidWZmZXIgZGF0YSBpcyBtaXNzaW5nLlxuXHRcdHRoaXMuZGVmYXVsdEF0dHJpYnV0ZVZhbHVlcyA9IHtcblx0XHRcdCdjb2xvcic6IFsgMSwgMSwgMSBdLFxuXHRcdFx0J3V2JzogWyAwLCAwIF0sXG5cdFx0XHQndXYxJzogWyAwLCAwIF1cblx0XHR9O1xuXG5cdFx0dGhpcy5pbmRleDBBdHRyaWJ1dGVOYW1lID0gdW5kZWZpbmVkO1xuXHRcdHRoaXMudW5pZm9ybXNOZWVkVXBkYXRlID0gZmFsc2U7XG5cblx0XHR0aGlzLmdsc2xWZXJzaW9uID0gbnVsbDtcblxuXHRcdGlmICggcGFyYW1ldGVycyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuZnJhZ21lbnRTaGFkZXIgPSBzb3VyY2UuZnJhZ21lbnRTaGFkZXI7XG5cdFx0dGhpcy52ZXJ0ZXhTaGFkZXIgPSBzb3VyY2UudmVydGV4U2hhZGVyO1xuXG5cdFx0dGhpcy51bmlmb3JtcyA9IGNsb25lVW5pZm9ybXMoIHNvdXJjZS51bmlmb3JtcyApO1xuXHRcdHRoaXMudW5pZm9ybXNHcm91cHMgPSBjbG9uZVVuaWZvcm1zR3JvdXBzKCBzb3VyY2UudW5pZm9ybXNHcm91cHMgKTtcblxuXHRcdHRoaXMuZGVmaW5lcyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UuZGVmaW5lcyApO1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBzb3VyY2Uud2lyZWZyYW1lO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZXdpZHRoID0gc291cmNlLndpcmVmcmFtZUxpbmV3aWR0aDtcblxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcblx0XHR0aGlzLmxpZ2h0cyA9IHNvdXJjZS5saWdodHM7XG5cdFx0dGhpcy5jbGlwcGluZyA9IHNvdXJjZS5jbGlwcGluZztcblxuXHRcdHRoaXMuZXh0ZW5zaW9ucyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UuZXh0ZW5zaW9ucyApO1xuXG5cdFx0dGhpcy5nbHNsVmVyc2lvbiA9IHNvdXJjZS5nbHNsVmVyc2lvbjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oIG1ldGEgKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCBtZXRhICk7XG5cblx0XHRkYXRhLmdsc2xWZXJzaW9uID0gdGhpcy5nbHNsVmVyc2lvbjtcblx0XHRkYXRhLnVuaWZvcm1zID0ge307XG5cblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIHRoaXMudW5pZm9ybXMgKSB7XG5cblx0XHRcdGNvbnN0IHVuaWZvcm0gPSB0aGlzLnVuaWZvcm1zWyBuYW1lIF07XG5cdFx0XHRjb25zdCB2YWx1ZSA9IHVuaWZvcm0udmFsdWU7XG5cblx0XHRcdGlmICggdmFsdWUgJiYgdmFsdWUuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRcdGRhdGEudW5pZm9ybXNbIG5hbWUgXSA9IHtcblx0XHRcdFx0XHR0eXBlOiAndCcsXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvSlNPTiggbWV0YSApLnV1aWRcblx0XHRcdFx0fTtcblxuXHRcdFx0fSBlbHNlIGlmICggdmFsdWUgJiYgdmFsdWUuaXNDb2xvciApIHtcblxuXHRcdFx0XHRkYXRhLnVuaWZvcm1zWyBuYW1lIF0gPSB7XG5cdFx0XHRcdFx0dHlwZTogJ2MnLFxuXHRcdFx0XHRcdHZhbHVlOiB2YWx1ZS5nZXRIZXgoKVxuXHRcdFx0XHR9O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZSAmJiB2YWx1ZS5pc1ZlY3RvcjIgKSB7XG5cblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xuXHRcdFx0XHRcdHR5cGU6ICd2MicsXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvQXJyYXkoKVxuXHRcdFx0XHR9O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZSAmJiB2YWx1ZS5pc1ZlY3RvcjMgKSB7XG5cblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xuXHRcdFx0XHRcdHR5cGU6ICd2MycsXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvQXJyYXkoKVxuXHRcdFx0XHR9O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZSAmJiB2YWx1ZS5pc1ZlY3RvcjQgKSB7XG5cblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xuXHRcdFx0XHRcdHR5cGU6ICd2NCcsXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvQXJyYXkoKVxuXHRcdFx0XHR9O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZSAmJiB2YWx1ZS5pc01hdHJpeDMgKSB7XG5cblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xuXHRcdFx0XHRcdHR5cGU6ICdtMycsXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvQXJyYXkoKVxuXHRcdFx0XHR9O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZSAmJiB2YWx1ZS5pc01hdHJpeDQgKSB7XG5cblx0XHRcdFx0ZGF0YS51bmlmb3Jtc1sgbmFtZSBdID0ge1xuXHRcdFx0XHRcdHR5cGU6ICdtNCcsXG5cdFx0XHRcdFx0dmFsdWU6IHZhbHVlLnRvQXJyYXkoKVxuXHRcdFx0XHR9O1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGRhdGEudW5pZm9ybXNbIG5hbWUgXSA9IHtcblx0XHRcdFx0XHR2YWx1ZTogdmFsdWVcblx0XHRcdFx0fTtcblxuXHRcdFx0XHQvLyBub3RlOiB0aGUgYXJyYXkgdmFyaWFudHMgdjJ2LCB2M3YsIHY0diwgbTR2IGFuZCB0diBhcmUgbm90IHN1cHBvcnRlZCBzbyBmYXJcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBPYmplY3Qua2V5cyggdGhpcy5kZWZpbmVzICkubGVuZ3RoID4gMCApIGRhdGEuZGVmaW5lcyA9IHRoaXMuZGVmaW5lcztcblxuXHRcdGRhdGEudmVydGV4U2hhZGVyID0gdGhpcy52ZXJ0ZXhTaGFkZXI7XG5cdFx0ZGF0YS5mcmFnbWVudFNoYWRlciA9IHRoaXMuZnJhZ21lbnRTaGFkZXI7XG5cblx0XHRkYXRhLmxpZ2h0cyA9IHRoaXMubGlnaHRzO1xuXHRcdGRhdGEuY2xpcHBpbmcgPSB0aGlzLmNsaXBwaW5nO1xuXG5cdFx0Y29uc3QgZXh0ZW5zaW9ucyA9IHt9O1xuXG5cdFx0Zm9yICggY29uc3Qga2V5IGluIHRoaXMuZXh0ZW5zaW9ucyApIHtcblxuXHRcdFx0aWYgKCB0aGlzLmV4dGVuc2lvbnNbIGtleSBdID09PSB0cnVlICkgZXh0ZW5zaW9uc1sga2V5IF0gPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBPYmplY3Qua2V5cyggZXh0ZW5zaW9ucyApLmxlbmd0aCA+IDAgKSBkYXRhLmV4dGVuc2lvbnMgPSBleHRlbnNpb25zO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbmNsYXNzIENhbWVyYSBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzQ2FtZXJhID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdDYW1lcmEnO1xuXG5cdFx0dGhpcy5tYXRyaXhXb3JsZEludmVyc2UgPSBuZXcgTWF0cml4NCgpO1xuXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4ID0gbmV3IE1hdHJpeDQoKTtcblx0XHR0aGlzLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlID0gbmV3IE1hdHJpeDQoKTtcblxuXHRcdHRoaXMuY29vcmRpbmF0ZVN5c3RlbSA9IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbTtcblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0dGhpcy5tYXRyaXhXb3JsZEludmVyc2UuY29weSggc291cmNlLm1hdHJpeFdvcmxkSW52ZXJzZSApO1xuXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4LmNvcHkoIHNvdXJjZS5wcm9qZWN0aW9uTWF0cml4ICk7XG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZS5jb3B5KCBzb3VyY2UucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKTtcblxuXHRcdHRoaXMuY29vcmRpbmF0ZVN5c3RlbSA9IHNvdXJjZS5jb29yZGluYXRlU3lzdGVtO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldFdvcmxkRGlyZWN0aW9uKCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gc3VwZXIuZ2V0V29ybGREaXJlY3Rpb24oIHRhcmdldCApLm5lZ2F0ZSgpO1xuXG5cdH1cblxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XG5cblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcblxuXHRcdHRoaXMubWF0cml4V29ybGRJbnZlcnNlLmNvcHkoIHRoaXMubWF0cml4V29ybGQgKS5pbnZlcnQoKTtcblxuXHR9XG5cblx0dXBkYXRlV29ybGRNYXRyaXgoIHVwZGF0ZVBhcmVudHMsIHVwZGF0ZUNoaWxkcmVuICkge1xuXG5cdFx0c3VwZXIudXBkYXRlV29ybGRNYXRyaXgoIHVwZGF0ZVBhcmVudHMsIHVwZGF0ZUNoaWxkcmVuICk7XG5cblx0XHR0aGlzLm1hdHJpeFdvcmxkSW52ZXJzZS5jb3B5KCB0aGlzLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxufVxuXG5jb25zdCBfdjMkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9taW5UYXJnZXQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XG5jb25zdCBfbWF4VGFyZ2V0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xuXG5cbmNsYXNzIFBlcnNwZWN0aXZlQ2FtZXJhIGV4dGVuZHMgQ2FtZXJhIHtcblxuXHRjb25zdHJ1Y3RvciggZm92ID0gNTAsIGFzcGVjdCA9IDEsIG5lYXIgPSAwLjEsIGZhciA9IDIwMDAgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc1BlcnNwZWN0aXZlQ2FtZXJhID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdQZXJzcGVjdGl2ZUNhbWVyYSc7XG5cblx0XHR0aGlzLmZvdiA9IGZvdjtcblx0XHR0aGlzLnpvb20gPSAxO1xuXG5cdFx0dGhpcy5uZWFyID0gbmVhcjtcblx0XHR0aGlzLmZhciA9IGZhcjtcblx0XHR0aGlzLmZvY3VzID0gMTA7XG5cblx0XHR0aGlzLmFzcGVjdCA9IGFzcGVjdDtcblx0XHR0aGlzLnZpZXcgPSBudWxsO1xuXG5cdFx0dGhpcy5maWxtR2F1Z2UgPSAzNTtcdC8vIHdpZHRoIG9mIHRoZSBmaWxtIChkZWZhdWx0IGluIG1pbGxpbWV0ZXJzKVxuXHRcdHRoaXMuZmlsbU9mZnNldCA9IDA7XHQvLyBob3Jpem9udGFsIGZpbG0gb2Zmc2V0IChzYW1lIHVuaXQgYXMgZ2F1Z2UpXG5cblx0XHR0aGlzLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0dGhpcy5mb3YgPSBzb3VyY2UuZm92O1xuXHRcdHRoaXMuem9vbSA9IHNvdXJjZS56b29tO1xuXG5cdFx0dGhpcy5uZWFyID0gc291cmNlLm5lYXI7XG5cdFx0dGhpcy5mYXIgPSBzb3VyY2UuZmFyO1xuXHRcdHRoaXMuZm9jdXMgPSBzb3VyY2UuZm9jdXM7XG5cblx0XHR0aGlzLmFzcGVjdCA9IHNvdXJjZS5hc3BlY3Q7XG5cdFx0dGhpcy52aWV3ID0gc291cmNlLnZpZXcgPT09IG51bGwgPyBudWxsIDogT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS52aWV3ICk7XG5cblx0XHR0aGlzLmZpbG1HYXVnZSA9IHNvdXJjZS5maWxtR2F1Z2U7XG5cdFx0dGhpcy5maWxtT2Zmc2V0ID0gc291cmNlLmZpbG1PZmZzZXQ7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0LyoqXG5cdCAqIFNldHMgdGhlIEZPViBieSBmb2NhbCBsZW5ndGggaW4gcmVzcGVjdCB0byB0aGUgY3VycmVudCAuZmlsbUdhdWdlLlxuXHQgKlxuXHQgKiBUaGUgZGVmYXVsdCBmaWxtIGdhdWdlIGlzIDM1LCBzbyB0aGF0IHRoZSBmb2NhbCBsZW5ndGggY2FuIGJlIHNwZWNpZmllZCBmb3Jcblx0ICogYSAzNW1tIChmdWxsIGZyYW1lKSBjYW1lcmEuXG5cdCAqXG5cdCAqIFZhbHVlcyBmb3IgZm9jYWwgbGVuZ3RoIGFuZCBmaWxtIGdhdWdlIG11c3QgaGF2ZSB0aGUgc2FtZSB1bml0LlxuXHQgKi9cblx0c2V0Rm9jYWxMZW5ndGgoIGZvY2FsTGVuZ3RoICkge1xuXG5cdFx0LyoqIHNlZSB7QGxpbmsgaHR0cDovL3d3dy5ib2JhdGtpbnMuY29tL3Bob3RvZ3JhcGh5L3RlY2huaWNhbC9maWVsZF9vZl92aWV3Lmh0bWx9ICovXG5cdFx0Y29uc3QgdkV4dGVudFNsb3BlID0gMC41ICogdGhpcy5nZXRGaWxtSGVpZ2h0KCkgLyBmb2NhbExlbmd0aDtcblxuXHRcdHRoaXMuZm92ID0gUkFEMkRFRyAqIDIgKiBNYXRoLmF0YW4oIHZFeHRlbnRTbG9wZSApO1xuXHRcdHRoaXMudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXG5cdH1cblxuXHQvKipcblx0ICogQ2FsY3VsYXRlcyB0aGUgZm9jYWwgbGVuZ3RoIGZyb20gdGhlIGN1cnJlbnQgLmZvdiBhbmQgLmZpbG1HYXVnZS5cblx0ICovXG5cdGdldEZvY2FsTGVuZ3RoKCkge1xuXG5cdFx0Y29uc3QgdkV4dGVudFNsb3BlID0gTWF0aC50YW4oIERFRzJSQUQgKiAwLjUgKiB0aGlzLmZvdiApO1xuXG5cdFx0cmV0dXJuIDAuNSAqIHRoaXMuZ2V0RmlsbUhlaWdodCgpIC8gdkV4dGVudFNsb3BlO1xuXG5cdH1cblxuXHRnZXRFZmZlY3RpdmVGT1YoKSB7XG5cblx0XHRyZXR1cm4gUkFEMkRFRyAqIDIgKiBNYXRoLmF0YW4oXG5cdFx0XHRNYXRoLnRhbiggREVHMlJBRCAqIDAuNSAqIHRoaXMuZm92ICkgLyB0aGlzLnpvb20gKTtcblxuXHR9XG5cblx0Z2V0RmlsbVdpZHRoKCkge1xuXG5cdFx0Ly8gZmlsbSBub3QgY29tcGxldGVseSBjb3ZlcmVkIGluIHBvcnRyYWl0IGZvcm1hdCAoYXNwZWN0IDwgMSlcblx0XHRyZXR1cm4gdGhpcy5maWxtR2F1Z2UgKiBNYXRoLm1pbiggdGhpcy5hc3BlY3QsIDEgKTtcblxuXHR9XG5cblx0Z2V0RmlsbUhlaWdodCgpIHtcblxuXHRcdC8vIGZpbG0gbm90IGNvbXBsZXRlbHkgY292ZXJlZCBpbiBsYW5kc2NhcGUgZm9ybWF0IChhc3BlY3QgPiAxKVxuXHRcdHJldHVybiB0aGlzLmZpbG1HYXVnZSAvIE1hdGgubWF4KCB0aGlzLmFzcGVjdCwgMSApO1xuXG5cdH1cblxuXHQvKipcblx0ICogQ29tcHV0ZXMgdGhlIDJEIGJvdW5kcyBvZiB0aGUgY2FtZXJhJ3Mgdmlld2FibGUgcmVjdGFuZ2xlIGF0IGEgZ2l2ZW4gZGlzdGFuY2UgYWxvbmcgdGhlIHZpZXdpbmcgZGlyZWN0aW9uLlxuXHQgKiBTZXRzIG1pblRhcmdldCBhbmQgbWF4VGFyZ2V0IHRvIHRoZSBjb29yZGluYXRlcyBvZiB0aGUgbG93ZXItbGVmdCBhbmQgdXBwZXItcmlnaHQgY29ybmVycyBvZiB0aGUgdmlldyByZWN0YW5nbGUuXG5cdCAqL1xuXHRnZXRWaWV3Qm91bmRzKCBkaXN0YW5jZSwgbWluVGFyZ2V0LCBtYXhUYXJnZXQgKSB7XG5cblx0XHRfdjMkMS5zZXQoIC0gMSwgLSAxLCAwLjUgKS5hcHBseU1hdHJpeDQoIHRoaXMucHJvamVjdGlvbk1hdHJpeEludmVyc2UgKTtcblxuXHRcdG1pblRhcmdldC5zZXQoIF92MyQxLngsIF92MyQxLnkgKS5tdWx0aXBseVNjYWxhciggLSBkaXN0YW5jZSAvIF92MyQxLnogKTtcblxuXHRcdF92MyQxLnNldCggMSwgMSwgMC41ICkuYXBwbHlNYXRyaXg0KCB0aGlzLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlICk7XG5cblx0XHRtYXhUYXJnZXQuc2V0KCBfdjMkMS54LCBfdjMkMS55ICkubXVsdGlwbHlTY2FsYXIoIC0gZGlzdGFuY2UgLyBfdjMkMS56ICk7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBDb21wdXRlcyB0aGUgd2lkdGggYW5kIGhlaWdodCBvZiB0aGUgY2FtZXJhJ3Mgdmlld2FibGUgcmVjdGFuZ2xlIGF0IGEgZ2l2ZW4gZGlzdGFuY2UgYWxvbmcgdGhlIHZpZXdpbmcgZGlyZWN0aW9uLlxuXHQgKiBDb3BpZXMgdGhlIHJlc3VsdCBpbnRvIHRoZSB0YXJnZXQgVmVjdG9yMiwgd2hlcmUgeCBpcyB3aWR0aCBhbmQgeSBpcyBoZWlnaHQuXG5cdCAqL1xuXHRnZXRWaWV3U2l6ZSggZGlzdGFuY2UsIHRhcmdldCApIHtcblxuXHRcdHRoaXMuZ2V0Vmlld0JvdW5kcyggZGlzdGFuY2UsIF9taW5UYXJnZXQsIF9tYXhUYXJnZXQgKTtcblxuXHRcdHJldHVybiB0YXJnZXQuc3ViVmVjdG9ycyggX21heFRhcmdldCwgX21pblRhcmdldCApO1xuXG5cdH1cblxuXHQvKipcblx0ICogU2V0cyBhbiBvZmZzZXQgaW4gYSBsYXJnZXIgZnJ1c3R1bS4gVGhpcyBpcyB1c2VmdWwgZm9yIG11bHRpLXdpbmRvdyBvclxuXHQgKiBtdWx0aS1tb25pdG9yL211bHRpLW1hY2hpbmUgc2V0dXBzLlxuXHQgKlxuXHQgKiBGb3IgZXhhbXBsZSwgaWYgeW91IGhhdmUgM3gyIG1vbml0b3JzIGFuZCBlYWNoIG1vbml0b3IgaXMgMTkyMHgxMDgwIGFuZFxuXHQgKiB0aGUgbW9uaXRvcnMgYXJlIGluIGdyaWQgbGlrZSB0aGlzXG5cdCAqXG5cdCAqICAgKy0tLSstLS0rLS0tK1xuXHQgKiAgIHwgQSB8IEIgfCBDIHxcblx0ICogICArLS0tKy0tLSstLS0rXG5cdCAqICAgfCBEIHwgRSB8IEYgfFxuXHQgKiAgICstLS0rLS0tKy0tLStcblx0ICpcblx0ICogdGhlbiBmb3IgZWFjaCBtb25pdG9yIHlvdSB3b3VsZCBjYWxsIGl0IGxpa2UgdGhpc1xuXHQgKlxuXHQgKiAgIGNvbnN0IHcgPSAxOTIwO1xuXHQgKiAgIGNvbnN0IGggPSAxMDgwO1xuXHQgKiAgIGNvbnN0IGZ1bGxXaWR0aCA9IHcgKiAzO1xuXHQgKiAgIGNvbnN0IGZ1bGxIZWlnaHQgPSBoICogMjtcblx0ICpcblx0ICogICAtLUEtLVxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAwLCBoICogMCwgdywgaCApO1xuXHQgKiAgIC0tQi0tXG5cdCAqICAgY2FtZXJhLnNldFZpZXdPZmZzZXQoIGZ1bGxXaWR0aCwgZnVsbEhlaWdodCwgdyAqIDEsIGggKiAwLCB3LCBoICk7XG5cdCAqICAgLS1DLS1cblx0ICogICBjYW1lcmEuc2V0Vmlld09mZnNldCggZnVsbFdpZHRoLCBmdWxsSGVpZ2h0LCB3ICogMiwgaCAqIDAsIHcsIGggKTtcblx0ICogICAtLUQtLVxuXHQgKiAgIGNhbWVyYS5zZXRWaWV3T2Zmc2V0KCBmdWxsV2lkdGgsIGZ1bGxIZWlnaHQsIHcgKiAwLCBoICogMSwgdywgaCApO1xuXHQgKiAgIC0tRS0tXG5cdCAqICAgY2FtZXJhLnNldFZpZXdPZmZzZXQoIGZ1bGxXaWR0aCwgZnVsbEhlaWdodCwgdyAqIDEsIGggKiAxLCB3LCBoICk7XG5cdCAqICAgLS1GLS1cblx0ICogICBjYW1lcmEuc2V0Vmlld09mZnNldCggZnVsbFdpZHRoLCBmdWxsSGVpZ2h0LCB3ICogMiwgaCAqIDEsIHcsIGggKTtcblx0ICpcblx0ICogICBOb3RlIHRoZXJlIGlzIG5vIHJlYXNvbiBtb25pdG9ycyBoYXZlIHRvIGJlIHRoZSBzYW1lIHNpemUgb3IgaW4gYSBncmlkLlxuXHQgKi9cblx0c2V0Vmlld09mZnNldCggZnVsbFdpZHRoLCBmdWxsSGVpZ2h0LCB4LCB5LCB3aWR0aCwgaGVpZ2h0ICkge1xuXG5cdFx0dGhpcy5hc3BlY3QgPSBmdWxsV2lkdGggLyBmdWxsSGVpZ2h0O1xuXG5cdFx0aWYgKCB0aGlzLnZpZXcgPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMudmlldyA9IHtcblx0XHRcdFx0ZW5hYmxlZDogdHJ1ZSxcblx0XHRcdFx0ZnVsbFdpZHRoOiAxLFxuXHRcdFx0XHRmdWxsSGVpZ2h0OiAxLFxuXHRcdFx0XHRvZmZzZXRYOiAwLFxuXHRcdFx0XHRvZmZzZXRZOiAwLFxuXHRcdFx0XHR3aWR0aDogMSxcblx0XHRcdFx0aGVpZ2h0OiAxXG5cdFx0XHR9O1xuXG5cdFx0fVxuXG5cdFx0dGhpcy52aWV3LmVuYWJsZWQgPSB0cnVlO1xuXHRcdHRoaXMudmlldy5mdWxsV2lkdGggPSBmdWxsV2lkdGg7XG5cdFx0dGhpcy52aWV3LmZ1bGxIZWlnaHQgPSBmdWxsSGVpZ2h0O1xuXHRcdHRoaXMudmlldy5vZmZzZXRYID0geDtcblx0XHR0aGlzLnZpZXcub2Zmc2V0WSA9IHk7XG5cdFx0dGhpcy52aWV3LndpZHRoID0gd2lkdGg7XG5cdFx0dGhpcy52aWV3LmhlaWdodCA9IGhlaWdodDtcblxuXHRcdHRoaXMudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXG5cdH1cblxuXHRjbGVhclZpZXdPZmZzZXQoKSB7XG5cblx0XHRpZiAoIHRoaXMudmlldyAhPT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy52aWV3LmVuYWJsZWQgPSBmYWxzZTtcblxuXHRcdH1cblxuXHRcdHRoaXMudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXG5cdH1cblxuXHR1cGRhdGVQcm9qZWN0aW9uTWF0cml4KCkge1xuXG5cdFx0Y29uc3QgbmVhciA9IHRoaXMubmVhcjtcblx0XHRsZXQgdG9wID0gbmVhciAqIE1hdGgudGFuKCBERUcyUkFEICogMC41ICogdGhpcy5mb3YgKSAvIHRoaXMuem9vbTtcblx0XHRsZXQgaGVpZ2h0ID0gMiAqIHRvcDtcblx0XHRsZXQgd2lkdGggPSB0aGlzLmFzcGVjdCAqIGhlaWdodDtcblx0XHRsZXQgbGVmdCA9IC0gMC41ICogd2lkdGg7XG5cdFx0Y29uc3QgdmlldyA9IHRoaXMudmlldztcblxuXHRcdGlmICggdGhpcy52aWV3ICE9PSBudWxsICYmIHRoaXMudmlldy5lbmFibGVkICkge1xuXG5cdFx0XHRjb25zdCBmdWxsV2lkdGggPSB2aWV3LmZ1bGxXaWR0aCxcblx0XHRcdFx0ZnVsbEhlaWdodCA9IHZpZXcuZnVsbEhlaWdodDtcblxuXHRcdFx0bGVmdCArPSB2aWV3Lm9mZnNldFggKiB3aWR0aCAvIGZ1bGxXaWR0aDtcblx0XHRcdHRvcCAtPSB2aWV3Lm9mZnNldFkgKiBoZWlnaHQgLyBmdWxsSGVpZ2h0O1xuXHRcdFx0d2lkdGggKj0gdmlldy53aWR0aCAvIGZ1bGxXaWR0aDtcblx0XHRcdGhlaWdodCAqPSB2aWV3LmhlaWdodCAvIGZ1bGxIZWlnaHQ7XG5cblx0XHR9XG5cblx0XHRjb25zdCBza2V3ID0gdGhpcy5maWxtT2Zmc2V0O1xuXHRcdGlmICggc2tldyAhPT0gMCApIGxlZnQgKz0gbmVhciAqIHNrZXcgLyB0aGlzLmdldEZpbG1XaWR0aCgpO1xuXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4Lm1ha2VQZXJzcGVjdGl2ZSggbGVmdCwgbGVmdCArIHdpZHRoLCB0b3AsIHRvcCAtIGhlaWdodCwgbmVhciwgdGhpcy5mYXIsIHRoaXMuY29vcmRpbmF0ZVN5c3RlbSApO1xuXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZS5jb3B5KCB0aGlzLnByb2plY3Rpb25NYXRyaXggKS5pbnZlcnQoKTtcblxuXHR9XG5cblx0dG9KU09OKCBtZXRhICkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xuXG5cdFx0ZGF0YS5vYmplY3QuZm92ID0gdGhpcy5mb3Y7XG5cdFx0ZGF0YS5vYmplY3Quem9vbSA9IHRoaXMuem9vbTtcblxuXHRcdGRhdGEub2JqZWN0Lm5lYXIgPSB0aGlzLm5lYXI7XG5cdFx0ZGF0YS5vYmplY3QuZmFyID0gdGhpcy5mYXI7XG5cdFx0ZGF0YS5vYmplY3QuZm9jdXMgPSB0aGlzLmZvY3VzO1xuXG5cdFx0ZGF0YS5vYmplY3QuYXNwZWN0ID0gdGhpcy5hc3BlY3Q7XG5cblx0XHRpZiAoIHRoaXMudmlldyAhPT0gbnVsbCApIGRhdGEub2JqZWN0LnZpZXcgPSBPYmplY3QuYXNzaWduKCB7fSwgdGhpcy52aWV3ICk7XG5cblx0XHRkYXRhLm9iamVjdC5maWxtR2F1Z2UgPSB0aGlzLmZpbG1HYXVnZTtcblx0XHRkYXRhLm9iamVjdC5maWxtT2Zmc2V0ID0gdGhpcy5maWxtT2Zmc2V0O1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbmNvbnN0IGZvdiA9IC0gOTA7IC8vIG5lZ2F0aXZlIGZvdiBpcyBub3QgYW4gZXJyb3JcbmNvbnN0IGFzcGVjdCA9IDE7XG5cbmNsYXNzIEN1YmVDYW1lcmEgZXh0ZW5kcyBPYmplY3QzRCB7XG5cblx0Y29uc3RydWN0b3IoIG5lYXIsIGZhciwgcmVuZGVyVGFyZ2V0ICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdDdWJlQ2FtZXJhJztcblxuXHRcdHRoaXMucmVuZGVyVGFyZ2V0ID0gcmVuZGVyVGFyZ2V0O1xuXHRcdHRoaXMuY29vcmRpbmF0ZVN5c3RlbSA9IG51bGw7XG5cdFx0dGhpcy5hY3RpdmVNaXBtYXBMZXZlbCA9IDA7XG5cblx0XHRjb25zdCBjYW1lcmFQWCA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xuXHRcdGNhbWVyYVBYLmxheWVycyA9IHRoaXMubGF5ZXJzO1xuXHRcdHRoaXMuYWRkKCBjYW1lcmFQWCApO1xuXG5cdFx0Y29uc3QgY2FtZXJhTlggPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoIGZvdiwgYXNwZWN0LCBuZWFyLCBmYXIgKTtcblx0XHRjYW1lcmFOWC5sYXllcnMgPSB0aGlzLmxheWVycztcblx0XHR0aGlzLmFkZCggY2FtZXJhTlggKTtcblxuXHRcdGNvbnN0IGNhbWVyYVBZID0gbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCBmb3YsIGFzcGVjdCwgbmVhciwgZmFyICk7XG5cdFx0Y2FtZXJhUFkubGF5ZXJzID0gdGhpcy5sYXllcnM7XG5cdFx0dGhpcy5hZGQoIGNhbWVyYVBZICk7XG5cblx0XHRjb25zdCBjYW1lcmFOWSA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggZm92LCBhc3BlY3QsIG5lYXIsIGZhciApO1xuXHRcdGNhbWVyYU5ZLmxheWVycyA9IHRoaXMubGF5ZXJzO1xuXHRcdHRoaXMuYWRkKCBjYW1lcmFOWSApO1xuXG5cdFx0Y29uc3QgY2FtZXJhUFogPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoIGZvdiwgYXNwZWN0LCBuZWFyLCBmYXIgKTtcblx0XHRjYW1lcmFQWi5sYXllcnMgPSB0aGlzLmxheWVycztcblx0XHR0aGlzLmFkZCggY2FtZXJhUFogKTtcblxuXHRcdGNvbnN0IGNhbWVyYU5aID0gbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCBmb3YsIGFzcGVjdCwgbmVhciwgZmFyICk7XG5cdFx0Y2FtZXJhTloubGF5ZXJzID0gdGhpcy5sYXllcnM7XG5cdFx0dGhpcy5hZGQoIGNhbWVyYU5aICk7XG5cblx0fVxuXG5cdHVwZGF0ZUNvb3JkaW5hdGVTeXN0ZW0oKSB7XG5cblx0XHRjb25zdCBjb29yZGluYXRlU3lzdGVtID0gdGhpcy5jb29yZGluYXRlU3lzdGVtO1xuXG5cdFx0Y29uc3QgY2FtZXJhcyA9IHRoaXMuY2hpbGRyZW4uY29uY2F0KCk7XG5cblx0XHRjb25zdCBbIGNhbWVyYVBYLCBjYW1lcmFOWCwgY2FtZXJhUFksIGNhbWVyYU5ZLCBjYW1lcmFQWiwgY2FtZXJhTlogXSA9IGNhbWVyYXM7XG5cblx0XHRmb3IgKCBjb25zdCBjYW1lcmEgb2YgY2FtZXJhcyApIHRoaXMucmVtb3ZlKCBjYW1lcmEgKTtcblxuXHRcdGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR0xDb29yZGluYXRlU3lzdGVtICkge1xuXG5cdFx0XHRjYW1lcmFQWC51cC5zZXQoIDAsIDEsIDAgKTtcblx0XHRcdGNhbWVyYVBYLmxvb2tBdCggMSwgMCwgMCApO1xuXG5cdFx0XHRjYW1lcmFOWC51cC5zZXQoIDAsIDEsIDAgKTtcblx0XHRcdGNhbWVyYU5YLmxvb2tBdCggLSAxLCAwLCAwICk7XG5cblx0XHRcdGNhbWVyYVBZLnVwLnNldCggMCwgMCwgLSAxICk7XG5cdFx0XHRjYW1lcmFQWS5sb29rQXQoIDAsIDEsIDAgKTtcblxuXHRcdFx0Y2FtZXJhTlkudXAuc2V0KCAwLCAwLCAxICk7XG5cdFx0XHRjYW1lcmFOWS5sb29rQXQoIDAsIC0gMSwgMCApO1xuXG5cdFx0XHRjYW1lcmFQWi51cC5zZXQoIDAsIDEsIDAgKTtcblx0XHRcdGNhbWVyYVBaLmxvb2tBdCggMCwgMCwgMSApO1xuXG5cdFx0XHRjYW1lcmFOWi51cC5zZXQoIDAsIDEsIDAgKTtcblx0XHRcdGNhbWVyYU5aLmxvb2tBdCggMCwgMCwgLSAxICk7XG5cblx0XHR9IGVsc2UgaWYgKCBjb29yZGluYXRlU3lzdGVtID09PSBXZWJHUFVDb29yZGluYXRlU3lzdGVtICkge1xuXG5cdFx0XHRjYW1lcmFQWC51cC5zZXQoIDAsIC0gMSwgMCApO1xuXHRcdFx0Y2FtZXJhUFgubG9va0F0KCAtIDEsIDAsIDAgKTtcblxuXHRcdFx0Y2FtZXJhTlgudXAuc2V0KCAwLCAtIDEsIDAgKTtcblx0XHRcdGNhbWVyYU5YLmxvb2tBdCggMSwgMCwgMCApO1xuXG5cdFx0XHRjYW1lcmFQWS51cC5zZXQoIDAsIDAsIDEgKTtcblx0XHRcdGNhbWVyYVBZLmxvb2tBdCggMCwgMSwgMCApO1xuXG5cdFx0XHRjYW1lcmFOWS51cC5zZXQoIDAsIDAsIC0gMSApO1xuXHRcdFx0Y2FtZXJhTlkubG9va0F0KCAwLCAtIDEsIDAgKTtcblxuXHRcdFx0Y2FtZXJhUFoudXAuc2V0KCAwLCAtIDEsIDAgKTtcblx0XHRcdGNhbWVyYVBaLmxvb2tBdCggMCwgMCwgMSApO1xuXG5cdFx0XHRjYW1lcmFOWi51cC5zZXQoIDAsIC0gMSwgMCApO1xuXHRcdFx0Y2FtZXJhTloubG9va0F0KCAwLCAwLCAtIDEgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLkN1YmVDYW1lcmEudXBkYXRlQ29vcmRpbmF0ZVN5c3RlbSgpOiBJbnZhbGlkIGNvb3JkaW5hdGUgc3lzdGVtOiAnICsgY29vcmRpbmF0ZVN5c3RlbSApO1xuXG5cdFx0fVxuXG5cdFx0Zm9yICggY29uc3QgY2FtZXJhIG9mIGNhbWVyYXMgKSB7XG5cblx0XHRcdHRoaXMuYWRkKCBjYW1lcmEgKTtcblxuXHRcdFx0Y2FtZXJhLnVwZGF0ZU1hdHJpeFdvcmxkKCk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHVwZGF0ZSggcmVuZGVyZXIsIHNjZW5lICkge1xuXG5cdFx0aWYgKCB0aGlzLnBhcmVudCA9PT0gbnVsbCApIHRoaXMudXBkYXRlTWF0cml4V29ybGQoKTtcblxuXHRcdGNvbnN0IHsgcmVuZGVyVGFyZ2V0LCBhY3RpdmVNaXBtYXBMZXZlbCB9ID0gdGhpcztcblxuXHRcdGlmICggdGhpcy5jb29yZGluYXRlU3lzdGVtICE9PSByZW5kZXJlci5jb29yZGluYXRlU3lzdGVtICkge1xuXG5cdFx0XHR0aGlzLmNvb3JkaW5hdGVTeXN0ZW0gPSByZW5kZXJlci5jb29yZGluYXRlU3lzdGVtO1xuXG5cdFx0XHR0aGlzLnVwZGF0ZUNvb3JkaW5hdGVTeXN0ZW0oKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IFsgY2FtZXJhUFgsIGNhbWVyYU5YLCBjYW1lcmFQWSwgY2FtZXJhTlksIGNhbWVyYVBaLCBjYW1lcmFOWiBdID0gdGhpcy5jaGlsZHJlbjtcblxuXHRcdGNvbnN0IGN1cnJlbnRSZW5kZXJUYXJnZXQgPSByZW5kZXJlci5nZXRSZW5kZXJUYXJnZXQoKTtcblx0XHRjb25zdCBjdXJyZW50QWN0aXZlQ3ViZUZhY2UgPSByZW5kZXJlci5nZXRBY3RpdmVDdWJlRmFjZSgpO1xuXHRcdGNvbnN0IGN1cnJlbnRBY3RpdmVNaXBtYXBMZXZlbCA9IHJlbmRlcmVyLmdldEFjdGl2ZU1pcG1hcExldmVsKCk7XG5cblx0XHRjb25zdCBjdXJyZW50WHJFbmFibGVkID0gcmVuZGVyZXIueHIuZW5hYmxlZDtcblxuXHRcdHJlbmRlcmVyLnhyLmVuYWJsZWQgPSBmYWxzZTtcblxuXHRcdGNvbnN0IGdlbmVyYXRlTWlwbWFwcyA9IHJlbmRlclRhcmdldC50ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcztcblxuXHRcdHJlbmRlclRhcmdldC50ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQsIDAsIGFjdGl2ZU1pcG1hcExldmVsICk7XG5cdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY2FtZXJhUFggKTtcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0LCAxLCBhY3RpdmVNaXBtYXBMZXZlbCApO1xuXHRcdHJlbmRlcmVyLnJlbmRlciggc2NlbmUsIGNhbWVyYU5YICk7XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCwgMiwgYWN0aXZlTWlwbWFwTGV2ZWwgKTtcblx0XHRyZW5kZXJlci5yZW5kZXIoIHNjZW5lLCBjYW1lcmFQWSApO1xuXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQsIDMsIGFjdGl2ZU1pcG1hcExldmVsICk7XG5cdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY2FtZXJhTlkgKTtcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0LCA0LCBhY3RpdmVNaXBtYXBMZXZlbCApO1xuXHRcdHJlbmRlcmVyLnJlbmRlciggc2NlbmUsIGNhbWVyYVBaICk7XG5cblx0XHQvLyBtaXBtYXBzIGFyZSBnZW5lcmF0ZWQgZHVyaW5nIHRoZSBsYXN0IGNhbGwgb2YgcmVuZGVyKClcblx0XHQvLyBhdCB0aGlzIHBvaW50LCBhbGwgc2lkZXMgb2YgdGhlIGN1YmUgcmVuZGVyIHRhcmdldCBhcmUgZGVmaW5lZFxuXG5cdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZ2VuZXJhdGVNaXBtYXBzO1xuXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCByZW5kZXJUYXJnZXQsIDUsIGFjdGl2ZU1pcG1hcExldmVsICk7XG5cdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY2FtZXJhTlogKTtcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggY3VycmVudFJlbmRlclRhcmdldCwgY3VycmVudEFjdGl2ZUN1YmVGYWNlLCBjdXJyZW50QWN0aXZlTWlwbWFwTGV2ZWwgKTtcblxuXHRcdHJlbmRlcmVyLnhyLmVuYWJsZWQgPSBjdXJyZW50WHJFbmFibGVkO1xuXG5cdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUubmVlZHNQTVJFTVVwZGF0ZSA9IHRydWU7XG5cblx0fVxuXG59XG5cbmNsYXNzIEN1YmVUZXh0dXJlIGV4dGVuZHMgVGV4dHVyZSB7XG5cblx0Y29uc3RydWN0b3IoIGltYWdlcywgbWFwcGluZywgd3JhcFMsIHdyYXBULCBtYWdGaWx0ZXIsIG1pbkZpbHRlciwgZm9ybWF0LCB0eXBlLCBhbmlzb3Ryb3B5LCBjb2xvclNwYWNlICkge1xuXG5cdFx0aW1hZ2VzID0gaW1hZ2VzICE9PSB1bmRlZmluZWQgPyBpbWFnZXMgOiBbXTtcblx0XHRtYXBwaW5nID0gbWFwcGluZyAhPT0gdW5kZWZpbmVkID8gbWFwcGluZyA6IEN1YmVSZWZsZWN0aW9uTWFwcGluZztcblxuXHRcdHN1cGVyKCBpbWFnZXMsIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSwgY29sb3JTcGFjZSApO1xuXG5cdFx0dGhpcy5pc0N1YmVUZXh0dXJlID0gdHJ1ZTtcblxuXHRcdHRoaXMuZmxpcFkgPSBmYWxzZTtcblxuXHR9XG5cblx0Z2V0IGltYWdlcygpIHtcblxuXHRcdHJldHVybiB0aGlzLmltYWdlO1xuXG5cdH1cblxuXHRzZXQgaW1hZ2VzKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMuaW1hZ2UgPSB2YWx1ZTtcblxuXHR9XG5cbn1cblxuY2xhc3MgV2ViR0xDdWJlUmVuZGVyVGFyZ2V0IGV4dGVuZHMgV2ViR0xSZW5kZXJUYXJnZXQge1xuXG5cdGNvbnN0cnVjdG9yKCBzaXplID0gMSwgb3B0aW9ucyA9IHt9ICkge1xuXG5cdFx0c3VwZXIoIHNpemUsIHNpemUsIG9wdGlvbnMgKTtcblxuXHRcdHRoaXMuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgPSB0cnVlO1xuXG5cdFx0Y29uc3QgaW1hZ2UgPSB7IHdpZHRoOiBzaXplLCBoZWlnaHQ6IHNpemUsIGRlcHRoOiAxIH07XG5cdFx0Y29uc3QgaW1hZ2VzID0gWyBpbWFnZSwgaW1hZ2UsIGltYWdlLCBpbWFnZSwgaW1hZ2UsIGltYWdlIF07XG5cblx0XHR0aGlzLnRleHR1cmUgPSBuZXcgQ3ViZVRleHR1cmUoIGltYWdlcywgb3B0aW9ucy5tYXBwaW5nLCBvcHRpb25zLndyYXBTLCBvcHRpb25zLndyYXBULCBvcHRpb25zLm1hZ0ZpbHRlciwgb3B0aW9ucy5taW5GaWx0ZXIsIG9wdGlvbnMuZm9ybWF0LCBvcHRpb25zLnR5cGUsIG9wdGlvbnMuYW5pc290cm9weSwgb3B0aW9ucy5jb2xvclNwYWNlICk7XG5cblx0XHQvLyBCeSBjb252ZW50aW9uIC0tIGxpa2VseSBiYXNlZCBvbiB0aGUgUmVuZGVyTWFuIHNwZWMgZnJvbSB0aGUgMTk5MCdzIC0tIGN1YmUgbWFwcyBhcmUgc3BlY2lmaWVkIGJ5IFdlYkdMIChhbmQgdGhyZWUuanMpXG5cdFx0Ly8gaW4gYSBjb29yZGluYXRlIHN5c3RlbSBpbiB3aGljaCBwb3NpdGl2ZS14IGlzIHRvIHRoZSByaWdodCB3aGVuIGxvb2tpbmcgdXAgdGhlIHBvc2l0aXZlLXogYXhpcyAtLSBpbiBvdGhlciB3b3Jkcyxcblx0XHQvLyBpbiBhIGxlZnQtaGFuZGVkIGNvb3JkaW5hdGUgc3lzdGVtLiBCeSBjb250aW51aW5nIHRoaXMgY29udmVudGlvbiwgcHJlZXhpc3RpbmcgY3ViZSBtYXBzIGNvbnRpbnVlZCB0byByZW5kZXIgY29ycmVjdGx5LlxuXG5cdFx0Ly8gdGhyZWUuanMgdXNlcyBhIHJpZ2h0LWhhbmRlZCBjb29yZGluYXRlIHN5c3RlbS4gU28gZW52aXJvbm1lbnQgbWFwcyB1c2VkIGluIHRocmVlLmpzIGFwcGVhciB0byBoYXZlIHB4IGFuZCBueCBzd2FwcGVkXG5cdFx0Ly8gYW5kIHRoZSBmbGFnIGlzUmVuZGVyVGFyZ2V0VGV4dHVyZSBjb250cm9scyB0aGlzIGNvbnZlcnNpb24uIFRoZSBmbGlwIGlzIG5vdCByZXF1aXJlZCB3aGVuIHVzaW5nIFdlYkdMQ3ViZVJlbmRlclRhcmdldC50ZXh0dXJlXG5cdFx0Ly8gYXMgYSBjdWJlIHRleHR1cmUgKHRoaXMgaXMgZGV0ZWN0ZWQgd2hlbiBpc1JlbmRlclRhcmdldFRleHR1cmUgaXMgc2V0IHRvIHRydWUgZm9yIGN1YmUgdGV4dHVyZXMpLlxuXG5cdFx0dGhpcy50ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9IHRydWU7XG5cblx0XHR0aGlzLnRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gb3B0aW9ucy5nZW5lcmF0ZU1pcG1hcHMgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuZ2VuZXJhdGVNaXBtYXBzIDogZmFsc2U7XG5cdFx0dGhpcy50ZXh0dXJlLm1pbkZpbHRlciA9IG9wdGlvbnMubWluRmlsdGVyICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLm1pbkZpbHRlciA6IExpbmVhckZpbHRlcjtcblxuXHR9XG5cblx0ZnJvbUVxdWlyZWN0YW5ndWxhclRleHR1cmUoIHJlbmRlcmVyLCB0ZXh0dXJlICkge1xuXG5cdFx0dGhpcy50ZXh0dXJlLnR5cGUgPSB0ZXh0dXJlLnR5cGU7XG5cdFx0dGhpcy50ZXh0dXJlLmNvbG9yU3BhY2UgPSB0ZXh0dXJlLmNvbG9yU3BhY2U7XG5cblx0XHR0aGlzLnRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gdGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHM7XG5cdFx0dGhpcy50ZXh0dXJlLm1pbkZpbHRlciA9IHRleHR1cmUubWluRmlsdGVyO1xuXHRcdHRoaXMudGV4dHVyZS5tYWdGaWx0ZXIgPSB0ZXh0dXJlLm1hZ0ZpbHRlcjtcblxuXHRcdGNvbnN0IHNoYWRlciA9IHtcblxuXHRcdFx0dW5pZm9ybXM6IHtcblx0XHRcdFx0dEVxdWlyZWN0OiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHR9LFxuXG5cdFx0XHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHRcdFx0dmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcblxuXHRcdFx0XHR2ZWMzIHRyYW5zZm9ybURpcmVjdGlvbiggaW4gdmVjMyBkaXIsIGluIG1hdDQgbWF0cml4ICkge1xuXG5cdFx0XHRcdFx0cmV0dXJuIG5vcm1hbGl6ZSggKCBtYXRyaXggKiB2ZWM0KCBkaXIsIDAuMCApICkueHl6ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0XHRcdHZXb3JsZERpcmVjdGlvbiA9IHRyYW5zZm9ybURpcmVjdGlvbiggcG9zaXRpb24sIG1vZGVsTWF0cml4ICk7XG5cblx0XHRcdFx0XHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxuXHRcdFx0XHRcdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cblxuXHRcdFx0XHR9XG5cdFx0XHRgLFxuXG5cdFx0XHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2BcblxuXHRcdFx0XHR1bmlmb3JtIHNhbXBsZXIyRCB0RXF1aXJlY3Q7XG5cblx0XHRcdFx0dmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcblxuXHRcdFx0XHQjaW5jbHVkZSA8Y29tbW9uPlxuXG5cdFx0XHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0XHRcdHZlYzMgZGlyZWN0aW9uID0gbm9ybWFsaXplKCB2V29ybGREaXJlY3Rpb24gKTtcblxuXHRcdFx0XHRcdHZlYzIgc2FtcGxlVVYgPSBlcXVpcmVjdFV2KCBkaXJlY3Rpb24gKTtcblxuXHRcdFx0XHRcdGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCggdEVxdWlyZWN0LCBzYW1wbGVVViApO1xuXG5cdFx0XHRcdH1cblx0XHRcdGBcblx0XHR9O1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgQm94R2VvbWV0cnkoIDUsIDUsIDUgKTtcblxuXHRcdGNvbnN0IG1hdGVyaWFsID0gbmV3IFNoYWRlck1hdGVyaWFsKCB7XG5cblx0XHRcdG5hbWU6ICdDdWJlbWFwRnJvbUVxdWlyZWN0JyxcblxuXHRcdFx0dW5pZm9ybXM6IGNsb25lVW5pZm9ybXMoIHNoYWRlci51bmlmb3JtcyApLFxuXHRcdFx0dmVydGV4U2hhZGVyOiBzaGFkZXIudmVydGV4U2hhZGVyLFxuXHRcdFx0ZnJhZ21lbnRTaGFkZXI6IHNoYWRlci5mcmFnbWVudFNoYWRlcixcblx0XHRcdHNpZGU6IEJhY2tTaWRlLFxuXHRcdFx0YmxlbmRpbmc6IE5vQmxlbmRpbmdcblxuXHRcdH0gKTtcblxuXHRcdG1hdGVyaWFsLnVuaWZvcm1zLnRFcXVpcmVjdC52YWx1ZSA9IHRleHR1cmU7XG5cblx0XHRjb25zdCBtZXNoID0gbmV3IE1lc2goIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xuXG5cdFx0Y29uc3QgY3VycmVudE1pbkZpbHRlciA9IHRleHR1cmUubWluRmlsdGVyO1xuXG5cdFx0Ly8gQXZvaWQgYmx1cnJlZCBwb2xlc1xuXHRcdGlmICggdGV4dHVyZS5taW5GaWx0ZXIgPT09IExpbmVhck1pcG1hcExpbmVhckZpbHRlciApIHRleHR1cmUubWluRmlsdGVyID0gTGluZWFyRmlsdGVyO1xuXG5cdFx0Y29uc3QgY2FtZXJhID0gbmV3IEN1YmVDYW1lcmEoIDEsIDEwLCB0aGlzICk7XG5cdFx0Y2FtZXJhLnVwZGF0ZSggcmVuZGVyZXIsIG1lc2ggKTtcblxuXHRcdHRleHR1cmUubWluRmlsdGVyID0gY3VycmVudE1pbkZpbHRlcjtcblxuXHRcdG1lc2guZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXHRcdG1lc2gubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsZWFyKCByZW5kZXJlciwgY29sb3IsIGRlcHRoLCBzdGVuY2lsICkge1xuXG5cdFx0Y29uc3QgY3VycmVudFJlbmRlclRhcmdldCA9IHJlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcblxuXHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCB0aGlzLCBpICk7XG5cblx0XHRcdHJlbmRlcmVyLmNsZWFyKCBjb2xvciwgZGVwdGgsIHN0ZW5jaWwgKTtcblxuXHRcdH1cblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggY3VycmVudFJlbmRlclRhcmdldCApO1xuXG5cdH1cblxufVxuXG5jb25zdCBfdmVjdG9yMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92ZWN0b3IyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX25vcm1hbE1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKTtcblxuY2xhc3MgUGxhbmUge1xuXG5cdGNvbnN0cnVjdG9yKCBub3JtYWwgPSBuZXcgVmVjdG9yMyggMSwgMCwgMCApLCBjb25zdGFudCA9IDAgKSB7XG5cblx0XHR0aGlzLmlzUGxhbmUgPSB0cnVlO1xuXG5cdFx0Ly8gbm9ybWFsIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZFxuXG5cdFx0dGhpcy5ub3JtYWwgPSBub3JtYWw7XG5cdFx0dGhpcy5jb25zdGFudCA9IGNvbnN0YW50O1xuXG5cdH1cblxuXHRzZXQoIG5vcm1hbCwgY29uc3RhbnQgKSB7XG5cblx0XHR0aGlzLm5vcm1hbC5jb3B5KCBub3JtYWwgKTtcblx0XHR0aGlzLmNvbnN0YW50ID0gY29uc3RhbnQ7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0Q29tcG9uZW50cyggeCwgeSwgeiwgdyApIHtcblxuXHRcdHRoaXMubm9ybWFsLnNldCggeCwgeSwgeiApO1xuXHRcdHRoaXMuY29uc3RhbnQgPSB3O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21Ob3JtYWxBbmRDb3BsYW5hclBvaW50KCBub3JtYWwsIHBvaW50ICkge1xuXG5cdFx0dGhpcy5ub3JtYWwuY29weSggbm9ybWFsICk7XG5cdFx0dGhpcy5jb25zdGFudCA9IC0gcG9pbnQuZG90KCB0aGlzLm5vcm1hbCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21Db3BsYW5hclBvaW50cyggYSwgYiwgYyApIHtcblxuXHRcdGNvbnN0IG5vcm1hbCA9IF92ZWN0b3IxLnN1YlZlY3RvcnMoIGMsIGIgKS5jcm9zcyggX3ZlY3RvcjIuc3ViVmVjdG9ycyggYSwgYiApICkubm9ybWFsaXplKCk7XG5cblx0XHQvLyBROiBzaG91bGQgYW4gZXJyb3IgYmUgdGhyb3duIGlmIG5vcm1hbCBpcyB6ZXJvIChlLmcuIGRlZ2VuZXJhdGUgcGxhbmUpP1xuXG5cdFx0dGhpcy5zZXRGcm9tTm9ybWFsQW5kQ29wbGFuYXJQb2ludCggbm9ybWFsLCBhICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weSggcGxhbmUgKSB7XG5cblx0XHR0aGlzLm5vcm1hbC5jb3B5KCBwbGFuZS5ub3JtYWwgKTtcblx0XHR0aGlzLmNvbnN0YW50ID0gcGxhbmUuY29uc3RhbnQ7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bm9ybWFsaXplKCkge1xuXG5cdFx0Ly8gTm90ZTogd2lsbCBsZWFkIHRvIGEgZGl2aWRlIGJ5IHplcm8gaWYgdGhlIHBsYW5lIGlzIGludmFsaWQuXG5cblx0XHRjb25zdCBpbnZlcnNlTm9ybWFsTGVuZ3RoID0gMS4wIC8gdGhpcy5ub3JtYWwubGVuZ3RoKCk7XG5cdFx0dGhpcy5ub3JtYWwubXVsdGlwbHlTY2FsYXIoIGludmVyc2VOb3JtYWxMZW5ndGggKTtcblx0XHR0aGlzLmNvbnN0YW50ICo9IGludmVyc2VOb3JtYWxMZW5ndGg7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0bmVnYXRlKCkge1xuXG5cdFx0dGhpcy5jb25zdGFudCAqPSAtIDE7XG5cdFx0dGhpcy5ub3JtYWwubmVnYXRlKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGlzdGFuY2VUb1BvaW50KCBwb2ludCApIHtcblxuXHRcdHJldHVybiB0aGlzLm5vcm1hbC5kb3QoIHBvaW50ICkgKyB0aGlzLmNvbnN0YW50O1xuXG5cdH1cblxuXHRkaXN0YW5jZVRvU3BoZXJlKCBzcGhlcmUgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5kaXN0YW5jZVRvUG9pbnQoIHNwaGVyZS5jZW50ZXIgKSAtIHNwaGVyZS5yYWRpdXM7XG5cblx0fVxuXG5cdHByb2plY3RQb2ludCggcG9pbnQsIHRhcmdldCApIHtcblxuXHRcdHJldHVybiB0YXJnZXQuY29weSggcG9pbnQgKS5hZGRTY2FsZWRWZWN0b3IoIHRoaXMubm9ybWFsLCAtIHRoaXMuZGlzdGFuY2VUb1BvaW50KCBwb2ludCApICk7XG5cblx0fVxuXG5cdGludGVyc2VjdExpbmUoIGxpbmUsIHRhcmdldCApIHtcblxuXHRcdGNvbnN0IGRpcmVjdGlvbiA9IGxpbmUuZGVsdGEoIF92ZWN0b3IxICk7XG5cblx0XHRjb25zdCBkZW5vbWluYXRvciA9IHRoaXMubm9ybWFsLmRvdCggZGlyZWN0aW9uICk7XG5cblx0XHRpZiAoIGRlbm9taW5hdG9yID09PSAwICkge1xuXG5cdFx0XHQvLyBsaW5lIGlzIGNvcGxhbmFyLCByZXR1cm4gb3JpZ2luXG5cdFx0XHRpZiAoIHRoaXMuZGlzdGFuY2VUb1BvaW50KCBsaW5lLnN0YXJ0ICkgPT09IDAgKSB7XG5cblx0XHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBsaW5lLnN0YXJ0ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gVW5zdXJlIGlmIHRoaXMgaXMgdGhlIGNvcnJlY3QgbWV0aG9kIHRvIGhhbmRsZSB0aGlzIGNhc2UuXG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHQgPSAtICggbGluZS5zdGFydC5kb3QoIHRoaXMubm9ybWFsICkgKyB0aGlzLmNvbnN0YW50ICkgLyBkZW5vbWluYXRvcjtcblxuXHRcdGlmICggdCA8IDAgfHwgdCA+IDEgKSB7XG5cblx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBsaW5lLnN0YXJ0ICkuYWRkU2NhbGVkVmVjdG9yKCBkaXJlY3Rpb24sIHQgKTtcblxuXHR9XG5cblx0aW50ZXJzZWN0c0xpbmUoIGxpbmUgKSB7XG5cblx0XHQvLyBOb3RlOiB0aGlzIHRlc3RzIGlmIGEgbGluZSBpbnRlcnNlY3RzIHRoZSBwbGFuZSwgbm90IHdoZXRoZXIgaXQgKG9yIGl0cyBlbmQtcG9pbnRzKSBhcmUgY29wbGFuYXIgd2l0aCBpdC5cblxuXHRcdGNvbnN0IHN0YXJ0U2lnbiA9IHRoaXMuZGlzdGFuY2VUb1BvaW50KCBsaW5lLnN0YXJ0ICk7XG5cdFx0Y29uc3QgZW5kU2lnbiA9IHRoaXMuZGlzdGFuY2VUb1BvaW50KCBsaW5lLmVuZCApO1xuXG5cdFx0cmV0dXJuICggc3RhcnRTaWduIDwgMCAmJiBlbmRTaWduID4gMCApIHx8ICggZW5kU2lnbiA8IDAgJiYgc3RhcnRTaWduID4gMCApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzQm94KCBib3ggKSB7XG5cblx0XHRyZXR1cm4gYm94LmludGVyc2VjdHNQbGFuZSggdGhpcyApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzU3BoZXJlKCBzcGhlcmUgKSB7XG5cblx0XHRyZXR1cm4gc3BoZXJlLmludGVyc2VjdHNQbGFuZSggdGhpcyApO1xuXG5cdH1cblxuXHRjb3BsYW5hclBvaW50KCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LmNvcHkoIHRoaXMubm9ybWFsICkubXVsdGlwbHlTY2FsYXIoIC0gdGhpcy5jb25zdGFudCApO1xuXG5cdH1cblxuXHRhcHBseU1hdHJpeDQoIG1hdHJpeCwgb3B0aW9uYWxOb3JtYWxNYXRyaXggKSB7XG5cblx0XHRjb25zdCBub3JtYWxNYXRyaXggPSBvcHRpb25hbE5vcm1hbE1hdHJpeCB8fCBfbm9ybWFsTWF0cml4LmdldE5vcm1hbE1hdHJpeCggbWF0cml4ICk7XG5cblx0XHRjb25zdCByZWZlcmVuY2VQb2ludCA9IHRoaXMuY29wbGFuYXJQb2ludCggX3ZlY3RvcjEgKS5hcHBseU1hdHJpeDQoIG1hdHJpeCApO1xuXG5cdFx0Y29uc3Qgbm9ybWFsID0gdGhpcy5ub3JtYWwuYXBwbHlNYXRyaXgzKCBub3JtYWxNYXRyaXggKS5ub3JtYWxpemUoKTtcblxuXHRcdHRoaXMuY29uc3RhbnQgPSAtIHJlZmVyZW5jZVBvaW50LmRvdCggbm9ybWFsICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJhbnNsYXRlKCBvZmZzZXQgKSB7XG5cblx0XHR0aGlzLmNvbnN0YW50IC09IG9mZnNldC5kb3QoIHRoaXMubm9ybWFsICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXF1YWxzKCBwbGFuZSApIHtcblxuXHRcdHJldHVybiBwbGFuZS5ub3JtYWwuZXF1YWxzKCB0aGlzLm5vcm1hbCApICYmICggcGxhbmUuY29uc3RhbnQgPT09IHRoaXMuY29uc3RhbnQgKTtcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9zcGhlcmUkNSA9IC8qQF9fUFVSRV9fKi8gbmV3IFNwaGVyZSgpO1xuY29uc3QgX3ZlY3RvciQ3ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jbGFzcyBGcnVzdHVtIHtcblxuXHRjb25zdHJ1Y3RvciggcDAgPSBuZXcgUGxhbmUoKSwgcDEgPSBuZXcgUGxhbmUoKSwgcDIgPSBuZXcgUGxhbmUoKSwgcDMgPSBuZXcgUGxhbmUoKSwgcDQgPSBuZXcgUGxhbmUoKSwgcDUgPSBuZXcgUGxhbmUoKSApIHtcblxuXHRcdHRoaXMucGxhbmVzID0gWyBwMCwgcDEsIHAyLCBwMywgcDQsIHA1IF07XG5cblx0fVxuXG5cdHNldCggcDAsIHAxLCBwMiwgcDMsIHA0LCBwNSApIHtcblxuXHRcdGNvbnN0IHBsYW5lcyA9IHRoaXMucGxhbmVzO1xuXG5cdFx0cGxhbmVzWyAwIF0uY29weSggcDAgKTtcblx0XHRwbGFuZXNbIDEgXS5jb3B5KCBwMSApO1xuXHRcdHBsYW5lc1sgMiBdLmNvcHkoIHAyICk7XG5cdFx0cGxhbmVzWyAzIF0uY29weSggcDMgKTtcblx0XHRwbGFuZXNbIDQgXS5jb3B5KCBwNCApO1xuXHRcdHBsYW5lc1sgNSBdLmNvcHkoIHA1ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weSggZnJ1c3R1bSApIHtcblxuXHRcdGNvbnN0IHBsYW5lcyA9IHRoaXMucGxhbmVzO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcblxuXHRcdFx0cGxhbmVzWyBpIF0uY29weSggZnJ1c3R1bS5wbGFuZXNbIGkgXSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21Qcm9qZWN0aW9uTWF0cml4KCBtLCBjb29yZGluYXRlU3lzdGVtID0gV2ViR0xDb29yZGluYXRlU3lzdGVtICkge1xuXG5cdFx0Y29uc3QgcGxhbmVzID0gdGhpcy5wbGFuZXM7XG5cdFx0Y29uc3QgbWUgPSBtLmVsZW1lbnRzO1xuXHRcdGNvbnN0IG1lMCA9IG1lWyAwIF0sIG1lMSA9IG1lWyAxIF0sIG1lMiA9IG1lWyAyIF0sIG1lMyA9IG1lWyAzIF07XG5cdFx0Y29uc3QgbWU0ID0gbWVbIDQgXSwgbWU1ID0gbWVbIDUgXSwgbWU2ID0gbWVbIDYgXSwgbWU3ID0gbWVbIDcgXTtcblx0XHRjb25zdCBtZTggPSBtZVsgOCBdLCBtZTkgPSBtZVsgOSBdLCBtZTEwID0gbWVbIDEwIF0sIG1lMTEgPSBtZVsgMTEgXTtcblx0XHRjb25zdCBtZTEyID0gbWVbIDEyIF0sIG1lMTMgPSBtZVsgMTMgXSwgbWUxNCA9IG1lWyAxNCBdLCBtZTE1ID0gbWVbIDE1IF07XG5cblx0XHRwbGFuZXNbIDAgXS5zZXRDb21wb25lbnRzKCBtZTMgLSBtZTAsIG1lNyAtIG1lNCwgbWUxMSAtIG1lOCwgbWUxNSAtIG1lMTIgKS5ub3JtYWxpemUoKTtcblx0XHRwbGFuZXNbIDEgXS5zZXRDb21wb25lbnRzKCBtZTMgKyBtZTAsIG1lNyArIG1lNCwgbWUxMSArIG1lOCwgbWUxNSArIG1lMTIgKS5ub3JtYWxpemUoKTtcblx0XHRwbGFuZXNbIDIgXS5zZXRDb21wb25lbnRzKCBtZTMgKyBtZTEsIG1lNyArIG1lNSwgbWUxMSArIG1lOSwgbWUxNSArIG1lMTMgKS5ub3JtYWxpemUoKTtcblx0XHRwbGFuZXNbIDMgXS5zZXRDb21wb25lbnRzKCBtZTMgLSBtZTEsIG1lNyAtIG1lNSwgbWUxMSAtIG1lOSwgbWUxNSAtIG1lMTMgKS5ub3JtYWxpemUoKTtcblx0XHRwbGFuZXNbIDQgXS5zZXRDb21wb25lbnRzKCBtZTMgLSBtZTIsIG1lNyAtIG1lNiwgbWUxMSAtIG1lMTAsIG1lMTUgLSBtZTE0ICkubm9ybWFsaXplKCk7XG5cblx0XHRpZiAoIGNvb3JkaW5hdGVTeXN0ZW0gPT09IFdlYkdMQ29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdFx0cGxhbmVzWyA1IF0uc2V0Q29tcG9uZW50cyggbWUzICsgbWUyLCBtZTcgKyBtZTYsIG1lMTEgKyBtZTEwLCBtZTE1ICsgbWUxNCApLm5vcm1hbGl6ZSgpO1xuXG5cdFx0fSBlbHNlIGlmICggY29vcmRpbmF0ZVN5c3RlbSA9PT0gV2ViR1BVQ29vcmRpbmF0ZVN5c3RlbSApIHtcblxuXHRcdFx0cGxhbmVzWyA1IF0uc2V0Q29tcG9uZW50cyggbWUyLCBtZTYsIG1lMTAsIG1lMTQgKS5ub3JtYWxpemUoKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLkZydXN0dW0uc2V0RnJvbVByb2plY3Rpb25NYXRyaXgoKTogSW52YWxpZCBjb29yZGluYXRlIHN5c3RlbTogJyArIGNvb3JkaW5hdGVTeXN0ZW0gKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzT2JqZWN0KCBvYmplY3QgKSB7XG5cblx0XHRpZiAoIG9iamVjdC5ib3VuZGluZ1NwaGVyZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRpZiAoIG9iamVjdC5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIG9iamVjdC5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcblxuXHRcdFx0X3NwaGVyZSQ1LmNvcHkoIG9iamVjdC5ib3VuZGluZ1NwaGVyZSApLmFwcGx5TWF0cml4NCggb2JqZWN0Lm1hdHJpeFdvcmxkICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zdCBnZW9tZXRyeSA9IG9iamVjdC5nZW9tZXRyeTtcblxuXHRcdFx0aWYgKCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIGdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xuXG5cdFx0XHRfc3BoZXJlJDUuY29weSggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgKS5hcHBseU1hdHJpeDQoIG9iamVjdC5tYXRyaXhXb3JsZCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSQ1ICk7XG5cblx0fVxuXG5cdGludGVyc2VjdHNTcHJpdGUoIHNwcml0ZSApIHtcblxuXHRcdF9zcGhlcmUkNS5jZW50ZXIuc2V0KCAwLCAwLCAwICk7XG5cdFx0X3NwaGVyZSQ1LnJhZGl1cyA9IDAuNzA3MTA2NzgxMTg2NTQ3Njtcblx0XHRfc3BoZXJlJDUuYXBwbHlNYXRyaXg0KCBzcHJpdGUubWF0cml4V29ybGQgKTtcblxuXHRcdHJldHVybiB0aGlzLmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUkNSApO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzU3BoZXJlKCBzcGhlcmUgKSB7XG5cblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcblx0XHRjb25zdCBjZW50ZXIgPSBzcGhlcmUuY2VudGVyO1xuXHRcdGNvbnN0IG5lZ1JhZGl1cyA9IC0gc3BoZXJlLnJhZGl1cztcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGRpc3RhbmNlID0gcGxhbmVzWyBpIF0uZGlzdGFuY2VUb1BvaW50KCBjZW50ZXIgKTtcblxuXHRcdFx0aWYgKCBkaXN0YW5jZSA8IG5lZ1JhZGl1cyApIHtcblxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0cnVlO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzQm94KCBib3ggKSB7XG5cblx0XHRjb25zdCBwbGFuZXMgPSB0aGlzLnBsYW5lcztcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHBsYW5lID0gcGxhbmVzWyBpIF07XG5cblx0XHRcdC8vIGNvcm5lciBhdCBtYXggZGlzdGFuY2VcblxuXHRcdFx0X3ZlY3RvciQ3LnggPSBwbGFuZS5ub3JtYWwueCA+IDAgPyBib3gubWF4LnggOiBib3gubWluLng7XG5cdFx0XHRfdmVjdG9yJDcueSA9IHBsYW5lLm5vcm1hbC55ID4gMCA/IGJveC5tYXgueSA6IGJveC5taW4ueTtcblx0XHRcdF92ZWN0b3IkNy56ID0gcGxhbmUubm9ybWFsLnogPiAwID8gYm94Lm1heC56IDogYm94Lm1pbi56O1xuXG5cdFx0XHRpZiAoIHBsYW5lLmRpc3RhbmNlVG9Qb2ludCggX3ZlY3RvciQ3ICkgPCAwICkge1xuXG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fVxuXG5cdGNvbnRhaW5zUG9pbnQoIHBvaW50ICkge1xuXG5cdFx0Y29uc3QgcGxhbmVzID0gdGhpcy5wbGFuZXM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xuXG5cdFx0XHRpZiAoIHBsYW5lc1sgaSBdLmRpc3RhbmNlVG9Qb2ludCggcG9pbnQgKSA8IDAgKSB7XG5cblx0XHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIFdlYkdMQW5pbWF0aW9uKCkge1xuXG5cdGxldCBjb250ZXh0ID0gbnVsbDtcblx0bGV0IGlzQW5pbWF0aW5nID0gZmFsc2U7XG5cdGxldCBhbmltYXRpb25Mb29wID0gbnVsbDtcblx0bGV0IHJlcXVlc3RJZCA9IG51bGw7XG5cblx0ZnVuY3Rpb24gb25BbmltYXRpb25GcmFtZSggdGltZSwgZnJhbWUgKSB7XG5cblx0XHRhbmltYXRpb25Mb29wKCB0aW1lLCBmcmFtZSApO1xuXG5cdFx0cmVxdWVzdElkID0gY29udGV4dC5yZXF1ZXN0QW5pbWF0aW9uRnJhbWUoIG9uQW5pbWF0aW9uRnJhbWUgKTtcblxuXHR9XG5cblx0cmV0dXJuIHtcblxuXHRcdHN0YXJ0OiBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdGlmICggaXNBbmltYXRpbmcgPT09IHRydWUgKSByZXR1cm47XG5cdFx0XHRpZiAoIGFuaW1hdGlvbkxvb3AgPT09IG51bGwgKSByZXR1cm47XG5cblx0XHRcdHJlcXVlc3RJZCA9IGNvbnRleHQucmVxdWVzdEFuaW1hdGlvbkZyYW1lKCBvbkFuaW1hdGlvbkZyYW1lICk7XG5cblx0XHRcdGlzQW5pbWF0aW5nID0gdHJ1ZTtcblxuXHRcdH0sXG5cblx0XHRzdG9wOiBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdGNvbnRleHQuY2FuY2VsQW5pbWF0aW9uRnJhbWUoIHJlcXVlc3RJZCApO1xuXG5cdFx0XHRpc0FuaW1hdGluZyA9IGZhbHNlO1xuXG5cdFx0fSxcblxuXHRcdHNldEFuaW1hdGlvbkxvb3A6IGZ1bmN0aW9uICggY2FsbGJhY2sgKSB7XG5cblx0XHRcdGFuaW1hdGlvbkxvb3AgPSBjYWxsYmFjaztcblxuXHRcdH0sXG5cblx0XHRzZXRDb250ZXh0OiBmdW5jdGlvbiAoIHZhbHVlICkge1xuXG5cdFx0XHRjb250ZXh0ID0gdmFsdWU7XG5cblx0XHR9XG5cblx0fTtcblxufVxuXG5mdW5jdGlvbiBXZWJHTEF0dHJpYnV0ZXMoIGdsICkge1xuXG5cdGNvbnN0IGJ1ZmZlcnMgPSBuZXcgV2Vha01hcCgpO1xuXG5cdGZ1bmN0aW9uIGNyZWF0ZUJ1ZmZlciggYXR0cmlidXRlLCBidWZmZXJUeXBlICkge1xuXG5cdFx0Y29uc3QgYXJyYXkgPSBhdHRyaWJ1dGUuYXJyYXk7XG5cdFx0Y29uc3QgdXNhZ2UgPSBhdHRyaWJ1dGUudXNhZ2U7XG5cdFx0Y29uc3Qgc2l6ZSA9IGFycmF5LmJ5dGVMZW5ndGg7XG5cblx0XHRjb25zdCBidWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcblxuXHRcdGdsLmJpbmRCdWZmZXIoIGJ1ZmZlclR5cGUsIGJ1ZmZlciApO1xuXHRcdGdsLmJ1ZmZlckRhdGEoIGJ1ZmZlclR5cGUsIGFycmF5LCB1c2FnZSApO1xuXG5cdFx0YXR0cmlidXRlLm9uVXBsb2FkQ2FsbGJhY2soKTtcblxuXHRcdGxldCB0eXBlO1xuXG5cdFx0aWYgKCBhcnJheSBpbnN0YW5jZW9mIEZsb2F0MzJBcnJheSApIHtcblxuXHRcdFx0dHlwZSA9IGdsLkZMT0FUO1xuXG5cdFx0fSBlbHNlIGlmICggYXJyYXkgaW5zdGFuY2VvZiBVaW50MTZBcnJheSApIHtcblxuXHRcdFx0aWYgKCBhdHRyaWJ1dGUuaXNGbG9hdDE2QnVmZmVyQXR0cmlidXRlICkge1xuXG5cdFx0XHRcdHR5cGUgPSBnbC5IQUxGX0ZMT0FUO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHR5cGUgPSBnbC5VTlNJR05FRF9TSE9SVDtcblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIGlmICggYXJyYXkgaW5zdGFuY2VvZiBJbnQxNkFycmF5ICkge1xuXG5cdFx0XHR0eXBlID0gZ2wuU0hPUlQ7XG5cblx0XHR9IGVsc2UgaWYgKCBhcnJheSBpbnN0YW5jZW9mIFVpbnQzMkFycmF5ICkge1xuXG5cdFx0XHR0eXBlID0gZ2wuVU5TSUdORURfSU5UO1xuXG5cdFx0fSBlbHNlIGlmICggYXJyYXkgaW5zdGFuY2VvZiBJbnQzMkFycmF5ICkge1xuXG5cdFx0XHR0eXBlID0gZ2wuSU5UO1xuXG5cdFx0fSBlbHNlIGlmICggYXJyYXkgaW5zdGFuY2VvZiBJbnQ4QXJyYXkgKSB7XG5cblx0XHRcdHR5cGUgPSBnbC5CWVRFO1xuXG5cdFx0fSBlbHNlIGlmICggYXJyYXkgaW5zdGFuY2VvZiBVaW50OEFycmF5ICkge1xuXG5cdFx0XHR0eXBlID0gZ2wuVU5TSUdORURfQllURTtcblxuXHRcdH0gZWxzZSBpZiAoIGFycmF5IGluc3RhbmNlb2YgVWludDhDbGFtcGVkQXJyYXkgKSB7XG5cblx0XHRcdHR5cGUgPSBnbC5VTlNJR05FRF9CWVRFO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuV2ViR0xBdHRyaWJ1dGVzOiBVbnN1cHBvcnRlZCBidWZmZXIgZGF0YSBmb3JtYXQ6ICcgKyBhcnJheSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHtcblx0XHRcdGJ1ZmZlcjogYnVmZmVyLFxuXHRcdFx0dHlwZTogdHlwZSxcblx0XHRcdGJ5dGVzUGVyRWxlbWVudDogYXJyYXkuQllURVNfUEVSX0VMRU1FTlQsXG5cdFx0XHR2ZXJzaW9uOiBhdHRyaWJ1dGUudmVyc2lvbixcblx0XHRcdHNpemU6IHNpemVcblx0XHR9O1xuXG5cdH1cblxuXHRmdW5jdGlvbiB1cGRhdGVCdWZmZXIoIGJ1ZmZlciwgYXR0cmlidXRlLCBidWZmZXJUeXBlICkge1xuXG5cdFx0Y29uc3QgYXJyYXkgPSBhdHRyaWJ1dGUuYXJyYXk7XG5cdFx0Y29uc3QgdXBkYXRlUmFuZ2UgPSBhdHRyaWJ1dGUuX3VwZGF0ZVJhbmdlOyAvLyBAZGVwcmVjYXRlZCwgcjE1OVxuXHRcdGNvbnN0IHVwZGF0ZVJhbmdlcyA9IGF0dHJpYnV0ZS51cGRhdGVSYW5nZXM7XG5cblx0XHRnbC5iaW5kQnVmZmVyKCBidWZmZXJUeXBlLCBidWZmZXIgKTtcblxuXHRcdGlmICggdXBkYXRlUmFuZ2UuY291bnQgPT09IC0gMSAmJiB1cGRhdGVSYW5nZXMubGVuZ3RoID09PSAwICkge1xuXG5cdFx0XHQvLyBOb3QgdXNpbmcgdXBkYXRlIHJhbmdlc1xuXHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggYnVmZmVyVHlwZSwgMCwgYXJyYXkgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdXBkYXRlUmFuZ2VzLmxlbmd0aCAhPT0gMCApIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdXBkYXRlUmFuZ2VzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgcmFuZ2UgPSB1cGRhdGVSYW5nZXNbIGkgXTtcblxuXHRcdFx0XHRnbC5idWZmZXJTdWJEYXRhKCBidWZmZXJUeXBlLCByYW5nZS5zdGFydCAqIGFycmF5LkJZVEVTX1BFUl9FTEVNRU5ULFxuXHRcdFx0XHRcdGFycmF5LCByYW5nZS5zdGFydCwgcmFuZ2UuY291bnQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRhdHRyaWJ1dGUuY2xlYXJVcGRhdGVSYW5nZXMoKTtcblxuXHRcdH1cblxuXHRcdC8vIEBkZXByZWNhdGVkLCByMTU5XG5cdFx0aWYgKCB1cGRhdGVSYW5nZS5jb3VudCAhPT0gLSAxICkge1xuXG5cdFx0XHRnbC5idWZmZXJTdWJEYXRhKCBidWZmZXJUeXBlLCB1cGRhdGVSYW5nZS5vZmZzZXQgKiBhcnJheS5CWVRFU19QRVJfRUxFTUVOVCxcblx0XHRcdFx0YXJyYXksIHVwZGF0ZVJhbmdlLm9mZnNldCwgdXBkYXRlUmFuZ2UuY291bnQgKTtcblxuXHRcdFx0dXBkYXRlUmFuZ2UuY291bnQgPSAtIDE7IC8vIHJlc2V0IHJhbmdlXG5cblx0XHR9XG5cblx0XHRhdHRyaWJ1dGUub25VcGxvYWRDYWxsYmFjaygpO1xuXG5cdH1cblxuXHQvL1xuXG5cdGZ1bmN0aW9uIGdldCggYXR0cmlidXRlICkge1xuXG5cdFx0aWYgKCBhdHRyaWJ1dGUuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSApIGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZS5kYXRhO1xuXG5cdFx0cmV0dXJuIGJ1ZmZlcnMuZ2V0KCBhdHRyaWJ1dGUgKTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVtb3ZlKCBhdHRyaWJ1dGUgKSB7XG5cblx0XHRpZiAoIGF0dHJpYnV0ZS5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlICkgYXR0cmlidXRlID0gYXR0cmlidXRlLmRhdGE7XG5cblx0XHRjb25zdCBkYXRhID0gYnVmZmVycy5nZXQoIGF0dHJpYnV0ZSApO1xuXG5cdFx0aWYgKCBkYXRhICkge1xuXG5cdFx0XHRnbC5kZWxldGVCdWZmZXIoIGRhdGEuYnVmZmVyICk7XG5cblx0XHRcdGJ1ZmZlcnMuZGVsZXRlKCBhdHRyaWJ1dGUgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gdXBkYXRlKCBhdHRyaWJ1dGUsIGJ1ZmZlclR5cGUgKSB7XG5cblx0XHRpZiAoIGF0dHJpYnV0ZS5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlICkgYXR0cmlidXRlID0gYXR0cmlidXRlLmRhdGE7XG5cblx0XHRpZiAoIGF0dHJpYnV0ZS5pc0dMQnVmZmVyQXR0cmlidXRlICkge1xuXG5cdFx0XHRjb25zdCBjYWNoZWQgPSBidWZmZXJzLmdldCggYXR0cmlidXRlICk7XG5cblx0XHRcdGlmICggISBjYWNoZWQgfHwgY2FjaGVkLnZlcnNpb24gPCBhdHRyaWJ1dGUudmVyc2lvbiApIHtcblxuXHRcdFx0XHRidWZmZXJzLnNldCggYXR0cmlidXRlLCB7XG5cdFx0XHRcdFx0YnVmZmVyOiBhdHRyaWJ1dGUuYnVmZmVyLFxuXHRcdFx0XHRcdHR5cGU6IGF0dHJpYnV0ZS50eXBlLFxuXHRcdFx0XHRcdGJ5dGVzUGVyRWxlbWVudDogYXR0cmlidXRlLmVsZW1lbnRTaXplLFxuXHRcdFx0XHRcdHZlcnNpb246IGF0dHJpYnV0ZS52ZXJzaW9uXG5cdFx0XHRcdH0gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHRjb25zdCBkYXRhID0gYnVmZmVycy5nZXQoIGF0dHJpYnV0ZSApO1xuXG5cdFx0aWYgKCBkYXRhID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGJ1ZmZlcnMuc2V0KCBhdHRyaWJ1dGUsIGNyZWF0ZUJ1ZmZlciggYXR0cmlidXRlLCBidWZmZXJUeXBlICkgKTtcblxuXHRcdH0gZWxzZSBpZiAoIGRhdGEudmVyc2lvbiA8IGF0dHJpYnV0ZS52ZXJzaW9uICkge1xuXG5cdFx0XHRpZiAoIGRhdGEuc2l6ZSAhPT0gYXR0cmlidXRlLmFycmF5LmJ5dGVMZW5ndGggKSB7XG5cblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuV2ViR0xBdHRyaWJ1dGVzOiBUaGUgc2l6ZSBvZiB0aGUgYnVmZmVyIGF0dHJpYnV0ZVxcJ3MgYXJyYXkgYnVmZmVyIGRvZXMgbm90IG1hdGNoIHRoZSBvcmlnaW5hbCBzaXplLiBSZXNpemluZyBidWZmZXIgYXR0cmlidXRlcyBpcyBub3Qgc3VwcG9ydGVkLicgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHR1cGRhdGVCdWZmZXIoIGRhdGEuYnVmZmVyLCBhdHRyaWJ1dGUsIGJ1ZmZlclR5cGUgKTtcblxuXHRcdFx0ZGF0YS52ZXJzaW9uID0gYXR0cmlidXRlLnZlcnNpb247XG5cblx0XHR9XG5cblx0fVxuXG5cdHJldHVybiB7XG5cblx0XHRnZXQ6IGdldCxcblx0XHRyZW1vdmU6IHJlbW92ZSxcblx0XHR1cGRhdGU6IHVwZGF0ZVxuXG5cdH07XG5cbn1cblxuY2xhc3MgUGxhbmVHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3Rvciggd2lkdGggPSAxLCBoZWlnaHQgPSAxLCB3aWR0aFNlZ21lbnRzID0gMSwgaGVpZ2h0U2VnbWVudHMgPSAxICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdQbGFuZUdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHdpZHRoOiB3aWR0aCxcblx0XHRcdGhlaWdodDogaGVpZ2h0LFxuXHRcdFx0d2lkdGhTZWdtZW50czogd2lkdGhTZWdtZW50cyxcblx0XHRcdGhlaWdodFNlZ21lbnRzOiBoZWlnaHRTZWdtZW50c1xuXHRcdH07XG5cblx0XHRjb25zdCB3aWR0aF9oYWxmID0gd2lkdGggLyAyO1xuXHRcdGNvbnN0IGhlaWdodF9oYWxmID0gaGVpZ2h0IC8gMjtcblxuXHRcdGNvbnN0IGdyaWRYID0gTWF0aC5mbG9vciggd2lkdGhTZWdtZW50cyApO1xuXHRcdGNvbnN0IGdyaWRZID0gTWF0aC5mbG9vciggaGVpZ2h0U2VnbWVudHMgKTtcblxuXHRcdGNvbnN0IGdyaWRYMSA9IGdyaWRYICsgMTtcblx0XHRjb25zdCBncmlkWTEgPSBncmlkWSArIDE7XG5cblx0XHRjb25zdCBzZWdtZW50X3dpZHRoID0gd2lkdGggLyBncmlkWDtcblx0XHRjb25zdCBzZWdtZW50X2hlaWdodCA9IGhlaWdodCAvIGdyaWRZO1xuXG5cdFx0Ly9cblxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcblx0XHRjb25zdCB1dnMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpeSA9IDA7IGl5IDwgZ3JpZFkxOyBpeSArKyApIHtcblxuXHRcdFx0Y29uc3QgeSA9IGl5ICogc2VnbWVudF9oZWlnaHQgLSBoZWlnaHRfaGFsZjtcblxuXHRcdFx0Zm9yICggbGV0IGl4ID0gMDsgaXggPCBncmlkWDE7IGl4ICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHggPSBpeCAqIHNlZ21lbnRfd2lkdGggLSB3aWR0aF9oYWxmO1xuXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHgsIC0geSwgMCApO1xuXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgMCwgMSApO1xuXG5cdFx0XHRcdHV2cy5wdXNoKCBpeCAvIGdyaWRYICk7XG5cdFx0XHRcdHV2cy5wdXNoKCAxIC0gKCBpeSAvIGdyaWRZICkgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Zm9yICggbGV0IGl5ID0gMDsgaXkgPCBncmlkWTsgaXkgKysgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpeCA9IDA7IGl4IDwgZ3JpZFg7IGl4ICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGEgPSBpeCArIGdyaWRYMSAqIGl5O1xuXHRcdFx0XHRjb25zdCBiID0gaXggKyBncmlkWDEgKiAoIGl5ICsgMSApO1xuXHRcdFx0XHRjb25zdCBjID0gKCBpeCArIDEgKSArIGdyaWRYMSAqICggaXkgKyAxICk7XG5cdFx0XHRcdGNvbnN0IGQgPSAoIGl4ICsgMSApICsgZ3JpZFgxICogaXk7XG5cblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBhLCBiLCBkICk7XG5cdFx0XHRcdGluZGljZXMucHVzaCggYiwgYywgZCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdHJldHVybiBuZXcgUGxhbmVHZW9tZXRyeSggZGF0YS53aWR0aCwgZGF0YS5oZWlnaHQsIGRhdGEud2lkdGhTZWdtZW50cywgZGF0YS5oZWlnaHRTZWdtZW50cyApO1xuXG5cdH1cblxufVxuXG52YXIgYWxwaGFoYXNoX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0FMUEhBSEFTSFxcblxcdGlmICggZGlmZnVzZUNvbG9yLmEgPCBnZXRBbHBoYUhhc2hUaHJlc2hvbGQoIHZQb3NpdGlvbiApICkgZGlzY2FyZDtcXG4jZW5kaWZcIjtcblxudmFyIGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0FMUEhBSEFTSFxcblxcdGNvbnN0IGZsb2F0IEFMUEhBX0hBU0hfU0NBTEUgPSAwLjA1O1xcblxcdGZsb2F0IGhhc2gyRCggdmVjMiB2YWx1ZSApIHtcXG5cXHRcXHRyZXR1cm4gZnJhY3QoIDEuMGU0ICogc2luKCAxNy4wICogdmFsdWUueCArIDAuMSAqIHZhbHVlLnkgKSAqICggMC4xICsgYWJzKCBzaW4oIDEzLjAgKiB2YWx1ZS55ICsgdmFsdWUueCApICkgKSApO1xcblxcdH1cXG5cXHRmbG9hdCBoYXNoM0QoIHZlYzMgdmFsdWUgKSB7XFxuXFx0XFx0cmV0dXJuIGhhc2gyRCggdmVjMiggaGFzaDJEKCB2YWx1ZS54eSApLCB2YWx1ZS56ICkgKTtcXG5cXHR9XFxuXFx0ZmxvYXQgZ2V0QWxwaGFIYXNoVGhyZXNob2xkKCB2ZWMzIHBvc2l0aW9uICkge1xcblxcdFxcdGZsb2F0IG1heERlcml2ID0gbWF4KFxcblxcdFxcdFxcdGxlbmd0aCggZEZkeCggcG9zaXRpb24ueHl6ICkgKSxcXG5cXHRcXHRcXHRsZW5ndGgoIGRGZHkoIHBvc2l0aW9uLnh5eiApIClcXG5cXHRcXHQpO1xcblxcdFxcdGZsb2F0IHBpeFNjYWxlID0gMS4wIC8gKCBBTFBIQV9IQVNIX1NDQUxFICogbWF4RGVyaXYgKTtcXG5cXHRcXHR2ZWMyIHBpeFNjYWxlcyA9IHZlYzIoXFxuXFx0XFx0XFx0ZXhwMiggZmxvb3IoIGxvZzIoIHBpeFNjYWxlICkgKSApLFxcblxcdFxcdFxcdGV4cDIoIGNlaWwoIGxvZzIoIHBpeFNjYWxlICkgKSApXFxuXFx0XFx0KTtcXG5cXHRcXHR2ZWMyIGFscGhhID0gdmVjMihcXG5cXHRcXHRcXHRoYXNoM0QoIGZsb29yKCBwaXhTY2FsZXMueCAqIHBvc2l0aW9uLnh5eiApICksXFxuXFx0XFx0XFx0aGFzaDNEKCBmbG9vciggcGl4U2NhbGVzLnkgKiBwb3NpdGlvbi54eXogKSApXFxuXFx0XFx0KTtcXG5cXHRcXHRmbG9hdCBsZXJwRmFjdG9yID0gZnJhY3QoIGxvZzIoIHBpeFNjYWxlICkgKTtcXG5cXHRcXHRmbG9hdCB4ID0gKCAxLjAgLSBsZXJwRmFjdG9yICkgKiBhbHBoYS54ICsgbGVycEZhY3RvciAqIGFscGhhLnk7XFxuXFx0XFx0ZmxvYXQgYSA9IG1pbiggbGVycEZhY3RvciwgMS4wIC0gbGVycEZhY3RvciApO1xcblxcdFxcdHZlYzMgY2FzZXMgPSB2ZWMzKFxcblxcdFxcdFxcdHggKiB4IC8gKCAyLjAgKiBhICogKCAxLjAgLSBhICkgKSxcXG5cXHRcXHRcXHQoIHggLSAwLjUgKiBhICkgLyAoIDEuMCAtIGEgKSxcXG5cXHRcXHRcXHQxLjAgLSAoICggMS4wIC0geCApICogKCAxLjAgLSB4ICkgLyAoIDIuMCAqIGEgKiAoIDEuMCAtIGEgKSApIClcXG5cXHRcXHQpO1xcblxcdFxcdGZsb2F0IHRocmVzaG9sZCA9ICggeCA8ICggMS4wIC0gYSApIClcXG5cXHRcXHRcXHQ/ICggKCB4IDwgYSApID8gY2FzZXMueCA6IGNhc2VzLnkgKVxcblxcdFxcdFxcdDogY2FzZXMuejtcXG5cXHRcXHRyZXR1cm4gY2xhbXAoIHRocmVzaG9sZCAsIDEuMGUtNiwgMS4wICk7XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgYWxwaGFtYXBfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfQUxQSEFNQVBcXG5cXHRkaWZmdXNlQ29sb3IuYSAqPSB0ZXh0dXJlMkQoIGFscGhhTWFwLCB2QWxwaGFNYXBVdiApLmc7XFxuI2VuZGlmXCI7XG5cbnZhciBhbHBoYW1hcF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0FMUEhBTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgYWxwaGFNYXA7XFxuI2VuZGlmXCI7XG5cbnZhciBhbHBoYXRlc3RfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfQUxQSEFURVNUXFxuXFx0I2lmZGVmIEFMUEhBX1RPX0NPVkVSQUdFXFxuXFx0ZGlmZnVzZUNvbG9yLmEgPSBzbW9vdGhzdGVwKCBhbHBoYVRlc3QsIGFscGhhVGVzdCArIGZ3aWR0aCggZGlmZnVzZUNvbG9yLmEgKSwgZGlmZnVzZUNvbG9yLmEgKTtcXG5cXHRpZiAoIGRpZmZ1c2VDb2xvci5hID09IDAuMCApIGRpc2NhcmQ7XFxuXFx0I2Vsc2VcXG5cXHRpZiAoIGRpZmZ1c2VDb2xvci5hIDwgYWxwaGFUZXN0ICkgZGlzY2FyZDtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcIjtcblxudmFyIGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0FMUEhBVEVTVFxcblxcdHVuaWZvcm0gZmxvYXQgYWxwaGFUZXN0O1xcbiNlbmRpZlwiO1xuXG52YXIgYW9tYXBfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfQU9NQVBcXG5cXHRmbG9hdCBhbWJpZW50T2NjbHVzaW9uID0gKCB0ZXh0dXJlMkQoIGFvTWFwLCB2QW9NYXBVdiApLnIgLSAxLjAgKSAqIGFvTWFwSW50ZW5zaXR5ICsgMS4wO1xcblxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSAqPSBhbWJpZW50T2NjbHVzaW9uO1xcblxcdCNpZiBkZWZpbmVkKCBVU0VfQ0xFQVJDT0FUICkgXFxuXFx0XFx0Y2xlYXJjb2F0U3BlY3VsYXJJbmRpcmVjdCAqPSBhbWJpZW50T2NjbHVzaW9uO1xcblxcdCNlbmRpZlxcblxcdCNpZiBkZWZpbmVkKCBVU0VfU0hFRU4gKSBcXG5cXHRcXHRzaGVlblNwZWN1bGFySW5kaXJlY3QgKj0gYW1iaWVudE9jY2x1c2lvbjtcXG5cXHQjZW5kaWZcXG5cXHQjaWYgZGVmaW5lZCggVVNFX0VOVk1BUCApICYmIGRlZmluZWQoIFNUQU5EQVJEIClcXG5cXHRcXHRmbG9hdCBkb3ROViA9IHNhdHVyYXRlKCBkb3QoIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIgKSApO1xcblxcdFxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0U3BlY3VsYXIgKj0gY29tcHV0ZVNwZWN1bGFyT2NjbHVzaW9uKCBkb3ROViwgYW1iaWVudE9jY2x1c2lvbiwgbWF0ZXJpYWwucm91Z2huZXNzICk7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXCI7XG5cbnZhciBhb21hcF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0FPTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgYW9NYXA7XFxuXFx0dW5pZm9ybSBmbG9hdCBhb01hcEludGVuc2l0eTtcXG4jZW5kaWZcIjtcblxudmFyIGJhdGNoaW5nX3BhcnNfdmVydGV4ID0gXCIjaWZkZWYgVVNFX0JBVENISU5HXFxuXFx0I2lmICEgZGVmaW5lZCggR0xfQU5HTEVfbXVsdGlfZHJhdyApXFxuXFx0I2RlZmluZSBnbF9EcmF3SUQgX2dsX0RyYXdJRFxcblxcdHVuaWZvcm0gaW50IF9nbF9EcmF3SUQ7XFxuXFx0I2VuZGlmXFxuXFx0dW5pZm9ybSBoaWdocCBzYW1wbGVyMkQgYmF0Y2hpbmdUZXh0dXJlO1xcblxcdHVuaWZvcm0gaGlnaHAgdXNhbXBsZXIyRCBiYXRjaGluZ0lkVGV4dHVyZTtcXG5cXHRtYXQ0IGdldEJhdGNoaW5nTWF0cml4KCBjb25zdCBpbiBmbG9hdCBpICkge1xcblxcdFxcdGludCBzaXplID0gdGV4dHVyZVNpemUoIGJhdGNoaW5nVGV4dHVyZSwgMCApLng7XFxuXFx0XFx0aW50IGogPSBpbnQoIGkgKSAqIDQ7XFxuXFx0XFx0aW50IHggPSBqICUgc2l6ZTtcXG5cXHRcXHRpbnQgeSA9IGogLyBzaXplO1xcblxcdFxcdHZlYzQgdjEgPSB0ZXhlbEZldGNoKCBiYXRjaGluZ1RleHR1cmUsIGl2ZWMyKCB4LCB5ICksIDAgKTtcXG5cXHRcXHR2ZWM0IHYyID0gdGV4ZWxGZXRjaCggYmF0Y2hpbmdUZXh0dXJlLCBpdmVjMiggeCArIDEsIHkgKSwgMCApO1xcblxcdFxcdHZlYzQgdjMgPSB0ZXhlbEZldGNoKCBiYXRjaGluZ1RleHR1cmUsIGl2ZWMyKCB4ICsgMiwgeSApLCAwICk7XFxuXFx0XFx0dmVjNCB2NCA9IHRleGVsRmV0Y2goIGJhdGNoaW5nVGV4dHVyZSwgaXZlYzIoIHggKyAzLCB5ICksIDAgKTtcXG5cXHRcXHRyZXR1cm4gbWF0NCggdjEsIHYyLCB2MywgdjQgKTtcXG5cXHR9XFxuXFx0ZmxvYXQgZ2V0SW5kaXJlY3RJbmRleCggY29uc3QgaW4gaW50IGkgKSB7XFxuXFx0XFx0aW50IHNpemUgPSB0ZXh0dXJlU2l6ZSggYmF0Y2hpbmdJZFRleHR1cmUsIDAgKS54O1xcblxcdFxcdGludCB4ID0gaSAlIHNpemU7XFxuXFx0XFx0aW50IHkgPSBpIC8gc2l6ZTtcXG5cXHRcXHRyZXR1cm4gZmxvYXQoIHRleGVsRmV0Y2goIGJhdGNoaW5nSWRUZXh0dXJlLCBpdmVjMiggeCwgeSApLCAwICkuciApO1xcblxcdH1cXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0JBVENISU5HX0NPTE9SXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgYmF0Y2hpbmdDb2xvclRleHR1cmU7XFxuXFx0dmVjMyBnZXRCYXRjaGluZ0NvbG9yKCBjb25zdCBpbiBmbG9hdCBpICkge1xcblxcdFxcdGludCBzaXplID0gdGV4dHVyZVNpemUoIGJhdGNoaW5nQ29sb3JUZXh0dXJlLCAwICkueDtcXG5cXHRcXHRpbnQgaiA9IGludCggaSApO1xcblxcdFxcdGludCB4ID0gaiAlIHNpemU7XFxuXFx0XFx0aW50IHkgPSBqIC8gc2l6ZTtcXG5cXHRcXHRyZXR1cm4gdGV4ZWxGZXRjaCggYmF0Y2hpbmdDb2xvclRleHR1cmUsIGl2ZWMyKCB4LCB5ICksIDAgKS5yZ2I7XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgYmF0Y2hpbmdfdmVydGV4ID0gXCIjaWZkZWYgVVNFX0JBVENISU5HXFxuXFx0bWF0NCBiYXRjaGluZ01hdHJpeCA9IGdldEJhdGNoaW5nTWF0cml4KCBnZXRJbmRpcmVjdEluZGV4KCBnbF9EcmF3SUQgKSApO1xcbiNlbmRpZlwiO1xuXG52YXIgYmVnaW5fdmVydGV4ID0gXCJ2ZWMzIHRyYW5zZm9ybWVkID0gdmVjMyggcG9zaXRpb24gKTtcXG4jaWZkZWYgVVNFX0FMUEhBSEFTSFxcblxcdHZQb3NpdGlvbiA9IHZlYzMoIHBvc2l0aW9uICk7XFxuI2VuZGlmXCI7XG5cbnZhciBiZWdpbm5vcm1hbF92ZXJ0ZXggPSBcInZlYzMgb2JqZWN0Tm9ybWFsID0gdmVjMyggbm9ybWFsICk7XFxuI2lmZGVmIFVTRV9UQU5HRU5UXFxuXFx0dmVjMyBvYmplY3RUYW5nZW50ID0gdmVjMyggdGFuZ2VudC54eXogKTtcXG4jZW5kaWZcIjtcblxudmFyIGJzZGZzID0gXCJmbG9hdCBHX0JsaW5uUGhvbmdfSW1wbGljaXQoICkge1xcblxcdHJldHVybiAwLjI1O1xcbn1cXG5mbG9hdCBEX0JsaW5uUGhvbmcoIGNvbnN0IGluIGZsb2F0IHNoaW5pbmVzcywgY29uc3QgaW4gZmxvYXQgZG90TkggKSB7XFxuXFx0cmV0dXJuIFJFQ0lQUk9DQUxfUEkgKiAoIHNoaW5pbmVzcyAqIDAuNSArIDEuMCApICogcG93KCBkb3ROSCwgc2hpbmluZXNzICk7XFxufVxcbnZlYzMgQlJERl9CbGlublBob25nKCBjb25zdCBpbiB2ZWMzIGxpZ2h0RGlyLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiB2ZWMzIHNwZWN1bGFyQ29sb3IsIGNvbnN0IGluIGZsb2F0IHNoaW5pbmVzcyApIHtcXG5cXHR2ZWMzIGhhbGZEaXIgPSBub3JtYWxpemUoIGxpZ2h0RGlyICsgdmlld0RpciApO1xcblxcdGZsb2F0IGRvdE5IID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCBoYWxmRGlyICkgKTtcXG5cXHRmbG9hdCBkb3RWSCA9IHNhdHVyYXRlKCBkb3QoIHZpZXdEaXIsIGhhbGZEaXIgKSApO1xcblxcdHZlYzMgRiA9IEZfU2NobGljayggc3BlY3VsYXJDb2xvciwgMS4wLCBkb3RWSCApO1xcblxcdGZsb2F0IEcgPSBHX0JsaW5uUGhvbmdfSW1wbGljaXQoICk7XFxuXFx0ZmxvYXQgRCA9IERfQmxpbm5QaG9uZyggc2hpbmluZXNzLCBkb3ROSCApO1xcblxcdHJldHVybiBGICogKCBHICogRCApO1xcbn0gLy8gdmFsaWRhdGVkXCI7XG5cbnZhciBpcmlkZXNjZW5jZV9mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9JUklERVNDRU5DRVxcblxcdGNvbnN0IG1hdDMgWFlaX1RPX1JFQzcwOSA9IG1hdDMoXFxuXFx0XFx0IDMuMjQwNDU0MiwgLTAuOTY5MjY2MCwgIDAuMDU1NjQzNCxcXG5cXHRcXHQtMS41MzcxMzg1LCAgMS44NzYwMTA4LCAtMC4yMDQwMjU5LFxcblxcdFxcdC0wLjQ5ODUzMTQsICAwLjA0MTU1NjAsICAxLjA1NzIyNTJcXG5cXHQpO1xcblxcdHZlYzMgRnJlc25lbDBUb0lvciggdmVjMyBmcmVzbmVsMCApIHtcXG5cXHRcXHR2ZWMzIHNxcnRGMCA9IHNxcnQoIGZyZXNuZWwwICk7XFxuXFx0XFx0cmV0dXJuICggdmVjMyggMS4wICkgKyBzcXJ0RjAgKSAvICggdmVjMyggMS4wICkgLSBzcXJ0RjAgKTtcXG5cXHR9XFxuXFx0dmVjMyBJb3JUb0ZyZXNuZWwwKCB2ZWMzIHRyYW5zbWl0dGVkSW9yLCBmbG9hdCBpbmNpZGVudElvciApIHtcXG5cXHRcXHRyZXR1cm4gcG93MiggKCB0cmFuc21pdHRlZElvciAtIHZlYzMoIGluY2lkZW50SW9yICkgKSAvICggdHJhbnNtaXR0ZWRJb3IgKyB2ZWMzKCBpbmNpZGVudElvciApICkgKTtcXG5cXHR9XFxuXFx0ZmxvYXQgSW9yVG9GcmVzbmVsMCggZmxvYXQgdHJhbnNtaXR0ZWRJb3IsIGZsb2F0IGluY2lkZW50SW9yICkge1xcblxcdFxcdHJldHVybiBwb3cyKCAoIHRyYW5zbWl0dGVkSW9yIC0gaW5jaWRlbnRJb3IgKSAvICggdHJhbnNtaXR0ZWRJb3IgKyBpbmNpZGVudElvciApKTtcXG5cXHR9XFxuXFx0dmVjMyBldmFsU2Vuc2l0aXZpdHkoIGZsb2F0IE9QRCwgdmVjMyBzaGlmdCApIHtcXG5cXHRcXHRmbG9hdCBwaGFzZSA9IDIuMCAqIFBJICogT1BEICogMS4wZS05O1xcblxcdFxcdHZlYzMgdmFsID0gdmVjMyggNS40ODU2ZS0xMywgNC40MjAxZS0xMywgNS4yNDgxZS0xMyApO1xcblxcdFxcdHZlYzMgcG9zID0gdmVjMyggMS42ODEwZSswNiwgMS43OTUzZSswNiwgMi4yMDg0ZSswNiApO1xcblxcdFxcdHZlYzMgdmFyID0gdmVjMyggNC4zMjc4ZSswOSwgOS4zMDQ2ZSswOSwgNi42MTIxZSswOSApO1xcblxcdFxcdHZlYzMgeHl6ID0gdmFsICogc3FydCggMi4wICogUEkgKiB2YXIgKSAqIGNvcyggcG9zICogcGhhc2UgKyBzaGlmdCApICogZXhwKCAtIHBvdzIoIHBoYXNlICkgKiB2YXIgKTtcXG5cXHRcXHR4eXoueCArPSA5Ljc0NzBlLTE0ICogc3FydCggMi4wICogUEkgKiA0LjUyODJlKzA5ICkgKiBjb3MoIDIuMjM5OWUrMDYgKiBwaGFzZSArIHNoaWZ0WyAwIF0gKSAqIGV4cCggLSA0LjUyODJlKzA5ICogcG93MiggcGhhc2UgKSApO1xcblxcdFxcdHh5eiAvPSAxLjA2ODVlLTc7XFxuXFx0XFx0dmVjMyByZ2IgPSBYWVpfVE9fUkVDNzA5ICogeHl6O1xcblxcdFxcdHJldHVybiByZ2I7XFxuXFx0fVxcblxcdHZlYzMgZXZhbElyaWRlc2NlbmNlKCBmbG9hdCBvdXRzaWRlSU9SLCBmbG9hdCBldGEyLCBmbG9hdCBjb3NUaGV0YTEsIGZsb2F0IHRoaW5GaWxtVGhpY2tuZXNzLCB2ZWMzIGJhc2VGMCApIHtcXG5cXHRcXHR2ZWMzIEk7XFxuXFx0XFx0ZmxvYXQgaXJpZGVzY2VuY2VJT1IgPSBtaXgoIG91dHNpZGVJT1IsIGV0YTIsIHNtb290aHN0ZXAoIDAuMCwgMC4wMywgdGhpbkZpbG1UaGlja25lc3MgKSApO1xcblxcdFxcdGZsb2F0IHNpblRoZXRhMlNxID0gcG93Miggb3V0c2lkZUlPUiAvIGlyaWRlc2NlbmNlSU9SICkgKiAoIDEuMCAtIHBvdzIoIGNvc1RoZXRhMSApICk7XFxuXFx0XFx0ZmxvYXQgY29zVGhldGEyU3EgPSAxLjAgLSBzaW5UaGV0YTJTcTtcXG5cXHRcXHRpZiAoIGNvc1RoZXRhMlNxIDwgMC4wICkge1xcblxcdFxcdFxcdHJldHVybiB2ZWMzKCAxLjAgKTtcXG5cXHRcXHR9XFxuXFx0XFx0ZmxvYXQgY29zVGhldGEyID0gc3FydCggY29zVGhldGEyU3EgKTtcXG5cXHRcXHRmbG9hdCBSMCA9IElvclRvRnJlc25lbDAoIGlyaWRlc2NlbmNlSU9SLCBvdXRzaWRlSU9SICk7XFxuXFx0XFx0ZmxvYXQgUjEyID0gRl9TY2hsaWNrKCBSMCwgMS4wLCBjb3NUaGV0YTEgKTtcXG5cXHRcXHRmbG9hdCBUMTIxID0gMS4wIC0gUjEyO1xcblxcdFxcdGZsb2F0IHBoaTEyID0gMC4wO1xcblxcdFxcdGlmICggaXJpZGVzY2VuY2VJT1IgPCBvdXRzaWRlSU9SICkgcGhpMTIgPSBQSTtcXG5cXHRcXHRmbG9hdCBwaGkyMSA9IFBJIC0gcGhpMTI7XFxuXFx0XFx0dmVjMyBiYXNlSU9SID0gRnJlc25lbDBUb0lvciggY2xhbXAoIGJhc2VGMCwgMC4wLCAwLjk5OTkgKSApO1xcdFxcdHZlYzMgUjEgPSBJb3JUb0ZyZXNuZWwwKCBiYXNlSU9SLCBpcmlkZXNjZW5jZUlPUiApO1xcblxcdFxcdHZlYzMgUjIzID0gRl9TY2hsaWNrKCBSMSwgMS4wLCBjb3NUaGV0YTIgKTtcXG5cXHRcXHR2ZWMzIHBoaTIzID0gdmVjMyggMC4wICk7XFxuXFx0XFx0aWYgKCBiYXNlSU9SWyAwIF0gPCBpcmlkZXNjZW5jZUlPUiApIHBoaTIzWyAwIF0gPSBQSTtcXG5cXHRcXHRpZiAoIGJhc2VJT1JbIDEgXSA8IGlyaWRlc2NlbmNlSU9SICkgcGhpMjNbIDEgXSA9IFBJO1xcblxcdFxcdGlmICggYmFzZUlPUlsgMiBdIDwgaXJpZGVzY2VuY2VJT1IgKSBwaGkyM1sgMiBdID0gUEk7XFxuXFx0XFx0ZmxvYXQgT1BEID0gMi4wICogaXJpZGVzY2VuY2VJT1IgKiB0aGluRmlsbVRoaWNrbmVzcyAqIGNvc1RoZXRhMjtcXG5cXHRcXHR2ZWMzIHBoaSA9IHZlYzMoIHBoaTIxICkgKyBwaGkyMztcXG5cXHRcXHR2ZWMzIFIxMjMgPSBjbGFtcCggUjEyICogUjIzLCAxZS01LCAwLjk5OTkgKTtcXG5cXHRcXHR2ZWMzIHIxMjMgPSBzcXJ0KCBSMTIzICk7XFxuXFx0XFx0dmVjMyBScyA9IHBvdzIoIFQxMjEgKSAqIFIyMyAvICggdmVjMyggMS4wICkgLSBSMTIzICk7XFxuXFx0XFx0dmVjMyBDMCA9IFIxMiArIFJzO1xcblxcdFxcdEkgPSBDMDtcXG5cXHRcXHR2ZWMzIENtID0gUnMgLSBUMTIxO1xcblxcdFxcdGZvciAoIGludCBtID0gMTsgbSA8PSAyOyArKyBtICkge1xcblxcdFxcdFxcdENtICo9IHIxMjM7XFxuXFx0XFx0XFx0dmVjMyBTbSA9IDIuMCAqIGV2YWxTZW5zaXRpdml0eSggZmxvYXQoIG0gKSAqIE9QRCwgZmxvYXQoIG0gKSAqIHBoaSApO1xcblxcdFxcdFxcdEkgKz0gQ20gKiBTbTtcXG5cXHRcXHR9XFxuXFx0XFx0cmV0dXJuIG1heCggSSwgdmVjMyggMC4wICkgKTtcXG5cXHR9XFxuI2VuZGlmXCI7XG5cbnZhciBidW1wbWFwX3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfQlVNUE1BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGJ1bXBNYXA7XFxuXFx0dW5pZm9ybSBmbG9hdCBidW1wU2NhbGU7XFxuXFx0dmVjMiBkSGR4eV9md2QoKSB7XFxuXFx0XFx0dmVjMiBkU1RkeCA9IGRGZHgoIHZCdW1wTWFwVXYgKTtcXG5cXHRcXHR2ZWMyIGRTVGR5ID0gZEZkeSggdkJ1bXBNYXBVdiApO1xcblxcdFxcdGZsb2F0IEhsbCA9IGJ1bXBTY2FsZSAqIHRleHR1cmUyRCggYnVtcE1hcCwgdkJ1bXBNYXBVdiApLng7XFxuXFx0XFx0ZmxvYXQgZEJ4ID0gYnVtcFNjYWxlICogdGV4dHVyZTJEKCBidW1wTWFwLCB2QnVtcE1hcFV2ICsgZFNUZHggKS54IC0gSGxsO1xcblxcdFxcdGZsb2F0IGRCeSA9IGJ1bXBTY2FsZSAqIHRleHR1cmUyRCggYnVtcE1hcCwgdkJ1bXBNYXBVdiArIGRTVGR5ICkueCAtIEhsbDtcXG5cXHRcXHRyZXR1cm4gdmVjMiggZEJ4LCBkQnkgKTtcXG5cXHR9XFxuXFx0dmVjMyBwZXJ0dXJiTm9ybWFsQXJiKCB2ZWMzIHN1cmZfcG9zLCB2ZWMzIHN1cmZfbm9ybSwgdmVjMiBkSGR4eSwgZmxvYXQgZmFjZURpcmVjdGlvbiApIHtcXG5cXHRcXHR2ZWMzIHZTaWdtYVggPSBub3JtYWxpemUoIGRGZHgoIHN1cmZfcG9zLnh5eiApICk7XFxuXFx0XFx0dmVjMyB2U2lnbWFZID0gbm9ybWFsaXplKCBkRmR5KCBzdXJmX3Bvcy54eXogKSApO1xcblxcdFxcdHZlYzMgdk4gPSBzdXJmX25vcm07XFxuXFx0XFx0dmVjMyBSMSA9IGNyb3NzKCB2U2lnbWFZLCB2TiApO1xcblxcdFxcdHZlYzMgUjIgPSBjcm9zcyggdk4sIHZTaWdtYVggKTtcXG5cXHRcXHRmbG9hdCBmRGV0ID0gZG90KCB2U2lnbWFYLCBSMSApICogZmFjZURpcmVjdGlvbjtcXG5cXHRcXHR2ZWMzIHZHcmFkID0gc2lnbiggZkRldCApICogKCBkSGR4eS54ICogUjEgKyBkSGR4eS55ICogUjIgKTtcXG5cXHRcXHRyZXR1cm4gbm9ybWFsaXplKCBhYnMoIGZEZXQgKSAqIHN1cmZfbm9ybSAtIHZHcmFkICk7XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgY2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50ID0gXCIjaWYgTlVNX0NMSVBQSU5HX1BMQU5FUyA+IDBcXG5cXHR2ZWM0IHBsYW5lO1xcblxcdCNpZmRlZiBBTFBIQV9UT19DT1ZFUkFHRVxcblxcdFxcdGZsb2F0IGRpc3RhbmNlVG9QbGFuZSwgZGlzdGFuY2VHcmFkaWVudDtcXG5cXHRcXHRmbG9hdCBjbGlwT3BhY2l0eSA9IDEuMDtcXG5cXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XFxuXFx0XFx0Zm9yICggaW50IGkgPSAwOyBpIDwgVU5JT05fQ0xJUFBJTkdfUExBTkVTOyBpICsrICkge1xcblxcdFxcdFxcdHBsYW5lID0gY2xpcHBpbmdQbGFuZXNbIGkgXTtcXG5cXHRcXHRcXHRkaXN0YW5jZVRvUGxhbmUgPSAtIGRvdCggdkNsaXBQb3NpdGlvbiwgcGxhbmUueHl6ICkgKyBwbGFuZS53O1xcblxcdFxcdFxcdGRpc3RhbmNlR3JhZGllbnQgPSBmd2lkdGgoIGRpc3RhbmNlVG9QbGFuZSApIC8gMi4wO1xcblxcdFxcdFxcdGNsaXBPcGFjaXR5ICo9IHNtb290aHN0ZXAoIC0gZGlzdGFuY2VHcmFkaWVudCwgZGlzdGFuY2VHcmFkaWVudCwgZGlzdGFuY2VUb1BsYW5lICk7XFxuXFx0XFx0XFx0aWYgKCBjbGlwT3BhY2l0eSA9PSAwLjAgKSBkaXNjYXJkO1xcblxcdFxcdH1cXG5cXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxcblxcdFxcdCNpZiBVTklPTl9DTElQUElOR19QTEFORVMgPCBOVU1fQ0xJUFBJTkdfUExBTkVTXFxuXFx0XFx0XFx0ZmxvYXQgdW5pb25DbGlwT3BhY2l0eSA9IDEuMDtcXG5cXHRcXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XFxuXFx0XFx0XFx0Zm9yICggaW50IGkgPSBVTklPTl9DTElQUElOR19QTEFORVM7IGkgPCBOVU1fQ0xJUFBJTkdfUExBTkVTOyBpICsrICkge1xcblxcdFxcdFxcdFxcdHBsYW5lID0gY2xpcHBpbmdQbGFuZXNbIGkgXTtcXG5cXHRcXHRcXHRcXHRkaXN0YW5jZVRvUGxhbmUgPSAtIGRvdCggdkNsaXBQb3NpdGlvbiwgcGxhbmUueHl6ICkgKyBwbGFuZS53O1xcblxcdFxcdFxcdFxcdGRpc3RhbmNlR3JhZGllbnQgPSBmd2lkdGgoIGRpc3RhbmNlVG9QbGFuZSApIC8gMi4wO1xcblxcdFxcdFxcdFxcdHVuaW9uQ2xpcE9wYWNpdHkgKj0gMS4wIC0gc21vb3Roc3RlcCggLSBkaXN0YW5jZUdyYWRpZW50LCBkaXN0YW5jZUdyYWRpZW50LCBkaXN0YW5jZVRvUGxhbmUgKTtcXG5cXHRcXHRcXHR9XFxuXFx0XFx0XFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcXG5cXHRcXHRcXHRjbGlwT3BhY2l0eSAqPSAxLjAgLSB1bmlvbkNsaXBPcGFjaXR5O1xcblxcdFxcdCNlbmRpZlxcblxcdFxcdGRpZmZ1c2VDb2xvci5hICo9IGNsaXBPcGFjaXR5O1xcblxcdFxcdGlmICggZGlmZnVzZUNvbG9yLmEgPT0gMC4wICkgZGlzY2FyZDtcXG5cXHQjZWxzZVxcblxcdFxcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcXG5cXHRcXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBVTklPTl9DTElQUElOR19QTEFORVM7IGkgKysgKSB7XFxuXFx0XFx0XFx0cGxhbmUgPSBjbGlwcGluZ1BsYW5lc1sgaSBdO1xcblxcdFxcdFxcdGlmICggZG90KCB2Q2xpcFBvc2l0aW9uLCBwbGFuZS54eXogKSA+IHBsYW5lLncgKSBkaXNjYXJkO1xcblxcdFxcdH1cXG5cXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxcblxcdFxcdCNpZiBVTklPTl9DTElQUElOR19QTEFORVMgPCBOVU1fQ0xJUFBJTkdfUExBTkVTXFxuXFx0XFx0XFx0Ym9vbCBjbGlwcGVkID0gdHJ1ZTtcXG5cXHRcXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XFxuXFx0XFx0XFx0Zm9yICggaW50IGkgPSBVTklPTl9DTElQUElOR19QTEFORVM7IGkgPCBOVU1fQ0xJUFBJTkdfUExBTkVTOyBpICsrICkge1xcblxcdFxcdFxcdFxcdHBsYW5lID0gY2xpcHBpbmdQbGFuZXNbIGkgXTtcXG5cXHRcXHRcXHRcXHRjbGlwcGVkID0gKCBkb3QoIHZDbGlwUG9zaXRpb24sIHBsYW5lLnh5eiApID4gcGxhbmUudyApICYmIGNsaXBwZWQ7XFxuXFx0XFx0XFx0fVxcblxcdFxcdFxcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXFxuXFx0XFx0XFx0aWYgKCBjbGlwcGVkICkgZGlzY2FyZDtcXG5cXHRcXHQjZW5kaWZcXG5cXHQjZW5kaWZcXG4jZW5kaWZcIjtcblxudmFyIGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50ID0gXCIjaWYgTlVNX0NMSVBQSU5HX1BMQU5FUyA+IDBcXG5cXHR2YXJ5aW5nIHZlYzMgdkNsaXBQb3NpdGlvbjtcXG5cXHR1bmlmb3JtIHZlYzQgY2xpcHBpbmdQbGFuZXNbIE5VTV9DTElQUElOR19QTEFORVMgXTtcXG4jZW5kaWZcIjtcblxudmFyIGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleCA9IFwiI2lmIE5VTV9DTElQUElOR19QTEFORVMgPiAwXFxuXFx0dmFyeWluZyB2ZWMzIHZDbGlwUG9zaXRpb247XFxuI2VuZGlmXCI7XG5cbnZhciBjbGlwcGluZ19wbGFuZXNfdmVydGV4ID0gXCIjaWYgTlVNX0NMSVBQSU5HX1BMQU5FUyA+IDBcXG5cXHR2Q2xpcFBvc2l0aW9uID0gLSBtdlBvc2l0aW9uLnh5ejtcXG4jZW5kaWZcIjtcblxudmFyIGNvbG9yX2ZyYWdtZW50ID0gXCIjaWYgZGVmaW5lZCggVVNFX0NPTE9SX0FMUEhBIClcXG5cXHRkaWZmdXNlQ29sb3IgKj0gdkNvbG9yO1xcbiNlbGlmIGRlZmluZWQoIFVTRV9DT0xPUiApXFxuXFx0ZGlmZnVzZUNvbG9yLnJnYiAqPSB2Q29sb3I7XFxuI2VuZGlmXCI7XG5cbnZhciBjb2xvcl9wYXJzX2ZyYWdtZW50ID0gXCIjaWYgZGVmaW5lZCggVVNFX0NPTE9SX0FMUEhBIClcXG5cXHR2YXJ5aW5nIHZlYzQgdkNvbG9yO1xcbiNlbGlmIGRlZmluZWQoIFVTRV9DT0xPUiApXFxuXFx0dmFyeWluZyB2ZWMzIHZDb2xvcjtcXG4jZW5kaWZcIjtcblxudmFyIGNvbG9yX3BhcnNfdmVydGV4ID0gXCIjaWYgZGVmaW5lZCggVVNFX0NPTE9SX0FMUEhBIClcXG5cXHR2YXJ5aW5nIHZlYzQgdkNvbG9yO1xcbiNlbGlmIGRlZmluZWQoIFVTRV9DT0xPUiApIHx8IGRlZmluZWQoIFVTRV9JTlNUQU5DSU5HX0NPTE9SICkgfHwgZGVmaW5lZCggVVNFX0JBVENISU5HX0NPTE9SIClcXG5cXHR2YXJ5aW5nIHZlYzMgdkNvbG9yO1xcbiNlbmRpZlwiO1xuXG52YXIgY29sb3JfdmVydGV4ID0gXCIjaWYgZGVmaW5lZCggVVNFX0NPTE9SX0FMUEhBIClcXG5cXHR2Q29sb3IgPSB2ZWM0KCAxLjAgKTtcXG4jZWxpZiBkZWZpbmVkKCBVU0VfQ09MT1IgKSB8fCBkZWZpbmVkKCBVU0VfSU5TVEFOQ0lOR19DT0xPUiApIHx8IGRlZmluZWQoIFVTRV9CQVRDSElOR19DT0xPUiApXFxuXFx0dkNvbG9yID0gdmVjMyggMS4wICk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DT0xPUlxcblxcdHZDb2xvciAqPSBjb2xvcjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0lOU1RBTkNJTkdfQ09MT1JcXG5cXHR2Q29sb3IueHl6ICo9IGluc3RhbmNlQ29sb3IueHl6O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQkFUQ0hJTkdfQ09MT1JcXG5cXHR2ZWMzIGJhdGNoaW5nQ29sb3IgPSBnZXRCYXRjaGluZ0NvbG9yKCBnZXRJbmRpcmVjdEluZGV4KCBnbF9EcmF3SUQgKSApO1xcblxcdHZDb2xvci54eXogKj0gYmF0Y2hpbmdDb2xvci54eXo7XFxuI2VuZGlmXCI7XG5cbnZhciBjb21tb24gPSBcIiNkZWZpbmUgUEkgMy4xNDE1OTI2NTM1ODk3OTNcXG4jZGVmaW5lIFBJMiA2LjI4MzE4NTMwNzE3OTU4NlxcbiNkZWZpbmUgUElfSEFMRiAxLjU3MDc5NjMyNjc5NDg5NjZcXG4jZGVmaW5lIFJFQ0lQUk9DQUxfUEkgMC4zMTgzMDk4ODYxODM3OTA3XFxuI2RlZmluZSBSRUNJUFJPQ0FMX1BJMiAwLjE1OTE1NDk0MzA5MTg5NTM1XFxuI2RlZmluZSBFUFNJTE9OIDFlLTZcXG4jaWZuZGVmIHNhdHVyYXRlXFxuI2RlZmluZSBzYXR1cmF0ZSggYSApIGNsYW1wKCBhLCAwLjAsIDEuMCApXFxuI2VuZGlmXFxuI2RlZmluZSB3aGl0ZUNvbXBsZW1lbnQoIGEgKSAoIDEuMCAtIHNhdHVyYXRlKCBhICkgKVxcbmZsb2F0IHBvdzIoIGNvbnN0IGluIGZsb2F0IHggKSB7IHJldHVybiB4Kng7IH1cXG52ZWMzIHBvdzIoIGNvbnN0IGluIHZlYzMgeCApIHsgcmV0dXJuIHgqeDsgfVxcbmZsb2F0IHBvdzMoIGNvbnN0IGluIGZsb2F0IHggKSB7IHJldHVybiB4KngqeDsgfVxcbmZsb2F0IHBvdzQoIGNvbnN0IGluIGZsb2F0IHggKSB7IGZsb2F0IHgyID0geCp4OyByZXR1cm4geDIqeDI7IH1cXG5mbG9hdCBtYXgzKCBjb25zdCBpbiB2ZWMzIHYgKSB7IHJldHVybiBtYXgoIG1heCggdi54LCB2LnkgKSwgdi56ICk7IH1cXG5mbG9hdCBhdmVyYWdlKCBjb25zdCBpbiB2ZWMzIHYgKSB7IHJldHVybiBkb3QoIHYsIHZlYzMoIDAuMzMzMzMzMyApICk7IH1cXG5oaWdocCBmbG9hdCByYW5kKCBjb25zdCBpbiB2ZWMyIHV2ICkge1xcblxcdGNvbnN0IGhpZ2hwIGZsb2F0IGEgPSAxMi45ODk4LCBiID0gNzguMjMzLCBjID0gNDM3NTguNTQ1MztcXG5cXHRoaWdocCBmbG9hdCBkdCA9IGRvdCggdXYueHksIHZlYzIoIGEsYiApICksIHNuID0gbW9kKCBkdCwgUEkgKTtcXG5cXHRyZXR1cm4gZnJhY3QoIHNpbiggc24gKSAqIGMgKTtcXG59XFxuI2lmZGVmIEhJR0hfUFJFQ0lTSU9OXFxuXFx0ZmxvYXQgcHJlY2lzaW9uU2FmZUxlbmd0aCggdmVjMyB2ICkgeyByZXR1cm4gbGVuZ3RoKCB2ICk7IH1cXG4jZWxzZVxcblxcdGZsb2F0IHByZWNpc2lvblNhZmVMZW5ndGgoIHZlYzMgdiApIHtcXG5cXHRcXHRmbG9hdCBtYXhDb21wb25lbnQgPSBtYXgzKCBhYnMoIHYgKSApO1xcblxcdFxcdHJldHVybiBsZW5ndGgoIHYgLyBtYXhDb21wb25lbnQgKSAqIG1heENvbXBvbmVudDtcXG5cXHR9XFxuI2VuZGlmXFxuc3RydWN0IEluY2lkZW50TGlnaHQge1xcblxcdHZlYzMgY29sb3I7XFxuXFx0dmVjMyBkaXJlY3Rpb247XFxuXFx0Ym9vbCB2aXNpYmxlO1xcbn07XFxuc3RydWN0IFJlZmxlY3RlZExpZ2h0IHtcXG5cXHR2ZWMzIGRpcmVjdERpZmZ1c2U7XFxuXFx0dmVjMyBkaXJlY3RTcGVjdWxhcjtcXG5cXHR2ZWMzIGluZGlyZWN0RGlmZnVzZTtcXG5cXHR2ZWMzIGluZGlyZWN0U3BlY3VsYXI7XFxufTtcXG4jaWZkZWYgVVNFX0FMUEhBSEFTSFxcblxcdHZhcnlpbmcgdmVjMyB2UG9zaXRpb247XFxuI2VuZGlmXFxudmVjMyB0cmFuc2Zvcm1EaXJlY3Rpb24oIGluIHZlYzMgZGlyLCBpbiBtYXQ0IG1hdHJpeCApIHtcXG5cXHRyZXR1cm4gbm9ybWFsaXplKCAoIG1hdHJpeCAqIHZlYzQoIGRpciwgMC4wICkgKS54eXogKTtcXG59XFxudmVjMyBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCBpbiB2ZWMzIGRpciwgaW4gbWF0NCBtYXRyaXggKSB7XFxuXFx0cmV0dXJuIG5vcm1hbGl6ZSggKCB2ZWM0KCBkaXIsIDAuMCApICogbWF0cml4ICkueHl6ICk7XFxufVxcbm1hdDMgdHJhbnNwb3NlTWF0MyggY29uc3QgaW4gbWF0MyBtICkge1xcblxcdG1hdDMgdG1wO1xcblxcdHRtcFsgMCBdID0gdmVjMyggbVsgMCBdLngsIG1bIDEgXS54LCBtWyAyIF0ueCApO1xcblxcdHRtcFsgMSBdID0gdmVjMyggbVsgMCBdLnksIG1bIDEgXS55LCBtWyAyIF0ueSApO1xcblxcdHRtcFsgMiBdID0gdmVjMyggbVsgMCBdLnosIG1bIDEgXS56LCBtWyAyIF0ueiApO1xcblxcdHJldHVybiB0bXA7XFxufVxcbmJvb2wgaXNQZXJzcGVjdGl2ZU1hdHJpeCggbWF0NCBtICkge1xcblxcdHJldHVybiBtWyAyIF1bIDMgXSA9PSAtIDEuMDtcXG59XFxudmVjMiBlcXVpcmVjdFV2KCBpbiB2ZWMzIGRpciApIHtcXG5cXHRmbG9hdCB1ID0gYXRhbiggZGlyLnosIGRpci54ICkgKiBSRUNJUFJPQ0FMX1BJMiArIDAuNTtcXG5cXHRmbG9hdCB2ID0gYXNpbiggY2xhbXAoIGRpci55LCAtIDEuMCwgMS4wICkgKSAqIFJFQ0lQUk9DQUxfUEkgKyAwLjU7XFxuXFx0cmV0dXJuIHZlYzIoIHUsIHYgKTtcXG59XFxudmVjMyBCUkRGX0xhbWJlcnQoIGNvbnN0IGluIHZlYzMgZGlmZnVzZUNvbG9yICkge1xcblxcdHJldHVybiBSRUNJUFJPQ0FMX1BJICogZGlmZnVzZUNvbG9yO1xcbn1cXG52ZWMzIEZfU2NobGljayggY29uc3QgaW4gdmVjMyBmMCwgY29uc3QgaW4gZmxvYXQgZjkwLCBjb25zdCBpbiBmbG9hdCBkb3RWSCApIHtcXG5cXHRmbG9hdCBmcmVzbmVsID0gZXhwMiggKCAtIDUuNTU0NzMgKiBkb3RWSCAtIDYuOTgzMTYgKSAqIGRvdFZIICk7XFxuXFx0cmV0dXJuIGYwICogKCAxLjAgLSBmcmVzbmVsICkgKyAoIGY5MCAqIGZyZXNuZWwgKTtcXG59XFxuZmxvYXQgRl9TY2hsaWNrKCBjb25zdCBpbiBmbG9hdCBmMCwgY29uc3QgaW4gZmxvYXQgZjkwLCBjb25zdCBpbiBmbG9hdCBkb3RWSCApIHtcXG5cXHRmbG9hdCBmcmVzbmVsID0gZXhwMiggKCAtIDUuNTU0NzMgKiBkb3RWSCAtIDYuOTgzMTYgKSAqIGRvdFZIICk7XFxuXFx0cmV0dXJuIGYwICogKCAxLjAgLSBmcmVzbmVsICkgKyAoIGY5MCAqIGZyZXNuZWwgKTtcXG59IC8vIHZhbGlkYXRlZFwiO1xuXG52YXIgY3ViZV91dl9yZWZsZWN0aW9uX2ZyYWdtZW50ID0gXCIjaWZkZWYgRU5WTUFQX1RZUEVfQ1VCRV9VVlxcblxcdCNkZWZpbmUgY3ViZVVWX21pbk1pcExldmVsIDQuMFxcblxcdCNkZWZpbmUgY3ViZVVWX21pblRpbGVTaXplIDE2LjBcXG5cXHRmbG9hdCBnZXRGYWNlKCB2ZWMzIGRpcmVjdGlvbiApIHtcXG5cXHRcXHR2ZWMzIGFic0RpcmVjdGlvbiA9IGFicyggZGlyZWN0aW9uICk7XFxuXFx0XFx0ZmxvYXQgZmFjZSA9IC0gMS4wO1xcblxcdFxcdGlmICggYWJzRGlyZWN0aW9uLnggPiBhYnNEaXJlY3Rpb24ueiApIHtcXG5cXHRcXHRcXHRpZiAoIGFic0RpcmVjdGlvbi54ID4gYWJzRGlyZWN0aW9uLnkgKVxcblxcdFxcdFxcdFxcdGZhY2UgPSBkaXJlY3Rpb24ueCA+IDAuMCA/IDAuMCA6IDMuMDtcXG5cXHRcXHRcXHRlbHNlXFxuXFx0XFx0XFx0XFx0ZmFjZSA9IGRpcmVjdGlvbi55ID4gMC4wID8gMS4wIDogNC4wO1xcblxcdFxcdH0gZWxzZSB7XFxuXFx0XFx0XFx0aWYgKCBhYnNEaXJlY3Rpb24ueiA+IGFic0RpcmVjdGlvbi55IClcXG5cXHRcXHRcXHRcXHRmYWNlID0gZGlyZWN0aW9uLnogPiAwLjAgPyAyLjAgOiA1LjA7XFxuXFx0XFx0XFx0ZWxzZVxcblxcdFxcdFxcdFxcdGZhY2UgPSBkaXJlY3Rpb24ueSA+IDAuMCA/IDEuMCA6IDQuMDtcXG5cXHRcXHR9XFxuXFx0XFx0cmV0dXJuIGZhY2U7XFxuXFx0fVxcblxcdHZlYzIgZ2V0VVYoIHZlYzMgZGlyZWN0aW9uLCBmbG9hdCBmYWNlICkge1xcblxcdFxcdHZlYzIgdXY7XFxuXFx0XFx0aWYgKCBmYWNlID09IDAuMCApIHtcXG5cXHRcXHRcXHR1diA9IHZlYzIoIGRpcmVjdGlvbi56LCBkaXJlY3Rpb24ueSApIC8gYWJzKCBkaXJlY3Rpb24ueCApO1xcblxcdFxcdH0gZWxzZSBpZiAoIGZhY2UgPT0gMS4wICkge1xcblxcdFxcdFxcdHV2ID0gdmVjMiggLSBkaXJlY3Rpb24ueCwgLSBkaXJlY3Rpb24ueiApIC8gYWJzKCBkaXJlY3Rpb24ueSApO1xcblxcdFxcdH0gZWxzZSBpZiAoIGZhY2UgPT0gMi4wICkge1xcblxcdFxcdFxcdHV2ID0gdmVjMiggLSBkaXJlY3Rpb24ueCwgZGlyZWN0aW9uLnkgKSAvIGFicyggZGlyZWN0aW9uLnogKTtcXG5cXHRcXHR9IGVsc2UgaWYgKCBmYWNlID09IDMuMCApIHtcXG5cXHRcXHRcXHR1diA9IHZlYzIoIC0gZGlyZWN0aW9uLnosIGRpcmVjdGlvbi55ICkgLyBhYnMoIGRpcmVjdGlvbi54ICk7XFxuXFx0XFx0fSBlbHNlIGlmICggZmFjZSA9PSA0LjAgKSB7XFxuXFx0XFx0XFx0dXYgPSB2ZWMyKCAtIGRpcmVjdGlvbi54LCBkaXJlY3Rpb24ueiApIC8gYWJzKCBkaXJlY3Rpb24ueSApO1xcblxcdFxcdH0gZWxzZSB7XFxuXFx0XFx0XFx0dXYgPSB2ZWMyKCBkaXJlY3Rpb24ueCwgZGlyZWN0aW9uLnkgKSAvIGFicyggZGlyZWN0aW9uLnogKTtcXG5cXHRcXHR9XFxuXFx0XFx0cmV0dXJuIDAuNSAqICggdXYgKyAxLjAgKTtcXG5cXHR9XFxuXFx0dmVjMyBiaWxpbmVhckN1YmVVViggc2FtcGxlcjJEIGVudk1hcCwgdmVjMyBkaXJlY3Rpb24sIGZsb2F0IG1pcEludCApIHtcXG5cXHRcXHRmbG9hdCBmYWNlID0gZ2V0RmFjZSggZGlyZWN0aW9uICk7XFxuXFx0XFx0ZmxvYXQgZmlsdGVySW50ID0gbWF4KCBjdWJlVVZfbWluTWlwTGV2ZWwgLSBtaXBJbnQsIDAuMCApO1xcblxcdFxcdG1pcEludCA9IG1heCggbWlwSW50LCBjdWJlVVZfbWluTWlwTGV2ZWwgKTtcXG5cXHRcXHRmbG9hdCBmYWNlU2l6ZSA9IGV4cDIoIG1pcEludCApO1xcblxcdFxcdGhpZ2hwIHZlYzIgdXYgPSBnZXRVViggZGlyZWN0aW9uLCBmYWNlICkgKiAoIGZhY2VTaXplIC0gMi4wICkgKyAxLjA7XFxuXFx0XFx0aWYgKCBmYWNlID4gMi4wICkge1xcblxcdFxcdFxcdHV2LnkgKz0gZmFjZVNpemU7XFxuXFx0XFx0XFx0ZmFjZSAtPSAzLjA7XFxuXFx0XFx0fVxcblxcdFxcdHV2LnggKz0gZmFjZSAqIGZhY2VTaXplO1xcblxcdFxcdHV2LnggKz0gZmlsdGVySW50ICogMy4wICogY3ViZVVWX21pblRpbGVTaXplO1xcblxcdFxcdHV2LnkgKz0gNC4wICogKCBleHAyKCBDVUJFVVZfTUFYX01JUCApIC0gZmFjZVNpemUgKTtcXG5cXHRcXHR1di54ICo9IENVQkVVVl9URVhFTF9XSURUSDtcXG5cXHRcXHR1di55ICo9IENVQkVVVl9URVhFTF9IRUlHSFQ7XFxuXFx0XFx0I2lmZGVmIHRleHR1cmUyREdyYWRFWFRcXG5cXHRcXHRcXHRyZXR1cm4gdGV4dHVyZTJER3JhZEVYVCggZW52TWFwLCB1diwgdmVjMiggMC4wICksIHZlYzIoIDAuMCApICkucmdiO1xcblxcdFxcdCNlbHNlXFxuXFx0XFx0XFx0cmV0dXJuIHRleHR1cmUyRCggZW52TWFwLCB1diApLnJnYjtcXG5cXHRcXHQjZW5kaWZcXG5cXHR9XFxuXFx0I2RlZmluZSBjdWJlVVZfcjAgMS4wXFxuXFx0I2RlZmluZSBjdWJlVVZfbTAgLSAyLjBcXG5cXHQjZGVmaW5lIGN1YmVVVl9yMSAwLjhcXG5cXHQjZGVmaW5lIGN1YmVVVl9tMSAtIDEuMFxcblxcdCNkZWZpbmUgY3ViZVVWX3I0IDAuNFxcblxcdCNkZWZpbmUgY3ViZVVWX200IDIuMFxcblxcdCNkZWZpbmUgY3ViZVVWX3I1IDAuMzA1XFxuXFx0I2RlZmluZSBjdWJlVVZfbTUgMy4wXFxuXFx0I2RlZmluZSBjdWJlVVZfcjYgMC4yMVxcblxcdCNkZWZpbmUgY3ViZVVWX202IDQuMFxcblxcdGZsb2F0IHJvdWdobmVzc1RvTWlwKCBmbG9hdCByb3VnaG5lc3MgKSB7XFxuXFx0XFx0ZmxvYXQgbWlwID0gMC4wO1xcblxcdFxcdGlmICggcm91Z2huZXNzID49IGN1YmVVVl9yMSApIHtcXG5cXHRcXHRcXHRtaXAgPSAoIGN1YmVVVl9yMCAtIHJvdWdobmVzcyApICogKCBjdWJlVVZfbTEgLSBjdWJlVVZfbTAgKSAvICggY3ViZVVWX3IwIC0gY3ViZVVWX3IxICkgKyBjdWJlVVZfbTA7XFxuXFx0XFx0fSBlbHNlIGlmICggcm91Z2huZXNzID49IGN1YmVVVl9yNCApIHtcXG5cXHRcXHRcXHRtaXAgPSAoIGN1YmVVVl9yMSAtIHJvdWdobmVzcyApICogKCBjdWJlVVZfbTQgLSBjdWJlVVZfbTEgKSAvICggY3ViZVVWX3IxIC0gY3ViZVVWX3I0ICkgKyBjdWJlVVZfbTE7XFxuXFx0XFx0fSBlbHNlIGlmICggcm91Z2huZXNzID49IGN1YmVVVl9yNSApIHtcXG5cXHRcXHRcXHRtaXAgPSAoIGN1YmVVVl9yNCAtIHJvdWdobmVzcyApICogKCBjdWJlVVZfbTUgLSBjdWJlVVZfbTQgKSAvICggY3ViZVVWX3I0IC0gY3ViZVVWX3I1ICkgKyBjdWJlVVZfbTQ7XFxuXFx0XFx0fSBlbHNlIGlmICggcm91Z2huZXNzID49IGN1YmVVVl9yNiApIHtcXG5cXHRcXHRcXHRtaXAgPSAoIGN1YmVVVl9yNSAtIHJvdWdobmVzcyApICogKCBjdWJlVVZfbTYgLSBjdWJlVVZfbTUgKSAvICggY3ViZVVWX3I1IC0gY3ViZVVWX3I2ICkgKyBjdWJlVVZfbTU7XFxuXFx0XFx0fSBlbHNlIHtcXG5cXHRcXHRcXHRtaXAgPSAtIDIuMCAqIGxvZzIoIDEuMTYgKiByb3VnaG5lc3MgKTtcXHRcXHR9XFxuXFx0XFx0cmV0dXJuIG1pcDtcXG5cXHR9XFxuXFx0dmVjNCB0ZXh0dXJlQ3ViZVVWKCBzYW1wbGVyMkQgZW52TWFwLCB2ZWMzIHNhbXBsZURpciwgZmxvYXQgcm91Z2huZXNzICkge1xcblxcdFxcdGZsb2F0IG1pcCA9IGNsYW1wKCByb3VnaG5lc3NUb01pcCggcm91Z2huZXNzICksIGN1YmVVVl9tMCwgQ1VCRVVWX01BWF9NSVAgKTtcXG5cXHRcXHRmbG9hdCBtaXBGID0gZnJhY3QoIG1pcCApO1xcblxcdFxcdGZsb2F0IG1pcEludCA9IGZsb29yKCBtaXAgKTtcXG5cXHRcXHR2ZWMzIGNvbG9yMCA9IGJpbGluZWFyQ3ViZVVWKCBlbnZNYXAsIHNhbXBsZURpciwgbWlwSW50ICk7XFxuXFx0XFx0aWYgKCBtaXBGID09IDAuMCApIHtcXG5cXHRcXHRcXHRyZXR1cm4gdmVjNCggY29sb3IwLCAxLjAgKTtcXG5cXHRcXHR9IGVsc2Uge1xcblxcdFxcdFxcdHZlYzMgY29sb3IxID0gYmlsaW5lYXJDdWJlVVYoIGVudk1hcCwgc2FtcGxlRGlyLCBtaXBJbnQgKyAxLjAgKTtcXG5cXHRcXHRcXHRyZXR1cm4gdmVjNCggbWl4KCBjb2xvcjAsIGNvbG9yMSwgbWlwRiApLCAxLjAgKTtcXG5cXHRcXHR9XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgZGVmYXVsdG5vcm1hbF92ZXJ0ZXggPSBcInZlYzMgdHJhbnNmb3JtZWROb3JtYWwgPSBvYmplY3ROb3JtYWw7XFxuI2lmZGVmIFVTRV9UQU5HRU5UXFxuXFx0dmVjMyB0cmFuc2Zvcm1lZFRhbmdlbnQgPSBvYmplY3RUYW5nZW50O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQkFUQ0hJTkdcXG5cXHRtYXQzIGJtID0gbWF0MyggYmF0Y2hpbmdNYXRyaXggKTtcXG5cXHR0cmFuc2Zvcm1lZE5vcm1hbCAvPSB2ZWMzKCBkb3QoIGJtWyAwIF0sIGJtWyAwIF0gKSwgZG90KCBibVsgMSBdLCBibVsgMSBdICksIGRvdCggYm1bIDIgXSwgYm1bIDIgXSApICk7XFxuXFx0dHJhbnNmb3JtZWROb3JtYWwgPSBibSAqIHRyYW5zZm9ybWVkTm9ybWFsO1xcblxcdCNpZmRlZiBVU0VfVEFOR0VOVFxcblxcdFxcdHRyYW5zZm9ybWVkVGFuZ2VudCA9IGJtICogdHJhbnNmb3JtZWRUYW5nZW50O1xcblxcdCNlbmRpZlxcbiNlbmRpZlxcbiNpZmRlZiBVU0VfSU5TVEFOQ0lOR1xcblxcdG1hdDMgaW0gPSBtYXQzKCBpbnN0YW5jZU1hdHJpeCApO1xcblxcdHRyYW5zZm9ybWVkTm9ybWFsIC89IHZlYzMoIGRvdCggaW1bIDAgXSwgaW1bIDAgXSApLCBkb3QoIGltWyAxIF0sIGltWyAxIF0gKSwgZG90KCBpbVsgMiBdLCBpbVsgMiBdICkgKTtcXG5cXHR0cmFuc2Zvcm1lZE5vcm1hbCA9IGltICogdHJhbnNmb3JtZWROb3JtYWw7XFxuXFx0I2lmZGVmIFVTRV9UQU5HRU5UXFxuXFx0XFx0dHJhbnNmb3JtZWRUYW5nZW50ID0gaW0gKiB0cmFuc2Zvcm1lZFRhbmdlbnQ7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXFxudHJhbnNmb3JtZWROb3JtYWwgPSBub3JtYWxNYXRyaXggKiB0cmFuc2Zvcm1lZE5vcm1hbDtcXG4jaWZkZWYgRkxJUF9TSURFRFxcblxcdHRyYW5zZm9ybWVkTm9ybWFsID0gLSB0cmFuc2Zvcm1lZE5vcm1hbDtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1RBTkdFTlRcXG5cXHR0cmFuc2Zvcm1lZFRhbmdlbnQgPSAoIG1vZGVsVmlld01hdHJpeCAqIHZlYzQoIHRyYW5zZm9ybWVkVGFuZ2VudCwgMC4wICkgKS54eXo7XFxuXFx0I2lmZGVmIEZMSVBfU0lERURcXG5cXHRcXHR0cmFuc2Zvcm1lZFRhbmdlbnQgPSAtIHRyYW5zZm9ybWVkVGFuZ2VudDtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcIjtcblxudmFyIGRpc3BsYWNlbWVudG1hcF9wYXJzX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9ESVNQTEFDRU1FTlRNQVBcXG5cXHR1bmlmb3JtIHNhbXBsZXIyRCBkaXNwbGFjZW1lbnRNYXA7XFxuXFx0dW5pZm9ybSBmbG9hdCBkaXNwbGFjZW1lbnRTY2FsZTtcXG5cXHR1bmlmb3JtIGZsb2F0IGRpc3BsYWNlbWVudEJpYXM7XFxuI2VuZGlmXCI7XG5cbnZhciBkaXNwbGFjZW1lbnRtYXBfdmVydGV4ID0gXCIjaWZkZWYgVVNFX0RJU1BMQUNFTUVOVE1BUFxcblxcdHRyYW5zZm9ybWVkICs9IG5vcm1hbGl6ZSggb2JqZWN0Tm9ybWFsICkgKiAoIHRleHR1cmUyRCggZGlzcGxhY2VtZW50TWFwLCB2RGlzcGxhY2VtZW50TWFwVXYgKS54ICogZGlzcGxhY2VtZW50U2NhbGUgKyBkaXNwbGFjZW1lbnRCaWFzICk7XFxuI2VuZGlmXCI7XG5cbnZhciBlbWlzc2l2ZW1hcF9mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9FTUlTU0lWRU1BUFxcblxcdHZlYzQgZW1pc3NpdmVDb2xvciA9IHRleHR1cmUyRCggZW1pc3NpdmVNYXAsIHZFbWlzc2l2ZU1hcFV2ICk7XFxuXFx0dG90YWxFbWlzc2l2ZVJhZGlhbmNlICo9IGVtaXNzaXZlQ29sb3IucmdiO1xcbiNlbmRpZlwiO1xuXG52YXIgZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9FTUlTU0lWRU1BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGVtaXNzaXZlTWFwO1xcbiNlbmRpZlwiO1xuXG52YXIgY29sb3JzcGFjZV9mcmFnbWVudCA9IFwiZ2xfRnJhZ0NvbG9yID0gbGluZWFyVG9PdXRwdXRUZXhlbCggZ2xfRnJhZ0NvbG9yICk7XCI7XG5cbnZhciBjb2xvcnNwYWNlX3BhcnNfZnJhZ21lbnQgPSBcIlxcbmNvbnN0IG1hdDMgTElORUFSX1NSR0JfVE9fTElORUFSX0RJU1BMQVlfUDMgPSBtYXQzKFxcblxcdHZlYzMoIDAuODIyNDYyMSwgMC4xNzc1MzgsIDAuMCApLFxcblxcdHZlYzMoIDAuMDMzMTk0MSwgMC45NjY4MDU4LCAwLjAgKSxcXG5cXHR2ZWMzKCAwLjAxNzA4MjcsIDAuMDcyMzk3NCwgMC45MTA1MTk5IClcXG4pO1xcbmNvbnN0IG1hdDMgTElORUFSX0RJU1BMQVlfUDNfVE9fTElORUFSX1NSR0IgPSBtYXQzKFxcblxcdHZlYzMoIDEuMjI0OTQwMSwgLSAwLjIyNDk0MDQsIDAuMCApLFxcblxcdHZlYzMoIC0gMC4wNDIwNTY5LCAxLjA0MjA1NzEsIDAuMCApLFxcblxcdHZlYzMoIC0gMC4wMTk2Mzc2LCAtIDAuMDc4NjM2MSwgMS4wOTgyNzM1IClcXG4pO1xcbnZlYzQgTGluZWFyU1JHQlRvTGluZWFyRGlzcGxheVAzKCBpbiB2ZWM0IHZhbHVlICkge1xcblxcdHJldHVybiB2ZWM0KCB2YWx1ZS5yZ2IgKiBMSU5FQVJfU1JHQl9UT19MSU5FQVJfRElTUExBWV9QMywgdmFsdWUuYSApO1xcbn1cXG52ZWM0IExpbmVhckRpc3BsYXlQM1RvTGluZWFyU1JHQiggaW4gdmVjNCB2YWx1ZSApIHtcXG5cXHRyZXR1cm4gdmVjNCggdmFsdWUucmdiICogTElORUFSX0RJU1BMQVlfUDNfVE9fTElORUFSX1NSR0IsIHZhbHVlLmEgKTtcXG59XFxudmVjNCBMaW5lYXJUcmFuc2Zlck9FVEYoIGluIHZlYzQgdmFsdWUgKSB7XFxuXFx0cmV0dXJuIHZhbHVlO1xcbn1cXG52ZWM0IHNSR0JUcmFuc2Zlck9FVEYoIGluIHZlYzQgdmFsdWUgKSB7XFxuXFx0cmV0dXJuIHZlYzQoIG1peCggcG93KCB2YWx1ZS5yZ2IsIHZlYzMoIDAuNDE2NjYgKSApICogMS4wNTUgLSB2ZWMzKCAwLjA1NSApLCB2YWx1ZS5yZ2IgKiAxMi45MiwgdmVjMyggbGVzc1RoYW5FcXVhbCggdmFsdWUucmdiLCB2ZWMzKCAwLjAwMzEzMDggKSApICkgKSwgdmFsdWUuYSApO1xcbn1cIjtcblxudmFyIGVudm1hcF9mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9FTlZNQVBcXG5cXHQjaWZkZWYgRU5WX1dPUkxEUE9TXFxuXFx0XFx0dmVjMyBjYW1lcmFUb0ZyYWc7XFxuXFx0XFx0aWYgKCBpc09ydGhvZ3JhcGhpYyApIHtcXG5cXHRcXHRcXHRjYW1lcmFUb0ZyYWcgPSBub3JtYWxpemUoIHZlYzMoIC0gdmlld01hdHJpeFsgMCBdWyAyIF0sIC0gdmlld01hdHJpeFsgMSBdWyAyIF0sIC0gdmlld01hdHJpeFsgMiBdWyAyIF0gKSApO1xcblxcdFxcdH0gZWxzZSB7XFxuXFx0XFx0XFx0Y2FtZXJhVG9GcmFnID0gbm9ybWFsaXplKCB2V29ybGRQb3NpdGlvbiAtIGNhbWVyYVBvc2l0aW9uICk7XFxuXFx0XFx0fVxcblxcdFxcdHZlYzMgd29ybGROb3JtYWwgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCBub3JtYWwsIHZpZXdNYXRyaXggKTtcXG5cXHRcXHQjaWZkZWYgRU5WTUFQX01PREVfUkVGTEVDVElPTlxcblxcdFxcdFxcdHZlYzMgcmVmbGVjdFZlYyA9IHJlZmxlY3QoIGNhbWVyYVRvRnJhZywgd29ybGROb3JtYWwgKTtcXG5cXHRcXHQjZWxzZVxcblxcdFxcdFxcdHZlYzMgcmVmbGVjdFZlYyA9IHJlZnJhY3QoIGNhbWVyYVRvRnJhZywgd29ybGROb3JtYWwsIHJlZnJhY3Rpb25SYXRpbyApO1xcblxcdFxcdCNlbmRpZlxcblxcdCNlbHNlXFxuXFx0XFx0dmVjMyByZWZsZWN0VmVjID0gdlJlZmxlY3Q7XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIEVOVk1BUF9UWVBFX0NVQkVcXG5cXHRcXHR2ZWM0IGVudkNvbG9yID0gdGV4dHVyZUN1YmUoIGVudk1hcCwgZW52TWFwUm90YXRpb24gKiB2ZWMzKCBmbGlwRW52TWFwICogcmVmbGVjdFZlYy54LCByZWZsZWN0VmVjLnl6ICkgKTtcXG5cXHQjZWxzZVxcblxcdFxcdHZlYzQgZW52Q29sb3IgPSB2ZWM0KCAwLjAgKTtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgRU5WTUFQX0JMRU5ESU5HX01VTFRJUExZXFxuXFx0XFx0b3V0Z29pbmdMaWdodCA9IG1peCggb3V0Z29pbmdMaWdodCwgb3V0Z29pbmdMaWdodCAqIGVudkNvbG9yLnh5eiwgc3BlY3VsYXJTdHJlbmd0aCAqIHJlZmxlY3Rpdml0eSApO1xcblxcdCNlbGlmIGRlZmluZWQoIEVOVk1BUF9CTEVORElOR19NSVggKVxcblxcdFxcdG91dGdvaW5nTGlnaHQgPSBtaXgoIG91dGdvaW5nTGlnaHQsIGVudkNvbG9yLnh5eiwgc3BlY3VsYXJTdHJlbmd0aCAqIHJlZmxlY3Rpdml0eSApO1xcblxcdCNlbGlmIGRlZmluZWQoIEVOVk1BUF9CTEVORElOR19BREQgKVxcblxcdFxcdG91dGdvaW5nTGlnaHQgKz0gZW52Q29sb3IueHl6ICogc3BlY3VsYXJTdHJlbmd0aCAqIHJlZmxlY3Rpdml0eTtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcIjtcblxudmFyIGVudm1hcF9jb21tb25fcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9FTlZNQVBcXG5cXHR1bmlmb3JtIGZsb2F0IGVudk1hcEludGVuc2l0eTtcXG5cXHR1bmlmb3JtIGZsb2F0IGZsaXBFbnZNYXA7XFxuXFx0dW5pZm9ybSBtYXQzIGVudk1hcFJvdGF0aW9uO1xcblxcdCNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFXFxuXFx0XFx0dW5pZm9ybSBzYW1wbGVyQ3ViZSBlbnZNYXA7XFxuXFx0I2Vsc2VcXG5cXHRcXHR1bmlmb3JtIHNhbXBsZXIyRCBlbnZNYXA7XFxuXFx0I2VuZGlmXFxuXFx0XFxuI2VuZGlmXCI7XG5cbnZhciBlbnZtYXBfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9FTlZNQVBcXG5cXHR1bmlmb3JtIGZsb2F0IHJlZmxlY3Rpdml0eTtcXG5cXHQjaWYgZGVmaW5lZCggVVNFX0JVTVBNQVAgKSB8fCBkZWZpbmVkKCBVU0VfTk9STUFMTUFQICkgfHwgZGVmaW5lZCggUEhPTkcgKSB8fCBkZWZpbmVkKCBMQU1CRVJUIClcXG5cXHRcXHQjZGVmaW5lIEVOVl9XT1JMRFBPU1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBFTlZfV09STERQT1NcXG5cXHRcXHR2YXJ5aW5nIHZlYzMgdldvcmxkUG9zaXRpb247XFxuXFx0XFx0dW5pZm9ybSBmbG9hdCByZWZyYWN0aW9uUmF0aW87XFxuXFx0I2Vsc2VcXG5cXHRcXHR2YXJ5aW5nIHZlYzMgdlJlZmxlY3Q7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXCI7XG5cbnZhciBlbnZtYXBfcGFyc192ZXJ0ZXggPSBcIiNpZmRlZiBVU0VfRU5WTUFQXFxuXFx0I2lmIGRlZmluZWQoIFVTRV9CVU1QTUFQICkgfHwgZGVmaW5lZCggVVNFX05PUk1BTE1BUCApIHx8IGRlZmluZWQoIFBIT05HICkgfHwgZGVmaW5lZCggTEFNQkVSVCApXFxuXFx0XFx0I2RlZmluZSBFTlZfV09STERQT1NcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgRU5WX1dPUkxEUE9TXFxuXFx0XFx0XFxuXFx0XFx0dmFyeWluZyB2ZWMzIHZXb3JsZFBvc2l0aW9uO1xcblxcdCNlbHNlXFxuXFx0XFx0dmFyeWluZyB2ZWMzIHZSZWZsZWN0O1xcblxcdFxcdHVuaWZvcm0gZmxvYXQgcmVmcmFjdGlvblJhdGlvO1xcblxcdCNlbmRpZlxcbiNlbmRpZlwiO1xuXG52YXIgZW52bWFwX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9FTlZNQVBcXG5cXHQjaWZkZWYgRU5WX1dPUkxEUE9TXFxuXFx0XFx0dldvcmxkUG9zaXRpb24gPSB3b3JsZFBvc2l0aW9uLnh5ejtcXG5cXHQjZWxzZVxcblxcdFxcdHZlYzMgY2FtZXJhVG9WZXJ0ZXg7XFxuXFx0XFx0aWYgKCBpc09ydGhvZ3JhcGhpYyApIHtcXG5cXHRcXHRcXHRjYW1lcmFUb1ZlcnRleCA9IG5vcm1hbGl6ZSggdmVjMyggLSB2aWV3TWF0cml4WyAwIF1bIDIgXSwgLSB2aWV3TWF0cml4WyAxIF1bIDIgXSwgLSB2aWV3TWF0cml4WyAyIF1bIDIgXSApICk7XFxuXFx0XFx0fSBlbHNlIHtcXG5cXHRcXHRcXHRjYW1lcmFUb1ZlcnRleCA9IG5vcm1hbGl6ZSggd29ybGRQb3NpdGlvbi54eXogLSBjYW1lcmFQb3NpdGlvbiApO1xcblxcdFxcdH1cXG5cXHRcXHR2ZWMzIHdvcmxkTm9ybWFsID0gaW52ZXJzZVRyYW5zZm9ybURpcmVjdGlvbiggdHJhbnNmb3JtZWROb3JtYWwsIHZpZXdNYXRyaXggKTtcXG5cXHRcXHQjaWZkZWYgRU5WTUFQX01PREVfUkVGTEVDVElPTlxcblxcdFxcdFxcdHZSZWZsZWN0ID0gcmVmbGVjdCggY2FtZXJhVG9WZXJ0ZXgsIHdvcmxkTm9ybWFsICk7XFxuXFx0XFx0I2Vsc2VcXG5cXHRcXHRcXHR2UmVmbGVjdCA9IHJlZnJhY3QoIGNhbWVyYVRvVmVydGV4LCB3b3JsZE5vcm1hbCwgcmVmcmFjdGlvblJhdGlvICk7XFxuXFx0XFx0I2VuZGlmXFxuXFx0I2VuZGlmXFxuI2VuZGlmXCI7XG5cbnZhciBmb2dfdmVydGV4ID0gXCIjaWZkZWYgVVNFX0ZPR1xcblxcdHZGb2dEZXB0aCA9IC0gbXZQb3NpdGlvbi56O1xcbiNlbmRpZlwiO1xuXG52YXIgZm9nX3BhcnNfdmVydGV4ID0gXCIjaWZkZWYgVVNFX0ZPR1xcblxcdHZhcnlpbmcgZmxvYXQgdkZvZ0RlcHRoO1xcbiNlbmRpZlwiO1xuXG52YXIgZm9nX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0ZPR1xcblxcdCNpZmRlZiBGT0dfRVhQMlxcblxcdFxcdGZsb2F0IGZvZ0ZhY3RvciA9IDEuMCAtIGV4cCggLSBmb2dEZW5zaXR5ICogZm9nRGVuc2l0eSAqIHZGb2dEZXB0aCAqIHZGb2dEZXB0aCApO1xcblxcdCNlbHNlXFxuXFx0XFx0ZmxvYXQgZm9nRmFjdG9yID0gc21vb3Roc3RlcCggZm9nTmVhciwgZm9nRmFyLCB2Rm9nRGVwdGggKTtcXG5cXHQjZW5kaWZcXG5cXHRnbF9GcmFnQ29sb3IucmdiID0gbWl4KCBnbF9GcmFnQ29sb3IucmdiLCBmb2dDb2xvciwgZm9nRmFjdG9yICk7XFxuI2VuZGlmXCI7XG5cbnZhciBmb2dfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9GT0dcXG5cXHR1bmlmb3JtIHZlYzMgZm9nQ29sb3I7XFxuXFx0dmFyeWluZyBmbG9hdCB2Rm9nRGVwdGg7XFxuXFx0I2lmZGVmIEZPR19FWFAyXFxuXFx0XFx0dW5pZm9ybSBmbG9hdCBmb2dEZW5zaXR5O1xcblxcdCNlbHNlXFxuXFx0XFx0dW5pZm9ybSBmbG9hdCBmb2dOZWFyO1xcblxcdFxcdHVuaWZvcm0gZmxvYXQgZm9nRmFyO1xcblxcdCNlbmRpZlxcbiNlbmRpZlwiO1xuXG52YXIgZ3JhZGllbnRtYXBfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9HUkFESUVOVE1BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIGdyYWRpZW50TWFwO1xcbiNlbmRpZlxcbnZlYzMgZ2V0R3JhZGllbnRJcnJhZGlhbmNlKCB2ZWMzIG5vcm1hbCwgdmVjMyBsaWdodERpcmVjdGlvbiApIHtcXG5cXHRmbG9hdCBkb3ROTCA9IGRvdCggbm9ybWFsLCBsaWdodERpcmVjdGlvbiApO1xcblxcdHZlYzIgY29vcmQgPSB2ZWMyKCBkb3ROTCAqIDAuNSArIDAuNSwgMC4wICk7XFxuXFx0I2lmZGVmIFVTRV9HUkFESUVOVE1BUFxcblxcdFxcdHJldHVybiB2ZWMzKCB0ZXh0dXJlMkQoIGdyYWRpZW50TWFwLCBjb29yZCApLnIgKTtcXG5cXHQjZWxzZVxcblxcdFxcdHZlYzIgZncgPSBmd2lkdGgoIGNvb3JkICkgKiAwLjU7XFxuXFx0XFx0cmV0dXJuIG1peCggdmVjMyggMC43ICksIHZlYzMoIDEuMCApLCBzbW9vdGhzdGVwKCAwLjcgLSBmdy54LCAwLjcgKyBmdy54LCBjb29yZC54ICkgKTtcXG5cXHQjZW5kaWZcXG59XCI7XG5cbnZhciBsaWdodG1hcF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0xJR0hUTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgbGlnaHRNYXA7XFxuXFx0dW5pZm9ybSBmbG9hdCBsaWdodE1hcEludGVuc2l0eTtcXG4jZW5kaWZcIjtcblxudmFyIGxpZ2h0c19sYW1iZXJ0X2ZyYWdtZW50ID0gXCJMYW1iZXJ0TWF0ZXJpYWwgbWF0ZXJpYWw7XFxubWF0ZXJpYWwuZGlmZnVzZUNvbG9yID0gZGlmZnVzZUNvbG9yLnJnYjtcXG5tYXRlcmlhbC5zcGVjdWxhclN0cmVuZ3RoID0gc3BlY3VsYXJTdHJlbmd0aDtcIjtcblxudmFyIGxpZ2h0c19sYW1iZXJ0X3BhcnNfZnJhZ21lbnQgPSBcInZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xcbnN0cnVjdCBMYW1iZXJ0TWF0ZXJpYWwge1xcblxcdHZlYzMgZGlmZnVzZUNvbG9yO1xcblxcdGZsb2F0IHNwZWN1bGFyU3RyZW5ndGg7XFxufTtcXG52b2lkIFJFX0RpcmVjdF9MYW1iZXJ0KCBjb25zdCBpbiBJbmNpZGVudExpZ2h0IGRpcmVjdExpZ2h0LCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBMYW1iZXJ0TWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xcblxcdGZsb2F0IGRvdE5MID0gc2F0dXJhdGUoIGRvdCggZ2VvbWV0cnlOb3JtYWwsIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiApICk7XFxuXFx0dmVjMyBpcnJhZGlhbmNlID0gZG90TkwgKiBkaXJlY3RMaWdodC5jb2xvcjtcXG5cXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xcbn1cXG52b2lkIFJFX0luZGlyZWN0RGlmZnVzZV9MYW1iZXJ0KCBjb25zdCBpbiB2ZWMzIGlycmFkaWFuY2UsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeU5vcm1hbCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVZpZXdEaXIsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGNvbnN0IGluIExhbWJlcnRNYXRlcmlhbCBtYXRlcmlhbCwgaW5vdXQgUmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgKSB7XFxuXFx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xcbn1cXG4jZGVmaW5lIFJFX0RpcmVjdFxcdFxcdFxcdFxcdFJFX0RpcmVjdF9MYW1iZXJ0XFxuI2RlZmluZSBSRV9JbmRpcmVjdERpZmZ1c2VcXHRcXHRSRV9JbmRpcmVjdERpZmZ1c2VfTGFtYmVydFwiO1xuXG52YXIgbGlnaHRzX3BhcnNfYmVnaW4gPSBcInVuaWZvcm0gYm9vbCByZWNlaXZlU2hhZG93O1xcbnVuaWZvcm0gdmVjMyBhbWJpZW50TGlnaHRDb2xvcjtcXG4jaWYgZGVmaW5lZCggVVNFX0xJR0hUX1BST0JFUyApXFxuXFx0dW5pZm9ybSB2ZWMzIGxpZ2h0UHJvYmVbIDkgXTtcXG4jZW5kaWZcXG52ZWMzIHNoR2V0SXJyYWRpYW5jZUF0KCBpbiB2ZWMzIG5vcm1hbCwgaW4gdmVjMyBzaENvZWZmaWNpZW50c1sgOSBdICkge1xcblxcdGZsb2F0IHggPSBub3JtYWwueCwgeSA9IG5vcm1hbC55LCB6ID0gbm9ybWFsLno7XFxuXFx0dmVjMyByZXN1bHQgPSBzaENvZWZmaWNpZW50c1sgMCBdICogMC44ODYyMjc7XFxuXFx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyAxIF0gKiAyLjAgKiAwLjUxMTY2NCAqIHk7XFxuXFx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyAyIF0gKiAyLjAgKiAwLjUxMTY2NCAqIHo7XFxuXFx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyAzIF0gKiAyLjAgKiAwLjUxMTY2NCAqIHg7XFxuXFx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyA0IF0gKiAyLjAgKiAwLjQyOTA0MyAqIHggKiB5O1xcblxcdHJlc3VsdCArPSBzaENvZWZmaWNpZW50c1sgNSBdICogMi4wICogMC40MjkwNDMgKiB5ICogejtcXG5cXHRyZXN1bHQgKz0gc2hDb2VmZmljaWVudHNbIDYgXSAqICggMC43NDMxMjUgKiB6ICogeiAtIDAuMjQ3NzA4ICk7XFxuXFx0cmVzdWx0ICs9IHNoQ29lZmZpY2llbnRzWyA3IF0gKiAyLjAgKiAwLjQyOTA0MyAqIHggKiB6O1xcblxcdHJlc3VsdCArPSBzaENvZWZmaWNpZW50c1sgOCBdICogMC40MjkwNDMgKiAoIHggKiB4IC0geSAqIHkgKTtcXG5cXHRyZXR1cm4gcmVzdWx0O1xcbn1cXG52ZWMzIGdldExpZ2h0UHJvYmVJcnJhZGlhbmNlKCBjb25zdCBpbiB2ZWMzIGxpZ2h0UHJvYmVbIDkgXSwgY29uc3QgaW4gdmVjMyBub3JtYWwgKSB7XFxuXFx0dmVjMyB3b3JsZE5vcm1hbCA9IGludmVyc2VUcmFuc2Zvcm1EaXJlY3Rpb24oIG5vcm1hbCwgdmlld01hdHJpeCApO1xcblxcdHZlYzMgaXJyYWRpYW5jZSA9IHNoR2V0SXJyYWRpYW5jZUF0KCB3b3JsZE5vcm1hbCwgbGlnaHRQcm9iZSApO1xcblxcdHJldHVybiBpcnJhZGlhbmNlO1xcbn1cXG52ZWMzIGdldEFtYmllbnRMaWdodElycmFkaWFuY2UoIGNvbnN0IGluIHZlYzMgYW1iaWVudExpZ2h0Q29sb3IgKSB7XFxuXFx0dmVjMyBpcnJhZGlhbmNlID0gYW1iaWVudExpZ2h0Q29sb3I7XFxuXFx0cmV0dXJuIGlycmFkaWFuY2U7XFxufVxcbmZsb2F0IGdldERpc3RhbmNlQXR0ZW51YXRpb24oIGNvbnN0IGluIGZsb2F0IGxpZ2h0RGlzdGFuY2UsIGNvbnN0IGluIGZsb2F0IGN1dG9mZkRpc3RhbmNlLCBjb25zdCBpbiBmbG9hdCBkZWNheUV4cG9uZW50ICkge1xcblxcdGZsb2F0IGRpc3RhbmNlRmFsbG9mZiA9IDEuMCAvIG1heCggcG93KCBsaWdodERpc3RhbmNlLCBkZWNheUV4cG9uZW50ICksIDAuMDEgKTtcXG5cXHRpZiAoIGN1dG9mZkRpc3RhbmNlID4gMC4wICkge1xcblxcdFxcdGRpc3RhbmNlRmFsbG9mZiAqPSBwb3cyKCBzYXR1cmF0ZSggMS4wIC0gcG93NCggbGlnaHREaXN0YW5jZSAvIGN1dG9mZkRpc3RhbmNlICkgKSApO1xcblxcdH1cXG5cXHRyZXR1cm4gZGlzdGFuY2VGYWxsb2ZmO1xcbn1cXG5mbG9hdCBnZXRTcG90QXR0ZW51YXRpb24oIGNvbnN0IGluIGZsb2F0IGNvbmVDb3NpbmUsIGNvbnN0IGluIGZsb2F0IHBlbnVtYnJhQ29zaW5lLCBjb25zdCBpbiBmbG9hdCBhbmdsZUNvc2luZSApIHtcXG5cXHRyZXR1cm4gc21vb3Roc3RlcCggY29uZUNvc2luZSwgcGVudW1icmFDb3NpbmUsIGFuZ2xlQ29zaW5lICk7XFxufVxcbiNpZiBOVU1fRElSX0xJR0hUUyA+IDBcXG5cXHRzdHJ1Y3QgRGlyZWN0aW9uYWxMaWdodCB7XFxuXFx0XFx0dmVjMyBkaXJlY3Rpb247XFxuXFx0XFx0dmVjMyBjb2xvcjtcXG5cXHR9O1xcblxcdHVuaWZvcm0gRGlyZWN0aW9uYWxMaWdodCBkaXJlY3Rpb25hbExpZ2h0c1sgTlVNX0RJUl9MSUdIVFMgXTtcXG5cXHR2b2lkIGdldERpcmVjdGlvbmFsTGlnaHRJbmZvKCBjb25zdCBpbiBEaXJlY3Rpb25hbExpZ2h0IGRpcmVjdGlvbmFsTGlnaHQsIG91dCBJbmNpZGVudExpZ2h0IGxpZ2h0ICkge1xcblxcdFxcdGxpZ2h0LmNvbG9yID0gZGlyZWN0aW9uYWxMaWdodC5jb2xvcjtcXG5cXHRcXHRsaWdodC5kaXJlY3Rpb24gPSBkaXJlY3Rpb25hbExpZ2h0LmRpcmVjdGlvbjtcXG5cXHRcXHRsaWdodC52aXNpYmxlID0gdHJ1ZTtcXG5cXHR9XFxuI2VuZGlmXFxuI2lmIE5VTV9QT0lOVF9MSUdIVFMgPiAwXFxuXFx0c3RydWN0IFBvaW50TGlnaHQge1xcblxcdFxcdHZlYzMgcG9zaXRpb247XFxuXFx0XFx0dmVjMyBjb2xvcjtcXG5cXHRcXHRmbG9hdCBkaXN0YW5jZTtcXG5cXHRcXHRmbG9hdCBkZWNheTtcXG5cXHR9O1xcblxcdHVuaWZvcm0gUG9pbnRMaWdodCBwb2ludExpZ2h0c1sgTlVNX1BPSU5UX0xJR0hUUyBdO1xcblxcdHZvaWQgZ2V0UG9pbnRMaWdodEluZm8oIGNvbnN0IGluIFBvaW50TGlnaHQgcG9pbnRMaWdodCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBvdXQgSW5jaWRlbnRMaWdodCBsaWdodCApIHtcXG5cXHRcXHR2ZWMzIGxWZWN0b3IgPSBwb2ludExpZ2h0LnBvc2l0aW9uIC0gZ2VvbWV0cnlQb3NpdGlvbjtcXG5cXHRcXHRsaWdodC5kaXJlY3Rpb24gPSBub3JtYWxpemUoIGxWZWN0b3IgKTtcXG5cXHRcXHRmbG9hdCBsaWdodERpc3RhbmNlID0gbGVuZ3RoKCBsVmVjdG9yICk7XFxuXFx0XFx0bGlnaHQuY29sb3IgPSBwb2ludExpZ2h0LmNvbG9yO1xcblxcdFxcdGxpZ2h0LmNvbG9yICo9IGdldERpc3RhbmNlQXR0ZW51YXRpb24oIGxpZ2h0RGlzdGFuY2UsIHBvaW50TGlnaHQuZGlzdGFuY2UsIHBvaW50TGlnaHQuZGVjYXkgKTtcXG5cXHRcXHRsaWdodC52aXNpYmxlID0gKCBsaWdodC5jb2xvciAhPSB2ZWMzKCAwLjAgKSApO1xcblxcdH1cXG4jZW5kaWZcXG4jaWYgTlVNX1NQT1RfTElHSFRTID4gMFxcblxcdHN0cnVjdCBTcG90TGlnaHQge1xcblxcdFxcdHZlYzMgcG9zaXRpb247XFxuXFx0XFx0dmVjMyBkaXJlY3Rpb247XFxuXFx0XFx0dmVjMyBjb2xvcjtcXG5cXHRcXHRmbG9hdCBkaXN0YW5jZTtcXG5cXHRcXHRmbG9hdCBkZWNheTtcXG5cXHRcXHRmbG9hdCBjb25lQ29zO1xcblxcdFxcdGZsb2F0IHBlbnVtYnJhQ29zO1xcblxcdH07XFxuXFx0dW5pZm9ybSBTcG90TGlnaHQgc3BvdExpZ2h0c1sgTlVNX1NQT1RfTElHSFRTIF07XFxuXFx0dm9pZCBnZXRTcG90TGlnaHRJbmZvKCBjb25zdCBpbiBTcG90TGlnaHQgc3BvdExpZ2h0LCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIG91dCBJbmNpZGVudExpZ2h0IGxpZ2h0ICkge1xcblxcdFxcdHZlYzMgbFZlY3RvciA9IHNwb3RMaWdodC5wb3NpdGlvbiAtIGdlb21ldHJ5UG9zaXRpb247XFxuXFx0XFx0bGlnaHQuZGlyZWN0aW9uID0gbm9ybWFsaXplKCBsVmVjdG9yICk7XFxuXFx0XFx0ZmxvYXQgYW5nbGVDb3MgPSBkb3QoIGxpZ2h0LmRpcmVjdGlvbiwgc3BvdExpZ2h0LmRpcmVjdGlvbiApO1xcblxcdFxcdGZsb2F0IHNwb3RBdHRlbnVhdGlvbiA9IGdldFNwb3RBdHRlbnVhdGlvbiggc3BvdExpZ2h0LmNvbmVDb3MsIHNwb3RMaWdodC5wZW51bWJyYUNvcywgYW5nbGVDb3MgKTtcXG5cXHRcXHRpZiAoIHNwb3RBdHRlbnVhdGlvbiA+IDAuMCApIHtcXG5cXHRcXHRcXHRmbG9hdCBsaWdodERpc3RhbmNlID0gbGVuZ3RoKCBsVmVjdG9yICk7XFxuXFx0XFx0XFx0bGlnaHQuY29sb3IgPSBzcG90TGlnaHQuY29sb3IgKiBzcG90QXR0ZW51YXRpb247XFxuXFx0XFx0XFx0bGlnaHQuY29sb3IgKj0gZ2V0RGlzdGFuY2VBdHRlbnVhdGlvbiggbGlnaHREaXN0YW5jZSwgc3BvdExpZ2h0LmRpc3RhbmNlLCBzcG90TGlnaHQuZGVjYXkgKTtcXG5cXHRcXHRcXHRsaWdodC52aXNpYmxlID0gKCBsaWdodC5jb2xvciAhPSB2ZWMzKCAwLjAgKSApO1xcblxcdFxcdH0gZWxzZSB7XFxuXFx0XFx0XFx0bGlnaHQuY29sb3IgPSB2ZWMzKCAwLjAgKTtcXG5cXHRcXHRcXHRsaWdodC52aXNpYmxlID0gZmFsc2U7XFxuXFx0XFx0fVxcblxcdH1cXG4jZW5kaWZcXG4jaWYgTlVNX1JFQ1RfQVJFQV9MSUdIVFMgPiAwXFxuXFx0c3RydWN0IFJlY3RBcmVhTGlnaHQge1xcblxcdFxcdHZlYzMgY29sb3I7XFxuXFx0XFx0dmVjMyBwb3NpdGlvbjtcXG5cXHRcXHR2ZWMzIGhhbGZXaWR0aDtcXG5cXHRcXHR2ZWMzIGhhbGZIZWlnaHQ7XFxuXFx0fTtcXG5cXHR1bmlmb3JtIHNhbXBsZXIyRCBsdGNfMTtcXHR1bmlmb3JtIHNhbXBsZXIyRCBsdGNfMjtcXG5cXHR1bmlmb3JtIFJlY3RBcmVhTGlnaHQgcmVjdEFyZWFMaWdodHNbIE5VTV9SRUNUX0FSRUFfTElHSFRTIF07XFxuI2VuZGlmXFxuI2lmIE5VTV9IRU1JX0xJR0hUUyA+IDBcXG5cXHRzdHJ1Y3QgSGVtaXNwaGVyZUxpZ2h0IHtcXG5cXHRcXHR2ZWMzIGRpcmVjdGlvbjtcXG5cXHRcXHR2ZWMzIHNreUNvbG9yO1xcblxcdFxcdHZlYzMgZ3JvdW5kQ29sb3I7XFxuXFx0fTtcXG5cXHR1bmlmb3JtIEhlbWlzcGhlcmVMaWdodCBoZW1pc3BoZXJlTGlnaHRzWyBOVU1fSEVNSV9MSUdIVFMgXTtcXG5cXHR2ZWMzIGdldEhlbWlzcGhlcmVMaWdodElycmFkaWFuY2UoIGNvbnN0IGluIEhlbWlzcGhlcmVMaWdodCBoZW1pTGlnaHQsIGNvbnN0IGluIHZlYzMgbm9ybWFsICkge1xcblxcdFxcdGZsb2F0IGRvdE5MID0gZG90KCBub3JtYWwsIGhlbWlMaWdodC5kaXJlY3Rpb24gKTtcXG5cXHRcXHRmbG9hdCBoZW1pRGlmZnVzZVdlaWdodCA9IDAuNSAqIGRvdE5MICsgMC41O1xcblxcdFxcdHZlYzMgaXJyYWRpYW5jZSA9IG1peCggaGVtaUxpZ2h0Lmdyb3VuZENvbG9yLCBoZW1pTGlnaHQuc2t5Q29sb3IsIGhlbWlEaWZmdXNlV2VpZ2h0ICk7XFxuXFx0XFx0cmV0dXJuIGlycmFkaWFuY2U7XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgZW52bWFwX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfRU5WTUFQXFxuXFx0dmVjMyBnZXRJQkxJcnJhZGlhbmNlKCBjb25zdCBpbiB2ZWMzIG5vcm1hbCApIHtcXG5cXHRcXHQjaWZkZWYgRU5WTUFQX1RZUEVfQ1VCRV9VVlxcblxcdFxcdFxcdHZlYzMgd29ybGROb3JtYWwgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCBub3JtYWwsIHZpZXdNYXRyaXggKTtcXG5cXHRcXHRcXHR2ZWM0IGVudk1hcENvbG9yID0gdGV4dHVyZUN1YmVVViggZW52TWFwLCBlbnZNYXBSb3RhdGlvbiAqIHdvcmxkTm9ybWFsLCAxLjAgKTtcXG5cXHRcXHRcXHRyZXR1cm4gUEkgKiBlbnZNYXBDb2xvci5yZ2IgKiBlbnZNYXBJbnRlbnNpdHk7XFxuXFx0XFx0I2Vsc2VcXG5cXHRcXHRcXHRyZXR1cm4gdmVjMyggMC4wICk7XFxuXFx0XFx0I2VuZGlmXFxuXFx0fVxcblxcdHZlYzMgZ2V0SUJMUmFkaWFuY2UoIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcyApIHtcXG5cXHRcXHQjaWZkZWYgRU5WTUFQX1RZUEVfQ1VCRV9VVlxcblxcdFxcdFxcdHZlYzMgcmVmbGVjdFZlYyA9IHJlZmxlY3QoIC0gdmlld0Rpciwgbm9ybWFsICk7XFxuXFx0XFx0XFx0cmVmbGVjdFZlYyA9IG5vcm1hbGl6ZSggbWl4KCByZWZsZWN0VmVjLCBub3JtYWwsIHJvdWdobmVzcyAqIHJvdWdobmVzcykgKTtcXG5cXHRcXHRcXHRyZWZsZWN0VmVjID0gaW52ZXJzZVRyYW5zZm9ybURpcmVjdGlvbiggcmVmbGVjdFZlYywgdmlld01hdHJpeCApO1xcblxcdFxcdFxcdHZlYzQgZW52TWFwQ29sb3IgPSB0ZXh0dXJlQ3ViZVVWKCBlbnZNYXAsIGVudk1hcFJvdGF0aW9uICogcmVmbGVjdFZlYywgcm91Z2huZXNzICk7XFxuXFx0XFx0XFx0cmV0dXJuIGVudk1hcENvbG9yLnJnYiAqIGVudk1hcEludGVuc2l0eTtcXG5cXHRcXHQjZWxzZVxcblxcdFxcdFxcdHJldHVybiB2ZWMzKCAwLjAgKTtcXG5cXHRcXHQjZW5kaWZcXG5cXHR9XFxuXFx0I2lmZGVmIFVTRV9BTklTT1RST1BZXFxuXFx0XFx0dmVjMyBnZXRJQkxBbmlzb3Ryb3B5UmFkaWFuY2UoIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcywgY29uc3QgaW4gdmVjMyBiaXRhbmdlbnQsIGNvbnN0IGluIGZsb2F0IGFuaXNvdHJvcHkgKSB7XFxuXFx0XFx0XFx0I2lmZGVmIEVOVk1BUF9UWVBFX0NVQkVfVVZcXG5cXHRcXHRcXHRcXHR2ZWMzIGJlbnROb3JtYWwgPSBjcm9zcyggYml0YW5nZW50LCB2aWV3RGlyICk7XFxuXFx0XFx0XFx0XFx0YmVudE5vcm1hbCA9IG5vcm1hbGl6ZSggY3Jvc3MoIGJlbnROb3JtYWwsIGJpdGFuZ2VudCApICk7XFxuXFx0XFx0XFx0XFx0YmVudE5vcm1hbCA9IG5vcm1hbGl6ZSggbWl4KCBiZW50Tm9ybWFsLCBub3JtYWwsIHBvdzIoIHBvdzIoIDEuMCAtIGFuaXNvdHJvcHkgKiAoIDEuMCAtIHJvdWdobmVzcyApICkgKSApICk7XFxuXFx0XFx0XFx0XFx0cmV0dXJuIGdldElCTFJhZGlhbmNlKCB2aWV3RGlyLCBiZW50Tm9ybWFsLCByb3VnaG5lc3MgKTtcXG5cXHRcXHRcXHQjZWxzZVxcblxcdFxcdFxcdFxcdHJldHVybiB2ZWMzKCAwLjAgKTtcXG5cXHRcXHRcXHQjZW5kaWZcXG5cXHRcXHR9XFxuXFx0I2VuZGlmXFxuI2VuZGlmXCI7XG5cbnZhciBsaWdodHNfdG9vbl9mcmFnbWVudCA9IFwiVG9vbk1hdGVyaWFsIG1hdGVyaWFsO1xcbm1hdGVyaWFsLmRpZmZ1c2VDb2xvciA9IGRpZmZ1c2VDb2xvci5yZ2I7XCI7XG5cbnZhciBsaWdodHNfdG9vbl9wYXJzX2ZyYWdtZW50ID0gXCJ2YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcXG5zdHJ1Y3QgVG9vbk1hdGVyaWFsIHtcXG5cXHR2ZWMzIGRpZmZ1c2VDb2xvcjtcXG59O1xcbnZvaWQgUkVfRGlyZWN0X1Rvb24oIGNvbnN0IGluIEluY2lkZW50TGlnaHQgZGlyZWN0TGlnaHQsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeU5vcm1hbCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVZpZXdEaXIsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGNvbnN0IGluIFRvb25NYXRlcmlhbCBtYXRlcmlhbCwgaW5vdXQgUmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgKSB7XFxuXFx0dmVjMyBpcnJhZGlhbmNlID0gZ2V0R3JhZGllbnRJcnJhZGlhbmNlKCBnZW9tZXRyeU5vcm1hbCwgZGlyZWN0TGlnaHQuZGlyZWN0aW9uICkgKiBkaXJlY3RMaWdodC5jb2xvcjtcXG5cXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xcbn1cXG52b2lkIFJFX0luZGlyZWN0RGlmZnVzZV9Ub29uKCBjb25zdCBpbiB2ZWMzIGlycmFkaWFuY2UsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeU5vcm1hbCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVZpZXdEaXIsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGNvbnN0IGluIFRvb25NYXRlcmlhbCBtYXRlcmlhbCwgaW5vdXQgUmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgKSB7XFxuXFx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xcbn1cXG4jZGVmaW5lIFJFX0RpcmVjdFxcdFxcdFxcdFxcdFJFX0RpcmVjdF9Ub29uXFxuI2RlZmluZSBSRV9JbmRpcmVjdERpZmZ1c2VcXHRcXHRSRV9JbmRpcmVjdERpZmZ1c2VfVG9vblwiO1xuXG52YXIgbGlnaHRzX3Bob25nX2ZyYWdtZW50ID0gXCJCbGlublBob25nTWF0ZXJpYWwgbWF0ZXJpYWw7XFxubWF0ZXJpYWwuZGlmZnVzZUNvbG9yID0gZGlmZnVzZUNvbG9yLnJnYjtcXG5tYXRlcmlhbC5zcGVjdWxhckNvbG9yID0gc3BlY3VsYXI7XFxubWF0ZXJpYWwuc3BlY3VsYXJTaGluaW5lc3MgPSBzaGluaW5lc3M7XFxubWF0ZXJpYWwuc3BlY3VsYXJTdHJlbmd0aCA9IHNwZWN1bGFyU3RyZW5ndGg7XCI7XG5cbnZhciBsaWdodHNfcGhvbmdfcGFyc19mcmFnbWVudCA9IFwidmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XFxuc3RydWN0IEJsaW5uUGhvbmdNYXRlcmlhbCB7XFxuXFx0dmVjMyBkaWZmdXNlQ29sb3I7XFxuXFx0dmVjMyBzcGVjdWxhckNvbG9yO1xcblxcdGZsb2F0IHNwZWN1bGFyU2hpbmluZXNzO1xcblxcdGZsb2F0IHNwZWN1bGFyU3RyZW5ndGg7XFxufTtcXG52b2lkIFJFX0RpcmVjdF9CbGlublBob25nKCBjb25zdCBpbiBJbmNpZGVudExpZ2h0IGRpcmVjdExpZ2h0LCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBCbGlublBob25nTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xcblxcdGZsb2F0IGRvdE5MID0gc2F0dXJhdGUoIGRvdCggZ2VvbWV0cnlOb3JtYWwsIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiApICk7XFxuXFx0dmVjMyBpcnJhZGlhbmNlID0gZG90TkwgKiBkaXJlY3RMaWdodC5jb2xvcjtcXG5cXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICs9IGlycmFkaWFuY2UgKiBCUkRGX0xhbWJlcnQoIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciApO1xcblxcdHJlZmxlY3RlZExpZ2h0LmRpcmVjdFNwZWN1bGFyICs9IGlycmFkaWFuY2UgKiBCUkRGX0JsaW5uUGhvbmcoIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiwgZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeU5vcm1hbCwgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciwgbWF0ZXJpYWwuc3BlY3VsYXJTaGluaW5lc3MgKSAqIG1hdGVyaWFsLnNwZWN1bGFyU3RyZW5ndGg7XFxufVxcbnZvaWQgUkVfSW5kaXJlY3REaWZmdXNlX0JsaW5uUGhvbmcoIGNvbnN0IGluIHZlYzMgaXJyYWRpYW5jZSwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVBvc2l0aW9uLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Tm9ybWFsLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Vmlld0RpciwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgY29uc3QgaW4gQmxpbm5QaG9uZ01hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcXG5cXHRyZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKz0gaXJyYWRpYW5jZSAqIEJSREZfTGFtYmVydCggbWF0ZXJpYWwuZGlmZnVzZUNvbG9yICk7XFxufVxcbiNkZWZpbmUgUkVfRGlyZWN0XFx0XFx0XFx0XFx0UkVfRGlyZWN0X0JsaW5uUGhvbmdcXG4jZGVmaW5lIFJFX0luZGlyZWN0RGlmZnVzZVxcdFxcdFJFX0luZGlyZWN0RGlmZnVzZV9CbGlublBob25nXCI7XG5cbnZhciBsaWdodHNfcGh5c2ljYWxfZnJhZ21lbnQgPSBcIlBoeXNpY2FsTWF0ZXJpYWwgbWF0ZXJpYWw7XFxubWF0ZXJpYWwuZGlmZnVzZUNvbG9yID0gZGlmZnVzZUNvbG9yLnJnYiAqICggMS4wIC0gbWV0YWxuZXNzRmFjdG9yICk7XFxudmVjMyBkeHkgPSBtYXgoIGFicyggZEZkeCggbm9uUGVydHVyYmVkTm9ybWFsICkgKSwgYWJzKCBkRmR5KCBub25QZXJ0dXJiZWROb3JtYWwgKSApICk7XFxuZmxvYXQgZ2VvbWV0cnlSb3VnaG5lc3MgPSBtYXgoIG1heCggZHh5LngsIGR4eS55ICksIGR4eS56ICk7XFxubWF0ZXJpYWwucm91Z2huZXNzID0gbWF4KCByb3VnaG5lc3NGYWN0b3IsIDAuMDUyNSApO21hdGVyaWFsLnJvdWdobmVzcyArPSBnZW9tZXRyeVJvdWdobmVzcztcXG5tYXRlcmlhbC5yb3VnaG5lc3MgPSBtaW4oIG1hdGVyaWFsLnJvdWdobmVzcywgMS4wICk7XFxuI2lmZGVmIElPUlxcblxcdG1hdGVyaWFsLmlvciA9IGlvcjtcXG5cXHQjaWZkZWYgVVNFX1NQRUNVTEFSXFxuXFx0XFx0ZmxvYXQgc3BlY3VsYXJJbnRlbnNpdHlGYWN0b3IgPSBzcGVjdWxhckludGVuc2l0eTtcXG5cXHRcXHR2ZWMzIHNwZWN1bGFyQ29sb3JGYWN0b3IgPSBzcGVjdWxhckNvbG9yO1xcblxcdFxcdCNpZmRlZiBVU0VfU1BFQ1VMQVJfQ09MT1JNQVBcXG5cXHRcXHRcXHRzcGVjdWxhckNvbG9yRmFjdG9yICo9IHRleHR1cmUyRCggc3BlY3VsYXJDb2xvck1hcCwgdlNwZWN1bGFyQ29sb3JNYXBVdiApLnJnYjtcXG5cXHRcXHQjZW5kaWZcXG5cXHRcXHQjaWZkZWYgVVNFX1NQRUNVTEFSX0lOVEVOU0lUWU1BUFxcblxcdFxcdFxcdHNwZWN1bGFySW50ZW5zaXR5RmFjdG9yICo9IHRleHR1cmUyRCggc3BlY3VsYXJJbnRlbnNpdHlNYXAsIHZTcGVjdWxhckludGVuc2l0eU1hcFV2ICkuYTtcXG5cXHRcXHQjZW5kaWZcXG5cXHRcXHRtYXRlcmlhbC5zcGVjdWxhckY5MCA9IG1peCggc3BlY3VsYXJJbnRlbnNpdHlGYWN0b3IsIDEuMCwgbWV0YWxuZXNzRmFjdG9yICk7XFxuXFx0I2Vsc2VcXG5cXHRcXHRmbG9hdCBzcGVjdWxhckludGVuc2l0eUZhY3RvciA9IDEuMDtcXG5cXHRcXHR2ZWMzIHNwZWN1bGFyQ29sb3JGYWN0b3IgPSB2ZWMzKCAxLjAgKTtcXG5cXHRcXHRtYXRlcmlhbC5zcGVjdWxhckY5MCA9IDEuMDtcXG5cXHQjZW5kaWZcXG5cXHRtYXRlcmlhbC5zcGVjdWxhckNvbG9yID0gbWl4KCBtaW4oIHBvdzIoICggbWF0ZXJpYWwuaW9yIC0gMS4wICkgLyAoIG1hdGVyaWFsLmlvciArIDEuMCApICkgKiBzcGVjdWxhckNvbG9yRmFjdG9yLCB2ZWMzKCAxLjAgKSApICogc3BlY3VsYXJJbnRlbnNpdHlGYWN0b3IsIGRpZmZ1c2VDb2xvci5yZ2IsIG1ldGFsbmVzc0ZhY3RvciApO1xcbiNlbHNlXFxuXFx0bWF0ZXJpYWwuc3BlY3VsYXJDb2xvciA9IG1peCggdmVjMyggMC4wNCApLCBkaWZmdXNlQ29sb3IucmdiLCBtZXRhbG5lc3NGYWN0b3IgKTtcXG5cXHRtYXRlcmlhbC5zcGVjdWxhckY5MCA9IDEuMDtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0NMRUFSQ09BVFxcblxcdG1hdGVyaWFsLmNsZWFyY29hdCA9IGNsZWFyY29hdDtcXG5cXHRtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgPSBjbGVhcmNvYXRSb3VnaG5lc3M7XFxuXFx0bWF0ZXJpYWwuY2xlYXJjb2F0RjAgPSB2ZWMzKCAwLjA0ICk7XFxuXFx0bWF0ZXJpYWwuY2xlYXJjb2F0RjkwID0gMS4wO1xcblxcdCNpZmRlZiBVU0VfQ0xFQVJDT0FUTUFQXFxuXFx0XFx0bWF0ZXJpYWwuY2xlYXJjb2F0ICo9IHRleHR1cmUyRCggY2xlYXJjb2F0TWFwLCB2Q2xlYXJjb2F0TWFwVXYgKS54O1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUFxcblxcdFxcdG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcyAqPSB0ZXh0dXJlMkQoIGNsZWFyY29hdFJvdWdobmVzc01hcCwgdkNsZWFyY29hdFJvdWdobmVzc01hcFV2ICkueTtcXG5cXHQjZW5kaWZcXG5cXHRtYXRlcmlhbC5jbGVhcmNvYXQgPSBzYXR1cmF0ZSggbWF0ZXJpYWwuY2xlYXJjb2F0ICk7XFx0bWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzID0gbWF4KCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MsIDAuMDUyNSApO1xcblxcdG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcyArPSBnZW9tZXRyeVJvdWdobmVzcztcXG5cXHRtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgPSBtaW4oIG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzcywgMS4wICk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9ESVNQRVJTSU9OXFxuXFx0bWF0ZXJpYWwuZGlzcGVyc2lvbiA9IGRpc3BlcnNpb247XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9JUklERVNDRU5DRVxcblxcdG1hdGVyaWFsLmlyaWRlc2NlbmNlID0gaXJpZGVzY2VuY2U7XFxuXFx0bWF0ZXJpYWwuaXJpZGVzY2VuY2VJT1IgPSBpcmlkZXNjZW5jZUlPUjtcXG5cXHQjaWZkZWYgVVNFX0lSSURFU0NFTkNFTUFQXFxuXFx0XFx0bWF0ZXJpYWwuaXJpZGVzY2VuY2UgKj0gdGV4dHVyZTJEKCBpcmlkZXNjZW5jZU1hcCwgdklyaWRlc2NlbmNlTWFwVXYgKS5yO1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXFxuXFx0XFx0bWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3MgPSAoaXJpZGVzY2VuY2VUaGlja25lc3NNYXhpbXVtIC0gaXJpZGVzY2VuY2VUaGlja25lc3NNaW5pbXVtKSAqIHRleHR1cmUyRCggaXJpZGVzY2VuY2VUaGlja25lc3NNYXAsIHZJcmlkZXNjZW5jZVRoaWNrbmVzc01hcFV2ICkuZyArIGlyaWRlc2NlbmNlVGhpY2tuZXNzTWluaW11bTtcXG5cXHQjZWxzZVxcblxcdFxcdG1hdGVyaWFsLmlyaWRlc2NlbmNlVGhpY2tuZXNzID0gaXJpZGVzY2VuY2VUaGlja25lc3NNYXhpbXVtO1xcblxcdCNlbmRpZlxcbiNlbmRpZlxcbiNpZmRlZiBVU0VfU0hFRU5cXG5cXHRtYXRlcmlhbC5zaGVlbkNvbG9yID0gc2hlZW5Db2xvcjtcXG5cXHQjaWZkZWYgVVNFX1NIRUVOX0NPTE9STUFQXFxuXFx0XFx0bWF0ZXJpYWwuc2hlZW5Db2xvciAqPSB0ZXh0dXJlMkQoIHNoZWVuQ29sb3JNYXAsIHZTaGVlbkNvbG9yTWFwVXYgKS5yZ2I7XFxuXFx0I2VuZGlmXFxuXFx0bWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3MgPSBjbGFtcCggc2hlZW5Sb3VnaG5lc3MsIDAuMDcsIDEuMCApO1xcblxcdCNpZmRlZiBVU0VfU0hFRU5fUk9VR0hORVNTTUFQXFxuXFx0XFx0bWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3MgKj0gdGV4dHVyZTJEKCBzaGVlblJvdWdobmVzc01hcCwgdlNoZWVuUm91Z2huZXNzTWFwVXYgKS5hO1xcblxcdCNlbmRpZlxcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQU5JU09UUk9QWVxcblxcdCNpZmRlZiBVU0VfQU5JU09UUk9QWU1BUFxcblxcdFxcdG1hdDIgYW5pc290cm9weU1hdCA9IG1hdDIoIGFuaXNvdHJvcHlWZWN0b3IueCwgYW5pc290cm9weVZlY3Rvci55LCAtIGFuaXNvdHJvcHlWZWN0b3IueSwgYW5pc290cm9weVZlY3Rvci54ICk7XFxuXFx0XFx0dmVjMyBhbmlzb3Ryb3B5UG9sYXIgPSB0ZXh0dXJlMkQoIGFuaXNvdHJvcHlNYXAsIHZBbmlzb3Ryb3B5TWFwVXYgKS5yZ2I7XFxuXFx0XFx0dmVjMiBhbmlzb3Ryb3B5ViA9IGFuaXNvdHJvcHlNYXQgKiBub3JtYWxpemUoIDIuMCAqIGFuaXNvdHJvcHlQb2xhci5yZyAtIHZlYzIoIDEuMCApICkgKiBhbmlzb3Ryb3B5UG9sYXIuYjtcXG5cXHQjZWxzZVxcblxcdFxcdHZlYzIgYW5pc290cm9weVYgPSBhbmlzb3Ryb3B5VmVjdG9yO1xcblxcdCNlbmRpZlxcblxcdG1hdGVyaWFsLmFuaXNvdHJvcHkgPSBsZW5ndGgoIGFuaXNvdHJvcHlWICk7XFxuXFx0aWYoIG1hdGVyaWFsLmFuaXNvdHJvcHkgPT0gMC4wICkge1xcblxcdFxcdGFuaXNvdHJvcHlWID0gdmVjMiggMS4wLCAwLjAgKTtcXG5cXHR9IGVsc2Uge1xcblxcdFxcdGFuaXNvdHJvcHlWIC89IG1hdGVyaWFsLmFuaXNvdHJvcHk7XFxuXFx0XFx0bWF0ZXJpYWwuYW5pc290cm9weSA9IHNhdHVyYXRlKCBtYXRlcmlhbC5hbmlzb3Ryb3B5ICk7XFxuXFx0fVxcblxcdG1hdGVyaWFsLmFscGhhVCA9IG1peCggcG93MiggbWF0ZXJpYWwucm91Z2huZXNzICksIDEuMCwgcG93MiggbWF0ZXJpYWwuYW5pc290cm9weSApICk7XFxuXFx0bWF0ZXJpYWwuYW5pc290cm9weVQgPSB0Ym5bIDAgXSAqIGFuaXNvdHJvcHlWLnggKyB0Ym5bIDEgXSAqIGFuaXNvdHJvcHlWLnk7XFxuXFx0bWF0ZXJpYWwuYW5pc290cm9weUIgPSB0Ym5bIDEgXSAqIGFuaXNvdHJvcHlWLnggLSB0Ym5bIDAgXSAqIGFuaXNvdHJvcHlWLnk7XFxuI2VuZGlmXCI7XG5cbnZhciBsaWdodHNfcGh5c2ljYWxfcGFyc19mcmFnbWVudCA9IFwic3RydWN0IFBoeXNpY2FsTWF0ZXJpYWwge1xcblxcdHZlYzMgZGlmZnVzZUNvbG9yO1xcblxcdGZsb2F0IHJvdWdobmVzcztcXG5cXHR2ZWMzIHNwZWN1bGFyQ29sb3I7XFxuXFx0ZmxvYXQgc3BlY3VsYXJGOTA7XFxuXFx0ZmxvYXQgZGlzcGVyc2lvbjtcXG5cXHQjaWZkZWYgVVNFX0NMRUFSQ09BVFxcblxcdFxcdGZsb2F0IGNsZWFyY29hdDtcXG5cXHRcXHRmbG9hdCBjbGVhcmNvYXRSb3VnaG5lc3M7XFxuXFx0XFx0dmVjMyBjbGVhcmNvYXRGMDtcXG5cXHRcXHRmbG9hdCBjbGVhcmNvYXRGOTA7XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIFVTRV9JUklERVNDRU5DRVxcblxcdFxcdGZsb2F0IGlyaWRlc2NlbmNlO1xcblxcdFxcdGZsb2F0IGlyaWRlc2NlbmNlSU9SO1xcblxcdFxcdGZsb2F0IGlyaWRlc2NlbmNlVGhpY2tuZXNzO1xcblxcdFxcdHZlYzMgaXJpZGVzY2VuY2VGcmVzbmVsO1xcblxcdFxcdHZlYzMgaXJpZGVzY2VuY2VGMDtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX1NIRUVOXFxuXFx0XFx0dmVjMyBzaGVlbkNvbG9yO1xcblxcdFxcdGZsb2F0IHNoZWVuUm91Z2huZXNzO1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBJT1JcXG5cXHRcXHRmbG9hdCBpb3I7XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIFVTRV9UUkFOU01JU1NJT05cXG5cXHRcXHRmbG9hdCB0cmFuc21pc3Npb247XFxuXFx0XFx0ZmxvYXQgdHJhbnNtaXNzaW9uQWxwaGE7XFxuXFx0XFx0ZmxvYXQgdGhpY2tuZXNzO1xcblxcdFxcdGZsb2F0IGF0dGVudWF0aW9uRGlzdGFuY2U7XFxuXFx0XFx0dmVjMyBhdHRlbnVhdGlvbkNvbG9yO1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBVU0VfQU5JU09UUk9QWVxcblxcdFxcdGZsb2F0IGFuaXNvdHJvcHk7XFxuXFx0XFx0ZmxvYXQgYWxwaGFUO1xcblxcdFxcdHZlYzMgYW5pc290cm9weVQ7XFxuXFx0XFx0dmVjMyBhbmlzb3Ryb3B5QjtcXG5cXHQjZW5kaWZcXG59O1xcbnZlYzMgY2xlYXJjb2F0U3BlY3VsYXJEaXJlY3QgPSB2ZWMzKCAwLjAgKTtcXG52ZWMzIGNsZWFyY29hdFNwZWN1bGFySW5kaXJlY3QgPSB2ZWMzKCAwLjAgKTtcXG52ZWMzIHNoZWVuU3BlY3VsYXJEaXJlY3QgPSB2ZWMzKCAwLjAgKTtcXG52ZWMzIHNoZWVuU3BlY3VsYXJJbmRpcmVjdCA9IHZlYzMoMC4wICk7XFxudmVjMyBTY2hsaWNrX3RvX0YwKCBjb25zdCBpbiB2ZWMzIGYsIGNvbnN0IGluIGZsb2F0IGY5MCwgY29uc3QgaW4gZmxvYXQgZG90VkggKSB7XFxuICAgIGZsb2F0IHggPSBjbGFtcCggMS4wIC0gZG90VkgsIDAuMCwgMS4wICk7XFxuICAgIGZsb2F0IHgyID0geCAqIHg7XFxuICAgIGZsb2F0IHg1ID0gY2xhbXAoIHggKiB4MiAqIHgyLCAwLjAsIDAuOTk5OSApO1xcbiAgICByZXR1cm4gKCBmIC0gdmVjMyggZjkwICkgKiB4NSApIC8gKCAxLjAgLSB4NSApO1xcbn1cXG5mbG9hdCBWX0dHWF9TbWl0aENvcnJlbGF0ZWQoIGNvbnN0IGluIGZsb2F0IGFscGhhLCBjb25zdCBpbiBmbG9hdCBkb3ROTCwgY29uc3QgaW4gZmxvYXQgZG90TlYgKSB7XFxuXFx0ZmxvYXQgYTIgPSBwb3cyKCBhbHBoYSApO1xcblxcdGZsb2F0IGd2ID0gZG90TkwgKiBzcXJ0KCBhMiArICggMS4wIC0gYTIgKSAqIHBvdzIoIGRvdE5WICkgKTtcXG5cXHRmbG9hdCBnbCA9IGRvdE5WICogc3FydCggYTIgKyAoIDEuMCAtIGEyICkgKiBwb3cyKCBkb3ROTCApICk7XFxuXFx0cmV0dXJuIDAuNSAvIG1heCggZ3YgKyBnbCwgRVBTSUxPTiApO1xcbn1cXG5mbG9hdCBEX0dHWCggY29uc3QgaW4gZmxvYXQgYWxwaGEsIGNvbnN0IGluIGZsb2F0IGRvdE5IICkge1xcblxcdGZsb2F0IGEyID0gcG93MiggYWxwaGEgKTtcXG5cXHRmbG9hdCBkZW5vbSA9IHBvdzIoIGRvdE5IICkgKiAoIGEyIC0gMS4wICkgKyAxLjA7XFxuXFx0cmV0dXJuIFJFQ0lQUk9DQUxfUEkgKiBhMiAvIHBvdzIoIGRlbm9tICk7XFxufVxcbiNpZmRlZiBVU0VfQU5JU09UUk9QWVxcblxcdGZsb2F0IFZfR0dYX1NtaXRoQ29ycmVsYXRlZF9Bbmlzb3Ryb3BpYyggY29uc3QgaW4gZmxvYXQgYWxwaGFULCBjb25zdCBpbiBmbG9hdCBhbHBoYUIsIGNvbnN0IGluIGZsb2F0IGRvdFRWLCBjb25zdCBpbiBmbG9hdCBkb3RCViwgY29uc3QgaW4gZmxvYXQgZG90VEwsIGNvbnN0IGluIGZsb2F0IGRvdEJMLCBjb25zdCBpbiBmbG9hdCBkb3ROViwgY29uc3QgaW4gZmxvYXQgZG90TkwgKSB7XFxuXFx0XFx0ZmxvYXQgZ3YgPSBkb3ROTCAqIGxlbmd0aCggdmVjMyggYWxwaGFUICogZG90VFYsIGFscGhhQiAqIGRvdEJWLCBkb3ROViApICk7XFxuXFx0XFx0ZmxvYXQgZ2wgPSBkb3ROViAqIGxlbmd0aCggdmVjMyggYWxwaGFUICogZG90VEwsIGFscGhhQiAqIGRvdEJMLCBkb3ROTCApICk7XFxuXFx0XFx0ZmxvYXQgdiA9IDAuNSAvICggZ3YgKyBnbCApO1xcblxcdFxcdHJldHVybiBzYXR1cmF0ZSh2KTtcXG5cXHR9XFxuXFx0ZmxvYXQgRF9HR1hfQW5pc290cm9waWMoIGNvbnN0IGluIGZsb2F0IGFscGhhVCwgY29uc3QgaW4gZmxvYXQgYWxwaGFCLCBjb25zdCBpbiBmbG9hdCBkb3ROSCwgY29uc3QgaW4gZmxvYXQgZG90VEgsIGNvbnN0IGluIGZsb2F0IGRvdEJIICkge1xcblxcdFxcdGZsb2F0IGEyID0gYWxwaGFUICogYWxwaGFCO1xcblxcdFxcdGhpZ2hwIHZlYzMgdiA9IHZlYzMoIGFscGhhQiAqIGRvdFRILCBhbHBoYVQgKiBkb3RCSCwgYTIgKiBkb3ROSCApO1xcblxcdFxcdGhpZ2hwIGZsb2F0IHYyID0gZG90KCB2LCB2ICk7XFxuXFx0XFx0ZmxvYXQgdzIgPSBhMiAvIHYyO1xcblxcdFxcdHJldHVybiBSRUNJUFJPQ0FMX1BJICogYTIgKiBwb3cyICggdzIgKTtcXG5cXHR9XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRcXG5cXHR2ZWMzIEJSREZfR0dYX0NsZWFyY29hdCggY29uc3QgaW4gdmVjMyBsaWdodERpciwgY29uc3QgaW4gdmVjMyB2aWV3RGlyLCBjb25zdCBpbiB2ZWMzIG5vcm1hbCwgY29uc3QgaW4gUGh5c2ljYWxNYXRlcmlhbCBtYXRlcmlhbCkge1xcblxcdFxcdHZlYzMgZjAgPSBtYXRlcmlhbC5jbGVhcmNvYXRGMDtcXG5cXHRcXHRmbG9hdCBmOTAgPSBtYXRlcmlhbC5jbGVhcmNvYXRGOTA7XFxuXFx0XFx0ZmxvYXQgcm91Z2huZXNzID0gbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzO1xcblxcdFxcdGZsb2F0IGFscGhhID0gcG93Miggcm91Z2huZXNzICk7XFxuXFx0XFx0dmVjMyBoYWxmRGlyID0gbm9ybWFsaXplKCBsaWdodERpciArIHZpZXdEaXIgKTtcXG5cXHRcXHRmbG9hdCBkb3ROTCA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgbGlnaHREaXIgKSApO1xcblxcdFxcdGZsb2F0IGRvdE5WID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCB2aWV3RGlyICkgKTtcXG5cXHRcXHRmbG9hdCBkb3ROSCA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgaGFsZkRpciApICk7XFxuXFx0XFx0ZmxvYXQgZG90VkggPSBzYXR1cmF0ZSggZG90KCB2aWV3RGlyLCBoYWxmRGlyICkgKTtcXG5cXHRcXHR2ZWMzIEYgPSBGX1NjaGxpY2soIGYwLCBmOTAsIGRvdFZIICk7XFxuXFx0XFx0ZmxvYXQgViA9IFZfR0dYX1NtaXRoQ29ycmVsYXRlZCggYWxwaGEsIGRvdE5MLCBkb3ROViApO1xcblxcdFxcdGZsb2F0IEQgPSBEX0dHWCggYWxwaGEsIGRvdE5IICk7XFxuXFx0XFx0cmV0dXJuIEYgKiAoIFYgKiBEICk7XFxuXFx0fVxcbiNlbmRpZlxcbnZlYzMgQlJERl9HR1goIGNvbnN0IGluIHZlYzMgbGlnaHREaXIsIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIFBoeXNpY2FsTWF0ZXJpYWwgbWF0ZXJpYWwgKSB7XFxuXFx0dmVjMyBmMCA9IG1hdGVyaWFsLnNwZWN1bGFyQ29sb3I7XFxuXFx0ZmxvYXQgZjkwID0gbWF0ZXJpYWwuc3BlY3VsYXJGOTA7XFxuXFx0ZmxvYXQgcm91Z2huZXNzID0gbWF0ZXJpYWwucm91Z2huZXNzO1xcblxcdGZsb2F0IGFscGhhID0gcG93Miggcm91Z2huZXNzICk7XFxuXFx0dmVjMyBoYWxmRGlyID0gbm9ybWFsaXplKCBsaWdodERpciArIHZpZXdEaXIgKTtcXG5cXHRmbG9hdCBkb3ROTCA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgbGlnaHREaXIgKSApO1xcblxcdGZsb2F0IGRvdE5WID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCB2aWV3RGlyICkgKTtcXG5cXHRmbG9hdCBkb3ROSCA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgaGFsZkRpciApICk7XFxuXFx0ZmxvYXQgZG90VkggPSBzYXR1cmF0ZSggZG90KCB2aWV3RGlyLCBoYWxmRGlyICkgKTtcXG5cXHR2ZWMzIEYgPSBGX1NjaGxpY2soIGYwLCBmOTAsIGRvdFZIICk7XFxuXFx0I2lmZGVmIFVTRV9JUklERVNDRU5DRVxcblxcdFxcdEYgPSBtaXgoIEYsIG1hdGVyaWFsLmlyaWRlc2NlbmNlRnJlc25lbCwgbWF0ZXJpYWwuaXJpZGVzY2VuY2UgKTtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlcXG5cXHRcXHRmbG9hdCBkb3RUTCA9IGRvdCggbWF0ZXJpYWwuYW5pc290cm9weVQsIGxpZ2h0RGlyICk7XFxuXFx0XFx0ZmxvYXQgZG90VFYgPSBkb3QoIG1hdGVyaWFsLmFuaXNvdHJvcHlULCB2aWV3RGlyICk7XFxuXFx0XFx0ZmxvYXQgZG90VEggPSBkb3QoIG1hdGVyaWFsLmFuaXNvdHJvcHlULCBoYWxmRGlyICk7XFxuXFx0XFx0ZmxvYXQgZG90QkwgPSBkb3QoIG1hdGVyaWFsLmFuaXNvdHJvcHlCLCBsaWdodERpciApO1xcblxcdFxcdGZsb2F0IGRvdEJWID0gZG90KCBtYXRlcmlhbC5hbmlzb3Ryb3B5Qiwgdmlld0RpciApO1xcblxcdFxcdGZsb2F0IGRvdEJIID0gZG90KCBtYXRlcmlhbC5hbmlzb3Ryb3B5QiwgaGFsZkRpciApO1xcblxcdFxcdGZsb2F0IFYgPSBWX0dHWF9TbWl0aENvcnJlbGF0ZWRfQW5pc290cm9waWMoIG1hdGVyaWFsLmFscGhhVCwgYWxwaGEsIGRvdFRWLCBkb3RCViwgZG90VEwsIGRvdEJMLCBkb3ROViwgZG90TkwgKTtcXG5cXHRcXHRmbG9hdCBEID0gRF9HR1hfQW5pc290cm9waWMoIG1hdGVyaWFsLmFscGhhVCwgYWxwaGEsIGRvdE5ILCBkb3RUSCwgZG90QkggKTtcXG5cXHQjZWxzZVxcblxcdFxcdGZsb2F0IFYgPSBWX0dHWF9TbWl0aENvcnJlbGF0ZWQoIGFscGhhLCBkb3ROTCwgZG90TlYgKTtcXG5cXHRcXHRmbG9hdCBEID0gRF9HR1goIGFscGhhLCBkb3ROSCApO1xcblxcdCNlbmRpZlxcblxcdHJldHVybiBGICogKCBWICogRCApO1xcbn1cXG52ZWMyIExUQ19VdiggY29uc3QgaW4gdmVjMyBOLCBjb25zdCBpbiB2ZWMzIFYsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcyApIHtcXG5cXHRjb25zdCBmbG9hdCBMVVRfU0laRSA9IDY0LjA7XFxuXFx0Y29uc3QgZmxvYXQgTFVUX1NDQUxFID0gKCBMVVRfU0laRSAtIDEuMCApIC8gTFVUX1NJWkU7XFxuXFx0Y29uc3QgZmxvYXQgTFVUX0JJQVMgPSAwLjUgLyBMVVRfU0laRTtcXG5cXHRmbG9hdCBkb3ROViA9IHNhdHVyYXRlKCBkb3QoIE4sIFYgKSApO1xcblxcdHZlYzIgdXYgPSB2ZWMyKCByb3VnaG5lc3MsIHNxcnQoIDEuMCAtIGRvdE5WICkgKTtcXG5cXHR1diA9IHV2ICogTFVUX1NDQUxFICsgTFVUX0JJQVM7XFxuXFx0cmV0dXJuIHV2O1xcbn1cXG5mbG9hdCBMVENfQ2xpcHBlZFNwaGVyZUZvcm1GYWN0b3IoIGNvbnN0IGluIHZlYzMgZiApIHtcXG5cXHRmbG9hdCBsID0gbGVuZ3RoKCBmICk7XFxuXFx0cmV0dXJuIG1heCggKCBsICogbCArIGYueiApIC8gKCBsICsgMS4wICksIDAuMCApO1xcbn1cXG52ZWMzIExUQ19FZGdlVmVjdG9yRm9ybUZhY3RvciggY29uc3QgaW4gdmVjMyB2MSwgY29uc3QgaW4gdmVjMyB2MiApIHtcXG5cXHRmbG9hdCB4ID0gZG90KCB2MSwgdjIgKTtcXG5cXHRmbG9hdCB5ID0gYWJzKCB4ICk7XFxuXFx0ZmxvYXQgYSA9IDAuODU0Mzk4NSArICggMC40OTY1MTU1ICsgMC4wMTQ1MjA2ICogeSApICogeTtcXG5cXHRmbG9hdCBiID0gMy40MTc1OTQwICsgKCA0LjE2MTY3MjQgKyB5ICkgKiB5O1xcblxcdGZsb2F0IHYgPSBhIC8gYjtcXG5cXHRmbG9hdCB0aGV0YV9zaW50aGV0YSA9ICggeCA+IDAuMCApID8gdiA6IDAuNSAqIGludmVyc2VzcXJ0KCBtYXgoIDEuMCAtIHggKiB4LCAxZS03ICkgKSAtIHY7XFxuXFx0cmV0dXJuIGNyb3NzKCB2MSwgdjIgKSAqIHRoZXRhX3NpbnRoZXRhO1xcbn1cXG52ZWMzIExUQ19FdmFsdWF0ZSggY29uc3QgaW4gdmVjMyBOLCBjb25zdCBpbiB2ZWMzIFYsIGNvbnN0IGluIHZlYzMgUCwgY29uc3QgaW4gbWF0MyBtSW52LCBjb25zdCBpbiB2ZWMzIHJlY3RDb29yZHNbIDQgXSApIHtcXG5cXHR2ZWMzIHYxID0gcmVjdENvb3Jkc1sgMSBdIC0gcmVjdENvb3Jkc1sgMCBdO1xcblxcdHZlYzMgdjIgPSByZWN0Q29vcmRzWyAzIF0gLSByZWN0Q29vcmRzWyAwIF07XFxuXFx0dmVjMyBsaWdodE5vcm1hbCA9IGNyb3NzKCB2MSwgdjIgKTtcXG5cXHRpZiggZG90KCBsaWdodE5vcm1hbCwgUCAtIHJlY3RDb29yZHNbIDAgXSApIDwgMC4wICkgcmV0dXJuIHZlYzMoIDAuMCApO1xcblxcdHZlYzMgVDEsIFQyO1xcblxcdFQxID0gbm9ybWFsaXplKCBWIC0gTiAqIGRvdCggViwgTiApICk7XFxuXFx0VDIgPSAtIGNyb3NzKCBOLCBUMSApO1xcblxcdG1hdDMgbWF0ID0gbUludiAqIHRyYW5zcG9zZU1hdDMoIG1hdDMoIFQxLCBUMiwgTiApICk7XFxuXFx0dmVjMyBjb29yZHNbIDQgXTtcXG5cXHRjb29yZHNbIDAgXSA9IG1hdCAqICggcmVjdENvb3Jkc1sgMCBdIC0gUCApO1xcblxcdGNvb3Jkc1sgMSBdID0gbWF0ICogKCByZWN0Q29vcmRzWyAxIF0gLSBQICk7XFxuXFx0Y29vcmRzWyAyIF0gPSBtYXQgKiAoIHJlY3RDb29yZHNbIDIgXSAtIFAgKTtcXG5cXHRjb29yZHNbIDMgXSA9IG1hdCAqICggcmVjdENvb3Jkc1sgMyBdIC0gUCApO1xcblxcdGNvb3Jkc1sgMCBdID0gbm9ybWFsaXplKCBjb29yZHNbIDAgXSApO1xcblxcdGNvb3Jkc1sgMSBdID0gbm9ybWFsaXplKCBjb29yZHNbIDEgXSApO1xcblxcdGNvb3Jkc1sgMiBdID0gbm9ybWFsaXplKCBjb29yZHNbIDIgXSApO1xcblxcdGNvb3Jkc1sgMyBdID0gbm9ybWFsaXplKCBjb29yZHNbIDMgXSApO1xcblxcdHZlYzMgdmVjdG9yRm9ybUZhY3RvciA9IHZlYzMoIDAuMCApO1xcblxcdHZlY3RvckZvcm1GYWN0b3IgKz0gTFRDX0VkZ2VWZWN0b3JGb3JtRmFjdG9yKCBjb29yZHNbIDAgXSwgY29vcmRzWyAxIF0gKTtcXG5cXHR2ZWN0b3JGb3JtRmFjdG9yICs9IExUQ19FZGdlVmVjdG9yRm9ybUZhY3RvciggY29vcmRzWyAxIF0sIGNvb3Jkc1sgMiBdICk7XFxuXFx0dmVjdG9yRm9ybUZhY3RvciArPSBMVENfRWRnZVZlY3RvckZvcm1GYWN0b3IoIGNvb3Jkc1sgMiBdLCBjb29yZHNbIDMgXSApO1xcblxcdHZlY3RvckZvcm1GYWN0b3IgKz0gTFRDX0VkZ2VWZWN0b3JGb3JtRmFjdG9yKCBjb29yZHNbIDMgXSwgY29vcmRzWyAwIF0gKTtcXG5cXHRmbG9hdCByZXN1bHQgPSBMVENfQ2xpcHBlZFNwaGVyZUZvcm1GYWN0b3IoIHZlY3RvckZvcm1GYWN0b3IgKTtcXG5cXHRyZXR1cm4gdmVjMyggcmVzdWx0ICk7XFxufVxcbiNpZiBkZWZpbmVkKCBVU0VfU0hFRU4gKVxcbmZsb2F0IERfQ2hhcmxpZSggZmxvYXQgcm91Z2huZXNzLCBmbG9hdCBkb3ROSCApIHtcXG5cXHRmbG9hdCBhbHBoYSA9IHBvdzIoIHJvdWdobmVzcyApO1xcblxcdGZsb2F0IGludkFscGhhID0gMS4wIC8gYWxwaGE7XFxuXFx0ZmxvYXQgY29zMmggPSBkb3ROSCAqIGRvdE5IO1xcblxcdGZsb2F0IHNpbjJoID0gbWF4KCAxLjAgLSBjb3MyaCwgMC4wMDc4MTI1ICk7XFxuXFx0cmV0dXJuICggMi4wICsgaW52QWxwaGEgKSAqIHBvdyggc2luMmgsIGludkFscGhhICogMC41ICkgLyAoIDIuMCAqIFBJICk7XFxufVxcbmZsb2F0IFZfTmV1YmVsdCggZmxvYXQgZG90TlYsIGZsb2F0IGRvdE5MICkge1xcblxcdHJldHVybiBzYXR1cmF0ZSggMS4wIC8gKCA0LjAgKiAoIGRvdE5MICsgZG90TlYgLSBkb3ROTCAqIGRvdE5WICkgKSApO1xcbn1cXG52ZWMzIEJSREZfU2hlZW4oIGNvbnN0IGluIHZlYzMgbGlnaHREaXIsIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gdmVjMyBub3JtYWwsIHZlYzMgc2hlZW5Db2xvciwgY29uc3QgaW4gZmxvYXQgc2hlZW5Sb3VnaG5lc3MgKSB7XFxuXFx0dmVjMyBoYWxmRGlyID0gbm9ybWFsaXplKCBsaWdodERpciArIHZpZXdEaXIgKTtcXG5cXHRmbG9hdCBkb3ROTCA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgbGlnaHREaXIgKSApO1xcblxcdGZsb2F0IGRvdE5WID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCB2aWV3RGlyICkgKTtcXG5cXHRmbG9hdCBkb3ROSCA9IHNhdHVyYXRlKCBkb3QoIG5vcm1hbCwgaGFsZkRpciApICk7XFxuXFx0ZmxvYXQgRCA9IERfQ2hhcmxpZSggc2hlZW5Sb3VnaG5lc3MsIGRvdE5IICk7XFxuXFx0ZmxvYXQgViA9IFZfTmV1YmVsdCggZG90TlYsIGRvdE5MICk7XFxuXFx0cmV0dXJuIHNoZWVuQ29sb3IgKiAoIEQgKiBWICk7XFxufVxcbiNlbmRpZlxcbmZsb2F0IElCTFNoZWVuQlJERiggY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzICkge1xcblxcdGZsb2F0IGRvdE5WID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCB2aWV3RGlyICkgKTtcXG5cXHRmbG9hdCByMiA9IHJvdWdobmVzcyAqIHJvdWdobmVzcztcXG5cXHRmbG9hdCBhID0gcm91Z2huZXNzIDwgMC4yNSA/IC0zMzkuMiAqIHIyICsgMTYxLjQgKiByb3VnaG5lc3MgLSAyNS45IDogLTguNDggKiByMiArIDE0LjMgKiByb3VnaG5lc3MgLSA5Ljk1O1xcblxcdGZsb2F0IGIgPSByb3VnaG5lc3MgPCAwLjI1ID8gNDQuMCAqIHIyIC0gMjMuNyAqIHJvdWdobmVzcyArIDMuMjYgOiAxLjk3ICogcjIgLSAzLjI3ICogcm91Z2huZXNzICsgMC43MjtcXG5cXHRmbG9hdCBERyA9IGV4cCggYSAqIGRvdE5WICsgYiApICsgKCByb3VnaG5lc3MgPCAwLjI1ID8gMC4wIDogMC4xICogKCByb3VnaG5lc3MgLSAwLjI1ICkgKTtcXG5cXHRyZXR1cm4gc2F0dXJhdGUoIERHICogUkVDSVBST0NBTF9QSSApO1xcbn1cXG52ZWMyIERGR0FwcHJveCggY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzICkge1xcblxcdGZsb2F0IGRvdE5WID0gc2F0dXJhdGUoIGRvdCggbm9ybWFsLCB2aWV3RGlyICkgKTtcXG5cXHRjb25zdCB2ZWM0IGMwID0gdmVjNCggLSAxLCAtIDAuMDI3NSwgLSAwLjU3MiwgMC4wMjIgKTtcXG5cXHRjb25zdCB2ZWM0IGMxID0gdmVjNCggMSwgMC4wNDI1LCAxLjA0LCAtIDAuMDQgKTtcXG5cXHR2ZWM0IHIgPSByb3VnaG5lc3MgKiBjMCArIGMxO1xcblxcdGZsb2F0IGEwMDQgPSBtaW4oIHIueCAqIHIueCwgZXhwMiggLSA5LjI4ICogZG90TlYgKSApICogci54ICsgci55O1xcblxcdHZlYzIgZmFiID0gdmVjMiggLSAxLjA0LCAxLjA0ICkgKiBhMDA0ICsgci56dztcXG5cXHRyZXR1cm4gZmFiO1xcbn1cXG52ZWMzIEVudmlyb25tZW50QlJERiggY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gdmVjMyBzcGVjdWxhckNvbG9yLCBjb25zdCBpbiBmbG9hdCBzcGVjdWxhckY5MCwgY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzICkge1xcblxcdHZlYzIgZmFiID0gREZHQXBwcm94KCBub3JtYWwsIHZpZXdEaXIsIHJvdWdobmVzcyApO1xcblxcdHJldHVybiBzcGVjdWxhckNvbG9yICogZmFiLnggKyBzcGVjdWxhckY5MCAqIGZhYi55O1xcbn1cXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFXFxudm9pZCBjb21wdXRlTXVsdGlzY2F0dGVyaW5nSXJpZGVzY2VuY2UoIGNvbnN0IGluIHZlYzMgbm9ybWFsLCBjb25zdCBpbiB2ZWMzIHZpZXdEaXIsIGNvbnN0IGluIHZlYzMgc3BlY3VsYXJDb2xvciwgY29uc3QgaW4gZmxvYXQgc3BlY3VsYXJGOTAsIGNvbnN0IGluIGZsb2F0IGlyaWRlc2NlbmNlLCBjb25zdCBpbiB2ZWMzIGlyaWRlc2NlbmNlRjAsIGNvbnN0IGluIGZsb2F0IHJvdWdobmVzcywgaW5vdXQgdmVjMyBzaW5nbGVTY2F0dGVyLCBpbm91dCB2ZWMzIG11bHRpU2NhdHRlciApIHtcXG4jZWxzZVxcbnZvaWQgY29tcHV0ZU11bHRpc2NhdHRlcmluZyggY29uc3QgaW4gdmVjMyBub3JtYWwsIGNvbnN0IGluIHZlYzMgdmlld0RpciwgY29uc3QgaW4gdmVjMyBzcGVjdWxhckNvbG9yLCBjb25zdCBpbiBmbG9hdCBzcGVjdWxhckY5MCwgY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzLCBpbm91dCB2ZWMzIHNpbmdsZVNjYXR0ZXIsIGlub3V0IHZlYzMgbXVsdGlTY2F0dGVyICkge1xcbiNlbmRpZlxcblxcdHZlYzIgZmFiID0gREZHQXBwcm94KCBub3JtYWwsIHZpZXdEaXIsIHJvdWdobmVzcyApO1xcblxcdCNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcXG5cXHRcXHR2ZWMzIEZyID0gbWl4KCBzcGVjdWxhckNvbG9yLCBpcmlkZXNjZW5jZUYwLCBpcmlkZXNjZW5jZSApO1xcblxcdCNlbHNlXFxuXFx0XFx0dmVjMyBGciA9IHNwZWN1bGFyQ29sb3I7XFxuXFx0I2VuZGlmXFxuXFx0dmVjMyBGc3NFc3MgPSBGciAqIGZhYi54ICsgc3BlY3VsYXJGOTAgKiBmYWIueTtcXG5cXHRmbG9hdCBFc3MgPSBmYWIueCArIGZhYi55O1xcblxcdGZsb2F0IEVtcyA9IDEuMCAtIEVzcztcXG5cXHR2ZWMzIEZhdmcgPSBGciArICggMS4wIC0gRnIgKSAqIDAuMDQ3NjE5O1xcdHZlYzMgRm1zID0gRnNzRXNzICogRmF2ZyAvICggMS4wIC0gRW1zICogRmF2ZyApO1xcblxcdHNpbmdsZVNjYXR0ZXIgKz0gRnNzRXNzO1xcblxcdG11bHRpU2NhdHRlciArPSBGbXMgKiBFbXM7XFxufVxcbiNpZiBOVU1fUkVDVF9BUkVBX0xJR0hUUyA+IDBcXG5cXHR2b2lkIFJFX0RpcmVjdF9SZWN0QXJlYV9QaHlzaWNhbCggY29uc3QgaW4gUmVjdEFyZWFMaWdodCByZWN0QXJlYUxpZ2h0LCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5UG9zaXRpb24sIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlOb3JtYWwsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlWaWV3RGlyLCBjb25zdCBpbiB2ZWMzIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBjb25zdCBpbiBQaHlzaWNhbE1hdGVyaWFsIG1hdGVyaWFsLCBpbm91dCBSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCApIHtcXG5cXHRcXHR2ZWMzIG5vcm1hbCA9IGdlb21ldHJ5Tm9ybWFsO1xcblxcdFxcdHZlYzMgdmlld0RpciA9IGdlb21ldHJ5Vmlld0RpcjtcXG5cXHRcXHR2ZWMzIHBvc2l0aW9uID0gZ2VvbWV0cnlQb3NpdGlvbjtcXG5cXHRcXHR2ZWMzIGxpZ2h0UG9zID0gcmVjdEFyZWFMaWdodC5wb3NpdGlvbjtcXG5cXHRcXHR2ZWMzIGhhbGZXaWR0aCA9IHJlY3RBcmVhTGlnaHQuaGFsZldpZHRoO1xcblxcdFxcdHZlYzMgaGFsZkhlaWdodCA9IHJlY3RBcmVhTGlnaHQuaGFsZkhlaWdodDtcXG5cXHRcXHR2ZWMzIGxpZ2h0Q29sb3IgPSByZWN0QXJlYUxpZ2h0LmNvbG9yO1xcblxcdFxcdGZsb2F0IHJvdWdobmVzcyA9IG1hdGVyaWFsLnJvdWdobmVzcztcXG5cXHRcXHR2ZWMzIHJlY3RDb29yZHNbIDQgXTtcXG5cXHRcXHRyZWN0Q29vcmRzWyAwIF0gPSBsaWdodFBvcyArIGhhbGZXaWR0aCAtIGhhbGZIZWlnaHQ7XFx0XFx0cmVjdENvb3Jkc1sgMSBdID0gbGlnaHRQb3MgLSBoYWxmV2lkdGggLSBoYWxmSGVpZ2h0O1xcblxcdFxcdHJlY3RDb29yZHNbIDIgXSA9IGxpZ2h0UG9zIC0gaGFsZldpZHRoICsgaGFsZkhlaWdodDtcXG5cXHRcXHRyZWN0Q29vcmRzWyAzIF0gPSBsaWdodFBvcyArIGhhbGZXaWR0aCArIGhhbGZIZWlnaHQ7XFxuXFx0XFx0dmVjMiB1diA9IExUQ19Vdiggbm9ybWFsLCB2aWV3RGlyLCByb3VnaG5lc3MgKTtcXG5cXHRcXHR2ZWM0IHQxID0gdGV4dHVyZTJEKCBsdGNfMSwgdXYgKTtcXG5cXHRcXHR2ZWM0IHQyID0gdGV4dHVyZTJEKCBsdGNfMiwgdXYgKTtcXG5cXHRcXHRtYXQzIG1JbnYgPSBtYXQzKFxcblxcdFxcdFxcdHZlYzMoIHQxLngsIDAsIHQxLnkgKSxcXG5cXHRcXHRcXHR2ZWMzKCAgICAwLCAxLCAgICAwICksXFxuXFx0XFx0XFx0dmVjMyggdDEueiwgMCwgdDEudyApXFxuXFx0XFx0KTtcXG5cXHRcXHR2ZWMzIGZyZXNuZWwgPSAoIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgKiB0Mi54ICsgKCB2ZWMzKCAxLjAgKSAtIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgKSAqIHQyLnkgKTtcXG5cXHRcXHRyZWZsZWN0ZWRMaWdodC5kaXJlY3RTcGVjdWxhciArPSBsaWdodENvbG9yICogZnJlc25lbCAqIExUQ19FdmFsdWF0ZSggbm9ybWFsLCB2aWV3RGlyLCBwb3NpdGlvbiwgbUludiwgcmVjdENvb3JkcyApO1xcblxcdFxcdHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKz0gbGlnaHRDb2xvciAqIG1hdGVyaWFsLmRpZmZ1c2VDb2xvciAqIExUQ19FdmFsdWF0ZSggbm9ybWFsLCB2aWV3RGlyLCBwb3NpdGlvbiwgbWF0MyggMS4wICksIHJlY3RDb29yZHMgKTtcXG5cXHR9XFxuI2VuZGlmXFxudm9pZCBSRV9EaXJlY3RfUGh5c2ljYWwoIGNvbnN0IGluIEluY2lkZW50TGlnaHQgZGlyZWN0TGlnaHQsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeU5vcm1hbCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVZpZXdEaXIsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGNvbnN0IGluIFBoeXNpY2FsTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xcblxcdGZsb2F0IGRvdE5MID0gc2F0dXJhdGUoIGRvdCggZ2VvbWV0cnlOb3JtYWwsIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiApICk7XFxuXFx0dmVjMyBpcnJhZGlhbmNlID0gZG90TkwgKiBkaXJlY3RMaWdodC5jb2xvcjtcXG5cXHQjaWZkZWYgVVNFX0NMRUFSQ09BVFxcblxcdFxcdGZsb2F0IGRvdE5MY2MgPSBzYXR1cmF0ZSggZG90KCBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgZGlyZWN0TGlnaHQuZGlyZWN0aW9uICkgKTtcXG5cXHRcXHR2ZWMzIGNjSXJyYWRpYW5jZSA9IGRvdE5MY2MgKiBkaXJlY3RMaWdodC5jb2xvcjtcXG5cXHRcXHRjbGVhcmNvYXRTcGVjdWxhckRpcmVjdCArPSBjY0lycmFkaWFuY2UgKiBCUkRGX0dHWF9DbGVhcmNvYXQoIGRpcmVjdExpZ2h0LmRpcmVjdGlvbiwgZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgbWF0ZXJpYWwgKTtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX1NIRUVOXFxuXFx0XFx0c2hlZW5TcGVjdWxhckRpcmVjdCArPSBpcnJhZGlhbmNlICogQlJERl9TaGVlbiggZGlyZWN0TGlnaHQuZGlyZWN0aW9uLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Tm9ybWFsLCBtYXRlcmlhbC5zaGVlbkNvbG9yLCBtYXRlcmlhbC5zaGVlblJvdWdobmVzcyApO1xcblxcdCNlbmRpZlxcblxcdHJlZmxlY3RlZExpZ2h0LmRpcmVjdFNwZWN1bGFyICs9IGlycmFkaWFuY2UgKiBCUkRGX0dHWCggZGlyZWN0TGlnaHQuZGlyZWN0aW9uLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Tm9ybWFsLCBtYXRlcmlhbCApO1xcblxcdHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKz0gaXJyYWRpYW5jZSAqIEJSREZfTGFtYmVydCggbWF0ZXJpYWwuZGlmZnVzZUNvbG9yICk7XFxufVxcbnZvaWQgUkVfSW5kaXJlY3REaWZmdXNlX1BoeXNpY2FsKCBjb25zdCBpbiB2ZWMzIGlycmFkaWFuY2UsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeU5vcm1hbCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVZpZXdEaXIsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGNvbnN0IGluIFBoeXNpY2FsTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ICkge1xcblxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSArPSBpcnJhZGlhbmNlICogQlJERl9MYW1iZXJ0KCBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKTtcXG59XFxudm9pZCBSRV9JbmRpcmVjdFNwZWN1bGFyX1BoeXNpY2FsKCBjb25zdCBpbiB2ZWMzIHJhZGlhbmNlLCBjb25zdCBpbiB2ZWMzIGlycmFkaWFuY2UsIGNvbnN0IGluIHZlYzMgY2xlYXJjb2F0UmFkaWFuY2UsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlQb3NpdGlvbiwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeU5vcm1hbCwgY29uc3QgaW4gdmVjMyBnZW9tZXRyeVZpZXdEaXIsIGNvbnN0IGluIHZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIGNvbnN0IGluIFBoeXNpY2FsTWF0ZXJpYWwgbWF0ZXJpYWwsIGlub3V0IFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0KSB7XFxuXFx0I2lmZGVmIFVTRV9DTEVBUkNPQVRcXG5cXHRcXHRjbGVhcmNvYXRTcGVjdWxhckluZGlyZWN0ICs9IGNsZWFyY29hdFJhZGlhbmNlICogRW52aXJvbm1lbnRCUkRGKCBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBtYXRlcmlhbC5jbGVhcmNvYXRGMCwgbWF0ZXJpYWwuY2xlYXJjb2F0RjkwLCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgKTtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX1NIRUVOXFxuXFx0XFx0c2hlZW5TcGVjdWxhckluZGlyZWN0ICs9IGlycmFkaWFuY2UgKiBtYXRlcmlhbC5zaGVlbkNvbG9yICogSUJMU2hlZW5CUkRGKCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBtYXRlcmlhbC5zaGVlblJvdWdobmVzcyApO1xcblxcdCNlbmRpZlxcblxcdHZlYzMgc2luZ2xlU2NhdHRlcmluZyA9IHZlYzMoIDAuMCApO1xcblxcdHZlYzMgbXVsdGlTY2F0dGVyaW5nID0gdmVjMyggMC4wICk7XFxuXFx0dmVjMyBjb3NpbmVXZWlnaHRlZElycmFkaWFuY2UgPSBpcnJhZGlhbmNlICogUkVDSVBST0NBTF9QSTtcXG5cXHQjaWZkZWYgVVNFX0lSSURFU0NFTkNFXFxuXFx0XFx0Y29tcHV0ZU11bHRpc2NhdHRlcmluZ0lyaWRlc2NlbmNlKCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBtYXRlcmlhbC5zcGVjdWxhckNvbG9yLCBtYXRlcmlhbC5zcGVjdWxhckY5MCwgbWF0ZXJpYWwuaXJpZGVzY2VuY2UsIG1hdGVyaWFsLmlyaWRlc2NlbmNlRnJlc25lbCwgbWF0ZXJpYWwucm91Z2huZXNzLCBzaW5nbGVTY2F0dGVyaW5nLCBtdWx0aVNjYXR0ZXJpbmcgKTtcXG5cXHQjZWxzZVxcblxcdFxcdGNvbXB1dGVNdWx0aXNjYXR0ZXJpbmcoIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IsIG1hdGVyaWFsLnNwZWN1bGFyRjkwLCBtYXRlcmlhbC5yb3VnaG5lc3MsIHNpbmdsZVNjYXR0ZXJpbmcsIG11bHRpU2NhdHRlcmluZyApO1xcblxcdCNlbmRpZlxcblxcdHZlYzMgdG90YWxTY2F0dGVyaW5nID0gc2luZ2xlU2NhdHRlcmluZyArIG11bHRpU2NhdHRlcmluZztcXG5cXHR2ZWMzIGRpZmZ1c2UgPSBtYXRlcmlhbC5kaWZmdXNlQ29sb3IgKiAoIDEuMCAtIG1heCggbWF4KCB0b3RhbFNjYXR0ZXJpbmcuciwgdG90YWxTY2F0dGVyaW5nLmcgKSwgdG90YWxTY2F0dGVyaW5nLmIgKSApO1xcblxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0U3BlY3VsYXIgKz0gcmFkaWFuY2UgKiBzaW5nbGVTY2F0dGVyaW5nO1xcblxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0U3BlY3VsYXIgKz0gbXVsdGlTY2F0dGVyaW5nICogY29zaW5lV2VpZ2h0ZWRJcnJhZGlhbmNlO1xcblxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSArPSBkaWZmdXNlICogY29zaW5lV2VpZ2h0ZWRJcnJhZGlhbmNlO1xcbn1cXG4jZGVmaW5lIFJFX0RpcmVjdFxcdFxcdFxcdFxcdFJFX0RpcmVjdF9QaHlzaWNhbFxcbiNkZWZpbmUgUkVfRGlyZWN0X1JlY3RBcmVhXFx0XFx0UkVfRGlyZWN0X1JlY3RBcmVhX1BoeXNpY2FsXFxuI2RlZmluZSBSRV9JbmRpcmVjdERpZmZ1c2VcXHRcXHRSRV9JbmRpcmVjdERpZmZ1c2VfUGh5c2ljYWxcXG4jZGVmaW5lIFJFX0luZGlyZWN0U3BlY3VsYXJcXHRcXHRSRV9JbmRpcmVjdFNwZWN1bGFyX1BoeXNpY2FsXFxuZmxvYXQgY29tcHV0ZVNwZWN1bGFyT2NjbHVzaW9uKCBjb25zdCBpbiBmbG9hdCBkb3ROViwgY29uc3QgaW4gZmxvYXQgYW1iaWVudE9jY2x1c2lvbiwgY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzICkge1xcblxcdHJldHVybiBzYXR1cmF0ZSggcG93KCBkb3ROViArIGFtYmllbnRPY2NsdXNpb24sIGV4cDIoIC0gMTYuMCAqIHJvdWdobmVzcyAtIDEuMCApICkgLSAxLjAgKyBhbWJpZW50T2NjbHVzaW9uICk7XFxufVwiO1xuXG52YXIgbGlnaHRzX2ZyYWdtZW50X2JlZ2luID0gXCJcXG52ZWMzIGdlb21ldHJ5UG9zaXRpb24gPSAtIHZWaWV3UG9zaXRpb247XFxudmVjMyBnZW9tZXRyeU5vcm1hbCA9IG5vcm1hbDtcXG52ZWMzIGdlb21ldHJ5Vmlld0RpciA9ICggaXNPcnRob2dyYXBoaWMgKSA/IHZlYzMoIDAsIDAsIDEgKSA6IG5vcm1hbGl6ZSggdlZpZXdQb3NpdGlvbiApO1xcbnZlYzMgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwgPSB2ZWMzKCAwLjAgKTtcXG4jaWZkZWYgVVNFX0NMRUFSQ09BVFxcblxcdGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsID0gY2xlYXJjb2F0Tm9ybWFsO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VcXG5cXHRmbG9hdCBkb3ROVmkgPSBzYXR1cmF0ZSggZG90KCBub3JtYWwsIGdlb21ldHJ5Vmlld0RpciApICk7XFxuXFx0aWYgKCBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzcyA9PSAwLjAgKSB7XFxuXFx0XFx0bWF0ZXJpYWwuaXJpZGVzY2VuY2UgPSAwLjA7XFxuXFx0fSBlbHNlIHtcXG5cXHRcXHRtYXRlcmlhbC5pcmlkZXNjZW5jZSA9IHNhdHVyYXRlKCBtYXRlcmlhbC5pcmlkZXNjZW5jZSApO1xcblxcdH1cXG5cXHRpZiAoIG1hdGVyaWFsLmlyaWRlc2NlbmNlID4gMC4wICkge1xcblxcdFxcdG1hdGVyaWFsLmlyaWRlc2NlbmNlRnJlc25lbCA9IGV2YWxJcmlkZXNjZW5jZSggMS4wLCBtYXRlcmlhbC5pcmlkZXNjZW5jZUlPUiwgZG90TlZpLCBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzcywgbWF0ZXJpYWwuc3BlY3VsYXJDb2xvciApO1xcblxcdFxcdG1hdGVyaWFsLmlyaWRlc2NlbmNlRjAgPSBTY2hsaWNrX3RvX0YwKCBtYXRlcmlhbC5pcmlkZXNjZW5jZUZyZXNuZWwsIDEuMCwgZG90TlZpICk7XFxuXFx0fVxcbiNlbmRpZlxcbkluY2lkZW50TGlnaHQgZGlyZWN0TGlnaHQ7XFxuI2lmICggTlVNX1BPSU5UX0xJR0hUUyA+IDAgKSAmJiBkZWZpbmVkKCBSRV9EaXJlY3QgKVxcblxcdFBvaW50TGlnaHQgcG9pbnRMaWdodDtcXG5cXHQjaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTID4gMFxcblxcdFBvaW50TGlnaHRTaGFkb3cgcG9pbnRMaWdodFNoYWRvdztcXG5cXHQjZW5kaWZcXG5cXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XFxuXFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX1BPSU5UX0xJR0hUUzsgaSArKyApIHtcXG5cXHRcXHRwb2ludExpZ2h0ID0gcG9pbnRMaWdodHNbIGkgXTtcXG5cXHRcXHRnZXRQb2ludExpZ2h0SW5mbyggcG9pbnRMaWdodCwgZ2VvbWV0cnlQb3NpdGlvbiwgZGlyZWN0TGlnaHQgKTtcXG5cXHRcXHQjaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmICggVU5ST0xMRURfTE9PUF9JTkRFWCA8IE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIClcXG5cXHRcXHRwb2ludExpZ2h0U2hhZG93ID0gcG9pbnRMaWdodFNoYWRvd3NbIGkgXTtcXG5cXHRcXHRkaXJlY3RMaWdodC5jb2xvciAqPSAoIGRpcmVjdExpZ2h0LnZpc2libGUgJiYgcmVjZWl2ZVNoYWRvdyApID8gZ2V0UG9pbnRTaGFkb3coIHBvaW50U2hhZG93TWFwWyBpIF0sIHBvaW50TGlnaHRTaGFkb3cuc2hhZG93TWFwU2l6ZSwgcG9pbnRMaWdodFNoYWRvdy5zaGFkb3dJbnRlbnNpdHksIHBvaW50TGlnaHRTaGFkb3cuc2hhZG93QmlhcywgcG9pbnRMaWdodFNoYWRvdy5zaGFkb3dSYWRpdXMsIHZQb2ludFNoYWRvd0Nvb3JkWyBpIF0sIHBvaW50TGlnaHRTaGFkb3cuc2hhZG93Q2FtZXJhTmVhciwgcG9pbnRMaWdodFNoYWRvdy5zaGFkb3dDYW1lcmFGYXIgKSA6IDEuMDtcXG5cXHRcXHQjZW5kaWZcXG5cXHRcXHRSRV9EaXJlY3QoIGRpcmVjdExpZ2h0LCBnZW9tZXRyeVBvc2l0aW9uLCBnZW9tZXRyeU5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyLCBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgbWF0ZXJpYWwsIHJlZmxlY3RlZExpZ2h0ICk7XFxuXFx0fVxcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXFxuI2VuZGlmXFxuI2lmICggTlVNX1NQT1RfTElHSFRTID4gMCApICYmIGRlZmluZWQoIFJFX0RpcmVjdCApXFxuXFx0U3BvdExpZ2h0IHNwb3RMaWdodDtcXG5cXHR2ZWM0IHNwb3RDb2xvcjtcXG5cXHR2ZWMzIHNwb3RMaWdodENvb3JkO1xcblxcdGJvb2wgaW5TcG90TGlnaHRNYXA7XFxuXFx0I2lmIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKSAmJiBOVU1fU1BPVF9MSUdIVF9TSEFET1dTID4gMFxcblxcdFNwb3RMaWdodFNoYWRvdyBzcG90TGlnaHRTaGFkb3c7XFxuXFx0I2VuZGlmXFxuXFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxcblxcdGZvciAoIGludCBpID0gMDsgaSA8IE5VTV9TUE9UX0xJR0hUUzsgaSArKyApIHtcXG5cXHRcXHRzcG90TGlnaHQgPSBzcG90TGlnaHRzWyBpIF07XFxuXFx0XFx0Z2V0U3BvdExpZ2h0SW5mbyggc3BvdExpZ2h0LCBnZW9tZXRyeVBvc2l0aW9uLCBkaXJlY3RMaWdodCApO1xcblxcdFxcdCNpZiAoIFVOUk9MTEVEX0xPT1BfSU5ERVggPCBOVU1fU1BPVF9MSUdIVF9TSEFET1dTX1dJVEhfTUFQUyApXFxuXFx0XFx0I2RlZmluZSBTUE9UX0xJR0hUX01BUF9JTkRFWCBVTlJPTExFRF9MT09QX0lOREVYXFxuXFx0XFx0I2VsaWYgKCBVTlJPTExFRF9MT09QX0lOREVYIDwgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyApXFxuXFx0XFx0I2RlZmluZSBTUE9UX0xJR0hUX01BUF9JTkRFWCBOVU1fU1BPVF9MSUdIVF9NQVBTXFxuXFx0XFx0I2Vsc2VcXG5cXHRcXHQjZGVmaW5lIFNQT1RfTElHSFRfTUFQX0lOREVYICggVU5ST0xMRURfTE9PUF9JTkRFWCAtIE5VTV9TUE9UX0xJR0hUX1NIQURPV1MgKyBOVU1fU1BPVF9MSUdIVF9TSEFET1dTX1dJVEhfTUFQUyApXFxuXFx0XFx0I2VuZGlmXFxuXFx0XFx0I2lmICggU1BPVF9MSUdIVF9NQVBfSU5ERVggPCBOVU1fU1BPVF9MSUdIVF9NQVBTIClcXG5cXHRcXHRcXHRzcG90TGlnaHRDb29yZCA9IHZTcG90TGlnaHRDb29yZFsgaSBdLnh5eiAvIHZTcG90TGlnaHRDb29yZFsgaSBdLnc7XFxuXFx0XFx0XFx0aW5TcG90TGlnaHRNYXAgPSBhbGwoIGxlc3NUaGFuKCBhYnMoIHNwb3RMaWdodENvb3JkICogMi4gLSAxLiApLCB2ZWMzKCAxLjAgKSApICk7XFxuXFx0XFx0XFx0c3BvdENvbG9yID0gdGV4dHVyZTJEKCBzcG90TGlnaHRNYXBbIFNQT1RfTElHSFRfTUFQX0lOREVYIF0sIHNwb3RMaWdodENvb3JkLnh5ICk7XFxuXFx0XFx0XFx0ZGlyZWN0TGlnaHQuY29sb3IgPSBpblNwb3RMaWdodE1hcCA/IGRpcmVjdExpZ2h0LmNvbG9yICogc3BvdENvbG9yLnJnYiA6IGRpcmVjdExpZ2h0LmNvbG9yO1xcblxcdFxcdCNlbmRpZlxcblxcdFxcdCN1bmRlZiBTUE9UX0xJR0hUX01BUF9JTkRFWFxcblxcdFxcdCNpZiBkZWZpbmVkKCBVU0VfU0hBRE9XTUFQICkgJiYgKCBVTlJPTExFRF9MT09QX0lOREVYIDwgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyApXFxuXFx0XFx0c3BvdExpZ2h0U2hhZG93ID0gc3BvdExpZ2h0U2hhZG93c1sgaSBdO1xcblxcdFxcdGRpcmVjdExpZ2h0LmNvbG9yICo9ICggZGlyZWN0TGlnaHQudmlzaWJsZSAmJiByZWNlaXZlU2hhZG93ICkgPyBnZXRTaGFkb3coIHNwb3RTaGFkb3dNYXBbIGkgXSwgc3BvdExpZ2h0U2hhZG93LnNoYWRvd01hcFNpemUsIHNwb3RMaWdodFNoYWRvdy5zaGFkb3dJbnRlbnNpdHksIHNwb3RMaWdodFNoYWRvdy5zaGFkb3dCaWFzLCBzcG90TGlnaHRTaGFkb3cuc2hhZG93UmFkaXVzLCB2U3BvdExpZ2h0Q29vcmRbIGkgXSApIDogMS4wO1xcblxcdFxcdCNlbmRpZlxcblxcdFxcdFJFX0RpcmVjdCggZGlyZWN0TGlnaHQsIGdlb21ldHJ5UG9zaXRpb24sIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCwgcmVmbGVjdGVkTGlnaHQgKTtcXG5cXHR9XFxuXFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcXG4jZW5kaWZcXG4jaWYgKCBOVU1fRElSX0xJR0hUUyA+IDAgKSAmJiBkZWZpbmVkKCBSRV9EaXJlY3QgKVxcblxcdERpcmVjdGlvbmFsTGlnaHQgZGlyZWN0aW9uYWxMaWdodDtcXG5cXHQjaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApICYmIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHREaXJlY3Rpb25hbExpZ2h0U2hhZG93IGRpcmVjdGlvbmFsTGlnaHRTaGFkb3c7XFxuXFx0I2VuZGlmXFxuXFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxcblxcdGZvciAoIGludCBpID0gMDsgaSA8IE5VTV9ESVJfTElHSFRTOyBpICsrICkge1xcblxcdFxcdGRpcmVjdGlvbmFsTGlnaHQgPSBkaXJlY3Rpb25hbExpZ2h0c1sgaSBdO1xcblxcdFxcdGdldERpcmVjdGlvbmFsTGlnaHRJbmZvKCBkaXJlY3Rpb25hbExpZ2h0LCBkaXJlY3RMaWdodCApO1xcblxcdFxcdCNpZiBkZWZpbmVkKCBVU0VfU0hBRE9XTUFQICkgJiYgKCBVTlJPTExFRF9MT09QX0lOREVYIDwgTlVNX0RJUl9MSUdIVF9TSEFET1dTIClcXG5cXHRcXHRkaXJlY3Rpb25hbExpZ2h0U2hhZG93ID0gZGlyZWN0aW9uYWxMaWdodFNoYWRvd3NbIGkgXTtcXG5cXHRcXHRkaXJlY3RMaWdodC5jb2xvciAqPSAoIGRpcmVjdExpZ2h0LnZpc2libGUgJiYgcmVjZWl2ZVNoYWRvdyApID8gZ2V0U2hhZG93KCBkaXJlY3Rpb25hbFNoYWRvd01hcFsgaSBdLCBkaXJlY3Rpb25hbExpZ2h0U2hhZG93LnNoYWRvd01hcFNpemUsIGRpcmVjdGlvbmFsTGlnaHRTaGFkb3cuc2hhZG93SW50ZW5zaXR5LCBkaXJlY3Rpb25hbExpZ2h0U2hhZG93LnNoYWRvd0JpYXMsIGRpcmVjdGlvbmFsTGlnaHRTaGFkb3cuc2hhZG93UmFkaXVzLCB2RGlyZWN0aW9uYWxTaGFkb3dDb29yZFsgaSBdICkgOiAxLjA7XFxuXFx0XFx0I2VuZGlmXFxuXFx0XFx0UkVfRGlyZWN0KCBkaXJlY3RMaWdodCwgZ2VvbWV0cnlQb3NpdGlvbiwgZ2VvbWV0cnlOb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIG1hdGVyaWFsLCByZWZsZWN0ZWRMaWdodCApO1xcblxcdH1cXG5cXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxcbiNlbmRpZlxcbiNpZiAoIE5VTV9SRUNUX0FSRUFfTElHSFRTID4gMCApICYmIGRlZmluZWQoIFJFX0RpcmVjdF9SZWN0QXJlYSApXFxuXFx0UmVjdEFyZWFMaWdodCByZWN0QXJlYUxpZ2h0O1xcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcXG5cXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fUkVDVF9BUkVBX0xJR0hUUzsgaSArKyApIHtcXG5cXHRcXHRyZWN0QXJlYUxpZ2h0ID0gcmVjdEFyZWFMaWdodHNbIGkgXTtcXG5cXHRcXHRSRV9EaXJlY3RfUmVjdEFyZWEoIHJlY3RBcmVhTGlnaHQsIGdlb21ldHJ5UG9zaXRpb24sIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCwgcmVmbGVjdGVkTGlnaHQgKTtcXG5cXHR9XFxuXFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcXG4jZW5kaWZcXG4jaWYgZGVmaW5lZCggUkVfSW5kaXJlY3REaWZmdXNlIClcXG5cXHR2ZWMzIGlibElycmFkaWFuY2UgPSB2ZWMzKCAwLjAgKTtcXG5cXHR2ZWMzIGlycmFkaWFuY2UgPSBnZXRBbWJpZW50TGlnaHRJcnJhZGlhbmNlKCBhbWJpZW50TGlnaHRDb2xvciApO1xcblxcdCNpZiBkZWZpbmVkKCBVU0VfTElHSFRfUFJPQkVTIClcXG5cXHRcXHRpcnJhZGlhbmNlICs9IGdldExpZ2h0UHJvYmVJcnJhZGlhbmNlKCBsaWdodFByb2JlLCBnZW9tZXRyeU5vcm1hbCApO1xcblxcdCNlbmRpZlxcblxcdCNpZiAoIE5VTV9IRU1JX0xJR0hUUyA+IDAgKVxcblxcdFxcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcXG5cXHRcXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fSEVNSV9MSUdIVFM7IGkgKysgKSB7XFxuXFx0XFx0XFx0aXJyYWRpYW5jZSArPSBnZXRIZW1pc3BoZXJlTGlnaHRJcnJhZGlhbmNlKCBoZW1pc3BoZXJlTGlnaHRzWyBpIF0sIGdlb21ldHJ5Tm9ybWFsICk7XFxuXFx0XFx0fVxcblxcdFxcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXFxuXFx0I2VuZGlmXFxuI2VuZGlmXFxuI2lmIGRlZmluZWQoIFJFX0luZGlyZWN0U3BlY3VsYXIgKVxcblxcdHZlYzMgcmFkaWFuY2UgPSB2ZWMzKCAwLjAgKTtcXG5cXHR2ZWMzIGNsZWFyY29hdFJhZGlhbmNlID0gdmVjMyggMC4wICk7XFxuI2VuZGlmXCI7XG5cbnZhciBsaWdodHNfZnJhZ21lbnRfbWFwcyA9IFwiI2lmIGRlZmluZWQoIFJFX0luZGlyZWN0RGlmZnVzZSApXFxuXFx0I2lmZGVmIFVTRV9MSUdIVE1BUFxcblxcdFxcdHZlYzQgbGlnaHRNYXBUZXhlbCA9IHRleHR1cmUyRCggbGlnaHRNYXAsIHZMaWdodE1hcFV2ICk7XFxuXFx0XFx0dmVjMyBsaWdodE1hcElycmFkaWFuY2UgPSBsaWdodE1hcFRleGVsLnJnYiAqIGxpZ2h0TWFwSW50ZW5zaXR5O1xcblxcdFxcdGlycmFkaWFuY2UgKz0gbGlnaHRNYXBJcnJhZGlhbmNlO1xcblxcdCNlbmRpZlxcblxcdCNpZiBkZWZpbmVkKCBVU0VfRU5WTUFQICkgJiYgZGVmaW5lZCggU1RBTkRBUkQgKSAmJiBkZWZpbmVkKCBFTlZNQVBfVFlQRV9DVUJFX1VWIClcXG5cXHRcXHRpYmxJcnJhZGlhbmNlICs9IGdldElCTElycmFkaWFuY2UoIGdlb21ldHJ5Tm9ybWFsICk7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXFxuI2lmIGRlZmluZWQoIFVTRV9FTlZNQVAgKSAmJiBkZWZpbmVkKCBSRV9JbmRpcmVjdFNwZWN1bGFyIClcXG5cXHQjaWZkZWYgVVNFX0FOSVNPVFJPUFlcXG5cXHRcXHRyYWRpYW5jZSArPSBnZXRJQkxBbmlzb3Ryb3B5UmFkaWFuY2UoIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlOb3JtYWwsIG1hdGVyaWFsLnJvdWdobmVzcywgbWF0ZXJpYWwuYW5pc290cm9weUIsIG1hdGVyaWFsLmFuaXNvdHJvcHkgKTtcXG5cXHQjZWxzZVxcblxcdFxcdHJhZGlhbmNlICs9IGdldElCTFJhZGlhbmNlKCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Tm9ybWFsLCBtYXRlcmlhbC5yb3VnaG5lc3MgKTtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX0NMRUFSQ09BVFxcblxcdFxcdGNsZWFyY29hdFJhZGlhbmNlICs9IGdldElCTFJhZGlhbmNlKCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgKTtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcIjtcblxudmFyIGxpZ2h0c19mcmFnbWVudF9lbmQgPSBcIiNpZiBkZWZpbmVkKCBSRV9JbmRpcmVjdERpZmZ1c2UgKVxcblxcdFJFX0luZGlyZWN0RGlmZnVzZSggaXJyYWRpYW5jZSwgZ2VvbWV0cnlQb3NpdGlvbiwgZ2VvbWV0cnlOb3JtYWwsIGdlb21ldHJ5Vmlld0RpciwgZ2VvbWV0cnlDbGVhcmNvYXROb3JtYWwsIG1hdGVyaWFsLCByZWZsZWN0ZWRMaWdodCApO1xcbiNlbmRpZlxcbiNpZiBkZWZpbmVkKCBSRV9JbmRpcmVjdFNwZWN1bGFyIClcXG5cXHRSRV9JbmRpcmVjdFNwZWN1bGFyKCByYWRpYW5jZSwgaWJsSXJyYWRpYW5jZSwgY2xlYXJjb2F0UmFkaWFuY2UsIGdlb21ldHJ5UG9zaXRpb24sIGdlb21ldHJ5Tm9ybWFsLCBnZW9tZXRyeVZpZXdEaXIsIGdlb21ldHJ5Q2xlYXJjb2F0Tm9ybWFsLCBtYXRlcmlhbCwgcmVmbGVjdGVkTGlnaHQgKTtcXG4jZW5kaWZcIjtcblxudmFyIGxvZ2RlcHRoYnVmX2ZyYWdtZW50ID0gXCIjaWYgZGVmaW5lZCggVVNFX0xPR0RFUFRIQlVGIClcXG5cXHRnbF9GcmFnRGVwdGggPSB2SXNQZXJzcGVjdGl2ZSA9PSAwLjAgPyBnbF9GcmFnQ29vcmQueiA6IGxvZzIoIHZGcmFnRGVwdGggKSAqIGxvZ0RlcHRoQnVmRkMgKiAwLjU7XFxuI2VuZGlmXCI7XG5cbnZhciBsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50ID0gXCIjaWYgZGVmaW5lZCggVVNFX0xPR0RFUFRIQlVGIClcXG5cXHR1bmlmb3JtIGZsb2F0IGxvZ0RlcHRoQnVmRkM7XFxuXFx0dmFyeWluZyBmbG9hdCB2RnJhZ0RlcHRoO1xcblxcdHZhcnlpbmcgZmxvYXQgdklzUGVyc3BlY3RpdmU7XFxuI2VuZGlmXCI7XG5cbnZhciBsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9MT0dERVBUSEJVRlxcblxcdHZhcnlpbmcgZmxvYXQgdkZyYWdEZXB0aDtcXG5cXHR2YXJ5aW5nIGZsb2F0IHZJc1BlcnNwZWN0aXZlO1xcbiNlbmRpZlwiO1xuXG52YXIgbG9nZGVwdGhidWZfdmVydGV4ID0gXCIjaWZkZWYgVVNFX0xPR0RFUFRIQlVGXFxuXFx0dkZyYWdEZXB0aCA9IDEuMCArIGdsX1Bvc2l0aW9uLnc7XFxuXFx0dklzUGVyc3BlY3RpdmUgPSBmbG9hdCggaXNQZXJzcGVjdGl2ZU1hdHJpeCggcHJvamVjdGlvbk1hdHJpeCApICk7XFxuI2VuZGlmXCI7XG5cbnZhciBtYXBfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfTUFQXFxuXFx0dmVjNCBzYW1wbGVkRGlmZnVzZUNvbG9yID0gdGV4dHVyZTJEKCBtYXAsIHZNYXBVdiApO1xcblxcdCNpZmRlZiBERUNPREVfVklERU9fVEVYVFVSRVxcblxcdFxcdHNhbXBsZWREaWZmdXNlQ29sb3IgPSB2ZWM0KCBtaXgoIHBvdyggc2FtcGxlZERpZmZ1c2VDb2xvci5yZ2IgKiAwLjk0Nzg2NzI5ODYgKyB2ZWMzKCAwLjA1MjEzMjcwMTQgKSwgdmVjMyggMi40ICkgKSwgc2FtcGxlZERpZmZ1c2VDb2xvci5yZ2IgKiAwLjA3NzM5OTM4MDgsIHZlYzMoIGxlc3NUaGFuRXF1YWwoIHNhbXBsZWREaWZmdXNlQ29sb3IucmdiLCB2ZWMzKCAwLjA0MDQ1ICkgKSApICksIHNhbXBsZWREaWZmdXNlQ29sb3IudyApO1xcblxcdFxcblxcdCNlbmRpZlxcblxcdGRpZmZ1c2VDb2xvciAqPSBzYW1wbGVkRGlmZnVzZUNvbG9yO1xcbiNlbmRpZlwiO1xuXG52YXIgbWFwX3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgbWFwO1xcbiNlbmRpZlwiO1xuXG52YXIgbWFwX3BhcnRpY2xlX2ZyYWdtZW50ID0gXCIjaWYgZGVmaW5lZCggVVNFX01BUCApIHx8IGRlZmluZWQoIFVTRV9BTFBIQU1BUCApXFxuXFx0I2lmIGRlZmluZWQoIFVTRV9QT0lOVFNfVVYgKVxcblxcdFxcdHZlYzIgdXYgPSB2VXY7XFxuXFx0I2Vsc2VcXG5cXHRcXHR2ZWMyIHV2ID0gKCB1dlRyYW5zZm9ybSAqIHZlYzMoIGdsX1BvaW50Q29vcmQueCwgMS4wIC0gZ2xfUG9pbnRDb29yZC55LCAxICkgKS54eTtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX01BUFxcblxcdGRpZmZ1c2VDb2xvciAqPSB0ZXh0dXJlMkQoIG1hcCwgdXYgKTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0FMUEhBTUFQXFxuXFx0ZGlmZnVzZUNvbG9yLmEgKj0gdGV4dHVyZTJEKCBhbHBoYU1hcCwgdXYgKS5nO1xcbiNlbmRpZlwiO1xuXG52YXIgbWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQgPSBcIiNpZiBkZWZpbmVkKCBVU0VfUE9JTlRTX1VWIClcXG5cXHR2YXJ5aW5nIHZlYzIgdlV2O1xcbiNlbHNlXFxuXFx0I2lmIGRlZmluZWQoIFVTRV9NQVAgKSB8fCBkZWZpbmVkKCBVU0VfQUxQSEFNQVAgKVxcblxcdFxcdHVuaWZvcm0gbWF0MyB1dlRyYW5zZm9ybTtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX01BUFxcblxcdHVuaWZvcm0gc2FtcGxlcjJEIG1hcDtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0FMUEhBTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgYWxwaGFNYXA7XFxuI2VuZGlmXCI7XG5cbnZhciBtZXRhbG5lc3NtYXBfZnJhZ21lbnQgPSBcImZsb2F0IG1ldGFsbmVzc0ZhY3RvciA9IG1ldGFsbmVzcztcXG4jaWZkZWYgVVNFX01FVEFMTkVTU01BUFxcblxcdHZlYzQgdGV4ZWxNZXRhbG5lc3MgPSB0ZXh0dXJlMkQoIG1ldGFsbmVzc01hcCwgdk1ldGFsbmVzc01hcFV2ICk7XFxuXFx0bWV0YWxuZXNzRmFjdG9yICo9IHRleGVsTWV0YWxuZXNzLmI7XFxuI2VuZGlmXCI7XG5cbnZhciBtZXRhbG5lc3NtYXBfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9NRVRBTE5FU1NNQVBcXG5cXHR1bmlmb3JtIHNhbXBsZXIyRCBtZXRhbG5lc3NNYXA7XFxuI2VuZGlmXCI7XG5cbnZhciBtb3JwaGluc3RhbmNlX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9JTlNUQU5DSU5HX01PUlBIXFxuXFx0ZmxvYXQgbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBNT1JQSFRBUkdFVFNfQ09VTlQgXTtcXG5cXHRmbG9hdCBtb3JwaFRhcmdldEJhc2VJbmZsdWVuY2UgPSB0ZXhlbEZldGNoKCBtb3JwaFRleHR1cmUsIGl2ZWMyKCAwLCBnbF9JbnN0YW5jZUlEICksIDAgKS5yO1xcblxcdGZvciAoIGludCBpID0gMDsgaSA8IE1PUlBIVEFSR0VUU19DT1VOVDsgaSArKyApIHtcXG5cXHRcXHRtb3JwaFRhcmdldEluZmx1ZW5jZXNbaV0gPSAgdGV4ZWxGZXRjaCggbW9ycGhUZXh0dXJlLCBpdmVjMiggaSArIDEsIGdsX0luc3RhbmNlSUQgKSwgMCApLnI7XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgbW9ycGhjb2xvcl92ZXJ0ZXggPSBcIiNpZiBkZWZpbmVkKCBVU0VfTU9SUEhDT0xPUlMgKVxcblxcdHZDb2xvciAqPSBtb3JwaFRhcmdldEJhc2VJbmZsdWVuY2U7XFxuXFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTU9SUEhUQVJHRVRTX0NPVU5UOyBpICsrICkge1xcblxcdFxcdCNpZiBkZWZpbmVkKCBVU0VfQ09MT1JfQUxQSEEgKVxcblxcdFxcdFxcdGlmICggbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF0gIT0gMC4wICkgdkNvbG9yICs9IGdldE1vcnBoKCBnbF9WZXJ0ZXhJRCwgaSwgMiApICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF07XFxuXFx0XFx0I2VsaWYgZGVmaW5lZCggVVNFX0NPTE9SIClcXG5cXHRcXHRcXHRpZiAoIG1vcnBoVGFyZ2V0SW5mbHVlbmNlc1sgaSBdICE9IDAuMCApIHZDb2xvciArPSBnZXRNb3JwaCggZ2xfVmVydGV4SUQsIGksIDIgKS5yZ2IgKiBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIGkgXTtcXG5cXHRcXHQjZW5kaWZcXG5cXHR9XFxuI2VuZGlmXCI7XG5cbnZhciBtb3JwaG5vcm1hbF92ZXJ0ZXggPSBcIiNpZmRlZiBVU0VfTU9SUEhOT1JNQUxTXFxuXFx0b2JqZWN0Tm9ybWFsICo9IG1vcnBoVGFyZ2V0QmFzZUluZmx1ZW5jZTtcXG5cXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBNT1JQSFRBUkdFVFNfQ09VTlQ7IGkgKysgKSB7XFxuXFx0XFx0aWYgKCBtb3JwaFRhcmdldEluZmx1ZW5jZXNbIGkgXSAhPSAwLjAgKSBvYmplY3ROb3JtYWwgKz0gZ2V0TW9ycGgoIGdsX1ZlcnRleElELCBpLCAxICkueHl6ICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF07XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgbW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXggPSBcIiNpZmRlZiBVU0VfTU9SUEhUQVJHRVRTXFxuXFx0I2lmbmRlZiBVU0VfSU5TVEFOQ0lOR19NT1JQSFxcblxcdFxcdHVuaWZvcm0gZmxvYXQgbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlO1xcblxcdFxcdHVuaWZvcm0gZmxvYXQgbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBNT1JQSFRBUkdFVFNfQ09VTlQgXTtcXG5cXHQjZW5kaWZcXG5cXHR1bmlmb3JtIHNhbXBsZXIyREFycmF5IG1vcnBoVGFyZ2V0c1RleHR1cmU7XFxuXFx0dW5pZm9ybSBpdmVjMiBtb3JwaFRhcmdldHNUZXh0dXJlU2l6ZTtcXG5cXHR2ZWM0IGdldE1vcnBoKCBjb25zdCBpbiBpbnQgdmVydGV4SW5kZXgsIGNvbnN0IGluIGludCBtb3JwaFRhcmdldEluZGV4LCBjb25zdCBpbiBpbnQgb2Zmc2V0ICkge1xcblxcdFxcdGludCB0ZXhlbEluZGV4ID0gdmVydGV4SW5kZXggKiBNT1JQSFRBUkdFVFNfVEVYVFVSRV9TVFJJREUgKyBvZmZzZXQ7XFxuXFx0XFx0aW50IHkgPSB0ZXhlbEluZGV4IC8gbW9ycGhUYXJnZXRzVGV4dHVyZVNpemUueDtcXG5cXHRcXHRpbnQgeCA9IHRleGVsSW5kZXggLSB5ICogbW9ycGhUYXJnZXRzVGV4dHVyZVNpemUueDtcXG5cXHRcXHRpdmVjMyBtb3JwaFVWID0gaXZlYzMoIHgsIHksIG1vcnBoVGFyZ2V0SW5kZXggKTtcXG5cXHRcXHRyZXR1cm4gdGV4ZWxGZXRjaCggbW9ycGhUYXJnZXRzVGV4dHVyZSwgbW9ycGhVViwgMCApO1xcblxcdH1cXG4jZW5kaWZcIjtcblxudmFyIG1vcnBodGFyZ2V0X3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9NT1JQSFRBUkdFVFNcXG5cXHR0cmFuc2Zvcm1lZCAqPSBtb3JwaFRhcmdldEJhc2VJbmZsdWVuY2U7XFxuXFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTU9SUEhUQVJHRVRTX0NPVU5UOyBpICsrICkge1xcblxcdFxcdGlmICggbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF0gIT0gMC4wICkgdHJhbnNmb3JtZWQgKz0gZ2V0TW9ycGgoIGdsX1ZlcnRleElELCBpLCAwICkueHl6ICogbW9ycGhUYXJnZXRJbmZsdWVuY2VzWyBpIF07XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgbm9ybWFsX2ZyYWdtZW50X2JlZ2luID0gXCJmbG9hdCBmYWNlRGlyZWN0aW9uID0gZ2xfRnJvbnRGYWNpbmcgPyAxLjAgOiAtIDEuMDtcXG4jaWZkZWYgRkxBVF9TSEFERURcXG5cXHR2ZWMzIGZkeCA9IGRGZHgoIHZWaWV3UG9zaXRpb24gKTtcXG5cXHR2ZWMzIGZkeSA9IGRGZHkoIHZWaWV3UG9zaXRpb24gKTtcXG5cXHR2ZWMzIG5vcm1hbCA9IG5vcm1hbGl6ZSggY3Jvc3MoIGZkeCwgZmR5ICkgKTtcXG4jZWxzZVxcblxcdHZlYzMgbm9ybWFsID0gbm9ybWFsaXplKCB2Tm9ybWFsICk7XFxuXFx0I2lmZGVmIERPVUJMRV9TSURFRFxcblxcdFxcdG5vcm1hbCAqPSBmYWNlRGlyZWN0aW9uO1xcblxcdCNlbmRpZlxcbiNlbmRpZlxcbiNpZiBkZWZpbmVkKCBVU0VfTk9STUFMTUFQX1RBTkdFTlRTUEFDRSApIHx8IGRlZmluZWQoIFVTRV9DTEVBUkNPQVRfTk9STUFMTUFQICkgfHwgZGVmaW5lZCggVVNFX0FOSVNPVFJPUFkgKVxcblxcdCNpZmRlZiBVU0VfVEFOR0VOVFxcblxcdFxcdG1hdDMgdGJuID0gbWF0Myggbm9ybWFsaXplKCB2VGFuZ2VudCApLCBub3JtYWxpemUoIHZCaXRhbmdlbnQgKSwgbm9ybWFsICk7XFxuXFx0I2Vsc2VcXG5cXHRcXHRtYXQzIHRibiA9IGdldFRhbmdlbnRGcmFtZSggLSB2Vmlld1Bvc2l0aW9uLCBub3JtYWwsXFxuXFx0XFx0I2lmIGRlZmluZWQoIFVTRV9OT1JNQUxNQVAgKVxcblxcdFxcdFxcdHZOb3JtYWxNYXBVdlxcblxcdFxcdCNlbGlmIGRlZmluZWQoIFVTRV9DTEVBUkNPQVRfTk9STUFMTUFQIClcXG5cXHRcXHRcXHR2Q2xlYXJjb2F0Tm9ybWFsTWFwVXZcXG5cXHRcXHQjZWxzZVxcblxcdFxcdFxcdHZVdlxcblxcdFxcdCNlbmRpZlxcblxcdFxcdCk7XFxuXFx0I2VuZGlmXFxuXFx0I2lmIGRlZmluZWQoIERPVUJMRV9TSURFRCApICYmICEgZGVmaW5lZCggRkxBVF9TSEFERUQgKVxcblxcdFxcdHRiblswXSAqPSBmYWNlRGlyZWN0aW9uO1xcblxcdFxcdHRiblsxXSAqPSBmYWNlRGlyZWN0aW9uO1xcblxcdCNlbmRpZlxcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUFxcblxcdCNpZmRlZiBVU0VfVEFOR0VOVFxcblxcdFxcdG1hdDMgdGJuMiA9IG1hdDMoIG5vcm1hbGl6ZSggdlRhbmdlbnQgKSwgbm9ybWFsaXplKCB2Qml0YW5nZW50ICksIG5vcm1hbCApO1xcblxcdCNlbHNlXFxuXFx0XFx0bWF0MyB0Ym4yID0gZ2V0VGFuZ2VudEZyYW1lKCAtIHZWaWV3UG9zaXRpb24sIG5vcm1hbCwgdkNsZWFyY29hdE5vcm1hbE1hcFV2ICk7XFxuXFx0I2VuZGlmXFxuXFx0I2lmIGRlZmluZWQoIERPVUJMRV9TSURFRCApICYmICEgZGVmaW5lZCggRkxBVF9TSEFERUQgKVxcblxcdFxcdHRibjJbMF0gKj0gZmFjZURpcmVjdGlvbjtcXG5cXHRcXHR0Ym4yWzFdICo9IGZhY2VEaXJlY3Rpb247XFxuXFx0I2VuZGlmXFxuI2VuZGlmXFxudmVjMyBub25QZXJ0dXJiZWROb3JtYWwgPSBub3JtYWw7XCI7XG5cbnZhciBub3JtYWxfZnJhZ21lbnRfbWFwcyA9IFwiI2lmZGVmIFVTRV9OT1JNQUxNQVBfT0JKRUNUU1BBQ0VcXG5cXHRub3JtYWwgPSB0ZXh0dXJlMkQoIG5vcm1hbE1hcCwgdk5vcm1hbE1hcFV2ICkueHl6ICogMi4wIC0gMS4wO1xcblxcdCNpZmRlZiBGTElQX1NJREVEXFxuXFx0XFx0bm9ybWFsID0gLSBub3JtYWw7XFxuXFx0I2VuZGlmXFxuXFx0I2lmZGVmIERPVUJMRV9TSURFRFxcblxcdFxcdG5vcm1hbCA9IG5vcm1hbCAqIGZhY2VEaXJlY3Rpb247XFxuXFx0I2VuZGlmXFxuXFx0bm9ybWFsID0gbm9ybWFsaXplKCBub3JtYWxNYXRyaXggKiBub3JtYWwgKTtcXG4jZWxpZiBkZWZpbmVkKCBVU0VfTk9STUFMTUFQX1RBTkdFTlRTUEFDRSApXFxuXFx0dmVjMyBtYXBOID0gdGV4dHVyZTJEKCBub3JtYWxNYXAsIHZOb3JtYWxNYXBVdiApLnh5eiAqIDIuMCAtIDEuMDtcXG5cXHRtYXBOLnh5ICo9IG5vcm1hbFNjYWxlO1xcblxcdG5vcm1hbCA9IG5vcm1hbGl6ZSggdGJuICogbWFwTiApO1xcbiNlbGlmIGRlZmluZWQoIFVTRV9CVU1QTUFQIClcXG5cXHRub3JtYWwgPSBwZXJ0dXJiTm9ybWFsQXJiKCAtIHZWaWV3UG9zaXRpb24sIG5vcm1hbCwgZEhkeHlfZndkKCksIGZhY2VEaXJlY3Rpb24gKTtcXG4jZW5kaWZcIjtcblxudmFyIG5vcm1hbF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZuZGVmIEZMQVRfU0hBREVEXFxuXFx0dmFyeWluZyB2ZWMzIHZOb3JtYWw7XFxuXFx0I2lmZGVmIFVTRV9UQU5HRU5UXFxuXFx0XFx0dmFyeWluZyB2ZWMzIHZUYW5nZW50O1xcblxcdFxcdHZhcnlpbmcgdmVjMyB2Qml0YW5nZW50O1xcblxcdCNlbmRpZlxcbiNlbmRpZlwiO1xuXG52YXIgbm9ybWFsX3BhcnNfdmVydGV4ID0gXCIjaWZuZGVmIEZMQVRfU0hBREVEXFxuXFx0dmFyeWluZyB2ZWMzIHZOb3JtYWw7XFxuXFx0I2lmZGVmIFVTRV9UQU5HRU5UXFxuXFx0XFx0dmFyeWluZyB2ZWMzIHZUYW5nZW50O1xcblxcdFxcdHZhcnlpbmcgdmVjMyB2Qml0YW5nZW50O1xcblxcdCNlbmRpZlxcbiNlbmRpZlwiO1xuXG52YXIgbm9ybWFsX3ZlcnRleCA9IFwiI2lmbmRlZiBGTEFUX1NIQURFRFxcblxcdHZOb3JtYWwgPSBub3JtYWxpemUoIHRyYW5zZm9ybWVkTm9ybWFsICk7XFxuXFx0I2lmZGVmIFVTRV9UQU5HRU5UXFxuXFx0XFx0dlRhbmdlbnQgPSBub3JtYWxpemUoIHRyYW5zZm9ybWVkVGFuZ2VudCApO1xcblxcdFxcdHZCaXRhbmdlbnQgPSBub3JtYWxpemUoIGNyb3NzKCB2Tm9ybWFsLCB2VGFuZ2VudCApICogdGFuZ2VudC53ICk7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXCI7XG5cbnZhciBub3JtYWxtYXBfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9OT1JNQUxNQVBcXG5cXHR1bmlmb3JtIHNhbXBsZXIyRCBub3JtYWxNYXA7XFxuXFx0dW5pZm9ybSB2ZWMyIG5vcm1hbFNjYWxlO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTk9STUFMTUFQX09CSkVDVFNQQUNFXFxuXFx0dW5pZm9ybSBtYXQzIG5vcm1hbE1hdHJpeDtcXG4jZW5kaWZcXG4jaWYgISBkZWZpbmVkICggVVNFX1RBTkdFTlQgKSAmJiAoIGRlZmluZWQgKCBVU0VfTk9STUFMTUFQX1RBTkdFTlRTUEFDRSApIHx8IGRlZmluZWQgKCBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUCApIHx8IGRlZmluZWQoIFVTRV9BTklTT1RST1BZICkgKVxcblxcdG1hdDMgZ2V0VGFuZ2VudEZyYW1lKCB2ZWMzIGV5ZV9wb3MsIHZlYzMgc3VyZl9ub3JtLCB2ZWMyIHV2ICkge1xcblxcdFxcdHZlYzMgcTAgPSBkRmR4KCBleWVfcG9zLnh5eiApO1xcblxcdFxcdHZlYzMgcTEgPSBkRmR5KCBleWVfcG9zLnh5eiApO1xcblxcdFxcdHZlYzIgc3QwID0gZEZkeCggdXYuc3QgKTtcXG5cXHRcXHR2ZWMyIHN0MSA9IGRGZHkoIHV2LnN0ICk7XFxuXFx0XFx0dmVjMyBOID0gc3VyZl9ub3JtO1xcblxcdFxcdHZlYzMgcTFwZXJwID0gY3Jvc3MoIHExLCBOICk7XFxuXFx0XFx0dmVjMyBxMHBlcnAgPSBjcm9zcyggTiwgcTAgKTtcXG5cXHRcXHR2ZWMzIFQgPSBxMXBlcnAgKiBzdDAueCArIHEwcGVycCAqIHN0MS54O1xcblxcdFxcdHZlYzMgQiA9IHExcGVycCAqIHN0MC55ICsgcTBwZXJwICogc3QxLnk7XFxuXFx0XFx0ZmxvYXQgZGV0ID0gbWF4KCBkb3QoIFQsIFQgKSwgZG90KCBCLCBCICkgKTtcXG5cXHRcXHRmbG9hdCBzY2FsZSA9ICggZGV0ID09IDAuMCApID8gMC4wIDogaW52ZXJzZXNxcnQoIGRldCApO1xcblxcdFxcdHJldHVybiBtYXQzKCBUICogc2NhbGUsIEIgKiBzY2FsZSwgTiApO1xcblxcdH1cXG4jZW5kaWZcIjtcblxudmFyIGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfYmVnaW4gPSBcIiNpZmRlZiBVU0VfQ0xFQVJDT0FUXFxuXFx0dmVjMyBjbGVhcmNvYXROb3JtYWwgPSBub25QZXJ0dXJiZWROb3JtYWw7XFxuI2VuZGlmXCI7XG5cbnZhciBjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X21hcHMgPSBcIiNpZmRlZiBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUFxcblxcdHZlYzMgY2xlYXJjb2F0TWFwTiA9IHRleHR1cmUyRCggY2xlYXJjb2F0Tm9ybWFsTWFwLCB2Q2xlYXJjb2F0Tm9ybWFsTWFwVXYgKS54eXogKiAyLjAgLSAxLjA7XFxuXFx0Y2xlYXJjb2F0TWFwTi54eSAqPSBjbGVhcmNvYXROb3JtYWxTY2FsZTtcXG5cXHRjbGVhcmNvYXROb3JtYWwgPSBub3JtYWxpemUoIHRibjIgKiBjbGVhcmNvYXRNYXBOICk7XFxuI2VuZGlmXCI7XG5cbnZhciBjbGVhcmNvYXRfcGFyc19mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9DTEVBUkNPQVRNQVBcXG5cXHR1bmlmb3JtIHNhbXBsZXIyRCBjbGVhcmNvYXRNYXA7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRfTk9STUFMTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgY2xlYXJjb2F0Tm9ybWFsTWFwO1xcblxcdHVuaWZvcm0gdmVjMiBjbGVhcmNvYXROb3JtYWxTY2FsZTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0NMRUFSQ09BVF9ST1VHSE5FU1NNQVBcXG5cXHR1bmlmb3JtIHNhbXBsZXIyRCBjbGVhcmNvYXRSb3VnaG5lc3NNYXA7XFxuI2VuZGlmXCI7XG5cbnZhciBpcmlkZXNjZW5jZV9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX0lSSURFU0NFTkNFTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgaXJpZGVzY2VuY2VNYXA7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9JUklERVNDRU5DRV9USElDS05FU1NNQVBcXG5cXHR1bmlmb3JtIHNhbXBsZXIyRCBpcmlkZXNjZW5jZVRoaWNrbmVzc01hcDtcXG4jZW5kaWZcIjtcblxudmFyIG9wYXF1ZV9mcmFnbWVudCA9IFwiI2lmZGVmIE9QQVFVRVxcbmRpZmZ1c2VDb2xvci5hID0gMS4wO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OXFxuZGlmZnVzZUNvbG9yLmEgKj0gbWF0ZXJpYWwudHJhbnNtaXNzaW9uQWxwaGE7XFxuI2VuZGlmXFxuZ2xfRnJhZ0NvbG9yID0gdmVjNCggb3V0Z29pbmdMaWdodCwgZGlmZnVzZUNvbG9yLmEgKTtcIjtcblxudmFyIHBhY2tpbmcgPSBcInZlYzMgcGFja05vcm1hbFRvUkdCKCBjb25zdCBpbiB2ZWMzIG5vcm1hbCApIHtcXG5cXHRyZXR1cm4gbm9ybWFsaXplKCBub3JtYWwgKSAqIDAuNSArIDAuNTtcXG59XFxudmVjMyB1bnBhY2tSR0JUb05vcm1hbCggY29uc3QgaW4gdmVjMyByZ2IgKSB7XFxuXFx0cmV0dXJuIDIuMCAqIHJnYi54eXogLSAxLjA7XFxufVxcbmNvbnN0IGZsb2F0IFBhY2tVcHNjYWxlID0gMjU2LiAvIDI1NS47Y29uc3QgZmxvYXQgVW5wYWNrRG93bnNjYWxlID0gMjU1LiAvIDI1Ni47Y29uc3QgZmxvYXQgU2hpZnRSaWdodDggPSAxLiAvIDI1Ni47XFxuY29uc3QgZmxvYXQgSW52MjU1ID0gMS4gLyAyNTUuO1xcbmNvbnN0IHZlYzQgUGFja0ZhY3RvcnMgPSB2ZWM0KCAxLjAsIDI1Ni4wLCAyNTYuMCAqIDI1Ni4wLCAyNTYuMCAqIDI1Ni4wICogMjU2LjAgKTtcXG5jb25zdCB2ZWMyIFVucGFja0ZhY3RvcnMyID0gdmVjMiggVW5wYWNrRG93bnNjYWxlLCAxLjAgLyBQYWNrRmFjdG9ycy5nICk7XFxuY29uc3QgdmVjMyBVbnBhY2tGYWN0b3JzMyA9IHZlYzMoIFVucGFja0Rvd25zY2FsZSAvIFBhY2tGYWN0b3JzLnJnLCAxLjAgLyBQYWNrRmFjdG9ycy5iICk7XFxuY29uc3QgdmVjNCBVbnBhY2tGYWN0b3JzNCA9IHZlYzQoIFVucGFja0Rvd25zY2FsZSAvIFBhY2tGYWN0b3JzLnJnYiwgMS4wIC8gUGFja0ZhY3RvcnMuYSApO1xcbnZlYzQgcGFja0RlcHRoVG9SR0JBKCBjb25zdCBpbiBmbG9hdCB2ICkge1xcblxcdGlmKCB2IDw9IDAuMCApXFxuXFx0XFx0cmV0dXJuIHZlYzQoIDAuLCAwLiwgMC4sIDAuICk7XFxuXFx0aWYoIHYgPj0gMS4wIClcXG5cXHRcXHRyZXR1cm4gdmVjNCggMS4sIDEuLCAxLiwgMS4gKTtcXG5cXHRmbG9hdCB2dWY7XFxuXFx0ZmxvYXQgYWYgPSBtb2RmKCB2ICogUGFja0ZhY3RvcnMuYSwgdnVmICk7XFxuXFx0ZmxvYXQgYmYgPSBtb2RmKCB2dWYgKiBTaGlmdFJpZ2h0OCwgdnVmICk7XFxuXFx0ZmxvYXQgZ2YgPSBtb2RmKCB2dWYgKiBTaGlmdFJpZ2h0OCwgdnVmICk7XFxuXFx0cmV0dXJuIHZlYzQoIHZ1ZiAqIEludjI1NSwgZ2YgKiBQYWNrVXBzY2FsZSwgYmYgKiBQYWNrVXBzY2FsZSwgYWYgKTtcXG59XFxudmVjMyBwYWNrRGVwdGhUb1JHQiggY29uc3QgaW4gZmxvYXQgdiApIHtcXG5cXHRpZiggdiA8PSAwLjAgKVxcblxcdFxcdHJldHVybiB2ZWMzKCAwLiwgMC4sIDAuICk7XFxuXFx0aWYoIHYgPj0gMS4wIClcXG5cXHRcXHRyZXR1cm4gdmVjMyggMS4sIDEuLCAxLiApO1xcblxcdGZsb2F0IHZ1ZjtcXG5cXHRmbG9hdCBiZiA9IG1vZGYoIHYgKiBQYWNrRmFjdG9ycy5iLCB2dWYgKTtcXG5cXHRmbG9hdCBnZiA9IG1vZGYoIHZ1ZiAqIFNoaWZ0UmlnaHQ4LCB2dWYgKTtcXG5cXHRyZXR1cm4gdmVjMyggdnVmICogSW52MjU1LCBnZiAqIFBhY2tVcHNjYWxlLCBiZiApO1xcbn1cXG52ZWMyIHBhY2tEZXB0aFRvUkcoIGNvbnN0IGluIGZsb2F0IHYgKSB7XFxuXFx0aWYoIHYgPD0gMC4wIClcXG5cXHRcXHRyZXR1cm4gdmVjMiggMC4sIDAuICk7XFxuXFx0aWYoIHYgPj0gMS4wIClcXG5cXHRcXHRyZXR1cm4gdmVjMiggMS4sIDEuICk7XFxuXFx0ZmxvYXQgdnVmO1xcblxcdGZsb2F0IGdmID0gbW9kZiggdiAqIDI1Ni4sIHZ1ZiApO1xcblxcdHJldHVybiB2ZWMyKCB2dWYgKiBJbnYyNTUsIGdmICk7XFxufVxcbmZsb2F0IHVucGFja1JHQkFUb0RlcHRoKCBjb25zdCBpbiB2ZWM0IHYgKSB7XFxuXFx0cmV0dXJuIGRvdCggdiwgVW5wYWNrRmFjdG9yczQgKTtcXG59XFxuZmxvYXQgdW5wYWNrUkdCVG9EZXB0aCggY29uc3QgaW4gdmVjMyB2ICkge1xcblxcdHJldHVybiBkb3QoIHYsIFVucGFja0ZhY3RvcnMzICk7XFxufVxcbmZsb2F0IHVucGFja1JHVG9EZXB0aCggY29uc3QgaW4gdmVjMiB2ICkge1xcblxcdHJldHVybiB2LnIgKiBVbnBhY2tGYWN0b3JzMi5yICsgdi5nICogVW5wYWNrRmFjdG9yczIuZztcXG59XFxudmVjNCBwYWNrMkhhbGZUb1JHQkEoIGNvbnN0IGluIHZlYzIgdiApIHtcXG5cXHR2ZWM0IHIgPSB2ZWM0KCB2LngsIGZyYWN0KCB2LnggKiAyNTUuMCApLCB2LnksIGZyYWN0KCB2LnkgKiAyNTUuMCApICk7XFxuXFx0cmV0dXJuIHZlYzQoIHIueCAtIHIueSAvIDI1NS4wLCByLnksIHIueiAtIHIudyAvIDI1NS4wLCByLncgKTtcXG59XFxudmVjMiB1bnBhY2tSR0JBVG8ySGFsZiggY29uc3QgaW4gdmVjNCB2ICkge1xcblxcdHJldHVybiB2ZWMyKCB2LnggKyAoIHYueSAvIDI1NS4wICksIHYueiArICggdi53IC8gMjU1LjAgKSApO1xcbn1cXG5mbG9hdCB2aWV3WlRvT3J0aG9ncmFwaGljRGVwdGgoIGNvbnN0IGluIGZsb2F0IHZpZXdaLCBjb25zdCBpbiBmbG9hdCBuZWFyLCBjb25zdCBpbiBmbG9hdCBmYXIgKSB7XFxuXFx0cmV0dXJuICggdmlld1ogKyBuZWFyICkgLyAoIG5lYXIgLSBmYXIgKTtcXG59XFxuZmxvYXQgb3J0aG9ncmFwaGljRGVwdGhUb1ZpZXdaKCBjb25zdCBpbiBmbG9hdCBkZXB0aCwgY29uc3QgaW4gZmxvYXQgbmVhciwgY29uc3QgaW4gZmxvYXQgZmFyICkge1xcblxcdHJldHVybiBkZXB0aCAqICggbmVhciAtIGZhciApIC0gbmVhcjtcXG59XFxuZmxvYXQgdmlld1pUb1BlcnNwZWN0aXZlRGVwdGgoIGNvbnN0IGluIGZsb2F0IHZpZXdaLCBjb25zdCBpbiBmbG9hdCBuZWFyLCBjb25zdCBpbiBmbG9hdCBmYXIgKSB7XFxuXFx0cmV0dXJuICggKCBuZWFyICsgdmlld1ogKSAqIGZhciApIC8gKCAoIGZhciAtIG5lYXIgKSAqIHZpZXdaICk7XFxufVxcbmZsb2F0IHBlcnNwZWN0aXZlRGVwdGhUb1ZpZXdaKCBjb25zdCBpbiBmbG9hdCBkZXB0aCwgY29uc3QgaW4gZmxvYXQgbmVhciwgY29uc3QgaW4gZmxvYXQgZmFyICkge1xcblxcdHJldHVybiAoIG5lYXIgKiBmYXIgKSAvICggKCBmYXIgLSBuZWFyICkgKiBkZXB0aCAtIGZhciApO1xcbn1cIjtcblxudmFyIHByZW11bHRpcGxpZWRfYWxwaGFfZnJhZ21lbnQgPSBcIiNpZmRlZiBQUkVNVUxUSVBMSUVEX0FMUEhBXFxuXFx0Z2xfRnJhZ0NvbG9yLnJnYiAqPSBnbF9GcmFnQ29sb3IuYTtcXG4jZW5kaWZcIjtcblxudmFyIHByb2plY3RfdmVydGV4ID0gXCJ2ZWM0IG12UG9zaXRpb24gPSB2ZWM0KCB0cmFuc2Zvcm1lZCwgMS4wICk7XFxuI2lmZGVmIFVTRV9CQVRDSElOR1xcblxcdG12UG9zaXRpb24gPSBiYXRjaGluZ01hdHJpeCAqIG12UG9zaXRpb247XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9JTlNUQU5DSU5HXFxuXFx0bXZQb3NpdGlvbiA9IGluc3RhbmNlTWF0cml4ICogbXZQb3NpdGlvbjtcXG4jZW5kaWZcXG5tdlBvc2l0aW9uID0gbW9kZWxWaWV3TWF0cml4ICogbXZQb3NpdGlvbjtcXG5nbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtdlBvc2l0aW9uO1wiO1xuXG52YXIgZGl0aGVyaW5nX2ZyYWdtZW50ID0gXCIjaWZkZWYgRElUSEVSSU5HXFxuXFx0Z2xfRnJhZ0NvbG9yLnJnYiA9IGRpdGhlcmluZyggZ2xfRnJhZ0NvbG9yLnJnYiApO1xcbiNlbmRpZlwiO1xuXG52YXIgZGl0aGVyaW5nX3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBESVRIRVJJTkdcXG5cXHR2ZWMzIGRpdGhlcmluZyggdmVjMyBjb2xvciApIHtcXG5cXHRcXHRmbG9hdCBncmlkX3Bvc2l0aW9uID0gcmFuZCggZ2xfRnJhZ0Nvb3JkLnh5ICk7XFxuXFx0XFx0dmVjMyBkaXRoZXJfc2hpZnRfUkdCID0gdmVjMyggMC4yNSAvIDI1NS4wLCAtMC4yNSAvIDI1NS4wLCAwLjI1IC8gMjU1LjAgKTtcXG5cXHRcXHRkaXRoZXJfc2hpZnRfUkdCID0gbWl4KCAyLjAgKiBkaXRoZXJfc2hpZnRfUkdCLCAtMi4wICogZGl0aGVyX3NoaWZ0X1JHQiwgZ3JpZF9wb3NpdGlvbiApO1xcblxcdFxcdHJldHVybiBjb2xvciArIGRpdGhlcl9zaGlmdF9SR0I7XFxuXFx0fVxcbiNlbmRpZlwiO1xuXG52YXIgcm91Z2huZXNzbWFwX2ZyYWdtZW50ID0gXCJmbG9hdCByb3VnaG5lc3NGYWN0b3IgPSByb3VnaG5lc3M7XFxuI2lmZGVmIFVTRV9ST1VHSE5FU1NNQVBcXG5cXHR2ZWM0IHRleGVsUm91Z2huZXNzID0gdGV4dHVyZTJEKCByb3VnaG5lc3NNYXAsIHZSb3VnaG5lc3NNYXBVdiApO1xcblxcdHJvdWdobmVzc0ZhY3RvciAqPSB0ZXhlbFJvdWdobmVzcy5nO1xcbiNlbmRpZlwiO1xuXG52YXIgcm91Z2huZXNzbWFwX3BhcnNfZnJhZ21lbnQgPSBcIiNpZmRlZiBVU0VfUk9VR0hORVNTTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgcm91Z2huZXNzTWFwO1xcbiNlbmRpZlwiO1xuXG52YXIgc2hhZG93bWFwX3BhcnNfZnJhZ21lbnQgPSBcIiNpZiBOVU1fU1BPVF9MSUdIVF9DT09SRFMgPiAwXFxuXFx0dmFyeWluZyB2ZWM0IHZTcG90TGlnaHRDb29yZFsgTlVNX1NQT1RfTElHSFRfQ09PUkRTIF07XFxuI2VuZGlmXFxuI2lmIE5VTV9TUE9UX0xJR0hUX01BUFMgPiAwXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgc3BvdExpZ2h0TWFwWyBOVU1fU1BPVF9MSUdIVF9NQVBTIF07XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TSEFET1dNQVBcXG5cXHQjaWYgTlVNX0RJUl9MSUdIVF9TSEFET1dTID4gMFxcblxcdFxcdHVuaWZvcm0gc2FtcGxlcjJEIGRpcmVjdGlvbmFsU2hhZG93TWFwWyBOVU1fRElSX0xJR0hUX1NIQURPV1MgXTtcXG5cXHRcXHR2YXJ5aW5nIHZlYzQgdkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIE5VTV9ESVJfTElHSFRfU0hBRE9XUyBdO1xcblxcdFxcdHN0cnVjdCBEaXJlY3Rpb25hbExpZ2h0U2hhZG93IHtcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dJbnRlbnNpdHk7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93QmlhcztcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dOb3JtYWxCaWFzO1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd1JhZGl1cztcXG5cXHRcXHRcXHR2ZWMyIHNoYWRvd01hcFNpemU7XFxuXFx0XFx0fTtcXG5cXHRcXHR1bmlmb3JtIERpcmVjdGlvbmFsTGlnaHRTaGFkb3cgZGlyZWN0aW9uYWxMaWdodFNoYWRvd3NbIE5VTV9ESVJfTElHSFRfU0hBRE9XUyBdO1xcblxcdCNlbmRpZlxcblxcdCNpZiBOVU1fU1BPVF9MSUdIVF9TSEFET1dTID4gMFxcblxcdFxcdHVuaWZvcm0gc2FtcGxlcjJEIHNwb3RTaGFkb3dNYXBbIE5VTV9TUE9UX0xJR0hUX1NIQURPV1MgXTtcXG5cXHRcXHRzdHJ1Y3QgU3BvdExpZ2h0U2hhZG93IHtcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dJbnRlbnNpdHk7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93QmlhcztcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dOb3JtYWxCaWFzO1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd1JhZGl1cztcXG5cXHRcXHRcXHR2ZWMyIHNoYWRvd01hcFNpemU7XFxuXFx0XFx0fTtcXG5cXHRcXHR1bmlmb3JtIFNwb3RMaWdodFNoYWRvdyBzcG90TGlnaHRTaGFkb3dzWyBOVU1fU1BPVF9MSUdIVF9TSEFET1dTIF07XFxuXFx0I2VuZGlmXFxuXFx0I2lmIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTID4gMFxcblxcdFxcdHVuaWZvcm0gc2FtcGxlcjJEIHBvaW50U2hhZG93TWFwWyBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUyBdO1xcblxcdFxcdHZhcnlpbmcgdmVjNCB2UG9pbnRTaGFkb3dDb29yZFsgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgXTtcXG5cXHRcXHRzdHJ1Y3QgUG9pbnRMaWdodFNoYWRvdyB7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93SW50ZW5zaXR5O1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd0JpYXM7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93Tm9ybWFsQmlhcztcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dSYWRpdXM7XFxuXFx0XFx0XFx0dmVjMiBzaGFkb3dNYXBTaXplO1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd0NhbWVyYU5lYXI7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93Q2FtZXJhRmFyO1xcblxcdFxcdH07XFxuXFx0XFx0dW5pZm9ybSBQb2ludExpZ2h0U2hhZG93IHBvaW50TGlnaHRTaGFkb3dzWyBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUyBdO1xcblxcdCNlbmRpZlxcblxcdGZsb2F0IHRleHR1cmUyRENvbXBhcmUoIHNhbXBsZXIyRCBkZXB0aHMsIHZlYzIgdXYsIGZsb2F0IGNvbXBhcmUgKSB7XFxuXFx0XFx0cmV0dXJuIHN0ZXAoIGNvbXBhcmUsIHVucGFja1JHQkFUb0RlcHRoKCB0ZXh0dXJlMkQoIGRlcHRocywgdXYgKSApICk7XFxuXFx0fVxcblxcdHZlYzIgdGV4dHVyZTJERGlzdHJpYnV0aW9uKCBzYW1wbGVyMkQgc2hhZG93LCB2ZWMyIHV2ICkge1xcblxcdFxcdHJldHVybiB1bnBhY2tSR0JBVG8ySGFsZiggdGV4dHVyZTJEKCBzaGFkb3csIHV2ICkgKTtcXG5cXHR9XFxuXFx0ZmxvYXQgVlNNU2hhZG93IChzYW1wbGVyMkQgc2hhZG93LCB2ZWMyIHV2LCBmbG9hdCBjb21wYXJlICl7XFxuXFx0XFx0ZmxvYXQgb2NjbHVzaW9uID0gMS4wO1xcblxcdFxcdHZlYzIgZGlzdHJpYnV0aW9uID0gdGV4dHVyZTJERGlzdHJpYnV0aW9uKCBzaGFkb3csIHV2ICk7XFxuXFx0XFx0ZmxvYXQgaGFyZF9zaGFkb3cgPSBzdGVwKCBjb21wYXJlICwgZGlzdHJpYnV0aW9uLnggKTtcXG5cXHRcXHRpZiAoaGFyZF9zaGFkb3cgIT0gMS4wICkge1xcblxcdFxcdFxcdGZsb2F0IGRpc3RhbmNlID0gY29tcGFyZSAtIGRpc3RyaWJ1dGlvbi54IDtcXG5cXHRcXHRcXHRmbG9hdCB2YXJpYW5jZSA9IG1heCggMC4wMDAwMCwgZGlzdHJpYnV0aW9uLnkgKiBkaXN0cmlidXRpb24ueSApO1xcblxcdFxcdFxcdGZsb2F0IHNvZnRuZXNzX3Byb2JhYmlsaXR5ID0gdmFyaWFuY2UgLyAodmFyaWFuY2UgKyBkaXN0YW5jZSAqIGRpc3RhbmNlICk7XFx0XFx0XFx0c29mdG5lc3NfcHJvYmFiaWxpdHkgPSBjbGFtcCggKCBzb2Z0bmVzc19wcm9iYWJpbGl0eSAtIDAuMyApIC8gKCAwLjk1IC0gMC4zICksIDAuMCwgMS4wICk7XFx0XFx0XFx0b2NjbHVzaW9uID0gY2xhbXAoIG1heCggaGFyZF9zaGFkb3csIHNvZnRuZXNzX3Byb2JhYmlsaXR5ICksIDAuMCwgMS4wICk7XFxuXFx0XFx0fVxcblxcdFxcdHJldHVybiBvY2NsdXNpb247XFxuXFx0fVxcblxcdGZsb2F0IGdldFNoYWRvdyggc2FtcGxlcjJEIHNoYWRvd01hcCwgdmVjMiBzaGFkb3dNYXBTaXplLCBmbG9hdCBzaGFkb3dJbnRlbnNpdHksIGZsb2F0IHNoYWRvd0JpYXMsIGZsb2F0IHNoYWRvd1JhZGl1cywgdmVjNCBzaGFkb3dDb29yZCApIHtcXG5cXHRcXHRmbG9hdCBzaGFkb3cgPSAxLjA7XFxuXFx0XFx0c2hhZG93Q29vcmQueHl6IC89IHNoYWRvd0Nvb3JkLnc7XFxuXFx0XFx0c2hhZG93Q29vcmQueiArPSBzaGFkb3dCaWFzO1xcblxcdFxcdGJvb2wgaW5GcnVzdHVtID0gc2hhZG93Q29vcmQueCA+PSAwLjAgJiYgc2hhZG93Q29vcmQueCA8PSAxLjAgJiYgc2hhZG93Q29vcmQueSA+PSAwLjAgJiYgc2hhZG93Q29vcmQueSA8PSAxLjA7XFxuXFx0XFx0Ym9vbCBmcnVzdHVtVGVzdCA9IGluRnJ1c3R1bSAmJiBzaGFkb3dDb29yZC56IDw9IDEuMDtcXG5cXHRcXHRpZiAoIGZydXN0dW1UZXN0ICkge1xcblxcdFxcdCNpZiBkZWZpbmVkKCBTSEFET1dNQVBfVFlQRV9QQ0YgKVxcblxcdFxcdFxcdHZlYzIgdGV4ZWxTaXplID0gdmVjMiggMS4wICkgLyBzaGFkb3dNYXBTaXplO1xcblxcdFxcdFxcdGZsb2F0IGR4MCA9IC0gdGV4ZWxTaXplLnggKiBzaGFkb3dSYWRpdXM7XFxuXFx0XFx0XFx0ZmxvYXQgZHkwID0gLSB0ZXhlbFNpemUueSAqIHNoYWRvd1JhZGl1cztcXG5cXHRcXHRcXHRmbG9hdCBkeDEgPSArIHRleGVsU2l6ZS54ICogc2hhZG93UmFkaXVzO1xcblxcdFxcdFxcdGZsb2F0IGR5MSA9ICsgdGV4ZWxTaXplLnkgKiBzaGFkb3dSYWRpdXM7XFxuXFx0XFx0XFx0ZmxvYXQgZHgyID0gZHgwIC8gMi4wO1xcblxcdFxcdFxcdGZsb2F0IGR5MiA9IGR5MCAvIDIuMDtcXG5cXHRcXHRcXHRmbG9hdCBkeDMgPSBkeDEgLyAyLjA7XFxuXFx0XFx0XFx0ZmxvYXQgZHkzID0gZHkxIC8gMi4wO1xcblxcdFxcdFxcdHNoYWRvdyA9IChcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgwLCBkeTAgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggMC4wLCBkeTAgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgxLCBkeTAgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgyLCBkeTIgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggMC4wLCBkeTIgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgzLCBkeTIgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgwLCAwLjAgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5ICsgdmVjMiggZHgyLCAwLjAgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHNoYWRvd0Nvb3JkLnh5LCBzaGFkb3dDb29yZC56ICkgK1xcblxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDMsIDAuMCApLCBzaGFkb3dDb29yZC56ICkgK1xcblxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDEsIDAuMCApLCBzaGFkb3dDb29yZC56ICkgK1xcblxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDIsIGR5MyApLCBzaGFkb3dDb29yZC56ICkgK1xcblxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCAwLjAsIGR5MyApLCBzaGFkb3dDb29yZC56ICkgK1xcblxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDMsIGR5MyApLCBzaGFkb3dDb29yZC56ICkgK1xcblxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDAsIGR5MSApLCBzaGFkb3dDb29yZC56ICkgK1xcblxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCAwLjAsIGR5MSApLCBzaGFkb3dDb29yZC56ICkgK1xcblxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgc2hhZG93Q29vcmQueHkgKyB2ZWMyKCBkeDEsIGR5MSApLCBzaGFkb3dDb29yZC56IClcXG5cXHRcXHRcXHQpICogKCAxLjAgLyAxNy4wICk7XFxuXFx0XFx0I2VsaWYgZGVmaW5lZCggU0hBRE9XTUFQX1RZUEVfUENGX1NPRlQgKVxcblxcdFxcdFxcdHZlYzIgdGV4ZWxTaXplID0gdmVjMiggMS4wICkgLyBzaGFkb3dNYXBTaXplO1xcblxcdFxcdFxcdGZsb2F0IGR4ID0gdGV4ZWxTaXplLng7XFxuXFx0XFx0XFx0ZmxvYXQgZHkgPSB0ZXhlbFNpemUueTtcXG5cXHRcXHRcXHR2ZWMyIHV2ID0gc2hhZG93Q29vcmQueHk7XFxuXFx0XFx0XFx0dmVjMiBmID0gZnJhY3QoIHV2ICogc2hhZG93TWFwU2l6ZSArIDAuNSApO1xcblxcdFxcdFxcdHV2IC09IGYgKiB0ZXhlbFNpemU7XFxuXFx0XFx0XFx0c2hhZG93ID0gKFxcblxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYsIHNoYWRvd0Nvb3JkLnogKSArXFxuXFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIGR4LCAwLjAgKSwgc2hhZG93Q29vcmQueiApICtcXG5cXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggMC4wLCBkeSApLCBzaGFkb3dDb29yZC56ICkgK1xcblxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB0ZXhlbFNpemUsIHNoYWRvd0Nvb3JkLnogKSArXFxuXFx0XFx0XFx0XFx0bWl4KCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggLWR4LCAwLjAgKSwgc2hhZG93Q29vcmQueiApLFxcblxcdFxcdFxcdFxcdFxcdCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggMi4wICogZHgsIDAuMCApLCBzaGFkb3dDb29yZC56ICksXFxuXFx0XFx0XFx0XFx0XFx0IGYueCApICtcXG5cXHRcXHRcXHRcXHRtaXgoIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAtZHgsIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcXG5cXHRcXHRcXHRcXHRcXHQgdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIDIuMCAqIGR4LCBkeSApLCBzaGFkb3dDb29yZC56ICksXFxuXFx0XFx0XFx0XFx0XFx0IGYueCApICtcXG5cXHRcXHRcXHRcXHRtaXgoIHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAwLjAsIC1keSApLCBzaGFkb3dDb29yZC56ICksXFxuXFx0XFx0XFx0XFx0XFx0IHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgdXYgKyB2ZWMyKCAwLjAsIDIuMCAqIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcXG5cXHRcXHRcXHRcXHRcXHQgZi55ICkgK1xcblxcdFxcdFxcdFxcdG1peCggdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIGR4LCAtZHkgKSwgc2hhZG93Q29vcmQueiApLFxcblxcdFxcdFxcdFxcdFxcdCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggZHgsIDIuMCAqIGR5ICksIHNoYWRvd0Nvb3JkLnogKSxcXG5cXHRcXHRcXHRcXHRcXHQgZi55ICkgK1xcblxcdFxcdFxcdFxcdG1peCggbWl4KCB0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIHV2ICsgdmVjMiggLWR4LCAtZHkgKSwgc2hhZG93Q29vcmQueiApLFxcblxcdFxcdFxcdFxcdFxcdFxcdCAgdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIDIuMCAqIGR4LCAtZHkgKSwgc2hhZG93Q29vcmQueiApLFxcblxcdFxcdFxcdFxcdFxcdFxcdCAgZi54ICksXFxuXFx0XFx0XFx0XFx0XFx0IG1peCggdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIC1keCwgMi4wICogZHkgKSwgc2hhZG93Q29vcmQueiApLFxcblxcdFxcdFxcdFxcdFxcdFxcdCAgdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCB1diArIHZlYzIoIDIuMCAqIGR4LCAyLjAgKiBkeSApLCBzaGFkb3dDb29yZC56ICksXFxuXFx0XFx0XFx0XFx0XFx0XFx0ICBmLnggKSxcXG5cXHRcXHRcXHRcXHRcXHQgZi55IClcXG5cXHRcXHRcXHQpICogKCAxLjAgLyA5LjAgKTtcXG5cXHRcXHQjZWxpZiBkZWZpbmVkKCBTSEFET1dNQVBfVFlQRV9WU00gKVxcblxcdFxcdFxcdHNoYWRvdyA9IFZTTVNoYWRvdyggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSwgc2hhZG93Q29vcmQueiApO1xcblxcdFxcdCNlbHNlXFxuXFx0XFx0XFx0c2hhZG93ID0gdGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBzaGFkb3dDb29yZC54eSwgc2hhZG93Q29vcmQueiApO1xcblxcdFxcdCNlbmRpZlxcblxcdFxcdH1cXG5cXHRcXHRyZXR1cm4gbWl4KCAxLjAsIHNoYWRvdywgc2hhZG93SW50ZW5zaXR5ICk7XFxuXFx0fVxcblxcdHZlYzIgY3ViZVRvVVYoIHZlYzMgdiwgZmxvYXQgdGV4ZWxTaXplWSApIHtcXG5cXHRcXHR2ZWMzIGFic1YgPSBhYnMoIHYgKTtcXG5cXHRcXHRmbG9hdCBzY2FsZVRvQ3ViZSA9IDEuMCAvIG1heCggYWJzVi54LCBtYXgoIGFic1YueSwgYWJzVi56ICkgKTtcXG5cXHRcXHRhYnNWICo9IHNjYWxlVG9DdWJlO1xcblxcdFxcdHYgKj0gc2NhbGVUb0N1YmUgKiAoIDEuMCAtIDIuMCAqIHRleGVsU2l6ZVkgKTtcXG5cXHRcXHR2ZWMyIHBsYW5hciA9IHYueHk7XFxuXFx0XFx0ZmxvYXQgYWxtb3N0QVRleGVsID0gMS41ICogdGV4ZWxTaXplWTtcXG5cXHRcXHRmbG9hdCBhbG1vc3RPbmUgPSAxLjAgLSBhbG1vc3RBVGV4ZWw7XFxuXFx0XFx0aWYgKCBhYnNWLnogPj0gYWxtb3N0T25lICkge1xcblxcdFxcdFxcdGlmICggdi56ID4gMC4wIClcXG5cXHRcXHRcXHRcXHRwbGFuYXIueCA9IDQuMCAtIHYueDtcXG5cXHRcXHR9IGVsc2UgaWYgKCBhYnNWLnggPj0gYWxtb3N0T25lICkge1xcblxcdFxcdFxcdGZsb2F0IHNpZ25YID0gc2lnbiggdi54ICk7XFxuXFx0XFx0XFx0cGxhbmFyLnggPSB2LnogKiBzaWduWCArIDIuMCAqIHNpZ25YO1xcblxcdFxcdH0gZWxzZSBpZiAoIGFic1YueSA+PSBhbG1vc3RPbmUgKSB7XFxuXFx0XFx0XFx0ZmxvYXQgc2lnblkgPSBzaWduKCB2LnkgKTtcXG5cXHRcXHRcXHRwbGFuYXIueCA9IHYueCArIDIuMCAqIHNpZ25ZICsgMi4wO1xcblxcdFxcdFxcdHBsYW5hci55ID0gdi56ICogc2lnblkgLSAyLjA7XFxuXFx0XFx0fVxcblxcdFxcdHJldHVybiB2ZWMyKCAwLjEyNSwgMC4yNSApICogcGxhbmFyICsgdmVjMiggMC4zNzUsIDAuNzUgKTtcXG5cXHR9XFxuXFx0ZmxvYXQgZ2V0UG9pbnRTaGFkb3coIHNhbXBsZXIyRCBzaGFkb3dNYXAsIHZlYzIgc2hhZG93TWFwU2l6ZSwgZmxvYXQgc2hhZG93SW50ZW5zaXR5LCBmbG9hdCBzaGFkb3dCaWFzLCBmbG9hdCBzaGFkb3dSYWRpdXMsIHZlYzQgc2hhZG93Q29vcmQsIGZsb2F0IHNoYWRvd0NhbWVyYU5lYXIsIGZsb2F0IHNoYWRvd0NhbWVyYUZhciApIHtcXG5cXHRcXHRmbG9hdCBzaGFkb3cgPSAxLjA7XFxuXFx0XFx0dmVjMyBsaWdodFRvUG9zaXRpb24gPSBzaGFkb3dDb29yZC54eXo7XFxuXFx0XFx0XFxuXFx0XFx0ZmxvYXQgbGlnaHRUb1Bvc2l0aW9uTGVuZ3RoID0gbGVuZ3RoKCBsaWdodFRvUG9zaXRpb24gKTtcXG5cXHRcXHRpZiAoIGxpZ2h0VG9Qb3NpdGlvbkxlbmd0aCAtIHNoYWRvd0NhbWVyYUZhciA8PSAwLjAgJiYgbGlnaHRUb1Bvc2l0aW9uTGVuZ3RoIC0gc2hhZG93Q2FtZXJhTmVhciA+PSAwLjAgKSB7XFxuXFx0XFx0XFx0ZmxvYXQgZHAgPSAoIGxpZ2h0VG9Qb3NpdGlvbkxlbmd0aCAtIHNoYWRvd0NhbWVyYU5lYXIgKSAvICggc2hhZG93Q2FtZXJhRmFyIC0gc2hhZG93Q2FtZXJhTmVhciApO1xcdFxcdFxcdGRwICs9IHNoYWRvd0JpYXM7XFxuXFx0XFx0XFx0dmVjMyBiZDNEID0gbm9ybWFsaXplKCBsaWdodFRvUG9zaXRpb24gKTtcXG5cXHRcXHRcXHR2ZWMyIHRleGVsU2l6ZSA9IHZlYzIoIDEuMCApIC8gKCBzaGFkb3dNYXBTaXplICogdmVjMiggNC4wLCAyLjAgKSApO1xcblxcdFxcdFxcdCNpZiBkZWZpbmVkKCBTSEFET1dNQVBfVFlQRV9QQ0YgKSB8fCBkZWZpbmVkKCBTSEFET1dNQVBfVFlQRV9QQ0ZfU09GVCApIHx8IGRlZmluZWQoIFNIQURPV01BUF9UWVBFX1ZTTSApXFxuXFx0XFx0XFx0XFx0dmVjMiBvZmZzZXQgPSB2ZWMyKCAtIDEsIDEgKSAqIHNoYWRvd1JhZGl1cyAqIHRleGVsU2l6ZS55O1xcblxcdFxcdFxcdFxcdHNoYWRvdyA9IChcXG5cXHRcXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNEICsgb2Zmc2V0Lnh5eSwgdGV4ZWxTaXplLnkgKSwgZHAgKSArXFxuXFx0XFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBjdWJlVG9VViggYmQzRCArIG9mZnNldC55eXksIHRleGVsU2l6ZS55ICksIGRwICkgK1xcblxcdFxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QgKyBvZmZzZXQueHl4LCB0ZXhlbFNpemUueSApLCBkcCApICtcXG5cXHRcXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNEICsgb2Zmc2V0Lnl5eCwgdGV4ZWxTaXplLnkgKSwgZHAgKSArXFxuXFx0XFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBjdWJlVG9VViggYmQzRCwgdGV4ZWxTaXplLnkgKSwgZHAgKSArXFxuXFx0XFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBjdWJlVG9VViggYmQzRCArIG9mZnNldC54eHksIHRleGVsU2l6ZS55ICksIGRwICkgK1xcblxcdFxcdFxcdFxcdFxcdHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QgKyBvZmZzZXQueXh5LCB0ZXhlbFNpemUueSApLCBkcCApICtcXG5cXHRcXHRcXHRcXHRcXHR0ZXh0dXJlMkRDb21wYXJlKCBzaGFkb3dNYXAsIGN1YmVUb1VWKCBiZDNEICsgb2Zmc2V0Lnh4eCwgdGV4ZWxTaXplLnkgKSwgZHAgKSArXFxuXFx0XFx0XFx0XFx0XFx0dGV4dHVyZTJEQ29tcGFyZSggc2hhZG93TWFwLCBjdWJlVG9VViggYmQzRCArIG9mZnNldC55eHgsIHRleGVsU2l6ZS55ICksIGRwIClcXG5cXHRcXHRcXHRcXHQpICogKCAxLjAgLyA5LjAgKTtcXG5cXHRcXHRcXHQjZWxzZVxcblxcdFxcdFxcdFxcdHNoYWRvdyA9IHRleHR1cmUyRENvbXBhcmUoIHNoYWRvd01hcCwgY3ViZVRvVVYoIGJkM0QsIHRleGVsU2l6ZS55ICksIGRwICk7XFxuXFx0XFx0XFx0I2VuZGlmXFxuXFx0XFx0fVxcblxcdFxcdHJldHVybiBtaXgoIDEuMCwgc2hhZG93LCBzaGFkb3dJbnRlbnNpdHkgKTtcXG5cXHR9XFxuI2VuZGlmXCI7XG5cbnZhciBzaGFkb3dtYXBfcGFyc192ZXJ0ZXggPSBcIiNpZiBOVU1fU1BPVF9MSUdIVF9DT09SRFMgPiAwXFxuXFx0dW5pZm9ybSBtYXQ0IHNwb3RMaWdodE1hdHJpeFsgTlVNX1NQT1RfTElHSFRfQ09PUkRTIF07XFxuXFx0dmFyeWluZyB2ZWM0IHZTcG90TGlnaHRDb29yZFsgTlVNX1NQT1RfTElHSFRfQ09PUkRTIF07XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TSEFET1dNQVBcXG5cXHQjaWYgTlVNX0RJUl9MSUdIVF9TSEFET1dTID4gMFxcblxcdFxcdHVuaWZvcm0gbWF0NCBkaXJlY3Rpb25hbFNoYWRvd01hdHJpeFsgTlVNX0RJUl9MSUdIVF9TSEFET1dTIF07XFxuXFx0XFx0dmFyeWluZyB2ZWM0IHZEaXJlY3Rpb25hbFNoYWRvd0Nvb3JkWyBOVU1fRElSX0xJR0hUX1NIQURPV1MgXTtcXG5cXHRcXHRzdHJ1Y3QgRGlyZWN0aW9uYWxMaWdodFNoYWRvdyB7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93SW50ZW5zaXR5O1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd0JpYXM7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93Tm9ybWFsQmlhcztcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dSYWRpdXM7XFxuXFx0XFx0XFx0dmVjMiBzaGFkb3dNYXBTaXplO1xcblxcdFxcdH07XFxuXFx0XFx0dW5pZm9ybSBEaXJlY3Rpb25hbExpZ2h0U2hhZG93IGRpcmVjdGlvbmFsTGlnaHRTaGFkb3dzWyBOVU1fRElSX0xJR0hUX1NIQURPV1MgXTtcXG5cXHQjZW5kaWZcXG5cXHQjaWYgTlVNX1NQT1RfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHRcXHRzdHJ1Y3QgU3BvdExpZ2h0U2hhZG93IHtcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dJbnRlbnNpdHk7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93QmlhcztcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dOb3JtYWxCaWFzO1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd1JhZGl1cztcXG5cXHRcXHRcXHR2ZWMyIHNoYWRvd01hcFNpemU7XFxuXFx0XFx0fTtcXG5cXHRcXHR1bmlmb3JtIFNwb3RMaWdodFNoYWRvdyBzcG90TGlnaHRTaGFkb3dzWyBOVU1fU1BPVF9MSUdIVF9TSEFET1dTIF07XFxuXFx0I2VuZGlmXFxuXFx0I2lmIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTID4gMFxcblxcdFxcdHVuaWZvcm0gbWF0NCBwb2ludFNoYWRvd01hdHJpeFsgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgXTtcXG5cXHRcXHR2YXJ5aW5nIHZlYzQgdlBvaW50U2hhZG93Q29vcmRbIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTIF07XFxuXFx0XFx0c3RydWN0IFBvaW50TGlnaHRTaGFkb3cge1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd0ludGVuc2l0eTtcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dCaWFzO1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd05vcm1hbEJpYXM7XFxuXFx0XFx0XFx0ZmxvYXQgc2hhZG93UmFkaXVzO1xcblxcdFxcdFxcdHZlYzIgc2hhZG93TWFwU2l6ZTtcXG5cXHRcXHRcXHRmbG9hdCBzaGFkb3dDYW1lcmFOZWFyO1xcblxcdFxcdFxcdGZsb2F0IHNoYWRvd0NhbWVyYUZhcjtcXG5cXHRcXHR9O1xcblxcdFxcdHVuaWZvcm0gUG9pbnRMaWdodFNoYWRvdyBwb2ludExpZ2h0U2hhZG93c1sgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgXTtcXG5cXHQjZW5kaWZcXG4jZW5kaWZcIjtcblxudmFyIHNoYWRvd21hcF92ZXJ0ZXggPSBcIiNpZiAoIGRlZmluZWQoIFVTRV9TSEFET1dNQVAgKSAmJiAoIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDAgfHwgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgPiAwICkgKSB8fCAoIE5VTV9TUE9UX0xJR0hUX0NPT1JEUyA+IDAgKVxcblxcdHZlYzMgc2hhZG93V29ybGROb3JtYWwgPSBpbnZlcnNlVHJhbnNmb3JtRGlyZWN0aW9uKCB0cmFuc2Zvcm1lZE5vcm1hbCwgdmlld01hdHJpeCApO1xcblxcdHZlYzQgc2hhZG93V29ybGRQb3NpdGlvbjtcXG4jZW5kaWZcXG4jaWYgZGVmaW5lZCggVVNFX1NIQURPV01BUCApXFxuXFx0I2lmIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XFxuXFx0XFx0Zm9yICggaW50IGkgPSAwOyBpIDwgTlVNX0RJUl9MSUdIVF9TSEFET1dTOyBpICsrICkge1xcblxcdFxcdFxcdHNoYWRvd1dvcmxkUG9zaXRpb24gPSB3b3JsZFBvc2l0aW9uICsgdmVjNCggc2hhZG93V29ybGROb3JtYWwgKiBkaXJlY3Rpb25hbExpZ2h0U2hhZG93c1sgaSBdLnNoYWRvd05vcm1hbEJpYXMsIDAgKTtcXG5cXHRcXHRcXHR2RGlyZWN0aW9uYWxTaGFkb3dDb29yZFsgaSBdID0gZGlyZWN0aW9uYWxTaGFkb3dNYXRyaXhbIGkgXSAqIHNoYWRvd1dvcmxkUG9zaXRpb247XFxuXFx0XFx0fVxcblxcdFxcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXFxuXFx0I2VuZGlmXFxuXFx0I2lmIE5VTV9QT0lOVF9MSUdIVF9TSEFET1dTID4gMFxcblxcdFxcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcXG5cXHRcXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUzsgaSArKyApIHtcXG5cXHRcXHRcXHRzaGFkb3dXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbiArIHZlYzQoIHNoYWRvd1dvcmxkTm9ybWFsICogcG9pbnRMaWdodFNoYWRvd3NbIGkgXS5zaGFkb3dOb3JtYWxCaWFzLCAwICk7XFxuXFx0XFx0XFx0dlBvaW50U2hhZG93Q29vcmRbIGkgXSA9IHBvaW50U2hhZG93TWF0cml4WyBpIF0gKiBzaGFkb3dXb3JsZFBvc2l0aW9uO1xcblxcdFxcdH1cXG5cXHRcXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxcblxcdCNlbmRpZlxcbiNlbmRpZlxcbiNpZiBOVU1fU1BPVF9MSUdIVF9DT09SRFMgPiAwXFxuXFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxcblxcdGZvciAoIGludCBpID0gMDsgaSA8IE5VTV9TUE9UX0xJR0hUX0NPT1JEUzsgaSArKyApIHtcXG5cXHRcXHRzaGFkb3dXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbjtcXG5cXHRcXHQjaWYgKCBkZWZpbmVkKCBVU0VfU0hBRE9XTUFQICkgJiYgVU5ST0xMRURfTE9PUF9JTkRFWCA8IE5VTV9TUE9UX0xJR0hUX1NIQURPV1MgKVxcblxcdFxcdFxcdHNoYWRvd1dvcmxkUG9zaXRpb24ueHl6ICs9IHNoYWRvd1dvcmxkTm9ybWFsICogc3BvdExpZ2h0U2hhZG93c1sgaSBdLnNoYWRvd05vcm1hbEJpYXM7XFxuXFx0XFx0I2VuZGlmXFxuXFx0XFx0dlNwb3RMaWdodENvb3JkWyBpIF0gPSBzcG90TGlnaHRNYXRyaXhbIGkgXSAqIHNoYWRvd1dvcmxkUG9zaXRpb247XFxuXFx0fVxcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXFxuI2VuZGlmXCI7XG5cbnZhciBzaGFkb3dtYXNrX3BhcnNfZnJhZ21lbnQgPSBcImZsb2F0IGdldFNoYWRvd01hc2soKSB7XFxuXFx0ZmxvYXQgc2hhZG93ID0gMS4wO1xcblxcdCNpZmRlZiBVU0VfU0hBRE9XTUFQXFxuXFx0I2lmIE5VTV9ESVJfTElHSFRfU0hBRE9XUyA+IDBcXG5cXHREaXJlY3Rpb25hbExpZ2h0U2hhZG93IGRpcmVjdGlvbmFsTGlnaHQ7XFxuXFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxcblxcdGZvciAoIGludCBpID0gMDsgaSA8IE5VTV9ESVJfTElHSFRfU0hBRE9XUzsgaSArKyApIHtcXG5cXHRcXHRkaXJlY3Rpb25hbExpZ2h0ID0gZGlyZWN0aW9uYWxMaWdodFNoYWRvd3NbIGkgXTtcXG5cXHRcXHRzaGFkb3cgKj0gcmVjZWl2ZVNoYWRvdyA/IGdldFNoYWRvdyggZGlyZWN0aW9uYWxTaGFkb3dNYXBbIGkgXSwgZGlyZWN0aW9uYWxMaWdodC5zaGFkb3dNYXBTaXplLCBkaXJlY3Rpb25hbExpZ2h0LnNoYWRvd0ludGVuc2l0eSwgZGlyZWN0aW9uYWxMaWdodC5zaGFkb3dCaWFzLCBkaXJlY3Rpb25hbExpZ2h0LnNoYWRvd1JhZGl1cywgdkRpcmVjdGlvbmFsU2hhZG93Q29vcmRbIGkgXSApIDogMS4wO1xcblxcdH1cXG5cXHQjcHJhZ21hIHVucm9sbF9sb29wX2VuZFxcblxcdCNlbmRpZlxcblxcdCNpZiBOVU1fU1BPVF9MSUdIVF9TSEFET1dTID4gMFxcblxcdFNwb3RMaWdodFNoYWRvdyBzcG90TGlnaHQ7XFxuXFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9zdGFydFxcblxcdGZvciAoIGludCBpID0gMDsgaSA8IE5VTV9TUE9UX0xJR0hUX1NIQURPV1M7IGkgKysgKSB7XFxuXFx0XFx0c3BvdExpZ2h0ID0gc3BvdExpZ2h0U2hhZG93c1sgaSBdO1xcblxcdFxcdHNoYWRvdyAqPSByZWNlaXZlU2hhZG93ID8gZ2V0U2hhZG93KCBzcG90U2hhZG93TWFwWyBpIF0sIHNwb3RMaWdodC5zaGFkb3dNYXBTaXplLCBzcG90TGlnaHQuc2hhZG93SW50ZW5zaXR5LCBzcG90TGlnaHQuc2hhZG93Qmlhcywgc3BvdExpZ2h0LnNoYWRvd1JhZGl1cywgdlNwb3RMaWdodENvb3JkWyBpIF0gKSA6IDEuMDtcXG5cXHR9XFxuXFx0I3ByYWdtYSB1bnJvbGxfbG9vcF9lbmRcXG5cXHQjZW5kaWZcXG5cXHQjaWYgTlVNX1BPSU5UX0xJR0hUX1NIQURPV1MgPiAwXFxuXFx0UG9pbnRMaWdodFNoYWRvdyBwb2ludExpZ2h0O1xcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3Bfc3RhcnRcXG5cXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBOVU1fUE9JTlRfTElHSFRfU0hBRE9XUzsgaSArKyApIHtcXG5cXHRcXHRwb2ludExpZ2h0ID0gcG9pbnRMaWdodFNoYWRvd3NbIGkgXTtcXG5cXHRcXHRzaGFkb3cgKj0gcmVjZWl2ZVNoYWRvdyA/IGdldFBvaW50U2hhZG93KCBwb2ludFNoYWRvd01hcFsgaSBdLCBwb2ludExpZ2h0LnNoYWRvd01hcFNpemUsIHBvaW50TGlnaHQuc2hhZG93SW50ZW5zaXR5LCBwb2ludExpZ2h0LnNoYWRvd0JpYXMsIHBvaW50TGlnaHQuc2hhZG93UmFkaXVzLCB2UG9pbnRTaGFkb3dDb29yZFsgaSBdLCBwb2ludExpZ2h0LnNoYWRvd0NhbWVyYU5lYXIsIHBvaW50TGlnaHQuc2hhZG93Q2FtZXJhRmFyICkgOiAxLjA7XFxuXFx0fVxcblxcdCNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kXFxuXFx0I2VuZGlmXFxuXFx0I2VuZGlmXFxuXFx0cmV0dXJuIHNoYWRvdztcXG59XCI7XG5cbnZhciBza2luYmFzZV92ZXJ0ZXggPSBcIiNpZmRlZiBVU0VfU0tJTk5JTkdcXG5cXHRtYXQ0IGJvbmVNYXRYID0gZ2V0Qm9uZU1hdHJpeCggc2tpbkluZGV4LnggKTtcXG5cXHRtYXQ0IGJvbmVNYXRZID0gZ2V0Qm9uZU1hdHJpeCggc2tpbkluZGV4LnkgKTtcXG5cXHRtYXQ0IGJvbmVNYXRaID0gZ2V0Qm9uZU1hdHJpeCggc2tpbkluZGV4LnogKTtcXG5cXHRtYXQ0IGJvbmVNYXRXID0gZ2V0Qm9uZU1hdHJpeCggc2tpbkluZGV4LncgKTtcXG4jZW5kaWZcIjtcblxudmFyIHNraW5uaW5nX3BhcnNfdmVydGV4ID0gXCIjaWZkZWYgVVNFX1NLSU5OSU5HXFxuXFx0dW5pZm9ybSBtYXQ0IGJpbmRNYXRyaXg7XFxuXFx0dW5pZm9ybSBtYXQ0IGJpbmRNYXRyaXhJbnZlcnNlO1xcblxcdHVuaWZvcm0gaGlnaHAgc2FtcGxlcjJEIGJvbmVUZXh0dXJlO1xcblxcdG1hdDQgZ2V0Qm9uZU1hdHJpeCggY29uc3QgaW4gZmxvYXQgaSApIHtcXG5cXHRcXHRpbnQgc2l6ZSA9IHRleHR1cmVTaXplKCBib25lVGV4dHVyZSwgMCApLng7XFxuXFx0XFx0aW50IGogPSBpbnQoIGkgKSAqIDQ7XFxuXFx0XFx0aW50IHggPSBqICUgc2l6ZTtcXG5cXHRcXHRpbnQgeSA9IGogLyBzaXplO1xcblxcdFxcdHZlYzQgdjEgPSB0ZXhlbEZldGNoKCBib25lVGV4dHVyZSwgaXZlYzIoIHgsIHkgKSwgMCApO1xcblxcdFxcdHZlYzQgdjIgPSB0ZXhlbEZldGNoKCBib25lVGV4dHVyZSwgaXZlYzIoIHggKyAxLCB5ICksIDAgKTtcXG5cXHRcXHR2ZWM0IHYzID0gdGV4ZWxGZXRjaCggYm9uZVRleHR1cmUsIGl2ZWMyKCB4ICsgMiwgeSApLCAwICk7XFxuXFx0XFx0dmVjNCB2NCA9IHRleGVsRmV0Y2goIGJvbmVUZXh0dXJlLCBpdmVjMiggeCArIDMsIHkgKSwgMCApO1xcblxcdFxcdHJldHVybiBtYXQ0KCB2MSwgdjIsIHYzLCB2NCApO1xcblxcdH1cXG4jZW5kaWZcIjtcblxudmFyIHNraW5uaW5nX3ZlcnRleCA9IFwiI2lmZGVmIFVTRV9TS0lOTklOR1xcblxcdHZlYzQgc2tpblZlcnRleCA9IGJpbmRNYXRyaXggKiB2ZWM0KCB0cmFuc2Zvcm1lZCwgMS4wICk7XFxuXFx0dmVjNCBza2lubmVkID0gdmVjNCggMC4wICk7XFxuXFx0c2tpbm5lZCArPSBib25lTWF0WCAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lng7XFxuXFx0c2tpbm5lZCArPSBib25lTWF0WSAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lnk7XFxuXFx0c2tpbm5lZCArPSBib25lTWF0WiAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lno7XFxuXFx0c2tpbm5lZCArPSBib25lTWF0VyAqIHNraW5WZXJ0ZXggKiBza2luV2VpZ2h0Lnc7XFxuXFx0dHJhbnNmb3JtZWQgPSAoIGJpbmRNYXRyaXhJbnZlcnNlICogc2tpbm5lZCApLnh5ejtcXG4jZW5kaWZcIjtcblxudmFyIHNraW5ub3JtYWxfdmVydGV4ID0gXCIjaWZkZWYgVVNFX1NLSU5OSU5HXFxuXFx0bWF0NCBza2luTWF0cml4ID0gbWF0NCggMC4wICk7XFxuXFx0c2tpbk1hdHJpeCArPSBza2luV2VpZ2h0LnggKiBib25lTWF0WDtcXG5cXHRza2luTWF0cml4ICs9IHNraW5XZWlnaHQueSAqIGJvbmVNYXRZO1xcblxcdHNraW5NYXRyaXggKz0gc2tpbldlaWdodC56ICogYm9uZU1hdFo7XFxuXFx0c2tpbk1hdHJpeCArPSBza2luV2VpZ2h0LncgKiBib25lTWF0VztcXG5cXHRza2luTWF0cml4ID0gYmluZE1hdHJpeEludmVyc2UgKiBza2luTWF0cml4ICogYmluZE1hdHJpeDtcXG5cXHRvYmplY3ROb3JtYWwgPSB2ZWM0KCBza2luTWF0cml4ICogdmVjNCggb2JqZWN0Tm9ybWFsLCAwLjAgKSApLnh5ejtcXG5cXHQjaWZkZWYgVVNFX1RBTkdFTlRcXG5cXHRcXHRvYmplY3RUYW5nZW50ID0gdmVjNCggc2tpbk1hdHJpeCAqIHZlYzQoIG9iamVjdFRhbmdlbnQsIDAuMCApICkueHl6O1xcblxcdCNlbmRpZlxcbiNlbmRpZlwiO1xuXG52YXIgc3BlY3VsYXJtYXBfZnJhZ21lbnQgPSBcImZsb2F0IHNwZWN1bGFyU3RyZW5ndGg7XFxuI2lmZGVmIFVTRV9TUEVDVUxBUk1BUFxcblxcdHZlYzQgdGV4ZWxTcGVjdWxhciA9IHRleHR1cmUyRCggc3BlY3VsYXJNYXAsIHZTcGVjdWxhck1hcFV2ICk7XFxuXFx0c3BlY3VsYXJTdHJlbmd0aCA9IHRleGVsU3BlY3VsYXIucjtcXG4jZWxzZVxcblxcdHNwZWN1bGFyU3RyZW5ndGggPSAxLjA7XFxuI2VuZGlmXCI7XG5cbnZhciBzcGVjdWxhcm1hcF9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX1NQRUNVTEFSTUFQXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgc3BlY3VsYXJNYXA7XFxuI2VuZGlmXCI7XG5cbnZhciB0b25lbWFwcGluZ19mcmFnbWVudCA9IFwiI2lmIGRlZmluZWQoIFRPTkVfTUFQUElORyApXFxuXFx0Z2xfRnJhZ0NvbG9yLnJnYiA9IHRvbmVNYXBwaW5nKCBnbF9GcmFnQ29sb3IucmdiICk7XFxuI2VuZGlmXCI7XG5cbnZhciB0b25lbWFwcGluZ19wYXJzX2ZyYWdtZW50ID0gXCIjaWZuZGVmIHNhdHVyYXRlXFxuI2RlZmluZSBzYXR1cmF0ZSggYSApIGNsYW1wKCBhLCAwLjAsIDEuMCApXFxuI2VuZGlmXFxudW5pZm9ybSBmbG9hdCB0b25lTWFwcGluZ0V4cG9zdXJlO1xcbnZlYzMgTGluZWFyVG9uZU1hcHBpbmcoIHZlYzMgY29sb3IgKSB7XFxuXFx0cmV0dXJuIHNhdHVyYXRlKCB0b25lTWFwcGluZ0V4cG9zdXJlICogY29sb3IgKTtcXG59XFxudmVjMyBSZWluaGFyZFRvbmVNYXBwaW5nKCB2ZWMzIGNvbG9yICkge1xcblxcdGNvbG9yICo9IHRvbmVNYXBwaW5nRXhwb3N1cmU7XFxuXFx0cmV0dXJuIHNhdHVyYXRlKCBjb2xvciAvICggdmVjMyggMS4wICkgKyBjb2xvciApICk7XFxufVxcbnZlYzMgT3B0aW1pemVkQ2luZW9uVG9uZU1hcHBpbmcoIHZlYzMgY29sb3IgKSB7XFxuXFx0Y29sb3IgKj0gdG9uZU1hcHBpbmdFeHBvc3VyZTtcXG5cXHRjb2xvciA9IG1heCggdmVjMyggMC4wICksIGNvbG9yIC0gMC4wMDQgKTtcXG5cXHRyZXR1cm4gcG93KCAoIGNvbG9yICogKCA2LjIgKiBjb2xvciArIDAuNSApICkgLyAoIGNvbG9yICogKCA2LjIgKiBjb2xvciArIDEuNyApICsgMC4wNiApLCB2ZWMzKCAyLjIgKSApO1xcbn1cXG52ZWMzIFJSVEFuZE9EVEZpdCggdmVjMyB2ICkge1xcblxcdHZlYzMgYSA9IHYgKiAoIHYgKyAwLjAyNDU3ODYgKSAtIDAuMDAwMDkwNTM3O1xcblxcdHZlYzMgYiA9IHYgKiAoIDAuOTgzNzI5ICogdiArIDAuNDMyOTUxMCApICsgMC4yMzgwODE7XFxuXFx0cmV0dXJuIGEgLyBiO1xcbn1cXG52ZWMzIEFDRVNGaWxtaWNUb25lTWFwcGluZyggdmVjMyBjb2xvciApIHtcXG5cXHRjb25zdCBtYXQzIEFDRVNJbnB1dE1hdCA9IG1hdDMoXFxuXFx0XFx0dmVjMyggMC41OTcxOSwgMC4wNzYwMCwgMC4wMjg0MCApLFxcdFxcdHZlYzMoIDAuMzU0NTgsIDAuOTA4MzQsIDAuMTMzODMgKSxcXG5cXHRcXHR2ZWMzKCAwLjA0ODIzLCAwLjAxNTY2LCAwLjgzNzc3IClcXG5cXHQpO1xcblxcdGNvbnN0IG1hdDMgQUNFU091dHB1dE1hdCA9IG1hdDMoXFxuXFx0XFx0dmVjMyggIDEuNjA0NzUsIC0wLjEwMjA4LCAtMC4wMDMyNyApLFxcdFxcdHZlYzMoIC0wLjUzMTA4LCAgMS4xMDgxMywgLTAuMDcyNzYgKSxcXG5cXHRcXHR2ZWMzKCAtMC4wNzM2NywgLTAuMDA2MDUsICAxLjA3NjAyIClcXG5cXHQpO1xcblxcdGNvbG9yICo9IHRvbmVNYXBwaW5nRXhwb3N1cmUgLyAwLjY7XFxuXFx0Y29sb3IgPSBBQ0VTSW5wdXRNYXQgKiBjb2xvcjtcXG5cXHRjb2xvciA9IFJSVEFuZE9EVEZpdCggY29sb3IgKTtcXG5cXHRjb2xvciA9IEFDRVNPdXRwdXRNYXQgKiBjb2xvcjtcXG5cXHRyZXR1cm4gc2F0dXJhdGUoIGNvbG9yICk7XFxufVxcbmNvbnN0IG1hdDMgTElORUFSX1JFQzIwMjBfVE9fTElORUFSX1NSR0IgPSBtYXQzKFxcblxcdHZlYzMoIDEuNjYwNSwgLSAwLjEyNDYsIC0gMC4wMTgyICksXFxuXFx0dmVjMyggLSAwLjU4NzYsIDEuMTMyOSwgLSAwLjEwMDYgKSxcXG5cXHR2ZWMzKCAtIDAuMDcyOCwgLSAwLjAwODMsIDEuMTE4NyApXFxuKTtcXG5jb25zdCBtYXQzIExJTkVBUl9TUkdCX1RPX0xJTkVBUl9SRUMyMDIwID0gbWF0MyhcXG5cXHR2ZWMzKCAwLjYyNzQsIDAuMDY5MSwgMC4wMTY0ICksXFxuXFx0dmVjMyggMC4zMjkzLCAwLjkxOTUsIDAuMDg4MCApLFxcblxcdHZlYzMoIDAuMDQzMywgMC4wMTEzLCAwLjg5NTYgKVxcbik7XFxudmVjMyBhZ3hEZWZhdWx0Q29udHJhc3RBcHByb3goIHZlYzMgeCApIHtcXG5cXHR2ZWMzIHgyID0geCAqIHg7XFxuXFx0dmVjMyB4NCA9IHgyICogeDI7XFxuXFx0cmV0dXJuICsgMTUuNSAqIHg0ICogeDJcXG5cXHRcXHQtIDQwLjE0ICogeDQgKiB4XFxuXFx0XFx0KyAzMS45NiAqIHg0XFxuXFx0XFx0LSA2Ljg2OCAqIHgyICogeFxcblxcdFxcdCsgMC40Mjk4ICogeDJcXG5cXHRcXHQrIDAuMTE5MSAqIHhcXG5cXHRcXHQtIDAuMDAyMzI7XFxufVxcbnZlYzMgQWdYVG9uZU1hcHBpbmcoIHZlYzMgY29sb3IgKSB7XFxuXFx0Y29uc3QgbWF0MyBBZ1hJbnNldE1hdHJpeCA9IG1hdDMoXFxuXFx0XFx0dmVjMyggMC44NTY2MjcxNTMzMTU5ODMsIDAuMTM3MzE4OTcyOTI5ODQ3LCAwLjExMTg5ODIxMjk5OTk1ICksXFxuXFx0XFx0dmVjMyggMC4wOTUxMjEyNDA1MzgxNTg4LCAwLjc2MTI0MTk5MDYwMjU5MSwgMC4wNzY3OTk0MTg2MDMxOTAzICksXFxuXFx0XFx0dmVjMyggMC4wNDgyNTE2MDYxNDU4NTgzLCAwLjEwMTQzOTAzNjQ2NzU2MiwgMC44MTEzMDIzNjgzOTY4NTkgKVxcblxcdCk7XFxuXFx0Y29uc3QgbWF0MyBBZ1hPdXRzZXRNYXRyaXggPSBtYXQzKFxcblxcdFxcdHZlYzMoIDEuMTI3MTAwNTgxODE0NDM2OCwgLSAwLjE0MTMyOTc2MzQ5ODQzODMsIC0gMC4xNDEzMjk3NjM0OTg0MzgyNiApLFxcblxcdFxcdHZlYzMoIC0gMC4xMTA2MDY2NDMwOTY2MDMyMywgMS4xNTc4MjM3MDIyMTYyNzIsIC0gMC4xMTA2MDY2NDMwOTY2MDI5NCApLFxcblxcdFxcdHZlYzMoIC0gMC4wMTY0OTM5Mzg3MTc4MzQ1NzMsIC0gMC4wMTY0OTM5Mzg3MTc4MzQyNTcsIDEuMjUxOTM2NDA2NTk1MDQwNSApXFxuXFx0KTtcXG5cXHRjb25zdCBmbG9hdCBBZ3hNaW5FdiA9IC0gMTIuNDczOTM7XFx0Y29uc3QgZmxvYXQgQWd4TWF4RXYgPSA0LjAyNjA2OTtcXG5cXHRjb2xvciAqPSB0b25lTWFwcGluZ0V4cG9zdXJlO1xcblxcdGNvbG9yID0gTElORUFSX1NSR0JfVE9fTElORUFSX1JFQzIwMjAgKiBjb2xvcjtcXG5cXHRjb2xvciA9IEFnWEluc2V0TWF0cml4ICogY29sb3I7XFxuXFx0Y29sb3IgPSBtYXgoIGNvbG9yLCAxZS0xMCApO1xcdGNvbG9yID0gbG9nMiggY29sb3IgKTtcXG5cXHRjb2xvciA9ICggY29sb3IgLSBBZ3hNaW5FdiApIC8gKCBBZ3hNYXhFdiAtIEFneE1pbkV2ICk7XFxuXFx0Y29sb3IgPSBjbGFtcCggY29sb3IsIDAuMCwgMS4wICk7XFxuXFx0Y29sb3IgPSBhZ3hEZWZhdWx0Q29udHJhc3RBcHByb3goIGNvbG9yICk7XFxuXFx0Y29sb3IgPSBBZ1hPdXRzZXRNYXRyaXggKiBjb2xvcjtcXG5cXHRjb2xvciA9IHBvdyggbWF4KCB2ZWMzKCAwLjAgKSwgY29sb3IgKSwgdmVjMyggMi4yICkgKTtcXG5cXHRjb2xvciA9IExJTkVBUl9SRUMyMDIwX1RPX0xJTkVBUl9TUkdCICogY29sb3I7XFxuXFx0Y29sb3IgPSBjbGFtcCggY29sb3IsIDAuMCwgMS4wICk7XFxuXFx0cmV0dXJuIGNvbG9yO1xcbn1cXG52ZWMzIE5ldXRyYWxUb25lTWFwcGluZyggdmVjMyBjb2xvciApIHtcXG5cXHRjb25zdCBmbG9hdCBTdGFydENvbXByZXNzaW9uID0gMC44IC0gMC4wNDtcXG5cXHRjb25zdCBmbG9hdCBEZXNhdHVyYXRpb24gPSAwLjE1O1xcblxcdGNvbG9yICo9IHRvbmVNYXBwaW5nRXhwb3N1cmU7XFxuXFx0ZmxvYXQgeCA9IG1pbiggY29sb3IuciwgbWluKCBjb2xvci5nLCBjb2xvci5iICkgKTtcXG5cXHRmbG9hdCBvZmZzZXQgPSB4IDwgMC4wOCA/IHggLSA2LjI1ICogeCAqIHggOiAwLjA0O1xcblxcdGNvbG9yIC09IG9mZnNldDtcXG5cXHRmbG9hdCBwZWFrID0gbWF4KCBjb2xvci5yLCBtYXgoIGNvbG9yLmcsIGNvbG9yLmIgKSApO1xcblxcdGlmICggcGVhayA8IFN0YXJ0Q29tcHJlc3Npb24gKSByZXR1cm4gY29sb3I7XFxuXFx0ZmxvYXQgZCA9IDEuIC0gU3RhcnRDb21wcmVzc2lvbjtcXG5cXHRmbG9hdCBuZXdQZWFrID0gMS4gLSBkICogZCAvICggcGVhayArIGQgLSBTdGFydENvbXByZXNzaW9uICk7XFxuXFx0Y29sb3IgKj0gbmV3UGVhayAvIHBlYWs7XFxuXFx0ZmxvYXQgZyA9IDEuIC0gMS4gLyAoIERlc2F0dXJhdGlvbiAqICggcGVhayAtIG5ld1BlYWsgKSArIDEuICk7XFxuXFx0cmV0dXJuIG1peCggY29sb3IsIHZlYzMoIG5ld1BlYWsgKSwgZyApO1xcbn1cXG52ZWMzIEN1c3RvbVRvbmVNYXBwaW5nKCB2ZWMzIGNvbG9yICkgeyByZXR1cm4gY29sb3I7IH1cIjtcblxudmFyIHRyYW5zbWlzc2lvbl9mcmFnbWVudCA9IFwiI2lmZGVmIFVTRV9UUkFOU01JU1NJT05cXG5cXHRtYXRlcmlhbC50cmFuc21pc3Npb24gPSB0cmFuc21pc3Npb247XFxuXFx0bWF0ZXJpYWwudHJhbnNtaXNzaW9uQWxwaGEgPSAxLjA7XFxuXFx0bWF0ZXJpYWwudGhpY2tuZXNzID0gdGhpY2tuZXNzO1xcblxcdG1hdGVyaWFsLmF0dGVudWF0aW9uRGlzdGFuY2UgPSBhdHRlbnVhdGlvbkRpc3RhbmNlO1xcblxcdG1hdGVyaWFsLmF0dGVudWF0aW9uQ29sb3IgPSBhdHRlbnVhdGlvbkNvbG9yO1xcblxcdCNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OTUFQXFxuXFx0XFx0bWF0ZXJpYWwudHJhbnNtaXNzaW9uICo9IHRleHR1cmUyRCggdHJhbnNtaXNzaW9uTWFwLCB2VHJhbnNtaXNzaW9uTWFwVXYgKS5yO1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBVU0VfVEhJQ0tORVNTTUFQXFxuXFx0XFx0bWF0ZXJpYWwudGhpY2tuZXNzICo9IHRleHR1cmUyRCggdGhpY2tuZXNzTWFwLCB2VGhpY2tuZXNzTWFwVXYgKS5nO1xcblxcdCNlbmRpZlxcblxcdHZlYzMgcG9zID0gdldvcmxkUG9zaXRpb247XFxuXFx0dmVjMyB2ID0gbm9ybWFsaXplKCBjYW1lcmFQb3NpdGlvbiAtIHBvcyApO1xcblxcdHZlYzMgbiA9IGludmVyc2VUcmFuc2Zvcm1EaXJlY3Rpb24oIG5vcm1hbCwgdmlld01hdHJpeCApO1xcblxcdHZlYzQgdHJhbnNtaXR0ZWQgPSBnZXRJQkxWb2x1bWVSZWZyYWN0aW9uKFxcblxcdFxcdG4sIHYsIG1hdGVyaWFsLnJvdWdobmVzcywgbWF0ZXJpYWwuZGlmZnVzZUNvbG9yLCBtYXRlcmlhbC5zcGVjdWxhckNvbG9yLCBtYXRlcmlhbC5zcGVjdWxhckY5MCxcXG5cXHRcXHRwb3MsIG1vZGVsTWF0cml4LCB2aWV3TWF0cml4LCBwcm9qZWN0aW9uTWF0cml4LCBtYXRlcmlhbC5kaXNwZXJzaW9uLCBtYXRlcmlhbC5pb3IsIG1hdGVyaWFsLnRoaWNrbmVzcyxcXG5cXHRcXHRtYXRlcmlhbC5hdHRlbnVhdGlvbkNvbG9yLCBtYXRlcmlhbC5hdHRlbnVhdGlvbkRpc3RhbmNlICk7XFxuXFx0bWF0ZXJpYWwudHJhbnNtaXNzaW9uQWxwaGEgPSBtaXgoIG1hdGVyaWFsLnRyYW5zbWlzc2lvbkFscGhhLCB0cmFuc21pdHRlZC5hLCBtYXRlcmlhbC50cmFuc21pc3Npb24gKTtcXG5cXHR0b3RhbERpZmZ1c2UgPSBtaXgoIHRvdGFsRGlmZnVzZSwgdHJhbnNtaXR0ZWQucmdiLCBtYXRlcmlhbC50cmFuc21pc3Npb24gKTtcXG4jZW5kaWZcIjtcblxudmFyIHRyYW5zbWlzc2lvbl9wYXJzX2ZyYWdtZW50ID0gXCIjaWZkZWYgVVNFX1RSQU5TTUlTU0lPTlxcblxcdHVuaWZvcm0gZmxvYXQgdHJhbnNtaXNzaW9uO1xcblxcdHVuaWZvcm0gZmxvYXQgdGhpY2tuZXNzO1xcblxcdHVuaWZvcm0gZmxvYXQgYXR0ZW51YXRpb25EaXN0YW5jZTtcXG5cXHR1bmlmb3JtIHZlYzMgYXR0ZW51YXRpb25Db2xvcjtcXG5cXHQjaWZkZWYgVVNFX1RSQU5TTUlTU0lPTk1BUFxcblxcdFxcdHVuaWZvcm0gc2FtcGxlcjJEIHRyYW5zbWlzc2lvbk1hcDtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX1RISUNLTkVTU01BUFxcblxcdFxcdHVuaWZvcm0gc2FtcGxlcjJEIHRoaWNrbmVzc01hcDtcXG5cXHQjZW5kaWZcXG5cXHR1bmlmb3JtIHZlYzIgdHJhbnNtaXNzaW9uU2FtcGxlclNpemU7XFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgdHJhbnNtaXNzaW9uU2FtcGxlck1hcDtcXG5cXHR1bmlmb3JtIG1hdDQgbW9kZWxNYXRyaXg7XFxuXFx0dW5pZm9ybSBtYXQ0IHByb2plY3Rpb25NYXRyaXg7XFxuXFx0dmFyeWluZyB2ZWMzIHZXb3JsZFBvc2l0aW9uO1xcblxcdGZsb2F0IHcwKCBmbG9hdCBhICkge1xcblxcdFxcdHJldHVybiAoIDEuMCAvIDYuMCApICogKCBhICogKCBhICogKCAtIGEgKyAzLjAgKSAtIDMuMCApICsgMS4wICk7XFxuXFx0fVxcblxcdGZsb2F0IHcxKCBmbG9hdCBhICkge1xcblxcdFxcdHJldHVybiAoIDEuMCAvIDYuMCApICogKCBhICogIGEgKiAoIDMuMCAqIGEgLSA2LjAgKSArIDQuMCApO1xcblxcdH1cXG5cXHRmbG9hdCB3MiggZmxvYXQgYSApe1xcblxcdFxcdHJldHVybiAoIDEuMCAvIDYuMCApICogKCBhICogKCBhICogKCAtIDMuMCAqIGEgKyAzLjAgKSArIDMuMCApICsgMS4wICk7XFxuXFx0fVxcblxcdGZsb2F0IHczKCBmbG9hdCBhICkge1xcblxcdFxcdHJldHVybiAoIDEuMCAvIDYuMCApICogKCBhICogYSAqIGEgKTtcXG5cXHR9XFxuXFx0ZmxvYXQgZzAoIGZsb2F0IGEgKSB7XFxuXFx0XFx0cmV0dXJuIHcwKCBhICkgKyB3MSggYSApO1xcblxcdH1cXG5cXHRmbG9hdCBnMSggZmxvYXQgYSApIHtcXG5cXHRcXHRyZXR1cm4gdzIoIGEgKSArIHczKCBhICk7XFxuXFx0fVxcblxcdGZsb2F0IGgwKCBmbG9hdCBhICkge1xcblxcdFxcdHJldHVybiAtIDEuMCArIHcxKCBhICkgLyAoIHcwKCBhICkgKyB3MSggYSApICk7XFxuXFx0fVxcblxcdGZsb2F0IGgxKCBmbG9hdCBhICkge1xcblxcdFxcdHJldHVybiAxLjAgKyB3MyggYSApIC8gKCB3MiggYSApICsgdzMoIGEgKSApO1xcblxcdH1cXG5cXHR2ZWM0IGJpY3ViaWMoIHNhbXBsZXIyRCB0ZXgsIHZlYzIgdXYsIHZlYzQgdGV4ZWxTaXplLCBmbG9hdCBsb2QgKSB7XFxuXFx0XFx0dXYgPSB1diAqIHRleGVsU2l6ZS56dyArIDAuNTtcXG5cXHRcXHR2ZWMyIGl1diA9IGZsb29yKCB1diApO1xcblxcdFxcdHZlYzIgZnV2ID0gZnJhY3QoIHV2ICk7XFxuXFx0XFx0ZmxvYXQgZzB4ID0gZzAoIGZ1di54ICk7XFxuXFx0XFx0ZmxvYXQgZzF4ID0gZzEoIGZ1di54ICk7XFxuXFx0XFx0ZmxvYXQgaDB4ID0gaDAoIGZ1di54ICk7XFxuXFx0XFx0ZmxvYXQgaDF4ID0gaDEoIGZ1di54ICk7XFxuXFx0XFx0ZmxvYXQgaDB5ID0gaDAoIGZ1di55ICk7XFxuXFx0XFx0ZmxvYXQgaDF5ID0gaDEoIGZ1di55ICk7XFxuXFx0XFx0dmVjMiBwMCA9ICggdmVjMiggaXV2LnggKyBoMHgsIGl1di55ICsgaDB5ICkgLSAwLjUgKSAqIHRleGVsU2l6ZS54eTtcXG5cXHRcXHR2ZWMyIHAxID0gKCB2ZWMyKCBpdXYueCArIGgxeCwgaXV2LnkgKyBoMHkgKSAtIDAuNSApICogdGV4ZWxTaXplLnh5O1xcblxcdFxcdHZlYzIgcDIgPSAoIHZlYzIoIGl1di54ICsgaDB4LCBpdXYueSArIGgxeSApIC0gMC41ICkgKiB0ZXhlbFNpemUueHk7XFxuXFx0XFx0dmVjMiBwMyA9ICggdmVjMiggaXV2LnggKyBoMXgsIGl1di55ICsgaDF5ICkgLSAwLjUgKSAqIHRleGVsU2l6ZS54eTtcXG5cXHRcXHRyZXR1cm4gZzAoIGZ1di55ICkgKiAoIGcweCAqIHRleHR1cmVMb2QoIHRleCwgcDAsIGxvZCApICsgZzF4ICogdGV4dHVyZUxvZCggdGV4LCBwMSwgbG9kICkgKSArXFxuXFx0XFx0XFx0ZzEoIGZ1di55ICkgKiAoIGcweCAqIHRleHR1cmVMb2QoIHRleCwgcDIsIGxvZCApICsgZzF4ICogdGV4dHVyZUxvZCggdGV4LCBwMywgbG9kICkgKTtcXG5cXHR9XFxuXFx0dmVjNCB0ZXh0dXJlQmljdWJpYyggc2FtcGxlcjJEIHNhbXBsZXIsIHZlYzIgdXYsIGZsb2F0IGxvZCApIHtcXG5cXHRcXHR2ZWMyIGZMb2RTaXplID0gdmVjMiggdGV4dHVyZVNpemUoIHNhbXBsZXIsIGludCggbG9kICkgKSApO1xcblxcdFxcdHZlYzIgY0xvZFNpemUgPSB2ZWMyKCB0ZXh0dXJlU2l6ZSggc2FtcGxlciwgaW50KCBsb2QgKyAxLjAgKSApICk7XFxuXFx0XFx0dmVjMiBmTG9kU2l6ZUludiA9IDEuMCAvIGZMb2RTaXplO1xcblxcdFxcdHZlYzIgY0xvZFNpemVJbnYgPSAxLjAgLyBjTG9kU2l6ZTtcXG5cXHRcXHR2ZWM0IGZTYW1wbGUgPSBiaWN1YmljKCBzYW1wbGVyLCB1diwgdmVjNCggZkxvZFNpemVJbnYsIGZMb2RTaXplICksIGZsb29yKCBsb2QgKSApO1xcblxcdFxcdHZlYzQgY1NhbXBsZSA9IGJpY3ViaWMoIHNhbXBsZXIsIHV2LCB2ZWM0KCBjTG9kU2l6ZUludiwgY0xvZFNpemUgKSwgY2VpbCggbG9kICkgKTtcXG5cXHRcXHRyZXR1cm4gbWl4KCBmU2FtcGxlLCBjU2FtcGxlLCBmcmFjdCggbG9kICkgKTtcXG5cXHR9XFxuXFx0dmVjMyBnZXRWb2x1bWVUcmFuc21pc3Npb25SYXkoIGNvbnN0IGluIHZlYzMgbiwgY29uc3QgaW4gdmVjMyB2LCBjb25zdCBpbiBmbG9hdCB0aGlja25lc3MsIGNvbnN0IGluIGZsb2F0IGlvciwgY29uc3QgaW4gbWF0NCBtb2RlbE1hdHJpeCApIHtcXG5cXHRcXHR2ZWMzIHJlZnJhY3Rpb25WZWN0b3IgPSByZWZyYWN0KCAtIHYsIG5vcm1hbGl6ZSggbiApLCAxLjAgLyBpb3IgKTtcXG5cXHRcXHR2ZWMzIG1vZGVsU2NhbGU7XFxuXFx0XFx0bW9kZWxTY2FsZS54ID0gbGVuZ3RoKCB2ZWMzKCBtb2RlbE1hdHJpeFsgMCBdLnh5eiApICk7XFxuXFx0XFx0bW9kZWxTY2FsZS55ID0gbGVuZ3RoKCB2ZWMzKCBtb2RlbE1hdHJpeFsgMSBdLnh5eiApICk7XFxuXFx0XFx0bW9kZWxTY2FsZS56ID0gbGVuZ3RoKCB2ZWMzKCBtb2RlbE1hdHJpeFsgMiBdLnh5eiApICk7XFxuXFx0XFx0cmV0dXJuIG5vcm1hbGl6ZSggcmVmcmFjdGlvblZlY3RvciApICogdGhpY2tuZXNzICogbW9kZWxTY2FsZTtcXG5cXHR9XFxuXFx0ZmxvYXQgYXBwbHlJb3JUb1JvdWdobmVzcyggY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzLCBjb25zdCBpbiBmbG9hdCBpb3IgKSB7XFxuXFx0XFx0cmV0dXJuIHJvdWdobmVzcyAqIGNsYW1wKCBpb3IgKiAyLjAgLSAyLjAsIDAuMCwgMS4wICk7XFxuXFx0fVxcblxcdHZlYzQgZ2V0VHJhbnNtaXNzaW9uU2FtcGxlKCBjb25zdCBpbiB2ZWMyIGZyYWdDb29yZCwgY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzLCBjb25zdCBpbiBmbG9hdCBpb3IgKSB7XFxuXFx0XFx0ZmxvYXQgbG9kID0gbG9nMiggdHJhbnNtaXNzaW9uU2FtcGxlclNpemUueCApICogYXBwbHlJb3JUb1JvdWdobmVzcyggcm91Z2huZXNzLCBpb3IgKTtcXG5cXHRcXHRyZXR1cm4gdGV4dHVyZUJpY3ViaWMoIHRyYW5zbWlzc2lvblNhbXBsZXJNYXAsIGZyYWdDb29yZC54eSwgbG9kICk7XFxuXFx0fVxcblxcdHZlYzMgdm9sdW1lQXR0ZW51YXRpb24oIGNvbnN0IGluIGZsb2F0IHRyYW5zbWlzc2lvbkRpc3RhbmNlLCBjb25zdCBpbiB2ZWMzIGF0dGVudWF0aW9uQ29sb3IsIGNvbnN0IGluIGZsb2F0IGF0dGVudWF0aW9uRGlzdGFuY2UgKSB7XFxuXFx0XFx0aWYgKCBpc2luZiggYXR0ZW51YXRpb25EaXN0YW5jZSApICkge1xcblxcdFxcdFxcdHJldHVybiB2ZWMzKCAxLjAgKTtcXG5cXHRcXHR9IGVsc2Uge1xcblxcdFxcdFxcdHZlYzMgYXR0ZW51YXRpb25Db2VmZmljaWVudCA9IC1sb2coIGF0dGVudWF0aW9uQ29sb3IgKSAvIGF0dGVudWF0aW9uRGlzdGFuY2U7XFxuXFx0XFx0XFx0dmVjMyB0cmFuc21pdHRhbmNlID0gZXhwKCAtIGF0dGVudWF0aW9uQ29lZmZpY2llbnQgKiB0cmFuc21pc3Npb25EaXN0YW5jZSApO1xcdFxcdFxcdHJldHVybiB0cmFuc21pdHRhbmNlO1xcblxcdFxcdH1cXG5cXHR9XFxuXFx0dmVjNCBnZXRJQkxWb2x1bWVSZWZyYWN0aW9uKCBjb25zdCBpbiB2ZWMzIG4sIGNvbnN0IGluIHZlYzMgdiwgY29uc3QgaW4gZmxvYXQgcm91Z2huZXNzLCBjb25zdCBpbiB2ZWMzIGRpZmZ1c2VDb2xvcixcXG5cXHRcXHRjb25zdCBpbiB2ZWMzIHNwZWN1bGFyQ29sb3IsIGNvbnN0IGluIGZsb2F0IHNwZWN1bGFyRjkwLCBjb25zdCBpbiB2ZWMzIHBvc2l0aW9uLCBjb25zdCBpbiBtYXQ0IG1vZGVsTWF0cml4LFxcblxcdFxcdGNvbnN0IGluIG1hdDQgdmlld01hdHJpeCwgY29uc3QgaW4gbWF0NCBwcm9qTWF0cml4LCBjb25zdCBpbiBmbG9hdCBkaXNwZXJzaW9uLCBjb25zdCBpbiBmbG9hdCBpb3IsIGNvbnN0IGluIGZsb2F0IHRoaWNrbmVzcyxcXG5cXHRcXHRjb25zdCBpbiB2ZWMzIGF0dGVudWF0aW9uQ29sb3IsIGNvbnN0IGluIGZsb2F0IGF0dGVudWF0aW9uRGlzdGFuY2UgKSB7XFxuXFx0XFx0dmVjNCB0cmFuc21pdHRlZExpZ2h0O1xcblxcdFxcdHZlYzMgdHJhbnNtaXR0YW5jZTtcXG5cXHRcXHQjaWZkZWYgVVNFX0RJU1BFUlNJT05cXG5cXHRcXHRcXHRmbG9hdCBoYWxmU3ByZWFkID0gKCBpb3IgLSAxLjAgKSAqIDAuMDI1ICogZGlzcGVyc2lvbjtcXG5cXHRcXHRcXHR2ZWMzIGlvcnMgPSB2ZWMzKCBpb3IgLSBoYWxmU3ByZWFkLCBpb3IsIGlvciArIGhhbGZTcHJlYWQgKTtcXG5cXHRcXHRcXHRmb3IgKCBpbnQgaSA9IDA7IGkgPCAzOyBpICsrICkge1xcblxcdFxcdFxcdFxcdHZlYzMgdHJhbnNtaXNzaW9uUmF5ID0gZ2V0Vm9sdW1lVHJhbnNtaXNzaW9uUmF5KCBuLCB2LCB0aGlja25lc3MsIGlvcnNbIGkgXSwgbW9kZWxNYXRyaXggKTtcXG5cXHRcXHRcXHRcXHR2ZWMzIHJlZnJhY3RlZFJheUV4aXQgPSBwb3NpdGlvbiArIHRyYW5zbWlzc2lvblJheTtcXG5cXHRcXHRcXG5cXHRcXHRcXHRcXHR2ZWM0IG5kY1BvcyA9IHByb2pNYXRyaXggKiB2aWV3TWF0cml4ICogdmVjNCggcmVmcmFjdGVkUmF5RXhpdCwgMS4wICk7XFxuXFx0XFx0XFx0XFx0dmVjMiByZWZyYWN0aW9uQ29vcmRzID0gbmRjUG9zLnh5IC8gbmRjUG9zLnc7XFxuXFx0XFx0XFx0XFx0cmVmcmFjdGlvbkNvb3JkcyArPSAxLjA7XFxuXFx0XFx0XFx0XFx0cmVmcmFjdGlvbkNvb3JkcyAvPSAyLjA7XFxuXFx0XFx0XFxuXFx0XFx0XFx0XFx0dmVjNCB0cmFuc21pc3Npb25TYW1wbGUgPSBnZXRUcmFuc21pc3Npb25TYW1wbGUoIHJlZnJhY3Rpb25Db29yZHMsIHJvdWdobmVzcywgaW9yc1sgaSBdICk7XFxuXFx0XFx0XFx0XFx0dHJhbnNtaXR0ZWRMaWdodFsgaSBdID0gdHJhbnNtaXNzaW9uU2FtcGxlWyBpIF07XFxuXFx0XFx0XFx0XFx0dHJhbnNtaXR0ZWRMaWdodC5hICs9IHRyYW5zbWlzc2lvblNhbXBsZS5hO1xcblxcdFxcdFxcdFxcdHRyYW5zbWl0dGFuY2VbIGkgXSA9IGRpZmZ1c2VDb2xvclsgaSBdICogdm9sdW1lQXR0ZW51YXRpb24oIGxlbmd0aCggdHJhbnNtaXNzaW9uUmF5ICksIGF0dGVudWF0aW9uQ29sb3IsIGF0dGVudWF0aW9uRGlzdGFuY2UgKVsgaSBdO1xcblxcdFxcdFxcdH1cXG5cXHRcXHRcXHR0cmFuc21pdHRlZExpZ2h0LmEgLz0gMy4wO1xcblxcdFxcdFxcblxcdFxcdCNlbHNlXFxuXFx0XFx0XFxuXFx0XFx0XFx0dmVjMyB0cmFuc21pc3Npb25SYXkgPSBnZXRWb2x1bWVUcmFuc21pc3Npb25SYXkoIG4sIHYsIHRoaWNrbmVzcywgaW9yLCBtb2RlbE1hdHJpeCApO1xcblxcdFxcdFxcdHZlYzMgcmVmcmFjdGVkUmF5RXhpdCA9IHBvc2l0aW9uICsgdHJhbnNtaXNzaW9uUmF5O1xcblxcdFxcdFxcdHZlYzQgbmRjUG9zID0gcHJvak1hdHJpeCAqIHZpZXdNYXRyaXggKiB2ZWM0KCByZWZyYWN0ZWRSYXlFeGl0LCAxLjAgKTtcXG5cXHRcXHRcXHR2ZWMyIHJlZnJhY3Rpb25Db29yZHMgPSBuZGNQb3MueHkgLyBuZGNQb3MudztcXG5cXHRcXHRcXHRyZWZyYWN0aW9uQ29vcmRzICs9IDEuMDtcXG5cXHRcXHRcXHRyZWZyYWN0aW9uQ29vcmRzIC89IDIuMDtcXG5cXHRcXHRcXHR0cmFuc21pdHRlZExpZ2h0ID0gZ2V0VHJhbnNtaXNzaW9uU2FtcGxlKCByZWZyYWN0aW9uQ29vcmRzLCByb3VnaG5lc3MsIGlvciApO1xcblxcdFxcdFxcdHRyYW5zbWl0dGFuY2UgPSBkaWZmdXNlQ29sb3IgKiB2b2x1bWVBdHRlbnVhdGlvbiggbGVuZ3RoKCB0cmFuc21pc3Npb25SYXkgKSwgYXR0ZW51YXRpb25Db2xvciwgYXR0ZW51YXRpb25EaXN0YW5jZSApO1xcblxcdFxcdFxcblxcdFxcdCNlbmRpZlxcblxcdFxcdHZlYzMgYXR0ZW51YXRlZENvbG9yID0gdHJhbnNtaXR0YW5jZSAqIHRyYW5zbWl0dGVkTGlnaHQucmdiO1xcblxcdFxcdHZlYzMgRiA9IEVudmlyb25tZW50QlJERiggbiwgdiwgc3BlY3VsYXJDb2xvciwgc3BlY3VsYXJGOTAsIHJvdWdobmVzcyApO1xcblxcdFxcdGZsb2F0IHRyYW5zbWl0dGFuY2VGYWN0b3IgPSAoIHRyYW5zbWl0dGFuY2UuciArIHRyYW5zbWl0dGFuY2UuZyArIHRyYW5zbWl0dGFuY2UuYiApIC8gMy4wO1xcblxcdFxcdHJldHVybiB2ZWM0KCAoIDEuMCAtIEYgKSAqIGF0dGVudWF0ZWRDb2xvciwgMS4wIC0gKCAxLjAgLSB0cmFuc21pdHRlZExpZ2h0LmEgKSAqIHRyYW5zbWl0dGFuY2VGYWN0b3IgKTtcXG5cXHR9XFxuI2VuZGlmXCI7XG5cbnZhciB1dl9wYXJzX2ZyYWdtZW50ID0gXCIjaWYgZGVmaW5lZCggVVNFX1VWICkgfHwgZGVmaW5lZCggVVNFX0FOSVNPVFJPUFkgKVxcblxcdHZhcnlpbmcgdmVjMiB2VXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9NQVBcXG5cXHR2YXJ5aW5nIHZlYzIgdk1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQUxQSEFNQVBcXG5cXHR2YXJ5aW5nIHZlYzIgdkFscGhhTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9MSUdIVE1BUFxcblxcdHZhcnlpbmcgdmVjMiB2TGlnaHRNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0FPTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZBb01hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQlVNUE1BUFxcblxcdHZhcnlpbmcgdmVjMiB2QnVtcE1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTk9STUFMTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZOb3JtYWxNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0VNSVNTSVZFTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZFbWlzc2l2ZU1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTUVUQUxORVNTTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZNZXRhbG5lc3NNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1JPVUdITkVTU01BUFxcblxcdHZhcnlpbmcgdmVjMiB2Um91Z2huZXNzTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9BTklTT1RST1BZTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZBbmlzb3Ryb3B5TWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRNQVBcXG5cXHR2YXJ5aW5nIHZlYzIgdkNsZWFyY29hdE1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUFxcblxcdHZhcnlpbmcgdmVjMiB2Q2xlYXJjb2F0Tm9ybWFsTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRfUk9VR0hORVNTTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXRSb3VnaG5lc3NNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZJcmlkZXNjZW5jZU1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZJcmlkZXNjZW5jZVRoaWNrbmVzc01hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfU0hFRU5fQ09MT1JNQVBcXG5cXHR2YXJ5aW5nIHZlYzIgdlNoZWVuQ29sb3JNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NIRUVOX1JPVUdITkVTU01BUFxcblxcdHZhcnlpbmcgdmVjMiB2U2hlZW5Sb3VnaG5lc3NNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NQRUNVTEFSTUFQXFxuXFx0dmFyeWluZyB2ZWMyIHZTcGVjdWxhck1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfU1BFQ1VMQVJfQ09MT1JNQVBcXG5cXHR2YXJ5aW5nIHZlYzIgdlNwZWN1bGFyQ29sb3JNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NQRUNVTEFSX0lOVEVOU0lUWU1BUFxcblxcdHZhcnlpbmcgdmVjMiB2U3BlY3VsYXJJbnRlbnNpdHlNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1RSQU5TTUlTU0lPTk1BUFxcblxcdHVuaWZvcm0gbWF0MyB0cmFuc21pc3Npb25NYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZUcmFuc21pc3Npb25NYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1RISUNLTkVTU01BUFxcblxcdHVuaWZvcm0gbWF0MyB0aGlja25lc3NNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZUaGlja25lc3NNYXBVdjtcXG4jZW5kaWZcIjtcblxudmFyIHV2X3BhcnNfdmVydGV4ID0gXCIjaWYgZGVmaW5lZCggVVNFX1VWICkgfHwgZGVmaW5lZCggVVNFX0FOSVNPVFJPUFkgKVxcblxcdHZhcnlpbmcgdmVjMiB2VXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9NQVBcXG5cXHR1bmlmb3JtIG1hdDMgbWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2TWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9BTFBIQU1BUFxcblxcdHVuaWZvcm0gbWF0MyBhbHBoYU1hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdkFscGhhTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9MSUdIVE1BUFxcblxcdHVuaWZvcm0gbWF0MyBsaWdodE1hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdkxpZ2h0TWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9BT01BUFxcblxcdHVuaWZvcm0gbWF0MyBhb01hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdkFvTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9CVU1QTUFQXFxuXFx0dW5pZm9ybSBtYXQzIGJ1bXBNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZCdW1wTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9OT1JNQUxNQVBcXG5cXHR1bmlmb3JtIG1hdDMgbm9ybWFsTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2Tm9ybWFsTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9ESVNQTEFDRU1FTlRNQVBcXG5cXHR1bmlmb3JtIG1hdDMgZGlzcGxhY2VtZW50TWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2RGlzcGxhY2VtZW50TWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9FTUlTU0lWRU1BUFxcblxcdHVuaWZvcm0gbWF0MyBlbWlzc2l2ZU1hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdkVtaXNzaXZlTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9NRVRBTE5FU1NNQVBcXG5cXHR1bmlmb3JtIG1hdDMgbWV0YWxuZXNzTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2TWV0YWxuZXNzTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9ST1VHSE5FU1NNQVBcXG5cXHR1bmlmb3JtIG1hdDMgcm91Z2huZXNzTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2Um91Z2huZXNzTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9BTklTT1RST1BZTUFQXFxuXFx0dW5pZm9ybSBtYXQzIGFuaXNvdHJvcHlNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZBbmlzb3Ryb3B5TWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRNQVBcXG5cXHR1bmlmb3JtIG1hdDMgY2xlYXJjb2F0TWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2Q2xlYXJjb2F0TWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRfTk9STUFMTUFQXFxuXFx0dW5pZm9ybSBtYXQzIGNsZWFyY29hdE5vcm1hbE1hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdkNsZWFyY29hdE5vcm1hbE1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUFxcblxcdHVuaWZvcm0gbWF0MyBjbGVhcmNvYXRSb3VnaG5lc3NNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZDbGVhcmNvYXRSb3VnaG5lc3NNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NIRUVOX0NPTE9STUFQXFxuXFx0dW5pZm9ybSBtYXQzIHNoZWVuQ29sb3JNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZTaGVlbkNvbG9yTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TSEVFTl9ST1VHSE5FU1NNQVBcXG5cXHR1bmlmb3JtIG1hdDMgc2hlZW5Sb3VnaG5lc3NNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZTaGVlblJvdWdobmVzc01hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VNQVBcXG5cXHR1bmlmb3JtIG1hdDMgaXJpZGVzY2VuY2VNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZJcmlkZXNjZW5jZU1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXFxuXFx0dW5pZm9ybSBtYXQzIGlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2SXJpZGVzY2VuY2VUaGlja25lc3NNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NQRUNVTEFSTUFQXFxuXFx0dW5pZm9ybSBtYXQzIHNwZWN1bGFyTWFwVHJhbnNmb3JtO1xcblxcdHZhcnlpbmcgdmVjMiB2U3BlY3VsYXJNYXBVdjtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NQRUNVTEFSX0NPTE9STUFQXFxuXFx0dW5pZm9ybSBtYXQzIHNwZWN1bGFyQ29sb3JNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZTcGVjdWxhckNvbG9yTWFwVXY7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TUEVDVUxBUl9JTlRFTlNJVFlNQVBcXG5cXHR1bmlmb3JtIG1hdDMgc3BlY3VsYXJJbnRlbnNpdHlNYXBUcmFuc2Zvcm07XFxuXFx0dmFyeWluZyB2ZWMyIHZTcGVjdWxhckludGVuc2l0eU1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OTUFQXFxuXFx0dW5pZm9ybSBtYXQzIHRyYW5zbWlzc2lvbk1hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdlRyYW5zbWlzc2lvbk1hcFV2O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfVEhJQ0tORVNTTUFQXFxuXFx0dW5pZm9ybSBtYXQzIHRoaWNrbmVzc01hcFRyYW5zZm9ybTtcXG5cXHR2YXJ5aW5nIHZlYzIgdlRoaWNrbmVzc01hcFV2O1xcbiNlbmRpZlwiO1xuXG52YXIgdXZfdmVydGV4ID0gXCIjaWYgZGVmaW5lZCggVVNFX1VWICkgfHwgZGVmaW5lZCggVVNFX0FOSVNPVFJPUFkgKVxcblxcdHZVdiA9IHZlYzMoIHV2LCAxICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9NQVBcXG5cXHR2TWFwVXYgPSAoIG1hcFRyYW5zZm9ybSAqIHZlYzMoIE1BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9BTFBIQU1BUFxcblxcdHZBbHBoYU1hcFV2ID0gKCBhbHBoYU1hcFRyYW5zZm9ybSAqIHZlYzMoIEFMUEhBTUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0xJR0hUTUFQXFxuXFx0dkxpZ2h0TWFwVXYgPSAoIGxpZ2h0TWFwVHJhbnNmb3JtICogdmVjMyggTElHSFRNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQU9NQVBcXG5cXHR2QW9NYXBVdiA9ICggYW9NYXBUcmFuc2Zvcm0gKiB2ZWMzKCBBT01BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9CVU1QTUFQXFxuXFx0dkJ1bXBNYXBVdiA9ICggYnVtcE1hcFRyYW5zZm9ybSAqIHZlYzMoIEJVTVBNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfTk9STUFMTUFQXFxuXFx0dk5vcm1hbE1hcFV2ID0gKCBub3JtYWxNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBOT1JNQUxNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfRElTUExBQ0VNRU5UTUFQXFxuXFx0dkRpc3BsYWNlbWVudE1hcFV2ID0gKCBkaXNwbGFjZW1lbnRNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBESVNQTEFDRU1FTlRNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfRU1JU1NJVkVNQVBcXG5cXHR2RW1pc3NpdmVNYXBVdiA9ICggZW1pc3NpdmVNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBFTUlTU0lWRU1BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9NRVRBTE5FU1NNQVBcXG5cXHR2TWV0YWxuZXNzTWFwVXYgPSAoIG1ldGFsbmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIE1FVEFMTkVTU01BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9ST1VHSE5FU1NNQVBcXG5cXHR2Um91Z2huZXNzTWFwVXYgPSAoIHJvdWdobmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIFJPVUdITkVTU01BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9BTklTT1RST1BZTUFQXFxuXFx0dkFuaXNvdHJvcHlNYXBVdiA9ICggYW5pc290cm9weU1hcFRyYW5zZm9ybSAqIHZlYzMoIEFOSVNPVFJPUFlNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUTUFQXFxuXFx0dkNsZWFyY29hdE1hcFV2ID0gKCBjbGVhcmNvYXRNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBDTEVBUkNPQVRNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUFxcblxcdHZDbGVhcmNvYXROb3JtYWxNYXBVdiA9ICggY2xlYXJjb2F0Tm9ybWFsTWFwVHJhbnNmb3JtICogdmVjMyggQ0xFQVJDT0FUX05PUk1BTE1BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRfUk9VR0hORVNTTUFQXFxuXFx0dkNsZWFyY29hdFJvdWdobmVzc01hcFV2ID0gKCBjbGVhcmNvYXRSb3VnaG5lc3NNYXBUcmFuc2Zvcm0gKiB2ZWMzKCBDTEVBUkNPQVRfUk9VR0hORVNTTUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0lSSURFU0NFTkNFTUFQXFxuXFx0dklyaWRlc2NlbmNlTWFwVXYgPSAoIGlyaWRlc2NlbmNlTWFwVHJhbnNmb3JtICogdmVjMyggSVJJREVTQ0VOQ0VNQVBfVVYsIDEgKSApLnh5O1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQXFxuXFx0dklyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVXYgPSAoIGlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVHJhbnNmb3JtICogdmVjMyggSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NIRUVOX0NPTE9STUFQXFxuXFx0dlNoZWVuQ29sb3JNYXBVdiA9ICggc2hlZW5Db2xvck1hcFRyYW5zZm9ybSAqIHZlYzMoIFNIRUVOX0NPTE9STUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NIRUVOX1JPVUdITkVTU01BUFxcblxcdHZTaGVlblJvdWdobmVzc01hcFV2ID0gKCBzaGVlblJvdWdobmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIFNIRUVOX1JPVUdITkVTU01BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9TUEVDVUxBUk1BUFxcblxcdHZTcGVjdWxhck1hcFV2ID0gKCBzcGVjdWxhck1hcFRyYW5zZm9ybSAqIHZlYzMoIFNQRUNVTEFSTUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NQRUNVTEFSX0NPTE9STUFQXFxuXFx0dlNwZWN1bGFyQ29sb3JNYXBVdiA9ICggc3BlY3VsYXJDb2xvck1hcFRyYW5zZm9ybSAqIHZlYzMoIFNQRUNVTEFSX0NPTE9STUFQX1VWLCAxICkgKS54eTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NQRUNVTEFSX0lOVEVOU0lUWU1BUFxcblxcdHZTcGVjdWxhckludGVuc2l0eU1hcFV2ID0gKCBzcGVjdWxhckludGVuc2l0eU1hcFRyYW5zZm9ybSAqIHZlYzMoIFNQRUNVTEFSX0lOVEVOU0lUWU1BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9UUkFOU01JU1NJT05NQVBcXG5cXHR2VHJhbnNtaXNzaW9uTWFwVXYgPSAoIHRyYW5zbWlzc2lvbk1hcFRyYW5zZm9ybSAqIHZlYzMoIFRSQU5TTUlTU0lPTk1BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9USElDS05FU1NNQVBcXG5cXHR2VGhpY2tuZXNzTWFwVXYgPSAoIHRoaWNrbmVzc01hcFRyYW5zZm9ybSAqIHZlYzMoIFRISUNLTkVTU01BUF9VViwgMSApICkueHk7XFxuI2VuZGlmXCI7XG5cbnZhciB3b3JsZHBvc192ZXJ0ZXggPSBcIiNpZiBkZWZpbmVkKCBVU0VfRU5WTUFQICkgfHwgZGVmaW5lZCggRElTVEFOQ0UgKSB8fCBkZWZpbmVkICggVVNFX1NIQURPV01BUCApIHx8IGRlZmluZWQgKCBVU0VfVFJBTlNNSVNTSU9OICkgfHwgTlVNX1NQT1RfTElHSFRfQ09PUkRTID4gMFxcblxcdHZlYzQgd29ybGRQb3NpdGlvbiA9IHZlYzQoIHRyYW5zZm9ybWVkLCAxLjAgKTtcXG5cXHQjaWZkZWYgVVNFX0JBVENISU5HXFxuXFx0XFx0d29ybGRQb3NpdGlvbiA9IGJhdGNoaW5nTWF0cml4ICogd29ybGRQb3NpdGlvbjtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX0lOU1RBTkNJTkdcXG5cXHRcXHR3b3JsZFBvc2l0aW9uID0gaW5zdGFuY2VNYXRyaXggKiB3b3JsZFBvc2l0aW9uO1xcblxcdCNlbmRpZlxcblxcdHdvcmxkUG9zaXRpb24gPSBtb2RlbE1hdHJpeCAqIHdvcmxkUG9zaXRpb247XFxuI2VuZGlmXCI7XG5cbmNvbnN0IHZlcnRleCRoID0gXCJ2YXJ5aW5nIHZlYzIgdlV2O1xcbnVuaWZvcm0gbWF0MyB1dlRyYW5zZm9ybTtcXG52b2lkIG1haW4oKSB7XFxuXFx0dlV2ID0gKCB1dlRyYW5zZm9ybSAqIHZlYzMoIHV2LCAxICkgKS54eTtcXG5cXHRnbF9Qb3NpdGlvbiA9IHZlYzQoIHBvc2l0aW9uLnh5LCAxLjAsIDEuMCApO1xcbn1cIjtcblxuY29uc3QgZnJhZ21lbnQkaCA9IFwidW5pZm9ybSBzYW1wbGVyMkQgdDJEO1xcbnVuaWZvcm0gZmxvYXQgYmFja2dyb3VuZEludGVuc2l0eTtcXG52YXJ5aW5nIHZlYzIgdlV2O1xcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IHRleENvbG9yID0gdGV4dHVyZTJEKCB0MkQsIHZVdiApO1xcblxcdCNpZmRlZiBERUNPREVfVklERU9fVEVYVFVSRVxcblxcdFxcdHRleENvbG9yID0gdmVjNCggbWl4KCBwb3coIHRleENvbG9yLnJnYiAqIDAuOTQ3ODY3Mjk4NiArIHZlYzMoIDAuMDUyMTMyNzAxNCApLCB2ZWMzKCAyLjQgKSApLCB0ZXhDb2xvci5yZ2IgKiAwLjA3NzM5OTM4MDgsIHZlYzMoIGxlc3NUaGFuRXF1YWwoIHRleENvbG9yLnJnYiwgdmVjMyggMC4wNDA0NSApICkgKSApLCB0ZXhDb2xvci53ICk7XFxuXFx0I2VuZGlmXFxuXFx0dGV4Q29sb3IucmdiICo9IGJhY2tncm91bmRJbnRlbnNpdHk7XFxuXFx0Z2xfRnJhZ0NvbG9yID0gdGV4Q29sb3I7XFxuXFx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JGcgPSBcInZhcnlpbmcgdmVjMyB2V29ybGREaXJlY3Rpb247XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG52b2lkIG1haW4oKSB7XFxuXFx0dldvcmxkRGlyZWN0aW9uID0gdHJhbnNmb3JtRGlyZWN0aW9uKCBwb3NpdGlvbiwgbW9kZWxNYXRyaXggKTtcXG5cXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxcblxcdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cXG5cXHRnbF9Qb3NpdGlvbi56ID0gZ2xfUG9zaXRpb24udztcXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JGcgPSBcIiNpZmRlZiBFTlZNQVBfVFlQRV9DVUJFXFxuXFx0dW5pZm9ybSBzYW1wbGVyQ3ViZSBlbnZNYXA7XFxuI2VsaWYgZGVmaW5lZCggRU5WTUFQX1RZUEVfQ1VCRV9VViApXFxuXFx0dW5pZm9ybSBzYW1wbGVyMkQgZW52TWFwO1xcbiNlbmRpZlxcbnVuaWZvcm0gZmxvYXQgZmxpcEVudk1hcDtcXG51bmlmb3JtIGZsb2F0IGJhY2tncm91bmRCbHVycmluZXNzO1xcbnVuaWZvcm0gZmxvYXQgYmFja2dyb3VuZEludGVuc2l0eTtcXG51bmlmb3JtIG1hdDMgYmFja2dyb3VuZFJvdGF0aW9uO1xcbnZhcnlpbmcgdmVjMyB2V29ybGREaXJlY3Rpb247XFxuI2luY2x1ZGUgPGN1YmVfdXZfcmVmbGVjdGlvbl9mcmFnbWVudD5cXG52b2lkIG1haW4oKSB7XFxuXFx0I2lmZGVmIEVOVk1BUF9UWVBFX0NVQkVcXG5cXHRcXHR2ZWM0IHRleENvbG9yID0gdGV4dHVyZUN1YmUoIGVudk1hcCwgYmFja2dyb3VuZFJvdGF0aW9uICogdmVjMyggZmxpcEVudk1hcCAqIHZXb3JsZERpcmVjdGlvbi54LCB2V29ybGREaXJlY3Rpb24ueXogKSApO1xcblxcdCNlbGlmIGRlZmluZWQoIEVOVk1BUF9UWVBFX0NVQkVfVVYgKVxcblxcdFxcdHZlYzQgdGV4Q29sb3IgPSB0ZXh0dXJlQ3ViZVVWKCBlbnZNYXAsIGJhY2tncm91bmRSb3RhdGlvbiAqIHZXb3JsZERpcmVjdGlvbiwgYmFja2dyb3VuZEJsdXJyaW5lc3MgKTtcXG5cXHQjZWxzZVxcblxcdFxcdHZlYzQgdGV4Q29sb3IgPSB2ZWM0KCAwLjAsIDAuMCwgMC4wLCAxLjAgKTtcXG5cXHQjZW5kaWZcXG5cXHR0ZXhDb2xvci5yZ2IgKj0gYmFja2dyb3VuZEludGVuc2l0eTtcXG5cXHRnbF9GcmFnQ29sb3IgPSB0ZXhDb2xvcjtcXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxufVwiO1xuXG5jb25zdCB2ZXJ0ZXgkZiA9IFwidmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2V29ybGREaXJlY3Rpb24gPSB0cmFuc2Zvcm1EaXJlY3Rpb24oIHBvc2l0aW9uLCBtb2RlbE1hdHJpeCApO1xcblxcdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxcblxcdGdsX1Bvc2l0aW9uLnogPSBnbF9Qb3NpdGlvbi53O1xcbn1cIjtcblxuY29uc3QgZnJhZ21lbnQkZiA9IFwidW5pZm9ybSBzYW1wbGVyQ3ViZSB0Q3ViZTtcXG51bmlmb3JtIGZsb2F0IHRGbGlwO1xcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcXG52YXJ5aW5nIHZlYzMgdldvcmxkRGlyZWN0aW9uO1xcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IHRleENvbG9yID0gdGV4dHVyZUN1YmUoIHRDdWJlLCB2ZWMzKCB0RmxpcCAqIHZXb3JsZERpcmVjdGlvbi54LCB2V29ybGREaXJlY3Rpb24ueXogKSApO1xcblxcdGdsX0ZyYWdDb2xvciA9IHRleENvbG9yO1xcblxcdGdsX0ZyYWdDb2xvci5hICo9IG9wYWNpdHk7XFxuXFx0I2luY2x1ZGUgPHRvbmVtYXBwaW5nX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxjb2xvcnNwYWNlX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JGUgPSBcIiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XFxudmFyeWluZyB2ZWMyIHZIaWdoUHJlY2lzaW9uWlc7XFxudm9pZCBtYWluKCkge1xcblxcdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJhdGNoaW5nX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaGluc3RhbmNlX3ZlcnRleD5cXG5cXHQjaWZkZWYgVVNFX0RJU1BMQUNFTUVOVE1BUFxcblxcdFxcdCNpbmNsdWRlIDxiZWdpbm5vcm1hbF92ZXJ0ZXg+XFxuXFx0XFx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cXG5cXHRcXHQjaW5jbHVkZSA8c2tpbm5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2VuZGlmXFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XFxuXFx0dkhpZ2hQcmVjaXNpb25aVyA9IGdsX1Bvc2l0aW9uLnp3O1xcbn1cIjtcblxuY29uc3QgZnJhZ21lbnQkZSA9IFwiI2lmIERFUFRIX1BBQ0tJTkcgPT0gMzIwMFxcblxcdHVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcXG4jZW5kaWZcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxwYWNraW5nPlxcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGFtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cXG52YXJ5aW5nIHZlYzIgdkhpZ2hQcmVjaXNpb25aVztcXG52b2lkIG1haW4oKSB7XFxuXFx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCAxLjAgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdCNpZiBERVBUSF9QQUNLSU5HID09IDMyMDBcXG5cXHRcXHRkaWZmdXNlQ29sb3IuYSA9IG9wYWNpdHk7XFxuXFx0I2VuZGlmXFxuXFx0I2luY2x1ZGUgPG1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGFtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhdGVzdF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGFoYXNoX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHRmbG9hdCBmcmFnQ29vcmRaID0gMC41ICogdkhpZ2hQcmVjaXNpb25aV1swXSAvIHZIaWdoUHJlY2lzaW9uWldbMV0gKyAwLjU7XFxuXFx0I2lmIERFUFRIX1BBQ0tJTkcgPT0gMzIwMFxcblxcdFxcdGdsX0ZyYWdDb2xvciA9IHZlYzQoIHZlYzMoIDEuMCAtIGZyYWdDb29yZFogKSwgb3BhY2l0eSApO1xcblxcdCNlbGlmIERFUFRIX1BBQ0tJTkcgPT0gMzIwMVxcblxcdFxcdGdsX0ZyYWdDb2xvciA9IHBhY2tEZXB0aFRvUkdCQSggZnJhZ0Nvb3JkWiApO1xcblxcdCNlbGlmIERFUFRIX1BBQ0tJTkcgPT0gMzIwMlxcblxcdFxcdGdsX0ZyYWdDb2xvciA9IHZlYzQoIHBhY2tEZXB0aFRvUkdCKCBmcmFnQ29vcmRaICksIDEuMCApO1xcblxcdCNlbGlmIERFUFRIX1BBQ0tJTkcgPT0gMzIwM1xcblxcdFxcdGdsX0ZyYWdDb2xvciA9IHZlYzQoIHBhY2tEZXB0aFRvUkcoIGZyYWdDb29yZFogKSwgMC4wLCAxLjAgKTtcXG5cXHQjZW5kaWZcXG59XCI7XG5cbmNvbnN0IHZlcnRleCRkID0gXCIjZGVmaW5lIERJU1RBTkNFXFxudmFyeWluZyB2ZWMzIHZXb3JsZFBvc2l0aW9uO1xcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cXG52b2lkIG1haW4oKSB7XFxuXFx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoaW5zdGFuY2VfdmVydGV4PlxcblxcdCNpZmRlZiBVU0VfRElTUExBQ0VNRU5UTUFQXFxuXFx0XFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHRcXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxcblxcdFxcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjZW5kaWZcXG5cXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHdvcmxkcG9zX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cXG5cXHR2V29ybGRQb3NpdGlvbiA9IHdvcmxkUG9zaXRpb24ueHl6O1xcbn1cIjtcblxuY29uc3QgZnJhZ21lbnQkZCA9IFwiI2RlZmluZSBESVNUQU5DRVxcbnVuaWZvcm0gdmVjMyByZWZlcmVuY2VQb3NpdGlvbjtcXG51bmlmb3JtIGZsb2F0IG5lYXJEaXN0YW5jZTtcXG51bmlmb3JtIGZsb2F0IGZhckRpc3RhbmNlO1xcbnZhcnlpbmcgdmVjMyB2V29ybGRQb3NpdGlvbjtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxwYWNraW5nPlxcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGFtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cXG52b2lkIG1haW4gKCkge1xcblxcdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggMS4wICk7XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XFxuXFx0ZmxvYXQgZGlzdCA9IGxlbmd0aCggdldvcmxkUG9zaXRpb24gLSByZWZlcmVuY2VQb3NpdGlvbiApO1xcblxcdGRpc3QgPSAoIGRpc3QgLSBuZWFyRGlzdGFuY2UgKSAvICggZmFyRGlzdGFuY2UgLSBuZWFyRGlzdGFuY2UgKTtcXG5cXHRkaXN0ID0gc2F0dXJhdGUoIGRpc3QgKTtcXG5cXHRnbF9GcmFnQ29sb3IgPSBwYWNrRGVwdGhUb1JHQkEoIGRpc3QgKTtcXG59XCI7XG5cbmNvbnN0IHZlcnRleCRjID0gXCJ2YXJ5aW5nIHZlYzMgdldvcmxkRGlyZWN0aW9uO1xcbiNpbmNsdWRlIDxjb21tb24+XFxudm9pZCBtYWluKCkge1xcblxcdHZXb3JsZERpcmVjdGlvbiA9IHRyYW5zZm9ybURpcmVjdGlvbiggcG9zaXRpb24sIG1vZGVsTWF0cml4ICk7XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCRjID0gXCJ1bmlmb3JtIHNhbXBsZXIyRCB0RXF1aXJlY3Q7XFxudmFyeWluZyB2ZWMzIHZXb3JsZERpcmVjdGlvbjtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWMzIGRpcmVjdGlvbiA9IG5vcm1hbGl6ZSggdldvcmxkRGlyZWN0aW9uICk7XFxuXFx0dmVjMiBzYW1wbGVVViA9IGVxdWlyZWN0VXYoIGRpcmVjdGlvbiApO1xcblxcdGdsX0ZyYWdDb2xvciA9IHRleHR1cmUyRCggdEVxdWlyZWN0LCBzYW1wbGVVViApO1xcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG59XCI7XG5cbmNvbnN0IHZlcnRleCRiID0gXCJ1bmlmb3JtIGZsb2F0IHNjYWxlO1xcbmF0dHJpYnV0ZSBmbG9hdCBsaW5lRGlzdGFuY2U7XFxudmFyeWluZyBmbG9hdCB2TGluZURpc3RhbmNlO1xcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPHV2X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cXG52b2lkIG1haW4oKSB7XFxuXFx0dkxpbmVEaXN0YW5jZSA9IHNjYWxlICogbGluZURpc3RhbmNlO1xcblxcdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBodGFyZ2V0X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JGIgPSBcInVuaWZvcm0gdmVjMyBkaWZmdXNlO1xcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcXG51bmlmb3JtIGZsb2F0IGRhc2hTaXplO1xcbnVuaWZvcm0gZmxvYXQgdG90YWxTaXplO1xcbnZhcnlpbmcgZmxvYXQgdkxpbmVEaXN0YW5jZTtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDx1dl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdGlmICggbW9kKCB2TGluZURpc3RhbmNlLCB0b3RhbFNpemUgKSA+IGRhc2hTaXplICkge1xcblxcdFxcdGRpc2NhcmQ7XFxuXFx0fVxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHZlYzMoIDAuMCApO1xcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cXG5cXHRvdXRnb2luZ0xpZ2h0ID0gZGlmZnVzZUNvbG9yLnJnYjtcXG5cXHQjaW5jbHVkZSA8b3BhcXVlX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxwcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JGEgPSBcIiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XFxudm9pZCBtYWluKCkge1xcblxcdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XFxuXFx0I2lmIGRlZmluZWQgKCBVU0VfRU5WTUFQICkgfHwgZGVmaW5lZCAoIFVTRV9TS0lOTklORyApXFxuXFx0XFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHRcXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxcblxcdFxcdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XFxuXFx0XFx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxcblxcdFxcdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cXG5cXHQjZW5kaWZcXG5cXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8d29ybGRwb3NfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxlbnZtYXBfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxmb2dfdmVydGV4Plxcbn1cIjtcblxuY29uc3QgZnJhZ21lbnQkYSA9IFwidW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XFxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xcbiNpZm5kZWYgRkxBVF9TSEFERURcXG5cXHR2YXJ5aW5nIHZlYzMgdk5vcm1hbDtcXG4jZW5kaWZcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxkaXRoZXJpbmdfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bGlnaHRtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8ZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxlbnZtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHNwZWN1bGFybWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGFtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhdGVzdF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGFoYXNoX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxzcGVjdWxhcm1hcF9mcmFnbWVudD5cXG5cXHRSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCA9IFJlZmxlY3RlZExpZ2h0KCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSApO1xcblxcdCNpZmRlZiBVU0VfTElHSFRNQVBcXG5cXHRcXHR2ZWM0IGxpZ2h0TWFwVGV4ZWwgPSB0ZXh0dXJlMkQoIGxpZ2h0TWFwLCB2TGlnaHRNYXBVdiApO1xcblxcdFxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSArPSBsaWdodE1hcFRleGVsLnJnYiAqIGxpZ2h0TWFwSW50ZW5zaXR5ICogUkVDSVBST0NBTF9QSTtcXG5cXHQjZWxzZVxcblxcdFxcdHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0RGlmZnVzZSArPSB2ZWMzKCAxLjAgKTtcXG5cXHQjZW5kaWZcXG5cXHQjaW5jbHVkZSA8YW9tYXBfZnJhZ21lbnQ+XFxuXFx0cmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlICo9IGRpZmZ1c2VDb2xvci5yZ2I7XFxuXFx0dmVjMyBvdXRnb2luZ0xpZ2h0ID0gcmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlO1xcblxcdCNpbmNsdWRlIDxlbnZtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JDkgPSBcIiNkZWZpbmUgTEFNQkVSVFxcbnZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxlbnZtYXBfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XFxudm9pZCBtYWluKCkge1xcblxcdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cXG5cXHR2Vmlld1Bvc2l0aW9uID0gLSBtdlBvc2l0aW9uLnh5ejtcXG5cXHQjaW5jbHVkZSA8d29ybGRwb3NfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxlbnZtYXBfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxzaGFkb3dtYXBfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxmb2dfdmVydGV4Plxcbn1cIjtcblxuY29uc3QgZnJhZ21lbnQkOSA9IFwiI2RlZmluZSBMQU1CRVJUXFxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XFxudW5pZm9ybSB2ZWMzIGVtaXNzaXZlO1xcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxwYWNraW5nPlxcbiNpbmNsdWRlIDxkaXRoZXJpbmdfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YW9tYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bGlnaHRtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8ZW1pc3NpdmVtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8ZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxlbnZtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGJzZGZzPlxcbiNpbmNsdWRlIDxsaWdodHNfcGFyc19iZWdpbj5cXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxpZ2h0c19sYW1iZXJ0X3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHNoYWRvd21hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxidW1wbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxzcGVjdWxhcm1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cXG52b2lkIG1haW4oKSB7XFxuXFx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cXG5cXHRSZWZsZWN0ZWRMaWdodCByZWZsZWN0ZWRMaWdodCA9IFJlZmxlY3RlZExpZ2h0KCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSApO1xcblxcdHZlYzMgdG90YWxFbWlzc2l2ZVJhZGlhbmNlID0gZW1pc3NpdmU7XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPHNwZWN1bGFybWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfYmVnaW4+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9tYXBzPlxcblxcdCNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2xhbWJlcnRfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9iZWdpbj5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X21hcHM+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9lbmQ+XFxuXFx0I2luY2x1ZGUgPGFvbWFwX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKyByZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XFxuXFx0I2luY2x1ZGUgPGVudm1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8b3BhcXVlX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxwcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxkaXRoZXJpbmdfZnJhZ21lbnQ+XFxufVwiO1xuXG5jb25zdCB2ZXJ0ZXgkOCA9IFwiI2RlZmluZSBNQVRDQVBcXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxiYXRjaGluZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8dXZfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc192ZXJ0ZXg+XFxudm9pZCBtYWluKCkge1xcblxcdCNpbmNsdWRlIDx1dl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoY29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2luYmFzZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5ub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxkZWZhdWx0bm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmVnaW5fdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaHRhcmdldF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5uaW5nX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8cHJvamVjdF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cXG5cXHR2Vmlld1Bvc2l0aW9uID0gLSBtdlBvc2l0aW9uLnh5ejtcXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JDggPSBcIiNkZWZpbmUgTUFUQ0FQXFxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XFxudW5pZm9ybSBmbG9hdCBvcGFjaXR5O1xcbnVuaWZvcm0gc2FtcGxlcjJEIG1hdGNhcDtcXG52YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxkaXRoZXJpbmdfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxidW1wbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudD5cXG52b2lkIG1haW4oKSB7XFxuXFx0dmVjNCBkaWZmdXNlQ29sb3IgPSB2ZWM0KCBkaWZmdXNlLCBvcGFjaXR5ICk7XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X2JlZ2luPlxcblxcdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfbWFwcz5cXG5cXHR2ZWMzIHZpZXdEaXIgPSBub3JtYWxpemUoIHZWaWV3UG9zaXRpb24gKTtcXG5cXHR2ZWMzIHggPSBub3JtYWxpemUoIHZlYzMoIHZpZXdEaXIueiwgMC4wLCAtIHZpZXdEaXIueCApICk7XFxuXFx0dmVjMyB5ID0gY3Jvc3MoIHZpZXdEaXIsIHggKTtcXG5cXHR2ZWMyIHV2ID0gdmVjMiggZG90KCB4LCBub3JtYWwgKSwgZG90KCB5LCBub3JtYWwgKSApICogMC40OTUgKyAwLjU7XFxuXFx0I2lmZGVmIFVTRV9NQVRDQVBcXG5cXHRcXHR2ZWM0IG1hdGNhcENvbG9yID0gdGV4dHVyZTJEKCBtYXRjYXAsIHV2ICk7XFxuXFx0I2Vsc2VcXG5cXHRcXHR2ZWM0IG1hdGNhcENvbG9yID0gdmVjNCggdmVjMyggbWl4KCAwLjIsIDAuOCwgdXYueSApICksIDEuMCApO1xcblxcdCNlbmRpZlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IGRpZmZ1c2VDb2xvci5yZ2IgKiBtYXRjYXBDb2xvci5yZ2I7XFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JDcgPSBcIiNkZWZpbmUgTk9STUFMXFxuI2lmIGRlZmluZWQoIEZMQVRfU0hBREVEICkgfHwgZGVmaW5lZCggVVNFX0JVTVBNQVAgKSB8fCBkZWZpbmVkKCBVU0VfTk9STUFMTUFQX1RBTkdFTlRTUEFDRSApXFxuXFx0dmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XFxuI2VuZGlmXFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8YmF0Y2hpbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPHV2X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPHNraW5uaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxcbnZvaWQgbWFpbigpIHtcXG5cXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XFxuI2lmIGRlZmluZWQoIEZMQVRfU0hBREVEICkgfHwgZGVmaW5lZCggVVNFX0JVTVBNQVAgKSB8fCBkZWZpbmVkKCBVU0VfTk9STUFMTUFQX1RBTkdFTlRTUEFDRSApXFxuXFx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XFxuI2VuZGlmXFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCQ3ID0gXCIjZGVmaW5lIE5PUk1BTFxcbnVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcXG4jaWYgZGVmaW5lZCggRkxBVF9TSEFERUQgKSB8fCBkZWZpbmVkKCBVU0VfQlVNUE1BUCApIHx8IGRlZmluZWQoIFVTRV9OT1JNQUxNQVBfVEFOR0VOVFNQQUNFIClcXG5cXHR2YXJ5aW5nIHZlYzMgdlZpZXdQb3NpdGlvbjtcXG4jZW5kaWZcXG4jaW5jbHVkZSA8cGFja2luZz5cXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIDAuMCwgMC4wLCAwLjAsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X2JlZ2luPlxcblxcdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfbWFwcz5cXG5cXHRnbF9GcmFnQ29sb3IgPSB2ZWM0KCBwYWNrTm9ybWFsVG9SR0IoIG5vcm1hbCApLCBkaWZmdXNlQ29sb3IuYSApO1xcblxcdCNpZmRlZiBPUEFRVUVcXG5cXHRcXHRnbF9GcmFnQ29sb3IuYSA9IDEuMDtcXG5cXHQjZW5kaWZcXG59XCI7XG5cbmNvbnN0IHZlcnRleCQ2ID0gXCIjZGVmaW5lIFBIT05HXFxudmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8YmF0Y2hpbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPHV2X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGVudm1hcF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y29sb3JfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGZvZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPHNoYWRvd21hcF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleD5cXG52b2lkIG1haW4oKSB7XFxuXFx0I2luY2x1ZGUgPHV2X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiZWdpbm5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoaW5zdGFuY2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNraW5iYXNlX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbm5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGRlZmF1bHRub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxub3JtYWxfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiZWdpbl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBodGFyZ2V0X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbm5pbmdfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxkaXNwbGFjZW1lbnRtYXBfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxcblxcdHZWaWV3UG9zaXRpb24gPSAtIG12UG9zaXRpb24ueHl6O1xcblxcdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGVudm1hcF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHNoYWRvd21hcF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCQ2ID0gXCIjZGVmaW5lIFBIT05HXFxudW5pZm9ybSB2ZWMzIGRpZmZ1c2U7XFxudW5pZm9ybSB2ZWMzIGVtaXNzaXZlO1xcbnVuaWZvcm0gdmVjMyBzcGVjdWxhcjtcXG51bmlmb3JtIGZsb2F0IHNoaW5pbmVzcztcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8cGFja2luZz5cXG4jaW5jbHVkZSA8ZGl0aGVyaW5nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGFoYXNoX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFvbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGVtaXNzaXZlbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGVudm1hcF9jb21tb25fcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8ZW52bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxic2Rmcz5cXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XFxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxsaWdodHNfcGhvbmdfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHNwZWN1bGFybWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ID0gUmVmbGVjdGVkTGlnaHQoIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApICk7XFxuXFx0dmVjMyB0b3RhbEVtaXNzaXZlUmFkaWFuY2UgPSBlbWlzc2l2ZTtcXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8c3BlY3VsYXJtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9iZWdpbj5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X21hcHM+XFxuXFx0I2luY2x1ZGUgPGVtaXNzaXZlbWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxsaWdodHNfcGhvbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9iZWdpbj5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X21hcHM+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9lbmQ+XFxuXFx0I2luY2x1ZGUgPGFvbWFwX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKyByZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKyByZWZsZWN0ZWRMaWdodC5kaXJlY3RTcGVjdWxhciArIHJlZmxlY3RlZExpZ2h0LmluZGlyZWN0U3BlY3VsYXIgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XFxuXFx0I2luY2x1ZGUgPGVudm1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8b3BhcXVlX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxwcmVtdWx0aXBsaWVkX2FscGhhX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxkaXRoZXJpbmdfZnJhZ21lbnQ+XFxufVwiO1xuXG5jb25zdCB2ZXJ0ZXgkNSA9IFwiI2RlZmluZSBTVEFOREFSRFxcbnZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xcbiNpZmRlZiBVU0VfVFJBTlNNSVNTSU9OXFxuXFx0dmFyeWluZyB2ZWMzIHZXb3JsZFBvc2l0aW9uO1xcbiNlbmRpZlxcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxub3JtYWxfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxza2lubmluZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxcbnZvaWQgbWFpbigpIHtcXG5cXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxjb2xvcl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoaW5zdGFuY2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiZWdpbm5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XFxuXFx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XFxuXFx0I2luY2x1ZGUgPHdvcmxkcG9zX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2hhZG93bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cXG4jaWZkZWYgVVNFX1RSQU5TTUlTU0lPTlxcblxcdHZXb3JsZFBvc2l0aW9uID0gd29ybGRQb3NpdGlvbi54eXo7XFxuI2VuZGlmXFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCQ1ID0gXCIjZGVmaW5lIFNUQU5EQVJEXFxuI2lmZGVmIFBIWVNJQ0FMXFxuXFx0I2RlZmluZSBJT1JcXG5cXHQjZGVmaW5lIFVTRV9TUEVDVUxBUlxcbiNlbmRpZlxcbnVuaWZvcm0gdmVjMyBkaWZmdXNlO1xcbnVuaWZvcm0gdmVjMyBlbWlzc2l2ZTtcXG51bmlmb3JtIGZsb2F0IHJvdWdobmVzcztcXG51bmlmb3JtIGZsb2F0IG1ldGFsbmVzcztcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2lmZGVmIElPUlxcblxcdHVuaWZvcm0gZmxvYXQgaW9yO1xcbiNlbmRpZlxcbiNpZmRlZiBVU0VfU1BFQ1VMQVJcXG5cXHR1bmlmb3JtIGZsb2F0IHNwZWN1bGFySW50ZW5zaXR5O1xcblxcdHVuaWZvcm0gdmVjMyBzcGVjdWxhckNvbG9yO1xcblxcdCNpZmRlZiBVU0VfU1BFQ1VMQVJfQ09MT1JNQVBcXG5cXHRcXHR1bmlmb3JtIHNhbXBsZXIyRCBzcGVjdWxhckNvbG9yTWFwO1xcblxcdCNlbmRpZlxcblxcdCNpZmRlZiBVU0VfU1BFQ1VMQVJfSU5URU5TSVRZTUFQXFxuXFx0XFx0dW5pZm9ybSBzYW1wbGVyMkQgc3BlY3VsYXJJbnRlbnNpdHlNYXA7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9DTEVBUkNPQVRcXG5cXHR1bmlmb3JtIGZsb2F0IGNsZWFyY29hdDtcXG5cXHR1bmlmb3JtIGZsb2F0IGNsZWFyY29hdFJvdWdobmVzcztcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX0RJU1BFUlNJT05cXG5cXHR1bmlmb3JtIGZsb2F0IGRpc3BlcnNpb247XFxuI2VuZGlmXFxuI2lmZGVmIFVTRV9JUklERVNDRU5DRVxcblxcdHVuaWZvcm0gZmxvYXQgaXJpZGVzY2VuY2U7XFxuXFx0dW5pZm9ybSBmbG9hdCBpcmlkZXNjZW5jZUlPUjtcXG5cXHR1bmlmb3JtIGZsb2F0IGlyaWRlc2NlbmNlVGhpY2tuZXNzTWluaW11bTtcXG5cXHR1bmlmb3JtIGZsb2F0IGlyaWRlc2NlbmNlVGhpY2tuZXNzTWF4aW11bTtcXG4jZW5kaWZcXG4jaWZkZWYgVVNFX1NIRUVOXFxuXFx0dW5pZm9ybSB2ZWMzIHNoZWVuQ29sb3I7XFxuXFx0dW5pZm9ybSBmbG9hdCBzaGVlblJvdWdobmVzcztcXG5cXHQjaWZkZWYgVVNFX1NIRUVOX0NPTE9STUFQXFxuXFx0XFx0dW5pZm9ybSBzYW1wbGVyMkQgc2hlZW5Db2xvck1hcDtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX1NIRUVOX1JPVUdITkVTU01BUFxcblxcdFxcdHVuaWZvcm0gc2FtcGxlcjJEIHNoZWVuUm91Z2huZXNzTWFwO1xcblxcdCNlbmRpZlxcbiNlbmRpZlxcbiNpZmRlZiBVU0VfQU5JU09UUk9QWVxcblxcdHVuaWZvcm0gdmVjMiBhbmlzb3Ryb3B5VmVjdG9yO1xcblxcdCNpZmRlZiBVU0VfQU5JU09UUk9QWU1BUFxcblxcdFxcdHVuaWZvcm0gc2FtcGxlcjJEIGFuaXNvdHJvcHlNYXA7XFxuXFx0I2VuZGlmXFxuI2VuZGlmXFxudmFyeWluZyB2ZWMzIHZWaWV3UG9zaXRpb247XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8cGFja2luZz5cXG4jaW5jbHVkZSA8ZGl0aGVyaW5nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGFoYXNoX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFvbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGVtaXNzaXZlbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGlyaWRlc2NlbmNlX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGVudm1hcF9jb21tb25fcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8ZW52bWFwX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxsaWdodHNfcGFyc19iZWdpbj5cXG4jaW5jbHVkZSA8bm9ybWFsX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxpZ2h0c19waHlzaWNhbF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDx0cmFuc21pc3Npb25fcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGJ1bXBtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsZWFyY29hdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxpcmlkZXNjZW5jZV9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxyb3VnaG5lc3NtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWV0YWxuZXNzbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdFJlZmxlY3RlZExpZ2h0IHJlZmxlY3RlZExpZ2h0ID0gUmVmbGVjdGVkTGlnaHQoIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICksIHZlYzMoIDAuMCApICk7XFxuXFx0dmVjMyB0b3RhbEVtaXNzaXZlUmFkaWFuY2UgPSBlbWlzc2l2ZTtcXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhbWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYXRlc3RfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhaGFzaF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cm91Z2huZXNzbWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxtZXRhbG5lc3NtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9iZWdpbj5cXG5cXHQjaW5jbHVkZSA8bm9ybWFsX2ZyYWdtZW50X21hcHM+XFxuXFx0I2luY2x1ZGUgPGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfYmVnaW4+XFxuXFx0I2luY2x1ZGUgPGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfbWFwcz5cXG5cXHQjaW5jbHVkZSA8ZW1pc3NpdmVtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19waHlzaWNhbF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X2JlZ2luPlxcblxcdCNpbmNsdWRlIDxsaWdodHNfZnJhZ21lbnRfbWFwcz5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X2VuZD5cXG5cXHQjaW5jbHVkZSA8YW9tYXBfZnJhZ21lbnQ+XFxuXFx0dmVjMyB0b3RhbERpZmZ1c2UgPSByZWZsZWN0ZWRMaWdodC5kaXJlY3REaWZmdXNlICsgcmVmbGVjdGVkTGlnaHQuaW5kaXJlY3REaWZmdXNlO1xcblxcdHZlYzMgdG90YWxTcGVjdWxhciA9IHJlZmxlY3RlZExpZ2h0LmRpcmVjdFNwZWN1bGFyICsgcmVmbGVjdGVkTGlnaHQuaW5kaXJlY3RTcGVjdWxhcjtcXG5cXHQjaW5jbHVkZSA8dHJhbnNtaXNzaW9uX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHRvdGFsRGlmZnVzZSArIHRvdGFsU3BlY3VsYXIgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XFxuXFx0I2lmZGVmIFVTRV9TSEVFTlxcblxcdFxcdGZsb2F0IHNoZWVuRW5lcmd5Q29tcCA9IDEuMCAtIDAuMTU3ICogbWF4MyggbWF0ZXJpYWwuc2hlZW5Db2xvciApO1xcblxcdFxcdG91dGdvaW5nTGlnaHQgPSBvdXRnb2luZ0xpZ2h0ICogc2hlZW5FbmVyZ3lDb21wICsgc2hlZW5TcGVjdWxhckRpcmVjdCArIHNoZWVuU3BlY3VsYXJJbmRpcmVjdDtcXG5cXHQjZW5kaWZcXG5cXHQjaWZkZWYgVVNFX0NMRUFSQ09BVFxcblxcdFxcdGZsb2F0IGRvdE5WY2MgPSBzYXR1cmF0ZSggZG90KCBnZW9tZXRyeUNsZWFyY29hdE5vcm1hbCwgZ2VvbWV0cnlWaWV3RGlyICkgKTtcXG5cXHRcXHR2ZWMzIEZjYyA9IEZfU2NobGljayggbWF0ZXJpYWwuY2xlYXJjb2F0RjAsIG1hdGVyaWFsLmNsZWFyY29hdEY5MCwgZG90TlZjYyApO1xcblxcdFxcdG91dGdvaW5nTGlnaHQgPSBvdXRnb2luZ0xpZ2h0ICogKCAxLjAgLSBtYXRlcmlhbC5jbGVhcmNvYXQgKiBGY2MgKSArICggY2xlYXJjb2F0U3BlY3VsYXJEaXJlY3QgKyBjbGVhcmNvYXRTcGVjdWxhckluZGlyZWN0ICkgKiBtYXRlcmlhbC5jbGVhcmNvYXQ7XFxuXFx0I2VuZGlmXFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JDQgPSBcIiNkZWZpbmUgVE9PTlxcbnZhcnlpbmcgdmVjMyB2Vmlld1Bvc2l0aW9uO1xcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGJhdGNoaW5nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8ZGlzcGxhY2VtZW50bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxjb2xvcl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxub3JtYWxfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxza2lubmluZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxcbnZvaWQgbWFpbigpIHtcXG5cXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxjb2xvcl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBoaW5zdGFuY2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaGNvbG9yX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8YmF0Y2hpbmdfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxiZWdpbm5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGRpc3BsYWNlbWVudG1hcF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XFxuXFx0dlZpZXdQb3NpdGlvbiA9IC0gbXZQb3NpdGlvbi54eXo7XFxuXFx0I2luY2x1ZGUgPHdvcmxkcG9zX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2hhZG93bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JDQgPSBcIiNkZWZpbmUgVE9PTlxcbnVuaWZvcm0gdmVjMyBkaWZmdXNlO1xcbnVuaWZvcm0gdmVjMyBlbWlzc2l2ZTtcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8cGFja2luZz5cXG4jaW5jbHVkZSA8ZGl0aGVyaW5nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHV2X3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYW1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYXRlc3RfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YWxwaGFoYXNoX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFvbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxpZ2h0bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGVtaXNzaXZlbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGdyYWRpZW50bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGZvZ19wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxic2Rmcz5cXG4jaW5jbHVkZSA8bGlnaHRzX3BhcnNfYmVnaW4+XFxuI2luY2x1ZGUgPG5vcm1hbF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxsaWdodHNfdG9vbl9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8YnVtcG1hcF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxub3JtYWxtYXBfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQ+XFxudm9pZCBtYWluKCkge1xcblxcdHZlYzQgZGlmZnVzZUNvbG9yID0gdmVjNCggZGlmZnVzZSwgb3BhY2l0eSApO1xcblxcdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfZnJhZ21lbnQ+XFxuXFx0UmVmbGVjdGVkTGlnaHQgcmVmbGVjdGVkTGlnaHQgPSBSZWZsZWN0ZWRMaWdodCggdmVjMyggMC4wICksIHZlYzMoIDAuMCApLCB2ZWMzKCAwLjAgKSwgdmVjMyggMC4wICkgKTtcXG5cXHR2ZWMzIHRvdGFsRW1pc3NpdmVSYWRpYW5jZSA9IGVtaXNzaXZlO1xcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGFtYXBfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGFscGhhdGVzdF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGFoYXNoX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxub3JtYWxfZnJhZ21lbnRfYmVnaW4+XFxuXFx0I2luY2x1ZGUgPG5vcm1hbF9mcmFnbWVudF9tYXBzPlxcblxcdCNpbmNsdWRlIDxlbWlzc2l2ZW1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX3Rvb25fZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9iZWdpbj5cXG5cXHQjaW5jbHVkZSA8bGlnaHRzX2ZyYWdtZW50X21hcHM+XFxuXFx0I2luY2x1ZGUgPGxpZ2h0c19mcmFnbWVudF9lbmQ+XFxuXFx0I2luY2x1ZGUgPGFvbWFwX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHJlZmxlY3RlZExpZ2h0LmRpcmVjdERpZmZ1c2UgKyByZWZsZWN0ZWRMaWdodC5pbmRpcmVjdERpZmZ1c2UgKyB0b3RhbEVtaXNzaXZlUmFkaWFuY2U7XFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8ZGl0aGVyaW5nX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JDMgPSBcInVuaWZvcm0gZmxvYXQgc2l6ZTtcXG51bmlmb3JtIGZsb2F0IHNjYWxlO1xcbiNpbmNsdWRlIDxjb21tb24+XFxuI2luY2x1ZGUgPGNvbG9yX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxmb2dfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxcbiNpZmRlZiBVU0VfUE9JTlRTX1VWXFxuXFx0dmFyeWluZyB2ZWMyIHZVdjtcXG5cXHR1bmlmb3JtIG1hdDMgdXZUcmFuc2Zvcm07XFxuI2VuZGlmXFxudm9pZCBtYWluKCkge1xcblxcdCNpZmRlZiBVU0VfUE9JTlRTX1VWXFxuXFx0XFx0dlV2ID0gKCB1dlRyYW5zZm9ybSAqIHZlYzMoIHV2LCAxICkgKS54eTtcXG5cXHQjZW5kaWZcXG5cXHQjaW5jbHVkZSA8Y29sb3JfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxtb3JwaGluc3RhbmNlX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhjb2xvcl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxwcm9qZWN0X3ZlcnRleD5cXG5cXHRnbF9Qb2ludFNpemUgPSBzaXplO1xcblxcdCNpZmRlZiBVU0VfU0laRUFUVEVOVUFUSU9OXFxuXFx0XFx0Ym9vbCBpc1BlcnNwZWN0aXZlID0gaXNQZXJzcGVjdGl2ZU1hdHJpeCggcHJvamVjdGlvbk1hdHJpeCApO1xcblxcdFxcdGlmICggaXNQZXJzcGVjdGl2ZSApIGdsX1BvaW50U2l6ZSAqPSAoIHNjYWxlIC8gLSBtdlBvc2l0aW9uLnogKTtcXG5cXHQjZW5kaWZcXG5cXHQjaW5jbHVkZSA8bG9nZGVwdGhidWZfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxjbGlwcGluZ19wbGFuZXNfdmVydGV4PlxcblxcdCNpbmNsdWRlIDx3b3JsZHBvc192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCQzID0gXCJ1bmlmb3JtIHZlYzMgZGlmZnVzZTtcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8Y29sb3JfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHZlYzMoIDAuMCApO1xcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX3BhcnRpY2xlX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxjb2xvcl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XFxuXFx0b3V0Z29pbmdMaWdodCA9IGRpZmZ1c2VDb2xvci5yZ2I7XFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudD5cXG59XCI7XG5cbmNvbnN0IHZlcnRleCQyID0gXCIjaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDxiYXRjaGluZ19wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxtb3JwaHRhcmdldF9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8c2tpbm5pbmdfcGFyc192ZXJ0ZXg+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxzaGFkb3dtYXBfcGFyc192ZXJ0ZXg+XFxudm9pZCBtYWluKCkge1xcblxcdCNpbmNsdWRlIDxiYXRjaGluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGhpbnN0YW5jZV92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPG1vcnBobm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2tpbmJhc2VfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubm9ybWFsX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGJlZ2luX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8bW9ycGh0YXJnZXRfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxza2lubmluZ192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHByb2plY3RfdmVydGV4PlxcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPHdvcmxkcG9zX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8c2hhZG93bWFwX3ZlcnRleD5cXG5cXHQjaW5jbHVkZSA8Zm9nX3ZlcnRleD5cXG59XCI7XG5cbmNvbnN0IGZyYWdtZW50JDIgPSBcInVuaWZvcm0gdmVjMyBjb2xvcjtcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8cGFja2luZz5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGJzZGZzPlxcbiNpbmNsdWRlIDxsaWdodHNfcGFyc19iZWdpbj5cXG4jaW5jbHVkZSA8bG9nZGVwdGhidWZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8c2hhZG93bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPHNoYWRvd21hc2tfcGFyc19mcmFnbWVudD5cXG52b2lkIG1haW4oKSB7XFxuXFx0I2luY2x1ZGUgPGxvZ2RlcHRoYnVmX2ZyYWdtZW50PlxcblxcdGdsX0ZyYWdDb2xvciA9IHZlYzQoIGNvbG9yLCBvcGFjaXR5ICogKCAxLjAgLSBnZXRTaGFkb3dNYXNrKCkgKSApO1xcblxcdCNpbmNsdWRlIDx0b25lbWFwcGluZ19mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8Zm9nX2ZyYWdtZW50Plxcbn1cIjtcblxuY29uc3QgdmVydGV4JDEgPSBcInVuaWZvcm0gZmxvYXQgcm90YXRpb247XFxudW5pZm9ybSB2ZWMyIGNlbnRlcjtcXG4jaW5jbHVkZSA8Y29tbW9uPlxcbiNpbmNsdWRlIDx1dl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfdmVydGV4PlxcbiNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleD5cXG4jaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4PlxcbnZvaWQgbWFpbigpIHtcXG5cXHQjaW5jbHVkZSA8dXZfdmVydGV4PlxcblxcdHZlYzQgbXZQb3NpdGlvbiA9IG1vZGVsVmlld01hdHJpeCAqIHZlYzQoIDAuMCwgMC4wLCAwLjAsIDEuMCApO1xcblxcdHZlYzIgc2NhbGU7XFxuXFx0c2NhbGUueCA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDAgXS54LCBtb2RlbE1hdHJpeFsgMCBdLnksIG1vZGVsTWF0cml4WyAwIF0ueiApICk7XFxuXFx0c2NhbGUueSA9IGxlbmd0aCggdmVjMyggbW9kZWxNYXRyaXhbIDEgXS54LCBtb2RlbE1hdHJpeFsgMSBdLnksIG1vZGVsTWF0cml4WyAxIF0ueiApICk7XFxuXFx0I2lmbmRlZiBVU0VfU0laRUFUVEVOVUFUSU9OXFxuXFx0XFx0Ym9vbCBpc1BlcnNwZWN0aXZlID0gaXNQZXJzcGVjdGl2ZU1hdHJpeCggcHJvamVjdGlvbk1hdHJpeCApO1xcblxcdFxcdGlmICggaXNQZXJzcGVjdGl2ZSApIHNjYWxlICo9IC0gbXZQb3NpdGlvbi56O1xcblxcdCNlbmRpZlxcblxcdHZlYzIgYWxpZ25lZFBvc2l0aW9uID0gKCBwb3NpdGlvbi54eSAtICggY2VudGVyIC0gdmVjMiggMC41ICkgKSApICogc2NhbGU7XFxuXFx0dmVjMiByb3RhdGVkUG9zaXRpb247XFxuXFx0cm90YXRlZFBvc2l0aW9uLnggPSBjb3MoIHJvdGF0aW9uICkgKiBhbGlnbmVkUG9zaXRpb24ueCAtIHNpbiggcm90YXRpb24gKSAqIGFsaWduZWRQb3NpdGlvbi55O1xcblxcdHJvdGF0ZWRQb3NpdGlvbi55ID0gc2luKCByb3RhdGlvbiApICogYWxpZ25lZFBvc2l0aW9uLnggKyBjb3MoIHJvdGF0aW9uICkgKiBhbGlnbmVkUG9zaXRpb24ueTtcXG5cXHRtdlBvc2l0aW9uLnh5ICs9IHJvdGF0ZWRQb3NpdGlvbjtcXG5cXHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtdlBvc2l0aW9uO1xcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl92ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc192ZXJ0ZXg+XFxuXFx0I2luY2x1ZGUgPGZvZ192ZXJ0ZXg+XFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCQxID0gXCJ1bmlmb3JtIHZlYzMgZGlmZnVzZTtcXG51bmlmb3JtIGZsb2F0IG9wYWNpdHk7XFxuI2luY2x1ZGUgPGNvbW1vbj5cXG4jaW5jbHVkZSA8dXZfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8bWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGFscGhhdGVzdF9wYXJzX2ZyYWdtZW50PlxcbiNpbmNsdWRlIDxhbHBoYWhhc2hfcGFyc19mcmFnbWVudD5cXG4jaW5jbHVkZSA8Zm9nX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ+XFxuI2luY2x1ZGUgPGNsaXBwaW5nX3BsYW5lc19wYXJzX2ZyYWdtZW50PlxcbnZvaWQgbWFpbigpIHtcXG5cXHR2ZWM0IGRpZmZ1c2VDb2xvciA9IHZlYzQoIGRpZmZ1c2UsIG9wYWNpdHkgKTtcXG5cXHQjaW5jbHVkZSA8Y2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50PlxcblxcdHZlYzMgb3V0Z29pbmdMaWdodCA9IHZlYzMoIDAuMCApO1xcblxcdCNpbmNsdWRlIDxsb2dkZXB0aGJ1Zl9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8bWFwX2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYW1hcF9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8YWxwaGF0ZXN0X2ZyYWdtZW50PlxcblxcdCNpbmNsdWRlIDxhbHBoYWhhc2hfZnJhZ21lbnQ+XFxuXFx0b3V0Z29pbmdMaWdodCA9IGRpZmZ1c2VDb2xvci5yZ2I7XFxuXFx0I2luY2x1ZGUgPG9wYXF1ZV9mcmFnbWVudD5cXG5cXHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGNvbG9yc3BhY2VfZnJhZ21lbnQ+XFxuXFx0I2luY2x1ZGUgPGZvZ19mcmFnbWVudD5cXG59XCI7XG5cbmNvbnN0IFNoYWRlckNodW5rID0ge1xuXHRhbHBoYWhhc2hfZnJhZ21lbnQ6IGFscGhhaGFzaF9mcmFnbWVudCxcblx0YWxwaGFoYXNoX3BhcnNfZnJhZ21lbnQ6IGFscGhhaGFzaF9wYXJzX2ZyYWdtZW50LFxuXHRhbHBoYW1hcF9mcmFnbWVudDogYWxwaGFtYXBfZnJhZ21lbnQsXG5cdGFscGhhbWFwX3BhcnNfZnJhZ21lbnQ6IGFscGhhbWFwX3BhcnNfZnJhZ21lbnQsXG5cdGFscGhhdGVzdF9mcmFnbWVudDogYWxwaGF0ZXN0X2ZyYWdtZW50LFxuXHRhbHBoYXRlc3RfcGFyc19mcmFnbWVudDogYWxwaGF0ZXN0X3BhcnNfZnJhZ21lbnQsXG5cdGFvbWFwX2ZyYWdtZW50OiBhb21hcF9mcmFnbWVudCxcblx0YW9tYXBfcGFyc19mcmFnbWVudDogYW9tYXBfcGFyc19mcmFnbWVudCxcblx0YmF0Y2hpbmdfcGFyc192ZXJ0ZXg6IGJhdGNoaW5nX3BhcnNfdmVydGV4LFxuXHRiYXRjaGluZ192ZXJ0ZXg6IGJhdGNoaW5nX3ZlcnRleCxcblx0YmVnaW5fdmVydGV4OiBiZWdpbl92ZXJ0ZXgsXG5cdGJlZ2lubm9ybWFsX3ZlcnRleDogYmVnaW5ub3JtYWxfdmVydGV4LFxuXHRic2RmczogYnNkZnMsXG5cdGlyaWRlc2NlbmNlX2ZyYWdtZW50OiBpcmlkZXNjZW5jZV9mcmFnbWVudCxcblx0YnVtcG1hcF9wYXJzX2ZyYWdtZW50OiBidW1wbWFwX3BhcnNfZnJhZ21lbnQsXG5cdGNsaXBwaW5nX3BsYW5lc19mcmFnbWVudDogY2xpcHBpbmdfcGxhbmVzX2ZyYWdtZW50LFxuXHRjbGlwcGluZ19wbGFuZXNfcGFyc19mcmFnbWVudDogY2xpcHBpbmdfcGxhbmVzX3BhcnNfZnJhZ21lbnQsXG5cdGNsaXBwaW5nX3BsYW5lc19wYXJzX3ZlcnRleDogY2xpcHBpbmdfcGxhbmVzX3BhcnNfdmVydGV4LFxuXHRjbGlwcGluZ19wbGFuZXNfdmVydGV4OiBjbGlwcGluZ19wbGFuZXNfdmVydGV4LFxuXHRjb2xvcl9mcmFnbWVudDogY29sb3JfZnJhZ21lbnQsXG5cdGNvbG9yX3BhcnNfZnJhZ21lbnQ6IGNvbG9yX3BhcnNfZnJhZ21lbnQsXG5cdGNvbG9yX3BhcnNfdmVydGV4OiBjb2xvcl9wYXJzX3ZlcnRleCxcblx0Y29sb3JfdmVydGV4OiBjb2xvcl92ZXJ0ZXgsXG5cdGNvbW1vbjogY29tbW9uLFxuXHRjdWJlX3V2X3JlZmxlY3Rpb25fZnJhZ21lbnQ6IGN1YmVfdXZfcmVmbGVjdGlvbl9mcmFnbWVudCxcblx0ZGVmYXVsdG5vcm1hbF92ZXJ0ZXg6IGRlZmF1bHRub3JtYWxfdmVydGV4LFxuXHRkaXNwbGFjZW1lbnRtYXBfcGFyc192ZXJ0ZXg6IGRpc3BsYWNlbWVudG1hcF9wYXJzX3ZlcnRleCxcblx0ZGlzcGxhY2VtZW50bWFwX3ZlcnRleDogZGlzcGxhY2VtZW50bWFwX3ZlcnRleCxcblx0ZW1pc3NpdmVtYXBfZnJhZ21lbnQ6IGVtaXNzaXZlbWFwX2ZyYWdtZW50LFxuXHRlbWlzc2l2ZW1hcF9wYXJzX2ZyYWdtZW50OiBlbWlzc2l2ZW1hcF9wYXJzX2ZyYWdtZW50LFxuXHRjb2xvcnNwYWNlX2ZyYWdtZW50OiBjb2xvcnNwYWNlX2ZyYWdtZW50LFxuXHRjb2xvcnNwYWNlX3BhcnNfZnJhZ21lbnQ6IGNvbG9yc3BhY2VfcGFyc19mcmFnbWVudCxcblx0ZW52bWFwX2ZyYWdtZW50OiBlbnZtYXBfZnJhZ21lbnQsXG5cdGVudm1hcF9jb21tb25fcGFyc19mcmFnbWVudDogZW52bWFwX2NvbW1vbl9wYXJzX2ZyYWdtZW50LFxuXHRlbnZtYXBfcGFyc19mcmFnbWVudDogZW52bWFwX3BhcnNfZnJhZ21lbnQsXG5cdGVudm1hcF9wYXJzX3ZlcnRleDogZW52bWFwX3BhcnNfdmVydGV4LFxuXHRlbnZtYXBfcGh5c2ljYWxfcGFyc19mcmFnbWVudDogZW52bWFwX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQsXG5cdGVudm1hcF92ZXJ0ZXg6IGVudm1hcF92ZXJ0ZXgsXG5cdGZvZ192ZXJ0ZXg6IGZvZ192ZXJ0ZXgsXG5cdGZvZ19wYXJzX3ZlcnRleDogZm9nX3BhcnNfdmVydGV4LFxuXHRmb2dfZnJhZ21lbnQ6IGZvZ19mcmFnbWVudCxcblx0Zm9nX3BhcnNfZnJhZ21lbnQ6IGZvZ19wYXJzX2ZyYWdtZW50LFxuXHRncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50OiBncmFkaWVudG1hcF9wYXJzX2ZyYWdtZW50LFxuXHRsaWdodG1hcF9wYXJzX2ZyYWdtZW50OiBsaWdodG1hcF9wYXJzX2ZyYWdtZW50LFxuXHRsaWdodHNfbGFtYmVydF9mcmFnbWVudDogbGlnaHRzX2xhbWJlcnRfZnJhZ21lbnQsXG5cdGxpZ2h0c19sYW1iZXJ0X3BhcnNfZnJhZ21lbnQ6IGxpZ2h0c19sYW1iZXJ0X3BhcnNfZnJhZ21lbnQsXG5cdGxpZ2h0c19wYXJzX2JlZ2luOiBsaWdodHNfcGFyc19iZWdpbixcblx0bGlnaHRzX3Rvb25fZnJhZ21lbnQ6IGxpZ2h0c190b29uX2ZyYWdtZW50LFxuXHRsaWdodHNfdG9vbl9wYXJzX2ZyYWdtZW50OiBsaWdodHNfdG9vbl9wYXJzX2ZyYWdtZW50LFxuXHRsaWdodHNfcGhvbmdfZnJhZ21lbnQ6IGxpZ2h0c19waG9uZ19mcmFnbWVudCxcblx0bGlnaHRzX3Bob25nX3BhcnNfZnJhZ21lbnQ6IGxpZ2h0c19waG9uZ19wYXJzX2ZyYWdtZW50LFxuXHRsaWdodHNfcGh5c2ljYWxfZnJhZ21lbnQ6IGxpZ2h0c19waHlzaWNhbF9mcmFnbWVudCxcblx0bGlnaHRzX3BoeXNpY2FsX3BhcnNfZnJhZ21lbnQ6IGxpZ2h0c19waHlzaWNhbF9wYXJzX2ZyYWdtZW50LFxuXHRsaWdodHNfZnJhZ21lbnRfYmVnaW46IGxpZ2h0c19mcmFnbWVudF9iZWdpbixcblx0bGlnaHRzX2ZyYWdtZW50X21hcHM6IGxpZ2h0c19mcmFnbWVudF9tYXBzLFxuXHRsaWdodHNfZnJhZ21lbnRfZW5kOiBsaWdodHNfZnJhZ21lbnRfZW5kLFxuXHRsb2dkZXB0aGJ1Zl9mcmFnbWVudDogbG9nZGVwdGhidWZfZnJhZ21lbnQsXG5cdGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQ6IGxvZ2RlcHRoYnVmX3BhcnNfZnJhZ21lbnQsXG5cdGxvZ2RlcHRoYnVmX3BhcnNfdmVydGV4OiBsb2dkZXB0aGJ1Zl9wYXJzX3ZlcnRleCxcblx0bG9nZGVwdGhidWZfdmVydGV4OiBsb2dkZXB0aGJ1Zl92ZXJ0ZXgsXG5cdG1hcF9mcmFnbWVudDogbWFwX2ZyYWdtZW50LFxuXHRtYXBfcGFyc19mcmFnbWVudDogbWFwX3BhcnNfZnJhZ21lbnQsXG5cdG1hcF9wYXJ0aWNsZV9mcmFnbWVudDogbWFwX3BhcnRpY2xlX2ZyYWdtZW50LFxuXHRtYXBfcGFydGljbGVfcGFyc19mcmFnbWVudDogbWFwX3BhcnRpY2xlX3BhcnNfZnJhZ21lbnQsXG5cdG1ldGFsbmVzc21hcF9mcmFnbWVudDogbWV0YWxuZXNzbWFwX2ZyYWdtZW50LFxuXHRtZXRhbG5lc3NtYXBfcGFyc19mcmFnbWVudDogbWV0YWxuZXNzbWFwX3BhcnNfZnJhZ21lbnQsXG5cdG1vcnBoaW5zdGFuY2VfdmVydGV4OiBtb3JwaGluc3RhbmNlX3ZlcnRleCxcblx0bW9ycGhjb2xvcl92ZXJ0ZXg6IG1vcnBoY29sb3JfdmVydGV4LFxuXHRtb3JwaG5vcm1hbF92ZXJ0ZXg6IG1vcnBobm9ybWFsX3ZlcnRleCxcblx0bW9ycGh0YXJnZXRfcGFyc192ZXJ0ZXg6IG1vcnBodGFyZ2V0X3BhcnNfdmVydGV4LFxuXHRtb3JwaHRhcmdldF92ZXJ0ZXg6IG1vcnBodGFyZ2V0X3ZlcnRleCxcblx0bm9ybWFsX2ZyYWdtZW50X2JlZ2luOiBub3JtYWxfZnJhZ21lbnRfYmVnaW4sXG5cdG5vcm1hbF9mcmFnbWVudF9tYXBzOiBub3JtYWxfZnJhZ21lbnRfbWFwcyxcblx0bm9ybWFsX3BhcnNfZnJhZ21lbnQ6IG5vcm1hbF9wYXJzX2ZyYWdtZW50LFxuXHRub3JtYWxfcGFyc192ZXJ0ZXg6IG5vcm1hbF9wYXJzX3ZlcnRleCxcblx0bm9ybWFsX3ZlcnRleDogbm9ybWFsX3ZlcnRleCxcblx0bm9ybWFsbWFwX3BhcnNfZnJhZ21lbnQ6IG5vcm1hbG1hcF9wYXJzX2ZyYWdtZW50LFxuXHRjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X2JlZ2luOiBjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X2JlZ2luLFxuXHRjbGVhcmNvYXRfbm9ybWFsX2ZyYWdtZW50X21hcHM6IGNsZWFyY29hdF9ub3JtYWxfZnJhZ21lbnRfbWFwcyxcblx0Y2xlYXJjb2F0X3BhcnNfZnJhZ21lbnQ6IGNsZWFyY29hdF9wYXJzX2ZyYWdtZW50LFxuXHRpcmlkZXNjZW5jZV9wYXJzX2ZyYWdtZW50OiBpcmlkZXNjZW5jZV9wYXJzX2ZyYWdtZW50LFxuXHRvcGFxdWVfZnJhZ21lbnQ6IG9wYXF1ZV9mcmFnbWVudCxcblx0cGFja2luZzogcGFja2luZyxcblx0cHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudDogcHJlbXVsdGlwbGllZF9hbHBoYV9mcmFnbWVudCxcblx0cHJvamVjdF92ZXJ0ZXg6IHByb2plY3RfdmVydGV4LFxuXHRkaXRoZXJpbmdfZnJhZ21lbnQ6IGRpdGhlcmluZ19mcmFnbWVudCxcblx0ZGl0aGVyaW5nX3BhcnNfZnJhZ21lbnQ6IGRpdGhlcmluZ19wYXJzX2ZyYWdtZW50LFxuXHRyb3VnaG5lc3NtYXBfZnJhZ21lbnQ6IHJvdWdobmVzc21hcF9mcmFnbWVudCxcblx0cm91Z2huZXNzbWFwX3BhcnNfZnJhZ21lbnQ6IHJvdWdobmVzc21hcF9wYXJzX2ZyYWdtZW50LFxuXHRzaGFkb3dtYXBfcGFyc19mcmFnbWVudDogc2hhZG93bWFwX3BhcnNfZnJhZ21lbnQsXG5cdHNoYWRvd21hcF9wYXJzX3ZlcnRleDogc2hhZG93bWFwX3BhcnNfdmVydGV4LFxuXHRzaGFkb3dtYXBfdmVydGV4OiBzaGFkb3dtYXBfdmVydGV4LFxuXHRzaGFkb3dtYXNrX3BhcnNfZnJhZ21lbnQ6IHNoYWRvd21hc2tfcGFyc19mcmFnbWVudCxcblx0c2tpbmJhc2VfdmVydGV4OiBza2luYmFzZV92ZXJ0ZXgsXG5cdHNraW5uaW5nX3BhcnNfdmVydGV4OiBza2lubmluZ19wYXJzX3ZlcnRleCxcblx0c2tpbm5pbmdfdmVydGV4OiBza2lubmluZ192ZXJ0ZXgsXG5cdHNraW5ub3JtYWxfdmVydGV4OiBza2lubm9ybWFsX3ZlcnRleCxcblx0c3BlY3VsYXJtYXBfZnJhZ21lbnQ6IHNwZWN1bGFybWFwX2ZyYWdtZW50LFxuXHRzcGVjdWxhcm1hcF9wYXJzX2ZyYWdtZW50OiBzcGVjdWxhcm1hcF9wYXJzX2ZyYWdtZW50LFxuXHR0b25lbWFwcGluZ19mcmFnbWVudDogdG9uZW1hcHBpbmdfZnJhZ21lbnQsXG5cdHRvbmVtYXBwaW5nX3BhcnNfZnJhZ21lbnQ6IHRvbmVtYXBwaW5nX3BhcnNfZnJhZ21lbnQsXG5cdHRyYW5zbWlzc2lvbl9mcmFnbWVudDogdHJhbnNtaXNzaW9uX2ZyYWdtZW50LFxuXHR0cmFuc21pc3Npb25fcGFyc19mcmFnbWVudDogdHJhbnNtaXNzaW9uX3BhcnNfZnJhZ21lbnQsXG5cdHV2X3BhcnNfZnJhZ21lbnQ6IHV2X3BhcnNfZnJhZ21lbnQsXG5cdHV2X3BhcnNfdmVydGV4OiB1dl9wYXJzX3ZlcnRleCxcblx0dXZfdmVydGV4OiB1dl92ZXJ0ZXgsXG5cdHdvcmxkcG9zX3ZlcnRleDogd29ybGRwb3NfdmVydGV4LFxuXG5cdGJhY2tncm91bmRfdmVydDogdmVydGV4JGgsXG5cdGJhY2tncm91bmRfZnJhZzogZnJhZ21lbnQkaCxcblx0YmFja2dyb3VuZEN1YmVfdmVydDogdmVydGV4JGcsXG5cdGJhY2tncm91bmRDdWJlX2ZyYWc6IGZyYWdtZW50JGcsXG5cdGN1YmVfdmVydDogdmVydGV4JGYsXG5cdGN1YmVfZnJhZzogZnJhZ21lbnQkZixcblx0ZGVwdGhfdmVydDogdmVydGV4JGUsXG5cdGRlcHRoX2ZyYWc6IGZyYWdtZW50JGUsXG5cdGRpc3RhbmNlUkdCQV92ZXJ0OiB2ZXJ0ZXgkZCxcblx0ZGlzdGFuY2VSR0JBX2ZyYWc6IGZyYWdtZW50JGQsXG5cdGVxdWlyZWN0X3ZlcnQ6IHZlcnRleCRjLFxuXHRlcXVpcmVjdF9mcmFnOiBmcmFnbWVudCRjLFxuXHRsaW5lZGFzaGVkX3ZlcnQ6IHZlcnRleCRiLFxuXHRsaW5lZGFzaGVkX2ZyYWc6IGZyYWdtZW50JGIsXG5cdG1lc2hiYXNpY192ZXJ0OiB2ZXJ0ZXgkYSxcblx0bWVzaGJhc2ljX2ZyYWc6IGZyYWdtZW50JGEsXG5cdG1lc2hsYW1iZXJ0X3ZlcnQ6IHZlcnRleCQ5LFxuXHRtZXNobGFtYmVydF9mcmFnOiBmcmFnbWVudCQ5LFxuXHRtZXNobWF0Y2FwX3ZlcnQ6IHZlcnRleCQ4LFxuXHRtZXNobWF0Y2FwX2ZyYWc6IGZyYWdtZW50JDgsXG5cdG1lc2hub3JtYWxfdmVydDogdmVydGV4JDcsXG5cdG1lc2hub3JtYWxfZnJhZzogZnJhZ21lbnQkNyxcblx0bWVzaHBob25nX3ZlcnQ6IHZlcnRleCQ2LFxuXHRtZXNocGhvbmdfZnJhZzogZnJhZ21lbnQkNixcblx0bWVzaHBoeXNpY2FsX3ZlcnQ6IHZlcnRleCQ1LFxuXHRtZXNocGh5c2ljYWxfZnJhZzogZnJhZ21lbnQkNSxcblx0bWVzaHRvb25fdmVydDogdmVydGV4JDQsXG5cdG1lc2h0b29uX2ZyYWc6IGZyYWdtZW50JDQsXG5cdHBvaW50c192ZXJ0OiB2ZXJ0ZXgkMyxcblx0cG9pbnRzX2ZyYWc6IGZyYWdtZW50JDMsXG5cdHNoYWRvd192ZXJ0OiB2ZXJ0ZXgkMixcblx0c2hhZG93X2ZyYWc6IGZyYWdtZW50JDIsXG5cdHNwcml0ZV92ZXJ0OiB2ZXJ0ZXgkMSxcblx0c3ByaXRlX2ZyYWc6IGZyYWdtZW50JDFcbn07XG5cbi8qKlxuICogVW5pZm9ybXMgbGlicmFyeSBmb3Igc2hhcmVkIHdlYmdsIHNoYWRlcnNcbiAqL1xuXG5jb25zdCBVbmlmb3Jtc0xpYiA9IHtcblxuXHRjb21tb246IHtcblxuXHRcdGRpZmZ1c2U6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweGZmZmZmZiApIH0sXG5cdFx0b3BhY2l0eTogeyB2YWx1ZTogMS4wIH0sXG5cblx0XHRtYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRtYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXG5cdFx0YWxwaGFNYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRhbHBoYU1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cblx0XHRhbHBoYVRlc3Q6IHsgdmFsdWU6IDAgfVxuXG5cdH0sXG5cblx0c3BlY3VsYXJtYXA6IHtcblxuXHRcdHNwZWN1bGFyTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0c3BlY3VsYXJNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XG5cblx0fSxcblxuXHRlbnZtYXA6IHtcblxuXHRcdGVudk1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGVudk1hcFJvdGF0aW9uOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRmbGlwRW52TWFwOiB7IHZhbHVlOiAtIDEgfSxcblx0XHRyZWZsZWN0aXZpdHk6IHsgdmFsdWU6IDEuMCB9LCAvLyBiYXNpYywgbGFtYmVydCwgcGhvbmdcblx0XHRpb3I6IHsgdmFsdWU6IDEuNSB9LCAvLyBwaHlzaWNhbFxuXHRcdHJlZnJhY3Rpb25SYXRpbzogeyB2YWx1ZTogMC45OCB9LCAvLyBiYXNpYywgbGFtYmVydCwgcGhvbmdcblxuXHR9LFxuXG5cdGFvbWFwOiB7XG5cblx0XHRhb01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGFvTWFwSW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0sXG5cdFx0YW9NYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XG5cblx0fSxcblxuXHRsaWdodG1hcDoge1xuXG5cdFx0bGlnaHRNYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRsaWdodE1hcEludGVuc2l0eTogeyB2YWx1ZTogMSB9LFxuXHRcdGxpZ2h0TWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfVxuXG5cdH0sXG5cblx0YnVtcG1hcDoge1xuXG5cdFx0YnVtcE1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGJ1bXBNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdGJ1bXBTY2FsZTogeyB2YWx1ZTogMSB9XG5cblx0fSxcblxuXHRub3JtYWxtYXA6IHtcblxuXHRcdG5vcm1hbE1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdG5vcm1hbE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cdFx0bm9ybWFsU2NhbGU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoIDEsIDEgKSB9XG5cblx0fSxcblxuXHRkaXNwbGFjZW1lbnRtYXA6IHtcblxuXHRcdGRpc3BsYWNlbWVudE1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGRpc3BsYWNlbWVudE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cdFx0ZGlzcGxhY2VtZW50U2NhbGU6IHsgdmFsdWU6IDEgfSxcblx0XHRkaXNwbGFjZW1lbnRCaWFzOiB7IHZhbHVlOiAwIH1cblxuXHR9LFxuXG5cdGVtaXNzaXZlbWFwOiB7XG5cblx0XHRlbWlzc2l2ZU1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGVtaXNzaXZlTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfVxuXG5cdH0sXG5cblx0bWV0YWxuZXNzbWFwOiB7XG5cblx0XHRtZXRhbG5lc3NNYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRtZXRhbG5lc3NNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XG5cblx0fSxcblxuXHRyb3VnaG5lc3NtYXA6IHtcblxuXHRcdHJvdWdobmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdHJvdWdobmVzc01hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH1cblxuXHR9LFxuXG5cdGdyYWRpZW50bWFwOiB7XG5cblx0XHRncmFkaWVudE1hcDogeyB2YWx1ZTogbnVsbCB9XG5cblx0fSxcblxuXHRmb2c6IHtcblxuXHRcdGZvZ0RlbnNpdHk6IHsgdmFsdWU6IDAuMDAwMjUgfSxcblx0XHRmb2dOZWFyOiB7IHZhbHVlOiAxIH0sXG5cdFx0Zm9nRmFyOiB7IHZhbHVlOiAyMDAwIH0sXG5cdFx0Zm9nQ29sb3I6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweGZmZmZmZiApIH1cblxuXHR9LFxuXG5cdGxpZ2h0czoge1xuXG5cdFx0YW1iaWVudExpZ2h0Q29sb3I6IHsgdmFsdWU6IFtdIH0sXG5cblx0XHRsaWdodFByb2JlOiB7IHZhbHVlOiBbXSB9LFxuXG5cdFx0ZGlyZWN0aW9uYWxMaWdodHM6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XG5cdFx0XHRkaXJlY3Rpb246IHt9LFxuXHRcdFx0Y29sb3I6IHt9XG5cdFx0fSB9LFxuXG5cdFx0ZGlyZWN0aW9uYWxMaWdodFNoYWRvd3M6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XG5cdFx0XHRzaGFkb3dJbnRlbnNpdHk6IDEsXG5cdFx0XHRzaGFkb3dCaWFzOiB7fSxcblx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IHt9LFxuXHRcdFx0c2hhZG93UmFkaXVzOiB7fSxcblx0XHRcdHNoYWRvd01hcFNpemU6IHt9XG5cdFx0fSB9LFxuXG5cdFx0ZGlyZWN0aW9uYWxTaGFkb3dNYXA6IHsgdmFsdWU6IFtdIH0sXG5cdFx0ZGlyZWN0aW9uYWxTaGFkb3dNYXRyaXg6IHsgdmFsdWU6IFtdIH0sXG5cblx0XHRzcG90TGlnaHRzOiB7IHZhbHVlOiBbXSwgcHJvcGVydGllczoge1xuXHRcdFx0Y29sb3I6IHt9LFxuXHRcdFx0cG9zaXRpb246IHt9LFxuXHRcdFx0ZGlyZWN0aW9uOiB7fSxcblx0XHRcdGRpc3RhbmNlOiB7fSxcblx0XHRcdGNvbmVDb3M6IHt9LFxuXHRcdFx0cGVudW1icmFDb3M6IHt9LFxuXHRcdFx0ZGVjYXk6IHt9XG5cdFx0fSB9LFxuXG5cdFx0c3BvdExpZ2h0U2hhZG93czogeyB2YWx1ZTogW10sIHByb3BlcnRpZXM6IHtcblx0XHRcdHNoYWRvd0ludGVuc2l0eTogMSxcblx0XHRcdHNoYWRvd0JpYXM6IHt9LFxuXHRcdFx0c2hhZG93Tm9ybWFsQmlhczoge30sXG5cdFx0XHRzaGFkb3dSYWRpdXM6IHt9LFxuXHRcdFx0c2hhZG93TWFwU2l6ZToge31cblx0XHR9IH0sXG5cblx0XHRzcG90TGlnaHRNYXA6IHsgdmFsdWU6IFtdIH0sXG5cdFx0c3BvdFNoYWRvd01hcDogeyB2YWx1ZTogW10gfSxcblx0XHRzcG90TGlnaHRNYXRyaXg6IHsgdmFsdWU6IFtdIH0sXG5cblx0XHRwb2ludExpZ2h0czogeyB2YWx1ZTogW10sIHByb3BlcnRpZXM6IHtcblx0XHRcdGNvbG9yOiB7fSxcblx0XHRcdHBvc2l0aW9uOiB7fSxcblx0XHRcdGRlY2F5OiB7fSxcblx0XHRcdGRpc3RhbmNlOiB7fVxuXHRcdH0gfSxcblxuXHRcdHBvaW50TGlnaHRTaGFkb3dzOiB7IHZhbHVlOiBbXSwgcHJvcGVydGllczoge1xuXHRcdFx0c2hhZG93SW50ZW5zaXR5OiAxLFxuXHRcdFx0c2hhZG93Qmlhczoge30sXG5cdFx0XHRzaGFkb3dOb3JtYWxCaWFzOiB7fSxcblx0XHRcdHNoYWRvd1JhZGl1czoge30sXG5cdFx0XHRzaGFkb3dNYXBTaXplOiB7fSxcblx0XHRcdHNoYWRvd0NhbWVyYU5lYXI6IHt9LFxuXHRcdFx0c2hhZG93Q2FtZXJhRmFyOiB7fVxuXHRcdH0gfSxcblxuXHRcdHBvaW50U2hhZG93TWFwOiB7IHZhbHVlOiBbXSB9LFxuXHRcdHBvaW50U2hhZG93TWF0cml4OiB7IHZhbHVlOiBbXSB9LFxuXG5cdFx0aGVtaXNwaGVyZUxpZ2h0czogeyB2YWx1ZTogW10sIHByb3BlcnRpZXM6IHtcblx0XHRcdGRpcmVjdGlvbjoge30sXG5cdFx0XHRza3lDb2xvcjoge30sXG5cdFx0XHRncm91bmRDb2xvcjoge31cblx0XHR9IH0sXG5cblx0XHQvLyBUT0RPIChhYmVsbmF0aW9uKTogUmVjdEFyZWFMaWdodCBCUkRGIGRhdGEgbmVlZHMgdG8gYmUgbW92ZWQgZnJvbSBleGFtcGxlIHRvIG1haW4gc3JjXG5cdFx0cmVjdEFyZWFMaWdodHM6IHsgdmFsdWU6IFtdLCBwcm9wZXJ0aWVzOiB7XG5cdFx0XHRjb2xvcjoge30sXG5cdFx0XHRwb3NpdGlvbjoge30sXG5cdFx0XHR3aWR0aDoge30sXG5cdFx0XHRoZWlnaHQ6IHt9XG5cdFx0fSB9LFxuXG5cdFx0bHRjXzE6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRsdGNfMjogeyB2YWx1ZTogbnVsbCB9XG5cblx0fSxcblxuXHRwb2ludHM6IHtcblxuXHRcdGRpZmZ1c2U6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweGZmZmZmZiApIH0sXG5cdFx0b3BhY2l0eTogeyB2YWx1ZTogMS4wIH0sXG5cdFx0c2l6ZTogeyB2YWx1ZTogMS4wIH0sXG5cdFx0c2NhbGU6IHsgdmFsdWU6IDEuMCB9LFxuXHRcdG1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdGFscGhhTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0YWxwaGFNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdGFscGhhVGVzdDogeyB2YWx1ZTogMCB9LFxuXHRcdHV2VHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfVxuXG5cdH0sXG5cblx0c3ByaXRlOiB7XG5cblx0XHRkaWZmdXNlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHhmZmZmZmYgKSB9LFxuXHRcdG9wYWNpdHk6IHsgdmFsdWU6IDEuMCB9LFxuXHRcdGNlbnRlcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMiggMC41LCAwLjUgKSB9LFxuXHRcdHJvdGF0aW9uOiB7IHZhbHVlOiAwLjAgfSxcblx0XHRtYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRtYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdGFscGhhTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0YWxwaGFNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdGFscGhhVGVzdDogeyB2YWx1ZTogMCB9XG5cblx0fVxuXG59O1xuXG5jb25zdCBTaGFkZXJMaWIgPSB7XG5cblx0YmFzaWM6IHtcblxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcblx0XHRcdFVuaWZvcm1zTGliLnNwZWN1bGFybWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuZW52bWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuYW9tYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmZvZ1xuXHRcdF0gKSxcblxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaGJhc2ljX3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hiYXNpY19mcmFnXG5cblx0fSxcblxuXHRsYW1iZXJ0OiB7XG5cblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXG5cdFx0XHRVbmlmb3Jtc0xpYi5jb21tb24sXG5cdFx0XHRVbmlmb3Jtc0xpYi5zcGVjdWxhcm1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmVudm1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmFvbWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbWlzc2l2ZW1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmJ1bXBtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5ub3JtYWxtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2csXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodHMsXG5cdFx0XHR7XG5cdFx0XHRcdGVtaXNzaXZlOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMHgwMDAwMDAgKSB9XG5cdFx0XHR9XG5cdFx0XSApLFxuXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobGFtYmVydF92ZXJ0LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobGFtYmVydF9mcmFnXG5cblx0fSxcblxuXHRwaG9uZzoge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxuXHRcdFx0VW5pZm9ybXNMaWIuc3BlY3VsYXJtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbnZtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5hb21hcCxcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0bWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuZW1pc3NpdmVtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5idW1wbWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIubm9ybWFsbWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuZGlzcGxhY2VtZW50bWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuZm9nLFxuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRzLFxuXHRcdFx0e1xuXHRcdFx0XHRlbWlzc2l2ZTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDB4MDAwMDAwICkgfSxcblx0XHRcdFx0c3BlY3VsYXI6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDExMTExMSApIH0sXG5cdFx0XHRcdHNoaW5pbmVzczogeyB2YWx1ZTogMzAgfVxuXHRcdFx0fVxuXHRcdF0gKSxcblxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaHBob25nX3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hwaG9uZ19mcmFnXG5cblx0fSxcblxuXHRzdGFuZGFyZDoge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxuXHRcdFx0VW5pZm9ybXNMaWIuZW52bWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuYW9tYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5saWdodG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmVtaXNzaXZlbWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIuYnVtcG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLm5vcm1hbG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmRpc3BsYWNlbWVudG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLnJvdWdobmVzc21hcCxcblx0XHRcdFVuaWZvcm1zTGliLm1ldGFsbmVzc21hcCxcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0cyxcblx0XHRcdHtcblx0XHRcdFx0ZW1pc3NpdmU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDAwMDAwMCApIH0sXG5cdFx0XHRcdHJvdWdobmVzczogeyB2YWx1ZTogMS4wIH0sXG5cdFx0XHRcdG1ldGFsbmVzczogeyB2YWx1ZTogMC4wIH0sXG5cdFx0XHRcdGVudk1hcEludGVuc2l0eTogeyB2YWx1ZTogMSB9XG5cdFx0XHR9XG5cdFx0XSApLFxuXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNocGh5c2ljYWxfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaHBoeXNpY2FsX2ZyYWdcblxuXHR9LFxuXG5cdHRvb246IHtcblxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcblx0XHRcdFVuaWZvcm1zTGliLmFvbWFwLFxuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5lbWlzc2l2ZW1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmJ1bXBtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5ub3JtYWxtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5ncmFkaWVudG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcblx0XHRcdFVuaWZvcm1zTGliLmxpZ2h0cyxcblx0XHRcdHtcblx0XHRcdFx0ZW1pc3NpdmU6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDAwMDAwMCApIH1cblx0XHRcdH1cblx0XHRdICksXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2h0b29uX3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2h0b29uX2ZyYWdcblxuXHR9LFxuXG5cdG1hdGNhcDoge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxuXHRcdFx0VW5pZm9ybXNMaWIuYnVtcG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLm5vcm1hbG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmRpc3BsYWNlbWVudG1hcCxcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcblx0XHRcdHtcblx0XHRcdFx0bWF0Y2FwOiB7IHZhbHVlOiBudWxsIH1cblx0XHRcdH1cblx0XHRdICksXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2htYXRjYXBfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaG1hdGNhcF9mcmFnXG5cblx0fSxcblxuXHRwb2ludHM6IHtcblxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRcdFVuaWZvcm1zTGliLnBvaW50cyxcblx0XHRcdFVuaWZvcm1zTGliLmZvZ1xuXHRcdF0gKSxcblxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsucG9pbnRzX3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLnBvaW50c19mcmFnXG5cblx0fSxcblxuXHRkYXNoZWQ6IHtcblxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcblx0XHRcdFVuaWZvcm1zTGliLmZvZyxcblx0XHRcdHtcblx0XHRcdFx0c2NhbGU6IHsgdmFsdWU6IDEgfSxcblx0XHRcdFx0ZGFzaFNpemU6IHsgdmFsdWU6IDEgfSxcblx0XHRcdFx0dG90YWxTaXplOiB7IHZhbHVlOiAyIH1cblx0XHRcdH1cblx0XHRdICksXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmxpbmVkYXNoZWRfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubGluZWRhc2hlZF9mcmFnXG5cblx0fSxcblxuXHRkZXB0aDoge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxuXHRcdFx0VW5pZm9ybXNMaWIuZGlzcGxhY2VtZW50bWFwXG5cdFx0XSApLFxuXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5kZXB0aF92ZXJ0LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5kZXB0aF9mcmFnXG5cblx0fSxcblxuXHRub3JtYWw6IHtcblxuXHRcdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRcdFVuaWZvcm1zTGliLmNvbW1vbixcblx0XHRcdFVuaWZvcm1zTGliLmJ1bXBtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5ub3JtYWxtYXAsXG5cdFx0XHRVbmlmb3Jtc0xpYi5kaXNwbGFjZW1lbnRtYXAsXG5cdFx0XHR7XG5cdFx0XHRcdG9wYWNpdHk6IHsgdmFsdWU6IDEuMCB9XG5cdFx0XHR9XG5cdFx0XSApLFxuXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5tZXNobm9ybWFsX3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hub3JtYWxfZnJhZ1xuXG5cdH0sXG5cblx0c3ByaXRlOiB7XG5cblx0XHR1bmlmb3JtczogLypAX19QVVJFX18qLyBtZXJnZVVuaWZvcm1zKCBbXG5cdFx0XHRVbmlmb3Jtc0xpYi5zcHJpdGUsXG5cdFx0XHRVbmlmb3Jtc0xpYi5mb2dcblx0XHRdICksXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLnNwcml0ZV92ZXJ0LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5zcHJpdGVfZnJhZ1xuXG5cdH0sXG5cblx0YmFja2dyb3VuZDoge1xuXG5cdFx0dW5pZm9ybXM6IHtcblx0XHRcdHV2VHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRcdHQyRDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0YmFja2dyb3VuZEludGVuc2l0eTogeyB2YWx1ZTogMSB9XG5cdFx0fSxcblxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsuYmFja2dyb3VuZF92ZXJ0LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5iYWNrZ3JvdW5kX2ZyYWdcblxuXHR9LFxuXG5cdGJhY2tncm91bmRDdWJlOiB7XG5cblx0XHR1bmlmb3Jtczoge1xuXHRcdFx0ZW52TWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRmbGlwRW52TWFwOiB7IHZhbHVlOiAtIDEgfSxcblx0XHRcdGJhY2tncm91bmRCbHVycmluZXNzOiB7IHZhbHVlOiAwIH0sXG5cdFx0XHRiYWNrZ3JvdW5kSW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0sXG5cdFx0XHRiYWNrZ3JvdW5kUm90YXRpb246IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9XG5cdFx0fSxcblxuXHRcdHZlcnRleFNoYWRlcjogU2hhZGVyQ2h1bmsuYmFja2dyb3VuZEN1YmVfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsuYmFja2dyb3VuZEN1YmVfZnJhZ1xuXG5cdH0sXG5cblx0Y3ViZToge1xuXG5cdFx0dW5pZm9ybXM6IHtcblx0XHRcdHRDdWJlOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHR0RmxpcDogeyB2YWx1ZTogLSAxIH0sXG5cdFx0XHRvcGFjaXR5OiB7IHZhbHVlOiAxLjAgfVxuXHRcdH0sXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmN1YmVfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsuY3ViZV9mcmFnXG5cblx0fSxcblxuXHRlcXVpcmVjdDoge1xuXG5cdFx0dW5pZm9ybXM6IHtcblx0XHRcdHRFcXVpcmVjdDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdH0sXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLmVxdWlyZWN0X3ZlcnQsXG5cdFx0ZnJhZ21lbnRTaGFkZXI6IFNoYWRlckNodW5rLmVxdWlyZWN0X2ZyYWdcblxuXHR9LFxuXG5cdGRpc3RhbmNlUkdCQToge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIuY29tbW9uLFxuXHRcdFx0VW5pZm9ybXNMaWIuZGlzcGxhY2VtZW50bWFwLFxuXHRcdFx0e1xuXHRcdFx0XHRyZWZlcmVuY2VQb3NpdGlvbjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpIH0sXG5cdFx0XHRcdG5lYXJEaXN0YW5jZTogeyB2YWx1ZTogMSB9LFxuXHRcdFx0XHRmYXJEaXN0YW5jZTogeyB2YWx1ZTogMTAwMCB9XG5cdFx0XHR9XG5cdFx0XSApLFxuXG5cdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJDaHVuay5kaXN0YW5jZVJHQkFfdmVydCxcblx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsuZGlzdGFuY2VSR0JBX2ZyYWdcblxuXHR9LFxuXG5cdHNoYWRvdzoge1xuXG5cdFx0dW5pZm9ybXM6IC8qQF9fUFVSRV9fKi8gbWVyZ2VVbmlmb3JtcyggW1xuXHRcdFx0VW5pZm9ybXNMaWIubGlnaHRzLFxuXHRcdFx0VW5pZm9ybXNMaWIuZm9nLFxuXHRcdFx0e1xuXHRcdFx0XHRjb2xvcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDB4MDAwMDAgKSB9LFxuXHRcdFx0XHRvcGFjaXR5OiB7IHZhbHVlOiAxLjAgfVxuXHRcdFx0fSxcblx0XHRdICksXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLnNoYWRvd192ZXJ0LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJDaHVuay5zaGFkb3dfZnJhZ1xuXG5cdH1cblxufTtcblxuU2hhZGVyTGliLnBoeXNpY2FsID0ge1xuXG5cdHVuaWZvcm1zOiAvKkBfX1BVUkVfXyovIG1lcmdlVW5pZm9ybXMoIFtcblx0XHRTaGFkZXJMaWIuc3RhbmRhcmQudW5pZm9ybXMsXG5cdFx0e1xuXHRcdFx0Y2xlYXJjb2F0OiB7IHZhbHVlOiAwIH0sXG5cdFx0XHRjbGVhcmNvYXRNYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdGNsZWFyY29hdE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cdFx0XHRjbGVhcmNvYXROb3JtYWxNYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdGNsZWFyY29hdE5vcm1hbE1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cdFx0XHRjbGVhcmNvYXROb3JtYWxTY2FsZTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMiggMSwgMSApIH0sXG5cdFx0XHRjbGVhcmNvYXRSb3VnaG5lc3M6IHsgdmFsdWU6IDAgfSxcblx0XHRcdGNsZWFyY29hdFJvdWdobmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0Y2xlYXJjb2F0Um91Z2huZXNzTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRcdGRpc3BlcnNpb246IHsgdmFsdWU6IDAgfSxcblx0XHRcdGlyaWRlc2NlbmNlOiB7IHZhbHVlOiAwIH0sXG5cdFx0XHRpcmlkZXNjZW5jZU1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0aXJpZGVzY2VuY2VNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdFx0aXJpZGVzY2VuY2VJT1I6IHsgdmFsdWU6IDEuMyB9LFxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNaW5pbXVtOiB7IHZhbHVlOiAxMDAgfSxcblx0XHRcdGlyaWRlc2NlbmNlVGhpY2tuZXNzTWF4aW11bTogeyB2YWx1ZTogNDAwIH0sXG5cdFx0XHRpcmlkZXNjZW5jZVRoaWNrbmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdFx0c2hlZW46IHsgdmFsdWU6IDAgfSxcblx0XHRcdHNoZWVuQ29sb3I6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDAwMDAwMCApIH0sXG5cdFx0XHRzaGVlbkNvbG9yTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRzaGVlbkNvbG9yTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRcdHNoZWVuUm91Z2huZXNzOiB7IHZhbHVlOiAxIH0sXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0c2hlZW5Sb3VnaG5lc3NNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdFx0dHJhbnNtaXNzaW9uOiB7IHZhbHVlOiAwIH0sXG5cdFx0XHR0cmFuc21pc3Npb25NYXA6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdHRyYW5zbWlzc2lvbk1hcFRyYW5zZm9ybTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgTWF0cml4MygpIH0sXG5cdFx0XHR0cmFuc21pc3Npb25TYW1wbGVyU2l6ZTogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpIH0sXG5cdFx0XHR0cmFuc21pc3Npb25TYW1wbGVyTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHR0aGlja25lc3M6IHsgdmFsdWU6IDAgfSxcblx0XHRcdHRoaWNrbmVzc01hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0dGhpY2tuZXNzTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRcdGF0dGVudWF0aW9uRGlzdGFuY2U6IHsgdmFsdWU6IDAgfSxcblx0XHRcdGF0dGVudWF0aW9uQ29sb3I6IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCAweDAwMDAwMCApIH0sXG5cdFx0XHRzcGVjdWxhckNvbG9yOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBDb2xvciggMSwgMSwgMSApIH0sXG5cdFx0XHRzcGVjdWxhckNvbG9yTWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRzcGVjdWxhckNvbG9yTWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5OiB7IHZhbHVlOiAxIH0sXG5cdFx0XHRzcGVjdWxhckludGVuc2l0eU1hcDogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdFx0c3BlY3VsYXJJbnRlbnNpdHlNYXBUcmFuc2Zvcm06IHsgdmFsdWU6IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDMoKSB9LFxuXHRcdFx0YW5pc290cm9weVZlY3RvcjogeyB2YWx1ZTogLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpIH0sXG5cdFx0XHRhbmlzb3Ryb3B5TWFwOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRhbmlzb3Ryb3B5TWFwVHJhbnNmb3JtOiB7IHZhbHVlOiAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXgzKCkgfSxcblx0XHR9XG5cdF0gKSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IFNoYWRlckNodW5rLm1lc2hwaHlzaWNhbF92ZXJ0LFxuXHRmcmFnbWVudFNoYWRlcjogU2hhZGVyQ2h1bmsubWVzaHBoeXNpY2FsX2ZyYWdcblxufTtcblxuY29uc3QgX3JnYiA9IHsgcjogMCwgYjogMCwgZzogMCB9O1xuY29uc3QgX2UxJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBFdWxlcigpO1xuY29uc3QgX20xJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5cbmZ1bmN0aW9uIFdlYkdMQmFja2dyb3VuZCggcmVuZGVyZXIsIGN1YmVtYXBzLCBjdWJldXZtYXBzLCBzdGF0ZSwgb2JqZWN0cywgYWxwaGEsIHByZW11bHRpcGxpZWRBbHBoYSApIHtcblxuXHRjb25zdCBjbGVhckNvbG9yID0gbmV3IENvbG9yKCAweDAwMDAwMCApO1xuXHRsZXQgY2xlYXJBbHBoYSA9IGFscGhhID09PSB0cnVlID8gMCA6IDE7XG5cblx0bGV0IHBsYW5lTWVzaDtcblx0bGV0IGJveE1lc2g7XG5cblx0bGV0IGN1cnJlbnRCYWNrZ3JvdW5kID0gbnVsbDtcblx0bGV0IGN1cnJlbnRCYWNrZ3JvdW5kVmVyc2lvbiA9IDA7XG5cdGxldCBjdXJyZW50VG9uZW1hcHBpbmcgPSBudWxsO1xuXG5cdGZ1bmN0aW9uIGdldEJhY2tncm91bmQoIHNjZW5lICkge1xuXG5cdFx0bGV0IGJhY2tncm91bmQgPSBzY2VuZS5pc1NjZW5lID09PSB0cnVlID8gc2NlbmUuYmFja2dyb3VuZCA6IG51bGw7XG5cblx0XHRpZiAoIGJhY2tncm91bmQgJiYgYmFja2dyb3VuZC5pc1RleHR1cmUgKSB7XG5cblx0XHRcdGNvbnN0IHVzZVBNUkVNID0gc2NlbmUuYmFja2dyb3VuZEJsdXJyaW5lc3MgPiAwOyAvLyB1c2UgUE1SRU0gaWYgdGhlIHVzZXIgd2FudHMgdG8gYmx1ciB0aGUgYmFja2dyb3VuZFxuXHRcdFx0YmFja2dyb3VuZCA9ICggdXNlUE1SRU0gPyBjdWJldXZtYXBzIDogY3ViZW1hcHMgKS5nZXQoIGJhY2tncm91bmQgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBiYWNrZ3JvdW5kO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXIoIHNjZW5lICkge1xuXG5cdFx0bGV0IGZvcmNlQ2xlYXIgPSBmYWxzZTtcblx0XHRjb25zdCBiYWNrZ3JvdW5kID0gZ2V0QmFja2dyb3VuZCggc2NlbmUgKTtcblxuXHRcdGlmICggYmFja2dyb3VuZCA9PT0gbnVsbCApIHtcblxuXHRcdFx0c2V0Q2xlYXIoIGNsZWFyQ29sb3IsIGNsZWFyQWxwaGEgKTtcblxuXHRcdH0gZWxzZSBpZiAoIGJhY2tncm91bmQgJiYgYmFja2dyb3VuZC5pc0NvbG9yICkge1xuXG5cdFx0XHRzZXRDbGVhciggYmFja2dyb3VuZCwgMSApO1xuXHRcdFx0Zm9yY2VDbGVhciA9IHRydWU7XG5cblx0XHR9XG5cblx0XHRjb25zdCBlbnZpcm9ubWVudEJsZW5kTW9kZSA9IHJlbmRlcmVyLnhyLmdldEVudmlyb25tZW50QmxlbmRNb2RlKCk7XG5cblx0XHRpZiAoIGVudmlyb25tZW50QmxlbmRNb2RlID09PSAnYWRkaXRpdmUnICkge1xuXG5cdFx0XHRzdGF0ZS5idWZmZXJzLmNvbG9yLnNldENsZWFyKCAwLCAwLCAwLCAxLCBwcmVtdWx0aXBsaWVkQWxwaGEgKTtcblxuXHRcdH0gZWxzZSBpZiAoIGVudmlyb25tZW50QmxlbmRNb2RlID09PSAnYWxwaGEtYmxlbmQnICkge1xuXG5cdFx0XHRzdGF0ZS5idWZmZXJzLmNvbG9yLnNldENsZWFyKCAwLCAwLCAwLCAwLCBwcmVtdWx0aXBsaWVkQWxwaGEgKTtcblxuXHRcdH1cblxuXHRcdGlmICggcmVuZGVyZXIuYXV0b0NsZWFyIHx8IGZvcmNlQ2xlYXIgKSB7XG5cblx0XHRcdC8vIGJ1ZmZlcnMgbWlnaHQgbm90IGJlIHdyaXRhYmxlIHdoaWNoIGlzIHJlcXVpcmVkIHRvIGVuc3VyZSBhIGNvcnJlY3QgY2xlYXJcblxuXHRcdFx0c3RhdGUuYnVmZmVycy5kZXB0aC5zZXRUZXN0KCB0cnVlICk7XG5cdFx0XHRzdGF0ZS5idWZmZXJzLmRlcHRoLnNldE1hc2soIHRydWUgKTtcblx0XHRcdHN0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0TWFzayggdHJ1ZSApO1xuXG5cdFx0XHRyZW5kZXJlci5jbGVhciggcmVuZGVyZXIuYXV0b0NsZWFyQ29sb3IsIHJlbmRlcmVyLmF1dG9DbGVhckRlcHRoLCByZW5kZXJlci5hdXRvQ2xlYXJTdGVuY2lsICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGFkZFRvUmVuZGVyTGlzdCggcmVuZGVyTGlzdCwgc2NlbmUgKSB7XG5cblx0XHRjb25zdCBiYWNrZ3JvdW5kID0gZ2V0QmFja2dyb3VuZCggc2NlbmUgKTtcblxuXHRcdGlmICggYmFja2dyb3VuZCAmJiAoIGJhY2tncm91bmQuaXNDdWJlVGV4dHVyZSB8fCBiYWNrZ3JvdW5kLm1hcHBpbmcgPT09IEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nICkgKSB7XG5cblx0XHRcdGlmICggYm94TWVzaCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGJveE1lc2ggPSBuZXcgTWVzaChcblx0XHRcdFx0XHRuZXcgQm94R2VvbWV0cnkoIDEsIDEsIDEgKSxcblx0XHRcdFx0XHRuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcblx0XHRcdFx0XHRcdG5hbWU6ICdCYWNrZ3JvdW5kQ3ViZU1hdGVyaWFsJyxcblx0XHRcdFx0XHRcdHVuaWZvcm1zOiBjbG9uZVVuaWZvcm1zKCBTaGFkZXJMaWIuYmFja2dyb3VuZEN1YmUudW5pZm9ybXMgKSxcblx0XHRcdFx0XHRcdHZlcnRleFNoYWRlcjogU2hhZGVyTGliLmJhY2tncm91bmRDdWJlLnZlcnRleFNoYWRlcixcblx0XHRcdFx0XHRcdGZyYWdtZW50U2hhZGVyOiBTaGFkZXJMaWIuYmFja2dyb3VuZEN1YmUuZnJhZ21lbnRTaGFkZXIsXG5cdFx0XHRcdFx0XHRzaWRlOiBCYWNrU2lkZSxcblx0XHRcdFx0XHRcdGRlcHRoVGVzdDogZmFsc2UsXG5cdFx0XHRcdFx0XHRkZXB0aFdyaXRlOiBmYWxzZSxcblx0XHRcdFx0XHRcdGZvZzogZmFsc2Vcblx0XHRcdFx0XHR9IClcblx0XHRcdFx0KTtcblxuXHRcdFx0XHRib3hNZXNoLmdlb21ldHJ5LmRlbGV0ZUF0dHJpYnV0ZSggJ25vcm1hbCcgKTtcblx0XHRcdFx0Ym94TWVzaC5nZW9tZXRyeS5kZWxldGVBdHRyaWJ1dGUoICd1dicgKTtcblxuXHRcdFx0XHRib3hNZXNoLm9uQmVmb3JlUmVuZGVyID0gZnVuY3Rpb24gKCByZW5kZXJlciwgc2NlbmUsIGNhbWVyYSApIHtcblxuXHRcdFx0XHRcdHRoaXMubWF0cml4V29ybGQuY29weVBvc2l0aW9uKCBjYW1lcmEubWF0cml4V29ybGQgKTtcblxuXHRcdFx0XHR9O1xuXG5cdFx0XHRcdC8vIGFkZCBcImVudk1hcFwiIG1hdGVyaWFsIHByb3BlcnR5IHNvIHRoZSByZW5kZXJlciBjYW4gZXZhbHVhdGUgaXQgbGlrZSBmb3IgYnVpbHQtaW4gbWF0ZXJpYWxzXG5cdFx0XHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0eSggYm94TWVzaC5tYXRlcmlhbCwgJ2Vudk1hcCcsIHtcblxuXHRcdFx0XHRcdGdldDogZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy51bmlmb3Jtcy5lbnZNYXAudmFsdWU7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdG9iamVjdHMudXBkYXRlKCBib3hNZXNoICk7XG5cblx0XHRcdH1cblxuXHRcdFx0X2UxJDEuY29weSggc2NlbmUuYmFja2dyb3VuZFJvdGF0aW9uICk7XG5cblx0XHRcdC8vIGFjY29tbW9kYXRlIGxlZnQtaGFuZGVkIGZyYW1lXG5cdFx0XHRfZTEkMS54ICo9IC0gMTsgX2UxJDEueSAqPSAtIDE7IF9lMSQxLnogKj0gLSAxO1xuXG5cdFx0XHRpZiAoIGJhY2tncm91bmQuaXNDdWJlVGV4dHVyZSAmJiBiYWNrZ3JvdW5kLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0Ly8gZW52aXJvbm1lbnQgbWFwcyB3aGljaCBhcmUgbm90IGN1YmUgcmVuZGVyIHRhcmdldHMgb3IgUE1SRU1zIGZvbGxvdyBhIGRpZmZlcmVudCBjb252ZW50aW9uXG5cdFx0XHRcdF9lMSQxLnkgKj0gLSAxO1xuXHRcdFx0XHRfZTEkMS56ICo9IC0gMTtcblxuXHRcdFx0fVxuXG5cdFx0XHRib3hNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmVudk1hcC52YWx1ZSA9IGJhY2tncm91bmQ7XG5cdFx0XHRib3hNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmZsaXBFbnZNYXAudmFsdWUgPSAoIGJhY2tncm91bmQuaXNDdWJlVGV4dHVyZSAmJiBiYWNrZ3JvdW5kLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSA/IC0gMSA6IDE7XG5cdFx0XHRib3hNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmJhY2tncm91bmRCbHVycmluZXNzLnZhbHVlID0gc2NlbmUuYmFja2dyb3VuZEJsdXJyaW5lc3M7XG5cdFx0XHRib3hNZXNoLm1hdGVyaWFsLnVuaWZvcm1zLmJhY2tncm91bmRJbnRlbnNpdHkudmFsdWUgPSBzY2VuZS5iYWNrZ3JvdW5kSW50ZW5zaXR5O1xuXHRcdFx0Ym94TWVzaC5tYXRlcmlhbC51bmlmb3Jtcy5iYWNrZ3JvdW5kUm90YXRpb24udmFsdWUuc2V0RnJvbU1hdHJpeDQoIF9tMSQxLm1ha2VSb3RhdGlvbkZyb21FdWxlciggX2UxJDEgKSApO1xuXHRcdFx0Ym94TWVzaC5tYXRlcmlhbC50b25lTWFwcGVkID0gQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBiYWNrZ3JvdW5kLmNvbG9yU3BhY2UgKSAhPT0gU1JHQlRyYW5zZmVyO1xuXG5cdFx0XHRpZiAoIGN1cnJlbnRCYWNrZ3JvdW5kICE9PSBiYWNrZ3JvdW5kIHx8XG5cdFx0XHRcdGN1cnJlbnRCYWNrZ3JvdW5kVmVyc2lvbiAhPT0gYmFja2dyb3VuZC52ZXJzaW9uIHx8XG5cdFx0XHRcdGN1cnJlbnRUb25lbWFwcGluZyAhPT0gcmVuZGVyZXIudG9uZU1hcHBpbmcgKSB7XG5cblx0XHRcdFx0Ym94TWVzaC5tYXRlcmlhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdFx0Y3VycmVudEJhY2tncm91bmQgPSBiYWNrZ3JvdW5kO1xuXHRcdFx0XHRjdXJyZW50QmFja2dyb3VuZFZlcnNpb24gPSBiYWNrZ3JvdW5kLnZlcnNpb247XG5cdFx0XHRcdGN1cnJlbnRUb25lbWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xuXG5cdFx0XHR9XG5cblx0XHRcdGJveE1lc2gubGF5ZXJzLmVuYWJsZUFsbCgpO1xuXG5cdFx0XHQvLyBwdXNoIHRvIHRoZSBwcmUtc29ydGVkIG9wYXF1ZSByZW5kZXIgbGlzdFxuXHRcdFx0cmVuZGVyTGlzdC51bnNoaWZ0KCBib3hNZXNoLCBib3hNZXNoLmdlb21ldHJ5LCBib3hNZXNoLm1hdGVyaWFsLCAwLCAwLCBudWxsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBiYWNrZ3JvdW5kICYmIGJhY2tncm91bmQuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRpZiAoIHBsYW5lTWVzaCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHBsYW5lTWVzaCA9IG5ldyBNZXNoKFxuXHRcdFx0XHRcdG5ldyBQbGFuZUdlb21ldHJ5KCAyLCAyICksXG5cdFx0XHRcdFx0bmV3IFNoYWRlck1hdGVyaWFsKCB7XG5cdFx0XHRcdFx0XHRuYW1lOiAnQmFja2dyb3VuZE1hdGVyaWFsJyxcblx0XHRcdFx0XHRcdHVuaWZvcm1zOiBjbG9uZVVuaWZvcm1zKCBTaGFkZXJMaWIuYmFja2dyb3VuZC51bmlmb3JtcyApLFxuXHRcdFx0XHRcdFx0dmVydGV4U2hhZGVyOiBTaGFkZXJMaWIuYmFja2dyb3VuZC52ZXJ0ZXhTaGFkZXIsXG5cdFx0XHRcdFx0XHRmcmFnbWVudFNoYWRlcjogU2hhZGVyTGliLmJhY2tncm91bmQuZnJhZ21lbnRTaGFkZXIsXG5cdFx0XHRcdFx0XHRzaWRlOiBGcm9udFNpZGUsXG5cdFx0XHRcdFx0XHRkZXB0aFRlc3Q6IGZhbHNlLFxuXHRcdFx0XHRcdFx0ZGVwdGhXcml0ZTogZmFsc2UsXG5cdFx0XHRcdFx0XHRmb2c6IGZhbHNlXG5cdFx0XHRcdFx0fSApXG5cdFx0XHRcdCk7XG5cblx0XHRcdFx0cGxhbmVNZXNoLmdlb21ldHJ5LmRlbGV0ZUF0dHJpYnV0ZSggJ25vcm1hbCcgKTtcblxuXHRcdFx0XHQvLyBhZGQgXCJtYXBcIiBtYXRlcmlhbCBwcm9wZXJ0eSBzbyB0aGUgcmVuZGVyZXIgY2FuIGV2YWx1YXRlIGl0IGxpa2UgZm9yIGJ1aWx0LWluIG1hdGVyaWFsc1xuXHRcdFx0XHRPYmplY3QuZGVmaW5lUHJvcGVydHkoIHBsYW5lTWVzaC5tYXRlcmlhbCwgJ21hcCcsIHtcblxuXHRcdFx0XHRcdGdldDogZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRcdFx0XHRyZXR1cm4gdGhpcy51bmlmb3Jtcy50MkQudmFsdWU7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdG9iamVjdHMudXBkYXRlKCBwbGFuZU1lc2ggKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRwbGFuZU1lc2gubWF0ZXJpYWwudW5pZm9ybXMudDJELnZhbHVlID0gYmFja2dyb3VuZDtcblx0XHRcdHBsYW5lTWVzaC5tYXRlcmlhbC51bmlmb3Jtcy5iYWNrZ3JvdW5kSW50ZW5zaXR5LnZhbHVlID0gc2NlbmUuYmFja2dyb3VuZEludGVuc2l0eTtcblx0XHRcdHBsYW5lTWVzaC5tYXRlcmlhbC50b25lTWFwcGVkID0gQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBiYWNrZ3JvdW5kLmNvbG9yU3BhY2UgKSAhPT0gU1JHQlRyYW5zZmVyO1xuXG5cdFx0XHRpZiAoIGJhY2tncm91bmQubWF0cml4QXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRiYWNrZ3JvdW5kLnVwZGF0ZU1hdHJpeCgpO1xuXG5cdFx0XHR9XG5cblx0XHRcdHBsYW5lTWVzaC5tYXRlcmlhbC51bmlmb3Jtcy51dlRyYW5zZm9ybS52YWx1ZS5jb3B5KCBiYWNrZ3JvdW5kLm1hdHJpeCApO1xuXG5cdFx0XHRpZiAoIGN1cnJlbnRCYWNrZ3JvdW5kICE9PSBiYWNrZ3JvdW5kIHx8XG5cdFx0XHRcdGN1cnJlbnRCYWNrZ3JvdW5kVmVyc2lvbiAhPT0gYmFja2dyb3VuZC52ZXJzaW9uIHx8XG5cdFx0XHRcdGN1cnJlbnRUb25lbWFwcGluZyAhPT0gcmVuZGVyZXIudG9uZU1hcHBpbmcgKSB7XG5cblx0XHRcdFx0cGxhbmVNZXNoLm1hdGVyaWFsLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdFx0XHRjdXJyZW50QmFja2dyb3VuZCA9IGJhY2tncm91bmQ7XG5cdFx0XHRcdGN1cnJlbnRCYWNrZ3JvdW5kVmVyc2lvbiA9IGJhY2tncm91bmQudmVyc2lvbjtcblx0XHRcdFx0Y3VycmVudFRvbmVtYXBwaW5nID0gcmVuZGVyZXIudG9uZU1hcHBpbmc7XG5cblx0XHRcdH1cblxuXHRcdFx0cGxhbmVNZXNoLmxheWVycy5lbmFibGVBbGwoKTtcblxuXHRcdFx0Ly8gcHVzaCB0byB0aGUgcHJlLXNvcnRlZCBvcGFxdWUgcmVuZGVyIGxpc3Rcblx0XHRcdHJlbmRlckxpc3QudW5zaGlmdCggcGxhbmVNZXNoLCBwbGFuZU1lc2guZ2VvbWV0cnksIHBsYW5lTWVzaC5tYXRlcmlhbCwgMCwgMCwgbnVsbCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBzZXRDbGVhciggY29sb3IsIGFscGhhICkge1xuXG5cdFx0Y29sb3IuZ2V0UkdCKCBfcmdiLCBnZXRVbmxpdFVuaWZvcm1Db2xvclNwYWNlKCByZW5kZXJlciApICk7XG5cblx0XHRzdGF0ZS5idWZmZXJzLmNvbG9yLnNldENsZWFyKCBfcmdiLnIsIF9yZ2IuZywgX3JnYi5iLCBhbHBoYSwgcHJlbXVsdGlwbGllZEFscGhhICk7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cblx0XHRnZXRDbGVhckNvbG9yOiBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBjbGVhckNvbG9yO1xuXG5cdFx0fSxcblx0XHRzZXRDbGVhckNvbG9yOiBmdW5jdGlvbiAoIGNvbG9yLCBhbHBoYSA9IDEgKSB7XG5cblx0XHRcdGNsZWFyQ29sb3Iuc2V0KCBjb2xvciApO1xuXHRcdFx0Y2xlYXJBbHBoYSA9IGFscGhhO1xuXHRcdFx0c2V0Q2xlYXIoIGNsZWFyQ29sb3IsIGNsZWFyQWxwaGEgKTtcblxuXHRcdH0sXG5cdFx0Z2V0Q2xlYXJBbHBoYTogZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gY2xlYXJBbHBoYTtcblxuXHRcdH0sXG5cdFx0c2V0Q2xlYXJBbHBoYTogZnVuY3Rpb24gKCBhbHBoYSApIHtcblxuXHRcdFx0Y2xlYXJBbHBoYSA9IGFscGhhO1xuXHRcdFx0c2V0Q2xlYXIoIGNsZWFyQ29sb3IsIGNsZWFyQWxwaGEgKTtcblxuXHRcdH0sXG5cdFx0cmVuZGVyOiByZW5kZXIsXG5cdFx0YWRkVG9SZW5kZXJMaXN0OiBhZGRUb1JlbmRlckxpc3RcblxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMQmluZGluZ1N0YXRlcyggZ2wsIGF0dHJpYnV0ZXMgKSB7XG5cblx0Y29uc3QgbWF4VmVydGV4QXR0cmlidXRlcyA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1ZFUlRFWF9BVFRSSUJTICk7XG5cblx0Y29uc3QgYmluZGluZ1N0YXRlcyA9IHt9O1xuXG5cdGNvbnN0IGRlZmF1bHRTdGF0ZSA9IGNyZWF0ZUJpbmRpbmdTdGF0ZSggbnVsbCApO1xuXHRsZXQgY3VycmVudFN0YXRlID0gZGVmYXVsdFN0YXRlO1xuXHRsZXQgZm9yY2VVcGRhdGUgPSBmYWxzZTtcblxuXHRmdW5jdGlvbiBzZXR1cCggb2JqZWN0LCBtYXRlcmlhbCwgcHJvZ3JhbSwgZ2VvbWV0cnksIGluZGV4ICkge1xuXG5cdFx0bGV0IHVwZGF0ZUJ1ZmZlcnMgPSBmYWxzZTtcblxuXHRcdGNvbnN0IHN0YXRlID0gZ2V0QmluZGluZ1N0YXRlKCBnZW9tZXRyeSwgcHJvZ3JhbSwgbWF0ZXJpYWwgKTtcblxuXHRcdGlmICggY3VycmVudFN0YXRlICE9PSBzdGF0ZSApIHtcblxuXHRcdFx0Y3VycmVudFN0YXRlID0gc3RhdGU7XG5cdFx0XHRiaW5kVmVydGV4QXJyYXlPYmplY3QoIGN1cnJlbnRTdGF0ZS5vYmplY3QgKTtcblxuXHRcdH1cblxuXHRcdHVwZGF0ZUJ1ZmZlcnMgPSBuZWVkc1VwZGF0ZSggb2JqZWN0LCBnZW9tZXRyeSwgcHJvZ3JhbSwgaW5kZXggKTtcblxuXHRcdGlmICggdXBkYXRlQnVmZmVycyApIHNhdmVDYWNoZSggb2JqZWN0LCBnZW9tZXRyeSwgcHJvZ3JhbSwgaW5kZXggKTtcblxuXHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XG5cblx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBpbmRleCwgZ2wuRUxFTUVOVF9BUlJBWV9CVUZGRVIgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdXBkYXRlQnVmZmVycyB8fCBmb3JjZVVwZGF0ZSApIHtcblxuXHRcdFx0Zm9yY2VVcGRhdGUgPSBmYWxzZTtcblxuXHRcdFx0c2V0dXBWZXJ0ZXhBdHRyaWJ1dGVzKCBvYmplY3QsIG1hdGVyaWFsLCBwcm9ncmFtLCBnZW9tZXRyeSApO1xuXG5cdFx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGdsLmJpbmRCdWZmZXIoIGdsLkVMRU1FTlRfQVJSQVlfQlVGRkVSLCBhdHRyaWJ1dGVzLmdldCggaW5kZXggKS5idWZmZXIgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBjcmVhdGVWZXJ0ZXhBcnJheU9iamVjdCgpIHtcblxuXHRcdHJldHVybiBnbC5jcmVhdGVWZXJ0ZXhBcnJheSgpO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBiaW5kVmVydGV4QXJyYXlPYmplY3QoIHZhbyApIHtcblxuXHRcdHJldHVybiBnbC5iaW5kVmVydGV4QXJyYXkoIHZhbyApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBkZWxldGVWZXJ0ZXhBcnJheU9iamVjdCggdmFvICkge1xuXG5cdFx0cmV0dXJuIGdsLmRlbGV0ZVZlcnRleEFycmF5KCB2YW8gKTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0QmluZGluZ1N0YXRlKCBnZW9tZXRyeSwgcHJvZ3JhbSwgbWF0ZXJpYWwgKSB7XG5cblx0XHRjb25zdCB3aXJlZnJhbWUgPSAoIG1hdGVyaWFsLndpcmVmcmFtZSA9PT0gdHJ1ZSApO1xuXG5cdFx0bGV0IHByb2dyYW1NYXAgPSBiaW5kaW5nU3RhdGVzWyBnZW9tZXRyeS5pZCBdO1xuXG5cdFx0aWYgKCBwcm9ncmFtTWFwID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHByb2dyYW1NYXAgPSB7fTtcblx0XHRcdGJpbmRpbmdTdGF0ZXNbIGdlb21ldHJ5LmlkIF0gPSBwcm9ncmFtTWFwO1xuXG5cdFx0fVxuXG5cdFx0bGV0IHN0YXRlTWFwID0gcHJvZ3JhbU1hcFsgcHJvZ3JhbS5pZCBdO1xuXG5cdFx0aWYgKCBzdGF0ZU1hcCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRzdGF0ZU1hcCA9IHt9O1xuXHRcdFx0cHJvZ3JhbU1hcFsgcHJvZ3JhbS5pZCBdID0gc3RhdGVNYXA7XG5cblx0XHR9XG5cblx0XHRsZXQgc3RhdGUgPSBzdGF0ZU1hcFsgd2lyZWZyYW1lIF07XG5cblx0XHRpZiAoIHN0YXRlID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHN0YXRlID0gY3JlYXRlQmluZGluZ1N0YXRlKCBjcmVhdGVWZXJ0ZXhBcnJheU9iamVjdCgpICk7XG5cdFx0XHRzdGF0ZU1hcFsgd2lyZWZyYW1lIF0gPSBzdGF0ZTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBzdGF0ZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gY3JlYXRlQmluZGluZ1N0YXRlKCB2YW8gKSB7XG5cblx0XHRjb25zdCBuZXdBdHRyaWJ1dGVzID0gW107XG5cdFx0Y29uc3QgZW5hYmxlZEF0dHJpYnV0ZXMgPSBbXTtcblx0XHRjb25zdCBhdHRyaWJ1dGVEaXZpc29ycyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbWF4VmVydGV4QXR0cmlidXRlczsgaSArKyApIHtcblxuXHRcdFx0bmV3QXR0cmlidXRlc1sgaSBdID0gMDtcblx0XHRcdGVuYWJsZWRBdHRyaWJ1dGVzWyBpIF0gPSAwO1xuXHRcdFx0YXR0cmlidXRlRGl2aXNvcnNbIGkgXSA9IDA7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4ge1xuXG5cdFx0XHQvLyBmb3IgYmFja3dhcmQgY29tcGF0aWJpbGl0eSBvbiBub24tVkFPIHN1cHBvcnQgYnJvd3NlclxuXHRcdFx0Z2VvbWV0cnk6IG51bGwsXG5cdFx0XHRwcm9ncmFtOiBudWxsLFxuXHRcdFx0d2lyZWZyYW1lOiBmYWxzZSxcblxuXHRcdFx0bmV3QXR0cmlidXRlczogbmV3QXR0cmlidXRlcyxcblx0XHRcdGVuYWJsZWRBdHRyaWJ1dGVzOiBlbmFibGVkQXR0cmlidXRlcyxcblx0XHRcdGF0dHJpYnV0ZURpdmlzb3JzOiBhdHRyaWJ1dGVEaXZpc29ycyxcblx0XHRcdG9iamVjdDogdmFvLFxuXHRcdFx0YXR0cmlidXRlczoge30sXG5cdFx0XHRpbmRleDogbnVsbFxuXG5cdFx0fTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gbmVlZHNVcGRhdGUoIG9iamVjdCwgZ2VvbWV0cnksIHByb2dyYW0sIGluZGV4ICkge1xuXG5cdFx0Y29uc3QgY2FjaGVkQXR0cmlidXRlcyA9IGN1cnJlbnRTdGF0ZS5hdHRyaWJ1dGVzO1xuXHRcdGNvbnN0IGdlb21ldHJ5QXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XG5cblx0XHRsZXQgYXR0cmlidXRlc051bSA9IDA7XG5cblx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlcyA9IHByb2dyYW0uZ2V0QXR0cmlidXRlcygpO1xuXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBwcm9ncmFtQXR0cmlidXRlcyApIHtcblxuXHRcdFx0Y29uc3QgcHJvZ3JhbUF0dHJpYnV0ZSA9IHByb2dyYW1BdHRyaWJ1dGVzWyBuYW1lIF07XG5cblx0XHRcdGlmICggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiA+PSAwICkge1xuXG5cdFx0XHRcdGNvbnN0IGNhY2hlZEF0dHJpYnV0ZSA9IGNhY2hlZEF0dHJpYnV0ZXNbIG5hbWUgXTtcblx0XHRcdFx0bGV0IGdlb21ldHJ5QXR0cmlidXRlID0gZ2VvbWV0cnlBdHRyaWJ1dGVzWyBuYW1lIF07XG5cblx0XHRcdFx0aWYgKCBnZW9tZXRyeUF0dHJpYnV0ZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0aWYgKCBuYW1lID09PSAnaW5zdGFuY2VNYXRyaXgnICYmIG9iamVjdC5pbnN0YW5jZU1hdHJpeCApIGdlb21ldHJ5QXR0cmlidXRlID0gb2JqZWN0Lmluc3RhbmNlTWF0cml4O1xuXHRcdFx0XHRcdGlmICggbmFtZSA9PT0gJ2luc3RhbmNlQ29sb3InICYmIG9iamVjdC5pbnN0YW5jZUNvbG9yICkgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBvYmplY3QuaW5zdGFuY2VDb2xvcjtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBjYWNoZWRBdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIHJldHVybiB0cnVlO1xuXG5cdFx0XHRcdGlmICggY2FjaGVkQXR0cmlidXRlLmF0dHJpYnV0ZSAhPT0gZ2VvbWV0cnlBdHRyaWJ1dGUgKSByZXR1cm4gdHJ1ZTtcblxuXHRcdFx0XHRpZiAoIGdlb21ldHJ5QXR0cmlidXRlICYmIGNhY2hlZEF0dHJpYnV0ZS5kYXRhICE9PSBnZW9tZXRyeUF0dHJpYnV0ZS5kYXRhICkgcmV0dXJuIHRydWU7XG5cblx0XHRcdFx0YXR0cmlidXRlc051bSArKztcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBjdXJyZW50U3RhdGUuYXR0cmlidXRlc051bSAhPT0gYXR0cmlidXRlc051bSApIHJldHVybiB0cnVlO1xuXG5cdFx0aWYgKCBjdXJyZW50U3RhdGUuaW5kZXggIT09IGluZGV4ICkgcmV0dXJuIHRydWU7XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHNhdmVDYWNoZSggb2JqZWN0LCBnZW9tZXRyeSwgcHJvZ3JhbSwgaW5kZXggKSB7XG5cblx0XHRjb25zdCBjYWNoZSA9IHt9O1xuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzO1xuXHRcdGxldCBhdHRyaWJ1dGVzTnVtID0gMDtcblxuXHRcdGNvbnN0IHByb2dyYW1BdHRyaWJ1dGVzID0gcHJvZ3JhbS5nZXRBdHRyaWJ1dGVzKCk7XG5cblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIHByb2dyYW1BdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlID0gcHJvZ3JhbUF0dHJpYnV0ZXNbIG5hbWUgXTtcblxuXHRcdFx0aWYgKCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uID49IDAgKSB7XG5cblx0XHRcdFx0bGV0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXNbIG5hbWUgXTtcblxuXHRcdFx0XHRpZiAoIGF0dHJpYnV0ZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0aWYgKCBuYW1lID09PSAnaW5zdGFuY2VNYXRyaXgnICYmIG9iamVjdC5pbnN0YW5jZU1hdHJpeCApIGF0dHJpYnV0ZSA9IG9iamVjdC5pbnN0YW5jZU1hdHJpeDtcblx0XHRcdFx0XHRpZiAoIG5hbWUgPT09ICdpbnN0YW5jZUNvbG9yJyAmJiBvYmplY3QuaW5zdGFuY2VDb2xvciApIGF0dHJpYnV0ZSA9IG9iamVjdC5pbnN0YW5jZUNvbG9yO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRjb25zdCBkYXRhID0ge307XG5cdFx0XHRcdGRhdGEuYXR0cmlidXRlID0gYXR0cmlidXRlO1xuXG5cdFx0XHRcdGlmICggYXR0cmlidXRlICYmIGF0dHJpYnV0ZS5kYXRhICkge1xuXG5cdFx0XHRcdFx0ZGF0YS5kYXRhID0gYXR0cmlidXRlLmRhdGE7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNhY2hlWyBuYW1lIF0gPSBkYXRhO1xuXG5cdFx0XHRcdGF0dHJpYnV0ZXNOdW0gKys7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGN1cnJlbnRTdGF0ZS5hdHRyaWJ1dGVzID0gY2FjaGU7XG5cdFx0Y3VycmVudFN0YXRlLmF0dHJpYnV0ZXNOdW0gPSBhdHRyaWJ1dGVzTnVtO1xuXG5cdFx0Y3VycmVudFN0YXRlLmluZGV4ID0gaW5kZXg7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGluaXRBdHRyaWJ1dGVzKCkge1xuXG5cdFx0Y29uc3QgbmV3QXR0cmlidXRlcyA9IGN1cnJlbnRTdGF0ZS5uZXdBdHRyaWJ1dGVzO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IG5ld0F0dHJpYnV0ZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdG5ld0F0dHJpYnV0ZXNbIGkgXSA9IDA7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGVuYWJsZUF0dHJpYnV0ZSggYXR0cmlidXRlICkge1xuXG5cdFx0ZW5hYmxlQXR0cmlidXRlQW5kRGl2aXNvciggYXR0cmlidXRlLCAwICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGVuYWJsZUF0dHJpYnV0ZUFuZERpdmlzb3IoIGF0dHJpYnV0ZSwgbWVzaFBlckF0dHJpYnV0ZSApIHtcblxuXHRcdGNvbnN0IG5ld0F0dHJpYnV0ZXMgPSBjdXJyZW50U3RhdGUubmV3QXR0cmlidXRlcztcblx0XHRjb25zdCBlbmFibGVkQXR0cmlidXRlcyA9IGN1cnJlbnRTdGF0ZS5lbmFibGVkQXR0cmlidXRlcztcblx0XHRjb25zdCBhdHRyaWJ1dGVEaXZpc29ycyA9IGN1cnJlbnRTdGF0ZS5hdHRyaWJ1dGVEaXZpc29ycztcblxuXHRcdG5ld0F0dHJpYnV0ZXNbIGF0dHJpYnV0ZSBdID0gMTtcblxuXHRcdGlmICggZW5hYmxlZEF0dHJpYnV0ZXNbIGF0dHJpYnV0ZSBdID09PSAwICkge1xuXG5cdFx0XHRnbC5lbmFibGVWZXJ0ZXhBdHRyaWJBcnJheSggYXR0cmlidXRlICk7XG5cdFx0XHRlbmFibGVkQXR0cmlidXRlc1sgYXR0cmlidXRlIF0gPSAxO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBhdHRyaWJ1dGVEaXZpc29yc1sgYXR0cmlidXRlIF0gIT09IG1lc2hQZXJBdHRyaWJ1dGUgKSB7XG5cblx0XHRcdGdsLnZlcnRleEF0dHJpYkRpdmlzb3IoIGF0dHJpYnV0ZSwgbWVzaFBlckF0dHJpYnV0ZSApO1xuXHRcdFx0YXR0cmlidXRlRGl2aXNvcnNbIGF0dHJpYnV0ZSBdID0gbWVzaFBlckF0dHJpYnV0ZTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gZGlzYWJsZVVudXNlZEF0dHJpYnV0ZXMoKSB7XG5cblx0XHRjb25zdCBuZXdBdHRyaWJ1dGVzID0gY3VycmVudFN0YXRlLm5ld0F0dHJpYnV0ZXM7XG5cdFx0Y29uc3QgZW5hYmxlZEF0dHJpYnV0ZXMgPSBjdXJyZW50U3RhdGUuZW5hYmxlZEF0dHJpYnV0ZXM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gZW5hYmxlZEF0dHJpYnV0ZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdGlmICggZW5hYmxlZEF0dHJpYnV0ZXNbIGkgXSAhPT0gbmV3QXR0cmlidXRlc1sgaSBdICkge1xuXG5cdFx0XHRcdGdsLmRpc2FibGVWZXJ0ZXhBdHRyaWJBcnJheSggaSApO1xuXHRcdFx0XHRlbmFibGVkQXR0cmlidXRlc1sgaSBdID0gMDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB2ZXJ0ZXhBdHRyaWJQb2ludGVyKCBpbmRleCwgc2l6ZSwgdHlwZSwgbm9ybWFsaXplZCwgc3RyaWRlLCBvZmZzZXQsIGludGVnZXIgKSB7XG5cblx0XHRpZiAoIGludGVnZXIgPT09IHRydWUgKSB7XG5cblx0XHRcdGdsLnZlcnRleEF0dHJpYklQb2ludGVyKCBpbmRleCwgc2l6ZSwgdHlwZSwgc3RyaWRlLCBvZmZzZXQgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGdsLnZlcnRleEF0dHJpYlBvaW50ZXIoIGluZGV4LCBzaXplLCB0eXBlLCBub3JtYWxpemVkLCBzdHJpZGUsIG9mZnNldCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBzZXR1cFZlcnRleEF0dHJpYnV0ZXMoIG9iamVjdCwgbWF0ZXJpYWwsIHByb2dyYW0sIGdlb21ldHJ5ICkge1xuXG5cdFx0aW5pdEF0dHJpYnV0ZXMoKTtcblxuXHRcdGNvbnN0IGdlb21ldHJ5QXR0cmlidXRlcyA9IGdlb21ldHJ5LmF0dHJpYnV0ZXM7XG5cblx0XHRjb25zdCBwcm9ncmFtQXR0cmlidXRlcyA9IHByb2dyYW0uZ2V0QXR0cmlidXRlcygpO1xuXG5cdFx0Y29uc3QgbWF0ZXJpYWxEZWZhdWx0QXR0cmlidXRlVmFsdWVzID0gbWF0ZXJpYWwuZGVmYXVsdEF0dHJpYnV0ZVZhbHVlcztcblxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gcHJvZ3JhbUF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdGNvbnN0IHByb2dyYW1BdHRyaWJ1dGUgPSBwcm9ncmFtQXR0cmlidXRlc1sgbmFtZSBdO1xuXG5cdFx0XHRpZiAoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gPj0gMCApIHtcblxuXHRcdFx0XHRsZXQgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBnZW9tZXRyeUF0dHJpYnV0ZXNbIG5hbWUgXTtcblxuXHRcdFx0XHRpZiAoIGdlb21ldHJ5QXR0cmlidXRlID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRpZiAoIG5hbWUgPT09ICdpbnN0YW5jZU1hdHJpeCcgJiYgb2JqZWN0Lmluc3RhbmNlTWF0cml4ICkgZ2VvbWV0cnlBdHRyaWJ1dGUgPSBvYmplY3QuaW5zdGFuY2VNYXRyaXg7XG5cdFx0XHRcdFx0aWYgKCBuYW1lID09PSAnaW5zdGFuY2VDb2xvcicgJiYgb2JqZWN0Lmluc3RhbmNlQ29sb3IgKSBnZW9tZXRyeUF0dHJpYnV0ZSA9IG9iamVjdC5pbnN0YW5jZUNvbG9yO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIGdlb21ldHJ5QXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBub3JtYWxpemVkID0gZ2VvbWV0cnlBdHRyaWJ1dGUubm9ybWFsaXplZDtcblx0XHRcdFx0XHRjb25zdCBzaXplID0gZ2VvbWV0cnlBdHRyaWJ1dGUuaXRlbVNpemU7XG5cblx0XHRcdFx0XHRjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVzLmdldCggZ2VvbWV0cnlBdHRyaWJ1dGUgKTtcblxuXHRcdFx0XHRcdC8vIFRPRE8gQXR0cmlidXRlIG1heSBub3QgYmUgYXZhaWxhYmxlIG9uIGNvbnRleHQgcmVzdG9yZVxuXG5cdFx0XHRcdFx0aWYgKCBhdHRyaWJ1dGUgPT09IHVuZGVmaW5lZCApIGNvbnRpbnVlO1xuXG5cdFx0XHRcdFx0Y29uc3QgYnVmZmVyID0gYXR0cmlidXRlLmJ1ZmZlcjtcblx0XHRcdFx0XHRjb25zdCB0eXBlID0gYXR0cmlidXRlLnR5cGU7XG5cdFx0XHRcdFx0Y29uc3QgYnl0ZXNQZXJFbGVtZW50ID0gYXR0cmlidXRlLmJ5dGVzUGVyRWxlbWVudDtcblxuXHRcdFx0XHRcdC8vIGNoZWNrIGZvciBpbnRlZ2VyIGF0dHJpYnV0ZXNcblxuXHRcdFx0XHRcdGNvbnN0IGludGVnZXIgPSAoIHR5cGUgPT09IGdsLklOVCB8fCB0eXBlID09PSBnbC5VTlNJR05FRF9JTlQgfHwgZ2VvbWV0cnlBdHRyaWJ1dGUuZ3B1VHlwZSA9PT0gSW50VHlwZSApO1xuXG5cdFx0XHRcdFx0aWYgKCBnZW9tZXRyeUF0dHJpYnV0ZS5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBkYXRhID0gZ2VvbWV0cnlBdHRyaWJ1dGUuZGF0YTtcblx0XHRcdFx0XHRcdGNvbnN0IHN0cmlkZSA9IGRhdGEuc3RyaWRlO1xuXHRcdFx0XHRcdFx0Y29uc3Qgb2Zmc2V0ID0gZ2VvbWV0cnlBdHRyaWJ1dGUub2Zmc2V0O1xuXG5cdFx0XHRcdFx0XHRpZiAoIGRhdGEuaXNJbnN0YW5jZWRJbnRlcmxlYXZlZEJ1ZmZlciApIHtcblxuXHRcdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGVuYWJsZUF0dHJpYnV0ZUFuZERpdmlzb3IoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gKyBpLCBkYXRhLm1lc2hQZXJBdHRyaWJ1dGUgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBvYmplY3QuaXNJbnN0YW5jZWRNZXNoICE9PSB0cnVlICYmIGdlb21ldHJ5Ll9tYXhJbnN0YW5jZUNvdW50ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudCA9IGRhdGEubWVzaFBlckF0dHJpYnV0ZSAqIGRhdGEuY291bnQ7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb25TaXplOyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0ZW5hYmxlQXR0cmlidXRlKCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uICsgaSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRnbC5iaW5kQnVmZmVyKCBnbC5BUlJBWV9CVUZGRVIsIGJ1ZmZlciApO1xuXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0XHR2ZXJ0ZXhBdHRyaWJQb2ludGVyKFxuXHRcdFx0XHRcdFx0XHRcdHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24gKyBpLFxuXHRcdFx0XHRcdFx0XHRcdHNpemUgLyBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZSxcblx0XHRcdFx0XHRcdFx0XHR0eXBlLFxuXHRcdFx0XHRcdFx0XHRcdG5vcm1hbGl6ZWQsXG5cdFx0XHRcdFx0XHRcdFx0c3RyaWRlICogYnl0ZXNQZXJFbGVtZW50LFxuXHRcdFx0XHRcdFx0XHRcdCggb2Zmc2V0ICsgKCBzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUgKSAqIGkgKSAqIGJ5dGVzUGVyRWxlbWVudCxcblx0XHRcdFx0XHRcdFx0XHRpbnRlZ2VyXG5cdFx0XHRcdFx0XHRcdCk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGlmICggZ2VvbWV0cnlBdHRyaWJ1dGUuaXNJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUgKSB7XG5cblx0XHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemU7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRlbmFibGVBdHRyaWJ1dGVBbmREaXZpc29yKCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uICsgaSwgZ2VvbWV0cnlBdHRyaWJ1dGUubWVzaFBlckF0dHJpYnV0ZSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggIT09IHRydWUgJiYgZ2VvbWV0cnkuX21heEluc3RhbmNlQ291bnQgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGdlb21ldHJ5Ll9tYXhJbnN0YW5jZUNvdW50ID0gZ2VvbWV0cnlBdHRyaWJ1dGUubWVzaFBlckF0dHJpYnV0ZSAqIGdlb21ldHJ5QXR0cmlidXRlLmNvdW50O1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uU2l6ZTsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGVuYWJsZUF0dHJpYnV0ZSggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiArIGkgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0Z2wuYmluZEJ1ZmZlciggZ2wuQVJSQVlfQlVGRkVSLCBidWZmZXIgKTtcblxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemU7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdFx0dmVydGV4QXR0cmliUG9pbnRlcihcblx0XHRcdFx0XHRcdFx0XHRwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uICsgaSxcblx0XHRcdFx0XHRcdFx0XHRzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUsXG5cdFx0XHRcdFx0XHRcdFx0dHlwZSxcblx0XHRcdFx0XHRcdFx0XHRub3JtYWxpemVkLFxuXHRcdFx0XHRcdFx0XHRcdHNpemUgKiBieXRlc1BlckVsZW1lbnQsXG5cdFx0XHRcdFx0XHRcdFx0KCBzaXplIC8gcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvblNpemUgKSAqIGkgKiBieXRlc1BlckVsZW1lbnQsXG5cdFx0XHRcdFx0XHRcdFx0aW50ZWdlclxuXHRcdFx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxEZWZhdWx0QXR0cmlidXRlVmFsdWVzICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB2YWx1ZSA9IG1hdGVyaWFsRGVmYXVsdEF0dHJpYnV0ZVZhbHVlc1sgbmFtZSBdO1xuXG5cdFx0XHRcdFx0aWYgKCB2YWx1ZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRzd2l0Y2ggKCB2YWx1ZS5sZW5ndGggKSB7XG5cblx0XHRcdFx0XHRcdFx0Y2FzZSAyOlxuXHRcdFx0XHRcdFx0XHRcdGdsLnZlcnRleEF0dHJpYjJmdiggcHJvZ3JhbUF0dHJpYnV0ZS5sb2NhdGlvbiwgdmFsdWUgKTtcblx0XHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0XHRjYXNlIDM6XG5cdFx0XHRcdFx0XHRcdFx0Z2wudmVydGV4QXR0cmliM2Z2KCBwcm9ncmFtQXR0cmlidXRlLmxvY2F0aW9uLCB2YWx1ZSApO1xuXHRcdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRcdGNhc2UgNDpcblx0XHRcdFx0XHRcdFx0XHRnbC52ZXJ0ZXhBdHRyaWI0ZnYoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24sIHZhbHVlICk7XG5cdFx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0XHRcdFx0XHRnbC52ZXJ0ZXhBdHRyaWIxZnYoIHByb2dyYW1BdHRyaWJ1dGUubG9jYXRpb24sIHZhbHVlICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGRpc2FibGVVbnVzZWRBdHRyaWJ1dGVzKCk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG5cblx0XHRyZXNldCgpO1xuXG5cdFx0Zm9yICggY29uc3QgZ2VvbWV0cnlJZCBpbiBiaW5kaW5nU3RhdGVzICkge1xuXG5cdFx0XHRjb25zdCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnlJZCBdO1xuXG5cdFx0XHRmb3IgKCBjb25zdCBwcm9ncmFtSWQgaW4gcHJvZ3JhbU1hcCApIHtcblxuXHRcdFx0XHRjb25zdCBzdGF0ZU1hcCA9IHByb2dyYW1NYXBbIHByb2dyYW1JZCBdO1xuXG5cdFx0XHRcdGZvciAoIGNvbnN0IHdpcmVmcmFtZSBpbiBzdGF0ZU1hcCApIHtcblxuXHRcdFx0XHRcdGRlbGV0ZVZlcnRleEFycmF5T2JqZWN0KCBzdGF0ZU1hcFsgd2lyZWZyYW1lIF0ub2JqZWN0ICk7XG5cblx0XHRcdFx0XHRkZWxldGUgc3RhdGVNYXBbIHdpcmVmcmFtZSBdO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRkZWxldGUgcHJvZ3JhbU1hcFsgcHJvZ3JhbUlkIF07XG5cblx0XHRcdH1cblxuXHRcdFx0ZGVsZXRlIGJpbmRpbmdTdGF0ZXNbIGdlb21ldHJ5SWQgXTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVsZWFzZVN0YXRlc09mR2VvbWV0cnkoIGdlb21ldHJ5ICkge1xuXG5cdFx0aWYgKCBiaW5kaW5nU3RhdGVzWyBnZW9tZXRyeS5pZCBdID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHRjb25zdCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnkuaWQgXTtcblxuXHRcdGZvciAoIGNvbnN0IHByb2dyYW1JZCBpbiBwcm9ncmFtTWFwICkge1xuXG5cdFx0XHRjb25zdCBzdGF0ZU1hcCA9IHByb2dyYW1NYXBbIHByb2dyYW1JZCBdO1xuXG5cdFx0XHRmb3IgKCBjb25zdCB3aXJlZnJhbWUgaW4gc3RhdGVNYXAgKSB7XG5cblx0XHRcdFx0ZGVsZXRlVmVydGV4QXJyYXlPYmplY3QoIHN0YXRlTWFwWyB3aXJlZnJhbWUgXS5vYmplY3QgKTtcblxuXHRcdFx0XHRkZWxldGUgc3RhdGVNYXBbIHdpcmVmcmFtZSBdO1xuXG5cdFx0XHR9XG5cblx0XHRcdGRlbGV0ZSBwcm9ncmFtTWFwWyBwcm9ncmFtSWQgXTtcblxuXHRcdH1cblxuXHRcdGRlbGV0ZSBiaW5kaW5nU3RhdGVzWyBnZW9tZXRyeS5pZCBdO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZWxlYXNlU3RhdGVzT2ZQcm9ncmFtKCBwcm9ncmFtICkge1xuXG5cdFx0Zm9yICggY29uc3QgZ2VvbWV0cnlJZCBpbiBiaW5kaW5nU3RhdGVzICkge1xuXG5cdFx0XHRjb25zdCBwcm9ncmFtTWFwID0gYmluZGluZ1N0YXRlc1sgZ2VvbWV0cnlJZCBdO1xuXG5cdFx0XHRpZiAoIHByb2dyYW1NYXBbIHByb2dyYW0uaWQgXSA9PT0gdW5kZWZpbmVkICkgY29udGludWU7XG5cblx0XHRcdGNvbnN0IHN0YXRlTWFwID0gcHJvZ3JhbU1hcFsgcHJvZ3JhbS5pZCBdO1xuXG5cdFx0XHRmb3IgKCBjb25zdCB3aXJlZnJhbWUgaW4gc3RhdGVNYXAgKSB7XG5cblx0XHRcdFx0ZGVsZXRlVmVydGV4QXJyYXlPYmplY3QoIHN0YXRlTWFwWyB3aXJlZnJhbWUgXS5vYmplY3QgKTtcblxuXHRcdFx0XHRkZWxldGUgc3RhdGVNYXBbIHdpcmVmcmFtZSBdO1xuXG5cdFx0XHR9XG5cblx0XHRcdGRlbGV0ZSBwcm9ncmFtTWFwWyBwcm9ncmFtLmlkIF07XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlc2V0KCkge1xuXG5cdFx0cmVzZXREZWZhdWx0U3RhdGUoKTtcblx0XHRmb3JjZVVwZGF0ZSA9IHRydWU7XG5cblx0XHRpZiAoIGN1cnJlbnRTdGF0ZSA9PT0gZGVmYXVsdFN0YXRlICkgcmV0dXJuO1xuXG5cdFx0Y3VycmVudFN0YXRlID0gZGVmYXVsdFN0YXRlO1xuXHRcdGJpbmRWZXJ0ZXhBcnJheU9iamVjdCggY3VycmVudFN0YXRlLm9iamVjdCApO1xuXG5cdH1cblxuXHQvLyBmb3IgYmFja3dhcmQtY29tcGF0aWJpbGl0eVxuXG5cdGZ1bmN0aW9uIHJlc2V0RGVmYXVsdFN0YXRlKCkge1xuXG5cdFx0ZGVmYXVsdFN0YXRlLmdlb21ldHJ5ID0gbnVsbDtcblx0XHRkZWZhdWx0U3RhdGUucHJvZ3JhbSA9IG51bGw7XG5cdFx0ZGVmYXVsdFN0YXRlLndpcmVmcmFtZSA9IGZhbHNlO1xuXG5cdH1cblxuXHRyZXR1cm4ge1xuXG5cdFx0c2V0dXA6IHNldHVwLFxuXHRcdHJlc2V0OiByZXNldCxcblx0XHRyZXNldERlZmF1bHRTdGF0ZTogcmVzZXREZWZhdWx0U3RhdGUsXG5cdFx0ZGlzcG9zZTogZGlzcG9zZSxcblx0XHRyZWxlYXNlU3RhdGVzT2ZHZW9tZXRyeTogcmVsZWFzZVN0YXRlc09mR2VvbWV0cnksXG5cdFx0cmVsZWFzZVN0YXRlc09mUHJvZ3JhbTogcmVsZWFzZVN0YXRlc09mUHJvZ3JhbSxcblxuXHRcdGluaXRBdHRyaWJ1dGVzOiBpbml0QXR0cmlidXRlcyxcblx0XHRlbmFibGVBdHRyaWJ1dGU6IGVuYWJsZUF0dHJpYnV0ZSxcblx0XHRkaXNhYmxlVW51c2VkQXR0cmlidXRlczogZGlzYWJsZVVudXNlZEF0dHJpYnV0ZXNcblxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMQnVmZmVyUmVuZGVyZXIoIGdsLCBleHRlbnNpb25zLCBpbmZvICkge1xuXG5cdGxldCBtb2RlO1xuXG5cdGZ1bmN0aW9uIHNldE1vZGUoIHZhbHVlICkge1xuXG5cdFx0bW9kZSA9IHZhbHVlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXIoIHN0YXJ0LCBjb3VudCApIHtcblxuXHRcdGdsLmRyYXdBcnJheXMoIG1vZGUsIHN0YXJ0LCBjb3VudCApO1xuXG5cdFx0aW5mby51cGRhdGUoIGNvdW50LCBtb2RlLCAxICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlbmRlckluc3RhbmNlcyggc3RhcnQsIGNvdW50LCBwcmltY291bnQgKSB7XG5cblx0XHRpZiAoIHByaW1jb3VudCA9PT0gMCApIHJldHVybjtcblxuXHRcdGdsLmRyYXdBcnJheXNJbnN0YW5jZWQoIG1vZGUsIHN0YXJ0LCBjb3VudCwgcHJpbWNvdW50ICk7XG5cblx0XHRpbmZvLnVwZGF0ZSggY291bnQsIG1vZGUsIHByaW1jb3VudCApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXJNdWx0aURyYXcoIHN0YXJ0cywgY291bnRzLCBkcmF3Q291bnQgKSB7XG5cblx0XHRpZiAoIGRyYXdDb3VudCA9PT0gMCApIHJldHVybjtcblxuXHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbXVsdGlfZHJhdycgKTtcblx0XHRleHRlbnNpb24ubXVsdGlEcmF3QXJyYXlzV0VCR0woIG1vZGUsIHN0YXJ0cywgMCwgY291bnRzLCAwLCBkcmF3Q291bnQgKTtcblxuXHRcdGxldCBlbGVtZW50Q291bnQgPSAwO1xuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGRyYXdDb3VudDsgaSArKyApIHtcblxuXHRcdFx0ZWxlbWVudENvdW50ICs9IGNvdW50c1sgaSBdO1xuXG5cdFx0fVxuXG5cdFx0aW5mby51cGRhdGUoIGVsZW1lbnRDb3VudCwgbW9kZSwgMSApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXJNdWx0aURyYXdJbnN0YW5jZXMoIHN0YXJ0cywgY291bnRzLCBkcmF3Q291bnQsIHByaW1jb3VudCApIHtcblxuXHRcdGlmICggZHJhd0NvdW50ID09PSAwICkgcmV0dXJuO1xuXG5cdFx0Y29uc3QgZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9tdWx0aV9kcmF3JyApO1xuXG5cdFx0aWYgKCBleHRlbnNpb24gPT09IG51bGwgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHN0YXJ0cy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0cmVuZGVySW5zdGFuY2VzKCBzdGFydHNbIGkgXSwgY291bnRzWyBpIF0sIHByaW1jb3VudFsgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGV4dGVuc2lvbi5tdWx0aURyYXdBcnJheXNJbnN0YW5jZWRXRUJHTCggbW9kZSwgc3RhcnRzLCAwLCBjb3VudHMsIDAsIHByaW1jb3VudCwgMCwgZHJhd0NvdW50ICk7XG5cblx0XHRcdGxldCBlbGVtZW50Q291bnQgPSAwO1xuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZHJhd0NvdW50OyBpICsrICkge1xuXG5cdFx0XHRcdGVsZW1lbnRDb3VudCArPSBjb3VudHNbIGkgXTtcblxuXHRcdFx0fVxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcmltY291bnQubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGluZm8udXBkYXRlKCBlbGVtZW50Q291bnQsIG1vZGUsIHByaW1jb3VudFsgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0Ly9cblxuXHR0aGlzLnNldE1vZGUgPSBzZXRNb2RlO1xuXHR0aGlzLnJlbmRlciA9IHJlbmRlcjtcblx0dGhpcy5yZW5kZXJJbnN0YW5jZXMgPSByZW5kZXJJbnN0YW5jZXM7XG5cdHRoaXMucmVuZGVyTXVsdGlEcmF3ID0gcmVuZGVyTXVsdGlEcmF3O1xuXHR0aGlzLnJlbmRlck11bHRpRHJhd0luc3RhbmNlcyA9IHJlbmRlck11bHRpRHJhd0luc3RhbmNlcztcblxufVxuXG5mdW5jdGlvbiBXZWJHTENhcGFiaWxpdGllcyggZ2wsIGV4dGVuc2lvbnMsIHBhcmFtZXRlcnMsIHV0aWxzICkge1xuXG5cdGxldCBtYXhBbmlzb3Ryb3B5O1xuXG5cdGZ1bmN0aW9uIGdldE1heEFuaXNvdHJvcHkoKSB7XG5cblx0XHRpZiAoIG1heEFuaXNvdHJvcHkgIT09IHVuZGVmaW5lZCApIHJldHVybiBtYXhBbmlzb3Ryb3B5O1xuXG5cdFx0aWYgKCBleHRlbnNpb25zLmhhcyggJ0VYVF90ZXh0dXJlX2ZpbHRlcl9hbmlzb3Ryb3BpYycgKSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0Y29uc3QgZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfdGV4dHVyZV9maWx0ZXJfYW5pc290cm9waWMnICk7XG5cblx0XHRcdG1heEFuaXNvdHJvcHkgPSBnbC5nZXRQYXJhbWV0ZXIoIGV4dGVuc2lvbi5NQVhfVEVYVFVSRV9NQVhfQU5JU09UUk9QWV9FWFQgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdG1heEFuaXNvdHJvcHkgPSAwO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG1heEFuaXNvdHJvcHk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHRleHR1cmVGb3JtYXRSZWFkYWJsZSggdGV4dHVyZUZvcm1hdCApIHtcblxuXHRcdGlmICggdGV4dHVyZUZvcm1hdCAhPT0gUkdCQUZvcm1hdCAmJiB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlRm9ybWF0ICkgIT09IGdsLmdldFBhcmFtZXRlciggZ2wuSU1QTEVNRU5UQVRJT05fQ09MT1JfUkVBRF9GT1JNQVQgKSApIHtcblxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHRleHR1cmVUeXBlUmVhZGFibGUoIHRleHR1cmVUeXBlICkge1xuXG5cdFx0Y29uc3QgaGFsZkZsb2F0U3VwcG9ydGVkQnlFeHQgPSAoIHRleHR1cmVUeXBlID09PSBIYWxmRmxvYXRUeXBlICkgJiYgKCBleHRlbnNpb25zLmhhcyggJ0VYVF9jb2xvcl9idWZmZXJfaGFsZl9mbG9hdCcgKSB8fCBleHRlbnNpb25zLmhhcyggJ0VYVF9jb2xvcl9idWZmZXJfZmxvYXQnICkgKTtcblxuXHRcdGlmICggdGV4dHVyZVR5cGUgIT09IFVuc2lnbmVkQnl0ZVR5cGUgJiYgdXRpbHMuY29udmVydCggdGV4dHVyZVR5cGUgKSAhPT0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5JTVBMRU1FTlRBVElPTl9DT0xPUl9SRUFEX1RZUEUgKSAmJiAvLyBFZGdlIGFuZCBDaHJvbWUgTWFjIDwgNTIgKCM5NTEzKVxuXHRcdFx0dGV4dHVyZVR5cGUgIT09IEZsb2F0VHlwZSAmJiAhIGhhbGZGbG9hdFN1cHBvcnRlZEJ5RXh0ICkge1xuXG5cdFx0XHRyZXR1cm4gZmFsc2U7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0TWF4UHJlY2lzaW9uKCBwcmVjaXNpb24gKSB7XG5cblx0XHRpZiAoIHByZWNpc2lvbiA9PT0gJ2hpZ2hwJyApIHtcblxuXHRcdFx0aWYgKCBnbC5nZXRTaGFkZXJQcmVjaXNpb25Gb3JtYXQoIGdsLlZFUlRFWF9TSEFERVIsIGdsLkhJR0hfRkxPQVQgKS5wcmVjaXNpb24gPiAwICYmXG5cdFx0XHRcdGdsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCggZ2wuRlJBR01FTlRfU0hBREVSLCBnbC5ISUdIX0ZMT0FUICkucHJlY2lzaW9uID4gMCApIHtcblxuXHRcdFx0XHRyZXR1cm4gJ2hpZ2hwJztcblxuXHRcdFx0fVxuXG5cdFx0XHRwcmVjaXNpb24gPSAnbWVkaXVtcCc7XG5cblx0XHR9XG5cblx0XHRpZiAoIHByZWNpc2lvbiA9PT0gJ21lZGl1bXAnICkge1xuXG5cdFx0XHRpZiAoIGdsLmdldFNoYWRlclByZWNpc2lvbkZvcm1hdCggZ2wuVkVSVEVYX1NIQURFUiwgZ2wuTUVESVVNX0ZMT0FUICkucHJlY2lzaW9uID4gMCAmJlxuXHRcdFx0XHRnbC5nZXRTaGFkZXJQcmVjaXNpb25Gb3JtYXQoIGdsLkZSQUdNRU5UX1NIQURFUiwgZ2wuTUVESVVNX0ZMT0FUICkucHJlY2lzaW9uID4gMCApIHtcblxuXHRcdFx0XHRyZXR1cm4gJ21lZGl1bXAnO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gJ2xvd3AnO1xuXG5cdH1cblxuXHRsZXQgcHJlY2lzaW9uID0gcGFyYW1ldGVycy5wcmVjaXNpb24gIT09IHVuZGVmaW5lZCA/IHBhcmFtZXRlcnMucHJlY2lzaW9uIDogJ2hpZ2hwJztcblx0Y29uc3QgbWF4UHJlY2lzaW9uID0gZ2V0TWF4UHJlY2lzaW9uKCBwcmVjaXNpb24gKTtcblxuXHRpZiAoIG1heFByZWNpc2lvbiAhPT0gcHJlY2lzaW9uICkge1xuXG5cdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjonLCBwcmVjaXNpb24sICdub3Qgc3VwcG9ydGVkLCB1c2luZycsIG1heFByZWNpc2lvbiwgJ2luc3RlYWQuJyApO1xuXHRcdHByZWNpc2lvbiA9IG1heFByZWNpc2lvbjtcblxuXHR9XG5cblx0Y29uc3QgbG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA9IHBhcmFtZXRlcnMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA9PT0gdHJ1ZTtcblxuXHRjb25zdCBtYXhUZXh0dXJlcyA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1RFWFRVUkVfSU1BR0VfVU5JVFMgKTtcblx0Y29uc3QgbWF4VmVydGV4VGV4dHVyZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WRVJURVhfVEVYVFVSRV9JTUFHRV9VTklUUyApO1xuXHRjb25zdCBtYXhUZXh0dXJlU2l6ZSA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1RFWFRVUkVfU0laRSApO1xuXHRjb25zdCBtYXhDdWJlbWFwU2l6ZSA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX0NVQkVfTUFQX1RFWFRVUkVfU0laRSApO1xuXG5cdGNvbnN0IG1heEF0dHJpYnV0ZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WRVJURVhfQVRUUklCUyApO1xuXHRjb25zdCBtYXhWZXJ0ZXhVbmlmb3JtcyA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX1ZFUlRFWF9VTklGT1JNX1ZFQ1RPUlMgKTtcblx0Y29uc3QgbWF4VmFyeWluZ3MgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9WQVJZSU5HX1ZFQ1RPUlMgKTtcblx0Y29uc3QgbWF4RnJhZ21lbnRVbmlmb3JtcyA9IGdsLmdldFBhcmFtZXRlciggZ2wuTUFYX0ZSQUdNRU5UX1VOSUZPUk1fVkVDVE9SUyApO1xuXG5cdGNvbnN0IHZlcnRleFRleHR1cmVzID0gbWF4VmVydGV4VGV4dHVyZXMgPiAwO1xuXG5cdGNvbnN0IG1heFNhbXBsZXMgPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLk1BWF9TQU1QTEVTICk7XG5cblx0cmV0dXJuIHtcblxuXHRcdGlzV2ViR0wyOiB0cnVlLCAvLyBrZWVwaW5nIHRoaXMgZm9yIGJhY2t3YXJkcyBjb21wYXRpYmlsaXR5XG5cblx0XHRnZXRNYXhBbmlzb3Ryb3B5OiBnZXRNYXhBbmlzb3Ryb3B5LFxuXHRcdGdldE1heFByZWNpc2lvbjogZ2V0TWF4UHJlY2lzaW9uLFxuXG5cdFx0dGV4dHVyZUZvcm1hdFJlYWRhYmxlOiB0ZXh0dXJlRm9ybWF0UmVhZGFibGUsXG5cdFx0dGV4dHVyZVR5cGVSZWFkYWJsZTogdGV4dHVyZVR5cGVSZWFkYWJsZSxcblxuXHRcdHByZWNpc2lvbjogcHJlY2lzaW9uLFxuXHRcdGxvZ2FyaXRobWljRGVwdGhCdWZmZXI6IGxvZ2FyaXRobWljRGVwdGhCdWZmZXIsXG5cblx0XHRtYXhUZXh0dXJlczogbWF4VGV4dHVyZXMsXG5cdFx0bWF4VmVydGV4VGV4dHVyZXM6IG1heFZlcnRleFRleHR1cmVzLFxuXHRcdG1heFRleHR1cmVTaXplOiBtYXhUZXh0dXJlU2l6ZSxcblx0XHRtYXhDdWJlbWFwU2l6ZTogbWF4Q3ViZW1hcFNpemUsXG5cblx0XHRtYXhBdHRyaWJ1dGVzOiBtYXhBdHRyaWJ1dGVzLFxuXHRcdG1heFZlcnRleFVuaWZvcm1zOiBtYXhWZXJ0ZXhVbmlmb3Jtcyxcblx0XHRtYXhWYXJ5aW5nczogbWF4VmFyeWluZ3MsXG5cdFx0bWF4RnJhZ21lbnRVbmlmb3JtczogbWF4RnJhZ21lbnRVbmlmb3JtcyxcblxuXHRcdHZlcnRleFRleHR1cmVzOiB2ZXJ0ZXhUZXh0dXJlcyxcblxuXHRcdG1heFNhbXBsZXM6IG1heFNhbXBsZXNcblxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMQ2xpcHBpbmcoIHByb3BlcnRpZXMgKSB7XG5cblx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdGxldCBnbG9iYWxTdGF0ZSA9IG51bGwsXG5cdFx0bnVtR2xvYmFsUGxhbmVzID0gMCxcblx0XHRsb2NhbENsaXBwaW5nRW5hYmxlZCA9IGZhbHNlLFxuXHRcdHJlbmRlcmluZ1NoYWRvd3MgPSBmYWxzZTtcblxuXHRjb25zdCBwbGFuZSA9IG5ldyBQbGFuZSgpLFxuXHRcdHZpZXdOb3JtYWxNYXRyaXggPSBuZXcgTWF0cml4MygpLFxuXG5cdFx0dW5pZm9ybSA9IHsgdmFsdWU6IG51bGwsIG5lZWRzVXBkYXRlOiBmYWxzZSB9O1xuXG5cdHRoaXMudW5pZm9ybSA9IHVuaWZvcm07XG5cdHRoaXMubnVtUGxhbmVzID0gMDtcblx0dGhpcy5udW1JbnRlcnNlY3Rpb24gPSAwO1xuXG5cdHRoaXMuaW5pdCA9IGZ1bmN0aW9uICggcGxhbmVzLCBlbmFibGVMb2NhbENsaXBwaW5nICkge1xuXG5cdFx0Y29uc3QgZW5hYmxlZCA9XG5cdFx0XHRwbGFuZXMubGVuZ3RoICE9PSAwIHx8XG5cdFx0XHRlbmFibGVMb2NhbENsaXBwaW5nIHx8XG5cdFx0XHQvLyBlbmFibGUgc3RhdGUgb2YgcHJldmlvdXMgZnJhbWUgLSB0aGUgY2xpcHBpbmcgY29kZSBoYXMgdG9cblx0XHRcdC8vIHJ1biBhbm90aGVyIGZyYW1lIGluIG9yZGVyIHRvIHJlc2V0IHRoZSBzdGF0ZTpcblx0XHRcdG51bUdsb2JhbFBsYW5lcyAhPT0gMCB8fFxuXHRcdFx0bG9jYWxDbGlwcGluZ0VuYWJsZWQ7XG5cblx0XHRsb2NhbENsaXBwaW5nRW5hYmxlZCA9IGVuYWJsZUxvY2FsQ2xpcHBpbmc7XG5cblx0XHRudW1HbG9iYWxQbGFuZXMgPSBwbGFuZXMubGVuZ3RoO1xuXG5cdFx0cmV0dXJuIGVuYWJsZWQ7XG5cblx0fTtcblxuXHR0aGlzLmJlZ2luU2hhZG93cyA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdHJlbmRlcmluZ1NoYWRvd3MgPSB0cnVlO1xuXHRcdHByb2plY3RQbGFuZXMoIG51bGwgKTtcblxuXHR9O1xuXG5cdHRoaXMuZW5kU2hhZG93cyA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdHJlbmRlcmluZ1NoYWRvd3MgPSBmYWxzZTtcblxuXHR9O1xuXG5cdHRoaXMuc2V0R2xvYmFsU3RhdGUgPSBmdW5jdGlvbiAoIHBsYW5lcywgY2FtZXJhICkge1xuXG5cdFx0Z2xvYmFsU3RhdGUgPSBwcm9qZWN0UGxhbmVzKCBwbGFuZXMsIGNhbWVyYSwgMCApO1xuXG5cdH07XG5cblx0dGhpcy5zZXRTdGF0ZSA9IGZ1bmN0aW9uICggbWF0ZXJpYWwsIGNhbWVyYSwgdXNlQ2FjaGUgKSB7XG5cblx0XHRjb25zdCBwbGFuZXMgPSBtYXRlcmlhbC5jbGlwcGluZ1BsYW5lcyxcblx0XHRcdGNsaXBJbnRlcnNlY3Rpb24gPSBtYXRlcmlhbC5jbGlwSW50ZXJzZWN0aW9uLFxuXHRcdFx0Y2xpcFNoYWRvd3MgPSBtYXRlcmlhbC5jbGlwU2hhZG93cztcblxuXHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xuXG5cdFx0aWYgKCAhIGxvY2FsQ2xpcHBpbmdFbmFibGVkIHx8IHBsYW5lcyA9PT0gbnVsbCB8fCBwbGFuZXMubGVuZ3RoID09PSAwIHx8IHJlbmRlcmluZ1NoYWRvd3MgJiYgISBjbGlwU2hhZG93cyApIHtcblxuXHRcdFx0Ly8gdGhlcmUncyBubyBsb2NhbCBjbGlwcGluZ1xuXG5cdFx0XHRpZiAoIHJlbmRlcmluZ1NoYWRvd3MgKSB7XG5cblx0XHRcdFx0Ly8gdGhlcmUncyBubyBnbG9iYWwgY2xpcHBpbmdcblxuXHRcdFx0XHRwcm9qZWN0UGxhbmVzKCBudWxsICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0cmVzZXRHbG9iYWxTdGF0ZSgpO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zdCBuR2xvYmFsID0gcmVuZGVyaW5nU2hhZG93cyA/IDAgOiBudW1HbG9iYWxQbGFuZXMsXG5cdFx0XHRcdGxHbG9iYWwgPSBuR2xvYmFsICogNDtcblxuXHRcdFx0bGV0IGRzdEFycmF5ID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLmNsaXBwaW5nU3RhdGUgfHwgbnVsbDtcblxuXHRcdFx0dW5pZm9ybS52YWx1ZSA9IGRzdEFycmF5OyAvLyBlbnN1cmUgdW5pcXVlIHN0YXRlXG5cblx0XHRcdGRzdEFycmF5ID0gcHJvamVjdFBsYW5lcyggcGxhbmVzLCBjYW1lcmEsIGxHbG9iYWwsIHVzZUNhY2hlICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbEdsb2JhbDsgKysgaSApIHtcblxuXHRcdFx0XHRkc3RBcnJheVsgaSBdID0gZ2xvYmFsU3RhdGVbIGkgXTtcblxuXHRcdFx0fVxuXG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMuY2xpcHBpbmdTdGF0ZSA9IGRzdEFycmF5O1xuXHRcdFx0dGhpcy5udW1JbnRlcnNlY3Rpb24gPSBjbGlwSW50ZXJzZWN0aW9uID8gdGhpcy5udW1QbGFuZXMgOiAwO1xuXHRcdFx0dGhpcy5udW1QbGFuZXMgKz0gbkdsb2JhbDtcblxuXHRcdH1cblxuXG5cdH07XG5cblx0ZnVuY3Rpb24gcmVzZXRHbG9iYWxTdGF0ZSgpIHtcblxuXHRcdGlmICggdW5pZm9ybS52YWx1ZSAhPT0gZ2xvYmFsU3RhdGUgKSB7XG5cblx0XHRcdHVuaWZvcm0udmFsdWUgPSBnbG9iYWxTdGF0ZTtcblx0XHRcdHVuaWZvcm0ubmVlZHNVcGRhdGUgPSBudW1HbG9iYWxQbGFuZXMgPiAwO1xuXG5cdFx0fVxuXG5cdFx0c2NvcGUubnVtUGxhbmVzID0gbnVtR2xvYmFsUGxhbmVzO1xuXHRcdHNjb3BlLm51bUludGVyc2VjdGlvbiA9IDA7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHByb2plY3RQbGFuZXMoIHBsYW5lcywgY2FtZXJhLCBkc3RPZmZzZXQsIHNraXBUcmFuc2Zvcm0gKSB7XG5cblx0XHRjb25zdCBuUGxhbmVzID0gcGxhbmVzICE9PSBudWxsID8gcGxhbmVzLmxlbmd0aCA6IDA7XG5cdFx0bGV0IGRzdEFycmF5ID0gbnVsbDtcblxuXHRcdGlmICggblBsYW5lcyAhPT0gMCApIHtcblxuXHRcdFx0ZHN0QXJyYXkgPSB1bmlmb3JtLnZhbHVlO1xuXG5cdFx0XHRpZiAoIHNraXBUcmFuc2Zvcm0gIT09IHRydWUgfHwgZHN0QXJyYXkgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0Y29uc3QgZmxhdFNpemUgPSBkc3RPZmZzZXQgKyBuUGxhbmVzICogNCxcblx0XHRcdFx0XHR2aWV3TWF0cml4ID0gY2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZTtcblxuXHRcdFx0XHR2aWV3Tm9ybWFsTWF0cml4LmdldE5vcm1hbE1hdHJpeCggdmlld01hdHJpeCApO1xuXG5cdFx0XHRcdGlmICggZHN0QXJyYXkgPT09IG51bGwgfHwgZHN0QXJyYXkubGVuZ3RoIDwgZmxhdFNpemUgKSB7XG5cblx0XHRcdFx0XHRkc3RBcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoIGZsYXRTaXplICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaTQgPSBkc3RPZmZzZXQ7IGkgIT09IG5QbGFuZXM7ICsrIGksIGk0ICs9IDQgKSB7XG5cblx0XHRcdFx0XHRwbGFuZS5jb3B5KCBwbGFuZXNbIGkgXSApLmFwcGx5TWF0cml4NCggdmlld01hdHJpeCwgdmlld05vcm1hbE1hdHJpeCApO1xuXG5cdFx0XHRcdFx0cGxhbmUubm9ybWFsLnRvQXJyYXkoIGRzdEFycmF5LCBpNCApO1xuXHRcdFx0XHRcdGRzdEFycmF5WyBpNCArIDMgXSA9IHBsYW5lLmNvbnN0YW50O1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHR1bmlmb3JtLnZhbHVlID0gZHN0QXJyYXk7XG5cdFx0XHR1bmlmb3JtLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdHNjb3BlLm51bVBsYW5lcyA9IG5QbGFuZXM7XG5cdFx0c2NvcGUubnVtSW50ZXJzZWN0aW9uID0gMDtcblxuXHRcdHJldHVybiBkc3RBcnJheTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xDdWJlTWFwcyggcmVuZGVyZXIgKSB7XG5cblx0bGV0IGN1YmVtYXBzID0gbmV3IFdlYWtNYXAoKTtcblxuXHRmdW5jdGlvbiBtYXBUZXh0dXJlTWFwcGluZyggdGV4dHVyZSwgbWFwcGluZyApIHtcblxuXHRcdGlmICggbWFwcGluZyA9PT0gRXF1aXJlY3Rhbmd1bGFyUmVmbGVjdGlvbk1hcHBpbmcgKSB7XG5cblx0XHRcdHRleHR1cmUubWFwcGluZyA9IEN1YmVSZWZsZWN0aW9uTWFwcGluZztcblxuXHRcdH0gZWxzZSBpZiAoIG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZnJhY3Rpb25NYXBwaW5nICkge1xuXG5cdFx0XHR0ZXh0dXJlLm1hcHBpbmcgPSBDdWJlUmVmcmFjdGlvbk1hcHBpbmc7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGV4dHVyZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0KCB0ZXh0dXJlICkge1xuXG5cdFx0aWYgKCB0ZXh0dXJlICYmIHRleHR1cmUuaXNUZXh0dXJlICkge1xuXG5cdFx0XHRjb25zdCBtYXBwaW5nID0gdGV4dHVyZS5tYXBwaW5nO1xuXG5cdFx0XHRpZiAoIG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nIHx8IG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZnJhY3Rpb25NYXBwaW5nICkge1xuXG5cdFx0XHRcdGlmICggY3ViZW1hcHMuaGFzKCB0ZXh0dXJlICkgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBjdWJlbWFwID0gY3ViZW1hcHMuZ2V0KCB0ZXh0dXJlICkudGV4dHVyZTtcblx0XHRcdFx0XHRyZXR1cm4gbWFwVGV4dHVyZU1hcHBpbmcoIGN1YmVtYXAsIHRleHR1cmUubWFwcGluZyApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRjb25zdCBpbWFnZSA9IHRleHR1cmUuaW1hZ2U7XG5cblx0XHRcdFx0XHRpZiAoIGltYWdlICYmIGltYWdlLmhlaWdodCA+IDAgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IHJlbmRlclRhcmdldCA9IG5ldyBXZWJHTEN1YmVSZW5kZXJUYXJnZXQoIGltYWdlLmhlaWdodCApO1xuXHRcdFx0XHRcdFx0cmVuZGVyVGFyZ2V0LmZyb21FcXVpcmVjdGFuZ3VsYXJUZXh0dXJlKCByZW5kZXJlciwgdGV4dHVyZSApO1xuXHRcdFx0XHRcdFx0Y3ViZW1hcHMuc2V0KCB0ZXh0dXJlLCByZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHRcdFx0dGV4dHVyZS5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVGV4dHVyZURpc3Bvc2UgKTtcblxuXHRcdFx0XHRcdFx0cmV0dXJuIG1hcFRleHR1cmVNYXBwaW5nKCByZW5kZXJUYXJnZXQudGV4dHVyZSwgdGV4dHVyZS5tYXBwaW5nICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHQvLyBpbWFnZSBub3QgeWV0IHJlYWR5LiB0cnkgdGhlIGNvbnZlcnNpb24gbmV4dCBmcmFtZVxuXG5cdFx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0ZXh0dXJlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBvblRleHR1cmVEaXNwb3NlKCBldmVudCApIHtcblxuXHRcdGNvbnN0IHRleHR1cmUgPSBldmVudC50YXJnZXQ7XG5cblx0XHR0ZXh0dXJlLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25UZXh0dXJlRGlzcG9zZSApO1xuXG5cdFx0Y29uc3QgY3ViZW1hcCA9IGN1YmVtYXBzLmdldCggdGV4dHVyZSApO1xuXG5cdFx0aWYgKCBjdWJlbWFwICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGN1YmVtYXBzLmRlbGV0ZSggdGV4dHVyZSApO1xuXHRcdFx0Y3ViZW1hcC5kaXNwb3NlKCk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG5cblx0XHRjdWJlbWFwcyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0Z2V0OiBnZXQsXG5cdFx0ZGlzcG9zZTogZGlzcG9zZVxuXHR9O1xuXG59XG5cbmNsYXNzIE9ydGhvZ3JhcGhpY0NhbWVyYSBleHRlbmRzIENhbWVyYSB7XG5cblx0Y29uc3RydWN0b3IoIGxlZnQgPSAtIDEsIHJpZ2h0ID0gMSwgdG9wID0gMSwgYm90dG9tID0gLSAxLCBuZWFyID0gMC4xLCBmYXIgPSAyMDAwICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNPcnRob2dyYXBoaWNDYW1lcmEgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ09ydGhvZ3JhcGhpY0NhbWVyYSc7XG5cblx0XHR0aGlzLnpvb20gPSAxO1xuXHRcdHRoaXMudmlldyA9IG51bGw7XG5cblx0XHR0aGlzLmxlZnQgPSBsZWZ0O1xuXHRcdHRoaXMucmlnaHQgPSByaWdodDtcblx0XHR0aGlzLnRvcCA9IHRvcDtcblx0XHR0aGlzLmJvdHRvbSA9IGJvdHRvbTtcblxuXHRcdHRoaXMubmVhciA9IG5lYXI7XG5cdFx0dGhpcy5mYXIgPSBmYXI7XG5cblx0XHR0aGlzLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0dGhpcy5sZWZ0ID0gc291cmNlLmxlZnQ7XG5cdFx0dGhpcy5yaWdodCA9IHNvdXJjZS5yaWdodDtcblx0XHR0aGlzLnRvcCA9IHNvdXJjZS50b3A7XG5cdFx0dGhpcy5ib3R0b20gPSBzb3VyY2UuYm90dG9tO1xuXHRcdHRoaXMubmVhciA9IHNvdXJjZS5uZWFyO1xuXHRcdHRoaXMuZmFyID0gc291cmNlLmZhcjtcblxuXHRcdHRoaXMuem9vbSA9IHNvdXJjZS56b29tO1xuXHRcdHRoaXMudmlldyA9IHNvdXJjZS52aWV3ID09PSBudWxsID8gbnVsbCA6IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UudmlldyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFZpZXdPZmZzZXQoIGZ1bGxXaWR0aCwgZnVsbEhlaWdodCwgeCwgeSwgd2lkdGgsIGhlaWdodCApIHtcblxuXHRcdGlmICggdGhpcy52aWV3ID09PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLnZpZXcgPSB7XG5cdFx0XHRcdGVuYWJsZWQ6IHRydWUsXG5cdFx0XHRcdGZ1bGxXaWR0aDogMSxcblx0XHRcdFx0ZnVsbEhlaWdodDogMSxcblx0XHRcdFx0b2Zmc2V0WDogMCxcblx0XHRcdFx0b2Zmc2V0WTogMCxcblx0XHRcdFx0d2lkdGg6IDEsXG5cdFx0XHRcdGhlaWdodDogMVxuXHRcdFx0fTtcblxuXHRcdH1cblxuXHRcdHRoaXMudmlldy5lbmFibGVkID0gdHJ1ZTtcblx0XHR0aGlzLnZpZXcuZnVsbFdpZHRoID0gZnVsbFdpZHRoO1xuXHRcdHRoaXMudmlldy5mdWxsSGVpZ2h0ID0gZnVsbEhlaWdodDtcblx0XHR0aGlzLnZpZXcub2Zmc2V0WCA9IHg7XG5cdFx0dGhpcy52aWV3Lm9mZnNldFkgPSB5O1xuXHRcdHRoaXMudmlldy53aWR0aCA9IHdpZHRoO1xuXHRcdHRoaXMudmlldy5oZWlnaHQgPSBoZWlnaHQ7XG5cblx0XHR0aGlzLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHR9XG5cblx0Y2xlYXJWaWV3T2Zmc2V0KCkge1xuXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMudmlldy5lbmFibGVkID0gZmFsc2U7XG5cblx0XHR9XG5cblx0XHR0aGlzLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHR9XG5cblx0dXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpIHtcblxuXHRcdGNvbnN0IGR4ID0gKCB0aGlzLnJpZ2h0IC0gdGhpcy5sZWZ0ICkgLyAoIDIgKiB0aGlzLnpvb20gKTtcblx0XHRjb25zdCBkeSA9ICggdGhpcy50b3AgLSB0aGlzLmJvdHRvbSApIC8gKCAyICogdGhpcy56b29tICk7XG5cdFx0Y29uc3QgY3ggPSAoIHRoaXMucmlnaHQgKyB0aGlzLmxlZnQgKSAvIDI7XG5cdFx0Y29uc3QgY3kgPSAoIHRoaXMudG9wICsgdGhpcy5ib3R0b20gKSAvIDI7XG5cblx0XHRsZXQgbGVmdCA9IGN4IC0gZHg7XG5cdFx0bGV0IHJpZ2h0ID0gY3ggKyBkeDtcblx0XHRsZXQgdG9wID0gY3kgKyBkeTtcblx0XHRsZXQgYm90dG9tID0gY3kgLSBkeTtcblxuXHRcdGlmICggdGhpcy52aWV3ICE9PSBudWxsICYmIHRoaXMudmlldy5lbmFibGVkICkge1xuXG5cdFx0XHRjb25zdCBzY2FsZVcgPSAoIHRoaXMucmlnaHQgLSB0aGlzLmxlZnQgKSAvIHRoaXMudmlldy5mdWxsV2lkdGggLyB0aGlzLnpvb207XG5cdFx0XHRjb25zdCBzY2FsZUggPSAoIHRoaXMudG9wIC0gdGhpcy5ib3R0b20gKSAvIHRoaXMudmlldy5mdWxsSGVpZ2h0IC8gdGhpcy56b29tO1xuXG5cdFx0XHRsZWZ0ICs9IHNjYWxlVyAqIHRoaXMudmlldy5vZmZzZXRYO1xuXHRcdFx0cmlnaHQgPSBsZWZ0ICsgc2NhbGVXICogdGhpcy52aWV3LndpZHRoO1xuXHRcdFx0dG9wIC09IHNjYWxlSCAqIHRoaXMudmlldy5vZmZzZXRZO1xuXHRcdFx0Ym90dG9tID0gdG9wIC0gc2NhbGVIICogdGhpcy52aWV3LmhlaWdodDtcblxuXHRcdH1cblxuXHRcdHRoaXMucHJvamVjdGlvbk1hdHJpeC5tYWtlT3J0aG9ncmFwaGljKCBsZWZ0LCByaWdodCwgdG9wLCBib3R0b20sIHRoaXMubmVhciwgdGhpcy5mYXIsIHRoaXMuY29vcmRpbmF0ZVN5c3RlbSApO1xuXG5cdFx0dGhpcy5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZS5jb3B5KCB0aGlzLnByb2plY3Rpb25NYXRyaXggKS5pbnZlcnQoKTtcblxuXHR9XG5cblx0dG9KU09OKCBtZXRhICkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTiggbWV0YSApO1xuXG5cdFx0ZGF0YS5vYmplY3Quem9vbSA9IHRoaXMuem9vbTtcblx0XHRkYXRhLm9iamVjdC5sZWZ0ID0gdGhpcy5sZWZ0O1xuXHRcdGRhdGEub2JqZWN0LnJpZ2h0ID0gdGhpcy5yaWdodDtcblx0XHRkYXRhLm9iamVjdC50b3AgPSB0aGlzLnRvcDtcblx0XHRkYXRhLm9iamVjdC5ib3R0b20gPSB0aGlzLmJvdHRvbTtcblx0XHRkYXRhLm9iamVjdC5uZWFyID0gdGhpcy5uZWFyO1xuXHRcdGRhdGEub2JqZWN0LmZhciA9IHRoaXMuZmFyO1xuXG5cdFx0aWYgKCB0aGlzLnZpZXcgIT09IG51bGwgKSBkYXRhLm9iamVjdC52aWV3ID0gT2JqZWN0LmFzc2lnbigge30sIHRoaXMudmlldyApO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbmNvbnN0IExPRF9NSU4gPSA0O1xuXG4vLyBUaGUgc3RhbmRhcmQgZGV2aWF0aW9ucyAocmFkaWFucykgYXNzb2NpYXRlZCB3aXRoIHRoZSBleHRyYSBtaXBzLiBUaGVzZSBhcmVcbi8vIGNob3NlbiB0byBhcHByb3hpbWF0ZSBhIFRyb3dicmlkZ2UtUmVpdHogZGlzdHJpYnV0aW9uIGZ1bmN0aW9uIHRpbWVzIHRoZVxuLy8gZ2VvbWV0cmljIHNoYWRvd2luZyBmdW5jdGlvbi4gVGhlc2Ugc2lnbWEgdmFsdWVzIHNxdWFyZWQgbXVzdCBtYXRjaCB0aGVcbi8vIHZhcmlhbmNlICNkZWZpbmVzIGluIGN1YmVfdXZfcmVmbGVjdGlvbl9mcmFnbWVudC5nbHNsLmpzLlxuY29uc3QgRVhUUkFfTE9EX1NJR01BID0gWyAwLjEyNSwgMC4yMTUsIDAuMzUsIDAuNDQ2LCAwLjUyNiwgMC41ODIgXTtcblxuLy8gVGhlIG1heGltdW0gbGVuZ3RoIG9mIHRoZSBibHVyIGZvciBsb29wLiBTbWFsbGVyIHNpZ21hcyB3aWxsIHVzZSBmZXdlclxuLy8gc2FtcGxlcyBhbmQgZXhpdCBlYXJseSwgYnV0IG5vdCByZWNvbXBpbGUgdGhlIHNoYWRlci5cbmNvbnN0IE1BWF9TQU1QTEVTID0gMjA7XG5cbmNvbnN0IF9mbGF0Q2FtZXJhID0gLypAX19QVVJFX18qLyBuZXcgT3J0aG9ncmFwaGljQ2FtZXJhKCk7XG5jb25zdCBfY2xlYXJDb2xvciA9IC8qQF9fUFVSRV9fKi8gbmV3IENvbG9yKCk7XG5sZXQgX29sZFRhcmdldCA9IG51bGw7XG5sZXQgX29sZEFjdGl2ZUN1YmVGYWNlID0gMDtcbmxldCBfb2xkQWN0aXZlTWlwbWFwTGV2ZWwgPSAwO1xubGV0IF9vbGRYckVuYWJsZWQgPSBmYWxzZTtcblxuLy8gR29sZGVuIFJhdGlvXG5jb25zdCBQSEkgPSAoIDEgKyBNYXRoLnNxcnQoIDUgKSApIC8gMjtcbmNvbnN0IElOVl9QSEkgPSAxIC8gUEhJO1xuXG4vLyBWZXJ0aWNlcyBvZiBhIGRvZGVjYWhlZHJvbiAoZXhjZXB0IHRoZSBvcHBvc2l0ZXMsIHdoaWNoIHJlcHJlc2VudCB0aGVcbi8vIHNhbWUgYXhpcyksIHVzZWQgYXMgYXhpcyBkaXJlY3Rpb25zIGV2ZW5seSBzcHJlYWQgb24gYSBzcGhlcmUuXG5jb25zdCBfYXhpc0RpcmVjdGlvbnMgPSBbXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIC0gUEhJLCBJTlZfUEhJLCAwICksXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIFBISSwgSU5WX1BISSwgMCApLFxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAtIElOVl9QSEksIDAsIFBISSApLFxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCBJTlZfUEhJLCAwLCBQSEkgKSxcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgUEhJLCAtIElOVl9QSEkgKSxcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMCwgUEhJLCBJTlZfUEhJICksXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIC0gMSwgMSwgLSAxICksXG5cdC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoIDEsIDEsIC0gMSApLFxuXHQvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCAtIDEsIDEsIDEgKSxcblx0LypAX19QVVJFX18qLyBuZXcgVmVjdG9yMyggMSwgMSwgMSApIF07XG5cbi8qKlxuICogVGhpcyBjbGFzcyBnZW5lcmF0ZXMgYSBQcmVmaWx0ZXJlZCwgTWlwbWFwcGVkIFJhZGlhbmNlIEVudmlyb25tZW50IE1hcFxuICogKFBNUkVNKSBmcm9tIGEgY3ViZU1hcCBlbnZpcm9ubWVudCB0ZXh0dXJlLiBUaGlzIGFsbG93cyBkaWZmZXJlbnQgbGV2ZWxzIG9mXG4gKiBibHVyIHRvIGJlIHF1aWNrbHkgYWNjZXNzZWQgYmFzZWQgb24gbWF0ZXJpYWwgcm91Z2huZXNzLiBJdCBpcyBwYWNrZWQgaW50byBhXG4gKiBzcGVjaWFsIEN1YmVVViBmb3JtYXQgdGhhdCBhbGxvd3MgdXMgdG8gcGVyZm9ybSBjdXN0b20gaW50ZXJwb2xhdGlvbiBzbyB0aGF0XG4gKiB3ZSBjYW4gc3VwcG9ydCBub25saW5lYXIgZm9ybWF0cyBzdWNoIGFzIFJHQkUuIFVubGlrZSBhIHRyYWRpdGlvbmFsIG1pcG1hcFxuICogY2hhaW4sIGl0IG9ubHkgZ29lcyBkb3duIHRvIHRoZSBMT0RfTUlOIGxldmVsIChhYm92ZSksIGFuZCB0aGVuIGNyZWF0ZXMgZXh0cmFcbiAqIGV2ZW4gbW9yZSBmaWx0ZXJlZCAnbWlwcycgYXQgdGhlIHNhbWUgTE9EX01JTiByZXNvbHV0aW9uLCBhc3NvY2lhdGVkIHdpdGhcbiAqIGhpZ2hlciByb3VnaG5lc3MgbGV2ZWxzLiBJbiB0aGlzIHdheSB3ZSBtYWludGFpbiByZXNvbHV0aW9uIHRvIHNtb290aGx5XG4gKiBpbnRlcnBvbGF0ZSBkaWZmdXNlIGxpZ2h0aW5nIHdoaWxlIGxpbWl0aW5nIHNhbXBsaW5nIGNvbXB1dGF0aW9uLlxuICpcbiAqIFBhcGVyOiBGYXN0LCBBY2N1cmF0ZSBJbWFnZS1CYXNlZCBMaWdodGluZ1xuICogaHR0cHM6Ly9kcml2ZS5nb29nbGUuY29tL2ZpbGUvZC8xNXk4cl9VcEtsVTlTdlY0SUxiMEMzcUNQZWNTOHB2THovdmlld1xuKi9cblxuY2xhc3MgUE1SRU1HZW5lcmF0b3Ige1xuXG5cdGNvbnN0cnVjdG9yKCByZW5kZXJlciApIHtcblxuXHRcdHRoaXMuX3JlbmRlcmVyID0gcmVuZGVyZXI7XG5cdFx0dGhpcy5fcGluZ1BvbmdSZW5kZXJUYXJnZXQgPSBudWxsO1xuXG5cdFx0dGhpcy5fbG9kTWF4ID0gMDtcblx0XHR0aGlzLl9jdWJlU2l6ZSA9IDA7XG5cdFx0dGhpcy5fbG9kUGxhbmVzID0gW107XG5cdFx0dGhpcy5fc2l6ZUxvZHMgPSBbXTtcblx0XHR0aGlzLl9zaWdtYXMgPSBbXTtcblxuXHRcdHRoaXMuX2JsdXJNYXRlcmlhbCA9IG51bGw7XG5cdFx0dGhpcy5fY3ViZW1hcE1hdGVyaWFsID0gbnVsbDtcblx0XHR0aGlzLl9lcXVpcmVjdE1hdGVyaWFsID0gbnVsbDtcblxuXHRcdHRoaXMuX2NvbXBpbGVNYXRlcmlhbCggdGhpcy5fYmx1ck1hdGVyaWFsICk7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBHZW5lcmF0ZXMgYSBQTVJFTSBmcm9tIGEgc3VwcGxpZWQgU2NlbmUsIHdoaWNoIGNhbiBiZSBmYXN0ZXIgdGhhbiB1c2luZyBhblxuXHQgKiBpbWFnZSBpZiBuZXR3b3JraW5nIGJhbmR3aWR0aCBpcyBsb3cuIE9wdGlvbmFsIHNpZ21hIHNwZWNpZmllcyBhIGJsdXIgcmFkaXVzXG5cdCAqIGluIHJhZGlhbnMgdG8gYmUgYXBwbGllZCB0byB0aGUgc2NlbmUgYmVmb3JlIFBNUkVNIGdlbmVyYXRpb24uIE9wdGlvbmFsIG5lYXJcblx0ICogYW5kIGZhciBwbGFuZXMgZW5zdXJlIHRoZSBzY2VuZSBpcyByZW5kZXJlZCBpbiBpdHMgZW50aXJldHkgKHRoZSBjdWJlQ2FtZXJhXG5cdCAqIGlzIHBsYWNlZCBhdCB0aGUgb3JpZ2luKS5cblx0ICovXG5cdGZyb21TY2VuZSggc2NlbmUsIHNpZ21hID0gMCwgbmVhciA9IDAuMSwgZmFyID0gMTAwICkge1xuXG5cdFx0X29sZFRhcmdldCA9IHRoaXMuX3JlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xuXHRcdF9vbGRBY3RpdmVDdWJlRmFjZSA9IHRoaXMuX3JlbmRlcmVyLmdldEFjdGl2ZUN1YmVGYWNlKCk7XG5cdFx0X29sZEFjdGl2ZU1pcG1hcExldmVsID0gdGhpcy5fcmVuZGVyZXIuZ2V0QWN0aXZlTWlwbWFwTGV2ZWwoKTtcblx0XHRfb2xkWHJFbmFibGVkID0gdGhpcy5fcmVuZGVyZXIueHIuZW5hYmxlZDtcblxuXHRcdHRoaXMuX3JlbmRlcmVyLnhyLmVuYWJsZWQgPSBmYWxzZTtcblxuXHRcdHRoaXMuX3NldFNpemUoIDI1NiApO1xuXG5cdFx0Y29uc3QgY3ViZVVWUmVuZGVyVGFyZ2V0ID0gdGhpcy5fYWxsb2NhdGVUYXJnZXRzKCk7XG5cdFx0Y3ViZVVWUmVuZGVyVGFyZ2V0LmRlcHRoQnVmZmVyID0gdHJ1ZTtcblxuXHRcdHRoaXMuX3NjZW5lVG9DdWJlVVYoIHNjZW5lLCBuZWFyLCBmYXIsIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXG5cdFx0aWYgKCBzaWdtYSA+IDAgKSB7XG5cblx0XHRcdHRoaXMuX2JsdXIoIGN1YmVVVlJlbmRlclRhcmdldCwgMCwgMCwgc2lnbWEgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuX2FwcGx5UE1SRU0oIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXHRcdHRoaXMuX2NsZWFudXAoIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXG5cdFx0cmV0dXJuIGN1YmVVVlJlbmRlclRhcmdldDtcblxuXHR9XG5cblx0LyoqXG5cdCAqIEdlbmVyYXRlcyBhIFBNUkVNIGZyb20gYW4gZXF1aXJlY3Rhbmd1bGFyIHRleHR1cmUsIHdoaWNoIGNhbiBiZSBlaXRoZXIgTERSXG5cdCAqIG9yIEhEUi4gVGhlIGlkZWFsIGlucHV0IGltYWdlIHNpemUgaXMgMWsgKDEwMjQgeCA1MTIpLFxuXHQgKiBhcyB0aGlzIG1hdGNoZXMgYmVzdCB3aXRoIHRoZSAyNTYgeCAyNTYgY3ViZW1hcCBvdXRwdXQuXG5cdCAqIFRoZSBzbWFsbGVzdCBzdXBwb3J0ZWQgZXF1aXJlY3Rhbmd1bGFyIGltYWdlIHNpemUgaXMgNjQgeCAzMi5cblx0ICovXG5cdGZyb21FcXVpcmVjdGFuZ3VsYXIoIGVxdWlyZWN0YW5ndWxhciwgcmVuZGVyVGFyZ2V0ID0gbnVsbCApIHtcblxuXHRcdHJldHVybiB0aGlzLl9mcm9tVGV4dHVyZSggZXF1aXJlY3Rhbmd1bGFyLCByZW5kZXJUYXJnZXQgKTtcblxuXHR9XG5cblx0LyoqXG5cdCAqIEdlbmVyYXRlcyBhIFBNUkVNIGZyb20gYW4gY3ViZW1hcCB0ZXh0dXJlLCB3aGljaCBjYW4gYmUgZWl0aGVyIExEUlxuXHQgKiBvciBIRFIuIFRoZSBpZGVhbCBpbnB1dCBjdWJlIHNpemUgaXMgMjU2IHggMjU2LFxuXHQgKiBhcyB0aGlzIG1hdGNoZXMgYmVzdCB3aXRoIHRoZSAyNTYgeCAyNTYgY3ViZW1hcCBvdXRwdXQuXG5cdCAqIFRoZSBzbWFsbGVzdCBzdXBwb3J0ZWQgY3ViZSBzaXplIGlzIDE2IHggMTYuXG5cdCAqL1xuXHRmcm9tQ3ViZW1hcCggY3ViZW1hcCwgcmVuZGVyVGFyZ2V0ID0gbnVsbCApIHtcblxuXHRcdHJldHVybiB0aGlzLl9mcm9tVGV4dHVyZSggY3ViZW1hcCwgcmVuZGVyVGFyZ2V0ICk7XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBQcmUtY29tcGlsZXMgdGhlIGN1YmVtYXAgc2hhZGVyLiBZb3UgY2FuIGdldCBmYXN0ZXIgc3RhcnQtdXAgYnkgaW52b2tpbmcgdGhpcyBtZXRob2QgZHVyaW5nXG5cdCAqIHlvdXIgdGV4dHVyZSdzIG5ldHdvcmsgZmV0Y2ggZm9yIGluY3JlYXNlZCBjb25jdXJyZW5jeS5cblx0ICovXG5cdGNvbXBpbGVDdWJlbWFwU2hhZGVyKCkge1xuXG5cdFx0aWYgKCB0aGlzLl9jdWJlbWFwTWF0ZXJpYWwgPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX2N1YmVtYXBNYXRlcmlhbCA9IF9nZXRDdWJlbWFwTWF0ZXJpYWwoKTtcblx0XHRcdHRoaXMuX2NvbXBpbGVNYXRlcmlhbCggdGhpcy5fY3ViZW1hcE1hdGVyaWFsICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBQcmUtY29tcGlsZXMgdGhlIGVxdWlyZWN0YW5ndWxhciBzaGFkZXIuIFlvdSBjYW4gZ2V0IGZhc3RlciBzdGFydC11cCBieSBpbnZva2luZyB0aGlzIG1ldGhvZCBkdXJpbmdcblx0ICogeW91ciB0ZXh0dXJlJ3MgbmV0d29yayBmZXRjaCBmb3IgaW5jcmVhc2VkIGNvbmN1cnJlbmN5LlxuXHQgKi9cblx0Y29tcGlsZUVxdWlyZWN0YW5ndWxhclNoYWRlcigpIHtcblxuXHRcdGlmICggdGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9IF9nZXRFcXVpcmVjdE1hdGVyaWFsKCk7XG5cdFx0XHR0aGlzLl9jb21waWxlTWF0ZXJpYWwoIHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWwgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0LyoqXG5cdCAqIERpc3Bvc2VzIG9mIHRoZSBQTVJFTUdlbmVyYXRvcidzIGludGVybmFsIG1lbW9yeS4gTm90ZSB0aGF0IFBNUkVNR2VuZXJhdG9yIGlzIGEgc3RhdGljIGNsYXNzLFxuXHQgKiBzbyB5b3Ugc2hvdWxkIG5vdCBuZWVkIG1vcmUgdGhhbiBvbmUgUE1SRU1HZW5lcmF0b3Igb2JqZWN0LiBJZiB5b3UgZG8sIGNhbGxpbmcgZGlzcG9zZSgpIG9uXG5cdCAqIG9uZSBvZiB0aGVtIHdpbGwgY2F1c2UgYW55IG90aGVycyB0byBhbHNvIGJlY29tZSB1bnVzYWJsZS5cblx0ICovXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLl9kaXNwb3NlKCk7XG5cblx0XHRpZiAoIHRoaXMuX2N1YmVtYXBNYXRlcmlhbCAhPT0gbnVsbCApIHRoaXMuX2N1YmVtYXBNYXRlcmlhbC5kaXNwb3NlKCk7XG5cdFx0aWYgKCB0aGlzLl9lcXVpcmVjdE1hdGVyaWFsICE9PSBudWxsICkgdGhpcy5fZXF1aXJlY3RNYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0fVxuXG5cdC8vIHByaXZhdGUgaW50ZXJmYWNlXG5cblx0X3NldFNpemUoIGN1YmVTaXplICkge1xuXG5cdFx0dGhpcy5fbG9kTWF4ID0gTWF0aC5mbG9vciggTWF0aC5sb2cyKCBjdWJlU2l6ZSApICk7XG5cdFx0dGhpcy5fY3ViZVNpemUgPSBNYXRoLnBvdyggMiwgdGhpcy5fbG9kTWF4ICk7XG5cblx0fVxuXG5cdF9kaXNwb3NlKCkge1xuXG5cdFx0aWYgKCB0aGlzLl9ibHVyTWF0ZXJpYWwgIT09IG51bGwgKSB0aGlzLl9ibHVyTWF0ZXJpYWwuZGlzcG9zZSgpO1xuXG5cdFx0aWYgKCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldCAhPT0gbnVsbCApIHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0LmRpc3Bvc2UoKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMuX2xvZFBsYW5lcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuX2xvZFBsYW5lc1sgaSBdLmRpc3Bvc2UoKTtcblxuXHRcdH1cblxuXHR9XG5cblx0X2NsZWFudXAoIG91dHB1dFRhcmdldCApIHtcblxuXHRcdHRoaXMuX3JlbmRlcmVyLnNldFJlbmRlclRhcmdldCggX29sZFRhcmdldCwgX29sZEFjdGl2ZUN1YmVGYWNlLCBfb2xkQWN0aXZlTWlwbWFwTGV2ZWwgKTtcblx0XHR0aGlzLl9yZW5kZXJlci54ci5lbmFibGVkID0gX29sZFhyRW5hYmxlZDtcblxuXHRcdG91dHB1dFRhcmdldC5zY2lzc29yVGVzdCA9IGZhbHNlO1xuXHRcdF9zZXRWaWV3cG9ydCggb3V0cHV0VGFyZ2V0LCAwLCAwLCBvdXRwdXRUYXJnZXQud2lkdGgsIG91dHB1dFRhcmdldC5oZWlnaHQgKTtcblxuXHR9XG5cblx0X2Zyb21UZXh0dXJlKCB0ZXh0dXJlLCByZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRpZiAoIHRleHR1cmUubWFwcGluZyA9PT0gQ3ViZVJlZmxlY3Rpb25NYXBwaW5nIHx8IHRleHR1cmUubWFwcGluZyA9PT0gQ3ViZVJlZnJhY3Rpb25NYXBwaW5nICkge1xuXG5cdFx0XHR0aGlzLl9zZXRTaXplKCB0ZXh0dXJlLmltYWdlLmxlbmd0aCA9PT0gMCA/IDE2IDogKCB0ZXh0dXJlLmltYWdlWyAwIF0ud2lkdGggfHwgdGV4dHVyZS5pbWFnZVsgMCBdLmltYWdlLndpZHRoICkgKTtcblxuXHRcdH0gZWxzZSB7IC8vIEVxdWlyZWN0YW5ndWxhclxuXG5cdFx0XHR0aGlzLl9zZXRTaXplKCB0ZXh0dXJlLmltYWdlLndpZHRoIC8gNCApO1xuXG5cdFx0fVxuXG5cdFx0X29sZFRhcmdldCA9IHRoaXMuX3JlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xuXHRcdF9vbGRBY3RpdmVDdWJlRmFjZSA9IHRoaXMuX3JlbmRlcmVyLmdldEFjdGl2ZUN1YmVGYWNlKCk7XG5cdFx0X29sZEFjdGl2ZU1pcG1hcExldmVsID0gdGhpcy5fcmVuZGVyZXIuZ2V0QWN0aXZlTWlwbWFwTGV2ZWwoKTtcblx0XHRfb2xkWHJFbmFibGVkID0gdGhpcy5fcmVuZGVyZXIueHIuZW5hYmxlZDtcblxuXHRcdHRoaXMuX3JlbmRlcmVyLnhyLmVuYWJsZWQgPSBmYWxzZTtcblxuXHRcdGNvbnN0IGN1YmVVVlJlbmRlclRhcmdldCA9IHJlbmRlclRhcmdldCB8fCB0aGlzLl9hbGxvY2F0ZVRhcmdldHMoKTtcblx0XHR0aGlzLl90ZXh0dXJlVG9DdWJlVVYoIHRleHR1cmUsIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXHRcdHRoaXMuX2FwcGx5UE1SRU0oIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXHRcdHRoaXMuX2NsZWFudXAoIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXG5cdFx0cmV0dXJuIGN1YmVVVlJlbmRlclRhcmdldDtcblxuXHR9XG5cblx0X2FsbG9jYXRlVGFyZ2V0cygpIHtcblxuXHRcdGNvbnN0IHdpZHRoID0gMyAqIE1hdGgubWF4KCB0aGlzLl9jdWJlU2l6ZSwgMTYgKiA3ICk7XG5cdFx0Y29uc3QgaGVpZ2h0ID0gNCAqIHRoaXMuX2N1YmVTaXplO1xuXG5cdFx0Y29uc3QgcGFyYW1zID0ge1xuXHRcdFx0bWFnRmlsdGVyOiBMaW5lYXJGaWx0ZXIsXG5cdFx0XHRtaW5GaWx0ZXI6IExpbmVhckZpbHRlcixcblx0XHRcdGdlbmVyYXRlTWlwbWFwczogZmFsc2UsXG5cdFx0XHR0eXBlOiBIYWxmRmxvYXRUeXBlLFxuXHRcdFx0Zm9ybWF0OiBSR0JBRm9ybWF0LFxuXHRcdFx0Y29sb3JTcGFjZTogTGluZWFyU1JHQkNvbG9yU3BhY2UsXG5cdFx0XHRkZXB0aEJ1ZmZlcjogZmFsc2Vcblx0XHR9O1xuXG5cdFx0Y29uc3QgY3ViZVVWUmVuZGVyVGFyZ2V0ID0gX2NyZWF0ZVJlbmRlclRhcmdldCggd2lkdGgsIGhlaWdodCwgcGFyYW1zICk7XG5cblx0XHRpZiAoIHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0ID09PSBudWxsIHx8IHRoaXMuX3BpbmdQb25nUmVuZGVyVGFyZ2V0LndpZHRoICE9PSB3aWR0aCB8fCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldC5oZWlnaHQgIT09IGhlaWdodCApIHtcblxuXHRcdFx0aWYgKCB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHR0aGlzLl9kaXNwb3NlKCk7XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fcGluZ1BvbmdSZW5kZXJUYXJnZXQgPSBfY3JlYXRlUmVuZGVyVGFyZ2V0KCB3aWR0aCwgaGVpZ2h0LCBwYXJhbXMgKTtcblxuXHRcdFx0Y29uc3QgeyBfbG9kTWF4IH0gPSB0aGlzO1xuXHRcdFx0KCB7IHNpemVMb2RzOiB0aGlzLl9zaXplTG9kcywgbG9kUGxhbmVzOiB0aGlzLl9sb2RQbGFuZXMsIHNpZ21hczogdGhpcy5fc2lnbWFzIH0gPSBfY3JlYXRlUGxhbmVzKCBfbG9kTWF4ICkgKTtcblxuXHRcdFx0dGhpcy5fYmx1ck1hdGVyaWFsID0gX2dldEJsdXJTaGFkZXIoIF9sb2RNYXgsIHdpZHRoLCBoZWlnaHQgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBjdWJlVVZSZW5kZXJUYXJnZXQ7XG5cblx0fVxuXG5cdF9jb21waWxlTWF0ZXJpYWwoIG1hdGVyaWFsICkge1xuXG5cdFx0Y29uc3QgdG1wTWVzaCA9IG5ldyBNZXNoKCB0aGlzLl9sb2RQbGFuZXNbIDAgXSwgbWF0ZXJpYWwgKTtcblx0XHR0aGlzLl9yZW5kZXJlci5jb21waWxlKCB0bXBNZXNoLCBfZmxhdENhbWVyYSApO1xuXG5cdH1cblxuXHRfc2NlbmVUb0N1YmVVViggc2NlbmUsIG5lYXIsIGZhciwgY3ViZVVWUmVuZGVyVGFyZ2V0ICkge1xuXG5cdFx0Y29uc3QgZm92ID0gOTA7XG5cdFx0Y29uc3QgYXNwZWN0ID0gMTtcblx0XHRjb25zdCBjdWJlQ2FtZXJhID0gbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCBmb3YsIGFzcGVjdCwgbmVhciwgZmFyICk7XG5cdFx0Y29uc3QgdXBTaWduID0gWyAxLCAtIDEsIDEsIDEsIDEsIDEgXTtcblx0XHRjb25zdCBmb3J3YXJkU2lnbiA9IFsgMSwgMSwgMSwgLSAxLCAtIDEsIC0gMSBdO1xuXHRcdGNvbnN0IHJlbmRlcmVyID0gdGhpcy5fcmVuZGVyZXI7XG5cblx0XHRjb25zdCBvcmlnaW5hbEF1dG9DbGVhciA9IHJlbmRlcmVyLmF1dG9DbGVhcjtcblx0XHRjb25zdCB0b25lTWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xuXHRcdHJlbmRlcmVyLmdldENsZWFyQ29sb3IoIF9jbGVhckNvbG9yICk7XG5cblx0XHRyZW5kZXJlci50b25lTWFwcGluZyA9IE5vVG9uZU1hcHBpbmc7XG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gZmFsc2U7XG5cblx0XHRjb25zdCBiYWNrZ3JvdW5kTWF0ZXJpYWwgPSBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHtcblx0XHRcdG5hbWU6ICdQTVJFTS5CYWNrZ3JvdW5kJyxcblx0XHRcdHNpZGU6IEJhY2tTaWRlLFxuXHRcdFx0ZGVwdGhXcml0ZTogZmFsc2UsXG5cdFx0XHRkZXB0aFRlc3Q6IGZhbHNlLFxuXHRcdH0gKTtcblxuXHRcdGNvbnN0IGJhY2tncm91bmRCb3ggPSBuZXcgTWVzaCggbmV3IEJveEdlb21ldHJ5KCksIGJhY2tncm91bmRNYXRlcmlhbCApO1xuXG5cdFx0bGV0IHVzZVNvbGlkQ29sb3IgPSBmYWxzZTtcblx0XHRjb25zdCBiYWNrZ3JvdW5kID0gc2NlbmUuYmFja2dyb3VuZDtcblxuXHRcdGlmICggYmFja2dyb3VuZCApIHtcblxuXHRcdFx0aWYgKCBiYWNrZ3JvdW5kLmlzQ29sb3IgKSB7XG5cblx0XHRcdFx0YmFja2dyb3VuZE1hdGVyaWFsLmNvbG9yLmNvcHkoIGJhY2tncm91bmQgKTtcblx0XHRcdFx0c2NlbmUuYmFja2dyb3VuZCA9IG51bGw7XG5cdFx0XHRcdHVzZVNvbGlkQ29sb3IgPSB0cnVlO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRiYWNrZ3JvdW5kTWF0ZXJpYWwuY29sb3IuY29weSggX2NsZWFyQ29sb3IgKTtcblx0XHRcdHVzZVNvbGlkQ29sb3IgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgY29sID0gaSAlIDM7XG5cblx0XHRcdGlmICggY29sID09PSAwICkge1xuXG5cdFx0XHRcdGN1YmVDYW1lcmEudXAuc2V0KCAwLCB1cFNpZ25bIGkgXSwgMCApO1xuXHRcdFx0XHRjdWJlQ2FtZXJhLmxvb2tBdCggZm9yd2FyZFNpZ25bIGkgXSwgMCwgMCApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBjb2wgPT09IDEgKSB7XG5cblx0XHRcdFx0Y3ViZUNhbWVyYS51cC5zZXQoIDAsIDAsIHVwU2lnblsgaSBdICk7XG5cdFx0XHRcdGN1YmVDYW1lcmEubG9va0F0KCAwLCBmb3J3YXJkU2lnblsgaSBdLCAwICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Y3ViZUNhbWVyYS51cC5zZXQoIDAsIHVwU2lnblsgaSBdLCAwICk7XG5cdFx0XHRcdGN1YmVDYW1lcmEubG9va0F0KCAwLCAwLCBmb3J3YXJkU2lnblsgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3Qgc2l6ZSA9IHRoaXMuX2N1YmVTaXplO1xuXG5cdFx0XHRfc2V0Vmlld3BvcnQoIGN1YmVVVlJlbmRlclRhcmdldCwgY29sICogc2l6ZSwgaSA+IDIgPyBzaXplIDogMCwgc2l6ZSwgc2l6ZSApO1xuXG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXG5cdFx0XHRpZiAoIHVzZVNvbGlkQ29sb3IgKSB7XG5cblx0XHRcdFx0cmVuZGVyZXIucmVuZGVyKCBiYWNrZ3JvdW5kQm94LCBjdWJlQ2FtZXJhICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmVuZGVyZXIucmVuZGVyKCBzY2VuZSwgY3ViZUNhbWVyYSApO1xuXG5cdFx0fVxuXG5cdFx0YmFja2dyb3VuZEJveC5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0YmFja2dyb3VuZEJveC5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0XHRyZW5kZXJlci50b25lTWFwcGluZyA9IHRvbmVNYXBwaW5nO1xuXHRcdHJlbmRlcmVyLmF1dG9DbGVhciA9IG9yaWdpbmFsQXV0b0NsZWFyO1xuXHRcdHNjZW5lLmJhY2tncm91bmQgPSBiYWNrZ3JvdW5kO1xuXG5cdH1cblxuXHRfdGV4dHVyZVRvQ3ViZVVWKCB0ZXh0dXJlLCBjdWJlVVZSZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRjb25zdCByZW5kZXJlciA9IHRoaXMuX3JlbmRlcmVyO1xuXG5cdFx0Y29uc3QgaXNDdWJlVGV4dHVyZSA9ICggdGV4dHVyZS5tYXBwaW5nID09PSBDdWJlUmVmbGVjdGlvbk1hcHBpbmcgfHwgdGV4dHVyZS5tYXBwaW5nID09PSBDdWJlUmVmcmFjdGlvbk1hcHBpbmcgKTtcblxuXHRcdGlmICggaXNDdWJlVGV4dHVyZSApIHtcblxuXHRcdFx0aWYgKCB0aGlzLl9jdWJlbWFwTWF0ZXJpYWwgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0dGhpcy5fY3ViZW1hcE1hdGVyaWFsID0gX2dldEN1YmVtYXBNYXRlcmlhbCgpO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2N1YmVtYXBNYXRlcmlhbC51bmlmb3Jtcy5mbGlwRW52TWFwLnZhbHVlID0gKCB0ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgKSA/IC0gMSA6IDE7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWwgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0dGhpcy5fZXF1aXJlY3RNYXRlcmlhbCA9IF9nZXRFcXVpcmVjdE1hdGVyaWFsKCk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IG1hdGVyaWFsID0gaXNDdWJlVGV4dHVyZSA/IHRoaXMuX2N1YmVtYXBNYXRlcmlhbCA6IHRoaXMuX2VxdWlyZWN0TWF0ZXJpYWw7XG5cdFx0Y29uc3QgbWVzaCA9IG5ldyBNZXNoKCB0aGlzLl9sb2RQbGFuZXNbIDAgXSwgbWF0ZXJpYWwgKTtcblxuXHRcdGNvbnN0IHVuaWZvcm1zID0gbWF0ZXJpYWwudW5pZm9ybXM7XG5cblx0XHR1bmlmb3Jtc1sgJ2Vudk1hcCcgXS52YWx1ZSA9IHRleHR1cmU7XG5cblx0XHRjb25zdCBzaXplID0gdGhpcy5fY3ViZVNpemU7XG5cblx0XHRfc2V0Vmlld3BvcnQoIGN1YmVVVlJlbmRlclRhcmdldCwgMCwgMCwgMyAqIHNpemUsIDIgKiBzaXplICk7XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1YmVVVlJlbmRlclRhcmdldCApO1xuXHRcdHJlbmRlcmVyLnJlbmRlciggbWVzaCwgX2ZsYXRDYW1lcmEgKTtcblxuXHR9XG5cblx0X2FwcGx5UE1SRU0oIGN1YmVVVlJlbmRlclRhcmdldCApIHtcblxuXHRcdGNvbnN0IHJlbmRlcmVyID0gdGhpcy5fcmVuZGVyZXI7XG5cdFx0Y29uc3QgYXV0b0NsZWFyID0gcmVuZGVyZXIuYXV0b0NsZWFyO1xuXHRcdHJlbmRlcmVyLmF1dG9DbGVhciA9IGZhbHNlO1xuXHRcdGNvbnN0IG4gPSB0aGlzLl9sb2RQbGFuZXMubGVuZ3RoO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAxOyBpIDwgbjsgaSArKyApIHtcblxuXHRcdFx0Y29uc3Qgc2lnbWEgPSBNYXRoLnNxcnQoIHRoaXMuX3NpZ21hc1sgaSBdICogdGhpcy5fc2lnbWFzWyBpIF0gLSB0aGlzLl9zaWdtYXNbIGkgLSAxIF0gKiB0aGlzLl9zaWdtYXNbIGkgLSAxIF0gKTtcblxuXHRcdFx0Y29uc3QgcG9sZUF4aXMgPSBfYXhpc0RpcmVjdGlvbnNbICggbiAtIGkgLSAxICkgJSBfYXhpc0RpcmVjdGlvbnMubGVuZ3RoIF07XG5cblx0XHRcdHRoaXMuX2JsdXIoIGN1YmVVVlJlbmRlclRhcmdldCwgaSAtIDEsIGksIHNpZ21hLCBwb2xlQXhpcyApO1xuXG5cdFx0fVxuXG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gYXV0b0NsZWFyO1xuXG5cdH1cblxuXHQvKipcblx0ICogVGhpcyBpcyBhIHR3by1wYXNzIEdhdXNzaWFuIGJsdXIgZm9yIGEgY3ViZW1hcC4gTm9ybWFsbHkgdGhpcyBpcyBkb25lXG5cdCAqIHZlcnRpY2FsbHkgYW5kIGhvcml6b250YWxseSwgYnV0IHRoaXMgYnJlYWtzIGRvd24gb24gYSBjdWJlLiBIZXJlIHdlIGFwcGx5XG5cdCAqIHRoZSBibHVyIGxhdGl0dWRpbmFsbHkgKGFyb3VuZCB0aGUgcG9sZXMpLCBhbmQgdGhlbiBsb25naXR1ZGluYWxseSAodG93YXJkc1xuXHQgKiB0aGUgcG9sZXMpIHRvIGFwcHJveGltYXRlIHRoZSBvcnRob2dvbmFsbHktc2VwYXJhYmxlIGJsdXIuIEl0IGlzIGxlYXN0XG5cdCAqIGFjY3VyYXRlIGF0IHRoZSBwb2xlcywgYnV0IHN0aWxsIGRvZXMgYSBkZWNlbnQgam9iLlxuXHQgKi9cblx0X2JsdXIoIGN1YmVVVlJlbmRlclRhcmdldCwgbG9kSW4sIGxvZE91dCwgc2lnbWEsIHBvbGVBeGlzICkge1xuXG5cdFx0Y29uc3QgcGluZ1BvbmdSZW5kZXJUYXJnZXQgPSB0aGlzLl9waW5nUG9uZ1JlbmRlclRhcmdldDtcblxuXHRcdHRoaXMuX2hhbGZCbHVyKFxuXHRcdFx0Y3ViZVVWUmVuZGVyVGFyZ2V0LFxuXHRcdFx0cGluZ1BvbmdSZW5kZXJUYXJnZXQsXG5cdFx0XHRsb2RJbixcblx0XHRcdGxvZE91dCxcblx0XHRcdHNpZ21hLFxuXHRcdFx0J2xhdGl0dWRpbmFsJyxcblx0XHRcdHBvbGVBeGlzICk7XG5cblx0XHR0aGlzLl9oYWxmQmx1cihcblx0XHRcdHBpbmdQb25nUmVuZGVyVGFyZ2V0LFxuXHRcdFx0Y3ViZVVWUmVuZGVyVGFyZ2V0LFxuXHRcdFx0bG9kT3V0LFxuXHRcdFx0bG9kT3V0LFxuXHRcdFx0c2lnbWEsXG5cdFx0XHQnbG9uZ2l0dWRpbmFsJyxcblx0XHRcdHBvbGVBeGlzICk7XG5cblx0fVxuXG5cdF9oYWxmQmx1ciggdGFyZ2V0SW4sIHRhcmdldE91dCwgbG9kSW4sIGxvZE91dCwgc2lnbWFSYWRpYW5zLCBkaXJlY3Rpb24sIHBvbGVBeGlzICkge1xuXG5cdFx0Y29uc3QgcmVuZGVyZXIgPSB0aGlzLl9yZW5kZXJlcjtcblx0XHRjb25zdCBibHVyTWF0ZXJpYWwgPSB0aGlzLl9ibHVyTWF0ZXJpYWw7XG5cblx0XHRpZiAoIGRpcmVjdGlvbiAhPT0gJ2xhdGl0dWRpbmFsJyAmJiBkaXJlY3Rpb24gIT09ICdsb25naXR1ZGluYWwnICkge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKFxuXHRcdFx0XHQnYmx1ciBkaXJlY3Rpb24gbXVzdCBiZSBlaXRoZXIgbGF0aXR1ZGluYWwgb3IgbG9uZ2l0dWRpbmFsIScgKTtcblxuXHRcdH1cblxuXHRcdC8vIE51bWJlciBvZiBzdGFuZGFyZCBkZXZpYXRpb25zIGF0IHdoaWNoIHRvIGN1dCBvZmYgdGhlIGRpc2NyZXRlIGFwcHJveGltYXRpb24uXG5cdFx0Y29uc3QgU1RBTkRBUkRfREVWSUFUSU9OUyA9IDM7XG5cblx0XHRjb25zdCBibHVyTWVzaCA9IG5ldyBNZXNoKCB0aGlzLl9sb2RQbGFuZXNbIGxvZE91dCBdLCBibHVyTWF0ZXJpYWwgKTtcblx0XHRjb25zdCBibHVyVW5pZm9ybXMgPSBibHVyTWF0ZXJpYWwudW5pZm9ybXM7XG5cblx0XHRjb25zdCBwaXhlbHMgPSB0aGlzLl9zaXplTG9kc1sgbG9kSW4gXSAtIDE7XG5cdFx0Y29uc3QgcmFkaWFuc1BlclBpeGVsID0gaXNGaW5pdGUoIHNpZ21hUmFkaWFucyApID8gTWF0aC5QSSAvICggMiAqIHBpeGVscyApIDogMiAqIE1hdGguUEkgLyAoIDIgKiBNQVhfU0FNUExFUyAtIDEgKTtcblx0XHRjb25zdCBzaWdtYVBpeGVscyA9IHNpZ21hUmFkaWFucyAvIHJhZGlhbnNQZXJQaXhlbDtcblx0XHRjb25zdCBzYW1wbGVzID0gaXNGaW5pdGUoIHNpZ21hUmFkaWFucyApID8gMSArIE1hdGguZmxvb3IoIFNUQU5EQVJEX0RFVklBVElPTlMgKiBzaWdtYVBpeGVscyApIDogTUFYX1NBTVBMRVM7XG5cblx0XHRpZiAoIHNhbXBsZXMgPiBNQVhfU0FNUExFUyApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCBgc2lnbWFSYWRpYW5zLCAke1xuXHRcdFx0XHRzaWdtYVJhZGlhbnN9LCBpcyB0b28gbGFyZ2UgYW5kIHdpbGwgY2xpcCwgYXMgaXQgcmVxdWVzdGVkICR7XG5cdFx0XHRcdHNhbXBsZXN9IHNhbXBsZXMgd2hlbiB0aGUgbWF4aW11bSBpcyBzZXQgdG8gJHtNQVhfU0FNUExFU31gICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCB3ZWlnaHRzID0gW107XG5cdFx0bGV0IHN1bSA9IDA7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBNQVhfU0FNUExFUzsgKysgaSApIHtcblxuXHRcdFx0Y29uc3QgeCA9IGkgLyBzaWdtYVBpeGVscztcblx0XHRcdGNvbnN0IHdlaWdodCA9IE1hdGguZXhwKCAtIHggKiB4IC8gMiApO1xuXHRcdFx0d2VpZ2h0cy5wdXNoKCB3ZWlnaHQgKTtcblxuXHRcdFx0aWYgKCBpID09PSAwICkge1xuXG5cdFx0XHRcdHN1bSArPSB3ZWlnaHQ7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGkgPCBzYW1wbGVzICkge1xuXG5cdFx0XHRcdHN1bSArPSAyICogd2VpZ2h0O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB3ZWlnaHRzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0d2VpZ2h0c1sgaSBdID0gd2VpZ2h0c1sgaSBdIC8gc3VtO1xuXG5cdFx0fVxuXG5cdFx0Ymx1clVuaWZvcm1zWyAnZW52TWFwJyBdLnZhbHVlID0gdGFyZ2V0SW4udGV4dHVyZTtcblx0XHRibHVyVW5pZm9ybXNbICdzYW1wbGVzJyBdLnZhbHVlID0gc2FtcGxlcztcblx0XHRibHVyVW5pZm9ybXNbICd3ZWlnaHRzJyBdLnZhbHVlID0gd2VpZ2h0cztcblx0XHRibHVyVW5pZm9ybXNbICdsYXRpdHVkaW5hbCcgXS52YWx1ZSA9IGRpcmVjdGlvbiA9PT0gJ2xhdGl0dWRpbmFsJztcblxuXHRcdGlmICggcG9sZUF4aXMgKSB7XG5cblx0XHRcdGJsdXJVbmlmb3Jtc1sgJ3BvbGVBeGlzJyBdLnZhbHVlID0gcG9sZUF4aXM7XG5cblx0XHR9XG5cblx0XHRjb25zdCB7IF9sb2RNYXggfSA9IHRoaXM7XG5cdFx0Ymx1clVuaWZvcm1zWyAnZFRoZXRhJyBdLnZhbHVlID0gcmFkaWFuc1BlclBpeGVsO1xuXHRcdGJsdXJVbmlmb3Jtc1sgJ21pcEludCcgXS52YWx1ZSA9IF9sb2RNYXggLSBsb2RJbjtcblxuXHRcdGNvbnN0IG91dHB1dFNpemUgPSB0aGlzLl9zaXplTG9kc1sgbG9kT3V0IF07XG5cdFx0Y29uc3QgeCA9IDMgKiBvdXRwdXRTaXplICogKCBsb2RPdXQgPiBfbG9kTWF4IC0gTE9EX01JTiA/IGxvZE91dCAtIF9sb2RNYXggKyBMT0RfTUlOIDogMCApO1xuXHRcdGNvbnN0IHkgPSA0ICogKCB0aGlzLl9jdWJlU2l6ZSAtIG91dHB1dFNpemUgKTtcblxuXHRcdF9zZXRWaWV3cG9ydCggdGFyZ2V0T3V0LCB4LCB5LCAzICogb3V0cHV0U2l6ZSwgMiAqIG91dHB1dFNpemUgKTtcblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHRhcmdldE91dCApO1xuXHRcdHJlbmRlcmVyLnJlbmRlciggYmx1ck1lc2gsIF9mbGF0Q2FtZXJhICk7XG5cblx0fVxuXG59XG5cblxuXG5mdW5jdGlvbiBfY3JlYXRlUGxhbmVzKCBsb2RNYXggKSB7XG5cblx0Y29uc3QgbG9kUGxhbmVzID0gW107XG5cdGNvbnN0IHNpemVMb2RzID0gW107XG5cdGNvbnN0IHNpZ21hcyA9IFtdO1xuXG5cdGxldCBsb2QgPSBsb2RNYXg7XG5cblx0Y29uc3QgdG90YWxMb2RzID0gbG9kTWF4IC0gTE9EX01JTiArIDEgKyBFWFRSQV9MT0RfU0lHTUEubGVuZ3RoO1xuXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IHRvdGFsTG9kczsgaSArKyApIHtcblxuXHRcdGNvbnN0IHNpemVMb2QgPSBNYXRoLnBvdyggMiwgbG9kICk7XG5cdFx0c2l6ZUxvZHMucHVzaCggc2l6ZUxvZCApO1xuXHRcdGxldCBzaWdtYSA9IDEuMCAvIHNpemVMb2Q7XG5cblx0XHRpZiAoIGkgPiBsb2RNYXggLSBMT0RfTUlOICkge1xuXG5cdFx0XHRzaWdtYSA9IEVYVFJBX0xPRF9TSUdNQVsgaSAtIGxvZE1heCArIExPRF9NSU4gLSAxIF07XG5cblx0XHR9IGVsc2UgaWYgKCBpID09PSAwICkge1xuXG5cdFx0XHRzaWdtYSA9IDA7XG5cblx0XHR9XG5cblx0XHRzaWdtYXMucHVzaCggc2lnbWEgKTtcblxuXHRcdGNvbnN0IHRleGVsU2l6ZSA9IDEuMCAvICggc2l6ZUxvZCAtIDIgKTtcblx0XHRjb25zdCBtaW4gPSAtIHRleGVsU2l6ZTtcblx0XHRjb25zdCBtYXggPSAxICsgdGV4ZWxTaXplO1xuXHRcdGNvbnN0IHV2MSA9IFsgbWluLCBtaW4sIG1heCwgbWluLCBtYXgsIG1heCwgbWluLCBtaW4sIG1heCwgbWF4LCBtaW4sIG1heCBdO1xuXG5cdFx0Y29uc3QgY3ViZUZhY2VzID0gNjtcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IDY7XG5cdFx0Y29uc3QgcG9zaXRpb25TaXplID0gMztcblx0XHRjb25zdCB1dlNpemUgPSAyO1xuXHRcdGNvbnN0IGZhY2VJbmRleFNpemUgPSAxO1xuXG5cdFx0Y29uc3QgcG9zaXRpb24gPSBuZXcgRmxvYXQzMkFycmF5KCBwb3NpdGlvblNpemUgKiB2ZXJ0aWNlcyAqIGN1YmVGYWNlcyApO1xuXHRcdGNvbnN0IHV2ID0gbmV3IEZsb2F0MzJBcnJheSggdXZTaXplICogdmVydGljZXMgKiBjdWJlRmFjZXMgKTtcblx0XHRjb25zdCBmYWNlSW5kZXggPSBuZXcgRmxvYXQzMkFycmF5KCBmYWNlSW5kZXhTaXplICogdmVydGljZXMgKiBjdWJlRmFjZXMgKTtcblxuXHRcdGZvciAoIGxldCBmYWNlID0gMDsgZmFjZSA8IGN1YmVGYWNlczsgZmFjZSArKyApIHtcblxuXHRcdFx0Y29uc3QgeCA9ICggZmFjZSAlIDMgKSAqIDIgLyAzIC0gMTtcblx0XHRcdGNvbnN0IHkgPSBmYWNlID4gMiA/IDAgOiAtIDE7XG5cdFx0XHRjb25zdCBjb29yZGluYXRlcyA9IFtcblx0XHRcdFx0eCwgeSwgMCxcblx0XHRcdFx0eCArIDIgLyAzLCB5LCAwLFxuXHRcdFx0XHR4ICsgMiAvIDMsIHkgKyAxLCAwLFxuXHRcdFx0XHR4LCB5LCAwLFxuXHRcdFx0XHR4ICsgMiAvIDMsIHkgKyAxLCAwLFxuXHRcdFx0XHR4LCB5ICsgMSwgMFxuXHRcdFx0XTtcblx0XHRcdHBvc2l0aW9uLnNldCggY29vcmRpbmF0ZXMsIHBvc2l0aW9uU2l6ZSAqIHZlcnRpY2VzICogZmFjZSApO1xuXHRcdFx0dXYuc2V0KCB1djEsIHV2U2l6ZSAqIHZlcnRpY2VzICogZmFjZSApO1xuXHRcdFx0Y29uc3QgZmlsbCA9IFsgZmFjZSwgZmFjZSwgZmFjZSwgZmFjZSwgZmFjZSwgZmFjZSBdO1xuXHRcdFx0ZmFjZUluZGV4LnNldCggZmlsbCwgZmFjZUluZGV4U2l6ZSAqIHZlcnRpY2VzICogZmFjZSApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgcGxhbmVzID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cdFx0cGxhbmVzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIHBvc2l0aW9uU2l6ZSApICk7XG5cdFx0cGxhbmVzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEJ1ZmZlckF0dHJpYnV0ZSggdXYsIHV2U2l6ZSApICk7XG5cdFx0cGxhbmVzLnNldEF0dHJpYnV0ZSggJ2ZhY2VJbmRleCcsIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGZhY2VJbmRleCwgZmFjZUluZGV4U2l6ZSApICk7XG5cdFx0bG9kUGxhbmVzLnB1c2goIHBsYW5lcyApO1xuXG5cdFx0aWYgKCBsb2QgPiBMT0RfTUlOICkge1xuXG5cdFx0XHRsb2QgLS07XG5cblx0XHR9XG5cblx0fVxuXG5cdHJldHVybiB7IGxvZFBsYW5lcywgc2l6ZUxvZHMsIHNpZ21hcyB9O1xuXG59XG5cbmZ1bmN0aW9uIF9jcmVhdGVSZW5kZXJUYXJnZXQoIHdpZHRoLCBoZWlnaHQsIHBhcmFtcyApIHtcblxuXHRjb25zdCBjdWJlVVZSZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoIHdpZHRoLCBoZWlnaHQsIHBhcmFtcyApO1xuXHRjdWJlVVZSZW5kZXJUYXJnZXQudGV4dHVyZS5tYXBwaW5nID0gQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmc7XG5cdGN1YmVVVlJlbmRlclRhcmdldC50ZXh0dXJlLm5hbWUgPSAnUE1SRU0uY3ViZVV2Jztcblx0Y3ViZVVWUmVuZGVyVGFyZ2V0LnNjaXNzb3JUZXN0ID0gdHJ1ZTtcblx0cmV0dXJuIGN1YmVVVlJlbmRlclRhcmdldDtcblxufVxuXG5mdW5jdGlvbiBfc2V0Vmlld3BvcnQoIHRhcmdldCwgeCwgeSwgd2lkdGgsIGhlaWdodCApIHtcblxuXHR0YXJnZXQudmlld3BvcnQuc2V0KCB4LCB5LCB3aWR0aCwgaGVpZ2h0ICk7XG5cdHRhcmdldC5zY2lzc29yLnNldCggeCwgeSwgd2lkdGgsIGhlaWdodCApO1xuXG59XG5cbmZ1bmN0aW9uIF9nZXRCbHVyU2hhZGVyKCBsb2RNYXgsIHdpZHRoLCBoZWlnaHQgKSB7XG5cblx0Y29uc3Qgd2VpZ2h0cyA9IG5ldyBGbG9hdDMyQXJyYXkoIE1BWF9TQU1QTEVTICk7XG5cdGNvbnN0IHBvbGVBeGlzID0gbmV3IFZlY3RvcjMoIDAsIDEsIDAgKTtcblx0Y29uc3Qgc2hhZGVyTWF0ZXJpYWwgPSBuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcblxuXHRcdG5hbWU6ICdTcGhlcmljYWxHYXVzc2lhbkJsdXInLFxuXG5cdFx0ZGVmaW5lczoge1xuXHRcdFx0J24nOiBNQVhfU0FNUExFUyxcblx0XHRcdCdDVUJFVVZfVEVYRUxfV0lEVEgnOiAxLjAgLyB3aWR0aCxcblx0XHRcdCdDVUJFVVZfVEVYRUxfSEVJR0hUJzogMS4wIC8gaGVpZ2h0LFxuXHRcdFx0J0NVQkVVVl9NQVhfTUlQJzogYCR7bG9kTWF4fS4wYCxcblx0XHR9LFxuXG5cdFx0dW5pZm9ybXM6IHtcblx0XHRcdCdlbnZNYXAnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHQnc2FtcGxlcyc6IHsgdmFsdWU6IDEgfSxcblx0XHRcdCd3ZWlnaHRzJzogeyB2YWx1ZTogd2VpZ2h0cyB9LFxuXHRcdFx0J2xhdGl0dWRpbmFsJzogeyB2YWx1ZTogZmFsc2UgfSxcblx0XHRcdCdkVGhldGEnOiB7IHZhbHVlOiAwIH0sXG5cdFx0XHQnbWlwSW50JzogeyB2YWx1ZTogMCB9LFxuXHRcdFx0J3BvbGVBeGlzJzogeyB2YWx1ZTogcG9sZUF4aXMgfVxuXHRcdH0sXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IF9nZXRDb21tb25WZXJ0ZXhTaGFkZXIoKSxcblxuXHRcdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxuXG5cdFx0XHRwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDtcblx0XHRcdHByZWNpc2lvbiBtZWRpdW1wIGludDtcblxuXHRcdFx0dmFyeWluZyB2ZWMzIHZPdXRwdXREaXJlY3Rpb247XG5cblx0XHRcdHVuaWZvcm0gc2FtcGxlcjJEIGVudk1hcDtcblx0XHRcdHVuaWZvcm0gaW50IHNhbXBsZXM7XG5cdFx0XHR1bmlmb3JtIGZsb2F0IHdlaWdodHNbIG4gXTtcblx0XHRcdHVuaWZvcm0gYm9vbCBsYXRpdHVkaW5hbDtcblx0XHRcdHVuaWZvcm0gZmxvYXQgZFRoZXRhO1xuXHRcdFx0dW5pZm9ybSBmbG9hdCBtaXBJbnQ7XG5cdFx0XHR1bmlmb3JtIHZlYzMgcG9sZUF4aXM7XG5cblx0XHRcdCNkZWZpbmUgRU5WTUFQX1RZUEVfQ1VCRV9VVlxuXHRcdFx0I2luY2x1ZGUgPGN1YmVfdXZfcmVmbGVjdGlvbl9mcmFnbWVudD5cblxuXHRcdFx0dmVjMyBnZXRTYW1wbGUoIGZsb2F0IHRoZXRhLCB2ZWMzIGF4aXMgKSB7XG5cblx0XHRcdFx0ZmxvYXQgY29zVGhldGEgPSBjb3MoIHRoZXRhICk7XG5cdFx0XHRcdC8vIFJvZHJpZ3VlcycgYXhpcy1hbmdsZSByb3RhdGlvblxuXHRcdFx0XHR2ZWMzIHNhbXBsZURpcmVjdGlvbiA9IHZPdXRwdXREaXJlY3Rpb24gKiBjb3NUaGV0YVxuXHRcdFx0XHRcdCsgY3Jvc3MoIGF4aXMsIHZPdXRwdXREaXJlY3Rpb24gKSAqIHNpbiggdGhldGEgKVxuXHRcdFx0XHRcdCsgYXhpcyAqIGRvdCggYXhpcywgdk91dHB1dERpcmVjdGlvbiApICogKCAxLjAgLSBjb3NUaGV0YSApO1xuXG5cdFx0XHRcdHJldHVybiBiaWxpbmVhckN1YmVVViggZW52TWFwLCBzYW1wbGVEaXJlY3Rpb24sIG1pcEludCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0XHR2ZWMzIGF4aXMgPSBsYXRpdHVkaW5hbCA/IHBvbGVBeGlzIDogY3Jvc3MoIHBvbGVBeGlzLCB2T3V0cHV0RGlyZWN0aW9uICk7XG5cblx0XHRcdFx0aWYgKCBhbGwoIGVxdWFsKCBheGlzLCB2ZWMzKCAwLjAgKSApICkgKSB7XG5cblx0XHRcdFx0XHRheGlzID0gdmVjMyggdk91dHB1dERpcmVjdGlvbi56LCAwLjAsIC0gdk91dHB1dERpcmVjdGlvbi54ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGF4aXMgPSBub3JtYWxpemUoIGF4aXMgKTtcblxuXHRcdFx0XHRnbF9GcmFnQ29sb3IgPSB2ZWM0KCAwLjAsIDAuMCwgMC4wLCAxLjAgKTtcblx0XHRcdFx0Z2xfRnJhZ0NvbG9yLnJnYiArPSB3ZWlnaHRzWyAwIF0gKiBnZXRTYW1wbGUoIDAuMCwgYXhpcyApO1xuXG5cdFx0XHRcdGZvciAoIGludCBpID0gMTsgaSA8IG47IGkrKyApIHtcblxuXHRcdFx0XHRcdGlmICggaSA+PSBzYW1wbGVzICkge1xuXG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGZsb2F0IHRoZXRhID0gZFRoZXRhICogZmxvYXQoIGkgKTtcblx0XHRcdFx0XHRnbF9GcmFnQ29sb3IucmdiICs9IHdlaWdodHNbIGkgXSAqIGdldFNhbXBsZSggLTEuMCAqIHRoZXRhLCBheGlzICk7XG5cdFx0XHRcdFx0Z2xfRnJhZ0NvbG9yLnJnYiArPSB3ZWlnaHRzWyBpIF0gKiBnZXRTYW1wbGUoIHRoZXRhLCBheGlzICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cdFx0YCxcblxuXHRcdGJsZW5kaW5nOiBOb0JsZW5kaW5nLFxuXHRcdGRlcHRoVGVzdDogZmFsc2UsXG5cdFx0ZGVwdGhXcml0ZTogZmFsc2VcblxuXHR9ICk7XG5cblx0cmV0dXJuIHNoYWRlck1hdGVyaWFsO1xuXG59XG5cbmZ1bmN0aW9uIF9nZXRFcXVpcmVjdE1hdGVyaWFsKCkge1xuXG5cdHJldHVybiBuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcblxuXHRcdG5hbWU6ICdFcXVpcmVjdGFuZ3VsYXJUb0N1YmVVVicsXG5cblx0XHR1bmlmb3Jtczoge1xuXHRcdFx0J2Vudk1hcCc6IHsgdmFsdWU6IG51bGwgfVxuXHRcdH0sXG5cblx0XHR2ZXJ0ZXhTaGFkZXI6IF9nZXRDb21tb25WZXJ0ZXhTaGFkZXIoKSxcblxuXHRcdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxuXG5cdFx0XHRwcmVjaXNpb24gbWVkaXVtcCBmbG9hdDtcblx0XHRcdHByZWNpc2lvbiBtZWRpdW1wIGludDtcblxuXHRcdFx0dmFyeWluZyB2ZWMzIHZPdXRwdXREaXJlY3Rpb247XG5cblx0XHRcdHVuaWZvcm0gc2FtcGxlcjJEIGVudk1hcDtcblxuXHRcdFx0I2luY2x1ZGUgPGNvbW1vbj5cblxuXHRcdFx0dm9pZCBtYWluKCkge1xuXG5cdFx0XHRcdHZlYzMgb3V0cHV0RGlyZWN0aW9uID0gbm9ybWFsaXplKCB2T3V0cHV0RGlyZWN0aW9uICk7XG5cdFx0XHRcdHZlYzIgdXYgPSBlcXVpcmVjdFV2KCBvdXRwdXREaXJlY3Rpb24gKTtcblxuXHRcdFx0XHRnbF9GcmFnQ29sb3IgPSB2ZWM0KCB0ZXh0dXJlMkQgKCBlbnZNYXAsIHV2ICkucmdiLCAxLjAgKTtcblxuXHRcdFx0fVxuXHRcdGAsXG5cblx0XHRibGVuZGluZzogTm9CbGVuZGluZyxcblx0XHRkZXB0aFRlc3Q6IGZhbHNlLFxuXHRcdGRlcHRoV3JpdGU6IGZhbHNlXG5cblx0fSApO1xuXG59XG5cbmZ1bmN0aW9uIF9nZXRDdWJlbWFwTWF0ZXJpYWwoKSB7XG5cblx0cmV0dXJuIG5ldyBTaGFkZXJNYXRlcmlhbCgge1xuXG5cdFx0bmFtZTogJ0N1YmVtYXBUb0N1YmVVVicsXG5cblx0XHR1bmlmb3Jtczoge1xuXHRcdFx0J2Vudk1hcCc6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdCdmbGlwRW52TWFwJzogeyB2YWx1ZTogLSAxIH1cblx0XHR9LFxuXG5cdFx0dmVydGV4U2hhZGVyOiBfZ2V0Q29tbW9uVmVydGV4U2hhZGVyKCksXG5cblx0XHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2BcblxuXHRcdFx0cHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7XG5cdFx0XHRwcmVjaXNpb24gbWVkaXVtcCBpbnQ7XG5cblx0XHRcdHVuaWZvcm0gZmxvYXQgZmxpcEVudk1hcDtcblxuXHRcdFx0dmFyeWluZyB2ZWMzIHZPdXRwdXREaXJlY3Rpb247XG5cblx0XHRcdHVuaWZvcm0gc2FtcGxlckN1YmUgZW52TWFwO1xuXG5cdFx0XHR2b2lkIG1haW4oKSB7XG5cblx0XHRcdFx0Z2xfRnJhZ0NvbG9yID0gdGV4dHVyZUN1YmUoIGVudk1hcCwgdmVjMyggZmxpcEVudk1hcCAqIHZPdXRwdXREaXJlY3Rpb24ueCwgdk91dHB1dERpcmVjdGlvbi55eiApICk7XG5cblx0XHRcdH1cblx0XHRgLFxuXG5cdFx0YmxlbmRpbmc6IE5vQmxlbmRpbmcsXG5cdFx0ZGVwdGhUZXN0OiBmYWxzZSxcblx0XHRkZXB0aFdyaXRlOiBmYWxzZVxuXG5cdH0gKTtcblxufVxuXG5mdW5jdGlvbiBfZ2V0Q29tbW9uVmVydGV4U2hhZGVyKCkge1xuXG5cdHJldHVybiAvKiBnbHNsICovYFxuXG5cdFx0cHJlY2lzaW9uIG1lZGl1bXAgZmxvYXQ7XG5cdFx0cHJlY2lzaW9uIG1lZGl1bXAgaW50O1xuXG5cdFx0YXR0cmlidXRlIGZsb2F0IGZhY2VJbmRleDtcblxuXHRcdHZhcnlpbmcgdmVjMyB2T3V0cHV0RGlyZWN0aW9uO1xuXG5cdFx0Ly8gUkggY29vcmRpbmF0ZSBzeXN0ZW07IFBNUkVNIGZhY2UtaW5kZXhpbmcgY29udmVudGlvblxuXHRcdHZlYzMgZ2V0RGlyZWN0aW9uKCB2ZWMyIHV2LCBmbG9hdCBmYWNlICkge1xuXG5cdFx0XHR1diA9IDIuMCAqIHV2IC0gMS4wO1xuXG5cdFx0XHR2ZWMzIGRpcmVjdGlvbiA9IHZlYzMoIHV2LCAxLjAgKTtcblxuXHRcdFx0aWYgKCBmYWNlID09IDAuMCApIHtcblxuXHRcdFx0XHRkaXJlY3Rpb24gPSBkaXJlY3Rpb24uenl4OyAvLyAoIDEsIHYsIHUgKSBwb3MgeFxuXG5cdFx0XHR9IGVsc2UgaWYgKCBmYWNlID09IDEuMCApIHtcblxuXHRcdFx0XHRkaXJlY3Rpb24gPSBkaXJlY3Rpb24ueHp5O1xuXHRcdFx0XHRkaXJlY3Rpb24ueHogKj0gLTEuMDsgLy8gKCAtdSwgMSwgLXYgKSBwb3MgeVxuXG5cdFx0XHR9IGVsc2UgaWYgKCBmYWNlID09IDIuMCApIHtcblxuXHRcdFx0XHRkaXJlY3Rpb24ueCAqPSAtMS4wOyAvLyAoIC11LCB2LCAxICkgcG9zIHpcblxuXHRcdFx0fSBlbHNlIGlmICggZmFjZSA9PSAzLjAgKSB7XG5cblx0XHRcdFx0ZGlyZWN0aW9uID0gZGlyZWN0aW9uLnp5eDtcblx0XHRcdFx0ZGlyZWN0aW9uLnh6ICo9IC0xLjA7IC8vICggLTEsIHYsIC11ICkgbmVnIHhcblxuXHRcdFx0fSBlbHNlIGlmICggZmFjZSA9PSA0LjAgKSB7XG5cblx0XHRcdFx0ZGlyZWN0aW9uID0gZGlyZWN0aW9uLnh6eTtcblx0XHRcdFx0ZGlyZWN0aW9uLnh5ICo9IC0xLjA7IC8vICggLXUsIC0xLCB2ICkgbmVnIHlcblxuXHRcdFx0fSBlbHNlIGlmICggZmFjZSA9PSA1LjAgKSB7XG5cblx0XHRcdFx0ZGlyZWN0aW9uLnogKj0gLTEuMDsgLy8gKCB1LCB2LCAtMSApIG5lZyB6XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGRpcmVjdGlvbjtcblxuXHRcdH1cblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0dk91dHB1dERpcmVjdGlvbiA9IGdldERpcmVjdGlvbiggdXYsIGZhY2VJbmRleCApO1xuXHRcdFx0Z2xfUG9zaXRpb24gPSB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XG5cblx0XHR9XG5cdGA7XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xDdWJlVVZNYXBzKCByZW5kZXJlciApIHtcblxuXHRsZXQgY3ViZVVWbWFwcyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0bGV0IHBtcmVtR2VuZXJhdG9yID0gbnVsbDtcblxuXHRmdW5jdGlvbiBnZXQoIHRleHR1cmUgKSB7XG5cblx0XHRpZiAoIHRleHR1cmUgJiYgdGV4dHVyZS5pc1RleHR1cmUgKSB7XG5cblx0XHRcdGNvbnN0IG1hcHBpbmcgPSB0ZXh0dXJlLm1hcHBpbmc7XG5cblx0XHRcdGNvbnN0IGlzRXF1aXJlY3RNYXAgPSAoIG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nIHx8IG1hcHBpbmcgPT09IEVxdWlyZWN0YW5ndWxhclJlZnJhY3Rpb25NYXBwaW5nICk7XG5cdFx0XHRjb25zdCBpc0N1YmVNYXAgPSAoIG1hcHBpbmcgPT09IEN1YmVSZWZsZWN0aW9uTWFwcGluZyB8fCBtYXBwaW5nID09PSBDdWJlUmVmcmFjdGlvbk1hcHBpbmcgKTtcblxuXHRcdFx0Ly8gZXF1aXJlY3QvY3ViZSBtYXAgdG8gY3ViZVVWIGNvbnZlcnNpb25cblxuXHRcdFx0aWYgKCBpc0VxdWlyZWN0TWFwIHx8IGlzQ3ViZU1hcCApIHtcblxuXHRcdFx0XHRsZXQgcmVuZGVyVGFyZ2V0ID0gY3ViZVVWbWFwcy5nZXQoIHRleHR1cmUgKTtcblxuXHRcdFx0XHRjb25zdCBjdXJyZW50UE1SRU1WZXJzaW9uID0gcmVuZGVyVGFyZ2V0ICE9PSB1bmRlZmluZWQgPyByZW5kZXJUYXJnZXQudGV4dHVyZS5wbXJlbVZlcnNpb24gOiAwO1xuXG5cdFx0XHRcdGlmICggdGV4dHVyZS5pc1JlbmRlclRhcmdldFRleHR1cmUgJiYgdGV4dHVyZS5wbXJlbVZlcnNpb24gIT09IGN1cnJlbnRQTVJFTVZlcnNpb24gKSB7XG5cblx0XHRcdFx0XHRpZiAoIHBtcmVtR2VuZXJhdG9yID09PSBudWxsICkgcG1yZW1HZW5lcmF0b3IgPSBuZXcgUE1SRU1HZW5lcmF0b3IoIHJlbmRlcmVyICk7XG5cblx0XHRcdFx0XHRyZW5kZXJUYXJnZXQgPSBpc0VxdWlyZWN0TWFwID8gcG1yZW1HZW5lcmF0b3IuZnJvbUVxdWlyZWN0YW5ndWxhciggdGV4dHVyZSwgcmVuZGVyVGFyZ2V0ICkgOiBwbXJlbUdlbmVyYXRvci5mcm9tQ3ViZW1hcCggdGV4dHVyZSwgcmVuZGVyVGFyZ2V0ICk7XG5cdFx0XHRcdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUucG1yZW1WZXJzaW9uID0gdGV4dHVyZS5wbXJlbVZlcnNpb247XG5cblx0XHRcdFx0XHRjdWJlVVZtYXBzLnNldCggdGV4dHVyZSwgcmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRcdFx0XHRyZXR1cm4gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRcdHJldHVybiByZW5kZXJUYXJnZXQudGV4dHVyZTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGltYWdlID0gdGV4dHVyZS5pbWFnZTtcblxuXHRcdFx0XHRcdFx0aWYgKCAoIGlzRXF1aXJlY3RNYXAgJiYgaW1hZ2UgJiYgaW1hZ2UuaGVpZ2h0ID4gMCApIHx8ICggaXNDdWJlTWFwICYmIGltYWdlICYmIGlzQ3ViZVRleHR1cmVDb21wbGV0ZSggaW1hZ2UgKSApICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggcG1yZW1HZW5lcmF0b3IgPT09IG51bGwgKSBwbXJlbUdlbmVyYXRvciA9IG5ldyBQTVJFTUdlbmVyYXRvciggcmVuZGVyZXIgKTtcblxuXHRcdFx0XHRcdFx0XHRyZW5kZXJUYXJnZXQgPSBpc0VxdWlyZWN0TWFwID8gcG1yZW1HZW5lcmF0b3IuZnJvbUVxdWlyZWN0YW5ndWxhciggdGV4dHVyZSApIDogcG1yZW1HZW5lcmF0b3IuZnJvbUN1YmVtYXAoIHRleHR1cmUgKTtcblx0XHRcdFx0XHRcdFx0cmVuZGVyVGFyZ2V0LnRleHR1cmUucG1yZW1WZXJzaW9uID0gdGV4dHVyZS5wbXJlbVZlcnNpb247XG5cblx0XHRcdFx0XHRcdFx0Y3ViZVVWbWFwcy5zZXQoIHRleHR1cmUsIHJlbmRlclRhcmdldCApO1xuXG5cdFx0XHRcdFx0XHRcdHRleHR1cmUuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XG5cblx0XHRcdFx0XHRcdFx0cmV0dXJuIHJlbmRlclRhcmdldC50ZXh0dXJlO1xuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdC8vIGltYWdlIG5vdCB5ZXQgcmVhZHkuIHRyeSB0aGUgY29udmVyc2lvbiBuZXh0IGZyYW1lXG5cblx0XHRcdFx0XHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0ZXh0dXJlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBpc0N1YmVUZXh0dXJlQ29tcGxldGUoIGltYWdlICkge1xuXG5cdFx0bGV0IGNvdW50ID0gMDtcblx0XHRjb25zdCBsZW5ndGggPSA2O1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRpZiAoIGltYWdlWyBpIF0gIT09IHVuZGVmaW5lZCApIGNvdW50ICsrO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGNvdW50ID09PSBsZW5ndGg7XG5cblxuXHR9XG5cblx0ZnVuY3Rpb24gb25UZXh0dXJlRGlzcG9zZSggZXZlbnQgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlID0gZXZlbnQudGFyZ2V0O1xuXG5cdFx0dGV4dHVyZS5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVGV4dHVyZURpc3Bvc2UgKTtcblxuXHRcdGNvbnN0IGN1YmVtYXBVViA9IGN1YmVVVm1hcHMuZ2V0KCB0ZXh0dXJlICk7XG5cblx0XHRpZiAoIGN1YmVtYXBVViAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjdWJlVVZtYXBzLmRlbGV0ZSggdGV4dHVyZSApO1xuXHRcdFx0Y3ViZW1hcFVWLmRpc3Bvc2UoKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gZGlzcG9zZSgpIHtcblxuXHRcdGN1YmVVVm1hcHMgPSBuZXcgV2Vha01hcCgpO1xuXG5cdFx0aWYgKCBwbXJlbUdlbmVyYXRvciAhPT0gbnVsbCApIHtcblxuXHRcdFx0cG1yZW1HZW5lcmF0b3IuZGlzcG9zZSgpO1xuXHRcdFx0cG1yZW1HZW5lcmF0b3IgPSBudWxsO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4ge1xuXHRcdGdldDogZ2V0LFxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2Vcblx0fTtcblxufVxuXG5mdW5jdGlvbiBXZWJHTEV4dGVuc2lvbnMoIGdsICkge1xuXG5cdGNvbnN0IGV4dGVuc2lvbnMgPSB7fTtcblxuXHRmdW5jdGlvbiBnZXRFeHRlbnNpb24oIG5hbWUgKSB7XG5cblx0XHRpZiAoIGV4dGVuc2lvbnNbIG5hbWUgXSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRyZXR1cm4gZXh0ZW5zaW9uc1sgbmFtZSBdO1xuXG5cdFx0fVxuXG5cdFx0bGV0IGV4dGVuc2lvbjtcblxuXHRcdHN3aXRjaCAoIG5hbWUgKSB7XG5cblx0XHRcdGNhc2UgJ1dFQkdMX2RlcHRoX3RleHR1cmUnOlxuXHRcdFx0XHRleHRlbnNpb24gPSBnbC5nZXRFeHRlbnNpb24oICdXRUJHTF9kZXB0aF90ZXh0dXJlJyApIHx8IGdsLmdldEV4dGVuc2lvbiggJ01PWl9XRUJHTF9kZXB0aF90ZXh0dXJlJyApIHx8IGdsLmdldEV4dGVuc2lvbiggJ1dFQktJVF9XRUJHTF9kZXB0aF90ZXh0dXJlJyApO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJzpcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJyApIHx8IGdsLmdldEV4dGVuc2lvbiggJ01PWl9FWFRfdGV4dHVyZV9maWx0ZXJfYW5pc290cm9waWMnICkgfHwgZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCS0lUX0VYVF90ZXh0dXJlX2ZpbHRlcl9hbmlzb3Ryb3BpYycgKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9zM3RjJzpcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3MzdGMnICkgfHwgZ2wuZ2V0RXh0ZW5zaW9uKCAnTU9aX1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9zM3RjJyApIHx8IGdsLmdldEV4dGVuc2lvbiggJ1dFQktJVF9XRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfczN0YycgKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9wdnJ0Yyc6XG5cdFx0XHRcdGV4dGVuc2lvbiA9IGdsLmdldEV4dGVuc2lvbiggJ1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9wdnJ0YycgKSB8fCBnbC5nZXRFeHRlbnNpb24oICdXRUJLSVRfV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3B2cnRjJyApO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0ZGVmYXVsdDpcblx0XHRcdFx0ZXh0ZW5zaW9uID0gZ2wuZ2V0RXh0ZW5zaW9uKCBuYW1lICk7XG5cblx0XHR9XG5cblx0XHRleHRlbnNpb25zWyBuYW1lIF0gPSBleHRlbnNpb247XG5cblx0XHRyZXR1cm4gZXh0ZW5zaW9uO1xuXG5cdH1cblxuXHRyZXR1cm4ge1xuXG5cdFx0aGFzOiBmdW5jdGlvbiAoIG5hbWUgKSB7XG5cblx0XHRcdHJldHVybiBnZXRFeHRlbnNpb24oIG5hbWUgKSAhPT0gbnVsbDtcblxuXHRcdH0sXG5cblx0XHRpbml0OiBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdGdldEV4dGVuc2lvbiggJ0VYVF9jb2xvcl9idWZmZXJfZmxvYXQnICk7XG5cdFx0XHRnZXRFeHRlbnNpb24oICdXRUJHTF9jbGlwX2N1bGxfZGlzdGFuY2UnICk7XG5cdFx0XHRnZXRFeHRlbnNpb24oICdPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXInICk7XG5cdFx0XHRnZXRFeHRlbnNpb24oICdFWFRfY29sb3JfYnVmZmVyX2hhbGZfZmxvYXQnICk7XG5cdFx0XHRnZXRFeHRlbnNpb24oICdXRUJHTF9tdWx0aXNhbXBsZWRfcmVuZGVyX3RvX3RleHR1cmUnICk7XG5cdFx0XHRnZXRFeHRlbnNpb24oICdXRUJHTF9yZW5kZXJfc2hhcmVkX2V4cG9uZW50JyApO1xuXG5cdFx0fSxcblxuXHRcdGdldDogZnVuY3Rpb24gKCBuYW1lICkge1xuXG5cdFx0XHRjb25zdCBleHRlbnNpb24gPSBnZXRFeHRlbnNpb24oIG5hbWUgKTtcblxuXHRcdFx0aWYgKCBleHRlbnNpb24gPT09IG51bGwgKSB7XG5cblx0XHRcdFx0d2Fybk9uY2UoICdUSFJFRS5XZWJHTFJlbmRlcmVyOiAnICsgbmFtZSArICcgZXh0ZW5zaW9uIG5vdCBzdXBwb3J0ZWQuJyApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBleHRlbnNpb247XG5cblx0XHR9XG5cblx0fTtcblxufVxuXG5mdW5jdGlvbiBXZWJHTEdlb21ldHJpZXMoIGdsLCBhdHRyaWJ1dGVzLCBpbmZvLCBiaW5kaW5nU3RhdGVzICkge1xuXG5cdGNvbnN0IGdlb21ldHJpZXMgPSB7fTtcblx0Y29uc3Qgd2lyZWZyYW1lQXR0cmlidXRlcyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0ZnVuY3Rpb24gb25HZW9tZXRyeURpc3Bvc2UoIGV2ZW50ICkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBldmVudC50YXJnZXQ7XG5cblx0XHRpZiAoIGdlb21ldHJ5LmluZGV4ICE9PSBudWxsICkge1xuXG5cdFx0XHRhdHRyaWJ1dGVzLnJlbW92ZSggZ2VvbWV0cnkuaW5kZXggKTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gZ2VvbWV0cnkuYXR0cmlidXRlcyApIHtcblxuXHRcdFx0YXR0cmlidXRlcy5yZW1vdmUoIGdlb21ldHJ5LmF0dHJpYnV0ZXNbIG5hbWUgXSApO1xuXG5cdFx0fVxuXG5cdFx0Zm9yICggY29uc3QgbmFtZSBpbiBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdGNvbnN0IGFycmF5ID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzWyBuYW1lIF07XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGFycmF5Lmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0YXR0cmlidXRlcy5yZW1vdmUoIGFycmF5WyBpIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Z2VvbWV0cnkucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvbkdlb21ldHJ5RGlzcG9zZSApO1xuXG5cdFx0ZGVsZXRlIGdlb21ldHJpZXNbIGdlb21ldHJ5LmlkIF07XG5cblx0XHRjb25zdCBhdHRyaWJ1dGUgPSB3aXJlZnJhbWVBdHRyaWJ1dGVzLmdldCggZ2VvbWV0cnkgKTtcblxuXHRcdGlmICggYXR0cmlidXRlICkge1xuXG5cdFx0XHRhdHRyaWJ1dGVzLnJlbW92ZSggYXR0cmlidXRlICk7XG5cdFx0XHR3aXJlZnJhbWVBdHRyaWJ1dGVzLmRlbGV0ZSggZ2VvbWV0cnkgKTtcblxuXHRcdH1cblxuXHRcdGJpbmRpbmdTdGF0ZXMucmVsZWFzZVN0YXRlc09mR2VvbWV0cnkoIGdlb21ldHJ5ICk7XG5cblx0XHRpZiAoIGdlb21ldHJ5LmlzSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgPT09IHRydWUgKSB7XG5cblx0XHRcdGRlbGV0ZSBnZW9tZXRyeS5fbWF4SW5zdGFuY2VDb3VudDtcblxuXHRcdH1cblxuXHRcdC8vXG5cblx0XHRpbmZvLm1lbW9yeS5nZW9tZXRyaWVzIC0tO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBnZXQoIG9iamVjdCwgZ2VvbWV0cnkgKSB7XG5cblx0XHRpZiAoIGdlb21ldHJpZXNbIGdlb21ldHJ5LmlkIF0gPT09IHRydWUgKSByZXR1cm4gZ2VvbWV0cnk7XG5cblx0XHRnZW9tZXRyeS5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uR2VvbWV0cnlEaXNwb3NlICk7XG5cblx0XHRnZW9tZXRyaWVzWyBnZW9tZXRyeS5pZCBdID0gdHJ1ZTtcblxuXHRcdGluZm8ubWVtb3J5Lmdlb21ldHJpZXMgKys7XG5cblx0XHRyZXR1cm4gZ2VvbWV0cnk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHVwZGF0ZSggZ2VvbWV0cnkgKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeUF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzO1xuXG5cdFx0Ly8gVXBkYXRpbmcgaW5kZXggYnVmZmVyIGluIFZBTyBub3cuIFNlZSBXZWJHTEJpbmRpbmdTdGF0ZXMuXG5cblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIGdlb21ldHJ5QXR0cmlidXRlcyApIHtcblxuXHRcdFx0YXR0cmlidXRlcy51cGRhdGUoIGdlb21ldHJ5QXR0cmlidXRlc1sgbmFtZSBdLCBnbC5BUlJBWV9CVUZGRVIgKTtcblxuXHRcdH1cblxuXHRcdC8vIG1vcnBoIHRhcmdldHNcblxuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlcyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcztcblxuXHRcdGZvciAoIGNvbnN0IG5hbWUgaW4gbW9ycGhBdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRjb25zdCBhcnJheSA9IG1vcnBoQXR0cmlidXRlc1sgbmFtZSBdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBhcnJheS5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBhcnJheVsgaSBdLCBnbC5BUlJBWV9CVUZGRVIgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB1cGRhdGVXaXJlZnJhbWVBdHRyaWJ1dGUoIGdlb21ldHJ5ICkge1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnlJbmRleCA9IGdlb21ldHJ5LmluZGV4O1xuXHRcdGNvbnN0IGdlb21ldHJ5UG9zaXRpb24gPSBnZW9tZXRyeS5hdHRyaWJ1dGVzLnBvc2l0aW9uO1xuXHRcdGxldCB2ZXJzaW9uID0gMDtcblxuXHRcdGlmICggZ2VvbWV0cnlJbmRleCAhPT0gbnVsbCApIHtcblxuXHRcdFx0Y29uc3QgYXJyYXkgPSBnZW9tZXRyeUluZGV4LmFycmF5O1xuXHRcdFx0dmVyc2lvbiA9IGdlb21ldHJ5SW5kZXgudmVyc2lvbjtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gYXJyYXkubGVuZ3RoOyBpIDwgbDsgaSArPSAzICkge1xuXG5cdFx0XHRcdGNvbnN0IGEgPSBhcnJheVsgaSArIDAgXTtcblx0XHRcdFx0Y29uc3QgYiA9IGFycmF5WyBpICsgMSBdO1xuXHRcdFx0XHRjb25zdCBjID0gYXJyYXlbIGkgKyAyIF07XG5cblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBhLCBiLCBiLCBjLCBjLCBhICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSBpZiAoIGdlb21ldHJ5UG9zaXRpb24gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3QgYXJyYXkgPSBnZW9tZXRyeVBvc2l0aW9uLmFycmF5O1xuXHRcdFx0dmVyc2lvbiA9IGdlb21ldHJ5UG9zaXRpb24udmVyc2lvbjtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gKCBhcnJheS5sZW5ndGggLyAzICkgLSAxOyBpIDwgbDsgaSArPSAzICkge1xuXG5cdFx0XHRcdGNvbnN0IGEgPSBpICsgMDtcblx0XHRcdFx0Y29uc3QgYiA9IGkgKyAxO1xuXHRcdFx0XHRjb25zdCBjID0gaSArIDI7XG5cblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBhLCBiLCBiLCBjLCBjLCBhICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGF0dHJpYnV0ZSA9IG5ldyAoIGFycmF5TmVlZHNVaW50MzIoIGluZGljZXMgKSA/IFVpbnQzMkJ1ZmZlckF0dHJpYnV0ZSA6IFVpbnQxNkJ1ZmZlckF0dHJpYnV0ZSApKCBpbmRpY2VzLCAxICk7XG5cdFx0YXR0cmlidXRlLnZlcnNpb24gPSB2ZXJzaW9uO1xuXG5cdFx0Ly8gVXBkYXRpbmcgaW5kZXggYnVmZmVyIGluIFZBTyBub3cuIFNlZSBXZWJHTEJpbmRpbmdTdGF0ZXNcblxuXHRcdC8vXG5cblx0XHRjb25zdCBwcmV2aW91c0F0dHJpYnV0ZSA9IHdpcmVmcmFtZUF0dHJpYnV0ZXMuZ2V0KCBnZW9tZXRyeSApO1xuXG5cdFx0aWYgKCBwcmV2aW91c0F0dHJpYnV0ZSApIGF0dHJpYnV0ZXMucmVtb3ZlKCBwcmV2aW91c0F0dHJpYnV0ZSApO1xuXG5cdFx0Ly9cblxuXHRcdHdpcmVmcmFtZUF0dHJpYnV0ZXMuc2V0KCBnZW9tZXRyeSwgYXR0cmlidXRlICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldFdpcmVmcmFtZUF0dHJpYnV0ZSggZ2VvbWV0cnkgKSB7XG5cblx0XHRjb25zdCBjdXJyZW50QXR0cmlidXRlID0gd2lyZWZyYW1lQXR0cmlidXRlcy5nZXQoIGdlb21ldHJ5ICk7XG5cblx0XHRpZiAoIGN1cnJlbnRBdHRyaWJ1dGUgKSB7XG5cblx0XHRcdGNvbnN0IGdlb21ldHJ5SW5kZXggPSBnZW9tZXRyeS5pbmRleDtcblxuXHRcdFx0aWYgKCBnZW9tZXRyeUluZGV4ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdC8vIGlmIHRoZSBhdHRyaWJ1dGUgaXMgb2Jzb2xldGUsIGNyZWF0ZSBhIG5ldyBvbmVcblxuXHRcdFx0XHRpZiAoIGN1cnJlbnRBdHRyaWJ1dGUudmVyc2lvbiA8IGdlb21ldHJ5SW5kZXgudmVyc2lvbiApIHtcblxuXHRcdFx0XHRcdHVwZGF0ZVdpcmVmcmFtZUF0dHJpYnV0ZSggZ2VvbWV0cnkgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHVwZGF0ZVdpcmVmcmFtZUF0dHJpYnV0ZSggZ2VvbWV0cnkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB3aXJlZnJhbWVBdHRyaWJ1dGVzLmdldCggZ2VvbWV0cnkgKTtcblxuXHR9XG5cblx0cmV0dXJuIHtcblxuXHRcdGdldDogZ2V0LFxuXHRcdHVwZGF0ZTogdXBkYXRlLFxuXG5cdFx0Z2V0V2lyZWZyYW1lQXR0cmlidXRlOiBnZXRXaXJlZnJhbWVBdHRyaWJ1dGVcblxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMSW5kZXhlZEJ1ZmZlclJlbmRlcmVyKCBnbCwgZXh0ZW5zaW9ucywgaW5mbyApIHtcblxuXHRsZXQgbW9kZTtcblxuXHRmdW5jdGlvbiBzZXRNb2RlKCB2YWx1ZSApIHtcblxuXHRcdG1vZGUgPSB2YWx1ZTtcblxuXHR9XG5cblx0bGV0IHR5cGUsIGJ5dGVzUGVyRWxlbWVudDtcblxuXHRmdW5jdGlvbiBzZXRJbmRleCggdmFsdWUgKSB7XG5cblx0XHR0eXBlID0gdmFsdWUudHlwZTtcblx0XHRieXRlc1BlckVsZW1lbnQgPSB2YWx1ZS5ieXRlc1BlckVsZW1lbnQ7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlbmRlciggc3RhcnQsIGNvdW50ICkge1xuXG5cdFx0Z2wuZHJhd0VsZW1lbnRzKCBtb2RlLCBjb3VudCwgdHlwZSwgc3RhcnQgKiBieXRlc1BlckVsZW1lbnQgKTtcblxuXHRcdGluZm8udXBkYXRlKCBjb3VudCwgbW9kZSwgMSApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXJJbnN0YW5jZXMoIHN0YXJ0LCBjb3VudCwgcHJpbWNvdW50ICkge1xuXG5cdFx0aWYgKCBwcmltY291bnQgPT09IDAgKSByZXR1cm47XG5cblx0XHRnbC5kcmF3RWxlbWVudHNJbnN0YW5jZWQoIG1vZGUsIGNvdW50LCB0eXBlLCBzdGFydCAqIGJ5dGVzUGVyRWxlbWVudCwgcHJpbWNvdW50ICk7XG5cblx0XHRpbmZvLnVwZGF0ZSggY291bnQsIG1vZGUsIHByaW1jb3VudCApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiByZW5kZXJNdWx0aURyYXcoIHN0YXJ0cywgY291bnRzLCBkcmF3Q291bnQgKSB7XG5cblx0XHRpZiAoIGRyYXdDb3VudCA9PT0gMCApIHJldHVybjtcblxuXHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbXVsdGlfZHJhdycgKTtcblx0XHRleHRlbnNpb24ubXVsdGlEcmF3RWxlbWVudHNXRUJHTCggbW9kZSwgY291bnRzLCAwLCB0eXBlLCBzdGFydHMsIDAsIGRyYXdDb3VudCApO1xuXG5cdFx0bGV0IGVsZW1lbnRDb3VudCA9IDA7XG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZHJhd0NvdW50OyBpICsrICkge1xuXG5cdFx0XHRlbGVtZW50Q291bnQgKz0gY291bnRzWyBpIF07XG5cblx0XHR9XG5cblx0XHRpbmZvLnVwZGF0ZSggZWxlbWVudENvdW50LCBtb2RlLCAxICk7XG5cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVuZGVyTXVsdGlEcmF3SW5zdGFuY2VzKCBzdGFydHMsIGNvdW50cywgZHJhd0NvdW50LCBwcmltY291bnQgKSB7XG5cblx0XHRpZiAoIGRyYXdDb3VudCA9PT0gMCApIHJldHVybjtcblxuXHRcdGNvbnN0IGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfbXVsdGlfZHJhdycgKTtcblxuXHRcdGlmICggZXh0ZW5zaW9uID09PSBudWxsICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzdGFydHMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdHJlbmRlckluc3RhbmNlcyggc3RhcnRzWyBpIF0gLyBieXRlc1BlckVsZW1lbnQsIGNvdW50c1sgaSBdLCBwcmltY291bnRbIGkgXSApO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRleHRlbnNpb24ubXVsdGlEcmF3RWxlbWVudHNJbnN0YW5jZWRXRUJHTCggbW9kZSwgY291bnRzLCAwLCB0eXBlLCBzdGFydHMsIDAsIHByaW1jb3VudCwgMCwgZHJhd0NvdW50ICk7XG5cblx0XHRcdGxldCBlbGVtZW50Q291bnQgPSAwO1xuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZHJhd0NvdW50OyBpICsrICkge1xuXG5cdFx0XHRcdGVsZW1lbnRDb3VudCArPSBjb3VudHNbIGkgXTtcblxuXHRcdFx0fVxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBwcmltY291bnQubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGluZm8udXBkYXRlKCBlbGVtZW50Q291bnQsIG1vZGUsIHByaW1jb3VudFsgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0Ly9cblxuXHR0aGlzLnNldE1vZGUgPSBzZXRNb2RlO1xuXHR0aGlzLnNldEluZGV4ID0gc2V0SW5kZXg7XG5cdHRoaXMucmVuZGVyID0gcmVuZGVyO1xuXHR0aGlzLnJlbmRlckluc3RhbmNlcyA9IHJlbmRlckluc3RhbmNlcztcblx0dGhpcy5yZW5kZXJNdWx0aURyYXcgPSByZW5kZXJNdWx0aURyYXc7XG5cdHRoaXMucmVuZGVyTXVsdGlEcmF3SW5zdGFuY2VzID0gcmVuZGVyTXVsdGlEcmF3SW5zdGFuY2VzO1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMSW5mbyggZ2wgKSB7XG5cblx0Y29uc3QgbWVtb3J5ID0ge1xuXHRcdGdlb21ldHJpZXM6IDAsXG5cdFx0dGV4dHVyZXM6IDBcblx0fTtcblxuXHRjb25zdCByZW5kZXIgPSB7XG5cdFx0ZnJhbWU6IDAsXG5cdFx0Y2FsbHM6IDAsXG5cdFx0dHJpYW5nbGVzOiAwLFxuXHRcdHBvaW50czogMCxcblx0XHRsaW5lczogMFxuXHR9O1xuXG5cdGZ1bmN0aW9uIHVwZGF0ZSggY291bnQsIG1vZGUsIGluc3RhbmNlQ291bnQgKSB7XG5cblx0XHRyZW5kZXIuY2FsbHMgKys7XG5cblx0XHRzd2l0Y2ggKCBtb2RlICkge1xuXG5cdFx0XHRjYXNlIGdsLlRSSUFOR0xFUzpcblx0XHRcdFx0cmVuZGVyLnRyaWFuZ2xlcyArPSBpbnN0YW5jZUNvdW50ICogKCBjb3VudCAvIDMgKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgZ2wuTElORVM6XG5cdFx0XHRcdHJlbmRlci5saW5lcyArPSBpbnN0YW5jZUNvdW50ICogKCBjb3VudCAvIDIgKTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgZ2wuTElORV9TVFJJUDpcblx0XHRcdFx0cmVuZGVyLmxpbmVzICs9IGluc3RhbmNlQ291bnQgKiAoIGNvdW50IC0gMSApO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSBnbC5MSU5FX0xPT1A6XG5cdFx0XHRcdHJlbmRlci5saW5lcyArPSBpbnN0YW5jZUNvdW50ICogY291bnQ7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlIGdsLlBPSU5UUzpcblx0XHRcdFx0cmVuZGVyLnBvaW50cyArPSBpbnN0YW5jZUNvdW50ICogY291bnQ7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xJbmZvOiBVbmtub3duIGRyYXcgbW9kZTonLCBtb2RlICk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiByZXNldCgpIHtcblxuXHRcdHJlbmRlci5jYWxscyA9IDA7XG5cdFx0cmVuZGVyLnRyaWFuZ2xlcyA9IDA7XG5cdFx0cmVuZGVyLnBvaW50cyA9IDA7XG5cdFx0cmVuZGVyLmxpbmVzID0gMDtcblxuXHR9XG5cblx0cmV0dXJuIHtcblx0XHRtZW1vcnk6IG1lbW9yeSxcblx0XHRyZW5kZXI6IHJlbmRlcixcblx0XHRwcm9ncmFtczogbnVsbCxcblx0XHRhdXRvUmVzZXQ6IHRydWUsXG5cdFx0cmVzZXQ6IHJlc2V0LFxuXHRcdHVwZGF0ZTogdXBkYXRlXG5cdH07XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xNb3JwaHRhcmdldHMoIGdsLCBjYXBhYmlsaXRpZXMsIHRleHR1cmVzICkge1xuXG5cdGNvbnN0IG1vcnBoVGV4dHVyZXMgPSBuZXcgV2Vha01hcCgpO1xuXHRjb25zdCBtb3JwaCA9IG5ldyBWZWN0b3I0KCk7XG5cblx0ZnVuY3Rpb24gdXBkYXRlKCBvYmplY3QsIGdlb21ldHJ5LCBwcm9ncmFtICkge1xuXG5cdFx0Y29uc3Qgb2JqZWN0SW5mbHVlbmNlcyA9IG9iamVjdC5tb3JwaFRhcmdldEluZmx1ZW5jZXM7XG5cblx0XHQvLyB0aGUgZm9sbG93aW5nIGVuY29kZXMgbW9ycGggdGFyZ2V0cyBpbnRvIGFuIGFycmF5IG9mIGRhdGEgdGV4dHVyZXMuIEVhY2ggbGF5ZXIgcmVwcmVzZW50cyBhIHNpbmdsZSBtb3JwaCB0YXJnZXQuXG5cblx0XHRjb25zdCBtb3JwaEF0dHJpYnV0ZSA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiB8fCBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsIHx8IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvcjtcblx0XHRjb25zdCBtb3JwaFRhcmdldHNDb3VudCA9ICggbW9ycGhBdHRyaWJ1dGUgIT09IHVuZGVmaW5lZCApID8gbW9ycGhBdHRyaWJ1dGUubGVuZ3RoIDogMDtcblxuXHRcdGxldCBlbnRyeSA9IG1vcnBoVGV4dHVyZXMuZ2V0KCBnZW9tZXRyeSApO1xuXG5cdFx0aWYgKCBlbnRyeSA9PT0gdW5kZWZpbmVkIHx8IGVudHJ5LmNvdW50ICE9PSBtb3JwaFRhcmdldHNDb3VudCApIHtcblxuXHRcdFx0aWYgKCBlbnRyeSAhPT0gdW5kZWZpbmVkICkgZW50cnkudGV4dHVyZS5kaXNwb3NlKCk7XG5cblx0XHRcdGNvbnN0IGhhc01vcnBoUG9zaXRpb24gPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb24gIT09IHVuZGVmaW5lZDtcblx0XHRcdGNvbnN0IGhhc01vcnBoTm9ybWFscyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5ub3JtYWwgIT09IHVuZGVmaW5lZDtcblx0XHRcdGNvbnN0IGhhc01vcnBoQ29sb3JzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yICE9PSB1bmRlZmluZWQ7XG5cblx0XHRcdGNvbnN0IG1vcnBoVGFyZ2V0cyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiB8fCBbXTtcblx0XHRcdGNvbnN0IG1vcnBoTm9ybWFscyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5ub3JtYWwgfHwgW107XG5cdFx0XHRjb25zdCBtb3JwaENvbG9ycyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvciB8fCBbXTtcblxuXHRcdFx0bGV0IHZlcnRleERhdGFDb3VudCA9IDA7XG5cblx0XHRcdGlmICggaGFzTW9ycGhQb3NpdGlvbiA9PT0gdHJ1ZSApIHZlcnRleERhdGFDb3VudCA9IDE7XG5cdFx0XHRpZiAoIGhhc01vcnBoTm9ybWFscyA9PT0gdHJ1ZSApIHZlcnRleERhdGFDb3VudCA9IDI7XG5cdFx0XHRpZiAoIGhhc01vcnBoQ29sb3JzID09PSB0cnVlICkgdmVydGV4RGF0YUNvdW50ID0gMztcblxuXHRcdFx0bGV0IHdpZHRoID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbi5jb3VudCAqIHZlcnRleERhdGFDb3VudDtcblx0XHRcdGxldCBoZWlnaHQgPSAxO1xuXG5cdFx0XHRpZiAoIHdpZHRoID4gY2FwYWJpbGl0aWVzLm1heFRleHR1cmVTaXplICkge1xuXG5cdFx0XHRcdGhlaWdodCA9IE1hdGguY2VpbCggd2lkdGggLyBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemUgKTtcblx0XHRcdFx0d2lkdGggPSBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemU7XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgYnVmZmVyID0gbmV3IEZsb2F0MzJBcnJheSggd2lkdGggKiBoZWlnaHQgKiA0ICogbW9ycGhUYXJnZXRzQ291bnQgKTtcblxuXHRcdFx0Y29uc3QgdGV4dHVyZSA9IG5ldyBEYXRhQXJyYXlUZXh0dXJlKCBidWZmZXIsIHdpZHRoLCBoZWlnaHQsIG1vcnBoVGFyZ2V0c0NvdW50ICk7XG5cdFx0XHR0ZXh0dXJlLnR5cGUgPSBGbG9hdFR5cGU7XG5cdFx0XHR0ZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdFx0Ly8gZmlsbCBidWZmZXJcblxuXHRcdFx0Y29uc3QgdmVydGV4RGF0YVN0cmlkZSA9IHZlcnRleERhdGFDb3VudCAqIDQ7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG1vcnBoVGFyZ2V0c0NvdW50OyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IG1vcnBoVGFyZ2V0ID0gbW9ycGhUYXJnZXRzWyBpIF07XG5cdFx0XHRcdGNvbnN0IG1vcnBoTm9ybWFsID0gbW9ycGhOb3JtYWxzWyBpIF07XG5cdFx0XHRcdGNvbnN0IG1vcnBoQ29sb3IgPSBtb3JwaENvbG9yc1sgaSBdO1xuXG5cdFx0XHRcdGNvbnN0IG9mZnNldCA9IHdpZHRoICogaGVpZ2h0ICogNCAqIGk7XG5cblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgbW9ycGhUYXJnZXQuY291bnQ7IGogKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBzdHJpZGUgPSBqICogdmVydGV4RGF0YVN0cmlkZTtcblxuXHRcdFx0XHRcdGlmICggaGFzTW9ycGhQb3NpdGlvbiA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdFx0bW9ycGguZnJvbUJ1ZmZlckF0dHJpYnV0ZSggbW9ycGhUYXJnZXQsIGogKTtcblxuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAwIF0gPSBtb3JwaC54O1xuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAxIF0gPSBtb3JwaC55O1xuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAyIF0gPSBtb3JwaC56O1xuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAzIF0gPSAwO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCBoYXNNb3JwaE5vcm1hbHMgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRcdG1vcnBoLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoTm9ybWFsLCBqICk7XG5cblx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgNCBdID0gbW9ycGgueDtcblx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgNSBdID0gbW9ycGgueTtcblx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgNiBdID0gbW9ycGguejtcblx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgNyBdID0gMDtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggaGFzTW9ycGhDb2xvcnMgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRcdG1vcnBoLmZyb21CdWZmZXJBdHRyaWJ1dGUoIG1vcnBoQ29sb3IsIGogKTtcblxuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyA4IF0gPSBtb3JwaC54O1xuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyA5IF0gPSBtb3JwaC55O1xuXHRcdFx0XHRcdFx0YnVmZmVyWyBvZmZzZXQgKyBzdHJpZGUgKyAxMCBdID0gbW9ycGguejtcblx0XHRcdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgc3RyaWRlICsgMTEgXSA9ICggbW9ycGhDb2xvci5pdGVtU2l6ZSA9PT0gNCApID8gbW9ycGgudyA6IDE7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGVudHJ5ID0ge1xuXHRcdFx0XHRjb3VudDogbW9ycGhUYXJnZXRzQ291bnQsXG5cdFx0XHRcdHRleHR1cmU6IHRleHR1cmUsXG5cdFx0XHRcdHNpemU6IG5ldyBWZWN0b3IyKCB3aWR0aCwgaGVpZ2h0IClcblx0XHRcdH07XG5cblx0XHRcdG1vcnBoVGV4dHVyZXMuc2V0KCBnZW9tZXRyeSwgZW50cnkgKTtcblxuXHRcdFx0ZnVuY3Rpb24gZGlzcG9zZVRleHR1cmUoKSB7XG5cblx0XHRcdFx0dGV4dHVyZS5kaXNwb3NlKCk7XG5cblx0XHRcdFx0bW9ycGhUZXh0dXJlcy5kZWxldGUoIGdlb21ldHJ5ICk7XG5cblx0XHRcdFx0Z2VvbWV0cnkucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBkaXNwb3NlVGV4dHVyZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGdlb21ldHJ5LmFkZEV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgZGlzcG9zZVRleHR1cmUgKTtcblxuXHRcdH1cblxuXHRcdC8vXG5cdFx0aWYgKCBvYmplY3QuaXNJbnN0YW5jZWRNZXNoID09PSB0cnVlICYmIG9iamVjdC5tb3JwaFRleHR1cmUgIT09IG51bGwgKSB7XG5cblx0XHRcdHByb2dyYW0uZ2V0VW5pZm9ybXMoKS5zZXRWYWx1ZSggZ2wsICdtb3JwaFRleHR1cmUnLCBvYmplY3QubW9ycGhUZXh0dXJlLCB0ZXh0dXJlcyApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0bGV0IG1vcnBoSW5mbHVlbmNlc1N1bSA9IDA7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG9iamVjdEluZmx1ZW5jZXMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdG1vcnBoSW5mbHVlbmNlc1N1bSArPSBvYmplY3RJbmZsdWVuY2VzWyBpIF07XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgbW9ycGhCYXNlSW5mbHVlbmNlID0gZ2VvbWV0cnkubW9ycGhUYXJnZXRzUmVsYXRpdmUgPyAxIDogMSAtIG1vcnBoSW5mbHVlbmNlc1N1bTtcblxuXG5cdFx0XHRwcm9ncmFtLmdldFVuaWZvcm1zKCkuc2V0VmFsdWUoIGdsLCAnbW9ycGhUYXJnZXRCYXNlSW5mbHVlbmNlJywgbW9ycGhCYXNlSW5mbHVlbmNlICk7XG5cdFx0XHRwcm9ncmFtLmdldFVuaWZvcm1zKCkuc2V0VmFsdWUoIGdsLCAnbW9ycGhUYXJnZXRJbmZsdWVuY2VzJywgb2JqZWN0SW5mbHVlbmNlcyApO1xuXG5cdFx0fVxuXG5cdFx0cHJvZ3JhbS5nZXRVbmlmb3JtcygpLnNldFZhbHVlKCBnbCwgJ21vcnBoVGFyZ2V0c1RleHR1cmUnLCBlbnRyeS50ZXh0dXJlLCB0ZXh0dXJlcyApO1xuXHRcdHByb2dyYW0uZ2V0VW5pZm9ybXMoKS5zZXRWYWx1ZSggZ2wsICdtb3JwaFRhcmdldHNUZXh0dXJlU2l6ZScsIGVudHJ5LnNpemUgKTtcblxuXHR9XG5cblx0cmV0dXJuIHtcblxuXHRcdHVwZGF0ZTogdXBkYXRlXG5cblx0fTtcblxufVxuXG5mdW5jdGlvbiBXZWJHTE9iamVjdHMoIGdsLCBnZW9tZXRyaWVzLCBhdHRyaWJ1dGVzLCBpbmZvICkge1xuXG5cdGxldCB1cGRhdGVNYXAgPSBuZXcgV2Vha01hcCgpO1xuXG5cdGZ1bmN0aW9uIHVwZGF0ZSggb2JqZWN0ICkge1xuXG5cdFx0Y29uc3QgZnJhbWUgPSBpbmZvLnJlbmRlci5mcmFtZTtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0Lmdlb21ldHJ5O1xuXHRcdGNvbnN0IGJ1ZmZlcmdlb21ldHJ5ID0gZ2VvbWV0cmllcy5nZXQoIG9iamVjdCwgZ2VvbWV0cnkgKTtcblxuXHRcdC8vIFVwZGF0ZSBvbmNlIHBlciBmcmFtZVxuXG5cdFx0aWYgKCB1cGRhdGVNYXAuZ2V0KCBidWZmZXJnZW9tZXRyeSApICE9PSBmcmFtZSApIHtcblxuXHRcdFx0Z2VvbWV0cmllcy51cGRhdGUoIGJ1ZmZlcmdlb21ldHJ5ICk7XG5cblx0XHRcdHVwZGF0ZU1hcC5zZXQoIGJ1ZmZlcmdlb21ldHJ5LCBmcmFtZSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBvYmplY3QuaXNJbnN0YW5jZWRNZXNoICkge1xuXG5cdFx0XHRpZiAoIG9iamVjdC5oYXNFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uSW5zdGFuY2VkTWVzaERpc3Bvc2UgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0b2JqZWN0LmFkZEV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25JbnN0YW5jZWRNZXNoRGlzcG9zZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdXBkYXRlTWFwLmdldCggb2JqZWN0ICkgIT09IGZyYW1lICkge1xuXG5cdFx0XHRcdGF0dHJpYnV0ZXMudXBkYXRlKCBvYmplY3QuaW5zdGFuY2VNYXRyaXgsIGdsLkFSUkFZX0JVRkZFUiApO1xuXG5cdFx0XHRcdGlmICggb2JqZWN0Lmluc3RhbmNlQ29sb3IgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRhdHRyaWJ1dGVzLnVwZGF0ZSggb2JqZWN0Lmluc3RhbmNlQ29sb3IsIGdsLkFSUkFZX0JVRkZFUiApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHR1cGRhdGVNYXAuc2V0KCBvYmplY3QsIGZyYW1lICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggb2JqZWN0LmlzU2tpbm5lZE1lc2ggKSB7XG5cblx0XHRcdGNvbnN0IHNrZWxldG9uID0gb2JqZWN0LnNrZWxldG9uO1xuXG5cdFx0XHRpZiAoIHVwZGF0ZU1hcC5nZXQoIHNrZWxldG9uICkgIT09IGZyYW1lICkge1xuXG5cdFx0XHRcdHNrZWxldG9uLnVwZGF0ZSgpO1xuXG5cdFx0XHRcdHVwZGF0ZU1hcC5zZXQoIHNrZWxldG9uLCBmcmFtZSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gYnVmZmVyZ2VvbWV0cnk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG5cblx0XHR1cGRhdGVNYXAgPSBuZXcgV2Vha01hcCgpO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBvbkluc3RhbmNlZE1lc2hEaXNwb3NlKCBldmVudCApIHtcblxuXHRcdGNvbnN0IGluc3RhbmNlZE1lc2ggPSBldmVudC50YXJnZXQ7XG5cblx0XHRpbnN0YW5jZWRNZXNoLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25JbnN0YW5jZWRNZXNoRGlzcG9zZSApO1xuXG5cdFx0YXR0cmlidXRlcy5yZW1vdmUoIGluc3RhbmNlZE1lc2guaW5zdGFuY2VNYXRyaXggKTtcblxuXHRcdGlmICggaW5zdGFuY2VkTWVzaC5pbnN0YW5jZUNvbG9yICE9PSBudWxsICkgYXR0cmlidXRlcy5yZW1vdmUoIGluc3RhbmNlZE1lc2guaW5zdGFuY2VDb2xvciApO1xuXG5cdH1cblxuXHRyZXR1cm4ge1xuXG5cdFx0dXBkYXRlOiB1cGRhdGUsXG5cdFx0ZGlzcG9zZTogZGlzcG9zZVxuXG5cdH07XG5cbn1cblxuY2xhc3MgRGVwdGhUZXh0dXJlIGV4dGVuZHMgVGV4dHVyZSB7XG5cblx0Y29uc3RydWN0b3IoIHdpZHRoLCBoZWlnaHQsIHR5cGUsIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGFuaXNvdHJvcHksIGZvcm1hdCA9IERlcHRoRm9ybWF0ICkge1xuXG5cdFx0aWYgKCBmb3JtYXQgIT09IERlcHRoRm9ybWF0ICYmIGZvcm1hdCAhPT0gRGVwdGhTdGVuY2lsRm9ybWF0ICkge1xuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdEZXB0aFRleHR1cmUgZm9ybWF0IG11c3QgYmUgZWl0aGVyIFRIUkVFLkRlcHRoRm9ybWF0IG9yIFRIUkVFLkRlcHRoU3RlbmNpbEZvcm1hdCcgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdHlwZSA9PT0gdW5kZWZpbmVkICYmIGZvcm1hdCA9PT0gRGVwdGhGb3JtYXQgKSB0eXBlID0gVW5zaWduZWRJbnRUeXBlO1xuXHRcdGlmICggdHlwZSA9PT0gdW5kZWZpbmVkICYmIGZvcm1hdCA9PT0gRGVwdGhTdGVuY2lsRm9ybWF0ICkgdHlwZSA9IFVuc2lnbmVkSW50MjQ4VHlwZTtcblxuXHRcdHN1cGVyKCBudWxsLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHkgKTtcblxuXHRcdHRoaXMuaXNEZXB0aFRleHR1cmUgPSB0cnVlO1xuXG5cdFx0dGhpcy5pbWFnZSA9IHsgd2lkdGg6IHdpZHRoLCBoZWlnaHQ6IGhlaWdodCB9O1xuXG5cdFx0dGhpcy5tYWdGaWx0ZXIgPSBtYWdGaWx0ZXIgIT09IHVuZGVmaW5lZCA/IG1hZ0ZpbHRlciA6IE5lYXJlc3RGaWx0ZXI7XG5cdFx0dGhpcy5taW5GaWx0ZXIgPSBtaW5GaWx0ZXIgIT09IHVuZGVmaW5lZCA/IG1pbkZpbHRlciA6IE5lYXJlc3RGaWx0ZXI7XG5cblx0XHR0aGlzLmZsaXBZID0gZmFsc2U7XG5cdFx0dGhpcy5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcblxuXHRcdHRoaXMuY29tcGFyZUZ1bmN0aW9uID0gbnVsbDtcblxuXHR9XG5cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuY29tcGFyZUZ1bmN0aW9uID0gc291cmNlLmNvbXBhcmVGdW5jdGlvbjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oIG1ldGEgKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCBtZXRhICk7XG5cblx0XHRpZiAoIHRoaXMuY29tcGFyZUZ1bmN0aW9uICE9PSBudWxsICkgZGF0YS5jb21wYXJlRnVuY3Rpb24gPSB0aGlzLmNvbXBhcmVGdW5jdGlvbjtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxufVxuXG4vKipcbiAqIFVuaWZvcm1zIG9mIGEgcHJvZ3JhbS5cbiAqIFRob3NlIGZvcm0gYSB0cmVlIHN0cnVjdHVyZSB3aXRoIGEgc3BlY2lhbCB0b3AtbGV2ZWwgY29udGFpbmVyIGZvciB0aGUgcm9vdCxcbiAqIHdoaWNoIHlvdSBnZXQgYnkgY2FsbGluZyAnbmV3IFdlYkdMVW5pZm9ybXMoIGdsLCBwcm9ncmFtICknLlxuICpcbiAqXG4gKiBQcm9wZXJ0aWVzIG9mIGlubmVyIG5vZGVzIGluY2x1ZGluZyB0aGUgdG9wLWxldmVsIGNvbnRhaW5lcjpcbiAqXG4gKiAuc2VxIC0gYXJyYXkgb2YgbmVzdGVkIHVuaWZvcm1zXG4gKiAubWFwIC0gbmVzdGVkIHVuaWZvcm1zIGJ5IG5hbWVcbiAqXG4gKlxuICogTWV0aG9kcyBvZiBhbGwgbm9kZXMgZXhjZXB0IHRoZSB0b3AtbGV2ZWwgY29udGFpbmVyOlxuICpcbiAqIC5zZXRWYWx1ZSggZ2wsIHZhbHVlLCBbdGV4dHVyZXNdIClcbiAqXG4gKiBcdFx0dXBsb2FkcyBhIHVuaWZvcm0gdmFsdWUocylcbiAqICBcdHRoZSAndGV4dHVyZXMnIHBhcmFtZXRlciBpcyBuZWVkZWQgZm9yIHNhbXBsZXIgdW5pZm9ybXNcbiAqXG4gKlxuICogU3RhdGljIG1ldGhvZHMgb2YgdGhlIHRvcC1sZXZlbCBjb250YWluZXIgKHRleHR1cmVzIGZhY3Rvcml6YXRpb25zKTpcbiAqXG4gKiAudXBsb2FkKCBnbCwgc2VxLCB2YWx1ZXMsIHRleHR1cmVzIClcbiAqXG4gKiBcdFx0c2V0cyB1bmlmb3JtcyBpbiAnc2VxJyB0byAndmFsdWVzW2lkXS52YWx1ZSdcbiAqXG4gKiAuc2VxV2l0aFZhbHVlKCBzZXEsIHZhbHVlcyApIDogZmlsdGVyZWRTZXFcbiAqXG4gKiBcdFx0ZmlsdGVycyAnc2VxJyBlbnRyaWVzIHdpdGggY29ycmVzcG9uZGluZyBlbnRyeSBpbiB2YWx1ZXNcbiAqXG4gKlxuICogTWV0aG9kcyBvZiB0aGUgdG9wLWxldmVsIGNvbnRhaW5lciAodGV4dHVyZXMgZmFjdG9yaXphdGlvbnMpOlxuICpcbiAqIC5zZXRWYWx1ZSggZ2wsIG5hbWUsIHZhbHVlLCB0ZXh0dXJlcyApXG4gKlxuICogXHRcdHNldHMgdW5pZm9ybSB3aXRoICBuYW1lICduYW1lJyB0byAndmFsdWUnXG4gKlxuICogLnNldE9wdGlvbmFsKCBnbCwgb2JqLCBwcm9wIClcbiAqXG4gKiBcdFx0bGlrZSAuc2V0IGZvciBhbiBvcHRpb25hbCBwcm9wZXJ0eSBvZiB0aGUgb2JqZWN0XG4gKlxuICovXG5cblxuY29uc3QgZW1wdHlUZXh0dXJlID0gLypAX19QVVJFX18qLyBuZXcgVGV4dHVyZSgpO1xuXG5jb25zdCBlbXB0eVNoYWRvd1RleHR1cmUgPSAvKkBfX1BVUkVfXyovIG5ldyBEZXB0aFRleHR1cmUoIDEsIDEgKTtcblxuY29uc3QgZW1wdHlBcnJheVRleHR1cmUgPSAvKkBfX1BVUkVfXyovIG5ldyBEYXRhQXJyYXlUZXh0dXJlKCk7XG5jb25zdCBlbXB0eTNkVGV4dHVyZSA9IC8qQF9fUFVSRV9fKi8gbmV3IERhdGEzRFRleHR1cmUoKTtcbmNvbnN0IGVtcHR5Q3ViZVRleHR1cmUgPSAvKkBfX1BVUkVfXyovIG5ldyBDdWJlVGV4dHVyZSgpO1xuXG4vLyAtLS0gVXRpbGl0aWVzIC0tLVxuXG4vLyBBcnJheSBDYWNoZXMgKHByb3ZpZGUgdHlwZWQgYXJyYXlzIGZvciB0ZW1wb3JhcnkgYnkgc2l6ZSlcblxuY29uc3QgYXJyYXlDYWNoZUYzMiA9IFtdO1xuY29uc3QgYXJyYXlDYWNoZUkzMiA9IFtdO1xuXG4vLyBGbG9hdDMyQXJyYXkgY2FjaGVzIHVzZWQgZm9yIHVwbG9hZGluZyBNYXRyaXggdW5pZm9ybXNcblxuY29uc3QgbWF0NGFycmF5ID0gbmV3IEZsb2F0MzJBcnJheSggMTYgKTtcbmNvbnN0IG1hdDNhcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoIDkgKTtcbmNvbnN0IG1hdDJhcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoIDQgKTtcblxuLy8gRmxhdHRlbmluZyBmb3IgYXJyYXlzIG9mIHZlY3RvcnMgYW5kIG1hdHJpY2VzXG5cbmZ1bmN0aW9uIGZsYXR0ZW4oIGFycmF5LCBuQmxvY2tzLCBibG9ja1NpemUgKSB7XG5cblx0Y29uc3QgZmlyc3RFbGVtID0gYXJyYXlbIDAgXTtcblxuXHRpZiAoIGZpcnN0RWxlbSA8PSAwIHx8IGZpcnN0RWxlbSA+IDAgKSByZXR1cm4gYXJyYXk7XG5cdC8vIHVub3B0aW1pemVkOiAhIGlzTmFOKCBmaXJzdEVsZW0gKVxuXHQvLyBzZWUgaHR0cDovL2phY2tzb25kdW5zdGFuLmNvbS9hcnRpY2xlcy85ODNcblxuXHRjb25zdCBuID0gbkJsb2NrcyAqIGJsb2NrU2l6ZTtcblx0bGV0IHIgPSBhcnJheUNhY2hlRjMyWyBuIF07XG5cblx0aWYgKCByID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRyID0gbmV3IEZsb2F0MzJBcnJheSggbiApO1xuXHRcdGFycmF5Q2FjaGVGMzJbIG4gXSA9IHI7XG5cblx0fVxuXG5cdGlmICggbkJsb2NrcyAhPT0gMCApIHtcblxuXHRcdGZpcnN0RWxlbS50b0FycmF5KCByLCAwICk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDEsIG9mZnNldCA9IDA7IGkgIT09IG5CbG9ja3M7ICsrIGkgKSB7XG5cblx0XHRcdG9mZnNldCArPSBibG9ja1NpemU7XG5cdFx0XHRhcnJheVsgaSBdLnRvQXJyYXkoIHIsIG9mZnNldCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4gcjtcblxufVxuXG5mdW5jdGlvbiBhcnJheXNFcXVhbCggYSwgYiApIHtcblxuXHRpZiAoIGEubGVuZ3RoICE9PSBiLmxlbmd0aCApIHJldHVybiBmYWxzZTtcblxuXHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBhLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRpZiAoIGFbIGkgXSAhPT0gYlsgaSBdICkgcmV0dXJuIGZhbHNlO1xuXG5cdH1cblxuXHRyZXR1cm4gdHJ1ZTtcblxufVxuXG5mdW5jdGlvbiBjb3B5QXJyYXkoIGEsIGIgKSB7XG5cblx0Zm9yICggbGV0IGkgPSAwLCBsID0gYi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0YVsgaSBdID0gYlsgaSBdO1xuXG5cdH1cblxufVxuXG4vLyBUZXh0dXJlIHVuaXQgYWxsb2NhdGlvblxuXG5mdW5jdGlvbiBhbGxvY1RleFVuaXRzKCB0ZXh0dXJlcywgbiApIHtcblxuXHRsZXQgciA9IGFycmF5Q2FjaGVJMzJbIG4gXTtcblxuXHRpZiAoIHIgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdHIgPSBuZXcgSW50MzJBcnJheSggbiApO1xuXHRcdGFycmF5Q2FjaGVJMzJbIG4gXSA9IHI7XG5cblx0fVxuXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdHJbIGkgXSA9IHRleHR1cmVzLmFsbG9jYXRlVGV4dHVyZVVuaXQoKTtcblxuXHR9XG5cblx0cmV0dXJuIHI7XG5cbn1cblxuLy8gLS0tIFNldHRlcnMgLS0tXG5cbi8vIE5vdGU6IERlZmluaW5nIHRoZXNlIG1ldGhvZHMgZXh0ZXJuYWxseSwgYmVjYXVzZSB0aGV5IGNvbWUgaW4gYSBidW5jaFxuLy8gYW5kIHRoaXMgd2F5IHRoZWlyIG5hbWVzIG1pbmlmeS5cblxuLy8gU2luZ2xlIHNjYWxhclxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYxZiggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGlmICggY2FjaGVbIDAgXSA9PT0gdiApIHJldHVybjtcblxuXHRnbC51bmlmb3JtMWYoIHRoaXMuYWRkciwgdiApO1xuXG5cdGNhY2hlWyAwIF0gPSB2O1xuXG59XG5cbi8vIFNpbmdsZSBmbG9hdCB2ZWN0b3IgKGZyb20gZmxhdCBhcnJheSBvciBUSFJFRS5WZWN0b3JOKVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYyZiggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRpZiAoIGNhY2hlWyAwIF0gIT09IHYueCB8fCBjYWNoZVsgMSBdICE9PSB2LnkgKSB7XG5cblx0XHRcdGdsLnVuaWZvcm0yZiggdGhpcy5hZGRyLCB2LngsIHYueSApO1xuXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcblxuXHRcdH1cblxuXHR9IGVsc2Uge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcblxuXHRcdGdsLnVuaWZvcm0yZnYoIHRoaXMuYWRkciwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYzZiggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRpZiAoIGNhY2hlWyAwIF0gIT09IHYueCB8fCBjYWNoZVsgMSBdICE9PSB2LnkgfHwgY2FjaGVbIDIgXSAhPT0gdi56ICkge1xuXG5cdFx0XHRnbC51bmlmb3JtM2YoIHRoaXMuYWRkciwgdi54LCB2LnksIHYueiApO1xuXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcblx0XHRcdGNhY2hlWyAyIF0gPSB2Lno7XG5cblx0XHR9XG5cblx0fSBlbHNlIGlmICggdi5yICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRpZiAoIGNhY2hlWyAwIF0gIT09IHYuciB8fCBjYWNoZVsgMSBdICE9PSB2LmcgfHwgY2FjaGVbIDIgXSAhPT0gdi5iICkge1xuXG5cdFx0XHRnbC51bmlmb3JtM2YoIHRoaXMuYWRkciwgdi5yLCB2LmcsIHYuYiApO1xuXG5cdFx0XHRjYWNoZVsgMCBdID0gdi5yO1xuXHRcdFx0Y2FjaGVbIDEgXSA9IHYuZztcblx0XHRcdGNhY2hlWyAyIF0gPSB2LmI7XG5cblx0XHR9XG5cblx0fSBlbHNlIHtcblxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XG5cblx0XHRnbC51bmlmb3JtM2Z2KCB0aGlzLmFkZHIsIHYgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gc2V0VmFsdWVWNGYoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55IHx8IGNhY2hlWyAyIF0gIT09IHYueiB8fCBjYWNoZVsgMyBdICE9PSB2LncgKSB7XG5cblx0XHRcdGdsLnVuaWZvcm00ZiggdGhpcy5hZGRyLCB2LngsIHYueSwgdi56LCB2LncgKTtcblxuXHRcdFx0Y2FjaGVbIDAgXSA9IHYueDtcblx0XHRcdGNhY2hlWyAxIF0gPSB2Lnk7XG5cdFx0XHRjYWNoZVsgMiBdID0gdi56O1xuXHRcdFx0Y2FjaGVbIDMgXSA9IHYudztcblxuXHRcdH1cblxuXHR9IGVsc2Uge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcblxuXHRcdGdsLnVuaWZvcm00ZnYoIHRoaXMuYWRkciwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH1cblxufVxuXG4vLyBTaW5nbGUgbWF0cml4IChmcm9tIGZsYXQgYXJyYXkgb3IgVEhSRUUuTWF0cml4TilcblxuZnVuY3Rpb24gc2V0VmFsdWVNMiggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXHRjb25zdCBlbGVtZW50cyA9IHYuZWxlbWVudHM7XG5cblx0aWYgKCBlbGVtZW50cyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcblxuXHRcdGdsLnVuaWZvcm1NYXRyaXgyZnYoIHRoaXMuYWRkciwgZmFsc2UsIHYgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcblxuXHR9IGVsc2Uge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIGVsZW1lbnRzICkgKSByZXR1cm47XG5cblx0XHRtYXQyYXJyYXkuc2V0KCBlbGVtZW50cyApO1xuXG5cdFx0Z2wudW5pZm9ybU1hdHJpeDJmdiggdGhpcy5hZGRyLCBmYWxzZSwgbWF0MmFycmF5ICk7XG5cblx0XHRjb3B5QXJyYXkoIGNhY2hlLCBlbGVtZW50cyApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZU0zKCBnbCwgdiApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cdGNvbnN0IGVsZW1lbnRzID0gdi5lbGVtZW50cztcblxuXHRpZiAoIGVsZW1lbnRzID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xuXG5cdFx0Z2wudW5pZm9ybU1hdHJpeDNmdiggdGhpcy5hZGRyLCBmYWxzZSwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgZWxlbWVudHMgKSApIHJldHVybjtcblxuXHRcdG1hdDNhcnJheS5zZXQoIGVsZW1lbnRzICk7XG5cblx0XHRnbC51bmlmb3JtTWF0cml4M2Z2KCB0aGlzLmFkZHIsIGZhbHNlLCBtYXQzYXJyYXkgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIGVsZW1lbnRzICk7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlTTQoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblx0Y29uc3QgZWxlbWVudHMgPSB2LmVsZW1lbnRzO1xuXG5cdGlmICggZWxlbWVudHMgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCB2ICkgKSByZXR1cm47XG5cblx0XHRnbC51bmlmb3JtTWF0cml4NGZ2KCB0aGlzLmFkZHIsIGZhbHNlLCB2ICk7XG5cblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XG5cblx0fSBlbHNlIHtcblxuXHRcdGlmICggYXJyYXlzRXF1YWwoIGNhY2hlLCBlbGVtZW50cyApICkgcmV0dXJuO1xuXG5cdFx0bWF0NGFycmF5LnNldCggZWxlbWVudHMgKTtcblxuXHRcdGdsLnVuaWZvcm1NYXRyaXg0ZnYoIHRoaXMuYWRkciwgZmFsc2UsIG1hdDRhcnJheSApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgZWxlbWVudHMgKTtcblxuXHR9XG5cbn1cblxuLy8gU2luZ2xlIGludGVnZXIgLyBib29sZWFuXG5cbmZ1bmN0aW9uIHNldFZhbHVlVjFpKCBnbCwgdiApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cblx0aWYgKCBjYWNoZVsgMCBdID09PSB2ICkgcmV0dXJuO1xuXG5cdGdsLnVuaWZvcm0xaSggdGhpcy5hZGRyLCB2ICk7XG5cblx0Y2FjaGVbIDAgXSA9IHY7XG5cbn1cblxuLy8gU2luZ2xlIGludGVnZXIgLyBib29sZWFuIHZlY3RvciAoZnJvbSBmbGF0IGFycmF5IG9yIFRIUkVFLlZlY3Rvck4pXG5cbmZ1bmN0aW9uIHNldFZhbHVlVjJpKCBnbCwgdiApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cblx0aWYgKCB2LnggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSApIHtcblxuXHRcdFx0Z2wudW5pZm9ybTJpKCB0aGlzLmFkZHIsIHYueCwgdi55ICk7XG5cblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xuXG5cdFx0fVxuXG5cdH0gZWxzZSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xuXG5cdFx0Z2wudW5pZm9ybTJpdiggdGhpcy5hZGRyLCB2ICk7XG5cblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlVjNpKCBnbCwgdiApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cblx0aWYgKCB2LnggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogKSB7XG5cblx0XHRcdGdsLnVuaWZvcm0zaSggdGhpcy5hZGRyLCB2LngsIHYueSwgdi56ICk7XG5cblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xuXHRcdFx0Y2FjaGVbIDIgXSA9IHYuejtcblxuXHRcdH1cblxuXHR9IGVsc2Uge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcblxuXHRcdGdsLnVuaWZvcm0zaXYoIHRoaXMuYWRkciwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVY0aSggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGlmICggdi54ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRpZiAoIGNhY2hlWyAwIF0gIT09IHYueCB8fCBjYWNoZVsgMSBdICE9PSB2LnkgfHwgY2FjaGVbIDIgXSAhPT0gdi56IHx8IGNhY2hlWyAzIF0gIT09IHYudyApIHtcblxuXHRcdFx0Z2wudW5pZm9ybTRpKCB0aGlzLmFkZHIsIHYueCwgdi55LCB2LnosIHYudyApO1xuXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcblx0XHRcdGNhY2hlWyAyIF0gPSB2Lno7XG5cdFx0XHRjYWNoZVsgMyBdID0gdi53O1xuXG5cdFx0fVxuXG5cdH0gZWxzZSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xuXG5cdFx0Z2wudW5pZm9ybTRpdiggdGhpcy5hZGRyLCB2ICk7XG5cblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB2ICk7XG5cblx0fVxuXG59XG5cbi8vIFNpbmdsZSB1bnNpZ25lZCBpbnRlZ2VyXG5cbmZ1bmN0aW9uIHNldFZhbHVlVjF1aSggZ2wsIHYgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGlmICggY2FjaGVbIDAgXSA9PT0gdiApIHJldHVybjtcblxuXHRnbC51bmlmb3JtMXVpKCB0aGlzLmFkZHIsIHYgKTtcblxuXHRjYWNoZVsgMCBdID0gdjtcblxufVxuXG4vLyBTaW5nbGUgdW5zaWduZWQgaW50ZWdlciB2ZWN0b3IgKGZyb20gZmxhdCBhcnJheSBvciBUSFJFRS5WZWN0b3JOKVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYydWkoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55ICkge1xuXG5cdFx0XHRnbC51bmlmb3JtMnVpKCB0aGlzLmFkZHIsIHYueCwgdi55ICk7XG5cblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xuXG5cdFx0fVxuXG5cdH0gZWxzZSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xuXG5cdFx0Z2wudW5pZm9ybTJ1aXYoIHRoaXMuYWRkciwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYzdWkoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblxuXHRpZiAoIHYueCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0aWYgKCBjYWNoZVsgMCBdICE9PSB2LnggfHwgY2FjaGVbIDEgXSAhPT0gdi55IHx8IGNhY2hlWyAyIF0gIT09IHYueiApIHtcblxuXHRcdFx0Z2wudW5pZm9ybTN1aSggdGhpcy5hZGRyLCB2LngsIHYueSwgdi56ICk7XG5cblx0XHRcdGNhY2hlWyAwIF0gPSB2Lng7XG5cdFx0XHRjYWNoZVsgMSBdID0gdi55O1xuXHRcdFx0Y2FjaGVbIDIgXSA9IHYuejtcblxuXHRcdH1cblxuXHR9IGVsc2Uge1xuXG5cdFx0aWYgKCBhcnJheXNFcXVhbCggY2FjaGUsIHYgKSApIHJldHVybjtcblxuXHRcdGdsLnVuaWZvcm0zdWl2KCB0aGlzLmFkZHIsIHYgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHYgKTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gc2V0VmFsdWVWNHVpKCBnbCwgdiApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cblx0aWYgKCB2LnggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGlmICggY2FjaGVbIDAgXSAhPT0gdi54IHx8IGNhY2hlWyAxIF0gIT09IHYueSB8fCBjYWNoZVsgMiBdICE9PSB2LnogfHwgY2FjaGVbIDMgXSAhPT0gdi53ICkge1xuXG5cdFx0XHRnbC51bmlmb3JtNHVpKCB0aGlzLmFkZHIsIHYueCwgdi55LCB2LnosIHYudyApO1xuXG5cdFx0XHRjYWNoZVsgMCBdID0gdi54O1xuXHRcdFx0Y2FjaGVbIDEgXSA9IHYueTtcblx0XHRcdGNhY2hlWyAyIF0gPSB2Lno7XG5cdFx0XHRjYWNoZVsgMyBdID0gdi53O1xuXG5cdFx0fVxuXG5cdH0gZWxzZSB7XG5cblx0XHRpZiAoIGFycmF5c0VxdWFsKCBjYWNoZSwgdiApICkgcmV0dXJuO1xuXG5cdFx0Z2wudW5pZm9ybTR1aXYoIHRoaXMuYWRkciwgdiApO1xuXG5cdFx0Y29weUFycmF5KCBjYWNoZSwgdiApO1xuXG5cdH1cblxufVxuXG5cbi8vIFNpbmdsZSB0ZXh0dXJlICgyRCAvIEN1YmUpXG5cbmZ1bmN0aW9uIHNldFZhbHVlVDEoIGdsLCB2LCB0ZXh0dXJlcyApIHtcblxuXHRjb25zdCBjYWNoZSA9IHRoaXMuY2FjaGU7XG5cdGNvbnN0IHVuaXQgPSB0ZXh0dXJlcy5hbGxvY2F0ZVRleHR1cmVVbml0KCk7XG5cblx0aWYgKCBjYWNoZVsgMCBdICE9PSB1bml0ICkge1xuXG5cdFx0Z2wudW5pZm9ybTFpKCB0aGlzLmFkZHIsIHVuaXQgKTtcblx0XHRjYWNoZVsgMCBdID0gdW5pdDtcblxuXHR9XG5cblx0bGV0IGVtcHR5VGV4dHVyZTJEO1xuXG5cdGlmICggdGhpcy50eXBlID09PSBnbC5TQU1QTEVSXzJEX1NIQURPVyApIHtcblxuXHRcdGVtcHR5U2hhZG93VGV4dHVyZS5jb21wYXJlRnVuY3Rpb24gPSBMZXNzRXF1YWxDb21wYXJlOyAvLyAjMjg2NzBcblx0XHRlbXB0eVRleHR1cmUyRCA9IGVtcHR5U2hhZG93VGV4dHVyZTtcblxuXHR9IGVsc2Uge1xuXG5cdFx0ZW1wdHlUZXh0dXJlMkQgPSBlbXB0eVRleHR1cmU7XG5cblx0fVxuXG5cdHRleHR1cmVzLnNldFRleHR1cmUyRCggdiB8fCBlbXB0eVRleHR1cmUyRCwgdW5pdCApO1xuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlVDNEMSggZ2wsIHYsIHRleHR1cmVzICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblx0Y29uc3QgdW5pdCA9IHRleHR1cmVzLmFsbG9jYXRlVGV4dHVyZVVuaXQoKTtcblxuXHRpZiAoIGNhY2hlWyAwIF0gIT09IHVuaXQgKSB7XG5cblx0XHRnbC51bmlmb3JtMWkoIHRoaXMuYWRkciwgdW5pdCApO1xuXHRcdGNhY2hlWyAwIF0gPSB1bml0O1xuXG5cdH1cblxuXHR0ZXh0dXJlcy5zZXRUZXh0dXJlM0QoIHYgfHwgZW1wdHkzZFRleHR1cmUsIHVuaXQgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVQ2KCBnbCwgdiwgdGV4dHVyZXMgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXHRjb25zdCB1bml0ID0gdGV4dHVyZXMuYWxsb2NhdGVUZXh0dXJlVW5pdCgpO1xuXG5cdGlmICggY2FjaGVbIDAgXSAhPT0gdW5pdCApIHtcblxuXHRcdGdsLnVuaWZvcm0xaSggdGhpcy5hZGRyLCB1bml0ICk7XG5cdFx0Y2FjaGVbIDAgXSA9IHVuaXQ7XG5cblx0fVxuXG5cdHRleHR1cmVzLnNldFRleHR1cmVDdWJlKCB2IHx8IGVtcHR5Q3ViZVRleHR1cmUsIHVuaXQgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVQyREFycmF5MSggZ2wsIHYsIHRleHR1cmVzICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblx0Y29uc3QgdW5pdCA9IHRleHR1cmVzLmFsbG9jYXRlVGV4dHVyZVVuaXQoKTtcblxuXHRpZiAoIGNhY2hlWyAwIF0gIT09IHVuaXQgKSB7XG5cblx0XHRnbC51bmlmb3JtMWkoIHRoaXMuYWRkciwgdW5pdCApO1xuXHRcdGNhY2hlWyAwIF0gPSB1bml0O1xuXG5cdH1cblxuXHR0ZXh0dXJlcy5zZXRUZXh0dXJlMkRBcnJheSggdiB8fCBlbXB0eUFycmF5VGV4dHVyZSwgdW5pdCApO1xuXG59XG5cbi8vIEhlbHBlciB0byBwaWNrIHRoZSByaWdodCBzZXR0ZXIgZm9yIHRoZSBzaW5ndWxhciBjYXNlXG5cbmZ1bmN0aW9uIGdldFNpbmd1bGFyU2V0dGVyKCB0eXBlICkge1xuXG5cdHN3aXRjaCAoIHR5cGUgKSB7XG5cblx0XHRjYXNlIDB4MTQwNjogcmV0dXJuIHNldFZhbHVlVjFmOyAvLyBGTE9BVFxuXHRcdGNhc2UgMHg4YjUwOiByZXR1cm4gc2V0VmFsdWVWMmY7IC8vIF9WRUMyXG5cdFx0Y2FzZSAweDhiNTE6IHJldHVybiBzZXRWYWx1ZVYzZjsgLy8gX1ZFQzNcblx0XHRjYXNlIDB4OGI1MjogcmV0dXJuIHNldFZhbHVlVjRmOyAvLyBfVkVDNFxuXG5cdFx0Y2FzZSAweDhiNWE6IHJldHVybiBzZXRWYWx1ZU0yOyAvLyBfTUFUMlxuXHRcdGNhc2UgMHg4YjViOiByZXR1cm4gc2V0VmFsdWVNMzsgLy8gX01BVDNcblx0XHRjYXNlIDB4OGI1YzogcmV0dXJuIHNldFZhbHVlTTQ7IC8vIF9NQVQ0XG5cblx0XHRjYXNlIDB4MTQwNDogY2FzZSAweDhiNTY6IHJldHVybiBzZXRWYWx1ZVYxaTsgLy8gSU5ULCBCT09MXG5cdFx0Y2FzZSAweDhiNTM6IGNhc2UgMHg4YjU3OiByZXR1cm4gc2V0VmFsdWVWMmk7IC8vIF9WRUMyXG5cdFx0Y2FzZSAweDhiNTQ6IGNhc2UgMHg4YjU4OiByZXR1cm4gc2V0VmFsdWVWM2k7IC8vIF9WRUMzXG5cdFx0Y2FzZSAweDhiNTU6IGNhc2UgMHg4YjU5OiByZXR1cm4gc2V0VmFsdWVWNGk7IC8vIF9WRUM0XG5cblx0XHRjYXNlIDB4MTQwNTogcmV0dXJuIHNldFZhbHVlVjF1aTsgLy8gVUlOVFxuXHRcdGNhc2UgMHg4ZGM2OiByZXR1cm4gc2V0VmFsdWVWMnVpOyAvLyBfVkVDMlxuXHRcdGNhc2UgMHg4ZGM3OiByZXR1cm4gc2V0VmFsdWVWM3VpOyAvLyBfVkVDM1xuXHRcdGNhc2UgMHg4ZGM4OiByZXR1cm4gc2V0VmFsdWVWNHVpOyAvLyBfVkVDNFxuXG5cdFx0Y2FzZSAweDhiNWU6IC8vIFNBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGQ2NjogLy8gU0FNUExFUl9FWFRFUk5BTF9PRVNcblx0XHRjYXNlIDB4OGRjYTogLy8gSU5UX1NBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGRkMjogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGI2MjogLy8gU0FNUExFUl8yRF9TSEFET1dcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQxO1xuXG5cdFx0Y2FzZSAweDhiNWY6IC8vIFNBTVBMRVJfM0Rcblx0XHRjYXNlIDB4OGRjYjogLy8gSU5UX1NBTVBMRVJfM0Rcblx0XHRjYXNlIDB4OGRkMzogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfM0Rcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQzRDE7XG5cblx0XHRjYXNlIDB4OGI2MDogLy8gU0FNUExFUl9DVUJFXG5cdFx0Y2FzZSAweDhkY2M6IC8vIElOVF9TQU1QTEVSX0NVQkVcblx0XHRjYXNlIDB4OGRkNDogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfQ1VCRVxuXHRcdGNhc2UgMHg4ZGM1OiAvLyBTQU1QTEVSX0NVQkVfU0hBRE9XXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUNjtcblxuXHRcdGNhc2UgMHg4ZGMxOiAvLyBTQU1QTEVSXzJEX0FSUkFZXG5cdFx0Y2FzZSAweDhkY2Y6IC8vIElOVF9TQU1QTEVSXzJEX0FSUkFZXG5cdFx0Y2FzZSAweDhkZDc6IC8vIFVOU0lHTkVEX0lOVF9TQU1QTEVSXzJEX0FSUkFZXG5cdFx0Y2FzZSAweDhkYzQ6IC8vIFNBTVBMRVJfMkRfQVJSQVlfU0hBRE9XXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUMkRBcnJheTE7XG5cblx0fVxuXG59XG5cblxuLy8gQXJyYXkgb2Ygc2NhbGFyc1xuXG5mdW5jdGlvbiBzZXRWYWx1ZVYxZkFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtMWZ2KCB0aGlzLmFkZHIsIHYgKTtcblxufVxuXG4vLyBBcnJheSBvZiB2ZWN0b3JzIChmcm9tIGZsYXQgYXJyYXkgb3IgYXJyYXkgb2YgVEhSRUUuVmVjdG9yTilcblxuZnVuY3Rpb24gc2V0VmFsdWVWMmZBcnJheSggZ2wsIHYgKSB7XG5cblx0Y29uc3QgZGF0YSA9IGZsYXR0ZW4oIHYsIHRoaXMuc2l6ZSwgMiApO1xuXG5cdGdsLnVuaWZvcm0yZnYoIHRoaXMuYWRkciwgZGF0YSApO1xuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlVjNmQXJyYXkoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGRhdGEgPSBmbGF0dGVuKCB2LCB0aGlzLnNpemUsIDMgKTtcblxuXHRnbC51bmlmb3JtM2Z2KCB0aGlzLmFkZHIsIGRhdGEgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVY0ZkFycmF5KCBnbCwgdiApIHtcblxuXHRjb25zdCBkYXRhID0gZmxhdHRlbiggdiwgdGhpcy5zaXplLCA0ICk7XG5cblx0Z2wudW5pZm9ybTRmdiggdGhpcy5hZGRyLCBkYXRhICk7XG5cbn1cblxuLy8gQXJyYXkgb2YgbWF0cmljZXMgKGZyb20gZmxhdCBhcnJheSBvciBhcnJheSBvZiBUSFJFRS5NYXRyaXhOKVxuXG5mdW5jdGlvbiBzZXRWYWx1ZU0yQXJyYXkoIGdsLCB2ICkge1xuXG5cdGNvbnN0IGRhdGEgPSBmbGF0dGVuKCB2LCB0aGlzLnNpemUsIDQgKTtcblxuXHRnbC51bmlmb3JtTWF0cml4MmZ2KCB0aGlzLmFkZHIsIGZhbHNlLCBkYXRhICk7XG5cbn1cblxuZnVuY3Rpb24gc2V0VmFsdWVNM0FycmF5KCBnbCwgdiApIHtcblxuXHRjb25zdCBkYXRhID0gZmxhdHRlbiggdiwgdGhpcy5zaXplLCA5ICk7XG5cblx0Z2wudW5pZm9ybU1hdHJpeDNmdiggdGhpcy5hZGRyLCBmYWxzZSwgZGF0YSApO1xuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlTTRBcnJheSggZ2wsIHYgKSB7XG5cblx0Y29uc3QgZGF0YSA9IGZsYXR0ZW4oIHYsIHRoaXMuc2l6ZSwgMTYgKTtcblxuXHRnbC51bmlmb3JtTWF0cml4NGZ2KCB0aGlzLmFkZHIsIGZhbHNlLCBkYXRhICk7XG5cbn1cblxuLy8gQXJyYXkgb2YgaW50ZWdlciAvIGJvb2xlYW5cblxuZnVuY3Rpb24gc2V0VmFsdWVWMWlBcnJheSggZ2wsIHYgKSB7XG5cblx0Z2wudW5pZm9ybTFpdiggdGhpcy5hZGRyLCB2ICk7XG5cbn1cblxuLy8gQXJyYXkgb2YgaW50ZWdlciAvIGJvb2xlYW4gdmVjdG9ycyAoZnJvbSBmbGF0IGFycmF5KVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYyaUFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtMml2KCB0aGlzLmFkZHIsIHYgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVYzaUFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtM2l2KCB0aGlzLmFkZHIsIHYgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVY0aUFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtNGl2KCB0aGlzLmFkZHIsIHYgKTtcblxufVxuXG4vLyBBcnJheSBvZiB1bnNpZ25lZCBpbnRlZ2VyXG5cbmZ1bmN0aW9uIHNldFZhbHVlVjF1aUFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtMXVpdiggdGhpcy5hZGRyLCB2ICk7XG5cbn1cblxuLy8gQXJyYXkgb2YgdW5zaWduZWQgaW50ZWdlciB2ZWN0b3JzIChmcm9tIGZsYXQgYXJyYXkpXG5cbmZ1bmN0aW9uIHNldFZhbHVlVjJ1aUFycmF5KCBnbCwgdiApIHtcblxuXHRnbC51bmlmb3JtMnVpdiggdGhpcy5hZGRyLCB2ICk7XG5cbn1cblxuZnVuY3Rpb24gc2V0VmFsdWVWM3VpQXJyYXkoIGdsLCB2ICkge1xuXG5cdGdsLnVuaWZvcm0zdWl2KCB0aGlzLmFkZHIsIHYgKTtcblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVY0dWlBcnJheSggZ2wsIHYgKSB7XG5cblx0Z2wudW5pZm9ybTR1aXYoIHRoaXMuYWRkciwgdiApO1xuXG59XG5cblxuLy8gQXJyYXkgb2YgdGV4dHVyZXMgKDJEIC8gM0QgLyBDdWJlIC8gMkRBcnJheSlcblxuZnVuY3Rpb24gc2V0VmFsdWVUMUFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGNvbnN0IG4gPSB2Lmxlbmd0aDtcblxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XG5cblx0aWYgKCAhIGFycmF5c0VxdWFsKCBjYWNoZSwgdW5pdHMgKSApIHtcblxuXHRcdGdsLnVuaWZvcm0xaXYoIHRoaXMuYWRkciwgdW5pdHMgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XG5cblx0fVxuXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUyRCggdlsgaSBdIHx8IGVtcHR5VGV4dHVyZSwgdW5pdHNbIGkgXSApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzZXRWYWx1ZVQzREFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGNvbnN0IG4gPSB2Lmxlbmd0aDtcblxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XG5cblx0aWYgKCAhIGFycmF5c0VxdWFsKCBjYWNoZSwgdW5pdHMgKSApIHtcblxuXHRcdGdsLnVuaWZvcm0xaXYoIHRoaXMuYWRkciwgdW5pdHMgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XG5cblx0fVxuXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUzRCggdlsgaSBdIHx8IGVtcHR5M2RUZXh0dXJlLCB1bml0c1sgaSBdICk7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHNldFZhbHVlVDZBcnJheSggZ2wsIHYsIHRleHR1cmVzICkge1xuXG5cdGNvbnN0IGNhY2hlID0gdGhpcy5jYWNoZTtcblxuXHRjb25zdCBuID0gdi5sZW5ndGg7XG5cblx0Y29uc3QgdW5pdHMgPSBhbGxvY1RleFVuaXRzKCB0ZXh0dXJlcywgbiApO1xuXG5cdGlmICggISBhcnJheXNFcXVhbCggY2FjaGUsIHVuaXRzICkgKSB7XG5cblx0XHRnbC51bmlmb3JtMWl2KCB0aGlzLmFkZHIsIHVuaXRzICk7XG5cblx0XHRjb3B5QXJyYXkoIGNhY2hlLCB1bml0cyApO1xuXG5cdH1cblxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlQ3ViZSggdlsgaSBdIHx8IGVtcHR5Q3ViZVRleHR1cmUsIHVuaXRzWyBpIF0gKTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gc2V0VmFsdWVUMkRBcnJheUFycmF5KCBnbCwgdiwgdGV4dHVyZXMgKSB7XG5cblx0Y29uc3QgY2FjaGUgPSB0aGlzLmNhY2hlO1xuXG5cdGNvbnN0IG4gPSB2Lmxlbmd0aDtcblxuXHRjb25zdCB1bml0cyA9IGFsbG9jVGV4VW5pdHMoIHRleHR1cmVzLCBuICk7XG5cblx0aWYgKCAhIGFycmF5c0VxdWFsKCBjYWNoZSwgdW5pdHMgKSApIHtcblxuXHRcdGdsLnVuaWZvcm0xaXYoIHRoaXMuYWRkciwgdW5pdHMgKTtcblxuXHRcdGNvcHlBcnJheSggY2FjaGUsIHVuaXRzICk7XG5cblx0fVxuXG5cdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdHRleHR1cmVzLnNldFRleHR1cmUyREFycmF5KCB2WyBpIF0gfHwgZW1wdHlBcnJheVRleHR1cmUsIHVuaXRzWyBpIF0gKTtcblxuXHR9XG5cbn1cblxuXG4vLyBIZWxwZXIgdG8gcGljayB0aGUgcmlnaHQgc2V0dGVyIGZvciBhIHB1cmUgKGJvdHRvbS1sZXZlbCkgYXJyYXlcblxuZnVuY3Rpb24gZ2V0UHVyZUFycmF5U2V0dGVyKCB0eXBlICkge1xuXG5cdHN3aXRjaCAoIHR5cGUgKSB7XG5cblx0XHRjYXNlIDB4MTQwNjogcmV0dXJuIHNldFZhbHVlVjFmQXJyYXk7IC8vIEZMT0FUXG5cdFx0Y2FzZSAweDhiNTA6IHJldHVybiBzZXRWYWx1ZVYyZkFycmF5OyAvLyBfVkVDMlxuXHRcdGNhc2UgMHg4YjUxOiByZXR1cm4gc2V0VmFsdWVWM2ZBcnJheTsgLy8gX1ZFQzNcblx0XHRjYXNlIDB4OGI1MjogcmV0dXJuIHNldFZhbHVlVjRmQXJyYXk7IC8vIF9WRUM0XG5cblx0XHRjYXNlIDB4OGI1YTogcmV0dXJuIHNldFZhbHVlTTJBcnJheTsgLy8gX01BVDJcblx0XHRjYXNlIDB4OGI1YjogcmV0dXJuIHNldFZhbHVlTTNBcnJheTsgLy8gX01BVDNcblx0XHRjYXNlIDB4OGI1YzogcmV0dXJuIHNldFZhbHVlTTRBcnJheTsgLy8gX01BVDRcblxuXHRcdGNhc2UgMHgxNDA0OiBjYXNlIDB4OGI1NjogcmV0dXJuIHNldFZhbHVlVjFpQXJyYXk7IC8vIElOVCwgQk9PTFxuXHRcdGNhc2UgMHg4YjUzOiBjYXNlIDB4OGI1NzogcmV0dXJuIHNldFZhbHVlVjJpQXJyYXk7IC8vIF9WRUMyXG5cdFx0Y2FzZSAweDhiNTQ6IGNhc2UgMHg4YjU4OiByZXR1cm4gc2V0VmFsdWVWM2lBcnJheTsgLy8gX1ZFQzNcblx0XHRjYXNlIDB4OGI1NTogY2FzZSAweDhiNTk6IHJldHVybiBzZXRWYWx1ZVY0aUFycmF5OyAvLyBfVkVDNFxuXG5cdFx0Y2FzZSAweDE0MDU6IHJldHVybiBzZXRWYWx1ZVYxdWlBcnJheTsgLy8gVUlOVFxuXHRcdGNhc2UgMHg4ZGM2OiByZXR1cm4gc2V0VmFsdWVWMnVpQXJyYXk7IC8vIF9WRUMyXG5cdFx0Y2FzZSAweDhkYzc6IHJldHVybiBzZXRWYWx1ZVYzdWlBcnJheTsgLy8gX1ZFQzNcblx0XHRjYXNlIDB4OGRjODogcmV0dXJuIHNldFZhbHVlVjR1aUFycmF5OyAvLyBfVkVDNFxuXG5cdFx0Y2FzZSAweDhiNWU6IC8vIFNBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGQ2NjogLy8gU0FNUExFUl9FWFRFUk5BTF9PRVNcblx0XHRjYXNlIDB4OGRjYTogLy8gSU5UX1NBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGRkMjogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfMkRcblx0XHRjYXNlIDB4OGI2MjogLy8gU0FNUExFUl8yRF9TSEFET1dcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQxQXJyYXk7XG5cblx0XHRjYXNlIDB4OGI1ZjogLy8gU0FNUExFUl8zRFxuXHRcdGNhc2UgMHg4ZGNiOiAvLyBJTlRfU0FNUExFUl8zRFxuXHRcdGNhc2UgMHg4ZGQzOiAvLyBVTlNJR05FRF9JTlRfU0FNUExFUl8zRFxuXHRcdFx0cmV0dXJuIHNldFZhbHVlVDNEQXJyYXk7XG5cblx0XHRjYXNlIDB4OGI2MDogLy8gU0FNUExFUl9DVUJFXG5cdFx0Y2FzZSAweDhkY2M6IC8vIElOVF9TQU1QTEVSX0NVQkVcblx0XHRjYXNlIDB4OGRkNDogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfQ1VCRVxuXHRcdGNhc2UgMHg4ZGM1OiAvLyBTQU1QTEVSX0NVQkVfU0hBRE9XXG5cdFx0XHRyZXR1cm4gc2V0VmFsdWVUNkFycmF5O1xuXG5cdFx0Y2FzZSAweDhkYzE6IC8vIFNBTVBMRVJfMkRfQVJSQVlcblx0XHRjYXNlIDB4OGRjZjogLy8gSU5UX1NBTVBMRVJfMkRfQVJSQVlcblx0XHRjYXNlIDB4OGRkNzogLy8gVU5TSUdORURfSU5UX1NBTVBMRVJfMkRfQVJSQVlcblx0XHRjYXNlIDB4OGRjNDogLy8gU0FNUExFUl8yRF9BUlJBWV9TSEFET1dcblx0XHRcdHJldHVybiBzZXRWYWx1ZVQyREFycmF5QXJyYXk7XG5cblx0fVxuXG59XG5cbi8vIC0tLSBVbmlmb3JtIENsYXNzZXMgLS0tXG5cbmNsYXNzIFNpbmdsZVVuaWZvcm0ge1xuXG5cdGNvbnN0cnVjdG9yKCBpZCwgYWN0aXZlSW5mbywgYWRkciApIHtcblxuXHRcdHRoaXMuaWQgPSBpZDtcblx0XHR0aGlzLmFkZHIgPSBhZGRyO1xuXHRcdHRoaXMuY2FjaGUgPSBbXTtcblx0XHR0aGlzLnR5cGUgPSBhY3RpdmVJbmZvLnR5cGU7XG5cdFx0dGhpcy5zZXRWYWx1ZSA9IGdldFNpbmd1bGFyU2V0dGVyKCBhY3RpdmVJbmZvLnR5cGUgKTtcblxuXHRcdC8vIHRoaXMucGF0aCA9IGFjdGl2ZUluZm8ubmFtZTsgLy8gREVCVUdcblxuXHR9XG5cbn1cblxuY2xhc3MgUHVyZUFycmF5VW5pZm9ybSB7XG5cblx0Y29uc3RydWN0b3IoIGlkLCBhY3RpdmVJbmZvLCBhZGRyICkge1xuXG5cdFx0dGhpcy5pZCA9IGlkO1xuXHRcdHRoaXMuYWRkciA9IGFkZHI7XG5cdFx0dGhpcy5jYWNoZSA9IFtdO1xuXHRcdHRoaXMudHlwZSA9IGFjdGl2ZUluZm8udHlwZTtcblx0XHR0aGlzLnNpemUgPSBhY3RpdmVJbmZvLnNpemU7XG5cdFx0dGhpcy5zZXRWYWx1ZSA9IGdldFB1cmVBcnJheVNldHRlciggYWN0aXZlSW5mby50eXBlICk7XG5cblx0XHQvLyB0aGlzLnBhdGggPSBhY3RpdmVJbmZvLm5hbWU7IC8vIERFQlVHXG5cblx0fVxuXG59XG5cbmNsYXNzIFN0cnVjdHVyZWRVbmlmb3JtIHtcblxuXHRjb25zdHJ1Y3RvciggaWQgKSB7XG5cblx0XHR0aGlzLmlkID0gaWQ7XG5cblx0XHR0aGlzLnNlcSA9IFtdO1xuXHRcdHRoaXMubWFwID0ge307XG5cblx0fVxuXG5cdHNldFZhbHVlKCBnbCwgdmFsdWUsIHRleHR1cmVzICkge1xuXG5cdFx0Y29uc3Qgc2VxID0gdGhpcy5zZXE7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBzZXEubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCB1ID0gc2VxWyBpIF07XG5cdFx0XHR1LnNldFZhbHVlKCBnbCwgdmFsdWVbIHUuaWQgXSwgdGV4dHVyZXMgKTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuLy8gLS0tIFRvcC1sZXZlbCAtLS1cblxuLy8gUGFyc2VyIC0gYnVpbGRzIHVwIHRoZSBwcm9wZXJ0eSB0cmVlIGZyb20gdGhlIHBhdGggc3RyaW5nc1xuXG5jb25zdCBSZVBhdGhQYXJ0ID0gLyhcXHcrKShcXF0pPyhcXFt8XFwuKT8vZztcblxuLy8gZXh0cmFjdHNcbi8vIFx0LSB0aGUgaWRlbnRpZmllciAobWVtYmVyIG5hbWUgb3IgYXJyYXkgaW5kZXgpXG4vLyAgLSBmb2xsb3dlZCBieSBhbiBvcHRpb25hbCByaWdodCBicmFja2V0IChmb3VuZCB3aGVuIGFycmF5IGluZGV4KVxuLy8gIC0gZm9sbG93ZWQgYnkgYW4gb3B0aW9uYWwgbGVmdCBicmFja2V0IG9yIGRvdCAodHlwZSBvZiBzdWJzY3JpcHQpXG4vL1xuLy8gTm90ZTogVGhlc2UgcG9ydGlvbnMgY2FuIGJlIHJlYWQgaW4gYSBub24tb3ZlcmxhcHBpbmcgZmFzaGlvbiBhbmRcbi8vIGFsbG93IHN0cmFpZ2h0Zm9yd2FyZCBwYXJzaW5nIG9mIHRoZSBoaWVyYXJjaHkgdGhhdCBXZWJHTCBlbmNvZGVzXG4vLyBpbiB0aGUgdW5pZm9ybSBuYW1lcy5cblxuZnVuY3Rpb24gYWRkVW5pZm9ybSggY29udGFpbmVyLCB1bmlmb3JtT2JqZWN0ICkge1xuXG5cdGNvbnRhaW5lci5zZXEucHVzaCggdW5pZm9ybU9iamVjdCApO1xuXHRjb250YWluZXIubWFwWyB1bmlmb3JtT2JqZWN0LmlkIF0gPSB1bmlmb3JtT2JqZWN0O1xuXG59XG5cbmZ1bmN0aW9uIHBhcnNlVW5pZm9ybSggYWN0aXZlSW5mbywgYWRkciwgY29udGFpbmVyICkge1xuXG5cdGNvbnN0IHBhdGggPSBhY3RpdmVJbmZvLm5hbWUsXG5cdFx0cGF0aExlbmd0aCA9IHBhdGgubGVuZ3RoO1xuXG5cdC8vIHJlc2V0IFJlZ0V4cCBvYmplY3QsIGJlY2F1c2Ugb2YgdGhlIGVhcmx5IGV4aXQgb2YgYSBwcmV2aW91cyBydW5cblx0UmVQYXRoUGFydC5sYXN0SW5kZXggPSAwO1xuXG5cdHdoaWxlICggdHJ1ZSApIHtcblxuXHRcdGNvbnN0IG1hdGNoID0gUmVQYXRoUGFydC5leGVjKCBwYXRoICksXG5cdFx0XHRtYXRjaEVuZCA9IFJlUGF0aFBhcnQubGFzdEluZGV4O1xuXG5cdFx0bGV0IGlkID0gbWF0Y2hbIDEgXTtcblx0XHRjb25zdCBpZElzSW5kZXggPSBtYXRjaFsgMiBdID09PSAnXScsXG5cdFx0XHRzdWJzY3JpcHQgPSBtYXRjaFsgMyBdO1xuXG5cdFx0aWYgKCBpZElzSW5kZXggKSBpZCA9IGlkIHwgMDsgLy8gY29udmVydCB0byBpbnRlZ2VyXG5cblx0XHRpZiAoIHN1YnNjcmlwdCA9PT0gdW5kZWZpbmVkIHx8IHN1YnNjcmlwdCA9PT0gJ1snICYmIG1hdGNoRW5kICsgMiA9PT0gcGF0aExlbmd0aCApIHtcblxuXHRcdFx0Ly8gYmFyZSBuYW1lIG9yIFwicHVyZVwiIGJvdHRvbS1sZXZlbCBhcnJheSBcIlswXVwiIHN1ZmZpeFxuXG5cdFx0XHRhZGRVbmlmb3JtKCBjb250YWluZXIsIHN1YnNjcmlwdCA9PT0gdW5kZWZpbmVkID9cblx0XHRcdFx0bmV3IFNpbmdsZVVuaWZvcm0oIGlkLCBhY3RpdmVJbmZvLCBhZGRyICkgOlxuXHRcdFx0XHRuZXcgUHVyZUFycmF5VW5pZm9ybSggaWQsIGFjdGl2ZUluZm8sIGFkZHIgKSApO1xuXG5cdFx0XHRicmVhaztcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIHN0ZXAgaW50byBpbm5lciBub2RlIC8gY3JlYXRlIGl0IGluIGNhc2UgaXQgZG9lc24ndCBleGlzdFxuXG5cdFx0XHRjb25zdCBtYXAgPSBjb250YWluZXIubWFwO1xuXHRcdFx0bGV0IG5leHQgPSBtYXBbIGlkIF07XG5cblx0XHRcdGlmICggbmV4dCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdG5leHQgPSBuZXcgU3RydWN0dXJlZFVuaWZvcm0oIGlkICk7XG5cdFx0XHRcdGFkZFVuaWZvcm0oIGNvbnRhaW5lciwgbmV4dCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnRhaW5lciA9IG5leHQ7XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbi8vIFJvb3QgQ29udGFpbmVyXG5cbmNsYXNzIFdlYkdMVW5pZm9ybXMge1xuXG5cdGNvbnN0cnVjdG9yKCBnbCwgcHJvZ3JhbSApIHtcblxuXHRcdHRoaXMuc2VxID0gW107XG5cdFx0dGhpcy5tYXAgPSB7fTtcblxuXHRcdGNvbnN0IG4gPSBnbC5nZXRQcm9ncmFtUGFyYW1ldGVyKCBwcm9ncmFtLCBnbC5BQ1RJVkVfVU5JRk9STVMgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG47ICsrIGkgKSB7XG5cblx0XHRcdGNvbnN0IGluZm8gPSBnbC5nZXRBY3RpdmVVbmlmb3JtKCBwcm9ncmFtLCBpICksXG5cdFx0XHRcdGFkZHIgPSBnbC5nZXRVbmlmb3JtTG9jYXRpb24oIHByb2dyYW0sIGluZm8ubmFtZSApO1xuXG5cdFx0XHRwYXJzZVVuaWZvcm0oIGluZm8sIGFkZHIsIHRoaXMgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0c2V0VmFsdWUoIGdsLCBuYW1lLCB2YWx1ZSwgdGV4dHVyZXMgKSB7XG5cblx0XHRjb25zdCB1ID0gdGhpcy5tYXBbIG5hbWUgXTtcblxuXHRcdGlmICggdSAhPT0gdW5kZWZpbmVkICkgdS5zZXRWYWx1ZSggZ2wsIHZhbHVlLCB0ZXh0dXJlcyApO1xuXG5cdH1cblxuXHRzZXRPcHRpb25hbCggZ2wsIG9iamVjdCwgbmFtZSApIHtcblxuXHRcdGNvbnN0IHYgPSBvYmplY3RbIG5hbWUgXTtcblxuXHRcdGlmICggdiAhPT0gdW5kZWZpbmVkICkgdGhpcy5zZXRWYWx1ZSggZ2wsIG5hbWUsIHYgKTtcblxuXHR9XG5cblx0c3RhdGljIHVwbG9hZCggZ2wsIHNlcSwgdmFsdWVzLCB0ZXh0dXJlcyApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IHNlcS5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdGNvbnN0IHUgPSBzZXFbIGkgXSxcblx0XHRcdFx0diA9IHZhbHVlc1sgdS5pZCBdO1xuXG5cdFx0XHRpZiAoIHYubmVlZHNVcGRhdGUgIT09IGZhbHNlICkge1xuXG5cdFx0XHRcdC8vIG5vdGU6IGFsd2F5cyB1cGRhdGluZyB3aGVuIC5uZWVkc1VwZGF0ZSBpcyB1bmRlZmluZWRcblx0XHRcdFx0dS5zZXRWYWx1ZSggZ2wsIHYudmFsdWUsIHRleHR1cmVzICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0c3RhdGljIHNlcVdpdGhWYWx1ZSggc2VxLCB2YWx1ZXMgKSB7XG5cblx0XHRjb25zdCByID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBzZXEubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCB1ID0gc2VxWyBpIF07XG5cdFx0XHRpZiAoIHUuaWQgaW4gdmFsdWVzICkgci5wdXNoKCB1ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcjtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xTaGFkZXIoIGdsLCB0eXBlLCBzdHJpbmcgKSB7XG5cblx0Y29uc3Qgc2hhZGVyID0gZ2wuY3JlYXRlU2hhZGVyKCB0eXBlICk7XG5cblx0Z2wuc2hhZGVyU291cmNlKCBzaGFkZXIsIHN0cmluZyApO1xuXHRnbC5jb21waWxlU2hhZGVyKCBzaGFkZXIgKTtcblxuXHRyZXR1cm4gc2hhZGVyO1xuXG59XG5cbi8vIEZyb20gaHR0cHM6Ly93d3cua2hyb25vcy5vcmcvcmVnaXN0cnkvd2ViZ2wvZXh0ZW5zaW9ucy9LSFJfcGFyYWxsZWxfc2hhZGVyX2NvbXBpbGUvXG5jb25zdCBDT01QTEVUSU9OX1NUQVRVU19LSFIgPSAweDkxQjE7XG5cbmxldCBwcm9ncmFtSWRDb3VudCA9IDA7XG5cbmZ1bmN0aW9uIGhhbmRsZVNvdXJjZSggc3RyaW5nLCBlcnJvckxpbmUgKSB7XG5cblx0Y29uc3QgbGluZXMgPSBzdHJpbmcuc3BsaXQoICdcXG4nICk7XG5cdGNvbnN0IGxpbmVzMiA9IFtdO1xuXG5cdGNvbnN0IGZyb20gPSBNYXRoLm1heCggZXJyb3JMaW5lIC0gNiwgMCApO1xuXHRjb25zdCB0byA9IE1hdGgubWluKCBlcnJvckxpbmUgKyA2LCBsaW5lcy5sZW5ndGggKTtcblxuXHRmb3IgKCBsZXQgaSA9IGZyb207IGkgPCB0bzsgaSArKyApIHtcblxuXHRcdGNvbnN0IGxpbmUgPSBpICsgMTtcblx0XHRsaW5lczIucHVzaCggYCR7bGluZSA9PT0gZXJyb3JMaW5lID8gJz4nIDogJyAnfSAke2xpbmV9OiAke2xpbmVzWyBpIF19YCApO1xuXG5cdH1cblxuXHRyZXR1cm4gbGluZXMyLmpvaW4oICdcXG4nICk7XG5cbn1cblxuZnVuY3Rpb24gZ2V0RW5jb2RpbmdDb21wb25lbnRzKCBjb2xvclNwYWNlICkge1xuXG5cdGNvbnN0IHdvcmtpbmdQcmltYXJpZXMgPSBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCBDb2xvck1hbmFnZW1lbnQud29ya2luZ0NvbG9yU3BhY2UgKTtcblx0Y29uc3QgZW5jb2RpbmdQcmltYXJpZXMgPSBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCBjb2xvclNwYWNlICk7XG5cblx0bGV0IGdhbXV0TWFwcGluZztcblxuXHRpZiAoIHdvcmtpbmdQcmltYXJpZXMgPT09IGVuY29kaW5nUHJpbWFyaWVzICkge1xuXG5cdFx0Z2FtdXRNYXBwaW5nID0gJyc7XG5cblx0fSBlbHNlIGlmICggd29ya2luZ1ByaW1hcmllcyA9PT0gUDNQcmltYXJpZXMgJiYgZW5jb2RpbmdQcmltYXJpZXMgPT09IFJlYzcwOVByaW1hcmllcyApIHtcblxuXHRcdGdhbXV0TWFwcGluZyA9ICdMaW5lYXJEaXNwbGF5UDNUb0xpbmVhclNSR0InO1xuXG5cdH0gZWxzZSBpZiAoIHdvcmtpbmdQcmltYXJpZXMgPT09IFJlYzcwOVByaW1hcmllcyAmJiBlbmNvZGluZ1ByaW1hcmllcyA9PT0gUDNQcmltYXJpZXMgKSB7XG5cblx0XHRnYW11dE1hcHBpbmcgPSAnTGluZWFyU1JHQlRvTGluZWFyRGlzcGxheVAzJztcblxuXHR9XG5cblx0c3dpdGNoICggY29sb3JTcGFjZSApIHtcblxuXHRcdGNhc2UgTGluZWFyU1JHQkNvbG9yU3BhY2U6XG5cdFx0Y2FzZSBMaW5lYXJEaXNwbGF5UDNDb2xvclNwYWNlOlxuXHRcdFx0cmV0dXJuIFsgZ2FtdXRNYXBwaW5nLCAnTGluZWFyVHJhbnNmZXJPRVRGJyBdO1xuXG5cdFx0Y2FzZSBTUkdCQ29sb3JTcGFjZTpcblx0XHRjYXNlIERpc3BsYXlQM0NvbG9yU3BhY2U6XG5cdFx0XHRyZXR1cm4gWyBnYW11dE1hcHBpbmcsICdzUkdCVHJhbnNmZXJPRVRGJyBdO1xuXG5cdFx0ZGVmYXVsdDpcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUHJvZ3JhbTogVW5zdXBwb3J0ZWQgY29sb3Igc3BhY2U6JywgY29sb3JTcGFjZSApO1xuXHRcdFx0cmV0dXJuIFsgZ2FtdXRNYXBwaW5nLCAnTGluZWFyVHJhbnNmZXJPRVRGJyBdO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBnZXRTaGFkZXJFcnJvcnMoIGdsLCBzaGFkZXIsIHR5cGUgKSB7XG5cblx0Y29uc3Qgc3RhdHVzID0gZ2wuZ2V0U2hhZGVyUGFyYW1ldGVyKCBzaGFkZXIsIGdsLkNPTVBJTEVfU1RBVFVTICk7XG5cdGNvbnN0IGVycm9ycyA9IGdsLmdldFNoYWRlckluZm9Mb2coIHNoYWRlciApLnRyaW0oKTtcblxuXHRpZiAoIHN0YXR1cyAmJiBlcnJvcnMgPT09ICcnICkgcmV0dXJuICcnO1xuXG5cdGNvbnN0IGVycm9yTWF0Y2hlcyA9IC9FUlJPUjogMDooXFxkKykvLmV4ZWMoIGVycm9ycyApO1xuXHRpZiAoIGVycm9yTWF0Y2hlcyApIHtcblxuXHRcdC8vIC0tZW5hYmxlLXByaXZpbGVnZWQtd2ViZ2wtZXh0ZW5zaW9uXG5cdFx0Ly8gY29uc29sZS5sb2coICcqKicgKyB0eXBlICsgJyoqJywgZ2wuZ2V0RXh0ZW5zaW9uKCAnV0VCR0xfZGVidWdfc2hhZGVycycgKS5nZXRUcmFuc2xhdGVkU2hhZGVyU291cmNlKCBzaGFkZXIgKSApO1xuXG5cdFx0Y29uc3QgZXJyb3JMaW5lID0gcGFyc2VJbnQoIGVycm9yTWF0Y2hlc1sgMSBdICk7XG5cdFx0cmV0dXJuIHR5cGUudG9VcHBlckNhc2UoKSArICdcXG5cXG4nICsgZXJyb3JzICsgJ1xcblxcbicgKyBoYW5kbGVTb3VyY2UoIGdsLmdldFNoYWRlclNvdXJjZSggc2hhZGVyICksIGVycm9yTGluZSApO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRyZXR1cm4gZXJyb3JzO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBnZXRUZXhlbEVuY29kaW5nRnVuY3Rpb24oIGZ1bmN0aW9uTmFtZSwgY29sb3JTcGFjZSApIHtcblxuXHRjb25zdCBjb21wb25lbnRzID0gZ2V0RW5jb2RpbmdDb21wb25lbnRzKCBjb2xvclNwYWNlICk7XG5cdHJldHVybiBgdmVjNCAke2Z1bmN0aW9uTmFtZX0oIHZlYzQgdmFsdWUgKSB7IHJldHVybiAke2NvbXBvbmVudHNbIDAgXX0oICR7Y29tcG9uZW50c1sgMSBdfSggdmFsdWUgKSApOyB9YDtcblxufVxuXG5mdW5jdGlvbiBnZXRUb25lTWFwcGluZ0Z1bmN0aW9uKCBmdW5jdGlvbk5hbWUsIHRvbmVNYXBwaW5nICkge1xuXG5cdGxldCB0b25lTWFwcGluZ05hbWU7XG5cblx0c3dpdGNoICggdG9uZU1hcHBpbmcgKSB7XG5cblx0XHRjYXNlIExpbmVhclRvbmVNYXBwaW5nOlxuXHRcdFx0dG9uZU1hcHBpbmdOYW1lID0gJ0xpbmVhcic7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgUmVpbmhhcmRUb25lTWFwcGluZzpcblx0XHRcdHRvbmVNYXBwaW5nTmFtZSA9ICdSZWluaGFyZCc7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgQ2luZW9uVG9uZU1hcHBpbmc6XG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnT3B0aW1pemVkQ2luZW9uJztcblx0XHRcdGJyZWFrO1xuXG5cdFx0Y2FzZSBBQ0VTRmlsbWljVG9uZU1hcHBpbmc6XG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnQUNFU0ZpbG1pYyc7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgQWdYVG9uZU1hcHBpbmc6XG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnQWdYJztcblx0XHRcdGJyZWFrO1xuXG5cdFx0Y2FzZSBOZXV0cmFsVG9uZU1hcHBpbmc6XG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnTmV1dHJhbCc7XG5cdFx0XHRicmVhaztcblxuXHRcdGNhc2UgQ3VzdG9tVG9uZU1hcHBpbmc6XG5cdFx0XHR0b25lTWFwcGluZ05hbWUgPSAnQ3VzdG9tJztcblx0XHRcdGJyZWFrO1xuXG5cdFx0ZGVmYXVsdDpcblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUHJvZ3JhbTogVW5zdXBwb3J0ZWQgdG9uZU1hcHBpbmc6JywgdG9uZU1hcHBpbmcgKTtcblx0XHRcdHRvbmVNYXBwaW5nTmFtZSA9ICdMaW5lYXInO1xuXG5cdH1cblxuXHRyZXR1cm4gJ3ZlYzMgJyArIGZ1bmN0aW9uTmFtZSArICcoIHZlYzMgY29sb3IgKSB7IHJldHVybiAnICsgdG9uZU1hcHBpbmdOYW1lICsgJ1RvbmVNYXBwaW5nKCBjb2xvciApOyB9JztcblxufVxuXG5jb25zdCBfdjAkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuZnVuY3Rpb24gZ2V0THVtaW5hbmNlRnVuY3Rpb24oKSB7XG5cblx0Q29sb3JNYW5hZ2VtZW50LmdldEx1bWluYW5jZUNvZWZmaWNpZW50cyggX3YwJDEgKTtcblxuXHRjb25zdCByID0gX3YwJDEueC50b0ZpeGVkKCA0ICk7XG5cdGNvbnN0IGcgPSBfdjAkMS55LnRvRml4ZWQoIDQgKTtcblx0Y29uc3QgYiA9IF92MCQxLnoudG9GaXhlZCggNCApO1xuXG5cdHJldHVybiBbXG5cblx0XHQnZmxvYXQgbHVtaW5hbmNlKCBjb25zdCBpbiB2ZWMzIHJnYiApIHsnLFxuXG5cdFx0YFx0Y29uc3QgdmVjMyB3ZWlnaHRzID0gdmVjMyggJHsgciB9LCAkeyBnIH0sICR7IGIgfSApO2AsXG5cblx0XHQnXHRyZXR1cm4gZG90KCB3ZWlnaHRzLCByZ2IgKTsnLFxuXG5cdFx0J30nXG5cblx0XS5qb2luKCAnXFxuJyApO1xuXG59XG5cbmZ1bmN0aW9uIGdlbmVyYXRlVmVydGV4RXh0ZW5zaW9ucyggcGFyYW1ldGVycyApIHtcblxuXHRjb25zdCBjaHVua3MgPSBbXG5cdFx0cGFyYW1ldGVycy5leHRlbnNpb25DbGlwQ3VsbERpc3RhbmNlID8gJyNleHRlbnNpb24gR0xfQU5HTEVfY2xpcF9jdWxsX2Rpc3RhbmNlIDogcmVxdWlyZScgOiAnJyxcblx0XHRwYXJhbWV0ZXJzLmV4dGVuc2lvbk11bHRpRHJhdyA/ICcjZXh0ZW5zaW9uIEdMX0FOR0xFX211bHRpX2RyYXcgOiByZXF1aXJlJyA6ICcnLFxuXHRdO1xuXG5cdHJldHVybiBjaHVua3MuZmlsdGVyKCBmaWx0ZXJFbXB0eUxpbmUgKS5qb2luKCAnXFxuJyApO1xuXG59XG5cbmZ1bmN0aW9uIGdlbmVyYXRlRGVmaW5lcyggZGVmaW5lcyApIHtcblxuXHRjb25zdCBjaHVua3MgPSBbXTtcblxuXHRmb3IgKCBjb25zdCBuYW1lIGluIGRlZmluZXMgKSB7XG5cblx0XHRjb25zdCB2YWx1ZSA9IGRlZmluZXNbIG5hbWUgXTtcblxuXHRcdGlmICggdmFsdWUgPT09IGZhbHNlICkgY29udGludWU7XG5cblx0XHRjaHVua3MucHVzaCggJyNkZWZpbmUgJyArIG5hbWUgKyAnICcgKyB2YWx1ZSApO1xuXG5cdH1cblxuXHRyZXR1cm4gY2h1bmtzLmpvaW4oICdcXG4nICk7XG5cbn1cblxuZnVuY3Rpb24gZmV0Y2hBdHRyaWJ1dGVMb2NhdGlvbnMoIGdsLCBwcm9ncmFtICkge1xuXG5cdGNvbnN0IGF0dHJpYnV0ZXMgPSB7fTtcblxuXHRjb25zdCBuID0gZ2wuZ2V0UHJvZ3JhbVBhcmFtZXRlciggcHJvZ3JhbSwgZ2wuQUNUSVZFX0FUVFJJQlVURVMgKTtcblxuXHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBuOyBpICsrICkge1xuXG5cdFx0Y29uc3QgaW5mbyA9IGdsLmdldEFjdGl2ZUF0dHJpYiggcHJvZ3JhbSwgaSApO1xuXHRcdGNvbnN0IG5hbWUgPSBpbmZvLm5hbWU7XG5cblx0XHRsZXQgbG9jYXRpb25TaXplID0gMTtcblx0XHRpZiAoIGluZm8udHlwZSA9PT0gZ2wuRkxPQVRfTUFUMiApIGxvY2F0aW9uU2l6ZSA9IDI7XG5cdFx0aWYgKCBpbmZvLnR5cGUgPT09IGdsLkZMT0FUX01BVDMgKSBsb2NhdGlvblNpemUgPSAzO1xuXHRcdGlmICggaW5mby50eXBlID09PSBnbC5GTE9BVF9NQVQ0ICkgbG9jYXRpb25TaXplID0gNDtcblxuXHRcdC8vIGNvbnNvbGUubG9nKCAnVEhSRUUuV2ViR0xQcm9ncmFtOiBBQ1RJVkUgVkVSVEVYIEFUVFJJQlVURTonLCBuYW1lLCBpICk7XG5cblx0XHRhdHRyaWJ1dGVzWyBuYW1lIF0gPSB7XG5cdFx0XHR0eXBlOiBpbmZvLnR5cGUsXG5cdFx0XHRsb2NhdGlvbjogZ2wuZ2V0QXR0cmliTG9jYXRpb24oIHByb2dyYW0sIG5hbWUgKSxcblx0XHRcdGxvY2F0aW9uU2l6ZTogbG9jYXRpb25TaXplXG5cdFx0fTtcblxuXHR9XG5cblx0cmV0dXJuIGF0dHJpYnV0ZXM7XG5cbn1cblxuZnVuY3Rpb24gZmlsdGVyRW1wdHlMaW5lKCBzdHJpbmcgKSB7XG5cblx0cmV0dXJuIHN0cmluZyAhPT0gJyc7XG5cbn1cblxuZnVuY3Rpb24gcmVwbGFjZUxpZ2h0TnVtcyggc3RyaW5nLCBwYXJhbWV0ZXJzICkge1xuXG5cdGNvbnN0IG51bVNwb3RMaWdodENvb3JkcyA9IHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0U2hhZG93cyArIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0TWFwcyAtIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0U2hhZG93c1dpdGhNYXBzO1xuXG5cdHJldHVybiBzdHJpbmdcblx0XHQucmVwbGFjZSggL05VTV9ESVJfTElHSFRTL2csIHBhcmFtZXRlcnMubnVtRGlyTGlnaHRzIClcblx0XHQucmVwbGFjZSggL05VTV9TUE9UX0xJR0hUUy9nLCBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodHMgKVxuXHRcdC5yZXBsYWNlKCAvTlVNX1NQT1RfTElHSFRfTUFQUy9nLCBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodE1hcHMgKVxuXHRcdC5yZXBsYWNlKCAvTlVNX1NQT1RfTElHSFRfQ09PUkRTL2csIG51bVNwb3RMaWdodENvb3JkcyApXG5cdFx0LnJlcGxhY2UoIC9OVU1fUkVDVF9BUkVBX0xJR0hUUy9nLCBwYXJhbWV0ZXJzLm51bVJlY3RBcmVhTGlnaHRzIClcblx0XHQucmVwbGFjZSggL05VTV9QT0lOVF9MSUdIVFMvZywgcGFyYW1ldGVycy5udW1Qb2ludExpZ2h0cyApXG5cdFx0LnJlcGxhY2UoIC9OVU1fSEVNSV9MSUdIVFMvZywgcGFyYW1ldGVycy5udW1IZW1pTGlnaHRzIClcblx0XHQucmVwbGFjZSggL05VTV9ESVJfTElHSFRfU0hBRE9XUy9nLCBwYXJhbWV0ZXJzLm51bURpckxpZ2h0U2hhZG93cyApXG5cdFx0LnJlcGxhY2UoIC9OVU1fU1BPVF9MSUdIVF9TSEFET1dTX1dJVEhfTUFQUy9nLCBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodFNoYWRvd3NXaXRoTWFwcyApXG5cdFx0LnJlcGxhY2UoIC9OVU1fU1BPVF9MSUdIVF9TSEFET1dTL2csIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0U2hhZG93cyApXG5cdFx0LnJlcGxhY2UoIC9OVU1fUE9JTlRfTElHSFRfU0hBRE9XUy9nLCBwYXJhbWV0ZXJzLm51bVBvaW50TGlnaHRTaGFkb3dzICk7XG5cbn1cblxuZnVuY3Rpb24gcmVwbGFjZUNsaXBwaW5nUGxhbmVOdW1zKCBzdHJpbmcsIHBhcmFtZXRlcnMgKSB7XG5cblx0cmV0dXJuIHN0cmluZ1xuXHRcdC5yZXBsYWNlKCAvTlVNX0NMSVBQSU5HX1BMQU5FUy9nLCBwYXJhbWV0ZXJzLm51bUNsaXBwaW5nUGxhbmVzIClcblx0XHQucmVwbGFjZSggL1VOSU9OX0NMSVBQSU5HX1BMQU5FUy9nLCAoIHBhcmFtZXRlcnMubnVtQ2xpcHBpbmdQbGFuZXMgLSBwYXJhbWV0ZXJzLm51bUNsaXBJbnRlcnNlY3Rpb24gKSApO1xuXG59XG5cbi8vIFJlc29sdmUgSW5jbHVkZXNcblxuY29uc3QgaW5jbHVkZVBhdHRlcm4gPSAvXlsgXFx0XSojaW5jbHVkZSArPChbXFx3XFxkLi9dKyk+L2dtO1xuXG5mdW5jdGlvbiByZXNvbHZlSW5jbHVkZXMoIHN0cmluZyApIHtcblxuXHRyZXR1cm4gc3RyaW5nLnJlcGxhY2UoIGluY2x1ZGVQYXR0ZXJuLCBpbmNsdWRlUmVwbGFjZXIgKTtcblxufVxuXG5jb25zdCBzaGFkZXJDaHVua01hcCA9IG5ldyBNYXAoKTtcblxuZnVuY3Rpb24gaW5jbHVkZVJlcGxhY2VyKCBtYXRjaCwgaW5jbHVkZSApIHtcblxuXHRsZXQgc3RyaW5nID0gU2hhZGVyQ2h1bmtbIGluY2x1ZGUgXTtcblxuXHRpZiAoIHN0cmluZyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0Y29uc3QgbmV3SW5jbHVkZSA9IHNoYWRlckNodW5rTWFwLmdldCggaW5jbHVkZSApO1xuXG5cdFx0aWYgKCBuZXdJbmNsdWRlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHN0cmluZyA9IFNoYWRlckNodW5rWyBuZXdJbmNsdWRlIF07XG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBTaGFkZXIgY2h1bmsgXCIlc1wiIGhhcyBiZWVuIGRlcHJlY2F0ZWQuIFVzZSBcIiVzXCIgaW5zdGVhZC4nLCBpbmNsdWRlLCBuZXdJbmNsdWRlICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdDYW4gbm90IHJlc29sdmUgI2luY2x1ZGUgPCcgKyBpbmNsdWRlICsgJz4nICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHJldHVybiByZXNvbHZlSW5jbHVkZXMoIHN0cmluZyApO1xuXG59XG5cbi8vIFVucm9sbCBMb29wc1xuXG5jb25zdCB1bnJvbGxMb29wUGF0dGVybiA9IC8jcHJhZ21hIHVucm9sbF9sb29wX3N0YXJ0XFxzK2ZvclxccypcXChcXHMqaW50XFxzK2lcXHMqPVxccyooXFxkKylcXHMqO1xccyppXFxzKjxcXHMqKFxcZCspXFxzKjtcXHMqaVxccypcXCtcXCtcXHMqXFwpXFxzKnsoW1xcc1xcU10rPyl9XFxzKyNwcmFnbWEgdW5yb2xsX2xvb3BfZW5kL2c7XG5cbmZ1bmN0aW9uIHVucm9sbExvb3BzKCBzdHJpbmcgKSB7XG5cblx0cmV0dXJuIHN0cmluZy5yZXBsYWNlKCB1bnJvbGxMb29wUGF0dGVybiwgbG9vcFJlcGxhY2VyICk7XG5cbn1cblxuZnVuY3Rpb24gbG9vcFJlcGxhY2VyKCBtYXRjaCwgc3RhcnQsIGVuZCwgc25pcHBldCApIHtcblxuXHRsZXQgc3RyaW5nID0gJyc7XG5cblx0Zm9yICggbGV0IGkgPSBwYXJzZUludCggc3RhcnQgKTsgaSA8IHBhcnNlSW50KCBlbmQgKTsgaSArKyApIHtcblxuXHRcdHN0cmluZyArPSBzbmlwcGV0XG5cdFx0XHQucmVwbGFjZSggL1xcW1xccyppXFxzKlxcXS9nLCAnWyAnICsgaSArICcgXScgKVxuXHRcdFx0LnJlcGxhY2UoIC9VTlJPTExFRF9MT09QX0lOREVYL2csIGkgKTtcblxuXHR9XG5cblx0cmV0dXJuIHN0cmluZztcblxufVxuXG4vL1xuXG5mdW5jdGlvbiBnZW5lcmF0ZVByZWNpc2lvbiggcGFyYW1ldGVycyApIHtcblxuXHRsZXQgcHJlY2lzaW9uc3RyaW5nID0gYHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBmbG9hdDtcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IGludDtcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHNhbXBsZXIyRDtcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHNhbXBsZXJDdWJlO1xuXHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gc2FtcGxlcjNEO1xuXHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gc2FtcGxlcjJEQXJyYXk7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBzYW1wbGVyMkRTaGFkb3c7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBzYW1wbGVyQ3ViZVNoYWRvdztcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHNhbXBsZXIyREFycmF5U2hhZG93O1xuXHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gaXNhbXBsZXIyRDtcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IGlzYW1wbGVyM0Q7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBpc2FtcGxlckN1YmU7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSBpc2FtcGxlcjJEQXJyYXk7XG5cdHByZWNpc2lvbiAke3BhcmFtZXRlcnMucHJlY2lzaW9ufSB1c2FtcGxlcjJEO1xuXHRwcmVjaXNpb24gJHtwYXJhbWV0ZXJzLnByZWNpc2lvbn0gdXNhbXBsZXIzRDtcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHVzYW1wbGVyQ3ViZTtcblx0cHJlY2lzaW9uICR7cGFyYW1ldGVycy5wcmVjaXNpb259IHVzYW1wbGVyMkRBcnJheTtcblx0YDtcblxuXHRpZiAoIHBhcmFtZXRlcnMucHJlY2lzaW9uID09PSAnaGlnaHAnICkge1xuXG5cdFx0cHJlY2lzaW9uc3RyaW5nICs9ICdcXG4jZGVmaW5lIEhJR0hfUFJFQ0lTSU9OJztcblxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLnByZWNpc2lvbiA9PT0gJ21lZGl1bXAnICkge1xuXG5cdFx0cHJlY2lzaW9uc3RyaW5nICs9ICdcXG4jZGVmaW5lIE1FRElVTV9QUkVDSVNJT04nO1xuXG5cdH0gZWxzZSBpZiAoIHBhcmFtZXRlcnMucHJlY2lzaW9uID09PSAnbG93cCcgKSB7XG5cblx0XHRwcmVjaXNpb25zdHJpbmcgKz0gJ1xcbiNkZWZpbmUgTE9XX1BSRUNJU0lPTic7XG5cblx0fVxuXG5cdHJldHVybiBwcmVjaXNpb25zdHJpbmc7XG5cbn1cblxuZnVuY3Rpb24gZ2VuZXJhdGVTaGFkb3dNYXBUeXBlRGVmaW5lKCBwYXJhbWV0ZXJzICkge1xuXG5cdGxldCBzaGFkb3dNYXBUeXBlRGVmaW5lID0gJ1NIQURPV01BUF9UWVBFX0JBU0lDJztcblxuXHRpZiAoIHBhcmFtZXRlcnMuc2hhZG93TWFwVHlwZSA9PT0gUENGU2hhZG93TWFwICkge1xuXG5cdFx0c2hhZG93TWFwVHlwZURlZmluZSA9ICdTSEFET1dNQVBfVFlQRV9QQ0YnO1xuXG5cdH0gZWxzZSBpZiAoIHBhcmFtZXRlcnMuc2hhZG93TWFwVHlwZSA9PT0gUENGU29mdFNoYWRvd01hcCApIHtcblxuXHRcdHNoYWRvd01hcFR5cGVEZWZpbmUgPSAnU0hBRE9XTUFQX1RZUEVfUENGX1NPRlQnO1xuXG5cdH0gZWxzZSBpZiAoIHBhcmFtZXRlcnMuc2hhZG93TWFwVHlwZSA9PT0gVlNNU2hhZG93TWFwICkge1xuXG5cdFx0c2hhZG93TWFwVHlwZURlZmluZSA9ICdTSEFET1dNQVBfVFlQRV9WU00nO1xuXG5cdH1cblxuXHRyZXR1cm4gc2hhZG93TWFwVHlwZURlZmluZTtcblxufVxuXG5mdW5jdGlvbiBnZW5lcmF0ZUVudk1hcFR5cGVEZWZpbmUoIHBhcmFtZXRlcnMgKSB7XG5cblx0bGV0IGVudk1hcFR5cGVEZWZpbmUgPSAnRU5WTUFQX1RZUEVfQ1VCRSc7XG5cblx0aWYgKCBwYXJhbWV0ZXJzLmVudk1hcCApIHtcblxuXHRcdHN3aXRjaCAoIHBhcmFtZXRlcnMuZW52TWFwTW9kZSApIHtcblxuXHRcdFx0Y2FzZSBDdWJlUmVmbGVjdGlvbk1hcHBpbmc6XG5cdFx0XHRjYXNlIEN1YmVSZWZyYWN0aW9uTWFwcGluZzpcblx0XHRcdFx0ZW52TWFwVHlwZURlZmluZSA9ICdFTlZNQVBfVFlQRV9DVUJFJztcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmc6XG5cdFx0XHRcdGVudk1hcFR5cGVEZWZpbmUgPSAnRU5WTUFQX1RZUEVfQ1VCRV9VVic7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZXR1cm4gZW52TWFwVHlwZURlZmluZTtcblxufVxuXG5mdW5jdGlvbiBnZW5lcmF0ZUVudk1hcE1vZGVEZWZpbmUoIHBhcmFtZXRlcnMgKSB7XG5cblx0bGV0IGVudk1hcE1vZGVEZWZpbmUgPSAnRU5WTUFQX01PREVfUkVGTEVDVElPTic7XG5cblx0aWYgKCBwYXJhbWV0ZXJzLmVudk1hcCApIHtcblxuXHRcdHN3aXRjaCAoIHBhcmFtZXRlcnMuZW52TWFwTW9kZSApIHtcblxuXHRcdFx0Y2FzZSBDdWJlUmVmcmFjdGlvbk1hcHBpbmc6XG5cblx0XHRcdFx0ZW52TWFwTW9kZURlZmluZSA9ICdFTlZNQVBfTU9ERV9SRUZSQUNUSU9OJztcblx0XHRcdFx0YnJlYWs7XG5cblx0XHR9XG5cblx0fVxuXG5cdHJldHVybiBlbnZNYXBNb2RlRGVmaW5lO1xuXG59XG5cbmZ1bmN0aW9uIGdlbmVyYXRlRW52TWFwQmxlbmRpbmdEZWZpbmUoIHBhcmFtZXRlcnMgKSB7XG5cblx0bGV0IGVudk1hcEJsZW5kaW5nRGVmaW5lID0gJ0VOVk1BUF9CTEVORElOR19OT05FJztcblxuXHRpZiAoIHBhcmFtZXRlcnMuZW52TWFwICkge1xuXG5cdFx0c3dpdGNoICggcGFyYW1ldGVycy5jb21iaW5lICkge1xuXG5cdFx0XHRjYXNlIE11bHRpcGx5T3BlcmF0aW9uOlxuXHRcdFx0XHRlbnZNYXBCbGVuZGluZ0RlZmluZSA9ICdFTlZNQVBfQkxFTkRJTkdfTVVMVElQTFknO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSBNaXhPcGVyYXRpb246XG5cdFx0XHRcdGVudk1hcEJsZW5kaW5nRGVmaW5lID0gJ0VOVk1BUF9CTEVORElOR19NSVgnO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSBBZGRPcGVyYXRpb246XG5cdFx0XHRcdGVudk1hcEJsZW5kaW5nRGVmaW5lID0gJ0VOVk1BUF9CTEVORElOR19BREQnO1xuXHRcdFx0XHRicmVhaztcblxuXHRcdH1cblxuXHR9XG5cblx0cmV0dXJuIGVudk1hcEJsZW5kaW5nRGVmaW5lO1xuXG59XG5cbmZ1bmN0aW9uIGdlbmVyYXRlQ3ViZVVWU2l6ZSggcGFyYW1ldGVycyApIHtcblxuXHRjb25zdCBpbWFnZUhlaWdodCA9IHBhcmFtZXRlcnMuZW52TWFwQ3ViZVVWSGVpZ2h0O1xuXG5cdGlmICggaW1hZ2VIZWlnaHQgPT09IG51bGwgKSByZXR1cm4gbnVsbDtcblxuXHRjb25zdCBtYXhNaXAgPSBNYXRoLmxvZzIoIGltYWdlSGVpZ2h0ICkgLSAyO1xuXG5cdGNvbnN0IHRleGVsSGVpZ2h0ID0gMS4wIC8gaW1hZ2VIZWlnaHQ7XG5cblx0Y29uc3QgdGV4ZWxXaWR0aCA9IDEuMCAvICggMyAqIE1hdGgubWF4KCBNYXRoLnBvdyggMiwgbWF4TWlwICksIDcgKiAxNiApICk7XG5cblx0cmV0dXJuIHsgdGV4ZWxXaWR0aCwgdGV4ZWxIZWlnaHQsIG1heE1pcCB9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMUHJvZ3JhbSggcmVuZGVyZXIsIGNhY2hlS2V5LCBwYXJhbWV0ZXJzLCBiaW5kaW5nU3RhdGVzICkge1xuXG5cdC8vIFRPRE8gU2VuZCB0aGlzIGV2ZW50IHRvIFRocmVlLmpzIERldlRvb2xzXG5cdC8vIGNvbnNvbGUubG9nKCAnV2ViR0xQcm9ncmFtJywgY2FjaGVLZXkgKTtcblxuXHRjb25zdCBnbCA9IHJlbmRlcmVyLmdldENvbnRleHQoKTtcblxuXHRjb25zdCBkZWZpbmVzID0gcGFyYW1ldGVycy5kZWZpbmVzO1xuXG5cdGxldCB2ZXJ0ZXhTaGFkZXIgPSBwYXJhbWV0ZXJzLnZlcnRleFNoYWRlcjtcblx0bGV0IGZyYWdtZW50U2hhZGVyID0gcGFyYW1ldGVycy5mcmFnbWVudFNoYWRlcjtcblxuXHRjb25zdCBzaGFkb3dNYXBUeXBlRGVmaW5lID0gZ2VuZXJhdGVTaGFkb3dNYXBUeXBlRGVmaW5lKCBwYXJhbWV0ZXJzICk7XG5cdGNvbnN0IGVudk1hcFR5cGVEZWZpbmUgPSBnZW5lcmF0ZUVudk1hcFR5cGVEZWZpbmUoIHBhcmFtZXRlcnMgKTtcblx0Y29uc3QgZW52TWFwTW9kZURlZmluZSA9IGdlbmVyYXRlRW52TWFwTW9kZURlZmluZSggcGFyYW1ldGVycyApO1xuXHRjb25zdCBlbnZNYXBCbGVuZGluZ0RlZmluZSA9IGdlbmVyYXRlRW52TWFwQmxlbmRpbmdEZWZpbmUoIHBhcmFtZXRlcnMgKTtcblx0Y29uc3QgZW52TWFwQ3ViZVVWU2l6ZSA9IGdlbmVyYXRlQ3ViZVVWU2l6ZSggcGFyYW1ldGVycyApO1xuXG5cdGNvbnN0IGN1c3RvbVZlcnRleEV4dGVuc2lvbnMgPSBnZW5lcmF0ZVZlcnRleEV4dGVuc2lvbnMoIHBhcmFtZXRlcnMgKTtcblxuXHRjb25zdCBjdXN0b21EZWZpbmVzID0gZ2VuZXJhdGVEZWZpbmVzKCBkZWZpbmVzICk7XG5cblx0Y29uc3QgcHJvZ3JhbSA9IGdsLmNyZWF0ZVByb2dyYW0oKTtcblxuXHRsZXQgcHJlZml4VmVydGV4LCBwcmVmaXhGcmFnbWVudDtcblx0bGV0IHZlcnNpb25TdHJpbmcgPSBwYXJhbWV0ZXJzLmdsc2xWZXJzaW9uID8gJyN2ZXJzaW9uICcgKyBwYXJhbWV0ZXJzLmdsc2xWZXJzaW9uICsgJ1xcbicgOiAnJztcblxuXHRpZiAoIHBhcmFtZXRlcnMuaXNSYXdTaGFkZXJNYXRlcmlhbCApIHtcblxuXHRcdHByZWZpeFZlcnRleCA9IFtcblxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX1RZUEUgJyArIHBhcmFtZXRlcnMuc2hhZGVyVHlwZSxcblx0XHRcdCcjZGVmaW5lIFNIQURFUl9OQU1FICcgKyBwYXJhbWV0ZXJzLnNoYWRlck5hbWUsXG5cblx0XHRcdGN1c3RvbURlZmluZXNcblxuXHRcdF0uZmlsdGVyKCBmaWx0ZXJFbXB0eUxpbmUgKS5qb2luKCAnXFxuJyApO1xuXG5cdFx0aWYgKCBwcmVmaXhWZXJ0ZXgubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0cHJlZml4VmVydGV4ICs9ICdcXG4nO1xuXG5cdFx0fVxuXG5cdFx0cHJlZml4RnJhZ21lbnQgPSBbXG5cblx0XHRcdCcjZGVmaW5lIFNIQURFUl9UWVBFICcgKyBwYXJhbWV0ZXJzLnNoYWRlclR5cGUsXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfTkFNRSAnICsgcGFyYW1ldGVycy5zaGFkZXJOYW1lLFxuXG5cdFx0XHRjdXN0b21EZWZpbmVzXG5cblx0XHRdLmZpbHRlciggZmlsdGVyRW1wdHlMaW5lICkuam9pbiggJ1xcbicgKTtcblxuXHRcdGlmICggcHJlZml4RnJhZ21lbnQubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0cHJlZml4RnJhZ21lbnQgKz0gJ1xcbic7XG5cblx0XHR9XG5cblx0fSBlbHNlIHtcblxuXHRcdHByZWZpeFZlcnRleCA9IFtcblxuXHRcdFx0Z2VuZXJhdGVQcmVjaXNpb24oIHBhcmFtZXRlcnMgKSxcblxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX1RZUEUgJyArIHBhcmFtZXRlcnMuc2hhZGVyVHlwZSxcblx0XHRcdCcjZGVmaW5lIFNIQURFUl9OQU1FICcgKyBwYXJhbWV0ZXJzLnNoYWRlck5hbWUsXG5cblx0XHRcdGN1c3RvbURlZmluZXMsXG5cblx0XHRcdHBhcmFtZXRlcnMuZXh0ZW5zaW9uQ2xpcEN1bGxEaXN0YW5jZSA/ICcjZGVmaW5lIFVTRV9DTElQX0RJU1RBTkNFJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5iYXRjaGluZyA/ICcjZGVmaW5lIFVTRV9CQVRDSElORycgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuYmF0Y2hpbmdDb2xvciA/ICcjZGVmaW5lIFVTRV9CQVRDSElOR19DT0xPUicgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuaW5zdGFuY2luZyA/ICcjZGVmaW5lIFVTRV9JTlNUQU5DSU5HJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5pbnN0YW5jaW5nQ29sb3IgPyAnI2RlZmluZSBVU0VfSU5TVEFOQ0lOR19DT0xPUicgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuaW5zdGFuY2luZ01vcnBoID8gJyNkZWZpbmUgVVNFX0lOU1RBTkNJTkdfTU9SUEgnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMudXNlRm9nICYmIHBhcmFtZXRlcnMuZm9nID8gJyNkZWZpbmUgVVNFX0ZPRycgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudXNlRm9nICYmIHBhcmFtZXRlcnMuZm9nRXhwMiA/ICcjZGVmaW5lIEZPR19FWFAyJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLm1hcCA/ICcjZGVmaW5lIFVTRV9NQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmVudk1hcCA/ICcjZGVmaW5lIFVTRV9FTlZNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmVudk1hcCA/ICcjZGVmaW5lICcgKyBlbnZNYXBNb2RlRGVmaW5lIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmxpZ2h0TWFwID8gJyNkZWZpbmUgVVNFX0xJR0hUTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5hb01hcCA/ICcjZGVmaW5lIFVTRV9BT01BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuYnVtcE1hcCA/ICcjZGVmaW5lIFVTRV9CVU1QTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5ub3JtYWxNYXAgPyAnI2RlZmluZSBVU0VfTk9STUFMTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5ub3JtYWxNYXBPYmplY3RTcGFjZSA/ICcjZGVmaW5lIFVTRV9OT1JNQUxNQVBfT0JKRUNUU1BBQ0UnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLm5vcm1hbE1hcFRhbmdlbnRTcGFjZSA/ICcjZGVmaW5lIFVTRV9OT1JNQUxNQVBfVEFOR0VOVFNQQUNFJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5kaXNwbGFjZW1lbnRNYXAgPyAnI2RlZmluZSBVU0VfRElTUExBQ0VNRU5UTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5lbWlzc2l2ZU1hcCA/ICcjZGVmaW5lIFVTRV9FTUlTU0lWRU1BUCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5hbmlzb3Ryb3B5ID8gJyNkZWZpbmUgVVNFX0FOSVNPVFJPUFknIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmFuaXNvdHJvcHlNYXAgPyAnI2RlZmluZSBVU0VfQU5JU09UUk9QWU1BUCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXRNYXAgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUX1JPVUdITkVTU01BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuY2xlYXJjb2F0Tm9ybWFsTWFwID8gJyNkZWZpbmUgVVNFX0NMRUFSQ09BVF9OT1JNQUxNQVAnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VNYXAgPyAnI2RlZmluZSBVU0VfSVJJREVTQ0VOQ0VNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwID8gJyNkZWZpbmUgVVNFX0lSSURFU0NFTkNFX1RISUNLTkVTU01BUCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5zcGVjdWxhck1hcCA/ICcjZGVmaW5lIFVTRV9TUEVDVUxBUk1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJDb2xvck1hcCA/ICcjZGVmaW5lIFVTRV9TUEVDVUxBUl9DT0xPUk1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJJbnRlbnNpdHlNYXAgPyAnI2RlZmluZSBVU0VfU1BFQ1VMQVJfSU5URU5TSVRZTUFQJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnJvdWdobmVzc01hcCA/ICcjZGVmaW5lIFVTRV9ST1VHSE5FU1NNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLm1ldGFsbmVzc01hcCA/ICcjZGVmaW5lIFVTRV9NRVRBTE5FU1NNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmFscGhhTWFwID8gJyNkZWZpbmUgVVNFX0FMUEhBTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5hbHBoYUhhc2ggPyAnI2RlZmluZSBVU0VfQUxQSEFIQVNIJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbiA/ICcjZGVmaW5lIFVTRV9UUkFOU01JU1NJT04nIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbk1hcCA/ICcjZGVmaW5lIFVTRV9UUkFOU01JU1NJT05NQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnRoaWNrbmVzc01hcCA/ICcjZGVmaW5lIFVTRV9USElDS05FU1NNQVAnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuc2hlZW5Db2xvck1hcCA/ICcjZGVmaW5lIFVTRV9TSEVFTl9DT0xPUk1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuc2hlZW5Sb3VnaG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfU0hFRU5fUk9VR0hORVNTTUFQJyA6ICcnLFxuXG5cdFx0XHQvL1xuXG5cdFx0XHRwYXJhbWV0ZXJzLm1hcFV2ID8gJyNkZWZpbmUgTUFQX1VWICcgKyBwYXJhbWV0ZXJzLm1hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmFscGhhTWFwVXYgPyAnI2RlZmluZSBBTFBIQU1BUF9VViAnICsgcGFyYW1ldGVycy5hbHBoYU1hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmxpZ2h0TWFwVXYgPyAnI2RlZmluZSBMSUdIVE1BUF9VViAnICsgcGFyYW1ldGVycy5saWdodE1hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmFvTWFwVXYgPyAnI2RlZmluZSBBT01BUF9VViAnICsgcGFyYW1ldGVycy5hb01hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmVtaXNzaXZlTWFwVXYgPyAnI2RlZmluZSBFTUlTU0lWRU1BUF9VViAnICsgcGFyYW1ldGVycy5lbWlzc2l2ZU1hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmJ1bXBNYXBVdiA/ICcjZGVmaW5lIEJVTVBNQVBfVVYgJyArIHBhcmFtZXRlcnMuYnVtcE1hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLm5vcm1hbE1hcFV2ID8gJyNkZWZpbmUgTk9STUFMTUFQX1VWICcgKyBwYXJhbWV0ZXJzLm5vcm1hbE1hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmRpc3BsYWNlbWVudE1hcFV2ID8gJyNkZWZpbmUgRElTUExBQ0VNRU5UTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmRpc3BsYWNlbWVudE1hcFV2IDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMubWV0YWxuZXNzTWFwVXYgPyAnI2RlZmluZSBNRVRBTE5FU1NNQVBfVVYgJyArIHBhcmFtZXRlcnMubWV0YWxuZXNzTWFwVXYgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMucm91Z2huZXNzTWFwVXYgPyAnI2RlZmluZSBST1VHSE5FU1NNQVBfVVYgJyArIHBhcmFtZXRlcnMucm91Z2huZXNzTWFwVXYgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5hbmlzb3Ryb3B5TWFwVXYgPyAnI2RlZmluZSBBTklTT1RST1BZTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmFuaXNvdHJvcHlNYXBVdiA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdE1hcFV2ID8gJyNkZWZpbmUgQ0xFQVJDT0FUTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmNsZWFyY29hdE1hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdE5vcm1hbE1hcFV2ID8gJyNkZWZpbmUgQ0xFQVJDT0FUX05PUk1BTE1BUF9VViAnICsgcGFyYW1ldGVycy5jbGVhcmNvYXROb3JtYWxNYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXRSb3VnaG5lc3NNYXBVdiA/ICcjZGVmaW5lIENMRUFSQ09BVF9ST1VHSE5FU1NNQVBfVVYgJyArIHBhcmFtZXRlcnMuY2xlYXJjb2F0Um91Z2huZXNzTWFwVXYgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5pcmlkZXNjZW5jZU1hcFV2ID8gJyNkZWZpbmUgSVJJREVTQ0VOQ0VNQVBfVVYgJyArIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VNYXBVdiA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcFV2ID8gJyNkZWZpbmUgSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQX1VWICcgKyBwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVXYgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwVXYgPyAnI2RlZmluZSBTSEVFTl9DT0xPUk1BUF9VViAnICsgcGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwVXYgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuc2hlZW5Sb3VnaG5lc3NNYXBVdiA/ICcjZGVmaW5lIFNIRUVOX1JPVUdITkVTU01BUF9VViAnICsgcGFyYW1ldGVycy5zaGVlblJvdWdobmVzc01hcFV2IDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJNYXBVdiA/ICcjZGVmaW5lIFNQRUNVTEFSTUFQX1VWICcgKyBwYXJhbWV0ZXJzLnNwZWN1bGFyTWFwVXYgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJDb2xvck1hcFV2ID8gJyNkZWZpbmUgU1BFQ1VMQVJfQ09MT1JNQVBfVVYgJyArIHBhcmFtZXRlcnMuc3BlY3VsYXJDb2xvck1hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnNwZWN1bGFySW50ZW5zaXR5TWFwVXYgPyAnI2RlZmluZSBTUEVDVUxBUl9JTlRFTlNJVFlNQVBfVVYgJyArIHBhcmFtZXRlcnMuc3BlY3VsYXJJbnRlbnNpdHlNYXBVdiA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbk1hcFV2ID8gJyNkZWZpbmUgVFJBTlNNSVNTSU9OTUFQX1VWICcgKyBwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbk1hcFV2IDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnRoaWNrbmVzc01hcFV2ID8gJyNkZWZpbmUgVEhJQ0tORVNTTUFQX1VWICcgKyBwYXJhbWV0ZXJzLnRoaWNrbmVzc01hcFV2IDogJycsXG5cblx0XHRcdC8vXG5cblx0XHRcdHBhcmFtZXRlcnMudmVydGV4VGFuZ2VudHMgJiYgcGFyYW1ldGVycy5mbGF0U2hhZGluZyA9PT0gZmFsc2UgPyAnI2RlZmluZSBVU0VfVEFOR0VOVCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4Q29sb3JzID8gJyNkZWZpbmUgVVNFX0NPTE9SJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhBbHBoYXMgPyAnI2RlZmluZSBVU0VfQ09MT1JfQUxQSEEnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2MXMgPyAnI2RlZmluZSBVU0VfVVYxJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjJzID8gJyNkZWZpbmUgVVNFX1VWMicgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4VXYzcyA/ICcjZGVmaW5lIFVTRV9VVjMnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMucG9pbnRzVXZzID8gJyNkZWZpbmUgVVNFX1BPSU5UU19VVicgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5mbGF0U2hhZGluZyA/ICcjZGVmaW5lIEZMQVRfU0hBREVEJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnNraW5uaW5nID8gJyNkZWZpbmUgVVNFX1NLSU5OSU5HJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLm1vcnBoVGFyZ2V0cyA/ICcjZGVmaW5lIFVTRV9NT1JQSFRBUkdFVFMnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLm1vcnBoTm9ybWFscyAmJiBwYXJhbWV0ZXJzLmZsYXRTaGFkaW5nID09PSBmYWxzZSA/ICcjZGVmaW5lIFVTRV9NT1JQSE5PUk1BTFMnIDogJycsXG5cdFx0XHQoIHBhcmFtZXRlcnMubW9ycGhDb2xvcnMgKSA/ICcjZGVmaW5lIFVTRV9NT1JQSENPTE9SUycgOiAnJyxcblx0XHRcdCggcGFyYW1ldGVycy5tb3JwaFRhcmdldHNDb3VudCA+IDAgKSA/ICcjZGVmaW5lIE1PUlBIVEFSR0VUU19URVhUVVJFX1NUUklERSAnICsgcGFyYW1ldGVycy5tb3JwaFRleHR1cmVTdHJpZGUgOiAnJyxcblx0XHRcdCggcGFyYW1ldGVycy5tb3JwaFRhcmdldHNDb3VudCA+IDAgKSA/ICcjZGVmaW5lIE1PUlBIVEFSR0VUU19DT1VOVCAnICsgcGFyYW1ldGVycy5tb3JwaFRhcmdldHNDb3VudCA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5kb3VibGVTaWRlZCA/ICcjZGVmaW5lIERPVUJMRV9TSURFRCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuZmxpcFNpZGVkID8gJyNkZWZpbmUgRkxJUF9TSURFRCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5zaGFkb3dNYXBFbmFibGVkID8gJyNkZWZpbmUgVVNFX1NIQURPV01BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuc2hhZG93TWFwRW5hYmxlZCA/ICcjZGVmaW5lICcgKyBzaGFkb3dNYXBUeXBlRGVmaW5lIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuc2l6ZUF0dGVudWF0aW9uID8gJyNkZWZpbmUgVVNFX1NJWkVBVFRFTlVBVElPTicgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5udW1MaWdodFByb2JlcyA+IDAgPyAnI2RlZmluZSBVU0VfTElHSFRfUFJPQkVTJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmxvZ2FyaXRobWljRGVwdGhCdWZmZXIgPyAnI2RlZmluZSBVU0VfTE9HREVQVEhCVUYnIDogJycsXG5cblx0XHRcdCd1bmlmb3JtIG1hdDQgbW9kZWxNYXRyaXg7Jyxcblx0XHRcdCd1bmlmb3JtIG1hdDQgbW9kZWxWaWV3TWF0cml4OycsXG5cdFx0XHQndW5pZm9ybSBtYXQ0IHByb2plY3Rpb25NYXRyaXg7Jyxcblx0XHRcdCd1bmlmb3JtIG1hdDQgdmlld01hdHJpeDsnLFxuXHRcdFx0J3VuaWZvcm0gbWF0MyBub3JtYWxNYXRyaXg7Jyxcblx0XHRcdCd1bmlmb3JtIHZlYzMgY2FtZXJhUG9zaXRpb247Jyxcblx0XHRcdCd1bmlmb3JtIGJvb2wgaXNPcnRob2dyYXBoaWM7JyxcblxuXHRcdFx0JyNpZmRlZiBVU0VfSU5TVEFOQ0lORycsXG5cblx0XHRcdCdcdGF0dHJpYnV0ZSBtYXQ0IGluc3RhbmNlTWF0cml4OycsXG5cblx0XHRcdCcjZW5kaWYnLFxuXG5cdFx0XHQnI2lmZGVmIFVTRV9JTlNUQU5DSU5HX0NPTE9SJyxcblxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzMgaW5zdGFuY2VDb2xvcjsnLFxuXG5cdFx0XHQnI2VuZGlmJyxcblxuXHRcdFx0JyNpZmRlZiBVU0VfSU5TVEFOQ0lOR19NT1JQSCcsXG5cblx0XHRcdCdcdHVuaWZvcm0gc2FtcGxlcjJEIG1vcnBoVGV4dHVyZTsnLFxuXG5cdFx0XHQnI2VuZGlmJyxcblxuXHRcdFx0J2F0dHJpYnV0ZSB2ZWMzIHBvc2l0aW9uOycsXG5cdFx0XHQnYXR0cmlidXRlIHZlYzMgbm9ybWFsOycsXG5cdFx0XHQnYXR0cmlidXRlIHZlYzIgdXY7JyxcblxuXHRcdFx0JyNpZmRlZiBVU0VfVVYxJyxcblxuXHRcdFx0J1x0YXR0cmlidXRlIHZlYzIgdXYxOycsXG5cblx0XHRcdCcjZW5kaWYnLFxuXG5cdFx0XHQnI2lmZGVmIFVTRV9VVjInLFxuXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjMiB1djI7JyxcblxuXHRcdFx0JyNlbmRpZicsXG5cblx0XHRcdCcjaWZkZWYgVVNFX1VWMycsXG5cblx0XHRcdCdcdGF0dHJpYnV0ZSB2ZWMyIHV2MzsnLFxuXG5cdFx0XHQnI2VuZGlmJyxcblxuXHRcdFx0JyNpZmRlZiBVU0VfVEFOR0VOVCcsXG5cblx0XHRcdCdcdGF0dHJpYnV0ZSB2ZWM0IHRhbmdlbnQ7JyxcblxuXHRcdFx0JyNlbmRpZicsXG5cblx0XHRcdCcjaWYgZGVmaW5lZCggVVNFX0NPTE9SX0FMUEhBICknLFxuXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjNCBjb2xvcjsnLFxuXG5cdFx0XHQnI2VsaWYgZGVmaW5lZCggVVNFX0NPTE9SICknLFxuXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjMyBjb2xvcjsnLFxuXG5cdFx0XHQnI2VuZGlmJyxcblxuXHRcdFx0JyNpZmRlZiBVU0VfU0tJTk5JTkcnLFxuXG5cdFx0XHQnXHRhdHRyaWJ1dGUgdmVjNCBza2luSW5kZXg7Jyxcblx0XHRcdCdcdGF0dHJpYnV0ZSB2ZWM0IHNraW5XZWlnaHQ7JyxcblxuXHRcdFx0JyNlbmRpZicsXG5cblx0XHRcdCdcXG4nXG5cblx0XHRdLmZpbHRlciggZmlsdGVyRW1wdHlMaW5lICkuam9pbiggJ1xcbicgKTtcblxuXHRcdHByZWZpeEZyYWdtZW50ID0gW1xuXG5cdFx0XHRnZW5lcmF0ZVByZWNpc2lvbiggcGFyYW1ldGVycyApLFxuXG5cdFx0XHQnI2RlZmluZSBTSEFERVJfVFlQRSAnICsgcGFyYW1ldGVycy5zaGFkZXJUeXBlLFxuXHRcdFx0JyNkZWZpbmUgU0hBREVSX05BTUUgJyArIHBhcmFtZXRlcnMuc2hhZGVyTmFtZSxcblxuXHRcdFx0Y3VzdG9tRGVmaW5lcyxcblxuXHRcdFx0cGFyYW1ldGVycy51c2VGb2cgJiYgcGFyYW1ldGVycy5mb2cgPyAnI2RlZmluZSBVU0VfRk9HJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy51c2VGb2cgJiYgcGFyYW1ldGVycy5mb2dFeHAyID8gJyNkZWZpbmUgRk9HX0VYUDInIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuYWxwaGFUb0NvdmVyYWdlID8gJyNkZWZpbmUgQUxQSEFfVE9fQ09WRVJBR0UnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLm1hcCA/ICcjZGVmaW5lIFVTRV9NQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLm1hdGNhcCA/ICcjZGVmaW5lIFVTRV9NQVRDQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmVudk1hcCA/ICcjZGVmaW5lIFVTRV9FTlZNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmVudk1hcCA/ICcjZGVmaW5lICcgKyBlbnZNYXBUeXBlRGVmaW5lIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmVudk1hcCA/ICcjZGVmaW5lICcgKyBlbnZNYXBNb2RlRGVmaW5lIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmVudk1hcCA/ICcjZGVmaW5lICcgKyBlbnZNYXBCbGVuZGluZ0RlZmluZSA6ICcnLFxuXHRcdFx0ZW52TWFwQ3ViZVVWU2l6ZSA/ICcjZGVmaW5lIENVQkVVVl9URVhFTF9XSURUSCAnICsgZW52TWFwQ3ViZVVWU2l6ZS50ZXhlbFdpZHRoIDogJycsXG5cdFx0XHRlbnZNYXBDdWJlVVZTaXplID8gJyNkZWZpbmUgQ1VCRVVWX1RFWEVMX0hFSUdIVCAnICsgZW52TWFwQ3ViZVVWU2l6ZS50ZXhlbEhlaWdodCA6ICcnLFxuXHRcdFx0ZW52TWFwQ3ViZVVWU2l6ZSA/ICcjZGVmaW5lIENVQkVVVl9NQVhfTUlQICcgKyBlbnZNYXBDdWJlVVZTaXplLm1heE1pcCArICcuMCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMubGlnaHRNYXAgPyAnI2RlZmluZSBVU0VfTElHSFRNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmFvTWFwID8gJyNkZWZpbmUgVVNFX0FPTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5idW1wTWFwID8gJyNkZWZpbmUgVVNFX0JVTVBNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLm5vcm1hbE1hcCA/ICcjZGVmaW5lIFVTRV9OT1JNQUxNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLm5vcm1hbE1hcE9iamVjdFNwYWNlID8gJyNkZWZpbmUgVVNFX05PUk1BTE1BUF9PQkpFQ1RTUEFDRScgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMubm9ybWFsTWFwVGFuZ2VudFNwYWNlID8gJyNkZWZpbmUgVVNFX05PUk1BTE1BUF9UQU5HRU5UU1BBQ0UnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmVtaXNzaXZlTWFwID8gJyNkZWZpbmUgVVNFX0VNSVNTSVZFTUFQJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmFuaXNvdHJvcHkgPyAnI2RlZmluZSBVU0VfQU5JU09UUk9QWScgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMuYW5pc290cm9weU1hcCA/ICcjZGVmaW5lIFVTRV9BTklTT1RST1BZTUFQJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdCA/ICcjZGVmaW5lIFVTRV9DTEVBUkNPQVQnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdE1hcCA/ICcjZGVmaW5lIFVTRV9DTEVBUkNPQVRNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmNsZWFyY29hdFJvdWdobmVzc01hcCA/ICcjZGVmaW5lIFVTRV9DTEVBUkNPQVRfUk9VR0hORVNTTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5jbGVhcmNvYXROb3JtYWxNYXAgPyAnI2RlZmluZSBVU0VfQ0xFQVJDT0FUX05PUk1BTE1BUCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5kaXNwZXJzaW9uID8gJyNkZWZpbmUgVVNFX0RJU1BFUlNJT04nIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuaXJpZGVzY2VuY2UgPyAnI2RlZmluZSBVU0VfSVJJREVTQ0VOQ0UnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLmlyaWRlc2NlbmNlTWFwID8gJyNkZWZpbmUgVVNFX0lSSURFU0NFTkNFTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcCA/ICcjZGVmaW5lIFVTRV9JUklERVNDRU5DRV9USElDS05FU1NNQVAnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuc3BlY3VsYXJNYXAgPyAnI2RlZmluZSBVU0VfU1BFQ1VMQVJNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnNwZWN1bGFyQ29sb3JNYXAgPyAnI2RlZmluZSBVU0VfU1BFQ1VMQVJfQ09MT1JNQVAnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnNwZWN1bGFySW50ZW5zaXR5TWFwID8gJyNkZWZpbmUgVVNFX1NQRUNVTEFSX0lOVEVOU0lUWU1BUCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5yb3VnaG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfUk9VR0hORVNTTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5tZXRhbG5lc3NNYXAgPyAnI2RlZmluZSBVU0VfTUVUQUxORVNTTUFQJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmFscGhhTWFwID8gJyNkZWZpbmUgVVNFX0FMUEhBTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5hbHBoYVRlc3QgPyAnI2RlZmluZSBVU0VfQUxQSEFURVNUJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5hbHBoYUhhc2ggPyAnI2RlZmluZSBVU0VfQUxQSEFIQVNIJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnNoZWVuID8gJyNkZWZpbmUgVVNFX1NIRUVOJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5zaGVlbkNvbG9yTWFwID8gJyNkZWZpbmUgVVNFX1NIRUVOX0NPTE9STUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5zaGVlblJvdWdobmVzc01hcCA/ICcjZGVmaW5lIFVTRV9TSEVFTl9ST1VHSE5FU1NNQVAnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uID8gJyNkZWZpbmUgVVNFX1RSQU5TTUlTU0lPTicgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudHJhbnNtaXNzaW9uTWFwID8gJyNkZWZpbmUgVVNFX1RSQU5TTUlTU0lPTk1BUCcgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudGhpY2tuZXNzTWFwID8gJyNkZWZpbmUgVVNFX1RISUNLTkVTU01BUCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhUYW5nZW50cyAmJiBwYXJhbWV0ZXJzLmZsYXRTaGFkaW5nID09PSBmYWxzZSA/ICcjZGVmaW5lIFVTRV9UQU5HRU5UJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhDb2xvcnMgfHwgcGFyYW1ldGVycy5pbnN0YW5jaW5nQ29sb3IgfHwgcGFyYW1ldGVycy5iYXRjaGluZ0NvbG9yID8gJyNkZWZpbmUgVVNFX0NPTE9SJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhBbHBoYXMgPyAnI2RlZmluZSBVU0VfQ09MT1JfQUxQSEEnIDogJycsXG5cdFx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2MXMgPyAnI2RlZmluZSBVU0VfVVYxJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjJzID8gJyNkZWZpbmUgVVNFX1VWMicgOiAnJyxcblx0XHRcdHBhcmFtZXRlcnMudmVydGV4VXYzcyA/ICcjZGVmaW5lIFVTRV9VVjMnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMucG9pbnRzVXZzID8gJyNkZWZpbmUgVVNFX1BPSU5UU19VVicgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5ncmFkaWVudE1hcCA/ICcjZGVmaW5lIFVTRV9HUkFESUVOVE1BUCcgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5mbGF0U2hhZGluZyA/ICcjZGVmaW5lIEZMQVRfU0hBREVEJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLmRvdWJsZVNpZGVkID8gJyNkZWZpbmUgRE9VQkxFX1NJREVEJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5mbGlwU2lkZWQgPyAnI2RlZmluZSBGTElQX1NJREVEJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLnNoYWRvd01hcEVuYWJsZWQgPyAnI2RlZmluZSBVU0VfU0hBRE9XTUFQJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5zaGFkb3dNYXBFbmFibGVkID8gJyNkZWZpbmUgJyArIHNoYWRvd01hcFR5cGVEZWZpbmUgOiAnJyxcblxuXHRcdFx0cGFyYW1ldGVycy5wcmVtdWx0aXBsaWVkQWxwaGEgPyAnI2RlZmluZSBQUkVNVUxUSVBMSUVEX0FMUEhBJyA6ICcnLFxuXG5cdFx0XHRwYXJhbWV0ZXJzLm51bUxpZ2h0UHJvYmVzID4gMCA/ICcjZGVmaW5lIFVTRV9MSUdIVF9QUk9CRVMnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuZGVjb2RlVmlkZW9UZXh0dXJlID8gJyNkZWZpbmUgREVDT0RFX1ZJREVPX1RFWFRVUkUnIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlciA/ICcjZGVmaW5lIFVTRV9MT0dERVBUSEJVRicgOiAnJyxcblxuXHRcdFx0J3VuaWZvcm0gbWF0NCB2aWV3TWF0cml4OycsXG5cdFx0XHQndW5pZm9ybSB2ZWMzIGNhbWVyYVBvc2l0aW9uOycsXG5cdFx0XHQndW5pZm9ybSBib29sIGlzT3J0aG9ncmFwaGljOycsXG5cblx0XHRcdCggcGFyYW1ldGVycy50b25lTWFwcGluZyAhPT0gTm9Ub25lTWFwcGluZyApID8gJyNkZWZpbmUgVE9ORV9NQVBQSU5HJyA6ICcnLFxuXHRcdFx0KCBwYXJhbWV0ZXJzLnRvbmVNYXBwaW5nICE9PSBOb1RvbmVNYXBwaW5nICkgPyBTaGFkZXJDaHVua1sgJ3RvbmVtYXBwaW5nX3BhcnNfZnJhZ21lbnQnIF0gOiAnJywgLy8gdGhpcyBjb2RlIGlzIHJlcXVpcmVkIGhlcmUgYmVjYXVzZSBpdCBpcyB1c2VkIGJ5IHRoZSB0b25lTWFwcGluZygpIGZ1bmN0aW9uIGRlZmluZWQgYmVsb3dcblx0XHRcdCggcGFyYW1ldGVycy50b25lTWFwcGluZyAhPT0gTm9Ub25lTWFwcGluZyApID8gZ2V0VG9uZU1hcHBpbmdGdW5jdGlvbiggJ3RvbmVNYXBwaW5nJywgcGFyYW1ldGVycy50b25lTWFwcGluZyApIDogJycsXG5cblx0XHRcdHBhcmFtZXRlcnMuZGl0aGVyaW5nID8gJyNkZWZpbmUgRElUSEVSSU5HJyA6ICcnLFxuXHRcdFx0cGFyYW1ldGVycy5vcGFxdWUgPyAnI2RlZmluZSBPUEFRVUUnIDogJycsXG5cblx0XHRcdFNoYWRlckNodW5rWyAnY29sb3JzcGFjZV9wYXJzX2ZyYWdtZW50JyBdLCAvLyB0aGlzIGNvZGUgaXMgcmVxdWlyZWQgaGVyZSBiZWNhdXNlIGl0IGlzIHVzZWQgYnkgdGhlIHZhcmlvdXMgZW5jb2RpbmcvZGVjb2RpbmcgZnVuY3Rpb24gZGVmaW5lZCBiZWxvd1xuXHRcdFx0Z2V0VGV4ZWxFbmNvZGluZ0Z1bmN0aW9uKCAnbGluZWFyVG9PdXRwdXRUZXhlbCcsIHBhcmFtZXRlcnMub3V0cHV0Q29sb3JTcGFjZSApLFxuXHRcdFx0Z2V0THVtaW5hbmNlRnVuY3Rpb24oKSxcblxuXHRcdFx0cGFyYW1ldGVycy51c2VEZXB0aFBhY2tpbmcgPyAnI2RlZmluZSBERVBUSF9QQUNLSU5HICcgKyBwYXJhbWV0ZXJzLmRlcHRoUGFja2luZyA6ICcnLFxuXG5cdFx0XHQnXFxuJ1xuXG5cdFx0XS5maWx0ZXIoIGZpbHRlckVtcHR5TGluZSApLmpvaW4oICdcXG4nICk7XG5cblx0fVxuXG5cdHZlcnRleFNoYWRlciA9IHJlc29sdmVJbmNsdWRlcyggdmVydGV4U2hhZGVyICk7XG5cdHZlcnRleFNoYWRlciA9IHJlcGxhY2VMaWdodE51bXMoIHZlcnRleFNoYWRlciwgcGFyYW1ldGVycyApO1xuXHR2ZXJ0ZXhTaGFkZXIgPSByZXBsYWNlQ2xpcHBpbmdQbGFuZU51bXMoIHZlcnRleFNoYWRlciwgcGFyYW1ldGVycyApO1xuXG5cdGZyYWdtZW50U2hhZGVyID0gcmVzb2x2ZUluY2x1ZGVzKCBmcmFnbWVudFNoYWRlciApO1xuXHRmcmFnbWVudFNoYWRlciA9IHJlcGxhY2VMaWdodE51bXMoIGZyYWdtZW50U2hhZGVyLCBwYXJhbWV0ZXJzICk7XG5cdGZyYWdtZW50U2hhZGVyID0gcmVwbGFjZUNsaXBwaW5nUGxhbmVOdW1zKCBmcmFnbWVudFNoYWRlciwgcGFyYW1ldGVycyApO1xuXG5cdHZlcnRleFNoYWRlciA9IHVucm9sbExvb3BzKCB2ZXJ0ZXhTaGFkZXIgKTtcblx0ZnJhZ21lbnRTaGFkZXIgPSB1bnJvbGxMb29wcyggZnJhZ21lbnRTaGFkZXIgKTtcblxuXHRpZiAoIHBhcmFtZXRlcnMuaXNSYXdTaGFkZXJNYXRlcmlhbCAhPT0gdHJ1ZSApIHtcblxuXHRcdC8vIEdMU0wgMy4wIGNvbnZlcnNpb24gZm9yIGJ1aWx0LWluIG1hdGVyaWFscyBhbmQgU2hhZGVyTWF0ZXJpYWxcblxuXHRcdHZlcnNpb25TdHJpbmcgPSAnI3ZlcnNpb24gMzAwIGVzXFxuJztcblxuXHRcdHByZWZpeFZlcnRleCA9IFtcblx0XHRcdGN1c3RvbVZlcnRleEV4dGVuc2lvbnMsXG5cdFx0XHQnI2RlZmluZSBhdHRyaWJ1dGUgaW4nLFxuXHRcdFx0JyNkZWZpbmUgdmFyeWluZyBvdXQnLFxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEIHRleHR1cmUnXG5cdFx0XS5qb2luKCAnXFxuJyApICsgJ1xcbicgKyBwcmVmaXhWZXJ0ZXg7XG5cblx0XHRwcmVmaXhGcmFnbWVudCA9IFtcblx0XHRcdCcjZGVmaW5lIHZhcnlpbmcgaW4nLFxuXHRcdFx0KCBwYXJhbWV0ZXJzLmdsc2xWZXJzaW9uID09PSBHTFNMMyApID8gJycgOiAnbGF5b3V0KGxvY2F0aW9uID0gMCkgb3V0IGhpZ2hwIHZlYzQgcGNfZnJhZ0NvbG9yOycsXG5cdFx0XHQoIHBhcmFtZXRlcnMuZ2xzbFZlcnNpb24gPT09IEdMU0wzICkgPyAnJyA6ICcjZGVmaW5lIGdsX0ZyYWdDb2xvciBwY19mcmFnQ29sb3InLFxuXHRcdFx0JyNkZWZpbmUgZ2xfRnJhZ0RlcHRoRVhUIGdsX0ZyYWdEZXB0aCcsXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlMkQgdGV4dHVyZScsXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlQ3ViZSB0ZXh0dXJlJyxcblx0XHRcdCcjZGVmaW5lIHRleHR1cmUyRFByb2ogdGV4dHVyZVByb2onLFxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJETG9kRVhUIHRleHR1cmVMb2QnLFxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEUHJvakxvZEVYVCB0ZXh0dXJlUHJvakxvZCcsXG5cdFx0XHQnI2RlZmluZSB0ZXh0dXJlQ3ViZUxvZEVYVCB0ZXh0dXJlTG9kJyxcblx0XHRcdCcjZGVmaW5lIHRleHR1cmUyREdyYWRFWFQgdGV4dHVyZUdyYWQnLFxuXHRcdFx0JyNkZWZpbmUgdGV4dHVyZTJEUHJvakdyYWRFWFQgdGV4dHVyZVByb2pHcmFkJyxcblx0XHRcdCcjZGVmaW5lIHRleHR1cmVDdWJlR3JhZEVYVCB0ZXh0dXJlR3JhZCdcblx0XHRdLmpvaW4oICdcXG4nICkgKyAnXFxuJyArIHByZWZpeEZyYWdtZW50O1xuXG5cdH1cblxuXHRjb25zdCB2ZXJ0ZXhHbHNsID0gdmVyc2lvblN0cmluZyArIHByZWZpeFZlcnRleCArIHZlcnRleFNoYWRlcjtcblx0Y29uc3QgZnJhZ21lbnRHbHNsID0gdmVyc2lvblN0cmluZyArIHByZWZpeEZyYWdtZW50ICsgZnJhZ21lbnRTaGFkZXI7XG5cblx0Ly8gY29uc29sZS5sb2coICcqVkVSVEVYKicsIHZlcnRleEdsc2wgKTtcblx0Ly8gY29uc29sZS5sb2coICcqRlJBR01FTlQqJywgZnJhZ21lbnRHbHNsICk7XG5cblx0Y29uc3QgZ2xWZXJ0ZXhTaGFkZXIgPSBXZWJHTFNoYWRlciggZ2wsIGdsLlZFUlRFWF9TSEFERVIsIHZlcnRleEdsc2wgKTtcblx0Y29uc3QgZ2xGcmFnbWVudFNoYWRlciA9IFdlYkdMU2hhZGVyKCBnbCwgZ2wuRlJBR01FTlRfU0hBREVSLCBmcmFnbWVudEdsc2wgKTtcblxuXHRnbC5hdHRhY2hTaGFkZXIoIHByb2dyYW0sIGdsVmVydGV4U2hhZGVyICk7XG5cdGdsLmF0dGFjaFNoYWRlciggcHJvZ3JhbSwgZ2xGcmFnbWVudFNoYWRlciApO1xuXG5cdC8vIEZvcmNlIGEgcGFydGljdWxhciBhdHRyaWJ1dGUgdG8gaW5kZXggMC5cblxuXHRpZiAoIHBhcmFtZXRlcnMuaW5kZXgwQXR0cmlidXRlTmFtZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0Z2wuYmluZEF0dHJpYkxvY2F0aW9uKCBwcm9ncmFtLCAwLCBwYXJhbWV0ZXJzLmluZGV4MEF0dHJpYnV0ZU5hbWUgKTtcblxuXHR9IGVsc2UgaWYgKCBwYXJhbWV0ZXJzLm1vcnBoVGFyZ2V0cyA9PT0gdHJ1ZSApIHtcblxuXHRcdC8vIHByb2dyYW1zIHdpdGggbW9ycGhUYXJnZXRzIGRpc3BsYWNlIHBvc2l0aW9uIG91dCBvZiBhdHRyaWJ1dGUgMFxuXHRcdGdsLmJpbmRBdHRyaWJMb2NhdGlvbiggcHJvZ3JhbSwgMCwgJ3Bvc2l0aW9uJyApO1xuXG5cdH1cblxuXHRnbC5saW5rUHJvZ3JhbSggcHJvZ3JhbSApO1xuXG5cdGZ1bmN0aW9uIG9uRmlyc3RVc2UoIHNlbGYgKSB7XG5cblx0XHQvLyBjaGVjayBmb3IgbGluayBlcnJvcnNcblx0XHRpZiAoIHJlbmRlcmVyLmRlYnVnLmNoZWNrU2hhZGVyRXJyb3JzICkge1xuXG5cdFx0XHRjb25zdCBwcm9ncmFtTG9nID0gZ2wuZ2V0UHJvZ3JhbUluZm9Mb2coIHByb2dyYW0gKS50cmltKCk7XG5cdFx0XHRjb25zdCB2ZXJ0ZXhMb2cgPSBnbC5nZXRTaGFkZXJJbmZvTG9nKCBnbFZlcnRleFNoYWRlciApLnRyaW0oKTtcblx0XHRcdGNvbnN0IGZyYWdtZW50TG9nID0gZ2wuZ2V0U2hhZGVySW5mb0xvZyggZ2xGcmFnbWVudFNoYWRlciApLnRyaW0oKTtcblxuXHRcdFx0bGV0IHJ1bm5hYmxlID0gdHJ1ZTtcblx0XHRcdGxldCBoYXZlRGlhZ25vc3RpY3MgPSB0cnVlO1xuXG5cdFx0XHRpZiAoIGdsLmdldFByb2dyYW1QYXJhbWV0ZXIoIHByb2dyYW0sIGdsLkxJTktfU1RBVFVTICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdHJ1bm5hYmxlID0gZmFsc2U7XG5cblx0XHRcdFx0aWYgKCB0eXBlb2YgcmVuZGVyZXIuZGVidWcub25TaGFkZXJFcnJvciA9PT0gJ2Z1bmN0aW9uJyApIHtcblxuXHRcdFx0XHRcdHJlbmRlcmVyLmRlYnVnLm9uU2hhZGVyRXJyb3IoIGdsLCBwcm9ncmFtLCBnbFZlcnRleFNoYWRlciwgZ2xGcmFnbWVudFNoYWRlciApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBkZWZhdWx0IGVycm9yIHJlcG9ydGluZ1xuXG5cdFx0XHRcdFx0Y29uc3QgdmVydGV4RXJyb3JzID0gZ2V0U2hhZGVyRXJyb3JzKCBnbCwgZ2xWZXJ0ZXhTaGFkZXIsICd2ZXJ0ZXgnICk7XG5cdFx0XHRcdFx0Y29uc3QgZnJhZ21lbnRFcnJvcnMgPSBnZXRTaGFkZXJFcnJvcnMoIGdsLCBnbEZyYWdtZW50U2hhZGVyLCAnZnJhZ21lbnQnICk7XG5cblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKFxuXHRcdFx0XHRcdFx0J1RIUkVFLldlYkdMUHJvZ3JhbTogU2hhZGVyIEVycm9yICcgKyBnbC5nZXRFcnJvcigpICsgJyAtICcgK1xuXHRcdFx0XHRcdFx0J1ZBTElEQVRFX1NUQVRVUyAnICsgZ2wuZ2V0UHJvZ3JhbVBhcmFtZXRlciggcHJvZ3JhbSwgZ2wuVkFMSURBVEVfU1RBVFVTICkgKyAnXFxuXFxuJyArXG5cdFx0XHRcdFx0XHQnTWF0ZXJpYWwgTmFtZTogJyArIHNlbGYubmFtZSArICdcXG4nICtcblx0XHRcdFx0XHRcdCdNYXRlcmlhbCBUeXBlOiAnICsgc2VsZi50eXBlICsgJ1xcblxcbicgK1xuXHRcdFx0XHRcdFx0J1Byb2dyYW0gSW5mbyBMb2c6ICcgKyBwcm9ncmFtTG9nICsgJ1xcbicgK1xuXHRcdFx0XHRcdFx0dmVydGV4RXJyb3JzICsgJ1xcbicgK1xuXHRcdFx0XHRcdFx0ZnJhZ21lbnRFcnJvcnNcblx0XHRcdFx0XHQpO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIGlmICggcHJvZ3JhbUxvZyAhPT0gJycgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xQcm9ncmFtOiBQcm9ncmFtIEluZm8gTG9nOicsIHByb2dyYW1Mb2cgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggdmVydGV4TG9nID09PSAnJyB8fCBmcmFnbWVudExvZyA9PT0gJycgKSB7XG5cblx0XHRcdFx0aGF2ZURpYWdub3N0aWNzID0gZmFsc2U7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBoYXZlRGlhZ25vc3RpY3MgKSB7XG5cblx0XHRcdFx0c2VsZi5kaWFnbm9zdGljcyA9IHtcblxuXHRcdFx0XHRcdHJ1bm5hYmxlOiBydW5uYWJsZSxcblxuXHRcdFx0XHRcdHByb2dyYW1Mb2c6IHByb2dyYW1Mb2csXG5cblx0XHRcdFx0XHR2ZXJ0ZXhTaGFkZXI6IHtcblxuXHRcdFx0XHRcdFx0bG9nOiB2ZXJ0ZXhMb2csXG5cdFx0XHRcdFx0XHRwcmVmaXg6IHByZWZpeFZlcnRleFxuXG5cdFx0XHRcdFx0fSxcblxuXHRcdFx0XHRcdGZyYWdtZW50U2hhZGVyOiB7XG5cblx0XHRcdFx0XHRcdGxvZzogZnJhZ21lbnRMb2csXG5cdFx0XHRcdFx0XHRwcmVmaXg6IHByZWZpeEZyYWdtZW50XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gQ2xlYW4gdXBcblxuXHRcdC8vIENyYXNoZXMgaW4gaU9TOSBhbmQgaU9TMTAuICMxODQwMlxuXHRcdC8vIGdsLmRldGFjaFNoYWRlciggcHJvZ3JhbSwgZ2xWZXJ0ZXhTaGFkZXIgKTtcblx0XHQvLyBnbC5kZXRhY2hTaGFkZXIoIHByb2dyYW0sIGdsRnJhZ21lbnRTaGFkZXIgKTtcblxuXHRcdGdsLmRlbGV0ZVNoYWRlciggZ2xWZXJ0ZXhTaGFkZXIgKTtcblx0XHRnbC5kZWxldGVTaGFkZXIoIGdsRnJhZ21lbnRTaGFkZXIgKTtcblxuXHRcdGNhY2hlZFVuaWZvcm1zID0gbmV3IFdlYkdMVW5pZm9ybXMoIGdsLCBwcm9ncmFtICk7XG5cdFx0Y2FjaGVkQXR0cmlidXRlcyA9IGZldGNoQXR0cmlidXRlTG9jYXRpb25zKCBnbCwgcHJvZ3JhbSApO1xuXG5cdH1cblxuXHQvLyBzZXQgdXAgY2FjaGluZyBmb3IgdW5pZm9ybSBsb2NhdGlvbnNcblxuXHRsZXQgY2FjaGVkVW5pZm9ybXM7XG5cblx0dGhpcy5nZXRVbmlmb3JtcyA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdGlmICggY2FjaGVkVW5pZm9ybXMgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Ly8gUG9wdWxhdGVzIGNhY2hlZFVuaWZvcm1zIGFuZCBjYWNoZWRBdHRyaWJ1dGVzXG5cdFx0XHRvbkZpcnN0VXNlKCB0aGlzICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gY2FjaGVkVW5pZm9ybXM7XG5cblx0fTtcblxuXHQvLyBzZXQgdXAgY2FjaGluZyBmb3IgYXR0cmlidXRlIGxvY2F0aW9uc1xuXG5cdGxldCBjYWNoZWRBdHRyaWJ1dGVzO1xuXG5cdHRoaXMuZ2V0QXR0cmlidXRlcyA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdGlmICggY2FjaGVkQXR0cmlidXRlcyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHQvLyBQb3B1bGF0ZXMgY2FjaGVkQXR0cmlidXRlcyBhbmQgY2FjaGVkVW5pZm9ybXNcblx0XHRcdG9uRmlyc3RVc2UoIHRoaXMgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBjYWNoZWRBdHRyaWJ1dGVzO1xuXG5cdH07XG5cblx0Ly8gaW5kaWNhdGUgd2hlbiB0aGUgcHJvZ3JhbSBpcyByZWFkeSB0byBiZSB1c2VkLiBpZiB0aGUgS0hSX3BhcmFsbGVsX3NoYWRlcl9jb21waWxlIGV4dGVuc2lvbiBpc24ndCBzdXBwb3J0ZWQsXG5cdC8vIGZsYWcgdGhlIHByb2dyYW0gYXMgcmVhZHkgaW1tZWRpYXRlbHkuIEl0IG1heSBjYXVzZSBhIHN0YWxsIHdoZW4gaXQncyBmaXJzdCB1c2VkLlxuXG5cdGxldCBwcm9ncmFtUmVhZHkgPSAoIHBhcmFtZXRlcnMucmVuZGVyZXJFeHRlbnNpb25QYXJhbGxlbFNoYWRlckNvbXBpbGUgPT09IGZhbHNlICk7XG5cblx0dGhpcy5pc1JlYWR5ID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0aWYgKCBwcm9ncmFtUmVhZHkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRwcm9ncmFtUmVhZHkgPSBnbC5nZXRQcm9ncmFtUGFyYW1ldGVyKCBwcm9ncmFtLCBDT01QTEVUSU9OX1NUQVRVU19LSFIgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBwcm9ncmFtUmVhZHk7XG5cblx0fTtcblxuXHQvLyBmcmVlIHJlc291cmNlXG5cblx0dGhpcy5kZXN0cm95ID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0YmluZGluZ1N0YXRlcy5yZWxlYXNlU3RhdGVzT2ZQcm9ncmFtKCB0aGlzICk7XG5cblx0XHRnbC5kZWxldGVQcm9ncmFtKCBwcm9ncmFtICk7XG5cdFx0dGhpcy5wcm9ncmFtID0gdW5kZWZpbmVkO1xuXG5cdH07XG5cblx0Ly9cblxuXHR0aGlzLnR5cGUgPSBwYXJhbWV0ZXJzLnNoYWRlclR5cGU7XG5cdHRoaXMubmFtZSA9IHBhcmFtZXRlcnMuc2hhZGVyTmFtZTtcblx0dGhpcy5pZCA9IHByb2dyYW1JZENvdW50ICsrO1xuXHR0aGlzLmNhY2hlS2V5ID0gY2FjaGVLZXk7XG5cdHRoaXMudXNlZFRpbWVzID0gMTtcblx0dGhpcy5wcm9ncmFtID0gcHJvZ3JhbTtcblx0dGhpcy52ZXJ0ZXhTaGFkZXIgPSBnbFZlcnRleFNoYWRlcjtcblx0dGhpcy5mcmFnbWVudFNoYWRlciA9IGdsRnJhZ21lbnRTaGFkZXI7XG5cblx0cmV0dXJuIHRoaXM7XG5cbn1cblxubGV0IF9pZCQxID0gMDtcblxuY2xhc3MgV2ViR0xTaGFkZXJDYWNoZSB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHR0aGlzLnNoYWRlckNhY2hlID0gbmV3IE1hcCgpO1xuXHRcdHRoaXMubWF0ZXJpYWxDYWNoZSA9IG5ldyBNYXAoKTtcblxuXHR9XG5cblx0dXBkYXRlKCBtYXRlcmlhbCApIHtcblxuXHRcdGNvbnN0IHZlcnRleFNoYWRlciA9IG1hdGVyaWFsLnZlcnRleFNoYWRlcjtcblx0XHRjb25zdCBmcmFnbWVudFNoYWRlciA9IG1hdGVyaWFsLmZyYWdtZW50U2hhZGVyO1xuXG5cdFx0Y29uc3QgdmVydGV4U2hhZGVyU3RhZ2UgPSB0aGlzLl9nZXRTaGFkZXJTdGFnZSggdmVydGV4U2hhZGVyICk7XG5cdFx0Y29uc3QgZnJhZ21lbnRTaGFkZXJTdGFnZSA9IHRoaXMuX2dldFNoYWRlclN0YWdlKCBmcmFnbWVudFNoYWRlciApO1xuXG5cdFx0Y29uc3QgbWF0ZXJpYWxTaGFkZXJzID0gdGhpcy5fZ2V0U2hhZGVyQ2FjaGVGb3JNYXRlcmlhbCggbWF0ZXJpYWwgKTtcblxuXHRcdGlmICggbWF0ZXJpYWxTaGFkZXJzLmhhcyggdmVydGV4U2hhZGVyU3RhZ2UgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdG1hdGVyaWFsU2hhZGVycy5hZGQoIHZlcnRleFNoYWRlclN0YWdlICk7XG5cdFx0XHR2ZXJ0ZXhTaGFkZXJTdGFnZS51c2VkVGltZXMgKys7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsU2hhZGVycy5oYXMoIGZyYWdtZW50U2hhZGVyU3RhZ2UgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdG1hdGVyaWFsU2hhZGVycy5hZGQoIGZyYWdtZW50U2hhZGVyU3RhZ2UgKTtcblx0XHRcdGZyYWdtZW50U2hhZGVyU3RhZ2UudXNlZFRpbWVzICsrO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJlbW92ZSggbWF0ZXJpYWwgKSB7XG5cblx0XHRjb25zdCBtYXRlcmlhbFNoYWRlcnMgPSB0aGlzLm1hdGVyaWFsQ2FjaGUuZ2V0KCBtYXRlcmlhbCApO1xuXG5cdFx0Zm9yICggY29uc3Qgc2hhZGVyU3RhZ2Ugb2YgbWF0ZXJpYWxTaGFkZXJzICkge1xuXG5cdFx0XHRzaGFkZXJTdGFnZS51c2VkVGltZXMgLS07XG5cblx0XHRcdGlmICggc2hhZGVyU3RhZ2UudXNlZFRpbWVzID09PSAwICkgdGhpcy5zaGFkZXJDYWNoZS5kZWxldGUoIHNoYWRlclN0YWdlLmNvZGUgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMubWF0ZXJpYWxDYWNoZS5kZWxldGUoIG1hdGVyaWFsICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0VmVydGV4U2hhZGVySUQoIG1hdGVyaWFsICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX2dldFNoYWRlclN0YWdlKCBtYXRlcmlhbC52ZXJ0ZXhTaGFkZXIgKS5pZDtcblxuXHR9XG5cblx0Z2V0RnJhZ21lbnRTaGFkZXJJRCggbWF0ZXJpYWwgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fZ2V0U2hhZGVyU3RhZ2UoIG1hdGVyaWFsLmZyYWdtZW50U2hhZGVyICkuaWQ7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLnNoYWRlckNhY2hlLmNsZWFyKCk7XG5cdFx0dGhpcy5tYXRlcmlhbENhY2hlLmNsZWFyKCk7XG5cblx0fVxuXG5cdF9nZXRTaGFkZXJDYWNoZUZvck1hdGVyaWFsKCBtYXRlcmlhbCApIHtcblxuXHRcdGNvbnN0IGNhY2hlID0gdGhpcy5tYXRlcmlhbENhY2hlO1xuXHRcdGxldCBzZXQgPSBjYWNoZS5nZXQoIG1hdGVyaWFsICk7XG5cblx0XHRpZiAoIHNldCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRzZXQgPSBuZXcgU2V0KCk7XG5cdFx0XHRjYWNoZS5zZXQoIG1hdGVyaWFsLCBzZXQgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBzZXQ7XG5cblx0fVxuXG5cdF9nZXRTaGFkZXJTdGFnZSggY29kZSApIHtcblxuXHRcdGNvbnN0IGNhY2hlID0gdGhpcy5zaGFkZXJDYWNoZTtcblx0XHRsZXQgc3RhZ2UgPSBjYWNoZS5nZXQoIGNvZGUgKTtcblxuXHRcdGlmICggc3RhZ2UgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0c3RhZ2UgPSBuZXcgV2ViR0xTaGFkZXJTdGFnZSggY29kZSApO1xuXHRcdFx0Y2FjaGUuc2V0KCBjb2RlLCBzdGFnZSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHN0YWdlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBXZWJHTFNoYWRlclN0YWdlIHtcblxuXHRjb25zdHJ1Y3RvciggY29kZSApIHtcblxuXHRcdHRoaXMuaWQgPSBfaWQkMSArKztcblxuXHRcdHRoaXMuY29kZSA9IGNvZGU7XG5cdFx0dGhpcy51c2VkVGltZXMgPSAwO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBXZWJHTFByb2dyYW1zKCByZW5kZXJlciwgY3ViZW1hcHMsIGN1YmV1dm1hcHMsIGV4dGVuc2lvbnMsIGNhcGFiaWxpdGllcywgYmluZGluZ1N0YXRlcywgY2xpcHBpbmcgKSB7XG5cblx0Y29uc3QgX3Byb2dyYW1MYXllcnMgPSBuZXcgTGF5ZXJzKCk7XG5cdGNvbnN0IF9jdXN0b21TaGFkZXJzID0gbmV3IFdlYkdMU2hhZGVyQ2FjaGUoKTtcblx0Y29uc3QgX2FjdGl2ZUNoYW5uZWxzID0gbmV3IFNldCgpO1xuXHRjb25zdCBwcm9ncmFtcyA9IFtdO1xuXG5cdGNvbnN0IGxvZ2FyaXRobWljRGVwdGhCdWZmZXIgPSBjYXBhYmlsaXRpZXMubG9nYXJpdGhtaWNEZXB0aEJ1ZmZlcjtcblx0Y29uc3QgU1VQUE9SVFNfVkVSVEVYX1RFWFRVUkVTID0gY2FwYWJpbGl0aWVzLnZlcnRleFRleHR1cmVzO1xuXG5cdGxldCBwcmVjaXNpb24gPSBjYXBhYmlsaXRpZXMucHJlY2lzaW9uO1xuXG5cdGNvbnN0IHNoYWRlcklEcyA9IHtcblx0XHRNZXNoRGVwdGhNYXRlcmlhbDogJ2RlcHRoJyxcblx0XHRNZXNoRGlzdGFuY2VNYXRlcmlhbDogJ2Rpc3RhbmNlUkdCQScsXG5cdFx0TWVzaE5vcm1hbE1hdGVyaWFsOiAnbm9ybWFsJyxcblx0XHRNZXNoQmFzaWNNYXRlcmlhbDogJ2Jhc2ljJyxcblx0XHRNZXNoTGFtYmVydE1hdGVyaWFsOiAnbGFtYmVydCcsXG5cdFx0TWVzaFBob25nTWF0ZXJpYWw6ICdwaG9uZycsXG5cdFx0TWVzaFRvb25NYXRlcmlhbDogJ3Rvb24nLFxuXHRcdE1lc2hTdGFuZGFyZE1hdGVyaWFsOiAncGh5c2ljYWwnLFxuXHRcdE1lc2hQaHlzaWNhbE1hdGVyaWFsOiAncGh5c2ljYWwnLFxuXHRcdE1lc2hNYXRjYXBNYXRlcmlhbDogJ21hdGNhcCcsXG5cdFx0TGluZUJhc2ljTWF0ZXJpYWw6ICdiYXNpYycsXG5cdFx0TGluZURhc2hlZE1hdGVyaWFsOiAnZGFzaGVkJyxcblx0XHRQb2ludHNNYXRlcmlhbDogJ3BvaW50cycsXG5cdFx0U2hhZG93TWF0ZXJpYWw6ICdzaGFkb3cnLFxuXHRcdFNwcml0ZU1hdGVyaWFsOiAnc3ByaXRlJ1xuXHR9O1xuXG5cdGZ1bmN0aW9uIGdldENoYW5uZWwoIHZhbHVlICkge1xuXG5cdFx0X2FjdGl2ZUNoYW5uZWxzLmFkZCggdmFsdWUgKTtcblxuXHRcdGlmICggdmFsdWUgPT09IDAgKSByZXR1cm4gJ3V2JztcblxuXHRcdHJldHVybiBgdXYkeyB2YWx1ZSB9YDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0UGFyYW1ldGVycyggbWF0ZXJpYWwsIGxpZ2h0cywgc2hhZG93cywgc2NlbmUsIG9iamVjdCApIHtcblxuXHRcdGNvbnN0IGZvZyA9IHNjZW5lLmZvZztcblx0XHRjb25zdCBnZW9tZXRyeSA9IG9iamVjdC5nZW9tZXRyeTtcblx0XHRjb25zdCBlbnZpcm9ubWVudCA9IG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBzY2VuZS5lbnZpcm9ubWVudCA6IG51bGw7XG5cblx0XHRjb25zdCBlbnZNYXAgPSAoIG1hdGVyaWFsLmlzTWVzaFN0YW5kYXJkTWF0ZXJpYWwgPyBjdWJldXZtYXBzIDogY3ViZW1hcHMgKS5nZXQoIG1hdGVyaWFsLmVudk1hcCB8fCBlbnZpcm9ubWVudCApO1xuXHRcdGNvbnN0IGVudk1hcEN1YmVVVkhlaWdodCA9ICggISEgZW52TWFwICkgJiYgKCBlbnZNYXAubWFwcGluZyA9PT0gQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmcgKSA/IGVudk1hcC5pbWFnZS5oZWlnaHQgOiBudWxsO1xuXG5cdFx0Y29uc3Qgc2hhZGVySUQgPSBzaGFkZXJJRHNbIG1hdGVyaWFsLnR5cGUgXTtcblxuXHRcdC8vIGhldXJpc3RpY3MgdG8gY3JlYXRlIHNoYWRlciBwYXJhbWV0ZXJzIGFjY29yZGluZyB0byBsaWdodHMgaW4gdGhlIHNjZW5lXG5cdFx0Ly8gKG5vdCB0byBibG93IG92ZXIgbWF4TGlnaHRzIGJ1ZGdldClcblxuXHRcdGlmICggbWF0ZXJpYWwucHJlY2lzaW9uICE9PSBudWxsICkge1xuXG5cdFx0XHRwcmVjaXNpb24gPSBjYXBhYmlsaXRpZXMuZ2V0TWF4UHJlY2lzaW9uKCBtYXRlcmlhbC5wcmVjaXNpb24gKTtcblxuXHRcdFx0aWYgKCBwcmVjaXNpb24gIT09IG1hdGVyaWFsLnByZWNpc2lvbiApIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFByb2dyYW0uZ2V0UGFyYW1ldGVyczonLCBtYXRlcmlhbC5wcmVjaXNpb24sICdub3Qgc3VwcG9ydGVkLCB1c2luZycsIHByZWNpc2lvbiwgJ2luc3RlYWQuJyApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvL1xuXG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMucG9zaXRpb24gfHwgZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLm5vcm1hbCB8fCBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMuY29sb3I7XG5cdFx0Y29uc3QgbW9ycGhUYXJnZXRzQ291bnQgPSAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSA/IG1vcnBoQXR0cmlidXRlLmxlbmd0aCA6IDA7XG5cblx0XHRsZXQgbW9ycGhUZXh0dXJlU3RyaWRlID0gMDtcblxuXHRcdGlmICggZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uICE9PSB1bmRlZmluZWQgKSBtb3JwaFRleHR1cmVTdHJpZGUgPSAxO1xuXHRcdGlmICggZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLm5vcm1hbCAhPT0gdW5kZWZpbmVkICkgbW9ycGhUZXh0dXJlU3RyaWRlID0gMjtcblx0XHRpZiAoIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvciAhPT0gdW5kZWZpbmVkICkgbW9ycGhUZXh0dXJlU3RyaWRlID0gMztcblxuXHRcdC8vXG5cblx0XHRsZXQgdmVydGV4U2hhZGVyLCBmcmFnbWVudFNoYWRlcjtcblx0XHRsZXQgY3VzdG9tVmVydGV4U2hhZGVySUQsIGN1c3RvbUZyYWdtZW50U2hhZGVySUQ7XG5cblx0XHRpZiAoIHNoYWRlcklEICkge1xuXG5cdFx0XHRjb25zdCBzaGFkZXIgPSBTaGFkZXJMaWJbIHNoYWRlcklEIF07XG5cblx0XHRcdHZlcnRleFNoYWRlciA9IHNoYWRlci52ZXJ0ZXhTaGFkZXI7XG5cdFx0XHRmcmFnbWVudFNoYWRlciA9IHNoYWRlci5mcmFnbWVudFNoYWRlcjtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHZlcnRleFNoYWRlciA9IG1hdGVyaWFsLnZlcnRleFNoYWRlcjtcblx0XHRcdGZyYWdtZW50U2hhZGVyID0gbWF0ZXJpYWwuZnJhZ21lbnRTaGFkZXI7XG5cblx0XHRcdF9jdXN0b21TaGFkZXJzLnVwZGF0ZSggbWF0ZXJpYWwgKTtcblxuXHRcdFx0Y3VzdG9tVmVydGV4U2hhZGVySUQgPSBfY3VzdG9tU2hhZGVycy5nZXRWZXJ0ZXhTaGFkZXJJRCggbWF0ZXJpYWwgKTtcblx0XHRcdGN1c3RvbUZyYWdtZW50U2hhZGVySUQgPSBfY3VzdG9tU2hhZGVycy5nZXRGcmFnbWVudFNoYWRlcklEKCBtYXRlcmlhbCApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgY3VycmVudFJlbmRlclRhcmdldCA9IHJlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xuXG5cdFx0Y29uc3QgSVNfSU5TVEFOQ0VETUVTSCA9IG9iamVjdC5pc0luc3RhbmNlZE1lc2ggPT09IHRydWU7XG5cdFx0Y29uc3QgSVNfQkFUQ0hFRE1FU0ggPSBvYmplY3QuaXNCYXRjaGVkTWVzaCA9PT0gdHJ1ZTtcblxuXHRcdGNvbnN0IEhBU19NQVAgPSAhISBtYXRlcmlhbC5tYXA7XG5cdFx0Y29uc3QgSEFTX01BVENBUCA9ICEhIG1hdGVyaWFsLm1hdGNhcDtcblx0XHRjb25zdCBIQVNfRU5WTUFQID0gISEgZW52TWFwO1xuXHRcdGNvbnN0IEhBU19BT01BUCA9ICEhIG1hdGVyaWFsLmFvTWFwO1xuXHRcdGNvbnN0IEhBU19MSUdIVE1BUCA9ICEhIG1hdGVyaWFsLmxpZ2h0TWFwO1xuXHRcdGNvbnN0IEhBU19CVU1QTUFQID0gISEgbWF0ZXJpYWwuYnVtcE1hcDtcblx0XHRjb25zdCBIQVNfTk9STUFMTUFQID0gISEgbWF0ZXJpYWwubm9ybWFsTWFwO1xuXHRcdGNvbnN0IEhBU19ESVNQTEFDRU1FTlRNQVAgPSAhISBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXA7XG5cdFx0Y29uc3QgSEFTX0VNSVNTSVZFTUFQID0gISEgbWF0ZXJpYWwuZW1pc3NpdmVNYXA7XG5cblx0XHRjb25zdCBIQVNfTUVUQUxORVNTTUFQID0gISEgbWF0ZXJpYWwubWV0YWxuZXNzTWFwO1xuXHRcdGNvbnN0IEhBU19ST1VHSE5FU1NNQVAgPSAhISBtYXRlcmlhbC5yb3VnaG5lc3NNYXA7XG5cblx0XHRjb25zdCBIQVNfQU5JU09UUk9QWSA9IG1hdGVyaWFsLmFuaXNvdHJvcHkgPiAwO1xuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVQgPSBtYXRlcmlhbC5jbGVhcmNvYXQgPiAwO1xuXHRcdGNvbnN0IEhBU19ESVNQRVJTSU9OID0gbWF0ZXJpYWwuZGlzcGVyc2lvbiA+IDA7XG5cdFx0Y29uc3QgSEFTX0lSSURFU0NFTkNFID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2UgPiAwO1xuXHRcdGNvbnN0IEhBU19TSEVFTiA9IG1hdGVyaWFsLnNoZWVuID4gMDtcblx0XHRjb25zdCBIQVNfVFJBTlNNSVNTSU9OID0gbWF0ZXJpYWwudHJhbnNtaXNzaW9uID4gMDtcblxuXHRcdGNvbnN0IEhBU19BTklTT1RST1BZTUFQID0gSEFTX0FOSVNPVFJPUFkgJiYgISEgbWF0ZXJpYWwuYW5pc290cm9weU1hcDtcblxuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVRNQVAgPSBIQVNfQ0xFQVJDT0FUICYmICEhIG1hdGVyaWFsLmNsZWFyY29hdE1hcDtcblx0XHRjb25zdCBIQVNfQ0xFQVJDT0FUX05PUk1BTE1BUCA9IEhBU19DTEVBUkNPQVQgJiYgISEgbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsTWFwO1xuXHRcdGNvbnN0IEhBU19DTEVBUkNPQVRfUk9VR0hORVNTTUFQID0gSEFTX0NMRUFSQ09BVCAmJiAhISBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3NNYXA7XG5cblx0XHRjb25zdCBIQVNfSVJJREVTQ0VOQ0VNQVAgPSBIQVNfSVJJREVTQ0VOQ0UgJiYgISEgbWF0ZXJpYWwuaXJpZGVzY2VuY2VNYXA7XG5cdFx0Y29uc3QgSEFTX0lSSURFU0NFTkNFX1RISUNLTkVTU01BUCA9IEhBU19JUklERVNDRU5DRSAmJiAhISBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcDtcblxuXHRcdGNvbnN0IEhBU19TSEVFTl9DT0xPUk1BUCA9IEhBU19TSEVFTiAmJiAhISBtYXRlcmlhbC5zaGVlbkNvbG9yTWFwO1xuXHRcdGNvbnN0IEhBU19TSEVFTl9ST1VHSE5FU1NNQVAgPSBIQVNfU0hFRU4gJiYgISEgbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3NNYXA7XG5cblx0XHRjb25zdCBIQVNfU1BFQ1VMQVJNQVAgPSAhISBtYXRlcmlhbC5zcGVjdWxhck1hcDtcblx0XHRjb25zdCBIQVNfU1BFQ1VMQVJfQ09MT1JNQVAgPSAhISBtYXRlcmlhbC5zcGVjdWxhckNvbG9yTWFwO1xuXHRcdGNvbnN0IEhBU19TUEVDVUxBUl9JTlRFTlNJVFlNQVAgPSAhISBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eU1hcDtcblxuXHRcdGNvbnN0IEhBU19UUkFOU01JU1NJT05NQVAgPSBIQVNfVFJBTlNNSVNTSU9OICYmICEhIG1hdGVyaWFsLnRyYW5zbWlzc2lvbk1hcDtcblx0XHRjb25zdCBIQVNfVEhJQ0tORVNTTUFQID0gSEFTX1RSQU5TTUlTU0lPTiAmJiAhISBtYXRlcmlhbC50aGlja25lc3NNYXA7XG5cblx0XHRjb25zdCBIQVNfR1JBRElFTlRNQVAgPSAhISBtYXRlcmlhbC5ncmFkaWVudE1hcDtcblxuXHRcdGNvbnN0IEhBU19BTFBIQU1BUCA9ICEhIG1hdGVyaWFsLmFscGhhTWFwO1xuXG5cdFx0Y29uc3QgSEFTX0FMUEhBVEVTVCA9IG1hdGVyaWFsLmFscGhhVGVzdCA+IDA7XG5cblx0XHRjb25zdCBIQVNfQUxQSEFIQVNIID0gISEgbWF0ZXJpYWwuYWxwaGFIYXNoO1xuXG5cdFx0Y29uc3QgSEFTX0VYVEVOU0lPTlMgPSAhISBtYXRlcmlhbC5leHRlbnNpb25zO1xuXG5cdFx0bGV0IHRvbmVNYXBwaW5nID0gTm9Ub25lTWFwcGluZztcblxuXHRcdGlmICggbWF0ZXJpYWwudG9uZU1hcHBlZCApIHtcblxuXHRcdFx0aWYgKCBjdXJyZW50UmVuZGVyVGFyZ2V0ID09PSBudWxsIHx8IGN1cnJlbnRSZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHR0b25lTWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRjb25zdCBwYXJhbWV0ZXJzID0ge1xuXG5cdFx0XHRzaGFkZXJJRDogc2hhZGVySUQsXG5cdFx0XHRzaGFkZXJUeXBlOiBtYXRlcmlhbC50eXBlLFxuXHRcdFx0c2hhZGVyTmFtZTogbWF0ZXJpYWwubmFtZSxcblxuXHRcdFx0dmVydGV4U2hhZGVyOiB2ZXJ0ZXhTaGFkZXIsXG5cdFx0XHRmcmFnbWVudFNoYWRlcjogZnJhZ21lbnRTaGFkZXIsXG5cdFx0XHRkZWZpbmVzOiBtYXRlcmlhbC5kZWZpbmVzLFxuXG5cdFx0XHRjdXN0b21WZXJ0ZXhTaGFkZXJJRDogY3VzdG9tVmVydGV4U2hhZGVySUQsXG5cdFx0XHRjdXN0b21GcmFnbWVudFNoYWRlcklEOiBjdXN0b21GcmFnbWVudFNoYWRlcklELFxuXG5cdFx0XHRpc1Jhd1NoYWRlck1hdGVyaWFsOiBtYXRlcmlhbC5pc1Jhd1NoYWRlck1hdGVyaWFsID09PSB0cnVlLFxuXHRcdFx0Z2xzbFZlcnNpb246IG1hdGVyaWFsLmdsc2xWZXJzaW9uLFxuXG5cdFx0XHRwcmVjaXNpb246IHByZWNpc2lvbixcblxuXHRcdFx0YmF0Y2hpbmc6IElTX0JBVENIRURNRVNILFxuXHRcdFx0YmF0Y2hpbmdDb2xvcjogSVNfQkFUQ0hFRE1FU0ggJiYgb2JqZWN0Ll9jb2xvcnNUZXh0dXJlICE9PSBudWxsLFxuXHRcdFx0aW5zdGFuY2luZzogSVNfSU5TVEFOQ0VETUVTSCxcblx0XHRcdGluc3RhbmNpbmdDb2xvcjogSVNfSU5TVEFOQ0VETUVTSCAmJiBvYmplY3QuaW5zdGFuY2VDb2xvciAhPT0gbnVsbCxcblx0XHRcdGluc3RhbmNpbmdNb3JwaDogSVNfSU5TVEFOQ0VETUVTSCAmJiBvYmplY3QubW9ycGhUZXh0dXJlICE9PSBudWxsLFxuXG5cdFx0XHRzdXBwb3J0c1ZlcnRleFRleHR1cmVzOiBTVVBQT1JUU19WRVJURVhfVEVYVFVSRVMsXG5cdFx0XHRvdXRwdXRDb2xvclNwYWNlOiAoIGN1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgKSA/IHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2UgOiAoIGN1cnJlbnRSZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSA/IGN1cnJlbnRSZW5kZXJUYXJnZXQudGV4dHVyZS5jb2xvclNwYWNlIDogTGluZWFyU1JHQkNvbG9yU3BhY2UgKSxcblx0XHRcdGFscGhhVG9Db3ZlcmFnZTogISEgbWF0ZXJpYWwuYWxwaGFUb0NvdmVyYWdlLFxuXG5cdFx0XHRtYXA6IEhBU19NQVAsXG5cdFx0XHRtYXRjYXA6IEhBU19NQVRDQVAsXG5cdFx0XHRlbnZNYXA6IEhBU19FTlZNQVAsXG5cdFx0XHRlbnZNYXBNb2RlOiBIQVNfRU5WTUFQICYmIGVudk1hcC5tYXBwaW5nLFxuXHRcdFx0ZW52TWFwQ3ViZVVWSGVpZ2h0OiBlbnZNYXBDdWJlVVZIZWlnaHQsXG5cdFx0XHRhb01hcDogSEFTX0FPTUFQLFxuXHRcdFx0bGlnaHRNYXA6IEhBU19MSUdIVE1BUCxcblx0XHRcdGJ1bXBNYXA6IEhBU19CVU1QTUFQLFxuXHRcdFx0bm9ybWFsTWFwOiBIQVNfTk9STUFMTUFQLFxuXHRcdFx0ZGlzcGxhY2VtZW50TWFwOiBTVVBQT1JUU19WRVJURVhfVEVYVFVSRVMgJiYgSEFTX0RJU1BMQUNFTUVOVE1BUCxcblx0XHRcdGVtaXNzaXZlTWFwOiBIQVNfRU1JU1NJVkVNQVAsXG5cblx0XHRcdG5vcm1hbE1hcE9iamVjdFNwYWNlOiBIQVNfTk9STUFMTUFQICYmIG1hdGVyaWFsLm5vcm1hbE1hcFR5cGUgPT09IE9iamVjdFNwYWNlTm9ybWFsTWFwLFxuXHRcdFx0bm9ybWFsTWFwVGFuZ2VudFNwYWNlOiBIQVNfTk9STUFMTUFQICYmIG1hdGVyaWFsLm5vcm1hbE1hcFR5cGUgPT09IFRhbmdlbnRTcGFjZU5vcm1hbE1hcCxcblxuXHRcdFx0bWV0YWxuZXNzTWFwOiBIQVNfTUVUQUxORVNTTUFQLFxuXHRcdFx0cm91Z2huZXNzTWFwOiBIQVNfUk9VR0hORVNTTUFQLFxuXG5cdFx0XHRhbmlzb3Ryb3B5OiBIQVNfQU5JU09UUk9QWSxcblx0XHRcdGFuaXNvdHJvcHlNYXA6IEhBU19BTklTT1RST1BZTUFQLFxuXG5cdFx0XHRjbGVhcmNvYXQ6IEhBU19DTEVBUkNPQVQsXG5cdFx0XHRjbGVhcmNvYXRNYXA6IEhBU19DTEVBUkNPQVRNQVAsXG5cdFx0XHRjbGVhcmNvYXROb3JtYWxNYXA6IEhBU19DTEVBUkNPQVRfTk9STUFMTUFQLFxuXHRcdFx0Y2xlYXJjb2F0Um91Z2huZXNzTWFwOiBIQVNfQ0xFQVJDT0FUX1JPVUdITkVTU01BUCxcblxuXHRcdFx0ZGlzcGVyc2lvbjogSEFTX0RJU1BFUlNJT04sXG5cblx0XHRcdGlyaWRlc2NlbmNlOiBIQVNfSVJJREVTQ0VOQ0UsXG5cdFx0XHRpcmlkZXNjZW5jZU1hcDogSEFTX0lSSURFU0NFTkNFTUFQLFxuXHRcdFx0aXJpZGVzY2VuY2VUaGlja25lc3NNYXA6IEhBU19JUklERVNDRU5DRV9USElDS05FU1NNQVAsXG5cblx0XHRcdHNoZWVuOiBIQVNfU0hFRU4sXG5cdFx0XHRzaGVlbkNvbG9yTWFwOiBIQVNfU0hFRU5fQ09MT1JNQVAsXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcDogSEFTX1NIRUVOX1JPVUdITkVTU01BUCxcblxuXHRcdFx0c3BlY3VsYXJNYXA6IEhBU19TUEVDVUxBUk1BUCxcblx0XHRcdHNwZWN1bGFyQ29sb3JNYXA6IEhBU19TUEVDVUxBUl9DT0xPUk1BUCxcblx0XHRcdHNwZWN1bGFySW50ZW5zaXR5TWFwOiBIQVNfU1BFQ1VMQVJfSU5URU5TSVRZTUFQLFxuXG5cdFx0XHR0cmFuc21pc3Npb246IEhBU19UUkFOU01JU1NJT04sXG5cdFx0XHR0cmFuc21pc3Npb25NYXA6IEhBU19UUkFOU01JU1NJT05NQVAsXG5cdFx0XHR0aGlja25lc3NNYXA6IEhBU19USElDS05FU1NNQVAsXG5cblx0XHRcdGdyYWRpZW50TWFwOiBIQVNfR1JBRElFTlRNQVAsXG5cblx0XHRcdG9wYXF1ZTogbWF0ZXJpYWwudHJhbnNwYXJlbnQgPT09IGZhbHNlICYmIG1hdGVyaWFsLmJsZW5kaW5nID09PSBOb3JtYWxCbGVuZGluZyAmJiBtYXRlcmlhbC5hbHBoYVRvQ292ZXJhZ2UgPT09IGZhbHNlLFxuXG5cdFx0XHRhbHBoYU1hcDogSEFTX0FMUEhBTUFQLFxuXHRcdFx0YWxwaGFUZXN0OiBIQVNfQUxQSEFURVNULFxuXHRcdFx0YWxwaGFIYXNoOiBIQVNfQUxQSEFIQVNILFxuXG5cdFx0XHRjb21iaW5lOiBtYXRlcmlhbC5jb21iaW5lLFxuXG5cdFx0XHQvL1xuXG5cdFx0XHRtYXBVdjogSEFTX01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5tYXAuY2hhbm5lbCApLFxuXHRcdFx0YW9NYXBVdjogSEFTX0FPTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmFvTWFwLmNoYW5uZWwgKSxcblx0XHRcdGxpZ2h0TWFwVXY6IEhBU19MSUdIVE1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5saWdodE1hcC5jaGFubmVsICksXG5cdFx0XHRidW1wTWFwVXY6IEhBU19CVU1QTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmJ1bXBNYXAuY2hhbm5lbCApLFxuXHRcdFx0bm9ybWFsTWFwVXY6IEhBU19OT1JNQUxNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwubm9ybWFsTWFwLmNoYW5uZWwgKSxcblx0XHRcdGRpc3BsYWNlbWVudE1hcFV2OiBIQVNfRElTUExBQ0VNRU5UTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmRpc3BsYWNlbWVudE1hcC5jaGFubmVsICksXG5cdFx0XHRlbWlzc2l2ZU1hcFV2OiBIQVNfRU1JU1NJVkVNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuZW1pc3NpdmVNYXAuY2hhbm5lbCApLFxuXG5cdFx0XHRtZXRhbG5lc3NNYXBVdjogSEFTX01FVEFMTkVTU01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5tZXRhbG5lc3NNYXAuY2hhbm5lbCApLFxuXHRcdFx0cm91Z2huZXNzTWFwVXY6IEhBU19ST1VHSE5FU1NNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwucm91Z2huZXNzTWFwLmNoYW5uZWwgKSxcblxuXHRcdFx0YW5pc290cm9weU1hcFV2OiBIQVNfQU5JU09UUk9QWU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5hbmlzb3Ryb3B5TWFwLmNoYW5uZWwgKSxcblxuXHRcdFx0Y2xlYXJjb2F0TWFwVXY6IEhBU19DTEVBUkNPQVRNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuY2xlYXJjb2F0TWFwLmNoYW5uZWwgKSxcblx0XHRcdGNsZWFyY29hdE5vcm1hbE1hcFV2OiBIQVNfQ0xFQVJDT0FUX05PUk1BTE1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxNYXAuY2hhbm5lbCApLFxuXHRcdFx0Y2xlYXJjb2F0Um91Z2huZXNzTWFwVXY6IEhBU19DTEVBUkNPQVRfUk9VR0hORVNTTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmNsZWFyY29hdFJvdWdobmVzc01hcC5jaGFubmVsICksXG5cblx0XHRcdGlyaWRlc2NlbmNlTWFwVXY6IEhBU19JUklERVNDRU5DRU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcC5jaGFubmVsICksXG5cdFx0XHRpcmlkZXNjZW5jZVRoaWNrbmVzc01hcFV2OiBIQVNfSVJJREVTQ0VOQ0VfVEhJQ0tORVNTTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwLmNoYW5uZWwgKSxcblxuXHRcdFx0c2hlZW5Db2xvck1hcFV2OiBIQVNfU0hFRU5fQ09MT1JNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuc2hlZW5Db2xvck1hcC5jaGFubmVsICksXG5cdFx0XHRzaGVlblJvdWdobmVzc01hcFV2OiBIQVNfU0hFRU5fUk9VR0hORVNTTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLnNoZWVuUm91Z2huZXNzTWFwLmNoYW5uZWwgKSxcblxuXHRcdFx0c3BlY3VsYXJNYXBVdjogSEFTX1NQRUNVTEFSTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLnNwZWN1bGFyTWFwLmNoYW5uZWwgKSxcblx0XHRcdHNwZWN1bGFyQ29sb3JNYXBVdjogSEFTX1NQRUNVTEFSX0NPTE9STUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3JNYXAuY2hhbm5lbCApLFxuXHRcdFx0c3BlY3VsYXJJbnRlbnNpdHlNYXBVdjogSEFTX1NQRUNVTEFSX0lOVEVOU0lUWU1BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eU1hcC5jaGFubmVsICksXG5cblx0XHRcdHRyYW5zbWlzc2lvbk1hcFV2OiBIQVNfVFJBTlNNSVNTSU9OTUFQICYmIGdldENoYW5uZWwoIG1hdGVyaWFsLnRyYW5zbWlzc2lvbk1hcC5jaGFubmVsICksXG5cdFx0XHR0aGlja25lc3NNYXBVdjogSEFTX1RISUNLTkVTU01BUCAmJiBnZXRDaGFubmVsKCBtYXRlcmlhbC50aGlja25lc3NNYXAuY2hhbm5lbCApLFxuXG5cdFx0XHRhbHBoYU1hcFV2OiBIQVNfQUxQSEFNQVAgJiYgZ2V0Q2hhbm5lbCggbWF0ZXJpYWwuYWxwaGFNYXAuY2hhbm5lbCApLFxuXG5cdFx0XHQvL1xuXG5cdFx0XHR2ZXJ0ZXhUYW5nZW50czogISEgZ2VvbWV0cnkuYXR0cmlidXRlcy50YW5nZW50ICYmICggSEFTX05PUk1BTE1BUCB8fCBIQVNfQU5JU09UUk9QWSApLFxuXHRcdFx0dmVydGV4Q29sb3JzOiBtYXRlcmlhbC52ZXJ0ZXhDb2xvcnMsXG5cdFx0XHR2ZXJ0ZXhBbHBoYXM6IG1hdGVyaWFsLnZlcnRleENvbG9ycyA9PT0gdHJ1ZSAmJiAhISBnZW9tZXRyeS5hdHRyaWJ1dGVzLmNvbG9yICYmIGdlb21ldHJ5LmF0dHJpYnV0ZXMuY29sb3IuaXRlbVNpemUgPT09IDQsXG5cblx0XHRcdHBvaW50c1V2czogb2JqZWN0LmlzUG9pbnRzID09PSB0cnVlICYmICEhIGdlb21ldHJ5LmF0dHJpYnV0ZXMudXYgJiYgKCBIQVNfTUFQIHx8IEhBU19BTFBIQU1BUCApLFxuXG5cdFx0XHRmb2c6ICEhIGZvZyxcblx0XHRcdHVzZUZvZzogbWF0ZXJpYWwuZm9nID09PSB0cnVlLFxuXHRcdFx0Zm9nRXhwMjogKCAhISBmb2cgJiYgZm9nLmlzRm9nRXhwMiApLFxuXG5cdFx0XHRmbGF0U2hhZGluZzogbWF0ZXJpYWwuZmxhdFNoYWRpbmcgPT09IHRydWUsXG5cblx0XHRcdHNpemVBdHRlbnVhdGlvbjogbWF0ZXJpYWwuc2l6ZUF0dGVudWF0aW9uID09PSB0cnVlLFxuXHRcdFx0bG9nYXJpdGhtaWNEZXB0aEJ1ZmZlcjogbG9nYXJpdGhtaWNEZXB0aEJ1ZmZlcixcblxuXHRcdFx0c2tpbm5pbmc6IG9iamVjdC5pc1NraW5uZWRNZXNoID09PSB0cnVlLFxuXG5cdFx0XHRtb3JwaFRhcmdldHM6IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbiAhPT0gdW5kZWZpbmVkLFxuXHRcdFx0bW9ycGhOb3JtYWxzOiBnZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMubm9ybWFsICE9PSB1bmRlZmluZWQsXG5cdFx0XHRtb3JwaENvbG9yczogZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yICE9PSB1bmRlZmluZWQsXG5cdFx0XHRtb3JwaFRhcmdldHNDb3VudDogbW9ycGhUYXJnZXRzQ291bnQsXG5cdFx0XHRtb3JwaFRleHR1cmVTdHJpZGU6IG1vcnBoVGV4dHVyZVN0cmlkZSxcblxuXHRcdFx0bnVtRGlyTGlnaHRzOiBsaWdodHMuZGlyZWN0aW9uYWwubGVuZ3RoLFxuXHRcdFx0bnVtUG9pbnRMaWdodHM6IGxpZ2h0cy5wb2ludC5sZW5ndGgsXG5cdFx0XHRudW1TcG90TGlnaHRzOiBsaWdodHMuc3BvdC5sZW5ndGgsXG5cdFx0XHRudW1TcG90TGlnaHRNYXBzOiBsaWdodHMuc3BvdExpZ2h0TWFwLmxlbmd0aCxcblx0XHRcdG51bVJlY3RBcmVhTGlnaHRzOiBsaWdodHMucmVjdEFyZWEubGVuZ3RoLFxuXHRcdFx0bnVtSGVtaUxpZ2h0czogbGlnaHRzLmhlbWkubGVuZ3RoLFxuXG5cdFx0XHRudW1EaXJMaWdodFNoYWRvd3M6IGxpZ2h0cy5kaXJlY3Rpb25hbFNoYWRvd01hcC5sZW5ndGgsXG5cdFx0XHRudW1Qb2ludExpZ2h0U2hhZG93czogbGlnaHRzLnBvaW50U2hhZG93TWFwLmxlbmd0aCxcblx0XHRcdG51bVNwb3RMaWdodFNoYWRvd3M6IGxpZ2h0cy5zcG90U2hhZG93TWFwLmxlbmd0aCxcblx0XHRcdG51bVNwb3RMaWdodFNoYWRvd3NXaXRoTWFwczogbGlnaHRzLm51bVNwb3RMaWdodFNoYWRvd3NXaXRoTWFwcyxcblxuXHRcdFx0bnVtTGlnaHRQcm9iZXM6IGxpZ2h0cy5udW1MaWdodFByb2JlcyxcblxuXHRcdFx0bnVtQ2xpcHBpbmdQbGFuZXM6IGNsaXBwaW5nLm51bVBsYW5lcyxcblx0XHRcdG51bUNsaXBJbnRlcnNlY3Rpb246IGNsaXBwaW5nLm51bUludGVyc2VjdGlvbixcblxuXHRcdFx0ZGl0aGVyaW5nOiBtYXRlcmlhbC5kaXRoZXJpbmcsXG5cblx0XHRcdHNoYWRvd01hcEVuYWJsZWQ6IHJlbmRlcmVyLnNoYWRvd01hcC5lbmFibGVkICYmIHNoYWRvd3MubGVuZ3RoID4gMCxcblx0XHRcdHNoYWRvd01hcFR5cGU6IHJlbmRlcmVyLnNoYWRvd01hcC50eXBlLFxuXG5cdFx0XHR0b25lTWFwcGluZzogdG9uZU1hcHBpbmcsXG5cblx0XHRcdGRlY29kZVZpZGVvVGV4dHVyZTogSEFTX01BUCAmJiAoIG1hdGVyaWFsLm1hcC5pc1ZpZGVvVGV4dHVyZSA9PT0gdHJ1ZSApICYmICggQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBtYXRlcmlhbC5tYXAuY29sb3JTcGFjZSApID09PSBTUkdCVHJhbnNmZXIgKSxcblxuXHRcdFx0cHJlbXVsdGlwbGllZEFscGhhOiBtYXRlcmlhbC5wcmVtdWx0aXBsaWVkQWxwaGEsXG5cblx0XHRcdGRvdWJsZVNpZGVkOiBtYXRlcmlhbC5zaWRlID09PSBEb3VibGVTaWRlLFxuXHRcdFx0ZmxpcFNpZGVkOiBtYXRlcmlhbC5zaWRlID09PSBCYWNrU2lkZSxcblxuXHRcdFx0dXNlRGVwdGhQYWNraW5nOiBtYXRlcmlhbC5kZXB0aFBhY2tpbmcgPj0gMCxcblx0XHRcdGRlcHRoUGFja2luZzogbWF0ZXJpYWwuZGVwdGhQYWNraW5nIHx8IDAsXG5cblx0XHRcdGluZGV4MEF0dHJpYnV0ZU5hbWU6IG1hdGVyaWFsLmluZGV4MEF0dHJpYnV0ZU5hbWUsXG5cblx0XHRcdGV4dGVuc2lvbkNsaXBDdWxsRGlzdGFuY2U6IEhBU19FWFRFTlNJT05TICYmIG1hdGVyaWFsLmV4dGVuc2lvbnMuY2xpcEN1bGxEaXN0YW5jZSA9PT0gdHJ1ZSAmJiBleHRlbnNpb25zLmhhcyggJ1dFQkdMX2NsaXBfY3VsbF9kaXN0YW5jZScgKSxcblx0XHRcdGV4dGVuc2lvbk11bHRpRHJhdzogKCBIQVNfRVhURU5TSU9OUyAmJiBtYXRlcmlhbC5leHRlbnNpb25zLm11bHRpRHJhdyA9PT0gdHJ1ZSB8fCBJU19CQVRDSEVETUVTSCApICYmIGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfbXVsdGlfZHJhdycgKSxcblxuXHRcdFx0cmVuZGVyZXJFeHRlbnNpb25QYXJhbGxlbFNoYWRlckNvbXBpbGU6IGV4dGVuc2lvbnMuaGFzKCAnS0hSX3BhcmFsbGVsX3NoYWRlcl9jb21waWxlJyApLFxuXG5cdFx0XHRjdXN0b21Qcm9ncmFtQ2FjaGVLZXk6IG1hdGVyaWFsLmN1c3RvbVByb2dyYW1DYWNoZUtleSgpXG5cblx0XHR9O1xuXG5cdFx0Ly8gdGhlIHVzYWdlIG9mIGdldENoYW5uZWwoKSBkZXRlcm1pbmVzIHRoZSBhY3RpdmUgdGV4dHVyZSBjaGFubmVscyBmb3IgdGhpcyBzaGFkZXJcblxuXHRcdHBhcmFtZXRlcnMudmVydGV4VXYxcyA9IF9hY3RpdmVDaGFubmVscy5oYXMoIDEgKTtcblx0XHRwYXJhbWV0ZXJzLnZlcnRleFV2MnMgPSBfYWN0aXZlQ2hhbm5lbHMuaGFzKCAyICk7XG5cdFx0cGFyYW1ldGVycy52ZXJ0ZXhVdjNzID0gX2FjdGl2ZUNoYW5uZWxzLmhhcyggMyApO1xuXG5cdFx0X2FjdGl2ZUNoYW5uZWxzLmNsZWFyKCk7XG5cblx0XHRyZXR1cm4gcGFyYW1ldGVycztcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0UHJvZ3JhbUNhY2hlS2V5KCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0Y29uc3QgYXJyYXkgPSBbXTtcblxuXHRcdGlmICggcGFyYW1ldGVycy5zaGFkZXJJRCApIHtcblxuXHRcdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zaGFkZXJJRCApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jdXN0b21WZXJ0ZXhTaGFkZXJJRCApO1xuXHRcdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jdXN0b21GcmFnbWVudFNoYWRlcklEICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHBhcmFtZXRlcnMuZGVmaW5lcyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRmb3IgKCBjb25zdCBuYW1lIGluIHBhcmFtZXRlcnMuZGVmaW5lcyApIHtcblxuXHRcdFx0XHRhcnJheS5wdXNoKCBuYW1lICk7XG5cdFx0XHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuZGVmaW5lc1sgbmFtZSBdICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggcGFyYW1ldGVycy5pc1Jhd1NoYWRlck1hdGVyaWFsID09PSBmYWxzZSApIHtcblxuXHRcdFx0Z2V0UHJvZ3JhbUNhY2hlS2V5UGFyYW1ldGVycyggYXJyYXksIHBhcmFtZXRlcnMgKTtcblx0XHRcdGdldFByb2dyYW1DYWNoZUtleUJvb2xlYW5zKCBhcnJheSwgcGFyYW1ldGVycyApO1xuXHRcdFx0YXJyYXkucHVzaCggcmVuZGVyZXIub3V0cHV0Q29sb3JTcGFjZSApO1xuXG5cdFx0fVxuXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jdXN0b21Qcm9ncmFtQ2FjaGVLZXkgKTtcblxuXHRcdHJldHVybiBhcnJheS5qb2luKCk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldFByb2dyYW1DYWNoZUtleVBhcmFtZXRlcnMoIGFycmF5LCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5wcmVjaXNpb24gKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm91dHB1dENvbG9yU3BhY2UgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmVudk1hcE1vZGUgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmVudk1hcEN1YmVVVkhlaWdodCApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmFscGhhTWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmxpZ2h0TWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmFvTWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmJ1bXBNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubm9ybWFsTWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmRpc3BsYWNlbWVudE1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5lbWlzc2l2ZU1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5tZXRhbG5lc3NNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMucm91Z2huZXNzTWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmFuaXNvdHJvcHlNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuY2xlYXJjb2F0TWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLmNsZWFyY29hdE5vcm1hbE1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5jbGVhcmNvYXRSb3VnaG5lc3NNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuc2hlZW5Db2xvck1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zaGVlblJvdWdobmVzc01hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zcGVjdWxhck1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5zcGVjdWxhckNvbG9yTWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnNwZWN1bGFySW50ZW5zaXR5TWFwVXYgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnRyYW5zbWlzc2lvbk1hcFV2ICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy50aGlja25lc3NNYXBVdiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuY29tYmluZSApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuZm9nRXhwMiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuc2l6ZUF0dGVudWF0aW9uICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5tb3JwaFRhcmdldHNDb3VudCApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubW9ycGhBdHRyaWJ1dGVDb3VudCApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtRGlyTGlnaHRzICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5udW1Qb2ludExpZ2h0cyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0cyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtU3BvdExpZ2h0TWFwcyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtSGVtaUxpZ2h0cyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtUmVjdEFyZWFMaWdodHMgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bURpckxpZ2h0U2hhZG93cyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtUG9pbnRMaWdodFNoYWRvd3MgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodFNoYWRvd3MgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLm51bVNwb3RMaWdodFNoYWRvd3NXaXRoTWFwcyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtTGlnaHRQcm9iZXMgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnNoYWRvd01hcFR5cGUgKTtcblx0XHRhcnJheS5wdXNoKCBwYXJhbWV0ZXJzLnRvbmVNYXBwaW5nICk7XG5cdFx0YXJyYXkucHVzaCggcGFyYW1ldGVycy5udW1DbGlwcGluZ1BsYW5lcyApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMubnVtQ2xpcEludGVyc2VjdGlvbiApO1xuXHRcdGFycmF5LnB1c2goIHBhcmFtZXRlcnMuZGVwdGhQYWNraW5nICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldFByb2dyYW1DYWNoZUtleUJvb2xlYW5zKCBhcnJheSwgcGFyYW1ldGVycyApIHtcblxuXHRcdF9wcm9ncmFtTGF5ZXJzLmRpc2FibGVBbGwoKTtcblxuXHRcdGlmICggcGFyYW1ldGVycy5zdXBwb3J0c1ZlcnRleFRleHR1cmVzIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMCApO1xuXHRcdGlmICggcGFyYW1ldGVycy5pbnN0YW5jaW5nIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMSApO1xuXHRcdGlmICggcGFyYW1ldGVycy5pbnN0YW5jaW5nQ29sb3IgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAyICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmluc3RhbmNpbmdNb3JwaCApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDMgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMubWF0Y2FwIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggNCApO1xuXHRcdGlmICggcGFyYW1ldGVycy5lbnZNYXAgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA1ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLm5vcm1hbE1hcE9iamVjdFNwYWNlIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggNiApO1xuXHRcdGlmICggcGFyYW1ldGVycy5ub3JtYWxNYXBUYW5nZW50U3BhY2UgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA3ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmNsZWFyY29hdCApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDggKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuaXJpZGVzY2VuY2UgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA5ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFscGhhVGVzdCApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEwICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleENvbG9ycyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDExICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleEFscGhhcyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEyICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleFV2MXMgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMyApO1xuXHRcdGlmICggcGFyYW1ldGVycy52ZXJ0ZXhVdjJzIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTQgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMudmVydGV4VXYzcyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE1ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnZlcnRleFRhbmdlbnRzIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTYgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuYW5pc290cm9weSApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE3ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFscGhhSGFzaCApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE4ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmJhdGNoaW5nIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggMTkgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuZGlzcGVyc2lvbiApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDIwICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmJhdGNoaW5nQ29sb3IgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAyMSApO1xuXG5cdFx0YXJyYXkucHVzaCggX3Byb2dyYW1MYXllcnMubWFzayApO1xuXHRcdF9wcm9ncmFtTGF5ZXJzLmRpc2FibGVBbGwoKTtcblxuXHRcdGlmICggcGFyYW1ldGVycy5mb2cgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAwICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnVzZUZvZyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDEgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuZmxhdFNoYWRpbmcgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAyICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmxvZ2FyaXRobWljRGVwdGhCdWZmZXIgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAzICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnNraW5uaW5nIClcblx0XHRcdF9wcm9ncmFtTGF5ZXJzLmVuYWJsZSggNCApO1xuXHRcdGlmICggcGFyYW1ldGVycy5tb3JwaFRhcmdldHMgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA1ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLm1vcnBoTm9ybWFscyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDYgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMubW9ycGhDb2xvcnMgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCA3ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnByZW11bHRpcGxpZWRBbHBoYSApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDggKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuc2hhZG93TWFwRW5hYmxlZCApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDkgKTtcblx0XHRpZiAoIHBhcmFtZXRlcnMuZG91YmxlU2lkZWQgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMCApO1xuXHRcdGlmICggcGFyYW1ldGVycy5mbGlwU2lkZWQgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMSApO1xuXHRcdGlmICggcGFyYW1ldGVycy51c2VEZXB0aFBhY2tpbmcgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMiApO1xuXHRcdGlmICggcGFyYW1ldGVycy5kaXRoZXJpbmcgKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxMyApO1xuXHRcdGlmICggcGFyYW1ldGVycy50cmFuc21pc3Npb24gKVxuXHRcdFx0X3Byb2dyYW1MYXllcnMuZW5hYmxlKCAxNCApO1xuXHRcdGlmICggcGFyYW1ldGVycy5zaGVlbiApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE1ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLm9wYXF1ZSApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE2ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLnBvaW50c1V2cyApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE3ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmRlY29kZVZpZGVvVGV4dHVyZSApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE4ICk7XG5cdFx0aWYgKCBwYXJhbWV0ZXJzLmFscGhhVG9Db3ZlcmFnZSApXG5cdFx0XHRfcHJvZ3JhbUxheWVycy5lbmFibGUoIDE5ICk7XG5cblx0XHRhcnJheS5wdXNoKCBfcHJvZ3JhbUxheWVycy5tYXNrICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldFVuaWZvcm1zKCBtYXRlcmlhbCApIHtcblxuXHRcdGNvbnN0IHNoYWRlcklEID0gc2hhZGVySURzWyBtYXRlcmlhbC50eXBlIF07XG5cdFx0bGV0IHVuaWZvcm1zO1xuXG5cdFx0aWYgKCBzaGFkZXJJRCApIHtcblxuXHRcdFx0Y29uc3Qgc2hhZGVyID0gU2hhZGVyTGliWyBzaGFkZXJJRCBdO1xuXHRcdFx0dW5pZm9ybXMgPSBVbmlmb3Jtc1V0aWxzLmNsb25lKCBzaGFkZXIudW5pZm9ybXMgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHVuaWZvcm1zID0gbWF0ZXJpYWwudW5pZm9ybXM7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdW5pZm9ybXM7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGFjcXVpcmVQcm9ncmFtKCBwYXJhbWV0ZXJzLCBjYWNoZUtleSApIHtcblxuXHRcdGxldCBwcm9ncmFtO1xuXG5cdFx0Ly8gQ2hlY2sgaWYgY29kZSBoYXMgYmVlbiBhbHJlYWR5IGNvbXBpbGVkXG5cdFx0Zm9yICggbGV0IHAgPSAwLCBwbCA9IHByb2dyYW1zLmxlbmd0aDsgcCA8IHBsOyBwICsrICkge1xuXG5cdFx0XHRjb25zdCBwcmVleGlzdGluZ1Byb2dyYW0gPSBwcm9ncmFtc1sgcCBdO1xuXG5cdFx0XHRpZiAoIHByZWV4aXN0aW5nUHJvZ3JhbS5jYWNoZUtleSA9PT0gY2FjaGVLZXkgKSB7XG5cblx0XHRcdFx0cHJvZ3JhbSA9IHByZWV4aXN0aW5nUHJvZ3JhbTtcblx0XHRcdFx0KysgcHJvZ3JhbS51c2VkVGltZXM7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggcHJvZ3JhbSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRwcm9ncmFtID0gbmV3IFdlYkdMUHJvZ3JhbSggcmVuZGVyZXIsIGNhY2hlS2V5LCBwYXJhbWV0ZXJzLCBiaW5kaW5nU3RhdGVzICk7XG5cdFx0XHRwcm9ncmFtcy5wdXNoKCBwcm9ncmFtICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcHJvZ3JhbTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVsZWFzZVByb2dyYW0oIHByb2dyYW0gKSB7XG5cblx0XHRpZiAoIC0tIHByb2dyYW0udXNlZFRpbWVzID09PSAwICkge1xuXG5cdFx0XHQvLyBSZW1vdmUgZnJvbSB1bm9yZGVyZWQgc2V0XG5cdFx0XHRjb25zdCBpID0gcHJvZ3JhbXMuaW5kZXhPZiggcHJvZ3JhbSApO1xuXHRcdFx0cHJvZ3JhbXNbIGkgXSA9IHByb2dyYW1zWyBwcm9ncmFtcy5sZW5ndGggLSAxIF07XG5cdFx0XHRwcm9ncmFtcy5wb3AoKTtcblxuXHRcdFx0Ly8gRnJlZSBXZWJHTCByZXNvdXJjZXNcblx0XHRcdHByb2dyYW0uZGVzdHJveSgpO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiByZWxlYXNlU2hhZGVyQ2FjaGUoIG1hdGVyaWFsICkge1xuXG5cdFx0X2N1c3RvbVNoYWRlcnMucmVtb3ZlKCBtYXRlcmlhbCApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xuXG5cdFx0X2N1c3RvbVNoYWRlcnMuZGlzcG9zZSgpO1xuXG5cdH1cblxuXHRyZXR1cm4ge1xuXHRcdGdldFBhcmFtZXRlcnM6IGdldFBhcmFtZXRlcnMsXG5cdFx0Z2V0UHJvZ3JhbUNhY2hlS2V5OiBnZXRQcm9ncmFtQ2FjaGVLZXksXG5cdFx0Z2V0VW5pZm9ybXM6IGdldFVuaWZvcm1zLFxuXHRcdGFjcXVpcmVQcm9ncmFtOiBhY3F1aXJlUHJvZ3JhbSxcblx0XHRyZWxlYXNlUHJvZ3JhbTogcmVsZWFzZVByb2dyYW0sXG5cdFx0cmVsZWFzZVNoYWRlckNhY2hlOiByZWxlYXNlU2hhZGVyQ2FjaGUsXG5cdFx0Ly8gRXhwb3NlZCBmb3IgcmVzb3VyY2UgbW9uaXRvcmluZyAmIGVycm9yIGZlZWRiYWNrIHZpYSByZW5kZXJlci5pbmZvOlxuXHRcdHByb2dyYW1zOiBwcm9ncmFtcyxcblx0XHRkaXNwb3NlOiBkaXNwb3NlXG5cdH07XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xQcm9wZXJ0aWVzKCkge1xuXG5cdGxldCBwcm9wZXJ0aWVzID0gbmV3IFdlYWtNYXAoKTtcblxuXHRmdW5jdGlvbiBnZXQoIG9iamVjdCApIHtcblxuXHRcdGxldCBtYXAgPSBwcm9wZXJ0aWVzLmdldCggb2JqZWN0ICk7XG5cblx0XHRpZiAoIG1hcCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRtYXAgPSB7fTtcblx0XHRcdHByb3BlcnRpZXMuc2V0KCBvYmplY3QsIG1hcCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG1hcDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVtb3ZlKCBvYmplY3QgKSB7XG5cblx0XHRwcm9wZXJ0aWVzLmRlbGV0ZSggb2JqZWN0ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHVwZGF0ZSggb2JqZWN0LCBrZXksIHZhbHVlICkge1xuXG5cdFx0cHJvcGVydGllcy5nZXQoIG9iamVjdCApWyBrZXkgXSA9IHZhbHVlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBkaXNwb3NlKCkge1xuXG5cdFx0cHJvcGVydGllcyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0Z2V0OiBnZXQsXG5cdFx0cmVtb3ZlOiByZW1vdmUsXG5cdFx0dXBkYXRlOiB1cGRhdGUsXG5cdFx0ZGlzcG9zZTogZGlzcG9zZVxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIHBhaW50ZXJTb3J0U3RhYmxlKCBhLCBiICkge1xuXG5cdGlmICggYS5ncm91cE9yZGVyICE9PSBiLmdyb3VwT3JkZXIgKSB7XG5cblx0XHRyZXR1cm4gYS5ncm91cE9yZGVyIC0gYi5ncm91cE9yZGVyO1xuXG5cdH0gZWxzZSBpZiAoIGEucmVuZGVyT3JkZXIgIT09IGIucmVuZGVyT3JkZXIgKSB7XG5cblx0XHRyZXR1cm4gYS5yZW5kZXJPcmRlciAtIGIucmVuZGVyT3JkZXI7XG5cblx0fSBlbHNlIGlmICggYS5tYXRlcmlhbC5pZCAhPT0gYi5tYXRlcmlhbC5pZCApIHtcblxuXHRcdHJldHVybiBhLm1hdGVyaWFsLmlkIC0gYi5tYXRlcmlhbC5pZDtcblxuXHR9IGVsc2UgaWYgKCBhLnogIT09IGIueiApIHtcblxuXHRcdHJldHVybiBhLnogLSBiLno7XG5cblx0fSBlbHNlIHtcblxuXHRcdHJldHVybiBhLmlkIC0gYi5pZDtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gcmV2ZXJzZVBhaW50ZXJTb3J0U3RhYmxlKCBhLCBiICkge1xuXG5cdGlmICggYS5ncm91cE9yZGVyICE9PSBiLmdyb3VwT3JkZXIgKSB7XG5cblx0XHRyZXR1cm4gYS5ncm91cE9yZGVyIC0gYi5ncm91cE9yZGVyO1xuXG5cdH0gZWxzZSBpZiAoIGEucmVuZGVyT3JkZXIgIT09IGIucmVuZGVyT3JkZXIgKSB7XG5cblx0XHRyZXR1cm4gYS5yZW5kZXJPcmRlciAtIGIucmVuZGVyT3JkZXI7XG5cblx0fSBlbHNlIGlmICggYS56ICE9PSBiLnogKSB7XG5cblx0XHRyZXR1cm4gYi56IC0gYS56O1xuXG5cdH0gZWxzZSB7XG5cblx0XHRyZXR1cm4gYS5pZCAtIGIuaWQ7XG5cblx0fVxuXG59XG5cblxuZnVuY3Rpb24gV2ViR0xSZW5kZXJMaXN0KCkge1xuXG5cdGNvbnN0IHJlbmRlckl0ZW1zID0gW107XG5cdGxldCByZW5kZXJJdGVtc0luZGV4ID0gMDtcblxuXHRjb25zdCBvcGFxdWUgPSBbXTtcblx0Y29uc3QgdHJhbnNtaXNzaXZlID0gW107XG5cdGNvbnN0IHRyYW5zcGFyZW50ID0gW107XG5cblx0ZnVuY3Rpb24gaW5pdCgpIHtcblxuXHRcdHJlbmRlckl0ZW1zSW5kZXggPSAwO1xuXG5cdFx0b3BhcXVlLmxlbmd0aCA9IDA7XG5cdFx0dHJhbnNtaXNzaXZlLmxlbmd0aCA9IDA7XG5cdFx0dHJhbnNwYXJlbnQubGVuZ3RoID0gMDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0TmV4dFJlbmRlckl0ZW0oIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApIHtcblxuXHRcdGxldCByZW5kZXJJdGVtID0gcmVuZGVySXRlbXNbIHJlbmRlckl0ZW1zSW5kZXggXTtcblxuXHRcdGlmICggcmVuZGVySXRlbSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRyZW5kZXJJdGVtID0ge1xuXHRcdFx0XHRpZDogb2JqZWN0LmlkLFxuXHRcdFx0XHRvYmplY3Q6IG9iamVjdCxcblx0XHRcdFx0Z2VvbWV0cnk6IGdlb21ldHJ5LFxuXHRcdFx0XHRtYXRlcmlhbDogbWF0ZXJpYWwsXG5cdFx0XHRcdGdyb3VwT3JkZXI6IGdyb3VwT3JkZXIsXG5cdFx0XHRcdHJlbmRlck9yZGVyOiBvYmplY3QucmVuZGVyT3JkZXIsXG5cdFx0XHRcdHo6IHosXG5cdFx0XHRcdGdyb3VwOiBncm91cFxuXHRcdFx0fTtcblxuXHRcdFx0cmVuZGVySXRlbXNbIHJlbmRlckl0ZW1zSW5kZXggXSA9IHJlbmRlckl0ZW07XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRyZW5kZXJJdGVtLmlkID0gb2JqZWN0LmlkO1xuXHRcdFx0cmVuZGVySXRlbS5vYmplY3QgPSBvYmplY3Q7XG5cdFx0XHRyZW5kZXJJdGVtLmdlb21ldHJ5ID0gZ2VvbWV0cnk7XG5cdFx0XHRyZW5kZXJJdGVtLm1hdGVyaWFsID0gbWF0ZXJpYWw7XG5cdFx0XHRyZW5kZXJJdGVtLmdyb3VwT3JkZXIgPSBncm91cE9yZGVyO1xuXHRcdFx0cmVuZGVySXRlbS5yZW5kZXJPcmRlciA9IG9iamVjdC5yZW5kZXJPcmRlcjtcblx0XHRcdHJlbmRlckl0ZW0ueiA9IHo7XG5cdFx0XHRyZW5kZXJJdGVtLmdyb3VwID0gZ3JvdXA7XG5cblx0XHR9XG5cblx0XHRyZW5kZXJJdGVtc0luZGV4ICsrO1xuXG5cdFx0cmV0dXJuIHJlbmRlckl0ZW07XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHB1c2goIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApIHtcblxuXHRcdGNvbnN0IHJlbmRlckl0ZW0gPSBnZXROZXh0UmVuZGVySXRlbSggb2JqZWN0LCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwT3JkZXIsIHosIGdyb3VwICk7XG5cblx0XHRpZiAoIG1hdGVyaWFsLnRyYW5zbWlzc2lvbiA+IDAuMCApIHtcblxuXHRcdFx0dHJhbnNtaXNzaXZlLnB1c2goIHJlbmRlckl0ZW0gKTtcblxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLnRyYW5zcGFyZW50ID09PSB0cnVlICkge1xuXG5cdFx0XHR0cmFuc3BhcmVudC5wdXNoKCByZW5kZXJJdGVtICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRvcGFxdWUucHVzaCggcmVuZGVySXRlbSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB1bnNoaWZ0KCBvYmplY3QsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXBPcmRlciwgeiwgZ3JvdXAgKSB7XG5cblx0XHRjb25zdCByZW5kZXJJdGVtID0gZ2V0TmV4dFJlbmRlckl0ZW0oIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCB6LCBncm91cCApO1xuXG5cdFx0aWYgKCBtYXRlcmlhbC50cmFuc21pc3Npb24gPiAwLjAgKSB7XG5cblx0XHRcdHRyYW5zbWlzc2l2ZS51bnNoaWZ0KCByZW5kZXJJdGVtICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC50cmFuc3BhcmVudCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0dHJhbnNwYXJlbnQudW5zaGlmdCggcmVuZGVySXRlbSApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0b3BhcXVlLnVuc2hpZnQoIHJlbmRlckl0ZW0gKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gc29ydCggY3VzdG9tT3BhcXVlU29ydCwgY3VzdG9tVHJhbnNwYXJlbnRTb3J0ICkge1xuXG5cdFx0aWYgKCBvcGFxdWUubGVuZ3RoID4gMSApIG9wYXF1ZS5zb3J0KCBjdXN0b21PcGFxdWVTb3J0IHx8IHBhaW50ZXJTb3J0U3RhYmxlICk7XG5cdFx0aWYgKCB0cmFuc21pc3NpdmUubGVuZ3RoID4gMSApIHRyYW5zbWlzc2l2ZS5zb3J0KCBjdXN0b21UcmFuc3BhcmVudFNvcnQgfHwgcmV2ZXJzZVBhaW50ZXJTb3J0U3RhYmxlICk7XG5cdFx0aWYgKCB0cmFuc3BhcmVudC5sZW5ndGggPiAxICkgdHJhbnNwYXJlbnQuc29ydCggY3VzdG9tVHJhbnNwYXJlbnRTb3J0IHx8IHJldmVyc2VQYWludGVyU29ydFN0YWJsZSApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBmaW5pc2goKSB7XG5cblx0XHQvLyBDbGVhciByZWZlcmVuY2VzIGZyb20gaW5hY3RpdmUgcmVuZGVySXRlbXMgaW4gdGhlIGxpc3RcblxuXHRcdGZvciAoIGxldCBpID0gcmVuZGVySXRlbXNJbmRleCwgaWwgPSByZW5kZXJJdGVtcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgcmVuZGVySXRlbSA9IHJlbmRlckl0ZW1zWyBpIF07XG5cblx0XHRcdGlmICggcmVuZGVySXRlbS5pZCA9PT0gbnVsbCApIGJyZWFrO1xuXG5cdFx0XHRyZW5kZXJJdGVtLmlkID0gbnVsbDtcblx0XHRcdHJlbmRlckl0ZW0ub2JqZWN0ID0gbnVsbDtcblx0XHRcdHJlbmRlckl0ZW0uZ2VvbWV0cnkgPSBudWxsO1xuXHRcdFx0cmVuZGVySXRlbS5tYXRlcmlhbCA9IG51bGw7XG5cdFx0XHRyZW5kZXJJdGVtLmdyb3VwID0gbnVsbDtcblxuXHRcdH1cblxuXHR9XG5cblx0cmV0dXJuIHtcblxuXHRcdG9wYXF1ZTogb3BhcXVlLFxuXHRcdHRyYW5zbWlzc2l2ZTogdHJhbnNtaXNzaXZlLFxuXHRcdHRyYW5zcGFyZW50OiB0cmFuc3BhcmVudCxcblxuXHRcdGluaXQ6IGluaXQsXG5cdFx0cHVzaDogcHVzaCxcblx0XHR1bnNoaWZ0OiB1bnNoaWZ0LFxuXHRcdGZpbmlzaDogZmluaXNoLFxuXG5cdFx0c29ydDogc29ydFxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMUmVuZGVyTGlzdHMoKSB7XG5cblx0bGV0IGxpc3RzID0gbmV3IFdlYWtNYXAoKTtcblxuXHRmdW5jdGlvbiBnZXQoIHNjZW5lLCByZW5kZXJDYWxsRGVwdGggKSB7XG5cblx0XHRjb25zdCBsaXN0QXJyYXkgPSBsaXN0cy5nZXQoIHNjZW5lICk7XG5cdFx0bGV0IGxpc3Q7XG5cblx0XHRpZiAoIGxpc3RBcnJheSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRsaXN0ID0gbmV3IFdlYkdMUmVuZGVyTGlzdCgpO1xuXHRcdFx0bGlzdHMuc2V0KCBzY2VuZSwgWyBsaXN0IF0gKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGlmICggcmVuZGVyQ2FsbERlcHRoID49IGxpc3RBcnJheS5sZW5ndGggKSB7XG5cblx0XHRcdFx0bGlzdCA9IG5ldyBXZWJHTFJlbmRlckxpc3QoKTtcblx0XHRcdFx0bGlzdEFycmF5LnB1c2goIGxpc3QgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRsaXN0ID0gbGlzdEFycmF5WyByZW5kZXJDYWxsRGVwdGggXTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGxpc3Q7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG5cblx0XHRsaXN0cyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0Z2V0OiBnZXQsXG5cdFx0ZGlzcG9zZTogZGlzcG9zZVxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFVuaWZvcm1zQ2FjaGUoKSB7XG5cblx0Y29uc3QgbGlnaHRzID0ge307XG5cblx0cmV0dXJuIHtcblxuXHRcdGdldDogZnVuY3Rpb24gKCBsaWdodCApIHtcblxuXHRcdFx0aWYgKCBsaWdodHNbIGxpZ2h0LmlkIF0gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRyZXR1cm4gbGlnaHRzWyBsaWdodC5pZCBdO1xuXG5cdFx0XHR9XG5cblx0XHRcdGxldCB1bmlmb3JtcztcblxuXHRcdFx0c3dpdGNoICggbGlnaHQudHlwZSApIHtcblxuXHRcdFx0XHRjYXNlICdEaXJlY3Rpb25hbExpZ2h0Jzpcblx0XHRcdFx0XHR1bmlmb3JtcyA9IHtcblx0XHRcdFx0XHRcdGRpcmVjdGlvbjogbmV3IFZlY3RvcjMoKSxcblx0XHRcdFx0XHRcdGNvbG9yOiBuZXcgQ29sb3IoKVxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAnU3BvdExpZ2h0Jzpcblx0XHRcdFx0XHR1bmlmb3JtcyA9IHtcblx0XHRcdFx0XHRcdHBvc2l0aW9uOiBuZXcgVmVjdG9yMygpLFxuXHRcdFx0XHRcdFx0ZGlyZWN0aW9uOiBuZXcgVmVjdG9yMygpLFxuXHRcdFx0XHRcdFx0Y29sb3I6IG5ldyBDb2xvcigpLFxuXHRcdFx0XHRcdFx0ZGlzdGFuY2U6IDAsXG5cdFx0XHRcdFx0XHRjb25lQ29zOiAwLFxuXHRcdFx0XHRcdFx0cGVudW1icmFDb3M6IDAsXG5cdFx0XHRcdFx0XHRkZWNheTogMFxuXHRcdFx0XHRcdH07XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAnUG9pbnRMaWdodCc6XG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XG5cdFx0XHRcdFx0XHRwb3NpdGlvbjogbmV3IFZlY3RvcjMoKSxcblx0XHRcdFx0XHRcdGNvbG9yOiBuZXcgQ29sb3IoKSxcblx0XHRcdFx0XHRcdGRpc3RhbmNlOiAwLFxuXHRcdFx0XHRcdFx0ZGVjYXk6IDBcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgJ0hlbWlzcGhlcmVMaWdodCc6XG5cdFx0XHRcdFx0dW5pZm9ybXMgPSB7XG5cdFx0XHRcdFx0XHRkaXJlY3Rpb246IG5ldyBWZWN0b3IzKCksXG5cdFx0XHRcdFx0XHRza3lDb2xvcjogbmV3IENvbG9yKCksXG5cdFx0XHRcdFx0XHRncm91bmRDb2xvcjogbmV3IENvbG9yKClcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgJ1JlY3RBcmVhTGlnaHQnOlxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xuXHRcdFx0XHRcdFx0Y29sb3I6IG5ldyBDb2xvcigpLFxuXHRcdFx0XHRcdFx0cG9zaXRpb246IG5ldyBWZWN0b3IzKCksXG5cdFx0XHRcdFx0XHRoYWxmV2lkdGg6IG5ldyBWZWN0b3IzKCksXG5cdFx0XHRcdFx0XHRoYWxmSGVpZ2h0OiBuZXcgVmVjdG9yMygpXG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0fVxuXG5cdFx0XHRsaWdodHNbIGxpZ2h0LmlkIF0gPSB1bmlmb3JtcztcblxuXHRcdFx0cmV0dXJuIHVuaWZvcm1zO1xuXG5cdFx0fVxuXG5cdH07XG5cbn1cblxuZnVuY3Rpb24gU2hhZG93VW5pZm9ybXNDYWNoZSgpIHtcblxuXHRjb25zdCBsaWdodHMgPSB7fTtcblxuXHRyZXR1cm4ge1xuXG5cdFx0Z2V0OiBmdW5jdGlvbiAoIGxpZ2h0ICkge1xuXG5cdFx0XHRpZiAoIGxpZ2h0c1sgbGlnaHQuaWQgXSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHJldHVybiBsaWdodHNbIGxpZ2h0LmlkIF07XG5cblx0XHRcdH1cblxuXHRcdFx0bGV0IHVuaWZvcm1zO1xuXG5cdFx0XHRzd2l0Y2ggKCBsaWdodC50eXBlICkge1xuXG5cdFx0XHRcdGNhc2UgJ0RpcmVjdGlvbmFsTGlnaHQnOlxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xuXHRcdFx0XHRcdFx0c2hhZG93SW50ZW5zaXR5OiAxLFxuXHRcdFx0XHRcdFx0c2hhZG93QmlhczogMCxcblx0XHRcdFx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IDAsXG5cdFx0XHRcdFx0XHRzaGFkb3dSYWRpdXM6IDEsXG5cdFx0XHRcdFx0XHRzaGFkb3dNYXBTaXplOiBuZXcgVmVjdG9yMigpXG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlICdTcG90TGlnaHQnOlxuXHRcdFx0XHRcdHVuaWZvcm1zID0ge1xuXHRcdFx0XHRcdFx0c2hhZG93SW50ZW5zaXR5OiAxLFxuXHRcdFx0XHRcdFx0c2hhZG93QmlhczogMCxcblx0XHRcdFx0XHRcdHNoYWRvd05vcm1hbEJpYXM6IDAsXG5cdFx0XHRcdFx0XHRzaGFkb3dSYWRpdXM6IDEsXG5cdFx0XHRcdFx0XHRzaGFkb3dNYXBTaXplOiBuZXcgVmVjdG9yMigpXG5cdFx0XHRcdFx0fTtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlICdQb2ludExpZ2h0Jzpcblx0XHRcdFx0XHR1bmlmb3JtcyA9IHtcblx0XHRcdFx0XHRcdHNoYWRvd0ludGVuc2l0eTogMSxcblx0XHRcdFx0XHRcdHNoYWRvd0JpYXM6IDAsXG5cdFx0XHRcdFx0XHRzaGFkb3dOb3JtYWxCaWFzOiAwLFxuXHRcdFx0XHRcdFx0c2hhZG93UmFkaXVzOiAxLFxuXHRcdFx0XHRcdFx0c2hhZG93TWFwU2l6ZTogbmV3IFZlY3RvcjIoKSxcblx0XHRcdFx0XHRcdHNoYWRvd0NhbWVyYU5lYXI6IDEsXG5cdFx0XHRcdFx0XHRzaGFkb3dDYW1lcmFGYXI6IDEwMDBcblx0XHRcdFx0XHR9O1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdC8vIFRPRE8gKGFiZWxuYXRpb24pOiBzZXQgUmVjdEFyZWFMaWdodCBzaGFkb3cgdW5pZm9ybXNcblxuXHRcdFx0fVxuXG5cdFx0XHRsaWdodHNbIGxpZ2h0LmlkIF0gPSB1bmlmb3JtcztcblxuXHRcdFx0cmV0dXJuIHVuaWZvcm1zO1xuXG5cdFx0fVxuXG5cdH07XG5cbn1cblxuXG5cbmxldCBuZXh0VmVyc2lvbiA9IDA7XG5cbmZ1bmN0aW9uIHNoYWRvd0Nhc3RpbmdBbmRUZXh0dXJpbmdMaWdodHNGaXJzdCggbGlnaHRBLCBsaWdodEIgKSB7XG5cblx0cmV0dXJuICggbGlnaHRCLmNhc3RTaGFkb3cgPyAyIDogMCApIC0gKCBsaWdodEEuY2FzdFNoYWRvdyA/IDIgOiAwICkgKyAoIGxpZ2h0Qi5tYXAgPyAxIDogMCApIC0gKCBsaWdodEEubWFwID8gMSA6IDAgKTtcblxufVxuXG5mdW5jdGlvbiBXZWJHTExpZ2h0cyggZXh0ZW5zaW9ucyApIHtcblxuXHRjb25zdCBjYWNoZSA9IG5ldyBVbmlmb3Jtc0NhY2hlKCk7XG5cblx0Y29uc3Qgc2hhZG93Q2FjaGUgPSBTaGFkb3dVbmlmb3Jtc0NhY2hlKCk7XG5cblx0Y29uc3Qgc3RhdGUgPSB7XG5cblx0XHR2ZXJzaW9uOiAwLFxuXG5cdFx0aGFzaDoge1xuXHRcdFx0ZGlyZWN0aW9uYWxMZW5ndGg6IC0gMSxcblx0XHRcdHBvaW50TGVuZ3RoOiAtIDEsXG5cdFx0XHRzcG90TGVuZ3RoOiAtIDEsXG5cdFx0XHRyZWN0QXJlYUxlbmd0aDogLSAxLFxuXHRcdFx0aGVtaUxlbmd0aDogLSAxLFxuXG5cdFx0XHRudW1EaXJlY3Rpb25hbFNoYWRvd3M6IC0gMSxcblx0XHRcdG51bVBvaW50U2hhZG93czogLSAxLFxuXHRcdFx0bnVtU3BvdFNoYWRvd3M6IC0gMSxcblx0XHRcdG51bVNwb3RNYXBzOiAtIDEsXG5cblx0XHRcdG51bUxpZ2h0UHJvYmVzOiAtIDFcblx0XHR9LFxuXG5cdFx0YW1iaWVudDogWyAwLCAwLCAwIF0sXG5cdFx0cHJvYmU6IFtdLFxuXHRcdGRpcmVjdGlvbmFsOiBbXSxcblx0XHRkaXJlY3Rpb25hbFNoYWRvdzogW10sXG5cdFx0ZGlyZWN0aW9uYWxTaGFkb3dNYXA6IFtdLFxuXHRcdGRpcmVjdGlvbmFsU2hhZG93TWF0cml4OiBbXSxcblx0XHRzcG90OiBbXSxcblx0XHRzcG90TGlnaHRNYXA6IFtdLFxuXHRcdHNwb3RTaGFkb3c6IFtdLFxuXHRcdHNwb3RTaGFkb3dNYXA6IFtdLFxuXHRcdHNwb3RMaWdodE1hdHJpeDogW10sXG5cdFx0cmVjdEFyZWE6IFtdLFxuXHRcdHJlY3RBcmVhTFRDMTogbnVsbCxcblx0XHRyZWN0QXJlYUxUQzI6IG51bGwsXG5cdFx0cG9pbnQ6IFtdLFxuXHRcdHBvaW50U2hhZG93OiBbXSxcblx0XHRwb2ludFNoYWRvd01hcDogW10sXG5cdFx0cG9pbnRTaGFkb3dNYXRyaXg6IFtdLFxuXHRcdGhlbWk6IFtdLFxuXHRcdG51bVNwb3RMaWdodFNoYWRvd3NXaXRoTWFwczogMCxcblx0XHRudW1MaWdodFByb2JlczogMFxuXG5cdH07XG5cblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHN0YXRlLnByb2JlLnB1c2goIG5ldyBWZWN0b3IzKCkgKTtcblxuXHRjb25zdCB2ZWN0b3IzID0gbmV3IFZlY3RvcjMoKTtcblx0Y29uc3QgbWF0cml4NCA9IG5ldyBNYXRyaXg0KCk7XG5cdGNvbnN0IG1hdHJpeDQyID0gbmV3IE1hdHJpeDQoKTtcblxuXHRmdW5jdGlvbiBzZXR1cCggbGlnaHRzICkge1xuXG5cdFx0bGV0IHIgPSAwLCBnID0gMCwgYiA9IDA7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkgc3RhdGUucHJvYmVbIGkgXS5zZXQoIDAsIDAsIDAgKTtcblxuXHRcdGxldCBkaXJlY3Rpb25hbExlbmd0aCA9IDA7XG5cdFx0bGV0IHBvaW50TGVuZ3RoID0gMDtcblx0XHRsZXQgc3BvdExlbmd0aCA9IDA7XG5cdFx0bGV0IHJlY3RBcmVhTGVuZ3RoID0gMDtcblx0XHRsZXQgaGVtaUxlbmd0aCA9IDA7XG5cblx0XHRsZXQgbnVtRGlyZWN0aW9uYWxTaGFkb3dzID0gMDtcblx0XHRsZXQgbnVtUG9pbnRTaGFkb3dzID0gMDtcblx0XHRsZXQgbnVtU3BvdFNoYWRvd3MgPSAwO1xuXHRcdGxldCBudW1TcG90TWFwcyA9IDA7XG5cdFx0bGV0IG51bVNwb3RTaGFkb3dzV2l0aE1hcHMgPSAwO1xuXG5cdFx0bGV0IG51bUxpZ2h0UHJvYmVzID0gMDtcblxuXHRcdC8vIG9yZGVyaW5nIDogW3NoYWRvdyBjYXN0aW5nICsgbWFwIHRleHR1cmluZywgbWFwIHRleHR1cmluZywgc2hhZG93IGNhc3RpbmcsIG5vbmUgXVxuXHRcdGxpZ2h0cy5zb3J0KCBzaGFkb3dDYXN0aW5nQW5kVGV4dHVyaW5nTGlnaHRzRmlyc3QgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGxpZ2h0cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBsaWdodCA9IGxpZ2h0c1sgaSBdO1xuXG5cdFx0XHRjb25zdCBjb2xvciA9IGxpZ2h0LmNvbG9yO1xuXHRcdFx0Y29uc3QgaW50ZW5zaXR5ID0gbGlnaHQuaW50ZW5zaXR5O1xuXHRcdFx0Y29uc3QgZGlzdGFuY2UgPSBsaWdodC5kaXN0YW5jZTtcblxuXHRcdFx0Y29uc3Qgc2hhZG93TWFwID0gKCBsaWdodC5zaGFkb3cgJiYgbGlnaHQuc2hhZG93Lm1hcCApID8gbGlnaHQuc2hhZG93Lm1hcC50ZXh0dXJlIDogbnVsbDtcblxuXHRcdFx0aWYgKCBsaWdodC5pc0FtYmllbnRMaWdodCApIHtcblxuXHRcdFx0XHRyICs9IGNvbG9yLnIgKiBpbnRlbnNpdHk7XG5cdFx0XHRcdGcgKz0gY29sb3IuZyAqIGludGVuc2l0eTtcblx0XHRcdFx0YiArPSBjb2xvci5iICogaW50ZW5zaXR5O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc0xpZ2h0UHJvYmUgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgOTsgaiArKyApIHtcblxuXHRcdFx0XHRcdHN0YXRlLnByb2JlWyBqIF0uYWRkU2NhbGVkVmVjdG9yKCBsaWdodC5zaC5jb2VmZmljaWVudHNbIGogXSwgaW50ZW5zaXR5ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdG51bUxpZ2h0UHJvYmVzICsrO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBsaWdodC5pc0RpcmVjdGlvbmFsTGlnaHQgKSB7XG5cblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBjYWNoZS5nZXQoIGxpZ2h0ICk7XG5cblx0XHRcdFx0dW5pZm9ybXMuY29sb3IuY29weSggbGlnaHQuY29sb3IgKS5tdWx0aXBseVNjYWxhciggbGlnaHQuaW50ZW5zaXR5ICk7XG5cblx0XHRcdFx0aWYgKCBsaWdodC5jYXN0U2hhZG93ICkge1xuXG5cdFx0XHRcdFx0Y29uc3Qgc2hhZG93ID0gbGlnaHQuc2hhZG93O1xuXG5cdFx0XHRcdFx0Y29uc3Qgc2hhZG93VW5pZm9ybXMgPSBzaGFkb3dDYWNoZS5nZXQoIGxpZ2h0ICk7XG5cblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dJbnRlbnNpdHkgPSBzaGFkb3cuaW50ZW5zaXR5O1xuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0JpYXMgPSBzaGFkb3cuYmlhcztcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dOb3JtYWxCaWFzID0gc2hhZG93Lm5vcm1hbEJpYXM7XG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93UmFkaXVzID0gc2hhZG93LnJhZGl1cztcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dNYXBTaXplID0gc2hhZG93Lm1hcFNpemU7XG5cblx0XHRcdFx0XHRzdGF0ZS5kaXJlY3Rpb25hbFNoYWRvd1sgZGlyZWN0aW9uYWxMZW5ndGggXSA9IHNoYWRvd1VuaWZvcm1zO1xuXHRcdFx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWFwWyBkaXJlY3Rpb25hbExlbmd0aCBdID0gc2hhZG93TWFwO1xuXHRcdFx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsU2hhZG93TWF0cml4WyBkaXJlY3Rpb25hbExlbmd0aCBdID0gbGlnaHQuc2hhZG93Lm1hdHJpeDtcblxuXHRcdFx0XHRcdG51bURpcmVjdGlvbmFsU2hhZG93cyArKztcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0c3RhdGUuZGlyZWN0aW9uYWxbIGRpcmVjdGlvbmFsTGVuZ3RoIF0gPSB1bmlmb3JtcztcblxuXHRcdFx0XHRkaXJlY3Rpb25hbExlbmd0aCArKztcblxuXHRcdFx0fSBlbHNlIGlmICggbGlnaHQuaXNTcG90TGlnaHQgKSB7XG5cblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBjYWNoZS5nZXQoIGxpZ2h0ICk7XG5cblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xuXG5cdFx0XHRcdHVuaWZvcm1zLmNvbG9yLmNvcHkoIGNvbG9yICkubXVsdGlwbHlTY2FsYXIoIGludGVuc2l0eSApO1xuXHRcdFx0XHR1bmlmb3Jtcy5kaXN0YW5jZSA9IGRpc3RhbmNlO1xuXG5cdFx0XHRcdHVuaWZvcm1zLmNvbmVDb3MgPSBNYXRoLmNvcyggbGlnaHQuYW5nbGUgKTtcblx0XHRcdFx0dW5pZm9ybXMucGVudW1icmFDb3MgPSBNYXRoLmNvcyggbGlnaHQuYW5nbGUgKiAoIDEgLSBsaWdodC5wZW51bWJyYSApICk7XG5cdFx0XHRcdHVuaWZvcm1zLmRlY2F5ID0gbGlnaHQuZGVjYXk7XG5cblx0XHRcdFx0c3RhdGUuc3BvdFsgc3BvdExlbmd0aCBdID0gdW5pZm9ybXM7XG5cblx0XHRcdFx0Y29uc3Qgc2hhZG93ID0gbGlnaHQuc2hhZG93O1xuXG5cdFx0XHRcdGlmICggbGlnaHQubWFwICkge1xuXG5cdFx0XHRcdFx0c3RhdGUuc3BvdExpZ2h0TWFwWyBudW1TcG90TWFwcyBdID0gbGlnaHQubWFwO1xuXHRcdFx0XHRcdG51bVNwb3RNYXBzICsrO1xuXG5cdFx0XHRcdFx0Ly8gbWFrZSBzdXJlIHRoZSBsaWdodE1hdHJpeCBpcyB1cCB0byBkYXRlXG5cdFx0XHRcdFx0Ly8gVE9ETyA6IGRvIGl0IGlmIHJlcXVpcmVkIG9ubHlcblx0XHRcdFx0XHRzaGFkb3cudXBkYXRlTWF0cmljZXMoIGxpZ2h0ICk7XG5cblx0XHRcdFx0XHRpZiAoIGxpZ2h0LmNhc3RTaGFkb3cgKSBudW1TcG90U2hhZG93c1dpdGhNYXBzICsrO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXRyaXhbIHNwb3RMZW5ndGggXSA9IHNoYWRvdy5tYXRyaXg7XG5cblx0XHRcdFx0aWYgKCBsaWdodC5jYXN0U2hhZG93ICkge1xuXG5cdFx0XHRcdFx0Y29uc3Qgc2hhZG93VW5pZm9ybXMgPSBzaGFkb3dDYWNoZS5nZXQoIGxpZ2h0ICk7XG5cblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dJbnRlbnNpdHkgPSBzaGFkb3cuaW50ZW5zaXR5O1xuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0JpYXMgPSBzaGFkb3cuYmlhcztcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dOb3JtYWxCaWFzID0gc2hhZG93Lm5vcm1hbEJpYXM7XG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93UmFkaXVzID0gc2hhZG93LnJhZGl1cztcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dNYXBTaXplID0gc2hhZG93Lm1hcFNpemU7XG5cblx0XHRcdFx0XHRzdGF0ZS5zcG90U2hhZG93WyBzcG90TGVuZ3RoIF0gPSBzaGFkb3dVbmlmb3Jtcztcblx0XHRcdFx0XHRzdGF0ZS5zcG90U2hhZG93TWFwWyBzcG90TGVuZ3RoIF0gPSBzaGFkb3dNYXA7XG5cblx0XHRcdFx0XHRudW1TcG90U2hhZG93cyArKztcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0c3BvdExlbmd0aCArKztcblxuXHRcdFx0fSBlbHNlIGlmICggbGlnaHQuaXNSZWN0QXJlYUxpZ2h0ICkge1xuXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gY2FjaGUuZ2V0KCBsaWdodCApO1xuXG5cdFx0XHRcdHVuaWZvcm1zLmNvbG9yLmNvcHkoIGNvbG9yICkubXVsdGlwbHlTY2FsYXIoIGludGVuc2l0eSApO1xuXG5cdFx0XHRcdHVuaWZvcm1zLmhhbGZXaWR0aC5zZXQoIGxpZ2h0LndpZHRoICogMC41LCAwLjAsIDAuMCApO1xuXHRcdFx0XHR1bmlmb3Jtcy5oYWxmSGVpZ2h0LnNldCggMC4wLCBsaWdodC5oZWlnaHQgKiAwLjUsIDAuMCApO1xuXG5cdFx0XHRcdHN0YXRlLnJlY3RBcmVhWyByZWN0QXJlYUxlbmd0aCBdID0gdW5pZm9ybXM7XG5cblx0XHRcdFx0cmVjdEFyZWFMZW5ndGggKys7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzUG9pbnRMaWdodCApIHtcblxuXHRcdFx0XHRjb25zdCB1bmlmb3JtcyA9IGNhY2hlLmdldCggbGlnaHQgKTtcblxuXHRcdFx0XHR1bmlmb3Jtcy5jb2xvci5jb3B5KCBsaWdodC5jb2xvciApLm11bHRpcGx5U2NhbGFyKCBsaWdodC5pbnRlbnNpdHkgKTtcblx0XHRcdFx0dW5pZm9ybXMuZGlzdGFuY2UgPSBsaWdodC5kaXN0YW5jZTtcblx0XHRcdFx0dW5pZm9ybXMuZGVjYXkgPSBsaWdodC5kZWNheTtcblxuXHRcdFx0XHRpZiAoIGxpZ2h0LmNhc3RTaGFkb3cgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBzaGFkb3cgPSBsaWdodC5zaGFkb3c7XG5cblx0XHRcdFx0XHRjb25zdCBzaGFkb3dVbmlmb3JtcyA9IHNoYWRvd0NhY2hlLmdldCggbGlnaHQgKTtcblxuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0ludGVuc2l0eSA9IHNoYWRvdy5pbnRlbnNpdHk7XG5cdFx0XHRcdFx0c2hhZG93VW5pZm9ybXMuc2hhZG93QmlhcyA9IHNoYWRvdy5iaWFzO1xuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd05vcm1hbEJpYXMgPSBzaGFkb3cubm9ybWFsQmlhcztcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dSYWRpdXMgPSBzaGFkb3cucmFkaXVzO1xuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd01hcFNpemUgPSBzaGFkb3cubWFwU2l6ZTtcblx0XHRcdFx0XHRzaGFkb3dVbmlmb3Jtcy5zaGFkb3dDYW1lcmFOZWFyID0gc2hhZG93LmNhbWVyYS5uZWFyO1xuXHRcdFx0XHRcdHNoYWRvd1VuaWZvcm1zLnNoYWRvd0NhbWVyYUZhciA9IHNoYWRvdy5jYW1lcmEuZmFyO1xuXG5cdFx0XHRcdFx0c3RhdGUucG9pbnRTaGFkb3dbIHBvaW50TGVuZ3RoIF0gPSBzaGFkb3dVbmlmb3Jtcztcblx0XHRcdFx0XHRzdGF0ZS5wb2ludFNoYWRvd01hcFsgcG9pbnRMZW5ndGggXSA9IHNoYWRvd01hcDtcblx0XHRcdFx0XHRzdGF0ZS5wb2ludFNoYWRvd01hdHJpeFsgcG9pbnRMZW5ndGggXSA9IGxpZ2h0LnNoYWRvdy5tYXRyaXg7XG5cblx0XHRcdFx0XHRudW1Qb2ludFNoYWRvd3MgKys7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHN0YXRlLnBvaW50WyBwb2ludExlbmd0aCBdID0gdW5pZm9ybXM7XG5cblx0XHRcdFx0cG9pbnRMZW5ndGggKys7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzSGVtaXNwaGVyZUxpZ2h0ICkge1xuXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gY2FjaGUuZ2V0KCBsaWdodCApO1xuXG5cdFx0XHRcdHVuaWZvcm1zLnNreUNvbG9yLmNvcHkoIGxpZ2h0LmNvbG9yICkubXVsdGlwbHlTY2FsYXIoIGludGVuc2l0eSApO1xuXHRcdFx0XHR1bmlmb3Jtcy5ncm91bmRDb2xvci5jb3B5KCBsaWdodC5ncm91bmRDb2xvciApLm11bHRpcGx5U2NhbGFyKCBpbnRlbnNpdHkgKTtcblxuXHRcdFx0XHRzdGF0ZS5oZW1pWyBoZW1pTGVuZ3RoIF0gPSB1bmlmb3JtcztcblxuXHRcdFx0XHRoZW1pTGVuZ3RoICsrO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIHJlY3RBcmVhTGVuZ3RoID4gMCApIHtcblxuXHRcdFx0aWYgKCBleHRlbnNpb25zLmhhcyggJ09FU190ZXh0dXJlX2Zsb2F0X2xpbmVhcicgKSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRzdGF0ZS5yZWN0QXJlYUxUQzEgPSBVbmlmb3Jtc0xpYi5MVENfRkxPQVRfMTtcblx0XHRcdFx0c3RhdGUucmVjdEFyZWFMVEMyID0gVW5pZm9ybXNMaWIuTFRDX0ZMT0FUXzI7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0c3RhdGUucmVjdEFyZWFMVEMxID0gVW5pZm9ybXNMaWIuTFRDX0hBTEZfMTtcblx0XHRcdFx0c3RhdGUucmVjdEFyZWFMVEMyID0gVW5pZm9ybXNMaWIuTFRDX0hBTEZfMjtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0c3RhdGUuYW1iaWVudFsgMCBdID0gcjtcblx0XHRzdGF0ZS5hbWJpZW50WyAxIF0gPSBnO1xuXHRcdHN0YXRlLmFtYmllbnRbIDIgXSA9IGI7XG5cblx0XHRjb25zdCBoYXNoID0gc3RhdGUuaGFzaDtcblxuXHRcdGlmICggaGFzaC5kaXJlY3Rpb25hbExlbmd0aCAhPT0gZGlyZWN0aW9uYWxMZW5ndGggfHxcblx0XHRcdGhhc2gucG9pbnRMZW5ndGggIT09IHBvaW50TGVuZ3RoIHx8XG5cdFx0XHRoYXNoLnNwb3RMZW5ndGggIT09IHNwb3RMZW5ndGggfHxcblx0XHRcdGhhc2gucmVjdEFyZWFMZW5ndGggIT09IHJlY3RBcmVhTGVuZ3RoIHx8XG5cdFx0XHRoYXNoLmhlbWlMZW5ndGggIT09IGhlbWlMZW5ndGggfHxcblx0XHRcdGhhc2gubnVtRGlyZWN0aW9uYWxTaGFkb3dzICE9PSBudW1EaXJlY3Rpb25hbFNoYWRvd3MgfHxcblx0XHRcdGhhc2gubnVtUG9pbnRTaGFkb3dzICE9PSBudW1Qb2ludFNoYWRvd3MgfHxcblx0XHRcdGhhc2gubnVtU3BvdFNoYWRvd3MgIT09IG51bVNwb3RTaGFkb3dzIHx8XG5cdFx0XHRoYXNoLm51bVNwb3RNYXBzICE9PSBudW1TcG90TWFwcyB8fFxuXHRcdFx0aGFzaC5udW1MaWdodFByb2JlcyAhPT0gbnVtTGlnaHRQcm9iZXMgKSB7XG5cblx0XHRcdHN0YXRlLmRpcmVjdGlvbmFsLmxlbmd0aCA9IGRpcmVjdGlvbmFsTGVuZ3RoO1xuXHRcdFx0c3RhdGUuc3BvdC5sZW5ndGggPSBzcG90TGVuZ3RoO1xuXHRcdFx0c3RhdGUucmVjdEFyZWEubGVuZ3RoID0gcmVjdEFyZWFMZW5ndGg7XG5cdFx0XHRzdGF0ZS5wb2ludC5sZW5ndGggPSBwb2ludExlbmd0aDtcblx0XHRcdHN0YXRlLmhlbWkubGVuZ3RoID0gaGVtaUxlbmd0aDtcblxuXHRcdFx0c3RhdGUuZGlyZWN0aW9uYWxTaGFkb3cubGVuZ3RoID0gbnVtRGlyZWN0aW9uYWxTaGFkb3dzO1xuXHRcdFx0c3RhdGUuZGlyZWN0aW9uYWxTaGFkb3dNYXAubGVuZ3RoID0gbnVtRGlyZWN0aW9uYWxTaGFkb3dzO1xuXHRcdFx0c3RhdGUucG9pbnRTaGFkb3cubGVuZ3RoID0gbnVtUG9pbnRTaGFkb3dzO1xuXHRcdFx0c3RhdGUucG9pbnRTaGFkb3dNYXAubGVuZ3RoID0gbnVtUG9pbnRTaGFkb3dzO1xuXHRcdFx0c3RhdGUuc3BvdFNoYWRvdy5sZW5ndGggPSBudW1TcG90U2hhZG93cztcblx0XHRcdHN0YXRlLnNwb3RTaGFkb3dNYXAubGVuZ3RoID0gbnVtU3BvdFNoYWRvd3M7XG5cdFx0XHRzdGF0ZS5kaXJlY3Rpb25hbFNoYWRvd01hdHJpeC5sZW5ndGggPSBudW1EaXJlY3Rpb25hbFNoYWRvd3M7XG5cdFx0XHRzdGF0ZS5wb2ludFNoYWRvd01hdHJpeC5sZW5ndGggPSBudW1Qb2ludFNoYWRvd3M7XG5cdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXRyaXgubGVuZ3RoID0gbnVtU3BvdFNoYWRvd3MgKyBudW1TcG90TWFwcyAtIG51bVNwb3RTaGFkb3dzV2l0aE1hcHM7XG5cdFx0XHRzdGF0ZS5zcG90TGlnaHRNYXAubGVuZ3RoID0gbnVtU3BvdE1hcHM7XG5cdFx0XHRzdGF0ZS5udW1TcG90TGlnaHRTaGFkb3dzV2l0aE1hcHMgPSBudW1TcG90U2hhZG93c1dpdGhNYXBzO1xuXHRcdFx0c3RhdGUubnVtTGlnaHRQcm9iZXMgPSBudW1MaWdodFByb2JlcztcblxuXHRcdFx0aGFzaC5kaXJlY3Rpb25hbExlbmd0aCA9IGRpcmVjdGlvbmFsTGVuZ3RoO1xuXHRcdFx0aGFzaC5wb2ludExlbmd0aCA9IHBvaW50TGVuZ3RoO1xuXHRcdFx0aGFzaC5zcG90TGVuZ3RoID0gc3BvdExlbmd0aDtcblx0XHRcdGhhc2gucmVjdEFyZWFMZW5ndGggPSByZWN0QXJlYUxlbmd0aDtcblx0XHRcdGhhc2guaGVtaUxlbmd0aCA9IGhlbWlMZW5ndGg7XG5cblx0XHRcdGhhc2gubnVtRGlyZWN0aW9uYWxTaGFkb3dzID0gbnVtRGlyZWN0aW9uYWxTaGFkb3dzO1xuXHRcdFx0aGFzaC5udW1Qb2ludFNoYWRvd3MgPSBudW1Qb2ludFNoYWRvd3M7XG5cdFx0XHRoYXNoLm51bVNwb3RTaGFkb3dzID0gbnVtU3BvdFNoYWRvd3M7XG5cdFx0XHRoYXNoLm51bVNwb3RNYXBzID0gbnVtU3BvdE1hcHM7XG5cblx0XHRcdGhhc2gubnVtTGlnaHRQcm9iZXMgPSBudW1MaWdodFByb2JlcztcblxuXHRcdFx0c3RhdGUudmVyc2lvbiA9IG5leHRWZXJzaW9uICsrO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBzZXR1cFZpZXcoIGxpZ2h0cywgY2FtZXJhICkge1xuXG5cdFx0bGV0IGRpcmVjdGlvbmFsTGVuZ3RoID0gMDtcblx0XHRsZXQgcG9pbnRMZW5ndGggPSAwO1xuXHRcdGxldCBzcG90TGVuZ3RoID0gMDtcblx0XHRsZXQgcmVjdEFyZWFMZW5ndGggPSAwO1xuXHRcdGxldCBoZW1pTGVuZ3RoID0gMDtcblxuXHRcdGNvbnN0IHZpZXdNYXRyaXggPSBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gbGlnaHRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGxpZ2h0ID0gbGlnaHRzWyBpIF07XG5cblx0XHRcdGlmICggbGlnaHQuaXNEaXJlY3Rpb25hbExpZ2h0ICkge1xuXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gc3RhdGUuZGlyZWN0aW9uYWxbIGRpcmVjdGlvbmFsTGVuZ3RoIF07XG5cblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcblx0XHRcdFx0dmVjdG9yMy5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGxpZ2h0LnRhcmdldC5tYXRyaXhXb3JsZCApO1xuXHRcdFx0XHR1bmlmb3Jtcy5kaXJlY3Rpb24uc3ViKCB2ZWN0b3IzICk7XG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi50cmFuc2Zvcm1EaXJlY3Rpb24oIHZpZXdNYXRyaXggKTtcblxuXHRcdFx0XHRkaXJlY3Rpb25hbExlbmd0aCArKztcblxuXHRcdFx0fSBlbHNlIGlmICggbGlnaHQuaXNTcG90TGlnaHQgKSB7XG5cblx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBzdGF0ZS5zcG90WyBzcG90TGVuZ3RoIF07XG5cblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xuXHRcdFx0XHR1bmlmb3Jtcy5wb3NpdGlvbi5hcHBseU1hdHJpeDQoIHZpZXdNYXRyaXggKTtcblxuXHRcdFx0XHR1bmlmb3Jtcy5kaXJlY3Rpb24uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xuXHRcdFx0XHR2ZWN0b3IzLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQudGFyZ2V0Lm1hdHJpeFdvcmxkICk7XG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi5zdWIoIHZlY3RvcjMgKTtcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uLnRyYW5zZm9ybURpcmVjdGlvbiggdmlld01hdHJpeCApO1xuXG5cdFx0XHRcdHNwb3RMZW5ndGggKys7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzUmVjdEFyZWFMaWdodCApIHtcblxuXHRcdFx0XHRjb25zdCB1bmlmb3JtcyA9IHN0YXRlLnJlY3RBcmVhWyByZWN0QXJlYUxlbmd0aCBdO1xuXG5cdFx0XHRcdHVuaWZvcm1zLnBvc2l0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uYXBwbHlNYXRyaXg0KCB2aWV3TWF0cml4ICk7XG5cblx0XHRcdFx0Ly8gZXh0cmFjdCBsb2NhbCByb3RhdGlvbiBvZiBsaWdodCB0byBkZXJpdmUgd2lkdGgvaGVpZ2h0IGhhbGYgdmVjdG9yc1xuXHRcdFx0XHRtYXRyaXg0Mi5pZGVudGl0eSgpO1xuXHRcdFx0XHRtYXRyaXg0LmNvcHkoIGxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cdFx0XHRcdG1hdHJpeDQucHJlbXVsdGlwbHkoIHZpZXdNYXRyaXggKTtcblx0XHRcdFx0bWF0cml4NDIuZXh0cmFjdFJvdGF0aW9uKCBtYXRyaXg0ICk7XG5cblx0XHRcdFx0dW5pZm9ybXMuaGFsZldpZHRoLnNldCggbGlnaHQud2lkdGggKiAwLjUsIDAuMCwgMC4wICk7XG5cdFx0XHRcdHVuaWZvcm1zLmhhbGZIZWlnaHQuc2V0KCAwLjAsIGxpZ2h0LmhlaWdodCAqIDAuNSwgMC4wICk7XG5cblx0XHRcdFx0dW5pZm9ybXMuaGFsZldpZHRoLmFwcGx5TWF0cml4NCggbWF0cml4NDIgKTtcblx0XHRcdFx0dW5pZm9ybXMuaGFsZkhlaWdodC5hcHBseU1hdHJpeDQoIG1hdHJpeDQyICk7XG5cblx0XHRcdFx0cmVjdEFyZWFMZW5ndGggKys7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzUG9pbnRMaWdodCApIHtcblxuXHRcdFx0XHRjb25zdCB1bmlmb3JtcyA9IHN0YXRlLnBvaW50WyBwb2ludExlbmd0aCBdO1xuXG5cdFx0XHRcdHVuaWZvcm1zLnBvc2l0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggbGlnaHQubWF0cml4V29ybGQgKTtcblx0XHRcdFx0dW5pZm9ybXMucG9zaXRpb24uYXBwbHlNYXRyaXg0KCB2aWV3TWF0cml4ICk7XG5cblx0XHRcdFx0cG9pbnRMZW5ndGggKys7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGxpZ2h0LmlzSGVtaXNwaGVyZUxpZ2h0ICkge1xuXG5cdFx0XHRcdGNvbnN0IHVuaWZvcm1zID0gc3RhdGUuaGVtaVsgaGVtaUxlbmd0aCBdO1xuXG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbi50cmFuc2Zvcm1EaXJlY3Rpb24oIHZpZXdNYXRyaXggKTtcblxuXHRcdFx0XHRoZW1pTGVuZ3RoICsrO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0c2V0dXA6IHNldHVwLFxuXHRcdHNldHVwVmlldzogc2V0dXBWaWV3LFxuXHRcdHN0YXRlOiBzdGF0ZVxuXHR9O1xuXG59XG5cbmZ1bmN0aW9uIFdlYkdMUmVuZGVyU3RhdGUoIGV4dGVuc2lvbnMgKSB7XG5cblx0Y29uc3QgbGlnaHRzID0gbmV3IFdlYkdMTGlnaHRzKCBleHRlbnNpb25zICk7XG5cblx0Y29uc3QgbGlnaHRzQXJyYXkgPSBbXTtcblx0Y29uc3Qgc2hhZG93c0FycmF5ID0gW107XG5cblx0ZnVuY3Rpb24gaW5pdCggY2FtZXJhICkge1xuXG5cdFx0c3RhdGUuY2FtZXJhID0gY2FtZXJhO1xuXG5cdFx0bGlnaHRzQXJyYXkubGVuZ3RoID0gMDtcblx0XHRzaGFkb3dzQXJyYXkubGVuZ3RoID0gMDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gcHVzaExpZ2h0KCBsaWdodCApIHtcblxuXHRcdGxpZ2h0c0FycmF5LnB1c2goIGxpZ2h0ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHB1c2hTaGFkb3coIHNoYWRvd0xpZ2h0ICkge1xuXG5cdFx0c2hhZG93c0FycmF5LnB1c2goIHNoYWRvd0xpZ2h0ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHNldHVwTGlnaHRzKCkge1xuXG5cdFx0bGlnaHRzLnNldHVwKCBsaWdodHNBcnJheSApO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBzZXR1cExpZ2h0c1ZpZXcoIGNhbWVyYSApIHtcblxuXHRcdGxpZ2h0cy5zZXR1cFZpZXcoIGxpZ2h0c0FycmF5LCBjYW1lcmEgKTtcblxuXHR9XG5cblx0Y29uc3Qgc3RhdGUgPSB7XG5cdFx0bGlnaHRzQXJyYXk6IGxpZ2h0c0FycmF5LFxuXHRcdHNoYWRvd3NBcnJheTogc2hhZG93c0FycmF5LFxuXG5cdFx0Y2FtZXJhOiBudWxsLFxuXG5cdFx0bGlnaHRzOiBsaWdodHMsXG5cblx0XHR0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQ6IHt9XG5cdH07XG5cblx0cmV0dXJuIHtcblx0XHRpbml0OiBpbml0LFxuXHRcdHN0YXRlOiBzdGF0ZSxcblx0XHRzZXR1cExpZ2h0czogc2V0dXBMaWdodHMsXG5cdFx0c2V0dXBMaWdodHNWaWV3OiBzZXR1cExpZ2h0c1ZpZXcsXG5cblx0XHRwdXNoTGlnaHQ6IHB1c2hMaWdodCxcblx0XHRwdXNoU2hhZG93OiBwdXNoU2hhZG93XG5cdH07XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xSZW5kZXJTdGF0ZXMoIGV4dGVuc2lvbnMgKSB7XG5cblx0bGV0IHJlbmRlclN0YXRlcyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0ZnVuY3Rpb24gZ2V0KCBzY2VuZSwgcmVuZGVyQ2FsbERlcHRoID0gMCApIHtcblxuXHRcdGNvbnN0IHJlbmRlclN0YXRlQXJyYXkgPSByZW5kZXJTdGF0ZXMuZ2V0KCBzY2VuZSApO1xuXHRcdGxldCByZW5kZXJTdGF0ZTtcblxuXHRcdGlmICggcmVuZGVyU3RhdGVBcnJheSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRyZW5kZXJTdGF0ZSA9IG5ldyBXZWJHTFJlbmRlclN0YXRlKCBleHRlbnNpb25zICk7XG5cdFx0XHRyZW5kZXJTdGF0ZXMuc2V0KCBzY2VuZSwgWyByZW5kZXJTdGF0ZSBdICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIHJlbmRlckNhbGxEZXB0aCA+PSByZW5kZXJTdGF0ZUFycmF5Lmxlbmd0aCApIHtcblxuXHRcdFx0XHRyZW5kZXJTdGF0ZSA9IG5ldyBXZWJHTFJlbmRlclN0YXRlKCBleHRlbnNpb25zICk7XG5cdFx0XHRcdHJlbmRlclN0YXRlQXJyYXkucHVzaCggcmVuZGVyU3RhdGUgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRyZW5kZXJTdGF0ZSA9IHJlbmRlclN0YXRlQXJyYXlbIHJlbmRlckNhbGxEZXB0aCBdO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcmVuZGVyU3RhdGU7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc3Bvc2UoKSB7XG5cblx0XHRyZW5kZXJTdGF0ZXMgPSBuZXcgV2Vha01hcCgpO1xuXG5cdH1cblxuXHRyZXR1cm4ge1xuXHRcdGdldDogZ2V0LFxuXHRcdGRpc3Bvc2U6IGRpc3Bvc2Vcblx0fTtcblxufVxuXG5jbGFzcyBNZXNoRGVwdGhNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTWVzaERlcHRoTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ01lc2hEZXB0aE1hdGVyaWFsJztcblxuXHRcdHRoaXMuZGVwdGhQYWNraW5nID0gQmFzaWNEZXB0aFBhY2tpbmc7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XG5cblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuZGVwdGhQYWNraW5nID0gc291cmNlLmRlcHRoUGFja2luZztcblxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBzb3VyY2UuYWxwaGFNYXA7XG5cblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IHNvdXJjZS5kaXNwbGFjZW1lbnRTY2FsZTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcblxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgTWVzaERpc3RhbmNlTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc01lc2hEaXN0YW5jZU1hdGVyaWFsID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdNZXNoRGlzdGFuY2VNYXRlcmlhbCc7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xuXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xuXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBzb3VyY2UuZGlzcGxhY2VtZW50TWFwO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY29uc3QgdmVydGV4ID0gXCJ2b2lkIG1haW4oKSB7XFxuXFx0Z2xfUG9zaXRpb24gPSB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XFxufVwiO1xuXG5jb25zdCBmcmFnbWVudCA9IFwidW5pZm9ybSBzYW1wbGVyMkQgc2hhZG93X3Bhc3M7XFxudW5pZm9ybSB2ZWMyIHJlc29sdXRpb247XFxudW5pZm9ybSBmbG9hdCByYWRpdXM7XFxuI2luY2x1ZGUgPHBhY2tpbmc+XFxudm9pZCBtYWluKCkge1xcblxcdGNvbnN0IGZsb2F0IHNhbXBsZXMgPSBmbG9hdCggVlNNX1NBTVBMRVMgKTtcXG5cXHRmbG9hdCBtZWFuID0gMC4wO1xcblxcdGZsb2F0IHNxdWFyZWRfbWVhbiA9IDAuMDtcXG5cXHRmbG9hdCB1dlN0cmlkZSA9IHNhbXBsZXMgPD0gMS4wID8gMC4wIDogMi4wIC8gKCBzYW1wbGVzIC0gMS4wICk7XFxuXFx0ZmxvYXQgdXZTdGFydCA9IHNhbXBsZXMgPD0gMS4wID8gMC4wIDogLSAxLjA7XFxuXFx0Zm9yICggZmxvYXQgaSA9IDAuMDsgaSA8IHNhbXBsZXM7IGkgKysgKSB7XFxuXFx0XFx0ZmxvYXQgdXZPZmZzZXQgPSB1dlN0YXJ0ICsgaSAqIHV2U3RyaWRlO1xcblxcdFxcdCNpZmRlZiBIT1JJWk9OVEFMX1BBU1NcXG5cXHRcXHRcXHR2ZWMyIGRpc3RyaWJ1dGlvbiA9IHVucGFja1JHQkFUbzJIYWxmKCB0ZXh0dXJlMkQoIHNoYWRvd19wYXNzLCAoIGdsX0ZyYWdDb29yZC54eSArIHZlYzIoIHV2T2Zmc2V0LCAwLjAgKSAqIHJhZGl1cyApIC8gcmVzb2x1dGlvbiApICk7XFxuXFx0XFx0XFx0bWVhbiArPSBkaXN0cmlidXRpb24ueDtcXG5cXHRcXHRcXHRzcXVhcmVkX21lYW4gKz0gZGlzdHJpYnV0aW9uLnkgKiBkaXN0cmlidXRpb24ueSArIGRpc3RyaWJ1dGlvbi54ICogZGlzdHJpYnV0aW9uLng7XFxuXFx0XFx0I2Vsc2VcXG5cXHRcXHRcXHRmbG9hdCBkZXB0aCA9IHVucGFja1JHQkFUb0RlcHRoKCB0ZXh0dXJlMkQoIHNoYWRvd19wYXNzLCAoIGdsX0ZyYWdDb29yZC54eSArIHZlYzIoIDAuMCwgdXZPZmZzZXQgKSAqIHJhZGl1cyApIC8gcmVzb2x1dGlvbiApICk7XFxuXFx0XFx0XFx0bWVhbiArPSBkZXB0aDtcXG5cXHRcXHRcXHRzcXVhcmVkX21lYW4gKz0gZGVwdGggKiBkZXB0aDtcXG5cXHRcXHQjZW5kaWZcXG5cXHR9XFxuXFx0bWVhbiA9IG1lYW4gLyBzYW1wbGVzO1xcblxcdHNxdWFyZWRfbWVhbiA9IHNxdWFyZWRfbWVhbiAvIHNhbXBsZXM7XFxuXFx0ZmxvYXQgc3RkX2RldiA9IHNxcnQoIHNxdWFyZWRfbWVhbiAtIG1lYW4gKiBtZWFuICk7XFxuXFx0Z2xfRnJhZ0NvbG9yID0gcGFjazJIYWxmVG9SR0JBKCB2ZWMyKCBtZWFuLCBzdGRfZGV2ICkgKTtcXG59XCI7XG5cbmZ1bmN0aW9uIFdlYkdMU2hhZG93TWFwKCByZW5kZXJlciwgb2JqZWN0cywgY2FwYWJpbGl0aWVzICkge1xuXG5cdGxldCBfZnJ1c3R1bSA9IG5ldyBGcnVzdHVtKCk7XG5cblx0Y29uc3QgX3NoYWRvd01hcFNpemUgPSBuZXcgVmVjdG9yMigpLFxuXHRcdF92aWV3cG9ydFNpemUgPSBuZXcgVmVjdG9yMigpLFxuXG5cdFx0X3ZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKSxcblxuXHRcdF9kZXB0aE1hdGVyaWFsID0gbmV3IE1lc2hEZXB0aE1hdGVyaWFsKCB7IGRlcHRoUGFja2luZzogUkdCQURlcHRoUGFja2luZyB9ICksXG5cdFx0X2Rpc3RhbmNlTWF0ZXJpYWwgPSBuZXcgTWVzaERpc3RhbmNlTWF0ZXJpYWwoKSxcblxuXHRcdF9tYXRlcmlhbENhY2hlID0ge30sXG5cblx0XHRfbWF4VGV4dHVyZVNpemUgPSBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemU7XG5cblx0Y29uc3Qgc2hhZG93U2lkZSA9IHsgWyBGcm9udFNpZGUgXTogQmFja1NpZGUsIFsgQmFja1NpZGUgXTogRnJvbnRTaWRlLCBbIERvdWJsZVNpZGUgXTogRG91YmxlU2lkZSB9O1xuXG5cdGNvbnN0IHNoYWRvd01hdGVyaWFsVmVydGljYWwgPSBuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcblx0XHRkZWZpbmVzOiB7XG5cdFx0XHRWU01fU0FNUExFUzogOFxuXHRcdH0sXG5cdFx0dW5pZm9ybXM6IHtcblx0XHRcdHNoYWRvd19wYXNzOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0XHRyZXNvbHV0aW9uOiB7IHZhbHVlOiBuZXcgVmVjdG9yMigpIH0sXG5cdFx0XHRyYWRpdXM6IHsgdmFsdWU6IDQuMCB9XG5cdFx0fSxcblxuXHRcdHZlcnRleFNoYWRlcjogdmVydGV4LFxuXHRcdGZyYWdtZW50U2hhZGVyOiBmcmFnbWVudFxuXG5cdH0gKTtcblxuXHRjb25zdCBzaGFkb3dNYXRlcmlhbEhvcml6b250YWwgPSBzaGFkb3dNYXRlcmlhbFZlcnRpY2FsLmNsb25lKCk7XG5cdHNoYWRvd01hdGVyaWFsSG9yaXpvbnRhbC5kZWZpbmVzLkhPUklaT05UQUxfUEFTUyA9IDE7XG5cblx0Y29uc3QgZnVsbFNjcmVlblRyaSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXHRmdWxsU2NyZWVuVHJpLnNldEF0dHJpYnV0ZShcblx0XHQncG9zaXRpb24nLFxuXHRcdG5ldyBCdWZmZXJBdHRyaWJ1dGUoXG5cdFx0XHRuZXcgRmxvYXQzMkFycmF5KCBbIC0gMSwgLSAxLCAwLjUsIDMsIC0gMSwgMC41LCAtIDEsIDMsIDAuNSBdICksXG5cdFx0XHQzXG5cdFx0KVxuXHQpO1xuXG5cdGNvbnN0IGZ1bGxTY3JlZW5NZXNoID0gbmV3IE1lc2goIGZ1bGxTY3JlZW5UcmksIHNoYWRvd01hdGVyaWFsVmVydGljYWwgKTtcblxuXHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0dGhpcy5lbmFibGVkID0gZmFsc2U7XG5cblx0dGhpcy5hdXRvVXBkYXRlID0gdHJ1ZTtcblx0dGhpcy5uZWVkc1VwZGF0ZSA9IGZhbHNlO1xuXG5cdHRoaXMudHlwZSA9IFBDRlNoYWRvd01hcDtcblx0bGV0IF9wcmV2aW91c1R5cGUgPSB0aGlzLnR5cGU7XG5cblx0dGhpcy5yZW5kZXIgPSBmdW5jdGlvbiAoIGxpZ2h0cywgc2NlbmUsIGNhbWVyYSApIHtcblxuXHRcdGlmICggc2NvcGUuZW5hYmxlZCA9PT0gZmFsc2UgKSByZXR1cm47XG5cdFx0aWYgKCBzY29wZS5hdXRvVXBkYXRlID09PSBmYWxzZSAmJiBzY29wZS5uZWVkc1VwZGF0ZSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHRpZiAoIGxpZ2h0cy5sZW5ndGggPT09IDAgKSByZXR1cm47XG5cblx0XHRjb25zdCBjdXJyZW50UmVuZGVyVGFyZ2V0ID0gcmVuZGVyZXIuZ2V0UmVuZGVyVGFyZ2V0KCk7XG5cdFx0Y29uc3QgYWN0aXZlQ3ViZUZhY2UgPSByZW5kZXJlci5nZXRBY3RpdmVDdWJlRmFjZSgpO1xuXHRcdGNvbnN0IGFjdGl2ZU1pcG1hcExldmVsID0gcmVuZGVyZXIuZ2V0QWN0aXZlTWlwbWFwTGV2ZWwoKTtcblxuXHRcdGNvbnN0IF9zdGF0ZSA9IHJlbmRlcmVyLnN0YXRlO1xuXG5cdFx0Ly8gU2V0IEdMIHN0YXRlIGZvciBkZXB0aCBtYXAuXG5cdFx0X3N0YXRlLnNldEJsZW5kaW5nKCBOb0JsZW5kaW5nICk7XG5cdFx0X3N0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0Q2xlYXIoIDEsIDEsIDEsIDEgKTtcblx0XHRfc3RhdGUuYnVmZmVycy5kZXB0aC5zZXRUZXN0KCB0cnVlICk7XG5cdFx0X3N0YXRlLnNldFNjaXNzb3JUZXN0KCBmYWxzZSApO1xuXG5cdFx0Ly8gY2hlY2sgZm9yIHNoYWRvdyBtYXAgdHlwZSBjaGFuZ2VzXG5cblx0XHRjb25zdCB0b1ZTTSA9ICggX3ByZXZpb3VzVHlwZSAhPT0gVlNNU2hhZG93TWFwICYmIHRoaXMudHlwZSA9PT0gVlNNU2hhZG93TWFwICk7XG5cdFx0Y29uc3QgZnJvbVZTTSA9ICggX3ByZXZpb3VzVHlwZSA9PT0gVlNNU2hhZG93TWFwICYmIHRoaXMudHlwZSAhPT0gVlNNU2hhZG93TWFwICk7XG5cblx0XHQvLyByZW5kZXIgZGVwdGggbWFwXG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbGlnaHRzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBsaWdodCA9IGxpZ2h0c1sgaSBdO1xuXHRcdFx0Y29uc3Qgc2hhZG93ID0gbGlnaHQuc2hhZG93O1xuXG5cdFx0XHRpZiAoIHNoYWRvdyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMU2hhZG93TWFwOicsIGxpZ2h0LCAnaGFzIG5vIHNoYWRvdy4nICk7XG5cdFx0XHRcdGNvbnRpbnVlO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggc2hhZG93LmF1dG9VcGRhdGUgPT09IGZhbHNlICYmIHNoYWRvdy5uZWVkc1VwZGF0ZSA9PT0gZmFsc2UgKSBjb250aW51ZTtcblxuXHRcdFx0X3NoYWRvd01hcFNpemUuY29weSggc2hhZG93Lm1hcFNpemUgKTtcblxuXHRcdFx0Y29uc3Qgc2hhZG93RnJhbWVFeHRlbnRzID0gc2hhZG93LmdldEZyYW1lRXh0ZW50cygpO1xuXG5cdFx0XHRfc2hhZG93TWFwU2l6ZS5tdWx0aXBseSggc2hhZG93RnJhbWVFeHRlbnRzICk7XG5cblx0XHRcdF92aWV3cG9ydFNpemUuY29weSggc2hhZG93Lm1hcFNpemUgKTtcblxuXHRcdFx0aWYgKCBfc2hhZG93TWFwU2l6ZS54ID4gX21heFRleHR1cmVTaXplIHx8IF9zaGFkb3dNYXBTaXplLnkgPiBfbWF4VGV4dHVyZVNpemUgKSB7XG5cblx0XHRcdFx0aWYgKCBfc2hhZG93TWFwU2l6ZS54ID4gX21heFRleHR1cmVTaXplICkge1xuXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS54ID0gTWF0aC5mbG9vciggX21heFRleHR1cmVTaXplIC8gc2hhZG93RnJhbWVFeHRlbnRzLnggKTtcblx0XHRcdFx0XHRfc2hhZG93TWFwU2l6ZS54ID0gX3ZpZXdwb3J0U2l6ZS54ICogc2hhZG93RnJhbWVFeHRlbnRzLng7XG5cdFx0XHRcdFx0c2hhZG93Lm1hcFNpemUueCA9IF92aWV3cG9ydFNpemUueDtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBfc2hhZG93TWFwU2l6ZS55ID4gX21heFRleHR1cmVTaXplICkge1xuXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS55ID0gTWF0aC5mbG9vciggX21heFRleHR1cmVTaXplIC8gc2hhZG93RnJhbWVFeHRlbnRzLnkgKTtcblx0XHRcdFx0XHRfc2hhZG93TWFwU2l6ZS55ID0gX3ZpZXdwb3J0U2l6ZS55ICogc2hhZG93RnJhbWVFeHRlbnRzLnk7XG5cdFx0XHRcdFx0c2hhZG93Lm1hcFNpemUueSA9IF92aWV3cG9ydFNpemUueTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBzaGFkb3cubWFwID09PSBudWxsIHx8IHRvVlNNID09PSB0cnVlIHx8IGZyb21WU00gPT09IHRydWUgKSB7XG5cblx0XHRcdFx0Y29uc3QgcGFycyA9ICggdGhpcy50eXBlICE9PSBWU01TaGFkb3dNYXAgKSA/IHsgbWluRmlsdGVyOiBOZWFyZXN0RmlsdGVyLCBtYWdGaWx0ZXI6IE5lYXJlc3RGaWx0ZXIgfSA6IHt9O1xuXG5cdFx0XHRcdGlmICggc2hhZG93Lm1hcCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdHNoYWRvdy5tYXAuZGlzcG9zZSgpO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzaGFkb3cubWFwID0gbmV3IFdlYkdMUmVuZGVyVGFyZ2V0KCBfc2hhZG93TWFwU2l6ZS54LCBfc2hhZG93TWFwU2l6ZS55LCBwYXJzICk7XG5cdFx0XHRcdHNoYWRvdy5tYXAudGV4dHVyZS5uYW1lID0gbGlnaHQubmFtZSArICcuc2hhZG93TWFwJztcblxuXHRcdFx0XHRzaGFkb3cuY2FtZXJhLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHNoYWRvdy5tYXAgKTtcblx0XHRcdHJlbmRlcmVyLmNsZWFyKCk7XG5cblx0XHRcdGNvbnN0IHZpZXdwb3J0Q291bnQgPSBzaGFkb3cuZ2V0Vmlld3BvcnRDb3VudCgpO1xuXG5cdFx0XHRmb3IgKCBsZXQgdnAgPSAwOyB2cCA8IHZpZXdwb3J0Q291bnQ7IHZwICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHZpZXdwb3J0ID0gc2hhZG93LmdldFZpZXdwb3J0KCB2cCApO1xuXG5cdFx0XHRcdF92aWV3cG9ydC5zZXQoXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS54ICogdmlld3BvcnQueCxcblx0XHRcdFx0XHRfdmlld3BvcnRTaXplLnkgKiB2aWV3cG9ydC55LFxuXHRcdFx0XHRcdF92aWV3cG9ydFNpemUueCAqIHZpZXdwb3J0LnosXG5cdFx0XHRcdFx0X3ZpZXdwb3J0U2l6ZS55ICogdmlld3BvcnQud1xuXHRcdFx0XHQpO1xuXG5cdFx0XHRcdF9zdGF0ZS52aWV3cG9ydCggX3ZpZXdwb3J0ICk7XG5cblx0XHRcdFx0c2hhZG93LnVwZGF0ZU1hdHJpY2VzKCBsaWdodCwgdnAgKTtcblxuXHRcdFx0XHRfZnJ1c3R1bSA9IHNoYWRvdy5nZXRGcnVzdHVtKCk7XG5cblx0XHRcdFx0cmVuZGVyT2JqZWN0KCBzY2VuZSwgY2FtZXJhLCBzaGFkb3cuY2FtZXJhLCBsaWdodCwgdGhpcy50eXBlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gZG8gYmx1ciBwYXNzIGZvciBWU01cblxuXHRcdFx0aWYgKCBzaGFkb3cuaXNQb2ludExpZ2h0U2hhZG93ICE9PSB0cnVlICYmIHRoaXMudHlwZSA9PT0gVlNNU2hhZG93TWFwICkge1xuXG5cdFx0XHRcdFZTTVBhc3MoIHNoYWRvdywgY2FtZXJhICk7XG5cblx0XHRcdH1cblxuXHRcdFx0c2hhZG93Lm5lZWRzVXBkYXRlID0gZmFsc2U7XG5cblx0XHR9XG5cblx0XHRfcHJldmlvdXNUeXBlID0gdGhpcy50eXBlO1xuXG5cdFx0c2NvcGUubmVlZHNVcGRhdGUgPSBmYWxzZTtcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggY3VycmVudFJlbmRlclRhcmdldCwgYWN0aXZlQ3ViZUZhY2UsIGFjdGl2ZU1pcG1hcExldmVsICk7XG5cblx0fTtcblxuXHRmdW5jdGlvbiBWU01QYXNzKCBzaGFkb3csIGNhbWVyYSApIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0cy51cGRhdGUoIGZ1bGxTY3JlZW5NZXNoICk7XG5cblx0XHRpZiAoIHNoYWRvd01hdGVyaWFsVmVydGljYWwuZGVmaW5lcy5WU01fU0FNUExFUyAhPT0gc2hhZG93LmJsdXJTYW1wbGVzICkge1xuXG5cdFx0XHRzaGFkb3dNYXRlcmlhbFZlcnRpY2FsLmRlZmluZXMuVlNNX1NBTVBMRVMgPSBzaGFkb3cuYmx1clNhbXBsZXM7XG5cdFx0XHRzaGFkb3dNYXRlcmlhbEhvcml6b250YWwuZGVmaW5lcy5WU01fU0FNUExFUyA9IHNoYWRvdy5ibHVyU2FtcGxlcztcblxuXHRcdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0XHRzaGFkb3dNYXRlcmlhbEhvcml6b250YWwubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBzaGFkb3cubWFwUGFzcyA9PT0gbnVsbCApIHtcblxuXHRcdFx0c2hhZG93Lm1hcFBhc3MgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoIF9zaGFkb3dNYXBTaXplLngsIF9zaGFkb3dNYXBTaXplLnkgKTtcblxuXHRcdH1cblxuXHRcdC8vIHZlcnRpY2FsIHBhc3NcblxuXHRcdHNoYWRvd01hdGVyaWFsVmVydGljYWwudW5pZm9ybXMuc2hhZG93X3Bhc3MudmFsdWUgPSBzaGFkb3cubWFwLnRleHR1cmU7XG5cdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC51bmlmb3Jtcy5yZXNvbHV0aW9uLnZhbHVlID0gc2hhZG93Lm1hcFNpemU7XG5cdFx0c2hhZG93TWF0ZXJpYWxWZXJ0aWNhbC51bmlmb3Jtcy5yYWRpdXMudmFsdWUgPSBzaGFkb3cucmFkaXVzO1xuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggc2hhZG93Lm1hcFBhc3MgKTtcblx0XHRyZW5kZXJlci5jbGVhcigpO1xuXHRcdHJlbmRlcmVyLnJlbmRlckJ1ZmZlckRpcmVjdCggY2FtZXJhLCBudWxsLCBnZW9tZXRyeSwgc2hhZG93TWF0ZXJpYWxWZXJ0aWNhbCwgZnVsbFNjcmVlbk1lc2gsIG51bGwgKTtcblxuXHRcdC8vIGhvcml6b250YWwgcGFzc1xuXG5cdFx0c2hhZG93TWF0ZXJpYWxIb3Jpem9udGFsLnVuaWZvcm1zLnNoYWRvd19wYXNzLnZhbHVlID0gc2hhZG93Lm1hcFBhc3MudGV4dHVyZTtcblx0XHRzaGFkb3dNYXRlcmlhbEhvcml6b250YWwudW5pZm9ybXMucmVzb2x1dGlvbi52YWx1ZSA9IHNoYWRvdy5tYXBTaXplO1xuXHRcdHNoYWRvd01hdGVyaWFsSG9yaXpvbnRhbC51bmlmb3Jtcy5yYWRpdXMudmFsdWUgPSBzaGFkb3cucmFkaXVzO1xuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggc2hhZG93Lm1hcCApO1xuXHRcdHJlbmRlcmVyLmNsZWFyKCk7XG5cdFx0cmVuZGVyZXIucmVuZGVyQnVmZmVyRGlyZWN0KCBjYW1lcmEsIG51bGwsIGdlb21ldHJ5LCBzaGFkb3dNYXRlcmlhbEhvcml6b250YWwsIGZ1bGxTY3JlZW5NZXNoLCBudWxsICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldERlcHRoTWF0ZXJpYWwoIG9iamVjdCwgbWF0ZXJpYWwsIGxpZ2h0LCB0eXBlICkge1xuXG5cdFx0bGV0IHJlc3VsdCA9IG51bGw7XG5cblx0XHRjb25zdCBjdXN0b21NYXRlcmlhbCA9ICggbGlnaHQuaXNQb2ludExpZ2h0ID09PSB0cnVlICkgPyBvYmplY3QuY3VzdG9tRGlzdGFuY2VNYXRlcmlhbCA6IG9iamVjdC5jdXN0b21EZXB0aE1hdGVyaWFsO1xuXG5cdFx0aWYgKCBjdXN0b21NYXRlcmlhbCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRyZXN1bHQgPSBjdXN0b21NYXRlcmlhbDtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJlc3VsdCA9ICggbGlnaHQuaXNQb2ludExpZ2h0ID09PSB0cnVlICkgPyBfZGlzdGFuY2VNYXRlcmlhbCA6IF9kZXB0aE1hdGVyaWFsO1xuXG5cdFx0XHRpZiAoICggcmVuZGVyZXIubG9jYWxDbGlwcGluZ0VuYWJsZWQgJiYgbWF0ZXJpYWwuY2xpcFNoYWRvd3MgPT09IHRydWUgJiYgQXJyYXkuaXNBcnJheSggbWF0ZXJpYWwuY2xpcHBpbmdQbGFuZXMgKSAmJiBtYXRlcmlhbC5jbGlwcGluZ1BsYW5lcy5sZW5ndGggIT09IDAgKSB8fFxuXHRcdFx0XHQoIG1hdGVyaWFsLmRpc3BsYWNlbWVudE1hcCAmJiBtYXRlcmlhbC5kaXNwbGFjZW1lbnRTY2FsZSAhPT0gMCApIHx8XG5cdFx0XHRcdCggbWF0ZXJpYWwuYWxwaGFNYXAgJiYgbWF0ZXJpYWwuYWxwaGFUZXN0ID4gMCApIHx8XG5cdFx0XHRcdCggbWF0ZXJpYWwubWFwICYmIG1hdGVyaWFsLmFscGhhVGVzdCA+IDAgKSApIHtcblxuXHRcdFx0XHQvLyBpbiB0aGlzIGNhc2Ugd2UgbmVlZCBhIHVuaXF1ZSBtYXRlcmlhbCBpbnN0YW5jZSByZWZsZWN0aW5nIHRoZVxuXHRcdFx0XHQvLyBhcHByb3ByaWF0ZSBzdGF0ZVxuXG5cdFx0XHRcdGNvbnN0IGtleUEgPSByZXN1bHQudXVpZCwga2V5QiA9IG1hdGVyaWFsLnV1aWQ7XG5cblx0XHRcdFx0bGV0IG1hdGVyaWFsc0ZvclZhcmlhbnQgPSBfbWF0ZXJpYWxDYWNoZVsga2V5QSBdO1xuXG5cdFx0XHRcdGlmICggbWF0ZXJpYWxzRm9yVmFyaWFudCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0bWF0ZXJpYWxzRm9yVmFyaWFudCA9IHt9O1xuXHRcdFx0XHRcdF9tYXRlcmlhbENhY2hlWyBrZXlBIF0gPSBtYXRlcmlhbHNGb3JWYXJpYW50O1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRsZXQgY2FjaGVkTWF0ZXJpYWwgPSBtYXRlcmlhbHNGb3JWYXJpYW50WyBrZXlCIF07XG5cblx0XHRcdFx0aWYgKCBjYWNoZWRNYXRlcmlhbCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0Y2FjaGVkTWF0ZXJpYWwgPSByZXN1bHQuY2xvbmUoKTtcblx0XHRcdFx0XHRtYXRlcmlhbHNGb3JWYXJpYW50WyBrZXlCIF0gPSBjYWNoZWRNYXRlcmlhbDtcblx0XHRcdFx0XHRtYXRlcmlhbC5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uTWF0ZXJpYWxEaXNwb3NlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJlc3VsdCA9IGNhY2hlZE1hdGVyaWFsO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXN1bHQudmlzaWJsZSA9IG1hdGVyaWFsLnZpc2libGU7XG5cdFx0cmVzdWx0LndpcmVmcmFtZSA9IG1hdGVyaWFsLndpcmVmcmFtZTtcblxuXHRcdGlmICggdHlwZSA9PT0gVlNNU2hhZG93TWFwICkge1xuXG5cdFx0XHRyZXN1bHQuc2lkZSA9ICggbWF0ZXJpYWwuc2hhZG93U2lkZSAhPT0gbnVsbCApID8gbWF0ZXJpYWwuc2hhZG93U2lkZSA6IG1hdGVyaWFsLnNpZGU7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRyZXN1bHQuc2lkZSA9ICggbWF0ZXJpYWwuc2hhZG93U2lkZSAhPT0gbnVsbCApID8gbWF0ZXJpYWwuc2hhZG93U2lkZSA6IHNoYWRvd1NpZGVbIG1hdGVyaWFsLnNpZGUgXTtcblxuXHRcdH1cblxuXHRcdHJlc3VsdC5hbHBoYU1hcCA9IG1hdGVyaWFsLmFscGhhTWFwO1xuXHRcdHJlc3VsdC5hbHBoYVRlc3QgPSBtYXRlcmlhbC5hbHBoYVRlc3Q7XG5cdFx0cmVzdWx0Lm1hcCA9IG1hdGVyaWFsLm1hcDtcblxuXHRcdHJlc3VsdC5jbGlwU2hhZG93cyA9IG1hdGVyaWFsLmNsaXBTaGFkb3dzO1xuXHRcdHJlc3VsdC5jbGlwcGluZ1BsYW5lcyA9IG1hdGVyaWFsLmNsaXBwaW5nUGxhbmVzO1xuXHRcdHJlc3VsdC5jbGlwSW50ZXJzZWN0aW9uID0gbWF0ZXJpYWwuY2xpcEludGVyc2VjdGlvbjtcblxuXHRcdHJlc3VsdC5kaXNwbGFjZW1lbnRNYXAgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXA7XG5cdFx0cmVzdWx0LmRpc3BsYWNlbWVudFNjYWxlID0gbWF0ZXJpYWwuZGlzcGxhY2VtZW50U2NhbGU7XG5cdFx0cmVzdWx0LmRpc3BsYWNlbWVudEJpYXMgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRCaWFzO1xuXG5cdFx0cmVzdWx0LndpcmVmcmFtZUxpbmV3aWR0aCA9IG1hdGVyaWFsLndpcmVmcmFtZUxpbmV3aWR0aDtcblx0XHRyZXN1bHQubGluZXdpZHRoID0gbWF0ZXJpYWwubGluZXdpZHRoO1xuXG5cdFx0aWYgKCBsaWdodC5pc1BvaW50TGlnaHQgPT09IHRydWUgJiYgcmVzdWx0LmlzTWVzaERpc3RhbmNlTWF0ZXJpYWwgPT09IHRydWUgKSB7XG5cblx0XHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHJlbmRlcmVyLnByb3BlcnRpZXMuZ2V0KCByZXN1bHQgKTtcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5saWdodCA9IGxpZ2h0O1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJlc3VsdDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVuZGVyT2JqZWN0KCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBsaWdodCwgdHlwZSApIHtcblxuXHRcdGlmICggb2JqZWN0LnZpc2libGUgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0Y29uc3QgdmlzaWJsZSA9IG9iamVjdC5sYXllcnMudGVzdCggY2FtZXJhLmxheWVycyApO1xuXG5cdFx0aWYgKCB2aXNpYmxlICYmICggb2JqZWN0LmlzTWVzaCB8fCBvYmplY3QuaXNMaW5lIHx8IG9iamVjdC5pc1BvaW50cyApICkge1xuXG5cdFx0XHRpZiAoICggb2JqZWN0LmNhc3RTaGFkb3cgfHwgKCBvYmplY3QucmVjZWl2ZVNoYWRvdyAmJiB0eXBlID09PSBWU01TaGFkb3dNYXAgKSApICYmICggISBvYmplY3QuZnJ1c3R1bUN1bGxlZCB8fCBfZnJ1c3R1bS5pbnRlcnNlY3RzT2JqZWN0KCBvYmplY3QgKSApICkge1xuXG5cdFx0XHRcdG9iamVjdC5tb2RlbFZpZXdNYXRyaXgubXVsdGlwbHlNYXRyaWNlcyggc2hhZG93Q2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSwgb2JqZWN0Lm1hdHJpeFdvcmxkICk7XG5cblx0XHRcdFx0Y29uc3QgZ2VvbWV0cnkgPSBvYmplY3RzLnVwZGF0ZSggb2JqZWN0ICk7XG5cdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gb2JqZWN0Lm1hdGVyaWFsO1xuXG5cdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggbWF0ZXJpYWwgKSApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGdyb3VwcyA9IGdlb21ldHJ5Lmdyb3VwcztcblxuXHRcdFx0XHRcdGZvciAoIGxldCBrID0gMCwga2wgPSBncm91cHMubGVuZ3RoOyBrIDwga2w7IGsgKysgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGdyb3VwID0gZ3JvdXBzWyBrIF07XG5cdFx0XHRcdFx0XHRjb25zdCBncm91cE1hdGVyaWFsID0gbWF0ZXJpYWxbIGdyb3VwLm1hdGVyaWFsSW5kZXggXTtcblxuXHRcdFx0XHRcdFx0aWYgKCBncm91cE1hdGVyaWFsICYmIGdyb3VwTWF0ZXJpYWwudmlzaWJsZSApIHtcblxuXHRcdFx0XHRcdFx0XHRjb25zdCBkZXB0aE1hdGVyaWFsID0gZ2V0RGVwdGhNYXRlcmlhbCggb2JqZWN0LCBncm91cE1hdGVyaWFsLCBsaWdodCwgdHlwZSApO1xuXG5cdFx0XHRcdFx0XHRcdG9iamVjdC5vbkJlZm9yZVNoYWRvdyggcmVuZGVyZXIsIG9iamVjdCwgY2FtZXJhLCBzaGFkb3dDYW1lcmEsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsLCBncm91cCApO1xuXG5cdFx0XHRcdFx0XHRcdHJlbmRlcmVyLnJlbmRlckJ1ZmZlckRpcmVjdCggc2hhZG93Q2FtZXJhLCBudWxsLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgb2JqZWN0LCBncm91cCApO1xuXG5cdFx0XHRcdFx0XHRcdG9iamVjdC5vbkFmdGVyU2hhZG93KCByZW5kZXJlciwgb2JqZWN0LCBjYW1lcmEsIHNoYWRvd0NhbWVyYSwgZ2VvbWV0cnksIGRlcHRoTWF0ZXJpYWwsIGdyb3VwICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC52aXNpYmxlICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgZGVwdGhNYXRlcmlhbCA9IGdldERlcHRoTWF0ZXJpYWwoIG9iamVjdCwgbWF0ZXJpYWwsIGxpZ2h0LCB0eXBlICk7XG5cblx0XHRcdFx0XHRvYmplY3Qub25CZWZvcmVTaGFkb3coIHJlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCwgbnVsbCApO1xuXG5cdFx0XHRcdFx0cmVuZGVyZXIucmVuZGVyQnVmZmVyRGlyZWN0KCBzaGFkb3dDYW1lcmEsIG51bGwsIGdlb21ldHJ5LCBkZXB0aE1hdGVyaWFsLCBvYmplY3QsIG51bGwgKTtcblxuXHRcdFx0XHRcdG9iamVjdC5vbkFmdGVyU2hhZG93KCByZW5kZXJlciwgb2JqZWN0LCBjYW1lcmEsIHNoYWRvd0NhbWVyYSwgZ2VvbWV0cnksIGRlcHRoTWF0ZXJpYWwsIG51bGwgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IGNoaWxkcmVuID0gb2JqZWN0LmNoaWxkcmVuO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0cmVuZGVyT2JqZWN0KCBjaGlsZHJlblsgaSBdLCBjYW1lcmEsIHNoYWRvd0NhbWVyYSwgbGlnaHQsIHR5cGUgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gb25NYXRlcmlhbERpc3Bvc2UoIGV2ZW50ICkge1xuXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBldmVudC50YXJnZXQ7XG5cblx0XHRtYXRlcmlhbC5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uTWF0ZXJpYWxEaXNwb3NlICk7XG5cblx0XHQvLyBtYWtlIHN1cmUgdG8gcmVtb3ZlIHRoZSB1bmlxdWUgZGlzdGFuY2UvZGVwdGggbWF0ZXJpYWxzIHVzZWQgZm9yIHNoYWRvdyBtYXAgcmVuZGVyaW5nXG5cblx0XHRmb3IgKCBjb25zdCBpZCBpbiBfbWF0ZXJpYWxDYWNoZSApIHtcblxuXHRcdFx0Y29uc3QgY2FjaGUgPSBfbWF0ZXJpYWxDYWNoZVsgaWQgXTtcblxuXHRcdFx0Y29uc3QgdXVpZCA9IGV2ZW50LnRhcmdldC51dWlkO1xuXG5cdFx0XHRpZiAoIHV1aWQgaW4gY2FjaGUgKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2hhZG93TWF0ZXJpYWwgPSBjYWNoZVsgdXVpZCBdO1xuXHRcdFx0XHRzaGFkb3dNYXRlcmlhbC5kaXNwb3NlKCk7XG5cdFx0XHRcdGRlbGV0ZSBjYWNoZVsgdXVpZCBdO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIFdlYkdMU3RhdGUoIGdsICkge1xuXG5cdGZ1bmN0aW9uIENvbG9yQnVmZmVyKCkge1xuXG5cdFx0bGV0IGxvY2tlZCA9IGZhbHNlO1xuXG5cdFx0Y29uc3QgY29sb3IgPSBuZXcgVmVjdG9yNCgpO1xuXHRcdGxldCBjdXJyZW50Q29sb3JNYXNrID0gbnVsbDtcblx0XHRjb25zdCBjdXJyZW50Q29sb3JDbGVhciA9IG5ldyBWZWN0b3I0KCAwLCAwLCAwLCAwICk7XG5cblx0XHRyZXR1cm4ge1xuXG5cdFx0XHRzZXRNYXNrOiBmdW5jdGlvbiAoIGNvbG9yTWFzayApIHtcblxuXHRcdFx0XHRpZiAoIGN1cnJlbnRDb2xvck1hc2sgIT09IGNvbG9yTWFzayAmJiAhIGxvY2tlZCApIHtcblxuXHRcdFx0XHRcdGdsLmNvbG9yTWFzayggY29sb3JNYXNrLCBjb2xvck1hc2ssIGNvbG9yTWFzaywgY29sb3JNYXNrICk7XG5cdFx0XHRcdFx0Y3VycmVudENvbG9yTWFzayA9IGNvbG9yTWFzaztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldExvY2tlZDogZnVuY3Rpb24gKCBsb2NrICkge1xuXG5cdFx0XHRcdGxvY2tlZCA9IGxvY2s7XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldENsZWFyOiBmdW5jdGlvbiAoIHIsIGcsIGIsIGEsIHByZW11bHRpcGxpZWRBbHBoYSApIHtcblxuXHRcdFx0XHRpZiAoIHByZW11bHRpcGxpZWRBbHBoYSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdHIgKj0gYTsgZyAqPSBhOyBiICo9IGE7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNvbG9yLnNldCggciwgZywgYiwgYSApO1xuXG5cdFx0XHRcdGlmICggY3VycmVudENvbG9yQ2xlYXIuZXF1YWxzKCBjb2xvciApID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHRcdGdsLmNsZWFyQ29sb3IoIHIsIGcsIGIsIGEgKTtcblx0XHRcdFx0XHRjdXJyZW50Q29sb3JDbGVhci5jb3B5KCBjb2xvciApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblxuXHRcdFx0cmVzZXQ6IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRsb2NrZWQgPSBmYWxzZTtcblxuXHRcdFx0XHRjdXJyZW50Q29sb3JNYXNrID0gbnVsbDtcblx0XHRcdFx0Y3VycmVudENvbG9yQ2xlYXIuc2V0KCAtIDEsIDAsIDAsIDAgKTsgLy8gc2V0IHRvIGludmFsaWQgc3RhdGVcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gRGVwdGhCdWZmZXIoKSB7XG5cblx0XHRsZXQgbG9ja2VkID0gZmFsc2U7XG5cblx0XHRsZXQgY3VycmVudERlcHRoTWFzayA9IG51bGw7XG5cdFx0bGV0IGN1cnJlbnREZXB0aEZ1bmMgPSBudWxsO1xuXHRcdGxldCBjdXJyZW50RGVwdGhDbGVhciA9IG51bGw7XG5cblx0XHRyZXR1cm4ge1xuXG5cdFx0XHRzZXRUZXN0OiBmdW5jdGlvbiAoIGRlcHRoVGVzdCApIHtcblxuXHRcdFx0XHRpZiAoIGRlcHRoVGVzdCApIHtcblxuXHRcdFx0XHRcdGVuYWJsZSggZ2wuREVQVEhfVEVTVCApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRkaXNhYmxlKCBnbC5ERVBUSF9URVNUICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9LFxuXG5cdFx0XHRzZXRNYXNrOiBmdW5jdGlvbiAoIGRlcHRoTWFzayApIHtcblxuXHRcdFx0XHRpZiAoIGN1cnJlbnREZXB0aE1hc2sgIT09IGRlcHRoTWFzayAmJiAhIGxvY2tlZCApIHtcblxuXHRcdFx0XHRcdGdsLmRlcHRoTWFzayggZGVwdGhNYXNrICk7XG5cdFx0XHRcdFx0Y3VycmVudERlcHRoTWFzayA9IGRlcHRoTWFzaztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldEZ1bmM6IGZ1bmN0aW9uICggZGVwdGhGdW5jICkge1xuXG5cdFx0XHRcdGlmICggY3VycmVudERlcHRoRnVuYyAhPT0gZGVwdGhGdW5jICkge1xuXG5cdFx0XHRcdFx0c3dpdGNoICggZGVwdGhGdW5jICkge1xuXG5cdFx0XHRcdFx0XHRjYXNlIE5ldmVyRGVwdGg6XG5cblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5ORVZFUiApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBBbHdheXNEZXB0aDpcblxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLkFMV0FZUyApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBMZXNzRGVwdGg6XG5cblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5MRVNTICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRjYXNlIExlc3NFcXVhbERlcHRoOlxuXG5cdFx0XHRcdFx0XHRcdGdsLmRlcHRoRnVuYyggZ2wuTEVRVUFMICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRjYXNlIEVxdWFsRGVwdGg6XG5cblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5FUVVBTCApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBHcmVhdGVyRXF1YWxEZXB0aDpcblxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLkdFUVVBTCApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBHcmVhdGVyRGVwdGg6XG5cblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5HUkVBVEVSICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRjYXNlIE5vdEVxdWFsRGVwdGg6XG5cblx0XHRcdFx0XHRcdFx0Z2wuZGVwdGhGdW5jKCBnbC5OT1RFUVVBTCApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0ZGVmYXVsdDpcblxuXHRcdFx0XHRcdFx0XHRnbC5kZXB0aEZ1bmMoIGdsLkxFUVVBTCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Y3VycmVudERlcHRoRnVuYyA9IGRlcHRoRnVuYztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldExvY2tlZDogZnVuY3Rpb24gKCBsb2NrICkge1xuXG5cdFx0XHRcdGxvY2tlZCA9IGxvY2s7XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldENsZWFyOiBmdW5jdGlvbiAoIGRlcHRoICkge1xuXG5cdFx0XHRcdGlmICggY3VycmVudERlcHRoQ2xlYXIgIT09IGRlcHRoICkge1xuXG5cdFx0XHRcdFx0Z2wuY2xlYXJEZXB0aCggZGVwdGggKTtcblx0XHRcdFx0XHRjdXJyZW50RGVwdGhDbGVhciA9IGRlcHRoO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblxuXHRcdFx0cmVzZXQ6IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRsb2NrZWQgPSBmYWxzZTtcblxuXHRcdFx0XHRjdXJyZW50RGVwdGhNYXNrID0gbnVsbDtcblx0XHRcdFx0Y3VycmVudERlcHRoRnVuYyA9IG51bGw7XG5cdFx0XHRcdGN1cnJlbnREZXB0aENsZWFyID0gbnVsbDtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gU3RlbmNpbEJ1ZmZlcigpIHtcblxuXHRcdGxldCBsb2NrZWQgPSBmYWxzZTtcblxuXHRcdGxldCBjdXJyZW50U3RlbmNpbE1hc2sgPSBudWxsO1xuXHRcdGxldCBjdXJyZW50U3RlbmNpbEZ1bmMgPSBudWxsO1xuXHRcdGxldCBjdXJyZW50U3RlbmNpbFJlZiA9IG51bGw7XG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsRnVuY01hc2sgPSBudWxsO1xuXHRcdGxldCBjdXJyZW50U3RlbmNpbEZhaWwgPSBudWxsO1xuXHRcdGxldCBjdXJyZW50U3RlbmNpbFpGYWlsID0gbnVsbDtcblx0XHRsZXQgY3VycmVudFN0ZW5jaWxaUGFzcyA9IG51bGw7XG5cdFx0bGV0IGN1cnJlbnRTdGVuY2lsQ2xlYXIgPSBudWxsO1xuXG5cdFx0cmV0dXJuIHtcblxuXHRcdFx0c2V0VGVzdDogZnVuY3Rpb24gKCBzdGVuY2lsVGVzdCApIHtcblxuXHRcdFx0XHRpZiAoICEgbG9ja2VkICkge1xuXG5cdFx0XHRcdFx0aWYgKCBzdGVuY2lsVGVzdCApIHtcblxuXHRcdFx0XHRcdFx0ZW5hYmxlKCBnbC5TVEVOQ0lMX1RFU1QgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGRpc2FibGUoIGdsLlNURU5DSUxfVEVTVCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblxuXHRcdFx0c2V0TWFzazogZnVuY3Rpb24gKCBzdGVuY2lsTWFzayApIHtcblxuXHRcdFx0XHRpZiAoIGN1cnJlbnRTdGVuY2lsTWFzayAhPT0gc3RlbmNpbE1hc2sgJiYgISBsb2NrZWQgKSB7XG5cblx0XHRcdFx0XHRnbC5zdGVuY2lsTWFzayggc3RlbmNpbE1hc2sgKTtcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbE1hc2sgPSBzdGVuY2lsTWFzaztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0sXG5cblx0XHRcdHNldEZ1bmM6IGZ1bmN0aW9uICggc3RlbmNpbEZ1bmMsIHN0ZW5jaWxSZWYsIHN0ZW5jaWxNYXNrICkge1xuXG5cdFx0XHRcdGlmICggY3VycmVudFN0ZW5jaWxGdW5jICE9PSBzdGVuY2lsRnVuYyB8fFxuXHRcdFx0XHQgICAgIGN1cnJlbnRTdGVuY2lsUmVmICE9PSBzdGVuY2lsUmVmIHx8XG5cdFx0XHRcdCAgICAgY3VycmVudFN0ZW5jaWxGdW5jTWFzayAhPT0gc3RlbmNpbE1hc2sgKSB7XG5cblx0XHRcdFx0XHRnbC5zdGVuY2lsRnVuYyggc3RlbmNpbEZ1bmMsIHN0ZW5jaWxSZWYsIHN0ZW5jaWxNYXNrICk7XG5cblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbEZ1bmMgPSBzdGVuY2lsRnVuYztcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbFJlZiA9IHN0ZW5jaWxSZWY7XG5cdFx0XHRcdFx0Y3VycmVudFN0ZW5jaWxGdW5jTWFzayA9IHN0ZW5jaWxNYXNrO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblxuXHRcdFx0c2V0T3A6IGZ1bmN0aW9uICggc3RlbmNpbEZhaWwsIHN0ZW5jaWxaRmFpbCwgc3RlbmNpbFpQYXNzICkge1xuXG5cdFx0XHRcdGlmICggY3VycmVudFN0ZW5jaWxGYWlsICE9PSBzdGVuY2lsRmFpbCB8fFxuXHRcdFx0XHQgICAgIGN1cnJlbnRTdGVuY2lsWkZhaWwgIT09IHN0ZW5jaWxaRmFpbCB8fFxuXHRcdFx0XHQgICAgIGN1cnJlbnRTdGVuY2lsWlBhc3MgIT09IHN0ZW5jaWxaUGFzcyApIHtcblxuXHRcdFx0XHRcdGdsLnN0ZW5jaWxPcCggc3RlbmNpbEZhaWwsIHN0ZW5jaWxaRmFpbCwgc3RlbmNpbFpQYXNzICk7XG5cblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbEZhaWwgPSBzdGVuY2lsRmFpbDtcblx0XHRcdFx0XHRjdXJyZW50U3RlbmNpbFpGYWlsID0gc3RlbmNpbFpGYWlsO1xuXHRcdFx0XHRcdGN1cnJlbnRTdGVuY2lsWlBhc3MgPSBzdGVuY2lsWlBhc3M7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9LFxuXG5cdFx0XHRzZXRMb2NrZWQ6IGZ1bmN0aW9uICggbG9jayApIHtcblxuXHRcdFx0XHRsb2NrZWQgPSBsb2NrO1xuXG5cdFx0XHR9LFxuXG5cdFx0XHRzZXRDbGVhcjogZnVuY3Rpb24gKCBzdGVuY2lsICkge1xuXG5cdFx0XHRcdGlmICggY3VycmVudFN0ZW5jaWxDbGVhciAhPT0gc3RlbmNpbCApIHtcblxuXHRcdFx0XHRcdGdsLmNsZWFyU3RlbmNpbCggc3RlbmNpbCApO1xuXHRcdFx0XHRcdGN1cnJlbnRTdGVuY2lsQ2xlYXIgPSBzdGVuY2lsO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSxcblxuXHRcdFx0cmVzZXQ6IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRsb2NrZWQgPSBmYWxzZTtcblxuXHRcdFx0XHRjdXJyZW50U3RlbmNpbE1hc2sgPSBudWxsO1xuXHRcdFx0XHRjdXJyZW50U3RlbmNpbEZ1bmMgPSBudWxsO1xuXHRcdFx0XHRjdXJyZW50U3RlbmNpbFJlZiA9IG51bGw7XG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsRnVuY01hc2sgPSBudWxsO1xuXHRcdFx0XHRjdXJyZW50U3RlbmNpbEZhaWwgPSBudWxsO1xuXHRcdFx0XHRjdXJyZW50U3RlbmNpbFpGYWlsID0gbnVsbDtcblx0XHRcdFx0Y3VycmVudFN0ZW5jaWxaUGFzcyA9IG51bGw7XG5cdFx0XHRcdGN1cnJlbnRTdGVuY2lsQ2xlYXIgPSBudWxsO1xuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdH1cblxuXHQvL1xuXG5cdGNvbnN0IGNvbG9yQnVmZmVyID0gbmV3IENvbG9yQnVmZmVyKCk7XG5cdGNvbnN0IGRlcHRoQnVmZmVyID0gbmV3IERlcHRoQnVmZmVyKCk7XG5cdGNvbnN0IHN0ZW5jaWxCdWZmZXIgPSBuZXcgU3RlbmNpbEJ1ZmZlcigpO1xuXG5cdGNvbnN0IHVib0JpbmRpbmdzID0gbmV3IFdlYWtNYXAoKTtcblx0Y29uc3QgdWJvUHJvZ3JhbU1hcCA9IG5ldyBXZWFrTWFwKCk7XG5cblx0bGV0IGVuYWJsZWRDYXBhYmlsaXRpZXMgPSB7fTtcblxuXHRsZXQgY3VycmVudEJvdW5kRnJhbWVidWZmZXJzID0ge307XG5cdGxldCBjdXJyZW50RHJhd2J1ZmZlcnMgPSBuZXcgV2Vha01hcCgpO1xuXHRsZXQgZGVmYXVsdERyYXdidWZmZXJzID0gW107XG5cblx0bGV0IGN1cnJlbnRQcm9ncmFtID0gbnVsbDtcblxuXHRsZXQgY3VycmVudEJsZW5kaW5nRW5hYmxlZCA9IGZhbHNlO1xuXHRsZXQgY3VycmVudEJsZW5kaW5nID0gbnVsbDtcblx0bGV0IGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gbnVsbDtcblx0bGV0IGN1cnJlbnRCbGVuZFNyYyA9IG51bGw7XG5cdGxldCBjdXJyZW50QmxlbmREc3QgPSBudWxsO1xuXHRsZXQgY3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSA9IG51bGw7XG5cdGxldCBjdXJyZW50QmxlbmRTcmNBbHBoYSA9IG51bGw7XG5cdGxldCBjdXJyZW50QmxlbmREc3RBbHBoYSA9IG51bGw7XG5cdGxldCBjdXJyZW50QmxlbmRDb2xvciA9IG5ldyBDb2xvciggMCwgMCwgMCApO1xuXHRsZXQgY3VycmVudEJsZW5kQWxwaGEgPSAwO1xuXHRsZXQgY3VycmVudFByZW11bHRpcGxlZEFscGhhID0gZmFsc2U7XG5cblx0bGV0IGN1cnJlbnRGbGlwU2lkZWQgPSBudWxsO1xuXHRsZXQgY3VycmVudEN1bGxGYWNlID0gbnVsbDtcblxuXHRsZXQgY3VycmVudExpbmVXaWR0aCA9IG51bGw7XG5cblx0bGV0IGN1cnJlbnRQb2x5Z29uT2Zmc2V0RmFjdG9yID0gbnVsbDtcblx0bGV0IGN1cnJlbnRQb2x5Z29uT2Zmc2V0VW5pdHMgPSBudWxsO1xuXG5cdGNvbnN0IG1heFRleHR1cmVzID0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfQ09NQklORURfVEVYVFVSRV9JTUFHRV9VTklUUyApO1xuXG5cdGxldCBsaW5lV2lkdGhBdmFpbGFibGUgPSBmYWxzZTtcblx0bGV0IHZlcnNpb24gPSAwO1xuXHRjb25zdCBnbFZlcnNpb24gPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLlZFUlNJT04gKTtcblxuXHRpZiAoIGdsVmVyc2lvbi5pbmRleE9mKCAnV2ViR0wnICkgIT09IC0gMSApIHtcblxuXHRcdHZlcnNpb24gPSBwYXJzZUZsb2F0KCAvXldlYkdMIChcXGQpLy5leGVjKCBnbFZlcnNpb24gKVsgMSBdICk7XG5cdFx0bGluZVdpZHRoQXZhaWxhYmxlID0gKCB2ZXJzaW9uID49IDEuMCApO1xuXG5cdH0gZWxzZSBpZiAoIGdsVmVyc2lvbi5pbmRleE9mKCAnT3BlbkdMIEVTJyApICE9PSAtIDEgKSB7XG5cblx0XHR2ZXJzaW9uID0gcGFyc2VGbG9hdCggL15PcGVuR0wgRVMgKFxcZCkvLmV4ZWMoIGdsVmVyc2lvbiApWyAxIF0gKTtcblx0XHRsaW5lV2lkdGhBdmFpbGFibGUgPSAoIHZlcnNpb24gPj0gMi4wICk7XG5cblx0fVxuXG5cdGxldCBjdXJyZW50VGV4dHVyZVNsb3QgPSBudWxsO1xuXHRsZXQgY3VycmVudEJvdW5kVGV4dHVyZXMgPSB7fTtcblxuXHRjb25zdCBzY2lzc29yUGFyYW0gPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLlNDSVNTT1JfQk9YICk7XG5cdGNvbnN0IHZpZXdwb3J0UGFyYW0gPSBnbC5nZXRQYXJhbWV0ZXIoIGdsLlZJRVdQT1JUICk7XG5cblx0Y29uc3QgY3VycmVudFNjaXNzb3IgPSBuZXcgVmVjdG9yNCgpLmZyb21BcnJheSggc2Npc3NvclBhcmFtICk7XG5cdGNvbnN0IGN1cnJlbnRWaWV3cG9ydCA9IG5ldyBWZWN0b3I0KCkuZnJvbUFycmF5KCB2aWV3cG9ydFBhcmFtICk7XG5cblx0ZnVuY3Rpb24gY3JlYXRlVGV4dHVyZSggdHlwZSwgdGFyZ2V0LCBjb3VudCwgZGltZW5zaW9ucyApIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBuZXcgVWludDhBcnJheSggNCApOyAvLyA0IGlzIHJlcXVpcmVkIHRvIG1hdGNoIGRlZmF1bHQgdW5wYWNrIGFsaWdubWVudCBvZiA0LlxuXHRcdGNvbnN0IHRleHR1cmUgPSBnbC5jcmVhdGVUZXh0dXJlKCk7XG5cblx0XHRnbC5iaW5kVGV4dHVyZSggdHlwZSwgdGV4dHVyZSApO1xuXHRcdGdsLnRleFBhcmFtZXRlcmkoIHR5cGUsIGdsLlRFWFRVUkVfTUlOX0ZJTFRFUiwgZ2wuTkVBUkVTVCApO1xuXHRcdGdsLnRleFBhcmFtZXRlcmkoIHR5cGUsIGdsLlRFWFRVUkVfTUFHX0ZJTFRFUiwgZ2wuTkVBUkVTVCApO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY291bnQ7IGkgKysgKSB7XG5cblx0XHRcdGlmICggdHlwZSA9PT0gZ2wuVEVYVFVSRV8zRCB8fCB0eXBlID09PSBnbC5URVhUVVJFXzJEX0FSUkFZICkge1xuXG5cdFx0XHRcdGdsLnRleEltYWdlM0QoIHRhcmdldCwgMCwgZ2wuUkdCQSwgMSwgMSwgZGltZW5zaW9ucywgMCwgZ2wuUkdCQSwgZ2wuVU5TSUdORURfQllURSwgZGF0YSApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGdsLnRleEltYWdlMkQoIHRhcmdldCArIGksIDAsIGdsLlJHQkEsIDEsIDEsIDAsIGdsLlJHQkEsIGdsLlVOU0lHTkVEX0JZVEUsIGRhdGEgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRleHR1cmU7XG5cblx0fVxuXG5cdGNvbnN0IGVtcHR5VGV4dHVyZXMgPSB7fTtcblx0ZW1wdHlUZXh0dXJlc1sgZ2wuVEVYVFVSRV8yRCBdID0gY3JlYXRlVGV4dHVyZSggZ2wuVEVYVFVSRV8yRCwgZ2wuVEVYVFVSRV8yRCwgMSApO1xuXHRlbXB0eVRleHR1cmVzWyBnbC5URVhUVVJFX0NVQkVfTUFQIF0gPSBjcmVhdGVUZXh0dXJlKCBnbC5URVhUVVJFX0NVQkVfTUFQLCBnbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1gsIDYgKTtcblx0ZW1wdHlUZXh0dXJlc1sgZ2wuVEVYVFVSRV8yRF9BUlJBWSBdID0gY3JlYXRlVGV4dHVyZSggZ2wuVEVYVFVSRV8yRF9BUlJBWSwgZ2wuVEVYVFVSRV8yRF9BUlJBWSwgMSwgMSApO1xuXHRlbXB0eVRleHR1cmVzWyBnbC5URVhUVVJFXzNEIF0gPSBjcmVhdGVUZXh0dXJlKCBnbC5URVhUVVJFXzNELCBnbC5URVhUVVJFXzNELCAxLCAxICk7XG5cblx0Ly8gaW5pdFxuXG5cdGNvbG9yQnVmZmVyLnNldENsZWFyKCAwLCAwLCAwLCAxICk7XG5cdGRlcHRoQnVmZmVyLnNldENsZWFyKCAxICk7XG5cdHN0ZW5jaWxCdWZmZXIuc2V0Q2xlYXIoIDAgKTtcblxuXHRlbmFibGUoIGdsLkRFUFRIX1RFU1QgKTtcblx0ZGVwdGhCdWZmZXIuc2V0RnVuYyggTGVzc0VxdWFsRGVwdGggKTtcblxuXHRzZXRGbGlwU2lkZWQoIGZhbHNlICk7XG5cdHNldEN1bGxGYWNlKCBDdWxsRmFjZUJhY2sgKTtcblx0ZW5hYmxlKCBnbC5DVUxMX0ZBQ0UgKTtcblxuXHRzZXRCbGVuZGluZyggTm9CbGVuZGluZyApO1xuXG5cdC8vXG5cblx0ZnVuY3Rpb24gZW5hYmxlKCBpZCApIHtcblxuXHRcdGlmICggZW5hYmxlZENhcGFiaWxpdGllc1sgaWQgXSAhPT0gdHJ1ZSApIHtcblxuXHRcdFx0Z2wuZW5hYmxlKCBpZCApO1xuXHRcdFx0ZW5hYmxlZENhcGFiaWxpdGllc1sgaWQgXSA9IHRydWU7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRpc2FibGUoIGlkICkge1xuXG5cdFx0aWYgKCBlbmFibGVkQ2FwYWJpbGl0aWVzWyBpZCBdICE9PSBmYWxzZSApIHtcblxuXHRcdFx0Z2wuZGlzYWJsZSggaWQgKTtcblx0XHRcdGVuYWJsZWRDYXBhYmlsaXRpZXNbIGlkIF0gPSBmYWxzZTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gYmluZEZyYW1lYnVmZmVyKCB0YXJnZXQsIGZyYW1lYnVmZmVyICkge1xuXG5cdFx0aWYgKCBjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnNbIHRhcmdldCBdICE9PSBmcmFtZWJ1ZmZlciApIHtcblxuXHRcdFx0Z2wuYmluZEZyYW1lYnVmZmVyKCB0YXJnZXQsIGZyYW1lYnVmZmVyICk7XG5cblx0XHRcdGN1cnJlbnRCb3VuZEZyYW1lYnVmZmVyc1sgdGFyZ2V0IF0gPSBmcmFtZWJ1ZmZlcjtcblxuXHRcdFx0Ly8gZ2wuRFJBV19GUkFNRUJVRkZFUiBpcyBlcXVpdmFsZW50IHRvIGdsLkZSQU1FQlVGRkVSXG5cblx0XHRcdGlmICggdGFyZ2V0ID09PSBnbC5EUkFXX0ZSQU1FQlVGRkVSICkge1xuXG5cdFx0XHRcdGN1cnJlbnRCb3VuZEZyYW1lYnVmZmVyc1sgZ2wuRlJBTUVCVUZGRVIgXSA9IGZyYW1lYnVmZmVyO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGFyZ2V0ID09PSBnbC5GUkFNRUJVRkZFUiApIHtcblxuXHRcdFx0XHRjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnNbIGdsLkRSQVdfRlJBTUVCVUZGRVIgXSA9IGZyYW1lYnVmZmVyO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBkcmF3QnVmZmVycyggcmVuZGVyVGFyZ2V0LCBmcmFtZWJ1ZmZlciApIHtcblxuXHRcdGxldCBkcmF3QnVmZmVycyA9IGRlZmF1bHREcmF3YnVmZmVycztcblxuXHRcdGxldCBuZWVkc1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRcdGRyYXdCdWZmZXJzID0gY3VycmVudERyYXdidWZmZXJzLmdldCggZnJhbWVidWZmZXIgKTtcblxuXHRcdFx0aWYgKCBkcmF3QnVmZmVycyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGRyYXdCdWZmZXJzID0gW107XG5cdFx0XHRcdGN1cnJlbnREcmF3YnVmZmVycy5zZXQoIGZyYW1lYnVmZmVyLCBkcmF3QnVmZmVycyApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmVzO1xuXG5cdFx0XHRpZiAoIGRyYXdCdWZmZXJzLmxlbmd0aCAhPT0gdGV4dHVyZXMubGVuZ3RoIHx8IGRyYXdCdWZmZXJzWyAwIF0gIT09IGdsLkNPTE9SX0FUVEFDSE1FTlQwICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGRyYXdCdWZmZXJzWyBpIF0gPSBnbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGRyYXdCdWZmZXJzLmxlbmd0aCA9IHRleHR1cmVzLmxlbmd0aDtcblxuXHRcdFx0XHRuZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGlmICggZHJhd0J1ZmZlcnNbIDAgXSAhPT0gZ2wuQkFDSyApIHtcblxuXHRcdFx0XHRkcmF3QnVmZmVyc1sgMCBdID0gZ2wuQkFDSztcblxuXHRcdFx0XHRuZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggbmVlZHNVcGRhdGUgKSB7XG5cblx0XHRcdGdsLmRyYXdCdWZmZXJzKCBkcmF3QnVmZmVycyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB1c2VQcm9ncmFtKCBwcm9ncmFtICkge1xuXG5cdFx0aWYgKCBjdXJyZW50UHJvZ3JhbSAhPT0gcHJvZ3JhbSApIHtcblxuXHRcdFx0Z2wudXNlUHJvZ3JhbSggcHJvZ3JhbSApO1xuXG5cdFx0XHRjdXJyZW50UHJvZ3JhbSA9IHByb2dyYW07XG5cblx0XHRcdHJldHVybiB0cnVlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZhbHNlO1xuXG5cdH1cblxuXHRjb25zdCBlcXVhdGlvblRvR0wgPSB7XG5cdFx0WyBBZGRFcXVhdGlvbiBdOiBnbC5GVU5DX0FERCxcblx0XHRbIFN1YnRyYWN0RXF1YXRpb24gXTogZ2wuRlVOQ19TVUJUUkFDVCxcblx0XHRbIFJldmVyc2VTdWJ0cmFjdEVxdWF0aW9uIF06IGdsLkZVTkNfUkVWRVJTRV9TVUJUUkFDVFxuXHR9O1xuXG5cdGVxdWF0aW9uVG9HTFsgTWluRXF1YXRpb24gXSA9IGdsLk1JTjtcblx0ZXF1YXRpb25Ub0dMWyBNYXhFcXVhdGlvbiBdID0gZ2wuTUFYO1xuXG5cdGNvbnN0IGZhY3RvclRvR0wgPSB7XG5cdFx0WyBaZXJvRmFjdG9yIF06IGdsLlpFUk8sXG5cdFx0WyBPbmVGYWN0b3IgXTogZ2wuT05FLFxuXHRcdFsgU3JjQ29sb3JGYWN0b3IgXTogZ2wuU1JDX0NPTE9SLFxuXHRcdFsgU3JjQWxwaGFGYWN0b3IgXTogZ2wuU1JDX0FMUEhBLFxuXHRcdFsgU3JjQWxwaGFTYXR1cmF0ZUZhY3RvciBdOiBnbC5TUkNfQUxQSEFfU0FUVVJBVEUsXG5cdFx0WyBEc3RDb2xvckZhY3RvciBdOiBnbC5EU1RfQ09MT1IsXG5cdFx0WyBEc3RBbHBoYUZhY3RvciBdOiBnbC5EU1RfQUxQSEEsXG5cdFx0WyBPbmVNaW51c1NyY0NvbG9yRmFjdG9yIF06IGdsLk9ORV9NSU5VU19TUkNfQ09MT1IsXG5cdFx0WyBPbmVNaW51c1NyY0FscGhhRmFjdG9yIF06IGdsLk9ORV9NSU5VU19TUkNfQUxQSEEsXG5cdFx0WyBPbmVNaW51c0RzdENvbG9yRmFjdG9yIF06IGdsLk9ORV9NSU5VU19EU1RfQ09MT1IsXG5cdFx0WyBPbmVNaW51c0RzdEFscGhhRmFjdG9yIF06IGdsLk9ORV9NSU5VU19EU1RfQUxQSEEsXG5cdFx0WyBDb25zdGFudENvbG9yRmFjdG9yIF06IGdsLkNPTlNUQU5UX0NPTE9SLFxuXHRcdFsgT25lTWludXNDb25zdGFudENvbG9yRmFjdG9yIF06IGdsLk9ORV9NSU5VU19DT05TVEFOVF9DT0xPUixcblx0XHRbIENvbnN0YW50QWxwaGFGYWN0b3IgXTogZ2wuQ09OU1RBTlRfQUxQSEEsXG5cdFx0WyBPbmVNaW51c0NvbnN0YW50QWxwaGFGYWN0b3IgXTogZ2wuT05FX01JTlVTX0NPTlNUQU5UX0FMUEhBXG5cdH07XG5cblx0ZnVuY3Rpb24gc2V0QmxlbmRpbmcoIGJsZW5kaW5nLCBibGVuZEVxdWF0aW9uLCBibGVuZFNyYywgYmxlbmREc3QsIGJsZW5kRXF1YXRpb25BbHBoYSwgYmxlbmRTcmNBbHBoYSwgYmxlbmREc3RBbHBoYSwgYmxlbmRDb2xvciwgYmxlbmRBbHBoYSwgcHJlbXVsdGlwbGllZEFscGhhICkge1xuXG5cdFx0aWYgKCBibGVuZGluZyA9PT0gTm9CbGVuZGluZyApIHtcblxuXHRcdFx0aWYgKCBjdXJyZW50QmxlbmRpbmdFbmFibGVkID09PSB0cnVlICkge1xuXG5cdFx0XHRcdGRpc2FibGUoIGdsLkJMRU5EICk7XG5cdFx0XHRcdGN1cnJlbnRCbGVuZGluZ0VuYWJsZWQgPSBmYWxzZTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHRpZiAoIGN1cnJlbnRCbGVuZGluZ0VuYWJsZWQgPT09IGZhbHNlICkge1xuXG5cdFx0XHRlbmFibGUoIGdsLkJMRU5EICk7XG5cdFx0XHRjdXJyZW50QmxlbmRpbmdFbmFibGVkID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdGlmICggYmxlbmRpbmcgIT09IEN1c3RvbUJsZW5kaW5nICkge1xuXG5cdFx0XHRpZiAoIGJsZW5kaW5nICE9PSBjdXJyZW50QmxlbmRpbmcgfHwgcHJlbXVsdGlwbGllZEFscGhhICE9PSBjdXJyZW50UHJlbXVsdGlwbGVkQWxwaGEgKSB7XG5cblx0XHRcdFx0aWYgKCBjdXJyZW50QmxlbmRFcXVhdGlvbiAhPT0gQWRkRXF1YXRpb24gfHwgY3VycmVudEJsZW5kRXF1YXRpb25BbHBoYSAhPT0gQWRkRXF1YXRpb24gKSB7XG5cblx0XHRcdFx0XHRnbC5ibGVuZEVxdWF0aW9uKCBnbC5GVU5DX0FERCApO1xuXG5cdFx0XHRcdFx0Y3VycmVudEJsZW5kRXF1YXRpb24gPSBBZGRFcXVhdGlvbjtcblx0XHRcdFx0XHRjdXJyZW50QmxlbmRFcXVhdGlvbkFscGhhID0gQWRkRXF1YXRpb247XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggcHJlbXVsdGlwbGllZEFscGhhICkge1xuXG5cdFx0XHRcdFx0c3dpdGNoICggYmxlbmRpbmcgKSB7XG5cblx0XHRcdFx0XHRcdGNhc2UgTm9ybWFsQmxlbmRpbmc6XG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuY1NlcGFyYXRlKCBnbC5PTkUsIGdsLk9ORV9NSU5VU19TUkNfQUxQSEEsIGdsLk9ORSwgZ2wuT05FX01JTlVTX1NSQ19BTFBIQSApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBBZGRpdGl2ZUJsZW5kaW5nOlxuXHRcdFx0XHRcdFx0XHRnbC5ibGVuZEZ1bmMoIGdsLk9ORSwgZ2wuT05FICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRjYXNlIFN1YnRyYWN0aXZlQmxlbmRpbmc6XG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuY1NlcGFyYXRlKCBnbC5aRVJPLCBnbC5PTkVfTUlOVVNfU1JDX0NPTE9SLCBnbC5aRVJPLCBnbC5PTkUgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdGNhc2UgTXVsdGlwbHlCbGVuZGluZzpcblx0XHRcdFx0XHRcdFx0Z2wuYmxlbmRGdW5jU2VwYXJhdGUoIGdsLlpFUk8sIGdsLlNSQ19DT0xPUiwgZ2wuWkVSTywgZ2wuU1JDX0FMUEhBICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTogSW52YWxpZCBibGVuZGluZzogJywgYmxlbmRpbmcgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHN3aXRjaCAoIGJsZW5kaW5nICkge1xuXG5cdFx0XHRcdFx0XHRjYXNlIE5vcm1hbEJsZW5kaW5nOlxuXHRcdFx0XHRcdFx0XHRnbC5ibGVuZEZ1bmNTZXBhcmF0ZSggZ2wuU1JDX0FMUEhBLCBnbC5PTkVfTUlOVVNfU1JDX0FMUEhBLCBnbC5PTkUsIGdsLk9ORV9NSU5VU19TUkNfQUxQSEEgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdGNhc2UgQWRkaXRpdmVCbGVuZGluZzpcblx0XHRcdFx0XHRcdFx0Z2wuYmxlbmRGdW5jKCBnbC5TUkNfQUxQSEEsIGdsLk9ORSApO1xuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBTdWJ0cmFjdGl2ZUJsZW5kaW5nOlxuXHRcdFx0XHRcdFx0XHRnbC5ibGVuZEZ1bmNTZXBhcmF0ZSggZ2wuWkVSTywgZ2wuT05FX01JTlVTX1NSQ19DT0xPUiwgZ2wuWkVSTywgZ2wuT05FICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRjYXNlIE11bHRpcGx5QmxlbmRpbmc6XG5cdFx0XHRcdFx0XHRcdGdsLmJsZW5kRnVuYyggZ2wuWkVSTywgZ2wuU1JDX0NPTE9SICk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTogSW52YWxpZCBibGVuZGluZzogJywgYmxlbmRpbmcgKTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGN1cnJlbnRCbGVuZFNyYyA9IG51bGw7XG5cdFx0XHRcdGN1cnJlbnRCbGVuZERzdCA9IG51bGw7XG5cdFx0XHRcdGN1cnJlbnRCbGVuZFNyY0FscGhhID0gbnVsbDtcblx0XHRcdFx0Y3VycmVudEJsZW5kRHN0QWxwaGEgPSBudWxsO1xuXHRcdFx0XHRjdXJyZW50QmxlbmRDb2xvci5zZXQoIDAsIDAsIDAgKTtcblx0XHRcdFx0Y3VycmVudEJsZW5kQWxwaGEgPSAwO1xuXG5cdFx0XHRcdGN1cnJlbnRCbGVuZGluZyA9IGJsZW5kaW5nO1xuXHRcdFx0XHRjdXJyZW50UHJlbXVsdGlwbGVkQWxwaGEgPSBwcmVtdWx0aXBsaWVkQWxwaGE7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0Ly8gY3VzdG9tIGJsZW5kaW5nXG5cblx0XHRibGVuZEVxdWF0aW9uQWxwaGEgPSBibGVuZEVxdWF0aW9uQWxwaGEgfHwgYmxlbmRFcXVhdGlvbjtcblx0XHRibGVuZFNyY0FscGhhID0gYmxlbmRTcmNBbHBoYSB8fCBibGVuZFNyYztcblx0XHRibGVuZERzdEFscGhhID0gYmxlbmREc3RBbHBoYSB8fCBibGVuZERzdDtcblxuXHRcdGlmICggYmxlbmRFcXVhdGlvbiAhPT0gY3VycmVudEJsZW5kRXF1YXRpb24gfHwgYmxlbmRFcXVhdGlvbkFscGhhICE9PSBjdXJyZW50QmxlbmRFcXVhdGlvbkFscGhhICkge1xuXG5cdFx0XHRnbC5ibGVuZEVxdWF0aW9uU2VwYXJhdGUoIGVxdWF0aW9uVG9HTFsgYmxlbmRFcXVhdGlvbiBdLCBlcXVhdGlvblRvR0xbIGJsZW5kRXF1YXRpb25BbHBoYSBdICk7XG5cblx0XHRcdGN1cnJlbnRCbGVuZEVxdWF0aW9uID0gYmxlbmRFcXVhdGlvbjtcblx0XHRcdGN1cnJlbnRCbGVuZEVxdWF0aW9uQWxwaGEgPSBibGVuZEVxdWF0aW9uQWxwaGE7XG5cblx0XHR9XG5cblx0XHRpZiAoIGJsZW5kU3JjICE9PSBjdXJyZW50QmxlbmRTcmMgfHwgYmxlbmREc3QgIT09IGN1cnJlbnRCbGVuZERzdCB8fCBibGVuZFNyY0FscGhhICE9PSBjdXJyZW50QmxlbmRTcmNBbHBoYSB8fCBibGVuZERzdEFscGhhICE9PSBjdXJyZW50QmxlbmREc3RBbHBoYSApIHtcblxuXHRcdFx0Z2wuYmxlbmRGdW5jU2VwYXJhdGUoIGZhY3RvclRvR0xbIGJsZW5kU3JjIF0sIGZhY3RvclRvR0xbIGJsZW5kRHN0IF0sIGZhY3RvclRvR0xbIGJsZW5kU3JjQWxwaGEgXSwgZmFjdG9yVG9HTFsgYmxlbmREc3RBbHBoYSBdICk7XG5cblx0XHRcdGN1cnJlbnRCbGVuZFNyYyA9IGJsZW5kU3JjO1xuXHRcdFx0Y3VycmVudEJsZW5kRHN0ID0gYmxlbmREc3Q7XG5cdFx0XHRjdXJyZW50QmxlbmRTcmNBbHBoYSA9IGJsZW5kU3JjQWxwaGE7XG5cdFx0XHRjdXJyZW50QmxlbmREc3RBbHBoYSA9IGJsZW5kRHN0QWxwaGE7XG5cblx0XHR9XG5cblx0XHRpZiAoIGJsZW5kQ29sb3IuZXF1YWxzKCBjdXJyZW50QmxlbmRDb2xvciApID09PSBmYWxzZSB8fCBibGVuZEFscGhhICE9PSBjdXJyZW50QmxlbmRBbHBoYSApIHtcblxuXHRcdFx0Z2wuYmxlbmRDb2xvciggYmxlbmRDb2xvci5yLCBibGVuZENvbG9yLmcsIGJsZW5kQ29sb3IuYiwgYmxlbmRBbHBoYSApO1xuXG5cdFx0XHRjdXJyZW50QmxlbmRDb2xvci5jb3B5KCBibGVuZENvbG9yICk7XG5cdFx0XHRjdXJyZW50QmxlbmRBbHBoYSA9IGJsZW5kQWxwaGE7XG5cblx0XHR9XG5cblx0XHRjdXJyZW50QmxlbmRpbmcgPSBibGVuZGluZztcblx0XHRjdXJyZW50UHJlbXVsdGlwbGVkQWxwaGEgPSBmYWxzZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gc2V0TWF0ZXJpYWwoIG1hdGVyaWFsLCBmcm9udEZhY2VDVyApIHtcblxuXHRcdG1hdGVyaWFsLnNpZGUgPT09IERvdWJsZVNpZGVcblx0XHRcdD8gZGlzYWJsZSggZ2wuQ1VMTF9GQUNFIClcblx0XHRcdDogZW5hYmxlKCBnbC5DVUxMX0ZBQ0UgKTtcblxuXHRcdGxldCBmbGlwU2lkZWQgPSAoIG1hdGVyaWFsLnNpZGUgPT09IEJhY2tTaWRlICk7XG5cdFx0aWYgKCBmcm9udEZhY2VDVyApIGZsaXBTaWRlZCA9ICEgZmxpcFNpZGVkO1xuXG5cdFx0c2V0RmxpcFNpZGVkKCBmbGlwU2lkZWQgKTtcblxuXHRcdCggbWF0ZXJpYWwuYmxlbmRpbmcgPT09IE5vcm1hbEJsZW5kaW5nICYmIG1hdGVyaWFsLnRyYW5zcGFyZW50ID09PSBmYWxzZSApXG5cdFx0XHQ/IHNldEJsZW5kaW5nKCBOb0JsZW5kaW5nIClcblx0XHRcdDogc2V0QmxlbmRpbmcoIG1hdGVyaWFsLmJsZW5kaW5nLCBtYXRlcmlhbC5ibGVuZEVxdWF0aW9uLCBtYXRlcmlhbC5ibGVuZFNyYywgbWF0ZXJpYWwuYmxlbmREc3QsIG1hdGVyaWFsLmJsZW5kRXF1YXRpb25BbHBoYSwgbWF0ZXJpYWwuYmxlbmRTcmNBbHBoYSwgbWF0ZXJpYWwuYmxlbmREc3RBbHBoYSwgbWF0ZXJpYWwuYmxlbmRDb2xvciwgbWF0ZXJpYWwuYmxlbmRBbHBoYSwgbWF0ZXJpYWwucHJlbXVsdGlwbGllZEFscGhhICk7XG5cblx0XHRkZXB0aEJ1ZmZlci5zZXRGdW5jKCBtYXRlcmlhbC5kZXB0aEZ1bmMgKTtcblx0XHRkZXB0aEJ1ZmZlci5zZXRUZXN0KCBtYXRlcmlhbC5kZXB0aFRlc3QgKTtcblx0XHRkZXB0aEJ1ZmZlci5zZXRNYXNrKCBtYXRlcmlhbC5kZXB0aFdyaXRlICk7XG5cdFx0Y29sb3JCdWZmZXIuc2V0TWFzayggbWF0ZXJpYWwuY29sb3JXcml0ZSApO1xuXG5cdFx0Y29uc3Qgc3RlbmNpbFdyaXRlID0gbWF0ZXJpYWwuc3RlbmNpbFdyaXRlO1xuXHRcdHN0ZW5jaWxCdWZmZXIuc2V0VGVzdCggc3RlbmNpbFdyaXRlICk7XG5cdFx0aWYgKCBzdGVuY2lsV3JpdGUgKSB7XG5cblx0XHRcdHN0ZW5jaWxCdWZmZXIuc2V0TWFzayggbWF0ZXJpYWwuc3RlbmNpbFdyaXRlTWFzayApO1xuXHRcdFx0c3RlbmNpbEJ1ZmZlci5zZXRGdW5jKCBtYXRlcmlhbC5zdGVuY2lsRnVuYywgbWF0ZXJpYWwuc3RlbmNpbFJlZiwgbWF0ZXJpYWwuc3RlbmNpbEZ1bmNNYXNrICk7XG5cdFx0XHRzdGVuY2lsQnVmZmVyLnNldE9wKCBtYXRlcmlhbC5zdGVuY2lsRmFpbCwgbWF0ZXJpYWwuc3RlbmNpbFpGYWlsLCBtYXRlcmlhbC5zdGVuY2lsWlBhc3MgKTtcblxuXHRcdH1cblxuXHRcdHNldFBvbHlnb25PZmZzZXQoIG1hdGVyaWFsLnBvbHlnb25PZmZzZXQsIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRGYWN0b3IsIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRVbml0cyApO1xuXG5cdFx0bWF0ZXJpYWwuYWxwaGFUb0NvdmVyYWdlID09PSB0cnVlXG5cdFx0XHQ/IGVuYWJsZSggZ2wuU0FNUExFX0FMUEhBX1RPX0NPVkVSQUdFIClcblx0XHRcdDogZGlzYWJsZSggZ2wuU0FNUExFX0FMUEhBX1RPX0NPVkVSQUdFICk7XG5cblx0fVxuXG5cdC8vXG5cblx0ZnVuY3Rpb24gc2V0RmxpcFNpZGVkKCBmbGlwU2lkZWQgKSB7XG5cblx0XHRpZiAoIGN1cnJlbnRGbGlwU2lkZWQgIT09IGZsaXBTaWRlZCApIHtcblxuXHRcdFx0aWYgKCBmbGlwU2lkZWQgKSB7XG5cblx0XHRcdFx0Z2wuZnJvbnRGYWNlKCBnbC5DVyApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGdsLmZyb250RmFjZSggZ2wuQ0NXICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Y3VycmVudEZsaXBTaWRlZCA9IGZsaXBTaWRlZDtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gc2V0Q3VsbEZhY2UoIGN1bGxGYWNlICkge1xuXG5cdFx0aWYgKCBjdWxsRmFjZSAhPT0gQ3VsbEZhY2VOb25lICkge1xuXG5cdFx0XHRlbmFibGUoIGdsLkNVTExfRkFDRSApO1xuXG5cdFx0XHRpZiAoIGN1bGxGYWNlICE9PSBjdXJyZW50Q3VsbEZhY2UgKSB7XG5cblx0XHRcdFx0aWYgKCBjdWxsRmFjZSA9PT0gQ3VsbEZhY2VCYWNrICkge1xuXG5cdFx0XHRcdFx0Z2wuY3VsbEZhY2UoIGdsLkJBQ0sgKTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBjdWxsRmFjZSA9PT0gQ3VsbEZhY2VGcm9udCApIHtcblxuXHRcdFx0XHRcdGdsLmN1bGxGYWNlKCBnbC5GUk9OVCApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRnbC5jdWxsRmFjZSggZ2wuRlJPTlRfQU5EX0JBQ0sgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGRpc2FibGUoIGdsLkNVTExfRkFDRSApO1xuXG5cdFx0fVxuXG5cdFx0Y3VycmVudEN1bGxGYWNlID0gY3VsbEZhY2U7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHNldExpbmVXaWR0aCggd2lkdGggKSB7XG5cblx0XHRpZiAoIHdpZHRoICE9PSBjdXJyZW50TGluZVdpZHRoICkge1xuXG5cdFx0XHRpZiAoIGxpbmVXaWR0aEF2YWlsYWJsZSApIGdsLmxpbmVXaWR0aCggd2lkdGggKTtcblxuXHRcdFx0Y3VycmVudExpbmVXaWR0aCA9IHdpZHRoO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBzZXRQb2x5Z29uT2Zmc2V0KCBwb2x5Z29uT2Zmc2V0LCBmYWN0b3IsIHVuaXRzICkge1xuXG5cdFx0aWYgKCBwb2x5Z29uT2Zmc2V0ICkge1xuXG5cdFx0XHRlbmFibGUoIGdsLlBPTFlHT05fT0ZGU0VUX0ZJTEwgKTtcblxuXHRcdFx0aWYgKCBjdXJyZW50UG9seWdvbk9mZnNldEZhY3RvciAhPT0gZmFjdG9yIHx8IGN1cnJlbnRQb2x5Z29uT2Zmc2V0VW5pdHMgIT09IHVuaXRzICkge1xuXG5cdFx0XHRcdGdsLnBvbHlnb25PZmZzZXQoIGZhY3RvciwgdW5pdHMgKTtcblxuXHRcdFx0XHRjdXJyZW50UG9seWdvbk9mZnNldEZhY3RvciA9IGZhY3Rvcjtcblx0XHRcdFx0Y3VycmVudFBvbHlnb25PZmZzZXRVbml0cyA9IHVuaXRzO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRkaXNhYmxlKCBnbC5QT0xZR09OX09GRlNFVF9GSUxMICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHNldFNjaXNzb3JUZXN0KCBzY2lzc29yVGVzdCApIHtcblxuXHRcdGlmICggc2Npc3NvclRlc3QgKSB7XG5cblx0XHRcdGVuYWJsZSggZ2wuU0NJU1NPUl9URVNUICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRkaXNhYmxlKCBnbC5TQ0lTU09SX1RFU1QgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Ly8gdGV4dHVyZVxuXG5cdGZ1bmN0aW9uIGFjdGl2ZVRleHR1cmUoIHdlYmdsU2xvdCApIHtcblxuXHRcdGlmICggd2ViZ2xTbG90ID09PSB1bmRlZmluZWQgKSB3ZWJnbFNsb3QgPSBnbC5URVhUVVJFMCArIG1heFRleHR1cmVzIC0gMTtcblxuXHRcdGlmICggY3VycmVudFRleHR1cmVTbG90ICE9PSB3ZWJnbFNsb3QgKSB7XG5cblx0XHRcdGdsLmFjdGl2ZVRleHR1cmUoIHdlYmdsU2xvdCApO1xuXHRcdFx0Y3VycmVudFRleHR1cmVTbG90ID0gd2ViZ2xTbG90O1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBiaW5kVGV4dHVyZSggd2ViZ2xUeXBlLCB3ZWJnbFRleHR1cmUsIHdlYmdsU2xvdCApIHtcblxuXHRcdGlmICggd2ViZ2xTbG90ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGlmICggY3VycmVudFRleHR1cmVTbG90ID09PSBudWxsICkge1xuXG5cdFx0XHRcdHdlYmdsU2xvdCA9IGdsLlRFWFRVUkUwICsgbWF4VGV4dHVyZXMgLSAxO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHdlYmdsU2xvdCA9IGN1cnJlbnRUZXh0dXJlU2xvdDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0bGV0IGJvdW5kVGV4dHVyZSA9IGN1cnJlbnRCb3VuZFRleHR1cmVzWyB3ZWJnbFNsb3QgXTtcblxuXHRcdGlmICggYm91bmRUZXh0dXJlID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGJvdW5kVGV4dHVyZSA9IHsgdHlwZTogdW5kZWZpbmVkLCB0ZXh0dXJlOiB1bmRlZmluZWQgfTtcblx0XHRcdGN1cnJlbnRCb3VuZFRleHR1cmVzWyB3ZWJnbFNsb3QgXSA9IGJvdW5kVGV4dHVyZTtcblxuXHRcdH1cblxuXHRcdGlmICggYm91bmRUZXh0dXJlLnR5cGUgIT09IHdlYmdsVHlwZSB8fCBib3VuZFRleHR1cmUudGV4dHVyZSAhPT0gd2ViZ2xUZXh0dXJlICkge1xuXG5cdFx0XHRpZiAoIGN1cnJlbnRUZXh0dXJlU2xvdCAhPT0gd2ViZ2xTbG90ICkge1xuXG5cdFx0XHRcdGdsLmFjdGl2ZVRleHR1cmUoIHdlYmdsU2xvdCApO1xuXHRcdFx0XHRjdXJyZW50VGV4dHVyZVNsb3QgPSB3ZWJnbFNsb3Q7XG5cblx0XHRcdH1cblxuXHRcdFx0Z2wuYmluZFRleHR1cmUoIHdlYmdsVHlwZSwgd2ViZ2xUZXh0dXJlIHx8IGVtcHR5VGV4dHVyZXNbIHdlYmdsVHlwZSBdICk7XG5cblx0XHRcdGJvdW5kVGV4dHVyZS50eXBlID0gd2ViZ2xUeXBlO1xuXHRcdFx0Ym91bmRUZXh0dXJlLnRleHR1cmUgPSB3ZWJnbFRleHR1cmU7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHVuYmluZFRleHR1cmUoKSB7XG5cblx0XHRjb25zdCBib3VuZFRleHR1cmUgPSBjdXJyZW50Qm91bmRUZXh0dXJlc1sgY3VycmVudFRleHR1cmVTbG90IF07XG5cblx0XHRpZiAoIGJvdW5kVGV4dHVyZSAhPT0gdW5kZWZpbmVkICYmIGJvdW5kVGV4dHVyZS50eXBlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGdsLmJpbmRUZXh0dXJlKCBib3VuZFRleHR1cmUudHlwZSwgbnVsbCApO1xuXG5cdFx0XHRib3VuZFRleHR1cmUudHlwZSA9IHVuZGVmaW5lZDtcblx0XHRcdGJvdW5kVGV4dHVyZS50ZXh0dXJlID0gdW5kZWZpbmVkO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBjb21wcmVzc2VkVGV4SW1hZ2UyRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLmNvbXByZXNzZWRUZXhJbWFnZTJELmFwcGx5KCBnbCwgYXJndW1lbnRzICk7XG5cblx0XHR9IGNhdGNoICggZXJyb3IgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGNvbXByZXNzZWRUZXhJbWFnZTNEKCkge1xuXG5cdFx0dHJ5IHtcblxuXHRcdFx0Z2wuY29tcHJlc3NlZFRleEltYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gdGV4U3ViSW1hZ2UyRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLnRleFN1YkltYWdlMkQuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gdGV4U3ViSW1hZ2UzRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLnRleFN1YkltYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gY29tcHJlc3NlZFRleFN1YkltYWdlMkQoKSB7XG5cblx0XHR0cnkge1xuXG5cdFx0XHRnbC5jb21wcmVzc2VkVGV4U3ViSW1hZ2UyRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xuXG5cdFx0fSBjYXRjaCAoIGVycm9yICkge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTonLCBlcnJvciApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiBjb21wcmVzc2VkVGV4U3ViSW1hZ2UzRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLmNvbXByZXNzZWRUZXhTdWJJbWFnZTNELmFwcGx5KCBnbCwgYXJndW1lbnRzICk7XG5cblx0XHR9IGNhdGNoICggZXJyb3IgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFN0YXRlOicsIGVycm9yICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHRleFN0b3JhZ2UyRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLnRleFN0b3JhZ2UyRC5hcHBseSggZ2wsIGFyZ3VtZW50cyApO1xuXG5cdFx0fSBjYXRjaCAoIGVycm9yICkge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xTdGF0ZTonLCBlcnJvciApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB0ZXhTdG9yYWdlM0QoKSB7XG5cblx0XHR0cnkge1xuXG5cdFx0XHRnbC50ZXhTdG9yYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gdGV4SW1hZ2UyRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLnRleEltYWdlMkQuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gdGV4SW1hZ2UzRCgpIHtcblxuXHRcdHRyeSB7XG5cblx0XHRcdGdsLnRleEltYWdlM0QuYXBwbHkoIGdsLCBhcmd1bWVudHMgKTtcblxuXHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMU3RhdGU6JywgZXJyb3IgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Ly9cblxuXHRmdW5jdGlvbiBzY2lzc29yKCBzY2lzc29yICkge1xuXG5cdFx0aWYgKCBjdXJyZW50U2Npc3Nvci5lcXVhbHMoIHNjaXNzb3IgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdGdsLnNjaXNzb3IoIHNjaXNzb3IueCwgc2Npc3Nvci55LCBzY2lzc29yLnosIHNjaXNzb3IudyApO1xuXHRcdFx0Y3VycmVudFNjaXNzb3IuY29weSggc2Npc3NvciApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB2aWV3cG9ydCggdmlld3BvcnQgKSB7XG5cblx0XHRpZiAoIGN1cnJlbnRWaWV3cG9ydC5lcXVhbHMoIHZpZXdwb3J0ICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRnbC52aWV3cG9ydCggdmlld3BvcnQueCwgdmlld3BvcnQueSwgdmlld3BvcnQueiwgdmlld3BvcnQudyApO1xuXHRcdFx0Y3VycmVudFZpZXdwb3J0LmNvcHkoIHZpZXdwb3J0ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHVwZGF0ZVVCT01hcHBpbmcoIHVuaWZvcm1zR3JvdXAsIHByb2dyYW0gKSB7XG5cblx0XHRsZXQgbWFwcGluZyA9IHVib1Byb2dyYW1NYXAuZ2V0KCBwcm9ncmFtICk7XG5cblx0XHRpZiAoIG1hcHBpbmcgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0bWFwcGluZyA9IG5ldyBXZWFrTWFwKCk7XG5cblx0XHRcdHVib1Byb2dyYW1NYXAuc2V0KCBwcm9ncmFtLCBtYXBwaW5nICk7XG5cblx0XHR9XG5cblx0XHRsZXQgYmxvY2tJbmRleCA9IG1hcHBpbmcuZ2V0KCB1bmlmb3Jtc0dyb3VwICk7XG5cblx0XHRpZiAoIGJsb2NrSW5kZXggPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0YmxvY2tJbmRleCA9IGdsLmdldFVuaWZvcm1CbG9ja0luZGV4KCBwcm9ncmFtLCB1bmlmb3Jtc0dyb3VwLm5hbWUgKTtcblxuXHRcdFx0bWFwcGluZy5zZXQoIHVuaWZvcm1zR3JvdXAsIGJsb2NrSW5kZXggKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gdW5pZm9ybUJsb2NrQmluZGluZyggdW5pZm9ybXNHcm91cCwgcHJvZ3JhbSApIHtcblxuXHRcdGNvbnN0IG1hcHBpbmcgPSB1Ym9Qcm9ncmFtTWFwLmdldCggcHJvZ3JhbSApO1xuXHRcdGNvbnN0IGJsb2NrSW5kZXggPSBtYXBwaW5nLmdldCggdW5pZm9ybXNHcm91cCApO1xuXG5cdFx0aWYgKCB1Ym9CaW5kaW5ncy5nZXQoIHByb2dyYW0gKSAhPT0gYmxvY2tJbmRleCApIHtcblxuXHRcdFx0Ly8gYmluZCBzaGFkZXIgc3BlY2lmaWMgYmxvY2sgaW5kZXggdG8gZ2xvYmFsIGJsb2NrIHBvaW50XG5cdFx0XHRnbC51bmlmb3JtQmxvY2tCaW5kaW5nKCBwcm9ncmFtLCBibG9ja0luZGV4LCB1bmlmb3Jtc0dyb3VwLl9fYmluZGluZ1BvaW50SW5kZXggKTtcblxuXHRcdFx0dWJvQmluZGluZ3Muc2V0KCBwcm9ncmFtLCBibG9ja0luZGV4ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdC8vXG5cblx0ZnVuY3Rpb24gcmVzZXQoKSB7XG5cblx0XHQvLyByZXNldCBzdGF0ZVxuXG5cdFx0Z2wuZGlzYWJsZSggZ2wuQkxFTkQgKTtcblx0XHRnbC5kaXNhYmxlKCBnbC5DVUxMX0ZBQ0UgKTtcblx0XHRnbC5kaXNhYmxlKCBnbC5ERVBUSF9URVNUICk7XG5cdFx0Z2wuZGlzYWJsZSggZ2wuUE9MWUdPTl9PRkZTRVRfRklMTCApO1xuXHRcdGdsLmRpc2FibGUoIGdsLlNDSVNTT1JfVEVTVCApO1xuXHRcdGdsLmRpc2FibGUoIGdsLlNURU5DSUxfVEVTVCApO1xuXHRcdGdsLmRpc2FibGUoIGdsLlNBTVBMRV9BTFBIQV9UT19DT1ZFUkFHRSApO1xuXG5cdFx0Z2wuYmxlbmRFcXVhdGlvbiggZ2wuRlVOQ19BREQgKTtcblx0XHRnbC5ibGVuZEZ1bmMoIGdsLk9ORSwgZ2wuWkVSTyApO1xuXHRcdGdsLmJsZW5kRnVuY1NlcGFyYXRlKCBnbC5PTkUsIGdsLlpFUk8sIGdsLk9ORSwgZ2wuWkVSTyApO1xuXHRcdGdsLmJsZW5kQ29sb3IoIDAsIDAsIDAsIDAgKTtcblxuXHRcdGdsLmNvbG9yTWFzayggdHJ1ZSwgdHJ1ZSwgdHJ1ZSwgdHJ1ZSApO1xuXHRcdGdsLmNsZWFyQ29sb3IoIDAsIDAsIDAsIDAgKTtcblxuXHRcdGdsLmRlcHRoTWFzayggdHJ1ZSApO1xuXHRcdGdsLmRlcHRoRnVuYyggZ2wuTEVTUyApO1xuXHRcdGdsLmNsZWFyRGVwdGgoIDEgKTtcblxuXHRcdGdsLnN0ZW5jaWxNYXNrKCAweGZmZmZmZmZmICk7XG5cdFx0Z2wuc3RlbmNpbEZ1bmMoIGdsLkFMV0FZUywgMCwgMHhmZmZmZmZmZiApO1xuXHRcdGdsLnN0ZW5jaWxPcCggZ2wuS0VFUCwgZ2wuS0VFUCwgZ2wuS0VFUCApO1xuXHRcdGdsLmNsZWFyU3RlbmNpbCggMCApO1xuXG5cdFx0Z2wuY3VsbEZhY2UoIGdsLkJBQ0sgKTtcblx0XHRnbC5mcm9udEZhY2UoIGdsLkNDVyApO1xuXG5cdFx0Z2wucG9seWdvbk9mZnNldCggMCwgMCApO1xuXG5cdFx0Z2wuYWN0aXZlVGV4dHVyZSggZ2wuVEVYVFVSRTAgKTtcblxuXHRcdGdsLmJpbmRGcmFtZWJ1ZmZlciggZ2wuRlJBTUVCVUZGRVIsIG51bGwgKTtcblx0XHRnbC5iaW5kRnJhbWVidWZmZXIoIGdsLkRSQVdfRlJBTUVCVUZGRVIsIG51bGwgKTtcblx0XHRnbC5iaW5kRnJhbWVidWZmZXIoIGdsLlJFQURfRlJBTUVCVUZGRVIsIG51bGwgKTtcblxuXHRcdGdsLnVzZVByb2dyYW0oIG51bGwgKTtcblxuXHRcdGdsLmxpbmVXaWR0aCggMSApO1xuXG5cdFx0Z2wuc2Npc3NvciggMCwgMCwgZ2wuY2FudmFzLndpZHRoLCBnbC5jYW52YXMuaGVpZ2h0ICk7XG5cdFx0Z2wudmlld3BvcnQoIDAsIDAsIGdsLmNhbnZhcy53aWR0aCwgZ2wuY2FudmFzLmhlaWdodCApO1xuXG5cdFx0Ly8gcmVzZXQgaW50ZXJuYWxzXG5cblx0XHRlbmFibGVkQ2FwYWJpbGl0aWVzID0ge307XG5cblx0XHRjdXJyZW50VGV4dHVyZVNsb3QgPSBudWxsO1xuXHRcdGN1cnJlbnRCb3VuZFRleHR1cmVzID0ge307XG5cblx0XHRjdXJyZW50Qm91bmRGcmFtZWJ1ZmZlcnMgPSB7fTtcblx0XHRjdXJyZW50RHJhd2J1ZmZlcnMgPSBuZXcgV2Vha01hcCgpO1xuXHRcdGRlZmF1bHREcmF3YnVmZmVycyA9IFtdO1xuXG5cdFx0Y3VycmVudFByb2dyYW0gPSBudWxsO1xuXG5cdFx0Y3VycmVudEJsZW5kaW5nRW5hYmxlZCA9IGZhbHNlO1xuXHRcdGN1cnJlbnRCbGVuZGluZyA9IG51bGw7XG5cdFx0Y3VycmVudEJsZW5kRXF1YXRpb24gPSBudWxsO1xuXHRcdGN1cnJlbnRCbGVuZFNyYyA9IG51bGw7XG5cdFx0Y3VycmVudEJsZW5kRHN0ID0gbnVsbDtcblx0XHRjdXJyZW50QmxlbmRFcXVhdGlvbkFscGhhID0gbnVsbDtcblx0XHRjdXJyZW50QmxlbmRTcmNBbHBoYSA9IG51bGw7XG5cdFx0Y3VycmVudEJsZW5kRHN0QWxwaGEgPSBudWxsO1xuXHRcdGN1cnJlbnRCbGVuZENvbG9yID0gbmV3IENvbG9yKCAwLCAwLCAwICk7XG5cdFx0Y3VycmVudEJsZW5kQWxwaGEgPSAwO1xuXHRcdGN1cnJlbnRQcmVtdWx0aXBsZWRBbHBoYSA9IGZhbHNlO1xuXG5cdFx0Y3VycmVudEZsaXBTaWRlZCA9IG51bGw7XG5cdFx0Y3VycmVudEN1bGxGYWNlID0gbnVsbDtcblxuXHRcdGN1cnJlbnRMaW5lV2lkdGggPSBudWxsO1xuXG5cdFx0Y3VycmVudFBvbHlnb25PZmZzZXRGYWN0b3IgPSBudWxsO1xuXHRcdGN1cnJlbnRQb2x5Z29uT2Zmc2V0VW5pdHMgPSBudWxsO1xuXG5cdFx0Y3VycmVudFNjaXNzb3Iuc2V0KCAwLCAwLCBnbC5jYW52YXMud2lkdGgsIGdsLmNhbnZhcy5oZWlnaHQgKTtcblx0XHRjdXJyZW50Vmlld3BvcnQuc2V0KCAwLCAwLCBnbC5jYW52YXMud2lkdGgsIGdsLmNhbnZhcy5oZWlnaHQgKTtcblxuXHRcdGNvbG9yQnVmZmVyLnJlc2V0KCk7XG5cdFx0ZGVwdGhCdWZmZXIucmVzZXQoKTtcblx0XHRzdGVuY2lsQnVmZmVyLnJlc2V0KCk7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cblx0XHRidWZmZXJzOiB7XG5cdFx0XHRjb2xvcjogY29sb3JCdWZmZXIsXG5cdFx0XHRkZXB0aDogZGVwdGhCdWZmZXIsXG5cdFx0XHRzdGVuY2lsOiBzdGVuY2lsQnVmZmVyXG5cdFx0fSxcblxuXHRcdGVuYWJsZTogZW5hYmxlLFxuXHRcdGRpc2FibGU6IGRpc2FibGUsXG5cblx0XHRiaW5kRnJhbWVidWZmZXI6IGJpbmRGcmFtZWJ1ZmZlcixcblx0XHRkcmF3QnVmZmVyczogZHJhd0J1ZmZlcnMsXG5cblx0XHR1c2VQcm9ncmFtOiB1c2VQcm9ncmFtLFxuXG5cdFx0c2V0QmxlbmRpbmc6IHNldEJsZW5kaW5nLFxuXHRcdHNldE1hdGVyaWFsOiBzZXRNYXRlcmlhbCxcblxuXHRcdHNldEZsaXBTaWRlZDogc2V0RmxpcFNpZGVkLFxuXHRcdHNldEN1bGxGYWNlOiBzZXRDdWxsRmFjZSxcblxuXHRcdHNldExpbmVXaWR0aDogc2V0TGluZVdpZHRoLFxuXHRcdHNldFBvbHlnb25PZmZzZXQ6IHNldFBvbHlnb25PZmZzZXQsXG5cblx0XHRzZXRTY2lzc29yVGVzdDogc2V0U2Npc3NvclRlc3QsXG5cblx0XHRhY3RpdmVUZXh0dXJlOiBhY3RpdmVUZXh0dXJlLFxuXHRcdGJpbmRUZXh0dXJlOiBiaW5kVGV4dHVyZSxcblx0XHR1bmJpbmRUZXh0dXJlOiB1bmJpbmRUZXh0dXJlLFxuXHRcdGNvbXByZXNzZWRUZXhJbWFnZTJEOiBjb21wcmVzc2VkVGV4SW1hZ2UyRCxcblx0XHRjb21wcmVzc2VkVGV4SW1hZ2UzRDogY29tcHJlc3NlZFRleEltYWdlM0QsXG5cdFx0dGV4SW1hZ2UyRDogdGV4SW1hZ2UyRCxcblx0XHR0ZXhJbWFnZTNEOiB0ZXhJbWFnZTNELFxuXG5cdFx0dXBkYXRlVUJPTWFwcGluZzogdXBkYXRlVUJPTWFwcGluZyxcblx0XHR1bmlmb3JtQmxvY2tCaW5kaW5nOiB1bmlmb3JtQmxvY2tCaW5kaW5nLFxuXG5cdFx0dGV4U3RvcmFnZTJEOiB0ZXhTdG9yYWdlMkQsXG5cdFx0dGV4U3RvcmFnZTNEOiB0ZXhTdG9yYWdlM0QsXG5cdFx0dGV4U3ViSW1hZ2UyRDogdGV4U3ViSW1hZ2UyRCxcblx0XHR0ZXhTdWJJbWFnZTNEOiB0ZXhTdWJJbWFnZTNELFxuXHRcdGNvbXByZXNzZWRUZXhTdWJJbWFnZTJEOiBjb21wcmVzc2VkVGV4U3ViSW1hZ2UyRCxcblx0XHRjb21wcmVzc2VkVGV4U3ViSW1hZ2UzRDogY29tcHJlc3NlZFRleFN1YkltYWdlM0QsXG5cblx0XHRzY2lzc29yOiBzY2lzc29yLFxuXHRcdHZpZXdwb3J0OiB2aWV3cG9ydCxcblxuXHRcdHJlc2V0OiByZXNldFxuXG5cdH07XG5cbn1cblxuZnVuY3Rpb24gY29udGFpbiggdGV4dHVyZSwgYXNwZWN0ICkge1xuXG5cdGNvbnN0IGltYWdlQXNwZWN0ID0gKCB0ZXh0dXJlLmltYWdlICYmIHRleHR1cmUuaW1hZ2Uud2lkdGggKSA/IHRleHR1cmUuaW1hZ2Uud2lkdGggLyB0ZXh0dXJlLmltYWdlLmhlaWdodCA6IDE7XG5cblx0aWYgKCBpbWFnZUFzcGVjdCA+IGFzcGVjdCApIHtcblxuXHRcdHRleHR1cmUucmVwZWF0LnggPSAxO1xuXHRcdHRleHR1cmUucmVwZWF0LnkgPSBpbWFnZUFzcGVjdCAvIGFzcGVjdDtcblxuXHRcdHRleHR1cmUub2Zmc2V0LnggPSAwO1xuXHRcdHRleHR1cmUub2Zmc2V0LnkgPSAoIDEgLSB0ZXh0dXJlLnJlcGVhdC55ICkgLyAyO1xuXG5cdH0gZWxzZSB7XG5cblx0XHR0ZXh0dXJlLnJlcGVhdC54ID0gYXNwZWN0IC8gaW1hZ2VBc3BlY3Q7XG5cdFx0dGV4dHVyZS5yZXBlYXQueSA9IDE7XG5cblx0XHR0ZXh0dXJlLm9mZnNldC54ID0gKCAxIC0gdGV4dHVyZS5yZXBlYXQueCApIC8gMjtcblx0XHR0ZXh0dXJlLm9mZnNldC55ID0gMDtcblxuXHR9XG5cblx0cmV0dXJuIHRleHR1cmU7XG5cbn1cblxuZnVuY3Rpb24gY292ZXIoIHRleHR1cmUsIGFzcGVjdCApIHtcblxuXHRjb25zdCBpbWFnZUFzcGVjdCA9ICggdGV4dHVyZS5pbWFnZSAmJiB0ZXh0dXJlLmltYWdlLndpZHRoICkgPyB0ZXh0dXJlLmltYWdlLndpZHRoIC8gdGV4dHVyZS5pbWFnZS5oZWlnaHQgOiAxO1xuXG5cdGlmICggaW1hZ2VBc3BlY3QgPiBhc3BlY3QgKSB7XG5cblx0XHR0ZXh0dXJlLnJlcGVhdC54ID0gYXNwZWN0IC8gaW1hZ2VBc3BlY3Q7XG5cdFx0dGV4dHVyZS5yZXBlYXQueSA9IDE7XG5cblx0XHR0ZXh0dXJlLm9mZnNldC54ID0gKCAxIC0gdGV4dHVyZS5yZXBlYXQueCApIC8gMjtcblx0XHR0ZXh0dXJlLm9mZnNldC55ID0gMDtcblxuXHR9IGVsc2Uge1xuXG5cdFx0dGV4dHVyZS5yZXBlYXQueCA9IDE7XG5cdFx0dGV4dHVyZS5yZXBlYXQueSA9IGltYWdlQXNwZWN0IC8gYXNwZWN0O1xuXG5cdFx0dGV4dHVyZS5vZmZzZXQueCA9IDA7XG5cdFx0dGV4dHVyZS5vZmZzZXQueSA9ICggMSAtIHRleHR1cmUucmVwZWF0LnkgKSAvIDI7XG5cblx0fVxuXG5cdHJldHVybiB0ZXh0dXJlO1xuXG59XG5cbmZ1bmN0aW9uIGZpbGwoIHRleHR1cmUgKSB7XG5cblx0dGV4dHVyZS5yZXBlYXQueCA9IDE7XG5cdHRleHR1cmUucmVwZWF0LnkgPSAxO1xuXG5cdHRleHR1cmUub2Zmc2V0LnggPSAwO1xuXHR0ZXh0dXJlLm9mZnNldC55ID0gMDtcblxuXHRyZXR1cm4gdGV4dHVyZTtcblxufVxuXG5cblxuLyoqXG4gKiBHaXZlbiB0aGUgd2lkdGgsIGhlaWdodCwgZm9ybWF0LCBhbmQgdHlwZSBvZiBhIHRleHR1cmUuIERldGVybWluZXMgaG93IG1hbnlcbiAqIGJ5dGVzIG11c3QgYmUgdXNlZCB0byByZXByZXNlbnQgdGhlIHRleHR1cmUuXG4gKi9cbmZ1bmN0aW9uIGdldEJ5dGVMZW5ndGgoIHdpZHRoLCBoZWlnaHQsIGZvcm1hdCwgdHlwZSApIHtcblxuXHRjb25zdCB0eXBlQnl0ZUxlbmd0aCA9IGdldFRleHR1cmVUeXBlQnl0ZUxlbmd0aCggdHlwZSApO1xuXG5cdHN3aXRjaCAoIGZvcm1hdCApIHtcblxuXHRcdC8vIGh0dHBzOi8vcmVnaXN0cnkua2hyb25vcy5vcmcvT3BlbkdMLVJlZnBhZ2VzL2VzMy4wL2h0bWwvZ2xUZXhJbWFnZTJELnhodG1sXG5cdFx0Y2FzZSBBbHBoYUZvcm1hdDpcblx0XHRcdHJldHVybiB3aWR0aCAqIGhlaWdodDtcblx0XHRjYXNlIEx1bWluYW5jZUZvcm1hdDpcblx0XHRcdHJldHVybiB3aWR0aCAqIGhlaWdodDtcblx0XHRjYXNlIEx1bWluYW5jZUFscGhhRm9ybWF0OlxuXHRcdFx0cmV0dXJuIHdpZHRoICogaGVpZ2h0ICogMjtcblx0XHRjYXNlIFJlZEZvcm1hdDpcblx0XHRcdHJldHVybiAoICggd2lkdGggKiBoZWlnaHQgKSAvIHR5cGVCeXRlTGVuZ3RoLmNvbXBvbmVudHMgKSAqIHR5cGVCeXRlTGVuZ3RoLmJ5dGVMZW5ndGg7XG5cdFx0Y2FzZSBSZWRJbnRlZ2VyRm9ybWF0OlxuXHRcdFx0cmV0dXJuICggKCB3aWR0aCAqIGhlaWdodCApIC8gdHlwZUJ5dGVMZW5ndGguY29tcG9uZW50cyApICogdHlwZUJ5dGVMZW5ndGguYnl0ZUxlbmd0aDtcblx0XHRjYXNlIFJHRm9ybWF0OlxuXHRcdFx0cmV0dXJuICggKCB3aWR0aCAqIGhlaWdodCAqIDIgKSAvIHR5cGVCeXRlTGVuZ3RoLmNvbXBvbmVudHMgKSAqIHR5cGVCeXRlTGVuZ3RoLmJ5dGVMZW5ndGg7XG5cdFx0Y2FzZSBSR0ludGVnZXJGb3JtYXQ6XG5cdFx0XHRyZXR1cm4gKCAoIHdpZHRoICogaGVpZ2h0ICogMiApIC8gdHlwZUJ5dGVMZW5ndGguY29tcG9uZW50cyApICogdHlwZUJ5dGVMZW5ndGguYnl0ZUxlbmd0aDtcblx0XHRjYXNlIFJHQkZvcm1hdDpcblx0XHRcdHJldHVybiAoICggd2lkdGggKiBoZWlnaHQgKiAzICkgLyB0eXBlQnl0ZUxlbmd0aC5jb21wb25lbnRzICkgKiB0eXBlQnl0ZUxlbmd0aC5ieXRlTGVuZ3RoO1xuXHRcdGNhc2UgUkdCQUZvcm1hdDpcblx0XHRcdHJldHVybiAoICggd2lkdGggKiBoZWlnaHQgKiA0ICkgLyB0eXBlQnl0ZUxlbmd0aC5jb21wb25lbnRzICkgKiB0eXBlQnl0ZUxlbmd0aC5ieXRlTGVuZ3RoO1xuXHRcdGNhc2UgUkdCQUludGVnZXJGb3JtYXQ6XG5cdFx0XHRyZXR1cm4gKCAoIHdpZHRoICogaGVpZ2h0ICogNCApIC8gdHlwZUJ5dGVMZW5ndGguY29tcG9uZW50cyApICogdHlwZUJ5dGVMZW5ndGguYnl0ZUxlbmd0aDtcblxuXHRcdC8vIGh0dHBzOi8vcmVnaXN0cnkua2hyb25vcy5vcmcvd2ViZ2wvZXh0ZW5zaW9ucy9XRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfczN0Y19zcmdiL1xuXHRcdGNhc2UgUkdCX1MzVENfRFhUMV9Gb3JtYXQ6XG5cdFx0Y2FzZSBSR0JBX1MzVENfRFhUMV9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDMgKSAvIDQgKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgMyApIC8gNCApICogODtcblx0XHRjYXNlIFJHQkFfUzNUQ19EWFQzX0Zvcm1hdDpcblx0XHRjYXNlIFJHQkFfUzNUQ19EWFQ1X0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgMyApIC8gNCApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyAzICkgLyA0ICkgKiAxNjtcblxuXHRcdC8vIGh0dHBzOi8vcmVnaXN0cnkua2hyb25vcy5vcmcvd2ViZ2wvZXh0ZW5zaW9ucy9XRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfcHZydGMvXG5cdFx0Y2FzZSBSR0JfUFZSVENfMkJQUFYxX0Zvcm1hdDpcblx0XHRjYXNlIFJHQkFfUFZSVENfMkJQUFYxX0Zvcm1hdDpcblx0XHRcdHJldHVybiAoIE1hdGgubWF4KCB3aWR0aCwgMTYgKSAqIE1hdGgubWF4KCBoZWlnaHQsIDggKSApIC8gNDtcblx0XHRjYXNlIFJHQl9QVlJUQ180QlBQVjFfRm9ybWF0OlxuXHRcdGNhc2UgUkdCQV9QVlJUQ180QlBQVjFfRm9ybWF0OlxuXHRcdFx0cmV0dXJuICggTWF0aC5tYXgoIHdpZHRoLCA4ICkgKiBNYXRoLm1heCggaGVpZ2h0LCA4ICkgKSAvIDI7XG5cblx0XHQvLyBodHRwczovL3JlZ2lzdHJ5Lmtocm9ub3Mub3JnL3dlYmdsL2V4dGVuc2lvbnMvV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX2V0Yy9cblx0XHRjYXNlIFJHQl9FVEMxX0Zvcm1hdDpcblx0XHRjYXNlIFJHQl9FVEMyX0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgMyApIC8gNCApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyAzICkgLyA0ICkgKiA4O1xuXHRcdGNhc2UgUkdCQV9FVEMyX0VBQ19Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDMgKSAvIDQgKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgMyApIC8gNCApICogMTY7XG5cblx0XHQvLyBodHRwczovL3JlZ2lzdHJ5Lmtocm9ub3Mub3JnL3dlYmdsL2V4dGVuc2lvbnMvV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX2FzdGMvXG5cdFx0Y2FzZSBSR0JBX0FTVENfNHg0X0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgMyApIC8gNCApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyAzICkgLyA0ICkgKiAxNjtcblx0XHRjYXNlIFJHQkFfQVNUQ181eDRfRm9ybWF0OlxuXHRcdFx0cmV0dXJuIE1hdGguZmxvb3IoICggd2lkdGggKyA0ICkgLyA1ICkgKiBNYXRoLmZsb29yKCAoIGhlaWdodCArIDMgKSAvIDQgKSAqIDE2O1xuXHRcdGNhc2UgUkdCQV9BU1RDXzV4NV9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDQgKSAvIDUgKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgNCApIC8gNSApICogMTY7XG5cdFx0Y2FzZSBSR0JBX0FTVENfNng1X0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgNSApIC8gNiApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyA0ICkgLyA1ICkgKiAxNjtcblx0XHRjYXNlIFJHQkFfQVNUQ182eDZfRm9ybWF0OlxuXHRcdFx0cmV0dXJuIE1hdGguZmxvb3IoICggd2lkdGggKyA1ICkgLyA2ICkgKiBNYXRoLmZsb29yKCAoIGhlaWdodCArIDUgKSAvIDYgKSAqIDE2O1xuXHRcdGNhc2UgUkdCQV9BU1RDXzh4NV9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDcgKSAvIDggKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgNCApIC8gNSApICogMTY7XG5cdFx0Y2FzZSBSR0JBX0FTVENfOHg2X0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgNyApIC8gOCApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyA1ICkgLyA2ICkgKiAxNjtcblx0XHRjYXNlIFJHQkFfQVNUQ184eDhfRm9ybWF0OlxuXHRcdFx0cmV0dXJuIE1hdGguZmxvb3IoICggd2lkdGggKyA3ICkgLyA4ICkgKiBNYXRoLmZsb29yKCAoIGhlaWdodCArIDcgKSAvIDggKSAqIDE2O1xuXHRcdGNhc2UgUkdCQV9BU1RDXzEweDVfRm9ybWF0OlxuXHRcdFx0cmV0dXJuIE1hdGguZmxvb3IoICggd2lkdGggKyA5ICkgLyAxMCApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyA0ICkgLyA1ICkgKiAxNjtcblx0XHRjYXNlIFJHQkFfQVNUQ18xMHg2X0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgOSApIC8gMTAgKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgNSApIC8gNiApICogMTY7XG5cdFx0Y2FzZSBSR0JBX0FTVENfMTB4OF9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDkgKSAvIDEwICkgKiBNYXRoLmZsb29yKCAoIGhlaWdodCArIDcgKSAvIDggKSAqIDE2O1xuXHRcdGNhc2UgUkdCQV9BU1RDXzEweDEwX0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgOSApIC8gMTAgKSAqIE1hdGguZmxvb3IoICggaGVpZ2h0ICsgOSApIC8gMTAgKSAqIDE2O1xuXHRcdGNhc2UgUkdCQV9BU1RDXzEyeDEwX0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmZsb29yKCAoIHdpZHRoICsgMTEgKSAvIDEyICkgKiBNYXRoLmZsb29yKCAoIGhlaWdodCArIDkgKSAvIDEwICkgKiAxNjtcblx0XHRjYXNlIFJHQkFfQVNUQ18xMngxMl9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5mbG9vciggKCB3aWR0aCArIDExICkgLyAxMiApICogTWF0aC5mbG9vciggKCBoZWlnaHQgKyAxMSApIC8gMTIgKSAqIDE2O1xuXG5cdFx0Ly8gaHR0cHM6Ly9yZWdpc3RyeS5raHJvbm9zLm9yZy93ZWJnbC9leHRlbnNpb25zL0VYVF90ZXh0dXJlX2NvbXByZXNzaW9uX2JwdGMvXG5cdFx0Y2FzZSBSR0JBX0JQVENfRm9ybWF0OlxuXHRcdGNhc2UgUkdCX0JQVENfU0lHTkVEX0Zvcm1hdDpcblx0XHRjYXNlIFJHQl9CUFRDX1VOU0lHTkVEX0Zvcm1hdDpcblx0XHRcdHJldHVybiBNYXRoLmNlaWwoIHdpZHRoIC8gNCApICogTWF0aC5jZWlsKCBoZWlnaHQgLyA0ICkgKiAxNjtcblxuXHRcdC8vIGh0dHBzOi8vcmVnaXN0cnkua2hyb25vcy5vcmcvd2ViZ2wvZXh0ZW5zaW9ucy9FWFRfdGV4dHVyZV9jb21wcmVzc2lvbl9yZ3RjL1xuXHRcdGNhc2UgUkVEX1JHVEMxX0Zvcm1hdDpcblx0XHRjYXNlIFNJR05FRF9SRURfUkdUQzFfRm9ybWF0OlxuXHRcdFx0cmV0dXJuIE1hdGguY2VpbCggd2lkdGggLyA0ICkgKiBNYXRoLmNlaWwoIGhlaWdodCAvIDQgKSAqIDg7XG5cdFx0Y2FzZSBSRURfR1JFRU5fUkdUQzJfRm9ybWF0OlxuXHRcdGNhc2UgU0lHTkVEX1JFRF9HUkVFTl9SR1RDMl9Gb3JtYXQ6XG5cdFx0XHRyZXR1cm4gTWF0aC5jZWlsKCB3aWR0aCAvIDQgKSAqIE1hdGguY2VpbCggaGVpZ2h0IC8gNCApICogMTY7XG5cblx0fVxuXG5cdHRocm93IG5ldyBFcnJvcihcblx0XHRgVW5hYmxlIHRvIGRldGVybWluZSB0ZXh0dXJlIGJ5dGUgbGVuZ3RoIGZvciAke2Zvcm1hdH0gZm9ybWF0LmAsXG5cdCk7XG5cbn1cblxuZnVuY3Rpb24gZ2V0VGV4dHVyZVR5cGVCeXRlTGVuZ3RoKCB0eXBlICkge1xuXG5cdHN3aXRjaCAoIHR5cGUgKSB7XG5cblx0XHRjYXNlIFVuc2lnbmVkQnl0ZVR5cGU6XG5cdFx0Y2FzZSBCeXRlVHlwZTpcblx0XHRcdHJldHVybiB7IGJ5dGVMZW5ndGg6IDEsIGNvbXBvbmVudHM6IDEgfTtcblx0XHRjYXNlIFVuc2lnbmVkU2hvcnRUeXBlOlxuXHRcdGNhc2UgU2hvcnRUeXBlOlxuXHRcdGNhc2UgSGFsZkZsb2F0VHlwZTpcblx0XHRcdHJldHVybiB7IGJ5dGVMZW5ndGg6IDIsIGNvbXBvbmVudHM6IDEgfTtcblx0XHRjYXNlIFVuc2lnbmVkU2hvcnQ0NDQ0VHlwZTpcblx0XHRjYXNlIFVuc2lnbmVkU2hvcnQ1NTUxVHlwZTpcblx0XHRcdHJldHVybiB7IGJ5dGVMZW5ndGg6IDIsIGNvbXBvbmVudHM6IDQgfTtcblx0XHRjYXNlIFVuc2lnbmVkSW50VHlwZTpcblx0XHRjYXNlIEludFR5cGU6XG5cdFx0Y2FzZSBGbG9hdFR5cGU6XG5cdFx0XHRyZXR1cm4geyBieXRlTGVuZ3RoOiA0LCBjb21wb25lbnRzOiAxIH07XG5cdFx0Y2FzZSBVbnNpZ25lZEludDU5OTlUeXBlOlxuXHRcdFx0cmV0dXJuIHsgYnl0ZUxlbmd0aDogNCwgY29tcG9uZW50czogMyB9O1xuXG5cdH1cblxuXHR0aHJvdyBuZXcgRXJyb3IoIGBVbmtub3duIHRleHR1cmUgdHlwZSAke3R5cGV9LmAgKTtcblxufVxuXG5jb25zdCBUZXh0dXJlVXRpbHMgPSB7XG5cdGNvbnRhaW4sXG5cdGNvdmVyLFxuXHRmaWxsLFxuXHRnZXRCeXRlTGVuZ3RoXG59O1xuXG5mdW5jdGlvbiBXZWJHTFRleHR1cmVzKCBfZ2wsIGV4dGVuc2lvbnMsIHN0YXRlLCBwcm9wZXJ0aWVzLCBjYXBhYmlsaXRpZXMsIHV0aWxzLCBpbmZvICkge1xuXG5cdGNvbnN0IG11bHRpc2FtcGxlZFJUVEV4dCA9IGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfbXVsdGlzYW1wbGVkX3JlbmRlcl90b190ZXh0dXJlJyApID8gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9tdWx0aXNhbXBsZWRfcmVuZGVyX3RvX3RleHR1cmUnICkgOiBudWxsO1xuXHRjb25zdCBzdXBwb3J0c0ludmFsaWRhdGVGcmFtZWJ1ZmZlciA9IHR5cGVvZiBuYXZpZ2F0b3IgPT09ICd1bmRlZmluZWQnID8gZmFsc2UgOiAvT2N1bHVzQnJvd3Nlci9nLnRlc3QoIG5hdmlnYXRvci51c2VyQWdlbnQgKTtcblxuXHRjb25zdCBfaW1hZ2VEaW1lbnNpb25zID0gbmV3IFZlY3RvcjIoKTtcblx0Y29uc3QgX3ZpZGVvVGV4dHVyZXMgPSBuZXcgV2Vha01hcCgpO1xuXHRsZXQgX2NhbnZhcztcblxuXHRjb25zdCBfc291cmNlcyA9IG5ldyBXZWFrTWFwKCk7IC8vIG1hcHMgV2ViZ2xUZXh0dXJlIG9iamVjdHMgdG8gaW5zdGFuY2VzIG9mIFNvdXJjZVxuXG5cdC8vIGNvcmRvdmEgaU9TIChhcyBvZiA1LjApIHN0aWxsIHVzZXMgVUlXZWJWaWV3LCB3aGljaCBwcm92aWRlcyBPZmZzY3JlZW5DYW52YXMsXG5cdC8vIGFsc28gT2Zmc2NyZWVuQ2FudmFzLmdldENvbnRleHQoXCJ3ZWJnbFwiKSwgYnV0IG5vdCBPZmZzY3JlZW5DYW52YXMuZ2V0Q29udGV4dChcIjJkXCIpIVxuXHQvLyBTb21lIGltcGxlbWVudGF0aW9ucyBtYXkgb25seSBpbXBsZW1lbnQgT2Zmc2NyZWVuQ2FudmFzIHBhcnRpYWxseSAoZS5nLiBsYWNraW5nIDJkKS5cblxuXHRsZXQgdXNlT2Zmc2NyZWVuQ2FudmFzID0gZmFsc2U7XG5cblx0dHJ5IHtcblxuXHRcdHVzZU9mZnNjcmVlbkNhbnZhcyA9IHR5cGVvZiBPZmZzY3JlZW5DYW52YXMgIT09ICd1bmRlZmluZWQnXG5cdFx0XHQvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgY29tcGF0L2NvbXBhdFxuXHRcdFx0JiYgKCBuZXcgT2Zmc2NyZWVuQ2FudmFzKCAxLCAxICkuZ2V0Q29udGV4dCggJzJkJyApICkgIT09IG51bGw7XG5cblx0fSBjYXRjaCAoIGVyciApIHtcblxuXHRcdC8vIElnbm9yZSBhbnkgZXJyb3JzXG5cblx0fVxuXG5cdGZ1bmN0aW9uIGNyZWF0ZUNhbnZhcyggd2lkdGgsIGhlaWdodCApIHtcblxuXHRcdC8vIFVzZSBPZmZzY3JlZW5DYW52YXMgd2hlbiBhdmFpbGFibGUuIFNwZWNpYWxseSBuZWVkZWQgaW4gd2ViIHdvcmtlcnNcblxuXHRcdHJldHVybiB1c2VPZmZzY3JlZW5DYW52YXMgP1xuXHRcdFx0Ly8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIGNvbXBhdC9jb21wYXRcblx0XHRcdG5ldyBPZmZzY3JlZW5DYW52YXMoIHdpZHRoLCBoZWlnaHQgKSA6IGNyZWF0ZUVsZW1lbnROUyggJ2NhbnZhcycgKTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVzaXplSW1hZ2UoIGltYWdlLCBuZWVkc05ld0NhbnZhcywgbWF4U2l6ZSApIHtcblxuXHRcdGxldCBzY2FsZSA9IDE7XG5cblx0XHRjb25zdCBkaW1lbnNpb25zID0gZ2V0RGltZW5zaW9ucyggaW1hZ2UgKTtcblxuXHRcdC8vIGhhbmRsZSBjYXNlIGlmIHRleHR1cmUgZXhjZWVkcyBtYXggc2l6ZVxuXG5cdFx0aWYgKCBkaW1lbnNpb25zLndpZHRoID4gbWF4U2l6ZSB8fCBkaW1lbnNpb25zLmhlaWdodCA+IG1heFNpemUgKSB7XG5cblx0XHRcdHNjYWxlID0gbWF4U2l6ZSAvIE1hdGgubWF4KCBkaW1lbnNpb25zLndpZHRoLCBkaW1lbnNpb25zLmhlaWdodCApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gb25seSBwZXJmb3JtIHJlc2l6ZSBpZiBuZWNlc3NhcnlcblxuXHRcdGlmICggc2NhbGUgPCAxICkge1xuXG5cdFx0XHQvLyBvbmx5IHBlcmZvcm0gcmVzaXplIGZvciBjZXJ0YWluIGltYWdlIHR5cGVzXG5cblx0XHRcdGlmICggKCB0eXBlb2YgSFRNTEltYWdlRWxlbWVudCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBIVE1MSW1hZ2VFbGVtZW50ICkgfHxcblx0XHRcdFx0KCB0eXBlb2YgSFRNTENhbnZhc0VsZW1lbnQgIT09ICd1bmRlZmluZWQnICYmIGltYWdlIGluc3RhbmNlb2YgSFRNTENhbnZhc0VsZW1lbnQgKSB8fFxuXHRcdFx0XHQoIHR5cGVvZiBJbWFnZUJpdG1hcCAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBJbWFnZUJpdG1hcCApIHx8XG5cdFx0XHRcdCggdHlwZW9mIFZpZGVvRnJhbWUgIT09ICd1bmRlZmluZWQnICYmIGltYWdlIGluc3RhbmNlb2YgVmlkZW9GcmFtZSApICkge1xuXG5cdFx0XHRcdGNvbnN0IHdpZHRoID0gTWF0aC5mbG9vciggc2NhbGUgKiBkaW1lbnNpb25zLndpZHRoICk7XG5cdFx0XHRcdGNvbnN0IGhlaWdodCA9IE1hdGguZmxvb3IoIHNjYWxlICogZGltZW5zaW9ucy5oZWlnaHQgKTtcblxuXHRcdFx0XHRpZiAoIF9jYW52YXMgPT09IHVuZGVmaW5lZCApIF9jYW52YXMgPSBjcmVhdGVDYW52YXMoIHdpZHRoLCBoZWlnaHQgKTtcblxuXHRcdFx0XHQvLyBjdWJlIHRleHR1cmVzIGNhbid0IHJldXNlIHRoZSBzYW1lIGNhbnZhc1xuXG5cdFx0XHRcdGNvbnN0IGNhbnZhcyA9IG5lZWRzTmV3Q2FudmFzID8gY3JlYXRlQ2FudmFzKCB3aWR0aCwgaGVpZ2h0ICkgOiBfY2FudmFzO1xuXG5cdFx0XHRcdGNhbnZhcy53aWR0aCA9IHdpZHRoO1xuXHRcdFx0XHRjYW52YXMuaGVpZ2h0ID0gaGVpZ2h0O1xuXG5cdFx0XHRcdGNvbnN0IGNvbnRleHQgPSBjYW52YXMuZ2V0Q29udGV4dCggJzJkJyApO1xuXHRcdFx0XHRjb250ZXh0LmRyYXdJbWFnZSggaW1hZ2UsIDAsIDAsIHdpZHRoLCBoZWlnaHQgKTtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBUZXh0dXJlIGhhcyBiZWVuIHJlc2l6ZWQgZnJvbSAoJyArIGRpbWVuc2lvbnMud2lkdGggKyAneCcgKyBkaW1lbnNpb25zLmhlaWdodCArICcpIHRvICgnICsgd2lkdGggKyAneCcgKyBoZWlnaHQgKyAnKS4nICk7XG5cblx0XHRcdFx0cmV0dXJuIGNhbnZhcztcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRpZiAoICdkYXRhJyBpbiBpbWFnZSApIHtcblxuXHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IEltYWdlIGluIERhdGFUZXh0dXJlIGlzIHRvbyBiaWcgKCcgKyBkaW1lbnNpb25zLndpZHRoICsgJ3gnICsgZGltZW5zaW9ucy5oZWlnaHQgKyAnKS4nICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiBpbWFnZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGltYWdlO1xuXG5cdH1cblxuXHRmdW5jdGlvbiB0ZXh0dXJlTmVlZHNHZW5lcmF0ZU1pcG1hcHMoIHRleHR1cmUgKSB7XG5cblx0XHRyZXR1cm4gdGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgJiYgdGV4dHVyZS5taW5GaWx0ZXIgIT09IE5lYXJlc3RGaWx0ZXIgJiYgdGV4dHVyZS5taW5GaWx0ZXIgIT09IExpbmVhckZpbHRlcjtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2VuZXJhdGVNaXBtYXAoIHRhcmdldCApIHtcblxuXHRcdF9nbC5nZW5lcmF0ZU1pcG1hcCggdGFyZ2V0ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldEludGVybmFsRm9ybWF0KCBpbnRlcm5hbEZvcm1hdE5hbWUsIGdsRm9ybWF0LCBnbFR5cGUsIGNvbG9yU3BhY2UsIGZvcmNlTGluZWFyVHJhbnNmZXIgPSBmYWxzZSApIHtcblxuXHRcdGlmICggaW50ZXJuYWxGb3JtYXROYW1lICE9PSBudWxsICkge1xuXG5cdFx0XHRpZiAoIF9nbFsgaW50ZXJuYWxGb3JtYXROYW1lIF0gIT09IHVuZGVmaW5lZCApIHJldHVybiBfZ2xbIGludGVybmFsRm9ybWF0TmFtZSBdO1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBBdHRlbXB0IHRvIHVzZSBub24tZXhpc3RpbmcgV2ViR0wgaW50ZXJuYWwgZm9ybWF0IFxcJycgKyBpbnRlcm5hbEZvcm1hdE5hbWUgKyAnXFwnJyApO1xuXG5cdFx0fVxuXG5cdFx0bGV0IGludGVybmFsRm9ybWF0ID0gZ2xGb3JtYXQ7XG5cblx0XHRpZiAoIGdsRm9ybWF0ID09PSBfZ2wuUkVEICkge1xuXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkZMT0FUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjMyRjtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuSEFMRl9GTE9BVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlIxNkY7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX0JZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SODtcblxuXHRcdH1cblxuXHRcdGlmICggZ2xGb3JtYXQgPT09IF9nbC5SRURfSU5URUdFUiApIHtcblxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9CWVRFICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjhVSTtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfU0hPUlQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SMTZVSTtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfSU5UICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjMyVUk7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkJZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SOEk7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlNIT1JUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjE2STtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuSU5UICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUjMySTtcblxuXHRcdH1cblxuXHRcdGlmICggZ2xGb3JtYXQgPT09IF9nbC5SRyApIHtcblxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5GTE9BVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHMzJGO1xuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5IQUxGX0ZMT0FUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkcxNkY7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX0JZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SRzg7XG5cblx0XHR9XG5cblx0XHRpZiAoIGdsRm9ybWF0ID09PSBfZ2wuUkdfSU5URUdFUiApIHtcblxuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9CWVRFICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkc4VUk7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX1NIT1JUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkcxNlVJO1xuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9JTlQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SRzMyVUk7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkJZVEUgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SRzhJO1xuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5TSE9SVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHMTZJO1xuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5JTlQgKSBpbnRlcm5hbEZvcm1hdCA9IF9nbC5SRzMySTtcblxuXHRcdH1cblxuXHRcdGlmICggZ2xGb3JtYXQgPT09IF9nbC5SR0IgKSB7XG5cblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfSU5UXzVfOV85XzlfUkVWICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkdCOV9FNTtcblxuXHRcdH1cblxuXHRcdGlmICggZ2xGb3JtYXQgPT09IF9nbC5SR0JBICkge1xuXG5cdFx0XHRjb25zdCB0cmFuc2ZlciA9IGZvcmNlTGluZWFyVHJhbnNmZXIgPyBMaW5lYXJUcmFuc2ZlciA6IENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggY29sb3JTcGFjZSApO1xuXG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLkZMT0FUICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkdCQTMyRjtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuSEFMRl9GTE9BVCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHQkExNkY7XG5cdFx0XHRpZiAoIGdsVHlwZSA9PT0gX2dsLlVOU0lHTkVEX0JZVEUgKSBpbnRlcm5hbEZvcm1hdCA9ICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gX2dsLlNSR0I4X0FMUEhBOCA6IF9nbC5SR0JBODtcblx0XHRcdGlmICggZ2xUeXBlID09PSBfZ2wuVU5TSUdORURfU0hPUlRfNF80XzRfNCApIGludGVybmFsRm9ybWF0ID0gX2dsLlJHQkE0O1xuXHRcdFx0aWYgKCBnbFR5cGUgPT09IF9nbC5VTlNJR05FRF9TSE9SVF81XzVfNV8xICkgaW50ZXJuYWxGb3JtYXQgPSBfZ2wuUkdCNV9BMTtcblxuXHRcdH1cblxuXHRcdGlmICggaW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SMTZGIHx8IGludGVybmFsRm9ybWF0ID09PSBfZ2wuUjMyRiB8fFxuXHRcdFx0aW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SRzE2RiB8fCBpbnRlcm5hbEZvcm1hdCA9PT0gX2dsLlJHMzJGIHx8XG5cdFx0XHRpbnRlcm5hbEZvcm1hdCA9PT0gX2dsLlJHQkExNkYgfHwgaW50ZXJuYWxGb3JtYXQgPT09IF9nbC5SR0JBMzJGICkge1xuXG5cdFx0XHRleHRlbnNpb25zLmdldCggJ0VYVF9jb2xvcl9idWZmZXJfZmxvYXQnICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gaW50ZXJuYWxGb3JtYXQ7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldEludGVybmFsRGVwdGhGb3JtYXQoIHVzZVN0ZW5jaWwsIGRlcHRoVHlwZSApIHtcblxuXHRcdGxldCBnbEludGVybmFsRm9ybWF0O1xuXHRcdGlmICggdXNlU3RlbmNpbCApIHtcblxuXHRcdFx0aWYgKCBkZXB0aFR5cGUgPT09IG51bGwgfHwgZGVwdGhUeXBlID09PSBVbnNpZ25lZEludFR5cGUgfHwgZGVwdGhUeXBlID09PSBVbnNpZ25lZEludDI0OFR5cGUgKSB7XG5cblx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IF9nbC5ERVBUSDI0X1NURU5DSUw4O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBkZXB0aFR5cGUgPT09IEZsb2F0VHlwZSApIHtcblxuXHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gX2dsLkRFUFRIMzJGX1NURU5DSUw4O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBkZXB0aFR5cGUgPT09IFVuc2lnbmVkU2hvcnRUeXBlICkge1xuXG5cdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBfZ2wuREVQVEgyNF9TVEVOQ0lMODtcblx0XHRcdFx0Y29uc29sZS53YXJuKCAnRGVwdGhUZXh0dXJlOiAxNiBiaXQgZGVwdGggYXR0YWNobWVudCBpcyBub3Qgc3VwcG9ydGVkIHdpdGggc3RlbmNpbC4gVXNpbmcgMjQtYml0IGF0dGFjaG1lbnQuJyApO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIGRlcHRoVHlwZSA9PT0gbnVsbCB8fCBkZXB0aFR5cGUgPT09IFVuc2lnbmVkSW50VHlwZSB8fCBkZXB0aFR5cGUgPT09IFVuc2lnbmVkSW50MjQ4VHlwZSApIHtcblxuXHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gX2dsLkRFUFRIX0NPTVBPTkVOVDI0O1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBkZXB0aFR5cGUgPT09IEZsb2F0VHlwZSApIHtcblxuXHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gX2dsLkRFUFRIX0NPTVBPTkVOVDMyRjtcblxuXHRcdFx0fSBlbHNlIGlmICggZGVwdGhUeXBlID09PSBVbnNpZ25lZFNob3J0VHlwZSApIHtcblxuXHRcdFx0XHRnbEludGVybmFsRm9ybWF0ID0gX2dsLkRFUFRIX0NPTVBPTkVOVDE2O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gZ2xJbnRlcm5hbEZvcm1hdDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0TWlwTGV2ZWxzKCB0ZXh0dXJlLCBpbWFnZSApIHtcblxuXHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlICkgPT09IHRydWUgfHwgKCB0ZXh0dXJlLmlzRnJhbWVidWZmZXJUZXh0dXJlICYmIHRleHR1cmUubWluRmlsdGVyICE9PSBOZWFyZXN0RmlsdGVyICYmIHRleHR1cmUubWluRmlsdGVyICE9PSBMaW5lYXJGaWx0ZXIgKSApIHtcblxuXHRcdFx0cmV0dXJuIE1hdGgubG9nMiggTWF0aC5tYXgoIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQgKSApICsgMTtcblxuXHRcdH0gZWxzZSBpZiAoIHRleHR1cmUubWlwbWFwcyAhPT0gdW5kZWZpbmVkICYmIHRleHR1cmUubWlwbWFwcy5sZW5ndGggPiAwICkge1xuXG5cdFx0XHQvLyB1c2VyLWRlZmluZWQgbWlwbWFwc1xuXG5cdFx0XHRyZXR1cm4gdGV4dHVyZS5taXBtYXBzLmxlbmd0aDtcblxuXHRcdH0gZWxzZSBpZiAoIHRleHR1cmUuaXNDb21wcmVzc2VkVGV4dHVyZSAmJiBBcnJheS5pc0FycmF5KCB0ZXh0dXJlLmltYWdlICkgKSB7XG5cblx0XHRcdHJldHVybiBpbWFnZS5taXBtYXBzLmxlbmd0aDtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIHRleHR1cmUgd2l0aG91dCBtaXBtYXBzIChvbmx5IGJhc2UgbGV2ZWwpXG5cblx0XHRcdHJldHVybiAxO1xuXG5cdFx0fVxuXG5cdH1cblxuXHQvL1xuXG5cdGZ1bmN0aW9uIG9uVGV4dHVyZURpc3Bvc2UoIGV2ZW50ICkge1xuXG5cdFx0Y29uc3QgdGV4dHVyZSA9IGV2ZW50LnRhcmdldDtcblxuXHRcdHRleHR1cmUucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblRleHR1cmVEaXNwb3NlICk7XG5cblx0XHRkZWFsbG9jYXRlVGV4dHVyZSggdGV4dHVyZSApO1xuXG5cdFx0aWYgKCB0ZXh0dXJlLmlzVmlkZW9UZXh0dXJlICkge1xuXG5cdFx0XHRfdmlkZW9UZXh0dXJlcy5kZWxldGUoIHRleHR1cmUgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gb25SZW5kZXJUYXJnZXREaXNwb3NlKCBldmVudCApIHtcblxuXHRcdGNvbnN0IHJlbmRlclRhcmdldCA9IGV2ZW50LnRhcmdldDtcblxuXHRcdHJlbmRlclRhcmdldC5yZW1vdmVFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uUmVuZGVyVGFyZ2V0RGlzcG9zZSApO1xuXG5cdFx0ZGVhbGxvY2F0ZVJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0ICk7XG5cblx0fVxuXG5cdC8vXG5cblx0ZnVuY3Rpb24gZGVhbGxvY2F0ZVRleHR1cmUoIHRleHR1cmUgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICk7XG5cblx0XHRpZiAoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xJbml0ID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHQvLyBjaGVjayBpZiBpdCdzIG5lY2Vzc2FyeSB0byByZW1vdmUgdGhlIFdlYkdMVGV4dHVyZSBvYmplY3RcblxuXHRcdGNvbnN0IHNvdXJjZSA9IHRleHR1cmUuc291cmNlO1xuXHRcdGNvbnN0IHdlYmdsVGV4dHVyZXMgPSBfc291cmNlcy5nZXQoIHNvdXJjZSApO1xuXG5cdFx0aWYgKCB3ZWJnbFRleHR1cmVzICkge1xuXG5cdFx0XHRjb25zdCB3ZWJnbFRleHR1cmUgPSB3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlUHJvcGVydGllcy5fX2NhY2hlS2V5IF07XG5cdFx0XHR3ZWJnbFRleHR1cmUudXNlZFRpbWVzIC0tO1xuXG5cdFx0XHQvLyB0aGUgV2ViR0xUZXh0dXJlIG9iamVjdCBpcyBub3QgdXNlZCBhbnltb3JlLCByZW1vdmUgaXRcblxuXHRcdFx0aWYgKCB3ZWJnbFRleHR1cmUudXNlZFRpbWVzID09PSAwICkge1xuXG5cdFx0XHRcdGRlbGV0ZVRleHR1cmUoIHRleHR1cmUgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyByZW1vdmUgdGhlIHdlYWsgbWFwIGVudHJ5IGlmIG5vIFdlYkdMVGV4dHVyZSB1c2VzIHRoZSBzb3VyY2UgYW55bW9yZVxuXG5cdFx0XHRpZiAoIE9iamVjdC5rZXlzKCB3ZWJnbFRleHR1cmVzICkubGVuZ3RoID09PSAwICkge1xuXG5cdFx0XHRcdF9zb3VyY2VzLmRlbGV0ZSggc291cmNlICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHByb3BlcnRpZXMucmVtb3ZlKCB0ZXh0dXJlICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRlbGV0ZVRleHR1cmUoIHRleHR1cmUgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICk7XG5cdFx0X2dsLmRlbGV0ZVRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlICk7XG5cblx0XHRjb25zdCBzb3VyY2UgPSB0ZXh0dXJlLnNvdXJjZTtcblx0XHRjb25zdCB3ZWJnbFRleHR1cmVzID0gX3NvdXJjZXMuZ2V0KCBzb3VyY2UgKTtcblx0XHRkZWxldGUgd2ViZ2xUZXh0dXJlc1sgdGV4dHVyZVByb3BlcnRpZXMuX19jYWNoZUtleSBdO1xuXG5cdFx0aW5mby5tZW1vcnkudGV4dHVyZXMgLS07XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGRlYWxsb2NhdGVSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCApIHtcblxuXHRcdGNvbnN0IHJlbmRlclRhcmdldFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgKSB7XG5cblx0XHRcdHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUuZGlzcG9zZSgpO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgaSBdICkgKSB7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgbGV2ZWwgPSAwOyBsZXZlbCA8IHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF0ubGVuZ3RoOyBsZXZlbCArKyApIF9nbC5kZWxldGVGcmFtZWJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXVsgbGV2ZWwgXSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRfZ2wuZGVsZXRlRnJhbWVidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyWyBpIF0gKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciApIF9nbC5kZWxldGVSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyWyBpIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciApICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBsZXZlbCA9IDA7IGxldmVsIDwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIubGVuZ3RoOyBsZXZlbCArKyApIF9nbC5kZWxldGVGcmFtZWJ1ZmZlciggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGxldmVsIF0gKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRfZ2wuZGVsZXRlRnJhbWVidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciApIF9nbC5kZWxldGVSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyICk7XG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICkgX2dsLmRlbGV0ZUZyYW1lYnVmZmVyKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlciApO1xuXG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsQ29sb3JSZW5kZXJidWZmZXJbIGkgXSApIF9nbC5kZWxldGVSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyWyBpIF0gKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aFJlbmRlcmJ1ZmZlciApIF9nbC5kZWxldGVSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoUmVuZGVyYnVmZmVyICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCB0ZXh0dXJlcyA9IHJlbmRlclRhcmdldC50ZXh0dXJlcztcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgYXR0YWNobWVudFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZXNbIGkgXSApO1xuXG5cdFx0XHRpZiAoIGF0dGFjaG1lbnRQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlICkge1xuXG5cdFx0XHRcdF9nbC5kZWxldGVUZXh0dXJlKCBhdHRhY2htZW50UHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xuXG5cdFx0XHRcdGluZm8ubWVtb3J5LnRleHR1cmVzIC0tO1xuXG5cdFx0XHR9XG5cblx0XHRcdHByb3BlcnRpZXMucmVtb3ZlKCB0ZXh0dXJlc1sgaSBdICk7XG5cblx0XHR9XG5cblx0XHRwcm9wZXJ0aWVzLnJlbW92ZSggcmVuZGVyVGFyZ2V0ICk7XG5cblx0fVxuXG5cdC8vXG5cblx0bGV0IHRleHR1cmVVbml0cyA9IDA7XG5cblx0ZnVuY3Rpb24gcmVzZXRUZXh0dXJlVW5pdHMoKSB7XG5cblx0XHR0ZXh0dXJlVW5pdHMgPSAwO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBhbGxvY2F0ZVRleHR1cmVVbml0KCkge1xuXG5cdFx0Y29uc3QgdGV4dHVyZVVuaXQgPSB0ZXh0dXJlVW5pdHM7XG5cblx0XHRpZiAoIHRleHR1cmVVbml0ID49IGNhcGFiaWxpdGllcy5tYXhUZXh0dXJlcyApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xUZXh0dXJlczogVHJ5aW5nIHRvIHVzZSAnICsgdGV4dHVyZVVuaXQgKyAnIHRleHR1cmUgdW5pdHMgd2hpbGUgdGhpcyBHUFUgc3VwcG9ydHMgb25seSAnICsgY2FwYWJpbGl0aWVzLm1heFRleHR1cmVzICk7XG5cblx0XHR9XG5cblx0XHR0ZXh0dXJlVW5pdHMgKz0gMTtcblxuXHRcdHJldHVybiB0ZXh0dXJlVW5pdDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0VGV4dHVyZUNhY2hlS2V5KCB0ZXh0dXJlICkge1xuXG5cdFx0Y29uc3QgYXJyYXkgPSBbXTtcblxuXHRcdGFycmF5LnB1c2goIHRleHR1cmUud3JhcFMgKTtcblx0XHRhcnJheS5wdXNoKCB0ZXh0dXJlLndyYXBUICk7XG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS53cmFwUiB8fCAwICk7XG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5tYWdGaWx0ZXIgKTtcblx0XHRhcnJheS5wdXNoKCB0ZXh0dXJlLm1pbkZpbHRlciApO1xuXHRcdGFycmF5LnB1c2goIHRleHR1cmUuYW5pc290cm9weSApO1xuXHRcdGFycmF5LnB1c2goIHRleHR1cmUuaW50ZXJuYWxGb3JtYXQgKTtcblx0XHRhcnJheS5wdXNoKCB0ZXh0dXJlLmZvcm1hdCApO1xuXHRcdGFycmF5LnB1c2goIHRleHR1cmUudHlwZSApO1xuXHRcdGFycmF5LnB1c2goIHRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzICk7XG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5wcmVtdWx0aXBseUFscGhhICk7XG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5mbGlwWSApO1xuXHRcdGFycmF5LnB1c2goIHRleHR1cmUudW5wYWNrQWxpZ25tZW50ICk7XG5cdFx0YXJyYXkucHVzaCggdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cblx0XHRyZXR1cm4gYXJyYXkuam9pbigpO1xuXG5cdH1cblxuXHQvL1xuXG5cdGZ1bmN0aW9uIHNldFRleHR1cmUyRCggdGV4dHVyZSwgc2xvdCApIHtcblxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcblxuXHRcdGlmICggdGV4dHVyZS5pc1ZpZGVvVGV4dHVyZSApIHVwZGF0ZVZpZGVvVGV4dHVyZSggdGV4dHVyZSApO1xuXG5cdFx0aWYgKCB0ZXh0dXJlLmlzUmVuZGVyVGFyZ2V0VGV4dHVyZSA9PT0gZmFsc2UgJiYgdGV4dHVyZS52ZXJzaW9uID4gMCAmJiB0ZXh0dXJlUHJvcGVydGllcy5fX3ZlcnNpb24gIT09IHRleHR1cmUudmVyc2lvbiApIHtcblxuXHRcdFx0Y29uc3QgaW1hZ2UgPSB0ZXh0dXJlLmltYWdlO1xuXG5cdFx0XHRpZiAoIGltYWdlID09PSBudWxsICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFRleHR1cmUgbWFya2VkIGZvciB1cGRhdGUgYnV0IG5vIGltYWdlIGRhdGEgZm91bmQuJyApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBpbWFnZS5jb21wbGV0ZSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVGV4dHVyZSBtYXJrZWQgZm9yIHVwZGF0ZSBidXQgaW1hZ2UgaXMgaW5jb21wbGV0ZScgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHR1cGxvYWRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApO1xuXHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBfZ2wuVEVYVFVSRV8yRCwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIF9nbC5URVhUVVJFMCArIHNsb3QgKTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gc2V0VGV4dHVyZTJEQXJyYXkoIHRleHR1cmUsIHNsb3QgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICk7XG5cblx0XHRpZiAoIHRleHR1cmUudmVyc2lvbiA+IDAgJiYgdGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uICE9PSB0ZXh0dXJlLnZlcnNpb24gKSB7XG5cblx0XHRcdHVwbG9hZFRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLCB0ZXh0dXJlLCBzbG90ICk7XG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHRzdGF0ZS5iaW5kVGV4dHVyZSggX2dsLlRFWFRVUkVfMkRfQVJSQVksIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlLCBfZ2wuVEVYVFVSRTAgKyBzbG90ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHNldFRleHR1cmUzRCggdGV4dHVyZSwgc2xvdCApIHtcblxuXHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcblxuXHRcdGlmICggdGV4dHVyZS52ZXJzaW9uID4gMCAmJiB0ZXh0dXJlUHJvcGVydGllcy5fX3ZlcnNpb24gIT09IHRleHR1cmUudmVyc2lvbiApIHtcblxuXHRcdFx0dXBsb2FkVGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMsIHRleHR1cmUsIHNsb3QgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBfZ2wuVEVYVFVSRV8zRCwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIF9nbC5URVhUVVJFMCArIHNsb3QgKTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gc2V0VGV4dHVyZUN1YmUoIHRleHR1cmUsIHNsb3QgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICk7XG5cblx0XHRpZiAoIHRleHR1cmUudmVyc2lvbiA+IDAgJiYgdGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uICE9PSB0ZXh0dXJlLnZlcnNpb24gKSB7XG5cblx0XHRcdHVwbG9hZEN1YmVUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApO1xuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgX2dsLlRFWFRVUkUwICsgc2xvdCApO1xuXG5cdH1cblxuXHRjb25zdCB3cmFwcGluZ1RvR0wgPSB7XG5cdFx0WyBSZXBlYXRXcmFwcGluZyBdOiBfZ2wuUkVQRUFULFxuXHRcdFsgQ2xhbXBUb0VkZ2VXcmFwcGluZyBdOiBfZ2wuQ0xBTVBfVE9fRURHRSxcblx0XHRbIE1pcnJvcmVkUmVwZWF0V3JhcHBpbmcgXTogX2dsLk1JUlJPUkVEX1JFUEVBVFxuXHR9O1xuXG5cdGNvbnN0IGZpbHRlclRvR0wgPSB7XG5cdFx0WyBOZWFyZXN0RmlsdGVyIF06IF9nbC5ORUFSRVNULFxuXHRcdFsgTmVhcmVzdE1pcG1hcE5lYXJlc3RGaWx0ZXIgXTogX2dsLk5FQVJFU1RfTUlQTUFQX05FQVJFU1QsXG5cdFx0WyBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyIF06IF9nbC5ORUFSRVNUX01JUE1BUF9MSU5FQVIsXG5cblx0XHRbIExpbmVhckZpbHRlciBdOiBfZ2wuTElORUFSLFxuXHRcdFsgTGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlciBdOiBfZ2wuTElORUFSX01JUE1BUF9ORUFSRVNULFxuXHRcdFsgTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyIF06IF9nbC5MSU5FQVJfTUlQTUFQX0xJTkVBUlxuXHR9O1xuXG5cdGNvbnN0IGNvbXBhcmVUb0dMID0ge1xuXHRcdFsgTmV2ZXJDb21wYXJlIF06IF9nbC5ORVZFUixcblx0XHRbIEFsd2F5c0NvbXBhcmUgXTogX2dsLkFMV0FZUyxcblx0XHRbIExlc3NDb21wYXJlIF06IF9nbC5MRVNTLFxuXHRcdFsgTGVzc0VxdWFsQ29tcGFyZSBdOiBfZ2wuTEVRVUFMLFxuXHRcdFsgRXF1YWxDb21wYXJlIF06IF9nbC5FUVVBTCxcblx0XHRbIEdyZWF0ZXJFcXVhbENvbXBhcmUgXTogX2dsLkdFUVVBTCxcblx0XHRbIEdyZWF0ZXJDb21wYXJlIF06IF9nbC5HUkVBVEVSLFxuXHRcdFsgTm90RXF1YWxDb21wYXJlIF06IF9nbC5OT1RFUVVBTFxuXHR9O1xuXG5cdGZ1bmN0aW9uIHNldFRleHR1cmVQYXJhbWV0ZXJzKCB0ZXh0dXJlVHlwZSwgdGV4dHVyZSApIHtcblxuXHRcdGlmICggdGV4dHVyZS50eXBlID09PSBGbG9hdFR5cGUgJiYgZXh0ZW5zaW9ucy5oYXMoICdPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXInICkgPT09IGZhbHNlICYmXG5cdFx0XHQoIHRleHR1cmUubWFnRmlsdGVyID09PSBMaW5lYXJGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IExpbmVhck1pcG1hcE5lYXJlc3RGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXIgfHwgdGV4dHVyZS5tYWdGaWx0ZXIgPT09IExpbmVhck1pcG1hcExpbmVhckZpbHRlciB8fFxuXHRcdFx0dGV4dHVyZS5taW5GaWx0ZXIgPT09IExpbmVhckZpbHRlciB8fCB0ZXh0dXJlLm1pbkZpbHRlciA9PT0gTGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlciB8fCB0ZXh0dXJlLm1pbkZpbHRlciA9PT0gTmVhcmVzdE1pcG1hcExpbmVhckZpbHRlciB8fCB0ZXh0dXJlLm1pbkZpbHRlciA9PT0gTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyICkgKSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFVuYWJsZSB0byB1c2UgbGluZWFyIGZpbHRlcmluZyB3aXRoIGZsb2F0aW5nIHBvaW50IHRleHR1cmVzLiBPRVNfdGV4dHVyZV9mbG9hdF9saW5lYXIgbm90IHN1cHBvcnRlZCBvbiB0aGlzIGRldmljZS4nICk7XG5cblx0XHR9XG5cblx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX1dSQVBfUywgd3JhcHBpbmdUb0dMWyB0ZXh0dXJlLndyYXBTIF0gKTtcblx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX1dSQVBfVCwgd3JhcHBpbmdUb0dMWyB0ZXh0dXJlLndyYXBUIF0gKTtcblxuXHRcdGlmICggdGV4dHVyZVR5cGUgPT09IF9nbC5URVhUVVJFXzNEIHx8IHRleHR1cmVUeXBlID09PSBfZ2wuVEVYVFVSRV8yRF9BUlJBWSApIHtcblxuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9XUkFQX1IsIHdyYXBwaW5nVG9HTFsgdGV4dHVyZS53cmFwUiBdICk7XG5cblx0XHR9XG5cblx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX01BR19GSUxURVIsIGZpbHRlclRvR0xbIHRleHR1cmUubWFnRmlsdGVyIF0gKTtcblx0XHRfZ2wudGV4UGFyYW1ldGVyaSggdGV4dHVyZVR5cGUsIF9nbC5URVhUVVJFX01JTl9GSUxURVIsIGZpbHRlclRvR0xbIHRleHR1cmUubWluRmlsdGVyIF0gKTtcblxuXHRcdGlmICggdGV4dHVyZS5jb21wYXJlRnVuY3Rpb24gKSB7XG5cblx0XHRcdF9nbC50ZXhQYXJhbWV0ZXJpKCB0ZXh0dXJlVHlwZSwgX2dsLlRFWFRVUkVfQ09NUEFSRV9NT0RFLCBfZ2wuQ09NUEFSRV9SRUZfVE9fVEVYVFVSRSApO1xuXHRcdFx0X2dsLnRleFBhcmFtZXRlcmkoIHRleHR1cmVUeXBlLCBfZ2wuVEVYVFVSRV9DT01QQVJFX0ZVTkMsIGNvbXBhcmVUb0dMWyB0ZXh0dXJlLmNvbXBhcmVGdW5jdGlvbiBdICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIGV4dGVuc2lvbnMuaGFzKCAnRVhUX3RleHR1cmVfZmlsdGVyX2FuaXNvdHJvcGljJyApID09PSB0cnVlICkge1xuXG5cdFx0XHRpZiAoIHRleHR1cmUubWFnRmlsdGVyID09PSBOZWFyZXN0RmlsdGVyICkgcmV0dXJuO1xuXHRcdFx0aWYgKCB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTmVhcmVzdE1pcG1hcExpbmVhckZpbHRlciAmJiB0ZXh0dXJlLm1pbkZpbHRlciAhPT0gTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyICkgcmV0dXJuO1xuXHRcdFx0aWYgKCB0ZXh0dXJlLnR5cGUgPT09IEZsb2F0VHlwZSAmJiBleHRlbnNpb25zLmhhcyggJ09FU190ZXh0dXJlX2Zsb2F0X2xpbmVhcicgKSA9PT0gZmFsc2UgKSByZXR1cm47IC8vIHZlcmlmeSBleHRlbnNpb25cblxuXHRcdFx0aWYgKCB0ZXh0dXJlLmFuaXNvdHJvcHkgPiAxIHx8IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX19jdXJyZW50QW5pc290cm9weSApIHtcblxuXHRcdFx0XHRjb25zdCBleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ0VYVF90ZXh0dXJlX2ZpbHRlcl9hbmlzb3Ryb3BpYycgKTtcblx0XHRcdFx0X2dsLnRleFBhcmFtZXRlcmYoIHRleHR1cmVUeXBlLCBleHRlbnNpb24uVEVYVFVSRV9NQVhfQU5JU09UUk9QWV9FWFQsIE1hdGgubWluKCB0ZXh0dXJlLmFuaXNvdHJvcHksIGNhcGFiaWxpdGllcy5nZXRNYXhBbmlzb3Ryb3B5KCkgKSApO1xuXHRcdFx0XHRwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApLl9fY3VycmVudEFuaXNvdHJvcHkgPSB0ZXh0dXJlLmFuaXNvdHJvcHk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gaW5pdFRleHR1cmUoIHRleHR1cmVQcm9wZXJ0aWVzLCB0ZXh0dXJlICkge1xuXG5cdFx0bGV0IGZvcmNlVXBsb2FkID0gZmFsc2U7XG5cblx0XHRpZiAoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xJbml0ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xJbml0ID0gdHJ1ZTtcblxuXHRcdFx0dGV4dHVyZS5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVGV4dHVyZURpc3Bvc2UgKTtcblxuXHRcdH1cblxuXHRcdC8vIGNyZWF0ZSBTb3VyY2UgPC0+IFdlYkdMVGV4dHVyZXMgbWFwcGluZyBpZiBuZWNlc3NhcnlcblxuXHRcdGNvbnN0IHNvdXJjZSA9IHRleHR1cmUuc291cmNlO1xuXHRcdGxldCB3ZWJnbFRleHR1cmVzID0gX3NvdXJjZXMuZ2V0KCBzb3VyY2UgKTtcblxuXHRcdGlmICggd2ViZ2xUZXh0dXJlcyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR3ZWJnbFRleHR1cmVzID0ge307XG5cdFx0XHRfc291cmNlcy5zZXQoIHNvdXJjZSwgd2ViZ2xUZXh0dXJlcyApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gY2hlY2sgaWYgdGhlcmUgaXMgYWxyZWFkeSBhIFdlYkdMVGV4dHVyZSBvYmplY3QgZm9yIHRoZSBnaXZlbiB0ZXh0dXJlIHBhcmFtZXRlcnNcblxuXHRcdGNvbnN0IHRleHR1cmVDYWNoZUtleSA9IGdldFRleHR1cmVDYWNoZUtleSggdGV4dHVyZSApO1xuXG5cdFx0aWYgKCB0ZXh0dXJlQ2FjaGVLZXkgIT09IHRleHR1cmVQcm9wZXJ0aWVzLl9fY2FjaGVLZXkgKSB7XG5cblx0XHRcdC8vIGlmIG5vdCwgY3JlYXRlIGEgbmV3IGluc3RhbmNlIG9mIFdlYkdMVGV4dHVyZVxuXG5cdFx0XHRpZiAoIHdlYmdsVGV4dHVyZXNbIHRleHR1cmVDYWNoZUtleSBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Ly8gY3JlYXRlIG5ldyBlbnRyeVxuXG5cdFx0XHRcdHdlYmdsVGV4dHVyZXNbIHRleHR1cmVDYWNoZUtleSBdID0ge1xuXHRcdFx0XHRcdHRleHR1cmU6IF9nbC5jcmVhdGVUZXh0dXJlKCksXG5cdFx0XHRcdFx0dXNlZFRpbWVzOiAwXG5cdFx0XHRcdH07XG5cblx0XHRcdFx0aW5mby5tZW1vcnkudGV4dHVyZXMgKys7XG5cblx0XHRcdFx0Ly8gd2hlbiBhIG5ldyBpbnN0YW5jZSBvZiBXZWJHTFRleHR1cmUgd2FzIGNyZWF0ZWQsIGEgdGV4dHVyZSB1cGxvYWQgaXMgcmVxdWlyZWRcblx0XHRcdFx0Ly8gZXZlbiBpZiB0aGUgaW1hZ2UgY29udGVudHMgYXJlIGlkZW50aWNhbFxuXG5cdFx0XHRcdGZvcmNlVXBsb2FkID0gdHJ1ZTtcblxuXHRcdFx0fVxuXG5cdFx0XHR3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlQ2FjaGVLZXkgXS51c2VkVGltZXMgKys7XG5cblx0XHRcdC8vIGV2ZXJ5IHRpbWUgdGhlIHRleHR1cmUgY2FjaGUga2V5IGNoYW5nZXMsIGl0J3MgbmVjZXNzYXJ5IHRvIGNoZWNrIGlmIGFuIGluc3RhbmNlIG9mXG5cdFx0XHQvLyBXZWJHTFRleHR1cmUgY2FuIGJlIGRlbGV0ZWQgaW4gb3JkZXIgdG8gYXZvaWQgYSBtZW1vcnkgbGVhay5cblxuXHRcdFx0Y29uc3Qgd2ViZ2xUZXh0dXJlID0gd2ViZ2xUZXh0dXJlc1sgdGV4dHVyZVByb3BlcnRpZXMuX19jYWNoZUtleSBdO1xuXG5cdFx0XHRpZiAoIHdlYmdsVGV4dHVyZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHdlYmdsVGV4dHVyZXNbIHRleHR1cmVQcm9wZXJ0aWVzLl9fY2FjaGVLZXkgXS51c2VkVGltZXMgLS07XG5cblx0XHRcdFx0aWYgKCB3ZWJnbFRleHR1cmUudXNlZFRpbWVzID09PSAwICkge1xuXG5cdFx0XHRcdFx0ZGVsZXRlVGV4dHVyZSggdGV4dHVyZSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBzdG9yZSByZWZlcmVuY2VzIHRvIGNhY2hlIGtleSBhbmQgV2ViR0xUZXh0dXJlIG9iamVjdFxuXG5cdFx0XHR0ZXh0dXJlUHJvcGVydGllcy5fX2NhY2hlS2V5ID0gdGV4dHVyZUNhY2hlS2V5O1xuXHRcdFx0dGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgPSB3ZWJnbFRleHR1cmVzWyB0ZXh0dXJlQ2FjaGVLZXkgXS50ZXh0dXJlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGZvcmNlVXBsb2FkO1xuXG5cdH1cblxuXHRmdW5jdGlvbiB1cGxvYWRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSwgc2xvdCApIHtcblxuXHRcdGxldCB0ZXh0dXJlVHlwZSA9IF9nbC5URVhUVVJFXzJEO1xuXG5cdFx0aWYgKCB0ZXh0dXJlLmlzRGF0YUFycmF5VGV4dHVyZSB8fCB0ZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHRleHR1cmVUeXBlID0gX2dsLlRFWFRVUkVfMkRfQVJSQVk7XG5cdFx0aWYgKCB0ZXh0dXJlLmlzRGF0YTNEVGV4dHVyZSApIHRleHR1cmVUeXBlID0gX2dsLlRFWFRVUkVfM0Q7XG5cblx0XHRjb25zdCBmb3JjZVVwbG9hZCA9IGluaXRUZXh0dXJlKCB0ZXh0dXJlUHJvcGVydGllcywgdGV4dHVyZSApO1xuXHRcdGNvbnN0IHNvdXJjZSA9IHRleHR1cmUuc291cmNlO1xuXG5cdFx0c3RhdGUuYmluZFRleHR1cmUoIHRleHR1cmVUeXBlLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgX2dsLlRFWFRVUkUwICsgc2xvdCApO1xuXG5cdFx0Y29uc3Qgc291cmNlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBzb3VyY2UgKTtcblxuXHRcdGlmICggc291cmNlLnZlcnNpb24gIT09IHNvdXJjZVByb3BlcnRpZXMuX192ZXJzaW9uIHx8IGZvcmNlVXBsb2FkID09PSB0cnVlICkge1xuXG5cdFx0XHRzdGF0ZS5hY3RpdmVUZXh0dXJlKCBfZ2wuVEVYVFVSRTAgKyBzbG90ICk7XG5cblx0XHRcdGNvbnN0IHdvcmtpbmdQcmltYXJpZXMgPSBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCBDb2xvck1hbmFnZW1lbnQud29ya2luZ0NvbG9yU3BhY2UgKTtcblx0XHRcdGNvbnN0IHRleHR1cmVQcmltYXJpZXMgPSB0ZXh0dXJlLmNvbG9yU3BhY2UgPT09IE5vQ29sb3JTcGFjZSA/IG51bGwgOiBDb2xvck1hbmFnZW1lbnQuZ2V0UHJpbWFyaWVzKCB0ZXh0dXJlLmNvbG9yU3BhY2UgKTtcblx0XHRcdGNvbnN0IHVucGFja0NvbnZlcnNpb24gPSB0ZXh0dXJlLmNvbG9yU3BhY2UgPT09IE5vQ29sb3JTcGFjZSB8fCB3b3JraW5nUHJpbWFyaWVzID09PSB0ZXh0dXJlUHJpbWFyaWVzID8gX2dsLk5PTkUgOiBfZ2wuQlJPV1NFUl9ERUZBVUxUX1dFQkdMO1xuXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfRkxJUF9ZX1dFQkdMLCB0ZXh0dXJlLmZsaXBZICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfUFJFTVVMVElQTFlfQUxQSEFfV0VCR0wsIHRleHR1cmUucHJlbXVsdGlwbHlBbHBoYSApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0FMSUdOTUVOVCwgdGV4dHVyZS51bnBhY2tBbGlnbm1lbnQgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19DT0xPUlNQQUNFX0NPTlZFUlNJT05fV0VCR0wsIHVucGFja0NvbnZlcnNpb24gKTtcblxuXHRcdFx0bGV0IGltYWdlID0gcmVzaXplSW1hZ2UoIHRleHR1cmUuaW1hZ2UsIGZhbHNlLCBjYXBhYmlsaXRpZXMubWF4VGV4dHVyZVNpemUgKTtcblx0XHRcdGltYWdlID0gdmVyaWZ5Q29sb3JTcGFjZSggdGV4dHVyZSwgaW1hZ2UgKTtcblxuXHRcdFx0Y29uc3QgZ2xGb3JtYXQgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLmZvcm1hdCwgdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cblx0XHRcdGNvbnN0IGdsVHlwZSA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUudHlwZSApO1xuXHRcdFx0bGV0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlLCB0ZXh0dXJlLmlzVmlkZW9UZXh0dXJlICk7XG5cblx0XHRcdHNldFRleHR1cmVQYXJhbWV0ZXJzKCB0ZXh0dXJlVHlwZSwgdGV4dHVyZSApO1xuXG5cdFx0XHRsZXQgbWlwbWFwO1xuXHRcdFx0Y29uc3QgbWlwbWFwcyA9IHRleHR1cmUubWlwbWFwcztcblxuXHRcdFx0Y29uc3QgdXNlVGV4U3RvcmFnZSA9ICggdGV4dHVyZS5pc1ZpZGVvVGV4dHVyZSAhPT0gdHJ1ZSApO1xuXHRcdFx0Y29uc3QgYWxsb2NhdGVNZW1vcnkgPSAoIHNvdXJjZVByb3BlcnRpZXMuX192ZXJzaW9uID09PSB1bmRlZmluZWQgKSB8fCAoIGZvcmNlVXBsb2FkID09PSB0cnVlICk7XG5cdFx0XHRjb25zdCBkYXRhUmVhZHkgPSBzb3VyY2UuZGF0YVJlYWR5O1xuXHRcdFx0Y29uc3QgbGV2ZWxzID0gZ2V0TWlwTGV2ZWxzKCB0ZXh0dXJlLCBpbWFnZSApO1xuXG5cdFx0XHRpZiAoIHRleHR1cmUuaXNEZXB0aFRleHR1cmUgKSB7XG5cblx0XHRcdFx0Z2xJbnRlcm5hbEZvcm1hdCA9IGdldEludGVybmFsRGVwdGhGb3JtYXQoIHRleHR1cmUuZm9ybWF0ID09PSBEZXB0aFN0ZW5jaWxGb3JtYXQsIHRleHR1cmUudHlwZSApO1xuXG5cdFx0XHRcdC8vXG5cblx0XHRcdFx0aWYgKCBhbGxvY2F0ZU1lbW9yeSApIHtcblxuXHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgMSwgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG51bGwgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSBpZiAoIHRleHR1cmUuaXNEYXRhVGV4dHVyZSApIHtcblxuXHRcdFx0XHQvLyB1c2UgbWFudWFsbHkgY3JlYXRlZCBtaXBtYXBzIGlmIGF2YWlsYWJsZVxuXHRcdFx0XHQvLyBpZiB0aGVyZSBhcmUgbm8gbWFudWFsIG1pcG1hcHNcblx0XHRcdFx0Ly8gc2V0IDAgbGV2ZWwgbWlwbWFwIGFuZCB0aGVuIHVzZSBHTCB0byBnZW5lcmF0ZSBvdGhlciBtaXBtYXAgbGV2ZWxzXG5cblx0XHRcdFx0aWYgKCBtaXBtYXBzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgJiYgYWxsb2NhdGVNZW1vcnkgKSB7XG5cblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwc1sgMCBdLndpZHRoLCBtaXBtYXBzWyAwIF0uaGVpZ2h0ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbWlwbWFwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0bWlwbWFwID0gbWlwbWFwc1sgaSBdO1xuXG5cdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgMCwgMCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR0ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdGlmICggYWxsb2NhdGVNZW1vcnkgKSB7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0ICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIDAsIDAsIDAsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSBpZiAoIHRleHR1cmUuaXNDb21wcmVzc2VkVGV4dHVyZSApIHtcblxuXHRcdFx0XHRpZiAoIHRleHR1cmUuaXNDb21wcmVzc2VkQXJyYXlUZXh0dXJlICkge1xuXG5cdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICYmIGFsbG9jYXRlTWVtb3J5ICkge1xuXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlM0QoIF9nbC5URVhUVVJFXzJEX0FSUkFZLCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcHNbIDAgXS53aWR0aCwgbWlwbWFwc1sgMCBdLmhlaWdodCwgaW1hZ2UuZGVwdGggKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBtaXBtYXBzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRtaXBtYXAgPSBtaXBtYXBzWyBpIF07XG5cblx0XHRcdFx0XHRcdGlmICggdGV4dHVyZS5mb3JtYXQgIT09IFJHQkFGb3JtYXQgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBnbEZvcm1hdCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0aWYgKCB0ZXh0dXJlLmxheWVyVXBkYXRlcy5zaXplID4gMCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdGNvbnN0IGxheWVyQnl0ZUxlbmd0aCA9IGdldEJ5dGVMZW5ndGgoIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUudHlwZSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Zm9yICggY29uc3QgbGF5ZXJJbmRleCBvZiB0ZXh0dXJlLmxheWVyVXBkYXRlcyApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0Y29uc3QgbGF5ZXJEYXRhID0gbWlwbWFwLmRhdGEuc3ViYXJyYXkoXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdGxheWVySW5kZXggKiBsYXllckJ5dGVMZW5ndGggLyBtaXBtYXAuZGF0YS5CWVRFU19QRVJfRUxFTUVOVCxcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdFx0KCBsYXllckluZGV4ICsgMSApICogbGF5ZXJCeXRlTGVuZ3RoIC8gbWlwbWFwLmRhdGEuQllURVNfUEVSX0VMRU1FTlRcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRcdCk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS5jb21wcmVzc2VkVGV4U3ViSW1hZ2UzRCggX2dsLlRFWFRVUkVfMkRfQVJSQVksIGksIDAsIDAsIGxheWVySW5kZXgsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMSwgZ2xGb3JtYXQsIGxheWVyRGF0YSwgMCwgMCApO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0dGV4dHVyZS5jbGVhckxheWVyVXBkYXRlcygpO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS5jb21wcmVzc2VkVGV4U3ViSW1hZ2UzRCggX2dsLlRFWFRVUkVfMkRfQVJSQVksIGksIDAsIDAsIDAsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgaW1hZ2UuZGVwdGgsIGdsRm9ybWF0LCBtaXBtYXAuZGF0YSwgMCwgMCApO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUuY29tcHJlc3NlZFRleEltYWdlM0QoIF9nbC5URVhUVVJFXzJEX0FSUkFZLCBpLCBnbEludGVybmFsRm9ybWF0LCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGltYWdlLmRlcHRoLCAwLCBtaXBtYXAuZGF0YSwgMCwgMCApO1xuXG5cdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBBdHRlbXB0IHRvIGxvYWQgdW5zdXBwb3J0ZWQgY29tcHJlc3NlZCB0ZXh0dXJlIGZvcm1hdCBpbiAudXBsb2FkVGV4dHVyZSgpJyApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UzRCggX2dsLlRFWFRVUkVfMkRfQVJSQVksIGksIDAsIDAsIDAsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgaW1hZ2UuZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcC5kYXRhICk7XG5cblx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlM0QoIF9nbC5URVhUVVJFXzJEX0FSUkFZLCBpLCBnbEludGVybmFsRm9ybWF0LCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGltYWdlLmRlcHRoLCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgJiYgYWxsb2NhdGVNZW1vcnkgKSB7XG5cblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwc1sgMCBdLndpZHRoLCBtaXBtYXBzWyAwIF0uaGVpZ2h0ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbWlwbWFwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0bWlwbWFwID0gbWlwbWFwc1sgaSBdO1xuXG5cdFx0XHRcdFx0XHRpZiAoIHRleHR1cmUuZm9ybWF0ICE9PSBSR0JBRm9ybWF0ICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggZ2xGb3JtYXQgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLmNvbXByZXNzZWRUZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgMCwgMCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBnbEZvcm1hdCwgbWlwbWFwLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUuY29tcHJlc3NlZFRleEltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBpLCBnbEludGVybmFsRm9ybWF0LCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIDAsIG1pcG1hcC5kYXRhICk7XG5cblx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IEF0dGVtcHQgdG8gbG9hZCB1bnN1cHBvcnRlZCBjb21wcmVzc2VkIHRleHR1cmUgZm9ybWF0IGluIC51cGxvYWRUZXh0dXJlKCknICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgMCwgMCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0RhdGFBcnJheVRleHR1cmUgKSB7XG5cblx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xuXG5cdFx0XHRcdFx0aWYgKCBhbGxvY2F0ZU1lbW9yeSApIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0LCBpbWFnZS5kZXB0aCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdGlmICggdGV4dHVyZS5sYXllclVwZGF0ZXMuc2l6ZSA+IDAgKSB7XG5cblx0XHRcdFx0XHRcdFx0Y29uc3QgbGF5ZXJCeXRlTGVuZ3RoID0gZ2V0Qnl0ZUxlbmd0aCggaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUudHlwZSApO1xuXG5cdFx0XHRcdFx0XHRcdGZvciAoIGNvbnN0IGxheWVySW5kZXggb2YgdGV4dHVyZS5sYXllclVwZGF0ZXMgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRjb25zdCBsYXllckRhdGEgPSBpbWFnZS5kYXRhLnN1YmFycmF5KFxuXHRcdFx0XHRcdFx0XHRcdFx0bGF5ZXJJbmRleCAqIGxheWVyQnl0ZUxlbmd0aCAvIGltYWdlLmRhdGEuQllURVNfUEVSX0VMRU1FTlQsXG5cdFx0XHRcdFx0XHRcdFx0XHQoIGxheWVySW5kZXggKyAxICkgKiBsYXllckJ5dGVMZW5ndGggLyBpbWFnZS5kYXRhLkJZVEVTX1BFUl9FTEVNRU5UXG5cdFx0XHRcdFx0XHRcdFx0KTtcblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgMCwgMCwgMCwgbGF5ZXJJbmRleCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgMSwgZ2xGb3JtYXQsIGdsVHlwZSwgbGF5ZXJEYXRhICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdHRleHR1cmUuY2xlYXJMYXllclVwZGF0ZXMoKTtcblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgMCwgMCwgMCwgMCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTNEKCBfZ2wuVEVYVFVSRV8yRF9BUlJBWSwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGgsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSBpZiAoIHRleHR1cmUuaXNEYXRhM0RUZXh0dXJlICkge1xuXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdGlmICggYWxsb2NhdGVNZW1vcnkgKSB7XG5cblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UzRCggX2dsLlRFWFRVUkVfM0QsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGggKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xuXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTNEKCBfZ2wuVEVYVFVSRV8zRCwgMCwgMCwgMCwgMCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgaW1hZ2UuZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UzRCggX2dsLlRFWFRVUkVfM0QsIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGltYWdlLndpZHRoLCBpbWFnZS5oZWlnaHQsIGltYWdlLmRlcHRoLCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBpbWFnZS5kYXRhICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLmlzRnJhbWVidWZmZXJUZXh0dXJlICkge1xuXG5cdFx0XHRcdGlmICggYWxsb2NhdGVNZW1vcnkgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0bGV0IHdpZHRoID0gaW1hZ2Uud2lkdGgsIGhlaWdodCA9IGltYWdlLmhlaWdodDtcblxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbGV2ZWxzOyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBpLCBnbEludGVybmFsRm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBudWxsICk7XG5cblx0XHRcdFx0XHRcdFx0d2lkdGggPj49IDE7XG5cdFx0XHRcdFx0XHRcdGhlaWdodCA+Pj0gMTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHQvLyByZWd1bGFyIFRleHR1cmUgKGltYWdlLCB2aWRlbywgY2FudmFzKVxuXG5cdFx0XHRcdC8vIHVzZSBtYW51YWxseSBjcmVhdGVkIG1pcG1hcHMgaWYgYXZhaWxhYmxlXG5cdFx0XHRcdC8vIGlmIHRoZXJlIGFyZSBubyBtYW51YWwgbWlwbWFwc1xuXHRcdFx0XHQvLyBzZXQgMCBsZXZlbCBtaXBtYXAgYW5kIHRoZW4gdXNlIEdMIHRvIGdlbmVyYXRlIG90aGVyIG1pcG1hcCBsZXZlbHNcblxuXHRcdFx0XHRpZiAoIG1pcG1hcHMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgZGltZW5zaW9ucyA9IGdldERpbWVuc2lvbnMoIG1pcG1hcHNbIDAgXSApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdG9yYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbHMsIGdsSW50ZXJuYWxGb3JtYXQsIGRpbWVuc2lvbnMud2lkdGgsIGRpbWVuc2lvbnMuaGVpZ2h0ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gbWlwbWFwcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0bWlwbWFwID0gbWlwbWFwc1sgaSBdO1xuXG5cdFx0XHRcdFx0XHRpZiAoIHVzZVRleFN0b3JhZ2UgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgaSwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBpLCBnbEludGVybmFsRm9ybWF0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0dGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xuXG5cdFx0XHRcdFx0XHRpZiAoIGFsbG9jYXRlTWVtb3J5ICkge1xuXG5cdFx0XHRcdFx0XHRcdGNvbnN0IGRpbWVuc2lvbnMgPSBnZXREaW1lbnNpb25zKCBpbWFnZSApO1xuXG5cdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgZGltZW5zaW9ucy53aWR0aCwgZGltZW5zaW9ucy5oZWlnaHQgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcblxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV8yRCwgMCwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlICkgKSB7XG5cblx0XHRcdFx0Z2VuZXJhdGVNaXBtYXAoIHRleHR1cmVUeXBlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0c291cmNlUHJvcGVydGllcy5fX3ZlcnNpb24gPSBzb3VyY2UudmVyc2lvbjtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlLm9uVXBkYXRlICkgdGV4dHVyZS5vblVwZGF0ZSggdGV4dHVyZSApO1xuXG5cdFx0fVxuXG5cdFx0dGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uID0gdGV4dHVyZS52ZXJzaW9uO1xuXG5cdH1cblxuXHRmdW5jdGlvbiB1cGxvYWRDdWJlVGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMsIHRleHR1cmUsIHNsb3QgKSB7XG5cblx0XHRpZiAoIHRleHR1cmUuaW1hZ2UubGVuZ3RoICE9PSA2ICkgcmV0dXJuO1xuXG5cdFx0Y29uc3QgZm9yY2VVcGxvYWQgPSBpbml0VGV4dHVyZSggdGV4dHVyZVByb3BlcnRpZXMsIHRleHR1cmUgKTtcblx0XHRjb25zdCBzb3VyY2UgPSB0ZXh0dXJlLnNvdXJjZTtcblxuXHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBfZ2wuVEVYVFVSRV9DVUJFX01BUCwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIF9nbC5URVhUVVJFMCArIHNsb3QgKTtcblxuXHRcdGNvbnN0IHNvdXJjZVByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggc291cmNlICk7XG5cblx0XHRpZiAoIHNvdXJjZS52ZXJzaW9uICE9PSBzb3VyY2VQcm9wZXJ0aWVzLl9fdmVyc2lvbiB8fCBmb3JjZVVwbG9hZCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0c3RhdGUuYWN0aXZlVGV4dHVyZSggX2dsLlRFWFRVUkUwICsgc2xvdCApO1xuXG5cdFx0XHRjb25zdCB3b3JraW5nUHJpbWFyaWVzID0gQ29sb3JNYW5hZ2VtZW50LmdldFByaW1hcmllcyggQ29sb3JNYW5hZ2VtZW50LndvcmtpbmdDb2xvclNwYWNlICk7XG5cdFx0XHRjb25zdCB0ZXh0dXJlUHJpbWFyaWVzID0gdGV4dHVyZS5jb2xvclNwYWNlID09PSBOb0NvbG9yU3BhY2UgPyBudWxsIDogQ29sb3JNYW5hZ2VtZW50LmdldFByaW1hcmllcyggdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cdFx0XHRjb25zdCB1bnBhY2tDb252ZXJzaW9uID0gdGV4dHVyZS5jb2xvclNwYWNlID09PSBOb0NvbG9yU3BhY2UgfHwgd29ya2luZ1ByaW1hcmllcyA9PT0gdGV4dHVyZVByaW1hcmllcyA/IF9nbC5OT05FIDogX2dsLkJST1dTRVJfREVGQVVMVF9XRUJHTDtcblxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0ZMSVBfWV9XRUJHTCwgdGV4dHVyZS5mbGlwWSApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1BSRU1VTFRJUExZX0FMUEhBX1dFQkdMLCB0ZXh0dXJlLnByZW11bHRpcGx5QWxwaGEgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19BTElHTk1FTlQsIHRleHR1cmUudW5wYWNrQWxpZ25tZW50ICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfQ09MT1JTUEFDRV9DT05WRVJTSU9OX1dFQkdMLCB1bnBhY2tDb252ZXJzaW9uICk7XG5cblx0XHRcdGNvbnN0IGlzQ29tcHJlc3NlZCA9ICggdGV4dHVyZS5pc0NvbXByZXNzZWRUZXh0dXJlIHx8IHRleHR1cmUuaW1hZ2VbIDAgXS5pc0NvbXByZXNzZWRUZXh0dXJlICk7XG5cdFx0XHRjb25zdCBpc0RhdGFUZXh0dXJlID0gKCB0ZXh0dXJlLmltYWdlWyAwIF0gJiYgdGV4dHVyZS5pbWFnZVsgMCBdLmlzRGF0YVRleHR1cmUgKTtcblxuXHRcdFx0Y29uc3QgY3ViZUltYWdlID0gW107XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdFx0aWYgKCAhIGlzQ29tcHJlc3NlZCAmJiAhIGlzRGF0YVRleHR1cmUgKSB7XG5cblx0XHRcdFx0XHRjdWJlSW1hZ2VbIGkgXSA9IHJlc2l6ZUltYWdlKCB0ZXh0dXJlLmltYWdlWyBpIF0sIHRydWUsIGNhcGFiaWxpdGllcy5tYXhDdWJlbWFwU2l6ZSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRjdWJlSW1hZ2VbIGkgXSA9IGlzRGF0YVRleHR1cmUgPyB0ZXh0dXJlLmltYWdlWyBpIF0uaW1hZ2UgOiB0ZXh0dXJlLmltYWdlWyBpIF07XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGN1YmVJbWFnZVsgaSBdID0gdmVyaWZ5Q29sb3JTcGFjZSggdGV4dHVyZSwgY3ViZUltYWdlWyBpIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBpbWFnZSA9IGN1YmVJbWFnZVsgMCBdLFxuXHRcdFx0XHRnbEZvcm1hdCA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUuZm9ybWF0LCB0ZXh0dXJlLmNvbG9yU3BhY2UgKSxcblx0XHRcdFx0Z2xUeXBlID0gdXRpbHMuY29udmVydCggdGV4dHVyZS50eXBlICksXG5cdFx0XHRcdGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cblx0XHRcdGNvbnN0IHVzZVRleFN0b3JhZ2UgPSAoIHRleHR1cmUuaXNWaWRlb1RleHR1cmUgIT09IHRydWUgKTtcblx0XHRcdGNvbnN0IGFsbG9jYXRlTWVtb3J5ID0gKCBzb3VyY2VQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9PT0gdW5kZWZpbmVkICkgfHwgKCBmb3JjZVVwbG9hZCA9PT0gdHJ1ZSApO1xuXHRcdFx0Y29uc3QgZGF0YVJlYWR5ID0gc291cmNlLmRhdGFSZWFkeTtcblx0XHRcdGxldCBsZXZlbHMgPSBnZXRNaXBMZXZlbHMoIHRleHR1cmUsIGltYWdlICk7XG5cblx0XHRcdHNldFRleHR1cmVQYXJhbWV0ZXJzKCBfZ2wuVEVYVFVSRV9DVUJFX01BUCwgdGV4dHVyZSApO1xuXG5cdFx0XHRsZXQgbWlwbWFwcztcblxuXHRcdFx0aWYgKCBpc0NvbXByZXNzZWQgKSB7XG5cblx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICYmIGFsbG9jYXRlTWVtb3J5ICkge1xuXG5cdFx0XHRcdFx0c3RhdGUudGV4U3RvcmFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUCwgbGV2ZWxzLCBnbEludGVybmFsRm9ybWF0LCBpbWFnZS53aWR0aCwgaW1hZ2UuaGVpZ2h0ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRtaXBtYXBzID0gY3ViZUltYWdlWyBpIF0ubWlwbWFwcztcblxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IG1pcG1hcHMubGVuZ3RoOyBqICsrICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBtaXBtYXAgPSBtaXBtYXBzWyBqIF07XG5cblx0XHRcdFx0XHRcdGlmICggdGV4dHVyZS5mb3JtYXQgIT09IFJHQkFGb3JtYXQgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBnbEZvcm1hdCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdFx0c3RhdGUuY29tcHJlc3NlZFRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqLCAwLCAwLCBtaXBtYXAud2lkdGgsIG1pcG1hcC5oZWlnaHQsIGdsRm9ybWF0LCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS5jb21wcmVzc2VkVGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIGosIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcC53aWR0aCwgbWlwbWFwLmhlaWdodCwgMCwgbWlwbWFwLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQXR0ZW1wdCB0byBsb2FkIHVuc3VwcG9ydGVkIGNvbXByZXNzZWQgdGV4dHVyZSBmb3JtYXQgaW4gLnNldFRleHR1cmVDdWJlKCknICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhTdWJJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgaiwgMCwgMCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgaiwgZ2xJbnRlcm5hbEZvcm1hdCwgbWlwbWFwLndpZHRoLCBtaXBtYXAuaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRtaXBtYXBzID0gdGV4dHVyZS5taXBtYXBzO1xuXG5cdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSAmJiBhbGxvY2F0ZU1lbW9yeSApIHtcblxuXHRcdFx0XHRcdC8vIFRPRE86IFVuaWZvcm1seSBoYW5kbGUgbWlwbWFwIGRlZmluaXRpb25zXG5cdFx0XHRcdFx0Ly8gTm9ybWFsIHRleHR1cmVzIGFuZCBjb21wcmVzc2VkIGN1YmUgdGV4dHVyZXMgZGVmaW5lIGJhc2UgbGV2ZWwgKyBtaXBzIHdpdGggdGhlaXIgbWlwbWFwIGFycmF5XG5cdFx0XHRcdFx0Ly8gVW5jb21wcmVzc2VkIGN1YmUgdGV4dHVyZXMgdXNlIHRoZWlyIG1pcG1hcCBhcnJheSBvbmx5IGZvciBtaXBzIChubyBiYXNlIGxldmVsKVxuXG5cdFx0XHRcdFx0aWYgKCBtaXBtYXBzLmxlbmd0aCA+IDAgKSBsZXZlbHMgKys7XG5cblx0XHRcdFx0XHRjb25zdCBkaW1lbnNpb25zID0gZ2V0RGltZW5zaW9ucyggY3ViZUltYWdlWyAwIF0gKTtcblxuXHRcdFx0XHRcdHN0YXRlLnRleFN0b3JhZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVAsIGxldmVscywgZ2xJbnRlcm5hbEZvcm1hdCwgZGltZW5zaW9ucy53aWR0aCwgZGltZW5zaW9ucy5oZWlnaHQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNjsgaSArKyApIHtcblxuXHRcdFx0XHRcdGlmICggaXNEYXRhVGV4dHVyZSApIHtcblxuXHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggZGF0YVJlYWR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIDAsIDAsIDAsIGN1YmVJbWFnZVsgaSBdLndpZHRoLCBjdWJlSW1hZ2VbIGkgXS5oZWlnaHQsIGdsRm9ybWF0LCBnbFR5cGUsIGN1YmVJbWFnZVsgaSBdLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIDAsIGdsSW50ZXJuYWxGb3JtYXQsIGN1YmVJbWFnZVsgaSBdLndpZHRoLCBjdWJlSW1hZ2VbIGkgXS5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIGN1YmVJbWFnZVsgaSBdLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBtaXBtYXBzLmxlbmd0aDsgaiArKyApIHtcblxuXHRcdFx0XHRcdFx0XHRjb25zdCBtaXBtYXAgPSBtaXBtYXBzWyBqIF07XG5cdFx0XHRcdFx0XHRcdGNvbnN0IG1pcG1hcEltYWdlID0gbWlwbWFwLmltYWdlWyBpIF0uaW1hZ2U7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqICsgMSwgMCwgMCwgbWlwbWFwSW1hZ2Uud2lkdGgsIG1pcG1hcEltYWdlLmhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwSW1hZ2UuZGF0YSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgaiArIDEsIGdsSW50ZXJuYWxGb3JtYXQsIG1pcG1hcEltYWdlLndpZHRoLCBtaXBtYXBJbWFnZS5oZWlnaHQsIDAsIGdsRm9ybWF0LCBnbFR5cGUsIG1pcG1hcEltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGlmICggdXNlVGV4U3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0XHRpZiAoIGRhdGFSZWFkeSApIHtcblxuXHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCAwLCAwLCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBjdWJlSW1hZ2VbIGkgXSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRzdGF0ZS50ZXhJbWFnZTJEKCBfZ2wuVEVYVFVSRV9DVUJFX01BUF9QT1NJVElWRV9YICsgaSwgMCwgZ2xJbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgY3ViZUltYWdlWyBpIF0gKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBtaXBtYXBzLmxlbmd0aDsgaiArKyApIHtcblxuXHRcdFx0XHRcdFx0XHRjb25zdCBtaXBtYXAgPSBtaXBtYXBzWyBqIF07XG5cblx0XHRcdFx0XHRcdFx0aWYgKCB1c2VUZXhTdG9yYWdlICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBkYXRhUmVhZHkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdHN0YXRlLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBqICsgMSwgMCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbWlwbWFwLmltYWdlWyBpIF0gKTtcblxuXHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdFx0c3RhdGUudGV4SW1hZ2UyRCggX2dsLlRFWFRVUkVfQ1VCRV9NQVBfUE9TSVRJVkVfWCArIGksIGogKyAxLCBnbEludGVybmFsRm9ybWF0LCBnbEZvcm1hdCwgZ2xUeXBlLCBtaXBtYXAuaW1hZ2VbIGkgXSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRleHR1cmVOZWVkc0dlbmVyYXRlTWlwbWFwcyggdGV4dHVyZSApICkge1xuXG5cdFx0XHRcdC8vIFdlIGFzc3VtZSBpbWFnZXMgZm9yIGN1YmUgbWFwIGhhdmUgdGhlIHNhbWUgc2l6ZS5cblx0XHRcdFx0Z2VuZXJhdGVNaXBtYXAoIF9nbC5URVhUVVJFX0NVQkVfTUFQICk7XG5cblx0XHRcdH1cblxuXHRcdFx0c291cmNlUHJvcGVydGllcy5fX3ZlcnNpb24gPSBzb3VyY2UudmVyc2lvbjtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlLm9uVXBkYXRlICkgdGV4dHVyZS5vblVwZGF0ZSggdGV4dHVyZSApO1xuXG5cdFx0fVxuXG5cdFx0dGV4dHVyZVByb3BlcnRpZXMuX192ZXJzaW9uID0gdGV4dHVyZS52ZXJzaW9uO1xuXG5cdH1cblxuXHQvLyBSZW5kZXIgdGFyZ2V0c1xuXG5cdC8vIFNldHVwIHN0b3JhZ2UgZm9yIHRhcmdldCB0ZXh0dXJlIGFuZCBiaW5kIGl0IHRvIGNvcnJlY3QgZnJhbWVidWZmZXJcblx0ZnVuY3Rpb24gc2V0dXBGcmFtZUJ1ZmZlclRleHR1cmUoIGZyYW1lYnVmZmVyLCByZW5kZXJUYXJnZXQsIHRleHR1cmUsIGF0dGFjaG1lbnQsIHRleHR1cmVUYXJnZXQsIGxldmVsICkge1xuXG5cdFx0Y29uc3QgZ2xGb3JtYXQgPSB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlLmZvcm1hdCwgdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cdFx0Y29uc3QgZ2xUeXBlID0gdXRpbHMuY29udmVydCggdGV4dHVyZS50eXBlICk7XG5cdFx0Y29uc3QgZ2xJbnRlcm5hbEZvcm1hdCA9IGdldEludGVybmFsRm9ybWF0KCB0ZXh0dXJlLmludGVybmFsRm9ybWF0LCBnbEZvcm1hdCwgZ2xUeXBlLCB0ZXh0dXJlLmNvbG9yU3BhY2UgKTtcblx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xuXG5cdFx0aWYgKCAhIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX19oYXNFeHRlcm5hbFRleHR1cmVzICkge1xuXG5cdFx0XHRjb25zdCB3aWR0aCA9IE1hdGgubWF4KCAxLCByZW5kZXJUYXJnZXQud2lkdGggPj4gbGV2ZWwgKTtcblx0XHRcdGNvbnN0IGhlaWdodCA9IE1hdGgubWF4KCAxLCByZW5kZXJUYXJnZXQuaGVpZ2h0ID4+IGxldmVsICk7XG5cblx0XHRcdGlmICggdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfM0QgfHwgdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfMkRfQVJSQVkgKSB7XG5cblx0XHRcdFx0c3RhdGUudGV4SW1hZ2UzRCggdGV4dHVyZVRhcmdldCwgbGV2ZWwsIGdsSW50ZXJuYWxGb3JtYXQsIHdpZHRoLCBoZWlnaHQsIHJlbmRlclRhcmdldC5kZXB0aCwgMCwgZ2xGb3JtYXQsIGdsVHlwZSwgbnVsbCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHN0YXRlLnRleEltYWdlMkQoIHRleHR1cmVUYXJnZXQsIGxldmVsLCBnbEludGVybmFsRm9ybWF0LCB3aWR0aCwgaGVpZ2h0LCAwLCBnbEZvcm1hdCwgZ2xUeXBlLCBudWxsICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xuXG5cdFx0aWYgKCB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApICkge1xuXG5cdFx0XHRtdWx0aXNhbXBsZWRSVFRFeHQuZnJhbWVidWZmZXJUZXh0dXJlMkRNdWx0aXNhbXBsZUVYVCggX2dsLkZSQU1FQlVGRkVSLCBhdHRhY2htZW50LCB0ZXh0dXJlVGFyZ2V0LCBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlLCAwLCBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKSApO1xuXG5cdFx0fSBlbHNlIGlmICggdGV4dHVyZVRhcmdldCA9PT0gX2dsLlRFWFRVUkVfMkQgfHwgKCB0ZXh0dXJlVGFyZ2V0ID49IF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggJiYgdGV4dHVyZVRhcmdldCA8PSBfZ2wuVEVYVFVSRV9DVUJFX01BUF9ORUdBVElWRV9aICkgKSB7IC8vIHNlZSAjMjQ3NTNcblxuXHRcdFx0X2dsLmZyYW1lYnVmZmVyVGV4dHVyZTJEKCBfZ2wuRlJBTUVCVUZGRVIsIGF0dGFjaG1lbnQsIHRleHR1cmVUYXJnZXQsIHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICkuX193ZWJnbFRleHR1cmUsIGxldmVsICk7XG5cblx0XHR9XG5cblx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgbnVsbCApO1xuXG5cdH1cblxuXHQvLyBTZXR1cCBzdG9yYWdlIGZvciBpbnRlcm5hbCBkZXB0aC9zdGVuY2lsIGJ1ZmZlcnMgYW5kIGJpbmQgdG8gY29ycmVjdCBmcmFtZWJ1ZmZlclxuXHRmdW5jdGlvbiBzZXR1cFJlbmRlckJ1ZmZlclN0b3JhZ2UoIHJlbmRlcmJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCBpc011bHRpc2FtcGxlICkge1xuXG5cdFx0X2dsLmJpbmRSZW5kZXJidWZmZXIoIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlcmJ1ZmZlciApO1xuXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgKSB7XG5cblx0XHRcdC8vIHJldHJpZXZlIHRoZSBkZXB0aCBhdHRhY2htZW50IHR5cGVzXG5cdFx0XHRjb25zdCBkZXB0aFRleHR1cmUgPSByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlO1xuXHRcdFx0Y29uc3QgZGVwdGhUeXBlID0gZGVwdGhUZXh0dXJlICYmIGRlcHRoVGV4dHVyZS5pc0RlcHRoVGV4dHVyZSA/IGRlcHRoVGV4dHVyZS50eXBlIDogbnVsbDtcblx0XHRcdGNvbnN0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbERlcHRoRm9ybWF0KCByZW5kZXJUYXJnZXQuc3RlbmNpbEJ1ZmZlciwgZGVwdGhUeXBlICk7XG5cdFx0XHRjb25zdCBnbEF0dGFjaG1lbnRUeXBlID0gcmVuZGVyVGFyZ2V0LnN0ZW5jaWxCdWZmZXIgPyBfZ2wuREVQVEhfU1RFTkNJTF9BVFRBQ0hNRU5UIDogX2dsLkRFUFRIX0FUVEFDSE1FTlQ7XG5cblx0XHRcdC8vIHNldCB1cCB0aGUgYXR0YWNobWVudFxuXHRcdFx0Y29uc3Qgc2FtcGxlcyA9IGdldFJlbmRlclRhcmdldFNhbXBsZXMoIHJlbmRlclRhcmdldCApO1xuXHRcdFx0Y29uc3QgaXNVc2VNdWx0aXNhbXBsZWRSVFQgPSB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApO1xuXHRcdFx0aWYgKCBpc1VzZU11bHRpc2FtcGxlZFJUVCApIHtcblxuXHRcdFx0XHRtdWx0aXNhbXBsZWRSVFRFeHQucmVuZGVyYnVmZmVyU3RvcmFnZU11bHRpc2FtcGxlRVhUKCBfZ2wuUkVOREVSQlVGRkVSLCBzYW1wbGVzLCBnbEludGVybmFsRm9ybWF0LCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggaXNNdWx0aXNhbXBsZSApIHtcblxuXHRcdFx0XHRfZ2wucmVuZGVyYnVmZmVyU3RvcmFnZU11bHRpc2FtcGxlKCBfZ2wuUkVOREVSQlVGRkVSLCBzYW1wbGVzLCBnbEludGVybmFsRm9ybWF0LCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRfZ2wucmVuZGVyYnVmZmVyU3RvcmFnZSggX2dsLlJFTkRFUkJVRkZFUiwgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0X2dsLmZyYW1lYnVmZmVyUmVuZGVyYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIGdsQXR0YWNobWVudFR5cGUsIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlcmJ1ZmZlciApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc3QgdGV4dHVyZXMgPSByZW5kZXJUYXJnZXQudGV4dHVyZXM7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRleHR1cmVzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCB0ZXh0dXJlID0gdGV4dHVyZXNbIGkgXTtcblxuXHRcdFx0XHRjb25zdCBnbEZvcm1hdCA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUuZm9ybWF0LCB0ZXh0dXJlLmNvbG9yU3BhY2UgKTtcblx0XHRcdFx0Y29uc3QgZ2xUeXBlID0gdXRpbHMuY29udmVydCggdGV4dHVyZS50eXBlICk7XG5cdFx0XHRcdGNvbnN0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlICk7XG5cdFx0XHRcdGNvbnN0IHNhbXBsZXMgPSBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHRpZiAoIGlzTXVsdGlzYW1wbGUgJiYgdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0XHRfZ2wucmVuZGVyYnVmZmVyU3RvcmFnZU11bHRpc2FtcGxlKCBfZ2wuUkVOREVSQlVGRkVSLCBzYW1wbGVzLCBnbEludGVybmFsRm9ybWF0LCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCB1c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApICkge1xuXG5cdFx0XHRcdFx0bXVsdGlzYW1wbGVkUlRURXh0LnJlbmRlcmJ1ZmZlclN0b3JhZ2VNdWx0aXNhbXBsZUVYVCggX2dsLlJFTkRFUkJVRkZFUiwgc2FtcGxlcywgZ2xJbnRlcm5hbEZvcm1hdCwgcmVuZGVyVGFyZ2V0LndpZHRoLCByZW5kZXJUYXJnZXQuaGVpZ2h0ICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdF9nbC5yZW5kZXJidWZmZXJTdG9yYWdlKCBfZ2wuUkVOREVSQlVGRkVSLCBnbEludGVybmFsRm9ybWF0LCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdF9nbC5iaW5kUmVuZGVyYnVmZmVyKCBfZ2wuUkVOREVSQlVGRkVSLCBudWxsICk7XG5cblx0fVxuXG5cdC8vIFNldHVwIHJlc291cmNlcyBmb3IgYSBEZXB0aCBUZXh0dXJlIGZvciBhIEZCTyAobmVlZHMgYW4gZXh0ZW5zaW9uKVxuXHRmdW5jdGlvbiBzZXR1cERlcHRoVGV4dHVyZSggZnJhbWVidWZmZXIsIHJlbmRlclRhcmdldCApIHtcblxuXHRcdGNvbnN0IGlzQ3ViZSA9ICggcmVuZGVyVGFyZ2V0ICYmIHJlbmRlclRhcmdldC5pc1dlYkdMQ3ViZVJlbmRlclRhcmdldCApO1xuXHRcdGlmICggaXNDdWJlICkgdGhyb3cgbmV3IEVycm9yKCAnRGVwdGggVGV4dHVyZSB3aXRoIGN1YmUgcmVuZGVyIHRhcmdldHMgaXMgbm90IHN1cHBvcnRlZCcgKTtcblxuXHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xuXG5cdFx0aWYgKCAhICggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSAmJiByZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmlzRGVwdGhUZXh0dXJlICkgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ3JlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgbXVzdCBiZSBhbiBpbnN0YW5jZSBvZiBUSFJFRS5EZXB0aFRleHR1cmUnICk7XG5cblx0XHR9XG5cblx0XHQvLyB1cGxvYWQgYW4gZW1wdHkgZGVwdGggdGV4dHVyZSB3aXRoIGZyYW1lYnVmZmVyIHNpemVcblx0XHRpZiAoICEgcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgKS5fX3dlYmdsVGV4dHVyZSB8fFxuXHRcdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmltYWdlLndpZHRoICE9PSByZW5kZXJUYXJnZXQud2lkdGggfHxcblx0XHRcdFx0cmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZS5pbWFnZS5oZWlnaHQgIT09IHJlbmRlclRhcmdldC5oZWlnaHQgKSB7XG5cblx0XHRcdHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUuaW1hZ2Uud2lkdGggPSByZW5kZXJUYXJnZXQud2lkdGg7XG5cdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLmltYWdlLmhlaWdodCA9IHJlbmRlclRhcmdldC5oZWlnaHQ7XG5cdFx0XHRyZW5kZXJUYXJnZXQuZGVwdGhUZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdHNldFRleHR1cmUyRCggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSwgMCApO1xuXG5cdFx0Y29uc3Qgd2ViZ2xEZXB0aFRleHR1cmUgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlO1xuXHRcdGNvbnN0IHNhbXBsZXMgPSBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKTtcblxuXHRcdGlmICggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZS5mb3JtYXQgPT09IERlcHRoRm9ybWF0ICkge1xuXG5cdFx0XHRpZiAoIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgKSB7XG5cblx0XHRcdFx0bXVsdGlzYW1wbGVkUlRURXh0LmZyYW1lYnVmZmVyVGV4dHVyZTJETXVsdGlzYW1wbGVFWFQoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX0FUVEFDSE1FTlQsIF9nbC5URVhUVVJFXzJELCB3ZWJnbERlcHRoVGV4dHVyZSwgMCwgc2FtcGxlcyApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkZSQU1FQlVGRkVSLCBfZ2wuREVQVEhfQVRUQUNITUVOVCwgX2dsLlRFWFRVUkVfMkQsIHdlYmdsRGVwdGhUZXh0dXJlLCAwICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSBpZiAoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUuZm9ybWF0ID09PSBEZXB0aFN0ZW5jaWxGb3JtYXQgKSB7XG5cblx0XHRcdGlmICggdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSApIHtcblxuXHRcdFx0XHRtdWx0aXNhbXBsZWRSVFRFeHQuZnJhbWVidWZmZXJUZXh0dXJlMkRNdWx0aXNhbXBsZUVYVCggX2dsLkZSQU1FQlVGRkVSLCBfZ2wuREVQVEhfU1RFTkNJTF9BVFRBQ0hNRU5ULCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xEZXB0aFRleHR1cmUsIDAsIHNhbXBsZXMgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlMkQoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCwgX2dsLlRFWFRVUkVfMkQsIHdlYmdsRGVwdGhUZXh0dXJlLCAwICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1Vua25vd24gZGVwdGhUZXh0dXJlIGZvcm1hdCcgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Ly8gU2V0dXAgR0wgcmVzb3VyY2VzIGZvciBhIG5vbi10ZXh0dXJlIGRlcHRoIGJ1ZmZlclxuXHRmdW5jdGlvbiBzZXR1cERlcHRoUmVuZGVyYnVmZmVyKCByZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xuXHRcdGNvbnN0IGlzQ3ViZSA9ICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xDdWJlUmVuZGVyVGFyZ2V0ID09PSB0cnVlICk7XG5cblx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgJiYgISByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fYXV0b0FsbG9jYXRlRGVwdGhCdWZmZXIgKSB7XG5cblx0XHRcdGlmICggaXNDdWJlICkgdGhyb3cgbmV3IEVycm9yKCAndGFyZ2V0LmRlcHRoVGV4dHVyZSBub3Qgc3VwcG9ydGVkIGluIEN1YmUgcmVuZGVyIHRhcmdldHMnICk7XG5cblx0XHRcdHNldHVwRGVwdGhUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciwgcmVuZGVyVGFyZ2V0ICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIGlzQ3ViZSApIHtcblxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciA9IFtdO1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXSApO1xuXHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoYnVmZmVyWyBpIF0gPSBfZ2wuY3JlYXRlUmVuZGVyYnVmZmVyKCk7XG5cdFx0XHRcdFx0c2V0dXBSZW5kZXJCdWZmZXJTdG9yYWdlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlclsgaSBdLCByZW5kZXJUYXJnZXQsIGZhbHNlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciApO1xuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciA9IF9nbC5jcmVhdGVSZW5kZXJidWZmZXIoKTtcblx0XHRcdFx0c2V0dXBSZW5kZXJCdWZmZXJTdG9yYWdlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aGJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCBmYWxzZSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgbnVsbCApO1xuXG5cdH1cblxuXHQvLyByZWJpbmQgZnJhbWVidWZmZXIgd2l0aCBleHRlcm5hbCB0ZXh0dXJlc1xuXHRmdW5jdGlvbiByZWJpbmRUZXh0dXJlcyggcmVuZGVyVGFyZ2V0LCBjb2xvclRleHR1cmUsIGRlcHRoVGV4dHVyZSApIHtcblxuXHRcdGNvbnN0IHJlbmRlclRhcmdldFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRpZiAoIGNvbG9yVGV4dHVyZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRzZXR1cEZyYW1lQnVmZmVyVGV4dHVyZSggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIsIHJlbmRlclRhcmdldCwgcmVuZGVyVGFyZ2V0LnRleHR1cmUsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCwgX2dsLlRFWFRVUkVfMkQsIDAgKTtcblxuXHRcdH1cblxuXHRcdGlmICggZGVwdGhUZXh0dXJlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHNldHVwRGVwdGhSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHQvLyBTZXQgdXAgR0wgcmVzb3VyY2VzIGZvciB0aGUgcmVuZGVyIHRhcmdldFxuXHRmdW5jdGlvbiBzZXR1cFJlbmRlclRhcmdldCggcmVuZGVyVGFyZ2V0ICkge1xuXG5cdFx0Y29uc3QgdGV4dHVyZSA9IHJlbmRlclRhcmdldC50ZXh0dXJlO1xuXG5cdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcblx0XHRjb25zdCB0ZXh0dXJlUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCB0ZXh0dXJlICk7XG5cblx0XHRyZW5kZXJUYXJnZXQuYWRkRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblJlbmRlclRhcmdldERpc3Bvc2UgKTtcblxuXHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmVzO1xuXG5cdFx0Y29uc3QgaXNDdWJlID0gKCByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgPT09IHRydWUgKTtcblx0XHRjb25zdCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyA9ICggdGV4dHVyZXMubGVuZ3RoID4gMSApO1xuXG5cdFx0aWYgKCAhIGlzTXVsdGlwbGVSZW5kZXJUYXJnZXRzICkge1xuXG5cdFx0XHRpZiAoIHRleHR1cmVQcm9wZXJ0aWVzLl9fd2ViZ2xUZXh0dXJlID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgPSBfZ2wuY3JlYXRlVGV4dHVyZSgpO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRleHR1cmVQcm9wZXJ0aWVzLl9fdmVyc2lvbiA9IHRleHR1cmUudmVyc2lvbjtcblx0XHRcdGluZm8ubWVtb3J5LnRleHR1cmVzICsrO1xuXG5cdFx0fVxuXG5cdFx0Ly8gU2V0dXAgZnJhbWVidWZmZXJcblxuXHRcdGlmICggaXNDdWJlICkge1xuXG5cdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9IFtdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA2OyBpICsrICkge1xuXG5cdFx0XHRcdGlmICggdGV4dHVyZS5taXBtYXBzICYmIHRleHR1cmUubWlwbWFwcy5sZW5ndGggPiAwICkge1xuXG5cdFx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXSA9IFtdO1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGxldmVsID0gMDsgbGV2ZWwgPCB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoOyBsZXZlbCArKyApIHtcblxuXHRcdFx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXVsgbGV2ZWwgXSA9IF9nbC5jcmVhdGVGcmFtZWJ1ZmZlcigpO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgaSBdID0gX2dsLmNyZWF0ZUZyYW1lYnVmZmVyKCk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIHRleHR1cmUubWlwbWFwcyAmJiB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9IFtdO1xuXG5cdFx0XHRcdGZvciAoIGxldCBsZXZlbCA9IDA7IGxldmVsIDwgdGV4dHVyZS5taXBtYXBzLmxlbmd0aDsgbGV2ZWwgKysgKSB7XG5cblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgbGV2ZWwgXSA9IF9nbC5jcmVhdGVGcmFtZWJ1ZmZlcigpO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9IF9nbC5jcmVhdGVGcmFtZWJ1ZmZlcigpO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggaXNNdWx0aXBsZVJlbmRlclRhcmdldHMgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRleHR1cmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgYXR0YWNobWVudFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZXNbIGkgXSApO1xuXG5cdFx0XHRcdFx0aWYgKCBhdHRhY2htZW50UHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRhdHRhY2htZW50UHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSA9IF9nbC5jcmVhdGVUZXh0dXJlKCk7XG5cblx0XHRcdFx0XHRcdGluZm8ubWVtb3J5LnRleHR1cmVzICsrO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoICggcmVuZGVyVGFyZ2V0LnNhbXBsZXMgPiAwICkgJiYgdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsTXVsdGlzYW1wbGVkRnJhbWVidWZmZXIgPSBfZ2wuY3JlYXRlRnJhbWVidWZmZXIoKTtcblx0XHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsQ29sb3JSZW5kZXJidWZmZXIgPSBbXTtcblxuXHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsTXVsdGlzYW1wbGVkRnJhbWVidWZmZXIgKTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0ZXh0dXJlcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB0ZXh0dXJlID0gdGV4dHVyZXNbIGkgXTtcblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlclsgaSBdID0gX2dsLmNyZWF0ZVJlbmRlcmJ1ZmZlcigpO1xuXG5cdFx0XHRcdFx0X2dsLmJpbmRSZW5kZXJidWZmZXIoIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyWyBpIF0gKTtcblxuXHRcdFx0XHRcdGNvbnN0IGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggdGV4dHVyZS5mb3JtYXQsIHRleHR1cmUuY29sb3JTcGFjZSApO1xuXHRcdFx0XHRcdGNvbnN0IGdsVHlwZSA9IHV0aWxzLmNvbnZlcnQoIHRleHR1cmUudHlwZSApO1xuXHRcdFx0XHRcdGNvbnN0IGdsSW50ZXJuYWxGb3JtYXQgPSBnZXRJbnRlcm5hbEZvcm1hdCggdGV4dHVyZS5pbnRlcm5hbEZvcm1hdCwgZ2xGb3JtYXQsIGdsVHlwZSwgdGV4dHVyZS5jb2xvclNwYWNlLCByZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSApO1xuXHRcdFx0XHRcdGNvbnN0IHNhbXBsZXMgPSBnZXRSZW5kZXJUYXJnZXRTYW1wbGVzKCByZW5kZXJUYXJnZXQgKTtcblx0XHRcdFx0XHRfZ2wucmVuZGVyYnVmZmVyU3RvcmFnZU11bHRpc2FtcGxlKCBfZ2wuUkVOREVSQlVGRkVSLCBzYW1wbGVzLCBnbEludGVybmFsRm9ybWF0LCByZW5kZXJUYXJnZXQud2lkdGgsIHJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclJlbmRlcmJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAgKyBpLCBfZ2wuUkVOREVSQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xDb2xvclJlbmRlcmJ1ZmZlclsgaSBdICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdF9nbC5iaW5kUmVuZGVyYnVmZmVyKCBfZ2wuUkVOREVSQlVGRkVSLCBudWxsICk7XG5cblx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgKSB7XG5cblx0XHRcdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xEZXB0aFJlbmRlcmJ1ZmZlciA9IF9nbC5jcmVhdGVSZW5kZXJidWZmZXIoKTtcblx0XHRcdFx0XHRzZXR1cFJlbmRlckJ1ZmZlclN0b3JhZ2UoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbERlcHRoUmVuZGVyYnVmZmVyLCByZW5kZXJUYXJnZXQsIHRydWUgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIG51bGwgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gU2V0dXAgY29sb3IgYnVmZmVyXG5cblx0XHRpZiAoIGlzQ3ViZSApIHtcblxuXHRcdFx0c3RhdGUuYmluZFRleHR1cmUoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xuXHRcdFx0c2V0VGV4dHVyZVBhcmFtZXRlcnMoIF9nbC5URVhUVVJFX0NVQkVfTUFQLCB0ZXh0dXJlICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDY7IGkgKysgKSB7XG5cblx0XHRcdFx0aWYgKCB0ZXh0dXJlLm1pcG1hcHMgJiYgdGV4dHVyZS5taXBtYXBzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgbGV2ZWwgPSAwOyBsZXZlbCA8IHRleHR1cmUubWlwbWFwcy5sZW5ndGg7IGxldmVsICsrICkge1xuXG5cdFx0XHRcdFx0XHRzZXR1cEZyYW1lQnVmZmVyVGV4dHVyZSggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXVsgbGV2ZWwgXSwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCBsZXZlbCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRzZXR1cEZyYW1lQnVmZmVyVGV4dHVyZSggcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXJbIGkgXSwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBpLCAwICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCB0ZXh0dXJlICkgKSB7XG5cblx0XHRcdFx0Z2VuZXJhdGVNaXBtYXAoIF9nbC5URVhUVVJFX0NVQkVfTUFQICk7XG5cblx0XHRcdH1cblxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xuXG5cdFx0fSBlbHNlIGlmICggaXNNdWx0aXBsZVJlbmRlclRhcmdldHMgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0ZXh0dXJlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBhdHRhY2htZW50ID0gdGV4dHVyZXNbIGkgXTtcblx0XHRcdFx0Y29uc3QgYXR0YWNobWVudFByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggYXR0YWNobWVudCApO1xuXG5cdFx0XHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBfZ2wuVEVYVFVSRV8yRCwgYXR0YWNobWVudFByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUgKTtcblx0XHRcdFx0c2V0VGV4dHVyZVBhcmFtZXRlcnMoIF9nbC5URVhUVVJFXzJELCBhdHRhY2htZW50ICk7XG5cdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCBhdHRhY2htZW50LCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAgKyBpLCBfZ2wuVEVYVFVSRV8yRCwgMCApO1xuXG5cdFx0XHRcdGlmICggdGV4dHVyZU5lZWRzR2VuZXJhdGVNaXBtYXBzKCBhdHRhY2htZW50ICkgKSB7XG5cblx0XHRcdFx0XHRnZW5lcmF0ZU1pcG1hcCggX2dsLlRFWFRVUkVfMkQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0bGV0IGdsVGV4dHVyZVR5cGUgPSBfZ2wuVEVYVFVSRV8yRDtcblxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTDNEUmVuZGVyVGFyZ2V0IHx8IHJlbmRlclRhcmdldC5pc1dlYkdMQXJyYXlSZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRcdFx0Z2xUZXh0dXJlVHlwZSA9IHJlbmRlclRhcmdldC5pc1dlYkdMM0RSZW5kZXJUYXJnZXQgPyBfZ2wuVEVYVFVSRV8zRCA6IF9nbC5URVhUVVJFXzJEX0FSUkFZO1xuXG5cdFx0XHR9XG5cblx0XHRcdHN0YXRlLmJpbmRUZXh0dXJlKCBnbFRleHR1cmVUeXBlLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSApO1xuXHRcdFx0c2V0VGV4dHVyZVBhcmFtZXRlcnMoIGdsVGV4dHVyZVR5cGUsIHRleHR1cmUgKTtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlLm1pcG1hcHMgJiYgdGV4dHVyZS5taXBtYXBzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGxldmVsID0gMDsgbGV2ZWwgPCB0ZXh0dXJlLm1pcG1hcHMubGVuZ3RoOyBsZXZlbCArKyApIHtcblxuXHRcdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlclsgbGV2ZWwgXSwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIGdsVGV4dHVyZVR5cGUsIGxldmVsICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHNldHVwRnJhbWVCdWZmZXJUZXh0dXJlKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciwgcmVuZGVyVGFyZ2V0LCB0ZXh0dXJlLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIGdsVGV4dHVyZVR5cGUsIDAgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRleHR1cmVOZWVkc0dlbmVyYXRlTWlwbWFwcyggdGV4dHVyZSApICkge1xuXG5cdFx0XHRcdGdlbmVyYXRlTWlwbWFwKCBnbFRleHR1cmVUeXBlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xuXG5cdFx0fVxuXG5cdFx0Ly8gU2V0dXAgZGVwdGggYW5kIHN0ZW5jaWwgYnVmZmVyc1xuXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgKSB7XG5cblx0XHRcdHNldHVwRGVwdGhSZW5kZXJidWZmZXIoIHJlbmRlclRhcmdldCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiB1cGRhdGVSZW5kZXJUYXJnZXRNaXBtYXAoIHJlbmRlclRhcmdldCApIHtcblxuXHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmVzO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRleHR1cmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCB0ZXh0dXJlID0gdGV4dHVyZXNbIGkgXTtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlTmVlZHNHZW5lcmF0ZU1pcG1hcHMoIHRleHR1cmUgKSApIHtcblxuXHRcdFx0XHRjb25zdCB0YXJnZXQgPSByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgPyBfZ2wuVEVYVFVSRV9DVUJFX01BUCA6IF9nbC5URVhUVVJFXzJEO1xuXHRcdFx0XHRjb25zdCB3ZWJnbFRleHR1cmUgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlO1xuXG5cdFx0XHRcdHN0YXRlLmJpbmRUZXh0dXJlKCB0YXJnZXQsIHdlYmdsVGV4dHVyZSApO1xuXHRcdFx0XHRnZW5lcmF0ZU1pcG1hcCggdGFyZ2V0ICk7XG5cdFx0XHRcdHN0YXRlLnVuYmluZFRleHR1cmUoKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRjb25zdCBpbnZhbGlkYXRpb25BcnJheVJlYWQgPSBbXTtcblx0Y29uc3QgaW52YWxpZGF0aW9uQXJyYXlEcmF3ID0gW107XG5cblx0ZnVuY3Rpb24gdXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCApIHtcblxuXHRcdGlmICggcmVuZGVyVGFyZ2V0LnNhbXBsZXMgPiAwICkge1xuXG5cdFx0XHRpZiAoIHVzZU11bHRpc2FtcGxlZFJUVCggcmVuZGVyVGFyZ2V0ICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdGNvbnN0IHRleHR1cmVzID0gcmVuZGVyVGFyZ2V0LnRleHR1cmVzO1xuXHRcdFx0XHRjb25zdCB3aWR0aCA9IHJlbmRlclRhcmdldC53aWR0aDtcblx0XHRcdFx0Y29uc3QgaGVpZ2h0ID0gcmVuZGVyVGFyZ2V0LmhlaWdodDtcblx0XHRcdFx0bGV0IG1hc2sgPSBfZ2wuQ09MT1JfQlVGRkVSX0JJVDtcblx0XHRcdFx0Y29uc3QgZGVwdGhTdHlsZSA9IHJlbmRlclRhcmdldC5zdGVuY2lsQnVmZmVyID8gX2dsLkRFUFRIX1NURU5DSUxfQVRUQUNITUVOVCA6IF9nbC5ERVBUSF9BVFRBQ0hNRU5UO1xuXHRcdFx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xuXHRcdFx0XHRjb25zdCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyA9ICggdGV4dHVyZXMubGVuZ3RoID4gMSApO1xuXG5cdFx0XHRcdC8vIElmIE1SVCB3ZSBuZWVkIHRvIHJlbW92ZSBGQk8gYXR0YWNobWVudHNcblx0XHRcdFx0aWYgKCBpc011bHRpcGxlUmVuZGVyVGFyZ2V0cyApIHtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRleHR1cmVzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XG5cdFx0XHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJSZW5kZXJidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwICsgaSwgX2dsLlJFTkRFUkJVRkZFUiwgbnVsbCApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsRnJhbWVidWZmZXIgKTtcblx0XHRcdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5URVhUVVJFXzJELCBudWxsLCAwICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLlJFQURfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGV4dHVyZXMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXQucmVzb2x2ZURlcHRoQnVmZmVyICkge1xuXG5cdFx0XHRcdFx0XHRpZiAoIHJlbmRlclRhcmdldC5kZXB0aEJ1ZmZlciApIG1hc2sgfD0gX2dsLkRFUFRIX0JVRkZFUl9CSVQ7XG5cblx0XHRcdFx0XHRcdC8vIHJlc29sdmluZyBzdGVuY2lsIGlzIHNsb3cgd2l0aCBhIEQzRCBiYWNrZW5kLiBkaXNhYmxlIGl0IGZvciBhbGwgdHJhbnNtaXNzaW9uIHJlbmRlciB0YXJnZXRzIChzZWUgIzI3Nzk5KVxuXG5cdFx0XHRcdFx0XHRpZiAoIHJlbmRlclRhcmdldC5zdGVuY2lsQnVmZmVyICYmIHJlbmRlclRhcmdldC5yZXNvbHZlU3RlbmNpbEJ1ZmZlciApIG1hc2sgfD0gX2dsLlNURU5DSUxfQlVGRkVSX0JJVDtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggaXNNdWx0aXBsZVJlbmRlclRhcmdldHMgKSB7XG5cblx0XHRcdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclJlbmRlcmJ1ZmZlciggX2dsLlJFQURfRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCwgX2dsLlJFTkRFUkJVRkZFUiwgcmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3dlYmdsQ29sb3JSZW5kZXJidWZmZXJbIGkgXSApO1xuXG5cdFx0XHRcdFx0XHRjb25zdCB3ZWJnbFRleHR1cmUgPSBwcm9wZXJ0aWVzLmdldCggdGV4dHVyZXNbIGkgXSApLl9fd2ViZ2xUZXh0dXJlO1xuXHRcdFx0XHRcdFx0X2dsLmZyYW1lYnVmZmVyVGV4dHVyZTJEKCBfZ2wuRFJBV19GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwLCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xUZXh0dXJlLCAwICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRfZ2wuYmxpdEZyYW1lYnVmZmVyKCAwLCAwLCB3aWR0aCwgaGVpZ2h0LCAwLCAwLCB3aWR0aCwgaGVpZ2h0LCBtYXNrLCBfZ2wuTkVBUkVTVCApO1xuXG5cdFx0XHRcdFx0aWYgKCBzdXBwb3J0c0ludmFsaWRhdGVGcmFtZWJ1ZmZlciA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdFx0aW52YWxpZGF0aW9uQXJyYXlSZWFkLmxlbmd0aCA9IDA7XG5cdFx0XHRcdFx0XHRpbnZhbGlkYXRpb25BcnJheURyYXcubGVuZ3RoID0gMDtcblxuXHRcdFx0XHRcdFx0aW52YWxpZGF0aW9uQXJyYXlSZWFkLnB1c2goIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGkgKTtcblxuXHRcdFx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgJiYgcmVuZGVyVGFyZ2V0LnJlc29sdmVEZXB0aEJ1ZmZlciA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0XHRcdFx0aW52YWxpZGF0aW9uQXJyYXlSZWFkLnB1c2goIGRlcHRoU3R5bGUgKTtcblx0XHRcdFx0XHRcdFx0aW52YWxpZGF0aW9uQXJyYXlEcmF3LnB1c2goIGRlcHRoU3R5bGUgKTtcblxuXHRcdFx0XHRcdFx0XHRfZ2wuaW52YWxpZGF0ZUZyYW1lYnVmZmVyKCBfZ2wuRFJBV19GUkFNRUJVRkZFUiwgaW52YWxpZGF0aW9uQXJyYXlEcmF3ICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0X2dsLmludmFsaWRhdGVGcmFtZWJ1ZmZlciggX2dsLlJFQURfRlJBTUVCVUZGRVIsIGludmFsaWRhdGlvbkFycmF5UmVhZCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5SRUFEX0ZSQU1FQlVGRkVSLCBudWxsICk7XG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIG51bGwgKTtcblxuXHRcdFx0XHQvLyBJZiBNUlQgc2luY2UgcHJlLWJsaXQgd2UgcmVtb3ZlZCB0aGUgRkJPIHdlIG5lZWQgdG8gcmVjb25zdHJ1Y3QgdGhlIGF0dGFjaG1lbnRzXG5cdFx0XHRcdGlmICggaXNNdWx0aXBsZVJlbmRlclRhcmdldHMgKSB7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0ZXh0dXJlcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlciApO1xuXHRcdFx0XHRcdFx0X2dsLmZyYW1lYnVmZmVyUmVuZGVyYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIF9nbC5DT0xPUl9BVFRBQ0hNRU5UMCArIGksIF9nbC5SRU5ERVJCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbENvbG9yUmVuZGVyYnVmZmVyWyBpIF0gKTtcblxuXHRcdFx0XHRcdFx0Y29uc3Qgd2ViZ2xUZXh0dXJlID0gcHJvcGVydGllcy5nZXQoIHRleHR1cmVzWyBpIF0gKS5fX3dlYmdsVGV4dHVyZTtcblxuXHRcdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyICk7XG5cdFx0XHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlMkQoIF9nbC5EUkFXX0ZSQU1FQlVGRkVSLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAgKyBpLCBfZ2wuVEVYVFVSRV8yRCwgd2ViZ2xUZXh0dXJlLCAwICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkRSQVdfRlJBTUVCVUZGRVIsIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbE11bHRpc2FtcGxlZEZyYW1lYnVmZmVyICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuZGVwdGhCdWZmZXIgJiYgcmVuZGVyVGFyZ2V0LnJlc29sdmVEZXB0aEJ1ZmZlciA9PT0gZmFsc2UgJiYgc3VwcG9ydHNJbnZhbGlkYXRlRnJhbWVidWZmZXIgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBkZXB0aFN0eWxlID0gcmVuZGVyVGFyZ2V0LnN0ZW5jaWxCdWZmZXIgPyBfZ2wuREVQVEhfU1RFTkNJTF9BVFRBQ0hNRU5UIDogX2dsLkRFUFRIX0FUVEFDSE1FTlQ7XG5cblx0XHRcdFx0XHRfZ2wuaW52YWxpZGF0ZUZyYW1lYnVmZmVyKCBfZ2wuRFJBV19GUkFNRUJVRkZFUiwgWyBkZXB0aFN0eWxlIF0gKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0UmVuZGVyVGFyZ2V0U2FtcGxlcyggcmVuZGVyVGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIE1hdGgubWluKCBjYXBhYmlsaXRpZXMubWF4U2FtcGxlcywgcmVuZGVyVGFyZ2V0LnNhbXBsZXMgKTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gdXNlTXVsdGlzYW1wbGVkUlRUKCByZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xuXG5cdFx0cmV0dXJuIHJlbmRlclRhcmdldC5zYW1wbGVzID4gMCAmJiBleHRlbnNpb25zLmhhcyggJ1dFQkdMX211bHRpc2FtcGxlZF9yZW5kZXJfdG9fdGV4dHVyZScgKSA9PT0gdHJ1ZSAmJiByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fdXNlUmVuZGVyVG9UZXh0dXJlICE9PSBmYWxzZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gdXBkYXRlVmlkZW9UZXh0dXJlKCB0ZXh0dXJlICkge1xuXG5cdFx0Y29uc3QgZnJhbWUgPSBpbmZvLnJlbmRlci5mcmFtZTtcblxuXHRcdC8vIENoZWNrIHRoZSBsYXN0IGZyYW1lIHdlIHVwZGF0ZWQgdGhlIFZpZGVvVGV4dHVyZVxuXG5cdFx0aWYgKCBfdmlkZW9UZXh0dXJlcy5nZXQoIHRleHR1cmUgKSAhPT0gZnJhbWUgKSB7XG5cblx0XHRcdF92aWRlb1RleHR1cmVzLnNldCggdGV4dHVyZSwgZnJhbWUgKTtcblx0XHRcdHRleHR1cmUudXBkYXRlKCk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHZlcmlmeUNvbG9yU3BhY2UoIHRleHR1cmUsIGltYWdlICkge1xuXG5cdFx0Y29uc3QgY29sb3JTcGFjZSA9IHRleHR1cmUuY29sb3JTcGFjZTtcblx0XHRjb25zdCBmb3JtYXQgPSB0ZXh0dXJlLmZvcm1hdDtcblx0XHRjb25zdCB0eXBlID0gdGV4dHVyZS50eXBlO1xuXG5cdFx0aWYgKCB0ZXh0dXJlLmlzQ29tcHJlc3NlZFRleHR1cmUgPT09IHRydWUgfHwgdGV4dHVyZS5pc1ZpZGVvVGV4dHVyZSA9PT0gdHJ1ZSApIHJldHVybiBpbWFnZTtcblxuXHRcdGlmICggY29sb3JTcGFjZSAhPT0gTGluZWFyU1JHQkNvbG9yU3BhY2UgJiYgY29sb3JTcGFjZSAhPT0gTm9Db2xvclNwYWNlICkge1xuXG5cdFx0XHQvLyBzUkdCXG5cblx0XHRcdGlmICggQ29sb3JNYW5hZ2VtZW50LmdldFRyYW5zZmVyKCBjb2xvclNwYWNlICkgPT09IFNSR0JUcmFuc2ZlciApIHtcblxuXHRcdFx0XHQvLyBpbiBXZWJHTCAyIHVuY29tcHJlc3NlZCB0ZXh0dXJlcyBjYW4gb25seSBiZSBzUkdCIGVuY29kZWQgaWYgdGhleSBoYXZlIHRoZSBSR0JBOCBmb3JtYXRcblxuXHRcdFx0XHRpZiAoIGZvcm1hdCAhPT0gUkdCQUZvcm1hdCB8fCB0eXBlICE9PSBVbnNpZ25lZEJ5dGVUeXBlICkge1xuXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xUZXh0dXJlczogc1JHQiBlbmNvZGVkIHRleHR1cmVzIGhhdmUgdG8gdXNlIFJHQkFGb3JtYXQgYW5kIFVuc2lnbmVkQnl0ZVR5cGUuJyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xUZXh0dXJlczogVW5zdXBwb3J0ZWQgdGV4dHVyZSBjb2xvciBzcGFjZTonLCBjb2xvclNwYWNlICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiBpbWFnZTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZ2V0RGltZW5zaW9ucyggaW1hZ2UgKSB7XG5cblx0XHRpZiAoIHR5cGVvZiBIVE1MSW1hZ2VFbGVtZW50ICE9PSAndW5kZWZpbmVkJyAmJiBpbWFnZSBpbnN0YW5jZW9mIEhUTUxJbWFnZUVsZW1lbnQgKSB7XG5cblx0XHRcdC8vIGlmIGludHJpbnNpYyBkYXRhIGFyZSBub3QgYXZhaWxhYmxlLCBmYWxsYmFjayB0byB3aWR0aC9oZWlnaHRcblxuXHRcdFx0X2ltYWdlRGltZW5zaW9ucy53aWR0aCA9IGltYWdlLm5hdHVyYWxXaWR0aCB8fCBpbWFnZS53aWR0aDtcblx0XHRcdF9pbWFnZURpbWVuc2lvbnMuaGVpZ2h0ID0gaW1hZ2UubmF0dXJhbEhlaWdodCB8fCBpbWFnZS5oZWlnaHQ7XG5cblx0XHR9IGVsc2UgaWYgKCB0eXBlb2YgVmlkZW9GcmFtZSAhPT0gJ3VuZGVmaW5lZCcgJiYgaW1hZ2UgaW5zdGFuY2VvZiBWaWRlb0ZyYW1lICkge1xuXG5cdFx0XHRfaW1hZ2VEaW1lbnNpb25zLndpZHRoID0gaW1hZ2UuZGlzcGxheVdpZHRoO1xuXHRcdFx0X2ltYWdlRGltZW5zaW9ucy5oZWlnaHQgPSBpbWFnZS5kaXNwbGF5SGVpZ2h0O1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0X2ltYWdlRGltZW5zaW9ucy53aWR0aCA9IGltYWdlLndpZHRoO1xuXHRcdFx0X2ltYWdlRGltZW5zaW9ucy5oZWlnaHQgPSBpbWFnZS5oZWlnaHQ7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gX2ltYWdlRGltZW5zaW9ucztcblxuXHR9XG5cblx0Ly9cblxuXHR0aGlzLmFsbG9jYXRlVGV4dHVyZVVuaXQgPSBhbGxvY2F0ZVRleHR1cmVVbml0O1xuXHR0aGlzLnJlc2V0VGV4dHVyZVVuaXRzID0gcmVzZXRUZXh0dXJlVW5pdHM7XG5cblx0dGhpcy5zZXRUZXh0dXJlMkQgPSBzZXRUZXh0dXJlMkQ7XG5cdHRoaXMuc2V0VGV4dHVyZTJEQXJyYXkgPSBzZXRUZXh0dXJlMkRBcnJheTtcblx0dGhpcy5zZXRUZXh0dXJlM0QgPSBzZXRUZXh0dXJlM0Q7XG5cdHRoaXMuc2V0VGV4dHVyZUN1YmUgPSBzZXRUZXh0dXJlQ3ViZTtcblx0dGhpcy5yZWJpbmRUZXh0dXJlcyA9IHJlYmluZFRleHR1cmVzO1xuXHR0aGlzLnNldHVwUmVuZGVyVGFyZ2V0ID0gc2V0dXBSZW5kZXJUYXJnZXQ7XG5cdHRoaXMudXBkYXRlUmVuZGVyVGFyZ2V0TWlwbWFwID0gdXBkYXRlUmVuZGVyVGFyZ2V0TWlwbWFwO1xuXHR0aGlzLnVwZGF0ZU11bHRpc2FtcGxlUmVuZGVyVGFyZ2V0ID0gdXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQ7XG5cdHRoaXMuc2V0dXBEZXB0aFJlbmRlcmJ1ZmZlciA9IHNldHVwRGVwdGhSZW5kZXJidWZmZXI7XG5cdHRoaXMuc2V0dXBGcmFtZUJ1ZmZlclRleHR1cmUgPSBzZXR1cEZyYW1lQnVmZmVyVGV4dHVyZTtcblx0dGhpcy51c2VNdWx0aXNhbXBsZWRSVFQgPSB1c2VNdWx0aXNhbXBsZWRSVFQ7XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xVdGlscyggZ2wsIGV4dGVuc2lvbnMgKSB7XG5cblx0ZnVuY3Rpb24gY29udmVydCggcCwgY29sb3JTcGFjZSA9IE5vQ29sb3JTcGFjZSApIHtcblxuXHRcdGxldCBleHRlbnNpb247XG5cblx0XHRjb25zdCB0cmFuc2ZlciA9IENvbG9yTWFuYWdlbWVudC5nZXRUcmFuc2ZlciggY29sb3JTcGFjZSApO1xuXG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZEJ5dGVUeXBlICkgcmV0dXJuIGdsLlVOU0lHTkVEX0JZVEU7XG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZFNob3J0NDQ0NFR5cGUgKSByZXR1cm4gZ2wuVU5TSUdORURfU0hPUlRfNF80XzRfNDtcblx0XHRpZiAoIHAgPT09IFVuc2lnbmVkU2hvcnQ1NTUxVHlwZSApIHJldHVybiBnbC5VTlNJR05FRF9TSE9SVF81XzVfNV8xO1xuXHRcdGlmICggcCA9PT0gVW5zaWduZWRJbnQ1OTk5VHlwZSApIHJldHVybiBnbC5VTlNJR05FRF9JTlRfNV85XzlfOV9SRVY7XG5cblx0XHRpZiAoIHAgPT09IEJ5dGVUeXBlICkgcmV0dXJuIGdsLkJZVEU7XG5cdFx0aWYgKCBwID09PSBTaG9ydFR5cGUgKSByZXR1cm4gZ2wuU0hPUlQ7XG5cdFx0aWYgKCBwID09PSBVbnNpZ25lZFNob3J0VHlwZSApIHJldHVybiBnbC5VTlNJR05FRF9TSE9SVDtcblx0XHRpZiAoIHAgPT09IEludFR5cGUgKSByZXR1cm4gZ2wuSU5UO1xuXHRcdGlmICggcCA9PT0gVW5zaWduZWRJbnRUeXBlICkgcmV0dXJuIGdsLlVOU0lHTkVEX0lOVDtcblx0XHRpZiAoIHAgPT09IEZsb2F0VHlwZSApIHJldHVybiBnbC5GTE9BVDtcblx0XHRpZiAoIHAgPT09IEhhbGZGbG9hdFR5cGUgKSByZXR1cm4gZ2wuSEFMRl9GTE9BVDtcblxuXHRcdGlmICggcCA9PT0gQWxwaGFGb3JtYXQgKSByZXR1cm4gZ2wuQUxQSEE7XG5cdFx0aWYgKCBwID09PSBSR0JGb3JtYXQgKSByZXR1cm4gZ2wuUkdCO1xuXHRcdGlmICggcCA9PT0gUkdCQUZvcm1hdCApIHJldHVybiBnbC5SR0JBO1xuXHRcdGlmICggcCA9PT0gTHVtaW5hbmNlRm9ybWF0ICkgcmV0dXJuIGdsLkxVTUlOQU5DRTtcblx0XHRpZiAoIHAgPT09IEx1bWluYW5jZUFscGhhRm9ybWF0ICkgcmV0dXJuIGdsLkxVTUlOQU5DRV9BTFBIQTtcblx0XHRpZiAoIHAgPT09IERlcHRoRm9ybWF0ICkgcmV0dXJuIGdsLkRFUFRIX0NPTVBPTkVOVDtcblx0XHRpZiAoIHAgPT09IERlcHRoU3RlbmNpbEZvcm1hdCApIHJldHVybiBnbC5ERVBUSF9TVEVOQ0lMO1xuXG5cdFx0Ly8gV2ViR0wyIGZvcm1hdHMuXG5cblx0XHRpZiAoIHAgPT09IFJlZEZvcm1hdCApIHJldHVybiBnbC5SRUQ7XG5cdFx0aWYgKCBwID09PSBSZWRJbnRlZ2VyRm9ybWF0ICkgcmV0dXJuIGdsLlJFRF9JTlRFR0VSO1xuXHRcdGlmICggcCA9PT0gUkdGb3JtYXQgKSByZXR1cm4gZ2wuUkc7XG5cdFx0aWYgKCBwID09PSBSR0ludGVnZXJGb3JtYXQgKSByZXR1cm4gZ2wuUkdfSU5URUdFUjtcblx0XHRpZiAoIHAgPT09IFJHQkFJbnRlZ2VyRm9ybWF0ICkgcmV0dXJuIGdsLlJHQkFfSU5URUdFUjtcblxuXHRcdC8vIFMzVENcblxuXHRcdGlmICggcCA9PT0gUkdCX1MzVENfRFhUMV9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9TM1RDX0RYVDFfRm9ybWF0IHx8IHAgPT09IFJHQkFfUzNUQ19EWFQzX0Zvcm1hdCB8fCBwID09PSBSR0JBX1MzVENfRFhUNV9Gb3JtYXQgKSB7XG5cblx0XHRcdGlmICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApIHtcblxuXHRcdFx0XHRleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ1dFQkdMX2NvbXByZXNzZWRfdGV4dHVyZV9zM3RjX3NyZ2InICk7XG5cblx0XHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHAgPT09IFJHQl9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfUzNUQ19EWFQxX0VYVDtcblx0XHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfUzNUQ19EWFQxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCX0FMUEhBX1MzVENfRFhUMV9FWFQ7XG5cdFx0XHRcdFx0aWYgKCBwID09PSBSR0JBX1MzVENfRFhUM19Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQl9BTFBIQV9TM1RDX0RYVDNfRVhUO1xuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDVfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfQUxQSEFfUzNUQ19EWFQ1X0VYVDtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3MzdGMnICk7XG5cblx0XHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHAgPT09IFJHQl9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQl9TM1RDX0RYVDFfRVhUO1xuXHRcdFx0XHRcdGlmICggcCA9PT0gUkdCQV9TM1RDX0RYVDFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfUzNUQ19EWFQxX0VYVDtcblx0XHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfUzNUQ19EWFQzX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX1MzVENfRFhUM19FWFQ7XG5cdFx0XHRcdFx0aWYgKCBwID09PSBSR0JBX1MzVENfRFhUNV9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9TM1RDX0RYVDVfRVhUO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIFBWUlRDXG5cblx0XHRpZiAoIHAgPT09IFJHQl9QVlJUQ180QlBQVjFfRm9ybWF0IHx8IHAgPT09IFJHQl9QVlJUQ18yQlBQVjFfRm9ybWF0IHx8IHAgPT09IFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCB8fCBwID09PSBSR0JBX1BWUlRDXzJCUFBWMV9Gb3JtYXQgKSB7XG5cblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX3B2cnRjJyApO1xuXG5cdFx0XHRpZiAoIGV4dGVuc2lvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9QVlJUQ180QlBQVjFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQl9QVlJUQ180QlBQVjFfSU1HO1xuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9QVlJUQ18yQlBQVjFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQl9QVlJUQ18yQlBQVjFfSU1HO1xuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX1BWUlRDXzRCUFBWMV9JTUc7XG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9QVlJUQ18yQlBQVjFfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfUFZSVENfMkJQUFYxX0lNRztcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gRVRDXG5cblx0XHRpZiAoIHAgPT09IFJHQl9FVEMxX0Zvcm1hdCB8fCBwID09PSBSR0JfRVRDMl9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9FVEMyX0VBQ19Gb3JtYXQgKSB7XG5cblx0XHRcdGV4dGVuc2lvbiA9IGV4dGVuc2lvbnMuZ2V0KCAnV0VCR0xfY29tcHJlc3NlZF90ZXh0dXJlX2V0YycgKTtcblxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0aWYgKCBwID09PSBSR0JfRVRDMV9Gb3JtYXQgfHwgcCA9PT0gUkdCX0VUQzJfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfRVRDMiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQjhfRVRDMjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0VUQzJfRUFDX0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9FVEMyX0VBQyA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkE4X0VUQzJfRUFDO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBBU1RDXG5cblx0XHRpZiAoIHAgPT09IFJHQkFfQVNUQ180eDRfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ181eDRfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ181eDVfRm9ybWF0IHx8XG5cdFx0XHRwID09PSBSR0JBX0FTVENfNng1X0Zvcm1hdCB8fCBwID09PSBSR0JBX0FTVENfNng2X0Zvcm1hdCB8fCBwID09PSBSR0JBX0FTVENfOHg1X0Zvcm1hdCB8fFxuXHRcdFx0cCA9PT0gUkdCQV9BU1RDXzh4Nl9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9BU1RDXzh4OF9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9BU1RDXzEweDVfRm9ybWF0IHx8XG5cdFx0XHRwID09PSBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9BU1RDXzEweDhfRm9ybWF0IHx8IHAgPT09IFJHQkFfQVNUQ18xMHgxMF9Gb3JtYXQgfHxcblx0XHRcdHAgPT09IFJHQkFfQVNUQ18xMngxMF9Gb3JtYXQgfHwgcCA9PT0gUkdCQV9BU1RDXzEyeDEyX0Zvcm1hdCApIHtcblxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdXRUJHTF9jb21wcmVzc2VkX3RleHR1cmVfYXN0YycgKTtcblxuXHRcdFx0aWYgKCBleHRlbnNpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNHg0X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzR4NF9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNHg0X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNXg0X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzV4NF9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNXg0X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNXg1X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzV4NV9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNXg1X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNng1X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzZ4NV9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNng1X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfNng2X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzZ4Nl9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfNng2X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfOHg1X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzh4NV9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfOHg1X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfOHg2X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzh4Nl9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfOHg2X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfOHg4X0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0I4X0FMUEhBOF9BU1RDXzh4OF9LSFIgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0FTVENfOHg4X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4NV9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ18xMHg1X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ18xMHg1X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4Nl9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ18xMHg2X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ18xMHg2X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4OF9Gb3JtYXQgKSByZXR1cm4gKCB0cmFuc2ZlciA9PT0gU1JHQlRyYW5zZmVyICkgPyBleHRlbnNpb24uQ09NUFJFU1NFRF9TUkdCOF9BTFBIQThfQVNUQ18xMHg4X0tIUiA6IGV4dGVuc2lvbi5DT01QUkVTU0VEX1JHQkFfQVNUQ18xMHg4X0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTB4MTBfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfMTB4MTBfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzEweDEwX0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTJ4MTBfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfMTJ4MTBfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzEyeDEwX0tIUjtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JBX0FTVENfMTJ4MTJfRm9ybWF0ICkgcmV0dXJuICggdHJhbnNmZXIgPT09IFNSR0JUcmFuc2ZlciApID8gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU1JHQjhfQUxQSEE4X0FTVENfMTJ4MTJfS0hSIDogZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCQV9BU1RDXzEyeDEyX0tIUjtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gQlBUQ1xuXG5cdFx0aWYgKCBwID09PSBSR0JBX0JQVENfRm9ybWF0IHx8IHAgPT09IFJHQl9CUFRDX1NJR05FRF9Gb3JtYXQgfHwgcCA9PT0gUkdCX0JQVENfVU5TSUdORURfRm9ybWF0ICkge1xuXG5cdFx0XHRleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ0VYVF90ZXh0dXJlX2NvbXByZXNzaW9uX2JwdGMnICk7XG5cblx0XHRcdGlmICggZXh0ZW5zaW9uICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGlmICggcCA9PT0gUkdCQV9CUFRDX0Zvcm1hdCApIHJldHVybiAoIHRyYW5zZmVyID09PSBTUkdCVHJhbnNmZXIgKSA/IGV4dGVuc2lvbi5DT01QUkVTU0VEX1NSR0JfQUxQSEFfQlBUQ19VTk9STV9FWFQgOiBleHRlbnNpb24uQ09NUFJFU1NFRF9SR0JBX0JQVENfVU5PUk1fRVhUO1xuXHRcdFx0XHRpZiAoIHAgPT09IFJHQl9CUFRDX1NJR05FRF9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCX0JQVENfU0lHTkVEX0ZMT0FUX0VYVDtcblx0XHRcdFx0aWYgKCBwID09PSBSR0JfQlBUQ19VTlNJR05FRF9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkdCX0JQVENfVU5TSUdORURfRkxPQVRfRVhUO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBSR1RDXG5cblx0XHRpZiAoIHAgPT09IFJFRF9SR1RDMV9Gb3JtYXQgfHwgcCA9PT0gU0lHTkVEX1JFRF9SR1RDMV9Gb3JtYXQgfHwgcCA9PT0gUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCB8fCBwID09PSBTSUdORURfUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCApIHtcblxuXHRcdFx0ZXh0ZW5zaW9uID0gZXh0ZW5zaW9ucy5nZXQoICdFWFRfdGV4dHVyZV9jb21wcmVzc2lvbl9yZ3RjJyApO1xuXG5cdFx0XHRpZiAoIGV4dGVuc2lvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRpZiAoIHAgPT09IFJHQkFfQlBUQ19Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfUkVEX1JHVEMxX0VYVDtcblx0XHRcdFx0aWYgKCBwID09PSBTSUdORURfUkVEX1JHVEMxX0Zvcm1hdCApIHJldHVybiBleHRlbnNpb24uQ09NUFJFU1NFRF9TSUdORURfUkVEX1JHVEMxX0VYVDtcblx0XHRcdFx0aWYgKCBwID09PSBSRURfR1JFRU5fUkdUQzJfRm9ybWF0ICkgcmV0dXJuIGV4dGVuc2lvbi5DT01QUkVTU0VEX1JFRF9HUkVFTl9SR1RDMl9FWFQ7XG5cdFx0XHRcdGlmICggcCA9PT0gU0lHTkVEX1JFRF9HUkVFTl9SR1RDMl9Gb3JtYXQgKSByZXR1cm4gZXh0ZW5zaW9uLkNPTVBSRVNTRURfU0lHTkVEX1JFRF9HUkVFTl9SR1RDMl9FWFQ7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vXG5cblx0XHRpZiAoIHAgPT09IFVuc2lnbmVkSW50MjQ4VHlwZSApIHJldHVybiBnbC5VTlNJR05FRF9JTlRfMjRfODtcblxuXHRcdC8vIGlmIFwicFwiIGNhbid0IGJlIHJlc29sdmVkLCBhc3N1bWUgdGhlIHVzZXIgZGVmaW5lcyBhIFdlYkdMIGNvbnN0YW50IGFzIGEgc3RyaW5nIChmYWxsYmFjay93b3JrYXJvdW5kIGZvciBwYWNrZWQgUkdCIGZvcm1hdHMpXG5cblx0XHRyZXR1cm4gKCBnbFsgcCBdICE9PSB1bmRlZmluZWQgKSA/IGdsWyBwIF0gOiBudWxsO1xuXG5cdH1cblxuXHRyZXR1cm4geyBjb252ZXJ0OiBjb252ZXJ0IH07XG5cbn1cblxuY2xhc3MgQXJyYXlDYW1lcmEgZXh0ZW5kcyBQZXJzcGVjdGl2ZUNhbWVyYSB7XG5cblx0Y29uc3RydWN0b3IoIGFycmF5ID0gW10gKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc0FycmF5Q2FtZXJhID0gdHJ1ZTtcblxuXHRcdHRoaXMuY2FtZXJhcyA9IGFycmF5O1xuXG5cdH1cblxufVxuXG5jbGFzcyBHcm91cCBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzR3JvdXAgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0dyb3VwJztcblxuXHR9XG5cbn1cblxuY29uc3QgX21vdmVFdmVudCA9IHsgdHlwZTogJ21vdmUnIH07XG5cbmNsYXNzIFdlYlhSQ29udHJvbGxlciB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHR0aGlzLl90YXJnZXRSYXkgPSBudWxsO1xuXHRcdHRoaXMuX2dyaXAgPSBudWxsO1xuXHRcdHRoaXMuX2hhbmQgPSBudWxsO1xuXG5cdH1cblxuXHRnZXRIYW5kU3BhY2UoKSB7XG5cblx0XHRpZiAoIHRoaXMuX2hhbmQgPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX2hhbmQgPSBuZXcgR3JvdXAoKTtcblx0XHRcdHRoaXMuX2hhbmQubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xuXHRcdFx0dGhpcy5faGFuZC52aXNpYmxlID0gZmFsc2U7XG5cblx0XHRcdHRoaXMuX2hhbmQuam9pbnRzID0ge307XG5cdFx0XHR0aGlzLl9oYW5kLmlucHV0U3RhdGUgPSB7IHBpbmNoaW5nOiBmYWxzZSB9O1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMuX2hhbmQ7XG5cblx0fVxuXG5cdGdldFRhcmdldFJheVNwYWNlKCkge1xuXG5cdFx0aWYgKCB0aGlzLl90YXJnZXRSYXkgPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX3RhcmdldFJheSA9IG5ldyBHcm91cCgpO1xuXHRcdFx0dGhpcy5fdGFyZ2V0UmF5Lm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblx0XHRcdHRoaXMuX3RhcmdldFJheS52aXNpYmxlID0gZmFsc2U7XG5cdFx0XHR0aGlzLl90YXJnZXRSYXkuaGFzTGluZWFyVmVsb2NpdHkgPSBmYWxzZTtcblx0XHRcdHRoaXMuX3RhcmdldFJheS5saW5lYXJWZWxvY2l0eSA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0XHR0aGlzLl90YXJnZXRSYXkuaGFzQW5ndWxhclZlbG9jaXR5ID0gZmFsc2U7XG5cdFx0XHR0aGlzLl90YXJnZXRSYXkuYW5ndWxhclZlbG9jaXR5ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLl90YXJnZXRSYXk7XG5cblx0fVxuXG5cdGdldEdyaXBTcGFjZSgpIHtcblxuXHRcdGlmICggdGhpcy5fZ3JpcCA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5fZ3JpcCA9IG5ldyBHcm91cCgpO1xuXHRcdFx0dGhpcy5fZ3JpcC5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XG5cdFx0XHR0aGlzLl9ncmlwLnZpc2libGUgPSBmYWxzZTtcblx0XHRcdHRoaXMuX2dyaXAuaGFzTGluZWFyVmVsb2NpdHkgPSBmYWxzZTtcblx0XHRcdHRoaXMuX2dyaXAubGluZWFyVmVsb2NpdHkgPSBuZXcgVmVjdG9yMygpO1xuXHRcdFx0dGhpcy5fZ3JpcC5oYXNBbmd1bGFyVmVsb2NpdHkgPSBmYWxzZTtcblx0XHRcdHRoaXMuX2dyaXAuYW5ndWxhclZlbG9jaXR5ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLl9ncmlwO1xuXG5cdH1cblxuXHRkaXNwYXRjaEV2ZW50KCBldmVudCApIHtcblxuXHRcdGlmICggdGhpcy5fdGFyZ2V0UmF5ICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl90YXJnZXRSYXkuZGlzcGF0Y2hFdmVudCggZXZlbnQgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5fZ3JpcCAhPT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5fZ3JpcC5kaXNwYXRjaEV2ZW50KCBldmVudCApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl9oYW5kICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl9oYW5kLmRpc3BhdGNoRXZlbnQoIGV2ZW50ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29ubmVjdCggaW5wdXRTb3VyY2UgKSB7XG5cblx0XHRpZiAoIGlucHV0U291cmNlICYmIGlucHV0U291cmNlLmhhbmQgKSB7XG5cblx0XHRcdGNvbnN0IGhhbmQgPSB0aGlzLl9oYW5kO1xuXG5cdFx0XHRpZiAoIGhhbmQgKSB7XG5cblx0XHRcdFx0Zm9yICggY29uc3QgaW5wdXRqb2ludCBvZiBpbnB1dFNvdXJjZS5oYW5kLnZhbHVlcygpICkge1xuXG5cdFx0XHRcdFx0Ly8gSW5pdGlhbGl6ZSBoYW5kIHdpdGggam9pbnRzIHdoZW4gY29ubmVjdGVkXG5cdFx0XHRcdFx0dGhpcy5fZ2V0SGFuZEpvaW50KCBoYW5kLCBpbnB1dGpvaW50ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHR0aGlzLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogJ2Nvbm5lY3RlZCcsIGRhdGE6IGlucHV0U291cmNlIH0gKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkaXNjb25uZWN0KCBpbnB1dFNvdXJjZSApIHtcblxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzY29ubmVjdGVkJywgZGF0YTogaW5wdXRTb3VyY2UgfSApO1xuXG5cdFx0aWYgKCB0aGlzLl90YXJnZXRSYXkgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX3RhcmdldFJheS52aXNpYmxlID0gZmFsc2U7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuX2dyaXAgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX2dyaXAudmlzaWJsZSA9IGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLl9oYW5kICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl9oYW5kLnZpc2libGUgPSBmYWxzZTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR1cGRhdGUoIGlucHV0U291cmNlLCBmcmFtZSwgcmVmZXJlbmNlU3BhY2UgKSB7XG5cblx0XHRsZXQgaW5wdXRQb3NlID0gbnVsbDtcblx0XHRsZXQgZ3JpcFBvc2UgPSBudWxsO1xuXHRcdGxldCBoYW5kUG9zZSA9IG51bGw7XG5cblx0XHRjb25zdCB0YXJnZXRSYXkgPSB0aGlzLl90YXJnZXRSYXk7XG5cdFx0Y29uc3QgZ3JpcCA9IHRoaXMuX2dyaXA7XG5cdFx0Y29uc3QgaGFuZCA9IHRoaXMuX2hhbmQ7XG5cblx0XHRpZiAoIGlucHV0U291cmNlICYmIGZyYW1lLnNlc3Npb24udmlzaWJpbGl0eVN0YXRlICE9PSAndmlzaWJsZS1ibHVycmVkJyApIHtcblxuXHRcdFx0aWYgKCBoYW5kICYmIGlucHV0U291cmNlLmhhbmQgKSB7XG5cblx0XHRcdFx0aGFuZFBvc2UgPSB0cnVlO1xuXG5cdFx0XHRcdGZvciAoIGNvbnN0IGlucHV0am9pbnQgb2YgaW5wdXRTb3VyY2UuaGFuZC52YWx1ZXMoKSApIHtcblxuXHRcdFx0XHRcdC8vIFVwZGF0ZSB0aGUgam9pbnRzIGdyb3VwcyB3aXRoIHRoZSBYUkpvaW50IHBvc2VzXG5cdFx0XHRcdFx0Y29uc3Qgam9pbnRQb3NlID0gZnJhbWUuZ2V0Sm9pbnRQb3NlKCBpbnB1dGpvaW50LCByZWZlcmVuY2VTcGFjZSApO1xuXG5cdFx0XHRcdFx0Ly8gVGhlIHRyYW5zZm9ybSBvZiB0aGlzIGpvaW50IHdpbGwgYmUgdXBkYXRlZCB3aXRoIHRoZSBqb2ludCBwb3NlIG9uIGVhY2ggZnJhbWVcblx0XHRcdFx0XHRjb25zdCBqb2ludCA9IHRoaXMuX2dldEhhbmRKb2ludCggaGFuZCwgaW5wdXRqb2ludCApO1xuXG5cdFx0XHRcdFx0aWYgKCBqb2ludFBvc2UgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRcdGpvaW50Lm1hdHJpeC5mcm9tQXJyYXkoIGpvaW50UG9zZS50cmFuc2Zvcm0ubWF0cml4ICk7XG5cdFx0XHRcdFx0XHRqb2ludC5tYXRyaXguZGVjb21wb3NlKCBqb2ludC5wb3NpdGlvbiwgam9pbnQucm90YXRpb24sIGpvaW50LnNjYWxlICk7XG5cdFx0XHRcdFx0XHRqb2ludC5tYXRyaXhXb3JsZE5lZWRzVXBkYXRlID0gdHJ1ZTtcblx0XHRcdFx0XHRcdGpvaW50LmpvaW50UmFkaXVzID0gam9pbnRQb3NlLnJhZGl1cztcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGpvaW50LnZpc2libGUgPSBqb2ludFBvc2UgIT09IG51bGw7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIEN1c3RvbSBldmVudHNcblxuXHRcdFx0XHQvLyBDaGVjayBwaW5jaHpcblx0XHRcdFx0Y29uc3QgaW5kZXhUaXAgPSBoYW5kLmpvaW50c1sgJ2luZGV4LWZpbmdlci10aXAnIF07XG5cdFx0XHRcdGNvbnN0IHRodW1iVGlwID0gaGFuZC5qb2ludHNbICd0aHVtYi10aXAnIF07XG5cdFx0XHRcdGNvbnN0IGRpc3RhbmNlID0gaW5kZXhUaXAucG9zaXRpb24uZGlzdGFuY2VUbyggdGh1bWJUaXAucG9zaXRpb24gKTtcblxuXHRcdFx0XHRjb25zdCBkaXN0YW5jZVRvUGluY2ggPSAwLjAyO1xuXHRcdFx0XHRjb25zdCB0aHJlc2hvbGQgPSAwLjAwNTtcblxuXHRcdFx0XHRpZiAoIGhhbmQuaW5wdXRTdGF0ZS5waW5jaGluZyAmJiBkaXN0YW5jZSA+IGRpc3RhbmNlVG9QaW5jaCArIHRocmVzaG9sZCApIHtcblxuXHRcdFx0XHRcdGhhbmQuaW5wdXRTdGF0ZS5waW5jaGluZyA9IGZhbHNlO1xuXHRcdFx0XHRcdHRoaXMuZGlzcGF0Y2hFdmVudCgge1xuXHRcdFx0XHRcdFx0dHlwZTogJ3BpbmNoZW5kJyxcblx0XHRcdFx0XHRcdGhhbmRlZG5lc3M6IGlucHV0U291cmNlLmhhbmRlZG5lc3MsXG5cdFx0XHRcdFx0XHR0YXJnZXQ6IHRoaXNcblx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggISBoYW5kLmlucHV0U3RhdGUucGluY2hpbmcgJiYgZGlzdGFuY2UgPD0gZGlzdGFuY2VUb1BpbmNoIC0gdGhyZXNob2xkICkge1xuXG5cdFx0XHRcdFx0aGFuZC5pbnB1dFN0YXRlLnBpbmNoaW5nID0gdHJ1ZTtcblx0XHRcdFx0XHR0aGlzLmRpc3BhdGNoRXZlbnQoIHtcblx0XHRcdFx0XHRcdHR5cGU6ICdwaW5jaHN0YXJ0Jyxcblx0XHRcdFx0XHRcdGhhbmRlZG5lc3M6IGlucHV0U291cmNlLmhhbmRlZG5lc3MsXG5cdFx0XHRcdFx0XHR0YXJnZXQ6IHRoaXNcblx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGlmICggZ3JpcCAhPT0gbnVsbCAmJiBpbnB1dFNvdXJjZS5ncmlwU3BhY2UgKSB7XG5cblx0XHRcdFx0XHRncmlwUG9zZSA9IGZyYW1lLmdldFBvc2UoIGlucHV0U291cmNlLmdyaXBTcGFjZSwgcmVmZXJlbmNlU3BhY2UgKTtcblxuXHRcdFx0XHRcdGlmICggZ3JpcFBvc2UgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRcdGdyaXAubWF0cml4LmZyb21BcnJheSggZ3JpcFBvc2UudHJhbnNmb3JtLm1hdHJpeCApO1xuXHRcdFx0XHRcdFx0Z3JpcC5tYXRyaXguZGVjb21wb3NlKCBncmlwLnBvc2l0aW9uLCBncmlwLnJvdGF0aW9uLCBncmlwLnNjYWxlICk7XG5cdFx0XHRcdFx0XHRncmlwLm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0XHRcdFx0XHRpZiAoIGdyaXBQb3NlLmxpbmVhclZlbG9jaXR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdGdyaXAuaGFzTGluZWFyVmVsb2NpdHkgPSB0cnVlO1xuXHRcdFx0XHRcdFx0XHRncmlwLmxpbmVhclZlbG9jaXR5LmNvcHkoIGdyaXBQb3NlLmxpbmVhclZlbG9jaXR5ICk7XG5cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0Z3JpcC5oYXNMaW5lYXJWZWxvY2l0eSA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdGlmICggZ3JpcFBvc2UuYW5ndWxhclZlbG9jaXR5ICkge1xuXG5cdFx0XHRcdFx0XHRcdGdyaXAuaGFzQW5ndWxhclZlbG9jaXR5ID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0Z3JpcC5hbmd1bGFyVmVsb2NpdHkuY29weSggZ3JpcFBvc2UuYW5ndWxhclZlbG9jaXR5ICk7XG5cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0Z3JpcC5oYXNBbmd1bGFyVmVsb2NpdHkgPSBmYWxzZTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRhcmdldFJheSAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRpbnB1dFBvc2UgPSBmcmFtZS5nZXRQb3NlKCBpbnB1dFNvdXJjZS50YXJnZXRSYXlTcGFjZSwgcmVmZXJlbmNlU3BhY2UgKTtcblxuXHRcdFx0XHQvLyBTb21lIHJ1bnRpbWVzIChuYW1lbHkgVml2ZSBDb3Ntb3Mgd2l0aCBWaXZlIE9wZW5YUiBSdW50aW1lKSBoYXZlIG9ubHkgZ3JpcCBzcGFjZSBhbmQgcmF5IHNwYWNlIGlzIGVxdWFsIHRvIGl0XG5cdFx0XHRcdGlmICggaW5wdXRQb3NlID09PSBudWxsICYmIGdyaXBQb3NlICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0aW5wdXRQb3NlID0gZ3JpcFBvc2U7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggaW5wdXRQb3NlICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0dGFyZ2V0UmF5Lm1hdHJpeC5mcm9tQXJyYXkoIGlucHV0UG9zZS50cmFuc2Zvcm0ubWF0cml4ICk7XG5cdFx0XHRcdFx0dGFyZ2V0UmF5Lm1hdHJpeC5kZWNvbXBvc2UoIHRhcmdldFJheS5wb3NpdGlvbiwgdGFyZ2V0UmF5LnJvdGF0aW9uLCB0YXJnZXRSYXkuc2NhbGUgKTtcblx0XHRcdFx0XHR0YXJnZXRSYXkubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdFx0XHRpZiAoIGlucHV0UG9zZS5saW5lYXJWZWxvY2l0eSApIHtcblxuXHRcdFx0XHRcdFx0dGFyZ2V0UmF5Lmhhc0xpbmVhclZlbG9jaXR5ID0gdHJ1ZTtcblx0XHRcdFx0XHRcdHRhcmdldFJheS5saW5lYXJWZWxvY2l0eS5jb3B5KCBpbnB1dFBvc2UubGluZWFyVmVsb2NpdHkgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHRhcmdldFJheS5oYXNMaW5lYXJWZWxvY2l0eSA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCBpbnB1dFBvc2UuYW5ndWxhclZlbG9jaXR5ICkge1xuXG5cdFx0XHRcdFx0XHR0YXJnZXRSYXkuaGFzQW5ndWxhclZlbG9jaXR5ID0gdHJ1ZTtcblx0XHRcdFx0XHRcdHRhcmdldFJheS5hbmd1bGFyVmVsb2NpdHkuY29weSggaW5wdXRQb3NlLmFuZ3VsYXJWZWxvY2l0eSApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0dGFyZ2V0UmF5Lmhhc0FuZ3VsYXJWZWxvY2l0eSA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCBfbW92ZUV2ZW50ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblxuXHRcdH1cblxuXHRcdGlmICggdGFyZ2V0UmF5ICE9PSBudWxsICkge1xuXG5cdFx0XHR0YXJnZXRSYXkudmlzaWJsZSA9ICggaW5wdXRQb3NlICE9PSBudWxsICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIGdyaXAgIT09IG51bGwgKSB7XG5cblx0XHRcdGdyaXAudmlzaWJsZSA9ICggZ3JpcFBvc2UgIT09IG51bGwgKTtcblxuXHRcdH1cblxuXHRcdGlmICggaGFuZCAhPT0gbnVsbCApIHtcblxuXHRcdFx0aGFuZC52aXNpYmxlID0gKCBoYW5kUG9zZSAhPT0gbnVsbCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIHByaXZhdGUgbWV0aG9kXG5cblx0X2dldEhhbmRKb2ludCggaGFuZCwgaW5wdXRqb2ludCApIHtcblxuXHRcdGlmICggaGFuZC5qb2ludHNbIGlucHV0am9pbnQuam9pbnROYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3Qgam9pbnQgPSBuZXcgR3JvdXAoKTtcblx0XHRcdGpvaW50Lm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblx0XHRcdGpvaW50LnZpc2libGUgPSBmYWxzZTtcblx0XHRcdGhhbmQuam9pbnRzWyBpbnB1dGpvaW50LmpvaW50TmFtZSBdID0gam9pbnQ7XG5cblx0XHRcdGhhbmQuYWRkKCBqb2ludCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGhhbmQuam9pbnRzWyBpbnB1dGpvaW50LmpvaW50TmFtZSBdO1xuXG5cdH1cblxufVxuXG5jb25zdCBfb2NjbHVzaW9uX3ZlcnRleCA9IGBcbnZvaWQgbWFpbigpIHtcblxuXHRnbF9Qb3NpdGlvbiA9IHZlYzQoIHBvc2l0aW9uLCAxLjAgKTtcblxufWA7XG5cbmNvbnN0IF9vY2NsdXNpb25fZnJhZ21lbnQgPSBgXG51bmlmb3JtIHNhbXBsZXIyREFycmF5IGRlcHRoQ29sb3I7XG51bmlmb3JtIGZsb2F0IGRlcHRoV2lkdGg7XG51bmlmb3JtIGZsb2F0IGRlcHRoSGVpZ2h0O1xuXG52b2lkIG1haW4oKSB7XG5cblx0dmVjMiBjb29yZCA9IHZlYzIoIGdsX0ZyYWdDb29yZC54IC8gZGVwdGhXaWR0aCwgZ2xfRnJhZ0Nvb3JkLnkgLyBkZXB0aEhlaWdodCApO1xuXG5cdGlmICggY29vcmQueCA+PSAxLjAgKSB7XG5cblx0XHRnbF9GcmFnRGVwdGggPSB0ZXh0dXJlKCBkZXB0aENvbG9yLCB2ZWMzKCBjb29yZC54IC0gMS4wLCBjb29yZC55LCAxICkgKS5yO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRnbF9GcmFnRGVwdGggPSB0ZXh0dXJlKCBkZXB0aENvbG9yLCB2ZWMzKCBjb29yZC54LCBjb29yZC55LCAwICkgKS5yO1xuXG5cdH1cblxufWA7XG5cbmNsYXNzIFdlYlhSRGVwdGhTZW5zaW5nIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHRoaXMudGV4dHVyZSA9IG51bGw7XG5cdFx0dGhpcy5tZXNoID0gbnVsbDtcblxuXHRcdHRoaXMuZGVwdGhOZWFyID0gMDtcblx0XHR0aGlzLmRlcHRoRmFyID0gMDtcblxuXHR9XG5cblx0aW5pdCggcmVuZGVyZXIsIGRlcHRoRGF0YSwgcmVuZGVyU3RhdGUgKSB7XG5cblx0XHRpZiAoIHRoaXMudGV4dHVyZSA9PT0gbnVsbCApIHtcblxuXHRcdFx0Y29uc3QgdGV4dHVyZSA9IG5ldyBUZXh0dXJlKCk7XG5cblx0XHRcdGNvbnN0IHRleFByb3BzID0gcmVuZGVyZXIucHJvcGVydGllcy5nZXQoIHRleHR1cmUgKTtcblx0XHRcdHRleFByb3BzLl9fd2ViZ2xUZXh0dXJlID0gZGVwdGhEYXRhLnRleHR1cmU7XG5cblx0XHRcdGlmICggKCBkZXB0aERhdGEuZGVwdGhOZWFyICE9IHJlbmRlclN0YXRlLmRlcHRoTmVhciApIHx8ICggZGVwdGhEYXRhLmRlcHRoRmFyICE9IHJlbmRlclN0YXRlLmRlcHRoRmFyICkgKSB7XG5cblx0XHRcdFx0dGhpcy5kZXB0aE5lYXIgPSBkZXB0aERhdGEuZGVwdGhOZWFyO1xuXHRcdFx0XHR0aGlzLmRlcHRoRmFyID0gZGVwdGhEYXRhLmRlcHRoRmFyO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMudGV4dHVyZSA9IHRleHR1cmU7XG5cblx0XHR9XG5cblx0fVxuXG5cdGdldE1lc2goIGNhbWVyYVhSICkge1xuXG5cdFx0aWYgKCB0aGlzLnRleHR1cmUgIT09IG51bGwgKSB7XG5cblx0XHRcdGlmICggdGhpcy5tZXNoID09PSBudWxsICkge1xuXG5cdFx0XHRcdGNvbnN0IHZpZXdwb3J0ID0gY2FtZXJhWFIuY2FtZXJhc1sgMCBdLnZpZXdwb3J0O1xuXHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xuXHRcdFx0XHRcdHZlcnRleFNoYWRlcjogX29jY2x1c2lvbl92ZXJ0ZXgsXG5cdFx0XHRcdFx0ZnJhZ21lbnRTaGFkZXI6IF9vY2NsdXNpb25fZnJhZ21lbnQsXG5cdFx0XHRcdFx0dW5pZm9ybXM6IHtcblx0XHRcdFx0XHRcdGRlcHRoQ29sb3I6IHsgdmFsdWU6IHRoaXMudGV4dHVyZSB9LFxuXHRcdFx0XHRcdFx0ZGVwdGhXaWR0aDogeyB2YWx1ZTogdmlld3BvcnQueiB9LFxuXHRcdFx0XHRcdFx0ZGVwdGhIZWlnaHQ6IHsgdmFsdWU6IHZpZXdwb3J0LncgfVxuXHRcdFx0XHRcdH1cblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdHRoaXMubWVzaCA9IG5ldyBNZXNoKCBuZXcgUGxhbmVHZW9tZXRyeSggMjAsIDIwICksIG1hdGVyaWFsICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLm1lc2g7XG5cblx0fVxuXG5cdHJlc2V0KCkge1xuXG5cdFx0dGhpcy50ZXh0dXJlID0gbnVsbDtcblx0XHR0aGlzLm1lc2ggPSBudWxsO1xuXG5cdH1cblxuXHRnZXREZXB0aFRleHR1cmUoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy50ZXh0dXJlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBXZWJYUk1hbmFnZXIgZXh0ZW5kcyBFdmVudERpc3BhdGNoZXIge1xuXG5cdGNvbnN0cnVjdG9yKCByZW5kZXJlciwgZ2wgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0bGV0IHNlc3Npb24gPSBudWxsO1xuXG5cdFx0bGV0IGZyYW1lYnVmZmVyU2NhbGVGYWN0b3IgPSAxLjA7XG5cblx0XHRsZXQgcmVmZXJlbmNlU3BhY2UgPSBudWxsO1xuXHRcdGxldCByZWZlcmVuY2VTcGFjZVR5cGUgPSAnbG9jYWwtZmxvb3InO1xuXHRcdC8vIFNldCBkZWZhdWx0IGZvdmVhdGlvbiB0byBtYXhpbXVtLlxuXHRcdGxldCBmb3ZlYXRpb24gPSAxLjA7XG5cdFx0bGV0IGN1c3RvbVJlZmVyZW5jZVNwYWNlID0gbnVsbDtcblxuXHRcdGxldCBwb3NlID0gbnVsbDtcblx0XHRsZXQgZ2xCaW5kaW5nID0gbnVsbDtcblx0XHRsZXQgZ2xQcm9qTGF5ZXIgPSBudWxsO1xuXHRcdGxldCBnbEJhc2VMYXllciA9IG51bGw7XG5cdFx0bGV0IHhyRnJhbWUgPSBudWxsO1xuXG5cdFx0Y29uc3QgZGVwdGhTZW5zaW5nID0gbmV3IFdlYlhSRGVwdGhTZW5zaW5nKCk7XG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IGdsLmdldENvbnRleHRBdHRyaWJ1dGVzKCk7XG5cblx0XHRsZXQgaW5pdGlhbFJlbmRlclRhcmdldCA9IG51bGw7XG5cdFx0bGV0IG5ld1JlbmRlclRhcmdldCA9IG51bGw7XG5cblx0XHRjb25zdCBjb250cm9sbGVycyA9IFtdO1xuXHRcdGNvbnN0IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXMgPSBbXTtcblxuXHRcdGNvbnN0IGN1cnJlbnRTaXplID0gbmV3IFZlY3RvcjIoKTtcblx0XHRsZXQgY3VycmVudFBpeGVsUmF0aW8gPSBudWxsO1xuXG5cdFx0Ly9cblxuXHRcdGNvbnN0IGNhbWVyYUwgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoKTtcblx0XHRjYW1lcmFMLmxheWVycy5lbmFibGUoIDEgKTtcblx0XHRjYW1lcmFMLnZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKTtcblxuXHRcdGNvbnN0IGNhbWVyYVIgPSBuZXcgUGVyc3BlY3RpdmVDYW1lcmEoKTtcblx0XHRjYW1lcmFSLmxheWVycy5lbmFibGUoIDIgKTtcblx0XHRjYW1lcmFSLnZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKTtcblxuXHRcdGNvbnN0IGNhbWVyYXMgPSBbIGNhbWVyYUwsIGNhbWVyYVIgXTtcblxuXHRcdGNvbnN0IGNhbWVyYVhSID0gbmV3IEFycmF5Q2FtZXJhKCk7XG5cdFx0Y2FtZXJhWFIubGF5ZXJzLmVuYWJsZSggMSApO1xuXHRcdGNhbWVyYVhSLmxheWVycy5lbmFibGUoIDIgKTtcblxuXHRcdGxldCBfY3VycmVudERlcHRoTmVhciA9IG51bGw7XG5cdFx0bGV0IF9jdXJyZW50RGVwdGhGYXIgPSBudWxsO1xuXG5cdFx0Ly9cblxuXHRcdHRoaXMuY2FtZXJhQXV0b1VwZGF0ZSA9IHRydWU7XG5cdFx0dGhpcy5lbmFibGVkID0gZmFsc2U7XG5cblx0XHR0aGlzLmlzUHJlc2VudGluZyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5nZXRDb250cm9sbGVyID0gZnVuY3Rpb24gKCBpbmRleCApIHtcblxuXHRcdFx0bGV0IGNvbnRyb2xsZXIgPSBjb250cm9sbGVyc1sgaW5kZXggXTtcblxuXHRcdFx0aWYgKCBjb250cm9sbGVyID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29udHJvbGxlciA9IG5ldyBXZWJYUkNvbnRyb2xsZXIoKTtcblx0XHRcdFx0Y29udHJvbGxlcnNbIGluZGV4IF0gPSBjb250cm9sbGVyO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBjb250cm9sbGVyLmdldFRhcmdldFJheVNwYWNlKCk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRDb250cm9sbGVyR3JpcCA9IGZ1bmN0aW9uICggaW5kZXggKSB7XG5cblx0XHRcdGxldCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGluZGV4IF07XG5cblx0XHRcdGlmICggY29udHJvbGxlciA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGNvbnRyb2xsZXIgPSBuZXcgV2ViWFJDb250cm9sbGVyKCk7XG5cdFx0XHRcdGNvbnRyb2xsZXJzWyBpbmRleCBdID0gY29udHJvbGxlcjtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gY29udHJvbGxlci5nZXRHcmlwU3BhY2UoKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldEhhbmQgPSBmdW5jdGlvbiAoIGluZGV4ICkge1xuXG5cdFx0XHRsZXQgY29udHJvbGxlciA9IGNvbnRyb2xsZXJzWyBpbmRleCBdO1xuXG5cdFx0XHRpZiAoIGNvbnRyb2xsZXIgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRjb250cm9sbGVyID0gbmV3IFdlYlhSQ29udHJvbGxlcigpO1xuXHRcdFx0XHRjb250cm9sbGVyc1sgaW5kZXggXSA9IGNvbnRyb2xsZXI7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGNvbnRyb2xsZXIuZ2V0SGFuZFNwYWNlKCk7XG5cblx0XHR9O1xuXG5cdFx0Ly9cblxuXHRcdGZ1bmN0aW9uIG9uU2Vzc2lvbkV2ZW50KCBldmVudCApIHtcblxuXHRcdFx0Y29uc3QgY29udHJvbGxlckluZGV4ID0gY29udHJvbGxlcklucHV0U291cmNlcy5pbmRleE9mKCBldmVudC5pbnB1dFNvdXJjZSApO1xuXG5cdFx0XHRpZiAoIGNvbnRyb2xsZXJJbmRleCA9PT0gLSAxICkge1xuXG5cdFx0XHRcdHJldHVybjtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGNvbnRyb2xsZXJJbmRleCBdO1xuXG5cdFx0XHRpZiAoIGNvbnRyb2xsZXIgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRjb250cm9sbGVyLnVwZGF0ZSggZXZlbnQuaW5wdXRTb3VyY2UsIGV2ZW50LmZyYW1lLCBjdXN0b21SZWZlcmVuY2VTcGFjZSB8fCByZWZlcmVuY2VTcGFjZSApO1xuXHRcdFx0XHRjb250cm9sbGVyLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogZXZlbnQudHlwZSwgZGF0YTogZXZlbnQuaW5wdXRTb3VyY2UgfSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBvblNlc3Npb25FbmQoKSB7XG5cblx0XHRcdHNlc3Npb24ucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3NlbGVjdCcsIG9uU2Vzc2lvbkV2ZW50ICk7XG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdzZWxlY3RzdGFydCcsIG9uU2Vzc2lvbkV2ZW50ICk7XG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdzZWxlY3RlbmQnLCBvblNlc3Npb25FdmVudCApO1xuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZScsIG9uU2Vzc2lvbkV2ZW50ICk7XG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdzcXVlZXplc3RhcnQnLCBvblNlc3Npb25FdmVudCApO1xuXHRcdFx0c2Vzc2lvbi5yZW1vdmVFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZWVuZCcsIG9uU2Vzc2lvbkV2ZW50ICk7XG5cdFx0XHRzZXNzaW9uLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdlbmQnLCBvblNlc3Npb25FbmQgKTtcblx0XHRcdHNlc3Npb24ucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2lucHV0c291cmNlc2NoYW5nZScsIG9uSW5wdXRTb3VyY2VzQ2hhbmdlICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvbnRyb2xsZXJzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbnB1dFNvdXJjZSA9IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXNbIGkgXTtcblxuXHRcdFx0XHRpZiAoIGlucHV0U291cmNlID09PSBudWxsICkgY29udGludWU7XG5cblx0XHRcdFx0Y29udHJvbGxlcklucHV0U291cmNlc1sgaSBdID0gbnVsbDtcblxuXHRcdFx0XHRjb250cm9sbGVyc1sgaSBdLmRpc2Nvbm5lY3QoIGlucHV0U291cmNlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0X2N1cnJlbnREZXB0aE5lYXIgPSBudWxsO1xuXHRcdFx0X2N1cnJlbnREZXB0aEZhciA9IG51bGw7XG5cblx0XHRcdGRlcHRoU2Vuc2luZy5yZXNldCgpO1xuXG5cdFx0XHQvLyByZXN0b3JlIGZyYW1lYnVmZmVyL3JlbmRlcmluZyBzdGF0ZVxuXG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGluaXRpYWxSZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0Z2xCYXNlTGF5ZXIgPSBudWxsO1xuXHRcdFx0Z2xQcm9qTGF5ZXIgPSBudWxsO1xuXHRcdFx0Z2xCaW5kaW5nID0gbnVsbDtcblx0XHRcdHNlc3Npb24gPSBudWxsO1xuXHRcdFx0bmV3UmVuZGVyVGFyZ2V0ID0gbnVsbDtcblxuXHRcdFx0Ly9cblxuXHRcdFx0YW5pbWF0aW9uLnN0b3AoKTtcblxuXHRcdFx0c2NvcGUuaXNQcmVzZW50aW5nID0gZmFsc2U7XG5cblx0XHRcdHJlbmRlcmVyLnNldFBpeGVsUmF0aW8oIGN1cnJlbnRQaXhlbFJhdGlvICk7XG5cdFx0XHRyZW5kZXJlci5zZXRTaXplKCBjdXJyZW50U2l6ZS53aWR0aCwgY3VycmVudFNpemUuaGVpZ2h0LCBmYWxzZSApO1xuXG5cdFx0XHRzY29wZS5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdzZXNzaW9uZW5kJyB9ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLnNldEZyYW1lYnVmZmVyU2NhbGVGYWN0b3IgPSBmdW5jdGlvbiAoIHZhbHVlICkge1xuXG5cdFx0XHRmcmFtZWJ1ZmZlclNjYWxlRmFjdG9yID0gdmFsdWU7XG5cblx0XHRcdGlmICggc2NvcGUuaXNQcmVzZW50aW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYlhSTWFuYWdlcjogQ2Fubm90IGNoYW5nZSBmcmFtZWJ1ZmZlciBzY2FsZSB3aGlsZSBwcmVzZW50aW5nLicgKTtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0UmVmZXJlbmNlU3BhY2VUeXBlID0gZnVuY3Rpb24gKCB2YWx1ZSApIHtcblxuXHRcdFx0cmVmZXJlbmNlU3BhY2VUeXBlID0gdmFsdWU7XG5cblx0XHRcdGlmICggc2NvcGUuaXNQcmVzZW50aW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLldlYlhSTWFuYWdlcjogQ2Fubm90IGNoYW5nZSByZWZlcmVuY2Ugc3BhY2UgdHlwZSB3aGlsZSBwcmVzZW50aW5nLicgKTtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0UmVmZXJlbmNlU3BhY2UgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBjdXN0b21SZWZlcmVuY2VTcGFjZSB8fCByZWZlcmVuY2VTcGFjZTtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldFJlZmVyZW5jZVNwYWNlID0gZnVuY3Rpb24gKCBzcGFjZSApIHtcblxuXHRcdFx0Y3VzdG9tUmVmZXJlbmNlU3BhY2UgPSBzcGFjZTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldEJhc2VMYXllciA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIGdsUHJvakxheWVyICE9PSBudWxsID8gZ2xQcm9qTGF5ZXIgOiBnbEJhc2VMYXllcjtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldEJpbmRpbmcgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBnbEJpbmRpbmc7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRGcmFtZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIHhyRnJhbWU7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRTZXNzaW9uID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gc2Vzc2lvbjtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldFNlc3Npb24gPSBhc3luYyBmdW5jdGlvbiAoIHZhbHVlICkge1xuXG5cdFx0XHRzZXNzaW9uID0gdmFsdWU7XG5cblx0XHRcdGlmICggc2Vzc2lvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRpbml0aWFsUmVuZGVyVGFyZ2V0ID0gcmVuZGVyZXIuZ2V0UmVuZGVyVGFyZ2V0KCk7XG5cblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnc2VsZWN0Jywgb25TZXNzaW9uRXZlbnQgKTtcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnc2VsZWN0c3RhcnQnLCBvblNlc3Npb25FdmVudCApO1xuXHRcdFx0XHRzZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoICdzZWxlY3RlbmQnLCBvblNlc3Npb25FdmVudCApO1xuXHRcdFx0XHRzZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoICdzcXVlZXplJywgb25TZXNzaW9uRXZlbnQgKTtcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZXN0YXJ0Jywgb25TZXNzaW9uRXZlbnQgKTtcblx0XHRcdFx0c2Vzc2lvbi5hZGRFdmVudExpc3RlbmVyKCAnc3F1ZWV6ZWVuZCcsIG9uU2Vzc2lvbkV2ZW50ICk7XG5cdFx0XHRcdHNlc3Npb24uYWRkRXZlbnRMaXN0ZW5lciggJ2VuZCcsIG9uU2Vzc2lvbkVuZCApO1xuXHRcdFx0XHRzZXNzaW9uLmFkZEV2ZW50TGlzdGVuZXIoICdpbnB1dHNvdXJjZXNjaGFuZ2UnLCBvbklucHV0U291cmNlc0NoYW5nZSApO1xuXG5cdFx0XHRcdGlmICggYXR0cmlidXRlcy54ckNvbXBhdGlibGUgIT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRhd2FpdCBnbC5tYWtlWFJDb21wYXRpYmxlKCk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGN1cnJlbnRQaXhlbFJhdGlvID0gcmVuZGVyZXIuZ2V0UGl4ZWxSYXRpbygpO1xuXHRcdFx0XHRyZW5kZXJlci5nZXRTaXplKCBjdXJyZW50U2l6ZSApO1xuXG5cdFx0XHRcdGlmICggc2Vzc2lvbi5yZW5kZXJTdGF0ZS5sYXllcnMgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGxheWVySW5pdCA9IHtcblx0XHRcdFx0XHRcdGFudGlhbGlhczogYXR0cmlidXRlcy5hbnRpYWxpYXMsXG5cdFx0XHRcdFx0XHRhbHBoYTogdHJ1ZSxcblx0XHRcdFx0XHRcdGRlcHRoOiBhdHRyaWJ1dGVzLmRlcHRoLFxuXHRcdFx0XHRcdFx0c3RlbmNpbDogYXR0cmlidXRlcy5zdGVuY2lsLFxuXHRcdFx0XHRcdFx0ZnJhbWVidWZmZXJTY2FsZUZhY3RvcjogZnJhbWVidWZmZXJTY2FsZUZhY3RvclxuXHRcdFx0XHRcdH07XG5cblx0XHRcdFx0XHRnbEJhc2VMYXllciA9IG5ldyBYUldlYkdMTGF5ZXIoIHNlc3Npb24sIGdsLCBsYXllckluaXQgKTtcblxuXHRcdFx0XHRcdHNlc3Npb24udXBkYXRlUmVuZGVyU3RhdGUoIHsgYmFzZUxheWVyOiBnbEJhc2VMYXllciB9ICk7XG5cblx0XHRcdFx0XHRyZW5kZXJlci5zZXRQaXhlbFJhdGlvKCAxICk7XG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0U2l6ZSggZ2xCYXNlTGF5ZXIuZnJhbWVidWZmZXJXaWR0aCwgZ2xCYXNlTGF5ZXIuZnJhbWVidWZmZXJIZWlnaHQsIGZhbHNlICk7XG5cblx0XHRcdFx0XHRuZXdSZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoXG5cdFx0XHRcdFx0XHRnbEJhc2VMYXllci5mcmFtZWJ1ZmZlcldpZHRoLFxuXHRcdFx0XHRcdFx0Z2xCYXNlTGF5ZXIuZnJhbWVidWZmZXJIZWlnaHQsXG5cdFx0XHRcdFx0XHR7XG5cdFx0XHRcdFx0XHRcdGZvcm1hdDogUkdCQUZvcm1hdCxcblx0XHRcdFx0XHRcdFx0dHlwZTogVW5zaWduZWRCeXRlVHlwZSxcblx0XHRcdFx0XHRcdFx0Y29sb3JTcGFjZTogcmVuZGVyZXIub3V0cHV0Q29sb3JTcGFjZSxcblx0XHRcdFx0XHRcdFx0c3RlbmNpbEJ1ZmZlcjogYXR0cmlidXRlcy5zdGVuY2lsXG5cdFx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0KTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0bGV0IGRlcHRoRm9ybWF0ID0gbnVsbDtcblx0XHRcdFx0XHRsZXQgZGVwdGhUeXBlID0gbnVsbDtcblx0XHRcdFx0XHRsZXQgZ2xEZXB0aEZvcm1hdCA9IG51bGw7XG5cblx0XHRcdFx0XHRpZiAoIGF0dHJpYnV0ZXMuZGVwdGggKSB7XG5cblx0XHRcdFx0XHRcdGdsRGVwdGhGb3JtYXQgPSBhdHRyaWJ1dGVzLnN0ZW5jaWwgPyBnbC5ERVBUSDI0X1NURU5DSUw4IDogZ2wuREVQVEhfQ09NUE9ORU5UMjQ7XG5cdFx0XHRcdFx0XHRkZXB0aEZvcm1hdCA9IGF0dHJpYnV0ZXMuc3RlbmNpbCA/IERlcHRoU3RlbmNpbEZvcm1hdCA6IERlcHRoRm9ybWF0O1xuXHRcdFx0XHRcdFx0ZGVwdGhUeXBlID0gYXR0cmlidXRlcy5zdGVuY2lsID8gVW5zaWduZWRJbnQyNDhUeXBlIDogVW5zaWduZWRJbnRUeXBlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Y29uc3QgcHJvamVjdGlvbmxheWVySW5pdCA9IHtcblx0XHRcdFx0XHRcdGNvbG9yRm9ybWF0OiBnbC5SR0JBOCxcblx0XHRcdFx0XHRcdGRlcHRoRm9ybWF0OiBnbERlcHRoRm9ybWF0LFxuXHRcdFx0XHRcdFx0c2NhbGVGYWN0b3I6IGZyYW1lYnVmZmVyU2NhbGVGYWN0b3Jcblx0XHRcdFx0XHR9O1xuXG5cdFx0XHRcdFx0Z2xCaW5kaW5nID0gbmV3IFhSV2ViR0xCaW5kaW5nKCBzZXNzaW9uLCBnbCApO1xuXG5cdFx0XHRcdFx0Z2xQcm9qTGF5ZXIgPSBnbEJpbmRpbmcuY3JlYXRlUHJvamVjdGlvbkxheWVyKCBwcm9qZWN0aW9ubGF5ZXJJbml0ICk7XG5cblx0XHRcdFx0XHRzZXNzaW9uLnVwZGF0ZVJlbmRlclN0YXRlKCB7IGxheWVyczogWyBnbFByb2pMYXllciBdIH0gKTtcblxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldFBpeGVsUmF0aW8oIDEgKTtcblx0XHRcdFx0XHRyZW5kZXJlci5zZXRTaXplKCBnbFByb2pMYXllci50ZXh0dXJlV2lkdGgsIGdsUHJvakxheWVyLnRleHR1cmVIZWlnaHQsIGZhbHNlICk7XG5cblx0XHRcdFx0XHRuZXdSZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoXG5cdFx0XHRcdFx0XHRnbFByb2pMYXllci50ZXh0dXJlV2lkdGgsXG5cdFx0XHRcdFx0XHRnbFByb2pMYXllci50ZXh0dXJlSGVpZ2h0LFxuXHRcdFx0XHRcdFx0e1xuXHRcdFx0XHRcdFx0XHRmb3JtYXQ6IFJHQkFGb3JtYXQsXG5cdFx0XHRcdFx0XHRcdHR5cGU6IFVuc2lnbmVkQnl0ZVR5cGUsXG5cdFx0XHRcdFx0XHRcdGRlcHRoVGV4dHVyZTogbmV3IERlcHRoVGV4dHVyZSggZ2xQcm9qTGF5ZXIudGV4dHVyZVdpZHRoLCBnbFByb2pMYXllci50ZXh0dXJlSGVpZ2h0LCBkZXB0aFR5cGUsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIHVuZGVmaW5lZCwgdW5kZWZpbmVkLCB1bmRlZmluZWQsIGRlcHRoRm9ybWF0ICksXG5cdFx0XHRcdFx0XHRcdHN0ZW5jaWxCdWZmZXI6IGF0dHJpYnV0ZXMuc3RlbmNpbCxcblx0XHRcdFx0XHRcdFx0Y29sb3JTcGFjZTogcmVuZGVyZXIub3V0cHV0Q29sb3JTcGFjZSxcblx0XHRcdFx0XHRcdFx0c2FtcGxlczogYXR0cmlidXRlcy5hbnRpYWxpYXMgPyA0IDogMCxcblx0XHRcdFx0XHRcdFx0cmVzb2x2ZURlcHRoQnVmZmVyOiAoIGdsUHJvakxheWVyLmlnbm9yZURlcHRoVmFsdWVzID09PSBmYWxzZSApXG5cdFx0XHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdG5ld1JlbmRlclRhcmdldC5pc1hSUmVuZGVyVGFyZ2V0ID0gdHJ1ZTsgLy8gVE9ETyBSZW1vdmUgdGhpcyB3aGVuIHBvc3NpYmxlLCBzZWUgIzIzMjc4XG5cblx0XHRcdFx0dGhpcy5zZXRGb3ZlYXRpb24oIGZvdmVhdGlvbiApO1xuXG5cdFx0XHRcdGN1c3RvbVJlZmVyZW5jZVNwYWNlID0gbnVsbDtcblx0XHRcdFx0cmVmZXJlbmNlU3BhY2UgPSBhd2FpdCBzZXNzaW9uLnJlcXVlc3RSZWZlcmVuY2VTcGFjZSggcmVmZXJlbmNlU3BhY2VUeXBlICk7XG5cblx0XHRcdFx0YW5pbWF0aW9uLnNldENvbnRleHQoIHNlc3Npb24gKTtcblx0XHRcdFx0YW5pbWF0aW9uLnN0YXJ0KCk7XG5cblx0XHRcdFx0c2NvcGUuaXNQcmVzZW50aW5nID0gdHJ1ZTtcblxuXHRcdFx0XHRzY29wZS5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdzZXNzaW9uc3RhcnQnIH0gKTtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0RW52aXJvbm1lbnRCbGVuZE1vZGUgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdGlmICggc2Vzc2lvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRyZXR1cm4gc2Vzc2lvbi5lbnZpcm9ubWVudEJsZW5kTW9kZTtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0RGVwdGhUZXh0dXJlID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gZGVwdGhTZW5zaW5nLmdldERlcHRoVGV4dHVyZSgpO1xuXG5cdFx0fTtcblxuXHRcdGZ1bmN0aW9uIG9uSW5wdXRTb3VyY2VzQ2hhbmdlKCBldmVudCApIHtcblxuXHRcdFx0Ly8gTm90aWZ5IGRpc2Nvbm5lY3RlZFxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBldmVudC5yZW1vdmVkLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbnB1dFNvdXJjZSA9IGV2ZW50LnJlbW92ZWRbIGkgXTtcblx0XHRcdFx0Y29uc3QgaW5kZXggPSBjb250cm9sbGVySW5wdXRTb3VyY2VzLmluZGV4T2YoIGlucHV0U291cmNlICk7XG5cblx0XHRcdFx0aWYgKCBpbmRleCA+PSAwICkge1xuXG5cdFx0XHRcdFx0Y29udHJvbGxlcklucHV0U291cmNlc1sgaW5kZXggXSA9IG51bGw7XG5cdFx0XHRcdFx0Y29udHJvbGxlcnNbIGluZGV4IF0uZGlzY29ubmVjdCggaW5wdXRTb3VyY2UgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gTm90aWZ5IGNvbm5lY3RlZFxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBldmVudC5hZGRlZC5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgaW5wdXRTb3VyY2UgPSBldmVudC5hZGRlZFsgaSBdO1xuXG5cdFx0XHRcdGxldCBjb250cm9sbGVySW5kZXggPSBjb250cm9sbGVySW5wdXRTb3VyY2VzLmluZGV4T2YoIGlucHV0U291cmNlICk7XG5cblx0XHRcdFx0aWYgKCBjb250cm9sbGVySW5kZXggPT09IC0gMSApIHtcblxuXHRcdFx0XHRcdC8vIEFzc2lnbiBpbnB1dCBzb3VyY2UgYSBjb250cm9sbGVyIHRoYXQgY3VycmVudGx5IGhhcyBubyBpbnB1dCBzb3VyY2VcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvbnRyb2xsZXJzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0aWYgKCBpID49IGNvbnRyb2xsZXJJbnB1dFNvdXJjZXMubGVuZ3RoICkge1xuXG5cdFx0XHRcdFx0XHRcdGNvbnRyb2xsZXJJbnB1dFNvdXJjZXMucHVzaCggaW5wdXRTb3VyY2UgKTtcblx0XHRcdFx0XHRcdFx0Y29udHJvbGxlckluZGV4ID0gaTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdH0gZWxzZSBpZiAoIGNvbnRyb2xsZXJJbnB1dFNvdXJjZXNbIGkgXSA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdFx0XHRjb250cm9sbGVySW5wdXRTb3VyY2VzWyBpIF0gPSBpbnB1dFNvdXJjZTtcblx0XHRcdFx0XHRcdFx0Y29udHJvbGxlckluZGV4ID0gaTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIElmIGFsbCBjb250cm9sbGVycyBkbyBjdXJyZW50bHkgcmVjZWl2ZSBpbnB1dCB3ZSBpZ25vcmUgbmV3IG9uZXNcblxuXHRcdFx0XHRcdGlmICggY29udHJvbGxlckluZGV4ID09PSAtIDEgKSBicmVhaztcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Y29uc3QgY29udHJvbGxlciA9IGNvbnRyb2xsZXJzWyBjb250cm9sbGVySW5kZXggXTtcblxuXHRcdFx0XHRpZiAoIGNvbnRyb2xsZXIgKSB7XG5cblx0XHRcdFx0XHRjb250cm9sbGVyLmNvbm5lY3QoIGlucHV0U291cmNlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvL1xuXG5cdFx0Y29uc3QgY2FtZXJhTFBvcyA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0Y29uc3QgY2FtZXJhUlBvcyA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHQvKipcblx0XHQgKiBBc3N1bWVzIDIgY2FtZXJhcyB0aGF0IGFyZSBwYXJhbGxlbCBhbmQgc2hhcmUgYW4gWC1heGlzLCBhbmQgdGhhdFxuXHRcdCAqIHRoZSBjYW1lcmFzJyBwcm9qZWN0aW9uIGFuZCB3b3JsZCBtYXRyaWNlcyBoYXZlIGFscmVhZHkgYmVlbiBzZXQuXG5cdFx0ICogQW5kIHRoYXQgbmVhciBhbmQgZmFyIHBsYW5lcyBhcmUgaWRlbnRpY2FsIGZvciBib3RoIGNhbWVyYXMuXG5cdFx0ICogVmlzdWFsaXphdGlvbiBvZiB0aGlzIHRlY2huaXF1ZTogaHR0cHM6Ly9jb21wdXRlcmdyYXBoaWNzLnN0YWNrZXhjaGFuZ2UuY29tL2EvNDc2NVxuXHRcdCAqL1xuXHRcdGZ1bmN0aW9uIHNldFByb2plY3Rpb25Gcm9tVW5pb24oIGNhbWVyYSwgY2FtZXJhTCwgY2FtZXJhUiApIHtcblxuXHRcdFx0Y2FtZXJhTFBvcy5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGNhbWVyYUwubWF0cml4V29ybGQgKTtcblx0XHRcdGNhbWVyYVJQb3Muc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBjYW1lcmFSLm1hdHJpeFdvcmxkICk7XG5cblx0XHRcdGNvbnN0IGlwZCA9IGNhbWVyYUxQb3MuZGlzdGFuY2VUbyggY2FtZXJhUlBvcyApO1xuXG5cdFx0XHRjb25zdCBwcm9qTCA9IGNhbWVyYUwucHJvamVjdGlvbk1hdHJpeC5lbGVtZW50cztcblx0XHRcdGNvbnN0IHByb2pSID0gY2FtZXJhUi5wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzO1xuXG5cdFx0XHQvLyBWUiBzeXN0ZW1zIHdpbGwgaGF2ZSBpZGVudGljYWwgZmFyIGFuZCBuZWFyIHBsYW5lcywgYW5kXG5cdFx0XHQvLyBtb3N0IGxpa2VseSBpZGVudGljYWwgdG9wIGFuZCBib3R0b20gZnJ1c3R1bSBleHRlbnRzLlxuXHRcdFx0Ly8gVXNlIHRoZSBsZWZ0IGNhbWVyYSBmb3IgdGhlc2UgdmFsdWVzLlxuXHRcdFx0Y29uc3QgbmVhciA9IHByb2pMWyAxNCBdIC8gKCBwcm9qTFsgMTAgXSAtIDEgKTtcblx0XHRcdGNvbnN0IGZhciA9IHByb2pMWyAxNCBdIC8gKCBwcm9qTFsgMTAgXSArIDEgKTtcblx0XHRcdGNvbnN0IHRvcEZvdiA9ICggcHJvakxbIDkgXSArIDEgKSAvIHByb2pMWyA1IF07XG5cdFx0XHRjb25zdCBib3R0b21Gb3YgPSAoIHByb2pMWyA5IF0gLSAxICkgLyBwcm9qTFsgNSBdO1xuXG5cdFx0XHRjb25zdCBsZWZ0Rm92ID0gKCBwcm9qTFsgOCBdIC0gMSApIC8gcHJvakxbIDAgXTtcblx0XHRcdGNvbnN0IHJpZ2h0Rm92ID0gKCBwcm9qUlsgOCBdICsgMSApIC8gcHJvalJbIDAgXTtcblx0XHRcdGNvbnN0IGxlZnQgPSBuZWFyICogbGVmdEZvdjtcblx0XHRcdGNvbnN0IHJpZ2h0ID0gbmVhciAqIHJpZ2h0Rm92O1xuXG5cdFx0XHQvLyBDYWxjdWxhdGUgdGhlIG5ldyBjYW1lcmEncyBwb3NpdGlvbiBvZmZzZXQgZnJvbSB0aGVcblx0XHRcdC8vIGxlZnQgY2FtZXJhLiB4T2Zmc2V0IHNob3VsZCBiZSByb3VnaGx5IGhhbGYgYGlwZGAuXG5cdFx0XHRjb25zdCB6T2Zmc2V0ID0gaXBkIC8gKCAtIGxlZnRGb3YgKyByaWdodEZvdiApO1xuXHRcdFx0Y29uc3QgeE9mZnNldCA9IHpPZmZzZXQgKiAtIGxlZnRGb3Y7XG5cblx0XHRcdC8vIFRPRE86IEJldHRlciB3YXkgdG8gYXBwbHkgdGhpcyBvZmZzZXQ/XG5cdFx0XHRjYW1lcmFMLm1hdHJpeFdvcmxkLmRlY29tcG9zZSggY2FtZXJhLnBvc2l0aW9uLCBjYW1lcmEucXVhdGVybmlvbiwgY2FtZXJhLnNjYWxlICk7XG5cdFx0XHRjYW1lcmEudHJhbnNsYXRlWCggeE9mZnNldCApO1xuXHRcdFx0Y2FtZXJhLnRyYW5zbGF0ZVooIHpPZmZzZXQgKTtcblx0XHRcdGNhbWVyYS5tYXRyaXhXb3JsZC5jb21wb3NlKCBjYW1lcmEucG9zaXRpb24sIGNhbWVyYS5xdWF0ZXJuaW9uLCBjYW1lcmEuc2NhbGUgKTtcblx0XHRcdGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UuY29weSggY2FtZXJhLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cblx0XHRcdC8vIEZpbmQgdGhlIHVuaW9uIG9mIHRoZSBmcnVzdHVtIHZhbHVlcyBvZiB0aGUgY2FtZXJhcyBhbmQgc2NhbGVcblx0XHRcdC8vIHRoZSB2YWx1ZXMgc28gdGhhdCB0aGUgbmVhciBwbGFuZSdzIHBvc2l0aW9uIGRvZXMgbm90IGNoYW5nZSBpbiB3b3JsZCBzcGFjZSxcblx0XHRcdC8vIGFsdGhvdWdoIG11c3Qgbm93IGJlIHJlbGF0aXZlIHRvIHRoZSBuZXcgdW5pb24gY2FtZXJhLlxuXHRcdFx0Y29uc3QgbmVhcjIgPSBuZWFyICsgek9mZnNldDtcblx0XHRcdGNvbnN0IGZhcjIgPSBmYXIgKyB6T2Zmc2V0O1xuXHRcdFx0Y29uc3QgbGVmdDIgPSBsZWZ0IC0geE9mZnNldDtcblx0XHRcdGNvbnN0IHJpZ2h0MiA9IHJpZ2h0ICsgKCBpcGQgLSB4T2Zmc2V0ICk7XG5cdFx0XHRjb25zdCB0b3AyID0gdG9wRm92ICogZmFyIC8gZmFyMiAqIG5lYXIyO1xuXHRcdFx0Y29uc3QgYm90dG9tMiA9IGJvdHRvbUZvdiAqIGZhciAvIGZhcjIgKiBuZWFyMjtcblxuXHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXgubWFrZVBlcnNwZWN0aXZlKCBsZWZ0MiwgcmlnaHQyLCB0b3AyLCBib3R0b20yLCBuZWFyMiwgZmFyMiApO1xuXHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlLmNvcHkoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4ICkuaW52ZXJ0KCk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiB1cGRhdGVDYW1lcmEoIGNhbWVyYSwgcGFyZW50ICkge1xuXG5cdFx0XHRpZiAoIHBhcmVudCA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRjYW1lcmEubWF0cml4V29ybGQuY29weSggY2FtZXJhLm1hdHJpeCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNhbWVyYS5tYXRyaXhXb3JsZC5tdWx0aXBseU1hdHJpY2VzKCBwYXJlbnQubWF0cml4V29ybGQsIGNhbWVyYS5tYXRyaXggKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlLmNvcHkoIGNhbWVyYS5tYXRyaXhXb3JsZCApLmludmVydCgpO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy51cGRhdGVDYW1lcmEgPSBmdW5jdGlvbiAoIGNhbWVyYSApIHtcblxuXHRcdFx0aWYgKCBzZXNzaW9uID09PSBudWxsICkgcmV0dXJuO1xuXG5cdFx0XHRpZiAoIGRlcHRoU2Vuc2luZy50ZXh0dXJlICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGNhbWVyYS5uZWFyID0gZGVwdGhTZW5zaW5nLmRlcHRoTmVhcjtcblx0XHRcdFx0Y2FtZXJhLmZhciA9IGRlcHRoU2Vuc2luZy5kZXB0aEZhcjtcblxuXHRcdFx0fVxuXG5cdFx0XHRjYW1lcmFYUi5uZWFyID0gY2FtZXJhUi5uZWFyID0gY2FtZXJhTC5uZWFyID0gY2FtZXJhLm5lYXI7XG5cdFx0XHRjYW1lcmFYUi5mYXIgPSBjYW1lcmFSLmZhciA9IGNhbWVyYUwuZmFyID0gY2FtZXJhLmZhcjtcblxuXHRcdFx0aWYgKCBfY3VycmVudERlcHRoTmVhciAhPT0gY2FtZXJhWFIubmVhciB8fCBfY3VycmVudERlcHRoRmFyICE9PSBjYW1lcmFYUi5mYXIgKSB7XG5cblx0XHRcdFx0Ly8gTm90ZSB0aGF0IHRoZSBuZXcgcmVuZGVyU3RhdGUgd29uJ3QgYXBwbHkgdW50aWwgdGhlIG5leHQgZnJhbWUuIFNlZSAjMTgzMjBcblxuXHRcdFx0XHRzZXNzaW9uLnVwZGF0ZVJlbmRlclN0YXRlKCB7XG5cdFx0XHRcdFx0ZGVwdGhOZWFyOiBjYW1lcmFYUi5uZWFyLFxuXHRcdFx0XHRcdGRlcHRoRmFyOiBjYW1lcmFYUi5mYXJcblx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdF9jdXJyZW50RGVwdGhOZWFyID0gY2FtZXJhWFIubmVhcjtcblx0XHRcdFx0X2N1cnJlbnREZXB0aEZhciA9IGNhbWVyYVhSLmZhcjtcblxuXHRcdFx0XHRjYW1lcmFMLm5lYXIgPSBfY3VycmVudERlcHRoTmVhcjtcblx0XHRcdFx0Y2FtZXJhTC5mYXIgPSBfY3VycmVudERlcHRoRmFyO1xuXHRcdFx0XHRjYW1lcmFSLm5lYXIgPSBfY3VycmVudERlcHRoTmVhcjtcblx0XHRcdFx0Y2FtZXJhUi5mYXIgPSBfY3VycmVudERlcHRoRmFyO1xuXG5cdFx0XHRcdGNhbWVyYUwudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXHRcdFx0XHRjYW1lcmFSLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblx0XHRcdFx0Y2FtZXJhLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBwYXJlbnQgPSBjYW1lcmEucGFyZW50O1xuXHRcdFx0Y29uc3QgY2FtZXJhcyA9IGNhbWVyYVhSLmNhbWVyYXM7XG5cblx0XHRcdHVwZGF0ZUNhbWVyYSggY2FtZXJhWFIsIHBhcmVudCApO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjYW1lcmFzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHR1cGRhdGVDYW1lcmEoIGNhbWVyYXNbIGkgXSwgcGFyZW50ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gdXBkYXRlIHByb2plY3Rpb24gbWF0cml4IGZvciBwcm9wZXIgdmlldyBmcnVzdHVtIGN1bGxpbmdcblxuXHRcdFx0aWYgKCBjYW1lcmFzLmxlbmd0aCA9PT0gMiApIHtcblxuXHRcdFx0XHRzZXRQcm9qZWN0aW9uRnJvbVVuaW9uKCBjYW1lcmFYUiwgY2FtZXJhTCwgY2FtZXJhUiApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdC8vIGFzc3VtZSBzaW5nbGUgY2FtZXJhIHNldHVwIChBUilcblxuXHRcdFx0XHRjYW1lcmFYUi5wcm9qZWN0aW9uTWF0cml4LmNvcHkoIGNhbWVyYUwucHJvamVjdGlvbk1hdHJpeCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIHVwZGF0ZSB1c2VyIGNhbWVyYSBhbmQgaXRzIGNoaWxkcmVuXG5cblx0XHRcdHVwZGF0ZVVzZXJDYW1lcmEoIGNhbWVyYSwgY2FtZXJhWFIsIHBhcmVudCApO1xuXG5cdFx0fTtcblxuXHRcdGZ1bmN0aW9uIHVwZGF0ZVVzZXJDYW1lcmEoIGNhbWVyYSwgY2FtZXJhWFIsIHBhcmVudCApIHtcblxuXHRcdFx0aWYgKCBwYXJlbnQgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0Y2FtZXJhLm1hdHJpeC5jb3B5KCBjYW1lcmFYUi5tYXRyaXhXb3JsZCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNhbWVyYS5tYXRyaXguY29weSggcGFyZW50Lm1hdHJpeFdvcmxkICk7XG5cdFx0XHRcdGNhbWVyYS5tYXRyaXguaW52ZXJ0KCk7XG5cdFx0XHRcdGNhbWVyYS5tYXRyaXgubXVsdGlwbHkoIGNhbWVyYVhSLm1hdHJpeFdvcmxkICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Y2FtZXJhLm1hdHJpeC5kZWNvbXBvc2UoIGNhbWVyYS5wb3NpdGlvbiwgY2FtZXJhLnF1YXRlcm5pb24sIGNhbWVyYS5zY2FsZSApO1xuXHRcdFx0Y2FtZXJhLnVwZGF0ZU1hdHJpeFdvcmxkKCB0cnVlICk7XG5cblx0XHRcdGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LmNvcHkoIGNhbWVyYVhSLnByb2plY3Rpb25NYXRyaXggKTtcblx0XHRcdGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZS5jb3B5KCBjYW1lcmFYUi5wcm9qZWN0aW9uTWF0cml4SW52ZXJzZSApO1xuXG5cdFx0XHRpZiAoIGNhbWVyYS5pc1BlcnNwZWN0aXZlQ2FtZXJhICkge1xuXG5cdFx0XHRcdGNhbWVyYS5mb3YgPSBSQUQyREVHICogMiAqIE1hdGguYXRhbiggMSAvIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyA1IF0gKTtcblx0XHRcdFx0Y2FtZXJhLnpvb20gPSAxO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHR0aGlzLmdldENhbWVyYSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIGNhbWVyYVhSO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0Rm92ZWF0aW9uID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRpZiAoIGdsUHJvakxheWVyID09PSBudWxsICYmIGdsQmFzZUxheWVyID09PSBudWxsICkge1xuXG5cdFx0XHRcdHJldHVybiB1bmRlZmluZWQ7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGZvdmVhdGlvbjtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldEZvdmVhdGlvbiA9IGZ1bmN0aW9uICggdmFsdWUgKSB7XG5cblx0XHRcdC8vIDAgPSBubyBmb3ZlYXRpb24gPSBmdWxsIHJlc29sdXRpb25cblx0XHRcdC8vIDEgPSBtYXhpbXVtIGZvdmVhdGlvbiA9IHRoZSBlZGdlcyByZW5kZXIgYXQgbG93ZXIgcmVzb2x1dGlvblxuXG5cdFx0XHRmb3ZlYXRpb24gPSB2YWx1ZTtcblxuXHRcdFx0aWYgKCBnbFByb2pMYXllciAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRnbFByb2pMYXllci5maXhlZEZvdmVhdGlvbiA9IHZhbHVlO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggZ2xCYXNlTGF5ZXIgIT09IG51bGwgJiYgZ2xCYXNlTGF5ZXIuZml4ZWRGb3ZlYXRpb24gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRnbEJhc2VMYXllci5maXhlZEZvdmVhdGlvbiA9IHZhbHVlO1xuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5oYXNEZXB0aFNlbnNpbmcgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBkZXB0aFNlbnNpbmcudGV4dHVyZSAhPT0gbnVsbDtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldERlcHRoU2Vuc2luZ01lc2ggPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBkZXB0aFNlbnNpbmcuZ2V0TWVzaCggY2FtZXJhWFIgKTtcblxuXHRcdH07XG5cblx0XHQvLyBBbmltYXRpb24gTG9vcFxuXG5cdFx0bGV0IG9uQW5pbWF0aW9uRnJhbWVDYWxsYmFjayA9IG51bGw7XG5cblx0XHRmdW5jdGlvbiBvbkFuaW1hdGlvbkZyYW1lKCB0aW1lLCBmcmFtZSApIHtcblxuXHRcdFx0cG9zZSA9IGZyYW1lLmdldFZpZXdlclBvc2UoIGN1c3RvbVJlZmVyZW5jZVNwYWNlIHx8IHJlZmVyZW5jZVNwYWNlICk7XG5cdFx0XHR4ckZyYW1lID0gZnJhbWU7XG5cblx0XHRcdGlmICggcG9zZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRjb25zdCB2aWV3cyA9IHBvc2Uudmlld3M7XG5cblx0XHRcdFx0aWYgKCBnbEJhc2VMYXllciAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldEZyYW1lYnVmZmVyKCBuZXdSZW5kZXJUYXJnZXQsIGdsQmFzZUxheWVyLmZyYW1lYnVmZmVyICk7XG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCBuZXdSZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0bGV0IGNhbWVyYVhSTmVlZHNVcGRhdGUgPSBmYWxzZTtcblxuXHRcdFx0XHQvLyBjaGVjayBpZiBpdCdzIG5lY2Vzc2FyeSB0byByZWJ1aWxkIGNhbWVyYVhSJ3MgY2FtZXJhIGxpc3RcblxuXHRcdFx0XHRpZiAoIHZpZXdzLmxlbmd0aCAhPT0gY2FtZXJhWFIuY2FtZXJhcy5sZW5ndGggKSB7XG5cblx0XHRcdFx0XHRjYW1lcmFYUi5jYW1lcmFzLmxlbmd0aCA9IDA7XG5cdFx0XHRcdFx0Y2FtZXJhWFJOZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHZpZXdzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IHZpZXcgPSB2aWV3c1sgaSBdO1xuXG5cdFx0XHRcdFx0bGV0IHZpZXdwb3J0ID0gbnVsbDtcblxuXHRcdFx0XHRcdGlmICggZ2xCYXNlTGF5ZXIgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRcdHZpZXdwb3J0ID0gZ2xCYXNlTGF5ZXIuZ2V0Vmlld3BvcnQoIHZpZXcgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGdsU3ViSW1hZ2UgPSBnbEJpbmRpbmcuZ2V0Vmlld1N1YkltYWdlKCBnbFByb2pMYXllciwgdmlldyApO1xuXHRcdFx0XHRcdFx0dmlld3BvcnQgPSBnbFN1YkltYWdlLnZpZXdwb3J0O1xuXG5cdFx0XHRcdFx0XHQvLyBGb3Igc2lkZS1ieS1zaWRlIHByb2plY3Rpb24sIHdlIG9ubHkgcHJvZHVjZSBhIHNpbmdsZSB0ZXh0dXJlIGZvciBib3RoIGV5ZXMuXG5cdFx0XHRcdFx0XHRpZiAoIGkgPT09IDAgKSB7XG5cblx0XHRcdFx0XHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0VGV4dHVyZXMoXG5cdFx0XHRcdFx0XHRcdFx0bmV3UmVuZGVyVGFyZ2V0LFxuXHRcdFx0XHRcdFx0XHRcdGdsU3ViSW1hZ2UuY29sb3JUZXh0dXJlLFxuXHRcdFx0XHRcdFx0XHRcdGdsUHJvakxheWVyLmlnbm9yZURlcHRoVmFsdWVzID8gdW5kZWZpbmVkIDogZ2xTdWJJbWFnZS5kZXB0aFN0ZW5jaWxUZXh0dXJlICk7XG5cblx0XHRcdFx0XHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCBuZXdSZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0bGV0IGNhbWVyYSA9IGNhbWVyYXNbIGkgXTtcblxuXHRcdFx0XHRcdGlmICggY2FtZXJhID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRcdGNhbWVyYSA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSgpO1xuXHRcdFx0XHRcdFx0Y2FtZXJhLmxheWVycy5lbmFibGUoIGkgKTtcblx0XHRcdFx0XHRcdGNhbWVyYS52aWV3cG9ydCA9IG5ldyBWZWN0b3I0KCk7XG5cdFx0XHRcdFx0XHRjYW1lcmFzWyBpIF0gPSBjYW1lcmE7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRjYW1lcmEubWF0cml4LmZyb21BcnJheSggdmlldy50cmFuc2Zvcm0ubWF0cml4ICk7XG5cdFx0XHRcdFx0Y2FtZXJhLm1hdHJpeC5kZWNvbXBvc2UoIGNhbWVyYS5wb3NpdGlvbiwgY2FtZXJhLnF1YXRlcm5pb24sIGNhbWVyYS5zY2FsZSApO1xuXHRcdFx0XHRcdGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LmZyb21BcnJheSggdmlldy5wcm9qZWN0aW9uTWF0cml4ICk7XG5cdFx0XHRcdFx0Y2FtZXJhLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlLmNvcHkoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4ICkuaW52ZXJ0KCk7XG5cdFx0XHRcdFx0Y2FtZXJhLnZpZXdwb3J0LnNldCggdmlld3BvcnQueCwgdmlld3BvcnQueSwgdmlld3BvcnQud2lkdGgsIHZpZXdwb3J0LmhlaWdodCApO1xuXG5cdFx0XHRcdFx0aWYgKCBpID09PSAwICkge1xuXG5cdFx0XHRcdFx0XHRjYW1lcmFYUi5tYXRyaXguY29weSggY2FtZXJhLm1hdHJpeCApO1xuXHRcdFx0XHRcdFx0Y2FtZXJhWFIubWF0cml4LmRlY29tcG9zZSggY2FtZXJhWFIucG9zaXRpb24sIGNhbWVyYVhSLnF1YXRlcm5pb24sIGNhbWVyYVhSLnNjYWxlICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoIGNhbWVyYVhSTmVlZHNVcGRhdGUgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRcdGNhbWVyYVhSLmNhbWVyYXMucHVzaCggY2FtZXJhICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vXG5cblx0XHRcdFx0Y29uc3QgZW5hYmxlZEZlYXR1cmVzID0gc2Vzc2lvbi5lbmFibGVkRmVhdHVyZXM7XG5cblx0XHRcdFx0aWYgKCBlbmFibGVkRmVhdHVyZXMgJiYgZW5hYmxlZEZlYXR1cmVzLmluY2x1ZGVzKCAnZGVwdGgtc2Vuc2luZycgKSApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGRlcHRoRGF0YSA9IGdsQmluZGluZy5nZXREZXB0aEluZm9ybWF0aW9uKCB2aWV3c1sgMCBdICk7XG5cblx0XHRcdFx0XHRpZiAoIGRlcHRoRGF0YSAmJiBkZXB0aERhdGEuaXNWYWxpZCAmJiBkZXB0aERhdGEudGV4dHVyZSApIHtcblxuXHRcdFx0XHRcdFx0ZGVwdGhTZW5zaW5nLmluaXQoIHJlbmRlcmVyLCBkZXB0aERhdGEsIHNlc3Npb24ucmVuZGVyU3RhdGUgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9cblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY29udHJvbGxlcnMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGlucHV0U291cmNlID0gY29udHJvbGxlcklucHV0U291cmNlc1sgaSBdO1xuXHRcdFx0XHRjb25zdCBjb250cm9sbGVyID0gY29udHJvbGxlcnNbIGkgXTtcblxuXHRcdFx0XHRpZiAoIGlucHV0U291cmNlICE9PSBudWxsICYmIGNvbnRyb2xsZXIgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGNvbnRyb2xsZXIudXBkYXRlKCBpbnB1dFNvdXJjZSwgZnJhbWUsIGN1c3RvbVJlZmVyZW5jZVNwYWNlIHx8IHJlZmVyZW5jZVNwYWNlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggb25BbmltYXRpb25GcmFtZUNhbGxiYWNrICkgb25BbmltYXRpb25GcmFtZUNhbGxiYWNrKCB0aW1lLCBmcmFtZSApO1xuXG5cdFx0XHRpZiAoIGZyYW1lLmRldGVjdGVkUGxhbmVzICkge1xuXG5cdFx0XHRcdHNjb3BlLmRpc3BhdGNoRXZlbnQoIHsgdHlwZTogJ3BsYW5lc2RldGVjdGVkJywgZGF0YTogZnJhbWUgfSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHhyRnJhbWUgPSBudWxsO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgYW5pbWF0aW9uID0gbmV3IFdlYkdMQW5pbWF0aW9uKCk7XG5cblx0XHRhbmltYXRpb24uc2V0QW5pbWF0aW9uTG9vcCggb25BbmltYXRpb25GcmFtZSApO1xuXG5cdFx0dGhpcy5zZXRBbmltYXRpb25Mb29wID0gZnVuY3Rpb24gKCBjYWxsYmFjayApIHtcblxuXHRcdFx0b25BbmltYXRpb25GcmFtZUNhbGxiYWNrID0gY2FsbGJhY2s7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5kaXNwb3NlID0gZnVuY3Rpb24gKCkge307XG5cblx0fVxuXG59XG5cbmNvbnN0IF9lMSA9IC8qQF9fUFVSRV9fKi8gbmV3IEV1bGVyKCk7XG5jb25zdCBfbTEgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5cbmZ1bmN0aW9uIFdlYkdMTWF0ZXJpYWxzKCByZW5kZXJlciwgcHJvcGVydGllcyApIHtcblxuXHRmdW5jdGlvbiByZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWFwLCB1bmlmb3JtICkge1xuXG5cdFx0aWYgKCBtYXAubWF0cml4QXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0bWFwLnVwZGF0ZU1hdHJpeCgpO1xuXG5cdFx0fVxuXG5cdFx0dW5pZm9ybS52YWx1ZS5jb3B5KCBtYXAubWF0cml4ICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hGb2dVbmlmb3JtcyggdW5pZm9ybXMsIGZvZyApIHtcblxuXHRcdGZvZy5jb2xvci5nZXRSR0IoIHVuaWZvcm1zLmZvZ0NvbG9yLnZhbHVlLCBnZXRVbmxpdFVuaWZvcm1Db2xvclNwYWNlKCByZW5kZXJlciApICk7XG5cblx0XHRpZiAoIGZvZy5pc0ZvZyApIHtcblxuXHRcdFx0dW5pZm9ybXMuZm9nTmVhci52YWx1ZSA9IGZvZy5uZWFyO1xuXHRcdFx0dW5pZm9ybXMuZm9nRmFyLnZhbHVlID0gZm9nLmZhcjtcblxuXHRcdH0gZWxzZSBpZiAoIGZvZy5pc0ZvZ0V4cDIgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmZvZ0RlbnNpdHkudmFsdWUgPSBmb2cuZGVuc2l0eTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaE1hdGVyaWFsVW5pZm9ybXMoIHVuaWZvcm1zLCBtYXRlcmlhbCwgcGl4ZWxSYXRpbywgaGVpZ2h0LCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaEJhc2ljTWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hMYW1iZXJ0TWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hUb29uTWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNUb29uKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcblxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmlzTWVzaFBob25nTWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNQaG9uZyggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsICkge1xuXG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNDb21tb24oIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xuXHRcdFx0cmVmcmVzaFVuaWZvcm1zU3RhbmRhcmQoIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlzTWVzaFBoeXNpY2FsTWF0ZXJpYWwgKSB7XG5cblx0XHRcdFx0cmVmcmVzaFVuaWZvcm1zUGh5c2ljYWwoIHVuaWZvcm1zLCBtYXRlcmlhbCwgdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmlzTWVzaE1hdGNhcE1hdGVyaWFsICkge1xuXG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNDb21tb24oIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xuXHRcdFx0cmVmcmVzaFVuaWZvcm1zTWF0Y2FwKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcblxuXHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsLmlzTWVzaERlcHRoTWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc01lc2hEaXN0YW5jZU1hdGVyaWFsICkge1xuXG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNDb21tb24oIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xuXHRcdFx0cmVmcmVzaFVuaWZvcm1zRGlzdGFuY2UoIHVuaWZvcm1zLCBtYXRlcmlhbCApO1xuXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNNZXNoTm9ybWFsTWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc0xpbmVCYXNpY01hdGVyaWFsICkge1xuXG5cdFx0XHRyZWZyZXNoVW5pZm9ybXNMaW5lKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcblxuXHRcdFx0aWYgKCBtYXRlcmlhbC5pc0xpbmVEYXNoZWRNYXRlcmlhbCApIHtcblxuXHRcdFx0XHRyZWZyZXNoVW5pZm9ybXNEYXNoKCB1bmlmb3JtcywgbWF0ZXJpYWwgKTtcblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNQb2ludHNNYXRlcmlhbCApIHtcblxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zUG9pbnRzKCB1bmlmb3JtcywgbWF0ZXJpYWwsIHBpeGVsUmF0aW8sIGhlaWdodCApO1xuXG5cdFx0fSBlbHNlIGlmICggbWF0ZXJpYWwuaXNTcHJpdGVNYXRlcmlhbCApIHtcblxuXHRcdFx0cmVmcmVzaFVuaWZvcm1zU3ByaXRlcyggdW5pZm9ybXMsIG1hdGVyaWFsICk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc1NoYWRvd01hdGVyaWFsICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5jb2xvci52YWx1ZS5jb3B5KCBtYXRlcmlhbC5jb2xvciApO1xuXHRcdFx0dW5pZm9ybXMub3BhY2l0eS52YWx1ZSA9IG1hdGVyaWFsLm9wYWNpdHk7XG5cblx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5pc1NoYWRlck1hdGVyaWFsICkge1xuXG5cdFx0XHRtYXRlcmlhbC51bmlmb3Jtc05lZWRVcGRhdGUgPSBmYWxzZTsgLy8gIzE1NTgxXG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc0NvbW1vbiggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xuXG5cdFx0dW5pZm9ybXMub3BhY2l0eS52YWx1ZSA9IG1hdGVyaWFsLm9wYWNpdHk7XG5cblx0XHRpZiAoIG1hdGVyaWFsLmNvbG9yICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5kaWZmdXNlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLmNvbG9yICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmVtaXNzaXZlICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5lbWlzc2l2ZS52YWx1ZS5jb3B5KCBtYXRlcmlhbC5lbWlzc2l2ZSApLm11bHRpcGx5U2NhbGFyKCBtYXRlcmlhbC5lbWlzc2l2ZUludGVuc2l0eSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5tYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLm1hcC52YWx1ZSA9IG1hdGVyaWFsLm1hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1hcCwgdW5pZm9ybXMubWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmFscGhhTWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5hbHBoYU1hcC52YWx1ZSA9IG1hdGVyaWFsLmFscGhhTWFwO1xuXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuYWxwaGFNYXAsIHVuaWZvcm1zLmFscGhhTWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmJ1bXBNYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmJ1bXBNYXAudmFsdWUgPSBtYXRlcmlhbC5idW1wTWFwO1xuXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuYnVtcE1hcCwgdW5pZm9ybXMuYnVtcE1hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR1bmlmb3Jtcy5idW1wU2NhbGUudmFsdWUgPSBtYXRlcmlhbC5idW1wU2NhbGU7XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuc2lkZSA9PT0gQmFja1NpZGUgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMuYnVtcFNjYWxlLnZhbHVlICo9IC0gMTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5ub3JtYWxNYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLm5vcm1hbE1hcC52YWx1ZSA9IG1hdGVyaWFsLm5vcm1hbE1hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm5vcm1hbE1hcCwgdW5pZm9ybXMubm9ybWFsTWFwVHJhbnNmb3JtICk7XG5cblx0XHRcdHVuaWZvcm1zLm5vcm1hbFNjYWxlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLm5vcm1hbFNjYWxlICk7XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuc2lkZSA9PT0gQmFja1NpZGUgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMubm9ybWFsU2NhbGUudmFsdWUubmVnYXRlKCk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwuZGlzcGxhY2VtZW50TWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5kaXNwbGFjZW1lbnRNYXAudmFsdWUgPSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXA7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5kaXNwbGFjZW1lbnRNYXAsIHVuaWZvcm1zLmRpc3BsYWNlbWVudE1hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR1bmlmb3Jtcy5kaXNwbGFjZW1lbnRTY2FsZS52YWx1ZSA9IG1hdGVyaWFsLmRpc3BsYWNlbWVudFNjYWxlO1xuXHRcdFx0dW5pZm9ybXMuZGlzcGxhY2VtZW50Qmlhcy52YWx1ZSA9IG1hdGVyaWFsLmRpc3BsYWNlbWVudEJpYXM7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmVtaXNzaXZlTWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5lbWlzc2l2ZU1hcC52YWx1ZSA9IG1hdGVyaWFsLmVtaXNzaXZlTWFwO1xuXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuZW1pc3NpdmVNYXAsIHVuaWZvcm1zLmVtaXNzaXZlTWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLnNwZWN1bGFyTWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5zcGVjdWxhck1hcC52YWx1ZSA9IG1hdGVyaWFsLnNwZWN1bGFyTWFwO1xuXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc3BlY3VsYXJNYXAsIHVuaWZvcm1zLnNwZWN1bGFyTWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmFscGhhVGVzdCA+IDAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmFscGhhVGVzdC52YWx1ZSA9IG1hdGVyaWFsLmFscGhhVGVzdDtcblxuXHRcdH1cblxuXHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xuXG5cdFx0Y29uc3QgZW52TWFwID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLmVudk1hcDtcblx0XHRjb25zdCBlbnZNYXBSb3RhdGlvbiA9IG1hdGVyaWFsUHJvcGVydGllcy5lbnZNYXBSb3RhdGlvbjtcblxuXHRcdGlmICggZW52TWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5lbnZNYXAudmFsdWUgPSBlbnZNYXA7XG5cblx0XHRcdF9lMS5jb3B5KCBlbnZNYXBSb3RhdGlvbiApO1xuXG5cdFx0XHQvLyBhY2NvbW1vZGF0ZSBsZWZ0LWhhbmRlZCBmcmFtZVxuXHRcdFx0X2UxLnggKj0gLSAxOyBfZTEueSAqPSAtIDE7IF9lMS56ICo9IC0gMTtcblxuXHRcdFx0aWYgKCBlbnZNYXAuaXNDdWJlVGV4dHVyZSAmJiBlbnZNYXAuaXNSZW5kZXJUYXJnZXRUZXh0dXJlID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHQvLyBlbnZpcm9ubWVudCBtYXBzIHdoaWNoIGFyZSBub3QgY3ViZSByZW5kZXIgdGFyZ2V0cyBvciBQTVJFTXMgZm9sbG93IGEgZGlmZmVyZW50IGNvbnZlbnRpb25cblx0XHRcdFx0X2UxLnkgKj0gLSAxO1xuXHRcdFx0XHRfZTEueiAqPSAtIDE7XG5cblx0XHRcdH1cblxuXHRcdFx0dW5pZm9ybXMuZW52TWFwUm90YXRpb24udmFsdWUuc2V0RnJvbU1hdHJpeDQoIF9tMS5tYWtlUm90YXRpb25Gcm9tRXVsZXIoIF9lMSApICk7XG5cblx0XHRcdHVuaWZvcm1zLmZsaXBFbnZNYXAudmFsdWUgPSAoIGVudk1hcC5pc0N1YmVUZXh0dXJlICYmIGVudk1hcC5pc1JlbmRlclRhcmdldFRleHR1cmUgPT09IGZhbHNlICkgPyAtIDEgOiAxO1xuXG5cdFx0XHR1bmlmb3Jtcy5yZWZsZWN0aXZpdHkudmFsdWUgPSBtYXRlcmlhbC5yZWZsZWN0aXZpdHk7XG5cdFx0XHR1bmlmb3Jtcy5pb3IudmFsdWUgPSBtYXRlcmlhbC5pb3I7XG5cdFx0XHR1bmlmb3Jtcy5yZWZyYWN0aW9uUmF0aW8udmFsdWUgPSBtYXRlcmlhbC5yZWZyYWN0aW9uUmF0aW87XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmxpZ2h0TWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5saWdodE1hcC52YWx1ZSA9IG1hdGVyaWFsLmxpZ2h0TWFwO1xuXHRcdFx0dW5pZm9ybXMubGlnaHRNYXBJbnRlbnNpdHkudmFsdWUgPSBtYXRlcmlhbC5saWdodE1hcEludGVuc2l0eTtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmxpZ2h0TWFwLCB1bmlmb3Jtcy5saWdodE1hcFRyYW5zZm9ybSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5hb01hcCApIHtcblxuXHRcdFx0dW5pZm9ybXMuYW9NYXAudmFsdWUgPSBtYXRlcmlhbC5hb01hcDtcblx0XHRcdHVuaWZvcm1zLmFvTWFwSW50ZW5zaXR5LnZhbHVlID0gbWF0ZXJpYWwuYW9NYXBJbnRlbnNpdHk7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5hb01hcCwgdW5pZm9ybXMuYW9NYXBUcmFuc2Zvcm0gKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zTGluZSggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xuXG5cdFx0dW5pZm9ybXMuZGlmZnVzZS52YWx1ZS5jb3B5KCBtYXRlcmlhbC5jb2xvciApO1xuXHRcdHVuaWZvcm1zLm9wYWNpdHkudmFsdWUgPSBtYXRlcmlhbC5vcGFjaXR5O1xuXG5cdFx0aWYgKCBtYXRlcmlhbC5tYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLm1hcC52YWx1ZSA9IG1hdGVyaWFsLm1hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1hcCwgdW5pZm9ybXMubWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc0Rhc2goIHVuaWZvcm1zLCBtYXRlcmlhbCApIHtcblxuXHRcdHVuaWZvcm1zLmRhc2hTaXplLnZhbHVlID0gbWF0ZXJpYWwuZGFzaFNpemU7XG5cdFx0dW5pZm9ybXMudG90YWxTaXplLnZhbHVlID0gbWF0ZXJpYWwuZGFzaFNpemUgKyBtYXRlcmlhbC5nYXBTaXplO1xuXHRcdHVuaWZvcm1zLnNjYWxlLnZhbHVlID0gbWF0ZXJpYWwuc2NhbGU7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc1BvaW50cyggdW5pZm9ybXMsIG1hdGVyaWFsLCBwaXhlbFJhdGlvLCBoZWlnaHQgKSB7XG5cblx0XHR1bmlmb3Jtcy5kaWZmdXNlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLmNvbG9yICk7XG5cdFx0dW5pZm9ybXMub3BhY2l0eS52YWx1ZSA9IG1hdGVyaWFsLm9wYWNpdHk7XG5cdFx0dW5pZm9ybXMuc2l6ZS52YWx1ZSA9IG1hdGVyaWFsLnNpemUgKiBwaXhlbFJhdGlvO1xuXHRcdHVuaWZvcm1zLnNjYWxlLnZhbHVlID0gaGVpZ2h0ICogMC41O1xuXG5cdFx0aWYgKCBtYXRlcmlhbC5tYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLm1hcC52YWx1ZSA9IG1hdGVyaWFsLm1hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLm1hcCwgdW5pZm9ybXMudXZUcmFuc2Zvcm0gKTtcblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwuYWxwaGFNYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmFscGhhTWFwLnZhbHVlID0gbWF0ZXJpYWwuYWxwaGFNYXA7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5hbHBoYU1hcCwgdW5pZm9ybXMuYWxwaGFNYXBUcmFuc2Zvcm0gKTtcblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwuYWxwaGFUZXN0ID4gMCApIHtcblxuXHRcdFx0dW5pZm9ybXMuYWxwaGFUZXN0LnZhbHVlID0gbWF0ZXJpYWwuYWxwaGFUZXN0O1xuXG5cdFx0fVxuXG5cdH1cblxuXHRmdW5jdGlvbiByZWZyZXNoVW5pZm9ybXNTcHJpdGVzKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XG5cblx0XHR1bmlmb3Jtcy5kaWZmdXNlLnZhbHVlLmNvcHkoIG1hdGVyaWFsLmNvbG9yICk7XG5cdFx0dW5pZm9ybXMub3BhY2l0eS52YWx1ZSA9IG1hdGVyaWFsLm9wYWNpdHk7XG5cdFx0dW5pZm9ybXMucm90YXRpb24udmFsdWUgPSBtYXRlcmlhbC5yb3RhdGlvbjtcblxuXHRcdGlmICggbWF0ZXJpYWwubWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5tYXAudmFsdWUgPSBtYXRlcmlhbC5tYXA7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5tYXAsIHVuaWZvcm1zLm1hcFRyYW5zZm9ybSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5hbHBoYU1hcCApIHtcblxuXHRcdFx0dW5pZm9ybXMuYWxwaGFNYXAudmFsdWUgPSBtYXRlcmlhbC5hbHBoYU1hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmFscGhhTWFwLCB1bmlmb3Jtcy5hbHBoYU1hcFRyYW5zZm9ybSApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5hbHBoYVRlc3QgPiAwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5hbHBoYVRlc3QudmFsdWUgPSBtYXRlcmlhbC5hbHBoYVRlc3Q7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc1Bob25nKCB1bmlmb3JtcywgbWF0ZXJpYWwgKSB7XG5cblx0XHR1bmlmb3Jtcy5zcGVjdWxhci52YWx1ZS5jb3B5KCBtYXRlcmlhbC5zcGVjdWxhciApO1xuXHRcdHVuaWZvcm1zLnNoaW5pbmVzcy52YWx1ZSA9IE1hdGgubWF4KCBtYXRlcmlhbC5zaGluaW5lc3MsIDFlLTQgKTsgLy8gdG8gcHJldmVudCBwb3coIDAuMCwgMC4wIClcblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zVG9vbiggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xuXG5cdFx0aWYgKCBtYXRlcmlhbC5ncmFkaWVudE1hcCApIHtcblxuXHRcdFx0dW5pZm9ybXMuZ3JhZGllbnRNYXAudmFsdWUgPSBtYXRlcmlhbC5ncmFkaWVudE1hcDtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zU3RhbmRhcmQoIHVuaWZvcm1zLCBtYXRlcmlhbCApIHtcblxuXHRcdHVuaWZvcm1zLm1ldGFsbmVzcy52YWx1ZSA9IG1hdGVyaWFsLm1ldGFsbmVzcztcblxuXHRcdGlmICggbWF0ZXJpYWwubWV0YWxuZXNzTWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5tZXRhbG5lc3NNYXAudmFsdWUgPSBtYXRlcmlhbC5tZXRhbG5lc3NNYXA7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5tZXRhbG5lc3NNYXAsIHVuaWZvcm1zLm1ldGFsbmVzc01hcFRyYW5zZm9ybSApO1xuXG5cdFx0fVxuXG5cdFx0dW5pZm9ybXMucm91Z2huZXNzLnZhbHVlID0gbWF0ZXJpYWwucm91Z2huZXNzO1xuXG5cdFx0aWYgKCBtYXRlcmlhbC5yb3VnaG5lc3NNYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLnJvdWdobmVzc01hcC52YWx1ZSA9IG1hdGVyaWFsLnJvdWdobmVzc01hcDtcblxuXHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLnJvdWdobmVzc01hcCwgdW5pZm9ybXMucm91Z2huZXNzTWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmVudk1hcCApIHtcblxuXHRcdFx0Ly91bmlmb3Jtcy5lbnZNYXAudmFsdWUgPSBtYXRlcmlhbC5lbnZNYXA7IC8vIHBhcnQgb2YgdW5pZm9ybXMgY29tbW9uXG5cblx0XHRcdHVuaWZvcm1zLmVudk1hcEludGVuc2l0eS52YWx1ZSA9IG1hdGVyaWFsLmVudk1hcEludGVuc2l0eTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zUGh5c2ljYWwoIHVuaWZvcm1zLCBtYXRlcmlhbCwgdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICkge1xuXG5cdFx0dW5pZm9ybXMuaW9yLnZhbHVlID0gbWF0ZXJpYWwuaW9yOyAvLyBhbHNvIHBhcnQgb2YgdW5pZm9ybXMgY29tbW9uXG5cblx0XHRpZiAoIG1hdGVyaWFsLnNoZWVuID4gMCApIHtcblxuXHRcdFx0dW5pZm9ybXMuc2hlZW5Db2xvci52YWx1ZS5jb3B5KCBtYXRlcmlhbC5zaGVlbkNvbG9yICkubXVsdGlwbHlTY2FsYXIoIG1hdGVyaWFsLnNoZWVuICk7XG5cblx0XHRcdHVuaWZvcm1zLnNoZWVuUm91Z2huZXNzLnZhbHVlID0gbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3M7XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuc2hlZW5Db2xvck1hcCApIHtcblxuXHRcdFx0XHR1bmlmb3Jtcy5zaGVlbkNvbG9yTWFwLnZhbHVlID0gbWF0ZXJpYWwuc2hlZW5Db2xvck1hcDtcblxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc2hlZW5Db2xvck1hcCwgdW5pZm9ybXMuc2hlZW5Db2xvck1hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3NNYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMuc2hlZW5Sb3VnaG5lc3NNYXAudmFsdWUgPSBtYXRlcmlhbC5zaGVlblJvdWdobmVzc01hcDtcblxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc2hlZW5Sb3VnaG5lc3NNYXAsIHVuaWZvcm1zLnNoZWVuUm91Z2huZXNzTWFwVHJhbnNmb3JtICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwuY2xlYXJjb2F0ID4gMCApIHtcblxuXHRcdFx0dW5pZm9ybXMuY2xlYXJjb2F0LnZhbHVlID0gbWF0ZXJpYWwuY2xlYXJjb2F0O1xuXHRcdFx0dW5pZm9ybXMuY2xlYXJjb2F0Um91Z2huZXNzLnZhbHVlID0gbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzO1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmNsZWFyY29hdE1hcCApIHtcblxuXHRcdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXRNYXAudmFsdWUgPSBtYXRlcmlhbC5jbGVhcmNvYXRNYXA7XG5cblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmNsZWFyY29hdE1hcCwgdW5pZm9ybXMuY2xlYXJjb2F0TWFwVHJhbnNmb3JtICk7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwLnZhbHVlID0gbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzTWFwO1xuXG5cdFx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3NNYXAsIHVuaWZvcm1zLmNsZWFyY29hdFJvdWdobmVzc01hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsTWFwICkge1xuXG5cdFx0XHRcdHVuaWZvcm1zLmNsZWFyY29hdE5vcm1hbE1hcC52YWx1ZSA9IG1hdGVyaWFsLmNsZWFyY29hdE5vcm1hbE1hcDtcblxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsTWFwLCB1bmlmb3Jtcy5jbGVhcmNvYXROb3JtYWxNYXBUcmFuc2Zvcm0gKTtcblxuXHRcdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXROb3JtYWxTY2FsZS52YWx1ZS5jb3B5KCBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxTY2FsZSApO1xuXG5cdFx0XHRcdGlmICggbWF0ZXJpYWwuc2lkZSA9PT0gQmFja1NpZGUgKSB7XG5cblx0XHRcdFx0XHR1bmlmb3Jtcy5jbGVhcmNvYXROb3JtYWxTY2FsZS52YWx1ZS5uZWdhdGUoKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwuZGlzcGVyc2lvbiA+IDAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmRpc3BlcnNpb24udmFsdWUgPSBtYXRlcmlhbC5kaXNwZXJzaW9uO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBtYXRlcmlhbC5pcmlkZXNjZW5jZSA+IDAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmlyaWRlc2NlbmNlLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2U7XG5cdFx0XHR1bmlmb3Jtcy5pcmlkZXNjZW5jZUlPUi52YWx1ZSA9IG1hdGVyaWFsLmlyaWRlc2NlbmNlSU9SO1xuXHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VUaGlja25lc3NNaW5pbXVtLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZVsgMCBdO1xuXHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXhpbXVtLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZVsgMSBdO1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlyaWRlc2NlbmNlTWFwICkge1xuXG5cdFx0XHRcdHVuaWZvcm1zLmlyaWRlc2NlbmNlTWFwLnZhbHVlID0gbWF0ZXJpYWwuaXJpZGVzY2VuY2VNYXA7XG5cblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmlyaWRlc2NlbmNlTWFwLCB1bmlmb3Jtcy5pcmlkZXNjZW5jZU1hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAudmFsdWUgPSBtYXRlcmlhbC5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcDtcblxuXHRcdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NNYXAsIHVuaWZvcm1zLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwVHJhbnNmb3JtICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggbWF0ZXJpYWwudHJhbnNtaXNzaW9uID4gMCApIHtcblxuXHRcdFx0dW5pZm9ybXMudHJhbnNtaXNzaW9uLnZhbHVlID0gbWF0ZXJpYWwudHJhbnNtaXNzaW9uO1xuXHRcdFx0dW5pZm9ybXMudHJhbnNtaXNzaW9uU2FtcGxlck1hcC52YWx1ZSA9IHRyYW5zbWlzc2lvblJlbmRlclRhcmdldC50ZXh0dXJlO1xuXHRcdFx0dW5pZm9ybXMudHJhbnNtaXNzaW9uU2FtcGxlclNpemUudmFsdWUuc2V0KCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQud2lkdGgsIHRyYW5zbWlzc2lvblJlbmRlclRhcmdldC5oZWlnaHQgKTtcblxuXHRcdFx0aWYgKCBtYXRlcmlhbC50cmFuc21pc3Npb25NYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMudHJhbnNtaXNzaW9uTWFwLnZhbHVlID0gbWF0ZXJpYWwudHJhbnNtaXNzaW9uTWFwO1xuXG5cdFx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC50cmFuc21pc3Npb25NYXAsIHVuaWZvcm1zLnRyYW5zbWlzc2lvbk1hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHVuaWZvcm1zLnRoaWNrbmVzcy52YWx1ZSA9IG1hdGVyaWFsLnRoaWNrbmVzcztcblxuXHRcdFx0aWYgKCBtYXRlcmlhbC50aGlja25lc3NNYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMudGhpY2tuZXNzTWFwLnZhbHVlID0gbWF0ZXJpYWwudGhpY2tuZXNzTWFwO1xuXG5cdFx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC50aGlja25lc3NNYXAsIHVuaWZvcm1zLnRoaWNrbmVzc01hcFRyYW5zZm9ybSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHVuaWZvcm1zLmF0dGVudWF0aW9uRGlzdGFuY2UudmFsdWUgPSBtYXRlcmlhbC5hdHRlbnVhdGlvbkRpc3RhbmNlO1xuXHRcdFx0dW5pZm9ybXMuYXR0ZW51YXRpb25Db2xvci52YWx1ZS5jb3B5KCBtYXRlcmlhbC5hdHRlbnVhdGlvbkNvbG9yICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLmFuaXNvdHJvcHkgPiAwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5hbmlzb3Ryb3B5VmVjdG9yLnZhbHVlLnNldCggbWF0ZXJpYWwuYW5pc290cm9weSAqIE1hdGguY29zKCBtYXRlcmlhbC5hbmlzb3Ryb3B5Um90YXRpb24gKSwgbWF0ZXJpYWwuYW5pc290cm9weSAqIE1hdGguc2luKCBtYXRlcmlhbC5hbmlzb3Ryb3B5Um90YXRpb24gKSApO1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmFuaXNvdHJvcHlNYXAgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMuYW5pc290cm9weU1hcC52YWx1ZSA9IG1hdGVyaWFsLmFuaXNvdHJvcHlNYXA7XG5cblx0XHRcdFx0cmVmcmVzaFRyYW5zZm9ybVVuaWZvcm0oIG1hdGVyaWFsLmFuaXNvdHJvcHlNYXAsIHVuaWZvcm1zLmFuaXNvdHJvcHlNYXBUcmFuc2Zvcm0gKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0dW5pZm9ybXMuc3BlY3VsYXJJbnRlbnNpdHkudmFsdWUgPSBtYXRlcmlhbC5zcGVjdWxhckludGVuc2l0eTtcblx0XHR1bmlmb3Jtcy5zcGVjdWxhckNvbG9yLnZhbHVlLmNvcHkoIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgKTtcblxuXHRcdGlmICggbWF0ZXJpYWwuc3BlY3VsYXJDb2xvck1hcCApIHtcblxuXHRcdFx0dW5pZm9ybXMuc3BlY3VsYXJDb2xvck1hcC52YWx1ZSA9IG1hdGVyaWFsLnNwZWN1bGFyQ29sb3JNYXA7XG5cblx0XHRcdHJlZnJlc2hUcmFuc2Zvcm1Vbmlmb3JtKCBtYXRlcmlhbC5zcGVjdWxhckNvbG9yTWFwLCB1bmlmb3Jtcy5zcGVjdWxhckNvbG9yTWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIG1hdGVyaWFsLnNwZWN1bGFySW50ZW5zaXR5TWFwICkge1xuXG5cdFx0XHR1bmlmb3Jtcy5zcGVjdWxhckludGVuc2l0eU1hcC52YWx1ZSA9IG1hdGVyaWFsLnNwZWN1bGFySW50ZW5zaXR5TWFwO1xuXG5cdFx0XHRyZWZyZXNoVHJhbnNmb3JtVW5pZm9ybSggbWF0ZXJpYWwuc3BlY3VsYXJJbnRlbnNpdHlNYXAsIHVuaWZvcm1zLnNwZWN1bGFySW50ZW5zaXR5TWFwVHJhbnNmb3JtICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHJlZnJlc2hVbmlmb3Jtc01hdGNhcCggdW5pZm9ybXMsIG1hdGVyaWFsICkge1xuXG5cdFx0aWYgKCBtYXRlcmlhbC5tYXRjYXAgKSB7XG5cblx0XHRcdHVuaWZvcm1zLm1hdGNhcC52YWx1ZSA9IG1hdGVyaWFsLm1hdGNhcDtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gcmVmcmVzaFVuaWZvcm1zRGlzdGFuY2UoIHVuaWZvcm1zLCBtYXRlcmlhbCApIHtcblxuXHRcdGNvbnN0IGxpZ2h0ID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICkubGlnaHQ7XG5cblx0XHR1bmlmb3Jtcy5yZWZlcmVuY2VQb3NpdGlvbi52YWx1ZS5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cdFx0dW5pZm9ybXMubmVhckRpc3RhbmNlLnZhbHVlID0gbGlnaHQuc2hhZG93LmNhbWVyYS5uZWFyO1xuXHRcdHVuaWZvcm1zLmZhckRpc3RhbmNlLnZhbHVlID0gbGlnaHQuc2hhZG93LmNhbWVyYS5mYXI7XG5cblx0fVxuXG5cdHJldHVybiB7XG5cdFx0cmVmcmVzaEZvZ1VuaWZvcm1zOiByZWZyZXNoRm9nVW5pZm9ybXMsXG5cdFx0cmVmcmVzaE1hdGVyaWFsVW5pZm9ybXM6IHJlZnJlc2hNYXRlcmlhbFVuaWZvcm1zXG5cdH07XG5cbn1cblxuZnVuY3Rpb24gV2ViR0xVbmlmb3Jtc0dyb3VwcyggZ2wsIGluZm8sIGNhcGFiaWxpdGllcywgc3RhdGUgKSB7XG5cblx0bGV0IGJ1ZmZlcnMgPSB7fTtcblx0bGV0IHVwZGF0ZUxpc3QgPSB7fTtcblx0bGV0IGFsbG9jYXRlZEJpbmRpbmdQb2ludHMgPSBbXTtcblxuXHRjb25zdCBtYXhCaW5kaW5nUG9pbnRzID0gZ2wuZ2V0UGFyYW1ldGVyKCBnbC5NQVhfVU5JRk9STV9CVUZGRVJfQklORElOR1MgKTsgLy8gYmluZGluZyBwb2ludHMgYXJlIGdsb2JhbCB3aGVyZWFzIGJsb2NrIGluZGljZXMgYXJlIHBlciBzaGFkZXIgcHJvZ3JhbVxuXG5cdGZ1bmN0aW9uIGJpbmQoIHVuaWZvcm1zR3JvdXAsIHByb2dyYW0gKSB7XG5cblx0XHRjb25zdCB3ZWJnbFByb2dyYW0gPSBwcm9ncmFtLnByb2dyYW07XG5cdFx0c3RhdGUudW5pZm9ybUJsb2NrQmluZGluZyggdW5pZm9ybXNHcm91cCwgd2ViZ2xQcm9ncmFtICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHVwZGF0ZSggdW5pZm9ybXNHcm91cCwgcHJvZ3JhbSApIHtcblxuXHRcdGxldCBidWZmZXIgPSBidWZmZXJzWyB1bmlmb3Jtc0dyb3VwLmlkIF07XG5cblx0XHRpZiAoIGJ1ZmZlciA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRwcmVwYXJlVW5pZm9ybXNHcm91cCggdW5pZm9ybXNHcm91cCApO1xuXG5cdFx0XHRidWZmZXIgPSBjcmVhdGVCdWZmZXIoIHVuaWZvcm1zR3JvdXAgKTtcblx0XHRcdGJ1ZmZlcnNbIHVuaWZvcm1zR3JvdXAuaWQgXSA9IGJ1ZmZlcjtcblxuXHRcdFx0dW5pZm9ybXNHcm91cC5hZGRFdmVudExpc3RlbmVyKCAnZGlzcG9zZScsIG9uVW5pZm9ybXNHcm91cHNEaXNwb3NlICk7XG5cblx0XHR9XG5cblx0XHQvLyBlbnN1cmUgdG8gdXBkYXRlIHRoZSBiaW5kaW5nIHBvaW50cy9ibG9jayBpbmRpY2VzIG1hcHBpbmcgZm9yIHRoaXMgcHJvZ3JhbVxuXG5cdFx0Y29uc3Qgd2ViZ2xQcm9ncmFtID0gcHJvZ3JhbS5wcm9ncmFtO1xuXHRcdHN0YXRlLnVwZGF0ZVVCT01hcHBpbmcoIHVuaWZvcm1zR3JvdXAsIHdlYmdsUHJvZ3JhbSApO1xuXG5cdFx0Ly8gdXBkYXRlIFVCTyBvbmNlIHBlciBmcmFtZVxuXG5cdFx0Y29uc3QgZnJhbWUgPSBpbmZvLnJlbmRlci5mcmFtZTtcblxuXHRcdGlmICggdXBkYXRlTGlzdFsgdW5pZm9ybXNHcm91cC5pZCBdICE9PSBmcmFtZSApIHtcblxuXHRcdFx0dXBkYXRlQnVmZmVyRGF0YSggdW5pZm9ybXNHcm91cCApO1xuXG5cdFx0XHR1cGRhdGVMaXN0WyB1bmlmb3Jtc0dyb3VwLmlkIF0gPSBmcmFtZTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnVuY3Rpb24gY3JlYXRlQnVmZmVyKCB1bmlmb3Jtc0dyb3VwICkge1xuXG5cdFx0Ly8gdGhlIHNldHVwIG9mIGFuIFVCTyBpcyBpbmRlcGVuZGVudCBvZiBhIHBhcnRpY3VsYXIgc2hhZGVyIHByb2dyYW0gYnV0IGdsb2JhbFxuXG5cdFx0Y29uc3QgYmluZGluZ1BvaW50SW5kZXggPSBhbGxvY2F0ZUJpbmRpbmdQb2ludEluZGV4KCk7XG5cdFx0dW5pZm9ybXNHcm91cC5fX2JpbmRpbmdQb2ludEluZGV4ID0gYmluZGluZ1BvaW50SW5kZXg7XG5cblx0XHRjb25zdCBidWZmZXIgPSBnbC5jcmVhdGVCdWZmZXIoKTtcblx0XHRjb25zdCBzaXplID0gdW5pZm9ybXNHcm91cC5fX3NpemU7XG5cdFx0Y29uc3QgdXNhZ2UgPSB1bmlmb3Jtc0dyb3VwLnVzYWdlO1xuXG5cdFx0Z2wuYmluZEJ1ZmZlciggZ2wuVU5JRk9STV9CVUZGRVIsIGJ1ZmZlciApO1xuXHRcdGdsLmJ1ZmZlckRhdGEoIGdsLlVOSUZPUk1fQlVGRkVSLCBzaXplLCB1c2FnZSApO1xuXHRcdGdsLmJpbmRCdWZmZXIoIGdsLlVOSUZPUk1fQlVGRkVSLCBudWxsICk7XG5cdFx0Z2wuYmluZEJ1ZmZlckJhc2UoIGdsLlVOSUZPUk1fQlVGRkVSLCBiaW5kaW5nUG9pbnRJbmRleCwgYnVmZmVyICk7XG5cblx0XHRyZXR1cm4gYnVmZmVyO1xuXG5cdH1cblxuXHRmdW5jdGlvbiBhbGxvY2F0ZUJpbmRpbmdQb2ludEluZGV4KCkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgbWF4QmluZGluZ1BvaW50czsgaSArKyApIHtcblxuXHRcdFx0aWYgKCBhbGxvY2F0ZWRCaW5kaW5nUG9pbnRzLmluZGV4T2YoIGkgKSA9PT0gLSAxICkge1xuXG5cdFx0XHRcdGFsbG9jYXRlZEJpbmRpbmdQb2ludHMucHVzaCggaSApO1xuXHRcdFx0XHRyZXR1cm4gaTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IE1heGltdW0gbnVtYmVyIG9mIHNpbXVsdGFuZW91c2x5IHVzYWJsZSB1bmlmb3JtcyBncm91cHMgcmVhY2hlZC4nICk7XG5cblx0XHRyZXR1cm4gMDtcblxuXHR9XG5cblx0ZnVuY3Rpb24gdXBkYXRlQnVmZmVyRGF0YSggdW5pZm9ybXNHcm91cCApIHtcblxuXHRcdGNvbnN0IGJ1ZmZlciA9IGJ1ZmZlcnNbIHVuaWZvcm1zR3JvdXAuaWQgXTtcblx0XHRjb25zdCB1bmlmb3JtcyA9IHVuaWZvcm1zR3JvdXAudW5pZm9ybXM7XG5cdFx0Y29uc3QgY2FjaGUgPSB1bmlmb3Jtc0dyb3VwLl9fY2FjaGU7XG5cblx0XHRnbC5iaW5kQnVmZmVyKCBnbC5VTklGT1JNX0JVRkZFUiwgYnVmZmVyICk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdW5pZm9ybXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHVuaWZvcm1BcnJheSA9IEFycmF5LmlzQXJyYXkoIHVuaWZvcm1zWyBpIF0gKSA/IHVuaWZvcm1zWyBpIF0gOiBbIHVuaWZvcm1zWyBpIF0gXTtcblxuXHRcdFx0Zm9yICggbGV0IGogPSAwLCBqbCA9IHVuaWZvcm1BcnJheS5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcblxuXHRcdFx0XHRjb25zdCB1bmlmb3JtID0gdW5pZm9ybUFycmF5WyBqIF07XG5cblx0XHRcdFx0aWYgKCBoYXNVbmlmb3JtQ2hhbmdlZCggdW5pZm9ybSwgaSwgaiwgY2FjaGUgKSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdGNvbnN0IG9mZnNldCA9IHVuaWZvcm0uX19vZmZzZXQ7XG5cblx0XHRcdFx0XHRjb25zdCB2YWx1ZXMgPSBBcnJheS5pc0FycmF5KCB1bmlmb3JtLnZhbHVlICkgPyB1bmlmb3JtLnZhbHVlIDogWyB1bmlmb3JtLnZhbHVlIF07XG5cblx0XHRcdFx0XHRsZXQgYXJyYXlPZmZzZXQgPSAwO1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGsgPSAwOyBrIDwgdmFsdWVzLmxlbmd0aDsgayArKyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgdmFsdWUgPSB2YWx1ZXNbIGsgXTtcblxuXHRcdFx0XHRcdFx0Y29uc3QgaW5mbyA9IGdldFVuaWZvcm1TaXplKCB2YWx1ZSApO1xuXG5cdFx0XHRcdFx0XHQvLyBUT0RPIGFkZCBpbnRlZ2VyIGFuZCBzdHJ1Y3Qgc3VwcG9ydFxuXHRcdFx0XHRcdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInIHx8IHR5cGVvZiB2YWx1ZSA9PT0gJ2Jvb2xlYW4nICkge1xuXG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyAwIF0gPSB2YWx1ZTtcblx0XHRcdFx0XHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggZ2wuVU5JRk9STV9CVUZGRVIsIG9mZnNldCArIGFycmF5T2Zmc2V0LCB1bmlmb3JtLl9fZGF0YSApO1xuXG5cdFx0XHRcdFx0XHR9IGVsc2UgaWYgKCB2YWx1ZS5pc01hdHJpeDMgKSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gbWFudWFsbHkgY29udmVydGluZyAzeDMgdG8gM3g0XG5cblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDAgXSA9IHZhbHVlLmVsZW1lbnRzWyAwIF07XG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyAxIF0gPSB2YWx1ZS5lbGVtZW50c1sgMSBdO1xuXHRcdFx0XHRcdFx0XHR1bmlmb3JtLl9fZGF0YVsgMiBdID0gdmFsdWUuZWxlbWVudHNbIDIgXTtcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDMgXSA9IDA7XG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyA0IF0gPSB2YWx1ZS5lbGVtZW50c1sgMyBdO1xuXHRcdFx0XHRcdFx0XHR1bmlmb3JtLl9fZGF0YVsgNSBdID0gdmFsdWUuZWxlbWVudHNbIDQgXTtcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDYgXSA9IHZhbHVlLmVsZW1lbnRzWyA1IF07XG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyA3IF0gPSAwO1xuXHRcdFx0XHRcdFx0XHR1bmlmb3JtLl9fZGF0YVsgOCBdID0gdmFsdWUuZWxlbWVudHNbIDYgXTtcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDkgXSA9IHZhbHVlLmVsZW1lbnRzWyA3IF07XG5cdFx0XHRcdFx0XHRcdHVuaWZvcm0uX19kYXRhWyAxMCBdID0gdmFsdWUuZWxlbWVudHNbIDggXTtcblx0XHRcdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGFbIDExIF0gPSAwO1xuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdHZhbHVlLnRvQXJyYXkoIHVuaWZvcm0uX19kYXRhLCBhcnJheU9mZnNldCApO1xuXG5cdFx0XHRcdFx0XHRcdGFycmF5T2Zmc2V0ICs9IGluZm8uc3RvcmFnZSAvIEZsb2F0MzJBcnJheS5CWVRFU19QRVJfRUxFTUVOVDtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Z2wuYnVmZmVyU3ViRGF0YSggZ2wuVU5JRk9STV9CVUZGRVIsIG9mZnNldCwgdW5pZm9ybS5fX2RhdGEgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGdsLmJpbmRCdWZmZXIoIGdsLlVOSUZPUk1fQlVGRkVSLCBudWxsICk7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGhhc1VuaWZvcm1DaGFuZ2VkKCB1bmlmb3JtLCBpbmRleCwgaW5kZXhBcnJheSwgY2FjaGUgKSB7XG5cblx0XHRjb25zdCB2YWx1ZSA9IHVuaWZvcm0udmFsdWU7XG5cdFx0Y29uc3QgaW5kZXhTdHJpbmcgPSBpbmRleCArICdfJyArIGluZGV4QXJyYXk7XG5cblx0XHRpZiAoIGNhY2hlWyBpbmRleFN0cmluZyBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdC8vIGNhY2hlIGVudHJ5IGRvZXMgbm90IGV4aXN0IHNvIGZhclxuXG5cdFx0XHRpZiAoIHR5cGVvZiB2YWx1ZSA9PT0gJ251bWJlcicgfHwgdHlwZW9mIHZhbHVlID09PSAnYm9vbGVhbicgKSB7XG5cblx0XHRcdFx0Y2FjaGVbIGluZGV4U3RyaW5nIF0gPSB2YWx1ZTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjYWNoZVsgaW5kZXhTdHJpbmcgXSA9IHZhbHVlLmNsb25lKCk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRydWU7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zdCBjYWNoZWRPYmplY3QgPSBjYWNoZVsgaW5kZXhTdHJpbmcgXTtcblxuXHRcdFx0Ly8gY29tcGFyZSBjdXJyZW50IHZhbHVlIHdpdGggY2FjaGVkIGVudHJ5XG5cblx0XHRcdGlmICggdHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyB8fCB0eXBlb2YgdmFsdWUgPT09ICdib29sZWFuJyApIHtcblxuXHRcdFx0XHRpZiAoIGNhY2hlZE9iamVjdCAhPT0gdmFsdWUgKSB7XG5cblx0XHRcdFx0XHRjYWNoZVsgaW5kZXhTdHJpbmcgXSA9IHZhbHVlO1xuXHRcdFx0XHRcdHJldHVybiB0cnVlO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRpZiAoIGNhY2hlZE9iamVjdC5lcXVhbHMoIHZhbHVlICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdFx0Y2FjaGVkT2JqZWN0LmNvcHkoIHZhbHVlICk7XG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gZmFsc2U7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIHByZXBhcmVVbmlmb3Jtc0dyb3VwKCB1bmlmb3Jtc0dyb3VwICkge1xuXG5cdFx0Ly8gZGV0ZXJtaW5lIHRvdGFsIGJ1ZmZlciBzaXplIGFjY29yZGluZyB0byB0aGUgU1REMTQwIGxheW91dFxuXHRcdC8vIEhpbnQ6IFNURDE0MCBpcyB0aGUgb25seSBzdXBwb3J0ZWQgbGF5b3V0IGluIFdlYkdMIDJcblxuXHRcdGNvbnN0IHVuaWZvcm1zID0gdW5pZm9ybXNHcm91cC51bmlmb3JtcztcblxuXHRcdGxldCBvZmZzZXQgPSAwOyAvLyBnbG9iYWwgYnVmZmVyIG9mZnNldCBpbiBieXRlc1xuXHRcdGNvbnN0IGNodW5rU2l6ZSA9IDE2OyAvLyBzaXplIG9mIGEgY2h1bmsgaW4gYnl0ZXNcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHVuaWZvcm1zLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHVuaWZvcm1BcnJheSA9IEFycmF5LmlzQXJyYXkoIHVuaWZvcm1zWyBpIF0gKSA/IHVuaWZvcm1zWyBpIF0gOiBbIHVuaWZvcm1zWyBpIF0gXTtcblxuXHRcdFx0Zm9yICggbGV0IGogPSAwLCBqbCA9IHVuaWZvcm1BcnJheS5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcblxuXHRcdFx0XHRjb25zdCB1bmlmb3JtID0gdW5pZm9ybUFycmF5WyBqIF07XG5cblx0XHRcdFx0Y29uc3QgdmFsdWVzID0gQXJyYXkuaXNBcnJheSggdW5pZm9ybS52YWx1ZSApID8gdW5pZm9ybS52YWx1ZSA6IFsgdW5pZm9ybS52YWx1ZSBdO1xuXG5cdFx0XHRcdGZvciAoIGxldCBrID0gMCwga2wgPSB2YWx1ZXMubGVuZ3RoOyBrIDwga2w7IGsgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB2YWx1ZSA9IHZhbHVlc1sgayBdO1xuXG5cdFx0XHRcdFx0Y29uc3QgaW5mbyA9IGdldFVuaWZvcm1TaXplKCB2YWx1ZSApO1xuXG5cdFx0XHRcdFx0Y29uc3QgY2h1bmtPZmZzZXQgPSBvZmZzZXQgJSBjaHVua1NpemU7IC8vIG9mZnNldCBpbiB0aGUgY3VycmVudCBjaHVua1xuXHRcdFx0XHRcdGNvbnN0IGNodW5rUGFkZGluZyA9IGNodW5rT2Zmc2V0ICUgaW5mby5ib3VuZGFyeTsgLy8gcmVxdWlyZWQgcGFkZGluZyB0byBtYXRjaCBib3VuZGFyeVxuXHRcdFx0XHRcdGNvbnN0IGNodW5rU3RhcnQgPSBjaHVua09mZnNldCArIGNodW5rUGFkZGluZzsgLy8gdGhlIHN0YXJ0IHBvc2l0aW9uIGluIHRoZSBjdXJyZW50IGNodW5rIGZvciB0aGUgZGF0YVxuXG5cdFx0XHRcdFx0b2Zmc2V0ICs9IGNodW5rUGFkZGluZztcblxuXHRcdFx0XHRcdC8vIENoZWNrIGZvciBjaHVuayBvdmVyZmxvd1xuXHRcdFx0XHRcdGlmICggY2h1bmtTdGFydCAhPT0gMCAmJiAoIGNodW5rU2l6ZSAtIGNodW5rU3RhcnQgKSA8IGluZm8uc3RvcmFnZSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gQWRkIHBhZGRpbmcgYW5kIGFkanVzdCBvZmZzZXRcblx0XHRcdFx0XHRcdG9mZnNldCArPSAoIGNodW5rU2l6ZSAtIGNodW5rU3RhcnQgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIHRoZSBmb2xsb3dpbmcgdHdvIHByb3BlcnRpZXMgd2lsbCBiZSB1c2VkIGZvciBwYXJ0aWFsIGJ1ZmZlciB1cGRhdGVzXG5cdFx0XHRcdFx0dW5pZm9ybS5fX2RhdGEgPSBuZXcgRmxvYXQzMkFycmF5KCBpbmZvLnN0b3JhZ2UgLyBGbG9hdDMyQXJyYXkuQllURVNfUEVSX0VMRU1FTlQgKTtcblx0XHRcdFx0XHR1bmlmb3JtLl9fb2Zmc2V0ID0gb2Zmc2V0O1xuXG5cdFx0XHRcdFx0Ly8gVXBkYXRlIHRoZSBnbG9iYWwgb2Zmc2V0XG5cdFx0XHRcdFx0b2Zmc2V0ICs9IGluZm8uc3RvcmFnZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGVuc3VyZSBjb3JyZWN0IGZpbmFsIHBhZGRpbmdcblxuXHRcdGNvbnN0IGNodW5rT2Zmc2V0ID0gb2Zmc2V0ICUgY2h1bmtTaXplO1xuXG5cdFx0aWYgKCBjaHVua09mZnNldCA+IDAgKSBvZmZzZXQgKz0gKCBjaHVua1NpemUgLSBjaHVua09mZnNldCApO1xuXG5cdFx0Ly9cblxuXHRcdHVuaWZvcm1zR3JvdXAuX19zaXplID0gb2Zmc2V0O1xuXHRcdHVuaWZvcm1zR3JvdXAuX19jYWNoZSA9IHt9O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGZ1bmN0aW9uIGdldFVuaWZvcm1TaXplKCB2YWx1ZSApIHtcblxuXHRcdGNvbnN0IGluZm8gPSB7XG5cdFx0XHRib3VuZGFyeTogMCwgLy8gYnl0ZXNcblx0XHRcdHN0b3JhZ2U6IDAgLy8gYnl0ZXNcblx0XHR9O1xuXG5cdFx0Ly8gZGV0ZXJtaW5lIHNpemVzIGFjY29yZGluZyB0byBTVEQxNDBcblxuXHRcdGlmICggdHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyB8fCB0eXBlb2YgdmFsdWUgPT09ICdib29sZWFuJyApIHtcblxuXHRcdFx0Ly8gZmxvYXQvaW50L2Jvb2xcblxuXHRcdFx0aW5mby5ib3VuZGFyeSA9IDQ7XG5cdFx0XHRpbmZvLnN0b3JhZ2UgPSA0O1xuXG5cdFx0fSBlbHNlIGlmICggdmFsdWUuaXNWZWN0b3IyICkge1xuXG5cdFx0XHQvLyB2ZWMyXG5cblx0XHRcdGluZm8uYm91bmRhcnkgPSA4O1xuXHRcdFx0aW5mby5zdG9yYWdlID0gODtcblxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzVmVjdG9yMyB8fCB2YWx1ZS5pc0NvbG9yICkge1xuXG5cdFx0XHQvLyB2ZWMzXG5cblx0XHRcdGluZm8uYm91bmRhcnkgPSAxNjtcblx0XHRcdGluZm8uc3RvcmFnZSA9IDEyOyAvLyBldmlsOiB2ZWMzIG11c3Qgc3RhcnQgb24gYSAxNi1ieXRlIGJvdW5kYXJ5IGJ1dCBpdCBvbmx5IGNvbnN1bWVzIDEyIGJ5dGVzXG5cblx0XHR9IGVsc2UgaWYgKCB2YWx1ZS5pc1ZlY3RvcjQgKSB7XG5cblx0XHRcdC8vIHZlYzRcblxuXHRcdFx0aW5mby5ib3VuZGFyeSA9IDE2O1xuXHRcdFx0aW5mby5zdG9yYWdlID0gMTY7XG5cblx0XHR9IGVsc2UgaWYgKCB2YWx1ZS5pc01hdHJpeDMgKSB7XG5cblx0XHRcdC8vIG1hdDMgKGluIFNURDE0MCBhIDN4MyBtYXRyaXggaXMgcmVwcmVzZW50ZWQgYXMgM3g0KVxuXG5cdFx0XHRpbmZvLmJvdW5kYXJ5ID0gNDg7XG5cdFx0XHRpbmZvLnN0b3JhZ2UgPSA0ODtcblxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzTWF0cml4NCApIHtcblxuXHRcdFx0Ly8gbWF0NFxuXG5cdFx0XHRpbmZvLmJvdW5kYXJ5ID0gNjQ7XG5cdFx0XHRpbmZvLnN0b3JhZ2UgPSA2NDtcblxuXHRcdH0gZWxzZSBpZiAoIHZhbHVlLmlzVGV4dHVyZSApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVGV4dHVyZSBzYW1wbGVycyBjYW4gbm90IGJlIHBhcnQgb2YgYW4gdW5pZm9ybXMgZ3JvdXAuJyApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogVW5zdXBwb3J0ZWQgdW5pZm9ybSB2YWx1ZSB0eXBlLicsIHZhbHVlICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gaW5mbztcblxuXHR9XG5cblx0ZnVuY3Rpb24gb25Vbmlmb3Jtc0dyb3Vwc0Rpc3Bvc2UoIGV2ZW50ICkge1xuXG5cdFx0Y29uc3QgdW5pZm9ybXNHcm91cCA9IGV2ZW50LnRhcmdldDtcblxuXHRcdHVuaWZvcm1zR3JvdXAucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Rpc3Bvc2UnLCBvblVuaWZvcm1zR3JvdXBzRGlzcG9zZSApO1xuXG5cdFx0Y29uc3QgaW5kZXggPSBhbGxvY2F0ZWRCaW5kaW5nUG9pbnRzLmluZGV4T2YoIHVuaWZvcm1zR3JvdXAuX19iaW5kaW5nUG9pbnRJbmRleCApO1xuXHRcdGFsbG9jYXRlZEJpbmRpbmdQb2ludHMuc3BsaWNlKCBpbmRleCwgMSApO1xuXG5cdFx0Z2wuZGVsZXRlQnVmZmVyKCBidWZmZXJzWyB1bmlmb3Jtc0dyb3VwLmlkIF0gKTtcblxuXHRcdGRlbGV0ZSBidWZmZXJzWyB1bmlmb3Jtc0dyb3VwLmlkIF07XG5cdFx0ZGVsZXRlIHVwZGF0ZUxpc3RbIHVuaWZvcm1zR3JvdXAuaWQgXTtcblxuXHR9XG5cblx0ZnVuY3Rpb24gZGlzcG9zZSgpIHtcblxuXHRcdGZvciAoIGNvbnN0IGlkIGluIGJ1ZmZlcnMgKSB7XG5cblx0XHRcdGdsLmRlbGV0ZUJ1ZmZlciggYnVmZmVyc1sgaWQgXSApO1xuXG5cdFx0fVxuXG5cdFx0YWxsb2NhdGVkQmluZGluZ1BvaW50cyA9IFtdO1xuXHRcdGJ1ZmZlcnMgPSB7fTtcblx0XHR1cGRhdGVMaXN0ID0ge307XG5cblx0fVxuXG5cdHJldHVybiB7XG5cblx0XHRiaW5kOiBiaW5kLFxuXHRcdHVwZGF0ZTogdXBkYXRlLFxuXG5cdFx0ZGlzcG9zZTogZGlzcG9zZVxuXG5cdH07XG5cbn1cblxuY2xhc3MgV2ViR0xSZW5kZXJlciB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgPSB7fSApIHtcblxuXHRcdGNvbnN0IHtcblx0XHRcdGNhbnZhcyA9IGNyZWF0ZUNhbnZhc0VsZW1lbnQoKSxcblx0XHRcdGNvbnRleHQgPSBudWxsLFxuXHRcdFx0ZGVwdGggPSB0cnVlLFxuXHRcdFx0c3RlbmNpbCA9IGZhbHNlLFxuXHRcdFx0YWxwaGEgPSBmYWxzZSxcblx0XHRcdGFudGlhbGlhcyA9IGZhbHNlLFxuXHRcdFx0cHJlbXVsdGlwbGllZEFscGhhID0gdHJ1ZSxcblx0XHRcdHByZXNlcnZlRHJhd2luZ0J1ZmZlciA9IGZhbHNlLFxuXHRcdFx0cG93ZXJQcmVmZXJlbmNlID0gJ2RlZmF1bHQnLFxuXHRcdFx0ZmFpbElmTWFqb3JQZXJmb3JtYW5jZUNhdmVhdCA9IGZhbHNlLFxuXHRcdH0gPSBwYXJhbWV0ZXJzO1xuXG5cdFx0dGhpcy5pc1dlYkdMUmVuZGVyZXIgPSB0cnVlO1xuXG5cdFx0bGV0IF9hbHBoYTtcblxuXHRcdGlmICggY29udGV4dCAhPT0gbnVsbCApIHtcblxuXHRcdFx0aWYgKCB0eXBlb2YgV2ViR0xSZW5kZXJpbmdDb250ZXh0ICE9PSAndW5kZWZpbmVkJyAmJiBjb250ZXh0IGluc3RhbmNlb2YgV2ViR0xSZW5kZXJpbmdDb250ZXh0ICkge1xuXG5cdFx0XHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IFdlYkdMIDEgaXMgbm90IHN1cHBvcnRlZCBzaW5jZSByMTYzLicgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRfYWxwaGEgPSBjb250ZXh0LmdldENvbnRleHRBdHRyaWJ1dGVzKCkuYWxwaGE7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRfYWxwaGEgPSBhbHBoYTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHVpbnRDbGVhckNvbG9yID0gbmV3IFVpbnQzMkFycmF5KCA0ICk7XG5cdFx0Y29uc3QgaW50Q2xlYXJDb2xvciA9IG5ldyBJbnQzMkFycmF5KCA0ICk7XG5cblx0XHRsZXQgY3VycmVudFJlbmRlckxpc3QgPSBudWxsO1xuXHRcdGxldCBjdXJyZW50UmVuZGVyU3RhdGUgPSBudWxsO1xuXG5cdFx0Ly8gcmVuZGVyKCkgY2FuIGJlIGNhbGxlZCBmcm9tIHdpdGhpbiBhIGNhbGxiYWNrIHRyaWdnZXJlZCBieSBhbm90aGVyIHJlbmRlci5cblx0XHQvLyBXZSB0cmFjayB0aGlzIHNvIHRoYXQgdGhlIG5lc3RlZCByZW5kZXIgY2FsbCBnZXRzIGl0cyBsaXN0IGFuZCBzdGF0ZSBpc29sYXRlZCBmcm9tIHRoZSBwYXJlbnQgcmVuZGVyIGNhbGwuXG5cblx0XHRjb25zdCByZW5kZXJMaXN0U3RhY2sgPSBbXTtcblx0XHRjb25zdCByZW5kZXJTdGF0ZVN0YWNrID0gW107XG5cblx0XHQvLyBwdWJsaWMgcHJvcGVydGllc1xuXG5cdFx0dGhpcy5kb21FbGVtZW50ID0gY2FudmFzO1xuXG5cdFx0Ly8gRGVidWcgY29uZmlndXJhdGlvbiBjb250YWluZXJcblx0XHR0aGlzLmRlYnVnID0ge1xuXG5cdFx0XHQvKipcblx0XHRcdCAqIEVuYWJsZXMgZXJyb3IgY2hlY2tpbmcgYW5kIHJlcG9ydGluZyB3aGVuIHNoYWRlciBwcm9ncmFtcyBhcmUgYmVpbmcgY29tcGlsZWRcblx0XHRcdCAqIEB0eXBlIHtib29sZWFufVxuXHRcdFx0ICovXG5cdFx0XHRjaGVja1NoYWRlckVycm9yczogdHJ1ZSxcblx0XHRcdC8qKlxuXHRcdFx0ICogQ2FsbGJhY2sgZm9yIGN1c3RvbSBlcnJvciByZXBvcnRpbmcuXG5cdFx0XHQgKiBAdHlwZSB7P0Z1bmN0aW9ufVxuXHRcdFx0ICovXG5cdFx0XHRvblNoYWRlckVycm9yOiBudWxsXG5cdFx0fTtcblxuXHRcdC8vIGNsZWFyaW5nXG5cblx0XHR0aGlzLmF1dG9DbGVhciA9IHRydWU7XG5cdFx0dGhpcy5hdXRvQ2xlYXJDb2xvciA9IHRydWU7XG5cdFx0dGhpcy5hdXRvQ2xlYXJEZXB0aCA9IHRydWU7XG5cdFx0dGhpcy5hdXRvQ2xlYXJTdGVuY2lsID0gdHJ1ZTtcblxuXHRcdC8vIHNjZW5lIGdyYXBoXG5cblx0XHR0aGlzLnNvcnRPYmplY3RzID0gdHJ1ZTtcblxuXHRcdC8vIHVzZXItZGVmaW5lZCBjbGlwcGluZ1xuXG5cdFx0dGhpcy5jbGlwcGluZ1BsYW5lcyA9IFtdO1xuXHRcdHRoaXMubG9jYWxDbGlwcGluZ0VuYWJsZWQgPSBmYWxzZTtcblxuXHRcdC8vIHBoeXNpY2FsbHkgYmFzZWQgc2hhZGluZ1xuXG5cdFx0dGhpcy5fb3V0cHV0Q29sb3JTcGFjZSA9IFNSR0JDb2xvclNwYWNlO1xuXG5cdFx0Ly8gdG9uZSBtYXBwaW5nXG5cblx0XHR0aGlzLnRvbmVNYXBwaW5nID0gTm9Ub25lTWFwcGluZztcblx0XHR0aGlzLnRvbmVNYXBwaW5nRXhwb3N1cmUgPSAxLjA7XG5cblx0XHQvLyBpbnRlcm5hbCBwcm9wZXJ0aWVzXG5cblx0XHRjb25zdCBfdGhpcyA9IHRoaXM7XG5cblx0XHRsZXQgX2lzQ29udGV4dExvc3QgPSBmYWxzZTtcblxuXHRcdC8vIGludGVybmFsIHN0YXRlIGNhY2hlXG5cblx0XHRsZXQgX2N1cnJlbnRBY3RpdmVDdWJlRmFjZSA9IDA7XG5cdFx0bGV0IF9jdXJyZW50QWN0aXZlTWlwbWFwTGV2ZWwgPSAwO1xuXHRcdGxldCBfY3VycmVudFJlbmRlclRhcmdldCA9IG51bGw7XG5cdFx0bGV0IF9jdXJyZW50TWF0ZXJpYWxJZCA9IC0gMTtcblxuXHRcdGxldCBfY3VycmVudENhbWVyYSA9IG51bGw7XG5cblx0XHRjb25zdCBfY3VycmVudFZpZXdwb3J0ID0gbmV3IFZlY3RvcjQoKTtcblx0XHRjb25zdCBfY3VycmVudFNjaXNzb3IgPSBuZXcgVmVjdG9yNCgpO1xuXHRcdGxldCBfY3VycmVudFNjaXNzb3JUZXN0ID0gbnVsbDtcblxuXHRcdGNvbnN0IF9jdXJyZW50Q2xlYXJDb2xvciA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcblx0XHRsZXQgX2N1cnJlbnRDbGVhckFscGhhID0gMDtcblxuXHRcdC8vXG5cblx0XHRsZXQgX3dpZHRoID0gY2FudmFzLndpZHRoO1xuXHRcdGxldCBfaGVpZ2h0ID0gY2FudmFzLmhlaWdodDtcblxuXHRcdGxldCBfcGl4ZWxSYXRpbyA9IDE7XG5cdFx0bGV0IF9vcGFxdWVTb3J0ID0gbnVsbDtcblx0XHRsZXQgX3RyYW5zcGFyZW50U29ydCA9IG51bGw7XG5cblx0XHRjb25zdCBfdmlld3BvcnQgPSBuZXcgVmVjdG9yNCggMCwgMCwgX3dpZHRoLCBfaGVpZ2h0ICk7XG5cdFx0Y29uc3QgX3NjaXNzb3IgPSBuZXcgVmVjdG9yNCggMCwgMCwgX3dpZHRoLCBfaGVpZ2h0ICk7XG5cdFx0bGV0IF9zY2lzc29yVGVzdCA9IGZhbHNlO1xuXG5cdFx0Ly8gZnJ1c3R1bVxuXG5cdFx0Y29uc3QgX2ZydXN0dW0gPSBuZXcgRnJ1c3R1bSgpO1xuXG5cdFx0Ly8gY2xpcHBpbmdcblxuXHRcdGxldCBfY2xpcHBpbmdFbmFibGVkID0gZmFsc2U7XG5cdFx0bGV0IF9sb2NhbENsaXBwaW5nRW5hYmxlZCA9IGZhbHNlO1xuXG5cdFx0Ly8gY2FtZXJhIG1hdHJpY2VzIGNhY2hlXG5cblx0XHRjb25zdCBfcHJvalNjcmVlbk1hdHJpeCA9IG5ldyBNYXRyaXg0KCk7XG5cblx0XHRjb25zdCBfdmVjdG9yMyA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRjb25zdCBfdmVjdG9yNCA9IG5ldyBWZWN0b3I0KCk7XG5cblx0XHRjb25zdCBfZW1wdHlTY2VuZSA9IHsgYmFja2dyb3VuZDogbnVsbCwgZm9nOiBudWxsLCBlbnZpcm9ubWVudDogbnVsbCwgb3ZlcnJpZGVNYXRlcmlhbDogbnVsbCwgaXNTY2VuZTogdHJ1ZSB9O1xuXG5cdFx0bGV0IF9yZW5kZXJCYWNrZ3JvdW5kID0gZmFsc2U7XG5cblx0XHRmdW5jdGlvbiBnZXRUYXJnZXRQaXhlbFJhdGlvKCkge1xuXG5cdFx0XHRyZXR1cm4gX2N1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgPyBfcGl4ZWxSYXRpbyA6IDE7XG5cblx0XHR9XG5cblx0XHQvLyBpbml0aWFsaXplXG5cblx0XHRsZXQgX2dsID0gY29udGV4dDtcblxuXHRcdGZ1bmN0aW9uIGdldENvbnRleHQoIGNvbnRleHROYW1lLCBjb250ZXh0QXR0cmlidXRlcyApIHtcblxuXHRcdFx0cmV0dXJuIGNhbnZhcy5nZXRDb250ZXh0KCBjb250ZXh0TmFtZSwgY29udGV4dEF0dHJpYnV0ZXMgKTtcblxuXHRcdH1cblxuXHRcdHRyeSB7XG5cblx0XHRcdGNvbnN0IGNvbnRleHRBdHRyaWJ1dGVzID0ge1xuXHRcdFx0XHRhbHBoYTogdHJ1ZSxcblx0XHRcdFx0ZGVwdGgsXG5cdFx0XHRcdHN0ZW5jaWwsXG5cdFx0XHRcdGFudGlhbGlhcyxcblx0XHRcdFx0cHJlbXVsdGlwbGllZEFscGhhLFxuXHRcdFx0XHRwcmVzZXJ2ZURyYXdpbmdCdWZmZXIsXG5cdFx0XHRcdHBvd2VyUHJlZmVyZW5jZSxcblx0XHRcdFx0ZmFpbElmTWFqb3JQZXJmb3JtYW5jZUNhdmVhdCxcblx0XHRcdH07XG5cblx0XHRcdC8vIE9mZnNjcmVlbkNhbnZhcyBkb2VzIG5vdCBoYXZlIHNldEF0dHJpYnV0ZSwgc2VlICMyMjgxMVxuXHRcdFx0aWYgKCAnc2V0QXR0cmlidXRlJyBpbiBjYW52YXMgKSBjYW52YXMuc2V0QXR0cmlidXRlKCAnZGF0YS1lbmdpbmUnLCBgdGhyZWUuanMgciR7UkVWSVNJT059YCApO1xuXG5cdFx0XHQvLyBldmVudCBsaXN0ZW5lcnMgbXVzdCBiZSByZWdpc3RlcmVkIGJlZm9yZSBXZWJHTCBjb250ZXh0IGlzIGNyZWF0ZWQsIHNlZSAjMTI3NTNcblx0XHRcdGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCAnd2ViZ2xjb250ZXh0bG9zdCcsIG9uQ29udGV4dExvc3QsIGZhbHNlICk7XG5cdFx0XHRjYW52YXMuYWRkRXZlbnRMaXN0ZW5lciggJ3dlYmdsY29udGV4dHJlc3RvcmVkJywgb25Db250ZXh0UmVzdG9yZSwgZmFsc2UgKTtcblx0XHRcdGNhbnZhcy5hZGRFdmVudExpc3RlbmVyKCAnd2ViZ2xjb250ZXh0Y3JlYXRpb25lcnJvcicsIG9uQ29udGV4dENyZWF0aW9uRXJyb3IsIGZhbHNlICk7XG5cblx0XHRcdGlmICggX2dsID09PSBudWxsICkge1xuXG5cdFx0XHRcdGNvbnN0IGNvbnRleHROYW1lID0gJ3dlYmdsMic7XG5cblx0XHRcdFx0X2dsID0gZ2V0Q29udGV4dCggY29udGV4dE5hbWUsIGNvbnRleHRBdHRyaWJ1dGVzICk7XG5cblx0XHRcdFx0aWYgKCBfZ2wgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRpZiAoIGdldENvbnRleHQoIGNvbnRleHROYW1lICkgKSB7XG5cblx0XHRcdFx0XHRcdHRocm93IG5ldyBFcnJvciggJ0Vycm9yIGNyZWF0aW5nIFdlYkdMIGNvbnRleHQgd2l0aCB5b3VyIHNlbGVjdGVkIGF0dHJpYnV0ZXMuJyApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnRXJyb3IgY3JlYXRpbmcgV2ViR0wgY29udGV4dC4nICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9IGNhdGNoICggZXJyb3IgKSB7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyOiAnICsgZXJyb3IubWVzc2FnZSApO1xuXHRcdFx0dGhyb3cgZXJyb3I7XG5cblx0XHR9XG5cblx0XHRsZXQgZXh0ZW5zaW9ucywgY2FwYWJpbGl0aWVzLCBzdGF0ZSwgaW5mbztcblx0XHRsZXQgcHJvcGVydGllcywgdGV4dHVyZXMsIGN1YmVtYXBzLCBjdWJldXZtYXBzLCBhdHRyaWJ1dGVzLCBnZW9tZXRyaWVzLCBvYmplY3RzO1xuXHRcdGxldCBwcm9ncmFtQ2FjaGUsIG1hdGVyaWFscywgcmVuZGVyTGlzdHMsIHJlbmRlclN0YXRlcywgY2xpcHBpbmcsIHNoYWRvd01hcDtcblxuXHRcdGxldCBiYWNrZ3JvdW5kLCBtb3JwaHRhcmdldHMsIGJ1ZmZlclJlbmRlcmVyLCBpbmRleGVkQnVmZmVyUmVuZGVyZXI7XG5cblx0XHRsZXQgdXRpbHMsIGJpbmRpbmdTdGF0ZXMsIHVuaWZvcm1zR3JvdXBzO1xuXG5cdFx0ZnVuY3Rpb24gaW5pdEdMQ29udGV4dCgpIHtcblxuXHRcdFx0ZXh0ZW5zaW9ucyA9IG5ldyBXZWJHTEV4dGVuc2lvbnMoIF9nbCApO1xuXHRcdFx0ZXh0ZW5zaW9ucy5pbml0KCk7XG5cblx0XHRcdHV0aWxzID0gbmV3IFdlYkdMVXRpbHMoIF9nbCwgZXh0ZW5zaW9ucyApO1xuXG5cdFx0XHRjYXBhYmlsaXRpZXMgPSBuZXcgV2ViR0xDYXBhYmlsaXRpZXMoIF9nbCwgZXh0ZW5zaW9ucywgcGFyYW1ldGVycywgdXRpbHMgKTtcblxuXHRcdFx0c3RhdGUgPSBuZXcgV2ViR0xTdGF0ZSggX2dsICk7XG5cblx0XHRcdGluZm8gPSBuZXcgV2ViR0xJbmZvKCBfZ2wgKTtcblx0XHRcdHByb3BlcnRpZXMgPSBuZXcgV2ViR0xQcm9wZXJ0aWVzKCk7XG5cdFx0XHR0ZXh0dXJlcyA9IG5ldyBXZWJHTFRleHR1cmVzKCBfZ2wsIGV4dGVuc2lvbnMsIHN0YXRlLCBwcm9wZXJ0aWVzLCBjYXBhYmlsaXRpZXMsIHV0aWxzLCBpbmZvICk7XG5cdFx0XHRjdWJlbWFwcyA9IG5ldyBXZWJHTEN1YmVNYXBzKCBfdGhpcyApO1xuXHRcdFx0Y3ViZXV2bWFwcyA9IG5ldyBXZWJHTEN1YmVVVk1hcHMoIF90aGlzICk7XG5cdFx0XHRhdHRyaWJ1dGVzID0gbmV3IFdlYkdMQXR0cmlidXRlcyggX2dsICk7XG5cdFx0XHRiaW5kaW5nU3RhdGVzID0gbmV3IFdlYkdMQmluZGluZ1N0YXRlcyggX2dsLCBhdHRyaWJ1dGVzICk7XG5cdFx0XHRnZW9tZXRyaWVzID0gbmV3IFdlYkdMR2VvbWV0cmllcyggX2dsLCBhdHRyaWJ1dGVzLCBpbmZvLCBiaW5kaW5nU3RhdGVzICk7XG5cdFx0XHRvYmplY3RzID0gbmV3IFdlYkdMT2JqZWN0cyggX2dsLCBnZW9tZXRyaWVzLCBhdHRyaWJ1dGVzLCBpbmZvICk7XG5cdFx0XHRtb3JwaHRhcmdldHMgPSBuZXcgV2ViR0xNb3JwaHRhcmdldHMoIF9nbCwgY2FwYWJpbGl0aWVzLCB0ZXh0dXJlcyApO1xuXHRcdFx0Y2xpcHBpbmcgPSBuZXcgV2ViR0xDbGlwcGluZyggcHJvcGVydGllcyApO1xuXHRcdFx0cHJvZ3JhbUNhY2hlID0gbmV3IFdlYkdMUHJvZ3JhbXMoIF90aGlzLCBjdWJlbWFwcywgY3ViZXV2bWFwcywgZXh0ZW5zaW9ucywgY2FwYWJpbGl0aWVzLCBiaW5kaW5nU3RhdGVzLCBjbGlwcGluZyApO1xuXHRcdFx0bWF0ZXJpYWxzID0gbmV3IFdlYkdMTWF0ZXJpYWxzKCBfdGhpcywgcHJvcGVydGllcyApO1xuXHRcdFx0cmVuZGVyTGlzdHMgPSBuZXcgV2ViR0xSZW5kZXJMaXN0cygpO1xuXHRcdFx0cmVuZGVyU3RhdGVzID0gbmV3IFdlYkdMUmVuZGVyU3RhdGVzKCBleHRlbnNpb25zICk7XG5cdFx0XHRiYWNrZ3JvdW5kID0gbmV3IFdlYkdMQmFja2dyb3VuZCggX3RoaXMsIGN1YmVtYXBzLCBjdWJldXZtYXBzLCBzdGF0ZSwgb2JqZWN0cywgX2FscGhhLCBwcmVtdWx0aXBsaWVkQWxwaGEgKTtcblx0XHRcdHNoYWRvd01hcCA9IG5ldyBXZWJHTFNoYWRvd01hcCggX3RoaXMsIG9iamVjdHMsIGNhcGFiaWxpdGllcyApO1xuXHRcdFx0dW5pZm9ybXNHcm91cHMgPSBuZXcgV2ViR0xVbmlmb3Jtc0dyb3VwcyggX2dsLCBpbmZvLCBjYXBhYmlsaXRpZXMsIHN0YXRlICk7XG5cblx0XHRcdGJ1ZmZlclJlbmRlcmVyID0gbmV3IFdlYkdMQnVmZmVyUmVuZGVyZXIoIF9nbCwgZXh0ZW5zaW9ucywgaW5mbyApO1xuXHRcdFx0aW5kZXhlZEJ1ZmZlclJlbmRlcmVyID0gbmV3IFdlYkdMSW5kZXhlZEJ1ZmZlclJlbmRlcmVyKCBfZ2wsIGV4dGVuc2lvbnMsIGluZm8gKTtcblxuXHRcdFx0aW5mby5wcm9ncmFtcyA9IHByb2dyYW1DYWNoZS5wcm9ncmFtcztcblxuXHRcdFx0X3RoaXMuY2FwYWJpbGl0aWVzID0gY2FwYWJpbGl0aWVzO1xuXHRcdFx0X3RoaXMuZXh0ZW5zaW9ucyA9IGV4dGVuc2lvbnM7XG5cdFx0XHRfdGhpcy5wcm9wZXJ0aWVzID0gcHJvcGVydGllcztcblx0XHRcdF90aGlzLnJlbmRlckxpc3RzID0gcmVuZGVyTGlzdHM7XG5cdFx0XHRfdGhpcy5zaGFkb3dNYXAgPSBzaGFkb3dNYXA7XG5cdFx0XHRfdGhpcy5zdGF0ZSA9IHN0YXRlO1xuXHRcdFx0X3RoaXMuaW5mbyA9IGluZm87XG5cblx0XHR9XG5cblx0XHRpbml0R0xDb250ZXh0KCk7XG5cblx0XHQvLyB4clxuXG5cdFx0Y29uc3QgeHIgPSBuZXcgV2ViWFJNYW5hZ2VyKCBfdGhpcywgX2dsICk7XG5cblx0XHR0aGlzLnhyID0geHI7XG5cblx0XHQvLyBBUElcblxuXHRcdHRoaXMuZ2V0Q29udGV4dCA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIF9nbDtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldENvbnRleHRBdHRyaWJ1dGVzID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gX2dsLmdldENvbnRleHRBdHRyaWJ1dGVzKCk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5mb3JjZUNvbnRleHRMb3NzID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRjb25zdCBleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ1dFQkdMX2xvc2VfY29udGV4dCcgKTtcblx0XHRcdGlmICggZXh0ZW5zaW9uICkgZXh0ZW5zaW9uLmxvc2VDb250ZXh0KCk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5mb3JjZUNvbnRleHRSZXN0b3JlID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRjb25zdCBleHRlbnNpb24gPSBleHRlbnNpb25zLmdldCggJ1dFQkdMX2xvc2VfY29udGV4dCcgKTtcblx0XHRcdGlmICggZXh0ZW5zaW9uICkgZXh0ZW5zaW9uLnJlc3RvcmVDb250ZXh0KCk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRQaXhlbFJhdGlvID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gX3BpeGVsUmF0aW87XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5zZXRQaXhlbFJhdGlvID0gZnVuY3Rpb24gKCB2YWx1ZSApIHtcblxuXHRcdFx0aWYgKCB2YWx1ZSA9PT0gdW5kZWZpbmVkICkgcmV0dXJuO1xuXG5cdFx0XHRfcGl4ZWxSYXRpbyA9IHZhbHVlO1xuXG5cdFx0XHR0aGlzLnNldFNpemUoIF93aWR0aCwgX2hlaWdodCwgZmFsc2UgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldFNpemUgPSBmdW5jdGlvbiAoIHRhcmdldCApIHtcblxuXHRcdFx0cmV0dXJuIHRhcmdldC5zZXQoIF93aWR0aCwgX2hlaWdodCApO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0U2l6ZSA9IGZ1bmN0aW9uICggd2lkdGgsIGhlaWdodCwgdXBkYXRlU3R5bGUgPSB0cnVlICkge1xuXG5cdFx0XHRpZiAoIHhyLmlzUHJlc2VudGluZyApIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5XZWJHTFJlbmRlcmVyOiBDYW5cXCd0IGNoYW5nZSBzaXplIHdoaWxlIFZSIGRldmljZSBpcyBwcmVzZW50aW5nLicgKTtcblx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHR9XG5cblx0XHRcdF93aWR0aCA9IHdpZHRoO1xuXHRcdFx0X2hlaWdodCA9IGhlaWdodDtcblxuXHRcdFx0Y2FudmFzLndpZHRoID0gTWF0aC5mbG9vciggd2lkdGggKiBfcGl4ZWxSYXRpbyApO1xuXHRcdFx0Y2FudmFzLmhlaWdodCA9IE1hdGguZmxvb3IoIGhlaWdodCAqIF9waXhlbFJhdGlvICk7XG5cblx0XHRcdGlmICggdXBkYXRlU3R5bGUgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0Y2FudmFzLnN0eWxlLndpZHRoID0gd2lkdGggKyAncHgnO1xuXHRcdFx0XHRjYW52YXMuc3R5bGUuaGVpZ2h0ID0gaGVpZ2h0ICsgJ3B4JztcblxuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLnNldFZpZXdwb3J0KCAwLCAwLCB3aWR0aCwgaGVpZ2h0ICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXREcmF3aW5nQnVmZmVyU2l6ZSA9IGZ1bmN0aW9uICggdGFyZ2V0ICkge1xuXG5cdFx0XHRyZXR1cm4gdGFyZ2V0LnNldCggX3dpZHRoICogX3BpeGVsUmF0aW8sIF9oZWlnaHQgKiBfcGl4ZWxSYXRpbyApLmZsb29yKCk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5zZXREcmF3aW5nQnVmZmVyU2l6ZSA9IGZ1bmN0aW9uICggd2lkdGgsIGhlaWdodCwgcGl4ZWxSYXRpbyApIHtcblxuXHRcdFx0X3dpZHRoID0gd2lkdGg7XG5cdFx0XHRfaGVpZ2h0ID0gaGVpZ2h0O1xuXG5cdFx0XHRfcGl4ZWxSYXRpbyA9IHBpeGVsUmF0aW87XG5cblx0XHRcdGNhbnZhcy53aWR0aCA9IE1hdGguZmxvb3IoIHdpZHRoICogcGl4ZWxSYXRpbyApO1xuXHRcdFx0Y2FudmFzLmhlaWdodCA9IE1hdGguZmxvb3IoIGhlaWdodCAqIHBpeGVsUmF0aW8gKTtcblxuXHRcdFx0dGhpcy5zZXRWaWV3cG9ydCggMCwgMCwgd2lkdGgsIGhlaWdodCApO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0Q3VycmVudFZpZXdwb3J0ID0gZnVuY3Rpb24gKCB0YXJnZXQgKSB7XG5cblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggX2N1cnJlbnRWaWV3cG9ydCApO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0Vmlld3BvcnQgPSBmdW5jdGlvbiAoIHRhcmdldCApIHtcblxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBfdmlld3BvcnQgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldFZpZXdwb3J0ID0gZnVuY3Rpb24gKCB4LCB5LCB3aWR0aCwgaGVpZ2h0ICkge1xuXG5cdFx0XHRpZiAoIHguaXNWZWN0b3I0ICkge1xuXG5cdFx0XHRcdF92aWV3cG9ydC5zZXQoIHgueCwgeC55LCB4LnosIHgudyApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdF92aWV3cG9ydC5zZXQoIHgsIHksIHdpZHRoLCBoZWlnaHQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRzdGF0ZS52aWV3cG9ydCggX2N1cnJlbnRWaWV3cG9ydC5jb3B5KCBfdmlld3BvcnQgKS5tdWx0aXBseVNjYWxhciggX3BpeGVsUmF0aW8gKS5yb3VuZCgpICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRTY2lzc29yID0gZnVuY3Rpb24gKCB0YXJnZXQgKSB7XG5cblx0XHRcdHJldHVybiB0YXJnZXQuY29weSggX3NjaXNzb3IgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldFNjaXNzb3IgPSBmdW5jdGlvbiAoIHgsIHksIHdpZHRoLCBoZWlnaHQgKSB7XG5cblx0XHRcdGlmICggeC5pc1ZlY3RvcjQgKSB7XG5cblx0XHRcdFx0X3NjaXNzb3Iuc2V0KCB4LngsIHgueSwgeC56LCB4LncgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRfc2Npc3Nvci5zZXQoIHgsIHksIHdpZHRoLCBoZWlnaHQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRzdGF0ZS5zY2lzc29yKCBfY3VycmVudFNjaXNzb3IuY29weSggX3NjaXNzb3IgKS5tdWx0aXBseVNjYWxhciggX3BpeGVsUmF0aW8gKS5yb3VuZCgpICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRTY2lzc29yVGVzdCA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIF9zY2lzc29yVGVzdDtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldFNjaXNzb3JUZXN0ID0gZnVuY3Rpb24gKCBib29sZWFuICkge1xuXG5cdFx0XHRzdGF0ZS5zZXRTY2lzc29yVGVzdCggX3NjaXNzb3JUZXN0ID0gYm9vbGVhbiApO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0T3BhcXVlU29ydCA9IGZ1bmN0aW9uICggbWV0aG9kICkge1xuXG5cdFx0XHRfb3BhcXVlU29ydCA9IG1ldGhvZDtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldFRyYW5zcGFyZW50U29ydCA9IGZ1bmN0aW9uICggbWV0aG9kICkge1xuXG5cdFx0XHRfdHJhbnNwYXJlbnRTb3J0ID0gbWV0aG9kO1xuXG5cdFx0fTtcblxuXHRcdC8vIENsZWFyaW5nXG5cblx0XHR0aGlzLmdldENsZWFyQ29sb3IgPSBmdW5jdGlvbiAoIHRhcmdldCApIHtcblxuXHRcdFx0cmV0dXJuIHRhcmdldC5jb3B5KCBiYWNrZ3JvdW5kLmdldENsZWFyQ29sb3IoKSApO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0Q2xlYXJDb2xvciA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0YmFja2dyb3VuZC5zZXRDbGVhckNvbG9yLmFwcGx5KCBiYWNrZ3JvdW5kLCBhcmd1bWVudHMgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldENsZWFyQWxwaGEgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBiYWNrZ3JvdW5kLmdldENsZWFyQWxwaGEoKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLnNldENsZWFyQWxwaGEgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdGJhY2tncm91bmQuc2V0Q2xlYXJBbHBoYS5hcHBseSggYmFja2dyb3VuZCwgYXJndW1lbnRzICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5jbGVhciA9IGZ1bmN0aW9uICggY29sb3IgPSB0cnVlLCBkZXB0aCA9IHRydWUsIHN0ZW5jaWwgPSB0cnVlICkge1xuXG5cdFx0XHRsZXQgYml0cyA9IDA7XG5cblx0XHRcdGlmICggY29sb3IgKSB7XG5cblx0XHRcdFx0Ly8gY2hlY2sgaWYgd2UncmUgdHJ5aW5nIHRvIGNsZWFyIGFuIGludGVnZXIgdGFyZ2V0XG5cdFx0XHRcdGxldCBpc0ludGVnZXJGb3JtYXQgPSBmYWxzZTtcblx0XHRcdFx0aWYgKCBfY3VycmVudFJlbmRlclRhcmdldCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdGNvbnN0IHRhcmdldEZvcm1hdCA9IF9jdXJyZW50UmVuZGVyVGFyZ2V0LnRleHR1cmUuZm9ybWF0O1xuXHRcdFx0XHRcdGlzSW50ZWdlckZvcm1hdCA9IHRhcmdldEZvcm1hdCA9PT0gUkdCQUludGVnZXJGb3JtYXQgfHxcblx0XHRcdFx0XHRcdHRhcmdldEZvcm1hdCA9PT0gUkdJbnRlZ2VyRm9ybWF0IHx8XG5cdFx0XHRcdFx0XHR0YXJnZXRGb3JtYXQgPT09IFJlZEludGVnZXJGb3JtYXQ7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIHVzZSB0aGUgYXBwcm9wcmlhdGUgY2xlYXIgZnVuY3Rpb25zIHRvIGNsZWFyIHRoZSB0YXJnZXQgaWYgaXQncyBhIHNpZ25lZFxuXHRcdFx0XHQvLyBvciB1bnNpZ25lZCBpbnRlZ2VyIHRhcmdldFxuXHRcdFx0XHRpZiAoIGlzSW50ZWdlckZvcm1hdCApIHtcblxuXHRcdFx0XHRcdGNvbnN0IHRhcmdldFR5cGUgPSBfY3VycmVudFJlbmRlclRhcmdldC50ZXh0dXJlLnR5cGU7XG5cdFx0XHRcdFx0Y29uc3QgaXNVbnNpZ25lZFR5cGUgPSB0YXJnZXRUeXBlID09PSBVbnNpZ25lZEJ5dGVUeXBlIHx8XG5cdFx0XHRcdFx0XHR0YXJnZXRUeXBlID09PSBVbnNpZ25lZEludFR5cGUgfHxcblx0XHRcdFx0XHRcdHRhcmdldFR5cGUgPT09IFVuc2lnbmVkU2hvcnRUeXBlIHx8XG5cdFx0XHRcdFx0XHR0YXJnZXRUeXBlID09PSBVbnNpZ25lZEludDI0OFR5cGUgfHxcblx0XHRcdFx0XHRcdHRhcmdldFR5cGUgPT09IFVuc2lnbmVkU2hvcnQ0NDQ0VHlwZSB8fFxuXHRcdFx0XHRcdFx0dGFyZ2V0VHlwZSA9PT0gVW5zaWduZWRTaG9ydDU1NTFUeXBlO1xuXG5cdFx0XHRcdFx0Y29uc3QgY2xlYXJDb2xvciA9IGJhY2tncm91bmQuZ2V0Q2xlYXJDb2xvcigpO1xuXHRcdFx0XHRcdGNvbnN0IGEgPSBiYWNrZ3JvdW5kLmdldENsZWFyQWxwaGEoKTtcblx0XHRcdFx0XHRjb25zdCByID0gY2xlYXJDb2xvci5yO1xuXHRcdFx0XHRcdGNvbnN0IGcgPSBjbGVhckNvbG9yLmc7XG5cdFx0XHRcdFx0Y29uc3QgYiA9IGNsZWFyQ29sb3IuYjtcblxuXHRcdFx0XHRcdGlmICggaXNVbnNpZ25lZFR5cGUgKSB7XG5cblx0XHRcdFx0XHRcdHVpbnRDbGVhckNvbG9yWyAwIF0gPSByO1xuXHRcdFx0XHRcdFx0dWludENsZWFyQ29sb3JbIDEgXSA9IGc7XG5cdFx0XHRcdFx0XHR1aW50Q2xlYXJDb2xvclsgMiBdID0gYjtcblx0XHRcdFx0XHRcdHVpbnRDbGVhckNvbG9yWyAzIF0gPSBhO1xuXHRcdFx0XHRcdFx0X2dsLmNsZWFyQnVmZmVydWl2KCBfZ2wuQ09MT1IsIDAsIHVpbnRDbGVhckNvbG9yICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRpbnRDbGVhckNvbG9yWyAwIF0gPSByO1xuXHRcdFx0XHRcdFx0aW50Q2xlYXJDb2xvclsgMSBdID0gZztcblx0XHRcdFx0XHRcdGludENsZWFyQ29sb3JbIDIgXSA9IGI7XG5cdFx0XHRcdFx0XHRpbnRDbGVhckNvbG9yWyAzIF0gPSBhO1xuXHRcdFx0XHRcdFx0X2dsLmNsZWFyQnVmZmVyaXYoIF9nbC5DT0xPUiwgMCwgaW50Q2xlYXJDb2xvciApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRiaXRzIHw9IF9nbC5DT0xPUl9CVUZGRVJfQklUO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGRlcHRoICkgYml0cyB8PSBfZ2wuREVQVEhfQlVGRkVSX0JJVDtcblx0XHRcdGlmICggc3RlbmNpbCApIHtcblxuXHRcdFx0XHRiaXRzIHw9IF9nbC5TVEVOQ0lMX0JVRkZFUl9CSVQ7XG5cdFx0XHRcdHRoaXMuc3RhdGUuYnVmZmVycy5zdGVuY2lsLnNldE1hc2soIDB4ZmZmZmZmZmYgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRfZ2wuY2xlYXIoIGJpdHMgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmNsZWFyQ29sb3IgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHRoaXMuY2xlYXIoIHRydWUsIGZhbHNlLCBmYWxzZSApO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuY2xlYXJEZXB0aCA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0dGhpcy5jbGVhciggZmFsc2UsIHRydWUsIGZhbHNlICk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5jbGVhclN0ZW5jaWwgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHRoaXMuY2xlYXIoIGZhbHNlLCBmYWxzZSwgdHJ1ZSApO1xuXG5cdFx0fTtcblxuXHRcdC8vXG5cblx0XHR0aGlzLmRpc3Bvc2UgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdGNhbnZhcy5yZW1vdmVFdmVudExpc3RlbmVyKCAnd2ViZ2xjb250ZXh0bG9zdCcsIG9uQ29udGV4dExvc3QsIGZhbHNlICk7XG5cdFx0XHRjYW52YXMucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3dlYmdsY29udGV4dHJlc3RvcmVkJywgb25Db250ZXh0UmVzdG9yZSwgZmFsc2UgKTtcblx0XHRcdGNhbnZhcy5yZW1vdmVFdmVudExpc3RlbmVyKCAnd2ViZ2xjb250ZXh0Y3JlYXRpb25lcnJvcicsIG9uQ29udGV4dENyZWF0aW9uRXJyb3IsIGZhbHNlICk7XG5cblx0XHRcdHJlbmRlckxpc3RzLmRpc3Bvc2UoKTtcblx0XHRcdHJlbmRlclN0YXRlcy5kaXNwb3NlKCk7XG5cdFx0XHRwcm9wZXJ0aWVzLmRpc3Bvc2UoKTtcblx0XHRcdGN1YmVtYXBzLmRpc3Bvc2UoKTtcblx0XHRcdGN1YmV1dm1hcHMuZGlzcG9zZSgpO1xuXHRcdFx0b2JqZWN0cy5kaXNwb3NlKCk7XG5cdFx0XHRiaW5kaW5nU3RhdGVzLmRpc3Bvc2UoKTtcblx0XHRcdHVuaWZvcm1zR3JvdXBzLmRpc3Bvc2UoKTtcblx0XHRcdHByb2dyYW1DYWNoZS5kaXNwb3NlKCk7XG5cblx0XHRcdHhyLmRpc3Bvc2UoKTtcblxuXHRcdFx0eHIucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3Nlc3Npb25zdGFydCcsIG9uWFJTZXNzaW9uU3RhcnQgKTtcblx0XHRcdHhyLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdzZXNzaW9uZW5kJywgb25YUlNlc3Npb25FbmQgKTtcblxuXHRcdFx0YW5pbWF0aW9uLnN0b3AoKTtcblxuXHRcdH07XG5cblx0XHQvLyBFdmVudHNcblxuXHRcdGZ1bmN0aW9uIG9uQ29udGV4dExvc3QoIGV2ZW50ICkge1xuXG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0XHRjb25zb2xlLmxvZyggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IENvbnRleHQgTG9zdC4nICk7XG5cblx0XHRcdF9pc0NvbnRleHRMb3N0ID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uQ29udGV4dFJlc3RvcmUoIC8qIGV2ZW50ICovICkge1xuXG5cdFx0XHRjb25zb2xlLmxvZyggJ1RIUkVFLldlYkdMUmVuZGVyZXI6IENvbnRleHQgUmVzdG9yZWQuJyApO1xuXG5cdFx0XHRfaXNDb250ZXh0TG9zdCA9IGZhbHNlO1xuXG5cdFx0XHRjb25zdCBpbmZvQXV0b1Jlc2V0ID0gaW5mby5hdXRvUmVzZXQ7XG5cdFx0XHRjb25zdCBzaGFkb3dNYXBFbmFibGVkID0gc2hhZG93TWFwLmVuYWJsZWQ7XG5cdFx0XHRjb25zdCBzaGFkb3dNYXBBdXRvVXBkYXRlID0gc2hhZG93TWFwLmF1dG9VcGRhdGU7XG5cdFx0XHRjb25zdCBzaGFkb3dNYXBOZWVkc1VwZGF0ZSA9IHNoYWRvd01hcC5uZWVkc1VwZGF0ZTtcblx0XHRcdGNvbnN0IHNoYWRvd01hcFR5cGUgPSBzaGFkb3dNYXAudHlwZTtcblxuXHRcdFx0aW5pdEdMQ29udGV4dCgpO1xuXG5cdFx0XHRpbmZvLmF1dG9SZXNldCA9IGluZm9BdXRvUmVzZXQ7XG5cdFx0XHRzaGFkb3dNYXAuZW5hYmxlZCA9IHNoYWRvd01hcEVuYWJsZWQ7XG5cdFx0XHRzaGFkb3dNYXAuYXV0b1VwZGF0ZSA9IHNoYWRvd01hcEF1dG9VcGRhdGU7XG5cdFx0XHRzaGFkb3dNYXAubmVlZHNVcGRhdGUgPSBzaGFkb3dNYXBOZWVkc1VwZGF0ZTtcblx0XHRcdHNoYWRvd01hcC50eXBlID0gc2hhZG93TWFwVHlwZTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uQ29udGV4dENyZWF0aW9uRXJyb3IoIGV2ZW50ICkge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogQSBXZWJHTCBjb250ZXh0IGNvdWxkIG5vdCBiZSBjcmVhdGVkLiBSZWFzb246ICcsIGV2ZW50LnN0YXR1c01lc3NhZ2UgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uTWF0ZXJpYWxEaXNwb3NlKCBldmVudCApIHtcblxuXHRcdFx0Y29uc3QgbWF0ZXJpYWwgPSBldmVudC50YXJnZXQ7XG5cblx0XHRcdG1hdGVyaWFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25NYXRlcmlhbERpc3Bvc2UgKTtcblxuXHRcdFx0ZGVhbGxvY2F0ZU1hdGVyaWFsKCBtYXRlcmlhbCApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gQnVmZmVyIGRlYWxsb2NhdGlvblxuXG5cdFx0ZnVuY3Rpb24gZGVhbGxvY2F0ZU1hdGVyaWFsKCBtYXRlcmlhbCApIHtcblxuXHRcdFx0cmVsZWFzZU1hdGVyaWFsUHJvZ3JhbVJlZmVyZW5jZXMoIG1hdGVyaWFsICk7XG5cblx0XHRcdHByb3BlcnRpZXMucmVtb3ZlKCBtYXRlcmlhbCApO1xuXG5cdFx0fVxuXG5cblx0XHRmdW5jdGlvbiByZWxlYXNlTWF0ZXJpYWxQcm9ncmFtUmVmZXJlbmNlcyggbWF0ZXJpYWwgKSB7XG5cblx0XHRcdGNvbnN0IHByb2dyYW1zID0gcHJvcGVydGllcy5nZXQoIG1hdGVyaWFsICkucHJvZ3JhbXM7XG5cblx0XHRcdGlmICggcHJvZ3JhbXMgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRwcm9ncmFtcy5mb3JFYWNoKCBmdW5jdGlvbiAoIHByb2dyYW0gKSB7XG5cblx0XHRcdFx0XHRwcm9ncmFtQ2FjaGUucmVsZWFzZVByb2dyYW0oIHByb2dyYW0gKTtcblxuXHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0aWYgKCBtYXRlcmlhbC5pc1NoYWRlck1hdGVyaWFsICkge1xuXG5cdFx0XHRcdFx0cHJvZ3JhbUNhY2hlLnJlbGVhc2VTaGFkZXJDYWNoZSggbWF0ZXJpYWwgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIEJ1ZmZlciByZW5kZXJpbmdcblxuXHRcdHRoaXMucmVuZGVyQnVmZmVyRGlyZWN0ID0gZnVuY3Rpb24gKCBjYW1lcmEsIHNjZW5lLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIG9iamVjdCwgZ3JvdXAgKSB7XG5cblx0XHRcdGlmICggc2NlbmUgPT09IG51bGwgKSBzY2VuZSA9IF9lbXB0eVNjZW5lOyAvLyByZW5kZXJCdWZmZXJEaXJlY3Qgc2Vjb25kIHBhcmFtZXRlciB1c2VkIHRvIGJlIGZvZyAoY291bGQgYmUgbnVsbClcblxuXHRcdFx0Y29uc3QgZnJvbnRGYWNlQ1cgPSAoIG9iamVjdC5pc01lc2ggJiYgb2JqZWN0Lm1hdHJpeFdvcmxkLmRldGVybWluYW50KCkgPCAwICk7XG5cblx0XHRcdGNvbnN0IHByb2dyYW0gPSBzZXRQcm9ncmFtKCBjYW1lcmEsIHNjZW5lLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIG9iamVjdCApO1xuXG5cdFx0XHRzdGF0ZS5zZXRNYXRlcmlhbCggbWF0ZXJpYWwsIGZyb250RmFjZUNXICk7XG5cblx0XHRcdC8vXG5cblx0XHRcdGxldCBpbmRleCA9IGdlb21ldHJ5LmluZGV4O1xuXHRcdFx0bGV0IHJhbmdlRmFjdG9yID0gMTtcblxuXHRcdFx0aWYgKCBtYXRlcmlhbC53aXJlZnJhbWUgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0aW5kZXggPSBnZW9tZXRyaWVzLmdldFdpcmVmcmFtZUF0dHJpYnV0ZSggZ2VvbWV0cnkgKTtcblxuXHRcdFx0XHRpZiAoIGluZGV4ID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHRcdFx0cmFuZ2VGYWN0b3IgPSAyO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vXG5cblx0XHRcdGNvbnN0IGRyYXdSYW5nZSA9IGdlb21ldHJ5LmRyYXdSYW5nZTtcblx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcblxuXHRcdFx0bGV0IGRyYXdTdGFydCA9IGRyYXdSYW5nZS5zdGFydCAqIHJhbmdlRmFjdG9yO1xuXHRcdFx0bGV0IGRyYXdFbmQgPSAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICogcmFuZ2VGYWN0b3I7XG5cblx0XHRcdGlmICggZ3JvdXAgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0ZHJhd1N0YXJ0ID0gTWF0aC5tYXgoIGRyYXdTdGFydCwgZ3JvdXAuc3RhcnQgKiByYW5nZUZhY3RvciApO1xuXHRcdFx0XHRkcmF3RW5kID0gTWF0aC5taW4oIGRyYXdFbmQsICggZ3JvdXAuc3RhcnQgKyBncm91cC5jb3VudCApICogcmFuZ2VGYWN0b3IgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGRyYXdTdGFydCA9IE1hdGgubWF4KCBkcmF3U3RhcnQsIDAgKTtcblx0XHRcdFx0ZHJhd0VuZCA9IE1hdGgubWluKCBkcmF3RW5kLCBpbmRleC5jb3VudCApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBwb3NpdGlvbiAhPT0gdW5kZWZpbmVkICYmIHBvc2l0aW9uICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGRyYXdTdGFydCA9IE1hdGgubWF4KCBkcmF3U3RhcnQsIDAgKTtcblx0XHRcdFx0ZHJhd0VuZCA9IE1hdGgubWluKCBkcmF3RW5kLCBwb3NpdGlvbi5jb3VudCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGRyYXdDb3VudCA9IGRyYXdFbmQgLSBkcmF3U3RhcnQ7XG5cblx0XHRcdGlmICggZHJhd0NvdW50IDwgMCB8fCBkcmF3Q291bnQgPT09IEluZmluaXR5ICkgcmV0dXJuO1xuXG5cdFx0XHQvL1xuXG5cdFx0XHRiaW5kaW5nU3RhdGVzLnNldHVwKCBvYmplY3QsIG1hdGVyaWFsLCBwcm9ncmFtLCBnZW9tZXRyeSwgaW5kZXggKTtcblxuXHRcdFx0bGV0IGF0dHJpYnV0ZTtcblx0XHRcdGxldCByZW5kZXJlciA9IGJ1ZmZlclJlbmRlcmVyO1xuXG5cdFx0XHRpZiAoIGluZGV4ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXMuZ2V0KCBpbmRleCApO1xuXG5cdFx0XHRcdHJlbmRlcmVyID0gaW5kZXhlZEJ1ZmZlclJlbmRlcmVyO1xuXHRcdFx0XHRyZW5kZXJlci5zZXRJbmRleCggYXR0cmlidXRlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9cblxuXHRcdFx0aWYgKCBvYmplY3QuaXNNZXNoICkge1xuXG5cdFx0XHRcdGlmICggbWF0ZXJpYWwud2lyZWZyYW1lID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0c3RhdGUuc2V0TGluZVdpZHRoKCBtYXRlcmlhbC53aXJlZnJhbWVMaW5ld2lkdGggKiBnZXRUYXJnZXRQaXhlbFJhdGlvKCkgKTtcblx0XHRcdFx0XHRyZW5kZXJlci5zZXRNb2RlKCBfZ2wuTElORVMgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0TW9kZSggX2dsLlRSSUFOR0xFUyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzTGluZSApIHtcblxuXHRcdFx0XHRsZXQgbGluZVdpZHRoID0gbWF0ZXJpYWwubGluZXdpZHRoO1xuXG5cdFx0XHRcdGlmICggbGluZVdpZHRoID09PSB1bmRlZmluZWQgKSBsaW5lV2lkdGggPSAxOyAvLyBOb3QgdXNpbmcgTGluZSpNYXRlcmlhbFxuXG5cdFx0XHRcdHN0YXRlLnNldExpbmVXaWR0aCggbGluZVdpZHRoICogZ2V0VGFyZ2V0UGl4ZWxSYXRpbygpICk7XG5cblx0XHRcdFx0aWYgKCBvYmplY3QuaXNMaW5lU2VnbWVudHMgKSB7XG5cblx0XHRcdFx0XHRyZW5kZXJlci5zZXRNb2RlKCBfZ2wuTElORVMgKTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNMaW5lTG9vcCApIHtcblxuXHRcdFx0XHRcdHJlbmRlcmVyLnNldE1vZGUoIF9nbC5MSU5FX0xPT1AgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0cmVuZGVyZXIuc2V0TW9kZSggX2dsLkxJTkVfU1RSSVAgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc1BvaW50cyApIHtcblxuXHRcdFx0XHRyZW5kZXJlci5zZXRNb2RlKCBfZ2wuUE9JTlRTICk7XG5cblx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc1Nwcml0ZSApIHtcblxuXHRcdFx0XHRyZW5kZXJlci5zZXRNb2RlKCBfZ2wuVFJJQU5HTEVTICk7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBvYmplY3QuaXNCYXRjaGVkTWVzaCApIHtcblxuXHRcdFx0XHRpZiAoIG9iamVjdC5fbXVsdGlEcmF3SW5zdGFuY2VzICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0cmVuZGVyZXIucmVuZGVyTXVsdGlEcmF3SW5zdGFuY2VzKCBvYmplY3QuX211bHRpRHJhd1N0YXJ0cywgb2JqZWN0Ll9tdWx0aURyYXdDb3VudHMsIG9iamVjdC5fbXVsdGlEcmF3Q291bnQsIG9iamVjdC5fbXVsdGlEcmF3SW5zdGFuY2VzICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGlmICggISBleHRlbnNpb25zLmdldCggJ1dFQkdMX211bHRpX2RyYXcnICkgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IHN0YXJ0cyA9IG9iamVjdC5fbXVsdGlEcmF3U3RhcnRzO1xuXHRcdFx0XHRcdFx0Y29uc3QgY291bnRzID0gb2JqZWN0Ll9tdWx0aURyYXdDb3VudHM7XG5cdFx0XHRcdFx0XHRjb25zdCBkcmF3Q291bnQgPSBvYmplY3QuX211bHRpRHJhd0NvdW50O1xuXHRcdFx0XHRcdFx0Y29uc3QgYnl0ZXNQZXJFbGVtZW50ID0gaW5kZXggPyBhdHRyaWJ1dGVzLmdldCggaW5kZXggKS5ieXRlc1BlckVsZW1lbnQgOiAxO1xuXHRcdFx0XHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBwcm9wZXJ0aWVzLmdldCggbWF0ZXJpYWwgKS5jdXJyZW50UHJvZ3JhbS5nZXRVbmlmb3JtcygpO1xuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgZHJhd0NvdW50OyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRcdHVuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdfZ2xfRHJhd0lEJywgaSApO1xuXHRcdFx0XHRcdFx0XHRyZW5kZXJlci5yZW5kZXIoIHN0YXJ0c1sgaSBdIC8gYnl0ZXNQZXJFbGVtZW50LCBjb3VudHNbIGkgXSApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRyZW5kZXJlci5yZW5kZXJNdWx0aURyYXcoIG9iamVjdC5fbXVsdGlEcmF3U3RhcnRzLCBvYmplY3QuX211bHRpRHJhd0NvdW50cywgb2JqZWN0Ll9tdWx0aURyYXdDb3VudCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCApIHtcblxuXHRcdFx0XHRyZW5kZXJlci5yZW5kZXJJbnN0YW5jZXMoIGRyYXdTdGFydCwgZHJhd0NvdW50LCBvYmplY3QuY291bnQgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggZ2VvbWV0cnkuaXNJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSApIHtcblxuXHRcdFx0XHRjb25zdCBtYXhJbnN0YW5jZUNvdW50ID0gZ2VvbWV0cnkuX21heEluc3RhbmNlQ291bnQgIT09IHVuZGVmaW5lZCA/IGdlb21ldHJ5Ll9tYXhJbnN0YW5jZUNvdW50IDogSW5maW5pdHk7XG5cdFx0XHRcdGNvbnN0IGluc3RhbmNlQ291bnQgPSBNYXRoLm1pbiggZ2VvbWV0cnkuaW5zdGFuY2VDb3VudCwgbWF4SW5zdGFuY2VDb3VudCApO1xuXG5cdFx0XHRcdHJlbmRlcmVyLnJlbmRlckluc3RhbmNlcyggZHJhd1N0YXJ0LCBkcmF3Q291bnQsIGluc3RhbmNlQ291bnQgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRyZW5kZXJlci5yZW5kZXIoIGRyYXdTdGFydCwgZHJhd0NvdW50ICk7XG5cblx0XHRcdH1cblxuXHRcdH07XG5cblx0XHQvLyBDb21waWxlXG5cblx0XHRmdW5jdGlvbiBwcmVwYXJlTWF0ZXJpYWwoIG1hdGVyaWFsLCBzY2VuZSwgb2JqZWN0ICkge1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLnRyYW5zcGFyZW50ID09PSB0cnVlICYmIG1hdGVyaWFsLnNpZGUgPT09IERvdWJsZVNpZGUgJiYgbWF0ZXJpYWwuZm9yY2VTaW5nbGVQYXNzID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHRtYXRlcmlhbC5zaWRlID0gQmFja1NpZGU7XG5cdFx0XHRcdG1hdGVyaWFsLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblx0XHRcdFx0Z2V0UHJvZ3JhbSggbWF0ZXJpYWwsIHNjZW5lLCBvYmplY3QgKTtcblxuXHRcdFx0XHRtYXRlcmlhbC5zaWRlID0gRnJvbnRTaWRlO1xuXHRcdFx0XHRtYXRlcmlhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0XHRcdGdldFByb2dyYW0oIG1hdGVyaWFsLCBzY2VuZSwgb2JqZWN0ICk7XG5cblx0XHRcdFx0bWF0ZXJpYWwuc2lkZSA9IERvdWJsZVNpZGU7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Z2V0UHJvZ3JhbSggbWF0ZXJpYWwsIHNjZW5lLCBvYmplY3QgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0dGhpcy5jb21waWxlID0gZnVuY3Rpb24gKCBzY2VuZSwgY2FtZXJhLCB0YXJnZXRTY2VuZSA9IG51bGwgKSB7XG5cblx0XHRcdGlmICggdGFyZ2V0U2NlbmUgPT09IG51bGwgKSB0YXJnZXRTY2VuZSA9IHNjZW5lO1xuXG5cdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUgPSByZW5kZXJTdGF0ZXMuZ2V0KCB0YXJnZXRTY2VuZSApO1xuXHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLmluaXQoIGNhbWVyYSApO1xuXG5cdFx0XHRyZW5kZXJTdGF0ZVN0YWNrLnB1c2goIGN1cnJlbnRSZW5kZXJTdGF0ZSApO1xuXG5cdFx0XHQvLyBnYXRoZXIgbGlnaHRzIGZyb20gYm90aCB0aGUgdGFyZ2V0IHNjZW5lIGFuZCB0aGUgbmV3IG9iamVjdCB0aGF0IHdpbGwgYmUgYWRkZWQgdG8gdGhlIHNjZW5lLlxuXG5cdFx0XHR0YXJnZXRTY2VuZS50cmF2ZXJzZVZpc2libGUoIGZ1bmN0aW9uICggb2JqZWN0ICkge1xuXG5cdFx0XHRcdGlmICggb2JqZWN0LmlzTGlnaHQgJiYgb2JqZWN0LmxheWVycy50ZXN0KCBjYW1lcmEubGF5ZXJzICkgKSB7XG5cblx0XHRcdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUucHVzaExpZ2h0KCBvYmplY3QgKTtcblxuXHRcdFx0XHRcdGlmICggb2JqZWN0LmNhc3RTaGFkb3cgKSB7XG5cblx0XHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5wdXNoU2hhZG93KCBvYmplY3QgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gKTtcblxuXHRcdFx0aWYgKCBzY2VuZSAhPT0gdGFyZ2V0U2NlbmUgKSB7XG5cblx0XHRcdFx0c2NlbmUudHJhdmVyc2VWaXNpYmxlKCBmdW5jdGlvbiAoIG9iamVjdCApIHtcblxuXHRcdFx0XHRcdGlmICggb2JqZWN0LmlzTGlnaHQgJiYgb2JqZWN0LmxheWVycy50ZXN0KCBjYW1lcmEubGF5ZXJzICkgKSB7XG5cblx0XHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5wdXNoTGlnaHQoIG9iamVjdCApO1xuXG5cdFx0XHRcdFx0XHRpZiAoIG9iamVjdC5jYXN0U2hhZG93ICkge1xuXG5cdFx0XHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5wdXNoU2hhZG93KCBvYmplY3QgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUuc2V0dXBMaWdodHMoKTtcblxuXHRcdFx0Ly8gT25seSBpbml0aWFsaXplIG1hdGVyaWFscyBpbiB0aGUgbmV3IHNjZW5lLCBub3QgdGhlIHRhcmdldFNjZW5lLlxuXG5cdFx0XHRjb25zdCBtYXRlcmlhbHMgPSBuZXcgU2V0KCk7XG5cblx0XHRcdHNjZW5lLnRyYXZlcnNlKCBmdW5jdGlvbiAoIG9iamVjdCApIHtcblxuXHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IG9iamVjdC5tYXRlcmlhbDtcblxuXHRcdFx0XHRpZiAoIG1hdGVyaWFsICkge1xuXG5cdFx0XHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBtYXRlcmlhbCApICkge1xuXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBtYXRlcmlhbC5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdFx0Y29uc3QgbWF0ZXJpYWwyID0gbWF0ZXJpYWxbIGkgXTtcblxuXHRcdFx0XHRcdFx0XHRwcmVwYXJlTWF0ZXJpYWwoIG1hdGVyaWFsMiwgdGFyZ2V0U2NlbmUsIG9iamVjdCApO1xuXHRcdFx0XHRcdFx0XHRtYXRlcmlhbHMuYWRkKCBtYXRlcmlhbDIgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0cHJlcGFyZU1hdGVyaWFsKCBtYXRlcmlhbCwgdGFyZ2V0U2NlbmUsIG9iamVjdCApO1xuXHRcdFx0XHRcdFx0bWF0ZXJpYWxzLmFkZCggbWF0ZXJpYWwgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gKTtcblxuXHRcdFx0cmVuZGVyU3RhdGVTdGFjay5wb3AoKTtcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IG51bGw7XG5cblx0XHRcdHJldHVybiBtYXRlcmlhbHM7XG5cblx0XHR9O1xuXG5cdFx0Ly8gY29tcGlsZUFzeW5jXG5cblx0XHR0aGlzLmNvbXBpbGVBc3luYyA9IGZ1bmN0aW9uICggc2NlbmUsIGNhbWVyYSwgdGFyZ2V0U2NlbmUgPSBudWxsICkge1xuXG5cdFx0XHRjb25zdCBtYXRlcmlhbHMgPSB0aGlzLmNvbXBpbGUoIHNjZW5lLCBjYW1lcmEsIHRhcmdldFNjZW5lICk7XG5cblx0XHRcdC8vIFdhaXQgZm9yIGFsbCB0aGUgbWF0ZXJpYWxzIGluIHRoZSBuZXcgb2JqZWN0IHRvIGluZGljYXRlIHRoYXQgdGhleSdyZVxuXHRcdFx0Ly8gcmVhZHkgdG8gYmUgdXNlZCBiZWZvcmUgcmVzb2x2aW5nIHRoZSBwcm9taXNlLlxuXG5cdFx0XHRyZXR1cm4gbmV3IFByb21pc2UoICggcmVzb2x2ZSApID0+IHtcblxuXHRcdFx0XHRmdW5jdGlvbiBjaGVja01hdGVyaWFsc1JlYWR5KCkge1xuXG5cdFx0XHRcdFx0bWF0ZXJpYWxzLmZvckVhY2goIGZ1bmN0aW9uICggbWF0ZXJpYWwgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xuXHRcdFx0XHRcdFx0Y29uc3QgcHJvZ3JhbSA9IG1hdGVyaWFsUHJvcGVydGllcy5jdXJyZW50UHJvZ3JhbTtcblxuXHRcdFx0XHRcdFx0aWYgKCBwcm9ncmFtLmlzUmVhZHkoKSApIHtcblxuXHRcdFx0XHRcdFx0XHQvLyByZW1vdmUgYW55IHByb2dyYW1zIHRoYXQgcmVwb3J0IHRoZXkncmUgcmVhZHkgdG8gdXNlIGZyb20gdGhlIGxpc3Rcblx0XHRcdFx0XHRcdFx0bWF0ZXJpYWxzLmRlbGV0ZSggbWF0ZXJpYWwgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdFx0Ly8gb25jZSB0aGUgbGlzdCBvZiBjb21waWxpbmcgbWF0ZXJpYWxzIGlzIGVtcHR5LCBjYWxsIHRoZSBjYWxsYmFja1xuXG5cdFx0XHRcdFx0aWYgKCBtYXRlcmlhbHMuc2l6ZSA9PT0gMCApIHtcblxuXHRcdFx0XHRcdFx0cmVzb2x2ZSggc2NlbmUgKTtcblx0XHRcdFx0XHRcdHJldHVybjtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIGlmIHNvbWUgbWF0ZXJpYWxzIGFyZSBzdGlsbCBub3QgcmVhZHksIHdhaXQgYSBiaXQgYW5kIGNoZWNrIGFnYWluXG5cblx0XHRcdFx0XHRzZXRUaW1lb3V0KCBjaGVja01hdGVyaWFsc1JlYWR5LCAxMCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIGV4dGVuc2lvbnMuZ2V0KCAnS0hSX3BhcmFsbGVsX3NoYWRlcl9jb21waWxlJyApICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0Ly8gSWYgd2UgY2FuIGNoZWNrIHRoZSBjb21waWxhdGlvbiBzdGF0dXMgb2YgdGhlIG1hdGVyaWFscyB3aXRob3V0XG5cdFx0XHRcdFx0Ly8gYmxvY2tpbmcgdGhlbiBkbyBzbyByaWdodCBhd2F5LlxuXG5cdFx0XHRcdFx0Y2hlY2tNYXRlcmlhbHNSZWFkeSgpO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBPdGhlcndpc2Ugc3RhcnQgYnkgd2FpdGluZyBhIGJpdCB0byBnaXZlIHRoZSBtYXRlcmlhbHMgd2UganVzdFxuXHRcdFx0XHRcdC8vIGluaXRpYWxpemVkIGEgY2hhbmNlIHRvIGZpbmlzaC5cblxuXHRcdFx0XHRcdHNldFRpbWVvdXQoIGNoZWNrTWF0ZXJpYWxzUmVhZHksIDEwICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9ICk7XG5cblx0XHR9O1xuXG5cdFx0Ly8gQW5pbWF0aW9uIExvb3BcblxuXHRcdGxldCBvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2sgPSBudWxsO1xuXG5cdFx0ZnVuY3Rpb24gb25BbmltYXRpb25GcmFtZSggdGltZSApIHtcblxuXHRcdFx0aWYgKCBvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2sgKSBvbkFuaW1hdGlvbkZyYW1lQ2FsbGJhY2soIHRpbWUgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uWFJTZXNzaW9uU3RhcnQoKSB7XG5cblx0XHRcdGFuaW1hdGlvbi5zdG9wKCk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBvblhSU2Vzc2lvbkVuZCgpIHtcblxuXHRcdFx0YW5pbWF0aW9uLnN0YXJ0KCk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBhbmltYXRpb24gPSBuZXcgV2ViR0xBbmltYXRpb24oKTtcblx0XHRhbmltYXRpb24uc2V0QW5pbWF0aW9uTG9vcCggb25BbmltYXRpb25GcmFtZSApO1xuXG5cdFx0aWYgKCB0eXBlb2Ygc2VsZiAhPT0gJ3VuZGVmaW5lZCcgKSBhbmltYXRpb24uc2V0Q29udGV4dCggc2VsZiApO1xuXG5cdFx0dGhpcy5zZXRBbmltYXRpb25Mb29wID0gZnVuY3Rpb24gKCBjYWxsYmFjayApIHtcblxuXHRcdFx0b25BbmltYXRpb25GcmFtZUNhbGxiYWNrID0gY2FsbGJhY2s7XG5cdFx0XHR4ci5zZXRBbmltYXRpb25Mb29wKCBjYWxsYmFjayApO1xuXG5cdFx0XHQoIGNhbGxiYWNrID09PSBudWxsICkgPyBhbmltYXRpb24uc3RvcCgpIDogYW5pbWF0aW9uLnN0YXJ0KCk7XG5cblx0XHR9O1xuXG5cdFx0eHIuYWRkRXZlbnRMaXN0ZW5lciggJ3Nlc3Npb25zdGFydCcsIG9uWFJTZXNzaW9uU3RhcnQgKTtcblx0XHR4ci5hZGRFdmVudExpc3RlbmVyKCAnc2Vzc2lvbmVuZCcsIG9uWFJTZXNzaW9uRW5kICk7XG5cblx0XHQvLyBSZW5kZXJpbmdcblxuXHRcdHRoaXMucmVuZGVyID0gZnVuY3Rpb24gKCBzY2VuZSwgY2FtZXJhICkge1xuXG5cdFx0XHRpZiAoIGNhbWVyYSAhPT0gdW5kZWZpbmVkICYmIGNhbWVyYS5pc0NhbWVyYSAhPT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuV2ViR0xSZW5kZXJlci5yZW5kZXI6IGNhbWVyYSBpcyBub3QgYW4gaW5zdGFuY2Ugb2YgVEhSRUUuQ2FtZXJhLicgKTtcblx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggX2lzQ29udGV4dExvc3QgPT09IHRydWUgKSByZXR1cm47XG5cblx0XHRcdC8vIHVwZGF0ZSBzY2VuZSBncmFwaFxuXG5cdFx0XHRpZiAoIHNjZW5lLm1hdHJpeFdvcmxkQXV0b1VwZGF0ZSA9PT0gdHJ1ZSApIHNjZW5lLnVwZGF0ZU1hdHJpeFdvcmxkKCk7XG5cblx0XHRcdC8vIHVwZGF0ZSBjYW1lcmEgbWF0cmljZXMgYW5kIGZydXN0dW1cblxuXHRcdFx0aWYgKCBjYW1lcmEucGFyZW50ID09PSBudWxsICYmIGNhbWVyYS5tYXRyaXhXb3JsZEF1dG9VcGRhdGUgPT09IHRydWUgKSBjYW1lcmEudXBkYXRlTWF0cml4V29ybGQoKTtcblxuXHRcdFx0aWYgKCB4ci5lbmFibGVkID09PSB0cnVlICYmIHhyLmlzUHJlc2VudGluZyA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRpZiAoIHhyLmNhbWVyYUF1dG9VcGRhdGUgPT09IHRydWUgKSB4ci51cGRhdGVDYW1lcmEoIGNhbWVyYSApO1xuXG5cdFx0XHRcdGNhbWVyYSA9IHhyLmdldENhbWVyYSgpOyAvLyB1c2UgWFIgY2FtZXJhIGZvciByZW5kZXJpbmdcblxuXHRcdFx0fVxuXG5cdFx0XHQvL1xuXHRcdFx0aWYgKCBzY2VuZS5pc1NjZW5lID09PSB0cnVlICkgc2NlbmUub25CZWZvcmVSZW5kZXIoIF90aGlzLCBzY2VuZSwgY2FtZXJhLCBfY3VycmVudFJlbmRlclRhcmdldCApO1xuXG5cdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUgPSByZW5kZXJTdGF0ZXMuZ2V0KCBzY2VuZSwgcmVuZGVyU3RhdGVTdGFjay5sZW5ndGggKTtcblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5pbml0KCBjYW1lcmEgKTtcblxuXHRcdFx0cmVuZGVyU3RhdGVTdGFjay5wdXNoKCBjdXJyZW50UmVuZGVyU3RhdGUgKTtcblxuXHRcdFx0X3Byb2pTY3JlZW5NYXRyaXgubXVsdGlwbHlNYXRyaWNlcyggY2FtZXJhLnByb2plY3Rpb25NYXRyaXgsIGNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UgKTtcblx0XHRcdF9mcnVzdHVtLnNldEZyb21Qcm9qZWN0aW9uTWF0cml4KCBfcHJvalNjcmVlbk1hdHJpeCApO1xuXG5cdFx0XHRfbG9jYWxDbGlwcGluZ0VuYWJsZWQgPSB0aGlzLmxvY2FsQ2xpcHBpbmdFbmFibGVkO1xuXHRcdFx0X2NsaXBwaW5nRW5hYmxlZCA9IGNsaXBwaW5nLmluaXQoIHRoaXMuY2xpcHBpbmdQbGFuZXMsIF9sb2NhbENsaXBwaW5nRW5hYmxlZCApO1xuXG5cdFx0XHRjdXJyZW50UmVuZGVyTGlzdCA9IHJlbmRlckxpc3RzLmdldCggc2NlbmUsIHJlbmRlckxpc3RTdGFjay5sZW5ndGggKTtcblx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0LmluaXQoKTtcblxuXHRcdFx0cmVuZGVyTGlzdFN0YWNrLnB1c2goIGN1cnJlbnRSZW5kZXJMaXN0ICk7XG5cblx0XHRcdGlmICggeHIuZW5hYmxlZCA9PT0gdHJ1ZSAmJiB4ci5pc1ByZXNlbnRpbmcgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0Y29uc3QgZGVwdGhTZW5zaW5nTWVzaCA9IF90aGlzLnhyLmdldERlcHRoU2Vuc2luZ01lc2goKTtcblxuXHRcdFx0XHRpZiAoIGRlcHRoU2Vuc2luZ01lc2ggIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRwcm9qZWN0T2JqZWN0KCBkZXB0aFNlbnNpbmdNZXNoLCBjYW1lcmEsIC0gSW5maW5pdHksIF90aGlzLnNvcnRPYmplY3RzICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHByb2plY3RPYmplY3QoIHNjZW5lLCBjYW1lcmEsIDAsIF90aGlzLnNvcnRPYmplY3RzICk7XG5cblx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0LmZpbmlzaCgpO1xuXG5cdFx0XHRpZiAoIF90aGlzLnNvcnRPYmplY3RzID09PSB0cnVlICkge1xuXG5cdFx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0LnNvcnQoIF9vcGFxdWVTb3J0LCBfdHJhbnNwYXJlbnRTb3J0ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0X3JlbmRlckJhY2tncm91bmQgPSB4ci5lbmFibGVkID09PSBmYWxzZSB8fCB4ci5pc1ByZXNlbnRpbmcgPT09IGZhbHNlIHx8IHhyLmhhc0RlcHRoU2Vuc2luZygpID09PSBmYWxzZTtcblx0XHRcdGlmICggX3JlbmRlckJhY2tncm91bmQgKSB7XG5cblx0XHRcdFx0YmFja2dyb3VuZC5hZGRUb1JlbmRlckxpc3QoIGN1cnJlbnRSZW5kZXJMaXN0LCBzY2VuZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vXG5cblx0XHRcdHRoaXMuaW5mby5yZW5kZXIuZnJhbWUgKys7XG5cblx0XHRcdGlmICggX2NsaXBwaW5nRW5hYmxlZCA9PT0gdHJ1ZSApIGNsaXBwaW5nLmJlZ2luU2hhZG93cygpO1xuXG5cdFx0XHRjb25zdCBzaGFkb3dzQXJyYXkgPSBjdXJyZW50UmVuZGVyU3RhdGUuc3RhdGUuc2hhZG93c0FycmF5O1xuXG5cdFx0XHRzaGFkb3dNYXAucmVuZGVyKCBzaGFkb3dzQXJyYXksIHNjZW5lLCBjYW1lcmEgKTtcblxuXHRcdFx0aWYgKCBfY2xpcHBpbmdFbmFibGVkID09PSB0cnVlICkgY2xpcHBpbmcuZW5kU2hhZG93cygpO1xuXG5cdFx0XHQvL1xuXG5cdFx0XHRpZiAoIHRoaXMuaW5mby5hdXRvUmVzZXQgPT09IHRydWUgKSB0aGlzLmluZm8ucmVzZXQoKTtcblxuXHRcdFx0Ly8gcmVuZGVyIHNjZW5lXG5cblx0XHRcdGNvbnN0IG9wYXF1ZU9iamVjdHMgPSBjdXJyZW50UmVuZGVyTGlzdC5vcGFxdWU7XG5cdFx0XHRjb25zdCB0cmFuc21pc3NpdmVPYmplY3RzID0gY3VycmVudFJlbmRlckxpc3QudHJhbnNtaXNzaXZlO1xuXG5cdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUuc2V0dXBMaWdodHMoKTtcblxuXHRcdFx0aWYgKCBjYW1lcmEuaXNBcnJheUNhbWVyYSApIHtcblxuXHRcdFx0XHRjb25zdCBjYW1lcmFzID0gY2FtZXJhLmNhbWVyYXM7XG5cblx0XHRcdFx0aWYgKCB0cmFuc21pc3NpdmVPYmplY3RzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjYW1lcmFzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGNhbWVyYTIgPSBjYW1lcmFzWyBpIF07XG5cblx0XHRcdFx0XHRcdHJlbmRlclRyYW5zbWlzc2lvblBhc3MoIG9wYXF1ZU9iamVjdHMsIHRyYW5zbWlzc2l2ZU9iamVjdHMsIHNjZW5lLCBjYW1lcmEyICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggX3JlbmRlckJhY2tncm91bmQgKSBiYWNrZ3JvdW5kLnJlbmRlciggc2NlbmUgKTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBjYW1lcmFzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBjYW1lcmEyID0gY2FtZXJhc1sgaSBdO1xuXG5cdFx0XHRcdFx0cmVuZGVyU2NlbmUoIGN1cnJlbnRSZW5kZXJMaXN0LCBzY2VuZSwgY2FtZXJhMiwgY2FtZXJhMi52aWV3cG9ydCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRpZiAoIHRyYW5zbWlzc2l2ZU9iamVjdHMubGVuZ3RoID4gMCApIHJlbmRlclRyYW5zbWlzc2lvblBhc3MoIG9wYXF1ZU9iamVjdHMsIHRyYW5zbWlzc2l2ZU9iamVjdHMsIHNjZW5lLCBjYW1lcmEgKTtcblxuXHRcdFx0XHRpZiAoIF9yZW5kZXJCYWNrZ3JvdW5kICkgYmFja2dyb3VuZC5yZW5kZXIoIHNjZW5lICk7XG5cblx0XHRcdFx0cmVuZGVyU2NlbmUoIGN1cnJlbnRSZW5kZXJMaXN0LCBzY2VuZSwgY2FtZXJhICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9cblxuXHRcdFx0aWYgKCBfY3VycmVudFJlbmRlclRhcmdldCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHQvLyByZXNvbHZlIG11bHRpc2FtcGxlIHJlbmRlcmJ1ZmZlcnMgdG8gYSBzaW5nbGUtc2FtcGxlIHRleHR1cmUgaWYgbmVjZXNzYXJ5XG5cblx0XHRcdFx0dGV4dHVyZXMudXBkYXRlTXVsdGlzYW1wbGVSZW5kZXJUYXJnZXQoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRcdFx0Ly8gR2VuZXJhdGUgbWlwbWFwIGlmIHdlJ3JlIHVzaW5nIGFueSBraW5kIG9mIG1pcG1hcCBmaWx0ZXJpbmdcblxuXHRcdFx0XHR0ZXh0dXJlcy51cGRhdGVSZW5kZXJUYXJnZXRNaXBtYXAoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9cblxuXHRcdFx0aWYgKCBzY2VuZS5pc1NjZW5lID09PSB0cnVlICkgc2NlbmUub25BZnRlclJlbmRlciggX3RoaXMsIHNjZW5lLCBjYW1lcmEgKTtcblxuXHRcdFx0Ly8gX2dsLmZpbmlzaCgpO1xuXG5cdFx0XHRiaW5kaW5nU3RhdGVzLnJlc2V0RGVmYXVsdFN0YXRlKCk7XG5cdFx0XHRfY3VycmVudE1hdGVyaWFsSWQgPSAtIDE7XG5cdFx0XHRfY3VycmVudENhbWVyYSA9IG51bGw7XG5cblx0XHRcdHJlbmRlclN0YXRlU3RhY2sucG9wKCk7XG5cblx0XHRcdGlmICggcmVuZGVyU3RhdGVTdGFjay5sZW5ndGggPiAwICkge1xuXG5cdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IHJlbmRlclN0YXRlU3RhY2tbIHJlbmRlclN0YXRlU3RhY2subGVuZ3RoIC0gMSBdO1xuXG5cdFx0XHRcdGlmICggX2NsaXBwaW5nRW5hYmxlZCA9PT0gdHJ1ZSApIGNsaXBwaW5nLnNldEdsb2JhbFN0YXRlKCBfdGhpcy5jbGlwcGluZ1BsYW5lcywgY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLmNhbWVyYSApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZSA9IG51bGw7XG5cblx0XHRcdH1cblxuXHRcdFx0cmVuZGVyTGlzdFN0YWNrLnBvcCgpO1xuXG5cdFx0XHRpZiAoIHJlbmRlckxpc3RTdGFjay5sZW5ndGggPiAwICkge1xuXG5cdFx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0ID0gcmVuZGVyTGlzdFN0YWNrWyByZW5kZXJMaXN0U3RhY2subGVuZ3RoIC0gMSBdO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0ID0gbnVsbDtcblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdGZ1bmN0aW9uIHByb2plY3RPYmplY3QoIG9iamVjdCwgY2FtZXJhLCBncm91cE9yZGVyLCBzb3J0T2JqZWN0cyApIHtcblxuXHRcdFx0aWYgKCBvYmplY3QudmlzaWJsZSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHRcdGNvbnN0IHZpc2libGUgPSBvYmplY3QubGF5ZXJzLnRlc3QoIGNhbWVyYS5sYXllcnMgKTtcblxuXHRcdFx0aWYgKCB2aXNpYmxlICkge1xuXG5cdFx0XHRcdGlmICggb2JqZWN0LmlzR3JvdXAgKSB7XG5cblx0XHRcdFx0XHRncm91cE9yZGVyID0gb2JqZWN0LnJlbmRlck9yZGVyO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0xPRCApIHtcblxuXHRcdFx0XHRcdGlmICggb2JqZWN0LmF1dG9VcGRhdGUgPT09IHRydWUgKSBvYmplY3QudXBkYXRlKCBjYW1lcmEgKTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNMaWdodCApIHtcblxuXHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5wdXNoTGlnaHQoIG9iamVjdCApO1xuXG5cdFx0XHRcdFx0aWYgKCBvYmplY3QuY2FzdFNoYWRvdyApIHtcblxuXHRcdFx0XHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLnB1c2hTaGFkb3coIG9iamVjdCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc1Nwcml0ZSApIHtcblxuXHRcdFx0XHRcdGlmICggISBvYmplY3QuZnJ1c3R1bUN1bGxlZCB8fCBfZnJ1c3R1bS5pbnRlcnNlY3RzU3ByaXRlKCBvYmplY3QgKSApIHtcblxuXHRcdFx0XHRcdFx0aWYgKCBzb3J0T2JqZWN0cyApIHtcblxuXHRcdFx0XHRcdFx0XHRfdmVjdG9yNC5zZXRGcm9tTWF0cml4UG9zaXRpb24oIG9iamVjdC5tYXRyaXhXb3JsZCApXG5cdFx0XHRcdFx0XHRcdFx0LmFwcGx5TWF0cml4NCggX3Byb2pTY3JlZW5NYXRyaXggKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRjb25zdCBnZW9tZXRyeSA9IG9iamVjdHMudXBkYXRlKCBvYmplY3QgKTtcblx0XHRcdFx0XHRcdGNvbnN0IG1hdGVyaWFsID0gb2JqZWN0Lm1hdGVyaWFsO1xuXG5cdFx0XHRcdFx0XHRpZiAoIG1hdGVyaWFsLnZpc2libGUgKSB7XG5cblx0XHRcdFx0XHRcdFx0Y3VycmVudFJlbmRlckxpc3QucHVzaCggb2JqZWN0LCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwT3JkZXIsIF92ZWN0b3I0LnosIG51bGwgKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc01lc2ggfHwgb2JqZWN0LmlzTGluZSB8fCBvYmplY3QuaXNQb2ludHMgKSB7XG5cblx0XHRcdFx0XHRpZiAoICEgb2JqZWN0LmZydXN0dW1DdWxsZWQgfHwgX2ZydXN0dW0uaW50ZXJzZWN0c09iamVjdCggb2JqZWN0ICkgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGdlb21ldHJ5ID0gb2JqZWN0cy51cGRhdGUoIG9iamVjdCApO1xuXHRcdFx0XHRcdFx0Y29uc3QgbWF0ZXJpYWwgPSBvYmplY3QubWF0ZXJpYWw7XG5cblx0XHRcdFx0XHRcdGlmICggc29ydE9iamVjdHMgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBvYmplY3QuYm91bmRpbmdTcGhlcmUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGlmICggb2JqZWN0LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkgb2JqZWN0LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xuXHRcdFx0XHRcdFx0XHRcdF92ZWN0b3I0LmNvcHkoIG9iamVjdC5ib3VuZGluZ1NwaGVyZS5jZW50ZXIgKTtcblxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdFx0aWYgKCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIGdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xuXHRcdFx0XHRcdFx0XHRcdF92ZWN0b3I0LmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlLmNlbnRlciApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRfdmVjdG9yNFxuXHRcdFx0XHRcdFx0XHRcdC5hcHBseU1hdHJpeDQoIG9iamVjdC5tYXRyaXhXb3JsZCApXG5cdFx0XHRcdFx0XHRcdFx0LmFwcGx5TWF0cml4NCggX3Byb2pTY3JlZW5NYXRyaXggKTtcblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIG1hdGVyaWFsICkgKSB7XG5cblx0XHRcdFx0XHRcdFx0Y29uc3QgZ3JvdXBzID0gZ2VvbWV0cnkuZ3JvdXBzO1xuXG5cdFx0XHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGdyb3Vwcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcblx0XHRcdFx0XHRcdFx0XHRjb25zdCBncm91cE1hdGVyaWFsID0gbWF0ZXJpYWxbIGdyb3VwLm1hdGVyaWFsSW5kZXggXTtcblxuXHRcdFx0XHRcdFx0XHRcdGlmICggZ3JvdXBNYXRlcmlhbCAmJiBncm91cE1hdGVyaWFsLnZpc2libGUgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0LnB1c2goIG9iamVjdCwgZ2VvbWV0cnksIGdyb3VwTWF0ZXJpYWwsIGdyb3VwT3JkZXIsIF92ZWN0b3I0LnosIGdyb3VwICk7XG5cblx0XHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC52aXNpYmxlICkge1xuXG5cdFx0XHRcdFx0XHRcdGN1cnJlbnRSZW5kZXJMaXN0LnB1c2goIG9iamVjdCwgZ2VvbWV0cnksIG1hdGVyaWFsLCBncm91cE9yZGVyLCBfdmVjdG9yNC56LCBudWxsICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgY2hpbGRyZW4gPSBvYmplY3QuY2hpbGRyZW47XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGNoaWxkcmVuLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0cHJvamVjdE9iamVjdCggY2hpbGRyZW5bIGkgXSwgY2FtZXJhLCBncm91cE9yZGVyLCBzb3J0T2JqZWN0cyApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiByZW5kZXJTY2VuZSggY3VycmVudFJlbmRlckxpc3QsIHNjZW5lLCBjYW1lcmEsIHZpZXdwb3J0ICkge1xuXG5cdFx0XHRjb25zdCBvcGFxdWVPYmplY3RzID0gY3VycmVudFJlbmRlckxpc3Qub3BhcXVlO1xuXHRcdFx0Y29uc3QgdHJhbnNtaXNzaXZlT2JqZWN0cyA9IGN1cnJlbnRSZW5kZXJMaXN0LnRyYW5zbWlzc2l2ZTtcblx0XHRcdGNvbnN0IHRyYW5zcGFyZW50T2JqZWN0cyA9IGN1cnJlbnRSZW5kZXJMaXN0LnRyYW5zcGFyZW50O1xuXG5cdFx0XHRjdXJyZW50UmVuZGVyU3RhdGUuc2V0dXBMaWdodHNWaWV3KCBjYW1lcmEgKTtcblxuXHRcdFx0aWYgKCBfY2xpcHBpbmdFbmFibGVkID09PSB0cnVlICkgY2xpcHBpbmcuc2V0R2xvYmFsU3RhdGUoIF90aGlzLmNsaXBwaW5nUGxhbmVzLCBjYW1lcmEgKTtcblxuXHRcdFx0aWYgKCB2aWV3cG9ydCApIHN0YXRlLnZpZXdwb3J0KCBfY3VycmVudFZpZXdwb3J0LmNvcHkoIHZpZXdwb3J0ICkgKTtcblxuXHRcdFx0aWYgKCBvcGFxdWVPYmplY3RzLmxlbmd0aCA+IDAgKSByZW5kZXJPYmplY3RzKCBvcGFxdWVPYmplY3RzLCBzY2VuZSwgY2FtZXJhICk7XG5cdFx0XHRpZiAoIHRyYW5zbWlzc2l2ZU9iamVjdHMubGVuZ3RoID4gMCApIHJlbmRlck9iamVjdHMoIHRyYW5zbWlzc2l2ZU9iamVjdHMsIHNjZW5lLCBjYW1lcmEgKTtcblx0XHRcdGlmICggdHJhbnNwYXJlbnRPYmplY3RzLmxlbmd0aCA+IDAgKSByZW5kZXJPYmplY3RzKCB0cmFuc3BhcmVudE9iamVjdHMsIHNjZW5lLCBjYW1lcmEgKTtcblxuXHRcdFx0Ly8gRW5zdXJlIGRlcHRoIGJ1ZmZlciB3cml0aW5nIGlzIGVuYWJsZWQgc28gaXQgY2FuIGJlIGNsZWFyZWQgb24gbmV4dCByZW5kZXJcblxuXHRcdFx0c3RhdGUuYnVmZmVycy5kZXB0aC5zZXRUZXN0KCB0cnVlICk7XG5cdFx0XHRzdGF0ZS5idWZmZXJzLmRlcHRoLnNldE1hc2soIHRydWUgKTtcblx0XHRcdHN0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0TWFzayggdHJ1ZSApO1xuXG5cdFx0XHRzdGF0ZS5zZXRQb2x5Z29uT2Zmc2V0KCBmYWxzZSApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gcmVuZGVyVHJhbnNtaXNzaW9uUGFzcyggb3BhcXVlT2JqZWN0cywgdHJhbnNtaXNzaXZlT2JqZWN0cywgc2NlbmUsIGNhbWVyYSApIHtcblxuXHRcdFx0Y29uc3Qgb3ZlcnJpZGVNYXRlcmlhbCA9IHNjZW5lLmlzU2NlbmUgPT09IHRydWUgPyBzY2VuZS5vdmVycmlkZU1hdGVyaWFsIDogbnVsbDtcblxuXHRcdFx0aWYgKCBvdmVycmlkZU1hdGVyaWFsICE9PSBudWxsICkge1xuXG5cdFx0XHRcdHJldHVybjtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGN1cnJlbnRSZW5kZXJTdGF0ZS5zdGF0ZS50cmFuc21pc3Npb25SZW5kZXJUYXJnZXRbIGNhbWVyYS5pZCBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y3VycmVudFJlbmRlclN0YXRlLnN0YXRlLnRyYW5zbWlzc2lvblJlbmRlclRhcmdldFsgY2FtZXJhLmlkIF0gPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoIDEsIDEsIHtcblx0XHRcdFx0XHRnZW5lcmF0ZU1pcG1hcHM6IHRydWUsXG5cdFx0XHRcdFx0dHlwZTogKCBleHRlbnNpb25zLmhhcyggJ0VYVF9jb2xvcl9idWZmZXJfaGFsZl9mbG9hdCcgKSB8fCBleHRlbnNpb25zLmhhcyggJ0VYVF9jb2xvcl9idWZmZXJfZmxvYXQnICkgKSA/IEhhbGZGbG9hdFR5cGUgOiBVbnNpZ25lZEJ5dGVUeXBlLFxuXHRcdFx0XHRcdG1pbkZpbHRlcjogTGluZWFyTWlwbWFwTGluZWFyRmlsdGVyLFxuXHRcdFx0XHRcdHNhbXBsZXM6IDQsXG5cdFx0XHRcdFx0c3RlbmNpbEJ1ZmZlcjogc3RlbmNpbCxcblx0XHRcdFx0XHRyZXNvbHZlRGVwdGhCdWZmZXI6IGZhbHNlLFxuXHRcdFx0XHRcdHJlc29sdmVTdGVuY2lsQnVmZmVyOiBmYWxzZSxcblx0XHRcdFx0XHRjb2xvclNwYWNlOiBDb2xvck1hbmFnZW1lbnQud29ya2luZ0NvbG9yU3BhY2UsXG5cdFx0XHRcdH0gKTtcblxuXHRcdFx0XHQvLyBkZWJ1Z1xuXG5cdFx0XHRcdC8qXG5cdFx0XHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IFBsYW5lR2VvbWV0cnkoKTtcblx0XHRcdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHsgbWFwOiBfdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0LnRleHR1cmUgfSApO1xuXG5cdFx0XHRcdGNvbnN0IG1lc2ggPSBuZXcgTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cdFx0XHRcdHNjZW5lLmFkZCggbWVzaCApO1xuXHRcdFx0XHQqL1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IHRyYW5zbWlzc2lvblJlbmRlclRhcmdldCA9IGN1cnJlbnRSZW5kZXJTdGF0ZS5zdGF0ZS50cmFuc21pc3Npb25SZW5kZXJUYXJnZXRbIGNhbWVyYS5pZCBdO1xuXG5cdFx0XHRjb25zdCBhY3RpdmVWaWV3cG9ydCA9IGNhbWVyYS52aWV3cG9ydCB8fCBfY3VycmVudFZpZXdwb3J0O1xuXHRcdFx0dHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0LnNldFNpemUoIGFjdGl2ZVZpZXdwb3J0LnosIGFjdGl2ZVZpZXdwb3J0LncgKTtcblxuXHRcdFx0Ly9cblxuXHRcdFx0Y29uc3QgY3VycmVudFJlbmRlclRhcmdldCA9IF90aGlzLmdldFJlbmRlclRhcmdldCgpO1xuXHRcdFx0X3RoaXMuc2V0UmVuZGVyVGFyZ2V0KCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0X3RoaXMuZ2V0Q2xlYXJDb2xvciggX2N1cnJlbnRDbGVhckNvbG9yICk7XG5cdFx0XHRfY3VycmVudENsZWFyQWxwaGEgPSBfdGhpcy5nZXRDbGVhckFscGhhKCk7XG5cdFx0XHRpZiAoIF9jdXJyZW50Q2xlYXJBbHBoYSA8IDEgKSBfdGhpcy5zZXRDbGVhckNvbG9yKCAweGZmZmZmZiwgMC41ICk7XG5cblx0XHRcdF90aGlzLmNsZWFyKCk7XG5cblx0XHRcdGlmICggX3JlbmRlckJhY2tncm91bmQgKSBiYWNrZ3JvdW5kLnJlbmRlciggc2NlbmUgKTtcblxuXHRcdFx0Ly8gVHVybiBvZmYgdGhlIGZlYXR1cmVzIHdoaWNoIGNhbiBhZmZlY3QgdGhlIGZyYWcgY29sb3IgZm9yIG9wYXF1ZSBvYmplY3RzIHBhc3MuXG5cdFx0XHQvLyBPdGhlcndpc2UgdGhleSBhcmUgYXBwbGllZCB0d2ljZSBpbiBvcGFxdWUgb2JqZWN0cyBwYXNzIGFuZCB0cmFuc21pc3Npb24gb2JqZWN0cyBwYXNzLlxuXHRcdFx0Y29uc3QgY3VycmVudFRvbmVNYXBwaW5nID0gX3RoaXMudG9uZU1hcHBpbmc7XG5cdFx0XHRfdGhpcy50b25lTWFwcGluZyA9IE5vVG9uZU1hcHBpbmc7XG5cblx0XHRcdC8vIFJlbW92ZSB2aWV3cG9ydCBmcm9tIGNhbWVyYSB0byBhdm9pZCBuZXN0ZWQgcmVuZGVyIGNhbGxzIHJlc2V0dGluZyB2aWV3cG9ydCB0byBpdCAoZS5nIFJlZmxlY3RvcikuXG5cdFx0XHQvLyBUcmFuc21pc3Npb24gcmVuZGVyIHBhc3MgcmVxdWlyZXMgdmlld3BvcnQgdG8gbWF0Y2ggdGhlIHRyYW5zbWlzc2lvblJlbmRlclRhcmdldC5cblx0XHRcdGNvbnN0IGN1cnJlbnRDYW1lcmFWaWV3cG9ydCA9IGNhbWVyYS52aWV3cG9ydDtcblx0XHRcdGlmICggY2FtZXJhLnZpZXdwb3J0ICE9PSB1bmRlZmluZWQgKSBjYW1lcmEudmlld3BvcnQgPSB1bmRlZmluZWQ7XG5cblx0XHRcdGN1cnJlbnRSZW5kZXJTdGF0ZS5zZXR1cExpZ2h0c1ZpZXcoIGNhbWVyYSApO1xuXG5cdFx0XHRpZiAoIF9jbGlwcGluZ0VuYWJsZWQgPT09IHRydWUgKSBjbGlwcGluZy5zZXRHbG9iYWxTdGF0ZSggX3RoaXMuY2xpcHBpbmdQbGFuZXMsIGNhbWVyYSApO1xuXG5cdFx0XHRyZW5kZXJPYmplY3RzKCBvcGFxdWVPYmplY3RzLCBzY2VuZSwgY2FtZXJhICk7XG5cblx0XHRcdHRleHR1cmVzLnVwZGF0ZU11bHRpc2FtcGxlUmVuZGVyVGFyZ2V0KCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKTtcblx0XHRcdHRleHR1cmVzLnVwZGF0ZVJlbmRlclRhcmdldE1pcG1hcCggdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRcdGlmICggZXh0ZW5zaW9ucy5oYXMoICdXRUJHTF9tdWx0aXNhbXBsZWRfcmVuZGVyX3RvX3RleHR1cmUnICkgPT09IGZhbHNlICkgeyAvLyBzZWUgIzI4MTMxXG5cblx0XHRcdFx0bGV0IHJlbmRlclRhcmdldE5lZWRzVXBkYXRlID0gZmFsc2U7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdHJhbnNtaXNzaXZlT2JqZWN0cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgcmVuZGVySXRlbSA9IHRyYW5zbWlzc2l2ZU9iamVjdHNbIGkgXTtcblxuXHRcdFx0XHRcdGNvbnN0IG9iamVjdCA9IHJlbmRlckl0ZW0ub2JqZWN0O1xuXHRcdFx0XHRcdGNvbnN0IGdlb21ldHJ5ID0gcmVuZGVySXRlbS5nZW9tZXRyeTtcblx0XHRcdFx0XHRjb25zdCBtYXRlcmlhbCA9IHJlbmRlckl0ZW0ubWF0ZXJpYWw7XG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXAgPSByZW5kZXJJdGVtLmdyb3VwO1xuXG5cdFx0XHRcdFx0aWYgKCBtYXRlcmlhbC5zaWRlID09PSBEb3VibGVTaWRlICYmIG9iamVjdC5sYXllcnMudGVzdCggY2FtZXJhLmxheWVycyApICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBjdXJyZW50U2lkZSA9IG1hdGVyaWFsLnNpZGU7XG5cblx0XHRcdFx0XHRcdG1hdGVyaWFsLnNpZGUgPSBCYWNrU2lkZTtcblx0XHRcdFx0XHRcdG1hdGVyaWFsLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdFx0XHRcdFx0cmVuZGVyT2JqZWN0KCBvYmplY3QsIHNjZW5lLCBjYW1lcmEsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXAgKTtcblxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwuc2lkZSA9IGN1cnJlbnRTaWRlO1xuXHRcdFx0XHRcdFx0bWF0ZXJpYWwubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0XHRcdFx0XHRyZW5kZXJUYXJnZXROZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0TmVlZHNVcGRhdGUgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHR0ZXh0dXJlcy51cGRhdGVNdWx0aXNhbXBsZVJlbmRlclRhcmdldCggdHJhbnNtaXNzaW9uUmVuZGVyVGFyZ2V0ICk7XG5cdFx0XHRcdFx0dGV4dHVyZXMudXBkYXRlUmVuZGVyVGFyZ2V0TWlwbWFwKCB0cmFuc21pc3Npb25SZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0X3RoaXMuc2V0UmVuZGVyVGFyZ2V0KCBjdXJyZW50UmVuZGVyVGFyZ2V0ICk7XG5cblx0XHRcdF90aGlzLnNldENsZWFyQ29sb3IoIF9jdXJyZW50Q2xlYXJDb2xvciwgX2N1cnJlbnRDbGVhckFscGhhICk7XG5cblx0XHRcdGlmICggY3VycmVudENhbWVyYVZpZXdwb3J0ICE9PSB1bmRlZmluZWQgKSBjYW1lcmEudmlld3BvcnQgPSBjdXJyZW50Q2FtZXJhVmlld3BvcnQ7XG5cblx0XHRcdF90aGlzLnRvbmVNYXBwaW5nID0gY3VycmVudFRvbmVNYXBwaW5nO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gcmVuZGVyT2JqZWN0cyggcmVuZGVyTGlzdCwgc2NlbmUsIGNhbWVyYSApIHtcblxuXHRcdFx0Y29uc3Qgb3ZlcnJpZGVNYXRlcmlhbCA9IHNjZW5lLmlzU2NlbmUgPT09IHRydWUgPyBzY2VuZS5vdmVycmlkZU1hdGVyaWFsIDogbnVsbDtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gcmVuZGVyTGlzdC5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHJlbmRlckl0ZW0gPSByZW5kZXJMaXN0WyBpIF07XG5cblx0XHRcdFx0Y29uc3Qgb2JqZWN0ID0gcmVuZGVySXRlbS5vYmplY3Q7XG5cdFx0XHRcdGNvbnN0IGdlb21ldHJ5ID0gcmVuZGVySXRlbS5nZW9tZXRyeTtcblx0XHRcdFx0Y29uc3QgbWF0ZXJpYWwgPSBvdmVycmlkZU1hdGVyaWFsID09PSBudWxsID8gcmVuZGVySXRlbS5tYXRlcmlhbCA6IG92ZXJyaWRlTWF0ZXJpYWw7XG5cdFx0XHRcdGNvbnN0IGdyb3VwID0gcmVuZGVySXRlbS5ncm91cDtcblxuXHRcdFx0XHRpZiAoIG9iamVjdC5sYXllcnMudGVzdCggY2FtZXJhLmxheWVycyApICkge1xuXG5cdFx0XHRcdFx0cmVuZGVyT2JqZWN0KCBvYmplY3QsIHNjZW5lLCBjYW1lcmEsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXAgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHJlbmRlck9iamVjdCggb2JqZWN0LCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwICkge1xuXG5cdFx0XHRvYmplY3Qub25CZWZvcmVSZW5kZXIoIF90aGlzLCBzY2VuZSwgY2FtZXJhLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGdyb3VwICk7XG5cblx0XHRcdG9iamVjdC5tb2RlbFZpZXdNYXRyaXgubXVsdGlwbHlNYXRyaWNlcyggY2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSwgb2JqZWN0Lm1hdHJpeFdvcmxkICk7XG5cdFx0XHRvYmplY3Qubm9ybWFsTWF0cml4LmdldE5vcm1hbE1hdHJpeCggb2JqZWN0Lm1vZGVsVmlld01hdHJpeCApO1xuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLnRyYW5zcGFyZW50ID09PSB0cnVlICYmIG1hdGVyaWFsLnNpZGUgPT09IERvdWJsZVNpZGUgJiYgbWF0ZXJpYWwuZm9yY2VTaW5nbGVQYXNzID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHRtYXRlcmlhbC5zaWRlID0gQmFja1NpZGU7XG5cdFx0XHRcdG1hdGVyaWFsLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblx0XHRcdFx0X3RoaXMucmVuZGVyQnVmZmVyRGlyZWN0KCBjYW1lcmEsIHNjZW5lLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIG9iamVjdCwgZ3JvdXAgKTtcblxuXHRcdFx0XHRtYXRlcmlhbC5zaWRlID0gRnJvbnRTaWRlO1xuXHRcdFx0XHRtYXRlcmlhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0XHRcdF90aGlzLnJlbmRlckJ1ZmZlckRpcmVjdCggY2FtZXJhLCBzY2VuZSwgZ2VvbWV0cnksIG1hdGVyaWFsLCBvYmplY3QsIGdyb3VwICk7XG5cblx0XHRcdFx0bWF0ZXJpYWwuc2lkZSA9IERvdWJsZVNpZGU7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0X3RoaXMucmVuZGVyQnVmZmVyRGlyZWN0KCBjYW1lcmEsIHNjZW5lLCBnZW9tZXRyeSwgbWF0ZXJpYWwsIG9iamVjdCwgZ3JvdXAgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRvYmplY3Qub25BZnRlclJlbmRlciggX3RoaXMsIHNjZW5lLCBjYW1lcmEsIGdlb21ldHJ5LCBtYXRlcmlhbCwgZ3JvdXAgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdldFByb2dyYW0oIG1hdGVyaWFsLCBzY2VuZSwgb2JqZWN0ICkge1xuXG5cdFx0XHRpZiAoIHNjZW5lLmlzU2NlbmUgIT09IHRydWUgKSBzY2VuZSA9IF9lbXB0eVNjZW5lOyAvLyBzY2VuZSBjb3VsZCBiZSBhIE1lc2gsIExpbmUsIFBvaW50cywgLi4uXG5cblx0XHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xuXG5cdFx0XHRjb25zdCBsaWdodHMgPSBjdXJyZW50UmVuZGVyU3RhdGUuc3RhdGUubGlnaHRzO1xuXHRcdFx0Y29uc3Qgc2hhZG93c0FycmF5ID0gY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLnNoYWRvd3NBcnJheTtcblxuXHRcdFx0Y29uc3QgbGlnaHRzU3RhdGVWZXJzaW9uID0gbGlnaHRzLnN0YXRlLnZlcnNpb247XG5cblx0XHRcdGNvbnN0IHBhcmFtZXRlcnMgPSBwcm9ncmFtQ2FjaGUuZ2V0UGFyYW1ldGVycyggbWF0ZXJpYWwsIGxpZ2h0cy5zdGF0ZSwgc2hhZG93c0FycmF5LCBzY2VuZSwgb2JqZWN0ICk7XG5cdFx0XHRjb25zdCBwcm9ncmFtQ2FjaGVLZXkgPSBwcm9ncmFtQ2FjaGUuZ2V0UHJvZ3JhbUNhY2hlS2V5KCBwYXJhbWV0ZXJzICk7XG5cblx0XHRcdGxldCBwcm9ncmFtcyA9IG1hdGVyaWFsUHJvcGVydGllcy5wcm9ncmFtcztcblxuXHRcdFx0Ly8gYWx3YXlzIHVwZGF0ZSBlbnZpcm9ubWVudCBhbmQgZm9nIC0gY2hhbmdpbmcgdGhlc2UgdHJpZ2dlciBhbiBnZXRQcm9ncmFtIGNhbGwsIGJ1dCBpdCdzIHBvc3NpYmxlIHRoYXQgdGhlIHByb2dyYW0gZG9lc24ndCBjaGFuZ2VcblxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmVudmlyb25tZW50ID0gbWF0ZXJpYWwuaXNNZXNoU3RhbmRhcmRNYXRlcmlhbCA/IHNjZW5lLmVudmlyb25tZW50IDogbnVsbDtcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5mb2cgPSBzY2VuZS5mb2c7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMuZW52TWFwID0gKCBtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsID8gY3ViZXV2bWFwcyA6IGN1YmVtYXBzICkuZ2V0KCBtYXRlcmlhbC5lbnZNYXAgfHwgbWF0ZXJpYWxQcm9wZXJ0aWVzLmVudmlyb25tZW50ICk7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMuZW52TWFwUm90YXRpb24gPSAoIG1hdGVyaWFsUHJvcGVydGllcy5lbnZpcm9ubWVudCAhPT0gbnVsbCAmJiBtYXRlcmlhbC5lbnZNYXAgPT09IG51bGwgKSA/IHNjZW5lLmVudmlyb25tZW50Um90YXRpb24gOiBtYXRlcmlhbC5lbnZNYXBSb3RhdGlvbjtcblxuXHRcdFx0aWYgKCBwcm9ncmFtcyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdC8vIG5ldyBtYXRlcmlhbFxuXG5cdFx0XHRcdG1hdGVyaWFsLmFkZEV2ZW50TGlzdGVuZXIoICdkaXNwb3NlJywgb25NYXRlcmlhbERpc3Bvc2UgKTtcblxuXHRcdFx0XHRwcm9ncmFtcyA9IG5ldyBNYXAoKTtcblx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnByb2dyYW1zID0gcHJvZ3JhbXM7XG5cblx0XHRcdH1cblxuXHRcdFx0bGV0IHByb2dyYW0gPSBwcm9ncmFtcy5nZXQoIHByb2dyYW1DYWNoZUtleSApO1xuXG5cdFx0XHRpZiAoIHByb2dyYW0gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHQvLyBlYXJseSBvdXQgaWYgcHJvZ3JhbSBhbmQgbGlnaHQgc3RhdGUgaXMgaWRlbnRpY2FsXG5cblx0XHRcdFx0aWYgKCBtYXRlcmlhbFByb3BlcnRpZXMuY3VycmVudFByb2dyYW0gPT09IHByb2dyYW0gJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmxpZ2h0c1N0YXRlVmVyc2lvbiA9PT0gbGlnaHRzU3RhdGVWZXJzaW9uICkge1xuXG5cdFx0XHRcdFx0dXBkYXRlQ29tbW9uTWF0ZXJpYWxQcm9wZXJ0aWVzKCBtYXRlcmlhbCwgcGFyYW1ldGVycyApO1xuXG5cdFx0XHRcdFx0cmV0dXJuIHByb2dyYW07XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdHBhcmFtZXRlcnMudW5pZm9ybXMgPSBwcm9ncmFtQ2FjaGUuZ2V0VW5pZm9ybXMoIG1hdGVyaWFsICk7XG5cblx0XHRcdFx0bWF0ZXJpYWwub25CZWZvcmVDb21waWxlKCBwYXJhbWV0ZXJzLCBfdGhpcyApO1xuXG5cdFx0XHRcdHByb2dyYW0gPSBwcm9ncmFtQ2FjaGUuYWNxdWlyZVByb2dyYW0oIHBhcmFtZXRlcnMsIHByb2dyYW1DYWNoZUtleSApO1xuXHRcdFx0XHRwcm9ncmFtcy5zZXQoIHByb2dyYW1DYWNoZUtleSwgcHJvZ3JhbSApO1xuXG5cdFx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy51bmlmb3JtcyA9IHBhcmFtZXRlcnMudW5pZm9ybXM7XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBtYXRlcmlhbFByb3BlcnRpZXMudW5pZm9ybXM7XG5cblx0XHRcdGlmICggKCAhIG1hdGVyaWFsLmlzU2hhZGVyTWF0ZXJpYWwgJiYgISBtYXRlcmlhbC5pc1Jhd1NoYWRlck1hdGVyaWFsICkgfHwgbWF0ZXJpYWwuY2xpcHBpbmcgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0dW5pZm9ybXMuY2xpcHBpbmdQbGFuZXMgPSBjbGlwcGluZy51bmlmb3JtO1xuXG5cdFx0XHR9XG5cblx0XHRcdHVwZGF0ZUNvbW1vbk1hdGVyaWFsUHJvcGVydGllcyggbWF0ZXJpYWwsIHBhcmFtZXRlcnMgKTtcblxuXHRcdFx0Ly8gc3RvcmUgdGhlIGxpZ2h0IHNldHVwIGl0IHdhcyBjcmVhdGVkIGZvclxuXG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMubmVlZHNMaWdodHMgPSBtYXRlcmlhbE5lZWRzTGlnaHRzKCBtYXRlcmlhbCApO1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmxpZ2h0c1N0YXRlVmVyc2lvbiA9IGxpZ2h0c1N0YXRlVmVyc2lvbjtcblxuXHRcdFx0aWYgKCBtYXRlcmlhbFByb3BlcnRpZXMubmVlZHNMaWdodHMgKSB7XG5cblx0XHRcdFx0Ly8gd2lyZSB1cCB0aGUgbWF0ZXJpYWwgdG8gdGhpcyByZW5kZXJlcidzIGxpZ2h0aW5nIHN0YXRlXG5cblx0XHRcdFx0dW5pZm9ybXMuYW1iaWVudExpZ2h0Q29sb3IudmFsdWUgPSBsaWdodHMuc3RhdGUuYW1iaWVudDtcblx0XHRcdFx0dW5pZm9ybXMubGlnaHRQcm9iZS52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5wcm9iZTtcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uYWxMaWdodHMudmFsdWUgPSBsaWdodHMuc3RhdGUuZGlyZWN0aW9uYWw7XG5cdFx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsTGlnaHRTaGFkb3dzLnZhbHVlID0gbGlnaHRzLnN0YXRlLmRpcmVjdGlvbmFsU2hhZG93O1xuXHRcdFx0XHR1bmlmb3Jtcy5zcG90TGlnaHRzLnZhbHVlID0gbGlnaHRzLnN0YXRlLnNwb3Q7XG5cdFx0XHRcdHVuaWZvcm1zLnNwb3RMaWdodFNoYWRvd3MudmFsdWUgPSBsaWdodHMuc3RhdGUuc3BvdFNoYWRvdztcblx0XHRcdFx0dW5pZm9ybXMucmVjdEFyZWFMaWdodHMudmFsdWUgPSBsaWdodHMuc3RhdGUucmVjdEFyZWE7XG5cdFx0XHRcdHVuaWZvcm1zLmx0Y18xLnZhbHVlID0gbGlnaHRzLnN0YXRlLnJlY3RBcmVhTFRDMTtcblx0XHRcdFx0dW5pZm9ybXMubHRjXzIudmFsdWUgPSBsaWdodHMuc3RhdGUucmVjdEFyZWFMVEMyO1xuXHRcdFx0XHR1bmlmb3Jtcy5wb2ludExpZ2h0cy52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5wb2ludDtcblx0XHRcdFx0dW5pZm9ybXMucG9pbnRMaWdodFNoYWRvd3MudmFsdWUgPSBsaWdodHMuc3RhdGUucG9pbnRTaGFkb3c7XG5cdFx0XHRcdHVuaWZvcm1zLmhlbWlzcGhlcmVMaWdodHMudmFsdWUgPSBsaWdodHMuc3RhdGUuaGVtaTtcblxuXHRcdFx0XHR1bmlmb3Jtcy5kaXJlY3Rpb25hbFNoYWRvd01hcC52YWx1ZSA9IGxpZ2h0cy5zdGF0ZS5kaXJlY3Rpb25hbFNoYWRvd01hcDtcblx0XHRcdFx0dW5pZm9ybXMuZGlyZWN0aW9uYWxTaGFkb3dNYXRyaXgudmFsdWUgPSBsaWdodHMuc3RhdGUuZGlyZWN0aW9uYWxTaGFkb3dNYXRyaXg7XG5cdFx0XHRcdHVuaWZvcm1zLnNwb3RTaGFkb3dNYXAudmFsdWUgPSBsaWdodHMuc3RhdGUuc3BvdFNoYWRvd01hcDtcblx0XHRcdFx0dW5pZm9ybXMuc3BvdExpZ2h0TWF0cml4LnZhbHVlID0gbGlnaHRzLnN0YXRlLnNwb3RMaWdodE1hdHJpeDtcblx0XHRcdFx0dW5pZm9ybXMuc3BvdExpZ2h0TWFwLnZhbHVlID0gbGlnaHRzLnN0YXRlLnNwb3RMaWdodE1hcDtcblx0XHRcdFx0dW5pZm9ybXMucG9pbnRTaGFkb3dNYXAudmFsdWUgPSBsaWdodHMuc3RhdGUucG9pbnRTaGFkb3dNYXA7XG5cdFx0XHRcdHVuaWZvcm1zLnBvaW50U2hhZG93TWF0cml4LnZhbHVlID0gbGlnaHRzLnN0YXRlLnBvaW50U2hhZG93TWF0cml4O1xuXHRcdFx0XHQvLyBUT0RPIChhYmVsbmF0aW9uKTogYWRkIGFyZWEgbGlnaHRzIHNoYWRvdyBpbmZvIHRvIHVuaWZvcm1zXG5cblx0XHRcdH1cblxuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmN1cnJlbnRQcm9ncmFtID0gcHJvZ3JhbTtcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy51bmlmb3Jtc0xpc3QgPSBudWxsO1xuXG5cdFx0XHRyZXR1cm4gcHJvZ3JhbTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdldFVuaWZvcm1MaXN0KCBtYXRlcmlhbFByb3BlcnRpZXMgKSB7XG5cblx0XHRcdGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zTGlzdCA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRjb25zdCBwcm9nVW5pZm9ybXMgPSBtYXRlcmlhbFByb3BlcnRpZXMuY3VycmVudFByb2dyYW0uZ2V0VW5pZm9ybXMoKTtcblx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zTGlzdCA9IFdlYkdMVW5pZm9ybXMuc2VxV2l0aFZhbHVlKCBwcm9nVW5pZm9ybXMuc2VxLCBtYXRlcmlhbFByb3BlcnRpZXMudW5pZm9ybXMgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gbWF0ZXJpYWxQcm9wZXJ0aWVzLnVuaWZvcm1zTGlzdDtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHVwZGF0ZUNvbW1vbk1hdGVyaWFsUHJvcGVydGllcyggbWF0ZXJpYWwsIHBhcmFtZXRlcnMgKSB7XG5cblx0XHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xuXG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMub3V0cHV0Q29sb3JTcGFjZSA9IHBhcmFtZXRlcnMub3V0cHV0Q29sb3JTcGFjZTtcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5iYXRjaGluZyA9IHBhcmFtZXRlcnMuYmF0Y2hpbmc7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMuYmF0Y2hpbmdDb2xvciA9IHBhcmFtZXRlcnMuYmF0Y2hpbmdDb2xvcjtcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5pbnN0YW5jaW5nID0gcGFyYW1ldGVycy5pbnN0YW5jaW5nO1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmdDb2xvciA9IHBhcmFtZXRlcnMuaW5zdGFuY2luZ0NvbG9yO1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmdNb3JwaCA9IHBhcmFtZXRlcnMuaW5zdGFuY2luZ01vcnBoO1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnNraW5uaW5nID0gcGFyYW1ldGVycy5za2lubmluZztcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaFRhcmdldHMgPSBwYXJhbWV0ZXJzLm1vcnBoVGFyZ2V0cztcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaE5vcm1hbHMgPSBwYXJhbWV0ZXJzLm1vcnBoTm9ybWFscztcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaENvbG9ycyA9IHBhcmFtZXRlcnMubW9ycGhDb2xvcnM7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhUYXJnZXRzQ291bnQgPSBwYXJhbWV0ZXJzLm1vcnBoVGFyZ2V0c0NvdW50O1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLm51bUNsaXBwaW5nUGxhbmVzID0gcGFyYW1ldGVycy5udW1DbGlwcGluZ1BsYW5lcztcblx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5udW1JbnRlcnNlY3Rpb24gPSBwYXJhbWV0ZXJzLm51bUNsaXBJbnRlcnNlY3Rpb247XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMudmVydGV4QWxwaGFzID0gcGFyYW1ldGVycy52ZXJ0ZXhBbHBoYXM7XG5cdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMudmVydGV4VGFuZ2VudHMgPSBwYXJhbWV0ZXJzLnZlcnRleFRhbmdlbnRzO1xuXHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnRvbmVNYXBwaW5nID0gcGFyYW1ldGVycy50b25lTWFwcGluZztcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHNldFByb2dyYW0oIGNhbWVyYSwgc2NlbmUsIGdlb21ldHJ5LCBtYXRlcmlhbCwgb2JqZWN0ICkge1xuXG5cdFx0XHRpZiAoIHNjZW5lLmlzU2NlbmUgIT09IHRydWUgKSBzY2VuZSA9IF9lbXB0eVNjZW5lOyAvLyBzY2VuZSBjb3VsZCBiZSBhIE1lc2gsIExpbmUsIFBvaW50cywgLi4uXG5cblx0XHRcdHRleHR1cmVzLnJlc2V0VGV4dHVyZVVuaXRzKCk7XG5cblx0XHRcdGNvbnN0IGZvZyA9IHNjZW5lLmZvZztcblx0XHRcdGNvbnN0IGVudmlyb25tZW50ID0gbWF0ZXJpYWwuaXNNZXNoU3RhbmRhcmRNYXRlcmlhbCA/IHNjZW5lLmVudmlyb25tZW50IDogbnVsbDtcblx0XHRcdGNvbnN0IGNvbG9yU3BhY2UgPSAoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ID09PSBudWxsICkgPyBfdGhpcy5vdXRwdXRDb2xvclNwYWNlIDogKCBfY3VycmVudFJlbmRlclRhcmdldC5pc1hSUmVuZGVyVGFyZ2V0ID09PSB0cnVlID8gX2N1cnJlbnRSZW5kZXJUYXJnZXQudGV4dHVyZS5jb2xvclNwYWNlIDogTGluZWFyU1JHQkNvbG9yU3BhY2UgKTtcblx0XHRcdGNvbnN0IGVudk1hcCA9ICggbWF0ZXJpYWwuaXNNZXNoU3RhbmRhcmRNYXRlcmlhbCA/IGN1YmV1dm1hcHMgOiBjdWJlbWFwcyApLmdldCggbWF0ZXJpYWwuZW52TWFwIHx8IGVudmlyb25tZW50ICk7XG5cdFx0XHRjb25zdCB2ZXJ0ZXhBbHBoYXMgPSBtYXRlcmlhbC52ZXJ0ZXhDb2xvcnMgPT09IHRydWUgJiYgISEgZ2VvbWV0cnkuYXR0cmlidXRlcy5jb2xvciAmJiBnZW9tZXRyeS5hdHRyaWJ1dGVzLmNvbG9yLml0ZW1TaXplID09PSA0O1xuXHRcdFx0Y29uc3QgdmVydGV4VGFuZ2VudHMgPSAhISBnZW9tZXRyeS5hdHRyaWJ1dGVzLnRhbmdlbnQgJiYgKCAhISBtYXRlcmlhbC5ub3JtYWxNYXAgfHwgbWF0ZXJpYWwuYW5pc290cm9weSA+IDAgKTtcblx0XHRcdGNvbnN0IG1vcnBoVGFyZ2V0cyA9ICEhIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5wb3NpdGlvbjtcblx0XHRcdGNvbnN0IG1vcnBoTm9ybWFscyA9ICEhIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5ub3JtYWw7XG5cdFx0XHRjb25zdCBtb3JwaENvbG9ycyA9ICEhIGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5jb2xvcjtcblxuXHRcdFx0bGV0IHRvbmVNYXBwaW5nID0gTm9Ub25lTWFwcGluZztcblxuXHRcdFx0aWYgKCBtYXRlcmlhbC50b25lTWFwcGVkICkge1xuXG5cdFx0XHRcdGlmICggX2N1cnJlbnRSZW5kZXJUYXJnZXQgPT09IG51bGwgfHwgX2N1cnJlbnRSZW5kZXJUYXJnZXQuaXNYUlJlbmRlclRhcmdldCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdHRvbmVNYXBwaW5nID0gX3RoaXMudG9uZU1hcHBpbmc7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLnBvc2l0aW9uIHx8IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcy5ub3JtYWwgfHwgZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLmNvbG9yO1xuXHRcdFx0Y29uc3QgbW9ycGhUYXJnZXRzQ291bnQgPSAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSA/IG1vcnBoQXR0cmlidXRlLmxlbmd0aCA6IDA7XG5cblx0XHRcdGNvbnN0IG1hdGVyaWFsUHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCBtYXRlcmlhbCApO1xuXHRcdFx0Y29uc3QgbGlnaHRzID0gY3VycmVudFJlbmRlclN0YXRlLnN0YXRlLmxpZ2h0cztcblxuXHRcdFx0aWYgKCBfY2xpcHBpbmdFbmFibGVkID09PSB0cnVlICkge1xuXG5cdFx0XHRcdGlmICggX2xvY2FsQ2xpcHBpbmdFbmFibGVkID09PSB0cnVlIHx8IGNhbWVyYSAhPT0gX2N1cnJlbnRDYW1lcmEgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB1c2VDYWNoZSA9XG5cdFx0XHRcdFx0XHRjYW1lcmEgPT09IF9jdXJyZW50Q2FtZXJhICYmXG5cdFx0XHRcdFx0XHRtYXRlcmlhbC5pZCA9PT0gX2N1cnJlbnRNYXRlcmlhbElkO1xuXG5cdFx0XHRcdFx0Ly8gd2UgbWlnaHQgd2FudCB0byBjYWxsIHRoaXMgZnVuY3Rpb24gd2l0aCBzb21lIENsaXBwaW5nR3JvdXBcblx0XHRcdFx0XHQvLyBvYmplY3QgaW5zdGVhZCBvZiB0aGUgbWF0ZXJpYWwsIG9uY2UgaXQgYmVjb21lcyBmZWFzaWJsZVxuXHRcdFx0XHRcdC8vICgjODQ2NSwgIzgzNzkpXG5cdFx0XHRcdFx0Y2xpcHBpbmcuc2V0U3RhdGUoIG1hdGVyaWFsLCBjYW1lcmEsIHVzZUNhY2hlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdC8vXG5cblx0XHRcdGxldCBuZWVkc1Byb2dyYW1DaGFuZ2UgPSBmYWxzZTtcblxuXHRcdFx0aWYgKCBtYXRlcmlhbC52ZXJzaW9uID09PSBtYXRlcmlhbFByb3BlcnRpZXMuX192ZXJzaW9uICkge1xuXG5cdFx0XHRcdGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm5lZWRzTGlnaHRzICYmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLmxpZ2h0c1N0YXRlVmVyc2lvbiAhPT0gbGlnaHRzLnN0YXRlLnZlcnNpb24gKSApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm91dHB1dENvbG9yU3BhY2UgIT09IGNvbG9yU3BhY2UgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0JhdGNoZWRNZXNoICYmIG1hdGVyaWFsUHJvcGVydGllcy5iYXRjaGluZyA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoICEgb2JqZWN0LmlzQmF0Y2hlZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmJhdGNoaW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNCYXRjaGVkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuYmF0Y2hpbmdDb2xvciA9PT0gdHJ1ZSAmJiBvYmplY3QuY29sb3JUZXh0dXJlID09PSBudWxsICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBvYmplY3QuaXNCYXRjaGVkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuYmF0Y2hpbmdDb2xvciA9PT0gZmFsc2UgJiYgb2JqZWN0LmNvbG9yVGV4dHVyZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuaW5zdGFuY2luZyA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoICEgb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuaW5zdGFuY2luZyA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzU2tpbm5lZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLnNraW5uaW5nID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggISBvYmplY3QuaXNTa2lubmVkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuc2tpbm5pbmcgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmdDb2xvciA9PT0gdHJ1ZSAmJiBvYmplY3QuaW5zdGFuY2VDb2xvciA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuaW5zdGFuY2luZ0NvbG9yID09PSBmYWxzZSAmJiBvYmplY3QuaW5zdGFuY2VDb2xvciAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggb2JqZWN0LmlzSW5zdGFuY2VkTWVzaCAmJiBtYXRlcmlhbFByb3BlcnRpZXMuaW5zdGFuY2luZ01vcnBoID09PSB0cnVlICYmIG9iamVjdC5tb3JwaFRleHR1cmUgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG9iamVjdC5pc0luc3RhbmNlZE1lc2ggJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmluc3RhbmNpbmdNb3JwaCA9PT0gZmFsc2UgJiYgb2JqZWN0Lm1vcnBoVGV4dHVyZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLmVudk1hcCAhPT0gZW52TWFwICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbC5mb2cgPT09IHRydWUgJiYgbWF0ZXJpYWxQcm9wZXJ0aWVzLmZvZyAhPT0gZm9nICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbFByb3BlcnRpZXMubnVtQ2xpcHBpbmdQbGFuZXMgIT09IHVuZGVmaW5lZCAmJlxuXHRcdFx0XHRcdCggbWF0ZXJpYWxQcm9wZXJ0aWVzLm51bUNsaXBwaW5nUGxhbmVzICE9PSBjbGlwcGluZy5udW1QbGFuZXMgfHxcblx0XHRcdFx0XHRtYXRlcmlhbFByb3BlcnRpZXMubnVtSW50ZXJzZWN0aW9uICE9PSBjbGlwcGluZy5udW1JbnRlcnNlY3Rpb24gKSApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLnZlcnRleEFscGhhcyAhPT0gdmVydGV4QWxwaGFzICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbFByb3BlcnRpZXMudmVydGV4VGFuZ2VudHMgIT09IHZlcnRleFRhbmdlbnRzICkge1xuXG5cdFx0XHRcdFx0bmVlZHNQcm9ncmFtQ2hhbmdlID0gdHJ1ZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBtYXRlcmlhbFByb3BlcnRpZXMubW9ycGhUYXJnZXRzICE9PSBtb3JwaFRhcmdldHMgKSB7XG5cblx0XHRcdFx0XHRuZWVkc1Byb2dyYW1DaGFuZ2UgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIG1hdGVyaWFsUHJvcGVydGllcy5tb3JwaE5vcm1hbHMgIT09IG1vcnBoTm9ybWFscyApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm1vcnBoQ29sb3JzICE9PSBtb3JwaENvbG9ycyApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLnRvbmVNYXBwaW5nICE9PSB0b25lTWFwcGluZyApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm1vcnBoVGFyZ2V0c0NvdW50ICE9PSBtb3JwaFRhcmdldHNDb3VudCApIHtcblxuXHRcdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdG5lZWRzUHJvZ3JhbUNoYW5nZSA9IHRydWU7XG5cdFx0XHRcdG1hdGVyaWFsUHJvcGVydGllcy5fX3ZlcnNpb24gPSBtYXRlcmlhbC52ZXJzaW9uO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vXG5cblx0XHRcdGxldCBwcm9ncmFtID0gbWF0ZXJpYWxQcm9wZXJ0aWVzLmN1cnJlbnRQcm9ncmFtO1xuXG5cdFx0XHRpZiAoIG5lZWRzUHJvZ3JhbUNoYW5nZSA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0XHRwcm9ncmFtID0gZ2V0UHJvZ3JhbSggbWF0ZXJpYWwsIHNjZW5lLCBvYmplY3QgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRsZXQgcmVmcmVzaFByb2dyYW0gPSBmYWxzZTtcblx0XHRcdGxldCByZWZyZXNoTWF0ZXJpYWwgPSBmYWxzZTtcblx0XHRcdGxldCByZWZyZXNoTGlnaHRzID0gZmFsc2U7XG5cblx0XHRcdGNvbnN0IHBfdW5pZm9ybXMgPSBwcm9ncmFtLmdldFVuaWZvcm1zKCksXG5cdFx0XHRcdG1fdW5pZm9ybXMgPSBtYXRlcmlhbFByb3BlcnRpZXMudW5pZm9ybXM7XG5cblx0XHRcdGlmICggc3RhdGUudXNlUHJvZ3JhbSggcHJvZ3JhbS5wcm9ncmFtICkgKSB7XG5cblx0XHRcdFx0cmVmcmVzaFByb2dyYW0gPSB0cnVlO1xuXHRcdFx0XHRyZWZyZXNoTWF0ZXJpYWwgPSB0cnVlO1xuXHRcdFx0XHRyZWZyZXNoTGlnaHRzID0gdHJ1ZTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlkICE9PSBfY3VycmVudE1hdGVyaWFsSWQgKSB7XG5cblx0XHRcdFx0X2N1cnJlbnRNYXRlcmlhbElkID0gbWF0ZXJpYWwuaWQ7XG5cblx0XHRcdFx0cmVmcmVzaE1hdGVyaWFsID0gdHJ1ZTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHJlZnJlc2hQcm9ncmFtIHx8IF9jdXJyZW50Q2FtZXJhICE9PSBjYW1lcmEgKSB7XG5cblx0XHRcdFx0Ly8gY29tbW9uIGNhbWVyYSB1bmlmb3Jtc1xuXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ3Byb2plY3Rpb25NYXRyaXgnLCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeCApO1xuXHRcdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICd2aWV3TWF0cml4JywgY2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSApO1xuXG5cdFx0XHRcdGNvbnN0IHVDYW1Qb3MgPSBwX3VuaWZvcm1zLm1hcC5jYW1lcmFQb3NpdGlvbjtcblxuXHRcdFx0XHRpZiAoIHVDYW1Qb3MgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdHVDYW1Qb3Muc2V0VmFsdWUoIF9nbCwgX3ZlY3RvcjMuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBjYW1lcmEubWF0cml4V29ybGQgKSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIGNhcGFiaWxpdGllcy5sb2dhcml0aG1pY0RlcHRoQnVmZmVyICkge1xuXG5cdFx0XHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnbG9nRGVwdGhCdWZGQycsXG5cdFx0XHRcdFx0XHQyLjAgLyAoIE1hdGgubG9nKCBjYW1lcmEuZmFyICsgMS4wICkgLyBNYXRoLkxOMiApICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIGNvbnNpZGVyIG1vdmluZyBpc09ydGhvZ3JhcGhpYyB0byBVbmlmb3JtTGliIGFuZCBXZWJHTE1hdGVyaWFscywgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvcHVsbC8yNjQ2NyNpc3N1ZWNvbW1lbnQtMTY0NTE4NTA2N1xuXG5cdFx0XHRcdGlmICggbWF0ZXJpYWwuaXNNZXNoUGhvbmdNYXRlcmlhbCB8fFxuXHRcdFx0XHRcdG1hdGVyaWFsLmlzTWVzaFRvb25NYXRlcmlhbCB8fFxuXHRcdFx0XHRcdG1hdGVyaWFsLmlzTWVzaExhbWJlcnRNYXRlcmlhbCB8fFxuXHRcdFx0XHRcdG1hdGVyaWFsLmlzTWVzaEJhc2ljTWF0ZXJpYWwgfHxcblx0XHRcdFx0XHRtYXRlcmlhbC5pc01lc2hTdGFuZGFyZE1hdGVyaWFsIHx8XG5cdFx0XHRcdFx0bWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCApIHtcblxuXHRcdFx0XHRcdHBfdW5pZm9ybXMuc2V0VmFsdWUoIF9nbCwgJ2lzT3J0aG9ncmFwaGljJywgY2FtZXJhLmlzT3J0aG9ncmFwaGljQ2FtZXJhID09PSB0cnVlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggX2N1cnJlbnRDYW1lcmEgIT09IGNhbWVyYSApIHtcblxuXHRcdFx0XHRcdF9jdXJyZW50Q2FtZXJhID0gY2FtZXJhO1xuXG5cdFx0XHRcdFx0Ly8gbGlnaHRpbmcgdW5pZm9ybXMgZGVwZW5kIG9uIHRoZSBjYW1lcmEgc28gZW5mb3JjZSBhbiB1cGRhdGVcblx0XHRcdFx0XHQvLyBub3csIGluIGNhc2UgdGhpcyBtYXRlcmlhbCBzdXBwb3J0cyBsaWdodHMgLSBvciBsYXRlciwgd2hlblxuXHRcdFx0XHRcdC8vIHRoZSBuZXh0IG1hdGVyaWFsIHRoYXQgZG9lcyBnZXRzIGFjdGl2YXRlZDpcblxuXHRcdFx0XHRcdHJlZnJlc2hNYXRlcmlhbCA9IHRydWU7XHRcdC8vIHNldCB0byB0cnVlIG9uIG1hdGVyaWFsIGNoYW5nZVxuXHRcdFx0XHRcdHJlZnJlc2hMaWdodHMgPSB0cnVlO1x0XHQvLyByZW1haW5zIHNldCB1bnRpbCB1cGRhdGUgZG9uZVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBza2lubmluZyBhbmQgbW9ycGggdGFyZ2V0IHVuaWZvcm1zIG11c3QgYmUgc2V0IGV2ZW4gaWYgbWF0ZXJpYWwgZGlkbid0IGNoYW5nZVxuXHRcdFx0Ly8gYXV0by1zZXR0aW5nIG9mIHRleHR1cmUgdW5pdCBmb3IgYm9uZSBhbmQgbW9ycGggdGV4dHVyZSBtdXN0IGdvIGJlZm9yZSBvdGhlciB0ZXh0dXJlc1xuXHRcdFx0Ly8gb3RoZXJ3aXNlIHRleHR1cmVzIHVzZWQgZm9yIHNraW5uaW5nIGFuZCBtb3JwaGluZyBjYW4gdGFrZSBvdmVyIHRleHR1cmUgdW5pdHMgcmVzZXJ2ZWQgZm9yIG90aGVyIG1hdGVyaWFsIHRleHR1cmVzXG5cblx0XHRcdGlmICggb2JqZWN0LmlzU2tpbm5lZE1lc2ggKSB7XG5cblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRPcHRpb25hbCggX2dsLCBvYmplY3QsICdiaW5kTWF0cml4JyApO1xuXHRcdFx0XHRwX3VuaWZvcm1zLnNldE9wdGlvbmFsKCBfZ2wsIG9iamVjdCwgJ2JpbmRNYXRyaXhJbnZlcnNlJyApO1xuXG5cdFx0XHRcdGNvbnN0IHNrZWxldG9uID0gb2JqZWN0LnNrZWxldG9uO1xuXG5cdFx0XHRcdGlmICggc2tlbGV0b24gKSB7XG5cblx0XHRcdFx0XHRpZiAoIHNrZWxldG9uLmJvbmVUZXh0dXJlID09PSBudWxsICkgc2tlbGV0b24uY29tcHV0ZUJvbmVUZXh0dXJlKCk7XG5cblx0XHRcdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdib25lVGV4dHVyZScsIHNrZWxldG9uLmJvbmVUZXh0dXJlLCB0ZXh0dXJlcyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG9iamVjdC5pc0JhdGNoZWRNZXNoICkge1xuXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0T3B0aW9uYWwoIF9nbCwgb2JqZWN0LCAnYmF0Y2hpbmdUZXh0dXJlJyApO1xuXHRcdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdiYXRjaGluZ1RleHR1cmUnLCBvYmplY3QuX21hdHJpY2VzVGV4dHVyZSwgdGV4dHVyZXMgKTtcblxuXHRcdFx0XHRwX3VuaWZvcm1zLnNldE9wdGlvbmFsKCBfZ2wsIG9iamVjdCwgJ2JhdGNoaW5nSWRUZXh0dXJlJyApO1xuXHRcdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdiYXRjaGluZ0lkVGV4dHVyZScsIG9iamVjdC5faW5kaXJlY3RUZXh0dXJlLCB0ZXh0dXJlcyApO1xuXG5cdFx0XHRcdHBfdW5pZm9ybXMuc2V0T3B0aW9uYWwoIF9nbCwgb2JqZWN0LCAnYmF0Y2hpbmdDb2xvclRleHR1cmUnICk7XG5cdFx0XHRcdGlmICggb2JqZWN0Ll9jb2xvcnNUZXh0dXJlICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnYmF0Y2hpbmdDb2xvclRleHR1cmUnLCBvYmplY3QuX2NvbG9yc1RleHR1cmUsIHRleHR1cmVzICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlcyA9IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcztcblxuXHRcdFx0aWYgKCBtb3JwaEF0dHJpYnV0ZXMucG9zaXRpb24gIT09IHVuZGVmaW5lZCB8fCBtb3JwaEF0dHJpYnV0ZXMubm9ybWFsICE9PSB1bmRlZmluZWQgfHwgKCBtb3JwaEF0dHJpYnV0ZXMuY29sb3IgIT09IHVuZGVmaW5lZCApICkge1xuXG5cdFx0XHRcdG1vcnBodGFyZ2V0cy51cGRhdGUoIG9iamVjdCwgZ2VvbWV0cnksIHByb2dyYW0gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHJlZnJlc2hNYXRlcmlhbCB8fCBtYXRlcmlhbFByb3BlcnRpZXMucmVjZWl2ZVNoYWRvdyAhPT0gb2JqZWN0LnJlY2VpdmVTaGFkb3cgKSB7XG5cblx0XHRcdFx0bWF0ZXJpYWxQcm9wZXJ0aWVzLnJlY2VpdmVTaGFkb3cgPSBvYmplY3QucmVjZWl2ZVNoYWRvdztcblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAncmVjZWl2ZVNoYWRvdycsIG9iamVjdC5yZWNlaXZlU2hhZG93ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gaHR0cHM6Ly9naXRodWIuY29tL21yZG9vYi90aHJlZS5qcy9wdWxsLzI0NDY3I2lzc3VlY29tbWVudC0xMjA5MDMxNTEyXG5cblx0XHRcdGlmICggbWF0ZXJpYWwuaXNNZXNoR291cmF1ZE1hdGVyaWFsICYmIG1hdGVyaWFsLmVudk1hcCAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRtX3VuaWZvcm1zLmVudk1hcC52YWx1ZSA9IGVudk1hcDtcblxuXHRcdFx0XHRtX3VuaWZvcm1zLmZsaXBFbnZNYXAudmFsdWUgPSAoIGVudk1hcC5pc0N1YmVUZXh0dXJlICYmIGVudk1hcC5pc1JlbmRlclRhcmdldFRleHR1cmUgPT09IGZhbHNlICkgPyAtIDEgOiAxO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuaXNNZXNoU3RhbmRhcmRNYXRlcmlhbCAmJiBtYXRlcmlhbC5lbnZNYXAgPT09IG51bGwgJiYgc2NlbmUuZW52aXJvbm1lbnQgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0bV91bmlmb3Jtcy5lbnZNYXBJbnRlbnNpdHkudmFsdWUgPSBzY2VuZS5lbnZpcm9ubWVudEludGVuc2l0eTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHJlZnJlc2hNYXRlcmlhbCApIHtcblxuXHRcdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICd0b25lTWFwcGluZ0V4cG9zdXJlJywgX3RoaXMudG9uZU1hcHBpbmdFeHBvc3VyZSApO1xuXG5cdFx0XHRcdGlmICggbWF0ZXJpYWxQcm9wZXJ0aWVzLm5lZWRzTGlnaHRzICkge1xuXG5cdFx0XHRcdFx0Ly8gdGhlIGN1cnJlbnQgbWF0ZXJpYWwgcmVxdWlyZXMgbGlnaHRpbmcgaW5mb1xuXG5cdFx0XHRcdFx0Ly8gbm90ZTogYWxsIGxpZ2h0aW5nIHVuaWZvcm1zIGFyZSBhbHdheXMgc2V0IGNvcnJlY3RseVxuXHRcdFx0XHRcdC8vIHRoZXkgc2ltcGx5IHJlZmVyZW5jZSB0aGUgcmVuZGVyZXIncyBzdGF0ZSBmb3IgdGhlaXJcblx0XHRcdFx0XHQvLyB2YWx1ZXNcblx0XHRcdFx0XHQvL1xuXHRcdFx0XHRcdC8vIHVzZSB0aGUgY3VycmVudCBtYXRlcmlhbCdzIC5uZWVkc1VwZGF0ZSBmbGFncyB0byBzZXRcblx0XHRcdFx0XHQvLyB0aGUgR0wgc3RhdGUgd2hlbiByZXF1aXJlZFxuXG5cdFx0XHRcdFx0bWFya1VuaWZvcm1zTGlnaHRzTmVlZHNVcGRhdGUoIG1fdW5pZm9ybXMsIHJlZnJlc2hMaWdodHMgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gcmVmcmVzaCB1bmlmb3JtcyBjb21tb24gdG8gc2V2ZXJhbCBtYXRlcmlhbHNcblxuXHRcdFx0XHRpZiAoIGZvZyAmJiBtYXRlcmlhbC5mb2cgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0XHRtYXRlcmlhbHMucmVmcmVzaEZvZ1VuaWZvcm1zKCBtX3VuaWZvcm1zLCBmb2cgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0bWF0ZXJpYWxzLnJlZnJlc2hNYXRlcmlhbFVuaWZvcm1zKCBtX3VuaWZvcm1zLCBtYXRlcmlhbCwgX3BpeGVsUmF0aW8sIF9oZWlnaHQsIGN1cnJlbnRSZW5kZXJTdGF0ZS5zdGF0ZS50cmFuc21pc3Npb25SZW5kZXJUYXJnZXRbIGNhbWVyYS5pZCBdICk7XG5cblx0XHRcdFx0V2ViR0xVbmlmb3Jtcy51cGxvYWQoIF9nbCwgZ2V0VW5pZm9ybUxpc3QoIG1hdGVyaWFsUHJvcGVydGllcyApLCBtX3VuaWZvcm1zLCB0ZXh0dXJlcyApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggbWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCAmJiBtYXRlcmlhbC51bmlmb3Jtc05lZWRVcGRhdGUgPT09IHRydWUgKSB7XG5cblx0XHRcdFx0V2ViR0xVbmlmb3Jtcy51cGxvYWQoIF9nbCwgZ2V0VW5pZm9ybUxpc3QoIG1hdGVyaWFsUHJvcGVydGllcyApLCBtX3VuaWZvcm1zLCB0ZXh0dXJlcyApO1xuXHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc05lZWRVcGRhdGUgPSBmYWxzZTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG1hdGVyaWFsLmlzU3ByaXRlTWF0ZXJpYWwgKSB7XG5cblx0XHRcdFx0cF91bmlmb3Jtcy5zZXRWYWx1ZSggX2dsLCAnY2VudGVyJywgb2JqZWN0LmNlbnRlciApO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGNvbW1vbiBtYXRyaWNlc1xuXG5cdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdtb2RlbFZpZXdNYXRyaXgnLCBvYmplY3QubW9kZWxWaWV3TWF0cml4ICk7XG5cdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdub3JtYWxNYXRyaXgnLCBvYmplY3Qubm9ybWFsTWF0cml4ICk7XG5cdFx0XHRwX3VuaWZvcm1zLnNldFZhbHVlKCBfZ2wsICdtb2RlbE1hdHJpeCcsIG9iamVjdC5tYXRyaXhXb3JsZCApO1xuXG5cdFx0XHQvLyBVQk9zXG5cblx0XHRcdGlmICggbWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCB8fCBtYXRlcmlhbC5pc1Jhd1NoYWRlck1hdGVyaWFsICkge1xuXG5cdFx0XHRcdGNvbnN0IGdyb3VwcyA9IG1hdGVyaWFsLnVuaWZvcm1zR3JvdXBzO1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGdyb3Vwcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcblxuXHRcdFx0XHRcdHVuaWZvcm1zR3JvdXBzLnVwZGF0ZSggZ3JvdXAsIHByb2dyYW0gKTtcblx0XHRcdFx0XHR1bmlmb3Jtc0dyb3Vwcy5iaW5kKCBncm91cCwgcHJvZ3JhbSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gcHJvZ3JhbTtcblxuXHRcdH1cblxuXHRcdC8vIElmIHVuaWZvcm1zIGFyZSBtYXJrZWQgYXMgY2xlYW4sIHRoZXkgZG9uJ3QgbmVlZCB0byBiZSBsb2FkZWQgdG8gdGhlIEdQVS5cblxuXHRcdGZ1bmN0aW9uIG1hcmtVbmlmb3Jtc0xpZ2h0c05lZWRzVXBkYXRlKCB1bmlmb3JtcywgdmFsdWUgKSB7XG5cblx0XHRcdHVuaWZvcm1zLmFtYmllbnRMaWdodENvbG9yLm5lZWRzVXBkYXRlID0gdmFsdWU7XG5cdFx0XHR1bmlmb3Jtcy5saWdodFByb2JlLm5lZWRzVXBkYXRlID0gdmFsdWU7XG5cblx0XHRcdHVuaWZvcm1zLmRpcmVjdGlvbmFsTGlnaHRzLm5lZWRzVXBkYXRlID0gdmFsdWU7XG5cdFx0XHR1bmlmb3Jtcy5kaXJlY3Rpb25hbExpZ2h0U2hhZG93cy5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xuXHRcdFx0dW5pZm9ybXMucG9pbnRMaWdodHMubmVlZHNVcGRhdGUgPSB2YWx1ZTtcblx0XHRcdHVuaWZvcm1zLnBvaW50TGlnaHRTaGFkb3dzLm5lZWRzVXBkYXRlID0gdmFsdWU7XG5cdFx0XHR1bmlmb3Jtcy5zcG90TGlnaHRzLm5lZWRzVXBkYXRlID0gdmFsdWU7XG5cdFx0XHR1bmlmb3Jtcy5zcG90TGlnaHRTaGFkb3dzLm5lZWRzVXBkYXRlID0gdmFsdWU7XG5cdFx0XHR1bmlmb3Jtcy5yZWN0QXJlYUxpZ2h0cy5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xuXHRcdFx0dW5pZm9ybXMuaGVtaXNwaGVyZUxpZ2h0cy5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gbWF0ZXJpYWxOZWVkc0xpZ2h0cyggbWF0ZXJpYWwgKSB7XG5cblx0XHRcdHJldHVybiBtYXRlcmlhbC5pc01lc2hMYW1iZXJ0TWF0ZXJpYWwgfHwgbWF0ZXJpYWwuaXNNZXNoVG9vbk1hdGVyaWFsIHx8IG1hdGVyaWFsLmlzTWVzaFBob25nTWF0ZXJpYWwgfHxcblx0XHRcdFx0bWF0ZXJpYWwuaXNNZXNoU3RhbmRhcmRNYXRlcmlhbCB8fCBtYXRlcmlhbC5pc1NoYWRvd01hdGVyaWFsIHx8XG5cdFx0XHRcdCggbWF0ZXJpYWwuaXNTaGFkZXJNYXRlcmlhbCAmJiBtYXRlcmlhbC5saWdodHMgPT09IHRydWUgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuZ2V0QWN0aXZlQ3ViZUZhY2UgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBfY3VycmVudEFjdGl2ZUN1YmVGYWNlO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0QWN0aXZlTWlwbWFwTGV2ZWwgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHJldHVybiBfY3VycmVudEFjdGl2ZU1pcG1hcExldmVsO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuZ2V0UmVuZGVyVGFyZ2V0ID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gX2N1cnJlbnRSZW5kZXJUYXJnZXQ7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5zZXRSZW5kZXJUYXJnZXRUZXh0dXJlcyA9IGZ1bmN0aW9uICggcmVuZGVyVGFyZ2V0LCBjb2xvclRleHR1cmUsIGRlcHRoVGV4dHVyZSApIHtcblxuXHRcdFx0cHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldC50ZXh0dXJlICkuX193ZWJnbFRleHR1cmUgPSBjb2xvclRleHR1cmU7XG5cdFx0XHRwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0LmRlcHRoVGV4dHVyZSApLl9fd2ViZ2xUZXh0dXJlID0gZGVwdGhUZXh0dXJlO1xuXG5cdFx0XHRjb25zdCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApO1xuXHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX2hhc0V4dGVybmFsVGV4dHVyZXMgPSB0cnVlO1xuXG5cdFx0XHRyZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fYXV0b0FsbG9jYXRlRGVwdGhCdWZmZXIgPSBkZXB0aFRleHR1cmUgPT09IHVuZGVmaW5lZDtcblxuXHRcdFx0aWYgKCAhIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX19hdXRvQWxsb2NhdGVEZXB0aEJ1ZmZlciApIHtcblxuXHRcdFx0XHQvLyBUaGUgbXVsdGlzYW1wbGVfcmVuZGVyX3RvX3RleHR1cmUgZXh0ZW5zaW9uIGRvZXNuJ3Qgd29yayBwcm9wZXJseSBpZiB0aGVyZVxuXHRcdFx0XHQvLyBhcmUgbWlkZnJhbWUgZmx1c2hlcyBhbmQgYW4gZXh0ZXJuYWwgZGVwdGggYnVmZmVyLiBEaXNhYmxlIHVzZSBvZiB0aGUgZXh0ZW5zaW9uLlxuXHRcdFx0XHRpZiAoIGV4dGVuc2lvbnMuaGFzKCAnV0VCR0xfbXVsdGlzYW1wbGVkX3JlbmRlcl90b190ZXh0dXJlJyApID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlcjogUmVuZGVyLXRvLXRleHR1cmUgZXh0ZW5zaW9uIHdhcyBkaXNhYmxlZCBiZWNhdXNlIGFuIGV4dGVybmFsIHRleHR1cmUgd2FzIHByb3ZpZGVkJyApO1xuXHRcdFx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX191c2VSZW5kZXJUb1RleHR1cmUgPSBmYWxzZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH07XG5cblx0XHR0aGlzLnNldFJlbmRlclRhcmdldEZyYW1lYnVmZmVyID0gZnVuY3Rpb24gKCByZW5kZXJUYXJnZXQsIGRlZmF1bHRGcmFtZWJ1ZmZlciApIHtcblxuXHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcblx0XHRcdHJlbmRlclRhcmdldFByb3BlcnRpZXMuX193ZWJnbEZyYW1lYnVmZmVyID0gZGVmYXVsdEZyYW1lYnVmZmVyO1xuXHRcdFx0cmVuZGVyVGFyZ2V0UHJvcGVydGllcy5fX3VzZURlZmF1bHRGcmFtZWJ1ZmZlciA9IGRlZmF1bHRGcmFtZWJ1ZmZlciA9PT0gdW5kZWZpbmVkO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0UmVuZGVyVGFyZ2V0ID0gZnVuY3Rpb24gKCByZW5kZXJUYXJnZXQsIGFjdGl2ZUN1YmVGYWNlID0gMCwgYWN0aXZlTWlwbWFwTGV2ZWwgPSAwICkge1xuXG5cdFx0XHRfY3VycmVudFJlbmRlclRhcmdldCA9IHJlbmRlclRhcmdldDtcblx0XHRcdF9jdXJyZW50QWN0aXZlQ3ViZUZhY2UgPSBhY3RpdmVDdWJlRmFjZTtcblx0XHRcdF9jdXJyZW50QWN0aXZlTWlwbWFwTGV2ZWwgPSBhY3RpdmVNaXBtYXBMZXZlbDtcblxuXHRcdFx0bGV0IHVzZURlZmF1bHRGcmFtZWJ1ZmZlciA9IHRydWU7XG5cdFx0XHRsZXQgZnJhbWVidWZmZXIgPSBudWxsO1xuXHRcdFx0bGV0IGlzQ3ViZSA9IGZhbHNlO1xuXHRcdFx0bGV0IGlzUmVuZGVyVGFyZ2V0M0QgPSBmYWxzZTtcblxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXQgKSB7XG5cblx0XHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0UHJvcGVydGllcyA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKTtcblxuXHRcdFx0XHRpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX191c2VEZWZhdWx0RnJhbWVidWZmZXIgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdC8vIFdlIG5lZWQgdG8gbWFrZSBzdXJlIHRvIHJlYmluZCB0aGUgZnJhbWVidWZmZXIuXG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIG51bGwgKTtcblx0XHRcdFx0XHR1c2VEZWZhdWx0RnJhbWVidWZmZXIgPSBmYWxzZTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCByZW5kZXJUYXJnZXRQcm9wZXJ0aWVzLl9fd2ViZ2xGcmFtZWJ1ZmZlciA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0dGV4dHVyZXMuc2V0dXBSZW5kZXJUYXJnZXQoIHJlbmRlclRhcmdldCApO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHJlbmRlclRhcmdldFByb3BlcnRpZXMuX19oYXNFeHRlcm5hbFRleHR1cmVzICkge1xuXG5cdFx0XHRcdFx0Ly8gQ29sb3IgYW5kIGRlcHRoIHRleHR1cmUgbXVzdCBiZSByZWJvdW5kIGluIG9yZGVyIGZvciB0aGUgc3dhcGNoYWluIHRvIHVwZGF0ZS5cblx0XHRcdFx0XHR0ZXh0dXJlcy5yZWJpbmRUZXh0dXJlcyggcmVuZGVyVGFyZ2V0LCBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0LnRleHR1cmUgKS5fX3dlYmdsVGV4dHVyZSwgcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldC5kZXB0aFRleHR1cmUgKS5fX3dlYmdsVGV4dHVyZSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRjb25zdCB0ZXh0dXJlID0gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XG5cblx0XHRcdFx0aWYgKCB0ZXh0dXJlLmlzRGF0YTNEVGV4dHVyZSB8fCB0ZXh0dXJlLmlzRGF0YUFycmF5VGV4dHVyZSB8fCB0ZXh0dXJlLmlzQ29tcHJlc3NlZEFycmF5VGV4dHVyZSApIHtcblxuXHRcdFx0XHRcdGlzUmVuZGVyVGFyZ2V0M0QgPSB0cnVlO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRjb25zdCBfX3dlYmdsRnJhbWVidWZmZXIgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0ICkuX193ZWJnbEZyYW1lYnVmZmVyO1xuXG5cdFx0XHRcdGlmICggcmVuZGVyVGFyZ2V0LmlzV2ViR0xDdWJlUmVuZGVyVGFyZ2V0ICkge1xuXG5cdFx0XHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBfX3dlYmdsRnJhbWVidWZmZXJbIGFjdGl2ZUN1YmVGYWNlIF0gKSApIHtcblxuXHRcdFx0XHRcdFx0ZnJhbWVidWZmZXIgPSBfX3dlYmdsRnJhbWVidWZmZXJbIGFjdGl2ZUN1YmVGYWNlIF1bIGFjdGl2ZU1pcG1hcExldmVsIF07XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRmcmFtZWJ1ZmZlciA9IF9fd2ViZ2xGcmFtZWJ1ZmZlclsgYWN0aXZlQ3ViZUZhY2UgXTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlzQ3ViZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIGlmICggKCByZW5kZXJUYXJnZXQuc2FtcGxlcyA+IDAgKSAmJiB0ZXh0dXJlcy51c2VNdWx0aXNhbXBsZWRSVFQoIHJlbmRlclRhcmdldCApID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHRcdGZyYW1lYnVmZmVyID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApLl9fd2ViZ2xNdWx0aXNhbXBsZWRGcmFtZWJ1ZmZlcjtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBfX3dlYmdsRnJhbWVidWZmZXIgKSApIHtcblxuXHRcdFx0XHRcdFx0ZnJhbWVidWZmZXIgPSBfX3dlYmdsRnJhbWVidWZmZXJbIGFjdGl2ZU1pcG1hcExldmVsIF07XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRmcmFtZWJ1ZmZlciA9IF9fd2ViZ2xGcmFtZWJ1ZmZlcjtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0X2N1cnJlbnRWaWV3cG9ydC5jb3B5KCByZW5kZXJUYXJnZXQudmlld3BvcnQgKTtcblx0XHRcdFx0X2N1cnJlbnRTY2lzc29yLmNvcHkoIHJlbmRlclRhcmdldC5zY2lzc29yICk7XG5cdFx0XHRcdF9jdXJyZW50U2Npc3NvclRlc3QgPSByZW5kZXJUYXJnZXQuc2Npc3NvclRlc3Q7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0X2N1cnJlbnRWaWV3cG9ydC5jb3B5KCBfdmlld3BvcnQgKS5tdWx0aXBseVNjYWxhciggX3BpeGVsUmF0aW8gKS5mbG9vcigpO1xuXHRcdFx0XHRfY3VycmVudFNjaXNzb3IuY29weSggX3NjaXNzb3IgKS5tdWx0aXBseVNjYWxhciggX3BpeGVsUmF0aW8gKS5mbG9vcigpO1xuXHRcdFx0XHRfY3VycmVudFNjaXNzb3JUZXN0ID0gX3NjaXNzb3JUZXN0O1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGZyYW1lYnVmZmVyQm91bmQgPSBzdGF0ZS5iaW5kRnJhbWVidWZmZXIoIF9nbC5GUkFNRUJVRkZFUiwgZnJhbWVidWZmZXIgKTtcblxuXHRcdFx0aWYgKCBmcmFtZWJ1ZmZlckJvdW5kICYmIHVzZURlZmF1bHRGcmFtZWJ1ZmZlciApIHtcblxuXHRcdFx0XHRzdGF0ZS5kcmF3QnVmZmVycyggcmVuZGVyVGFyZ2V0LCBmcmFtZWJ1ZmZlciApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHN0YXRlLnZpZXdwb3J0KCBfY3VycmVudFZpZXdwb3J0ICk7XG5cdFx0XHRzdGF0ZS5zY2lzc29yKCBfY3VycmVudFNjaXNzb3IgKTtcblx0XHRcdHN0YXRlLnNldFNjaXNzb3JUZXN0KCBfY3VycmVudFNjaXNzb3JUZXN0ICk7XG5cblx0XHRcdGlmICggaXNDdWJlICkge1xuXG5cdFx0XHRcdGNvbnN0IHRleHR1cmVQcm9wZXJ0aWVzID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldC50ZXh0dXJlICk7XG5cdFx0XHRcdF9nbC5mcmFtZWJ1ZmZlclRleHR1cmUyRCggX2dsLkZSQU1FQlVGRkVSLCBfZ2wuQ09MT1JfQVRUQUNITUVOVDAsIF9nbC5URVhUVVJFX0NVQkVfTUFQX1BPU0lUSVZFX1ggKyBhY3RpdmVDdWJlRmFjZSwgdGV4dHVyZVByb3BlcnRpZXMuX193ZWJnbFRleHR1cmUsIGFjdGl2ZU1pcG1hcExldmVsICk7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGlzUmVuZGVyVGFyZ2V0M0QgKSB7XG5cblx0XHRcdFx0Y29uc3QgdGV4dHVyZVByb3BlcnRpZXMgPSBwcm9wZXJ0aWVzLmdldCggcmVuZGVyVGFyZ2V0LnRleHR1cmUgKTtcblx0XHRcdFx0Y29uc3QgbGF5ZXIgPSBhY3RpdmVDdWJlRmFjZSB8fCAwO1xuXHRcdFx0XHRfZ2wuZnJhbWVidWZmZXJUZXh0dXJlTGF5ZXIoIF9nbC5GUkFNRUJVRkZFUiwgX2dsLkNPTE9SX0FUVEFDSE1FTlQwLCB0ZXh0dXJlUHJvcGVydGllcy5fX3dlYmdsVGV4dHVyZSwgYWN0aXZlTWlwbWFwTGV2ZWwgfHwgMCwgbGF5ZXIgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRfY3VycmVudE1hdGVyaWFsSWQgPSAtIDE7IC8vIHJlc2V0IGN1cnJlbnQgbWF0ZXJpYWwgdG8gZW5zdXJlIGNvcnJlY3QgdW5pZm9ybSBiaW5kaW5nc1xuXG5cdFx0fTtcblxuXHRcdHRoaXMucmVhZFJlbmRlclRhcmdldFBpeGVscyA9IGZ1bmN0aW9uICggcmVuZGVyVGFyZ2V0LCB4LCB5LCB3aWR0aCwgaGVpZ2h0LCBidWZmZXIsIGFjdGl2ZUN1YmVGYWNlSW5kZXggKSB7XG5cblx0XHRcdGlmICggISAoIHJlbmRlclRhcmdldCAmJiByZW5kZXJUYXJnZXQuaXNXZWJHTFJlbmRlclRhcmdldCApICkge1xuXG5cdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyLnJlYWRSZW5kZXJUYXJnZXRQaXhlbHM6IHJlbmRlclRhcmdldCBpcyBub3QgVEhSRUUuV2ViR0xSZW5kZXJUYXJnZXQuJyApO1xuXHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdH1cblxuXHRcdFx0bGV0IGZyYW1lYnVmZmVyID0gcHJvcGVydGllcy5nZXQoIHJlbmRlclRhcmdldCApLl9fd2ViZ2xGcmFtZWJ1ZmZlcjtcblxuXHRcdFx0aWYgKCByZW5kZXJUYXJnZXQuaXNXZWJHTEN1YmVSZW5kZXJUYXJnZXQgJiYgYWN0aXZlQ3ViZUZhY2VJbmRleCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGZyYW1lYnVmZmVyID0gZnJhbWVidWZmZXJbIGFjdGl2ZUN1YmVGYWNlSW5kZXggXTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGZyYW1lYnVmZmVyICkge1xuXG5cdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xuXG5cdFx0XHRcdHRyeSB7XG5cblx0XHRcdFx0XHRjb25zdCB0ZXh0dXJlID0gcmVuZGVyVGFyZ2V0LnRleHR1cmU7XG5cdFx0XHRcdFx0Y29uc3QgdGV4dHVyZUZvcm1hdCA9IHRleHR1cmUuZm9ybWF0O1xuXHRcdFx0XHRcdGNvbnN0IHRleHR1cmVUeXBlID0gdGV4dHVyZS50eXBlO1xuXG5cdFx0XHRcdFx0aWYgKCAhIGNhcGFiaWxpdGllcy50ZXh0dXJlRm9ybWF0UmVhZGFibGUoIHRleHR1cmVGb3JtYXQgKSApIHtcblxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXIucmVhZFJlbmRlclRhcmdldFBpeGVsczogcmVuZGVyVGFyZ2V0IGlzIG5vdCBpbiBSR0JBIG9yIGltcGxlbWVudGF0aW9uIGRlZmluZWQgZm9ybWF0LicgKTtcblx0XHRcdFx0XHRcdHJldHVybjtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggISBjYXBhYmlsaXRpZXMudGV4dHVyZVR5cGVSZWFkYWJsZSggdGV4dHVyZVR5cGUgKSApIHtcblxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLldlYkdMUmVuZGVyZXIucmVhZFJlbmRlclRhcmdldFBpeGVsczogcmVuZGVyVGFyZ2V0IGlzIG5vdCBpbiBVbnNpZ25lZEJ5dGVUeXBlIG9yIGltcGxlbWVudGF0aW9uIGRlZmluZWQgdHlwZS4nICk7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyB0aGUgZm9sbG93aW5nIGlmIHN0YXRlbWVudCBlbnN1cmVzIHZhbGlkIHJlYWQgcmVxdWVzdHMgKG5vIG91dC1vZi1ib3VuZHMgcGl4ZWxzLCBzZWUgIzg2MDQpXG5cblx0XHRcdFx0XHRpZiAoICggeCA+PSAwICYmIHggPD0gKCByZW5kZXJUYXJnZXQud2lkdGggLSB3aWR0aCApICkgJiYgKCB5ID49IDAgJiYgeSA8PSAoIHJlbmRlclRhcmdldC5oZWlnaHQgLSBoZWlnaHQgKSApICkge1xuXG5cdFx0XHRcdFx0XHRfZ2wucmVhZFBpeGVscyggeCwgeSwgd2lkdGgsIGhlaWdodCwgdXRpbHMuY29udmVydCggdGV4dHVyZUZvcm1hdCApLCB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlVHlwZSApLCBidWZmZXIgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGZpbmFsbHkge1xuXG5cdFx0XHRcdFx0Ly8gcmVzdG9yZSBmcmFtZWJ1ZmZlciBvZiBjdXJyZW50IHJlbmRlciB0YXJnZXQgaWYgbmVjZXNzYXJ5XG5cblx0XHRcdFx0XHRjb25zdCBmcmFtZWJ1ZmZlciA9ICggX2N1cnJlbnRSZW5kZXJUYXJnZXQgIT09IG51bGwgKSA/IHByb3BlcnRpZXMuZ2V0KCBfY3VycmVudFJlbmRlclRhcmdldCApLl9fd2ViZ2xGcmFtZWJ1ZmZlciA6IG51bGw7XG5cdFx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIGZyYW1lYnVmZmVyICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5yZWFkUmVuZGVyVGFyZ2V0UGl4ZWxzQXN5bmMgPSBhc3luYyBmdW5jdGlvbiAoIHJlbmRlclRhcmdldCwgeCwgeSwgd2lkdGgsIGhlaWdodCwgYnVmZmVyLCBhY3RpdmVDdWJlRmFjZUluZGV4ICkge1xuXG5cdFx0XHRpZiAoICEgKCByZW5kZXJUYXJnZXQgJiYgcmVuZGVyVGFyZ2V0LmlzV2ViR0xSZW5kZXJUYXJnZXQgKSApIHtcblxuXHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyLnJlYWRSZW5kZXJUYXJnZXRQaXhlbHM6IHJlbmRlclRhcmdldCBpcyBub3QgVEhSRUUuV2ViR0xSZW5kZXJUYXJnZXQuJyApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGxldCBmcmFtZWJ1ZmZlciA9IHByb3BlcnRpZXMuZ2V0KCByZW5kZXJUYXJnZXQgKS5fX3dlYmdsRnJhbWVidWZmZXI7XG5cdFx0XHRpZiAoIHJlbmRlclRhcmdldC5pc1dlYkdMQ3ViZVJlbmRlclRhcmdldCAmJiBhY3RpdmVDdWJlRmFjZUluZGV4ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0ZnJhbWVidWZmZXIgPSBmcmFtZWJ1ZmZlclsgYWN0aXZlQ3ViZUZhY2VJbmRleCBdO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggZnJhbWVidWZmZXIgKSB7XG5cblx0XHRcdFx0c3RhdGUuYmluZEZyYW1lYnVmZmVyKCBfZ2wuRlJBTUVCVUZGRVIsIGZyYW1lYnVmZmVyICk7XG5cblx0XHRcdFx0dHJ5IHtcblxuXHRcdFx0XHRcdGNvbnN0IHRleHR1cmUgPSByZW5kZXJUYXJnZXQudGV4dHVyZTtcblx0XHRcdFx0XHRjb25zdCB0ZXh0dXJlRm9ybWF0ID0gdGV4dHVyZS5mb3JtYXQ7XG5cdFx0XHRcdFx0Y29uc3QgdGV4dHVyZVR5cGUgPSB0ZXh0dXJlLnR5cGU7XG5cblx0XHRcdFx0XHRpZiAoICEgY2FwYWJpbGl0aWVzLnRleHR1cmVGb3JtYXRSZWFkYWJsZSggdGV4dHVyZUZvcm1hdCApICkge1xuXG5cdFx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5XZWJHTFJlbmRlcmVyLnJlYWRSZW5kZXJUYXJnZXRQaXhlbHNBc3luYzogcmVuZGVyVGFyZ2V0IGlzIG5vdCBpbiBSR0JBIG9yIGltcGxlbWVudGF0aW9uIGRlZmluZWQgZm9ybWF0LicgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggISBjYXBhYmlsaXRpZXMudGV4dHVyZVR5cGVSZWFkYWJsZSggdGV4dHVyZVR5cGUgKSApIHtcblxuXHRcdFx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuV2ViR0xSZW5kZXJlci5yZWFkUmVuZGVyVGFyZ2V0UGl4ZWxzQXN5bmM6IHJlbmRlclRhcmdldCBpcyBub3QgaW4gVW5zaWduZWRCeXRlVHlwZSBvciBpbXBsZW1lbnRhdGlvbiBkZWZpbmVkIHR5cGUuJyApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gdGhlIGZvbGxvd2luZyBpZiBzdGF0ZW1lbnQgZW5zdXJlcyB2YWxpZCByZWFkIHJlcXVlc3RzIChubyBvdXQtb2YtYm91bmRzIHBpeGVscywgc2VlICM4NjA0KVxuXHRcdFx0XHRcdGlmICggKCB4ID49IDAgJiYgeCA8PSAoIHJlbmRlclRhcmdldC53aWR0aCAtIHdpZHRoICkgKSAmJiAoIHkgPj0gMCAmJiB5IDw9ICggcmVuZGVyVGFyZ2V0LmhlaWdodCAtIGhlaWdodCApICkgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGdsQnVmZmVyID0gX2dsLmNyZWF0ZUJ1ZmZlcigpO1xuXHRcdFx0XHRcdFx0X2dsLmJpbmRCdWZmZXIoIF9nbC5QSVhFTF9QQUNLX0JVRkZFUiwgZ2xCdWZmZXIgKTtcblx0XHRcdFx0XHRcdF9nbC5idWZmZXJEYXRhKCBfZ2wuUElYRUxfUEFDS19CVUZGRVIsIGJ1ZmZlci5ieXRlTGVuZ3RoLCBfZ2wuU1RSRUFNX1JFQUQgKTtcblx0XHRcdFx0XHRcdF9nbC5yZWFkUGl4ZWxzKCB4LCB5LCB3aWR0aCwgaGVpZ2h0LCB1dGlscy5jb252ZXJ0KCB0ZXh0dXJlRm9ybWF0ICksIHV0aWxzLmNvbnZlcnQoIHRleHR1cmVUeXBlICksIDAgKTtcblx0XHRcdFx0XHRcdF9nbC5mbHVzaCgpO1xuXG5cdFx0XHRcdFx0XHQvLyBjaGVjayBpZiB0aGUgY29tbWFuZHMgaGF2ZSBmaW5pc2hlZCBldmVyeSA4IG1zXG5cdFx0XHRcdFx0XHRjb25zdCBzeW5jID0gX2dsLmZlbmNlU3luYyggX2dsLlNZTkNfR1BVX0NPTU1BTkRTX0NPTVBMRVRFLCAwICk7XG5cdFx0XHRcdFx0XHRhd2FpdCBwcm9iZUFzeW5jKCBfZ2wsIHN5bmMsIDQgKTtcblxuXHRcdFx0XHRcdFx0dHJ5IHtcblxuXHRcdFx0XHRcdFx0XHRfZ2wuYmluZEJ1ZmZlciggX2dsLlBJWEVMX1BBQ0tfQlVGRkVSLCBnbEJ1ZmZlciApO1xuXHRcdFx0XHRcdFx0XHRfZ2wuZ2V0QnVmZmVyU3ViRGF0YSggX2dsLlBJWEVMX1BBQ0tfQlVGRkVSLCAwLCBidWZmZXIgKTtcblxuXHRcdFx0XHRcdFx0fSBmaW5hbGx5IHtcblxuXHRcdFx0XHRcdFx0XHRfZ2wuZGVsZXRlQnVmZmVyKCBnbEJ1ZmZlciApO1xuXHRcdFx0XHRcdFx0XHRfZ2wuZGVsZXRlU3luYyggc3luYyApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdHJldHVybiBidWZmZXI7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBmaW5hbGx5IHtcblxuXHRcdFx0XHRcdC8vIHJlc3RvcmUgZnJhbWVidWZmZXIgb2YgY3VycmVudCByZW5kZXIgdGFyZ2V0IGlmIG5lY2Vzc2FyeVxuXG5cdFx0XHRcdFx0Y29uc3QgZnJhbWVidWZmZXIgPSAoIF9jdXJyZW50UmVuZGVyVGFyZ2V0ICE9PSBudWxsICkgPyBwcm9wZXJ0aWVzLmdldCggX2N1cnJlbnRSZW5kZXJUYXJnZXQgKS5fX3dlYmdsRnJhbWVidWZmZXIgOiBudWxsO1xuXHRcdFx0XHRcdHN0YXRlLmJpbmRGcmFtZWJ1ZmZlciggX2dsLkZSQU1FQlVGRkVSLCBmcmFtZWJ1ZmZlciApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdHRoaXMuY29weUZyYW1lYnVmZmVyVG9UZXh0dXJlID0gZnVuY3Rpb24gKCB0ZXh0dXJlLCBwb3NpdGlvbiA9IG51bGwsIGxldmVsID0gMCApIHtcblxuXHRcdFx0Ly8gc3VwcG9ydCBwcmV2aW91cyBzaWduYXR1cmUgd2l0aCBwb3NpdGlvbiBmaXJzdFxuXHRcdFx0aWYgKCB0ZXh0dXJlLmlzVGV4dHVyZSAhPT0gdHJ1ZSApIHtcblxuXHRcdFx0XHQvLyBAZGVwcmVjYXRlZCwgcjE2NVxuXHRcdFx0XHR3YXJuT25jZSggJ1dlYkdMUmVuZGVyZXI6IGNvcHlGcmFtZWJ1ZmZlclRvVGV4dHVyZSBmdW5jdGlvbiBzaWduYXR1cmUgaGFzIGNoYW5nZWQuJyApO1xuXG5cdFx0XHRcdHBvc2l0aW9uID0gYXJndW1lbnRzWyAwIF0gfHwgbnVsbDtcblx0XHRcdFx0dGV4dHVyZSA9IGFyZ3VtZW50c1sgMSBdO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGxldmVsU2NhbGUgPSBNYXRoLnBvdyggMiwgLSBsZXZlbCApO1xuXHRcdFx0Y29uc3Qgd2lkdGggPSBNYXRoLmZsb29yKCB0ZXh0dXJlLmltYWdlLndpZHRoICogbGV2ZWxTY2FsZSApO1xuXHRcdFx0Y29uc3QgaGVpZ2h0ID0gTWF0aC5mbG9vciggdGV4dHVyZS5pbWFnZS5oZWlnaHQgKiBsZXZlbFNjYWxlICk7XG5cblx0XHRcdGNvbnN0IHggPSBwb3NpdGlvbiAhPT0gbnVsbCA/IHBvc2l0aW9uLnggOiAwO1xuXHRcdFx0Y29uc3QgeSA9IHBvc2l0aW9uICE9PSBudWxsID8gcG9zaXRpb24ueSA6IDA7XG5cblx0XHRcdHRleHR1cmVzLnNldFRleHR1cmUyRCggdGV4dHVyZSwgMCApO1xuXG5cdFx0XHRfZ2wuY29weVRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbCwgMCwgMCwgeCwgeSwgd2lkdGgsIGhlaWdodCApO1xuXG5cdFx0XHRzdGF0ZS51bmJpbmRUZXh0dXJlKCk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5jb3B5VGV4dHVyZVRvVGV4dHVyZSA9IGZ1bmN0aW9uICggc3JjVGV4dHVyZSwgZHN0VGV4dHVyZSwgc3JjUmVnaW9uID0gbnVsbCwgZHN0UG9zaXRpb24gPSBudWxsLCBsZXZlbCA9IDAgKSB7XG5cblx0XHRcdC8vIHN1cHBvcnQgcHJldmlvdXMgc2lnbmF0dXJlIHdpdGggZHN0UG9zaXRpb24gZmlyc3Rcblx0XHRcdGlmICggc3JjVGV4dHVyZS5pc1RleHR1cmUgIT09IHRydWUgKSB7XG5cblx0XHRcdFx0Ly8gQGRlcHJlY2F0ZWQsIHIxNjVcblx0XHRcdFx0d2Fybk9uY2UoICdXZWJHTFJlbmRlcmVyOiBjb3B5VGV4dHVyZVRvVGV4dHVyZSBmdW5jdGlvbiBzaWduYXR1cmUgaGFzIGNoYW5nZWQuJyApO1xuXG5cdFx0XHRcdGRzdFBvc2l0aW9uID0gYXJndW1lbnRzWyAwIF0gfHwgbnVsbDtcblx0XHRcdFx0c3JjVGV4dHVyZSA9IGFyZ3VtZW50c1sgMSBdO1xuXHRcdFx0XHRkc3RUZXh0dXJlID0gYXJndW1lbnRzWyAyIF07XG5cdFx0XHRcdGxldmVsID0gYXJndW1lbnRzWyAzIF0gfHwgMDtcblx0XHRcdFx0c3JjUmVnaW9uID0gbnVsbDtcblxuXHRcdFx0fVxuXG5cdFx0XHRsZXQgd2lkdGgsIGhlaWdodCwgbWluWCwgbWluWTtcblx0XHRcdGxldCBkc3RYLCBkc3RZO1xuXHRcdFx0aWYgKCBzcmNSZWdpb24gIT09IG51bGwgKSB7XG5cblx0XHRcdFx0d2lkdGggPSBzcmNSZWdpb24ubWF4LnggLSBzcmNSZWdpb24ubWluLng7XG5cdFx0XHRcdGhlaWdodCA9IHNyY1JlZ2lvbi5tYXgueSAtIHNyY1JlZ2lvbi5taW4ueTtcblx0XHRcdFx0bWluWCA9IHNyY1JlZ2lvbi5taW4ueDtcblx0XHRcdFx0bWluWSA9IHNyY1JlZ2lvbi5taW4ueTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHR3aWR0aCA9IHNyY1RleHR1cmUuaW1hZ2Uud2lkdGg7XG5cdFx0XHRcdGhlaWdodCA9IHNyY1RleHR1cmUuaW1hZ2UuaGVpZ2h0O1xuXHRcdFx0XHRtaW5YID0gMDtcblx0XHRcdFx0bWluWSA9IDA7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBkc3RQb3NpdGlvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRkc3RYID0gZHN0UG9zaXRpb24ueDtcblx0XHRcdFx0ZHN0WSA9IGRzdFBvc2l0aW9uLnk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0ZHN0WCA9IDA7XG5cdFx0XHRcdGRzdFkgPSAwO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGdsRm9ybWF0ID0gdXRpbHMuY29udmVydCggZHN0VGV4dHVyZS5mb3JtYXQgKTtcblx0XHRcdGNvbnN0IGdsVHlwZSA9IHV0aWxzLmNvbnZlcnQoIGRzdFRleHR1cmUudHlwZSApO1xuXG5cdFx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlMkQoIGRzdFRleHR1cmUsIDAgKTtcblxuXHRcdFx0Ly8gQXMgYW5vdGhlciB0ZXh0dXJlIHVwbG9hZCBtYXkgaGF2ZSBjaGFuZ2VkIHBpeGVsU3RvcmVpXG5cdFx0XHQvLyBwYXJhbWV0ZXJzLCBtYWtlIHN1cmUgdGhleSBhcmUgY29ycmVjdCBmb3IgdGhlIGRzdFRleHR1cmVcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19GTElQX1lfV0VCR0wsIGRzdFRleHR1cmUuZmxpcFkgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19QUkVNVUxUSVBMWV9BTFBIQV9XRUJHTCwgZHN0VGV4dHVyZS5wcmVtdWx0aXBseUFscGhhICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfQUxJR05NRU5ULCBkc3RUZXh0dXJlLnVucGFja0FsaWdubWVudCApO1xuXG5cdFx0XHRjb25zdCBjdXJyZW50VW5wYWNrUm93TGVuID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19ST1dfTEVOR1RIICk7XG5cdFx0XHRjb25zdCBjdXJyZW50VW5wYWNrSW1hZ2VIZWlnaHQgPSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuVU5QQUNLX0lNQUdFX0hFSUdIVCApO1xuXHRcdFx0Y29uc3QgY3VycmVudFVucGFja1NraXBQaXhlbHMgPSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuVU5QQUNLX1NLSVBfUElYRUxTICk7XG5cdFx0XHRjb25zdCBjdXJyZW50VW5wYWNrU2tpcFJvd3MgPSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuVU5QQUNLX1NLSVBfUk9XUyApO1xuXHRcdFx0Y29uc3QgY3VycmVudFVucGFja1NraXBJbWFnZXMgPSBfZ2wuZ2V0UGFyYW1ldGVyKCBfZ2wuVU5QQUNLX1NLSVBfSU1BR0VTICk7XG5cblx0XHRcdGNvbnN0IGltYWdlID0gc3JjVGV4dHVyZS5pc0NvbXByZXNzZWRUZXh0dXJlID8gc3JjVGV4dHVyZS5taXBtYXBzWyBsZXZlbCBdIDogc3JjVGV4dHVyZS5pbWFnZTtcblxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1JPV19MRU5HVEgsIGltYWdlLndpZHRoICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfSU1BR0VfSEVJR0hULCBpbWFnZS5oZWlnaHQgKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19TS0lQX1BJWEVMUywgbWluWCApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUk9XUywgbWluWSApO1xuXG5cdFx0XHRpZiAoIHNyY1RleHR1cmUuaXNEYXRhVGV4dHVyZSApIHtcblxuXHRcdFx0XHRfZ2wudGV4U3ViSW1hZ2UyRCggX2dsLlRFWFRVUkVfMkQsIGxldmVsLCBkc3RYLCBkc3RZLCB3aWR0aCwgaGVpZ2h0LCBnbEZvcm1hdCwgZ2xUeXBlLCBpbWFnZS5kYXRhICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0aWYgKCBzcmNUZXh0dXJlLmlzQ29tcHJlc3NlZFRleHR1cmUgKSB7XG5cblx0XHRcdFx0XHRfZ2wuY29tcHJlc3NlZFRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbCwgZHN0WCwgZHN0WSwgaW1hZ2Uud2lkdGgsIGltYWdlLmhlaWdodCwgZ2xGb3JtYXQsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0X2dsLnRleFN1YkltYWdlMkQoIF9nbC5URVhUVVJFXzJELCBsZXZlbCwgZHN0WCwgZHN0WSwgd2lkdGgsIGhlaWdodCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1JPV19MRU5HVEgsIGN1cnJlbnRVbnBhY2tSb3dMZW4gKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19JTUFHRV9IRUlHSFQsIGN1cnJlbnRVbnBhY2tJbWFnZUhlaWdodCApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUElYRUxTLCBjdXJyZW50VW5wYWNrU2tpcFBpeGVscyApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUk9XUywgY3VycmVudFVucGFja1NraXBSb3dzICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfU0tJUF9JTUFHRVMsIGN1cnJlbnRVbnBhY2tTa2lwSW1hZ2VzICk7XG5cblx0XHRcdC8vIEdlbmVyYXRlIG1pcG1hcHMgb25seSB3aGVuIGNvcHlpbmcgbGV2ZWwgMFxuXHRcdFx0aWYgKCBsZXZlbCA9PT0gMCAmJiBkc3RUZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyApIF9nbC5nZW5lcmF0ZU1pcG1hcCggX2dsLlRFWFRVUkVfMkQgKTtcblxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuY29weVRleHR1cmVUb1RleHR1cmUzRCA9IGZ1bmN0aW9uICggc3JjVGV4dHVyZSwgZHN0VGV4dHVyZSwgc3JjUmVnaW9uID0gbnVsbCwgZHN0UG9zaXRpb24gPSBudWxsLCBsZXZlbCA9IDAgKSB7XG5cblx0XHRcdC8vIHN1cHBvcnQgcHJldmlvdXMgc2lnbmF0dXJlIHdpdGggc291cmNlIGJveCBmaXJzdFxuXHRcdFx0aWYgKCBzcmNUZXh0dXJlLmlzVGV4dHVyZSAhPT0gdHJ1ZSApIHtcblxuXHRcdFx0XHQvLyBAZGVwcmVjYXRlZCwgcjE2NVxuXHRcdFx0XHR3YXJuT25jZSggJ1dlYkdMUmVuZGVyZXI6IGNvcHlUZXh0dXJlVG9UZXh0dXJlM0QgZnVuY3Rpb24gc2lnbmF0dXJlIGhhcyBjaGFuZ2VkLicgKTtcblxuXHRcdFx0XHRzcmNSZWdpb24gPSBhcmd1bWVudHNbIDAgXSB8fCBudWxsO1xuXHRcdFx0XHRkc3RQb3NpdGlvbiA9IGFyZ3VtZW50c1sgMSBdIHx8IG51bGw7XG5cdFx0XHRcdHNyY1RleHR1cmUgPSBhcmd1bWVudHNbIDIgXTtcblx0XHRcdFx0ZHN0VGV4dHVyZSA9IGFyZ3VtZW50c1sgMyBdO1xuXHRcdFx0XHRsZXZlbCA9IGFyZ3VtZW50c1sgNCBdIHx8IDA7XG5cblx0XHRcdH1cblxuXHRcdFx0bGV0IHdpZHRoLCBoZWlnaHQsIGRlcHRoLCBtaW5YLCBtaW5ZLCBtaW5aO1xuXHRcdFx0bGV0IGRzdFgsIGRzdFksIGRzdFo7XG5cdFx0XHRjb25zdCBpbWFnZSA9IHNyY1RleHR1cmUuaXNDb21wcmVzc2VkVGV4dHVyZSA/IHNyY1RleHR1cmUubWlwbWFwc1sgbGV2ZWwgXSA6IHNyY1RleHR1cmUuaW1hZ2U7XG5cdFx0XHRpZiAoIHNyY1JlZ2lvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHR3aWR0aCA9IHNyY1JlZ2lvbi5tYXgueCAtIHNyY1JlZ2lvbi5taW4ueDtcblx0XHRcdFx0aGVpZ2h0ID0gc3JjUmVnaW9uLm1heC55IC0gc3JjUmVnaW9uLm1pbi55O1xuXHRcdFx0XHRkZXB0aCA9IHNyY1JlZ2lvbi5tYXgueiAtIHNyY1JlZ2lvbi5taW4uejtcblx0XHRcdFx0bWluWCA9IHNyY1JlZ2lvbi5taW4ueDtcblx0XHRcdFx0bWluWSA9IHNyY1JlZ2lvbi5taW4ueTtcblx0XHRcdFx0bWluWiA9IHNyY1JlZ2lvbi5taW4uejtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHR3aWR0aCA9IGltYWdlLndpZHRoO1xuXHRcdFx0XHRoZWlnaHQgPSBpbWFnZS5oZWlnaHQ7XG5cdFx0XHRcdGRlcHRoID0gaW1hZ2UuZGVwdGg7XG5cdFx0XHRcdG1pblggPSAwO1xuXHRcdFx0XHRtaW5ZID0gMDtcblx0XHRcdFx0bWluWiA9IDA7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBkc3RQb3NpdGlvbiAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRkc3RYID0gZHN0UG9zaXRpb24ueDtcblx0XHRcdFx0ZHN0WSA9IGRzdFBvc2l0aW9uLnk7XG5cdFx0XHRcdGRzdFogPSBkc3RQb3NpdGlvbi56O1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGRzdFggPSAwO1xuXHRcdFx0XHRkc3RZID0gMDtcblx0XHRcdFx0ZHN0WiA9IDA7XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgZ2xGb3JtYXQgPSB1dGlscy5jb252ZXJ0KCBkc3RUZXh0dXJlLmZvcm1hdCApO1xuXHRcdFx0Y29uc3QgZ2xUeXBlID0gdXRpbHMuY29udmVydCggZHN0VGV4dHVyZS50eXBlICk7XG5cdFx0XHRsZXQgZ2xUYXJnZXQ7XG5cblx0XHRcdGlmICggZHN0VGV4dHVyZS5pc0RhdGEzRFRleHR1cmUgKSB7XG5cblx0XHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZTNEKCBkc3RUZXh0dXJlLCAwICk7XG5cdFx0XHRcdGdsVGFyZ2V0ID0gX2dsLlRFWFRVUkVfM0Q7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGRzdFRleHR1cmUuaXNEYXRhQXJyYXlUZXh0dXJlIHx8IGRzdFRleHR1cmUuaXNDb21wcmVzc2VkQXJyYXlUZXh0dXJlICkge1xuXG5cdFx0XHRcdHRleHR1cmVzLnNldFRleHR1cmUyREFycmF5KCBkc3RUZXh0dXJlLCAwICk7XG5cdFx0XHRcdGdsVGFyZ2V0ID0gX2dsLlRFWFRVUkVfMkRfQVJSQVk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xSZW5kZXJlci5jb3B5VGV4dHVyZVRvVGV4dHVyZTNEOiBvbmx5IHN1cHBvcnRzIFRIUkVFLkRhdGFUZXh0dXJlM0QgYW5kIFRIUkVFLkRhdGFUZXh0dXJlMkRBcnJheS4nICk7XG5cdFx0XHRcdHJldHVybjtcblxuXHRcdFx0fVxuXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfRkxJUF9ZX1dFQkdMLCBkc3RUZXh0dXJlLmZsaXBZICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfUFJFTVVMVElQTFlfQUxQSEFfV0VCR0wsIGRzdFRleHR1cmUucHJlbXVsdGlwbHlBbHBoYSApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX0FMSUdOTUVOVCwgZHN0VGV4dHVyZS51bnBhY2tBbGlnbm1lbnQgKTtcblxuXHRcdFx0Y29uc3QgY3VycmVudFVucGFja1Jvd0xlbiA9IF9nbC5nZXRQYXJhbWV0ZXIoIF9nbC5VTlBBQ0tfUk9XX0xFTkdUSCApO1xuXHRcdFx0Y29uc3QgY3VycmVudFVucGFja0ltYWdlSGVpZ2h0ID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19JTUFHRV9IRUlHSFQgKTtcblx0XHRcdGNvbnN0IGN1cnJlbnRVbnBhY2tTa2lwUGl4ZWxzID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19TS0lQX1BJWEVMUyApO1xuXHRcdFx0Y29uc3QgY3VycmVudFVucGFja1NraXBSb3dzID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19TS0lQX1JPV1MgKTtcblx0XHRcdGNvbnN0IGN1cnJlbnRVbnBhY2tTa2lwSW1hZ2VzID0gX2dsLmdldFBhcmFtZXRlciggX2dsLlVOUEFDS19TS0lQX0lNQUdFUyApO1xuXG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfUk9XX0xFTkdUSCwgaW1hZ2Uud2lkdGggKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19JTUFHRV9IRUlHSFQsIGltYWdlLmhlaWdodCApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUElYRUxTLCBtaW5YICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfU0tJUF9ST1dTLCBtaW5ZICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfU0tJUF9JTUFHRVMsIG1pblogKTtcblxuXHRcdFx0aWYgKCBzcmNUZXh0dXJlLmlzRGF0YVRleHR1cmUgfHwgc3JjVGV4dHVyZS5pc0RhdGEzRFRleHR1cmUgKSB7XG5cblx0XHRcdFx0X2dsLnRleFN1YkltYWdlM0QoIGdsVGFyZ2V0LCBsZXZlbCwgZHN0WCwgZHN0WSwgZHN0Wiwgd2lkdGgsIGhlaWdodCwgZGVwdGgsIGdsRm9ybWF0LCBnbFR5cGUsIGltYWdlLmRhdGEgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRpZiAoIGRzdFRleHR1cmUuaXNDb21wcmVzc2VkQXJyYXlUZXh0dXJlICkge1xuXG5cdFx0XHRcdFx0X2dsLmNvbXByZXNzZWRUZXhTdWJJbWFnZTNEKCBnbFRhcmdldCwgbGV2ZWwsIGRzdFgsIGRzdFksIGRzdFosIHdpZHRoLCBoZWlnaHQsIGRlcHRoLCBnbEZvcm1hdCwgaW1hZ2UuZGF0YSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRfZ2wudGV4U3ViSW1hZ2UzRCggZ2xUYXJnZXQsIGxldmVsLCBkc3RYLCBkc3RZLCBkc3RaLCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCwgZ2xGb3JtYXQsIGdsVHlwZSwgaW1hZ2UgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1JPV19MRU5HVEgsIGN1cnJlbnRVbnBhY2tSb3dMZW4gKTtcblx0XHRcdF9nbC5waXhlbFN0b3JlaSggX2dsLlVOUEFDS19JTUFHRV9IRUlHSFQsIGN1cnJlbnRVbnBhY2tJbWFnZUhlaWdodCApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUElYRUxTLCBjdXJyZW50VW5wYWNrU2tpcFBpeGVscyApO1xuXHRcdFx0X2dsLnBpeGVsU3RvcmVpKCBfZ2wuVU5QQUNLX1NLSVBfUk9XUywgY3VycmVudFVucGFja1NraXBSb3dzICk7XG5cdFx0XHRfZ2wucGl4ZWxTdG9yZWkoIF9nbC5VTlBBQ0tfU0tJUF9JTUFHRVMsIGN1cnJlbnRVbnBhY2tTa2lwSW1hZ2VzICk7XG5cblx0XHRcdC8vIEdlbmVyYXRlIG1pcG1hcHMgb25seSB3aGVuIGNvcHlpbmcgbGV2ZWwgMFxuXHRcdFx0aWYgKCBsZXZlbCA9PT0gMCAmJiBkc3RUZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyApIF9nbC5nZW5lcmF0ZU1pcG1hcCggZ2xUYXJnZXQgKTtcblxuXHRcdFx0c3RhdGUudW5iaW5kVGV4dHVyZSgpO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuaW5pdFJlbmRlclRhcmdldCA9IGZ1bmN0aW9uICggdGFyZ2V0ICkge1xuXG5cdFx0XHRpZiAoIHByb3BlcnRpZXMuZ2V0KCB0YXJnZXQgKS5fX3dlYmdsRnJhbWVidWZmZXIgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0ZXh0dXJlcy5zZXR1cFJlbmRlclRhcmdldCggdGFyZ2V0ICk7XG5cblx0XHRcdH1cblxuXHRcdH07XG5cblx0XHR0aGlzLmluaXRUZXh0dXJlID0gZnVuY3Rpb24gKCB0ZXh0dXJlICkge1xuXG5cdFx0XHRpZiAoIHRleHR1cmUuaXNDdWJlVGV4dHVyZSApIHtcblxuXHRcdFx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlQ3ViZSggdGV4dHVyZSwgMCApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCB0ZXh0dXJlLmlzRGF0YTNEVGV4dHVyZSApIHtcblxuXHRcdFx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlM0QoIHRleHR1cmUsIDAgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggdGV4dHVyZS5pc0RhdGFBcnJheVRleHR1cmUgfHwgdGV4dHVyZS5pc0NvbXByZXNzZWRBcnJheVRleHR1cmUgKSB7XG5cblx0XHRcdFx0dGV4dHVyZXMuc2V0VGV4dHVyZTJEQXJyYXkoIHRleHR1cmUsIDAgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHR0ZXh0dXJlcy5zZXRUZXh0dXJlMkQoIHRleHR1cmUsIDAgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRzdGF0ZS51bmJpbmRUZXh0dXJlKCk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5yZXNldFN0YXRlID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRfY3VycmVudEFjdGl2ZUN1YmVGYWNlID0gMDtcblx0XHRcdF9jdXJyZW50QWN0aXZlTWlwbWFwTGV2ZWwgPSAwO1xuXHRcdFx0X2N1cnJlbnRSZW5kZXJUYXJnZXQgPSBudWxsO1xuXG5cdFx0XHRzdGF0ZS5yZXNldCgpO1xuXHRcdFx0YmluZGluZ1N0YXRlcy5yZXNldCgpO1xuXG5cdFx0fTtcblxuXHRcdGlmICggdHlwZW9mIF9fVEhSRUVfREVWVE9PTFNfXyAhPT0gJ3VuZGVmaW5lZCcgKSB7XG5cblx0XHRcdF9fVEhSRUVfREVWVE9PTFNfXy5kaXNwYXRjaEV2ZW50KCBuZXcgQ3VzdG9tRXZlbnQoICdvYnNlcnZlJywgeyBkZXRhaWw6IHRoaXMgfSApICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGdldCBjb29yZGluYXRlU3lzdGVtKCkge1xuXG5cdFx0cmV0dXJuIFdlYkdMQ29vcmRpbmF0ZVN5c3RlbTtcblxuXHR9XG5cblx0Z2V0IG91dHB1dENvbG9yU3BhY2UoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fb3V0cHV0Q29sb3JTcGFjZTtcblxuXHR9XG5cblx0c2V0IG91dHB1dENvbG9yU3BhY2UoIGNvbG9yU3BhY2UgKSB7XG5cblx0XHR0aGlzLl9vdXRwdXRDb2xvclNwYWNlID0gY29sb3JTcGFjZTtcblxuXHRcdGNvbnN0IGdsID0gdGhpcy5nZXRDb250ZXh0KCk7XG5cdFx0Z2wuZHJhd2luZ0J1ZmZlckNvbG9yU3BhY2UgPSBjb2xvclNwYWNlID09PSBEaXNwbGF5UDNDb2xvclNwYWNlID8gJ2Rpc3BsYXktcDMnIDogJ3NyZ2InO1xuXHRcdGdsLnVucGFja0NvbG9yU3BhY2UgPSBDb2xvck1hbmFnZW1lbnQud29ya2luZ0NvbG9yU3BhY2UgPT09IExpbmVhckRpc3BsYXlQM0NvbG9yU3BhY2UgPyAnZGlzcGxheS1wMycgOiAnc3JnYic7XG5cblx0fVxuXG59XG5cbmNsYXNzIEZvZ0V4cDIge1xuXG5cdGNvbnN0cnVjdG9yKCBjb2xvciwgZGVuc2l0eSA9IDAuMDAwMjUgKSB7XG5cblx0XHR0aGlzLmlzRm9nRXhwMiA9IHRydWU7XG5cblx0XHR0aGlzLm5hbWUgPSAnJztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIGNvbG9yICk7XG5cdFx0dGhpcy5kZW5zaXR5ID0gZGVuc2l0eTtcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IEZvZ0V4cDIoIHRoaXMuY29sb3IsIHRoaXMuZGVuc2l0eSApO1xuXG5cdH1cblxuXHR0b0pTT04oIC8qIG1ldGEgKi8gKSB7XG5cblx0XHRyZXR1cm4ge1xuXHRcdFx0dHlwZTogJ0ZvZ0V4cDInLFxuXHRcdFx0bmFtZTogdGhpcy5uYW1lLFxuXHRcdFx0Y29sb3I6IHRoaXMuY29sb3IuZ2V0SGV4KCksXG5cdFx0XHRkZW5zaXR5OiB0aGlzLmRlbnNpdHlcblx0XHR9O1xuXG5cdH1cblxufVxuXG5jbGFzcyBGb2cge1xuXG5cdGNvbnN0cnVjdG9yKCBjb2xvciwgbmVhciA9IDEsIGZhciA9IDEwMDAgKSB7XG5cblx0XHR0aGlzLmlzRm9nID0gdHJ1ZTtcblxuXHRcdHRoaXMubmFtZSA9ICcnO1xuXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggY29sb3IgKTtcblxuXHRcdHRoaXMubmVhciA9IG5lYXI7XG5cdFx0dGhpcy5mYXIgPSBmYXI7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyBGb2coIHRoaXMuY29sb3IsIHRoaXMubmVhciwgdGhpcy5mYXIgKTtcblxuXHR9XG5cblx0dG9KU09OKCAvKiBtZXRhICovICkge1xuXG5cdFx0cmV0dXJuIHtcblx0XHRcdHR5cGU6ICdGb2cnLFxuXHRcdFx0bmFtZTogdGhpcy5uYW1lLFxuXHRcdFx0Y29sb3I6IHRoaXMuY29sb3IuZ2V0SGV4KCksXG5cdFx0XHRuZWFyOiB0aGlzLm5lYXIsXG5cdFx0XHRmYXI6IHRoaXMuZmFyXG5cdFx0fTtcblxuXHR9XG5cbn1cblxuY2xhc3MgU2NlbmUgZXh0ZW5kcyBPYmplY3QzRCB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc1NjZW5lID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdTY2VuZSc7XG5cblx0XHR0aGlzLmJhY2tncm91bmQgPSBudWxsO1xuXHRcdHRoaXMuZW52aXJvbm1lbnQgPSBudWxsO1xuXHRcdHRoaXMuZm9nID0gbnVsbDtcblxuXHRcdHRoaXMuYmFja2dyb3VuZEJsdXJyaW5lc3MgPSAwO1xuXHRcdHRoaXMuYmFja2dyb3VuZEludGVuc2l0eSA9IDE7XG5cdFx0dGhpcy5iYWNrZ3JvdW5kUm90YXRpb24gPSBuZXcgRXVsZXIoKTtcblxuXHRcdHRoaXMuZW52aXJvbm1lbnRJbnRlbnNpdHkgPSAxO1xuXHRcdHRoaXMuZW52aXJvbm1lbnRSb3RhdGlvbiA9IG5ldyBFdWxlcigpO1xuXG5cdFx0dGhpcy5vdmVycmlkZU1hdGVyaWFsID0gbnVsbDtcblxuXHRcdGlmICggdHlwZW9mIF9fVEhSRUVfREVWVE9PTFNfXyAhPT0gJ3VuZGVmaW5lZCcgKSB7XG5cblx0XHRcdF9fVEhSRUVfREVWVE9PTFNfXy5kaXNwYXRjaEV2ZW50KCBuZXcgQ3VzdG9tRXZlbnQoICdvYnNlcnZlJywgeyBkZXRhaWw6IHRoaXMgfSApICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcblxuXHRcdGlmICggc291cmNlLmJhY2tncm91bmQgIT09IG51bGwgKSB0aGlzLmJhY2tncm91bmQgPSBzb3VyY2UuYmFja2dyb3VuZC5jbG9uZSgpO1xuXHRcdGlmICggc291cmNlLmVudmlyb25tZW50ICE9PSBudWxsICkgdGhpcy5lbnZpcm9ubWVudCA9IHNvdXJjZS5lbnZpcm9ubWVudC5jbG9uZSgpO1xuXHRcdGlmICggc291cmNlLmZvZyAhPT0gbnVsbCApIHRoaXMuZm9nID0gc291cmNlLmZvZy5jbG9uZSgpO1xuXG5cdFx0dGhpcy5iYWNrZ3JvdW5kQmx1cnJpbmVzcyA9IHNvdXJjZS5iYWNrZ3JvdW5kQmx1cnJpbmVzcztcblx0XHR0aGlzLmJhY2tncm91bmRJbnRlbnNpdHkgPSBzb3VyY2UuYmFja2dyb3VuZEludGVuc2l0eTtcblx0XHR0aGlzLmJhY2tncm91bmRSb3RhdGlvbi5jb3B5KCBzb3VyY2UuYmFja2dyb3VuZFJvdGF0aW9uICk7XG5cblx0XHR0aGlzLmVudmlyb25tZW50SW50ZW5zaXR5ID0gc291cmNlLmVudmlyb25tZW50SW50ZW5zaXR5O1xuXHRcdHRoaXMuZW52aXJvbm1lbnRSb3RhdGlvbi5jb3B5KCBzb3VyY2UuZW52aXJvbm1lbnRSb3RhdGlvbiApO1xuXG5cdFx0aWYgKCBzb3VyY2Uub3ZlcnJpZGVNYXRlcmlhbCAhPT0gbnVsbCApIHRoaXMub3ZlcnJpZGVNYXRlcmlhbCA9IHNvdXJjZS5vdmVycmlkZU1hdGVyaWFsLmNsb25lKCk7XG5cblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBzb3VyY2UubWF0cml4QXV0b1VwZGF0ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oIG1ldGEgKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCBtZXRhICk7XG5cblx0XHRpZiAoIHRoaXMuZm9nICE9PSBudWxsICkgZGF0YS5vYmplY3QuZm9nID0gdGhpcy5mb2cudG9KU09OKCk7XG5cblx0XHRpZiAoIHRoaXMuYmFja2dyb3VuZEJsdXJyaW5lc3MgPiAwICkgZGF0YS5vYmplY3QuYmFja2dyb3VuZEJsdXJyaW5lc3MgPSB0aGlzLmJhY2tncm91bmRCbHVycmluZXNzO1xuXHRcdGlmICggdGhpcy5iYWNrZ3JvdW5kSW50ZW5zaXR5ICE9PSAxICkgZGF0YS5vYmplY3QuYmFja2dyb3VuZEludGVuc2l0eSA9IHRoaXMuYmFja2dyb3VuZEludGVuc2l0eTtcblx0XHRkYXRhLm9iamVjdC5iYWNrZ3JvdW5kUm90YXRpb24gPSB0aGlzLmJhY2tncm91bmRSb3RhdGlvbi50b0FycmF5KCk7XG5cblx0XHRpZiAoIHRoaXMuZW52aXJvbm1lbnRJbnRlbnNpdHkgIT09IDEgKSBkYXRhLm9iamVjdC5lbnZpcm9ubWVudEludGVuc2l0eSA9IHRoaXMuZW52aXJvbm1lbnRJbnRlbnNpdHk7XG5cdFx0ZGF0YS5vYmplY3QuZW52aXJvbm1lbnRSb3RhdGlvbiA9IHRoaXMuZW52aXJvbm1lbnRSb3RhdGlvbi50b0FycmF5KCk7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cbn1cblxuY2xhc3MgSW50ZXJsZWF2ZWRCdWZmZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgc3RyaWRlICkge1xuXG5cdFx0dGhpcy5pc0ludGVybGVhdmVkQnVmZmVyID0gdHJ1ZTtcblxuXHRcdHRoaXMuYXJyYXkgPSBhcnJheTtcblx0XHR0aGlzLnN0cmlkZSA9IHN0cmlkZTtcblx0XHR0aGlzLmNvdW50ID0gYXJyYXkgIT09IHVuZGVmaW5lZCA/IGFycmF5Lmxlbmd0aCAvIHN0cmlkZSA6IDA7XG5cblx0XHR0aGlzLnVzYWdlID0gU3RhdGljRHJhd1VzYWdlO1xuXHRcdHRoaXMuX3VwZGF0ZVJhbmdlID0geyBvZmZzZXQ6IDAsIGNvdW50OiAtIDEgfTtcblx0XHR0aGlzLnVwZGF0ZVJhbmdlcyA9IFtdO1xuXG5cdFx0dGhpcy52ZXJzaW9uID0gMDtcblxuXHRcdHRoaXMudXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdH1cblxuXHRvblVwbG9hZENhbGxiYWNrKCkge31cblxuXHRzZXQgbmVlZHNVcGRhdGUoIHZhbHVlICkge1xuXG5cdFx0aWYgKCB2YWx1ZSA9PT0gdHJ1ZSApIHRoaXMudmVyc2lvbiArKztcblxuXHR9XG5cblx0Z2V0IHVwZGF0ZVJhbmdlKCkge1xuXG5cdFx0d2Fybk9uY2UoICdUSFJFRS5JbnRlcmxlYXZlZEJ1ZmZlcjogdXBkYXRlUmFuZ2UoKSBpcyBkZXByZWNhdGVkIGFuZCB3aWxsIGJlIHJlbW92ZWQgaW4gcjE2OS4gVXNlIGFkZFVwZGF0ZVJhbmdlKCkgaW5zdGVhZC4nICk7IC8vIEBkZXByZWNhdGVkLCByMTU5XG5cdFx0cmV0dXJuIHRoaXMuX3VwZGF0ZVJhbmdlO1xuXG5cdH1cblxuXHRzZXRVc2FnZSggdmFsdWUgKSB7XG5cblx0XHR0aGlzLnVzYWdlID0gdmFsdWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YWRkVXBkYXRlUmFuZ2UoIHN0YXJ0LCBjb3VudCApIHtcblxuXHRcdHRoaXMudXBkYXRlUmFuZ2VzLnB1c2goIHsgc3RhcnQsIGNvdW50IH0gKTtcblxuXHR9XG5cblx0Y2xlYXJVcGRhdGVSYW5nZXMoKSB7XG5cblx0XHR0aGlzLnVwZGF0ZVJhbmdlcy5sZW5ndGggPSAwO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHR0aGlzLmFycmF5ID0gbmV3IHNvdXJjZS5hcnJheS5jb25zdHJ1Y3Rvciggc291cmNlLmFycmF5ICk7XG5cdFx0dGhpcy5jb3VudCA9IHNvdXJjZS5jb3VudDtcblx0XHR0aGlzLnN0cmlkZSA9IHNvdXJjZS5zdHJpZGU7XG5cdFx0dGhpcy51c2FnZSA9IHNvdXJjZS51c2FnZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb3B5QXQoIGluZGV4MSwgYXR0cmlidXRlLCBpbmRleDIgKSB7XG5cblx0XHRpbmRleDEgKj0gdGhpcy5zdHJpZGU7XG5cdFx0aW5kZXgyICo9IGF0dHJpYnV0ZS5zdHJpZGU7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLnN0cmlkZTsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuYXJyYXlbIGluZGV4MSArIGkgXSA9IGF0dHJpYnV0ZS5hcnJheVsgaW5kZXgyICsgaSBdO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldCggdmFsdWUsIG9mZnNldCA9IDAgKSB7XG5cblx0XHR0aGlzLmFycmF5LnNldCggdmFsdWUsIG9mZnNldCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsb25lKCBkYXRhICkge1xuXG5cdFx0aWYgKCBkYXRhLmFycmF5QnVmZmVycyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRkYXRhLmFycmF5QnVmZmVycyA9IHt9O1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBkYXRhLmFycmF5QnVmZmVyc1sgdGhpcy5hcnJheS5idWZmZXIuX3V1aWQgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRkYXRhLmFycmF5QnVmZmVyc1sgdGhpcy5hcnJheS5idWZmZXIuX3V1aWQgXSA9IHRoaXMuYXJyYXkuc2xpY2UoIDAgKS5idWZmZXI7XG5cblx0XHR9XG5cblx0XHRjb25zdCBhcnJheSA9IG5ldyB0aGlzLmFycmF5LmNvbnN0cnVjdG9yKCBkYXRhLmFycmF5QnVmZmVyc1sgdGhpcy5hcnJheS5idWZmZXIuX3V1aWQgXSApO1xuXG5cdFx0Y29uc3QgaWIgPSBuZXcgdGhpcy5jb25zdHJ1Y3RvciggYXJyYXksIHRoaXMuc3RyaWRlICk7XG5cdFx0aWIuc2V0VXNhZ2UoIHRoaXMudXNhZ2UgKTtcblxuXHRcdHJldHVybiBpYjtcblxuXHR9XG5cblx0b25VcGxvYWQoIGNhbGxiYWNrICkge1xuXG5cdFx0dGhpcy5vblVwbG9hZENhbGxiYWNrID0gY2FsbGJhY2s7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCBkYXRhICkge1xuXG5cdFx0aWYgKCBkYXRhLmFycmF5QnVmZmVycyA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRkYXRhLmFycmF5QnVmZmVycyA9IHt9O1xuXG5cdFx0fVxuXG5cdFx0Ly8gZ2VuZXJhdGUgVVVJRCBmb3IgYXJyYXkgYnVmZmVyIGlmIG5lY2Vzc2FyeVxuXG5cdFx0aWYgKCB0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLmFycmF5LmJ1ZmZlci5fdXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBkYXRhLmFycmF5QnVmZmVyc1sgdGhpcy5hcnJheS5idWZmZXIuX3V1aWQgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRkYXRhLmFycmF5QnVmZmVyc1sgdGhpcy5hcnJheS5idWZmZXIuX3V1aWQgXSA9IEFycmF5LmZyb20oIG5ldyBVaW50MzJBcnJheSggdGhpcy5hcnJheS5idWZmZXIgKSApO1xuXG5cdFx0fVxuXG5cdFx0Ly9cblxuXHRcdHJldHVybiB7XG5cdFx0XHR1dWlkOiB0aGlzLnV1aWQsXG5cdFx0XHRidWZmZXI6IHRoaXMuYXJyYXkuYnVmZmVyLl91dWlkLFxuXHRcdFx0dHlwZTogdGhpcy5hcnJheS5jb25zdHJ1Y3Rvci5uYW1lLFxuXHRcdFx0c3RyaWRlOiB0aGlzLnN0cmlkZVxuXHRcdH07XG5cblx0fVxuXG59XG5cbmNvbnN0IF92ZWN0b3IkNiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUge1xuXG5cdGNvbnN0cnVjdG9yKCBpbnRlcmxlYXZlZEJ1ZmZlciwgaXRlbVNpemUsIG9mZnNldCwgbm9ybWFsaXplZCA9IGZhbHNlICkge1xuXG5cdFx0dGhpcy5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcblxuXHRcdHRoaXMubmFtZSA9ICcnO1xuXG5cdFx0dGhpcy5kYXRhID0gaW50ZXJsZWF2ZWRCdWZmZXI7XG5cdFx0dGhpcy5pdGVtU2l6ZSA9IGl0ZW1TaXplO1xuXHRcdHRoaXMub2Zmc2V0ID0gb2Zmc2V0O1xuXG5cdFx0dGhpcy5ub3JtYWxpemVkID0gbm9ybWFsaXplZDtcblxuXHR9XG5cblx0Z2V0IGNvdW50KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZGF0YS5jb3VudDtcblxuXHR9XG5cblx0Z2V0IGFycmF5KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZGF0YS5hcnJheTtcblxuXHR9XG5cblx0c2V0IG5lZWRzVXBkYXRlKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMuZGF0YS5uZWVkc1VwZGF0ZSA9IHZhbHVlO1xuXG5cdH1cblxuXHRhcHBseU1hdHJpeDQoIG0gKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmRhdGEuY291bnQ7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRfdmVjdG9yJDYuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggdGhpcywgaSApO1xuXG5cdFx0XHRfdmVjdG9yJDYuYXBwbHlNYXRyaXg0KCBtICk7XG5cblx0XHRcdHRoaXMuc2V0WFlaKCBpLCBfdmVjdG9yJDYueCwgX3ZlY3RvciQ2LnksIF92ZWN0b3IkNi56ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YXBwbHlOb3JtYWxNYXRyaXgoIG0gKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmNvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0X3ZlY3RvciQ2LmZyb21CdWZmZXJBdHRyaWJ1dGUoIHRoaXMsIGkgKTtcblxuXHRcdFx0X3ZlY3RvciQ2LmFwcGx5Tm9ybWFsTWF0cml4KCBtICk7XG5cblx0XHRcdHRoaXMuc2V0WFlaKCBpLCBfdmVjdG9yJDYueCwgX3ZlY3RvciQ2LnksIF92ZWN0b3IkNi56ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJhbnNmb3JtRGlyZWN0aW9uKCBtICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5jb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdF92ZWN0b3IkNi5mcm9tQnVmZmVyQXR0cmlidXRlKCB0aGlzLCBpICk7XG5cblx0XHRcdF92ZWN0b3IkNi50cmFuc2Zvcm1EaXJlY3Rpb24oIG0gKTtcblxuXHRcdFx0dGhpcy5zZXRYWVooIGksIF92ZWN0b3IkNi54LCBfdmVjdG9yJDYueSwgX3ZlY3RvciQ2LnogKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRDb21wb25lbnQoIGluZGV4LCBjb21wb25lbnQgKSB7XG5cblx0XHRsZXQgdmFsdWUgPSB0aGlzLmFycmF5WyBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldCArIGNvbXBvbmVudCBdO1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB2YWx1ZSA9IGRlbm9ybWFsaXplKCB2YWx1ZSwgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHZhbHVlO1xuXG5cdH1cblxuXHRzZXRDb21wb25lbnQoIGluZGV4LCBjb21wb25lbnQsIHZhbHVlICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB2YWx1ZSA9IG5vcm1hbGl6ZSggdmFsdWUsIHRoaXMuYXJyYXkgKTtcblxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyBjb21wb25lbnQgXSA9IHZhbHVlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFgoIGluZGV4LCB4ICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB4ID0gbm9ybWFsaXplKCB4LCB0aGlzLmFycmF5ICk7XG5cblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0IF0gPSB4O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFkoIGluZGV4LCB5ICkge1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB5ID0gbm9ybWFsaXplKCB5LCB0aGlzLmFycmF5ICk7XG5cblx0XHR0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgMSBdID0geTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRaKCBpbmRleCwgeiApIHtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xuXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldCArIDIgXSA9IHo7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0VyggaW5kZXgsIHcgKSB7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHcgPSBub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcblxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyAzIF0gPSB3O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldFgoIGluZGV4ICkge1xuXG5cdFx0bGV0IHggPSB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0IF07XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHggPSBkZW5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHg7XG5cblx0fVxuXG5cdGdldFkoIGluZGV4ICkge1xuXG5cdFx0bGV0IHkgPSB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0ICsgMSBdO1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB5ID0gZGVub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcblxuXHRcdHJldHVybiB5O1xuXG5cdH1cblxuXHRnZXRaKCBpbmRleCApIHtcblxuXHRcdGxldCB6ID0gdGhpcy5kYXRhLmFycmF5WyBpbmRleCAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldCArIDIgXTtcblxuXHRcdGlmICggdGhpcy5ub3JtYWxpemVkICkgeiA9IGRlbm9ybWFsaXplKCB6LCB0aGlzLmFycmF5ICk7XG5cblx0XHRyZXR1cm4gejtcblxuXHR9XG5cblx0Z2V0VyggaW5kZXggKSB7XG5cblx0XHRsZXQgdyA9IHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQgKyAzIF07XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHcgPSBkZW5vcm1hbGl6ZSggdywgdGhpcy5hcnJheSApO1xuXG5cdFx0cmV0dXJuIHc7XG5cblx0fVxuXG5cdHNldFhZKCBpbmRleCwgeCwgeSApIHtcblxuXHRcdGluZGV4ID0gaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQ7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcblxuXHRcdFx0eCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDAgXSA9IHg7XG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDEgXSA9IHk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0WFlaKCBpbmRleCwgeCwgeSwgeiApIHtcblxuXHRcdGluZGV4ID0gaW5kZXggKiB0aGlzLmRhdGEuc3RyaWRlICsgdGhpcy5vZmZzZXQ7XG5cblx0XHRpZiAoIHRoaXMubm9ybWFsaXplZCApIHtcblxuXHRcdFx0eCA9IG5vcm1hbGl6ZSggeCwgdGhpcy5hcnJheSApO1xuXHRcdFx0eSA9IG5vcm1hbGl6ZSggeSwgdGhpcy5hcnJheSApO1xuXHRcdFx0eiA9IG5vcm1hbGl6ZSggeiwgdGhpcy5hcnJheSApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDAgXSA9IHg7XG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDEgXSA9IHk7XG5cdFx0dGhpcy5kYXRhLmFycmF5WyBpbmRleCArIDIgXSA9IHo7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0WFlaVyggaW5kZXgsIHgsIHksIHosIHcgKSB7XG5cblx0XHRpbmRleCA9IGluZGV4ICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0O1xuXG5cdFx0aWYgKCB0aGlzLm5vcm1hbGl6ZWQgKSB7XG5cblx0XHRcdHggPSBub3JtYWxpemUoIHgsIHRoaXMuYXJyYXkgKTtcblx0XHRcdHkgPSBub3JtYWxpemUoIHksIHRoaXMuYXJyYXkgKTtcblx0XHRcdHogPSBub3JtYWxpemUoIHosIHRoaXMuYXJyYXkgKTtcblx0XHRcdHcgPSBub3JtYWxpemUoIHcsIHRoaXMuYXJyYXkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAwIF0gPSB4O1xuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAxIF0gPSB5O1xuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAyIF0gPSB6O1xuXHRcdHRoaXMuZGF0YS5hcnJheVsgaW5kZXggKyAzIF0gPSB3O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsb25lKCBkYXRhICkge1xuXG5cdFx0aWYgKCBkYXRhID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnNvbGUubG9nKCAnVEhSRUUuSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUuY2xvbmUoKTogQ2xvbmluZyBhbiBpbnRlcmxlYXZlZCBidWZmZXIgYXR0cmlidXRlIHdpbGwgZGUtaW50ZXJsZWF2ZSBidWZmZXIgZGF0YS4nICk7XG5cblx0XHRcdGNvbnN0IGFycmF5ID0gW107XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMuY291bnQ7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgaW5kZXggPSBpICogdGhpcy5kYXRhLnN0cmlkZSArIHRoaXMub2Zmc2V0O1xuXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IHRoaXMuaXRlbVNpemU7IGogKysgKSB7XG5cblx0XHRcdFx0XHRhcnJheS5wdXNoKCB0aGlzLmRhdGEuYXJyYXlbIGluZGV4ICsgaiBdICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBuZXcgQnVmZmVyQXR0cmlidXRlKCBuZXcgdGhpcy5hcnJheS5jb25zdHJ1Y3RvciggYXJyYXkgKSwgdGhpcy5pdGVtU2l6ZSwgdGhpcy5ub3JtYWxpemVkICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIGRhdGEuaW50ZXJsZWF2ZWRCdWZmZXJzID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnMgPSB7fTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGRhdGEuaW50ZXJsZWF2ZWRCdWZmZXJzWyB0aGlzLmRhdGEudXVpZCBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnNbIHRoaXMuZGF0YS51dWlkIF0gPSB0aGlzLmRhdGEuY2xvbmUoIGRhdGEgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gbmV3IEludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlKCBkYXRhLmludGVybGVhdmVkQnVmZmVyc1sgdGhpcy5kYXRhLnV1aWQgXSwgdGhpcy5pdGVtU2l6ZSwgdGhpcy5vZmZzZXQsIHRoaXMubm9ybWFsaXplZCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHR0b0pTT04oIGRhdGEgKSB7XG5cblx0XHRpZiAoIGRhdGEgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc29sZS5sb2coICdUSFJFRS5JbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZS50b0pTT04oKTogU2VyaWFsaXppbmcgYW4gaW50ZXJsZWF2ZWQgYnVmZmVyIGF0dHJpYnV0ZSB3aWxsIGRlLWludGVybGVhdmUgYnVmZmVyIGRhdGEuJyApO1xuXG5cdFx0XHRjb25zdCBhcnJheSA9IFtdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLmNvdW50OyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGluZGV4ID0gaSAqIHRoaXMuZGF0YS5zdHJpZGUgKyB0aGlzLm9mZnNldDtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCB0aGlzLml0ZW1TaXplOyBqICsrICkge1xuXG5cdFx0XHRcdFx0YXJyYXkucHVzaCggdGhpcy5kYXRhLmFycmF5WyBpbmRleCArIGogXSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBkZS1pbnRlcmxlYXZlIGRhdGEgYW5kIHNhdmUgaXQgYXMgYW4gb3JkaW5hcnkgYnVmZmVyIGF0dHJpYnV0ZSBmb3Igbm93XG5cblx0XHRcdHJldHVybiB7XG5cdFx0XHRcdGl0ZW1TaXplOiB0aGlzLml0ZW1TaXplLFxuXHRcdFx0XHR0eXBlOiB0aGlzLmFycmF5LmNvbnN0cnVjdG9yLm5hbWUsXG5cdFx0XHRcdGFycmF5OiBhcnJheSxcblx0XHRcdFx0bm9ybWFsaXplZDogdGhpcy5ub3JtYWxpemVkXG5cdFx0XHR9O1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gc2F2ZSBhcyB0cnVlIGludGVybGVhdmVkIGF0dHJpYnV0ZVxuXG5cdFx0XHRpZiAoIGRhdGEuaW50ZXJsZWF2ZWRCdWZmZXJzID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnMgPSB7fTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGRhdGEuaW50ZXJsZWF2ZWRCdWZmZXJzWyB0aGlzLmRhdGEudXVpZCBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0ZGF0YS5pbnRlcmxlYXZlZEJ1ZmZlcnNbIHRoaXMuZGF0YS51dWlkIF0gPSB0aGlzLmRhdGEudG9KU09OKCBkYXRhICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHtcblx0XHRcdFx0aXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZTogdHJ1ZSxcblx0XHRcdFx0aXRlbVNpemU6IHRoaXMuaXRlbVNpemUsXG5cdFx0XHRcdGRhdGE6IHRoaXMuZGF0YS51dWlkLFxuXHRcdFx0XHRvZmZzZXQ6IHRoaXMub2Zmc2V0LFxuXHRcdFx0XHRub3JtYWxpemVkOiB0aGlzLm5vcm1hbGl6ZWRcblx0XHRcdH07XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbmNsYXNzIFNwcml0ZU1hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNTcHJpdGVNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnU3ByaXRlTWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHhmZmZmZmYgKTtcblxuXHRcdHRoaXMubWFwID0gbnVsbDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5yb3RhdGlvbiA9IDA7XG5cblx0XHR0aGlzLnNpemVBdHRlbnVhdGlvbiA9IHRydWU7XG5cblx0XHR0aGlzLnRyYW5zcGFyZW50ID0gdHJ1ZTtcblxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcblxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcblxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBzb3VyY2UuYWxwaGFNYXA7XG5cblx0XHR0aGlzLnJvdGF0aW9uID0gc291cmNlLnJvdGF0aW9uO1xuXG5cdFx0dGhpcy5zaXplQXR0ZW51YXRpb24gPSBzb3VyY2Uuc2l6ZUF0dGVudWF0aW9uO1xuXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmxldCBfZ2VvbWV0cnk7XG5cbmNvbnN0IF9pbnRlcnNlY3RQb2ludCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF93b3JsZFNjYWxlID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX212UG9zaXRpb24gPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNvbnN0IF9hbGlnbmVkUG9zaXRpb24gPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XG5jb25zdCBfcm90YXRlZFBvc2l0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xuY29uc3QgX3ZpZXdXb3JsZE1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcblxuY29uc3QgX3ZBID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3ZCID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3ZDID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jb25zdCBfdXZBID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xuY29uc3QgX3V2QiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjIoKTtcbmNvbnN0IF91dkMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IyKCk7XG5cbmNsYXNzIFNwcml0ZSBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvciggbWF0ZXJpYWwgPSBuZXcgU3ByaXRlTWF0ZXJpYWwoKSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzU3ByaXRlID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdTcHJpdGUnO1xuXG5cdFx0aWYgKCBfZ2VvbWV0cnkgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0X2dlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cblx0XHRcdGNvbnN0IGZsb2F0MzJBcnJheSA9IG5ldyBGbG9hdDMyQXJyYXkoIFtcblx0XHRcdFx0LSAwLjUsIC0gMC41LCAwLCAwLCAwLFxuXHRcdFx0XHQwLjUsIC0gMC41LCAwLCAxLCAwLFxuXHRcdFx0XHQwLjUsIDAuNSwgMCwgMSwgMSxcblx0XHRcdFx0LSAwLjUsIDAuNSwgMCwgMCwgMVxuXHRcdFx0XSApO1xuXG5cdFx0XHRjb25zdCBpbnRlcmxlYXZlZEJ1ZmZlciA9IG5ldyBJbnRlcmxlYXZlZEJ1ZmZlciggZmxvYXQzMkFycmF5LCA1ICk7XG5cblx0XHRcdF9nZW9tZXRyeS5zZXRJbmRleCggWyAwLCAxLCAyLFx0MCwgMiwgMyBdICk7XG5cdFx0XHRfZ2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUoIGludGVybGVhdmVkQnVmZmVyLCAzLCAwLCBmYWxzZSApICk7XG5cdFx0XHRfZ2VvbWV0cnkuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUoIGludGVybGVhdmVkQnVmZmVyLCAyLCAzLCBmYWxzZSApICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmdlb21ldHJ5ID0gX2dlb21ldHJ5O1xuXHRcdHRoaXMubWF0ZXJpYWwgPSBtYXRlcmlhbDtcblxuXHRcdHRoaXMuY2VudGVyID0gbmV3IFZlY3RvcjIoIDAuNSwgMC41ICk7XG5cblx0fVxuXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcblxuXHRcdGlmICggcmF5Y2FzdGVyLmNhbWVyYSA9PT0gbnVsbCApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlNwcml0ZTogXCJSYXljYXN0ZXIuY2FtZXJhXCIgbmVlZHMgdG8gYmUgc2V0IGluIG9yZGVyIHRvIHJheWNhc3QgYWdhaW5zdCBzcHJpdGVzLicgKTtcblxuXHRcdH1cblxuXHRcdF93b3JsZFNjYWxlLnNldEZyb21NYXRyaXhTY2FsZSggdGhpcy5tYXRyaXhXb3JsZCApO1xuXG5cdFx0X3ZpZXdXb3JsZE1hdHJpeC5jb3B5KCByYXljYXN0ZXIuY2FtZXJhLm1hdHJpeFdvcmxkICk7XG5cdFx0dGhpcy5tb2RlbFZpZXdNYXRyaXgubXVsdGlwbHlNYXRyaWNlcyggcmF5Y2FzdGVyLmNhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UsIHRoaXMubWF0cml4V29ybGQgKTtcblxuXHRcdF9tdlBvc2l0aW9uLnNldEZyb21NYXRyaXhQb3NpdGlvbiggdGhpcy5tb2RlbFZpZXdNYXRyaXggKTtcblxuXHRcdGlmICggcmF5Y2FzdGVyLmNhbWVyYS5pc1BlcnNwZWN0aXZlQ2FtZXJhICYmIHRoaXMubWF0ZXJpYWwuc2l6ZUF0dGVudWF0aW9uID09PSBmYWxzZSApIHtcblxuXHRcdFx0X3dvcmxkU2NhbGUubXVsdGlwbHlTY2FsYXIoIC0gX212UG9zaXRpb24ueiApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3Qgcm90YXRpb24gPSB0aGlzLm1hdGVyaWFsLnJvdGF0aW9uO1xuXHRcdGxldCBzaW4sIGNvcztcblxuXHRcdGlmICggcm90YXRpb24gIT09IDAgKSB7XG5cblx0XHRcdGNvcyA9IE1hdGguY29zKCByb3RhdGlvbiApO1xuXHRcdFx0c2luID0gTWF0aC5zaW4oIHJvdGF0aW9uICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBjZW50ZXIgPSB0aGlzLmNlbnRlcjtcblxuXHRcdHRyYW5zZm9ybVZlcnRleCggX3ZBLnNldCggLSAwLjUsIC0gMC41LCAwICksIF9tdlBvc2l0aW9uLCBjZW50ZXIsIF93b3JsZFNjYWxlLCBzaW4sIGNvcyApO1xuXHRcdHRyYW5zZm9ybVZlcnRleCggX3ZCLnNldCggMC41LCAtIDAuNSwgMCApLCBfbXZQb3NpdGlvbiwgY2VudGVyLCBfd29ybGRTY2FsZSwgc2luLCBjb3MgKTtcblx0XHR0cmFuc2Zvcm1WZXJ0ZXgoIF92Qy5zZXQoIDAuNSwgMC41LCAwICksIF9tdlBvc2l0aW9uLCBjZW50ZXIsIF93b3JsZFNjYWxlLCBzaW4sIGNvcyApO1xuXG5cdFx0X3V2QS5zZXQoIDAsIDAgKTtcblx0XHRfdXZCLnNldCggMSwgMCApO1xuXHRcdF91dkMuc2V0KCAxLCAxICk7XG5cblx0XHQvLyBjaGVjayBmaXJzdCB0cmlhbmdsZVxuXHRcdGxldCBpbnRlcnNlY3QgPSByYXljYXN0ZXIucmF5LmludGVyc2VjdFRyaWFuZ2xlKCBfdkEsIF92QiwgX3ZDLCBmYWxzZSwgX2ludGVyc2VjdFBvaW50ICk7XG5cblx0XHRpZiAoIGludGVyc2VjdCA9PT0gbnVsbCApIHtcblxuXHRcdFx0Ly8gY2hlY2sgc2Vjb25kIHRyaWFuZ2xlXG5cdFx0XHR0cmFuc2Zvcm1WZXJ0ZXgoIF92Qi5zZXQoIC0gMC41LCAwLjUsIDAgKSwgX212UG9zaXRpb24sIGNlbnRlciwgX3dvcmxkU2NhbGUsIHNpbiwgY29zICk7XG5cdFx0XHRfdXZCLnNldCggMCwgMSApO1xuXG5cdFx0XHRpbnRlcnNlY3QgPSByYXljYXN0ZXIucmF5LmludGVyc2VjdFRyaWFuZ2xlKCBfdkEsIF92QywgX3ZCLCBmYWxzZSwgX2ludGVyc2VjdFBvaW50ICk7XG5cdFx0XHRpZiAoIGludGVyc2VjdCA9PT0gbnVsbCApIHtcblxuXHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IGRpc3RhbmNlID0gcmF5Y2FzdGVyLnJheS5vcmlnaW4uZGlzdGFuY2VUbyggX2ludGVyc2VjdFBvaW50ICk7XG5cblx0XHRpZiAoIGRpc3RhbmNlIDwgcmF5Y2FzdGVyLm5lYXIgfHwgZGlzdGFuY2UgPiByYXljYXN0ZXIuZmFyICkgcmV0dXJuO1xuXG5cdFx0aW50ZXJzZWN0cy5wdXNoKCB7XG5cblx0XHRcdGRpc3RhbmNlOiBkaXN0YW5jZSxcblx0XHRcdHBvaW50OiBfaW50ZXJzZWN0UG9pbnQuY2xvbmUoKSxcblx0XHRcdHV2OiBUcmlhbmdsZS5nZXRJbnRlcnBvbGF0aW9uKCBfaW50ZXJzZWN0UG9pbnQsIF92QSwgX3ZCLCBfdkMsIF91dkEsIF91dkIsIF91dkMsIG5ldyBWZWN0b3IyKCkgKSxcblx0XHRcdGZhY2U6IG51bGwsXG5cdFx0XHRvYmplY3Q6IHRoaXNcblxuXHRcdH0gKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0aWYgKCBzb3VyY2UuY2VudGVyICE9PSB1bmRlZmluZWQgKSB0aGlzLmNlbnRlci5jb3B5KCBzb3VyY2UuY2VudGVyICk7XG5cblx0XHR0aGlzLm1hdGVyaWFsID0gc291cmNlLm1hdGVyaWFsO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHRyYW5zZm9ybVZlcnRleCggdmVydGV4UG9zaXRpb24sIG12UG9zaXRpb24sIGNlbnRlciwgc2NhbGUsIHNpbiwgY29zICkge1xuXG5cdC8vIGNvbXB1dGUgcG9zaXRpb24gaW4gY2FtZXJhIHNwYWNlXG5cdF9hbGlnbmVkUG9zaXRpb24uc3ViVmVjdG9ycyggdmVydGV4UG9zaXRpb24sIGNlbnRlciApLmFkZFNjYWxhciggMC41ICkubXVsdGlwbHkoIHNjYWxlICk7XG5cblx0Ly8gdG8gY2hlY2sgaWYgcm90YXRpb24gaXMgbm90IHplcm9cblx0aWYgKCBzaW4gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdF9yb3RhdGVkUG9zaXRpb24ueCA9ICggY29zICogX2FsaWduZWRQb3NpdGlvbi54ICkgLSAoIHNpbiAqIF9hbGlnbmVkUG9zaXRpb24ueSApO1xuXHRcdF9yb3RhdGVkUG9zaXRpb24ueSA9ICggc2luICogX2FsaWduZWRQb3NpdGlvbi54ICkgKyAoIGNvcyAqIF9hbGlnbmVkUG9zaXRpb24ueSApO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRfcm90YXRlZFBvc2l0aW9uLmNvcHkoIF9hbGlnbmVkUG9zaXRpb24gKTtcblxuXHR9XG5cblxuXHR2ZXJ0ZXhQb3NpdGlvbi5jb3B5KCBtdlBvc2l0aW9uICk7XG5cdHZlcnRleFBvc2l0aW9uLnggKz0gX3JvdGF0ZWRQb3NpdGlvbi54O1xuXHR2ZXJ0ZXhQb3NpdGlvbi55ICs9IF9yb3RhdGVkUG9zaXRpb24ueTtcblxuXHQvLyB0cmFuc2Zvcm0gdG8gd29ybGQgc3BhY2Vcblx0dmVydGV4UG9zaXRpb24uYXBwbHlNYXRyaXg0KCBfdmlld1dvcmxkTWF0cml4ICk7XG5cbn1cblxuY29uc3QgX3YxJDIgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdjIkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgTE9EIGV4dGVuZHMgT2JqZWN0M0Qge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuX2N1cnJlbnRMZXZlbCA9IDA7XG5cblx0XHR0aGlzLnR5cGUgPSAnTE9EJztcblxuXHRcdE9iamVjdC5kZWZpbmVQcm9wZXJ0aWVzKCB0aGlzLCB7XG5cdFx0XHRsZXZlbHM6IHtcblx0XHRcdFx0ZW51bWVyYWJsZTogdHJ1ZSxcblx0XHRcdFx0dmFsdWU6IFtdXG5cdFx0XHR9LFxuXHRcdFx0aXNMT0Q6IHtcblx0XHRcdFx0dmFsdWU6IHRydWUsXG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0dGhpcy5hdXRvVXBkYXRlID0gdHJ1ZTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCBmYWxzZSApO1xuXG5cdFx0Y29uc3QgbGV2ZWxzID0gc291cmNlLmxldmVscztcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGxldmVscy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBsZXZlbCA9IGxldmVsc1sgaSBdO1xuXG5cdFx0XHR0aGlzLmFkZExldmVsKCBsZXZlbC5vYmplY3QuY2xvbmUoKSwgbGV2ZWwuZGlzdGFuY2UsIGxldmVsLmh5c3RlcmVzaXMgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuYXV0b1VwZGF0ZSA9IHNvdXJjZS5hdXRvVXBkYXRlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFkZExldmVsKCBvYmplY3QsIGRpc3RhbmNlID0gMCwgaHlzdGVyZXNpcyA9IDAgKSB7XG5cblx0XHRkaXN0YW5jZSA9IE1hdGguYWJzKCBkaXN0YW5jZSApO1xuXG5cdFx0Y29uc3QgbGV2ZWxzID0gdGhpcy5sZXZlbHM7XG5cblx0XHRsZXQgbDtcblxuXHRcdGZvciAoIGwgPSAwOyBsIDwgbGV2ZWxzLmxlbmd0aDsgbCArKyApIHtcblxuXHRcdFx0aWYgKCBkaXN0YW5jZSA8IGxldmVsc1sgbCBdLmRpc3RhbmNlICkge1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRsZXZlbHMuc3BsaWNlKCBsLCAwLCB7IGRpc3RhbmNlOiBkaXN0YW5jZSwgaHlzdGVyZXNpczogaHlzdGVyZXNpcywgb2JqZWN0OiBvYmplY3QgfSApO1xuXG5cdFx0dGhpcy5hZGQoIG9iamVjdCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldEN1cnJlbnRMZXZlbCgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9jdXJyZW50TGV2ZWw7XG5cblx0fVxuXG5cblxuXHRnZXRPYmplY3RGb3JEaXN0YW5jZSggZGlzdGFuY2UgKSB7XG5cblx0XHRjb25zdCBsZXZlbHMgPSB0aGlzLmxldmVscztcblxuXHRcdGlmICggbGV2ZWxzLmxlbmd0aCA+IDAgKSB7XG5cblx0XHRcdGxldCBpLCBsO1xuXG5cdFx0XHRmb3IgKCBpID0gMSwgbCA9IGxldmVscy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGxldCBsZXZlbERpc3RhbmNlID0gbGV2ZWxzWyBpIF0uZGlzdGFuY2U7XG5cblx0XHRcdFx0aWYgKCBsZXZlbHNbIGkgXS5vYmplY3QudmlzaWJsZSApIHtcblxuXHRcdFx0XHRcdGxldmVsRGlzdGFuY2UgLT0gbGV2ZWxEaXN0YW5jZSAqIGxldmVsc1sgaSBdLmh5c3RlcmVzaXM7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggZGlzdGFuY2UgPCBsZXZlbERpc3RhbmNlICkge1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBsZXZlbHNbIGkgLSAxIF0ub2JqZWN0O1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG51bGw7XG5cblx0fVxuXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcblxuXHRcdGNvbnN0IGxldmVscyA9IHRoaXMubGV2ZWxzO1xuXG5cdFx0aWYgKCBsZXZlbHMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0X3YxJDIuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLm1hdHJpeFdvcmxkICk7XG5cblx0XHRcdGNvbnN0IGRpc3RhbmNlID0gcmF5Y2FzdGVyLnJheS5vcmlnaW4uZGlzdGFuY2VUbyggX3YxJDIgKTtcblxuXHRcdFx0dGhpcy5nZXRPYmplY3RGb3JEaXN0YW5jZSggZGlzdGFuY2UgKS5yYXljYXN0KCByYXljYXN0ZXIsIGludGVyc2VjdHMgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0dXBkYXRlKCBjYW1lcmEgKSB7XG5cblx0XHRjb25zdCBsZXZlbHMgPSB0aGlzLmxldmVscztcblxuXHRcdGlmICggbGV2ZWxzLmxlbmd0aCA+IDEgKSB7XG5cblx0XHRcdF92MSQyLnNldEZyb21NYXRyaXhQb3NpdGlvbiggY2FtZXJhLm1hdHJpeFdvcmxkICk7XG5cdFx0XHRfdjIkMS5zZXRGcm9tTWF0cml4UG9zaXRpb24oIHRoaXMubWF0cml4V29ybGQgKTtcblxuXHRcdFx0Y29uc3QgZGlzdGFuY2UgPSBfdjEkMi5kaXN0YW5jZVRvKCBfdjIkMSApIC8gY2FtZXJhLnpvb207XG5cblx0XHRcdGxldmVsc1sgMCBdLm9iamVjdC52aXNpYmxlID0gdHJ1ZTtcblxuXHRcdFx0bGV0IGksIGw7XG5cblx0XHRcdGZvciAoIGkgPSAxLCBsID0gbGV2ZWxzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0bGV0IGxldmVsRGlzdGFuY2UgPSBsZXZlbHNbIGkgXS5kaXN0YW5jZTtcblxuXHRcdFx0XHRpZiAoIGxldmVsc1sgaSBdLm9iamVjdC52aXNpYmxlICkge1xuXG5cdFx0XHRcdFx0bGV2ZWxEaXN0YW5jZSAtPSBsZXZlbERpc3RhbmNlICogbGV2ZWxzWyBpIF0uaHlzdGVyZXNpcztcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBkaXN0YW5jZSA+PSBsZXZlbERpc3RhbmNlICkge1xuXG5cdFx0XHRcdFx0bGV2ZWxzWyBpIC0gMSBdLm9iamVjdC52aXNpYmxlID0gZmFsc2U7XG5cdFx0XHRcdFx0bGV2ZWxzWyBpIF0ub2JqZWN0LnZpc2libGUgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5fY3VycmVudExldmVsID0gaSAtIDE7XG5cblx0XHRcdGZvciAoIDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0bGV2ZWxzWyBpIF0ub2JqZWN0LnZpc2libGUgPSBmYWxzZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHR0b0pTT04oIG1ldGEgKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCBtZXRhICk7XG5cblx0XHRpZiAoIHRoaXMuYXV0b1VwZGF0ZSA9PT0gZmFsc2UgKSBkYXRhLm9iamVjdC5hdXRvVXBkYXRlID0gZmFsc2U7XG5cblx0XHRkYXRhLm9iamVjdC5sZXZlbHMgPSBbXTtcblxuXHRcdGNvbnN0IGxldmVscyA9IHRoaXMubGV2ZWxzO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gbGV2ZWxzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGxldmVsID0gbGV2ZWxzWyBpIF07XG5cblx0XHRcdGRhdGEub2JqZWN0LmxldmVscy5wdXNoKCB7XG5cdFx0XHRcdG9iamVjdDogbGV2ZWwub2JqZWN0LnV1aWQsXG5cdFx0XHRcdGRpc3RhbmNlOiBsZXZlbC5kaXN0YW5jZSxcblx0XHRcdFx0aHlzdGVyZXNpczogbGV2ZWwuaHlzdGVyZXNpc1xuXHRcdFx0fSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9iYXNlUG9zaXRpb24gPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNvbnN0IF9za2luSW5kZXggPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3I0KCk7XG5jb25zdCBfc2tpbldlaWdodCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjQoKTtcblxuY29uc3QgX3ZlY3RvcjMgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfbWF0cml4NCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF92ZXJ0ZXggPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNvbnN0IF9zcGhlcmUkNCA9IC8qQF9fUFVSRV9fKi8gbmV3IFNwaGVyZSgpO1xuY29uc3QgX2ludmVyc2VNYXRyaXgkMiA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF9yYXkkMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFJheSgpO1xuXG5jbGFzcyBTa2lubmVkTWVzaCBleHRlbmRzIE1lc2gge1xuXG5cdGNvbnN0cnVjdG9yKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKSB7XG5cblx0XHRzdXBlciggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cblx0XHR0aGlzLmlzU2tpbm5lZE1lc2ggPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ1NraW5uZWRNZXNoJztcblxuXHRcdHRoaXMuYmluZE1vZGUgPSBBdHRhY2hlZEJpbmRNb2RlO1xuXHRcdHRoaXMuYmluZE1hdHJpeCA9IG5ldyBNYXRyaXg0KCk7XG5cdFx0dGhpcy5iaW5kTWF0cml4SW52ZXJzZSA9IG5ldyBNYXRyaXg0KCk7XG5cblx0XHR0aGlzLmJvdW5kaW5nQm94ID0gbnVsbDtcblx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlID0gbnVsbDtcblxuXHR9XG5cblx0Y29tcHV0ZUJvdW5kaW5nQm94KCkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nQm94ID09PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94ID0gbmV3IEJveDMoKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuYm91bmRpbmdCb3gubWFrZUVtcHR5KCk7XG5cblx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgcG9zaXRpb25BdHRyaWJ1dGUuY291bnQ7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuZ2V0VmVydGV4UG9zaXRpb24oIGksIF92ZXJ0ZXggKTtcblx0XHRcdHRoaXMuYm91bmRpbmdCb3guZXhwYW5kQnlQb2ludCggX3ZlcnRleCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb21wdXRlQm91bmRpbmdTcGhlcmUoKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cblx0XHRpZiAoIHRoaXMuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBuZXcgU3BoZXJlKCk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlLm1ha2VFbXB0eSgpO1xuXG5cdFx0Y29uc3QgcG9zaXRpb25BdHRyaWJ1dGUgPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHBvc2l0aW9uQXR0cmlidXRlLmNvdW50OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmdldFZlcnRleFBvc2l0aW9uKCBpLCBfdmVydGV4ICk7XG5cdFx0XHR0aGlzLmJvdW5kaW5nU3BoZXJlLmV4cGFuZEJ5UG9pbnQoIF92ZXJ0ZXggKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0dGhpcy5iaW5kTW9kZSA9IHNvdXJjZS5iaW5kTW9kZTtcblx0XHR0aGlzLmJpbmRNYXRyaXguY29weSggc291cmNlLmJpbmRNYXRyaXggKTtcblx0XHR0aGlzLmJpbmRNYXRyaXhJbnZlcnNlLmNvcHkoIHNvdXJjZS5iaW5kTWF0cml4SW52ZXJzZSApO1xuXG5cdFx0dGhpcy5za2VsZXRvbiA9IHNvdXJjZS5za2VsZXRvbjtcblxuXHRcdGlmICggc291cmNlLmJvdW5kaW5nQm94ICE9PSBudWxsICkgdGhpcy5ib3VuZGluZ0JveCA9IHNvdXJjZS5ib3VuZGluZ0JveC5jbG9uZSgpO1xuXHRcdGlmICggc291cmNlLmJvdW5kaW5nU3BoZXJlICE9PSBudWxsICkgdGhpcy5ib3VuZGluZ1NwaGVyZSA9IHNvdXJjZS5ib3VuZGluZ1NwaGVyZS5jbG9uZSgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcblxuXHRcdGNvbnN0IG1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbDtcblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XG5cblx0XHRpZiAoIG1hdGVyaWFsID09PSB1bmRlZmluZWQgKSByZXR1cm47XG5cblx0XHQvLyB0ZXN0IHdpdGggYm91bmRpbmcgc3BoZXJlIGluIHdvcmxkIHNwYWNlXG5cblx0XHRpZiAoIHRoaXMuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB0aGlzLmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xuXG5cdFx0X3NwaGVyZSQ0LmNvcHkoIHRoaXMuYm91bmRpbmdTcGhlcmUgKTtcblx0XHRfc3BoZXJlJDQuYXBwbHlNYXRyaXg0KCBtYXRyaXhXb3JsZCApO1xuXG5cdFx0aWYgKCByYXljYXN0ZXIucmF5LmludGVyc2VjdHNTcGhlcmUoIF9zcGhlcmUkNCApID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdC8vIGNvbnZlcnQgcmF5IHRvIGxvY2FsIHNwYWNlIG9mIHNraW5uZWQgbWVzaFxuXG5cdFx0X2ludmVyc2VNYXRyaXgkMi5jb3B5KCBtYXRyaXhXb3JsZCApLmludmVydCgpO1xuXHRcdF9yYXkkMi5jb3B5KCByYXljYXN0ZXIucmF5ICkuYXBwbHlNYXRyaXg0KCBfaW52ZXJzZU1hdHJpeCQyICk7XG5cblx0XHQvLyB0ZXN0IHdpdGggYm91bmRpbmcgYm94IGluIGxvY2FsIHNwYWNlXG5cblx0XHRpZiAoIHRoaXMuYm91bmRpbmdCb3ggIT09IG51bGwgKSB7XG5cblx0XHRcdGlmICggX3JheSQyLmludGVyc2VjdHNCb3goIHRoaXMuYm91bmRpbmdCb3ggKSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHR9XG5cblx0XHQvLyB0ZXN0IGZvciBpbnRlcnNlY3Rpb25zIHdpdGggZ2VvbWV0cnlcblxuXHRcdHRoaXMuX2NvbXB1dGVJbnRlcnNlY3Rpb25zKCByYXljYXN0ZXIsIGludGVyc2VjdHMsIF9yYXkkMiApO1xuXG5cdH1cblxuXHRnZXRWZXJ0ZXhQb3NpdGlvbiggaW5kZXgsIHRhcmdldCApIHtcblxuXHRcdHN1cGVyLmdldFZlcnRleFBvc2l0aW9uKCBpbmRleCwgdGFyZ2V0ICk7XG5cblx0XHR0aGlzLmFwcGx5Qm9uZVRyYW5zZm9ybSggaW5kZXgsIHRhcmdldCApO1xuXG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0YmluZCggc2tlbGV0b24sIGJpbmRNYXRyaXggKSB7XG5cblx0XHR0aGlzLnNrZWxldG9uID0gc2tlbGV0b247XG5cblx0XHRpZiAoIGJpbmRNYXRyaXggPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGhpcy51cGRhdGVNYXRyaXhXb3JsZCggdHJ1ZSApO1xuXG5cdFx0XHR0aGlzLnNrZWxldG9uLmNhbGN1bGF0ZUludmVyc2VzKCk7XG5cblx0XHRcdGJpbmRNYXRyaXggPSB0aGlzLm1hdHJpeFdvcmxkO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5iaW5kTWF0cml4LmNvcHkoIGJpbmRNYXRyaXggKTtcblx0XHR0aGlzLmJpbmRNYXRyaXhJbnZlcnNlLmNvcHkoIGJpbmRNYXRyaXggKS5pbnZlcnQoKTtcblxuXHR9XG5cblx0cG9zZSgpIHtcblxuXHRcdHRoaXMuc2tlbGV0b24ucG9zZSgpO1xuXG5cdH1cblxuXHRub3JtYWxpemVTa2luV2VpZ2h0cygpIHtcblxuXHRcdGNvbnN0IHZlY3RvciA9IG5ldyBWZWN0b3I0KCk7XG5cblx0XHRjb25zdCBza2luV2VpZ2h0ID0gdGhpcy5nZW9tZXRyeS5hdHRyaWJ1dGVzLnNraW5XZWlnaHQ7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBza2luV2VpZ2h0LmNvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0dmVjdG9yLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHNraW5XZWlnaHQsIGkgKTtcblxuXHRcdFx0Y29uc3Qgc2NhbGUgPSAxLjAgLyB2ZWN0b3IubWFuaGF0dGFuTGVuZ3RoKCk7XG5cblx0XHRcdGlmICggc2NhbGUgIT09IEluZmluaXR5ICkge1xuXG5cdFx0XHRcdHZlY3Rvci5tdWx0aXBseVNjYWxhciggc2NhbGUgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHR2ZWN0b3Iuc2V0KCAxLCAwLCAwLCAwICk7IC8vIGRvIHNvbWV0aGluZyByZWFzb25hYmxlXG5cblx0XHRcdH1cblxuXHRcdFx0c2tpbldlaWdodC5zZXRYWVpXKCBpLCB2ZWN0b3IueCwgdmVjdG9yLnksIHZlY3Rvci56LCB2ZWN0b3IudyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XG5cblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcblxuXHRcdGlmICggdGhpcy5iaW5kTW9kZSA9PT0gQXR0YWNoZWRCaW5kTW9kZSApIHtcblxuXHRcdFx0dGhpcy5iaW5kTWF0cml4SW52ZXJzZS5jb3B5KCB0aGlzLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cblx0XHR9IGVsc2UgaWYgKCB0aGlzLmJpbmRNb2RlID09PSBEZXRhY2hlZEJpbmRNb2RlICkge1xuXG5cdFx0XHR0aGlzLmJpbmRNYXRyaXhJbnZlcnNlLmNvcHkoIHRoaXMuYmluZE1hdHJpeCApLmludmVydCgpO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuU2tpbm5lZE1lc2g6IFVucmVjb2duaXplZCBiaW5kTW9kZTogJyArIHRoaXMuYmluZE1vZGUgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0YXBwbHlCb25lVHJhbnNmb3JtKCBpbmRleCwgdmVjdG9yICkge1xuXG5cdFx0Y29uc3Qgc2tlbGV0b24gPSB0aGlzLnNrZWxldG9uO1xuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcblxuXHRcdF9za2luSW5kZXguZnJvbUJ1ZmZlckF0dHJpYnV0ZSggZ2VvbWV0cnkuYXR0cmlidXRlcy5za2luSW5kZXgsIGluZGV4ICk7XG5cdFx0X3NraW5XZWlnaHQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggZ2VvbWV0cnkuYXR0cmlidXRlcy5za2luV2VpZ2h0LCBpbmRleCApO1xuXG5cdFx0X2Jhc2VQb3NpdGlvbi5jb3B5KCB2ZWN0b3IgKS5hcHBseU1hdHJpeDQoIHRoaXMuYmluZE1hdHJpeCApO1xuXG5cdFx0dmVjdG9yLnNldCggMCwgMCwgMCApO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgNDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3Qgd2VpZ2h0ID0gX3NraW5XZWlnaHQuZ2V0Q29tcG9uZW50KCBpICk7XG5cblx0XHRcdGlmICggd2VpZ2h0ICE9PSAwICkge1xuXG5cdFx0XHRcdGNvbnN0IGJvbmVJbmRleCA9IF9za2luSW5kZXguZ2V0Q29tcG9uZW50KCBpICk7XG5cblx0XHRcdFx0X21hdHJpeDQubXVsdGlwbHlNYXRyaWNlcyggc2tlbGV0b24uYm9uZXNbIGJvbmVJbmRleCBdLm1hdHJpeFdvcmxkLCBza2VsZXRvbi5ib25lSW52ZXJzZXNbIGJvbmVJbmRleCBdICk7XG5cblx0XHRcdFx0dmVjdG9yLmFkZFNjYWxlZFZlY3RvciggX3ZlY3RvcjMuY29weSggX2Jhc2VQb3NpdGlvbiApLmFwcGx5TWF0cml4NCggX21hdHJpeDQgKSwgd2VpZ2h0ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB2ZWN0b3IuYXBwbHlNYXRyaXg0KCB0aGlzLmJpbmRNYXRyaXhJbnZlcnNlICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIEJvbmUgZXh0ZW5kcyBPYmplY3QzRCB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc0JvbmUgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0JvbmUnO1xuXG5cdH1cblxufVxuXG5jbGFzcyBEYXRhVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xuXG5cdGNvbnN0cnVjdG9yKCBkYXRhID0gbnVsbCwgd2lkdGggPSAxLCBoZWlnaHQgPSAxLCBmb3JtYXQsIHR5cGUsIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyID0gTmVhcmVzdEZpbHRlciwgbWluRmlsdGVyID0gTmVhcmVzdEZpbHRlciwgYW5pc290cm9weSwgY29sb3JTcGFjZSApIHtcblxuXHRcdHN1cGVyKCBudWxsLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHksIGNvbG9yU3BhY2UgKTtcblxuXHRcdHRoaXMuaXNEYXRhVGV4dHVyZSA9IHRydWU7XG5cblx0XHR0aGlzLmltYWdlID0geyBkYXRhOiBkYXRhLCB3aWR0aDogd2lkdGgsIGhlaWdodDogaGVpZ2h0IH07XG5cblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXHRcdHRoaXMuZmxpcFkgPSBmYWxzZTtcblx0XHR0aGlzLnVucGFja0FsaWdubWVudCA9IDE7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9vZmZzZXRNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfaWRlbnRpdHlNYXRyaXgkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcblxuY2xhc3MgU2tlbGV0b24ge1xuXG5cdGNvbnN0cnVjdG9yKCBib25lcyA9IFtdLCBib25lSW52ZXJzZXMgPSBbXSApIHtcblxuXHRcdHRoaXMudXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0dGhpcy5ib25lcyA9IGJvbmVzLnNsaWNlKCAwICk7XG5cdFx0dGhpcy5ib25lSW52ZXJzZXMgPSBib25lSW52ZXJzZXM7XG5cdFx0dGhpcy5ib25lTWF0cmljZXMgPSBudWxsO1xuXG5cdFx0dGhpcy5ib25lVGV4dHVyZSA9IG51bGw7XG5cblx0XHR0aGlzLmluaXQoKTtcblxuXHR9XG5cblx0aW5pdCgpIHtcblxuXHRcdGNvbnN0IGJvbmVzID0gdGhpcy5ib25lcztcblx0XHRjb25zdCBib25lSW52ZXJzZXMgPSB0aGlzLmJvbmVJbnZlcnNlcztcblxuXHRcdHRoaXMuYm9uZU1hdHJpY2VzID0gbmV3IEZsb2F0MzJBcnJheSggYm9uZXMubGVuZ3RoICogMTYgKTtcblxuXHRcdC8vIGNhbGN1bGF0ZSBpbnZlcnNlIGJvbmUgbWF0cmljZXMgaWYgbmVjZXNzYXJ5XG5cblx0XHRpZiAoIGJvbmVJbnZlcnNlcy5sZW5ndGggPT09IDAgKSB7XG5cblx0XHRcdHRoaXMuY2FsY3VsYXRlSW52ZXJzZXMoKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIGhhbmRsZSBzcGVjaWFsIGNhc2VcblxuXHRcdFx0aWYgKCBib25lcy5sZW5ndGggIT09IGJvbmVJbnZlcnNlcy5sZW5ndGggKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuU2tlbGV0b246IE51bWJlciBvZiBpbnZlcnNlIGJvbmUgbWF0cmljZXMgZG9lcyBub3QgbWF0Y2ggYW1vdW50IG9mIGJvbmVzLicgKTtcblxuXHRcdFx0XHR0aGlzLmJvbmVJbnZlcnNlcyA9IFtdO1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0aGlzLmJvbmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0dGhpcy5ib25lSW52ZXJzZXMucHVzaCggbmV3IE1hdHJpeDQoKSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRjYWxjdWxhdGVJbnZlcnNlcygpIHtcblxuXHRcdHRoaXMuYm9uZUludmVyc2VzLmxlbmd0aCA9IDA7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdGhpcy5ib25lcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgaW52ZXJzZSA9IG5ldyBNYXRyaXg0KCk7XG5cblx0XHRcdGlmICggdGhpcy5ib25lc1sgaSBdICkge1xuXG5cdFx0XHRcdGludmVyc2UuY29weSggdGhpcy5ib25lc1sgaSBdLm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5ib25lSW52ZXJzZXMucHVzaCggaW52ZXJzZSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRwb3NlKCkge1xuXG5cdFx0Ly8gcmVjb3ZlciB0aGUgYmluZC10aW1lIHdvcmxkIG1hdHJpY2VzXG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdGhpcy5ib25lcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgYm9uZSA9IHRoaXMuYm9uZXNbIGkgXTtcblxuXHRcdFx0aWYgKCBib25lICkge1xuXG5cdFx0XHRcdGJvbmUubWF0cml4V29ybGQuY29weSggdGhpcy5ib25lSW52ZXJzZXNbIGkgXSApLmludmVydCgpO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBjb21wdXRlIHRoZSBsb2NhbCBtYXRyaWNlcywgcG9zaXRpb25zLCByb3RhdGlvbnMgYW5kIHNjYWxlc1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IHRoaXMuYm9uZXMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGJvbmUgPSB0aGlzLmJvbmVzWyBpIF07XG5cblx0XHRcdGlmICggYm9uZSApIHtcblxuXHRcdFx0XHRpZiAoIGJvbmUucGFyZW50ICYmIGJvbmUucGFyZW50LmlzQm9uZSApIHtcblxuXHRcdFx0XHRcdGJvbmUubWF0cml4LmNvcHkoIGJvbmUucGFyZW50Lm1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cdFx0XHRcdFx0Ym9uZS5tYXRyaXgubXVsdGlwbHkoIGJvbmUubWF0cml4V29ybGQgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ym9uZS5tYXRyaXguY29weSggYm9uZS5tYXRyaXhXb3JsZCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRib25lLm1hdHJpeC5kZWNvbXBvc2UoIGJvbmUucG9zaXRpb24sIGJvbmUucXVhdGVybmlvbiwgYm9uZS5zY2FsZSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdHVwZGF0ZSgpIHtcblxuXHRcdGNvbnN0IGJvbmVzID0gdGhpcy5ib25lcztcblx0XHRjb25zdCBib25lSW52ZXJzZXMgPSB0aGlzLmJvbmVJbnZlcnNlcztcblx0XHRjb25zdCBib25lTWF0cmljZXMgPSB0aGlzLmJvbmVNYXRyaWNlcztcblx0XHRjb25zdCBib25lVGV4dHVyZSA9IHRoaXMuYm9uZVRleHR1cmU7XG5cblx0XHQvLyBmbGF0dGVuIGJvbmUgbWF0cmljZXMgdG8gYXJyYXlcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBib25lcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Ly8gY29tcHV0ZSB0aGUgb2Zmc2V0IGJldHdlZW4gdGhlIGN1cnJlbnQgYW5kIHRoZSBvcmlnaW5hbCB0cmFuc2Zvcm1cblxuXHRcdFx0Y29uc3QgbWF0cml4ID0gYm9uZXNbIGkgXSA/IGJvbmVzWyBpIF0ubWF0cml4V29ybGQgOiBfaWRlbnRpdHlNYXRyaXgkMTtcblxuXHRcdFx0X29mZnNldE1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBtYXRyaXgsIGJvbmVJbnZlcnNlc1sgaSBdICk7XG5cdFx0XHRfb2Zmc2V0TWF0cml4LnRvQXJyYXkoIGJvbmVNYXRyaWNlcywgaSAqIDE2ICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIGJvbmVUZXh0dXJlICE9PSBudWxsICkge1xuXG5cdFx0XHRib25lVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyBTa2VsZXRvbiggdGhpcy5ib25lcywgdGhpcy5ib25lSW52ZXJzZXMgKTtcblxuXHR9XG5cblx0Y29tcHV0ZUJvbmVUZXh0dXJlKCkge1xuXG5cdFx0Ly8gbGF5b3V0ICgxIG1hdHJpeCA9IDQgcGl4ZWxzKVxuXHRcdC8vICAgICAgUkdCQSBSR0JBIFJHQkEgUkdCQSAoPT4gY29sdW1uMSwgY29sdW1uMiwgY29sdW1uMywgY29sdW1uNClcblx0XHQvLyAgd2l0aCAgOHg4ICBwaXhlbCB0ZXh0dXJlIG1heCAgIDE2IGJvbmVzICogNCBwaXhlbHMgPSAgKDggKiA4KVxuXHRcdC8vICAgICAgIDE2eDE2IHBpeGVsIHRleHR1cmUgbWF4ICAgNjQgYm9uZXMgKiA0IHBpeGVscyA9ICgxNiAqIDE2KVxuXHRcdC8vICAgICAgIDMyeDMyIHBpeGVsIHRleHR1cmUgbWF4ICAyNTYgYm9uZXMgKiA0IHBpeGVscyA9ICgzMiAqIDMyKVxuXHRcdC8vICAgICAgIDY0eDY0IHBpeGVsIHRleHR1cmUgbWF4IDEwMjQgYm9uZXMgKiA0IHBpeGVscyA9ICg2NCAqIDY0KVxuXG5cdFx0bGV0IHNpemUgPSBNYXRoLnNxcnQoIHRoaXMuYm9uZXMubGVuZ3RoICogNCApOyAvLyA0IHBpeGVscyBuZWVkZWQgZm9yIDEgbWF0cml4XG5cdFx0c2l6ZSA9IE1hdGguY2VpbCggc2l6ZSAvIDQgKSAqIDQ7XG5cdFx0c2l6ZSA9IE1hdGgubWF4KCBzaXplLCA0ICk7XG5cblx0XHRjb25zdCBib25lTWF0cmljZXMgPSBuZXcgRmxvYXQzMkFycmF5KCBzaXplICogc2l6ZSAqIDQgKTsgLy8gNCBmbG9hdHMgcGVyIFJHQkEgcGl4ZWxcblx0XHRib25lTWF0cmljZXMuc2V0KCB0aGlzLmJvbmVNYXRyaWNlcyApOyAvLyBjb3B5IGN1cnJlbnQgdmFsdWVzXG5cblx0XHRjb25zdCBib25lVGV4dHVyZSA9IG5ldyBEYXRhVGV4dHVyZSggYm9uZU1hdHJpY2VzLCBzaXplLCBzaXplLCBSR0JBRm9ybWF0LCBGbG9hdFR5cGUgKTtcblx0XHRib25lVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR0aGlzLmJvbmVNYXRyaWNlcyA9IGJvbmVNYXRyaWNlcztcblx0XHR0aGlzLmJvbmVUZXh0dXJlID0gYm9uZVRleHR1cmU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0Qm9uZUJ5TmFtZSggbmFtZSApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0aGlzLmJvbmVzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBib25lID0gdGhpcy5ib25lc1sgaSBdO1xuXG5cdFx0XHRpZiAoIGJvbmUubmFtZSA9PT0gbmFtZSApIHtcblxuXHRcdFx0XHRyZXR1cm4gYm9uZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHVuZGVmaW5lZDtcblxuXHR9XG5cblx0ZGlzcG9zZSggKSB7XG5cblx0XHRpZiAoIHRoaXMuYm9uZVRleHR1cmUgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuYm9uZVRleHR1cmUuZGlzcG9zZSgpO1xuXG5cdFx0XHR0aGlzLmJvbmVUZXh0dXJlID0gbnVsbDtcblxuXHRcdH1cblxuXHR9XG5cblx0ZnJvbUpTT04oIGpzb24sIGJvbmVzICkge1xuXG5cdFx0dGhpcy51dWlkID0ganNvbi51dWlkO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0ganNvbi5ib25lcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCB1dWlkID0ganNvbi5ib25lc1sgaSBdO1xuXHRcdFx0bGV0IGJvbmUgPSBib25lc1sgdXVpZCBdO1xuXG5cdFx0XHRpZiAoIGJvbmUgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5Ta2VsZXRvbjogTm8gYm9uZSBmb3VuZCB3aXRoIFVVSUQ6JywgdXVpZCApO1xuXHRcdFx0XHRib25lID0gbmV3IEJvbmUoKTtcblxuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLmJvbmVzLnB1c2goIGJvbmUgKTtcblx0XHRcdHRoaXMuYm9uZUludmVyc2VzLnB1c2goIG5ldyBNYXRyaXg0KCkuZnJvbUFycmF5KCBqc29uLmJvbmVJbnZlcnNlc1sgaSBdICkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuaW5pdCgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSB7XG5cdFx0XHRtZXRhZGF0YToge1xuXHRcdFx0XHR2ZXJzaW9uOiA0LjYsXG5cdFx0XHRcdHR5cGU6ICdTa2VsZXRvbicsXG5cdFx0XHRcdGdlbmVyYXRvcjogJ1NrZWxldG9uLnRvSlNPTidcblx0XHRcdH0sXG5cdFx0XHRib25lczogW10sXG5cdFx0XHRib25lSW52ZXJzZXM6IFtdXG5cdFx0fTtcblxuXHRcdGRhdGEudXVpZCA9IHRoaXMudXVpZDtcblxuXHRcdGNvbnN0IGJvbmVzID0gdGhpcy5ib25lcztcblx0XHRjb25zdCBib25lSW52ZXJzZXMgPSB0aGlzLmJvbmVJbnZlcnNlcztcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGJvbmVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGJvbmUgPSBib25lc1sgaSBdO1xuXHRcdFx0ZGF0YS5ib25lcy5wdXNoKCBib25lLnV1aWQgKTtcblxuXHRcdFx0Y29uc3QgYm9uZUludmVyc2UgPSBib25lSW52ZXJzZXNbIGkgXTtcblx0XHRcdGRhdGEuYm9uZUludmVyc2VzLnB1c2goIGJvbmVJbnZlcnNlLnRvQXJyYXkoKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbmNsYXNzIEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSBleHRlbmRzIEJ1ZmZlckF0dHJpYnV0ZSB7XG5cblx0Y29uc3RydWN0b3IoIGFycmF5LCBpdGVtU2l6ZSwgbm9ybWFsaXplZCwgbWVzaFBlckF0dHJpYnV0ZSA9IDEgKSB7XG5cblx0XHRzdXBlciggYXJyYXksIGl0ZW1TaXplLCBub3JtYWxpemVkICk7XG5cblx0XHR0aGlzLmlzSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcblxuXHRcdHRoaXMubWVzaFBlckF0dHJpYnV0ZSA9IG1lc2hQZXJBdHRyaWJ1dGU7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5tZXNoUGVyQXR0cmlidXRlID0gc291cmNlLm1lc2hQZXJBdHRyaWJ1dGU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS5tZXNoUGVyQXR0cmlidXRlID0gdGhpcy5tZXNoUGVyQXR0cmlidXRlO1xuXG5cdFx0ZGF0YS5pc0luc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSA9IHRydWU7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cbn1cblxuY29uc3QgX2luc3RhbmNlTG9jYWxNYXRyaXggPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfaW5zdGFuY2VXb3JsZE1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcblxuY29uc3QgX2luc3RhbmNlSW50ZXJzZWN0cyA9IFtdO1xuXG5jb25zdCBfYm94MyA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcbmNvbnN0IF9pZGVudGl0eSA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF9tZXNoJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBNZXNoKCk7XG5jb25zdCBfc3BoZXJlJDMgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcblxuY2xhc3MgSW5zdGFuY2VkTWVzaCBleHRlbmRzIE1lc2gge1xuXG5cdGNvbnN0cnVjdG9yKCBnZW9tZXRyeSwgbWF0ZXJpYWwsIGNvdW50ICkge1xuXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xuXG5cdFx0dGhpcy5pc0luc3RhbmNlZE1lc2ggPSB0cnVlO1xuXG5cdFx0dGhpcy5pbnN0YW5jZU1hdHJpeCA9IG5ldyBJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUoIG5ldyBGbG9hdDMyQXJyYXkoIGNvdW50ICogMTYgKSwgMTYgKTtcblx0XHR0aGlzLmluc3RhbmNlQ29sb3IgPSBudWxsO1xuXHRcdHRoaXMubW9ycGhUZXh0dXJlID0gbnVsbDtcblxuXHRcdHRoaXMuY291bnQgPSBjb3VudDtcblxuXHRcdHRoaXMuYm91bmRpbmdCb3ggPSBudWxsO1xuXHRcdHRoaXMuYm91bmRpbmdTcGhlcmUgPSBudWxsO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY291bnQ7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuc2V0TWF0cml4QXQoIGksIF9pZGVudGl0eSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb21wdXRlQm91bmRpbmdCb3goKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cdFx0Y29uc3QgY291bnQgPSB0aGlzLmNvdW50O1xuXG5cdFx0aWYgKCB0aGlzLmJvdW5kaW5nQm94ID09PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLmJvdW5kaW5nQm94ID0gbmV3IEJveDMoKTtcblxuXHRcdH1cblxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XG5cblx0XHRcdGdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ0JveCgpO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5ib3VuZGluZ0JveC5tYWtlRW1wdHkoKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvdW50OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpLCBfaW5zdGFuY2VMb2NhbE1hdHJpeCApO1xuXG5cdFx0XHRfYm94My5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ0JveCApLmFwcGx5TWF0cml4NCggX2luc3RhbmNlTG9jYWxNYXRyaXggKTtcblxuXHRcdFx0dGhpcy5ib3VuZGluZ0JveC51bmlvbiggX2JveDMgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Y29tcHV0ZUJvdW5kaW5nU3BoZXJlKCkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGNvbnN0IGNvdW50ID0gdGhpcy5jb3VudDtcblxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG5ldyBTcGhlcmUoKTtcblxuXHRcdH1cblxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgPT09IG51bGwgKSB7XG5cblx0XHRcdGdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZS5tYWtlRW1wdHkoKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGNvdW50OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpLCBfaW5zdGFuY2VMb2NhbE1hdHJpeCApO1xuXG5cdFx0XHRfc3BoZXJlJDMuY29weSggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgKS5hcHBseU1hdHJpeDQoIF9pbnN0YW5jZUxvY2FsTWF0cml4ICk7XG5cblx0XHRcdHRoaXMuYm91bmRpbmdTcGhlcmUudW5pb24oIF9zcGhlcmUkMyApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XG5cblx0XHR0aGlzLmluc3RhbmNlTWF0cml4LmNvcHkoIHNvdXJjZS5pbnN0YW5jZU1hdHJpeCApO1xuXG5cdFx0aWYgKCBzb3VyY2UubW9ycGhUZXh0dXJlICE9PSBudWxsICkgdGhpcy5tb3JwaFRleHR1cmUgPSBzb3VyY2UubW9ycGhUZXh0dXJlLmNsb25lKCk7XG5cdFx0aWYgKCBzb3VyY2UuaW5zdGFuY2VDb2xvciAhPT0gbnVsbCApIHRoaXMuaW5zdGFuY2VDb2xvciA9IHNvdXJjZS5pbnN0YW5jZUNvbG9yLmNsb25lKCk7XG5cblx0XHR0aGlzLmNvdW50ID0gc291cmNlLmNvdW50O1xuXG5cdFx0aWYgKCBzb3VyY2UuYm91bmRpbmdCb3ggIT09IG51bGwgKSB0aGlzLmJvdW5kaW5nQm94ID0gc291cmNlLmJvdW5kaW5nQm94LmNsb25lKCk7XG5cdFx0aWYgKCBzb3VyY2UuYm91bmRpbmdTcGhlcmUgIT09IG51bGwgKSB0aGlzLmJvdW5kaW5nU3BoZXJlID0gc291cmNlLmJvdW5kaW5nU3BoZXJlLmNsb25lKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0Q29sb3JBdCggaW5kZXgsIGNvbG9yICkge1xuXG5cdFx0Y29sb3IuZnJvbUFycmF5KCB0aGlzLmluc3RhbmNlQ29sb3IuYXJyYXksIGluZGV4ICogMyApO1xuXG5cdH1cblxuXHRnZXRNYXRyaXhBdCggaW5kZXgsIG1hdHJpeCApIHtcblxuXHRcdG1hdHJpeC5mcm9tQXJyYXkoIHRoaXMuaW5zdGFuY2VNYXRyaXguYXJyYXksIGluZGV4ICogMTYgKTtcblxuXHR9XG5cblx0Z2V0TW9ycGhBdCggaW5kZXgsIG9iamVjdCApIHtcblxuXHRcdGNvbnN0IG9iamVjdEluZmx1ZW5jZXMgPSBvYmplY3QubW9ycGhUYXJnZXRJbmZsdWVuY2VzO1xuXG5cdFx0Y29uc3QgYXJyYXkgPSB0aGlzLm1vcnBoVGV4dHVyZS5zb3VyY2UuZGF0YS5kYXRhO1xuXG5cdFx0Y29uc3QgbGVuID0gb2JqZWN0SW5mbHVlbmNlcy5sZW5ndGggKyAxOyAvLyBBbGwgaW5mbHVlbmNlcyArIHRoZSBiYXNlSW5mbHVlbmNlU3VtXG5cblx0XHRjb25zdCBkYXRhSW5kZXggPSBpbmRleCAqIGxlbiArIDE7IC8vIFNraXAgdGhlIGJhc2VJbmZsdWVuY2VTdW0gYXQgdGhlIGJlZ2lubmluZ1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgb2JqZWN0SW5mbHVlbmNlcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdG9iamVjdEluZmx1ZW5jZXNbIGkgXSA9IGFycmF5WyBkYXRhSW5kZXggKyBpIF07XG5cblx0XHR9XG5cblx0fVxuXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcblxuXHRcdGNvbnN0IG1hdHJpeFdvcmxkID0gdGhpcy5tYXRyaXhXb3JsZDtcblx0XHRjb25zdCByYXljYXN0VGltZXMgPSB0aGlzLmNvdW50O1xuXG5cdFx0X21lc2gkMS5nZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cdFx0X21lc2gkMS5tYXRlcmlhbCA9IHRoaXMubWF0ZXJpYWw7XG5cblx0XHRpZiAoIF9tZXNoJDEubWF0ZXJpYWwgPT09IHVuZGVmaW5lZCApIHJldHVybjtcblxuXHRcdC8vIHRlc3Qgd2l0aCBib3VuZGluZyBzcGhlcmUgZmlyc3RcblxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHRoaXMuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XG5cblx0XHRfc3BoZXJlJDMuY29weSggdGhpcy5ib3VuZGluZ1NwaGVyZSApO1xuXHRcdF9zcGhlcmUkMy5hcHBseU1hdHJpeDQoIG1hdHJpeFdvcmxkICk7XG5cblx0XHRpZiAoIHJheWNhc3Rlci5yYXkuaW50ZXJzZWN0c1NwaGVyZSggX3NwaGVyZSQzICkgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0Ly8gbm93IHRlc3QgZWFjaCBpbnN0YW5jZVxuXG5cdFx0Zm9yICggbGV0IGluc3RhbmNlSWQgPSAwOyBpbnN0YW5jZUlkIDwgcmF5Y2FzdFRpbWVzOyBpbnN0YW5jZUlkICsrICkge1xuXG5cdFx0XHQvLyBjYWxjdWxhdGUgdGhlIHdvcmxkIG1hdHJpeCBmb3IgZWFjaCBpbnN0YW5jZVxuXG5cdFx0XHR0aGlzLmdldE1hdHJpeEF0KCBpbnN0YW5jZUlkLCBfaW5zdGFuY2VMb2NhbE1hdHJpeCApO1xuXG5cdFx0XHRfaW5zdGFuY2VXb3JsZE1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBtYXRyaXhXb3JsZCwgX2luc3RhbmNlTG9jYWxNYXRyaXggKTtcblxuXHRcdFx0Ly8gdGhlIG1lc2ggcmVwcmVzZW50cyB0aGlzIHNpbmdsZSBpbnN0YW5jZVxuXG5cdFx0XHRfbWVzaCQxLm1hdHJpeFdvcmxkID0gX2luc3RhbmNlV29ybGRNYXRyaXg7XG5cblx0XHRcdF9tZXNoJDEucmF5Y2FzdCggcmF5Y2FzdGVyLCBfaW5zdGFuY2VJbnRlcnNlY3RzICk7XG5cblx0XHRcdC8vIHByb2Nlc3MgdGhlIHJlc3VsdCBvZiByYXljYXN0XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IF9pbnN0YW5jZUludGVyc2VjdHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbnRlcnNlY3QgPSBfaW5zdGFuY2VJbnRlcnNlY3RzWyBpIF07XG5cdFx0XHRcdGludGVyc2VjdC5pbnN0YW5jZUlkID0gaW5zdGFuY2VJZDtcblx0XHRcdFx0aW50ZXJzZWN0Lm9iamVjdCA9IHRoaXM7XG5cdFx0XHRcdGludGVyc2VjdHMucHVzaCggaW50ZXJzZWN0ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0X2luc3RhbmNlSW50ZXJzZWN0cy5sZW5ndGggPSAwO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRzZXRDb2xvckF0KCBpbmRleCwgY29sb3IgKSB7XG5cblx0XHRpZiAoIHRoaXMuaW5zdGFuY2VDb2xvciA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5pbnN0YW5jZUNvbG9yID0gbmV3IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSggbmV3IEZsb2F0MzJBcnJheSggdGhpcy5pbnN0YW5jZU1hdHJpeC5jb3VudCAqIDMgKS5maWxsKCAxICksIDMgKTtcblxuXHRcdH1cblxuXHRcdGNvbG9yLnRvQXJyYXkoIHRoaXMuaW5zdGFuY2VDb2xvci5hcnJheSwgaW5kZXggKiAzICk7XG5cblx0fVxuXG5cdHNldE1hdHJpeEF0KCBpbmRleCwgbWF0cml4ICkge1xuXG5cdFx0bWF0cml4LnRvQXJyYXkoIHRoaXMuaW5zdGFuY2VNYXRyaXguYXJyYXksIGluZGV4ICogMTYgKTtcblxuXHR9XG5cblx0c2V0TW9ycGhBdCggaW5kZXgsIG9iamVjdCApIHtcblxuXHRcdGNvbnN0IG9iamVjdEluZmx1ZW5jZXMgPSBvYmplY3QubW9ycGhUYXJnZXRJbmZsdWVuY2VzO1xuXG5cdFx0Y29uc3QgbGVuID0gb2JqZWN0SW5mbHVlbmNlcy5sZW5ndGggKyAxOyAvLyBtb3JwaEJhc2VJbmZsdWVuY2UgKyBhbGwgaW5mbHVlbmNlc1xuXG5cdFx0aWYgKCB0aGlzLm1vcnBoVGV4dHVyZSA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5tb3JwaFRleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoIG5ldyBGbG9hdDMyQXJyYXkoIGxlbiAqIHRoaXMuY291bnQgKSwgbGVuLCB0aGlzLmNvdW50LCBSZWRGb3JtYXQsIEZsb2F0VHlwZSApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgYXJyYXkgPSB0aGlzLm1vcnBoVGV4dHVyZS5zb3VyY2UuZGF0YS5kYXRhO1xuXG5cdFx0bGV0IG1vcnBoSW5mbHVlbmNlc1N1bSA9IDA7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBvYmplY3RJbmZsdWVuY2VzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0bW9ycGhJbmZsdWVuY2VzU3VtICs9IG9iamVjdEluZmx1ZW5jZXNbIGkgXTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IG1vcnBoQmFzZUluZmx1ZW5jZSA9IHRoaXMuZ2VvbWV0cnkubW9ycGhUYXJnZXRzUmVsYXRpdmUgPyAxIDogMSAtIG1vcnBoSW5mbHVlbmNlc1N1bTtcblxuXHRcdGNvbnN0IGRhdGFJbmRleCA9IGxlbiAqIGluZGV4O1xuXG5cdFx0YXJyYXlbIGRhdGFJbmRleCBdID0gbW9ycGhCYXNlSW5mbHVlbmNlO1xuXG5cdFx0YXJyYXkuc2V0KCBvYmplY3RJbmZsdWVuY2VzLCBkYXRhSW5kZXggKyAxICk7XG5cblx0fVxuXG5cdHVwZGF0ZU1vcnBoVGFyZ2V0cygpIHtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZGlzcGF0Y2hFdmVudCggeyB0eXBlOiAnZGlzcG9zZScgfSApO1xuXG5cdFx0aWYgKCB0aGlzLm1vcnBoVGV4dHVyZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5tb3JwaFRleHR1cmUuZGlzcG9zZSgpO1xuXHRcdFx0dGhpcy5tb3JwaFRleHR1cmUgPSBudWxsO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHNvcnRPcGFxdWUoIGEsIGIgKSB7XG5cblx0cmV0dXJuIGEueiAtIGIuejtcblxufVxuXG5mdW5jdGlvbiBzb3J0VHJhbnNwYXJlbnQoIGEsIGIgKSB7XG5cblx0cmV0dXJuIGIueiAtIGEuejtcblxufVxuXG5jbGFzcyBNdWx0aURyYXdSZW5kZXJMaXN0IHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHRoaXMuaW5kZXggPSAwO1xuXHRcdHRoaXMucG9vbCA9IFtdO1xuXHRcdHRoaXMubGlzdCA9IFtdO1xuXG5cdH1cblxuXHRwdXNoKCBkcmF3UmFuZ2UsIHosIGluZGV4ICkge1xuXG5cdFx0Y29uc3QgcG9vbCA9IHRoaXMucG9vbDtcblx0XHRjb25zdCBsaXN0ID0gdGhpcy5saXN0O1xuXHRcdGlmICggdGhpcy5pbmRleCA+PSBwb29sLmxlbmd0aCApIHtcblxuXHRcdFx0cG9vbC5wdXNoKCB7XG5cblx0XHRcdFx0c3RhcnQ6IC0gMSxcblx0XHRcdFx0Y291bnQ6IC0gMSxcblx0XHRcdFx0ejogLSAxLFxuXHRcdFx0XHRpbmRleDogLSAxLFxuXG5cdFx0XHR9ICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBpdGVtID0gcG9vbFsgdGhpcy5pbmRleCBdO1xuXHRcdGxpc3QucHVzaCggaXRlbSApO1xuXHRcdHRoaXMuaW5kZXggKys7XG5cblx0XHRpdGVtLnN0YXJ0ID0gZHJhd1JhbmdlLnN0YXJ0O1xuXHRcdGl0ZW0uY291bnQgPSBkcmF3UmFuZ2UuY291bnQ7XG5cdFx0aXRlbS56ID0gejtcblx0XHRpdGVtLmluZGV4ID0gaW5kZXg7XG5cblx0fVxuXG5cdHJlc2V0KCkge1xuXG5cdFx0dGhpcy5saXN0Lmxlbmd0aCA9IDA7XG5cdFx0dGhpcy5pbmRleCA9IDA7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9tYXRyaXgkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF9pbnZNYXRyaXhXb3JsZCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF9pZGVudGl0eU1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF93aGl0ZUNvbG9yID0gLypAX19QVVJFX18qLyBuZXcgQ29sb3IoIDEsIDEsIDEgKTtcbmNvbnN0IF9wcm9qU2NyZWVuTWF0cml4JDIgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfZnJ1c3R1bSA9IC8qQF9fUFVSRV9fKi8gbmV3IEZydXN0dW0oKTtcbmNvbnN0IF9ib3gkMSA9IC8qQF9fUFVSRV9fKi8gbmV3IEJveDMoKTtcbmNvbnN0IF9zcGhlcmUkMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFNwaGVyZSgpO1xuY29uc3QgX3ZlY3RvciQ1ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2ZvcndhcmQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfdGVtcCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9yZW5kZXJMaXN0ID0gLypAX19QVVJFX18qLyBuZXcgTXVsdGlEcmF3UmVuZGVyTGlzdCgpO1xuY29uc3QgX21lc2ggPSAvKkBfX1BVUkVfXyovIG5ldyBNZXNoKCk7XG5jb25zdCBfYmF0Y2hJbnRlcnNlY3RzID0gW107XG5cbi8vIEBUT0RPOiBTa2lubmVkTWVzaCBzdXBwb3J0P1xuLy8gQFRPRE86IGdlb21ldHJ5Lmdyb3VwcyBzdXBwb3J0P1xuLy8gQFRPRE86IGdlb21ldHJ5LmRyYXdSYW5nZSBzdXBwb3J0P1xuLy8gQFRPRE86IGdlb21ldHJ5Lm1vcnBoQXR0cmlidXRlcyBzdXBwb3J0P1xuLy8gQFRPRE86IFN1cHBvcnQgdW5pZm9ybSBwYXJhbWV0ZXIgcGVyIGdlb21ldHJ5XG4vLyBAVE9ETzogQWRkIGFuIFwib3B0aW1pemVcIiBmdW5jdGlvbiB0byBwYWNrIGdlb21ldHJ5IGFuZCByZW1vdmUgZGF0YSBnYXBzXG5cbi8vIGNvcGllcyBkYXRhIGZyb20gYXR0cmlidXRlIFwic3JjXCIgaW50byBcInRhcmdldFwiIHN0YXJ0aW5nIGF0IFwidGFyZ2V0T2Zmc2V0XCJcbmZ1bmN0aW9uIGNvcHlBdHRyaWJ1dGVEYXRhKCBzcmMsIHRhcmdldCwgdGFyZ2V0T2Zmc2V0ID0gMCApIHtcblxuXHRjb25zdCBpdGVtU2l6ZSA9IHRhcmdldC5pdGVtU2l6ZTtcblx0aWYgKCBzcmMuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSB8fCBzcmMuYXJyYXkuY29uc3RydWN0b3IgIT09IHRhcmdldC5hcnJheS5jb25zdHJ1Y3RvciApIHtcblxuXHRcdC8vIHVzZSB0aGUgY29tcG9uZW50IGdldHRlcnMgYW5kIHNldHRlcnMgaWYgdGhlIGFycmF5IGRhdGEgY2Fubm90XG5cdFx0Ly8gYmUgY29waWVkIGRpcmVjdGx5XG5cdFx0Y29uc3QgdmVydGV4Q291bnQgPSBzcmMuY291bnQ7XG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdmVydGV4Q291bnQ7IGkgKysgKSB7XG5cblx0XHRcdGZvciAoIGxldCBjID0gMDsgYyA8IGl0ZW1TaXplOyBjICsrICkge1xuXG5cdFx0XHRcdHRhcmdldC5zZXRDb21wb25lbnQoIGkgKyB0YXJnZXRPZmZzZXQsIGMsIHNyYy5nZXRDb21wb25lbnQoIGksIGMgKSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fSBlbHNlIHtcblxuXHRcdC8vIGZhc3RlciBjb3B5IGFwcHJvYWNoIHVzaW5nIHR5cGVkIGFycmF5IHNldCBmdW5jdGlvblxuXHRcdHRhcmdldC5hcnJheS5zZXQoIHNyYy5hcnJheSwgdGFyZ2V0T2Zmc2V0ICogaXRlbVNpemUgKTtcblxuXHR9XG5cblx0dGFyZ2V0Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxufVxuXG5jbGFzcyBCYXRjaGVkTWVzaCBleHRlbmRzIE1lc2gge1xuXG5cdGdldCBtYXhJbnN0YW5jZUNvdW50KCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX21heEluc3RhbmNlQ291bnQ7XG5cblx0fVxuXG5cdGNvbnN0cnVjdG9yKCBtYXhJbnN0YW5jZUNvdW50LCBtYXhWZXJ0ZXhDb3VudCwgbWF4SW5kZXhDb3VudCA9IG1heFZlcnRleENvdW50ICogMiwgbWF0ZXJpYWwgKSB7XG5cblx0XHRzdXBlciggbmV3IEJ1ZmZlckdlb21ldHJ5KCksIG1hdGVyaWFsICk7XG5cblx0XHR0aGlzLmlzQmF0Y2hlZE1lc2ggPSB0cnVlO1xuXHRcdHRoaXMucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCA9IHRydWU7XG5cdFx0dGhpcy5zb3J0T2JqZWN0cyA9IHRydWU7XG5cdFx0dGhpcy5ib3VuZGluZ0JveCA9IG51bGw7XG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG51bGw7XG5cdFx0dGhpcy5jdXN0b21Tb3J0ID0gbnVsbDtcblxuXHRcdC8vIHN0b3JlcyB2aXNpYmxlLCBhY3RpdmUsIGFuZCBnZW9tZXRyeSBpZCBwZXIgb2JqZWN0XG5cdFx0dGhpcy5fZHJhd0luZm8gPSBbXTtcblxuXHRcdC8vIGdlb21ldHJ5IGluZm9ybWF0aW9uXG5cdFx0dGhpcy5fZHJhd1JhbmdlcyA9IFtdO1xuXHRcdHRoaXMuX3Jlc2VydmVkUmFuZ2VzID0gW107XG5cdFx0dGhpcy5fYm91bmRzID0gW107XG5cblx0XHR0aGlzLl9tYXhJbnN0YW5jZUNvdW50ID0gbWF4SW5zdGFuY2VDb3VudDtcblx0XHR0aGlzLl9tYXhWZXJ0ZXhDb3VudCA9IG1heFZlcnRleENvdW50O1xuXHRcdHRoaXMuX21heEluZGV4Q291bnQgPSBtYXhJbmRleENvdW50O1xuXG5cdFx0dGhpcy5fZ2VvbWV0cnlJbml0aWFsaXplZCA9IGZhbHNlO1xuXHRcdHRoaXMuX2dlb21ldHJ5Q291bnQgPSAwO1xuXHRcdHRoaXMuX211bHRpRHJhd0NvdW50cyA9IG5ldyBJbnQzMkFycmF5KCBtYXhJbnN0YW5jZUNvdW50ICk7XG5cdFx0dGhpcy5fbXVsdGlEcmF3U3RhcnRzID0gbmV3IEludDMyQXJyYXkoIG1heEluc3RhbmNlQ291bnQgKTtcblx0XHR0aGlzLl9tdWx0aURyYXdDb3VudCA9IDA7XG5cdFx0dGhpcy5fbXVsdGlEcmF3SW5zdGFuY2VzID0gbnVsbDtcblx0XHR0aGlzLl92aXNpYmlsaXR5Q2hhbmdlZCA9IHRydWU7XG5cblx0XHQvLyBMb2NhbCBtYXRyaXggcGVyIGdlb21ldHJ5IGJ5IHVzaW5nIGRhdGEgdGV4dHVyZVxuXHRcdHRoaXMuX21hdHJpY2VzVGV4dHVyZSA9IG51bGw7XG5cdFx0dGhpcy5faW5kaXJlY3RUZXh0dXJlID0gbnVsbDtcblx0XHR0aGlzLl9jb2xvcnNUZXh0dXJlID0gbnVsbDtcblxuXHRcdHRoaXMuX2luaXRNYXRyaWNlc1RleHR1cmUoKTtcblx0XHR0aGlzLl9pbml0SW5kaXJlY3RUZXh0dXJlKCk7XG5cblx0fVxuXG5cdF9pbml0TWF0cmljZXNUZXh0dXJlKCkge1xuXG5cdFx0Ly8gbGF5b3V0ICgxIG1hdHJpeCA9IDQgcGl4ZWxzKVxuXHRcdC8vICAgICAgUkdCQSBSR0JBIFJHQkEgUkdCQSAoPT4gY29sdW1uMSwgY29sdW1uMiwgY29sdW1uMywgY29sdW1uNClcblx0XHQvLyAgd2l0aCAgOHg4ICBwaXhlbCB0ZXh0dXJlIG1heCAgIDE2IG1hdHJpY2VzICogNCBwaXhlbHMgPSAgKDggKiA4KVxuXHRcdC8vICAgICAgIDE2eDE2IHBpeGVsIHRleHR1cmUgbWF4ICAgNjQgbWF0cmljZXMgKiA0IHBpeGVscyA9ICgxNiAqIDE2KVxuXHRcdC8vICAgICAgIDMyeDMyIHBpeGVsIHRleHR1cmUgbWF4ICAyNTYgbWF0cmljZXMgKiA0IHBpeGVscyA9ICgzMiAqIDMyKVxuXHRcdC8vICAgICAgIDY0eDY0IHBpeGVsIHRleHR1cmUgbWF4IDEwMjQgbWF0cmljZXMgKiA0IHBpeGVscyA9ICg2NCAqIDY0KVxuXG5cdFx0bGV0IHNpemUgPSBNYXRoLnNxcnQoIHRoaXMuX21heEluc3RhbmNlQ291bnQgKiA0ICk7IC8vIDQgcGl4ZWxzIG5lZWRlZCBmb3IgMSBtYXRyaXhcblx0XHRzaXplID0gTWF0aC5jZWlsKCBzaXplIC8gNCApICogNDtcblx0XHRzaXplID0gTWF0aC5tYXgoIHNpemUsIDQgKTtcblxuXHRcdGNvbnN0IG1hdHJpY2VzQXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KCBzaXplICogc2l6ZSAqIDQgKTsgLy8gNCBmbG9hdHMgcGVyIFJHQkEgcGl4ZWxcblx0XHRjb25zdCBtYXRyaWNlc1RleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoIG1hdHJpY2VzQXJyYXksIHNpemUsIHNpemUsIFJHQkFGb3JtYXQsIEZsb2F0VHlwZSApO1xuXG5cdFx0dGhpcy5fbWF0cmljZXNUZXh0dXJlID0gbWF0cmljZXNUZXh0dXJlO1xuXG5cdH1cblxuXHRfaW5pdEluZGlyZWN0VGV4dHVyZSgpIHtcblxuXHRcdGxldCBzaXplID0gTWF0aC5zcXJ0KCB0aGlzLl9tYXhJbnN0YW5jZUNvdW50ICk7XG5cdFx0c2l6ZSA9IE1hdGguY2VpbCggc2l6ZSApO1xuXG5cdFx0Y29uc3QgaW5kaXJlY3RBcnJheSA9IG5ldyBVaW50MzJBcnJheSggc2l6ZSAqIHNpemUgKTtcblx0XHRjb25zdCBpbmRpcmVjdFRleHR1cmUgPSBuZXcgRGF0YVRleHR1cmUoIGluZGlyZWN0QXJyYXksIHNpemUsIHNpemUsIFJlZEludGVnZXJGb3JtYXQsIFVuc2lnbmVkSW50VHlwZSApO1xuXG5cdFx0dGhpcy5faW5kaXJlY3RUZXh0dXJlID0gaW5kaXJlY3RUZXh0dXJlO1xuXG5cdH1cblxuXHRfaW5pdENvbG9yc1RleHR1cmUoKSB7XG5cblx0XHRsZXQgc2l6ZSA9IE1hdGguc3FydCggdGhpcy5fbWF4SW5kZXhDb3VudCApO1xuXHRcdHNpemUgPSBNYXRoLmNlaWwoIHNpemUgKTtcblxuXHRcdC8vIDQgZmxvYXRzIHBlciBSR0JBIHBpeGVsIGluaXRpYWxpemVkIHRvIHdoaXRlXG5cdFx0Y29uc3QgY29sb3JzQXJyYXkgPSBuZXcgRmxvYXQzMkFycmF5KCBzaXplICogc2l6ZSAqIDQgKS5maWxsKCAxICk7XG5cdFx0Y29uc3QgY29sb3JzVGV4dHVyZSA9IG5ldyBEYXRhVGV4dHVyZSggY29sb3JzQXJyYXksIHNpemUsIHNpemUsIFJHQkFGb3JtYXQsIEZsb2F0VHlwZSApO1xuXHRcdGNvbG9yc1RleHR1cmUuY29sb3JTcGFjZSA9IENvbG9yTWFuYWdlbWVudC53b3JraW5nQ29sb3JTcGFjZTtcblxuXHRcdHRoaXMuX2NvbG9yc1RleHR1cmUgPSBjb2xvcnNUZXh0dXJlO1xuXG5cdH1cblxuXHRfaW5pdGlhbGl6ZUdlb21ldHJ5KCByZWZlcmVuY2UgKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cdFx0Y29uc3QgbWF4VmVydGV4Q291bnQgPSB0aGlzLl9tYXhWZXJ0ZXhDb3VudDtcblx0XHRjb25zdCBtYXhJbmRleENvdW50ID0gdGhpcy5fbWF4SW5kZXhDb3VudDtcblx0XHRpZiAoIHRoaXMuX2dlb21ldHJ5SW5pdGlhbGl6ZWQgPT09IGZhbHNlICkge1xuXG5cdFx0XHRmb3IgKCBjb25zdCBhdHRyaWJ1dGVOYW1lIGluIHJlZmVyZW5jZS5hdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRcdGNvbnN0IHNyY0F0dHJpYnV0ZSA9IHJlZmVyZW5jZS5nZXRBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUgKTtcblx0XHRcdFx0Y29uc3QgeyBhcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgfSA9IHNyY0F0dHJpYnV0ZTtcblxuXHRcdFx0XHRjb25zdCBkc3RBcnJheSA9IG5ldyBhcnJheS5jb25zdHJ1Y3RvciggbWF4VmVydGV4Q291bnQgKiBpdGVtU2l6ZSApO1xuXHRcdFx0XHRjb25zdCBkc3RBdHRyaWJ1dGUgPSBuZXcgQnVmZmVyQXR0cmlidXRlKCBkc3RBcnJheSwgaXRlbVNpemUsIG5vcm1hbGl6ZWQgKTtcblxuXHRcdFx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUsIGRzdEF0dHJpYnV0ZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggcmVmZXJlbmNlLmdldEluZGV4KCkgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0Ly8gUmVzZXJ2ZSBsYXN0IHUxNiBpbmRleCBmb3IgcHJpbWl0aXZlIHJlc3RhcnQuXG5cdFx0XHRcdGNvbnN0IGluZGV4QXJyYXkgPSBtYXhWZXJ0ZXhDb3VudCA+IDY1NTM1XG5cdFx0XHRcdFx0PyBuZXcgVWludDMyQXJyYXkoIG1heEluZGV4Q291bnQgKVxuXHRcdFx0XHRcdDogbmV3IFVpbnQxNkFycmF5KCBtYXhJbmRleENvdW50ICk7XG5cblx0XHRcdFx0Z2VvbWV0cnkuc2V0SW5kZXgoIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGluZGV4QXJyYXksIDEgKSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2dlb21ldHJ5SW5pdGlhbGl6ZWQgPSB0cnVlO1xuXG5cdFx0fVxuXG5cdH1cblxuXHQvLyBNYWtlIHN1cmUgdGhlIGdlb21ldHJ5IGlzIGNvbXBhdGlibGUgd2l0aCB0aGUgZXhpc3RpbmcgY29tYmluZWQgZ2VvbWV0cnkgYXR0cmlidXRlc1xuXHRfdmFsaWRhdGVHZW9tZXRyeSggZ2VvbWV0cnkgKSB7XG5cblx0XHQvLyBjaGVjayB0byBlbnN1cmUgdGhlIGdlb21ldHJpZXMgYXJlIHVzaW5nIGNvbnNpc3RlbnQgYXR0cmlidXRlcyBhbmQgaW5kaWNlc1xuXHRcdGNvbnN0IGJhdGNoR2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGlmICggQm9vbGVhbiggZ2VvbWV0cnkuZ2V0SW5kZXgoKSApICE9PSBCb29sZWFuKCBiYXRjaEdlb21ldHJ5LmdldEluZGV4KCkgKSApIHtcblxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnQmF0Y2hlZE1lc2g6IEFsbCBnZW9tZXRyaWVzIG11c3QgY29uc2lzdGVudGx5IGhhdmUgXCJpbmRleFwiLicgKTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGNvbnN0IGF0dHJpYnV0ZU5hbWUgaW4gYmF0Y2hHZW9tZXRyeS5hdHRyaWJ1dGVzICkge1xuXG5cdFx0XHRpZiAoICEgZ2VvbWV0cnkuaGFzQXR0cmlidXRlKCBhdHRyaWJ1dGVOYW1lICkgKSB7XG5cblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCBgQmF0Y2hlZE1lc2g6IEFkZGVkIGdlb21ldHJ5IG1pc3NpbmcgXCIkeyBhdHRyaWJ1dGVOYW1lIH1cIi4gQWxsIGdlb21ldHJpZXMgbXVzdCBoYXZlIGNvbnNpc3RlbnQgYXR0cmlidXRlcy5gICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3Qgc3JjQXR0cmlidXRlID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCBhdHRyaWJ1dGVOYW1lICk7XG5cdFx0XHRjb25zdCBkc3RBdHRyaWJ1dGUgPSBiYXRjaEdlb21ldHJ5LmdldEF0dHJpYnV0ZSggYXR0cmlidXRlTmFtZSApO1xuXHRcdFx0aWYgKCBzcmNBdHRyaWJ1dGUuaXRlbVNpemUgIT09IGRzdEF0dHJpYnV0ZS5pdGVtU2l6ZSB8fCBzcmNBdHRyaWJ1dGUubm9ybWFsaXplZCAhPT0gZHN0QXR0cmlidXRlLm5vcm1hbGl6ZWQgKSB7XG5cblx0XHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnQmF0Y2hlZE1lc2g6IEFsbCBhdHRyaWJ1dGVzIG11c3QgaGF2ZSBhIGNvbnNpc3RlbnQgaXRlbVNpemUgYW5kIG5vcm1hbGl6ZWQgdmFsdWUuJyApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdHNldEN1c3RvbVNvcnQoIGZ1bmMgKSB7XG5cblx0XHR0aGlzLmN1c3RvbVNvcnQgPSBmdW5jO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb21wdXRlQm91bmRpbmdCb3goKSB7XG5cblx0XHRpZiAoIHRoaXMuYm91bmRpbmdCb3ggPT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuYm91bmRpbmdCb3ggPSBuZXcgQm94MygpO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgZ2VvbWV0cnlDb3VudCA9IHRoaXMuX2dlb21ldHJ5Q291bnQ7XG5cdFx0Y29uc3QgYm91bmRpbmdCb3ggPSB0aGlzLmJvdW5kaW5nQm94O1xuXHRcdGNvbnN0IGRyYXdJbmZvID0gdGhpcy5fZHJhd0luZm87XG5cblx0XHRib3VuZGluZ0JveC5tYWtlRW1wdHkoKTtcblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBnZW9tZXRyeUNvdW50OyBpICsrICkge1xuXG5cdFx0XHRpZiAoIGRyYXdJbmZvWyBpIF0uYWN0aXZlID09PSBmYWxzZSApIGNvbnRpbnVlO1xuXG5cdFx0XHRjb25zdCBnZW9tZXRyeUlkID0gZHJhd0luZm9bIGkgXS5nZW9tZXRyeUluZGV4O1xuXHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX21hdHJpeCQxICk7XG5cdFx0XHR0aGlzLmdldEJvdW5kaW5nQm94QXQoIGdlb21ldHJ5SWQsIF9ib3gkMSApLmFwcGx5TWF0cml4NCggX21hdHJpeCQxICk7XG5cdFx0XHRib3VuZGluZ0JveC51bmlvbiggX2JveCQxICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpIHtcblxuXHRcdGlmICggdGhpcy5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IG5ldyBTcGhlcmUoKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGJvdW5kaW5nU3BoZXJlID0gdGhpcy5ib3VuZGluZ1NwaGVyZTtcblx0XHRjb25zdCBkcmF3SW5mbyA9IHRoaXMuX2RyYXdJbmZvO1xuXG5cdFx0Ym91bmRpbmdTcGhlcmUubWFrZUVtcHR5KCk7XG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZHJhd0luZm8ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0aWYgKCBkcmF3SW5mb1sgaSBdLmFjdGl2ZSA9PT0gZmFsc2UgKSBjb250aW51ZTtcblxuXHRcdFx0Y29uc3QgZ2VvbWV0cnlJZCA9IGRyYXdJbmZvWyBpIF0uZ2VvbWV0cnlJbmRleDtcblx0XHRcdHRoaXMuZ2V0TWF0cml4QXQoIGksIF9tYXRyaXgkMSApO1xuXHRcdFx0dGhpcy5nZXRCb3VuZGluZ1NwaGVyZUF0KCBnZW9tZXRyeUlkLCBfc3BoZXJlJDIgKS5hcHBseU1hdHJpeDQoIF9tYXRyaXgkMSApO1xuXHRcdFx0Ym91bmRpbmdTcGhlcmUudW5pb24oIF9zcGhlcmUkMiApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRhZGRJbnN0YW5jZSggZ2VvbWV0cnlJZCApIHtcblxuXHRcdC8vIGVuc3VyZSB3ZSdyZSBub3Qgb3ZlciBnZW9tZXRyeVxuXHRcdGlmICggdGhpcy5fZHJhd0luZm8ubGVuZ3RoID49IHRoaXMuX21heEluc3RhbmNlQ291bnQgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBNYXhpbXVtIGl0ZW0gY291bnQgcmVhY2hlZC4nICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLl9kcmF3SW5mby5wdXNoKCB7XG5cblx0XHRcdHZpc2libGU6IHRydWUsXG5cdFx0XHRhY3RpdmU6IHRydWUsXG5cdFx0XHRnZW9tZXRyeUluZGV4OiBnZW9tZXRyeUlkLFxuXG5cdFx0fSApO1xuXG5cdFx0Ly8gaW5pdGlhbGl6ZSB0aGUgbWF0cml4XG5cdFx0Y29uc3QgZHJhd0lkID0gdGhpcy5fZHJhd0luZm8ubGVuZ3RoIC0gMTtcblx0XHRjb25zdCBtYXRyaWNlc1RleHR1cmUgPSB0aGlzLl9tYXRyaWNlc1RleHR1cmU7XG5cdFx0Y29uc3QgbWF0cmljZXNBcnJheSA9IG1hdHJpY2VzVGV4dHVyZS5pbWFnZS5kYXRhO1xuXHRcdF9pZGVudGl0eU1hdHJpeC50b0FycmF5KCBtYXRyaWNlc0FycmF5LCBkcmF3SWQgKiAxNiApO1xuXHRcdG1hdHJpY2VzVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRjb25zdCBjb2xvcnNUZXh0dXJlID0gdGhpcy5fY29sb3JzVGV4dHVyZTtcblx0XHRpZiAoIGNvbG9yc1RleHR1cmUgKSB7XG5cblx0XHRcdF93aGl0ZUNvbG9yLnRvQXJyYXkoIGNvbG9yc1RleHR1cmUuaW1hZ2UuZGF0YSwgZHJhd0lkICogNCApO1xuXHRcdFx0Y29sb3JzVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gZHJhd0lkO1xuXG5cdH1cblxuXHRhZGRHZW9tZXRyeSggZ2VvbWV0cnksIHZlcnRleENvdW50ID0gLSAxLCBpbmRleENvdW50ID0gLSAxICkge1xuXG5cdFx0dGhpcy5faW5pdGlhbGl6ZUdlb21ldHJ5KCBnZW9tZXRyeSApO1xuXG5cdFx0dGhpcy5fdmFsaWRhdGVHZW9tZXRyeSggZ2VvbWV0cnkgKTtcblxuXHRcdC8vIGVuc3VyZSB3ZSdyZSBub3Qgb3ZlciBnZW9tZXRyeVxuXHRcdGlmICggdGhpcy5fZHJhd0luZm8ubGVuZ3RoID49IHRoaXMuX21heEluc3RhbmNlQ291bnQgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBNYXhpbXVtIGl0ZW0gY291bnQgcmVhY2hlZC4nICk7XG5cblx0XHR9XG5cblx0XHQvLyBnZXQgdGhlIG5lY2Vzc2FyeSByYW5nZSBmbyB0aGUgZ2VvbWV0cnlcblx0XHRjb25zdCByZXNlcnZlZFJhbmdlID0ge1xuXHRcdFx0dmVydGV4U3RhcnQ6IC0gMSxcblx0XHRcdHZlcnRleENvdW50OiAtIDEsXG5cdFx0XHRpbmRleFN0YXJ0OiAtIDEsXG5cdFx0XHRpbmRleENvdW50OiAtIDEsXG5cdFx0fTtcblxuXHRcdGxldCBsYXN0UmFuZ2UgPSBudWxsO1xuXHRcdGNvbnN0IHJlc2VydmVkUmFuZ2VzID0gdGhpcy5fcmVzZXJ2ZWRSYW5nZXM7XG5cdFx0Y29uc3QgZHJhd1JhbmdlcyA9IHRoaXMuX2RyYXdSYW5nZXM7XG5cdFx0Y29uc3QgYm91bmRzID0gdGhpcy5fYm91bmRzO1xuXHRcdGlmICggdGhpcy5fZ2VvbWV0cnlDb3VudCAhPT0gMCApIHtcblxuXHRcdFx0bGFzdFJhbmdlID0gcmVzZXJ2ZWRSYW5nZXNbIHJlc2VydmVkUmFuZ2VzLmxlbmd0aCAtIDEgXTtcblxuXHRcdH1cblxuXHRcdGlmICggdmVydGV4Q291bnQgPT09IC0gMSApIHtcblxuXHRcdFx0cmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhDb3VudCA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApLmNvdW50O1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhDb3VudCA9IHZlcnRleENvdW50O1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBsYXN0UmFuZ2UgPT09IG51bGwgKSB7XG5cblx0XHRcdHJlc2VydmVkUmFuZ2UudmVydGV4U3RhcnQgPSAwO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhTdGFydCA9IGxhc3RSYW5nZS52ZXJ0ZXhTdGFydCArIGxhc3RSYW5nZS52ZXJ0ZXhDb3VudDtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGluZGV4ID0gZ2VvbWV0cnkuZ2V0SW5kZXgoKTtcblx0XHRjb25zdCBoYXNJbmRleCA9IGluZGV4ICE9PSBudWxsO1xuXHRcdGlmICggaGFzSW5kZXggKSB7XG5cblx0XHRcdGlmICggaW5kZXhDb3VudFx0PT09IC0gMSApIHtcblxuXHRcdFx0XHRyZXNlcnZlZFJhbmdlLmluZGV4Q291bnQgPSBpbmRleC5jb3VudDtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRyZXNlcnZlZFJhbmdlLmluZGV4Q291bnQgPSBpbmRleENvdW50O1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggbGFzdFJhbmdlID09PSBudWxsICkge1xuXG5cdFx0XHRcdHJlc2VydmVkUmFuZ2UuaW5kZXhTdGFydCA9IDA7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0cmVzZXJ2ZWRSYW5nZS5pbmRleFN0YXJ0ID0gbGFzdFJhbmdlLmluZGV4U3RhcnQgKyBsYXN0UmFuZ2UuaW5kZXhDb3VudDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKFxuXHRcdFx0cmVzZXJ2ZWRSYW5nZS5pbmRleFN0YXJ0ICE9PSAtIDEgJiZcblx0XHRcdHJlc2VydmVkUmFuZ2UuaW5kZXhTdGFydCArIHJlc2VydmVkUmFuZ2UuaW5kZXhDb3VudCA+IHRoaXMuX21heEluZGV4Q291bnQgfHxcblx0XHRcdHJlc2VydmVkUmFuZ2UudmVydGV4U3RhcnQgKyByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50ID4gdGhpcy5fbWF4VmVydGV4Q291bnRcblx0XHQpIHtcblxuXHRcdFx0dGhyb3cgbmV3IEVycm9yKCAnQmF0Y2hlZE1lc2g6IFJlc2VydmVkIHNwYWNlIHJlcXVlc3QgZXhjZWVkcyB0aGUgbWF4aW11bSBidWZmZXIgc2l6ZS4nICk7XG5cblx0XHR9XG5cblx0XHQvLyB1cGRhdGUgaWRcblx0XHRjb25zdCBnZW9tZXRyeUlkID0gdGhpcy5fZ2VvbWV0cnlDb3VudDtcblx0XHR0aGlzLl9nZW9tZXRyeUNvdW50ICsrO1xuXG5cdFx0Ly8gYWRkIHRoZSByZXNlcnZlZCByYW5nZSBhbmQgZHJhdyByYW5nZSBvYmplY3RzXG5cdFx0cmVzZXJ2ZWRSYW5nZXMucHVzaCggcmVzZXJ2ZWRSYW5nZSApO1xuXHRcdGRyYXdSYW5nZXMucHVzaCgge1xuXHRcdFx0c3RhcnQ6IGhhc0luZGV4ID8gcmVzZXJ2ZWRSYW5nZS5pbmRleFN0YXJ0IDogcmVzZXJ2ZWRSYW5nZS52ZXJ0ZXhTdGFydCxcblx0XHRcdGNvdW50OiAtIDFcblx0XHR9ICk7XG5cdFx0Ym91bmRzLnB1c2goIHtcblx0XHRcdGJveEluaXRpYWxpemVkOiBmYWxzZSxcblx0XHRcdGJveDogbmV3IEJveDMoKSxcblxuXHRcdFx0c3BoZXJlSW5pdGlhbGl6ZWQ6IGZhbHNlLFxuXHRcdFx0c3BoZXJlOiBuZXcgU3BoZXJlKClcblx0XHR9ICk7XG5cblx0XHQvLyB1cGRhdGUgdGhlIGdlb21ldHJ5XG5cdFx0dGhpcy5zZXRHZW9tZXRyeUF0KCBnZW9tZXRyeUlkLCBnZW9tZXRyeSApO1xuXG5cdFx0cmV0dXJuIGdlb21ldHJ5SWQ7XG5cblx0fVxuXG5cdHNldEdlb21ldHJ5QXQoIGdlb21ldHJ5SWQsIGdlb21ldHJ5ICkge1xuXG5cdFx0aWYgKCBnZW9tZXRyeUlkID49IHRoaXMuX2dlb21ldHJ5Q291bnQgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBNYXhpbXVtIGdlb21ldHJ5IGNvdW50IHJlYWNoZWQuJyApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5fdmFsaWRhdGVHZW9tZXRyeSggZ2VvbWV0cnkgKTtcblxuXHRcdGNvbnN0IGJhdGNoR2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGNvbnN0IGhhc0luZGV4ID0gYmF0Y2hHZW9tZXRyeS5nZXRJbmRleCgpICE9PSBudWxsO1xuXHRcdGNvbnN0IGRzdEluZGV4ID0gYmF0Y2hHZW9tZXRyeS5nZXRJbmRleCgpO1xuXHRcdGNvbnN0IHNyY0luZGV4ID0gZ2VvbWV0cnkuZ2V0SW5kZXgoKTtcblx0XHRjb25zdCByZXNlcnZlZFJhbmdlID0gdGhpcy5fcmVzZXJ2ZWRSYW5nZXNbIGdlb21ldHJ5SWQgXTtcblx0XHRpZiAoXG5cdFx0XHRoYXNJbmRleCAmJlxuXHRcdFx0c3JjSW5kZXguY291bnQgPiByZXNlcnZlZFJhbmdlLmluZGV4Q291bnQgfHxcblx0XHRcdGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb24uY291bnQgPiByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50XG5cdFx0KSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ0JhdGNoZWRNZXNoOiBSZXNlcnZlZCBzcGFjZSBub3QgbGFyZ2UgZW5vdWdoIGZvciBwcm92aWRlZCBnZW9tZXRyeS4nICk7XG5cblx0XHR9XG5cblx0XHQvLyBjb3B5IGdlb21ldHJ5IG92ZXJcblx0XHRjb25zdCB2ZXJ0ZXhTdGFydCA9IHJlc2VydmVkUmFuZ2UudmVydGV4U3RhcnQ7XG5cdFx0Y29uc3QgdmVydGV4Q291bnQgPSByZXNlcnZlZFJhbmdlLnZlcnRleENvdW50O1xuXHRcdGZvciAoIGNvbnN0IGF0dHJpYnV0ZU5hbWUgaW4gYmF0Y2hHZW9tZXRyeS5hdHRyaWJ1dGVzICkge1xuXG5cdFx0XHQvLyBjb3B5IGF0dHJpYnV0ZSBkYXRhXG5cdFx0XHRjb25zdCBzcmNBdHRyaWJ1dGUgPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoIGF0dHJpYnV0ZU5hbWUgKTtcblx0XHRcdGNvbnN0IGRzdEF0dHJpYnV0ZSA9IGJhdGNoR2VvbWV0cnkuZ2V0QXR0cmlidXRlKCBhdHRyaWJ1dGVOYW1lICk7XG5cdFx0XHRjb3B5QXR0cmlidXRlRGF0YSggc3JjQXR0cmlidXRlLCBkc3RBdHRyaWJ1dGUsIHZlcnRleFN0YXJ0ICk7XG5cblx0XHRcdC8vIGZpbGwgdGhlIHJlc3QgaW4gd2l0aCB6ZXJvZXNcblx0XHRcdGNvbnN0IGl0ZW1TaXplID0gc3JjQXR0cmlidXRlLml0ZW1TaXplO1xuXHRcdFx0Zm9yICggbGV0IGkgPSBzcmNBdHRyaWJ1dGUuY291bnQsIGwgPSB2ZXJ0ZXhDb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgaW5kZXggPSB2ZXJ0ZXhTdGFydCArIGk7XG5cdFx0XHRcdGZvciAoIGxldCBjID0gMDsgYyA8IGl0ZW1TaXplOyBjICsrICkge1xuXG5cdFx0XHRcdFx0ZHN0QXR0cmlidXRlLnNldENvbXBvbmVudCggaW5kZXgsIGMsIDAgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0ZHN0QXR0cmlidXRlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblx0XHRcdGRzdEF0dHJpYnV0ZS5hZGRVcGRhdGVSYW5nZSggdmVydGV4U3RhcnQgKiBpdGVtU2l6ZSwgdmVydGV4Q291bnQgKiBpdGVtU2l6ZSApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gY29weSBpbmRleFxuXHRcdGlmICggaGFzSW5kZXggKSB7XG5cblx0XHRcdGNvbnN0IGluZGV4U3RhcnQgPSByZXNlcnZlZFJhbmdlLmluZGV4U3RhcnQ7XG5cblx0XHRcdC8vIGNvcHkgaW5kZXggZGF0YSBvdmVyXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzcmNJbmRleC5jb3VudDsgaSArKyApIHtcblxuXHRcdFx0XHRkc3RJbmRleC5zZXRYKCBpbmRleFN0YXJ0ICsgaSwgdmVydGV4U3RhcnQgKyBzcmNJbmRleC5nZXRYKCBpICkgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBmaWxsIHRoZSByZXN0IGluIHdpdGggemVyb2VzXG5cdFx0XHRmb3IgKCBsZXQgaSA9IHNyY0luZGV4LmNvdW50LCBsID0gcmVzZXJ2ZWRSYW5nZS5pbmRleENvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRkc3RJbmRleC5zZXRYKCBpbmRleFN0YXJ0ICsgaSwgdmVydGV4U3RhcnQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRkc3RJbmRleC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0XHRkc3RJbmRleC5hZGRVcGRhdGVSYW5nZSggaW5kZXhTdGFydCwgcmVzZXJ2ZWRSYW5nZS5pbmRleENvdW50ICk7XG5cblx0XHR9XG5cblx0XHQvLyBzdG9yZSB0aGUgYm91bmRpbmcgYm94ZXNcblx0XHRjb25zdCBib3VuZCA9IHRoaXMuX2JvdW5kc1sgZ2VvbWV0cnlJZCBdO1xuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdCb3ggIT09IG51bGwgKSB7XG5cblx0XHRcdGJvdW5kLmJveC5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ0JveCApO1xuXHRcdFx0Ym91bmQuYm94SW5pdGlhbGl6ZWQgPSB0cnVlO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ym91bmQuYm94SW5pdGlhbGl6ZWQgPSBmYWxzZTtcblxuXHRcdH1cblxuXHRcdGlmICggZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgIT09IG51bGwgKSB7XG5cblx0XHRcdGJvdW5kLnNwaGVyZS5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSApO1xuXHRcdFx0Ym91bmQuc3BoZXJlSW5pdGlhbGl6ZWQgPSB0cnVlO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ym91bmQuc3BoZXJlSW5pdGlhbGl6ZWQgPSBmYWxzZTtcblxuXHRcdH1cblxuXHRcdC8vIHNldCBkcmF3UmFuZ2UgY291bnRcblx0XHRjb25zdCBkcmF3UmFuZ2UgPSB0aGlzLl9kcmF3UmFuZ2VzWyBnZW9tZXRyeUlkIF07XG5cdFx0Y29uc3QgcG9zQXR0ciA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApO1xuXHRcdGRyYXdSYW5nZS5jb3VudCA9IGhhc0luZGV4ID8gc3JjSW5kZXguY291bnQgOiBwb3NBdHRyLmNvdW50O1xuXHRcdHRoaXMuX3Zpc2liaWxpdHlDaGFuZ2VkID0gdHJ1ZTtcblxuXHRcdHJldHVybiBnZW9tZXRyeUlkO1xuXG5cdH1cblxuXHQvKlxuXHRkZWxldGVHZW9tZXRyeSggZ2VvbWV0cnlJZCApIHtcblxuXHRcdC8vIFRPRE86IGRlbGV0ZSBnZW9tZXRyeSBhbmQgYXNzb2NpYXRlZCBpbnN0YW5jZXNcblxuXHR9XG5cdCovXG5cblx0Lypcblx0ZGVsZXRlSW5zdGFuY2UoIGluc3RhbmNlSWQgKSB7XG5cblx0XHQvLyBOb3RlOiBVc2VyIG5lZWRzIHRvIGNhbGwgb3B0aW1pemUoKSBhZnRlcndhcmQgdG8gcGFjayB0aGUgZGF0YS5cblxuXHRcdGNvbnN0IGRyYXdJbmZvID0gdGhpcy5fZHJhd0luZm87XG5cdFx0aWYgKCBpbnN0YW5jZUlkID49IGRyYXdJbmZvLmxlbmd0aCB8fCBkcmF3SW5mb1sgaW5zdGFuY2VJZCBdLmFjdGl2ZSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fVxuXG5cdFx0ZHJhd0luZm9bIGluc3RhbmNlSWQgXS5hY3RpdmUgPSBmYWxzZTtcblx0XHR0aGlzLl92aXNpYmlsaXR5Q2hhbmdlZCA9IHRydWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cdCovXG5cblx0Ly8gZ2V0IGJvdW5kaW5nIGJveCBhbmQgY29tcHV0ZSBpdCBpZiBpdCBkb2Vzbid0IGV4aXN0XG5cdGdldEJvdW5kaW5nQm94QXQoIGdlb21ldHJ5SWQsIHRhcmdldCApIHtcblxuXHRcdGlmICggZ2VvbWV0cnlJZCA+PSB0aGlzLl9nZW9tZXRyeUNvdW50ICkge1xuXG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdC8vIGNvbXB1dGUgYm91bmRpbmcgYm94XG5cdFx0Y29uc3QgYm91bmQgPSB0aGlzLl9ib3VuZHNbIGdlb21ldHJ5SWQgXTtcblx0XHRjb25zdCBib3ggPSBib3VuZC5ib3g7XG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGlmICggYm91bmQuYm94SW5pdGlhbGl6ZWQgPT09IGZhbHNlICkge1xuXG5cdFx0XHRib3gubWFrZUVtcHR5KCk7XG5cblx0XHRcdGNvbnN0IGluZGV4ID0gZ2VvbWV0cnkuaW5kZXg7XG5cdFx0XHRjb25zdCBwb3NpdGlvbiA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb247XG5cdFx0XHRjb25zdCBkcmF3UmFuZ2UgPSB0aGlzLl9kcmF3UmFuZ2VzWyBnZW9tZXRyeUlkIF07XG5cdFx0XHRmb3IgKCBsZXQgaSA9IGRyYXdSYW5nZS5zdGFydCwgbCA9IGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0bGV0IGl2ID0gaTtcblx0XHRcdFx0aWYgKCBpbmRleCApIHtcblxuXHRcdFx0XHRcdGl2ID0gaW5kZXguZ2V0WCggaXYgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ym94LmV4cGFuZEJ5UG9pbnQoIF92ZWN0b3IkNS5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaXYgKSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGJvdW5kLmJveEluaXRpYWxpemVkID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdHRhcmdldC5jb3B5KCBib3ggKTtcblx0XHRyZXR1cm4gdGFyZ2V0O1xuXG5cdH1cblxuXHQvLyBnZXQgYm91bmRpbmcgc3BoZXJlIGFuZCBjb21wdXRlIGl0IGlmIGl0IGRvZXNuJ3QgZXhpc3Rcblx0Z2V0Qm91bmRpbmdTcGhlcmVBdCggZ2VvbWV0cnlJZCwgdGFyZ2V0ICkge1xuXG5cdFx0aWYgKCBnZW9tZXRyeUlkID49IHRoaXMuX2dlb21ldHJ5Q291bnQgKSB7XG5cblx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0fVxuXG5cdFx0Ly8gY29tcHV0ZSBib3VuZGluZyBzcGhlcmVcblx0XHRjb25zdCBib3VuZCA9IHRoaXMuX2JvdW5kc1sgZ2VvbWV0cnlJZCBdO1xuXHRcdGNvbnN0IHNwaGVyZSA9IGJvdW5kLnNwaGVyZTtcblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cdFx0aWYgKCBib3VuZC5zcGhlcmVJbml0aWFsaXplZCA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdHNwaGVyZS5tYWtlRW1wdHkoKTtcblxuXHRcdFx0dGhpcy5nZXRCb3VuZGluZ0JveEF0KCBnZW9tZXRyeUlkLCBfYm94JDEgKTtcblx0XHRcdF9ib3gkMS5nZXRDZW50ZXIoIHNwaGVyZS5jZW50ZXIgKTtcblxuXHRcdFx0Y29uc3QgaW5kZXggPSBnZW9tZXRyeS5pbmRleDtcblx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcblx0XHRcdGNvbnN0IGRyYXdSYW5nZSA9IHRoaXMuX2RyYXdSYW5nZXNbIGdlb21ldHJ5SWQgXTtcblxuXHRcdFx0bGV0IG1heFJhZGl1c1NxID0gMDtcblx0XHRcdGZvciAoIGxldCBpID0gZHJhd1JhbmdlLnN0YXJ0LCBsID0gZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRsZXQgaXYgPSBpO1xuXHRcdFx0XHRpZiAoIGluZGV4ICkge1xuXG5cdFx0XHRcdFx0aXYgPSBpbmRleC5nZXRYKCBpdiApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRfdmVjdG9yJDUuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIGl2ICk7XG5cdFx0XHRcdG1heFJhZGl1c1NxID0gTWF0aC5tYXgoIG1heFJhZGl1c1NxLCBzcGhlcmUuY2VudGVyLmRpc3RhbmNlVG9TcXVhcmVkKCBfdmVjdG9yJDUgKSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHNwaGVyZS5yYWRpdXMgPSBNYXRoLnNxcnQoIG1heFJhZGl1c1NxICk7XG5cdFx0XHRib3VuZC5zcGhlcmVJbml0aWFsaXplZCA9IHRydWU7XG5cblx0XHR9XG5cblx0XHR0YXJnZXQuY29weSggc3BoZXJlICk7XG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0c2V0TWF0cml4QXQoIGluc3RhbmNlSWQsIG1hdHJpeCApIHtcblxuXHRcdC8vIEBUT0RPOiBNYXAgZ2VvbWV0cnlJZCB0byBpbmRleCBvZiB0aGUgYXJyYXlzIGJlY2F1c2Vcblx0XHQvLyAgICAgICAgb3B0aW1pemUoKSBjYW4gbWFrZSBnZW9tZXRyeUlkIG1pc21hdGNoIHRoZSBpbmRleFxuXG5cdFx0Y29uc3QgZHJhd0luZm8gPSB0aGlzLl9kcmF3SW5mbztcblx0XHRjb25zdCBtYXRyaWNlc1RleHR1cmUgPSB0aGlzLl9tYXRyaWNlc1RleHR1cmU7XG5cdFx0Y29uc3QgbWF0cmljZXNBcnJheSA9IHRoaXMuX21hdHJpY2VzVGV4dHVyZS5pbWFnZS5kYXRhO1xuXHRcdGlmICggaW5zdGFuY2VJZCA+PSBkcmF3SW5mby5sZW5ndGggfHwgZHJhd0luZm9bIGluc3RhbmNlSWQgXS5hY3RpdmUgPT09IGZhbHNlICkge1xuXG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH1cblxuXHRcdG1hdHJpeC50b0FycmF5KCBtYXRyaWNlc0FycmF5LCBpbnN0YW5jZUlkICogMTYgKTtcblx0XHRtYXRyaWNlc1RleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldE1hdHJpeEF0KCBpbnN0YW5jZUlkLCBtYXRyaXggKSB7XG5cblx0XHRjb25zdCBkcmF3SW5mbyA9IHRoaXMuX2RyYXdJbmZvO1xuXHRcdGNvbnN0IG1hdHJpY2VzQXJyYXkgPSB0aGlzLl9tYXRyaWNlc1RleHR1cmUuaW1hZ2UuZGF0YTtcblx0XHRpZiAoIGluc3RhbmNlSWQgPj0gZHJhd0luZm8ubGVuZ3RoIHx8IGRyYXdJbmZvWyBpbnN0YW5jZUlkIF0uYWN0aXZlID09PSBmYWxzZSApIHtcblxuXHRcdFx0cmV0dXJuIG51bGw7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gbWF0cml4LmZyb21BcnJheSggbWF0cmljZXNBcnJheSwgaW5zdGFuY2VJZCAqIDE2ICk7XG5cblx0fVxuXG5cdHNldENvbG9yQXQoIGluc3RhbmNlSWQsIGNvbG9yICkge1xuXG5cdFx0aWYgKCB0aGlzLl9jb2xvcnNUZXh0dXJlID09PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl9pbml0Q29sb3JzVGV4dHVyZSgpO1xuXG5cdFx0fVxuXG5cdFx0Ly8gQFRPRE86IE1hcCBpZCB0byBpbmRleCBvZiB0aGUgYXJyYXlzIGJlY2F1c2Vcblx0XHQvLyAgICAgICAgb3B0aW1pemUoKSBjYW4gbWFrZSBpZCBtaXNtYXRjaCB0aGUgaW5kZXhcblxuXHRcdGNvbnN0IGNvbG9yc1RleHR1cmUgPSB0aGlzLl9jb2xvcnNUZXh0dXJlO1xuXHRcdGNvbnN0IGNvbG9yc0FycmF5ID0gdGhpcy5fY29sb3JzVGV4dHVyZS5pbWFnZS5kYXRhO1xuXHRcdGNvbnN0IGRyYXdJbmZvID0gdGhpcy5fZHJhd0luZm87XG5cdFx0aWYgKCBpbnN0YW5jZUlkID49IGRyYXdJbmZvLmxlbmd0aCB8fCBkcmF3SW5mb1sgaW5zdGFuY2VJZCBdLmFjdGl2ZSA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fVxuXG5cdFx0Y29sb3IudG9BcnJheSggY29sb3JzQXJyYXksIGluc3RhbmNlSWQgKiA0ICk7XG5cdFx0Y29sb3JzVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0Q29sb3JBdCggaW5zdGFuY2VJZCwgY29sb3IgKSB7XG5cblx0XHRjb25zdCBjb2xvcnNBcnJheSA9IHRoaXMuX2NvbG9yc1RleHR1cmUuaW1hZ2UuZGF0YTtcblx0XHRjb25zdCBkcmF3SW5mbyA9IHRoaXMuX2RyYXdJbmZvO1xuXHRcdGlmICggaW5zdGFuY2VJZCA+PSBkcmF3SW5mby5sZW5ndGggfHwgZHJhd0luZm9bIGluc3RhbmNlSWQgXS5hY3RpdmUgPT09IGZhbHNlICkge1xuXG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdHJldHVybiBjb2xvci5mcm9tQXJyYXkoIGNvbG9yc0FycmF5LCBpbnN0YW5jZUlkICogNCApO1xuXG5cdH1cblxuXHRzZXRWaXNpYmxlQXQoIGluc3RhbmNlSWQsIHZhbHVlICkge1xuXG5cdFx0Ly8gaWYgdGhlIGdlb21ldHJ5IGlzIG91dCBvZiByYW5nZSwgbm90IGFjdGl2ZSwgb3IgdmlzaWJpbGl0eSBzdGF0ZVxuXHRcdC8vIGRvZXMgbm90IGNoYW5nZSB0aGVuIHJldHVybiBlYXJseVxuXHRcdGNvbnN0IGRyYXdJbmZvID0gdGhpcy5fZHJhd0luZm87XG5cdFx0aWYgKFxuXHRcdFx0aW5zdGFuY2VJZCA+PSBkcmF3SW5mby5sZW5ndGggfHxcblx0XHRcdGRyYXdJbmZvWyBpbnN0YW5jZUlkIF0uYWN0aXZlID09PSBmYWxzZSB8fFxuXHRcdFx0ZHJhd0luZm9bIGluc3RhbmNlSWQgXS52aXNpYmxlID09PSB2YWx1ZVxuXHRcdCkge1xuXG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH1cblxuXHRcdGRyYXdJbmZvWyBpbnN0YW5jZUlkIF0udmlzaWJsZSA9IHZhbHVlO1xuXHRcdHRoaXMuX3Zpc2liaWxpdHlDaGFuZ2VkID0gdHJ1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRWaXNpYmxlQXQoIGluc3RhbmNlSWQgKSB7XG5cblx0XHQvLyByZXR1cm4gZWFybHkgaWYgdGhlIGdlb21ldHJ5IGlzIG91dCBvZiByYW5nZSBvciBub3QgYWN0aXZlXG5cdFx0Y29uc3QgZHJhd0luZm8gPSB0aGlzLl9kcmF3SW5mbztcblx0XHRpZiAoIGluc3RhbmNlSWQgPj0gZHJhd0luZm8ubGVuZ3RoIHx8IGRyYXdJbmZvWyBpbnN0YW5jZUlkIF0uYWN0aXZlID09PSBmYWxzZSApIHtcblxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRyYXdJbmZvWyBpbnN0YW5jZUlkIF0udmlzaWJsZTtcblxuXHR9XG5cblx0cmF5Y2FzdCggcmF5Y2FzdGVyLCBpbnRlcnNlY3RzICkge1xuXG5cdFx0Y29uc3QgZHJhd0luZm8gPSB0aGlzLl9kcmF3SW5mbztcblx0XHRjb25zdCBkcmF3UmFuZ2VzID0gdGhpcy5fZHJhd1Jhbmdlcztcblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XG5cdFx0Y29uc3QgYmF0Y2hHZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cblx0XHQvLyBpdGVyYXRlIG92ZXIgZWFjaCBnZW9tZXRyeVxuXHRcdF9tZXNoLm1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbDtcblx0XHRfbWVzaC5nZW9tZXRyeS5pbmRleCA9IGJhdGNoR2VvbWV0cnkuaW5kZXg7XG5cdFx0X21lc2guZ2VvbWV0cnkuYXR0cmlidXRlcyA9IGJhdGNoR2VvbWV0cnkuYXR0cmlidXRlcztcblx0XHRpZiAoIF9tZXNoLmdlb21ldHJ5LmJvdW5kaW5nQm94ID09PSBudWxsICkge1xuXG5cdFx0XHRfbWVzaC5nZW9tZXRyeS5ib3VuZGluZ0JveCA9IG5ldyBCb3gzKCk7XG5cblx0XHR9XG5cblx0XHRpZiAoIF9tZXNoLmdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID09PSBudWxsICkge1xuXG5cdFx0XHRfbWVzaC5nZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9IG5ldyBTcGhlcmUoKTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGRyYXdJbmZvLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGlmICggISBkcmF3SW5mb1sgaSBdLnZpc2libGUgfHwgISBkcmF3SW5mb1sgaSBdLmFjdGl2ZSApIHtcblxuXHRcdFx0XHRjb250aW51ZTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBnZW9tZXRyeUlkID0gZHJhd0luZm9bIGkgXS5nZW9tZXRyeUluZGV4O1xuXHRcdFx0Y29uc3QgZHJhd1JhbmdlID0gZHJhd1Jhbmdlc1sgZ2VvbWV0cnlJZCBdO1xuXHRcdFx0X21lc2guZ2VvbWV0cnkuc2V0RHJhd1JhbmdlKCBkcmF3UmFuZ2Uuc3RhcnQsIGRyYXdSYW5nZS5jb3VudCApO1xuXG5cdFx0XHQvLyBnZSB0aGUgaW50ZXJzZWN0c1xuXHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX21lc2gubWF0cml4V29ybGQgKS5wcmVtdWx0aXBseSggbWF0cml4V29ybGQgKTtcblx0XHRcdHRoaXMuZ2V0Qm91bmRpbmdCb3hBdCggZ2VvbWV0cnlJZCwgX21lc2guZ2VvbWV0cnkuYm91bmRpbmdCb3ggKTtcblx0XHRcdHRoaXMuZ2V0Qm91bmRpbmdTcGhlcmVBdCggZ2VvbWV0cnlJZCwgX21lc2guZ2VvbWV0cnkuYm91bmRpbmdTcGhlcmUgKTtcblx0XHRcdF9tZXNoLnJheWNhc3QoIHJheWNhc3RlciwgX2JhdGNoSW50ZXJzZWN0cyApO1xuXG5cdFx0XHQvLyBhZGQgYmF0Y2ggaWQgdG8gdGhlIGludGVyc2VjdHNcblx0XHRcdGZvciAoIGxldCBqID0gMCwgbCA9IF9iYXRjaEludGVyc2VjdHMubGVuZ3RoOyBqIDwgbDsgaiArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbnRlcnNlY3QgPSBfYmF0Y2hJbnRlcnNlY3RzWyBqIF07XG5cdFx0XHRcdGludGVyc2VjdC5vYmplY3QgPSB0aGlzO1xuXHRcdFx0XHRpbnRlcnNlY3QuYmF0Y2hJZCA9IGk7XG5cdFx0XHRcdGludGVyc2VjdHMucHVzaCggaW50ZXJzZWN0ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0X2JhdGNoSW50ZXJzZWN0cy5sZW5ndGggPSAwO1xuXG5cdFx0fVxuXG5cdFx0X21lc2gubWF0ZXJpYWwgPSBudWxsO1xuXHRcdF9tZXNoLmdlb21ldHJ5LmluZGV4ID0gbnVsbDtcblx0XHRfbWVzaC5nZW9tZXRyeS5hdHRyaWJ1dGVzID0ge307XG5cdFx0X21lc2guZ2VvbWV0cnkuc2V0RHJhd1JhbmdlKCAwLCBJbmZpbml0eSApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuZ2VvbWV0cnkgPSBzb3VyY2UuZ2VvbWV0cnkuY2xvbmUoKTtcblx0XHR0aGlzLnBlck9iamVjdEZydXN0dW1DdWxsZWQgPSBzb3VyY2UucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZDtcblx0XHR0aGlzLnNvcnRPYmplY3RzID0gc291cmNlLnNvcnRPYmplY3RzO1xuXHRcdHRoaXMuYm91bmRpbmdCb3ggPSBzb3VyY2UuYm91bmRpbmdCb3ggIT09IG51bGwgPyBzb3VyY2UuYm91bmRpbmdCb3guY2xvbmUoKSA6IG51bGw7XG5cdFx0dGhpcy5ib3VuZGluZ1NwaGVyZSA9IHNvdXJjZS5ib3VuZGluZ1NwaGVyZSAhPT0gbnVsbCA/IHNvdXJjZS5ib3VuZGluZ1NwaGVyZS5jbG9uZSgpIDogbnVsbDtcblxuXHRcdHRoaXMuX2RyYXdSYW5nZXMgPSBzb3VyY2UuX2RyYXdSYW5nZXMubWFwKCByYW5nZSA9PiAoIHsgLi4ucmFuZ2UgfSApICk7XG5cdFx0dGhpcy5fcmVzZXJ2ZWRSYW5nZXMgPSBzb3VyY2UuX3Jlc2VydmVkUmFuZ2VzLm1hcCggcmFuZ2UgPT4gKCB7IC4uLnJhbmdlIH0gKSApO1xuXG5cdFx0dGhpcy5fZHJhd0luZm8gPSBzb3VyY2UuX2RyYXdJbmZvLm1hcCggaW5mID0+ICggeyAuLi5pbmYgfSApICk7XG5cdFx0dGhpcy5fYm91bmRzID0gc291cmNlLl9ib3VuZHMubWFwKCBib3VuZCA9PiAoIHtcblx0XHRcdGJveEluaXRpYWxpemVkOiBib3VuZC5ib3hJbml0aWFsaXplZCxcblx0XHRcdGJveDogYm91bmQuYm94LmNsb25lKCksXG5cblx0XHRcdHNwaGVyZUluaXRpYWxpemVkOiBib3VuZC5zcGhlcmVJbml0aWFsaXplZCxcblx0XHRcdHNwaGVyZTogYm91bmQuc3BoZXJlLmNsb25lKClcblx0XHR9ICkgKTtcblxuXHRcdHRoaXMuX21heEluc3RhbmNlQ291bnQgPSBzb3VyY2UuX21heEluc3RhbmNlQ291bnQ7XG5cdFx0dGhpcy5fbWF4VmVydGV4Q291bnQgPSBzb3VyY2UuX21heFZlcnRleENvdW50O1xuXHRcdHRoaXMuX21heEluZGV4Q291bnQgPSBzb3VyY2UuX21heEluZGV4Q291bnQ7XG5cblx0XHR0aGlzLl9nZW9tZXRyeUluaXRpYWxpemVkID0gc291cmNlLl9nZW9tZXRyeUluaXRpYWxpemVkO1xuXHRcdHRoaXMuX2dlb21ldHJ5Q291bnQgPSBzb3VyY2UuX2dlb21ldHJ5Q291bnQ7XG5cdFx0dGhpcy5fbXVsdGlEcmF3Q291bnRzID0gc291cmNlLl9tdWx0aURyYXdDb3VudHMuc2xpY2UoKTtcblx0XHR0aGlzLl9tdWx0aURyYXdTdGFydHMgPSBzb3VyY2UuX211bHRpRHJhd1N0YXJ0cy5zbGljZSgpO1xuXG5cdFx0dGhpcy5fbWF0cmljZXNUZXh0dXJlID0gc291cmNlLl9tYXRyaWNlc1RleHR1cmUuY2xvbmUoKTtcblx0XHR0aGlzLl9tYXRyaWNlc1RleHR1cmUuaW1hZ2UuZGF0YSA9IHRoaXMuX21hdHJpY2VzVGV4dHVyZS5pbWFnZS5kYXRhLnNsaWNlKCk7XG5cblx0XHRpZiAoIHRoaXMuX2NvbG9yc1RleHR1cmUgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX2NvbG9yc1RleHR1cmUgPSBzb3VyY2UuX2NvbG9yc1RleHR1cmUuY2xvbmUoKTtcblx0XHRcdHRoaXMuX2NvbG9yc1RleHR1cmUuaW1hZ2UuZGF0YSA9IHRoaXMuX2NvbG9yc1RleHR1cmUuaW1hZ2UuZGF0YS5zbGljZSgpO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHQvLyBBc3N1bWluZyB0aGUgZ2VvbWV0cnkgaXMgbm90IHNoYXJlZCB3aXRoIG90aGVyIG1lc2hlc1xuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXG5cdFx0dGhpcy5fbWF0cmljZXNUZXh0dXJlLmRpc3Bvc2UoKTtcblx0XHR0aGlzLl9tYXRyaWNlc1RleHR1cmUgPSBudWxsO1xuXG5cdFx0dGhpcy5faW5kaXJlY3RUZXh0dXJlLmRpc3Bvc2UoKTtcblx0XHR0aGlzLl9pbmRpcmVjdFRleHR1cmUgPSBudWxsO1xuXG5cdFx0aWYgKCB0aGlzLl9jb2xvcnNUZXh0dXJlICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl9jb2xvcnNUZXh0dXJlLmRpc3Bvc2UoKTtcblx0XHRcdHRoaXMuX2NvbG9yc1RleHR1cmUgPSBudWxsO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG9uQmVmb3JlUmVuZGVyKCByZW5kZXJlciwgc2NlbmUsIGNhbWVyYSwgZ2VvbWV0cnksIG1hdGVyaWFsLyosIF9ncm91cCovICkge1xuXG5cdFx0Ly8gaWYgdmlzaWJpbGl0eSBoYXMgbm90IGNoYW5nZWQgYW5kIGZydXN0dW0gY3VsbGluZyBhbmQgb2JqZWN0IHNvcnRpbmcgaXMgbm90IHJlcXVpcmVkXG5cdFx0Ly8gdGhlbiBza2lwIGl0ZXJhdGluZyBvdmVyIGFsbCBpdGVtc1xuXHRcdGlmICggISB0aGlzLl92aXNpYmlsaXR5Q2hhbmdlZCAmJiAhIHRoaXMucGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCAmJiAhIHRoaXMuc29ydE9iamVjdHMgKSB7XG5cblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdC8vIHRoZSBpbmRleGVkIHZlcnNpb24gb2YgdGhlIG11bHRpIGRyYXcgZnVuY3Rpb24gcmVxdWlyZXMgc3BlY2lmeWluZyB0aGUgc3RhcnRcblx0XHQvLyBvZmZzZXQgaW4gYnl0ZXMuXG5cdFx0Y29uc3QgaW5kZXggPSBnZW9tZXRyeS5nZXRJbmRleCgpO1xuXHRcdGNvbnN0IGJ5dGVzUGVyRWxlbWVudCA9IGluZGV4ID09PSBudWxsID8gMSA6IGluZGV4LmFycmF5LkJZVEVTX1BFUl9FTEVNRU5UO1xuXG5cdFx0Y29uc3QgZHJhd0luZm8gPSB0aGlzLl9kcmF3SW5mbztcblx0XHRjb25zdCBtdWx0aURyYXdTdGFydHMgPSB0aGlzLl9tdWx0aURyYXdTdGFydHM7XG5cdFx0Y29uc3QgbXVsdGlEcmF3Q291bnRzID0gdGhpcy5fbXVsdGlEcmF3Q291bnRzO1xuXHRcdGNvbnN0IGRyYXdSYW5nZXMgPSB0aGlzLl9kcmF3UmFuZ2VzO1xuXHRcdGNvbnN0IHBlck9iamVjdEZydXN0dW1DdWxsZWQgPSB0aGlzLnBlck9iamVjdEZydXN0dW1DdWxsZWQ7XG5cdFx0Y29uc3QgaW5kaXJlY3RUZXh0dXJlID0gdGhpcy5faW5kaXJlY3RUZXh0dXJlO1xuXHRcdGNvbnN0IGluZGlyZWN0QXJyYXkgPSBpbmRpcmVjdFRleHR1cmUuaW1hZ2UuZGF0YTtcblxuXHRcdC8vIHByZXBhcmUgdGhlIGZydXN0dW0gaW4gdGhlIGxvY2FsIGZyYW1lXG5cdFx0aWYgKCBwZXJPYmplY3RGcnVzdHVtQ3VsbGVkICkge1xuXG5cdFx0XHRfcHJvalNjcmVlbk1hdHJpeCQyXG5cdFx0XHRcdC5tdWx0aXBseU1hdHJpY2VzKCBjYW1lcmEucHJvamVjdGlvbk1hdHJpeCwgY2FtZXJhLm1hdHJpeFdvcmxkSW52ZXJzZSApXG5cdFx0XHRcdC5tdWx0aXBseSggdGhpcy5tYXRyaXhXb3JsZCApO1xuXHRcdFx0X2ZydXN0dW0uc2V0RnJvbVByb2plY3Rpb25NYXRyaXgoXG5cdFx0XHRcdF9wcm9qU2NyZWVuTWF0cml4JDIsXG5cdFx0XHRcdHJlbmRlcmVyLmNvb3JkaW5hdGVTeXN0ZW1cblx0XHRcdCk7XG5cblx0XHR9XG5cblx0XHRsZXQgY291bnQgPSAwO1xuXHRcdGlmICggdGhpcy5zb3J0T2JqZWN0cyApIHtcblxuXHRcdFx0Ly8gZ2V0IHRoZSBjYW1lcmEgcG9zaXRpb24gaW4gdGhlIGxvY2FsIGZyYW1lXG5cdFx0XHRfaW52TWF0cml4V29ybGQuY29weSggdGhpcy5tYXRyaXhXb3JsZCApLmludmVydCgpO1xuXHRcdFx0X3ZlY3RvciQ1LnNldEZyb21NYXRyaXhQb3NpdGlvbiggY2FtZXJhLm1hdHJpeFdvcmxkICkuYXBwbHlNYXRyaXg0KCBfaW52TWF0cml4V29ybGQgKTtcblx0XHRcdF9mb3J3YXJkLnNldCggMCwgMCwgLSAxICkudHJhbnNmb3JtRGlyZWN0aW9uKCBjYW1lcmEubWF0cml4V29ybGQgKS50cmFuc2Zvcm1EaXJlY3Rpb24oIF9pbnZNYXRyaXhXb3JsZCApO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBkcmF3SW5mby5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGlmICggZHJhd0luZm9bIGkgXS52aXNpYmxlICYmIGRyYXdJbmZvWyBpIF0uYWN0aXZlICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgZ2VvbWV0cnlJZCA9IGRyYXdJbmZvWyBpIF0uZ2VvbWV0cnlJbmRleDtcblxuXHRcdFx0XHRcdC8vIGdldCB0aGUgYm91bmRzIGluIHdvcmxkIHNwYWNlXG5cdFx0XHRcdFx0dGhpcy5nZXRNYXRyaXhBdCggaSwgX21hdHJpeCQxICk7XG5cdFx0XHRcdFx0dGhpcy5nZXRCb3VuZGluZ1NwaGVyZUF0KCBnZW9tZXRyeUlkLCBfc3BoZXJlJDIgKS5hcHBseU1hdHJpeDQoIF9tYXRyaXgkMSApO1xuXG5cdFx0XHRcdFx0Ly8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGJhdGNoZWQgZ2VvbWV0cnkgaXMgd2l0aGluIHRoZSBmcnVzdHVtXG5cdFx0XHRcdFx0bGV0IGN1bGxlZCA9IGZhbHNlO1xuXHRcdFx0XHRcdGlmICggcGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCApIHtcblxuXHRcdFx0XHRcdFx0Y3VsbGVkID0gISBfZnJ1c3R1bS5pbnRlcnNlY3RzU3BoZXJlKCBfc3BoZXJlJDIgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggISBjdWxsZWQgKSB7XG5cblx0XHRcdFx0XHRcdC8vIGdldCB0aGUgZGlzdGFuY2UgZnJvbSBjYW1lcmEgdXNlZCBmb3Igc29ydGluZ1xuXHRcdFx0XHRcdFx0Y29uc3QgeiA9IF90ZW1wLnN1YlZlY3RvcnMoIF9zcGhlcmUkMi5jZW50ZXIsIF92ZWN0b3IkNSApLmRvdCggX2ZvcndhcmQgKTtcblx0XHRcdFx0XHRcdF9yZW5kZXJMaXN0LnB1c2goIGRyYXdSYW5nZXNbIGdlb21ldHJ5SWQgXSwgeiwgaSApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBTb3J0IHRoZSBkcmF3IHJhbmdlcyBhbmQgcHJlcCBmb3IgcmVuZGVyaW5nXG5cdFx0XHRjb25zdCBsaXN0ID0gX3JlbmRlckxpc3QubGlzdDtcblx0XHRcdGNvbnN0IGN1c3RvbVNvcnQgPSB0aGlzLmN1c3RvbVNvcnQ7XG5cdFx0XHRpZiAoIGN1c3RvbVNvcnQgPT09IG51bGwgKSB7XG5cblx0XHRcdFx0bGlzdC5zb3J0KCBtYXRlcmlhbC50cmFuc3BhcmVudCA/IHNvcnRUcmFuc3BhcmVudCA6IHNvcnRPcGFxdWUgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjdXN0b21Tb3J0LmNhbGwoIHRoaXMsIGxpc3QsIGNhbWVyYSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGxpc3QubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpdGVtID0gbGlzdFsgaSBdO1xuXHRcdFx0XHRtdWx0aURyYXdTdGFydHNbIGNvdW50IF0gPSBpdGVtLnN0YXJ0ICogYnl0ZXNQZXJFbGVtZW50O1xuXHRcdFx0XHRtdWx0aURyYXdDb3VudHNbIGNvdW50IF0gPSBpdGVtLmNvdW50O1xuXHRcdFx0XHRpbmRpcmVjdEFycmF5WyBjb3VudCBdID0gaXRlbS5pbmRleDtcblx0XHRcdFx0Y291bnQgKys7XG5cblx0XHRcdH1cblxuXHRcdFx0X3JlbmRlckxpc3QucmVzZXQoKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGRyYXdJbmZvLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0aWYgKCBkcmF3SW5mb1sgaSBdLnZpc2libGUgJiYgZHJhd0luZm9bIGkgXS5hY3RpdmUgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBnZW9tZXRyeUlkID0gZHJhd0luZm9bIGkgXS5nZW9tZXRyeUluZGV4O1xuXG5cdFx0XHRcdFx0Ly8gZGV0ZXJtaW5lIHdoZXRoZXIgdGhlIGJhdGNoZWQgZ2VvbWV0cnkgaXMgd2l0aGluIHRoZSBmcnVzdHVtXG5cdFx0XHRcdFx0bGV0IGN1bGxlZCA9IGZhbHNlO1xuXHRcdFx0XHRcdGlmICggcGVyT2JqZWN0RnJ1c3R1bUN1bGxlZCApIHtcblxuXHRcdFx0XHRcdFx0Ly8gZ2V0IHRoZSBib3VuZHMgaW4gd29ybGQgc3BhY2Vcblx0XHRcdFx0XHRcdHRoaXMuZ2V0TWF0cml4QXQoIGksIF9tYXRyaXgkMSApO1xuXHRcdFx0XHRcdFx0dGhpcy5nZXRCb3VuZGluZ1NwaGVyZUF0KCBnZW9tZXRyeUlkLCBfc3BoZXJlJDIgKS5hcHBseU1hdHJpeDQoIF9tYXRyaXgkMSApO1xuXHRcdFx0XHRcdFx0Y3VsbGVkID0gISBfZnJ1c3R1bS5pbnRlcnNlY3RzU3BoZXJlKCBfc3BoZXJlJDIgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggISBjdWxsZWQgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IHJhbmdlID0gZHJhd1Jhbmdlc1sgZ2VvbWV0cnlJZCBdO1xuXHRcdFx0XHRcdFx0bXVsdGlEcmF3U3RhcnRzWyBjb3VudCBdID0gcmFuZ2Uuc3RhcnQgKiBieXRlc1BlckVsZW1lbnQ7XG5cdFx0XHRcdFx0XHRtdWx0aURyYXdDb3VudHNbIGNvdW50IF0gPSByYW5nZS5jb3VudDtcblx0XHRcdFx0XHRcdGluZGlyZWN0QXJyYXlbIGNvdW50IF0gPSBpO1xuXHRcdFx0XHRcdFx0Y291bnQgKys7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpbmRpcmVjdFRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXHRcdHRoaXMuX211bHRpRHJhd0NvdW50ID0gY291bnQ7XG5cdFx0dGhpcy5fdmlzaWJpbGl0eUNoYW5nZWQgPSBmYWxzZTtcblxuXHR9XG5cblx0b25CZWZvcmVTaGFkb3coIHJlbmRlcmVyLCBvYmplY3QsIGNhbWVyYSwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbC8qICwgZ3JvdXAgKi8gKSB7XG5cblx0XHR0aGlzLm9uQmVmb3JlUmVuZGVyKCByZW5kZXJlciwgbnVsbCwgc2hhZG93Q2FtZXJhLCBnZW9tZXRyeSwgZGVwdGhNYXRlcmlhbCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBMaW5lQmFzaWNNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTGluZUJhc2ljTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0xpbmVCYXNpY01hdGVyaWFsJztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmxpbmV3aWR0aCA9IDE7XG5cdFx0dGhpcy5saW5lY2FwID0gJ3JvdW5kJztcblx0XHR0aGlzLmxpbmVqb2luID0gJ3JvdW5kJztcblxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcblxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XG5cblx0fVxuXG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLmNvbG9yLmNvcHkoIHNvdXJjZS5jb2xvciApO1xuXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xuXG5cdFx0dGhpcy5saW5ld2lkdGggPSBzb3VyY2UubGluZXdpZHRoO1xuXHRcdHRoaXMubGluZWNhcCA9IHNvdXJjZS5saW5lY2FwO1xuXHRcdHRoaXMubGluZWpvaW4gPSBzb3VyY2UubGluZWpvaW47XG5cblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY29uc3QgX3ZTdGFydCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92RW5kID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jb25zdCBfaW52ZXJzZU1hdHJpeCQxID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX3JheSQxID0gLypAX19QVVJFX18qLyBuZXcgUmF5KCk7XG5jb25zdCBfc3BoZXJlJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcblxuY29uc3QgX2ludGVyc2VjdFBvaW50T25SYXkgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfaW50ZXJzZWN0UG9pbnRPblNlZ21lbnQgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5cbmNsYXNzIExpbmUgZXh0ZW5kcyBPYmplY3QzRCB7XG5cblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCksIG1hdGVyaWFsID0gbmV3IExpbmVCYXNpY01hdGVyaWFsKCkgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc0xpbmUgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0xpbmUnO1xuXG5cdFx0dGhpcy5nZW9tZXRyeSA9IGdlb21ldHJ5O1xuXHRcdHRoaXMubWF0ZXJpYWwgPSBtYXRlcmlhbDtcblxuXHRcdHRoaXMudXBkYXRlTW9ycGhUYXJnZXRzKCk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcblxuXHRcdHRoaXMubWF0ZXJpYWwgPSBBcnJheS5pc0FycmF5KCBzb3VyY2UubWF0ZXJpYWwgKSA/IHNvdXJjZS5tYXRlcmlhbC5zbGljZSgpIDogc291cmNlLm1hdGVyaWFsO1xuXHRcdHRoaXMuZ2VvbWV0cnkgPSBzb3VyY2UuZ2VvbWV0cnk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29tcHV0ZUxpbmVEaXN0YW5jZXMoKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cblx0XHQvLyB3ZSBhc3N1bWUgbm9uLWluZGV4ZWQgZ2VvbWV0cnlcblxuXHRcdGlmICggZ2VvbWV0cnkuaW5kZXggPT09IG51bGwgKSB7XG5cblx0XHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcblx0XHRcdGNvbnN0IGxpbmVEaXN0YW5jZXMgPSBbIDAgXTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAxLCBsID0gcG9zaXRpb25BdHRyaWJ1dGUuY291bnQ7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdF92U3RhcnQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgLSAxICk7XG5cdFx0XHRcdF92RW5kLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBpICk7XG5cblx0XHRcdFx0bGluZURpc3RhbmNlc1sgaSBdID0gbGluZURpc3RhbmNlc1sgaSAtIDEgXTtcblx0XHRcdFx0bGluZURpc3RhbmNlc1sgaSBdICs9IF92U3RhcnQuZGlzdGFuY2VUbyggX3ZFbmQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdsaW5lRGlzdGFuY2UnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbGluZURpc3RhbmNlcywgMSApICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5MaW5lLmNvbXB1dGVMaW5lRGlzdGFuY2VzKCk6IENvbXB1dGF0aW9uIG9ubHkgcG9zc2libGUgd2l0aCBub24taW5kZXhlZCBCdWZmZXJHZW9tZXRyeS4nICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cmF5Y2FzdCggcmF5Y2FzdGVyLCBpbnRlcnNlY3RzICkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGNvbnN0IG1hdHJpeFdvcmxkID0gdGhpcy5tYXRyaXhXb3JsZDtcblx0XHRjb25zdCB0aHJlc2hvbGQgPSByYXljYXN0ZXIucGFyYW1zLkxpbmUudGhyZXNob2xkO1xuXHRcdGNvbnN0IGRyYXdSYW5nZSA9IGdlb21ldHJ5LmRyYXdSYW5nZTtcblxuXHRcdC8vIENoZWNraW5nIGJvdW5kaW5nU3BoZXJlIGRpc3RhbmNlIHRvIHJheVxuXG5cdFx0aWYgKCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIGdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xuXG5cdFx0X3NwaGVyZSQxLmNvcHkoIGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlICk7XG5cdFx0X3NwaGVyZSQxLmFwcGx5TWF0cml4NCggbWF0cml4V29ybGQgKTtcblx0XHRfc3BoZXJlJDEucmFkaXVzICs9IHRocmVzaG9sZDtcblxuXHRcdGlmICggcmF5Y2FzdGVyLnJheS5pbnRlcnNlY3RzU3BoZXJlKCBfc3BoZXJlJDEgKSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHQvL1xuXG5cdFx0X2ludmVyc2VNYXRyaXgkMS5jb3B5KCBtYXRyaXhXb3JsZCApLmludmVydCgpO1xuXHRcdF9yYXkkMS5jb3B5KCByYXljYXN0ZXIucmF5ICkuYXBwbHlNYXRyaXg0KCBfaW52ZXJzZU1hdHJpeCQxICk7XG5cblx0XHRjb25zdCBsb2NhbFRocmVzaG9sZCA9IHRocmVzaG9sZCAvICggKCB0aGlzLnNjYWxlLnggKyB0aGlzLnNjYWxlLnkgKyB0aGlzLnNjYWxlLnogKSAvIDMgKTtcblx0XHRjb25zdCBsb2NhbFRocmVzaG9sZFNxID0gbG9jYWxUaHJlc2hvbGQgKiBsb2NhbFRocmVzaG9sZDtcblxuXHRcdGNvbnN0IHN0ZXAgPSB0aGlzLmlzTGluZVNlZ21lbnRzID8gMiA6IDE7XG5cblx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmluZGV4O1xuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzO1xuXHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gYXR0cmlidXRlcy5wb3NpdGlvbjtcblxuXHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XG5cblx0XHRcdGNvbnN0IHN0YXJ0ID0gTWF0aC5tYXgoIDAsIGRyYXdSYW5nZS5zdGFydCApO1xuXHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIGluZGV4LmNvdW50LCAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gc3RhcnQsIGwgPSBlbmQgLSAxOyBpIDwgbDsgaSArPSBzdGVwICkge1xuXG5cdFx0XHRcdGNvbnN0IGEgPSBpbmRleC5nZXRYKCBpICk7XG5cdFx0XHRcdGNvbnN0IGIgPSBpbmRleC5nZXRYKCBpICsgMSApO1xuXG5cdFx0XHRcdGNvbnN0IGludGVyc2VjdCA9IGNoZWNrSW50ZXJzZWN0aW9uKCB0aGlzLCByYXljYXN0ZXIsIF9yYXkkMSwgbG9jYWxUaHJlc2hvbGRTcSwgYSwgYiApO1xuXG5cdFx0XHRcdGlmICggaW50ZXJzZWN0ICkge1xuXG5cdFx0XHRcdFx0aW50ZXJzZWN0cy5wdXNoKCBpbnRlcnNlY3QgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0aGlzLmlzTGluZUxvb3AgKSB7XG5cblx0XHRcdFx0Y29uc3QgYSA9IGluZGV4LmdldFgoIGVuZCAtIDEgKTtcblx0XHRcdFx0Y29uc3QgYiA9IGluZGV4LmdldFgoIHN0YXJ0ICk7XG5cblx0XHRcdFx0Y29uc3QgaW50ZXJzZWN0ID0gY2hlY2tJbnRlcnNlY3Rpb24oIHRoaXMsIHJheWNhc3RlciwgX3JheSQxLCBsb2NhbFRocmVzaG9sZFNxLCBhLCBiICk7XG5cblx0XHRcdFx0aWYgKCBpbnRlcnNlY3QgKSB7XG5cblx0XHRcdFx0XHRpbnRlcnNlY3RzLnB1c2goIGludGVyc2VjdCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggMCwgZHJhd1JhbmdlLnN0YXJ0ICk7XG5cdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggcG9zaXRpb25BdHRyaWJ1dGUuY291bnQsICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSBzdGFydCwgbCA9IGVuZCAtIDE7IGkgPCBsOyBpICs9IHN0ZXAgKSB7XG5cblx0XHRcdFx0Y29uc3QgaW50ZXJzZWN0ID0gY2hlY2tJbnRlcnNlY3Rpb24oIHRoaXMsIHJheWNhc3RlciwgX3JheSQxLCBsb2NhbFRocmVzaG9sZFNxLCBpLCBpICsgMSApO1xuXG5cdFx0XHRcdGlmICggaW50ZXJzZWN0ICkge1xuXG5cdFx0XHRcdFx0aW50ZXJzZWN0cy5wdXNoKCBpbnRlcnNlY3QgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0aGlzLmlzTGluZUxvb3AgKSB7XG5cblx0XHRcdFx0Y29uc3QgaW50ZXJzZWN0ID0gY2hlY2tJbnRlcnNlY3Rpb24oIHRoaXMsIHJheWNhc3RlciwgX3JheSQxLCBsb2NhbFRocmVzaG9sZFNxLCBlbmQgLSAxLCBzdGFydCApO1xuXG5cdFx0XHRcdGlmICggaW50ZXJzZWN0ICkge1xuXG5cdFx0XHRcdFx0aW50ZXJzZWN0cy5wdXNoKCBpbnRlcnNlY3QgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0dXBkYXRlTW9ycGhUYXJnZXRzKCkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzO1xuXHRcdGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyggbW9ycGhBdHRyaWJ1dGVzICk7XG5cblx0XHRpZiAoIGtleXMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNbIGtleXNbIDAgXSBdO1xuXG5cdFx0XHRpZiAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldEluZmx1ZW5jZXMgPSBbXTtcblx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldERpY3Rpb25hcnkgPSB7fTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgbSA9IDAsIG1sID0gbW9ycGhBdHRyaWJ1dGUubGVuZ3RoOyBtIDwgbWw7IG0gKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBuYW1lID0gbW9ycGhBdHRyaWJ1dGVbIG0gXS5uYW1lIHx8IFN0cmluZyggbSApO1xuXG5cdFx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldEluZmx1ZW5jZXMucHVzaCggMCApO1xuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5WyBuYW1lIF0gPSBtO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBjaGVja0ludGVyc2VjdGlvbiggb2JqZWN0LCByYXljYXN0ZXIsIHJheSwgdGhyZXNob2xkU3EsIGEsIGIgKSB7XG5cblx0Y29uc3QgcG9zaXRpb25BdHRyaWJ1dGUgPSBvYmplY3QuZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcblxuXHRfdlN0YXJ0LmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBhICk7XG5cdF92RW5kLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBiICk7XG5cblx0Y29uc3QgZGlzdFNxID0gcmF5LmRpc3RhbmNlU3FUb1NlZ21lbnQoIF92U3RhcnQsIF92RW5kLCBfaW50ZXJzZWN0UG9pbnRPblJheSwgX2ludGVyc2VjdFBvaW50T25TZWdtZW50ICk7XG5cblx0aWYgKCBkaXN0U3EgPiB0aHJlc2hvbGRTcSApIHJldHVybjtcblxuXHRfaW50ZXJzZWN0UG9pbnRPblJheS5hcHBseU1hdHJpeDQoIG9iamVjdC5tYXRyaXhXb3JsZCApOyAvLyBNb3ZlIGJhY2sgdG8gd29ybGQgc3BhY2UgZm9yIGRpc3RhbmNlIGNhbGN1bGF0aW9uXG5cblx0Y29uc3QgZGlzdGFuY2UgPSByYXljYXN0ZXIucmF5Lm9yaWdpbi5kaXN0YW5jZVRvKCBfaW50ZXJzZWN0UG9pbnRPblJheSApO1xuXG5cdGlmICggZGlzdGFuY2UgPCByYXljYXN0ZXIubmVhciB8fCBkaXN0YW5jZSA+IHJheWNhc3Rlci5mYXIgKSByZXR1cm47XG5cblx0cmV0dXJuIHtcblxuXHRcdGRpc3RhbmNlOiBkaXN0YW5jZSxcblx0XHQvLyBXaGF0IGRvIHdlIHdhbnQ/IGludGVyc2VjdGlvbiBwb2ludCBvbiB0aGUgcmF5IG9yIG9uIHRoZSBzZWdtZW50Pz9cblx0XHQvLyBwb2ludDogcmF5Y2FzdGVyLnJheS5hdCggZGlzdGFuY2UgKSxcblx0XHRwb2ludDogX2ludGVyc2VjdFBvaW50T25TZWdtZW50LmNsb25lKCkuYXBwbHlNYXRyaXg0KCBvYmplY3QubWF0cml4V29ybGQgKSxcblx0XHRpbmRleDogYSxcblx0XHRmYWNlOiBudWxsLFxuXHRcdGZhY2VJbmRleDogbnVsbCxcblx0XHRvYmplY3Q6IG9iamVjdFxuXG5cdH07XG5cbn1cblxuY29uc3QgX3N0YXJ0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX2VuZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgTGluZVNlZ21lbnRzIGV4dGVuZHMgTGluZSB7XG5cblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5LCBtYXRlcmlhbCApIHtcblxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblxuXHRcdHRoaXMuaXNMaW5lU2VnbWVudHMgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0xpbmVTZWdtZW50cyc7XG5cblx0fVxuXG5cdGNvbXB1dGVMaW5lRGlzdGFuY2VzKCkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXG5cdFx0Ly8gd2UgYXNzdW1lIG5vbi1pbmRleGVkIGdlb21ldHJ5XG5cblx0XHRpZiAoIGdlb21ldHJ5LmluZGV4ID09PSBudWxsICkge1xuXG5cdFx0XHRjb25zdCBwb3NpdGlvbkF0dHJpYnV0ZSA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb247XG5cdFx0XHRjb25zdCBsaW5lRGlzdGFuY2VzID0gW107XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHBvc2l0aW9uQXR0cmlidXRlLmNvdW50OyBpIDwgbDsgaSArPSAyICkge1xuXG5cdFx0XHRcdF9zdGFydC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgaSApO1xuXHRcdFx0XHRfZW5kLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0cmlidXRlLCBpICsgMSApO1xuXG5cdFx0XHRcdGxpbmVEaXN0YW5jZXNbIGkgXSA9ICggaSA9PT0gMCApID8gMCA6IGxpbmVEaXN0YW5jZXNbIGkgLSAxIF07XG5cdFx0XHRcdGxpbmVEaXN0YW5jZXNbIGkgKyAxIF0gPSBsaW5lRGlzdGFuY2VzWyBpIF0gKyBfc3RhcnQuZGlzdGFuY2VUbyggX2VuZCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2xpbmVEaXN0YW5jZScsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBsaW5lRGlzdGFuY2VzLCAxICkgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkxpbmVTZWdtZW50cy5jb21wdXRlTGluZURpc3RhbmNlcygpOiBDb21wdXRhdGlvbiBvbmx5IHBvc3NpYmxlIHdpdGggbm9uLWluZGV4ZWQgQnVmZmVyR2VvbWV0cnkuJyApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIExpbmVMb29wIGV4dGVuZHMgTGluZSB7XG5cblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5LCBtYXRlcmlhbCApIHtcblxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblxuXHRcdHRoaXMuaXNMaW5lTG9vcCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnTGluZUxvb3AnO1xuXG5cdH1cblxufVxuXG5jbGFzcyBQb2ludHNNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzUG9pbnRzTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ1BvaW50c01hdGVyaWFsJztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuc2l6ZSA9IDE7XG5cdFx0dGhpcy5zaXplQXR0ZW51YXRpb24gPSB0cnVlO1xuXG5cdFx0dGhpcy5mb2cgPSB0cnVlO1xuXG5cdFx0dGhpcy5zZXRWYWx1ZXMoIHBhcmFtZXRlcnMgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLmNvbG9yLmNvcHkoIHNvdXJjZS5jb2xvciApO1xuXG5cdFx0dGhpcy5tYXAgPSBzb3VyY2UubWFwO1xuXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcblxuXHRcdHRoaXMuc2l6ZSA9IHNvdXJjZS5zaXplO1xuXHRcdHRoaXMuc2l6ZUF0dGVudWF0aW9uID0gc291cmNlLnNpemVBdHRlbnVhdGlvbjtcblxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jb25zdCBfaW52ZXJzZU1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcbmNvbnN0IF9yYXkgPSAvKkBfX1BVUkVfXyovIG5ldyBSYXkoKTtcbmNvbnN0IF9zcGhlcmUgPSAvKkBfX1BVUkVfXyovIG5ldyBTcGhlcmUoKTtcbmNvbnN0IF9wb3NpdGlvbiQyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jbGFzcyBQb2ludHMgZXh0ZW5kcyBPYmplY3QzRCB7XG5cblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCksIG1hdGVyaWFsID0gbmV3IFBvaW50c01hdGVyaWFsKCkgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc1BvaW50cyA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnUG9pbnRzJztcblxuXHRcdHRoaXMuZ2VvbWV0cnkgPSBnZW9tZXRyeTtcblx0XHR0aGlzLm1hdGVyaWFsID0gbWF0ZXJpYWw7XG5cblx0XHR0aGlzLnVwZGF0ZU1vcnBoVGFyZ2V0cygpO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XG5cblx0XHR0aGlzLm1hdGVyaWFsID0gQXJyYXkuaXNBcnJheSggc291cmNlLm1hdGVyaWFsICkgPyBzb3VyY2UubWF0ZXJpYWwuc2xpY2UoKSA6IHNvdXJjZS5tYXRlcmlhbDtcblx0XHR0aGlzLmdlb21ldHJ5ID0gc291cmNlLmdlb21ldHJ5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcblx0XHRjb25zdCBtYXRyaXhXb3JsZCA9IHRoaXMubWF0cml4V29ybGQ7XG5cdFx0Y29uc3QgdGhyZXNob2xkID0gcmF5Y2FzdGVyLnBhcmFtcy5Qb2ludHMudGhyZXNob2xkO1xuXHRcdGNvbnN0IGRyYXdSYW5nZSA9IGdlb21ldHJ5LmRyYXdSYW5nZTtcblxuXHRcdC8vIENoZWNraW5nIGJvdW5kaW5nU3BoZXJlIGRpc3RhbmNlIHRvIHJheVxuXG5cdFx0aWYgKCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSA9PT0gbnVsbCApIGdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xuXG5cdFx0X3NwaGVyZS5jb3B5KCBnZW9tZXRyeS5ib3VuZGluZ1NwaGVyZSApO1xuXHRcdF9zcGhlcmUuYXBwbHlNYXRyaXg0KCBtYXRyaXhXb3JsZCApO1xuXHRcdF9zcGhlcmUucmFkaXVzICs9IHRocmVzaG9sZDtcblxuXHRcdGlmICggcmF5Y2FzdGVyLnJheS5pbnRlcnNlY3RzU3BoZXJlKCBfc3BoZXJlICkgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0Ly9cblxuXHRcdF9pbnZlcnNlTWF0cml4LmNvcHkoIG1hdHJpeFdvcmxkICkuaW52ZXJ0KCk7XG5cdFx0X3JheS5jb3B5KCByYXljYXN0ZXIucmF5ICkuYXBwbHlNYXRyaXg0KCBfaW52ZXJzZU1hdHJpeCApO1xuXG5cdFx0Y29uc3QgbG9jYWxUaHJlc2hvbGQgPSB0aHJlc2hvbGQgLyAoICggdGhpcy5zY2FsZS54ICsgdGhpcy5zY2FsZS55ICsgdGhpcy5zY2FsZS56ICkgLyAzICk7XG5cdFx0Y29uc3QgbG9jYWxUaHJlc2hvbGRTcSA9IGxvY2FsVGhyZXNob2xkICogbG9jYWxUaHJlc2hvbGQ7XG5cblx0XHRjb25zdCBpbmRleCA9IGdlb21ldHJ5LmluZGV4O1xuXHRcdGNvbnN0IGF0dHJpYnV0ZXMgPSBnZW9tZXRyeS5hdHRyaWJ1dGVzO1xuXHRcdGNvbnN0IHBvc2l0aW9uQXR0cmlidXRlID0gYXR0cmlidXRlcy5wb3NpdGlvbjtcblxuXHRcdGlmICggaW5kZXggIT09IG51bGwgKSB7XG5cblx0XHRcdGNvbnN0IHN0YXJ0ID0gTWF0aC5tYXgoIDAsIGRyYXdSYW5nZS5zdGFydCApO1xuXHRcdFx0Y29uc3QgZW5kID0gTWF0aC5taW4oIGluZGV4LmNvdW50LCAoIGRyYXdSYW5nZS5zdGFydCArIGRyYXdSYW5nZS5jb3VudCApICk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gc3RhcnQsIGlsID0gZW5kOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgYSA9IGluZGV4LmdldFgoIGkgKTtcblxuXHRcdFx0XHRfcG9zaXRpb24kMi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHJpYnV0ZSwgYSApO1xuXG5cdFx0XHRcdHRlc3RQb2ludCggX3Bvc2l0aW9uJDIsIGEsIGxvY2FsVGhyZXNob2xkU3EsIG1hdHJpeFdvcmxkLCByYXljYXN0ZXIsIGludGVyc2VjdHMsIHRoaXMgKTtcblxuXHRcdFx0fVxuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc3Qgc3RhcnQgPSBNYXRoLm1heCggMCwgZHJhd1JhbmdlLnN0YXJ0ICk7XG5cdFx0XHRjb25zdCBlbmQgPSBNYXRoLm1pbiggcG9zaXRpb25BdHRyaWJ1dGUuY291bnQsICggZHJhd1JhbmdlLnN0YXJ0ICsgZHJhd1JhbmdlLmNvdW50ICkgKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSBzdGFydCwgbCA9IGVuZDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0X3Bvc2l0aW9uJDIuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyaWJ1dGUsIGkgKTtcblxuXHRcdFx0XHR0ZXN0UG9pbnQoIF9wb3NpdGlvbiQyLCBpLCBsb2NhbFRocmVzaG9sZFNxLCBtYXRyaXhXb3JsZCwgcmF5Y2FzdGVyLCBpbnRlcnNlY3RzLCB0aGlzICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0dXBkYXRlTW9ycGhUYXJnZXRzKCkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXG5cdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGVzID0gZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzO1xuXHRcdGNvbnN0IGtleXMgPSBPYmplY3Qua2V5cyggbW9ycGhBdHRyaWJ1dGVzICk7XG5cblx0XHRpZiAoIGtleXMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0Y29uc3QgbW9ycGhBdHRyaWJ1dGUgPSBtb3JwaEF0dHJpYnV0ZXNbIGtleXNbIDAgXSBdO1xuXG5cdFx0XHRpZiAoIG1vcnBoQXR0cmlidXRlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldEluZmx1ZW5jZXMgPSBbXTtcblx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldERpY3Rpb25hcnkgPSB7fTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgbSA9IDAsIG1sID0gbW9ycGhBdHRyaWJ1dGUubGVuZ3RoOyBtIDwgbWw7IG0gKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBuYW1lID0gbW9ycGhBdHRyaWJ1dGVbIG0gXS5uYW1lIHx8IFN0cmluZyggbSApO1xuXG5cdFx0XHRcdFx0dGhpcy5tb3JwaFRhcmdldEluZmx1ZW5jZXMucHVzaCggMCApO1xuXHRcdFx0XHRcdHRoaXMubW9ycGhUYXJnZXREaWN0aW9uYXJ5WyBuYW1lIF0gPSBtO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5mdW5jdGlvbiB0ZXN0UG9pbnQoIHBvaW50LCBpbmRleCwgbG9jYWxUaHJlc2hvbGRTcSwgbWF0cml4V29ybGQsIHJheWNhc3RlciwgaW50ZXJzZWN0cywgb2JqZWN0ICkge1xuXG5cdGNvbnN0IHJheVBvaW50RGlzdGFuY2VTcSA9IF9yYXkuZGlzdGFuY2VTcVRvUG9pbnQoIHBvaW50ICk7XG5cblx0aWYgKCByYXlQb2ludERpc3RhbmNlU3EgPCBsb2NhbFRocmVzaG9sZFNxICkge1xuXG5cdFx0Y29uc3QgaW50ZXJzZWN0UG9pbnQgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0X3JheS5jbG9zZXN0UG9pbnRUb1BvaW50KCBwb2ludCwgaW50ZXJzZWN0UG9pbnQgKTtcblx0XHRpbnRlcnNlY3RQb2ludC5hcHBseU1hdHJpeDQoIG1hdHJpeFdvcmxkICk7XG5cblx0XHRjb25zdCBkaXN0YW5jZSA9IHJheWNhc3Rlci5yYXkub3JpZ2luLmRpc3RhbmNlVG8oIGludGVyc2VjdFBvaW50ICk7XG5cblx0XHRpZiAoIGRpc3RhbmNlIDwgcmF5Y2FzdGVyLm5lYXIgfHwgZGlzdGFuY2UgPiByYXljYXN0ZXIuZmFyICkgcmV0dXJuO1xuXG5cdFx0aW50ZXJzZWN0cy5wdXNoKCB7XG5cblx0XHRcdGRpc3RhbmNlOiBkaXN0YW5jZSxcblx0XHRcdGRpc3RhbmNlVG9SYXk6IE1hdGguc3FydCggcmF5UG9pbnREaXN0YW5jZVNxICksXG5cdFx0XHRwb2ludDogaW50ZXJzZWN0UG9pbnQsXG5cdFx0XHRpbmRleDogaW5kZXgsXG5cdFx0XHRmYWNlOiBudWxsLFxuXHRcdFx0b2JqZWN0OiBvYmplY3RcblxuXHRcdH0gKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgVmlkZW9UZXh0dXJlIGV4dGVuZHMgVGV4dHVyZSB7XG5cblx0Y29uc3RydWN0b3IoIHZpZGVvLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHkgKSB7XG5cblx0XHRzdXBlciggdmlkZW8sIG1hcHBpbmcsIHdyYXBTLCB3cmFwVCwgbWFnRmlsdGVyLCBtaW5GaWx0ZXIsIGZvcm1hdCwgdHlwZSwgYW5pc290cm9weSApO1xuXG5cdFx0dGhpcy5pc1ZpZGVvVGV4dHVyZSA9IHRydWU7XG5cblx0XHR0aGlzLm1pbkZpbHRlciA9IG1pbkZpbHRlciAhPT0gdW5kZWZpbmVkID8gbWluRmlsdGVyIDogTGluZWFyRmlsdGVyO1xuXHRcdHRoaXMubWFnRmlsdGVyID0gbWFnRmlsdGVyICE9PSB1bmRlZmluZWQgPyBtYWdGaWx0ZXIgOiBMaW5lYXJGaWx0ZXI7XG5cblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0ZnVuY3Rpb24gdXBkYXRlVmlkZW8oKSB7XG5cblx0XHRcdHNjb3BlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblx0XHRcdHZpZGVvLnJlcXVlc3RWaWRlb0ZyYW1lQ2FsbGJhY2soIHVwZGF0ZVZpZGVvICk7XG5cblx0XHR9XG5cblx0XHRpZiAoICdyZXF1ZXN0VmlkZW9GcmFtZUNhbGxiYWNrJyBpbiB2aWRlbyApIHtcblxuXHRcdFx0dmlkZW8ucmVxdWVzdFZpZGVvRnJhbWVDYWxsYmFjayggdXBkYXRlVmlkZW8gKTtcblxuXHRcdH1cblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMuaW1hZ2UgKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG5cdHVwZGF0ZSgpIHtcblxuXHRcdGNvbnN0IHZpZGVvID0gdGhpcy5pbWFnZTtcblx0XHRjb25zdCBoYXNWaWRlb0ZyYW1lQ2FsbGJhY2sgPSAncmVxdWVzdFZpZGVvRnJhbWVDYWxsYmFjaycgaW4gdmlkZW87XG5cblx0XHRpZiAoIGhhc1ZpZGVvRnJhbWVDYWxsYmFjayA9PT0gZmFsc2UgJiYgdmlkZW8ucmVhZHlTdGF0ZSA+PSB2aWRlby5IQVZFX0NVUlJFTlRfREFUQSApIHtcblxuXHRcdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbmNsYXNzIEZyYW1lYnVmZmVyVGV4dHVyZSBleHRlbmRzIFRleHR1cmUge1xuXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCwgaGVpZ2h0ICkge1xuXG5cdFx0c3VwZXIoIHsgd2lkdGgsIGhlaWdodCB9ICk7XG5cblx0XHR0aGlzLmlzRnJhbWVidWZmZXJUZXh0dXJlID0gdHJ1ZTtcblxuXHRcdHRoaXMubWFnRmlsdGVyID0gTmVhcmVzdEZpbHRlcjtcblx0XHR0aGlzLm1pbkZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XG5cblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXG5cdFx0dGhpcy5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0fVxuXG59XG5cbmNsYXNzIENvbXByZXNzZWRUZXh0dXJlIGV4dGVuZHMgVGV4dHVyZSB7XG5cblx0Y29uc3RydWN0b3IoIG1pcG1hcHMsIHdpZHRoLCBoZWlnaHQsIGZvcm1hdCwgdHlwZSwgbWFwcGluZywgd3JhcFMsIHdyYXBULCBtYWdGaWx0ZXIsIG1pbkZpbHRlciwgYW5pc290cm9weSwgY29sb3JTcGFjZSApIHtcblxuXHRcdHN1cGVyKCBudWxsLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHksIGNvbG9yU3BhY2UgKTtcblxuXHRcdHRoaXMuaXNDb21wcmVzc2VkVGV4dHVyZSA9IHRydWU7XG5cblx0XHR0aGlzLmltYWdlID0geyB3aWR0aDogd2lkdGgsIGhlaWdodDogaGVpZ2h0IH07XG5cdFx0dGhpcy5taXBtYXBzID0gbWlwbWFwcztcblxuXHRcdC8vIG5vIGZsaXBwaW5nIGZvciBjdWJlIHRleHR1cmVzXG5cdFx0Ly8gKGFsc28gZmxpcHBpbmcgZG9lc24ndCB3b3JrIGZvciBjb21wcmVzc2VkIHRleHR1cmVzIClcblxuXHRcdHRoaXMuZmxpcFkgPSBmYWxzZTtcblxuXHRcdC8vIGNhbid0IGdlbmVyYXRlIG1pcG1hcHMgZm9yIGNvbXByZXNzZWQgdGV4dHVyZXNcblx0XHQvLyBtaXBzIG11c3QgYmUgZW1iZWRkZWQgaW4gRERTIGZpbGVzXG5cblx0XHR0aGlzLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBDb21wcmVzc2VkQXJyYXlUZXh0dXJlIGV4dGVuZHMgQ29tcHJlc3NlZFRleHR1cmUge1xuXG5cdGNvbnN0cnVjdG9yKCBtaXBtYXBzLCB3aWR0aCwgaGVpZ2h0LCBkZXB0aCwgZm9ybWF0LCB0eXBlICkge1xuXG5cdFx0c3VwZXIoIG1pcG1hcHMsIHdpZHRoLCBoZWlnaHQsIGZvcm1hdCwgdHlwZSApO1xuXG5cdFx0dGhpcy5pc0NvbXByZXNzZWRBcnJheVRleHR1cmUgPSB0cnVlO1xuXHRcdHRoaXMuaW1hZ2UuZGVwdGggPSBkZXB0aDtcblx0XHR0aGlzLndyYXBSID0gQ2xhbXBUb0VkZ2VXcmFwcGluZztcblxuXHRcdHRoaXMubGF5ZXJVcGRhdGVzID0gbmV3IFNldCgpO1xuXG5cdH1cblxuXHRhZGRMYXllclVwZGF0ZSggbGF5ZXJJbmRleCApIHtcblxuXHRcdHRoaXMubGF5ZXJVcGRhdGVzLmFkZCggbGF5ZXJJbmRleCApO1xuXG5cdH1cblxuXHRjbGVhckxheWVyVXBkYXRlcygpIHtcblxuXHRcdHRoaXMubGF5ZXJVcGRhdGVzLmNsZWFyKCk7XG5cblx0fVxuXG59XG5cbmNsYXNzIENvbXByZXNzZWRDdWJlVGV4dHVyZSBleHRlbmRzIENvbXByZXNzZWRUZXh0dXJlIHtcblxuXHRjb25zdHJ1Y3RvciggaW1hZ2VzLCBmb3JtYXQsIHR5cGUgKSB7XG5cblx0XHRzdXBlciggdW5kZWZpbmVkLCBpbWFnZXNbIDAgXS53aWR0aCwgaW1hZ2VzWyAwIF0uaGVpZ2h0LCBmb3JtYXQsIHR5cGUsIEN1YmVSZWZsZWN0aW9uTWFwcGluZyApO1xuXG5cdFx0dGhpcy5pc0NvbXByZXNzZWRDdWJlVGV4dHVyZSA9IHRydWU7XG5cdFx0dGhpcy5pc0N1YmVUZXh0dXJlID0gdHJ1ZTtcblxuXHRcdHRoaXMuaW1hZ2UgPSBpbWFnZXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIENhbnZhc1RleHR1cmUgZXh0ZW5kcyBUZXh0dXJlIHtcblxuXHRjb25zdHJ1Y3RvciggY2FudmFzLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHkgKSB7XG5cblx0XHRzdXBlciggY2FudmFzLCBtYXBwaW5nLCB3cmFwUywgd3JhcFQsIG1hZ0ZpbHRlciwgbWluRmlsdGVyLCBmb3JtYXQsIHR5cGUsIGFuaXNvdHJvcHkgKTtcblxuXHRcdHRoaXMuaXNDYW52YXNUZXh0dXJlID0gdHJ1ZTtcblxuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxufVxuXG4vKipcbiAqIEV4dGVuc2libGUgY3VydmUgb2JqZWN0LlxuICpcbiAqIFNvbWUgY29tbW9uIG9mIGN1cnZlIG1ldGhvZHM6XG4gKiAuZ2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ICksIC5nZXRUYW5nZW50KCB0LCBvcHRpb25hbFRhcmdldCApXG4gKiAuZ2V0UG9pbnRBdCggdSwgb3B0aW9uYWxUYXJnZXQgKSwgLmdldFRhbmdlbnRBdCggdSwgb3B0aW9uYWxUYXJnZXQgKVxuICogLmdldFBvaW50cygpLCAuZ2V0U3BhY2VkUG9pbnRzKClcbiAqIC5nZXRMZW5ndGgoKVxuICogLnVwZGF0ZUFyY0xlbmd0aHMoKVxuICpcbiAqIFRoaXMgZm9sbG93aW5nIGN1cnZlcyBpbmhlcml0IGZyb20gVEhSRUUuQ3VydmU6XG4gKlxuICogLS0gMkQgY3VydmVzIC0tXG4gKiBUSFJFRS5BcmNDdXJ2ZVxuICogVEhSRUUuQ3ViaWNCZXppZXJDdXJ2ZVxuICogVEhSRUUuRWxsaXBzZUN1cnZlXG4gKiBUSFJFRS5MaW5lQ3VydmVcbiAqIFRIUkVFLlF1YWRyYXRpY0JlemllckN1cnZlXG4gKiBUSFJFRS5TcGxpbmVDdXJ2ZVxuICpcbiAqIC0tIDNEIGN1cnZlcyAtLVxuICogVEhSRUUuQ2F0bXVsbFJvbUN1cnZlM1xuICogVEhSRUUuQ3ViaWNCZXppZXJDdXJ2ZTNcbiAqIFRIUkVFLkxpbmVDdXJ2ZTNcbiAqIFRIUkVFLlF1YWRyYXRpY0JlemllckN1cnZlM1xuICpcbiAqIEEgc2VyaWVzIG9mIGN1cnZlcyBjYW4gYmUgcmVwcmVzZW50ZWQgYXMgYSBUSFJFRS5DdXJ2ZVBhdGguXG4gKlxuICoqL1xuXG5jbGFzcyBDdXJ2ZSB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHR0aGlzLnR5cGUgPSAnQ3VydmUnO1xuXG5cdFx0dGhpcy5hcmNMZW5ndGhEaXZpc2lvbnMgPSAyMDA7XG5cblx0fVxuXG5cdC8vIFZpcnR1YWwgYmFzZSBjbGFzcyBtZXRob2QgdG8gb3ZlcndyaXRlIGFuZCBpbXBsZW1lbnQgaW4gc3ViY2xhc3Nlc1xuXHQvL1x0LSB0IFswIC4uIDFdXG5cblx0Z2V0UG9pbnQoIC8qIHQsIG9wdGlvbmFsVGFyZ2V0ICovICkge1xuXG5cdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQ3VydmU6IC5nZXRQb2ludCgpIG5vdCBpbXBsZW1lbnRlZC4nICk7XG5cdFx0cmV0dXJuIG51bGw7XG5cblx0fVxuXG5cdC8vIEdldCBwb2ludCBhdCByZWxhdGl2ZSBwb3NpdGlvbiBpbiBjdXJ2ZSBhY2NvcmRpbmcgdG8gYXJjIGxlbmd0aFxuXHQvLyAtIHUgWzAgLi4gMV1cblxuXHRnZXRQb2ludEF0KCB1LCBvcHRpb25hbFRhcmdldCApIHtcblxuXHRcdGNvbnN0IHQgPSB0aGlzLmdldFV0b1RtYXBwaW5nKCB1ICk7XG5cdFx0cmV0dXJuIHRoaXMuZ2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ICk7XG5cblx0fVxuXG5cdC8vIEdldCBzZXF1ZW5jZSBvZiBwb2ludHMgdXNpbmcgZ2V0UG9pbnQoIHQgKVxuXG5cdGdldFBvaW50cyggZGl2aXNpb25zID0gNSApIHtcblxuXHRcdGNvbnN0IHBvaW50cyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGQgPSAwOyBkIDw9IGRpdmlzaW9uczsgZCArKyApIHtcblxuXHRcdFx0cG9pbnRzLnB1c2goIHRoaXMuZ2V0UG9pbnQoIGQgLyBkaXZpc2lvbnMgKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHBvaW50cztcblxuXHR9XG5cblx0Ly8gR2V0IHNlcXVlbmNlIG9mIHBvaW50cyB1c2luZyBnZXRQb2ludEF0KCB1IClcblxuXHRnZXRTcGFjZWRQb2ludHMoIGRpdmlzaW9ucyA9IDUgKSB7XG5cblx0XHRjb25zdCBwb2ludHMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBkID0gMDsgZCA8PSBkaXZpc2lvbnM7IGQgKysgKSB7XG5cblx0XHRcdHBvaW50cy5wdXNoKCB0aGlzLmdldFBvaW50QXQoIGQgLyBkaXZpc2lvbnMgKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHBvaW50cztcblxuXHR9XG5cblx0Ly8gR2V0IHRvdGFsIGN1cnZlIGFyYyBsZW5ndGhcblxuXHRnZXRMZW5ndGgoKSB7XG5cblx0XHRjb25zdCBsZW5ndGhzID0gdGhpcy5nZXRMZW5ndGhzKCk7XG5cdFx0cmV0dXJuIGxlbmd0aHNbIGxlbmd0aHMubGVuZ3RoIC0gMSBdO1xuXG5cdH1cblxuXHQvLyBHZXQgbGlzdCBvZiBjdW11bGF0aXZlIHNlZ21lbnQgbGVuZ3Roc1xuXG5cdGdldExlbmd0aHMoIGRpdmlzaW9ucyA9IHRoaXMuYXJjTGVuZ3RoRGl2aXNpb25zICkge1xuXG5cdFx0aWYgKCB0aGlzLmNhY2hlQXJjTGVuZ3RocyAmJlxuXHRcdFx0KCB0aGlzLmNhY2hlQXJjTGVuZ3Rocy5sZW5ndGggPT09IGRpdmlzaW9ucyArIDEgKSAmJlxuXHRcdFx0ISB0aGlzLm5lZWRzVXBkYXRlICkge1xuXG5cdFx0XHRyZXR1cm4gdGhpcy5jYWNoZUFyY0xlbmd0aHM7XG5cblx0XHR9XG5cblx0XHR0aGlzLm5lZWRzVXBkYXRlID0gZmFsc2U7XG5cblx0XHRjb25zdCBjYWNoZSA9IFtdO1xuXHRcdGxldCBjdXJyZW50LCBsYXN0ID0gdGhpcy5nZXRQb2ludCggMCApO1xuXHRcdGxldCBzdW0gPSAwO1xuXG5cdFx0Y2FjaGUucHVzaCggMCApO1xuXG5cdFx0Zm9yICggbGV0IHAgPSAxOyBwIDw9IGRpdmlzaW9uczsgcCArKyApIHtcblxuXHRcdFx0Y3VycmVudCA9IHRoaXMuZ2V0UG9pbnQoIHAgLyBkaXZpc2lvbnMgKTtcblx0XHRcdHN1bSArPSBjdXJyZW50LmRpc3RhbmNlVG8oIGxhc3QgKTtcblx0XHRcdGNhY2hlLnB1c2goIHN1bSApO1xuXHRcdFx0bGFzdCA9IGN1cnJlbnQ7XG5cblx0XHR9XG5cblx0XHR0aGlzLmNhY2hlQXJjTGVuZ3RocyA9IGNhY2hlO1xuXG5cdFx0cmV0dXJuIGNhY2hlOyAvLyB7IHN1bXM6IGNhY2hlLCBzdW06IHN1bSB9OyBTdW0gaXMgaW4gdGhlIGxhc3QgZWxlbWVudC5cblxuXHR9XG5cblx0dXBkYXRlQXJjTGVuZ3RocygpIHtcblxuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSB0cnVlO1xuXHRcdHRoaXMuZ2V0TGVuZ3RocygpO1xuXG5cdH1cblxuXHQvLyBHaXZlbiB1ICggMCAuLiAxICksIGdldCBhIHQgdG8gZmluZCBwLiBUaGlzIGdpdmVzIHlvdSBwb2ludHMgd2hpY2ggYXJlIGVxdWlkaXN0YW50XG5cblx0Z2V0VXRvVG1hcHBpbmcoIHUsIGRpc3RhbmNlICkge1xuXG5cdFx0Y29uc3QgYXJjTGVuZ3RocyA9IHRoaXMuZ2V0TGVuZ3RocygpO1xuXG5cdFx0bGV0IGkgPSAwO1xuXHRcdGNvbnN0IGlsID0gYXJjTGVuZ3Rocy5sZW5ndGg7XG5cblx0XHRsZXQgdGFyZ2V0QXJjTGVuZ3RoOyAvLyBUaGUgdGFyZ2V0ZWQgdSBkaXN0YW5jZSB2YWx1ZSB0byBnZXRcblxuXHRcdGlmICggZGlzdGFuY2UgKSB7XG5cblx0XHRcdHRhcmdldEFyY0xlbmd0aCA9IGRpc3RhbmNlO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGFyZ2V0QXJjTGVuZ3RoID0gdSAqIGFyY0xlbmd0aHNbIGlsIC0gMSBdO1xuXG5cdFx0fVxuXG5cdFx0Ly8gYmluYXJ5IHNlYXJjaCBmb3IgdGhlIGluZGV4IHdpdGggbGFyZ2VzdCB2YWx1ZSBzbWFsbGVyIHRoYW4gdGFyZ2V0IHUgZGlzdGFuY2VcblxuXHRcdGxldCBsb3cgPSAwLCBoaWdoID0gaWwgLSAxLCBjb21wYXJpc29uO1xuXG5cdFx0d2hpbGUgKCBsb3cgPD0gaGlnaCApIHtcblxuXHRcdFx0aSA9IE1hdGguZmxvb3IoIGxvdyArICggaGlnaCAtIGxvdyApIC8gMiApOyAvLyBsZXNzIGxpa2VseSB0byBvdmVyZmxvdywgdGhvdWdoIHByb2JhYmx5IG5vdCBpc3N1ZSBoZXJlLCBKUyBkb2Vzbid0IHJlYWxseSBoYXZlIGludGVnZXJzLCBhbGwgbnVtYmVycyBhcmUgZmxvYXRzXG5cblx0XHRcdGNvbXBhcmlzb24gPSBhcmNMZW5ndGhzWyBpIF0gLSB0YXJnZXRBcmNMZW5ndGg7XG5cblx0XHRcdGlmICggY29tcGFyaXNvbiA8IDAgKSB7XG5cblx0XHRcdFx0bG93ID0gaSArIDE7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGNvbXBhcmlzb24gPiAwICkge1xuXG5cdFx0XHRcdGhpZ2ggPSBpIC0gMTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRoaWdoID0gaTtcblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Ly8gRE9ORVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpID0gaGlnaDtcblxuXHRcdGlmICggYXJjTGVuZ3Roc1sgaSBdID09PSB0YXJnZXRBcmNMZW5ndGggKSB7XG5cblx0XHRcdHJldHVybiBpIC8gKCBpbCAtIDEgKTtcblxuXHRcdH1cblxuXHRcdC8vIHdlIGNvdWxkIGdldCBmaW5lciBncmFpbiBhdCBsZW5ndGhzLCBvciB1c2Ugc2ltcGxlIGludGVycG9sYXRpb24gYmV0d2VlbiB0d28gcG9pbnRzXG5cblx0XHRjb25zdCBsZW5ndGhCZWZvcmUgPSBhcmNMZW5ndGhzWyBpIF07XG5cdFx0Y29uc3QgbGVuZ3RoQWZ0ZXIgPSBhcmNMZW5ndGhzWyBpICsgMSBdO1xuXG5cdFx0Y29uc3Qgc2VnbWVudExlbmd0aCA9IGxlbmd0aEFmdGVyIC0gbGVuZ3RoQmVmb3JlO1xuXG5cdFx0Ly8gZGV0ZXJtaW5lIHdoZXJlIHdlIGFyZSBiZXR3ZWVuIHRoZSAnYmVmb3JlJyBhbmQgJ2FmdGVyJyBwb2ludHNcblxuXHRcdGNvbnN0IHNlZ21lbnRGcmFjdGlvbiA9ICggdGFyZ2V0QXJjTGVuZ3RoIC0gbGVuZ3RoQmVmb3JlICkgLyBzZWdtZW50TGVuZ3RoO1xuXG5cdFx0Ly8gYWRkIHRoYXQgZnJhY3Rpb25hbCBhbW91bnQgdG8gdFxuXG5cdFx0Y29uc3QgdCA9ICggaSArIHNlZ21lbnRGcmFjdGlvbiApIC8gKCBpbCAtIDEgKTtcblxuXHRcdHJldHVybiB0O1xuXG5cdH1cblxuXHQvLyBSZXR1cm5zIGEgdW5pdCB2ZWN0b3IgdGFuZ2VudCBhdCB0XG5cdC8vIEluIGNhc2UgYW55IHN1YiBjdXJ2ZSBkb2VzIG5vdCBpbXBsZW1lbnQgaXRzIHRhbmdlbnQgZGVyaXZhdGlvbixcblx0Ly8gMiBwb2ludHMgYSBzbWFsbCBkZWx0YSBhcGFydCB3aWxsIGJlIHVzZWQgdG8gZmluZCBpdHMgZ3JhZGllbnRcblx0Ly8gd2hpY2ggc2VlbXMgdG8gZ2l2ZSBhIHJlYXNvbmFibGUgYXBwcm94aW1hdGlvblxuXG5cdGdldFRhbmdlbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ICkge1xuXG5cdFx0Y29uc3QgZGVsdGEgPSAwLjAwMDE7XG5cdFx0bGV0IHQxID0gdCAtIGRlbHRhO1xuXHRcdGxldCB0MiA9IHQgKyBkZWx0YTtcblxuXHRcdC8vIENhcHBpbmcgaW4gY2FzZSBvZiBkYW5nZXJcblxuXHRcdGlmICggdDEgPCAwICkgdDEgPSAwO1xuXHRcdGlmICggdDIgPiAxICkgdDIgPSAxO1xuXG5cdFx0Y29uc3QgcHQxID0gdGhpcy5nZXRQb2ludCggdDEgKTtcblx0XHRjb25zdCBwdDIgPSB0aGlzLmdldFBvaW50KCB0MiApO1xuXG5cdFx0Y29uc3QgdGFuZ2VudCA9IG9wdGlvbmFsVGFyZ2V0IHx8ICggKCBwdDEuaXNWZWN0b3IyICkgPyBuZXcgVmVjdG9yMigpIDogbmV3IFZlY3RvcjMoKSApO1xuXG5cdFx0dGFuZ2VudC5jb3B5KCBwdDIgKS5zdWIoIHB0MSApLm5vcm1hbGl6ZSgpO1xuXG5cdFx0cmV0dXJuIHRhbmdlbnQ7XG5cblx0fVxuXG5cdGdldFRhbmdlbnRBdCggdSwgb3B0aW9uYWxUYXJnZXQgKSB7XG5cblx0XHRjb25zdCB0ID0gdGhpcy5nZXRVdG9UbWFwcGluZyggdSApO1xuXHRcdHJldHVybiB0aGlzLmdldFRhbmdlbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ICk7XG5cblx0fVxuXG5cdGNvbXB1dGVGcmVuZXRGcmFtZXMoIHNlZ21lbnRzLCBjbG9zZWQgKSB7XG5cblx0XHQvLyBzZWUgaHR0cDovL3d3dy5jcy5pbmRpYW5hLmVkdS9wdWIvdGVjaHJlcG9ydHMvVFI0MjUucGRmXG5cblx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0Y29uc3QgdGFuZ2VudHMgPSBbXTtcblx0XHRjb25zdCBub3JtYWxzID0gW107XG5cdFx0Y29uc3QgYmlub3JtYWxzID0gW107XG5cblx0XHRjb25zdCB2ZWMgPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IG1hdCA9IG5ldyBNYXRyaXg0KCk7XG5cblx0XHQvLyBjb21wdXRlIHRoZSB0YW5nZW50IHZlY3RvcnMgZm9yIGVhY2ggc2VnbWVudCBvbiB0aGUgY3VydmVcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSBzZWdtZW50czsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgdSA9IGkgLyBzZWdtZW50cztcblxuXHRcdFx0dGFuZ2VudHNbIGkgXSA9IHRoaXMuZ2V0VGFuZ2VudEF0KCB1LCBuZXcgVmVjdG9yMygpICk7XG5cblx0XHR9XG5cblx0XHQvLyBzZWxlY3QgYW4gaW5pdGlhbCBub3JtYWwgdmVjdG9yIHBlcnBlbmRpY3VsYXIgdG8gdGhlIGZpcnN0IHRhbmdlbnQgdmVjdG9yLFxuXHRcdC8vIGFuZCBpbiB0aGUgZGlyZWN0aW9uIG9mIHRoZSBtaW5pbXVtIHRhbmdlbnQgeHl6IGNvbXBvbmVudFxuXG5cdFx0bm9ybWFsc1sgMCBdID0gbmV3IFZlY3RvcjMoKTtcblx0XHRiaW5vcm1hbHNbIDAgXSA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0bGV0IG1pbiA9IE51bWJlci5NQVhfVkFMVUU7XG5cdFx0Y29uc3QgdHggPSBNYXRoLmFicyggdGFuZ2VudHNbIDAgXS54ICk7XG5cdFx0Y29uc3QgdHkgPSBNYXRoLmFicyggdGFuZ2VudHNbIDAgXS55ICk7XG5cdFx0Y29uc3QgdHogPSBNYXRoLmFicyggdGFuZ2VudHNbIDAgXS56ICk7XG5cblx0XHRpZiAoIHR4IDw9IG1pbiApIHtcblxuXHRcdFx0bWluID0gdHg7XG5cdFx0XHRub3JtYWwuc2V0KCAxLCAwLCAwICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHR5IDw9IG1pbiApIHtcblxuXHRcdFx0bWluID0gdHk7XG5cdFx0XHRub3JtYWwuc2V0KCAwLCAxLCAwICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHR6IDw9IG1pbiApIHtcblxuXHRcdFx0bm9ybWFsLnNldCggMCwgMCwgMSApO1xuXG5cdFx0fVxuXG5cdFx0dmVjLmNyb3NzVmVjdG9ycyggdGFuZ2VudHNbIDAgXSwgbm9ybWFsICkubm9ybWFsaXplKCk7XG5cblx0XHRub3JtYWxzWyAwIF0uY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgMCBdLCB2ZWMgKTtcblx0XHRiaW5vcm1hbHNbIDAgXS5jcm9zc1ZlY3RvcnMoIHRhbmdlbnRzWyAwIF0sIG5vcm1hbHNbIDAgXSApO1xuXG5cblx0XHQvLyBjb21wdXRlIHRoZSBzbG93bHktdmFyeWluZyBub3JtYWwgYW5kIGJpbm9ybWFsIHZlY3RvcnMgZm9yIGVhY2ggc2VnbWVudCBvbiB0aGUgY3VydmVcblxuXHRcdGZvciAoIGxldCBpID0gMTsgaSA8PSBzZWdtZW50czsgaSArKyApIHtcblxuXHRcdFx0bm9ybWFsc1sgaSBdID0gbm9ybWFsc1sgaSAtIDEgXS5jbG9uZSgpO1xuXG5cdFx0XHRiaW5vcm1hbHNbIGkgXSA9IGJpbm9ybWFsc1sgaSAtIDEgXS5jbG9uZSgpO1xuXG5cdFx0XHR2ZWMuY3Jvc3NWZWN0b3JzKCB0YW5nZW50c1sgaSAtIDEgXSwgdGFuZ2VudHNbIGkgXSApO1xuXG5cdFx0XHRpZiAoIHZlYy5sZW5ndGgoKSA+IE51bWJlci5FUFNJTE9OICkge1xuXG5cdFx0XHRcdHZlYy5ub3JtYWxpemUoKTtcblxuXHRcdFx0XHRjb25zdCB0aGV0YSA9IE1hdGguYWNvcyggY2xhbXAoIHRhbmdlbnRzWyBpIC0gMSBdLmRvdCggdGFuZ2VudHNbIGkgXSApLCAtIDEsIDEgKSApOyAvLyBjbGFtcCBmb3IgZmxvYXRpbmcgcHQgZXJyb3JzXG5cblx0XHRcdFx0bm9ybWFsc1sgaSBdLmFwcGx5TWF0cml4NCggbWF0Lm1ha2VSb3RhdGlvbkF4aXMoIHZlYywgdGhldGEgKSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGJpbm9ybWFsc1sgaSBdLmNyb3NzVmVjdG9ycyggdGFuZ2VudHNbIGkgXSwgbm9ybWFsc1sgaSBdICk7XG5cblx0XHR9XG5cblx0XHQvLyBpZiB0aGUgY3VydmUgaXMgY2xvc2VkLCBwb3N0cHJvY2VzcyB0aGUgdmVjdG9ycyBzbyB0aGUgZmlyc3QgYW5kIGxhc3Qgbm9ybWFsIHZlY3RvcnMgYXJlIHRoZSBzYW1lXG5cblx0XHRpZiAoIGNsb3NlZCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0bGV0IHRoZXRhID0gTWF0aC5hY29zKCBjbGFtcCggbm9ybWFsc1sgMCBdLmRvdCggbm9ybWFsc1sgc2VnbWVudHMgXSApLCAtIDEsIDEgKSApO1xuXHRcdFx0dGhldGEgLz0gc2VnbWVudHM7XG5cblx0XHRcdGlmICggdGFuZ2VudHNbIDAgXS5kb3QoIHZlYy5jcm9zc1ZlY3RvcnMoIG5vcm1hbHNbIDAgXSwgbm9ybWFsc1sgc2VnbWVudHMgXSApICkgPiAwICkge1xuXG5cdFx0XHRcdHRoZXRhID0gLSB0aGV0YTtcblxuXHRcdFx0fVxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDE7IGkgPD0gc2VnbWVudHM7IGkgKysgKSB7XG5cblx0XHRcdFx0Ly8gdHdpc3QgYSBsaXR0bGUuLi5cblx0XHRcdFx0bm9ybWFsc1sgaSBdLmFwcGx5TWF0cml4NCggbWF0Lm1ha2VSb3RhdGlvbkF4aXMoIHRhbmdlbnRzWyBpIF0sIHRoZXRhICogaSApICk7XG5cdFx0XHRcdGJpbm9ybWFsc1sgaSBdLmNyb3NzVmVjdG9ycyggdGFuZ2VudHNbIGkgXSwgbm9ybWFsc1sgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB7XG5cdFx0XHR0YW5nZW50czogdGFuZ2VudHMsXG5cdFx0XHRub3JtYWxzOiBub3JtYWxzLFxuXHRcdFx0Ymlub3JtYWxzOiBiaW5vcm1hbHNcblx0XHR9O1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0dGhpcy5hcmNMZW5ndGhEaXZpc2lvbnMgPSBzb3VyY2UuYXJjTGVuZ3RoRGl2aXNpb25zO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSB7XG5cdFx0XHRtZXRhZGF0YToge1xuXHRcdFx0XHR2ZXJzaW9uOiA0LjYsXG5cdFx0XHRcdHR5cGU6ICdDdXJ2ZScsXG5cdFx0XHRcdGdlbmVyYXRvcjogJ0N1cnZlLnRvSlNPTidcblx0XHRcdH1cblx0XHR9O1xuXG5cdFx0ZGF0YS5hcmNMZW5ndGhEaXZpc2lvbnMgPSB0aGlzLmFyY0xlbmd0aERpdmlzaW9ucztcblx0XHRkYXRhLnR5cGUgPSB0aGlzLnR5cGU7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cblx0ZnJvbUpTT04oIGpzb24gKSB7XG5cblx0XHR0aGlzLmFyY0xlbmd0aERpdmlzaW9ucyA9IGpzb24uYXJjTGVuZ3RoRGl2aXNpb25zO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIEVsbGlwc2VDdXJ2ZSBleHRlbmRzIEN1cnZlIHtcblxuXHRjb25zdHJ1Y3RvciggYVggPSAwLCBhWSA9IDAsIHhSYWRpdXMgPSAxLCB5UmFkaXVzID0gMSwgYVN0YXJ0QW5nbGUgPSAwLCBhRW5kQW5nbGUgPSBNYXRoLlBJICogMiwgYUNsb2Nrd2lzZSA9IGZhbHNlLCBhUm90YXRpb24gPSAwICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNFbGxpcHNlQ3VydmUgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0VsbGlwc2VDdXJ2ZSc7XG5cblx0XHR0aGlzLmFYID0gYVg7XG5cdFx0dGhpcy5hWSA9IGFZO1xuXG5cdFx0dGhpcy54UmFkaXVzID0geFJhZGl1cztcblx0XHR0aGlzLnlSYWRpdXMgPSB5UmFkaXVzO1xuXG5cdFx0dGhpcy5hU3RhcnRBbmdsZSA9IGFTdGFydEFuZ2xlO1xuXHRcdHRoaXMuYUVuZEFuZ2xlID0gYUVuZEFuZ2xlO1xuXG5cdFx0dGhpcy5hQ2xvY2t3aXNlID0gYUNsb2Nrd2lzZTtcblxuXHRcdHRoaXMuYVJvdGF0aW9uID0gYVJvdGF0aW9uO1xuXG5cdH1cblxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgPSBuZXcgVmVjdG9yMigpICkge1xuXG5cdFx0Y29uc3QgcG9pbnQgPSBvcHRpb25hbFRhcmdldDtcblxuXHRcdGNvbnN0IHR3b1BpID0gTWF0aC5QSSAqIDI7XG5cdFx0bGV0IGRlbHRhQW5nbGUgPSB0aGlzLmFFbmRBbmdsZSAtIHRoaXMuYVN0YXJ0QW5nbGU7XG5cdFx0Y29uc3Qgc2FtZVBvaW50cyA9IE1hdGguYWJzKCBkZWx0YUFuZ2xlICkgPCBOdW1iZXIuRVBTSUxPTjtcblxuXHRcdC8vIGVuc3VyZXMgdGhhdCBkZWx0YUFuZ2xlIGlzIDAgLi4gMiBQSVxuXHRcdHdoaWxlICggZGVsdGFBbmdsZSA8IDAgKSBkZWx0YUFuZ2xlICs9IHR3b1BpO1xuXHRcdHdoaWxlICggZGVsdGFBbmdsZSA+IHR3b1BpICkgZGVsdGFBbmdsZSAtPSB0d29QaTtcblxuXHRcdGlmICggZGVsdGFBbmdsZSA8IE51bWJlci5FUFNJTE9OICkge1xuXG5cdFx0XHRpZiAoIHNhbWVQb2ludHMgKSB7XG5cblx0XHRcdFx0ZGVsdGFBbmdsZSA9IDA7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0ZGVsdGFBbmdsZSA9IHR3b1BpO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuYUNsb2Nrd2lzZSA9PT0gdHJ1ZSAmJiAhIHNhbWVQb2ludHMgKSB7XG5cblx0XHRcdGlmICggZGVsdGFBbmdsZSA9PT0gdHdvUGkgKSB7XG5cblx0XHRcdFx0ZGVsdGFBbmdsZSA9IC0gdHdvUGk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0ZGVsdGFBbmdsZSA9IGRlbHRhQW5nbGUgLSB0d29QaTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Y29uc3QgYW5nbGUgPSB0aGlzLmFTdGFydEFuZ2xlICsgdCAqIGRlbHRhQW5nbGU7XG5cdFx0bGV0IHggPSB0aGlzLmFYICsgdGhpcy54UmFkaXVzICogTWF0aC5jb3MoIGFuZ2xlICk7XG5cdFx0bGV0IHkgPSB0aGlzLmFZICsgdGhpcy55UmFkaXVzICogTWF0aC5zaW4oIGFuZ2xlICk7XG5cblx0XHRpZiAoIHRoaXMuYVJvdGF0aW9uICE9PSAwICkge1xuXG5cdFx0XHRjb25zdCBjb3MgPSBNYXRoLmNvcyggdGhpcy5hUm90YXRpb24gKTtcblx0XHRcdGNvbnN0IHNpbiA9IE1hdGguc2luKCB0aGlzLmFSb3RhdGlvbiApO1xuXG5cdFx0XHRjb25zdCB0eCA9IHggLSB0aGlzLmFYO1xuXHRcdFx0Y29uc3QgdHkgPSB5IC0gdGhpcy5hWTtcblxuXHRcdFx0Ly8gUm90YXRlIHRoZSBwb2ludCBhYm91dCB0aGUgY2VudGVyIG9mIHRoZSBlbGxpcHNlLlxuXHRcdFx0eCA9IHR4ICogY29zIC0gdHkgKiBzaW4gKyB0aGlzLmFYO1xuXHRcdFx0eSA9IHR4ICogc2luICsgdHkgKiBjb3MgKyB0aGlzLmFZO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHBvaW50LnNldCggeCwgeSApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuYVggPSBzb3VyY2UuYVg7XG5cdFx0dGhpcy5hWSA9IHNvdXJjZS5hWTtcblxuXHRcdHRoaXMueFJhZGl1cyA9IHNvdXJjZS54UmFkaXVzO1xuXHRcdHRoaXMueVJhZGl1cyA9IHNvdXJjZS55UmFkaXVzO1xuXG5cdFx0dGhpcy5hU3RhcnRBbmdsZSA9IHNvdXJjZS5hU3RhcnRBbmdsZTtcblx0XHR0aGlzLmFFbmRBbmdsZSA9IHNvdXJjZS5hRW5kQW5nbGU7XG5cblx0XHR0aGlzLmFDbG9ja3dpc2UgPSBzb3VyY2UuYUNsb2Nrd2lzZTtcblxuXHRcdHRoaXMuYVJvdGF0aW9uID0gc291cmNlLmFSb3RhdGlvbjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XG5cblx0XHRkYXRhLmFYID0gdGhpcy5hWDtcblx0XHRkYXRhLmFZID0gdGhpcy5hWTtcblxuXHRcdGRhdGEueFJhZGl1cyA9IHRoaXMueFJhZGl1cztcblx0XHRkYXRhLnlSYWRpdXMgPSB0aGlzLnlSYWRpdXM7XG5cblx0XHRkYXRhLmFTdGFydEFuZ2xlID0gdGhpcy5hU3RhcnRBbmdsZTtcblx0XHRkYXRhLmFFbmRBbmdsZSA9IHRoaXMuYUVuZEFuZ2xlO1xuXG5cdFx0ZGF0YS5hQ2xvY2t3aXNlID0gdGhpcy5hQ2xvY2t3aXNlO1xuXG5cdFx0ZGF0YS5hUm90YXRpb24gPSB0aGlzLmFSb3RhdGlvbjtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxuXHRmcm9tSlNPTigganNvbiApIHtcblxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XG5cblx0XHR0aGlzLmFYID0ganNvbi5hWDtcblx0XHR0aGlzLmFZID0ganNvbi5hWTtcblxuXHRcdHRoaXMueFJhZGl1cyA9IGpzb24ueFJhZGl1cztcblx0XHR0aGlzLnlSYWRpdXMgPSBqc29uLnlSYWRpdXM7XG5cblx0XHR0aGlzLmFTdGFydEFuZ2xlID0ganNvbi5hU3RhcnRBbmdsZTtcblx0XHR0aGlzLmFFbmRBbmdsZSA9IGpzb24uYUVuZEFuZ2xlO1xuXG5cdFx0dGhpcy5hQ2xvY2t3aXNlID0ganNvbi5hQ2xvY2t3aXNlO1xuXG5cdFx0dGhpcy5hUm90YXRpb24gPSBqc29uLmFSb3RhdGlvbjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBBcmNDdXJ2ZSBleHRlbmRzIEVsbGlwc2VDdXJ2ZSB7XG5cblx0Y29uc3RydWN0b3IoIGFYLCBhWSwgYVJhZGl1cywgYVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSApIHtcblxuXHRcdHN1cGVyKCBhWCwgYVksIGFSYWRpdXMsIGFSYWRpdXMsIGFTdGFydEFuZ2xlLCBhRW5kQW5nbGUsIGFDbG9ja3dpc2UgKTtcblxuXHRcdHRoaXMuaXNBcmNDdXJ2ZSA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnQXJjQ3VydmUnO1xuXG5cdH1cblxufVxuXG4vKipcbiAqIENlbnRyaXBldGFsIENhdG11bGxSb20gQ3VydmUgLSB3aGljaCBpcyB1c2VmdWwgZm9yIGF2b2lkaW5nXG4gKiBjdXNwcyBhbmQgc2VsZi1pbnRlcnNlY3Rpb25zIGluIG5vbi11bmlmb3JtIGNhdG11bGwgcm9tIGN1cnZlcy5cbiAqIGh0dHA6Ly93d3cuY2VteXVrc2VsLmNvbS9yZXNlYXJjaC9jYXRtdWxscm9tX3BhcmFtL2NhdG11bGxyb20ucGRmXG4gKlxuICogY3VydmUudHlwZSBhY2NlcHRzIGNlbnRyaXBldGFsKGRlZmF1bHQpLCBjaG9yZGFsIGFuZCBjYXRtdWxscm9tXG4gKiBjdXJ2ZS50ZW5zaW9uIGlzIHVzZWQgZm9yIGNhdG11bGxyb20gd2hpY2ggZGVmYXVsdHMgdG8gMC41XG4gKi9cblxuXG4vKlxuQmFzZWQgb24gYW4gb3B0aW1pemVkIGMrKyBzb2x1dGlvbiBpblxuIC0gaHR0cDovL3N0YWNrb3ZlcmZsb3cuY29tL3F1ZXN0aW9ucy85NDg5NzM2L2NhdG11bGwtcm9tLWN1cnZlLXdpdGgtbm8tY3VzcHMtYW5kLW5vLXNlbGYtaW50ZXJzZWN0aW9ucy9cbiAtIGh0dHA6Ly9pZGVvbmUuY29tL05vRWJWTVxuXG5UaGlzIEN1YmljUG9seSBjbGFzcyBjb3VsZCBiZSB1c2VkIGZvciByZXVzaW5nIHNvbWUgdmFyaWFibGVzIGFuZCBjYWxjdWxhdGlvbnMsXG5idXQgZm9yIHRocmVlLmpzIGN1cnZlIHVzZSwgaXQgY291bGQgYmUgcG9zc2libGUgaW5saW5lZCBhbmQgZmxhdHRlbiBpbnRvIGEgc2luZ2xlIGZ1bmN0aW9uIGNhbGxcbndoaWNoIGNhbiBiZSBwbGFjZWQgaW4gQ3VydmVVdGlscy5cbiovXG5cbmZ1bmN0aW9uIEN1YmljUG9seSgpIHtcblxuXHRsZXQgYzAgPSAwLCBjMSA9IDAsIGMyID0gMCwgYzMgPSAwO1xuXG5cdC8qXG5cdCAqIENvbXB1dGUgY29lZmZpY2llbnRzIGZvciBhIGN1YmljIHBvbHlub21pYWxcblx0ICogICBwKHMpID0gYzAgKyBjMSpzICsgYzIqc14yICsgYzMqc14zXG5cdCAqIHN1Y2ggdGhhdFxuXHQgKiAgIHAoMCkgPSB4MCwgcCgxKSA9IHgxXG5cdCAqICBhbmRcblx0ICogICBwJygwKSA9IHQwLCBwJygxKSA9IHQxLlxuXHQgKi9cblx0ZnVuY3Rpb24gaW5pdCggeDAsIHgxLCB0MCwgdDEgKSB7XG5cblx0XHRjMCA9IHgwO1xuXHRcdGMxID0gdDA7XG5cdFx0YzIgPSAtIDMgKiB4MCArIDMgKiB4MSAtIDIgKiB0MCAtIHQxO1xuXHRcdGMzID0gMiAqIHgwIC0gMiAqIHgxICsgdDAgKyB0MTtcblxuXHR9XG5cblx0cmV0dXJuIHtcblxuXHRcdGluaXRDYXRtdWxsUm9tOiBmdW5jdGlvbiAoIHgwLCB4MSwgeDIsIHgzLCB0ZW5zaW9uICkge1xuXG5cdFx0XHRpbml0KCB4MSwgeDIsIHRlbnNpb24gKiAoIHgyIC0geDAgKSwgdGVuc2lvbiAqICggeDMgLSB4MSApICk7XG5cblx0XHR9LFxuXG5cdFx0aW5pdE5vbnVuaWZvcm1DYXRtdWxsUm9tOiBmdW5jdGlvbiAoIHgwLCB4MSwgeDIsIHgzLCBkdDAsIGR0MSwgZHQyICkge1xuXG5cdFx0XHQvLyBjb21wdXRlIHRhbmdlbnRzIHdoZW4gcGFyYW1ldGVyaXplZCBpbiBbdDEsdDJdXG5cdFx0XHRsZXQgdDEgPSAoIHgxIC0geDAgKSAvIGR0MCAtICggeDIgLSB4MCApIC8gKCBkdDAgKyBkdDEgKSArICggeDIgLSB4MSApIC8gZHQxO1xuXHRcdFx0bGV0IHQyID0gKCB4MiAtIHgxICkgLyBkdDEgLSAoIHgzIC0geDEgKSAvICggZHQxICsgZHQyICkgKyAoIHgzIC0geDIgKSAvIGR0MjtcblxuXHRcdFx0Ly8gcmVzY2FsZSB0YW5nZW50cyBmb3IgcGFyYW1ldHJpemF0aW9uIGluIFswLDFdXG5cdFx0XHR0MSAqPSBkdDE7XG5cdFx0XHR0MiAqPSBkdDE7XG5cblx0XHRcdGluaXQoIHgxLCB4MiwgdDEsIHQyICk7XG5cblx0XHR9LFxuXG5cdFx0Y2FsYzogZnVuY3Rpb24gKCB0ICkge1xuXG5cdFx0XHRjb25zdCB0MiA9IHQgKiB0O1xuXHRcdFx0Y29uc3QgdDMgPSB0MiAqIHQ7XG5cdFx0XHRyZXR1cm4gYzAgKyBjMSAqIHQgKyBjMiAqIHQyICsgYzMgKiB0MztcblxuXHRcdH1cblxuXHR9O1xuXG59XG5cbi8vXG5cbmNvbnN0IHRtcCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IHB4ID0gLypAX19QVVJFX18qLyBuZXcgQ3ViaWNQb2x5KCk7XG5jb25zdCBweSA9IC8qQF9fUFVSRV9fKi8gbmV3IEN1YmljUG9seSgpO1xuY29uc3QgcHogPSAvKkBfX1BVUkVfXyovIG5ldyBDdWJpY1BvbHkoKTtcblxuY2xhc3MgQ2F0bXVsbFJvbUN1cnZlMyBleHRlbmRzIEN1cnZlIHtcblxuXHRjb25zdHJ1Y3RvciggcG9pbnRzID0gW10sIGNsb3NlZCA9IGZhbHNlLCBjdXJ2ZVR5cGUgPSAnY2VudHJpcGV0YWwnLCB0ZW5zaW9uID0gMC41ICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNDYXRtdWxsUm9tQ3VydmUzID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdDYXRtdWxsUm9tQ3VydmUzJztcblxuXHRcdHRoaXMucG9pbnRzID0gcG9pbnRzO1xuXHRcdHRoaXMuY2xvc2VkID0gY2xvc2VkO1xuXHRcdHRoaXMuY3VydmVUeXBlID0gY3VydmVUeXBlO1xuXHRcdHRoaXMudGVuc2lvbiA9IHRlbnNpb247XG5cblx0fVxuXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IzKCkgKSB7XG5cblx0XHRjb25zdCBwb2ludCA9IG9wdGlvbmFsVGFyZ2V0O1xuXG5cdFx0Y29uc3QgcG9pbnRzID0gdGhpcy5wb2ludHM7XG5cdFx0Y29uc3QgbCA9IHBvaW50cy5sZW5ndGg7XG5cblx0XHRjb25zdCBwID0gKCBsIC0gKCB0aGlzLmNsb3NlZCA/IDAgOiAxICkgKSAqIHQ7XG5cdFx0bGV0IGludFBvaW50ID0gTWF0aC5mbG9vciggcCApO1xuXHRcdGxldCB3ZWlnaHQgPSBwIC0gaW50UG9pbnQ7XG5cblx0XHRpZiAoIHRoaXMuY2xvc2VkICkge1xuXG5cdFx0XHRpbnRQb2ludCArPSBpbnRQb2ludCA+IDAgPyAwIDogKCBNYXRoLmZsb29yKCBNYXRoLmFicyggaW50UG9pbnQgKSAvIGwgKSArIDEgKSAqIGw7XG5cblx0XHR9IGVsc2UgaWYgKCB3ZWlnaHQgPT09IDAgJiYgaW50UG9pbnQgPT09IGwgLSAxICkge1xuXG5cdFx0XHRpbnRQb2ludCA9IGwgLSAyO1xuXHRcdFx0d2VpZ2h0ID0gMTtcblxuXHRcdH1cblxuXHRcdGxldCBwMCwgcDM7IC8vIDQgcG9pbnRzIChwMSAmIHAyIGRlZmluZWQgYmVsb3cpXG5cblx0XHRpZiAoIHRoaXMuY2xvc2VkIHx8IGludFBvaW50ID4gMCApIHtcblxuXHRcdFx0cDAgPSBwb2ludHNbICggaW50UG9pbnQgLSAxICkgJSBsIF07XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBleHRyYXBvbGF0ZSBmaXJzdCBwb2ludFxuXHRcdFx0dG1wLnN1YlZlY3RvcnMoIHBvaW50c1sgMCBdLCBwb2ludHNbIDEgXSApLmFkZCggcG9pbnRzWyAwIF0gKTtcblx0XHRcdHAwID0gdG1wO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgcDEgPSBwb2ludHNbIGludFBvaW50ICUgbCBdO1xuXHRcdGNvbnN0IHAyID0gcG9pbnRzWyAoIGludFBvaW50ICsgMSApICUgbCBdO1xuXG5cdFx0aWYgKCB0aGlzLmNsb3NlZCB8fCBpbnRQb2ludCArIDIgPCBsICkge1xuXG5cdFx0XHRwMyA9IHBvaW50c1sgKCBpbnRQb2ludCArIDIgKSAlIGwgXTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIGV4dHJhcG9sYXRlIGxhc3QgcG9pbnRcblx0XHRcdHRtcC5zdWJWZWN0b3JzKCBwb2ludHNbIGwgLSAxIF0sIHBvaW50c1sgbCAtIDIgXSApLmFkZCggcG9pbnRzWyBsIC0gMSBdICk7XG5cdFx0XHRwMyA9IHRtcDtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5jdXJ2ZVR5cGUgPT09ICdjZW50cmlwZXRhbCcgfHwgdGhpcy5jdXJ2ZVR5cGUgPT09ICdjaG9yZGFsJyApIHtcblxuXHRcdFx0Ly8gaW5pdCBDZW50cmlwZXRhbCAvIENob3JkYWwgQ2F0bXVsbC1Sb21cblx0XHRcdGNvbnN0IHBvdyA9IHRoaXMuY3VydmVUeXBlID09PSAnY2hvcmRhbCcgPyAwLjUgOiAwLjI1O1xuXHRcdFx0bGV0IGR0MCA9IE1hdGgucG93KCBwMC5kaXN0YW5jZVRvU3F1YXJlZCggcDEgKSwgcG93ICk7XG5cdFx0XHRsZXQgZHQxID0gTWF0aC5wb3coIHAxLmRpc3RhbmNlVG9TcXVhcmVkKCBwMiApLCBwb3cgKTtcblx0XHRcdGxldCBkdDIgPSBNYXRoLnBvdyggcDIuZGlzdGFuY2VUb1NxdWFyZWQoIHAzICksIHBvdyApO1xuXG5cdFx0XHQvLyBzYWZldHkgY2hlY2sgZm9yIHJlcGVhdGVkIHBvaW50c1xuXHRcdFx0aWYgKCBkdDEgPCAxZS00ICkgZHQxID0gMS4wO1xuXHRcdFx0aWYgKCBkdDAgPCAxZS00ICkgZHQwID0gZHQxO1xuXHRcdFx0aWYgKCBkdDIgPCAxZS00ICkgZHQyID0gZHQxO1xuXG5cdFx0XHRweC5pbml0Tm9udW5pZm9ybUNhdG11bGxSb20oIHAwLngsIHAxLngsIHAyLngsIHAzLngsIGR0MCwgZHQxLCBkdDIgKTtcblx0XHRcdHB5LmluaXROb251bmlmb3JtQ2F0bXVsbFJvbSggcDAueSwgcDEueSwgcDIueSwgcDMueSwgZHQwLCBkdDEsIGR0MiApO1xuXHRcdFx0cHouaW5pdE5vbnVuaWZvcm1DYXRtdWxsUm9tKCBwMC56LCBwMS56LCBwMi56LCBwMy56LCBkdDAsIGR0MSwgZHQyICk7XG5cblx0XHR9IGVsc2UgaWYgKCB0aGlzLmN1cnZlVHlwZSA9PT0gJ2NhdG11bGxyb20nICkge1xuXG5cdFx0XHRweC5pbml0Q2F0bXVsbFJvbSggcDAueCwgcDEueCwgcDIueCwgcDMueCwgdGhpcy50ZW5zaW9uICk7XG5cdFx0XHRweS5pbml0Q2F0bXVsbFJvbSggcDAueSwgcDEueSwgcDIueSwgcDMueSwgdGhpcy50ZW5zaW9uICk7XG5cdFx0XHRwei5pbml0Q2F0bXVsbFJvbSggcDAueiwgcDEueiwgcDIueiwgcDMueiwgdGhpcy50ZW5zaW9uICk7XG5cblx0XHR9XG5cblx0XHRwb2ludC5zZXQoXG5cdFx0XHRweC5jYWxjKCB3ZWlnaHQgKSxcblx0XHRcdHB5LmNhbGMoIHdlaWdodCApLFxuXHRcdFx0cHouY2FsYyggd2VpZ2h0IClcblx0XHQpO1xuXG5cdFx0cmV0dXJuIHBvaW50O1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucG9pbnRzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzb3VyY2UucG9pbnRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHBvaW50ID0gc291cmNlLnBvaW50c1sgaSBdO1xuXG5cdFx0XHR0aGlzLnBvaW50cy5wdXNoKCBwb2ludC5jbG9uZSgpICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmNsb3NlZCA9IHNvdXJjZS5jbG9zZWQ7XG5cdFx0dGhpcy5jdXJ2ZVR5cGUgPSBzb3VyY2UuY3VydmVUeXBlO1xuXHRcdHRoaXMudGVuc2lvbiA9IHNvdXJjZS50ZW5zaW9uO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcblxuXHRcdGRhdGEucG9pbnRzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLnBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBwb2ludCA9IHRoaXMucG9pbnRzWyBpIF07XG5cdFx0XHRkYXRhLnBvaW50cy5wdXNoKCBwb2ludC50b0FycmF5KCkgKTtcblxuXHRcdH1cblxuXHRcdGRhdGEuY2xvc2VkID0gdGhpcy5jbG9zZWQ7XG5cdFx0ZGF0YS5jdXJ2ZVR5cGUgPSB0aGlzLmN1cnZlVHlwZTtcblx0XHRkYXRhLnRlbnNpb24gPSB0aGlzLnRlbnNpb247XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cblx0ZnJvbUpTT04oIGpzb24gKSB7XG5cblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xuXG5cdFx0dGhpcy5wb2ludHMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ucG9pbnRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHBvaW50ID0ganNvbi5wb2ludHNbIGkgXTtcblx0XHRcdHRoaXMucG9pbnRzLnB1c2goIG5ldyBWZWN0b3IzKCkuZnJvbUFycmF5KCBwb2ludCApICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmNsb3NlZCA9IGpzb24uY2xvc2VkO1xuXHRcdHRoaXMuY3VydmVUeXBlID0ganNvbi5jdXJ2ZVR5cGU7XG5cdFx0dGhpcy50ZW5zaW9uID0ganNvbi50ZW5zaW9uO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbi8qKlxuICogQmV6aWVyIEN1cnZlcyBmb3JtdWxhcyBvYnRhaW5lZCBmcm9tXG4gKiBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9CJUMzJUE5emllcl9jdXJ2ZVxuICovXG5cbmZ1bmN0aW9uIENhdG11bGxSb20oIHQsIHAwLCBwMSwgcDIsIHAzICkge1xuXG5cdGNvbnN0IHYwID0gKCBwMiAtIHAwICkgKiAwLjU7XG5cdGNvbnN0IHYxID0gKCBwMyAtIHAxICkgKiAwLjU7XG5cdGNvbnN0IHQyID0gdCAqIHQ7XG5cdGNvbnN0IHQzID0gdCAqIHQyO1xuXHRyZXR1cm4gKCAyICogcDEgLSAyICogcDIgKyB2MCArIHYxICkgKiB0MyArICggLSAzICogcDEgKyAzICogcDIgLSAyICogdjAgLSB2MSApICogdDIgKyB2MCAqIHQgKyBwMTtcblxufVxuXG4vL1xuXG5mdW5jdGlvbiBRdWFkcmF0aWNCZXppZXJQMCggdCwgcCApIHtcblxuXHRjb25zdCBrID0gMSAtIHQ7XG5cdHJldHVybiBrICogayAqIHA7XG5cbn1cblxuZnVuY3Rpb24gUXVhZHJhdGljQmV6aWVyUDEoIHQsIHAgKSB7XG5cblx0cmV0dXJuIDIgKiAoIDEgLSB0ICkgKiB0ICogcDtcblxufVxuXG5mdW5jdGlvbiBRdWFkcmF0aWNCZXppZXJQMiggdCwgcCApIHtcblxuXHRyZXR1cm4gdCAqIHQgKiBwO1xuXG59XG5cbmZ1bmN0aW9uIFF1YWRyYXRpY0JlemllciggdCwgcDAsIHAxLCBwMiApIHtcblxuXHRyZXR1cm4gUXVhZHJhdGljQmV6aWVyUDAoIHQsIHAwICkgKyBRdWFkcmF0aWNCZXppZXJQMSggdCwgcDEgKSArXG5cdFx0UXVhZHJhdGljQmV6aWVyUDIoIHQsIHAyICk7XG5cbn1cblxuLy9cblxuZnVuY3Rpb24gQ3ViaWNCZXppZXJQMCggdCwgcCApIHtcblxuXHRjb25zdCBrID0gMSAtIHQ7XG5cdHJldHVybiBrICogayAqIGsgKiBwO1xuXG59XG5cbmZ1bmN0aW9uIEN1YmljQmV6aWVyUDEoIHQsIHAgKSB7XG5cblx0Y29uc3QgayA9IDEgLSB0O1xuXHRyZXR1cm4gMyAqIGsgKiBrICogdCAqIHA7XG5cbn1cblxuZnVuY3Rpb24gQ3ViaWNCZXppZXJQMiggdCwgcCApIHtcblxuXHRyZXR1cm4gMyAqICggMSAtIHQgKSAqIHQgKiB0ICogcDtcblxufVxuXG5mdW5jdGlvbiBDdWJpY0JlemllclAzKCB0LCBwICkge1xuXG5cdHJldHVybiB0ICogdCAqIHQgKiBwO1xuXG59XG5cbmZ1bmN0aW9uIEN1YmljQmV6aWVyKCB0LCBwMCwgcDEsIHAyLCBwMyApIHtcblxuXHRyZXR1cm4gQ3ViaWNCZXppZXJQMCggdCwgcDAgKSArIEN1YmljQmV6aWVyUDEoIHQsIHAxICkgKyBDdWJpY0JlemllclAyKCB0LCBwMiApICtcblx0XHRDdWJpY0JlemllclAzKCB0LCBwMyApO1xuXG59XG5cbmNsYXNzIEN1YmljQmV6aWVyQ3VydmUgZXh0ZW5kcyBDdXJ2ZSB7XG5cblx0Y29uc3RydWN0b3IoIHYwID0gbmV3IFZlY3RvcjIoKSwgdjEgPSBuZXcgVmVjdG9yMigpLCB2MiA9IG5ldyBWZWN0b3IyKCksIHYzID0gbmV3IFZlY3RvcjIoKSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzQ3ViaWNCZXppZXJDdXJ2ZSA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnQ3ViaWNCZXppZXJDdXJ2ZSc7XG5cblx0XHR0aGlzLnYwID0gdjA7XG5cdFx0dGhpcy52MSA9IHYxO1xuXHRcdHRoaXMudjIgPSB2Mjtcblx0XHR0aGlzLnYzID0gdjM7XG5cblx0fVxuXG5cdGdldFBvaW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IyKCkgKSB7XG5cblx0XHRjb25zdCBwb2ludCA9IG9wdGlvbmFsVGFyZ2V0O1xuXG5cdFx0Y29uc3QgdjAgPSB0aGlzLnYwLCB2MSA9IHRoaXMudjEsIHYyID0gdGhpcy52MiwgdjMgPSB0aGlzLnYzO1xuXG5cdFx0cG9pbnQuc2V0KFxuXHRcdFx0Q3ViaWNCZXppZXIoIHQsIHYwLngsIHYxLngsIHYyLngsIHYzLnggKSxcblx0XHRcdEN1YmljQmV6aWVyKCB0LCB2MC55LCB2MS55LCB2Mi55LCB2My55IClcblx0XHQpO1xuXG5cdFx0cmV0dXJuIHBvaW50O1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMudjAuY29weSggc291cmNlLnYwICk7XG5cdFx0dGhpcy52MS5jb3B5KCBzb3VyY2UudjEgKTtcblx0XHR0aGlzLnYyLmNvcHkoIHNvdXJjZS52MiApO1xuXHRcdHRoaXMudjMuY29weSggc291cmNlLnYzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS52MCA9IHRoaXMudjAudG9BcnJheSgpO1xuXHRcdGRhdGEudjEgPSB0aGlzLnYxLnRvQXJyYXkoKTtcblx0XHRkYXRhLnYyID0gdGhpcy52Mi50b0FycmF5KCk7XG5cdFx0ZGF0YS52MyA9IHRoaXMudjMudG9BcnJheSgpO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdGZyb21KU09OKCBqc29uICkge1xuXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcblxuXHRcdHRoaXMudjAuZnJvbUFycmF5KCBqc29uLnYwICk7XG5cdFx0dGhpcy52MS5mcm9tQXJyYXkoIGpzb24udjEgKTtcblx0XHR0aGlzLnYyLmZyb21BcnJheSgganNvbi52MiApO1xuXHRcdHRoaXMudjMuZnJvbUFycmF5KCBqc29uLnYzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgQ3ViaWNCZXppZXJDdXJ2ZTMgZXh0ZW5kcyBDdXJ2ZSB7XG5cblx0Y29uc3RydWN0b3IoIHYwID0gbmV3IFZlY3RvcjMoKSwgdjEgPSBuZXcgVmVjdG9yMygpLCB2MiA9IG5ldyBWZWN0b3IzKCksIHYzID0gbmV3IFZlY3RvcjMoKSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzQ3ViaWNCZXppZXJDdXJ2ZTMgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0N1YmljQmV6aWVyQ3VydmUzJztcblxuXHRcdHRoaXMudjAgPSB2MDtcblx0XHR0aGlzLnYxID0gdjE7XG5cdFx0dGhpcy52MiA9IHYyO1xuXHRcdHRoaXMudjMgPSB2MztcblxuXHR9XG5cblx0Z2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjMoKSApIHtcblxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XG5cblx0XHRjb25zdCB2MCA9IHRoaXMudjAsIHYxID0gdGhpcy52MSwgdjIgPSB0aGlzLnYyLCB2MyA9IHRoaXMudjM7XG5cblx0XHRwb2ludC5zZXQoXG5cdFx0XHRDdWJpY0JlemllciggdCwgdjAueCwgdjEueCwgdjIueCwgdjMueCApLFxuXHRcdFx0Q3ViaWNCZXppZXIoIHQsIHYwLnksIHYxLnksIHYyLnksIHYzLnkgKSxcblx0XHRcdEN1YmljQmV6aWVyKCB0LCB2MC56LCB2MS56LCB2Mi56LCB2My56IClcblx0XHQpO1xuXG5cdFx0cmV0dXJuIHBvaW50O1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMudjAuY29weSggc291cmNlLnYwICk7XG5cdFx0dGhpcy52MS5jb3B5KCBzb3VyY2UudjEgKTtcblx0XHR0aGlzLnYyLmNvcHkoIHNvdXJjZS52MiApO1xuXHRcdHRoaXMudjMuY29weSggc291cmNlLnYzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS52MCA9IHRoaXMudjAudG9BcnJheSgpO1xuXHRcdGRhdGEudjEgPSB0aGlzLnYxLnRvQXJyYXkoKTtcblx0XHRkYXRhLnYyID0gdGhpcy52Mi50b0FycmF5KCk7XG5cdFx0ZGF0YS52MyA9IHRoaXMudjMudG9BcnJheSgpO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdGZyb21KU09OKCBqc29uICkge1xuXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcblxuXHRcdHRoaXMudjAuZnJvbUFycmF5KCBqc29uLnYwICk7XG5cdFx0dGhpcy52MS5mcm9tQXJyYXkoIGpzb24udjEgKTtcblx0XHR0aGlzLnYyLmZyb21BcnJheSgganNvbi52MiApO1xuXHRcdHRoaXMudjMuZnJvbUFycmF5KCBqc29uLnYzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgTGluZUN1cnZlIGV4dGVuZHMgQ3VydmUge1xuXG5cdGNvbnN0cnVjdG9yKCB2MSA9IG5ldyBWZWN0b3IyKCksIHYyID0gbmV3IFZlY3RvcjIoKSApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTGluZUN1cnZlID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdMaW5lQ3VydmUnO1xuXG5cdFx0dGhpcy52MSA9IHYxO1xuXHRcdHRoaXMudjIgPSB2MjtcblxuXHR9XG5cblx0Z2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjIoKSApIHtcblxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XG5cblx0XHRpZiAoIHQgPT09IDEgKSB7XG5cblx0XHRcdHBvaW50LmNvcHkoIHRoaXMudjIgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHBvaW50LmNvcHkoIHRoaXMudjIgKS5zdWIoIHRoaXMudjEgKTtcblx0XHRcdHBvaW50Lm11bHRpcGx5U2NhbGFyKCB0ICkuYWRkKCB0aGlzLnYxICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcG9pbnQ7XG5cblx0fVxuXG5cdC8vIExpbmUgY3VydmUgaXMgbGluZWFyLCBzbyB3ZSBjYW4gb3ZlcndyaXRlIGRlZmF1bHQgZ2V0UG9pbnRBdFxuXHRnZXRQb2ludEF0KCB1LCBvcHRpb25hbFRhcmdldCApIHtcblxuXHRcdHJldHVybiB0aGlzLmdldFBvaW50KCB1LCBvcHRpb25hbFRhcmdldCApO1xuXG5cdH1cblxuXHRnZXRUYW5nZW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IyKCkgKSB7XG5cblx0XHRyZXR1cm4gb3B0aW9uYWxUYXJnZXQuc3ViVmVjdG9ycyggdGhpcy52MiwgdGhpcy52MSApLm5vcm1hbGl6ZSgpO1xuXG5cdH1cblxuXHRnZXRUYW5nZW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZ2V0VGFuZ2VudCggdSwgb3B0aW9uYWxUYXJnZXQgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLnYxLmNvcHkoIHNvdXJjZS52MSApO1xuXHRcdHRoaXMudjIuY29weSggc291cmNlLnYyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xuXHRcdGRhdGEudjIgPSB0aGlzLnYyLnRvQXJyYXkoKTtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxuXHRmcm9tSlNPTigganNvbiApIHtcblxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XG5cblx0XHR0aGlzLnYxLmZyb21BcnJheSgganNvbi52MSApO1xuXHRcdHRoaXMudjIuZnJvbUFycmF5KCBqc29uLnYyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgTGluZUN1cnZlMyBleHRlbmRzIEN1cnZlIHtcblxuXHRjb25zdHJ1Y3RvciggdjEgPSBuZXcgVmVjdG9yMygpLCB2MiA9IG5ldyBWZWN0b3IzKCkgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc0xpbmVDdXJ2ZTMgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ0xpbmVDdXJ2ZTMnO1xuXG5cdFx0dGhpcy52MSA9IHYxO1xuXHRcdHRoaXMudjIgPSB2MjtcblxuXHR9XG5cblx0Z2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjMoKSApIHtcblxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XG5cblx0XHRpZiAoIHQgPT09IDEgKSB7XG5cblx0XHRcdHBvaW50LmNvcHkoIHRoaXMudjIgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHBvaW50LmNvcHkoIHRoaXMudjIgKS5zdWIoIHRoaXMudjEgKTtcblx0XHRcdHBvaW50Lm11bHRpcGx5U2NhbGFyKCB0ICkuYWRkKCB0aGlzLnYxICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcG9pbnQ7XG5cblx0fVxuXG5cdC8vIExpbmUgY3VydmUgaXMgbGluZWFyLCBzbyB3ZSBjYW4gb3ZlcndyaXRlIGRlZmF1bHQgZ2V0UG9pbnRBdFxuXHRnZXRQb2ludEF0KCB1LCBvcHRpb25hbFRhcmdldCApIHtcblxuXHRcdHJldHVybiB0aGlzLmdldFBvaW50KCB1LCBvcHRpb25hbFRhcmdldCApO1xuXG5cdH1cblxuXHRnZXRUYW5nZW50KCB0LCBvcHRpb25hbFRhcmdldCA9IG5ldyBWZWN0b3IzKCkgKSB7XG5cblx0XHRyZXR1cm4gb3B0aW9uYWxUYXJnZXQuc3ViVmVjdG9ycyggdGhpcy52MiwgdGhpcy52MSApLm5vcm1hbGl6ZSgpO1xuXG5cdH1cblxuXHRnZXRUYW5nZW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZ2V0VGFuZ2VudCggdSwgb3B0aW9uYWxUYXJnZXQgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLnYxLmNvcHkoIHNvdXJjZS52MSApO1xuXHRcdHRoaXMudjIuY29weSggc291cmNlLnYyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xuXHRcdGRhdGEudjIgPSB0aGlzLnYyLnRvQXJyYXkoKTtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxuXHRmcm9tSlNPTigganNvbiApIHtcblxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XG5cblx0XHR0aGlzLnYxLmZyb21BcnJheSgganNvbi52MSApO1xuXHRcdHRoaXMudjIuZnJvbUFycmF5KCBqc29uLnYyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgUXVhZHJhdGljQmV6aWVyQ3VydmUgZXh0ZW5kcyBDdXJ2ZSB7XG5cblx0Y29uc3RydWN0b3IoIHYwID0gbmV3IFZlY3RvcjIoKSwgdjEgPSBuZXcgVmVjdG9yMigpLCB2MiA9IG5ldyBWZWN0b3IyKCkgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc1F1YWRyYXRpY0JlemllckN1cnZlID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdRdWFkcmF0aWNCZXppZXJDdXJ2ZSc7XG5cblx0XHR0aGlzLnYwID0gdjA7XG5cdFx0dGhpcy52MSA9IHYxO1xuXHRcdHRoaXMudjIgPSB2MjtcblxuXHR9XG5cblx0Z2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjIoKSApIHtcblxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XG5cblx0XHRjb25zdCB2MCA9IHRoaXMudjAsIHYxID0gdGhpcy52MSwgdjIgPSB0aGlzLnYyO1xuXG5cdFx0cG9pbnQuc2V0KFxuXHRcdFx0UXVhZHJhdGljQmV6aWVyKCB0LCB2MC54LCB2MS54LCB2Mi54ICksXG5cdFx0XHRRdWFkcmF0aWNCZXppZXIoIHQsIHYwLnksIHYxLnksIHYyLnkgKVxuXHRcdCk7XG5cblx0XHRyZXR1cm4gcG9pbnQ7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy52MC5jb3B5KCBzb3VyY2UudjAgKTtcblx0XHR0aGlzLnYxLmNvcHkoIHNvdXJjZS52MSApO1xuXHRcdHRoaXMudjIuY29weSggc291cmNlLnYyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS52MCA9IHRoaXMudjAudG9BcnJheSgpO1xuXHRcdGRhdGEudjEgPSB0aGlzLnYxLnRvQXJyYXkoKTtcblx0XHRkYXRhLnYyID0gdGhpcy52Mi50b0FycmF5KCk7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cblx0ZnJvbUpTT04oIGpzb24gKSB7XG5cblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xuXG5cdFx0dGhpcy52MC5mcm9tQXJyYXkoIGpzb24udjAgKTtcblx0XHR0aGlzLnYxLmZyb21BcnJheSgganNvbi52MSApO1xuXHRcdHRoaXMudjIuZnJvbUFycmF5KCBqc29uLnYyICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgUXVhZHJhdGljQmV6aWVyQ3VydmUzIGV4dGVuZHMgQ3VydmUge1xuXG5cdGNvbnN0cnVjdG9yKCB2MCA9IG5ldyBWZWN0b3IzKCksIHYxID0gbmV3IFZlY3RvcjMoKSwgdjIgPSBuZXcgVmVjdG9yMygpICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNRdWFkcmF0aWNCZXppZXJDdXJ2ZTMgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ1F1YWRyYXRpY0JlemllckN1cnZlMyc7XG5cblx0XHR0aGlzLnYwID0gdjA7XG5cdFx0dGhpcy52MSA9IHYxO1xuXHRcdHRoaXMudjIgPSB2MjtcblxuXHR9XG5cblx0Z2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjMoKSApIHtcblxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XG5cblx0XHRjb25zdCB2MCA9IHRoaXMudjAsIHYxID0gdGhpcy52MSwgdjIgPSB0aGlzLnYyO1xuXG5cdFx0cG9pbnQuc2V0KFxuXHRcdFx0UXVhZHJhdGljQmV6aWVyKCB0LCB2MC54LCB2MS54LCB2Mi54ICksXG5cdFx0XHRRdWFkcmF0aWNCZXppZXIoIHQsIHYwLnksIHYxLnksIHYyLnkgKSxcblx0XHRcdFF1YWRyYXRpY0JlemllciggdCwgdjAueiwgdjEueiwgdjIueiApXG5cdFx0KTtcblxuXHRcdHJldHVybiBwb2ludDtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLnYwLmNvcHkoIHNvdXJjZS52MCApO1xuXHRcdHRoaXMudjEuY29weSggc291cmNlLnYxICk7XG5cdFx0dGhpcy52Mi5jb3B5KCBzb3VyY2UudjIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XG5cblx0XHRkYXRhLnYwID0gdGhpcy52MC50b0FycmF5KCk7XG5cdFx0ZGF0YS52MSA9IHRoaXMudjEudG9BcnJheSgpO1xuXHRcdGRhdGEudjIgPSB0aGlzLnYyLnRvQXJyYXkoKTtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxuXHRmcm9tSlNPTigganNvbiApIHtcblxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XG5cblx0XHR0aGlzLnYwLmZyb21BcnJheSgganNvbi52MCApO1xuXHRcdHRoaXMudjEuZnJvbUFycmF5KCBqc29uLnYxICk7XG5cdFx0dGhpcy52Mi5mcm9tQXJyYXkoIGpzb24udjIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBTcGxpbmVDdXJ2ZSBleHRlbmRzIEN1cnZlIHtcblxuXHRjb25zdHJ1Y3RvciggcG9pbnRzID0gW10gKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc1NwbGluZUN1cnZlID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdTcGxpbmVDdXJ2ZSc7XG5cblx0XHR0aGlzLnBvaW50cyA9IHBvaW50cztcblxuXHR9XG5cblx0Z2V0UG9pbnQoIHQsIG9wdGlvbmFsVGFyZ2V0ID0gbmV3IFZlY3RvcjIoKSApIHtcblxuXHRcdGNvbnN0IHBvaW50ID0gb3B0aW9uYWxUYXJnZXQ7XG5cblx0XHRjb25zdCBwb2ludHMgPSB0aGlzLnBvaW50cztcblx0XHRjb25zdCBwID0gKCBwb2ludHMubGVuZ3RoIC0gMSApICogdDtcblxuXHRcdGNvbnN0IGludFBvaW50ID0gTWF0aC5mbG9vciggcCApO1xuXHRcdGNvbnN0IHdlaWdodCA9IHAgLSBpbnRQb2ludDtcblxuXHRcdGNvbnN0IHAwID0gcG9pbnRzWyBpbnRQb2ludCA9PT0gMCA/IGludFBvaW50IDogaW50UG9pbnQgLSAxIF07XG5cdFx0Y29uc3QgcDEgPSBwb2ludHNbIGludFBvaW50IF07XG5cdFx0Y29uc3QgcDIgPSBwb2ludHNbIGludFBvaW50ID4gcG9pbnRzLmxlbmd0aCAtIDIgPyBwb2ludHMubGVuZ3RoIC0gMSA6IGludFBvaW50ICsgMSBdO1xuXHRcdGNvbnN0IHAzID0gcG9pbnRzWyBpbnRQb2ludCA+IHBvaW50cy5sZW5ndGggLSAzID8gcG9pbnRzLmxlbmd0aCAtIDEgOiBpbnRQb2ludCArIDIgXTtcblxuXHRcdHBvaW50LnNldChcblx0XHRcdENhdG11bGxSb20oIHdlaWdodCwgcDAueCwgcDEueCwgcDIueCwgcDMueCApLFxuXHRcdFx0Q2F0bXVsbFJvbSggd2VpZ2h0LCBwMC55LCBwMS55LCBwMi55LCBwMy55IClcblx0XHQpO1xuXG5cdFx0cmV0dXJuIHBvaW50O1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucG9pbnRzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzb3VyY2UucG9pbnRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHBvaW50ID0gc291cmNlLnBvaW50c1sgaSBdO1xuXG5cdFx0XHR0aGlzLnBvaW50cy5wdXNoKCBwb2ludC5jbG9uZSgpICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS5wb2ludHMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMucG9pbnRzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHBvaW50ID0gdGhpcy5wb2ludHNbIGkgXTtcblx0XHRcdGRhdGEucG9pbnRzLnB1c2goIHBvaW50LnRvQXJyYXkoKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdGZyb21KU09OKCBqc29uICkge1xuXG5cdFx0c3VwZXIuZnJvbUpTT04oIGpzb24gKTtcblxuXHRcdHRoaXMucG9pbnRzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLnBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBwb2ludCA9IGpzb24ucG9pbnRzWyBpIF07XG5cdFx0XHR0aGlzLnBvaW50cy5wdXNoKCBuZXcgVmVjdG9yMigpLmZyb21BcnJheSggcG9pbnQgKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbnZhciBDdXJ2ZXMgPSAvKiNfX1BVUkVfXyovT2JqZWN0LmZyZWV6ZSh7XG5cdF9fcHJvdG9fXzogbnVsbCxcblx0QXJjQ3VydmU6IEFyY0N1cnZlLFxuXHRDYXRtdWxsUm9tQ3VydmUzOiBDYXRtdWxsUm9tQ3VydmUzLFxuXHRDdWJpY0JlemllckN1cnZlOiBDdWJpY0JlemllckN1cnZlLFxuXHRDdWJpY0JlemllckN1cnZlMzogQ3ViaWNCZXppZXJDdXJ2ZTMsXG5cdEVsbGlwc2VDdXJ2ZTogRWxsaXBzZUN1cnZlLFxuXHRMaW5lQ3VydmU6IExpbmVDdXJ2ZSxcblx0TGluZUN1cnZlMzogTGluZUN1cnZlMyxcblx0UXVhZHJhdGljQmV6aWVyQ3VydmU6IFF1YWRyYXRpY0JlemllckN1cnZlLFxuXHRRdWFkcmF0aWNCZXppZXJDdXJ2ZTM6IFF1YWRyYXRpY0JlemllckN1cnZlMyxcblx0U3BsaW5lQ3VydmU6IFNwbGluZUN1cnZlXG59KTtcblxuLyoqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqXG4gKlx0Q3VydmVkIFBhdGggLSBhIGN1cnZlIHBhdGggaXMgc2ltcGx5IGEgYXJyYXkgb2YgY29ubmVjdGVkXG4gKiAgY3VydmVzLCBidXQgcmV0YWlucyB0aGUgYXBpIG9mIGEgY3VydmVcbiAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKi9cblxuY2xhc3MgQ3VydmVQYXRoIGV4dGVuZHMgQ3VydmUge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdDdXJ2ZVBhdGgnO1xuXG5cdFx0dGhpcy5jdXJ2ZXMgPSBbXTtcblx0XHR0aGlzLmF1dG9DbG9zZSA9IGZhbHNlOyAvLyBBdXRvbWF0aWNhbGx5IGNsb3NlcyB0aGUgcGF0aFxuXG5cdH1cblxuXHRhZGQoIGN1cnZlICkge1xuXG5cdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUgKTtcblxuXHR9XG5cblx0Y2xvc2VQYXRoKCkge1xuXG5cdFx0Ly8gQWRkIGEgbGluZSBjdXJ2ZSBpZiBzdGFydCBhbmQgZW5kIG9mIGxpbmVzIGFyZSBub3QgY29ubmVjdGVkXG5cdFx0Y29uc3Qgc3RhcnRQb2ludCA9IHRoaXMuY3VydmVzWyAwIF0uZ2V0UG9pbnQoIDAgKTtcblx0XHRjb25zdCBlbmRQb2ludCA9IHRoaXMuY3VydmVzWyB0aGlzLmN1cnZlcy5sZW5ndGggLSAxIF0uZ2V0UG9pbnQoIDEgKTtcblxuXHRcdGlmICggISBzdGFydFBvaW50LmVxdWFscyggZW5kUG9pbnQgKSApIHtcblxuXHRcdFx0Y29uc3QgbGluZVR5cGUgPSAoIHN0YXJ0UG9pbnQuaXNWZWN0b3IyID09PSB0cnVlICkgPyAnTGluZUN1cnZlJyA6ICdMaW5lQ3VydmUzJztcblx0XHRcdHRoaXMuY3VydmVzLnB1c2goIG5ldyBDdXJ2ZXNbIGxpbmVUeXBlIF0oIGVuZFBvaW50LCBzdGFydFBvaW50ICkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvLyBUbyBnZXQgYWNjdXJhdGUgcG9pbnQgd2l0aCByZWZlcmVuY2UgdG9cblx0Ly8gZW50aXJlIHBhdGggZGlzdGFuY2UgYXQgdGltZSB0LFxuXHQvLyBmb2xsb3dpbmcgaGFzIHRvIGJlIGRvbmU6XG5cblx0Ly8gMS4gTGVuZ3RoIG9mIGVhY2ggc3ViIHBhdGggaGF2ZSB0byBiZSBrbm93blxuXHQvLyAyLiBMb2NhdGUgYW5kIGlkZW50aWZ5IHR5cGUgb2YgY3VydmVcblx0Ly8gMy4gR2V0IHQgZm9yIHRoZSBjdXJ2ZVxuXHQvLyA0LiBSZXR1cm4gY3VydmUuZ2V0UG9pbnRBdCh0JylcblxuXHRnZXRQb2ludCggdCwgb3B0aW9uYWxUYXJnZXQgKSB7XG5cblx0XHRjb25zdCBkID0gdCAqIHRoaXMuZ2V0TGVuZ3RoKCk7XG5cdFx0Y29uc3QgY3VydmVMZW5ndGhzID0gdGhpcy5nZXRDdXJ2ZUxlbmd0aHMoKTtcblx0XHRsZXQgaSA9IDA7XG5cblx0XHQvLyBUbyB0aGluayBhYm91dCBib3VuZGFyaWVzIHBvaW50cy5cblxuXHRcdHdoaWxlICggaSA8IGN1cnZlTGVuZ3Rocy5sZW5ndGggKSB7XG5cblx0XHRcdGlmICggY3VydmVMZW5ndGhzWyBpIF0gPj0gZCApIHtcblxuXHRcdFx0XHRjb25zdCBkaWZmID0gY3VydmVMZW5ndGhzWyBpIF0gLSBkO1xuXHRcdFx0XHRjb25zdCBjdXJ2ZSA9IHRoaXMuY3VydmVzWyBpIF07XG5cblx0XHRcdFx0Y29uc3Qgc2VnbWVudExlbmd0aCA9IGN1cnZlLmdldExlbmd0aCgpO1xuXHRcdFx0XHRjb25zdCB1ID0gc2VnbWVudExlbmd0aCA9PT0gMCA/IDAgOiAxIC0gZGlmZiAvIHNlZ21lbnRMZW5ndGg7XG5cblx0XHRcdFx0cmV0dXJuIGN1cnZlLmdldFBvaW50QXQoIHUsIG9wdGlvbmFsVGFyZ2V0ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0aSArKztcblxuXHRcdH1cblxuXHRcdHJldHVybiBudWxsO1xuXG5cdFx0Ly8gbG9vcCB3aGVyZSBzdW0gIT0gMCwgc3VtID4gZCAsIHN1bSsxIDxkXG5cblx0fVxuXG5cdC8vIFdlIGNhbm5vdCB1c2UgdGhlIGRlZmF1bHQgVEhSRUUuQ3VydmUgZ2V0UG9pbnQoKSB3aXRoIGdldExlbmd0aCgpIGJlY2F1c2UgaW5cblx0Ly8gVEhSRUUuQ3VydmUsIGdldExlbmd0aCgpIGRlcGVuZHMgb24gZ2V0UG9pbnQoKSBidXQgaW4gVEhSRUUuQ3VydmVQYXRoXG5cdC8vIGdldFBvaW50KCkgZGVwZW5kcyBvbiBnZXRMZW5ndGhcblxuXHRnZXRMZW5ndGgoKSB7XG5cblx0XHRjb25zdCBsZW5zID0gdGhpcy5nZXRDdXJ2ZUxlbmd0aHMoKTtcblx0XHRyZXR1cm4gbGVuc1sgbGVucy5sZW5ndGggLSAxIF07XG5cblx0fVxuXG5cdC8vIGNhY2hlTGVuZ3RocyBtdXN0IGJlIHJlY2FsY3VsYXRlZC5cblx0dXBkYXRlQXJjTGVuZ3RocygpIHtcblxuXHRcdHRoaXMubmVlZHNVcGRhdGUgPSB0cnVlO1xuXHRcdHRoaXMuY2FjaGVMZW5ndGhzID0gbnVsbDtcblx0XHR0aGlzLmdldEN1cnZlTGVuZ3RocygpO1xuXG5cdH1cblxuXHQvLyBDb21wdXRlIGxlbmd0aHMgYW5kIGNhY2hlIHRoZW1cblx0Ly8gV2UgY2Fubm90IG92ZXJ3cml0ZSBnZXRMZW5ndGhzKCkgYmVjYXVzZSBVdG9UIG1hcHBpbmcgdXNlcyBpdC5cblxuXHRnZXRDdXJ2ZUxlbmd0aHMoKSB7XG5cblx0XHQvLyBXZSB1c2UgY2FjaGUgdmFsdWVzIGlmIGN1cnZlcyBhbmQgY2FjaGUgYXJyYXkgYXJlIHNhbWUgbGVuZ3RoXG5cblx0XHRpZiAoIHRoaXMuY2FjaGVMZW5ndGhzICYmIHRoaXMuY2FjaGVMZW5ndGhzLmxlbmd0aCA9PT0gdGhpcy5jdXJ2ZXMubGVuZ3RoICkge1xuXG5cdFx0XHRyZXR1cm4gdGhpcy5jYWNoZUxlbmd0aHM7XG5cblx0XHR9XG5cblx0XHQvLyBHZXQgbGVuZ3RoIG9mIHN1Yi1jdXJ2ZVxuXHRcdC8vIFB1c2ggc3VtcyBpbnRvIGNhY2hlZCBhcnJheVxuXG5cdFx0Y29uc3QgbGVuZ3RocyA9IFtdO1xuXHRcdGxldCBzdW1zID0gMDtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHRoaXMuY3VydmVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdHN1bXMgKz0gdGhpcy5jdXJ2ZXNbIGkgXS5nZXRMZW5ndGgoKTtcblx0XHRcdGxlbmd0aHMucHVzaCggc3VtcyApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5jYWNoZUxlbmd0aHMgPSBsZW5ndGhzO1xuXG5cdFx0cmV0dXJuIGxlbmd0aHM7XG5cblx0fVxuXG5cdGdldFNwYWNlZFBvaW50cyggZGl2aXNpb25zID0gNDAgKSB7XG5cblx0XHRjb25zdCBwb2ludHMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSBkaXZpc2lvbnM7IGkgKysgKSB7XG5cblx0XHRcdHBvaW50cy5wdXNoKCB0aGlzLmdldFBvaW50KCBpIC8gZGl2aXNpb25zICkgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5hdXRvQ2xvc2UgKSB7XG5cblx0XHRcdHBvaW50cy5wdXNoKCBwb2ludHNbIDAgXSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHBvaW50cztcblxuXHR9XG5cblx0Z2V0UG9pbnRzKCBkaXZpc2lvbnMgPSAxMiApIHtcblxuXHRcdGNvbnN0IHBvaW50cyA9IFtdO1xuXHRcdGxldCBsYXN0O1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBjdXJ2ZXMgPSB0aGlzLmN1cnZlczsgaSA8IGN1cnZlcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGN1cnZlID0gY3VydmVzWyBpIF07XG5cdFx0XHRjb25zdCByZXNvbHV0aW9uID0gY3VydmUuaXNFbGxpcHNlQ3VydmUgPyBkaXZpc2lvbnMgKiAyXG5cdFx0XHRcdDogKCBjdXJ2ZS5pc0xpbmVDdXJ2ZSB8fCBjdXJ2ZS5pc0xpbmVDdXJ2ZTMgKSA/IDFcblx0XHRcdFx0XHQ6IGN1cnZlLmlzU3BsaW5lQ3VydmUgPyBkaXZpc2lvbnMgKiBjdXJ2ZS5wb2ludHMubGVuZ3RoXG5cdFx0XHRcdFx0XHQ6IGRpdmlzaW9ucztcblxuXHRcdFx0Y29uc3QgcHRzID0gY3VydmUuZ2V0UG9pbnRzKCByZXNvbHV0aW9uICk7XG5cblx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IHB0cy5sZW5ndGg7IGogKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgcG9pbnQgPSBwdHNbIGogXTtcblxuXHRcdFx0XHRpZiAoIGxhc3QgJiYgbGFzdC5lcXVhbHMoIHBvaW50ICkgKSBjb250aW51ZTsgLy8gZW5zdXJlcyBubyBjb25zZWN1dGl2ZSBwb2ludHMgYXJlIGR1cGxpY2F0ZXNcblxuXHRcdFx0XHRwb2ludHMucHVzaCggcG9pbnQgKTtcblx0XHRcdFx0bGFzdCA9IHBvaW50O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuYXV0b0Nsb3NlICYmIHBvaW50cy5sZW5ndGggPiAxICYmICEgcG9pbnRzWyBwb2ludHMubGVuZ3RoIC0gMSBdLmVxdWFscyggcG9pbnRzWyAwIF0gKSApIHtcblxuXHRcdFx0cG9pbnRzLnB1c2goIHBvaW50c1sgMCBdICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcG9pbnRzO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuY3VydmVzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzb3VyY2UuY3VydmVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGN1cnZlID0gc291cmNlLmN1cnZlc1sgaSBdO1xuXG5cdFx0XHR0aGlzLmN1cnZlcy5wdXNoKCBjdXJ2ZS5jbG9uZSgpICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmF1dG9DbG9zZSA9IHNvdXJjZS5hdXRvQ2xvc2U7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS5hdXRvQ2xvc2UgPSB0aGlzLmF1dG9DbG9zZTtcblx0XHRkYXRhLmN1cnZlcyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdGhpcy5jdXJ2ZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgY3VydmUgPSB0aGlzLmN1cnZlc1sgaSBdO1xuXHRcdFx0ZGF0YS5jdXJ2ZXMucHVzaCggY3VydmUudG9KU09OKCkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxuXHRmcm9tSlNPTigganNvbiApIHtcblxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XG5cblx0XHR0aGlzLmF1dG9DbG9zZSA9IGpzb24uYXV0b0Nsb3NlO1xuXHRcdHRoaXMuY3VydmVzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmN1cnZlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBjdXJ2ZSA9IGpzb24uY3VydmVzWyBpIF07XG5cdFx0XHR0aGlzLmN1cnZlcy5wdXNoKCBuZXcgQ3VydmVzWyBjdXJ2ZS50eXBlIF0oKS5mcm9tSlNPTiggY3VydmUgKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIFBhdGggZXh0ZW5kcyBDdXJ2ZVBhdGgge1xuXG5cdGNvbnN0cnVjdG9yKCBwb2ludHMgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ1BhdGgnO1xuXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQgPSBuZXcgVmVjdG9yMigpO1xuXG5cdFx0aWYgKCBwb2ludHMgKSB7XG5cblx0XHRcdHRoaXMuc2V0RnJvbVBvaW50cyggcG9pbnRzICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHNldEZyb21Qb2ludHMoIHBvaW50cyApIHtcblxuXHRcdHRoaXMubW92ZVRvKCBwb2ludHNbIDAgXS54LCBwb2ludHNbIDAgXS55ICk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDEsIGwgPSBwb2ludHMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5saW5lVG8oIHBvaW50c1sgaSBdLngsIHBvaW50c1sgaSBdLnkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRtb3ZlVG8oIHgsIHkgKSB7XG5cblx0XHR0aGlzLmN1cnJlbnRQb2ludC5zZXQoIHgsIHkgKTsgLy8gVE9ETyBjb25zaWRlciByZWZlcmVuY2luZyB2ZWN0b3JzIGluc3RlYWQgb2YgY29weWluZz9cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRsaW5lVG8oIHgsIHkgKSB7XG5cblx0XHRjb25zdCBjdXJ2ZSA9IG5ldyBMaW5lQ3VydmUoIHRoaXMuY3VycmVudFBvaW50LmNsb25lKCksIG5ldyBWZWN0b3IyKCB4LCB5ICkgKTtcblx0XHR0aGlzLmN1cnZlcy5wdXNoKCBjdXJ2ZSApO1xuXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuc2V0KCB4LCB5ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cXVhZHJhdGljQ3VydmVUbyggYUNQeCwgYUNQeSwgYVgsIGFZICkge1xuXG5cdFx0Y29uc3QgY3VydmUgPSBuZXcgUXVhZHJhdGljQmV6aWVyQ3VydmUoXG5cdFx0XHR0aGlzLmN1cnJlbnRQb2ludC5jbG9uZSgpLFxuXHRcdFx0bmV3IFZlY3RvcjIoIGFDUHgsIGFDUHkgKSxcblx0XHRcdG5ldyBWZWN0b3IyKCBhWCwgYVkgKVxuXHRcdCk7XG5cblx0XHR0aGlzLmN1cnZlcy5wdXNoKCBjdXJ2ZSApO1xuXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuc2V0KCBhWCwgYVkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRiZXppZXJDdXJ2ZVRvKCBhQ1AxeCwgYUNQMXksIGFDUDJ4LCBhQ1AyeSwgYVgsIGFZICkge1xuXG5cdFx0Y29uc3QgY3VydmUgPSBuZXcgQ3ViaWNCZXppZXJDdXJ2ZShcblx0XHRcdHRoaXMuY3VycmVudFBvaW50LmNsb25lKCksXG5cdFx0XHRuZXcgVmVjdG9yMiggYUNQMXgsIGFDUDF5ICksXG5cdFx0XHRuZXcgVmVjdG9yMiggYUNQMngsIGFDUDJ5ICksXG5cdFx0XHRuZXcgVmVjdG9yMiggYVgsIGFZIClcblx0XHQpO1xuXG5cdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUgKTtcblxuXHRcdHRoaXMuY3VycmVudFBvaW50LnNldCggYVgsIGFZICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3BsaW5lVGhydSggcHRzIC8qQXJyYXkgb2YgVmVjdG9yKi8gKSB7XG5cblx0XHRjb25zdCBucHRzID0gWyB0aGlzLmN1cnJlbnRQb2ludC5jbG9uZSgpIF0uY29uY2F0KCBwdHMgKTtcblxuXHRcdGNvbnN0IGN1cnZlID0gbmV3IFNwbGluZUN1cnZlKCBucHRzICk7XG5cdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUgKTtcblxuXHRcdHRoaXMuY3VycmVudFBvaW50LmNvcHkoIHB0c1sgcHRzLmxlbmd0aCAtIDEgXSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFyYyggYVgsIGFZLCBhUmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICkge1xuXG5cdFx0Y29uc3QgeDAgPSB0aGlzLmN1cnJlbnRQb2ludC54O1xuXHRcdGNvbnN0IHkwID0gdGhpcy5jdXJyZW50UG9pbnQueTtcblxuXHRcdHRoaXMuYWJzYXJjKCBhWCArIHgwLCBhWSArIHkwLCBhUmFkaXVzLFxuXHRcdFx0YVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFic2FyYyggYVgsIGFZLCBhUmFkaXVzLCBhU3RhcnRBbmdsZSwgYUVuZEFuZ2xlLCBhQ2xvY2t3aXNlICkge1xuXG5cdFx0dGhpcy5hYnNlbGxpcHNlKCBhWCwgYVksIGFSYWRpdXMsIGFSYWRpdXMsIGFTdGFydEFuZ2xlLCBhRW5kQW5nbGUsIGFDbG9ja3dpc2UgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRlbGxpcHNlKCBhWCwgYVksIHhSYWRpdXMsIHlSYWRpdXMsIGFTdGFydEFuZ2xlLCBhRW5kQW5nbGUsIGFDbG9ja3dpc2UsIGFSb3RhdGlvbiApIHtcblxuXHRcdGNvbnN0IHgwID0gdGhpcy5jdXJyZW50UG9pbnQueDtcblx0XHRjb25zdCB5MCA9IHRoaXMuY3VycmVudFBvaW50Lnk7XG5cblx0XHR0aGlzLmFic2VsbGlwc2UoIGFYICsgeDAsIGFZICsgeTAsIHhSYWRpdXMsIHlSYWRpdXMsIGFTdGFydEFuZ2xlLCBhRW5kQW5nbGUsIGFDbG9ja3dpc2UsIGFSb3RhdGlvbiApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFic2VsbGlwc2UoIGFYLCBhWSwgeFJhZGl1cywgeVJhZGl1cywgYVN0YXJ0QW5nbGUsIGFFbmRBbmdsZSwgYUNsb2Nrd2lzZSwgYVJvdGF0aW9uICkge1xuXG5cdFx0Y29uc3QgY3VydmUgPSBuZXcgRWxsaXBzZUN1cnZlKCBhWCwgYVksIHhSYWRpdXMsIHlSYWRpdXMsIGFTdGFydEFuZ2xlLCBhRW5kQW5nbGUsIGFDbG9ja3dpc2UsIGFSb3RhdGlvbiApO1xuXG5cdFx0aWYgKCB0aGlzLmN1cnZlcy5sZW5ndGggPiAwICkge1xuXG5cdFx0XHQvLyBpZiBhIHByZXZpb3VzIGN1cnZlIGlzIHByZXNlbnQsIGF0dGVtcHQgdG8gam9pblxuXHRcdFx0Y29uc3QgZmlyc3RQb2ludCA9IGN1cnZlLmdldFBvaW50KCAwICk7XG5cblx0XHRcdGlmICggISBmaXJzdFBvaW50LmVxdWFscyggdGhpcy5jdXJyZW50UG9pbnQgKSApIHtcblxuXHRcdFx0XHR0aGlzLmxpbmVUbyggZmlyc3RQb2ludC54LCBmaXJzdFBvaW50LnkgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0dGhpcy5jdXJ2ZXMucHVzaCggY3VydmUgKTtcblxuXHRcdGNvbnN0IGxhc3RQb2ludCA9IGN1cnZlLmdldFBvaW50KCAxICk7XG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuY29weSggbGFzdFBvaW50ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLmN1cnJlbnRQb2ludC5jb3B5KCBzb3VyY2UuY3VycmVudFBvaW50ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9KU09OKCkge1xuXG5cdFx0Y29uc3QgZGF0YSA9IHN1cGVyLnRvSlNPTigpO1xuXG5cdFx0ZGF0YS5jdXJyZW50UG9pbnQgPSB0aGlzLmN1cnJlbnRQb2ludC50b0FycmF5KCk7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cblx0ZnJvbUpTT04oIGpzb24gKSB7XG5cblx0XHRzdXBlci5mcm9tSlNPTigganNvbiApO1xuXG5cdFx0dGhpcy5jdXJyZW50UG9pbnQuZnJvbUFycmF5KCBqc29uLmN1cnJlbnRQb2ludCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIExhdGhlR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHBvaW50cyA9IFsgbmV3IFZlY3RvcjIoIDAsIC0gMC41ICksIG5ldyBWZWN0b3IyKCAwLjUsIDAgKSwgbmV3IFZlY3RvcjIoIDAsIDAuNSApIF0sIHNlZ21lbnRzID0gMTIsIHBoaVN0YXJ0ID0gMCwgcGhpTGVuZ3RoID0gTWF0aC5QSSAqIDIgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ0xhdGhlR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0cG9pbnRzOiBwb2ludHMsXG5cdFx0XHRzZWdtZW50czogc2VnbWVudHMsXG5cdFx0XHRwaGlTdGFydDogcGhpU3RhcnQsXG5cdFx0XHRwaGlMZW5ndGg6IHBoaUxlbmd0aFxuXHRcdH07XG5cblx0XHRzZWdtZW50cyA9IE1hdGguZmxvb3IoIHNlZ21lbnRzICk7XG5cblx0XHQvLyBjbGFtcCBwaGlMZW5ndGggc28gaXQncyBpbiByYW5nZSBvZiBbIDAsIDJQSSBdXG5cblx0XHRwaGlMZW5ndGggPSBjbGFtcCggcGhpTGVuZ3RoLCAwLCBNYXRoLlBJICogMiApO1xuXG5cdFx0Ly8gYnVmZmVyc1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0Y29uc3QgdXZzID0gW107XG5cdFx0Y29uc3QgaW5pdE5vcm1hbHMgPSBbXTtcblx0XHRjb25zdCBub3JtYWxzID0gW107XG5cblx0XHQvLyBoZWxwZXIgdmFyaWFibGVzXG5cblx0XHRjb25zdCBpbnZlcnNlU2VnbWVudHMgPSAxLjAgLyBzZWdtZW50cztcblx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IHV2ID0gbmV3IFZlY3RvcjIoKTtcblx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IGN1ck5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0Y29uc3QgcHJldk5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0bGV0IGR4ID0gMDtcblx0XHRsZXQgZHkgPSAwO1xuXG5cdFx0Ly8gcHJlLWNvbXB1dGUgbm9ybWFscyBmb3IgaW5pdGlhbCBcIm1lcmlkaWFuXCJcblxuXHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSAoIHBvaW50cy5sZW5ndGggLSAxICk7IGogKysgKSB7XG5cblx0XHRcdHN3aXRjaCAoIGogKSB7XG5cblx0XHRcdFx0Y2FzZSAwOlx0XHRcdFx0Ly8gc3BlY2lhbCBoYW5kbGluZyBmb3IgMXN0IHZlcnRleCBvbiBwYXRoXG5cblx0XHRcdFx0XHRkeCA9IHBvaW50c1sgaiArIDEgXS54IC0gcG9pbnRzWyBqIF0ueDtcblx0XHRcdFx0XHRkeSA9IHBvaW50c1sgaiArIDEgXS55IC0gcG9pbnRzWyBqIF0ueTtcblxuXHRcdFx0XHRcdG5vcm1hbC54ID0gZHkgKiAxLjA7XG5cdFx0XHRcdFx0bm9ybWFsLnkgPSAtIGR4O1xuXHRcdFx0XHRcdG5vcm1hbC56ID0gZHkgKiAwLjA7XG5cblx0XHRcdFx0XHRwcmV2Tm9ybWFsLmNvcHkoIG5vcm1hbCApO1xuXG5cdFx0XHRcdFx0bm9ybWFsLm5vcm1hbGl6ZSgpO1xuXG5cdFx0XHRcdFx0aW5pdE5vcm1hbHMucHVzaCggbm9ybWFsLngsIG5vcm1hbC55LCBub3JtYWwueiApO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAoIHBvaW50cy5sZW5ndGggLSAxICk6XHQvLyBzcGVjaWFsIGhhbmRsaW5nIGZvciBsYXN0IFZlcnRleCBvbiBwYXRoXG5cblx0XHRcdFx0XHRpbml0Tm9ybWFscy5wdXNoKCBwcmV2Tm9ybWFsLngsIHByZXZOb3JtYWwueSwgcHJldk5vcm1hbC56ICk7XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRkZWZhdWx0Olx0XHRcdC8vIGRlZmF1bHQgaGFuZGxpbmcgZm9yIGFsbCB2ZXJ0aWNlcyBpbiBiZXR3ZWVuXG5cblx0XHRcdFx0XHRkeCA9IHBvaW50c1sgaiArIDEgXS54IC0gcG9pbnRzWyBqIF0ueDtcblx0XHRcdFx0XHRkeSA9IHBvaW50c1sgaiArIDEgXS55IC0gcG9pbnRzWyBqIF0ueTtcblxuXHRcdFx0XHRcdG5vcm1hbC54ID0gZHkgKiAxLjA7XG5cdFx0XHRcdFx0bm9ybWFsLnkgPSAtIGR4O1xuXHRcdFx0XHRcdG5vcm1hbC56ID0gZHkgKiAwLjA7XG5cblx0XHRcdFx0XHRjdXJOb3JtYWwuY29weSggbm9ybWFsICk7XG5cblx0XHRcdFx0XHRub3JtYWwueCArPSBwcmV2Tm9ybWFsLng7XG5cdFx0XHRcdFx0bm9ybWFsLnkgKz0gcHJldk5vcm1hbC55O1xuXHRcdFx0XHRcdG5vcm1hbC56ICs9IHByZXZOb3JtYWwuejtcblxuXHRcdFx0XHRcdG5vcm1hbC5ub3JtYWxpemUoKTtcblxuXHRcdFx0XHRcdGluaXROb3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcblxuXHRcdFx0XHRcdHByZXZOb3JtYWwuY29weSggY3VyTm9ybWFsICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGdlbmVyYXRlIHZlcnRpY2VzLCB1dnMgYW5kIG5vcm1hbHNcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSBzZWdtZW50czsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgcGhpID0gcGhpU3RhcnQgKyBpICogaW52ZXJzZVNlZ21lbnRzICogcGhpTGVuZ3RoO1xuXG5cdFx0XHRjb25zdCBzaW4gPSBNYXRoLnNpbiggcGhpICk7XG5cdFx0XHRjb25zdCBjb3MgPSBNYXRoLmNvcyggcGhpICk7XG5cblx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSAoIHBvaW50cy5sZW5ndGggLSAxICk7IGogKysgKSB7XG5cblx0XHRcdFx0Ly8gdmVydGV4XG5cblx0XHRcdFx0dmVydGV4LnggPSBwb2ludHNbIGogXS54ICogc2luO1xuXHRcdFx0XHR2ZXJ0ZXgueSA9IHBvaW50c1sgaiBdLnk7XG5cdFx0XHRcdHZlcnRleC56ID0gcG9pbnRzWyBqIF0ueCAqIGNvcztcblxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XG5cblx0XHRcdFx0Ly8gdXZcblxuXHRcdFx0XHR1di54ID0gaSAvIHNlZ21lbnRzO1xuXHRcdFx0XHR1di55ID0gaiAvICggcG9pbnRzLmxlbmd0aCAtIDEgKTtcblxuXHRcdFx0XHR1dnMucHVzaCggdXYueCwgdXYueSApO1xuXG5cdFx0XHRcdC8vIG5vcm1hbFxuXG5cdFx0XHRcdGNvbnN0IHggPSBpbml0Tm9ybWFsc1sgMyAqIGogKyAwIF0gKiBzaW47XG5cdFx0XHRcdGNvbnN0IHkgPSBpbml0Tm9ybWFsc1sgMyAqIGogKyAxIF07XG5cdFx0XHRcdGNvbnN0IHogPSBpbml0Tm9ybWFsc1sgMyAqIGogKyAwIF0gKiBjb3M7XG5cblx0XHRcdFx0bm9ybWFscy5wdXNoKCB4LCB5LCB6ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGluZGljZXNcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHNlZ21lbnRzOyBpICsrICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCAoIHBvaW50cy5sZW5ndGggLSAxICk7IGogKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgYmFzZSA9IGogKyBpICogcG9pbnRzLmxlbmd0aDtcblxuXHRcdFx0XHRjb25zdCBhID0gYmFzZTtcblx0XHRcdFx0Y29uc3QgYiA9IGJhc2UgKyBwb2ludHMubGVuZ3RoO1xuXHRcdFx0XHRjb25zdCBjID0gYmFzZSArIHBvaW50cy5sZW5ndGggKyAxO1xuXHRcdFx0XHRjb25zdCBkID0gYmFzZSArIDE7XG5cblx0XHRcdFx0Ly8gZmFjZXNcblxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBjLCBkLCBiICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XG5cblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdHJldHVybiBuZXcgTGF0aGVHZW9tZXRyeSggZGF0YS5wb2ludHMsIGRhdGEuc2VnbWVudHMsIGRhdGEucGhpU3RhcnQsIGRhdGEucGhpTGVuZ3RoICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIENhcHN1bGVHZW9tZXRyeSBleHRlbmRzIExhdGhlR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBsZW5ndGggPSAxLCBjYXBTZWdtZW50cyA9IDQsIHJhZGlhbFNlZ21lbnRzID0gOCApIHtcblxuXHRcdGNvbnN0IHBhdGggPSBuZXcgUGF0aCgpO1xuXHRcdHBhdGguYWJzYXJjKCAwLCAtIGxlbmd0aCAvIDIsIHJhZGl1cywgTWF0aC5QSSAqIDEuNSwgMCApO1xuXHRcdHBhdGguYWJzYXJjKCAwLCBsZW5ndGggLyAyLCByYWRpdXMsIDAsIE1hdGguUEkgKiAwLjUgKTtcblxuXHRcdHN1cGVyKCBwYXRoLmdldFBvaW50cyggY2FwU2VnbWVudHMgKSwgcmFkaWFsU2VnbWVudHMgKTtcblxuXHRcdHRoaXMudHlwZSA9ICdDYXBzdWxlR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0cmFkaXVzOiByYWRpdXMsXG5cdFx0XHRsZW5ndGg6IGxlbmd0aCxcblx0XHRcdGNhcFNlZ21lbnRzOiBjYXBTZWdtZW50cyxcblx0XHRcdHJhZGlhbFNlZ21lbnRzOiByYWRpYWxTZWdtZW50cyxcblx0XHR9O1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IENhcHN1bGVHZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEubGVuZ3RoLCBkYXRhLmNhcFNlZ21lbnRzLCBkYXRhLnJhZGlhbFNlZ21lbnRzICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIENpcmNsZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBzZWdtZW50cyA9IDMyLCB0aGV0YVN0YXJ0ID0gMCwgdGhldGFMZW5ndGggPSBNYXRoLlBJICogMiApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnQ2lyY2xlR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0cmFkaXVzOiByYWRpdXMsXG5cdFx0XHRzZWdtZW50czogc2VnbWVudHMsXG5cdFx0XHR0aGV0YVN0YXJ0OiB0aGV0YVN0YXJ0LFxuXHRcdFx0dGhldGFMZW5ndGg6IHRoZXRhTGVuZ3RoXG5cdFx0fTtcblxuXHRcdHNlZ21lbnRzID0gTWF0aC5tYXgoIDMsIHNlZ21lbnRzICk7XG5cblx0XHQvLyBidWZmZXJzXG5cblx0XHRjb25zdCBpbmRpY2VzID0gW107XG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcblx0XHRjb25zdCBub3JtYWxzID0gW107XG5cdFx0Y29uc3QgdXZzID0gW107XG5cblx0XHQvLyBoZWxwZXIgdmFyaWFibGVzXG5cblx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IHV2ID0gbmV3IFZlY3RvcjIoKTtcblxuXHRcdC8vIGNlbnRlciBwb2ludFxuXG5cdFx0dmVydGljZXMucHVzaCggMCwgMCwgMCApO1xuXHRcdG5vcm1hbHMucHVzaCggMCwgMCwgMSApO1xuXHRcdHV2cy5wdXNoKCAwLjUsIDAuNSApO1xuXG5cdFx0Zm9yICggbGV0IHMgPSAwLCBpID0gMzsgcyA8PSBzZWdtZW50czsgcyArKywgaSArPSAzICkge1xuXG5cdFx0XHRjb25zdCBzZWdtZW50ID0gdGhldGFTdGFydCArIHMgLyBzZWdtZW50cyAqIHRoZXRhTGVuZ3RoO1xuXG5cdFx0XHQvLyB2ZXJ0ZXhcblxuXHRcdFx0dmVydGV4LnggPSByYWRpdXMgKiBNYXRoLmNvcyggc2VnbWVudCApO1xuXHRcdFx0dmVydGV4LnkgPSByYWRpdXMgKiBNYXRoLnNpbiggc2VnbWVudCApO1xuXG5cdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XG5cblx0XHRcdC8vIG5vcm1hbFxuXG5cdFx0XHRub3JtYWxzLnB1c2goIDAsIDAsIDEgKTtcblxuXHRcdFx0Ly8gdXZzXG5cblx0XHRcdHV2LnggPSAoIHZlcnRpY2VzWyBpIF0gLyByYWRpdXMgKyAxICkgLyAyO1xuXHRcdFx0dXYueSA9ICggdmVydGljZXNbIGkgKyAxIF0gLyByYWRpdXMgKyAxICkgLyAyO1xuXG5cdFx0XHR1dnMucHVzaCggdXYueCwgdXYueSApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gaW5kaWNlc1xuXG5cdFx0Zm9yICggbGV0IGkgPSAxOyBpIDw9IHNlZ21lbnRzOyBpICsrICkge1xuXG5cdFx0XHRpbmRpY2VzLnB1c2goIGksIGkgKyAxLCAwICk7XG5cblx0XHR9XG5cblx0XHQvLyBidWlsZCBnZW9tZXRyeVxuXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IENpcmNsZUdlb21ldHJ5KCBkYXRhLnJhZGl1cywgZGF0YS5zZWdtZW50cywgZGF0YS50aGV0YVN0YXJ0LCBkYXRhLnRoZXRhTGVuZ3RoICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIEN5bGluZGVyR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHJhZGl1c1RvcCA9IDEsIHJhZGl1c0JvdHRvbSA9IDEsIGhlaWdodCA9IDEsIHJhZGlhbFNlZ21lbnRzID0gMzIsIGhlaWdodFNlZ21lbnRzID0gMSwgb3BlbkVuZGVkID0gZmFsc2UsIHRoZXRhU3RhcnQgPSAwLCB0aGV0YUxlbmd0aCA9IE1hdGguUEkgKiAyICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdDeWxpbmRlckdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHJhZGl1c1RvcDogcmFkaXVzVG9wLFxuXHRcdFx0cmFkaXVzQm90dG9tOiByYWRpdXNCb3R0b20sXG5cdFx0XHRoZWlnaHQ6IGhlaWdodCxcblx0XHRcdHJhZGlhbFNlZ21lbnRzOiByYWRpYWxTZWdtZW50cyxcblx0XHRcdGhlaWdodFNlZ21lbnRzOiBoZWlnaHRTZWdtZW50cyxcblx0XHRcdG9wZW5FbmRlZDogb3BlbkVuZGVkLFxuXHRcdFx0dGhldGFTdGFydDogdGhldGFTdGFydCxcblx0XHRcdHRoZXRhTGVuZ3RoOiB0aGV0YUxlbmd0aFxuXHRcdH07XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRyYWRpYWxTZWdtZW50cyA9IE1hdGguZmxvb3IoIHJhZGlhbFNlZ21lbnRzICk7XG5cdFx0aGVpZ2h0U2VnbWVudHMgPSBNYXRoLmZsb29yKCBoZWlnaHRTZWdtZW50cyApO1xuXG5cdFx0Ly8gYnVmZmVyc1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xuXHRcdGNvbnN0IHV2cyA9IFtdO1xuXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xuXG5cdFx0bGV0IGluZGV4ID0gMDtcblx0XHRjb25zdCBpbmRleEFycmF5ID0gW107XG5cdFx0Y29uc3QgaGFsZkhlaWdodCA9IGhlaWdodCAvIDI7XG5cdFx0bGV0IGdyb3VwU3RhcnQgPSAwO1xuXG5cdFx0Ly8gZ2VuZXJhdGUgZ2VvbWV0cnlcblxuXHRcdGdlbmVyYXRlVG9yc28oKTtcblxuXHRcdGlmICggb3BlbkVuZGVkID09PSBmYWxzZSApIHtcblxuXHRcdFx0aWYgKCByYWRpdXNUb3AgPiAwICkgZ2VuZXJhdGVDYXAoIHRydWUgKTtcblx0XHRcdGlmICggcmFkaXVzQm90dG9tID4gMCApIGdlbmVyYXRlQ2FwKCBmYWxzZSApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcblxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBub3JtYWxzLCAzICkgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XG5cblx0XHRmdW5jdGlvbiBnZW5lcmF0ZVRvcnNvKCkge1xuXG5cdFx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xuXHRcdFx0Y29uc3QgdmVydGV4ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdFx0bGV0IGdyb3VwQ291bnQgPSAwO1xuXG5cdFx0XHQvLyB0aGlzIHdpbGwgYmUgdXNlZCB0byBjYWxjdWxhdGUgdGhlIG5vcm1hbFxuXHRcdFx0Y29uc3Qgc2xvcGUgPSAoIHJhZGl1c0JvdHRvbSAtIHJhZGl1c1RvcCApIC8gaGVpZ2h0O1xuXG5cdFx0XHQvLyBnZW5lcmF0ZSB2ZXJ0aWNlcywgbm9ybWFscyBhbmQgdXZzXG5cblx0XHRcdGZvciAoIGxldCB5ID0gMDsgeSA8PSBoZWlnaHRTZWdtZW50czsgeSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbmRleFJvdyA9IFtdO1xuXG5cdFx0XHRcdGNvbnN0IHYgPSB5IC8gaGVpZ2h0U2VnbWVudHM7XG5cblx0XHRcdFx0Ly8gY2FsY3VsYXRlIHRoZSByYWRpdXMgb2YgdGhlIGN1cnJlbnQgcm93XG5cblx0XHRcdFx0Y29uc3QgcmFkaXVzID0gdiAqICggcmFkaXVzQm90dG9tIC0gcmFkaXVzVG9wICkgKyByYWRpdXNUb3A7XG5cblx0XHRcdFx0Zm9yICggbGV0IHggPSAwOyB4IDw9IHJhZGlhbFNlZ21lbnRzOyB4ICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgdSA9IHggLyByYWRpYWxTZWdtZW50cztcblxuXHRcdFx0XHRcdGNvbnN0IHRoZXRhID0gdSAqIHRoZXRhTGVuZ3RoICsgdGhldGFTdGFydDtcblxuXHRcdFx0XHRcdGNvbnN0IHNpblRoZXRhID0gTWF0aC5zaW4oIHRoZXRhICk7XG5cdFx0XHRcdFx0Y29uc3QgY29zVGhldGEgPSBNYXRoLmNvcyggdGhldGEgKTtcblxuXHRcdFx0XHRcdC8vIHZlcnRleFxuXG5cdFx0XHRcdFx0dmVydGV4LnggPSByYWRpdXMgKiBzaW5UaGV0YTtcblx0XHRcdFx0XHR2ZXJ0ZXgueSA9IC0gdiAqIGhlaWdodCArIGhhbGZIZWlnaHQ7XG5cdFx0XHRcdFx0dmVydGV4LnogPSByYWRpdXMgKiBjb3NUaGV0YTtcblx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XG5cblx0XHRcdFx0XHQvLyBub3JtYWxcblxuXHRcdFx0XHRcdG5vcm1hbC5zZXQoIHNpblRoZXRhLCBzbG9wZSwgY29zVGhldGEgKS5ub3JtYWxpemUoKTtcblx0XHRcdFx0XHRub3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcblxuXHRcdFx0XHRcdC8vIHV2XG5cblx0XHRcdFx0XHR1dnMucHVzaCggdSwgMSAtIHYgKTtcblxuXHRcdFx0XHRcdC8vIHNhdmUgaW5kZXggb2YgdmVydGV4IGluIHJlc3BlY3RpdmUgcm93XG5cblx0XHRcdFx0XHRpbmRleFJvdy5wdXNoKCBpbmRleCArKyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBub3cgc2F2ZSB2ZXJ0aWNlcyBvZiB0aGUgcm93IGluIG91ciBpbmRleCBhcnJheVxuXG5cdFx0XHRcdGluZGV4QXJyYXkucHVzaCggaW5kZXhSb3cgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBnZW5lcmF0ZSBpbmRpY2VzXG5cblx0XHRcdGZvciAoIGxldCB4ID0gMDsgeCA8IHJhZGlhbFNlZ21lbnRzOyB4ICsrICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCB5ID0gMDsgeSA8IGhlaWdodFNlZ21lbnRzOyB5ICsrICkge1xuXG5cdFx0XHRcdFx0Ly8gd2UgdXNlIHRoZSBpbmRleCBhcnJheSB0byBhY2Nlc3MgdGhlIGNvcnJlY3QgaW5kaWNlc1xuXG5cdFx0XHRcdFx0Y29uc3QgYSA9IGluZGV4QXJyYXlbIHkgXVsgeCBdO1xuXHRcdFx0XHRcdGNvbnN0IGIgPSBpbmRleEFycmF5WyB5ICsgMSBdWyB4IF07XG5cdFx0XHRcdFx0Y29uc3QgYyA9IGluZGV4QXJyYXlbIHkgKyAxIF1bIHggKyAxIF07XG5cdFx0XHRcdFx0Y29uc3QgZCA9IGluZGV4QXJyYXlbIHkgXVsgeCArIDEgXTtcblxuXHRcdFx0XHRcdC8vIGZhY2VzXG5cblx0XHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcblx0XHRcdFx0XHRpbmRpY2VzLnB1c2goIGIsIGMsIGQgKTtcblxuXHRcdFx0XHRcdC8vIHVwZGF0ZSBncm91cCBjb3VudGVyXG5cblx0XHRcdFx0XHRncm91cENvdW50ICs9IDY7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGFkZCBhIGdyb3VwIHRvIHRoZSBnZW9tZXRyeS4gdGhpcyB3aWxsIGVuc3VyZSBtdWx0aSBtYXRlcmlhbCBzdXBwb3J0XG5cblx0XHRcdHNjb3BlLmFkZEdyb3VwKCBncm91cFN0YXJ0LCBncm91cENvdW50LCAwICk7XG5cblx0XHRcdC8vIGNhbGN1bGF0ZSBuZXcgc3RhcnQgdmFsdWUgZm9yIGdyb3Vwc1xuXG5cdFx0XHRncm91cFN0YXJ0ICs9IGdyb3VwQ291bnQ7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBnZW5lcmF0ZUNhcCggdG9wICkge1xuXG5cdFx0XHQvLyBzYXZlIHRoZSBpbmRleCBvZiB0aGUgZmlyc3QgY2VudGVyIHZlcnRleFxuXHRcdFx0Y29uc3QgY2VudGVySW5kZXhTdGFydCA9IGluZGV4O1xuXG5cdFx0XHRjb25zdCB1diA9IG5ldyBWZWN0b3IyKCk7XG5cdFx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHRsZXQgZ3JvdXBDb3VudCA9IDA7XG5cblx0XHRcdGNvbnN0IHJhZGl1cyA9ICggdG9wID09PSB0cnVlICkgPyByYWRpdXNUb3AgOiByYWRpdXNCb3R0b207XG5cdFx0XHRjb25zdCBzaWduID0gKCB0b3AgPT09IHRydWUgKSA/IDEgOiAtIDE7XG5cblx0XHRcdC8vIGZpcnN0IHdlIGdlbmVyYXRlIHRoZSBjZW50ZXIgdmVydGV4IGRhdGEgb2YgdGhlIGNhcC5cblx0XHRcdC8vIGJlY2F1c2UgdGhlIGdlb21ldHJ5IG5lZWRzIG9uZSBzZXQgb2YgdXZzIHBlciBmYWNlLFxuXHRcdFx0Ly8gd2UgbXVzdCBnZW5lcmF0ZSBhIGNlbnRlciB2ZXJ0ZXggcGVyIGZhY2Uvc2VnbWVudFxuXG5cdFx0XHRmb3IgKCBsZXQgeCA9IDE7IHggPD0gcmFkaWFsU2VnbWVudHM7IHggKysgKSB7XG5cblx0XHRcdFx0Ly8gdmVydGV4XG5cblx0XHRcdFx0dmVydGljZXMucHVzaCggMCwgaGFsZkhlaWdodCAqIHNpZ24sIDAgKTtcblxuXHRcdFx0XHQvLyBub3JtYWxcblxuXHRcdFx0XHRub3JtYWxzLnB1c2goIDAsIHNpZ24sIDAgKTtcblxuXHRcdFx0XHQvLyB1dlxuXG5cdFx0XHRcdHV2cy5wdXNoKCAwLjUsIDAuNSApO1xuXG5cdFx0XHRcdC8vIGluY3JlYXNlIGluZGV4XG5cblx0XHRcdFx0aW5kZXggKys7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gc2F2ZSB0aGUgaW5kZXggb2YgdGhlIGxhc3QgY2VudGVyIHZlcnRleFxuXHRcdFx0Y29uc3QgY2VudGVySW5kZXhFbmQgPSBpbmRleDtcblxuXHRcdFx0Ly8gbm93IHdlIGdlbmVyYXRlIHRoZSBzdXJyb3VuZGluZyB2ZXJ0aWNlcywgbm9ybWFscyBhbmQgdXZzXG5cblx0XHRcdGZvciAoIGxldCB4ID0gMDsgeCA8PSByYWRpYWxTZWdtZW50czsgeCArKyApIHtcblxuXHRcdFx0XHRjb25zdCB1ID0geCAvIHJhZGlhbFNlZ21lbnRzO1xuXHRcdFx0XHRjb25zdCB0aGV0YSA9IHUgKiB0aGV0YUxlbmd0aCArIHRoZXRhU3RhcnQ7XG5cblx0XHRcdFx0Y29uc3QgY29zVGhldGEgPSBNYXRoLmNvcyggdGhldGEgKTtcblx0XHRcdFx0Y29uc3Qgc2luVGhldGEgPSBNYXRoLnNpbiggdGhldGEgKTtcblxuXHRcdFx0XHQvLyB2ZXJ0ZXhcblxuXHRcdFx0XHR2ZXJ0ZXgueCA9IHJhZGl1cyAqIHNpblRoZXRhO1xuXHRcdFx0XHR2ZXJ0ZXgueSA9IGhhbGZIZWlnaHQgKiBzaWduO1xuXHRcdFx0XHR2ZXJ0ZXgueiA9IHJhZGl1cyAqIGNvc1RoZXRhO1xuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XG5cblx0XHRcdFx0Ly8gbm9ybWFsXG5cblx0XHRcdFx0bm9ybWFscy5wdXNoKCAwLCBzaWduLCAwICk7XG5cblx0XHRcdFx0Ly8gdXZcblxuXHRcdFx0XHR1di54ID0gKCBjb3NUaGV0YSAqIDAuNSApICsgMC41O1xuXHRcdFx0XHR1di55ID0gKCBzaW5UaGV0YSAqIDAuNSAqIHNpZ24gKSArIDAuNTtcblx0XHRcdFx0dXZzLnB1c2goIHV2LngsIHV2LnkgKTtcblxuXHRcdFx0XHQvLyBpbmNyZWFzZSBpbmRleFxuXG5cdFx0XHRcdGluZGV4ICsrO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGdlbmVyYXRlIGluZGljZXNcblxuXHRcdFx0Zm9yICggbGV0IHggPSAwOyB4IDwgcmFkaWFsU2VnbWVudHM7IHggKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgYyA9IGNlbnRlckluZGV4U3RhcnQgKyB4O1xuXHRcdFx0XHRjb25zdCBpID0gY2VudGVySW5kZXhFbmQgKyB4O1xuXG5cdFx0XHRcdGlmICggdG9wID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0Ly8gZmFjZSB0b3BcblxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggaSwgaSArIDEsIGMgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ly8gZmFjZSBib3R0b21cblxuXHRcdFx0XHRcdGluZGljZXMucHVzaCggaSArIDEsIGksIGMgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Z3JvdXBDb3VudCArPSAzO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGFkZCBhIGdyb3VwIHRvIHRoZSBnZW9tZXRyeS4gdGhpcyB3aWxsIGVuc3VyZSBtdWx0aSBtYXRlcmlhbCBzdXBwb3J0XG5cblx0XHRcdHNjb3BlLmFkZEdyb3VwKCBncm91cFN0YXJ0LCBncm91cENvdW50LCB0b3AgPT09IHRydWUgPyAxIDogMiApO1xuXG5cdFx0XHQvLyBjYWxjdWxhdGUgbmV3IHN0YXJ0IHZhbHVlIGZvciBncm91cHNcblxuXHRcdFx0Z3JvdXBTdGFydCArPSBncm91cENvdW50O1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdHJldHVybiBuZXcgQ3lsaW5kZXJHZW9tZXRyeSggZGF0YS5yYWRpdXNUb3AsIGRhdGEucmFkaXVzQm90dG9tLCBkYXRhLmhlaWdodCwgZGF0YS5yYWRpYWxTZWdtZW50cywgZGF0YS5oZWlnaHRTZWdtZW50cywgZGF0YS5vcGVuRW5kZWQsIGRhdGEudGhldGFTdGFydCwgZGF0YS50aGV0YUxlbmd0aCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBDb25lR2VvbWV0cnkgZXh0ZW5kcyBDeWxpbmRlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgaGVpZ2h0ID0gMSwgcmFkaWFsU2VnbWVudHMgPSAzMiwgaGVpZ2h0U2VnbWVudHMgPSAxLCBvcGVuRW5kZWQgPSBmYWxzZSwgdGhldGFTdGFydCA9IDAsIHRoZXRhTGVuZ3RoID0gTWF0aC5QSSAqIDIgKSB7XG5cblx0XHRzdXBlciggMCwgcmFkaXVzLCBoZWlnaHQsIHJhZGlhbFNlZ21lbnRzLCBoZWlnaHRTZWdtZW50cywgb3BlbkVuZGVkLCB0aGV0YVN0YXJ0LCB0aGV0YUxlbmd0aCApO1xuXG5cdFx0dGhpcy50eXBlID0gJ0NvbmVHZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcblx0XHRcdGhlaWdodDogaGVpZ2h0LFxuXHRcdFx0cmFkaWFsU2VnbWVudHM6IHJhZGlhbFNlZ21lbnRzLFxuXHRcdFx0aGVpZ2h0U2VnbWVudHM6IGhlaWdodFNlZ21lbnRzLFxuXHRcdFx0b3BlbkVuZGVkOiBvcGVuRW5kZWQsXG5cdFx0XHR0aGV0YVN0YXJ0OiB0aGV0YVN0YXJ0LFxuXHRcdFx0dGhldGFMZW5ndGg6IHRoZXRhTGVuZ3RoXG5cdFx0fTtcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xuXG5cdFx0cmV0dXJuIG5ldyBDb25lR2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLmhlaWdodCwgZGF0YS5yYWRpYWxTZWdtZW50cywgZGF0YS5oZWlnaHRTZWdtZW50cywgZGF0YS5vcGVuRW5kZWQsIGRhdGEudGhldGFTdGFydCwgZGF0YS50aGV0YUxlbmd0aCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBQb2x5aGVkcm9uR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHZlcnRpY2VzID0gW10sIGluZGljZXMgPSBbXSwgcmFkaXVzID0gMSwgZGV0YWlsID0gMCApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnUG9seWhlZHJvbkdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHZlcnRpY2VzOiB2ZXJ0aWNlcyxcblx0XHRcdGluZGljZXM6IGluZGljZXMsXG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcblx0XHRcdGRldGFpbDogZGV0YWlsXG5cdFx0fTtcblxuXHRcdC8vIGRlZmF1bHQgYnVmZmVyIGRhdGFcblxuXHRcdGNvbnN0IHZlcnRleEJ1ZmZlciA9IFtdO1xuXHRcdGNvbnN0IHV2QnVmZmVyID0gW107XG5cblx0XHQvLyB0aGUgc3ViZGl2aXNpb24gY3JlYXRlcyB0aGUgdmVydGV4IGJ1ZmZlciBkYXRhXG5cblx0XHRzdWJkaXZpZGUoIGRldGFpbCApO1xuXG5cdFx0Ly8gYWxsIHZlcnRpY2VzIHNob3VsZCBsaWUgb24gYSBjb25jZXB0dWFsIHNwaGVyZSB3aXRoIGEgZ2l2ZW4gcmFkaXVzXG5cblx0XHRhcHBseVJhZGl1cyggcmFkaXVzICk7XG5cblx0XHQvLyBmaW5hbGx5LCBjcmVhdGUgdGhlIHV2IGRhdGFcblxuXHRcdGdlbmVyYXRlVVZzKCk7XG5cblx0XHQvLyBidWlsZCBub24taW5kZXhlZCBnZW9tZXRyeVxuXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0ZXhCdWZmZXIsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRleEJ1ZmZlci5zbGljZSgpLCAzICkgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2QnVmZmVyLCAyICkgKTtcblxuXHRcdGlmICggZGV0YWlsID09PSAwICkge1xuXG5cdFx0XHR0aGlzLmNvbXB1dGVWZXJ0ZXhOb3JtYWxzKCk7IC8vIGZsYXQgbm9ybWFsc1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhpcy5ub3JtYWxpemVOb3JtYWxzKCk7IC8vIHNtb290aCBub3JtYWxzXG5cblx0XHR9XG5cblx0XHQvLyBoZWxwZXIgZnVuY3Rpb25zXG5cblx0XHRmdW5jdGlvbiBzdWJkaXZpZGUoIGRldGFpbCApIHtcblxuXHRcdFx0Y29uc3QgYSA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0XHRjb25zdCBiID0gbmV3IFZlY3RvcjMoKTtcblx0XHRcdGNvbnN0IGMgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHQvLyBpdGVyYXRlIG92ZXIgYWxsIGZhY2VzIGFuZCBhcHBseSBhIHN1YmRpdmlzaW9uIHdpdGggdGhlIGdpdmVuIGRldGFpbCB2YWx1ZVxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBpbmRpY2VzLmxlbmd0aDsgaSArPSAzICkge1xuXG5cdFx0XHRcdC8vIGdldCB0aGUgdmVydGljZXMgb2YgdGhlIGZhY2VcblxuXHRcdFx0XHRnZXRWZXJ0ZXhCeUluZGV4KCBpbmRpY2VzWyBpICsgMCBdLCBhICk7XG5cdFx0XHRcdGdldFZlcnRleEJ5SW5kZXgoIGluZGljZXNbIGkgKyAxIF0sIGIgKTtcblx0XHRcdFx0Z2V0VmVydGV4QnlJbmRleCggaW5kaWNlc1sgaSArIDIgXSwgYyApO1xuXG5cdFx0XHRcdC8vIHBlcmZvcm0gc3ViZGl2aXNpb25cblxuXHRcdFx0XHRzdWJkaXZpZGVGYWNlKCBhLCBiLCBjLCBkZXRhaWwgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gc3ViZGl2aWRlRmFjZSggYSwgYiwgYywgZGV0YWlsICkge1xuXG5cdFx0XHRjb25zdCBjb2xzID0gZGV0YWlsICsgMTtcblxuXHRcdFx0Ly8gd2UgdXNlIHRoaXMgbXVsdGlkaW1lbnNpb25hbCBhcnJheSBhcyBhIGRhdGEgc3RydWN0dXJlIGZvciBjcmVhdGluZyB0aGUgc3ViZGl2aXNpb25cblxuXHRcdFx0Y29uc3QgdiA9IFtdO1xuXG5cdFx0XHQvLyBjb25zdHJ1Y3QgYWxsIG9mIHRoZSB2ZXJ0aWNlcyBmb3IgdGhpcyBzdWJkaXZpc2lvblxuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPD0gY29sczsgaSArKyApIHtcblxuXHRcdFx0XHR2WyBpIF0gPSBbXTtcblxuXHRcdFx0XHRjb25zdCBhaiA9IGEuY2xvbmUoKS5sZXJwKCBjLCBpIC8gY29scyApO1xuXHRcdFx0XHRjb25zdCBiaiA9IGIuY2xvbmUoKS5sZXJwKCBjLCBpIC8gY29scyApO1xuXG5cdFx0XHRcdGNvbnN0IHJvd3MgPSBjb2xzIC0gaTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPD0gcm93czsgaiArKyApIHtcblxuXHRcdFx0XHRcdGlmICggaiA9PT0gMCAmJiBpID09PSBjb2xzICkge1xuXG5cdFx0XHRcdFx0XHR2WyBpIF1bIGogXSA9IGFqO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0dlsgaSBdWyBqIF0gPSBhai5jbG9uZSgpLmxlcnAoIGJqLCBqIC8gcm93cyApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBjb25zdHJ1Y3QgYWxsIG9mIHRoZSBmYWNlc1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjb2xzOyBpICsrICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IDIgKiAoIGNvbHMgLSBpICkgLSAxOyBqICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgayA9IE1hdGguZmxvb3IoIGogLyAyICk7XG5cblx0XHRcdFx0XHRpZiAoIGogJSAyID09PSAwICkge1xuXG5cdFx0XHRcdFx0XHRwdXNoVmVydGV4KCB2WyBpIF1bIGsgKyAxIF0gKTtcblx0XHRcdFx0XHRcdHB1c2hWZXJ0ZXgoIHZbIGkgKyAxIF1bIGsgXSApO1xuXHRcdFx0XHRcdFx0cHVzaFZlcnRleCggdlsgaSBdWyBrIF0gKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHB1c2hWZXJ0ZXgoIHZbIGkgXVsgayArIDEgXSApO1xuXHRcdFx0XHRcdFx0cHVzaFZlcnRleCggdlsgaSArIDEgXVsgayArIDEgXSApO1xuXHRcdFx0XHRcdFx0cHVzaFZlcnRleCggdlsgaSArIDEgXVsgayBdICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBhcHBseVJhZGl1cyggcmFkaXVzICkge1xuXG5cdFx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHQvLyBpdGVyYXRlIG92ZXIgdGhlIGVudGlyZSBidWZmZXIgYW5kIGFwcGx5IHRoZSByYWRpdXMgdG8gZWFjaCB2ZXJ0ZXhcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdmVydGV4QnVmZmVyLmxlbmd0aDsgaSArPSAzICkge1xuXG5cdFx0XHRcdHZlcnRleC54ID0gdmVydGV4QnVmZmVyWyBpICsgMCBdO1xuXHRcdFx0XHR2ZXJ0ZXgueSA9IHZlcnRleEJ1ZmZlclsgaSArIDEgXTtcblx0XHRcdFx0dmVydGV4LnogPSB2ZXJ0ZXhCdWZmZXJbIGkgKyAyIF07XG5cblx0XHRcdFx0dmVydGV4Lm5vcm1hbGl6ZSgpLm11bHRpcGx5U2NhbGFyKCByYWRpdXMgKTtcblxuXHRcdFx0XHR2ZXJ0ZXhCdWZmZXJbIGkgKyAwIF0gPSB2ZXJ0ZXgueDtcblx0XHRcdFx0dmVydGV4QnVmZmVyWyBpICsgMSBdID0gdmVydGV4Lnk7XG5cdFx0XHRcdHZlcnRleEJ1ZmZlclsgaSArIDIgXSA9IHZlcnRleC56O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBnZW5lcmF0ZVVWcygpIHtcblxuXHRcdFx0Y29uc3QgdmVydGV4ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdmVydGV4QnVmZmVyLmxlbmd0aDsgaSArPSAzICkge1xuXG5cdFx0XHRcdHZlcnRleC54ID0gdmVydGV4QnVmZmVyWyBpICsgMCBdO1xuXHRcdFx0XHR2ZXJ0ZXgueSA9IHZlcnRleEJ1ZmZlclsgaSArIDEgXTtcblx0XHRcdFx0dmVydGV4LnogPSB2ZXJ0ZXhCdWZmZXJbIGkgKyAyIF07XG5cblx0XHRcdFx0Y29uc3QgdSA9IGF6aW11dGgoIHZlcnRleCApIC8gMiAvIE1hdGguUEkgKyAwLjU7XG5cdFx0XHRcdGNvbnN0IHYgPSBpbmNsaW5hdGlvbiggdmVydGV4ICkgLyBNYXRoLlBJICsgMC41O1xuXHRcdFx0XHR1dkJ1ZmZlci5wdXNoKCB1LCAxIC0gdiApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvcnJlY3RVVnMoKTtcblxuXHRcdFx0Y29ycmVjdFNlYW0oKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGNvcnJlY3RTZWFtKCkge1xuXG5cdFx0XHQvLyBoYW5kbGUgY2FzZSB3aGVuIGZhY2Ugc3RyYWRkbGVzIHRoZSBzZWFtLCBzZWUgIzMyNjlcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdXZCdWZmZXIubGVuZ3RoOyBpICs9IDYgKSB7XG5cblx0XHRcdFx0Ly8gdXYgZGF0YSBvZiBhIHNpbmdsZSBmYWNlXG5cblx0XHRcdFx0Y29uc3QgeDAgPSB1dkJ1ZmZlclsgaSArIDAgXTtcblx0XHRcdFx0Y29uc3QgeDEgPSB1dkJ1ZmZlclsgaSArIDIgXTtcblx0XHRcdFx0Y29uc3QgeDIgPSB1dkJ1ZmZlclsgaSArIDQgXTtcblxuXHRcdFx0XHRjb25zdCBtYXggPSBNYXRoLm1heCggeDAsIHgxLCB4MiApO1xuXHRcdFx0XHRjb25zdCBtaW4gPSBNYXRoLm1pbiggeDAsIHgxLCB4MiApO1xuXG5cdFx0XHRcdC8vIDAuOSBpcyBzb21ld2hhdCBhcmJpdHJhcnlcblxuXHRcdFx0XHRpZiAoIG1heCA+IDAuOSAmJiBtaW4gPCAwLjEgKSB7XG5cblx0XHRcdFx0XHRpZiAoIHgwIDwgMC4yICkgdXZCdWZmZXJbIGkgKyAwIF0gKz0gMTtcblx0XHRcdFx0XHRpZiAoIHgxIDwgMC4yICkgdXZCdWZmZXJbIGkgKyAyIF0gKz0gMTtcblx0XHRcdFx0XHRpZiAoIHgyIDwgMC4yICkgdXZCdWZmZXJbIGkgKyA0IF0gKz0gMTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHB1c2hWZXJ0ZXgoIHZlcnRleCApIHtcblxuXHRcdFx0dmVydGV4QnVmZmVyLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdldFZlcnRleEJ5SW5kZXgoIGluZGV4LCB2ZXJ0ZXggKSB7XG5cblx0XHRcdGNvbnN0IHN0cmlkZSA9IGluZGV4ICogMztcblxuXHRcdFx0dmVydGV4LnggPSB2ZXJ0aWNlc1sgc3RyaWRlICsgMCBdO1xuXHRcdFx0dmVydGV4LnkgPSB2ZXJ0aWNlc1sgc3RyaWRlICsgMSBdO1xuXHRcdFx0dmVydGV4LnogPSB2ZXJ0aWNlc1sgc3RyaWRlICsgMiBdO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gY29ycmVjdFVWcygpIHtcblxuXHRcdFx0Y29uc3QgYSA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0XHRjb25zdCBiID0gbmV3IFZlY3RvcjMoKTtcblx0XHRcdGNvbnN0IGMgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHRjb25zdCBjZW50cm9pZCA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRcdGNvbnN0IHV2QSA9IG5ldyBWZWN0b3IyKCk7XG5cdFx0XHRjb25zdCB1dkIgPSBuZXcgVmVjdG9yMigpO1xuXHRcdFx0Y29uc3QgdXZDID0gbmV3IFZlY3RvcjIoKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBqID0gMDsgaSA8IHZlcnRleEJ1ZmZlci5sZW5ndGg7IGkgKz0gOSwgaiArPSA2ICkge1xuXG5cdFx0XHRcdGEuc2V0KCB2ZXJ0ZXhCdWZmZXJbIGkgKyAwIF0sIHZlcnRleEJ1ZmZlclsgaSArIDEgXSwgdmVydGV4QnVmZmVyWyBpICsgMiBdICk7XG5cdFx0XHRcdGIuc2V0KCB2ZXJ0ZXhCdWZmZXJbIGkgKyAzIF0sIHZlcnRleEJ1ZmZlclsgaSArIDQgXSwgdmVydGV4QnVmZmVyWyBpICsgNSBdICk7XG5cdFx0XHRcdGMuc2V0KCB2ZXJ0ZXhCdWZmZXJbIGkgKyA2IF0sIHZlcnRleEJ1ZmZlclsgaSArIDcgXSwgdmVydGV4QnVmZmVyWyBpICsgOCBdICk7XG5cblx0XHRcdFx0dXZBLnNldCggdXZCdWZmZXJbIGogKyAwIF0sIHV2QnVmZmVyWyBqICsgMSBdICk7XG5cdFx0XHRcdHV2Qi5zZXQoIHV2QnVmZmVyWyBqICsgMiBdLCB1dkJ1ZmZlclsgaiArIDMgXSApO1xuXHRcdFx0XHR1dkMuc2V0KCB1dkJ1ZmZlclsgaiArIDQgXSwgdXZCdWZmZXJbIGogKyA1IF0gKTtcblxuXHRcdFx0XHRjZW50cm9pZC5jb3B5KCBhICkuYWRkKCBiICkuYWRkKCBjICkuZGl2aWRlU2NhbGFyKCAzICk7XG5cblx0XHRcdFx0Y29uc3QgYXppID0gYXppbXV0aCggY2VudHJvaWQgKTtcblxuXHRcdFx0XHRjb3JyZWN0VVYoIHV2QSwgaiArIDAsIGEsIGF6aSApO1xuXHRcdFx0XHRjb3JyZWN0VVYoIHV2QiwgaiArIDIsIGIsIGF6aSApO1xuXHRcdFx0XHRjb3JyZWN0VVYoIHV2QywgaiArIDQsIGMsIGF6aSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBjb3JyZWN0VVYoIHV2LCBzdHJpZGUsIHZlY3RvciwgYXppbXV0aCApIHtcblxuXHRcdFx0aWYgKCAoIGF6aW11dGggPCAwICkgJiYgKCB1di54ID09PSAxICkgKSB7XG5cblx0XHRcdFx0dXZCdWZmZXJbIHN0cmlkZSBdID0gdXYueCAtIDE7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCAoIHZlY3Rvci54ID09PSAwICkgJiYgKCB2ZWN0b3IueiA9PT0gMCApICkge1xuXG5cdFx0XHRcdHV2QnVmZmVyWyBzdHJpZGUgXSA9IGF6aW11dGggLyAyIC8gTWF0aC5QSSArIDAuNTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gQW5nbGUgYXJvdW5kIHRoZSBZIGF4aXMsIGNvdW50ZXItY2xvY2t3aXNlIHdoZW4gbG9va2luZyBmcm9tIGFib3ZlLlxuXG5cdFx0ZnVuY3Rpb24gYXppbXV0aCggdmVjdG9yICkge1xuXG5cdFx0XHRyZXR1cm4gTWF0aC5hdGFuMiggdmVjdG9yLnosIC0gdmVjdG9yLnggKTtcblxuXHRcdH1cblxuXG5cdFx0Ly8gQW5nbGUgYWJvdmUgdGhlIFhaIHBsYW5lLlxuXG5cdFx0ZnVuY3Rpb24gaW5jbGluYXRpb24oIHZlY3RvciApIHtcblxuXHRcdFx0cmV0dXJuIE1hdGguYXRhbjIoIC0gdmVjdG9yLnksIE1hdGguc3FydCggKCB2ZWN0b3IueCAqIHZlY3Rvci54ICkgKyAoIHZlY3Rvci56ICogdmVjdG9yLnogKSApICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0gT2JqZWN0LmFzc2lnbigge30sIHNvdXJjZS5wYXJhbWV0ZXJzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xuXG5cdFx0cmV0dXJuIG5ldyBQb2x5aGVkcm9uR2VvbWV0cnkoIGRhdGEudmVydGljZXMsIGRhdGEuaW5kaWNlcywgZGF0YS5yYWRpdXMsIGRhdGEuZGV0YWlscyApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBEb2RlY2FoZWRyb25HZW9tZXRyeSBleHRlbmRzIFBvbHloZWRyb25HZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIGRldGFpbCA9IDAgKSB7XG5cblx0XHRjb25zdCB0ID0gKCAxICsgTWF0aC5zcXJ0KCA1ICkgKSAvIDI7XG5cdFx0Y29uc3QgciA9IDEgLyB0O1xuXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXG5cblx0XHRcdC8vICjCsTEsIMKxMSwgwrExKVxuXHRcdFx0LSAxLCAtIDEsIC0gMSxcdC0gMSwgLSAxLCAxLFxuXHRcdFx0LSAxLCAxLCAtIDEsIC0gMSwgMSwgMSxcblx0XHRcdDEsIC0gMSwgLSAxLCAxLCAtIDEsIDEsXG5cdFx0XHQxLCAxLCAtIDEsIDEsIDEsIDEsXG5cblx0XHRcdC8vICgwLCDCsTEvz4YsIMKxz4YpXG5cdFx0XHQwLCAtIHIsIC0gdCwgMCwgLSByLCB0LFxuXHRcdFx0MCwgciwgLSB0LCAwLCByLCB0LFxuXG5cdFx0XHQvLyAowrExL8+GLCDCsc+GLCAwKVxuXHRcdFx0LSByLCAtIHQsIDAsIC0gciwgdCwgMCxcblx0XHRcdHIsIC0gdCwgMCwgciwgdCwgMCxcblxuXHRcdFx0Ly8gKMKxz4YsIDAsIMKxMS/Philcblx0XHRcdC0gdCwgMCwgLSByLCB0LCAwLCAtIHIsXG5cdFx0XHQtIHQsIDAsIHIsIHQsIDAsIHJcblx0XHRdO1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtcblx0XHRcdDMsIDExLCA3LCBcdDMsIDcsIDE1LCBcdDMsIDE1LCAxMyxcblx0XHRcdDcsIDE5LCAxNywgXHQ3LCAxNywgNiwgXHQ3LCA2LCAxNSxcblx0XHRcdDE3LCA0LCA4LCBcdDE3LCA4LCAxMCwgXHQxNywgMTAsIDYsXG5cdFx0XHQ4LCAwLCAxNiwgXHQ4LCAxNiwgMiwgXHQ4LCAyLCAxMCxcblx0XHRcdDAsIDEyLCAxLCBcdDAsIDEsIDE4LCBcdDAsIDE4LCAxNixcblx0XHRcdDYsIDEwLCAyLCBcdDYsIDIsIDEzLCBcdDYsIDEzLCAxNSxcblx0XHRcdDIsIDE2LCAxOCwgXHQyLCAxOCwgMywgXHQyLCAzLCAxMyxcblx0XHRcdDE4LCAxLCA5LCBcdDE4LCA5LCAxMSwgXHQxOCwgMTEsIDMsXG5cdFx0XHQ0LCAxNCwgMTIsIFx0NCwgMTIsIDAsIFx0NCwgMCwgOCxcblx0XHRcdDExLCA5LCA1LCBcdDExLCA1LCAxOSwgXHQxMSwgMTksIDcsXG5cdFx0XHQxOSwgNSwgMTQsIFx0MTksIDE0LCA0LCBcdDE5LCA0LCAxNyxcblx0XHRcdDEsIDEyLCAxNCwgXHQxLCAxNCwgNSwgXHQxLCA1LCA5XG5cdFx0XTtcblxuXHRcdHN1cGVyKCB2ZXJ0aWNlcywgaW5kaWNlcywgcmFkaXVzLCBkZXRhaWwgKTtcblxuXHRcdHRoaXMudHlwZSA9ICdEb2RlY2FoZWRyb25HZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcblx0XHRcdGRldGFpbDogZGV0YWlsXG5cdFx0fTtcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xuXG5cdFx0cmV0dXJuIG5ldyBEb2RlY2FoZWRyb25HZW9tZXRyeSggZGF0YS5yYWRpdXMsIGRhdGEuZGV0YWlsICk7XG5cblx0fVxuXG59XG5cbmNvbnN0IF92MCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF92MSQxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX25vcm1hbCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF90cmlhbmdsZSA9IC8qQF9fUFVSRV9fKi8gbmV3IFRyaWFuZ2xlKCk7XG5cbmNsYXNzIEVkZ2VzR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIGdlb21ldHJ5ID0gbnVsbCwgdGhyZXNob2xkQW5nbGUgPSAxICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdFZGdlc0dlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdGdlb21ldHJ5OiBnZW9tZXRyeSxcblx0XHRcdHRocmVzaG9sZEFuZ2xlOiB0aHJlc2hvbGRBbmdsZVxuXHRcdH07XG5cblx0XHRpZiAoIGdlb21ldHJ5ICE9PSBudWxsICkge1xuXG5cdFx0XHRjb25zdCBwcmVjaXNpb25Qb2ludHMgPSA0O1xuXHRcdFx0Y29uc3QgcHJlY2lzaW9uID0gTWF0aC5wb3coIDEwLCBwcmVjaXNpb25Qb2ludHMgKTtcblx0XHRcdGNvbnN0IHRocmVzaG9sZERvdCA9IE1hdGguY29zKCBERUcyUkFEICogdGhyZXNob2xkQW5nbGUgKTtcblxuXHRcdFx0Y29uc3QgaW5kZXhBdHRyID0gZ2VvbWV0cnkuZ2V0SW5kZXgoKTtcblx0XHRcdGNvbnN0IHBvc2l0aW9uQXR0ciA9IGdlb21ldHJ5LmdldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJyApO1xuXHRcdFx0Y29uc3QgaW5kZXhDb3VudCA9IGluZGV4QXR0ciA/IGluZGV4QXR0ci5jb3VudCA6IHBvc2l0aW9uQXR0ci5jb3VudDtcblxuXHRcdFx0Y29uc3QgaW5kZXhBcnIgPSBbIDAsIDAsIDAgXTtcblx0XHRcdGNvbnN0IHZlcnRLZXlzID0gWyAnYScsICdiJywgJ2MnIF07XG5cdFx0XHRjb25zdCBoYXNoZXMgPSBuZXcgQXJyYXkoIDMgKTtcblxuXHRcdFx0Y29uc3QgZWRnZURhdGEgPSB7fTtcblx0XHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBpbmRleENvdW50OyBpICs9IDMgKSB7XG5cblx0XHRcdFx0aWYgKCBpbmRleEF0dHIgKSB7XG5cblx0XHRcdFx0XHRpbmRleEFyclsgMCBdID0gaW5kZXhBdHRyLmdldFgoIGkgKTtcblx0XHRcdFx0XHRpbmRleEFyclsgMSBdID0gaW5kZXhBdHRyLmdldFgoIGkgKyAxICk7XG5cdFx0XHRcdFx0aW5kZXhBcnJbIDIgXSA9IGluZGV4QXR0ci5nZXRYKCBpICsgMiApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRpbmRleEFyclsgMCBdID0gaTtcblx0XHRcdFx0XHRpbmRleEFyclsgMSBdID0gaSArIDE7XG5cdFx0XHRcdFx0aW5kZXhBcnJbIDIgXSA9IGkgKyAyO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRjb25zdCB7IGEsIGIsIGMgfSA9IF90cmlhbmdsZTtcblx0XHRcdFx0YS5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHIsIGluZGV4QXJyWyAwIF0gKTtcblx0XHRcdFx0Yi5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHIsIGluZGV4QXJyWyAxIF0gKTtcblx0XHRcdFx0Yy5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbkF0dHIsIGluZGV4QXJyWyAyIF0gKTtcblx0XHRcdFx0X3RyaWFuZ2xlLmdldE5vcm1hbCggX25vcm1hbCApO1xuXG5cdFx0XHRcdC8vIGNyZWF0ZSBoYXNoZXMgZm9yIHRoZSBlZGdlIGZyb20gdGhlIHZlcnRpY2VzXG5cdFx0XHRcdGhhc2hlc1sgMCBdID0gYCR7IE1hdGgucm91bmQoIGEueCAqIHByZWNpc2lvbiApIH0sJHsgTWF0aC5yb3VuZCggYS55ICogcHJlY2lzaW9uICkgfSwkeyBNYXRoLnJvdW5kKCBhLnogKiBwcmVjaXNpb24gKSB9YDtcblx0XHRcdFx0aGFzaGVzWyAxIF0gPSBgJHsgTWF0aC5yb3VuZCggYi54ICogcHJlY2lzaW9uICkgfSwkeyBNYXRoLnJvdW5kKCBiLnkgKiBwcmVjaXNpb24gKSB9LCR7IE1hdGgucm91bmQoIGIueiAqIHByZWNpc2lvbiApIH1gO1xuXHRcdFx0XHRoYXNoZXNbIDIgXSA9IGAkeyBNYXRoLnJvdW5kKCBjLnggKiBwcmVjaXNpb24gKSB9LCR7IE1hdGgucm91bmQoIGMueSAqIHByZWNpc2lvbiApIH0sJHsgTWF0aC5yb3VuZCggYy56ICogcHJlY2lzaW9uICkgfWA7XG5cblx0XHRcdFx0Ly8gc2tpcCBkZWdlbmVyYXRlIHRyaWFuZ2xlc1xuXHRcdFx0XHRpZiAoIGhhc2hlc1sgMCBdID09PSBoYXNoZXNbIDEgXSB8fCBoYXNoZXNbIDEgXSA9PT0gaGFzaGVzWyAyIF0gfHwgaGFzaGVzWyAyIF0gPT09IGhhc2hlc1sgMCBdICkge1xuXG5cdFx0XHRcdFx0Y29udGludWU7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIGl0ZXJhdGUgb3ZlciBldmVyeSBlZGdlXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IDM7IGogKysgKSB7XG5cblx0XHRcdFx0XHQvLyBnZXQgdGhlIGZpcnN0IGFuZCBuZXh0IHZlcnRleCBtYWtpbmcgdXAgdGhlIGVkZ2Vcblx0XHRcdFx0XHRjb25zdCBqTmV4dCA9ICggaiArIDEgKSAlIDM7XG5cdFx0XHRcdFx0Y29uc3QgdmVjSGFzaDAgPSBoYXNoZXNbIGogXTtcblx0XHRcdFx0XHRjb25zdCB2ZWNIYXNoMSA9IGhhc2hlc1sgak5leHQgXTtcblx0XHRcdFx0XHRjb25zdCB2MCA9IF90cmlhbmdsZVsgdmVydEtleXNbIGogXSBdO1xuXHRcdFx0XHRcdGNvbnN0IHYxID0gX3RyaWFuZ2xlWyB2ZXJ0S2V5c1sgak5leHQgXSBdO1xuXG5cdFx0XHRcdFx0Y29uc3QgaGFzaCA9IGAkeyB2ZWNIYXNoMCB9XyR7IHZlY0hhc2gxIH1gO1xuXHRcdFx0XHRcdGNvbnN0IHJldmVyc2VIYXNoID0gYCR7IHZlY0hhc2gxIH1fJHsgdmVjSGFzaDAgfWA7XG5cblx0XHRcdFx0XHRpZiAoIHJldmVyc2VIYXNoIGluIGVkZ2VEYXRhICYmIGVkZ2VEYXRhWyByZXZlcnNlSGFzaCBdICkge1xuXG5cdFx0XHRcdFx0XHQvLyBpZiB3ZSBmb3VuZCBhIHNpYmxpbmcgZWRnZSBhZGQgaXQgaW50byB0aGUgdmVydGV4IGFycmF5IGlmXG5cdFx0XHRcdFx0XHQvLyBpdCBtZWV0cyB0aGUgYW5nbGUgdGhyZXNob2xkIGFuZCBkZWxldGUgdGhlIGVkZ2UgZnJvbSB0aGUgbWFwLlxuXHRcdFx0XHRcdFx0aWYgKCBfbm9ybWFsLmRvdCggZWRnZURhdGFbIHJldmVyc2VIYXNoIF0ubm9ybWFsICkgPD0gdGhyZXNob2xkRG90ICkge1xuXG5cdFx0XHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIHYwLngsIHYwLnksIHYwLnogKTtcblx0XHRcdFx0XHRcdFx0dmVydGljZXMucHVzaCggdjEueCwgdjEueSwgdjEueiApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdGVkZ2VEYXRhWyByZXZlcnNlSGFzaCBdID0gbnVsbDtcblxuXHRcdFx0XHRcdH0gZWxzZSBpZiAoICEgKCBoYXNoIGluIGVkZ2VEYXRhICkgKSB7XG5cblx0XHRcdFx0XHRcdC8vIGlmIHdlJ3ZlIGFscmVhZHkgZ290IGFuIGVkZ2UgaGVyZSB0aGVuIHNraXAgYWRkaW5nIGEgbmV3IG9uZVxuXHRcdFx0XHRcdFx0ZWRnZURhdGFbIGhhc2ggXSA9IHtcblxuXHRcdFx0XHRcdFx0XHRpbmRleDA6IGluZGV4QXJyWyBqIF0sXG5cdFx0XHRcdFx0XHRcdGluZGV4MTogaW5kZXhBcnJbIGpOZXh0IF0sXG5cdFx0XHRcdFx0XHRcdG5vcm1hbDogX25vcm1hbC5jbG9uZSgpLFxuXG5cdFx0XHRcdFx0XHR9O1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBpdGVyYXRlIG92ZXIgYWxsIHJlbWFpbmluZywgdW5tYXRjaGVkIGVkZ2VzIGFuZCBhZGQgdGhlbSB0byB0aGUgdmVydGV4IGFycmF5XG5cdFx0XHRmb3IgKCBjb25zdCBrZXkgaW4gZWRnZURhdGEgKSB7XG5cblx0XHRcdFx0aWYgKCBlZGdlRGF0YVsga2V5IF0gKSB7XG5cblx0XHRcdFx0XHRjb25zdCB7IGluZGV4MCwgaW5kZXgxIH0gPSBlZGdlRGF0YVsga2V5IF07XG5cdFx0XHRcdFx0X3YwLmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uQXR0ciwgaW5kZXgwICk7XG5cdFx0XHRcdFx0X3YxJDEuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25BdHRyLCBpbmRleDEgKTtcblxuXHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIF92MC54LCBfdjAueSwgX3YwLnogKTtcblx0XHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCBfdjEkMS54LCBfdjEkMS55LCBfdjEkMS56ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIFNoYXBlIGV4dGVuZHMgUGF0aCB7XG5cblx0Y29uc3RydWN0b3IoIHBvaW50cyApIHtcblxuXHRcdHN1cGVyKCBwb2ludHMgKTtcblxuXHRcdHRoaXMudXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0dGhpcy50eXBlID0gJ1NoYXBlJztcblxuXHRcdHRoaXMuaG9sZXMgPSBbXTtcblxuXHR9XG5cblx0Z2V0UG9pbnRzSG9sZXMoIGRpdmlzaW9ucyApIHtcblxuXHRcdGNvbnN0IGhvbGVzUHRzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmhvbGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGhvbGVzUHRzWyBpIF0gPSB0aGlzLmhvbGVzWyBpIF0uZ2V0UG9pbnRzKCBkaXZpc2lvbnMgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBob2xlc1B0cztcblxuXHR9XG5cblx0Ly8gZ2V0IHBvaW50cyBvZiBzaGFwZSBhbmQgaG9sZXMgKGtleXBvaW50cyBiYXNlZCBvbiBzZWdtZW50cyBwYXJhbWV0ZXIpXG5cblx0ZXh0cmFjdFBvaW50cyggZGl2aXNpb25zICkge1xuXG5cdFx0cmV0dXJuIHtcblxuXHRcdFx0c2hhcGU6IHRoaXMuZ2V0UG9pbnRzKCBkaXZpc2lvbnMgKSxcblx0XHRcdGhvbGVzOiB0aGlzLmdldFBvaW50c0hvbGVzKCBkaXZpc2lvbnMgKVxuXG5cdFx0fTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLmhvbGVzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzb3VyY2UuaG9sZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgaG9sZSA9IHNvdXJjZS5ob2xlc1sgaSBdO1xuXG5cdFx0XHR0aGlzLmhvbGVzLnB1c2goIGhvbGUuY2xvbmUoKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcblxuXHRcdGRhdGEudXVpZCA9IHRoaXMudXVpZDtcblx0XHRkYXRhLmhvbGVzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSB0aGlzLmhvbGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGhvbGUgPSB0aGlzLmhvbGVzWyBpIF07XG5cdFx0XHRkYXRhLmhvbGVzLnB1c2goIGhvbGUudG9KU09OKCkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxuXHRmcm9tSlNPTigganNvbiApIHtcblxuXHRcdHN1cGVyLmZyb21KU09OKCBqc29uICk7XG5cblx0XHR0aGlzLnV1aWQgPSBqc29uLnV1aWQ7XG5cdFx0dGhpcy5ob2xlcyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0ganNvbi5ob2xlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBob2xlID0ganNvbi5ob2xlc1sgaSBdO1xuXHRcdFx0dGhpcy5ob2xlcy5wdXNoKCBuZXcgUGF0aCgpLmZyb21KU09OKCBob2xlICkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG4vKipcbiAqIFBvcnQgZnJvbSBodHRwczovL2dpdGh1Yi5jb20vbWFwYm94L2VhcmN1dCAodjIuMi40KVxuICovXG5cbmNvbnN0IEVhcmN1dCA9IHtcblxuXHR0cmlhbmd1bGF0ZTogZnVuY3Rpb24gKCBkYXRhLCBob2xlSW5kaWNlcywgZGltID0gMiApIHtcblxuXHRcdGNvbnN0IGhhc0hvbGVzID0gaG9sZUluZGljZXMgJiYgaG9sZUluZGljZXMubGVuZ3RoO1xuXHRcdGNvbnN0IG91dGVyTGVuID0gaGFzSG9sZXMgPyBob2xlSW5kaWNlc1sgMCBdICogZGltIDogZGF0YS5sZW5ndGg7XG5cdFx0bGV0IG91dGVyTm9kZSA9IGxpbmtlZExpc3QoIGRhdGEsIDAsIG91dGVyTGVuLCBkaW0sIHRydWUgKTtcblx0XHRjb25zdCB0cmlhbmdsZXMgPSBbXTtcblxuXHRcdGlmICggISBvdXRlck5vZGUgfHwgb3V0ZXJOb2RlLm5leHQgPT09IG91dGVyTm9kZS5wcmV2ICkgcmV0dXJuIHRyaWFuZ2xlcztcblxuXHRcdGxldCBtaW5YLCBtaW5ZLCBtYXhYLCBtYXhZLCB4LCB5LCBpbnZTaXplO1xuXG5cdFx0aWYgKCBoYXNIb2xlcyApIG91dGVyTm9kZSA9IGVsaW1pbmF0ZUhvbGVzKCBkYXRhLCBob2xlSW5kaWNlcywgb3V0ZXJOb2RlLCBkaW0gKTtcblxuXHRcdC8vIGlmIHRoZSBzaGFwZSBpcyBub3QgdG9vIHNpbXBsZSwgd2UnbGwgdXNlIHotb3JkZXIgY3VydmUgaGFzaCBsYXRlcjsgY2FsY3VsYXRlIHBvbHlnb24gYmJveFxuXHRcdGlmICggZGF0YS5sZW5ndGggPiA4MCAqIGRpbSApIHtcblxuXHRcdFx0bWluWCA9IG1heFggPSBkYXRhWyAwIF07XG5cdFx0XHRtaW5ZID0gbWF4WSA9IGRhdGFbIDEgXTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSBkaW07IGkgPCBvdXRlckxlbjsgaSArPSBkaW0gKSB7XG5cblx0XHRcdFx0eCA9IGRhdGFbIGkgXTtcblx0XHRcdFx0eSA9IGRhdGFbIGkgKyAxIF07XG5cdFx0XHRcdGlmICggeCA8IG1pblggKSBtaW5YID0geDtcblx0XHRcdFx0aWYgKCB5IDwgbWluWSApIG1pblkgPSB5O1xuXHRcdFx0XHRpZiAoIHggPiBtYXhYICkgbWF4WCA9IHg7XG5cdFx0XHRcdGlmICggeSA+IG1heFkgKSBtYXhZID0geTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBtaW5YLCBtaW5ZIGFuZCBpbnZTaXplIGFyZSBsYXRlciB1c2VkIHRvIHRyYW5zZm9ybSBjb29yZHMgaW50byBpbnRlZ2VycyBmb3Igei1vcmRlciBjYWxjdWxhdGlvblxuXHRcdFx0aW52U2l6ZSA9IE1hdGgubWF4KCBtYXhYIC0gbWluWCwgbWF4WSAtIG1pblkgKTtcblx0XHRcdGludlNpemUgPSBpbnZTaXplICE9PSAwID8gMzI3NjcgLyBpbnZTaXplIDogMDtcblxuXHRcdH1cblxuXHRcdGVhcmN1dExpbmtlZCggb3V0ZXJOb2RlLCB0cmlhbmdsZXMsIGRpbSwgbWluWCwgbWluWSwgaW52U2l6ZSwgMCApO1xuXG5cdFx0cmV0dXJuIHRyaWFuZ2xlcztcblxuXHR9XG5cbn07XG5cbi8vIGNyZWF0ZSBhIGNpcmN1bGFyIGRvdWJseSBsaW5rZWQgbGlzdCBmcm9tIHBvbHlnb24gcG9pbnRzIGluIHRoZSBzcGVjaWZpZWQgd2luZGluZyBvcmRlclxuZnVuY3Rpb24gbGlua2VkTGlzdCggZGF0YSwgc3RhcnQsIGVuZCwgZGltLCBjbG9ja3dpc2UgKSB7XG5cblx0bGV0IGksIGxhc3Q7XG5cblx0aWYgKCBjbG9ja3dpc2UgPT09ICggc2lnbmVkQXJlYSggZGF0YSwgc3RhcnQsIGVuZCwgZGltICkgPiAwICkgKSB7XG5cblx0XHRmb3IgKCBpID0gc3RhcnQ7IGkgPCBlbmQ7IGkgKz0gZGltICkgbGFzdCA9IGluc2VydE5vZGUoIGksIGRhdGFbIGkgXSwgZGF0YVsgaSArIDEgXSwgbGFzdCApO1xuXG5cdH0gZWxzZSB7XG5cblx0XHRmb3IgKCBpID0gZW5kIC0gZGltOyBpID49IHN0YXJ0OyBpIC09IGRpbSApIGxhc3QgPSBpbnNlcnROb2RlKCBpLCBkYXRhWyBpIF0sIGRhdGFbIGkgKyAxIF0sIGxhc3QgKTtcblxuXHR9XG5cblx0aWYgKCBsYXN0ICYmIGVxdWFscyggbGFzdCwgbGFzdC5uZXh0ICkgKSB7XG5cblx0XHRyZW1vdmVOb2RlKCBsYXN0ICk7XG5cdFx0bGFzdCA9IGxhc3QubmV4dDtcblxuXHR9XG5cblx0cmV0dXJuIGxhc3Q7XG5cbn1cblxuLy8gZWxpbWluYXRlIGNvbGluZWFyIG9yIGR1cGxpY2F0ZSBwb2ludHNcbmZ1bmN0aW9uIGZpbHRlclBvaW50cyggc3RhcnQsIGVuZCApIHtcblxuXHRpZiAoICEgc3RhcnQgKSByZXR1cm4gc3RhcnQ7XG5cdGlmICggISBlbmQgKSBlbmQgPSBzdGFydDtcblxuXHRsZXQgcCA9IHN0YXJ0LFxuXHRcdGFnYWluO1xuXHRkbyB7XG5cblx0XHRhZ2FpbiA9IGZhbHNlO1xuXG5cdFx0aWYgKCAhIHAuc3RlaW5lciAmJiAoIGVxdWFscyggcCwgcC5uZXh0ICkgfHwgYXJlYSggcC5wcmV2LCBwLCBwLm5leHQgKSA9PT0gMCApICkge1xuXG5cdFx0XHRyZW1vdmVOb2RlKCBwICk7XG5cdFx0XHRwID0gZW5kID0gcC5wcmV2O1xuXHRcdFx0aWYgKCBwID09PSBwLm5leHQgKSBicmVhaztcblx0XHRcdGFnYWluID0gdHJ1ZTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHAgPSBwLm5leHQ7XG5cblx0XHR9XG5cblx0fSB3aGlsZSAoIGFnYWluIHx8IHAgIT09IGVuZCApO1xuXG5cdHJldHVybiBlbmQ7XG5cbn1cblxuLy8gbWFpbiBlYXIgc2xpY2luZyBsb29wIHdoaWNoIHRyaWFuZ3VsYXRlcyBhIHBvbHlnb24gKGdpdmVuIGFzIGEgbGlua2VkIGxpc3QpXG5mdW5jdGlvbiBlYXJjdXRMaW5rZWQoIGVhciwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUsIHBhc3MgKSB7XG5cblx0aWYgKCAhIGVhciApIHJldHVybjtcblxuXHQvLyBpbnRlcmxpbmsgcG9seWdvbiBub2RlcyBpbiB6LW9yZGVyXG5cdGlmICggISBwYXNzICYmIGludlNpemUgKSBpbmRleEN1cnZlKCBlYXIsIG1pblgsIG1pblksIGludlNpemUgKTtcblxuXHRsZXQgc3RvcCA9IGVhcixcblx0XHRwcmV2LCBuZXh0O1xuXG5cdC8vIGl0ZXJhdGUgdGhyb3VnaCBlYXJzLCBzbGljaW5nIHRoZW0gb25lIGJ5IG9uZVxuXHR3aGlsZSAoIGVhci5wcmV2ICE9PSBlYXIubmV4dCApIHtcblxuXHRcdHByZXYgPSBlYXIucHJldjtcblx0XHRuZXh0ID0gZWFyLm5leHQ7XG5cblx0XHRpZiAoIGludlNpemUgPyBpc0Vhckhhc2hlZCggZWFyLCBtaW5YLCBtaW5ZLCBpbnZTaXplICkgOiBpc0VhciggZWFyICkgKSB7XG5cblx0XHRcdC8vIGN1dCBvZmYgdGhlIHRyaWFuZ2xlXG5cdFx0XHR0cmlhbmdsZXMucHVzaCggcHJldi5pIC8gZGltIHwgMCApO1xuXHRcdFx0dHJpYW5nbGVzLnB1c2goIGVhci5pIC8gZGltIHwgMCApO1xuXHRcdFx0dHJpYW5nbGVzLnB1c2goIG5leHQuaSAvIGRpbSB8IDAgKTtcblxuXHRcdFx0cmVtb3ZlTm9kZSggZWFyICk7XG5cblx0XHRcdC8vIHNraXBwaW5nIHRoZSBuZXh0IHZlcnRleCBsZWFkcyB0byBsZXNzIHNsaXZlciB0cmlhbmdsZXNcblx0XHRcdGVhciA9IG5leHQubmV4dDtcblx0XHRcdHN0b3AgPSBuZXh0Lm5leHQ7XG5cblx0XHRcdGNvbnRpbnVlO1xuXG5cdFx0fVxuXG5cdFx0ZWFyID0gbmV4dDtcblxuXHRcdC8vIGlmIHdlIGxvb3BlZCB0aHJvdWdoIHRoZSB3aG9sZSByZW1haW5pbmcgcG9seWdvbiBhbmQgY2FuJ3QgZmluZCBhbnkgbW9yZSBlYXJzXG5cdFx0aWYgKCBlYXIgPT09IHN0b3AgKSB7XG5cblx0XHRcdC8vIHRyeSBmaWx0ZXJpbmcgcG9pbnRzIGFuZCBzbGljaW5nIGFnYWluXG5cdFx0XHRpZiAoICEgcGFzcyApIHtcblxuXHRcdFx0XHRlYXJjdXRMaW5rZWQoIGZpbHRlclBvaW50cyggZWFyICksIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAxICk7XG5cblx0XHRcdFx0Ly8gaWYgdGhpcyBkaWRuJ3Qgd29yaywgdHJ5IGN1cmluZyBhbGwgc21hbGwgc2VsZi1pbnRlcnNlY3Rpb25zIGxvY2FsbHlcblxuXHRcdFx0fSBlbHNlIGlmICggcGFzcyA9PT0gMSApIHtcblxuXHRcdFx0XHRlYXIgPSBjdXJlTG9jYWxJbnRlcnNlY3Rpb25zKCBmaWx0ZXJQb2ludHMoIGVhciApLCB0cmlhbmdsZXMsIGRpbSApO1xuXHRcdFx0XHRlYXJjdXRMaW5rZWQoIGVhciwgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUsIDIgKTtcblxuXHRcdFx0XHQvLyBhcyBhIGxhc3QgcmVzb3J0LCB0cnkgc3BsaXR0aW5nIHRoZSByZW1haW5pbmcgcG9seWdvbiBpbnRvIHR3b1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBwYXNzID09PSAyICkge1xuXG5cdFx0XHRcdHNwbGl0RWFyY3V0KCBlYXIsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplICk7XG5cblx0XHRcdH1cblxuXHRcdFx0YnJlYWs7XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbi8vIGNoZWNrIHdoZXRoZXIgYSBwb2x5Z29uIG5vZGUgZm9ybXMgYSB2YWxpZCBlYXIgd2l0aCBhZGphY2VudCBub2Rlc1xuZnVuY3Rpb24gaXNFYXIoIGVhciApIHtcblxuXHRjb25zdCBhID0gZWFyLnByZXYsXG5cdFx0YiA9IGVhcixcblx0XHRjID0gZWFyLm5leHQ7XG5cblx0aWYgKCBhcmVhKCBhLCBiLCBjICkgPj0gMCApIHJldHVybiBmYWxzZTsgLy8gcmVmbGV4LCBjYW4ndCBiZSBhbiBlYXJcblxuXHQvLyBub3cgbWFrZSBzdXJlIHdlIGRvbid0IGhhdmUgb3RoZXIgcG9pbnRzIGluc2lkZSB0aGUgcG90ZW50aWFsIGVhclxuXHRjb25zdCBheCA9IGEueCwgYnggPSBiLngsIGN4ID0gYy54LCBheSA9IGEueSwgYnkgPSBiLnksIGN5ID0gYy55O1xuXG5cdC8vIHRyaWFuZ2xlIGJib3g7IG1pbiAmIG1heCBhcmUgY2FsY3VsYXRlZCBsaWtlIHRoaXMgZm9yIHNwZWVkXG5cdGNvbnN0IHgwID0gYXggPCBieCA/ICggYXggPCBjeCA/IGF4IDogY3ggKSA6ICggYnggPCBjeCA/IGJ4IDogY3ggKSxcblx0XHR5MCA9IGF5IDwgYnkgPyAoIGF5IDwgY3kgPyBheSA6IGN5ICkgOiAoIGJ5IDwgY3kgPyBieSA6IGN5ICksXG5cdFx0eDEgPSBheCA+IGJ4ID8gKCBheCA+IGN4ID8gYXggOiBjeCApIDogKCBieCA+IGN4ID8gYnggOiBjeCApLFxuXHRcdHkxID0gYXkgPiBieSA/ICggYXkgPiBjeSA/IGF5IDogY3kgKSA6ICggYnkgPiBjeSA/IGJ5IDogY3kgKTtcblxuXHRsZXQgcCA9IGMubmV4dDtcblx0d2hpbGUgKCBwICE9PSBhICkge1xuXG5cdFx0aWYgKCBwLnggPj0geDAgJiYgcC54IDw9IHgxICYmIHAueSA+PSB5MCAmJiBwLnkgPD0geTEgJiZcblx0XHRcdHBvaW50SW5UcmlhbmdsZSggYXgsIGF5LCBieCwgYnksIGN4LCBjeSwgcC54LCBwLnkgKSAmJlxuXHRcdFx0YXJlYSggcC5wcmV2LCBwLCBwLm5leHQgKSA+PSAwICkgcmV0dXJuIGZhbHNlO1xuXHRcdHAgPSBwLm5leHQ7XG5cblx0fVxuXG5cdHJldHVybiB0cnVlO1xuXG59XG5cbmZ1bmN0aW9uIGlzRWFySGFzaGVkKCBlYXIsIG1pblgsIG1pblksIGludlNpemUgKSB7XG5cblx0Y29uc3QgYSA9IGVhci5wcmV2LFxuXHRcdGIgPSBlYXIsXG5cdFx0YyA9IGVhci5uZXh0O1xuXG5cdGlmICggYXJlYSggYSwgYiwgYyApID49IDAgKSByZXR1cm4gZmFsc2U7IC8vIHJlZmxleCwgY2FuJ3QgYmUgYW4gZWFyXG5cblx0Y29uc3QgYXggPSBhLngsIGJ4ID0gYi54LCBjeCA9IGMueCwgYXkgPSBhLnksIGJ5ID0gYi55LCBjeSA9IGMueTtcblxuXHQvLyB0cmlhbmdsZSBiYm94OyBtaW4gJiBtYXggYXJlIGNhbGN1bGF0ZWQgbGlrZSB0aGlzIGZvciBzcGVlZFxuXHRjb25zdCB4MCA9IGF4IDwgYnggPyAoIGF4IDwgY3ggPyBheCA6IGN4ICkgOiAoIGJ4IDwgY3ggPyBieCA6IGN4ICksXG5cdFx0eTAgPSBheSA8IGJ5ID8gKCBheSA8IGN5ID8gYXkgOiBjeSApIDogKCBieSA8IGN5ID8gYnkgOiBjeSApLFxuXHRcdHgxID0gYXggPiBieCA/ICggYXggPiBjeCA/IGF4IDogY3ggKSA6ICggYnggPiBjeCA/IGJ4IDogY3ggKSxcblx0XHR5MSA9IGF5ID4gYnkgPyAoIGF5ID4gY3kgPyBheSA6IGN5ICkgOiAoIGJ5ID4gY3kgPyBieSA6IGN5ICk7XG5cblx0Ly8gei1vcmRlciByYW5nZSBmb3IgdGhlIGN1cnJlbnQgdHJpYW5nbGUgYmJveDtcblx0Y29uc3QgbWluWiA9IHpPcmRlciggeDAsIHkwLCBtaW5YLCBtaW5ZLCBpbnZTaXplICksXG5cdFx0bWF4WiA9IHpPcmRlciggeDEsIHkxLCBtaW5YLCBtaW5ZLCBpbnZTaXplICk7XG5cblx0bGV0IHAgPSBlYXIucHJldlosXG5cdFx0biA9IGVhci5uZXh0WjtcblxuXHQvLyBsb29rIGZvciBwb2ludHMgaW5zaWRlIHRoZSB0cmlhbmdsZSBpbiBib3RoIGRpcmVjdGlvbnNcblx0d2hpbGUgKCBwICYmIHAueiA+PSBtaW5aICYmIG4gJiYgbi56IDw9IG1heFogKSB7XG5cblx0XHRpZiAoIHAueCA+PSB4MCAmJiBwLnggPD0geDEgJiYgcC55ID49IHkwICYmIHAueSA8PSB5MSAmJiBwICE9PSBhICYmIHAgIT09IGMgJiZcblx0XHRcdHBvaW50SW5UcmlhbmdsZSggYXgsIGF5LCBieCwgYnksIGN4LCBjeSwgcC54LCBwLnkgKSAmJiBhcmVhKCBwLnByZXYsIHAsIHAubmV4dCApID49IDAgKSByZXR1cm4gZmFsc2U7XG5cdFx0cCA9IHAucHJldlo7XG5cblx0XHRpZiAoIG4ueCA+PSB4MCAmJiBuLnggPD0geDEgJiYgbi55ID49IHkwICYmIG4ueSA8PSB5MSAmJiBuICE9PSBhICYmIG4gIT09IGMgJiZcblx0XHRcdHBvaW50SW5UcmlhbmdsZSggYXgsIGF5LCBieCwgYnksIGN4LCBjeSwgbi54LCBuLnkgKSAmJiBhcmVhKCBuLnByZXYsIG4sIG4ubmV4dCApID49IDAgKSByZXR1cm4gZmFsc2U7XG5cdFx0biA9IG4ubmV4dFo7XG5cblx0fVxuXG5cdC8vIGxvb2sgZm9yIHJlbWFpbmluZyBwb2ludHMgaW4gZGVjcmVhc2luZyB6LW9yZGVyXG5cdHdoaWxlICggcCAmJiBwLnogPj0gbWluWiApIHtcblxuXHRcdGlmICggcC54ID49IHgwICYmIHAueCA8PSB4MSAmJiBwLnkgPj0geTAgJiYgcC55IDw9IHkxICYmIHAgIT09IGEgJiYgcCAhPT0gYyAmJlxuXHRcdFx0cG9pbnRJblRyaWFuZ2xlKCBheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBwLngsIHAueSApICYmIGFyZWEoIHAucHJldiwgcCwgcC5uZXh0ICkgPj0gMCApIHJldHVybiBmYWxzZTtcblx0XHRwID0gcC5wcmV2WjtcblxuXHR9XG5cblx0Ly8gbG9vayBmb3IgcmVtYWluaW5nIHBvaW50cyBpbiBpbmNyZWFzaW5nIHotb3JkZXJcblx0d2hpbGUgKCBuICYmIG4ueiA8PSBtYXhaICkge1xuXG5cdFx0aWYgKCBuLnggPj0geDAgJiYgbi54IDw9IHgxICYmIG4ueSA+PSB5MCAmJiBuLnkgPD0geTEgJiYgbiAhPT0gYSAmJiBuICE9PSBjICYmXG5cdFx0XHRwb2ludEluVHJpYW5nbGUoIGF4LCBheSwgYngsIGJ5LCBjeCwgY3ksIG4ueCwgbi55ICkgJiYgYXJlYSggbi5wcmV2LCBuLCBuLm5leHQgKSA+PSAwICkgcmV0dXJuIGZhbHNlO1xuXHRcdG4gPSBuLm5leHRaO1xuXG5cdH1cblxuXHRyZXR1cm4gdHJ1ZTtcblxufVxuXG4vLyBnbyB0aHJvdWdoIGFsbCBwb2x5Z29uIG5vZGVzIGFuZCBjdXJlIHNtYWxsIGxvY2FsIHNlbGYtaW50ZXJzZWN0aW9uc1xuZnVuY3Rpb24gY3VyZUxvY2FsSW50ZXJzZWN0aW9ucyggc3RhcnQsIHRyaWFuZ2xlcywgZGltICkge1xuXG5cdGxldCBwID0gc3RhcnQ7XG5cdGRvIHtcblxuXHRcdGNvbnN0IGEgPSBwLnByZXYsXG5cdFx0XHRiID0gcC5uZXh0Lm5leHQ7XG5cblx0XHRpZiAoICEgZXF1YWxzKCBhLCBiICkgJiYgaW50ZXJzZWN0cyggYSwgcCwgcC5uZXh0LCBiICkgJiYgbG9jYWxseUluc2lkZSggYSwgYiApICYmIGxvY2FsbHlJbnNpZGUoIGIsIGEgKSApIHtcblxuXHRcdFx0dHJpYW5nbGVzLnB1c2goIGEuaSAvIGRpbSB8IDAgKTtcblx0XHRcdHRyaWFuZ2xlcy5wdXNoKCBwLmkgLyBkaW0gfCAwICk7XG5cdFx0XHR0cmlhbmdsZXMucHVzaCggYi5pIC8gZGltIHwgMCApO1xuXG5cdFx0XHQvLyByZW1vdmUgdHdvIG5vZGVzIGludm9sdmVkXG5cdFx0XHRyZW1vdmVOb2RlKCBwICk7XG5cdFx0XHRyZW1vdmVOb2RlKCBwLm5leHQgKTtcblxuXHRcdFx0cCA9IHN0YXJ0ID0gYjtcblxuXHRcdH1cblxuXHRcdHAgPSBwLm5leHQ7XG5cblx0fSB3aGlsZSAoIHAgIT09IHN0YXJ0ICk7XG5cblx0cmV0dXJuIGZpbHRlclBvaW50cyggcCApO1xuXG59XG5cbi8vIHRyeSBzcGxpdHRpbmcgcG9seWdvbiBpbnRvIHR3byBhbmQgdHJpYW5ndWxhdGUgdGhlbSBpbmRlcGVuZGVudGx5XG5mdW5jdGlvbiBzcGxpdEVhcmN1dCggc3RhcnQsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplICkge1xuXG5cdC8vIGxvb2sgZm9yIGEgdmFsaWQgZGlhZ29uYWwgdGhhdCBkaXZpZGVzIHRoZSBwb2x5Z29uIGludG8gdHdvXG5cdGxldCBhID0gc3RhcnQ7XG5cdGRvIHtcblxuXHRcdGxldCBiID0gYS5uZXh0Lm5leHQ7XG5cdFx0d2hpbGUgKCBiICE9PSBhLnByZXYgKSB7XG5cblx0XHRcdGlmICggYS5pICE9PSBiLmkgJiYgaXNWYWxpZERpYWdvbmFsKCBhLCBiICkgKSB7XG5cblx0XHRcdFx0Ly8gc3BsaXQgdGhlIHBvbHlnb24gaW4gdHdvIGJ5IHRoZSBkaWFnb25hbFxuXHRcdFx0XHRsZXQgYyA9IHNwbGl0UG9seWdvbiggYSwgYiApO1xuXG5cdFx0XHRcdC8vIGZpbHRlciBjb2xpbmVhciBwb2ludHMgYXJvdW5kIHRoZSBjdXRzXG5cdFx0XHRcdGEgPSBmaWx0ZXJQb2ludHMoIGEsIGEubmV4dCApO1xuXHRcdFx0XHRjID0gZmlsdGVyUG9pbnRzKCBjLCBjLm5leHQgKTtcblxuXHRcdFx0XHQvLyBydW4gZWFyY3V0IG9uIGVhY2ggaGFsZlxuXHRcdFx0XHRlYXJjdXRMaW5rZWQoIGEsIHRyaWFuZ2xlcywgZGltLCBtaW5YLCBtaW5ZLCBpbnZTaXplLCAwICk7XG5cdFx0XHRcdGVhcmN1dExpbmtlZCggYywgdHJpYW5nbGVzLCBkaW0sIG1pblgsIG1pblksIGludlNpemUsIDAgKTtcblx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHR9XG5cblx0XHRcdGIgPSBiLm5leHQ7XG5cblx0XHR9XG5cblx0XHRhID0gYS5uZXh0O1xuXG5cdH0gd2hpbGUgKCBhICE9PSBzdGFydCApO1xuXG59XG5cbi8vIGxpbmsgZXZlcnkgaG9sZSBpbnRvIHRoZSBvdXRlciBsb29wLCBwcm9kdWNpbmcgYSBzaW5nbGUtcmluZyBwb2x5Z29uIHdpdGhvdXQgaG9sZXNcbmZ1bmN0aW9uIGVsaW1pbmF0ZUhvbGVzKCBkYXRhLCBob2xlSW5kaWNlcywgb3V0ZXJOb2RlLCBkaW0gKSB7XG5cblx0Y29uc3QgcXVldWUgPSBbXTtcblx0bGV0IGksIGxlbiwgc3RhcnQsIGVuZCwgbGlzdDtcblxuXHRmb3IgKCBpID0gMCwgbGVuID0gaG9sZUluZGljZXMubGVuZ3RoOyBpIDwgbGVuOyBpICsrICkge1xuXG5cdFx0c3RhcnQgPSBob2xlSW5kaWNlc1sgaSBdICogZGltO1xuXHRcdGVuZCA9IGkgPCBsZW4gLSAxID8gaG9sZUluZGljZXNbIGkgKyAxIF0gKiBkaW0gOiBkYXRhLmxlbmd0aDtcblx0XHRsaXN0ID0gbGlua2VkTGlzdCggZGF0YSwgc3RhcnQsIGVuZCwgZGltLCBmYWxzZSApO1xuXHRcdGlmICggbGlzdCA9PT0gbGlzdC5uZXh0ICkgbGlzdC5zdGVpbmVyID0gdHJ1ZTtcblx0XHRxdWV1ZS5wdXNoKCBnZXRMZWZ0bW9zdCggbGlzdCApICk7XG5cblx0fVxuXG5cdHF1ZXVlLnNvcnQoIGNvbXBhcmVYICk7XG5cblx0Ly8gcHJvY2VzcyBob2xlcyBmcm9tIGxlZnQgdG8gcmlnaHRcblx0Zm9yICggaSA9IDA7IGkgPCBxdWV1ZS5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRvdXRlck5vZGUgPSBlbGltaW5hdGVIb2xlKCBxdWV1ZVsgaSBdLCBvdXRlck5vZGUgKTtcblxuXHR9XG5cblx0cmV0dXJuIG91dGVyTm9kZTtcblxufVxuXG5mdW5jdGlvbiBjb21wYXJlWCggYSwgYiApIHtcblxuXHRyZXR1cm4gYS54IC0gYi54O1xuXG59XG5cbi8vIGZpbmQgYSBicmlkZ2UgYmV0d2VlbiB2ZXJ0aWNlcyB0aGF0IGNvbm5lY3RzIGhvbGUgd2l0aCBhbiBvdXRlciByaW5nIGFuZCBsaW5rIGl0XG5mdW5jdGlvbiBlbGltaW5hdGVIb2xlKCBob2xlLCBvdXRlck5vZGUgKSB7XG5cblx0Y29uc3QgYnJpZGdlID0gZmluZEhvbGVCcmlkZ2UoIGhvbGUsIG91dGVyTm9kZSApO1xuXHRpZiAoICEgYnJpZGdlICkge1xuXG5cdFx0cmV0dXJuIG91dGVyTm9kZTtcblxuXHR9XG5cblx0Y29uc3QgYnJpZGdlUmV2ZXJzZSA9IHNwbGl0UG9seWdvbiggYnJpZGdlLCBob2xlICk7XG5cblx0Ly8gZmlsdGVyIGNvbGxpbmVhciBwb2ludHMgYXJvdW5kIHRoZSBjdXRzXG5cdGZpbHRlclBvaW50cyggYnJpZGdlUmV2ZXJzZSwgYnJpZGdlUmV2ZXJzZS5uZXh0ICk7XG5cdHJldHVybiBmaWx0ZXJQb2ludHMoIGJyaWRnZSwgYnJpZGdlLm5leHQgKTtcblxufVxuXG4vLyBEYXZpZCBFYmVybHkncyBhbGdvcml0aG0gZm9yIGZpbmRpbmcgYSBicmlkZ2UgYmV0d2VlbiBob2xlIGFuZCBvdXRlciBwb2x5Z29uXG5mdW5jdGlvbiBmaW5kSG9sZUJyaWRnZSggaG9sZSwgb3V0ZXJOb2RlICkge1xuXG5cdGxldCBwID0gb3V0ZXJOb2RlLFxuXHRcdHF4ID0gLSBJbmZpbml0eSxcblx0XHRtO1xuXG5cdGNvbnN0IGh4ID0gaG9sZS54LCBoeSA9IGhvbGUueTtcblxuXHQvLyBmaW5kIGEgc2VnbWVudCBpbnRlcnNlY3RlZCBieSBhIHJheSBmcm9tIHRoZSBob2xlJ3MgbGVmdG1vc3QgcG9pbnQgdG8gdGhlIGxlZnQ7XG5cdC8vIHNlZ21lbnQncyBlbmRwb2ludCB3aXRoIGxlc3NlciB4IHdpbGwgYmUgcG90ZW50aWFsIGNvbm5lY3Rpb24gcG9pbnRcblx0ZG8ge1xuXG5cdFx0aWYgKCBoeSA8PSBwLnkgJiYgaHkgPj0gcC5uZXh0LnkgJiYgcC5uZXh0LnkgIT09IHAueSApIHtcblxuXHRcdFx0Y29uc3QgeCA9IHAueCArICggaHkgLSBwLnkgKSAqICggcC5uZXh0LnggLSBwLnggKSAvICggcC5uZXh0LnkgLSBwLnkgKTtcblx0XHRcdGlmICggeCA8PSBoeCAmJiB4ID4gcXggKSB7XG5cblx0XHRcdFx0cXggPSB4O1xuXHRcdFx0XHRtID0gcC54IDwgcC5uZXh0LnggPyBwIDogcC5uZXh0O1xuXHRcdFx0XHRpZiAoIHggPT09IGh4ICkgcmV0dXJuIG07IC8vIGhvbGUgdG91Y2hlcyBvdXRlciBzZWdtZW50OyBwaWNrIGxlZnRtb3N0IGVuZHBvaW50XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHAgPSBwLm5leHQ7XG5cblx0fSB3aGlsZSAoIHAgIT09IG91dGVyTm9kZSApO1xuXG5cdGlmICggISBtICkgcmV0dXJuIG51bGw7XG5cblx0Ly8gbG9vayBmb3IgcG9pbnRzIGluc2lkZSB0aGUgdHJpYW5nbGUgb2YgaG9sZSBwb2ludCwgc2VnbWVudCBpbnRlcnNlY3Rpb24gYW5kIGVuZHBvaW50O1xuXHQvLyBpZiB0aGVyZSBhcmUgbm8gcG9pbnRzIGZvdW5kLCB3ZSBoYXZlIGEgdmFsaWQgY29ubmVjdGlvbjtcblx0Ly8gb3RoZXJ3aXNlIGNob29zZSB0aGUgcG9pbnQgb2YgdGhlIG1pbmltdW0gYW5nbGUgd2l0aCB0aGUgcmF5IGFzIGNvbm5lY3Rpb24gcG9pbnRcblxuXHRjb25zdCBzdG9wID0gbSxcblx0XHRteCA9IG0ueCxcblx0XHRteSA9IG0ueTtcblx0bGV0IHRhbk1pbiA9IEluZmluaXR5LCB0YW47XG5cblx0cCA9IG07XG5cblx0ZG8ge1xuXG5cdFx0aWYgKCBoeCA+PSBwLnggJiYgcC54ID49IG14ICYmIGh4ICE9PSBwLnggJiZcblx0XHRcdFx0cG9pbnRJblRyaWFuZ2xlKCBoeSA8IG15ID8gaHggOiBxeCwgaHksIG14LCBteSwgaHkgPCBteSA/IHF4IDogaHgsIGh5LCBwLngsIHAueSApICkge1xuXG5cdFx0XHR0YW4gPSBNYXRoLmFicyggaHkgLSBwLnkgKSAvICggaHggLSBwLnggKTsgLy8gdGFuZ2VudGlhbFxuXG5cdFx0XHRpZiAoIGxvY2FsbHlJbnNpZGUoIHAsIGhvbGUgKSAmJiAoIHRhbiA8IHRhbk1pbiB8fCAoIHRhbiA9PT0gdGFuTWluICYmICggcC54ID4gbS54IHx8ICggcC54ID09PSBtLnggJiYgc2VjdG9yQ29udGFpbnNTZWN0b3IoIG0sIHAgKSApICkgKSApICkge1xuXG5cdFx0XHRcdG0gPSBwO1xuXHRcdFx0XHR0YW5NaW4gPSB0YW47XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHAgPSBwLm5leHQ7XG5cblx0fSB3aGlsZSAoIHAgIT09IHN0b3AgKTtcblxuXHRyZXR1cm4gbTtcblxufVxuXG4vLyB3aGV0aGVyIHNlY3RvciBpbiB2ZXJ0ZXggbSBjb250YWlucyBzZWN0b3IgaW4gdmVydGV4IHAgaW4gdGhlIHNhbWUgY29vcmRpbmF0ZXNcbmZ1bmN0aW9uIHNlY3RvckNvbnRhaW5zU2VjdG9yKCBtLCBwICkge1xuXG5cdHJldHVybiBhcmVhKCBtLnByZXYsIG0sIHAucHJldiApIDwgMCAmJiBhcmVhKCBwLm5leHQsIG0sIG0ubmV4dCApIDwgMDtcblxufVxuXG4vLyBpbnRlcmxpbmsgcG9seWdvbiBub2RlcyBpbiB6LW9yZGVyXG5mdW5jdGlvbiBpbmRleEN1cnZlKCBzdGFydCwgbWluWCwgbWluWSwgaW52U2l6ZSApIHtcblxuXHRsZXQgcCA9IHN0YXJ0O1xuXHRkbyB7XG5cblx0XHRpZiAoIHAueiA9PT0gMCApIHAueiA9IHpPcmRlciggcC54LCBwLnksIG1pblgsIG1pblksIGludlNpemUgKTtcblx0XHRwLnByZXZaID0gcC5wcmV2O1xuXHRcdHAubmV4dFogPSBwLm5leHQ7XG5cdFx0cCA9IHAubmV4dDtcblxuXHR9IHdoaWxlICggcCAhPT0gc3RhcnQgKTtcblxuXHRwLnByZXZaLm5leHRaID0gbnVsbDtcblx0cC5wcmV2WiA9IG51bGw7XG5cblx0c29ydExpbmtlZCggcCApO1xuXG59XG5cbi8vIFNpbW9uIFRhdGhhbSdzIGxpbmtlZCBsaXN0IG1lcmdlIHNvcnQgYWxnb3JpdGhtXG4vLyBodHRwOi8vd3d3LmNoaWFyay5ncmVlbmVuZC5vcmcudWsvfnNndGF0aGFtL2FsZ29yaXRobXMvbGlzdHNvcnQuaHRtbFxuZnVuY3Rpb24gc29ydExpbmtlZCggbGlzdCApIHtcblxuXHRsZXQgaSwgcCwgcSwgZSwgdGFpbCwgbnVtTWVyZ2VzLCBwU2l6ZSwgcVNpemUsXG5cdFx0aW5TaXplID0gMTtcblxuXHRkbyB7XG5cblx0XHRwID0gbGlzdDtcblx0XHRsaXN0ID0gbnVsbDtcblx0XHR0YWlsID0gbnVsbDtcblx0XHRudW1NZXJnZXMgPSAwO1xuXG5cdFx0d2hpbGUgKCBwICkge1xuXG5cdFx0XHRudW1NZXJnZXMgKys7XG5cdFx0XHRxID0gcDtcblx0XHRcdHBTaXplID0gMDtcblx0XHRcdGZvciAoIGkgPSAwOyBpIDwgaW5TaXplOyBpICsrICkge1xuXG5cdFx0XHRcdHBTaXplICsrO1xuXHRcdFx0XHRxID0gcS5uZXh0Wjtcblx0XHRcdFx0aWYgKCAhIHEgKSBicmVhaztcblxuXHRcdFx0fVxuXG5cdFx0XHRxU2l6ZSA9IGluU2l6ZTtcblxuXHRcdFx0d2hpbGUgKCBwU2l6ZSA+IDAgfHwgKCBxU2l6ZSA+IDAgJiYgcSApICkge1xuXG5cdFx0XHRcdGlmICggcFNpemUgIT09IDAgJiYgKCBxU2l6ZSA9PT0gMCB8fCAhIHEgfHwgcC56IDw9IHEueiApICkge1xuXG5cdFx0XHRcdFx0ZSA9IHA7XG5cdFx0XHRcdFx0cCA9IHAubmV4dFo7XG5cdFx0XHRcdFx0cFNpemUgLS07XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGUgPSBxO1xuXHRcdFx0XHRcdHEgPSBxLm5leHRaO1xuXHRcdFx0XHRcdHFTaXplIC0tO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIHRhaWwgKSB0YWlsLm5leHRaID0gZTtcblx0XHRcdFx0ZWxzZSBsaXN0ID0gZTtcblxuXHRcdFx0XHRlLnByZXZaID0gdGFpbDtcblx0XHRcdFx0dGFpbCA9IGU7XG5cblx0XHRcdH1cblxuXHRcdFx0cCA9IHE7XG5cblx0XHR9XG5cblx0XHR0YWlsLm5leHRaID0gbnVsbDtcblx0XHRpblNpemUgKj0gMjtcblxuXHR9IHdoaWxlICggbnVtTWVyZ2VzID4gMSApO1xuXG5cdHJldHVybiBsaXN0O1xuXG59XG5cbi8vIHotb3JkZXIgb2YgYSBwb2ludCBnaXZlbiBjb29yZHMgYW5kIGludmVyc2Ugb2YgdGhlIGxvbmdlciBzaWRlIG9mIGRhdGEgYmJveFxuZnVuY3Rpb24gek9yZGVyKCB4LCB5LCBtaW5YLCBtaW5ZLCBpbnZTaXplICkge1xuXG5cdC8vIGNvb3JkcyBhcmUgdHJhbnNmb3JtZWQgaW50byBub24tbmVnYXRpdmUgMTUtYml0IGludGVnZXIgcmFuZ2Vcblx0eCA9ICggeCAtIG1pblggKSAqIGludlNpemUgfCAwO1xuXHR5ID0gKCB5IC0gbWluWSApICogaW52U2l6ZSB8IDA7XG5cblx0eCA9ICggeCB8ICggeCA8PCA4ICkgKSAmIDB4MDBGRjAwRkY7XG5cdHggPSAoIHggfCAoIHggPDwgNCApICkgJiAweDBGMEYwRjBGO1xuXHR4ID0gKCB4IHwgKCB4IDw8IDIgKSApICYgMHgzMzMzMzMzMztcblx0eCA9ICggeCB8ICggeCA8PCAxICkgKSAmIDB4NTU1NTU1NTU7XG5cblx0eSA9ICggeSB8ICggeSA8PCA4ICkgKSAmIDB4MDBGRjAwRkY7XG5cdHkgPSAoIHkgfCAoIHkgPDwgNCApICkgJiAweDBGMEYwRjBGO1xuXHR5ID0gKCB5IHwgKCB5IDw8IDIgKSApICYgMHgzMzMzMzMzMztcblx0eSA9ICggeSB8ICggeSA8PCAxICkgKSAmIDB4NTU1NTU1NTU7XG5cblx0cmV0dXJuIHggfCAoIHkgPDwgMSApO1xuXG59XG5cbi8vIGZpbmQgdGhlIGxlZnRtb3N0IG5vZGUgb2YgYSBwb2x5Z29uIHJpbmdcbmZ1bmN0aW9uIGdldExlZnRtb3N0KCBzdGFydCApIHtcblxuXHRsZXQgcCA9IHN0YXJ0LFxuXHRcdGxlZnRtb3N0ID0gc3RhcnQ7XG5cdGRvIHtcblxuXHRcdGlmICggcC54IDwgbGVmdG1vc3QueCB8fCAoIHAueCA9PT0gbGVmdG1vc3QueCAmJiBwLnkgPCBsZWZ0bW9zdC55ICkgKSBsZWZ0bW9zdCA9IHA7XG5cdFx0cCA9IHAubmV4dDtcblxuXHR9IHdoaWxlICggcCAhPT0gc3RhcnQgKTtcblxuXHRyZXR1cm4gbGVmdG1vc3Q7XG5cbn1cblxuLy8gY2hlY2sgaWYgYSBwb2ludCBsaWVzIHdpdGhpbiBhIGNvbnZleCB0cmlhbmdsZVxuZnVuY3Rpb24gcG9pbnRJblRyaWFuZ2xlKCBheCwgYXksIGJ4LCBieSwgY3gsIGN5LCBweCwgcHkgKSB7XG5cblx0cmV0dXJuICggY3ggLSBweCApICogKCBheSAtIHB5ICkgPj0gKCBheCAtIHB4ICkgKiAoIGN5IC0gcHkgKSAmJlxuICAgICAgICAgICAoIGF4IC0gcHggKSAqICggYnkgLSBweSApID49ICggYnggLSBweCApICogKCBheSAtIHB5ICkgJiZcbiAgICAgICAgICAgKCBieCAtIHB4ICkgKiAoIGN5IC0gcHkgKSA+PSAoIGN4IC0gcHggKSAqICggYnkgLSBweSApO1xuXG59XG5cbi8vIGNoZWNrIGlmIGEgZGlhZ29uYWwgYmV0d2VlbiB0d28gcG9seWdvbiBub2RlcyBpcyB2YWxpZCAobGllcyBpbiBwb2x5Z29uIGludGVyaW9yKVxuZnVuY3Rpb24gaXNWYWxpZERpYWdvbmFsKCBhLCBiICkge1xuXG5cdHJldHVybiBhLm5leHQuaSAhPT0gYi5pICYmIGEucHJldi5pICE9PSBiLmkgJiYgISBpbnRlcnNlY3RzUG9seWdvbiggYSwgYiApICYmIC8vIGRvbmVzJ3QgaW50ZXJzZWN0IG90aGVyIGVkZ2VzXG4gICAgICAgICAgICggbG9jYWxseUluc2lkZSggYSwgYiApICYmIGxvY2FsbHlJbnNpZGUoIGIsIGEgKSAmJiBtaWRkbGVJbnNpZGUoIGEsIGIgKSAmJiAvLyBsb2NhbGx5IHZpc2libGVcbiAgICAgICAgICAgICggYXJlYSggYS5wcmV2LCBhLCBiLnByZXYgKSB8fCBhcmVhKCBhLCBiLnByZXYsIGIgKSApIHx8IC8vIGRvZXMgbm90IGNyZWF0ZSBvcHBvc2l0ZS1mYWNpbmcgc2VjdG9yc1xuICAgICAgICAgICAgZXF1YWxzKCBhLCBiICkgJiYgYXJlYSggYS5wcmV2LCBhLCBhLm5leHQgKSA+IDAgJiYgYXJlYSggYi5wcmV2LCBiLCBiLm5leHQgKSA+IDAgKTsgLy8gc3BlY2lhbCB6ZXJvLWxlbmd0aCBjYXNlXG5cbn1cblxuLy8gc2lnbmVkIGFyZWEgb2YgYSB0cmlhbmdsZVxuZnVuY3Rpb24gYXJlYSggcCwgcSwgciApIHtcblxuXHRyZXR1cm4gKCBxLnkgLSBwLnkgKSAqICggci54IC0gcS54ICkgLSAoIHEueCAtIHAueCApICogKCByLnkgLSBxLnkgKTtcblxufVxuXG4vLyBjaGVjayBpZiB0d28gcG9pbnRzIGFyZSBlcXVhbFxuZnVuY3Rpb24gZXF1YWxzKCBwMSwgcDIgKSB7XG5cblx0cmV0dXJuIHAxLnggPT09IHAyLnggJiYgcDEueSA9PT0gcDIueTtcblxufVxuXG4vLyBjaGVjayBpZiB0d28gc2VnbWVudHMgaW50ZXJzZWN0XG5mdW5jdGlvbiBpbnRlcnNlY3RzKCBwMSwgcTEsIHAyLCBxMiApIHtcblxuXHRjb25zdCBvMSA9IHNpZ24oIGFyZWEoIHAxLCBxMSwgcDIgKSApO1xuXHRjb25zdCBvMiA9IHNpZ24oIGFyZWEoIHAxLCBxMSwgcTIgKSApO1xuXHRjb25zdCBvMyA9IHNpZ24oIGFyZWEoIHAyLCBxMiwgcDEgKSApO1xuXHRjb25zdCBvNCA9IHNpZ24oIGFyZWEoIHAyLCBxMiwgcTEgKSApO1xuXG5cdGlmICggbzEgIT09IG8yICYmIG8zICE9PSBvNCApIHJldHVybiB0cnVlOyAvLyBnZW5lcmFsIGNhc2VcblxuXHRpZiAoIG8xID09PSAwICYmIG9uU2VnbWVudCggcDEsIHAyLCBxMSApICkgcmV0dXJuIHRydWU7IC8vIHAxLCBxMSBhbmQgcDIgYXJlIGNvbGxpbmVhciBhbmQgcDIgbGllcyBvbiBwMXExXG5cdGlmICggbzIgPT09IDAgJiYgb25TZWdtZW50KCBwMSwgcTIsIHExICkgKSByZXR1cm4gdHJ1ZTsgLy8gcDEsIHExIGFuZCBxMiBhcmUgY29sbGluZWFyIGFuZCBxMiBsaWVzIG9uIHAxcTFcblx0aWYgKCBvMyA9PT0gMCAmJiBvblNlZ21lbnQoIHAyLCBwMSwgcTIgKSApIHJldHVybiB0cnVlOyAvLyBwMiwgcTIgYW5kIHAxIGFyZSBjb2xsaW5lYXIgYW5kIHAxIGxpZXMgb24gcDJxMlxuXHRpZiAoIG80ID09PSAwICYmIG9uU2VnbWVudCggcDIsIHExLCBxMiApICkgcmV0dXJuIHRydWU7IC8vIHAyLCBxMiBhbmQgcTEgYXJlIGNvbGxpbmVhciBhbmQgcTEgbGllcyBvbiBwMnEyXG5cblx0cmV0dXJuIGZhbHNlO1xuXG59XG5cbi8vIGZvciBjb2xsaW5lYXIgcG9pbnRzIHAsIHEsIHIsIGNoZWNrIGlmIHBvaW50IHEgbGllcyBvbiBzZWdtZW50IHByXG5mdW5jdGlvbiBvblNlZ21lbnQoIHAsIHEsIHIgKSB7XG5cblx0cmV0dXJuIHEueCA8PSBNYXRoLm1heCggcC54LCByLnggKSAmJiBxLnggPj0gTWF0aC5taW4oIHAueCwgci54ICkgJiYgcS55IDw9IE1hdGgubWF4KCBwLnksIHIueSApICYmIHEueSA+PSBNYXRoLm1pbiggcC55LCByLnkgKTtcblxufVxuXG5mdW5jdGlvbiBzaWduKCBudW0gKSB7XG5cblx0cmV0dXJuIG51bSA+IDAgPyAxIDogbnVtIDwgMCA/IC0gMSA6IDA7XG5cbn1cblxuLy8gY2hlY2sgaWYgYSBwb2x5Z29uIGRpYWdvbmFsIGludGVyc2VjdHMgYW55IHBvbHlnb24gc2VnbWVudHNcbmZ1bmN0aW9uIGludGVyc2VjdHNQb2x5Z29uKCBhLCBiICkge1xuXG5cdGxldCBwID0gYTtcblx0ZG8ge1xuXG5cdFx0aWYgKCBwLmkgIT09IGEuaSAmJiBwLm5leHQuaSAhPT0gYS5pICYmIHAuaSAhPT0gYi5pICYmIHAubmV4dC5pICE9PSBiLmkgJiZcblx0XHRcdGludGVyc2VjdHMoIHAsIHAubmV4dCwgYSwgYiApICkgcmV0dXJuIHRydWU7XG5cdFx0cCA9IHAubmV4dDtcblxuXHR9IHdoaWxlICggcCAhPT0gYSApO1xuXG5cdHJldHVybiBmYWxzZTtcblxufVxuXG4vLyBjaGVjayBpZiBhIHBvbHlnb24gZGlhZ29uYWwgaXMgbG9jYWxseSBpbnNpZGUgdGhlIHBvbHlnb25cbmZ1bmN0aW9uIGxvY2FsbHlJbnNpZGUoIGEsIGIgKSB7XG5cblx0cmV0dXJuIGFyZWEoIGEucHJldiwgYSwgYS5uZXh0ICkgPCAwID9cblx0XHRhcmVhKCBhLCBiLCBhLm5leHQgKSA+PSAwICYmIGFyZWEoIGEsIGEucHJldiwgYiApID49IDAgOlxuXHRcdGFyZWEoIGEsIGIsIGEucHJldiApIDwgMCB8fCBhcmVhKCBhLCBhLm5leHQsIGIgKSA8IDA7XG5cbn1cblxuLy8gY2hlY2sgaWYgdGhlIG1pZGRsZSBwb2ludCBvZiBhIHBvbHlnb24gZGlhZ29uYWwgaXMgaW5zaWRlIHRoZSBwb2x5Z29uXG5mdW5jdGlvbiBtaWRkbGVJbnNpZGUoIGEsIGIgKSB7XG5cblx0bGV0IHAgPSBhLFxuXHRcdGluc2lkZSA9IGZhbHNlO1xuXHRjb25zdCBweCA9ICggYS54ICsgYi54ICkgLyAyLFxuXHRcdHB5ID0gKCBhLnkgKyBiLnkgKSAvIDI7XG5cdGRvIHtcblxuXHRcdGlmICggKCAoIHAueSA+IHB5ICkgIT09ICggcC5uZXh0LnkgPiBweSApICkgJiYgcC5uZXh0LnkgIT09IHAueSAmJlxuXHRcdFx0KCBweCA8ICggcC5uZXh0LnggLSBwLnggKSAqICggcHkgLSBwLnkgKSAvICggcC5uZXh0LnkgLSBwLnkgKSArIHAueCApIClcblx0XHRcdGluc2lkZSA9ICEgaW5zaWRlO1xuXHRcdHAgPSBwLm5leHQ7XG5cblx0fSB3aGlsZSAoIHAgIT09IGEgKTtcblxuXHRyZXR1cm4gaW5zaWRlO1xuXG59XG5cbi8vIGxpbmsgdHdvIHBvbHlnb24gdmVydGljZXMgd2l0aCBhIGJyaWRnZTsgaWYgdGhlIHZlcnRpY2VzIGJlbG9uZyB0byB0aGUgc2FtZSByaW5nLCBpdCBzcGxpdHMgcG9seWdvbiBpbnRvIHR3bztcbi8vIGlmIG9uZSBiZWxvbmdzIHRvIHRoZSBvdXRlciByaW5nIGFuZCBhbm90aGVyIHRvIGEgaG9sZSwgaXQgbWVyZ2VzIGl0IGludG8gYSBzaW5nbGUgcmluZ1xuZnVuY3Rpb24gc3BsaXRQb2x5Z29uKCBhLCBiICkge1xuXG5cdGNvbnN0IGEyID0gbmV3IE5vZGUoIGEuaSwgYS54LCBhLnkgKSxcblx0XHRiMiA9IG5ldyBOb2RlKCBiLmksIGIueCwgYi55ICksXG5cdFx0YW4gPSBhLm5leHQsXG5cdFx0YnAgPSBiLnByZXY7XG5cblx0YS5uZXh0ID0gYjtcblx0Yi5wcmV2ID0gYTtcblxuXHRhMi5uZXh0ID0gYW47XG5cdGFuLnByZXYgPSBhMjtcblxuXHRiMi5uZXh0ID0gYTI7XG5cdGEyLnByZXYgPSBiMjtcblxuXHRicC5uZXh0ID0gYjI7XG5cdGIyLnByZXYgPSBicDtcblxuXHRyZXR1cm4gYjI7XG5cbn1cblxuLy8gY3JlYXRlIGEgbm9kZSBhbmQgb3B0aW9uYWxseSBsaW5rIGl0IHdpdGggcHJldmlvdXMgb25lIChpbiBhIGNpcmN1bGFyIGRvdWJseSBsaW5rZWQgbGlzdClcbmZ1bmN0aW9uIGluc2VydE5vZGUoIGksIHgsIHksIGxhc3QgKSB7XG5cblx0Y29uc3QgcCA9IG5ldyBOb2RlKCBpLCB4LCB5ICk7XG5cblx0aWYgKCAhIGxhc3QgKSB7XG5cblx0XHRwLnByZXYgPSBwO1xuXHRcdHAubmV4dCA9IHA7XG5cblx0fSBlbHNlIHtcblxuXHRcdHAubmV4dCA9IGxhc3QubmV4dDtcblx0XHRwLnByZXYgPSBsYXN0O1xuXHRcdGxhc3QubmV4dC5wcmV2ID0gcDtcblx0XHRsYXN0Lm5leHQgPSBwO1xuXG5cdH1cblxuXHRyZXR1cm4gcDtcblxufVxuXG5mdW5jdGlvbiByZW1vdmVOb2RlKCBwICkge1xuXG5cdHAubmV4dC5wcmV2ID0gcC5wcmV2O1xuXHRwLnByZXYubmV4dCA9IHAubmV4dDtcblxuXHRpZiAoIHAucHJldlogKSBwLnByZXZaLm5leHRaID0gcC5uZXh0Wjtcblx0aWYgKCBwLm5leHRaICkgcC5uZXh0Wi5wcmV2WiA9IHAucHJldlo7XG5cbn1cblxuZnVuY3Rpb24gTm9kZSggaSwgeCwgeSApIHtcblxuXHQvLyB2ZXJ0ZXggaW5kZXggaW4gY29vcmRpbmF0ZXMgYXJyYXlcblx0dGhpcy5pID0gaTtcblxuXHQvLyB2ZXJ0ZXggY29vcmRpbmF0ZXNcblx0dGhpcy54ID0geDtcblx0dGhpcy55ID0geTtcblxuXHQvLyBwcmV2aW91cyBhbmQgbmV4dCB2ZXJ0ZXggbm9kZXMgaW4gYSBwb2x5Z29uIHJpbmdcblx0dGhpcy5wcmV2ID0gbnVsbDtcblx0dGhpcy5uZXh0ID0gbnVsbDtcblxuXHQvLyB6LW9yZGVyIGN1cnZlIHZhbHVlXG5cdHRoaXMueiA9IDA7XG5cblx0Ly8gcHJldmlvdXMgYW5kIG5leHQgbm9kZXMgaW4gei1vcmRlclxuXHR0aGlzLnByZXZaID0gbnVsbDtcblx0dGhpcy5uZXh0WiA9IG51bGw7XG5cblx0Ly8gaW5kaWNhdGVzIHdoZXRoZXIgdGhpcyBpcyBhIHN0ZWluZXIgcG9pbnRcblx0dGhpcy5zdGVpbmVyID0gZmFsc2U7XG5cbn1cblxuZnVuY3Rpb24gc2lnbmVkQXJlYSggZGF0YSwgc3RhcnQsIGVuZCwgZGltICkge1xuXG5cdGxldCBzdW0gPSAwO1xuXHRmb3IgKCBsZXQgaSA9IHN0YXJ0LCBqID0gZW5kIC0gZGltOyBpIDwgZW5kOyBpICs9IGRpbSApIHtcblxuXHRcdHN1bSArPSAoIGRhdGFbIGogXSAtIGRhdGFbIGkgXSApICogKCBkYXRhWyBpICsgMSBdICsgZGF0YVsgaiArIDEgXSApO1xuXHRcdGogPSBpO1xuXG5cdH1cblxuXHRyZXR1cm4gc3VtO1xuXG59XG5cbmNsYXNzIFNoYXBlVXRpbHMge1xuXG5cdC8vIGNhbGN1bGF0ZSBhcmVhIG9mIHRoZSBjb250b3VyIHBvbHlnb25cblxuXHRzdGF0aWMgYXJlYSggY29udG91ciApIHtcblxuXHRcdGNvbnN0IG4gPSBjb250b3VyLmxlbmd0aDtcblx0XHRsZXQgYSA9IDAuMDtcblxuXHRcdGZvciAoIGxldCBwID0gbiAtIDEsIHEgPSAwOyBxIDwgbjsgcCA9IHEgKysgKSB7XG5cblx0XHRcdGEgKz0gY29udG91clsgcCBdLnggKiBjb250b3VyWyBxIF0ueSAtIGNvbnRvdXJbIHEgXS54ICogY29udG91clsgcCBdLnk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gYSAqIDAuNTtcblxuXHR9XG5cblx0c3RhdGljIGlzQ2xvY2tXaXNlKCBwdHMgKSB7XG5cblx0XHRyZXR1cm4gU2hhcGVVdGlscy5hcmVhKCBwdHMgKSA8IDA7XG5cblx0fVxuXG5cdHN0YXRpYyB0cmlhbmd1bGF0ZVNoYXBlKCBjb250b3VyLCBob2xlcyApIHtcblxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107IC8vIGZsYXQgYXJyYXkgb2YgdmVydGljZXMgbGlrZSBbIHgwLHkwLCB4MSx5MSwgeDIseTIsIC4uLiBdXG5cdFx0Y29uc3QgaG9sZUluZGljZXMgPSBbXTsgLy8gYXJyYXkgb2YgaG9sZSBpbmRpY2VzXG5cdFx0Y29uc3QgZmFjZXMgPSBbXTsgLy8gZmluYWwgYXJyYXkgb2YgdmVydGV4IGluZGljZXMgbGlrZSBbIFsgYSxiLGQgXSwgWyBiLGMsZCBdIF1cblxuXHRcdHJlbW92ZUR1cEVuZFB0cyggY29udG91ciApO1xuXHRcdGFkZENvbnRvdXIoIHZlcnRpY2VzLCBjb250b3VyICk7XG5cblx0XHQvL1xuXG5cdFx0bGV0IGhvbGVJbmRleCA9IGNvbnRvdXIubGVuZ3RoO1xuXG5cdFx0aG9sZXMuZm9yRWFjaCggcmVtb3ZlRHVwRW5kUHRzICk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBob2xlcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdGhvbGVJbmRpY2VzLnB1c2goIGhvbGVJbmRleCApO1xuXHRcdFx0aG9sZUluZGV4ICs9IGhvbGVzWyBpIF0ubGVuZ3RoO1xuXHRcdFx0YWRkQ29udG91ciggdmVydGljZXMsIGhvbGVzWyBpIF0gKTtcblxuXHRcdH1cblxuXHRcdC8vXG5cblx0XHRjb25zdCB0cmlhbmdsZXMgPSBFYXJjdXQudHJpYW5ndWxhdGUoIHZlcnRpY2VzLCBob2xlSW5kaWNlcyApO1xuXG5cdFx0Ly9cblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRyaWFuZ2xlcy5sZW5ndGg7IGkgKz0gMyApIHtcblxuXHRcdFx0ZmFjZXMucHVzaCggdHJpYW5nbGVzLnNsaWNlKCBpLCBpICsgMyApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gZmFjZXM7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIHJlbW92ZUR1cEVuZFB0cyggcG9pbnRzICkge1xuXG5cdGNvbnN0IGwgPSBwb2ludHMubGVuZ3RoO1xuXG5cdGlmICggbCA+IDIgJiYgcG9pbnRzWyBsIC0gMSBdLmVxdWFscyggcG9pbnRzWyAwIF0gKSApIHtcblxuXHRcdHBvaW50cy5wb3AoKTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gYWRkQ29udG91ciggdmVydGljZXMsIGNvbnRvdXIgKSB7XG5cblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY29udG91ci5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHR2ZXJ0aWNlcy5wdXNoKCBjb250b3VyWyBpIF0ueCApO1xuXHRcdHZlcnRpY2VzLnB1c2goIGNvbnRvdXJbIGkgXS55ICk7XG5cblx0fVxuXG59XG5cbi8qKlxuICogQ3JlYXRlcyBleHRydWRlZCBnZW9tZXRyeSBmcm9tIGEgcGF0aCBzaGFwZS5cbiAqXG4gKiBwYXJhbWV0ZXJzID0ge1xuICpcbiAqICBjdXJ2ZVNlZ21lbnRzOiA8aW50PiwgLy8gbnVtYmVyIG9mIHBvaW50cyBvbiB0aGUgY3VydmVzXG4gKiAgc3RlcHM6IDxpbnQ+LCAvLyBudW1iZXIgb2YgcG9pbnRzIGZvciB6LXNpZGUgZXh0cnVzaW9ucyAvIHVzZWQgZm9yIHN1YmRpdmlkaW5nIHNlZ21lbnRzIG9mIGV4dHJ1ZGUgc3BsaW5lIHRvb1xuICogIGRlcHRoOiA8ZmxvYXQ+LCAvLyBEZXB0aCB0byBleHRydWRlIHRoZSBzaGFwZVxuICpcbiAqICBiZXZlbEVuYWJsZWQ6IDxib29sPiwgLy8gdHVybiBvbiBiZXZlbFxuICogIGJldmVsVGhpY2tuZXNzOiA8ZmxvYXQ+LCAvLyBob3cgZGVlcCBpbnRvIHRoZSBvcmlnaW5hbCBzaGFwZSBiZXZlbCBnb2VzXG4gKiAgYmV2ZWxTaXplOiA8ZmxvYXQ+LCAvLyBob3cgZmFyIGZyb20gc2hhcGUgb3V0bGluZSAoaW5jbHVkaW5nIGJldmVsT2Zmc2V0KSBpcyBiZXZlbFxuICogIGJldmVsT2Zmc2V0OiA8ZmxvYXQ+LCAvLyBob3cgZmFyIGZyb20gc2hhcGUgb3V0bGluZSBkb2VzIGJldmVsIHN0YXJ0XG4gKiAgYmV2ZWxTZWdtZW50czogPGludD4sIC8vIG51bWJlciBvZiBiZXZlbCBsYXllcnNcbiAqXG4gKiAgZXh0cnVkZVBhdGg6IDxUSFJFRS5DdXJ2ZT4gLy8gY3VydmUgdG8gZXh0cnVkZSBzaGFwZSBhbG9uZ1xuICpcbiAqICBVVkdlbmVyYXRvcjogPE9iamVjdD4gLy8gb2JqZWN0IHRoYXQgcHJvdmlkZXMgVVYgZ2VuZXJhdG9yIGZ1bmN0aW9uc1xuICpcbiAqIH1cbiAqL1xuXG5cbmNsYXNzIEV4dHJ1ZGVHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3Rvciggc2hhcGVzID0gbmV3IFNoYXBlKCBbIG5ldyBWZWN0b3IyKCAwLjUsIDAuNSApLCBuZXcgVmVjdG9yMiggLSAwLjUsIDAuNSApLCBuZXcgVmVjdG9yMiggLSAwLjUsIC0gMC41ICksIG5ldyBWZWN0b3IyKCAwLjUsIC0gMC41ICkgXSApLCBvcHRpb25zID0ge30gKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ0V4dHJ1ZGVHZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRzaGFwZXM6IHNoYXBlcyxcblx0XHRcdG9wdGlvbnM6IG9wdGlvbnNcblx0XHR9O1xuXG5cdFx0c2hhcGVzID0gQXJyYXkuaXNBcnJheSggc2hhcGVzICkgPyBzaGFwZXMgOiBbIHNoYXBlcyBdO1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0Y29uc3QgdmVydGljZXNBcnJheSA9IFtdO1xuXHRcdGNvbnN0IHV2QXJyYXkgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNoYXBlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBzaGFwZSA9IHNoYXBlc1sgaSBdO1xuXHRcdFx0YWRkU2hhcGUoIHNoYXBlICk7XG5cblx0XHR9XG5cblx0XHQvLyBidWlsZCBnZW9tZXRyeVxuXG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlc0FycmF5LCAzICkgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2QXJyYXksIDIgKSApO1xuXG5cdFx0dGhpcy5jb21wdXRlVmVydGV4Tm9ybWFscygpO1xuXG5cdFx0Ly8gZnVuY3Rpb25zXG5cblx0XHRmdW5jdGlvbiBhZGRTaGFwZSggc2hhcGUgKSB7XG5cblx0XHRcdGNvbnN0IHBsYWNlaG9sZGVyID0gW107XG5cblx0XHRcdC8vIG9wdGlvbnNcblxuXHRcdFx0Y29uc3QgY3VydmVTZWdtZW50cyA9IG9wdGlvbnMuY3VydmVTZWdtZW50cyAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5jdXJ2ZVNlZ21lbnRzIDogMTI7XG5cdFx0XHRjb25zdCBzdGVwcyA9IG9wdGlvbnMuc3RlcHMgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuc3RlcHMgOiAxO1xuXHRcdFx0Y29uc3QgZGVwdGggPSBvcHRpb25zLmRlcHRoICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmRlcHRoIDogMTtcblxuXHRcdFx0bGV0IGJldmVsRW5hYmxlZCA9IG9wdGlvbnMuYmV2ZWxFbmFibGVkICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmJldmVsRW5hYmxlZCA6IHRydWU7XG5cdFx0XHRsZXQgYmV2ZWxUaGlja25lc3MgPSBvcHRpb25zLmJldmVsVGhpY2tuZXNzICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmJldmVsVGhpY2tuZXNzIDogMC4yO1xuXHRcdFx0bGV0IGJldmVsU2l6ZSA9IG9wdGlvbnMuYmV2ZWxTaXplICE9PSB1bmRlZmluZWQgPyBvcHRpb25zLmJldmVsU2l6ZSA6IGJldmVsVGhpY2tuZXNzIC0gMC4xO1xuXHRcdFx0bGV0IGJldmVsT2Zmc2V0ID0gb3B0aW9ucy5iZXZlbE9mZnNldCAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5iZXZlbE9mZnNldCA6IDA7XG5cdFx0XHRsZXQgYmV2ZWxTZWdtZW50cyA9IG9wdGlvbnMuYmV2ZWxTZWdtZW50cyAhPT0gdW5kZWZpbmVkID8gb3B0aW9ucy5iZXZlbFNlZ21lbnRzIDogMztcblxuXHRcdFx0Y29uc3QgZXh0cnVkZVBhdGggPSBvcHRpb25zLmV4dHJ1ZGVQYXRoO1xuXG5cdFx0XHRjb25zdCB1dmdlbiA9IG9wdGlvbnMuVVZHZW5lcmF0b3IgIT09IHVuZGVmaW5lZCA/IG9wdGlvbnMuVVZHZW5lcmF0b3IgOiBXb3JsZFVWR2VuZXJhdG9yO1xuXG5cdFx0XHQvL1xuXG5cdFx0XHRsZXQgZXh0cnVkZVB0cywgZXh0cnVkZUJ5UGF0aCA9IGZhbHNlO1xuXHRcdFx0bGV0IHNwbGluZVR1YmUsIGJpbm9ybWFsLCBub3JtYWwsIHBvc2l0aW9uMjtcblxuXHRcdFx0aWYgKCBleHRydWRlUGF0aCApIHtcblxuXHRcdFx0XHRleHRydWRlUHRzID0gZXh0cnVkZVBhdGguZ2V0U3BhY2VkUG9pbnRzKCBzdGVwcyApO1xuXG5cdFx0XHRcdGV4dHJ1ZGVCeVBhdGggPSB0cnVlO1xuXHRcdFx0XHRiZXZlbEVuYWJsZWQgPSBmYWxzZTsgLy8gYmV2ZWxzIG5vdCBzdXBwb3J0ZWQgZm9yIHBhdGggZXh0cnVzaW9uXG5cblx0XHRcdFx0Ly8gU0VUVVAgVE5CIHZhcmlhYmxlc1xuXG5cdFx0XHRcdC8vIFRPRE8xIC0gaGF2ZSBhIC5pc0Nsb3NlZCBpbiBzcGxpbmU/XG5cblx0XHRcdFx0c3BsaW5lVHViZSA9IGV4dHJ1ZGVQYXRoLmNvbXB1dGVGcmVuZXRGcmFtZXMoIHN0ZXBzLCBmYWxzZSApO1xuXG5cdFx0XHRcdC8vIGNvbnNvbGUubG9nKHNwbGluZVR1YmUsICdzcGxpbmVUdWJlJywgc3BsaW5lVHViZS5ub3JtYWxzLmxlbmd0aCwgJ3N0ZXBzJywgc3RlcHMsICdleHRydWRlUHRzJywgZXh0cnVkZVB0cy5sZW5ndGgpO1xuXG5cdFx0XHRcdGJpbm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcblx0XHRcdFx0bm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcblx0XHRcdFx0cG9zaXRpb24yID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBTYWZlZ3VhcmRzIGlmIGJldmVscyBhcmUgbm90IGVuYWJsZWRcblxuXHRcdFx0aWYgKCAhIGJldmVsRW5hYmxlZCApIHtcblxuXHRcdFx0XHRiZXZlbFNlZ21lbnRzID0gMDtcblx0XHRcdFx0YmV2ZWxUaGlja25lc3MgPSAwO1xuXHRcdFx0XHRiZXZlbFNpemUgPSAwO1xuXHRcdFx0XHRiZXZlbE9mZnNldCA9IDA7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gVmFyaWFibGVzIGluaXRpYWxpemF0aW9uXG5cblx0XHRcdGNvbnN0IHNoYXBlUG9pbnRzID0gc2hhcGUuZXh0cmFjdFBvaW50cyggY3VydmVTZWdtZW50cyApO1xuXG5cdFx0XHRsZXQgdmVydGljZXMgPSBzaGFwZVBvaW50cy5zaGFwZTtcblx0XHRcdGNvbnN0IGhvbGVzID0gc2hhcGVQb2ludHMuaG9sZXM7XG5cblx0XHRcdGNvbnN0IHJldmVyc2UgPSAhIFNoYXBlVXRpbHMuaXNDbG9ja1dpc2UoIHZlcnRpY2VzICk7XG5cblx0XHRcdGlmICggcmV2ZXJzZSApIHtcblxuXHRcdFx0XHR2ZXJ0aWNlcyA9IHZlcnRpY2VzLnJldmVyc2UoKTtcblxuXHRcdFx0XHQvLyBNYXliZSB3ZSBzaG91bGQgYWxzbyBjaGVjayBpZiBob2xlcyBhcmUgaW4gdGhlIG9wcG9zaXRlIGRpcmVjdGlvbiwganVzdCB0byBiZSBzYWZlIC4uLlxuXG5cdFx0XHRcdGZvciAoIGxldCBoID0gMCwgaGwgPSBob2xlcy5sZW5ndGg7IGggPCBobDsgaCArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcblxuXHRcdFx0XHRcdGlmICggU2hhcGVVdGlscy5pc0Nsb2NrV2lzZSggYWhvbGUgKSApIHtcblxuXHRcdFx0XHRcdFx0aG9sZXNbIGggXSA9IGFob2xlLnJldmVyc2UoKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXG5cdFx0XHRjb25zdCBmYWNlcyA9IFNoYXBlVXRpbHMudHJpYW5ndWxhdGVTaGFwZSggdmVydGljZXMsIGhvbGVzICk7XG5cblx0XHRcdC8qIFZlcnRpY2VzICovXG5cblx0XHRcdGNvbnN0IGNvbnRvdXIgPSB2ZXJ0aWNlczsgLy8gdmVydGljZXMgaGFzIGFsbCBwb2ludHMgYnV0IGNvbnRvdXIgaGFzIG9ubHkgcG9pbnRzIG9mIGNpcmN1bWZlcmVuY2VcblxuXHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcblxuXHRcdFx0XHR2ZXJ0aWNlcyA9IHZlcnRpY2VzLmNvbmNhdCggYWhvbGUgKTtcblxuXHRcdFx0fVxuXG5cblx0XHRcdGZ1bmN0aW9uIHNjYWxlUHQyKCBwdCwgdmVjLCBzaXplICkge1xuXG5cdFx0XHRcdGlmICggISB2ZWMgKSBjb25zb2xlLmVycm9yKCAnVEhSRUUuRXh0cnVkZUdlb21ldHJ5OiB2ZWMgZG9lcyBub3QgZXhpc3QnICk7XG5cblx0XHRcdFx0cmV0dXJuIHB0LmNsb25lKCkuYWRkU2NhbGVkVmVjdG9yKCB2ZWMsIHNpemUgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCB2bGVuID0gdmVydGljZXMubGVuZ3RoLCBmbGVuID0gZmFjZXMubGVuZ3RoO1xuXG5cblx0XHRcdC8vIEZpbmQgZGlyZWN0aW9ucyBmb3IgcG9pbnQgbW92ZW1lbnRcblxuXG5cdFx0XHRmdW5jdGlvbiBnZXRCZXZlbFZlYyggaW5QdCwgaW5QcmV2LCBpbk5leHQgKSB7XG5cblx0XHRcdFx0Ly8gY29tcHV0ZXMgZm9yIGluUHQgdGhlIGNvcnJlc3BvbmRpbmcgcG9pbnQgaW5QdCcgb24gYSBuZXcgY29udG91clxuXHRcdFx0XHQvLyAgIHNoaWZ0ZWQgYnkgMSB1bml0IChsZW5ndGggb2Ygbm9ybWFsaXplZCB2ZWN0b3IpIHRvIHRoZSBsZWZ0XG5cdFx0XHRcdC8vIGlmIHdlIHdhbGsgYWxvbmcgY29udG91ciBjbG9ja3dpc2UsIHRoaXMgbmV3IGNvbnRvdXIgaXMgb3V0c2lkZSB0aGUgb2xkIG9uZVxuXHRcdFx0XHQvL1xuXHRcdFx0XHQvLyBpblB0JyBpcyB0aGUgaW50ZXJzZWN0aW9uIG9mIHRoZSB0d28gbGluZXMgcGFyYWxsZWwgdG8gdGhlIHR3b1xuXHRcdFx0XHQvLyAgYWRqYWNlbnQgZWRnZXMgb2YgaW5QdCBhdCBhIGRpc3RhbmNlIG9mIDEgdW5pdCBvbiB0aGUgbGVmdCBzaWRlLlxuXG5cdFx0XHRcdGxldCB2X3RyYW5zX3gsIHZfdHJhbnNfeSwgc2hyaW5rX2J5OyAvLyByZXN1bHRpbmcgdHJhbnNsYXRpb24gdmVjdG9yIGZvciBpblB0XG5cblx0XHRcdFx0Ly8gZ29vZCByZWFkaW5nIGZvciBnZW9tZXRyeSBhbGdvcml0aG1zIChoZXJlOiBsaW5lLWxpbmUgaW50ZXJzZWN0aW9uKVxuXHRcdFx0XHQvLyBodHRwOi8vZ2VvbWFsZ29yaXRobXMuY29tL2EwNS1faW50ZXJzZWN0LTEuaHRtbFxuXG5cdFx0XHRcdGNvbnN0IHZfcHJldl94ID0gaW5QdC54IC0gaW5QcmV2LngsXG5cdFx0XHRcdFx0dl9wcmV2X3kgPSBpblB0LnkgLSBpblByZXYueTtcblx0XHRcdFx0Y29uc3Qgdl9uZXh0X3ggPSBpbk5leHQueCAtIGluUHQueCxcblx0XHRcdFx0XHR2X25leHRfeSA9IGluTmV4dC55IC0gaW5QdC55O1xuXG5cdFx0XHRcdGNvbnN0IHZfcHJldl9sZW5zcSA9ICggdl9wcmV2X3ggKiB2X3ByZXZfeCArIHZfcHJldl95ICogdl9wcmV2X3kgKTtcblxuXHRcdFx0XHQvLyBjaGVjayBmb3IgY29sbGluZWFyIGVkZ2VzXG5cdFx0XHRcdGNvbnN0IGNvbGxpbmVhcjAgPSAoIHZfcHJldl94ICogdl9uZXh0X3kgLSB2X3ByZXZfeSAqIHZfbmV4dF94ICk7XG5cblx0XHRcdFx0aWYgKCBNYXRoLmFicyggY29sbGluZWFyMCApID4gTnVtYmVyLkVQU0lMT04gKSB7XG5cblx0XHRcdFx0XHQvLyBub3QgY29sbGluZWFyXG5cblx0XHRcdFx0XHQvLyBsZW5ndGggb2YgdmVjdG9ycyBmb3Igbm9ybWFsaXppbmdcblxuXHRcdFx0XHRcdGNvbnN0IHZfcHJldl9sZW4gPSBNYXRoLnNxcnQoIHZfcHJldl9sZW5zcSApO1xuXHRcdFx0XHRcdGNvbnN0IHZfbmV4dF9sZW4gPSBNYXRoLnNxcnQoIHZfbmV4dF94ICogdl9uZXh0X3ggKyB2X25leHRfeSAqIHZfbmV4dF95ICk7XG5cblx0XHRcdFx0XHQvLyBzaGlmdCBhZGphY2VudCBwb2ludHMgYnkgdW5pdCB2ZWN0b3JzIHRvIHRoZSBsZWZ0XG5cblx0XHRcdFx0XHRjb25zdCBwdFByZXZTaGlmdF94ID0gKCBpblByZXYueCAtIHZfcHJldl95IC8gdl9wcmV2X2xlbiApO1xuXHRcdFx0XHRcdGNvbnN0IHB0UHJldlNoaWZ0X3kgPSAoIGluUHJldi55ICsgdl9wcmV2X3ggLyB2X3ByZXZfbGVuICk7XG5cblx0XHRcdFx0XHRjb25zdCBwdE5leHRTaGlmdF94ID0gKCBpbk5leHQueCAtIHZfbmV4dF95IC8gdl9uZXh0X2xlbiApO1xuXHRcdFx0XHRcdGNvbnN0IHB0TmV4dFNoaWZ0X3kgPSAoIGluTmV4dC55ICsgdl9uZXh0X3ggLyB2X25leHRfbGVuICk7XG5cblx0XHRcdFx0XHQvLyBzY2FsaW5nIGZhY3RvciBmb3Igdl9wcmV2IHRvIGludGVyc2VjdGlvbiBwb2ludFxuXG5cdFx0XHRcdFx0Y29uc3Qgc2YgPSAoICggcHROZXh0U2hpZnRfeCAtIHB0UHJldlNoaWZ0X3ggKSAqIHZfbmV4dF95IC1cblx0XHRcdFx0XHRcdFx0KCBwdE5leHRTaGlmdF95IC0gcHRQcmV2U2hpZnRfeSApICogdl9uZXh0X3ggKSAvXG5cdFx0XHRcdFx0XHQoIHZfcHJldl94ICogdl9uZXh0X3kgLSB2X3ByZXZfeSAqIHZfbmV4dF94ICk7XG5cblx0XHRcdFx0XHQvLyB2ZWN0b3IgZnJvbSBpblB0IHRvIGludGVyc2VjdGlvbiBwb2ludFxuXG5cdFx0XHRcdFx0dl90cmFuc194ID0gKCBwdFByZXZTaGlmdF94ICsgdl9wcmV2X3ggKiBzZiAtIGluUHQueCApO1xuXHRcdFx0XHRcdHZfdHJhbnNfeSA9ICggcHRQcmV2U2hpZnRfeSArIHZfcHJldl95ICogc2YgLSBpblB0LnkgKTtcblxuXHRcdFx0XHRcdC8vIERvbid0IG5vcm1hbGl6ZSEsIG90aGVyd2lzZSBzaGFycCBjb3JuZXJzIGJlY29tZSB1Z2x5XG5cdFx0XHRcdFx0Ly8gIGJ1dCBwcmV2ZW50IGNyYXp5IHNwaWtlc1xuXHRcdFx0XHRcdGNvbnN0IHZfdHJhbnNfbGVuc3EgPSAoIHZfdHJhbnNfeCAqIHZfdHJhbnNfeCArIHZfdHJhbnNfeSAqIHZfdHJhbnNfeSApO1xuXHRcdFx0XHRcdGlmICggdl90cmFuc19sZW5zcSA8PSAyICkge1xuXG5cdFx0XHRcdFx0XHRyZXR1cm4gbmV3IFZlY3RvcjIoIHZfdHJhbnNfeCwgdl90cmFuc195ICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRzaHJpbmtfYnkgPSBNYXRoLnNxcnQoIHZfdHJhbnNfbGVuc3EgLyAyICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdC8vIGhhbmRsZSBzcGVjaWFsIGNhc2Ugb2YgY29sbGluZWFyIGVkZ2VzXG5cblx0XHRcdFx0XHRsZXQgZGlyZWN0aW9uX2VxID0gZmFsc2U7IC8vIGFzc3VtZXM6IG9wcG9zaXRlXG5cblx0XHRcdFx0XHRpZiAoIHZfcHJldl94ID4gTnVtYmVyLkVQU0lMT04gKSB7XG5cblx0XHRcdFx0XHRcdGlmICggdl9uZXh0X3ggPiBOdW1iZXIuRVBTSUxPTiApIHtcblxuXHRcdFx0XHRcdFx0XHRkaXJlY3Rpb25fZXEgPSB0cnVlO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRpZiAoIHZfcHJldl94IDwgLSBOdW1iZXIuRVBTSUxPTiApIHtcblxuXHRcdFx0XHRcdFx0XHRpZiAoIHZfbmV4dF94IDwgLSBOdW1iZXIuRVBTSUxPTiApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGRpcmVjdGlvbl9lcSA9IHRydWU7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggTWF0aC5zaWduKCB2X3ByZXZfeSApID09PSBNYXRoLnNpZ24oIHZfbmV4dF95ICkgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRkaXJlY3Rpb25fZXEgPSB0cnVlO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCBkaXJlY3Rpb25fZXEgKSB7XG5cblx0XHRcdFx0XHRcdC8vIGNvbnNvbGUubG9nKFwiV2FybmluZzogbGluZXMgYXJlIGEgc3RyYWlnaHQgc2VxdWVuY2VcIik7XG5cdFx0XHRcdFx0XHR2X3RyYW5zX3ggPSAtIHZfcHJldl95O1xuXHRcdFx0XHRcdFx0dl90cmFuc195ID0gdl9wcmV2X3g7XG5cdFx0XHRcdFx0XHRzaHJpbmtfYnkgPSBNYXRoLnNxcnQoIHZfcHJldl9sZW5zcSApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0Ly8gY29uc29sZS5sb2coXCJXYXJuaW5nOiBsaW5lcyBhcmUgYSBzdHJhaWdodCBzcGlrZVwiKTtcblx0XHRcdFx0XHRcdHZfdHJhbnNfeCA9IHZfcHJldl94O1xuXHRcdFx0XHRcdFx0dl90cmFuc195ID0gdl9wcmV2X3k7XG5cdFx0XHRcdFx0XHRzaHJpbmtfYnkgPSBNYXRoLnNxcnQoIHZfcHJldl9sZW5zcSAvIDIgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0cmV0dXJuIG5ldyBWZWN0b3IyKCB2X3RyYW5zX3ggLyBzaHJpbmtfYnksIHZfdHJhbnNfeSAvIHNocmlua19ieSApO1xuXG5cdFx0XHR9XG5cblxuXHRcdFx0Y29uc3QgY29udG91ck1vdmVtZW50cyA9IFtdO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gY29udG91ci5sZW5ndGgsIGogPSBpbCAtIDEsIGsgPSBpICsgMTsgaSA8IGlsOyBpICsrLCBqICsrLCBrICsrICkge1xuXG5cdFx0XHRcdGlmICggaiA9PT0gaWwgKSBqID0gMDtcblx0XHRcdFx0aWYgKCBrID09PSBpbCApIGsgPSAwO1xuXG5cdFx0XHRcdC8vICAoaiktLS0oaSktLS0oaylcblx0XHRcdFx0Ly8gY29uc29sZS5sb2coJ2ksaixrJywgaSwgaiAsIGspXG5cblx0XHRcdFx0Y29udG91ck1vdmVtZW50c1sgaSBdID0gZ2V0QmV2ZWxWZWMoIGNvbnRvdXJbIGkgXSwgY29udG91clsgaiBdLCBjb250b3VyWyBrIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBob2xlc01vdmVtZW50cyA9IFtdO1xuXHRcdFx0bGV0IG9uZUhvbGVNb3ZlbWVudHMsIHZlcnRpY2VzTW92ZW1lbnRzID0gY29udG91ck1vdmVtZW50cy5jb25jYXQoKTtcblxuXHRcdFx0Zm9yICggbGV0IGggPSAwLCBobCA9IGhvbGVzLmxlbmd0aDsgaCA8IGhsOyBoICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcblxuXHRcdFx0XHRvbmVIb2xlTW92ZW1lbnRzID0gW107XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGFob2xlLmxlbmd0aCwgaiA9IGlsIC0gMSwgayA9IGkgKyAxOyBpIDwgaWw7IGkgKyssIGogKyssIGsgKysgKSB7XG5cblx0XHRcdFx0XHRpZiAoIGogPT09IGlsICkgaiA9IDA7XG5cdFx0XHRcdFx0aWYgKCBrID09PSBpbCApIGsgPSAwO1xuXG5cdFx0XHRcdFx0Ly8gIChqKS0tLShpKS0tLShrKVxuXHRcdFx0XHRcdG9uZUhvbGVNb3ZlbWVudHNbIGkgXSA9IGdldEJldmVsVmVjKCBhaG9sZVsgaSBdLCBhaG9sZVsgaiBdLCBhaG9sZVsgayBdICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGhvbGVzTW92ZW1lbnRzLnB1c2goIG9uZUhvbGVNb3ZlbWVudHMgKTtcblx0XHRcdFx0dmVydGljZXNNb3ZlbWVudHMgPSB2ZXJ0aWNlc01vdmVtZW50cy5jb25jYXQoIG9uZUhvbGVNb3ZlbWVudHMgKTtcblxuXHRcdFx0fVxuXG5cblx0XHRcdC8vIExvb3AgYmV2ZWxTZWdtZW50cywgMSBmb3IgdGhlIGZyb250LCAxIGZvciB0aGUgYmFja1xuXG5cdFx0XHRmb3IgKCBsZXQgYiA9IDA7IGIgPCBiZXZlbFNlZ21lbnRzOyBiICsrICkge1xuXG5cdFx0XHRcdC8vZm9yICggYiA9IGJldmVsU2VnbWVudHM7IGIgPiAwOyBiIC0tICkge1xuXG5cdFx0XHRcdGNvbnN0IHQgPSBiIC8gYmV2ZWxTZWdtZW50cztcblx0XHRcdFx0Y29uc3QgeiA9IGJldmVsVGhpY2tuZXNzICogTWF0aC5jb3MoIHQgKiBNYXRoLlBJIC8gMiApO1xuXHRcdFx0XHRjb25zdCBicyA9IGJldmVsU2l6ZSAqIE1hdGguc2luKCB0ICogTWF0aC5QSSAvIDIgKSArIGJldmVsT2Zmc2V0O1xuXG5cdFx0XHRcdC8vIGNvbnRyYWN0IHNoYXBlXG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGNvbnRvdXIubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB2ZXJ0ID0gc2NhbGVQdDIoIGNvbnRvdXJbIGkgXSwgY29udG91ck1vdmVtZW50c1sgaSBdLCBicyApO1xuXG5cdFx0XHRcdFx0diggdmVydC54LCB2ZXJ0LnksIC0geiApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBleHBhbmQgaG9sZXNcblxuXHRcdFx0XHRmb3IgKCBsZXQgaCA9IDAsIGhsID0gaG9sZXMubGVuZ3RoOyBoIDwgaGw7IGggKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBhaG9sZSA9IGhvbGVzWyBoIF07XG5cdFx0XHRcdFx0b25lSG9sZU1vdmVtZW50cyA9IGhvbGVzTW92ZW1lbnRzWyBoIF07XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYWhvbGUubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IHZlcnQgPSBzY2FsZVB0MiggYWhvbGVbIGkgXSwgb25lSG9sZU1vdmVtZW50c1sgaSBdLCBicyApO1xuXG5cdFx0XHRcdFx0XHR2KCB2ZXJ0LngsIHZlcnQueSwgLSB6ICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGJzID0gYmV2ZWxTaXplICsgYmV2ZWxPZmZzZXQ7XG5cblx0XHRcdC8vIEJhY2sgZmFjaW5nIHZlcnRpY2VzXG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHZsZW47IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgdmVydCA9IGJldmVsRW5hYmxlZCA/IHNjYWxlUHQyKCB2ZXJ0aWNlc1sgaSBdLCB2ZXJ0aWNlc01vdmVtZW50c1sgaSBdLCBicyApIDogdmVydGljZXNbIGkgXTtcblxuXHRcdFx0XHRpZiAoICEgZXh0cnVkZUJ5UGF0aCApIHtcblxuXHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCAwICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdC8vIHYoIHZlcnQueCwgdmVydC55ICsgZXh0cnVkZVB0c1sgMCBdLnksIGV4dHJ1ZGVQdHNbIDAgXS54ICk7XG5cblx0XHRcdFx0XHRub3JtYWwuY29weSggc3BsaW5lVHViZS5ub3JtYWxzWyAwIF0gKS5tdWx0aXBseVNjYWxhciggdmVydC54ICk7XG5cdFx0XHRcdFx0Ymlub3JtYWwuY29weSggc3BsaW5lVHViZS5iaW5vcm1hbHNbIDAgXSApLm11bHRpcGx5U2NhbGFyKCB2ZXJ0LnkgKTtcblxuXHRcdFx0XHRcdHBvc2l0aW9uMi5jb3B5KCBleHRydWRlUHRzWyAwIF0gKS5hZGQoIG5vcm1hbCApLmFkZCggYmlub3JtYWwgKTtcblxuXHRcdFx0XHRcdHYoIHBvc2l0aW9uMi54LCBwb3NpdGlvbjIueSwgcG9zaXRpb24yLnogKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Ly8gQWRkIHN0ZXBwZWQgdmVydGljZXMuLi5cblx0XHRcdC8vIEluY2x1ZGluZyBmcm9udCBmYWNpbmcgdmVydGljZXNcblxuXHRcdFx0Zm9yICggbGV0IHMgPSAxOyBzIDw9IHN0ZXBzOyBzICsrICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHZsZW47IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB2ZXJ0ID0gYmV2ZWxFbmFibGVkID8gc2NhbGVQdDIoIHZlcnRpY2VzWyBpIF0sIHZlcnRpY2VzTW92ZW1lbnRzWyBpIF0sIGJzICkgOiB2ZXJ0aWNlc1sgaSBdO1xuXG5cdFx0XHRcdFx0aWYgKCAhIGV4dHJ1ZGVCeVBhdGggKSB7XG5cblx0XHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCBkZXB0aCAvIHN0ZXBzICogcyApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0Ly8gdiggdmVydC54LCB2ZXJ0LnkgKyBleHRydWRlUHRzWyBzIC0gMSBdLnksIGV4dHJ1ZGVQdHNbIHMgLSAxIF0ueCApO1xuXG5cdFx0XHRcdFx0XHRub3JtYWwuY29weSggc3BsaW5lVHViZS5ub3JtYWxzWyBzIF0gKS5tdWx0aXBseVNjYWxhciggdmVydC54ICk7XG5cdFx0XHRcdFx0XHRiaW5vcm1hbC5jb3B5KCBzcGxpbmVUdWJlLmJpbm9ybWFsc1sgcyBdICkubXVsdGlwbHlTY2FsYXIoIHZlcnQueSApO1xuXG5cdFx0XHRcdFx0XHRwb3NpdGlvbjIuY29weSggZXh0cnVkZVB0c1sgcyBdICkuYWRkKCBub3JtYWwgKS5hZGQoIGJpbm9ybWFsICk7XG5cblx0XHRcdFx0XHRcdHYoIHBvc2l0aW9uMi54LCBwb3NpdGlvbjIueSwgcG9zaXRpb24yLnogKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXG5cdFx0XHQvLyBBZGQgYmV2ZWwgc2VnbWVudHMgcGxhbmVzXG5cblx0XHRcdC8vZm9yICggYiA9IDE7IGIgPD0gYmV2ZWxTZWdtZW50czsgYiArKyApIHtcblx0XHRcdGZvciAoIGxldCBiID0gYmV2ZWxTZWdtZW50cyAtIDE7IGIgPj0gMDsgYiAtLSApIHtcblxuXHRcdFx0XHRjb25zdCB0ID0gYiAvIGJldmVsU2VnbWVudHM7XG5cdFx0XHRcdGNvbnN0IHogPSBiZXZlbFRoaWNrbmVzcyAqIE1hdGguY29zKCB0ICogTWF0aC5QSSAvIDIgKTtcblx0XHRcdFx0Y29uc3QgYnMgPSBiZXZlbFNpemUgKiBNYXRoLnNpbiggdCAqIE1hdGguUEkgLyAyICkgKyBiZXZlbE9mZnNldDtcblxuXHRcdFx0XHQvLyBjb250cmFjdCBzaGFwZVxuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBjb250b3VyLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgdmVydCA9IHNjYWxlUHQyKCBjb250b3VyWyBpIF0sIGNvbnRvdXJNb3ZlbWVudHNbIGkgXSwgYnMgKTtcblx0XHRcdFx0XHR2KCB2ZXJ0LngsIHZlcnQueSwgZGVwdGggKyB6ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIGV4cGFuZCBob2xlc1xuXG5cdFx0XHRcdGZvciAoIGxldCBoID0gMCwgaGwgPSBob2xlcy5sZW5ndGg7IGggPCBobDsgaCArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcblx0XHRcdFx0XHRvbmVIb2xlTW92ZW1lbnRzID0gaG9sZXNNb3ZlbWVudHNbIGggXTtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBhaG9sZS5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgdmVydCA9IHNjYWxlUHQyKCBhaG9sZVsgaSBdLCBvbmVIb2xlTW92ZW1lbnRzWyBpIF0sIGJzICk7XG5cblx0XHRcdFx0XHRcdGlmICggISBleHRydWRlQnlQYXRoICkge1xuXG5cdFx0XHRcdFx0XHRcdHYoIHZlcnQueCwgdmVydC55LCBkZXB0aCArIHogKTtcblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHR2KCB2ZXJ0LngsIHZlcnQueSArIGV4dHJ1ZGVQdHNbIHN0ZXBzIC0gMSBdLnksIGV4dHJ1ZGVQdHNbIHN0ZXBzIC0gMSBdLnggKyB6ICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0LyogRmFjZXMgKi9cblxuXHRcdFx0Ly8gVG9wIGFuZCBib3R0b20gZmFjZXNcblxuXHRcdFx0YnVpbGRMaWRGYWNlcygpO1xuXG5cdFx0XHQvLyBTaWRlcyBmYWNlc1xuXG5cdFx0XHRidWlsZFNpZGVGYWNlcygpO1xuXG5cblx0XHRcdC8vLy8vICBJbnRlcm5hbCBmdW5jdGlvbnNcblxuXHRcdFx0ZnVuY3Rpb24gYnVpbGRMaWRGYWNlcygpIHtcblxuXHRcdFx0XHRjb25zdCBzdGFydCA9IHZlcnRpY2VzQXJyYXkubGVuZ3RoIC8gMztcblxuXHRcdFx0XHRpZiAoIGJldmVsRW5hYmxlZCApIHtcblxuXHRcdFx0XHRcdGxldCBsYXllciA9IDA7IC8vIHN0ZXBzICsgMVxuXHRcdFx0XHRcdGxldCBvZmZzZXQgPSB2bGVuICogbGF5ZXI7XG5cblx0XHRcdFx0XHQvLyBCb3R0b20gZmFjZXNcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGZsZW47IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGZhY2UgPSBmYWNlc1sgaSBdO1xuXHRcdFx0XHRcdFx0ZjMoIGZhY2VbIDIgXSArIG9mZnNldCwgZmFjZVsgMSBdICsgb2Zmc2V0LCBmYWNlWyAwIF0gKyBvZmZzZXQgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGxheWVyID0gc3RlcHMgKyBiZXZlbFNlZ21lbnRzICogMjtcblx0XHRcdFx0XHRvZmZzZXQgPSB2bGVuICogbGF5ZXI7XG5cblx0XHRcdFx0XHQvLyBUb3AgZmFjZXNcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGZsZW47IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGZhY2UgPSBmYWNlc1sgaSBdO1xuXHRcdFx0XHRcdFx0ZjMoIGZhY2VbIDAgXSArIG9mZnNldCwgZmFjZVsgMSBdICsgb2Zmc2V0LCBmYWNlWyAyIF0gKyBvZmZzZXQgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ly8gQm90dG9tIGZhY2VzXG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBmbGVuOyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBmYWNlID0gZmFjZXNbIGkgXTtcblx0XHRcdFx0XHRcdGYzKCBmYWNlWyAyIF0sIGZhY2VbIDEgXSwgZmFjZVsgMCBdICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBUb3AgZmFjZXNcblxuXHRcdFx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IGZsZW47IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGZhY2UgPSBmYWNlc1sgaSBdO1xuXHRcdFx0XHRcdFx0ZjMoIGZhY2VbIDAgXSArIHZsZW4gKiBzdGVwcywgZmFjZVsgMSBdICsgdmxlbiAqIHN0ZXBzLCBmYWNlWyAyIF0gKyB2bGVuICogc3RlcHMgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0c2NvcGUuYWRkR3JvdXAoIHN0YXJ0LCB2ZXJ0aWNlc0FycmF5Lmxlbmd0aCAvIDMgLSBzdGFydCwgMCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIENyZWF0ZSBmYWNlcyBmb3IgdGhlIHotc2lkZXMgb2YgdGhlIHNoYXBlXG5cblx0XHRcdGZ1bmN0aW9uIGJ1aWxkU2lkZUZhY2VzKCkge1xuXG5cdFx0XHRcdGNvbnN0IHN0YXJ0ID0gdmVydGljZXNBcnJheS5sZW5ndGggLyAzO1xuXHRcdFx0XHRsZXQgbGF5ZXJvZmZzZXQgPSAwO1xuXHRcdFx0XHRzaWRld2FsbHMoIGNvbnRvdXIsIGxheWVyb2Zmc2V0ICk7XG5cdFx0XHRcdGxheWVyb2Zmc2V0ICs9IGNvbnRvdXIubGVuZ3RoO1xuXG5cdFx0XHRcdGZvciAoIGxldCBoID0gMCwgaGwgPSBob2xlcy5sZW5ndGg7IGggPCBobDsgaCArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGFob2xlID0gaG9sZXNbIGggXTtcblx0XHRcdFx0XHRzaWRld2FsbHMoIGFob2xlLCBsYXllcm9mZnNldCApO1xuXG5cdFx0XHRcdFx0Ly8sIHRydWVcblx0XHRcdFx0XHRsYXllcm9mZnNldCArPSBhaG9sZS5sZW5ndGg7XG5cblx0XHRcdFx0fVxuXG5cblx0XHRcdFx0c2NvcGUuYWRkR3JvdXAoIHN0YXJ0LCB2ZXJ0aWNlc0FycmF5Lmxlbmd0aCAvIDMgLSBzdGFydCwgMSApO1xuXG5cblx0XHRcdH1cblxuXHRcdFx0ZnVuY3Rpb24gc2lkZXdhbGxzKCBjb250b3VyLCBsYXllcm9mZnNldCApIHtcblxuXHRcdFx0XHRsZXQgaSA9IGNvbnRvdXIubGVuZ3RoO1xuXG5cdFx0XHRcdHdoaWxlICggLS0gaSA+PSAwICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgaiA9IGk7XG5cdFx0XHRcdFx0bGV0IGsgPSBpIC0gMTtcblx0XHRcdFx0XHRpZiAoIGsgPCAwICkgayA9IGNvbnRvdXIubGVuZ3RoIC0gMTtcblxuXHRcdFx0XHRcdC8vY29uc29sZS5sb2coJ2InLCBpLGosIGktMSwgayx2ZXJ0aWNlcy5sZW5ndGgpO1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IHMgPSAwLCBzbCA9ICggc3RlcHMgKyBiZXZlbFNlZ21lbnRzICogMiApOyBzIDwgc2w7IHMgKysgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IHNsZW4xID0gdmxlbiAqIHM7XG5cdFx0XHRcdFx0XHRjb25zdCBzbGVuMiA9IHZsZW4gKiAoIHMgKyAxICk7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGEgPSBsYXllcm9mZnNldCArIGogKyBzbGVuMSxcblx0XHRcdFx0XHRcdFx0YiA9IGxheWVyb2Zmc2V0ICsgayArIHNsZW4xLFxuXHRcdFx0XHRcdFx0XHRjID0gbGF5ZXJvZmZzZXQgKyBrICsgc2xlbjIsXG5cdFx0XHRcdFx0XHRcdGQgPSBsYXllcm9mZnNldCArIGogKyBzbGVuMjtcblxuXHRcdFx0XHRcdFx0ZjQoIGEsIGIsIGMsIGQgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0ZnVuY3Rpb24gdiggeCwgeSwgeiApIHtcblxuXHRcdFx0XHRwbGFjZWhvbGRlci5wdXNoKCB4ICk7XG5cdFx0XHRcdHBsYWNlaG9sZGVyLnB1c2goIHkgKTtcblx0XHRcdFx0cGxhY2Vob2xkZXIucHVzaCggeiApO1xuXG5cdFx0XHR9XG5cblxuXHRcdFx0ZnVuY3Rpb24gZjMoIGEsIGIsIGMgKSB7XG5cblx0XHRcdFx0YWRkVmVydGV4KCBhICk7XG5cdFx0XHRcdGFkZFZlcnRleCggYiApO1xuXHRcdFx0XHRhZGRWZXJ0ZXgoIGMgKTtcblxuXHRcdFx0XHRjb25zdCBuZXh0SW5kZXggPSB2ZXJ0aWNlc0FycmF5Lmxlbmd0aCAvIDM7XG5cdFx0XHRcdGNvbnN0IHV2cyA9IHV2Z2VuLmdlbmVyYXRlVG9wVVYoIHNjb3BlLCB2ZXJ0aWNlc0FycmF5LCBuZXh0SW5kZXggLSAzLCBuZXh0SW5kZXggLSAyLCBuZXh0SW5kZXggLSAxICk7XG5cblx0XHRcdFx0YWRkVVYoIHV2c1sgMCBdICk7XG5cdFx0XHRcdGFkZFVWKCB1dnNbIDEgXSApO1xuXHRcdFx0XHRhZGRVViggdXZzWyAyIF0gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRmdW5jdGlvbiBmNCggYSwgYiwgYywgZCApIHtcblxuXHRcdFx0XHRhZGRWZXJ0ZXgoIGEgKTtcblx0XHRcdFx0YWRkVmVydGV4KCBiICk7XG5cdFx0XHRcdGFkZFZlcnRleCggZCApO1xuXG5cdFx0XHRcdGFkZFZlcnRleCggYiApO1xuXHRcdFx0XHRhZGRWZXJ0ZXgoIGMgKTtcblx0XHRcdFx0YWRkVmVydGV4KCBkICk7XG5cblxuXHRcdFx0XHRjb25zdCBuZXh0SW5kZXggPSB2ZXJ0aWNlc0FycmF5Lmxlbmd0aCAvIDM7XG5cdFx0XHRcdGNvbnN0IHV2cyA9IHV2Z2VuLmdlbmVyYXRlU2lkZVdhbGxVViggc2NvcGUsIHZlcnRpY2VzQXJyYXksIG5leHRJbmRleCAtIDYsIG5leHRJbmRleCAtIDMsIG5leHRJbmRleCAtIDIsIG5leHRJbmRleCAtIDEgKTtcblxuXHRcdFx0XHRhZGRVViggdXZzWyAwIF0gKTtcblx0XHRcdFx0YWRkVVYoIHV2c1sgMSBdICk7XG5cdFx0XHRcdGFkZFVWKCB1dnNbIDMgXSApO1xuXG5cdFx0XHRcdGFkZFVWKCB1dnNbIDEgXSApO1xuXHRcdFx0XHRhZGRVViggdXZzWyAyIF0gKTtcblx0XHRcdFx0YWRkVVYoIHV2c1sgMyBdICk7XG5cblx0XHRcdH1cblxuXHRcdFx0ZnVuY3Rpb24gYWRkVmVydGV4KCBpbmRleCApIHtcblxuXHRcdFx0XHR2ZXJ0aWNlc0FycmF5LnB1c2goIHBsYWNlaG9sZGVyWyBpbmRleCAqIDMgKyAwIF0gKTtcblx0XHRcdFx0dmVydGljZXNBcnJheS5wdXNoKCBwbGFjZWhvbGRlclsgaW5kZXggKiAzICsgMSBdICk7XG5cdFx0XHRcdHZlcnRpY2VzQXJyYXkucHVzaCggcGxhY2Vob2xkZXJbIGluZGV4ICogMyArIDIgXSApO1xuXG5cdFx0XHR9XG5cblxuXHRcdFx0ZnVuY3Rpb24gYWRkVVYoIHZlY3RvcjIgKSB7XG5cblx0XHRcdFx0dXZBcnJheS5wdXNoKCB2ZWN0b3IyLnggKTtcblx0XHRcdFx0dXZBcnJheS5wdXNoKCB2ZWN0b3IyLnkgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcblxuXHRcdGNvbnN0IHNoYXBlcyA9IHRoaXMucGFyYW1ldGVycy5zaGFwZXM7XG5cdFx0Y29uc3Qgb3B0aW9ucyA9IHRoaXMucGFyYW1ldGVycy5vcHRpb25zO1xuXG5cdFx0cmV0dXJuIHRvSlNPTiQxKCBzaGFwZXMsIG9wdGlvbnMsIGRhdGEgKTtcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhLCBzaGFwZXMgKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeVNoYXBlcyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGogPSAwLCBqbCA9IGRhdGEuc2hhcGVzLmxlbmd0aDsgaiA8IGpsOyBqICsrICkge1xuXG5cdFx0XHRjb25zdCBzaGFwZSA9IHNoYXBlc1sgZGF0YS5zaGFwZXNbIGogXSBdO1xuXG5cdFx0XHRnZW9tZXRyeVNoYXBlcy5wdXNoKCBzaGFwZSApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgZXh0cnVkZVBhdGggPSBkYXRhLm9wdGlvbnMuZXh0cnVkZVBhdGg7XG5cblx0XHRpZiAoIGV4dHJ1ZGVQYXRoICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGRhdGEub3B0aW9ucy5leHRydWRlUGF0aCA9IG5ldyBDdXJ2ZXNbIGV4dHJ1ZGVQYXRoLnR5cGUgXSgpLmZyb21KU09OKCBleHRydWRlUGF0aCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG5ldyBFeHRydWRlR2VvbWV0cnkoIGdlb21ldHJ5U2hhcGVzLCBkYXRhLm9wdGlvbnMgKTtcblxuXHR9XG5cbn1cblxuY29uc3QgV29ybGRVVkdlbmVyYXRvciA9IHtcblxuXHRnZW5lcmF0ZVRvcFVWOiBmdW5jdGlvbiAoIGdlb21ldHJ5LCB2ZXJ0aWNlcywgaW5kZXhBLCBpbmRleEIsIGluZGV4QyApIHtcblxuXHRcdGNvbnN0IGFfeCA9IHZlcnRpY2VzWyBpbmRleEEgKiAzIF07XG5cdFx0Y29uc3QgYV95ID0gdmVydGljZXNbIGluZGV4QSAqIDMgKyAxIF07XG5cdFx0Y29uc3QgYl94ID0gdmVydGljZXNbIGluZGV4QiAqIDMgXTtcblx0XHRjb25zdCBiX3kgPSB2ZXJ0aWNlc1sgaW5kZXhCICogMyArIDEgXTtcblx0XHRjb25zdCBjX3ggPSB2ZXJ0aWNlc1sgaW5kZXhDICogMyBdO1xuXHRcdGNvbnN0IGNfeSA9IHZlcnRpY2VzWyBpbmRleEMgKiAzICsgMSBdO1xuXG5cdFx0cmV0dXJuIFtcblx0XHRcdG5ldyBWZWN0b3IyKCBhX3gsIGFfeSApLFxuXHRcdFx0bmV3IFZlY3RvcjIoIGJfeCwgYl95ICksXG5cdFx0XHRuZXcgVmVjdG9yMiggY194LCBjX3kgKVxuXHRcdF07XG5cblx0fSxcblxuXHRnZW5lcmF0ZVNpZGVXYWxsVVY6IGZ1bmN0aW9uICggZ2VvbWV0cnksIHZlcnRpY2VzLCBpbmRleEEsIGluZGV4QiwgaW5kZXhDLCBpbmRleEQgKSB7XG5cblx0XHRjb25zdCBhX3ggPSB2ZXJ0aWNlc1sgaW5kZXhBICogMyBdO1xuXHRcdGNvbnN0IGFfeSA9IHZlcnRpY2VzWyBpbmRleEEgKiAzICsgMSBdO1xuXHRcdGNvbnN0IGFfeiA9IHZlcnRpY2VzWyBpbmRleEEgKiAzICsgMiBdO1xuXHRcdGNvbnN0IGJfeCA9IHZlcnRpY2VzWyBpbmRleEIgKiAzIF07XG5cdFx0Y29uc3QgYl95ID0gdmVydGljZXNbIGluZGV4QiAqIDMgKyAxIF07XG5cdFx0Y29uc3QgYl96ID0gdmVydGljZXNbIGluZGV4QiAqIDMgKyAyIF07XG5cdFx0Y29uc3QgY194ID0gdmVydGljZXNbIGluZGV4QyAqIDMgXTtcblx0XHRjb25zdCBjX3kgPSB2ZXJ0aWNlc1sgaW5kZXhDICogMyArIDEgXTtcblx0XHRjb25zdCBjX3ogPSB2ZXJ0aWNlc1sgaW5kZXhDICogMyArIDIgXTtcblx0XHRjb25zdCBkX3ggPSB2ZXJ0aWNlc1sgaW5kZXhEICogMyBdO1xuXHRcdGNvbnN0IGRfeSA9IHZlcnRpY2VzWyBpbmRleEQgKiAzICsgMSBdO1xuXHRcdGNvbnN0IGRfeiA9IHZlcnRpY2VzWyBpbmRleEQgKiAzICsgMiBdO1xuXG5cdFx0aWYgKCBNYXRoLmFicyggYV95IC0gYl95ICkgPCBNYXRoLmFicyggYV94IC0gYl94ICkgKSB7XG5cblx0XHRcdHJldHVybiBbXG5cdFx0XHRcdG5ldyBWZWN0b3IyKCBhX3gsIDEgLSBhX3ogKSxcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGJfeCwgMSAtIGJfeiApLFxuXHRcdFx0XHRuZXcgVmVjdG9yMiggY194LCAxIC0gY196ICksXG5cdFx0XHRcdG5ldyBWZWN0b3IyKCBkX3gsIDEgLSBkX3ogKVxuXHRcdFx0XTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJldHVybiBbXG5cdFx0XHRcdG5ldyBWZWN0b3IyKCBhX3ksIDEgLSBhX3ogKSxcblx0XHRcdFx0bmV3IFZlY3RvcjIoIGJfeSwgMSAtIGJfeiApLFxuXHRcdFx0XHRuZXcgVmVjdG9yMiggY195LCAxIC0gY196ICksXG5cdFx0XHRcdG5ldyBWZWN0b3IyKCBkX3ksIDEgLSBkX3ogKVxuXHRcdFx0XTtcblxuXHRcdH1cblxuXHR9XG5cbn07XG5cbmZ1bmN0aW9uIHRvSlNPTiQxKCBzaGFwZXMsIG9wdGlvbnMsIGRhdGEgKSB7XG5cblx0ZGF0YS5zaGFwZXMgPSBbXTtcblxuXHRpZiAoIEFycmF5LmlzQXJyYXkoIHNoYXBlcyApICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IHNoYXBlID0gc2hhcGVzWyBpIF07XG5cblx0XHRcdGRhdGEuc2hhcGVzLnB1c2goIHNoYXBlLnV1aWQgKTtcblxuXHRcdH1cblxuXHR9IGVsc2Uge1xuXG5cdFx0ZGF0YS5zaGFwZXMucHVzaCggc2hhcGVzLnV1aWQgKTtcblxuXHR9XG5cblx0ZGF0YS5vcHRpb25zID0gT2JqZWN0LmFzc2lnbigge30sIG9wdGlvbnMgKTtcblxuXHRpZiAoIG9wdGlvbnMuZXh0cnVkZVBhdGggIT09IHVuZGVmaW5lZCApIGRhdGEub3B0aW9ucy5leHRydWRlUGF0aCA9IG9wdGlvbnMuZXh0cnVkZVBhdGgudG9KU09OKCk7XG5cblx0cmV0dXJuIGRhdGE7XG5cbn1cblxuY2xhc3MgSWNvc2FoZWRyb25HZW9tZXRyeSBleHRlbmRzIFBvbHloZWRyb25HZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEsIGRldGFpbCA9IDAgKSB7XG5cblx0XHRjb25zdCB0ID0gKCAxICsgTWF0aC5zcXJ0KCA1ICkgKSAvIDI7XG5cblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtcblx0XHRcdC0gMSwgdCwgMCwgXHQxLCB0LCAwLCBcdC0gMSwgLSB0LCAwLCBcdDEsIC0gdCwgMCxcblx0XHRcdDAsIC0gMSwgdCwgXHQwLCAxLCB0LFx0MCwgLSAxLCAtIHQsIFx0MCwgMSwgLSB0LFxuXHRcdFx0dCwgMCwgLSAxLCBcdHQsIDAsIDEsIFx0LSB0LCAwLCAtIDEsIFx0LSB0LCAwLCAxXG5cdFx0XTtcblxuXHRcdGNvbnN0IGluZGljZXMgPSBbXG5cdFx0XHQwLCAxMSwgNSwgXHQwLCA1LCAxLCBcdDAsIDEsIDcsIFx0MCwgNywgMTAsIFx0MCwgMTAsIDExLFxuXHRcdFx0MSwgNSwgOSwgXHQ1LCAxMSwgNCxcdDExLCAxMCwgMixcdDEwLCA3LCA2LFx0NywgMSwgOCxcblx0XHRcdDMsIDksIDQsIFx0MywgNCwgMixcdDMsIDIsIDYsXHQzLCA2LCA4LFx0MywgOCwgOSxcblx0XHRcdDQsIDksIDUsIFx0MiwgNCwgMTEsXHQ2LCAyLCAxMCxcdDgsIDYsIDcsXHQ5LCA4LCAxXG5cdFx0XTtcblxuXHRcdHN1cGVyKCB2ZXJ0aWNlcywgaW5kaWNlcywgcmFkaXVzLCBkZXRhaWwgKTtcblxuXHRcdHRoaXMudHlwZSA9ICdJY29zYWhlZHJvbkdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHJhZGl1czogcmFkaXVzLFxuXHRcdFx0ZGV0YWlsOiBkZXRhaWxcblx0XHR9O1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IEljb3NhaGVkcm9uR2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLmRldGFpbCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBPY3RhaGVkcm9uR2VvbWV0cnkgZXh0ZW5kcyBQb2x5aGVkcm9uR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBkZXRhaWwgPSAwICkge1xuXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXG5cdFx0XHQxLCAwLCAwLCBcdC0gMSwgMCwgMCxcdDAsIDEsIDAsXG5cdFx0XHQwLCAtIDEsIDAsIFx0MCwgMCwgMSxcdDAsIDAsIC0gMVxuXHRcdF07XG5cblx0XHRjb25zdCBpbmRpY2VzID0gW1xuXHRcdFx0MCwgMiwgNCxcdDAsIDQsIDMsXHQwLCAzLCA1LFxuXHRcdFx0MCwgNSwgMixcdDEsIDIsIDUsXHQxLCA1LCAzLFxuXHRcdFx0MSwgMywgNCxcdDEsIDQsIDJcblx0XHRdO1xuXG5cdFx0c3VwZXIoIHZlcnRpY2VzLCBpbmRpY2VzLCByYWRpdXMsIGRldGFpbCApO1xuXG5cdFx0dGhpcy50eXBlID0gJ09jdGFoZWRyb25HZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcblx0XHRcdGRldGFpbDogZGV0YWlsXG5cdFx0fTtcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xuXG5cdFx0cmV0dXJuIG5ldyBPY3RhaGVkcm9uR2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLmRldGFpbCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBSaW5nR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIGlubmVyUmFkaXVzID0gMC41LCBvdXRlclJhZGl1cyA9IDEsIHRoZXRhU2VnbWVudHMgPSAzMiwgcGhpU2VnbWVudHMgPSAxLCB0aGV0YVN0YXJ0ID0gMCwgdGhldGFMZW5ndGggPSBNYXRoLlBJICogMiApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnUmluZ0dlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdGlubmVyUmFkaXVzOiBpbm5lclJhZGl1cyxcblx0XHRcdG91dGVyUmFkaXVzOiBvdXRlclJhZGl1cyxcblx0XHRcdHRoZXRhU2VnbWVudHM6IHRoZXRhU2VnbWVudHMsXG5cdFx0XHRwaGlTZWdtZW50czogcGhpU2VnbWVudHMsXG5cdFx0XHR0aGV0YVN0YXJ0OiB0aGV0YVN0YXJ0LFxuXHRcdFx0dGhldGFMZW5ndGg6IHRoZXRhTGVuZ3RoXG5cdFx0fTtcblxuXHRcdHRoZXRhU2VnbWVudHMgPSBNYXRoLm1heCggMywgdGhldGFTZWdtZW50cyApO1xuXHRcdHBoaVNlZ21lbnRzID0gTWF0aC5tYXgoIDEsIHBoaVNlZ21lbnRzICk7XG5cblx0XHQvLyBidWZmZXJzXG5cblx0XHRjb25zdCBpbmRpY2VzID0gW107XG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcblx0XHRjb25zdCBub3JtYWxzID0gW107XG5cdFx0Y29uc3QgdXZzID0gW107XG5cblx0XHQvLyBzb21lIGhlbHBlciB2YXJpYWJsZXNcblxuXHRcdGxldCByYWRpdXMgPSBpbm5lclJhZGl1cztcblx0XHRjb25zdCByYWRpdXNTdGVwID0gKCAoIG91dGVyUmFkaXVzIC0gaW5uZXJSYWRpdXMgKSAvIHBoaVNlZ21lbnRzICk7XG5cdFx0Y29uc3QgdmVydGV4ID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCB1diA9IG5ldyBWZWN0b3IyKCk7XG5cblx0XHQvLyBnZW5lcmF0ZSB2ZXJ0aWNlcywgbm9ybWFscyBhbmQgdXZzXG5cblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPD0gcGhpU2VnbWVudHM7IGogKysgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSB0aGV0YVNlZ21lbnRzOyBpICsrICkge1xuXG5cdFx0XHRcdC8vIHZhbHVlcyBhcmUgZ2VuZXJhdGUgZnJvbSB0aGUgaW5zaWRlIG9mIHRoZSByaW5nIHRvIHRoZSBvdXRzaWRlXG5cblx0XHRcdFx0Y29uc3Qgc2VnbWVudCA9IHRoZXRhU3RhcnQgKyBpIC8gdGhldGFTZWdtZW50cyAqIHRoZXRhTGVuZ3RoO1xuXG5cdFx0XHRcdC8vIHZlcnRleFxuXG5cdFx0XHRcdHZlcnRleC54ID0gcmFkaXVzICogTWF0aC5jb3MoIHNlZ21lbnQgKTtcblx0XHRcdFx0dmVydGV4LnkgPSByYWRpdXMgKiBNYXRoLnNpbiggc2VnbWVudCApO1xuXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcblxuXHRcdFx0XHQvLyBub3JtYWxcblxuXHRcdFx0XHRub3JtYWxzLnB1c2goIDAsIDAsIDEgKTtcblxuXHRcdFx0XHQvLyB1dlxuXG5cdFx0XHRcdHV2LnggPSAoIHZlcnRleC54IC8gb3V0ZXJSYWRpdXMgKyAxICkgLyAyO1xuXHRcdFx0XHR1di55ID0gKCB2ZXJ0ZXgueSAvIG91dGVyUmFkaXVzICsgMSApIC8gMjtcblxuXHRcdFx0XHR1dnMucHVzaCggdXYueCwgdXYueSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGluY3JlYXNlIHRoZSByYWRpdXMgZm9yIG5leHQgcm93IG9mIHZlcnRpY2VzXG5cblx0XHRcdHJhZGl1cyArPSByYWRpdXNTdGVwO1xuXG5cdFx0fVxuXG5cdFx0Ly8gaW5kaWNlc1xuXG5cdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgcGhpU2VnbWVudHM7IGogKysgKSB7XG5cblx0XHRcdGNvbnN0IHRoZXRhU2VnbWVudExldmVsID0gaiAqICggdGhldGFTZWdtZW50cyArIDEgKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhldGFTZWdtZW50czsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBzZWdtZW50ID0gaSArIHRoZXRhU2VnbWVudExldmVsO1xuXG5cdFx0XHRcdGNvbnN0IGEgPSBzZWdtZW50O1xuXHRcdFx0XHRjb25zdCBiID0gc2VnbWVudCArIHRoZXRhU2VnbWVudHMgKyAxO1xuXHRcdFx0XHRjb25zdCBjID0gc2VnbWVudCArIHRoZXRhU2VnbWVudHMgKyAyO1xuXHRcdFx0XHRjb25zdCBkID0gc2VnbWVudCArIDE7XG5cblx0XHRcdFx0Ly8gZmFjZXNcblxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBiLCBjLCBkICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XG5cblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdHJldHVybiBuZXcgUmluZ0dlb21ldHJ5KCBkYXRhLmlubmVyUmFkaXVzLCBkYXRhLm91dGVyUmFkaXVzLCBkYXRhLnRoZXRhU2VnbWVudHMsIGRhdGEucGhpU2VnbWVudHMsIGRhdGEudGhldGFTdGFydCwgZGF0YS50aGV0YUxlbmd0aCApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBTaGFwZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCBzaGFwZXMgPSBuZXcgU2hhcGUoIFsgbmV3IFZlY3RvcjIoIDAsIDAuNSApLCBuZXcgVmVjdG9yMiggLSAwLjUsIC0gMC41ICksIG5ldyBWZWN0b3IyKCAwLjUsIC0gMC41ICkgXSApLCBjdXJ2ZVNlZ21lbnRzID0gMTIgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ1NoYXBlR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0c2hhcGVzOiBzaGFwZXMsXG5cdFx0XHRjdXJ2ZVNlZ21lbnRzOiBjdXJ2ZVNlZ21lbnRzXG5cdFx0fTtcblxuXHRcdC8vIGJ1ZmZlcnNcblxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcblx0XHRjb25zdCB1dnMgPSBbXTtcblxuXHRcdC8vIGhlbHBlciB2YXJpYWJsZXNcblxuXHRcdGxldCBncm91cFN0YXJ0ID0gMDtcblx0XHRsZXQgZ3JvdXBDb3VudCA9IDA7XG5cblx0XHQvLyBhbGxvdyBzaW5nbGUgYW5kIGFycmF5IHZhbHVlcyBmb3IgXCJzaGFwZXNcIiBwYXJhbWV0ZXJcblxuXHRcdGlmICggQXJyYXkuaXNBcnJheSggc2hhcGVzICkgPT09IGZhbHNlICkge1xuXG5cdFx0XHRhZGRTaGFwZSggc2hhcGVzICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBzaGFwZXMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGFkZFNoYXBlKCBzaGFwZXNbIGkgXSApO1xuXG5cdFx0XHRcdHRoaXMuYWRkR3JvdXAoIGdyb3VwU3RhcnQsIGdyb3VwQ291bnQsIGkgKTsgLy8gZW5hYmxlcyBNdWx0aU1hdGVyaWFsIHN1cHBvcnRcblxuXHRcdFx0XHRncm91cFN0YXJ0ICs9IGdyb3VwQ291bnQ7XG5cdFx0XHRcdGdyb3VwQ291bnQgPSAwO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBidWlsZCBnZW9tZXRyeVxuXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcblxuXG5cdFx0Ly8gaGVscGVyIGZ1bmN0aW9uc1xuXG5cdFx0ZnVuY3Rpb24gYWRkU2hhcGUoIHNoYXBlICkge1xuXG5cdFx0XHRjb25zdCBpbmRleE9mZnNldCA9IHZlcnRpY2VzLmxlbmd0aCAvIDM7XG5cdFx0XHRjb25zdCBwb2ludHMgPSBzaGFwZS5leHRyYWN0UG9pbnRzKCBjdXJ2ZVNlZ21lbnRzICk7XG5cblx0XHRcdGxldCBzaGFwZVZlcnRpY2VzID0gcG9pbnRzLnNoYXBlO1xuXHRcdFx0Y29uc3Qgc2hhcGVIb2xlcyA9IHBvaW50cy5ob2xlcztcblxuXHRcdFx0Ly8gY2hlY2sgZGlyZWN0aW9uIG9mIHZlcnRpY2VzXG5cblx0XHRcdGlmICggU2hhcGVVdGlscy5pc0Nsb2NrV2lzZSggc2hhcGVWZXJ0aWNlcyApID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHRzaGFwZVZlcnRpY2VzID0gc2hhcGVWZXJ0aWNlcy5yZXZlcnNlKCk7XG5cblx0XHRcdH1cblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVIb2xlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHNoYXBlSG9sZSA9IHNoYXBlSG9sZXNbIGkgXTtcblxuXHRcdFx0XHRpZiAoIFNoYXBlVXRpbHMuaXNDbG9ja1dpc2UoIHNoYXBlSG9sZSApID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0c2hhcGVIb2xlc1sgaSBdID0gc2hhcGVIb2xlLnJldmVyc2UoKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0Y29uc3QgZmFjZXMgPSBTaGFwZVV0aWxzLnRyaWFuZ3VsYXRlU2hhcGUoIHNoYXBlVmVydGljZXMsIHNoYXBlSG9sZXMgKTtcblxuXHRcdFx0Ly8gam9pbiB2ZXJ0aWNlcyBvZiBpbm5lciBhbmQgb3V0ZXIgcGF0aHMgdG8gYSBzaW5nbGUgYXJyYXlcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gc2hhcGVIb2xlcy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHNoYXBlSG9sZSA9IHNoYXBlSG9sZXNbIGkgXTtcblx0XHRcdFx0c2hhcGVWZXJ0aWNlcyA9IHNoYXBlVmVydGljZXMuY29uY2F0KCBzaGFwZUhvbGUgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyB2ZXJ0aWNlcywgbm9ybWFscywgdXZzXG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHNoYXBlVmVydGljZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCB2ZXJ0ZXggPSBzaGFwZVZlcnRpY2VzWyBpIF07XG5cblx0XHRcdFx0dmVydGljZXMucHVzaCggdmVydGV4LngsIHZlcnRleC55LCAwICk7XG5cdFx0XHRcdG5vcm1hbHMucHVzaCggMCwgMCwgMSApO1xuXHRcdFx0XHR1dnMucHVzaCggdmVydGV4LngsIHZlcnRleC55ICk7IC8vIHdvcmxkIHV2c1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGluZGljZXNcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gZmFjZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBmYWNlID0gZmFjZXNbIGkgXTtcblxuXHRcdFx0XHRjb25zdCBhID0gZmFjZVsgMCBdICsgaW5kZXhPZmZzZXQ7XG5cdFx0XHRcdGNvbnN0IGIgPSBmYWNlWyAxIF0gKyBpbmRleE9mZnNldDtcblx0XHRcdFx0Y29uc3QgYyA9IGZhY2VbIDIgXSArIGluZGV4T2Zmc2V0O1xuXG5cdFx0XHRcdGluZGljZXMucHVzaCggYSwgYiwgYyApO1xuXHRcdFx0XHRncm91cENvdW50ICs9IDM7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCk7XG5cblx0XHRjb25zdCBzaGFwZXMgPSB0aGlzLnBhcmFtZXRlcnMuc2hhcGVzO1xuXG5cdFx0cmV0dXJuIHRvSlNPTiggc2hhcGVzLCBkYXRhICk7XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSwgc2hhcGVzICkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnlTaGFwZXMgPSBbXTtcblxuXHRcdGZvciAoIGxldCBqID0gMCwgamwgPSBkYXRhLnNoYXBlcy5sZW5ndGg7IGogPCBqbDsgaiArKyApIHtcblxuXHRcdFx0Y29uc3Qgc2hhcGUgPSBzaGFwZXNbIGRhdGEuc2hhcGVzWyBqIF0gXTtcblxuXHRcdFx0Z2VvbWV0cnlTaGFwZXMucHVzaCggc2hhcGUgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBuZXcgU2hhcGVHZW9tZXRyeSggZ2VvbWV0cnlTaGFwZXMsIGRhdGEuY3VydmVTZWdtZW50cyApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiB0b0pTT04oIHNoYXBlcywgZGF0YSApIHtcblxuXHRkYXRhLnNoYXBlcyA9IFtdO1xuXG5cdGlmICggQXJyYXkuaXNBcnJheSggc2hhcGVzICkgKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzaGFwZXMubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3Qgc2hhcGUgPSBzaGFwZXNbIGkgXTtcblxuXHRcdFx0ZGF0YS5zaGFwZXMucHVzaCggc2hhcGUudXVpZCApO1xuXG5cdFx0fVxuXG5cdH0gZWxzZSB7XG5cblx0XHRkYXRhLnNoYXBlcy5wdXNoKCBzaGFwZXMudXVpZCApO1xuXG5cdH1cblxuXHRyZXR1cm4gZGF0YTtcblxufVxuXG5jbGFzcyBTcGhlcmVHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgd2lkdGhTZWdtZW50cyA9IDMyLCBoZWlnaHRTZWdtZW50cyA9IDE2LCBwaGlTdGFydCA9IDAsIHBoaUxlbmd0aCA9IE1hdGguUEkgKiAyLCB0aGV0YVN0YXJ0ID0gMCwgdGhldGFMZW5ndGggPSBNYXRoLlBJICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdTcGhlcmVHZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcblx0XHRcdHdpZHRoU2VnbWVudHM6IHdpZHRoU2VnbWVudHMsXG5cdFx0XHRoZWlnaHRTZWdtZW50czogaGVpZ2h0U2VnbWVudHMsXG5cdFx0XHRwaGlTdGFydDogcGhpU3RhcnQsXG5cdFx0XHRwaGlMZW5ndGg6IHBoaUxlbmd0aCxcblx0XHRcdHRoZXRhU3RhcnQ6IHRoZXRhU3RhcnQsXG5cdFx0XHR0aGV0YUxlbmd0aDogdGhldGFMZW5ndGhcblx0XHR9O1xuXG5cdFx0d2lkdGhTZWdtZW50cyA9IE1hdGgubWF4KCAzLCBNYXRoLmZsb29yKCB3aWR0aFNlZ21lbnRzICkgKTtcblx0XHRoZWlnaHRTZWdtZW50cyA9IE1hdGgubWF4KCAyLCBNYXRoLmZsb29yKCBoZWlnaHRTZWdtZW50cyApICk7XG5cblx0XHRjb25zdCB0aGV0YUVuZCA9IE1hdGgubWluKCB0aGV0YVN0YXJ0ICsgdGhldGFMZW5ndGgsIE1hdGguUEkgKTtcblxuXHRcdGxldCBpbmRleCA9IDA7XG5cdFx0Y29uc3QgZ3JpZCA9IFtdO1xuXG5cdFx0Y29uc3QgdmVydGV4ID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCBub3JtYWwgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0Ly8gYnVmZmVyc1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xuXHRcdGNvbnN0IHV2cyA9IFtdO1xuXG5cdFx0Ly8gZ2VuZXJhdGUgdmVydGljZXMsIG5vcm1hbHMgYW5kIHV2c1xuXG5cdFx0Zm9yICggbGV0IGl5ID0gMDsgaXkgPD0gaGVpZ2h0U2VnbWVudHM7IGl5ICsrICkge1xuXG5cdFx0XHRjb25zdCB2ZXJ0aWNlc1JvdyA9IFtdO1xuXG5cdFx0XHRjb25zdCB2ID0gaXkgLyBoZWlnaHRTZWdtZW50cztcblxuXHRcdFx0Ly8gc3BlY2lhbCBjYXNlIGZvciB0aGUgcG9sZXNcblxuXHRcdFx0bGV0IHVPZmZzZXQgPSAwO1xuXG5cdFx0XHRpZiAoIGl5ID09PSAwICYmIHRoZXRhU3RhcnQgPT09IDAgKSB7XG5cblx0XHRcdFx0dU9mZnNldCA9IDAuNSAvIHdpZHRoU2VnbWVudHM7XG5cblx0XHRcdH0gZWxzZSBpZiAoIGl5ID09PSBoZWlnaHRTZWdtZW50cyAmJiB0aGV0YUVuZCA9PT0gTWF0aC5QSSApIHtcblxuXHRcdFx0XHR1T2Zmc2V0ID0gLSAwLjUgLyB3aWR0aFNlZ21lbnRzO1xuXG5cdFx0XHR9XG5cblx0XHRcdGZvciAoIGxldCBpeCA9IDA7IGl4IDw9IHdpZHRoU2VnbWVudHM7IGl4ICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHUgPSBpeCAvIHdpZHRoU2VnbWVudHM7XG5cblx0XHRcdFx0Ly8gdmVydGV4XG5cblx0XHRcdFx0dmVydGV4LnggPSAtIHJhZGl1cyAqIE1hdGguY29zKCBwaGlTdGFydCArIHUgKiBwaGlMZW5ndGggKSAqIE1hdGguc2luKCB0aGV0YVN0YXJ0ICsgdiAqIHRoZXRhTGVuZ3RoICk7XG5cdFx0XHRcdHZlcnRleC55ID0gcmFkaXVzICogTWF0aC5jb3MoIHRoZXRhU3RhcnQgKyB2ICogdGhldGFMZW5ndGggKTtcblx0XHRcdFx0dmVydGV4LnogPSByYWRpdXMgKiBNYXRoLnNpbiggcGhpU3RhcnQgKyB1ICogcGhpTGVuZ3RoICkgKiBNYXRoLnNpbiggdGhldGFTdGFydCArIHYgKiB0aGV0YUxlbmd0aCApO1xuXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcblxuXHRcdFx0XHQvLyBub3JtYWxcblxuXHRcdFx0XHRub3JtYWwuY29weSggdmVydGV4ICkubm9ybWFsaXplKCk7XG5cdFx0XHRcdG5vcm1hbHMucHVzaCggbm9ybWFsLngsIG5vcm1hbC55LCBub3JtYWwueiApO1xuXG5cdFx0XHRcdC8vIHV2XG5cblx0XHRcdFx0dXZzLnB1c2goIHUgKyB1T2Zmc2V0LCAxIC0gdiApO1xuXG5cdFx0XHRcdHZlcnRpY2VzUm93LnB1c2goIGluZGV4ICsrICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Z3JpZC5wdXNoKCB2ZXJ0aWNlc1JvdyApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gaW5kaWNlc1xuXG5cdFx0Zm9yICggbGV0IGl5ID0gMDsgaXkgPCBoZWlnaHRTZWdtZW50czsgaXkgKysgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpeCA9IDA7IGl4IDwgd2lkdGhTZWdtZW50czsgaXggKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgYSA9IGdyaWRbIGl5IF1bIGl4ICsgMSBdO1xuXHRcdFx0XHRjb25zdCBiID0gZ3JpZFsgaXkgXVsgaXggXTtcblx0XHRcdFx0Y29uc3QgYyA9IGdyaWRbIGl5ICsgMSBdWyBpeCBdO1xuXHRcdFx0XHRjb25zdCBkID0gZ3JpZFsgaXkgKyAxIF1bIGl4ICsgMSBdO1xuXG5cdFx0XHRcdGlmICggaXkgIT09IDAgfHwgdGhldGFTdGFydCA+IDAgKSBpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcblx0XHRcdFx0aWYgKCBpeSAhPT0gaGVpZ2h0U2VnbWVudHMgLSAxIHx8IHRoZXRhRW5kIDwgTWF0aC5QSSApIGluZGljZXMucHVzaCggYiwgYywgZCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBidWlsZCBnZW9tZXRyeVxuXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IFNwaGVyZUdlb21ldHJ5KCBkYXRhLnJhZGl1cywgZGF0YS53aWR0aFNlZ21lbnRzLCBkYXRhLmhlaWdodFNlZ21lbnRzLCBkYXRhLnBoaVN0YXJ0LCBkYXRhLnBoaUxlbmd0aCwgZGF0YS50aGV0YVN0YXJ0LCBkYXRhLnRoZXRhTGVuZ3RoICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFRldHJhaGVkcm9uR2VvbWV0cnkgZXh0ZW5kcyBQb2x5aGVkcm9uR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBkZXRhaWwgPSAwICkge1xuXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXG5cdFx0XHQxLCAxLCAxLCBcdC0gMSwgLSAxLCAxLCBcdC0gMSwgMSwgLSAxLCBcdDEsIC0gMSwgLSAxXG5cdFx0XTtcblxuXHRcdGNvbnN0IGluZGljZXMgPSBbXG5cdFx0XHQyLCAxLCAwLCBcdDAsIDMsIDIsXHQxLCAzLCAwLFx0MiwgMywgMVxuXHRcdF07XG5cblx0XHRzdXBlciggdmVydGljZXMsIGluZGljZXMsIHJhZGl1cywgZGV0YWlsICk7XG5cblx0XHR0aGlzLnR5cGUgPSAnVGV0cmFoZWRyb25HZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcblx0XHRcdGRldGFpbDogZGV0YWlsXG5cdFx0fTtcblxuXHR9XG5cblx0c3RhdGljIGZyb21KU09OKCBkYXRhICkge1xuXG5cdFx0cmV0dXJuIG5ldyBUZXRyYWhlZHJvbkdlb21ldHJ5KCBkYXRhLnJhZGl1cywgZGF0YS5kZXRhaWwgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgVG9ydXNHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgdHViZSA9IDAuNCwgcmFkaWFsU2VnbWVudHMgPSAxMiwgdHVidWxhclNlZ21lbnRzID0gNDgsIGFyYyA9IE1hdGguUEkgKiAyICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdUb3J1c0dlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdHJhZGl1czogcmFkaXVzLFxuXHRcdFx0dHViZTogdHViZSxcblx0XHRcdHJhZGlhbFNlZ21lbnRzOiByYWRpYWxTZWdtZW50cyxcblx0XHRcdHR1YnVsYXJTZWdtZW50czogdHVidWxhclNlZ21lbnRzLFxuXHRcdFx0YXJjOiBhcmNcblx0XHR9O1xuXG5cdFx0cmFkaWFsU2VnbWVudHMgPSBNYXRoLmZsb29yKCByYWRpYWxTZWdtZW50cyApO1xuXHRcdHR1YnVsYXJTZWdtZW50cyA9IE1hdGguZmxvb3IoIHR1YnVsYXJTZWdtZW50cyApO1xuXG5cdFx0Ly8gYnVmZmVyc1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IFtdO1xuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0Y29uc3Qgbm9ybWFscyA9IFtdO1xuXHRcdGNvbnN0IHV2cyA9IFtdO1xuXG5cdFx0Ly8gaGVscGVyIHZhcmlhYmxlc1xuXG5cdFx0Y29uc3QgY2VudGVyID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCB2ZXJ0ZXggPSBuZXcgVmVjdG9yMygpO1xuXHRcdGNvbnN0IG5vcm1hbCA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHQvLyBnZW5lcmF0ZSB2ZXJ0aWNlcywgbm9ybWFscyBhbmQgdXZzXG5cblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPD0gcmFkaWFsU2VnbWVudHM7IGogKysgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSB0dWJ1bGFyU2VnbWVudHM7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgdSA9IGkgLyB0dWJ1bGFyU2VnbWVudHMgKiBhcmM7XG5cdFx0XHRcdGNvbnN0IHYgPSBqIC8gcmFkaWFsU2VnbWVudHMgKiBNYXRoLlBJICogMjtcblxuXHRcdFx0XHQvLyB2ZXJ0ZXhcblxuXHRcdFx0XHR2ZXJ0ZXgueCA9ICggcmFkaXVzICsgdHViZSAqIE1hdGguY29zKCB2ICkgKSAqIE1hdGguY29zKCB1ICk7XG5cdFx0XHRcdHZlcnRleC55ID0gKCByYWRpdXMgKyB0dWJlICogTWF0aC5jb3MoIHYgKSApICogTWF0aC5zaW4oIHUgKTtcblx0XHRcdFx0dmVydGV4LnogPSB0dWJlICogTWF0aC5zaW4oIHYgKTtcblxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB2ZXJ0ZXgueCwgdmVydGV4LnksIHZlcnRleC56ICk7XG5cblx0XHRcdFx0Ly8gbm9ybWFsXG5cblx0XHRcdFx0Y2VudGVyLnggPSByYWRpdXMgKiBNYXRoLmNvcyggdSApO1xuXHRcdFx0XHRjZW50ZXIueSA9IHJhZGl1cyAqIE1hdGguc2luKCB1ICk7XG5cdFx0XHRcdG5vcm1hbC5zdWJWZWN0b3JzKCB2ZXJ0ZXgsIGNlbnRlciApLm5vcm1hbGl6ZSgpO1xuXG5cdFx0XHRcdG5vcm1hbHMucHVzaCggbm9ybWFsLngsIG5vcm1hbC55LCBub3JtYWwueiApO1xuXG5cdFx0XHRcdC8vIHV2XG5cblx0XHRcdFx0dXZzLnB1c2goIGkgLyB0dWJ1bGFyU2VnbWVudHMgKTtcblx0XHRcdFx0dXZzLnB1c2goIGogLyByYWRpYWxTZWdtZW50cyApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBnZW5lcmF0ZSBpbmRpY2VzXG5cblx0XHRmb3IgKCBsZXQgaiA9IDE7IGogPD0gcmFkaWFsU2VnbWVudHM7IGogKysgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMTsgaSA8PSB0dWJ1bGFyU2VnbWVudHM7IGkgKysgKSB7XG5cblx0XHRcdFx0Ly8gaW5kaWNlc1xuXG5cdFx0XHRcdGNvbnN0IGEgPSAoIHR1YnVsYXJTZWdtZW50cyArIDEgKSAqIGogKyBpIC0gMTtcblx0XHRcdFx0Y29uc3QgYiA9ICggdHVidWxhclNlZ21lbnRzICsgMSApICogKCBqIC0gMSApICsgaSAtIDE7XG5cdFx0XHRcdGNvbnN0IGMgPSAoIHR1YnVsYXJTZWdtZW50cyArIDEgKSAqICggaiAtIDEgKSArIGk7XG5cdFx0XHRcdGNvbnN0IGQgPSAoIHR1YnVsYXJTZWdtZW50cyArIDEgKSAqIGogKyBpO1xuXG5cdFx0XHRcdC8vIGZhY2VzXG5cblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBhLCBiLCBkICk7XG5cdFx0XHRcdGluZGljZXMucHVzaCggYiwgYywgZCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBidWlsZCBnZW9tZXRyeVxuXG5cdFx0dGhpcy5zZXRJbmRleCggaW5kaWNlcyApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAnbm9ybWFsJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIG5vcm1hbHMsIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdXZzLCAyICkgKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSBPYmplY3QuYXNzaWduKCB7fSwgc291cmNlLnBhcmFtZXRlcnMgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdGF0aWMgZnJvbUpTT04oIGRhdGEgKSB7XG5cblx0XHRyZXR1cm4gbmV3IFRvcnVzR2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLnR1YmUsIGRhdGEucmFkaWFsU2VnbWVudHMsIGRhdGEudHVidWxhclNlZ21lbnRzLCBkYXRhLmFyYyApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBUb3J1c0tub3RHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgdHViZSA9IDAuNCwgdHVidWxhclNlZ21lbnRzID0gNjQsIHJhZGlhbFNlZ21lbnRzID0gOCwgcCA9IDIsIHEgPSAzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdUb3J1c0tub3RHZW9tZXRyeSc7XG5cblx0XHR0aGlzLnBhcmFtZXRlcnMgPSB7XG5cdFx0XHRyYWRpdXM6IHJhZGl1cyxcblx0XHRcdHR1YmU6IHR1YmUsXG5cdFx0XHR0dWJ1bGFyU2VnbWVudHM6IHR1YnVsYXJTZWdtZW50cyxcblx0XHRcdHJhZGlhbFNlZ21lbnRzOiByYWRpYWxTZWdtZW50cyxcblx0XHRcdHA6IHAsXG5cdFx0XHRxOiBxXG5cdFx0fTtcblxuXHRcdHR1YnVsYXJTZWdtZW50cyA9IE1hdGguZmxvb3IoIHR1YnVsYXJTZWdtZW50cyApO1xuXHRcdHJhZGlhbFNlZ21lbnRzID0gTWF0aC5mbG9vciggcmFkaWFsU2VnbWVudHMgKTtcblxuXHRcdC8vIGJ1ZmZlcnNcblxuXHRcdGNvbnN0IGluZGljZXMgPSBbXTtcblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcblx0XHRjb25zdCB1dnMgPSBbXTtcblxuXHRcdC8vIGhlbHBlciB2YXJpYWJsZXNcblxuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0Y29uc3Qgbm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdGNvbnN0IFAxID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCBQMiA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRjb25zdCBCID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCBUID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCBOID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdC8vIGdlbmVyYXRlIHZlcnRpY2VzLCBub3JtYWxzIGFuZCB1dnNcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8PSB0dWJ1bGFyU2VnbWVudHM7ICsrIGkgKSB7XG5cblx0XHRcdC8vIHRoZSByYWRpYW4gXCJ1XCIgaXMgdXNlZCB0byBjYWxjdWxhdGUgdGhlIHBvc2l0aW9uIG9uIHRoZSB0b3J1cyBjdXJ2ZSBvZiB0aGUgY3VycmVudCB0dWJ1bGFyIHNlZ21lbnRcblxuXHRcdFx0Y29uc3QgdSA9IGkgLyB0dWJ1bGFyU2VnbWVudHMgKiBwICogTWF0aC5QSSAqIDI7XG5cblx0XHRcdC8vIG5vdyB3ZSBjYWxjdWxhdGUgdHdvIHBvaW50cy4gUDEgaXMgb3VyIGN1cnJlbnQgcG9zaXRpb24gb24gdGhlIGN1cnZlLCBQMiBpcyBhIGxpdHRsZSBmYXJ0aGVyIGFoZWFkLlxuXHRcdFx0Ly8gdGhlc2UgcG9pbnRzIGFyZSB1c2VkIHRvIGNyZWF0ZSBhIHNwZWNpYWwgXCJjb29yZGluYXRlIHNwYWNlXCIsIHdoaWNoIGlzIG5lY2Vzc2FyeSB0byBjYWxjdWxhdGUgdGhlIGNvcnJlY3QgdmVydGV4IHBvc2l0aW9uc1xuXG5cdFx0XHRjYWxjdWxhdGVQb3NpdGlvbk9uQ3VydmUoIHUsIHAsIHEsIHJhZGl1cywgUDEgKTtcblx0XHRcdGNhbGN1bGF0ZVBvc2l0aW9uT25DdXJ2ZSggdSArIDAuMDEsIHAsIHEsIHJhZGl1cywgUDIgKTtcblxuXHRcdFx0Ly8gY2FsY3VsYXRlIG9ydGhvbm9ybWFsIGJhc2lzXG5cblx0XHRcdFQuc3ViVmVjdG9ycyggUDIsIFAxICk7XG5cdFx0XHROLmFkZFZlY3RvcnMoIFAyLCBQMSApO1xuXHRcdFx0Qi5jcm9zc1ZlY3RvcnMoIFQsIE4gKTtcblx0XHRcdE4uY3Jvc3NWZWN0b3JzKCBCLCBUICk7XG5cblx0XHRcdC8vIG5vcm1hbGl6ZSBCLCBOLiBUIGNhbiBiZSBpZ25vcmVkLCB3ZSBkb24ndCB1c2UgaXRcblxuXHRcdFx0Qi5ub3JtYWxpemUoKTtcblx0XHRcdE4ubm9ybWFsaXplKCk7XG5cblx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSByYWRpYWxTZWdtZW50czsgKysgaiApIHtcblxuXHRcdFx0XHQvLyBub3cgY2FsY3VsYXRlIHRoZSB2ZXJ0aWNlcy4gdGhleSBhcmUgbm90aGluZyBtb3JlIHRoYW4gYW4gZXh0cnVzaW9uIG9mIHRoZSB0b3J1cyBjdXJ2ZS5cblx0XHRcdFx0Ly8gYmVjYXVzZSB3ZSBleHRydWRlIGEgc2hhcGUgaW4gdGhlIHh5LXBsYW5lLCB0aGVyZSBpcyBubyBuZWVkIHRvIGNhbGN1bGF0ZSBhIHotdmFsdWUuXG5cblx0XHRcdFx0Y29uc3QgdiA9IGogLyByYWRpYWxTZWdtZW50cyAqIE1hdGguUEkgKiAyO1xuXHRcdFx0XHRjb25zdCBjeCA9IC0gdHViZSAqIE1hdGguY29zKCB2ICk7XG5cdFx0XHRcdGNvbnN0IGN5ID0gdHViZSAqIE1hdGguc2luKCB2ICk7XG5cblx0XHRcdFx0Ly8gbm93IGNhbGN1bGF0ZSB0aGUgZmluYWwgdmVydGV4IHBvc2l0aW9uLlxuXHRcdFx0XHQvLyBmaXJzdCB3ZSBvcmllbnQgdGhlIGV4dHJ1c2lvbiB3aXRoIG91ciBiYXNpcyB2ZWN0b3JzLCB0aGVuIHdlIGFkZCBpdCB0byB0aGUgY3VycmVudCBwb3NpdGlvbiBvbiB0aGUgY3VydmVcblxuXHRcdFx0XHR2ZXJ0ZXgueCA9IFAxLnggKyAoIGN4ICogTi54ICsgY3kgKiBCLnggKTtcblx0XHRcdFx0dmVydGV4LnkgPSBQMS55ICsgKCBjeCAqIE4ueSArIGN5ICogQi55ICk7XG5cdFx0XHRcdHZlcnRleC56ID0gUDEueiArICggY3ggKiBOLnogKyBjeSAqIEIueiApO1xuXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcblxuXHRcdFx0XHQvLyBub3JtYWwgKFAxIGlzIGFsd2F5cyB0aGUgY2VudGVyL29yaWdpbiBvZiB0aGUgZXh0cnVzaW9uLCB0aHVzIHdlIGNhbiB1c2UgaXQgdG8gY2FsY3VsYXRlIHRoZSBub3JtYWwpXG5cblx0XHRcdFx0bm9ybWFsLnN1YlZlY3RvcnMoIHZlcnRleCwgUDEgKS5ub3JtYWxpemUoKTtcblxuXHRcdFx0XHRub3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcblxuXHRcdFx0XHQvLyB1dlxuXG5cdFx0XHRcdHV2cy5wdXNoKCBpIC8gdHVidWxhclNlZ21lbnRzICk7XG5cdFx0XHRcdHV2cy5wdXNoKCBqIC8gcmFkaWFsU2VnbWVudHMgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gZ2VuZXJhdGUgaW5kaWNlc1xuXG5cdFx0Zm9yICggbGV0IGogPSAxOyBqIDw9IHR1YnVsYXJTZWdtZW50czsgaiArKyApIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAxOyBpIDw9IHJhZGlhbFNlZ21lbnRzOyBpICsrICkge1xuXG5cdFx0XHRcdC8vIGluZGljZXNcblxuXHRcdFx0XHRjb25zdCBhID0gKCByYWRpYWxTZWdtZW50cyArIDEgKSAqICggaiAtIDEgKSArICggaSAtIDEgKTtcblx0XHRcdFx0Y29uc3QgYiA9ICggcmFkaWFsU2VnbWVudHMgKyAxICkgKiBqICsgKCBpIC0gMSApO1xuXHRcdFx0XHRjb25zdCBjID0gKCByYWRpYWxTZWdtZW50cyArIDEgKSAqIGogKyBpO1xuXHRcdFx0XHRjb25zdCBkID0gKCByYWRpYWxTZWdtZW50cyArIDEgKSAqICggaiAtIDEgKSArIGk7XG5cblx0XHRcdFx0Ly8gZmFjZXNcblxuXHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcblx0XHRcdFx0aW5kaWNlcy5wdXNoKCBiLCBjLCBkICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGJ1aWxkIGdlb21ldHJ5XG5cblx0XHR0aGlzLnNldEluZGV4KCBpbmRpY2VzICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICdub3JtYWwnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggbm9ybWFscywgMyApICk7XG5cdFx0dGhpcy5zZXRBdHRyaWJ1dGUoICd1dicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB1dnMsIDIgKSApO1xuXG5cdFx0Ly8gdGhpcyBmdW5jdGlvbiBjYWxjdWxhdGVzIHRoZSBjdXJyZW50IHBvc2l0aW9uIG9uIHRoZSB0b3J1cyBjdXJ2ZVxuXG5cdFx0ZnVuY3Rpb24gY2FsY3VsYXRlUG9zaXRpb25PbkN1cnZlKCB1LCBwLCBxLCByYWRpdXMsIHBvc2l0aW9uICkge1xuXG5cdFx0XHRjb25zdCBjdSA9IE1hdGguY29zKCB1ICk7XG5cdFx0XHRjb25zdCBzdSA9IE1hdGguc2luKCB1ICk7XG5cdFx0XHRjb25zdCBxdU92ZXJQID0gcSAvIHAgKiB1O1xuXHRcdFx0Y29uc3QgY3MgPSBNYXRoLmNvcyggcXVPdmVyUCApO1xuXG5cdFx0XHRwb3NpdGlvbi54ID0gcmFkaXVzICogKCAyICsgY3MgKSAqIDAuNSAqIGN1O1xuXHRcdFx0cG9zaXRpb24ueSA9IHJhZGl1cyAqICggMiArIGNzICkgKiBzdSAqIDAuNTtcblx0XHRcdHBvc2l0aW9uLnogPSByYWRpdXMgKiBNYXRoLnNpbiggcXVPdmVyUCApICogMC41O1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdHJldHVybiBuZXcgVG9ydXNLbm90R2VvbWV0cnkoIGRhdGEucmFkaXVzLCBkYXRhLnR1YmUsIGRhdGEudHVidWxhclNlZ21lbnRzLCBkYXRhLnJhZGlhbFNlZ21lbnRzLCBkYXRhLnAsIGRhdGEucSApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBUdWJlR2VvbWV0cnkgZXh0ZW5kcyBCdWZmZXJHZW9tZXRyeSB7XG5cblx0Y29uc3RydWN0b3IoIHBhdGggPSBuZXcgUXVhZHJhdGljQmV6aWVyQ3VydmUzKCBuZXcgVmVjdG9yMyggLSAxLCAtIDEsIDAgKSwgbmV3IFZlY3RvcjMoIC0gMSwgMSwgMCApLCBuZXcgVmVjdG9yMyggMSwgMSwgMCApICksIHR1YnVsYXJTZWdtZW50cyA9IDY0LCByYWRpdXMgPSAxLCByYWRpYWxTZWdtZW50cyA9IDgsIGNsb3NlZCA9IGZhbHNlICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMudHlwZSA9ICdUdWJlR2VvbWV0cnknO1xuXG5cdFx0dGhpcy5wYXJhbWV0ZXJzID0ge1xuXHRcdFx0cGF0aDogcGF0aCxcblx0XHRcdHR1YnVsYXJTZWdtZW50czogdHVidWxhclNlZ21lbnRzLFxuXHRcdFx0cmFkaXVzOiByYWRpdXMsXG5cdFx0XHRyYWRpYWxTZWdtZW50czogcmFkaWFsU2VnbWVudHMsXG5cdFx0XHRjbG9zZWQ6IGNsb3NlZFxuXHRcdH07XG5cblx0XHRjb25zdCBmcmFtZXMgPSBwYXRoLmNvbXB1dGVGcmVuZXRGcmFtZXMoIHR1YnVsYXJTZWdtZW50cywgY2xvc2VkICk7XG5cblx0XHQvLyBleHBvc2UgaW50ZXJuYWxzXG5cblx0XHR0aGlzLnRhbmdlbnRzID0gZnJhbWVzLnRhbmdlbnRzO1xuXHRcdHRoaXMubm9ybWFscyA9IGZyYW1lcy5ub3JtYWxzO1xuXHRcdHRoaXMuYmlub3JtYWxzID0gZnJhbWVzLmJpbm9ybWFscztcblxuXHRcdC8vIGhlbHBlciB2YXJpYWJsZXNcblxuXHRcdGNvbnN0IHZlcnRleCA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0Y29uc3Qgbm9ybWFsID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCB1diA9IG5ldyBWZWN0b3IyKCk7XG5cdFx0bGV0IFAgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0Ly8gYnVmZmVyXG5cblx0XHRjb25zdCB2ZXJ0aWNlcyA9IFtdO1xuXHRcdGNvbnN0IG5vcm1hbHMgPSBbXTtcblx0XHRjb25zdCB1dnMgPSBbXTtcblx0XHRjb25zdCBpbmRpY2VzID0gW107XG5cblx0XHQvLyBjcmVhdGUgYnVmZmVyIGRhdGFcblxuXHRcdGdlbmVyYXRlQnVmZmVyRGF0YSgpO1xuXG5cdFx0Ly8gYnVpbGQgZ2VvbWV0cnlcblxuXHRcdHRoaXMuc2V0SW5kZXgoIGluZGljZXMgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ25vcm1hbCcsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBub3JtYWxzLCAzICkgKTtcblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3V2JywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHV2cywgMiApICk7XG5cblx0XHQvLyBmdW5jdGlvbnNcblxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlQnVmZmVyRGF0YSgpIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdHVidWxhclNlZ21lbnRzOyBpICsrICkge1xuXG5cdFx0XHRcdGdlbmVyYXRlU2VnbWVudCggaSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGlmIHRoZSBnZW9tZXRyeSBpcyBub3QgY2xvc2VkLCBnZW5lcmF0ZSB0aGUgbGFzdCByb3cgb2YgdmVydGljZXMgYW5kIG5vcm1hbHNcblx0XHRcdC8vIGF0IHRoZSByZWd1bGFyIHBvc2l0aW9uIG9uIHRoZSBnaXZlbiBwYXRoXG5cdFx0XHQvL1xuXHRcdFx0Ly8gaWYgdGhlIGdlb21ldHJ5IGlzIGNsb3NlZCwgZHVwbGljYXRlIHRoZSBmaXJzdCByb3cgb2YgdmVydGljZXMgYW5kIG5vcm1hbHMgKHV2cyB3aWxsIGRpZmZlcilcblxuXHRcdFx0Z2VuZXJhdGVTZWdtZW50KCAoIGNsb3NlZCA9PT0gZmFsc2UgKSA/IHR1YnVsYXJTZWdtZW50cyA6IDAgKTtcblxuXHRcdFx0Ly8gdXZzIGFyZSBnZW5lcmF0ZWQgaW4gYSBzZXBhcmF0ZSBmdW5jdGlvbi5cblx0XHRcdC8vIHRoaXMgbWFrZXMgaXQgZWFzeSBjb21wdXRlIGNvcnJlY3QgdmFsdWVzIGZvciBjbG9zZWQgZ2VvbWV0cmllc1xuXG5cdFx0XHRnZW5lcmF0ZVVWcygpO1xuXG5cdFx0XHQvLyBmaW5hbGx5IGNyZWF0ZSBmYWNlc1xuXG5cdFx0XHRnZW5lcmF0ZUluZGljZXMoKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlU2VnbWVudCggaSApIHtcblxuXHRcdFx0Ly8gd2UgdXNlIGdldFBvaW50QXQgdG8gc2FtcGxlIGV2ZW5seSBkaXN0cmlidXRlZCBwb2ludHMgZnJvbSB0aGUgZ2l2ZW4gcGF0aFxuXG5cdFx0XHRQID0gcGF0aC5nZXRQb2ludEF0KCBpIC8gdHVidWxhclNlZ21lbnRzLCBQICk7XG5cblx0XHRcdC8vIHJldHJpZXZlIGNvcnJlc3BvbmRpbmcgbm9ybWFsIGFuZCBiaW5vcm1hbFxuXG5cdFx0XHRjb25zdCBOID0gZnJhbWVzLm5vcm1hbHNbIGkgXTtcblx0XHRcdGNvbnN0IEIgPSBmcmFtZXMuYmlub3JtYWxzWyBpIF07XG5cblx0XHRcdC8vIGdlbmVyYXRlIG5vcm1hbHMgYW5kIHZlcnRpY2VzIGZvciB0aGUgY3VycmVudCBzZWdtZW50XG5cblx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSByYWRpYWxTZWdtZW50czsgaiArKyApIHtcblxuXHRcdFx0XHRjb25zdCB2ID0gaiAvIHJhZGlhbFNlZ21lbnRzICogTWF0aC5QSSAqIDI7XG5cblx0XHRcdFx0Y29uc3Qgc2luID0gTWF0aC5zaW4oIHYgKTtcblx0XHRcdFx0Y29uc3QgY29zID0gLSBNYXRoLmNvcyggdiApO1xuXG5cdFx0XHRcdC8vIG5vcm1hbFxuXG5cdFx0XHRcdG5vcm1hbC54ID0gKCBjb3MgKiBOLnggKyBzaW4gKiBCLnggKTtcblx0XHRcdFx0bm9ybWFsLnkgPSAoIGNvcyAqIE4ueSArIHNpbiAqIEIueSApO1xuXHRcdFx0XHRub3JtYWwueiA9ICggY29zICogTi56ICsgc2luICogQi56ICk7XG5cdFx0XHRcdG5vcm1hbC5ub3JtYWxpemUoKTtcblxuXHRcdFx0XHRub3JtYWxzLnB1c2goIG5vcm1hbC54LCBub3JtYWwueSwgbm9ybWFsLnogKTtcblxuXHRcdFx0XHQvLyB2ZXJ0ZXhcblxuXHRcdFx0XHR2ZXJ0ZXgueCA9IFAueCArIHJhZGl1cyAqIG5vcm1hbC54O1xuXHRcdFx0XHR2ZXJ0ZXgueSA9IFAueSArIHJhZGl1cyAqIG5vcm1hbC55O1xuXHRcdFx0XHR2ZXJ0ZXgueiA9IFAueiArIHJhZGl1cyAqIG5vcm1hbC56O1xuXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHZlcnRleC54LCB2ZXJ0ZXgueSwgdmVydGV4LnogKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gZ2VuZXJhdGVJbmRpY2VzKCkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaiA9IDE7IGogPD0gdHVidWxhclNlZ21lbnRzOyBqICsrICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBpID0gMTsgaSA8PSByYWRpYWxTZWdtZW50czsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGEgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogKCBqIC0gMSApICsgKCBpIC0gMSApO1xuXHRcdFx0XHRcdGNvbnN0IGIgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogaiArICggaSAtIDEgKTtcblx0XHRcdFx0XHRjb25zdCBjID0gKCByYWRpYWxTZWdtZW50cyArIDEgKSAqIGogKyBpO1xuXHRcdFx0XHRcdGNvbnN0IGQgPSAoIHJhZGlhbFNlZ21lbnRzICsgMSApICogKCBqIC0gMSApICsgaTtcblxuXHRcdFx0XHRcdC8vIGZhY2VzXG5cblx0XHRcdFx0XHRpbmRpY2VzLnB1c2goIGEsIGIsIGQgKTtcblx0XHRcdFx0XHRpbmRpY2VzLnB1c2goIGIsIGMsIGQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdlbmVyYXRlVVZzKCkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPD0gdHVidWxhclNlZ21lbnRzOyBpICsrICkge1xuXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8PSByYWRpYWxTZWdtZW50czsgaiArKyApIHtcblxuXHRcdFx0XHRcdHV2LnggPSBpIC8gdHVidWxhclNlZ21lbnRzO1xuXHRcdFx0XHRcdHV2LnkgPSBqIC8gcmFkaWFsU2VnbWVudHM7XG5cblx0XHRcdFx0XHR1dnMucHVzaCggdXYueCwgdXYueSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcblxuXHRcdGRhdGEucGF0aCA9IHRoaXMucGFyYW1ldGVycy5wYXRoLnRvSlNPTigpO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG5cdHN0YXRpYyBmcm9tSlNPTiggZGF0YSApIHtcblxuXHRcdC8vIFRoaXMgb25seSB3b3JrcyBmb3IgYnVpbHQtaW4gY3VydmVzIChlLmcuIENhdG11bGxSb21DdXJ2ZTMpLlxuXHRcdC8vIFVzZXIgZGVmaW5lZCBjdXJ2ZXMgb3IgaW5zdGFuY2VzIG9mIEN1cnZlUGF0aCB3aWxsIG5vdCBiZSBkZXNlcmlhbGl6ZWQuXG5cdFx0cmV0dXJuIG5ldyBUdWJlR2VvbWV0cnkoXG5cdFx0XHRuZXcgQ3VydmVzWyBkYXRhLnBhdGgudHlwZSBdKCkuZnJvbUpTT04oIGRhdGEucGF0aCApLFxuXHRcdFx0ZGF0YS50dWJ1bGFyU2VnbWVudHMsXG5cdFx0XHRkYXRhLnJhZGl1cyxcblx0XHRcdGRhdGEucmFkaWFsU2VnbWVudHMsXG5cdFx0XHRkYXRhLmNsb3NlZFxuXHRcdCk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFdpcmVmcmFtZUdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCBnZW9tZXRyeSA9IG51bGwgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ1dpcmVmcmFtZUdlb21ldHJ5JztcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IHtcblx0XHRcdGdlb21ldHJ5OiBnZW9tZXRyeVxuXHRcdH07XG5cblx0XHRpZiAoIGdlb21ldHJ5ICE9PSBudWxsICkge1xuXG5cdFx0XHQvLyBidWZmZXJcblxuXHRcdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcblx0XHRcdGNvbnN0IGVkZ2VzID0gbmV3IFNldCgpO1xuXG5cdFx0XHQvLyBoZWxwZXIgdmFyaWFibGVzXG5cblx0XHRcdGNvbnN0IHN0YXJ0ID0gbmV3IFZlY3RvcjMoKTtcblx0XHRcdGNvbnN0IGVuZCA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRcdGlmICggZ2VvbWV0cnkuaW5kZXggIT09IG51bGwgKSB7XG5cblx0XHRcdFx0Ly8gaW5kZXhlZCBCdWZmZXJHZW9tZXRyeVxuXG5cdFx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2VvbWV0cnkuYXR0cmlidXRlcy5wb3NpdGlvbjtcblx0XHRcdFx0Y29uc3QgaW5kaWNlcyA9IGdlb21ldHJ5LmluZGV4O1xuXHRcdFx0XHRsZXQgZ3JvdXBzID0gZ2VvbWV0cnkuZ3JvdXBzO1xuXG5cdFx0XHRcdGlmICggZ3JvdXBzLmxlbmd0aCA9PT0gMCApIHtcblxuXHRcdFx0XHRcdGdyb3VwcyA9IFsgeyBzdGFydDogMCwgY291bnQ6IGluZGljZXMuY291bnQsIG1hdGVyaWFsSW5kZXg6IDAgfSBdO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBjcmVhdGUgYSBkYXRhIHN0cnVjdHVyZSB0aGF0IGNvbnRhaW5zIGFsbCBlZGdlcyB3aXRob3V0IGR1cGxpY2F0ZXNcblxuXHRcdFx0XHRmb3IgKCBsZXQgbyA9IDAsIG9sID0gZ3JvdXBzLmxlbmd0aDsgbyA8IG9sOyArKyBvICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIG8gXTtcblxuXHRcdFx0XHRcdGNvbnN0IGdyb3VwU3RhcnQgPSBncm91cC5zdGFydDtcblx0XHRcdFx0XHRjb25zdCBncm91cENvdW50ID0gZ3JvdXAuY291bnQ7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IGdyb3VwU3RhcnQsIGwgPSAoIGdyb3VwU3RhcnQgKyBncm91cENvdW50ICk7IGkgPCBsOyBpICs9IDMgKSB7XG5cblx0XHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IDM7IGogKysgKSB7XG5cblx0XHRcdFx0XHRcdFx0Y29uc3QgaW5kZXgxID0gaW5kaWNlcy5nZXRYKCBpICsgaiApO1xuXHRcdFx0XHRcdFx0XHRjb25zdCBpbmRleDIgPSBpbmRpY2VzLmdldFgoIGkgKyAoIGogKyAxICkgJSAzICk7XG5cblx0XHRcdFx0XHRcdFx0c3RhcnQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIGluZGV4MSApO1xuXHRcdFx0XHRcdFx0XHRlbmQuZnJvbUJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb24sIGluZGV4MiApO1xuXG5cdFx0XHRcdFx0XHRcdGlmICggaXNVbmlxdWVFZGdlKCBzdGFydCwgZW5kLCBlZGdlcyApID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0dmVydGljZXMucHVzaCggc3RhcnQueCwgc3RhcnQueSwgc3RhcnQueiApO1xuXHRcdFx0XHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIGVuZC54LCBlbmQueSwgZW5kLnogKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gbm9uLWluZGV4ZWQgQnVmZmVyR2VvbWV0cnlcblxuXHRcdFx0XHRjb25zdCBwb3NpdGlvbiA9IGdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb247XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gKCBwb3NpdGlvbi5jb3VudCAvIDMgKTsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCAzOyBqICsrICkge1xuXG5cdFx0XHRcdFx0XHQvLyB0aHJlZSBlZGdlcyBwZXIgdHJpYW5nbGUsIGFuIGVkZ2UgaXMgcmVwcmVzZW50ZWQgYXMgKGluZGV4MSwgaW5kZXgyKVxuXHRcdFx0XHRcdFx0Ly8gZS5nLiB0aGUgZmlyc3QgdHJpYW5nbGUgaGFzIHRoZSBmb2xsb3dpbmcgZWRnZXM6ICgwLDEpLCgxLDIpLCgyLDApXG5cblx0XHRcdFx0XHRcdGNvbnN0IGluZGV4MSA9IDMgKiBpICsgajtcblx0XHRcdFx0XHRcdGNvbnN0IGluZGV4MiA9IDMgKiBpICsgKCAoIGogKyAxICkgJSAzICk7XG5cblx0XHRcdFx0XHRcdHN0YXJ0LmZyb21CdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9uLCBpbmRleDEgKTtcblx0XHRcdFx0XHRcdGVuZC5mcm9tQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbiwgaW5kZXgyICk7XG5cblx0XHRcdFx0XHRcdGlmICggaXNVbmlxdWVFZGdlKCBzdGFydCwgZW5kLCBlZGdlcyApID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0XHRcdHZlcnRpY2VzLnB1c2goIHN0YXJ0LngsIHN0YXJ0LnksIHN0YXJ0LnogKTtcblx0XHRcdFx0XHRcdFx0dmVydGljZXMucHVzaCggZW5kLngsIGVuZC55LCBlbmQueiApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGJ1aWxkIGdlb21ldHJ5XG5cblx0XHRcdHRoaXMuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMucGFyYW1ldGVycyA9IE9iamVjdC5hc3NpZ24oIHt9LCBzb3VyY2UucGFyYW1ldGVycyApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIGlzVW5pcXVlRWRnZSggc3RhcnQsIGVuZCwgZWRnZXMgKSB7XG5cblx0Y29uc3QgaGFzaDEgPSBgJHtzdGFydC54fSwke3N0YXJ0Lnl9LCR7c3RhcnQuen0tJHtlbmQueH0sJHtlbmQueX0sJHtlbmQuen1gO1xuXHRjb25zdCBoYXNoMiA9IGAke2VuZC54fSwke2VuZC55fSwke2VuZC56fS0ke3N0YXJ0Lnh9LCR7c3RhcnQueX0sJHtzdGFydC56fWA7IC8vIGNvaW5jaWRlbnQgZWRnZVxuXG5cdGlmICggZWRnZXMuaGFzKCBoYXNoMSApID09PSB0cnVlIHx8IGVkZ2VzLmhhcyggaGFzaDIgKSA9PT0gdHJ1ZSApIHtcblxuXHRcdHJldHVybiBmYWxzZTtcblxuXHR9IGVsc2Uge1xuXG5cdFx0ZWRnZXMuYWRkKCBoYXNoMSApO1xuXHRcdGVkZ2VzLmFkZCggaGFzaDIgKTtcblx0XHRyZXR1cm4gdHJ1ZTtcblxuXHR9XG5cbn1cblxudmFyIEdlb21ldHJpZXMgPSAvKiNfX1BVUkVfXyovT2JqZWN0LmZyZWV6ZSh7XG5cdF9fcHJvdG9fXzogbnVsbCxcblx0Qm94R2VvbWV0cnk6IEJveEdlb21ldHJ5LFxuXHRDYXBzdWxlR2VvbWV0cnk6IENhcHN1bGVHZW9tZXRyeSxcblx0Q2lyY2xlR2VvbWV0cnk6IENpcmNsZUdlb21ldHJ5LFxuXHRDb25lR2VvbWV0cnk6IENvbmVHZW9tZXRyeSxcblx0Q3lsaW5kZXJHZW9tZXRyeTogQ3lsaW5kZXJHZW9tZXRyeSxcblx0RG9kZWNhaGVkcm9uR2VvbWV0cnk6IERvZGVjYWhlZHJvbkdlb21ldHJ5LFxuXHRFZGdlc0dlb21ldHJ5OiBFZGdlc0dlb21ldHJ5LFxuXHRFeHRydWRlR2VvbWV0cnk6IEV4dHJ1ZGVHZW9tZXRyeSxcblx0SWNvc2FoZWRyb25HZW9tZXRyeTogSWNvc2FoZWRyb25HZW9tZXRyeSxcblx0TGF0aGVHZW9tZXRyeTogTGF0aGVHZW9tZXRyeSxcblx0T2N0YWhlZHJvbkdlb21ldHJ5OiBPY3RhaGVkcm9uR2VvbWV0cnksXG5cdFBsYW5lR2VvbWV0cnk6IFBsYW5lR2VvbWV0cnksXG5cdFBvbHloZWRyb25HZW9tZXRyeTogUG9seWhlZHJvbkdlb21ldHJ5LFxuXHRSaW5nR2VvbWV0cnk6IFJpbmdHZW9tZXRyeSxcblx0U2hhcGVHZW9tZXRyeTogU2hhcGVHZW9tZXRyeSxcblx0U3BoZXJlR2VvbWV0cnk6IFNwaGVyZUdlb21ldHJ5LFxuXHRUZXRyYWhlZHJvbkdlb21ldHJ5OiBUZXRyYWhlZHJvbkdlb21ldHJ5LFxuXHRUb3J1c0dlb21ldHJ5OiBUb3J1c0dlb21ldHJ5LFxuXHRUb3J1c0tub3RHZW9tZXRyeTogVG9ydXNLbm90R2VvbWV0cnksXG5cdFR1YmVHZW9tZXRyeTogVHViZUdlb21ldHJ5LFxuXHRXaXJlZnJhbWVHZW9tZXRyeTogV2lyZWZyYW1lR2VvbWV0cnlcbn0pO1xuXG5jbGFzcyBTaGFkb3dNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzU2hhZG93TWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ1NoYWRvd01hdGVyaWFsJztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4MDAwMDAwICk7XG5cdFx0dGhpcy50cmFuc3BhcmVudCA9IHRydWU7XG5cblx0XHR0aGlzLmZvZyA9IHRydWU7XG5cblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XG5cblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgUmF3U2hhZGVyTWF0ZXJpYWwgZXh0ZW5kcyBTaGFkZXJNYXRlcmlhbCB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XG5cblx0XHRzdXBlciggcGFyYW1ldGVycyApO1xuXG5cdFx0dGhpcy5pc1Jhd1NoYWRlck1hdGVyaWFsID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdSYXdTaGFkZXJNYXRlcmlhbCc7XG5cblx0fVxuXG59XG5cbmNsYXNzIE1lc2hTdGFuZGFyZE1hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNNZXNoU3RhbmRhcmRNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLmRlZmluZXMgPSB7ICdTVEFOREFSRCc6ICcnIH07XG5cblx0XHR0aGlzLnR5cGUgPSAnTWVzaFN0YW5kYXJkTWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHhmZmZmZmYgKTsgLy8gZGlmZnVzZVxuXHRcdHRoaXMucm91Z2huZXNzID0gMS4wO1xuXHRcdHRoaXMubWV0YWxuZXNzID0gMC4wO1xuXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5saWdodE1hcCA9IG51bGw7XG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IDEuMDtcblxuXHRcdHRoaXMuYW9NYXAgPSBudWxsO1xuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSAxLjA7XG5cblx0XHR0aGlzLmVtaXNzaXZlID0gbmV3IENvbG9yKCAweDAwMDAwMCApO1xuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSAxLjA7XG5cdFx0dGhpcy5lbWlzc2l2ZU1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmJ1bXBNYXAgPSBudWxsO1xuXHRcdHRoaXMuYnVtcFNjYWxlID0gMTtcblxuXHRcdHRoaXMubm9ybWFsTWFwID0gbnVsbDtcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBUYW5nZW50U3BhY2VOb3JtYWxNYXA7XG5cdFx0dGhpcy5ub3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XG5cblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IG51bGw7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IDE7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gMDtcblxuXHRcdHRoaXMucm91Z2huZXNzTWFwID0gbnVsbDtcblxuXHRcdHRoaXMubWV0YWxuZXNzTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5lbnZNYXAgPSBudWxsO1xuXHRcdHRoaXMuZW52TWFwUm90YXRpb24gPSBuZXcgRXVsZXIoKTtcblx0XHR0aGlzLmVudk1hcEludGVuc2l0eSA9IDEuMDtcblxuXHRcdHRoaXMud2lyZWZyYW1lID0gZmFsc2U7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPSAxO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWNhcCA9ICdyb3VuZCc7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9ICdyb3VuZCc7XG5cblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gZmFsc2U7XG5cblx0XHR0aGlzLmZvZyA9IHRydWU7XG5cblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuZGVmaW5lcyA9IHsgJ1NUQU5EQVJEJzogJycgfTtcblxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XG5cdFx0dGhpcy5yb3VnaG5lc3MgPSBzb3VyY2Uucm91Z2huZXNzO1xuXHRcdHRoaXMubWV0YWxuZXNzID0gc291cmNlLm1ldGFsbmVzcztcblxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcblxuXHRcdHRoaXMubGlnaHRNYXAgPSBzb3VyY2UubGlnaHRNYXA7XG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IHNvdXJjZS5saWdodE1hcEludGVuc2l0eTtcblxuXHRcdHRoaXMuYW9NYXAgPSBzb3VyY2UuYW9NYXA7XG5cdFx0dGhpcy5hb01hcEludGVuc2l0eSA9IHNvdXJjZS5hb01hcEludGVuc2l0eTtcblxuXHRcdHRoaXMuZW1pc3NpdmUuY29weSggc291cmNlLmVtaXNzaXZlICk7XG5cdFx0dGhpcy5lbWlzc2l2ZU1hcCA9IHNvdXJjZS5lbWlzc2l2ZU1hcDtcblx0XHR0aGlzLmVtaXNzaXZlSW50ZW5zaXR5ID0gc291cmNlLmVtaXNzaXZlSW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5idW1wTWFwID0gc291cmNlLmJ1bXBNYXA7XG5cdFx0dGhpcy5idW1wU2NhbGUgPSBzb3VyY2UuYnVtcFNjYWxlO1xuXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBzb3VyY2Uubm9ybWFsTWFwO1xuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IHNvdXJjZS5ub3JtYWxNYXBUeXBlO1xuXHRcdHRoaXMubm9ybWFsU2NhbGUuY29weSggc291cmNlLm5vcm1hbFNjYWxlICk7XG5cblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IHNvdXJjZS5kaXNwbGFjZW1lbnRTY2FsZTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcblxuXHRcdHRoaXMucm91Z2huZXNzTWFwID0gc291cmNlLnJvdWdobmVzc01hcDtcblxuXHRcdHRoaXMubWV0YWxuZXNzTWFwID0gc291cmNlLm1ldGFsbmVzc01hcDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBzb3VyY2UuYWxwaGFNYXA7XG5cblx0XHR0aGlzLmVudk1hcCA9IHNvdXJjZS5lbnZNYXA7XG5cdFx0dGhpcy5lbnZNYXBSb3RhdGlvbi5jb3B5KCBzb3VyY2UuZW52TWFwUm90YXRpb24gKTtcblx0XHR0aGlzLmVudk1hcEludGVuc2l0eSA9IHNvdXJjZS5lbnZNYXBJbnRlbnNpdHk7XG5cblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPSBzb3VyY2Uud2lyZWZyYW1lTGluZXdpZHRoO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWNhcCA9IHNvdXJjZS53aXJlZnJhbWVMaW5lY2FwO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSBzb3VyY2Uud2lyZWZyYW1lTGluZWpvaW47XG5cblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gc291cmNlLmZsYXRTaGFkaW5nO1xuXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIE1lc2hQaHlzaWNhbE1hdGVyaWFsIGV4dGVuZHMgTWVzaFN0YW5kYXJkTWF0ZXJpYWwge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNNZXNoUGh5c2ljYWxNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLmRlZmluZXMgPSB7XG5cblx0XHRcdCdTVEFOREFSRCc6ICcnLFxuXHRcdFx0J1BIWVNJQ0FMJzogJydcblxuXHRcdH07XG5cblx0XHR0aGlzLnR5cGUgPSAnTWVzaFBoeXNpY2FsTWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5hbmlzb3Ryb3B5Um90YXRpb24gPSAwO1xuXHRcdHRoaXMuYW5pc290cm9weU1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmNsZWFyY29hdE1hcCA9IG51bGw7XG5cdFx0dGhpcy5jbGVhcmNvYXRSb3VnaG5lc3MgPSAwLjA7XG5cdFx0dGhpcy5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgPSBudWxsO1xuXHRcdHRoaXMuY2xlYXJjb2F0Tm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xuXHRcdHRoaXMuY2xlYXJjb2F0Tm9ybWFsTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuaW9yID0gMS41O1xuXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAncmVmbGVjdGl2aXR5Jywge1xuXHRcdFx0Z2V0OiBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdFx0cmV0dXJuICggY2xhbXAoIDIuNSAqICggdGhpcy5pb3IgLSAxICkgLyAoIHRoaXMuaW9yICsgMSApLCAwLCAxICkgKTtcblxuXHRcdFx0fSxcblx0XHRcdHNldDogZnVuY3Rpb24gKCByZWZsZWN0aXZpdHkgKSB7XG5cblx0XHRcdFx0dGhpcy5pb3IgPSAoIDEgKyAwLjQgKiByZWZsZWN0aXZpdHkgKSAvICggMSAtIDAuNCAqIHJlZmxlY3Rpdml0eSApO1xuXG5cdFx0XHR9XG5cdFx0fSApO1xuXG5cdFx0dGhpcy5pcmlkZXNjZW5jZU1hcCA9IG51bGw7XG5cdFx0dGhpcy5pcmlkZXNjZW5jZUlPUiA9IDEuMztcblx0XHR0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzUmFuZ2UgPSBbIDEwMCwgNDAwIF07XG5cdFx0dGhpcy5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcCA9IG51bGw7XG5cblx0XHR0aGlzLnNoZWVuQ29sb3IgPSBuZXcgQ29sb3IoIDB4MDAwMDAwICk7XG5cdFx0dGhpcy5zaGVlbkNvbG9yTWFwID0gbnVsbDtcblx0XHR0aGlzLnNoZWVuUm91Z2huZXNzID0gMS4wO1xuXHRcdHRoaXMuc2hlZW5Sb3VnaG5lc3NNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy50cmFuc21pc3Npb25NYXAgPSBudWxsO1xuXG5cdFx0dGhpcy50aGlja25lc3MgPSAwO1xuXHRcdHRoaXMudGhpY2tuZXNzTWFwID0gbnVsbDtcblx0XHR0aGlzLmF0dGVudWF0aW9uRGlzdGFuY2UgPSBJbmZpbml0eTtcblx0XHR0aGlzLmF0dGVudWF0aW9uQ29sb3IgPSBuZXcgQ29sb3IoIDEsIDEsIDEgKTtcblxuXHRcdHRoaXMuc3BlY3VsYXJJbnRlbnNpdHkgPSAxLjA7XG5cdFx0dGhpcy5zcGVjdWxhckludGVuc2l0eU1hcCA9IG51bGw7XG5cdFx0dGhpcy5zcGVjdWxhckNvbG9yID0gbmV3IENvbG9yKCAxLCAxLCAxICk7XG5cdFx0dGhpcy5zcGVjdWxhckNvbG9yTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuX2FuaXNvdHJvcHkgPSAwO1xuXHRcdHRoaXMuX2NsZWFyY29hdCA9IDA7XG5cdFx0dGhpcy5fZGlzcGVyc2lvbiA9IDA7XG5cdFx0dGhpcy5faXJpZGVzY2VuY2UgPSAwO1xuXHRcdHRoaXMuX3NoZWVuID0gMC4wO1xuXHRcdHRoaXMuX3RyYW5zbWlzc2lvbiA9IDA7XG5cblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdH1cblxuXHRnZXQgYW5pc290cm9weSgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9hbmlzb3Ryb3B5O1xuXG5cdH1cblxuXHRzZXQgYW5pc290cm9weSggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHRoaXMuX2FuaXNvdHJvcHkgPiAwICE9PSB2YWx1ZSA+IDAgKSB7XG5cblx0XHRcdHRoaXMudmVyc2lvbiArKztcblxuXHRcdH1cblxuXHRcdHRoaXMuX2FuaXNvdHJvcHkgPSB2YWx1ZTtcblxuXHR9XG5cblx0Z2V0IGNsZWFyY29hdCgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9jbGVhcmNvYXQ7XG5cblx0fVxuXG5cdHNldCBjbGVhcmNvYXQoIHZhbHVlICkge1xuXG5cdFx0aWYgKCB0aGlzLl9jbGVhcmNvYXQgPiAwICE9PSB2YWx1ZSA+IDAgKSB7XG5cblx0XHRcdHRoaXMudmVyc2lvbiArKztcblxuXHRcdH1cblxuXHRcdHRoaXMuX2NsZWFyY29hdCA9IHZhbHVlO1xuXG5cdH1cblxuXHRnZXQgaXJpZGVzY2VuY2UoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5faXJpZGVzY2VuY2U7XG5cblx0fVxuXG5cdHNldCBpcmlkZXNjZW5jZSggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHRoaXMuX2lyaWRlc2NlbmNlID4gMCAhPT0gdmFsdWUgPiAwICkge1xuXG5cdFx0XHR0aGlzLnZlcnNpb24gKys7XG5cblx0XHR9XG5cblx0XHR0aGlzLl9pcmlkZXNjZW5jZSA9IHZhbHVlO1xuXG5cdH1cblxuXHRnZXQgZGlzcGVyc2lvbigpIHtcblxuXHRcdHJldHVybiB0aGlzLl9kaXNwZXJzaW9uO1xuXG5cdH1cblxuXHRzZXQgZGlzcGVyc2lvbiggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHRoaXMuX2Rpc3BlcnNpb24gPiAwICE9PSB2YWx1ZSA+IDAgKSB7XG5cblx0XHRcdHRoaXMudmVyc2lvbiArKztcblxuXHRcdH1cblxuXHRcdHRoaXMuX2Rpc3BlcnNpb24gPSB2YWx1ZTtcblxuXHR9XG5cblx0Z2V0IHNoZWVuKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3NoZWVuO1xuXG5cdH1cblxuXHRzZXQgc2hlZW4oIHZhbHVlICkge1xuXG5cdFx0aWYgKCB0aGlzLl9zaGVlbiA+IDAgIT09IHZhbHVlID4gMCApIHtcblxuXHRcdFx0dGhpcy52ZXJzaW9uICsrO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5fc2hlZW4gPSB2YWx1ZTtcblxuXHR9XG5cblx0Z2V0IHRyYW5zbWlzc2lvbigpIHtcblxuXHRcdHJldHVybiB0aGlzLl90cmFuc21pc3Npb247XG5cblx0fVxuXG5cdHNldCB0cmFuc21pc3Npb24oIHZhbHVlICkge1xuXG5cdFx0aWYgKCB0aGlzLl90cmFuc21pc3Npb24gPiAwICE9PSB2YWx1ZSA+IDAgKSB7XG5cblx0XHRcdHRoaXMudmVyc2lvbiArKztcblxuXHRcdH1cblxuXHRcdHRoaXMuX3RyYW5zbWlzc2lvbiA9IHZhbHVlO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuZGVmaW5lcyA9IHtcblxuXHRcdFx0J1NUQU5EQVJEJzogJycsXG5cdFx0XHQnUEhZU0lDQUwnOiAnJ1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuYW5pc290cm9weSA9IHNvdXJjZS5hbmlzb3Ryb3B5O1xuXHRcdHRoaXMuYW5pc290cm9weVJvdGF0aW9uID0gc291cmNlLmFuaXNvdHJvcHlSb3RhdGlvbjtcblx0XHR0aGlzLmFuaXNvdHJvcHlNYXAgPSBzb3VyY2UuYW5pc290cm9weU1hcDtcblxuXHRcdHRoaXMuY2xlYXJjb2F0ID0gc291cmNlLmNsZWFyY29hdDtcblx0XHR0aGlzLmNsZWFyY29hdE1hcCA9IHNvdXJjZS5jbGVhcmNvYXRNYXA7XG5cdFx0dGhpcy5jbGVhcmNvYXRSb3VnaG5lc3MgPSBzb3VyY2UuY2xlYXJjb2F0Um91Z2huZXNzO1xuXHRcdHRoaXMuY2xlYXJjb2F0Um91Z2huZXNzTWFwID0gc291cmNlLmNsZWFyY29hdFJvdWdobmVzc01hcDtcblx0XHR0aGlzLmNsZWFyY29hdE5vcm1hbE1hcCA9IHNvdXJjZS5jbGVhcmNvYXROb3JtYWxNYXA7XG5cdFx0dGhpcy5jbGVhcmNvYXROb3JtYWxTY2FsZS5jb3B5KCBzb3VyY2UuY2xlYXJjb2F0Tm9ybWFsU2NhbGUgKTtcblxuXHRcdHRoaXMuZGlzcGVyc2lvbiA9IHNvdXJjZS5kaXNwZXJzaW9uO1xuXHRcdHRoaXMuaW9yID0gc291cmNlLmlvcjtcblxuXHRcdHRoaXMuaXJpZGVzY2VuY2UgPSBzb3VyY2UuaXJpZGVzY2VuY2U7XG5cdFx0dGhpcy5pcmlkZXNjZW5jZU1hcCA9IHNvdXJjZS5pcmlkZXNjZW5jZU1hcDtcblx0XHR0aGlzLmlyaWRlc2NlbmNlSU9SID0gc291cmNlLmlyaWRlc2NlbmNlSU9SO1xuXHRcdHRoaXMuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZSA9IFsgLi4uc291cmNlLmlyaWRlc2NlbmNlVGhpY2tuZXNzUmFuZ2UgXTtcblx0XHR0aGlzLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwID0gc291cmNlLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwO1xuXG5cdFx0dGhpcy5zaGVlbiA9IHNvdXJjZS5zaGVlbjtcblx0XHR0aGlzLnNoZWVuQ29sb3IuY29weSggc291cmNlLnNoZWVuQ29sb3IgKTtcblx0XHR0aGlzLnNoZWVuQ29sb3JNYXAgPSBzb3VyY2Uuc2hlZW5Db2xvck1hcDtcblx0XHR0aGlzLnNoZWVuUm91Z2huZXNzID0gc291cmNlLnNoZWVuUm91Z2huZXNzO1xuXHRcdHRoaXMuc2hlZW5Sb3VnaG5lc3NNYXAgPSBzb3VyY2Uuc2hlZW5Sb3VnaG5lc3NNYXA7XG5cblx0XHR0aGlzLnRyYW5zbWlzc2lvbiA9IHNvdXJjZS50cmFuc21pc3Npb247XG5cdFx0dGhpcy50cmFuc21pc3Npb25NYXAgPSBzb3VyY2UudHJhbnNtaXNzaW9uTWFwO1xuXG5cdFx0dGhpcy50aGlja25lc3MgPSBzb3VyY2UudGhpY2tuZXNzO1xuXHRcdHRoaXMudGhpY2tuZXNzTWFwID0gc291cmNlLnRoaWNrbmVzc01hcDtcblx0XHR0aGlzLmF0dGVudWF0aW9uRGlzdGFuY2UgPSBzb3VyY2UuYXR0ZW51YXRpb25EaXN0YW5jZTtcblx0XHR0aGlzLmF0dGVudWF0aW9uQ29sb3IuY29weSggc291cmNlLmF0dGVudWF0aW9uQ29sb3IgKTtcblxuXHRcdHRoaXMuc3BlY3VsYXJJbnRlbnNpdHkgPSBzb3VyY2Uuc3BlY3VsYXJJbnRlbnNpdHk7XG5cdFx0dGhpcy5zcGVjdWxhckludGVuc2l0eU1hcCA9IHNvdXJjZS5zcGVjdWxhckludGVuc2l0eU1hcDtcblx0XHR0aGlzLnNwZWN1bGFyQ29sb3IuY29weSggc291cmNlLnNwZWN1bGFyQ29sb3IgKTtcblx0XHR0aGlzLnNwZWN1bGFyQ29sb3JNYXAgPSBzb3VyY2Uuc3BlY3VsYXJDb2xvck1hcDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBNZXNoUGhvbmdNYXRlcmlhbCBleHRlbmRzIE1hdGVyaWFsIHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVycyApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmlzTWVzaFBob25nTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ01lc2hQaG9uZ01hdGVyaWFsJztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7IC8vIGRpZmZ1c2Vcblx0XHR0aGlzLnNwZWN1bGFyID0gbmV3IENvbG9yKCAweDExMTExMSApO1xuXHRcdHRoaXMuc2hpbmluZXNzID0gMzA7XG5cblx0XHR0aGlzLm1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmxpZ2h0TWFwID0gbnVsbDtcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gMS4wO1xuXG5cdFx0dGhpcy5hb01hcCA9IG51bGw7XG5cdFx0dGhpcy5hb01hcEludGVuc2l0eSA9IDEuMDtcblxuXHRcdHRoaXMuZW1pc3NpdmUgPSBuZXcgQ29sb3IoIDB4MDAwMDAwICk7XG5cdFx0dGhpcy5lbWlzc2l2ZUludGVuc2l0eSA9IDEuMDtcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuYnVtcE1hcCA9IG51bGw7XG5cdFx0dGhpcy5idW1wU2NhbGUgPSAxO1xuXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBudWxsO1xuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IFRhbmdlbnRTcGFjZU5vcm1hbE1hcDtcblx0XHR0aGlzLm5vcm1hbFNjYWxlID0gbmV3IFZlY3RvcjIoIDEsIDEgKTtcblxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xuXG5cdFx0dGhpcy5zcGVjdWxhck1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuZW52TWFwID0gbnVsbDtcblx0XHR0aGlzLmVudk1hcFJvdGF0aW9uID0gbmV3IEV1bGVyKCk7XG5cdFx0dGhpcy5jb21iaW5lID0gTXVsdGlwbHlPcGVyYXRpb247XG5cdFx0dGhpcy5yZWZsZWN0aXZpdHkgPSAxO1xuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gMC45ODtcblxuXHRcdHRoaXMud2lyZWZyYW1lID0gZmFsc2U7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPSAxO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWNhcCA9ICdyb3VuZCc7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9ICdyb3VuZCc7XG5cblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gZmFsc2U7XG5cblx0XHR0aGlzLmZvZyA9IHRydWU7XG5cblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XG5cdFx0dGhpcy5zcGVjdWxhci5jb3B5KCBzb3VyY2Uuc3BlY3VsYXIgKTtcblx0XHR0aGlzLnNoaW5pbmVzcyA9IHNvdXJjZS5zaGluaW5lc3M7XG5cblx0XHR0aGlzLm1hcCA9IHNvdXJjZS5tYXA7XG5cblx0XHR0aGlzLmxpZ2h0TWFwID0gc291cmNlLmxpZ2h0TWFwO1xuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSBzb3VyY2UubGlnaHRNYXBJbnRlbnNpdHk7XG5cblx0XHR0aGlzLmFvTWFwID0gc291cmNlLmFvTWFwO1xuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSBzb3VyY2UuYW9NYXBJbnRlbnNpdHk7XG5cblx0XHR0aGlzLmVtaXNzaXZlLmNvcHkoIHNvdXJjZS5lbWlzc2l2ZSApO1xuXHRcdHRoaXMuZW1pc3NpdmVNYXAgPSBzb3VyY2UuZW1pc3NpdmVNYXA7XG5cdFx0dGhpcy5lbWlzc2l2ZUludGVuc2l0eSA9IHNvdXJjZS5lbWlzc2l2ZUludGVuc2l0eTtcblxuXHRcdHRoaXMuYnVtcE1hcCA9IHNvdXJjZS5idW1wTWFwO1xuXHRcdHRoaXMuYnVtcFNjYWxlID0gc291cmNlLmJ1bXBTY2FsZTtcblxuXHRcdHRoaXMubm9ybWFsTWFwID0gc291cmNlLm5vcm1hbE1hcDtcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBzb3VyY2Uubm9ybWFsTWFwVHlwZTtcblx0XHR0aGlzLm5vcm1hbFNjYWxlLmNvcHkoIHNvdXJjZS5ub3JtYWxTY2FsZSApO1xuXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBzb3VyY2UuZGlzcGxhY2VtZW50TWFwO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XG5cblx0XHR0aGlzLnNwZWN1bGFyTWFwID0gc291cmNlLnNwZWN1bGFyTWFwO1xuXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcblxuXHRcdHRoaXMuZW52TWFwID0gc291cmNlLmVudk1hcDtcblx0XHR0aGlzLmVudk1hcFJvdGF0aW9uLmNvcHkoIHNvdXJjZS5lbnZNYXBSb3RhdGlvbiApO1xuXHRcdHRoaXMuY29tYmluZSA9IHNvdXJjZS5jb21iaW5lO1xuXHRcdHRoaXMucmVmbGVjdGl2aXR5ID0gc291cmNlLnJlZmxlY3Rpdml0eTtcblx0XHR0aGlzLnJlZnJhY3Rpb25SYXRpbyA9IHNvdXJjZS5yZWZyYWN0aW9uUmF0aW87XG5cblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPSBzb3VyY2Uud2lyZWZyYW1lTGluZXdpZHRoO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWNhcCA9IHNvdXJjZS53aXJlZnJhbWVMaW5lY2FwO1xuXHRcdHRoaXMud2lyZWZyYW1lTGluZWpvaW4gPSBzb3VyY2Uud2lyZWZyYW1lTGluZWpvaW47XG5cblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gc291cmNlLmZsYXRTaGFkaW5nO1xuXG5cdFx0dGhpcy5mb2cgPSBzb3VyY2UuZm9nO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIE1lc2hUb29uTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc01lc2hUb29uTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy5kZWZpbmVzID0geyAnVE9PTic6ICcnIH07XG5cblx0XHR0aGlzLnR5cGUgPSAnTWVzaFRvb25NYXRlcmlhbCc7XG5cblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCAweGZmZmZmZiApO1xuXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xuXHRcdHRoaXMuZ3JhZGllbnRNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5saWdodE1hcCA9IG51bGw7XG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IDEuMDtcblxuXHRcdHRoaXMuYW9NYXAgPSBudWxsO1xuXHRcdHRoaXMuYW9NYXBJbnRlbnNpdHkgPSAxLjA7XG5cblx0XHR0aGlzLmVtaXNzaXZlID0gbmV3IENvbG9yKCAweDAwMDAwMCApO1xuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSAxLjA7XG5cdFx0dGhpcy5lbWlzc2l2ZU1hcCA9IG51bGw7XG5cblx0XHR0aGlzLmJ1bXBNYXAgPSBudWxsO1xuXHRcdHRoaXMuYnVtcFNjYWxlID0gMTtcblxuXHRcdHRoaXMubm9ybWFsTWFwID0gbnVsbDtcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBUYW5nZW50U3BhY2VOb3JtYWxNYXA7XG5cdFx0dGhpcy5ub3JtYWxTY2FsZSA9IG5ldyBWZWN0b3IyKCAxLCAxICk7XG5cblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IG51bGw7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IDE7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gMDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gJ3JvdW5kJztcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVqb2luID0gJ3JvdW5kJztcblxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcblxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcblxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcblx0XHR0aGlzLmdyYWRpZW50TWFwID0gc291cmNlLmdyYWRpZW50TWFwO1xuXG5cdFx0dGhpcy5saWdodE1hcCA9IHNvdXJjZS5saWdodE1hcDtcblx0XHR0aGlzLmxpZ2h0TWFwSW50ZW5zaXR5ID0gc291cmNlLmxpZ2h0TWFwSW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5hb01hcCA9IHNvdXJjZS5hb01hcDtcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gc291cmNlLmFvTWFwSW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5lbWlzc2l2ZS5jb3B5KCBzb3VyY2UuZW1pc3NpdmUgKTtcblx0XHR0aGlzLmVtaXNzaXZlTWFwID0gc291cmNlLmVtaXNzaXZlTWFwO1xuXHRcdHRoaXMuZW1pc3NpdmVJbnRlbnNpdHkgPSBzb3VyY2UuZW1pc3NpdmVJbnRlbnNpdHk7XG5cblx0XHR0aGlzLmJ1bXBNYXAgPSBzb3VyY2UuYnVtcE1hcDtcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IHNvdXJjZS5idW1wU2NhbGU7XG5cblx0XHR0aGlzLm5vcm1hbE1hcCA9IHNvdXJjZS5ub3JtYWxNYXA7XG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gc291cmNlLm5vcm1hbE1hcFR5cGU7XG5cdFx0dGhpcy5ub3JtYWxTY2FsZS5jb3B5KCBzb3VyY2Uubm9ybWFsU2NhbGUgKTtcblxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gc291cmNlLmRpc3BsYWNlbWVudE1hcDtcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gc291cmNlLmRpc3BsYWNlbWVudFNjYWxlO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IHNvdXJjZS5kaXNwbGFjZW1lbnRCaWFzO1xuXG5cdFx0dGhpcy5hbHBoYU1hcCA9IHNvdXJjZS5hbHBoYU1hcDtcblxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gc291cmNlLndpcmVmcmFtZUxpbmVjYXA7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9IHNvdXJjZS53aXJlZnJhbWVMaW5lam9pbjtcblxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBNZXNoTm9ybWFsTWF0ZXJpYWwgZXh0ZW5kcyBNYXRlcmlhbCB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc01lc2hOb3JtYWxNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnTWVzaE5vcm1hbE1hdGVyaWFsJztcblxuXHRcdHRoaXMuYnVtcE1hcCA9IG51bGw7XG5cdFx0dGhpcy5idW1wU2NhbGUgPSAxO1xuXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBudWxsO1xuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IFRhbmdlbnRTcGFjZU5vcm1hbE1hcDtcblx0XHR0aGlzLm5vcm1hbFNjYWxlID0gbmV3IFZlY3RvcjIoIDEsIDEgKTtcblxuXHRcdHRoaXMuZGlzcGxhY2VtZW50TWFwID0gbnVsbDtcblx0XHR0aGlzLmRpc3BsYWNlbWVudFNjYWxlID0gMTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSAwO1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XG5cblx0XHR0aGlzLmZsYXRTaGFkaW5nID0gZmFsc2U7XG5cblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuYnVtcE1hcCA9IHNvdXJjZS5idW1wTWFwO1xuXHRcdHRoaXMuYnVtcFNjYWxlID0gc291cmNlLmJ1bXBTY2FsZTtcblxuXHRcdHRoaXMubm9ybWFsTWFwID0gc291cmNlLm5vcm1hbE1hcDtcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBzb3VyY2Uubm9ybWFsTWFwVHlwZTtcblx0XHR0aGlzLm5vcm1hbFNjYWxlLmNvcHkoIHNvdXJjZS5ub3JtYWxTY2FsZSApO1xuXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBzb3VyY2UuZGlzcGxhY2VtZW50TWFwO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XG5cblx0XHR0aGlzLndpcmVmcmFtZSA9IHNvdXJjZS53aXJlZnJhbWU7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5ld2lkdGggPSBzb3VyY2Uud2lyZWZyYW1lTGluZXdpZHRoO1xuXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IHNvdXJjZS5mbGF0U2hhZGluZztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBNZXNoTGFtYmVydE1hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNNZXNoTGFtYmVydE1hdGVyaWFsID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdNZXNoTGFtYmVydE1hdGVyaWFsJztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7IC8vIGRpZmZ1c2VcblxuXHRcdHRoaXMubWFwID0gbnVsbDtcblxuXHRcdHRoaXMubGlnaHRNYXAgPSBudWxsO1xuXHRcdHRoaXMubGlnaHRNYXBJbnRlbnNpdHkgPSAxLjA7XG5cblx0XHR0aGlzLmFvTWFwID0gbnVsbDtcblx0XHR0aGlzLmFvTWFwSW50ZW5zaXR5ID0gMS4wO1xuXG5cdFx0dGhpcy5lbWlzc2l2ZSA9IG5ldyBDb2xvciggMHgwMDAwMDAgKTtcblx0XHR0aGlzLmVtaXNzaXZlSW50ZW5zaXR5ID0gMS4wO1xuXHRcdHRoaXMuZW1pc3NpdmVNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5idW1wTWFwID0gbnVsbDtcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IDE7XG5cblx0XHR0aGlzLm5vcm1hbE1hcCA9IG51bGw7XG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gVGFuZ2VudFNwYWNlTm9ybWFsTWFwO1xuXHRcdHRoaXMubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xuXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBudWxsO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSAxO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IDA7XG5cblx0XHR0aGlzLnNwZWN1bGFyTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuYWxwaGFNYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5lbnZNYXAgPSBudWxsO1xuXHRcdHRoaXMuZW52TWFwUm90YXRpb24gPSBuZXcgRXVsZXIoKTtcblx0XHR0aGlzLmNvbWJpbmUgPSBNdWx0aXBseU9wZXJhdGlvbjtcblx0XHR0aGlzLnJlZmxlY3Rpdml0eSA9IDE7XG5cdFx0dGhpcy5yZWZyYWN0aW9uUmF0aW8gPSAwLjk4O1xuXG5cdFx0dGhpcy53aXJlZnJhbWUgPSBmYWxzZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IDE7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gJ3JvdW5kJztcblx0XHR0aGlzLndpcmVmcmFtZUxpbmVqb2luID0gJ3JvdW5kJztcblxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBmYWxzZTtcblxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcblxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcblxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcblxuXHRcdHRoaXMubGlnaHRNYXAgPSBzb3VyY2UubGlnaHRNYXA7XG5cdFx0dGhpcy5saWdodE1hcEludGVuc2l0eSA9IHNvdXJjZS5saWdodE1hcEludGVuc2l0eTtcblxuXHRcdHRoaXMuYW9NYXAgPSBzb3VyY2UuYW9NYXA7XG5cdFx0dGhpcy5hb01hcEludGVuc2l0eSA9IHNvdXJjZS5hb01hcEludGVuc2l0eTtcblxuXHRcdHRoaXMuZW1pc3NpdmUuY29weSggc291cmNlLmVtaXNzaXZlICk7XG5cdFx0dGhpcy5lbWlzc2l2ZU1hcCA9IHNvdXJjZS5lbWlzc2l2ZU1hcDtcblx0XHR0aGlzLmVtaXNzaXZlSW50ZW5zaXR5ID0gc291cmNlLmVtaXNzaXZlSW50ZW5zaXR5O1xuXG5cdFx0dGhpcy5idW1wTWFwID0gc291cmNlLmJ1bXBNYXA7XG5cdFx0dGhpcy5idW1wU2NhbGUgPSBzb3VyY2UuYnVtcFNjYWxlO1xuXG5cdFx0dGhpcy5ub3JtYWxNYXAgPSBzb3VyY2Uubm9ybWFsTWFwO1xuXHRcdHRoaXMubm9ybWFsTWFwVHlwZSA9IHNvdXJjZS5ub3JtYWxNYXBUeXBlO1xuXHRcdHRoaXMubm9ybWFsU2NhbGUuY29weSggc291cmNlLm5vcm1hbFNjYWxlICk7XG5cblx0XHR0aGlzLmRpc3BsYWNlbWVudE1hcCA9IHNvdXJjZS5kaXNwbGFjZW1lbnRNYXA7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRTY2FsZSA9IHNvdXJjZS5kaXNwbGFjZW1lbnRTY2FsZTtcblx0XHR0aGlzLmRpc3BsYWNlbWVudEJpYXMgPSBzb3VyY2UuZGlzcGxhY2VtZW50QmlhcztcblxuXHRcdHRoaXMuc3BlY3VsYXJNYXAgPSBzb3VyY2Uuc3BlY3VsYXJNYXA7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xuXG5cdFx0dGhpcy5lbnZNYXAgPSBzb3VyY2UuZW52TWFwO1xuXHRcdHRoaXMuZW52TWFwUm90YXRpb24uY29weSggc291cmNlLmVudk1hcFJvdGF0aW9uICk7XG5cdFx0dGhpcy5jb21iaW5lID0gc291cmNlLmNvbWJpbmU7XG5cdFx0dGhpcy5yZWZsZWN0aXZpdHkgPSBzb3VyY2UucmVmbGVjdGl2aXR5O1xuXHRcdHRoaXMucmVmcmFjdGlvblJhdGlvID0gc291cmNlLnJlZnJhY3Rpb25SYXRpbztcblxuXHRcdHRoaXMud2lyZWZyYW1lID0gc291cmNlLndpcmVmcmFtZTtcblx0XHR0aGlzLndpcmVmcmFtZUxpbmV3aWR0aCA9IHNvdXJjZS53aXJlZnJhbWVMaW5ld2lkdGg7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lY2FwID0gc291cmNlLndpcmVmcmFtZUxpbmVjYXA7XG5cdFx0dGhpcy53aXJlZnJhbWVMaW5lam9pbiA9IHNvdXJjZS53aXJlZnJhbWVMaW5lam9pbjtcblxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBzb3VyY2UuZmxhdFNoYWRpbmc7XG5cblx0XHR0aGlzLmZvZyA9IHNvdXJjZS5mb2c7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgTWVzaE1hdGNhcE1hdGVyaWFsIGV4dGVuZHMgTWF0ZXJpYWwge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJzICkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNNZXNoTWF0Y2FwTWF0ZXJpYWwgPSB0cnVlO1xuXG5cdFx0dGhpcy5kZWZpbmVzID0geyAnTUFUQ0FQJzogJycgfTtcblxuXHRcdHRoaXMudHlwZSA9ICdNZXNoTWF0Y2FwTWF0ZXJpYWwnO1xuXG5cdFx0dGhpcy5jb2xvciA9IG5ldyBDb2xvciggMHhmZmZmZmYgKTsgLy8gZGlmZnVzZVxuXG5cdFx0dGhpcy5tYXRjYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5idW1wTWFwID0gbnVsbDtcblx0XHR0aGlzLmJ1bXBTY2FsZSA9IDE7XG5cblx0XHR0aGlzLm5vcm1hbE1hcCA9IG51bGw7XG5cdFx0dGhpcy5ub3JtYWxNYXBUeXBlID0gVGFuZ2VudFNwYWNlTm9ybWFsTWFwO1xuXHRcdHRoaXMubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xuXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBudWxsO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSAxO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50QmlhcyA9IDA7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gbnVsbDtcblxuXHRcdHRoaXMuZmxhdFNoYWRpbmcgPSBmYWxzZTtcblxuXHRcdHRoaXMuZm9nID0gdHJ1ZTtcblxuXHRcdHRoaXMuc2V0VmFsdWVzKCBwYXJhbWV0ZXJzICk7XG5cblx0fVxuXG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLmRlZmluZXMgPSB7ICdNQVRDQVAnOiAnJyB9O1xuXG5cdFx0dGhpcy5jb2xvci5jb3B5KCBzb3VyY2UuY29sb3IgKTtcblxuXHRcdHRoaXMubWF0Y2FwID0gc291cmNlLm1hdGNhcDtcblxuXHRcdHRoaXMubWFwID0gc291cmNlLm1hcDtcblxuXHRcdHRoaXMuYnVtcE1hcCA9IHNvdXJjZS5idW1wTWFwO1xuXHRcdHRoaXMuYnVtcFNjYWxlID0gc291cmNlLmJ1bXBTY2FsZTtcblxuXHRcdHRoaXMubm9ybWFsTWFwID0gc291cmNlLm5vcm1hbE1hcDtcblx0XHR0aGlzLm5vcm1hbE1hcFR5cGUgPSBzb3VyY2Uubm9ybWFsTWFwVHlwZTtcblx0XHR0aGlzLm5vcm1hbFNjYWxlLmNvcHkoIHNvdXJjZS5ub3JtYWxTY2FsZSApO1xuXG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRNYXAgPSBzb3VyY2UuZGlzcGxhY2VtZW50TWFwO1xuXHRcdHRoaXMuZGlzcGxhY2VtZW50U2NhbGUgPSBzb3VyY2UuZGlzcGxhY2VtZW50U2NhbGU7XG5cdFx0dGhpcy5kaXNwbGFjZW1lbnRCaWFzID0gc291cmNlLmRpc3BsYWNlbWVudEJpYXM7XG5cblx0XHR0aGlzLmFscGhhTWFwID0gc291cmNlLmFscGhhTWFwO1xuXG5cdFx0dGhpcy5mbGF0U2hhZGluZyA9IHNvdXJjZS5mbGF0U2hhZGluZztcblxuXHRcdHRoaXMuZm9nID0gc291cmNlLmZvZztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBMaW5lRGFzaGVkTWF0ZXJpYWwgZXh0ZW5kcyBMaW5lQmFzaWNNYXRlcmlhbCB7XG5cblx0Y29uc3RydWN0b3IoIHBhcmFtZXRlcnMgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc0xpbmVEYXNoZWRNYXRlcmlhbCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnTGluZURhc2hlZE1hdGVyaWFsJztcblxuXHRcdHRoaXMuc2NhbGUgPSAxO1xuXHRcdHRoaXMuZGFzaFNpemUgPSAzO1xuXHRcdHRoaXMuZ2FwU2l6ZSA9IDE7XG5cblx0XHR0aGlzLnNldFZhbHVlcyggcGFyYW1ldGVycyApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuc2NhbGUgPSBzb3VyY2Uuc2NhbGU7XG5cdFx0dGhpcy5kYXNoU2l6ZSA9IHNvdXJjZS5kYXNoU2l6ZTtcblx0XHR0aGlzLmdhcFNpemUgPSBzb3VyY2UuZ2FwU2l6ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG4vLyBjb252ZXJ0cyBhbiBhcnJheSB0byBhIHNwZWNpZmljIHR5cGVcbmZ1bmN0aW9uIGNvbnZlcnRBcnJheSggYXJyYXksIHR5cGUsIGZvcmNlQ2xvbmUgKSB7XG5cblx0aWYgKCAhIGFycmF5IHx8IC8vIGxldCAndW5kZWZpbmVkJyBhbmQgJ251bGwnIHBhc3Ncblx0XHQhIGZvcmNlQ2xvbmUgJiYgYXJyYXkuY29uc3RydWN0b3IgPT09IHR5cGUgKSByZXR1cm4gYXJyYXk7XG5cblx0aWYgKCB0eXBlb2YgdHlwZS5CWVRFU19QRVJfRUxFTUVOVCA9PT0gJ251bWJlcicgKSB7XG5cblx0XHRyZXR1cm4gbmV3IHR5cGUoIGFycmF5ICk7IC8vIGNyZWF0ZSB0eXBlZCBhcnJheVxuXG5cdH1cblxuXHRyZXR1cm4gQXJyYXkucHJvdG90eXBlLnNsaWNlLmNhbGwoIGFycmF5ICk7IC8vIGNyZWF0ZSBBcnJheVxuXG59XG5cbmZ1bmN0aW9uIGlzVHlwZWRBcnJheSggb2JqZWN0ICkge1xuXG5cdHJldHVybiBBcnJheUJ1ZmZlci5pc1ZpZXcoIG9iamVjdCApICYmXG5cdFx0ISAoIG9iamVjdCBpbnN0YW5jZW9mIERhdGFWaWV3ICk7XG5cbn1cblxuLy8gcmV0dXJucyBhbiBhcnJheSBieSB3aGljaCB0aW1lcyBhbmQgdmFsdWVzIGNhbiBiZSBzb3J0ZWRcbmZ1bmN0aW9uIGdldEtleWZyYW1lT3JkZXIoIHRpbWVzICkge1xuXG5cdGZ1bmN0aW9uIGNvbXBhcmVUaW1lKCBpLCBqICkge1xuXG5cdFx0cmV0dXJuIHRpbWVzWyBpIF0gLSB0aW1lc1sgaiBdO1xuXG5cdH1cblxuXHRjb25zdCBuID0gdGltZXMubGVuZ3RoO1xuXHRjb25zdCByZXN1bHQgPSBuZXcgQXJyYXkoIG4gKTtcblx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuOyArKyBpICkgcmVzdWx0WyBpIF0gPSBpO1xuXG5cdHJlc3VsdC5zb3J0KCBjb21wYXJlVGltZSApO1xuXG5cdHJldHVybiByZXN1bHQ7XG5cbn1cblxuLy8gdXNlcyB0aGUgYXJyYXkgcHJldmlvdXNseSByZXR1cm5lZCBieSAnZ2V0S2V5ZnJhbWVPcmRlcicgdG8gc29ydCBkYXRhXG5mdW5jdGlvbiBzb3J0ZWRBcnJheSggdmFsdWVzLCBzdHJpZGUsIG9yZGVyICkge1xuXG5cdGNvbnN0IG5WYWx1ZXMgPSB2YWx1ZXMubGVuZ3RoO1xuXHRjb25zdCByZXN1bHQgPSBuZXcgdmFsdWVzLmNvbnN0cnVjdG9yKCBuVmFsdWVzICk7XG5cblx0Zm9yICggbGV0IGkgPSAwLCBkc3RPZmZzZXQgPSAwOyBkc3RPZmZzZXQgIT09IG5WYWx1ZXM7ICsrIGkgKSB7XG5cblx0XHRjb25zdCBzcmNPZmZzZXQgPSBvcmRlclsgaSBdICogc3RyaWRlO1xuXG5cdFx0Zm9yICggbGV0IGogPSAwOyBqICE9PSBzdHJpZGU7ICsrIGogKSB7XG5cblx0XHRcdHJlc3VsdFsgZHN0T2Zmc2V0ICsrIF0gPSB2YWx1ZXNbIHNyY09mZnNldCArIGogXTtcblxuXHRcdH1cblxuXHR9XG5cblx0cmV0dXJuIHJlc3VsdDtcblxufVxuXG4vLyBmdW5jdGlvbiBmb3IgcGFyc2luZyBBT1Mga2V5ZnJhbWUgZm9ybWF0c1xuZnVuY3Rpb24gZmxhdHRlbkpTT04oIGpzb25LZXlzLCB0aW1lcywgdmFsdWVzLCB2YWx1ZVByb3BlcnR5TmFtZSApIHtcblxuXHRsZXQgaSA9IDEsIGtleSA9IGpzb25LZXlzWyAwIF07XG5cblx0d2hpbGUgKCBrZXkgIT09IHVuZGVmaW5lZCAmJiBrZXlbIHZhbHVlUHJvcGVydHlOYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGtleSA9IGpzb25LZXlzWyBpICsrIF07XG5cblx0fVxuXG5cdGlmICgga2V5ID09PSB1bmRlZmluZWQgKSByZXR1cm47IC8vIG5vIGRhdGFcblxuXHRsZXQgdmFsdWUgPSBrZXlbIHZhbHVlUHJvcGVydHlOYW1lIF07XG5cdGlmICggdmFsdWUgPT09IHVuZGVmaW5lZCApIHJldHVybjsgLy8gbm8gZGF0YVxuXG5cdGlmICggQXJyYXkuaXNBcnJheSggdmFsdWUgKSApIHtcblxuXHRcdGRvIHtcblxuXHRcdFx0dmFsdWUgPSBrZXlbIHZhbHVlUHJvcGVydHlOYW1lIF07XG5cblx0XHRcdGlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0aW1lcy5wdXNoKCBrZXkudGltZSApO1xuXHRcdFx0XHR2YWx1ZXMucHVzaC5hcHBseSggdmFsdWVzLCB2YWx1ZSApOyAvLyBwdXNoIGFsbCBlbGVtZW50c1xuXG5cdFx0XHR9XG5cblx0XHRcdGtleSA9IGpzb25LZXlzWyBpICsrIF07XG5cblx0XHR9IHdoaWxlICgga2V5ICE9PSB1bmRlZmluZWQgKTtcblxuXHR9IGVsc2UgaWYgKCB2YWx1ZS50b0FycmF5ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHQvLyAuLi5hc3N1bWUgVEhSRUUuTWF0aC1pc2hcblxuXHRcdGRvIHtcblxuXHRcdFx0dmFsdWUgPSBrZXlbIHZhbHVlUHJvcGVydHlOYW1lIF07XG5cblx0XHRcdGlmICggdmFsdWUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0aW1lcy5wdXNoKCBrZXkudGltZSApO1xuXHRcdFx0XHR2YWx1ZS50b0FycmF5KCB2YWx1ZXMsIHZhbHVlcy5sZW5ndGggKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRrZXkgPSBqc29uS2V5c1sgaSArKyBdO1xuXG5cdFx0fSB3aGlsZSAoIGtleSAhPT0gdW5kZWZpbmVkICk7XG5cblx0fSBlbHNlIHtcblxuXHRcdC8vIG90aGVyd2lzZSBwdXNoIGFzLWlzXG5cblx0XHRkbyB7XG5cblx0XHRcdHZhbHVlID0ga2V5WyB2YWx1ZVByb3BlcnR5TmFtZSBdO1xuXG5cdFx0XHRpZiAoIHZhbHVlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGltZXMucHVzaCgga2V5LnRpbWUgKTtcblx0XHRcdFx0dmFsdWVzLnB1c2goIHZhbHVlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0a2V5ID0ganNvbktleXNbIGkgKysgXTtcblxuXHRcdH0gd2hpbGUgKCBrZXkgIT09IHVuZGVmaW5lZCApO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBzdWJjbGlwKCBzb3VyY2VDbGlwLCBuYW1lLCBzdGFydEZyYW1lLCBlbmRGcmFtZSwgZnBzID0gMzAgKSB7XG5cblx0Y29uc3QgY2xpcCA9IHNvdXJjZUNsaXAuY2xvbmUoKTtcblxuXHRjbGlwLm5hbWUgPSBuYW1lO1xuXG5cdGNvbnN0IHRyYWNrcyA9IFtdO1xuXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IGNsaXAudHJhY2tzLmxlbmd0aDsgKysgaSApIHtcblxuXHRcdGNvbnN0IHRyYWNrID0gY2xpcC50cmFja3NbIGkgXTtcblx0XHRjb25zdCB2YWx1ZVNpemUgPSB0cmFjay5nZXRWYWx1ZVNpemUoKTtcblxuXHRcdGNvbnN0IHRpbWVzID0gW107XG5cdFx0Y29uc3QgdmFsdWVzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCB0cmFjay50aW1lcy5sZW5ndGg7ICsrIGogKSB7XG5cblx0XHRcdGNvbnN0IGZyYW1lID0gdHJhY2sudGltZXNbIGogXSAqIGZwcztcblxuXHRcdFx0aWYgKCBmcmFtZSA8IHN0YXJ0RnJhbWUgfHwgZnJhbWUgPj0gZW5kRnJhbWUgKSBjb250aW51ZTtcblxuXHRcdFx0dGltZXMucHVzaCggdHJhY2sudGltZXNbIGogXSApO1xuXG5cdFx0XHRmb3IgKCBsZXQgayA9IDA7IGsgPCB2YWx1ZVNpemU7ICsrIGsgKSB7XG5cblx0XHRcdFx0dmFsdWVzLnB1c2goIHRyYWNrLnZhbHVlc1sgaiAqIHZhbHVlU2l6ZSArIGsgXSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIHRpbWVzLmxlbmd0aCA9PT0gMCApIGNvbnRpbnVlO1xuXG5cdFx0dHJhY2sudGltZXMgPSBjb252ZXJ0QXJyYXkoIHRpbWVzLCB0cmFjay50aW1lcy5jb25zdHJ1Y3RvciApO1xuXHRcdHRyYWNrLnZhbHVlcyA9IGNvbnZlcnRBcnJheSggdmFsdWVzLCB0cmFjay52YWx1ZXMuY29uc3RydWN0b3IgKTtcblxuXHRcdHRyYWNrcy5wdXNoKCB0cmFjayApO1xuXG5cdH1cblxuXHRjbGlwLnRyYWNrcyA9IHRyYWNrcztcblxuXHQvLyBmaW5kIG1pbmltdW0gLnRpbWVzIHZhbHVlIGFjcm9zcyBhbGwgdHJhY2tzIGluIHRoZSB0cmltbWVkIGNsaXBcblxuXHRsZXQgbWluU3RhcnRUaW1lID0gSW5maW5pdHk7XG5cblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY2xpcC50cmFja3MubGVuZ3RoOyArKyBpICkge1xuXG5cdFx0aWYgKCBtaW5TdGFydFRpbWUgPiBjbGlwLnRyYWNrc1sgaSBdLnRpbWVzWyAwIF0gKSB7XG5cblx0XHRcdG1pblN0YXJ0VGltZSA9IGNsaXAudHJhY2tzWyBpIF0udGltZXNbIDAgXTtcblxuXHRcdH1cblxuXHR9XG5cblx0Ly8gc2hpZnQgYWxsIHRyYWNrcyBzdWNoIHRoYXQgY2xpcCBiZWdpbnMgYXQgdD0wXG5cblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgY2xpcC50cmFja3MubGVuZ3RoOyArKyBpICkge1xuXG5cdFx0Y2xpcC50cmFja3NbIGkgXS5zaGlmdCggLSAxICogbWluU3RhcnRUaW1lICk7XG5cblx0fVxuXG5cdGNsaXAucmVzZXREdXJhdGlvbigpO1xuXG5cdHJldHVybiBjbGlwO1xuXG59XG5cbmZ1bmN0aW9uIG1ha2VDbGlwQWRkaXRpdmUoIHRhcmdldENsaXAsIHJlZmVyZW5jZUZyYW1lID0gMCwgcmVmZXJlbmNlQ2xpcCA9IHRhcmdldENsaXAsIGZwcyA9IDMwICkge1xuXG5cdGlmICggZnBzIDw9IDAgKSBmcHMgPSAzMDtcblxuXHRjb25zdCBudW1UcmFja3MgPSByZWZlcmVuY2VDbGlwLnRyYWNrcy5sZW5ndGg7XG5cdGNvbnN0IHJlZmVyZW5jZVRpbWUgPSByZWZlcmVuY2VGcmFtZSAvIGZwcztcblxuXHQvLyBNYWtlIGVhY2ggdHJhY2sncyB2YWx1ZXMgcmVsYXRpdmUgdG8gdGhlIHZhbHVlcyBhdCB0aGUgcmVmZXJlbmNlIGZyYW1lXG5cdGZvciAoIGxldCBpID0gMDsgaSA8IG51bVRyYWNrczsgKysgaSApIHtcblxuXHRcdGNvbnN0IHJlZmVyZW5jZVRyYWNrID0gcmVmZXJlbmNlQ2xpcC50cmFja3NbIGkgXTtcblx0XHRjb25zdCByZWZlcmVuY2VUcmFja1R5cGUgPSByZWZlcmVuY2VUcmFjay5WYWx1ZVR5cGVOYW1lO1xuXG5cdFx0Ly8gU2tpcCB0aGlzIHRyYWNrIGlmIGl0J3Mgbm9uLW51bWVyaWNcblx0XHRpZiAoIHJlZmVyZW5jZVRyYWNrVHlwZSA9PT0gJ2Jvb2wnIHx8IHJlZmVyZW5jZVRyYWNrVHlwZSA9PT0gJ3N0cmluZycgKSBjb250aW51ZTtcblxuXHRcdC8vIEZpbmQgdGhlIHRyYWNrIGluIHRoZSB0YXJnZXQgY2xpcCB3aG9zZSBuYW1lIGFuZCB0eXBlIG1hdGNoZXMgdGhlIHJlZmVyZW5jZSB0cmFja1xuXHRcdGNvbnN0IHRhcmdldFRyYWNrID0gdGFyZ2V0Q2xpcC50cmFja3MuZmluZCggZnVuY3Rpb24gKCB0cmFjayApIHtcblxuXHRcdFx0cmV0dXJuIHRyYWNrLm5hbWUgPT09IHJlZmVyZW5jZVRyYWNrLm5hbWVcblx0XHRcdFx0JiYgdHJhY2suVmFsdWVUeXBlTmFtZSA9PT0gcmVmZXJlbmNlVHJhY2tUeXBlO1xuXG5cdFx0fSApO1xuXG5cdFx0aWYgKCB0YXJnZXRUcmFjayA9PT0gdW5kZWZpbmVkICkgY29udGludWU7XG5cblx0XHRsZXQgcmVmZXJlbmNlT2Zmc2V0ID0gMDtcblx0XHRjb25zdCByZWZlcmVuY2VWYWx1ZVNpemUgPSByZWZlcmVuY2VUcmFjay5nZXRWYWx1ZVNpemUoKTtcblxuXHRcdGlmICggcmVmZXJlbmNlVHJhY2suY3JlYXRlSW50ZXJwb2xhbnQuaXNJbnRlcnBvbGFudEZhY3RvcnlNZXRob2RHTFRGQ3ViaWNTcGxpbmUgKSB7XG5cblx0XHRcdHJlZmVyZW5jZU9mZnNldCA9IHJlZmVyZW5jZVZhbHVlU2l6ZSAvIDM7XG5cblx0XHR9XG5cblx0XHRsZXQgdGFyZ2V0T2Zmc2V0ID0gMDtcblx0XHRjb25zdCB0YXJnZXRWYWx1ZVNpemUgPSB0YXJnZXRUcmFjay5nZXRWYWx1ZVNpemUoKTtcblxuXHRcdGlmICggdGFyZ2V0VHJhY2suY3JlYXRlSW50ZXJwb2xhbnQuaXNJbnRlcnBvbGFudEZhY3RvcnlNZXRob2RHTFRGQ3ViaWNTcGxpbmUgKSB7XG5cblx0XHRcdHRhcmdldE9mZnNldCA9IHRhcmdldFZhbHVlU2l6ZSAvIDM7XG5cblx0XHR9XG5cblx0XHRjb25zdCBsYXN0SW5kZXggPSByZWZlcmVuY2VUcmFjay50aW1lcy5sZW5ndGggLSAxO1xuXHRcdGxldCByZWZlcmVuY2VWYWx1ZTtcblxuXHRcdC8vIEZpbmQgdGhlIHZhbHVlIHRvIHN1YnRyYWN0IG91dCBvZiB0aGUgdHJhY2tcblx0XHRpZiAoIHJlZmVyZW5jZVRpbWUgPD0gcmVmZXJlbmNlVHJhY2sudGltZXNbIDAgXSApIHtcblxuXHRcdFx0Ly8gUmVmZXJlbmNlIGZyYW1lIGlzIGVhcmxpZXIgdGhhbiB0aGUgZmlyc3Qga2V5ZnJhbWUsIHNvIGp1c3QgdXNlIHRoZSBmaXJzdCBrZXlmcmFtZVxuXHRcdFx0Y29uc3Qgc3RhcnRJbmRleCA9IHJlZmVyZW5jZU9mZnNldDtcblx0XHRcdGNvbnN0IGVuZEluZGV4ID0gcmVmZXJlbmNlVmFsdWVTaXplIC0gcmVmZXJlbmNlT2Zmc2V0O1xuXHRcdFx0cmVmZXJlbmNlVmFsdWUgPSByZWZlcmVuY2VUcmFjay52YWx1ZXMuc2xpY2UoIHN0YXJ0SW5kZXgsIGVuZEluZGV4ICk7XG5cblx0XHR9IGVsc2UgaWYgKCByZWZlcmVuY2VUaW1lID49IHJlZmVyZW5jZVRyYWNrLnRpbWVzWyBsYXN0SW5kZXggXSApIHtcblxuXHRcdFx0Ly8gUmVmZXJlbmNlIGZyYW1lIGlzIGFmdGVyIHRoZSBsYXN0IGtleWZyYW1lLCBzbyBqdXN0IHVzZSB0aGUgbGFzdCBrZXlmcmFtZVxuXHRcdFx0Y29uc3Qgc3RhcnRJbmRleCA9IGxhc3RJbmRleCAqIHJlZmVyZW5jZVZhbHVlU2l6ZSArIHJlZmVyZW5jZU9mZnNldDtcblx0XHRcdGNvbnN0IGVuZEluZGV4ID0gc3RhcnRJbmRleCArIHJlZmVyZW5jZVZhbHVlU2l6ZSAtIHJlZmVyZW5jZU9mZnNldDtcblx0XHRcdHJlZmVyZW5jZVZhbHVlID0gcmVmZXJlbmNlVHJhY2sudmFsdWVzLnNsaWNlKCBzdGFydEluZGV4LCBlbmRJbmRleCApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Ly8gSW50ZXJwb2xhdGUgdG8gdGhlIHJlZmVyZW5jZSB2YWx1ZVxuXHRcdFx0Y29uc3QgaW50ZXJwb2xhbnQgPSByZWZlcmVuY2VUcmFjay5jcmVhdGVJbnRlcnBvbGFudCgpO1xuXHRcdFx0Y29uc3Qgc3RhcnRJbmRleCA9IHJlZmVyZW5jZU9mZnNldDtcblx0XHRcdGNvbnN0IGVuZEluZGV4ID0gcmVmZXJlbmNlVmFsdWVTaXplIC0gcmVmZXJlbmNlT2Zmc2V0O1xuXHRcdFx0aW50ZXJwb2xhbnQuZXZhbHVhdGUoIHJlZmVyZW5jZVRpbWUgKTtcblx0XHRcdHJlZmVyZW5jZVZhbHVlID0gaW50ZXJwb2xhbnQucmVzdWx0QnVmZmVyLnNsaWNlKCBzdGFydEluZGV4LCBlbmRJbmRleCApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gQ29uanVnYXRlIHRoZSBxdWF0ZXJuaW9uXG5cdFx0aWYgKCByZWZlcmVuY2VUcmFja1R5cGUgPT09ICdxdWF0ZXJuaW9uJyApIHtcblxuXHRcdFx0Y29uc3QgcmVmZXJlbmNlUXVhdCA9IG5ldyBRdWF0ZXJuaW9uKCkuZnJvbUFycmF5KCByZWZlcmVuY2VWYWx1ZSApLm5vcm1hbGl6ZSgpLmNvbmp1Z2F0ZSgpO1xuXHRcdFx0cmVmZXJlbmNlUXVhdC50b0FycmF5KCByZWZlcmVuY2VWYWx1ZSApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gU3VidHJhY3QgdGhlIHJlZmVyZW5jZSB2YWx1ZSBmcm9tIGFsbCBvZiB0aGUgdHJhY2sgdmFsdWVzXG5cblx0XHRjb25zdCBudW1UaW1lcyA9IHRhcmdldFRyYWNrLnRpbWVzLmxlbmd0aDtcblx0XHRmb3IgKCBsZXQgaiA9IDA7IGogPCBudW1UaW1lczsgKysgaiApIHtcblxuXHRcdFx0Y29uc3QgdmFsdWVTdGFydCA9IGogKiB0YXJnZXRWYWx1ZVNpemUgKyB0YXJnZXRPZmZzZXQ7XG5cblx0XHRcdGlmICggcmVmZXJlbmNlVHJhY2tUeXBlID09PSAncXVhdGVybmlvbicgKSB7XG5cblx0XHRcdFx0Ly8gTXVsdGlwbHkgdGhlIGNvbmp1Z2F0ZSBmb3IgcXVhdGVybmlvbiB0cmFjayB0eXBlc1xuXHRcdFx0XHRRdWF0ZXJuaW9uLm11bHRpcGx5UXVhdGVybmlvbnNGbGF0KFxuXHRcdFx0XHRcdHRhcmdldFRyYWNrLnZhbHVlcyxcblx0XHRcdFx0XHR2YWx1ZVN0YXJ0LFxuXHRcdFx0XHRcdHJlZmVyZW5jZVZhbHVlLFxuXHRcdFx0XHRcdDAsXG5cdFx0XHRcdFx0dGFyZ2V0VHJhY2sudmFsdWVzLFxuXHRcdFx0XHRcdHZhbHVlU3RhcnRcblx0XHRcdFx0KTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zdCB2YWx1ZUVuZCA9IHRhcmdldFZhbHVlU2l6ZSAtIHRhcmdldE9mZnNldCAqIDI7XG5cblx0XHRcdFx0Ly8gU3VidHJhY3QgZWFjaCB2YWx1ZSBmb3IgYWxsIG90aGVyIG51bWVyaWMgdHJhY2sgdHlwZXNcblx0XHRcdFx0Zm9yICggbGV0IGsgPSAwOyBrIDwgdmFsdWVFbmQ7ICsrIGsgKSB7XG5cblx0XHRcdFx0XHR0YXJnZXRUcmFjay52YWx1ZXNbIHZhbHVlU3RhcnQgKyBrIF0gLT0gcmVmZXJlbmNlVmFsdWVbIGsgXTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0dGFyZ2V0Q2xpcC5ibGVuZE1vZGUgPSBBZGRpdGl2ZUFuaW1hdGlvbkJsZW5kTW9kZTtcblxuXHRyZXR1cm4gdGFyZ2V0Q2xpcDtcblxufVxuXG5jb25zdCBBbmltYXRpb25VdGlscyA9IHtcblx0Y29udmVydEFycmF5OiBjb252ZXJ0QXJyYXksXG5cdGlzVHlwZWRBcnJheTogaXNUeXBlZEFycmF5LFxuXHRnZXRLZXlmcmFtZU9yZGVyOiBnZXRLZXlmcmFtZU9yZGVyLFxuXHRzb3J0ZWRBcnJheTogc29ydGVkQXJyYXksXG5cdGZsYXR0ZW5KU09OOiBmbGF0dGVuSlNPTixcblx0c3ViY2xpcDogc3ViY2xpcCxcblx0bWFrZUNsaXBBZGRpdGl2ZTogbWFrZUNsaXBBZGRpdGl2ZVxufTtcblxuLyoqXG4gKiBBYnN0cmFjdCBiYXNlIGNsYXNzIG9mIGludGVycG9sYW50cyBvdmVyIHBhcmFtZXRyaWMgc2FtcGxlcy5cbiAqXG4gKiBUaGUgcGFyYW1ldGVyIGRvbWFpbiBpcyBvbmUgZGltZW5zaW9uYWwsIHR5cGljYWxseSB0aGUgdGltZSBvciBhIHBhdGhcbiAqIGFsb25nIGEgY3VydmUgZGVmaW5lZCBieSB0aGUgZGF0YS5cbiAqXG4gKiBUaGUgc2FtcGxlIHZhbHVlcyBjYW4gaGF2ZSBhbnkgZGltZW5zaW9uYWxpdHkgYW5kIGRlcml2ZWQgY2xhc3NlcyBtYXlcbiAqIGFwcGx5IHNwZWNpYWwgaW50ZXJwcmV0YXRpb25zIHRvIHRoZSBkYXRhLlxuICpcbiAqIFRoaXMgY2xhc3MgcHJvdmlkZXMgdGhlIGludGVydmFsIHNlZWsgaW4gYSBUZW1wbGF0ZSBNZXRob2QsIGRlZmVycmluZ1xuICogdGhlIGFjdHVhbCBpbnRlcnBvbGF0aW9uIHRvIGRlcml2ZWQgY2xhc3Nlcy5cbiAqXG4gKiBUaW1lIGNvbXBsZXhpdHkgaXMgTygxKSBmb3IgbGluZWFyIGFjY2VzcyBjcm9zc2luZyBhdCBtb3N0IHR3byBwb2ludHNcbiAqIGFuZCBPKGxvZyBOKSBmb3IgcmFuZG9tIGFjY2Vzcywgd2hlcmUgTiBpcyB0aGUgbnVtYmVyIG9mIHBvc2l0aW9ucy5cbiAqXG4gKiBSZWZlcmVuY2VzOlxuICpcbiAqIFx0XHRodHRwOi8vd3d3Lm9vZGVzaWduLmNvbS90ZW1wbGF0ZS1tZXRob2QtcGF0dGVybi5odG1sXG4gKlxuICovXG5cbmNsYXNzIEludGVycG9sYW50IHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApIHtcblxuXHRcdHRoaXMucGFyYW1ldGVyUG9zaXRpb25zID0gcGFyYW1ldGVyUG9zaXRpb25zO1xuXHRcdHRoaXMuX2NhY2hlZEluZGV4ID0gMDtcblxuXHRcdHRoaXMucmVzdWx0QnVmZmVyID0gcmVzdWx0QnVmZmVyICE9PSB1bmRlZmluZWQgP1xuXHRcdFx0cmVzdWx0QnVmZmVyIDogbmV3IHNhbXBsZVZhbHVlcy5jb25zdHJ1Y3Rvciggc2FtcGxlU2l6ZSApO1xuXHRcdHRoaXMuc2FtcGxlVmFsdWVzID0gc2FtcGxlVmFsdWVzO1xuXHRcdHRoaXMudmFsdWVTaXplID0gc2FtcGxlU2l6ZTtcblxuXHRcdHRoaXMuc2V0dGluZ3MgPSBudWxsO1xuXHRcdHRoaXMuRGVmYXVsdFNldHRpbmdzXyA9IHt9O1xuXG5cdH1cblxuXHRldmFsdWF0ZSggdCApIHtcblxuXHRcdGNvbnN0IHBwID0gdGhpcy5wYXJhbWV0ZXJQb3NpdGlvbnM7XG5cdFx0bGV0IGkxID0gdGhpcy5fY2FjaGVkSW5kZXgsXG5cdFx0XHR0MSA9IHBwWyBpMSBdLFxuXHRcdFx0dDAgPSBwcFsgaTEgLSAxIF07XG5cblx0XHR2YWxpZGF0ZV9pbnRlcnZhbDoge1xuXG5cdFx0XHRzZWVrOiB7XG5cblx0XHRcdFx0bGV0IHJpZ2h0O1xuXG5cdFx0XHRcdGxpbmVhcl9zY2FuOiB7XG5cblx0XHRcdFx0XHQvLy0gU2VlIGh0dHA6Ly9qc3BlcmYuY29tL2NvbXBhcmlzb24tdG8tdW5kZWZpbmVkLzNcblx0XHRcdFx0XHQvLy0gc2xvd2VyIGNvZGU6XG5cdFx0XHRcdFx0Ly8tXG5cdFx0XHRcdFx0Ly8tIFx0XHRcdFx0aWYgKCB0ID49IHQxIHx8IHQxID09PSB1bmRlZmluZWQgKSB7XG5cdFx0XHRcdFx0Zm9yd2FyZF9zY2FuOiBpZiAoICEgKCB0IDwgdDEgKSApIHtcblxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGdpdmVVcEF0ID0gaTEgKyAyOyA7ICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggdDEgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGlmICggdCA8IHQwICkgYnJlYWsgZm9yd2FyZF9zY2FuO1xuXG5cdFx0XHRcdFx0XHRcdFx0Ly8gYWZ0ZXIgZW5kXG5cblx0XHRcdFx0XHRcdFx0XHRpMSA9IHBwLmxlbmd0aDtcblx0XHRcdFx0XHRcdFx0XHR0aGlzLl9jYWNoZWRJbmRleCA9IGkxO1xuXHRcdFx0XHRcdFx0XHRcdHJldHVybiB0aGlzLmNvcHlTYW1wbGVWYWx1ZV8oIGkxIC0gMSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRpZiAoIGkxID09PSBnaXZlVXBBdCApIGJyZWFrOyAvLyB0aGlzIGxvb3BcblxuXHRcdFx0XHRcdFx0XHR0MCA9IHQxO1xuXHRcdFx0XHRcdFx0XHR0MSA9IHBwWyArKyBpMSBdO1xuXG5cdFx0XHRcdFx0XHRcdGlmICggdCA8IHQxICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0Ly8gd2UgaGF2ZSBhcnJpdmVkIGF0IHRoZSBzb3VnaHQgaW50ZXJ2YWxcblx0XHRcdFx0XHRcdFx0XHRicmVhayBzZWVrO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHQvLyBwcmVwYXJlIGJpbmFyeSBzZWFyY2ggb24gdGhlIHJpZ2h0IHNpZGUgb2YgdGhlIGluZGV4XG5cdFx0XHRcdFx0XHRyaWdodCA9IHBwLmxlbmd0aDtcblx0XHRcdFx0XHRcdGJyZWFrIGxpbmVhcl9zY2FuO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8tIHNsb3dlciBjb2RlOlxuXHRcdFx0XHRcdC8vLVx0XHRcdFx0XHRpZiAoIHQgPCB0MCB8fCB0MCA9PT0gdW5kZWZpbmVkICkge1xuXHRcdFx0XHRcdGlmICggISAoIHQgPj0gdDAgKSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gbG9vcGluZz9cblxuXHRcdFx0XHRcdFx0Y29uc3QgdDFnbG9iYWwgPSBwcFsgMSBdO1xuXG5cdFx0XHRcdFx0XHRpZiAoIHQgPCB0MWdsb2JhbCApIHtcblxuXHRcdFx0XHRcdFx0XHRpMSA9IDI7IC8vICsgMSwgdXNpbmcgdGhlIHNjYW4gZm9yIHRoZSBkZXRhaWxzXG5cdFx0XHRcdFx0XHRcdHQwID0gdDFnbG9iYWw7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0Ly8gbGluZWFyIHJldmVyc2Ugc2NhblxuXG5cdFx0XHRcdFx0XHRmb3IgKCBsZXQgZ2l2ZVVwQXQgPSBpMSAtIDI7IDsgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCB0MCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0Ly8gYmVmb3JlIHN0YXJ0XG5cblx0XHRcdFx0XHRcdFx0XHR0aGlzLl9jYWNoZWRJbmRleCA9IDA7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHRoaXMuY29weVNhbXBsZVZhbHVlXyggMCApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRpZiAoIGkxID09PSBnaXZlVXBBdCApIGJyZWFrOyAvLyB0aGlzIGxvb3BcblxuXHRcdFx0XHRcdFx0XHR0MSA9IHQwO1xuXHRcdFx0XHRcdFx0XHR0MCA9IHBwWyAtLSBpMSAtIDEgXTtcblxuXHRcdFx0XHRcdFx0XHRpZiAoIHQgPj0gdDAgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHQvLyB3ZSBoYXZlIGFycml2ZWQgYXQgdGhlIHNvdWdodCBpbnRlcnZhbFxuXHRcdFx0XHRcdFx0XHRcdGJyZWFrIHNlZWs7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdC8vIHByZXBhcmUgYmluYXJ5IHNlYXJjaCBvbiB0aGUgbGVmdCBzaWRlIG9mIHRoZSBpbmRleFxuXHRcdFx0XHRcdFx0cmlnaHQgPSBpMTtcblx0XHRcdFx0XHRcdGkxID0gMDtcblx0XHRcdFx0XHRcdGJyZWFrIGxpbmVhcl9zY2FuO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gdGhlIGludGVydmFsIGlzIHZhbGlkXG5cblx0XHRcdFx0XHRicmVhayB2YWxpZGF0ZV9pbnRlcnZhbDtcblxuXHRcdFx0XHR9IC8vIGxpbmVhciBzY2FuXG5cblx0XHRcdFx0Ly8gYmluYXJ5IHNlYXJjaFxuXG5cdFx0XHRcdHdoaWxlICggaTEgPCByaWdodCApIHtcblxuXHRcdFx0XHRcdGNvbnN0IG1pZCA9ICggaTEgKyByaWdodCApID4+PiAxO1xuXG5cdFx0XHRcdFx0aWYgKCB0IDwgcHBbIG1pZCBdICkge1xuXG5cdFx0XHRcdFx0XHRyaWdodCA9IG1pZDtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGkxID0gbWlkICsgMTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0dDEgPSBwcFsgaTEgXTtcblx0XHRcdFx0dDAgPSBwcFsgaTEgLSAxIF07XG5cblx0XHRcdFx0Ly8gY2hlY2sgYm91bmRhcnkgY2FzZXMsIGFnYWluXG5cblx0XHRcdFx0aWYgKCB0MCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0dGhpcy5fY2FjaGVkSW5kZXggPSAwO1xuXHRcdFx0XHRcdHJldHVybiB0aGlzLmNvcHlTYW1wbGVWYWx1ZV8oIDAgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCB0MSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0aTEgPSBwcC5sZW5ndGg7XG5cdFx0XHRcdFx0dGhpcy5fY2FjaGVkSW5kZXggPSBpMTtcblx0XHRcdFx0XHRyZXR1cm4gdGhpcy5jb3B5U2FtcGxlVmFsdWVfKCBpMSAtIDEgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gLy8gc2Vla1xuXG5cdFx0XHR0aGlzLl9jYWNoZWRJbmRleCA9IGkxO1xuXG5cdFx0XHR0aGlzLmludGVydmFsQ2hhbmdlZF8oIGkxLCB0MCwgdDEgKTtcblxuXHRcdH0gLy8gdmFsaWRhdGVfaW50ZXJ2YWxcblxuXHRcdHJldHVybiB0aGlzLmludGVycG9sYXRlXyggaTEsIHQwLCB0LCB0MSApO1xuXG5cdH1cblxuXHRnZXRTZXR0aW5nc18oKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5zZXR0aW5ncyB8fCB0aGlzLkRlZmF1bHRTZXR0aW5nc187XG5cblx0fVxuXG5cdGNvcHlTYW1wbGVWYWx1ZV8oIGluZGV4ICkge1xuXG5cdFx0Ly8gY29waWVzIGEgc2FtcGxlIHZhbHVlIHRvIHRoZSByZXN1bHQgYnVmZmVyXG5cblx0XHRjb25zdCByZXN1bHQgPSB0aGlzLnJlc3VsdEJ1ZmZlcixcblx0XHRcdHZhbHVlcyA9IHRoaXMuc2FtcGxlVmFsdWVzLFxuXHRcdFx0c3RyaWRlID0gdGhpcy52YWx1ZVNpemUsXG5cdFx0XHRvZmZzZXQgPSBpbmRleCAqIHN0cmlkZTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xuXG5cdFx0XHRyZXN1bHRbIGkgXSA9IHZhbHVlc1sgb2Zmc2V0ICsgaSBdO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHJlc3VsdDtcblxuXHR9XG5cblx0Ly8gVGVtcGxhdGUgbWV0aG9kcyBmb3IgZGVyaXZlZCBjbGFzc2VzOlxuXG5cdGludGVycG9sYXRlXyggLyogaTEsIHQwLCB0LCB0MSAqLyApIHtcblxuXHRcdHRocm93IG5ldyBFcnJvciggJ2NhbGwgdG8gYWJzdHJhY3QgbWV0aG9kJyApO1xuXHRcdC8vIGltcGxlbWVudGF0aW9ucyBzaGFsbCByZXR1cm4gdGhpcy5yZXN1bHRCdWZmZXJcblxuXHR9XG5cblx0aW50ZXJ2YWxDaGFuZ2VkXyggLyogaTEsIHQwLCB0MSAqLyApIHtcblxuXHRcdC8vIGVtcHR5XG5cblx0fVxuXG59XG5cbi8qKlxuICogRmFzdCBhbmQgc2ltcGxlIGN1YmljIHNwbGluZSBpbnRlcnBvbGFudC5cbiAqXG4gKiBJdCB3YXMgZGVyaXZlZCBmcm9tIGEgSGVybWl0aWFuIGNvbnN0cnVjdGlvbiBzZXR0aW5nIHRoZSBmaXJzdCBkZXJpdmF0aXZlXG4gKiBhdCBlYWNoIHNhbXBsZSBwb3NpdGlvbiB0byB0aGUgbGluZWFyIHNsb3BlIGJldHdlZW4gbmVpZ2hib3JpbmcgcG9zaXRpb25zXG4gKiBvdmVyIHRoZWlyIHBhcmFtZXRlciBpbnRlcnZhbC5cbiAqL1xuXG5jbGFzcyBDdWJpY0ludGVycG9sYW50IGV4dGVuZHMgSW50ZXJwb2xhbnQge1xuXG5cdGNvbnN0cnVjdG9yKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICkge1xuXG5cdFx0c3VwZXIoIHBhcmFtZXRlclBvc2l0aW9ucywgc2FtcGxlVmFsdWVzLCBzYW1wbGVTaXplLCByZXN1bHRCdWZmZXIgKTtcblxuXHRcdHRoaXMuX3dlaWdodFByZXYgPSAtIDA7XG5cdFx0dGhpcy5fb2Zmc2V0UHJldiA9IC0gMDtcblx0XHR0aGlzLl93ZWlnaHROZXh0ID0gLSAwO1xuXHRcdHRoaXMuX29mZnNldE5leHQgPSAtIDA7XG5cblx0XHR0aGlzLkRlZmF1bHRTZXR0aW5nc18gPSB7XG5cblx0XHRcdGVuZGluZ1N0YXJ0OiBaZXJvQ3VydmF0dXJlRW5kaW5nLFxuXHRcdFx0ZW5kaW5nRW5kOiBaZXJvQ3VydmF0dXJlRW5kaW5nXG5cblx0XHR9O1xuXG5cdH1cblxuXHRpbnRlcnZhbENoYW5nZWRfKCBpMSwgdDAsIHQxICkge1xuXG5cdFx0Y29uc3QgcHAgPSB0aGlzLnBhcmFtZXRlclBvc2l0aW9ucztcblx0XHRsZXQgaVByZXYgPSBpMSAtIDIsXG5cdFx0XHRpTmV4dCA9IGkxICsgMSxcblxuXHRcdFx0dFByZXYgPSBwcFsgaVByZXYgXSxcblx0XHRcdHROZXh0ID0gcHBbIGlOZXh0IF07XG5cblx0XHRpZiAoIHRQcmV2ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHN3aXRjaCAoIHRoaXMuZ2V0U2V0dGluZ3NfKCkuZW5kaW5nU3RhcnQgKSB7XG5cblx0XHRcdFx0Y2FzZSBaZXJvU2xvcGVFbmRpbmc6XG5cblx0XHRcdFx0XHQvLyBmJyh0MCkgPSAwXG5cdFx0XHRcdFx0aVByZXYgPSBpMTtcblx0XHRcdFx0XHR0UHJldiA9IDIgKiB0MCAtIHQxO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBXcmFwQXJvdW5kRW5kaW5nOlxuXG5cdFx0XHRcdFx0Ly8gdXNlIHRoZSBvdGhlciBlbmQgb2YgdGhlIGN1cnZlXG5cdFx0XHRcdFx0aVByZXYgPSBwcC5sZW5ndGggLSAyO1xuXHRcdFx0XHRcdHRQcmV2ID0gdDAgKyBwcFsgaVByZXYgXSAtIHBwWyBpUHJldiArIDEgXTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGRlZmF1bHQ6IC8vIFplcm9DdXJ2YXR1cmVFbmRpbmdcblxuXHRcdFx0XHRcdC8vIGYnJyh0MCkgPSAwIGEuay5hLiBOYXR1cmFsIFNwbGluZVxuXHRcdFx0XHRcdGlQcmV2ID0gaTE7XG5cdFx0XHRcdFx0dFByZXYgPSB0MTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCB0TmV4dCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRzd2l0Y2ggKCB0aGlzLmdldFNldHRpbmdzXygpLmVuZGluZ0VuZCApIHtcblxuXHRcdFx0XHRjYXNlIFplcm9TbG9wZUVuZGluZzpcblxuXHRcdFx0XHRcdC8vIGYnKHROKSA9IDBcblx0XHRcdFx0XHRpTmV4dCA9IGkxO1xuXHRcdFx0XHRcdHROZXh0ID0gMiAqIHQxIC0gdDA7XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlIFdyYXBBcm91bmRFbmRpbmc6XG5cblx0XHRcdFx0XHQvLyB1c2UgdGhlIG90aGVyIGVuZCBvZiB0aGUgY3VydmVcblx0XHRcdFx0XHRpTmV4dCA9IDE7XG5cdFx0XHRcdFx0dE5leHQgPSB0MSArIHBwWyAxIF0gLSBwcFsgMCBdO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0ZGVmYXVsdDogLy8gWmVyb0N1cnZhdHVyZUVuZGluZ1xuXG5cdFx0XHRcdFx0Ly8gZicnKHROKSA9IDAsIGEuay5hLiBOYXR1cmFsIFNwbGluZVxuXHRcdFx0XHRcdGlOZXh0ID0gaTEgLSAxO1xuXHRcdFx0XHRcdHROZXh0ID0gdDA7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IGhhbGZEdCA9ICggdDEgLSB0MCApICogMC41LFxuXHRcdFx0c3RyaWRlID0gdGhpcy52YWx1ZVNpemU7XG5cblx0XHR0aGlzLl93ZWlnaHRQcmV2ID0gaGFsZkR0IC8gKCB0MCAtIHRQcmV2ICk7XG5cdFx0dGhpcy5fd2VpZ2h0TmV4dCA9IGhhbGZEdCAvICggdE5leHQgLSB0MSApO1xuXHRcdHRoaXMuX29mZnNldFByZXYgPSBpUHJldiAqIHN0cmlkZTtcblx0XHR0aGlzLl9vZmZzZXROZXh0ID0gaU5leHQgKiBzdHJpZGU7XG5cblx0fVxuXG5cdGludGVycG9sYXRlXyggaTEsIHQwLCB0LCB0MSApIHtcblxuXHRcdGNvbnN0IHJlc3VsdCA9IHRoaXMucmVzdWx0QnVmZmVyLFxuXHRcdFx0dmFsdWVzID0gdGhpcy5zYW1wbGVWYWx1ZXMsXG5cdFx0XHRzdHJpZGUgPSB0aGlzLnZhbHVlU2l6ZSxcblxuXHRcdFx0bzEgPSBpMSAqIHN0cmlkZSxcdFx0bzAgPSBvMSAtIHN0cmlkZSxcblx0XHRcdG9QID0gdGhpcy5fb2Zmc2V0UHJldiwgXHRvTiA9IHRoaXMuX29mZnNldE5leHQsXG5cdFx0XHR3UCA9IHRoaXMuX3dlaWdodFByZXYsXHR3TiA9IHRoaXMuX3dlaWdodE5leHQsXG5cblx0XHRcdHAgPSAoIHQgLSB0MCApIC8gKCB0MSAtIHQwICksXG5cdFx0XHRwcCA9IHAgKiBwLFxuXHRcdFx0cHBwID0gcHAgKiBwO1xuXG5cdFx0Ly8gZXZhbHVhdGUgcG9seW5vbWlhbHNcblxuXHRcdGNvbnN0IHNQID0gLSB3UCAqIHBwcCArIDIgKiB3UCAqIHBwIC0gd1AgKiBwO1xuXHRcdGNvbnN0IHMwID0gKCAxICsgd1AgKSAqIHBwcCArICggLSAxLjUgLSAyICogd1AgKSAqIHBwICsgKCAtIDAuNSArIHdQICkgKiBwICsgMTtcblx0XHRjb25zdCBzMSA9ICggLSAxIC0gd04gKSAqIHBwcCArICggMS41ICsgd04gKSAqIHBwICsgMC41ICogcDtcblx0XHRjb25zdCBzTiA9IHdOICogcHBwIC0gd04gKiBwcDtcblxuXHRcdC8vIGNvbWJpbmUgZGF0YSBsaW5lYXJseVxuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBzdHJpZGU7ICsrIGkgKSB7XG5cblx0XHRcdHJlc3VsdFsgaSBdID1cblx0XHRcdFx0XHRzUCAqIHZhbHVlc1sgb1AgKyBpIF0gK1xuXHRcdFx0XHRcdHMwICogdmFsdWVzWyBvMCArIGkgXSArXG5cdFx0XHRcdFx0czEgKiB2YWx1ZXNbIG8xICsgaSBdICtcblx0XHRcdFx0XHRzTiAqIHZhbHVlc1sgb04gKyBpIF07XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcmVzdWx0O1xuXG5cdH1cblxufVxuXG5jbGFzcyBMaW5lYXJJbnRlcnBvbGFudCBleHRlbmRzIEludGVycG9sYW50IHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApIHtcblxuXHRcdHN1cGVyKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICk7XG5cblx0fVxuXG5cdGludGVycG9sYXRlXyggaTEsIHQwLCB0LCB0MSApIHtcblxuXHRcdGNvbnN0IHJlc3VsdCA9IHRoaXMucmVzdWx0QnVmZmVyLFxuXHRcdFx0dmFsdWVzID0gdGhpcy5zYW1wbGVWYWx1ZXMsXG5cdFx0XHRzdHJpZGUgPSB0aGlzLnZhbHVlU2l6ZSxcblxuXHRcdFx0b2Zmc2V0MSA9IGkxICogc3RyaWRlLFxuXHRcdFx0b2Zmc2V0MCA9IG9mZnNldDEgLSBzdHJpZGUsXG5cblx0XHRcdHdlaWdodDEgPSAoIHQgLSB0MCApIC8gKCB0MSAtIHQwICksXG5cdFx0XHR3ZWlnaHQwID0gMSAtIHdlaWdodDE7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IHN0cmlkZTsgKysgaSApIHtcblxuXHRcdFx0cmVzdWx0WyBpIF0gPVxuXHRcdFx0XHRcdHZhbHVlc1sgb2Zmc2V0MCArIGkgXSAqIHdlaWdodDAgK1xuXHRcdFx0XHRcdHZhbHVlc1sgb2Zmc2V0MSArIGkgXSAqIHdlaWdodDE7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gcmVzdWx0O1xuXG5cdH1cblxufVxuXG4vKipcbiAqXG4gKiBJbnRlcnBvbGFudCB0aGF0IGV2YWx1YXRlcyB0byB0aGUgc2FtcGxlIHZhbHVlIGF0IHRoZSBwb3NpdGlvbiBwcmVjZWRpbmdcbiAqIHRoZSBwYXJhbWV0ZXIuXG4gKi9cblxuY2xhc3MgRGlzY3JldGVJbnRlcnBvbGFudCBleHRlbmRzIEludGVycG9sYW50IHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApIHtcblxuXHRcdHN1cGVyKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICk7XG5cblx0fVxuXG5cdGludGVycG9sYXRlXyggaTEgLyosIHQwLCB0LCB0MSAqLyApIHtcblxuXHRcdHJldHVybiB0aGlzLmNvcHlTYW1wbGVWYWx1ZV8oIGkxIC0gMSApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBLZXlmcmFtZVRyYWNrIHtcblxuXHRjb25zdHJ1Y3RvciggbmFtZSwgdGltZXMsIHZhbHVlcywgaW50ZXJwb2xhdGlvbiApIHtcblxuXHRcdGlmICggbmFtZSA9PT0gdW5kZWZpbmVkICkgdGhyb3cgbmV3IEVycm9yKCAnVEhSRUUuS2V5ZnJhbWVUcmFjazogdHJhY2sgbmFtZSBpcyB1bmRlZmluZWQnICk7XG5cdFx0aWYgKCB0aW1lcyA9PT0gdW5kZWZpbmVkIHx8IHRpbWVzLmxlbmd0aCA9PT0gMCApIHRocm93IG5ldyBFcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IG5vIGtleWZyYW1lcyBpbiB0cmFjayBuYW1lZCAnICsgbmFtZSApO1xuXG5cdFx0dGhpcy5uYW1lID0gbmFtZTtcblxuXHRcdHRoaXMudGltZXMgPSBjb252ZXJ0QXJyYXkoIHRpbWVzLCB0aGlzLlRpbWVCdWZmZXJUeXBlICk7XG5cdFx0dGhpcy52YWx1ZXMgPSBjb252ZXJ0QXJyYXkoIHZhbHVlcywgdGhpcy5WYWx1ZUJ1ZmZlclR5cGUgKTtcblxuXHRcdHRoaXMuc2V0SW50ZXJwb2xhdGlvbiggaW50ZXJwb2xhdGlvbiB8fCB0aGlzLkRlZmF1bHRJbnRlcnBvbGF0aW9uICk7XG5cblx0fVxuXG5cdC8vIFNlcmlhbGl6YXRpb24gKGluIHN0YXRpYyBjb250ZXh0LCBiZWNhdXNlIG9mIGNvbnN0cnVjdG9yIGludm9jYXRpb25cblx0Ly8gYW5kIGF1dG9tYXRpYyBpbnZvY2F0aW9uIG9mIC50b0pTT04pOlxuXG5cdHN0YXRpYyB0b0pTT04oIHRyYWNrICkge1xuXG5cdFx0Y29uc3QgdHJhY2tUeXBlID0gdHJhY2suY29uc3RydWN0b3I7XG5cblx0XHRsZXQganNvbjtcblxuXHRcdC8vIGRlcml2ZWQgY2xhc3NlcyBjYW4gZGVmaW5lIGEgc3RhdGljIHRvSlNPTiBtZXRob2Rcblx0XHRpZiAoIHRyYWNrVHlwZS50b0pTT04gIT09IHRoaXMudG9KU09OICkge1xuXG5cdFx0XHRqc29uID0gdHJhY2tUeXBlLnRvSlNPTiggdHJhY2sgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIGJ5IGRlZmF1bHQsIHdlIGFzc3VtZSB0aGUgZGF0YSBjYW4gYmUgc2VyaWFsaXplZCBhcy1pc1xuXHRcdFx0anNvbiA9IHtcblxuXHRcdFx0XHQnbmFtZSc6IHRyYWNrLm5hbWUsXG5cdFx0XHRcdCd0aW1lcyc6IGNvbnZlcnRBcnJheSggdHJhY2sudGltZXMsIEFycmF5ICksXG5cdFx0XHRcdCd2YWx1ZXMnOiBjb252ZXJ0QXJyYXkoIHRyYWNrLnZhbHVlcywgQXJyYXkgKVxuXG5cdFx0XHR9O1xuXG5cdFx0XHRjb25zdCBpbnRlcnBvbGF0aW9uID0gdHJhY2suZ2V0SW50ZXJwb2xhdGlvbigpO1xuXG5cdFx0XHRpZiAoIGludGVycG9sYXRpb24gIT09IHRyYWNrLkRlZmF1bHRJbnRlcnBvbGF0aW9uICkge1xuXG5cdFx0XHRcdGpzb24uaW50ZXJwb2xhdGlvbiA9IGludGVycG9sYXRpb247XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGpzb24udHlwZSA9IHRyYWNrLlZhbHVlVHlwZU5hbWU7IC8vIG1hbmRhdG9yeVxuXG5cdFx0cmV0dXJuIGpzb247XG5cblx0fVxuXG5cdEludGVycG9sYW50RmFjdG9yeU1ldGhvZERpc2NyZXRlKCByZXN1bHQgKSB7XG5cblx0XHRyZXR1cm4gbmV3IERpc2NyZXRlSW50ZXJwb2xhbnQoIHRoaXMudGltZXMsIHRoaXMudmFsdWVzLCB0aGlzLmdldFZhbHVlU2l6ZSgpLCByZXN1bHQgKTtcblxuXHR9XG5cblx0SW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kTGluZWFyKCByZXN1bHQgKSB7XG5cblx0XHRyZXR1cm4gbmV3IExpbmVhckludGVycG9sYW50KCB0aGlzLnRpbWVzLCB0aGlzLnZhbHVlcywgdGhpcy5nZXRWYWx1ZVNpemUoKSwgcmVzdWx0ICk7XG5cblx0fVxuXG5cdEludGVycG9sYW50RmFjdG9yeU1ldGhvZFNtb290aCggcmVzdWx0ICkge1xuXG5cdFx0cmV0dXJuIG5ldyBDdWJpY0ludGVycG9sYW50KCB0aGlzLnRpbWVzLCB0aGlzLnZhbHVlcywgdGhpcy5nZXRWYWx1ZVNpemUoKSwgcmVzdWx0ICk7XG5cblx0fVxuXG5cdHNldEludGVycG9sYXRpb24oIGludGVycG9sYXRpb24gKSB7XG5cblx0XHRsZXQgZmFjdG9yeU1ldGhvZDtcblxuXHRcdHN3aXRjaCAoIGludGVycG9sYXRpb24gKSB7XG5cblx0XHRcdGNhc2UgSW50ZXJwb2xhdGVEaXNjcmV0ZTpcblxuXHRcdFx0XHRmYWN0b3J5TWV0aG9kID0gdGhpcy5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2REaXNjcmV0ZTtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSBJbnRlcnBvbGF0ZUxpbmVhcjpcblxuXHRcdFx0XHRmYWN0b3J5TWV0aG9kID0gdGhpcy5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RMaW5lYXI7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgSW50ZXJwb2xhdGVTbW9vdGg6XG5cblx0XHRcdFx0ZmFjdG9yeU1ldGhvZCA9IHRoaXMuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kU21vb3RoO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCBmYWN0b3J5TWV0aG9kID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IG1lc3NhZ2UgPSAndW5zdXBwb3J0ZWQgaW50ZXJwb2xhdGlvbiBmb3IgJyArXG5cdFx0XHRcdHRoaXMuVmFsdWVUeXBlTmFtZSArICcga2V5ZnJhbWUgdHJhY2sgbmFtZWQgJyArIHRoaXMubmFtZTtcblxuXHRcdFx0aWYgKCB0aGlzLmNyZWF0ZUludGVycG9sYW50ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Ly8gZmFsbCBiYWNrIHRvIGRlZmF1bHQsIHVubGVzcyB0aGUgZGVmYXVsdCBpdHNlbGYgaXMgbWVzc2VkIHVwXG5cdFx0XHRcdGlmICggaW50ZXJwb2xhdGlvbiAhPT0gdGhpcy5EZWZhdWx0SW50ZXJwb2xhdGlvbiApIHtcblxuXHRcdFx0XHRcdHRoaXMuc2V0SW50ZXJwb2xhdGlvbiggdGhpcy5EZWZhdWx0SW50ZXJwb2xhdGlvbiApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHR0aHJvdyBuZXcgRXJyb3IoIG1lc3NhZ2UgKTsgLy8gZmF0YWwsIGluIHRoaXMgY2FzZVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5LZXlmcmFtZVRyYWNrOicsIG1lc3NhZ2UgKTtcblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5jcmVhdGVJbnRlcnBvbGFudCA9IGZhY3RvcnlNZXRob2Q7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0SW50ZXJwb2xhdGlvbigpIHtcblxuXHRcdHN3aXRjaCAoIHRoaXMuY3JlYXRlSW50ZXJwb2xhbnQgKSB7XG5cblx0XHRcdGNhc2UgdGhpcy5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2REaXNjcmV0ZTpcblxuXHRcdFx0XHRyZXR1cm4gSW50ZXJwb2xhdGVEaXNjcmV0ZTtcblxuXHRcdFx0Y2FzZSB0aGlzLkludGVycG9sYW50RmFjdG9yeU1ldGhvZExpbmVhcjpcblxuXHRcdFx0XHRyZXR1cm4gSW50ZXJwb2xhdGVMaW5lYXI7XG5cblx0XHRcdGNhc2UgdGhpcy5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RTbW9vdGg6XG5cblx0XHRcdFx0cmV0dXJuIEludGVycG9sYXRlU21vb3RoO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRnZXRWYWx1ZVNpemUoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy52YWx1ZXMubGVuZ3RoIC8gdGhpcy50aW1lcy5sZW5ndGg7XG5cblx0fVxuXG5cdC8vIG1vdmUgYWxsIGtleWZyYW1lcyBlaXRoZXIgZm9yd2FyZHMgb3IgYmFja3dhcmRzIGluIHRpbWVcblx0c2hpZnQoIHRpbWVPZmZzZXQgKSB7XG5cblx0XHRpZiAoIHRpbWVPZmZzZXQgIT09IDAuMCApIHtcblxuXHRcdFx0Y29uc3QgdGltZXMgPSB0aGlzLnRpbWVzO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSB0aW1lcy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdFx0dGltZXNbIGkgXSArPSB0aW1lT2Zmc2V0O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Ly8gc2NhbGUgYWxsIGtleWZyYW1lIHRpbWVzIGJ5IGEgZmFjdG9yICh1c2VmdWwgZm9yIGZyYW1lIDwtPiBzZWNvbmRzIGNvbnZlcnNpb25zKVxuXHRzY2FsZSggdGltZVNjYWxlICkge1xuXG5cdFx0aWYgKCB0aW1lU2NhbGUgIT09IDEuMCApIHtcblxuXHRcdFx0Y29uc3QgdGltZXMgPSB0aGlzLnRpbWVzO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSB0aW1lcy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdFx0dGltZXNbIGkgXSAqPSB0aW1lU2NhbGU7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvLyByZW1vdmVzIGtleWZyYW1lcyBiZWZvcmUgYW5kIGFmdGVyIGFuaW1hdGlvbiB3aXRob3V0IGNoYW5naW5nIGFueSB2YWx1ZXMgd2l0aGluIHRoZSByYW5nZSBbc3RhcnRUaW1lLCBlbmRUaW1lXS5cblx0Ly8gSU1QT1JUQU5UOiBXZSBkbyBub3Qgc2hpZnQgYXJvdW5kIGtleXMgdG8gdGhlIHN0YXJ0IG9mIHRoZSB0cmFjayB0aW1lLCBiZWNhdXNlIGZvciBpbnRlcnBvbGF0ZWQga2V5cyB0aGlzIHdpbGwgY2hhbmdlIHRoZWlyIHZhbHVlc1xuXHR0cmltKCBzdGFydFRpbWUsIGVuZFRpbWUgKSB7XG5cblx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXMsXG5cdFx0XHRuS2V5cyA9IHRpbWVzLmxlbmd0aDtcblxuXHRcdGxldCBmcm9tID0gMCxcblx0XHRcdHRvID0gbktleXMgLSAxO1xuXG5cdFx0d2hpbGUgKCBmcm9tICE9PSBuS2V5cyAmJiB0aW1lc1sgZnJvbSBdIDwgc3RhcnRUaW1lICkge1xuXG5cdFx0XHQrKyBmcm9tO1xuXG5cdFx0fVxuXG5cdFx0d2hpbGUgKCB0byAhPT0gLSAxICYmIHRpbWVzWyB0byBdID4gZW5kVGltZSApIHtcblxuXHRcdFx0LS0gdG87XG5cblx0XHR9XG5cblx0XHQrKyB0bzsgLy8gaW5jbHVzaXZlIC0+IGV4Y2x1c2l2ZSBib3VuZFxuXG5cdFx0aWYgKCBmcm9tICE9PSAwIHx8IHRvICE9PSBuS2V5cyApIHtcblxuXHRcdFx0Ly8gZW1wdHkgdHJhY2tzIGFyZSBmb3JiaWRkZW4sIHNvIGtlZXAgYXQgbGVhc3Qgb25lIGtleWZyYW1lXG5cdFx0XHRpZiAoIGZyb20gPj0gdG8gKSB7XG5cblx0XHRcdFx0dG8gPSBNYXRoLm1heCggdG8sIDEgKTtcblx0XHRcdFx0ZnJvbSA9IHRvIC0gMTtcblxuXHRcdFx0fVxuXG5cdFx0XHRjb25zdCBzdHJpZGUgPSB0aGlzLmdldFZhbHVlU2l6ZSgpO1xuXHRcdFx0dGhpcy50aW1lcyA9IHRpbWVzLnNsaWNlKCBmcm9tLCB0byApO1xuXHRcdFx0dGhpcy52YWx1ZXMgPSB0aGlzLnZhbHVlcy5zbGljZSggZnJvbSAqIHN0cmlkZSwgdG8gKiBzdHJpZGUgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvLyBlbnN1cmUgd2UgZG8gbm90IGdldCBhIEdhcmJhZ2VJbkdhcmJhZ2VPdXQgc2l0dWF0aW9uLCBtYWtlIHN1cmUgdHJhY2tzIGFyZSBhdCBsZWFzdCBtaW5pbWFsbHkgdmlhYmxlXG5cdHZhbGlkYXRlKCkge1xuXG5cdFx0bGV0IHZhbGlkID0gdHJ1ZTtcblxuXHRcdGNvbnN0IHZhbHVlU2l6ZSA9IHRoaXMuZ2V0VmFsdWVTaXplKCk7XG5cdFx0aWYgKCB2YWx1ZVNpemUgLSBNYXRoLmZsb29yKCB2YWx1ZVNpemUgKSAhPT0gMCApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IEludmFsaWQgdmFsdWUgc2l6ZSBpbiB0cmFjay4nLCB0aGlzICk7XG5cdFx0XHR2YWxpZCA9IGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgdGltZXMgPSB0aGlzLnRpbWVzLFxuXHRcdFx0dmFsdWVzID0gdGhpcy52YWx1ZXMsXG5cblx0XHRcdG5LZXlzID0gdGltZXMubGVuZ3RoO1xuXG5cdFx0aWYgKCBuS2V5cyA9PT0gMCApIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IFRyYWNrIGlzIGVtcHR5LicsIHRoaXMgKTtcblx0XHRcdHZhbGlkID0gZmFsc2U7XG5cblx0XHR9XG5cblx0XHRsZXQgcHJldlRpbWUgPSBudWxsO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuS2V5czsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgY3VyclRpbWUgPSB0aW1lc1sgaSBdO1xuXG5cdFx0XHRpZiAoIHR5cGVvZiBjdXJyVGltZSA9PT0gJ251bWJlcicgJiYgaXNOYU4oIGN1cnJUaW1lICkgKSB7XG5cblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IFRpbWUgaXMgbm90IGEgdmFsaWQgbnVtYmVyLicsIHRoaXMsIGksIGN1cnJUaW1lICk7XG5cdFx0XHRcdHZhbGlkID0gZmFsc2U7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggcHJldlRpbWUgIT09IG51bGwgJiYgcHJldlRpbWUgPiBjdXJyVGltZSApIHtcblxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuS2V5ZnJhbWVUcmFjazogT3V0IG9mIG9yZGVyIGtleXMuJywgdGhpcywgaSwgY3VyclRpbWUsIHByZXZUaW1lICk7XG5cdFx0XHRcdHZhbGlkID0gZmFsc2U7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHR9XG5cblx0XHRcdHByZXZUaW1lID0gY3VyclRpbWU7XG5cblx0XHR9XG5cblx0XHRpZiAoIHZhbHVlcyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRpZiAoIGlzVHlwZWRBcnJheSggdmFsdWVzICkgKSB7XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gdmFsdWVzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0XHRcdGNvbnN0IHZhbHVlID0gdmFsdWVzWyBpIF07XG5cblx0XHRcdFx0XHRpZiAoIGlzTmFOKCB2YWx1ZSApICkge1xuXG5cdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuS2V5ZnJhbWVUcmFjazogVmFsdWUgaXMgbm90IGEgdmFsaWQgbnVtYmVyLicsIHRoaXMsIGksIHZhbHVlICk7XG5cdFx0XHRcdFx0XHR2YWxpZCA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdmFsaWQ7XG5cblx0fVxuXG5cdC8vIHJlbW92ZXMgZXF1aXZhbGVudCBzZXF1ZW50aWFsIGtleXMgYXMgY29tbW9uIGluIG1vcnBoIHRhcmdldCBzZXF1ZW5jZXNcblx0Ly8gKDAsMCwwLDAsMSwxLDEsMCwwLDAsMCwwLDAsMCkgLS0+ICgwLDAsMSwxLDAsMClcblx0b3B0aW1pemUoKSB7XG5cblx0XHQvLyB0aW1lcyBvciB2YWx1ZXMgbWF5IGJlIHNoYXJlZCB3aXRoIG90aGVyIHRyYWNrcywgc28gb3ZlcndyaXRpbmcgaXMgdW5zYWZlXG5cdFx0Y29uc3QgdGltZXMgPSB0aGlzLnRpbWVzLnNsaWNlKCksXG5cdFx0XHR2YWx1ZXMgPSB0aGlzLnZhbHVlcy5zbGljZSgpLFxuXHRcdFx0c3RyaWRlID0gdGhpcy5nZXRWYWx1ZVNpemUoKSxcblxuXHRcdFx0c21vb3RoSW50ZXJwb2xhdGlvbiA9IHRoaXMuZ2V0SW50ZXJwb2xhdGlvbigpID09PSBJbnRlcnBvbGF0ZVNtb290aCxcblxuXHRcdFx0bGFzdEluZGV4ID0gdGltZXMubGVuZ3RoIC0gMTtcblxuXHRcdGxldCB3cml0ZUluZGV4ID0gMTtcblxuXHRcdGZvciAoIGxldCBpID0gMTsgaSA8IGxhc3RJbmRleDsgKysgaSApIHtcblxuXHRcdFx0bGV0IGtlZXAgPSBmYWxzZTtcblxuXHRcdFx0Y29uc3QgdGltZSA9IHRpbWVzWyBpIF07XG5cdFx0XHRjb25zdCB0aW1lTmV4dCA9IHRpbWVzWyBpICsgMSBdO1xuXG5cdFx0XHQvLyByZW1vdmUgYWRqYWNlbnQga2V5ZnJhbWVzIHNjaGVkdWxlZCBhdCB0aGUgc2FtZSB0aW1lXG5cblx0XHRcdGlmICggdGltZSAhPT0gdGltZU5leHQgJiYgKCBpICE9PSAxIHx8IHRpbWUgIT09IHRpbWVzWyAwIF0gKSApIHtcblxuXHRcdFx0XHRpZiAoICEgc21vb3RoSW50ZXJwb2xhdGlvbiApIHtcblxuXHRcdFx0XHRcdC8vIHJlbW92ZSB1bm5lY2Vzc2FyeSBrZXlmcmFtZXMgc2FtZSBhcyB0aGVpciBuZWlnaGJvcnNcblxuXHRcdFx0XHRcdGNvbnN0IG9mZnNldCA9IGkgKiBzdHJpZGUsXG5cdFx0XHRcdFx0XHRvZmZzZXRQID0gb2Zmc2V0IC0gc3RyaWRlLFxuXHRcdFx0XHRcdFx0b2Zmc2V0TiA9IG9mZnNldCArIHN0cmlkZTtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMDsgaiAhPT0gc3RyaWRlOyArKyBqICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCB2YWx1ZSA9IHZhbHVlc1sgb2Zmc2V0ICsgaiBdO1xuXG5cdFx0XHRcdFx0XHRpZiAoIHZhbHVlICE9PSB2YWx1ZXNbIG9mZnNldFAgKyBqIF0gfHxcblx0XHRcdFx0XHRcdFx0dmFsdWUgIT09IHZhbHVlc1sgb2Zmc2V0TiArIGogXSApIHtcblxuXHRcdFx0XHRcdFx0XHRrZWVwID0gdHJ1ZTtcblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0a2VlcCA9IHRydWU7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGluLXBsYWNlIGNvbXBhY3Rpb25cblxuXHRcdFx0aWYgKCBrZWVwICkge1xuXG5cdFx0XHRcdGlmICggaSAhPT0gd3JpdGVJbmRleCApIHtcblxuXHRcdFx0XHRcdHRpbWVzWyB3cml0ZUluZGV4IF0gPSB0aW1lc1sgaSBdO1xuXG5cdFx0XHRcdFx0Y29uc3QgcmVhZE9mZnNldCA9IGkgKiBzdHJpZGUsXG5cdFx0XHRcdFx0XHR3cml0ZU9mZnNldCA9IHdyaXRlSW5kZXggKiBzdHJpZGU7XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDA7IGogIT09IHN0cmlkZTsgKysgaiApIHtcblxuXHRcdFx0XHRcdFx0dmFsdWVzWyB3cml0ZU9mZnNldCArIGogXSA9IHZhbHVlc1sgcmVhZE9mZnNldCArIGogXTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Kysgd3JpdGVJbmRleDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gZmx1c2ggbGFzdCBrZXlmcmFtZSAoY29tcGFjdGlvbiBsb29rcyBhaGVhZClcblxuXHRcdGlmICggbGFzdEluZGV4ID4gMCApIHtcblxuXHRcdFx0dGltZXNbIHdyaXRlSW5kZXggXSA9IHRpbWVzWyBsYXN0SW5kZXggXTtcblxuXHRcdFx0Zm9yICggbGV0IHJlYWRPZmZzZXQgPSBsYXN0SW5kZXggKiBzdHJpZGUsIHdyaXRlT2Zmc2V0ID0gd3JpdGVJbmRleCAqIHN0cmlkZSwgaiA9IDA7IGogIT09IHN0cmlkZTsgKysgaiApIHtcblxuXHRcdFx0XHR2YWx1ZXNbIHdyaXRlT2Zmc2V0ICsgaiBdID0gdmFsdWVzWyByZWFkT2Zmc2V0ICsgaiBdO1xuXG5cdFx0XHR9XG5cblx0XHRcdCsrIHdyaXRlSW5kZXg7XG5cblx0XHR9XG5cblx0XHRpZiAoIHdyaXRlSW5kZXggIT09IHRpbWVzLmxlbmd0aCApIHtcblxuXHRcdFx0dGhpcy50aW1lcyA9IHRpbWVzLnNsaWNlKCAwLCB3cml0ZUluZGV4ICk7XG5cdFx0XHR0aGlzLnZhbHVlcyA9IHZhbHVlcy5zbGljZSggMCwgd3JpdGVJbmRleCAqIHN0cmlkZSApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhpcy50aW1lcyA9IHRpbWVzO1xuXHRcdFx0dGhpcy52YWx1ZXMgPSB2YWx1ZXM7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRjb25zdCB0aW1lcyA9IHRoaXMudGltZXMuc2xpY2UoKTtcblx0XHRjb25zdCB2YWx1ZXMgPSB0aGlzLnZhbHVlcy5zbGljZSgpO1xuXG5cdFx0Y29uc3QgVHlwZWRLZXlmcmFtZVRyYWNrID0gdGhpcy5jb25zdHJ1Y3Rvcjtcblx0XHRjb25zdCB0cmFjayA9IG5ldyBUeXBlZEtleWZyYW1lVHJhY2soIHRoaXMubmFtZSwgdGltZXMsIHZhbHVlcyApO1xuXG5cdFx0Ly8gSW50ZXJwb2xhbnQgYXJndW1lbnQgdG8gY29uc3RydWN0b3IgaXMgbm90IHNhdmVkLCBzbyBjb3B5IHRoZSBmYWN0b3J5IG1ldGhvZCBkaXJlY3RseS5cblx0XHR0cmFjay5jcmVhdGVJbnRlcnBvbGFudCA9IHRoaXMuY3JlYXRlSW50ZXJwb2xhbnQ7XG5cblx0XHRyZXR1cm4gdHJhY2s7XG5cblx0fVxuXG59XG5cbktleWZyYW1lVHJhY2sucHJvdG90eXBlLlRpbWVCdWZmZXJUeXBlID0gRmxvYXQzMkFycmF5O1xuS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuVmFsdWVCdWZmZXJUeXBlID0gRmxvYXQzMkFycmF5O1xuS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuRGVmYXVsdEludGVycG9sYXRpb24gPSBJbnRlcnBvbGF0ZUxpbmVhcjtcblxuLyoqXG4gKiBBIFRyYWNrIG9mIEJvb2xlYW4ga2V5ZnJhbWUgdmFsdWVzLlxuICovXG5jbGFzcyBCb29sZWFuS2V5ZnJhbWVUcmFjayBleHRlbmRzIEtleWZyYW1lVHJhY2sge1xuXG5cdC8vIE5vIGludGVycG9sYXRpb24gcGFyYW1ldGVyIGJlY2F1c2Ugb25seSBJbnRlcnBvbGF0ZURpc2NyZXRlIGlzIHZhbGlkLlxuXHRjb25zdHJ1Y3RvciggbmFtZSwgdGltZXMsIHZhbHVlcyApIHtcblxuXHRcdHN1cGVyKCBuYW1lLCB0aW1lcywgdmFsdWVzICk7XG5cblx0fVxuXG59XG5cbkJvb2xlYW5LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZVR5cGVOYW1lID0gJ2Jvb2wnO1xuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlQnVmZmVyVHlwZSA9IEFycmF5O1xuQm9vbGVhbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkRlZmF1bHRJbnRlcnBvbGF0aW9uID0gSW50ZXJwb2xhdGVEaXNjcmV0ZTtcbkJvb2xlYW5LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5JbnRlcnBvbGFudEZhY3RvcnlNZXRob2RMaW5lYXIgPSB1bmRlZmluZWQ7XG5Cb29sZWFuS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kU21vb3RoID0gdW5kZWZpbmVkO1xuXG4vKipcbiAqIEEgVHJhY2sgb2Yga2V5ZnJhbWUgdmFsdWVzIHRoYXQgcmVwcmVzZW50IGNvbG9yLlxuICovXG5jbGFzcyBDb2xvcktleWZyYW1lVHJhY2sgZXh0ZW5kcyBLZXlmcmFtZVRyYWNrIHt9XG5cbkNvbG9yS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuVmFsdWVUeXBlTmFtZSA9ICdjb2xvcic7XG5cbi8qKlxuICogQSBUcmFjayBvZiBudW1lcmljIGtleWZyYW1lIHZhbHVlcy5cbiAqL1xuY2xhc3MgTnVtYmVyS2V5ZnJhbWVUcmFjayBleHRlbmRzIEtleWZyYW1lVHJhY2sge31cblxuTnVtYmVyS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuVmFsdWVUeXBlTmFtZSA9ICdudW1iZXInO1xuXG4vKipcbiAqIFNwaGVyaWNhbCBsaW5lYXIgdW5pdCBxdWF0ZXJuaW9uIGludGVycG9sYW50LlxuICovXG5cbmNsYXNzIFF1YXRlcm5pb25MaW5lYXJJbnRlcnBvbGFudCBleHRlbmRzIEludGVycG9sYW50IHtcblxuXHRjb25zdHJ1Y3RvciggcGFyYW1ldGVyUG9zaXRpb25zLCBzYW1wbGVWYWx1ZXMsIHNhbXBsZVNpemUsIHJlc3VsdEJ1ZmZlciApIHtcblxuXHRcdHN1cGVyKCBwYXJhbWV0ZXJQb3NpdGlvbnMsIHNhbXBsZVZhbHVlcywgc2FtcGxlU2l6ZSwgcmVzdWx0QnVmZmVyICk7XG5cblx0fVxuXG5cdGludGVycG9sYXRlXyggaTEsIHQwLCB0LCB0MSApIHtcblxuXHRcdGNvbnN0IHJlc3VsdCA9IHRoaXMucmVzdWx0QnVmZmVyLFxuXHRcdFx0dmFsdWVzID0gdGhpcy5zYW1wbGVWYWx1ZXMsXG5cdFx0XHRzdHJpZGUgPSB0aGlzLnZhbHVlU2l6ZSxcblxuXHRcdFx0YWxwaGEgPSAoIHQgLSB0MCApIC8gKCB0MSAtIHQwICk7XG5cblx0XHRsZXQgb2Zmc2V0ID0gaTEgKiBzdHJpZGU7XG5cblx0XHRmb3IgKCBsZXQgZW5kID0gb2Zmc2V0ICsgc3RyaWRlOyBvZmZzZXQgIT09IGVuZDsgb2Zmc2V0ICs9IDQgKSB7XG5cblx0XHRcdFF1YXRlcm5pb24uc2xlcnBGbGF0KCByZXN1bHQsIDAsIHZhbHVlcywgb2Zmc2V0IC0gc3RyaWRlLCB2YWx1ZXMsIG9mZnNldCwgYWxwaGEgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiByZXN1bHQ7XG5cblx0fVxuXG59XG5cbi8qKlxuICogQSBUcmFjayBvZiBxdWF0ZXJuaW9uIGtleWZyYW1lIHZhbHVlcy5cbiAqL1xuY2xhc3MgUXVhdGVybmlvbktleWZyYW1lVHJhY2sgZXh0ZW5kcyBLZXlmcmFtZVRyYWNrIHtcblxuXHRJbnRlcnBvbGFudEZhY3RvcnlNZXRob2RMaW5lYXIoIHJlc3VsdCApIHtcblxuXHRcdHJldHVybiBuZXcgUXVhdGVybmlvbkxpbmVhckludGVycG9sYW50KCB0aGlzLnRpbWVzLCB0aGlzLnZhbHVlcywgdGhpcy5nZXRWYWx1ZVNpemUoKSwgcmVzdWx0ICk7XG5cblx0fVxuXG59XG5cblF1YXRlcm5pb25LZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZVR5cGVOYW1lID0gJ3F1YXRlcm5pb24nO1xuLy8gVmFsdWVCdWZmZXJUeXBlIGlzIGluaGVyaXRlZFxuLy8gRGVmYXVsdEludGVycG9sYXRpb24gaXMgaW5oZXJpdGVkO1xuUXVhdGVybmlvbktleWZyYW1lVHJhY2sucHJvdG90eXBlLkludGVycG9sYW50RmFjdG9yeU1ldGhvZFNtb290aCA9IHVuZGVmaW5lZDtcblxuLyoqXG4gKiBBIFRyYWNrIHRoYXQgaW50ZXJwb2xhdGVzIFN0cmluZ3NcbiAqL1xuY2xhc3MgU3RyaW5nS2V5ZnJhbWVUcmFjayBleHRlbmRzIEtleWZyYW1lVHJhY2sge1xuXG5cdC8vIE5vIGludGVycG9sYXRpb24gcGFyYW1ldGVyIGJlY2F1c2Ugb25seSBJbnRlcnBvbGF0ZURpc2NyZXRlIGlzIHZhbGlkLlxuXHRjb25zdHJ1Y3RvciggbmFtZSwgdGltZXMsIHZhbHVlcyApIHtcblxuXHRcdHN1cGVyKCBuYW1lLCB0aW1lcywgdmFsdWVzICk7XG5cblx0fVxuXG59XG5cblN0cmluZ0tleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlVHlwZU5hbWUgPSAnc3RyaW5nJztcblN0cmluZ0tleWZyYW1lVHJhY2sucHJvdG90eXBlLlZhbHVlQnVmZmVyVHlwZSA9IEFycmF5O1xuU3RyaW5nS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuRGVmYXVsdEludGVycG9sYXRpb24gPSBJbnRlcnBvbGF0ZURpc2NyZXRlO1xuU3RyaW5nS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kTGluZWFyID0gdW5kZWZpbmVkO1xuU3RyaW5nS2V5ZnJhbWVUcmFjay5wcm90b3R5cGUuSW50ZXJwb2xhbnRGYWN0b3J5TWV0aG9kU21vb3RoID0gdW5kZWZpbmVkO1xuXG4vKipcbiAqIEEgVHJhY2sgb2YgdmVjdG9yZWQga2V5ZnJhbWUgdmFsdWVzLlxuICovXG5jbGFzcyBWZWN0b3JLZXlmcmFtZVRyYWNrIGV4dGVuZHMgS2V5ZnJhbWVUcmFjayB7fVxuXG5WZWN0b3JLZXlmcmFtZVRyYWNrLnByb3RvdHlwZS5WYWx1ZVR5cGVOYW1lID0gJ3ZlY3Rvcic7XG5cbmNsYXNzIEFuaW1hdGlvbkNsaXAge1xuXG5cdGNvbnN0cnVjdG9yKCBuYW1lID0gJycsIGR1cmF0aW9uID0gLSAxLCB0cmFja3MgPSBbXSwgYmxlbmRNb2RlID0gTm9ybWFsQW5pbWF0aW9uQmxlbmRNb2RlICkge1xuXG5cdFx0dGhpcy5uYW1lID0gbmFtZTtcblx0XHR0aGlzLnRyYWNrcyA9IHRyYWNrcztcblx0XHR0aGlzLmR1cmF0aW9uID0gZHVyYXRpb247XG5cdFx0dGhpcy5ibGVuZE1vZGUgPSBibGVuZE1vZGU7XG5cblx0XHR0aGlzLnV1aWQgPSBnZW5lcmF0ZVVVSUQoKTtcblxuXHRcdC8vIHRoaXMgbWVhbnMgaXQgc2hvdWxkIGZpZ3VyZSBvdXQgaXRzIGR1cmF0aW9uIGJ5IHNjYW5uaW5nIHRoZSB0cmFja3Ncblx0XHRpZiAoIHRoaXMuZHVyYXRpb24gPCAwICkge1xuXG5cdFx0XHR0aGlzLnJlc2V0RHVyYXRpb24oKTtcblxuXHRcdH1cblxuXHR9XG5cblxuXHRzdGF0aWMgcGFyc2UoIGpzb24gKSB7XG5cblx0XHRjb25zdCB0cmFja3MgPSBbXSxcblx0XHRcdGpzb25UcmFja3MgPSBqc29uLnRyYWNrcyxcblx0XHRcdGZyYW1lVGltZSA9IDEuMCAvICgganNvbi5mcHMgfHwgMS4wICk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBqc29uVHJhY2tzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0dHJhY2tzLnB1c2goIHBhcnNlS2V5ZnJhbWVUcmFjaygganNvblRyYWNrc1sgaSBdICkuc2NhbGUoIGZyYW1lVGltZSApICk7XG5cblx0XHR9XG5cblx0XHRjb25zdCBjbGlwID0gbmV3IHRoaXMoIGpzb24ubmFtZSwganNvbi5kdXJhdGlvbiwgdHJhY2tzLCBqc29uLmJsZW5kTW9kZSApO1xuXHRcdGNsaXAudXVpZCA9IGpzb24udXVpZDtcblxuXHRcdHJldHVybiBjbGlwO1xuXG5cdH1cblxuXHRzdGF0aWMgdG9KU09OKCBjbGlwICkge1xuXG5cdFx0Y29uc3QgdHJhY2tzID0gW10sXG5cdFx0XHRjbGlwVHJhY2tzID0gY2xpcC50cmFja3M7XG5cblx0XHRjb25zdCBqc29uID0ge1xuXG5cdFx0XHQnbmFtZSc6IGNsaXAubmFtZSxcblx0XHRcdCdkdXJhdGlvbic6IGNsaXAuZHVyYXRpb24sXG5cdFx0XHQndHJhY2tzJzogdHJhY2tzLFxuXHRcdFx0J3V1aWQnOiBjbGlwLnV1aWQsXG5cdFx0XHQnYmxlbmRNb2RlJzogY2xpcC5ibGVuZE1vZGVcblxuXHRcdH07XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBjbGlwVHJhY2tzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0dHJhY2tzLnB1c2goIEtleWZyYW1lVHJhY2sudG9KU09OKCBjbGlwVHJhY2tzWyBpIF0gKSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGpzb247XG5cblx0fVxuXG5cdHN0YXRpYyBDcmVhdGVGcm9tTW9ycGhUYXJnZXRTZXF1ZW5jZSggbmFtZSwgbW9ycGhUYXJnZXRTZXF1ZW5jZSwgZnBzLCBub0xvb3AgKSB7XG5cblx0XHRjb25zdCBudW1Nb3JwaFRhcmdldHMgPSBtb3JwaFRhcmdldFNlcXVlbmNlLmxlbmd0aDtcblx0XHRjb25zdCB0cmFja3MgPSBbXTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG51bU1vcnBoVGFyZ2V0czsgaSArKyApIHtcblxuXHRcdFx0bGV0IHRpbWVzID0gW107XG5cdFx0XHRsZXQgdmFsdWVzID0gW107XG5cblx0XHRcdHRpbWVzLnB1c2goXG5cdFx0XHRcdCggaSArIG51bU1vcnBoVGFyZ2V0cyAtIDEgKSAlIG51bU1vcnBoVGFyZ2V0cyxcblx0XHRcdFx0aSxcblx0XHRcdFx0KCBpICsgMSApICUgbnVtTW9ycGhUYXJnZXRzICk7XG5cblx0XHRcdHZhbHVlcy5wdXNoKCAwLCAxLCAwICk7XG5cblx0XHRcdGNvbnN0IG9yZGVyID0gZ2V0S2V5ZnJhbWVPcmRlciggdGltZXMgKTtcblx0XHRcdHRpbWVzID0gc29ydGVkQXJyYXkoIHRpbWVzLCAxLCBvcmRlciApO1xuXHRcdFx0dmFsdWVzID0gc29ydGVkQXJyYXkoIHZhbHVlcywgMSwgb3JkZXIgKTtcblxuXHRcdFx0Ly8gaWYgdGhlcmUgaXMgYSBrZXkgYXQgdGhlIGZpcnN0IGZyYW1lLCBkdXBsaWNhdGUgaXQgYXMgdGhlXG5cdFx0XHQvLyBsYXN0IGZyYW1lIGFzIHdlbGwgZm9yIHBlcmZlY3QgbG9vcC5cblx0XHRcdGlmICggISBub0xvb3AgJiYgdGltZXNbIDAgXSA9PT0gMCApIHtcblxuXHRcdFx0XHR0aW1lcy5wdXNoKCBudW1Nb3JwaFRhcmdldHMgKTtcblx0XHRcdFx0dmFsdWVzLnB1c2goIHZhbHVlc1sgMCBdICk7XG5cblx0XHRcdH1cblxuXHRcdFx0dHJhY2tzLnB1c2goXG5cdFx0XHRcdG5ldyBOdW1iZXJLZXlmcmFtZVRyYWNrKFxuXHRcdFx0XHRcdCcubW9ycGhUYXJnZXRJbmZsdWVuY2VzWycgKyBtb3JwaFRhcmdldFNlcXVlbmNlWyBpIF0ubmFtZSArICddJyxcblx0XHRcdFx0XHR0aW1lcywgdmFsdWVzXG5cdFx0XHRcdCkuc2NhbGUoIDEuMCAvIGZwcyApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMoIG5hbWUsIC0gMSwgdHJhY2tzICk7XG5cblx0fVxuXG5cdHN0YXRpYyBmaW5kQnlOYW1lKCBvYmplY3RPckNsaXBBcnJheSwgbmFtZSApIHtcblxuXHRcdGxldCBjbGlwQXJyYXkgPSBvYmplY3RPckNsaXBBcnJheTtcblxuXHRcdGlmICggISBBcnJheS5pc0FycmF5KCBvYmplY3RPckNsaXBBcnJheSApICkge1xuXG5cdFx0XHRjb25zdCBvID0gb2JqZWN0T3JDbGlwQXJyYXk7XG5cdFx0XHRjbGlwQXJyYXkgPSBvLmdlb21ldHJ5ICYmIG8uZ2VvbWV0cnkuYW5pbWF0aW9ucyB8fCBvLmFuaW1hdGlvbnM7XG5cblx0XHR9XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjbGlwQXJyYXkubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRpZiAoIGNsaXBBcnJheVsgaSBdLm5hbWUgPT09IG5hbWUgKSB7XG5cblx0XHRcdFx0cmV0dXJuIGNsaXBBcnJheVsgaSBdO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gbnVsbDtcblxuXHR9XG5cblx0c3RhdGljIENyZWF0ZUNsaXBzRnJvbU1vcnBoVGFyZ2V0U2VxdWVuY2VzKCBtb3JwaFRhcmdldHMsIGZwcywgbm9Mb29wICkge1xuXG5cdFx0Y29uc3QgYW5pbWF0aW9uVG9Nb3JwaFRhcmdldHMgPSB7fTtcblxuXHRcdC8vIHRlc3RlZCB3aXRoIGh0dHBzOi8vcmVnZXgxMDEuY29tLyBvbiB0cmljayBzZXF1ZW5jZXNcblx0XHQvLyBzdWNoIGZsYW1pbmdvX2ZseUFfMDAzLCBmbGFtaW5nb19ydW4xXzAwMywgY3JkZWF0aDAwNTlcblx0XHRjb25zdCBwYXR0ZXJuID0gL14oW1xcdy1dKj8pKFtcXGRdKykkLztcblxuXHRcdC8vIHNvcnQgbW9ycGggdGFyZ2V0IG5hbWVzIGludG8gYW5pbWF0aW9uIGdyb3VwcyBiYXNlZFxuXHRcdC8vIHBhdHRlcm5zIGxpa2UgV2Fsa18wMDEsIFdhbGtfMDAyLCBSdW5fMDAxLCBSdW5fMDAyXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IG1vcnBoVGFyZ2V0cy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgbW9ycGhUYXJnZXQgPSBtb3JwaFRhcmdldHNbIGkgXTtcblx0XHRcdGNvbnN0IHBhcnRzID0gbW9ycGhUYXJnZXQubmFtZS5tYXRjaCggcGF0dGVybiApO1xuXG5cdFx0XHRpZiAoIHBhcnRzICYmIHBhcnRzLmxlbmd0aCA+IDEgKSB7XG5cblx0XHRcdFx0Y29uc3QgbmFtZSA9IHBhcnRzWyAxIF07XG5cblx0XHRcdFx0bGV0IGFuaW1hdGlvbk1vcnBoVGFyZ2V0cyA9IGFuaW1hdGlvblRvTW9ycGhUYXJnZXRzWyBuYW1lIF07XG5cblx0XHRcdFx0aWYgKCAhIGFuaW1hdGlvbk1vcnBoVGFyZ2V0cyApIHtcblxuXHRcdFx0XHRcdGFuaW1hdGlvblRvTW9ycGhUYXJnZXRzWyBuYW1lIF0gPSBhbmltYXRpb25Nb3JwaFRhcmdldHMgPSBbXTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0YW5pbWF0aW9uTW9ycGhUYXJnZXRzLnB1c2goIG1vcnBoVGFyZ2V0ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IGNsaXBzID0gW107XG5cblx0XHRmb3IgKCBjb25zdCBuYW1lIGluIGFuaW1hdGlvblRvTW9ycGhUYXJnZXRzICkge1xuXG5cdFx0XHRjbGlwcy5wdXNoKCB0aGlzLkNyZWF0ZUZyb21Nb3JwaFRhcmdldFNlcXVlbmNlKCBuYW1lLCBhbmltYXRpb25Ub01vcnBoVGFyZ2V0c1sgbmFtZSBdLCBmcHMsIG5vTG9vcCApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gY2xpcHM7XG5cblx0fVxuXG5cdC8vIHBhcnNlIHRoZSBhbmltYXRpb24uaGllcmFyY2h5IGZvcm1hdFxuXHRzdGF0aWMgcGFyc2VBbmltYXRpb24oIGFuaW1hdGlvbiwgYm9uZXMgKSB7XG5cblx0XHRpZiAoICEgYW5pbWF0aW9uICkge1xuXG5cdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuQW5pbWF0aW9uQ2xpcDogTm8gYW5pbWF0aW9uIGluIEpTT05Mb2FkZXIgZGF0YS4nICk7XG5cdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGFkZE5vbmVtcHR5VHJhY2sgPSBmdW5jdGlvbiAoIHRyYWNrVHlwZSwgdHJhY2tOYW1lLCBhbmltYXRpb25LZXlzLCBwcm9wZXJ0eU5hbWUsIGRlc3RUcmFja3MgKSB7XG5cblx0XHRcdC8vIG9ubHkgcmV0dXJuIHRyYWNrIGlmIHRoZXJlIGFyZSBhY3R1YWxseSBrZXlzLlxuXHRcdFx0aWYgKCBhbmltYXRpb25LZXlzLmxlbmd0aCAhPT0gMCApIHtcblxuXHRcdFx0XHRjb25zdCB0aW1lcyA9IFtdO1xuXHRcdFx0XHRjb25zdCB2YWx1ZXMgPSBbXTtcblxuXHRcdFx0XHRmbGF0dGVuSlNPTiggYW5pbWF0aW9uS2V5cywgdGltZXMsIHZhbHVlcywgcHJvcGVydHlOYW1lICk7XG5cblx0XHRcdFx0Ly8gZW1wdHkga2V5cyBhcmUgZmlsdGVyZWQgb3V0LCBzbyBjaGVjayBhZ2FpblxuXHRcdFx0XHRpZiAoIHRpbWVzLmxlbmd0aCAhPT0gMCApIHtcblxuXHRcdFx0XHRcdGRlc3RUcmFja3MucHVzaCggbmV3IHRyYWNrVHlwZSggdHJhY2tOYW1lLCB0aW1lcywgdmFsdWVzICkgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH07XG5cblx0XHRjb25zdCB0cmFja3MgPSBbXTtcblxuXHRcdGNvbnN0IGNsaXBOYW1lID0gYW5pbWF0aW9uLm5hbWUgfHwgJ2RlZmF1bHQnO1xuXHRcdGNvbnN0IGZwcyA9IGFuaW1hdGlvbi5mcHMgfHwgMzA7XG5cdFx0Y29uc3QgYmxlbmRNb2RlID0gYW5pbWF0aW9uLmJsZW5kTW9kZTtcblxuXHRcdC8vIGF1dG9tYXRpYyBsZW5ndGggZGV0ZXJtaW5hdGlvbiBpbiBBbmltYXRpb25DbGlwLlxuXHRcdGxldCBkdXJhdGlvbiA9IGFuaW1hdGlvbi5sZW5ndGggfHwgLSAxO1xuXG5cdFx0Y29uc3QgaGllcmFyY2h5VHJhY2tzID0gYW5pbWF0aW9uLmhpZXJhcmNoeSB8fCBbXTtcblxuXHRcdGZvciAoIGxldCBoID0gMDsgaCA8IGhpZXJhcmNoeVRyYWNrcy5sZW5ndGg7IGggKysgKSB7XG5cblx0XHRcdGNvbnN0IGFuaW1hdGlvbktleXMgPSBoaWVyYXJjaHlUcmFja3NbIGggXS5rZXlzO1xuXG5cdFx0XHQvLyBza2lwIGVtcHR5IHRyYWNrc1xuXHRcdFx0aWYgKCAhIGFuaW1hdGlvbktleXMgfHwgYW5pbWF0aW9uS2V5cy5sZW5ndGggPT09IDAgKSBjb250aW51ZTtcblxuXHRcdFx0Ly8gcHJvY2VzcyBtb3JwaCB0YXJnZXRzXG5cdFx0XHRpZiAoIGFuaW1hdGlvbktleXNbIDAgXS5tb3JwaFRhcmdldHMgKSB7XG5cblx0XHRcdFx0Ly8gZmlndXJlIG91dCBhbGwgbW9ycGggdGFyZ2V0cyB1c2VkIGluIHRoaXMgdHJhY2tcblx0XHRcdFx0Y29uc3QgbW9ycGhUYXJnZXROYW1lcyA9IHt9O1xuXG5cdFx0XHRcdGxldCBrO1xuXG5cdFx0XHRcdGZvciAoIGsgPSAwOyBrIDwgYW5pbWF0aW9uS2V5cy5sZW5ndGg7IGsgKysgKSB7XG5cblx0XHRcdFx0XHRpZiAoIGFuaW1hdGlvbktleXNbIGsgXS5tb3JwaFRhcmdldHMgKSB7XG5cblx0XHRcdFx0XHRcdGZvciAoIGxldCBtID0gMDsgbSA8IGFuaW1hdGlvbktleXNbIGsgXS5tb3JwaFRhcmdldHMubGVuZ3RoOyBtICsrICkge1xuXG5cdFx0XHRcdFx0XHRcdG1vcnBoVGFyZ2V0TmFtZXNbIGFuaW1hdGlvbktleXNbIGsgXS5tb3JwaFRhcmdldHNbIG0gXSBdID0gLSAxO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIGNyZWF0ZSBhIHRyYWNrIGZvciBlYWNoIG1vcnBoIHRhcmdldCB3aXRoIGFsbCB6ZXJvXG5cdFx0XHRcdC8vIG1vcnBoVGFyZ2V0SW5mbHVlbmNlcyBleGNlcHQgZm9yIHRoZSBrZXlzIGluIHdoaWNoXG5cdFx0XHRcdC8vIHRoZSBtb3JwaFRhcmdldCBpcyBuYW1lZC5cblx0XHRcdFx0Zm9yICggY29uc3QgbW9ycGhUYXJnZXROYW1lIGluIG1vcnBoVGFyZ2V0TmFtZXMgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB0aW1lcyA9IFtdO1xuXHRcdFx0XHRcdGNvbnN0IHZhbHVlcyA9IFtdO1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IG0gPSAwOyBtICE9PSBhbmltYXRpb25LZXlzWyBrIF0ubW9ycGhUYXJnZXRzLmxlbmd0aDsgKysgbSApIHtcblxuXHRcdFx0XHRcdFx0Y29uc3QgYW5pbWF0aW9uS2V5ID0gYW5pbWF0aW9uS2V5c1sgayBdO1xuXG5cdFx0XHRcdFx0XHR0aW1lcy5wdXNoKCBhbmltYXRpb25LZXkudGltZSApO1xuXHRcdFx0XHRcdFx0dmFsdWVzLnB1c2goICggYW5pbWF0aW9uS2V5Lm1vcnBoVGFyZ2V0ID09PSBtb3JwaFRhcmdldE5hbWUgKSA/IDEgOiAwICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR0cmFja3MucHVzaCggbmV3IE51bWJlcktleWZyYW1lVHJhY2soICcubW9ycGhUYXJnZXRJbmZsdWVuY2VbJyArIG1vcnBoVGFyZ2V0TmFtZSArICddJywgdGltZXMsIHZhbHVlcyApICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGR1cmF0aW9uID0gbW9ycGhUYXJnZXROYW1lcy5sZW5ndGggKiBmcHM7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Ly8gLi4uYXNzdW1lIHNrZWxldGFsIGFuaW1hdGlvblxuXG5cdFx0XHRcdGNvbnN0IGJvbmVOYW1lID0gJy5ib25lc1snICsgYm9uZXNbIGggXS5uYW1lICsgJ10nO1xuXG5cdFx0XHRcdGFkZE5vbmVtcHR5VHJhY2soXG5cdFx0XHRcdFx0VmVjdG9yS2V5ZnJhbWVUcmFjaywgYm9uZU5hbWUgKyAnLnBvc2l0aW9uJyxcblx0XHRcdFx0XHRhbmltYXRpb25LZXlzLCAncG9zJywgdHJhY2tzICk7XG5cblx0XHRcdFx0YWRkTm9uZW1wdHlUcmFjayhcblx0XHRcdFx0XHRRdWF0ZXJuaW9uS2V5ZnJhbWVUcmFjaywgYm9uZU5hbWUgKyAnLnF1YXRlcm5pb24nLFxuXHRcdFx0XHRcdGFuaW1hdGlvbktleXMsICdyb3QnLCB0cmFja3MgKTtcblxuXHRcdFx0XHRhZGROb25lbXB0eVRyYWNrKFxuXHRcdFx0XHRcdFZlY3RvcktleWZyYW1lVHJhY2ssIGJvbmVOYW1lICsgJy5zY2FsZScsXG5cdFx0XHRcdFx0YW5pbWF0aW9uS2V5cywgJ3NjbCcsIHRyYWNrcyApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRpZiAoIHRyYWNrcy5sZW5ndGggPT09IDAgKSB7XG5cblx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgY2xpcCA9IG5ldyB0aGlzKCBjbGlwTmFtZSwgZHVyYXRpb24sIHRyYWNrcywgYmxlbmRNb2RlICk7XG5cblx0XHRyZXR1cm4gY2xpcDtcblxuXHR9XG5cblx0cmVzZXREdXJhdGlvbigpIHtcblxuXHRcdGNvbnN0IHRyYWNrcyA9IHRoaXMudHJhY2tzO1xuXHRcdGxldCBkdXJhdGlvbiA9IDA7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSB0cmFja3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCB0cmFjayA9IHRoaXMudHJhY2tzWyBpIF07XG5cblx0XHRcdGR1cmF0aW9uID0gTWF0aC5tYXgoIGR1cmF0aW9uLCB0cmFjay50aW1lc1sgdHJhY2sudGltZXMubGVuZ3RoIC0gMSBdICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmR1cmF0aW9uID0gZHVyYXRpb247XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dHJpbSgpIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMudHJhY2tzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0dGhpcy50cmFja3NbIGkgXS50cmltKCAwLCB0aGlzLmR1cmF0aW9uICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dmFsaWRhdGUoKSB7XG5cblx0XHRsZXQgdmFsaWQgPSB0cnVlO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy50cmFja3MubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHR2YWxpZCA9IHZhbGlkICYmIHRoaXMudHJhY2tzWyBpIF0udmFsaWRhdGUoKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB2YWxpZDtcblxuXHR9XG5cblx0b3B0aW1pemUoKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLnRyYWNrcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMudHJhY2tzWyBpIF0ub3B0aW1pemUoKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdGNvbnN0IHRyYWNrcyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy50cmFja3MubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHR0cmFja3MucHVzaCggdGhpcy50cmFja3NbIGkgXS5jbG9uZSgpICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoIHRoaXMubmFtZSwgdGhpcy5kdXJhdGlvbiwgdHJhY2tzLCB0aGlzLmJsZW5kTW9kZSApO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5jb25zdHJ1Y3Rvci50b0pTT04oIHRoaXMgKTtcblxuXHR9XG5cbn1cblxuZnVuY3Rpb24gZ2V0VHJhY2tUeXBlRm9yVmFsdWVUeXBlTmFtZSggdHlwZU5hbWUgKSB7XG5cblx0c3dpdGNoICggdHlwZU5hbWUudG9Mb3dlckNhc2UoKSApIHtcblxuXHRcdGNhc2UgJ3NjYWxhcic6XG5cdFx0Y2FzZSAnZG91YmxlJzpcblx0XHRjYXNlICdmbG9hdCc6XG5cdFx0Y2FzZSAnbnVtYmVyJzpcblx0XHRjYXNlICdpbnRlZ2VyJzpcblxuXHRcdFx0cmV0dXJuIE51bWJlcktleWZyYW1lVHJhY2s7XG5cblx0XHRjYXNlICd2ZWN0b3InOlxuXHRcdGNhc2UgJ3ZlY3RvcjInOlxuXHRcdGNhc2UgJ3ZlY3RvcjMnOlxuXHRcdGNhc2UgJ3ZlY3RvcjQnOlxuXG5cdFx0XHRyZXR1cm4gVmVjdG9yS2V5ZnJhbWVUcmFjaztcblxuXHRcdGNhc2UgJ2NvbG9yJzpcblxuXHRcdFx0cmV0dXJuIENvbG9yS2V5ZnJhbWVUcmFjaztcblxuXHRcdGNhc2UgJ3F1YXRlcm5pb24nOlxuXG5cdFx0XHRyZXR1cm4gUXVhdGVybmlvbktleWZyYW1lVHJhY2s7XG5cblx0XHRjYXNlICdib29sJzpcblx0XHRjYXNlICdib29sZWFuJzpcblxuXHRcdFx0cmV0dXJuIEJvb2xlYW5LZXlmcmFtZVRyYWNrO1xuXG5cdFx0Y2FzZSAnc3RyaW5nJzpcblxuXHRcdFx0cmV0dXJuIFN0cmluZ0tleWZyYW1lVHJhY2s7XG5cblx0fVxuXG5cdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IFVuc3VwcG9ydGVkIHR5cGVOYW1lOiAnICsgdHlwZU5hbWUgKTtcblxufVxuXG5mdW5jdGlvbiBwYXJzZUtleWZyYW1lVHJhY2soIGpzb24gKSB7XG5cblx0aWYgKCBqc29uLnR5cGUgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdHRocm93IG5ldyBFcnJvciggJ1RIUkVFLktleWZyYW1lVHJhY2s6IHRyYWNrIHR5cGUgdW5kZWZpbmVkLCBjYW4gbm90IHBhcnNlJyApO1xuXG5cdH1cblxuXHRjb25zdCB0cmFja1R5cGUgPSBnZXRUcmFja1R5cGVGb3JWYWx1ZVR5cGVOYW1lKCBqc29uLnR5cGUgKTtcblxuXHRpZiAoIGpzb24udGltZXMgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdGNvbnN0IHRpbWVzID0gW10sIHZhbHVlcyA9IFtdO1xuXG5cdFx0ZmxhdHRlbkpTT04oIGpzb24ua2V5cywgdGltZXMsIHZhbHVlcywgJ3ZhbHVlJyApO1xuXG5cdFx0anNvbi50aW1lcyA9IHRpbWVzO1xuXHRcdGpzb24udmFsdWVzID0gdmFsdWVzO1xuXG5cdH1cblxuXHQvLyBkZXJpdmVkIGNsYXNzZXMgY2FuIGRlZmluZSBhIHN0YXRpYyBwYXJzZSBtZXRob2Rcblx0aWYgKCB0cmFja1R5cGUucGFyc2UgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdHJldHVybiB0cmFja1R5cGUucGFyc2UoIGpzb24gKTtcblxuXHR9IGVsc2Uge1xuXG5cdFx0Ly8gYnkgZGVmYXVsdCwgd2UgYXNzdW1lIGEgY29uc3RydWN0b3IgY29tcGF0aWJsZSB3aXRoIHRoZSBiYXNlXG5cdFx0cmV0dXJuIG5ldyB0cmFja1R5cGUoIGpzb24ubmFtZSwganNvbi50aW1lcywganNvbi52YWx1ZXMsIGpzb24uaW50ZXJwb2xhdGlvbiApO1xuXG5cdH1cblxufVxuXG5jb25zdCBDYWNoZSA9IHtcblxuXHRlbmFibGVkOiBmYWxzZSxcblxuXHRmaWxlczoge30sXG5cblx0YWRkOiBmdW5jdGlvbiAoIGtleSwgZmlsZSApIHtcblxuXHRcdGlmICggdGhpcy5lbmFibGVkID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdC8vIGNvbnNvbGUubG9nKCAnVEhSRUUuQ2FjaGUnLCAnQWRkaW5nIGtleTonLCBrZXkgKTtcblxuXHRcdHRoaXMuZmlsZXNbIGtleSBdID0gZmlsZTtcblxuXHR9LFxuXG5cdGdldDogZnVuY3Rpb24gKCBrZXkgKSB7XG5cblx0XHRpZiAoIHRoaXMuZW5hYmxlZCA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHQvLyBjb25zb2xlLmxvZyggJ1RIUkVFLkNhY2hlJywgJ0NoZWNraW5nIGtleTonLCBrZXkgKTtcblxuXHRcdHJldHVybiB0aGlzLmZpbGVzWyBrZXkgXTtcblxuXHR9LFxuXG5cdHJlbW92ZTogZnVuY3Rpb24gKCBrZXkgKSB7XG5cblx0XHRkZWxldGUgdGhpcy5maWxlc1sga2V5IF07XG5cblx0fSxcblxuXHRjbGVhcjogZnVuY3Rpb24gKCkge1xuXG5cdFx0dGhpcy5maWxlcyA9IHt9O1xuXG5cdH1cblxufTtcblxuY2xhc3MgTG9hZGluZ01hbmFnZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRsZXQgaXNMb2FkaW5nID0gZmFsc2U7XG5cdFx0bGV0IGl0ZW1zTG9hZGVkID0gMDtcblx0XHRsZXQgaXRlbXNUb3RhbCA9IDA7XG5cdFx0bGV0IHVybE1vZGlmaWVyID0gdW5kZWZpbmVkO1xuXHRcdGNvbnN0IGhhbmRsZXJzID0gW107XG5cblx0XHQvLyBSZWZlciB0byAjNTY4OSBmb3IgdGhlIHJlYXNvbiB3aHkgd2UgZG9uJ3Qgc2V0IC5vblN0YXJ0XG5cdFx0Ly8gaW4gdGhlIGNvbnN0cnVjdG9yXG5cblx0XHR0aGlzLm9uU3RhcnQgPSB1bmRlZmluZWQ7XG5cdFx0dGhpcy5vbkxvYWQgPSBvbkxvYWQ7XG5cdFx0dGhpcy5vblByb2dyZXNzID0gb25Qcm9ncmVzcztcblx0XHR0aGlzLm9uRXJyb3IgPSBvbkVycm9yO1xuXG5cdFx0dGhpcy5pdGVtU3RhcnQgPSBmdW5jdGlvbiAoIHVybCApIHtcblxuXHRcdFx0aXRlbXNUb3RhbCArKztcblxuXHRcdFx0aWYgKCBpc0xvYWRpbmcgPT09IGZhbHNlICkge1xuXG5cdFx0XHRcdGlmICggc2NvcGUub25TdGFydCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0c2NvcGUub25TdGFydCggdXJsLCBpdGVtc0xvYWRlZCwgaXRlbXNUb3RhbCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpc0xvYWRpbmcgPSB0cnVlO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuaXRlbUVuZCA9IGZ1bmN0aW9uICggdXJsICkge1xuXG5cdFx0XHRpdGVtc0xvYWRlZCArKztcblxuXHRcdFx0aWYgKCBzY29wZS5vblByb2dyZXNzICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0c2NvcGUub25Qcm9ncmVzcyggdXJsLCBpdGVtc0xvYWRlZCwgaXRlbXNUb3RhbCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggaXRlbXNMb2FkZWQgPT09IGl0ZW1zVG90YWwgKSB7XG5cblx0XHRcdFx0aXNMb2FkaW5nID0gZmFsc2U7XG5cblx0XHRcdFx0aWYgKCBzY29wZS5vbkxvYWQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdHNjb3BlLm9uTG9hZCgpO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHRcdHRoaXMuaXRlbUVycm9yID0gZnVuY3Rpb24gKCB1cmwgKSB7XG5cblx0XHRcdGlmICggc2NvcGUub25FcnJvciAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHNjb3BlLm9uRXJyb3IoIHVybCApO1xuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5yZXNvbHZlVVJMID0gZnVuY3Rpb24gKCB1cmwgKSB7XG5cblx0XHRcdGlmICggdXJsTW9kaWZpZXIgKSB7XG5cblx0XHRcdFx0cmV0dXJuIHVybE1vZGlmaWVyKCB1cmwgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gdXJsO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2V0VVJMTW9kaWZpZXIgPSBmdW5jdGlvbiAoIHRyYW5zZm9ybSApIHtcblxuXHRcdFx0dXJsTW9kaWZpZXIgPSB0cmFuc2Zvcm07XG5cblx0XHRcdHJldHVybiB0aGlzO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuYWRkSGFuZGxlciA9IGZ1bmN0aW9uICggcmVnZXgsIGxvYWRlciApIHtcblxuXHRcdFx0aGFuZGxlcnMucHVzaCggcmVnZXgsIGxvYWRlciApO1xuXG5cdFx0XHRyZXR1cm4gdGhpcztcblxuXHRcdH07XG5cblx0XHR0aGlzLnJlbW92ZUhhbmRsZXIgPSBmdW5jdGlvbiAoIHJlZ2V4ICkge1xuXG5cdFx0XHRjb25zdCBpbmRleCA9IGhhbmRsZXJzLmluZGV4T2YoIHJlZ2V4ICk7XG5cblx0XHRcdGlmICggaW5kZXggIT09IC0gMSApIHtcblxuXHRcdFx0XHRoYW5kbGVycy5zcGxpY2UoIGluZGV4LCAyICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHRoaXM7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRIYW5kbGVyID0gZnVuY3Rpb24gKCBmaWxlICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBoYW5kbGVycy5sZW5ndGg7IGkgPCBsOyBpICs9IDIgKSB7XG5cblx0XHRcdFx0Y29uc3QgcmVnZXggPSBoYW5kbGVyc1sgaSBdO1xuXHRcdFx0XHRjb25zdCBsb2FkZXIgPSBoYW5kbGVyc1sgaSArIDEgXTtcblxuXHRcdFx0XHRpZiAoIHJlZ2V4Lmdsb2JhbCApIHJlZ2V4Lmxhc3RJbmRleCA9IDA7IC8vIHNlZSAjMTc5MjBcblxuXHRcdFx0XHRpZiAoIHJlZ2V4LnRlc3QoIGZpbGUgKSApIHtcblxuXHRcdFx0XHRcdHJldHVybiBsb2FkZXI7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0fTtcblxuXHR9XG5cbn1cblxuY29uc3QgRGVmYXVsdExvYWRpbmdNYW5hZ2VyID0gLypAX19QVVJFX18qLyBuZXcgTG9hZGluZ01hbmFnZXIoKTtcblxuY2xhc3MgTG9hZGVyIHtcblxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcblxuXHRcdHRoaXMubWFuYWdlciA9ICggbWFuYWdlciAhPT0gdW5kZWZpbmVkICkgPyBtYW5hZ2VyIDogRGVmYXVsdExvYWRpbmdNYW5hZ2VyO1xuXG5cdFx0dGhpcy5jcm9zc09yaWdpbiA9ICdhbm9ueW1vdXMnO1xuXHRcdHRoaXMud2l0aENyZWRlbnRpYWxzID0gZmFsc2U7XG5cdFx0dGhpcy5wYXRoID0gJyc7XG5cdFx0dGhpcy5yZXNvdXJjZVBhdGggPSAnJztcblx0XHR0aGlzLnJlcXVlc3RIZWFkZXIgPSB7fTtcblxuXHR9XG5cblx0bG9hZCggLyogdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKi8gKSB7fVxuXG5cdGxvYWRBc3luYyggdXJsLCBvblByb2dyZXNzICkge1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0cmV0dXJuIG5ldyBQcm9taXNlKCBmdW5jdGlvbiAoIHJlc29sdmUsIHJlamVjdCApIHtcblxuXHRcdFx0c2NvcGUubG9hZCggdXJsLCByZXNvbHZlLCBvblByb2dyZXNzLCByZWplY3QgKTtcblxuXHRcdH0gKTtcblxuXHR9XG5cblx0cGFyc2UoIC8qIGRhdGEgKi8gKSB7fVxuXG5cdHNldENyb3NzT3JpZ2luKCBjcm9zc09yaWdpbiApIHtcblxuXHRcdHRoaXMuY3Jvc3NPcmlnaW4gPSBjcm9zc09yaWdpbjtcblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0V2l0aENyZWRlbnRpYWxzKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMud2l0aENyZWRlbnRpYWxzID0gdmFsdWU7XG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFBhdGgoIHBhdGggKSB7XG5cblx0XHR0aGlzLnBhdGggPSBwYXRoO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRSZXNvdXJjZVBhdGgoIHJlc291cmNlUGF0aCApIHtcblxuXHRcdHRoaXMucmVzb3VyY2VQYXRoID0gcmVzb3VyY2VQYXRoO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRSZXF1ZXN0SGVhZGVyKCByZXF1ZXN0SGVhZGVyICkge1xuXG5cdFx0dGhpcy5yZXF1ZXN0SGVhZGVyID0gcmVxdWVzdEhlYWRlcjtcblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuTG9hZGVyLkRFRkFVTFRfTUFURVJJQUxfTkFNRSA9ICdfX0RFRkFVTFQnO1xuXG5jb25zdCBsb2FkaW5nID0ge307XG5cbmNsYXNzIEh0dHBFcnJvciBleHRlbmRzIEVycm9yIHtcblxuXHRjb25zdHJ1Y3RvciggbWVzc2FnZSwgcmVzcG9uc2UgKSB7XG5cblx0XHRzdXBlciggbWVzc2FnZSApO1xuXHRcdHRoaXMucmVzcG9uc2UgPSByZXNwb25zZTtcblxuXHR9XG5cbn1cblxuY2xhc3MgRmlsZUxvYWRlciBleHRlbmRzIExvYWRlciB7XG5cblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XG5cblx0XHRzdXBlciggbWFuYWdlciApO1xuXG5cdH1cblxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcblxuXHRcdGlmICggdXJsID09PSB1bmRlZmluZWQgKSB1cmwgPSAnJztcblxuXHRcdGlmICggdGhpcy5wYXRoICE9PSB1bmRlZmluZWQgKSB1cmwgPSB0aGlzLnBhdGggKyB1cmw7XG5cblx0XHR1cmwgPSB0aGlzLm1hbmFnZXIucmVzb2x2ZVVSTCggdXJsICk7XG5cblx0XHRjb25zdCBjYWNoZWQgPSBDYWNoZS5nZXQoIHVybCApO1xuXG5cdFx0aWYgKCBjYWNoZWQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGhpcy5tYW5hZ2VyLml0ZW1TdGFydCggdXJsICk7XG5cblx0XHRcdHNldFRpbWVvdXQoICgpID0+IHtcblxuXHRcdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggY2FjaGVkICk7XG5cblx0XHRcdFx0dGhpcy5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xuXG5cdFx0XHR9LCAwICk7XG5cblx0XHRcdHJldHVybiBjYWNoZWQ7XG5cblx0XHR9XG5cblx0XHQvLyBDaGVjayBpZiByZXF1ZXN0IGlzIGR1cGxpY2F0ZVxuXG5cdFx0aWYgKCBsb2FkaW5nWyB1cmwgXSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRsb2FkaW5nWyB1cmwgXS5wdXNoKCB7XG5cblx0XHRcdFx0b25Mb2FkOiBvbkxvYWQsXG5cdFx0XHRcdG9uUHJvZ3Jlc3M6IG9uUHJvZ3Jlc3MsXG5cdFx0XHRcdG9uRXJyb3I6IG9uRXJyb3JcblxuXHRcdFx0fSApO1xuXG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHQvLyBJbml0aWFsaXNlIGFycmF5IGZvciBkdXBsaWNhdGUgcmVxdWVzdHNcblx0XHRsb2FkaW5nWyB1cmwgXSA9IFtdO1xuXG5cdFx0bG9hZGluZ1sgdXJsIF0ucHVzaCgge1xuXHRcdFx0b25Mb2FkOiBvbkxvYWQsXG5cdFx0XHRvblByb2dyZXNzOiBvblByb2dyZXNzLFxuXHRcdFx0b25FcnJvcjogb25FcnJvcixcblx0XHR9ICk7XG5cblx0XHQvLyBjcmVhdGUgcmVxdWVzdFxuXHRcdGNvbnN0IHJlcSA9IG5ldyBSZXF1ZXN0KCB1cmwsIHtcblx0XHRcdGhlYWRlcnM6IG5ldyBIZWFkZXJzKCB0aGlzLnJlcXVlc3RIZWFkZXIgKSxcblx0XHRcdGNyZWRlbnRpYWxzOiB0aGlzLndpdGhDcmVkZW50aWFscyA/ICdpbmNsdWRlJyA6ICdzYW1lLW9yaWdpbicsXG5cdFx0XHQvLyBBbiBhYm9ydCBjb250cm9sbGVyIGNvdWxkIGJlIGFkZGVkIHdpdGhpbiBhIGZ1dHVyZSBQUlxuXHRcdH0gKTtcblxuXHRcdC8vIHJlY29yZCBzdGF0ZXMgKCBhdm9pZCBkYXRhIHJhY2UgKVxuXHRcdGNvbnN0IG1pbWVUeXBlID0gdGhpcy5taW1lVHlwZTtcblx0XHRjb25zdCByZXNwb25zZVR5cGUgPSB0aGlzLnJlc3BvbnNlVHlwZTtcblxuXHRcdC8vIHN0YXJ0IHRoZSBmZXRjaFxuXHRcdGZldGNoKCByZXEgKVxuXHRcdFx0LnRoZW4oIHJlc3BvbnNlID0+IHtcblxuXHRcdFx0XHRpZiAoIHJlc3BvbnNlLnN0YXR1cyA9PT0gMjAwIHx8IHJlc3BvbnNlLnN0YXR1cyA9PT0gMCApIHtcblxuXHRcdFx0XHRcdC8vIFNvbWUgYnJvd3NlcnMgcmV0dXJuIEhUVFAgU3RhdHVzIDAgd2hlbiB1c2luZyBub24taHR0cCBwcm90b2NvbFxuXHRcdFx0XHRcdC8vIGUuZy4gJ2ZpbGU6Ly8nIG9yICdkYXRhOi8vJy4gSGFuZGxlIGFzIHN1Y2Nlc3MuXG5cblx0XHRcdFx0XHRpZiAoIHJlc3BvbnNlLnN0YXR1cyA9PT0gMCApIHtcblxuXHRcdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuRmlsZUxvYWRlcjogSFRUUCBTdGF0dXMgMCByZWNlaXZlZC4nICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHQvLyBXb3JrYXJvdW5kOiBDaGVja2luZyBpZiByZXNwb25zZS5ib2R5ID09PSB1bmRlZmluZWQgZm9yIEFsaXBheSBicm93c2VyICMyMzU0OFxuXG5cdFx0XHRcdFx0aWYgKCB0eXBlb2YgUmVhZGFibGVTdHJlYW0gPT09ICd1bmRlZmluZWQnIHx8IHJlc3BvbnNlLmJvZHkgPT09IHVuZGVmaW5lZCB8fCByZXNwb25zZS5ib2R5LmdldFJlYWRlciA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRyZXR1cm4gcmVzcG9uc2U7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRjb25zdCBjYWxsYmFja3MgPSBsb2FkaW5nWyB1cmwgXTtcblx0XHRcdFx0XHRjb25zdCByZWFkZXIgPSByZXNwb25zZS5ib2R5LmdldFJlYWRlcigpO1xuXG5cdFx0XHRcdFx0Ly8gTmdpbnggbmVlZHMgWC1GaWxlLVNpemUgY2hlY2tcblx0XHRcdFx0XHQvLyBodHRwczovL3NlcnZlcmZhdWx0LmNvbS9xdWVzdGlvbnMvNDgyODc1L3doeS1kb2VzLW5naW54LXJlbW92ZS1jb250ZW50LWxlbmd0aC1oZWFkZXItZm9yLWNodW5rZWQtY29udGVudFxuXHRcdFx0XHRcdGNvbnN0IGNvbnRlbnRMZW5ndGggPSByZXNwb25zZS5oZWFkZXJzLmdldCggJ1gtRmlsZS1TaXplJyApIHx8IHJlc3BvbnNlLmhlYWRlcnMuZ2V0KCAnQ29udGVudC1MZW5ndGgnICk7XG5cdFx0XHRcdFx0Y29uc3QgdG90YWwgPSBjb250ZW50TGVuZ3RoID8gcGFyc2VJbnQoIGNvbnRlbnRMZW5ndGggKSA6IDA7XG5cdFx0XHRcdFx0Y29uc3QgbGVuZ3RoQ29tcHV0YWJsZSA9IHRvdGFsICE9PSAwO1xuXHRcdFx0XHRcdGxldCBsb2FkZWQgPSAwO1xuXG5cdFx0XHRcdFx0Ly8gcGVyaW9kaWNhbGx5IHJlYWQgZGF0YSBpbnRvIHRoZSBuZXcgc3RyZWFtIHRyYWNraW5nIHdoaWxlIGRvd25sb2FkIHByb2dyZXNzXG5cdFx0XHRcdFx0Y29uc3Qgc3RyZWFtID0gbmV3IFJlYWRhYmxlU3RyZWFtKCB7XG5cdFx0XHRcdFx0XHRzdGFydCggY29udHJvbGxlciApIHtcblxuXHRcdFx0XHRcdFx0XHRyZWFkRGF0YSgpO1xuXG5cdFx0XHRcdFx0XHRcdGZ1bmN0aW9uIHJlYWREYXRhKCkge1xuXG5cdFx0XHRcdFx0XHRcdFx0cmVhZGVyLnJlYWQoKS50aGVuKCAoIHsgZG9uZSwgdmFsdWUgfSApID0+IHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0aWYgKCBkb25lICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdGNvbnRyb2xsZXIuY2xvc2UoKTtcblxuXHRcdFx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHRsb2FkZWQgKz0gdmFsdWUuYnl0ZUxlbmd0aDtcblxuXHRcdFx0XHRcdFx0XHRcdFx0XHRjb25zdCBldmVudCA9IG5ldyBQcm9ncmVzc0V2ZW50KCAncHJvZ3Jlc3MnLCB7IGxlbmd0aENvbXB1dGFibGUsIGxvYWRlZCwgdG90YWwgfSApO1xuXHRcdFx0XHRcdFx0XHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gY2FsbGJhY2tzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdFx0Y29uc3QgY2FsbGJhY2sgPSBjYWxsYmFja3NbIGkgXTtcblx0XHRcdFx0XHRcdFx0XHRcdFx0XHRpZiAoIGNhbGxiYWNrLm9uUHJvZ3Jlc3MgKSBjYWxsYmFjay5vblByb2dyZXNzKCBldmVudCApO1xuXG5cdFx0XHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRcdFx0XHRjb250cm9sbGVyLmVucXVldWUoIHZhbHVlICk7XG5cdFx0XHRcdFx0XHRcdFx0XHRcdHJlYWREYXRhKCk7XG5cblx0XHRcdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0XHRcdH0sICggZSApID0+IHtcblxuXHRcdFx0XHRcdFx0XHRcdFx0Y29udHJvbGxlci5lcnJvciggZSApO1xuXG5cdFx0XHRcdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdFx0cmV0dXJuIG5ldyBSZXNwb25zZSggc3RyZWFtICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHRocm93IG5ldyBIdHRwRXJyb3IoIGBmZXRjaCBmb3IgXCIke3Jlc3BvbnNlLnVybH1cIiByZXNwb25kZWQgd2l0aCAke3Jlc3BvbnNlLnN0YXR1c306ICR7cmVzcG9uc2Uuc3RhdHVzVGV4dH1gLCByZXNwb25zZSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSApXG5cdFx0XHQudGhlbiggcmVzcG9uc2UgPT4ge1xuXG5cdFx0XHRcdHN3aXRjaCAoIHJlc3BvbnNlVHlwZSApIHtcblxuXHRcdFx0XHRcdGNhc2UgJ2FycmF5YnVmZmVyJzpcblxuXHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlLmFycmF5QnVmZmVyKCk7XG5cblx0XHRcdFx0XHRjYXNlICdibG9iJzpcblxuXHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlLmJsb2IoKTtcblxuXHRcdFx0XHRcdGNhc2UgJ2RvY3VtZW50JzpcblxuXHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlLnRleHQoKVxuXHRcdFx0XHRcdFx0XHQudGhlbiggdGV4dCA9PiB7XG5cblx0XHRcdFx0XHRcdFx0XHRjb25zdCBwYXJzZXIgPSBuZXcgRE9NUGFyc2VyKCk7XG5cdFx0XHRcdFx0XHRcdFx0cmV0dXJuIHBhcnNlci5wYXJzZUZyb21TdHJpbmcoIHRleHQsIG1pbWVUeXBlICk7XG5cblx0XHRcdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdFx0Y2FzZSAnanNvbic6XG5cblx0XHRcdFx0XHRcdHJldHVybiByZXNwb25zZS5qc29uKCk7XG5cblx0XHRcdFx0XHRkZWZhdWx0OlxuXG5cdFx0XHRcdFx0XHRpZiAoIG1pbWVUeXBlID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRcdFx0cmV0dXJuIHJlc3BvbnNlLnRleHQoKTtcblxuXHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHQvLyBzbmlmZiBlbmNvZGluZ1xuXHRcdFx0XHRcdFx0XHRjb25zdCByZSA9IC9jaGFyc2V0PVwiPyhbXjtcIlxcc10qKVwiPy9pO1xuXHRcdFx0XHRcdFx0XHRjb25zdCBleGVjID0gcmUuZXhlYyggbWltZVR5cGUgKTtcblx0XHRcdFx0XHRcdFx0Y29uc3QgbGFiZWwgPSBleGVjICYmIGV4ZWNbIDEgXSA/IGV4ZWNbIDEgXS50b0xvd2VyQ2FzZSgpIDogdW5kZWZpbmVkO1xuXHRcdFx0XHRcdFx0XHRjb25zdCBkZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKCBsYWJlbCApO1xuXHRcdFx0XHRcdFx0XHRyZXR1cm4gcmVzcG9uc2UuYXJyYXlCdWZmZXIoKS50aGVuKCBhYiA9PiBkZWNvZGVyLmRlY29kZSggYWIgKSApO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9IClcblx0XHRcdC50aGVuKCBkYXRhID0+IHtcblxuXHRcdFx0XHQvLyBBZGQgdG8gY2FjaGUgb25seSBvbiBIVFRQIHN1Y2Nlc3MsIHNvIHRoYXQgd2UgZG8gbm90IGNhY2hlXG5cdFx0XHRcdC8vIGVycm9yIHJlc3BvbnNlIGJvZGllcyBhcyBwcm9wZXIgcmVzcG9uc2VzIHRvIHJlcXVlc3RzLlxuXHRcdFx0XHRDYWNoZS5hZGQoIHVybCwgZGF0YSApO1xuXG5cdFx0XHRcdGNvbnN0IGNhbGxiYWNrcyA9IGxvYWRpbmdbIHVybCBdO1xuXHRcdFx0XHRkZWxldGUgbG9hZGluZ1sgdXJsIF07XG5cblx0XHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGNhbGxiYWNrcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGNhbGxiYWNrID0gY2FsbGJhY2tzWyBpIF07XG5cdFx0XHRcdFx0aWYgKCBjYWxsYmFjay5vbkxvYWQgKSBjYWxsYmFjay5vbkxvYWQoIGRhdGEgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gKVxuXHRcdFx0LmNhdGNoKCBlcnIgPT4ge1xuXG5cdFx0XHRcdC8vIEFib3J0IGVycm9ycyBhbmQgb3RoZXIgZXJyb3JzIGFyZSBoYW5kbGVkIHRoZSBzYW1lXG5cblx0XHRcdFx0Y29uc3QgY2FsbGJhY2tzID0gbG9hZGluZ1sgdXJsIF07XG5cblx0XHRcdFx0aWYgKCBjYWxsYmFja3MgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdC8vIFdoZW4gb25Mb2FkIHdhcyBjYWxsZWQgYW5kIHVybCB3YXMgZGVsZXRlZCBpbiBgbG9hZGluZ2Bcblx0XHRcdFx0XHR0aGlzLm1hbmFnZXIuaXRlbUVycm9yKCB1cmwgKTtcblx0XHRcdFx0XHR0aHJvdyBlcnI7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGRlbGV0ZSBsb2FkaW5nWyB1cmwgXTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gY2FsbGJhY2tzLmxlbmd0aDsgaSA8IGlsOyBpICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgY2FsbGJhY2sgPSBjYWxsYmFja3NbIGkgXTtcblx0XHRcdFx0XHRpZiAoIGNhbGxiYWNrLm9uRXJyb3IgKSBjYWxsYmFjay5vbkVycm9yKCBlcnIgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0dGhpcy5tYW5hZ2VyLml0ZW1FcnJvciggdXJsICk7XG5cblx0XHRcdH0gKVxuXHRcdFx0LmZpbmFsbHkoICgpID0+IHtcblxuXHRcdFx0XHR0aGlzLm1hbmFnZXIuaXRlbUVuZCggdXJsICk7XG5cblx0XHRcdH0gKTtcblxuXHRcdHRoaXMubWFuYWdlci5pdGVtU3RhcnQoIHVybCApO1xuXG5cdH1cblxuXHRzZXRSZXNwb25zZVR5cGUoIHZhbHVlICkge1xuXG5cdFx0dGhpcy5yZXNwb25zZVR5cGUgPSB2YWx1ZTtcblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0TWltZVR5cGUoIHZhbHVlICkge1xuXG5cdFx0dGhpcy5taW1lVHlwZSA9IHZhbHVlO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBBbmltYXRpb25Mb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xuXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcblxuXHR9XG5cblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XG5cdFx0bG9hZGVyLnNldFBhdGgoIHRoaXMucGF0aCApO1xuXHRcdGxvYWRlci5zZXRSZXF1ZXN0SGVhZGVyKCB0aGlzLnJlcXVlc3RIZWFkZXIgKTtcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCB0aGlzLndpdGhDcmVkZW50aWFscyApO1xuXHRcdGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICggdGV4dCApIHtcblxuXHRcdFx0dHJ5IHtcblxuXHRcdFx0XHRvbkxvYWQoIHNjb3BlLnBhcnNlKCBKU09OLnBhcnNlKCB0ZXh0ICkgKSApO1xuXG5cdFx0XHR9IGNhdGNoICggZSApIHtcblxuXHRcdFx0XHRpZiAoIG9uRXJyb3IgKSB7XG5cblx0XHRcdFx0XHRvbkVycm9yKCBlICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoIGUgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xuXG5cdFx0XHR9XG5cblx0XHR9LCBvblByb2dyZXNzLCBvbkVycm9yICk7XG5cblx0fVxuXG5cdHBhcnNlKCBqc29uICkge1xuXG5cdFx0Y29uc3QgYW5pbWF0aW9ucyA9IFtdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwganNvbi5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGNsaXAgPSBBbmltYXRpb25DbGlwLnBhcnNlKCBqc29uWyBpIF0gKTtcblxuXHRcdFx0YW5pbWF0aW9ucy5wdXNoKCBjbGlwICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gYW5pbWF0aW9ucztcblxuXHR9XG5cbn1cblxuLyoqXG4gKiBBYnN0cmFjdCBCYXNlIGNsYXNzIHRvIGJsb2NrIGJhc2VkIHRleHR1cmVzIGxvYWRlciAoZGRzLCBwdnIsIC4uLilcbiAqXG4gKiBTdWIgY2xhc3NlcyBoYXZlIHRvIGltcGxlbWVudCB0aGUgcGFyc2UoKSBtZXRob2Qgd2hpY2ggd2lsbCBiZSB1c2VkIGluIGxvYWQoKS5cbiAqL1xuXG5jbGFzcyBDb21wcmVzc2VkVGV4dHVyZUxvYWRlciBleHRlbmRzIExvYWRlciB7XG5cblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XG5cblx0XHRzdXBlciggbWFuYWdlciApO1xuXG5cdH1cblxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdGNvbnN0IGltYWdlcyA9IFtdO1xuXG5cdFx0Y29uc3QgdGV4dHVyZSA9IG5ldyBDb21wcmVzc2VkVGV4dHVyZSgpO1xuXG5cdFx0Y29uc3QgbG9hZGVyID0gbmV3IEZpbGVMb2FkZXIoIHRoaXMubWFuYWdlciApO1xuXHRcdGxvYWRlci5zZXRQYXRoKCB0aGlzLnBhdGggKTtcblx0XHRsb2FkZXIuc2V0UmVzcG9uc2VUeXBlKCAnYXJyYXlidWZmZXInICk7XG5cdFx0bG9hZGVyLnNldFJlcXVlc3RIZWFkZXIoIHRoaXMucmVxdWVzdEhlYWRlciApO1xuXHRcdGxvYWRlci5zZXRXaXRoQ3JlZGVudGlhbHMoIHNjb3BlLndpdGhDcmVkZW50aWFscyApO1xuXG5cdFx0bGV0IGxvYWRlZCA9IDA7XG5cblx0XHRmdW5jdGlvbiBsb2FkVGV4dHVyZSggaSApIHtcblxuXHRcdFx0bG9hZGVyLmxvYWQoIHVybFsgaSBdLCBmdW5jdGlvbiAoIGJ1ZmZlciApIHtcblxuXHRcdFx0XHRjb25zdCB0ZXhEYXRhcyA9IHNjb3BlLnBhcnNlKCBidWZmZXIsIHRydWUgKTtcblxuXHRcdFx0XHRpbWFnZXNbIGkgXSA9IHtcblx0XHRcdFx0XHR3aWR0aDogdGV4RGF0YXMud2lkdGgsXG5cdFx0XHRcdFx0aGVpZ2h0OiB0ZXhEYXRhcy5oZWlnaHQsXG5cdFx0XHRcdFx0Zm9ybWF0OiB0ZXhEYXRhcy5mb3JtYXQsXG5cdFx0XHRcdFx0bWlwbWFwczogdGV4RGF0YXMubWlwbWFwc1xuXHRcdFx0XHR9O1xuXG5cdFx0XHRcdGxvYWRlZCArPSAxO1xuXG5cdFx0XHRcdGlmICggbG9hZGVkID09PSA2ICkge1xuXG5cdFx0XHRcdFx0aWYgKCB0ZXhEYXRhcy5taXBtYXBDb3VudCA9PT0gMSApIHRleHR1cmUubWluRmlsdGVyID0gTGluZWFyRmlsdGVyO1xuXG5cdFx0XHRcdFx0dGV4dHVyZS5pbWFnZSA9IGltYWdlcztcblx0XHRcdFx0XHR0ZXh0dXJlLmZvcm1hdCA9IHRleERhdGFzLmZvcm1hdDtcblx0XHRcdFx0XHR0ZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdFx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCB0ZXh0dXJlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9LCBvblByb2dyZXNzLCBvbkVycm9yICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHVybCApICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gdXJsLmxlbmd0aDsgaSA8IGlsOyArKyBpICkge1xuXG5cdFx0XHRcdGxvYWRUZXh0dXJlKCBpICk7XG5cblx0XHRcdH1cblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIGNvbXByZXNzZWQgY3ViZW1hcCB0ZXh0dXJlIHN0b3JlZCBpbiBhIHNpbmdsZSBERFMgZmlsZVxuXG5cdFx0XHRsb2FkZXIubG9hZCggdXJsLCBmdW5jdGlvbiAoIGJ1ZmZlciApIHtcblxuXHRcdFx0XHRjb25zdCB0ZXhEYXRhcyA9IHNjb3BlLnBhcnNlKCBidWZmZXIsIHRydWUgKTtcblxuXHRcdFx0XHRpZiAoIHRleERhdGFzLmlzQ3ViZW1hcCApIHtcblxuXHRcdFx0XHRcdGNvbnN0IGZhY2VzID0gdGV4RGF0YXMubWlwbWFwcy5sZW5ndGggLyB0ZXhEYXRhcy5taXBtYXBDb3VudDtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBmID0gMDsgZiA8IGZhY2VzOyBmICsrICkge1xuXG5cdFx0XHRcdFx0XHRpbWFnZXNbIGYgXSA9IHsgbWlwbWFwczogW10gfTtcblxuXHRcdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGV4RGF0YXMubWlwbWFwQ291bnQ7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRcdFx0aW1hZ2VzWyBmIF0ubWlwbWFwcy5wdXNoKCB0ZXhEYXRhcy5taXBtYXBzWyBmICogdGV4RGF0YXMubWlwbWFwQ291bnQgKyBpIF0gKTtcblx0XHRcdFx0XHRcdFx0aW1hZ2VzWyBmIF0uZm9ybWF0ID0gdGV4RGF0YXMuZm9ybWF0O1xuXHRcdFx0XHRcdFx0XHRpbWFnZXNbIGYgXS53aWR0aCA9IHRleERhdGFzLndpZHRoO1xuXHRcdFx0XHRcdFx0XHRpbWFnZXNbIGYgXS5oZWlnaHQgPSB0ZXhEYXRhcy5oZWlnaHQ7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdHRleHR1cmUuaW1hZ2UgPSBpbWFnZXM7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHRleHR1cmUuaW1hZ2Uud2lkdGggPSB0ZXhEYXRhcy53aWR0aDtcblx0XHRcdFx0XHR0ZXh0dXJlLmltYWdlLmhlaWdodCA9IHRleERhdGFzLmhlaWdodDtcblx0XHRcdFx0XHR0ZXh0dXJlLm1pcG1hcHMgPSB0ZXhEYXRhcy5taXBtYXBzO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIHRleERhdGFzLm1pcG1hcENvdW50ID09PSAxICkge1xuXG5cdFx0XHRcdFx0dGV4dHVyZS5taW5GaWx0ZXIgPSBMaW5lYXJGaWx0ZXI7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRleHR1cmUuZm9ybWF0ID0gdGV4RGF0YXMuZm9ybWF0O1xuXHRcdFx0XHR0ZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggdGV4dHVyZSApO1xuXG5cdFx0XHR9LCBvblByb2dyZXNzLCBvbkVycm9yICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGV4dHVyZTtcblxuXHR9XG5cbn1cblxuY2xhc3MgSW1hZ2VMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xuXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcblxuXHR9XG5cblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XG5cblx0XHRpZiAoIHRoaXMucGF0aCAhPT0gdW5kZWZpbmVkICkgdXJsID0gdGhpcy5wYXRoICsgdXJsO1xuXG5cdFx0dXJsID0gdGhpcy5tYW5hZ2VyLnJlc29sdmVVUkwoIHVybCApO1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0Y29uc3QgY2FjaGVkID0gQ2FjaGUuZ2V0KCB1cmwgKTtcblxuXHRcdGlmICggY2FjaGVkICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbVN0YXJ0KCB1cmwgKTtcblxuXHRcdFx0c2V0VGltZW91dCggZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCBjYWNoZWQgKTtcblxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xuXG5cdFx0XHR9LCAwICk7XG5cblx0XHRcdHJldHVybiBjYWNoZWQ7XG5cblx0XHR9XG5cblx0XHRjb25zdCBpbWFnZSA9IGNyZWF0ZUVsZW1lbnROUyggJ2ltZycgKTtcblxuXHRcdGZ1bmN0aW9uIG9uSW1hZ2VMb2FkKCkge1xuXG5cdFx0XHRyZW1vdmVFdmVudExpc3RlbmVycygpO1xuXG5cdFx0XHRDYWNoZS5hZGQoIHVybCwgdGhpcyApO1xuXG5cdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggdGhpcyApO1xuXG5cdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gb25JbWFnZUVycm9yKCBldmVudCApIHtcblxuXHRcdFx0cmVtb3ZlRXZlbnRMaXN0ZW5lcnMoKTtcblxuXHRcdFx0aWYgKCBvbkVycm9yICkgb25FcnJvciggZXZlbnQgKTtcblxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHJlbW92ZUV2ZW50TGlzdGVuZXJzKCkge1xuXG5cdFx0XHRpbWFnZS5yZW1vdmVFdmVudExpc3RlbmVyKCAnbG9hZCcsIG9uSW1hZ2VMb2FkLCBmYWxzZSApO1xuXHRcdFx0aW1hZ2UucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2Vycm9yJywgb25JbWFnZUVycm9yLCBmYWxzZSApO1xuXG5cdFx0fVxuXG5cdFx0aW1hZ2UuYWRkRXZlbnRMaXN0ZW5lciggJ2xvYWQnLCBvbkltYWdlTG9hZCwgZmFsc2UgKTtcblx0XHRpbWFnZS5hZGRFdmVudExpc3RlbmVyKCAnZXJyb3InLCBvbkltYWdlRXJyb3IsIGZhbHNlICk7XG5cblx0XHRpZiAoIHVybC5zbGljZSggMCwgNSApICE9PSAnZGF0YTonICkge1xuXG5cdFx0XHRpZiAoIHRoaXMuY3Jvc3NPcmlnaW4gIT09IHVuZGVmaW5lZCApIGltYWdlLmNyb3NzT3JpZ2luID0gdGhpcy5jcm9zc09yaWdpbjtcblxuXHRcdH1cblxuXHRcdHNjb3BlLm1hbmFnZXIuaXRlbVN0YXJ0KCB1cmwgKTtcblxuXHRcdGltYWdlLnNyYyA9IHVybDtcblxuXHRcdHJldHVybiBpbWFnZTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQ3ViZVRleHR1cmVMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xuXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcblxuXHR9XG5cblx0bG9hZCggdXJscywgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xuXG5cdFx0Y29uc3QgdGV4dHVyZSA9IG5ldyBDdWJlVGV4dHVyZSgpO1xuXHRcdHRleHR1cmUuY29sb3JTcGFjZSA9IFNSR0JDb2xvclNwYWNlO1xuXG5cdFx0Y29uc3QgbG9hZGVyID0gbmV3IEltYWdlTG9hZGVyKCB0aGlzLm1hbmFnZXIgKTtcblx0XHRsb2FkZXIuc2V0Q3Jvc3NPcmlnaW4oIHRoaXMuY3Jvc3NPcmlnaW4gKTtcblx0XHRsb2FkZXIuc2V0UGF0aCggdGhpcy5wYXRoICk7XG5cblx0XHRsZXQgbG9hZGVkID0gMDtcblxuXHRcdGZ1bmN0aW9uIGxvYWRUZXh0dXJlKCBpICkge1xuXG5cdFx0XHRsb2FkZXIubG9hZCggdXJsc1sgaSBdLCBmdW5jdGlvbiAoIGltYWdlICkge1xuXG5cdFx0XHRcdHRleHR1cmUuaW1hZ2VzWyBpIF0gPSBpbWFnZTtcblxuXHRcdFx0XHRsb2FkZWQgKys7XG5cblx0XHRcdFx0aWYgKCBsb2FkZWQgPT09IDYgKSB7XG5cblx0XHRcdFx0XHR0ZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdFx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCB0ZXh0dXJlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9LCB1bmRlZmluZWQsIG9uRXJyb3IgKTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHVybHMubGVuZ3RoOyArKyBpICkge1xuXG5cdFx0XHRsb2FkVGV4dHVyZSggaSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRleHR1cmU7XG5cblx0fVxuXG59XG5cbi8qKlxuICogQWJzdHJhY3QgQmFzZSBjbGFzcyB0byBsb2FkIGdlbmVyaWMgYmluYXJ5IHRleHR1cmVzIGZvcm1hdHMgKHJnYmUsIGhkciwgLi4uKVxuICpcbiAqIFN1YiBjbGFzc2VzIGhhdmUgdG8gaW1wbGVtZW50IHRoZSBwYXJzZSgpIG1ldGhvZCB3aGljaCB3aWxsIGJlIHVzZWQgaW4gbG9hZCgpLlxuICovXG5cbmNsYXNzIERhdGFUZXh0dXJlTG9hZGVyIGV4dGVuZHMgTG9hZGVyIHtcblxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcblxuXHRcdHN1cGVyKCBtYW5hZ2VyICk7XG5cblx0fVxuXG5cdGxvYWQoIHVybCwgb25Mb2FkLCBvblByb2dyZXNzLCBvbkVycm9yICkge1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0Y29uc3QgdGV4dHVyZSA9IG5ldyBEYXRhVGV4dHVyZSgpO1xuXG5cdFx0Y29uc3QgbG9hZGVyID0gbmV3IEZpbGVMb2FkZXIoIHRoaXMubWFuYWdlciApO1xuXHRcdGxvYWRlci5zZXRSZXNwb25zZVR5cGUoICdhcnJheWJ1ZmZlcicgKTtcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggdGhpcy5yZXF1ZXN0SGVhZGVyICk7XG5cdFx0bG9hZGVyLnNldFBhdGgoIHRoaXMucGF0aCApO1xuXHRcdGxvYWRlci5zZXRXaXRoQ3JlZGVudGlhbHMoIHNjb3BlLndpdGhDcmVkZW50aWFscyApO1xuXHRcdGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICggYnVmZmVyICkge1xuXG5cdFx0XHRsZXQgdGV4RGF0YTtcblxuXHRcdFx0dHJ5IHtcblxuXHRcdFx0XHR0ZXhEYXRhID0gc2NvcGUucGFyc2UoIGJ1ZmZlciApO1xuXG5cdFx0XHR9IGNhdGNoICggZXJyb3IgKSB7XG5cblx0XHRcdFx0aWYgKCBvbkVycm9yICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRvbkVycm9yKCBlcnJvciApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCBlcnJvciApO1xuXHRcdFx0XHRcdHJldHVybjtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0ZXhEYXRhLmltYWdlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGV4dHVyZS5pbWFnZSA9IHRleERhdGEuaW1hZ2U7XG5cblx0XHRcdH0gZWxzZSBpZiAoIHRleERhdGEuZGF0YSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHRleHR1cmUuaW1hZ2Uud2lkdGggPSB0ZXhEYXRhLndpZHRoO1xuXHRcdFx0XHR0ZXh0dXJlLmltYWdlLmhlaWdodCA9IHRleERhdGEuaGVpZ2h0O1xuXHRcdFx0XHR0ZXh0dXJlLmltYWdlLmRhdGEgPSB0ZXhEYXRhLmRhdGE7XG5cblx0XHRcdH1cblxuXHRcdFx0dGV4dHVyZS53cmFwUyA9IHRleERhdGEud3JhcFMgIT09IHVuZGVmaW5lZCA/IHRleERhdGEud3JhcFMgOiBDbGFtcFRvRWRnZVdyYXBwaW5nO1xuXHRcdFx0dGV4dHVyZS53cmFwVCA9IHRleERhdGEud3JhcFQgIT09IHVuZGVmaW5lZCA/IHRleERhdGEud3JhcFQgOiBDbGFtcFRvRWRnZVdyYXBwaW5nO1xuXG5cdFx0XHR0ZXh0dXJlLm1hZ0ZpbHRlciA9IHRleERhdGEubWFnRmlsdGVyICE9PSB1bmRlZmluZWQgPyB0ZXhEYXRhLm1hZ0ZpbHRlciA6IExpbmVhckZpbHRlcjtcblx0XHRcdHRleHR1cmUubWluRmlsdGVyID0gdGV4RGF0YS5taW5GaWx0ZXIgIT09IHVuZGVmaW5lZCA/IHRleERhdGEubWluRmlsdGVyIDogTGluZWFyRmlsdGVyO1xuXG5cdFx0XHR0ZXh0dXJlLmFuaXNvdHJvcHkgPSB0ZXhEYXRhLmFuaXNvdHJvcHkgIT09IHVuZGVmaW5lZCA/IHRleERhdGEuYW5pc290cm9weSA6IDE7XG5cblx0XHRcdGlmICggdGV4RGF0YS5jb2xvclNwYWNlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGV4dHVyZS5jb2xvclNwYWNlID0gdGV4RGF0YS5jb2xvclNwYWNlO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGV4RGF0YS5mbGlwWSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHRleHR1cmUuZmxpcFkgPSB0ZXhEYXRhLmZsaXBZO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGV4RGF0YS5mb3JtYXQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0ZXh0dXJlLmZvcm1hdCA9IHRleERhdGEuZm9ybWF0O1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGV4RGF0YS50eXBlICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGV4dHVyZS50eXBlID0gdGV4RGF0YS50eXBlO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGV4RGF0YS5taXBtYXBzICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGV4dHVyZS5taXBtYXBzID0gdGV4RGF0YS5taXBtYXBzO1xuXHRcdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IExpbmVhck1pcG1hcExpbmVhckZpbHRlcjsgLy8gcHJlc3VtYWJseS4uLlxuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggdGV4RGF0YS5taXBtYXBDb3VudCA9PT0gMSApIHtcblxuXHRcdFx0XHR0ZXh0dXJlLm1pbkZpbHRlciA9IExpbmVhckZpbHRlcjtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRleERhdGEuZ2VuZXJhdGVNaXBtYXBzICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0dGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSB0ZXhEYXRhLmdlbmVyYXRlTWlwbWFwcztcblxuXHRcdFx0fVxuXG5cdFx0XHR0ZXh0dXJlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdFx0aWYgKCBvbkxvYWQgKSBvbkxvYWQoIHRleHR1cmUsIHRleERhdGEgKTtcblxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcblxuXG5cdFx0cmV0dXJuIHRleHR1cmU7XG5cblx0fVxuXG59XG5cbmNsYXNzIFRleHR1cmVMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xuXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcblxuXHR9XG5cblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XG5cblx0XHRjb25zdCB0ZXh0dXJlID0gbmV3IFRleHR1cmUoKTtcblxuXHRcdGNvbnN0IGxvYWRlciA9IG5ldyBJbWFnZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XG5cdFx0bG9hZGVyLnNldENyb3NzT3JpZ2luKCB0aGlzLmNyb3NzT3JpZ2luICk7XG5cdFx0bG9hZGVyLnNldFBhdGgoIHRoaXMucGF0aCApO1xuXG5cdFx0bG9hZGVyLmxvYWQoIHVybCwgZnVuY3Rpb24gKCBpbWFnZSApIHtcblxuXHRcdFx0dGV4dHVyZS5pbWFnZSA9IGltYWdlO1xuXHRcdFx0dGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdGlmICggb25Mb2FkICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0b25Mb2FkKCB0ZXh0dXJlICk7XG5cblx0XHRcdH1cblxuXHRcdH0sIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKTtcblxuXHRcdHJldHVybiB0ZXh0dXJlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBMaWdodCBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvciggY29sb3IsIGludGVuc2l0eSA9IDEgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc0xpZ2h0ID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdMaWdodCc7XG5cblx0XHR0aGlzLmNvbG9yID0gbmV3IENvbG9yKCBjb2xvciApO1xuXHRcdHRoaXMuaW50ZW5zaXR5ID0gaW50ZW5zaXR5O1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0Ly8gRW1wdHkgaGVyZSBpbiBiYXNlIGNsYXNzOyBzb21lIHN1YmNsYXNzZXMgb3ZlcnJpZGUuXG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcblxuXHRcdHRoaXMuY29sb3IuY29weSggc291cmNlLmNvbG9yICk7XG5cdFx0dGhpcy5pbnRlbnNpdHkgPSBzb3VyY2UuaW50ZW5zaXR5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTiggbWV0YSApIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oIG1ldGEgKTtcblxuXHRcdGRhdGEub2JqZWN0LmNvbG9yID0gdGhpcy5jb2xvci5nZXRIZXgoKTtcblx0XHRkYXRhLm9iamVjdC5pbnRlbnNpdHkgPSB0aGlzLmludGVuc2l0eTtcblxuXHRcdGlmICggdGhpcy5ncm91bmRDb2xvciAhPT0gdW5kZWZpbmVkICkgZGF0YS5vYmplY3QuZ3JvdW5kQ29sb3IgPSB0aGlzLmdyb3VuZENvbG9yLmdldEhleCgpO1xuXG5cdFx0aWYgKCB0aGlzLmRpc3RhbmNlICE9PSB1bmRlZmluZWQgKSBkYXRhLm9iamVjdC5kaXN0YW5jZSA9IHRoaXMuZGlzdGFuY2U7XG5cdFx0aWYgKCB0aGlzLmFuZ2xlICE9PSB1bmRlZmluZWQgKSBkYXRhLm9iamVjdC5hbmdsZSA9IHRoaXMuYW5nbGU7XG5cdFx0aWYgKCB0aGlzLmRlY2F5ICE9PSB1bmRlZmluZWQgKSBkYXRhLm9iamVjdC5kZWNheSA9IHRoaXMuZGVjYXk7XG5cdFx0aWYgKCB0aGlzLnBlbnVtYnJhICE9PSB1bmRlZmluZWQgKSBkYXRhLm9iamVjdC5wZW51bWJyYSA9IHRoaXMucGVudW1icmE7XG5cblx0XHRpZiAoIHRoaXMuc2hhZG93ICE9PSB1bmRlZmluZWQgKSBkYXRhLm9iamVjdC5zaGFkb3cgPSB0aGlzLnNoYWRvdy50b0pTT04oKTtcblx0XHRpZiAoIHRoaXMudGFyZ2V0ICE9PSB1bmRlZmluZWQgKSBkYXRhLm9iamVjdC50YXJnZXQgPSB0aGlzLnRhcmdldC51dWlkO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbmNsYXNzIEhlbWlzcGhlcmVMaWdodCBleHRlbmRzIExpZ2h0IHtcblxuXHRjb25zdHJ1Y3Rvciggc2t5Q29sb3IsIGdyb3VuZENvbG9yLCBpbnRlbnNpdHkgKSB7XG5cblx0XHRzdXBlciggc2t5Q29sb3IsIGludGVuc2l0eSApO1xuXG5cdFx0dGhpcy5pc0hlbWlzcGhlcmVMaWdodCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnSGVtaXNwaGVyZUxpZ2h0JztcblxuXHRcdHRoaXMucG9zaXRpb24uY29weSggT2JqZWN0M0QuREVGQVVMVF9VUCApO1xuXHRcdHRoaXMudXBkYXRlTWF0cml4KCk7XG5cblx0XHR0aGlzLmdyb3VuZENvbG9yID0gbmV3IENvbG9yKCBncm91bmRDb2xvciApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XG5cblx0XHR0aGlzLmdyb3VuZENvbG9yLmNvcHkoIHNvdXJjZS5ncm91bmRDb2xvciApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9wcm9qU2NyZWVuTWF0cml4JDEgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfbGlnaHRQb3NpdGlvbldvcmxkJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfbG9va1RhcmdldCQxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jbGFzcyBMaWdodFNoYWRvdyB7XG5cblx0Y29uc3RydWN0b3IoIGNhbWVyYSApIHtcblxuXHRcdHRoaXMuY2FtZXJhID0gY2FtZXJhO1xuXG5cdFx0dGhpcy5pbnRlbnNpdHkgPSAxO1xuXG5cdFx0dGhpcy5iaWFzID0gMDtcblx0XHR0aGlzLm5vcm1hbEJpYXMgPSAwO1xuXHRcdHRoaXMucmFkaXVzID0gMTtcblx0XHR0aGlzLmJsdXJTYW1wbGVzID0gODtcblxuXHRcdHRoaXMubWFwU2l6ZSA9IG5ldyBWZWN0b3IyKCA1MTIsIDUxMiApO1xuXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xuXHRcdHRoaXMubWFwUGFzcyA9IG51bGw7XG5cdFx0dGhpcy5tYXRyaXggPSBuZXcgTWF0cml4NCgpO1xuXG5cdFx0dGhpcy5hdXRvVXBkYXRlID0gdHJ1ZTtcblx0XHR0aGlzLm5lZWRzVXBkYXRlID0gZmFsc2U7XG5cblx0XHR0aGlzLl9mcnVzdHVtID0gbmV3IEZydXN0dW0oKTtcblx0XHR0aGlzLl9mcmFtZUV4dGVudHMgPSBuZXcgVmVjdG9yMiggMSwgMSApO1xuXG5cdFx0dGhpcy5fdmlld3BvcnRDb3VudCA9IDE7XG5cblx0XHR0aGlzLl92aWV3cG9ydHMgPSBbXG5cblx0XHRcdG5ldyBWZWN0b3I0KCAwLCAwLCAxLCAxIClcblxuXHRcdF07XG5cblx0fVxuXG5cdGdldFZpZXdwb3J0Q291bnQoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fdmlld3BvcnRDb3VudDtcblxuXHR9XG5cblx0Z2V0RnJ1c3R1bSgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9mcnVzdHVtO1xuXG5cdH1cblxuXHR1cGRhdGVNYXRyaWNlcyggbGlnaHQgKSB7XG5cblx0XHRjb25zdCBzaGFkb3dDYW1lcmEgPSB0aGlzLmNhbWVyYTtcblx0XHRjb25zdCBzaGFkb3dNYXRyaXggPSB0aGlzLm1hdHJpeDtcblxuXHRcdF9saWdodFBvc2l0aW9uV29ybGQkMS5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cdFx0c2hhZG93Q2FtZXJhLnBvc2l0aW9uLmNvcHkoIF9saWdodFBvc2l0aW9uV29ybGQkMSApO1xuXG5cdFx0X2xvb2tUYXJnZXQkMS5zZXRGcm9tTWF0cml4UG9zaXRpb24oIGxpZ2h0LnRhcmdldC5tYXRyaXhXb3JsZCApO1xuXHRcdHNoYWRvd0NhbWVyYS5sb29rQXQoIF9sb29rVGFyZ2V0JDEgKTtcblx0XHRzaGFkb3dDYW1lcmEudXBkYXRlTWF0cml4V29ybGQoKTtcblxuXHRcdF9wcm9qU2NyZWVuTWF0cml4JDEubXVsdGlwbHlNYXRyaWNlcyggc2hhZG93Q2FtZXJhLnByb2plY3Rpb25NYXRyaXgsIHNoYWRvd0NhbWVyYS5tYXRyaXhXb3JsZEludmVyc2UgKTtcblx0XHR0aGlzLl9mcnVzdHVtLnNldEZyb21Qcm9qZWN0aW9uTWF0cml4KCBfcHJvalNjcmVlbk1hdHJpeCQxICk7XG5cblx0XHRzaGFkb3dNYXRyaXguc2V0KFxuXHRcdFx0MC41LCAwLjAsIDAuMCwgMC41LFxuXHRcdFx0MC4wLCAwLjUsIDAuMCwgMC41LFxuXHRcdFx0MC4wLCAwLjAsIDAuNSwgMC41LFxuXHRcdFx0MC4wLCAwLjAsIDAuMCwgMS4wXG5cdFx0KTtcblxuXHRcdHNoYWRvd01hdHJpeC5tdWx0aXBseSggX3Byb2pTY3JlZW5NYXRyaXgkMSApO1xuXG5cdH1cblxuXHRnZXRWaWV3cG9ydCggdmlld3BvcnRJbmRleCApIHtcblxuXHRcdHJldHVybiB0aGlzLl92aWV3cG9ydHNbIHZpZXdwb3J0SW5kZXggXTtcblxuXHR9XG5cblx0Z2V0RnJhbWVFeHRlbnRzKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX2ZyYW1lRXh0ZW50cztcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdGlmICggdGhpcy5tYXAgKSB7XG5cblx0XHRcdHRoaXMubWFwLmRpc3Bvc2UoKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5tYXBQYXNzICkge1xuXG5cdFx0XHR0aGlzLm1hcFBhc3MuZGlzcG9zZSgpO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHR0aGlzLmNhbWVyYSA9IHNvdXJjZS5jYW1lcmEuY2xvbmUoKTtcblxuXHRcdHRoaXMuaW50ZW5zaXR5ID0gc291cmNlLmludGVuc2l0eTtcblxuXHRcdHRoaXMuYmlhcyA9IHNvdXJjZS5iaWFzO1xuXHRcdHRoaXMucmFkaXVzID0gc291cmNlLnJhZGl1cztcblxuXHRcdHRoaXMubWFwU2l6ZS5jb3B5KCBzb3VyY2UubWFwU2l6ZSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxuXHR0b0pTT04oKSB7XG5cblx0XHRjb25zdCBvYmplY3QgPSB7fTtcblxuXHRcdGlmICggdGhpcy5pbnRlbnNpdHkgIT09IDEgKSBvYmplY3QuaW50ZW5zaXR5ID0gdGhpcy5pbnRlbnNpdHk7XG5cdFx0aWYgKCB0aGlzLmJpYXMgIT09IDAgKSBvYmplY3QuYmlhcyA9IHRoaXMuYmlhcztcblx0XHRpZiAoIHRoaXMubm9ybWFsQmlhcyAhPT0gMCApIG9iamVjdC5ub3JtYWxCaWFzID0gdGhpcy5ub3JtYWxCaWFzO1xuXHRcdGlmICggdGhpcy5yYWRpdXMgIT09IDEgKSBvYmplY3QucmFkaXVzID0gdGhpcy5yYWRpdXM7XG5cdFx0aWYgKCB0aGlzLm1hcFNpemUueCAhPT0gNTEyIHx8IHRoaXMubWFwU2l6ZS55ICE9PSA1MTIgKSBvYmplY3QubWFwU2l6ZSA9IHRoaXMubWFwU2l6ZS50b0FycmF5KCk7XG5cblx0XHRvYmplY3QuY2FtZXJhID0gdGhpcy5jYW1lcmEudG9KU09OKCBmYWxzZSApLm9iamVjdDtcblx0XHRkZWxldGUgb2JqZWN0LmNhbWVyYS5tYXRyaXg7XG5cblx0XHRyZXR1cm4gb2JqZWN0O1xuXG5cdH1cblxufVxuXG5jbGFzcyBTcG90TGlnaHRTaGFkb3cgZXh0ZW5kcyBMaWdodFNoYWRvdyB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHRzdXBlciggbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCA1MCwgMSwgMC41LCA1MDAgKSApO1xuXG5cdFx0dGhpcy5pc1Nwb3RMaWdodFNoYWRvdyA9IHRydWU7XG5cblx0XHR0aGlzLmZvY3VzID0gMTtcblxuXHR9XG5cblx0dXBkYXRlTWF0cmljZXMoIGxpZ2h0ICkge1xuXG5cdFx0Y29uc3QgY2FtZXJhID0gdGhpcy5jYW1lcmE7XG5cblx0XHRjb25zdCBmb3YgPSBSQUQyREVHICogMiAqIGxpZ2h0LmFuZ2xlICogdGhpcy5mb2N1cztcblx0XHRjb25zdCBhc3BlY3QgPSB0aGlzLm1hcFNpemUud2lkdGggLyB0aGlzLm1hcFNpemUuaGVpZ2h0O1xuXHRcdGNvbnN0IGZhciA9IGxpZ2h0LmRpc3RhbmNlIHx8IGNhbWVyYS5mYXI7XG5cblx0XHRpZiAoIGZvdiAhPT0gY2FtZXJhLmZvdiB8fCBhc3BlY3QgIT09IGNhbWVyYS5hc3BlY3QgfHwgZmFyICE9PSBjYW1lcmEuZmFyICkge1xuXG5cdFx0XHRjYW1lcmEuZm92ID0gZm92O1xuXHRcdFx0Y2FtZXJhLmFzcGVjdCA9IGFzcGVjdDtcblx0XHRcdGNhbWVyYS5mYXIgPSBmYXI7XG5cdFx0XHRjYW1lcmEudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXG5cdFx0fVxuXG5cdFx0c3VwZXIudXBkYXRlTWF0cmljZXMoIGxpZ2h0ICk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSApO1xuXG5cdFx0dGhpcy5mb2N1cyA9IHNvdXJjZS5mb2N1cztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jbGFzcyBTcG90TGlnaHQgZXh0ZW5kcyBMaWdodCB7XG5cblx0Y29uc3RydWN0b3IoIGNvbG9yLCBpbnRlbnNpdHksIGRpc3RhbmNlID0gMCwgYW5nbGUgPSBNYXRoLlBJIC8gMywgcGVudW1icmEgPSAwLCBkZWNheSA9IDIgKSB7XG5cblx0XHRzdXBlciggY29sb3IsIGludGVuc2l0eSApO1xuXG5cdFx0dGhpcy5pc1Nwb3RMaWdodCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnU3BvdExpZ2h0JztcblxuXHRcdHRoaXMucG9zaXRpb24uY29weSggT2JqZWN0M0QuREVGQVVMVF9VUCApO1xuXHRcdHRoaXMudXBkYXRlTWF0cml4KCk7XG5cblx0XHR0aGlzLnRhcmdldCA9IG5ldyBPYmplY3QzRCgpO1xuXG5cdFx0dGhpcy5kaXN0YW5jZSA9IGRpc3RhbmNlO1xuXHRcdHRoaXMuYW5nbGUgPSBhbmdsZTtcblx0XHR0aGlzLnBlbnVtYnJhID0gcGVudW1icmE7XG5cdFx0dGhpcy5kZWNheSA9IGRlY2F5O1xuXG5cdFx0dGhpcy5tYXAgPSBudWxsO1xuXG5cdFx0dGhpcy5zaGFkb3cgPSBuZXcgU3BvdExpZ2h0U2hhZG93KCk7XG5cblx0fVxuXG5cdGdldCBwb3dlcigpIHtcblxuXHRcdC8vIGNvbXB1dGUgdGhlIGxpZ2h0J3MgbHVtaW5vdXMgcG93ZXIgKGluIGx1bWVucykgZnJvbSBpdHMgaW50ZW5zaXR5IChpbiBjYW5kZWxhKVxuXHRcdC8vIGJ5IGNvbnZlbnRpb24gZm9yIGEgc3BvdGxpZ2h0LCBsdW1pbm91cyBwb3dlciAobG0pID0gz4AgKiBsdW1pbm91cyBpbnRlbnNpdHkgKGNkKVxuXHRcdHJldHVybiB0aGlzLmludGVuc2l0eSAqIE1hdGguUEk7XG5cblx0fVxuXG5cdHNldCBwb3dlciggcG93ZXIgKSB7XG5cblx0XHQvLyBzZXQgdGhlIGxpZ2h0J3MgaW50ZW5zaXR5IChpbiBjYW5kZWxhKSBmcm9tIHRoZSBkZXNpcmVkIGx1bWlub3VzIHBvd2VyIChpbiBsdW1lbnMpXG5cdFx0dGhpcy5pbnRlbnNpdHkgPSBwb3dlciAvIE1hdGguUEk7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLnNoYWRvdy5kaXNwb3NlKCk7XG5cblx0fVxuXG5cdGNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlLCByZWN1cnNpdmUgKTtcblxuXHRcdHRoaXMuZGlzdGFuY2UgPSBzb3VyY2UuZGlzdGFuY2U7XG5cdFx0dGhpcy5hbmdsZSA9IHNvdXJjZS5hbmdsZTtcblx0XHR0aGlzLnBlbnVtYnJhID0gc291cmNlLnBlbnVtYnJhO1xuXHRcdHRoaXMuZGVjYXkgPSBzb3VyY2UuZGVjYXk7XG5cblx0XHR0aGlzLnRhcmdldCA9IHNvdXJjZS50YXJnZXQuY2xvbmUoKTtcblxuXHRcdHRoaXMuc2hhZG93ID0gc291cmNlLnNoYWRvdy5jbG9uZSgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9wcm9qU2NyZWVuTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX2xpZ2h0UG9zaXRpb25Xb3JsZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9sb29rVGFyZ2V0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jbGFzcyBQb2ludExpZ2h0U2hhZG93IGV4dGVuZHMgTGlnaHRTaGFkb3cge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoIG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSggOTAsIDEsIDAuNSwgNTAwICkgKTtcblxuXHRcdHRoaXMuaXNQb2ludExpZ2h0U2hhZG93ID0gdHJ1ZTtcblxuXHRcdHRoaXMuX2ZyYW1lRXh0ZW50cyA9IG5ldyBWZWN0b3IyKCA0LCAyICk7XG5cblx0XHR0aGlzLl92aWV3cG9ydENvdW50ID0gNjtcblxuXHRcdHRoaXMuX3ZpZXdwb3J0cyA9IFtcblx0XHRcdC8vIFRoZXNlIHZpZXdwb3J0cyBtYXAgYSBjdWJlLW1hcCBvbnRvIGEgMkQgdGV4dHVyZSB3aXRoIHRoZVxuXHRcdFx0Ly8gZm9sbG93aW5nIG9yaWVudGF0aW9uOlxuXHRcdFx0Ly9cblx0XHRcdC8vICB4elhaXG5cdFx0XHQvLyAgIHkgWVxuXHRcdFx0Ly9cblx0XHRcdC8vIFggLSBQb3NpdGl2ZSB4IGRpcmVjdGlvblxuXHRcdFx0Ly8geCAtIE5lZ2F0aXZlIHggZGlyZWN0aW9uXG5cdFx0XHQvLyBZIC0gUG9zaXRpdmUgeSBkaXJlY3Rpb25cblx0XHRcdC8vIHkgLSBOZWdhdGl2ZSB5IGRpcmVjdGlvblxuXHRcdFx0Ly8gWiAtIFBvc2l0aXZlIHogZGlyZWN0aW9uXG5cdFx0XHQvLyB6IC0gTmVnYXRpdmUgeiBkaXJlY3Rpb25cblxuXHRcdFx0Ly8gcG9zaXRpdmUgWFxuXHRcdFx0bmV3IFZlY3RvcjQoIDIsIDEsIDEsIDEgKSxcblx0XHRcdC8vIG5lZ2F0aXZlIFhcblx0XHRcdG5ldyBWZWN0b3I0KCAwLCAxLCAxLCAxICksXG5cdFx0XHQvLyBwb3NpdGl2ZSBaXG5cdFx0XHRuZXcgVmVjdG9yNCggMywgMSwgMSwgMSApLFxuXHRcdFx0Ly8gbmVnYXRpdmUgWlxuXHRcdFx0bmV3IFZlY3RvcjQoIDEsIDEsIDEsIDEgKSxcblx0XHRcdC8vIHBvc2l0aXZlIFlcblx0XHRcdG5ldyBWZWN0b3I0KCAzLCAwLCAxLCAxICksXG5cdFx0XHQvLyBuZWdhdGl2ZSBZXG5cdFx0XHRuZXcgVmVjdG9yNCggMSwgMCwgMSwgMSApXG5cdFx0XTtcblxuXHRcdHRoaXMuX2N1YmVEaXJlY3Rpb25zID0gW1xuXHRcdFx0bmV3IFZlY3RvcjMoIDEsIDAsIDAgKSwgbmV3IFZlY3RvcjMoIC0gMSwgMCwgMCApLCBuZXcgVmVjdG9yMyggMCwgMCwgMSApLFxuXHRcdFx0bmV3IFZlY3RvcjMoIDAsIDAsIC0gMSApLCBuZXcgVmVjdG9yMyggMCwgMSwgMCApLCBuZXcgVmVjdG9yMyggMCwgLSAxLCAwIClcblx0XHRdO1xuXG5cdFx0dGhpcy5fY3ViZVVwcyA9IFtcblx0XHRcdG5ldyBWZWN0b3IzKCAwLCAxLCAwICksIG5ldyBWZWN0b3IzKCAwLCAxLCAwICksIG5ldyBWZWN0b3IzKCAwLCAxLCAwICksXG5cdFx0XHRuZXcgVmVjdG9yMyggMCwgMSwgMCApLCBuZXcgVmVjdG9yMyggMCwgMCwgMSApLFx0bmV3IFZlY3RvcjMoIDAsIDAsIC0gMSApXG5cdFx0XTtcblxuXHR9XG5cblx0dXBkYXRlTWF0cmljZXMoIGxpZ2h0LCB2aWV3cG9ydEluZGV4ID0gMCApIHtcblxuXHRcdGNvbnN0IGNhbWVyYSA9IHRoaXMuY2FtZXJhO1xuXHRcdGNvbnN0IHNoYWRvd01hdHJpeCA9IHRoaXMubWF0cml4O1xuXG5cdFx0Y29uc3QgZmFyID0gbGlnaHQuZGlzdGFuY2UgfHwgY2FtZXJhLmZhcjtcblxuXHRcdGlmICggZmFyICE9PSBjYW1lcmEuZmFyICkge1xuXG5cdFx0XHRjYW1lcmEuZmFyID0gZmFyO1xuXHRcdFx0Y2FtZXJhLnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHRcdH1cblxuXHRcdF9saWdodFBvc2l0aW9uV29ybGQuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBsaWdodC5tYXRyaXhXb3JsZCApO1xuXHRcdGNhbWVyYS5wb3NpdGlvbi5jb3B5KCBfbGlnaHRQb3NpdGlvbldvcmxkICk7XG5cblx0XHRfbG9va1RhcmdldC5jb3B5KCBjYW1lcmEucG9zaXRpb24gKTtcblx0XHRfbG9va1RhcmdldC5hZGQoIHRoaXMuX2N1YmVEaXJlY3Rpb25zWyB2aWV3cG9ydEluZGV4IF0gKTtcblx0XHRjYW1lcmEudXAuY29weSggdGhpcy5fY3ViZVVwc1sgdmlld3BvcnRJbmRleCBdICk7XG5cdFx0Y2FtZXJhLmxvb2tBdCggX2xvb2tUYXJnZXQgKTtcblx0XHRjYW1lcmEudXBkYXRlTWF0cml4V29ybGQoKTtcblxuXHRcdHNoYWRvd01hdHJpeC5tYWtlVHJhbnNsYXRpb24oIC0gX2xpZ2h0UG9zaXRpb25Xb3JsZC54LCAtIF9saWdodFBvc2l0aW9uV29ybGQueSwgLSBfbGlnaHRQb3NpdGlvbldvcmxkLnogKTtcblxuXHRcdF9wcm9qU2NyZWVuTWF0cml4Lm11bHRpcGx5TWF0cmljZXMoIGNhbWVyYS5wcm9qZWN0aW9uTWF0cml4LCBjYW1lcmEubWF0cml4V29ybGRJbnZlcnNlICk7XG5cdFx0dGhpcy5fZnJ1c3R1bS5zZXRGcm9tUHJvamVjdGlvbk1hdHJpeCggX3Byb2pTY3JlZW5NYXRyaXggKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgUG9pbnRMaWdodCBleHRlbmRzIExpZ2h0IHtcblxuXHRjb25zdHJ1Y3RvciggY29sb3IsIGludGVuc2l0eSwgZGlzdGFuY2UgPSAwLCBkZWNheSA9IDIgKSB7XG5cblx0XHRzdXBlciggY29sb3IsIGludGVuc2l0eSApO1xuXG5cdFx0dGhpcy5pc1BvaW50TGlnaHQgPSB0cnVlO1xuXG5cdFx0dGhpcy50eXBlID0gJ1BvaW50TGlnaHQnO1xuXG5cdFx0dGhpcy5kaXN0YW5jZSA9IGRpc3RhbmNlO1xuXHRcdHRoaXMuZGVjYXkgPSBkZWNheTtcblxuXHRcdHRoaXMuc2hhZG93ID0gbmV3IFBvaW50TGlnaHRTaGFkb3coKTtcblxuXHR9XG5cblx0Z2V0IHBvd2VyKCkge1xuXG5cdFx0Ly8gY29tcHV0ZSB0aGUgbGlnaHQncyBsdW1pbm91cyBwb3dlciAoaW4gbHVtZW5zKSBmcm9tIGl0cyBpbnRlbnNpdHkgKGluIGNhbmRlbGEpXG5cdFx0Ly8gZm9yIGFuIGlzb3Ryb3BpYyBsaWdodCBzb3VyY2UsIGx1bWlub3VzIHBvd2VyIChsbSkgPSA0IM+AIGx1bWlub3VzIGludGVuc2l0eSAoY2QpXG5cdFx0cmV0dXJuIHRoaXMuaW50ZW5zaXR5ICogNCAqIE1hdGguUEk7XG5cblx0fVxuXG5cdHNldCBwb3dlciggcG93ZXIgKSB7XG5cblx0XHQvLyBzZXQgdGhlIGxpZ2h0J3MgaW50ZW5zaXR5IChpbiBjYW5kZWxhKSBmcm9tIHRoZSBkZXNpcmVkIGx1bWlub3VzIHBvd2VyIChpbiBsdW1lbnMpXG5cdFx0dGhpcy5pbnRlbnNpdHkgPSBwb3dlciAvICggNCAqIE1hdGguUEkgKTtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuc2hhZG93LmRpc3Bvc2UoKTtcblxuXHR9XG5cblx0Y29weSggc291cmNlLCByZWN1cnNpdmUgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApO1xuXG5cdFx0dGhpcy5kaXN0YW5jZSA9IHNvdXJjZS5kaXN0YW5jZTtcblx0XHR0aGlzLmRlY2F5ID0gc291cmNlLmRlY2F5O1xuXG5cdFx0dGhpcy5zaGFkb3cgPSBzb3VyY2Uuc2hhZG93LmNsb25lKCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY2xhc3MgRGlyZWN0aW9uYWxMaWdodFNoYWRvdyBleHRlbmRzIExpZ2h0U2hhZG93IHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCBuZXcgT3J0aG9ncmFwaGljQ2FtZXJhKCAtIDUsIDUsIDUsIC0gNSwgMC41LCA1MDAgKSApO1xuXG5cdFx0dGhpcy5pc0RpcmVjdGlvbmFsTGlnaHRTaGFkb3cgPSB0cnVlO1xuXG5cdH1cblxufVxuXG5jbGFzcyBEaXJlY3Rpb25hbExpZ2h0IGV4dGVuZHMgTGlnaHQge1xuXG5cdGNvbnN0cnVjdG9yKCBjb2xvciwgaW50ZW5zaXR5ICkge1xuXG5cdFx0c3VwZXIoIGNvbG9yLCBpbnRlbnNpdHkgKTtcblxuXHRcdHRoaXMuaXNEaXJlY3Rpb25hbExpZ2h0ID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdEaXJlY3Rpb25hbExpZ2h0JztcblxuXHRcdHRoaXMucG9zaXRpb24uY29weSggT2JqZWN0M0QuREVGQVVMVF9VUCApO1xuXHRcdHRoaXMudXBkYXRlTWF0cml4KCk7XG5cblx0XHR0aGlzLnRhcmdldCA9IG5ldyBPYmplY3QzRCgpO1xuXG5cdFx0dGhpcy5zaGFkb3cgPSBuZXcgRGlyZWN0aW9uYWxMaWdodFNoYWRvdygpO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5zaGFkb3cuZGlzcG9zZSgpO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMudGFyZ2V0ID0gc291cmNlLnRhcmdldC5jbG9uZSgpO1xuXHRcdHRoaXMuc2hhZG93ID0gc291cmNlLnNoYWRvdy5jbG9uZSgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIEFtYmllbnRMaWdodCBleHRlbmRzIExpZ2h0IHtcblxuXHRjb25zdHJ1Y3RvciggY29sb3IsIGludGVuc2l0eSApIHtcblxuXHRcdHN1cGVyKCBjb2xvciwgaW50ZW5zaXR5ICk7XG5cblx0XHR0aGlzLmlzQW1iaWVudExpZ2h0ID0gdHJ1ZTtcblxuXHRcdHRoaXMudHlwZSA9ICdBbWJpZW50TGlnaHQnO1xuXG5cdH1cblxufVxuXG5jbGFzcyBSZWN0QXJlYUxpZ2h0IGV4dGVuZHMgTGlnaHQge1xuXG5cdGNvbnN0cnVjdG9yKCBjb2xvciwgaW50ZW5zaXR5LCB3aWR0aCA9IDEwLCBoZWlnaHQgPSAxMCApIHtcblxuXHRcdHN1cGVyKCBjb2xvciwgaW50ZW5zaXR5ICk7XG5cblx0XHR0aGlzLmlzUmVjdEFyZWFMaWdodCA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnUmVjdEFyZWFMaWdodCc7XG5cblx0XHR0aGlzLndpZHRoID0gd2lkdGg7XG5cdFx0dGhpcy5oZWlnaHQgPSBoZWlnaHQ7XG5cblx0fVxuXG5cdGdldCBwb3dlcigpIHtcblxuXHRcdC8vIGNvbXB1dGUgdGhlIGxpZ2h0J3MgbHVtaW5vdXMgcG93ZXIgKGluIGx1bWVucykgZnJvbSBpdHMgaW50ZW5zaXR5IChpbiBuaXRzKVxuXHRcdHJldHVybiB0aGlzLmludGVuc2l0eSAqIHRoaXMud2lkdGggKiB0aGlzLmhlaWdodCAqIE1hdGguUEk7XG5cblx0fVxuXG5cdHNldCBwb3dlciggcG93ZXIgKSB7XG5cblx0XHQvLyBzZXQgdGhlIGxpZ2h0J3MgaW50ZW5zaXR5IChpbiBuaXRzKSBmcm9tIHRoZSBkZXNpcmVkIGx1bWlub3VzIHBvd2VyIChpbiBsdW1lbnMpXG5cdFx0dGhpcy5pbnRlbnNpdHkgPSBwb3dlciAvICggdGhpcy53aWR0aCAqIHRoaXMuaGVpZ2h0ICogTWF0aC5QSSApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMud2lkdGggPSBzb3VyY2Uud2lkdGg7XG5cdFx0dGhpcy5oZWlnaHQgPSBzb3VyY2UuaGVpZ2h0O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTiggbWV0YSApIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oIG1ldGEgKTtcblxuXHRcdGRhdGEub2JqZWN0LndpZHRoID0gdGhpcy53aWR0aDtcblx0XHRkYXRhLm9iamVjdC5oZWlnaHQgPSB0aGlzLmhlaWdodDtcblxuXHRcdHJldHVybiBkYXRhO1xuXG5cdH1cblxufVxuXG4vKipcbiAqIFByaW1hcnkgcmVmZXJlbmNlOlxuICogICBodHRwczovL2dyYXBoaWNzLnN0YW5mb3JkLmVkdS9wYXBlcnMvZW52bWFwL2Vudm1hcC5wZGZcbiAqXG4gKiBTZWNvbmRhcnkgcmVmZXJlbmNlOlxuICogICBodHRwczovL3d3dy5wcHNsb2FuLm9yZy9wdWJsaWNhdGlvbnMvU3R1cGlkU0gzNi5wZGZcbiAqL1xuXG4vLyAzLWJhbmQgU0ggZGVmaW5lZCBieSA5IGNvZWZmaWNpZW50c1xuXG5jbGFzcyBTcGhlcmljYWxIYXJtb25pY3MzIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHRoaXMuaXNTcGhlcmljYWxIYXJtb25pY3MzID0gdHJ1ZTtcblxuXHRcdHRoaXMuY29lZmZpY2llbnRzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmNvZWZmaWNpZW50cy5wdXNoKCBuZXcgVmVjdG9yMygpICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHNldCggY29lZmZpY2llbnRzICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5jb2VmZmljaWVudHNbIGkgXS5jb3B5KCBjb2VmZmljaWVudHNbIGkgXSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHplcm8oKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmNvZWZmaWNpZW50c1sgaSBdLnNldCggMCwgMCwgMCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIGdldCB0aGUgcmFkaWFuY2UgaW4gdGhlIGRpcmVjdGlvbiBvZiB0aGUgbm9ybWFsXG5cdC8vIHRhcmdldCBpcyBhIFZlY3RvcjNcblx0Z2V0QXQoIG5vcm1hbCwgdGFyZ2V0ICkge1xuXG5cdFx0Ly8gbm9ybWFsIGlzIGFzc3VtZWQgdG8gYmUgdW5pdCBsZW5ndGhcblxuXHRcdGNvbnN0IHggPSBub3JtYWwueCwgeSA9IG5vcm1hbC55LCB6ID0gbm9ybWFsLno7XG5cblx0XHRjb25zdCBjb2VmZiA9IHRoaXMuY29lZmZpY2llbnRzO1xuXG5cdFx0Ly8gYmFuZCAwXG5cdFx0dGFyZ2V0LmNvcHkoIGNvZWZmWyAwIF0gKS5tdWx0aXBseVNjYWxhciggMC4yODIwOTUgKTtcblxuXHRcdC8vIGJhbmQgMVxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyAxIF0sIDAuNDg4NjAzICogeSApO1xuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyAyIF0sIDAuNDg4NjAzICogeiApO1xuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyAzIF0sIDAuNDg4NjAzICogeCApO1xuXG5cdFx0Ly8gYmFuZCAyXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDQgXSwgMS4wOTI1NDggKiAoIHggKiB5ICkgKTtcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNSBdLCAxLjA5MjU0OCAqICggeSAqIHogKSApO1xuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA2IF0sIDAuMzE1MzkyICogKCAzLjAgKiB6ICogeiAtIDEuMCApICk7XG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDcgXSwgMS4wOTI1NDggKiAoIHggKiB6ICkgKTtcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgOCBdLCAwLjU0NjI3NCAqICggeCAqIHggLSB5ICogeSApICk7XG5cblx0XHRyZXR1cm4gdGFyZ2V0O1xuXG5cdH1cblxuXHQvLyBnZXQgdGhlIGlycmFkaWFuY2UgKHJhZGlhbmNlIGNvbnZvbHZlZCB3aXRoIGNvc2luZSBsb2JlKSBpbiB0aGUgZGlyZWN0aW9uIG9mIHRoZSBub3JtYWxcblx0Ly8gdGFyZ2V0IGlzIGEgVmVjdG9yM1xuXHQvLyBodHRwczovL2dyYXBoaWNzLnN0YW5mb3JkLmVkdS9wYXBlcnMvZW52bWFwL2Vudm1hcC5wZGZcblx0Z2V0SXJyYWRpYW5jZUF0KCBub3JtYWwsIHRhcmdldCApIHtcblxuXHRcdC8vIG5vcm1hbCBpcyBhc3N1bWVkIHRvIGJlIHVuaXQgbGVuZ3RoXG5cblx0XHRjb25zdCB4ID0gbm9ybWFsLngsIHkgPSBub3JtYWwueSwgeiA9IG5vcm1hbC56O1xuXG5cdFx0Y29uc3QgY29lZmYgPSB0aGlzLmNvZWZmaWNpZW50cztcblxuXHRcdC8vIGJhbmQgMFxuXHRcdHRhcmdldC5jb3B5KCBjb2VmZlsgMCBdICkubXVsdGlwbHlTY2FsYXIoIDAuODg2MjI3ICk7IC8vIM+AICogMC4yODIwOTVcblxuXHRcdC8vIGJhbmQgMVxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyAxIF0sIDIuMCAqIDAuNTExNjY0ICogeSApOyAvLyAoIDIgKiDPgCAvIDMgKSAqIDAuNDg4NjAzXG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDIgXSwgMi4wICogMC41MTE2NjQgKiB6ICk7XG5cdFx0dGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggY29lZmZbIDMgXSwgMi4wICogMC41MTE2NjQgKiB4ICk7XG5cblx0XHQvLyBiYW5kIDJcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNCBdLCAyLjAgKiAwLjQyOTA0MyAqIHggKiB5ICk7IC8vICggz4AgLyA0ICkgKiAxLjA5MjU0OFxuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA1IF0sIDIuMCAqIDAuNDI5MDQzICogeSAqIHogKTtcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgNiBdLCAwLjc0MzEyNSAqIHogKiB6IC0gMC4yNDc3MDggKTsgLy8gKCDPgCAvIDQgKSAqIDAuMzE1MzkyICogM1xuXHRcdHRhcmdldC5hZGRTY2FsZWRWZWN0b3IoIGNvZWZmWyA3IF0sIDIuMCAqIDAuNDI5MDQzICogeCAqIHogKTtcblx0XHR0YXJnZXQuYWRkU2NhbGVkVmVjdG9yKCBjb2VmZlsgOCBdLCAwLjQyOTA0MyAqICggeCAqIHggLSB5ICogeSApICk7IC8vICggz4AgLyA0ICkgKiAwLjU0NjI3NFxuXG5cdFx0cmV0dXJuIHRhcmdldDtcblxuXHR9XG5cblx0YWRkKCBzaCApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0uYWRkKCBzaC5jb2VmZmljaWVudHNbIGkgXSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGFkZFNjYWxlZFNIKCBzaCwgcyApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0uYWRkU2NhbGVkVmVjdG9yKCBzaC5jb2VmZmljaWVudHNbIGkgXSwgcyApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNjYWxlKCBzICkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgOTsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5jb2VmZmljaWVudHNbIGkgXS5tdWx0aXBseVNjYWxhciggcyApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGxlcnAoIHNoLCBhbHBoYSApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuY29lZmZpY2llbnRzWyBpIF0ubGVycCggc2guY29lZmZpY2llbnRzWyBpIF0sIGFscGhhICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZXF1YWxzKCBzaCApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDk7IGkgKysgKSB7XG5cblx0XHRcdGlmICggISB0aGlzLmNvZWZmaWNpZW50c1sgaSBdLmVxdWFscyggc2guY29lZmZpY2llbnRzWyBpIF0gKSApIHtcblxuXHRcdFx0XHRyZXR1cm4gZmFsc2U7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0cnVlO1xuXG5cdH1cblxuXHRjb3B5KCBzaCApIHtcblxuXHRcdHJldHVybiB0aGlzLnNldCggc2guY29lZmZpY2llbnRzICk7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxuXHRmcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgPSAwICkge1xuXG5cdFx0Y29uc3QgY29lZmZpY2llbnRzID0gdGhpcy5jb2VmZmljaWVudHM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xuXG5cdFx0XHRjb2VmZmljaWVudHNbIGkgXS5mcm9tQXJyYXkoIGFycmF5LCBvZmZzZXQgKyAoIGkgKiAzICkgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0FycmF5KCBhcnJheSA9IFtdLCBvZmZzZXQgPSAwICkge1xuXG5cdFx0Y29uc3QgY29lZmZpY2llbnRzID0gdGhpcy5jb2VmZmljaWVudHM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCA5OyBpICsrICkge1xuXG5cdFx0XHRjb2VmZmljaWVudHNbIGkgXS50b0FycmF5KCBhcnJheSwgb2Zmc2V0ICsgKCBpICogMyApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gYXJyYXk7XG5cblx0fVxuXG5cdC8vIGV2YWx1YXRlIHRoZSBiYXNpcyBmdW5jdGlvbnNcblx0Ly8gc2hCYXNpcyBpcyBhbiBBcnJheVsgOSBdXG5cdHN0YXRpYyBnZXRCYXNpc0F0KCBub3JtYWwsIHNoQmFzaXMgKSB7XG5cblx0XHQvLyBub3JtYWwgaXMgYXNzdW1lZCB0byBiZSB1bml0IGxlbmd0aFxuXG5cdFx0Y29uc3QgeCA9IG5vcm1hbC54LCB5ID0gbm9ybWFsLnksIHogPSBub3JtYWwuejtcblxuXHRcdC8vIGJhbmQgMFxuXHRcdHNoQmFzaXNbIDAgXSA9IDAuMjgyMDk1O1xuXG5cdFx0Ly8gYmFuZCAxXG5cdFx0c2hCYXNpc1sgMSBdID0gMC40ODg2MDMgKiB5O1xuXHRcdHNoQmFzaXNbIDIgXSA9IDAuNDg4NjAzICogejtcblx0XHRzaEJhc2lzWyAzIF0gPSAwLjQ4ODYwMyAqIHg7XG5cblx0XHQvLyBiYW5kIDJcblx0XHRzaEJhc2lzWyA0IF0gPSAxLjA5MjU0OCAqIHggKiB5O1xuXHRcdHNoQmFzaXNbIDUgXSA9IDEuMDkyNTQ4ICogeSAqIHo7XG5cdFx0c2hCYXNpc1sgNiBdID0gMC4zMTUzOTIgKiAoIDMgKiB6ICogeiAtIDEgKTtcblx0XHRzaEJhc2lzWyA3IF0gPSAxLjA5MjU0OCAqIHggKiB6O1xuXHRcdHNoQmFzaXNbIDggXSA9IDAuNTQ2Mjc0ICogKCB4ICogeCAtIHkgKiB5ICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIExpZ2h0UHJvYmUgZXh0ZW5kcyBMaWdodCB7XG5cblx0Y29uc3RydWN0b3IoIHNoID0gbmV3IFNwaGVyaWNhbEhhcm1vbmljczMoKSwgaW50ZW5zaXR5ID0gMSApIHtcblxuXHRcdHN1cGVyKCB1bmRlZmluZWQsIGludGVuc2l0eSApO1xuXG5cdFx0dGhpcy5pc0xpZ2h0UHJvYmUgPSB0cnVlO1xuXG5cdFx0dGhpcy5zaCA9IHNoO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuc2guY29weSggc291cmNlLnNoICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZnJvbUpTT04oIGpzb24gKSB7XG5cblx0XHR0aGlzLmludGVuc2l0eSA9IGpzb24uaW50ZW5zaXR5OyAvLyBUT0RPOiBNb3ZlIHRoaXMgYml0IHRvIExpZ2h0LmZyb21KU09OKCk7XG5cdFx0dGhpcy5zaC5mcm9tQXJyYXkoIGpzb24uc2ggKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0b0pTT04oIG1ldGEgKSB7XG5cblx0XHRjb25zdCBkYXRhID0gc3VwZXIudG9KU09OKCBtZXRhICk7XG5cblx0XHRkYXRhLm9iamVjdC5zaCA9IHRoaXMuc2gudG9BcnJheSgpO1xuXG5cdFx0cmV0dXJuIGRhdGE7XG5cblx0fVxuXG59XG5cbmNsYXNzIE1hdGVyaWFsTG9hZGVyIGV4dGVuZHMgTG9hZGVyIHtcblxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcblxuXHRcdHN1cGVyKCBtYW5hZ2VyICk7XG5cdFx0dGhpcy50ZXh0dXJlcyA9IHt9O1xuXG5cdH1cblxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdGNvbnN0IGxvYWRlciA9IG5ldyBGaWxlTG9hZGVyKCBzY29wZS5tYW5hZ2VyICk7XG5cdFx0bG9hZGVyLnNldFBhdGgoIHNjb3BlLnBhdGggKTtcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggc2NvcGUucmVxdWVzdEhlYWRlciApO1xuXHRcdGxvYWRlci5zZXRXaXRoQ3JlZGVudGlhbHMoIHNjb3BlLndpdGhDcmVkZW50aWFscyApO1xuXHRcdGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICggdGV4dCApIHtcblxuXHRcdFx0dHJ5IHtcblxuXHRcdFx0XHRvbkxvYWQoIHNjb3BlLnBhcnNlKCBKU09OLnBhcnNlKCB0ZXh0ICkgKSApO1xuXG5cdFx0XHR9IGNhdGNoICggZSApIHtcblxuXHRcdFx0XHRpZiAoIG9uRXJyb3IgKSB7XG5cblx0XHRcdFx0XHRvbkVycm9yKCBlICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoIGUgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xuXG5cdFx0XHR9XG5cblx0XHR9LCBvblByb2dyZXNzLCBvbkVycm9yICk7XG5cblx0fVxuXG5cdHBhcnNlKCBqc29uICkge1xuXG5cdFx0Y29uc3QgdGV4dHVyZXMgPSB0aGlzLnRleHR1cmVzO1xuXG5cdFx0ZnVuY3Rpb24gZ2V0VGV4dHVyZSggbmFtZSApIHtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlc1sgbmFtZSBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuTWF0ZXJpYWxMb2FkZXI6IFVuZGVmaW5lZCB0ZXh0dXJlJywgbmFtZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJldHVybiB0ZXh0dXJlc1sgbmFtZSBdO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBNYXRlcmlhbExvYWRlci5jcmVhdGVNYXRlcmlhbEZyb21UeXBlKCBqc29uLnR5cGUgKTtcblxuXHRcdGlmICgganNvbi51dWlkICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC51dWlkID0ganNvbi51dWlkO1xuXHRcdGlmICgganNvbi5uYW1lICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5uYW1lID0ganNvbi5uYW1lO1xuXHRcdGlmICgganNvbi5jb2xvciAhPT0gdW5kZWZpbmVkICYmIG1hdGVyaWFsLmNvbG9yICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jb2xvci5zZXRIZXgoIGpzb24uY29sb3IgKTtcblx0XHRpZiAoIGpzb24ucm91Z2huZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5yb3VnaG5lc3MgPSBqc29uLnJvdWdobmVzcztcblx0XHRpZiAoIGpzb24ubWV0YWxuZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5tZXRhbG5lc3MgPSBqc29uLm1ldGFsbmVzcztcblx0XHRpZiAoIGpzb24uc2hlZW4gIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNoZWVuID0ganNvbi5zaGVlbjtcblx0XHRpZiAoIGpzb24uc2hlZW5Db2xvciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2hlZW5Db2xvciA9IG5ldyBDb2xvcigpLnNldEhleCgganNvbi5zaGVlbkNvbG9yICk7XG5cdFx0aWYgKCBqc29uLnNoZWVuUm91Z2huZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGVlblJvdWdobmVzcyA9IGpzb24uc2hlZW5Sb3VnaG5lc3M7XG5cdFx0aWYgKCBqc29uLmVtaXNzaXZlICE9PSB1bmRlZmluZWQgJiYgbWF0ZXJpYWwuZW1pc3NpdmUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmVtaXNzaXZlLnNldEhleCgganNvbi5lbWlzc2l2ZSApO1xuXHRcdGlmICgganNvbi5zcGVjdWxhciAhPT0gdW5kZWZpbmVkICYmIG1hdGVyaWFsLnNwZWN1bGFyICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zcGVjdWxhci5zZXRIZXgoIGpzb24uc3BlY3VsYXIgKTtcblx0XHRpZiAoIGpzb24uc3BlY3VsYXJJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFySW50ZW5zaXR5ID0ganNvbi5zcGVjdWxhckludGVuc2l0eTtcblx0XHRpZiAoIGpzb24uc3BlY3VsYXJDb2xvciAhPT0gdW5kZWZpbmVkICYmIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFyQ29sb3Iuc2V0SGV4KCBqc29uLnNwZWN1bGFyQ29sb3IgKTtcblx0XHRpZiAoIGpzb24uc2hpbmluZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGluaW5lc3MgPSBqc29uLnNoaW5pbmVzcztcblx0XHRpZiAoIGpzb24uY2xlYXJjb2F0ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGVhcmNvYXQgPSBqc29uLmNsZWFyY29hdDtcblx0XHRpZiAoIGpzb24uY2xlYXJjb2F0Um91Z2huZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGVhcmNvYXRSb3VnaG5lc3MgPSBqc29uLmNsZWFyY29hdFJvdWdobmVzcztcblx0XHRpZiAoIGpzb24uZGlzcGVyc2lvbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZGlzcGVyc2lvbiA9IGpzb24uZGlzcGVyc2lvbjtcblx0XHRpZiAoIGpzb24uaXJpZGVzY2VuY2UgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmlyaWRlc2NlbmNlID0ganNvbi5pcmlkZXNjZW5jZTtcblx0XHRpZiAoIGpzb24uaXJpZGVzY2VuY2VJT1IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmlyaWRlc2NlbmNlSU9SID0ganNvbi5pcmlkZXNjZW5jZUlPUjtcblx0XHRpZiAoIGpzb24uaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZSA9IGpzb24uaXJpZGVzY2VuY2VUaGlja25lc3NSYW5nZTtcblx0XHRpZiAoIGpzb24udHJhbnNtaXNzaW9uICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC50cmFuc21pc3Npb24gPSBqc29uLnRyYW5zbWlzc2lvbjtcblx0XHRpZiAoIGpzb24udGhpY2tuZXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC50aGlja25lc3MgPSBqc29uLnRoaWNrbmVzcztcblx0XHRpZiAoIGpzb24uYXR0ZW51YXRpb25EaXN0YW5jZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYXR0ZW51YXRpb25EaXN0YW5jZSA9IGpzb24uYXR0ZW51YXRpb25EaXN0YW5jZTtcblx0XHRpZiAoIGpzb24uYXR0ZW51YXRpb25Db2xvciAhPT0gdW5kZWZpbmVkICYmIG1hdGVyaWFsLmF0dGVudWF0aW9uQ29sb3IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmF0dGVudWF0aW9uQ29sb3Iuc2V0SGV4KCBqc29uLmF0dGVudWF0aW9uQ29sb3IgKTtcblx0XHRpZiAoIGpzb24uYW5pc290cm9weSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYW5pc290cm9weSA9IGpzb24uYW5pc290cm9weTtcblx0XHRpZiAoIGpzb24uYW5pc290cm9weVJvdGF0aW9uICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hbmlzb3Ryb3B5Um90YXRpb24gPSBqc29uLmFuaXNvdHJvcHlSb3RhdGlvbjtcblx0XHRpZiAoIGpzb24uZm9nICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5mb2cgPSBqc29uLmZvZztcblx0XHRpZiAoIGpzb24uZmxhdFNoYWRpbmcgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmZsYXRTaGFkaW5nID0ganNvbi5mbGF0U2hhZGluZztcblx0XHRpZiAoIGpzb24uYmxlbmRpbmcgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmJsZW5kaW5nID0ganNvbi5ibGVuZGluZztcblx0XHRpZiAoIGpzb24uY29tYmluZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuY29tYmluZSA9IGpzb24uY29tYmluZTtcblx0XHRpZiAoIGpzb24uc2lkZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2lkZSA9IGpzb24uc2lkZTtcblx0XHRpZiAoIGpzb24uc2hhZG93U2lkZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2hhZG93U2lkZSA9IGpzb24uc2hhZG93U2lkZTtcblx0XHRpZiAoIGpzb24ub3BhY2l0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwub3BhY2l0eSA9IGpzb24ub3BhY2l0eTtcblx0XHRpZiAoIGpzb24udHJhbnNwYXJlbnQgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnRyYW5zcGFyZW50ID0ganNvbi50cmFuc3BhcmVudDtcblx0XHRpZiAoIGpzb24uYWxwaGFUZXN0ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hbHBoYVRlc3QgPSBqc29uLmFscGhhVGVzdDtcblx0XHRpZiAoIGpzb24uYWxwaGFIYXNoICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hbHBoYUhhc2ggPSBqc29uLmFscGhhSGFzaDtcblx0XHRpZiAoIGpzb24uZGVwdGhGdW5jICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kZXB0aEZ1bmMgPSBqc29uLmRlcHRoRnVuYztcblx0XHRpZiAoIGpzb24uZGVwdGhUZXN0ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kZXB0aFRlc3QgPSBqc29uLmRlcHRoVGVzdDtcblx0XHRpZiAoIGpzb24uZGVwdGhXcml0ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZGVwdGhXcml0ZSA9IGpzb24uZGVwdGhXcml0ZTtcblx0XHRpZiAoIGpzb24uY29sb3JXcml0ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuY29sb3JXcml0ZSA9IGpzb24uY29sb3JXcml0ZTtcblx0XHRpZiAoIGpzb24uYmxlbmRTcmMgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmJsZW5kU3JjID0ganNvbi5ibGVuZFNyYztcblx0XHRpZiAoIGpzb24uYmxlbmREc3QgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmJsZW5kRHN0ID0ganNvbi5ibGVuZERzdDtcblx0XHRpZiAoIGpzb24uYmxlbmRFcXVhdGlvbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRFcXVhdGlvbiA9IGpzb24uYmxlbmRFcXVhdGlvbjtcblx0XHRpZiAoIGpzb24uYmxlbmRTcmNBbHBoYSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRTcmNBbHBoYSA9IGpzb24uYmxlbmRTcmNBbHBoYTtcblx0XHRpZiAoIGpzb24uYmxlbmREc3RBbHBoYSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmREc3RBbHBoYSA9IGpzb24uYmxlbmREc3RBbHBoYTtcblx0XHRpZiAoIGpzb24uYmxlbmRFcXVhdGlvbkFscGhhICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ibGVuZEVxdWF0aW9uQWxwaGEgPSBqc29uLmJsZW5kRXF1YXRpb25BbHBoYTtcblx0XHRpZiAoIGpzb24uYmxlbmRDb2xvciAhPT0gdW5kZWZpbmVkICYmIG1hdGVyaWFsLmJsZW5kQ29sb3IgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmJsZW5kQ29sb3Iuc2V0SGV4KCBqc29uLmJsZW5kQ29sb3IgKTtcblx0XHRpZiAoIGpzb24uYmxlbmRBbHBoYSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYmxlbmRBbHBoYSA9IGpzb24uYmxlbmRBbHBoYTtcblx0XHRpZiAoIGpzb24uc3RlbmNpbFdyaXRlTWFzayAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbFdyaXRlTWFzayA9IGpzb24uc3RlbmNpbFdyaXRlTWFzaztcblx0XHRpZiAoIGpzb24uc3RlbmNpbEZ1bmMgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnN0ZW5jaWxGdW5jID0ganNvbi5zdGVuY2lsRnVuYztcblx0XHRpZiAoIGpzb24uc3RlbmNpbFJlZiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc3RlbmNpbFJlZiA9IGpzb24uc3RlbmNpbFJlZjtcblx0XHRpZiAoIGpzb24uc3RlbmNpbEZ1bmNNYXNrICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zdGVuY2lsRnVuY01hc2sgPSBqc29uLnN0ZW5jaWxGdW5jTWFzaztcblx0XHRpZiAoIGpzb24uc3RlbmNpbEZhaWwgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnN0ZW5jaWxGYWlsID0ganNvbi5zdGVuY2lsRmFpbDtcblx0XHRpZiAoIGpzb24uc3RlbmNpbFpGYWlsICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zdGVuY2lsWkZhaWwgPSBqc29uLnN0ZW5jaWxaRmFpbDtcblx0XHRpZiAoIGpzb24uc3RlbmNpbFpQYXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zdGVuY2lsWlBhc3MgPSBqc29uLnN0ZW5jaWxaUGFzcztcblx0XHRpZiAoIGpzb24uc3RlbmNpbFdyaXRlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zdGVuY2lsV3JpdGUgPSBqc29uLnN0ZW5jaWxXcml0ZTtcblxuXHRcdGlmICgganNvbi53aXJlZnJhbWUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLndpcmVmcmFtZSA9IGpzb24ud2lyZWZyYW1lO1xuXHRcdGlmICgganNvbi53aXJlZnJhbWVMaW5ld2lkdGggIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLndpcmVmcmFtZUxpbmV3aWR0aCA9IGpzb24ud2lyZWZyYW1lTGluZXdpZHRoO1xuXHRcdGlmICgganNvbi53aXJlZnJhbWVMaW5lY2FwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC53aXJlZnJhbWVMaW5lY2FwID0ganNvbi53aXJlZnJhbWVMaW5lY2FwO1xuXHRcdGlmICgganNvbi53aXJlZnJhbWVMaW5lam9pbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwud2lyZWZyYW1lTGluZWpvaW4gPSBqc29uLndpcmVmcmFtZUxpbmVqb2luO1xuXG5cdFx0aWYgKCBqc29uLnJvdGF0aW9uICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5yb3RhdGlvbiA9IGpzb24ucm90YXRpb247XG5cblx0XHRpZiAoIGpzb24ubGluZXdpZHRoICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5saW5ld2lkdGggPSBqc29uLmxpbmV3aWR0aDtcblx0XHRpZiAoIGpzb24uZGFzaFNpemUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRhc2hTaXplID0ganNvbi5kYXNoU2l6ZTtcblx0XHRpZiAoIGpzb24uZ2FwU2l6ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZ2FwU2l6ZSA9IGpzb24uZ2FwU2l6ZTtcblx0XHRpZiAoIGpzb24uc2NhbGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNjYWxlID0ganNvbi5zY2FsZTtcblxuXHRcdGlmICgganNvbi5wb2x5Z29uT2Zmc2V0ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5wb2x5Z29uT2Zmc2V0ID0ganNvbi5wb2x5Z29uT2Zmc2V0O1xuXHRcdGlmICgganNvbi5wb2x5Z29uT2Zmc2V0RmFjdG9yICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5wb2x5Z29uT2Zmc2V0RmFjdG9yID0ganNvbi5wb2x5Z29uT2Zmc2V0RmFjdG9yO1xuXHRcdGlmICgganNvbi5wb2x5Z29uT2Zmc2V0VW5pdHMgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnBvbHlnb25PZmZzZXRVbml0cyA9IGpzb24ucG9seWdvbk9mZnNldFVuaXRzO1xuXG5cdFx0aWYgKCBqc29uLmRpdGhlcmluZyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZGl0aGVyaW5nID0ganNvbi5kaXRoZXJpbmc7XG5cblx0XHRpZiAoIGpzb24uYWxwaGFUb0NvdmVyYWdlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5hbHBoYVRvQ292ZXJhZ2UgPSBqc29uLmFscGhhVG9Db3ZlcmFnZTtcblx0XHRpZiAoIGpzb24ucHJlbXVsdGlwbGllZEFscGhhICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5wcmVtdWx0aXBsaWVkQWxwaGEgPSBqc29uLnByZW11bHRpcGxpZWRBbHBoYTtcblx0XHRpZiAoIGpzb24uZm9yY2VTaW5nbGVQYXNzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5mb3JjZVNpbmdsZVBhc3MgPSBqc29uLmZvcmNlU2luZ2xlUGFzcztcblxuXHRcdGlmICgganNvbi52aXNpYmxlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC52aXNpYmxlID0ganNvbi52aXNpYmxlO1xuXG5cdFx0aWYgKCBqc29uLnRvbmVNYXBwZWQgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnRvbmVNYXBwZWQgPSBqc29uLnRvbmVNYXBwZWQ7XG5cblx0XHRpZiAoIGpzb24udXNlckRhdGEgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnVzZXJEYXRhID0ganNvbi51c2VyRGF0YTtcblxuXHRcdGlmICgganNvbi52ZXJ0ZXhDb2xvcnMgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0aWYgKCB0eXBlb2YganNvbi52ZXJ0ZXhDb2xvcnMgPT09ICdudW1iZXInICkge1xuXG5cdFx0XHRcdG1hdGVyaWFsLnZlcnRleENvbG9ycyA9ICgganNvbi52ZXJ0ZXhDb2xvcnMgPiAwICkgPyB0cnVlIDogZmFsc2U7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0bWF0ZXJpYWwudmVydGV4Q29sb3JzID0ganNvbi52ZXJ0ZXhDb2xvcnM7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIFNoYWRlciBNYXRlcmlhbFxuXG5cdFx0aWYgKCBqc29uLnVuaWZvcm1zICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGZvciAoIGNvbnN0IG5hbWUgaW4ganNvbi51bmlmb3JtcyApIHtcblxuXHRcdFx0XHRjb25zdCB1bmlmb3JtID0ganNvbi51bmlmb3Jtc1sgbmFtZSBdO1xuXG5cdFx0XHRcdG1hdGVyaWFsLnVuaWZvcm1zWyBuYW1lIF0gPSB7fTtcblxuXHRcdFx0XHRzd2l0Y2ggKCB1bmlmb3JtLnR5cGUgKSB7XG5cblx0XHRcdFx0XHRjYXNlICd0Jzpcblx0XHRcdFx0XHRcdG1hdGVyaWFsLnVuaWZvcm1zWyBuYW1lIF0udmFsdWUgPSBnZXRUZXh0dXJlKCB1bmlmb3JtLnZhbHVlICk7XG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdGNhc2UgJ2MnOlxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwudW5pZm9ybXNbIG5hbWUgXS52YWx1ZSA9IG5ldyBDb2xvcigpLnNldEhleCggdW5pZm9ybS52YWx1ZSApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRjYXNlICd2Mic6XG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IFZlY3RvcjIoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0Y2FzZSAndjMnOlxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwudW5pZm9ybXNbIG5hbWUgXS52YWx1ZSA9IG5ldyBWZWN0b3IzKCkuZnJvbUFycmF5KCB1bmlmb3JtLnZhbHVlICk7XG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdGNhc2UgJ3Y0Jzpcblx0XHRcdFx0XHRcdG1hdGVyaWFsLnVuaWZvcm1zWyBuYW1lIF0udmFsdWUgPSBuZXcgVmVjdG9yNCgpLmZyb21BcnJheSggdW5pZm9ybS52YWx1ZSApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRjYXNlICdtMyc6XG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gbmV3IE1hdHJpeDMoKS5mcm9tQXJyYXkoIHVuaWZvcm0udmFsdWUgKTtcblx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0Y2FzZSAnbTQnOlxuXHRcdFx0XHRcdFx0bWF0ZXJpYWwudW5pZm9ybXNbIG5hbWUgXS52YWx1ZSA9IG5ldyBNYXRyaXg0KCkuZnJvbUFycmF5KCB1bmlmb3JtLnZhbHVlICk7XG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdGRlZmF1bHQ6XG5cdFx0XHRcdFx0XHRtYXRlcmlhbC51bmlmb3Jtc1sgbmFtZSBdLnZhbHVlID0gdW5pZm9ybS52YWx1ZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICgganNvbi5kZWZpbmVzICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kZWZpbmVzID0ganNvbi5kZWZpbmVzO1xuXHRcdGlmICgganNvbi52ZXJ0ZXhTaGFkZXIgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnZlcnRleFNoYWRlciA9IGpzb24udmVydGV4U2hhZGVyO1xuXHRcdGlmICgganNvbi5mcmFnbWVudFNoYWRlciAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZnJhZ21lbnRTaGFkZXIgPSBqc29uLmZyYWdtZW50U2hhZGVyO1xuXHRcdGlmICgganNvbi5nbHNsVmVyc2lvbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZ2xzbFZlcnNpb24gPSBqc29uLmdsc2xWZXJzaW9uO1xuXG5cdFx0aWYgKCBqc29uLmV4dGVuc2lvbnMgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Zm9yICggY29uc3Qga2V5IGluIGpzb24uZXh0ZW5zaW9ucyApIHtcblxuXHRcdFx0XHRtYXRlcmlhbC5leHRlbnNpb25zWyBrZXkgXSA9IGpzb24uZXh0ZW5zaW9uc1sga2V5IF07XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICgganNvbi5saWdodHMgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmxpZ2h0cyA9IGpzb24ubGlnaHRzO1xuXHRcdGlmICgganNvbi5jbGlwcGluZyAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuY2xpcHBpbmcgPSBqc29uLmNsaXBwaW5nO1xuXG5cdFx0Ly8gZm9yIFBvaW50c01hdGVyaWFsXG5cblx0XHRpZiAoIGpzb24uc2l6ZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuc2l6ZSA9IGpzb24uc2l6ZTtcblx0XHRpZiAoIGpzb24uc2l6ZUF0dGVudWF0aW9uICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaXplQXR0ZW51YXRpb24gPSBqc29uLnNpemVBdHRlbnVhdGlvbjtcblxuXHRcdC8vIG1hcHNcblxuXHRcdGlmICgganNvbi5tYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLm1hcCA9IGdldFRleHR1cmUoIGpzb24ubWFwICk7XG5cdFx0aWYgKCBqc29uLm1hdGNhcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwubWF0Y2FwID0gZ2V0VGV4dHVyZSgganNvbi5tYXRjYXAgKTtcblxuXHRcdGlmICgganNvbi5hbHBoYU1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYWxwaGFNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmFscGhhTWFwICk7XG5cblx0XHRpZiAoIGpzb24uYnVtcE1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYnVtcE1hcCA9IGdldFRleHR1cmUoIGpzb24uYnVtcE1hcCApO1xuXHRcdGlmICgganNvbi5idW1wU2NhbGUgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmJ1bXBTY2FsZSA9IGpzb24uYnVtcFNjYWxlO1xuXG5cdFx0aWYgKCBqc29uLm5vcm1hbE1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwubm9ybWFsTWFwID0gZ2V0VGV4dHVyZSgganNvbi5ub3JtYWxNYXAgKTtcblx0XHRpZiAoIGpzb24ubm9ybWFsTWFwVHlwZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwubm9ybWFsTWFwVHlwZSA9IGpzb24ubm9ybWFsTWFwVHlwZTtcblx0XHRpZiAoIGpzb24ubm9ybWFsU2NhbGUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0bGV0IG5vcm1hbFNjYWxlID0ganNvbi5ub3JtYWxTY2FsZTtcblxuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBub3JtYWxTY2FsZSApID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHQvLyBCbGVuZGVyIGV4cG9ydGVyIHVzZWQgdG8gZXhwb3J0IGEgc2NhbGFyLiBTZWUgIzc0NTlcblxuXHRcdFx0XHRub3JtYWxTY2FsZSA9IFsgbm9ybWFsU2NhbGUsIG5vcm1hbFNjYWxlIF07XG5cblx0XHRcdH1cblxuXHRcdFx0bWF0ZXJpYWwubm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMigpLmZyb21BcnJheSggbm9ybWFsU2NhbGUgKTtcblxuXHRcdH1cblxuXHRcdGlmICgganNvbi5kaXNwbGFjZW1lbnRNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRpc3BsYWNlbWVudE1hcCA9IGdldFRleHR1cmUoIGpzb24uZGlzcGxhY2VtZW50TWFwICk7XG5cdFx0aWYgKCBqc29uLmRpc3BsYWNlbWVudFNjYWxlICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5kaXNwbGFjZW1lbnRTY2FsZSA9IGpzb24uZGlzcGxhY2VtZW50U2NhbGU7XG5cdFx0aWYgKCBqc29uLmRpc3BsYWNlbWVudEJpYXMgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmRpc3BsYWNlbWVudEJpYXMgPSBqc29uLmRpc3BsYWNlbWVudEJpYXM7XG5cblx0XHRpZiAoIGpzb24ucm91Z2huZXNzTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5yb3VnaG5lc3NNYXAgPSBnZXRUZXh0dXJlKCBqc29uLnJvdWdobmVzc01hcCApO1xuXHRcdGlmICgganNvbi5tZXRhbG5lc3NNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLm1ldGFsbmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24ubWV0YWxuZXNzTWFwICk7XG5cblx0XHRpZiAoIGpzb24uZW1pc3NpdmVNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmVtaXNzaXZlTWFwID0gZ2V0VGV4dHVyZSgganNvbi5lbWlzc2l2ZU1hcCApO1xuXHRcdGlmICgganNvbi5lbWlzc2l2ZUludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZW1pc3NpdmVJbnRlbnNpdHkgPSBqc29uLmVtaXNzaXZlSW50ZW5zaXR5O1xuXG5cdFx0aWYgKCBqc29uLnNwZWN1bGFyTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zcGVjdWxhck1hcCA9IGdldFRleHR1cmUoIGpzb24uc3BlY3VsYXJNYXAgKTtcblx0XHRpZiAoIGpzb24uc3BlY3VsYXJJbnRlbnNpdHlNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLnNwZWN1bGFySW50ZW5zaXR5TWFwID0gZ2V0VGV4dHVyZSgganNvbi5zcGVjdWxhckludGVuc2l0eU1hcCApO1xuXHRcdGlmICgganNvbi5zcGVjdWxhckNvbG9yTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zcGVjdWxhckNvbG9yTWFwID0gZ2V0VGV4dHVyZSgganNvbi5zcGVjdWxhckNvbG9yTWFwICk7XG5cblx0XHRpZiAoIGpzb24uZW52TWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5lbnZNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmVudk1hcCApO1xuXHRcdGlmICgganNvbi5lbnZNYXBSb3RhdGlvbiAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZW52TWFwUm90YXRpb24uZnJvbUFycmF5KCBqc29uLmVudk1hcFJvdGF0aW9uICk7XG5cdFx0aWYgKCBqc29uLmVudk1hcEludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuZW52TWFwSW50ZW5zaXR5ID0ganNvbi5lbnZNYXBJbnRlbnNpdHk7XG5cblx0XHRpZiAoIGpzb24ucmVmbGVjdGl2aXR5ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5yZWZsZWN0aXZpdHkgPSBqc29uLnJlZmxlY3Rpdml0eTtcblx0XHRpZiAoIGpzb24ucmVmcmFjdGlvblJhdGlvICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5yZWZyYWN0aW9uUmF0aW8gPSBqc29uLnJlZnJhY3Rpb25SYXRpbztcblxuXHRcdGlmICgganNvbi5saWdodE1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwubGlnaHRNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmxpZ2h0TWFwICk7XG5cdFx0aWYgKCBqc29uLmxpZ2h0TWFwSW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5saWdodE1hcEludGVuc2l0eSA9IGpzb24ubGlnaHRNYXBJbnRlbnNpdHk7XG5cblx0XHRpZiAoIGpzb24uYW9NYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFvTWFwID0gZ2V0VGV4dHVyZSgganNvbi5hb01hcCApO1xuXHRcdGlmICgganNvbi5hb01hcEludGVuc2l0eSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuYW9NYXBJbnRlbnNpdHkgPSBqc29uLmFvTWFwSW50ZW5zaXR5O1xuXG5cdFx0aWYgKCBqc29uLmdyYWRpZW50TWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5ncmFkaWVudE1hcCA9IGdldFRleHR1cmUoIGpzb24uZ3JhZGllbnRNYXAgKTtcblxuXHRcdGlmICgganNvbi5jbGVhcmNvYXRNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmNsZWFyY29hdE1hcCA9IGdldFRleHR1cmUoIGpzb24uY2xlYXJjb2F0TWFwICk7XG5cdFx0aWYgKCBqc29uLmNsZWFyY29hdFJvdWdobmVzc01hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuY2xlYXJjb2F0Um91Z2huZXNzTWFwID0gZ2V0VGV4dHVyZSgganNvbi5jbGVhcmNvYXRSb3VnaG5lc3NNYXAgKTtcblx0XHRpZiAoIGpzb24uY2xlYXJjb2F0Tm9ybWFsTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5jbGVhcmNvYXROb3JtYWxNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmNsZWFyY29hdE5vcm1hbE1hcCApO1xuXHRcdGlmICgganNvbi5jbGVhcmNvYXROb3JtYWxTY2FsZSAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwuY2xlYXJjb2F0Tm9ybWFsU2NhbGUgPSBuZXcgVmVjdG9yMigpLmZyb21BcnJheSgganNvbi5jbGVhcmNvYXROb3JtYWxTY2FsZSApO1xuXG5cdFx0aWYgKCBqc29uLmlyaWRlc2NlbmNlTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5pcmlkZXNjZW5jZU1hcCA9IGdldFRleHR1cmUoIGpzb24uaXJpZGVzY2VuY2VNYXAgKTtcblx0XHRpZiAoIGpzb24uaXJpZGVzY2VuY2VUaGlja25lc3NNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmlyaWRlc2NlbmNlVGhpY2tuZXNzTWFwID0gZ2V0VGV4dHVyZSgganNvbi5pcmlkZXNjZW5jZVRoaWNrbmVzc01hcCApO1xuXG5cdFx0aWYgKCBqc29uLnRyYW5zbWlzc2lvbk1hcCAhPT0gdW5kZWZpbmVkICkgbWF0ZXJpYWwudHJhbnNtaXNzaW9uTWFwID0gZ2V0VGV4dHVyZSgganNvbi50cmFuc21pc3Npb25NYXAgKTtcblx0XHRpZiAoIGpzb24udGhpY2tuZXNzTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC50aGlja25lc3NNYXAgPSBnZXRUZXh0dXJlKCBqc29uLnRoaWNrbmVzc01hcCApO1xuXG5cdFx0aWYgKCBqc29uLmFuaXNvdHJvcHlNYXAgIT09IHVuZGVmaW5lZCApIG1hdGVyaWFsLmFuaXNvdHJvcHlNYXAgPSBnZXRUZXh0dXJlKCBqc29uLmFuaXNvdHJvcHlNYXAgKTtcblxuXHRcdGlmICgganNvbi5zaGVlbkNvbG9yTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGVlbkNvbG9yTWFwID0gZ2V0VGV4dHVyZSgganNvbi5zaGVlbkNvbG9yTWFwICk7XG5cdFx0aWYgKCBqc29uLnNoZWVuUm91Z2huZXNzTWFwICE9PSB1bmRlZmluZWQgKSBtYXRlcmlhbC5zaGVlblJvdWdobmVzc01hcCA9IGdldFRleHR1cmUoIGpzb24uc2hlZW5Sb3VnaG5lc3NNYXAgKTtcblxuXHRcdHJldHVybiBtYXRlcmlhbDtcblxuXHR9XG5cblx0c2V0VGV4dHVyZXMoIHZhbHVlICkge1xuXG5cdFx0dGhpcy50ZXh0dXJlcyA9IHZhbHVlO1xuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdGF0aWMgY3JlYXRlTWF0ZXJpYWxGcm9tVHlwZSggdHlwZSApIHtcblxuXHRcdGNvbnN0IG1hdGVyaWFsTGliID0ge1xuXHRcdFx0U2hhZG93TWF0ZXJpYWwsXG5cdFx0XHRTcHJpdGVNYXRlcmlhbCxcblx0XHRcdFJhd1NoYWRlck1hdGVyaWFsLFxuXHRcdFx0U2hhZGVyTWF0ZXJpYWwsXG5cdFx0XHRQb2ludHNNYXRlcmlhbCxcblx0XHRcdE1lc2hQaHlzaWNhbE1hdGVyaWFsLFxuXHRcdFx0TWVzaFN0YW5kYXJkTWF0ZXJpYWwsXG5cdFx0XHRNZXNoUGhvbmdNYXRlcmlhbCxcblx0XHRcdE1lc2hUb29uTWF0ZXJpYWwsXG5cdFx0XHRNZXNoTm9ybWFsTWF0ZXJpYWwsXG5cdFx0XHRNZXNoTGFtYmVydE1hdGVyaWFsLFxuXHRcdFx0TWVzaERlcHRoTWF0ZXJpYWwsXG5cdFx0XHRNZXNoRGlzdGFuY2VNYXRlcmlhbCxcblx0XHRcdE1lc2hCYXNpY01hdGVyaWFsLFxuXHRcdFx0TWVzaE1hdGNhcE1hdGVyaWFsLFxuXHRcdFx0TGluZURhc2hlZE1hdGVyaWFsLFxuXHRcdFx0TGluZUJhc2ljTWF0ZXJpYWwsXG5cdFx0XHRNYXRlcmlhbFxuXHRcdH07XG5cblx0XHRyZXR1cm4gbmV3IG1hdGVyaWFsTGliWyB0eXBlIF0oKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgTG9hZGVyVXRpbHMge1xuXG5cdHN0YXRpYyBkZWNvZGVUZXh0KCBhcnJheSApIHsgLy8gQGRlcHJlY2F0ZWQsIHIxNjVcblxuXHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkxvYWRlclV0aWxzOiBkZWNvZGVUZXh0KCkgaGFzIGJlZW4gZGVwcmVjYXRlZCB3aXRoIHIxNjUgYW5kIHdpbGwgYmUgcmVtb3ZlZCB3aXRoIHIxNzUuIFVzZSBUZXh0RGVjb2RlciBpbnN0ZWFkLicgKTtcblxuXHRcdGlmICggdHlwZW9mIFRleHREZWNvZGVyICE9PSAndW5kZWZpbmVkJyApIHtcblxuXHRcdFx0cmV0dXJuIG5ldyBUZXh0RGVjb2RlcigpLmRlY29kZSggYXJyYXkgKTtcblxuXHRcdH1cblxuXHRcdC8vIEF2b2lkIHRoZSBTdHJpbmcuZnJvbUNoYXJDb2RlLmFwcGx5KG51bGwsIGFycmF5KSBzaG9ydGN1dCwgd2hpY2hcblx0XHQvLyB0aHJvd3MgYSBcIm1heGltdW0gY2FsbCBzdGFjayBzaXplIGV4Y2VlZGVkXCIgZXJyb3IgZm9yIGxhcmdlIGFycmF5cy5cblxuXHRcdGxldCBzID0gJyc7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXJyYXkubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdC8vIEltcGxpY2l0bHkgYXNzdW1lcyBsaXR0bGUtZW5kaWFuLlxuXHRcdFx0cyArPSBTdHJpbmcuZnJvbUNoYXJDb2RlKCBhcnJheVsgaSBdICk7XG5cblx0XHR9XG5cblx0XHR0cnkge1xuXG5cdFx0XHQvLyBtZXJnZXMgbXVsdGktYnl0ZSB1dGYtOCBjaGFyYWN0ZXJzLlxuXG5cdFx0XHRyZXR1cm4gZGVjb2RlVVJJQ29tcG9uZW50KCBlc2NhcGUoIHMgKSApO1xuXG5cdFx0fSBjYXRjaCAoIGUgKSB7IC8vIHNlZSAjMTYzNThcblxuXHRcdFx0cmV0dXJuIHM7XG5cblx0XHR9XG5cblx0fVxuXG5cdHN0YXRpYyBleHRyYWN0VXJsQmFzZSggdXJsICkge1xuXG5cdFx0Y29uc3QgaW5kZXggPSB1cmwubGFzdEluZGV4T2YoICcvJyApO1xuXG5cdFx0aWYgKCBpbmRleCA9PT0gLSAxICkgcmV0dXJuICcuLyc7XG5cblx0XHRyZXR1cm4gdXJsLnNsaWNlKCAwLCBpbmRleCArIDEgKTtcblxuXHR9XG5cblx0c3RhdGljIHJlc29sdmVVUkwoIHVybCwgcGF0aCApIHtcblxuXHRcdC8vIEludmFsaWQgVVJMXG5cdFx0aWYgKCB0eXBlb2YgdXJsICE9PSAnc3RyaW5nJyB8fCB1cmwgPT09ICcnICkgcmV0dXJuICcnO1xuXG5cdFx0Ly8gSG9zdCBSZWxhdGl2ZSBVUkxcblx0XHRpZiAoIC9eaHR0cHM/OlxcL1xcLy9pLnRlc3QoIHBhdGggKSAmJiAvXlxcLy8udGVzdCggdXJsICkgKSB7XG5cblx0XHRcdHBhdGggPSBwYXRoLnJlcGxhY2UoIC8oXmh0dHBzPzpcXC9cXC9bXlxcL10rKS4qL2ksICckMScgKTtcblxuXHRcdH1cblxuXHRcdC8vIEFic29sdXRlIFVSTCBodHRwOi8vLGh0dHBzOi8vLC8vXG5cdFx0aWYgKCAvXihodHRwcz86KT9cXC9cXC8vaS50ZXN0KCB1cmwgKSApIHJldHVybiB1cmw7XG5cblx0XHQvLyBEYXRhIFVSSVxuXHRcdGlmICggL15kYXRhOi4qLC4qJC9pLnRlc3QoIHVybCApICkgcmV0dXJuIHVybDtcblxuXHRcdC8vIEJsb2IgVVJMXG5cdFx0aWYgKCAvXmJsb2I6LiokL2kudGVzdCggdXJsICkgKSByZXR1cm4gdXJsO1xuXG5cdFx0Ly8gUmVsYXRpdmUgVVJMXG5cdFx0cmV0dXJuIHBhdGggKyB1cmw7XG5cblx0fVxuXG59XG5cbmNsYXNzIEluc3RhbmNlZEJ1ZmZlckdlb21ldHJ5IGV4dGVuZHMgQnVmZmVyR2VvbWV0cnkge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMuaXNJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnknO1xuXHRcdHRoaXMuaW5zdGFuY2VDb3VudCA9IEluZmluaXR5O1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UgKTtcblxuXHRcdHRoaXMuaW5zdGFuY2VDb3VudCA9IHNvdXJjZS5pbnN0YW5jZUNvdW50O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHRvSlNPTigpIHtcblxuXHRcdGNvbnN0IGRhdGEgPSBzdXBlci50b0pTT04oKTtcblxuXHRcdGRhdGEuaW5zdGFuY2VDb3VudCA9IHRoaXMuaW5zdGFuY2VDb3VudDtcblxuXHRcdGRhdGEuaXNJbnN0YW5jZWRCdWZmZXJHZW9tZXRyeSA9IHRydWU7XG5cblx0XHRyZXR1cm4gZGF0YTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQnVmZmVyR2VvbWV0cnlMb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xuXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcblxuXHR9XG5cblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggc2NvcGUubWFuYWdlciApO1xuXHRcdGxvYWRlci5zZXRQYXRoKCBzY29wZS5wYXRoICk7XG5cdFx0bG9hZGVyLnNldFJlcXVlc3RIZWFkZXIoIHNjb3BlLnJlcXVlc3RIZWFkZXIgKTtcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCBzY29wZS53aXRoQ3JlZGVudGlhbHMgKTtcblx0XHRsb2FkZXIubG9hZCggdXJsLCBmdW5jdGlvbiAoIHRleHQgKSB7XG5cblx0XHRcdHRyeSB7XG5cblx0XHRcdFx0b25Mb2FkKCBzY29wZS5wYXJzZSggSlNPTi5wYXJzZSggdGV4dCApICkgKTtcblxuXHRcdFx0fSBjYXRjaCAoIGUgKSB7XG5cblx0XHRcdFx0aWYgKCBvbkVycm9yICkge1xuXG5cdFx0XHRcdFx0b25FcnJvciggZSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCBlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbUVycm9yKCB1cmwgKTtcblxuXHRcdFx0fVxuXG5cdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xuXG5cdH1cblxuXHRwYXJzZSgganNvbiApIHtcblxuXHRcdGNvbnN0IGludGVybGVhdmVkQnVmZmVyTWFwID0ge307XG5cdFx0Y29uc3QgYXJyYXlCdWZmZXJNYXAgPSB7fTtcblxuXHRcdGZ1bmN0aW9uIGdldEludGVybGVhdmVkQnVmZmVyKCBqc29uLCB1dWlkICkge1xuXG5cdFx0XHRpZiAoIGludGVybGVhdmVkQnVmZmVyTWFwWyB1dWlkIF0gIT09IHVuZGVmaW5lZCApIHJldHVybiBpbnRlcmxlYXZlZEJ1ZmZlck1hcFsgdXVpZCBdO1xuXG5cdFx0XHRjb25zdCBpbnRlcmxlYXZlZEJ1ZmZlcnMgPSBqc29uLmludGVybGVhdmVkQnVmZmVycztcblx0XHRcdGNvbnN0IGludGVybGVhdmVkQnVmZmVyID0gaW50ZXJsZWF2ZWRCdWZmZXJzWyB1dWlkIF07XG5cblx0XHRcdGNvbnN0IGJ1ZmZlciA9IGdldEFycmF5QnVmZmVyKCBqc29uLCBpbnRlcmxlYXZlZEJ1ZmZlci5idWZmZXIgKTtcblxuXHRcdFx0Y29uc3QgYXJyYXkgPSBnZXRUeXBlZEFycmF5KCBpbnRlcmxlYXZlZEJ1ZmZlci50eXBlLCBidWZmZXIgKTtcblx0XHRcdGNvbnN0IGliID0gbmV3IEludGVybGVhdmVkQnVmZmVyKCBhcnJheSwgaW50ZXJsZWF2ZWRCdWZmZXIuc3RyaWRlICk7XG5cdFx0XHRpYi51dWlkID0gaW50ZXJsZWF2ZWRCdWZmZXIudXVpZDtcblxuXHRcdFx0aW50ZXJsZWF2ZWRCdWZmZXJNYXBbIHV1aWQgXSA9IGliO1xuXG5cdFx0XHRyZXR1cm4gaWI7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBnZXRBcnJheUJ1ZmZlcigganNvbiwgdXVpZCApIHtcblxuXHRcdFx0aWYgKCBhcnJheUJ1ZmZlck1hcFsgdXVpZCBdICE9PSB1bmRlZmluZWQgKSByZXR1cm4gYXJyYXlCdWZmZXJNYXBbIHV1aWQgXTtcblxuXHRcdFx0Y29uc3QgYXJyYXlCdWZmZXJzID0ganNvbi5hcnJheUJ1ZmZlcnM7XG5cdFx0XHRjb25zdCBhcnJheUJ1ZmZlciA9IGFycmF5QnVmZmVyc1sgdXVpZCBdO1xuXG5cdFx0XHRjb25zdCBhYiA9IG5ldyBVaW50MzJBcnJheSggYXJyYXlCdWZmZXIgKS5idWZmZXI7XG5cblx0XHRcdGFycmF5QnVmZmVyTWFwWyB1dWlkIF0gPSBhYjtcblxuXHRcdFx0cmV0dXJuIGFiO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBqc29uLmlzSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkgPyBuZXcgSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnkoKSA6IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXG5cdFx0Y29uc3QgaW5kZXggPSBqc29uLmRhdGEuaW5kZXg7XG5cblx0XHRpZiAoIGluZGV4ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IHR5cGVkQXJyYXkgPSBnZXRUeXBlZEFycmF5KCBpbmRleC50eXBlLCBpbmRleC5hcnJheSApO1xuXHRcdFx0Z2VvbWV0cnkuc2V0SW5kZXgoIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIHR5cGVkQXJyYXksIDEgKSApO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgYXR0cmlidXRlcyA9IGpzb24uZGF0YS5hdHRyaWJ1dGVzO1xuXG5cdFx0Zm9yICggY29uc3Qga2V5IGluIGF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdGNvbnN0IGF0dHJpYnV0ZSA9IGF0dHJpYnV0ZXNbIGtleSBdO1xuXHRcdFx0bGV0IGJ1ZmZlckF0dHJpYnV0ZTtcblxuXHRcdFx0aWYgKCBhdHRyaWJ1dGUuaXNJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSApIHtcblxuXHRcdFx0XHRjb25zdCBpbnRlcmxlYXZlZEJ1ZmZlciA9IGdldEludGVybGVhdmVkQnVmZmVyKCBqc29uLmRhdGEsIGF0dHJpYnV0ZS5kYXRhICk7XG5cdFx0XHRcdGJ1ZmZlckF0dHJpYnV0ZSA9IG5ldyBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSggaW50ZXJsZWF2ZWRCdWZmZXIsIGF0dHJpYnV0ZS5pdGVtU2l6ZSwgYXR0cmlidXRlLm9mZnNldCwgYXR0cmlidXRlLm5vcm1hbGl6ZWQgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zdCB0eXBlZEFycmF5ID0gZ2V0VHlwZWRBcnJheSggYXR0cmlidXRlLnR5cGUsIGF0dHJpYnV0ZS5hcnJheSApO1xuXHRcdFx0XHRjb25zdCBidWZmZXJBdHRyaWJ1dGVDb25zdHIgPSBhdHRyaWJ1dGUuaXNJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUgPyBJbnN0YW5jZWRCdWZmZXJBdHRyaWJ1dGUgOiBCdWZmZXJBdHRyaWJ1dGU7XG5cdFx0XHRcdGJ1ZmZlckF0dHJpYnV0ZSA9IG5ldyBidWZmZXJBdHRyaWJ1dGVDb25zdHIoIHR5cGVkQXJyYXksIGF0dHJpYnV0ZS5pdGVtU2l6ZSwgYXR0cmlidXRlLm5vcm1hbGl6ZWQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGF0dHJpYnV0ZS5uYW1lICE9PSB1bmRlZmluZWQgKSBidWZmZXJBdHRyaWJ1dGUubmFtZSA9IGF0dHJpYnV0ZS5uYW1lO1xuXHRcdFx0aWYgKCBhdHRyaWJ1dGUudXNhZ2UgIT09IHVuZGVmaW5lZCApIGJ1ZmZlckF0dHJpYnV0ZS5zZXRVc2FnZSggYXR0cmlidXRlLnVzYWdlICk7XG5cblx0XHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSgga2V5LCBidWZmZXJBdHRyaWJ1dGUgKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IG1vcnBoQXR0cmlidXRlcyA9IGpzb24uZGF0YS5tb3JwaEF0dHJpYnV0ZXM7XG5cblx0XHRpZiAoIG1vcnBoQXR0cmlidXRlcyApIHtcblxuXHRcdFx0Zm9yICggY29uc3Qga2V5IGluIG1vcnBoQXR0cmlidXRlcyApIHtcblxuXHRcdFx0XHRjb25zdCBhdHRyaWJ1dGVBcnJheSA9IG1vcnBoQXR0cmlidXRlc1sga2V5IF07XG5cblx0XHRcdFx0Y29uc3QgYXJyYXkgPSBbXTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0gYXR0cmlidXRlQXJyYXkubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBhdHRyaWJ1dGUgPSBhdHRyaWJ1dGVBcnJheVsgaSBdO1xuXHRcdFx0XHRcdGxldCBidWZmZXJBdHRyaWJ1dGU7XG5cblx0XHRcdFx0XHRpZiAoIGF0dHJpYnV0ZS5pc0ludGVybGVhdmVkQnVmZmVyQXR0cmlidXRlICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBpbnRlcmxlYXZlZEJ1ZmZlciA9IGdldEludGVybGVhdmVkQnVmZmVyKCBqc29uLmRhdGEsIGF0dHJpYnV0ZS5kYXRhICk7XG5cdFx0XHRcdFx0XHRidWZmZXJBdHRyaWJ1dGUgPSBuZXcgSW50ZXJsZWF2ZWRCdWZmZXJBdHRyaWJ1dGUoIGludGVybGVhdmVkQnVmZmVyLCBhdHRyaWJ1dGUuaXRlbVNpemUsIGF0dHJpYnV0ZS5vZmZzZXQsIGF0dHJpYnV0ZS5ub3JtYWxpemVkICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRjb25zdCB0eXBlZEFycmF5ID0gZ2V0VHlwZWRBcnJheSggYXR0cmlidXRlLnR5cGUsIGF0dHJpYnV0ZS5hcnJheSApO1xuXHRcdFx0XHRcdFx0YnVmZmVyQXR0cmlidXRlID0gbmV3IEJ1ZmZlckF0dHJpYnV0ZSggdHlwZWRBcnJheSwgYXR0cmlidXRlLml0ZW1TaXplLCBhdHRyaWJ1dGUubm9ybWFsaXplZCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0aWYgKCBhdHRyaWJ1dGUubmFtZSAhPT0gdW5kZWZpbmVkICkgYnVmZmVyQXR0cmlidXRlLm5hbWUgPSBhdHRyaWJ1dGUubmFtZTtcblx0XHRcdFx0XHRhcnJheS5wdXNoKCBidWZmZXJBdHRyaWJ1dGUgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Z2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzWyBrZXkgXSA9IGFycmF5O1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRjb25zdCBtb3JwaFRhcmdldHNSZWxhdGl2ZSA9IGpzb24uZGF0YS5tb3JwaFRhcmdldHNSZWxhdGl2ZTtcblxuXHRcdGlmICggbW9ycGhUYXJnZXRzUmVsYXRpdmUgKSB7XG5cblx0XHRcdGdlb21ldHJ5Lm1vcnBoVGFyZ2V0c1JlbGF0aXZlID0gdHJ1ZTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGdyb3VwcyA9IGpzb24uZGF0YS5ncm91cHMgfHwganNvbi5kYXRhLmRyYXdjYWxscyB8fCBqc29uLmRhdGEub2Zmc2V0cztcblxuXHRcdGlmICggZ3JvdXBzICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGdyb3Vwcy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdFx0Y29uc3QgZ3JvdXAgPSBncm91cHNbIGkgXTtcblxuXHRcdFx0XHRnZW9tZXRyeS5hZGRHcm91cCggZ3JvdXAuc3RhcnQsIGdyb3VwLmNvdW50LCBncm91cC5tYXRlcmlhbEluZGV4ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGNvbnN0IGJvdW5kaW5nU3BoZXJlID0ganNvbi5kYXRhLmJvdW5kaW5nU3BoZXJlO1xuXG5cdFx0aWYgKCBib3VuZGluZ1NwaGVyZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjb25zdCBjZW50ZXIgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHRpZiAoIGJvdW5kaW5nU3BoZXJlLmNlbnRlciAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdGNlbnRlci5mcm9tQXJyYXkoIGJvdW5kaW5nU3BoZXJlLmNlbnRlciApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGdlb21ldHJ5LmJvdW5kaW5nU3BoZXJlID0gbmV3IFNwaGVyZSggY2VudGVyLCBib3VuZGluZ1NwaGVyZS5yYWRpdXMgKTtcblxuXHRcdH1cblxuXHRcdGlmICgganNvbi5uYW1lICkgZ2VvbWV0cnkubmFtZSA9IGpzb24ubmFtZTtcblx0XHRpZiAoIGpzb24udXNlckRhdGEgKSBnZW9tZXRyeS51c2VyRGF0YSA9IGpzb24udXNlckRhdGE7XG5cblx0XHRyZXR1cm4gZ2VvbWV0cnk7XG5cblx0fVxuXG59XG5cbmNsYXNzIE9iamVjdExvYWRlciBleHRlbmRzIExvYWRlciB7XG5cblx0Y29uc3RydWN0b3IoIG1hbmFnZXIgKSB7XG5cblx0XHRzdXBlciggbWFuYWdlciApO1xuXG5cdH1cblxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdGNvbnN0IHBhdGggPSAoIHRoaXMucGF0aCA9PT0gJycgKSA/IExvYWRlclV0aWxzLmV4dHJhY3RVcmxCYXNlKCB1cmwgKSA6IHRoaXMucGF0aDtcblx0XHR0aGlzLnJlc291cmNlUGF0aCA9IHRoaXMucmVzb3VyY2VQYXRoIHx8IHBhdGg7XG5cblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XG5cdFx0bG9hZGVyLnNldFBhdGgoIHRoaXMucGF0aCApO1xuXHRcdGxvYWRlci5zZXRSZXF1ZXN0SGVhZGVyKCB0aGlzLnJlcXVlc3RIZWFkZXIgKTtcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCB0aGlzLndpdGhDcmVkZW50aWFscyApO1xuXHRcdGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICggdGV4dCApIHtcblxuXHRcdFx0bGV0IGpzb24gPSBudWxsO1xuXG5cdFx0XHR0cnkge1xuXG5cdFx0XHRcdGpzb24gPSBKU09OLnBhcnNlKCB0ZXh0ICk7XG5cblx0XHRcdH0gY2F0Y2ggKCBlcnJvciApIHtcblxuXHRcdFx0XHRpZiAoIG9uRXJyb3IgIT09IHVuZGVmaW5lZCApIG9uRXJyb3IoIGVycm9yICk7XG5cblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFOk9iamVjdExvYWRlcjogQ2FuXFwndCBwYXJzZSAnICsgdXJsICsgJy4nLCBlcnJvci5tZXNzYWdlICk7XG5cblx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IG1ldGFkYXRhID0ganNvbi5tZXRhZGF0YTtcblxuXHRcdFx0aWYgKCBtZXRhZGF0YSA9PT0gdW5kZWZpbmVkIHx8IG1ldGFkYXRhLnR5cGUgPT09IHVuZGVmaW5lZCB8fCBtZXRhZGF0YS50eXBlLnRvTG93ZXJDYXNlKCkgPT09ICdnZW9tZXRyeScgKSB7XG5cblx0XHRcdFx0aWYgKCBvbkVycm9yICE9PSB1bmRlZmluZWQgKSBvbkVycm9yKCBuZXcgRXJyb3IoICdUSFJFRS5PYmplY3RMb2FkZXI6IENhblxcJ3QgbG9hZCAnICsgdXJsICkgKTtcblxuXHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBDYW5cXCd0IGxvYWQgJyArIHVybCApO1xuXHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdH1cblxuXHRcdFx0c2NvcGUucGFyc2UoIGpzb24sIG9uTG9hZCApO1xuXG5cdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xuXG5cdH1cblxuXHRhc3luYyBsb2FkQXN5bmMoIHVybCwgb25Qcm9ncmVzcyApIHtcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdGNvbnN0IHBhdGggPSAoIHRoaXMucGF0aCA9PT0gJycgKSA/IExvYWRlclV0aWxzLmV4dHJhY3RVcmxCYXNlKCB1cmwgKSA6IHRoaXMucGF0aDtcblx0XHR0aGlzLnJlc291cmNlUGF0aCA9IHRoaXMucmVzb3VyY2VQYXRoIHx8IHBhdGg7XG5cblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XG5cdFx0bG9hZGVyLnNldFBhdGgoIHRoaXMucGF0aCApO1xuXHRcdGxvYWRlci5zZXRSZXF1ZXN0SGVhZGVyKCB0aGlzLnJlcXVlc3RIZWFkZXIgKTtcblx0XHRsb2FkZXIuc2V0V2l0aENyZWRlbnRpYWxzKCB0aGlzLndpdGhDcmVkZW50aWFscyApO1xuXG5cdFx0Y29uc3QgdGV4dCA9IGF3YWl0IGxvYWRlci5sb2FkQXN5bmMoIHVybCwgb25Qcm9ncmVzcyApO1xuXG5cdFx0Y29uc3QganNvbiA9IEpTT04ucGFyc2UoIHRleHQgKTtcblxuXHRcdGNvbnN0IG1ldGFkYXRhID0ganNvbi5tZXRhZGF0YTtcblxuXHRcdGlmICggbWV0YWRhdGEgPT09IHVuZGVmaW5lZCB8fCBtZXRhZGF0YS50eXBlID09PSB1bmRlZmluZWQgfHwgbWV0YWRhdGEudHlwZS50b0xvd2VyQ2FzZSgpID09PSAnZ2VvbWV0cnknICkge1xuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdUSFJFRS5PYmplY3RMb2FkZXI6IENhblxcJ3QgbG9hZCAnICsgdXJsICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gYXdhaXQgc2NvcGUucGFyc2VBc3luYygganNvbiApO1xuXG5cdH1cblxuXHRwYXJzZSgganNvbiwgb25Mb2FkICkge1xuXG5cdFx0Y29uc3QgYW5pbWF0aW9ucyA9IHRoaXMucGFyc2VBbmltYXRpb25zKCBqc29uLmFuaW1hdGlvbnMgKTtcblx0XHRjb25zdCBzaGFwZXMgPSB0aGlzLnBhcnNlU2hhcGVzKCBqc29uLnNoYXBlcyApO1xuXHRcdGNvbnN0IGdlb21ldHJpZXMgPSB0aGlzLnBhcnNlR2VvbWV0cmllcygganNvbi5nZW9tZXRyaWVzLCBzaGFwZXMgKTtcblxuXHRcdGNvbnN0IGltYWdlcyA9IHRoaXMucGFyc2VJbWFnZXMoIGpzb24uaW1hZ2VzLCBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdGlmICggb25Mb2FkICE9PSB1bmRlZmluZWQgKSBvbkxvYWQoIG9iamVjdCApO1xuXG5cdFx0fSApO1xuXG5cdFx0Y29uc3QgdGV4dHVyZXMgPSB0aGlzLnBhcnNlVGV4dHVyZXMoIGpzb24udGV4dHVyZXMsIGltYWdlcyApO1xuXHRcdGNvbnN0IG1hdGVyaWFscyA9IHRoaXMucGFyc2VNYXRlcmlhbHMoIGpzb24ubWF0ZXJpYWxzLCB0ZXh0dXJlcyApO1xuXG5cdFx0Y29uc3Qgb2JqZWN0ID0gdGhpcy5wYXJzZU9iamVjdCgganNvbi5vYmplY3QsIGdlb21ldHJpZXMsIG1hdGVyaWFscywgdGV4dHVyZXMsIGFuaW1hdGlvbnMgKTtcblx0XHRjb25zdCBza2VsZXRvbnMgPSB0aGlzLnBhcnNlU2tlbGV0b25zKCBqc29uLnNrZWxldG9ucywgb2JqZWN0ICk7XG5cblx0XHR0aGlzLmJpbmRTa2VsZXRvbnMoIG9iamVjdCwgc2tlbGV0b25zICk7XG5cdFx0dGhpcy5iaW5kTGlnaHRUYXJnZXRzKCBvYmplY3QgKTtcblxuXHRcdC8vXG5cblx0XHRpZiAoIG9uTG9hZCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRsZXQgaGFzSW1hZ2VzID0gZmFsc2U7XG5cblx0XHRcdGZvciAoIGNvbnN0IHV1aWQgaW4gaW1hZ2VzICkge1xuXG5cdFx0XHRcdGlmICggaW1hZ2VzWyB1dWlkIF0uZGF0YSBpbnN0YW5jZW9mIEhUTUxJbWFnZUVsZW1lbnQgKSB7XG5cblx0XHRcdFx0XHRoYXNJbWFnZXMgPSB0cnVlO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIGhhc0ltYWdlcyA9PT0gZmFsc2UgKSBvbkxvYWQoIG9iamVjdCApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG9iamVjdDtcblxuXHR9XG5cblx0YXN5bmMgcGFyc2VBc3luYygganNvbiApIHtcblxuXHRcdGNvbnN0IGFuaW1hdGlvbnMgPSB0aGlzLnBhcnNlQW5pbWF0aW9ucygganNvbi5hbmltYXRpb25zICk7XG5cdFx0Y29uc3Qgc2hhcGVzID0gdGhpcy5wYXJzZVNoYXBlcygganNvbi5zaGFwZXMgKTtcblx0XHRjb25zdCBnZW9tZXRyaWVzID0gdGhpcy5wYXJzZUdlb21ldHJpZXMoIGpzb24uZ2VvbWV0cmllcywgc2hhcGVzICk7XG5cblx0XHRjb25zdCBpbWFnZXMgPSBhd2FpdCB0aGlzLnBhcnNlSW1hZ2VzQXN5bmMoIGpzb24uaW1hZ2VzICk7XG5cblx0XHRjb25zdCB0ZXh0dXJlcyA9IHRoaXMucGFyc2VUZXh0dXJlcygganNvbi50ZXh0dXJlcywgaW1hZ2VzICk7XG5cdFx0Y29uc3QgbWF0ZXJpYWxzID0gdGhpcy5wYXJzZU1hdGVyaWFscygganNvbi5tYXRlcmlhbHMsIHRleHR1cmVzICk7XG5cblx0XHRjb25zdCBvYmplY3QgPSB0aGlzLnBhcnNlT2JqZWN0KCBqc29uLm9iamVjdCwgZ2VvbWV0cmllcywgbWF0ZXJpYWxzLCB0ZXh0dXJlcywgYW5pbWF0aW9ucyApO1xuXHRcdGNvbnN0IHNrZWxldG9ucyA9IHRoaXMucGFyc2VTa2VsZXRvbnMoIGpzb24uc2tlbGV0b25zLCBvYmplY3QgKTtcblxuXHRcdHRoaXMuYmluZFNrZWxldG9ucyggb2JqZWN0LCBza2VsZXRvbnMgKTtcblx0XHR0aGlzLmJpbmRMaWdodFRhcmdldHMoIG9iamVjdCApO1xuXG5cdFx0cmV0dXJuIG9iamVjdDtcblxuXHR9XG5cblx0cGFyc2VTaGFwZXMoIGpzb24gKSB7XG5cblx0XHRjb25zdCBzaGFwZXMgPSB7fTtcblxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2hhcGUgPSBuZXcgU2hhcGUoKS5mcm9tSlNPTigganNvblsgaSBdICk7XG5cblx0XHRcdFx0c2hhcGVzWyBzaGFwZS51dWlkIF0gPSBzaGFwZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHNoYXBlcztcblxuXHR9XG5cblx0cGFyc2VTa2VsZXRvbnMoIGpzb24sIG9iamVjdCApIHtcblxuXHRcdGNvbnN0IHNrZWxldG9ucyA9IHt9O1xuXHRcdGNvbnN0IGJvbmVzID0ge307XG5cblx0XHQvLyBnZW5lcmF0ZSBib25lIGxvb2t1cCB0YWJsZVxuXG5cdFx0b2JqZWN0LnRyYXZlcnNlKCBmdW5jdGlvbiAoIGNoaWxkICkge1xuXG5cdFx0XHRpZiAoIGNoaWxkLmlzQm9uZSApIGJvbmVzWyBjaGlsZC51dWlkIF0gPSBjaGlsZDtcblxuXHRcdH0gKTtcblxuXHRcdC8vIGNyZWF0ZSBza2VsZXRvbnNcblxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2tlbGV0b24gPSBuZXcgU2tlbGV0b24oKS5mcm9tSlNPTigganNvblsgaSBdLCBib25lcyApO1xuXG5cdFx0XHRcdHNrZWxldG9uc1sgc2tlbGV0b24udXVpZCBdID0gc2tlbGV0b247XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiBza2VsZXRvbnM7XG5cblx0fVxuXG5cdHBhcnNlR2VvbWV0cmllcygganNvbiwgc2hhcGVzICkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cmllcyA9IHt9O1xuXG5cdFx0aWYgKCBqc29uICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IGJ1ZmZlckdlb21ldHJ5TG9hZGVyID0gbmV3IEJ1ZmZlckdlb21ldHJ5TG9hZGVyKCk7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbCA9IGpzb24ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRsZXQgZ2VvbWV0cnk7XG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBqc29uWyBpIF07XG5cblx0XHRcdFx0c3dpdGNoICggZGF0YS50eXBlICkge1xuXG5cdFx0XHRcdFx0Y2FzZSAnQnVmZmVyR2VvbWV0cnknOlxuXHRcdFx0XHRcdGNhc2UgJ0luc3RhbmNlZEJ1ZmZlckdlb21ldHJ5JzpcblxuXHRcdFx0XHRcdFx0Z2VvbWV0cnkgPSBidWZmZXJHZW9tZXRyeUxvYWRlci5wYXJzZSggZGF0YSApO1xuXHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRkZWZhdWx0OlxuXG5cdFx0XHRcdFx0XHRpZiAoIGRhdGEudHlwZSBpbiBHZW9tZXRyaWVzICkge1xuXG5cdFx0XHRcdFx0XHRcdGdlb21ldHJ5ID0gR2VvbWV0cmllc1sgZGF0YS50eXBlIF0uZnJvbUpTT04oIGRhdGEsIHNoYXBlcyApO1xuXG5cdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggYFRIUkVFLk9iamVjdExvYWRlcjogVW5zdXBwb3J0ZWQgZ2VvbWV0cnkgdHlwZSBcIiR7IGRhdGEudHlwZSB9XCJgICk7XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Z2VvbWV0cnkudXVpZCA9IGRhdGEudXVpZDtcblxuXHRcdFx0XHRpZiAoIGRhdGEubmFtZSAhPT0gdW5kZWZpbmVkICkgZ2VvbWV0cnkubmFtZSA9IGRhdGEubmFtZTtcblx0XHRcdFx0aWYgKCBkYXRhLnVzZXJEYXRhICE9PSB1bmRlZmluZWQgKSBnZW9tZXRyeS51c2VyRGF0YSA9IGRhdGEudXNlckRhdGE7XG5cblx0XHRcdFx0Z2VvbWV0cmllc1sgZGF0YS51dWlkIF0gPSBnZW9tZXRyeTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGdlb21ldHJpZXM7XG5cblx0fVxuXG5cdHBhcnNlTWF0ZXJpYWxzKCBqc29uLCB0ZXh0dXJlcyApIHtcblxuXHRcdGNvbnN0IGNhY2hlID0ge307IC8vIE11bHRpTWF0ZXJpYWxcblx0XHRjb25zdCBtYXRlcmlhbHMgPSB7fTtcblxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjb25zdCBsb2FkZXIgPSBuZXcgTWF0ZXJpYWxMb2FkZXIoKTtcblx0XHRcdGxvYWRlci5zZXRUZXh0dXJlcyggdGV4dHVyZXMgKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0ganNvbi5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IGRhdGEgPSBqc29uWyBpIF07XG5cblx0XHRcdFx0aWYgKCBjYWNoZVsgZGF0YS51dWlkIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGNhY2hlWyBkYXRhLnV1aWQgXSA9IGxvYWRlci5wYXJzZSggZGF0YSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRtYXRlcmlhbHNbIGRhdGEudXVpZCBdID0gY2FjaGVbIGRhdGEudXVpZCBdO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gbWF0ZXJpYWxzO1xuXG5cdH1cblxuXHRwYXJzZUFuaW1hdGlvbnMoIGpzb24gKSB7XG5cblx0XHRjb25zdCBhbmltYXRpb25zID0ge307XG5cblx0XHRpZiAoIGpzb24gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwganNvbi5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgZGF0YSA9IGpzb25bIGkgXTtcblxuXHRcdFx0XHRjb25zdCBjbGlwID0gQW5pbWF0aW9uQ2xpcC5wYXJzZSggZGF0YSApO1xuXG5cdFx0XHRcdGFuaW1hdGlvbnNbIGNsaXAudXVpZCBdID0gY2xpcDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIGFuaW1hdGlvbnM7XG5cblx0fVxuXG5cdHBhcnNlSW1hZ2VzKCBqc29uLCBvbkxvYWQgKSB7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cdFx0Y29uc3QgaW1hZ2VzID0ge307XG5cblx0XHRsZXQgbG9hZGVyO1xuXG5cdFx0ZnVuY3Rpb24gbG9hZEltYWdlKCB1cmwgKSB7XG5cblx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbVN0YXJ0KCB1cmwgKTtcblxuXHRcdFx0cmV0dXJuIGxvYWRlci5sb2FkKCB1cmwsIGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xuXG5cdFx0XHR9LCB1bmRlZmluZWQsIGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FcnJvciggdXJsICk7XG5cdFx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbUVuZCggdXJsICk7XG5cblx0XHRcdH0gKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGRlc2VyaWFsaXplSW1hZ2UoIGltYWdlICkge1xuXG5cdFx0XHRpZiAoIHR5cGVvZiBpbWFnZSA9PT0gJ3N0cmluZycgKSB7XG5cblx0XHRcdFx0Y29uc3QgdXJsID0gaW1hZ2U7XG5cblx0XHRcdFx0Y29uc3QgcGF0aCA9IC9eKFxcL1xcLyl8KFthLXpdKzooXFwvXFwvKT8pL2kudGVzdCggdXJsICkgPyB1cmwgOiBzY29wZS5yZXNvdXJjZVBhdGggKyB1cmw7XG5cblx0XHRcdFx0cmV0dXJuIGxvYWRJbWFnZSggcGF0aCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGlmICggaW1hZ2UuZGF0YSApIHtcblxuXHRcdFx0XHRcdHJldHVybiB7XG5cdFx0XHRcdFx0XHRkYXRhOiBnZXRUeXBlZEFycmF5KCBpbWFnZS50eXBlLCBpbWFnZS5kYXRhICksXG5cdFx0XHRcdFx0XHR3aWR0aDogaW1hZ2Uud2lkdGgsXG5cdFx0XHRcdFx0XHRoZWlnaHQ6IGltYWdlLmhlaWdodFxuXHRcdFx0XHRcdH07XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHJldHVybiBudWxsO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBqc29uICE9PSB1bmRlZmluZWQgJiYganNvbi5sZW5ndGggPiAwICkge1xuXG5cdFx0XHRjb25zdCBtYW5hZ2VyID0gbmV3IExvYWRpbmdNYW5hZ2VyKCBvbkxvYWQgKTtcblxuXHRcdFx0bG9hZGVyID0gbmV3IEltYWdlTG9hZGVyKCBtYW5hZ2VyICk7XG5cdFx0XHRsb2FkZXIuc2V0Q3Jvc3NPcmlnaW4oIHRoaXMuY3Jvc3NPcmlnaW4gKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IGpzb24ubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgaW1hZ2UgPSBqc29uWyBpIF07XG5cdFx0XHRcdGNvbnN0IHVybCA9IGltYWdlLnVybDtcblxuXHRcdFx0XHRpZiAoIEFycmF5LmlzQXJyYXkoIHVybCApICkge1xuXG5cdFx0XHRcdFx0Ly8gbG9hZCBhcnJheSBvZiBpbWFnZXMgZS5nIEN1YmVUZXh0dXJlXG5cblx0XHRcdFx0XHRjb25zdCBpbWFnZUFycmF5ID0gW107XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIGpsID0gdXJsLmxlbmd0aDsgaiA8IGpsOyBqICsrICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBjdXJyZW50VXJsID0gdXJsWyBqIF07XG5cblx0XHRcdFx0XHRcdGNvbnN0IGRlc2VyaWFsaXplZEltYWdlID0gZGVzZXJpYWxpemVJbWFnZSggY3VycmVudFVybCApO1xuXG5cdFx0XHRcdFx0XHRpZiAoIGRlc2VyaWFsaXplZEltYWdlICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0XHRcdGlmICggZGVzZXJpYWxpemVkSW1hZ2UgaW5zdGFuY2VvZiBIVE1MSW1hZ2VFbGVtZW50ICkge1xuXG5cdFx0XHRcdFx0XHRcdFx0aW1hZ2VBcnJheS5wdXNoKCBkZXNlcmlhbGl6ZWRJbWFnZSApO1xuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHQvLyBzcGVjaWFsIGNhc2U6IGhhbmRsZSBhcnJheSBvZiBkYXRhIHRleHR1cmVzIGZvciBjdWJlIHRleHR1cmVzXG5cblx0XHRcdFx0XHRcdFx0XHRpbWFnZUFycmF5LnB1c2goIG5ldyBEYXRhVGV4dHVyZSggZGVzZXJpYWxpemVkSW1hZ2UuZGF0YSwgZGVzZXJpYWxpemVkSW1hZ2Uud2lkdGgsIGRlc2VyaWFsaXplZEltYWdlLmhlaWdodCApICk7XG5cblx0XHRcdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpbWFnZXNbIGltYWdlLnV1aWQgXSA9IG5ldyBTb3VyY2UoIGltYWdlQXJyYXkgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ly8gbG9hZCBzaW5nbGUgaW1hZ2VcblxuXHRcdFx0XHRcdGNvbnN0IGRlc2VyaWFsaXplZEltYWdlID0gZGVzZXJpYWxpemVJbWFnZSggaW1hZ2UudXJsICk7XG5cdFx0XHRcdFx0aW1hZ2VzWyBpbWFnZS51dWlkIF0gPSBuZXcgU291cmNlKCBkZXNlcmlhbGl6ZWRJbWFnZSApO1xuXG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gaW1hZ2VzO1xuXG5cdH1cblxuXHRhc3luYyBwYXJzZUltYWdlc0FzeW5jKCBqc29uICkge1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXHRcdGNvbnN0IGltYWdlcyA9IHt9O1xuXG5cdFx0bGV0IGxvYWRlcjtcblxuXHRcdGFzeW5jIGZ1bmN0aW9uIGRlc2VyaWFsaXplSW1hZ2UoIGltYWdlICkge1xuXG5cdFx0XHRpZiAoIHR5cGVvZiBpbWFnZSA9PT0gJ3N0cmluZycgKSB7XG5cblx0XHRcdFx0Y29uc3QgdXJsID0gaW1hZ2U7XG5cblx0XHRcdFx0Y29uc3QgcGF0aCA9IC9eKFxcL1xcLyl8KFthLXpdKzooXFwvXFwvKT8pL2kudGVzdCggdXJsICkgPyB1cmwgOiBzY29wZS5yZXNvdXJjZVBhdGggKyB1cmw7XG5cblx0XHRcdFx0cmV0dXJuIGF3YWl0IGxvYWRlci5sb2FkQXN5bmMoIHBhdGggKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRpZiAoIGltYWdlLmRhdGEgKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdFx0ZGF0YTogZ2V0VHlwZWRBcnJheSggaW1hZ2UudHlwZSwgaW1hZ2UuZGF0YSApLFxuXHRcdFx0XHRcdFx0d2lkdGg6IGltYWdlLndpZHRoLFxuXHRcdFx0XHRcdFx0aGVpZ2h0OiBpbWFnZS5oZWlnaHRcblx0XHRcdFx0XHR9O1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICYmIGpzb24ubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0bG9hZGVyID0gbmV3IEltYWdlTG9hZGVyKCB0aGlzLm1hbmFnZXIgKTtcblx0XHRcdGxvYWRlci5zZXRDcm9zc09yaWdpbiggdGhpcy5jcm9zc09yaWdpbiApO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGlsID0ganNvbi5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBpbWFnZSA9IGpzb25bIGkgXTtcblx0XHRcdFx0Y29uc3QgdXJsID0gaW1hZ2UudXJsO1xuXG5cdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggdXJsICkgKSB7XG5cblx0XHRcdFx0XHQvLyBsb2FkIGFycmF5IG9mIGltYWdlcyBlLmcgQ3ViZVRleHR1cmVcblxuXHRcdFx0XHRcdGNvbnN0IGltYWdlQXJyYXkgPSBbXTtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMCwgamwgPSB1cmwubGVuZ3RoOyBqIDwgamw7IGogKysgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGN1cnJlbnRVcmwgPSB1cmxbIGogXTtcblxuXHRcdFx0XHRcdFx0Y29uc3QgZGVzZXJpYWxpemVkSW1hZ2UgPSBhd2FpdCBkZXNlcmlhbGl6ZUltYWdlKCBjdXJyZW50VXJsICk7XG5cblx0XHRcdFx0XHRcdGlmICggZGVzZXJpYWxpemVkSW1hZ2UgIT09IG51bGwgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBkZXNlcmlhbGl6ZWRJbWFnZSBpbnN0YW5jZW9mIEhUTUxJbWFnZUVsZW1lbnQgKSB7XG5cblx0XHRcdFx0XHRcdFx0XHRpbWFnZUFycmF5LnB1c2goIGRlc2VyaWFsaXplZEltYWdlICk7XG5cblx0XHRcdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0XHRcdC8vIHNwZWNpYWwgY2FzZTogaGFuZGxlIGFycmF5IG9mIGRhdGEgdGV4dHVyZXMgZm9yIGN1YmUgdGV4dHVyZXNcblxuXHRcdFx0XHRcdFx0XHRcdGltYWdlQXJyYXkucHVzaCggbmV3IERhdGFUZXh0dXJlKCBkZXNlcmlhbGl6ZWRJbWFnZS5kYXRhLCBkZXNlcmlhbGl6ZWRJbWFnZS53aWR0aCwgZGVzZXJpYWxpemVkSW1hZ2UuaGVpZ2h0ICkgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGltYWdlc1sgaW1hZ2UudXVpZCBdID0gbmV3IFNvdXJjZSggaW1hZ2VBcnJheSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBsb2FkIHNpbmdsZSBpbWFnZVxuXG5cdFx0XHRcdFx0Y29uc3QgZGVzZXJpYWxpemVkSW1hZ2UgPSBhd2FpdCBkZXNlcmlhbGl6ZUltYWdlKCBpbWFnZS51cmwgKTtcblx0XHRcdFx0XHRpbWFnZXNbIGltYWdlLnV1aWQgXSA9IG5ldyBTb3VyY2UoIGRlc2VyaWFsaXplZEltYWdlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gaW1hZ2VzO1xuXG5cdH1cblxuXHRwYXJzZVRleHR1cmVzKCBqc29uLCBpbWFnZXMgKSB7XG5cblx0XHRmdW5jdGlvbiBwYXJzZUNvbnN0YW50KCB2YWx1ZSwgdHlwZSApIHtcblxuXHRcdFx0aWYgKCB0eXBlb2YgdmFsdWUgPT09ICdudW1iZXInICkgcmV0dXJuIHZhbHVlO1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXIucGFyc2VUZXh0dXJlOiBDb25zdGFudCBzaG91bGQgYmUgaW4gbnVtZXJpYyBmb3JtLicsIHZhbHVlICk7XG5cblx0XHRcdHJldHVybiB0eXBlWyB2YWx1ZSBdO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgdGV4dHVyZXMgPSB7fTtcblxuXHRcdGlmICgganNvbiAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBqc29uLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgZGF0YSA9IGpzb25bIGkgXTtcblxuXHRcdFx0XHRpZiAoIGRhdGEuaW1hZ2UgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLk9iamVjdExvYWRlcjogTm8gXCJpbWFnZVwiIHNwZWNpZmllZCBmb3InLCBkYXRhLnV1aWQgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBpbWFnZXNbIGRhdGEuaW1hZ2UgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBVbmRlZmluZWQgaW1hZ2UnLCBkYXRhLmltYWdlICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGNvbnN0IHNvdXJjZSA9IGltYWdlc1sgZGF0YS5pbWFnZSBdO1xuXHRcdFx0XHRjb25zdCBpbWFnZSA9IHNvdXJjZS5kYXRhO1xuXG5cdFx0XHRcdGxldCB0ZXh0dXJlO1xuXG5cdFx0XHRcdGlmICggQXJyYXkuaXNBcnJheSggaW1hZ2UgKSApIHtcblxuXHRcdFx0XHRcdHRleHR1cmUgPSBuZXcgQ3ViZVRleHR1cmUoKTtcblxuXHRcdFx0XHRcdGlmICggaW1hZ2UubGVuZ3RoID09PSA2ICkgdGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGlmICggaW1hZ2UgJiYgaW1hZ2UuZGF0YSApIHtcblxuXHRcdFx0XHRcdFx0dGV4dHVyZSA9IG5ldyBEYXRhVGV4dHVyZSgpO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0dGV4dHVyZSA9IG5ldyBUZXh0dXJlKCk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoIGltYWdlICkgdGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7IC8vIHRleHR1cmVzIGNhbiBoYXZlIHVuZGVmaW5lZCBpbWFnZSBkYXRhXG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRleHR1cmUuc291cmNlID0gc291cmNlO1xuXG5cdFx0XHRcdHRleHR1cmUudXVpZCA9IGRhdGEudXVpZDtcblxuXHRcdFx0XHRpZiAoIGRhdGEubmFtZSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5uYW1lID0gZGF0YS5uYW1lO1xuXG5cdFx0XHRcdGlmICggZGF0YS5tYXBwaW5nICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLm1hcHBpbmcgPSBwYXJzZUNvbnN0YW50KCBkYXRhLm1hcHBpbmcsIFRFWFRVUkVfTUFQUElORyApO1xuXHRcdFx0XHRpZiAoIGRhdGEuY2hhbm5lbCAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5jaGFubmVsID0gZGF0YS5jaGFubmVsO1xuXG5cdFx0XHRcdGlmICggZGF0YS5vZmZzZXQgIT09IHVuZGVmaW5lZCApIHRleHR1cmUub2Zmc2V0LmZyb21BcnJheSggZGF0YS5vZmZzZXQgKTtcblx0XHRcdFx0aWYgKCBkYXRhLnJlcGVhdCAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5yZXBlYXQuZnJvbUFycmF5KCBkYXRhLnJlcGVhdCApO1xuXHRcdFx0XHRpZiAoIGRhdGEuY2VudGVyICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmNlbnRlci5mcm9tQXJyYXkoIGRhdGEuY2VudGVyICk7XG5cdFx0XHRcdGlmICggZGF0YS5yb3RhdGlvbiAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5yb3RhdGlvbiA9IGRhdGEucm90YXRpb247XG5cblx0XHRcdFx0aWYgKCBkYXRhLndyYXAgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdHRleHR1cmUud3JhcFMgPSBwYXJzZUNvbnN0YW50KCBkYXRhLndyYXBbIDAgXSwgVEVYVFVSRV9XUkFQUElORyApO1xuXHRcdFx0XHRcdHRleHR1cmUud3JhcFQgPSBwYXJzZUNvbnN0YW50KCBkYXRhLndyYXBbIDEgXSwgVEVYVFVSRV9XUkFQUElORyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIGRhdGEuZm9ybWF0ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmZvcm1hdCA9IGRhdGEuZm9ybWF0O1xuXHRcdFx0XHRpZiAoIGRhdGEuaW50ZXJuYWxGb3JtYXQgIT09IHVuZGVmaW5lZCApIHRleHR1cmUuaW50ZXJuYWxGb3JtYXQgPSBkYXRhLmludGVybmFsRm9ybWF0O1xuXHRcdFx0XHRpZiAoIGRhdGEudHlwZSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS50eXBlID0gZGF0YS50eXBlO1xuXHRcdFx0XHRpZiAoIGRhdGEuY29sb3JTcGFjZSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5jb2xvclNwYWNlID0gZGF0YS5jb2xvclNwYWNlO1xuXG5cdFx0XHRcdGlmICggZGF0YS5taW5GaWx0ZXIgIT09IHVuZGVmaW5lZCApIHRleHR1cmUubWluRmlsdGVyID0gcGFyc2VDb25zdGFudCggZGF0YS5taW5GaWx0ZXIsIFRFWFRVUkVfRklMVEVSICk7XG5cdFx0XHRcdGlmICggZGF0YS5tYWdGaWx0ZXIgIT09IHVuZGVmaW5lZCApIHRleHR1cmUubWFnRmlsdGVyID0gcGFyc2VDb25zdGFudCggZGF0YS5tYWdGaWx0ZXIsIFRFWFRVUkVfRklMVEVSICk7XG5cdFx0XHRcdGlmICggZGF0YS5hbmlzb3Ryb3B5ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmFuaXNvdHJvcHkgPSBkYXRhLmFuaXNvdHJvcHk7XG5cblx0XHRcdFx0aWYgKCBkYXRhLmZsaXBZICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmZsaXBZID0gZGF0YS5mbGlwWTtcblxuXHRcdFx0XHRpZiAoIGRhdGEuZ2VuZXJhdGVNaXBtYXBzICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IGRhdGEuZ2VuZXJhdGVNaXBtYXBzO1xuXHRcdFx0XHRpZiAoIGRhdGEucHJlbXVsdGlwbHlBbHBoYSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS5wcmVtdWx0aXBseUFscGhhID0gZGF0YS5wcmVtdWx0aXBseUFscGhhO1xuXHRcdFx0XHRpZiAoIGRhdGEudW5wYWNrQWxpZ25tZW50ICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLnVucGFja0FsaWdubWVudCA9IGRhdGEudW5wYWNrQWxpZ25tZW50O1xuXHRcdFx0XHRpZiAoIGRhdGEuY29tcGFyZUZ1bmN0aW9uICE9PSB1bmRlZmluZWQgKSB0ZXh0dXJlLmNvbXBhcmVGdW5jdGlvbiA9IGRhdGEuY29tcGFyZUZ1bmN0aW9uO1xuXG5cdFx0XHRcdGlmICggZGF0YS51c2VyRGF0YSAhPT0gdW5kZWZpbmVkICkgdGV4dHVyZS51c2VyRGF0YSA9IGRhdGEudXNlckRhdGE7XG5cblx0XHRcdFx0dGV4dHVyZXNbIGRhdGEudXVpZCBdID0gdGV4dHVyZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRleHR1cmVzO1xuXG5cdH1cblxuXHRwYXJzZU9iamVjdCggZGF0YSwgZ2VvbWV0cmllcywgbWF0ZXJpYWxzLCB0ZXh0dXJlcywgYW5pbWF0aW9ucyApIHtcblxuXHRcdGxldCBvYmplY3Q7XG5cblx0XHRmdW5jdGlvbiBnZXRHZW9tZXRyeSggbmFtZSApIHtcblxuXHRcdFx0aWYgKCBnZW9tZXRyaWVzWyBuYW1lIF0gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXI6IFVuZGVmaW5lZCBnZW9tZXRyeScsIG5hbWUgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gZ2VvbWV0cmllc1sgbmFtZSBdO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gZ2V0TWF0ZXJpYWwoIG5hbWUgKSB7XG5cblx0XHRcdGlmICggbmFtZSA9PT0gdW5kZWZpbmVkICkgcmV0dXJuIHVuZGVmaW5lZDtcblxuXHRcdFx0aWYgKCBBcnJheS5pc0FycmF5KCBuYW1lICkgKSB7XG5cblx0XHRcdFx0Y29uc3QgYXJyYXkgPSBbXTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBuYW1lLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCB1dWlkID0gbmFtZVsgaSBdO1xuXG5cdFx0XHRcdFx0aWYgKCBtYXRlcmlhbHNbIHV1aWQgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5PYmplY3RMb2FkZXI6IFVuZGVmaW5lZCBtYXRlcmlhbCcsIHV1aWQgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGFycmF5LnB1c2goIG1hdGVyaWFsc1sgdXVpZCBdICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiBhcnJheTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIG1hdGVyaWFsc1sgbmFtZSBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBVbmRlZmluZWQgbWF0ZXJpYWwnLCBuYW1lICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIG1hdGVyaWFsc1sgbmFtZSBdO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gZ2V0VGV4dHVyZSggdXVpZCApIHtcblxuXHRcdFx0aWYgKCB0ZXh0dXJlc1sgdXVpZCBdID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBVbmRlZmluZWQgdGV4dHVyZScsIHV1aWQgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gdGV4dHVyZXNbIHV1aWQgXTtcblxuXHRcdH1cblxuXHRcdGxldCBnZW9tZXRyeSwgbWF0ZXJpYWw7XG5cblx0XHRzd2l0Y2ggKCBkYXRhLnR5cGUgKSB7XG5cblx0XHRcdGNhc2UgJ1NjZW5lJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgU2NlbmUoKTtcblxuXHRcdFx0XHRpZiAoIGRhdGEuYmFja2dyb3VuZCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0aWYgKCBOdW1iZXIuaXNJbnRlZ2VyKCBkYXRhLmJhY2tncm91bmQgKSApIHtcblxuXHRcdFx0XHRcdFx0b2JqZWN0LmJhY2tncm91bmQgPSBuZXcgQ29sb3IoIGRhdGEuYmFja2dyb3VuZCApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0b2JqZWN0LmJhY2tncm91bmQgPSBnZXRUZXh0dXJlKCBkYXRhLmJhY2tncm91bmQgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCBkYXRhLmVudmlyb25tZW50ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRvYmplY3QuZW52aXJvbm1lbnQgPSBnZXRUZXh0dXJlKCBkYXRhLmVudmlyb25tZW50ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggZGF0YS5mb2cgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGlmICggZGF0YS5mb2cudHlwZSA9PT0gJ0ZvZycgKSB7XG5cblx0XHRcdFx0XHRcdG9iamVjdC5mb2cgPSBuZXcgRm9nKCBkYXRhLmZvZy5jb2xvciwgZGF0YS5mb2cubmVhciwgZGF0YS5mb2cuZmFyICk7XG5cblx0XHRcdFx0XHR9IGVsc2UgaWYgKCBkYXRhLmZvZy50eXBlID09PSAnRm9nRXhwMicgKSB7XG5cblx0XHRcdFx0XHRcdG9iamVjdC5mb2cgPSBuZXcgRm9nRXhwMiggZGF0YS5mb2cuY29sb3IsIGRhdGEuZm9nLmRlbnNpdHkgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggZGF0YS5mb2cubmFtZSAhPT0gJycgKSB7XG5cblx0XHRcdFx0XHRcdG9iamVjdC5mb2cubmFtZSA9IGRhdGEuZm9nLm5hbWU7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggZGF0YS5iYWNrZ3JvdW5kQmx1cnJpbmVzcyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmJhY2tncm91bmRCbHVycmluZXNzID0gZGF0YS5iYWNrZ3JvdW5kQmx1cnJpbmVzcztcblx0XHRcdFx0aWYgKCBkYXRhLmJhY2tncm91bmRJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCApIG9iamVjdC5iYWNrZ3JvdW5kSW50ZW5zaXR5ID0gZGF0YS5iYWNrZ3JvdW5kSW50ZW5zaXR5O1xuXHRcdFx0XHRpZiAoIGRhdGEuYmFja2dyb3VuZFJvdGF0aW9uICE9PSB1bmRlZmluZWQgKSBvYmplY3QuYmFja2dyb3VuZFJvdGF0aW9uLmZyb21BcnJheSggZGF0YS5iYWNrZ3JvdW5kUm90YXRpb24gKTtcblxuXHRcdFx0XHRpZiAoIGRhdGEuZW52aXJvbm1lbnRJbnRlbnNpdHkgIT09IHVuZGVmaW5lZCApIG9iamVjdC5lbnZpcm9ubWVudEludGVuc2l0eSA9IGRhdGEuZW52aXJvbm1lbnRJbnRlbnNpdHk7XG5cdFx0XHRcdGlmICggZGF0YS5lbnZpcm9ubWVudFJvdGF0aW9uICE9PSB1bmRlZmluZWQgKSBvYmplY3QuZW52aXJvbm1lbnRSb3RhdGlvbi5mcm9tQXJyYXkoIGRhdGEuZW52aXJvbm1lbnRSb3RhdGlvbiApO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdQZXJzcGVjdGl2ZUNhbWVyYSc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IFBlcnNwZWN0aXZlQ2FtZXJhKCBkYXRhLmZvdiwgZGF0YS5hc3BlY3QsIGRhdGEubmVhciwgZGF0YS5mYXIgKTtcblxuXHRcdFx0XHRpZiAoIGRhdGEuZm9jdXMgIT09IHVuZGVmaW5lZCApIG9iamVjdC5mb2N1cyA9IGRhdGEuZm9jdXM7XG5cdFx0XHRcdGlmICggZGF0YS56b29tICE9PSB1bmRlZmluZWQgKSBvYmplY3Quem9vbSA9IGRhdGEuem9vbTtcblx0XHRcdFx0aWYgKCBkYXRhLmZpbG1HYXVnZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmZpbG1HYXVnZSA9IGRhdGEuZmlsbUdhdWdlO1xuXHRcdFx0XHRpZiAoIGRhdGEuZmlsbU9mZnNldCAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmZpbG1PZmZzZXQgPSBkYXRhLmZpbG1PZmZzZXQ7XG5cdFx0XHRcdGlmICggZGF0YS52aWV3ICE9PSB1bmRlZmluZWQgKSBvYmplY3QudmlldyA9IE9iamVjdC5hc3NpZ24oIHt9LCBkYXRhLnZpZXcgKTtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnT3J0aG9ncmFwaGljQ2FtZXJhJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgT3J0aG9ncmFwaGljQ2FtZXJhKCBkYXRhLmxlZnQsIGRhdGEucmlnaHQsIGRhdGEudG9wLCBkYXRhLmJvdHRvbSwgZGF0YS5uZWFyLCBkYXRhLmZhciApO1xuXG5cdFx0XHRcdGlmICggZGF0YS56b29tICE9PSB1bmRlZmluZWQgKSBvYmplY3Quem9vbSA9IGRhdGEuem9vbTtcblx0XHRcdFx0aWYgKCBkYXRhLnZpZXcgIT09IHVuZGVmaW5lZCApIG9iamVjdC52aWV3ID0gT2JqZWN0LmFzc2lnbigge30sIGRhdGEudmlldyApO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdBbWJpZW50TGlnaHQnOlxuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBBbWJpZW50TGlnaHQoIGRhdGEuY29sb3IsIGRhdGEuaW50ZW5zaXR5ICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0RpcmVjdGlvbmFsTGlnaHQnOlxuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBEaXJlY3Rpb25hbExpZ2h0KCBkYXRhLmNvbG9yLCBkYXRhLmludGVuc2l0eSApO1xuXHRcdFx0XHRvYmplY3QudGFyZ2V0ID0gZGF0YS50YXJnZXQgfHzCoCcnO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdQb2ludExpZ2h0JzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgUG9pbnRMaWdodCggZGF0YS5jb2xvciwgZGF0YS5pbnRlbnNpdHksIGRhdGEuZGlzdGFuY2UsIGRhdGEuZGVjYXkgKTtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnUmVjdEFyZWFMaWdodCc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IFJlY3RBcmVhTGlnaHQoIGRhdGEuY29sb3IsIGRhdGEuaW50ZW5zaXR5LCBkYXRhLndpZHRoLCBkYXRhLmhlaWdodCApO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdTcG90TGlnaHQnOlxuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBTcG90TGlnaHQoIGRhdGEuY29sb3IsIGRhdGEuaW50ZW5zaXR5LCBkYXRhLmRpc3RhbmNlLCBkYXRhLmFuZ2xlLCBkYXRhLnBlbnVtYnJhLCBkYXRhLmRlY2F5ICk7XG5cdFx0XHRcdG9iamVjdC50YXJnZXQgPSBkYXRhLnRhcmdldCB8fMKgJyc7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0hlbWlzcGhlcmVMaWdodCc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IEhlbWlzcGhlcmVMaWdodCggZGF0YS5jb2xvciwgZGF0YS5ncm91bmRDb2xvciwgZGF0YS5pbnRlbnNpdHkgKTtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnTGlnaHRQcm9iZSc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IExpZ2h0UHJvYmUoKS5mcm9tSlNPTiggZGF0YSApO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdTa2lubmVkTWVzaCc6XG5cblx0XHRcdFx0Z2VvbWV0cnkgPSBnZXRHZW9tZXRyeSggZGF0YS5nZW9tZXRyeSApO1xuXHRcdFx0IFx0bWF0ZXJpYWwgPSBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApO1xuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBTa2lubmVkTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cblx0XHRcdFx0aWYgKCBkYXRhLmJpbmRNb2RlICE9PSB1bmRlZmluZWQgKSBvYmplY3QuYmluZE1vZGUgPSBkYXRhLmJpbmRNb2RlO1xuXHRcdFx0XHRpZiAoIGRhdGEuYmluZE1hdHJpeCAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmJpbmRNYXRyaXguZnJvbUFycmF5KCBkYXRhLmJpbmRNYXRyaXggKTtcblx0XHRcdFx0aWYgKCBkYXRhLnNrZWxldG9uICE9PSB1bmRlZmluZWQgKSBvYmplY3Quc2tlbGV0b24gPSBkYXRhLnNrZWxldG9uO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdNZXNoJzpcblxuXHRcdFx0XHRnZW9tZXRyeSA9IGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICk7XG5cdFx0XHRcdG1hdGVyaWFsID0gZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKTtcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0luc3RhbmNlZE1lc2gnOlxuXG5cdFx0XHRcdGdlb21ldHJ5ID0gZ2V0R2VvbWV0cnkoIGRhdGEuZ2VvbWV0cnkgKTtcblx0XHRcdFx0bWF0ZXJpYWwgPSBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApO1xuXHRcdFx0XHRjb25zdCBjb3VudCA9IGRhdGEuY291bnQ7XG5cdFx0XHRcdGNvbnN0IGluc3RhbmNlTWF0cml4ID0gZGF0YS5pbnN0YW5jZU1hdHJpeDtcblx0XHRcdFx0Y29uc3QgaW5zdGFuY2VDb2xvciA9IGRhdGEuaW5zdGFuY2VDb2xvcjtcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgSW5zdGFuY2VkTWVzaCggZ2VvbWV0cnksIG1hdGVyaWFsLCBjb3VudCApO1xuXHRcdFx0XHRvYmplY3QuaW5zdGFuY2VNYXRyaXggPSBuZXcgSW5zdGFuY2VkQnVmZmVyQXR0cmlidXRlKCBuZXcgRmxvYXQzMkFycmF5KCBpbnN0YW5jZU1hdHJpeC5hcnJheSApLCAxNiApO1xuXHRcdFx0XHRpZiAoIGluc3RhbmNlQ29sb3IgIT09IHVuZGVmaW5lZCApIG9iamVjdC5pbnN0YW5jZUNvbG9yID0gbmV3IEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSggbmV3IEZsb2F0MzJBcnJheSggaW5zdGFuY2VDb2xvci5hcnJheSApLCBpbnN0YW5jZUNvbG9yLml0ZW1TaXplICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0JhdGNoZWRNZXNoJzpcblxuXHRcdFx0XHRnZW9tZXRyeSA9IGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICk7XG5cdFx0XHRcdG1hdGVyaWFsID0gZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKTtcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgQmF0Y2hlZE1lc2goIGRhdGEubWF4SW5zdGFuY2VDb3VudCwgZGF0YS5tYXhWZXJ0ZXhDb3VudCwgZGF0YS5tYXhJbmRleENvdW50LCBtYXRlcmlhbCApO1xuXHRcdFx0XHRvYmplY3QuZ2VvbWV0cnkgPSBnZW9tZXRyeTtcblx0XHRcdFx0b2JqZWN0LnBlck9iamVjdEZydXN0dW1DdWxsZWQgPSBkYXRhLnBlck9iamVjdEZydXN0dW1DdWxsZWQ7XG5cdFx0XHRcdG9iamVjdC5zb3J0T2JqZWN0cyA9IGRhdGEuc29ydE9iamVjdHM7XG5cblx0XHRcdFx0b2JqZWN0Ll9kcmF3UmFuZ2VzID0gZGF0YS5kcmF3UmFuZ2VzO1xuXHRcdFx0XHRvYmplY3QuX3Jlc2VydmVkUmFuZ2VzID0gZGF0YS5yZXNlcnZlZFJhbmdlcztcblxuXHRcdFx0XHRvYmplY3QuX3Zpc2liaWxpdHkgPSBkYXRhLnZpc2liaWxpdHk7XG5cdFx0XHRcdG9iamVjdC5fYWN0aXZlID0gZGF0YS5hY3RpdmU7XG5cdFx0XHRcdG9iamVjdC5fYm91bmRzID0gZGF0YS5ib3VuZHMubWFwKCBib3VuZCA9PiB7XG5cblx0XHRcdFx0XHRjb25zdCBib3ggPSBuZXcgQm94MygpO1xuXHRcdFx0XHRcdGJveC5taW4uZnJvbUFycmF5KCBib3VuZC5ib3hNaW4gKTtcblx0XHRcdFx0XHRib3gubWF4LmZyb21BcnJheSggYm91bmQuYm94TWF4ICk7XG5cblx0XHRcdFx0XHRjb25zdCBzcGhlcmUgPSBuZXcgU3BoZXJlKCk7XG5cdFx0XHRcdFx0c3BoZXJlLnJhZGl1cyA9IGJvdW5kLnNwaGVyZVJhZGl1cztcblx0XHRcdFx0XHRzcGhlcmUuY2VudGVyLmZyb21BcnJheSggYm91bmQuc3BoZXJlQ2VudGVyICk7XG5cblx0XHRcdFx0XHRyZXR1cm4ge1xuXHRcdFx0XHRcdFx0Ym94SW5pdGlhbGl6ZWQ6IGJvdW5kLmJveEluaXRpYWxpemVkLFxuXHRcdFx0XHRcdFx0Ym94OiBib3gsXG5cblx0XHRcdFx0XHRcdHNwaGVyZUluaXRpYWxpemVkOiBib3VuZC5zcGhlcmVJbml0aWFsaXplZCxcblx0XHRcdFx0XHRcdHNwaGVyZTogc3BoZXJlXG5cdFx0XHRcdFx0fTtcblxuXHRcdFx0XHR9ICk7XG5cblx0XHRcdFx0b2JqZWN0Ll9tYXhJbnN0YW5jZUNvdW50ID0gZGF0YS5tYXhJbnN0YW5jZUNvdW50O1xuXHRcdFx0XHRvYmplY3QuX21heFZlcnRleENvdW50ID0gZGF0YS5tYXhWZXJ0ZXhDb3VudDtcblx0XHRcdFx0b2JqZWN0Ll9tYXhJbmRleENvdW50ID0gZGF0YS5tYXhJbmRleENvdW50O1xuXG5cdFx0XHRcdG9iamVjdC5fZ2VvbWV0cnlJbml0aWFsaXplZCA9IGRhdGEuZ2VvbWV0cnlJbml0aWFsaXplZDtcblx0XHRcdFx0b2JqZWN0Ll9nZW9tZXRyeUNvdW50ID0gZGF0YS5nZW9tZXRyeUNvdW50O1xuXG5cdFx0XHRcdG9iamVjdC5fbWF0cmljZXNUZXh0dXJlID0gZ2V0VGV4dHVyZSggZGF0YS5tYXRyaWNlc1RleHR1cmUudXVpZCApO1xuXHRcdFx0XHRpZiAoIGRhdGEuY29sb3JzVGV4dHVyZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0Ll9jb2xvcnNUZXh0dXJlID0gZ2V0VGV4dHVyZSggZGF0YS5jb2xvcnNUZXh0dXJlLnV1aWQgKTtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnTE9EJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgTE9EKCk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0xpbmUnOlxuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBMaW5lKCBnZXRHZW9tZXRyeSggZGF0YS5nZW9tZXRyeSApLCBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0xpbmVMb29wJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgTGluZUxvb3AoIGdldEdlb21ldHJ5KCBkYXRhLmdlb21ldHJ5ICksIGdldE1hdGVyaWFsKCBkYXRhLm1hdGVyaWFsICkgKTtcblxuXHRcdFx0XHRicmVhaztcblxuXHRcdFx0Y2FzZSAnTGluZVNlZ21lbnRzJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgTGluZVNlZ21lbnRzKCBnZXRHZW9tZXRyeSggZGF0YS5nZW9tZXRyeSApLCBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1BvaW50Q2xvdWQnOlxuXHRcdFx0Y2FzZSAnUG9pbnRzJzpcblxuXHRcdFx0XHRvYmplY3QgPSBuZXcgUG9pbnRzKCBnZXRHZW9tZXRyeSggZGF0YS5nZW9tZXRyeSApLCBnZXRNYXRlcmlhbCggZGF0YS5tYXRlcmlhbCApICk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ1Nwcml0ZSc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IFNwcml0ZSggZ2V0TWF0ZXJpYWwoIGRhdGEubWF0ZXJpYWwgKSApO1xuXG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdHcm91cCc6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IEdyb3VwKCk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGNhc2UgJ0JvbmUnOlxuXG5cdFx0XHRcdG9iamVjdCA9IG5ldyBCb25lKCk7XG5cblx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0b2JqZWN0ID0gbmV3IE9iamVjdDNEKCk7XG5cblx0XHR9XG5cblx0XHRvYmplY3QudXVpZCA9IGRhdGEudXVpZDtcblxuXHRcdGlmICggZGF0YS5uYW1lICE9PSB1bmRlZmluZWQgKSBvYmplY3QubmFtZSA9IGRhdGEubmFtZTtcblxuXHRcdGlmICggZGF0YS5tYXRyaXggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0b2JqZWN0Lm1hdHJpeC5mcm9tQXJyYXkoIGRhdGEubWF0cml4ICk7XG5cblx0XHRcdGlmICggZGF0YS5tYXRyaXhBdXRvVXBkYXRlICE9PSB1bmRlZmluZWQgKSBvYmplY3QubWF0cml4QXV0b1VwZGF0ZSA9IGRhdGEubWF0cml4QXV0b1VwZGF0ZTtcblx0XHRcdGlmICggb2JqZWN0Lm1hdHJpeEF1dG9VcGRhdGUgKSBvYmplY3QubWF0cml4LmRlY29tcG9zZSggb2JqZWN0LnBvc2l0aW9uLCBvYmplY3QucXVhdGVybmlvbiwgb2JqZWN0LnNjYWxlICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRpZiAoIGRhdGEucG9zaXRpb24gIT09IHVuZGVmaW5lZCApIG9iamVjdC5wb3NpdGlvbi5mcm9tQXJyYXkoIGRhdGEucG9zaXRpb24gKTtcblx0XHRcdGlmICggZGF0YS5yb3RhdGlvbiAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnJvdGF0aW9uLmZyb21BcnJheSggZGF0YS5yb3RhdGlvbiApO1xuXHRcdFx0aWYgKCBkYXRhLnF1YXRlcm5pb24gIT09IHVuZGVmaW5lZCApIG9iamVjdC5xdWF0ZXJuaW9uLmZyb21BcnJheSggZGF0YS5xdWF0ZXJuaW9uICk7XG5cdFx0XHRpZiAoIGRhdGEuc2NhbGUgIT09IHVuZGVmaW5lZCApIG9iamVjdC5zY2FsZS5mcm9tQXJyYXkoIGRhdGEuc2NhbGUgKTtcblxuXHRcdH1cblxuXHRcdGlmICggZGF0YS51cCAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnVwLmZyb21BcnJheSggZGF0YS51cCApO1xuXG5cdFx0aWYgKCBkYXRhLmNhc3RTaGFkb3cgIT09IHVuZGVmaW5lZCApIG9iamVjdC5jYXN0U2hhZG93ID0gZGF0YS5jYXN0U2hhZG93O1xuXHRcdGlmICggZGF0YS5yZWNlaXZlU2hhZG93ICE9PSB1bmRlZmluZWQgKSBvYmplY3QucmVjZWl2ZVNoYWRvdyA9IGRhdGEucmVjZWl2ZVNoYWRvdztcblxuXHRcdGlmICggZGF0YS5zaGFkb3cgKSB7XG5cblx0XHRcdGlmICggZGF0YS5zaGFkb3cuaW50ZW5zaXR5ICE9PSB1bmRlZmluZWQgKSBvYmplY3Quc2hhZG93LmludGVuc2l0eSA9IGRhdGEuc2hhZG93LmludGVuc2l0eTtcblx0XHRcdGlmICggZGF0YS5zaGFkb3cuYmlhcyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5iaWFzID0gZGF0YS5zaGFkb3cuYmlhcztcblx0XHRcdGlmICggZGF0YS5zaGFkb3cubm9ybWFsQmlhcyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5ub3JtYWxCaWFzID0gZGF0YS5zaGFkb3cubm9ybWFsQmlhcztcblx0XHRcdGlmICggZGF0YS5zaGFkb3cucmFkaXVzICE9PSB1bmRlZmluZWQgKSBvYmplY3Quc2hhZG93LnJhZGl1cyA9IGRhdGEuc2hhZG93LnJhZGl1cztcblx0XHRcdGlmICggZGF0YS5zaGFkb3cubWFwU2l6ZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnNoYWRvdy5tYXBTaXplLmZyb21BcnJheSggZGF0YS5zaGFkb3cubWFwU2l6ZSApO1xuXHRcdFx0aWYgKCBkYXRhLnNoYWRvdy5jYW1lcmEgIT09IHVuZGVmaW5lZCApIG9iamVjdC5zaGFkb3cuY2FtZXJhID0gdGhpcy5wYXJzZU9iamVjdCggZGF0YS5zaGFkb3cuY2FtZXJhICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIGRhdGEudmlzaWJsZSAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnZpc2libGUgPSBkYXRhLnZpc2libGU7XG5cdFx0aWYgKCBkYXRhLmZydXN0dW1DdWxsZWQgIT09IHVuZGVmaW5lZCApIG9iamVjdC5mcnVzdHVtQ3VsbGVkID0gZGF0YS5mcnVzdHVtQ3VsbGVkO1xuXHRcdGlmICggZGF0YS5yZW5kZXJPcmRlciAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LnJlbmRlck9yZGVyID0gZGF0YS5yZW5kZXJPcmRlcjtcblx0XHRpZiAoIGRhdGEudXNlckRhdGEgIT09IHVuZGVmaW5lZCApIG9iamVjdC51c2VyRGF0YSA9IGRhdGEudXNlckRhdGE7XG5cdFx0aWYgKCBkYXRhLmxheWVycyAhPT0gdW5kZWZpbmVkICkgb2JqZWN0LmxheWVycy5tYXNrID0gZGF0YS5sYXllcnM7XG5cblx0XHRpZiAoIGRhdGEuY2hpbGRyZW4gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3QgY2hpbGRyZW4gPSBkYXRhLmNoaWxkcmVuO1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0b2JqZWN0LmFkZCggdGhpcy5wYXJzZU9iamVjdCggY2hpbGRyZW5bIGkgXSwgZ2VvbWV0cmllcywgbWF0ZXJpYWxzLCB0ZXh0dXJlcywgYW5pbWF0aW9ucyApICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggZGF0YS5hbmltYXRpb25zICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IG9iamVjdEFuaW1hdGlvbnMgPSBkYXRhLmFuaW1hdGlvbnM7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IG9iamVjdEFuaW1hdGlvbnMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHV1aWQgPSBvYmplY3RBbmltYXRpb25zWyBpIF07XG5cblx0XHRcdFx0b2JqZWN0LmFuaW1hdGlvbnMucHVzaCggYW5pbWF0aW9uc1sgdXVpZCBdICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGlmICggZGF0YS50eXBlID09PSAnTE9EJyApIHtcblxuXHRcdFx0aWYgKCBkYXRhLmF1dG9VcGRhdGUgIT09IHVuZGVmaW5lZCApIG9iamVjdC5hdXRvVXBkYXRlID0gZGF0YS5hdXRvVXBkYXRlO1xuXG5cdFx0XHRjb25zdCBsZXZlbHMgPSBkYXRhLmxldmVscztcblxuXHRcdFx0Zm9yICggbGV0IGwgPSAwOyBsIDwgbGV2ZWxzLmxlbmd0aDsgbCArKyApIHtcblxuXHRcdFx0XHRjb25zdCBsZXZlbCA9IGxldmVsc1sgbCBdO1xuXHRcdFx0XHRjb25zdCBjaGlsZCA9IG9iamVjdC5nZXRPYmplY3RCeVByb3BlcnR5KCAndXVpZCcsIGxldmVsLm9iamVjdCApO1xuXG5cdFx0XHRcdGlmICggY2hpbGQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdG9iamVjdC5hZGRMZXZlbCggY2hpbGQsIGxldmVsLmRpc3RhbmNlLCBsZXZlbC5oeXN0ZXJlc2lzICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gb2JqZWN0O1xuXG5cdH1cblxuXHRiaW5kU2tlbGV0b25zKCBvYmplY3QsIHNrZWxldG9ucyApIHtcblxuXHRcdGlmICggT2JqZWN0LmtleXMoIHNrZWxldG9ucyApLmxlbmd0aCA9PT0gMCApIHJldHVybjtcblxuXHRcdG9iamVjdC50cmF2ZXJzZSggZnVuY3Rpb24gKCBjaGlsZCApIHtcblxuXHRcdFx0aWYgKCBjaGlsZC5pc1NraW5uZWRNZXNoID09PSB0cnVlICYmIGNoaWxkLnNrZWxldG9uICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Y29uc3Qgc2tlbGV0b24gPSBza2VsZXRvbnNbIGNoaWxkLnNrZWxldG9uIF07XG5cblx0XHRcdFx0aWYgKCBza2VsZXRvbiA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuT2JqZWN0TG9hZGVyOiBObyBza2VsZXRvbiBmb3VuZCB3aXRoIFVVSUQ6JywgY2hpbGQuc2tlbGV0b24gKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Y2hpbGQuYmluZCggc2tlbGV0b24sIGNoaWxkLmJpbmRNYXRyaXggKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH0gKTtcblxuXHR9XG5cblx0YmluZExpZ2h0VGFyZ2V0cyggb2JqZWN0ICkge1xuXG5cdFx0b2JqZWN0LnRyYXZlcnNlKCBmdW5jdGlvbiAoIGNoaWxkICkge1xuXG5cdFx0XHRpZiAoIGNoaWxkLmlzRGlyZWN0aW9uYWxMaWdodCB8fMKgY2hpbGQuaXNTcG90TGlnaHQgKSB7XG5cblx0XHRcdFx0Y29uc3QgdXVpZCA9IGNoaWxkLnRhcmdldDtcblxuXHRcdFx0XHRjb25zdCB0YXJnZXQgPSBvYmplY3QuZ2V0T2JqZWN0QnlQcm9wZXJ0eSggJ3V1aWQnLCB1dWlkICk7XG5cblx0XHRcdFx0aWYgKCB0YXJnZXQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRcdGNoaWxkLnRhcmdldCA9IHRhcmdldDtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Y2hpbGQudGFyZ2V0ID0gbmV3IE9iamVjdDNEKCk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9ICk7XG5cblx0fVxuXG59XG5cbmNvbnN0IFRFWFRVUkVfTUFQUElORyA9IHtcblx0VVZNYXBwaW5nOiBVVk1hcHBpbmcsXG5cdEN1YmVSZWZsZWN0aW9uTWFwcGluZzogQ3ViZVJlZmxlY3Rpb25NYXBwaW5nLFxuXHRDdWJlUmVmcmFjdGlvbk1hcHBpbmc6IEN1YmVSZWZyYWN0aW9uTWFwcGluZyxcblx0RXF1aXJlY3Rhbmd1bGFyUmVmbGVjdGlvbk1hcHBpbmc6IEVxdWlyZWN0YW5ndWxhclJlZmxlY3Rpb25NYXBwaW5nLFxuXHRFcXVpcmVjdGFuZ3VsYXJSZWZyYWN0aW9uTWFwcGluZzogRXF1aXJlY3Rhbmd1bGFyUmVmcmFjdGlvbk1hcHBpbmcsXG5cdEN1YmVVVlJlZmxlY3Rpb25NYXBwaW5nOiBDdWJlVVZSZWZsZWN0aW9uTWFwcGluZ1xufTtcblxuY29uc3QgVEVYVFVSRV9XUkFQUElORyA9IHtcblx0UmVwZWF0V3JhcHBpbmc6IFJlcGVhdFdyYXBwaW5nLFxuXHRDbGFtcFRvRWRnZVdyYXBwaW5nOiBDbGFtcFRvRWRnZVdyYXBwaW5nLFxuXHRNaXJyb3JlZFJlcGVhdFdyYXBwaW5nOiBNaXJyb3JlZFJlcGVhdFdyYXBwaW5nXG59O1xuXG5jb25zdCBURVhUVVJFX0ZJTFRFUiA9IHtcblx0TmVhcmVzdEZpbHRlcjogTmVhcmVzdEZpbHRlcixcblx0TmVhcmVzdE1pcG1hcE5lYXJlc3RGaWx0ZXI6IE5lYXJlc3RNaXBtYXBOZWFyZXN0RmlsdGVyLFxuXHROZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyOiBOZWFyZXN0TWlwbWFwTGluZWFyRmlsdGVyLFxuXHRMaW5lYXJGaWx0ZXI6IExpbmVhckZpbHRlcixcblx0TGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlcjogTGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlcixcblx0TGluZWFyTWlwbWFwTGluZWFyRmlsdGVyOiBMaW5lYXJNaXBtYXBMaW5lYXJGaWx0ZXJcbn07XG5cbmNsYXNzIEltYWdlQml0bWFwTG9hZGVyIGV4dGVuZHMgTG9hZGVyIHtcblxuXHRjb25zdHJ1Y3RvciggbWFuYWdlciApIHtcblxuXHRcdHN1cGVyKCBtYW5hZ2VyICk7XG5cblx0XHR0aGlzLmlzSW1hZ2VCaXRtYXBMb2FkZXIgPSB0cnVlO1xuXG5cdFx0aWYgKCB0eXBlb2YgY3JlYXRlSW1hZ2VCaXRtYXAgPT09ICd1bmRlZmluZWQnICkge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5JbWFnZUJpdG1hcExvYWRlcjogY3JlYXRlSW1hZ2VCaXRtYXAoKSBub3Qgc3VwcG9ydGVkLicgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdHlwZW9mIGZldGNoID09PSAndW5kZWZpbmVkJyApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuSW1hZ2VCaXRtYXBMb2FkZXI6IGZldGNoKCkgbm90IHN1cHBvcnRlZC4nICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLm9wdGlvbnMgPSB7IHByZW11bHRpcGx5QWxwaGE6ICdub25lJyB9O1xuXG5cdH1cblxuXHRzZXRPcHRpb25zKCBvcHRpb25zICkge1xuXG5cdFx0dGhpcy5vcHRpb25zID0gb3B0aW9ucztcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRsb2FkKCB1cmwsIG9uTG9hZCwgb25Qcm9ncmVzcywgb25FcnJvciApIHtcblxuXHRcdGlmICggdXJsID09PSB1bmRlZmluZWQgKSB1cmwgPSAnJztcblxuXHRcdGlmICggdGhpcy5wYXRoICE9PSB1bmRlZmluZWQgKSB1cmwgPSB0aGlzLnBhdGggKyB1cmw7XG5cblx0XHR1cmwgPSB0aGlzLm1hbmFnZXIucmVzb2x2ZVVSTCggdXJsICk7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRjb25zdCBjYWNoZWQgPSBDYWNoZS5nZXQoIHVybCApO1xuXG5cdFx0aWYgKCBjYWNoZWQgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtU3RhcnQoIHVybCApO1xuXG5cdFx0XHQvLyBJZiBjYWNoZWQgaXMgYSBwcm9taXNlLCB3YWl0IGZvciBpdCB0byByZXNvbHZlXG5cdFx0XHRpZiAoIGNhY2hlZC50aGVuICkge1xuXG5cdFx0XHRcdGNhY2hlZC50aGVuKCBpbWFnZUJpdG1hcCA9PiB7XG5cblx0XHRcdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggaW1hZ2VCaXRtYXAgKTtcblxuXHRcdFx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbUVuZCggdXJsICk7XG5cblx0XHRcdFx0fSApLmNhdGNoKCBlID0+IHtcblxuXHRcdFx0XHRcdGlmICggb25FcnJvciApIG9uRXJyb3IoIGUgKTtcblxuXHRcdFx0XHR9ICk7XG5cdFx0XHRcdHJldHVybjtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyBJZiBjYWNoZWQgaXMgbm90IGEgcHJvbWlzZSAoaS5lLiwgaXQncyBhbHJlYWR5IGFuIGltYWdlQml0bWFwKVxuXHRcdFx0c2V0VGltZW91dCggZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRcdGlmICggb25Mb2FkICkgb25Mb2FkKCBjYWNoZWQgKTtcblxuXHRcdFx0XHRzY29wZS5tYW5hZ2VyLml0ZW1FbmQoIHVybCApO1xuXG5cdFx0XHR9LCAwICk7XG5cblx0XHRcdHJldHVybiBjYWNoZWQ7XG5cblx0XHR9XG5cblx0XHRjb25zdCBmZXRjaE9wdGlvbnMgPSB7fTtcblx0XHRmZXRjaE9wdGlvbnMuY3JlZGVudGlhbHMgPSAoIHRoaXMuY3Jvc3NPcmlnaW4gPT09ICdhbm9ueW1vdXMnICkgPyAnc2FtZS1vcmlnaW4nIDogJ2luY2x1ZGUnO1xuXHRcdGZldGNoT3B0aW9ucy5oZWFkZXJzID0gdGhpcy5yZXF1ZXN0SGVhZGVyO1xuXG5cdFx0Y29uc3QgcHJvbWlzZSA9IGZldGNoKCB1cmwsIGZldGNoT3B0aW9ucyApLnRoZW4oIGZ1bmN0aW9uICggcmVzICkge1xuXG5cdFx0XHRyZXR1cm4gcmVzLmJsb2IoKTtcblxuXHRcdH0gKS50aGVuKCBmdW5jdGlvbiAoIGJsb2IgKSB7XG5cblx0XHRcdHJldHVybiBjcmVhdGVJbWFnZUJpdG1hcCggYmxvYiwgT2JqZWN0LmFzc2lnbiggc2NvcGUub3B0aW9ucywgeyBjb2xvclNwYWNlQ29udmVyc2lvbjogJ25vbmUnIH0gKSApO1xuXG5cdFx0fSApLnRoZW4oIGZ1bmN0aW9uICggaW1hZ2VCaXRtYXAgKSB7XG5cblx0XHRcdENhY2hlLmFkZCggdXJsLCBpbWFnZUJpdG1hcCApO1xuXG5cdFx0XHRpZiAoIG9uTG9hZCApIG9uTG9hZCggaW1hZ2VCaXRtYXAgKTtcblxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcblxuXHRcdFx0cmV0dXJuIGltYWdlQml0bWFwO1xuXG5cdFx0fSApLmNhdGNoKCBmdW5jdGlvbiAoIGUgKSB7XG5cblx0XHRcdGlmICggb25FcnJvciApIG9uRXJyb3IoIGUgKTtcblxuXHRcdFx0Q2FjaGUucmVtb3ZlKCB1cmwgKTtcblxuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRXJyb3IoIHVybCApO1xuXHRcdFx0c2NvcGUubWFuYWdlci5pdGVtRW5kKCB1cmwgKTtcblxuXHRcdH0gKTtcblxuXHRcdENhY2hlLmFkZCggdXJsLCBwcm9taXNlICk7XG5cdFx0c2NvcGUubWFuYWdlci5pdGVtU3RhcnQoIHVybCApO1xuXG5cdH1cblxufVxuXG5sZXQgX2NvbnRleHQ7XG5cbmNsYXNzIEF1ZGlvQ29udGV4dCB7XG5cblx0c3RhdGljIGdldENvbnRleHQoKSB7XG5cblx0XHRpZiAoIF9jb250ZXh0ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdF9jb250ZXh0ID0gbmV3ICggd2luZG93LkF1ZGlvQ29udGV4dCB8fCB3aW5kb3cud2Via2l0QXVkaW9Db250ZXh0ICkoKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBfY29udGV4dDtcblxuXHR9XG5cblx0c3RhdGljIHNldENvbnRleHQoIHZhbHVlICkge1xuXG5cdFx0X2NvbnRleHQgPSB2YWx1ZTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQXVkaW9Mb2FkZXIgZXh0ZW5kcyBMb2FkZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBtYW5hZ2VyICkge1xuXG5cdFx0c3VwZXIoIG1hbmFnZXIgKTtcblxuXHR9XG5cblx0bG9hZCggdXJsLCBvbkxvYWQsIG9uUHJvZ3Jlc3MsIG9uRXJyb3IgKSB7XG5cblx0XHRjb25zdCBzY29wZSA9IHRoaXM7XG5cblx0XHRjb25zdCBsb2FkZXIgPSBuZXcgRmlsZUxvYWRlciggdGhpcy5tYW5hZ2VyICk7XG5cdFx0bG9hZGVyLnNldFJlc3BvbnNlVHlwZSggJ2FycmF5YnVmZmVyJyApO1xuXHRcdGxvYWRlci5zZXRQYXRoKCB0aGlzLnBhdGggKTtcblx0XHRsb2FkZXIuc2V0UmVxdWVzdEhlYWRlciggdGhpcy5yZXF1ZXN0SGVhZGVyICk7XG5cdFx0bG9hZGVyLnNldFdpdGhDcmVkZW50aWFscyggdGhpcy53aXRoQ3JlZGVudGlhbHMgKTtcblx0XHRsb2FkZXIubG9hZCggdXJsLCBmdW5jdGlvbiAoIGJ1ZmZlciApIHtcblxuXHRcdFx0dHJ5IHtcblxuXHRcdFx0XHQvLyBDcmVhdGUgYSBjb3B5IG9mIHRoZSBidWZmZXIuIFRoZSBgZGVjb2RlQXVkaW9EYXRhYCBtZXRob2Rcblx0XHRcdFx0Ly8gZGV0YWNoZXMgdGhlIGJ1ZmZlciB3aGVuIGNvbXBsZXRlLCBwcmV2ZW50aW5nIHJldXNlLlxuXHRcdFx0XHRjb25zdCBidWZmZXJDb3B5ID0gYnVmZmVyLnNsaWNlKCAwICk7XG5cblx0XHRcdFx0Y29uc3QgY29udGV4dCA9IEF1ZGlvQ29udGV4dC5nZXRDb250ZXh0KCk7XG5cdFx0XHRcdGNvbnRleHQuZGVjb2RlQXVkaW9EYXRhKCBidWZmZXJDb3B5LCBmdW5jdGlvbiAoIGF1ZGlvQnVmZmVyICkge1xuXG5cdFx0XHRcdFx0b25Mb2FkKCBhdWRpb0J1ZmZlciApO1xuXG5cdFx0XHRcdH0gKS5jYXRjaCggaGFuZGxlRXJyb3IgKTtcblxuXHRcdFx0fSBjYXRjaCAoIGUgKSB7XG5cblx0XHRcdFx0aGFuZGxlRXJyb3IoIGUgKTtcblxuXHRcdFx0fVxuXG5cdFx0fSwgb25Qcm9ncmVzcywgb25FcnJvciApO1xuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlRXJyb3IoIGUgKSB7XG5cblx0XHRcdGlmICggb25FcnJvciApIHtcblxuXHRcdFx0XHRvbkVycm9yKCBlICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Y29uc29sZS5lcnJvciggZSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHNjb3BlLm1hbmFnZXIuaXRlbUVycm9yKCB1cmwgKTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuY29uc3QgX2V5ZVJpZ2h0ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX2V5ZUxlZnQgPSAvKkBfX1BVUkVfXyovIG5ldyBNYXRyaXg0KCk7XG5jb25zdCBfcHJvamVjdGlvbk1hdHJpeCA9IC8qQF9fUFVSRV9fKi8gbmV3IE1hdHJpeDQoKTtcblxuY2xhc3MgU3RlcmVvQ2FtZXJhIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHRoaXMudHlwZSA9ICdTdGVyZW9DYW1lcmEnO1xuXG5cdFx0dGhpcy5hc3BlY3QgPSAxO1xuXG5cdFx0dGhpcy5leWVTZXAgPSAwLjA2NDtcblxuXHRcdHRoaXMuY2FtZXJhTCA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSgpO1xuXHRcdHRoaXMuY2FtZXJhTC5sYXllcnMuZW5hYmxlKCAxICk7XG5cdFx0dGhpcy5jYW1lcmFMLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblxuXHRcdHRoaXMuY2FtZXJhUiA9IG5ldyBQZXJzcGVjdGl2ZUNhbWVyYSgpO1xuXHRcdHRoaXMuY2FtZXJhUi5sYXllcnMuZW5hYmxlKCAyICk7XG5cdFx0dGhpcy5jYW1lcmFSLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblxuXHRcdHRoaXMuX2NhY2hlID0ge1xuXHRcdFx0Zm9jdXM6IG51bGwsXG5cdFx0XHRmb3Y6IG51bGwsXG5cdFx0XHRhc3BlY3Q6IG51bGwsXG5cdFx0XHRuZWFyOiBudWxsLFxuXHRcdFx0ZmFyOiBudWxsLFxuXHRcdFx0em9vbTogbnVsbCxcblx0XHRcdGV5ZVNlcDogbnVsbFxuXHRcdH07XG5cblx0fVxuXG5cdHVwZGF0ZSggY2FtZXJhICkge1xuXG5cdFx0Y29uc3QgY2FjaGUgPSB0aGlzLl9jYWNoZTtcblxuXHRcdGNvbnN0IG5lZWRzVXBkYXRlID0gY2FjaGUuZm9jdXMgIT09IGNhbWVyYS5mb2N1cyB8fCBjYWNoZS5mb3YgIT09IGNhbWVyYS5mb3YgfHxcblx0XHRcdGNhY2hlLmFzcGVjdCAhPT0gY2FtZXJhLmFzcGVjdCAqIHRoaXMuYXNwZWN0IHx8IGNhY2hlLm5lYXIgIT09IGNhbWVyYS5uZWFyIHx8XG5cdFx0XHRjYWNoZS5mYXIgIT09IGNhbWVyYS5mYXIgfHwgY2FjaGUuem9vbSAhPT0gY2FtZXJhLnpvb20gfHwgY2FjaGUuZXllU2VwICE9PSB0aGlzLmV5ZVNlcDtcblxuXHRcdGlmICggbmVlZHNVcGRhdGUgKSB7XG5cblx0XHRcdGNhY2hlLmZvY3VzID0gY2FtZXJhLmZvY3VzO1xuXHRcdFx0Y2FjaGUuZm92ID0gY2FtZXJhLmZvdjtcblx0XHRcdGNhY2hlLmFzcGVjdCA9IGNhbWVyYS5hc3BlY3QgKiB0aGlzLmFzcGVjdDtcblx0XHRcdGNhY2hlLm5lYXIgPSBjYW1lcmEubmVhcjtcblx0XHRcdGNhY2hlLmZhciA9IGNhbWVyYS5mYXI7XG5cdFx0XHRjYWNoZS56b29tID0gY2FtZXJhLnpvb207XG5cdFx0XHRjYWNoZS5leWVTZXAgPSB0aGlzLmV5ZVNlcDtcblxuXHRcdFx0Ly8gT2ZmLWF4aXMgc3RlcmVvc2NvcGljIGVmZmVjdCBiYXNlZCBvblxuXHRcdFx0Ly8gaHR0cDovL3BhdWxib3Vya2UubmV0L3N0ZXJlb2dyYXBoaWNzL3N0ZXJlb3JlbmRlci9cblxuXHRcdFx0X3Byb2plY3Rpb25NYXRyaXguY29weSggY2FtZXJhLnByb2plY3Rpb25NYXRyaXggKTtcblx0XHRcdGNvbnN0IGV5ZVNlcEhhbGYgPSBjYWNoZS5leWVTZXAgLyAyO1xuXHRcdFx0Y29uc3QgZXllU2VwT25Qcm9qZWN0aW9uID0gZXllU2VwSGFsZiAqIGNhY2hlLm5lYXIgLyBjYWNoZS5mb2N1cztcblx0XHRcdGNvbnN0IHltYXggPSAoIGNhY2hlLm5lYXIgKiBNYXRoLnRhbiggREVHMlJBRCAqIGNhY2hlLmZvdiAqIDAuNSApICkgLyBjYWNoZS56b29tO1xuXHRcdFx0bGV0IHhtaW4sIHhtYXg7XG5cblx0XHRcdC8vIHRyYW5zbGF0ZSB4T2Zmc2V0XG5cblx0XHRcdF9leWVMZWZ0LmVsZW1lbnRzWyAxMiBdID0gLSBleWVTZXBIYWxmO1xuXHRcdFx0X2V5ZVJpZ2h0LmVsZW1lbnRzWyAxMiBdID0gZXllU2VwSGFsZjtcblxuXHRcdFx0Ly8gZm9yIGxlZnQgZXllXG5cblx0XHRcdHhtaW4gPSAtIHltYXggKiBjYWNoZS5hc3BlY3QgKyBleWVTZXBPblByb2plY3Rpb247XG5cdFx0XHR4bWF4ID0geW1heCAqIGNhY2hlLmFzcGVjdCArIGV5ZVNlcE9uUHJvamVjdGlvbjtcblxuXHRcdFx0X3Byb2plY3Rpb25NYXRyaXguZWxlbWVudHNbIDAgXSA9IDIgKiBjYWNoZS5uZWFyIC8gKCB4bWF4IC0geG1pbiApO1xuXHRcdFx0X3Byb2plY3Rpb25NYXRyaXguZWxlbWVudHNbIDggXSA9ICggeG1heCArIHhtaW4gKSAvICggeG1heCAtIHhtaW4gKTtcblxuXHRcdFx0dGhpcy5jYW1lcmFMLnByb2plY3Rpb25NYXRyaXguY29weSggX3Byb2plY3Rpb25NYXRyaXggKTtcblxuXHRcdFx0Ly8gZm9yIHJpZ2h0IGV5ZVxuXG5cdFx0XHR4bWluID0gLSB5bWF4ICogY2FjaGUuYXNwZWN0IC0gZXllU2VwT25Qcm9qZWN0aW9uO1xuXHRcdFx0eG1heCA9IHltYXggKiBjYWNoZS5hc3BlY3QgLSBleWVTZXBPblByb2plY3Rpb247XG5cblx0XHRcdF9wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyAwIF0gPSAyICogY2FjaGUubmVhciAvICggeG1heCAtIHhtaW4gKTtcblx0XHRcdF9wcm9qZWN0aW9uTWF0cml4LmVsZW1lbnRzWyA4IF0gPSAoIHhtYXggKyB4bWluICkgLyAoIHhtYXggLSB4bWluICk7XG5cblx0XHRcdHRoaXMuY2FtZXJhUi5wcm9qZWN0aW9uTWF0cml4LmNvcHkoIF9wcm9qZWN0aW9uTWF0cml4ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLmNhbWVyYUwubWF0cml4V29ybGQuY29weSggY2FtZXJhLm1hdHJpeFdvcmxkICkubXVsdGlwbHkoIF9leWVMZWZ0ICk7XG5cdFx0dGhpcy5jYW1lcmFSLm1hdHJpeFdvcmxkLmNvcHkoIGNhbWVyYS5tYXRyaXhXb3JsZCApLm11bHRpcGx5KCBfZXllUmlnaHQgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQ2xvY2sge1xuXG5cdGNvbnN0cnVjdG9yKCBhdXRvU3RhcnQgPSB0cnVlICkge1xuXG5cdFx0dGhpcy5hdXRvU3RhcnQgPSBhdXRvU3RhcnQ7XG5cblx0XHR0aGlzLnN0YXJ0VGltZSA9IDA7XG5cdFx0dGhpcy5vbGRUaW1lID0gMDtcblx0XHR0aGlzLmVsYXBzZWRUaW1lID0gMDtcblxuXHRcdHRoaXMucnVubmluZyA9IGZhbHNlO1xuXG5cdH1cblxuXHRzdGFydCgpIHtcblxuXHRcdHRoaXMuc3RhcnRUaW1lID0gbm93KCk7XG5cblx0XHR0aGlzLm9sZFRpbWUgPSB0aGlzLnN0YXJ0VGltZTtcblx0XHR0aGlzLmVsYXBzZWRUaW1lID0gMDtcblx0XHR0aGlzLnJ1bm5pbmcgPSB0cnVlO1xuXG5cdH1cblxuXHRzdG9wKCkge1xuXG5cdFx0dGhpcy5nZXRFbGFwc2VkVGltZSgpO1xuXHRcdHRoaXMucnVubmluZyA9IGZhbHNlO1xuXHRcdHRoaXMuYXV0b1N0YXJ0ID0gZmFsc2U7XG5cblx0fVxuXG5cdGdldEVsYXBzZWRUaW1lKCkge1xuXG5cdFx0dGhpcy5nZXREZWx0YSgpO1xuXHRcdHJldHVybiB0aGlzLmVsYXBzZWRUaW1lO1xuXG5cdH1cblxuXHRnZXREZWx0YSgpIHtcblxuXHRcdGxldCBkaWZmID0gMDtcblxuXHRcdGlmICggdGhpcy5hdXRvU3RhcnQgJiYgISB0aGlzLnJ1bm5pbmcgKSB7XG5cblx0XHRcdHRoaXMuc3RhcnQoKTtcblx0XHRcdHJldHVybiAwO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLnJ1bm5pbmcgKSB7XG5cblx0XHRcdGNvbnN0IG5ld1RpbWUgPSBub3coKTtcblxuXHRcdFx0ZGlmZiA9ICggbmV3VGltZSAtIHRoaXMub2xkVGltZSApIC8gMTAwMDtcblx0XHRcdHRoaXMub2xkVGltZSA9IG5ld1RpbWU7XG5cblx0XHRcdHRoaXMuZWxhcHNlZFRpbWUgKz0gZGlmZjtcblxuXHRcdH1cblxuXHRcdHJldHVybiBkaWZmO1xuXG5cdH1cblxufVxuXG5mdW5jdGlvbiBub3coKSB7XG5cblx0cmV0dXJuICggdHlwZW9mIHBlcmZvcm1hbmNlID09PSAndW5kZWZpbmVkJyA/IERhdGUgOiBwZXJmb3JtYW5jZSApLm5vdygpOyAvLyBzZWUgIzEwNzMyXG5cbn1cblxuY29uc3QgX3Bvc2l0aW9uJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfcXVhdGVybmlvbiQxID0gLypAX19QVVJFX18qLyBuZXcgUXVhdGVybmlvbigpO1xuY29uc3QgX3NjYWxlJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfb3JpZW50YXRpb24kMSA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgQXVkaW9MaXN0ZW5lciBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnR5cGUgPSAnQXVkaW9MaXN0ZW5lcic7XG5cblx0XHR0aGlzLmNvbnRleHQgPSBBdWRpb0NvbnRleHQuZ2V0Q29udGV4dCgpO1xuXG5cdFx0dGhpcy5nYWluID0gdGhpcy5jb250ZXh0LmNyZWF0ZUdhaW4oKTtcblx0XHR0aGlzLmdhaW4uY29ubmVjdCggdGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uICk7XG5cblx0XHR0aGlzLmZpbHRlciA9IG51bGw7XG5cblx0XHR0aGlzLnRpbWVEZWx0YSA9IDA7XG5cblx0XHQvLyBwcml2YXRlXG5cblx0XHR0aGlzLl9jbG9jayA9IG5ldyBDbG9jaygpO1xuXG5cdH1cblxuXHRnZXRJbnB1dCgpIHtcblxuXHRcdHJldHVybiB0aGlzLmdhaW47XG5cblx0fVxuXG5cdHJlbW92ZUZpbHRlcigpIHtcblxuXHRcdGlmICggdGhpcy5maWx0ZXIgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuZ2Fpbi5kaXNjb25uZWN0KCB0aGlzLmZpbHRlciApO1xuXHRcdFx0dGhpcy5maWx0ZXIuZGlzY29ubmVjdCggdGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uICk7XG5cdFx0XHR0aGlzLmdhaW4uY29ubmVjdCggdGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uICk7XG5cdFx0XHR0aGlzLmZpbHRlciA9IG51bGw7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0RmlsdGVyKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZmlsdGVyO1xuXG5cdH1cblxuXHRzZXRGaWx0ZXIoIHZhbHVlICkge1xuXG5cdFx0aWYgKCB0aGlzLmZpbHRlciAhPT0gbnVsbCApIHtcblxuXHRcdFx0dGhpcy5nYWluLmRpc2Nvbm5lY3QoIHRoaXMuZmlsdGVyICk7XG5cdFx0XHR0aGlzLmZpbHRlci5kaXNjb25uZWN0KCB0aGlzLmNvbnRleHQuZGVzdGluYXRpb24gKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuZ2Fpbi5kaXNjb25uZWN0KCB0aGlzLmNvbnRleHQuZGVzdGluYXRpb24gKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuZmlsdGVyID0gdmFsdWU7XG5cdFx0dGhpcy5nYWluLmNvbm5lY3QoIHRoaXMuZmlsdGVyICk7XG5cdFx0dGhpcy5maWx0ZXIuY29ubmVjdCggdGhpcy5jb250ZXh0LmRlc3RpbmF0aW9uICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0TWFzdGVyVm9sdW1lKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZ2Fpbi5nYWluLnZhbHVlO1xuXG5cdH1cblxuXHRzZXRNYXN0ZXJWb2x1bWUoIHZhbHVlICkge1xuXG5cdFx0dGhpcy5nYWluLmdhaW4uc2V0VGFyZ2V0QXRUaW1lKCB2YWx1ZSwgdGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lLCAwLjAxICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICkge1xuXG5cdFx0c3VwZXIudXBkYXRlTWF0cml4V29ybGQoIGZvcmNlICk7XG5cblx0XHRjb25zdCBsaXN0ZW5lciA9IHRoaXMuY29udGV4dC5saXN0ZW5lcjtcblx0XHRjb25zdCB1cCA9IHRoaXMudXA7XG5cblx0XHR0aGlzLnRpbWVEZWx0YSA9IHRoaXMuX2Nsb2NrLmdldERlbHRhKCk7XG5cblx0XHR0aGlzLm1hdHJpeFdvcmxkLmRlY29tcG9zZSggX3Bvc2l0aW9uJDEsIF9xdWF0ZXJuaW9uJDEsIF9zY2FsZSQxICk7XG5cblx0XHRfb3JpZW50YXRpb24kMS5zZXQoIDAsIDAsIC0gMSApLmFwcGx5UXVhdGVybmlvbiggX3F1YXRlcm5pb24kMSApO1xuXG5cdFx0aWYgKCBsaXN0ZW5lci5wb3NpdGlvblggKSB7XG5cblx0XHRcdC8vIGNvZGUgcGF0aCBmb3IgQ2hyb21lIChzZWUgIzE0MzkzKVxuXG5cdFx0XHRjb25zdCBlbmRUaW1lID0gdGhpcy5jb250ZXh0LmN1cnJlbnRUaW1lICsgdGhpcy50aW1lRGVsdGE7XG5cblx0XHRcdGxpc3RlbmVyLnBvc2l0aW9uWC5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX3Bvc2l0aW9uJDEueCwgZW5kVGltZSApO1xuXHRcdFx0bGlzdGVuZXIucG9zaXRpb25ZLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfcG9zaXRpb24kMS55LCBlbmRUaW1lICk7XG5cdFx0XHRsaXN0ZW5lci5wb3NpdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbiQxLnosIGVuZFRpbWUgKTtcblx0XHRcdGxpc3RlbmVyLmZvcndhcmRYLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfb3JpZW50YXRpb24kMS54LCBlbmRUaW1lICk7XG5cdFx0XHRsaXN0ZW5lci5mb3J3YXJkWS5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX29yaWVudGF0aW9uJDEueSwgZW5kVGltZSApO1xuXHRcdFx0bGlzdGVuZXIuZm9yd2FyZFoubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbiQxLnosIGVuZFRpbWUgKTtcblx0XHRcdGxpc3RlbmVyLnVwWC5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggdXAueCwgZW5kVGltZSApO1xuXHRcdFx0bGlzdGVuZXIudXBZLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCB1cC55LCBlbmRUaW1lICk7XG5cdFx0XHRsaXN0ZW5lci51cFoubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIHVwLnosIGVuZFRpbWUgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdGxpc3RlbmVyLnNldFBvc2l0aW9uKCBfcG9zaXRpb24kMS54LCBfcG9zaXRpb24kMS55LCBfcG9zaXRpb24kMS56ICk7XG5cdFx0XHRsaXN0ZW5lci5zZXRPcmllbnRhdGlvbiggX29yaWVudGF0aW9uJDEueCwgX29yaWVudGF0aW9uJDEueSwgX29yaWVudGF0aW9uJDEueiwgdXAueCwgdXAueSwgdXAueiApO1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5jbGFzcyBBdWRpbyBleHRlbmRzIE9iamVjdDNEIHtcblxuXHRjb25zdHJ1Y3RvciggbGlzdGVuZXIgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ0F1ZGlvJztcblxuXHRcdHRoaXMubGlzdGVuZXIgPSBsaXN0ZW5lcjtcblx0XHR0aGlzLmNvbnRleHQgPSBsaXN0ZW5lci5jb250ZXh0O1xuXG5cdFx0dGhpcy5nYWluID0gdGhpcy5jb250ZXh0LmNyZWF0ZUdhaW4oKTtcblx0XHR0aGlzLmdhaW4uY29ubmVjdCggbGlzdGVuZXIuZ2V0SW5wdXQoKSApO1xuXG5cdFx0dGhpcy5hdXRvcGxheSA9IGZhbHNlO1xuXG5cdFx0dGhpcy5idWZmZXIgPSBudWxsO1xuXHRcdHRoaXMuZGV0dW5lID0gMDtcblx0XHR0aGlzLmxvb3AgPSBmYWxzZTtcblx0XHR0aGlzLmxvb3BTdGFydCA9IDA7XG5cdFx0dGhpcy5sb29wRW5kID0gMDtcblx0XHR0aGlzLm9mZnNldCA9IDA7XG5cdFx0dGhpcy5kdXJhdGlvbiA9IHVuZGVmaW5lZDtcblx0XHR0aGlzLnBsYXliYWNrUmF0ZSA9IDE7XG5cdFx0dGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcblx0XHR0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9IHRydWU7XG5cdFx0dGhpcy5zb3VyY2UgPSBudWxsO1xuXHRcdHRoaXMuc291cmNlVHlwZSA9ICdlbXB0eSc7XG5cblx0XHR0aGlzLl9zdGFydGVkQXQgPSAwO1xuXHRcdHRoaXMuX3Byb2dyZXNzID0gMDtcblx0XHR0aGlzLl9jb25uZWN0ZWQgPSBmYWxzZTtcblxuXHRcdHRoaXMuZmlsdGVycyA9IFtdO1xuXG5cdH1cblxuXHRnZXRPdXRwdXQoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5nYWluO1xuXG5cdH1cblxuXHRzZXROb2RlU291cmNlKCBhdWRpb05vZGUgKSB7XG5cblx0XHR0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9IGZhbHNlO1xuXHRcdHRoaXMuc291cmNlVHlwZSA9ICdhdWRpb05vZGUnO1xuXHRcdHRoaXMuc291cmNlID0gYXVkaW9Ob2RlO1xuXHRcdHRoaXMuY29ubmVjdCgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldE1lZGlhRWxlbWVudFNvdXJjZSggbWVkaWFFbGVtZW50ICkge1xuXG5cdFx0dGhpcy5oYXNQbGF5YmFja0NvbnRyb2wgPSBmYWxzZTtcblx0XHR0aGlzLnNvdXJjZVR5cGUgPSAnbWVkaWFOb2RlJztcblx0XHR0aGlzLnNvdXJjZSA9IHRoaXMuY29udGV4dC5jcmVhdGVNZWRpYUVsZW1lbnRTb3VyY2UoIG1lZGlhRWxlbWVudCApO1xuXHRcdHRoaXMuY29ubmVjdCgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldE1lZGlhU3RyZWFtU291cmNlKCBtZWRpYVN0cmVhbSApIHtcblxuXHRcdHRoaXMuaGFzUGxheWJhY2tDb250cm9sID0gZmFsc2U7XG5cdFx0dGhpcy5zb3VyY2VUeXBlID0gJ21lZGlhU3RyZWFtTm9kZSc7XG5cdFx0dGhpcy5zb3VyY2UgPSB0aGlzLmNvbnRleHQuY3JlYXRlTWVkaWFTdHJlYW1Tb3VyY2UoIG1lZGlhU3RyZWFtICk7XG5cdFx0dGhpcy5jb25uZWN0KCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0QnVmZmVyKCBhdWRpb0J1ZmZlciApIHtcblxuXHRcdHRoaXMuYnVmZmVyID0gYXVkaW9CdWZmZXI7XG5cdFx0dGhpcy5zb3VyY2VUeXBlID0gJ2J1ZmZlcic7XG5cblx0XHRpZiAoIHRoaXMuYXV0b3BsYXkgKSB0aGlzLnBsYXkoKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRwbGF5KCBkZWxheSA9IDAgKSB7XG5cblx0XHRpZiAoIHRoaXMuaXNQbGF5aW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5BdWRpbzogQXVkaW8gaXMgYWxyZWFkeSBwbGF5aW5nLicgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5oYXNQbGF5YmFja0NvbnRyb2wgPT09IGZhbHNlICkge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5BdWRpbzogdGhpcyBBdWRpbyBoYXMgbm8gcGxheWJhY2sgY29udHJvbC4nICk7XG5cdFx0XHRyZXR1cm47XG5cblx0XHR9XG5cblx0XHR0aGlzLl9zdGFydGVkQXQgPSB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUgKyBkZWxheTtcblxuXHRcdGNvbnN0IHNvdXJjZSA9IHRoaXMuY29udGV4dC5jcmVhdGVCdWZmZXJTb3VyY2UoKTtcblx0XHRzb3VyY2UuYnVmZmVyID0gdGhpcy5idWZmZXI7XG5cdFx0c291cmNlLmxvb3AgPSB0aGlzLmxvb3A7XG5cdFx0c291cmNlLmxvb3BTdGFydCA9IHRoaXMubG9vcFN0YXJ0O1xuXHRcdHNvdXJjZS5sb29wRW5kID0gdGhpcy5sb29wRW5kO1xuXHRcdHNvdXJjZS5vbmVuZGVkID0gdGhpcy5vbkVuZGVkLmJpbmQoIHRoaXMgKTtcblx0XHRzb3VyY2Uuc3RhcnQoIHRoaXMuX3N0YXJ0ZWRBdCwgdGhpcy5fcHJvZ3Jlc3MgKyB0aGlzLm9mZnNldCwgdGhpcy5kdXJhdGlvbiApO1xuXG5cdFx0dGhpcy5pc1BsYXlpbmcgPSB0cnVlO1xuXG5cdFx0dGhpcy5zb3VyY2UgPSBzb3VyY2U7XG5cblx0XHR0aGlzLnNldERldHVuZSggdGhpcy5kZXR1bmUgKTtcblx0XHR0aGlzLnNldFBsYXliYWNrUmF0ZSggdGhpcy5wbGF5YmFja1JhdGUgKTtcblxuXHRcdHJldHVybiB0aGlzLmNvbm5lY3QoKTtcblxuXHR9XG5cblx0cGF1c2UoKSB7XG5cblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQXVkaW86IHRoaXMgQXVkaW8gaGFzIG5vIHBsYXliYWNrIGNvbnRyb2wuJyApO1xuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmlzUGxheWluZyA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0Ly8gdXBkYXRlIGN1cnJlbnQgcHJvZ3Jlc3NcblxuXHRcdFx0dGhpcy5fcHJvZ3Jlc3MgKz0gTWF0aC5tYXgoIHRoaXMuY29udGV4dC5jdXJyZW50VGltZSAtIHRoaXMuX3N0YXJ0ZWRBdCwgMCApICogdGhpcy5wbGF5YmFja1JhdGU7XG5cblx0XHRcdGlmICggdGhpcy5sb29wID09PSB0cnVlICkge1xuXG5cdFx0XHRcdC8vIGVuc3VyZSBfcHJvZ3Jlc3MgZG9lcyBub3QgZXhjZWVkIGR1cmF0aW9uIHdpdGggbG9vcGVkIGF1ZGlvc1xuXG5cdFx0XHRcdHRoaXMuX3Byb2dyZXNzID0gdGhpcy5fcHJvZ3Jlc3MgJSAoIHRoaXMuZHVyYXRpb24gfHwgdGhpcy5idWZmZXIuZHVyYXRpb24gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLnNvdXJjZS5zdG9wKCk7XG5cdFx0XHR0aGlzLnNvdXJjZS5vbmVuZGVkID0gbnVsbDtcblxuXHRcdFx0dGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdG9wKCkge1xuXG5cdFx0aWYgKCB0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdHRoaXMuX3Byb2dyZXNzID0gMDtcblxuXHRcdGlmICggdGhpcy5zb3VyY2UgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuc291cmNlLnN0b3AoKTtcblx0XHRcdHRoaXMuc291cmNlLm9uZW5kZWQgPSBudWxsO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5pc1BsYXlpbmcgPSBmYWxzZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb25uZWN0KCkge1xuXG5cdFx0aWYgKCB0aGlzLmZpbHRlcnMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0dGhpcy5zb3VyY2UuY29ubmVjdCggdGhpcy5maWx0ZXJzWyAwIF0gKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAxLCBsID0gdGhpcy5maWx0ZXJzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0dGhpcy5maWx0ZXJzWyBpIC0gMSBdLmNvbm5lY3QoIHRoaXMuZmlsdGVyc1sgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5maWx0ZXJzWyB0aGlzLmZpbHRlcnMubGVuZ3RoIC0gMSBdLmNvbm5lY3QoIHRoaXMuZ2V0T3V0cHV0KCkgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuc291cmNlLmNvbm5lY3QoIHRoaXMuZ2V0T3V0cHV0KCkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuX2Nvbm5lY3RlZCA9IHRydWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGlzY29ubmVjdCgpIHtcblxuXHRcdGlmICggdGhpcy5fY29ubmVjdGVkID09PSBmYWxzZSApIHtcblxuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmZpbHRlcnMubGVuZ3RoID4gMCApIHtcblxuXHRcdFx0dGhpcy5zb3VyY2UuZGlzY29ubmVjdCggdGhpcy5maWx0ZXJzWyAwIF0gKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAxLCBsID0gdGhpcy5maWx0ZXJzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdFx0dGhpcy5maWx0ZXJzWyBpIC0gMSBdLmRpc2Nvbm5lY3QoIHRoaXMuZmlsdGVyc1sgaSBdICk7XG5cblx0XHRcdH1cblxuXHRcdFx0dGhpcy5maWx0ZXJzWyB0aGlzLmZpbHRlcnMubGVuZ3RoIC0gMSBdLmRpc2Nvbm5lY3QoIHRoaXMuZ2V0T3V0cHV0KCkgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuc291cmNlLmRpc2Nvbm5lY3QoIHRoaXMuZ2V0T3V0cHV0KCkgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuX2Nvbm5lY3RlZCA9IGZhbHNlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldEZpbHRlcnMoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5maWx0ZXJzO1xuXG5cdH1cblxuXHRzZXRGaWx0ZXJzKCB2YWx1ZSApIHtcblxuXHRcdGlmICggISB2YWx1ZSApIHZhbHVlID0gW107XG5cblx0XHRpZiAoIHRoaXMuX2Nvbm5lY3RlZCA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0dGhpcy5kaXNjb25uZWN0KCk7XG5cdFx0XHR0aGlzLmZpbHRlcnMgPSB2YWx1ZS5zbGljZSgpO1xuXHRcdFx0dGhpcy5jb25uZWN0KCk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLmZpbHRlcnMgPSB2YWx1ZS5zbGljZSgpO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldERldHVuZSggdmFsdWUgKSB7XG5cblx0XHR0aGlzLmRldHVuZSA9IHZhbHVlO1xuXG5cdFx0aWYgKCB0aGlzLmlzUGxheWluZyA9PT0gdHJ1ZSAmJiB0aGlzLnNvdXJjZS5kZXR1bmUgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGhpcy5zb3VyY2UuZGV0dW5lLnNldFRhcmdldEF0VGltZSggdGhpcy5kZXR1bmUsIHRoaXMuY29udGV4dC5jdXJyZW50VGltZSwgMC4wMSApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldERldHVuZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLmRldHVuZTtcblxuXHR9XG5cblx0Z2V0RmlsdGVyKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZ2V0RmlsdGVycygpWyAwIF07XG5cblx0fVxuXG5cdHNldEZpbHRlciggZmlsdGVyICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuc2V0RmlsdGVycyggZmlsdGVyID8gWyBmaWx0ZXIgXSA6IFtdICk7XG5cblx0fVxuXG5cdHNldFBsYXliYWNrUmF0ZSggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHRoaXMuaGFzUGxheWJhY2tDb250cm9sID09PSBmYWxzZSApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuQXVkaW86IHRoaXMgQXVkaW8gaGFzIG5vIHBsYXliYWNrIGNvbnRyb2wuJyApO1xuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5wbGF5YmFja1JhdGUgPSB2YWx1ZTtcblxuXHRcdGlmICggdGhpcy5pc1BsYXlpbmcgPT09IHRydWUgKSB7XG5cblx0XHRcdHRoaXMuc291cmNlLnBsYXliYWNrUmF0ZS5zZXRUYXJnZXRBdFRpbWUoIHRoaXMucGxheWJhY2tSYXRlLCB0aGlzLmNvbnRleHQuY3VycmVudFRpbWUsIDAuMDEgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRQbGF5YmFja1JhdGUoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5wbGF5YmFja1JhdGU7XG5cblx0fVxuXG5cdG9uRW5kZWQoKSB7XG5cblx0XHR0aGlzLmlzUGxheWluZyA9IGZhbHNlO1xuXG5cdH1cblxuXHRnZXRMb29wKCkge1xuXG5cdFx0aWYgKCB0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcblx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzLmxvb3A7XG5cblx0fVxuXG5cdHNldExvb3AoIHZhbHVlICkge1xuXG5cdFx0aWYgKCB0aGlzLmhhc1BsYXliYWNrQ29udHJvbCA9PT0gZmFsc2UgKSB7XG5cblx0XHRcdGNvbnNvbGUud2FybiggJ1RIUkVFLkF1ZGlvOiB0aGlzIEF1ZGlvIGhhcyBubyBwbGF5YmFjayBjb250cm9sLicgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdHRoaXMubG9vcCA9IHZhbHVlO1xuXG5cdFx0aWYgKCB0aGlzLmlzUGxheWluZyA9PT0gdHJ1ZSApIHtcblxuXHRcdFx0dGhpcy5zb3VyY2UubG9vcCA9IHRoaXMubG9vcDtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRMb29wU3RhcnQoIHZhbHVlICkge1xuXG5cdFx0dGhpcy5sb29wU3RhcnQgPSB2YWx1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRMb29wRW5kKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMubG9vcEVuZCA9IHZhbHVlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldFZvbHVtZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLmdhaW4uZ2Fpbi52YWx1ZTtcblxuXHR9XG5cblx0c2V0Vm9sdW1lKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMuZ2Fpbi5nYWluLnNldFRhcmdldEF0VGltZSggdmFsdWUsIHRoaXMuY29udGV4dC5jdXJyZW50VGltZSwgMC4wMSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9wb3NpdGlvbiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9xdWF0ZXJuaW9uID0gLypAX19QVVJFX18qLyBuZXcgUXVhdGVybmlvbigpO1xuY29uc3QgX3NjYWxlID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX29yaWVudGF0aW9uID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jbGFzcyBQb3NpdGlvbmFsQXVkaW8gZXh0ZW5kcyBBdWRpbyB7XG5cblx0Y29uc3RydWN0b3IoIGxpc3RlbmVyICkge1xuXG5cdFx0c3VwZXIoIGxpc3RlbmVyICk7XG5cblx0XHR0aGlzLnBhbm5lciA9IHRoaXMuY29udGV4dC5jcmVhdGVQYW5uZXIoKTtcblx0XHR0aGlzLnBhbm5lci5wYW5uaW5nTW9kZWwgPSAnSFJURic7XG5cdFx0dGhpcy5wYW5uZXIuY29ubmVjdCggdGhpcy5nYWluICk7XG5cblx0fVxuXG5cdGNvbm5lY3QoKSB7XG5cblx0XHRzdXBlci5jb25uZWN0KCk7XG5cblx0XHR0aGlzLnBhbm5lci5jb25uZWN0KCB0aGlzLmdhaW4gKTtcblxuXHR9XG5cblx0ZGlzY29ubmVjdCgpIHtcblxuXHRcdHN1cGVyLmRpc2Nvbm5lY3QoKTtcblxuXHRcdHRoaXMucGFubmVyLmRpc2Nvbm5lY3QoIHRoaXMuZ2FpbiApO1xuXG5cdH1cblxuXHRnZXRPdXRwdXQoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5wYW5uZXI7XG5cblx0fVxuXG5cdGdldFJlZkRpc3RhbmNlKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMucGFubmVyLnJlZkRpc3RhbmNlO1xuXG5cdH1cblxuXHRzZXRSZWZEaXN0YW5jZSggdmFsdWUgKSB7XG5cblx0XHR0aGlzLnBhbm5lci5yZWZEaXN0YW5jZSA9IHZhbHVlO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGdldFJvbGxvZmZGYWN0b3IoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5wYW5uZXIucm9sbG9mZkZhY3RvcjtcblxuXHR9XG5cblx0c2V0Um9sbG9mZkZhY3RvciggdmFsdWUgKSB7XG5cblx0XHR0aGlzLnBhbm5lci5yb2xsb2ZmRmFjdG9yID0gdmFsdWU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Z2V0RGlzdGFuY2VNb2RlbCgpIHtcblxuXHRcdHJldHVybiB0aGlzLnBhbm5lci5kaXN0YW5jZU1vZGVsO1xuXG5cdH1cblxuXHRzZXREaXN0YW5jZU1vZGVsKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMucGFubmVyLmRpc3RhbmNlTW9kZWwgPSB2YWx1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRNYXhEaXN0YW5jZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLnBhbm5lci5tYXhEaXN0YW5jZTtcblxuXHR9XG5cblx0c2V0TWF4RGlzdGFuY2UoIHZhbHVlICkge1xuXG5cdFx0dGhpcy5wYW5uZXIubWF4RGlzdGFuY2UgPSB2YWx1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXREaXJlY3Rpb25hbENvbmUoIGNvbmVJbm5lckFuZ2xlLCBjb25lT3V0ZXJBbmdsZSwgY29uZU91dGVyR2FpbiApIHtcblxuXHRcdHRoaXMucGFubmVyLmNvbmVJbm5lckFuZ2xlID0gY29uZUlubmVyQW5nbGU7XG5cdFx0dGhpcy5wYW5uZXIuY29uZU91dGVyQW5nbGUgPSBjb25lT3V0ZXJBbmdsZTtcblx0XHR0aGlzLnBhbm5lci5jb25lT3V0ZXJHYWluID0gY29uZU91dGVyR2FpbjtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XG5cblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcblxuXHRcdGlmICggdGhpcy5oYXNQbGF5YmFja0NvbnRyb2wgPT09IHRydWUgJiYgdGhpcy5pc1BsYXlpbmcgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0dGhpcy5tYXRyaXhXb3JsZC5kZWNvbXBvc2UoIF9wb3NpdGlvbiwgX3F1YXRlcm5pb24sIF9zY2FsZSApO1xuXG5cdFx0X29yaWVudGF0aW9uLnNldCggMCwgMCwgMSApLmFwcGx5UXVhdGVybmlvbiggX3F1YXRlcm5pb24gKTtcblxuXHRcdGNvbnN0IHBhbm5lciA9IHRoaXMucGFubmVyO1xuXG5cdFx0aWYgKCBwYW5uZXIucG9zaXRpb25YICkge1xuXG5cdFx0XHQvLyBjb2RlIHBhdGggZm9yIENocm9tZSBhbmQgRmlyZWZveCAoc2VlICMxNDM5MylcblxuXHRcdFx0Y29uc3QgZW5kVGltZSA9IHRoaXMuY29udGV4dC5jdXJyZW50VGltZSArIHRoaXMubGlzdGVuZXIudGltZURlbHRhO1xuXG5cdFx0XHRwYW5uZXIucG9zaXRpb25YLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfcG9zaXRpb24ueCwgZW5kVGltZSApO1xuXHRcdFx0cGFubmVyLnBvc2l0aW9uWS5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX3Bvc2l0aW9uLnksIGVuZFRpbWUgKTtcblx0XHRcdHBhbm5lci5wb3NpdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9wb3NpdGlvbi56LCBlbmRUaW1lICk7XG5cdFx0XHRwYW5uZXIub3JpZW50YXRpb25YLmxpbmVhclJhbXBUb1ZhbHVlQXRUaW1lKCBfb3JpZW50YXRpb24ueCwgZW5kVGltZSApO1xuXHRcdFx0cGFubmVyLm9yaWVudGF0aW9uWS5saW5lYXJSYW1wVG9WYWx1ZUF0VGltZSggX29yaWVudGF0aW9uLnksIGVuZFRpbWUgKTtcblx0XHRcdHBhbm5lci5vcmllbnRhdGlvbloubGluZWFyUmFtcFRvVmFsdWVBdFRpbWUoIF9vcmllbnRhdGlvbi56LCBlbmRUaW1lICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHRwYW5uZXIuc2V0UG9zaXRpb24oIF9wb3NpdGlvbi54LCBfcG9zaXRpb24ueSwgX3Bvc2l0aW9uLnogKTtcblx0XHRcdHBhbm5lci5zZXRPcmllbnRhdGlvbiggX29yaWVudGF0aW9uLngsIF9vcmllbnRhdGlvbi55LCBfb3JpZW50YXRpb24ueiApO1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG5jbGFzcyBBdWRpb0FuYWx5c2VyIHtcblxuXHRjb25zdHJ1Y3RvciggYXVkaW8sIGZmdFNpemUgPSAyMDQ4ICkge1xuXG5cdFx0dGhpcy5hbmFseXNlciA9IGF1ZGlvLmNvbnRleHQuY3JlYXRlQW5hbHlzZXIoKTtcblx0XHR0aGlzLmFuYWx5c2VyLmZmdFNpemUgPSBmZnRTaXplO1xuXG5cdFx0dGhpcy5kYXRhID0gbmV3IFVpbnQ4QXJyYXkoIHRoaXMuYW5hbHlzZXIuZnJlcXVlbmN5QmluQ291bnQgKTtcblxuXHRcdGF1ZGlvLmdldE91dHB1dCgpLmNvbm5lY3QoIHRoaXMuYW5hbHlzZXIgKTtcblxuXHR9XG5cblxuXHRnZXRGcmVxdWVuY3lEYXRhKCkge1xuXG5cdFx0dGhpcy5hbmFseXNlci5nZXRCeXRlRnJlcXVlbmN5RGF0YSggdGhpcy5kYXRhICk7XG5cblx0XHRyZXR1cm4gdGhpcy5kYXRhO1xuXG5cdH1cblxuXHRnZXRBdmVyYWdlRnJlcXVlbmN5KCkge1xuXG5cdFx0bGV0IHZhbHVlID0gMDtcblx0XHRjb25zdCBkYXRhID0gdGhpcy5nZXRGcmVxdWVuY3lEYXRhKCk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBkYXRhLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0dmFsdWUgKz0gZGF0YVsgaSBdO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHZhbHVlIC8gZGF0YS5sZW5ndGg7XG5cblx0fVxuXG59XG5cbmNsYXNzIFByb3BlcnR5TWl4ZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBiaW5kaW5nLCB0eXBlTmFtZSwgdmFsdWVTaXplICkge1xuXG5cdFx0dGhpcy5iaW5kaW5nID0gYmluZGluZztcblx0XHR0aGlzLnZhbHVlU2l6ZSA9IHZhbHVlU2l6ZTtcblxuXHRcdGxldCBtaXhGdW5jdGlvbixcblx0XHRcdG1peEZ1bmN0aW9uQWRkaXRpdmUsXG5cdFx0XHRzZXRJZGVudGl0eTtcblxuXHRcdC8vIGJ1ZmZlciBsYXlvdXQ6IFsgaW5jb21pbmcgfCBhY2N1MCB8IGFjY3UxIHwgb3JpZyB8IGFkZEFjY3UgfCAob3B0aW9uYWwgd29yaykgXVxuXHRcdC8vXG5cdFx0Ly8gaW50ZXJwb2xhdG9ycyBjYW4gdXNlIC5idWZmZXIgYXMgdGhlaXIgLnJlc3VsdFxuXHRcdC8vIHRoZSBkYXRhIHRoZW4gZ29lcyB0byAnaW5jb21pbmcnXG5cdFx0Ly9cblx0XHQvLyAnYWNjdTAnIGFuZCAnYWNjdTEnIGFyZSB1c2VkIGZyYW1lLWludGVybGVhdmVkIGZvclxuXHRcdC8vIHRoZSBjdW11bGF0aXZlIHJlc3VsdCBhbmQgYXJlIGNvbXBhcmVkIHRvIGRldGVjdFxuXHRcdC8vIGNoYW5nZXNcblx0XHQvL1xuXHRcdC8vICdvcmlnJyBzdG9yZXMgdGhlIG9yaWdpbmFsIHN0YXRlIG9mIHRoZSBwcm9wZXJ0eVxuXHRcdC8vXG5cdFx0Ly8gJ2FkZCcgaXMgdXNlZCBmb3IgYWRkaXRpdmUgY3VtdWxhdGl2ZSByZXN1bHRzXG5cdFx0Ly9cblx0XHQvLyAnd29yaycgaXMgb3B0aW9uYWwgYW5kIGlzIG9ubHkgcHJlc2VudCBmb3IgcXVhdGVybmlvbiB0eXBlcy4gSXQgaXMgdXNlZFxuXHRcdC8vIHRvIHN0b3JlIGludGVybWVkaWF0ZSBxdWF0ZXJuaW9uIG11bHRpcGxpY2F0aW9uIHJlc3VsdHNcblxuXHRcdHN3aXRjaCAoIHR5cGVOYW1lICkge1xuXG5cdFx0XHRjYXNlICdxdWF0ZXJuaW9uJzpcblx0XHRcdFx0bWl4RnVuY3Rpb24gPSB0aGlzLl9zbGVycDtcblx0XHRcdFx0bWl4RnVuY3Rpb25BZGRpdGl2ZSA9IHRoaXMuX3NsZXJwQWRkaXRpdmU7XG5cdFx0XHRcdHNldElkZW50aXR5ID0gdGhpcy5fc2V0QWRkaXRpdmVJZGVudGl0eVF1YXRlcm5pb247XG5cblx0XHRcdFx0dGhpcy5idWZmZXIgPSBuZXcgRmxvYXQ2NEFycmF5KCB2YWx1ZVNpemUgKiA2ICk7XG5cdFx0XHRcdHRoaXMuX3dvcmtJbmRleCA9IDU7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRjYXNlICdzdHJpbmcnOlxuXHRcdFx0Y2FzZSAnYm9vbCc6XG5cdFx0XHRcdG1peEZ1bmN0aW9uID0gdGhpcy5fc2VsZWN0O1xuXG5cdFx0XHRcdC8vIFVzZSB0aGUgcmVndWxhciBtaXggZnVuY3Rpb24gYW5kIGZvciBhZGRpdGl2ZSBvbiB0aGVzZSB0eXBlcyxcblx0XHRcdFx0Ly8gYWRkaXRpdmUgaXMgbm90IHJlbGV2YW50IGZvciBub24tbnVtZXJpYyB0eXBlc1xuXHRcdFx0XHRtaXhGdW5jdGlvbkFkZGl0aXZlID0gdGhpcy5fc2VsZWN0O1xuXG5cdFx0XHRcdHNldElkZW50aXR5ID0gdGhpcy5fc2V0QWRkaXRpdmVJZGVudGl0eU90aGVyO1xuXG5cdFx0XHRcdHRoaXMuYnVmZmVyID0gbmV3IEFycmF5KCB2YWx1ZVNpemUgKiA1ICk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRkZWZhdWx0OlxuXHRcdFx0XHRtaXhGdW5jdGlvbiA9IHRoaXMuX2xlcnA7XG5cdFx0XHRcdG1peEZ1bmN0aW9uQWRkaXRpdmUgPSB0aGlzLl9sZXJwQWRkaXRpdmU7XG5cdFx0XHRcdHNldElkZW50aXR5ID0gdGhpcy5fc2V0QWRkaXRpdmVJZGVudGl0eU51bWVyaWM7XG5cblx0XHRcdFx0dGhpcy5idWZmZXIgPSBuZXcgRmxvYXQ2NEFycmF5KCB2YWx1ZVNpemUgKiA1ICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb24gPSBtaXhGdW5jdGlvbjtcblx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb25BZGRpdGl2ZSA9IG1peEZ1bmN0aW9uQWRkaXRpdmU7XG5cdFx0dGhpcy5fc2V0SWRlbnRpdHkgPSBzZXRJZGVudGl0eTtcblx0XHR0aGlzLl9vcmlnSW5kZXggPSAzO1xuXHRcdHRoaXMuX2FkZEluZGV4ID0gNDtcblxuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodCA9IDA7XG5cdFx0dGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUgPSAwO1xuXG5cdFx0dGhpcy51c2VDb3VudCA9IDA7XG5cdFx0dGhpcy5yZWZlcmVuY2VDb3VudCA9IDA7XG5cblx0fVxuXG5cdC8vIGFjY3VtdWxhdGUgZGF0YSBpbiB0aGUgJ2luY29taW5nJyByZWdpb24gaW50byAnYWNjdTxpPidcblx0YWNjdW11bGF0ZSggYWNjdUluZGV4LCB3ZWlnaHQgKSB7XG5cblx0XHQvLyBub3RlOiBoYXBwaWx5IGFjY3VtdWxhdGluZyBub3RoaW5nIHdoZW4gd2VpZ2h0ID0gMCwgdGhlIGNhbGxlciBrbm93c1xuXHRcdC8vIHRoZSB3ZWlnaHQgYW5kIHNob3VsZG4ndCBoYXZlIG1hZGUgdGhlIGNhbGwgaW4gdGhlIGZpcnN0IHBsYWNlXG5cblx0XHRjb25zdCBidWZmZXIgPSB0aGlzLmJ1ZmZlcixcblx0XHRcdHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxuXHRcdFx0b2Zmc2V0ID0gYWNjdUluZGV4ICogc3RyaWRlICsgc3RyaWRlO1xuXG5cdFx0bGV0IGN1cnJlbnRXZWlnaHQgPSB0aGlzLmN1bXVsYXRpdmVXZWlnaHQ7XG5cblx0XHRpZiAoIGN1cnJlbnRXZWlnaHQgPT09IDAgKSB7XG5cblx0XHRcdC8vIGFjY3VOIDo9IGluY29taW5nICogd2VpZ2h0XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gc3RyaWRlOyArKyBpICkge1xuXG5cdFx0XHRcdGJ1ZmZlclsgb2Zmc2V0ICsgaSBdID0gYnVmZmVyWyBpIF07XG5cblx0XHRcdH1cblxuXHRcdFx0Y3VycmVudFdlaWdodCA9IHdlaWdodDtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdC8vIGFjY3VOIDo9IGFjY3VOICsgaW5jb21pbmcgKiB3ZWlnaHRcblxuXHRcdFx0Y3VycmVudFdlaWdodCArPSB3ZWlnaHQ7XG5cdFx0XHRjb25zdCBtaXggPSB3ZWlnaHQgLyBjdXJyZW50V2VpZ2h0O1xuXHRcdFx0dGhpcy5fbWl4QnVmZmVyUmVnaW9uKCBidWZmZXIsIG9mZnNldCwgMCwgbWl4LCBzdHJpZGUgKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodCA9IGN1cnJlbnRXZWlnaHQ7XG5cblx0fVxuXG5cdC8vIGFjY3VtdWxhdGUgZGF0YSBpbiB0aGUgJ2luY29taW5nJyByZWdpb24gaW50byAnYWRkJ1xuXHRhY2N1bXVsYXRlQWRkaXRpdmUoIHdlaWdodCApIHtcblxuXHRcdGNvbnN0IGJ1ZmZlciA9IHRoaXMuYnVmZmVyLFxuXHRcdFx0c3RyaWRlID0gdGhpcy52YWx1ZVNpemUsXG5cdFx0XHRvZmZzZXQgPSBzdHJpZGUgKiB0aGlzLl9hZGRJbmRleDtcblxuXHRcdGlmICggdGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUgPT09IDAgKSB7XG5cblx0XHRcdC8vIGFkZCA9IGlkZW50aXR5XG5cblx0XHRcdHRoaXMuX3NldElkZW50aXR5KCk7XG5cblx0XHR9XG5cblx0XHQvLyBhZGQgOj0gYWRkICsgaW5jb21pbmcgKiB3ZWlnaHRcblxuXHRcdHRoaXMuX21peEJ1ZmZlclJlZ2lvbkFkZGl0aXZlKCBidWZmZXIsIG9mZnNldCwgMCwgd2VpZ2h0LCBzdHJpZGUgKTtcblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHRBZGRpdGl2ZSArPSB3ZWlnaHQ7XG5cblx0fVxuXG5cdC8vIGFwcGx5IHRoZSBzdGF0ZSBvZiAnYWNjdTxpPicgdG8gdGhlIGJpbmRpbmcgd2hlbiBhY2N1cyBkaWZmZXJcblx0YXBwbHkoIGFjY3VJbmRleCApIHtcblxuXHRcdGNvbnN0IHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxuXHRcdFx0YnVmZmVyID0gdGhpcy5idWZmZXIsXG5cdFx0XHRvZmZzZXQgPSBhY2N1SW5kZXggKiBzdHJpZGUgKyBzdHJpZGUsXG5cblx0XHRcdHdlaWdodCA9IHRoaXMuY3VtdWxhdGl2ZVdlaWdodCxcblx0XHRcdHdlaWdodEFkZGl0aXZlID0gdGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUsXG5cblx0XHRcdGJpbmRpbmcgPSB0aGlzLmJpbmRpbmc7XG5cblx0XHR0aGlzLmN1bXVsYXRpdmVXZWlnaHQgPSAwO1xuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodEFkZGl0aXZlID0gMDtcblxuXHRcdGlmICggd2VpZ2h0IDwgMSApIHtcblxuXHRcdFx0Ly8gYWNjdU4gOj0gYWNjdU4gKyBvcmlnaW5hbCAqICggMSAtIGN1bXVsYXRpdmVXZWlnaHQgKVxuXG5cdFx0XHRjb25zdCBvcmlnaW5hbFZhbHVlT2Zmc2V0ID0gc3RyaWRlICogdGhpcy5fb3JpZ0luZGV4O1xuXG5cdFx0XHR0aGlzLl9taXhCdWZmZXJSZWdpb24oXG5cdFx0XHRcdGJ1ZmZlciwgb2Zmc2V0LCBvcmlnaW5hbFZhbHVlT2Zmc2V0LCAxIC0gd2VpZ2h0LCBzdHJpZGUgKTtcblxuXHRcdH1cblxuXHRcdGlmICggd2VpZ2h0QWRkaXRpdmUgPiAwICkge1xuXG5cdFx0XHQvLyBhY2N1TiA6PSBhY2N1TiArIGFkZGl0aXZlIGFjY3VOXG5cblx0XHRcdHRoaXMuX21peEJ1ZmZlclJlZ2lvbkFkZGl0aXZlKCBidWZmZXIsIG9mZnNldCwgdGhpcy5fYWRkSW5kZXggKiBzdHJpZGUsIDEsIHN0cmlkZSApO1xuXG5cdFx0fVxuXG5cdFx0Zm9yICggbGV0IGkgPSBzdHJpZGUsIGUgPSBzdHJpZGUgKyBzdHJpZGU7IGkgIT09IGU7ICsrIGkgKSB7XG5cblx0XHRcdGlmICggYnVmZmVyWyBpIF0gIT09IGJ1ZmZlclsgaSArIHN0cmlkZSBdICkge1xuXG5cdFx0XHRcdC8vIHZhbHVlIGhhcyBjaGFuZ2VkIC0+IHVwZGF0ZSBzY2VuZSBncmFwaFxuXG5cdFx0XHRcdGJpbmRpbmcuc2V0VmFsdWUoIGJ1ZmZlciwgb2Zmc2V0ICk7XG5cdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdC8vIHJlbWVtYmVyIHRoZSBzdGF0ZSBvZiB0aGUgYm91bmQgcHJvcGVydHkgYW5kIGNvcHkgaXQgdG8gYm90aCBhY2N1c1xuXHRzYXZlT3JpZ2luYWxTdGF0ZSgpIHtcblxuXHRcdGNvbnN0IGJpbmRpbmcgPSB0aGlzLmJpbmRpbmc7XG5cblx0XHRjb25zdCBidWZmZXIgPSB0aGlzLmJ1ZmZlcixcblx0XHRcdHN0cmlkZSA9IHRoaXMudmFsdWVTaXplLFxuXG5cdFx0XHRvcmlnaW5hbFZhbHVlT2Zmc2V0ID0gc3RyaWRlICogdGhpcy5fb3JpZ0luZGV4O1xuXG5cdFx0YmluZGluZy5nZXRWYWx1ZSggYnVmZmVyLCBvcmlnaW5hbFZhbHVlT2Zmc2V0ICk7XG5cblx0XHQvLyBhY2N1WzAuLjFdIDo9IG9yaWcgLS0gaW5pdGlhbGx5IGRldGVjdCBjaGFuZ2VzIGFnYWluc3QgdGhlIG9yaWdpbmFsXG5cdFx0Zm9yICggbGV0IGkgPSBzdHJpZGUsIGUgPSBvcmlnaW5hbFZhbHVlT2Zmc2V0OyBpICE9PSBlOyArKyBpICkge1xuXG5cdFx0XHRidWZmZXJbIGkgXSA9IGJ1ZmZlclsgb3JpZ2luYWxWYWx1ZU9mZnNldCArICggaSAlIHN0cmlkZSApIF07XG5cblx0XHR9XG5cblx0XHQvLyBBZGQgdG8gaWRlbnRpdHkgZm9yIGFkZGl0aXZlXG5cdFx0dGhpcy5fc2V0SWRlbnRpdHkoKTtcblxuXHRcdHRoaXMuY3VtdWxhdGl2ZVdlaWdodCA9IDA7XG5cdFx0dGhpcy5jdW11bGF0aXZlV2VpZ2h0QWRkaXRpdmUgPSAwO1xuXG5cdH1cblxuXHQvLyBhcHBseSB0aGUgc3RhdGUgcHJldmlvdXNseSB0YWtlbiB2aWEgJ3NhdmVPcmlnaW5hbFN0YXRlJyB0byB0aGUgYmluZGluZ1xuXHRyZXN0b3JlT3JpZ2luYWxTdGF0ZSgpIHtcblxuXHRcdGNvbnN0IG9yaWdpbmFsVmFsdWVPZmZzZXQgPSB0aGlzLnZhbHVlU2l6ZSAqIDM7XG5cdFx0dGhpcy5iaW5kaW5nLnNldFZhbHVlKCB0aGlzLmJ1ZmZlciwgb3JpZ2luYWxWYWx1ZU9mZnNldCApO1xuXG5cdH1cblxuXHRfc2V0QWRkaXRpdmVJZGVudGl0eU51bWVyaWMoKSB7XG5cblx0XHRjb25zdCBzdGFydEluZGV4ID0gdGhpcy5fYWRkSW5kZXggKiB0aGlzLnZhbHVlU2l6ZTtcblx0XHRjb25zdCBlbmRJbmRleCA9IHN0YXJ0SW5kZXggKyB0aGlzLnZhbHVlU2l6ZTtcblxuXHRcdGZvciAoIGxldCBpID0gc3RhcnRJbmRleDsgaSA8IGVuZEluZGV4OyBpICsrICkge1xuXG5cdFx0XHR0aGlzLmJ1ZmZlclsgaSBdID0gMDtcblxuXHRcdH1cblxuXHR9XG5cblx0X3NldEFkZGl0aXZlSWRlbnRpdHlRdWF0ZXJuaW9uKCkge1xuXG5cdFx0dGhpcy5fc2V0QWRkaXRpdmVJZGVudGl0eU51bWVyaWMoKTtcblx0XHR0aGlzLmJ1ZmZlclsgdGhpcy5fYWRkSW5kZXggKiB0aGlzLnZhbHVlU2l6ZSArIDMgXSA9IDE7XG5cblx0fVxuXG5cdF9zZXRBZGRpdGl2ZUlkZW50aXR5T3RoZXIoKSB7XG5cblx0XHRjb25zdCBzdGFydEluZGV4ID0gdGhpcy5fb3JpZ0luZGV4ICogdGhpcy52YWx1ZVNpemU7XG5cdFx0Y29uc3QgdGFyZ2V0SW5kZXggPSB0aGlzLl9hZGRJbmRleCAqIHRoaXMudmFsdWVTaXplO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy52YWx1ZVNpemU7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuYnVmZmVyWyB0YXJnZXRJbmRleCArIGkgXSA9IHRoaXMuYnVmZmVyWyBzdGFydEluZGV4ICsgaSBdO1xuXG5cdFx0fVxuXG5cdH1cblxuXG5cdC8vIG1peCBmdW5jdGlvbnNcblxuXHRfc2VsZWN0KCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XG5cblx0XHRpZiAoIHQgPj0gMC41ICkge1xuXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IHN0cmlkZTsgKysgaSApIHtcblxuXHRcdFx0XHRidWZmZXJbIGRzdE9mZnNldCArIGkgXSA9IGJ1ZmZlclsgc3JjT2Zmc2V0ICsgaSBdO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdF9zbGVycCggYnVmZmVyLCBkc3RPZmZzZXQsIHNyY09mZnNldCwgdCApIHtcblxuXHRcdFF1YXRlcm5pb24uc2xlcnBGbGF0KCBidWZmZXIsIGRzdE9mZnNldCwgYnVmZmVyLCBkc3RPZmZzZXQsIGJ1ZmZlciwgc3JjT2Zmc2V0LCB0ICk7XG5cblx0fVxuXG5cdF9zbGVycEFkZGl0aXZlKCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XG5cblx0XHRjb25zdCB3b3JrT2Zmc2V0ID0gdGhpcy5fd29ya0luZGV4ICogc3RyaWRlO1xuXG5cdFx0Ly8gU3RvcmUgcmVzdWx0IGluIGludGVybWVkaWF0ZSBidWZmZXIgb2Zmc2V0XG5cdFx0UXVhdGVybmlvbi5tdWx0aXBseVF1YXRlcm5pb25zRmxhdCggYnVmZmVyLCB3b3JrT2Zmc2V0LCBidWZmZXIsIGRzdE9mZnNldCwgYnVmZmVyLCBzcmNPZmZzZXQgKTtcblxuXHRcdC8vIFNsZXJwIHRvIHRoZSBpbnRlcm1lZGlhdGUgcmVzdWx0XG5cdFx0UXVhdGVybmlvbi5zbGVycEZsYXQoIGJ1ZmZlciwgZHN0T2Zmc2V0LCBidWZmZXIsIGRzdE9mZnNldCwgYnVmZmVyLCB3b3JrT2Zmc2V0LCB0ICk7XG5cblx0fVxuXG5cdF9sZXJwKCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XG5cblx0XHRjb25zdCBzID0gMSAtIHQ7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IHN0cmlkZTsgKysgaSApIHtcblxuXHRcdFx0Y29uc3QgaiA9IGRzdE9mZnNldCArIGk7XG5cblx0XHRcdGJ1ZmZlclsgaiBdID0gYnVmZmVyWyBqIF0gKiBzICsgYnVmZmVyWyBzcmNPZmZzZXQgKyBpIF0gKiB0O1xuXG5cdFx0fVxuXG5cdH1cblxuXHRfbGVycEFkZGl0aXZlKCBidWZmZXIsIGRzdE9mZnNldCwgc3JjT2Zmc2V0LCB0LCBzdHJpZGUgKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgIT09IHN0cmlkZTsgKysgaSApIHtcblxuXHRcdFx0Y29uc3QgaiA9IGRzdE9mZnNldCArIGk7XG5cblx0XHRcdGJ1ZmZlclsgaiBdID0gYnVmZmVyWyBqIF0gKyBidWZmZXJbIHNyY09mZnNldCArIGkgXSAqIHQ7XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbi8vIENoYXJhY3RlcnMgW10uOi8gYXJlIHJlc2VydmVkIGZvciB0cmFjayBiaW5kaW5nIHN5bnRheC5cbmNvbnN0IF9SRVNFUlZFRF9DSEFSU19SRSA9ICdcXFxcW1xcXFxdXFxcXC46XFxcXC8nO1xuY29uc3QgX3Jlc2VydmVkUmUgPSBuZXcgUmVnRXhwKCAnWycgKyBfUkVTRVJWRURfQ0hBUlNfUkUgKyAnXScsICdnJyApO1xuXG4vLyBBdHRlbXB0cyB0byBhbGxvdyBub2RlIG5hbWVzIGZyb20gYW55IGxhbmd1YWdlLiBFUzUncyBgXFx3YCByZWdleHAgbWF0Y2hlc1xuLy8gb25seSBsYXRpbiBjaGFyYWN0ZXJzLCBhbmQgdGhlIHVuaWNvZGUgXFxwe0x9IGlzIG5vdCB5ZXQgc3VwcG9ydGVkLiBTb1xuLy8gaW5zdGVhZCwgd2UgZXhjbHVkZSByZXNlcnZlZCBjaGFyYWN0ZXJzIGFuZCBtYXRjaCBldmVyeXRoaW5nIGVsc2UuXG5jb25zdCBfd29yZENoYXIgPSAnW14nICsgX1JFU0VSVkVEX0NIQVJTX1JFICsgJ10nO1xuY29uc3QgX3dvcmRDaGFyT3JEb3QgPSAnW14nICsgX1JFU0VSVkVEX0NIQVJTX1JFLnJlcGxhY2UoICdcXFxcLicsICcnICkgKyAnXSc7XG5cbi8vIFBhcmVudCBkaXJlY3RvcmllcywgZGVsaW1pdGVkIGJ5ICcvJyBvciAnOicuIEN1cnJlbnRseSB1bnVzZWQsIGJ1dCBtdXN0XG4vLyBiZSBtYXRjaGVkIHRvIHBhcnNlIHRoZSByZXN0IG9mIHRoZSB0cmFjayBuYW1lLlxuY29uc3QgX2RpcmVjdG9yeVJlID0gLypAX19QVVJFX18qLyAvKCg/OldDK1tcXC86XSkqKS8uc291cmNlLnJlcGxhY2UoICdXQycsIF93b3JkQ2hhciApO1xuXG4vLyBUYXJnZXQgbm9kZS4gTWF5IGNvbnRhaW4gd29yZCBjaGFyYWN0ZXJzIChhLXpBLVowLTlfKSBhbmQgJy4nIG9yICctJy5cbmNvbnN0IF9ub2RlUmUgPSAvKkBfX1BVUkVfXyovIC8oV0NPRCspPy8uc291cmNlLnJlcGxhY2UoICdXQ09EJywgX3dvcmRDaGFyT3JEb3QgKTtcblxuLy8gT2JqZWN0IG9uIHRhcmdldCBub2RlLCBhbmQgYWNjZXNzb3IuIE1heSBub3QgY29udGFpbiByZXNlcnZlZFxuLy8gY2hhcmFjdGVycy4gQWNjZXNzb3IgbWF5IGNvbnRhaW4gYW55IGNoYXJhY3RlciBleGNlcHQgY2xvc2luZyBicmFja2V0LlxuY29uc3QgX29iamVjdFJlID0gLypAX19QVVJFX18qLyAvKD86XFwuKFdDKykoPzpcXFsoLispXFxdKT8pPy8uc291cmNlLnJlcGxhY2UoICdXQycsIF93b3JkQ2hhciApO1xuXG4vLyBQcm9wZXJ0eSBhbmQgYWNjZXNzb3IuIE1heSBub3QgY29udGFpbiByZXNlcnZlZCBjaGFyYWN0ZXJzLiBBY2Nlc3NvciBtYXlcbi8vIGNvbnRhaW4gYW55IG5vbi1icmFja2V0IGNoYXJhY3RlcnMuXG5jb25zdCBfcHJvcGVydHlSZSA9IC8qQF9fUFVSRV9fKi8gL1xcLihXQyspKD86XFxbKC4rKVxcXSk/Ly5zb3VyY2UucmVwbGFjZSggJ1dDJywgX3dvcmRDaGFyICk7XG5cbmNvbnN0IF90cmFja1JlID0gbmV3IFJlZ0V4cCggJydcblx0KyAnXidcblx0KyBfZGlyZWN0b3J5UmVcblx0KyBfbm9kZVJlXG5cdCsgX29iamVjdFJlXG5cdCsgX3Byb3BlcnR5UmVcblx0KyAnJCdcbik7XG5cbmNvbnN0IF9zdXBwb3J0ZWRPYmplY3ROYW1lcyA9IFsgJ21hdGVyaWFsJywgJ21hdGVyaWFscycsICdib25lcycsICdtYXAnIF07XG5cbmNsYXNzIENvbXBvc2l0ZSB7XG5cblx0Y29uc3RydWN0b3IoIHRhcmdldEdyb3VwLCBwYXRoLCBvcHRpb25hbFBhcnNlZFBhdGggKSB7XG5cblx0XHRjb25zdCBwYXJzZWRQYXRoID0gb3B0aW9uYWxQYXJzZWRQYXRoIHx8IFByb3BlcnR5QmluZGluZy5wYXJzZVRyYWNrTmFtZSggcGF0aCApO1xuXG5cdFx0dGhpcy5fdGFyZ2V0R3JvdXAgPSB0YXJnZXRHcm91cDtcblx0XHR0aGlzLl9iaW5kaW5ncyA9IHRhcmdldEdyb3VwLnN1YnNjcmliZV8oIHBhdGgsIHBhcnNlZFBhdGggKTtcblxuXHR9XG5cblx0Z2V0VmFsdWUoIGFycmF5LCBvZmZzZXQgKSB7XG5cblx0XHR0aGlzLmJpbmQoKTsgLy8gYmluZCBhbGwgYmluZGluZ1xuXG5cdFx0Y29uc3QgZmlyc3RWYWxpZEluZGV4ID0gdGhpcy5fdGFyZ2V0R3JvdXAubkNhY2hlZE9iamVjdHNfLFxuXHRcdFx0YmluZGluZyA9IHRoaXMuX2JpbmRpbmdzWyBmaXJzdFZhbGlkSW5kZXggXTtcblxuXHRcdC8vIGFuZCBvbmx5IGNhbGwgLmdldFZhbHVlIG9uIHRoZSBmaXJzdFxuXHRcdGlmICggYmluZGluZyAhPT0gdW5kZWZpbmVkICkgYmluZGluZy5nZXRWYWx1ZSggYXJyYXksIG9mZnNldCApO1xuXG5cdH1cblxuXHRzZXRWYWx1ZSggYXJyYXksIG9mZnNldCApIHtcblxuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3M7XG5cblx0XHRmb3IgKCBsZXQgaSA9IHRoaXMuX3RhcmdldEdyb3VwLm5DYWNoZWRPYmplY3RzXywgbiA9IGJpbmRpbmdzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0YmluZGluZ3NbIGkgXS5zZXRWYWx1ZSggYXJyYXksIG9mZnNldCApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRiaW5kKCkge1xuXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncztcblxuXHRcdGZvciAoIGxldCBpID0gdGhpcy5fdGFyZ2V0R3JvdXAubkNhY2hlZE9iamVjdHNfLCBuID0gYmluZGluZ3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRiaW5kaW5nc1sgaSBdLmJpbmQoKTtcblxuXHRcdH1cblxuXHR9XG5cblx0dW5iaW5kKCkge1xuXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncztcblxuXHRcdGZvciAoIGxldCBpID0gdGhpcy5fdGFyZ2V0R3JvdXAubkNhY2hlZE9iamVjdHNfLCBuID0gYmluZGluZ3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRiaW5kaW5nc1sgaSBdLnVuYmluZCgpO1xuXG5cdFx0fVxuXG5cdH1cblxufVxuXG4vLyBOb3RlOiBUaGlzIGNsYXNzIHVzZXMgYSBTdGF0ZSBwYXR0ZXJuIG9uIGEgcGVyLW1ldGhvZCBiYXNpczpcbi8vICdiaW5kJyBzZXRzICd0aGlzLmdldFZhbHVlJyAvICdzZXRWYWx1ZScgYW5kIHNoYWRvd3MgdGhlXG4vLyBwcm90b3R5cGUgdmVyc2lvbiBvZiB0aGVzZSBtZXRob2RzIHdpdGggb25lIHRoYXQgcmVwcmVzZW50c1xuLy8gdGhlIGJvdW5kIHN0YXRlLiBXaGVuIHRoZSBwcm9wZXJ0eSBpcyBub3QgZm91bmQsIHRoZSBtZXRob2RzXG4vLyBiZWNvbWUgbm8tb3BzLlxuY2xhc3MgUHJvcGVydHlCaW5kaW5nIHtcblxuXHRjb25zdHJ1Y3Rvciggcm9vdE5vZGUsIHBhdGgsIHBhcnNlZFBhdGggKSB7XG5cblx0XHR0aGlzLnBhdGggPSBwYXRoO1xuXHRcdHRoaXMucGFyc2VkUGF0aCA9IHBhcnNlZFBhdGggfHwgUHJvcGVydHlCaW5kaW5nLnBhcnNlVHJhY2tOYW1lKCBwYXRoICk7XG5cblx0XHR0aGlzLm5vZGUgPSBQcm9wZXJ0eUJpbmRpbmcuZmluZE5vZGUoIHJvb3ROb2RlLCB0aGlzLnBhcnNlZFBhdGgubm9kZU5hbWUgKTtcblxuXHRcdHRoaXMucm9vdE5vZGUgPSByb290Tm9kZTtcblxuXHRcdC8vIGluaXRpYWwgc3RhdGUgb2YgdGhlc2UgbWV0aG9kcyB0aGF0IGNhbGxzICdiaW5kJ1xuXHRcdHRoaXMuZ2V0VmFsdWUgPSB0aGlzLl9nZXRWYWx1ZV91bmJvdW5kO1xuXHRcdHRoaXMuc2V0VmFsdWUgPSB0aGlzLl9zZXRWYWx1ZV91bmJvdW5kO1xuXG5cdH1cblxuXG5cdHN0YXRpYyBjcmVhdGUoIHJvb3QsIHBhdGgsIHBhcnNlZFBhdGggKSB7XG5cblx0XHRpZiAoICEgKCByb290ICYmIHJvb3QuaXNBbmltYXRpb25PYmplY3RHcm91cCApICkge1xuXG5cdFx0XHRyZXR1cm4gbmV3IFByb3BlcnR5QmluZGluZyggcm9vdCwgcGF0aCwgcGFyc2VkUGF0aCApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmV0dXJuIG5ldyBQcm9wZXJ0eUJpbmRpbmcuQ29tcG9zaXRlKCByb290LCBwYXRoLCBwYXJzZWRQYXRoICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdC8qKlxuXHQgKiBSZXBsYWNlcyBzcGFjZXMgd2l0aCB1bmRlcnNjb3JlcyBhbmQgcmVtb3ZlcyB1bnN1cHBvcnRlZCBjaGFyYWN0ZXJzIGZyb21cblx0ICogbm9kZSBuYW1lcywgdG8gZW5zdXJlIGNvbXBhdGliaWxpdHkgd2l0aCBwYXJzZVRyYWNrTmFtZSgpLlxuXHQgKlxuXHQgKiBAcGFyYW0ge3N0cmluZ30gbmFtZSBOb2RlIG5hbWUgdG8gYmUgc2FuaXRpemVkLlxuXHQgKiBAcmV0dXJuIHtzdHJpbmd9XG5cdCAqL1xuXHRzdGF0aWMgc2FuaXRpemVOb2RlTmFtZSggbmFtZSApIHtcblxuXHRcdHJldHVybiBuYW1lLnJlcGxhY2UoIC9cXHMvZywgJ18nICkucmVwbGFjZSggX3Jlc2VydmVkUmUsICcnICk7XG5cblx0fVxuXG5cdHN0YXRpYyBwYXJzZVRyYWNrTmFtZSggdHJhY2tOYW1lICkge1xuXG5cdFx0Y29uc3QgbWF0Y2hlcyA9IF90cmFja1JlLmV4ZWMoIHRyYWNrTmFtZSApO1xuXG5cdFx0aWYgKCBtYXRjaGVzID09PSBudWxsICkge1xuXG5cdFx0XHR0aHJvdyBuZXcgRXJyb3IoICdQcm9wZXJ0eUJpbmRpbmc6IENhbm5vdCBwYXJzZSB0cmFja05hbWU6ICcgKyB0cmFja05hbWUgKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHJlc3VsdHMgPSB7XG5cdFx0XHQvLyBkaXJlY3RvcnlOYW1lOiBtYXRjaGVzWyAxIF0sIC8vICh0c2NodykgY3VycmVudGx5IHVudXNlZFxuXHRcdFx0bm9kZU5hbWU6IG1hdGNoZXNbIDIgXSxcblx0XHRcdG9iamVjdE5hbWU6IG1hdGNoZXNbIDMgXSxcblx0XHRcdG9iamVjdEluZGV4OiBtYXRjaGVzWyA0IF0sXG5cdFx0XHRwcm9wZXJ0eU5hbWU6IG1hdGNoZXNbIDUgXSwgLy8gcmVxdWlyZWRcblx0XHRcdHByb3BlcnR5SW5kZXg6IG1hdGNoZXNbIDYgXVxuXHRcdH07XG5cblx0XHRjb25zdCBsYXN0RG90ID0gcmVzdWx0cy5ub2RlTmFtZSAmJiByZXN1bHRzLm5vZGVOYW1lLmxhc3RJbmRleE9mKCAnLicgKTtcblxuXHRcdGlmICggbGFzdERvdCAhPT0gdW5kZWZpbmVkICYmIGxhc3REb3QgIT09IC0gMSApIHtcblxuXHRcdFx0Y29uc3Qgb2JqZWN0TmFtZSA9IHJlc3VsdHMubm9kZU5hbWUuc3Vic3RyaW5nKCBsYXN0RG90ICsgMSApO1xuXG5cdFx0XHQvLyBPYmplY3QgbmFtZXMgbXVzdCBiZSBjaGVja2VkIGFnYWluc3QgYW4gYWxsb3dsaXN0LiBPdGhlcndpc2UsIHRoZXJlXG5cdFx0XHQvLyBpcyBubyB3YXkgdG8gcGFyc2UgJ2Zvby5iYXIuYmF6JzogJ2JheicgbXVzdCBiZSBhIHByb3BlcnR5LCBidXRcblx0XHRcdC8vICdiYXInIGNvdWxkIGJlIHRoZSBvYmplY3ROYW1lLCBvciBwYXJ0IG9mIGEgbm9kZU5hbWUgKHdoaWNoIGNhblxuXHRcdFx0Ly8gaW5jbHVkZSAnLicgY2hhcmFjdGVycykuXG5cdFx0XHRpZiAoIF9zdXBwb3J0ZWRPYmplY3ROYW1lcy5pbmRleE9mKCBvYmplY3ROYW1lICkgIT09IC0gMSApIHtcblxuXHRcdFx0XHRyZXN1bHRzLm5vZGVOYW1lID0gcmVzdWx0cy5ub2RlTmFtZS5zdWJzdHJpbmcoIDAsIGxhc3REb3QgKTtcblx0XHRcdFx0cmVzdWx0cy5vYmplY3ROYW1lID0gb2JqZWN0TmFtZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCByZXN1bHRzLnByb3BlcnR5TmFtZSA9PT0gbnVsbCB8fCByZXN1bHRzLnByb3BlcnR5TmFtZS5sZW5ndGggPT09IDAgKSB7XG5cblx0XHRcdHRocm93IG5ldyBFcnJvciggJ1Byb3BlcnR5QmluZGluZzogY2FuIG5vdCBwYXJzZSBwcm9wZXJ0eU5hbWUgZnJvbSB0cmFja05hbWU6ICcgKyB0cmFja05hbWUgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiByZXN1bHRzO1xuXG5cdH1cblxuXHRzdGF0aWMgZmluZE5vZGUoIHJvb3QsIG5vZGVOYW1lICkge1xuXG5cdFx0aWYgKCBub2RlTmFtZSA9PT0gdW5kZWZpbmVkIHx8IG5vZGVOYW1lID09PSAnJyB8fCBub2RlTmFtZSA9PT0gJy4nIHx8IG5vZGVOYW1lID09PSAtIDEgfHwgbm9kZU5hbWUgPT09IHJvb3QubmFtZSB8fCBub2RlTmFtZSA9PT0gcm9vdC51dWlkICkge1xuXG5cdFx0XHRyZXR1cm4gcm9vdDtcblxuXHRcdH1cblxuXHRcdC8vIHNlYXJjaCBpbnRvIHNrZWxldG9uIGJvbmVzLlxuXHRcdGlmICggcm9vdC5za2VsZXRvbiApIHtcblxuXHRcdFx0Y29uc3QgYm9uZSA9IHJvb3Quc2tlbGV0b24uZ2V0Qm9uZUJ5TmFtZSggbm9kZU5hbWUgKTtcblxuXHRcdFx0aWYgKCBib25lICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0cmV0dXJuIGJvbmU7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIHNlYXJjaCBpbnRvIG5vZGUgc3VidHJlZS5cblx0XHRpZiAoIHJvb3QuY2hpbGRyZW4gKSB7XG5cblx0XHRcdGNvbnN0IHNlYXJjaE5vZGVTdWJ0cmVlID0gZnVuY3Rpb24gKCBjaGlsZHJlbiApIHtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBjaGlsZHJlbi5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBjaGlsZE5vZGUgPSBjaGlsZHJlblsgaSBdO1xuXG5cdFx0XHRcdFx0aWYgKCBjaGlsZE5vZGUubmFtZSA9PT0gbm9kZU5hbWUgfHwgY2hpbGROb2RlLnV1aWQgPT09IG5vZGVOYW1lICkge1xuXG5cdFx0XHRcdFx0XHRyZXR1cm4gY2hpbGROb2RlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Y29uc3QgcmVzdWx0ID0gc2VhcmNoTm9kZVN1YnRyZWUoIGNoaWxkTm9kZS5jaGlsZHJlbiApO1xuXG5cdFx0XHRcdFx0aWYgKCByZXN1bHQgKSByZXR1cm4gcmVzdWx0O1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRyZXR1cm4gbnVsbDtcblxuXHRcdFx0fTtcblxuXHRcdFx0Y29uc3Qgc3ViVHJlZU5vZGUgPSBzZWFyY2hOb2RlU3VidHJlZSggcm9vdC5jaGlsZHJlbiApO1xuXG5cdFx0XHRpZiAoIHN1YlRyZWVOb2RlICkge1xuXG5cdFx0XHRcdHJldHVybiBzdWJUcmVlTm9kZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG51bGw7XG5cblx0fVxuXG5cdC8vIHRoZXNlIGFyZSB1c2VkIHRvIFwiYmluZFwiIGEgbm9uZXhpc3RlbnQgcHJvcGVydHlcblx0X2dldFZhbHVlX3VuYXZhaWxhYmxlKCkge31cblx0X3NldFZhbHVlX3VuYXZhaWxhYmxlKCkge31cblxuXHQvLyBHZXR0ZXJzXG5cblx0X2dldFZhbHVlX2RpcmVjdCggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHRidWZmZXJbIG9mZnNldCBdID0gdGhpcy50YXJnZXRPYmplY3RbIHRoaXMucHJvcGVydHlOYW1lIF07XG5cblx0fVxuXG5cdF9nZXRWYWx1ZV9hcnJheSggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHRjb25zdCBzb3VyY2UgPSB0aGlzLnJlc29sdmVkUHJvcGVydHk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBzb3VyY2UubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRidWZmZXJbIG9mZnNldCArKyBdID0gc291cmNlWyBpIF07XG5cblx0XHR9XG5cblx0fVxuXG5cdF9nZXRWYWx1ZV9hcnJheUVsZW1lbnQoIGJ1ZmZlciwgb2Zmc2V0ICkge1xuXG5cdFx0YnVmZmVyWyBvZmZzZXQgXSA9IHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF07XG5cblx0fVxuXG5cdF9nZXRWYWx1ZV90b0FycmF5KCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eS50b0FycmF5KCBidWZmZXIsIG9mZnNldCApO1xuXG5cdH1cblxuXHQvLyBEaXJlY3RcblxuXHRfc2V0VmFsdWVfZGlyZWN0KCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMudGFyZ2V0T2JqZWN0WyB0aGlzLnByb3BlcnR5TmFtZSBdID0gYnVmZmVyWyBvZmZzZXQgXTtcblxuXHR9XG5cblx0X3NldFZhbHVlX2RpcmVjdF9zZXROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHR0aGlzLnRhcmdldE9iamVjdFsgdGhpcy5wcm9wZXJ0eU5hbWUgXSA9IGJ1ZmZlclsgb2Zmc2V0IF07XG5cdFx0dGhpcy50YXJnZXRPYmplY3QubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxuXHRfc2V0VmFsdWVfZGlyZWN0X3NldE1hdHJpeFdvcmxkTmVlZHNVcGRhdGUoIGJ1ZmZlciwgb2Zmc2V0ICkge1xuXG5cdFx0dGhpcy50YXJnZXRPYmplY3RbIHRoaXMucHJvcGVydHlOYW1lIF0gPSBidWZmZXJbIG9mZnNldCBdO1xuXHRcdHRoaXMudGFyZ2V0T2JqZWN0Lm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxuXHQvLyBFbnRpcmVBcnJheVxuXG5cdF9zZXRWYWx1ZV9hcnJheSggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHRjb25zdCBkZXN0ID0gdGhpcy5yZXNvbHZlZFByb3BlcnR5O1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gZGVzdC5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdGRlc3RbIGkgXSA9IGJ1ZmZlclsgb2Zmc2V0ICsrIF07XG5cblx0XHR9XG5cblx0fVxuXG5cdF9zZXRWYWx1ZV9hcnJheV9zZXROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHRjb25zdCBkZXN0ID0gdGhpcy5yZXNvbHZlZFByb3BlcnR5O1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gZGVzdC5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdGRlc3RbIGkgXSA9IGJ1ZmZlclsgb2Zmc2V0ICsrIF07XG5cblx0XHR9XG5cblx0XHR0aGlzLnRhcmdldE9iamVjdC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0fVxuXG5cdF9zZXRWYWx1ZV9hcnJheV9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdGNvbnN0IGRlc3QgPSB0aGlzLnJlc29sdmVkUHJvcGVydHk7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBkZXN0Lmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0ZGVzdFsgaSBdID0gYnVmZmVyWyBvZmZzZXQgKysgXTtcblxuXHRcdH1cblxuXHRcdHRoaXMudGFyZ2V0T2JqZWN0Lm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxuXHQvLyBBcnJheUVsZW1lbnRcblxuXHRfc2V0VmFsdWVfYXJyYXlFbGVtZW50KCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF0gPSBidWZmZXJbIG9mZnNldCBdO1xuXG5cdH1cblxuXHRfc2V0VmFsdWVfYXJyYXlFbGVtZW50X3NldE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF0gPSBidWZmZXJbIG9mZnNldCBdO1xuXHRcdHRoaXMudGFyZ2V0T2JqZWN0Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHR9XG5cblx0X3NldFZhbHVlX2FycmF5RWxlbWVudF9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eVsgdGhpcy5wcm9wZXJ0eUluZGV4IF0gPSBidWZmZXJbIG9mZnNldCBdO1xuXHRcdHRoaXMudGFyZ2V0T2JqZWN0Lm1hdHJpeFdvcmxkTmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdH1cblxuXHQvLyBIYXNUb0Zyb21BcnJheVxuXG5cdF9zZXRWYWx1ZV9mcm9tQXJyYXkoIGJ1ZmZlciwgb2Zmc2V0ICkge1xuXG5cdFx0dGhpcy5yZXNvbHZlZFByb3BlcnR5LmZyb21BcnJheSggYnVmZmVyLCBvZmZzZXQgKTtcblxuXHR9XG5cblx0X3NldFZhbHVlX2Zyb21BcnJheV9zZXROZWVkc1VwZGF0ZSggYnVmZmVyLCBvZmZzZXQgKSB7XG5cblx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkuZnJvbUFycmF5KCBidWZmZXIsIG9mZnNldCApO1xuXHRcdHRoaXMudGFyZ2V0T2JqZWN0Lm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHR9XG5cblx0X3NldFZhbHVlX2Zyb21BcnJheV9zZXRNYXRyaXhXb3JsZE5lZWRzVXBkYXRlKCBidWZmZXIsIG9mZnNldCApIHtcblxuXHRcdHRoaXMucmVzb2x2ZWRQcm9wZXJ0eS5mcm9tQXJyYXkoIGJ1ZmZlciwgb2Zmc2V0ICk7XG5cdFx0dGhpcy50YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0fVxuXG5cdF9nZXRWYWx1ZV91bmJvdW5kKCB0YXJnZXRBcnJheSwgb2Zmc2V0ICkge1xuXG5cdFx0dGhpcy5iaW5kKCk7XG5cdFx0dGhpcy5nZXRWYWx1ZSggdGFyZ2V0QXJyYXksIG9mZnNldCApO1xuXG5cdH1cblxuXHRfc2V0VmFsdWVfdW5ib3VuZCggc291cmNlQXJyYXksIG9mZnNldCApIHtcblxuXHRcdHRoaXMuYmluZCgpO1xuXHRcdHRoaXMuc2V0VmFsdWUoIHNvdXJjZUFycmF5LCBvZmZzZXQgKTtcblxuXHR9XG5cblx0Ly8gY3JlYXRlIGdldHRlciAvIHNldHRlciBwYWlyIGZvciBhIHByb3BlcnR5IGluIHRoZSBzY2VuZSBncmFwaFxuXHRiaW5kKCkge1xuXG5cdFx0bGV0IHRhcmdldE9iamVjdCA9IHRoaXMubm9kZTtcblx0XHRjb25zdCBwYXJzZWRQYXRoID0gdGhpcy5wYXJzZWRQYXRoO1xuXG5cdFx0Y29uc3Qgb2JqZWN0TmFtZSA9IHBhcnNlZFBhdGgub2JqZWN0TmFtZTtcblx0XHRjb25zdCBwcm9wZXJ0eU5hbWUgPSBwYXJzZWRQYXRoLnByb3BlcnR5TmFtZTtcblx0XHRsZXQgcHJvcGVydHlJbmRleCA9IHBhcnNlZFBhdGgucHJvcGVydHlJbmRleDtcblxuXHRcdGlmICggISB0YXJnZXRPYmplY3QgKSB7XG5cblx0XHRcdHRhcmdldE9iamVjdCA9IFByb3BlcnR5QmluZGluZy5maW5kTm9kZSggdGhpcy5yb290Tm9kZSwgcGFyc2VkUGF0aC5ub2RlTmFtZSApO1xuXG5cdFx0XHR0aGlzLm5vZGUgPSB0YXJnZXRPYmplY3Q7XG5cblx0XHR9XG5cblx0XHQvLyBzZXQgZmFpbCBzdGF0ZSBzbyB3ZSBjYW4ganVzdCAncmV0dXJuJyBvbiBlcnJvclxuXHRcdHRoaXMuZ2V0VmFsdWUgPSB0aGlzLl9nZXRWYWx1ZV91bmF2YWlsYWJsZTtcblx0XHR0aGlzLnNldFZhbHVlID0gdGhpcy5fc2V0VmFsdWVfdW5hdmFpbGFibGU7XG5cblx0XHQvLyBlbnN1cmUgdGhlcmUgaXMgYSB2YWx1ZSBub2RlXG5cdFx0aWYgKCAhIHRhcmdldE9iamVjdCApIHtcblxuXHRcdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBObyB0YXJnZXQgbm9kZSBmb3VuZCBmb3IgdHJhY2s6ICcgKyB0aGlzLnBhdGggKyAnLicgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdGlmICggb2JqZWN0TmFtZSApIHtcblxuXHRcdFx0bGV0IG9iamVjdEluZGV4ID0gcGFyc2VkUGF0aC5vYmplY3RJbmRleDtcblxuXHRcdFx0Ly8gc3BlY2lhbCBjYXNlcyB3ZXJlIHdlIG5lZWQgdG8gcmVhY2ggZGVlcGVyIGludG8gdGhlIGhpZXJhcmNoeSB0byBnZXQgdGhlIGZhY2UgbWF0ZXJpYWxzLi4uLlxuXHRcdFx0c3dpdGNoICggb2JqZWN0TmFtZSApIHtcblxuXHRcdFx0XHRjYXNlICdtYXRlcmlhbHMnOlxuXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5tYXRlcmlhbCApIHtcblxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogQ2FuIG5vdCBiaW5kIHRvIG1hdGVyaWFsIGFzIG5vZGUgZG9lcyBub3QgaGF2ZSBhIG1hdGVyaWFsLicsIHRoaXMgKTtcblx0XHRcdFx0XHRcdHJldHVybjtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggISB0YXJnZXRPYmplY3QubWF0ZXJpYWwubWF0ZXJpYWxzICkge1xuXG5cdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbWF0ZXJpYWwubWF0ZXJpYWxzIGFzIG5vZGUubWF0ZXJpYWwgZG9lcyBub3QgaGF2ZSBhIG1hdGVyaWFscyBhcnJheS4nLCB0aGlzICk7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3QubWF0ZXJpYWwubWF0ZXJpYWxzO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAnYm9uZXMnOlxuXG5cdFx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5za2VsZXRvbiApIHtcblxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogQ2FuIG5vdCBiaW5kIHRvIGJvbmVzIGFzIG5vZGUgZG9lcyBub3QgaGF2ZSBhIHNrZWxldG9uLicsIHRoaXMgKTtcblx0XHRcdFx0XHRcdHJldHVybjtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdC8vIHBvdGVudGlhbCBmdXR1cmUgb3B0aW1pemF0aW9uOiBza2lwIHRoaXMgaWYgcHJvcGVydHlJbmRleCBpcyBhbHJlYWR5IGFuIGludGVnZXJcblx0XHRcdFx0XHQvLyBhbmQgY29udmVydCB0aGUgaW50ZWdlciBzdHJpbmcgdG8gYSB0cnVlIGludGVnZXIuXG5cblx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3Quc2tlbGV0b24uYm9uZXM7XG5cblx0XHRcdFx0XHQvLyBzdXBwb3J0IHJlc29sdmluZyBtb3JwaFRhcmdldCBuYW1lcyBpbnRvIGluZGljZXMuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGFyZ2V0T2JqZWN0Lmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRcdFx0aWYgKCB0YXJnZXRPYmplY3RbIGkgXS5uYW1lID09PSBvYmplY3RJbmRleCApIHtcblxuXHRcdFx0XHRcdFx0XHRvYmplY3RJbmRleCA9IGk7XG5cdFx0XHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlICdtYXAnOlxuXG5cdFx0XHRcdFx0aWYgKCAnbWFwJyBpbiB0YXJnZXRPYmplY3QgKSB7XG5cblx0XHRcdFx0XHRcdHRhcmdldE9iamVjdCA9IHRhcmdldE9iamVjdC5tYXA7XG5cdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggISB0YXJnZXRPYmplY3QubWF0ZXJpYWwgKSB7XG5cblx0XHRcdFx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IENhbiBub3QgYmluZCB0byBtYXRlcmlhbCBhcyBub2RlIGRvZXMgbm90IGhhdmUgYSBtYXRlcmlhbC4nLCB0aGlzICk7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoICEgdGFyZ2V0T2JqZWN0Lm1hdGVyaWFsLm1hcCApIHtcblxuXHRcdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogQ2FuIG5vdCBiaW5kIHRvIG1hdGVyaWFsLm1hcCBhcyBub2RlLm1hdGVyaWFsIGRvZXMgbm90IGhhdmUgYSBtYXAuJywgdGhpcyApO1xuXHRcdFx0XHRcdFx0cmV0dXJuO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0dGFyZ2V0T2JqZWN0ID0gdGFyZ2V0T2JqZWN0Lm1hdGVyaWFsLm1hcDtcblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRkZWZhdWx0OlxuXG5cdFx0XHRcdFx0aWYgKCB0YXJnZXRPYmplY3RbIG9iamVjdE5hbWUgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gb2JqZWN0TmFtZSBvZiBub2RlIHVuZGVmaW5lZC4nLCB0aGlzICk7XG5cdFx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR0YXJnZXRPYmplY3QgPSB0YXJnZXRPYmplY3RbIG9iamVjdE5hbWUgXTtcblxuXHRcdFx0fVxuXG5cblx0XHRcdGlmICggb2JqZWN0SW5kZXggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRpZiAoIHRhcmdldE9iamVjdFsgb2JqZWN0SW5kZXggXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlByb3BlcnR5QmluZGluZzogVHJ5aW5nIHRvIGJpbmQgdG8gb2JqZWN0SW5kZXggb2Ygb2JqZWN0TmFtZSwgYnV0IGlzIHVuZGVmaW5lZC4nLCB0aGlzLCB0YXJnZXRPYmplY3QgKTtcblx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHRhcmdldE9iamVjdCA9IHRhcmdldE9iamVjdFsgb2JqZWN0SW5kZXggXTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gcmVzb2x2ZSBwcm9wZXJ0eVxuXHRcdGNvbnN0IG5vZGVQcm9wZXJ0eSA9IHRhcmdldE9iamVjdFsgcHJvcGVydHlOYW1lIF07XG5cblx0XHRpZiAoIG5vZGVQcm9wZXJ0eSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjb25zdCBub2RlTmFtZSA9IHBhcnNlZFBhdGgubm9kZU5hbWU7XG5cblx0XHRcdGNvbnNvbGUuZXJyb3IoICdUSFJFRS5Qcm9wZXJ0eUJpbmRpbmc6IFRyeWluZyB0byB1cGRhdGUgcHJvcGVydHkgZm9yIHRyYWNrOiAnICsgbm9kZU5hbWUgK1xuXHRcdFx0XHQnLicgKyBwcm9wZXJ0eU5hbWUgKyAnIGJ1dCBpdCB3YXNuXFwndCBmb3VuZC4nLCB0YXJnZXRPYmplY3QgKTtcblx0XHRcdHJldHVybjtcblxuXHRcdH1cblxuXHRcdC8vIGRldGVybWluZSB2ZXJzaW9uaW5nIHNjaGVtZVxuXHRcdGxldCB2ZXJzaW9uaW5nID0gdGhpcy5WZXJzaW9uaW5nLk5vbmU7XG5cblx0XHR0aGlzLnRhcmdldE9iamVjdCA9IHRhcmdldE9iamVjdDtcblxuXHRcdGlmICggdGFyZ2V0T2JqZWN0Lm5lZWRzVXBkYXRlICE9PSB1bmRlZmluZWQgKSB7IC8vIG1hdGVyaWFsXG5cblx0XHRcdHZlcnNpb25pbmcgPSB0aGlzLlZlcnNpb25pbmcuTmVlZHNVcGRhdGU7XG5cblx0XHR9IGVsc2UgaWYgKCB0YXJnZXRPYmplY3QubWF0cml4V29ybGROZWVkc1VwZGF0ZSAhPT0gdW5kZWZpbmVkICkgeyAvLyBub2RlIHRyYW5zZm9ybVxuXG5cdFx0XHR2ZXJzaW9uaW5nID0gdGhpcy5WZXJzaW9uaW5nLk1hdHJpeFdvcmxkTmVlZHNVcGRhdGU7XG5cblx0XHR9XG5cblx0XHQvLyBkZXRlcm1pbmUgaG93IHRoZSBwcm9wZXJ0eSBnZXRzIGJvdW5kXG5cdFx0bGV0IGJpbmRpbmdUeXBlID0gdGhpcy5CaW5kaW5nVHlwZS5EaXJlY3Q7XG5cblx0XHRpZiAoIHByb3BlcnR5SW5kZXggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Ly8gYWNjZXNzIGEgc3ViIGVsZW1lbnQgb2YgdGhlIHByb3BlcnR5IGFycmF5IChvbmx5IHByaW1pdGl2ZXMgYXJlIHN1cHBvcnRlZCByaWdodCBub3cpXG5cblx0XHRcdGlmICggcHJvcGVydHlOYW1lID09PSAnbW9ycGhUYXJnZXRJbmZsdWVuY2VzJyApIHtcblxuXHRcdFx0XHQvLyBwb3RlbnRpYWwgb3B0aW1pemF0aW9uLCBza2lwIHRoaXMgaWYgcHJvcGVydHlJbmRleCBpcyBhbHJlYWR5IGFuIGludGVnZXIsIGFuZCBjb252ZXJ0IHRoZSBpbnRlZ2VyIHN0cmluZyB0byBhIHRydWUgaW50ZWdlci5cblxuXHRcdFx0XHQvLyBzdXBwb3J0IHJlc29sdmluZyBtb3JwaFRhcmdldCBuYW1lcyBpbnRvIGluZGljZXMuXG5cdFx0XHRcdGlmICggISB0YXJnZXRPYmplY3QuZ2VvbWV0cnkgKSB7XG5cblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbW9ycGhUYXJnZXRJbmZsdWVuY2VzIGJlY2F1c2Ugbm9kZSBkb2VzIG5vdCBoYXZlIGEgZ2VvbWV0cnkuJywgdGhpcyApO1xuXHRcdFx0XHRcdHJldHVybjtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0aWYgKCAhIHRhcmdldE9iamVjdC5nZW9tZXRyeS5tb3JwaEF0dHJpYnV0ZXMgKSB7XG5cblx0XHRcdFx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUHJvcGVydHlCaW5kaW5nOiBDYW4gbm90IGJpbmQgdG8gbW9ycGhUYXJnZXRJbmZsdWVuY2VzIGJlY2F1c2Ugbm9kZSBkb2VzIG5vdCBoYXZlIGEgZ2VvbWV0cnkubW9ycGhBdHRyaWJ1dGVzLicsIHRoaXMgKTtcblx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggdGFyZ2V0T2JqZWN0Lm1vcnBoVGFyZ2V0RGljdGlvbmFyeVsgcHJvcGVydHlJbmRleCBdICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRwcm9wZXJ0eUluZGV4ID0gdGFyZ2V0T2JqZWN0Lm1vcnBoVGFyZ2V0RGljdGlvbmFyeVsgcHJvcGVydHlJbmRleCBdO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRiaW5kaW5nVHlwZSA9IHRoaXMuQmluZGluZ1R5cGUuQXJyYXlFbGVtZW50O1xuXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XG5cdFx0XHR0aGlzLnByb3BlcnR5SW5kZXggPSBwcm9wZXJ0eUluZGV4O1xuXG5cdFx0fSBlbHNlIGlmICggbm9kZVByb3BlcnR5LmZyb21BcnJheSAhPT0gdW5kZWZpbmVkICYmIG5vZGVQcm9wZXJ0eS50b0FycmF5ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdC8vIG11c3QgdXNlIGNvcHkgZm9yIE9iamVjdDNELkV1bGVyL1F1YXRlcm5pb25cblxuXHRcdFx0YmluZGluZ1R5cGUgPSB0aGlzLkJpbmRpbmdUeXBlLkhhc0Zyb21Ub0FycmF5O1xuXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XG5cblx0XHR9IGVsc2UgaWYgKCBBcnJheS5pc0FycmF5KCBub2RlUHJvcGVydHkgKSApIHtcblxuXHRcdFx0YmluZGluZ1R5cGUgPSB0aGlzLkJpbmRpbmdUeXBlLkVudGlyZUFycmF5O1xuXG5cdFx0XHR0aGlzLnJlc29sdmVkUHJvcGVydHkgPSBub2RlUHJvcGVydHk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLnByb3BlcnR5TmFtZSA9IHByb3BlcnR5TmFtZTtcblxuXHRcdH1cblxuXHRcdC8vIHNlbGVjdCBnZXR0ZXIgLyBzZXR0ZXJcblx0XHR0aGlzLmdldFZhbHVlID0gdGhpcy5HZXR0ZXJCeUJpbmRpbmdUeXBlWyBiaW5kaW5nVHlwZSBdO1xuXHRcdHRoaXMuc2V0VmFsdWUgPSB0aGlzLlNldHRlckJ5QmluZGluZ1R5cGVBbmRWZXJzaW9uaW5nWyBiaW5kaW5nVHlwZSBdWyB2ZXJzaW9uaW5nIF07XG5cblx0fVxuXG5cdHVuYmluZCgpIHtcblxuXHRcdHRoaXMubm9kZSA9IG51bGw7XG5cblx0XHQvLyBiYWNrIHRvIHRoZSBwcm90b3R5cGUgdmVyc2lvbiBvZiBnZXRWYWx1ZSAvIHNldFZhbHVlXG5cdFx0Ly8gbm90ZTogYXZvaWRpbmcgdG8gbXV0YXRlIHRoZSBzaGFwZSBvZiAndGhpcycgdmlhICdkZWxldGUnXG5cdFx0dGhpcy5nZXRWYWx1ZSA9IHRoaXMuX2dldFZhbHVlX3VuYm91bmQ7XG5cdFx0dGhpcy5zZXRWYWx1ZSA9IHRoaXMuX3NldFZhbHVlX3VuYm91bmQ7XG5cblx0fVxuXG59XG5cblByb3BlcnR5QmluZGluZy5Db21wb3NpdGUgPSBDb21wb3NpdGU7XG5cblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuQmluZGluZ1R5cGUgPSB7XG5cdERpcmVjdDogMCxcblx0RW50aXJlQXJyYXk6IDEsXG5cdEFycmF5RWxlbWVudDogMixcblx0SGFzRnJvbVRvQXJyYXk6IDNcbn07XG5cblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuVmVyc2lvbmluZyA9IHtcblx0Tm9uZTogMCxcblx0TmVlZHNVcGRhdGU6IDEsXG5cdE1hdHJpeFdvcmxkTmVlZHNVcGRhdGU6IDJcbn07XG5cblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuR2V0dGVyQnlCaW5kaW5nVHlwZSA9IFtcblxuXHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9nZXRWYWx1ZV9kaXJlY3QsXG5cdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX2dldFZhbHVlX2FycmF5LFxuXHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9nZXRWYWx1ZV9hcnJheUVsZW1lbnQsXG5cdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX2dldFZhbHVlX3RvQXJyYXksXG5cbl07XG5cblByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuU2V0dGVyQnlCaW5kaW5nVHlwZUFuZFZlcnNpb25pbmcgPSBbXG5cblx0W1xuXHRcdC8vIERpcmVjdFxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2RpcmVjdCxcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9kaXJlY3Rfc2V0TmVlZHNVcGRhdGUsXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfZGlyZWN0X3NldE1hdHJpeFdvcmxkTmVlZHNVcGRhdGUsXG5cblx0XSwgW1xuXG5cdFx0Ly8gRW50aXJlQXJyYXlcblxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2FycmF5LFxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2FycmF5X3NldE5lZWRzVXBkYXRlLFxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2FycmF5X3NldE1hdHJpeFdvcmxkTmVlZHNVcGRhdGUsXG5cblx0XSwgW1xuXG5cdFx0Ly8gQXJyYXlFbGVtZW50XG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfYXJyYXlFbGVtZW50LFxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2FycmF5RWxlbWVudF9zZXROZWVkc1VwZGF0ZSxcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9hcnJheUVsZW1lbnRfc2V0TWF0cml4V29ybGROZWVkc1VwZGF0ZSxcblxuXHRdLCBbXG5cblx0XHQvLyBIYXNUb0Zyb21BcnJheVxuXHRcdFByb3BlcnR5QmluZGluZy5wcm90b3R5cGUuX3NldFZhbHVlX2Zyb21BcnJheSxcblx0XHRQcm9wZXJ0eUJpbmRpbmcucHJvdG90eXBlLl9zZXRWYWx1ZV9mcm9tQXJyYXlfc2V0TmVlZHNVcGRhdGUsXG5cdFx0UHJvcGVydHlCaW5kaW5nLnByb3RvdHlwZS5fc2V0VmFsdWVfZnJvbUFycmF5X3NldE1hdHJpeFdvcmxkTmVlZHNVcGRhdGUsXG5cblx0XVxuXG5dO1xuXG4vKipcbiAqXG4gKiBBIGdyb3VwIG9mIG9iamVjdHMgdGhhdCByZWNlaXZlcyBhIHNoYXJlZCBhbmltYXRpb24gc3RhdGUuXG4gKlxuICogVXNhZ2U6XG4gKlxuICogIC0gQWRkIG9iamVjdHMgeW91IHdvdWxkIG90aGVyd2lzZSBwYXNzIGFzICdyb290JyB0byB0aGVcbiAqICAgIGNvbnN0cnVjdG9yIG9yIHRoZSAuY2xpcEFjdGlvbiBtZXRob2Qgb2YgQW5pbWF0aW9uTWl4ZXIuXG4gKlxuICogIC0gSW5zdGVhZCBwYXNzIHRoaXMgb2JqZWN0IGFzICdyb290Jy5cbiAqXG4gKiAgLSBZb3UgY2FuIGFsc28gYWRkIGFuZCByZW1vdmUgb2JqZWN0cyBsYXRlciB3aGVuIHRoZSBtaXhlclxuICogICAgaXMgcnVubmluZy5cbiAqXG4gKiBOb3RlOlxuICpcbiAqICAgIE9iamVjdHMgb2YgdGhpcyBjbGFzcyBhcHBlYXIgYXMgb25lIG9iamVjdCB0byB0aGUgbWl4ZXIsXG4gKiAgICBzbyBjYWNoZSBjb250cm9sIG9mIHRoZSBpbmRpdmlkdWFsIG9iamVjdHMgbXVzdCBiZSBkb25lXG4gKiAgICBvbiB0aGUgZ3JvdXAuXG4gKlxuICogTGltaXRhdGlvbjpcbiAqXG4gKiAgLSBUaGUgYW5pbWF0ZWQgcHJvcGVydGllcyBtdXN0IGJlIGNvbXBhdGlibGUgYW1vbmcgdGhlXG4gKiAgICBhbGwgb2JqZWN0cyBpbiB0aGUgZ3JvdXAuXG4gKlxuICogIC0gQSBzaW5nbGUgcHJvcGVydHkgY2FuIGVpdGhlciBiZSBjb250cm9sbGVkIHRocm91Z2ggYVxuICogICAgdGFyZ2V0IGdyb3VwIG9yIGRpcmVjdGx5LCBidXQgbm90IGJvdGguXG4gKi9cblxuY2xhc3MgQW5pbWF0aW9uT2JqZWN0R3JvdXAge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0dGhpcy5pc0FuaW1hdGlvbk9iamVjdEdyb3VwID0gdHJ1ZTtcblxuXHRcdHRoaXMudXVpZCA9IGdlbmVyYXRlVVVJRCgpO1xuXG5cdFx0Ly8gY2FjaGVkIG9iamVjdHMgZm9sbG93ZWQgYnkgdGhlIGFjdGl2ZSBvbmVzXG5cdFx0dGhpcy5fb2JqZWN0cyA9IEFycmF5LnByb3RvdHlwZS5zbGljZS5jYWxsKCBhcmd1bWVudHMgKTtcblxuXHRcdHRoaXMubkNhY2hlZE9iamVjdHNfID0gMDsgLy8gdGhyZXNob2xkXG5cdFx0Ly8gbm90ZTogcmVhZCBieSBQcm9wZXJ0eUJpbmRpbmcuQ29tcG9zaXRlXG5cblx0XHRjb25zdCBpbmRpY2VzID0ge307XG5cdFx0dGhpcy5faW5kaWNlc0J5VVVJRCA9IGluZGljZXM7IC8vIGZvciBib29ra2VlcGluZ1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gYXJndW1lbnRzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0aW5kaWNlc1sgYXJndW1lbnRzWyBpIF0udXVpZCBdID0gaTtcblxuXHRcdH1cblxuXHRcdHRoaXMuX3BhdGhzID0gW107IC8vIGluc2lkZTogc3RyaW5nXG5cdFx0dGhpcy5fcGFyc2VkUGF0aHMgPSBbXTsgLy8gaW5zaWRlOiB7IHdlIGRvbid0IGNhcmUsIGhlcmUgfVxuXHRcdHRoaXMuX2JpbmRpbmdzID0gW107IC8vIGluc2lkZTogQXJyYXk8IFByb3BlcnR5QmluZGluZyA+XG5cdFx0dGhpcy5fYmluZGluZ3NJbmRpY2VzQnlQYXRoID0ge307IC8vIGluc2lkZTogaW5kaWNlcyBpbiB0aGVzZSBhcnJheXNcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdHRoaXMuc3RhdHMgPSB7XG5cblx0XHRcdG9iamVjdHM6IHtcblx0XHRcdFx0Z2V0IHRvdGFsKCkge1xuXG5cdFx0XHRcdFx0cmV0dXJuIHNjb3BlLl9vYmplY3RzLmxlbmd0aDtcblxuXHRcdFx0XHR9LFxuXHRcdFx0XHRnZXQgaW5Vc2UoKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gdGhpcy50b3RhbCAtIHNjb3BlLm5DYWNoZWRPYmplY3RzXztcblxuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0Z2V0IGJpbmRpbmdzUGVyT2JqZWN0KCkge1xuXG5cdFx0XHRcdHJldHVybiBzY29wZS5fYmluZGluZ3MubGVuZ3RoO1xuXG5cdFx0XHR9XG5cblx0XHR9O1xuXG5cdH1cblxuXHRhZGQoKSB7XG5cblx0XHRjb25zdCBvYmplY3RzID0gdGhpcy5fb2JqZWN0cyxcblx0XHRcdGluZGljZXNCeVVVSUQgPSB0aGlzLl9pbmRpY2VzQnlVVUlELFxuXHRcdFx0cGF0aHMgPSB0aGlzLl9wYXRocyxcblx0XHRcdHBhcnNlZFBhdGhzID0gdGhpcy5fcGFyc2VkUGF0aHMsXG5cdFx0XHRiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxuXHRcdFx0bkJpbmRpbmdzID0gYmluZGluZ3MubGVuZ3RoO1xuXG5cdFx0bGV0IGtub3duT2JqZWN0ID0gdW5kZWZpbmVkLFxuXHRcdFx0bk9iamVjdHMgPSBvYmplY3RzLmxlbmd0aCxcblx0XHRcdG5DYWNoZWRPYmplY3RzID0gdGhpcy5uQ2FjaGVkT2JqZWN0c187XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCBvYmplY3QgPSBhcmd1bWVudHNbIGkgXSxcblx0XHRcdFx0dXVpZCA9IG9iamVjdC51dWlkO1xuXHRcdFx0bGV0IGluZGV4ID0gaW5kaWNlc0J5VVVJRFsgdXVpZCBdO1xuXG5cdFx0XHRpZiAoIGluZGV4ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0Ly8gdW5rbm93biBvYmplY3QgLT4gYWRkIGl0IHRvIHRoZSBBQ1RJVkUgcmVnaW9uXG5cblx0XHRcdFx0aW5kZXggPSBuT2JqZWN0cyArKztcblx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgdXVpZCBdID0gaW5kZXg7XG5cdFx0XHRcdG9iamVjdHMucHVzaCggb2JqZWN0ICk7XG5cblx0XHRcdFx0Ly8gYWNjb3VudGluZyBpcyBkb25lLCBub3cgZG8gdGhlIHNhbWUgZm9yIGFsbCBiaW5kaW5nc1xuXG5cdFx0XHRcdGZvciAoIGxldCBqID0gMCwgbSA9IG5CaW5kaW5nczsgaiAhPT0gbTsgKysgaiApIHtcblxuXHRcdFx0XHRcdGJpbmRpbmdzWyBqIF0ucHVzaCggbmV3IFByb3BlcnR5QmluZGluZyggb2JqZWN0LCBwYXRoc1sgaiBdLCBwYXJzZWRQYXRoc1sgaiBdICkgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH0gZWxzZSBpZiAoIGluZGV4IDwgbkNhY2hlZE9iamVjdHMgKSB7XG5cblx0XHRcdFx0a25vd25PYmplY3QgPSBvYmplY3RzWyBpbmRleCBdO1xuXG5cdFx0XHRcdC8vIG1vdmUgZXhpc3Rpbmcgb2JqZWN0IHRvIHRoZSBBQ1RJVkUgcmVnaW9uXG5cblx0XHRcdFx0Y29uc3QgZmlyc3RBY3RpdmVJbmRleCA9IC0tIG5DYWNoZWRPYmplY3RzLFxuXHRcdFx0XHRcdGxhc3RDYWNoZWRPYmplY3QgPSBvYmplY3RzWyBmaXJzdEFjdGl2ZUluZGV4IF07XG5cblx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgbGFzdENhY2hlZE9iamVjdC51dWlkIF0gPSBpbmRleDtcblx0XHRcdFx0b2JqZWN0c1sgaW5kZXggXSA9IGxhc3RDYWNoZWRPYmplY3Q7XG5cblx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgdXVpZCBdID0gZmlyc3RBY3RpdmVJbmRleDtcblx0XHRcdFx0b2JqZWN0c1sgZmlyc3RBY3RpdmVJbmRleCBdID0gb2JqZWN0O1xuXG5cdFx0XHRcdC8vIGFjY291bnRpbmcgaXMgZG9uZSwgbm93IGRvIHRoZSBzYW1lIGZvciBhbGwgYmluZGluZ3NcblxuXHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBuQmluZGluZ3M7IGogIT09IG07ICsrIGogKSB7XG5cblx0XHRcdFx0XHRjb25zdCBiaW5kaW5nc0ZvclBhdGggPSBiaW5kaW5nc1sgaiBdLFxuXHRcdFx0XHRcdFx0bGFzdENhY2hlZCA9IGJpbmRpbmdzRm9yUGF0aFsgZmlyc3RBY3RpdmVJbmRleCBdO1xuXG5cdFx0XHRcdFx0bGV0IGJpbmRpbmcgPSBiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF07XG5cblx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF0gPSBsYXN0Q2FjaGVkO1xuXG5cdFx0XHRcdFx0aWYgKCBiaW5kaW5nID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0XHRcdC8vIHNpbmNlIHdlIGRvIG5vdCBib3RoZXIgdG8gY3JlYXRlIG5ldyBiaW5kaW5nc1xuXHRcdFx0XHRcdFx0Ly8gZm9yIG9iamVjdHMgdGhhdCBhcmUgY2FjaGVkLCB0aGUgYmluZGluZyBtYXlcblx0XHRcdFx0XHRcdC8vIG9yIG1heSBub3QgZXhpc3RcblxuXHRcdFx0XHRcdFx0YmluZGluZyA9IG5ldyBQcm9wZXJ0eUJpbmRpbmcoIG9iamVjdCwgcGF0aHNbIGogXSwgcGFyc2VkUGF0aHNbIGogXSApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoWyBmaXJzdEFjdGl2ZUluZGV4IF0gPSBiaW5kaW5nO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIGlmICggb2JqZWN0c1sgaW5kZXggXSAhPT0ga25vd25PYmplY3QgKSB7XG5cblx0XHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLkFuaW1hdGlvbk9iamVjdEdyb3VwOiBEaWZmZXJlbnQgb2JqZWN0cyB3aXRoIHRoZSBzYW1lIFVVSUQgJyArXG5cdFx0XHRcdFx0J2RldGVjdGVkLiBDbGVhbiB0aGUgY2FjaGVzIG9yIHJlY3JlYXRlIHlvdXIgaW5mcmFzdHJ1Y3R1cmUgd2hlbiByZWxvYWRpbmcgc2NlbmVzLicgKTtcblxuXHRcdFx0fSAvLyBlbHNlIHRoZSBvYmplY3QgaXMgYWxyZWFkeSB3aGVyZSB3ZSB3YW50IGl0IHRvIGJlXG5cblx0XHR9IC8vIGZvciBhcmd1bWVudHNcblxuXHRcdHRoaXMubkNhY2hlZE9iamVjdHNfID0gbkNhY2hlZE9iamVjdHM7XG5cblx0fVxuXG5cdHJlbW92ZSgpIHtcblxuXHRcdGNvbnN0IG9iamVjdHMgPSB0aGlzLl9vYmplY3RzLFxuXHRcdFx0aW5kaWNlc0J5VVVJRCA9IHRoaXMuX2luZGljZXNCeVVVSUQsXG5cdFx0XHRiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxuXHRcdFx0bkJpbmRpbmdzID0gYmluZGluZ3MubGVuZ3RoO1xuXG5cdFx0bGV0IG5DYWNoZWRPYmplY3RzID0gdGhpcy5uQ2FjaGVkT2JqZWN0c187XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBhcmd1bWVudHMubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCBvYmplY3QgPSBhcmd1bWVudHNbIGkgXSxcblx0XHRcdFx0dXVpZCA9IG9iamVjdC51dWlkLFxuXHRcdFx0XHRpbmRleCA9IGluZGljZXNCeVVVSURbIHV1aWQgXTtcblxuXHRcdFx0aWYgKCBpbmRleCAhPT0gdW5kZWZpbmVkICYmIGluZGV4ID49IG5DYWNoZWRPYmplY3RzICkge1xuXG5cdFx0XHRcdC8vIG1vdmUgZXhpc3Rpbmcgb2JqZWN0IGludG8gdGhlIENBQ0hFRCByZWdpb25cblxuXHRcdFx0XHRjb25zdCBsYXN0Q2FjaGVkSW5kZXggPSBuQ2FjaGVkT2JqZWN0cyArKyxcblx0XHRcdFx0XHRmaXJzdEFjdGl2ZU9iamVjdCA9IG9iamVjdHNbIGxhc3RDYWNoZWRJbmRleCBdO1xuXG5cdFx0XHRcdGluZGljZXNCeVVVSURbIGZpcnN0QWN0aXZlT2JqZWN0LnV1aWQgXSA9IGluZGV4O1xuXHRcdFx0XHRvYmplY3RzWyBpbmRleCBdID0gZmlyc3RBY3RpdmVPYmplY3Q7XG5cblx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgdXVpZCBdID0gbGFzdENhY2hlZEluZGV4O1xuXHRcdFx0XHRvYmplY3RzWyBsYXN0Q2FjaGVkSW5kZXggXSA9IG9iamVjdDtcblxuXHRcdFx0XHQvLyBhY2NvdW50aW5nIGlzIGRvbmUsIG5vdyBkbyB0aGUgc2FtZSBmb3IgYWxsIGJpbmRpbmdzXG5cblx0XHRcdFx0Zm9yICggbGV0IGogPSAwLCBtID0gbkJpbmRpbmdzOyBqICE9PSBtOyArKyBqICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgYmluZGluZ3NGb3JQYXRoID0gYmluZGluZ3NbIGogXSxcblx0XHRcdFx0XHRcdGZpcnN0QWN0aXZlID0gYmluZGluZ3NGb3JQYXRoWyBsYXN0Q2FjaGVkSW5kZXggXSxcblx0XHRcdFx0XHRcdGJpbmRpbmcgPSBiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF07XG5cblx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF0gPSBmaXJzdEFjdGl2ZTtcblx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGhbIGxhc3RDYWNoZWRJbmRleCBdID0gYmluZGluZztcblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH0gLy8gZm9yIGFyZ3VtZW50c1xuXG5cdFx0dGhpcy5uQ2FjaGVkT2JqZWN0c18gPSBuQ2FjaGVkT2JqZWN0cztcblxuXHR9XG5cblx0Ly8gcmVtb3ZlICYgZm9yZ2V0XG5cdHVuY2FjaGUoKSB7XG5cblx0XHRjb25zdCBvYmplY3RzID0gdGhpcy5fb2JqZWN0cyxcblx0XHRcdGluZGljZXNCeVVVSUQgPSB0aGlzLl9pbmRpY2VzQnlVVUlELFxuXHRcdFx0YmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcblx0XHRcdG5CaW5kaW5ncyA9IGJpbmRpbmdzLmxlbmd0aDtcblxuXHRcdGxldCBuQ2FjaGVkT2JqZWN0cyA9IHRoaXMubkNhY2hlZE9iamVjdHNfLFxuXHRcdFx0bk9iamVjdHMgPSBvYmplY3RzLmxlbmd0aDtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGFyZ3VtZW50cy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdGNvbnN0IG9iamVjdCA9IGFyZ3VtZW50c1sgaSBdLFxuXHRcdFx0XHR1dWlkID0gb2JqZWN0LnV1aWQsXG5cdFx0XHRcdGluZGV4ID0gaW5kaWNlc0J5VVVJRFsgdXVpZCBdO1xuXG5cdFx0XHRpZiAoIGluZGV4ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdFx0ZGVsZXRlIGluZGljZXNCeVVVSURbIHV1aWQgXTtcblxuXHRcdFx0XHRpZiAoIGluZGV4IDwgbkNhY2hlZE9iamVjdHMgKSB7XG5cblx0XHRcdFx0XHQvLyBvYmplY3QgaXMgY2FjaGVkLCBzaHJpbmsgdGhlIENBQ0hFRCByZWdpb25cblxuXHRcdFx0XHRcdGNvbnN0IGZpcnN0QWN0aXZlSW5kZXggPSAtLSBuQ2FjaGVkT2JqZWN0cyxcblx0XHRcdFx0XHRcdGxhc3RDYWNoZWRPYmplY3QgPSBvYmplY3RzWyBmaXJzdEFjdGl2ZUluZGV4IF0sXG5cdFx0XHRcdFx0XHRsYXN0SW5kZXggPSAtLSBuT2JqZWN0cyxcblx0XHRcdFx0XHRcdGxhc3RPYmplY3QgPSBvYmplY3RzWyBsYXN0SW5kZXggXTtcblxuXHRcdFx0XHRcdC8vIGxhc3QgY2FjaGVkIG9iamVjdCB0YWtlcyB0aGlzIG9iamVjdCdzIHBsYWNlXG5cdFx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgbGFzdENhY2hlZE9iamVjdC51dWlkIF0gPSBpbmRleDtcblx0XHRcdFx0XHRvYmplY3RzWyBpbmRleCBdID0gbGFzdENhY2hlZE9iamVjdDtcblxuXHRcdFx0XHRcdC8vIGxhc3Qgb2JqZWN0IGdvZXMgdG8gdGhlIGFjdGl2YXRlZCBzbG90IGFuZCBwb3Bcblx0XHRcdFx0XHRpbmRpY2VzQnlVVUlEWyBsYXN0T2JqZWN0LnV1aWQgXSA9IGZpcnN0QWN0aXZlSW5kZXg7XG5cdFx0XHRcdFx0b2JqZWN0c1sgZmlyc3RBY3RpdmVJbmRleCBdID0gbGFzdE9iamVjdDtcblx0XHRcdFx0XHRvYmplY3RzLnBvcCgpO1xuXG5cdFx0XHRcdFx0Ly8gYWNjb3VudGluZyBpcyBkb25lLCBub3cgZG8gdGhlIHNhbWUgZm9yIGFsbCBiaW5kaW5nc1xuXG5cdFx0XHRcdFx0Zm9yICggbGV0IGogPSAwLCBtID0gbkJpbmRpbmdzOyBqICE9PSBtOyArKyBqICkge1xuXG5cdFx0XHRcdFx0XHRjb25zdCBiaW5kaW5nc0ZvclBhdGggPSBiaW5kaW5nc1sgaiBdLFxuXHRcdFx0XHRcdFx0XHRsYXN0Q2FjaGVkID0gYmluZGluZ3NGb3JQYXRoWyBmaXJzdEFjdGl2ZUluZGV4IF0sXG5cdFx0XHRcdFx0XHRcdGxhc3QgPSBiaW5kaW5nc0ZvclBhdGhbIGxhc3RJbmRleCBdO1xuXG5cdFx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGhbIGluZGV4IF0gPSBsYXN0Q2FjaGVkO1xuXHRcdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoWyBmaXJzdEFjdGl2ZUluZGV4IF0gPSBsYXN0O1xuXHRcdFx0XHRcdFx0YmluZGluZ3NGb3JQYXRoLnBvcCgpO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBvYmplY3QgaXMgYWN0aXZlLCBqdXN0IHN3YXAgd2l0aCB0aGUgbGFzdCBhbmQgcG9wXG5cblx0XHRcdFx0XHRjb25zdCBsYXN0SW5kZXggPSAtLSBuT2JqZWN0cyxcblx0XHRcdFx0XHRcdGxhc3RPYmplY3QgPSBvYmplY3RzWyBsYXN0SW5kZXggXTtcblxuXHRcdFx0XHRcdGlmICggbGFzdEluZGV4ID4gMCApIHtcblxuXHRcdFx0XHRcdFx0aW5kaWNlc0J5VVVJRFsgbGFzdE9iamVjdC51dWlkIF0gPSBpbmRleDtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdG9iamVjdHNbIGluZGV4IF0gPSBsYXN0T2JqZWN0O1xuXHRcdFx0XHRcdG9iamVjdHMucG9wKCk7XG5cblx0XHRcdFx0XHQvLyBhY2NvdW50aW5nIGlzIGRvbmUsIG5vdyBkbyB0aGUgc2FtZSBmb3IgYWxsIGJpbmRpbmdzXG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBuQmluZGluZ3M7IGogIT09IG07ICsrIGogKSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IGJpbmRpbmdzRm9yUGF0aCA9IGJpbmRpbmdzWyBqIF07XG5cblx0XHRcdFx0XHRcdGJpbmRpbmdzRm9yUGF0aFsgaW5kZXggXSA9IGJpbmRpbmdzRm9yUGF0aFsgbGFzdEluZGV4IF07XG5cdFx0XHRcdFx0XHRiaW5kaW5nc0ZvclBhdGgucG9wKCk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSAvLyBjYWNoZWQgb3IgYWN0aXZlXG5cblx0XHRcdH0gLy8gaWYgb2JqZWN0IGlzIGtub3duXG5cblx0XHR9IC8vIGZvciBhcmd1bWVudHNcblxuXHRcdHRoaXMubkNhY2hlZE9iamVjdHNfID0gbkNhY2hlZE9iamVjdHM7XG5cblx0fVxuXG5cdC8vIEludGVybmFsIGludGVyZmFjZSB1c2VkIGJ5IGJlZnJpZW5kZWQgUHJvcGVydHlCaW5kaW5nLkNvbXBvc2l0ZTpcblxuXHRzdWJzY3JpYmVfKCBwYXRoLCBwYXJzZWRQYXRoICkge1xuXG5cdFx0Ly8gcmV0dXJucyBhbiBhcnJheSBvZiBiaW5kaW5ncyBmb3IgdGhlIGdpdmVuIHBhdGggdGhhdCBpcyBjaGFuZ2VkXG5cdFx0Ly8gYWNjb3JkaW5nIHRvIHRoZSBjb250YWluZWQgb2JqZWN0cyBpbiB0aGUgZ3JvdXBcblxuXHRcdGNvbnN0IGluZGljZXNCeVBhdGggPSB0aGlzLl9iaW5kaW5nc0luZGljZXNCeVBhdGg7XG5cdFx0bGV0IGluZGV4ID0gaW5kaWNlc0J5UGF0aFsgcGF0aCBdO1xuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3M7XG5cblx0XHRpZiAoIGluZGV4ICE9PSB1bmRlZmluZWQgKSByZXR1cm4gYmluZGluZ3NbIGluZGV4IF07XG5cblx0XHRjb25zdCBwYXRocyA9IHRoaXMuX3BhdGhzLFxuXHRcdFx0cGFyc2VkUGF0aHMgPSB0aGlzLl9wYXJzZWRQYXRocyxcblx0XHRcdG9iamVjdHMgPSB0aGlzLl9vYmplY3RzLFxuXHRcdFx0bk9iamVjdHMgPSBvYmplY3RzLmxlbmd0aCxcblx0XHRcdG5DYWNoZWRPYmplY3RzID0gdGhpcy5uQ2FjaGVkT2JqZWN0c18sXG5cdFx0XHRiaW5kaW5nc0ZvclBhdGggPSBuZXcgQXJyYXkoIG5PYmplY3RzICk7XG5cblx0XHRpbmRleCA9IGJpbmRpbmdzLmxlbmd0aDtcblxuXHRcdGluZGljZXNCeVBhdGhbIHBhdGggXSA9IGluZGV4O1xuXG5cdFx0cGF0aHMucHVzaCggcGF0aCApO1xuXHRcdHBhcnNlZFBhdGhzLnB1c2goIHBhcnNlZFBhdGggKTtcblx0XHRiaW5kaW5ncy5wdXNoKCBiaW5kaW5nc0ZvclBhdGggKTtcblxuXHRcdGZvciAoIGxldCBpID0gbkNhY2hlZE9iamVjdHMsIG4gPSBvYmplY3RzLmxlbmd0aDsgaSAhPT0gbjsgKysgaSApIHtcblxuXHRcdFx0Y29uc3Qgb2JqZWN0ID0gb2JqZWN0c1sgaSBdO1xuXHRcdFx0YmluZGluZ3NGb3JQYXRoWyBpIF0gPSBuZXcgUHJvcGVydHlCaW5kaW5nKCBvYmplY3QsIHBhdGgsIHBhcnNlZFBhdGggKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBiaW5kaW5nc0ZvclBhdGg7XG5cblx0fVxuXG5cdHVuc3Vic2NyaWJlXyggcGF0aCApIHtcblxuXHRcdC8vIHRlbGxzIHRoZSBncm91cCB0byBmb3JnZXQgYWJvdXQgYSBwcm9wZXJ0eSBwYXRoIGFuZCBubyBsb25nZXJcblx0XHQvLyB1cGRhdGUgdGhlIGFycmF5IHByZXZpb3VzbHkgb2J0YWluZWQgd2l0aCAnc3Vic2NyaWJlXydcblxuXHRcdGNvbnN0IGluZGljZXNCeVBhdGggPSB0aGlzLl9iaW5kaW5nc0luZGljZXNCeVBhdGgsXG5cdFx0XHRpbmRleCA9IGluZGljZXNCeVBhdGhbIHBhdGggXTtcblxuXHRcdGlmICggaW5kZXggIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3QgcGF0aHMgPSB0aGlzLl9wYXRocyxcblx0XHRcdFx0cGFyc2VkUGF0aHMgPSB0aGlzLl9wYXJzZWRQYXRocyxcblx0XHRcdFx0YmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcblx0XHRcdFx0bGFzdEJpbmRpbmdzSW5kZXggPSBiaW5kaW5ncy5sZW5ndGggLSAxLFxuXHRcdFx0XHRsYXN0QmluZGluZ3MgPSBiaW5kaW5nc1sgbGFzdEJpbmRpbmdzSW5kZXggXSxcblx0XHRcdFx0bGFzdEJpbmRpbmdzUGF0aCA9IHBhdGhbIGxhc3RCaW5kaW5nc0luZGV4IF07XG5cblx0XHRcdGluZGljZXNCeVBhdGhbIGxhc3RCaW5kaW5nc1BhdGggXSA9IGluZGV4O1xuXG5cdFx0XHRiaW5kaW5nc1sgaW5kZXggXSA9IGxhc3RCaW5kaW5ncztcblx0XHRcdGJpbmRpbmdzLnBvcCgpO1xuXG5cdFx0XHRwYXJzZWRQYXRoc1sgaW5kZXggXSA9IHBhcnNlZFBhdGhzWyBsYXN0QmluZGluZ3NJbmRleCBdO1xuXHRcdFx0cGFyc2VkUGF0aHMucG9wKCk7XG5cblx0XHRcdHBhdGhzWyBpbmRleCBdID0gcGF0aHNbIGxhc3RCaW5kaW5nc0luZGV4IF07XG5cdFx0XHRwYXRocy5wb3AoKTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuY2xhc3MgQW5pbWF0aW9uQWN0aW9uIHtcblxuXHRjb25zdHJ1Y3RvciggbWl4ZXIsIGNsaXAsIGxvY2FsUm9vdCA9IG51bGwsIGJsZW5kTW9kZSA9IGNsaXAuYmxlbmRNb2RlICkge1xuXG5cdFx0dGhpcy5fbWl4ZXIgPSBtaXhlcjtcblx0XHR0aGlzLl9jbGlwID0gY2xpcDtcblx0XHR0aGlzLl9sb2NhbFJvb3QgPSBsb2NhbFJvb3Q7XG5cdFx0dGhpcy5ibGVuZE1vZGUgPSBibGVuZE1vZGU7XG5cblx0XHRjb25zdCB0cmFja3MgPSBjbGlwLnRyYWNrcyxcblx0XHRcdG5UcmFja3MgPSB0cmFja3MubGVuZ3RoLFxuXHRcdFx0aW50ZXJwb2xhbnRzID0gbmV3IEFycmF5KCBuVHJhY2tzICk7XG5cblx0XHRjb25zdCBpbnRlcnBvbGFudFNldHRpbmdzID0ge1xuXHRcdFx0ZW5kaW5nU3RhcnQ6IFplcm9DdXJ2YXR1cmVFbmRpbmcsXG5cdFx0XHRlbmRpbmdFbmQ6IFplcm9DdXJ2YXR1cmVFbmRpbmdcblx0XHR9O1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuVHJhY2tzOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCBpbnRlcnBvbGFudCA9IHRyYWNrc1sgaSBdLmNyZWF0ZUludGVycG9sYW50KCBudWxsICk7XG5cdFx0XHRpbnRlcnBvbGFudHNbIGkgXSA9IGludGVycG9sYW50O1xuXHRcdFx0aW50ZXJwb2xhbnQuc2V0dGluZ3MgPSBpbnRlcnBvbGFudFNldHRpbmdzO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5faW50ZXJwb2xhbnRTZXR0aW5ncyA9IGludGVycG9sYW50U2V0dGluZ3M7XG5cblx0XHR0aGlzLl9pbnRlcnBvbGFudHMgPSBpbnRlcnBvbGFudHM7IC8vIGJvdW5kIGJ5IHRoZSBtaXhlclxuXG5cdFx0Ly8gaW5zaWRlOiBQcm9wZXJ0eU1peGVyIChtYW5hZ2VkIGJ5IHRoZSBtaXhlcilcblx0XHR0aGlzLl9wcm9wZXJ0eUJpbmRpbmdzID0gbmV3IEFycmF5KCBuVHJhY2tzICk7XG5cblx0XHR0aGlzLl9jYWNoZUluZGV4ID0gbnVsbDsgLy8gZm9yIHRoZSBtZW1vcnkgbWFuYWdlclxuXHRcdHRoaXMuX2J5Q2xpcENhY2hlSW5kZXggPSBudWxsOyAvLyBmb3IgdGhlIG1lbW9yeSBtYW5hZ2VyXG5cblx0XHR0aGlzLl90aW1lU2NhbGVJbnRlcnBvbGFudCA9IG51bGw7XG5cdFx0dGhpcy5fd2VpZ2h0SW50ZXJwb2xhbnQgPSBudWxsO1xuXG5cdFx0dGhpcy5sb29wID0gTG9vcFJlcGVhdDtcblx0XHR0aGlzLl9sb29wQ291bnQgPSAtIDE7XG5cblx0XHQvLyBnbG9iYWwgbWl4ZXIgdGltZSB3aGVuIHRoZSBhY3Rpb24gaXMgdG8gYmUgc3RhcnRlZFxuXHRcdC8vIGl0J3Mgc2V0IGJhY2sgdG8gJ251bGwnIHVwb24gc3RhcnQgb2YgdGhlIGFjdGlvblxuXHRcdHRoaXMuX3N0YXJ0VGltZSA9IG51bGw7XG5cblx0XHQvLyBzY2FsZWQgbG9jYWwgdGltZSBvZiB0aGUgYWN0aW9uXG5cdFx0Ly8gZ2V0cyBjbGFtcGVkIG9yIHdyYXBwZWQgdG8gMC4uY2xpcC5kdXJhdGlvbiBhY2NvcmRpbmcgdG8gbG9vcFxuXHRcdHRoaXMudGltZSA9IDA7XG5cblx0XHR0aGlzLnRpbWVTY2FsZSA9IDE7XG5cdFx0dGhpcy5fZWZmZWN0aXZlVGltZVNjYWxlID0gMTtcblxuXHRcdHRoaXMud2VpZ2h0ID0gMTtcblx0XHR0aGlzLl9lZmZlY3RpdmVXZWlnaHQgPSAxO1xuXG5cdFx0dGhpcy5yZXBldGl0aW9ucyA9IEluZmluaXR5OyAvLyBuby4gb2YgcmVwZXRpdGlvbnMgd2hlbiBsb29waW5nXG5cblx0XHR0aGlzLnBhdXNlZCA9IGZhbHNlOyAvLyB0cnVlIC0+IHplcm8gZWZmZWN0aXZlIHRpbWUgc2NhbGVcblx0XHR0aGlzLmVuYWJsZWQgPSB0cnVlOyAvLyBmYWxzZSAtPiB6ZXJvIGVmZmVjdGl2ZSB3ZWlnaHRcblxuXHRcdHRoaXMuY2xhbXBXaGVuRmluaXNoZWQgPSBmYWxzZTsvLyBrZWVwIGZlZWRpbmcgdGhlIGxhc3QgZnJhbWU/XG5cblx0XHR0aGlzLnplcm9TbG9wZUF0U3RhcnQgPSB0cnVlOy8vIGZvciBzbW9vdGggaW50ZXJwb2xhdGlvbiB3L28gc2VwYXJhdGVcblx0XHR0aGlzLnplcm9TbG9wZUF0RW5kID0gdHJ1ZTsvLyBjbGlwcyBmb3Igc3RhcnQsIGxvb3AgYW5kIGVuZFxuXG5cdH1cblxuXHQvLyBTdGF0ZSAmIFNjaGVkdWxpbmdcblxuXHRwbGF5KCkge1xuXG5cdFx0dGhpcy5fbWl4ZXIuX2FjdGl2YXRlQWN0aW9uKCB0aGlzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c3RvcCgpIHtcblxuXHRcdHRoaXMuX21peGVyLl9kZWFjdGl2YXRlQWN0aW9uKCB0aGlzICk7XG5cblx0XHRyZXR1cm4gdGhpcy5yZXNldCgpO1xuXG5cdH1cblxuXHRyZXNldCgpIHtcblxuXHRcdHRoaXMucGF1c2VkID0gZmFsc2U7XG5cdFx0dGhpcy5lbmFibGVkID0gdHJ1ZTtcblxuXHRcdHRoaXMudGltZSA9IDA7IC8vIHJlc3RhcnQgY2xpcFxuXHRcdHRoaXMuX2xvb3BDb3VudCA9IC0gMTsvLyBmb3JnZXQgcHJldmlvdXMgbG9vcHNcblx0XHR0aGlzLl9zdGFydFRpbWUgPSBudWxsOy8vIGZvcmdldCBzY2hlZHVsaW5nXG5cblx0XHRyZXR1cm4gdGhpcy5zdG9wRmFkaW5nKCkuc3RvcFdhcnBpbmcoKTtcblxuXHR9XG5cblx0aXNSdW5uaW5nKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZW5hYmxlZCAmJiAhIHRoaXMucGF1c2VkICYmIHRoaXMudGltZVNjYWxlICE9PSAwICYmXG5cdFx0XHR0aGlzLl9zdGFydFRpbWUgPT09IG51bGwgJiYgdGhpcy5fbWl4ZXIuX2lzQWN0aXZlQWN0aW9uKCB0aGlzICk7XG5cblx0fVxuXG5cdC8vIHJldHVybiB0cnVlIHdoZW4gcGxheSBoYXMgYmVlbiBjYWxsZWRcblx0aXNTY2hlZHVsZWQoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fbWl4ZXIuX2lzQWN0aXZlQWN0aW9uKCB0aGlzICk7XG5cblx0fVxuXG5cdHN0YXJ0QXQoIHRpbWUgKSB7XG5cblx0XHR0aGlzLl9zdGFydFRpbWUgPSB0aW1lO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldExvb3AoIG1vZGUsIHJlcGV0aXRpb25zICkge1xuXG5cdFx0dGhpcy5sb29wID0gbW9kZTtcblx0XHR0aGlzLnJlcGV0aXRpb25zID0gcmVwZXRpdGlvbnM7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Ly8gV2VpZ2h0XG5cblx0Ly8gc2V0IHRoZSB3ZWlnaHQgc3RvcHBpbmcgYW55IHNjaGVkdWxlZCBmYWRpbmdcblx0Ly8gYWx0aG91Z2ggLmVuYWJsZWQgPSBmYWxzZSB5aWVsZHMgYW4gZWZmZWN0aXZlIHdlaWdodCBvZiB6ZXJvLCB0aGlzXG5cdC8vIG1ldGhvZCBkb2VzICpub3QqIGNoYW5nZSAuZW5hYmxlZCwgYmVjYXVzZSBpdCB3b3VsZCBiZSBjb25mdXNpbmdcblx0c2V0RWZmZWN0aXZlV2VpZ2h0KCB3ZWlnaHQgKSB7XG5cblx0XHR0aGlzLndlaWdodCA9IHdlaWdodDtcblxuXHRcdC8vIG5vdGU6IHNhbWUgbG9naWMgYXMgd2hlbiB1cGRhdGVkIGF0IHJ1bnRpbWVcblx0XHR0aGlzLl9lZmZlY3RpdmVXZWlnaHQgPSB0aGlzLmVuYWJsZWQgPyB3ZWlnaHQgOiAwO1xuXG5cdFx0cmV0dXJuIHRoaXMuc3RvcEZhZGluZygpO1xuXG5cdH1cblxuXHQvLyByZXR1cm4gdGhlIHdlaWdodCBjb25zaWRlcmluZyBmYWRpbmcgYW5kIC5lbmFibGVkXG5cdGdldEVmZmVjdGl2ZVdlaWdodCgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9lZmZlY3RpdmVXZWlnaHQ7XG5cblx0fVxuXG5cdGZhZGVJbiggZHVyYXRpb24gKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fc2NoZWR1bGVGYWRpbmcoIGR1cmF0aW9uLCAwLCAxICk7XG5cblx0fVxuXG5cdGZhZGVPdXQoIGR1cmF0aW9uICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX3NjaGVkdWxlRmFkaW5nKCBkdXJhdGlvbiwgMSwgMCApO1xuXG5cdH1cblxuXHRjcm9zc0ZhZGVGcm9tKCBmYWRlT3V0QWN0aW9uLCBkdXJhdGlvbiwgd2FycCApIHtcblxuXHRcdGZhZGVPdXRBY3Rpb24uZmFkZU91dCggZHVyYXRpb24gKTtcblx0XHR0aGlzLmZhZGVJbiggZHVyYXRpb24gKTtcblxuXHRcdGlmICggd2FycCApIHtcblxuXHRcdFx0Y29uc3QgZmFkZUluRHVyYXRpb24gPSB0aGlzLl9jbGlwLmR1cmF0aW9uLFxuXHRcdFx0XHRmYWRlT3V0RHVyYXRpb24gPSBmYWRlT3V0QWN0aW9uLl9jbGlwLmR1cmF0aW9uLFxuXG5cdFx0XHRcdHN0YXJ0RW5kUmF0aW8gPSBmYWRlT3V0RHVyYXRpb24gLyBmYWRlSW5EdXJhdGlvbixcblx0XHRcdFx0ZW5kU3RhcnRSYXRpbyA9IGZhZGVJbkR1cmF0aW9uIC8gZmFkZU91dER1cmF0aW9uO1xuXG5cdFx0XHRmYWRlT3V0QWN0aW9uLndhcnAoIDEuMCwgc3RhcnRFbmRSYXRpbywgZHVyYXRpb24gKTtcblx0XHRcdHRoaXMud2FycCggZW5kU3RhcnRSYXRpbywgMS4wLCBkdXJhdGlvbiApO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNyb3NzRmFkZVRvKCBmYWRlSW5BY3Rpb24sIGR1cmF0aW9uLCB3YXJwICkge1xuXG5cdFx0cmV0dXJuIGZhZGVJbkFjdGlvbi5jcm9zc0ZhZGVGcm9tKCB0aGlzLCBkdXJhdGlvbiwgd2FycCApO1xuXG5cdH1cblxuXHRzdG9wRmFkaW5nKCkge1xuXG5cdFx0Y29uc3Qgd2VpZ2h0SW50ZXJwb2xhbnQgPSB0aGlzLl93ZWlnaHRJbnRlcnBvbGFudDtcblxuXHRcdGlmICggd2VpZ2h0SW50ZXJwb2xhbnQgIT09IG51bGwgKSB7XG5cblx0XHRcdHRoaXMuX3dlaWdodEludGVycG9sYW50ID0gbnVsbDtcblx0XHRcdHRoaXMuX21peGVyLl90YWtlQmFja0NvbnRyb2xJbnRlcnBvbGFudCggd2VpZ2h0SW50ZXJwb2xhbnQgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvLyBUaW1lIFNjYWxlIENvbnRyb2xcblxuXHQvLyBzZXQgdGhlIHRpbWUgc2NhbGUgc3RvcHBpbmcgYW55IHNjaGVkdWxlZCB3YXJwaW5nXG5cdC8vIGFsdGhvdWdoIC5wYXVzZWQgPSB0cnVlIHlpZWxkcyBhbiBlZmZlY3RpdmUgdGltZSBzY2FsZSBvZiB6ZXJvLCB0aGlzXG5cdC8vIG1ldGhvZCBkb2VzICpub3QqIGNoYW5nZSAucGF1c2VkLCBiZWNhdXNlIGl0IHdvdWxkIGJlIGNvbmZ1c2luZ1xuXHRzZXRFZmZlY3RpdmVUaW1lU2NhbGUoIHRpbWVTY2FsZSApIHtcblxuXHRcdHRoaXMudGltZVNjYWxlID0gdGltZVNjYWxlO1xuXHRcdHRoaXMuX2VmZmVjdGl2ZVRpbWVTY2FsZSA9IHRoaXMucGF1c2VkID8gMCA6IHRpbWVTY2FsZTtcblxuXHRcdHJldHVybiB0aGlzLnN0b3BXYXJwaW5nKCk7XG5cblx0fVxuXG5cdC8vIHJldHVybiB0aGUgdGltZSBzY2FsZSBjb25zaWRlcmluZyB3YXJwaW5nIGFuZCAucGF1c2VkXG5cdGdldEVmZmVjdGl2ZVRpbWVTY2FsZSgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9lZmZlY3RpdmVUaW1lU2NhbGU7XG5cblx0fVxuXG5cdHNldER1cmF0aW9uKCBkdXJhdGlvbiApIHtcblxuXHRcdHRoaXMudGltZVNjYWxlID0gdGhpcy5fY2xpcC5kdXJhdGlvbiAvIGR1cmF0aW9uO1xuXG5cdFx0cmV0dXJuIHRoaXMuc3RvcFdhcnBpbmcoKTtcblxuXHR9XG5cblx0c3luY1dpdGgoIGFjdGlvbiApIHtcblxuXHRcdHRoaXMudGltZSA9IGFjdGlvbi50aW1lO1xuXHRcdHRoaXMudGltZVNjYWxlID0gYWN0aW9uLnRpbWVTY2FsZTtcblxuXHRcdHJldHVybiB0aGlzLnN0b3BXYXJwaW5nKCk7XG5cblx0fVxuXG5cdGhhbHQoIGR1cmF0aW9uICkge1xuXG5cdFx0cmV0dXJuIHRoaXMud2FycCggdGhpcy5fZWZmZWN0aXZlVGltZVNjYWxlLCAwLCBkdXJhdGlvbiApO1xuXG5cdH1cblxuXHR3YXJwKCBzdGFydFRpbWVTY2FsZSwgZW5kVGltZVNjYWxlLCBkdXJhdGlvbiApIHtcblxuXHRcdGNvbnN0IG1peGVyID0gdGhpcy5fbWl4ZXIsXG5cdFx0XHRub3cgPSBtaXhlci50aW1lLFxuXHRcdFx0dGltZVNjYWxlID0gdGhpcy50aW1lU2NhbGU7XG5cblx0XHRsZXQgaW50ZXJwb2xhbnQgPSB0aGlzLl90aW1lU2NhbGVJbnRlcnBvbGFudDtcblxuXHRcdGlmICggaW50ZXJwb2xhbnQgPT09IG51bGwgKSB7XG5cblx0XHRcdGludGVycG9sYW50ID0gbWl4ZXIuX2xlbmRDb250cm9sSW50ZXJwb2xhbnQoKTtcblx0XHRcdHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50ID0gaW50ZXJwb2xhbnQ7XG5cblx0XHR9XG5cblx0XHRjb25zdCB0aW1lcyA9IGludGVycG9sYW50LnBhcmFtZXRlclBvc2l0aW9ucyxcblx0XHRcdHZhbHVlcyA9IGludGVycG9sYW50LnNhbXBsZVZhbHVlcztcblxuXHRcdHRpbWVzWyAwIF0gPSBub3c7XG5cdFx0dGltZXNbIDEgXSA9IG5vdyArIGR1cmF0aW9uO1xuXG5cdFx0dmFsdWVzWyAwIF0gPSBzdGFydFRpbWVTY2FsZSAvIHRpbWVTY2FsZTtcblx0XHR2YWx1ZXNbIDEgXSA9IGVuZFRpbWVTY2FsZSAvIHRpbWVTY2FsZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzdG9wV2FycGluZygpIHtcblxuXHRcdGNvbnN0IHRpbWVTY2FsZUludGVycG9sYW50ID0gdGhpcy5fdGltZVNjYWxlSW50ZXJwb2xhbnQ7XG5cblx0XHRpZiAoIHRpbWVTY2FsZUludGVycG9sYW50ICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl90aW1lU2NhbGVJbnRlcnBvbGFudCA9IG51bGw7XG5cdFx0XHR0aGlzLl9taXhlci5fdGFrZUJhY2tDb250cm9sSW50ZXJwb2xhbnQoIHRpbWVTY2FsZUludGVycG9sYW50ICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Ly8gT2JqZWN0IEFjY2Vzc29yc1xuXG5cdGdldE1peGVyKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX21peGVyO1xuXG5cdH1cblxuXHRnZXRDbGlwKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX2NsaXA7XG5cblx0fVxuXG5cdGdldFJvb3QoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5fbG9jYWxSb290IHx8IHRoaXMuX21peGVyLl9yb290O1xuXG5cdH1cblxuXHQvLyBJbnRlcm5hXG5cblx0X3VwZGF0ZSggdGltZSwgZGVsdGFUaW1lLCB0aW1lRGlyZWN0aW9uLCBhY2N1SW5kZXggKSB7XG5cblx0XHQvLyBjYWxsZWQgYnkgdGhlIG1peGVyXG5cblx0XHRpZiAoICEgdGhpcy5lbmFibGVkICkge1xuXG5cdFx0XHQvLyBjYWxsIC5fdXBkYXRlV2VpZ2h0KCkgdG8gdXBkYXRlIC5fZWZmZWN0aXZlV2VpZ2h0XG5cblx0XHRcdHRoaXMuX3VwZGF0ZVdlaWdodCggdGltZSApO1xuXHRcdFx0cmV0dXJuO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3Qgc3RhcnRUaW1lID0gdGhpcy5fc3RhcnRUaW1lO1xuXG5cdFx0aWYgKCBzdGFydFRpbWUgIT09IG51bGwgKSB7XG5cblx0XHRcdC8vIGNoZWNrIGZvciBzY2hlZHVsZWQgc3RhcnQgb2YgYWN0aW9uXG5cblx0XHRcdGNvbnN0IHRpbWVSdW5uaW5nID0gKCB0aW1lIC0gc3RhcnRUaW1lICkgKiB0aW1lRGlyZWN0aW9uO1xuXHRcdFx0aWYgKCB0aW1lUnVubmluZyA8IDAgfHwgdGltZURpcmVjdGlvbiA9PT0gMCApIHtcblxuXHRcdFx0XHRkZWx0YVRpbWUgPSAwO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cblx0XHRcdFx0dGhpcy5fc3RhcnRUaW1lID0gbnVsbDsgLy8gdW5zY2hlZHVsZVxuXHRcdFx0XHRkZWx0YVRpbWUgPSB0aW1lRGlyZWN0aW9uICogdGltZVJ1bm5pbmc7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdC8vIGFwcGx5IHRpbWUgc2NhbGUgYW5kIGFkdmFuY2UgdGltZVxuXG5cdFx0ZGVsdGFUaW1lICo9IHRoaXMuX3VwZGF0ZVRpbWVTY2FsZSggdGltZSApO1xuXHRcdGNvbnN0IGNsaXBUaW1lID0gdGhpcy5fdXBkYXRlVGltZSggZGVsdGFUaW1lICk7XG5cblx0XHQvLyBub3RlOiBfdXBkYXRlVGltZSBtYXkgZGlzYWJsZSB0aGUgYWN0aW9uIHJlc3VsdGluZyBpblxuXHRcdC8vIGFuIGVmZmVjdGl2ZSB3ZWlnaHQgb2YgMFxuXG5cdFx0Y29uc3Qgd2VpZ2h0ID0gdGhpcy5fdXBkYXRlV2VpZ2h0KCB0aW1lICk7XG5cblx0XHRpZiAoIHdlaWdodCA+IDAgKSB7XG5cblx0XHRcdGNvbnN0IGludGVycG9sYW50cyA9IHRoaXMuX2ludGVycG9sYW50cztcblx0XHRcdGNvbnN0IHByb3BlcnR5TWl4ZXJzID0gdGhpcy5fcHJvcGVydHlCaW5kaW5ncztcblxuXHRcdFx0c3dpdGNoICggdGhpcy5ibGVuZE1vZGUgKSB7XG5cblx0XHRcdFx0Y2FzZSBBZGRpdGl2ZUFuaW1hdGlvbkJsZW5kTW9kZTpcblxuXHRcdFx0XHRcdGZvciAoIGxldCBqID0gMCwgbSA9IGludGVycG9sYW50cy5sZW5ndGg7IGogIT09IG07ICsrIGogKSB7XG5cblx0XHRcdFx0XHRcdGludGVycG9sYW50c1sgaiBdLmV2YWx1YXRlKCBjbGlwVGltZSApO1xuXHRcdFx0XHRcdFx0cHJvcGVydHlNaXhlcnNbIGogXS5hY2N1bXVsYXRlQWRkaXRpdmUoIHdlaWdodCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGU6XG5cdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRmb3IgKCBsZXQgaiA9IDAsIG0gPSBpbnRlcnBvbGFudHMubGVuZ3RoOyBqICE9PSBtOyArKyBqICkge1xuXG5cdFx0XHRcdFx0XHRpbnRlcnBvbGFudHNbIGogXS5ldmFsdWF0ZSggY2xpcFRpbWUgKTtcblx0XHRcdFx0XHRcdHByb3BlcnR5TWl4ZXJzWyBqIF0uYWNjdW11bGF0ZSggYWNjdUluZGV4LCB3ZWlnaHQgKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRfdXBkYXRlV2VpZ2h0KCB0aW1lICkge1xuXG5cdFx0bGV0IHdlaWdodCA9IDA7XG5cblx0XHRpZiAoIHRoaXMuZW5hYmxlZCApIHtcblxuXHRcdFx0d2VpZ2h0ID0gdGhpcy53ZWlnaHQ7XG5cdFx0XHRjb25zdCBpbnRlcnBvbGFudCA9IHRoaXMuX3dlaWdodEludGVycG9sYW50O1xuXG5cdFx0XHRpZiAoIGludGVycG9sYW50ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGNvbnN0IGludGVycG9sYW50VmFsdWUgPSBpbnRlcnBvbGFudC5ldmFsdWF0ZSggdGltZSApWyAwIF07XG5cblx0XHRcdFx0d2VpZ2h0ICo9IGludGVycG9sYW50VmFsdWU7XG5cblx0XHRcdFx0aWYgKCB0aW1lID4gaW50ZXJwb2xhbnQucGFyYW1ldGVyUG9zaXRpb25zWyAxIF0gKSB7XG5cblx0XHRcdFx0XHR0aGlzLnN0b3BGYWRpbmcoKTtcblxuXHRcdFx0XHRcdGlmICggaW50ZXJwb2xhbnRWYWx1ZSA9PT0gMCApIHtcblxuXHRcdFx0XHRcdFx0Ly8gZmFkZWQgb3V0LCBkaXNhYmxlXG5cdFx0XHRcdFx0XHR0aGlzLmVuYWJsZWQgPSBmYWxzZTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHRoaXMuX2VmZmVjdGl2ZVdlaWdodCA9IHdlaWdodDtcblx0XHRyZXR1cm4gd2VpZ2h0O1xuXG5cdH1cblxuXHRfdXBkYXRlVGltZVNjYWxlKCB0aW1lICkge1xuXG5cdFx0bGV0IHRpbWVTY2FsZSA9IDA7XG5cblx0XHRpZiAoICEgdGhpcy5wYXVzZWQgKSB7XG5cblx0XHRcdHRpbWVTY2FsZSA9IHRoaXMudGltZVNjYWxlO1xuXG5cdFx0XHRjb25zdCBpbnRlcnBvbGFudCA9IHRoaXMuX3RpbWVTY2FsZUludGVycG9sYW50O1xuXG5cdFx0XHRpZiAoIGludGVycG9sYW50ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGNvbnN0IGludGVycG9sYW50VmFsdWUgPSBpbnRlcnBvbGFudC5ldmFsdWF0ZSggdGltZSApWyAwIF07XG5cblx0XHRcdFx0dGltZVNjYWxlICo9IGludGVycG9sYW50VmFsdWU7XG5cblx0XHRcdFx0aWYgKCB0aW1lID4gaW50ZXJwb2xhbnQucGFyYW1ldGVyUG9zaXRpb25zWyAxIF0gKSB7XG5cblx0XHRcdFx0XHR0aGlzLnN0b3BXYXJwaW5nKCk7XG5cblx0XHRcdFx0XHRpZiAoIHRpbWVTY2FsZSA9PT0gMCApIHtcblxuXHRcdFx0XHRcdFx0Ly8gbW90aW9uIGhhcyBoYWx0ZWQsIHBhdXNlXG5cdFx0XHRcdFx0XHR0aGlzLnBhdXNlZCA9IHRydWU7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHQvLyB3YXJwIGRvbmUgLSBhcHBseSBmaW5hbCB0aW1lIHNjYWxlXG5cdFx0XHRcdFx0XHR0aGlzLnRpbWVTY2FsZSA9IHRpbWVTY2FsZTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHRoaXMuX2VmZmVjdGl2ZVRpbWVTY2FsZSA9IHRpbWVTY2FsZTtcblx0XHRyZXR1cm4gdGltZVNjYWxlO1xuXG5cdH1cblxuXHRfdXBkYXRlVGltZSggZGVsdGFUaW1lICkge1xuXG5cdFx0Y29uc3QgZHVyYXRpb24gPSB0aGlzLl9jbGlwLmR1cmF0aW9uO1xuXHRcdGNvbnN0IGxvb3AgPSB0aGlzLmxvb3A7XG5cblx0XHRsZXQgdGltZSA9IHRoaXMudGltZSArIGRlbHRhVGltZTtcblx0XHRsZXQgbG9vcENvdW50ID0gdGhpcy5fbG9vcENvdW50O1xuXG5cdFx0Y29uc3QgcGluZ1BvbmcgPSAoIGxvb3AgPT09IExvb3BQaW5nUG9uZyApO1xuXG5cdFx0aWYgKCBkZWx0YVRpbWUgPT09IDAgKSB7XG5cblx0XHRcdGlmICggbG9vcENvdW50ID09PSAtIDEgKSByZXR1cm4gdGltZTtcblxuXHRcdFx0cmV0dXJuICggcGluZ1BvbmcgJiYgKCBsb29wQ291bnQgJiAxICkgPT09IDEgKSA/IGR1cmF0aW9uIC0gdGltZSA6IHRpbWU7XG5cblx0XHR9XG5cblx0XHRpZiAoIGxvb3AgPT09IExvb3BPbmNlICkge1xuXG5cdFx0XHRpZiAoIGxvb3BDb3VudCA9PT0gLSAxICkge1xuXG5cdFx0XHRcdC8vIGp1c3Qgc3RhcnRlZFxuXG5cdFx0XHRcdHRoaXMuX2xvb3BDb3VudCA9IDA7XG5cdFx0XHRcdHRoaXMuX3NldEVuZGluZ3MoIHRydWUsIHRydWUsIGZhbHNlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0aGFuZGxlX3N0b3A6IHtcblxuXHRcdFx0XHRpZiAoIHRpbWUgPj0gZHVyYXRpb24gKSB7XG5cblx0XHRcdFx0XHR0aW1lID0gZHVyYXRpb247XG5cblx0XHRcdFx0fSBlbHNlIGlmICggdGltZSA8IDAgKSB7XG5cblx0XHRcdFx0XHR0aW1lID0gMDtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0dGhpcy50aW1lID0gdGltZTtcblxuXHRcdFx0XHRcdGJyZWFrIGhhbmRsZV9zdG9wO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZiAoIHRoaXMuY2xhbXBXaGVuRmluaXNoZWQgKSB0aGlzLnBhdXNlZCA9IHRydWU7XG5cdFx0XHRcdGVsc2UgdGhpcy5lbmFibGVkID0gZmFsc2U7XG5cblx0XHRcdFx0dGhpcy50aW1lID0gdGltZTtcblxuXHRcdFx0XHR0aGlzLl9taXhlci5kaXNwYXRjaEV2ZW50KCB7XG5cdFx0XHRcdFx0dHlwZTogJ2ZpbmlzaGVkJywgYWN0aW9uOiB0aGlzLFxuXHRcdFx0XHRcdGRpcmVjdGlvbjogZGVsdGFUaW1lIDwgMCA/IC0gMSA6IDFcblx0XHRcdFx0fSApO1xuXG5cdFx0XHR9XG5cblx0XHR9IGVsc2UgeyAvLyByZXBldGl0aXZlIFJlcGVhdCBvciBQaW5nUG9uZ1xuXG5cdFx0XHRpZiAoIGxvb3BDb3VudCA9PT0gLSAxICkge1xuXG5cdFx0XHRcdC8vIGp1c3Qgc3RhcnRlZFxuXG5cdFx0XHRcdGlmICggZGVsdGFUaW1lID49IDAgKSB7XG5cblx0XHRcdFx0XHRsb29wQ291bnQgPSAwO1xuXG5cdFx0XHRcdFx0dGhpcy5fc2V0RW5kaW5ncyggdHJ1ZSwgdGhpcy5yZXBldGl0aW9ucyA9PT0gMCwgcGluZ1BvbmcgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0Ly8gd2hlbiBsb29waW5nIGluIHJldmVyc2UgZGlyZWN0aW9uLCB0aGUgaW5pdGlhbFxuXHRcdFx0XHRcdC8vIHRyYW5zaXRpb24gdGhyb3VnaCB6ZXJvIGNvdW50cyBhcyBhIHJlcGV0aXRpb24sXG5cdFx0XHRcdFx0Ly8gc28gbGVhdmUgbG9vcENvdW50IGF0IC0xXG5cblx0XHRcdFx0XHR0aGlzLl9zZXRFbmRpbmdzKCB0aGlzLnJlcGV0aXRpb25zID09PSAwLCB0cnVlLCBwaW5nUG9uZyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHRpbWUgPj0gZHVyYXRpb24gfHwgdGltZSA8IDAgKSB7XG5cblx0XHRcdFx0Ly8gd3JhcCBhcm91bmRcblxuXHRcdFx0XHRjb25zdCBsb29wRGVsdGEgPSBNYXRoLmZsb29yKCB0aW1lIC8gZHVyYXRpb24gKTsgLy8gc2lnbmVkXG5cdFx0XHRcdHRpbWUgLT0gZHVyYXRpb24gKiBsb29wRGVsdGE7XG5cblx0XHRcdFx0bG9vcENvdW50ICs9IE1hdGguYWJzKCBsb29wRGVsdGEgKTtcblxuXHRcdFx0XHRjb25zdCBwZW5kaW5nID0gdGhpcy5yZXBldGl0aW9ucyAtIGxvb3BDb3VudDtcblxuXHRcdFx0XHRpZiAoIHBlbmRpbmcgPD0gMCApIHtcblxuXHRcdFx0XHRcdC8vIGhhdmUgdG8gc3RvcCAoc3dpdGNoIHN0YXRlLCBjbGFtcCB0aW1lLCBmaXJlIGV2ZW50KVxuXG5cdFx0XHRcdFx0aWYgKCB0aGlzLmNsYW1wV2hlbkZpbmlzaGVkICkgdGhpcy5wYXVzZWQgPSB0cnVlO1xuXHRcdFx0XHRcdGVsc2UgdGhpcy5lbmFibGVkID0gZmFsc2U7XG5cblx0XHRcdFx0XHR0aW1lID0gZGVsdGFUaW1lID4gMCA/IGR1cmF0aW9uIDogMDtcblxuXHRcdFx0XHRcdHRoaXMudGltZSA9IHRpbWU7XG5cblx0XHRcdFx0XHR0aGlzLl9taXhlci5kaXNwYXRjaEV2ZW50KCB7XG5cdFx0XHRcdFx0XHR0eXBlOiAnZmluaXNoZWQnLCBhY3Rpb246IHRoaXMsXG5cdFx0XHRcdFx0XHRkaXJlY3Rpb246IGRlbHRhVGltZSA+IDAgPyAxIDogLSAxXG5cdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBrZWVwIHJ1bm5pbmdcblxuXHRcdFx0XHRcdGlmICggcGVuZGluZyA9PT0gMSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gZW50ZXJpbmcgdGhlIGxhc3Qgcm91bmRcblxuXHRcdFx0XHRcdFx0Y29uc3QgYXRTdGFydCA9IGRlbHRhVGltZSA8IDA7XG5cdFx0XHRcdFx0XHR0aGlzLl9zZXRFbmRpbmdzKCBhdFN0YXJ0LCAhIGF0U3RhcnQsIHBpbmdQb25nICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHR0aGlzLl9zZXRFbmRpbmdzKCBmYWxzZSwgZmFsc2UsIHBpbmdQb25nICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHR0aGlzLl9sb29wQ291bnQgPSBsb29wQ291bnQ7XG5cblx0XHRcdFx0XHR0aGlzLnRpbWUgPSB0aW1lO1xuXG5cdFx0XHRcdFx0dGhpcy5fbWl4ZXIuZGlzcGF0Y2hFdmVudCgge1xuXHRcdFx0XHRcdFx0dHlwZTogJ2xvb3AnLCBhY3Rpb246IHRoaXMsIGxvb3BEZWx0YTogbG9vcERlbHRhXG5cdFx0XHRcdFx0fSApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHR0aGlzLnRpbWUgPSB0aW1lO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggcGluZ1BvbmcgJiYgKCBsb29wQ291bnQgJiAxICkgPT09IDEgKSB7XG5cblx0XHRcdFx0Ly8gaW52ZXJ0IHRpbWUgZm9yIHRoZSBcInBvbmcgcm91bmRcIlxuXG5cdFx0XHRcdHJldHVybiBkdXJhdGlvbiAtIHRpbWU7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdHJldHVybiB0aW1lO1xuXG5cdH1cblxuXHRfc2V0RW5kaW5ncyggYXRTdGFydCwgYXRFbmQsIHBpbmdQb25nICkge1xuXG5cdFx0Y29uc3Qgc2V0dGluZ3MgPSB0aGlzLl9pbnRlcnBvbGFudFNldHRpbmdzO1xuXG5cdFx0aWYgKCBwaW5nUG9uZyApIHtcblxuXHRcdFx0c2V0dGluZ3MuZW5kaW5nU3RhcnQgPSBaZXJvU2xvcGVFbmRpbmc7XG5cdFx0XHRzZXR0aW5ncy5lbmRpbmdFbmQgPSBaZXJvU2xvcGVFbmRpbmc7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHQvLyBhc3N1bWluZyBmb3IgTG9vcE9uY2UgYXRTdGFydCA9PSBhdEVuZCA9PSB0cnVlXG5cblx0XHRcdGlmICggYXRTdGFydCApIHtcblxuXHRcdFx0XHRzZXR0aW5ncy5lbmRpbmdTdGFydCA9IHRoaXMuemVyb1Nsb3BlQXRTdGFydCA/IFplcm9TbG9wZUVuZGluZyA6IFplcm9DdXJ2YXR1cmVFbmRpbmc7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0c2V0dGluZ3MuZW5kaW5nU3RhcnQgPSBXcmFwQXJvdW5kRW5kaW5nO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggYXRFbmQgKSB7XG5cblx0XHRcdFx0c2V0dGluZ3MuZW5kaW5nRW5kID0gdGhpcy56ZXJvU2xvcGVBdEVuZCA/IFplcm9TbG9wZUVuZGluZyA6IFplcm9DdXJ2YXR1cmVFbmRpbmc7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0c2V0dGluZ3MuZW5kaW5nRW5kIFx0ID0gV3JhcEFyb3VuZEVuZGluZztcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdH1cblxuXHRfc2NoZWR1bGVGYWRpbmcoIGR1cmF0aW9uLCB3ZWlnaHROb3csIHdlaWdodFRoZW4gKSB7XG5cblx0XHRjb25zdCBtaXhlciA9IHRoaXMuX21peGVyLCBub3cgPSBtaXhlci50aW1lO1xuXHRcdGxldCBpbnRlcnBvbGFudCA9IHRoaXMuX3dlaWdodEludGVycG9sYW50O1xuXG5cdFx0aWYgKCBpbnRlcnBvbGFudCA9PT0gbnVsbCApIHtcblxuXHRcdFx0aW50ZXJwb2xhbnQgPSBtaXhlci5fbGVuZENvbnRyb2xJbnRlcnBvbGFudCgpO1xuXHRcdFx0dGhpcy5fd2VpZ2h0SW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudDtcblxuXHRcdH1cblxuXHRcdGNvbnN0IHRpbWVzID0gaW50ZXJwb2xhbnQucGFyYW1ldGVyUG9zaXRpb25zLFxuXHRcdFx0dmFsdWVzID0gaW50ZXJwb2xhbnQuc2FtcGxlVmFsdWVzO1xuXG5cdFx0dGltZXNbIDAgXSA9IG5vdztcblx0XHR2YWx1ZXNbIDAgXSA9IHdlaWdodE5vdztcblx0XHR0aW1lc1sgMSBdID0gbm93ICsgZHVyYXRpb247XG5cdFx0dmFsdWVzWyAxIF0gPSB3ZWlnaHRUaGVuO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG59XG5cbmNvbnN0IF9jb250cm9sSW50ZXJwb2xhbnRzUmVzdWx0QnVmZmVyID0gbmV3IEZsb2F0MzJBcnJheSggMSApO1xuXG5cbmNsYXNzIEFuaW1hdGlvbk1peGVyIGV4dGVuZHMgRXZlbnREaXNwYXRjaGVyIHtcblxuXHRjb25zdHJ1Y3Rvciggcm9vdCApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLl9yb290ID0gcm9vdDtcblx0XHR0aGlzLl9pbml0TWVtb3J5TWFuYWdlcigpO1xuXHRcdHRoaXMuX2FjY3VJbmRleCA9IDA7XG5cdFx0dGhpcy50aW1lID0gMDtcblx0XHR0aGlzLnRpbWVTY2FsZSA9IDEuMDtcblxuXHR9XG5cblx0X2JpbmRBY3Rpb24oIGFjdGlvbiwgcHJvdG90eXBlQWN0aW9uICkge1xuXG5cdFx0Y29uc3Qgcm9vdCA9IGFjdGlvbi5fbG9jYWxSb290IHx8IHRoaXMuX3Jvb3QsXG5cdFx0XHR0cmFja3MgPSBhY3Rpb24uX2NsaXAudHJhY2tzLFxuXHRcdFx0blRyYWNrcyA9IHRyYWNrcy5sZW5ndGgsXG5cdFx0XHRiaW5kaW5ncyA9IGFjdGlvbi5fcHJvcGVydHlCaW5kaW5ncyxcblx0XHRcdGludGVycG9sYW50cyA9IGFjdGlvbi5faW50ZXJwb2xhbnRzLFxuXHRcdFx0cm9vdFV1aWQgPSByb290LnV1aWQsXG5cdFx0XHRiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZTtcblxuXHRcdGxldCBiaW5kaW5nc0J5TmFtZSA9IGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdO1xuXG5cdFx0aWYgKCBiaW5kaW5nc0J5TmFtZSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRiaW5kaW5nc0J5TmFtZSA9IHt9O1xuXHRcdFx0YmluZGluZ3NCeVJvb3RbIHJvb3RVdWlkIF0gPSBiaW5kaW5nc0J5TmFtZTtcblxuXHRcdH1cblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gblRyYWNrczsgKysgaSApIHtcblxuXHRcdFx0Y29uc3QgdHJhY2sgPSB0cmFja3NbIGkgXSxcblx0XHRcdFx0dHJhY2tOYW1lID0gdHJhY2submFtZTtcblxuXHRcdFx0bGV0IGJpbmRpbmcgPSBiaW5kaW5nc0J5TmFtZVsgdHJhY2tOYW1lIF07XG5cblx0XHRcdGlmICggYmluZGluZyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdCsrIGJpbmRpbmcucmVmZXJlbmNlQ291bnQ7XG5cdFx0XHRcdGJpbmRpbmdzWyBpIF0gPSBiaW5kaW5nO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGJpbmRpbmcgPSBiaW5kaW5nc1sgaSBdO1xuXG5cdFx0XHRcdGlmICggYmluZGluZyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdFx0Ly8gZXhpc3RpbmcgYmluZGluZywgbWFrZSBzdXJlIHRoZSBjYWNoZSBrbm93c1xuXG5cdFx0XHRcdFx0aWYgKCBiaW5kaW5nLl9jYWNoZUluZGV4ID09PSBudWxsICkge1xuXG5cdFx0XHRcdFx0XHQrKyBiaW5kaW5nLnJlZmVyZW5jZUNvdW50O1xuXHRcdFx0XHRcdFx0dGhpcy5fYWRkSW5hY3RpdmVCaW5kaW5nKCBiaW5kaW5nLCByb290VXVpZCwgdHJhY2tOYW1lICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRjb250aW51ZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0Y29uc3QgcGF0aCA9IHByb3RvdHlwZUFjdGlvbiAmJiBwcm90b3R5cGVBY3Rpb24uXG5cdFx0XHRcdFx0X3Byb3BlcnR5QmluZGluZ3NbIGkgXS5iaW5kaW5nLnBhcnNlZFBhdGg7XG5cblx0XHRcdFx0YmluZGluZyA9IG5ldyBQcm9wZXJ0eU1peGVyKFxuXHRcdFx0XHRcdFByb3BlcnR5QmluZGluZy5jcmVhdGUoIHJvb3QsIHRyYWNrTmFtZSwgcGF0aCApLFxuXHRcdFx0XHRcdHRyYWNrLlZhbHVlVHlwZU5hbWUsIHRyYWNrLmdldFZhbHVlU2l6ZSgpICk7XG5cblx0XHRcdFx0KysgYmluZGluZy5yZWZlcmVuY2VDb3VudDtcblx0XHRcdFx0dGhpcy5fYWRkSW5hY3RpdmVCaW5kaW5nKCBiaW5kaW5nLCByb290VXVpZCwgdHJhY2tOYW1lICk7XG5cblx0XHRcdFx0YmluZGluZ3NbIGkgXSA9IGJpbmRpbmc7XG5cblx0XHRcdH1cblxuXHRcdFx0aW50ZXJwb2xhbnRzWyBpIF0ucmVzdWx0QnVmZmVyID0gYmluZGluZy5idWZmZXI7XG5cblx0XHR9XG5cblx0fVxuXG5cdF9hY3RpdmF0ZUFjdGlvbiggYWN0aW9uICkge1xuXG5cdFx0aWYgKCAhIHRoaXMuX2lzQWN0aXZlQWN0aW9uKCBhY3Rpb24gKSApIHtcblxuXHRcdFx0aWYgKCBhY3Rpb24uX2NhY2hlSW5kZXggPT09IG51bGwgKSB7XG5cblx0XHRcdFx0Ly8gdGhpcyBhY3Rpb24gaGFzIGJlZW4gZm9yZ290dGVuIGJ5IHRoZSBjYWNoZSwgYnV0IHRoZSB1c2VyXG5cdFx0XHRcdC8vIGFwcGVhcnMgdG8gYmUgc3RpbGwgdXNpbmcgaXQgLT4gcmViaW5kXG5cblx0XHRcdFx0Y29uc3Qgcm9vdFV1aWQgPSAoIGFjdGlvbi5fbG9jYWxSb290IHx8IHRoaXMuX3Jvb3QgKS51dWlkLFxuXHRcdFx0XHRcdGNsaXBVdWlkID0gYWN0aW9uLl9jbGlwLnV1aWQsXG5cdFx0XHRcdFx0YWN0aW9uc0ZvckNsaXAgPSB0aGlzLl9hY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xuXG5cdFx0XHRcdHRoaXMuX2JpbmRBY3Rpb24oIGFjdGlvbixcblx0XHRcdFx0XHRhY3Rpb25zRm9yQ2xpcCAmJiBhY3Rpb25zRm9yQ2xpcC5rbm93bkFjdGlvbnNbIDAgXSApO1xuXG5cdFx0XHRcdHRoaXMuX2FkZEluYWN0aXZlQWN0aW9uKCBhY3Rpb24sIGNsaXBVdWlkLCByb290VXVpZCApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbnN0IGJpbmRpbmdzID0gYWN0aW9uLl9wcm9wZXJ0eUJpbmRpbmdzO1xuXG5cdFx0XHQvLyBpbmNyZW1lbnQgcmVmZXJlbmNlIGNvdW50cyAvIHNvcnQgb3V0IHN0YXRlXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBiaW5kaW5ncy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdFx0Y29uc3QgYmluZGluZyA9IGJpbmRpbmdzWyBpIF07XG5cblx0XHRcdFx0aWYgKCBiaW5kaW5nLnVzZUNvdW50ICsrID09PSAwICkge1xuXG5cdFx0XHRcdFx0dGhpcy5fbGVuZEJpbmRpbmcoIGJpbmRpbmcgKTtcblx0XHRcdFx0XHRiaW5kaW5nLnNhdmVPcmlnaW5hbFN0YXRlKCk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHRcdHRoaXMuX2xlbmRBY3Rpb24oIGFjdGlvbiApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRfZGVhY3RpdmF0ZUFjdGlvbiggYWN0aW9uICkge1xuXG5cdFx0aWYgKCB0aGlzLl9pc0FjdGl2ZUFjdGlvbiggYWN0aW9uICkgKSB7XG5cblx0XHRcdGNvbnN0IGJpbmRpbmdzID0gYWN0aW9uLl9wcm9wZXJ0eUJpbmRpbmdzO1xuXG5cdFx0XHQvLyBkZWNyZW1lbnQgcmVmZXJlbmNlIGNvdW50cyAvIHNvcnQgb3V0IHN0YXRlXG5cdFx0XHRmb3IgKCBsZXQgaSA9IDAsIG4gPSBiaW5kaW5ncy5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdFx0Y29uc3QgYmluZGluZyA9IGJpbmRpbmdzWyBpIF07XG5cblx0XHRcdFx0aWYgKCAtLSBiaW5kaW5nLnVzZUNvdW50ID09PSAwICkge1xuXG5cdFx0XHRcdFx0YmluZGluZy5yZXN0b3JlT3JpZ2luYWxTdGF0ZSgpO1xuXHRcdFx0XHRcdHRoaXMuX3Rha2VCYWNrQmluZGluZyggYmluZGluZyApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHR0aGlzLl90YWtlQmFja0FjdGlvbiggYWN0aW9uICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdC8vIE1lbW9yeSBtYW5hZ2VyXG5cblx0X2luaXRNZW1vcnlNYW5hZ2VyKCkge1xuXG5cdFx0dGhpcy5fYWN0aW9ucyA9IFtdOyAvLyAnbkFjdGl2ZUFjdGlvbnMnIGZvbGxvd2VkIGJ5IGluYWN0aXZlIG9uZXNcblx0XHR0aGlzLl9uQWN0aXZlQWN0aW9ucyA9IDA7XG5cblx0XHR0aGlzLl9hY3Rpb25zQnlDbGlwID0ge307XG5cdFx0Ly8gaW5zaWRlOlxuXHRcdC8vIHtcblx0XHQvLyBcdGtub3duQWN0aW9uczogQXJyYXk8IEFuaW1hdGlvbkFjdGlvbiA+IC0gdXNlZCBhcyBwcm90b3R5cGVzXG5cdFx0Ly8gXHRhY3Rpb25CeVJvb3Q6IEFuaW1hdGlvbkFjdGlvbiAtIGxvb2t1cFxuXHRcdC8vIH1cblxuXG5cdFx0dGhpcy5fYmluZGluZ3MgPSBbXTsgLy8gJ25BY3RpdmVCaW5kaW5ncycgZm9sbG93ZWQgYnkgaW5hY3RpdmUgb25lc1xuXHRcdHRoaXMuX25BY3RpdmVCaW5kaW5ncyA9IDA7XG5cblx0XHR0aGlzLl9iaW5kaW5nc0J5Um9vdEFuZE5hbWUgPSB7fTsgLy8gaW5zaWRlOiBNYXA8IG5hbWUsIFByb3BlcnR5TWl4ZXIgPlxuXG5cblx0XHR0aGlzLl9jb250cm9sSW50ZXJwb2xhbnRzID0gW107IC8vIHNhbWUgZ2FtZSBhcyBhYm92ZVxuXHRcdHRoaXMuX25BY3RpdmVDb250cm9sSW50ZXJwb2xhbnRzID0gMDtcblxuXHRcdGNvbnN0IHNjb3BlID0gdGhpcztcblxuXHRcdHRoaXMuc3RhdHMgPSB7XG5cblx0XHRcdGFjdGlvbnM6IHtcblx0XHRcdFx0Z2V0IHRvdGFsKCkge1xuXG5cdFx0XHRcdFx0cmV0dXJuIHNjb3BlLl9hY3Rpb25zLmxlbmd0aDtcblxuXHRcdFx0XHR9LFxuXHRcdFx0XHRnZXQgaW5Vc2UoKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gc2NvcGUuX25BY3RpdmVBY3Rpb25zO1xuXG5cdFx0XHRcdH1cblx0XHRcdH0sXG5cdFx0XHRiaW5kaW5nczoge1xuXHRcdFx0XHRnZXQgdG90YWwoKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gc2NvcGUuX2JpbmRpbmdzLmxlbmd0aDtcblxuXHRcdFx0XHR9LFxuXHRcdFx0XHRnZXQgaW5Vc2UoKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gc2NvcGUuX25BY3RpdmVCaW5kaW5ncztcblxuXHRcdFx0XHR9XG5cdFx0XHR9LFxuXHRcdFx0Y29udHJvbEludGVycG9sYW50czoge1xuXHRcdFx0XHRnZXQgdG90YWwoKSB7XG5cblx0XHRcdFx0XHRyZXR1cm4gc2NvcGUuX2NvbnRyb2xJbnRlcnBvbGFudHMubGVuZ3RoO1xuXG5cdFx0XHRcdH0sXG5cdFx0XHRcdGdldCBpblVzZSgpIHtcblxuXHRcdFx0XHRcdHJldHVybiBzY29wZS5fbkFjdGl2ZUNvbnRyb2xJbnRlcnBvbGFudHM7XG5cblx0XHRcdFx0fVxuXHRcdFx0fVxuXG5cdFx0fTtcblxuXHR9XG5cblx0Ly8gTWVtb3J5IG1hbmFnZW1lbnQgZm9yIEFuaW1hdGlvbkFjdGlvbiBvYmplY3RzXG5cblx0X2lzQWN0aXZlQWN0aW9uKCBhY3Rpb24gKSB7XG5cblx0XHRjb25zdCBpbmRleCA9IGFjdGlvbi5fY2FjaGVJbmRleDtcblx0XHRyZXR1cm4gaW5kZXggIT09IG51bGwgJiYgaW5kZXggPCB0aGlzLl9uQWN0aXZlQWN0aW9ucztcblxuXHR9XG5cblx0X2FkZEluYWN0aXZlQWN0aW9uKCBhY3Rpb24sIGNsaXBVdWlkLCByb290VXVpZCApIHtcblxuXHRcdGNvbnN0IGFjdGlvbnMgPSB0aGlzLl9hY3Rpb25zLFxuXHRcdFx0YWN0aW9uc0J5Q2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXA7XG5cblx0XHRsZXQgYWN0aW9uc0ZvckNsaXAgPSBhY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xuXG5cdFx0aWYgKCBhY3Rpb25zRm9yQ2xpcCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRhY3Rpb25zRm9yQ2xpcCA9IHtcblxuXHRcdFx0XHRrbm93bkFjdGlvbnM6IFsgYWN0aW9uIF0sXG5cdFx0XHRcdGFjdGlvbkJ5Um9vdDoge31cblxuXHRcdFx0fTtcblxuXHRcdFx0YWN0aW9uLl9ieUNsaXBDYWNoZUluZGV4ID0gMDtcblxuXHRcdFx0YWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXSA9IGFjdGlvbnNGb3JDbGlwO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc3Qga25vd25BY3Rpb25zID0gYWN0aW9uc0ZvckNsaXAua25vd25BY3Rpb25zO1xuXG5cdFx0XHRhY3Rpb24uX2J5Q2xpcENhY2hlSW5kZXggPSBrbm93bkFjdGlvbnMubGVuZ3RoO1xuXHRcdFx0a25vd25BY3Rpb25zLnB1c2goIGFjdGlvbiApO1xuXG5cdFx0fVxuXG5cdFx0YWN0aW9uLl9jYWNoZUluZGV4ID0gYWN0aW9ucy5sZW5ndGg7XG5cdFx0YWN0aW9ucy5wdXNoKCBhY3Rpb24gKTtcblxuXHRcdGFjdGlvbnNGb3JDbGlwLmFjdGlvbkJ5Um9vdFsgcm9vdFV1aWQgXSA9IGFjdGlvbjtcblxuXHR9XG5cblx0X3JlbW92ZUluYWN0aXZlQWN0aW9uKCBhY3Rpb24gKSB7XG5cblx0XHRjb25zdCBhY3Rpb25zID0gdGhpcy5fYWN0aW9ucyxcblx0XHRcdGxhc3RJbmFjdGl2ZUFjdGlvbiA9IGFjdGlvbnNbIGFjdGlvbnMubGVuZ3RoIC0gMSBdLFxuXHRcdFx0Y2FjaGVJbmRleCA9IGFjdGlvbi5fY2FjaGVJbmRleDtcblxuXHRcdGxhc3RJbmFjdGl2ZUFjdGlvbi5fY2FjaGVJbmRleCA9IGNhY2hlSW5kZXg7XG5cdFx0YWN0aW9uc1sgY2FjaGVJbmRleCBdID0gbGFzdEluYWN0aXZlQWN0aW9uO1xuXHRcdGFjdGlvbnMucG9wKCk7XG5cblx0XHRhY3Rpb24uX2NhY2hlSW5kZXggPSBudWxsO1xuXG5cblx0XHRjb25zdCBjbGlwVXVpZCA9IGFjdGlvbi5fY2xpcC51dWlkLFxuXHRcdFx0YWN0aW9uc0J5Q2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXAsXG5cdFx0XHRhY3Rpb25zRm9yQ2xpcCA9IGFjdGlvbnNCeUNsaXBbIGNsaXBVdWlkIF0sXG5cdFx0XHRrbm93bkFjdGlvbnNGb3JDbGlwID0gYWN0aW9uc0ZvckNsaXAua25vd25BY3Rpb25zLFxuXG5cdFx0XHRsYXN0S25vd25BY3Rpb24gPVxuXHRcdFx0XHRrbm93bkFjdGlvbnNGb3JDbGlwWyBrbm93bkFjdGlvbnNGb3JDbGlwLmxlbmd0aCAtIDEgXSxcblxuXHRcdFx0YnlDbGlwQ2FjaGVJbmRleCA9IGFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleDtcblxuXHRcdGxhc3RLbm93bkFjdGlvbi5fYnlDbGlwQ2FjaGVJbmRleCA9IGJ5Q2xpcENhY2hlSW5kZXg7XG5cdFx0a25vd25BY3Rpb25zRm9yQ2xpcFsgYnlDbGlwQ2FjaGVJbmRleCBdID0gbGFzdEtub3duQWN0aW9uO1xuXHRcdGtub3duQWN0aW9uc0ZvckNsaXAucG9wKCk7XG5cblx0XHRhY3Rpb24uX2J5Q2xpcENhY2hlSW5kZXggPSBudWxsO1xuXG5cblx0XHRjb25zdCBhY3Rpb25CeVJvb3QgPSBhY3Rpb25zRm9yQ2xpcC5hY3Rpb25CeVJvb3QsXG5cdFx0XHRyb290VXVpZCA9ICggYWN0aW9uLl9sb2NhbFJvb3QgfHwgdGhpcy5fcm9vdCApLnV1aWQ7XG5cblx0XHRkZWxldGUgYWN0aW9uQnlSb290WyByb290VXVpZCBdO1xuXG5cdFx0aWYgKCBrbm93bkFjdGlvbnNGb3JDbGlwLmxlbmd0aCA9PT0gMCApIHtcblxuXHRcdFx0ZGVsZXRlIGFjdGlvbnNCeUNsaXBbIGNsaXBVdWlkIF07XG5cblx0XHR9XG5cblx0XHR0aGlzLl9yZW1vdmVJbmFjdGl2ZUJpbmRpbmdzRm9yQWN0aW9uKCBhY3Rpb24gKTtcblxuXHR9XG5cblx0X3JlbW92ZUluYWN0aXZlQmluZGluZ3NGb3JBY3Rpb24oIGFjdGlvbiApIHtcblxuXHRcdGNvbnN0IGJpbmRpbmdzID0gYWN0aW9uLl9wcm9wZXJ0eUJpbmRpbmdzO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBuID0gYmluZGluZ3MubGVuZ3RoOyBpICE9PSBuOyArKyBpICkge1xuXG5cdFx0XHRjb25zdCBiaW5kaW5nID0gYmluZGluZ3NbIGkgXTtcblxuXHRcdFx0aWYgKCAtLSBiaW5kaW5nLnJlZmVyZW5jZUNvdW50ID09PSAwICkge1xuXG5cdFx0XHRcdHRoaXMuX3JlbW92ZUluYWN0aXZlQmluZGluZyggYmluZGluZyApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0fVxuXG5cdF9sZW5kQWN0aW9uKCBhY3Rpb24gKSB7XG5cblx0XHQvLyBbIGFjdGl2ZSBhY3Rpb25zIHwgIGluYWN0aXZlIGFjdGlvbnMgIF1cblx0XHQvLyBbICBhY3RpdmUgYWN0aW9ucyA+fCBpbmFjdGl2ZSBhY3Rpb25zIF1cblx0XHQvLyAgICAgICAgICAgICAgICAgcyAgICAgICAgYVxuXHRcdC8vICAgICAgICAgICAgICAgICAgPC1zd2FwLT5cblx0XHQvLyAgICAgICAgICAgICAgICAgYSAgICAgICAgc1xuXG5cdFx0Y29uc3QgYWN0aW9ucyA9IHRoaXMuX2FjdGlvbnMsXG5cdFx0XHRwcmV2SW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXgsXG5cblx0XHRcdGxhc3RBY3RpdmVJbmRleCA9IHRoaXMuX25BY3RpdmVBY3Rpb25zICsrLFxuXG5cdFx0XHRmaXJzdEluYWN0aXZlQWN0aW9uID0gYWN0aW9uc1sgbGFzdEFjdGl2ZUluZGV4IF07XG5cblx0XHRhY3Rpb24uX2NhY2hlSW5kZXggPSBsYXN0QWN0aXZlSW5kZXg7XG5cdFx0YWN0aW9uc1sgbGFzdEFjdGl2ZUluZGV4IF0gPSBhY3Rpb247XG5cblx0XHRmaXJzdEluYWN0aXZlQWN0aW9uLl9jYWNoZUluZGV4ID0gcHJldkluZGV4O1xuXHRcdGFjdGlvbnNbIHByZXZJbmRleCBdID0gZmlyc3RJbmFjdGl2ZUFjdGlvbjtcblxuXHR9XG5cblx0X3Rha2VCYWNrQWN0aW9uKCBhY3Rpb24gKSB7XG5cblx0XHQvLyBbICBhY3RpdmUgYWN0aW9ucyAgfCBpbmFjdGl2ZSBhY3Rpb25zIF1cblx0XHQvLyBbIGFjdGl2ZSBhY3Rpb25zIHw8IGluYWN0aXZlIGFjdGlvbnMgIF1cblx0XHQvLyAgICAgICAgYSAgICAgICAgc1xuXHRcdC8vICAgICAgICAgPC1zd2FwLT5cblx0XHQvLyAgICAgICAgcyAgICAgICAgYVxuXG5cdFx0Y29uc3QgYWN0aW9ucyA9IHRoaXMuX2FjdGlvbnMsXG5cdFx0XHRwcmV2SW5kZXggPSBhY3Rpb24uX2NhY2hlSW5kZXgsXG5cblx0XHRcdGZpcnN0SW5hY3RpdmVJbmRleCA9IC0tIHRoaXMuX25BY3RpdmVBY3Rpb25zLFxuXG5cdFx0XHRsYXN0QWN0aXZlQWN0aW9uID0gYWN0aW9uc1sgZmlyc3RJbmFjdGl2ZUluZGV4IF07XG5cblx0XHRhY3Rpb24uX2NhY2hlSW5kZXggPSBmaXJzdEluYWN0aXZlSW5kZXg7XG5cdFx0YWN0aW9uc1sgZmlyc3RJbmFjdGl2ZUluZGV4IF0gPSBhY3Rpb247XG5cblx0XHRsYXN0QWN0aXZlQWN0aW9uLl9jYWNoZUluZGV4ID0gcHJldkluZGV4O1xuXHRcdGFjdGlvbnNbIHByZXZJbmRleCBdID0gbGFzdEFjdGl2ZUFjdGlvbjtcblxuXHR9XG5cblx0Ly8gTWVtb3J5IG1hbmFnZW1lbnQgZm9yIFByb3BlcnR5TWl4ZXIgb2JqZWN0c1xuXG5cdF9hZGRJbmFjdGl2ZUJpbmRpbmcoIGJpbmRpbmcsIHJvb3RVdWlkLCB0cmFja05hbWUgKSB7XG5cblx0XHRjb25zdCBiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZSxcblx0XHRcdGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3M7XG5cblx0XHRsZXQgYmluZGluZ0J5TmFtZSA9IGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdO1xuXG5cdFx0aWYgKCBiaW5kaW5nQnlOYW1lID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGJpbmRpbmdCeU5hbWUgPSB7fTtcblx0XHRcdGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdID0gYmluZGluZ0J5TmFtZTtcblxuXHRcdH1cblxuXHRcdGJpbmRpbmdCeU5hbWVbIHRyYWNrTmFtZSBdID0gYmluZGluZztcblxuXHRcdGJpbmRpbmcuX2NhY2hlSW5kZXggPSBiaW5kaW5ncy5sZW5ndGg7XG5cdFx0YmluZGluZ3MucHVzaCggYmluZGluZyApO1xuXG5cdH1cblxuXHRfcmVtb3ZlSW5hY3RpdmVCaW5kaW5nKCBiaW5kaW5nICkge1xuXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcblx0XHRcdHByb3BCaW5kaW5nID0gYmluZGluZy5iaW5kaW5nLFxuXHRcdFx0cm9vdFV1aWQgPSBwcm9wQmluZGluZy5yb290Tm9kZS51dWlkLFxuXHRcdFx0dHJhY2tOYW1lID0gcHJvcEJpbmRpbmcucGF0aCxcblx0XHRcdGJpbmRpbmdzQnlSb290ID0gdGhpcy5fYmluZGluZ3NCeVJvb3RBbmROYW1lLFxuXHRcdFx0YmluZGluZ0J5TmFtZSA9IGJpbmRpbmdzQnlSb290WyByb290VXVpZCBdLFxuXG5cdFx0XHRsYXN0SW5hY3RpdmVCaW5kaW5nID0gYmluZGluZ3NbIGJpbmRpbmdzLmxlbmd0aCAtIDEgXSxcblx0XHRcdGNhY2hlSW5kZXggPSBiaW5kaW5nLl9jYWNoZUluZGV4O1xuXG5cdFx0bGFzdEluYWN0aXZlQmluZGluZy5fY2FjaGVJbmRleCA9IGNhY2hlSW5kZXg7XG5cdFx0YmluZGluZ3NbIGNhY2hlSW5kZXggXSA9IGxhc3RJbmFjdGl2ZUJpbmRpbmc7XG5cdFx0YmluZGluZ3MucG9wKCk7XG5cblx0XHRkZWxldGUgYmluZGluZ0J5TmFtZVsgdHJhY2tOYW1lIF07XG5cblx0XHRpZiAoIE9iamVjdC5rZXlzKCBiaW5kaW5nQnlOYW1lICkubGVuZ3RoID09PSAwICkge1xuXG5cdFx0XHRkZWxldGUgYmluZGluZ3NCeVJvb3RbIHJvb3RVdWlkIF07XG5cblx0XHR9XG5cblx0fVxuXG5cdF9sZW5kQmluZGluZyggYmluZGluZyApIHtcblxuXHRcdGNvbnN0IGJpbmRpbmdzID0gdGhpcy5fYmluZGluZ3MsXG5cdFx0XHRwcmV2SW5kZXggPSBiaW5kaW5nLl9jYWNoZUluZGV4LFxuXG5cdFx0XHRsYXN0QWN0aXZlSW5kZXggPSB0aGlzLl9uQWN0aXZlQmluZGluZ3MgKyssXG5cblx0XHRcdGZpcnN0SW5hY3RpdmVCaW5kaW5nID0gYmluZGluZ3NbIGxhc3RBY3RpdmVJbmRleCBdO1xuXG5cdFx0YmluZGluZy5fY2FjaGVJbmRleCA9IGxhc3RBY3RpdmVJbmRleDtcblx0XHRiaW5kaW5nc1sgbGFzdEFjdGl2ZUluZGV4IF0gPSBiaW5kaW5nO1xuXG5cdFx0Zmlyc3RJbmFjdGl2ZUJpbmRpbmcuX2NhY2hlSW5kZXggPSBwcmV2SW5kZXg7XG5cdFx0YmluZGluZ3NbIHByZXZJbmRleCBdID0gZmlyc3RJbmFjdGl2ZUJpbmRpbmc7XG5cblx0fVxuXG5cdF90YWtlQmFja0JpbmRpbmcoIGJpbmRpbmcgKSB7XG5cblx0XHRjb25zdCBiaW5kaW5ncyA9IHRoaXMuX2JpbmRpbmdzLFxuXHRcdFx0cHJldkluZGV4ID0gYmluZGluZy5fY2FjaGVJbmRleCxcblxuXHRcdFx0Zmlyc3RJbmFjdGl2ZUluZGV4ID0gLS0gdGhpcy5fbkFjdGl2ZUJpbmRpbmdzLFxuXG5cdFx0XHRsYXN0QWN0aXZlQmluZGluZyA9IGJpbmRpbmdzWyBmaXJzdEluYWN0aXZlSW5kZXggXTtcblxuXHRcdGJpbmRpbmcuX2NhY2hlSW5kZXggPSBmaXJzdEluYWN0aXZlSW5kZXg7XG5cdFx0YmluZGluZ3NbIGZpcnN0SW5hY3RpdmVJbmRleCBdID0gYmluZGluZztcblxuXHRcdGxhc3RBY3RpdmVCaW5kaW5nLl9jYWNoZUluZGV4ID0gcHJldkluZGV4O1xuXHRcdGJpbmRpbmdzWyBwcmV2SW5kZXggXSA9IGxhc3RBY3RpdmVCaW5kaW5nO1xuXG5cdH1cblxuXG5cdC8vIE1lbW9yeSBtYW5hZ2VtZW50IG9mIEludGVycG9sYW50cyBmb3Igd2VpZ2h0IGFuZCB0aW1lIHNjYWxlXG5cblx0X2xlbmRDb250cm9sSW50ZXJwb2xhbnQoKSB7XG5cblx0XHRjb25zdCBpbnRlcnBvbGFudHMgPSB0aGlzLl9jb250cm9sSW50ZXJwb2xhbnRzLFxuXHRcdFx0bGFzdEFjdGl2ZUluZGV4ID0gdGhpcy5fbkFjdGl2ZUNvbnRyb2xJbnRlcnBvbGFudHMgKys7XG5cblx0XHRsZXQgaW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudHNbIGxhc3RBY3RpdmVJbmRleCBdO1xuXG5cdFx0aWYgKCBpbnRlcnBvbGFudCA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRpbnRlcnBvbGFudCA9IG5ldyBMaW5lYXJJbnRlcnBvbGFudChcblx0XHRcdFx0bmV3IEZsb2F0MzJBcnJheSggMiApLCBuZXcgRmxvYXQzMkFycmF5KCAyICksXG5cdFx0XHRcdDEsIF9jb250cm9sSW50ZXJwb2xhbnRzUmVzdWx0QnVmZmVyICk7XG5cblx0XHRcdGludGVycG9sYW50Ll9fY2FjaGVJbmRleCA9IGxhc3RBY3RpdmVJbmRleDtcblx0XHRcdGludGVycG9sYW50c1sgbGFzdEFjdGl2ZUluZGV4IF0gPSBpbnRlcnBvbGFudDtcblxuXHRcdH1cblxuXHRcdHJldHVybiBpbnRlcnBvbGFudDtcblxuXHR9XG5cblx0X3Rha2VCYWNrQ29udHJvbEludGVycG9sYW50KCBpbnRlcnBvbGFudCApIHtcblxuXHRcdGNvbnN0IGludGVycG9sYW50cyA9IHRoaXMuX2NvbnRyb2xJbnRlcnBvbGFudHMsXG5cdFx0XHRwcmV2SW5kZXggPSBpbnRlcnBvbGFudC5fX2NhY2hlSW5kZXgsXG5cblx0XHRcdGZpcnN0SW5hY3RpdmVJbmRleCA9IC0tIHRoaXMuX25BY3RpdmVDb250cm9sSW50ZXJwb2xhbnRzLFxuXG5cdFx0XHRsYXN0QWN0aXZlSW50ZXJwb2xhbnQgPSBpbnRlcnBvbGFudHNbIGZpcnN0SW5hY3RpdmVJbmRleCBdO1xuXG5cdFx0aW50ZXJwb2xhbnQuX19jYWNoZUluZGV4ID0gZmlyc3RJbmFjdGl2ZUluZGV4O1xuXHRcdGludGVycG9sYW50c1sgZmlyc3RJbmFjdGl2ZUluZGV4IF0gPSBpbnRlcnBvbGFudDtcblxuXHRcdGxhc3RBY3RpdmVJbnRlcnBvbGFudC5fX2NhY2hlSW5kZXggPSBwcmV2SW5kZXg7XG5cdFx0aW50ZXJwb2xhbnRzWyBwcmV2SW5kZXggXSA9IGxhc3RBY3RpdmVJbnRlcnBvbGFudDtcblxuXHR9XG5cblx0Ly8gcmV0dXJuIGFuIGFjdGlvbiBmb3IgYSBjbGlwIG9wdGlvbmFsbHkgdXNpbmcgYSBjdXN0b20gcm9vdCB0YXJnZXRcblx0Ly8gb2JqZWN0ICh0aGlzIG1ldGhvZCBhbGxvY2F0ZXMgYSBsb3Qgb2YgZHluYW1pYyBtZW1vcnkgaW4gY2FzZSBhXG5cdC8vIHByZXZpb3VzbHkgdW5rbm93biBjbGlwL3Jvb3QgY29tYmluYXRpb24gaXMgc3BlY2lmaWVkKVxuXHRjbGlwQWN0aW9uKCBjbGlwLCBvcHRpb25hbFJvb3QsIGJsZW5kTW9kZSApIHtcblxuXHRcdGNvbnN0IHJvb3QgPSBvcHRpb25hbFJvb3QgfHwgdGhpcy5fcm9vdCxcblx0XHRcdHJvb3RVdWlkID0gcm9vdC51dWlkO1xuXG5cdFx0bGV0IGNsaXBPYmplY3QgPSB0eXBlb2YgY2xpcCA9PT0gJ3N0cmluZycgPyBBbmltYXRpb25DbGlwLmZpbmRCeU5hbWUoIHJvb3QsIGNsaXAgKSA6IGNsaXA7XG5cblx0XHRjb25zdCBjbGlwVXVpZCA9IGNsaXBPYmplY3QgIT09IG51bGwgPyBjbGlwT2JqZWN0LnV1aWQgOiBjbGlwO1xuXG5cdFx0Y29uc3QgYWN0aW9uc0ZvckNsaXAgPSB0aGlzLl9hY3Rpb25zQnlDbGlwWyBjbGlwVXVpZCBdO1xuXHRcdGxldCBwcm90b3R5cGVBY3Rpb24gPSBudWxsO1xuXG5cdFx0aWYgKCBibGVuZE1vZGUgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0aWYgKCBjbGlwT2JqZWN0ICE9PSBudWxsICkge1xuXG5cdFx0XHRcdGJsZW5kTW9kZSA9IGNsaXBPYmplY3QuYmxlbmRNb2RlO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGJsZW5kTW9kZSA9IE5vcm1hbEFuaW1hdGlvbkJsZW5kTW9kZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0aWYgKCBhY3Rpb25zRm9yQ2xpcCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjb25zdCBleGlzdGluZ0FjdGlvbiA9IGFjdGlvbnNGb3JDbGlwLmFjdGlvbkJ5Um9vdFsgcm9vdFV1aWQgXTtcblxuXHRcdFx0aWYgKCBleGlzdGluZ0FjdGlvbiAhPT0gdW5kZWZpbmVkICYmIGV4aXN0aW5nQWN0aW9uLmJsZW5kTW9kZSA9PT0gYmxlbmRNb2RlICkge1xuXG5cdFx0XHRcdHJldHVybiBleGlzdGluZ0FjdGlvbjtcblxuXHRcdFx0fVxuXG5cdFx0XHQvLyB3ZSBrbm93IHRoZSBjbGlwLCBzbyB3ZSBkb24ndCBoYXZlIHRvIHBhcnNlIGFsbFxuXHRcdFx0Ly8gdGhlIGJpbmRpbmdzIGFnYWluIGJ1dCBjYW4ganVzdCBjb3B5XG5cdFx0XHRwcm90b3R5cGVBY3Rpb24gPSBhY3Rpb25zRm9yQ2xpcC5rbm93bkFjdGlvbnNbIDAgXTtcblxuXHRcdFx0Ly8gYWxzbywgdGFrZSB0aGUgY2xpcCBmcm9tIHRoZSBwcm90b3R5cGUgYWN0aW9uXG5cdFx0XHRpZiAoIGNsaXBPYmplY3QgPT09IG51bGwgKVxuXHRcdFx0XHRjbGlwT2JqZWN0ID0gcHJvdG90eXBlQWN0aW9uLl9jbGlwO1xuXG5cdFx0fVxuXG5cdFx0Ly8gY2xpcCBtdXN0IGJlIGtub3duIHdoZW4gc3BlY2lmaWVkIHZpYSBzdHJpbmdcblx0XHRpZiAoIGNsaXBPYmplY3QgPT09IG51bGwgKSByZXR1cm4gbnVsbDtcblxuXHRcdC8vIGFsbG9jYXRlIGFsbCByZXNvdXJjZXMgcmVxdWlyZWQgdG8gcnVuIGl0XG5cdFx0Y29uc3QgbmV3QWN0aW9uID0gbmV3IEFuaW1hdGlvbkFjdGlvbiggdGhpcywgY2xpcE9iamVjdCwgb3B0aW9uYWxSb290LCBibGVuZE1vZGUgKTtcblxuXHRcdHRoaXMuX2JpbmRBY3Rpb24oIG5ld0FjdGlvbiwgcHJvdG90eXBlQWN0aW9uICk7XG5cblx0XHQvLyBhbmQgbWFrZSB0aGUgYWN0aW9uIGtub3duIHRvIHRoZSBtZW1vcnkgbWFuYWdlclxuXHRcdHRoaXMuX2FkZEluYWN0aXZlQWN0aW9uKCBuZXdBY3Rpb24sIGNsaXBVdWlkLCByb290VXVpZCApO1xuXG5cdFx0cmV0dXJuIG5ld0FjdGlvbjtcblxuXHR9XG5cblx0Ly8gZ2V0IGFuIGV4aXN0aW5nIGFjdGlvblxuXHRleGlzdGluZ0FjdGlvbiggY2xpcCwgb3B0aW9uYWxSb290ICkge1xuXG5cdFx0Y29uc3Qgcm9vdCA9IG9wdGlvbmFsUm9vdCB8fCB0aGlzLl9yb290LFxuXHRcdFx0cm9vdFV1aWQgPSByb290LnV1aWQsXG5cblx0XHRcdGNsaXBPYmplY3QgPSB0eXBlb2YgY2xpcCA9PT0gJ3N0cmluZycgP1xuXHRcdFx0XHRBbmltYXRpb25DbGlwLmZpbmRCeU5hbWUoIHJvb3QsIGNsaXAgKSA6IGNsaXAsXG5cblx0XHRcdGNsaXBVdWlkID0gY2xpcE9iamVjdCA/IGNsaXBPYmplY3QudXVpZCA6IGNsaXAsXG5cblx0XHRcdGFjdGlvbnNGb3JDbGlwID0gdGhpcy5fYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXTtcblxuXHRcdGlmICggYWN0aW9uc0ZvckNsaXAgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0cmV0dXJuIGFjdGlvbnNGb3JDbGlwLmFjdGlvbkJ5Um9vdFsgcm9vdFV1aWQgXSB8fCBudWxsO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIG51bGw7XG5cblx0fVxuXG5cdC8vIGRlYWN0aXZhdGVzIGFsbCBwcmV2aW91c2x5IHNjaGVkdWxlZCBhY3Rpb25zXG5cdHN0b3BBbGxBY3Rpb24oKSB7XG5cblx0XHRjb25zdCBhY3Rpb25zID0gdGhpcy5fYWN0aW9ucyxcblx0XHRcdG5BY3Rpb25zID0gdGhpcy5fbkFjdGl2ZUFjdGlvbnM7XG5cblx0XHRmb3IgKCBsZXQgaSA9IG5BY3Rpb25zIC0gMTsgaSA+PSAwOyAtLSBpICkge1xuXG5cdFx0XHRhY3Rpb25zWyBpIF0uc3RvcCgpO1xuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIGFkdmFuY2UgdGhlIHRpbWUgYW5kIHVwZGF0ZSBhcHBseSB0aGUgYW5pbWF0aW9uXG5cdHVwZGF0ZSggZGVsdGFUaW1lICkge1xuXG5cdFx0ZGVsdGFUaW1lICo9IHRoaXMudGltZVNjYWxlO1xuXG5cdFx0Y29uc3QgYWN0aW9ucyA9IHRoaXMuX2FjdGlvbnMsXG5cdFx0XHRuQWN0aW9ucyA9IHRoaXMuX25BY3RpdmVBY3Rpb25zLFxuXG5cdFx0XHR0aW1lID0gdGhpcy50aW1lICs9IGRlbHRhVGltZSxcblx0XHRcdHRpbWVEaXJlY3Rpb24gPSBNYXRoLnNpZ24oIGRlbHRhVGltZSApLFxuXG5cdFx0XHRhY2N1SW5kZXggPSB0aGlzLl9hY2N1SW5kZXggXj0gMTtcblxuXHRcdC8vIHJ1biBhY3RpdmUgYWN0aW9uc1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpICE9PSBuQWN0aW9uczsgKysgaSApIHtcblxuXHRcdFx0Y29uc3QgYWN0aW9uID0gYWN0aW9uc1sgaSBdO1xuXG5cdFx0XHRhY3Rpb24uX3VwZGF0ZSggdGltZSwgZGVsdGFUaW1lLCB0aW1lRGlyZWN0aW9uLCBhY2N1SW5kZXggKTtcblxuXHRcdH1cblxuXHRcdC8vIHVwZGF0ZSBzY2VuZSBncmFwaFxuXG5cdFx0Y29uc3QgYmluZGluZ3MgPSB0aGlzLl9iaW5kaW5ncyxcblx0XHRcdG5CaW5kaW5ncyA9IHRoaXMuX25BY3RpdmVCaW5kaW5ncztcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSAhPT0gbkJpbmRpbmdzOyArKyBpICkge1xuXG5cdFx0XHRiaW5kaW5nc1sgaSBdLmFwcGx5KCBhY2N1SW5kZXggKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHQvLyBBbGxvd3MgeW91IHRvIHNlZWsgdG8gYSBzcGVjaWZpYyB0aW1lIGluIGFuIGFuaW1hdGlvbi5cblx0c2V0VGltZSggdGltZUluU2Vjb25kcyApIHtcblxuXHRcdHRoaXMudGltZSA9IDA7IC8vIFplcm8gb3V0IHRpbWUgYXR0cmlidXRlIGZvciBBbmltYXRpb25NaXhlciBvYmplY3Q7XG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy5fYWN0aW9ucy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuX2FjdGlvbnNbIGkgXS50aW1lID0gMDsgLy8gWmVybyBvdXQgdGltZSBhdHRyaWJ1dGUgZm9yIGFsbCBhc3NvY2lhdGVkIEFuaW1hdGlvbkFjdGlvbiBvYmplY3RzLlxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRoaXMudXBkYXRlKCB0aW1lSW5TZWNvbmRzICk7IC8vIFVwZGF0ZSB1c2VkIHRvIHNldCBleGFjdCB0aW1lLiBSZXR1cm5zIFwidGhpc1wiIEFuaW1hdGlvbk1peGVyIG9iamVjdC5cblxuXHR9XG5cblx0Ly8gcmV0dXJuIHRoaXMgbWl4ZXIncyByb290IHRhcmdldCBvYmplY3Rcblx0Z2V0Um9vdCgpIHtcblxuXHRcdHJldHVybiB0aGlzLl9yb290O1xuXG5cdH1cblxuXHQvLyBmcmVlIGFsbCByZXNvdXJjZXMgc3BlY2lmaWMgdG8gYSBwYXJ0aWN1bGFyIGNsaXBcblx0dW5jYWNoZUNsaXAoIGNsaXAgKSB7XG5cblx0XHRjb25zdCBhY3Rpb25zID0gdGhpcy5fYWN0aW9ucyxcblx0XHRcdGNsaXBVdWlkID0gY2xpcC51dWlkLFxuXHRcdFx0YWN0aW9uc0J5Q2xpcCA9IHRoaXMuX2FjdGlvbnNCeUNsaXAsXG5cdFx0XHRhY3Rpb25zRm9yQ2xpcCA9IGFjdGlvbnNCeUNsaXBbIGNsaXBVdWlkIF07XG5cblx0XHRpZiAoIGFjdGlvbnNGb3JDbGlwICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdC8vIG5vdGU6IGp1c3QgY2FsbGluZyBfcmVtb3ZlSW5hY3RpdmVBY3Rpb24gd291bGQgbWVzcyB1cCB0aGVcblx0XHRcdC8vIGl0ZXJhdGlvbiBzdGF0ZSBhbmQgYWxzbyByZXF1aXJlIHVwZGF0aW5nIHRoZSBzdGF0ZSB3ZSBjYW5cblx0XHRcdC8vIGp1c3QgdGhyb3cgYXdheVxuXG5cdFx0XHRjb25zdCBhY3Rpb25zVG9SZW1vdmUgPSBhY3Rpb25zRm9yQ2xpcC5rbm93bkFjdGlvbnM7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMCwgbiA9IGFjdGlvbnNUb1JlbW92ZS5sZW5ndGg7IGkgIT09IG47ICsrIGkgKSB7XG5cblx0XHRcdFx0Y29uc3QgYWN0aW9uID0gYWN0aW9uc1RvUmVtb3ZlWyBpIF07XG5cblx0XHRcdFx0dGhpcy5fZGVhY3RpdmF0ZUFjdGlvbiggYWN0aW9uICk7XG5cblx0XHRcdFx0Y29uc3QgY2FjaGVJbmRleCA9IGFjdGlvbi5fY2FjaGVJbmRleCxcblx0XHRcdFx0XHRsYXN0SW5hY3RpdmVBY3Rpb24gPSBhY3Rpb25zWyBhY3Rpb25zLmxlbmd0aCAtIDEgXTtcblxuXHRcdFx0XHRhY3Rpb24uX2NhY2hlSW5kZXggPSBudWxsO1xuXHRcdFx0XHRhY3Rpb24uX2J5Q2xpcENhY2hlSW5kZXggPSBudWxsO1xuXG5cdFx0XHRcdGxhc3RJbmFjdGl2ZUFjdGlvbi5fY2FjaGVJbmRleCA9IGNhY2hlSW5kZXg7XG5cdFx0XHRcdGFjdGlvbnNbIGNhY2hlSW5kZXggXSA9IGxhc3RJbmFjdGl2ZUFjdGlvbjtcblx0XHRcdFx0YWN0aW9ucy5wb3AoKTtcblxuXHRcdFx0XHR0aGlzLl9yZW1vdmVJbmFjdGl2ZUJpbmRpbmdzRm9yQWN0aW9uKCBhY3Rpb24gKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRkZWxldGUgYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXTtcblxuXHRcdH1cblxuXHR9XG5cblx0Ly8gZnJlZSBhbGwgcmVzb3VyY2VzIHNwZWNpZmljIHRvIGEgcGFydGljdWxhciByb290IHRhcmdldCBvYmplY3Rcblx0dW5jYWNoZVJvb3QoIHJvb3QgKSB7XG5cblx0XHRjb25zdCByb290VXVpZCA9IHJvb3QudXVpZCxcblx0XHRcdGFjdGlvbnNCeUNsaXAgPSB0aGlzLl9hY3Rpb25zQnlDbGlwO1xuXG5cdFx0Zm9yICggY29uc3QgY2xpcFV1aWQgaW4gYWN0aW9uc0J5Q2xpcCApIHtcblxuXHRcdFx0Y29uc3QgYWN0aW9uQnlSb290ID0gYWN0aW9uc0J5Q2xpcFsgY2xpcFV1aWQgXS5hY3Rpb25CeVJvb3QsXG5cdFx0XHRcdGFjdGlvbiA9IGFjdGlvbkJ5Um9vdFsgcm9vdFV1aWQgXTtcblxuXHRcdFx0aWYgKCBhY3Rpb24gIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHR0aGlzLl9kZWFjdGl2YXRlQWN0aW9uKCBhY3Rpb24gKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlSW5hY3RpdmVBY3Rpb24oIGFjdGlvbiApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRjb25zdCBiaW5kaW5nc0J5Um9vdCA9IHRoaXMuX2JpbmRpbmdzQnlSb290QW5kTmFtZSxcblx0XHRcdGJpbmRpbmdCeU5hbWUgPSBiaW5kaW5nc0J5Um9vdFsgcm9vdFV1aWQgXTtcblxuXHRcdGlmICggYmluZGluZ0J5TmFtZSAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRmb3IgKCBjb25zdCB0cmFja05hbWUgaW4gYmluZGluZ0J5TmFtZSApIHtcblxuXHRcdFx0XHRjb25zdCBiaW5kaW5nID0gYmluZGluZ0J5TmFtZVsgdHJhY2tOYW1lIF07XG5cdFx0XHRcdGJpbmRpbmcucmVzdG9yZU9yaWdpbmFsU3RhdGUoKTtcblx0XHRcdFx0dGhpcy5fcmVtb3ZlSW5hY3RpdmVCaW5kaW5nKCBiaW5kaW5nICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHR9XG5cblx0Ly8gcmVtb3ZlIGEgdGFyZ2V0ZWQgY2xpcCBmcm9tIHRoZSBjYWNoZVxuXHR1bmNhY2hlQWN0aW9uKCBjbGlwLCBvcHRpb25hbFJvb3QgKSB7XG5cblx0XHRjb25zdCBhY3Rpb24gPSB0aGlzLmV4aXN0aW5nQWN0aW9uKCBjbGlwLCBvcHRpb25hbFJvb3QgKTtcblxuXHRcdGlmICggYWN0aW9uICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLl9kZWFjdGl2YXRlQWN0aW9uKCBhY3Rpb24gKTtcblx0XHRcdHRoaXMuX3JlbW92ZUluYWN0aXZlQWN0aW9uKCBhY3Rpb24gKTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuY2xhc3MgVW5pZm9ybSB7XG5cblx0Y29uc3RydWN0b3IoIHZhbHVlICkge1xuXG5cdFx0dGhpcy52YWx1ZSA9IHZhbHVlO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgVW5pZm9ybSggdGhpcy52YWx1ZS5jbG9uZSA9PT0gdW5kZWZpbmVkID8gdGhpcy52YWx1ZSA6IHRoaXMudmFsdWUuY2xvbmUoKSApO1xuXG5cdH1cblxufVxuXG5sZXQgX2lkID0gMDtcblxuY2xhc3MgVW5pZm9ybXNHcm91cCBleHRlbmRzIEV2ZW50RGlzcGF0Y2hlciB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5pc1VuaWZvcm1zR3JvdXAgPSB0cnVlO1xuXG5cdFx0T2JqZWN0LmRlZmluZVByb3BlcnR5KCB0aGlzLCAnaWQnLCB7IHZhbHVlOiBfaWQgKysgfSApO1xuXG5cdFx0dGhpcy5uYW1lID0gJyc7XG5cblx0XHR0aGlzLnVzYWdlID0gU3RhdGljRHJhd1VzYWdlO1xuXHRcdHRoaXMudW5pZm9ybXMgPSBbXTtcblxuXHR9XG5cblx0YWRkKCB1bmlmb3JtICkge1xuXG5cdFx0dGhpcy51bmlmb3Jtcy5wdXNoKCB1bmlmb3JtICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0cmVtb3ZlKCB1bmlmb3JtICkge1xuXG5cdFx0Y29uc3QgaW5kZXggPSB0aGlzLnVuaWZvcm1zLmluZGV4T2YoIHVuaWZvcm0gKTtcblxuXHRcdGlmICggaW5kZXggIT09IC0gMSApIHRoaXMudW5pZm9ybXMuc3BsaWNlKCBpbmRleCwgMSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldE5hbWUoIG5hbWUgKSB7XG5cblx0XHR0aGlzLm5hbWUgPSBuYW1lO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFVzYWdlKCB2YWx1ZSApIHtcblxuXHRcdHRoaXMudXNhZ2UgPSB2YWx1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0dGhpcy5uYW1lID0gc291cmNlLm5hbWU7XG5cdFx0dGhpcy51c2FnZSA9IHNvdXJjZS51c2FnZTtcblxuXHRcdGNvbnN0IHVuaWZvcm1zU291cmNlID0gc291cmNlLnVuaWZvcm1zO1xuXG5cdFx0dGhpcy51bmlmb3Jtcy5sZW5ndGggPSAwO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gdW5pZm9ybXNTb3VyY2UubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgdW5pZm9ybXMgPSBBcnJheS5pc0FycmF5KCB1bmlmb3Jtc1NvdXJjZVsgaSBdICkgPyB1bmlmb3Jtc1NvdXJjZVsgaSBdIDogWyB1bmlmb3Jtc1NvdXJjZVsgaSBdIF07XG5cblx0XHRcdGZvciAoIGxldCBqID0gMDsgaiA8IHVuaWZvcm1zLmxlbmd0aDsgaiArKyApIHtcblxuXHRcdFx0XHR0aGlzLnVuaWZvcm1zLnB1c2goIHVuaWZvcm1zWyBqIF0uY2xvbmUoKSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG59XG5cbmNsYXNzIEluc3RhbmNlZEludGVybGVhdmVkQnVmZmVyIGV4dGVuZHMgSW50ZXJsZWF2ZWRCdWZmZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBhcnJheSwgc3RyaWRlLCBtZXNoUGVyQXR0cmlidXRlID0gMSApIHtcblxuXHRcdHN1cGVyKCBhcnJheSwgc3RyaWRlICk7XG5cblx0XHR0aGlzLmlzSW5zdGFuY2VkSW50ZXJsZWF2ZWRCdWZmZXIgPSB0cnVlO1xuXG5cdFx0dGhpcy5tZXNoUGVyQXR0cmlidXRlID0gbWVzaFBlckF0dHJpYnV0ZTtcblxuXHR9XG5cblx0Y29weSggc291cmNlICkge1xuXG5cdFx0c3VwZXIuY29weSggc291cmNlICk7XG5cblx0XHR0aGlzLm1lc2hQZXJBdHRyaWJ1dGUgPSBzb3VyY2UubWVzaFBlckF0dHJpYnV0ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSggZGF0YSApIHtcblxuXHRcdGNvbnN0IGliID0gc3VwZXIuY2xvbmUoIGRhdGEgKTtcblxuXHRcdGliLm1lc2hQZXJBdHRyaWJ1dGUgPSB0aGlzLm1lc2hQZXJBdHRyaWJ1dGU7XG5cblx0XHRyZXR1cm4gaWI7XG5cblx0fVxuXG5cdHRvSlNPTiggZGF0YSApIHtcblxuXHRcdGNvbnN0IGpzb24gPSBzdXBlci50b0pTT04oIGRhdGEgKTtcblxuXHRcdGpzb24uaXNJbnN0YW5jZWRJbnRlcmxlYXZlZEJ1ZmZlciA9IHRydWU7XG5cdFx0anNvbi5tZXNoUGVyQXR0cmlidXRlID0gdGhpcy5tZXNoUGVyQXR0cmlidXRlO1xuXG5cdFx0cmV0dXJuIGpzb247XG5cblx0fVxuXG59XG5cbmNsYXNzIEdMQnVmZmVyQXR0cmlidXRlIHtcblxuXHRjb25zdHJ1Y3RvciggYnVmZmVyLCB0eXBlLCBpdGVtU2l6ZSwgZWxlbWVudFNpemUsIGNvdW50ICkge1xuXG5cdFx0dGhpcy5pc0dMQnVmZmVyQXR0cmlidXRlID0gdHJ1ZTtcblxuXHRcdHRoaXMubmFtZSA9ICcnO1xuXG5cdFx0dGhpcy5idWZmZXIgPSBidWZmZXI7XG5cdFx0dGhpcy50eXBlID0gdHlwZTtcblx0XHR0aGlzLml0ZW1TaXplID0gaXRlbVNpemU7XG5cdFx0dGhpcy5lbGVtZW50U2l6ZSA9IGVsZW1lbnRTaXplO1xuXHRcdHRoaXMuY291bnQgPSBjb3VudDtcblxuXHRcdHRoaXMudmVyc2lvbiA9IDA7XG5cblx0fVxuXG5cdHNldCBuZWVkc1VwZGF0ZSggdmFsdWUgKSB7XG5cblx0XHRpZiAoIHZhbHVlID09PSB0cnVlICkgdGhpcy52ZXJzaW9uICsrO1xuXG5cdH1cblxuXHRzZXRCdWZmZXIoIGJ1ZmZlciApIHtcblxuXHRcdHRoaXMuYnVmZmVyID0gYnVmZmVyO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldFR5cGUoIHR5cGUsIGVsZW1lbnRTaXplICkge1xuXG5cdFx0dGhpcy50eXBlID0gdHlwZTtcblx0XHR0aGlzLmVsZW1lbnRTaXplID0gZWxlbWVudFNpemU7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0SXRlbVNpemUoIGl0ZW1TaXplICkge1xuXG5cdFx0dGhpcy5pdGVtU2l6ZSA9IGl0ZW1TaXplO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldENvdW50KCBjb3VudCApIHtcblxuXHRcdHRoaXMuY291bnQgPSBjb3VudDtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxufVxuXG5jb25zdCBfbWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuXG5jbGFzcyBSYXljYXN0ZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBvcmlnaW4sIGRpcmVjdGlvbiwgbmVhciA9IDAsIGZhciA9IEluZmluaXR5ICkge1xuXG5cdFx0dGhpcy5yYXkgPSBuZXcgUmF5KCBvcmlnaW4sIGRpcmVjdGlvbiApO1xuXHRcdC8vIGRpcmVjdGlvbiBpcyBhc3N1bWVkIHRvIGJlIG5vcm1hbGl6ZWQgKGZvciBhY2N1cmF0ZSBkaXN0YW5jZSBjYWxjdWxhdGlvbnMpXG5cblx0XHR0aGlzLm5lYXIgPSBuZWFyO1xuXHRcdHRoaXMuZmFyID0gZmFyO1xuXHRcdHRoaXMuY2FtZXJhID0gbnVsbDtcblx0XHR0aGlzLmxheWVycyA9IG5ldyBMYXllcnMoKTtcblxuXHRcdHRoaXMucGFyYW1zID0ge1xuXHRcdFx0TWVzaDoge30sXG5cdFx0XHRMaW5lOiB7IHRocmVzaG9sZDogMSB9LFxuXHRcdFx0TE9EOiB7fSxcblx0XHRcdFBvaW50czogeyB0aHJlc2hvbGQ6IDEgfSxcblx0XHRcdFNwcml0ZToge31cblx0XHR9O1xuXG5cdH1cblxuXHRzZXQoIG9yaWdpbiwgZGlyZWN0aW9uICkge1xuXG5cdFx0Ly8gZGlyZWN0aW9uIGlzIGFzc3VtZWQgdG8gYmUgbm9ybWFsaXplZCAoZm9yIGFjY3VyYXRlIGRpc3RhbmNlIGNhbGN1bGF0aW9ucylcblxuXHRcdHRoaXMucmF5LnNldCggb3JpZ2luLCBkaXJlY3Rpb24gKTtcblxuXHR9XG5cblx0c2V0RnJvbUNhbWVyYSggY29vcmRzLCBjYW1lcmEgKSB7XG5cblx0XHRpZiAoIGNhbWVyYS5pc1BlcnNwZWN0aXZlQ2FtZXJhICkge1xuXG5cdFx0XHR0aGlzLnJheS5vcmlnaW4uc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBjYW1lcmEubWF0cml4V29ybGQgKTtcblx0XHRcdHRoaXMucmF5LmRpcmVjdGlvbi5zZXQoIGNvb3Jkcy54LCBjb29yZHMueSwgMC41ICkudW5wcm9qZWN0KCBjYW1lcmEgKS5zdWIoIHRoaXMucmF5Lm9yaWdpbiApLm5vcm1hbGl6ZSgpO1xuXHRcdFx0dGhpcy5jYW1lcmEgPSBjYW1lcmE7XG5cblx0XHR9IGVsc2UgaWYgKCBjYW1lcmEuaXNPcnRob2dyYXBoaWNDYW1lcmEgKSB7XG5cblx0XHRcdHRoaXMucmF5Lm9yaWdpbi5zZXQoIGNvb3Jkcy54LCBjb29yZHMueSwgKCBjYW1lcmEubmVhciArIGNhbWVyYS5mYXIgKSAvICggY2FtZXJhLm5lYXIgLSBjYW1lcmEuZmFyICkgKS51bnByb2plY3QoIGNhbWVyYSApOyAvLyBzZXQgb3JpZ2luIGluIHBsYW5lIG9mIGNhbWVyYVxuXHRcdFx0dGhpcy5yYXkuZGlyZWN0aW9uLnNldCggMCwgMCwgLSAxICkudHJhbnNmb3JtRGlyZWN0aW9uKCBjYW1lcmEubWF0cml4V29ybGQgKTtcblx0XHRcdHRoaXMuY2FtZXJhID0gY2FtZXJhO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc29sZS5lcnJvciggJ1RIUkVFLlJheWNhc3RlcjogVW5zdXBwb3J0ZWQgY2FtZXJhIHR5cGU6ICcgKyBjYW1lcmEudHlwZSApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRzZXRGcm9tWFJDb250cm9sbGVyKCBjb250cm9sbGVyICkge1xuXG5cdFx0X21hdHJpeC5pZGVudGl0eSgpLmV4dHJhY3RSb3RhdGlvbiggY29udHJvbGxlci5tYXRyaXhXb3JsZCApO1xuXG5cdFx0dGhpcy5yYXkub3JpZ2luLnNldEZyb21NYXRyaXhQb3NpdGlvbiggY29udHJvbGxlci5tYXRyaXhXb3JsZCApO1xuXHRcdHRoaXMucmF5LmRpcmVjdGlvbi5zZXQoIDAsIDAsIC0gMSApLmFwcGx5TWF0cml4NCggX21hdHJpeCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGludGVyc2VjdE9iamVjdCggb2JqZWN0LCByZWN1cnNpdmUgPSB0cnVlLCBpbnRlcnNlY3RzID0gW10gKSB7XG5cblx0XHRpbnRlcnNlY3QoIG9iamVjdCwgdGhpcywgaW50ZXJzZWN0cywgcmVjdXJzaXZlICk7XG5cblx0XHRpbnRlcnNlY3RzLnNvcnQoIGFzY1NvcnQgKTtcblxuXHRcdHJldHVybiBpbnRlcnNlY3RzO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RPYmplY3RzKCBvYmplY3RzLCByZWN1cnNpdmUgPSB0cnVlLCBpbnRlcnNlY3RzID0gW10gKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBvYmplY3RzLmxlbmd0aDsgaSA8IGw7IGkgKysgKSB7XG5cblx0XHRcdGludGVyc2VjdCggb2JqZWN0c1sgaSBdLCB0aGlzLCBpbnRlcnNlY3RzLCByZWN1cnNpdmUgKTtcblxuXHRcdH1cblxuXHRcdGludGVyc2VjdHMuc29ydCggYXNjU29ydCApO1xuXG5cdFx0cmV0dXJuIGludGVyc2VjdHM7XG5cblx0fVxuXG59XG5cbmZ1bmN0aW9uIGFzY1NvcnQoIGEsIGIgKSB7XG5cblx0cmV0dXJuIGEuZGlzdGFuY2UgLSBiLmRpc3RhbmNlO1xuXG59XG5cbmZ1bmN0aW9uIGludGVyc2VjdCggb2JqZWN0LCByYXljYXN0ZXIsIGludGVyc2VjdHMsIHJlY3Vyc2l2ZSApIHtcblxuXHRsZXQgcHJvcGFnYXRlID0gdHJ1ZTtcblxuXHRpZiAoIG9iamVjdC5sYXllcnMudGVzdCggcmF5Y2FzdGVyLmxheWVycyApICkge1xuXG5cdFx0Y29uc3QgcmVzdWx0ID0gb2JqZWN0LnJheWNhc3QoIHJheWNhc3RlciwgaW50ZXJzZWN0cyApO1xuXG5cdFx0aWYgKCByZXN1bHQgPT09IGZhbHNlICkgcHJvcGFnYXRlID0gZmFsc2U7XG5cblx0fVxuXG5cdGlmICggcHJvcGFnYXRlID09PSB0cnVlICYmIHJlY3Vyc2l2ZSA9PT0gdHJ1ZSApIHtcblxuXHRcdGNvbnN0IGNoaWxkcmVuID0gb2JqZWN0LmNoaWxkcmVuO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY2hpbGRyZW4ubGVuZ3RoOyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0aW50ZXJzZWN0KCBjaGlsZHJlblsgaSBdLCByYXljYXN0ZXIsIGludGVyc2VjdHMsIHRydWUgKTtcblxuXHRcdH1cblxuXHR9XG5cbn1cblxuLyoqXG4gKiBSZWY6IGh0dHBzOi8vZW4ud2lraXBlZGlhLm9yZy93aWtpL1NwaGVyaWNhbF9jb29yZGluYXRlX3N5c3RlbVxuICpcbiAqIHBoaSAodGhlIHBvbGFyIGFuZ2xlKSBpcyBtZWFzdXJlZCBmcm9tIHRoZSBwb3NpdGl2ZSB5LWF4aXMuIFRoZSBwb3NpdGl2ZSB5LWF4aXMgaXMgdXAuXG4gKiB0aGV0YSAodGhlIGF6aW11dGhhbCBhbmdsZSkgaXMgbWVhc3VyZWQgZnJvbSB0aGUgcG9zaXRpdmUgei1heGlzLlxuICovXG5jbGFzcyBTcGhlcmljYWwge1xuXG5cdGNvbnN0cnVjdG9yKCByYWRpdXMgPSAxLCBwaGkgPSAwLCB0aGV0YSA9IDAgKSB7XG5cblx0XHR0aGlzLnJhZGl1cyA9IHJhZGl1cztcblx0XHR0aGlzLnBoaSA9IHBoaTsgLy8gcG9sYXIgYW5nbGVcblx0XHR0aGlzLnRoZXRhID0gdGhldGE7IC8vIGF6aW11dGhhbCBhbmdsZVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldCggcmFkaXVzLCBwaGksIHRoZXRhICkge1xuXG5cdFx0dGhpcy5yYWRpdXMgPSByYWRpdXM7XG5cdFx0dGhpcy5waGkgPSBwaGk7XG5cdFx0dGhpcy50aGV0YSA9IHRoZXRhO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvcHkoIG90aGVyICkge1xuXG5cdFx0dGhpcy5yYWRpdXMgPSBvdGhlci5yYWRpdXM7XG5cdFx0dGhpcy5waGkgPSBvdGhlci5waGk7XG5cdFx0dGhpcy50aGV0YSA9IG90aGVyLnRoZXRhO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdC8vIHJlc3RyaWN0IHBoaSB0byBiZSBiZXR3ZWVuIEVQUyBhbmQgUEktRVBTXG5cdG1ha2VTYWZlKCkge1xuXG5cdFx0Y29uc3QgRVBTID0gMC4wMDAwMDE7XG5cdFx0dGhpcy5waGkgPSBNYXRoLm1heCggRVBTLCBNYXRoLm1pbiggTWF0aC5QSSAtIEVQUywgdGhpcy5waGkgKSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldEZyb21WZWN0b3IzKCB2ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuc2V0RnJvbUNhcnRlc2lhbkNvb3Jkcyggdi54LCB2LnksIHYueiApO1xuXG5cdH1cblxuXHRzZXRGcm9tQ2FydGVzaWFuQ29vcmRzKCB4LCB5LCB6ICkge1xuXG5cdFx0dGhpcy5yYWRpdXMgPSBNYXRoLnNxcnQoIHggKiB4ICsgeSAqIHkgKyB6ICogeiApO1xuXG5cdFx0aWYgKCB0aGlzLnJhZGl1cyA9PT0gMCApIHtcblxuXHRcdFx0dGhpcy50aGV0YSA9IDA7XG5cdFx0XHR0aGlzLnBoaSA9IDA7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLnRoZXRhID0gTWF0aC5hdGFuMiggeCwgeiApO1xuXHRcdFx0dGhpcy5waGkgPSBNYXRoLmFjb3MoIGNsYW1wKCB5IC8gdGhpcy5yYWRpdXMsIC0gMSwgMSApICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG59XG5cbi8qKlxuICogUmVmOiBodHRwczovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9DeWxpbmRyaWNhbF9jb29yZGluYXRlX3N5c3RlbVxuICovXG5cbmNsYXNzIEN5bGluZHJpY2FsIHtcblxuXHRjb25zdHJ1Y3RvciggcmFkaXVzID0gMSwgdGhldGEgPSAwLCB5ID0gMCApIHtcblxuXHRcdHRoaXMucmFkaXVzID0gcmFkaXVzOyAvLyBkaXN0YW5jZSBmcm9tIHRoZSBvcmlnaW4gdG8gYSBwb2ludCBpbiB0aGUgeC16IHBsYW5lXG5cdFx0dGhpcy50aGV0YSA9IHRoZXRhOyAvLyBjb3VudGVyY2xvY2t3aXNlIGFuZ2xlIGluIHRoZSB4LXogcGxhbmUgbWVhc3VyZWQgaW4gcmFkaWFucyBmcm9tIHRoZSBwb3NpdGl2ZSB6LWF4aXNcblx0XHR0aGlzLnkgPSB5OyAvLyBoZWlnaHQgYWJvdmUgdGhlIHgteiBwbGFuZVxuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNldCggcmFkaXVzLCB0aGV0YSwgeSApIHtcblxuXHRcdHRoaXMucmFkaXVzID0gcmFkaXVzO1xuXHRcdHRoaXMudGhldGEgPSB0aGV0YTtcblx0XHR0aGlzLnkgPSB5O1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNvcHkoIG90aGVyICkge1xuXG5cdFx0dGhpcy5yYWRpdXMgPSBvdGhlci5yYWRpdXM7XG5cdFx0dGhpcy50aGV0YSA9IG90aGVyLnRoZXRhO1xuXHRcdHRoaXMueSA9IG90aGVyLnk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbVZlY3RvcjMoIHYgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5zZXRGcm9tQ2FydGVzaWFuQ29vcmRzKCB2LngsIHYueSwgdi56ICk7XG5cblx0fVxuXG5cdHNldEZyb21DYXJ0ZXNpYW5Db29yZHMoIHgsIHksIHogKSB7XG5cblx0XHR0aGlzLnJhZGl1cyA9IE1hdGguc3FydCggeCAqIHggKyB6ICogeiApO1xuXHRcdHRoaXMudGhldGEgPSBNYXRoLmF0YW4yKCB4LCB6ICk7XG5cdFx0dGhpcy55ID0geTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjbG9uZSgpIHtcblxuXHRcdHJldHVybiBuZXcgdGhpcy5jb25zdHJ1Y3RvcigpLmNvcHkoIHRoaXMgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgTWF0cml4MiB7XG5cblx0Y29uc3RydWN0b3IoIG4xMSwgbjEyLCBuMjEsIG4yMiApIHtcblxuXHRcdE1hdHJpeDIucHJvdG90eXBlLmlzTWF0cml4MiA9IHRydWU7XG5cblx0XHR0aGlzLmVsZW1lbnRzID0gW1xuXHRcdFx0MSwgMCxcblx0XHRcdDAsIDEsXG5cdFx0XTtcblxuXHRcdGlmICggbjExICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHRoaXMuc2V0KCBuMTEsIG4xMiwgbjIxLCBuMjIgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0aWRlbnRpdHkoKSB7XG5cblx0XHR0aGlzLnNldChcblx0XHRcdDEsIDAsXG5cdFx0XHQwLCAxLFxuXHRcdCk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZnJvbUFycmF5KCBhcnJheSwgb2Zmc2V0ID0gMCApIHtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IDQ7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuZWxlbWVudHNbIGkgXSA9IGFycmF5WyBpICsgb2Zmc2V0IF07XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0KCBuMTEsIG4xMiwgbjIxLCBuMjIgKSB7XG5cblx0XHRjb25zdCB0ZSA9IHRoaXMuZWxlbWVudHM7XG5cblx0XHR0ZVsgMCBdID0gbjExOyB0ZVsgMiBdID0gbjEyO1xuXHRcdHRlWyAxIF0gPSBuMjE7IHRlWyAzIF0gPSBuMjI7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cbn1cblxuY29uc3QgX3ZlY3RvciQ0ID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMigpO1xuXG5jbGFzcyBCb3gyIHtcblxuXHRjb25zdHJ1Y3RvciggbWluID0gbmV3IFZlY3RvcjIoICsgSW5maW5pdHksICsgSW5maW5pdHkgKSwgbWF4ID0gbmV3IFZlY3RvcjIoIC0gSW5maW5pdHksIC0gSW5maW5pdHkgKSApIHtcblxuXHRcdHRoaXMuaXNCb3gyID0gdHJ1ZTtcblxuXHRcdHRoaXMubWluID0gbWluO1xuXHRcdHRoaXMubWF4ID0gbWF4O1xuXG5cdH1cblxuXHRzZXQoIG1pbiwgbWF4ICkge1xuXG5cdFx0dGhpcy5taW4uY29weSggbWluICk7XG5cdFx0dGhpcy5tYXguY29weSggbWF4ICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0c2V0RnJvbVBvaW50cyggcG9pbnRzICkge1xuXG5cdFx0dGhpcy5tYWtlRW1wdHkoKTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSBwb2ludHMubGVuZ3RoOyBpIDwgaWw7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuZXhwYW5kQnlQb2ludCggcG9pbnRzWyBpIF0gKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRzZXRGcm9tQ2VudGVyQW5kU2l6ZSggY2VudGVyLCBzaXplICkge1xuXG5cdFx0Y29uc3QgaGFsZlNpemUgPSBfdmVjdG9yJDQuY29weSggc2l6ZSApLm11bHRpcGx5U2NhbGFyKCAwLjUgKTtcblx0XHR0aGlzLm1pbi5jb3B5KCBjZW50ZXIgKS5zdWIoIGhhbGZTaXplICk7XG5cdFx0dGhpcy5tYXguY29weSggY2VudGVyICkuYWRkKCBoYWxmU2l6ZSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGNsb25lKCkge1xuXG5cdFx0cmV0dXJuIG5ldyB0aGlzLmNvbnN0cnVjdG9yKCkuY29weSggdGhpcyApO1xuXG5cdH1cblxuXHRjb3B5KCBib3ggKSB7XG5cblx0XHR0aGlzLm1pbi5jb3B5KCBib3gubWluICk7XG5cdFx0dGhpcy5tYXguY29weSggYm94Lm1heCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdG1ha2VFbXB0eSgpIHtcblxuXHRcdHRoaXMubWluLnggPSB0aGlzLm1pbi55ID0gKyBJbmZpbml0eTtcblx0XHR0aGlzLm1heC54ID0gdGhpcy5tYXgueSA9IC0gSW5maW5pdHk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0aXNFbXB0eSgpIHtcblxuXHRcdC8vIHRoaXMgaXMgYSBtb3JlIHJvYnVzdCBjaGVjayBmb3IgZW1wdHkgdGhhbiAoIHZvbHVtZSA8PSAwICkgYmVjYXVzZSB2b2x1bWUgY2FuIGdldCBwb3NpdGl2ZSB3aXRoIHR3byBuZWdhdGl2ZSBheGVzXG5cblx0XHRyZXR1cm4gKCB0aGlzLm1heC54IDwgdGhpcy5taW4ueCApIHx8ICggdGhpcy5tYXgueSA8IHRoaXMubWluLnkgKTtcblxuXHR9XG5cblx0Z2V0Q2VudGVyKCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5pc0VtcHR5KCkgPyB0YXJnZXQuc2V0KCAwLCAwICkgOiB0YXJnZXQuYWRkVmVjdG9ycyggdGhpcy5taW4sIHRoaXMubWF4ICkubXVsdGlwbHlTY2FsYXIoIDAuNSApO1xuXG5cdH1cblxuXHRnZXRTaXplKCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5pc0VtcHR5KCkgPyB0YXJnZXQuc2V0KCAwLCAwICkgOiB0YXJnZXQuc3ViVmVjdG9ycyggdGhpcy5tYXgsIHRoaXMubWluICk7XG5cblx0fVxuXG5cdGV4cGFuZEJ5UG9pbnQoIHBvaW50ICkge1xuXG5cdFx0dGhpcy5taW4ubWluKCBwb2ludCApO1xuXHRcdHRoaXMubWF4Lm1heCggcG9pbnQgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRleHBhbmRCeVZlY3RvciggdmVjdG9yICkge1xuXG5cdFx0dGhpcy5taW4uc3ViKCB2ZWN0b3IgKTtcblx0XHR0aGlzLm1heC5hZGQoIHZlY3RvciApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGV4cGFuZEJ5U2NhbGFyKCBzY2FsYXIgKSB7XG5cblx0XHR0aGlzLm1pbi5hZGRTY2FsYXIoIC0gc2NhbGFyICk7XG5cdFx0dGhpcy5tYXguYWRkU2NhbGFyKCBzY2FsYXIgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb250YWluc1BvaW50KCBwb2ludCApIHtcblxuXHRcdHJldHVybiBwb2ludC54ID49IHRoaXMubWluLnggJiYgcG9pbnQueCA8PSB0aGlzLm1heC54ICYmXG5cdFx0XHRwb2ludC55ID49IHRoaXMubWluLnkgJiYgcG9pbnQueSA8PSB0aGlzLm1heC55O1xuXG5cdH1cblxuXHRjb250YWluc0JveCggYm94ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMubWluLnggPD0gYm94Lm1pbi54ICYmIGJveC5tYXgueCA8PSB0aGlzLm1heC54ICYmXG5cdFx0XHR0aGlzLm1pbi55IDw9IGJveC5taW4ueSAmJiBib3gubWF4LnkgPD0gdGhpcy5tYXgueTtcblxuXHR9XG5cblx0Z2V0UGFyYW1ldGVyKCBwb2ludCwgdGFyZ2V0ICkge1xuXG5cdFx0Ly8gVGhpcyBjYW4gcG90ZW50aWFsbHkgaGF2ZSBhIGRpdmlkZSBieSB6ZXJvIGlmIHRoZSBib3hcblx0XHQvLyBoYXMgYSBzaXplIGRpbWVuc2lvbiBvZiAwLlxuXG5cdFx0cmV0dXJuIHRhcmdldC5zZXQoXG5cdFx0XHQoIHBvaW50LnggLSB0aGlzLm1pbi54ICkgLyAoIHRoaXMubWF4LnggLSB0aGlzLm1pbi54ICksXG5cdFx0XHQoIHBvaW50LnkgLSB0aGlzLm1pbi55ICkgLyAoIHRoaXMubWF4LnkgLSB0aGlzLm1pbi55IClcblx0XHQpO1xuXG5cdH1cblxuXHRpbnRlcnNlY3RzQm94KCBib3ggKSB7XG5cblx0XHQvLyB1c2luZyA0IHNwbGl0dGluZyBwbGFuZXMgdG8gcnVsZSBvdXQgaW50ZXJzZWN0aW9uc1xuXG5cdFx0cmV0dXJuIGJveC5tYXgueCA+PSB0aGlzLm1pbi54ICYmIGJveC5taW4ueCA8PSB0aGlzLm1heC54ICYmXG5cdFx0XHRib3gubWF4LnkgPj0gdGhpcy5taW4ueSAmJiBib3gubWluLnkgPD0gdGhpcy5tYXgueTtcblxuXHR9XG5cblx0Y2xhbXBQb2ludCggcG9pbnQsIHRhcmdldCApIHtcblxuXHRcdHJldHVybiB0YXJnZXQuY29weSggcG9pbnQgKS5jbGFtcCggdGhpcy5taW4sIHRoaXMubWF4ICk7XG5cblx0fVxuXG5cdGRpc3RhbmNlVG9Qb2ludCggcG9pbnQgKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5jbGFtcFBvaW50KCBwb2ludCwgX3ZlY3RvciQ0ICkuZGlzdGFuY2VUbyggcG9pbnQgKTtcblxuXHR9XG5cblx0aW50ZXJzZWN0KCBib3ggKSB7XG5cblx0XHR0aGlzLm1pbi5tYXgoIGJveC5taW4gKTtcblx0XHR0aGlzLm1heC5taW4oIGJveC5tYXggKTtcblxuXHRcdGlmICggdGhpcy5pc0VtcHR5KCkgKSB0aGlzLm1ha2VFbXB0eSgpO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHVuaW9uKCBib3ggKSB7XG5cblx0XHR0aGlzLm1pbi5taW4oIGJveC5taW4gKTtcblx0XHR0aGlzLm1heC5tYXgoIGJveC5tYXggKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHR0cmFuc2xhdGUoIG9mZnNldCApIHtcblxuXHRcdHRoaXMubWluLmFkZCggb2Zmc2V0ICk7XG5cdFx0dGhpcy5tYXguYWRkKCBvZmZzZXQgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRlcXVhbHMoIGJveCApIHtcblxuXHRcdHJldHVybiBib3gubWluLmVxdWFscyggdGhpcy5taW4gKSAmJiBib3gubWF4LmVxdWFscyggdGhpcy5tYXggKTtcblxuXHR9XG5cbn1cblxuY29uc3QgX3N0YXJ0UCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9zdGFydEVuZCA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgTGluZTMge1xuXG5cdGNvbnN0cnVjdG9yKCBzdGFydCA9IG5ldyBWZWN0b3IzKCksIGVuZCA9IG5ldyBWZWN0b3IzKCkgKSB7XG5cblx0XHR0aGlzLnN0YXJ0ID0gc3RhcnQ7XG5cdFx0dGhpcy5lbmQgPSBlbmQ7XG5cblx0fVxuXG5cdHNldCggc3RhcnQsIGVuZCApIHtcblxuXHRcdHRoaXMuc3RhcnQuY29weSggc3RhcnQgKTtcblx0XHR0aGlzLmVuZC5jb3B5KCBlbmQgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb3B5KCBsaW5lICkge1xuXG5cdFx0dGhpcy5zdGFydC5jb3B5KCBsaW5lLnN0YXJ0ICk7XG5cdFx0dGhpcy5lbmQuY29weSggbGluZS5lbmQgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRnZXRDZW50ZXIoIHRhcmdldCApIHtcblxuXHRcdHJldHVybiB0YXJnZXQuYWRkVmVjdG9ycyggdGhpcy5zdGFydCwgdGhpcy5lbmQgKS5tdWx0aXBseVNjYWxhciggMC41ICk7XG5cblx0fVxuXG5cdGRlbHRhKCB0YXJnZXQgKSB7XG5cblx0XHRyZXR1cm4gdGFyZ2V0LnN1YlZlY3RvcnMoIHRoaXMuZW5kLCB0aGlzLnN0YXJ0ICk7XG5cblx0fVxuXG5cdGRpc3RhbmNlU3EoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5zdGFydC5kaXN0YW5jZVRvU3F1YXJlZCggdGhpcy5lbmQgKTtcblxuXHR9XG5cblx0ZGlzdGFuY2UoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy5zdGFydC5kaXN0YW5jZVRvKCB0aGlzLmVuZCApO1xuXG5cdH1cblxuXHRhdCggdCwgdGFyZ2V0ICkge1xuXG5cdFx0cmV0dXJuIHRoaXMuZGVsdGEoIHRhcmdldCApLm11bHRpcGx5U2NhbGFyKCB0ICkuYWRkKCB0aGlzLnN0YXJ0ICk7XG5cblx0fVxuXG5cdGNsb3Nlc3RQb2ludFRvUG9pbnRQYXJhbWV0ZXIoIHBvaW50LCBjbGFtcFRvTGluZSApIHtcblxuXHRcdF9zdGFydFAuc3ViVmVjdG9ycyggcG9pbnQsIHRoaXMuc3RhcnQgKTtcblx0XHRfc3RhcnRFbmQuc3ViVmVjdG9ycyggdGhpcy5lbmQsIHRoaXMuc3RhcnQgKTtcblxuXHRcdGNvbnN0IHN0YXJ0RW5kMiA9IF9zdGFydEVuZC5kb3QoIF9zdGFydEVuZCApO1xuXHRcdGNvbnN0IHN0YXJ0RW5kX3N0YXJ0UCA9IF9zdGFydEVuZC5kb3QoIF9zdGFydFAgKTtcblxuXHRcdGxldCB0ID0gc3RhcnRFbmRfc3RhcnRQIC8gc3RhcnRFbmQyO1xuXG5cdFx0aWYgKCBjbGFtcFRvTGluZSApIHtcblxuXHRcdFx0dCA9IGNsYW1wKCB0LCAwLCAxICk7XG5cblx0XHR9XG5cblx0XHRyZXR1cm4gdDtcblxuXHR9XG5cblx0Y2xvc2VzdFBvaW50VG9Qb2ludCggcG9pbnQsIGNsYW1wVG9MaW5lLCB0YXJnZXQgKSB7XG5cblx0XHRjb25zdCB0ID0gdGhpcy5jbG9zZXN0UG9pbnRUb1BvaW50UGFyYW1ldGVyKCBwb2ludCwgY2xhbXBUb0xpbmUgKTtcblxuXHRcdHJldHVybiB0aGlzLmRlbHRhKCB0YXJnZXQgKS5tdWx0aXBseVNjYWxhciggdCApLmFkZCggdGhpcy5zdGFydCApO1xuXG5cdH1cblxuXHRhcHBseU1hdHJpeDQoIG1hdHJpeCApIHtcblxuXHRcdHRoaXMuc3RhcnQuYXBwbHlNYXRyaXg0KCBtYXRyaXggKTtcblx0XHR0aGlzLmVuZC5hcHBseU1hdHJpeDQoIG1hdHJpeCApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdGVxdWFscyggbGluZSApIHtcblxuXHRcdHJldHVybiBsaW5lLnN0YXJ0LmVxdWFscyggdGhpcy5zdGFydCApICYmIGxpbmUuZW5kLmVxdWFscyggdGhpcy5lbmQgKTtcblxuXHR9XG5cblx0Y2xvbmUoKSB7XG5cblx0XHRyZXR1cm4gbmV3IHRoaXMuY29uc3RydWN0b3IoKS5jb3B5KCB0aGlzICk7XG5cblx0fVxuXG59XG5cbmNvbnN0IF92ZWN0b3IkMyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcblxuY2xhc3MgU3BvdExpZ2h0SGVscGVyIGV4dGVuZHMgT2JqZWN0M0Qge1xuXG5cdGNvbnN0cnVjdG9yKCBsaWdodCwgY29sb3IgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5saWdodCA9IGxpZ2h0O1xuXG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XG5cblx0XHR0aGlzLmNvbG9yID0gY29sb3I7XG5cblx0XHR0aGlzLnR5cGUgPSAnU3BvdExpZ2h0SGVscGVyJztcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cblx0XHRjb25zdCBwb3NpdGlvbnMgPSBbXG5cdFx0XHQwLCAwLCAwLCBcdDAsIDAsIDEsXG5cdFx0XHQwLCAwLCAwLCBcdDEsIDAsIDEsXG5cdFx0XHQwLCAwLCAwLFx0LSAxLCAwLCAxLFxuXHRcdFx0MCwgMCwgMCwgXHQwLCAxLCAxLFxuXHRcdFx0MCwgMCwgMCwgXHQwLCAtIDEsIDFcblx0XHRdO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBqID0gMSwgbCA9IDMyOyBpIDwgbDsgaSArKywgaiArKyApIHtcblxuXHRcdFx0Y29uc3QgcDEgPSAoIGkgLyBsICkgKiBNYXRoLlBJICogMjtcblx0XHRcdGNvbnN0IHAyID0gKCBqIC8gbCApICogTWF0aC5QSSAqIDI7XG5cblx0XHRcdHBvc2l0aW9ucy5wdXNoKFxuXHRcdFx0XHRNYXRoLmNvcyggcDEgKSwgTWF0aC5zaW4oIHAxICksIDEsXG5cdFx0XHRcdE1hdGguY29zKCBwMiApLCBNYXRoLnNpbiggcDIgKSwgMVxuXHRcdFx0KTtcblxuXHRcdH1cblxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9ucywgMyApICk7XG5cblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyBmb2c6IGZhbHNlLCB0b25lTWFwcGVkOiBmYWxzZSB9ICk7XG5cblx0XHR0aGlzLmNvbmUgPSBuZXcgTGluZVNlZ21lbnRzKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblx0XHR0aGlzLmFkZCggdGhpcy5jb25lICk7XG5cblx0XHR0aGlzLnVwZGF0ZSgpO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5jb25lLmdlb21ldHJ5LmRpc3Bvc2UoKTtcblx0XHR0aGlzLmNvbmUubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXG5cdH1cblxuXHR1cGRhdGUoKSB7XG5cblx0XHR0aGlzLmxpZ2h0LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xuXHRcdHRoaXMubGlnaHQudGFyZ2V0LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xuXG5cdFx0Ly8gdXBkYXRlIHRoZSBsb2NhbCBtYXRyaXggYmFzZWQgb24gdGhlIHBhcmVudCBhbmQgbGlnaHQgdGFyZ2V0IHRyYW5zZm9ybXNcblx0XHRpZiAoIHRoaXMucGFyZW50ICkge1xuXG5cdFx0XHR0aGlzLnBhcmVudC51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSApO1xuXG5cdFx0XHR0aGlzLm1hdHJpeFxuXHRcdFx0XHQuY29weSggdGhpcy5wYXJlbnQubWF0cml4V29ybGQgKVxuXHRcdFx0XHQuaW52ZXJ0KClcblx0XHRcdFx0Lm11bHRpcGx5KCB0aGlzLmxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLm1hdHJpeC5jb3B5KCB0aGlzLmxpZ2h0Lm1hdHJpeFdvcmxkICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLm1hdHJpeFdvcmxkLmNvcHkoIHRoaXMubGlnaHQubWF0cml4V29ybGQgKTtcblxuXHRcdGNvbnN0IGNvbmVMZW5ndGggPSB0aGlzLmxpZ2h0LmRpc3RhbmNlID8gdGhpcy5saWdodC5kaXN0YW5jZSA6IDEwMDA7XG5cdFx0Y29uc3QgY29uZVdpZHRoID0gY29uZUxlbmd0aCAqIE1hdGgudGFuKCB0aGlzLmxpZ2h0LmFuZ2xlICk7XG5cblx0XHR0aGlzLmNvbmUuc2NhbGUuc2V0KCBjb25lV2lkdGgsIGNvbmVXaWR0aCwgY29uZUxlbmd0aCApO1xuXG5cdFx0X3ZlY3RvciQzLnNldEZyb21NYXRyaXhQb3NpdGlvbiggdGhpcy5saWdodC50YXJnZXQubWF0cml4V29ybGQgKTtcblxuXHRcdHRoaXMuY29uZS5sb29rQXQoIF92ZWN0b3IkMyApO1xuXG5cdFx0aWYgKCB0aGlzLmNvbG9yICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHRoaXMuY29uZS5tYXRlcmlhbC5jb2xvci5zZXQoIHRoaXMuY29sb3IgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuY29uZS5tYXRlcmlhbC5jb2xvci5jb3B5KCB0aGlzLmxpZ2h0LmNvbG9yICk7XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbmNvbnN0IF92ZWN0b3IkMiA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9ib25lTWF0cml4ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuY29uc3QgX21hdHJpeFdvcmxkSW52ID0gLypAX19QVVJFX18qLyBuZXcgTWF0cml4NCgpO1xuXG5cbmNsYXNzIFNrZWxldG9uSGVscGVyIGV4dGVuZHMgTGluZVNlZ21lbnRzIHtcblxuXHRjb25zdHJ1Y3Rvciggb2JqZWN0ICkge1xuXG5cdFx0Y29uc3QgYm9uZXMgPSBnZXRCb25lTGlzdCggb2JqZWN0ICk7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcblx0XHRjb25zdCBjb2xvcnMgPSBbXTtcblxuXHRcdGNvbnN0IGNvbG9yMSA9IG5ldyBDb2xvciggMCwgMCwgMSApO1xuXHRcdGNvbnN0IGNvbG9yMiA9IG5ldyBDb2xvciggMCwgMSwgMCApO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgYm9uZXMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRjb25zdCBib25lID0gYm9uZXNbIGkgXTtcblxuXHRcdFx0aWYgKCBib25lLnBhcmVudCAmJiBib25lLnBhcmVudC5pc0JvbmUgKSB7XG5cblx0XHRcdFx0dmVydGljZXMucHVzaCggMCwgMCwgMCApO1xuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCAwLCAwLCAwICk7XG5cdFx0XHRcdGNvbG9ycy5wdXNoKCBjb2xvcjEuciwgY29sb3IxLmcsIGNvbG9yMS5iICk7XG5cdFx0XHRcdGNvbG9ycy5wdXNoKCBjb2xvcjIuciwgY29sb3IyLmcsIGNvbG9yMi5iICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHZlcnRpY2VzLCAzICkgKTtcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdjb2xvcicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBjb2xvcnMsIDMgKSApO1xuXG5cdFx0Y29uc3QgbWF0ZXJpYWwgPSBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgdmVydGV4Q29sb3JzOiB0cnVlLCBkZXB0aFRlc3Q6IGZhbHNlLCBkZXB0aFdyaXRlOiBmYWxzZSwgdG9uZU1hcHBlZDogZmFsc2UsIHRyYW5zcGFyZW50OiB0cnVlIH0gKTtcblxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblxuXHRcdHRoaXMuaXNTa2VsZXRvbkhlbHBlciA9IHRydWU7XG5cblx0XHR0aGlzLnR5cGUgPSAnU2tlbGV0b25IZWxwZXInO1xuXG5cdFx0dGhpcy5yb290ID0gb2JqZWN0O1xuXHRcdHRoaXMuYm9uZXMgPSBib25lcztcblxuXHRcdHRoaXMubWF0cml4ID0gb2JqZWN0Lm1hdHJpeFdvcmxkO1xuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xuXG5cdH1cblxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XG5cblx0XHRjb25zdCBib25lcyA9IHRoaXMuYm9uZXM7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IHRoaXMuZ2VvbWV0cnk7XG5cdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKTtcblxuXHRcdF9tYXRyaXhXb3JsZEludi5jb3B5KCB0aGlzLnJvb3QubWF0cml4V29ybGQgKS5pbnZlcnQoKTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaiA9IDA7IGkgPCBib25lcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGJvbmUgPSBib25lc1sgaSBdO1xuXG5cdFx0XHRpZiAoIGJvbmUucGFyZW50ICYmIGJvbmUucGFyZW50LmlzQm9uZSApIHtcblxuXHRcdFx0XHRfYm9uZU1hdHJpeC5tdWx0aXBseU1hdHJpY2VzKCBfbWF0cml4V29ybGRJbnYsIGJvbmUubWF0cml4V29ybGQgKTtcblx0XHRcdFx0X3ZlY3RvciQyLnNldEZyb21NYXRyaXhQb3NpdGlvbiggX2JvbmVNYXRyaXggKTtcblx0XHRcdFx0cG9zaXRpb24uc2V0WFlaKCBqLCBfdmVjdG9yJDIueCwgX3ZlY3RvciQyLnksIF92ZWN0b3IkMi56ICk7XG5cblx0XHRcdFx0X2JvbmVNYXRyaXgubXVsdGlwbHlNYXRyaWNlcyggX21hdHJpeFdvcmxkSW52LCBib25lLnBhcmVudC5tYXRyaXhXb3JsZCApO1xuXHRcdFx0XHRfdmVjdG9yJDIuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCBfYm9uZU1hdHJpeCApO1xuXHRcdFx0XHRwb3NpdGlvbi5zZXRYWVooIGogKyAxLCBfdmVjdG9yJDIueCwgX3ZlY3RvciQyLnksIF92ZWN0b3IkMi56ICk7XG5cblx0XHRcdFx0aiArPSAyO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHRzdXBlci51cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKTtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXG5cdH1cblxufVxuXG5cbmZ1bmN0aW9uIGdldEJvbmVMaXN0KCBvYmplY3QgKSB7XG5cblx0Y29uc3QgYm9uZUxpc3QgPSBbXTtcblxuXHRpZiAoIG9iamVjdC5pc0JvbmUgPT09IHRydWUgKSB7XG5cblx0XHRib25lTGlzdC5wdXNoKCBvYmplY3QgKTtcblxuXHR9XG5cblx0Zm9yICggbGV0IGkgPSAwOyBpIDwgb2JqZWN0LmNoaWxkcmVuLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdGJvbmVMaXN0LnB1c2guYXBwbHkoIGJvbmVMaXN0LCBnZXRCb25lTGlzdCggb2JqZWN0LmNoaWxkcmVuWyBpIF0gKSApO1xuXG5cdH1cblxuXHRyZXR1cm4gYm9uZUxpc3Q7XG5cbn1cblxuY2xhc3MgUG9pbnRMaWdodEhlbHBlciBleHRlbmRzIE1lc2gge1xuXG5cdGNvbnN0cnVjdG9yKCBsaWdodCwgc3BoZXJlU2l6ZSwgY29sb3IgKSB7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBTcGhlcmVHZW9tZXRyeSggc3BoZXJlU2l6ZSwgNCwgMiApO1xuXHRcdGNvbnN0IG1hdGVyaWFsID0gbmV3IE1lc2hCYXNpY01hdGVyaWFsKCB7IHdpcmVmcmFtZTogdHJ1ZSwgZm9nOiBmYWxzZSwgdG9uZU1hcHBlZDogZmFsc2UgfSApO1xuXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xuXG5cdFx0dGhpcy5saWdodCA9IGxpZ2h0O1xuXG5cdFx0dGhpcy5jb2xvciA9IGNvbG9yO1xuXG5cdFx0dGhpcy50eXBlID0gJ1BvaW50TGlnaHRIZWxwZXInO1xuXG5cdFx0dGhpcy5tYXRyaXggPSB0aGlzLmxpZ2h0Lm1hdHJpeFdvcmxkO1xuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0dGhpcy51cGRhdGUoKTtcblxuXG5cdFx0Lypcblx0Ly8gVE9ETzogZGVsZXRlIHRoaXMgY29tbWVudD9cblx0Y29uc3QgZGlzdGFuY2VHZW9tZXRyeSA9IG5ldyBUSFJFRS5JY29zYWhlZHJvbkdlb21ldHJ5KCAxLCAyICk7XG5cdGNvbnN0IGRpc3RhbmNlTWF0ZXJpYWwgPSBuZXcgVEhSRUUuTWVzaEJhc2ljTWF0ZXJpYWwoIHsgY29sb3I6IGhleENvbG9yLCBmb2c6IGZhbHNlLCB3aXJlZnJhbWU6IHRydWUsIG9wYWNpdHk6IDAuMSwgdHJhbnNwYXJlbnQ6IHRydWUgfSApO1xuXG5cdHRoaXMubGlnaHRTcGhlcmUgPSBuZXcgVEhSRUUuTWVzaCggYnVsYkdlb21ldHJ5LCBidWxiTWF0ZXJpYWwgKTtcblx0dGhpcy5saWdodERpc3RhbmNlID0gbmV3IFRIUkVFLk1lc2goIGRpc3RhbmNlR2VvbWV0cnksIGRpc3RhbmNlTWF0ZXJpYWwgKTtcblxuXHRjb25zdCBkID0gbGlnaHQuZGlzdGFuY2U7XG5cblx0aWYgKCBkID09PSAwLjAgKSB7XG5cblx0XHR0aGlzLmxpZ2h0RGlzdGFuY2UudmlzaWJsZSA9IGZhbHNlO1xuXG5cdH0gZWxzZSB7XG5cblx0XHR0aGlzLmxpZ2h0RGlzdGFuY2Uuc2NhbGUuc2V0KCBkLCBkLCBkICk7XG5cblx0fVxuXG5cdHRoaXMuYWRkKCB0aGlzLmxpZ2h0RGlzdGFuY2UgKTtcblx0Ki9cblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXG5cdH1cblxuXHR1cGRhdGUoKSB7XG5cblx0XHR0aGlzLmxpZ2h0LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xuXG5cdFx0aWYgKCB0aGlzLmNvbG9yICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdHRoaXMubWF0ZXJpYWwuY29sb3Iuc2V0KCB0aGlzLmNvbG9yICk7XG5cblx0XHR9IGVsc2Uge1xuXG5cdFx0XHR0aGlzLm1hdGVyaWFsLmNvbG9yLmNvcHkoIHRoaXMubGlnaHQuY29sb3IgKTtcblxuXHRcdH1cblxuXHRcdC8qXG5cdFx0Y29uc3QgZCA9IHRoaXMubGlnaHQuZGlzdGFuY2U7XG5cblx0XHRpZiAoIGQgPT09IDAuMCApIHtcblxuXHRcdFx0dGhpcy5saWdodERpc3RhbmNlLnZpc2libGUgPSBmYWxzZTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMubGlnaHREaXN0YW5jZS52aXNpYmxlID0gdHJ1ZTtcblx0XHRcdHRoaXMubGlnaHREaXN0YW5jZS5zY2FsZS5zZXQoIGQsIGQsIGQgKTtcblxuXHRcdH1cblx0XHQqL1xuXG5cdH1cblxufVxuXG5jb25zdCBfdmVjdG9yJDEgPSAvKkBfX1BVUkVfXyovIG5ldyBWZWN0b3IzKCk7XG5jb25zdCBfY29sb3IxID0gLypAX19QVVJFX18qLyBuZXcgQ29sb3IoKTtcbmNvbnN0IF9jb2xvcjIgPSAvKkBfX1BVUkVfXyovIG5ldyBDb2xvcigpO1xuXG5jbGFzcyBIZW1pc3BoZXJlTGlnaHRIZWxwZXIgZXh0ZW5kcyBPYmplY3QzRCB7XG5cblx0Y29uc3RydWN0b3IoIGxpZ2h0LCBzaXplLCBjb2xvciApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLmxpZ2h0ID0gbGlnaHQ7XG5cblx0XHR0aGlzLm1hdHJpeCA9IGxpZ2h0Lm1hdHJpeFdvcmxkO1xuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0dGhpcy5jb2xvciA9IGNvbG9yO1xuXG5cdFx0dGhpcy50eXBlID0gJ0hlbWlzcGhlcmVMaWdodEhlbHBlcic7XG5cblx0XHRjb25zdCBnZW9tZXRyeSA9IG5ldyBPY3RhaGVkcm9uR2VvbWV0cnkoIHNpemUgKTtcblx0XHRnZW9tZXRyeS5yb3RhdGVZKCBNYXRoLlBJICogMC41ICk7XG5cblx0XHR0aGlzLm1hdGVyaWFsID0gbmV3IE1lc2hCYXNpY01hdGVyaWFsKCB7IHdpcmVmcmFtZTogdHJ1ZSwgZm9nOiBmYWxzZSwgdG9uZU1hcHBlZDogZmFsc2UgfSApO1xuXHRcdGlmICggdGhpcy5jb2xvciA9PT0gdW5kZWZpbmVkICkgdGhpcy5tYXRlcmlhbC52ZXJ0ZXhDb2xvcnMgPSB0cnVlO1xuXG5cdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKTtcblx0XHRjb25zdCBjb2xvcnMgPSBuZXcgRmxvYXQzMkFycmF5KCBwb3NpdGlvbi5jb3VudCAqIDMgKTtcblxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2NvbG9yJywgbmV3IEJ1ZmZlckF0dHJpYnV0ZSggY29sb3JzLCAzICkgKTtcblxuXHRcdHRoaXMuYWRkKCBuZXcgTWVzaCggZ2VvbWV0cnksIHRoaXMubWF0ZXJpYWwgKSApO1xuXG5cdFx0dGhpcy51cGRhdGUoKTtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuY2hpbGRyZW5bIDAgXS5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5jaGlsZHJlblsgMCBdLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblxuXHR9XG5cblx0dXBkYXRlKCkge1xuXG5cdFx0Y29uc3QgbWVzaCA9IHRoaXMuY2hpbGRyZW5bIDAgXTtcblxuXHRcdGlmICggdGhpcy5jb2xvciAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHR0aGlzLm1hdGVyaWFsLmNvbG9yLnNldCggdGhpcy5jb2xvciApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0Y29uc3QgY29sb3JzID0gbWVzaC5nZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdjb2xvcicgKTtcblxuXHRcdFx0X2NvbG9yMS5jb3B5KCB0aGlzLmxpZ2h0LmNvbG9yICk7XG5cdFx0XHRfY29sb3IyLmNvcHkoIHRoaXMubGlnaHQuZ3JvdW5kQ29sb3IgKTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gY29sb3JzLmNvdW50OyBpIDwgbDsgaSArKyApIHtcblxuXHRcdFx0XHRjb25zdCBjb2xvciA9ICggaSA8ICggbCAvIDIgKSApID8gX2NvbG9yMSA6IF9jb2xvcjI7XG5cblx0XHRcdFx0Y29sb3JzLnNldFhZWiggaSwgY29sb3IuciwgY29sb3IuZywgY29sb3IuYiApO1xuXG5cdFx0XHR9XG5cblx0XHRcdGNvbG9ycy5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR9XG5cblx0XHR0aGlzLmxpZ2h0LnVwZGF0ZVdvcmxkTWF0cml4KCB0cnVlLCBmYWxzZSApO1xuXG5cdFx0bWVzaC5sb29rQXQoIF92ZWN0b3IkMS5zZXRGcm9tTWF0cml4UG9zaXRpb24oIHRoaXMubGlnaHQubWF0cml4V29ybGQgKS5uZWdhdGUoKSApO1xuXG5cdH1cblxufVxuXG5jbGFzcyBHcmlkSGVscGVyIGV4dGVuZHMgTGluZVNlZ21lbnRzIHtcblxuXHRjb25zdHJ1Y3Rvciggc2l6ZSA9IDEwLCBkaXZpc2lvbnMgPSAxMCwgY29sb3IxID0gMHg0NDQ0NDQsIGNvbG9yMiA9IDB4ODg4ODg4ICkge1xuXG5cdFx0Y29sb3IxID0gbmV3IENvbG9yKCBjb2xvcjEgKTtcblx0XHRjb2xvcjIgPSBuZXcgQ29sb3IoIGNvbG9yMiApO1xuXG5cdFx0Y29uc3QgY2VudGVyID0gZGl2aXNpb25zIC8gMjtcblx0XHRjb25zdCBzdGVwID0gc2l6ZSAvIGRpdmlzaW9ucztcblx0XHRjb25zdCBoYWxmU2l6ZSA9IHNpemUgLyAyO1xuXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXSwgY29sb3JzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGogPSAwLCBrID0gLSBoYWxmU2l6ZTsgaSA8PSBkaXZpc2lvbnM7IGkgKyssIGsgKz0gc3RlcCApIHtcblxuXHRcdFx0dmVydGljZXMucHVzaCggLSBoYWxmU2l6ZSwgMCwgaywgaGFsZlNpemUsIDAsIGsgKTtcblx0XHRcdHZlcnRpY2VzLnB1c2goIGssIDAsIC0gaGFsZlNpemUsIGssIDAsIGhhbGZTaXplICk7XG5cblx0XHRcdGNvbnN0IGNvbG9yID0gaSA9PT0gY2VudGVyID8gY29sb3IxIDogY29sb3IyO1xuXG5cdFx0XHRjb2xvci50b0FycmF5KCBjb2xvcnMsIGogKTsgaiArPSAzO1xuXHRcdFx0Y29sb3IudG9BcnJheSggY29sb3JzLCBqICk7IGogKz0gMztcblx0XHRcdGNvbG9yLnRvQXJyYXkoIGNvbG9ycywgaiApOyBqICs9IDM7XG5cdFx0XHRjb2xvci50b0FycmF5KCBjb2xvcnMsIGogKTsgaiArPSAzO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnY29sb3InLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggY29sb3JzLCAzICkgKTtcblxuXHRcdGNvbnN0IG1hdGVyaWFsID0gbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IHZlcnRleENvbG9yczogdHJ1ZSwgdG9uZU1hcHBlZDogZmFsc2UgfSApO1xuXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xuXG5cdFx0dGhpcy50eXBlID0gJ0dyaWRIZWxwZXInO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFBvbGFyR3JpZEhlbHBlciBleHRlbmRzIExpbmVTZWdtZW50cyB7XG5cblx0Y29uc3RydWN0b3IoIHJhZGl1cyA9IDEwLCBzZWN0b3JzID0gMTYsIHJpbmdzID0gOCwgZGl2aXNpb25zID0gNjQsIGNvbG9yMSA9IDB4NDQ0NDQ0LCBjb2xvcjIgPSAweDg4ODg4OCApIHtcblxuXHRcdGNvbG9yMSA9IG5ldyBDb2xvciggY29sb3IxICk7XG5cdFx0Y29sb3IyID0gbmV3IENvbG9yKCBjb2xvcjIgKTtcblxuXHRcdGNvbnN0IHZlcnRpY2VzID0gW107XG5cdFx0Y29uc3QgY29sb3JzID0gW107XG5cblx0XHQvLyBjcmVhdGUgdGhlIHNlY3RvcnNcblxuXHRcdGlmICggc2VjdG9ycyA+IDEgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHNlY3RvcnM7IGkgKysgKSB7XG5cblx0XHRcdFx0Y29uc3QgdiA9ICggaSAvIHNlY3RvcnMgKSAqICggTWF0aC5QSSAqIDIgKTtcblxuXHRcdFx0XHRjb25zdCB4ID0gTWF0aC5zaW4oIHYgKSAqIHJhZGl1cztcblx0XHRcdFx0Y29uc3QgeiA9IE1hdGguY29zKCB2ICkgKiByYWRpdXM7XG5cblx0XHRcdFx0dmVydGljZXMucHVzaCggMCwgMCwgMCApO1xuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB4LCAwLCB6ICk7XG5cblx0XHRcdFx0Y29uc3QgY29sb3IgPSAoIGkgJiAxICkgPyBjb2xvcjEgOiBjb2xvcjI7XG5cblx0XHRcdFx0Y29sb3JzLnB1c2goIGNvbG9yLnIsIGNvbG9yLmcsIGNvbG9yLmIgKTtcblx0XHRcdFx0Y29sb3JzLnB1c2goIGNvbG9yLnIsIGNvbG9yLmcsIGNvbG9yLmIgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Ly8gY3JlYXRlIHRoZSByaW5nc1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgcmluZ3M7IGkgKysgKSB7XG5cblx0XHRcdGNvbnN0IGNvbG9yID0gKCBpICYgMSApID8gY29sb3IxIDogY29sb3IyO1xuXG5cdFx0XHRjb25zdCByID0gcmFkaXVzIC0gKCByYWRpdXMgLyByaW5ncyAqIGkgKTtcblxuXHRcdFx0Zm9yICggbGV0IGogPSAwOyBqIDwgZGl2aXNpb25zOyBqICsrICkge1xuXG5cdFx0XHRcdC8vIGZpcnN0IHZlcnRleFxuXG5cdFx0XHRcdGxldCB2ID0gKCBqIC8gZGl2aXNpb25zICkgKiAoIE1hdGguUEkgKiAyICk7XG5cblx0XHRcdFx0bGV0IHggPSBNYXRoLnNpbiggdiApICogcjtcblx0XHRcdFx0bGV0IHogPSBNYXRoLmNvcyggdiApICogcjtcblxuXHRcdFx0XHR2ZXJ0aWNlcy5wdXNoKCB4LCAwLCB6ICk7XG5cdFx0XHRcdGNvbG9ycy5wdXNoKCBjb2xvci5yLCBjb2xvci5nLCBjb2xvci5iICk7XG5cblx0XHRcdFx0Ly8gc2Vjb25kIHZlcnRleFxuXG5cdFx0XHRcdHYgPSAoICggaiArIDEgKSAvIGRpdmlzaW9ucyApICogKCBNYXRoLlBJICogMiApO1xuXG5cdFx0XHRcdHggPSBNYXRoLnNpbiggdiApICogcjtcblx0XHRcdFx0eiA9IE1hdGguY29zKCB2ICkgKiByO1xuXG5cdFx0XHRcdHZlcnRpY2VzLnB1c2goIHgsIDAsIHogKTtcblx0XHRcdFx0Y29sb3JzLnB1c2goIGNvbG9yLnIsIGNvbG9yLmcsIGNvbG9yLmIgKTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnY29sb3InLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggY29sb3JzLCAzICkgKTtcblxuXHRcdGNvbnN0IG1hdGVyaWFsID0gbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IHZlcnRleENvbG9yczogdHJ1ZSwgdG9uZU1hcHBlZDogZmFsc2UgfSApO1xuXG5cdFx0c3VwZXIoIGdlb21ldHJ5LCBtYXRlcmlhbCApO1xuXG5cdFx0dGhpcy50eXBlID0gJ1BvbGFyR3JpZEhlbHBlcic7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLmdlb21ldHJ5LmRpc3Bvc2UoKTtcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblxuXHR9XG5cbn1cblxuY29uc3QgX3YxID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3YyID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuY29uc3QgX3YzID0gLypAX19QVVJFX18qLyBuZXcgVmVjdG9yMygpO1xuXG5jbGFzcyBEaXJlY3Rpb25hbExpZ2h0SGVscGVyIGV4dGVuZHMgT2JqZWN0M0Qge1xuXG5cdGNvbnN0cnVjdG9yKCBsaWdodCwgc2l6ZSwgY29sb3IgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5saWdodCA9IGxpZ2h0O1xuXG5cdFx0dGhpcy5tYXRyaXggPSBsaWdodC5tYXRyaXhXb3JsZDtcblx0XHR0aGlzLm1hdHJpeEF1dG9VcGRhdGUgPSBmYWxzZTtcblxuXHRcdHRoaXMuY29sb3IgPSBjb2xvcjtcblxuXHRcdHRoaXMudHlwZSA9ICdEaXJlY3Rpb25hbExpZ2h0SGVscGVyJztcblxuXHRcdGlmICggc2l6ZSA9PT0gdW5kZWZpbmVkICkgc2l6ZSA9IDE7XG5cblx0XHRsZXQgZ2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBbXG5cdFx0XHQtIHNpemUsIHNpemUsIDAsXG5cdFx0XHRzaXplLCBzaXplLCAwLFxuXHRcdFx0c2l6ZSwgLSBzaXplLCAwLFxuXHRcdFx0LSBzaXplLCAtIHNpemUsIDAsXG5cdFx0XHQtIHNpemUsIHNpemUsIDBcblx0XHRdLCAzICkgKTtcblxuXHRcdGNvbnN0IG1hdGVyaWFsID0gbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGZvZzogZmFsc2UsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKTtcblxuXHRcdHRoaXMubGlnaHRQbGFuZSA9IG5ldyBMaW5lKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblx0XHR0aGlzLmFkZCggdGhpcy5saWdodFBsYW5lICk7XG5cblx0XHRnZW9tZXRyeSA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIFsgMCwgMCwgMCwgMCwgMCwgMSBdLCAzICkgKTtcblxuXHRcdHRoaXMudGFyZ2V0TGluZSA9IG5ldyBMaW5lKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblx0XHR0aGlzLmFkZCggdGhpcy50YXJnZXRMaW5lICk7XG5cblx0XHR0aGlzLnVwZGF0ZSgpO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5saWdodFBsYW5lLmdlb21ldHJ5LmRpc3Bvc2UoKTtcblx0XHR0aGlzLmxpZ2h0UGxhbmUubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXHRcdHRoaXMudGFyZ2V0TGluZS5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy50YXJnZXRMaW5lLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblxuXHR9XG5cblx0dXBkYXRlKCkge1xuXG5cdFx0dGhpcy5saWdodC51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblx0XHR0aGlzLmxpZ2h0LnRhcmdldC51cGRhdGVXb3JsZE1hdHJpeCggdHJ1ZSwgZmFsc2UgKTtcblxuXHRcdF92MS5zZXRGcm9tTWF0cml4UG9zaXRpb24oIHRoaXMubGlnaHQubWF0cml4V29ybGQgKTtcblx0XHRfdjIuc2V0RnJvbU1hdHJpeFBvc2l0aW9uKCB0aGlzLmxpZ2h0LnRhcmdldC5tYXRyaXhXb3JsZCApO1xuXHRcdF92My5zdWJWZWN0b3JzKCBfdjIsIF92MSApO1xuXG5cdFx0dGhpcy5saWdodFBsYW5lLmxvb2tBdCggX3YyICk7XG5cblx0XHRpZiAoIHRoaXMuY29sb3IgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0dGhpcy5saWdodFBsYW5lLm1hdGVyaWFsLmNvbG9yLnNldCggdGhpcy5jb2xvciApO1xuXHRcdFx0dGhpcy50YXJnZXRMaW5lLm1hdGVyaWFsLmNvbG9yLnNldCggdGhpcy5jb2xvciApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0dGhpcy5saWdodFBsYW5lLm1hdGVyaWFsLmNvbG9yLmNvcHkoIHRoaXMubGlnaHQuY29sb3IgKTtcblx0XHRcdHRoaXMudGFyZ2V0TGluZS5tYXRlcmlhbC5jb2xvci5jb3B5KCB0aGlzLmxpZ2h0LmNvbG9yICk7XG5cblx0XHR9XG5cblx0XHR0aGlzLnRhcmdldExpbmUubG9va0F0KCBfdjIgKTtcblx0XHR0aGlzLnRhcmdldExpbmUuc2NhbGUueiA9IF92My5sZW5ndGgoKTtcblxuXHR9XG5cbn1cblxuY29uc3QgX3ZlY3RvciA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmNvbnN0IF9jYW1lcmEgPSAvKkBfX1BVUkVfXyovIG5ldyBDYW1lcmEoKTtcblxuLyoqXG4gKlx0LSBzaG93cyBmcnVzdHVtLCBsaW5lIG9mIHNpZ2h0IGFuZCB1cCBvZiB0aGUgY2FtZXJhXG4gKlx0LSBzdWl0YWJsZSBmb3IgZmFzdCB1cGRhdGVzXG4gKiBcdC0gYmFzZWQgb24gZnJ1c3R1bSB2aXN1YWxpemF0aW9uIGluIGxpZ2h0Z2wuanMgc2hhZG93bWFwIGV4YW1wbGVcbiAqXHRcdGh0dHBzOi8vZ2l0aHViLmNvbS9ldmFudy9saWdodGdsLmpzL2Jsb2IvbWFzdGVyL3Rlc3RzL3NoYWRvd21hcC5odG1sXG4gKi9cblxuY2xhc3MgQ2FtZXJhSGVscGVyIGV4dGVuZHMgTGluZVNlZ21lbnRzIHtcblxuXHRjb25zdHJ1Y3RvciggY2FtZXJhICkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyBjb2xvcjogMHhmZmZmZmYsIHZlcnRleENvbG9yczogdHJ1ZSwgdG9uZU1hcHBlZDogZmFsc2UgfSApO1xuXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXTtcblx0XHRjb25zdCBjb2xvcnMgPSBbXTtcblxuXHRcdGNvbnN0IHBvaW50TWFwID0ge307XG5cblx0XHQvLyBuZWFyXG5cblx0XHRhZGRMaW5lKCAnbjEnLCAnbjInICk7XG5cdFx0YWRkTGluZSggJ24yJywgJ240JyApO1xuXHRcdGFkZExpbmUoICduNCcsICduMycgKTtcblx0XHRhZGRMaW5lKCAnbjMnLCAnbjEnICk7XG5cblx0XHQvLyBmYXJcblxuXHRcdGFkZExpbmUoICdmMScsICdmMicgKTtcblx0XHRhZGRMaW5lKCAnZjInLCAnZjQnICk7XG5cdFx0YWRkTGluZSggJ2Y0JywgJ2YzJyApO1xuXHRcdGFkZExpbmUoICdmMycsICdmMScgKTtcblxuXHRcdC8vIHNpZGVzXG5cblx0XHRhZGRMaW5lKCAnbjEnLCAnZjEnICk7XG5cdFx0YWRkTGluZSggJ24yJywgJ2YyJyApO1xuXHRcdGFkZExpbmUoICduMycsICdmMycgKTtcblx0XHRhZGRMaW5lKCAnbjQnLCAnZjQnICk7XG5cblx0XHQvLyBjb25lXG5cblx0XHRhZGRMaW5lKCAncCcsICduMScgKTtcblx0XHRhZGRMaW5lKCAncCcsICduMicgKTtcblx0XHRhZGRMaW5lKCAncCcsICduMycgKTtcblx0XHRhZGRMaW5lKCAncCcsICduNCcgKTtcblxuXHRcdC8vIHVwXG5cblx0XHRhZGRMaW5lKCAndTEnLCAndTInICk7XG5cdFx0YWRkTGluZSggJ3UyJywgJ3UzJyApO1xuXHRcdGFkZExpbmUoICd1MycsICd1MScgKTtcblxuXHRcdC8vIHRhcmdldFxuXG5cdFx0YWRkTGluZSggJ2MnLCAndCcgKTtcblx0XHRhZGRMaW5lKCAncCcsICdjJyApO1xuXG5cdFx0Ly8gY3Jvc3NcblxuXHRcdGFkZExpbmUoICdjbjEnLCAnY24yJyApO1xuXHRcdGFkZExpbmUoICdjbjMnLCAnY240JyApO1xuXG5cdFx0YWRkTGluZSggJ2NmMScsICdjZjInICk7XG5cdFx0YWRkTGluZSggJ2NmMycsICdjZjQnICk7XG5cblx0XHRmdW5jdGlvbiBhZGRMaW5lKCBhLCBiICkge1xuXG5cdFx0XHRhZGRQb2ludCggYSApO1xuXHRcdFx0YWRkUG9pbnQoIGIgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGFkZFBvaW50KCBpZCApIHtcblxuXHRcdFx0dmVydGljZXMucHVzaCggMCwgMCwgMCApO1xuXHRcdFx0Y29sb3JzLnB1c2goIDAsIDAsIDAgKTtcblxuXHRcdFx0aWYgKCBwb2ludE1hcFsgaWQgXSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRcdHBvaW50TWFwWyBpZCBdID0gW107XG5cblx0XHRcdH1cblxuXHRcdFx0cG9pbnRNYXBbIGlkIF0ucHVzaCggKCB2ZXJ0aWNlcy5sZW5ndGggLyAzICkgLSAxICk7XG5cblx0XHR9XG5cblx0XHRnZW9tZXRyeS5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCB2ZXJ0aWNlcywgMyApICk7XG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAnY29sb3InLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggY29sb3JzLCAzICkgKTtcblxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblxuXHRcdHRoaXMudHlwZSA9ICdDYW1lcmFIZWxwZXInO1xuXG5cdFx0dGhpcy5jYW1lcmEgPSBjYW1lcmE7XG5cdFx0aWYgKCB0aGlzLmNhbWVyYS51cGRhdGVQcm9qZWN0aW9uTWF0cml4ICkgdGhpcy5jYW1lcmEudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXG5cdFx0dGhpcy5tYXRyaXggPSBjYW1lcmEubWF0cml4V29ybGQ7XG5cdFx0dGhpcy5tYXRyaXhBdXRvVXBkYXRlID0gZmFsc2U7XG5cblx0XHR0aGlzLnBvaW50TWFwID0gcG9pbnRNYXA7XG5cblx0XHR0aGlzLnVwZGF0ZSgpO1xuXG5cdFx0Ly8gY29sb3JzXG5cblx0XHRjb25zdCBjb2xvckZydXN0dW0gPSBuZXcgQ29sb3IoIDB4ZmZhYTAwICk7XG5cdFx0Y29uc3QgY29sb3JDb25lID0gbmV3IENvbG9yKCAweGZmMDAwMCApO1xuXHRcdGNvbnN0IGNvbG9yVXAgPSBuZXcgQ29sb3IoIDB4MDBhYWZmICk7XG5cdFx0Y29uc3QgY29sb3JUYXJnZXQgPSBuZXcgQ29sb3IoIDB4ZmZmZmZmICk7XG5cdFx0Y29uc3QgY29sb3JDcm9zcyA9IG5ldyBDb2xvciggMHgzMzMzMzMgKTtcblxuXHRcdHRoaXMuc2V0Q29sb3JzKCBjb2xvckZydXN0dW0sIGNvbG9yQ29uZSwgY29sb3JVcCwgY29sb3JUYXJnZXQsIGNvbG9yQ3Jvc3MgKTtcblxuXHR9XG5cblx0c2V0Q29sb3JzKCBmcnVzdHVtLCBjb25lLCB1cCwgdGFyZ2V0LCBjcm9zcyApIHtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gdGhpcy5nZW9tZXRyeTtcblxuXHRcdGNvbnN0IGNvbG9yQXR0cmlidXRlID0gZ2VvbWV0cnkuZ2V0QXR0cmlidXRlKCAnY29sb3InICk7XG5cblx0XHQvLyBuZWFyXG5cblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDAsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG4xLCBuMlxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMiwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDMsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgLy8gbjIsIG40XG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggNSwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBuNCwgbjNcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDYsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA3LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG4zLCBuMVxuXG5cdFx0Ly8gZmFyXG5cblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDgsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA5LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIGYxLCBmMlxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMTAsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxMSwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBmMiwgZjRcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDEyLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMTMsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgLy8gZjQsIGYzXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxNCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDE1LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIGYzLCBmMVxuXG5cdFx0Ly8gc2lkZXNcblxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMTYsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAxNywgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBuMSwgZjFcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDE4LCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMTksIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgLy8gbjIsIGYyXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyMCwgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDIxLCBmcnVzdHVtLnIsIGZydXN0dW0uZywgZnJ1c3R1bS5iICk7IC8vIG4zLCBmM1xuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjIsIGZydXN0dW0uciwgZnJ1c3R1bS5nLCBmcnVzdHVtLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyMywgZnJ1c3R1bS5yLCBmcnVzdHVtLmcsIGZydXN0dW0uYiApOyAvLyBuNCwgZjRcblxuXHRcdC8vIGNvbmVcblxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjQsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyNSwgY29uZS5yLCBjb25lLmcsIGNvbmUuYiApOyAvLyBwLCBuMVxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjYsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyNywgY29uZS5yLCBjb25lLmcsIGNvbmUuYiApOyAvLyBwLCBuMlxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMjgsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAyOSwgY29uZS5yLCBjb25lLmcsIGNvbmUuYiApOyAvLyBwLCBuM1xuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzAsIGNvbmUuciwgY29uZS5nLCBjb25lLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzMSwgY29uZS5yLCBjb25lLmcsIGNvbmUuYiApOyAvLyBwLCBuNFxuXG5cdFx0Ly8gdXBcblxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzIsIHVwLnIsIHVwLmcsIHVwLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzMywgdXAuciwgdXAuZywgdXAuYiApOyAvLyB1MSwgdTJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDM0LCB1cC5yLCB1cC5nLCB1cC5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzUsIHVwLnIsIHVwLmcsIHVwLmIgKTsgLy8gdTIsIHUzXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCAzNiwgdXAuciwgdXAuZywgdXAuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDM3LCB1cC5yLCB1cC5nLCB1cC5iICk7IC8vIHUzLCB1MVxuXG5cdFx0Ly8gdGFyZ2V0XG5cblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDM4LCB0YXJnZXQuciwgdGFyZ2V0LmcsIHRhcmdldC5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggMzksIHRhcmdldC5yLCB0YXJnZXQuZywgdGFyZ2V0LmIgKTsgLy8gYywgdFxuXHRcdGNvbG9yQXR0cmlidXRlLnNldFhZWiggNDAsIGNyb3NzLnIsIGNyb3NzLmcsIGNyb3NzLmIgKTsgY29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0MSwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyAvLyBwLCBjXG5cblx0XHQvLyBjcm9zc1xuXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0MiwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQzLCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IC8vIGNuMSwgY24yXG5cdFx0Y29sb3JBdHRyaWJ1dGUuc2V0WFlaKCA0NCwgY3Jvc3MuciwgY3Jvc3MuZywgY3Jvc3MuYiApOyBjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQ1LCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IC8vIGNuMywgY240XG5cblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQ2LCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggNDcsIGNyb3NzLnIsIGNyb3NzLmcsIGNyb3NzLmIgKTsgLy8gY2YxLCBjZjJcblx0XHRjb2xvckF0dHJpYnV0ZS5zZXRYWVooIDQ4LCBjcm9zcy5yLCBjcm9zcy5nLCBjcm9zcy5iICk7IGNvbG9yQXR0cmlidXRlLnNldFhZWiggNDksIGNyb3NzLnIsIGNyb3NzLmcsIGNyb3NzLmIgKTsgLy8gY2YzLCBjZjRcblxuXHRcdGNvbG9yQXR0cmlidXRlLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHR9XG5cblx0dXBkYXRlKCkge1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSB0aGlzLmdlb21ldHJ5O1xuXHRcdGNvbnN0IHBvaW50TWFwID0gdGhpcy5wb2ludE1hcDtcblxuXHRcdGNvbnN0IHcgPSAxLCBoID0gMTtcblxuXHRcdC8vIHdlIG5lZWQganVzdCBjYW1lcmEgcHJvamVjdGlvbiBtYXRyaXggaW52ZXJzZVxuXHRcdC8vIHdvcmxkIG1hdHJpeCBtdXN0IGJlIGlkZW50aXR5XG5cblx0XHRfY2FtZXJhLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlLmNvcHkoIHRoaXMuY2FtZXJhLnByb2plY3Rpb25NYXRyaXhJbnZlcnNlICk7XG5cblx0XHQvLyBjZW50ZXIgLyB0YXJnZXRcblxuXHRcdHNldFBvaW50KCAnYycsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgMCwgMCwgLSAxICk7XG5cdFx0c2V0UG9pbnQoICd0JywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAwLCAwLCAxICk7XG5cblx0XHQvLyBuZWFyXG5cblx0XHRzZXRQb2ludCggJ24xJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAtIHcsIC0gaCwgLSAxICk7XG5cdFx0c2V0UG9pbnQoICduMicsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgdywgLSBoLCAtIDEgKTtcblx0XHRzZXRQb2ludCggJ24zJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAtIHcsIGgsIC0gMSApO1xuXHRcdHNldFBvaW50KCAnbjQnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIHcsIGgsIC0gMSApO1xuXG5cdFx0Ly8gZmFyXG5cblx0XHRzZXRQb2ludCggJ2YxJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAtIHcsIC0gaCwgMSApO1xuXHRcdHNldFBvaW50KCAnZjInLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIHcsIC0gaCwgMSApO1xuXHRcdHNldFBvaW50KCAnZjMnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIC0gdywgaCwgMSApO1xuXHRcdHNldFBvaW50KCAnZjQnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIHcsIGgsIDEgKTtcblxuXHRcdC8vIHVwXG5cblx0XHRzZXRQb2ludCggJ3UxJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3ICogMC43LCBoICogMS4xLCAtIDEgKTtcblx0XHRzZXRQb2ludCggJ3UyJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAtIHcgKiAwLjcsIGggKiAxLjEsIC0gMSApO1xuXHRcdHNldFBvaW50KCAndTMnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIGggKiAyLCAtIDEgKTtcblxuXHRcdC8vIGNyb3NzXG5cblx0XHRzZXRQb2ludCggJ2NmMScsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgLSB3LCAwLCAxICk7XG5cdFx0c2V0UG9pbnQoICdjZjInLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIHcsIDAsIDEgKTtcblx0XHRzZXRQb2ludCggJ2NmMycsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgMCwgLSBoLCAxICk7XG5cdFx0c2V0UG9pbnQoICdjZjQnLCBwb2ludE1hcCwgZ2VvbWV0cnksIF9jYW1lcmEsIDAsIGgsIDEgKTtcblxuXHRcdHNldFBvaW50KCAnY24xJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCAtIHcsIDAsIC0gMSApO1xuXHRcdHNldFBvaW50KCAnY24yJywgcG9pbnRNYXAsIGdlb21ldHJ5LCBfY2FtZXJhLCB3LCAwLCAtIDEgKTtcblx0XHRzZXRQb2ludCggJ2NuMycsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgMCwgLSBoLCAtIDEgKTtcblx0XHRzZXRQb2ludCggJ2NuNCcsIHBvaW50TWFwLCBnZW9tZXRyeSwgX2NhbWVyYSwgMCwgaCwgLSAxICk7XG5cblx0XHRnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLmdlb21ldHJ5LmRpc3Bvc2UoKTtcblx0XHR0aGlzLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblxuXHR9XG5cbn1cblxuXG5mdW5jdGlvbiBzZXRQb2ludCggcG9pbnQsIHBvaW50TWFwLCBnZW9tZXRyeSwgY2FtZXJhLCB4LCB5LCB6ICkge1xuXG5cdF92ZWN0b3Iuc2V0KCB4LCB5LCB6ICkudW5wcm9qZWN0KCBjYW1lcmEgKTtcblxuXHRjb25zdCBwb2ludHMgPSBwb2ludE1hcFsgcG9pbnQgXTtcblxuXHRpZiAoIHBvaW50cyAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0Y29uc3QgcG9zaXRpb24gPSBnZW9tZXRyeS5nZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgbCA9IHBvaW50cy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRwb3NpdGlvbi5zZXRYWVooIHBvaW50c1sgaSBdLCBfdmVjdG9yLngsIF92ZWN0b3IueSwgX3ZlY3Rvci56ICk7XG5cblx0XHR9XG5cblx0fVxuXG59XG5cbmNvbnN0IF9ib3ggPSAvKkBfX1BVUkVfXyovIG5ldyBCb3gzKCk7XG5cbmNsYXNzIEJveEhlbHBlciBleHRlbmRzIExpbmVTZWdtZW50cyB7XG5cblx0Y29uc3RydWN0b3IoIG9iamVjdCwgY29sb3IgPSAweGZmZmYwMCApIHtcblxuXHRcdGNvbnN0IGluZGljZXMgPSBuZXcgVWludDE2QXJyYXkoIFsgMCwgMSwgMSwgMiwgMiwgMywgMywgMCwgNCwgNSwgNSwgNiwgNiwgNywgNywgNCwgMCwgNCwgMSwgNSwgMiwgNiwgMywgNyBdICk7XG5cdFx0Y29uc3QgcG9zaXRpb25zID0gbmV3IEZsb2F0MzJBcnJheSggOCAqIDMgKTtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cdFx0Z2VvbWV0cnkuc2V0SW5kZXgoIG5ldyBCdWZmZXJBdHRyaWJ1dGUoIGluZGljZXMsIDEgKSApO1xuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25zLCAzICkgKTtcblxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XG5cblx0XHR0aGlzLm9iamVjdCA9IG9iamVjdDtcblx0XHR0aGlzLnR5cGUgPSAnQm94SGVscGVyJztcblxuXHRcdHRoaXMubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0dGhpcy51cGRhdGUoKTtcblxuXHR9XG5cblx0dXBkYXRlKCBvYmplY3QgKSB7XG5cblx0XHRpZiAoIG9iamVjdCAhPT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRjb25zb2xlLndhcm4oICdUSFJFRS5Cb3hIZWxwZXI6IC51cGRhdGUoKSBoYXMgbm8gbG9uZ2VyIGFyZ3VtZW50cy4nICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMub2JqZWN0ICE9PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdF9ib3guc2V0RnJvbU9iamVjdCggdGhpcy5vYmplY3QgKTtcblxuXHRcdH1cblxuXHRcdGlmICggX2JveC5pc0VtcHR5KCkgKSByZXR1cm47XG5cblx0XHRjb25zdCBtaW4gPSBfYm94Lm1pbjtcblx0XHRjb25zdCBtYXggPSBfYm94Lm1heDtcblxuXHRcdC8qXG5cdFx0XHQ1X19fXzRcblx0XHQxL19fXzAvfFxuXHRcdHwgNl9ffF83XG5cdFx0Mi9fX18zL1xuXG5cdFx0MDogbWF4LngsIG1heC55LCBtYXguelxuXHRcdDE6IG1pbi54LCBtYXgueSwgbWF4Lnpcblx0XHQyOiBtaW4ueCwgbWluLnksIG1heC56XG5cdFx0MzogbWF4LngsIG1pbi55LCBtYXguelxuXHRcdDQ6IG1heC54LCBtYXgueSwgbWluLnpcblx0XHQ1OiBtaW4ueCwgbWF4LnksIG1pbi56XG5cdFx0NjogbWluLngsIG1pbi55LCBtaW4uelxuXHRcdDc6IG1heC54LCBtaW4ueSwgbWluLnpcblx0XHQqL1xuXG5cdFx0Y29uc3QgcG9zaXRpb24gPSB0aGlzLmdlb21ldHJ5LmF0dHJpYnV0ZXMucG9zaXRpb247XG5cdFx0Y29uc3QgYXJyYXkgPSBwb3NpdGlvbi5hcnJheTtcblxuXHRcdGFycmF5WyAwIF0gPSBtYXgueDsgYXJyYXlbIDEgXSA9IG1heC55OyBhcnJheVsgMiBdID0gbWF4Lno7XG5cdFx0YXJyYXlbIDMgXSA9IG1pbi54OyBhcnJheVsgNCBdID0gbWF4Lnk7IGFycmF5WyA1IF0gPSBtYXguejtcblx0XHRhcnJheVsgNiBdID0gbWluLng7IGFycmF5WyA3IF0gPSBtaW4ueTsgYXJyYXlbIDggXSA9IG1heC56O1xuXHRcdGFycmF5WyA5IF0gPSBtYXgueDsgYXJyYXlbIDEwIF0gPSBtaW4ueTsgYXJyYXlbIDExIF0gPSBtYXguejtcblx0XHRhcnJheVsgMTIgXSA9IG1heC54OyBhcnJheVsgMTMgXSA9IG1heC55OyBhcnJheVsgMTQgXSA9IG1pbi56O1xuXHRcdGFycmF5WyAxNSBdID0gbWluLng7IGFycmF5WyAxNiBdID0gbWF4Lnk7IGFycmF5WyAxNyBdID0gbWluLno7XG5cdFx0YXJyYXlbIDE4IF0gPSBtaW4ueDsgYXJyYXlbIDE5IF0gPSBtaW4ueTsgYXJyYXlbIDIwIF0gPSBtaW4uejtcblx0XHRhcnJheVsgMjEgXSA9IG1heC54OyBhcnJheVsgMjIgXSA9IG1pbi55OyBhcnJheVsgMjMgXSA9IG1pbi56O1xuXG5cdFx0cG9zaXRpb24ubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0dGhpcy5nZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcblxuXHR9XG5cblx0c2V0RnJvbU9iamVjdCggb2JqZWN0ICkge1xuXG5cdFx0dGhpcy5vYmplY3QgPSBvYmplY3Q7XG5cdFx0dGhpcy51cGRhdGUoKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UsIHJlY3Vyc2l2ZSApIHtcblxuXHRcdHN1cGVyLmNvcHkoIHNvdXJjZSwgcmVjdXJzaXZlICk7XG5cblx0XHR0aGlzLm9iamVjdCA9IHNvdXJjZS5vYmplY3Q7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMuZ2VvbWV0cnkuZGlzcG9zZSgpO1xuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXG5cdH1cblxufVxuXG5jbGFzcyBCb3gzSGVscGVyIGV4dGVuZHMgTGluZVNlZ21lbnRzIHtcblxuXHRjb25zdHJ1Y3RvciggYm94LCBjb2xvciA9IDB4ZmZmZjAwICkge1xuXG5cdFx0Y29uc3QgaW5kaWNlcyA9IG5ldyBVaW50MTZBcnJheSggWyAwLCAxLCAxLCAyLCAyLCAzLCAzLCAwLCA0LCA1LCA1LCA2LCA2LCA3LCA3LCA0LCAwLCA0LCAxLCA1LCAyLCA2LCAzLCA3IF0gKTtcblxuXHRcdGNvbnN0IHBvc2l0aW9ucyA9IFsgMSwgMSwgMSwgLSAxLCAxLCAxLCAtIDEsIC0gMSwgMSwgMSwgLSAxLCAxLCAxLCAxLCAtIDEsIC0gMSwgMSwgLSAxLCAtIDEsIC0gMSwgLSAxLCAxLCAtIDEsIC0gMSBdO1xuXG5cdFx0Y29uc3QgZ2VvbWV0cnkgPSBuZXcgQnVmZmVyR2VvbWV0cnkoKTtcblxuXHRcdGdlb21ldHJ5LnNldEluZGV4KCBuZXcgQnVmZmVyQXR0cmlidXRlKCBpbmRpY2VzLCAxICkgKTtcblxuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIHBvc2l0aW9ucywgMyApICk7XG5cblx0XHRzdXBlciggZ2VvbWV0cnksIG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyBjb2xvcjogY29sb3IsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKSApO1xuXG5cdFx0dGhpcy5ib3ggPSBib3g7XG5cblx0XHR0aGlzLnR5cGUgPSAnQm94M0hlbHBlcic7XG5cblx0XHR0aGlzLmdlb21ldHJ5LmNvbXB1dGVCb3VuZGluZ1NwaGVyZSgpO1xuXG5cdH1cblxuXHR1cGRhdGVNYXRyaXhXb3JsZCggZm9yY2UgKSB7XG5cblx0XHRjb25zdCBib3ggPSB0aGlzLmJveDtcblxuXHRcdGlmICggYm94LmlzRW1wdHkoKSApIHJldHVybjtcblxuXHRcdGJveC5nZXRDZW50ZXIoIHRoaXMucG9zaXRpb24gKTtcblxuXHRcdGJveC5nZXRTaXplKCB0aGlzLnNjYWxlICk7XG5cblx0XHR0aGlzLnNjYWxlLm11bHRpcGx5U2NhbGFyKCAwLjUgKTtcblxuXHRcdHN1cGVyLnVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFBsYW5lSGVscGVyIGV4dGVuZHMgTGluZSB7XG5cblx0Y29uc3RydWN0b3IoIHBsYW5lLCBzaXplID0gMSwgaGV4ID0gMHhmZmZmMDAgKSB7XG5cblx0XHRjb25zdCBjb2xvciA9IGhleDtcblxuXHRcdGNvbnN0IHBvc2l0aW9ucyA9IFsgMSwgLSAxLCAwLCAtIDEsIDEsIDAsIC0gMSwgLSAxLCAwLCAxLCAxLCAwLCAtIDEsIDEsIDAsIC0gMSwgLSAxLCAwLCAxLCAtIDEsIDAsIDEsIDEsIDAgXTtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggcG9zaXRpb25zLCAzICkgKTtcblx0XHRnZW9tZXRyeS5jb21wdXRlQm91bmRpbmdTcGhlcmUoKTtcblxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbmV3IExpbmVCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgdG9uZU1hcHBlZDogZmFsc2UgfSApICk7XG5cblx0XHR0aGlzLnR5cGUgPSAnUGxhbmVIZWxwZXInO1xuXG5cdFx0dGhpcy5wbGFuZSA9IHBsYW5lO1xuXG5cdFx0dGhpcy5zaXplID0gc2l6ZTtcblxuXHRcdGNvbnN0IHBvc2l0aW9uczIgPSBbIDEsIDEsIDAsIC0gMSwgMSwgMCwgLSAxLCAtIDEsIDAsIDEsIDEsIDAsIC0gMSwgLSAxLCAwLCAxLCAtIDEsIDAgXTtcblxuXHRcdGNvbnN0IGdlb21ldHJ5MiA9IG5ldyBCdWZmZXJHZW9tZXRyeSgpO1xuXHRcdGdlb21ldHJ5Mi5zZXRBdHRyaWJ1dGUoICdwb3NpdGlvbicsIG5ldyBGbG9hdDMyQnVmZmVyQXR0cmlidXRlKCBwb3NpdGlvbnMyLCAzICkgKTtcblx0XHRnZW9tZXRyeTIuY29tcHV0ZUJvdW5kaW5nU3BoZXJlKCk7XG5cblx0XHR0aGlzLmFkZCggbmV3IE1lc2goIGdlb21ldHJ5MiwgbmV3IE1lc2hCYXNpY01hdGVyaWFsKCB7IGNvbG9yOiBjb2xvciwgb3BhY2l0eTogMC4yLCB0cmFuc3BhcmVudDogdHJ1ZSwgZGVwdGhXcml0ZTogZmFsc2UsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKSApICk7XG5cblx0fVxuXG5cdHVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApIHtcblxuXHRcdHRoaXMucG9zaXRpb24uc2V0KCAwLCAwLCAwICk7XG5cblx0XHR0aGlzLnNjYWxlLnNldCggMC41ICogdGhpcy5zaXplLCAwLjUgKiB0aGlzLnNpemUsIDEgKTtcblxuXHRcdHRoaXMubG9va0F0KCB0aGlzLnBsYW5lLm5vcm1hbCApO1xuXG5cdFx0dGhpcy50cmFuc2xhdGVaKCAtIHRoaXMucGxhbmUuY29uc3RhbnQgKTtcblxuXHRcdHN1cGVyLnVwZGF0ZU1hdHJpeFdvcmxkKCBmb3JjZSApO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cdFx0dGhpcy5jaGlsZHJlblsgMCBdLmdlb21ldHJ5LmRpc3Bvc2UoKTtcblx0XHR0aGlzLmNoaWxkcmVuWyAwIF0ubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXG5cdH1cblxufVxuXG5jb25zdCBfYXhpcyA9IC8qQF9fUFVSRV9fKi8gbmV3IFZlY3RvcjMoKTtcbmxldCBfbGluZUdlb21ldHJ5LCBfY29uZUdlb21ldHJ5O1xuXG5jbGFzcyBBcnJvd0hlbHBlciBleHRlbmRzIE9iamVjdDNEIHtcblxuXHQvLyBkaXIgaXMgYXNzdW1lZCB0byBiZSBub3JtYWxpemVkXG5cblx0Y29uc3RydWN0b3IoIGRpciA9IG5ldyBWZWN0b3IzKCAwLCAwLCAxICksIG9yaWdpbiA9IG5ldyBWZWN0b3IzKCAwLCAwLCAwICksIGxlbmd0aCA9IDEsIGNvbG9yID0gMHhmZmZmMDAsIGhlYWRMZW5ndGggPSBsZW5ndGggKiAwLjIsIGhlYWRXaWR0aCA9IGhlYWRMZW5ndGggKiAwLjIgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50eXBlID0gJ0Fycm93SGVscGVyJztcblxuXHRcdGlmICggX2xpbmVHZW9tZXRyeSA9PT0gdW5kZWZpbmVkICkge1xuXG5cdFx0XHRfbGluZUdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cdFx0XHRfbGluZUdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIFsgMCwgMCwgMCwgMCwgMSwgMCBdLCAzICkgKTtcblxuXHRcdFx0X2NvbmVHZW9tZXRyeSA9IG5ldyBDeWxpbmRlckdlb21ldHJ5KCAwLCAwLjUsIDEsIDUsIDEgKTtcblx0XHRcdF9jb25lR2VvbWV0cnkudHJhbnNsYXRlKCAwLCAtIDAuNSwgMCApO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5wb3NpdGlvbi5jb3B5KCBvcmlnaW4gKTtcblxuXHRcdHRoaXMubGluZSA9IG5ldyBMaW5lKCBfbGluZUdlb21ldHJ5LCBuZXcgTGluZUJhc2ljTWF0ZXJpYWwoIHsgY29sb3I6IGNvbG9yLCB0b25lTWFwcGVkOiBmYWxzZSB9ICkgKTtcblx0XHR0aGlzLmxpbmUubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xuXHRcdHRoaXMuYWRkKCB0aGlzLmxpbmUgKTtcblxuXHRcdHRoaXMuY29uZSA9IG5ldyBNZXNoKCBfY29uZUdlb21ldHJ5LCBuZXcgTWVzaEJhc2ljTWF0ZXJpYWwoIHsgY29sb3I6IGNvbG9yLCB0b25lTWFwcGVkOiBmYWxzZSB9ICkgKTtcblx0XHR0aGlzLmNvbmUubWF0cml4QXV0b1VwZGF0ZSA9IGZhbHNlO1xuXHRcdHRoaXMuYWRkKCB0aGlzLmNvbmUgKTtcblxuXHRcdHRoaXMuc2V0RGlyZWN0aW9uKCBkaXIgKTtcblx0XHR0aGlzLnNldExlbmd0aCggbGVuZ3RoLCBoZWFkTGVuZ3RoLCBoZWFkV2lkdGggKTtcblxuXHR9XG5cblx0c2V0RGlyZWN0aW9uKCBkaXIgKSB7XG5cblx0XHQvLyBkaXIgaXMgYXNzdW1lZCB0byBiZSBub3JtYWxpemVkXG5cblx0XHRpZiAoIGRpci55ID4gMC45OTk5OSApIHtcblxuXHRcdFx0dGhpcy5xdWF0ZXJuaW9uLnNldCggMCwgMCwgMCwgMSApO1xuXG5cdFx0fSBlbHNlIGlmICggZGlyLnkgPCAtIDAuOTk5OTkgKSB7XG5cblx0XHRcdHRoaXMucXVhdGVybmlvbi5zZXQoIDEsIDAsIDAsIDAgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdF9heGlzLnNldCggZGlyLnosIDAsIC0gZGlyLnggKS5ub3JtYWxpemUoKTtcblxuXHRcdFx0Y29uc3QgcmFkaWFucyA9IE1hdGguYWNvcyggZGlyLnkgKTtcblxuXHRcdFx0dGhpcy5xdWF0ZXJuaW9uLnNldEZyb21BeGlzQW5nbGUoIF9heGlzLCByYWRpYW5zICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHNldExlbmd0aCggbGVuZ3RoLCBoZWFkTGVuZ3RoID0gbGVuZ3RoICogMC4yLCBoZWFkV2lkdGggPSBoZWFkTGVuZ3RoICogMC4yICkge1xuXG5cdFx0dGhpcy5saW5lLnNjYWxlLnNldCggMSwgTWF0aC5tYXgoIDAuMDAwMSwgbGVuZ3RoIC0gaGVhZExlbmd0aCApLCAxICk7IC8vIHNlZSAjMTc0NThcblx0XHR0aGlzLmxpbmUudXBkYXRlTWF0cml4KCk7XG5cblx0XHR0aGlzLmNvbmUuc2NhbGUuc2V0KCBoZWFkV2lkdGgsIGhlYWRMZW5ndGgsIGhlYWRXaWR0aCApO1xuXHRcdHRoaXMuY29uZS5wb3NpdGlvbi55ID0gbGVuZ3RoO1xuXHRcdHRoaXMuY29uZS51cGRhdGVNYXRyaXgoKTtcblxuXHR9XG5cblx0c2V0Q29sb3IoIGNvbG9yICkge1xuXG5cdFx0dGhpcy5saW5lLm1hdGVyaWFsLmNvbG9yLnNldCggY29sb3IgKTtcblx0XHR0aGlzLmNvbmUubWF0ZXJpYWwuY29sb3Iuc2V0KCBjb2xvciApO1xuXG5cdH1cblxuXHRjb3B5KCBzb3VyY2UgKSB7XG5cblx0XHRzdXBlci5jb3B5KCBzb3VyY2UsIGZhbHNlICk7XG5cblx0XHR0aGlzLmxpbmUuY29weSggc291cmNlLmxpbmUgKTtcblx0XHR0aGlzLmNvbmUuY29weSggc291cmNlLmNvbmUgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5saW5lLmdlb21ldHJ5LmRpc3Bvc2UoKTtcblx0XHR0aGlzLmxpbmUubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXHRcdHRoaXMuY29uZS5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5jb25lLm1hdGVyaWFsLmRpc3Bvc2UoKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQXhlc0hlbHBlciBleHRlbmRzIExpbmVTZWdtZW50cyB7XG5cblx0Y29uc3RydWN0b3IoIHNpemUgPSAxICkge1xuXG5cdFx0Y29uc3QgdmVydGljZXMgPSBbXG5cdFx0XHQwLCAwLCAwLFx0c2l6ZSwgMCwgMCxcblx0XHRcdDAsIDAsIDAsXHQwLCBzaXplLCAwLFxuXHRcdFx0MCwgMCwgMCxcdDAsIDAsIHNpemVcblx0XHRdO1xuXG5cdFx0Y29uc3QgY29sb3JzID0gW1xuXHRcdFx0MSwgMCwgMCxcdDEsIDAuNiwgMCxcblx0XHRcdDAsIDEsIDAsXHQwLjYsIDEsIDAsXG5cdFx0XHQwLCAwLCAxLFx0MCwgMC42LCAxXG5cdFx0XTtcblxuXHRcdGNvbnN0IGdlb21ldHJ5ID0gbmV3IEJ1ZmZlckdlb21ldHJ5KCk7XG5cdFx0Z2VvbWV0cnkuc2V0QXR0cmlidXRlKCAncG9zaXRpb24nLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggdmVydGljZXMsIDMgKSApO1xuXHRcdGdlb21ldHJ5LnNldEF0dHJpYnV0ZSggJ2NvbG9yJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIGNvbG9ycywgMyApICk7XG5cblx0XHRjb25zdCBtYXRlcmlhbCA9IG5ldyBMaW5lQmFzaWNNYXRlcmlhbCggeyB2ZXJ0ZXhDb2xvcnM6IHRydWUsIHRvbmVNYXBwZWQ6IGZhbHNlIH0gKTtcblxuXHRcdHN1cGVyKCBnZW9tZXRyeSwgbWF0ZXJpYWwgKTtcblxuXHRcdHRoaXMudHlwZSA9ICdBeGVzSGVscGVyJztcblxuXHR9XG5cblx0c2V0Q29sb3JzKCB4QXhpc0NvbG9yLCB5QXhpc0NvbG9yLCB6QXhpc0NvbG9yICkge1xuXG5cdFx0Y29uc3QgY29sb3IgPSBuZXcgQ29sb3IoKTtcblx0XHRjb25zdCBhcnJheSA9IHRoaXMuZ2VvbWV0cnkuYXR0cmlidXRlcy5jb2xvci5hcnJheTtcblxuXHRcdGNvbG9yLnNldCggeEF4aXNDb2xvciApO1xuXHRcdGNvbG9yLnRvQXJyYXkoIGFycmF5LCAwICk7XG5cdFx0Y29sb3IudG9BcnJheSggYXJyYXksIDMgKTtcblxuXHRcdGNvbG9yLnNldCggeUF4aXNDb2xvciApO1xuXHRcdGNvbG9yLnRvQXJyYXkoIGFycmF5LCA2ICk7XG5cdFx0Y29sb3IudG9BcnJheSggYXJyYXksIDkgKTtcblxuXHRcdGNvbG9yLnNldCggekF4aXNDb2xvciApO1xuXHRcdGNvbG9yLnRvQXJyYXkoIGFycmF5LCAxMiApO1xuXHRcdGNvbG9yLnRvQXJyYXkoIGFycmF5LCAxNSApO1xuXG5cdFx0dGhpcy5nZW9tZXRyeS5hdHRyaWJ1dGVzLmNvbG9yLm5lZWRzVXBkYXRlID0gdHJ1ZTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0fVxuXG59XG5cbmNsYXNzIFNoYXBlUGF0aCB7XG5cblx0Y29uc3RydWN0b3IoKSB7XG5cblx0XHR0aGlzLnR5cGUgPSAnU2hhcGVQYXRoJztcblxuXHRcdHRoaXMuY29sb3IgPSBuZXcgQ29sb3IoKTtcblxuXHRcdHRoaXMuc3ViUGF0aHMgPSBbXTtcblx0XHR0aGlzLmN1cnJlbnRQYXRoID0gbnVsbDtcblxuXHR9XG5cblx0bW92ZVRvKCB4LCB5ICkge1xuXG5cdFx0dGhpcy5jdXJyZW50UGF0aCA9IG5ldyBQYXRoKCk7XG5cdFx0dGhpcy5zdWJQYXRocy5wdXNoKCB0aGlzLmN1cnJlbnRQYXRoICk7XG5cdFx0dGhpcy5jdXJyZW50UGF0aC5tb3ZlVG8oIHgsIHkgKTtcblxuXHRcdHJldHVybiB0aGlzO1xuXG5cdH1cblxuXHRsaW5lVG8oIHgsIHkgKSB7XG5cblx0XHR0aGlzLmN1cnJlbnRQYXRoLmxpbmVUbyggeCwgeSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHF1YWRyYXRpY0N1cnZlVG8oIGFDUHgsIGFDUHksIGFYLCBhWSApIHtcblxuXHRcdHRoaXMuY3VycmVudFBhdGgucXVhZHJhdGljQ3VydmVUbyggYUNQeCwgYUNQeSwgYVgsIGFZICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0YmV6aWVyQ3VydmVUbyggYUNQMXgsIGFDUDF5LCBhQ1AyeCwgYUNQMnksIGFYLCBhWSApIHtcblxuXHRcdHRoaXMuY3VycmVudFBhdGguYmV6aWVyQ3VydmVUbyggYUNQMXgsIGFDUDF5LCBhQ1AyeCwgYUNQMnksIGFYLCBhWSApO1xuXG5cdFx0cmV0dXJuIHRoaXM7XG5cblx0fVxuXG5cdHNwbGluZVRocnUoIHB0cyApIHtcblxuXHRcdHRoaXMuY3VycmVudFBhdGguc3BsaW5lVGhydSggcHRzICk7XG5cblx0XHRyZXR1cm4gdGhpcztcblxuXHR9XG5cblx0dG9TaGFwZXMoIGlzQ0NXICkge1xuXG5cdFx0ZnVuY3Rpb24gdG9TaGFwZXNOb0hvbGVzKCBpblN1YnBhdGhzICkge1xuXG5cdFx0XHRjb25zdCBzaGFwZXMgPSBbXTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwLCBsID0gaW5TdWJwYXRocy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHRtcFBhdGggPSBpblN1YnBhdGhzWyBpIF07XG5cblx0XHRcdFx0Y29uc3QgdG1wU2hhcGUgPSBuZXcgU2hhcGUoKTtcblx0XHRcdFx0dG1wU2hhcGUuY3VydmVzID0gdG1wUGF0aC5jdXJ2ZXM7XG5cblx0XHRcdFx0c2hhcGVzLnB1c2goIHRtcFNoYXBlICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHNoYXBlcztcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGlzUG9pbnRJbnNpZGVQb2x5Z29uKCBpblB0LCBpblBvbHlnb24gKSB7XG5cblx0XHRcdGNvbnN0IHBvbHlMZW4gPSBpblBvbHlnb24ubGVuZ3RoO1xuXG5cdFx0XHQvLyBpblB0IG9uIHBvbHlnb24gY29udG91ciA9PiBpbW1lZGlhdGUgc3VjY2VzcyAgICBvclxuXHRcdFx0Ly8gdG9nZ2xpbmcgb2YgaW5zaWRlL291dHNpZGUgYXQgZXZlcnkgc2luZ2xlISBpbnRlcnNlY3Rpb24gcG9pbnQgb2YgYW4gZWRnZVxuXHRcdFx0Ly8gIHdpdGggdGhlIGhvcml6b250YWwgbGluZSB0aHJvdWdoIGluUHQsIGxlZnQgb2YgaW5QdFxuXHRcdFx0Ly8gIG5vdCBjb3VudGluZyBsb3dlclkgZW5kcG9pbnRzIG9mIGVkZ2VzIGFuZCB3aG9sZSBlZGdlcyBvbiB0aGF0IGxpbmVcblx0XHRcdGxldCBpbnNpZGUgPSBmYWxzZTtcblx0XHRcdGZvciAoIGxldCBwID0gcG9seUxlbiAtIDEsIHEgPSAwOyBxIDwgcG9seUxlbjsgcCA9IHEgKysgKSB7XG5cblx0XHRcdFx0bGV0IGVkZ2VMb3dQdCA9IGluUG9seWdvblsgcCBdO1xuXHRcdFx0XHRsZXQgZWRnZUhpZ2hQdCA9IGluUG9seWdvblsgcSBdO1xuXG5cdFx0XHRcdGxldCBlZGdlRHggPSBlZGdlSGlnaFB0LnggLSBlZGdlTG93UHQueDtcblx0XHRcdFx0bGV0IGVkZ2VEeSA9IGVkZ2VIaWdoUHQueSAtIGVkZ2VMb3dQdC55O1xuXG5cdFx0XHRcdGlmICggTWF0aC5hYnMoIGVkZ2VEeSApID4gTnVtYmVyLkVQU0lMT04gKSB7XG5cblx0XHRcdFx0XHQvLyBub3QgcGFyYWxsZWxcblx0XHRcdFx0XHRpZiAoIGVkZ2VEeSA8IDAgKSB7XG5cblx0XHRcdFx0XHRcdGVkZ2VMb3dQdCA9IGluUG9seWdvblsgcSBdOyBlZGdlRHggPSAtIGVkZ2VEeDtcblx0XHRcdFx0XHRcdGVkZ2VIaWdoUHQgPSBpblBvbHlnb25bIHAgXTsgZWRnZUR5ID0gLSBlZGdlRHk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRpZiAoICggaW5QdC55IDwgZWRnZUxvd1B0LnkgKSB8fCAoIGluUHQueSA+IGVkZ2VIaWdoUHQueSApICkgXHRcdGNvbnRpbnVlO1xuXG5cdFx0XHRcdFx0aWYgKCBpblB0LnkgPT09IGVkZ2VMb3dQdC55ICkge1xuXG5cdFx0XHRcdFx0XHRpZiAoIGluUHQueCA9PT0gZWRnZUxvd1B0LnggKVx0XHRyZXR1cm5cdHRydWU7XHRcdC8vIGluUHQgaXMgb24gY29udG91ciA/XG5cdFx0XHRcdFx0XHQvLyBjb250aW51ZTtcdFx0XHRcdC8vIG5vIGludGVyc2VjdGlvbiBvciBlZGdlTG93UHQgPT4gZG9lc24ndCBjb3VudCAhISFcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGNvbnN0IHBlcnBFZGdlID0gZWRnZUR5ICogKCBpblB0LnggLSBlZGdlTG93UHQueCApIC0gZWRnZUR4ICogKCBpblB0LnkgLSBlZGdlTG93UHQueSApO1xuXHRcdFx0XHRcdFx0aWYgKCBwZXJwRWRnZSA9PT0gMCApXHRcdFx0XHRyZXR1cm5cdHRydWU7XHRcdC8vIGluUHQgaXMgb24gY29udG91ciA/XG5cdFx0XHRcdFx0XHRpZiAoIHBlcnBFZGdlIDwgMCApIFx0XHRcdFx0Y29udGludWU7XG5cdFx0XHRcdFx0XHRpbnNpZGUgPSAhIGluc2lkZTtcdFx0Ly8gdHJ1ZSBpbnRlcnNlY3Rpb24gbGVmdCBvZiBpblB0XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdC8vIHBhcmFsbGVsIG9yIGNvbGxpbmVhclxuXHRcdFx0XHRcdGlmICggaW5QdC55ICE9PSBlZGdlTG93UHQueSApIFx0XHRjb250aW51ZTtcdFx0XHQvLyBwYXJhbGxlbFxuXHRcdFx0XHRcdC8vIGVkZ2UgbGllcyBvbiB0aGUgc2FtZSBob3Jpem9udGFsIGxpbmUgYXMgaW5QdFxuXHRcdFx0XHRcdGlmICggKCAoIGVkZ2VIaWdoUHQueCA8PSBpblB0LnggKSAmJiAoIGluUHQueCA8PSBlZGdlTG93UHQueCApICkgfHxcblx0XHRcdFx0XHRcdCAoICggZWRnZUxvd1B0LnggPD0gaW5QdC54ICkgJiYgKCBpblB0LnggPD0gZWRnZUhpZ2hQdC54ICkgKSApXHRcdHJldHVyblx0dHJ1ZTtcdC8vIGluUHQ6IFBvaW50IG9uIGNvbnRvdXIgIVxuXHRcdFx0XHRcdC8vIGNvbnRpbnVlO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm5cdGluc2lkZTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGlzQ2xvY2tXaXNlID0gU2hhcGVVdGlscy5pc0Nsb2NrV2lzZTtcblxuXHRcdGNvbnN0IHN1YlBhdGhzID0gdGhpcy5zdWJQYXRocztcblx0XHRpZiAoIHN1YlBhdGhzLmxlbmd0aCA9PT0gMCApIHJldHVybiBbXTtcblxuXHRcdGxldCBzb2xpZCwgdG1wUGF0aCwgdG1wU2hhcGU7XG5cdFx0Y29uc3Qgc2hhcGVzID0gW107XG5cblx0XHRpZiAoIHN1YlBhdGhzLmxlbmd0aCA9PT0gMSApIHtcblxuXHRcdFx0dG1wUGF0aCA9IHN1YlBhdGhzWyAwIF07XG5cdFx0XHR0bXBTaGFwZSA9IG5ldyBTaGFwZSgpO1xuXHRcdFx0dG1wU2hhcGUuY3VydmVzID0gdG1wUGF0aC5jdXJ2ZXM7XG5cdFx0XHRzaGFwZXMucHVzaCggdG1wU2hhcGUgKTtcblx0XHRcdHJldHVybiBzaGFwZXM7XG5cblx0XHR9XG5cblx0XHRsZXQgaG9sZXNGaXJzdCA9ICEgaXNDbG9ja1dpc2UoIHN1YlBhdGhzWyAwIF0uZ2V0UG9pbnRzKCkgKTtcblx0XHRob2xlc0ZpcnN0ID0gaXNDQ1cgPyAhIGhvbGVzRmlyc3QgOiBob2xlc0ZpcnN0O1xuXG5cdFx0Ly8gY29uc29sZS5sb2coXCJIb2xlcyBmaXJzdFwiLCBob2xlc0ZpcnN0KTtcblxuXHRcdGNvbnN0IGJldHRlclNoYXBlSG9sZXMgPSBbXTtcblx0XHRjb25zdCBuZXdTaGFwZXMgPSBbXTtcblx0XHRsZXQgbmV3U2hhcGVIb2xlcyA9IFtdO1xuXHRcdGxldCBtYWluSWR4ID0gMDtcblx0XHRsZXQgdG1wUG9pbnRzO1xuXG5cdFx0bmV3U2hhcGVzWyBtYWluSWR4IF0gPSB1bmRlZmluZWQ7XG5cdFx0bmV3U2hhcGVIb2xlc1sgbWFpbklkeCBdID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDAsIGwgPSBzdWJQYXRocy5sZW5ndGg7IGkgPCBsOyBpICsrICkge1xuXG5cdFx0XHR0bXBQYXRoID0gc3ViUGF0aHNbIGkgXTtcblx0XHRcdHRtcFBvaW50cyA9IHRtcFBhdGguZ2V0UG9pbnRzKCk7XG5cdFx0XHRzb2xpZCA9IGlzQ2xvY2tXaXNlKCB0bXBQb2ludHMgKTtcblx0XHRcdHNvbGlkID0gaXNDQ1cgPyAhIHNvbGlkIDogc29saWQ7XG5cblx0XHRcdGlmICggc29saWQgKSB7XG5cblx0XHRcdFx0aWYgKCAoICEgaG9sZXNGaXJzdCApICYmICggbmV3U2hhcGVzWyBtYWluSWR4IF0gKSApXHRtYWluSWR4ICsrO1xuXG5cdFx0XHRcdG5ld1NoYXBlc1sgbWFpbklkeCBdID0geyBzOiBuZXcgU2hhcGUoKSwgcDogdG1wUG9pbnRzIH07XG5cdFx0XHRcdG5ld1NoYXBlc1sgbWFpbklkeCBdLnMuY3VydmVzID0gdG1wUGF0aC5jdXJ2ZXM7XG5cblx0XHRcdFx0aWYgKCBob2xlc0ZpcnN0IClcdG1haW5JZHggKys7XG5cdFx0XHRcdG5ld1NoYXBlSG9sZXNbIG1haW5JZHggXSA9IFtdO1xuXG5cdFx0XHRcdC8vY29uc29sZS5sb2coJ2N3JywgaSk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0bmV3U2hhcGVIb2xlc1sgbWFpbklkeCBdLnB1c2goIHsgaDogdG1wUGF0aCwgcDogdG1wUG9pbnRzWyAwIF0gfSApO1xuXG5cdFx0XHRcdC8vY29uc29sZS5sb2coJ2NjdycsIGkpO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvLyBvbmx5IEhvbGVzPyAtPiBwcm9iYWJseSBhbGwgU2hhcGVzIHdpdGggd3Jvbmcgb3JpZW50YXRpb25cblx0XHRpZiAoICEgbmV3U2hhcGVzWyAwIF0gKVx0cmV0dXJuXHR0b1NoYXBlc05vSG9sZXMoIHN1YlBhdGhzICk7XG5cblxuXHRcdGlmICggbmV3U2hhcGVzLmxlbmd0aCA+IDEgKSB7XG5cblx0XHRcdGxldCBhbWJpZ3VvdXMgPSBmYWxzZTtcblx0XHRcdGxldCB0b0NoYW5nZSA9IDA7XG5cblx0XHRcdGZvciAoIGxldCBzSWR4ID0gMCwgc0xlbiA9IG5ld1NoYXBlcy5sZW5ndGg7IHNJZHggPCBzTGVuOyBzSWR4ICsrICkge1xuXG5cdFx0XHRcdGJldHRlclNoYXBlSG9sZXNbIHNJZHggXSA9IFtdO1xuXG5cdFx0XHR9XG5cblx0XHRcdGZvciAoIGxldCBzSWR4ID0gMCwgc0xlbiA9IG5ld1NoYXBlcy5sZW5ndGg7IHNJZHggPCBzTGVuOyBzSWR4ICsrICkge1xuXG5cdFx0XHRcdGNvbnN0IHNobyA9IG5ld1NoYXBlSG9sZXNbIHNJZHggXTtcblxuXHRcdFx0XHRmb3IgKCBsZXQgaElkeCA9IDA7IGhJZHggPCBzaG8ubGVuZ3RoOyBoSWR4ICsrICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgaG8gPSBzaG9bIGhJZHggXTtcblx0XHRcdFx0XHRsZXQgaG9sZV91bmFzc2lnbmVkID0gdHJ1ZTtcblxuXHRcdFx0XHRcdGZvciAoIGxldCBzMklkeCA9IDA7IHMySWR4IDwgbmV3U2hhcGVzLmxlbmd0aDsgczJJZHggKysgKSB7XG5cblx0XHRcdFx0XHRcdGlmICggaXNQb2ludEluc2lkZVBvbHlnb24oIGhvLnAsIG5ld1NoYXBlc1sgczJJZHggXS5wICkgKSB7XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBzSWR4ICE9PSBzMklkeCApXHR0b0NoYW5nZSArKztcblxuXHRcdFx0XHRcdFx0XHRpZiAoIGhvbGVfdW5hc3NpZ25lZCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdGhvbGVfdW5hc3NpZ25lZCA9IGZhbHNlO1xuXHRcdFx0XHRcdFx0XHRcdGJldHRlclNoYXBlSG9sZXNbIHMySWR4IF0ucHVzaCggaG8gKTtcblxuXHRcdFx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRcdFx0YW1iaWd1b3VzID0gdHJ1ZTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGlmICggaG9sZV91bmFzc2lnbmVkICkge1xuXG5cdFx0XHRcdFx0XHRiZXR0ZXJTaGFwZUhvbGVzWyBzSWR4IF0ucHVzaCggaG8gKTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCB0b0NoYW5nZSA+IDAgJiYgYW1iaWd1b3VzID09PSBmYWxzZSApIHtcblxuXHRcdFx0XHRuZXdTaGFwZUhvbGVzID0gYmV0dGVyU2hhcGVIb2xlcztcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0bGV0IHRtcEhvbGVzO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwLCBpbCA9IG5ld1NoYXBlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0dG1wU2hhcGUgPSBuZXdTaGFwZXNbIGkgXS5zO1xuXHRcdFx0c2hhcGVzLnB1c2goIHRtcFNoYXBlICk7XG5cdFx0XHR0bXBIb2xlcyA9IG5ld1NoYXBlSG9sZXNbIGkgXTtcblxuXHRcdFx0Zm9yICggbGV0IGogPSAwLCBqbCA9IHRtcEhvbGVzLmxlbmd0aDsgaiA8IGpsOyBqICsrICkge1xuXG5cdFx0XHRcdHRtcFNoYXBlLmhvbGVzLnB1c2goIHRtcEhvbGVzWyBqIF0uaCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHQvL2NvbnNvbGUubG9nKFwic2hhcGVcIiwgc2hhcGVzKTtcblxuXHRcdHJldHVybiBzaGFwZXM7XG5cblx0fVxuXG59XG5cbmNsYXNzIFdlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzIGV4dGVuZHMgV2ViR0xSZW5kZXJUYXJnZXQgeyAvLyBAZGVwcmVjYXRlZCwgcjE2MlxuXG5cdGNvbnN0cnVjdG9yKCB3aWR0aCA9IDEsIGhlaWdodCA9IDEsIGNvdW50ID0gMSwgb3B0aW9ucyA9IHt9ICkge1xuXG5cdFx0Y29uc29sZS53YXJuKCAnVEhSRUUuV2ViR0xNdWx0aXBsZVJlbmRlclRhcmdldHMgaGFzIGJlZW4gZGVwcmVjYXRlZCBhbmQgd2lsbCBiZSByZW1vdmVkIGluIHIxNzIuIFVzZSBUSFJFRS5XZWJHTFJlbmRlclRhcmdldCBhbmQgc2V0IHRoZSBcImNvdW50XCIgcGFyYW1ldGVyIHRvIGVuYWJsZSBNUlQuJyApO1xuXG5cdFx0c3VwZXIoIHdpZHRoLCBoZWlnaHQsIHsgLi4ub3B0aW9ucywgY291bnQgfSApO1xuXG5cdFx0dGhpcy5pc1dlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzID0gdHJ1ZTtcblxuXHR9XG5cblx0Z2V0IHRleHR1cmUoKSB7XG5cblx0XHRyZXR1cm4gdGhpcy50ZXh0dXJlcztcblxuXHR9XG5cbn1cblxuaWYgKCB0eXBlb2YgX19USFJFRV9ERVZUT09MU19fICE9PSAndW5kZWZpbmVkJyApIHtcblxuXHRfX1RIUkVFX0RFVlRPT0xTX18uZGlzcGF0Y2hFdmVudCggbmV3IEN1c3RvbUV2ZW50KCAncmVnaXN0ZXInLCB7IGRldGFpbDoge1xuXHRcdHJldmlzaW9uOiBSRVZJU0lPTixcblx0fSB9ICkgKTtcblxufVxuXG5pZiAoIHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnICkge1xuXG5cdGlmICggd2luZG93Ll9fVEhSRUVfXyApIHtcblxuXHRcdGNvbnNvbGUud2FybiggJ1dBUk5JTkc6IE11bHRpcGxlIGluc3RhbmNlcyBvZiBUaHJlZS5qcyBiZWluZyBpbXBvcnRlZC4nICk7XG5cblx0fSBlbHNlIHtcblxuXHRcdHdpbmRvdy5fX1RIUkVFX18gPSBSRVZJU0lPTjtcblxuXHR9XG5cbn1cblxuZXhwb3J0IHsgQUNFU0ZpbG1pY1RvbmVNYXBwaW5nLCBBZGRFcXVhdGlvbiwgQWRkT3BlcmF0aW9uLCBBZGRpdGl2ZUFuaW1hdGlvbkJsZW5kTW9kZSwgQWRkaXRpdmVCbGVuZGluZywgQWdYVG9uZU1hcHBpbmcsIEFscGhhRm9ybWF0LCBBbHdheXNDb21wYXJlLCBBbHdheXNEZXB0aCwgQWx3YXlzU3RlbmNpbEZ1bmMsIEFtYmllbnRMaWdodCwgQW5pbWF0aW9uQWN0aW9uLCBBbmltYXRpb25DbGlwLCBBbmltYXRpb25Mb2FkZXIsIEFuaW1hdGlvbk1peGVyLCBBbmltYXRpb25PYmplY3RHcm91cCwgQW5pbWF0aW9uVXRpbHMsIEFyY0N1cnZlLCBBcnJheUNhbWVyYSwgQXJyb3dIZWxwZXIsIEF0dGFjaGVkQmluZE1vZGUsIEF1ZGlvLCBBdWRpb0FuYWx5c2VyLCBBdWRpb0NvbnRleHQsIEF1ZGlvTGlzdGVuZXIsIEF1ZGlvTG9hZGVyLCBBeGVzSGVscGVyLCBCYWNrU2lkZSwgQmFzaWNEZXB0aFBhY2tpbmcsIEJhc2ljU2hhZG93TWFwLCBCYXRjaGVkTWVzaCwgQm9uZSwgQm9vbGVhbktleWZyYW1lVHJhY2ssIEJveDIsIEJveDMsIEJveDNIZWxwZXIsIEJveEdlb21ldHJ5LCBCb3hIZWxwZXIsIEJ1ZmZlckF0dHJpYnV0ZSwgQnVmZmVyR2VvbWV0cnksIEJ1ZmZlckdlb21ldHJ5TG9hZGVyLCBCeXRlVHlwZSwgQ2FjaGUsIENhbWVyYSwgQ2FtZXJhSGVscGVyLCBDYW52YXNUZXh0dXJlLCBDYXBzdWxlR2VvbWV0cnksIENhdG11bGxSb21DdXJ2ZTMsIENpbmVvblRvbmVNYXBwaW5nLCBDaXJjbGVHZW9tZXRyeSwgQ2xhbXBUb0VkZ2VXcmFwcGluZywgQ2xvY2ssIENvbG9yLCBDb2xvcktleWZyYW1lVHJhY2ssIENvbG9yTWFuYWdlbWVudCwgQ29tcHJlc3NlZEFycmF5VGV4dHVyZSwgQ29tcHJlc3NlZEN1YmVUZXh0dXJlLCBDb21wcmVzc2VkVGV4dHVyZSwgQ29tcHJlc3NlZFRleHR1cmVMb2FkZXIsIENvbmVHZW9tZXRyeSwgQ29uc3RhbnRBbHBoYUZhY3RvciwgQ29uc3RhbnRDb2xvckZhY3RvciwgQ3ViZUNhbWVyYSwgQ3ViZVJlZmxlY3Rpb25NYXBwaW5nLCBDdWJlUmVmcmFjdGlvbk1hcHBpbmcsIEN1YmVUZXh0dXJlLCBDdWJlVGV4dHVyZUxvYWRlciwgQ3ViZVVWUmVmbGVjdGlvbk1hcHBpbmcsIEN1YmljQmV6aWVyQ3VydmUsIEN1YmljQmV6aWVyQ3VydmUzLCBDdWJpY0ludGVycG9sYW50LCBDdWxsRmFjZUJhY2ssIEN1bGxGYWNlRnJvbnQsIEN1bGxGYWNlRnJvbnRCYWNrLCBDdWxsRmFjZU5vbmUsIEN1cnZlLCBDdXJ2ZVBhdGgsIEN1c3RvbUJsZW5kaW5nLCBDdXN0b21Ub25lTWFwcGluZywgQ3lsaW5kZXJHZW9tZXRyeSwgQ3lsaW5kcmljYWwsIERhdGEzRFRleHR1cmUsIERhdGFBcnJheVRleHR1cmUsIERhdGFUZXh0dXJlLCBEYXRhVGV4dHVyZUxvYWRlciwgRGF0YVV0aWxzLCBEZWNyZW1lbnRTdGVuY2lsT3AsIERlY3JlbWVudFdyYXBTdGVuY2lsT3AsIERlZmF1bHRMb2FkaW5nTWFuYWdlciwgRGVwdGhGb3JtYXQsIERlcHRoU3RlbmNpbEZvcm1hdCwgRGVwdGhUZXh0dXJlLCBEZXRhY2hlZEJpbmRNb2RlLCBEaXJlY3Rpb25hbExpZ2h0LCBEaXJlY3Rpb25hbExpZ2h0SGVscGVyLCBEaXNjcmV0ZUludGVycG9sYW50LCBEaXNwbGF5UDNDb2xvclNwYWNlLCBEb2RlY2FoZWRyb25HZW9tZXRyeSwgRG91YmxlU2lkZSwgRHN0QWxwaGFGYWN0b3IsIERzdENvbG9yRmFjdG9yLCBEeW5hbWljQ29weVVzYWdlLCBEeW5hbWljRHJhd1VzYWdlLCBEeW5hbWljUmVhZFVzYWdlLCBFZGdlc0dlb21ldHJ5LCBFbGxpcHNlQ3VydmUsIEVxdWFsQ29tcGFyZSwgRXF1YWxEZXB0aCwgRXF1YWxTdGVuY2lsRnVuYywgRXF1aXJlY3Rhbmd1bGFyUmVmbGVjdGlvbk1hcHBpbmcsIEVxdWlyZWN0YW5ndWxhclJlZnJhY3Rpb25NYXBwaW5nLCBFdWxlciwgRXZlbnREaXNwYXRjaGVyLCBFeHRydWRlR2VvbWV0cnksIEZpbGVMb2FkZXIsIEZsb2F0MTZCdWZmZXJBdHRyaWJ1dGUsIEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUsIEZsb2F0VHlwZSwgRm9nLCBGb2dFeHAyLCBGcmFtZWJ1ZmZlclRleHR1cmUsIEZyb250U2lkZSwgRnJ1c3R1bSwgR0xCdWZmZXJBdHRyaWJ1dGUsIEdMU0wxLCBHTFNMMywgR3JlYXRlckNvbXBhcmUsIEdyZWF0ZXJEZXB0aCwgR3JlYXRlckVxdWFsQ29tcGFyZSwgR3JlYXRlckVxdWFsRGVwdGgsIEdyZWF0ZXJFcXVhbFN0ZW5jaWxGdW5jLCBHcmVhdGVyU3RlbmNpbEZ1bmMsIEdyaWRIZWxwZXIsIEdyb3VwLCBIYWxmRmxvYXRUeXBlLCBIZW1pc3BoZXJlTGlnaHQsIEhlbWlzcGhlcmVMaWdodEhlbHBlciwgSWNvc2FoZWRyb25HZW9tZXRyeSwgSW1hZ2VCaXRtYXBMb2FkZXIsIEltYWdlTG9hZGVyLCBJbWFnZVV0aWxzLCBJbmNyZW1lbnRTdGVuY2lsT3AsIEluY3JlbWVudFdyYXBTdGVuY2lsT3AsIEluc3RhbmNlZEJ1ZmZlckF0dHJpYnV0ZSwgSW5zdGFuY2VkQnVmZmVyR2VvbWV0cnksIEluc3RhbmNlZEludGVybGVhdmVkQnVmZmVyLCBJbnN0YW5jZWRNZXNoLCBJbnQxNkJ1ZmZlckF0dHJpYnV0ZSwgSW50MzJCdWZmZXJBdHRyaWJ1dGUsIEludDhCdWZmZXJBdHRyaWJ1dGUsIEludFR5cGUsIEludGVybGVhdmVkQnVmZmVyLCBJbnRlcmxlYXZlZEJ1ZmZlckF0dHJpYnV0ZSwgSW50ZXJwb2xhbnQsIEludGVycG9sYXRlRGlzY3JldGUsIEludGVycG9sYXRlTGluZWFyLCBJbnRlcnBvbGF0ZVNtb290aCwgSW52ZXJ0U3RlbmNpbE9wLCBLZWVwU3RlbmNpbE9wLCBLZXlmcmFtZVRyYWNrLCBMT0QsIExhdGhlR2VvbWV0cnksIExheWVycywgTGVzc0NvbXBhcmUsIExlc3NEZXB0aCwgTGVzc0VxdWFsQ29tcGFyZSwgTGVzc0VxdWFsRGVwdGgsIExlc3NFcXVhbFN0ZW5jaWxGdW5jLCBMZXNzU3RlbmNpbEZ1bmMsIExpZ2h0LCBMaWdodFByb2JlLCBMaW5lLCBMaW5lMywgTGluZUJhc2ljTWF0ZXJpYWwsIExpbmVDdXJ2ZSwgTGluZUN1cnZlMywgTGluZURhc2hlZE1hdGVyaWFsLCBMaW5lTG9vcCwgTGluZVNlZ21lbnRzLCBMaW5lYXJEaXNwbGF5UDNDb2xvclNwYWNlLCBMaW5lYXJGaWx0ZXIsIExpbmVhckludGVycG9sYW50LCBMaW5lYXJNaXBNYXBMaW5lYXJGaWx0ZXIsIExpbmVhck1pcE1hcE5lYXJlc3RGaWx0ZXIsIExpbmVhck1pcG1hcExpbmVhckZpbHRlciwgTGluZWFyTWlwbWFwTmVhcmVzdEZpbHRlciwgTGluZWFyU1JHQkNvbG9yU3BhY2UsIExpbmVhclRvbmVNYXBwaW5nLCBMaW5lYXJUcmFuc2ZlciwgTG9hZGVyLCBMb2FkZXJVdGlscywgTG9hZGluZ01hbmFnZXIsIExvb3BPbmNlLCBMb29wUGluZ1BvbmcsIExvb3BSZXBlYXQsIEx1bWluYW5jZUFscGhhRm9ybWF0LCBMdW1pbmFuY2VGb3JtYXQsIE1PVVNFLCBNYXRlcmlhbCwgTWF0ZXJpYWxMb2FkZXIsIE1hdGhVdGlscywgTWF0cml4MiwgTWF0cml4MywgTWF0cml4NCwgTWF4RXF1YXRpb24sIE1lc2gsIE1lc2hCYXNpY01hdGVyaWFsLCBNZXNoRGVwdGhNYXRlcmlhbCwgTWVzaERpc3RhbmNlTWF0ZXJpYWwsIE1lc2hMYW1iZXJ0TWF0ZXJpYWwsIE1lc2hNYXRjYXBNYXRlcmlhbCwgTWVzaE5vcm1hbE1hdGVyaWFsLCBNZXNoUGhvbmdNYXRlcmlhbCwgTWVzaFBoeXNpY2FsTWF0ZXJpYWwsIE1lc2hTdGFuZGFyZE1hdGVyaWFsLCBNZXNoVG9vbk1hdGVyaWFsLCBNaW5FcXVhdGlvbiwgTWlycm9yZWRSZXBlYXRXcmFwcGluZywgTWl4T3BlcmF0aW9uLCBNdWx0aXBseUJsZW5kaW5nLCBNdWx0aXBseU9wZXJhdGlvbiwgTmVhcmVzdEZpbHRlciwgTmVhcmVzdE1pcE1hcExpbmVhckZpbHRlciwgTmVhcmVzdE1pcE1hcE5lYXJlc3RGaWx0ZXIsIE5lYXJlc3RNaXBtYXBMaW5lYXJGaWx0ZXIsIE5lYXJlc3RNaXBtYXBOZWFyZXN0RmlsdGVyLCBOZXV0cmFsVG9uZU1hcHBpbmcsIE5ldmVyQ29tcGFyZSwgTmV2ZXJEZXB0aCwgTmV2ZXJTdGVuY2lsRnVuYywgTm9CbGVuZGluZywgTm9Db2xvclNwYWNlLCBOb1RvbmVNYXBwaW5nLCBOb3JtYWxBbmltYXRpb25CbGVuZE1vZGUsIE5vcm1hbEJsZW5kaW5nLCBOb3RFcXVhbENvbXBhcmUsIE5vdEVxdWFsRGVwdGgsIE5vdEVxdWFsU3RlbmNpbEZ1bmMsIE51bWJlcktleWZyYW1lVHJhY2ssIE9iamVjdDNELCBPYmplY3RMb2FkZXIsIE9iamVjdFNwYWNlTm9ybWFsTWFwLCBPY3RhaGVkcm9uR2VvbWV0cnksIE9uZUZhY3RvciwgT25lTWludXNDb25zdGFudEFscGhhRmFjdG9yLCBPbmVNaW51c0NvbnN0YW50Q29sb3JGYWN0b3IsIE9uZU1pbnVzRHN0QWxwaGFGYWN0b3IsIE9uZU1pbnVzRHN0Q29sb3JGYWN0b3IsIE9uZU1pbnVzU3JjQWxwaGFGYWN0b3IsIE9uZU1pbnVzU3JjQ29sb3JGYWN0b3IsIE9ydGhvZ3JhcGhpY0NhbWVyYSwgUDNQcmltYXJpZXMsIFBDRlNoYWRvd01hcCwgUENGU29mdFNoYWRvd01hcCwgUE1SRU1HZW5lcmF0b3IsIFBhdGgsIFBlcnNwZWN0aXZlQ2FtZXJhLCBQbGFuZSwgUGxhbmVHZW9tZXRyeSwgUGxhbmVIZWxwZXIsIFBvaW50TGlnaHQsIFBvaW50TGlnaHRIZWxwZXIsIFBvaW50cywgUG9pbnRzTWF0ZXJpYWwsIFBvbGFyR3JpZEhlbHBlciwgUG9seWhlZHJvbkdlb21ldHJ5LCBQb3NpdGlvbmFsQXVkaW8sIFByb3BlcnR5QmluZGluZywgUHJvcGVydHlNaXhlciwgUXVhZHJhdGljQmV6aWVyQ3VydmUsIFF1YWRyYXRpY0JlemllckN1cnZlMywgUXVhdGVybmlvbiwgUXVhdGVybmlvbktleWZyYW1lVHJhY2ssIFF1YXRlcm5pb25MaW5lYXJJbnRlcnBvbGFudCwgUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCwgUkVEX1JHVEMxX0Zvcm1hdCwgUkVWSVNJT04sIFJHQkFEZXB0aFBhY2tpbmcsIFJHQkFGb3JtYXQsIFJHQkFJbnRlZ2VyRm9ybWF0LCBSR0JBX0FTVENfMTB4MTBfRm9ybWF0LCBSR0JBX0FTVENfMTB4NV9Gb3JtYXQsIFJHQkFfQVNUQ18xMHg2X0Zvcm1hdCwgUkdCQV9BU1RDXzEweDhfRm9ybWF0LCBSR0JBX0FTVENfMTJ4MTBfRm9ybWF0LCBSR0JBX0FTVENfMTJ4MTJfRm9ybWF0LCBSR0JBX0FTVENfNHg0X0Zvcm1hdCwgUkdCQV9BU1RDXzV4NF9Gb3JtYXQsIFJHQkFfQVNUQ181eDVfRm9ybWF0LCBSR0JBX0FTVENfNng1X0Zvcm1hdCwgUkdCQV9BU1RDXzZ4Nl9Gb3JtYXQsIFJHQkFfQVNUQ184eDVfRm9ybWF0LCBSR0JBX0FTVENfOHg2X0Zvcm1hdCwgUkdCQV9BU1RDXzh4OF9Gb3JtYXQsIFJHQkFfQlBUQ19Gb3JtYXQsIFJHQkFfRVRDMl9FQUNfRm9ybWF0LCBSR0JBX1BWUlRDXzJCUFBWMV9Gb3JtYXQsIFJHQkFfUFZSVENfNEJQUFYxX0Zvcm1hdCwgUkdCQV9TM1RDX0RYVDFfRm9ybWF0LCBSR0JBX1MzVENfRFhUM19Gb3JtYXQsIFJHQkFfUzNUQ19EWFQ1X0Zvcm1hdCwgUkdCRGVwdGhQYWNraW5nLCBSR0JGb3JtYXQsIFJHQkludGVnZXJGb3JtYXQsIFJHQl9CUFRDX1NJR05FRF9Gb3JtYXQsIFJHQl9CUFRDX1VOU0lHTkVEX0Zvcm1hdCwgUkdCX0VUQzFfRm9ybWF0LCBSR0JfRVRDMl9Gb3JtYXQsIFJHQl9QVlJUQ18yQlBQVjFfRm9ybWF0LCBSR0JfUFZSVENfNEJQUFYxX0Zvcm1hdCwgUkdCX1MzVENfRFhUMV9Gb3JtYXQsIFJHRGVwdGhQYWNraW5nLCBSR0Zvcm1hdCwgUkdJbnRlZ2VyRm9ybWF0LCBSYXdTaGFkZXJNYXRlcmlhbCwgUmF5LCBSYXljYXN0ZXIsIFJlYzcwOVByaW1hcmllcywgUmVjdEFyZWFMaWdodCwgUmVkRm9ybWF0LCBSZWRJbnRlZ2VyRm9ybWF0LCBSZWluaGFyZFRvbmVNYXBwaW5nLCBSZW5kZXJUYXJnZXQsIFJlcGVhdFdyYXBwaW5nLCBSZXBsYWNlU3RlbmNpbE9wLCBSZXZlcnNlU3VidHJhY3RFcXVhdGlvbiwgUmluZ0dlb21ldHJ5LCBTSUdORURfUkVEX0dSRUVOX1JHVEMyX0Zvcm1hdCwgU0lHTkVEX1JFRF9SR1RDMV9Gb3JtYXQsIFNSR0JDb2xvclNwYWNlLCBTUkdCVHJhbnNmZXIsIFNjZW5lLCBTaGFkZXJDaHVuaywgU2hhZGVyTGliLCBTaGFkZXJNYXRlcmlhbCwgU2hhZG93TWF0ZXJpYWwsIFNoYXBlLCBTaGFwZUdlb21ldHJ5LCBTaGFwZVBhdGgsIFNoYXBlVXRpbHMsIFNob3J0VHlwZSwgU2tlbGV0b24sIFNrZWxldG9uSGVscGVyLCBTa2lubmVkTWVzaCwgU291cmNlLCBTcGhlcmUsIFNwaGVyZUdlb21ldHJ5LCBTcGhlcmljYWwsIFNwaGVyaWNhbEhhcm1vbmljczMsIFNwbGluZUN1cnZlLCBTcG90TGlnaHQsIFNwb3RMaWdodEhlbHBlciwgU3ByaXRlLCBTcHJpdGVNYXRlcmlhbCwgU3JjQWxwaGFGYWN0b3IsIFNyY0FscGhhU2F0dXJhdGVGYWN0b3IsIFNyY0NvbG9yRmFjdG9yLCBTdGF0aWNDb3B5VXNhZ2UsIFN0YXRpY0RyYXdVc2FnZSwgU3RhdGljUmVhZFVzYWdlLCBTdGVyZW9DYW1lcmEsIFN0cmVhbUNvcHlVc2FnZSwgU3RyZWFtRHJhd1VzYWdlLCBTdHJlYW1SZWFkVXNhZ2UsIFN0cmluZ0tleWZyYW1lVHJhY2ssIFN1YnRyYWN0RXF1YXRpb24sIFN1YnRyYWN0aXZlQmxlbmRpbmcsIFRPVUNILCBUYW5nZW50U3BhY2VOb3JtYWxNYXAsIFRldHJhaGVkcm9uR2VvbWV0cnksIFRleHR1cmUsIFRleHR1cmVMb2FkZXIsIFRleHR1cmVVdGlscywgVG9ydXNHZW9tZXRyeSwgVG9ydXNLbm90R2VvbWV0cnksIFRyaWFuZ2xlLCBUcmlhbmdsZUZhbkRyYXdNb2RlLCBUcmlhbmdsZVN0cmlwRHJhd01vZGUsIFRyaWFuZ2xlc0RyYXdNb2RlLCBUdWJlR2VvbWV0cnksIFVWTWFwcGluZywgVWludDE2QnVmZmVyQXR0cmlidXRlLCBVaW50MzJCdWZmZXJBdHRyaWJ1dGUsIFVpbnQ4QnVmZmVyQXR0cmlidXRlLCBVaW50OENsYW1wZWRCdWZmZXJBdHRyaWJ1dGUsIFVuaWZvcm0sIFVuaWZvcm1zR3JvdXAsIFVuaWZvcm1zTGliLCBVbmlmb3Jtc1V0aWxzLCBVbnNpZ25lZEJ5dGVUeXBlLCBVbnNpZ25lZEludDI0OFR5cGUsIFVuc2lnbmVkSW50NTk5OVR5cGUsIFVuc2lnbmVkSW50VHlwZSwgVW5zaWduZWRTaG9ydDQ0NDRUeXBlLCBVbnNpZ25lZFNob3J0NTU1MVR5cGUsIFVuc2lnbmVkU2hvcnRUeXBlLCBWU01TaGFkb3dNYXAsIFZlY3RvcjIsIFZlY3RvcjMsIFZlY3RvcjQsIFZlY3RvcktleWZyYW1lVHJhY2ssIFZpZGVvVGV4dHVyZSwgV2ViR0wzRFJlbmRlclRhcmdldCwgV2ViR0xBcnJheVJlbmRlclRhcmdldCwgV2ViR0xDb29yZGluYXRlU3lzdGVtLCBXZWJHTEN1YmVSZW5kZXJUYXJnZXQsIFdlYkdMTXVsdGlwbGVSZW5kZXJUYXJnZXRzLCBXZWJHTFJlbmRlclRhcmdldCwgV2ViR0xSZW5kZXJlciwgV2ViR0xVdGlscywgV2ViR1BVQ29vcmRpbmF0ZVN5c3RlbSwgV2lyZWZyYW1lR2VvbWV0cnksIFdyYXBBcm91bmRFbmRpbmcsIFplcm9DdXJ2YXR1cmVFbmRpbmcsIFplcm9GYWN0b3IsIFplcm9TbG9wZUVuZGluZywgWmVyb1N0ZW5jaWxPcCwgY3JlYXRlQ2FudmFzRWxlbWVudCB9O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///753\n")},580:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ N: () => (/* binding */ OrbitControls)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(753);\n\n\n// OrbitControls performs orbiting, dollying (zooming), and panning.\n// Unlike TrackballControls, it maintains the \"up\" direction object.up (+Y by default).\n//\n// Orbit - left mouse / touch: one-finger move\n// Zoom - middle mouse, or mousewheel / touch: two-finger spread or squish\n// Pan - right mouse, or left mouse + ctrl/meta/shiftKey, or arrow keys / touch: two-finger move\n\nconst _changeEvent = { type: 'change' };\nconst _startEvent = { type: 'start' };\nconst _endEvent = { type: 'end' };\nconst _ray = new three__WEBPACK_IMPORTED_MODULE_0__/* .Ray */ .RlV();\nconst _plane = new three__WEBPACK_IMPORTED_MODULE_0__/* .Plane */ .Zcv();\nconst TILT_LIMIT = Math.cos( 70 * three__WEBPACK_IMPORTED_MODULE_0__/* .MathUtils */ .cj9.DEG2RAD );\n\nclass OrbitControls extends three__WEBPACK_IMPORTED_MODULE_0__/* .EventDispatcher */ .Qev {\n\n\tconstructor( object, domElement ) {\n\n\t\tsuper();\n\n\t\tthis.object = object;\n\t\tthis.domElement = domElement;\n\t\tthis.domElement.style.touchAction = 'none'; // disable touch scroll\n\n\t\t// Set to false to disable this control\n\t\tthis.enabled = true;\n\n\t\t// \"target\" sets the location of focus, where the object orbits around\n\t\tthis.target = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t// Sets the 3D cursor (similar to Blender), from which the maxTargetRadius takes effect\n\t\tthis.cursor = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t// How far you can dolly in and out ( PerspectiveCamera only )\n\t\tthis.minDistance = 0;\n\t\tthis.maxDistance = Infinity;\n\n\t\t// How far you can zoom in and out ( OrthographicCamera only )\n\t\tthis.minZoom = 0;\n\t\tthis.maxZoom = Infinity;\n\n\t\t// Limit camera target within a spherical area around the cursor\n\t\tthis.minTargetRadius = 0;\n\t\tthis.maxTargetRadius = Infinity;\n\n\t\t// How far you can orbit vertically, upper and lower limits.\n\t\t// Range is 0 to Math.PI radians.\n\t\tthis.minPolarAngle = 0; // radians\n\t\tthis.maxPolarAngle = Math.PI; // radians\n\n\t\t// How far you can orbit horizontally, upper and lower limits.\n\t\t// If set, the interval [ min, max ] must be a sub-interval of [ - 2 PI, 2 PI ], with ( max - min < 2 PI )\n\t\tthis.minAzimuthAngle = - Infinity; // radians\n\t\tthis.maxAzimuthAngle = Infinity; // radians\n\n\t\t// Set to true to enable damping (inertia)\n\t\t// If damping is enabled, you must call controls.update() in your animation loop\n\t\tthis.enableDamping = false;\n\t\tthis.dampingFactor = 0.05;\n\n\t\t// This option actually enables dollying in and out; left as \"zoom\" for backwards compatibility.\n\t\t// Set to false to disable zooming\n\t\tthis.enableZoom = true;\n\t\tthis.zoomSpeed = 1.0;\n\n\t\t// Set to false to disable rotating\n\t\tthis.enableRotate = true;\n\t\tthis.rotateSpeed = 1.0;\n\n\t\t// Set to false to disable panning\n\t\tthis.enablePan = true;\n\t\tthis.panSpeed = 1.0;\n\t\tthis.screenSpacePanning = true; // if false, pan orthogonal to world-space direction camera.up\n\t\tthis.keyPanSpeed = 7.0;\t// pixels moved per arrow key push\n\t\tthis.zoomToCursor = false;\n\n\t\t// Set to true to automatically rotate around the target\n\t\t// If auto-rotate is enabled, you must call controls.update() in your animation loop\n\t\tthis.autoRotate = false;\n\t\tthis.autoRotateSpeed = 2.0; // 30 seconds per orbit when fps is 60\n\n\t\t// The four arrow keys\n\t\tthis.keys = { LEFT: 'ArrowLeft', UP: 'ArrowUp', RIGHT: 'ArrowRight', BOTTOM: 'ArrowDown' };\n\n\t\t// Mouse buttons\n\t\tthis.mouseButtons = { LEFT: three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.ROTATE, MIDDLE: three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.DOLLY, RIGHT: three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.PAN };\n\n\t\t// Touch fingers\n\t\tthis.touches = { ONE: three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.ROTATE, TWO: three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.DOLLY_PAN };\n\n\t\t// for reset\n\t\tthis.target0 = this.target.clone();\n\t\tthis.position0 = this.object.position.clone();\n\t\tthis.zoom0 = this.object.zoom;\n\n\t\t// the target DOM element for key events\n\t\tthis._domElementKeyEvents = null;\n\n\t\t//\n\t\t// public methods\n\t\t//\n\n\t\tthis.getPolarAngle = function () {\n\n\t\t\treturn spherical.phi;\n\n\t\t};\n\n\t\tthis.getAzimuthalAngle = function () {\n\n\t\t\treturn spherical.theta;\n\n\t\t};\n\n\t\tthis.getDistance = function () {\n\n\t\t\treturn this.object.position.distanceTo( this.target );\n\n\t\t};\n\n\t\tthis.listenToKeyEvents = function ( domElement ) {\n\n\t\t\tdomElement.addEventListener( 'keydown', onKeyDown );\n\t\t\tthis._domElementKeyEvents = domElement;\n\n\t\t};\n\n\t\tthis.stopListenToKeyEvents = function () {\n\n\t\t\tthis._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown );\n\t\t\tthis._domElementKeyEvents = null;\n\n\t\t};\n\n\t\tthis.saveState = function () {\n\n\t\t\tscope.target0.copy( scope.target );\n\t\t\tscope.position0.copy( scope.object.position );\n\t\t\tscope.zoom0 = scope.object.zoom;\n\n\t\t};\n\n\t\tthis.reset = function () {\n\n\t\t\tscope.target.copy( scope.target0 );\n\t\t\tscope.object.position.copy( scope.position0 );\n\t\t\tscope.object.zoom = scope.zoom0;\n\n\t\t\tscope.object.updateProjectionMatrix();\n\t\t\tscope.dispatchEvent( _changeEvent );\n\n\t\t\tscope.update();\n\n\t\t\tstate = STATE.NONE;\n\n\t\t};\n\n\t\t// this method is exposed, but perhaps it would be better if we can make it private...\n\t\tthis.update = function () {\n\n\t\t\tconst offset = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t\t// so camera.up is the orbit axis\n\t\t\tconst quat = new three__WEBPACK_IMPORTED_MODULE_0__/* .Quaternion */ .PTz().setFromUnitVectors( object.up, new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0( 0, 1, 0 ) );\n\t\t\tconst quatInverse = quat.clone().invert();\n\n\t\t\tconst lastPosition = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\t\t\tconst lastQuaternion = new three__WEBPACK_IMPORTED_MODULE_0__/* .Quaternion */ .PTz();\n\t\t\tconst lastTargetPosition = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t\tconst twoPI = 2 * Math.PI;\n\n\t\t\treturn function update( deltaTime = null ) {\n\n\t\t\t\tconst position = scope.object.position;\n\n\t\t\t\toffset.copy( position ).sub( scope.target );\n\n\t\t\t\t// rotate offset to \"y-axis-is-up\" space\n\t\t\t\toffset.applyQuaternion( quat );\n\n\t\t\t\t// angle from z-axis around y-axis\n\t\t\t\tspherical.setFromVector3( offset );\n\n\t\t\t\tif ( scope.autoRotate && state === STATE.NONE ) {\n\n\t\t\t\t\trotateLeft( getAutoRotationAngle( deltaTime ) );\n\n\t\t\t\t}\n\n\t\t\t\tif ( scope.enableDamping ) {\n\n\t\t\t\t\tspherical.theta += sphericalDelta.theta * scope.dampingFactor;\n\t\t\t\t\tspherical.phi += sphericalDelta.phi * scope.dampingFactor;\n\n\t\t\t\t} else {\n\n\t\t\t\t\tspherical.theta += sphericalDelta.theta;\n\t\t\t\t\tspherical.phi += sphericalDelta.phi;\n\n\t\t\t\t}\n\n\t\t\t\t// restrict theta to be between desired limits\n\n\t\t\t\tlet min = scope.minAzimuthAngle;\n\t\t\t\tlet max = scope.maxAzimuthAngle;\n\n\t\t\t\tif ( isFinite( min ) && isFinite( max ) ) {\n\n\t\t\t\t\tif ( min < - Math.PI ) min += twoPI; else if ( min > Math.PI ) min -= twoPI;\n\n\t\t\t\t\tif ( max < - Math.PI ) max += twoPI; else if ( max > Math.PI ) max -= twoPI;\n\n\t\t\t\t\tif ( min <= max ) {\n\n\t\t\t\t\t\tspherical.theta = Math.max( min, Math.min( max, spherical.theta ) );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tspherical.theta = ( spherical.theta > ( min + max ) / 2 ) ?\n\t\t\t\t\t\t\tMath.max( min, spherical.theta ) :\n\t\t\t\t\t\t\tMath.min( max, spherical.theta );\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\t// restrict phi to be between desired limits\n\t\t\t\tspherical.phi = Math.max( scope.minPolarAngle, Math.min( scope.maxPolarAngle, spherical.phi ) );\n\n\t\t\t\tspherical.makeSafe();\n\n\n\t\t\t\t// move target to panned location\n\n\t\t\t\tif ( scope.enableDamping === true ) {\n\n\t\t\t\t\tscope.target.addScaledVector( panOffset, scope.dampingFactor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tscope.target.add( panOffset );\n\n\t\t\t\t}\n\n\t\t\t\t// Limit the target distance from the cursor to create a sphere around the center of interest\n\t\t\t\tscope.target.sub( scope.cursor );\n\t\t\t\tscope.target.clampLength( scope.minTargetRadius, scope.maxTargetRadius );\n\t\t\t\tscope.target.add( scope.cursor );\n\n\t\t\t\tlet zoomChanged = false;\n\t\t\t\t// adjust the camera position based on zoom only if we're not zooming to the cursor or if it's an ortho camera\n\t\t\t\t// we adjust zoom later in these cases\n\t\t\t\tif ( scope.zoomToCursor && performCursorZoom || scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\tspherical.radius = clampDistance( spherical.radius );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tconst prevRadius = spherical.radius;\n\t\t\t\t\tspherical.radius = clampDistance( spherical.radius * scale );\n\t\t\t\t\tzoomChanged = prevRadius != spherical.radius;\n\n\t\t\t\t}\n\n\t\t\t\toffset.setFromSpherical( spherical );\n\n\t\t\t\t// rotate offset back to \"camera-up-vector-is-up\" space\n\t\t\t\toffset.applyQuaternion( quatInverse );\n\n\t\t\t\tposition.copy( scope.target ).add( offset );\n\n\t\t\t\tscope.object.lookAt( scope.target );\n\n\t\t\t\tif ( scope.enableDamping === true ) {\n\n\t\t\t\t\tsphericalDelta.theta *= ( 1 - scope.dampingFactor );\n\t\t\t\t\tsphericalDelta.phi *= ( 1 - scope.dampingFactor );\n\n\t\t\t\t\tpanOffset.multiplyScalar( 1 - scope.dampingFactor );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tsphericalDelta.set( 0, 0, 0 );\n\n\t\t\t\t\tpanOffset.set( 0, 0, 0 );\n\n\t\t\t\t}\n\n\t\t\t\t// adjust camera position\n\t\t\t\tif ( scope.zoomToCursor && performCursorZoom ) {\n\n\t\t\t\t\tlet newRadius = null;\n\t\t\t\t\tif ( scope.object.isPerspectiveCamera ) {\n\n\t\t\t\t\t\t// move the camera down the pointer ray\n\t\t\t\t\t\t// this method avoids floating point error\n\t\t\t\t\t\tconst prevRadius = offset.length();\n\t\t\t\t\t\tnewRadius = clampDistance( prevRadius * scale );\n\n\t\t\t\t\t\tconst radiusDelta = prevRadius - newRadius;\n\t\t\t\t\t\tscope.object.position.addScaledVector( dollyDirection, radiusDelta );\n\t\t\t\t\t\tscope.object.updateMatrixWorld();\n\n\t\t\t\t\t\tzoomChanged = !! radiusDelta;\n\n\t\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\t\t// adjust the ortho camera position based on zoom changes\n\t\t\t\t\t\tconst mouseBefore = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0( mouse.x, mouse.y, 0 );\n\t\t\t\t\t\tmouseBefore.unproject( scope.object );\n\n\t\t\t\t\t\tconst prevZoom = scope.object.zoom;\n\t\t\t\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) );\n\t\t\t\t\t\tscope.object.updateProjectionMatrix();\n\n\t\t\t\t\t\tzoomChanged = prevZoom !== scope.object.zoom;\n\n\t\t\t\t\t\tconst mouseAfter = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0( mouse.x, mouse.y, 0 );\n\t\t\t\t\t\tmouseAfter.unproject( scope.object );\n\n\t\t\t\t\t\tscope.object.position.sub( mouseAfter ).add( mouseBefore );\n\t\t\t\t\t\tscope.object.updateMatrixWorld();\n\n\t\t\t\t\t\tnewRadius = offset.length();\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - zoom to cursor disabled.' );\n\t\t\t\t\t\tscope.zoomToCursor = false;\n\n\t\t\t\t\t}\n\n\t\t\t\t\t// handle the placement of the target\n\t\t\t\t\tif ( newRadius !== null ) {\n\n\t\t\t\t\t\tif ( this.screenSpacePanning ) {\n\n\t\t\t\t\t\t\t// position the orbit target in front of the new camera position\n\t\t\t\t\t\t\tscope.target.set( 0, 0, - 1 )\n\t\t\t\t\t\t\t\t.transformDirection( scope.object.matrix )\n\t\t\t\t\t\t\t\t.multiplyScalar( newRadius )\n\t\t\t\t\t\t\t\t.add( scope.object.position );\n\n\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t// get the ray and translation plane to compute target\n\t\t\t\t\t\t\t_ray.origin.copy( scope.object.position );\n\t\t\t\t\t\t\t_ray.direction.set( 0, 0, - 1 ).transformDirection( scope.object.matrix );\n\n\t\t\t\t\t\t\t// if the camera is 20 degrees above the horizon then don't adjust the focus target to avoid\n\t\t\t\t\t\t\t// extremely large values\n\t\t\t\t\t\t\tif ( Math.abs( scope.object.up.dot( _ray.direction ) ) < TILT_LIMIT ) {\n\n\t\t\t\t\t\t\t\tobject.lookAt( scope.target );\n\n\t\t\t\t\t\t\t} else {\n\n\t\t\t\t\t\t\t\t_plane.setFromNormalAndCoplanarPoint( scope.object.up, scope.target );\n\t\t\t\t\t\t\t\t_ray.intersectPlane( _plane, scope.target );\n\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t}\n\n\t\t\t\t\t}\n\n\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\tconst prevZoom = scope.object.zoom;\n\t\t\t\t\tscope.object.zoom = Math.max( scope.minZoom, Math.min( scope.maxZoom, scope.object.zoom / scale ) );\n\n\t\t\t\t\tif ( prevZoom !== scope.object.zoom ) {\n\n\t\t\t\t\t\tscope.object.updateProjectionMatrix();\n\t\t\t\t\t\tzoomChanged = true;\n\n\t\t\t\t\t}\n\n\t\t\t\t}\n\n\t\t\t\tscale = 1;\n\t\t\t\tperformCursorZoom = false;\n\n\t\t\t\t// update condition is:\n\t\t\t\t// min(camera displacement, camera rotation in radians)^2 > EPS\n\t\t\t\t// using small-angle approximation cos(x/2) = 1 - x^2 / 8\n\n\t\t\t\tif ( zoomChanged ||\n\t\t\t\t\tlastPosition.distanceToSquared( scope.object.position ) > EPS ||\n\t\t\t\t\t8 * ( 1 - lastQuaternion.dot( scope.object.quaternion ) ) > EPS ||\n\t\t\t\t\tlastTargetPosition.distanceToSquared( scope.target ) > EPS ) {\n\n\t\t\t\t\tscope.dispatchEvent( _changeEvent );\n\n\t\t\t\t\tlastPosition.copy( scope.object.position );\n\t\t\t\t\tlastQuaternion.copy( scope.object.quaternion );\n\t\t\t\t\tlastTargetPosition.copy( scope.target );\n\n\t\t\t\t\treturn true;\n\n\t\t\t\t}\n\n\t\t\t\treturn false;\n\n\t\t\t};\n\n\t\t}();\n\n\t\tthis.dispose = function () {\n\n\t\t\tscope.domElement.removeEventListener( 'contextmenu', onContextMenu );\n\n\t\t\tscope.domElement.removeEventListener( 'pointerdown', onPointerDown );\n\t\t\tscope.domElement.removeEventListener( 'pointercancel', onPointerUp );\n\t\t\tscope.domElement.removeEventListener( 'wheel', onMouseWheel );\n\n\t\t\tscope.domElement.removeEventListener( 'pointermove', onPointerMove );\n\t\t\tscope.domElement.removeEventListener( 'pointerup', onPointerUp );\n\n\t\t\tconst document = scope.domElement.getRootNode(); // offscreen canvas compatibility\n\n\t\t\tdocument.removeEventListener( 'keydown', interceptControlDown, { capture: true } );\n\n\t\t\tif ( scope._domElementKeyEvents !== null ) {\n\n\t\t\t\tscope._domElementKeyEvents.removeEventListener( 'keydown', onKeyDown );\n\t\t\t\tscope._domElementKeyEvents = null;\n\n\t\t\t}\n\n\t\t\t//scope.dispatchEvent( { type: 'dispose' } ); // should this be added here?\n\n\t\t};\n\n\t\t//\n\t\t// internals\n\t\t//\n\n\t\tconst scope = this;\n\n\t\tconst STATE = {\n\t\t\tNONE: - 1,\n\t\t\tROTATE: 0,\n\t\t\tDOLLY: 1,\n\t\t\tPAN: 2,\n\t\t\tTOUCH_ROTATE: 3,\n\t\t\tTOUCH_PAN: 4,\n\t\t\tTOUCH_DOLLY_PAN: 5,\n\t\t\tTOUCH_DOLLY_ROTATE: 6\n\t\t};\n\n\t\tlet state = STATE.NONE;\n\n\t\tconst EPS = 0.000001;\n\n\t\t// current position in spherical coordinates\n\t\tconst spherical = new three__WEBPACK_IMPORTED_MODULE_0__/* .Spherical */ .YHV();\n\t\tconst sphericalDelta = new three__WEBPACK_IMPORTED_MODULE_0__/* .Spherical */ .YHV();\n\n\t\tlet scale = 1;\n\t\tconst panOffset = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\tconst rotateStart = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst rotateEnd = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst rotateDelta = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\n\t\tconst panStart = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst panEnd = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst panDelta = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\n\t\tconst dollyStart = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst dollyEnd = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tconst dollyDelta = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\n\t\tconst dollyDirection = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\t\tconst mouse = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\tlet performCursorZoom = false;\n\n\t\tconst pointers = [];\n\t\tconst pointerPositions = {};\n\n\t\tlet controlActive = false;\n\n\t\tfunction getAutoRotationAngle( deltaTime ) {\n\n\t\t\tif ( deltaTime !== null ) {\n\n\t\t\t\treturn ( 2 * Math.PI / 60 * scope.autoRotateSpeed ) * deltaTime;\n\n\t\t\t} else {\n\n\t\t\t\treturn 2 * Math.PI / 60 / 60 * scope.autoRotateSpeed;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction getZoomScale( delta ) {\n\n\t\t\tconst normalizedDelta = Math.abs( delta * 0.01 );\n\t\t\treturn Math.pow( 0.95, scope.zoomSpeed * normalizedDelta );\n\n\t\t}\n\n\t\tfunction rotateLeft( angle ) {\n\n\t\t\tsphericalDelta.theta -= angle;\n\n\t\t}\n\n\t\tfunction rotateUp( angle ) {\n\n\t\t\tsphericalDelta.phi -= angle;\n\n\t\t}\n\n\t\tconst panLeft = function () {\n\n\t\t\tconst v = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t\treturn function panLeft( distance, objectMatrix ) {\n\n\t\t\t\tv.setFromMatrixColumn( objectMatrix, 0 ); // get X column of objectMatrix\n\t\t\t\tv.multiplyScalar( - distance );\n\n\t\t\t\tpanOffset.add( v );\n\n\t\t\t};\n\n\t\t}();\n\n\t\tconst panUp = function () {\n\n\t\t\tconst v = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t\treturn function panUp( distance, objectMatrix ) {\n\n\t\t\t\tif ( scope.screenSpacePanning === true ) {\n\n\t\t\t\t\tv.setFromMatrixColumn( objectMatrix, 1 );\n\n\t\t\t\t} else {\n\n\t\t\t\t\tv.setFromMatrixColumn( objectMatrix, 0 );\n\t\t\t\t\tv.crossVectors( scope.object.up, v );\n\n\t\t\t\t}\n\n\t\t\t\tv.multiplyScalar( distance );\n\n\t\t\t\tpanOffset.add( v );\n\n\t\t\t};\n\n\t\t}();\n\n\t\t// deltaX and deltaY are in pixels; right and down are positive\n\t\tconst pan = function () {\n\n\t\t\tconst offset = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector3 */ .Pq0();\n\n\t\t\treturn function pan( deltaX, deltaY ) {\n\n\t\t\t\tconst element = scope.domElement;\n\n\t\t\t\tif ( scope.object.isPerspectiveCamera ) {\n\n\t\t\t\t\t// perspective\n\t\t\t\t\tconst position = scope.object.position;\n\t\t\t\t\toffset.copy( position ).sub( scope.target );\n\t\t\t\t\tlet targetDistance = offset.length();\n\n\t\t\t\t\t// half of the fov is center to top of screen\n\t\t\t\t\ttargetDistance *= Math.tan( ( scope.object.fov / 2 ) * Math.PI / 180.0 );\n\n\t\t\t\t\t// we use only clientHeight here so aspect ratio does not distort speed\n\t\t\t\t\tpanLeft( 2 * deltaX * targetDistance / element.clientHeight, scope.object.matrix );\n\t\t\t\t\tpanUp( 2 * deltaY * targetDistance / element.clientHeight, scope.object.matrix );\n\n\t\t\t\t} else if ( scope.object.isOrthographicCamera ) {\n\n\t\t\t\t\t// orthographic\n\t\t\t\t\tpanLeft( deltaX * ( scope.object.right - scope.object.left ) / scope.object.zoom / element.clientWidth, scope.object.matrix );\n\t\t\t\t\tpanUp( deltaY * ( scope.object.top - scope.object.bottom ) / scope.object.zoom / element.clientHeight, scope.object.matrix );\n\n\t\t\t\t} else {\n\n\t\t\t\t\t// camera neither orthographic nor perspective\n\t\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - pan disabled.' );\n\t\t\t\t\tscope.enablePan = false;\n\n\t\t\t\t}\n\n\t\t\t};\n\n\t\t}();\n\n\t\tfunction dollyOut( dollyScale ) {\n\n\t\t\tif ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) {\n\n\t\t\t\tscale /= dollyScale;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\t\tscope.enableZoom = false;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction dollyIn( dollyScale ) {\n\n\t\t\tif ( scope.object.isPerspectiveCamera || scope.object.isOrthographicCamera ) {\n\n\t\t\t\tscale *= dollyScale;\n\n\t\t\t} else {\n\n\t\t\t\tconsole.warn( 'WARNING: OrbitControls.js encountered an unknown camera type - dolly/zoom disabled.' );\n\t\t\t\tscope.enableZoom = false;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction updateZoomParameters( x, y ) {\n\n\t\t\tif ( ! scope.zoomToCursor ) {\n\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tperformCursorZoom = true;\n\n\t\t\tconst rect = scope.domElement.getBoundingClientRect();\n\t\t\tconst dx = x - rect.left;\n\t\t\tconst dy = y - rect.top;\n\t\t\tconst w = rect.width;\n\t\t\tconst h = rect.height;\n\n\t\t\tmouse.x = ( dx / w ) * 2 - 1;\n\t\t\tmouse.y = - ( dy / h ) * 2 + 1;\n\n\t\t\tdollyDirection.set( mouse.x, mouse.y, 1 ).unproject( scope.object ).sub( scope.object.position ).normalize();\n\n\t\t}\n\n\t\tfunction clampDistance( dist ) {\n\n\t\t\treturn Math.max( scope.minDistance, Math.min( scope.maxDistance, dist ) );\n\n\t\t}\n\n\t\t//\n\t\t// event callbacks - update the object state\n\t\t//\n\n\t\tfunction handleMouseDownRotate( event ) {\n\n\t\t\trotateStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseDownDolly( event ) {\n\n\t\t\tupdateZoomParameters( event.clientX, event.clientX );\n\t\t\tdollyStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseDownPan( event ) {\n\n\t\t\tpanStart.set( event.clientX, event.clientY );\n\n\t\t}\n\n\t\tfunction handleMouseMoveRotate( event ) {\n\n\t\t\trotateEnd.set( event.clientX, event.clientY );\n\n\t\t\trotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );\n\n\t\t\tconst element = scope.domElement;\n\n\t\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height\n\n\t\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );\n\n\t\t\trotateStart.copy( rotateEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseMoveDolly( event ) {\n\n\t\t\tdollyEnd.set( event.clientX, event.clientY );\n\n\t\t\tdollyDelta.subVectors( dollyEnd, dollyStart );\n\n\t\t\tif ( dollyDelta.y > 0 ) {\n\n\t\t\t\tdollyOut( getZoomScale( dollyDelta.y ) );\n\n\t\t\t} else if ( dollyDelta.y < 0 ) {\n\n\t\t\t\tdollyIn( getZoomScale( dollyDelta.y ) );\n\n\t\t\t}\n\n\t\t\tdollyStart.copy( dollyEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseMovePan( event ) {\n\n\t\t\tpanEnd.set( event.clientX, event.clientY );\n\n\t\t\tpanDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );\n\n\t\t\tpan( panDelta.x, panDelta.y );\n\n\t\t\tpanStart.copy( panEnd );\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleMouseWheel( event ) {\n\n\t\t\tupdateZoomParameters( event.clientX, event.clientY );\n\n\t\t\tif ( event.deltaY < 0 ) {\n\n\t\t\t\tdollyIn( getZoomScale( event.deltaY ) );\n\n\t\t\t} else if ( event.deltaY > 0 ) {\n\n\t\t\t\tdollyOut( getZoomScale( event.deltaY ) );\n\n\t\t\t}\n\n\t\t\tscope.update();\n\n\t\t}\n\n\t\tfunction handleKeyDown( event ) {\n\n\t\t\tlet needsUpdate = false;\n\n\t\t\tswitch ( event.code ) {\n\n\t\t\t\tcase scope.keys.UP:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateUp( 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( 0, scope.keyPanSpeed );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.BOTTOM:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateUp( - 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( 0, - scope.keyPanSpeed );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.LEFT:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateLeft( 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( scope.keyPanSpeed, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase scope.keys.RIGHT:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\trotateLeft( - 2 * Math.PI * scope.rotateSpeed / scope.domElement.clientHeight );\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tpan( - scope.keyPanSpeed, 0 );\n\n\t\t\t\t\t}\n\n\t\t\t\t\tneedsUpdate = true;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\tif ( needsUpdate ) {\n\n\t\t\t\t// prevent the browser from scrolling on cursor keys\n\t\t\t\tevent.preventDefault();\n\n\t\t\t\tscope.update();\n\n\t\t\t}\n\n\n\t\t}\n\n\t\tfunction handleTouchStartRotate( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\trotateStart.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\trotateStart.set( x, y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction handleTouchStartPan( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\tpanStart.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\tpanStart.set( x, y );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction handleTouchStartDolly( event ) {\n\n\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\tconst dx = event.pageX - position.x;\n\t\t\tconst dy = event.pageY - position.y;\n\n\t\t\tconst distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tdollyStart.set( 0, distance );\n\n\t\t}\n\n\t\tfunction handleTouchStartDollyPan( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchStartDolly( event );\n\n\t\t\tif ( scope.enablePan ) handleTouchStartPan( event );\n\n\t\t}\n\n\t\tfunction handleTouchStartDollyRotate( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchStartDolly( event );\n\n\t\t\tif ( scope.enableRotate ) handleTouchStartRotate( event );\n\n\t\t}\n\n\t\tfunction handleTouchMoveRotate( event ) {\n\n\t\t\tif ( pointers.length == 1 ) {\n\n\t\t\t\trotateEnd.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\trotateEnd.set( x, y );\n\n\t\t\t}\n\n\t\t\trotateDelta.subVectors( rotateEnd, rotateStart ).multiplyScalar( scope.rotateSpeed );\n\n\t\t\tconst element = scope.domElement;\n\n\t\t\trotateLeft( 2 * Math.PI * rotateDelta.x / element.clientHeight ); // yes, height\n\n\t\t\trotateUp( 2 * Math.PI * rotateDelta.y / element.clientHeight );\n\n\t\t\trotateStart.copy( rotateEnd );\n\n\t\t}\n\n\t\tfunction handleTouchMovePan( event ) {\n\n\t\t\tif ( pointers.length === 1 ) {\n\n\t\t\t\tpanEnd.set( event.pageX, event.pageY );\n\n\t\t\t} else {\n\n\t\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\t\tconst x = 0.5 * ( event.pageX + position.x );\n\t\t\t\tconst y = 0.5 * ( event.pageY + position.y );\n\n\t\t\t\tpanEnd.set( x, y );\n\n\t\t\t}\n\n\t\t\tpanDelta.subVectors( panEnd, panStart ).multiplyScalar( scope.panSpeed );\n\n\t\t\tpan( panDelta.x, panDelta.y );\n\n\t\t\tpanStart.copy( panEnd );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDolly( event ) {\n\n\t\t\tconst position = getSecondPointerPosition( event );\n\n\t\t\tconst dx = event.pageX - position.x;\n\t\t\tconst dy = event.pageY - position.y;\n\n\t\t\tconst distance = Math.sqrt( dx * dx + dy * dy );\n\n\t\t\tdollyEnd.set( 0, distance );\n\n\t\t\tdollyDelta.set( 0, Math.pow( dollyEnd.y / dollyStart.y, scope.zoomSpeed ) );\n\n\t\t\tdollyOut( dollyDelta.y );\n\n\t\t\tdollyStart.copy( dollyEnd );\n\n\t\t\tconst centerX = ( event.pageX + position.x ) * 0.5;\n\t\t\tconst centerY = ( event.pageY + position.y ) * 0.5;\n\n\t\t\tupdateZoomParameters( centerX, centerY );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDollyPan( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchMoveDolly( event );\n\n\t\t\tif ( scope.enablePan ) handleTouchMovePan( event );\n\n\t\t}\n\n\t\tfunction handleTouchMoveDollyRotate( event ) {\n\n\t\t\tif ( scope.enableZoom ) handleTouchMoveDolly( event );\n\n\t\t\tif ( scope.enableRotate ) handleTouchMoveRotate( event );\n\n\t\t}\n\n\t\t//\n\t\t// event handlers - FSM: listen for events and reset state\n\t\t//\n\n\t\tfunction onPointerDown( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tif ( pointers.length === 0 ) {\n\n\t\t\t\tscope.domElement.setPointerCapture( event.pointerId );\n\n\t\t\t\tscope.domElement.addEventListener( 'pointermove', onPointerMove );\n\t\t\t\tscope.domElement.addEventListener( 'pointerup', onPointerUp );\n\n\t\t\t}\n\n\t\t\t//\n\n\t\t\tif ( isTrackingPointer( event ) ) return;\n\n\t\t\t//\n\n\t\t\taddPointer( event );\n\n\t\t\tif ( event.pointerType === 'touch' ) {\n\n\t\t\t\tonTouchStart( event );\n\n\t\t\t} else {\n\n\t\t\t\tonMouseDown( event );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onPointerMove( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tif ( event.pointerType === 'touch' ) {\n\n\t\t\t\tonTouchMove( event );\n\n\t\t\t} else {\n\n\t\t\t\tonMouseMove( event );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onPointerUp( event ) {\n\n\t\t\tremovePointer( event );\n\n\t\t\tswitch ( pointers.length ) {\n\n\t\t\t\tcase 0:\n\n\t\t\t\t\tscope.domElement.releasePointerCapture( event.pointerId );\n\n\t\t\t\t\tscope.domElement.removeEventListener( 'pointermove', onPointerMove );\n\t\t\t\t\tscope.domElement.removeEventListener( 'pointerup', onPointerUp );\n\n\t\t\t\t\tscope.dispatchEvent( _endEvent );\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 1:\n\n\t\t\t\t\tconst pointerId = pointers[ 0 ];\n\t\t\t\t\tconst position = pointerPositions[ pointerId ];\n\n\t\t\t\t\t// minimal placeholder event - allows state correction on pointer-up\n\t\t\t\t\tonTouchStart( { pointerId: pointerId, pageX: position.x, pageY: position.y } );\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseDown( event ) {\n\n\t\t\tlet mouseAction;\n\n\t\t\tswitch ( event.button ) {\n\n\t\t\t\tcase 0:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.LEFT;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 1:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.MIDDLE;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2:\n\n\t\t\t\t\tmouseAction = scope.mouseButtons.RIGHT;\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tmouseAction = - 1;\n\n\t\t\t}\n\n\t\t\tswitch ( mouseAction ) {\n\n\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.DOLLY:\n\n\t\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\t\thandleMouseDownDolly( event );\n\n\t\t\t\t\tstate = STATE.DOLLY;\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.ROTATE:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\thandleMouseDownPan( event );\n\n\t\t\t\t\t\tstate = STATE.PAN;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\thandleMouseDownRotate( event );\n\n\t\t\t\t\t\tstate = STATE.ROTATE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .MOUSE */ .kBv.PAN:\n\n\t\t\t\t\tif ( event.ctrlKey || event.metaKey || event.shiftKey ) {\n\n\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\thandleMouseDownRotate( event );\n\n\t\t\t\t\t\tstate = STATE.ROTATE;\n\n\t\t\t\t\t} else {\n\n\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\thandleMouseDownPan( event );\n\n\t\t\t\t\t\tstate = STATE.PAN;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t\tif ( state !== STATE.NONE ) {\n\n\t\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseMove( event ) {\n\n\t\t\tswitch ( state ) {\n\n\t\t\t\tcase STATE.ROTATE:\n\n\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleMouseMoveRotate( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.DOLLY:\n\n\t\t\t\t\tif ( scope.enableZoom === false ) return;\n\n\t\t\t\t\thandleMouseMoveDolly( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.PAN:\n\n\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\thandleMouseMovePan( event );\n\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onMouseWheel( event ) {\n\n\t\t\tif ( scope.enabled === false || scope.enableZoom === false || state !== STATE.NONE ) return;\n\n\t\t\tevent.preventDefault();\n\n\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\thandleMouseWheel( customWheelEvent( event ) );\n\n\t\t\tscope.dispatchEvent( _endEvent );\n\n\t\t}\n\n\t\tfunction customWheelEvent( event ) {\n\n\t\t\tconst mode = event.deltaMode;\n\n\t\t\t// minimal wheel event altered to meet delta-zoom demand\n\t\t\tconst newEvent = {\n\t\t\t\tclientX: event.clientX,\n\t\t\t\tclientY: event.clientY,\n\t\t\t\tdeltaY: event.deltaY,\n\t\t\t};\n\n\t\t\tswitch ( mode ) {\n\n\t\t\t\tcase 1: // LINE_MODE\n\t\t\t\t\tnewEvent.deltaY *= 16;\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2: // PAGE_MODE\n\t\t\t\t\tnewEvent.deltaY *= 100;\n\t\t\t\t\tbreak;\n\n\t\t\t}\n\n\t\t\t// detect if event was triggered by pinching\n\t\t\tif ( event.ctrlKey && ! controlActive ) {\n\n\t\t\t\tnewEvent.deltaY *= 10;\n\n\t\t\t}\n\n\t\t\treturn newEvent;\n\n\t\t}\n\n\t\tfunction interceptControlDown( event ) {\n\n\t\t\tif ( event.key === 'Control' ) {\n\n\t\t\t\tcontrolActive = true;\n\n\n\t\t\t\tconst document = scope.domElement.getRootNode(); // offscreen canvas compatibility\n\n\t\t\t\tdocument.addEventListener( 'keyup', interceptControlUp, { passive: true, capture: true } );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction interceptControlUp( event ) {\n\n\t\t\tif ( event.key === 'Control' ) {\n\n\t\t\t\tcontrolActive = false;\n\n\n\t\t\t\tconst document = scope.domElement.getRootNode(); // offscreen canvas compatibility\n\n\t\t\t\tdocument.removeEventListener( 'keyup', interceptControlUp, { passive: true, capture: true } );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onKeyDown( event ) {\n\n\t\t\tif ( scope.enabled === false || scope.enablePan === false ) return;\n\n\t\t\thandleKeyDown( event );\n\n\t\t}\n\n\t\tfunction onTouchStart( event ) {\n\n\t\t\ttrackPointer( event );\n\n\t\t\tswitch ( pointers.length ) {\n\n\t\t\t\tcase 1:\n\n\t\t\t\t\tswitch ( scope.touches.ONE ) {\n\n\t\t\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.ROTATE:\n\n\t\t\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartRotate( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_ROTATE;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.PAN:\n\n\t\t\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartPan( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_PAN;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase 2:\n\n\t\t\t\t\tswitch ( scope.touches.TWO ) {\n\n\t\t\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.DOLLY_PAN:\n\n\t\t\t\t\t\t\tif ( scope.enableZoom === false && scope.enablePan === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartDollyPan( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_DOLLY_PAN;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tcase three__WEBPACK_IMPORTED_MODULE_0__/* .TOUCH */ .wtR.DOLLY_ROTATE:\n\n\t\t\t\t\t\t\tif ( scope.enableZoom === false && scope.enableRotate === false ) return;\n\n\t\t\t\t\t\t\thandleTouchStartDollyRotate( event );\n\n\t\t\t\t\t\t\tstate = STATE.TOUCH_DOLLY_ROTATE;\n\n\t\t\t\t\t\t\tbreak;\n\n\t\t\t\t\t\tdefault:\n\n\t\t\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t\t\t}\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t\tif ( state !== STATE.NONE ) {\n\n\t\t\t\tscope.dispatchEvent( _startEvent );\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onTouchMove( event ) {\n\n\t\t\ttrackPointer( event );\n\n\t\t\tswitch ( state ) {\n\n\t\t\t\tcase STATE.TOUCH_ROTATE:\n\n\t\t\t\t\tif ( scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleTouchMoveRotate( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_PAN:\n\n\t\t\t\t\tif ( scope.enablePan === false ) return;\n\n\t\t\t\t\thandleTouchMovePan( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_DOLLY_PAN:\n\n\t\t\t\t\tif ( scope.enableZoom === false && scope.enablePan === false ) return;\n\n\t\t\t\t\thandleTouchMoveDollyPan( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tcase STATE.TOUCH_DOLLY_ROTATE:\n\n\t\t\t\t\tif ( scope.enableZoom === false && scope.enableRotate === false ) return;\n\n\t\t\t\t\thandleTouchMoveDollyRotate( event );\n\n\t\t\t\t\tscope.update();\n\n\t\t\t\t\tbreak;\n\n\t\t\t\tdefault:\n\n\t\t\t\t\tstate = STATE.NONE;\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction onContextMenu( event ) {\n\n\t\t\tif ( scope.enabled === false ) return;\n\n\t\t\tevent.preventDefault();\n\n\t\t}\n\n\t\tfunction addPointer( event ) {\n\n\t\t\tpointers.push( event.pointerId );\n\n\t\t}\n\n\t\tfunction removePointer( event ) {\n\n\t\t\tdelete pointerPositions[ event.pointerId ];\n\n\t\t\tfor ( let i = 0; i < pointers.length; i ++ ) {\n\n\t\t\t\tif ( pointers[ i ] == event.pointerId ) {\n\n\t\t\t\t\tpointers.splice( i, 1 );\n\t\t\t\t\treturn;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tfunction isTrackingPointer( event ) {\n\n\t\t\tfor ( let i = 0; i < pointers.length; i ++ ) {\n\n\t\t\t\tif ( pointers[ i ] == event.pointerId ) return true;\n\n\t\t\t}\n\n\t\t\treturn false;\n\n\t\t}\n\n\t\tfunction trackPointer( event ) {\n\n\t\t\tlet position = pointerPositions[ event.pointerId ];\n\n\t\t\tif ( position === undefined ) {\n\n\t\t\t\tposition = new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y();\n\t\t\t\tpointerPositions[ event.pointerId ] = position;\n\n\t\t\t}\n\n\t\t\tposition.set( event.pageX, event.pageY );\n\n\t\t}\n\n\t\tfunction getSecondPointerPosition( event ) {\n\n\t\t\tconst pointerId = ( event.pointerId === pointers[ 0 ] ) ? pointers[ 1 ] : pointers[ 0 ];\n\n\t\t\treturn pointerPositions[ pointerId ];\n\n\t\t}\n\n\t\t//\n\n\t\tscope.domElement.addEventListener( 'contextmenu', onContextMenu );\n\n\t\tscope.domElement.addEventListener( 'pointerdown', onPointerDown );\n\t\tscope.domElement.addEventListener( 'pointercancel', onPointerUp );\n\t\tscope.domElement.addEventListener( 'wheel', onMouseWheel, { passive: false } );\n\n\t\tconst document = scope.domElement.getRootNode(); // offscreen canvas compatibility\n\n\t\tdocument.addEventListener( 'keydown', interceptControlDown, { passive: true, capture: true } );\n\n\t\t// force an update at start\n\n\t\tthis.update();\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNTgwLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFXZTs7QUFFZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsdUJBQXVCO0FBQ3ZCLHNCQUFzQjtBQUN0QixvQkFBb0I7QUFDcEIsaUJBQWlCLGlEQUFHO0FBQ3BCLG1CQUFtQixtREFBSztBQUN4QixrQ0FBa0MsdURBQVM7O0FBRTNDLDRCQUE0Qiw2REFBZTs7QUFFM0M7O0FBRUE7O0FBRUE7QUFDQTtBQUNBLDhDQUE4Qzs7QUFFOUM7QUFDQTs7QUFFQTtBQUNBLG9CQUFvQixxREFBTzs7QUFFM0I7QUFDQSxvQkFBb0IscURBQU87O0FBRTNCO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSwwQkFBMEI7QUFDMUIsZ0NBQWdDOztBQUVoQztBQUNBO0FBQ0EscUNBQXFDO0FBQ3JDLG1DQUFtQzs7QUFFbkM7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsdURBQXVEO0FBQ3ZEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0Esa0NBQWtDO0FBQ2xDLDBCQUEwQjtBQUMxQjs7QUFFQTtBQUNBO0FBQ0E7QUFDQSw4QkFBOEI7O0FBRTlCO0FBQ0EsZ0JBQWdCOztBQUVoQjtBQUNBLHdCQUF3QixNQUFNLG1EQUFLLGlCQUFpQixtREFBSyxlQUFlLG1EQUFLOztBQUU3RTtBQUNBLG1CQUFtQixLQUFLLG1EQUFLLGNBQWMsbURBQUs7O0FBRWhEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxzQkFBc0IscURBQU87O0FBRTdCO0FBQ0Esb0JBQW9CLHdEQUFVLHNDQUFzQyxxREFBTztBQUMzRTs7QUFFQSw0QkFBNEIscURBQU87QUFDbkMsOEJBQThCLHdEQUFVO0FBQ3hDLGtDQUFrQyxxREFBTzs7QUFFekM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsTUFBTTs7QUFFTjtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsMENBQTBDOztBQUUxQywwQ0FBMEM7O0FBRTFDOztBQUVBOztBQUVBLE9BQU87O0FBRVA7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLE1BQU07O0FBRU47O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQO0FBQ0EsOEJBQThCLHFEQUFPO0FBQ3JDOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSw2QkFBNkIscURBQU87QUFDcEM7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLFFBQVE7O0FBRVI7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQSxTQUFTOztBQUVUO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsTUFBTTs7QUFFTjtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsb0RBQW9EOztBQUVwRCxvRUFBb0UsZ0JBQWdCOztBQUVwRjs7QUFFQTtBQUNBOztBQUVBOztBQUVBLDRCQUE0QixrQkFBa0IsR0FBRzs7QUFFakQ7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0Esd0JBQXdCLHVEQUFTO0FBQ2pDLDZCQUE2Qix1REFBUzs7QUFFdEM7QUFDQSx3QkFBd0IscURBQU87O0FBRS9CLDBCQUEwQixxREFBTztBQUNqQyx3QkFBd0IscURBQU87QUFDL0IsMEJBQTBCLHFEQUFPOztBQUVqQyx1QkFBdUIscURBQU87QUFDOUIscUJBQXFCLHFEQUFPO0FBQzVCLHVCQUF1QixxREFBTzs7QUFFOUIseUJBQXlCLHFEQUFPO0FBQ2hDLHVCQUF1QixxREFBTztBQUM5Qix5QkFBeUIscURBQU87O0FBRWhDLDZCQUE2QixxREFBTztBQUNwQyxvQkFBb0IscURBQU87QUFDM0I7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsaUJBQWlCLHFEQUFPOztBQUV4Qjs7QUFFQSw4Q0FBOEM7QUFDOUM7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQSxpQkFBaUIscURBQU87O0FBRXhCOztBQUVBOztBQUVBOztBQUVBLE1BQU07O0FBRU47QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVILHNDQUFzQztBQUN0Qzs7QUFFQSxzQkFBc0IscURBQU87O0FBRTdCOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBLE1BQU07O0FBRU47QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUVBQXFFOztBQUVyRTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxPQUFPOztBQUVQOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7OztBQUdBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEscUVBQXFFOztBQUVyRTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEtBQUs7O0FBRUw7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsS0FBSzs7QUFFTDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxxQkFBcUIsNkRBQTZEOztBQUVsRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxTQUFTLG1EQUFLOztBQUVkOztBQUVBOztBQUVBOztBQUVBOztBQUVBLFNBQVMsbURBQUs7O0FBRWQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsT0FBTzs7QUFFUDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxTQUFTLG1EQUFLOztBQUVkOztBQUVBOztBQUVBOztBQUVBOztBQUVBLE9BQU87O0FBRVA7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0EscURBQXFEOztBQUVyRCw4REFBOEQsK0JBQStCOztBQUU3Rjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7O0FBR0EscURBQXFEOztBQUVyRCxpRUFBaUUsK0JBQStCOztBQUVoRzs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxXQUFXLG1EQUFLOztBQUVoQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxXQUFXLG1EQUFLOztBQUVoQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxXQUFXLG1EQUFLOztBQUVoQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxXQUFXLG1EQUFLOztBQUVoQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IscUJBQXFCOztBQUV6Qzs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG9CQUFvQixxQkFBcUI7O0FBRXpDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQixxREFBTztBQUMxQjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0EsOERBQThELGlCQUFpQjs7QUFFL0UsbURBQW1EOztBQUVuRCxnRUFBZ0UsK0JBQStCOztBQUUvRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFeUIiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9jb250cm9scy9PcmJpdENvbnRyb2xzLmpzP2E2ZTEiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0RXZlbnREaXNwYXRjaGVyLFxuXHRNT1VTRSxcblx0UXVhdGVybmlvbixcblx0U3BoZXJpY2FsLFxuXHRUT1VDSCxcblx0VmVjdG9yMixcblx0VmVjdG9yMyxcblx0UGxhbmUsXG5cdFJheSxcblx0TWF0aFV0aWxzXG59IGZyb20gJ3RocmVlJztcblxuLy8gT3JiaXRDb250cm9scyBwZXJmb3JtcyBvcmJpdGluZywgZG9sbHlpbmcgKHpvb21pbmcpLCBhbmQgcGFubmluZy5cbi8vIFVubGlrZSBUcmFja2JhbGxDb250cm9scywgaXQgbWFpbnRhaW5zIHRoZSBcInVwXCIgZGlyZWN0aW9uIG9iamVjdC51cCAoK1kgYnkgZGVmYXVsdCkuXG4vL1xuLy8gICAgT3JiaXQgLSBsZWZ0IG1vdXNlIC8gdG91Y2g6IG9uZS1maW5nZXIgbW92ZVxuLy8gICAgWm9vbSAtIG1pZGRsZSBtb3VzZSwgb3IgbW91c2V3aGVlbCAvIHRvdWNoOiB0d28tZmluZ2VyIHNwcmVhZCBvciBzcXVpc2hcbi8vICAgIFBhbiAtIHJpZ2h0IG1vdXNlLCBvciBsZWZ0IG1vdXNlICsgY3RybC9tZXRhL3NoaWZ0S2V5LCBvciBhcnJvdyBrZXlzIC8gdG91Y2g6IHR3by1maW5nZXIgbW92ZVxuXG5jb25zdCBfY2hhbmdlRXZlbnQgPSB7IHR5cGU6ICdjaGFuZ2UnIH07XG5jb25zdCBfc3RhcnRFdmVudCA9IHsgdHlwZTogJ3N0YXJ0JyB9O1xuY29uc3QgX2VuZEV2ZW50ID0geyB0eXBlOiAnZW5kJyB9O1xuY29uc3QgX3JheSA9IG5ldyBSYXkoKTtcbmNvbnN0IF9wbGFuZSA9IG5ldyBQbGFuZSgpO1xuY29uc3QgVElMVF9MSU1JVCA9IE1hdGguY29zKCA3MCAqIE1hdGhVdGlscy5ERUcyUkFEICk7XG5cbmNsYXNzIE9yYml0Q29udHJvbHMgZXh0ZW5kcyBFdmVudERpc3BhdGNoZXIge1xuXG5cdGNvbnN0cnVjdG9yKCBvYmplY3QsIGRvbUVsZW1lbnQgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5vYmplY3QgPSBvYmplY3Q7XG5cdFx0dGhpcy5kb21FbGVtZW50ID0gZG9tRWxlbWVudDtcblx0XHR0aGlzLmRvbUVsZW1lbnQuc3R5bGUudG91Y2hBY3Rpb24gPSAnbm9uZSc7IC8vIGRpc2FibGUgdG91Y2ggc2Nyb2xsXG5cblx0XHQvLyBTZXQgdG8gZmFsc2UgdG8gZGlzYWJsZSB0aGlzIGNvbnRyb2xcblx0XHR0aGlzLmVuYWJsZWQgPSB0cnVlO1xuXG5cdFx0Ly8gXCJ0YXJnZXRcIiBzZXRzIHRoZSBsb2NhdGlvbiBvZiBmb2N1cywgd2hlcmUgdGhlIG9iamVjdCBvcmJpdHMgYXJvdW5kXG5cdFx0dGhpcy50YXJnZXQgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0Ly8gU2V0cyB0aGUgM0QgY3Vyc29yIChzaW1pbGFyIHRvIEJsZW5kZXIpLCBmcm9tIHdoaWNoIHRoZSBtYXhUYXJnZXRSYWRpdXMgdGFrZXMgZWZmZWN0XG5cdFx0dGhpcy5jdXJzb3IgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0Ly8gSG93IGZhciB5b3UgY2FuIGRvbGx5IGluIGFuZCBvdXQgKCBQZXJzcGVjdGl2ZUNhbWVyYSBvbmx5IClcblx0XHR0aGlzLm1pbkRpc3RhbmNlID0gMDtcblx0XHR0aGlzLm1heERpc3RhbmNlID0gSW5maW5pdHk7XG5cblx0XHQvLyBIb3cgZmFyIHlvdSBjYW4gem9vbSBpbiBhbmQgb3V0ICggT3J0aG9ncmFwaGljQ2FtZXJhIG9ubHkgKVxuXHRcdHRoaXMubWluWm9vbSA9IDA7XG5cdFx0dGhpcy5tYXhab29tID0gSW5maW5pdHk7XG5cblx0XHQvLyBMaW1pdCBjYW1lcmEgdGFyZ2V0IHdpdGhpbiBhIHNwaGVyaWNhbCBhcmVhIGFyb3VuZCB0aGUgY3Vyc29yXG5cdFx0dGhpcy5taW5UYXJnZXRSYWRpdXMgPSAwO1xuXHRcdHRoaXMubWF4VGFyZ2V0UmFkaXVzID0gSW5maW5pdHk7XG5cblx0XHQvLyBIb3cgZmFyIHlvdSBjYW4gb3JiaXQgdmVydGljYWxseSwgdXBwZXIgYW5kIGxvd2VyIGxpbWl0cy5cblx0XHQvLyBSYW5nZSBpcyAwIHRvIE1hdGguUEkgcmFkaWFucy5cblx0XHR0aGlzLm1pblBvbGFyQW5nbGUgPSAwOyAvLyByYWRpYW5zXG5cdFx0dGhpcy5tYXhQb2xhckFuZ2xlID0gTWF0aC5QSTsgLy8gcmFkaWFuc1xuXG5cdFx0Ly8gSG93IGZhciB5b3UgY2FuIG9yYml0IGhvcml6b250YWxseSwgdXBwZXIgYW5kIGxvd2VyIGxpbWl0cy5cblx0XHQvLyBJZiBzZXQsIHRoZSBpbnRlcnZhbCBbIG1pbiwgbWF4IF0gbXVzdCBiZSBhIHN1Yi1pbnRlcnZhbCBvZiBbIC0gMiBQSSwgMiBQSSBdLCB3aXRoICggbWF4IC0gbWluIDwgMiBQSSApXG5cdFx0dGhpcy5taW5BemltdXRoQW5nbGUgPSAtIEluZmluaXR5OyAvLyByYWRpYW5zXG5cdFx0dGhpcy5tYXhBemltdXRoQW5nbGUgPSBJbmZpbml0eTsgLy8gcmFkaWFuc1xuXG5cdFx0Ly8gU2V0IHRvIHRydWUgdG8gZW5hYmxlIGRhbXBpbmcgKGluZXJ0aWEpXG5cdFx0Ly8gSWYgZGFtcGluZyBpcyBlbmFibGVkLCB5b3UgbXVzdCBjYWxsIGNvbnRyb2xzLnVwZGF0ZSgpIGluIHlvdXIgYW5pbWF0aW9uIGxvb3Bcblx0XHR0aGlzLmVuYWJsZURhbXBpbmcgPSBmYWxzZTtcblx0XHR0aGlzLmRhbXBpbmdGYWN0b3IgPSAwLjA1O1xuXG5cdFx0Ly8gVGhpcyBvcHRpb24gYWN0dWFsbHkgZW5hYmxlcyBkb2xseWluZyBpbiBhbmQgb3V0OyBsZWZ0IGFzIFwiem9vbVwiIGZvciBiYWNrd2FyZHMgY29tcGF0aWJpbGl0eS5cblx0XHQvLyBTZXQgdG8gZmFsc2UgdG8gZGlzYWJsZSB6b29taW5nXG5cdFx0dGhpcy5lbmFibGVab29tID0gdHJ1ZTtcblx0XHR0aGlzLnpvb21TcGVlZCA9IDEuMDtcblxuXHRcdC8vIFNldCB0byBmYWxzZSB0byBkaXNhYmxlIHJvdGF0aW5nXG5cdFx0dGhpcy5lbmFibGVSb3RhdGUgPSB0cnVlO1xuXHRcdHRoaXMucm90YXRlU3BlZWQgPSAxLjA7XG5cblx0XHQvLyBTZXQgdG8gZmFsc2UgdG8gZGlzYWJsZSBwYW5uaW5nXG5cdFx0dGhpcy5lbmFibGVQYW4gPSB0cnVlO1xuXHRcdHRoaXMucGFuU3BlZWQgPSAxLjA7XG5cdFx0dGhpcy5zY3JlZW5TcGFjZVBhbm5pbmcgPSB0cnVlOyAvLyBpZiBmYWxzZSwgcGFuIG9ydGhvZ29uYWwgdG8gd29ybGQtc3BhY2UgZGlyZWN0aW9uIGNhbWVyYS51cFxuXHRcdHRoaXMua2V5UGFuU3BlZWQgPSA3LjA7XHQvLyBwaXhlbHMgbW92ZWQgcGVyIGFycm93IGtleSBwdXNoXG5cdFx0dGhpcy56b29tVG9DdXJzb3IgPSBmYWxzZTtcblxuXHRcdC8vIFNldCB0byB0cnVlIHRvIGF1dG9tYXRpY2FsbHkgcm90YXRlIGFyb3VuZCB0aGUgdGFyZ2V0XG5cdFx0Ly8gSWYgYXV0by1yb3RhdGUgaXMgZW5hYmxlZCwgeW91IG11c3QgY2FsbCBjb250cm9scy51cGRhdGUoKSBpbiB5b3VyIGFuaW1hdGlvbiBsb29wXG5cdFx0dGhpcy5hdXRvUm90YXRlID0gZmFsc2U7XG5cdFx0dGhpcy5hdXRvUm90YXRlU3BlZWQgPSAyLjA7IC8vIDMwIHNlY29uZHMgcGVyIG9yYml0IHdoZW4gZnBzIGlzIDYwXG5cblx0XHQvLyBUaGUgZm91ciBhcnJvdyBrZXlzXG5cdFx0dGhpcy5rZXlzID0geyBMRUZUOiAnQXJyb3dMZWZ0JywgVVA6ICdBcnJvd1VwJywgUklHSFQ6ICdBcnJvd1JpZ2h0JywgQk9UVE9NOiAnQXJyb3dEb3duJyB9O1xuXG5cdFx0Ly8gTW91c2UgYnV0dG9uc1xuXHRcdHRoaXMubW91c2VCdXR0b25zID0geyBMRUZUOiBNT1VTRS5ST1RBVEUsIE1JRERMRTogTU9VU0UuRE9MTFksIFJJR0hUOiBNT1VTRS5QQU4gfTtcblxuXHRcdC8vIFRvdWNoIGZpbmdlcnNcblx0XHR0aGlzLnRvdWNoZXMgPSB7IE9ORTogVE9VQ0guUk9UQVRFLCBUV086IFRPVUNILkRPTExZX1BBTiB9O1xuXG5cdFx0Ly8gZm9yIHJlc2V0XG5cdFx0dGhpcy50YXJnZXQwID0gdGhpcy50YXJnZXQuY2xvbmUoKTtcblx0XHR0aGlzLnBvc2l0aW9uMCA9IHRoaXMub2JqZWN0LnBvc2l0aW9uLmNsb25lKCk7XG5cdFx0dGhpcy56b29tMCA9IHRoaXMub2JqZWN0Lnpvb207XG5cblx0XHQvLyB0aGUgdGFyZ2V0IERPTSBlbGVtZW50IGZvciBrZXkgZXZlbnRzXG5cdFx0dGhpcy5fZG9tRWxlbWVudEtleUV2ZW50cyA9IG51bGw7XG5cblx0XHQvL1xuXHRcdC8vIHB1YmxpYyBtZXRob2RzXG5cdFx0Ly9cblxuXHRcdHRoaXMuZ2V0UG9sYXJBbmdsZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIHNwaGVyaWNhbC5waGk7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5nZXRBemltdXRoYWxBbmdsZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0cmV0dXJuIHNwaGVyaWNhbC50aGV0YTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmdldERpc3RhbmNlID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRyZXR1cm4gdGhpcy5vYmplY3QucG9zaXRpb24uZGlzdGFuY2VUbyggdGhpcy50YXJnZXQgKTtcblxuXHRcdH07XG5cblx0XHR0aGlzLmxpc3RlblRvS2V5RXZlbnRzID0gZnVuY3Rpb24gKCBkb21FbGVtZW50ICkge1xuXG5cdFx0XHRkb21FbGVtZW50LmFkZEV2ZW50TGlzdGVuZXIoICdrZXlkb3duJywgb25LZXlEb3duICk7XG5cdFx0XHR0aGlzLl9kb21FbGVtZW50S2V5RXZlbnRzID0gZG9tRWxlbWVudDtcblxuXHRcdH07XG5cblx0XHR0aGlzLnN0b3BMaXN0ZW5Ub0tleUV2ZW50cyA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0dGhpcy5fZG9tRWxlbWVudEtleUV2ZW50cy5yZW1vdmVFdmVudExpc3RlbmVyKCAna2V5ZG93bicsIG9uS2V5RG93biApO1xuXHRcdFx0dGhpcy5fZG9tRWxlbWVudEtleUV2ZW50cyA9IG51bGw7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5zYXZlU3RhdGUgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHNjb3BlLnRhcmdldDAuY29weSggc2NvcGUudGFyZ2V0ICk7XG5cdFx0XHRzY29wZS5wb3NpdGlvbjAuY29weSggc2NvcGUub2JqZWN0LnBvc2l0aW9uICk7XG5cdFx0XHRzY29wZS56b29tMCA9IHNjb3BlLm9iamVjdC56b29tO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMucmVzZXQgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdHNjb3BlLnRhcmdldC5jb3B5KCBzY29wZS50YXJnZXQwICk7XG5cdFx0XHRzY29wZS5vYmplY3QucG9zaXRpb24uY29weSggc2NvcGUucG9zaXRpb24wICk7XG5cdFx0XHRzY29wZS5vYmplY3Quem9vbSA9IHNjb3BlLnpvb20wO1xuXG5cdFx0XHRzY29wZS5vYmplY3QudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXHRcdFx0c2NvcGUuZGlzcGF0Y2hFdmVudCggX2NoYW5nZUV2ZW50ICk7XG5cblx0XHRcdHNjb3BlLnVwZGF0ZSgpO1xuXG5cdFx0XHRzdGF0ZSA9IFNUQVRFLk5PTkU7XG5cblx0XHR9O1xuXG5cdFx0Ly8gdGhpcyBtZXRob2QgaXMgZXhwb3NlZCwgYnV0IHBlcmhhcHMgaXQgd291bGQgYmUgYmV0dGVyIGlmIHdlIGNhbiBtYWtlIGl0IHByaXZhdGUuLi5cblx0XHR0aGlzLnVwZGF0ZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0Y29uc3Qgb2Zmc2V0ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdFx0Ly8gc28gY2FtZXJhLnVwIGlzIHRoZSBvcmJpdCBheGlzXG5cdFx0XHRjb25zdCBxdWF0ID0gbmV3IFF1YXRlcm5pb24oKS5zZXRGcm9tVW5pdFZlY3RvcnMoIG9iamVjdC51cCwgbmV3IFZlY3RvcjMoIDAsIDEsIDAgKSApO1xuXHRcdFx0Y29uc3QgcXVhdEludmVyc2UgPSBxdWF0LmNsb25lKCkuaW52ZXJ0KCk7XG5cblx0XHRcdGNvbnN0IGxhc3RQb3NpdGlvbiA9IG5ldyBWZWN0b3IzKCk7XG5cdFx0XHRjb25zdCBsYXN0UXVhdGVybmlvbiA9IG5ldyBRdWF0ZXJuaW9uKCk7XG5cdFx0XHRjb25zdCBsYXN0VGFyZ2V0UG9zaXRpb24gPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHRjb25zdCB0d29QSSA9IDIgKiBNYXRoLlBJO1xuXG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24gdXBkYXRlKCBkZWx0YVRpbWUgPSBudWxsICkge1xuXG5cdFx0XHRcdGNvbnN0IHBvc2l0aW9uID0gc2NvcGUub2JqZWN0LnBvc2l0aW9uO1xuXG5cdFx0XHRcdG9mZnNldC5jb3B5KCBwb3NpdGlvbiApLnN1Yiggc2NvcGUudGFyZ2V0ICk7XG5cblx0XHRcdFx0Ly8gcm90YXRlIG9mZnNldCB0byBcInktYXhpcy1pcy11cFwiIHNwYWNlXG5cdFx0XHRcdG9mZnNldC5hcHBseVF1YXRlcm5pb24oIHF1YXQgKTtcblxuXHRcdFx0XHQvLyBhbmdsZSBmcm9tIHotYXhpcyBhcm91bmQgeS1heGlzXG5cdFx0XHRcdHNwaGVyaWNhbC5zZXRGcm9tVmVjdG9yMyggb2Zmc2V0ICk7XG5cblx0XHRcdFx0aWYgKCBzY29wZS5hdXRvUm90YXRlICYmIHN0YXRlID09PSBTVEFURS5OT05FICkge1xuXG5cdFx0XHRcdFx0cm90YXRlTGVmdCggZ2V0QXV0b1JvdGF0aW9uQW5nbGUoIGRlbHRhVGltZSApICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlRGFtcGluZyApIHtcblxuXHRcdFx0XHRcdHNwaGVyaWNhbC50aGV0YSArPSBzcGhlcmljYWxEZWx0YS50aGV0YSAqIHNjb3BlLmRhbXBpbmdGYWN0b3I7XG5cdFx0XHRcdFx0c3BoZXJpY2FsLnBoaSArPSBzcGhlcmljYWxEZWx0YS5waGkgKiBzY29wZS5kYW1waW5nRmFjdG9yO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRzcGhlcmljYWwudGhldGEgKz0gc3BoZXJpY2FsRGVsdGEudGhldGE7XG5cdFx0XHRcdFx0c3BoZXJpY2FsLnBoaSArPSBzcGhlcmljYWxEZWx0YS5waGk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIHJlc3RyaWN0IHRoZXRhIHRvIGJlIGJldHdlZW4gZGVzaXJlZCBsaW1pdHNcblxuXHRcdFx0XHRsZXQgbWluID0gc2NvcGUubWluQXppbXV0aEFuZ2xlO1xuXHRcdFx0XHRsZXQgbWF4ID0gc2NvcGUubWF4QXppbXV0aEFuZ2xlO1xuXG5cdFx0XHRcdGlmICggaXNGaW5pdGUoIG1pbiApICYmIGlzRmluaXRlKCBtYXggKSApIHtcblxuXHRcdFx0XHRcdGlmICggbWluIDwgLSBNYXRoLlBJICkgbWluICs9IHR3b1BJOyBlbHNlIGlmICggbWluID4gTWF0aC5QSSApIG1pbiAtPSB0d29QSTtcblxuXHRcdFx0XHRcdGlmICggbWF4IDwgLSBNYXRoLlBJICkgbWF4ICs9IHR3b1BJOyBlbHNlIGlmICggbWF4ID4gTWF0aC5QSSApIG1heCAtPSB0d29QSTtcblxuXHRcdFx0XHRcdGlmICggbWluIDw9IG1heCApIHtcblxuXHRcdFx0XHRcdFx0c3BoZXJpY2FsLnRoZXRhID0gTWF0aC5tYXgoIG1pbiwgTWF0aC5taW4oIG1heCwgc3BoZXJpY2FsLnRoZXRhICkgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHNwaGVyaWNhbC50aGV0YSA9ICggc3BoZXJpY2FsLnRoZXRhID4gKCBtaW4gKyBtYXggKSAvIDIgKSA/XG5cdFx0XHRcdFx0XHRcdE1hdGgubWF4KCBtaW4sIHNwaGVyaWNhbC50aGV0YSApIDpcblx0XHRcdFx0XHRcdFx0TWF0aC5taW4oIG1heCwgc3BoZXJpY2FsLnRoZXRhICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdC8vIHJlc3RyaWN0IHBoaSB0byBiZSBiZXR3ZWVuIGRlc2lyZWQgbGltaXRzXG5cdFx0XHRcdHNwaGVyaWNhbC5waGkgPSBNYXRoLm1heCggc2NvcGUubWluUG9sYXJBbmdsZSwgTWF0aC5taW4oIHNjb3BlLm1heFBvbGFyQW5nbGUsIHNwaGVyaWNhbC5waGkgKSApO1xuXG5cdFx0XHRcdHNwaGVyaWNhbC5tYWtlU2FmZSgpO1xuXG5cblx0XHRcdFx0Ly8gbW92ZSB0YXJnZXQgdG8gcGFubmVkIGxvY2F0aW9uXG5cblx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVEYW1waW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0c2NvcGUudGFyZ2V0LmFkZFNjYWxlZFZlY3RvciggcGFuT2Zmc2V0LCBzY29wZS5kYW1waW5nRmFjdG9yICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHNjb3BlLnRhcmdldC5hZGQoIHBhbk9mZnNldCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBMaW1pdCB0aGUgdGFyZ2V0IGRpc3RhbmNlIGZyb20gdGhlIGN1cnNvciB0byBjcmVhdGUgYSBzcGhlcmUgYXJvdW5kIHRoZSBjZW50ZXIgb2YgaW50ZXJlc3Rcblx0XHRcdFx0c2NvcGUudGFyZ2V0LnN1Yiggc2NvcGUuY3Vyc29yICk7XG5cdFx0XHRcdHNjb3BlLnRhcmdldC5jbGFtcExlbmd0aCggc2NvcGUubWluVGFyZ2V0UmFkaXVzLCBzY29wZS5tYXhUYXJnZXRSYWRpdXMgKTtcblx0XHRcdFx0c2NvcGUudGFyZ2V0LmFkZCggc2NvcGUuY3Vyc29yICk7XG5cblx0XHRcdFx0bGV0IHpvb21DaGFuZ2VkID0gZmFsc2U7XG5cdFx0XHRcdC8vIGFkanVzdCB0aGUgY2FtZXJhIHBvc2l0aW9uIGJhc2VkIG9uIHpvb20gb25seSBpZiB3ZSdyZSBub3Qgem9vbWluZyB0byB0aGUgY3Vyc29yIG9yIGlmIGl0J3MgYW4gb3J0aG8gY2FtZXJhXG5cdFx0XHRcdC8vIHdlIGFkanVzdCB6b29tIGxhdGVyIGluIHRoZXNlIGNhc2VzXG5cdFx0XHRcdGlmICggc2NvcGUuem9vbVRvQ3Vyc29yICYmIHBlcmZvcm1DdXJzb3Jab29tIHx8IHNjb3BlLm9iamVjdC5pc09ydGhvZ3JhcGhpY0NhbWVyYSApIHtcblxuXHRcdFx0XHRcdHNwaGVyaWNhbC5yYWRpdXMgPSBjbGFtcERpc3RhbmNlKCBzcGhlcmljYWwucmFkaXVzICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdGNvbnN0IHByZXZSYWRpdXMgPSBzcGhlcmljYWwucmFkaXVzO1xuXHRcdFx0XHRcdHNwaGVyaWNhbC5yYWRpdXMgPSBjbGFtcERpc3RhbmNlKCBzcGhlcmljYWwucmFkaXVzICogc2NhbGUgKTtcblx0XHRcdFx0XHR6b29tQ2hhbmdlZCA9IHByZXZSYWRpdXMgIT0gc3BoZXJpY2FsLnJhZGl1cztcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0b2Zmc2V0LnNldEZyb21TcGhlcmljYWwoIHNwaGVyaWNhbCApO1xuXG5cdFx0XHRcdC8vIHJvdGF0ZSBvZmZzZXQgYmFjayB0byBcImNhbWVyYS11cC12ZWN0b3ItaXMtdXBcIiBzcGFjZVxuXHRcdFx0XHRvZmZzZXQuYXBwbHlRdWF0ZXJuaW9uKCBxdWF0SW52ZXJzZSApO1xuXG5cdFx0XHRcdHBvc2l0aW9uLmNvcHkoIHNjb3BlLnRhcmdldCApLmFkZCggb2Zmc2V0ICk7XG5cblx0XHRcdFx0c2NvcGUub2JqZWN0Lmxvb2tBdCggc2NvcGUudGFyZ2V0ICk7XG5cblx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVEYW1waW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0c3BoZXJpY2FsRGVsdGEudGhldGEgKj0gKCAxIC0gc2NvcGUuZGFtcGluZ0ZhY3RvciApO1xuXHRcdFx0XHRcdHNwaGVyaWNhbERlbHRhLnBoaSAqPSAoIDEgLSBzY29wZS5kYW1waW5nRmFjdG9yICk7XG5cblx0XHRcdFx0XHRwYW5PZmZzZXQubXVsdGlwbHlTY2FsYXIoIDEgLSBzY29wZS5kYW1waW5nRmFjdG9yICk7XG5cblx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdHNwaGVyaWNhbERlbHRhLnNldCggMCwgMCwgMCApO1xuXG5cdFx0XHRcdFx0cGFuT2Zmc2V0LnNldCggMCwgMCwgMCApO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHQvLyBhZGp1c3QgY2FtZXJhIHBvc2l0aW9uXG5cdFx0XHRcdGlmICggc2NvcGUuem9vbVRvQ3Vyc29yICYmIHBlcmZvcm1DdXJzb3Jab29tICkge1xuXG5cdFx0XHRcdFx0bGV0IG5ld1JhZGl1cyA9IG51bGw7XG5cdFx0XHRcdFx0aWYgKCBzY29wZS5vYmplY3QuaXNQZXJzcGVjdGl2ZUNhbWVyYSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gbW92ZSB0aGUgY2FtZXJhIGRvd24gdGhlIHBvaW50ZXIgcmF5XG5cdFx0XHRcdFx0XHQvLyB0aGlzIG1ldGhvZCBhdm9pZHMgZmxvYXRpbmcgcG9pbnQgZXJyb3Jcblx0XHRcdFx0XHRcdGNvbnN0IHByZXZSYWRpdXMgPSBvZmZzZXQubGVuZ3RoKCk7XG5cdFx0XHRcdFx0XHRuZXdSYWRpdXMgPSBjbGFtcERpc3RhbmNlKCBwcmV2UmFkaXVzICogc2NhbGUgKTtcblxuXHRcdFx0XHRcdFx0Y29uc3QgcmFkaXVzRGVsdGEgPSBwcmV2UmFkaXVzIC0gbmV3UmFkaXVzO1xuXHRcdFx0XHRcdFx0c2NvcGUub2JqZWN0LnBvc2l0aW9uLmFkZFNjYWxlZFZlY3RvciggZG9sbHlEaXJlY3Rpb24sIHJhZGl1c0RlbHRhICk7XG5cdFx0XHRcdFx0XHRzY29wZS5vYmplY3QudXBkYXRlTWF0cml4V29ybGQoKTtcblxuXHRcdFx0XHRcdFx0em9vbUNoYW5nZWQgPSAhISByYWRpdXNEZWx0YTtcblxuXHRcdFx0XHRcdH0gZWxzZSBpZiAoIHNjb3BlLm9iamVjdC5pc09ydGhvZ3JhcGhpY0NhbWVyYSApIHtcblxuXHRcdFx0XHRcdFx0Ly8gYWRqdXN0IHRoZSBvcnRobyBjYW1lcmEgcG9zaXRpb24gYmFzZWQgb24gem9vbSBjaGFuZ2VzXG5cdFx0XHRcdFx0XHRjb25zdCBtb3VzZUJlZm9yZSA9IG5ldyBWZWN0b3IzKCBtb3VzZS54LCBtb3VzZS55LCAwICk7XG5cdFx0XHRcdFx0XHRtb3VzZUJlZm9yZS51bnByb2plY3QoIHNjb3BlLm9iamVjdCApO1xuXG5cdFx0XHRcdFx0XHRjb25zdCBwcmV2Wm9vbSA9IHNjb3BlLm9iamVjdC56b29tO1xuXHRcdFx0XHRcdFx0c2NvcGUub2JqZWN0Lnpvb20gPSBNYXRoLm1heCggc2NvcGUubWluWm9vbSwgTWF0aC5taW4oIHNjb3BlLm1heFpvb20sIHNjb3BlLm9iamVjdC56b29tIC8gc2NhbGUgKSApO1xuXHRcdFx0XHRcdFx0c2NvcGUub2JqZWN0LnVwZGF0ZVByb2plY3Rpb25NYXRyaXgoKTtcblxuXHRcdFx0XHRcdFx0em9vbUNoYW5nZWQgPSBwcmV2Wm9vbSAhPT0gc2NvcGUub2JqZWN0Lnpvb207XG5cblx0XHRcdFx0XHRcdGNvbnN0IG1vdXNlQWZ0ZXIgPSBuZXcgVmVjdG9yMyggbW91c2UueCwgbW91c2UueSwgMCApO1xuXHRcdFx0XHRcdFx0bW91c2VBZnRlci51bnByb2plY3QoIHNjb3BlLm9iamVjdCApO1xuXG5cdFx0XHRcdFx0XHRzY29wZS5vYmplY3QucG9zaXRpb24uc3ViKCBtb3VzZUFmdGVyICkuYWRkKCBtb3VzZUJlZm9yZSApO1xuXHRcdFx0XHRcdFx0c2NvcGUub2JqZWN0LnVwZGF0ZU1hdHJpeFdvcmxkKCk7XG5cblx0XHRcdFx0XHRcdG5ld1JhZGl1cyA9IG9mZnNldC5sZW5ndGgoKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGNvbnNvbGUud2FybiggJ1dBUk5JTkc6IE9yYml0Q29udHJvbHMuanMgZW5jb3VudGVyZWQgYW4gdW5rbm93biBjYW1lcmEgdHlwZSAtIHpvb20gdG8gY3Vyc29yIGRpc2FibGVkLicgKTtcblx0XHRcdFx0XHRcdHNjb3BlLnpvb21Ub0N1cnNvciA9IGZhbHNlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0Ly8gaGFuZGxlIHRoZSBwbGFjZW1lbnQgb2YgdGhlIHRhcmdldFxuXHRcdFx0XHRcdGlmICggbmV3UmFkaXVzICE9PSBudWxsICkge1xuXG5cdFx0XHRcdFx0XHRpZiAoIHRoaXMuc2NyZWVuU3BhY2VQYW5uaW5nICkge1xuXG5cdFx0XHRcdFx0XHRcdC8vIHBvc2l0aW9uIHRoZSBvcmJpdCB0YXJnZXQgaW4gZnJvbnQgb2YgdGhlIG5ldyBjYW1lcmEgcG9zaXRpb25cblx0XHRcdFx0XHRcdFx0c2NvcGUudGFyZ2V0LnNldCggMCwgMCwgLSAxIClcblx0XHRcdFx0XHRcdFx0XHQudHJhbnNmb3JtRGlyZWN0aW9uKCBzY29wZS5vYmplY3QubWF0cml4IClcblx0XHRcdFx0XHRcdFx0XHQubXVsdGlwbHlTY2FsYXIoIG5ld1JhZGl1cyApXG5cdFx0XHRcdFx0XHRcdFx0LmFkZCggc2NvcGUub2JqZWN0LnBvc2l0aW9uICk7XG5cblx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0Ly8gZ2V0IHRoZSByYXkgYW5kIHRyYW5zbGF0aW9uIHBsYW5lIHRvIGNvbXB1dGUgdGFyZ2V0XG5cdFx0XHRcdFx0XHRcdF9yYXkub3JpZ2luLmNvcHkoIHNjb3BlLm9iamVjdC5wb3NpdGlvbiApO1xuXHRcdFx0XHRcdFx0XHRfcmF5LmRpcmVjdGlvbi5zZXQoIDAsIDAsIC0gMSApLnRyYW5zZm9ybURpcmVjdGlvbiggc2NvcGUub2JqZWN0Lm1hdHJpeCApO1xuXG5cdFx0XHRcdFx0XHRcdC8vIGlmIHRoZSBjYW1lcmEgaXMgMjAgZGVncmVlcyBhYm92ZSB0aGUgaG9yaXpvbiB0aGVuIGRvbid0IGFkanVzdCB0aGUgZm9jdXMgdGFyZ2V0IHRvIGF2b2lkXG5cdFx0XHRcdFx0XHRcdC8vIGV4dHJlbWVseSBsYXJnZSB2YWx1ZXNcblx0XHRcdFx0XHRcdFx0aWYgKCBNYXRoLmFicyggc2NvcGUub2JqZWN0LnVwLmRvdCggX3JheS5kaXJlY3Rpb24gKSApIDwgVElMVF9MSU1JVCApIHtcblxuXHRcdFx0XHRcdFx0XHRcdG9iamVjdC5sb29rQXQoIHNjb3BlLnRhcmdldCApO1xuXG5cdFx0XHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdFx0XHRfcGxhbmUuc2V0RnJvbU5vcm1hbEFuZENvcGxhbmFyUG9pbnQoIHNjb3BlLm9iamVjdC51cCwgc2NvcGUudGFyZ2V0ICk7XG5cdFx0XHRcdFx0XHRcdFx0X3JheS5pbnRlcnNlY3RQbGFuZSggX3BsYW5lLCBzY29wZS50YXJnZXQgKTtcblxuXHRcdFx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBzY29wZS5vYmplY3QuaXNPcnRob2dyYXBoaWNDYW1lcmEgKSB7XG5cblx0XHRcdFx0XHRjb25zdCBwcmV2Wm9vbSA9IHNjb3BlLm9iamVjdC56b29tO1xuXHRcdFx0XHRcdHNjb3BlLm9iamVjdC56b29tID0gTWF0aC5tYXgoIHNjb3BlLm1pblpvb20sIE1hdGgubWluKCBzY29wZS5tYXhab29tLCBzY29wZS5vYmplY3Quem9vbSAvIHNjYWxlICkgKTtcblxuXHRcdFx0XHRcdGlmICggcHJldlpvb20gIT09IHNjb3BlLm9iamVjdC56b29tICkge1xuXG5cdFx0XHRcdFx0XHRzY29wZS5vYmplY3QudXBkYXRlUHJvamVjdGlvbk1hdHJpeCgpO1xuXHRcdFx0XHRcdFx0em9vbUNoYW5nZWQgPSB0cnVlO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdH1cblxuXHRcdFx0XHRzY2FsZSA9IDE7XG5cdFx0XHRcdHBlcmZvcm1DdXJzb3Jab29tID0gZmFsc2U7XG5cblx0XHRcdFx0Ly8gdXBkYXRlIGNvbmRpdGlvbiBpczpcblx0XHRcdFx0Ly8gbWluKGNhbWVyYSBkaXNwbGFjZW1lbnQsIGNhbWVyYSByb3RhdGlvbiBpbiByYWRpYW5zKV4yID4gRVBTXG5cdFx0XHRcdC8vIHVzaW5nIHNtYWxsLWFuZ2xlIGFwcHJveGltYXRpb24gY29zKHgvMikgPSAxIC0geF4yIC8gOFxuXG5cdFx0XHRcdGlmICggem9vbUNoYW5nZWQgfHxcblx0XHRcdFx0XHRsYXN0UG9zaXRpb24uZGlzdGFuY2VUb1NxdWFyZWQoIHNjb3BlLm9iamVjdC5wb3NpdGlvbiApID4gRVBTIHx8XG5cdFx0XHRcdFx0OCAqICggMSAtIGxhc3RRdWF0ZXJuaW9uLmRvdCggc2NvcGUub2JqZWN0LnF1YXRlcm5pb24gKSApID4gRVBTIHx8XG5cdFx0XHRcdFx0bGFzdFRhcmdldFBvc2l0aW9uLmRpc3RhbmNlVG9TcXVhcmVkKCBzY29wZS50YXJnZXQgKSA+IEVQUyApIHtcblxuXHRcdFx0XHRcdHNjb3BlLmRpc3BhdGNoRXZlbnQoIF9jaGFuZ2VFdmVudCApO1xuXG5cdFx0XHRcdFx0bGFzdFBvc2l0aW9uLmNvcHkoIHNjb3BlLm9iamVjdC5wb3NpdGlvbiApO1xuXHRcdFx0XHRcdGxhc3RRdWF0ZXJuaW9uLmNvcHkoIHNjb3BlLm9iamVjdC5xdWF0ZXJuaW9uICk7XG5cdFx0XHRcdFx0bGFzdFRhcmdldFBvc2l0aW9uLmNvcHkoIHNjb3BlLnRhcmdldCApO1xuXG5cdFx0XHRcdFx0cmV0dXJuIHRydWU7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdFx0fTtcblxuXHRcdH0oKTtcblxuXHRcdHRoaXMuZGlzcG9zZSA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0c2NvcGUuZG9tRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCAnY29udGV4dG1lbnUnLCBvbkNvbnRleHRNZW51ICk7XG5cblx0XHRcdHNjb3BlLmRvbUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3BvaW50ZXJkb3duJywgb25Qb2ludGVyRG93biApO1xuXHRcdFx0c2NvcGUuZG9tRWxlbWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCAncG9pbnRlcmNhbmNlbCcsIG9uUG9pbnRlclVwICk7XG5cdFx0XHRzY29wZS5kb21FbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoICd3aGVlbCcsIG9uTW91c2VXaGVlbCApO1xuXG5cdFx0XHRzY29wZS5kb21FbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoICdwb2ludGVybW92ZScsIG9uUG9pbnRlck1vdmUgKTtcblx0XHRcdHNjb3BlLmRvbUVsZW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ3BvaW50ZXJ1cCcsIG9uUG9pbnRlclVwICk7XG5cblx0XHRcdGNvbnN0IGRvY3VtZW50ID0gc2NvcGUuZG9tRWxlbWVudC5nZXRSb290Tm9kZSgpOyAvLyBvZmZzY3JlZW4gY2FudmFzIGNvbXBhdGliaWxpdHlcblxuXHRcdFx0ZG9jdW1lbnQucmVtb3ZlRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCBpbnRlcmNlcHRDb250cm9sRG93biwgeyBjYXB0dXJlOiB0cnVlIH0gKTtcblxuXHRcdFx0aWYgKCBzY29wZS5fZG9tRWxlbWVudEtleUV2ZW50cyAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRzY29wZS5fZG9tRWxlbWVudEtleUV2ZW50cy5yZW1vdmVFdmVudExpc3RlbmVyKCAna2V5ZG93bicsIG9uS2V5RG93biApO1xuXHRcdFx0XHRzY29wZS5fZG9tRWxlbWVudEtleUV2ZW50cyA9IG51bGw7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9zY29wZS5kaXNwYXRjaEV2ZW50KCB7IHR5cGU6ICdkaXNwb3NlJyB9ICk7IC8vIHNob3VsZCB0aGlzIGJlIGFkZGVkIGhlcmU/XG5cblx0XHR9O1xuXG5cdFx0Ly9cblx0XHQvLyBpbnRlcm5hbHNcblx0XHQvL1xuXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0Y29uc3QgU1RBVEUgPSB7XG5cdFx0XHROT05FOiAtIDEsXG5cdFx0XHRST1RBVEU6IDAsXG5cdFx0XHRET0xMWTogMSxcblx0XHRcdFBBTjogMixcblx0XHRcdFRPVUNIX1JPVEFURTogMyxcblx0XHRcdFRPVUNIX1BBTjogNCxcblx0XHRcdFRPVUNIX0RPTExZX1BBTjogNSxcblx0XHRcdFRPVUNIX0RPTExZX1JPVEFURTogNlxuXHRcdH07XG5cblx0XHRsZXQgc3RhdGUgPSBTVEFURS5OT05FO1xuXG5cdFx0Y29uc3QgRVBTID0gMC4wMDAwMDE7XG5cblx0XHQvLyBjdXJyZW50IHBvc2l0aW9uIGluIHNwaGVyaWNhbCBjb29yZGluYXRlc1xuXHRcdGNvbnN0IHNwaGVyaWNhbCA9IG5ldyBTcGhlcmljYWwoKTtcblx0XHRjb25zdCBzcGhlcmljYWxEZWx0YSA9IG5ldyBTcGhlcmljYWwoKTtcblxuXHRcdGxldCBzY2FsZSA9IDE7XG5cdFx0Y29uc3QgcGFuT2Zmc2V0ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdGNvbnN0IHJvdGF0ZVN0YXJ0ID0gbmV3IFZlY3RvcjIoKTtcblx0XHRjb25zdCByb3RhdGVFbmQgPSBuZXcgVmVjdG9yMigpO1xuXHRcdGNvbnN0IHJvdGF0ZURlbHRhID0gbmV3IFZlY3RvcjIoKTtcblxuXHRcdGNvbnN0IHBhblN0YXJ0ID0gbmV3IFZlY3RvcjIoKTtcblx0XHRjb25zdCBwYW5FbmQgPSBuZXcgVmVjdG9yMigpO1xuXHRcdGNvbnN0IHBhbkRlbHRhID0gbmV3IFZlY3RvcjIoKTtcblxuXHRcdGNvbnN0IGRvbGx5U3RhcnQgPSBuZXcgVmVjdG9yMigpO1xuXHRcdGNvbnN0IGRvbGx5RW5kID0gbmV3IFZlY3RvcjIoKTtcblx0XHRjb25zdCBkb2xseURlbHRhID0gbmV3IFZlY3RvcjIoKTtcblxuXHRcdGNvbnN0IGRvbGx5RGlyZWN0aW9uID0gbmV3IFZlY3RvcjMoKTtcblx0XHRjb25zdCBtb3VzZSA9IG5ldyBWZWN0b3IyKCk7XG5cdFx0bGV0IHBlcmZvcm1DdXJzb3Jab29tID0gZmFsc2U7XG5cblx0XHRjb25zdCBwb2ludGVycyA9IFtdO1xuXHRcdGNvbnN0IHBvaW50ZXJQb3NpdGlvbnMgPSB7fTtcblxuXHRcdGxldCBjb250cm9sQWN0aXZlID0gZmFsc2U7XG5cblx0XHRmdW5jdGlvbiBnZXRBdXRvUm90YXRpb25BbmdsZSggZGVsdGFUaW1lICkge1xuXG5cdFx0XHRpZiAoIGRlbHRhVGltZSAhPT0gbnVsbCApIHtcblxuXHRcdFx0XHRyZXR1cm4gKCAyICogTWF0aC5QSSAvIDYwICogc2NvcGUuYXV0b1JvdGF0ZVNwZWVkICkgKiBkZWx0YVRpbWU7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0cmV0dXJuIDIgKiBNYXRoLlBJIC8gNjAgLyA2MCAqIHNjb3BlLmF1dG9Sb3RhdGVTcGVlZDtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gZ2V0Wm9vbVNjYWxlKCBkZWx0YSApIHtcblxuXHRcdFx0Y29uc3Qgbm9ybWFsaXplZERlbHRhID0gTWF0aC5hYnMoIGRlbHRhICogMC4wMSApO1xuXHRcdFx0cmV0dXJuIE1hdGgucG93KCAwLjk1LCBzY29wZS56b29tU3BlZWQgKiBub3JtYWxpemVkRGVsdGEgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHJvdGF0ZUxlZnQoIGFuZ2xlICkge1xuXG5cdFx0XHRzcGhlcmljYWxEZWx0YS50aGV0YSAtPSBhbmdsZTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHJvdGF0ZVVwKCBhbmdsZSApIHtcblxuXHRcdFx0c3BoZXJpY2FsRGVsdGEucGhpIC09IGFuZ2xlO1xuXG5cdFx0fVxuXG5cdFx0Y29uc3QgcGFuTGVmdCA9IGZ1bmN0aW9uICgpIHtcblxuXHRcdFx0Y29uc3QgdiA9IG5ldyBWZWN0b3IzKCk7XG5cblx0XHRcdHJldHVybiBmdW5jdGlvbiBwYW5MZWZ0KCBkaXN0YW5jZSwgb2JqZWN0TWF0cml4ICkge1xuXG5cdFx0XHRcdHYuc2V0RnJvbU1hdHJpeENvbHVtbiggb2JqZWN0TWF0cml4LCAwICk7IC8vIGdldCBYIGNvbHVtbiBvZiBvYmplY3RNYXRyaXhcblx0XHRcdFx0di5tdWx0aXBseVNjYWxhciggLSBkaXN0YW5jZSApO1xuXG5cdFx0XHRcdHBhbk9mZnNldC5hZGQoIHYgKTtcblxuXHRcdFx0fTtcblxuXHRcdH0oKTtcblxuXHRcdGNvbnN0IHBhblVwID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRjb25zdCB2ID0gbmV3IFZlY3RvcjMoKTtcblxuXHRcdFx0cmV0dXJuIGZ1bmN0aW9uIHBhblVwKCBkaXN0YW5jZSwgb2JqZWN0TWF0cml4ICkge1xuXG5cdFx0XHRcdGlmICggc2NvcGUuc2NyZWVuU3BhY2VQYW5uaW5nID09PSB0cnVlICkge1xuXG5cdFx0XHRcdFx0di5zZXRGcm9tTWF0cml4Q29sdW1uKCBvYmplY3RNYXRyaXgsIDEgKTtcblxuXHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0di5zZXRGcm9tTWF0cml4Q29sdW1uKCBvYmplY3RNYXRyaXgsIDAgKTtcblx0XHRcdFx0XHR2LmNyb3NzVmVjdG9ycyggc2NvcGUub2JqZWN0LnVwLCB2ICk7XG5cblx0XHRcdFx0fVxuXG5cdFx0XHRcdHYubXVsdGlwbHlTY2FsYXIoIGRpc3RhbmNlICk7XG5cblx0XHRcdFx0cGFuT2Zmc2V0LmFkZCggdiApO1xuXG5cdFx0XHR9O1xuXG5cdFx0fSgpO1xuXG5cdFx0Ly8gZGVsdGFYIGFuZCBkZWx0YVkgYXJlIGluIHBpeGVsczsgcmlnaHQgYW5kIGRvd24gYXJlIHBvc2l0aXZlXG5cdFx0Y29uc3QgcGFuID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHRjb25zdCBvZmZzZXQgPSBuZXcgVmVjdG9yMygpO1xuXG5cdFx0XHRyZXR1cm4gZnVuY3Rpb24gcGFuKCBkZWx0YVgsIGRlbHRhWSApIHtcblxuXHRcdFx0XHRjb25zdCBlbGVtZW50ID0gc2NvcGUuZG9tRWxlbWVudDtcblxuXHRcdFx0XHRpZiAoIHNjb3BlLm9iamVjdC5pc1BlcnNwZWN0aXZlQ2FtZXJhICkge1xuXG5cdFx0XHRcdFx0Ly8gcGVyc3BlY3RpdmVcblx0XHRcdFx0XHRjb25zdCBwb3NpdGlvbiA9IHNjb3BlLm9iamVjdC5wb3NpdGlvbjtcblx0XHRcdFx0XHRvZmZzZXQuY29weSggcG9zaXRpb24gKS5zdWIoIHNjb3BlLnRhcmdldCApO1xuXHRcdFx0XHRcdGxldCB0YXJnZXREaXN0YW5jZSA9IG9mZnNldC5sZW5ndGgoKTtcblxuXHRcdFx0XHRcdC8vIGhhbGYgb2YgdGhlIGZvdiBpcyBjZW50ZXIgdG8gdG9wIG9mIHNjcmVlblxuXHRcdFx0XHRcdHRhcmdldERpc3RhbmNlICo9IE1hdGgudGFuKCAoIHNjb3BlLm9iamVjdC5mb3YgLyAyICkgKiBNYXRoLlBJIC8gMTgwLjAgKTtcblxuXHRcdFx0XHRcdC8vIHdlIHVzZSBvbmx5IGNsaWVudEhlaWdodCBoZXJlIHNvIGFzcGVjdCByYXRpbyBkb2VzIG5vdCBkaXN0b3J0IHNwZWVkXG5cdFx0XHRcdFx0cGFuTGVmdCggMiAqIGRlbHRhWCAqIHRhcmdldERpc3RhbmNlIC8gZWxlbWVudC5jbGllbnRIZWlnaHQsIHNjb3BlLm9iamVjdC5tYXRyaXggKTtcblx0XHRcdFx0XHRwYW5VcCggMiAqIGRlbHRhWSAqIHRhcmdldERpc3RhbmNlIC8gZWxlbWVudC5jbGllbnRIZWlnaHQsIHNjb3BlLm9iamVjdC5tYXRyaXggKTtcblxuXHRcdFx0XHR9IGVsc2UgaWYgKCBzY29wZS5vYmplY3QuaXNPcnRob2dyYXBoaWNDYW1lcmEgKSB7XG5cblx0XHRcdFx0XHQvLyBvcnRob2dyYXBoaWNcblx0XHRcdFx0XHRwYW5MZWZ0KCBkZWx0YVggKiAoIHNjb3BlLm9iamVjdC5yaWdodCAtIHNjb3BlLm9iamVjdC5sZWZ0ICkgLyBzY29wZS5vYmplY3Quem9vbSAvIGVsZW1lbnQuY2xpZW50V2lkdGgsIHNjb3BlLm9iamVjdC5tYXRyaXggKTtcblx0XHRcdFx0XHRwYW5VcCggZGVsdGFZICogKCBzY29wZS5vYmplY3QudG9wIC0gc2NvcGUub2JqZWN0LmJvdHRvbSApIC8gc2NvcGUub2JqZWN0Lnpvb20gLyBlbGVtZW50LmNsaWVudEhlaWdodCwgc2NvcGUub2JqZWN0Lm1hdHJpeCApO1xuXG5cdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHQvLyBjYW1lcmEgbmVpdGhlciBvcnRob2dyYXBoaWMgbm9yIHBlcnNwZWN0aXZlXG5cdFx0XHRcdFx0Y29uc29sZS53YXJuKCAnV0FSTklORzogT3JiaXRDb250cm9scy5qcyBlbmNvdW50ZXJlZCBhbiB1bmtub3duIGNhbWVyYSB0eXBlIC0gcGFuIGRpc2FibGVkLicgKTtcblx0XHRcdFx0XHRzY29wZS5lbmFibGVQYW4gPSBmYWxzZTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdH07XG5cblx0XHR9KCk7XG5cblx0XHRmdW5jdGlvbiBkb2xseU91dCggZG9sbHlTY2FsZSApIHtcblxuXHRcdFx0aWYgKCBzY29wZS5vYmplY3QuaXNQZXJzcGVjdGl2ZUNhbWVyYSB8fCBzY29wZS5vYmplY3QuaXNPcnRob2dyYXBoaWNDYW1lcmEgKSB7XG5cblx0XHRcdFx0c2NhbGUgLz0gZG9sbHlTY2FsZTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zb2xlLndhcm4oICdXQVJOSU5HOiBPcmJpdENvbnRyb2xzLmpzIGVuY291bnRlcmVkIGFuIHVua25vd24gY2FtZXJhIHR5cGUgLSBkb2xseS96b29tIGRpc2FibGVkLicgKTtcblx0XHRcdFx0c2NvcGUuZW5hYmxlWm9vbSA9IGZhbHNlO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBkb2xseUluKCBkb2xseVNjYWxlICkge1xuXG5cdFx0XHRpZiAoIHNjb3BlLm9iamVjdC5pc1BlcnNwZWN0aXZlQ2FtZXJhIHx8IHNjb3BlLm9iamVjdC5pc09ydGhvZ3JhcGhpY0NhbWVyYSApIHtcblxuXHRcdFx0XHRzY2FsZSAqPSBkb2xseVNjYWxlO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNvbnNvbGUud2FybiggJ1dBUk5JTkc6IE9yYml0Q29udHJvbHMuanMgZW5jb3VudGVyZWQgYW4gdW5rbm93biBjYW1lcmEgdHlwZSAtIGRvbGx5L3pvb20gZGlzYWJsZWQuJyApO1xuXHRcdFx0XHRzY29wZS5lbmFibGVab29tID0gZmFsc2U7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIHVwZGF0ZVpvb21QYXJhbWV0ZXJzKCB4LCB5ICkge1xuXG5cdFx0XHRpZiAoICEgc2NvcGUuem9vbVRvQ3Vyc29yICkge1xuXG5cdFx0XHRcdHJldHVybjtcblxuXHRcdFx0fVxuXG5cdFx0XHRwZXJmb3JtQ3Vyc29yWm9vbSA9IHRydWU7XG5cblx0XHRcdGNvbnN0IHJlY3QgPSBzY29wZS5kb21FbGVtZW50LmdldEJvdW5kaW5nQ2xpZW50UmVjdCgpO1xuXHRcdFx0Y29uc3QgZHggPSB4IC0gcmVjdC5sZWZ0O1xuXHRcdFx0Y29uc3QgZHkgPSB5IC0gcmVjdC50b3A7XG5cdFx0XHRjb25zdCB3ID0gcmVjdC53aWR0aDtcblx0XHRcdGNvbnN0IGggPSByZWN0LmhlaWdodDtcblxuXHRcdFx0bW91c2UueCA9ICggZHggLyB3ICkgKiAyIC0gMTtcblx0XHRcdG1vdXNlLnkgPSAtICggZHkgLyBoICkgKiAyICsgMTtcblxuXHRcdFx0ZG9sbHlEaXJlY3Rpb24uc2V0KCBtb3VzZS54LCBtb3VzZS55LCAxICkudW5wcm9qZWN0KCBzY29wZS5vYmplY3QgKS5zdWIoIHNjb3BlLm9iamVjdC5wb3NpdGlvbiApLm5vcm1hbGl6ZSgpO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gY2xhbXBEaXN0YW5jZSggZGlzdCApIHtcblxuXHRcdFx0cmV0dXJuIE1hdGgubWF4KCBzY29wZS5taW5EaXN0YW5jZSwgTWF0aC5taW4oIHNjb3BlLm1heERpc3RhbmNlLCBkaXN0ICkgKTtcblxuXHRcdH1cblxuXHRcdC8vXG5cdFx0Ly8gZXZlbnQgY2FsbGJhY2tzIC0gdXBkYXRlIHRoZSBvYmplY3Qgc3RhdGVcblx0XHQvL1xuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlTW91c2VEb3duUm90YXRlKCBldmVudCApIHtcblxuXHRcdFx0cm90YXRlU3RhcnQuc2V0KCBldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVNb3VzZURvd25Eb2xseSggZXZlbnQgKSB7XG5cblx0XHRcdHVwZGF0ZVpvb21QYXJhbWV0ZXJzKCBldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRYICk7XG5cdFx0XHRkb2xseVN0YXJ0LnNldCggZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlTW91c2VEb3duUGFuKCBldmVudCApIHtcblxuXHRcdFx0cGFuU3RhcnQuc2V0KCBldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVNb3VzZU1vdmVSb3RhdGUoIGV2ZW50ICkge1xuXG5cdFx0XHRyb3RhdGVFbmQuc2V0KCBldmVudC5jbGllbnRYLCBldmVudC5jbGllbnRZICk7XG5cblx0XHRcdHJvdGF0ZURlbHRhLnN1YlZlY3RvcnMoIHJvdGF0ZUVuZCwgcm90YXRlU3RhcnQgKS5tdWx0aXBseVNjYWxhciggc2NvcGUucm90YXRlU3BlZWQgKTtcblxuXHRcdFx0Y29uc3QgZWxlbWVudCA9IHNjb3BlLmRvbUVsZW1lbnQ7XG5cblx0XHRcdHJvdGF0ZUxlZnQoIDIgKiBNYXRoLlBJICogcm90YXRlRGVsdGEueCAvIGVsZW1lbnQuY2xpZW50SGVpZ2h0ICk7IC8vIHllcywgaGVpZ2h0XG5cblx0XHRcdHJvdGF0ZVVwKCAyICogTWF0aC5QSSAqIHJvdGF0ZURlbHRhLnkgLyBlbGVtZW50LmNsaWVudEhlaWdodCApO1xuXG5cdFx0XHRyb3RhdGVTdGFydC5jb3B5KCByb3RhdGVFbmQgKTtcblxuXHRcdFx0c2NvcGUudXBkYXRlKCk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVNb3VzZU1vdmVEb2xseSggZXZlbnQgKSB7XG5cblx0XHRcdGRvbGx5RW5kLnNldCggZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSApO1xuXG5cdFx0XHRkb2xseURlbHRhLnN1YlZlY3RvcnMoIGRvbGx5RW5kLCBkb2xseVN0YXJ0ICk7XG5cblx0XHRcdGlmICggZG9sbHlEZWx0YS55ID4gMCApIHtcblxuXHRcdFx0XHRkb2xseU91dCggZ2V0Wm9vbVNjYWxlKCBkb2xseURlbHRhLnkgKSApO1xuXG5cdFx0XHR9IGVsc2UgaWYgKCBkb2xseURlbHRhLnkgPCAwICkge1xuXG5cdFx0XHRcdGRvbGx5SW4oIGdldFpvb21TY2FsZSggZG9sbHlEZWx0YS55ICkgKTtcblxuXHRcdFx0fVxuXG5cdFx0XHRkb2xseVN0YXJ0LmNvcHkoIGRvbGx5RW5kICk7XG5cblx0XHRcdHNjb3BlLnVwZGF0ZSgpO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlTW91c2VNb3ZlUGFuKCBldmVudCApIHtcblxuXHRcdFx0cGFuRW5kLnNldCggZXZlbnQuY2xpZW50WCwgZXZlbnQuY2xpZW50WSApO1xuXG5cdFx0XHRwYW5EZWx0YS5zdWJWZWN0b3JzKCBwYW5FbmQsIHBhblN0YXJ0ICkubXVsdGlwbHlTY2FsYXIoIHNjb3BlLnBhblNwZWVkICk7XG5cblx0XHRcdHBhbiggcGFuRGVsdGEueCwgcGFuRGVsdGEueSApO1xuXG5cdFx0XHRwYW5TdGFydC5jb3B5KCBwYW5FbmQgKTtcblxuXHRcdFx0c2NvcGUudXBkYXRlKCk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVNb3VzZVdoZWVsKCBldmVudCApIHtcblxuXHRcdFx0dXBkYXRlWm9vbVBhcmFtZXRlcnMoIGV2ZW50LmNsaWVudFgsIGV2ZW50LmNsaWVudFkgKTtcblxuXHRcdFx0aWYgKCBldmVudC5kZWx0YVkgPCAwICkge1xuXG5cdFx0XHRcdGRvbGx5SW4oIGdldFpvb21TY2FsZSggZXZlbnQuZGVsdGFZICkgKTtcblxuXHRcdFx0fSBlbHNlIGlmICggZXZlbnQuZGVsdGFZID4gMCApIHtcblxuXHRcdFx0XHRkb2xseU91dCggZ2V0Wm9vbVNjYWxlKCBldmVudC5kZWx0YVkgKSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHNjb3BlLnVwZGF0ZSgpO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlS2V5RG93biggZXZlbnQgKSB7XG5cblx0XHRcdGxldCBuZWVkc1VwZGF0ZSA9IGZhbHNlO1xuXG5cdFx0XHRzd2l0Y2ggKCBldmVudC5jb2RlICkge1xuXG5cdFx0XHRcdGNhc2Ugc2NvcGUua2V5cy5VUDpcblxuXHRcdFx0XHRcdGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5IHx8IGV2ZW50LnNoaWZ0S2V5ICkge1xuXG5cdFx0XHRcdFx0XHRyb3RhdGVVcCggMiAqIE1hdGguUEkgKiBzY29wZS5yb3RhdGVTcGVlZCAvIHNjb3BlLmRvbUVsZW1lbnQuY2xpZW50SGVpZ2h0ICk7XG5cblx0XHRcdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdFx0XHRwYW4oIDAsIHNjb3BlLmtleVBhblNwZWVkICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRuZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBzY29wZS5rZXlzLkJPVFRPTTpcblxuXHRcdFx0XHRcdGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5IHx8IGV2ZW50LnNoaWZ0S2V5ICkge1xuXG5cdFx0XHRcdFx0XHRyb3RhdGVVcCggLSAyICogTWF0aC5QSSAqIHNjb3BlLnJvdGF0ZVNwZWVkIC8gc2NvcGUuZG9tRWxlbWVudC5jbGllbnRIZWlnaHQgKTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdHBhbiggMCwgLSBzY29wZS5rZXlQYW5TcGVlZCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0bmVlZHNVcGRhdGUgPSB0cnVlO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2Ugc2NvcGUua2V5cy5MRUZUOlxuXG5cdFx0XHRcdFx0aWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuc2hpZnRLZXkgKSB7XG5cblx0XHRcdFx0XHRcdHJvdGF0ZUxlZnQoIDIgKiBNYXRoLlBJICogc2NvcGUucm90YXRlU3BlZWQgLyBzY29wZS5kb21FbGVtZW50LmNsaWVudEhlaWdodCApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0cGFuKCBzY29wZS5rZXlQYW5TcGVlZCwgMCApO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0bmVlZHNVcGRhdGUgPSB0cnVlO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2Ugc2NvcGUua2V5cy5SSUdIVDpcblxuXHRcdFx0XHRcdGlmICggZXZlbnQuY3RybEtleSB8fCBldmVudC5tZXRhS2V5IHx8IGV2ZW50LnNoaWZ0S2V5ICkge1xuXG5cdFx0XHRcdFx0XHRyb3RhdGVMZWZ0KCAtIDIgKiBNYXRoLlBJICogc2NvcGUucm90YXRlU3BlZWQgLyBzY29wZS5kb21FbGVtZW50LmNsaWVudEhlaWdodCApO1xuXG5cdFx0XHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRcdFx0cGFuKCAtIHNjb3BlLmtleVBhblNwZWVkLCAwICk7XG5cblx0XHRcdFx0XHR9XG5cblx0XHRcdFx0XHRuZWVkc1VwZGF0ZSA9IHRydWU7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBuZWVkc1VwZGF0ZSApIHtcblxuXHRcdFx0XHQvLyBwcmV2ZW50IHRoZSBicm93c2VyIGZyb20gc2Nyb2xsaW5nIG9uIGN1cnNvciBrZXlzXG5cdFx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRcdFx0c2NvcGUudXBkYXRlKCk7XG5cblx0XHRcdH1cblxuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlVG91Y2hTdGFydFJvdGF0ZSggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggcG9pbnRlcnMubGVuZ3RoID09PSAxICkge1xuXG5cdFx0XHRcdHJvdGF0ZVN0YXJ0LnNldCggZXZlbnQucGFnZVgsIGV2ZW50LnBhZ2VZICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0Y29uc3QgcG9zaXRpb24gPSBnZXRTZWNvbmRQb2ludGVyUG9zaXRpb24oIGV2ZW50ICk7XG5cblx0XHRcdFx0Y29uc3QgeCA9IDAuNSAqICggZXZlbnQucGFnZVggKyBwb3NpdGlvbi54ICk7XG5cdFx0XHRcdGNvbnN0IHkgPSAwLjUgKiAoIGV2ZW50LnBhZ2VZICsgcG9zaXRpb24ueSApO1xuXG5cdFx0XHRcdHJvdGF0ZVN0YXJ0LnNldCggeCwgeSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVUb3VjaFN0YXJ0UGFuKCBldmVudCApIHtcblxuXHRcdFx0aWYgKCBwb2ludGVycy5sZW5ndGggPT09IDEgKSB7XG5cblx0XHRcdFx0cGFuU3RhcnQuc2V0KCBldmVudC5wYWdlWCwgZXZlbnQucGFnZVkgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zdCBwb3NpdGlvbiA9IGdldFNlY29uZFBvaW50ZXJQb3NpdGlvbiggZXZlbnQgKTtcblxuXHRcdFx0XHRjb25zdCB4ID0gMC41ICogKCBldmVudC5wYWdlWCArIHBvc2l0aW9uLnggKTtcblx0XHRcdFx0Y29uc3QgeSA9IDAuNSAqICggZXZlbnQucGFnZVkgKyBwb3NpdGlvbi55ICk7XG5cblx0XHRcdFx0cGFuU3RhcnQuc2V0KCB4LCB5ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGhhbmRsZVRvdWNoU3RhcnREb2xseSggZXZlbnQgKSB7XG5cblx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2V0U2Vjb25kUG9pbnRlclBvc2l0aW9uKCBldmVudCApO1xuXG5cdFx0XHRjb25zdCBkeCA9IGV2ZW50LnBhZ2VYIC0gcG9zaXRpb24ueDtcblx0XHRcdGNvbnN0IGR5ID0gZXZlbnQucGFnZVkgLSBwb3NpdGlvbi55O1xuXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IE1hdGguc3FydCggZHggKiBkeCArIGR5ICogZHkgKTtcblxuXHRcdFx0ZG9sbHlTdGFydC5zZXQoIDAsIGRpc3RhbmNlICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVUb3VjaFN0YXJ0RG9sbHlQYW4oIGV2ZW50ICkge1xuXG5cdFx0XHRpZiAoIHNjb3BlLmVuYWJsZVpvb20gKSBoYW5kbGVUb3VjaFN0YXJ0RG9sbHkoIGV2ZW50ICk7XG5cblx0XHRcdGlmICggc2NvcGUuZW5hYmxlUGFuICkgaGFuZGxlVG91Y2hTdGFydFBhbiggZXZlbnQgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGhhbmRsZVRvdWNoU3RhcnREb2xseVJvdGF0ZSggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggc2NvcGUuZW5hYmxlWm9vbSApIGhhbmRsZVRvdWNoU3RhcnREb2xseSggZXZlbnQgKTtcblxuXHRcdFx0aWYgKCBzY29wZS5lbmFibGVSb3RhdGUgKSBoYW5kbGVUb3VjaFN0YXJ0Um90YXRlKCBldmVudCApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlVG91Y2hNb3ZlUm90YXRlKCBldmVudCApIHtcblxuXHRcdFx0aWYgKCBwb2ludGVycy5sZW5ndGggPT0gMSApIHtcblxuXHRcdFx0XHRyb3RhdGVFbmQuc2V0KCBldmVudC5wYWdlWCwgZXZlbnQucGFnZVkgKTtcblxuXHRcdFx0fSBlbHNlIHtcblxuXHRcdFx0XHRjb25zdCBwb3NpdGlvbiA9IGdldFNlY29uZFBvaW50ZXJQb3NpdGlvbiggZXZlbnQgKTtcblxuXHRcdFx0XHRjb25zdCB4ID0gMC41ICogKCBldmVudC5wYWdlWCArIHBvc2l0aW9uLnggKTtcblx0XHRcdFx0Y29uc3QgeSA9IDAuNSAqICggZXZlbnQucGFnZVkgKyBwb3NpdGlvbi55ICk7XG5cblx0XHRcdFx0cm90YXRlRW5kLnNldCggeCwgeSApO1xuXG5cdFx0XHR9XG5cblx0XHRcdHJvdGF0ZURlbHRhLnN1YlZlY3RvcnMoIHJvdGF0ZUVuZCwgcm90YXRlU3RhcnQgKS5tdWx0aXBseVNjYWxhciggc2NvcGUucm90YXRlU3BlZWQgKTtcblxuXHRcdFx0Y29uc3QgZWxlbWVudCA9IHNjb3BlLmRvbUVsZW1lbnQ7XG5cblx0XHRcdHJvdGF0ZUxlZnQoIDIgKiBNYXRoLlBJICogcm90YXRlRGVsdGEueCAvIGVsZW1lbnQuY2xpZW50SGVpZ2h0ICk7IC8vIHllcywgaGVpZ2h0XG5cblx0XHRcdHJvdGF0ZVVwKCAyICogTWF0aC5QSSAqIHJvdGF0ZURlbHRhLnkgLyBlbGVtZW50LmNsaWVudEhlaWdodCApO1xuXG5cdFx0XHRyb3RhdGVTdGFydC5jb3B5KCByb3RhdGVFbmQgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGhhbmRsZVRvdWNoTW92ZVBhbiggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggcG9pbnRlcnMubGVuZ3RoID09PSAxICkge1xuXG5cdFx0XHRcdHBhbkVuZC5zZXQoIGV2ZW50LnBhZ2VYLCBldmVudC5wYWdlWSApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2V0U2Vjb25kUG9pbnRlclBvc2l0aW9uKCBldmVudCApO1xuXG5cdFx0XHRcdGNvbnN0IHggPSAwLjUgKiAoIGV2ZW50LnBhZ2VYICsgcG9zaXRpb24ueCApO1xuXHRcdFx0XHRjb25zdCB5ID0gMC41ICogKCBldmVudC5wYWdlWSArIHBvc2l0aW9uLnkgKTtcblxuXHRcdFx0XHRwYW5FbmQuc2V0KCB4LCB5ICk7XG5cblx0XHRcdH1cblxuXHRcdFx0cGFuRGVsdGEuc3ViVmVjdG9ycyggcGFuRW5kLCBwYW5TdGFydCApLm11bHRpcGx5U2NhbGFyKCBzY29wZS5wYW5TcGVlZCApO1xuXG5cdFx0XHRwYW4oIHBhbkRlbHRhLngsIHBhbkRlbHRhLnkgKTtcblxuXHRcdFx0cGFuU3RhcnQuY29weSggcGFuRW5kICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVUb3VjaE1vdmVEb2xseSggZXZlbnQgKSB7XG5cblx0XHRcdGNvbnN0IHBvc2l0aW9uID0gZ2V0U2Vjb25kUG9pbnRlclBvc2l0aW9uKCBldmVudCApO1xuXG5cdFx0XHRjb25zdCBkeCA9IGV2ZW50LnBhZ2VYIC0gcG9zaXRpb24ueDtcblx0XHRcdGNvbnN0IGR5ID0gZXZlbnQucGFnZVkgLSBwb3NpdGlvbi55O1xuXG5cdFx0XHRjb25zdCBkaXN0YW5jZSA9IE1hdGguc3FydCggZHggKiBkeCArIGR5ICogZHkgKTtcblxuXHRcdFx0ZG9sbHlFbmQuc2V0KCAwLCBkaXN0YW5jZSApO1xuXG5cdFx0XHRkb2xseURlbHRhLnNldCggMCwgTWF0aC5wb3coIGRvbGx5RW5kLnkgLyBkb2xseVN0YXJ0LnksIHNjb3BlLnpvb21TcGVlZCApICk7XG5cblx0XHRcdGRvbGx5T3V0KCBkb2xseURlbHRhLnkgKTtcblxuXHRcdFx0ZG9sbHlTdGFydC5jb3B5KCBkb2xseUVuZCApO1xuXG5cdFx0XHRjb25zdCBjZW50ZXJYID0gKCBldmVudC5wYWdlWCArIHBvc2l0aW9uLnggKSAqIDAuNTtcblx0XHRcdGNvbnN0IGNlbnRlclkgPSAoIGV2ZW50LnBhZ2VZICsgcG9zaXRpb24ueSApICogMC41O1xuXG5cdFx0XHR1cGRhdGVab29tUGFyYW1ldGVycyggY2VudGVyWCwgY2VudGVyWSApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gaGFuZGxlVG91Y2hNb3ZlRG9sbHlQYW4oIGV2ZW50ICkge1xuXG5cdFx0XHRpZiAoIHNjb3BlLmVuYWJsZVpvb20gKSBoYW5kbGVUb3VjaE1vdmVEb2xseSggZXZlbnQgKTtcblxuXHRcdFx0aWYgKCBzY29wZS5lbmFibGVQYW4gKSBoYW5kbGVUb3VjaE1vdmVQYW4oIGV2ZW50ICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBoYW5kbGVUb3VjaE1vdmVEb2xseVJvdGF0ZSggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggc2NvcGUuZW5hYmxlWm9vbSApIGhhbmRsZVRvdWNoTW92ZURvbGx5KCBldmVudCApO1xuXG5cdFx0XHRpZiAoIHNjb3BlLmVuYWJsZVJvdGF0ZSApIGhhbmRsZVRvdWNoTW92ZVJvdGF0ZSggZXZlbnQgKTtcblxuXHRcdH1cblxuXHRcdC8vXG5cdFx0Ly8gZXZlbnQgaGFuZGxlcnMgLSBGU006IGxpc3RlbiBmb3IgZXZlbnRzIGFuZCByZXNldCBzdGF0ZVxuXHRcdC8vXG5cblx0XHRmdW5jdGlvbiBvblBvaW50ZXJEb3duKCBldmVudCApIHtcblxuXHRcdFx0aWYgKCBzY29wZS5lbmFibGVkID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0aWYgKCBwb2ludGVycy5sZW5ndGggPT09IDAgKSB7XG5cblx0XHRcdFx0c2NvcGUuZG9tRWxlbWVudC5zZXRQb2ludGVyQ2FwdHVyZSggZXZlbnQucG9pbnRlcklkICk7XG5cblx0XHRcdFx0c2NvcGUuZG9tRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCAncG9pbnRlcm1vdmUnLCBvblBvaW50ZXJNb3ZlICk7XG5cdFx0XHRcdHNjb3BlLmRvbUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ3BvaW50ZXJ1cCcsIG9uUG9pbnRlclVwICk7XG5cblx0XHRcdH1cblxuXHRcdFx0Ly9cblxuXHRcdFx0aWYgKCBpc1RyYWNraW5nUG9pbnRlciggZXZlbnQgKSApIHJldHVybjtcblxuXHRcdFx0Ly9cblxuXHRcdFx0YWRkUG9pbnRlciggZXZlbnQgKTtcblxuXHRcdFx0aWYgKCBldmVudC5wb2ludGVyVHlwZSA9PT0gJ3RvdWNoJyApIHtcblxuXHRcdFx0XHRvblRvdWNoU3RhcnQoIGV2ZW50ICk7XG5cblx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0b25Nb3VzZURvd24oIGV2ZW50ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uUG9pbnRlck1vdmUoIGV2ZW50ICkge1xuXG5cdFx0XHRpZiAoIHNjb3BlLmVuYWJsZWQgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRpZiAoIGV2ZW50LnBvaW50ZXJUeXBlID09PSAndG91Y2gnICkge1xuXG5cdFx0XHRcdG9uVG91Y2hNb3ZlKCBldmVudCApO1xuXG5cdFx0XHR9IGVsc2Uge1xuXG5cdFx0XHRcdG9uTW91c2VNb3ZlKCBldmVudCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBvblBvaW50ZXJVcCggZXZlbnQgKSB7XG5cblx0XHRcdHJlbW92ZVBvaW50ZXIoIGV2ZW50ICk7XG5cblx0XHRcdHN3aXRjaCAoIHBvaW50ZXJzLmxlbmd0aCApIHtcblxuXHRcdFx0XHRjYXNlIDA6XG5cblx0XHRcdFx0XHRzY29wZS5kb21FbGVtZW50LnJlbGVhc2VQb2ludGVyQ2FwdHVyZSggZXZlbnQucG9pbnRlcklkICk7XG5cblx0XHRcdFx0XHRzY29wZS5kb21FbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoICdwb2ludGVybW92ZScsIG9uUG9pbnRlck1vdmUgKTtcblx0XHRcdFx0XHRzY29wZS5kb21FbGVtZW50LnJlbW92ZUV2ZW50TGlzdGVuZXIoICdwb2ludGVydXAnLCBvblBvaW50ZXJVcCApO1xuXG5cdFx0XHRcdFx0c2NvcGUuZGlzcGF0Y2hFdmVudCggX2VuZEV2ZW50ICk7XG5cblx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLk5PTkU7XG5cblx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRjYXNlIDE6XG5cblx0XHRcdFx0XHRjb25zdCBwb2ludGVySWQgPSBwb2ludGVyc1sgMCBdO1xuXHRcdFx0XHRcdGNvbnN0IHBvc2l0aW9uID0gcG9pbnRlclBvc2l0aW9uc1sgcG9pbnRlcklkIF07XG5cblx0XHRcdFx0XHQvLyBtaW5pbWFsIHBsYWNlaG9sZGVyIGV2ZW50IC0gYWxsb3dzIHN0YXRlIGNvcnJlY3Rpb24gb24gcG9pbnRlci11cFxuXHRcdFx0XHRcdG9uVG91Y2hTdGFydCggeyBwb2ludGVySWQ6IHBvaW50ZXJJZCwgcGFnZVg6IHBvc2l0aW9uLngsIHBhZ2VZOiBwb3NpdGlvbi55IH0gKTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBvbk1vdXNlRG93biggZXZlbnQgKSB7XG5cblx0XHRcdGxldCBtb3VzZUFjdGlvbjtcblxuXHRcdFx0c3dpdGNoICggZXZlbnQuYnV0dG9uICkge1xuXG5cdFx0XHRcdGNhc2UgMDpcblxuXHRcdFx0XHRcdG1vdXNlQWN0aW9uID0gc2NvcGUubW91c2VCdXR0b25zLkxFRlQ7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAxOlxuXG5cdFx0XHRcdFx0bW91c2VBY3Rpb24gPSBzY29wZS5tb3VzZUJ1dHRvbnMuTUlERExFO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgMjpcblxuXHRcdFx0XHRcdG1vdXNlQWN0aW9uID0gc2NvcGUubW91c2VCdXR0b25zLlJJR0hUO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRtb3VzZUFjdGlvbiA9IC0gMTtcblxuXHRcdFx0fVxuXG5cdFx0XHRzd2l0Y2ggKCBtb3VzZUFjdGlvbiApIHtcblxuXHRcdFx0XHRjYXNlIE1PVVNFLkRPTExZOlxuXG5cdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVab29tID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdGhhbmRsZU1vdXNlRG93bkRvbGx5KCBldmVudCApO1xuXG5cdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5ET0xMWTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgTU9VU0UuUk9UQVRFOlxuXG5cdFx0XHRcdFx0aWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuc2hpZnRLZXkgKSB7XG5cblx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlUGFuID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0aGFuZGxlTW91c2VEb3duUGFuKCBldmVudCApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLlBBTjtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlUm90YXRlID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0aGFuZGxlTW91c2VEb3duUm90YXRlKCBldmVudCApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLlJPVEFURTtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgTU9VU0UuUEFOOlxuXG5cdFx0XHRcdFx0aWYgKCBldmVudC5jdHJsS2V5IHx8IGV2ZW50Lm1ldGFLZXkgfHwgZXZlbnQuc2hpZnRLZXkgKSB7XG5cblx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlUm90YXRlID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0aGFuZGxlTW91c2VEb3duUm90YXRlKCBldmVudCApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLlJPVEFURTtcblxuXHRcdFx0XHRcdH0gZWxzZSB7XG5cblx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlUGFuID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0aGFuZGxlTW91c2VEb3duUGFuKCBldmVudCApO1xuXG5cdFx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLlBBTjtcblxuXHRcdFx0XHRcdH1cblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLk5PTkU7XG5cblx0XHRcdH1cblxuXHRcdFx0aWYgKCBzdGF0ZSAhPT0gU1RBVEUuTk9ORSApIHtcblxuXHRcdFx0XHRzY29wZS5kaXNwYXRjaEV2ZW50KCBfc3RhcnRFdmVudCApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBvbk1vdXNlTW92ZSggZXZlbnQgKSB7XG5cblx0XHRcdHN3aXRjaCAoIHN0YXRlICkge1xuXG5cdFx0XHRcdGNhc2UgU1RBVEUuUk9UQVRFOlxuXG5cdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVSb3RhdGUgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRcdFx0aGFuZGxlTW91c2VNb3ZlUm90YXRlKCBldmVudCApO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBTVEFURS5ET0xMWTpcblxuXHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlWm9vbSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHRcdFx0XHRoYW5kbGVNb3VzZU1vdmVEb2xseSggZXZlbnQgKTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgU1RBVEUuUEFOOlxuXG5cdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVQYW4gPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRcdFx0aGFuZGxlTW91c2VNb3ZlUGFuKCBldmVudCApO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uTW91c2VXaGVlbCggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggc2NvcGUuZW5hYmxlZCA9PT0gZmFsc2UgfHwgc2NvcGUuZW5hYmxlWm9vbSA9PT0gZmFsc2UgfHwgc3RhdGUgIT09IFNUQVRFLk5PTkUgKSByZXR1cm47XG5cblx0XHRcdGV2ZW50LnByZXZlbnREZWZhdWx0KCk7XG5cblx0XHRcdHNjb3BlLmRpc3BhdGNoRXZlbnQoIF9zdGFydEV2ZW50ICk7XG5cblx0XHRcdGhhbmRsZU1vdXNlV2hlZWwoIGN1c3RvbVdoZWVsRXZlbnQoIGV2ZW50ICkgKTtcblxuXHRcdFx0c2NvcGUuZGlzcGF0Y2hFdmVudCggX2VuZEV2ZW50ICk7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBjdXN0b21XaGVlbEV2ZW50KCBldmVudCApIHtcblxuXHRcdFx0Y29uc3QgbW9kZSA9IGV2ZW50LmRlbHRhTW9kZTtcblxuXHRcdFx0Ly8gbWluaW1hbCB3aGVlbCBldmVudCBhbHRlcmVkIHRvIG1lZXQgZGVsdGEtem9vbSBkZW1hbmRcblx0XHRcdGNvbnN0IG5ld0V2ZW50ID0ge1xuXHRcdFx0XHRjbGllbnRYOiBldmVudC5jbGllbnRYLFxuXHRcdFx0XHRjbGllbnRZOiBldmVudC5jbGllbnRZLFxuXHRcdFx0XHRkZWx0YVk6IGV2ZW50LmRlbHRhWSxcblx0XHRcdH07XG5cblx0XHRcdHN3aXRjaCAoIG1vZGUgKSB7XG5cblx0XHRcdFx0Y2FzZSAxOiAvLyBMSU5FX01PREVcblx0XHRcdFx0XHRuZXdFdmVudC5kZWx0YVkgKj0gMTY7XG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAyOiAvLyBQQUdFX01PREVcblx0XHRcdFx0XHRuZXdFdmVudC5kZWx0YVkgKj0gMTAwO1xuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHR9XG5cblx0XHRcdC8vIGRldGVjdCBpZiBldmVudCB3YXMgdHJpZ2dlcmVkIGJ5IHBpbmNoaW5nXG5cdFx0XHRpZiAoIGV2ZW50LmN0cmxLZXkgJiYgISBjb250cm9sQWN0aXZlICkge1xuXG5cdFx0XHRcdG5ld0V2ZW50LmRlbHRhWSAqPSAxMDtcblxuXHRcdFx0fVxuXG5cdFx0XHRyZXR1cm4gbmV3RXZlbnQ7XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBpbnRlcmNlcHRDb250cm9sRG93biggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggZXZlbnQua2V5ID09PSAnQ29udHJvbCcgKSB7XG5cblx0XHRcdFx0Y29udHJvbEFjdGl2ZSA9IHRydWU7XG5cblxuXHRcdFx0XHRjb25zdCBkb2N1bWVudCA9IHNjb3BlLmRvbUVsZW1lbnQuZ2V0Um9vdE5vZGUoKTsgLy8gb2Zmc2NyZWVuIGNhbnZhcyBjb21wYXRpYmlsaXR5XG5cblx0XHRcdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ2tleXVwJywgaW50ZXJjZXB0Q29udHJvbFVwLCB7IHBhc3NpdmU6IHRydWUsIGNhcHR1cmU6IHRydWUgfSApO1xuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBpbnRlcmNlcHRDb250cm9sVXAoIGV2ZW50ICkge1xuXG5cdFx0XHRpZiAoIGV2ZW50LmtleSA9PT0gJ0NvbnRyb2wnICkge1xuXG5cdFx0XHRcdGNvbnRyb2xBY3RpdmUgPSBmYWxzZTtcblxuXG5cdFx0XHRcdGNvbnN0IGRvY3VtZW50ID0gc2NvcGUuZG9tRWxlbWVudC5nZXRSb290Tm9kZSgpOyAvLyBvZmZzY3JlZW4gY2FudmFzIGNvbXBhdGliaWxpdHlcblxuXHRcdFx0XHRkb2N1bWVudC5yZW1vdmVFdmVudExpc3RlbmVyKCAna2V5dXAnLCBpbnRlcmNlcHRDb250cm9sVXAsIHsgcGFzc2l2ZTogdHJ1ZSwgY2FwdHVyZTogdHJ1ZSB9ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uS2V5RG93biggZXZlbnQgKSB7XG5cblx0XHRcdGlmICggc2NvcGUuZW5hYmxlZCA9PT0gZmFsc2UgfHwgc2NvcGUuZW5hYmxlUGFuID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0aGFuZGxlS2V5RG93biggZXZlbnQgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uVG91Y2hTdGFydCggZXZlbnQgKSB7XG5cblx0XHRcdHRyYWNrUG9pbnRlciggZXZlbnQgKTtcblxuXHRcdFx0c3dpdGNoICggcG9pbnRlcnMubGVuZ3RoICkge1xuXG5cdFx0XHRcdGNhc2UgMTpcblxuXHRcdFx0XHRcdHN3aXRjaCAoIHNjb3BlLnRvdWNoZXMuT05FICkge1xuXG5cdFx0XHRcdFx0XHRjYXNlIFRPVUNILlJPVEFURTpcblxuXHRcdFx0XHRcdFx0XHRpZiAoIHNjb3BlLmVuYWJsZVJvdGF0ZSA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHRcdFx0XHRcdFx0aGFuZGxlVG91Y2hTdGFydFJvdGF0ZSggZXZlbnQgKTtcblxuXHRcdFx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLlRPVUNIX1JPVEFURTtcblxuXHRcdFx0XHRcdFx0XHRicmVhaztcblxuXHRcdFx0XHRcdFx0Y2FzZSBUT1VDSC5QQU46XG5cblx0XHRcdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVQYW4gPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRcdFx0XHRcdGhhbmRsZVRvdWNoU3RhcnRQYW4oIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5UT1VDSF9QQU47XG5cblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5OT05FO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSAyOlxuXG5cdFx0XHRcdFx0c3dpdGNoICggc2NvcGUudG91Y2hlcy5UV08gKSB7XG5cblx0XHRcdFx0XHRcdGNhc2UgVE9VQ0guRE9MTFlfUEFOOlxuXG5cdFx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlWm9vbSA9PT0gZmFsc2UgJiYgc2NvcGUuZW5hYmxlUGFuID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0XHRoYW5kbGVUb3VjaFN0YXJ0RG9sbHlQYW4oIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5UT1VDSF9ET0xMWV9QQU47XG5cblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdGNhc2UgVE9VQ0guRE9MTFlfUk9UQVRFOlxuXG5cdFx0XHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlWm9vbSA9PT0gZmFsc2UgJiYgc2NvcGUuZW5hYmxlUm90YXRlID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdFx0XHRoYW5kbGVUb3VjaFN0YXJ0RG9sbHlSb3RhdGUoIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5UT1VDSF9ET0xMWV9ST1RBVEU7XG5cblx0XHRcdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRcdFx0c3RhdGUgPSBTVEFURS5OT05FO1xuXG5cdFx0XHRcdFx0fVxuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0ZGVmYXVsdDpcblxuXHRcdFx0XHRcdHN0YXRlID0gU1RBVEUuTk9ORTtcblxuXHRcdFx0fVxuXG5cdFx0XHRpZiAoIHN0YXRlICE9PSBTVEFURS5OT05FICkge1xuXG5cdFx0XHRcdHNjb3BlLmRpc3BhdGNoRXZlbnQoIF9zdGFydEV2ZW50ICk7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uVG91Y2hNb3ZlKCBldmVudCApIHtcblxuXHRcdFx0dHJhY2tQb2ludGVyKCBldmVudCApO1xuXG5cdFx0XHRzd2l0Y2ggKCBzdGF0ZSApIHtcblxuXHRcdFx0XHRjYXNlIFNUQVRFLlRPVUNIX1JPVEFURTpcblxuXHRcdFx0XHRcdGlmICggc2NvcGUuZW5hYmxlUm90YXRlID09PSBmYWxzZSApIHJldHVybjtcblxuXHRcdFx0XHRcdGhhbmRsZVRvdWNoTW92ZVJvdGF0ZSggZXZlbnQgKTtcblxuXHRcdFx0XHRcdHNjb3BlLnVwZGF0ZSgpO1xuXG5cdFx0XHRcdFx0YnJlYWs7XG5cblx0XHRcdFx0Y2FzZSBTVEFURS5UT1VDSF9QQU46XG5cblx0XHRcdFx0XHRpZiAoIHNjb3BlLmVuYWJsZVBhbiA9PT0gZmFsc2UgKSByZXR1cm47XG5cblx0XHRcdFx0XHRoYW5kbGVUb3VjaE1vdmVQYW4oIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRzY29wZS51cGRhdGUoKTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgU1RBVEUuVE9VQ0hfRE9MTFlfUEFOOlxuXG5cdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVab29tID09PSBmYWxzZSAmJiBzY29wZS5lbmFibGVQYW4gPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRcdFx0aGFuZGxlVG91Y2hNb3ZlRG9sbHlQYW4oIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRzY29wZS51cGRhdGUoKTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGNhc2UgU1RBVEUuVE9VQ0hfRE9MTFlfUk9UQVRFOlxuXG5cdFx0XHRcdFx0aWYgKCBzY29wZS5lbmFibGVab29tID09PSBmYWxzZSAmJiBzY29wZS5lbmFibGVSb3RhdGUgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRcdFx0aGFuZGxlVG91Y2hNb3ZlRG9sbHlSb3RhdGUoIGV2ZW50ICk7XG5cblx0XHRcdFx0XHRzY29wZS51cGRhdGUoKTtcblxuXHRcdFx0XHRcdGJyZWFrO1xuXG5cdFx0XHRcdGRlZmF1bHQ6XG5cblx0XHRcdFx0XHRzdGF0ZSA9IFNUQVRFLk5PTkU7XG5cblx0XHRcdH1cblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIG9uQ29udGV4dE1lbnUoIGV2ZW50ICkge1xuXG5cdFx0XHRpZiAoIHNjb3BlLmVuYWJsZWQgPT09IGZhbHNlICkgcmV0dXJuO1xuXG5cdFx0XHRldmVudC5wcmV2ZW50RGVmYXVsdCgpO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gYWRkUG9pbnRlciggZXZlbnQgKSB7XG5cblx0XHRcdHBvaW50ZXJzLnB1c2goIGV2ZW50LnBvaW50ZXJJZCApO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gcmVtb3ZlUG9pbnRlciggZXZlbnQgKSB7XG5cblx0XHRcdGRlbGV0ZSBwb2ludGVyUG9zaXRpb25zWyBldmVudC5wb2ludGVySWQgXTtcblxuXHRcdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgcG9pbnRlcnMubGVuZ3RoOyBpICsrICkge1xuXG5cdFx0XHRcdGlmICggcG9pbnRlcnNbIGkgXSA9PSBldmVudC5wb2ludGVySWQgKSB7XG5cblx0XHRcdFx0XHRwb2ludGVycy5zcGxpY2UoIGksIDEgKTtcblx0XHRcdFx0XHRyZXR1cm47XG5cblx0XHRcdFx0fVxuXG5cdFx0XHR9XG5cblx0XHR9XG5cblx0XHRmdW5jdGlvbiBpc1RyYWNraW5nUG9pbnRlciggZXZlbnQgKSB7XG5cblx0XHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHBvaW50ZXJzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0XHRpZiAoIHBvaW50ZXJzWyBpIF0gPT0gZXZlbnQucG9pbnRlcklkICkgcmV0dXJuIHRydWU7XG5cblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIGZhbHNlO1xuXG5cdFx0fVxuXG5cdFx0ZnVuY3Rpb24gdHJhY2tQb2ludGVyKCBldmVudCApIHtcblxuXHRcdFx0bGV0IHBvc2l0aW9uID0gcG9pbnRlclBvc2l0aW9uc1sgZXZlbnQucG9pbnRlcklkIF07XG5cblx0XHRcdGlmICggcG9zaXRpb24gPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRwb3NpdGlvbiA9IG5ldyBWZWN0b3IyKCk7XG5cdFx0XHRcdHBvaW50ZXJQb3NpdGlvbnNbIGV2ZW50LnBvaW50ZXJJZCBdID0gcG9zaXRpb247XG5cblx0XHRcdH1cblxuXHRcdFx0cG9zaXRpb24uc2V0KCBldmVudC5wYWdlWCwgZXZlbnQucGFnZVkgKTtcblxuXHRcdH1cblxuXHRcdGZ1bmN0aW9uIGdldFNlY29uZFBvaW50ZXJQb3NpdGlvbiggZXZlbnQgKSB7XG5cblx0XHRcdGNvbnN0IHBvaW50ZXJJZCA9ICggZXZlbnQucG9pbnRlcklkID09PSBwb2ludGVyc1sgMCBdICkgPyBwb2ludGVyc1sgMSBdIDogcG9pbnRlcnNbIDAgXTtcblxuXHRcdFx0cmV0dXJuIHBvaW50ZXJQb3NpdGlvbnNbIHBvaW50ZXJJZCBdO1xuXG5cdFx0fVxuXG5cdFx0Ly9cblxuXHRcdHNjb3BlLmRvbUVsZW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ2NvbnRleHRtZW51Jywgb25Db250ZXh0TWVudSApO1xuXG5cdFx0c2NvcGUuZG9tRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCAncG9pbnRlcmRvd24nLCBvblBvaW50ZXJEb3duICk7XG5cdFx0c2NvcGUuZG9tRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCAncG9pbnRlcmNhbmNlbCcsIG9uUG9pbnRlclVwICk7XG5cdFx0c2NvcGUuZG9tRWxlbWVudC5hZGRFdmVudExpc3RlbmVyKCAnd2hlZWwnLCBvbk1vdXNlV2hlZWwsIHsgcGFzc2l2ZTogZmFsc2UgfSApO1xuXG5cdFx0Y29uc3QgZG9jdW1lbnQgPSBzY29wZS5kb21FbGVtZW50LmdldFJvb3ROb2RlKCk7IC8vIG9mZnNjcmVlbiBjYW52YXMgY29tcGF0aWJpbGl0eVxuXG5cdFx0ZG9jdW1lbnQuYWRkRXZlbnRMaXN0ZW5lciggJ2tleWRvd24nLCBpbnRlcmNlcHRDb250cm9sRG93biwgeyBwYXNzaXZlOiB0cnVlLCBjYXB0dXJlOiB0cnVlIH0gKTtcblxuXHRcdC8vIGZvcmNlIGFuIHVwZGF0ZSBhdCBzdGFydFxuXG5cdFx0dGhpcy51cGRhdGUoKTtcblxuXHR9XG5cbn1cblxuZXhwb3J0IHsgT3JiaXRDb250cm9scyB9O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///580\n")},596:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n s: () => (/* binding */ EffectComposer)\n});\n\n// EXTERNAL MODULE: ./node_modules/three/build/three.module.js\nvar three_module = __webpack_require__(753);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/shaders/CopyShader.js\nvar CopyShader = __webpack_require__(364);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/postprocessing/ShaderPass.js\nvar ShaderPass = __webpack_require__(45);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/postprocessing/Pass.js\nvar Pass = __webpack_require__(844);\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/postprocessing/MaskPass.js\n\n\nclass MaskPass extends Pass/* Pass */.o {\n\n\tconstructor( scene, camera ) {\n\n\t\tsuper();\n\n\t\tthis.scene = scene;\n\t\tthis.camera = camera;\n\n\t\tthis.clear = true;\n\t\tthis.needsSwap = false;\n\n\t\tthis.inverse = false;\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {\n\n\t\tconst context = renderer.getContext();\n\t\tconst state = renderer.state;\n\n\t\t// don't update color or depth\n\n\t\tstate.buffers.color.setMask( false );\n\t\tstate.buffers.depth.setMask( false );\n\n\t\t// lock buffers\n\n\t\tstate.buffers.color.setLocked( true );\n\t\tstate.buffers.depth.setLocked( true );\n\n\t\t// set up stencil\n\n\t\tlet writeValue, clearValue;\n\n\t\tif ( this.inverse ) {\n\n\t\t\twriteValue = 0;\n\t\t\tclearValue = 1;\n\n\t\t} else {\n\n\t\t\twriteValue = 1;\n\t\t\tclearValue = 0;\n\n\t\t}\n\n\t\tstate.buffers.stencil.setTest( true );\n\t\tstate.buffers.stencil.setOp( context.REPLACE, context.REPLACE, context.REPLACE );\n\t\tstate.buffers.stencil.setFunc( context.ALWAYS, writeValue, 0xffffffff );\n\t\tstate.buffers.stencil.setClear( clearValue );\n\t\tstate.buffers.stencil.setLocked( true );\n\n\t\t// draw into the stencil buffer\n\n\t\trenderer.setRenderTarget( readBuffer );\n\t\tif ( this.clear ) renderer.clear();\n\t\trenderer.render( this.scene, this.camera );\n\n\t\trenderer.setRenderTarget( writeBuffer );\n\t\tif ( this.clear ) renderer.clear();\n\t\trenderer.render( this.scene, this.camera );\n\n\t\t// unlock color and depth buffer and make them writable for subsequent rendering/clearing\n\n\t\tstate.buffers.color.setLocked( false );\n\t\tstate.buffers.depth.setLocked( false );\n\n\t\tstate.buffers.color.setMask( true );\n\t\tstate.buffers.depth.setMask( true );\n\n\t\t// only render where stencil is set to 1\n\n\t\tstate.buffers.stencil.setLocked( false );\n\t\tstate.buffers.stencil.setFunc( context.EQUAL, 1, 0xffffffff ); // draw if == 1\n\t\tstate.buffers.stencil.setOp( context.KEEP, context.KEEP, context.KEEP );\n\t\tstate.buffers.stencil.setLocked( true );\n\n\t}\n\n}\n\nclass ClearMaskPass extends Pass/* Pass */.o {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.needsSwap = false;\n\n\t}\n\n\trender( renderer /*, writeBuffer, readBuffer, deltaTime, maskActive */ ) {\n\n\t\trenderer.state.buffers.stencil.setLocked( false );\n\t\trenderer.state.buffers.stencil.setTest( false );\n\n\t}\n\n}\n\n\n\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/postprocessing/EffectComposer.js\n\n\n\n\n\n\nclass EffectComposer {\n\n\tconstructor( renderer, renderTarget ) {\n\n\t\tthis.renderer = renderer;\n\n\t\tthis._pixelRatio = renderer.getPixelRatio();\n\n\t\tif ( renderTarget === undefined ) {\n\n\t\t\tconst size = renderer.getSize( new three_module/* Vector2 */.I9Y() );\n\t\t\tthis._width = size.width;\n\t\t\tthis._height = size.height;\n\n\t\t\trenderTarget = new three_module/* WebGLRenderTarget */.nWS( this._width * this._pixelRatio, this._height * this._pixelRatio, { type: three_module/* HalfFloatType */.ix0 } );\n\t\t\trenderTarget.texture.name = 'EffectComposer.rt1';\n\n\t\t} else {\n\n\t\t\tthis._width = renderTarget.width;\n\t\t\tthis._height = renderTarget.height;\n\n\t\t}\n\n\t\tthis.renderTarget1 = renderTarget;\n\t\tthis.renderTarget2 = renderTarget.clone();\n\t\tthis.renderTarget2.texture.name = 'EffectComposer.rt2';\n\n\t\tthis.writeBuffer = this.renderTarget1;\n\t\tthis.readBuffer = this.renderTarget2;\n\n\t\tthis.renderToScreen = true;\n\n\t\tthis.passes = [];\n\n\t\tthis.copyPass = new ShaderPass/* ShaderPass */.p( CopyShader/* CopyShader */.Z );\n\t\tthis.copyPass.material.blending = three_module/* NoBlending */.XIg;\n\n\t\tthis.clock = new three_module/* Clock */.zD7();\n\n\t}\n\n\tswapBuffers() {\n\n\t\tconst tmp = this.readBuffer;\n\t\tthis.readBuffer = this.writeBuffer;\n\t\tthis.writeBuffer = tmp;\n\n\t}\n\n\taddPass( pass ) {\n\n\t\tthis.passes.push( pass );\n\t\tpass.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );\n\n\t}\n\n\tinsertPass( pass, index ) {\n\n\t\tthis.passes.splice( index, 0, pass );\n\t\tpass.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );\n\n\t}\n\n\tremovePass( pass ) {\n\n\t\tconst index = this.passes.indexOf( pass );\n\n\t\tif ( index !== - 1 ) {\n\n\t\t\tthis.passes.splice( index, 1 );\n\n\t\t}\n\n\t}\n\n\tisLastEnabledPass( passIndex ) {\n\n\t\tfor ( let i = passIndex + 1; i < this.passes.length; i ++ ) {\n\n\t\t\tif ( this.passes[ i ].enabled ) {\n\n\t\t\t\treturn false;\n\n\t\t\t}\n\n\t\t}\n\n\t\treturn true;\n\n\t}\n\n\trender( deltaTime ) {\n\n\t\t// deltaTime value is in seconds\n\n\t\tif ( deltaTime === undefined ) {\n\n\t\t\tdeltaTime = this.clock.getDelta();\n\n\t\t}\n\n\t\tconst currentRenderTarget = this.renderer.getRenderTarget();\n\n\t\tlet maskActive = false;\n\n\t\tfor ( let i = 0, il = this.passes.length; i < il; i ++ ) {\n\n\t\t\tconst pass = this.passes[ i ];\n\n\t\t\tif ( pass.enabled === false ) continue;\n\n\t\t\tpass.renderToScreen = ( this.renderToScreen && this.isLastEnabledPass( i ) );\n\t\t\tpass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime, maskActive );\n\n\t\t\tif ( pass.needsSwap ) {\n\n\t\t\t\tif ( maskActive ) {\n\n\t\t\t\t\tconst context = this.renderer.getContext();\n\t\t\t\t\tconst stencil = this.renderer.state.buffers.stencil;\n\n\t\t\t\t\t//context.stencilFunc( context.NOTEQUAL, 1, 0xffffffff );\n\t\t\t\t\tstencil.setFunc( context.NOTEQUAL, 1, 0xffffffff );\n\n\t\t\t\t\tthis.copyPass.render( this.renderer, this.writeBuffer, this.readBuffer, deltaTime );\n\n\t\t\t\t\t//context.stencilFunc( context.EQUAL, 1, 0xffffffff );\n\t\t\t\t\tstencil.setFunc( context.EQUAL, 1, 0xffffffff );\n\n\t\t\t\t}\n\n\t\t\t\tthis.swapBuffers();\n\n\t\t\t}\n\n\t\t\tif ( MaskPass !== undefined ) {\n\n\t\t\t\tif ( pass instanceof MaskPass ) {\n\n\t\t\t\t\tmaskActive = true;\n\n\t\t\t\t} else if ( pass instanceof ClearMaskPass ) {\n\n\t\t\t\t\tmaskActive = false;\n\n\t\t\t\t}\n\n\t\t\t}\n\n\t\t}\n\n\t\tthis.renderer.setRenderTarget( currentRenderTarget );\n\n\t}\n\n\treset( renderTarget ) {\n\n\t\tif ( renderTarget === undefined ) {\n\n\t\t\tconst size = this.renderer.getSize( new three_module/* Vector2 */.I9Y() );\n\t\t\tthis._pixelRatio = this.renderer.getPixelRatio();\n\t\t\tthis._width = size.width;\n\t\t\tthis._height = size.height;\n\n\t\t\trenderTarget = this.renderTarget1.clone();\n\t\t\trenderTarget.setSize( this._width * this._pixelRatio, this._height * this._pixelRatio );\n\n\t\t}\n\n\t\tthis.renderTarget1.dispose();\n\t\tthis.renderTarget2.dispose();\n\t\tthis.renderTarget1 = renderTarget;\n\t\tthis.renderTarget2 = renderTarget.clone();\n\n\t\tthis.writeBuffer = this.renderTarget1;\n\t\tthis.readBuffer = this.renderTarget2;\n\n\t}\n\n\tsetSize( width, height ) {\n\n\t\tthis._width = width;\n\t\tthis._height = height;\n\n\t\tconst effectiveWidth = this._width * this._pixelRatio;\n\t\tconst effectiveHeight = this._height * this._pixelRatio;\n\n\t\tthis.renderTarget1.setSize( effectiveWidth, effectiveHeight );\n\t\tthis.renderTarget2.setSize( effectiveWidth, effectiveHeight );\n\n\t\tfor ( let i = 0; i < this.passes.length; i ++ ) {\n\n\t\t\tthis.passes[ i ].setSize( effectiveWidth, effectiveHeight );\n\n\t\t}\n\n\t}\n\n\tsetPixelRatio( pixelRatio ) {\n\n\t\tthis._pixelRatio = pixelRatio;\n\n\t\tthis.setSize( this._width, this._height );\n\n\t}\n\n\tdispose() {\n\n\t\tthis.renderTarget1.dispose();\n\t\tthis.renderTarget2.dispose();\n\n\t\tthis.copyPass.dispose();\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNTk2LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7OztBQUFpQzs7QUFFakMsdUJBQXVCLGdCQUFJOztBQUUzQjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBLGlFQUFpRTtBQUNqRTtBQUNBOztBQUVBOztBQUVBOztBQUVBLDRCQUE0QixnQkFBSTs7QUFFaEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFbUM7OztBQ2pHcEI7QUFDdUM7QUFDVDtBQUNKO0FBQ0s7O0FBRTlDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLHNDQUFzQyw2QkFBTztBQUM3QztBQUNBOztBQUVBLHNCQUFzQix1Q0FBaUIscUVBQXFFLE1BQU0sbUNBQWEsR0FBRztBQUNsSTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsc0JBQXNCLDRCQUFVLEVBQUUsNEJBQVU7QUFDNUMsb0NBQW9DLGdDQUFVOztBQUU5QyxtQkFBbUIsMkJBQUs7O0FBRXhCOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsK0JBQStCLHdCQUF3Qjs7QUFFdkQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsNENBQTRDLFFBQVE7O0FBRXBEOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsUUFBUSxRQUFROztBQUVoQix5QkFBeUIsUUFBUTs7QUFFakM7O0FBRUEsTUFBTSwwQkFBMEIsYUFBYTs7QUFFN0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsMkNBQTJDLDZCQUFPO0FBQ2xEO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsbUJBQW1CLHdCQUF3Qjs7QUFFM0M7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFMEIiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9wb3N0cHJvY2Vzc2luZy9NYXNrUGFzcy5qcz9lMTA5Iiwid2VicGFjazovL3RocmVlanMtcG9zdHByb2Nlc3MvLi9ub2RlX21vZHVsZXMvdGhyZWUvZXhhbXBsZXMvanNtL3Bvc3Rwcm9jZXNzaW5nL0VmZmVjdENvbXBvc2VyLmpzPzM4NTkiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgUGFzcyB9IGZyb20gJy4vUGFzcy5qcyc7XG5cbmNsYXNzIE1hc2tQYXNzIGV4dGVuZHMgUGFzcyB7XG5cblx0Y29uc3RydWN0b3IoIHNjZW5lLCBjYW1lcmEgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy5zY2VuZSA9IHNjZW5lO1xuXHRcdHRoaXMuY2FtZXJhID0gY2FtZXJhO1xuXG5cdFx0dGhpcy5jbGVhciA9IHRydWU7XG5cdFx0dGhpcy5uZWVkc1N3YXAgPSBmYWxzZTtcblxuXHRcdHRoaXMuaW52ZXJzZSA9IGZhbHNlO1xuXG5cdH1cblxuXHRyZW5kZXIoIHJlbmRlcmVyLCB3cml0ZUJ1ZmZlciwgcmVhZEJ1ZmZlciAvKiwgZGVsdGFUaW1lLCBtYXNrQWN0aXZlICovICkge1xuXG5cdFx0Y29uc3QgY29udGV4dCA9IHJlbmRlcmVyLmdldENvbnRleHQoKTtcblx0XHRjb25zdCBzdGF0ZSA9IHJlbmRlcmVyLnN0YXRlO1xuXG5cdFx0Ly8gZG9uJ3QgdXBkYXRlIGNvbG9yIG9yIGRlcHRoXG5cblx0XHRzdGF0ZS5idWZmZXJzLmNvbG9yLnNldE1hc2soIGZhbHNlICk7XG5cdFx0c3RhdGUuYnVmZmVycy5kZXB0aC5zZXRNYXNrKCBmYWxzZSApO1xuXG5cdFx0Ly8gbG9jayBidWZmZXJzXG5cblx0XHRzdGF0ZS5idWZmZXJzLmNvbG9yLnNldExvY2tlZCggdHJ1ZSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuZGVwdGguc2V0TG9ja2VkKCB0cnVlICk7XG5cblx0XHQvLyBzZXQgdXAgc3RlbmNpbFxuXG5cdFx0bGV0IHdyaXRlVmFsdWUsIGNsZWFyVmFsdWU7XG5cblx0XHRpZiAoIHRoaXMuaW52ZXJzZSApIHtcblxuXHRcdFx0d3JpdGVWYWx1ZSA9IDA7XG5cdFx0XHRjbGVhclZhbHVlID0gMTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHdyaXRlVmFsdWUgPSAxO1xuXHRcdFx0Y2xlYXJWYWx1ZSA9IDA7XG5cblx0XHR9XG5cblx0XHRzdGF0ZS5idWZmZXJzLnN0ZW5jaWwuc2V0VGVzdCggdHJ1ZSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRPcCggY29udGV4dC5SRVBMQUNFLCBjb250ZXh0LlJFUExBQ0UsIGNvbnRleHQuUkVQTEFDRSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRGdW5jKCBjb250ZXh0LkFMV0FZUywgd3JpdGVWYWx1ZSwgMHhmZmZmZmZmZiApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRDbGVhciggY2xlYXJWYWx1ZSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRMb2NrZWQoIHRydWUgKTtcblxuXHRcdC8vIGRyYXcgaW50byB0aGUgc3RlbmNpbCBidWZmZXJcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggcmVhZEJ1ZmZlciApO1xuXHRcdGlmICggdGhpcy5jbGVhciApIHJlbmRlcmVyLmNsZWFyKCk7XG5cdFx0cmVuZGVyZXIucmVuZGVyKCB0aGlzLnNjZW5lLCB0aGlzLmNhbWVyYSApO1xuXG5cdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCB3cml0ZUJ1ZmZlciApO1xuXHRcdGlmICggdGhpcy5jbGVhciApIHJlbmRlcmVyLmNsZWFyKCk7XG5cdFx0cmVuZGVyZXIucmVuZGVyKCB0aGlzLnNjZW5lLCB0aGlzLmNhbWVyYSApO1xuXG5cdFx0Ly8gdW5sb2NrIGNvbG9yIGFuZCBkZXB0aCBidWZmZXIgYW5kIG1ha2UgdGhlbSB3cml0YWJsZSBmb3Igc3Vic2VxdWVudCByZW5kZXJpbmcvY2xlYXJpbmdcblxuXHRcdHN0YXRlLmJ1ZmZlcnMuY29sb3Iuc2V0TG9ja2VkKCBmYWxzZSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuZGVwdGguc2V0TG9ja2VkKCBmYWxzZSApO1xuXG5cdFx0c3RhdGUuYnVmZmVycy5jb2xvci5zZXRNYXNrKCB0cnVlICk7XG5cdFx0c3RhdGUuYnVmZmVycy5kZXB0aC5zZXRNYXNrKCB0cnVlICk7XG5cblx0XHQvLyBvbmx5IHJlbmRlciB3aGVyZSBzdGVuY2lsIGlzIHNldCB0byAxXG5cblx0XHRzdGF0ZS5idWZmZXJzLnN0ZW5jaWwuc2V0TG9ja2VkKCBmYWxzZSApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRGdW5jKCBjb250ZXh0LkVRVUFMLCAxLCAweGZmZmZmZmZmICk7IC8vIGRyYXcgaWYgPT0gMVxuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRPcCggY29udGV4dC5LRUVQLCBjb250ZXh0LktFRVAsIGNvbnRleHQuS0VFUCApO1xuXHRcdHN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRMb2NrZWQoIHRydWUgKTtcblxuXHR9XG5cbn1cblxuY2xhc3MgQ2xlYXJNYXNrUGFzcyBleHRlbmRzIFBhc3Mge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0c3VwZXIoKTtcblxuXHRcdHRoaXMubmVlZHNTd2FwID0gZmFsc2U7XG5cblx0fVxuXG5cdHJlbmRlciggcmVuZGVyZXIgLyosIHdyaXRlQnVmZmVyLCByZWFkQnVmZmVyLCBkZWx0YVRpbWUsIG1hc2tBY3RpdmUgKi8gKSB7XG5cblx0XHRyZW5kZXJlci5zdGF0ZS5idWZmZXJzLnN0ZW5jaWwuc2V0TG9ja2VkKCBmYWxzZSApO1xuXHRcdHJlbmRlcmVyLnN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRUZXN0KCBmYWxzZSApO1xuXG5cdH1cblxufVxuXG5leHBvcnQgeyBNYXNrUGFzcywgQ2xlYXJNYXNrUGFzcyB9O1xuIiwiaW1wb3J0IHtcblx0Q2xvY2ssXG5cdEhhbGZGbG9hdFR5cGUsXG5cdE5vQmxlbmRpbmcsXG5cdFZlY3RvcjIsXG5cdFdlYkdMUmVuZGVyVGFyZ2V0XG59IGZyb20gJ3RocmVlJztcbmltcG9ydCB7IENvcHlTaGFkZXIgfSBmcm9tICcuLi9zaGFkZXJzL0NvcHlTaGFkZXIuanMnO1xuaW1wb3J0IHsgU2hhZGVyUGFzcyB9IGZyb20gJy4vU2hhZGVyUGFzcy5qcyc7XG5pbXBvcnQgeyBNYXNrUGFzcyB9IGZyb20gJy4vTWFza1Bhc3MuanMnO1xuaW1wb3J0IHsgQ2xlYXJNYXNrUGFzcyB9IGZyb20gJy4vTWFza1Bhc3MuanMnO1xuXG5jbGFzcyBFZmZlY3RDb21wb3NlciB7XG5cblx0Y29uc3RydWN0b3IoIHJlbmRlcmVyLCByZW5kZXJUYXJnZXQgKSB7XG5cblx0XHR0aGlzLnJlbmRlcmVyID0gcmVuZGVyZXI7XG5cblx0XHR0aGlzLl9waXhlbFJhdGlvID0gcmVuZGVyZXIuZ2V0UGl4ZWxSYXRpbygpO1xuXG5cdFx0aWYgKCByZW5kZXJUYXJnZXQgPT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0Y29uc3Qgc2l6ZSA9IHJlbmRlcmVyLmdldFNpemUoIG5ldyBWZWN0b3IyKCkgKTtcblx0XHRcdHRoaXMuX3dpZHRoID0gc2l6ZS53aWR0aDtcblx0XHRcdHRoaXMuX2hlaWdodCA9IHNpemUuaGVpZ2h0O1xuXG5cdFx0XHRyZW5kZXJUYXJnZXQgPSBuZXcgV2ViR0xSZW5kZXJUYXJnZXQoIHRoaXMuX3dpZHRoICogdGhpcy5fcGl4ZWxSYXRpbywgdGhpcy5faGVpZ2h0ICogdGhpcy5fcGl4ZWxSYXRpbywgeyB0eXBlOiBIYWxmRmxvYXRUeXBlIH0gKTtcblx0XHRcdHJlbmRlclRhcmdldC50ZXh0dXJlLm5hbWUgPSAnRWZmZWN0Q29tcG9zZXIucnQxJztcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHRoaXMuX3dpZHRoID0gcmVuZGVyVGFyZ2V0LndpZHRoO1xuXHRcdFx0dGhpcy5faGVpZ2h0ID0gcmVuZGVyVGFyZ2V0LmhlaWdodDtcblxuXHRcdH1cblxuXHRcdHRoaXMucmVuZGVyVGFyZ2V0MSA9IHJlbmRlclRhcmdldDtcblx0XHR0aGlzLnJlbmRlclRhcmdldDIgPSByZW5kZXJUYXJnZXQuY2xvbmUoKTtcblx0XHR0aGlzLnJlbmRlclRhcmdldDIudGV4dHVyZS5uYW1lID0gJ0VmZmVjdENvbXBvc2VyLnJ0Mic7XG5cblx0XHR0aGlzLndyaXRlQnVmZmVyID0gdGhpcy5yZW5kZXJUYXJnZXQxO1xuXHRcdHRoaXMucmVhZEJ1ZmZlciA9IHRoaXMucmVuZGVyVGFyZ2V0MjtcblxuXHRcdHRoaXMucmVuZGVyVG9TY3JlZW4gPSB0cnVlO1xuXG5cdFx0dGhpcy5wYXNzZXMgPSBbXTtcblxuXHRcdHRoaXMuY29weVBhc3MgPSBuZXcgU2hhZGVyUGFzcyggQ29weVNoYWRlciApO1xuXHRcdHRoaXMuY29weVBhc3MubWF0ZXJpYWwuYmxlbmRpbmcgPSBOb0JsZW5kaW5nO1xuXG5cdFx0dGhpcy5jbG9jayA9IG5ldyBDbG9jaygpO1xuXG5cdH1cblxuXHRzd2FwQnVmZmVycygpIHtcblxuXHRcdGNvbnN0IHRtcCA9IHRoaXMucmVhZEJ1ZmZlcjtcblx0XHR0aGlzLnJlYWRCdWZmZXIgPSB0aGlzLndyaXRlQnVmZmVyO1xuXHRcdHRoaXMud3JpdGVCdWZmZXIgPSB0bXA7XG5cblx0fVxuXG5cdGFkZFBhc3MoIHBhc3MgKSB7XG5cblx0XHR0aGlzLnBhc3Nlcy5wdXNoKCBwYXNzICk7XG5cdFx0cGFzcy5zZXRTaXplKCB0aGlzLl93aWR0aCAqIHRoaXMuX3BpeGVsUmF0aW8sIHRoaXMuX2hlaWdodCAqIHRoaXMuX3BpeGVsUmF0aW8gKTtcblxuXHR9XG5cblx0aW5zZXJ0UGFzcyggcGFzcywgaW5kZXggKSB7XG5cblx0XHR0aGlzLnBhc3Nlcy5zcGxpY2UoIGluZGV4LCAwLCBwYXNzICk7XG5cdFx0cGFzcy5zZXRTaXplKCB0aGlzLl93aWR0aCAqIHRoaXMuX3BpeGVsUmF0aW8sIHRoaXMuX2hlaWdodCAqIHRoaXMuX3BpeGVsUmF0aW8gKTtcblxuXHR9XG5cblx0cmVtb3ZlUGFzcyggcGFzcyApIHtcblxuXHRcdGNvbnN0IGluZGV4ID0gdGhpcy5wYXNzZXMuaW5kZXhPZiggcGFzcyApO1xuXG5cdFx0aWYgKCBpbmRleCAhPT0gLSAxICkge1xuXG5cdFx0XHR0aGlzLnBhc3Nlcy5zcGxpY2UoIGluZGV4LCAxICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdGlzTGFzdEVuYWJsZWRQYXNzKCBwYXNzSW5kZXggKSB7XG5cblx0XHRmb3IgKCBsZXQgaSA9IHBhc3NJbmRleCArIDE7IGkgPCB0aGlzLnBhc3Nlcy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdGlmICggdGhpcy5wYXNzZXNbIGkgXS5lbmFibGVkICkge1xuXG5cdFx0XHRcdHJldHVybiBmYWxzZTtcblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0cmV0dXJuIHRydWU7XG5cblx0fVxuXG5cdHJlbmRlciggZGVsdGFUaW1lICkge1xuXG5cdFx0Ly8gZGVsdGFUaW1lIHZhbHVlIGlzIGluIHNlY29uZHNcblxuXHRcdGlmICggZGVsdGFUaW1lID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGRlbHRhVGltZSA9IHRoaXMuY2xvY2suZ2V0RGVsdGEoKTtcblxuXHRcdH1cblxuXHRcdGNvbnN0IGN1cnJlbnRSZW5kZXJUYXJnZXQgPSB0aGlzLnJlbmRlcmVyLmdldFJlbmRlclRhcmdldCgpO1xuXG5cdFx0bGV0IG1hc2tBY3RpdmUgPSBmYWxzZTtcblxuXHRcdGZvciAoIGxldCBpID0gMCwgaWwgPSB0aGlzLnBhc3Nlcy5sZW5ndGg7IGkgPCBpbDsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgcGFzcyA9IHRoaXMucGFzc2VzWyBpIF07XG5cblx0XHRcdGlmICggcGFzcy5lbmFibGVkID09PSBmYWxzZSApIGNvbnRpbnVlO1xuXG5cdFx0XHRwYXNzLnJlbmRlclRvU2NyZWVuID0gKCB0aGlzLnJlbmRlclRvU2NyZWVuICYmIHRoaXMuaXNMYXN0RW5hYmxlZFBhc3MoIGkgKSApO1xuXHRcdFx0cGFzcy5yZW5kZXIoIHRoaXMucmVuZGVyZXIsIHRoaXMud3JpdGVCdWZmZXIsIHRoaXMucmVhZEJ1ZmZlciwgZGVsdGFUaW1lLCBtYXNrQWN0aXZlICk7XG5cblx0XHRcdGlmICggcGFzcy5uZWVkc1N3YXAgKSB7XG5cblx0XHRcdFx0aWYgKCBtYXNrQWN0aXZlICkge1xuXG5cdFx0XHRcdFx0Y29uc3QgY29udGV4dCA9IHRoaXMucmVuZGVyZXIuZ2V0Q29udGV4dCgpO1xuXHRcdFx0XHRcdGNvbnN0IHN0ZW5jaWwgPSB0aGlzLnJlbmRlcmVyLnN0YXRlLmJ1ZmZlcnMuc3RlbmNpbDtcblxuXHRcdFx0XHRcdC8vY29udGV4dC5zdGVuY2lsRnVuYyggY29udGV4dC5OT1RFUVVBTCwgMSwgMHhmZmZmZmZmZiApO1xuXHRcdFx0XHRcdHN0ZW5jaWwuc2V0RnVuYyggY29udGV4dC5OT1RFUVVBTCwgMSwgMHhmZmZmZmZmZiApO1xuXG5cdFx0XHRcdFx0dGhpcy5jb3B5UGFzcy5yZW5kZXIoIHRoaXMucmVuZGVyZXIsIHRoaXMud3JpdGVCdWZmZXIsIHRoaXMucmVhZEJ1ZmZlciwgZGVsdGFUaW1lICk7XG5cblx0XHRcdFx0XHQvL2NvbnRleHQuc3RlbmNpbEZ1bmMoIGNvbnRleHQuRVFVQUwsIDEsIDB4ZmZmZmZmZmYgKTtcblx0XHRcdFx0XHRzdGVuY2lsLnNldEZ1bmMoIGNvbnRleHQuRVFVQUwsIDEsIDB4ZmZmZmZmZmYgKTtcblxuXHRcdFx0XHR9XG5cblx0XHRcdFx0dGhpcy5zd2FwQnVmZmVycygpO1xuXG5cdFx0XHR9XG5cblx0XHRcdGlmICggTWFza1Bhc3MgIT09IHVuZGVmaW5lZCApIHtcblxuXHRcdFx0XHRpZiAoIHBhc3MgaW5zdGFuY2VvZiBNYXNrUGFzcyApIHtcblxuXHRcdFx0XHRcdG1hc2tBY3RpdmUgPSB0cnVlO1xuXG5cdFx0XHRcdH0gZWxzZSBpZiAoIHBhc3MgaW5zdGFuY2VvZiBDbGVhck1hc2tQYXNzICkge1xuXG5cdFx0XHRcdFx0bWFza0FjdGl2ZSA9IGZhbHNlO1xuXG5cdFx0XHRcdH1cblxuXHRcdFx0fVxuXG5cdFx0fVxuXG5cdFx0dGhpcy5yZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIGN1cnJlbnRSZW5kZXJUYXJnZXQgKTtcblxuXHR9XG5cblx0cmVzZXQoIHJlbmRlclRhcmdldCApIHtcblxuXHRcdGlmICggcmVuZGVyVGFyZ2V0ID09PSB1bmRlZmluZWQgKSB7XG5cblx0XHRcdGNvbnN0IHNpemUgPSB0aGlzLnJlbmRlcmVyLmdldFNpemUoIG5ldyBWZWN0b3IyKCkgKTtcblx0XHRcdHRoaXMuX3BpeGVsUmF0aW8gPSB0aGlzLnJlbmRlcmVyLmdldFBpeGVsUmF0aW8oKTtcblx0XHRcdHRoaXMuX3dpZHRoID0gc2l6ZS53aWR0aDtcblx0XHRcdHRoaXMuX2hlaWdodCA9IHNpemUuaGVpZ2h0O1xuXG5cdFx0XHRyZW5kZXJUYXJnZXQgPSB0aGlzLnJlbmRlclRhcmdldDEuY2xvbmUoKTtcblx0XHRcdHJlbmRlclRhcmdldC5zZXRTaXplKCB0aGlzLl93aWR0aCAqIHRoaXMuX3BpeGVsUmF0aW8sIHRoaXMuX2hlaWdodCAqIHRoaXMuX3BpeGVsUmF0aW8gKTtcblxuXHRcdH1cblxuXHRcdHRoaXMucmVuZGVyVGFyZ2V0MS5kaXNwb3NlKCk7XG5cdFx0dGhpcy5yZW5kZXJUYXJnZXQyLmRpc3Bvc2UoKTtcblx0XHR0aGlzLnJlbmRlclRhcmdldDEgPSByZW5kZXJUYXJnZXQ7XG5cdFx0dGhpcy5yZW5kZXJUYXJnZXQyID0gcmVuZGVyVGFyZ2V0LmNsb25lKCk7XG5cblx0XHR0aGlzLndyaXRlQnVmZmVyID0gdGhpcy5yZW5kZXJUYXJnZXQxO1xuXHRcdHRoaXMucmVhZEJ1ZmZlciA9IHRoaXMucmVuZGVyVGFyZ2V0MjtcblxuXHR9XG5cblx0c2V0U2l6ZSggd2lkdGgsIGhlaWdodCApIHtcblxuXHRcdHRoaXMuX3dpZHRoID0gd2lkdGg7XG5cdFx0dGhpcy5faGVpZ2h0ID0gaGVpZ2h0O1xuXG5cdFx0Y29uc3QgZWZmZWN0aXZlV2lkdGggPSB0aGlzLl93aWR0aCAqIHRoaXMuX3BpeGVsUmF0aW87XG5cdFx0Y29uc3QgZWZmZWN0aXZlSGVpZ2h0ID0gdGhpcy5faGVpZ2h0ICogdGhpcy5fcGl4ZWxSYXRpbztcblxuXHRcdHRoaXMucmVuZGVyVGFyZ2V0MS5zZXRTaXplKCBlZmZlY3RpdmVXaWR0aCwgZWZmZWN0aXZlSGVpZ2h0ICk7XG5cdFx0dGhpcy5yZW5kZXJUYXJnZXQyLnNldFNpemUoIGVmZmVjdGl2ZVdpZHRoLCBlZmZlY3RpdmVIZWlnaHQgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMucGFzc2VzLmxlbmd0aDsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5wYXNzZXNbIGkgXS5zZXRTaXplKCBlZmZlY3RpdmVXaWR0aCwgZWZmZWN0aXZlSGVpZ2h0ICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHNldFBpeGVsUmF0aW8oIHBpeGVsUmF0aW8gKSB7XG5cblx0XHR0aGlzLl9waXhlbFJhdGlvID0gcGl4ZWxSYXRpbztcblxuXHRcdHRoaXMuc2V0U2l6ZSggdGhpcy5fd2lkdGgsIHRoaXMuX2hlaWdodCApO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5yZW5kZXJUYXJnZXQxLmRpc3Bvc2UoKTtcblx0XHR0aGlzLnJlbmRlclRhcmdldDIuZGlzcG9zZSgpO1xuXG5cdFx0dGhpcy5jb3B5UGFzcy5kaXNwb3NlKCk7XG5cblx0fVxuXG59XG5cbmV4cG9ydCB7IEVmZmVjdENvbXBvc2VyIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///596\n")},296:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n X: () => (/* binding */ OutputPass)\n});\n\n// EXTERNAL MODULE: ./node_modules/three/build/three.module.js\nvar three_module = __webpack_require__(753);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/postprocessing/Pass.js\nvar Pass = __webpack_require__(844);\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/shaders/OutputShader.js\nconst OutputShader = {\n\n\tname: 'OutputShader',\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'toneMappingExposure': { value: 1 }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\t\tprecision highp float;\n\n\t\tuniform mat4 modelViewMatrix;\n\t\tuniform mat4 projectionMatrix;\n\n\t\tattribute vec3 position;\n\t\tattribute vec2 uv;\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\t\n\t\tprecision highp float;\n\n\t\tuniform sampler2D tDiffuse;\n\n\t\t#include \n\t\t#include \n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tgl_FragColor = texture2D( tDiffuse, vUv );\n\n\t\t\t// tone mapping\n\n\t\t\t#ifdef LINEAR_TONE_MAPPING\n\n\t\t\t\tgl_FragColor.rgb = LinearToneMapping( gl_FragColor.rgb );\n\n\t\t\t#elif defined( REINHARD_TONE_MAPPING )\n\n\t\t\t\tgl_FragColor.rgb = ReinhardToneMapping( gl_FragColor.rgb );\n\n\t\t\t#elif defined( CINEON_TONE_MAPPING )\n\n\t\t\t\tgl_FragColor.rgb = OptimizedCineonToneMapping( gl_FragColor.rgb );\n\n\t\t\t#elif defined( ACES_FILMIC_TONE_MAPPING )\n\n\t\t\t\tgl_FragColor.rgb = ACESFilmicToneMapping( gl_FragColor.rgb );\n\n\t\t\t#elif defined( AGX_TONE_MAPPING )\n\n\t\t\t\tgl_FragColor.rgb = AgXToneMapping( gl_FragColor.rgb );\n\n\t\t\t#elif defined( NEUTRAL_TONE_MAPPING )\n\n\t\t\t\tgl_FragColor.rgb = NeutralToneMapping( gl_FragColor.rgb );\n\n\t\t\t#endif\n\n\t\t\t// color space\n\n\t\t\t#ifdef SRGB_TRANSFER\n\n\t\t\t\tgl_FragColor = sRGBTransferOETF( gl_FragColor );\n\n\t\t\t#endif\n\n\t\t}`\n\n};\n\n\n\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/postprocessing/OutputPass.js\n\n\n\n\nclass OutputPass extends Pass/* Pass */.o {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\t//\n\n\t\tconst shader = OutputShader;\n\n\t\tthis.uniforms = three_module/* UniformsUtils */.LlO.clone( shader.uniforms );\n\n\t\tthis.material = new three_module/* RawShaderMaterial */.D$Q( {\n\t\t\tname: shader.name,\n\t\t\tuniforms: this.uniforms,\n\t\t\tvertexShader: shader.vertexShader,\n\t\t\tfragmentShader: shader.fragmentShader\n\t\t} );\n\n\t\tthis.fsQuad = new Pass/* FullScreenQuad */.F( this.material );\n\n\t\t// internal cache\n\n\t\tthis._outputColorSpace = null;\n\t\tthis._toneMapping = null;\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive */ ) {\n\n\t\tthis.uniforms[ 'tDiffuse' ].value = readBuffer.texture;\n\t\tthis.uniforms[ 'toneMappingExposure' ].value = renderer.toneMappingExposure;\n\n\t\t// rebuild defines if required\n\n\t\tif ( this._outputColorSpace !== renderer.outputColorSpace || this._toneMapping !== renderer.toneMapping ) {\n\n\t\t\tthis._outputColorSpace = renderer.outputColorSpace;\n\t\t\tthis._toneMapping = renderer.toneMapping;\n\n\t\t\tthis.material.defines = {};\n\n\t\t\tif ( three_module/* ColorManagement */.ppV.getTransfer( this._outputColorSpace ) === three_module/* SRGBTransfer */.KLL ) this.material.defines.SRGB_TRANSFER = '';\n\n\t\t\tif ( this._toneMapping === three_module/* LinearToneMapping */.kyO ) this.material.defines.LINEAR_TONE_MAPPING = '';\n\t\t\telse if ( this._toneMapping === three_module/* ReinhardToneMapping */.Mjd ) this.material.defines.REINHARD_TONE_MAPPING = '';\n\t\t\telse if ( this._toneMapping === three_module/* CineonToneMapping */.nNL ) this.material.defines.CINEON_TONE_MAPPING = '';\n\t\t\telse if ( this._toneMapping === three_module/* ACESFilmicToneMapping */.FV ) this.material.defines.ACES_FILMIC_TONE_MAPPING = '';\n\t\t\telse if ( this._toneMapping === three_module/* AgXToneMapping */.LAk ) this.material.defines.AGX_TONE_MAPPING = '';\n\t\t\telse if ( this._toneMapping === three_module/* NeutralToneMapping */.aJ8 ) this.material.defines.NEUTRAL_TONE_MAPPING = '';\n\n\t\t\tthis.material.needsUpdate = true;\n\n\t\t}\n\n\t\t//\n\n\t\tif ( this.renderToScreen === true ) {\n\n\t\t\trenderer.setRenderTarget( null );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t} else {\n\n\t\t\trenderer.setRenderTarget( writeBuffer );\n\t\t\tif ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t}\n\n\t}\n\n\tdispose() {\n\n\t\tthis.material.dispose();\n\t\tthis.fsQuad.dispose();\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMjk2LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBQUE7O0FBRUE7O0FBRUE7O0FBRUEsZ0JBQWdCLGFBQWE7QUFDN0IsMkJBQTJCOztBQUUzQixFQUFFOztBQUVGO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsR0FBRzs7QUFFSDtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUV3Qjs7O0FDekVUO0FBQ2tDO0FBQ1M7O0FBRTFELHlCQUF5QixnQkFBSTs7QUFFN0I7O0FBRUE7O0FBRUE7O0FBRUEsaUJBQWlCLFlBQVk7O0FBRTdCLGtCQUFrQixtQ0FBYTs7QUFFL0Isc0JBQXNCLHVDQUFpQjtBQUN2QztBQUNBO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUosb0JBQW9CLDBCQUFjOztBQUVsQzs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQSxRQUFRLHFDQUFlLDJDQUEyQyxrQ0FBWTs7QUFFOUUsOEJBQThCLHVDQUFpQjtBQUMvQyxtQ0FBbUMseUNBQW1CO0FBQ3RELG1DQUFtQyx1Q0FBaUI7QUFDcEQsbUNBQW1DLDBDQUFxQjtBQUN4RCxtQ0FBbUMsb0NBQWM7QUFDakQsbUNBQW1DLHdDQUFrQjs7QUFFckQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVzQiIsInNvdXJjZXMiOlsid2VicGFjazovL3RocmVlanMtcG9zdHByb2Nlc3MvLi9ub2RlX21vZHVsZXMvdGhyZWUvZXhhbXBsZXMvanNtL3NoYWRlcnMvT3V0cHV0U2hhZGVyLmpzPzA5YzQiLCJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy90aHJlZS9leGFtcGxlcy9qc20vcG9zdHByb2Nlc3NpbmcvT3V0cHV0UGFzcy5qcz8yN2U3Il0sInNvdXJjZXNDb250ZW50IjpbImNvbnN0IE91dHB1dFNoYWRlciA9IHtcblxuXHRuYW1lOiAnT3V0cHV0U2hhZGVyJyxcblxuXHR1bmlmb3Jtczoge1xuXG5cdFx0J3REaWZmdXNlJzogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdCd0b25lTWFwcGluZ0V4cG9zdXJlJzogeyB2YWx1ZTogMSB9XG5cblx0fSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cdFx0cHJlY2lzaW9uIGhpZ2hwIGZsb2F0O1xuXG5cdFx0dW5pZm9ybSBtYXQ0IG1vZGVsVmlld01hdHJpeDtcblx0XHR1bmlmb3JtIG1hdDQgcHJvamVjdGlvbk1hdHJpeDtcblxuXHRcdGF0dHJpYnV0ZSB2ZWMzIHBvc2l0aW9uO1xuXHRcdGF0dHJpYnV0ZSB2ZWMyIHV2O1xuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0dlV2ID0gdXY7XG5cdFx0XHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XG5cblx0XHR9YCxcblxuXHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2Bcblx0XG5cdFx0cHJlY2lzaW9uIGhpZ2hwIGZsb2F0O1xuXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgdERpZmZ1c2U7XG5cblx0XHQjaW5jbHVkZSA8dG9uZW1hcHBpbmdfcGFyc19mcmFnbWVudD5cblx0XHQjaW5jbHVkZSA8Y29sb3JzcGFjZV9wYXJzX2ZyYWdtZW50PlxuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0Z2xfRnJhZ0NvbG9yID0gdGV4dHVyZTJEKCB0RGlmZnVzZSwgdlV2ICk7XG5cblx0XHRcdC8vIHRvbmUgbWFwcGluZ1xuXG5cdFx0XHQjaWZkZWYgTElORUFSX1RPTkVfTUFQUElOR1xuXG5cdFx0XHRcdGdsX0ZyYWdDb2xvci5yZ2IgPSBMaW5lYXJUb25lTWFwcGluZyggZ2xfRnJhZ0NvbG9yLnJnYiApO1xuXG5cdFx0XHQjZWxpZiBkZWZpbmVkKCBSRUlOSEFSRF9UT05FX01BUFBJTkcgKVxuXG5cdFx0XHRcdGdsX0ZyYWdDb2xvci5yZ2IgPSBSZWluaGFyZFRvbmVNYXBwaW5nKCBnbF9GcmFnQ29sb3IucmdiICk7XG5cblx0XHRcdCNlbGlmIGRlZmluZWQoIENJTkVPTl9UT05FX01BUFBJTkcgKVxuXG5cdFx0XHRcdGdsX0ZyYWdDb2xvci5yZ2IgPSBPcHRpbWl6ZWRDaW5lb25Ub25lTWFwcGluZyggZ2xfRnJhZ0NvbG9yLnJnYiApO1xuXG5cdFx0XHQjZWxpZiBkZWZpbmVkKCBBQ0VTX0ZJTE1JQ19UT05FX01BUFBJTkcgKVxuXG5cdFx0XHRcdGdsX0ZyYWdDb2xvci5yZ2IgPSBBQ0VTRmlsbWljVG9uZU1hcHBpbmcoIGdsX0ZyYWdDb2xvci5yZ2IgKTtcblxuXHRcdFx0I2VsaWYgZGVmaW5lZCggQUdYX1RPTkVfTUFQUElORyApXG5cblx0XHRcdFx0Z2xfRnJhZ0NvbG9yLnJnYiA9IEFnWFRvbmVNYXBwaW5nKCBnbF9GcmFnQ29sb3IucmdiICk7XG5cblx0XHRcdCNlbGlmIGRlZmluZWQoIE5FVVRSQUxfVE9ORV9NQVBQSU5HIClcblxuXHRcdFx0XHRnbF9GcmFnQ29sb3IucmdiID0gTmV1dHJhbFRvbmVNYXBwaW5nKCBnbF9GcmFnQ29sb3IucmdiICk7XG5cblx0XHRcdCNlbmRpZlxuXG5cdFx0XHQvLyBjb2xvciBzcGFjZVxuXG5cdFx0XHQjaWZkZWYgU1JHQl9UUkFOU0ZFUlxuXG5cdFx0XHRcdGdsX0ZyYWdDb2xvciA9IHNSR0JUcmFuc2Zlck9FVEYoIGdsX0ZyYWdDb2xvciApO1xuXG5cdFx0XHQjZW5kaWZcblxuXHRcdH1gXG5cbn07XG5cbmV4cG9ydCB7IE91dHB1dFNoYWRlciB9O1xuIiwiaW1wb3J0IHtcblx0Q29sb3JNYW5hZ2VtZW50LFxuXHRSYXdTaGFkZXJNYXRlcmlhbCxcblx0VW5pZm9ybXNVdGlscyxcblx0TGluZWFyVG9uZU1hcHBpbmcsXG5cdFJlaW5oYXJkVG9uZU1hcHBpbmcsXG5cdENpbmVvblRvbmVNYXBwaW5nLFxuXHRBZ1hUb25lTWFwcGluZyxcblx0QUNFU0ZpbG1pY1RvbmVNYXBwaW5nLFxuXHROZXV0cmFsVG9uZU1hcHBpbmcsXG5cdFNSR0JUcmFuc2ZlclxufSBmcm9tICd0aHJlZSc7XG5pbXBvcnQgeyBQYXNzLCBGdWxsU2NyZWVuUXVhZCB9IGZyb20gJy4vUGFzcy5qcyc7XG5pbXBvcnQgeyBPdXRwdXRTaGFkZXIgfSBmcm9tICcuLi9zaGFkZXJzL091dHB1dFNoYWRlci5qcyc7XG5cbmNsYXNzIE91dHB1dFBhc3MgZXh0ZW5kcyBQYXNzIHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHQvL1xuXG5cdFx0Y29uc3Qgc2hhZGVyID0gT3V0cHV0U2hhZGVyO1xuXG5cdFx0dGhpcy51bmlmb3JtcyA9IFVuaWZvcm1zVXRpbHMuY2xvbmUoIHNoYWRlci51bmlmb3JtcyApO1xuXG5cdFx0dGhpcy5tYXRlcmlhbCA9IG5ldyBSYXdTaGFkZXJNYXRlcmlhbCgge1xuXHRcdFx0bmFtZTogc2hhZGVyLm5hbWUsXG5cdFx0XHR1bmlmb3JtczogdGhpcy51bmlmb3Jtcyxcblx0XHRcdHZlcnRleFNoYWRlcjogc2hhZGVyLnZlcnRleFNoYWRlcixcblx0XHRcdGZyYWdtZW50U2hhZGVyOiBzaGFkZXIuZnJhZ21lbnRTaGFkZXJcblx0XHR9ICk7XG5cblx0XHR0aGlzLmZzUXVhZCA9IG5ldyBGdWxsU2NyZWVuUXVhZCggdGhpcy5tYXRlcmlhbCApO1xuXG5cdFx0Ly8gaW50ZXJuYWwgY2FjaGVcblxuXHRcdHRoaXMuX291dHB1dENvbG9yU3BhY2UgPSBudWxsO1xuXHRcdHRoaXMuX3RvbmVNYXBwaW5nID0gbnVsbDtcblxuXHR9XG5cblx0cmVuZGVyKCByZW5kZXJlciwgd3JpdGVCdWZmZXIsIHJlYWRCdWZmZXIvKiwgZGVsdGFUaW1lLCBtYXNrQWN0aXZlICovICkge1xuXG5cdFx0dGhpcy51bmlmb3Jtc1sgJ3REaWZmdXNlJyBdLnZhbHVlID0gcmVhZEJ1ZmZlci50ZXh0dXJlO1xuXHRcdHRoaXMudW5pZm9ybXNbICd0b25lTWFwcGluZ0V4cG9zdXJlJyBdLnZhbHVlID0gcmVuZGVyZXIudG9uZU1hcHBpbmdFeHBvc3VyZTtcblxuXHRcdC8vIHJlYnVpbGQgZGVmaW5lcyBpZiByZXF1aXJlZFxuXG5cdFx0aWYgKCB0aGlzLl9vdXRwdXRDb2xvclNwYWNlICE9PSByZW5kZXJlci5vdXRwdXRDb2xvclNwYWNlIHx8IHRoaXMuX3RvbmVNYXBwaW5nICE9PSByZW5kZXJlci50b25lTWFwcGluZyApIHtcblxuXHRcdFx0dGhpcy5fb3V0cHV0Q29sb3JTcGFjZSA9IHJlbmRlcmVyLm91dHB1dENvbG9yU3BhY2U7XG5cdFx0XHR0aGlzLl90b25lTWFwcGluZyA9IHJlbmRlcmVyLnRvbmVNYXBwaW5nO1xuXG5cdFx0XHR0aGlzLm1hdGVyaWFsLmRlZmluZXMgPSB7fTtcblxuXHRcdFx0aWYgKCBDb2xvck1hbmFnZW1lbnQuZ2V0VHJhbnNmZXIoIHRoaXMuX291dHB1dENvbG9yU3BhY2UgKSA9PT0gU1JHQlRyYW5zZmVyICkgdGhpcy5tYXRlcmlhbC5kZWZpbmVzLlNSR0JfVFJBTlNGRVIgPSAnJztcblxuXHRcdFx0aWYgKCB0aGlzLl90b25lTWFwcGluZyA9PT0gTGluZWFyVG9uZU1hcHBpbmcgKSB0aGlzLm1hdGVyaWFsLmRlZmluZXMuTElORUFSX1RPTkVfTUFQUElORyA9ICcnO1xuXHRcdFx0ZWxzZSBpZiAoIHRoaXMuX3RvbmVNYXBwaW5nID09PSBSZWluaGFyZFRvbmVNYXBwaW5nICkgdGhpcy5tYXRlcmlhbC5kZWZpbmVzLlJFSU5IQVJEX1RPTkVfTUFQUElORyA9ICcnO1xuXHRcdFx0ZWxzZSBpZiAoIHRoaXMuX3RvbmVNYXBwaW5nID09PSBDaW5lb25Ub25lTWFwcGluZyApIHRoaXMubWF0ZXJpYWwuZGVmaW5lcy5DSU5FT05fVE9ORV9NQVBQSU5HID0gJyc7XG5cdFx0XHRlbHNlIGlmICggdGhpcy5fdG9uZU1hcHBpbmcgPT09IEFDRVNGaWxtaWNUb25lTWFwcGluZyApIHRoaXMubWF0ZXJpYWwuZGVmaW5lcy5BQ0VTX0ZJTE1JQ19UT05FX01BUFBJTkcgPSAnJztcblx0XHRcdGVsc2UgaWYgKCB0aGlzLl90b25lTWFwcGluZyA9PT0gQWdYVG9uZU1hcHBpbmcgKSB0aGlzLm1hdGVyaWFsLmRlZmluZXMuQUdYX1RPTkVfTUFQUElORyA9ICcnO1xuXHRcdFx0ZWxzZSBpZiAoIHRoaXMuX3RvbmVNYXBwaW5nID09PSBOZXV0cmFsVG9uZU1hcHBpbmcgKSB0aGlzLm1hdGVyaWFsLmRlZmluZXMuTkVVVFJBTF9UT05FX01BUFBJTkcgPSAnJztcblxuXHRcdFx0dGhpcy5tYXRlcmlhbC5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR9XG5cblx0XHQvL1xuXG5cdFx0aWYgKCB0aGlzLnJlbmRlclRvU2NyZWVuID09PSB0cnVlICkge1xuXG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIG51bGwgKTtcblx0XHRcdHRoaXMuZnNRdWFkLnJlbmRlciggcmVuZGVyZXIgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggd3JpdGVCdWZmZXIgKTtcblx0XHRcdGlmICggdGhpcy5jbGVhciApIHJlbmRlcmVyLmNsZWFyKCByZW5kZXJlci5hdXRvQ2xlYXJDb2xvciwgcmVuZGVyZXIuYXV0b0NsZWFyRGVwdGgsIHJlbmRlcmVyLmF1dG9DbGVhclN0ZW5jaWwgKTtcblx0XHRcdHRoaXMuZnNRdWFkLnJlbmRlciggcmVuZGVyZXIgKTtcblxuXHRcdH1cblxuXHR9XG5cblx0ZGlzcG9zZSgpIHtcblxuXHRcdHRoaXMubWF0ZXJpYWwuZGlzcG9zZSgpO1xuXHRcdHRoaXMuZnNRdWFkLmRpc3Bvc2UoKTtcblxuXHR9XG5cbn1cblxuZXhwb3J0IHsgT3V0cHV0UGFzcyB9O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///296\n")},844:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ F: () => (/* binding */ FullScreenQuad),\n/* harmony export */ o: () => (/* binding */ Pass)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(753);\n\n\nclass Pass {\n\n\tconstructor() {\n\n\t\tthis.isPass = true;\n\n\t\t// if set to true, the pass is processed by the composer\n\t\tthis.enabled = true;\n\n\t\t// if set to true, the pass indicates to swap read and write buffer after rendering\n\t\tthis.needsSwap = true;\n\n\t\t// if set to true, the pass clears its buffer before rendering\n\t\tthis.clear = false;\n\n\t\t// if set to true, the result of the pass is rendered to screen. This is set automatically by EffectComposer.\n\t\tthis.renderToScreen = false;\n\n\t}\n\n\tsetSize( /* width, height */ ) {}\n\n\trender( /* renderer, writeBuffer, readBuffer, deltaTime, maskActive */ ) {\n\n\t\tconsole.error( 'THREE.Pass: .render() must be implemented in derived pass.' );\n\n\t}\n\n\tdispose() {}\n\n}\n\n// Helper for passes that need to fill the viewport with a single quad.\n\nconst _camera = new three__WEBPACK_IMPORTED_MODULE_0__/* .OrthographicCamera */ .qUd( - 1, 1, 1, - 1, 0, 1 );\n\n// https://github.com/mrdoob/three.js/pull/21358\n\nclass FullscreenTriangleGeometry extends three__WEBPACK_IMPORTED_MODULE_0__/* .BufferGeometry */ .LoY {\n\n\tconstructor() {\n\n\t\tsuper();\n\n\t\tthis.setAttribute( 'position', new three__WEBPACK_IMPORTED_MODULE_0__/* .Float32BufferAttribute */ .qtW( [ - 1, 3, 0, - 1, - 1, 0, 3, - 1, 0 ], 3 ) );\n\t\tthis.setAttribute( 'uv', new three__WEBPACK_IMPORTED_MODULE_0__/* .Float32BufferAttribute */ .qtW( [ 0, 2, 0, 0, 2, 0 ], 2 ) );\n\n\t}\n\n}\n\nconst _geometry = new FullscreenTriangleGeometry();\n\nclass FullScreenQuad {\n\n\tconstructor( material ) {\n\n\t\tthis._mesh = new three__WEBPACK_IMPORTED_MODULE_0__/* .Mesh */ .eaF( _geometry, material );\n\n\t}\n\n\tdispose() {\n\n\t\tthis._mesh.geometry.dispose();\n\n\t}\n\n\trender( renderer ) {\n\n\t\trenderer.render( this._mesh, _camera );\n\n\t}\n\n\tget material() {\n\n\t\treturn this._mesh.material;\n\n\t}\n\n\tset material( value ) {\n\n\t\tthis._mesh.material = value;\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiODQ0LmpzIiwibWFwcGluZ3MiOiI7Ozs7O0FBS2U7O0FBRWY7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxvQkFBb0IsZ0VBQWtCOztBQUV0Qzs7QUFFQSx5Q0FBeUMsNERBQWM7O0FBRXZEOztBQUVBOztBQUVBLHFDQUFxQyxvRUFBc0I7QUFDM0QsK0JBQStCLG9FQUFzQjs7QUFFckQ7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGtEQUFJOztBQUV2Qjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFZ0MiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9wb3N0cHJvY2Vzc2luZy9QYXNzLmpzP2FlMWYiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0QnVmZmVyR2VvbWV0cnksXG5cdEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUsXG5cdE9ydGhvZ3JhcGhpY0NhbWVyYSxcblx0TWVzaFxufSBmcm9tICd0aHJlZSc7XG5cbmNsYXNzIFBhc3Mge1xuXG5cdGNvbnN0cnVjdG9yKCkge1xuXG5cdFx0dGhpcy5pc1Bhc3MgPSB0cnVlO1xuXG5cdFx0Ly8gaWYgc2V0IHRvIHRydWUsIHRoZSBwYXNzIGlzIHByb2Nlc3NlZCBieSB0aGUgY29tcG9zZXJcblx0XHR0aGlzLmVuYWJsZWQgPSB0cnVlO1xuXG5cdFx0Ly8gaWYgc2V0IHRvIHRydWUsIHRoZSBwYXNzIGluZGljYXRlcyB0byBzd2FwIHJlYWQgYW5kIHdyaXRlIGJ1ZmZlciBhZnRlciByZW5kZXJpbmdcblx0XHR0aGlzLm5lZWRzU3dhcCA9IHRydWU7XG5cblx0XHQvLyBpZiBzZXQgdG8gdHJ1ZSwgdGhlIHBhc3MgY2xlYXJzIGl0cyBidWZmZXIgYmVmb3JlIHJlbmRlcmluZ1xuXHRcdHRoaXMuY2xlYXIgPSBmYWxzZTtcblxuXHRcdC8vIGlmIHNldCB0byB0cnVlLCB0aGUgcmVzdWx0IG9mIHRoZSBwYXNzIGlzIHJlbmRlcmVkIHRvIHNjcmVlbi4gVGhpcyBpcyBzZXQgYXV0b21hdGljYWxseSBieSBFZmZlY3RDb21wb3Nlci5cblx0XHR0aGlzLnJlbmRlclRvU2NyZWVuID0gZmFsc2U7XG5cblx0fVxuXG5cdHNldFNpemUoIC8qIHdpZHRoLCBoZWlnaHQgKi8gKSB7fVxuXG5cdHJlbmRlciggLyogcmVuZGVyZXIsIHdyaXRlQnVmZmVyLCByZWFkQnVmZmVyLCBkZWx0YVRpbWUsIG1hc2tBY3RpdmUgKi8gKSB7XG5cblx0XHRjb25zb2xlLmVycm9yKCAnVEhSRUUuUGFzczogLnJlbmRlcigpIG11c3QgYmUgaW1wbGVtZW50ZWQgaW4gZGVyaXZlZCBwYXNzLicgKTtcblxuXHR9XG5cblx0ZGlzcG9zZSgpIHt9XG5cbn1cblxuLy8gSGVscGVyIGZvciBwYXNzZXMgdGhhdCBuZWVkIHRvIGZpbGwgdGhlIHZpZXdwb3J0IHdpdGggYSBzaW5nbGUgcXVhZC5cblxuY29uc3QgX2NhbWVyYSA9IG5ldyBPcnRob2dyYXBoaWNDYW1lcmEoIC0gMSwgMSwgMSwgLSAxLCAwLCAxICk7XG5cbi8vIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvcHVsbC8yMTM1OFxuXG5jbGFzcyBGdWxsc2NyZWVuVHJpYW5nbGVHZW9tZXRyeSBleHRlbmRzIEJ1ZmZlckdlb21ldHJ5IHtcblxuXHRjb25zdHJ1Y3RvcigpIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnNldEF0dHJpYnV0ZSggJ3Bvc2l0aW9uJywgbmV3IEZsb2F0MzJCdWZmZXJBdHRyaWJ1dGUoIFsgLSAxLCAzLCAwLCAtIDEsIC0gMSwgMCwgMywgLSAxLCAwIF0sIDMgKSApO1xuXHRcdHRoaXMuc2V0QXR0cmlidXRlKCAndXYnLCBuZXcgRmxvYXQzMkJ1ZmZlckF0dHJpYnV0ZSggWyAwLCAyLCAwLCAwLCAyLCAwIF0sIDIgKSApO1xuXG5cdH1cblxufVxuXG5jb25zdCBfZ2VvbWV0cnkgPSBuZXcgRnVsbHNjcmVlblRyaWFuZ2xlR2VvbWV0cnkoKTtcblxuY2xhc3MgRnVsbFNjcmVlblF1YWQge1xuXG5cdGNvbnN0cnVjdG9yKCBtYXRlcmlhbCApIHtcblxuXHRcdHRoaXMuX21lc2ggPSBuZXcgTWVzaCggX2dlb21ldHJ5LCBtYXRlcmlhbCApO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5fbWVzaC5nZW9tZXRyeS5kaXNwb3NlKCk7XG5cblx0fVxuXG5cdHJlbmRlciggcmVuZGVyZXIgKSB7XG5cblx0XHRyZW5kZXJlci5yZW5kZXIoIHRoaXMuX21lc2gsIF9jYW1lcmEgKTtcblxuXHR9XG5cblx0Z2V0IG1hdGVyaWFsKCkge1xuXG5cdFx0cmV0dXJuIHRoaXMuX21lc2gubWF0ZXJpYWw7XG5cblx0fVxuXG5cdHNldCBtYXRlcmlhbCggdmFsdWUgKSB7XG5cblx0XHR0aGlzLl9tZXNoLm1hdGVyaWFsID0gdmFsdWU7XG5cblx0fVxuXG59XG5cbmV4cG9ydCB7IFBhc3MsIEZ1bGxTY3JlZW5RdWFkIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///844\n")},968:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ A: () => (/* binding */ RenderPass)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(753);\n/* harmony import */ var _Pass_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(844);\n\n\n\nclass RenderPass extends _Pass_js__WEBPACK_IMPORTED_MODULE_0__/* .Pass */ .o {\n\n\tconstructor( scene, camera, overrideMaterial = null, clearColor = null, clearAlpha = null ) {\n\n\t\tsuper();\n\n\t\tthis.scene = scene;\n\t\tthis.camera = camera;\n\n\t\tthis.overrideMaterial = overrideMaterial;\n\n\t\tthis.clearColor = clearColor;\n\t\tthis.clearAlpha = clearAlpha;\n\n\t\tthis.clear = true;\n\t\tthis.clearDepth = false;\n\t\tthis.needsSwap = false;\n\t\tthis._oldClearColor = new three__WEBPACK_IMPORTED_MODULE_1__/* .Color */ .Q1f();\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {\n\n\t\tconst oldAutoClear = renderer.autoClear;\n\t\trenderer.autoClear = false;\n\n\t\tlet oldClearAlpha, oldOverrideMaterial;\n\n\t\tif ( this.overrideMaterial !== null ) {\n\n\t\t\toldOverrideMaterial = this.scene.overrideMaterial;\n\n\t\t\tthis.scene.overrideMaterial = this.overrideMaterial;\n\n\t\t}\n\n\t\tif ( this.clearColor !== null ) {\n\n\t\t\trenderer.getClearColor( this._oldClearColor );\n\t\t\trenderer.setClearColor( this.clearColor, renderer.getClearAlpha() );\n\n\t\t}\n\n\t\tif ( this.clearAlpha !== null ) {\n\n\t\t\toldClearAlpha = renderer.getClearAlpha();\n\t\t\trenderer.setClearAlpha( this.clearAlpha );\n\n\t\t}\n\n\t\tif ( this.clearDepth == true ) {\n\n\t\t\trenderer.clearDepth();\n\n\t\t}\n\n\t\trenderer.setRenderTarget( this.renderToScreen ? null : readBuffer );\n\n\t\tif ( this.clear === true ) {\n\n\t\t\t// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600\n\t\t\trenderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );\n\n\t\t}\n\n\t\trenderer.render( this.scene, this.camera );\n\n\t\t// restore\n\n\t\tif ( this.clearColor !== null ) {\n\n\t\t\trenderer.setClearColor( this._oldClearColor );\n\n\t\t}\n\n\t\tif ( this.clearAlpha !== null ) {\n\n\t\t\trenderer.setClearAlpha( oldClearAlpha );\n\n\t\t}\n\n\t\tif ( this.overrideMaterial !== null ) {\n\n\t\t\tthis.scene.overrideMaterial = oldOverrideMaterial;\n\n\t\t}\n\n\t\trenderer.autoClear = oldAutoClear;\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiOTY4LmpzIiwibWFwcGluZ3MiOiI7Ozs7O0FBRWU7QUFDa0I7O0FBRWpDLHlCQUF5QixtREFBSTs7QUFFN0I7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDRCQUE0QixtREFBSzs7QUFFakM7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFc0IiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9wb3N0cHJvY2Vzc2luZy9SZW5kZXJQYXNzLmpzPzZjNDIiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0Q29sb3Jcbn0gZnJvbSAndGhyZWUnO1xuaW1wb3J0IHsgUGFzcyB9IGZyb20gJy4vUGFzcy5qcyc7XG5cbmNsYXNzIFJlbmRlclBhc3MgZXh0ZW5kcyBQYXNzIHtcblxuXHRjb25zdHJ1Y3Rvciggc2NlbmUsIGNhbWVyYSwgb3ZlcnJpZGVNYXRlcmlhbCA9IG51bGwsIGNsZWFyQ29sb3IgPSBudWxsLCBjbGVhckFscGhhID0gbnVsbCApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnNjZW5lID0gc2NlbmU7XG5cdFx0dGhpcy5jYW1lcmEgPSBjYW1lcmE7XG5cblx0XHR0aGlzLm92ZXJyaWRlTWF0ZXJpYWwgPSBvdmVycmlkZU1hdGVyaWFsO1xuXG5cdFx0dGhpcy5jbGVhckNvbG9yID0gY2xlYXJDb2xvcjtcblx0XHR0aGlzLmNsZWFyQWxwaGEgPSBjbGVhckFscGhhO1xuXG5cdFx0dGhpcy5jbGVhciA9IHRydWU7XG5cdFx0dGhpcy5jbGVhckRlcHRoID0gZmFsc2U7XG5cdFx0dGhpcy5uZWVkc1N3YXAgPSBmYWxzZTtcblx0XHR0aGlzLl9vbGRDbGVhckNvbG9yID0gbmV3IENvbG9yKCk7XG5cblx0fVxuXG5cdHJlbmRlciggcmVuZGVyZXIsIHdyaXRlQnVmZmVyLCByZWFkQnVmZmVyIC8qLCBkZWx0YVRpbWUsIG1hc2tBY3RpdmUgKi8gKSB7XG5cblx0XHRjb25zdCBvbGRBdXRvQ2xlYXIgPSByZW5kZXJlci5hdXRvQ2xlYXI7XG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gZmFsc2U7XG5cblx0XHRsZXQgb2xkQ2xlYXJBbHBoYSwgb2xkT3ZlcnJpZGVNYXRlcmlhbDtcblxuXHRcdGlmICggdGhpcy5vdmVycmlkZU1hdGVyaWFsICE9PSBudWxsICkge1xuXG5cdFx0XHRvbGRPdmVycmlkZU1hdGVyaWFsID0gdGhpcy5zY2VuZS5vdmVycmlkZU1hdGVyaWFsO1xuXG5cdFx0XHR0aGlzLnNjZW5lLm92ZXJyaWRlTWF0ZXJpYWwgPSB0aGlzLm92ZXJyaWRlTWF0ZXJpYWw7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuY2xlYXJDb2xvciAhPT0gbnVsbCApIHtcblxuXHRcdFx0cmVuZGVyZXIuZ2V0Q2xlYXJDb2xvciggdGhpcy5fb2xkQ2xlYXJDb2xvciApO1xuXHRcdFx0cmVuZGVyZXIuc2V0Q2xlYXJDb2xvciggdGhpcy5jbGVhckNvbG9yLCByZW5kZXJlci5nZXRDbGVhckFscGhhKCkgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5jbGVhckFscGhhICE9PSBudWxsICkge1xuXG5cdFx0XHRvbGRDbGVhckFscGhhID0gcmVuZGVyZXIuZ2V0Q2xlYXJBbHBoYSgpO1xuXHRcdFx0cmVuZGVyZXIuc2V0Q2xlYXJBbHBoYSggdGhpcy5jbGVhckFscGhhICk7XG5cblx0XHR9XG5cblx0XHRpZiAoIHRoaXMuY2xlYXJEZXB0aCA9PSB0cnVlICkge1xuXG5cdFx0XHRyZW5kZXJlci5jbGVhckRlcHRoKCk7XG5cblx0XHR9XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHRoaXMucmVuZGVyVG9TY3JlZW4gPyBudWxsIDogcmVhZEJ1ZmZlciApO1xuXG5cdFx0aWYgKCB0aGlzLmNsZWFyID09PSB0cnVlICkge1xuXG5cdFx0XHQvLyBUT0RPOiBBdm9pZCB1c2luZyBhdXRvQ2xlYXIgcHJvcGVydGllcywgc2VlIGh0dHBzOi8vZ2l0aHViLmNvbS9tcmRvb2IvdGhyZWUuanMvcHVsbC8xNTU3MSNpc3N1ZWNvbW1lbnQtNDY1NjY5NjAwXG5cdFx0XHRyZW5kZXJlci5jbGVhciggcmVuZGVyZXIuYXV0b0NsZWFyQ29sb3IsIHJlbmRlcmVyLmF1dG9DbGVhckRlcHRoLCByZW5kZXJlci5hdXRvQ2xlYXJTdGVuY2lsICk7XG5cblx0XHR9XG5cblx0XHRyZW5kZXJlci5yZW5kZXIoIHRoaXMuc2NlbmUsIHRoaXMuY2FtZXJhICk7XG5cblx0XHQvLyByZXN0b3JlXG5cblx0XHRpZiAoIHRoaXMuY2xlYXJDb2xvciAhPT0gbnVsbCApIHtcblxuXHRcdFx0cmVuZGVyZXIuc2V0Q2xlYXJDb2xvciggdGhpcy5fb2xkQ2xlYXJDb2xvciApO1xuXG5cdFx0fVxuXG5cdFx0aWYgKCB0aGlzLmNsZWFyQWxwaGEgIT09IG51bGwgKSB7XG5cblx0XHRcdHJlbmRlcmVyLnNldENsZWFyQWxwaGEoIG9sZENsZWFyQWxwaGEgKTtcblxuXHRcdH1cblxuXHRcdGlmICggdGhpcy5vdmVycmlkZU1hdGVyaWFsICE9PSBudWxsICkge1xuXG5cdFx0XHR0aGlzLnNjZW5lLm92ZXJyaWRlTWF0ZXJpYWwgPSBvbGRPdmVycmlkZU1hdGVyaWFsO1xuXG5cdFx0fVxuXG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gb2xkQXV0b0NsZWFyO1xuXG5cdH1cblxufVxuXG5leHBvcnQgeyBSZW5kZXJQYXNzIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///968\n")},737:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n I: () => (/* binding */ SMAAPass)\n});\n\n// EXTERNAL MODULE: ./node_modules/three/build/three.module.js\nvar three_module = __webpack_require__(753);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/postprocessing/Pass.js\nvar Pass = __webpack_require__(844);\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/shaders/SMAAShader.js\n\n\n/**\n * WebGL port of Subpixel Morphological Antialiasing (SMAA) v2.8\n * Preset: SMAA 1x Medium (with color edge detection)\n * https://github.com/iryoku/smaa/releases/tag/v2.8\n */\n\nconst SMAAEdgesShader = {\n\n\tname: 'SMAAEdgesShader',\n\n\tdefines: {\n\n\t\t'SMAA_THRESHOLD': '0.1'\n\n\t},\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'resolution': { value: new three_module/* Vector2 */.I9Y( 1 / 1024, 1 / 512 ) }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[ 3 ];\n\n\t\tvoid SMAAEdgeDetectionVS( vec2 texcoord ) {\n\t\t\tvOffset[ 0 ] = texcoord.xyxy + resolution.xyxy * vec4( -1.0, 0.0, 0.0, 1.0 ); // WebGL port note: Changed sign in W component\n\t\t\tvOffset[ 1 ] = texcoord.xyxy + resolution.xyxy * vec4( 1.0, 0.0, 0.0, -1.0 ); // WebGL port note: Changed sign in W component\n\t\t\tvOffset[ 2 ] = texcoord.xyxy + resolution.xyxy * vec4( -2.0, 0.0, 0.0, 2.0 ); // WebGL port note: Changed sign in W component\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\n\t\t\tSMAAEdgeDetectionVS( vUv );\n\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\n\t\tuniform sampler2D tDiffuse;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[ 3 ];\n\n\t\tvec4 SMAAColorEdgeDetectionPS( vec2 texcoord, vec4 offset[3], sampler2D colorTex ) {\n\t\t\tvec2 threshold = vec2( SMAA_THRESHOLD, SMAA_THRESHOLD );\n\n\t\t\t// Calculate color deltas:\n\t\t\tvec4 delta;\n\t\t\tvec3 C = texture2D( colorTex, texcoord ).rgb;\n\n\t\t\tvec3 Cleft = texture2D( colorTex, offset[0].xy ).rgb;\n\t\t\tvec3 t = abs( C - Cleft );\n\t\t\tdelta.x = max( max( t.r, t.g ), t.b );\n\n\t\t\tvec3 Ctop = texture2D( colorTex, offset[0].zw ).rgb;\n\t\t\tt = abs( C - Ctop );\n\t\t\tdelta.y = max( max( t.r, t.g ), t.b );\n\n\t\t\t// We do the usual threshold:\n\t\t\tvec2 edges = step( threshold, delta.xy );\n\n\t\t\t// Then discard if there is no edge:\n\t\t\tif ( dot( edges, vec2( 1.0, 1.0 ) ) == 0.0 )\n\t\t\t\tdiscard;\n\n\t\t\t// Calculate right and bottom deltas:\n\t\t\tvec3 Cright = texture2D( colorTex, offset[1].xy ).rgb;\n\t\t\tt = abs( C - Cright );\n\t\t\tdelta.z = max( max( t.r, t.g ), t.b );\n\n\t\t\tvec3 Cbottom = texture2D( colorTex, offset[1].zw ).rgb;\n\t\t\tt = abs( C - Cbottom );\n\t\t\tdelta.w = max( max( t.r, t.g ), t.b );\n\n\t\t\t// Calculate the maximum delta in the direct neighborhood:\n\t\t\tfloat maxDelta = max( max( max( delta.x, delta.y ), delta.z ), delta.w );\n\n\t\t\t// Calculate left-left and top-top deltas:\n\t\t\tvec3 Cleftleft = texture2D( colorTex, offset[2].xy ).rgb;\n\t\t\tt = abs( C - Cleftleft );\n\t\t\tdelta.z = max( max( t.r, t.g ), t.b );\n\n\t\t\tvec3 Ctoptop = texture2D( colorTex, offset[2].zw ).rgb;\n\t\t\tt = abs( C - Ctoptop );\n\t\t\tdelta.w = max( max( t.r, t.g ), t.b );\n\n\t\t\t// Calculate the final maximum delta:\n\t\t\tmaxDelta = max( max( maxDelta, delta.z ), delta.w );\n\n\t\t\t// Local contrast adaptation in action:\n\t\t\tedges.xy *= step( 0.5 * maxDelta, delta.xy );\n\n\t\t\treturn vec4( edges, 0.0, 0.0 );\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tgl_FragColor = SMAAColorEdgeDetectionPS( vUv, vOffset, tDiffuse );\n\n\t\t}`\n\n};\n\nconst SMAAWeightsShader = {\n\n\tname: 'SMAAWeightsShader',\n\n\tdefines: {\n\n\t\t'SMAA_MAX_SEARCH_STEPS': '8',\n\t\t'SMAA_AREATEX_MAX_DISTANCE': '16',\n\t\t'SMAA_AREATEX_PIXEL_SIZE': '( 1.0 / vec2( 160.0, 560.0 ) )',\n\t\t'SMAA_AREATEX_SUBTEX_SIZE': '( 1.0 / 7.0 )'\n\n\t},\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'tArea': { value: null },\n\t\t'tSearch': { value: null },\n\t\t'resolution': { value: new three_module/* Vector2 */.I9Y( 1 / 1024, 1 / 512 ) }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[ 3 ];\n\t\tvarying vec2 vPixcoord;\n\n\t\tvoid SMAABlendingWeightCalculationVS( vec2 texcoord ) {\n\t\t\tvPixcoord = texcoord / resolution;\n\n\t\t\t// We will use these offsets for the searches later on (see @PSEUDO_GATHER4):\n\t\t\tvOffset[ 0 ] = texcoord.xyxy + resolution.xyxy * vec4( -0.25, 0.125, 1.25, 0.125 ); // WebGL port note: Changed sign in Y and W components\n\t\t\tvOffset[ 1 ] = texcoord.xyxy + resolution.xyxy * vec4( -0.125, 0.25, -0.125, -1.25 ); // WebGL port note: Changed sign in Y and W components\n\n\t\t\t// And these for the searches, they indicate the ends of the loops:\n\t\t\tvOffset[ 2 ] = vec4( vOffset[ 0 ].xz, vOffset[ 1 ].yw ) + vec4( -2.0, 2.0, -2.0, 2.0 ) * resolution.xxyy * float( SMAA_MAX_SEARCH_STEPS );\n\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\n\t\t\tSMAABlendingWeightCalculationVS( vUv );\n\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\n\t\t#define SMAASampleLevelZeroOffset( tex, coord, offset ) texture2D( tex, coord + float( offset ) * resolution, 0.0 )\n\n\t\tuniform sampler2D tDiffuse;\n\t\tuniform sampler2D tArea;\n\t\tuniform sampler2D tSearch;\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[3];\n\t\tvarying vec2 vPixcoord;\n\n\t\t#if __VERSION__ == 100\n\t\tvec2 round( vec2 x ) {\n\t\t\treturn sign( x ) * floor( abs( x ) + 0.5 );\n\t\t}\n\t\t#endif\n\n\t\tfloat SMAASearchLength( sampler2D searchTex, vec2 e, float bias, float scale ) {\n\t\t\t// Not required if searchTex accesses are set to point:\n\t\t\t// float2 SEARCH_TEX_PIXEL_SIZE = 1.0 / float2(66.0, 33.0);\n\t\t\t// e = float2(bias, 0.0) + 0.5 * SEARCH_TEX_PIXEL_SIZE +\n\t\t\t// e * float2(scale, 1.0) * float2(64.0, 32.0) * SEARCH_TEX_PIXEL_SIZE;\n\t\t\te.r = bias + e.r * scale;\n\t\t\treturn 255.0 * texture2D( searchTex, e, 0.0 ).r;\n\t\t}\n\n\t\tfloat SMAASearchXLeft( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {\n\t\t\t/**\n\t\t\t\t* @PSEUDO_GATHER4\n\t\t\t\t* This texcoord has been offset by (-0.25, -0.125) in the vertex shader to\n\t\t\t\t* sample between edge, thus fetching four edges in a row.\n\t\t\t\t* Sampling with different offsets in each direction allows to disambiguate\n\t\t\t\t* which edges are active from the four fetched ones.\n\t\t\t\t*/\n\t\t\tvec2 e = vec2( 0.0, 1.0 );\n\n\t\t\tfor ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for\n\t\t\t\te = texture2D( edgesTex, texcoord, 0.0 ).rg;\n\t\t\t\ttexcoord -= vec2( 2.0, 0.0 ) * resolution;\n\t\t\t\tif ( ! ( texcoord.x > end && e.g > 0.8281 && e.r == 0.0 ) ) break;\n\t\t\t}\n\n\t\t\t// We correct the previous (-0.25, -0.125) offset we applied:\n\t\t\ttexcoord.x += 0.25 * resolution.x;\n\n\t\t\t// The searches are bias by 1, so adjust the coords accordingly:\n\t\t\ttexcoord.x += resolution.x;\n\n\t\t\t// Disambiguate the length added by the last step:\n\t\t\ttexcoord.x += 2.0 * resolution.x; // Undo last step\n\t\t\ttexcoord.x -= resolution.x * SMAASearchLength(searchTex, e, 0.0, 0.5);\n\n\t\t\treturn texcoord.x;\n\t\t}\n\n\t\tfloat SMAASearchXRight( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {\n\t\t\tvec2 e = vec2( 0.0, 1.0 );\n\n\t\t\tfor ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for\n\t\t\t\te = texture2D( edgesTex, texcoord, 0.0 ).rg;\n\t\t\t\ttexcoord += vec2( 2.0, 0.0 ) * resolution;\n\t\t\t\tif ( ! ( texcoord.x < end && e.g > 0.8281 && e.r == 0.0 ) ) break;\n\t\t\t}\n\n\t\t\ttexcoord.x -= 0.25 * resolution.x;\n\t\t\ttexcoord.x -= resolution.x;\n\t\t\ttexcoord.x -= 2.0 * resolution.x;\n\t\t\ttexcoord.x += resolution.x * SMAASearchLength( searchTex, e, 0.5, 0.5 );\n\n\t\t\treturn texcoord.x;\n\t\t}\n\n\t\tfloat SMAASearchYUp( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {\n\t\t\tvec2 e = vec2( 1.0, 0.0 );\n\n\t\t\tfor ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for\n\t\t\t\te = texture2D( edgesTex, texcoord, 0.0 ).rg;\n\t\t\t\ttexcoord += vec2( 0.0, 2.0 ) * resolution; // WebGL port note: Changed sign\n\t\t\t\tif ( ! ( texcoord.y > end && e.r > 0.8281 && e.g == 0.0 ) ) break;\n\t\t\t}\n\n\t\t\ttexcoord.y -= 0.25 * resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y -= resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y -= 2.0 * resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y += resolution.y * SMAASearchLength( searchTex, e.gr, 0.0, 0.5 ); // WebGL port note: Changed sign\n\n\t\t\treturn texcoord.y;\n\t\t}\n\n\t\tfloat SMAASearchYDown( sampler2D edgesTex, sampler2D searchTex, vec2 texcoord, float end ) {\n\t\t\tvec2 e = vec2( 1.0, 0.0 );\n\n\t\t\tfor ( int i = 0; i < SMAA_MAX_SEARCH_STEPS; i ++ ) { // WebGL port note: Changed while to for\n\t\t\t\te = texture2D( edgesTex, texcoord, 0.0 ).rg;\n\t\t\t\ttexcoord -= vec2( 0.0, 2.0 ) * resolution; // WebGL port note: Changed sign\n\t\t\t\tif ( ! ( texcoord.y < end && e.r > 0.8281 && e.g == 0.0 ) ) break;\n\t\t\t}\n\n\t\t\ttexcoord.y += 0.25 * resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y += resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y += 2.0 * resolution.y; // WebGL port note: Changed sign\n\t\t\ttexcoord.y -= resolution.y * SMAASearchLength( searchTex, e.gr, 0.5, 0.5 ); // WebGL port note: Changed sign\n\n\t\t\treturn texcoord.y;\n\t\t}\n\n\t\tvec2 SMAAArea( sampler2D areaTex, vec2 dist, float e1, float e2, float offset ) {\n\t\t\t// Rounding prevents precision errors of bilinear filtering:\n\t\t\tvec2 texcoord = float( SMAA_AREATEX_MAX_DISTANCE ) * round( 4.0 * vec2( e1, e2 ) ) + dist;\n\n\t\t\t// We do a scale and bias for mapping to texel space:\n\t\t\ttexcoord = SMAA_AREATEX_PIXEL_SIZE * texcoord + ( 0.5 * SMAA_AREATEX_PIXEL_SIZE );\n\n\t\t\t// Move to proper place, according to the subpixel offset:\n\t\t\ttexcoord.y += SMAA_AREATEX_SUBTEX_SIZE * offset;\n\n\t\t\treturn texture2D( areaTex, texcoord, 0.0 ).rg;\n\t\t}\n\n\t\tvec4 SMAABlendingWeightCalculationPS( vec2 texcoord, vec2 pixcoord, vec4 offset[ 3 ], sampler2D edgesTex, sampler2D areaTex, sampler2D searchTex, ivec4 subsampleIndices ) {\n\t\t\tvec4 weights = vec4( 0.0, 0.0, 0.0, 0.0 );\n\n\t\t\tvec2 e = texture2D( edgesTex, texcoord ).rg;\n\n\t\t\tif ( e.g > 0.0 ) { // Edge at north\n\t\t\t\tvec2 d;\n\n\t\t\t\t// Find the distance to the left:\n\t\t\t\tvec2 coords;\n\t\t\t\tcoords.x = SMAASearchXLeft( edgesTex, searchTex, offset[ 0 ].xy, offset[ 2 ].x );\n\t\t\t\tcoords.y = offset[ 1 ].y; // offset[1].y = texcoord.y - 0.25 * resolution.y (@CROSSING_OFFSET)\n\t\t\t\td.x = coords.x;\n\n\t\t\t\t// Now fetch the left crossing edges, two at a time using bilinear\n\t\t\t\t// filtering. Sampling at -0.25 (see @CROSSING_OFFSET) enables to\n\t\t\t\t// discern what value each edge has:\n\t\t\t\tfloat e1 = texture2D( edgesTex, coords, 0.0 ).r;\n\n\t\t\t\t// Find the distance to the right:\n\t\t\t\tcoords.x = SMAASearchXRight( edgesTex, searchTex, offset[ 0 ].zw, offset[ 2 ].y );\n\t\t\t\td.y = coords.x;\n\n\t\t\t\t// We want the distances to be in pixel units (doing this here allow to\n\t\t\t\t// better interleave arithmetic and memory accesses):\n\t\t\t\td = d / resolution.x - pixcoord.x;\n\n\t\t\t\t// SMAAArea below needs a sqrt, as the areas texture is compressed\n\t\t\t\t// quadratically:\n\t\t\t\tvec2 sqrt_d = sqrt( abs( d ) );\n\n\t\t\t\t// Fetch the right crossing edges:\n\t\t\t\tcoords.y -= 1.0 * resolution.y; // WebGL port note: Added\n\t\t\t\tfloat e2 = SMAASampleLevelZeroOffset( edgesTex, coords, ivec2( 1, 0 ) ).r;\n\n\t\t\t\t// Ok, we know how this pattern looks like, now it is time for getting\n\t\t\t\t// the actual area:\n\t\t\t\tweights.rg = SMAAArea( areaTex, sqrt_d, e1, e2, float( subsampleIndices.y ) );\n\t\t\t}\n\n\t\t\tif ( e.r > 0.0 ) { // Edge at west\n\t\t\t\tvec2 d;\n\n\t\t\t\t// Find the distance to the top:\n\t\t\t\tvec2 coords;\n\n\t\t\t\tcoords.y = SMAASearchYUp( edgesTex, searchTex, offset[ 1 ].xy, offset[ 2 ].z );\n\t\t\t\tcoords.x = offset[ 0 ].x; // offset[1].x = texcoord.x - 0.25 * resolution.x;\n\t\t\t\td.x = coords.y;\n\n\t\t\t\t// Fetch the top crossing edges:\n\t\t\t\tfloat e1 = texture2D( edgesTex, coords, 0.0 ).g;\n\n\t\t\t\t// Find the distance to the bottom:\n\t\t\t\tcoords.y = SMAASearchYDown( edgesTex, searchTex, offset[ 1 ].zw, offset[ 2 ].w );\n\t\t\t\td.y = coords.y;\n\n\t\t\t\t// We want the distances to be in pixel units:\n\t\t\t\td = d / resolution.y - pixcoord.y;\n\n\t\t\t\t// SMAAArea below needs a sqrt, as the areas texture is compressed\n\t\t\t\t// quadratically:\n\t\t\t\tvec2 sqrt_d = sqrt( abs( d ) );\n\n\t\t\t\t// Fetch the bottom crossing edges:\n\t\t\t\tcoords.y -= 1.0 * resolution.y; // WebGL port note: Added\n\t\t\t\tfloat e2 = SMAASampleLevelZeroOffset( edgesTex, coords, ivec2( 0, 1 ) ).g;\n\n\t\t\t\t// Get the area for this direction:\n\t\t\t\tweights.ba = SMAAArea( areaTex, sqrt_d, e1, e2, float( subsampleIndices.x ) );\n\t\t\t}\n\n\t\t\treturn weights;\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tgl_FragColor = SMAABlendingWeightCalculationPS( vUv, vPixcoord, vOffset, tDiffuse, tArea, tSearch, ivec4( 0.0 ) );\n\n\t\t}`\n\n};\n\nconst SMAABlendShader = {\n\n\tname: 'SMAABlendShader',\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'tColor': { value: null },\n\t\t'resolution': { value: new three_module/* Vector2 */.I9Y( 1 / 1024, 1 / 512 ) }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[ 2 ];\n\n\t\tvoid SMAANeighborhoodBlendingVS( vec2 texcoord ) {\n\t\t\tvOffset[ 0 ] = texcoord.xyxy + resolution.xyxy * vec4( -1.0, 0.0, 0.0, 1.0 ); // WebGL port note: Changed sign in W component\n\t\t\tvOffset[ 1 ] = texcoord.xyxy + resolution.xyxy * vec4( 1.0, 0.0, 0.0, -1.0 ); // WebGL port note: Changed sign in W component\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\n\t\t\tSMAANeighborhoodBlendingVS( vUv );\n\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\n\t\tuniform sampler2D tDiffuse;\n\t\tuniform sampler2D tColor;\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\t\tvarying vec4 vOffset[ 2 ];\n\n\t\tvec4 SMAANeighborhoodBlendingPS( vec2 texcoord, vec4 offset[ 2 ], sampler2D colorTex, sampler2D blendTex ) {\n\t\t\t// Fetch the blending weights for current pixel:\n\t\t\tvec4 a;\n\t\t\ta.xz = texture2D( blendTex, texcoord ).xz;\n\t\t\ta.y = texture2D( blendTex, offset[ 1 ].zw ).g;\n\t\t\ta.w = texture2D( blendTex, offset[ 1 ].xy ).a;\n\n\t\t\t// Is there any blending weight with a value greater than 0.0?\n\t\t\tif ( dot(a, vec4( 1.0, 1.0, 1.0, 1.0 )) < 1e-5 ) {\n\t\t\t\treturn texture2D( colorTex, texcoord, 0.0 );\n\t\t\t} else {\n\t\t\t\t// Up to 4 lines can be crossing a pixel (one through each edge). We\n\t\t\t\t// favor blending by choosing the line with the maximum weight for each\n\t\t\t\t// direction:\n\t\t\t\tvec2 offset;\n\t\t\t\toffset.x = a.a > a.b ? a.a : -a.b; // left vs. right\n\t\t\t\toffset.y = a.g > a.r ? -a.g : a.r; // top vs. bottom // WebGL port note: Changed signs\n\n\t\t\t\t// Then we go in the direction that has the maximum weight:\n\t\t\t\tif ( abs( offset.x ) > abs( offset.y )) { // horizontal vs. vertical\n\t\t\t\t\toffset.y = 0.0;\n\t\t\t\t} else {\n\t\t\t\t\toffset.x = 0.0;\n\t\t\t\t}\n\n\t\t\t\t// Fetch the opposite color and lerp by hand:\n\t\t\t\tvec4 C = texture2D( colorTex, texcoord, 0.0 );\n\t\t\t\ttexcoord += sign( offset ) * resolution;\n\t\t\t\tvec4 Cop = texture2D( colorTex, texcoord, 0.0 );\n\t\t\t\tfloat s = abs( offset.x ) > abs( offset.y ) ? abs( offset.x ) : abs( offset.y );\n\n\t\t\t\t// WebGL port note: Added gamma correction\n\t\t\t\tC.xyz = pow(C.xyz, vec3(2.2));\n\t\t\t\tCop.xyz = pow(Cop.xyz, vec3(2.2));\n\t\t\t\tvec4 mixed = mix(C, Cop, s);\n\t\t\t\tmixed.xyz = pow(mixed.xyz, vec3(1.0 / 2.2));\n\n\t\t\t\treturn mixed;\n\t\t\t}\n\t\t}\n\n\t\tvoid main() {\n\n\t\t\tgl_FragColor = SMAANeighborhoodBlendingPS( vUv, vOffset, tColor, tDiffuse );\n\n\t\t}`\n\n};\n\n\n\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/postprocessing/SMAAPass.js\n\n\n\n\n\n\nclass SMAAPass extends Pass/* Pass */.o {\n\n\tconstructor( width, height ) {\n\n\t\tsuper();\n\n\t\t// render targets\n\n\t\tthis.edgesRT = new three_module/* WebGLRenderTarget */.nWS( width, height, {\n\t\t\tdepthBuffer: false,\n\t\t\ttype: three_module/* HalfFloatType */.ix0\n\t\t} );\n\t\tthis.edgesRT.texture.name = 'SMAAPass.edges';\n\n\t\tthis.weightsRT = new three_module/* WebGLRenderTarget */.nWS( width, height, {\n\t\t\tdepthBuffer: false,\n\t\t\ttype: three_module/* HalfFloatType */.ix0\n\t\t} );\n\t\tthis.weightsRT.texture.name = 'SMAAPass.weights';\n\n\t\t// textures\n\t\tconst scope = this;\n\n\t\tconst areaTextureImage = new Image();\n\t\tareaTextureImage.src = this.getAreaTexture();\n\t\tareaTextureImage.onload = function () {\n\n\t\t\t// assigning data to HTMLImageElement.src is asynchronous (see #15162)\n\t\t\tscope.areaTexture.needsUpdate = true;\n\n\t\t};\n\n\t\tthis.areaTexture = new three_module/* Texture */.gPd();\n\t\tthis.areaTexture.name = 'SMAAPass.area';\n\t\tthis.areaTexture.image = areaTextureImage;\n\t\tthis.areaTexture.minFilter = three_module/* LinearFilter */.k6q;\n\t\tthis.areaTexture.generateMipmaps = false;\n\t\tthis.areaTexture.flipY = false;\n\n\t\tconst searchTextureImage = new Image();\n\t\tsearchTextureImage.src = this.getSearchTexture();\n\t\tsearchTextureImage.onload = function () {\n\n\t\t\t// assigning data to HTMLImageElement.src is asynchronous (see #15162)\n\t\t\tscope.searchTexture.needsUpdate = true;\n\n\t\t};\n\n\t\tthis.searchTexture = new three_module/* Texture */.gPd();\n\t\tthis.searchTexture.name = 'SMAAPass.search';\n\t\tthis.searchTexture.image = searchTextureImage;\n\t\tthis.searchTexture.magFilter = three_module/* NearestFilter */.hxR;\n\t\tthis.searchTexture.minFilter = three_module/* NearestFilter */.hxR;\n\t\tthis.searchTexture.generateMipmaps = false;\n\t\tthis.searchTexture.flipY = false;\n\n\t\t// materials - pass 1\n\n\t\tthis.uniformsEdges = three_module/* UniformsUtils */.LlO.clone( SMAAEdgesShader.uniforms );\n\n\t\tthis.uniformsEdges[ 'resolution' ].value.set( 1 / width, 1 / height );\n\n\t\tthis.materialEdges = new three_module/* ShaderMaterial */.BKk( {\n\t\t\tdefines: Object.assign( {}, SMAAEdgesShader.defines ),\n\t\t\tuniforms: this.uniformsEdges,\n\t\t\tvertexShader: SMAAEdgesShader.vertexShader,\n\t\t\tfragmentShader: SMAAEdgesShader.fragmentShader\n\t\t} );\n\n\t\t// materials - pass 2\n\n\t\tthis.uniformsWeights = three_module/* UniformsUtils */.LlO.clone( SMAAWeightsShader.uniforms );\n\n\t\tthis.uniformsWeights[ 'resolution' ].value.set( 1 / width, 1 / height );\n\t\tthis.uniformsWeights[ 'tDiffuse' ].value = this.edgesRT.texture;\n\t\tthis.uniformsWeights[ 'tArea' ].value = this.areaTexture;\n\t\tthis.uniformsWeights[ 'tSearch' ].value = this.searchTexture;\n\n\t\tthis.materialWeights = new three_module/* ShaderMaterial */.BKk( {\n\t\t\tdefines: Object.assign( {}, SMAAWeightsShader.defines ),\n\t\t\tuniforms: this.uniformsWeights,\n\t\t\tvertexShader: SMAAWeightsShader.vertexShader,\n\t\t\tfragmentShader: SMAAWeightsShader.fragmentShader\n\t\t} );\n\n\t\t// materials - pass 3\n\n\t\tthis.uniformsBlend = three_module/* UniformsUtils */.LlO.clone( SMAABlendShader.uniforms );\n\n\t\tthis.uniformsBlend[ 'resolution' ].value.set( 1 / width, 1 / height );\n\t\tthis.uniformsBlend[ 'tDiffuse' ].value = this.weightsRT.texture;\n\n\t\tthis.materialBlend = new three_module/* ShaderMaterial */.BKk( {\n\t\t\tuniforms: this.uniformsBlend,\n\t\t\tvertexShader: SMAABlendShader.vertexShader,\n\t\t\tfragmentShader: SMAABlendShader.fragmentShader\n\t\t} );\n\n\t\tthis.fsQuad = new Pass/* FullScreenQuad */.F( null );\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer/*, deltaTime, maskActive*/ ) {\n\n\t\t// pass 1\n\n\t\tthis.uniformsEdges[ 'tDiffuse' ].value = readBuffer.texture;\n\n\t\tthis.fsQuad.material = this.materialEdges;\n\n\t\trenderer.setRenderTarget( this.edgesRT );\n\t\tif ( this.clear ) renderer.clear();\n\t\tthis.fsQuad.render( renderer );\n\n\t\t// pass 2\n\n\t\tthis.fsQuad.material = this.materialWeights;\n\n\t\trenderer.setRenderTarget( this.weightsRT );\n\t\tif ( this.clear ) renderer.clear();\n\t\tthis.fsQuad.render( renderer );\n\n\t\t// pass 3\n\n\t\tthis.uniformsBlend[ 'tColor' ].value = readBuffer.texture;\n\n\t\tthis.fsQuad.material = this.materialBlend;\n\n\t\tif ( this.renderToScreen ) {\n\n\t\t\trenderer.setRenderTarget( null );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t} else {\n\n\t\t\trenderer.setRenderTarget( writeBuffer );\n\t\t\tif ( this.clear ) renderer.clear();\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t}\n\n\t}\n\n\tsetSize( width, height ) {\n\n\t\tthis.edgesRT.setSize( width, height );\n\t\tthis.weightsRT.setSize( width, height );\n\n\t\tthis.materialEdges.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height );\n\t\tthis.materialWeights.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height );\n\t\tthis.materialBlend.uniforms[ 'resolution' ].value.set( 1 / width, 1 / height );\n\n\t}\n\n\tgetAreaTexture() {\n\n\t\treturn 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAKAAAAIwCAIAAACOVPcQAACBeklEQVR42u39W4xlWXrnh/3WWvuciIzMrKxrV8/0rWbY0+SQFKcb4owIkSIFCjY9AC1BT/LYBozRi+EX+cV+8IMsYAaCwRcBwjzMiw2jAWtgwC8WR5Q8mDFHZLNHTarZGrLJJllt1W2qKrsumZWZcTvn7L3W54e1vrXX3vuciLPPORFR1XE2EomorB0nVuz//r71re/y/1eMvb4Cb3N11xV/PP/2v4UBAwJG/7H8urx6/25/Gf8O5hypMQ0EEEQwAqLfoN/Z+97f/SW+/NvcgQk4sGBJK6H7N4PFVL+K+e0N11yNfkKvwUdwdlUAXPHHL38oa15f/i/46Ih6SuMSPmLAYAwyRKn7dfMGH97jaMFBYCJUgotIC2YAdu+LyW9vvubxAP8kAL8H/koAuOKP3+q6+xGnd5kdYCeECnGIJViwGJMAkQKfDvB3WZxjLKGh8VSCCzhwEWBpMc5/kBbjawT4HnwJfhr+pPBIu7uu+OOTo9vsmtQcniMBGkKFd4jDWMSCRUpLjJYNJkM+IRzQ+PQvIeAMTrBS2LEiaiR9b/5PuT6Ap/AcfAFO4Y3dA3DFH7/VS+M8k4baEAQfMI4QfbVDDGIRg7GKaIY52qAjTAgTvGBAPGIIghOCYAUrGFNgzA7Q3QhgCwfwAnwe5vDejgG44o/fbm1C5ZlYQvQDARPAIQGxCWBM+wWl37ZQESb4gImexGMDouhGLx1Cst0Saa4b4AqO4Hk4gxo+3DHAV/nx27p3JziPM2pVgoiia5MdEzCGULprIN7gEEeQ5IQxEBBBQnxhsDb5auGmAAYcHMA9eAAz8PBol8/xij9+C4Djlim4gJjWcwZBhCBgMIIYxGAVIkH3ZtcBuLdtRFMWsPGoY9rN+HoBji9VBYdwD2ZQg4cnO7OSq/z4rU5KKdwVbFAjNojCQzTlCLPFSxtamwh2jMUcEgg2Wm/6XgErIBhBckQtGN3CzbVacERgCnfgLswhnvqf7QyAq/z4rRZm1YglYE3affGITaZsdIe2FmMIpnOCap25I6jt2kCwCW0D1uAD9sZctNGXcQIHCkINDQgc78aCr+zjtw3BU/ijdpw3zhCwcaONwBvdeS2YZKkJNJsMPf2JKEvC28RXxxI0ASJyzQCjCEQrO4Q7sFArEzjZhaFc4cdv+/JFdKULM4px0DfUBI2hIsy06BqLhGTQEVdbfAIZXYMPesq6VoCHICzUyjwInO4Y411//LYLs6TDa9wvg2CC2rElgAnpTBziThxaL22MYhzfkghz6GAs2VHbbdM91VZu1MEEpupMMwKyVTb5ij9+u4VJG/5EgEMMmFF01cFai3isRbKbzb+YaU/MQbAm2XSMoUPAmvZzbuKYRIFApbtlrfFuUGd6vq2hXNnH78ZLh/iFhsQG3T4D1ib7k5CC6vY0DCbtrohgLEIClXiGtl10zc0CnEGIhhatLBva7NP58Tvw0qE8yWhARLQ8h4+AhQSP+I4F5xoU+VilGRJs6wnS7ruti/4KvAY/CfdgqjsMy4pf8fodQO8/gnuX3f/3xi3om1/h7THr+co3x93PP9+FBUfbNUjcjEmhcrkT+8K7ml7V10Jo05mpIEFy1NmCJWx9SIKKt+EjAL4Ez8EBVOB6havuT/rByPvHXK+9zUcfcbb254+9fydJknYnRr1oGfdaiAgpxu1Rx/Rek8KISftx3L+DfsLWAANn8Hvw0/AFeAGO9DFV3c6D+CcWbL8Dj9e7f+T1k8AZv/d7+PXWM/Z+VvdCrIvuAKO09RpEEQJM0Ci6+B4xhTWr4cZNOvhktabw0ta0rSJmqz3Yw5/AKXwenod7cAhTmBSPKf6JBdvH8IP17h95pXqw50/+BFnj88fev4NchyaK47OPhhtI8RFSvAfDSNh0Ck0p2gLxGkib5NJj/JWCr90EWQJvwBzO4AHcgztwAFN1evHPUVGwfXON+0debT1YeGON9Yy9/63X+OguiwmhIhQhD7l4sMqlG3D86Suc3qWZ4rWjI1X7u0Ytw6x3rIMeIOPDprfe2XzNgyj6PahhBjO4C3e6puDgXrdg+/5l948vF3bqwZetZ+z9Rx9zdIY5pInPK4Nk0t+l52xdK2B45Qd87nM8fsD5EfUhIcJcERw4RdqqH7Yde5V7m1vhNmtedkz6EDzUMF/2jJYWbC+4fzzA/Y+/8PPH3j9dcBAPIRP8JLXd5BpAu03aziOL3VVHZzz3CXWDPWd+SH2AnxIqQoTZpo9Ckc6HIrFbAbzNmlcg8Ag8NFDDAhbJvTBZXbC94P7t68EXfv6o+21gUtPETU7bbkLxvNKRFG2+KXzvtObonPP4rBvsgmaKj404DlshFole1Glfh02fE7bYR7dZ82oTewIBGn1Md6CG6YUF26X376oevOLzx95vhUmgblI6LBZwTCDY7vMq0op5WVXgsObOXJ+1x3qaBl9j1FeLxbhU9w1F+Wiba6s1X/TBz1LnUfuYDi4r2C69f1f14BWfP+p+W2GFKuC9phcELMYRRLur9DEZTUdEH+iEqWdaM7X4WOoPGI+ZYD2+wcQ+y+ioHUZ9dTDbArzxmi/bJI9BND0Ynd6lBdve/butBw8+f/T9D3ABa3AG8W3VPX4hBin+bj8dMMmSpp5pg7fJ6xrBFE2WQQEWnV8Qg3FbAWzYfM1rREEnmvkN2o1+acG2d/9u68GDzx91v3mAjb1zkpqT21OipPKO0b9TO5W0nTdOmAQm0TObts3aBKgwARtoPDiCT0gHgwnbArzxmtcLc08HgF1asN0C4Ms/fvD5I+7PhfqyXE/b7RbbrGyRQRT9ARZcwAUmgdoz0ehJ9Fn7QAhUjhDAQSw0bV3T3WbNa59jzmiP6GsWbGXDX2ytjy8+f9T97fiBPq9YeLdBmyuizZHaqXITnXiMUEEVcJ7K4j3BFPurtB4bixW8wTpweL8DC95szWMOqucFYGsWbGU7p3TxxxefP+r+oTVktxY0v5hbq3KiOKYnY8ddJVSBxuMMVffNbxwIOERShst73HZ78DZrHpmJmH3K6sGz0fe3UUj0eyRrSCGTTc+rjVNoGzNSv05srAxUBh8IhqChiQgVNIIBH3AVPnrsnXQZbLTm8ammv8eVXn/vWpaTem5IXRlt+U/LA21zhSb9cye6jcOfCnOwhIAYXAMVTUNV0QhVha9xjgA27ODJbLbmitt3tRN80lqG6N/khgot4ZVlOyO4WNg3OIMzhIZQpUEHieg2im6F91hB3I2tubql6BYNN9Hj5S7G0G2tahslBWKDnOiIvuAEDzakDQKDNFQT6gbn8E2y4BBubM230YIpBnDbMa+y3dx0n1S0BtuG62lCCXwcY0F72T1VRR3t2ONcsmDjbmzNt9RFs2LO2hQNyb022JisaI8rAWuw4HI3FuAIhZdOGIcdjLJvvObqlpqvWTJnnQbyi/1M9O8UxWhBs//H42I0q1Yb/XPGONzcmm+ri172mHKvZBpHkJaNJz6v9jxqiklDj3U4CA2ugpAaYMWqNXsdXbmJNd9egCnJEsphXNM+MnK3m0FCJ5S1kmJpa3DgPVbnQnPGWIDspW9ozbcO4K/9LkfaQO2KHuqlfFXSbdNzcEcwoqNEFE9zcIXu9/6n/ym/BC/C3aJLzEKPuYVlbFnfhZ8kcWxV3dbv4bKl28566wD+8C53aw49lTABp9PWbsB+knfc/Li3eVizf5vv/xmvnPKg5ihwKEwlrcHqucuVcVOxEv8aH37E3ZqpZypUulrHEtIWKUr+txHg+ojZDGlwnqmkGlzcVi1dLiNSJiHjfbRNOPwKpx9TVdTn3K05DBx4psIk4Ei8aCkJahRgffk4YnEXe07T4H2RR1u27E6wfQsBDofUgjFUFnwC2AiVtA+05J2zpiDK2Oa0c5fmAecN1iJzmpqFZxqYBCYhFTCsUNEmUnIcZ6aEA5rQVhEywG6w7HSW02XfOoBlQmjwulOFQAg66SvJblrTEX1YtJ3uG15T/BH1OfOQeuR8g/c0gdpT5fx2SKbs9EfHTKdM8A1GaJRHLVIwhcGyydZsbifAFVKl5EMKNU2Hryo+06BeTgqnxzYjThVySDikbtJPieco75lYfKAJOMEZBTjoITuWHXXZVhcUDIS2hpiXHV9Ku4u44bN5OYLDOkJo8w+xJSMbhBRHEdEs9JZUCkQrPMAvaHyLkxgkEHxiNkx/x2YB0mGsQ8EUWj/stW5YLhtS5SMu+/YBbNPDCkGTUybN8krRLBGPlZkVOA0j+a1+rkyQKWGaPHPLZOkJhioQYnVZ2hS3zVxMtgC46KuRwbJNd9nV2PHgb36F194ecf/Yeu2vAFe5nm/bRBFrnY4BauE8ERmZRFUn0k8hbftiVYSKMEme2dJCJSCGYAlNqh87bXOPdUkGy24P6d1ll21MBqqx48Fvv8ZHH8HZFY7j/uAq1xMJUFqCSUlJPmNbIiNsmwuMs/q9CMtsZsFO6SprzCS1Z7QL8xCQClEelpjTduDMsmWD8S1PT152BtvmIGvUeDA/yRn83u/x0/4qxoPHjx+PXY9pqX9bgMvh/Nz9kpP4pOe1/fYf3axUiMdHLlPpZCNjgtNFAhcHEDxTumNONhHrBduW+vOyY++70WWnPXj98eA4kOt/mj/5E05l9+O4o8ePx67HFqyC+qSSnyselqjZGaVK2TadbFLPWAQ4NBhHqDCCV7OTpo34AlSSylPtIdd2AJZlyzYQrDJ5lcWGNceD80CunPLGGzsfD+7wRb95NevJI5docQ3tgCyr5bGnyaPRlmwNsFELViOOx9loebGNq2moDOKpHLVP5al2cymWHbkfzGXL7kfRl44H9wZy33tvt+PB/Xnf93e+nh5ZlU18wCiRUa9m7kib9LYuOk+hudQNbxwm0AQqbfloimaB2lM5fChex+ylMwuTbfmXQtmWlenZljbdXTLuOxjI/fDDHY4Hjx8/Hrse0zXfPFxbUN1kKqSCCSk50m0Ajtx3ub9XHBKHXESb8iO6E+qGytF4nO0OG3SXzbJlhxBnKtKyl0NwybjvYCD30aMdjgePHz8eu56SVTBbgxJMliQ3Oauwg0QHxXE2Ez/EIReLdQj42Gzb4CLS0YJD9xUx7bsi0vJi5mUbW1QzL0h0PFk17rtiIPfJk52MB48fPx67npJJwyrBa2RCCQRTbGZSPCxTPOiND4G2pYyOQ4h4jINIJh5wFU1NFZt+IsZ59LSnDqBjZ2awbOku+yInunLcd8VA7rNnOxkPHj9+PGY9B0MWJJNozOJmlglvDMXDEozdhQWbgs/U6oBanGzLrdSNNnZFjOkmbi5bNt1lX7JLLhn3vXAg9/h4y/Hg8ePHI9dzQMEkWCgdRfYykYKnkP7D4rIujsujaKPBsB54vE2TS00ccvFY/Tth7JXeq1hz+qgVy04sAJawTsvOknHfCwdyT062HA8eP348Zj0vdoXF4pilKa2BROed+9fyw9rWRXeTFXESMOanvDZfJuJaSXouQdMdDJZtekZcLLvEeK04d8m474UDuaenW44Hjx8/Xns9YYqZpszGWB3AN/4VHw+k7WSFtJ3Qicuqb/NlVmgXWsxh570xg2UwxUw3WfO6B5nOuO8aA7lnZxuPB48fPx6znm1i4bsfcbaptF3zNT78eFPtwi1OaCNOqp1x3zUGcs/PN++AGD1+fMXrSVm2baTtPhPahbPhA71wIHd2bXzRa69nG+3CraTtPivahV/55tXWg8fyRY/9AdsY8VbSdp8V7cKrrgdfM//z6ILQFtJ2nxHtwmuoB4/kf74+gLeRtvvMaBdeSz34+vifx0YG20jbfTa0C6+tHrwe//NmOG0L8EbSdp8R7cLrrQe/996O+ai3ujQOskpTNULa7jOjXXj99eCd8lHvoFiwsbTdZ0a78PrrwTvlo966pLuRtB2fFe3Cm6oHP9kNH/W2FryxtN1nTLvwRurBO+Kj3pWXHidtx2dFu/Bm68Fb81HvykuPlrb7LGkX3mw9eGs+6h1Y8MbSdjegXcguQLjmevDpTQLMxtJ2N6NdyBZu9AbrwVvwUW+LbteULUpCdqm0HTelXbhNPe8G68Gb8lFvVfYfSNuxvrTdTWoXbozAzdaDZzfkorOj1oxVxlIMlpSIlpLrt8D4hrQL17z+c3h6hU/wv4Q/utps4+bm+6P/hIcf0JwQ5oQGPBL0eKPTYEXTW+eL/2DKn73J9BTXYANG57hz1cEMviVf/4tf5b/6C5pTQkMIWoAq7hTpOJjtAM4pxKu5vg5vXeUrtI09/Mo/5H+4z+Mp5xULh7cEm2QbRP2tFIKR7WM3fPf/jZ3SWCqLM2l4NxID5zB72HQXv3jj/8mLR5xXNA5v8EbFQEz7PpRfl1+MB/hlAN65qgDn3wTgH13hK7T59bmP+NIx1SHHU84nLOITt3iVz8mNO+lPrjGAnBFqmioNn1mTyk1ta47R6d4MrX7tjrnjYUpdUbv2rVr6YpVfsGG58AG8Ah9eyUN8CX4WfgV+G8LVWPDGb+Zd4cU584CtqSbMKxauxTg+dyn/LkVgA+IR8KHtejeFKRtTmLLpxN6mYVLjYxwXf5x2VofiZcp/lwKk4wGOpYDnoIZPdg/AAbwMfx0+ge9dgZvYjuqKe4HnGnykYo5TvJbG0Vj12JagRhwKa44H95ShkZa5RyLGGdfYvG7aw1TsF6iapPAS29mNS3NmsTQZCmgTzFwgL3upCTgtBTRwvGMAKrgLn4evwin8+afJRcff+8izUGUM63GOOuAs3tJkw7J4kyoNreqrpO6cYLQeFUd7TTpr5YOTLc9RUUogUOVJQ1GYJaFLAW0oTmKyYS46ZooP4S4EON3xQ5zC8/CX4CnM4c1PE8ApexpoYuzqlP3d4S3OJP8ZDK7cKWNaTlqmgDiiHwl1YsE41w1zT4iRTm3DBqxvOUsbMKKDa/EHxagtnta072ejc3DOIh5ojvh8l3tk1JF/AV6FU6jh3U8HwEazLgdCLYSQ+MYiAI2ltomkzttUb0gGHdSUUgsIYjTzLG3mObX4FBRaYtpDVNZrih9TgTeYOBxsEnN1gOCTM8Bsw/ieMc75w9kuAT6A+/AiHGvN/+Gn4KRkiuzpNNDYhDGFndWRpE6SVfm8U5bxnSgVV2jrg6JCKmneqey8VMFgq2+AM/i4L4RUbfSi27lNXZ7R7W9RTcq/q9fk4Xw3AMQd4I5ifAZz8FcVtm9SAom/dyN4lczJQW/kC42ZrHgcCoIf1oVMKkVItmMBi9cOeNHGLqOZk+QqQmrbc5YmYgxELUUN35z2iohstgfLIFmcMV7s4CFmI74L9+EFmGsi+tGnAOD4Yk9gIpo01Y4cA43BWGygMdr4YZekG3OBIUXXNukvJS8tqa06e+lSDCtnqqMFu6hWHXCF+WaYt64m9QBmNxi7Ioy7D+fa1yHw+FMAcPt7SysFLtoG4PXAk7JOA3aAxBRqUiAdU9Yp5lK3HLSRFtOim0sa8euEt08xvKjYjzeJ2GU7YawexrnKI9tmobInjFXCewpwriY9+RR4aaezFhMhGCppKwom0ChrgFlKzyPKkGlTW1YQrE9HJqu8hKGgMc6hVi5QRq0PZxNfrYNgE64utmRv6KKHRpxf6VDUaOvNP5jCEx5q185My/7RKz69UQu2im5k4/eownpxZxNLwiZ1AZTO2ZjWjkU9uaB2HFn6Q3u0JcsSx/qV9hTEApRzeBLDJQXxYmTnq7bdLa3+uqFrxLJ5w1TehnNHx5ECvCh2g2c3hHH5YsfdaSKddztfjQ6imKFGSyFwlLzxEGPp6r5IevVjk1AMx3wMqi1NxDVjLBiPs9tbsCkIY5we5/ML22zrCScFxnNtzsr9Wcc3CnD+pYO+4VXXiDE0oc/vQQ/fDK3oPESJMYXNmJa/DuloJZkcTpcYE8lIH8Dz8DJMiynNC86Mb2lNaaqP/+L7f2fcE/yP7/Lde8xfgSOdMxvOixZf/9p3+M4hT1+F+zApxg9XfUvYjc8qX2lfOOpK2gNRtB4flpFu9FTKCp2XJRgXnX6olp1zyYjTKJSkGmLE2NjUr1bxFM4AeAAHBUFIeSLqXR+NvH/M9fOnfHzOD2vCSyQJKzfgsCh+yi/Mmc35F2fUrw7miW33W9hBD1vpuUojFphIyvg7aTeoymDkIkeW3XLHmguMzbIAJejN6B5MDrhipE2y6SoFRO/AK/AcHHZHNIfiWrEe/C6cr3f/yOvrQKB+zMM55/GQdLDsR+ifr5Fiuu+/y+M78LzOE5dsNuXC3PYvYWd8NXvphLSkJIasrlD2/HOqQ+RjcRdjKTGWYhhVUm4yxlyiGPuMsZR7sMCHUBeTuNWA7if+ifXgc/hovftHXs/DV+Fvwe+f8shzMiMcweFgBly3//vwJfg5AN4450fn1Hd1Rm1aBLu22Dy3y3H2+OqMemkbGZ4jozcDjJf6596xOLpC0eMTHbKnxLxH27uZ/bMTGs2jOaMOY4m87CfQwF0dw53oa1k80JRuz/XgS+8fX3N9Af4qPIMfzKgCp4H5TDGe9GGeFPzSsZz80SlPTxXjgwJmC45njzgt2vbQ4b4OAdUK4/vWhO8d8v6EE8fMUsfakXbPpFJeLs2ubM/qdm/la3WP91uWhxXHjoWhyRUq2iJ/+5mA73zwIIo+LoZ/SgvIRjAd1IMvvn98PfgOvAJfhhm8scAKVWDuaRaK8aQ9f7vuPDH6Bj47ZXau7rqYJ66mTDwEDU6lLbCjCK0qTXyl5mnDoeNRxanj3FJbaksTk0faXxHxLrssgPkWB9LnA/MFleXcJozzjwsUvUG0X/QCve51qkMDXp9mtcyOy3rwBfdvVJK7D6/ACSzg3RoruIq5UDeESfEmVclDxnniU82vxMLtceD0hGZWzBNPMM/jSPne2OVatiTKUpY5vY7gc0LdUAWeWM5tH+O2I66AOWw9xT2BuyRVLGdoDHUsVRXOo/c+ZdRXvFfnxWyIV4upFLCl9eAL7h8Zv0QH8Ry8pA2cHzQpGesctVA37ZtklBTgHjyvdSeKY/RZw/kJMk0Y25cSNRWSigQtlULPTw+kzuJPeYEkXjQRpoGZobYsLF79pyd1dMRHInbgFTZqNLhDqiIsTNpoex2WLcy0/X6rHcdMMQvFSd5dWA++4P7xv89deACnmr36uGlL69bRCL6BSZsS6c0TU2TKK5gtWCzgAOOwQcurqk9j8whvziZSMLcq5hbuwBEsYjopUBkqw1yYBGpLA97SRElEmx5MCInBY5vgLk94iKqSWmhIGmkJ4Bi9m4L645J68LyY4wsFYBfUg5feP/6gWWm58IEmKQM89hq7KsZNaKtP5TxxrUZZVkNmMJtjbKrGxLNEbHPJxhqy7lAmbC32ZqeF6lTaknRWcYaFpfLUBh/rwaQycCCJmW15Kstv6jRHyJFry2C1ahkkIW0LO75s61+owxK1y3XqweX9m5YLM2DPFeOjn/iiqCKJ+yKXF8t5Yl/kNsqaSCryxPq5xWTFIaP8KSW0RYxqupaUf0RcTNSSdJZGcKYdYA6kdtrtmyBckfKXwqk0pHpUHlwWaffjNRBYFPUDWa8e3Lt/o0R0CdisKDM89cX0pvRHEfM8ca4t0s2Xx4kgo91MPQJ/0c9MQYq0co8MBh7bz1fio0UUHLR4aAIOvOmoYO6kwlEVODSSTliWtOtH6sPkrtctF9ZtJ9GIerBskvhdVS5cFNv9s1BU0AbdUgdK4FG+dRnjFmDTzniRMdZO1QhzMK355vigbdkpz9P6qjUGE5J2qAcXmwJ20cZUiAD0z+pGMx6xkzJkmEf40Hr4qZfVg2XzF9YOyoV5BjzVkUJngKf8lgNYwKECEHrCNDrWZzMlflS3yBhr/InyoUgBc/lKT4pxVrrC6g1YwcceK3BmNxZcAtz3j5EIpqguh9H6wc011YN75cKDLpFDxuwkrPQmUwW4KTbj9mZTwBwLq4aQMUZbHm1rylJ46dzR0dua2n3RYCWZsiHROeywyJGR7mXKlpryyCiouY56sFkBWEnkEB/raeh/Sw4162KeuAxMQpEkzy5alMY5wamMsWKKrtW2WpEWNnReZWONKWjrdsKZarpFjqCslq773PLmEhM448Pc3+FKr1+94vv/rfw4tEcu+lKTBe4kZSdijBrykwv9vbCMPcLQTygBjzVckSLPRVGslqdunwJ4oegtFOYb4SwxNgWLCmD7T9kVjTv5YDgpo0XBmN34Z/rEHp0sgyz7lngsrm4lvMm2Mr1zNOJYJ5cuxuQxwMGJq/TP5emlb8fsQBZviK4t8hFL+zbhtlpwaRSxQRWfeETjuauPsdGxsBVdO7nmP4xvzSoT29pRl7kGqz+k26B3Oy0YNV+SXbbQas1ctC/GarskRdFpKczVAF1ZXnLcpaMuzVe6lZ2g/1ndcvOVgRG3sdUAY1bKD6achijMPdMxV4muKVorSpiDHituH7rSTs7n/4y5DhRXo4FVBN4vO/zbAcxhENzGbHCzU/98Mcx5e7a31kWjw9FCe/zNeYyQjZsWb1uc7U33pN4Mji6hCLhivqfa9Ss6xLg031AgfesA/l99m9fgvnaF9JoE6bYKmkGNK3aPbHB96w3+DnxFm4hs0drLsk7U8kf/N/CvwQNtllna0rjq61sH8L80HAuvwH1tvBy2ChqWSCaYTaGN19sTvlfzFD6n+iKTbvtayfrfe9ueWh6GJFoxLdr7V72a5ZpvHcCPDzma0wTO4EgbLyedxstO81n57LYBOBzyfsOhUKsW1J1BB5vr/tz8RyqOFylQP9Tvst2JALsC5lsH8PyQ40DV4ANzYa4dedNiKNR1s+x2wwbR7q4/4cTxqEk4LWDebfisuo36JXLiWFjOtLrlNWh3K1rRS4xvHcDNlFnNmWBBAl5SWaL3oPOfnvbr5pdjVnEaeBJSYjuLEkyLLsWhKccadmOphZkOPgVdalj2QpSmfOsADhMWE2ZBu4+EEJI4wKTAuCoC4xwQbWXBltpxbjkXJtKxxabo9e7tyhlgb6gNlSbUpMh+l/FaqzVwewGu8BW1Zx7pTpQDJUjb8tsUTW6+GDXbMn3mLbXlXJiGdggxFAoUrtPS3wE4Nk02UZG2OOzlk7fRs7i95QCLo3E0jtrjnM7SR3uS1p4qtS2nJ5OwtQVHgOvArLBFijZUV9QtSl8dAY5d0E0hM0w3HS2DpIeB6m/A1+HfhJcGUq4sOxH+x3f5+VO+Ds9rYNI7zPXOYWPrtf8bYMx6fuOAX5jzNR0PdsuON+X1f7EERxMJJoU6GkTEWBvVolVlb5lh3tKCg6Wx1IbaMDdJ+9sUCc5KC46hKGCk3IVOS4TCqdBNfUs7Kd4iXf2RjnT/LLysJy3XDcHLh/vde3x8DoGvwgsa67vBk91G5Pe/HbOe7xwym0NXbtiuuDkGO2IJDh9oQvJ4cY4vdoqLDuoH9Zl2F/ofsekn8lkuhIlhQcffUtSjytFyp++p6NiE7Rqx/lodgKVoceEp/CP4FfjrquZaTtj2AvH5K/ywpn7M34K/SsoYDAdIN448I1/0/wveW289T1/lX5xBzc8N5IaHr0XMOQdHsIkDuJFifj20pBm5jzwUv9e2FhwRsvhAbalCIuIw3bhJihY3p6nTFFIZgiSYjfTf3aXuOjmeGn4bPoGvwl+CFzTRczBIuHBEeImHc37/lGfwZR0cXzVDOvaKfNHvwe+suZ771K/y/XcBlsoN996JpBhoE2toYxOznNEOS5TJc6Id5GEXLjrWo+LEWGNpPDU4WAwsIRROu+1vM+0oW37z/MBN9kqHnSArwPfgFJ7Cq/Ai3Ie7g7ncmI09v8sjzw9mzOAEXoIHxURueaAce5V80f/DOuuZwHM8vsMb5wBzOFWM7wymTXPAEvm4vcFpZ2ut0VZRjkiP2MlmLd6DIpbGSiHOjdnUHN90hRYmhTnmvhzp1iKDNj+b7t5hi79lWGwQ+HN9RsfFMy0FXbEwhfuczKgCbyxYwBmcFhhvo/7a44v+i3XWcwDP86PzpGQYdWh7csP5dBvZ1jNzdxC8pBGuxqSW5vw40nBpj5JhMwvOzN0RWqERHMr4Lv1kWX84xLR830G3j6yqZ1a8UstTlW+qJPOZ+sZ7xZPKTJLhiNOAFd6tk+jrTH31ncLOxid8+nzRb128HhUcru/y0Wn6iT254YPC6FtVSIMoW2sk727AhvTtrWKZTvgsmckfXYZWeNRXx/3YQ2OUxLDrbHtN11IwrgXT6c8dATDwLniYwxzO4RzuQqTKSC5gAofMZ1QBK3zQ4JWobFbcvJm87FK+6JXrKahLn54m3p+McXzzYtP8VF/QpJuh1OwieElEoI1pRxPS09FBrkq2tWCU59+HdhNtTIqKm8EBrw2RTOEDpG3IKo2Y7mFdLm3ZeVjYwVw11o/oznceMve4CgMfNym/utA/d/ILMR7gpXzRy9eDsgLcgbs8O2Va1L0zzIdwGGemTBuwROHeoMShkUc7P+ISY3KH5ZZeWqO8mFTxQYeXTNuzvvK5FGPdQfuu00DwYFY9dyhctEt+OJDdnucfpmyhzUJzfsJjr29l8S0bXBfwRS9ZT26tmMIdZucch5ZboMz3Nio3nIOsYHCGoDT4kUA9MiXEp9Xsui1S8th/kbWIrMBxDGLodWUQIWcvnXy+9M23xPiSMOiRPqM+YMXkUN3gXFrZJwXGzUaMpJfyRS9ZT0lPe8TpScuRlbMHeUmlaKDoNuy62iWNTWNFYjoxFzuJs8oR+RhRx7O4SVNSXpa0ZJQ0K1LAHDQ+D9IepkMXpcsq5EVCvClBUIzDhDoyKwDw1Lc59GbTeORivugw1IcuaEOaGWdNm+Ps5fQ7/tm0DjMegq3yM3vb5j12qUId5UZD2oxDSEWOZMSqFl/W+5oynWDa/aI04tJRQ2eTXusg86SQVu/nwSYwpW6wLjlqIzwLuxGIvoAvul0PS+ZNz0/akp/pniO/8JDnGyaCkzbhl6YcqmK/69prxPqtpx2+Km9al9sjL+rwMgHw4jE/C8/HQ3m1vBuL1fldbzd8mOueVJ92syqdEY4KJjSCde3mcRw2TA6szxedn+zwhZMps0XrqEsiUjnC1hw0TELC2Ek7uAAdzcheXv1BYLagspxpzSAoZZUsIzIq35MnFQ9DOrlNB30jq3L4pkhccKUAA8/ocvN1Rzx9QyOtERs4CVsJRK/DF71kPYrxYsGsm6RMh4cps5g1DOmM54Ly1ii0Hd3Y/BMk8VWFgBVmhqrkJCPBHAolwZaWzLR9Vb7bcWdX9NyUYE+uB2BKfuaeBUcjDljbYVY4DdtsVWvzRZdWnyUzDpjNl1Du3aloAjVJTNDpcIOVVhrHFF66lLfJL1zJr9PQ2nFJSBaKoDe+sAvLufZVHVzYh7W0h/c6AAZ+7Tvj6q9j68G/cTCS/3n1vLKHZwNi+P+pS0WkZNMBMUl+LDLuiE4omZy71r3UFMwNJV+VJ/GC5ixVUkBStsT4gGKh0Gm4Oy3qvq7Lbmq24nPdDuDR9deR11XzP4vFu3TYzfnIyiSVmgizUYGqkIXNdKTY9pgb9D2Ix5t0+NHkVzCdU03suWkkVZAoCONCn0T35gAeW38de43mf97sMOpSvj4aa1KYUm58USI7Wxxes03bAZdRzk6UtbzMaCQ6IxO0dy7X+XsjoD16hpsBeGz9dfzHj+R/Hp8nCxZRqkEDTaCKCSywjiaoMJ1TITE9eg7Jqnq8HL6gDwiZb0u0V0Rr/rmvqjxKuaLCX7ZWXTvAY+uvm3z8CP7nzVpngqrJpZKwWnCUjIviYVlirlGOzPLI3SMVyp/elvBUjjDkNhrtufFFErQ8pmdSlbK16toBHlt/HV8uHMX/vEGALkV3RJREiSlopxwdMXOZPLZ+ix+kAHpMKIk8UtE1ygtquttwxNhphrIZ1IBzjGF3IIGxGcBj6q8bHJBG8T9vdsoWrTFEuebEZuVxhhClH6P5Zo89OG9fwHNjtNQTpD0TG9PJLEYqvEY6Rlxy+ZZGfL0Aj62/bnQCXp//eeM4KzfQVJbgMQbUjlMFIm6TpcfWlZje7NBSV6IsEVmumWIbjiloUzQX9OzYdo8L1wjw2PrrpimONfmfNyzKklrgnEkSzT5QWYQW40YShyzqsRmMXbvVxKtGuYyMKaU1ugenLDm5Ily4iT14fP11Mx+xJv+zZ3MvnfdFqxU3a1W/FTB4m3Qfsyc1XUcdVhDeUDZXSFHHLQj/Y5jtC7ZqM0CXGwB4bP11i3LhOvzPGygYtiUBiwQV/4wFO0majijGsafHyRLu0yG6q35cL1rOpVxr2s5cM2jJYMCdc10Aj6q/blRpWJ//+dmm5psMl0KA2+AFRx9jMe2WbC4jQxnikd4DU8TwUjRVacgdlhmr3bpddzuJ9zXqr2xnxJfzP29RexdtjDVZqzkqa6PyvcojGrfkXiJ8SEtml/nYskicv0ivlxbqjemwUjMw5evdg8fUX9nOiC/lf94Q2i7MURk9nW1MSj5j8eAyV6y5CN2S6qbnw3vdA1Iwq+XOSCl663udN3IzLnrt+us25cI1+Z83SXQUldqQq0b5XOT17bGpLd6ssN1VMPf8c+jG8L3NeCnMdF+Ra3fRa9dft39/LuZ/3vwHoHrqGmQFafmiQw6eyzMxS05K4bL9uA+SKUQzCnSDkqOGokXyJvbgJ/BHI+qvY69//4rl20NsmK2ou2dTsyIALv/91/8n3P2Aao71WFGi8KKv1fRC5+J67Q/507/E/SOshqN5TsmYIjVt+kcjAx98iz/4SaojbIV1rexE7/C29HcYD/DX4a0rBOF5VTu7omsb11L/AWcVlcVZHSsqGuXLLp9ha8I//w3Mv+T4Ew7nTBsmgapoCrNFObIcN4pf/Ob/mrvHTGqqgAupL8qWjWPS9m/31jAe4DjA+4+uCoQoT/zOzlrNd3qd4SdphFxsUvYwGWbTWtISc3wNOWH+kHBMfc6kpmpwPgHWwqaSUG2ZWWheYOGQGaHB+eQ/kn6b3pOgLV+ODSn94wDvr8Bvb70/LLuiPPEr8OGVWfDmr45PZyccEmsVXZGe1pRNX9SU5+AVQkNTIVPCHF/jGmyDC9j4R9LfWcQvfiETmgMMUCMN1uNCakkweZsowdYobiMSlnKA93u7NzTXlSfe+SVbfnPQXmg9LpYAQxpwEtONyEyaueWM4FPjjyjG3uOaFmBTWDNgBXGEiQpsaWhnAqIijB07Dlsy3fUGeP989xbWkyf+FF2SNEtT1E0f4DYYVlxFlbaSMPIRMk/3iMU5pME2SIWJvjckciebkQuIRRyhUvkHg/iUljG5kzVog5hV7vIlCuBrmlhvgPfNHQM8lCf+FEGsYbMIBC0qC9a0uuy2wLXVbLBaP5kjHokCRxapkQyzI4QEcwgYHRZBp+XEFTqXFuNVzMtjXLJgX4gAid24Hjwc4N3dtVSe+NNiwTrzH4WVUOlDobUqr1FuAgYllc8pmzoVrELRHSIW8ViPxNy4xwjBpyR55I6J220qQTZYR4guvUICJiSpr9gFFle4RcF/OMB7BRiX8sSfhpNSO3lvEZCQfLUVTKT78Ek1LRLhWN+yLyTnp8qWUZ46b6vxdRGXfHVqx3eI75YaLa4iNNiK4NOW7wPW6lhbSOF9/M9qw8e/aoB3d156qTzxp8pXx5BKAsYSTOIIiPkp68GmTq7sZtvyzBQaRLNxIZ+paozHWoLFeExIhRBrWitHCAHrCF7/thhD8JhYz84wg93QRV88wLuLY8zF8sQ36qF1J455bOlgnELfshKVxYOXKVuKx0jaj22sczTQqPqtV/XDgpswmGTWWMSDw3ssyUunLLrVPGjYRsH5ggHeHSWiV8kT33ycFSfMgkoOK8apCye0J6VW6GOYvffgU9RWsukEi2kUV2nl4dOYUzRik9p7bcA4ggdJ53LxKcEe17B1R8eqAd7dOepV8sTXf5lhejoL85hUdhDdknPtKHFhljOT+bdq0hxbm35p2nc8+Ja1Iw+tJykgp0EWuAAZYwMVwac5KzYMslhvgHdHRrxKnvhTYcfKsxTxtTETkjHO7rr3zjoV25lAQHrqpV7bTiy2aXMmUhTBnKS91jhtR3GEoF0oLnWhWNnYgtcc4N0FxlcgT7yz3TgNIKkscx9jtV1ZKpWW+Ub1tc1eOv5ucdgpx+FJy9pgbLE7xDyXb/f+hLHVGeitHOi6A7ybo3sF8sS7w7cgdk0nJaOn3hLj3uyD0Zp5pazFIUXUpuTTU18d1EPkDoX8SkmWTnVIozEdbTcZjoqxhNHf1JrSS/AcvHjZ/SMHhL/7i5z+POsTUh/8BvNfYMTA8n+yU/MlTZxSJDRStqvEuLQKWwDctMTQogUDyQRoTQG5Kc6oQRE1yV1jCA7ri7jdZyK0sYTRjCR0Hnnd+y7nHxNgTULqw+8wj0mQKxpYvhjm9uSUxg+TTy7s2GtLUGcywhXSKZN275GsqlclX90J6bRI1aouxmgL7Q0Nen5ziM80SqMIo8cSOo+8XplT/5DHNWsSUr/6lLN/QQ3rDyzLruEW5enpf7KqZoShEduuSFOV7DLX7Ye+GmXb6/hnNNqKsVXuMDFpb9Y9eH3C6NGEzuOuI3gpMH/I6e+zDiH1fXi15t3vA1czsLws0TGEtmPEJdiiFPwlwKbgLHAFk4P6ZyPdymYYHGE0dutsChQBl2JcBFlrEkY/N5bQeXQ18gjunuMfMfsBlxJSx3niO485fwO4fGD5T/+3fPQqkneWVdwnw/3bMPkW9Wbqg+iC765Zk+xcT98ibKZc2EdgHcLoF8cSOo/Oc8fS+OyEULF4g4sJqXVcmfMfsc7A8v1/yfGXmL9I6Fn5pRwZhsPv0TxFNlAfZCvG+Oohi82UC5f/2IsJo0cTOm9YrDoKhFPEUr/LBYTUNht9zelHXDqwfPCIw4owp3mOcIQcLttWXFe3VZ/j5H3cIc0G6oPbCR+6Y2xF2EC5cGUm6wKC5tGEzhsWqw5hNidUiKX5gFWE1GXh4/Qplw4sVzOmx9QxU78g3EF6wnZlEN4FzJ1QPSLEZz1KfXC7vd8ssGdIbNUYpVx4UapyFUHzJoTOo1McSkeNn1M5MDQfs4qQuhhX5vQZFw8suwWTcyYTgioISk2YdmkhehG4PkE7w51inyAGGaU+uCXADabGzJR1fn3lwkty0asIo8cROm9Vy1g0yDxxtPvHDAmpu+PKnM8Ix1wwsGw91YJqhteaWgjYBmmQiebmSpwKKzE19hx7jkzSWOm66oPbzZ8Yj6kxVSpYjVAuvLzYMCRo3oTQecOOjjgi3NQ4l9K5/hOGhNTdcWVOTrlgYNkEXINbpCkBRyqhp+LdRB3g0OU6rMfW2HPCFFMV9nSp+uB2woepdbLBuJQyaw/ZFysXrlXwHxI0b0LovEkiOpXGA1Ijagf+KUNC6rKNa9bQnLFqYNkEnMc1uJrg2u64ELPBHpkgWbmwKpJoDhMwNbbGzAp7Yg31wS2T5rGtzit59PrKhesWG550CZpHEzpv2NGRaxlNjbMqpmEIzygJqQfjypycs2pg2cS2RY9r8HUqkqdEgKTWtWTKoRvOBPDYBltja2SO0RGjy9UHtxwRjA11ujbKF+ti5cIR9eCnxUg6owidtyoU5tK4NLji5Q3HCtiyF2IqLGYsHViOXTXOYxucDqG0HyttqYAKqYo3KTY1ekyDXRAm2AWh9JmsVh/ccg9WJ2E8YjG201sPq5ULxxX8n3XLXuMInbft2mk80rRGjCGctJ8/GFdmEQ9Ug4FlE1ll1Y7jtiraqm5Fe04VV8lvSVBL8hiPrfFVd8+7QH3Qbu2ipTVi8cvSGivc9cj8yvH11YMHdNSERtuOslM97feYFOPKzGcsI4zW0YGAbTAOaxCnxdfiYUmVWslxiIblCeAYr9VYR1gM7GmoPrilunSxxeT3DN/2eBQ9H11+nk1adn6VK71+5+Jfct4/el10/7KBZfNryUunWSCPxPECk1rdOv1WVSrQmpC+Tl46YD3ikQYcpunSQgzVB2VHFhxHVGKDgMEY5GLlQnP7FMDzw7IacAWnO6sBr12u+XanW2AO0wQ8pknnFhsL7KYIqhkEPmEXFkwaN5KQphbkUmG72wgw7WSm9RiL9QT925hkjiVIIhphFS9HKI6/8QAjlpXqg9W2C0apyaVDwKQwrwLY3j6ADR13ZyUNByQXHQu6RY09Hu6zMqXRaNZGS/KEJs0cJEe9VH1QdvBSJv9h09eiRmy0V2uJcqHcShcdvbSNg5fxkenkVprXM9rDVnX24/y9MVtncvbKY706anNl3ASll9a43UiacVquXGhvq4s2FP62NGKfQLIQYu9q1WmdMfmUrDGt8eDS0cXozH/fjmUH6Jruvm50hBDSaEU/2Ru2LEN/dl006TSc/g7tfJERxGMsgDUEr104pfWH9lQaN+M4KWQjwZbVc2rZVNHsyHal23wZtIs2JJqtIc/WLXXRFCpJkfE9jvWlfFbsNQ9pP5ZBS0zKh4R0aMFj1IjTcTnvi0Zz2rt7NdvQb2mgbju1plsH8MmbnEk7KbK0b+wC2iy3aX3szW8xeZvDwET6hWZYwqTXSSG+wMETKum0Dq/q+x62gt2ua2ppAo309TRk9TPazfV3qL9H8z7uhGqGqxNVg/FKx0HBl9OVUORn8Q8Jx9gFttGQUDr3tzcXX9xGgN0EpzN9mdZ3GATtPhL+CjxFDmkeEU6x56kqZRusLzALXVqkCN7zMEcqwjmywDQ6OhyUe0Xao1Qpyncrg6wKp9XfWDsaZplElvQ/b3sdweeghorwBDlHzgk1JmMc/wiERICVy2VJFdMjFuLQSp3S0W3+sngt2njwNgLssFGVQdJ0tu0KH4ky1LW4yrbkuaA6Iy9oz/qEMMXMMDWyIHhsAyFZc2peV9hc7kiKvfULxCl9iddfRK1f8kk9qvbdOoBtOg7ZkOZ5MsGrSHsokgLXUp9y88smniwWyuFSIRVmjplga3yD8Uij5QS1ZiM4U3Qw5QlSm2bXjFe6jzzBFtpg+/YBbLAWG7OPynNjlCw65fukGNdkJRf7yM1fOxVzbxOJVocFoYIaGwH22mIQkrvu1E2nGuebxIgW9U9TSiukPGU+Lt++c3DJPKhyhEEbXCQLUpae2exiKy6tMPe9mDRBFCEMTWrtwxN8qvuGnt6MoihKWS5NSyBhbH8StXoAz8PLOrRgLtOT/+4vcu+7vDLnqNvztOq7fmd8sMmY9Xzn1zj8Dq8+XVdu2Nv0IIySgEdQo3xVHps3Q5i3fLFsV4aiqzAiBhbgMDEd1uh8qZZ+lwhjkgokkOIv4xNJmyncdfUUzgB4oFMBtiu71Xumpz/P+cfUP+SlwFExwWW62r7b+LSPxqxn/gvMZ5z9C16t15UbNlq+jbGJtco7p8wbYlL4alSyfWdeuu0j7JA3JFNuVAwtst7F7FhWBbPFNKIUORndWtLraFLmMu7KFVDDOzqkeaiN33YAW/r76wR4XDN/yN1z7hejPau06EddkS/6XThfcz1fI/4K736fO48vlxt2PXJYFaeUkFS8U15XE3428xdtn2kc8GQlf1vkIaNRRnOMvLTWrZbElEHeLWi1o0dlKPAh1MVgbbVquPJ5+Cr8LU5/H/+I2QlHIU2ClXM9G8v7Rr7oc/hozfUUgsPnb3D+I+7WF8kNO92GY0SNvuxiE+2Bt8prVJTkzE64sfOstxuwfxUUoyk8VjcTlsqe2qITSFoSj6Epd4KsT6BZOWmtgE3hBfir8IzZDwgV4ZTZvD8VvPHERo8v+vL1DASHTz/i9OlKueHDjK5Rnx/JB1Vb1ioXdBra16dmt7dgik10yA/FwJSVY6XjA3oy4SqM2frqDPPSRMex9qs3XQtoWxMj7/Er8GWYsXgjaVz4OYumP2+9kbxvny/6kvWsEBw+fcb5bInc8APdhpOSs01tEqIkoiZjbAqKMruLbJYddHuHFRIyJcbdEdbl2sVLaySygunutBg96Y2/JjKRCdyHV+AEFtTvIpbKIXOamknYSiB6KV/0JetZITgcjjk5ZdaskBtWO86UF0ap6ozGXJk2WNiRUlCPFir66lzdm/SLSuK7EUdPz8f1z29Skq6F1fXg8+5UVR6bszncP4Tn4KUkkdJ8UFCY1zR1i8RmL/qQL3rlei4THG7OODlnKko4oI01kd3CaM08Ia18kC3GNoVaO9iDh+hWxSyTXFABXoau7Q6q9OxYg/OVEMw6jdbtSrJ9cBcewGmaZmg+bvkUnUUaGr+ZfnMH45Ivevl61hMcXsxYLFTu1hTm2zViCp7u0o5l+2PSUh9bDj6FgYypufBDhqK2+oXkiuHFHR3zfj+9PtA8oR0xnqX8qn+sx3bFODSbbF0X8EUvWQ8jBIcjo5bRmLOljDNtcqNtOe756h3l0VhKa9hDd2l1eqmsnh0MNMT/Cqnx6BInumhLT8luljzQ53RiJeA/0dxe5NK0o2fA1+GLXr6eNQWHNUOJssQaTRlGpLHKL9fD+IrQzTOMZS9fNQD4AnRNVxvTdjC+fJdcDDWQcyB00B0t9BDwTxXgaAfzDZ/DBXzRnfWMFRwuNqocOmX6OKNkY63h5n/fFcB28McVHqnXZVI27K0i4rDLNE9lDKV/rT+udVbD8dFFu2GGZ8mOt0kAXcoX3ZkIWVtw+MNf5NjR2FbivROHmhV1/pj2egv/fMGIOWTIWrV3Av8N9imV9IWml36H6cUjqEWNv9aNc+veb2sH46PRaHSuMBxvtW+twxctq0z+QsHhux8Q7rCY4Ct8lqsx7c6Sy0dl5T89rIeEuZKoVctIk1hNpfavER6yyH1Vvm3MbsUHy4ab4hWr/OZPcsRBphnaV65/ZcdYPNNwsjN/djlf9NqCw9U5ExCPcdhKxUgLSmfROpLp4WSUr8ojdwbncbvCf+a/YzRaEc6QOvXcGO256TXc5Lab9POvB+AWY7PigWYjzhifbovuunzRawsO24ZqQQAqguBtmpmPB7ysXJfyDDaV/aPGillgz1MdQg4u5MYaEtBNNHFjkRlSpd65lp4hd2AVPTfbV7FGpyIOfmNc/XVsPfg7vzaS/3nkvLL593ANLvMuRMGpQIhiF7kUEW9QDpAUbTWYBcbp4WpacHHY1aacqQyjGZS9HI3yCBT9kUZJhVOD+zUDvEH9ddR11fzPcTDQ5TlgB0KwqdXSavk9BC0pKp0WmcuowSw07VXmXC5guzSa4p0UvRw2lbDiYUx0ExJJRzWzi6Gm8cnEkfXXsdcG/M/jAJa0+bmCgdmQ9CYlNlSYZOKixmRsgiFxkrmW4l3KdFKv1DM8tk6WxPYJZhUUzcd8Kdtgrw/gkfXXDT7+avmfVak32qhtkg6NVdUS5wgkru1YzIkSduTW1FDwVWV3JQVJVuieTc0y4iDpFwc7/BvSalvKdQM8sv662cevz/+8sQVnjVAT0W2wLllw1JiMhJRxgDjCjLQsOzSFSgZqx7lAW1JW0e03yAD3asC+GD3NbQhbe+mN5GXH1F83KDOM4n/e5JIuH4NpdQARrFPBVptUNcjj4cVMcFSRTE2NpR1LEYbYMmfWpXgP9KejaPsLUhuvLCsVXznAG9dfx9SR1ud/3hZdCLHb1GMdPqRJgqDmm76mHbvOXDtiO2QPUcKo/TWkQ0i2JFXpBoo7vij1i1Lp3ADAo+qvG3V0rM//vFnnTE4hxd5Ka/Cor5YEdsLVJyKtDgVoHgtW11pWSjolPNMnrlrVj9Fv2Qn60twMwKPqr+N/wvr8z5tZcDsDrv06tkqyzESM85Ycv6XBWA2birlNCXrI6VbD2lx2L0vQO0QVTVVLH4SE67fgsfVXv8n7sz7/85Z7cMtbE6f088wSaR4kCkCm10s6pKbJhfqiUNGLq+0gLWC6eUAZFPnLjwqtKd8EwGvWX59t7iPW4X/eAN1svgRVSY990YZg06BD1ohLMtyFTI4pKTJsS9xREq9EOaPWiO2gpms7397x6nQJkbh+Fz2q/rqRROX6/M8bJrqlVW4l6JEptKeUFuMYUbtCQ7CIttpGc6MY93x1r1vgAnRXvY5cvwWPqb9uWQm+lP95QxdNMeWhOq1x0Db55C7GcUv2ZUuN6n8iKzsvOxibC//Yfs9Na8r2Rlz02vXXDT57FP/zJi66/EJSmsJKa8QxnoqW3VLQ+jZVUtJwJ8PNX1NQCwfNgdhhHD9on7PdRdrdGPF28rJr1F+3LBdeyv+8yYfLoMYet1vX4upNAjVvwOUWnlNXJXlkzk5Il6kqeoiL0C07qno+/CYBXq/+utlnsz7/Mzvy0tmI4zm4ag23PRN3t/CWryoUVJGm+5+K8RJ0V8Hc88/XHUX/HfiAq7t+BH+x6v8t438enWmdJwFA6ZINriLGKv/95f8lT9/FnyA1NMVEvQyaXuu+gz36f/DD73E4pwqpLcvm/o0Vle78n//+L/NPvoefp1pTJye6e4A/D082FERa5/opeH9zpvh13cNm19/4v/LDe5xMWTi8I0Ta0qKlK27AS/v3/r+/x/2GO9K2c7kVMonDpq7//jc5PKCxeNPpFVzaRr01wF8C4Pu76hXuX18H4LduTr79guuFD3n5BHfI+ZRFhY8w29TYhbbLi/bvBdqKE4fUgg1pBKnV3FEaCWOWyA+m3WpORZr/j+9TKJtW8yBTF2/ZEODI9/QavHkVdGFp/Pjn4Q+u5hXapsP5sOH+OXXA1LiKuqJxiMNbhTkbdJTCy4llEt6NnqRT4dhg1V3nbdrm6dYMecA1yTOL4PWTE9L5VzPFlLBCvlG58AhehnN4uHsAYinyJ+AZ/NkVvELbfOBUuOO5syBIEtiqHU1k9XeISX5bsimrkUUhnGDxourN8SgUsCZVtKyGbyGzHXdjOhsAvOAswSRyIBddRdEZWP6GZhNK/yjwew9ehBo+3jEADu7Ay2n8mDc+TS7awUHg0OMzR0LABhqLD4hJEh/BEGyBdGlSJoXYXtr+3HS4ijzVpgi0paWXtdruGTknXBz+11qT1Q2inxaTzQCO46P3lfLpyS4fou2PH/PupwZgCxNhGlj4IvUuWEsTkqMWm6i4xCSMc9N1RDQoCVcuGItJ/MRWefais+3synowi/dESgJjkilnWnBTGvRWmaw8oR15257t7CHmCf8HOn7cwI8+NQBXMBEmAa8PMRemrNCEhLGEhDQKcGZWS319BX9PFBEwGTbRBhLbDcaV3drFcDqk5kCTd2JF1Wp0HraqBx8U0wwBTnbpCadwBA/gTH/CDrcCs93LV8E0YlmmcyQRQnjBa8JESmGUfIjK/7fkaDJpmD2QptFNVJU1bbtIAjjWQizepOKptRjbzR9Kag6xZmMLLjHOtcLT3Tx9o/0EcTT1XN3E45u24AiwEypDJXihKjQxjLprEwcmRKclaDNZCVqr/V8mYWyFADbusiY5hvgFoU2vio49RgJLn5OsReRFN6tabeetiiy0V7KFHT3HyZLx491u95sn4K1QQSPKM9hNT0wMVvAWbzDSVdrKw4zRjZMyJIHkfq1VAVCDl/bUhNKlGq0zGr05+YAceXVPCttVk0oqjVwMPt+BBefx4yPtGVkUsqY3CHDPiCM5ngupUwCdbkpd8kbPrCWHhkmtIKLEetF2499eS1jZlIPGYnlcPXeM2KD9vLS0bW3ktYNqUllpKLn5ZrsxlIzxvDu5eHxzGLctkZLEY4PgSOg2IUVVcUONzUDBEpRaMoXNmUc0tFZrTZquiLyKxrSm3DvIW9Fil+AkhXu5PhEPx9mUNwqypDvZWdKlhIJQY7vn2OsnmBeOWnYZ0m1iwbbw1U60by5om47iHRV6fOgzjMf/DAZrlP40Z7syxpLK0lJ0gqaAK1c2KQKu7tabTXkLFz0sCftuwX++MyNeNn68k5Buq23YQhUh0SNTJa1ioQ0p4nUG2y0XilF1JqODqdImloPS4Bp111DEWT0jJjVv95uX9BBV7eB3bUWcu0acSVM23YZdd8R8UbQUxJ9wdu3oMuhdt929ME+mh6JXJ8di2RxbTi6TbrDquqV4aUKR2iwT6aZbyOwEXN3DUsWr8Hn4EhwNyHuXHh7/pdaUjtR7vnDh/d8c9xD/s5f501eQ1+CuDiCvGhk1AN/4Tf74RfxPwD3toLarR0zNtsnPzmS64KIRk861dMWCU8ArasG9T9H0ZBpsDGnjtAOM2+/LuIb2iIUGXNgl5ZmKD/Tw8TlaAuihaFP5yrw18v4x1898zIdP+DDAX1bM3GAMvPgRP/cJn3zCW013nrhHkrITyvYuwOUkcHuKlRSW5C6rzIdY4ppnF7J8aAJbQepgbJYBjCY9usGXDKQxq7RZfh9eg5d1UHMVATRaD/4BHK93/1iAgYZ/+jqPn8Dn4UExmWrpa3+ZOK6MvM3bjwfzxNWA2dhs8+51XHSPJiaAhGSpWevEs5xHLXcEGFXYiCONySH3fPWq93JIsBiSWvWyc3CAN+EcXoT7rCSANloPPoa31rt/5PUA/gp8Q/jDD3hyrjzlR8VkanfOvB1XPubt17vzxAfdSVbD1pzAnfgyF3ycadOTOTXhpEUoLC1HZyNGW3dtmjeXgr2r56JNmRwdNNWaQVBddd6rh4MhviEB9EFRD/7RGvePvCbwAL4Mx/D6M541hHO4D3e7g6PafdcZVw689z7NGTwo5om7A8sPhccT6qKcl9NJl9aM/9kX+e59Hh1yPqGuCCZxuITcsmNaJ5F7d0q6J3H48TO1/+M57085q2icdu2U+W36Ldllz9Agiv4YGljoEN908EzvDOrBF98/vtJwCC/BF2AG75xxEmjmMIcjxbjoaxqOK3/4hPOZzhMPBpYPG44CM0dTVm1LjLtUWWVz1Bcf8tEx0zs8O2A2YVHRxKYOiy/aOVoAaMu0i7ubu43njjmd4ibMHU1sIDHaQNKrZND/FZYdk54oCXetjq7E7IVl9eAL7t+oHnwXXtLx44czzoRFHBztYVwtH1d+NOMkupZ5MTM+gUmq90X+Bh9zjRlmaQ+m7YMqUL/veemcecAtOJ0yq1JnVlN27di2E0+Klp1tAJ4KRw1eMI7aJjsO3R8kPSI3fUFXnIOfdQe86sIIVtWDL7h//Ok6vj8vwDk08NEcI8zz7OhBy+WwalzZeZ4+0XniRfst9pAJqQHDGLzVQ2pheZnnv1OWhwO43/AgcvAEXEVVpa4db9sGvNK8wjaENHkfFQ4Ci5i7dqnQlPoLQrHXZDvO3BIXZbJOBrOaEbML6sFL798I4FhKihjHMsPjBUZYCMFr6nvaArxqXPn4lCa+cHfSa2cP27g3Z3ziYTRrcbQNGLQmGF3F3cBdzzzX7AILx0IB9rbwn9kx2G1FW3Inic+ZLIsVvKR8Zwfj0l1fkqo8LWY1M3IX14OX3r9RKTIO+d9XzAI8qRPGPn/4NC2n6o4rN8XJ82TOIvuVA8zLKUHRFgBCetlDZlqR1gLKjS39xoE7Bt8UvA6BxuEDjU3tFsEijgA+615tmZkXKqiEENrh41iLDDZNq4pKTWR3LZfnos81LOuNa15cD956vLMsJd1rqYp51gDUQqMYm2XsxnUhD2jg1DM7SeuJxxgrmpfISSXVIJIS5qJJSvJPEQ49DQTVIbYWJ9QWa/E2+c/oPK1drmC7WSfJRNKBO5Yjvcp7Gc3dmmI/Xh1kDTEuiSnWqQf37h+fTMhGnDf6dsS8SQfQWlqqwXXGlc/PEZ/SC5mtzIV0nAshlQdM/LvUtYutrEZ/Y+EAFtq1k28zQhOwLr1AIeANzhF8t9qzTdZf2qRKO6MWE9ohBYwibbOmrFtNmg3mcS+tB28xv2uKd/agYCvOP+GkSc+0lr7RXzyufL7QbkUpjLjEWFLqOIkAGu2B0tNlO9Eau2W1qcOUvVRgKzypKIQZ5KI3q0MLzqTNRYqiZOqmtqloIRlmkBHVpHmRYV6/HixbO6UC47KOFJnoMrVyr7wYz+SlW6GUaghYbY1I6kkxA2W1fSJokUdSh2LQ1GAimRGm0MT+uu57H5l7QgOWxERpO9moLRPgTtquWCfFlGlIjQaRly9odmzMOWY+IBO5tB4sW/0+VWGUh32qYk79EidWKrjWuiLpiVNGFWFRJVktyeXWmbgBBzVl8anPuXyNJlBJOlKLTgAbi/EYHVHxWiDaVR06GnHQNpJcWcK2jJtiCfG2sEHLzuI66sGrMK47nPIInPnu799935aOK2cvmvubrE38ZzZjrELCmXM2hM7UcpXD2oC3+ECVp7xtIuxptJ0jUr3sBmBS47TVxlvJ1Sqb/E0uLdvLj0lLr29ypdd/eMX3f6lrxGlKwKQxEGvw0qHbkbwrF3uHKwVENbIV2wZ13kNEF6zD+x24aLNMfDTCbDPnEikZFyTNttxWBXDaBuM8KtI2rmaMdUY7cXcUPstqTGvBGSrFWIpNMfbdea990bvAOC1YX0qbc6smDS1mPxSJoW4fwEXvjMmhlijDRq6qale6aJEuFGoppYDoBELQzLBuh/mZNx7jkinv0EtnUp50lO9hbNK57lZaMAWuWR5Yo9/kYwcYI0t4gWM47Umnl3YmpeBPqSyNp3K7s2DSAS/39KRuEN2bS4xvowV3dFRMx/VFcp2Yp8w2nTO9hCXtHG1kF1L4KlrJr2wKfyq77R7MKpFKzWlY9UkhYxyHWW6nBWPaudvEAl3CGcNpSXPZ6R9BbBtIl6cHL3gIBi+42CYXqCx1gfGWe7Ap0h3luyXdt1MKy4YUT9xSF01G16YEdWsouW9mgDHd3veyA97H+Ya47ZmEbqMY72oPztCGvK0onL44AvgC49saZKkWRz4veWljE1FHjbRJaWv6ZKKtl875h4CziFCZhG5rx7tefsl0aRT1bMHZjm8dwL/6u7wCRysaQblQoG5yAQN5zpatMNY/+yf8z+GLcH/Qn0iX2W2oEfXP4GvwQHuIL9AYGnaO3zqAX6946nkgqZNnUhx43DIdQtMFeOPrgy/y3Yd85HlJWwjLFkU3kFwq28xPnuPhMWeS+tDLV9Otllq7pQCf3uXJDN9wFDiUTgefHaiYbdfi3b3u8+iY6TnzhgehI1LTe8lcd7s1wJSzKbahCRxKKztTLXstGAiu3a6rPuQs5pk9TWAan5f0BZmGf7Ylxzzk/A7PAs4QPPPAHeFQ2hbFHszlgZuKZsJcUmbDC40sEU403cEjczstOEypa+YxevL4QBC8oRYqWdK6b7sK25tfE+oDZgtOQ2Jg8T41HGcBE6fTWHn4JtHcu9S7uYgU5KSCkl/mcnq+5/YBXOEr6lCUCwOTOM1taOI8mSxx1NsCXBEmLKbMAg5MkwbLmpBaFOPrNSlO2HnLiEqW3tHEwd8AeiQLmn+2gxjC3k6AxREqvKcJbTEzlpLiw4rNZK6oJdidbMMGX9FULKr0AkW+2qDEPBNNm5QAt2Ik2nftNWHetubosHLo2nG4vQA7GkcVCgVCgaDixHqo9UUn1A6OshapaNR/LPRYFV8siT1cCtJE0k/3WtaNSuUZYKPnsVIW0xXWnMUxq5+En4Kvw/MqQmVXnAXj9Z+9zM98zM/Agy7F/qqj2Nh67b8HjFnPP3iBn/tkpdzwEJX/whIcQUXOaikeliCRGUk7tiwF0rItwMEhjkZ309hikFoRAmLTpEXWuHS6y+am/KB/fM50aLEhGnSMwkpxzOov4H0AvgovwJ1iGzDLtJn/9BU+fAINfwUe6FHSLhu83viV/+/HrOePX+STT2B9uWGbrMHHLldRBlhS/CJQmcRxJFqZica01XixAZsYiH1uolZxLrR/SgxVIJjkpQP4PE9sE59LKLr7kltSBogS5tyszzH8Fvw8/AS8rNOg0xUS9fIaHwb+6et8Q/gyvKRjf5OusOzGx8evA/BP4IP11uN/grca5O0lcsPLJ5YjwI4QkJBOHa0WdMZYGxPbh2W2nR9v3WxEWqgp/G3+6VZbRLSAAZ3BhdhAaUL33VUSw9yjEsvbaQ9u4A/gGXwZXoEHOuU1GSj2chf+Mo+f8IcfcAxfIKVmyunRbYQVnoevwgfw3TXXcw++xNuP4fhyueEUNttEduRVaDttddoP0eSxLe2LENk6itYxlrxBNBYrNNKSQmeaLcm9c8UsaB5WyO6675yyQIAWSDpBVoA/gxmcwEvwoDv0m58UE7gHn+fJOa8/Ywan8EKRfjsopF83eCglX/Sfr7OeaRoQfvt1CGvIDccH5BCvw1sWIzRGC/66t0VTcLZQZtm6PlAasbOJ9iwWtUo7biktTSIPxnR24jxP1ZKaqq+2RcXM9OrBAm/AAs7hDJ5bNmGb+KIfwCs8a3jnjBrOFeMjHSCdbKr+2uOLfnOd9eiA8Hvvwwq54VbP2OqwkB48Ytc4YEOiH2vTXqodabfWEOzso4qxdbqD5L6tbtNPECqbhnA708DZH4QOJUXqScmUlks7Ot6FBuZw3n2mEbaUX7kDzxHOOQk8nKWMzAzu6ZZ8sOFw4RK+6PcuXo9tB4SbMz58ApfKDXf3szjNIIbGpD5TKTRxGkEMLjLl+K3wlWXBsCUxIDU+jbOiysESqAy1MGUJpXgwbTWzNOVEziIXZrJ+VIztl1PUBxTSo0dwn2bOmfDRPD3TRTGlfbCJvO9KvuhL1hMHhB9wPuPRLGHcdOWG2xc0U+5bQtAJT0nRTewXL1pgk2+rZAdeWmz3jxAqfNQQdzTlbF8uJ5ecEIWvTkevAHpwz7w78QujlD/Lr491bD8/1vhM2yrUQRrWXNQY4fGilfctMWYjL72UL/qS9eiA8EmN88nbNdour+PBbbAjOjIa4iBhfFg6rxeKdEGcL6p3EWR1Qq2Qkhs2DrnkRnmN9tG2EAqmgPw6hoL7Oza7B+3SCrR9tRftko+Lsf2F/mkTndN2LmzuMcKTuj/mX2+4Va3ki16+nnJY+S7MefpkidxwnV+4wkXH8TKnX0tsYzYp29DOOoSW1nf7nTh2akYiWmcJOuTidSaqESrTYpwjJJNVGQr+rLI7WsqerHW6Kp/oM2pKuV7T1QY9gjqlZp41/WfKpl56FV/0kvXQFRyeQ83xaTu5E8p5dNP3dUF34ihyI3GSpeCsywSh22ZJdWto9winhqifb7VRvgktxp13vyjrS0EjvrRfZ62uyqddSWaWYlwTPAtJZ2oZ3j/Sgi/mi+6vpzesfAcWNA0n8xVyw90GVFGuZjTXEQy+6GfLGLMLL523f5E0OmxVjDoOuRiH91RKU+vtoCtH7TgmvBLvtFXWLW15H9GTdVw8ow4IlRLeHECN9ym1e9K0I+Cbnhgv4Yu+aD2HaQJ80XDqOzSGAV4+4yCqBxrsJAX6ZTIoX36QnvzhhzzMfFW2dZVLOJfo0zbce5OvwXMFaZ81mOnlTVXpDZsQNuoYWveketKb5+6JOOsgX+NTm7H49fUTlx+WLuWL7qxnOFh4BxpmJx0p2gDzA/BUARuS6phR+pUsY7MMboAHx5xNsSVfVZcYSwqCKrqon7zM+8ecCkeS4nm3rINuaWvVNnMRI1IRpxTqx8PZUZ0Br/UEduo3B3hNvmgZfs9gQPj8vIOxd2kndir3awvJ6BLvoUuOfFWNYB0LR1OQJoUySKb9IlOBx74q1+ADC2G6rOdmFdJcD8BkfualA+BdjOOzP9uUhGUEX/TwhZsUduwRr8wNuXKurCixLBgpQI0mDbJr9dIqUuV+92ngkJZ7xduCk2yZKbfWrH1VBiTg9VdzsgRjW3CVXCvAwDd+c1z9dWw9+B+8MJL/eY15ZQ/HqvTwVdsZn5WQsgRRnMaWaecu3jFvMBEmgg+FJFZsnSl0zjB9OqPYaBD7qmoVyImFvzi41usesV0julaAR9dfR15Xzv9sEruRDyk1nb+QaLU67T885GTls6YgcY+UiMa25M/pwGrbCfzkvR3e0jjtuaFtnwuagHTSb5y7boBH119HXhvwP487jJLsLJ4XnUkHX5sLbS61dpiAXRoZSCrFJ+EjpeU3puVfitngYNo6PJrAigKktmwjyQdZpfq30mmtulaAx9Zfx15Xzv+cyeuiBFUs9zq8Kq+XB9a4PVvph3GV4E3y8HENJrN55H1X2p8VyqSKwVusJDKzXOZzplWdzBUFK9e+B4+uv468xvI/b5xtSAkBHQaPvtqWzllVvEOxPbuiE6+j2pvjcKsbvI7txnRErgfH7LdXqjq0IokKzga14GzQ23SSbCQvO6r+Or7SMIr/efOkkqSdMnj9mBx2DRsiY29Uj6+qK9ZrssCKaptR6HKURdwUYeUWA2kPzVKQO8ku2nU3Anhs/XWkBx3F/7wJtCTTTIKftthue1ty9xvNYLY/zo5KSbIuKbXpbEdSyeRyYdAIwKY2neyoc3+k1XUaufYga3T9daMUx/r8z1s10ITknIO0kuoMt+TB8jK0lpayqqjsJ2qtXAYwBU932zinimgmd6mTRDnQfr88q36NAI+tv24E8Pr8zxtasBqx0+xHH9HhlrwsxxNUfKOHQaZBITNf0uccj8GXiVmXAuPEAKSdN/4GLHhs/XWj92dN/uetNuBMnVR+XWDc25JLjo5Mg5IZIq226tmCsip2zZliL213YrTlL2hcFjpCduyim3M7/eB16q/blQsv5X/esDRbtJeabLIosWy3ycavwLhtxdWzbMmHiBTiVjJo6lCLjXZsi7p9PEPnsq6X6wd4bP11i0rD5fzPm/0A6brrIsllenZs0lCJlU4abakR59enZKrKe3BZihbTxlyZ2zl1+g0wvgmA166/bhwDrcn/7Ddz0eWZuJvfSESug6NzZsox3Z04FIxz0mUjMwVOOVTq1CQ0AhdbBGVdjG/CgsfUX7esJl3K/7ytWHRv683praW/8iDOCqWLLhpljDY1ZpzK75QiaZoOTpLKl60auHS/97oBXrv+umU9+FL+5+NtLFgjqVLCdbmj7pY5zPCPLOHNCwXGOcLquOhi8CmCWvbcuO73XmMUPab+ug3A6/A/78Bwe0bcS2+tgHn4J5pyS2WbOck0F51Vq3LcjhLvZ67p1ABbaL2H67bg78BfjKi/jr3+T/ABV3ilLmNXTI2SpvxWBtt6/Z//D0z/FXaGbSBgylzlsEGp+5//xrd4/ae4d8DUUjlslfIYS3t06HZpvfQtvv0N7AHWqtjP2pW08QD/FLy//da38vo8PNlKHf5y37Dxdfe/oj4kVIgFq3koLReSR76W/bx//n9k8jonZxzWTANVwEniDsg87sOSd/z7//PvMp3jQiptGVWFX2caezzAXwfgtzYUvbr0iozs32c3Uge7varH+CNE6cvEYmzbPZ9hMaYDdjK4V2iecf6EcEbdUDVUARda2KzO/JtCuDbNQB/iTeL0EG1JSO1jbXS+nLxtPMDPw1fh5+EPrgSEKE/8Gry5A73ui87AmxwdatyMEBCPNOCSKUeRZ2P6Myb5MRvgCHmA9ywsMifU+AYXcB6Xa5GibUC5TSyerxyh0j6QgLVpdyhfArRTTLqQjwe4HOD9s92D4Ap54odXAPBWLAwB02igG5Kkc+piN4lvODIFGAZgT+EO4Si1s7fjSR7vcQETUkRm9O+MXyo9OYhfe4xt9STQ2pcZRLayCV90b4D3jR0DYAfyxJ+eywg2IL7NTMXna7S/RpQ63JhWEM8U41ZyQGjwsVS0QBrEKLu8xwZsbi4wLcCT+OGidPIOCe1PiSc9Qt+go+vYqB7cG+B9d8cAD+WJPz0Am2gxXgU9IneOqDpAAXOsOltVuMzpdakJXrdPCzXiNVUpCeOos5cxnpQT39G+XVLhs1osQVvJKPZyNq8HDwd4d7pNDuWJPxVX7MSzqUDU6gfadKiNlUFTzLeFHHDlzO4kpa7aiKhBPGKwOqxsBAmYkOIpipyXcQSPlRTf+Tii0U3EJGaZsDER2qoB3h2hu0qe+NNwUooYU8y5mILbJe6OuX+2FTKy7bieTDAemaQyQ0CPthljSWO+xmFDIYiESjM5xKd6Ik5lvLq5GrQ3aCMLvmCA9wowLuWJb9xF59hVVP6O0CrBi3ZjZSNOvRy+I6klNVRJYRBaEzdN+imiUXQ8iVF8fsp+W4JXw7WISW7fDh7lptWkCwZ4d7QTXyBPfJMYK7SijjFppGnlIVJBJBYj7eUwtiP1IBXGI1XCsjNpbjENVpSAJ2hq2LTywEly3hUYazt31J8w2+aiLx3g3fohXixPfOMYm6zCGs9LVo9MoW3MCJE7R5u/WsOIjrqBoHUO0bJE9vxBpbhsd3+Nb4/vtPCZ4oZYCitNeYuC/8UDvDvy0qvkiW/cgqNqRyzqSZa/s0mqNGjtKOoTm14zZpUauiQgVfqtQiZjq7Q27JNaSK5ExRcrGCXO1FJYh6jR6CFqK7bZdQZ4t8g0rSlPfP1RdBtqaa9diqtzJkQ9duSryi2brQXbxDwbRUpFMBHjRj8+Nt7GDKgvph9okW7LX47gu0SpGnnFQ1S1lYldOsC7hYteR574ZuKs7Ei1lBsfdz7IZoxzzCVmmVqaSySzQbBVAWDek+N4jh9E/4VqZrJjPwiv9BC1XcvOWgO8275CVyBPvAtTVlDJfZkaZGU7NpqBogAj/xEHkeAuJihWYCxGN6e8+9JtSegFXF1TrhhLGP1fak3pebgPz192/8gB4d/6WT7+GdYnpH7hH/DJzzFiYPn/vjW0SgNpTNuPIZoAEZv8tlGw4+RLxy+ZjnKa5NdFoC7UaW0aduoYse6+bXg1DLg6UfRYwmhGEjqPvF75U558SANrElK/+MdpXvmqBpaXOa/MTZaa1DOcSiLaw9j0NNNst3c+63c7EKTpkvKHzu6bPbP0RkuHAVcbRY8ijP46MIbQeeT1mhA+5PV/inyDdQipf8LTvMXbwvoDy7IruDNVZKTfV4CTSRUYdybUCnGU7KUTDxLgCknqUm5aAW6/1p6eMsOYsphLzsHrE0Y/P5bQedx1F/4yPHnMB3/IOoTU9+BL8PhtjuFKBpZXnYNJxTuv+2XqolKR2UQgHhS5novuxVySJhBNRF3SoKK1XZbbXjVwWNyOjlqWJjrWJIy+P5bQedyldNScP+HZ61xKSK3jyrz+NiHG1hcOLL/+P+PDF2gOkekKGiNWKgJ+8Z/x8Iv4DdQHzcpZyF4v19I27w9/yPGDFQvmEpKtqv/TLiWMfn4sofMm9eAH8Ao0zzh7h4sJqYtxZd5/D7hkYPneDzl5idlzNHcIB0jVlQ+8ULzw/nc5/ojzl2juE0apD7LRnJxe04dMz2iOCFNtGFpTuXA5AhcTRo8mdN4kz30nVjEC4YTZQy4gpC7GlTlrePKhGsKKgeXpCYeO0MAd/GH7yKQUlXPLOasOH3FnSphjHuDvEu4gB8g66oNbtr6eMbFIA4fIBJkgayoXriw2XEDQPJrQeROAlY6aeYOcMf+IVYTU3XFlZufMHinGywaW3YLpObVBAsbjF4QJMsVUSayjk4voPsHJOQfPWDhCgDnmDl6XIRerD24HsGtw86RMHOLvVSHrKBdeVE26gKB5NKHzaIwLOmrqBWJYZDLhASG16c0Tn+CdRhWDgWXnqRZUTnPIHuMJTfLVpkoYy5CzylHVTGZMTwkGAo2HBlkQplrJX6U+uF1wZz2uwS1SQ12IqWaPuO4baZaEFBdukksJmkcTOm+YJSvoqPFzxFA/YUhIvWxcmSdPWTWwbAKVp6rxTtPFUZfKIwpzm4IoMfaYQLWgmlG5FME2gdBgm+J7J+rtS/XBbaVLsR7bpPQnpMFlo2doWaVceHk9+MkyguZNCJ1He+kuHTWyQAzNM5YSUg/GlTk9ZunAsg1qELVOhUSAK0LABIJHLKbqaEbHZLL1VA3VgqoiOKXYiS+HRyaEKgsfIqX64HYWbLRXy/qWoylIV9gudL1OWBNgBgTNmxA6b4txDT4gi3Ri7xFSLxtXpmmYnzAcWDZgY8d503LFogz5sbonDgkKcxGsWsE1OI+rcQtlgBBCSOKD1mtqYpIU8cTvBmAT0yZe+zUzeY92fYjTtGipXLhuR0ePoHk0ofNWBX+lo8Z7pAZDk8mEw5L7dVyZZoE/pTewbI6SNbiAL5xeygW4xPRuLCGbhcO4RIeTMFYHEJkYyEO9HmJfXMDEj/LaH781wHHZEtqSQ/69UnGpzH7LKIAZEDSPJnTesJTUa+rwTepI9dLJEawYV+ZkRn9g+QirD8vF8Mq0jFQ29js6kCS3E1+jZIhgPNanHdHFqFvPJLHqFwQqbIA4jhDxcNsOCCQLDomaL/dr5lyJaJU6FxPFjO3JOh3kVMcROo8u+C+jo05GjMF3P3/FuDLn5x2M04xXULPwaS6hBYki+MrMdZJSgPHlcB7nCR5bJ9Kr5ACUn9jk5kivdd8tk95SOGrtqu9lr2IhK65ZtEl7ZKrp7DrqwZfRUSN1el7+7NJxZbywOC8neNKTch5vsTEMNsoCCqHBCqIPRjIPkm0BjvFODGtto99rCl+d3wmHkW0FPdpZtC7MMcVtGFQjJLX5bdQ2+x9ypdc313uj8xlsrfuLgWXz1cRhZvJYX0iNVBRcVcmCXZs6aEf3RQF2WI/TcCbKmGU3IOoDJGDdDub0+hYckt6PlGu2BcxmhbTdj/klhccLGJMcqRjMJP1jW2ETqLSWJ/29MAoORluJ+6LPffBZbi5gqi5h6catQpmOT7/OFf5UorRpLzCqcMltBLhwd1are3kztrSzXO0LUbXRQcdLh/RdSZ+swRm819REDrtqzC4es6Gw4JCKlSnjYVpo0xeq33PrADbFLL3RuCmObVmPN+24kfa+AojDuM4umKe2QwCf6EN906HwjujaitDs5o0s1y+k3lgbT2W2i7FJdnwbLXhJUBq/9liTctSmFC/0OqUinb0QddTWamtjbHRFuWJJ6NpqZ8vO3fZJ37Db+2GkaPYLGHs7XTTdiFQJ68SkVJFVmY6McR5UycflNCsccHFaV9FNbR4NttLxw4pQ7wJd066Z0ohVbzihaxHVExd/ay04oxUKWt+AsdiQ9OUyZ2krzN19IZIwafSTFgIBnMV73ADj7V/K8u1MaY2sJp2HWm0f41tqwajEvdHWOJs510MaAqN4aoSiPCXtN2KSi46dUxHdaMquar82O1x5jqhDGvqmoE9LfxcY3zqA7/x3HA67r9ZG4O6Cuxu12/+TP+eLP+I+HErqDDCDVmBDO4larujNe7x8om2rMug0MX0rL1+IWwdwfR+p1TNTyNmVJ85ljWzbWuGv8/C7HD/izjkHNZNYlhZcUOKVzKFUxsxxN/kax+8zPWPSFKw80rJr9Tizyj3o1gEsdwgWGoxPezDdZ1TSENE1dLdNvuKL+I84nxKesZgxXVA1VA1OcL49dFlpFV5yJMhzyCmNQ+a4BqusPJ2bB+xo8V9u3x48VVIEPS/mc3DvAbXyoYr6VgDfh5do5hhHOCXMqBZUPhWYbWZECwVJljLgMUWOCB4MUuMaxGNUQDVI50TQ+S3kFgIcu2qKkNSHVoM0SHsgoZxP2d5HH8B9woOk4x5bPkKtAHucZsdykjxuIpbUrSILgrT8G7G5oCW+K0990o7E3T6AdW4TilH5kDjds+H64kS0mz24grtwlzDHBJqI8YJQExotPvoC4JBq0lEjjQkyBZ8oH2LnRsQ4Hu1QsgDTJbO8fQDnllitkxuVskoiKbRF9VwzMDvxHAdwB7mD9yCplhHFEyUWHx3WtwCbSMMTCUCcEmSGlg4gTXkHpZXWQ7kpznK3EmCHiXInqndkQjunG5kxTKEeGye7jWz9cyMR2mGiFQ15ENRBTbCp+Gh86vAyASdgmJq2MC6hoADQ3GosP0QHbnMHjyBQvQqfhy/BUbeHd5WY/G/9LK/8Ka8Jd7UFeNWEZvzPb458Dn8DGLOe3/wGL/4xP+HXlRt+M1PE2iLhR8t+lfgxsuh7AfO2AOf+owWhSZRYQbd622hbpKWKuU+XuvNzP0OseRDa+mObgDHJUSc/pKx31QdKffQ5OIJpt8GWjlgTwMc/w5MPCR/yl1XC2a2Yut54SvOtMev55Of45BOat9aWG27p2ZVORRvnEk1hqWMVUmqa7S2YtvlIpspuF1pt0syuZS2NV14mUidCSfzQzg+KqvIYCMljIx2YK2AO34fX4GWdu5xcIAb8MzTw+j/lyWM+Dw/gjs4GD6ehNgA48kX/AI7XXM/XAN4WHr+9ntywqoCakCqmKP0rmQrJJEErG2Upg1JObr01lKQy4jskWalKYfJ/EDLMpjNSHFEUAde2fltaDgmrNaWQ9+AAb8I5vKjz3L1n1LriB/BXkG/wwR9y/oRX4LlioHA4LzP2inzRx/DWmutRweFjeP3tNeSGlaE1Fde0OS11yOpmbIp2u/jF1n2RRZviJM0yBT3IZl2HWImKjQOxIyeU325b/qWyU9Moj1o07tS0G7qJDoGHg5m8yeCxMoEH8GU45tnrNM84D2l297DQ9t1YP7jki/7RmutRweEA77/HWXOh3HCxkRgldDQkAjNTMl2Iloc1qN5JfJeeTlyTRzxURTdn1Ixv2uKjs12AbdEWlBtmVdk2k7FFwj07PCZ9XAwW3dG+8xKzNFr4EnwBZpy9Qzhh3jDXebBpYcpuo4fQ44u+fD1dweEnHzI7v0xuuOALRUV8rXpFyfSTQYkhd7IHm07jpyhlkCmI0ALYqPTpUxXS+z4jgDj1Pflvmz5ecuItpIBxyTHpSTGWd9g1ApfD/bvwUhL4nT1EzqgX7cxfCcNmb3mPL/qi9SwTHJ49oj5ZLjccbTG3pRmlYi6JCG0mQrAt1+i2UXTZ2dv9IlQpN5naMYtviaXlTrFpoMsl3bOAFEa8sqPj2WCMrx3Yjx99qFwO59Aw/wgx+HlqNz8oZvA3exRDvuhL1jMQHPaOJ0+XyA3fp1OfM3qObEVdhxjvynxNMXQV4+GJyvOEFqeQBaIbbO7i63rpxCltdZShPFxkjM2FPVkn3TG+Rp9pO3l2RzFegGfxGDHIAh8SteR0C4HopXzRF61nheDw6TFN05Ebvq8M3VKKpGjjO6r7nhudTEGMtYM92HTDaR1FDMXJ1eThsbKfywyoWwrzRSXkc51flG3vIid62h29bIcFbTGhfV+faaB+ohj7dPN0C2e2lC96+XouFByen9AsunLDJZ9z7NExiUc0OuoYW6UZkIyx2YUR2z6/TiRjyKMx5GbbjLHvHuf7YmtKghf34LJfx63Yg8vrvN2zC7lY0x0tvKezo4HmGYDU+Gab6dFL+KI761lDcNifcjLrrr9LWZJctG1FfU1uwhoQE22ObjdfkSzY63CbU5hzs21WeTddH2BaL11Gi7lVdlxP1nkxqhnKhVY6knS3EPgVGg1JpN5cP/hivujOelhXcPj8HC/LyI6MkteVjlolBdMmF3a3DbsuAYhL44dxzthWSN065xxUd55Lmf0wRbOYOqH09/o9WbO2VtFdaMb4qBgtFJoT1SqoN8wPXMoXLb3p1PUEhxfnnLzGzBI0Ku7FxrKsNJj/8bn/H8fPIVOd3rfrklUB/DOeO+nkghgSPzrlPxluCMtOnDL4Yml6dK1r3vsgMxgtPOrMFUZbEUbTdIzii5beq72G4PD0DKnwjmBULUVFmy8t+k7fZ3pKc0Q4UC6jpVRqS9Umv8bxw35flZVOU1X7qkjnhZlsMbk24qQ6Hz7QcuL6sDC0iHHki96Uh2UdvmgZnjIvExy2TeJdMDZNSbdZyAHe/Yd1xsQhHiKzjh7GxQ4yqMPaywPkjMamvqrYpmO7Knad+ZQC5msCuAPWUoxrxVhrGv7a+KLXFhyONdTMrZ7ke23qiO40ZJUyzgYyX5XyL0mV7NiUzEs9mjtbMN0dERqwyAJpigad0B3/zRV7s4PIfXSu6YV/MK7+OrYe/JvfGMn/PHJe2fyUdtnFrKRNpXV0Y2559aWPt/G4BlvjTMtXlVIWCnNyA3YQBDmYIodFz41PvXPSa6rq9lWZawZ4dP115HXV/M/tnFkkrBOdzg6aP4pID+MZnTJ1SuuB6iZlyiox4HT2y3YBtkUKWooacBQUDTpjwaDt5poBHl1/HXltwP887lKKXxNUEyPqpGTyA699UqY/lt9yGdlUKra0fFWS+36iylVWrAyd7Uw0CZM0z7xKTOduznLIjG2Hx8cDPLb+OvK6Bv7n1DYci4CxUuRxrjBc0bb4vD3rN5Zz36ntLb83eVJIB8LiIzCmn6SMPjlX+yNlTjvIGjs+QzHPf60Aj62/jrzG8j9vYMFtm1VoRWCJdmw7z9N0t+c8cxZpPeK4aTRicS25QhrVtUp7U578chk4q04Wx4YoQSjFryUlpcQ1AbxZ/XVMknIU//OGl7Q6z9Zpxi0+3yFhSkjUDpnCIUhLWVX23KQ+L9vKvFKI0ZWFQgkDLvBoylrHNVmaw10zwCPrr5tlodfnf94EWnQ0lFRWy8pW9LbkLsyUVDc2NSTHGDtnD1uMtchjbCeb1mpxFP0YbcClhzdLu6lfO8Bj6q+bdT2sz/+8SZCV7VIxtt0DUn9L7r4cLYWDSXnseEpOGFuty0qbOVlS7NNzs5FOGJUqQpl2Q64/yBpZf90sxbE+//PGdZ02HSipCbmD6NItmQ4Lk5XUrGpDMkhbMm2ZVheNYV+VbUWTcv99+2NyX1VoafSuC+AN6q9bFIMv5X/eagNWXZxEa9JjlMwNWb00akGUkSoepp1/yRuuqHGbUn3UdBSTxBU6SEVklzWRUkPndVvw2PrrpjvxOvzPmwHc0hpmq82npi7GRro8dXp0KXnUQmhZbRL7NEVp1uuZmO45vuzKsHrktS3GLWXODVjw+vXXLYx4Hf7njRPd0i3aoAGX6W29GnaV5YdyDj9TFkakje7GHYzDoObfddHtOSpoi2SmzJHrB3hM/XUDDEbxP2/oosszcRlehWXUvzHv4TpBVktHqwenFo8uLVmy4DKLa5d3RtLrmrM3aMFr1183E4sewf+85VWeg1c5ag276NZrM9IJVNcmLEvDNaV62aq+14IAOGFsBt973Ra8Xv11YzXwNfmft7Jg2oS+XOyoC8/cwzi66Dhmgk38kUmP1CUiYWOX1bpD2zWXt2FCp7uq8703APAa9dfNdscR/M/bZLIyouVxqJfeWvG9Je+JVckHQ9+CI9NWxz+blX/KYYvO5n2tAP/vrlZ7+8/h9y+9qeB/Hnt967e5mevX10rALDWK//FaAT5MXdBXdP0C/BAes792c40H+AiAp1e1oH8HgH94g/Lttx1gp63op1eyoM/Bvw5/G/7xFbqJPcCXnmBiwDPb/YKO4FX4OjyCb289db2/Noqicw4i7N6TVtoz8tNwDH+8x/i6Ae7lmaQVENzJFb3Di/BFeAwz+Is9SjeQySpPqbLFlNmyz47z5a/AF+AYFvDmHqibSXTEzoT4Gc3OALaqAP4KPFUJ6n+1x+rGAM6Zd78bgJ0a8QN4GU614vxwD9e1Amy6CcskNrczLx1JIp6HE5UZD/DBHrFr2oNlgG4Odv226BodoryjGJ9q2T/AR3vQrsOCS0ctXZi3ruLlhpFDJYl4HmYtjQCP9rhdn4suySLKDt6wLcC52h8xPlcjju1fn+yhuw4LZsAGUuo2b4Fx2UwQu77uqRHXGtg92aN3tQCbFexc0uk93vhTXbct6y7MulLycoUljx8ngDMBg1tvJjAazpEmOtxlzclvj1vQf1Tx7QlPDpGpqgtdSKz/d9/hdy1vTfFHSmC9dGDZbLiezz7Ac801HirGZsWjydfZyPvHXL/Y8Mjzg8BxTZiuwKz4Eb8sBE9zznszmjvFwHKPIWUnwhqfVRcd4Ck0K6ate48m1oOfrX3/yOtvAsJ8zsPAM89sjnddmuLuDPjX9Bu/L7x7xpMzFk6nWtyQfPg278Gn4Aekz2ZgOmU9eJ37R14vwE/BL8G3aibCiWMWWDQ0ZtkPMnlcGeAu/Ag+8ZyecU5BPuy2ILD+sQqyZhAKmn7XZd+jIMTN9eBL7x95xVLSX4On8EcNlXDqmBlqS13jG4LpmGbkF/0CnOi3H8ETOIXzmnmtb0a16Tzxj1sUvQCBiXZGDtmB3KAefPH94xcUa/6vwRn80GOFyjEXFpba4A1e8KQfFF+259tx5XS4egYn8fQsLGrqGrHbztr+uByTahWuL1NUGbDpsnrwBfePPwHHIf9X4RnM4Z2ABWdxUBlqQ2PwhuDxoS0vvqB1JzS0P4h2nA/QgTrsJFn+Y3AOjs9JFC07CGWX1oNX3T/yHOzgDjwPn1PM3g9Jk9lZrMEpxnlPmBbjyo2+KFXRU52TJM/2ALcY57RUzjObbjqxVw++4P6RAOf58pcVsw9Daje3htriYrpDOonre3CudSe6bfkTEgHBHuDiyu5MCsc7BHhYDx7ePxLjqigXZsw+ijMHFhuwBmtoTPtOxOrTvYJDnC75dnUbhfwu/ZW9AgYd+peL68HD+0emKquiXHhWjJg/UrkJYzuiaL3E9aI/ytrCvAd4GcYZMCkSQxfUg3v3j8c4e90j5ZTPdvmJJGHnOCI2nHS8081X013pHuBlV1gB2MX1YNmWLHqqGN/TWmG0y6clJWthxNUl48q38Bi8vtMKyzzpFdSDhxZ5WBA5ZLt8Jv3895DduBlgbPYAj8C4B8hO68FDkoh5lydC4FiWvBOVqjYdqjiLv92t8yPDjrDaiHdUD15qkSURSGmXJwOMSxWAXYwr3zaAufJ66l+94vv3AO+vPcD7aw/w/toDvL/2AO+vPcD7aw/wHuD9tQd4f+0B3l97gPfXHuD9tQd4f+0B3l97gG8LwP8G/AL8O/A5OCq0Ys2KIdv/qOIXG/4mvFAMF16gZD+2Xvu/B8as5+8bfllWyg0zaNO5bfXj6vfhhwD86/Aq3NfRS9t9WPnhfnvCIw/CT8GLcFTMnpntdF/z9V+PWc/vWoIH+FL3Znv57PitcdGP4R/C34avw5fgRVUInCwbsn1yyA8C8zm/BH8NXoXnVE6wVPjdeCI38kX/3+Ct9dbz1pTmHFRu+Hm4O9Ch3clr99negxfwj+ER/DR8EV6B5+DuQOnTgUw5rnkY+FbNU3gNXh0o/JYTuWOvyBf9FvzX663HH/HejO8LwAl8Hl5YLTd8q7sqA3wbjuExfAFegQdwfyDoSkWY8swzEf6o4Qyewefg+cHNbqMQruSL/u/WWc+E5g7vnnEXgDmcDeSGb/F4cBcCgT+GGRzDU3hZYburAt9TEtHgbM6JoxJ+6NMzzTcf6c2bycv2+KK/f+l6LBzw5IwfqZJhA3M472pWT/ajKxnjv4AFnMEpnBTPND6s2J7qHbPAqcMK74T2mZ4VGB9uJA465It+/eL1WKhYOD7xHOkr1ajK7d0C4+ke4Hy9qXZwpgLr+Znm/uNFw8xQOSy8H9IzjUrd9+BIfenYaylf9FsXr8fBAadnPIEDna8IBcwlxnuA0/Wv6GAWPd7dDIKjMdSWueAsBj4M7TOd06qBbwDwKr7oleuxMOEcTuEZTHWvDYUO7aHqAe0Bbq+HEFRzOz7WVoTDQkVds7A4sIIxfCQdCefFRoIOF/NFL1mPab/nvOakSL/Q1aFtNpUb/nFOVX6gzyg/1nISyDfUhsokIzaBR9Kxm80s5mK+6P56il1jXic7nhQxsxSm3OwBHl4fFdLqi64nDQZvqE2at7cWAp/IVvrN6/BFL1mPhYrGMBfOi4PyjuSGf6wBBh7p/FZTghCNWGgMzlBbrNJoPJX2mW5mwZfyRffXo7OFi5pZcS4qZUrlViptrXtw+GQoyhDPS+ANjcGBNRiLCQDPZPMHuiZfdFpPSTcQwwKYdRNqpkjm7AFeeT0pJzALgo7g8YYGrMHS0iocy+YTm2vyRUvvpXCIpQ5pe666TJrcygnScUf/p0NDs/iAI/nqDHC8TmQT8x3NF91l76oDdQGwu61Z6E0ABv7uO1dbf/37Zlv+Zw/Pbh8f1s4Avur6657/+YYBvur6657/+YYBvur6657/+YYBvur6657/+aYBvuL6657/+VMA8FXWX/f8zzcN8BXXX/f8zzcNMFdbf93zP38KLPiK6697/uebtuArrr/u+Z9vGmCusP6653/+1FjwVdZf9/zPN7oHX339dc//fNMu+irrr3v+50+Bi+Zq6697/uebA/jz8Pudf9ht/fWv517J/XUzAP8C/BAeX9WCDrUpZ3/dEMBxgPcfbtTVvsYV5Yn32u03B3Ac4P3b8I+vxNBKeeL9dRMAlwO83959qGO78sT769oB7g3w/vGVYFzKE++v6wV4OMD7F7tckFkmT7y/rhHgpQO8b+4Y46XyxPvrugBeNcB7BRiX8sT767oAvmCA9woAHsoT76+rBJjLBnh3txOvkifeX1dswZcO8G6N7sXyxPvr6i340gHe3TnqVfLE++uKAb50gHcXLnrX8sR7gNdPRqwzwLu7Y/FO5Yn3AK9jXCMGeHdgxDuVJ75VAI8ljP7PAb3/RfjcZfePHBB+79dpfpH1CanN30d+mT1h9GqAxxJGM5LQeeQ1+Tb+EQJrElLb38VHQ94TRq900aMIo8cSOo+8Dp8QfsB8zpqE1NO3OI9Zrj1h9EV78PqE0WMJnUdeU6E+Jjyk/hbrEFIfeWbvId8H9oTRFwdZaxJGvziW0Hn0gqYB/wyZ0PwRlxJST+BOw9m77Amj14ii1yGM/txYQudN0qDzGe4EqfA/5GJCagsHcPaEPWH0esekSwmjRxM6b5JEcZ4ww50ilvAOFxBSx4yLW+A/YU8YvfY5+ALC6NGEzhtmyZoFZoarwBLeZxUhtY4rc3bKnjB6TKJjFUHzJoTOozF2YBpsjcyxDgzhQ1YRUse8+J4wenwmaylB82hC5w0zoRXUNXaRBmSMQUqiWSWkLsaVqc/ZE0aPTFUuJWgeTei8SfLZQeMxNaZSIzbII4aE1Nmr13P2hNHjc9E9guYNCZ032YlNwESMLcZiLQHkE4aE1BFg0yAR4z1h9AiAGRA0jyZ03tyIxWMajMPWBIsxYJCnlITU5ShiHYdZ94TR4wCmSxg9jtB5KyPGYzymAYexWEMwAPIsAdYdV6aObmNPGD0aYLoEzaMJnTc0Ygs+YDw0GAtqxBjkuP38bMRWCHn73xNGjz75P73WenCEJnhwyVe3AEe8TtKdJcYhBl97wuhNAObK66lvD/9J9NS75v17wuitAN5fe4D31x7g/bUHeH/tAd5fe4D3AO+vPcD7aw/w/toDvL/2AO+vPcD7aw/w/toDvAd4f/24ABzZ8o+KLsSLS+Pv/TqTb3P4hKlQrTGh+fbIBT0Axqznnb+L/V2mb3HkN5Mb/nEHeK7d4IcDld6lmDW/iH9E+AH1MdOw/Jlu2T1xNmY98sv4wHnD7D3uNHu54WUuOsBTbQuvBsPT/UfzNxGYzwkP8c+Yz3C+r/i6DcyRL/rZ+utRwWH5PmfvcvYEt9jLDS/bg0/B64DWKrQM8AL8FPwS9beQCe6EMKNZYJol37jBMy35otdaz0Bw2H/C2Smc7+WGB0HWDELBmOByA3r5QONo4V+DpzR/hFS4U8wMW1PXNB4TOqYz9urxRV++ntWCw/U59Ty9ebdWbrgfRS9AYKKN63ZokZVygr8GZ/gfIhZXIXPsAlNjPOLBby5c1eOLvmQ9lwkOy5x6QV1j5TYqpS05JtUgUHUp5toHGsVfn4NX4RnMCe+AxTpwmApTYxqMxwfCeJGjpXzRF61nbcHhUBPqWze9svwcHJ+S6NPscKrEjug78Dx8Lj3T8D4YxGIdxmJcwhi34fzZUr7olevZCw5vkOhoClq5zBPZAnygD/Tl9EzDh6kl3VhsHYcDEb+hCtJSvuiV69kLDm+WycrOTArHmB5/VYyP6jOVjwgGawk2zQOaTcc1L+aLXrKeveDwZqlKrw8U9Y1p66uK8dEzdYwBeUQAY7DbyYNezBfdWQ97weEtAKYQg2xJIkuveAT3dYeLGH+ShrWNwZgN0b2YL7qznr3g8JYAo5bQBziPjx7BPZ0d9RCQp4UZbnFdzBddor4XHN4KYMrB2qHFRIzzcLAHQZ5the5ovui94PCWAPefaYnxIdzRwdHCbuR4B+tbiy96Lzi8E4D7z7S0mEPd+eqO3cT53Z0Y8SV80XvB4Z0ADJi/f7X113f+7p7/+UYBvur6657/+YYBvur6657/+aYBvuL6657/+aYBvuL6657/+aYBvuL6657/+aYBvuL6657/+VMA8FXWX/f8z58OgK+y/rrnf75RgLna+uue//lTA/CV1V/3/M837aKvvv6653++UQvmauuve/7nTwfAV1N/3fM/fzr24Cuuv+75nz8FFnxl9dc9//MOr/8/glixwRuUfM4AAAAASUVORK5CYII=';\n\n\t}\n\n\tgetSearchTexture() {\n\n\t\treturn 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEIAAAAhCAAAAABIXyLAAAAAOElEQVRIx2NgGAWjYBSMglEwEICREYRgFBZBqDCSLA2MGPUIVQETE9iNUAqLR5gIeoQKRgwXjwAAGn4AtaFeYLEAAAAASUVORK5CYII=';\n\n\t}\n\n\tdispose() {\n\n\t\tthis.edgesRT.dispose();\n\t\tthis.weightsRT.dispose();\n\n\t\tthis.areaTexture.dispose();\n\t\tthis.searchTexture.dispose();\n\n\t\tthis.materialEdges.dispose();\n\t\tthis.materialWeights.dispose();\n\t\tthis.materialBlend.dispose();\n\n\t\tthis.fsQuad.dispose();\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNzM3LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7O0FBRWU7O0FBRWY7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBLGdCQUFnQixhQUFhO0FBQzdCLGtCQUFrQixXQUFXLDZCQUFPOztBQUVwQyxFQUFFOztBQUVGOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSxrRkFBa0Y7QUFDbEYsa0ZBQWtGO0FBQ2xGLGtGQUFrRjtBQUNsRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxFQUFFOztBQUVGOztBQUVBLGdCQUFnQixhQUFhO0FBQzdCLGFBQWEsYUFBYTtBQUMxQixlQUFlLGFBQWE7QUFDNUIsa0JBQWtCLFdBQVcsNkJBQU87O0FBRXBDLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQSx1RkFBdUY7QUFDdkYseUZBQXlGOztBQUV6RjtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBLEdBQUc7O0FBRUg7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsb0JBQW9CLDJCQUEyQixTQUFTO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLHFDQUFxQztBQUNyQzs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUEsb0JBQW9CLDJCQUEyQixTQUFTO0FBQ3hEO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0IsMkJBQTJCLFNBQVM7QUFDeEQ7QUFDQSwrQ0FBK0M7QUFDL0M7QUFDQTs7QUFFQSxzQ0FBc0M7QUFDdEMsK0JBQStCO0FBQy9CLHFDQUFxQztBQUNyQywrRUFBK0U7O0FBRS9FO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQSxvQkFBb0IsMkJBQTJCLFNBQVM7QUFDeEQ7QUFDQSwrQ0FBK0M7QUFDL0M7QUFDQTs7QUFFQSxzQ0FBc0M7QUFDdEMsK0JBQStCO0FBQy9CLHFDQUFxQztBQUNyQywrRUFBK0U7O0FBRS9FO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsc0JBQXNCO0FBQ3RCOztBQUVBO0FBQ0E7QUFDQTtBQUNBLDhCQUE4QjtBQUM5Qjs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG9DQUFvQztBQUNwQzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQSxzQkFBc0I7QUFDdEI7O0FBRUE7QUFDQTs7QUFFQTtBQUNBLDhCQUE4QjtBQUM5Qjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBLG9DQUFvQztBQUNwQzs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBLGdCQUFnQixhQUFhO0FBQzdCLGNBQWMsYUFBYTtBQUMzQixrQkFBa0IsV0FBVyw2QkFBTzs7QUFFcEMsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0EsaUZBQWlGO0FBQ2pGLGlGQUFpRjtBQUNqRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSxLQUFLO0FBQ0w7QUFDQTtBQUNBO0FBQ0E7QUFDQSx1Q0FBdUM7QUFDdkMsdUNBQXVDOztBQUV2QztBQUNBLDhDQUE4QztBQUM5QztBQUNBLE1BQU07QUFDTjtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFK0Q7OztBQ3pjaEQ7QUFDa0M7QUFDVTtBQUNFO0FBQ0Y7O0FBRTNELHVCQUF1QixnQkFBSTs7QUFFM0I7O0FBRUE7O0FBRUE7O0FBRUEscUJBQXFCLHVDQUFpQjtBQUN0QztBQUNBLFNBQVMsbUNBQWE7QUFDdEIsSUFBSTtBQUNKOztBQUVBLHVCQUF1Qix1Q0FBaUI7QUFDeEM7QUFDQSxTQUFTLG1DQUFhO0FBQ3RCLElBQUk7QUFDSjs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLHlCQUF5Qiw2QkFBTztBQUNoQztBQUNBO0FBQ0EsK0JBQStCLGtDQUFZO0FBQzNDO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUEsMkJBQTJCLDZCQUFPO0FBQ2xDO0FBQ0E7QUFDQSxpQ0FBaUMsbUNBQWE7QUFDOUMsaUNBQWlDLG1DQUFhO0FBQzlDO0FBQ0E7O0FBRUE7O0FBRUEsdUJBQXVCLG1DQUFhLFFBQVEsZUFBZTs7QUFFM0Q7O0FBRUEsMkJBQTJCLG9DQUFjO0FBQ3pDLDZCQUE2QixFQUFFLGVBQWU7QUFDOUM7QUFDQSxpQkFBaUIsZUFBZTtBQUNoQyxtQkFBbUIsZUFBZTtBQUNsQyxJQUFJOztBQUVKOztBQUVBLHlCQUF5QixtQ0FBYSxRQUFRLGlCQUFpQjs7QUFFL0Q7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsNkJBQTZCLG9DQUFjO0FBQzNDLDZCQUE2QixFQUFFLGlCQUFpQjtBQUNoRDtBQUNBLGlCQUFpQixpQkFBaUI7QUFDbEMsbUJBQW1CLGlCQUFpQjtBQUNwQyxJQUFJOztBQUVKOztBQUVBLHVCQUF1QixtQ0FBYSxRQUFRLGVBQWU7O0FBRTNEO0FBQ0E7O0FBRUEsMkJBQTJCLG9DQUFjO0FBQ3pDO0FBQ0EsaUJBQWlCLGVBQWU7QUFDaEMsbUJBQW1CLGVBQWU7QUFDbEMsSUFBSTs7QUFFSixvQkFBb0IsMEJBQWM7O0FBRWxDOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQSx5QkFBeUI7O0FBRXpCOztBQUVBOztBQUVBLHlCQUF5Qjs7QUFFekI7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFb0IiLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9zaGFkZXJzL1NNQUFTaGFkZXIuanM/NDdmOSIsIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9wb3N0cHJvY2Vzc2luZy9TTUFBUGFzcy5qcz84YjFmIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG5cdFZlY3RvcjJcbn0gZnJvbSAndGhyZWUnO1xuXG4vKipcbiAqIFdlYkdMIHBvcnQgb2YgU3VicGl4ZWwgTW9ycGhvbG9naWNhbCBBbnRpYWxpYXNpbmcgKFNNQUEpIHYyLjhcbiAqIFByZXNldDogU01BQSAxeCBNZWRpdW0gKHdpdGggY29sb3IgZWRnZSBkZXRlY3Rpb24pXG4gKiBodHRwczovL2dpdGh1Yi5jb20vaXJ5b2t1L3NtYWEvcmVsZWFzZXMvdGFnL3YyLjhcbiAqL1xuXG5jb25zdCBTTUFBRWRnZXNTaGFkZXIgPSB7XG5cblx0bmFtZTogJ1NNQUFFZGdlc1NoYWRlcicsXG5cblx0ZGVmaW5lczoge1xuXG5cdFx0J1NNQUFfVEhSRVNIT0xEJzogJzAuMSdcblxuXHR9LFxuXG5cdHVuaWZvcm1zOiB7XG5cblx0XHQndERpZmZ1c2UnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0J3Jlc29sdXRpb24nOiB7IHZhbHVlOiBuZXcgVmVjdG9yMiggMSAvIDEwMjQsIDEgLyA1MTIgKSB9XG5cblx0fSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR1bmlmb3JtIHZlYzIgcmVzb2x1dGlvbjtcblxuXHRcdHZhcnlpbmcgdmVjMiB2VXY7XG5cdFx0dmFyeWluZyB2ZWM0IHZPZmZzZXRbIDMgXTtcblxuXHRcdHZvaWQgU01BQUVkZ2VEZXRlY3Rpb25WUyggdmVjMiB0ZXhjb29yZCApIHtcblx0XHRcdHZPZmZzZXRbIDAgXSA9IHRleGNvb3JkLnh5eHkgKyByZXNvbHV0aW9uLnh5eHkgKiB2ZWM0KCAtMS4wLCAwLjAsIDAuMCwgIDEuMCApOyAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgc2lnbiBpbiBXIGNvbXBvbmVudFxuXHRcdFx0dk9mZnNldFsgMSBdID0gdGV4Y29vcmQueHl4eSArIHJlc29sdXRpb24ueHl4eSAqIHZlYzQoICAxLjAsIDAuMCwgMC4wLCAtMS4wICk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduIGluIFcgY29tcG9uZW50XG5cdFx0XHR2T2Zmc2V0WyAyIF0gPSB0ZXhjb29yZC54eXh5ICsgcmVzb2x1dGlvbi54eXh5ICogdmVjNCggLTIuMCwgMC4wLCAwLjAsICAyLjAgKTsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHNpZ24gaW4gVyBjb21wb25lbnRcblx0XHR9XG5cblx0XHR2b2lkIG1haW4oKSB7XG5cblx0XHRcdHZVdiA9IHV2O1xuXG5cdFx0XHRTTUFBRWRnZURldGVjdGlvblZTKCB2VXYgKTtcblxuXHRcdFx0Z2xfUG9zaXRpb24gPSBwcm9qZWN0aW9uTWF0cml4ICogbW9kZWxWaWV3TWF0cml4ICogdmVjNCggcG9zaXRpb24sIDEuMCApO1xuXG5cdFx0fWAsXG5cblx0ZnJhZ21lbnRTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR1bmlmb3JtIHNhbXBsZXIyRCB0RGlmZnVzZTtcblxuXHRcdHZhcnlpbmcgdmVjMiB2VXY7XG5cdFx0dmFyeWluZyB2ZWM0IHZPZmZzZXRbIDMgXTtcblxuXHRcdHZlYzQgU01BQUNvbG9yRWRnZURldGVjdGlvblBTKCB2ZWMyIHRleGNvb3JkLCB2ZWM0IG9mZnNldFszXSwgc2FtcGxlcjJEIGNvbG9yVGV4ICkge1xuXHRcdFx0dmVjMiB0aHJlc2hvbGQgPSB2ZWMyKCBTTUFBX1RIUkVTSE9MRCwgU01BQV9USFJFU0hPTEQgKTtcblxuXHRcdFx0Ly8gQ2FsY3VsYXRlIGNvbG9yIGRlbHRhczpcblx0XHRcdHZlYzQgZGVsdGE7XG5cdFx0XHR2ZWMzIEMgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4LCB0ZXhjb29yZCApLnJnYjtcblxuXHRcdFx0dmVjMyBDbGVmdCA9IHRleHR1cmUyRCggY29sb3JUZXgsIG9mZnNldFswXS54eSApLnJnYjtcblx0XHRcdHZlYzMgdCA9IGFicyggQyAtIENsZWZ0ICk7XG5cdFx0XHRkZWx0YS54ID0gbWF4KCBtYXgoIHQuciwgdC5nICksIHQuYiApO1xuXG5cdFx0XHR2ZWMzIEN0b3AgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4LCBvZmZzZXRbMF0uencgKS5yZ2I7XG5cdFx0XHR0ID0gYWJzKCBDIC0gQ3RvcCApO1xuXHRcdFx0ZGVsdGEueSA9IG1heCggbWF4KCB0LnIsIHQuZyApLCB0LmIgKTtcblxuXHRcdFx0Ly8gV2UgZG8gdGhlIHVzdWFsIHRocmVzaG9sZDpcblx0XHRcdHZlYzIgZWRnZXMgPSBzdGVwKCB0aHJlc2hvbGQsIGRlbHRhLnh5ICk7XG5cblx0XHRcdC8vIFRoZW4gZGlzY2FyZCBpZiB0aGVyZSBpcyBubyBlZGdlOlxuXHRcdFx0aWYgKCBkb3QoIGVkZ2VzLCB2ZWMyKCAxLjAsIDEuMCApICkgPT0gMC4wIClcblx0XHRcdFx0ZGlzY2FyZDtcblxuXHRcdFx0Ly8gQ2FsY3VsYXRlIHJpZ2h0IGFuZCBib3R0b20gZGVsdGFzOlxuXHRcdFx0dmVjMyBDcmlnaHQgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4LCBvZmZzZXRbMV0ueHkgKS5yZ2I7XG5cdFx0XHR0ID0gYWJzKCBDIC0gQ3JpZ2h0ICk7XG5cdFx0XHRkZWx0YS56ID0gbWF4KCBtYXgoIHQuciwgdC5nICksIHQuYiApO1xuXG5cdFx0XHR2ZWMzIENib3R0b20gID0gdGV4dHVyZTJEKCBjb2xvclRleCwgb2Zmc2V0WzFdLnp3ICkucmdiO1xuXHRcdFx0dCA9IGFicyggQyAtIENib3R0b20gKTtcblx0XHRcdGRlbHRhLncgPSBtYXgoIG1heCggdC5yLCB0LmcgKSwgdC5iICk7XG5cblx0XHRcdC8vIENhbGN1bGF0ZSB0aGUgbWF4aW11bSBkZWx0YSBpbiB0aGUgZGlyZWN0IG5laWdoYm9yaG9vZDpcblx0XHRcdGZsb2F0IG1heERlbHRhID0gbWF4KCBtYXgoIG1heCggZGVsdGEueCwgZGVsdGEueSApLCBkZWx0YS56ICksIGRlbHRhLncgKTtcblxuXHRcdFx0Ly8gQ2FsY3VsYXRlIGxlZnQtbGVmdCBhbmQgdG9wLXRvcCBkZWx0YXM6XG5cdFx0XHR2ZWMzIENsZWZ0bGVmdCAgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4LCBvZmZzZXRbMl0ueHkgKS5yZ2I7XG5cdFx0XHR0ID0gYWJzKCBDIC0gQ2xlZnRsZWZ0ICk7XG5cdFx0XHRkZWx0YS56ID0gbWF4KCBtYXgoIHQuciwgdC5nICksIHQuYiApO1xuXG5cdFx0XHR2ZWMzIEN0b3B0b3AgPSB0ZXh0dXJlMkQoIGNvbG9yVGV4LCBvZmZzZXRbMl0uencgKS5yZ2I7XG5cdFx0XHR0ID0gYWJzKCBDIC0gQ3RvcHRvcCApO1xuXHRcdFx0ZGVsdGEudyA9IG1heCggbWF4KCB0LnIsIHQuZyApLCB0LmIgKTtcblxuXHRcdFx0Ly8gQ2FsY3VsYXRlIHRoZSBmaW5hbCBtYXhpbXVtIGRlbHRhOlxuXHRcdFx0bWF4RGVsdGEgPSBtYXgoIG1heCggbWF4RGVsdGEsIGRlbHRhLnogKSwgZGVsdGEudyApO1xuXG5cdFx0XHQvLyBMb2NhbCBjb250cmFzdCBhZGFwdGF0aW9uIGluIGFjdGlvbjpcblx0XHRcdGVkZ2VzLnh5ICo9IHN0ZXAoIDAuNSAqIG1heERlbHRhLCBkZWx0YS54eSApO1xuXG5cdFx0XHRyZXR1cm4gdmVjNCggZWRnZXMsIDAuMCwgMC4wICk7XG5cdFx0fVxuXG5cdFx0dm9pZCBtYWluKCkge1xuXG5cdFx0XHRnbF9GcmFnQ29sb3IgPSBTTUFBQ29sb3JFZGdlRGV0ZWN0aW9uUFMoIHZVdiwgdk9mZnNldCwgdERpZmZ1c2UgKTtcblxuXHRcdH1gXG5cbn07XG5cbmNvbnN0IFNNQUFXZWlnaHRzU2hhZGVyID0ge1xuXG5cdG5hbWU6ICdTTUFBV2VpZ2h0c1NoYWRlcicsXG5cblx0ZGVmaW5lczoge1xuXG5cdFx0J1NNQUFfTUFYX1NFQVJDSF9TVEVQUyc6ICc4Jyxcblx0XHQnU01BQV9BUkVBVEVYX01BWF9ESVNUQU5DRSc6ICcxNicsXG5cdFx0J1NNQUFfQVJFQVRFWF9QSVhFTF9TSVpFJzogJyggMS4wIC8gdmVjMiggMTYwLjAsIDU2MC4wICkgKScsXG5cdFx0J1NNQUFfQVJFQVRFWF9TVUJURVhfU0laRSc6ICcoIDEuMCAvIDcuMCApJ1xuXG5cdH0sXG5cblx0dW5pZm9ybXM6IHtcblxuXHRcdCd0RGlmZnVzZSc6IHsgdmFsdWU6IG51bGwgfSxcblx0XHQndEFyZWEnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0J3RTZWFyY2gnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0J3Jlc29sdXRpb24nOiB7IHZhbHVlOiBuZXcgVmVjdG9yMiggMSAvIDEwMjQsIDEgLyA1MTIgKSB9XG5cblx0fSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR1bmlmb3JtIHZlYzIgcmVzb2x1dGlvbjtcblxuXHRcdHZhcnlpbmcgdmVjMiB2VXY7XG5cdFx0dmFyeWluZyB2ZWM0IHZPZmZzZXRbIDMgXTtcblx0XHR2YXJ5aW5nIHZlYzIgdlBpeGNvb3JkO1xuXG5cdFx0dm9pZCBTTUFBQmxlbmRpbmdXZWlnaHRDYWxjdWxhdGlvblZTKCB2ZWMyIHRleGNvb3JkICkge1xuXHRcdFx0dlBpeGNvb3JkID0gdGV4Y29vcmQgLyByZXNvbHV0aW9uO1xuXG5cdFx0XHQvLyBXZSB3aWxsIHVzZSB0aGVzZSBvZmZzZXRzIGZvciB0aGUgc2VhcmNoZXMgbGF0ZXIgb24gKHNlZSBAUFNFVURPX0dBVEhFUjQpOlxuXHRcdFx0dk9mZnNldFsgMCBdID0gdGV4Y29vcmQueHl4eSArIHJlc29sdXRpb24ueHl4eSAqIHZlYzQoIC0wLjI1LCAwLjEyNSwgMS4yNSwgMC4xMjUgKTsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHNpZ24gaW4gWSBhbmQgVyBjb21wb25lbnRzXG5cdFx0XHR2T2Zmc2V0WyAxIF0gPSB0ZXhjb29yZC54eXh5ICsgcmVzb2x1dGlvbi54eXh5ICogdmVjNCggLTAuMTI1LCAwLjI1LCAtMC4xMjUsIC0xLjI1ICk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduIGluIFkgYW5kIFcgY29tcG9uZW50c1xuXG5cdFx0XHQvLyBBbmQgdGhlc2UgZm9yIHRoZSBzZWFyY2hlcywgdGhleSBpbmRpY2F0ZSB0aGUgZW5kcyBvZiB0aGUgbG9vcHM6XG5cdFx0XHR2T2Zmc2V0WyAyIF0gPSB2ZWM0KCB2T2Zmc2V0WyAwIF0ueHosIHZPZmZzZXRbIDEgXS55dyApICsgdmVjNCggLTIuMCwgMi4wLCAtMi4wLCAyLjAgKSAqIHJlc29sdXRpb24ueHh5eSAqIGZsb2F0KCBTTUFBX01BWF9TRUFSQ0hfU1RFUFMgKTtcblxuXHRcdH1cblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0dlV2ID0gdXY7XG5cblx0XHRcdFNNQUFCbGVuZGluZ1dlaWdodENhbGN1bGF0aW9uVlMoIHZVdiApO1xuXG5cdFx0XHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XG5cblx0XHR9YCxcblxuXHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2BcblxuXHRcdCNkZWZpbmUgU01BQVNhbXBsZUxldmVsWmVyb09mZnNldCggdGV4LCBjb29yZCwgb2Zmc2V0ICkgdGV4dHVyZTJEKCB0ZXgsIGNvb3JkICsgZmxvYXQoIG9mZnNldCApICogcmVzb2x1dGlvbiwgMC4wIClcblxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHREaWZmdXNlO1xuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHRBcmVhO1xuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHRTZWFyY2g7XG5cdFx0dW5pZm9ybSB2ZWMyIHJlc29sdXRpb247XG5cblx0XHR2YXJ5aW5nIHZlYzIgdlV2O1xuXHRcdHZhcnlpbmcgdmVjNCB2T2Zmc2V0WzNdO1xuXHRcdHZhcnlpbmcgdmVjMiB2UGl4Y29vcmQ7XG5cblx0XHQjaWYgX19WRVJTSU9OX18gPT0gMTAwXG5cdFx0dmVjMiByb3VuZCggdmVjMiB4ICkge1xuXHRcdFx0cmV0dXJuIHNpZ24oIHggKSAqIGZsb29yKCBhYnMoIHggKSArIDAuNSApO1xuXHRcdH1cblx0XHQjZW5kaWZcblxuXHRcdGZsb2F0IFNNQUFTZWFyY2hMZW5ndGgoIHNhbXBsZXIyRCBzZWFyY2hUZXgsIHZlYzIgZSwgZmxvYXQgYmlhcywgZmxvYXQgc2NhbGUgKSB7XG5cdFx0XHQvLyBOb3QgcmVxdWlyZWQgaWYgc2VhcmNoVGV4IGFjY2Vzc2VzIGFyZSBzZXQgdG8gcG9pbnQ6XG5cdFx0XHQvLyBmbG9hdDIgU0VBUkNIX1RFWF9QSVhFTF9TSVpFID0gMS4wIC8gZmxvYXQyKDY2LjAsIDMzLjApO1xuXHRcdFx0Ly8gZSA9IGZsb2F0MihiaWFzLCAwLjApICsgMC41ICogU0VBUkNIX1RFWF9QSVhFTF9TSVpFICtcblx0XHRcdC8vICAgICBlICogZmxvYXQyKHNjYWxlLCAxLjApICogZmxvYXQyKDY0LjAsIDMyLjApICogU0VBUkNIX1RFWF9QSVhFTF9TSVpFO1xuXHRcdFx0ZS5yID0gYmlhcyArIGUuciAqIHNjYWxlO1xuXHRcdFx0cmV0dXJuIDI1NS4wICogdGV4dHVyZTJEKCBzZWFyY2hUZXgsIGUsIDAuMCApLnI7XG5cdFx0fVxuXG5cdFx0ZmxvYXQgU01BQVNlYXJjaFhMZWZ0KCBzYW1wbGVyMkQgZWRnZXNUZXgsIHNhbXBsZXIyRCBzZWFyY2hUZXgsIHZlYzIgdGV4Y29vcmQsIGZsb2F0IGVuZCApIHtcblx0XHRcdC8qKlxuXHRcdFx0XHQqIEBQU0VVRE9fR0FUSEVSNFxuXHRcdFx0XHQqIFRoaXMgdGV4Y29vcmQgaGFzIGJlZW4gb2Zmc2V0IGJ5ICgtMC4yNSwgLTAuMTI1KSBpbiB0aGUgdmVydGV4IHNoYWRlciB0b1xuXHRcdFx0XHQqIHNhbXBsZSBiZXR3ZWVuIGVkZ2UsIHRodXMgZmV0Y2hpbmcgZm91ciBlZGdlcyBpbiBhIHJvdy5cblx0XHRcdFx0KiBTYW1wbGluZyB3aXRoIGRpZmZlcmVudCBvZmZzZXRzIGluIGVhY2ggZGlyZWN0aW9uIGFsbG93cyB0byBkaXNhbWJpZ3VhdGVcblx0XHRcdFx0KiB3aGljaCBlZGdlcyBhcmUgYWN0aXZlIGZyb20gdGhlIGZvdXIgZmV0Y2hlZCBvbmVzLlxuXHRcdFx0XHQqL1xuXHRcdFx0dmVjMiBlID0gdmVjMiggMC4wLCAxLjAgKTtcblxuXHRcdFx0Zm9yICggaW50IGkgPSAwOyBpIDwgU01BQV9NQVhfU0VBUkNIX1NURVBTOyBpICsrICkgeyAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgd2hpbGUgdG8gZm9yXG5cdFx0XHRcdGUgPSB0ZXh0dXJlMkQoIGVkZ2VzVGV4LCB0ZXhjb29yZCwgMC4wICkucmc7XG5cdFx0XHRcdHRleGNvb3JkIC09IHZlYzIoIDIuMCwgMC4wICkgKiByZXNvbHV0aW9uO1xuXHRcdFx0XHRpZiAoICEgKCB0ZXhjb29yZC54ID4gZW5kICYmIGUuZyA+IDAuODI4MSAmJiBlLnIgPT0gMC4wICkgKSBicmVhaztcblx0XHRcdH1cblxuXHRcdFx0Ly8gV2UgY29ycmVjdCB0aGUgcHJldmlvdXMgKC0wLjI1LCAtMC4xMjUpIG9mZnNldCB3ZSBhcHBsaWVkOlxuXHRcdFx0dGV4Y29vcmQueCArPSAwLjI1ICogcmVzb2x1dGlvbi54O1xuXG5cdFx0XHQvLyBUaGUgc2VhcmNoZXMgYXJlIGJpYXMgYnkgMSwgc28gYWRqdXN0IHRoZSBjb29yZHMgYWNjb3JkaW5nbHk6XG5cdFx0XHR0ZXhjb29yZC54ICs9IHJlc29sdXRpb24ueDtcblxuXHRcdFx0Ly8gRGlzYW1iaWd1YXRlIHRoZSBsZW5ndGggYWRkZWQgYnkgdGhlIGxhc3Qgc3RlcDpcblx0XHRcdHRleGNvb3JkLnggKz0gMi4wICogcmVzb2x1dGlvbi54OyAvLyBVbmRvIGxhc3Qgc3RlcFxuXHRcdFx0dGV4Y29vcmQueCAtPSByZXNvbHV0aW9uLnggKiBTTUFBU2VhcmNoTGVuZ3RoKHNlYXJjaFRleCwgZSwgMC4wLCAwLjUpO1xuXG5cdFx0XHRyZXR1cm4gdGV4Y29vcmQueDtcblx0XHR9XG5cblx0XHRmbG9hdCBTTUFBU2VhcmNoWFJpZ2h0KCBzYW1wbGVyMkQgZWRnZXNUZXgsIHNhbXBsZXIyRCBzZWFyY2hUZXgsIHZlYzIgdGV4Y29vcmQsIGZsb2F0IGVuZCApIHtcblx0XHRcdHZlYzIgZSA9IHZlYzIoIDAuMCwgMS4wICk7XG5cblx0XHRcdGZvciAoIGludCBpID0gMDsgaSA8IFNNQUFfTUFYX1NFQVJDSF9TVEVQUzsgaSArKyApIHsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHdoaWxlIHRvIGZvclxuXHRcdFx0XHRlID0gdGV4dHVyZTJEKCBlZGdlc1RleCwgdGV4Y29vcmQsIDAuMCApLnJnO1xuXHRcdFx0XHR0ZXhjb29yZCArPSB2ZWMyKCAyLjAsIDAuMCApICogcmVzb2x1dGlvbjtcblx0XHRcdFx0aWYgKCAhICggdGV4Y29vcmQueCA8IGVuZCAmJiBlLmcgPiAwLjgyODEgJiYgZS5yID09IDAuMCApICkgYnJlYWs7XG5cdFx0XHR9XG5cblx0XHRcdHRleGNvb3JkLnggLT0gMC4yNSAqIHJlc29sdXRpb24ueDtcblx0XHRcdHRleGNvb3JkLnggLT0gcmVzb2x1dGlvbi54O1xuXHRcdFx0dGV4Y29vcmQueCAtPSAyLjAgKiByZXNvbHV0aW9uLng7XG5cdFx0XHR0ZXhjb29yZC54ICs9IHJlc29sdXRpb24ueCAqIFNNQUFTZWFyY2hMZW5ndGgoIHNlYXJjaFRleCwgZSwgMC41LCAwLjUgKTtcblxuXHRcdFx0cmV0dXJuIHRleGNvb3JkLng7XG5cdFx0fVxuXG5cdFx0ZmxvYXQgU01BQVNlYXJjaFlVcCggc2FtcGxlcjJEIGVkZ2VzVGV4LCBzYW1wbGVyMkQgc2VhcmNoVGV4LCB2ZWMyIHRleGNvb3JkLCBmbG9hdCBlbmQgKSB7XG5cdFx0XHR2ZWMyIGUgPSB2ZWMyKCAxLjAsIDAuMCApO1xuXG5cdFx0XHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBTTUFBX01BWF9TRUFSQ0hfU1RFUFM7IGkgKysgKSB7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCB3aGlsZSB0byBmb3Jcblx0XHRcdFx0ZSA9IHRleHR1cmUyRCggZWRnZXNUZXgsIHRleGNvb3JkLCAwLjAgKS5yZztcblx0XHRcdFx0dGV4Y29vcmQgKz0gdmVjMiggMC4wLCAyLjAgKSAqIHJlc29sdXRpb247IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cdFx0XHRcdGlmICggISAoIHRleGNvb3JkLnkgPiBlbmQgJiYgZS5yID4gMC44MjgxICYmIGUuZyA9PSAwLjAgKSApIGJyZWFrO1xuXHRcdFx0fVxuXG5cdFx0XHR0ZXhjb29yZC55IC09IDAuMjUgKiByZXNvbHV0aW9uLnk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cdFx0XHR0ZXhjb29yZC55IC09IHJlc29sdXRpb24ueTsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHNpZ25cblx0XHRcdHRleGNvb3JkLnkgLT0gMi4wICogcmVzb2x1dGlvbi55OyAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgc2lnblxuXHRcdFx0dGV4Y29vcmQueSArPSByZXNvbHV0aW9uLnkgKiBTTUFBU2VhcmNoTGVuZ3RoKCBzZWFyY2hUZXgsIGUuZ3IsIDAuMCwgMC41ICk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cblx0XHRcdHJldHVybiB0ZXhjb29yZC55O1xuXHRcdH1cblxuXHRcdGZsb2F0IFNNQUFTZWFyY2hZRG93biggc2FtcGxlcjJEIGVkZ2VzVGV4LCBzYW1wbGVyMkQgc2VhcmNoVGV4LCB2ZWMyIHRleGNvb3JkLCBmbG9hdCBlbmQgKSB7XG5cdFx0XHR2ZWMyIGUgPSB2ZWMyKCAxLjAsIDAuMCApO1xuXG5cdFx0XHRmb3IgKCBpbnQgaSA9IDA7IGkgPCBTTUFBX01BWF9TRUFSQ0hfU1RFUFM7IGkgKysgKSB7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCB3aGlsZSB0byBmb3Jcblx0XHRcdFx0ZSA9IHRleHR1cmUyRCggZWRnZXNUZXgsIHRleGNvb3JkLCAwLjAgKS5yZztcblx0XHRcdFx0dGV4Y29vcmQgLT0gdmVjMiggMC4wLCAyLjAgKSAqIHJlc29sdXRpb247IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cdFx0XHRcdGlmICggISAoIHRleGNvb3JkLnkgPCBlbmQgJiYgZS5yID4gMC44MjgxICYmIGUuZyA9PSAwLjAgKSApIGJyZWFrO1xuXHRcdFx0fVxuXG5cdFx0XHR0ZXhjb29yZC55ICs9IDAuMjUgKiByZXNvbHV0aW9uLnk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cdFx0XHR0ZXhjb29yZC55ICs9IHJlc29sdXRpb24ueTsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHNpZ25cblx0XHRcdHRleGNvb3JkLnkgKz0gMi4wICogcmVzb2x1dGlvbi55OyAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgc2lnblxuXHRcdFx0dGV4Y29vcmQueSAtPSByZXNvbHV0aW9uLnkgKiBTTUFBU2VhcmNoTGVuZ3RoKCBzZWFyY2hUZXgsIGUuZ3IsIDAuNSwgMC41ICk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQ2hhbmdlZCBzaWduXG5cblx0XHRcdHJldHVybiB0ZXhjb29yZC55O1xuXHRcdH1cblxuXHRcdHZlYzIgU01BQUFyZWEoIHNhbXBsZXIyRCBhcmVhVGV4LCB2ZWMyIGRpc3QsIGZsb2F0IGUxLCBmbG9hdCBlMiwgZmxvYXQgb2Zmc2V0ICkge1xuXHRcdFx0Ly8gUm91bmRpbmcgcHJldmVudHMgcHJlY2lzaW9uIGVycm9ycyBvZiBiaWxpbmVhciBmaWx0ZXJpbmc6XG5cdFx0XHR2ZWMyIHRleGNvb3JkID0gZmxvYXQoIFNNQUFfQVJFQVRFWF9NQVhfRElTVEFOQ0UgKSAqIHJvdW5kKCA0LjAgKiB2ZWMyKCBlMSwgZTIgKSApICsgZGlzdDtcblxuXHRcdFx0Ly8gV2UgZG8gYSBzY2FsZSBhbmQgYmlhcyBmb3IgbWFwcGluZyB0byB0ZXhlbCBzcGFjZTpcblx0XHRcdHRleGNvb3JkID0gU01BQV9BUkVBVEVYX1BJWEVMX1NJWkUgKiB0ZXhjb29yZCArICggMC41ICogU01BQV9BUkVBVEVYX1BJWEVMX1NJWkUgKTtcblxuXHRcdFx0Ly8gTW92ZSB0byBwcm9wZXIgcGxhY2UsIGFjY29yZGluZyB0byB0aGUgc3VicGl4ZWwgb2Zmc2V0OlxuXHRcdFx0dGV4Y29vcmQueSArPSBTTUFBX0FSRUFURVhfU1VCVEVYX1NJWkUgKiBvZmZzZXQ7XG5cblx0XHRcdHJldHVybiB0ZXh0dXJlMkQoIGFyZWFUZXgsIHRleGNvb3JkLCAwLjAgKS5yZztcblx0XHR9XG5cblx0XHR2ZWM0IFNNQUFCbGVuZGluZ1dlaWdodENhbGN1bGF0aW9uUFMoIHZlYzIgdGV4Y29vcmQsIHZlYzIgcGl4Y29vcmQsIHZlYzQgb2Zmc2V0WyAzIF0sIHNhbXBsZXIyRCBlZGdlc1RleCwgc2FtcGxlcjJEIGFyZWFUZXgsIHNhbXBsZXIyRCBzZWFyY2hUZXgsIGl2ZWM0IHN1YnNhbXBsZUluZGljZXMgKSB7XG5cdFx0XHR2ZWM0IHdlaWdodHMgPSB2ZWM0KCAwLjAsIDAuMCwgMC4wLCAwLjAgKTtcblxuXHRcdFx0dmVjMiBlID0gdGV4dHVyZTJEKCBlZGdlc1RleCwgdGV4Y29vcmQgKS5yZztcblxuXHRcdFx0aWYgKCBlLmcgPiAwLjAgKSB7IC8vIEVkZ2UgYXQgbm9ydGhcblx0XHRcdFx0dmVjMiBkO1xuXG5cdFx0XHRcdC8vIEZpbmQgdGhlIGRpc3RhbmNlIHRvIHRoZSBsZWZ0OlxuXHRcdFx0XHR2ZWMyIGNvb3Jkcztcblx0XHRcdFx0Y29vcmRzLnggPSBTTUFBU2VhcmNoWExlZnQoIGVkZ2VzVGV4LCBzZWFyY2hUZXgsIG9mZnNldFsgMCBdLnh5LCBvZmZzZXRbIDIgXS54ICk7XG5cdFx0XHRcdGNvb3Jkcy55ID0gb2Zmc2V0WyAxIF0ueTsgLy8gb2Zmc2V0WzFdLnkgPSB0ZXhjb29yZC55IC0gMC4yNSAqIHJlc29sdXRpb24ueSAoQENST1NTSU5HX09GRlNFVClcblx0XHRcdFx0ZC54ID0gY29vcmRzLng7XG5cblx0XHRcdFx0Ly8gTm93IGZldGNoIHRoZSBsZWZ0IGNyb3NzaW5nIGVkZ2VzLCB0d28gYXQgYSB0aW1lIHVzaW5nIGJpbGluZWFyXG5cdFx0XHRcdC8vIGZpbHRlcmluZy4gU2FtcGxpbmcgYXQgLTAuMjUgKHNlZSBAQ1JPU1NJTkdfT0ZGU0VUKSBlbmFibGVzIHRvXG5cdFx0XHRcdC8vIGRpc2Nlcm4gd2hhdCB2YWx1ZSBlYWNoIGVkZ2UgaGFzOlxuXHRcdFx0XHRmbG9hdCBlMSA9IHRleHR1cmUyRCggZWRnZXNUZXgsIGNvb3JkcywgMC4wICkucjtcblxuXHRcdFx0XHQvLyBGaW5kIHRoZSBkaXN0YW5jZSB0byB0aGUgcmlnaHQ6XG5cdFx0XHRcdGNvb3Jkcy54ID0gU01BQVNlYXJjaFhSaWdodCggZWRnZXNUZXgsIHNlYXJjaFRleCwgb2Zmc2V0WyAwIF0uencsIG9mZnNldFsgMiBdLnkgKTtcblx0XHRcdFx0ZC55ID0gY29vcmRzLng7XG5cblx0XHRcdFx0Ly8gV2Ugd2FudCB0aGUgZGlzdGFuY2VzIHRvIGJlIGluIHBpeGVsIHVuaXRzIChkb2luZyB0aGlzIGhlcmUgYWxsb3cgdG9cblx0XHRcdFx0Ly8gYmV0dGVyIGludGVybGVhdmUgYXJpdGhtZXRpYyBhbmQgbWVtb3J5IGFjY2Vzc2VzKTpcblx0XHRcdFx0ZCA9IGQgLyByZXNvbHV0aW9uLnggLSBwaXhjb29yZC54O1xuXG5cdFx0XHRcdC8vIFNNQUFBcmVhIGJlbG93IG5lZWRzIGEgc3FydCwgYXMgdGhlIGFyZWFzIHRleHR1cmUgaXMgY29tcHJlc3NlZFxuXHRcdFx0XHQvLyBxdWFkcmF0aWNhbGx5OlxuXHRcdFx0XHR2ZWMyIHNxcnRfZCA9IHNxcnQoIGFicyggZCApICk7XG5cblx0XHRcdFx0Ly8gRmV0Y2ggdGhlIHJpZ2h0IGNyb3NzaW5nIGVkZ2VzOlxuXHRcdFx0XHRjb29yZHMueSAtPSAxLjAgKiByZXNvbHV0aW9uLnk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQWRkZWRcblx0XHRcdFx0ZmxvYXQgZTIgPSBTTUFBU2FtcGxlTGV2ZWxaZXJvT2Zmc2V0KCBlZGdlc1RleCwgY29vcmRzLCBpdmVjMiggMSwgMCApICkucjtcblxuXHRcdFx0XHQvLyBPaywgd2Uga25vdyBob3cgdGhpcyBwYXR0ZXJuIGxvb2tzIGxpa2UsIG5vdyBpdCBpcyB0aW1lIGZvciBnZXR0aW5nXG5cdFx0XHRcdC8vIHRoZSBhY3R1YWwgYXJlYTpcblx0XHRcdFx0d2VpZ2h0cy5yZyA9IFNNQUFBcmVhKCBhcmVhVGV4LCBzcXJ0X2QsIGUxLCBlMiwgZmxvYXQoIHN1YnNhbXBsZUluZGljZXMueSApICk7XG5cdFx0XHR9XG5cblx0XHRcdGlmICggZS5yID4gMC4wICkgeyAvLyBFZGdlIGF0IHdlc3Rcblx0XHRcdFx0dmVjMiBkO1xuXG5cdFx0XHRcdC8vIEZpbmQgdGhlIGRpc3RhbmNlIHRvIHRoZSB0b3A6XG5cdFx0XHRcdHZlYzIgY29vcmRzO1xuXG5cdFx0XHRcdGNvb3Jkcy55ID0gU01BQVNlYXJjaFlVcCggZWRnZXNUZXgsIHNlYXJjaFRleCwgb2Zmc2V0WyAxIF0ueHksIG9mZnNldFsgMiBdLnogKTtcblx0XHRcdFx0Y29vcmRzLnggPSBvZmZzZXRbIDAgXS54OyAvLyBvZmZzZXRbMV0ueCA9IHRleGNvb3JkLnggLSAwLjI1ICogcmVzb2x1dGlvbi54O1xuXHRcdFx0XHRkLnggPSBjb29yZHMueTtcblxuXHRcdFx0XHQvLyBGZXRjaCB0aGUgdG9wIGNyb3NzaW5nIGVkZ2VzOlxuXHRcdFx0XHRmbG9hdCBlMSA9IHRleHR1cmUyRCggZWRnZXNUZXgsIGNvb3JkcywgMC4wICkuZztcblxuXHRcdFx0XHQvLyBGaW5kIHRoZSBkaXN0YW5jZSB0byB0aGUgYm90dG9tOlxuXHRcdFx0XHRjb29yZHMueSA9IFNNQUFTZWFyY2hZRG93biggZWRnZXNUZXgsIHNlYXJjaFRleCwgb2Zmc2V0WyAxIF0uencsIG9mZnNldFsgMiBdLncgKTtcblx0XHRcdFx0ZC55ID0gY29vcmRzLnk7XG5cblx0XHRcdFx0Ly8gV2Ugd2FudCB0aGUgZGlzdGFuY2VzIHRvIGJlIGluIHBpeGVsIHVuaXRzOlxuXHRcdFx0XHRkID0gZCAvIHJlc29sdXRpb24ueSAtIHBpeGNvb3JkLnk7XG5cblx0XHRcdFx0Ly8gU01BQUFyZWEgYmVsb3cgbmVlZHMgYSBzcXJ0LCBhcyB0aGUgYXJlYXMgdGV4dHVyZSBpcyBjb21wcmVzc2VkXG5cdFx0XHRcdC8vIHF1YWRyYXRpY2FsbHk6XG5cdFx0XHRcdHZlYzIgc3FydF9kID0gc3FydCggYWJzKCBkICkgKTtcblxuXHRcdFx0XHQvLyBGZXRjaCB0aGUgYm90dG9tIGNyb3NzaW5nIGVkZ2VzOlxuXHRcdFx0XHRjb29yZHMueSAtPSAxLjAgKiByZXNvbHV0aW9uLnk7IC8vIFdlYkdMIHBvcnQgbm90ZTogQWRkZWRcblx0XHRcdFx0ZmxvYXQgZTIgPSBTTUFBU2FtcGxlTGV2ZWxaZXJvT2Zmc2V0KCBlZGdlc1RleCwgY29vcmRzLCBpdmVjMiggMCwgMSApICkuZztcblxuXHRcdFx0XHQvLyBHZXQgdGhlIGFyZWEgZm9yIHRoaXMgZGlyZWN0aW9uOlxuXHRcdFx0XHR3ZWlnaHRzLmJhID0gU01BQUFyZWEoIGFyZWFUZXgsIHNxcnRfZCwgZTEsIGUyLCBmbG9hdCggc3Vic2FtcGxlSW5kaWNlcy54ICkgKTtcblx0XHRcdH1cblxuXHRcdFx0cmV0dXJuIHdlaWdodHM7XG5cdFx0fVxuXG5cdFx0dm9pZCBtYWluKCkge1xuXG5cdFx0XHRnbF9GcmFnQ29sb3IgPSBTTUFBQmxlbmRpbmdXZWlnaHRDYWxjdWxhdGlvblBTKCB2VXYsIHZQaXhjb29yZCwgdk9mZnNldCwgdERpZmZ1c2UsIHRBcmVhLCB0U2VhcmNoLCBpdmVjNCggMC4wICkgKTtcblxuXHRcdH1gXG5cbn07XG5cbmNvbnN0IFNNQUFCbGVuZFNoYWRlciA9IHtcblxuXHRuYW1lOiAnU01BQUJsZW5kU2hhZGVyJyxcblxuXHR1bmlmb3Jtczoge1xuXG5cdFx0J3REaWZmdXNlJzogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdCd0Q29sb3InOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0J3Jlc29sdXRpb24nOiB7IHZhbHVlOiBuZXcgVmVjdG9yMiggMSAvIDEwMjQsIDEgLyA1MTIgKSB9XG5cblx0fSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR1bmlmb3JtIHZlYzIgcmVzb2x1dGlvbjtcblxuXHRcdHZhcnlpbmcgdmVjMiB2VXY7XG5cdFx0dmFyeWluZyB2ZWM0IHZPZmZzZXRbIDIgXTtcblxuXHRcdHZvaWQgU01BQU5laWdoYm9yaG9vZEJsZW5kaW5nVlMoIHZlYzIgdGV4Y29vcmQgKSB7XG5cdFx0XHR2T2Zmc2V0WyAwIF0gPSB0ZXhjb29yZC54eXh5ICsgcmVzb2x1dGlvbi54eXh5ICogdmVjNCggLTEuMCwgMC4wLCAwLjAsIDEuMCApOyAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgc2lnbiBpbiBXIGNvbXBvbmVudFxuXHRcdFx0dk9mZnNldFsgMSBdID0gdGV4Y29vcmQueHl4eSArIHJlc29sdXRpb24ueHl4eSAqIHZlYzQoIDEuMCwgMC4wLCAwLjAsIC0xLjAgKTsgLy8gV2ViR0wgcG9ydCBub3RlOiBDaGFuZ2VkIHNpZ24gaW4gVyBjb21wb25lbnRcblx0XHR9XG5cblx0XHR2b2lkIG1haW4oKSB7XG5cblx0XHRcdHZVdiA9IHV2O1xuXG5cdFx0XHRTTUFBTmVpZ2hib3Job29kQmxlbmRpbmdWUyggdlV2ICk7XG5cblx0XHRcdGdsX1Bvc2l0aW9uID0gcHJvamVjdGlvbk1hdHJpeCAqIG1vZGVsVmlld01hdHJpeCAqIHZlYzQoIHBvc2l0aW9uLCAxLjAgKTtcblxuXHRcdH1gLFxuXG5cdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxuXG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgdERpZmZ1c2U7XG5cdFx0dW5pZm9ybSBzYW1wbGVyMkQgdENvbG9yO1xuXHRcdHVuaWZvcm0gdmVjMiByZXNvbHV0aW9uO1xuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblx0XHR2YXJ5aW5nIHZlYzQgdk9mZnNldFsgMiBdO1xuXG5cdFx0dmVjNCBTTUFBTmVpZ2hib3Job29kQmxlbmRpbmdQUyggdmVjMiB0ZXhjb29yZCwgdmVjNCBvZmZzZXRbIDIgXSwgc2FtcGxlcjJEIGNvbG9yVGV4LCBzYW1wbGVyMkQgYmxlbmRUZXggKSB7XG5cdFx0XHQvLyBGZXRjaCB0aGUgYmxlbmRpbmcgd2VpZ2h0cyBmb3IgY3VycmVudCBwaXhlbDpcblx0XHRcdHZlYzQgYTtcblx0XHRcdGEueHogPSB0ZXh0dXJlMkQoIGJsZW5kVGV4LCB0ZXhjb29yZCApLnh6O1xuXHRcdFx0YS55ID0gdGV4dHVyZTJEKCBibGVuZFRleCwgb2Zmc2V0WyAxIF0uencgKS5nO1xuXHRcdFx0YS53ID0gdGV4dHVyZTJEKCBibGVuZFRleCwgb2Zmc2V0WyAxIF0ueHkgKS5hO1xuXG5cdFx0XHQvLyBJcyB0aGVyZSBhbnkgYmxlbmRpbmcgd2VpZ2h0IHdpdGggYSB2YWx1ZSBncmVhdGVyIHRoYW4gMC4wP1xuXHRcdFx0aWYgKCBkb3QoYSwgdmVjNCggMS4wLCAxLjAsIDEuMCwgMS4wICkpIDwgMWUtNSApIHtcblx0XHRcdFx0cmV0dXJuIHRleHR1cmUyRCggY29sb3JUZXgsIHRleGNvb3JkLCAwLjAgKTtcblx0XHRcdH0gZWxzZSB7XG5cdFx0XHRcdC8vIFVwIHRvIDQgbGluZXMgY2FuIGJlIGNyb3NzaW5nIGEgcGl4ZWwgKG9uZSB0aHJvdWdoIGVhY2ggZWRnZSkuIFdlXG5cdFx0XHRcdC8vIGZhdm9yIGJsZW5kaW5nIGJ5IGNob29zaW5nIHRoZSBsaW5lIHdpdGggdGhlIG1heGltdW0gd2VpZ2h0IGZvciBlYWNoXG5cdFx0XHRcdC8vIGRpcmVjdGlvbjpcblx0XHRcdFx0dmVjMiBvZmZzZXQ7XG5cdFx0XHRcdG9mZnNldC54ID0gYS5hID4gYS5iID8gYS5hIDogLWEuYjsgLy8gbGVmdCB2cy4gcmlnaHRcblx0XHRcdFx0b2Zmc2V0LnkgPSBhLmcgPiBhLnIgPyAtYS5nIDogYS5yOyAvLyB0b3AgdnMuIGJvdHRvbSAvLyBXZWJHTCBwb3J0IG5vdGU6IENoYW5nZWQgc2lnbnNcblxuXHRcdFx0XHQvLyBUaGVuIHdlIGdvIGluIHRoZSBkaXJlY3Rpb24gdGhhdCBoYXMgdGhlIG1heGltdW0gd2VpZ2h0OlxuXHRcdFx0XHRpZiAoIGFicyggb2Zmc2V0LnggKSA+IGFicyggb2Zmc2V0LnkgKSkgeyAvLyBob3Jpem9udGFsIHZzLiB2ZXJ0aWNhbFxuXHRcdFx0XHRcdG9mZnNldC55ID0gMC4wO1xuXHRcdFx0XHR9IGVsc2Uge1xuXHRcdFx0XHRcdG9mZnNldC54ID0gMC4wO1xuXHRcdFx0XHR9XG5cblx0XHRcdFx0Ly8gRmV0Y2ggdGhlIG9wcG9zaXRlIGNvbG9yIGFuZCBsZXJwIGJ5IGhhbmQ6XG5cdFx0XHRcdHZlYzQgQyA9IHRleHR1cmUyRCggY29sb3JUZXgsIHRleGNvb3JkLCAwLjAgKTtcblx0XHRcdFx0dGV4Y29vcmQgKz0gc2lnbiggb2Zmc2V0ICkgKiByZXNvbHV0aW9uO1xuXHRcdFx0XHR2ZWM0IENvcCA9IHRleHR1cmUyRCggY29sb3JUZXgsIHRleGNvb3JkLCAwLjAgKTtcblx0XHRcdFx0ZmxvYXQgcyA9IGFicyggb2Zmc2V0LnggKSA+IGFicyggb2Zmc2V0LnkgKSA/IGFicyggb2Zmc2V0LnggKSA6IGFicyggb2Zmc2V0LnkgKTtcblxuXHRcdFx0XHQvLyBXZWJHTCBwb3J0IG5vdGU6IEFkZGVkIGdhbW1hIGNvcnJlY3Rpb25cblx0XHRcdFx0Qy54eXogPSBwb3coQy54eXosIHZlYzMoMi4yKSk7XG5cdFx0XHRcdENvcC54eXogPSBwb3coQ29wLnh5eiwgdmVjMygyLjIpKTtcblx0XHRcdFx0dmVjNCBtaXhlZCA9IG1peChDLCBDb3AsIHMpO1xuXHRcdFx0XHRtaXhlZC54eXogPSBwb3cobWl4ZWQueHl6LCB2ZWMzKDEuMCAvIDIuMikpO1xuXG5cdFx0XHRcdHJldHVybiBtaXhlZDtcblx0XHRcdH1cblx0XHR9XG5cblx0XHR2b2lkIG1haW4oKSB7XG5cblx0XHRcdGdsX0ZyYWdDb2xvciA9IFNNQUFOZWlnaGJvcmhvb2RCbGVuZGluZ1BTKCB2VXYsIHZPZmZzZXQsIHRDb2xvciwgdERpZmZ1c2UgKTtcblxuXHRcdH1gXG5cbn07XG5cbmV4cG9ydCB7IFNNQUFFZGdlc1NoYWRlciwgU01BQVdlaWdodHNTaGFkZXIsIFNNQUFCbGVuZFNoYWRlciB9O1xuIiwiaW1wb3J0IHtcblx0SGFsZkZsb2F0VHlwZSxcblx0TGluZWFyRmlsdGVyLFxuXHROZWFyZXN0RmlsdGVyLFxuXHRTaGFkZXJNYXRlcmlhbCxcblx0VGV4dHVyZSxcblx0VW5pZm9ybXNVdGlscyxcblx0V2ViR0xSZW5kZXJUYXJnZXRcbn0gZnJvbSAndGhyZWUnO1xuaW1wb3J0IHsgUGFzcywgRnVsbFNjcmVlblF1YWQgfSBmcm9tICcuL1Bhc3MuanMnO1xuaW1wb3J0IHsgU01BQUVkZ2VzU2hhZGVyIH0gZnJvbSAnLi4vc2hhZGVycy9TTUFBU2hhZGVyLmpzJztcbmltcG9ydCB7IFNNQUFXZWlnaHRzU2hhZGVyIH0gZnJvbSAnLi4vc2hhZGVycy9TTUFBU2hhZGVyLmpzJztcbmltcG9ydCB7IFNNQUFCbGVuZFNoYWRlciB9IGZyb20gJy4uL3NoYWRlcnMvU01BQVNoYWRlci5qcyc7XG5cbmNsYXNzIFNNQUFQYXNzIGV4dGVuZHMgUGFzcyB7XG5cblx0Y29uc3RydWN0b3IoIHdpZHRoLCBoZWlnaHQgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0Ly8gcmVuZGVyIHRhcmdldHNcblxuXHRcdHRoaXMuZWRnZXNSVCA9IG5ldyBXZWJHTFJlbmRlclRhcmdldCggd2lkdGgsIGhlaWdodCwge1xuXHRcdFx0ZGVwdGhCdWZmZXI6IGZhbHNlLFxuXHRcdFx0dHlwZTogSGFsZkZsb2F0VHlwZVxuXHRcdH0gKTtcblx0XHR0aGlzLmVkZ2VzUlQudGV4dHVyZS5uYW1lID0gJ1NNQUFQYXNzLmVkZ2VzJztcblxuXHRcdHRoaXMud2VpZ2h0c1JUID0gbmV3IFdlYkdMUmVuZGVyVGFyZ2V0KCB3aWR0aCwgaGVpZ2h0LCB7XG5cdFx0XHRkZXB0aEJ1ZmZlcjogZmFsc2UsXG5cdFx0XHR0eXBlOiBIYWxmRmxvYXRUeXBlXG5cdFx0fSApO1xuXHRcdHRoaXMud2VpZ2h0c1JULnRleHR1cmUubmFtZSA9ICdTTUFBUGFzcy53ZWlnaHRzJztcblxuXHRcdC8vIHRleHR1cmVzXG5cdFx0Y29uc3Qgc2NvcGUgPSB0aGlzO1xuXG5cdFx0Y29uc3QgYXJlYVRleHR1cmVJbWFnZSA9IG5ldyBJbWFnZSgpO1xuXHRcdGFyZWFUZXh0dXJlSW1hZ2Uuc3JjID0gdGhpcy5nZXRBcmVhVGV4dHVyZSgpO1xuXHRcdGFyZWFUZXh0dXJlSW1hZ2Uub25sb2FkID0gZnVuY3Rpb24gKCkge1xuXG5cdFx0XHQvLyBhc3NpZ25pbmcgZGF0YSB0byBIVE1MSW1hZ2VFbGVtZW50LnNyYyBpcyBhc3luY2hyb25vdXMgKHNlZSAjMTUxNjIpXG5cdFx0XHRzY29wZS5hcmVhVGV4dHVyZS5uZWVkc1VwZGF0ZSA9IHRydWU7XG5cblx0XHR9O1xuXG5cdFx0dGhpcy5hcmVhVGV4dHVyZSA9IG5ldyBUZXh0dXJlKCk7XG5cdFx0dGhpcy5hcmVhVGV4dHVyZS5uYW1lID0gJ1NNQUFQYXNzLmFyZWEnO1xuXHRcdHRoaXMuYXJlYVRleHR1cmUuaW1hZ2UgPSBhcmVhVGV4dHVyZUltYWdlO1xuXHRcdHRoaXMuYXJlYVRleHR1cmUubWluRmlsdGVyID0gTGluZWFyRmlsdGVyO1xuXHRcdHRoaXMuYXJlYVRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XG5cdFx0dGhpcy5hcmVhVGV4dHVyZS5mbGlwWSA9IGZhbHNlO1xuXG5cdFx0Y29uc3Qgc2VhcmNoVGV4dHVyZUltYWdlID0gbmV3IEltYWdlKCk7XG5cdFx0c2VhcmNoVGV4dHVyZUltYWdlLnNyYyA9IHRoaXMuZ2V0U2VhcmNoVGV4dHVyZSgpO1xuXHRcdHNlYXJjaFRleHR1cmVJbWFnZS5vbmxvYWQgPSBmdW5jdGlvbiAoKSB7XG5cblx0XHRcdC8vIGFzc2lnbmluZyBkYXRhIHRvIEhUTUxJbWFnZUVsZW1lbnQuc3JjIGlzIGFzeW5jaHJvbm91cyAoc2VlICMxNTE2Milcblx0XHRcdHNjb3BlLnNlYXJjaFRleHR1cmUubmVlZHNVcGRhdGUgPSB0cnVlO1xuXG5cdFx0fTtcblxuXHRcdHRoaXMuc2VhcmNoVGV4dHVyZSA9IG5ldyBUZXh0dXJlKCk7XG5cdFx0dGhpcy5zZWFyY2hUZXh0dXJlLm5hbWUgPSAnU01BQVBhc3Muc2VhcmNoJztcblx0XHR0aGlzLnNlYXJjaFRleHR1cmUuaW1hZ2UgPSBzZWFyY2hUZXh0dXJlSW1hZ2U7XG5cdFx0dGhpcy5zZWFyY2hUZXh0dXJlLm1hZ0ZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XG5cdFx0dGhpcy5zZWFyY2hUZXh0dXJlLm1pbkZpbHRlciA9IE5lYXJlc3RGaWx0ZXI7XG5cdFx0dGhpcy5zZWFyY2hUZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXHRcdHRoaXMuc2VhcmNoVGV4dHVyZS5mbGlwWSA9IGZhbHNlO1xuXG5cdFx0Ly8gbWF0ZXJpYWxzIC0gcGFzcyAxXG5cblx0XHR0aGlzLnVuaWZvcm1zRWRnZXMgPSBVbmlmb3Jtc1V0aWxzLmNsb25lKCBTTUFBRWRnZXNTaGFkZXIudW5pZm9ybXMgKTtcblxuXHRcdHRoaXMudW5pZm9ybXNFZGdlc1sgJ3Jlc29sdXRpb24nIF0udmFsdWUuc2V0KCAxIC8gd2lkdGgsIDEgLyBoZWlnaHQgKTtcblxuXHRcdHRoaXMubWF0ZXJpYWxFZGdlcyA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xuXHRcdFx0ZGVmaW5lczogT2JqZWN0LmFzc2lnbigge30sIFNNQUFFZGdlc1NoYWRlci5kZWZpbmVzICksXG5cdFx0XHR1bmlmb3JtczogdGhpcy51bmlmb3Jtc0VkZ2VzLFxuXHRcdFx0dmVydGV4U2hhZGVyOiBTTUFBRWRnZXNTaGFkZXIudmVydGV4U2hhZGVyLFxuXHRcdFx0ZnJhZ21lbnRTaGFkZXI6IFNNQUFFZGdlc1NoYWRlci5mcmFnbWVudFNoYWRlclxuXHRcdH0gKTtcblxuXHRcdC8vIG1hdGVyaWFscyAtIHBhc3MgMlxuXG5cdFx0dGhpcy51bmlmb3Jtc1dlaWdodHMgPSBVbmlmb3Jtc1V0aWxzLmNsb25lKCBTTUFBV2VpZ2h0c1NoYWRlci51bmlmb3JtcyApO1xuXG5cdFx0dGhpcy51bmlmb3Jtc1dlaWdodHNbICdyZXNvbHV0aW9uJyBdLnZhbHVlLnNldCggMSAvIHdpZHRoLCAxIC8gaGVpZ2h0ICk7XG5cdFx0dGhpcy51bmlmb3Jtc1dlaWdodHNbICd0RGlmZnVzZScgXS52YWx1ZSA9IHRoaXMuZWRnZXNSVC50ZXh0dXJlO1xuXHRcdHRoaXMudW5pZm9ybXNXZWlnaHRzWyAndEFyZWEnIF0udmFsdWUgPSB0aGlzLmFyZWFUZXh0dXJlO1xuXHRcdHRoaXMudW5pZm9ybXNXZWlnaHRzWyAndFNlYXJjaCcgXS52YWx1ZSA9IHRoaXMuc2VhcmNoVGV4dHVyZTtcblxuXHRcdHRoaXMubWF0ZXJpYWxXZWlnaHRzID0gbmV3IFNoYWRlck1hdGVyaWFsKCB7XG5cdFx0XHRkZWZpbmVzOiBPYmplY3QuYXNzaWduKCB7fSwgU01BQVdlaWdodHNTaGFkZXIuZGVmaW5lcyApLFxuXHRcdFx0dW5pZm9ybXM6IHRoaXMudW5pZm9ybXNXZWlnaHRzLFxuXHRcdFx0dmVydGV4U2hhZGVyOiBTTUFBV2VpZ2h0c1NoYWRlci52ZXJ0ZXhTaGFkZXIsXG5cdFx0XHRmcmFnbWVudFNoYWRlcjogU01BQVdlaWdodHNTaGFkZXIuZnJhZ21lbnRTaGFkZXJcblx0XHR9ICk7XG5cblx0XHQvLyBtYXRlcmlhbHMgLSBwYXNzIDNcblxuXHRcdHRoaXMudW5pZm9ybXNCbGVuZCA9IFVuaWZvcm1zVXRpbHMuY2xvbmUoIFNNQUFCbGVuZFNoYWRlci51bmlmb3JtcyApO1xuXG5cdFx0dGhpcy51bmlmb3Jtc0JsZW5kWyAncmVzb2x1dGlvbicgXS52YWx1ZS5zZXQoIDEgLyB3aWR0aCwgMSAvIGhlaWdodCApO1xuXHRcdHRoaXMudW5pZm9ybXNCbGVuZFsgJ3REaWZmdXNlJyBdLnZhbHVlID0gdGhpcy53ZWlnaHRzUlQudGV4dHVyZTtcblxuXHRcdHRoaXMubWF0ZXJpYWxCbGVuZCA9IG5ldyBTaGFkZXJNYXRlcmlhbCgge1xuXHRcdFx0dW5pZm9ybXM6IHRoaXMudW5pZm9ybXNCbGVuZCxcblx0XHRcdHZlcnRleFNoYWRlcjogU01BQUJsZW5kU2hhZGVyLnZlcnRleFNoYWRlcixcblx0XHRcdGZyYWdtZW50U2hhZGVyOiBTTUFBQmxlbmRTaGFkZXIuZnJhZ21lbnRTaGFkZXJcblx0XHR9ICk7XG5cblx0XHR0aGlzLmZzUXVhZCA9IG5ldyBGdWxsU2NyZWVuUXVhZCggbnVsbCApO1xuXG5cdH1cblxuXHRyZW5kZXIoIHJlbmRlcmVyLCB3cml0ZUJ1ZmZlciwgcmVhZEJ1ZmZlci8qLCBkZWx0YVRpbWUsIG1hc2tBY3RpdmUqLyApIHtcblxuXHRcdC8vIHBhc3MgMVxuXG5cdFx0dGhpcy51bmlmb3Jtc0VkZ2VzWyAndERpZmZ1c2UnIF0udmFsdWUgPSByZWFkQnVmZmVyLnRleHR1cmU7XG5cblx0XHR0aGlzLmZzUXVhZC5tYXRlcmlhbCA9IHRoaXMubWF0ZXJpYWxFZGdlcztcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggdGhpcy5lZGdlc1JUICk7XG5cdFx0aWYgKCB0aGlzLmNsZWFyICkgcmVuZGVyZXIuY2xlYXIoKTtcblx0XHR0aGlzLmZzUXVhZC5yZW5kZXIoIHJlbmRlcmVyICk7XG5cblx0XHQvLyBwYXNzIDJcblxuXHRcdHRoaXMuZnNRdWFkLm1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbFdlaWdodHM7XG5cblx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHRoaXMud2VpZ2h0c1JUICk7XG5cdFx0aWYgKCB0aGlzLmNsZWFyICkgcmVuZGVyZXIuY2xlYXIoKTtcblx0XHR0aGlzLmZzUXVhZC5yZW5kZXIoIHJlbmRlcmVyICk7XG5cblx0XHQvLyBwYXNzIDNcblxuXHRcdHRoaXMudW5pZm9ybXNCbGVuZFsgJ3RDb2xvcicgXS52YWx1ZSA9IHJlYWRCdWZmZXIudGV4dHVyZTtcblxuXHRcdHRoaXMuZnNRdWFkLm1hdGVyaWFsID0gdGhpcy5tYXRlcmlhbEJsZW5kO1xuXG5cdFx0aWYgKCB0aGlzLnJlbmRlclRvU2NyZWVuICkge1xuXG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIG51bGwgKTtcblx0XHRcdHRoaXMuZnNRdWFkLnJlbmRlciggcmVuZGVyZXIgKTtcblxuXHRcdH0gZWxzZSB7XG5cblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggd3JpdGVCdWZmZXIgKTtcblx0XHRcdGlmICggdGhpcy5jbGVhciApIHJlbmRlcmVyLmNsZWFyKCk7XG5cdFx0XHR0aGlzLmZzUXVhZC5yZW5kZXIoIHJlbmRlcmVyICk7XG5cblx0XHR9XG5cblx0fVxuXG5cdHNldFNpemUoIHdpZHRoLCBoZWlnaHQgKSB7XG5cblx0XHR0aGlzLmVkZ2VzUlQuc2V0U2l6ZSggd2lkdGgsIGhlaWdodCApO1xuXHRcdHRoaXMud2VpZ2h0c1JULnNldFNpemUoIHdpZHRoLCBoZWlnaHQgKTtcblxuXHRcdHRoaXMubWF0ZXJpYWxFZGdlcy51bmlmb3Jtc1sgJ3Jlc29sdXRpb24nIF0udmFsdWUuc2V0KCAxIC8gd2lkdGgsIDEgLyBoZWlnaHQgKTtcblx0XHR0aGlzLm1hdGVyaWFsV2VpZ2h0cy51bmlmb3Jtc1sgJ3Jlc29sdXRpb24nIF0udmFsdWUuc2V0KCAxIC8gd2lkdGgsIDEgLyBoZWlnaHQgKTtcblx0XHR0aGlzLm1hdGVyaWFsQmxlbmQudW5pZm9ybXNbICdyZXNvbHV0aW9uJyBdLnZhbHVlLnNldCggMSAvIHdpZHRoLCAxIC8gaGVpZ2h0ICk7XG5cblx0fVxuXG5cdGdldEFyZWFUZXh0dXJlKCkge1xuXG5cdFx0cmV0dXJuICdkYXRhOmltYWdlL3BuZztiYXNlNjQsaVZCT1J3MEtHZ29BQUFBTlNVaEVVZ0FBQUtBQUFBSXdDQUlBQUFDT1ZQY1FBQUNCZWtsRVFWUjQydTM5VzR4bFdYcm5oLzNXV3Z1Y2lJek1yS3hyVjgvMHJXYlkwK1NRRktjYjRvd0lrU0lGQ2pZOUFDMUJUL0xZQm96UmkrRVgrY1YrOElNc1lBYUN3UmNCd2p6TWl3MmpBV3Rnd0M4V1I1UThtREZIWkxOSFRhclpHckxKSmxsdDFXMnFLcnN1bVpXWmNUdm43TDNXNTRlMXZyWFgzdnVjaUxQUE9SRlIxWEUyRW9tb3JCMG5WdXovL3I3MXJlL3kvMWVNdmI0Q2IzTjExeFYvUFAvMnY0VUJBd0pHLzdIOHVyeDYvMjUvR2Y4TzVoeXBNUTBFRUVRd0FxTGZvTi9aKzk3Zi9TVysvTnZjZ1FrNHNHQkpLNkg3TjRQRlZMK0srZTBOMTF5TmZrS3Z3VWR3ZGxVQVhQSEhMMzhvYTE1Zi9pLzQ2SWg2U3VNU1BtTEFZQXd5UktuN2RmTUdIOTdqYU1GQllDSlVnb3RJQzJZQWR1K0x5Vzl2dnVieEFQOGtBTDhIL2tvQXVPS1AzK3E2K3hHbmQ1a2RZQ2VFQ25HSUpWaXdHSk1Ba1FLZkR2QjNXWnhqTEtHaDhWU0NDemh3RVdCcE1jNS9rQmJqYXdUNEhud0pmaHIrcFBCSXU3dXUrT09Ubzl2c210UWNuaU1CR2tLRmQ0akRXTVNDUlVwTGpKWU5Ka00rSVJ6UStQUXZJZUFNVHJCUzJMRWlhaVI5Yi81UHVUNkFwL0FjZkFGTzRZM2RBM0RGSDcvVlMrTThrNGJhRUFRZk1JNFFmYlZEREdJUmc3R0thSVk1MnFBalRBZ1R2R0JBUEdJSWdoT0NZQVVyR0ZOZ3pBN1EzUWhnQ3dmd0Fud2U1dkRlamdHNDRvL2ZibTFDNVpsWVF2UURBUlBBSVFHeENXQk0rd1dsMzdaUUVTYjRnSW1leEdNRG91aEdMeDFDc3QwU2FhNGI0QXFPNEhrNGd4byszREhBVi9ueDI3cDNKemlQTTJwVmdvaWlhNU1kRXpDR1VMcHJJTjdnRUVlUTVJUXhFQkJCUW54aHNEYjVhdUdtQUFZY0hNQTllQUF6OFBCb2w4L3hpajkrQzREamxpbTRnSmpXY3daQmhDQmdNSUlZeEdBVklrSDNadGNCdUxkdFJGTVdzUEdvWTlyTitIb0JqaTlWQllkd0QyWlFnNGNuTzdPU3EvejRyVTVLS2R3VmJGQWpOb2pDUXpUbENMUEZTeHRhbXdoMmpNVWNFZ2cyV20vNlhnRXJJQmhCY2tRdEdOM0N6YlZhY0VSZ0NuZmdMc3dobnZxZjdReUFxL3o0clJabTFZZ2xZRTNhZmZHSVRhWnNkSWUyRm1NSXBuT0NhcDI1STZqdDJrQ3dDVzBEMXVBRDlzWmN0TkdYY1FJSENrSU5EUWdjNzhhQ3Iremp0dzNCVS9pamRwdzN6aEN3Y2FPTndCdmRlUzJZWktrSk5Kc01QZjJKS0V2QzI4Ulh4eEkwQVNKeXpRQ2pDRVFyTzRRN3NGQXJFempaaGFGYzRjZHYrL0pGZEtVTE00cHgwRGZVQkkyaElzeTA2QnFMaEdUUUVWZGJmQUlaWFlNUGVzcTZWb0NISUN6VXlqd0luTzRZNDExLy9MWUxzNlREYTl3dmcyQ0MyckVsZ0FucFRCemlUaHhhTDIyTVloemZrZ2h6NkdBczJWSGJiZE05MVZadTFNRUVwdXBNTXdLeVZUYjVpajkrdTRWSkcvNUVnRU1NbUZGMDFjRmFpM2lzUmJLYnpiK1lhVS9NUWJBbTJYU01vVVBBbXZaemJ1S1lSSUZBcGJ0bHJmRnVVR2Q2dnEyaFhObkg3OFpMaC9pRmhzUUczVDREMWliN2s1Q0M2dlkwRENidHJvaGdMRUlDbFhpR3RsMTB6YzBDbkVHSWhoYXRMQnZhN05QNThUdncwcUU4eVdoQVJMUThoNCtBaFFTUCtJNEY1eG9VK1ZpbEdSSnM2d25TN3J1dGkvNEt2QVkvQ2ZkZ3Fqc015NHBmOGZvZFFPOC9nbnVYM2YvM3hpM29tMS9oN1RIcitjbzN4OTNQUDkrRkJVZmJOVWpjakVtaGNya1QrOEs3bWw3VjEwSm8wNW1wSUVGeTFObUNKV3g5U0lLS3QrRWpBTDRFejhFQlZPQjZoYXZ1VC9yQnlQdkhYSys5elVjZmNiYjI1NCs5ZnlkSmtuWW5ScjFvR2ZkYWlBZ3B4dTFSeC9SZWs4S0lTZnR4M0wrRGZzTFdBQU5uOEh2dzAvQUZlQUdPOURGVjNjNkQrQ2NXYkw4RGo5ZTdmK1QxazhBWnYvZDcrUFhXTS9aK1Z2ZENySXZ1QUtPMDlScEVFUUpNMENpNitCNHhoVFdyNGNaTk92aGt0YWJ3MHRhMHJTSm1xejNZdzUvQUtYd2Vub2Q3Y0FoVG1CU1BLZjZKQmR2SDhJUDE3aDk1cFhxdzUwLytCRm5qODhmZXY0TmNoeWFLNDdPUGhodEk4UkZTdkFmRFNOaDBDazBwMmdMeEdraWI1TkpqL0pXQ3I5MEVXUUp2d0J6TzRBSGNnenR3QUZOMWV2SFBVVkd3ZlhPTiswZGViVDFZZUdPTjlZeTkvNjNYK09ndWl3bWhJaFFoRDdsNHNNcWxHM0Q4NlN1YzNxV1o0cldqSTFYN3UwWXR3NngzcklNZUlPUERwcmZlMlh6Tmd5ajZQYWhoQmpPNEMzZTZwdURnWHJkZysvNWw5NDh2RjNicXdaZXRaK3o5Ung5emRJWTVwSW5QSzROazB0K2w1MnhkSzJCNDVRZDg3bk04ZnNENUVmVWhJY0pjRVJ3NFJkcXFIN1lkZTVWN20xdmhObXRlZGt6NkVEelVNRi8yakpZV2JDKzRmenpBL1krLzhQUEgzajlkY0JBUElSUDhKTFhkNUJwQXUwM2F6aU9MM1ZWSFp6ejNDWFdEUFdkK1NIMkFueElxUW9UWnBvOUNrYzZISXJGYkFiek5tbGNnOEFnOE5GRERBaGJKdlRCWlhiQzk0UDd0NjhFWGZ2Nm8rMjFnVXRQRVRVN2Jia0x4dk5LUkZHMitLWHp2dE9ib25QUDRyQnZzZ21hS2o0MDREbHNoRm9sZTFHbGZoMDJmRTdiWVI3ZFo4Mm9UZXdJQkduMU1kNkNHNllVRjI2WDM3Nm9ldk9Meng5NXZoVW1nYmxJNkxCWndUQ0RZN3ZNcTBvcDVXVlhnc09iT1hKKzF4M3FhQmw5ajFGZUx4YmhVOXcxRitXaWJhNnMxWC9UQnoxTG5VZnVZRGk0cjJDNjlmMWYxNEJXZlArcCtXMkdGS3VDOXBoY0VMTVlSUkx1cjlERVpUVWRFSCtpRXFXZGFNN1g0V09vUEdJK1pZRDIrd2NRK3kraW9IVVo5ZFREYkFyenhtaS9iSkk5Qk5EMFluZDZsQmR2ZS9idXRCdzgrZi9UOUQzQUJhM0FHOFczVlBYNGhCaW4rYmo4ZE1NbVNwcDVwZzdmSjZ4ckJGRTJXUVFFV25WOFFnM0ZiQVd6WWZNMXJSRUVubXZrTjJvMSthY0cyZC85dTY4R0R6eDkxdjNtQWpiMXprcHFUMjFPaXBQS08wYjlUTzVXMG5UZE9tQVFtMFRPYnRzM2FCS2d3QVJ0b1BEaUNUMGdIZ3duYkFyenhtdGNMYzA4SGdGMWFzTjBDNE1zL2Z2RDVJKzdQaGZxeVhFL2I3UmJickd5UlFSVDlBUlpjd0FVbWdkb3owZWhKOUZuN1FBaFVqaERBUVN3MGJWM1QzV2JOYTU5anptaVA2R3NXYkdYRFgyeXRqeTgrZjlUOTdmaUJQcTlZZUxkQm15dWl6WkhhcVhJVG5YaU1VRUVWY0o3SzRqM0JGUHVydEI0Yml4Vzh3VHB3ZUw4REM5NXN6V01PcXVjRllHc1diR1U3cDNUeHh4ZWZQK3Irb1RWa3R4WTB2NWhicTNLaU9LWW5ZOGRkSlZTQnh1TU1WZmZOYnh3SU9FUlNoc3Q3M0haNzhEWnJIcG1KbUgzSzZzR3owZmUzVVVqMGV5UnJTQ0dUVGMrcmpWTm9Hek5TdjA1c3JBeFVCaDhJaHFDaGlRZ1ZOSUlCSDNBVlBucnNuWFFaYkxUbThhbW12OGVWWG4vdldwYVRlbTVJWFJsdCtVL0xBMjF6aFNiOWN5ZTZqY09mQ25Pd2hJQVlYQU1WVFVOVjBRaFZoYTl4amdBMjdPREpiTGJtaXR0M3RSTjgwbHFHNk4va2hnb3Q0WlZsT3lPNFdOZzNPSU16aElaUXBVRUhpZWcyaW02RjkxaEIzSTJ0dWJxbDZCWU5OOUhqNVM3RzBHMnRhaHNsQldLRG5PaUl2dUFFRHpha0RRS0RORlFUNmdibjhFMnk0QkJ1Yk0yMzBZSXBCbkRiTWEreTNkeDBuMVMwQnR1RzYybENDWHdjWTBGNzJUMVZSUjN0Mk9OY3NtRGpibXpOdDlSRnMyTE8yaFFOeWIwMjJKaXNhSThyQVd1dzRISTNGdUFJaFpkT0dJY2RqTEp2dk9icWxwcXZXVEpublFieWkvMU05TzhVeFdoQnMvL0g0MkkwcTFZYi9YUEdPTnpjbW0rcmkxNzJtSEt2WkJwSGtKYU5KejZ2OWp4cWlrbERqM1U0Q0EydWdwQWFZTVdxTlhzZFhibUpOZDllZ0NuSkVzcGhYTk0rTW5LM20wRkNKNVMxa21KcGEzRGdQVmJuUW5QR1dJRHNwVzlvemJjTzRLLzlMa2ZhUU8yS0h1cWxmRlhTYmROemNFY3dvcU5FRkU5emNJWHU5LzZuL3ltL0JDL0MzYUpMekVLUHVZVmxiRm5maFo4a2NXeFYzZGJ2NGJLbDI4NTY2d0QrOEM1M2F3NDlsVEFCcDlQV2JzQitrbmZjL0xpM2VWaXpmNXZ2L3htdm5QS2c1aWh3S0V3bHJjSHF1Y3VWY1ZPeEV2OGFIMzdFM1pxcFp5cFV1bHJIRXRJV0tVcit0eEhnK29qWkRHbHducW1rR2x6Y1ZpMWRMaU5TSmlIamZiUk5PUHdLcHg5VFZkVG4zSzA1REJ4NHBzSWs0RWk4YUNrSmFoUmdmZms0WW5FWGUwN1Q0SDJSUjF1MjdFNndmUXNCRG9mVWdqRlVGbndDMkFpVnRBKzA1SjJ6cGlESzJPYTBjNWZtQWVjTjFpSnptcHFGWnhxWUJDWWhGVENzVU5FbVVuSWNaNmFFQTVyUVZoRXl3RzZ3N0hTVzAyWGZPb0JsUW1qd3VsT0ZRQWc2NlN2SmJsclRFWDFZdEozdUcxNVQvQkgxT2ZPUWV1UjhnL2MwZ2RwVDVmeDJTS2JzOUVmSFRLZE04QTFHYUpSSExWSXdoY0d5eWRac2JpZkFGVktsNUVNS05VMkhyeW8rMDZCZVRncW54ellqVGhWeVNEaWtidEpQaWVjbzc1bFlmS0FKT01FWkJUam9JVHVXSFhYWlZoY1VESVMyaHBpWEhWOUt1NHU0NGJONU9ZTERPa0pvOHcreEpTTWJoQlJIRWRFczlKWlVDa1FyUE1BdmFIeUxreGdrRUh4aU5reC94MllCMG1Hc1E4RVVXai9zdFc1WUxodFM1U011Ky9ZQmJOUERDa0dUVXliTjhrclJMQkdQbFprVk9BMGorYTErcmt5UUtXR2FQSFBMWk9rSmhpb1FZblZaMmhTM3pWeE10Z0M0Nkt1UndiSk5kOW5WMlBIZ2IzNkYxOTRlY2YvWWV1MnZBRmU1bm0vYlJCRnJuWTRCYXVFOEVSbVpSRlVuMGs4aGJmdGlWWVNLTUVtZTJkSkNKU0NHWUFsTnFoODdiWE9QZFVrR3kyNFA2ZDFsbDIxTUJxcXg0OEZ2djhaSEg4SFpGWTdqL3VBcTF4TUpVRnFDU1VsSlBtTmJJaU5zbXd1TXMvcTlDTXRzWnNGTzZTcHJ6Q1MxWjdRTDh4Q1FDbEVlbHBqVGR1RE1zbVdEOFMxUFQxNTJCdHZtSUd2VWVEQS95Um44M3UveDAvNHF4b1BIangrUFhZOXBxWDliZ012aC9OejlrcFA0cE9lMS9mWWYzYXhVaU1kSExsUHBaQ05qZ3RORkFoY0hFRHhUdW1OT05oSHJCZHVXK3ZPeVkrKzcwV1duUFhqOThlQTRrT3QvbWovNUUwNWw5K080bzhlUHg2N0hGcXlDK3FTU255c2VscWpaR2FWSzJUYWRiRkxQV0FRNE5CaEhxRENDVjdPVHBvMzRBbFNTeWxQdElkZDJBSlpseXpZUXJESjVsY1dHTmNlRDgwQ3VuUExHR3pzZkQrN3dSYjk1TmV2Skk1ZG9jUTN0Z0N5cjViR255YVBSbG13TnNGRUxWaU9PeDlsb2ViR05xMm1vRE9LcEhMVlA1YWwyY3ltV0hia2Z6R1hMN2tmUmw0NEg5d1p5MzN0dnQrUEIvWG5mOTNlK25oNVpsVTE4d0NpUlVhOW03a2liOUxZdU9rK2h1ZFFOYnh3bTBBUXFiZmxvaW1hQjJsTTVmQ2hleCt5bE13dVRiZm1YUXRtV2xlblpsamJkWFRMdU94akkvZkRESFk0SGp4OC9IcnNlMHpYZlBGeGJVTjFrS3FTQ0NTazUwbTBBanR4M3ViOVhIQktIWEVTYjhpTzZFK3FHeXRGNG5PME9HM1NYemJKbGh4Qm5LdEt5bDBOd3lianZZQ0QzMGFNZGpnZVBIejhldTU2U1ZUQmJneEpNbGlRM09hdXdnMFFIeFhFMkV6L0VJUmVMZFFqNDJHemI0Q0xTMFlKRDl4VXg3YnNpMHZKaTVtVWJXMVF6TDBoMFBGazE3cnRpSVBmSms1Mk1CNDhmUHg2N25wSkp3eXJCYTJSQ0NRUlRiR1pTUEN4VFBPaU5ENEcycFl5T1E0aDRqSU5JSmg1d0ZVMU5GWnQrSXNaNTlMU25EcUJqWjJhd2JPa3UreUludW5MY2Q4VkE3ck5uT3hrUEhqOStQR1k5QjBNV0pKTm96T0ptbGdsdkRNWERFb3pkaFFXYmdzL1U2b0Jhbkd6THJkU05OblpGak9rbWJpNWJOdDFsWDdKTExobjN2WEFnOS9oNHkvSGc4ZVBISTlkelFNRWtXQ2dkUmZZeWtZS25rUDdENHJJdWpzdWphS1BCc0I1NHZFMlRTMDBjY3ZGWS9UdGg3SlhlcTFoeitxZ1Z5MDRzQUphd1Rzdk9rbkhmQ3dkeVQwNjJIQThlUDM0OFpqMHZkb1hGNHBpbEthMkJST2VkKzlmeXc5cldSWGVURlhFU01PYW52RFpmSnVKYVNYb3VRZE1kREpadGVrWmNMTHZFZUswNGQ4bTQ3NFVEdWFlblc0NEhqeDgvWG5zOVlZcVpwc3pHV0IzQU4vNFZIdytrN1dTRnRKM1FpY3VxYi9ObFZtZ1hXc3hoNTcweGcyVXd4VXczV2ZPNkI1bk91TzhhQTdsblp4dVBCNDhmUHg2em5tMWk0YnNmY2JhcHRGM3pOVDc4ZUZQdHdpMU9hQ05PcXAxeDN6VUdjcy9QTisrQUdEMStmTVhyU1ZtMmJhVHRQaFBhaGJQaEE3MXdJSGQyYlh6UmE2OW5HKzNDcmFUdFBpdmFoVi81NXRYV2c4ZnlSWS85QWRzWThWYlNkcDhWN2NLcnJnZGZNLy96NklMUUZ0SjJueEh0d211b0I0L2tmNzQrZ0xlUnR2dk1hQmRlU3ozNCt2aWZ4MFlHMjBqYmZUYTBDNit0SHJ3ZS8vTm1PRzBMOEViU2RwOFI3Y0xyclFlLzk5Nk8rYWkzdWpRT3NrcFROVUxhN2pPalhYajk5ZUNkOGxIdm9GaXdzYlRkWjBhNzhQcnJ3VHZsbzk2NnBMdVJ0QjJmRmUzQ202b0hQOWtOSC9XMkZyeXh0TjFuVEx2d1J1ckJPK0tqM3BXWEhpZHR4MmRGdS9CbTY4RmI4MUh2eWt1UGxyYjdMR2tYM213OWVHcys2aDFZOE1iU2RqZWdYY2d1UUxqbWV2RHBUUUxNeHRKMk42TmR5Qlp1OUFicndWdndVVytMYnRlVUxVcENkcW0wSFRlbFhiaE5QZThHNjhHYjhsRnZWZllmU051eHZyVGRUV29YYm96QXpkYURaemZrb3JPajFveFZ4bElNbHBTSWxwTHJ0OEQ0aHJRTDE3eitjM2g2aFUvd3Y0US91dHBzNCtibSs2UC9oSWNmMEp3UTVvUUdQQkwwZUtQVFlFWFRXK2VMLzJES243M0o5QlRYWUFORzU3aHoxY0VNdmlWZi80dGY1Yi82QzVwVFFrTUlXb0FxN2hUcE9KanRBTTRweEt1NXZnNXZYZVVydEkwOS9Nby81SCs0eitNcDV4VUxoN2NFbTJRYlJQMnRGSUtSN1dNM2ZQZi9qWjNTV0NxTE0ybDROeElENXpCNzJIUVh2M2pqLzhtTFI1eFhOQTV2OEViRlFFejdQcFJmbDErTUIvaGxBTjY1cWdEbjN3VGdIMTNoSzdUNTlibVArTkl4MVNISFU4NG5MT0lUdDNpVno4bU5PK2xQcmpHQW5CRnFtaW9ObjFtVHlrMXRhNDdSNmQ0TXJYN3Rqcm5qWVVwZFVidjJyVnI2WXBWZnNHRzU4QUc4QWg5ZXlVTjhDWDRXZmdWK0c4TFZXUERHYitaZDRjVTU4NEN0cVNiTUt4YXV4VGcrZHluL0xrVmdBK0lSOEtIdGVqZUZLUnRUbUxMcHhONm1ZVkxqWXh3WGY1eDJWb2ZpWmNwL2x3S2s0d0dPcFlEbm9JWlBkZy9BQWJ3TWZ4MCtnZTlkZ1p2WWp1cUtlNEhuR255a1lvNVR2SmJHMFZqMTJKYWdSaHdLYTQ0SDk1U2hrWmE1UnlMR0dkZll2RzdhdzFUc0Y2aWFwUEFTMjltTlMzTm1zVFFaQ21nVHpGd2dMM3VwQ1RndEJUUnd2R01BS3JnTG40ZXZ3aW44K2FmSlJjZmYrOGl6VUdVTTYzR09PdUFzM3RKa3c3SjRreW9OcmVxcnBPNmNZTFFlRlVkN1RUcHI1WU9UTGM5UlVVb2dVT1ZKUTFHWUphRkxBVzBvVG1LeVlTNDZab29QNFM0RU9OM3hRNXpDOC9DWDRDbk00YzFQRThBcGV4cG9ZdXpxbFAzZDRTM09KUDhaREs3Y0tXTmFUbHFtZ0RpaUh3bDFZc0U0MXcxelQ0aVJUbTNEQnF4dk9Vc2JNS0tEYS9FSHhhZ3RudGEwNzJlamMzRE9JaDVvanZoOGwzdGsxSkYvQVY2RlU2amgzVThId0VhekxnZENMWVNRK01ZaUFJMmx0b21renR0VWIwZ0dIZFNVVWdzSVlqVHpMRzNtT2JYNEZCUmFZdHBEVk5acmloOVRnVGVZT0J4c0VuTjFnT0NUTThCc3cvaWVNYzc1dzlrdUFUNkErL0FpSEd2Ti8rR240S1JraXV6cE5ORFloREdGbmRXUnBFNlNWZm04VTVieG5TZ1ZWMmpyZzZKQ0ttbmVxZXk4Vk1GZ3EyK0FNL2k0TDRSVWJmU2kyN2xOWFo3UjdXOVJUY3EvcTlmazRYdzNBTVFkNEk1aWZBWno4RmNWdG05U0FvbS9keU40bGN6SlFXL2tDNDJackhnY0NvSWYxb1ZNS2tWSXRtTUJpOWNPZU5IR0xxT1prK1FxUW1yYmM1WW1ZZ3hFTFVVTjM1ejJpb2hzdGdmTElGbWNNVjdzNENGbUk3NEw5K0VGbUdzaSt0R25BT0Q0WWs5Z0lwbzAxWTRjQTQzQldHeWdNZHI0WVpla0czT0JJVVhYTnVrdkpTOHRxYTA2ZStsU0RDdG5xcU1GdTZoV0hYQ0YrV2FZdDY0bTlRQm1OeGk3SW95N0QrZmExeUh3K0ZNQWNQdDdTeXNGTHRvRzRQWEFrN0pPQTNhQXhCUnFVaUFkVTlZcDVsSzNITFNSRnRPaW0wc2E4ZXVFdDA4eHZLallqemVKMkdVN1lhd2V4cm5LSTl0bW9iSW5qRlhDZXdwd3JpWTkrUlI0YWFlekZoTWhHQ3BwS3dvbTBDaHJnRmxLenlQS2tHbFRXMVlRckU5SEpxdThoS0dnTWM2aFZpNVFScTBQWnhOZnJZTmdFNjR1dG1SdjZLS0hScHhmNlZEVWFPdk5QNWpDRXg1cTE4NU15LzdSS3o2OVVRdTJpbTVrNC9lb3ducHhaeE5Md2laMUFaVE8yWmpXamtVOXVhQjJIRm42UTN1MEpjc1N4L3FWOWhURUFwUnplQkxESlFYeFltVG5xN2JkTGEzK3VxRnJ4TEo1dzFUZWhuTkh4NUVDdkNoMmcyYzNoSEg1WXNmZGFTS2RkenRmalE2aW1LRkdTeUZ3bEx6eEVHUHA2cjVJZXZWamsxQU14M3dNcWkxTnhEVmpMQmlQczl0YnNDa0lZNXdlNS9NTDIyenJDU2NGeG5OdHpzcjlXY2MzQ25EK3BZTys0VlhYaURFMG9jL3ZRUS9mREszb1BFU0pNWVhObUphL0R1bG9KWmtjVHBjWUU4bElIOER6OERKTWl5bk5DODZNYjJsTmFhcVAvK0w3ZjJmY0UveVA3L0xkZTh4ZmdTT2RNeHZPaXhaZi85cDMrTTRoVDErRit6QXB4ZzlYZlV2WWpjOHFYMmxmT09wSzJnTlJ0QjRmbHBGdTlGVEtDcDJYSlJnWG5YNm9scDF6eVlqVEtKU2tHbUxFMk5qVXIxYnhGTTRBZUFBSEJVRkllU0xxWFIrTnZIL005Zk9uZkh6T0QydkNTeVFKS3pmZ3NDaCt5aS9NbWMzNUYyZlVydzdtaVczM1c5aEJEMXZwdVVvakZwaEl5dmc3YVRlb3ltRGtJa2VXM1hMSG1ndU16YklBSmVqTjZCNU1EcmhpcEUyeTZTb0ZSTy9BSy9BY0hIWkhOSWZpV3JFZS9DNmNyM2YveU92clFLQit6TU01NS9HUWRMRHNSK2lmcjVGaXV1Ky95K003OEx6T0U1ZHNOdVhDM1BZdllXZDhOWHZwaExTa0pJYXNybEQyL0hPcVErUmpjUmRqS1RHV1loaFZVbTR5eGx5aUdQdU1zWlI3c01DSFVCZVR1TldBN2lmK2lmWGdjL2hvdmZ0SFhzL0RWK0Z2d2UrZjhzaHpNaU1jd2VGZ0JseTMvL3Z3SmZnNUFONDQ1MGZuMUhkMVJtMWFCTHUyMkR5M3kzSDIrT3FNZW1rYkdaNGpvemNEakpmNjU5NnhPTHBDMGVNVEhiS254THhIMjd1Wi9iTVRHczJqT2FNT1k0bTg3Q2ZRd0YwZHc1M29hMWs4MEpSdXovWGdTKzhmWDNOOUFmNHFQSU1mektnQ3A0SDVUREdlOUdHZUZQelNzWno4MFNsUFR4WGpnd0ptQzQ1bmp6Z3QydmJRNGI0T0FkVUs0L3ZXaE84ZDh2NkVFOGZNVXNmYWtYYlBwRkplTHMydWJNL3FkbS9sYTNXUDkxdVdoeFhIam9XaHlSVXEyaUovKzVtQTczendJSW8rTG9aL1NndklSakFkMUlNdnZuOThQZmdPdkFKZmhobThzY0FLVldEdWFSYUs4YVE5Zjd2dVBESDZCajQ3WlhhdTdycVlKNjZtVER3RURVNmxMYkNqQ0swcVRYeWw1bW5Eb2VOUnhhbmozRkpiYWtzVGswZmFYeEh4THJzc2dQa1dCOUxuQS9NRmxlWGNKb3p6andzVXZVRzBYL1FDdmU1MXFrTURYcDltdGN5T3kzcndCZmR2VkpLN0Q2L0FDU3pnM1JvcnVJcTVVRGVFU2ZFbVZjbER4bm5pVTgydnhNTHRjZUQwaEdaV3pCTlBNTS9qU1BuZTJPVmF0aVRLVXBZNXZZN2djMExkVUFXZVdNNXRIK08ySTY2QU9Xdzl4VDJCdXlSVkxHZG9ESFVzVlJYT28vYytaZFJYdkZmbnhXeUlWNHVwRkxDbDllQUw3aDhadjBRSDhSeThwQTJjSHpRcEdlc2N0VkEzN1p0a2xCVGdIanl2ZFNlS1kvUlp3L2tKTWswWTI1Y1NOUldTaWdRdGxVTFBUdytrenVKUGVZRWtYalFScG9HWm9iWXNMRjc5cHlkMWRNUkhJbmJnRlRacU5MaERxaUlzVE5wb2V4MldMY3kwL1g2ckhjZE1NUXZGU2Q1ZFdBKys0UDd4djg5ZGVBQ25tcjM2dUdsTDY5YlJDTDZCU1pzUzZjMFRVMlRLSzVndFdDemdBT093UWN1cnFrOWo4d2h2emlaU01MY3E1aGJ1d0JFc1lqb3BVQmtxdzF5WUJHcExBOTdTUkVsRW14NU1DSW5CWTV2Z0xrOTRpS3FTV21oSUdta0o0Qmk5bTRMNjQ1SjY4THlZNHdzRllCZlVnNWZlUC82Z1dXbTU4SUVtS1FNODlocTdLc1pOYUt0UDVUeHhyVVpaVmtObU1KdGpiS3JHeExORWJIUEp4aHF5N2xBbWJDMzJacWVGNmxUYWtuUldjWWFGcGZMVUJoL3J3YVF5Y0NDSm1XMTVLc3R2NmpSSHlKRnJ5MkMxYWhra0lXMExPNzVzNjErb3d4SzF5M1hxd2VYOW01WUxNMkRQRmVPam4vaWlxQ0tKK3lLWEY4dDVZbC9rTnNxYVNDcnl4UHE1eFdURklhUDhLU1cwUll4cXVwYVVmMFJjVE5TU2RKWkdjS1lkWUE2a2R0cnRteUJja2ZLWHdxazBwSHBVSGx3V2FmZmpOUkJZRlBVRFdhOGUzTHQvbzBSMENkaXNLRE04OWNYMHB2UkhFZk04Y2E0dDBzMlh4NGtnbzkxTVBRSi8wYzlNUVlxMGNvOE1CaDdiejFmaW8wVVVITFI0YUFJT3ZPbW9ZTzZrd2xFVk9EU1NUbGlXdE90SDZzUGtydGN0RjladEo5R0llckJza3ZoZFZTNWNGTnY5czFCVTBBYmRVZ2RLNEZHK2RSbmpGbURUem5pUk1kWk8xUWh6TUszNTV2aWdiZGtwejlQNnFqVUdFNUoycUFjWG13SjIwY1pVaUFEMHorcEdNeDZ4a3pKa21FZjQwSHI0cVpmVmcyWHpGOVlPeW9WNUJqelZrVUpuZ0tmOGxnTll3S0VDRUhyQ05Ecldaek1sZmxTM3lCaHIvSW55b1VnQmMvbEtUNHB4VnJyQzZnMVl3Y2NlSzNCbU54WmNBdHozajVFSXBxZ3VoOUg2d2MwMTFZTjc1Y0tETHBGRHh1d2tyUFFtVXdXNEtUYmo5bVpUd0J3THE0YVFNVVpiSG0xcnlsSjQ2ZHpSMGR1YTJuM1JZQ1dac2lIUk9leXd5SkdSN21YS2xwcnl5Q2lvdVk1NnNGa0JXRW5rRUIvcmFlaC9TdzQxNjJLZXVBeE1RcEVrenk1YWxNWTV3YW1Nc1dLS3J0VzJXcEVXTm5SZVpXT05LV2pyZHNLWmFycEZqcUNzbHE3NzNQTG1FaE00NDhQYzMrRktyMSs5NHZ2L3JmdzR0RWN1K2xLVEJlNGtaU2RpakJyeWt3djl2YkNNUGNMUVR5Z0JqelZja1NMUFJWR3NscWR1bndKNG9lZ3RGT1liNFN3eE5nV0xDbUQ3VDlrVmpUdjVZRGdwbzBYQm1OMzRaL3JFSHAwc2d5ejdsbmdzcm00bHZNbTJNcjF6Tk9KWUo1Y3V4dVF4d01HSnEvVFA1ZW1sYjhmc1FCWnZpSzR0OGhGTCt6Ymh0bHB3YVJTeFFSV2ZlRVRqdWF1UHNkR3hzQlZkTzdubVA0eHZ6U29UMjlwUmw3a0dxeitrMjZCM095MFlOVitTWGJiUWFzMWN0Qy9HYXJza1JkRnBLY3pWQUYxWlhuTGNwYU11elZlNmxaMmcvMW5kY3ZPVmdSRzNzZFVBWTFiS0Q2YWNoaWpNUGRNeFY0bXVLVm9yU3BpREhpdHVIN3JTVHM3bi80eTVEaFJYbzRGVkJONHZPL3piQWN4aEVOekdiSEN6VS85OE1jeDVlN2EzMWtXanc5RkNlL3pOZVl5UWpac1diMXVjN1UzM3BONE1qaTZoQ0xoaXZxZmE5U3M2eExnMDMxQWdmZXNBL2w5OW05Zmd2bmFGOUpvRTZiWUtta0dOSzNhUGJIQjk2dzMrRG54Rm00aHMwZHJMc2s3VThrZi9OL0N2d1FOdGxsbmEwcmpxNjFzSDhMODBIQXV2d0gxdHZCeTJDaHFXU0NhWVRhR04xOXNUdmxmekZENm4raUtUYnZ0YXlmcmZlOXVlV2g2R0pGb3hMZHI3VjcyYTVacHZIY0NQRHptYTB3VE80RWdiTHllZHhzdE84MW41N0xZQk9Cenlmc09oVUtzVzFKMUJCNXZyL3R6OFJ5cU9GeWxRUDlUdnN0MkpBTHNDNWxzSDhQeVE0MERWNEFOellhNGRlZE5pS05SMXMreDJ3d2JSN3E0LzRjVHhxRWs0TFdEZWJmaXN1bzM2SlhMaVdGak90THJsTldoM0sxclJTNHh2SGNETmxGbk5tV0JCQWw1U1dhTDNvUE9mbnZicjVwZGpWbkVhZUJKU1lqdUxFa3lMTHNXaEtjY2FkbU9waFprT1BnVmRhbGoyUXBTbWZPc0FEaE1XRTJaQnU0K0VFSkk0d0tUQXVDb0M0eHdRYldYQmx0cHhiamtYSnRLeHhhYm85ZTd0eWhsZ2I2Z05sU2JVcE1oK2wvRmFxelZ3ZXdHdThCVzFaeDdwVHBRREpVamI4dHNVVFc2K0dEWGJNbjNtTGJYbFhKaUdkZ2d4RkFvVXJ0UFMzd0U0TmswMlVaRzJPT3psazdmUnM3aTk1UUNMbzNFMGp0cmpuTTdTUjN1UzFwNHF0UzJuSjVPd3RRVkhnT3ZBckxCRmlqWlVWOVF0U2w4ZEFZNWQwRTBoTTB3M0hTMkRwSWVCNm0vQTErSGZoSmNHVXE0c094SCt4M2Y1K1ZPK0RzOXJZTkk3elBYT1lXUHJ0ZjhiWU14NmZ1T0FYNWp6TlIwUGRzdU9OK1gxZjdFRVJ4TUpKb1U2R2tURVdCdlZvbFZsYjVsaDN0S0NnNld4MUliYU1EZEorOXNVQ2M1S0M0NmhLR0NrM0lWT1M0VENxZEJOZlVzN0tkNGlYZjJSam5UL0xMeXNKeTNYRGNITGgvdmRlM3g4RG9Hdndnc2E2N3ZCazkxRzVQZS9IYk9lN3h3eW0wTlhidGl1dURrR08ySUpEaDlvUXZKNGNZNHZkb3FMRHVvSDlabDJGL29mc2Vrbjhsa3VoSWxoUWNmZlV0U2p5dEZ5cCsrcDZOaUU3UnF4L2xvZGdLVm9jZUVwL0NQNEZmanJxdVphVHRqMkF2SDVLL3l3cG43TTM0Sy9Tc29ZREFkSU40NDhJMS8wL3d2ZVcyODlUMS9sWDV4QnpjOE41SWFIcjBYTU9RZEhzSWtEdUpGaWZqMjBwQm01anp3VXY5ZTJGaHdSc3ZoQWJhbENJdUl3M2JoSmloWTNwNm5URkZJWmdpU1lqZlRmM2FYdU9qbWVHbjRiUG9HdndsK0NGelRSY3pCSXVIQkVlSW1IYzM3L2xHZndaUjBjWHpWRE92YUtmTkh2d2Urc3VaNzcxSy95L1hjQmxzb045OTZKcEJob0UydG9ZeE96bk5FT1M1VEpjNklkNUdFWExqcldvK0xFV0dOcFBEVTRXQXdzSVJST3UrMXZNKzBvVzM3ei9NQk45a3FIblNBcndQZmdGSjdDcS9BaTNJZTdnN25jbUkwOXY4c2p6dzltek9BRVhvSUh4VVJ1ZWFBY2U1VjgwZi9ET3V1WndITTh2c01iNXdCek9GV003d3ltVFhQQUV2bTR2Y0ZwWjJ1dDBWWlJqa2lQMk1sbUxkNkRJcGJHU2lIT2pkblVITjkwaFJZbWhUbm12aHpwMWlLRE5qK2I3dDVoaTc5bFdHd1ErSE45UnNmRk15MEZYYkV3aGZ1Y3pLZ0NieXhZd0JtY0ZoaHZvLzdhNDR2K2kzWFdjd0RQODZQenBHUVlkV2g3Y3NQNWRCdloxak56ZHhDOHBCR3V4cVNXNXZ3NDBuQnBqNUpoTXd2T3pOMFJXcUVSSE1yNEx2MWtXWDg0eExSODMwRzNqNnlxWjFhOFVzdFRsVytxSlBPWitzWjd4WlBLVEpMaGlOT0FGZDZ0aytqclRIMzFuY0xPeGlkOCtuelJiMTI4SGhVY3J1L3kwV242aVQyNTRZUEM2RnRWU0lNb1cyc2s3MjdBaHZUdHJXS1pUdmdzbWNrZlhZWldlTlJYeC8zWVEyT1V4TERyYkh0TjExSXdyZ1hUNmM4ZEFURHdMbmlZd3h6TzRSenVRcVRLU0M1Z0FvZk1aMVFCSzN6UTRKV29iRmJjdkptODdGSys2SlhyS2FoTG41NG0zcCtNY1h6ell0UDhWRi9RcEp1aDFPd2llRWxFb0kxcFJ4UFMwOUZCcmtxMnRXQ1U1OStIZGhOdFRJcUttOEVCcncyUlRPRURwRzNJS28yWTdtRmRMbTNaZVZqWXdWdzExby9vem5jZU12ZTRDZ01mTnltL3V0QS9kL0lMTVI3Z3BYelJ5OWVEc2dMY2diczhPMlZhMUwwenpJZHdHR2VtVEJ1d1JPSGVvTVNoa1VjN1ArSVNZM0tINVpaZVdxTzhtRlR4UVllWFROdXp2dks1RkdQZFFmdXUwMER3WUZZOWR5aGN0RXQrT0pEZG51Y2ZwbXloelVKemZzSmpyMjlsOFMwYlhCZndSUzlaVDI2dG1NSWRadWNjaDVaYm9NejNOaW8zbklPc1lIQ0dvRFQ0a1VBOU1pWEVwOVhzdWkxUzh0aC9rYldJck1CeERHTG9kV1VRSVdjdm5YeSs5TTIzeFBpU01PaVJQcU0rWU1Ya1VOM2dYRnJaSndYR3pVYU1wSmZ5UlM5WlQwbFBlOFRwU2N1UmxiTUhlVW1sYUtEb051eTYyaVdOVFdORllqb3hGenVKczhvUitSaFJ4N080U1ZOU1hwYTBaSlEwSzFMQUhEUStEOUllcGtNWHBjc3E1RVZDdkNsQlVJekRoRG95S3dEdzFMYzU5R2JUZU9SaXZ1Z3cxSWN1YUVPYUdXZE5tK1BzNWZRNy90bTBEak1lZ3EzeU0zdmI1ajEycVVJZDVVWkQyb3hEU0VXT1pNU3FGbC9XKzVveW5XRGEvYUkwNHRKUlEyZVRYdXNnODZTUVZ1L253U1l3cFc2d0xqbHFJendMdXhHSXZvQXZ1bDBQUytaTnowL2FrcC9wbmlPLzhKRG5HeWFDa3piaGw2WWNxbUsvNjlwcnhQcXRweDIrS205YWw5c2pMK3J3TWdIdzRqRS9DOC9IUTNtMXZCdUwxZmxkYnpkOG1PdWVWSjkyc3lxZEVZNEtKalNDZGUzbWNSdzJUQTZzenhlZG4rendoWk1wczBYcnFFc2lVam5DMWh3MFRFTEMyRWs3dUFBZHpjaGVYdjFCWUxhZ3NweHB6U0FvWlpVc0l6SXEzNU1uRlE5RE9ybE5CMzBqcTNMNHBraGNjS1VBQTgvb2N2TjFSeng5UXlPdEVSczRDVnNKUksvREY3MWtQWXJ4WXNHc202Uk1oNGNwczVnMURPbU01NEx5MWlpMEhkM1kvQk1rOFZXRmdCVm1ocXJrSkNQQkhBb2x3WmFXekxSOVZiN2JjV2RYOU55VVlFK3VCMkJLZnVhZUJVY2pEbGpiWVZZNERkdHNWV3Z6UlpkV255VXpEcGpObDFEdTNhbG9BalZKVE5EcGNJT1ZWaHJIRkY2NmxMZkpMMXpKcjlQUTJuRkpTQmFLb0RlK3NBdkx1ZlpWSFZ6WWg3VzBoL2M2QUFaKzdUdmo2cTlqNjhHL2NUQ1MvM24xdkxLSFp3TmkrUCtwUzBXa1pOTUJNVWwrTERMdWlFNG9tWnk3MXIzVUZNd05KVitWSi9HQzVpeFZVa0JTdHNUNGdHS2gwR200T3kzcXZxN0xibXEyNG5QZER1RFI5ZGVSMTFYelA0dkZ1M1RZemZuSXlpU1ZtZ2l6VVlHcWtJWE5kS1RZOXBnYjlEMkl4NXQwK05Ia1Z6Q2RVMDNzdVdra1ZaQW9DT05DbjBUMzVnQWVXMzhkZTQzbWY5N3NNT3BTdmo0YWExS1lVbTU4VVNJN1d4eGVzMDNiQVpkUnprNlV0YnpNYUNRNkl4TzBkeTdYK1hzam9EMTZocHNCZUd6OWRmekhqK1IvSHA4bkN4WlJxa0VEVGFDS0NTeXdqaWFvTUoxVElURTllZzdKcW5xOEhMNmdEd2laYjB1MFYwUnIvcm12cWp4S3VhTENYN1pXWFR2QVkrdXZtM3o4Q1A3bnpWcG5ncXJKcFpLd1duQ1VqSXZpWVZsaXJsR096UExJM1NNVnlwL2VsdkJVampEa05ocnR1ZkZGRXJROHBtZFNsYksxNnRvQkhsdC9IVjh1SE1YL3ZFR0FMa1YzUkpSRWlTbG9weHdkTVhPWlBMWitpeCtrQUhwTUtJazhVdEUxeWd0cXV0dHd4TmhwaHJJWjFJQnpqR0YzSUlHeEdjQmo2cThiSEpCRzhUOXZkc29XclRGRXVlYkVadVZ4aGhDbEg2UDVabzg5T0c5ZndITmp0TlFUcEQwVEc5UEpMRVlxdkVZNlJseHkrWlpHZkwwQWo2Mi9iblFDWHAvL2VlTTRLemZRVkpiZ01RYlVqbE1GSW02VHBjZldsWmplN05CU1Y2SXNFVm11bVdJYmppbG9VelFYOU96WWRvOEwxd2p3MlBycnBpbU9OZm1mTnl6S2tscmduRWtTelQ1UVdZUVc0MFlTaHl6cXNSbU1YYnZWeEt0R3VZeU1LYVUxdWdlbkxEbTVJbHk0aVQxNGZQMTFNeCt4SnYrelozTXZuZmRGcXhVM2ExVy9GVEI0bTNRZnN5YzFYVWNkVmhEZVVEWlhTRkhITFFqL1k1anRDN1pxTTBDWEd3QjRiUDExaTNMaE92elBHeWdZdGlVQml3UVYvNHdGTzBtYWppakdzYWZIeVJMdTB5RzZxMzVjTDFyT3BWeHIyczVjTTJqSllNQ2RjMTBBajZxL2JsUnBXSi8vK2RtbTVwc01sMEtBMitBRlJ4OWpNZTJXYkM0alF4bmlrZDREVThUd1VqUlZhY2dkbGhtcjNicGRkenVKOXpYcXIyeG54SmZ6UDI5UmV4ZHRqRFZacXprcWE2UHl2Y29qR3Jma1hpSjhTRXRtbC9uWXNraWN2MGl2bHhicWplbXdVak13NWV2ZGc4ZlVYOW5PaUMvbGY5NFEyaTdNVVJrOW5XMU1TajVqOGVBeVY2eTVDTjJTNnFibnczdmRBMUl3cStYT1NDbDY2M3VkTjNJekxucnQrdXMyNWNJMStaODNTWFFVbGRxUXEwYjVYT1QxN2JHcExkNnNzTjFWTVBmOGMrakc4TDNOZUNuTWRGK1JhM2ZSYTlkZnQzOS9MdVovM3Z3SG9IcnFHbVFGYWZtaVF3NmV5ek14UzA1SzRiTDl1QStTS1VRekNuU0RrcU9Hb2tYeUp2YmdKL0JISStxdlk2OS8vNHJsMjBOc21LMm91MmRUc3lJQUx2LzkxLzhuM1AyQWFvNzFXRkdpOEtLdjFmUkM1K0o2N1EvNTA3L0UvU09zaHFONVRzbVlJalZ0K2tjakF4OThpei80U2FvamJJVjFyZXhFNy9DMjlIY1lEL0RYNGEwckJPRjVWVHU3b21zYjExTC9BV2NWbGNWWkhTc3FHdVhMTHA5aGE4SS8vdzNNditUNEV3N25UQnNtZ2Fwb0NyTkZPYkljTjRwZi9PYi9tcnZIVEdxcWdBdXBMOHFXaldQUzltLzMxakFlNERqQSs0K3VDb1FvVC96T3psck5kM3FkNFNkcGhGeHNVdll3R1diVFd0SVNjM3dOT1dIK2tIQk1mYzZrcG1wd1BnSFd3cWFTVUcyWldXaGVZT0dRR2FIQitlUS9rbjZiM3BPZ0xWK09EU245NHdEdnI4QnZiNzAvTEx1aVBQRXI4T0dWV2ZEbXI0NVBaeWNjRW1zVlhaR2UxcFJOWDlTVTUrQVZRa05USVZQQ0hGL2pHbXlEQzlqNFI5TGZXY1F2ZmlFVG1nTU1VQ01OMXVOQ2Fra3dlWnNvd2RZb2JpTVNsbktBOTN1N056VFhsU2ZlK1NWYmZuUFFYbWc5THBZQVF4cHdFdE9OeUV5YXVlV000RlBqanlqRzN1T2FGbUJUV0ROZ0JYR0VpUXBzYVdobkFxSWlqQjA3RGxzeTNmVUdlUDk4OXhiV2t5ZitGRjJTTkV0VDFFMGY0RFlZVmx4RmxiYVNNUElSTWsvM2lNVTVwTUUyU0lXSnZqY2tjaWVia1F1SVJSeWhVdmtIZy9pVWxqRzVrelZvZzVoVjd2SWxDdUJybWxodmdQZk5IUU04bENmK0ZFR3NZYk1JQkMwcUM5YTB1dXkyd0xYVmJMQmFQNWtqSG9rQ1J4YXBrUXl6STRRRWN3Z1lIUlpCcCtYRUZUcVhGdU5Wek10alhMSmdYNGdBaWQyNEhqd2M0TjNkdFZTZStOTml3VHJ6SDRXVlVPbERvYlVxcjFGdUFnWWxsYzhwbXpvVnJFTFJIU0lXOFZpUHhOeTR4d2pCcHlSNTVJNkoyMjBxUVRaWVI0Z3V2VUlDSmlTcHI5Z0ZGbGU0UmNGL09NQjdCUmlYOHNTZmhwTlNPM2x2RVpDUWZMVVZUS1Q3OEVrMUxSTGhXTit5THlUbnA4cVdVWjQ2YjZ2eGRSR1hmSFZxeDNlSTc1WWFMYTRpTk5pSzROT1c3d1BXNmxoYlNPRjkvTTlxdzhlL2FvQjNkMTU2cVR6eHA4cFh4NUJLQXNZU1RPSUlpUGtwNjhHbVRxN3NadHZ5ekJRYVJMTnhJWitwYW96SFdvTEZlRXhJaFJCcldpdEhDQUhyQ0Y3L3RoaEQ4SmhZejg0d2c5M1FSVjg4d0x1TFk4ekY4c1EzNnFGMUo0NTViT2xnbkVMZnNoS1Z4WU9YS1Z1S3gwamFqMjJzY3pUUXFQcXRWL1hEZ3Bzd21HVFdXTVNEdzNzc3lVdW5MTHJWUEdqWVJzSDVnZ0hlSFNXaVY4a1QzM3ljRlNmTWdrb09LOGFwQ3llMEo2Vlc2R09ZdmZmZ1U5UldzdWtFaTJrVVYybmw0ZE9ZVXpSaWs5cDdiY0E0Z2dkSjUzTHhLY0VlMTdCMVI4ZXFBZDdkT2VwVjhzVFhmNWxoZWpvTDg1aFVkaERka25QdEtIRmhsak9UK2JkcTBoeGJtMzVwMm5jOCtKYTFJdyt0SnlrZ3AwRVd1QUFaWXdNVndhYzVLellNc2xodmdIZEhScnhLbnZoVFljZktzeFR4dFRFVGtqSE83cnIzempvVjI1bEFRSHJxcFY3YlRpeTJhWE1tVWhUQm5LUzkxamh0UjNHRW9GMG9MbldoV05uWWd0Y2M0TjBGeGxjZ1Q3eXozVGdOSUtrc2N4OWp0VjFaS3BXVytVYjF0YzFlT3Y1dWNkZ3B4K0ZKeTlwZ2JMRTd4RHlYYi9mK2hMSFZHZWl0SE9pNkE3eWJvM3NGOHNTN3c3Y2dkazBuSmFPbjNoTGozdXlEMFpwNXBhekZJVVhVcHVUVFUxOGQxRVBrRG9YOFNrbVdUblZJb3pFZGJUY1pqb3F4aE5IZjFKclNTL0FjdkhqWi9TTUhoTC83aTV6K1BPc1RVaC84QnZOZllNVEE4bit5VS9NbFRaeFNKRFJTdHF2RXVMUUtXd0RjdE1UUW9nVUR5UVJvVFFHNUtjNm9RUkUxeVYxakNBN3JpN2pkWnlLMHNZVFJqQ1IwSG5uZCt5N25IeE5nVFVMcXcrOHdqMG1RS3hwWXZoam05dVNVeGcrVFR5N3MyR3RMVUdjeXdoWFNLWk4yNzVHc3FsY2xYOTBKNmJSSTFhb3V4bWdMN1EwTmVuNXppTTgwU3FNSW84Y1NPbys4WHBsVC81REhOV3NTVXIvNmxMTi9RUTNyRHl6THJ1RVc1ZW5wZjdLcVpvU2hFZHV1U0ZPVjdETFg3WWUrR21YYjYvaG5OTnFLc1ZYdU1ERnBiOVk5ZUgzQzZOR0V6dU91STNncE1IL0k2ZSt6RGlIMWZYaTE1dDN2QTFjenNMd3MwVEdFdG1QRUpkaWlGUHdsd0tiZ0xIQUZrNFA2WnlQZHltWVlIR0UwZHV0c0NoUUJsMkpjQkZsckVrWS9ONWJRZVhRMThnanVudU1mTWZzQmx4SlN4M25pTzQ4NWZ3TzRmR0Q1VC8rM2ZQUXFrbmVXVmR3bncvM2JNUGtXOVdicWcraUM3NjVaayt4Y1Q5OGliS1pjMkVkZ0hjTG9GOGNTT28vT2M4ZlMrT3lFVUxGNGc0c0pxWFZjbWZNZnNjN0E4djEveWZHWG1MOUk2Rm41cFJ3WmhzUHYwVHhGTmxBZlpDdkcrT29oaTgyVUM1Zi8ySXNKbzBjVE9tOVlyRG9LaEZQRVVyL0xCWVRVTmh0OXplbEhYRHF3ZlBDSXc0b3dwM21PY0lRY0x0dFdYRmUzVlovajVIM2NJYzBHNm9QYkNSKzZZMnhGMkVDNWNHVW02d0tDNXRHRXpoc1dxdzVoTmlkVWlLWDVnRldFMUdYaDQvUXBsdzRzVnpPbXg5UXhVNzhnM0VGNnduWmxFTjRGekoxUVBTTEVaejFLZlhDN3ZkOHNzR2RJYk5VWXBWeDRVYXB5RlVIekpvVE9vMU1jU2tlTm4xTTVNRFFmczRxUXVoaFg1dlFaRnc4c3V3V1RjeVlUZ2lvSVNrMllkbWtoZWhHNFBrRTd3NTFpbnlBR0dhVSt1Q1hBRGFiR3pKUjFmbjNsd2t0eTBhc0lvOGNST205VnkxZzB5RHh4dFB2SERBbXB1K1BLbk04SXgxd3dzR3c5MVlKcWh0ZWFXZ2pZQm1tUWllYm1TcHdLS3pFMTloeDdqa3pTV09tNjZvUGJ6WjhZajZreFZTcFlqVkF1dkx6WU1DUm8zb1RRZWNPT2pqZ2kzTlE0bDlLNS9oT0doTlRkY1dWT1RybGdZTmtFWElOYnBDa0JSeXFocCtMZFJCM2cwT1U2ck1mVzJIUENGRk1WOW5TcCt1QjJ3b2VwZGJMQnVKUXlhdy9aRnlzWHJsWHdIeEkwYjBMb3ZFa2lPcFhHQTFJamFnZitLVU5DNnJLTmE5YlFuTEZxWU5rRW5NYzF1SnJnMnU2NEVMUEJIcGtnV2Jtd0twSm9EaE13TmJiR3pBcDdZZzMxd1MyVDVyR3R6aXQ1OVByS2hlc1dHNTUwQ1pwSEV6cHYyTkdSYXhsTmpiTXFwbUVJenlnSnFRZmp5cHljczJwZzJjUzJSWTlyOEhVcWtxZEVnS1RXdFdUS29Sdk9CUERZQmx0amEyU08wUkdqeTlVSHR4d1JqQTExdWpiS0YrdGk1Y0lSOWVDbnhVZzZvd2lkdHlvVTV0SzROTGppNVEzSEN0aXlGMklxTEdZc0hWaU9YVFhPWXh1Y0RxRzBIeXR0cVlBS3FZbzNLVFkxZWt5RFhSQW0yQVdoOUptc1ZoL2NjZzlXSjJFOFlqRzIwMXNQcTVVTHh4WDhuM1hMWHVNSW5iZnQybWs4MHJSR2pDR2N0SjgvR0ZkbUVROVVnNEZsRTFsbDFZN2p0aXJhcW01RmUwNFZWOGx2U1ZCTDhoaVByZkZWZDgrN1FIM1FidTJpcFRWaThjdlNHaXZjOWNqOHl2SDExWU1IZE5TRVJ0dU9zbE05N2ZlWUZPUEt6R2NzSTR6VzBZR0FiVEFPYXhDbnhkZmlZVW1WV3NseGlJYmxDZUFZcjlWWVIxZ003R21vUHJpbHVuU3h4ZVQzRE4vMmVCUTlIMTErbmsxYWRuNlZLNzErNStKZmN0NC9lbDEwLzdLQlpmTnJ5VXVuV1NDUHhQRUNrMXJkT3YxV1ZTclFtcEMrVGw0NllEM2lrUVljcHVuU1FnelZCMlZIRmh4SFZHS0RnTUVZNUdMbFFuUDdGTUR6dzdJYWNBV25PNnNCcjEydStYYW5XMkFPMHdROHBrbm5GaHNMN0tZSXFoa0VQbUVYRmt3YU41S1FwaGJrVW1HNzJ3Z3c3V1NtOVJpTDlRVDkyNWhramlWSUlocGhGUzlIS0k2LzhRQWpscFhxZzlXMkMwYXB5YVZEd0tRd3J3TFkzajZBRFIxM1p5VU5CeVFYSFF1NlJZMDlIdTZ6TXFYUmFOWkdTL0tFSnMwY0pFZTlWSDFRZHZCU0p2OWgwOWVpUm15MFYydUpjcUhjU2hjZHZiU05nNWZ4a2Vua1ZwclhNOXJEVm5YMjQveTlNVnRuY3ZiS1k3MDZhbk5sM0FTbGw5YTQzVWlhY1ZxdVhHaHZxNHMyRlA2Mk5HS2ZRTElRWXU5cTFXbWRNZm1VckRHdDhlRFMwY1hvekgvZmptVUg2SnJ1dm01MGhCRFNhRVUvMlJ1MkxFTi9kbDAwNlRTYy9nN3RmSkVSeEdNc2dEVUVyMTA0cGZXSDlsUWFOK000S1dRandaYlZjMnJaVk5Ic3lIYWwyM3dadElzMkpKcXRJYy9XTFhYUkZDcEprZkU5anZXbGZGYnNOUTlwUDVaQlMwektoNFIwYU1GajFJalRjVG52aTBaejJydDdOZHZRYjJtZ2JqdTFwbHNIOE1tYm5FazdLYkswYit3QzJpeTNhWDNzelc4eGVadkR3RVQ2aFdaWXdxVFhTU0crd01FVEt1bTBEcS9xK3g2Mmd0MnVhMnBwQW8zMDlUUms5VFBhemZWM3FMOUg4ejd1aEdxR3F4TlZnL0ZLeDBIQmw5T1ZVT1JuOFE4Sng5Z0Z0dEdRVURyM3R6Y1hYOXhHZ04wRXB6TjltZFozR0FUdFBoTCtDanhGRG1rZUVVNng1NmtxWlJ1c0x6QUxYVnFrQ043ek1FY3F3am15d0RRNk9oeVVlMFhhbzFRcHluY3JnNndLcDlYZldEc2FacGxFbHZRL2Izc2R3ZWVnaG9yd0JEbEh6Z2sxSm1NYy93aUVSSUNWeTJWSkZkTWpGdUxRU3AzUzBXMytzbmd0Mm5qd05nTHNzRkdWUWRKMHR1MEtINGt5MUxXNHlyYmt1YUE2SXk5b3ovcUVNTVhNTURXeUlIaHNBeUZaYzJwZVY5aGM3a2lLdmZVTHhDbDlpZGRmUksxZjhrazlxdmJkT29CdE9nN1prT1o1TXNHclNIc29rZ0xYVXA5eTg4c21uaXdXeXVGU0lSVm1qcGxnYTN5RDhVaWo1UVMxWmlNNFUzUXc1UWxTbTJiWGpGZTZqenpCRnRwZysvWUJiTEFXRzdPUHluTmpsQ3c2NWZ1a0dOZGtKUmY3eU0xZk94VnpieE9KVm9jRm9ZSWFHd0gyMm1JUWtydnUxRTJuR3VlYnhJZ1c5VTlUU2l1a1BHVStMdCsrYzNESlBLaHloRUViWENRTFVwYWUyZXhpS3k2dE1QZTltRFJCRkNFTVRXcnR3eE44cXZ1R250Nk1vaWhLV1M1TlN5QmhiSDhTdFhvQXo4UExPclJnTHRPVC8rNHZjdSs3dkRMbnFOdnp0T3E3Zm1kOHNNbVk5WHpuMXpqOERxOCtYVmR1Mk52MElJeVNnRWRRbzN4VkhwczNRNWkzZkxGc1Y0YWlxekFpQmhiZ01ERWQxdWg4cVpaK2x3aGprZ29ra09JdjR4TkpteW5jZGZVVXpnQjRvRk1CdGl1NzFYdW1wei9QK2NmVVArU2x3RkV4d1dXNjJyN2IrTFNQeHF4bi9ndk1aNXo5QzE2dDE1VWJObHEramJHSnRjbzdwOHdiWWxMNGFsU3lmV2RldXUwajdKQTNKRk51VkF3dHN0N0Y3RmhXQmJQRk5LSVVPUm5kV3RMcmFGTG1NdTdLRlZERE96cWtlYWlOMzNZQVcvcjc2d1I0WEROL3lOMXo3aGVqUGF1MDZFZGRrUy82WFRoZmN6MWZJLzRLNzM2Zk80OHZseHQyUFhKWUZhZVVrRlM4VTE1WEUzNDI4eGR0bjJrYzhHUWxmMXZrSWFOUlJuT012TFRXclpiRWxFSGVMV2kxbzBkbEtQQWgxTVZnYmJWcXVQSjUrQ3I4TFU1L0gvK0kyUWxISVUyQ2xYTTlHOHY3UnI3b2MvaG96ZlVVZ3NQbmIzRCtJKzdXRjhrTk85MkdZMFNOdnV4aUUrMkJ0OHByVkpUa3pFNjRzZk9zdHh1d2Z4VVVveWs4VmpjVGxzcWUycUlUU0ZvU2o2RXBkNEtzVDZCWk9XbXRnRTNoQmZpcjhJelpEd2dWNFpUWnZEOFZ2UEhFUm84dit2TDFEQVNIVHovaTlPbEt1ZUhEaks1Um54L0pCMVZiMWlvWGRCcmExNmRtdDdkZ2lrMTB5QS9Gd0pTVlk2WGpBM295NFNxTTJmcnFEUFBTUk1leDlxczNYUXRvV3hNajcvRXI4R1dZc1hnamFWejRPWXVtUDIrOWtieHZueS82a3ZXc0VCdytmY2I1YkluYzhBUGRocE9TczAxdEVxSWtvaVpqYkFxS01ydUxiSllkZEh1SEZSSXlKY2JkRWRibDJzVkxheVN5Z3VudXRCZzk2WTIvSmpLUkNkeUhWK0FFRnRUdklwYktJWE9hbWtuWVNpQjZLVi8wSmV0WklUZ2Nqams1WmRhc2tCdFdPODZVRjBhcDZvekdYSmsyV05pUlVsQ1BGaXI2Nmx6ZG0vU0xTdUs3RVVkUHo4ZjF6MjlTa3E2RjFmWGc4KzVVVlI2YnN6bmNQNFRuNEtVa2tkSjhVRkNZMXpSMWk4Um1ML3FRTDNybGVpNFRIRzdPT0RsbktrbzRvSTAxa2QzQ2FNMDhJYTE4a0MzR05vVmFPOWlEaCtoV3hTeVRYRkFCWG9hdTdRNnE5T3hZZy9PVkVNdzZqZGJ0U3JKOWNCY2V3R21hWm1nK2J2a1VuVVVhR3IrWmZuTUg0NUl2ZXZsNjFoTWNYc3hZTEZUdTFoVG0yelZpQ3A3dTBvNWwrMlBTVWg5YkRqNkZnWXlwdWZCRGhxSzIrb1hraXVIRkhSM3pmais5UHRBOG9SMHhucVg4cW4rc3gzYkZPRFNiYkYwWDhFVXZXUThqQkljam81YlJtTE9sakROdGNxTnRPZTc1NmgzbDBWaEthOWhEZDJsMWVxbXNuaDBNTk1UL0Nxbng2QkludW1oTFQ4bHVsanpRNTNSaUplQS8wZHhlNU5LMG8yZkExK0dMWHI2ZU5RV0hOVU9Kc3NRYVRSbEdwTEhLTDlmRCtJclF6VE9NWlM5Zk5RRDRBblJOVnh2VGRqQytmSmRjRERXUWN5QjAwQjB0OUJEd1R4WGdhQWZ6RFovREJYelJuZldNRlJ3dU5xb2NPbVg2T0tOa1k2M2g1bi9mRmNCMjhNY1ZIcW5YWlZJMjdLMGk0ckRMTkU5bERLVi9yVCt1ZFZiRDhkRkZ1MkdHWjhtT3Qwa0FYY29YM1prSVdWdHcrTU5mNU5qUjJGYml2Uk9IbWhWMS9wajJlZ3YvZk1HSU9XVElXclYzQXY4TjlpbVY5SVdtbDM2SDZjVWpxRVdOdjlhTmMrdmViMnNINDZQUmFIU3VNQnh2dFcrdHd4Y3RxMHorUXNIaHV4OFE3ckNZNEN0OGxxc3g3YzZTeTBkbDVUODlySWVFdVpLb1ZjdElrMWhOcGZhdkVSNnl5SDFWdm0zTWJzVUh5NGFiNGhXci9PWlBjc1JCcGhuYVY2NS9aY2RZUE5Od3NqTi9kamxmOU5xQ3c5VTVFeENQY2RoS3hVZ0xTbWZST3BMcDRXU1VyOG9qZHdibmNidkNmK2EvWXpSYUVjNlFPdlhjR08yNTZUWGM1TGFiOVBPdkIrQVdZN1BpZ1dZanpoaWZib3Z1dW56UmF3c08yNFpxUVFBcWd1QnRtcG1QQjd5c1hKZnlERGFWL2FQR2lsbGd6MU1kUWc0dTVNWWFFdEJOTkhGamtSbFNwZDY1bHA0aGQyQVZQVGZiVjdGR3B5SU9mbU5jL1hWc1BmZzd2emFTLzNua3ZMTDU5M0FOTHZNdVJNR3BRSWhpRjdrVUVXOVFEcEFVYlRXWUJjYnA0V3BhY0hIWTFhYWNxUXlqR1pTOUhJM3lDQlQ5a1VaSmhWT0QrelVEdkVIOWRkUjExZnpQY1REUTVUbGdCMEt3cWRYU2F2azlCQzBwS3AwV21jdW93U3cwN1ZYbVhDNWd1elNhNHAwVXZSdzJsYkRpWVV4MEV4SkpSeld6aTZHbThjbkVrZlhYc2RjRy9NL2pBSmEwK2JtQ2dkbVE5Q1lsTmxTWVpPS2l4bVJzZ2lGeGtybVc0bDNLZEZLdjFETTh0azZXeFBZSlpoVVV6Y2Q4S2R0Z3J3L2drZlhYRFQ3K2F2bWZWYWszMnFodGtnNk5WZFVTNXdna3J1MVl6SWtTZHVUVzFGRHdWV1YzSlFWSlZ1aWVUYzB5NGlEcEZ3YzcvQnZTYWx2S2RRTThzdjY2MmNldnovKzhzUVZualZBVDBXMndMbGx3MUppTWhKUnhnRGpDakxRc096U0ZTZ1pxeDdsQVcxSlcwZTAzeUFEM2FzQytHRDNOYlFoYmUrbU41R1hIMUY4M0tET000bi9lNUpJdUg0TnBkUUFSckZQQlZwdFVOY2pqNGNWTWNGU1JURTJOcFIxTEVZYllNbWZXcFhnUDlLZWphUHNMVWh1dkxDc1ZYem5BRzlkZng5U1IxdWQvM2haZENMSGIxR01kUHFSSmdxRG1tNzZtSGJ2T1hEdGlPMlFQVWNLby9UV2tRMGkySkZYcEJvbzd2aWoxaTFMcDNBREFvK3F2RzNWMHJNLy92Rm5uVEU0aHhkNUthL0NvcjVZRWRzTFZKeUt0RGdWb0hndFcxMXBXU2pvbFBOTW5ybHJWajlGdjJRbjYwdHdNd0tQcXIrTi93dnI4ejV0WmNEc0RydjA2dGtxeXpFU004NVljdjZYQldBMmJpcmxOQ1hySTZWYkQybHgyTDB2UU8wUVZUVlZMSDRTRTY3ZmdzZlZYdjhuN3N6Ny84NVo3Y010YkU2ZjA4OHdTYVI0a0NrQ20xMHM2cEtiSmhmcWlVTkdMcSswZ0xXQzZlVUFaRlBuTGp3cXRLZDhFd0d2V1g1OXQ3aVBXNFgvZUFOMXN2Z1JWU1k5OTBZWmcwNkJEMW9oTE10eUZUSTRwS1RKc1M5eFJFcTlFT2FQV2lPMmdwbXM3Mzk3eDZuUUprYmgrRnoycS9ycVJST1g2L004YkpycWxWVzRsNkpFcHRLZVVGdU1ZVWJ0Q1E3Q0l0dHBHYzZNWTkzeDFyMXZnQW5SWHZZNWN2d1dQcWI5dVdRbStsUDk1UXhkTk1lV2hPcTF4MERiNTVDN0djVXYyWlV1TjZuOGlLenN2T3hpYkMvL1lmczlOYThyMlJsejAydlhYRFQ1N0ZQL3pKaTY2L0VKU21zSkthOFF4bm9xVzNWTFEralpWVXRKd0o4UE5YMU5RQ3dmTmdkaGhIRDlvbjdQZFJkcmRHUEYyOHJKcjFGKzNMQmRleXYrOHlZZkxvTVlldDF2WDR1cE5BalZ2d09VV25sTlhKWGxrems1SWw2a3Flb2lMMEMwN3FubysvQ1lCWHEvK3V0bG5zejcvTXp2eTB0bUk0em00YWcyM1BSTjN0L0NXcnlvVVZKR20rNStLOFJKMFY4SGM4OC9YSFVYL0hmaUFxN3QrQkgreDZ2OHQ0MzhlbldtZEp3RkE2WklOcmlMR0t2Lzk1ZjhsVDkvRm55QTFOTVZFdlF5YVh1dStnejM2Zi9ERDczRTRwd3FwTGN2bS9vMFZsZTc4bi8vK0wvTlB2b2VmcDFwVEp5ZTZlNEEvRDA4MkZFUmE1L29wZUg5enB2aDEzY05tMTkvNHYvTERlNXhNV1RpOEkwVGEwcUtsSzI3QVMvdjMvcisveC8yR085SzJjN2tWTW9uRHBxNy8vamM1UEtDeGVOUHBGVnphUnIwMXdGOEM0UHU3NmhYdVgxOEg0TGR1VHI3OWd1dUZEM241QkhmSStaUkZoWTh3MjlUWWhiYkxpL2J2QmRxS0U0ZlVnZzFwQktuVjNGRWFDV09XeUErbTNXcE9SWnIvais5VEtKdFc4eUJURjIvWkVPREk5L1FhdkhrVmRHRnAvUGpuNFErdTVoWGFwc1A1c09IK09YWEExTGlLdXFKeGlNTmJoVGtiZEpUQ3k0bGxFdDZObnFSVDRkaGcxVjNuYmRybTZkWU1lY0ExeVRPTDRQV1RFOUw1VnpQRmxMQkN2bEc1OEFoZWhuTjR1SHNBWWlueUorQVovTmtWdkVMYmZPQlV1T081c3lCSUV0aXFIVTFrOVhlSVNYNWJzaW1ya1VVaG5HRHhvdXJOOFNnVXNDWlZ0S3lHYnlHekhYZGpPaHNBdk9Bc3dTUnlJQmRkUmRFWldQNkdaaE5LL3lqd2V3OWVoQm8rM2pFQUR1N0F5Mm44bURjK1RTN2F3VUhnME9NelIwTEFCaHFMRDRoSkVoL0JFR3lCZEdsU0pvWFlYdHIrM0hTNGlqelZwZ2kwcGFXWHRkcnVHVGtuWEJ6KzExcVQxUTJpbnhhVHpRQ080NlAzbGZMcHlTNGZvdTJQSC9QdXB3WmdDeE5oR2xqNEl2VXVXRXNUa3FNV202aTR4Q1NNYzlOMVJEUW9DVmN1R0l0Si9NUldlZmFpcyszc3lub3dpL2RFU2dKamtpbG5XbkJUR3ZSV21hdzhvUjE1MjU3dDdDSG1DZjhIT243Y3dJOCtOUUJYTUJFbUFhOFBNUmVtck5DRWhMR0VoRFFLY0daV1MzMTlCWDlQRkJFd0dUYlJCaExiRGNhVjNkckZjRHFrNWtDVGQySkYxV3AwSHJhcUJ4OFUwd3dCVG5icENhZHdCQS9nVEgvQ0RyY0NzOTNMVjhFMFlsbW1jeVFSUW5qQmE4SkVTbUdVZklqSy83ZmthREpwbUQyUXB0Rk5WSlUxYmJ0SUFqaldRaXplcE9LcHRSamJ6UjlLYWc2eFptTUxMakhPdGNMVDNUeDlvLzBFY1RUMVhOM0U0NXUyNEFpd0V5cERKWGloS2pReGpMcHJFd2NtUktjbGFETlpDVnFyL1Y4bVlXeUZBRGJ1c2lZNWh2Z0ZvVTJ2aW80OVJnSkxuNU9zUmVSRk42dGFiZWV0aWl5MFY3S0ZIVDNIeVpMeDQ5MXU5NXNuNEsxUVFTUEtNOWhOVDB3TVZ2QVdiekRTVmRyS3c0elJqWk15SklIa2ZxMVZBVkNEbC9iVWhOS2xHcTB6R3IwNStZQWNlWFZQQ3R0Vmswb3FqVndNUHQrQkJlZng0eVB0R1ZrVXNxWTNDSERQaUNNNW5ndXBVd0NkYmtwZDhrYlByQ1dIaGttdElLTEVldEYyNDk5ZVMxalpsSVBHWW5sY1BYZU0yS0Q5dkxTMGJXM2t0WU5xVWxscEtMbjVacnN4bEl6eHZEdTVlSHh6R0xjdGtaTEVZNFBnU09nMklVVlZjVU9OelVEQkVwUmFNb1hObVVjMHRGWnJUWnF1aUx5S3hyU20zRHZJVzlGaWwrQWtoWHU1UGhFUHg5bVVOd3F5cER2WldkS2xoSUpRWTd2bjJPc25tQmVPV25ZWjBtMWl3YmJ3MVU2MGJ5NW9tNDdpSFJWNmZPZ3pqTWYvREFacmxQNDBaN3N5eHBMSzBsSjBncWFBSzFjMktRS3U3dGFiVFhrTEZ6MHNDZnR1d1grK015TmVObjY4azVCdXEyM1lRaFVoMFNOVEphMWlvUTBwNG5VRzJ5MFhpbEYxSnFPRHFkSW1sb1BTNEJwMTExREVXVDBqSmpWdjk1dVg5QkJWN2VCM2JVV2N1MGFjU1ZNMjNZWmRkOFI4VWJRVXhKOXdkdTNvTXVoZHQ5MjlNRSttaDZKWEo4ZGkyUnhiVGk2VGJyRHF1cVY0YVVLUjJpd1Q2YVpieU93RVhOM0RVc1dyOEhuNEVod055SHVYSGg3L3BkYVVqdFI3dm5EaC9kOGM5eEQvczVmNTAxZVExK0N1RGlDdkdoazFBTi80VGY3NFJmeFB3RDN0b0xhclIwek50c25Qem1TNjRLSVJrODYxZE1XQ1U4QXJhc0c5VDlIMFpCcHNER25qdEFPTTIrL0x1SWIyaUlVR1hOZ2w1Wm1LRC9UdzhUbGFBdWloYUZQNXlydzE4djR4MTg5OHpJZFArRERBWDFiTTNHQU12UGdSUC9jSm4zekNXMDEzbnJoSGtySVR5dll1d09Va2NIdUtsUlNXNUM2cnpJZFk0cHBuRjdKOGFBSmJRZXBnYkpZQmpDWTl1c0dYREtReHE3UlpmaDllZzVkMVVITVZBVFJhRC80QkhLOTMvMWlBZ1laLytqcVBuOERuNFVFeG1XcnBhMytaT0s2TXZNM2Jqd2Z6eE5XQTJkaHM4KzUxWEhTUEppYUFoR1NwV2V2RXM1eEhMWGNFR0ZYWWlDT055U0gzZlBXcTkzSklzQmlTV3ZXeWMzQ0FOK0VjWG9UN3JDU0FObG9QUG9hMzFydC81UFVBL2dwOFEvakREM2h5cmp6bFI4VmthbmZPdkIxWFB1YnQxN3Z6eEFmZFNWYkQxcHpBbmZneUYzeWNhZE9UT1RYaHBFVW9MQzFIWnlOR1czZHRtamVYZ3IycjU2Sk5tUndkTk5XYVFWQmRkZDZyaDRNaHZpRUI5RUZSRC83Ukd2ZVB2Q2J3QUw0TXgvRDZNNTQxaEhPNEQzZTdnNlBhZmRjWlZ3Njg5ejdOR1R3bzVvbTdBOHNQaGNjVDZxS2NsOU5KbDlhTS85a1grZTU5SGgxeVBxR3VDQ1p4dUlUY3NtTmFKNUY3ZDBxNkozSDQ4VE8xLytNNTcwODVxMmljZHUyVStXMzZMZGxsejlBZ2l2NFlHbGpvRU45MDhFenZET3JCRjk4L3Z0SndDQy9CRjJBRzc1eHhFbWptTUljanhiam9heHFPSzMvNGhQT1p6aE1QQnBZUEc0NENNMGRUVm0xTGpMdFVXV1Z6MUJjZjh0RXgwenM4TzJBMllWSFJ4S1lPaXkvYU9Wb0FhTXUwaTd1YnU0M25qam1kNGliTUhVMXNJREhhUU5LclpORC9GWllkazU0b0NYZXRqcTdFN0lWbDllQUw3dCtvSG53WFh0THg0NGN6em9SRkhCenRZVnd0SDFkK05PTWt1cFo1TVRNK2dVbXE5MFgrQmg5empSbG1hUSttN1lNcVVML3ZlZW1jZWNBdE9KMHlxMUpuVmxOMjdkaTJFMCtLbHAxdEFKNEtSdzFlTUk3YUpqc08zUjhrUFNJM2ZVRlhuSU9mZFFlODZzSUlWdFdETDdoLy9PazZ2ajh2d0RrMDhORWNJOHp6N09oQnkrV3dhbHpaZVo0KzBYbmlSZnN0OXBBSnFRSERHTHpWUTJwaGVabm52MU9XaHdPNDMvQWdjdkFFWEVWVnBhNGRiOXNHdk5LOHdqYUVOSGtmRlE0Q2k1aTdkcW5RbFBvTFFySFhaRHZPM0JJWFpiSk9Cck9hRWJNTDZzRkw3OThJNEZoS2loakhNc1BqQlVaWUNNRnI2bnZhQXJ4cVhQbjRsQ2ErY0hmU2EyY1AyN2czWjN6aVlUUnJjYlFOR0xRbUdGM0YzY0Jkenp6WDdBSUx4MElCOXJid245a3gyRzFGVzNJbmljK1pMSXNWdktSOFp3ZmowbDFma3FvOExXWTFNM0lYMTRPWDNyOVJLVElPK2Q5WHpBSThxUlBHUG4vNE5DMm42bzRyTjhYSjgyVE9JdnVWQTh6TEtVSFJGZ0JDZXRsRFpscVIxZ0xLalMzOXhvRTdCdDhVdkE2Qnh1RURqVTN0RnNFaWpnQSs2MTV0bVprWEtxaUVFTnJoNDFpTEREWk5xNHBLVFdSM0xaZm5vczgxTE91TmExNWNEOTU2dkxNc0pkMXJxWXA1MWdEVVFxTVltMlhzeG5VaEQyamcxRE03U2V1Snh4Z3JtcGZJU1NYVklKSVM1cUpKU3ZKUEVRNDlEUVRWSWJZV0o5UVdhL0UyK2Mvb1BLMWRybUM3V1NmSlJOS0JPNVlqdmNwN0djM2RtbUkvWGgxa0RURXVpU25XcVFmMzdoK2ZUTWhHbkRmNmRzUzhTUWZRV2xxcXdYWEdsYy9QRVovU0M1bXR6SVYwbkFzaGxRZE0vTHZVdFl1dHJFWi9ZK0VBRnRxMWsyOHpRaE93THIxQUllQU56aEY4dDlxelRkWmYycVJLTzZNV0U5b2hCWXdpYmJPbXJGdE5tZzNtY1MrdEIyOHh2MnVLZC9hZ1lDdk9QK0drU2MrMGxyN1JYenl1Zkw3UWJrVXBqTGpFV0ZMcU9Ja0FHdTJCMHRObE85RWF1MlcxcWNPVXZWUmdLenlwS0lRWjVLSTNxME1MenFUTlJZcWlaT3FtdHFsb0lSbG1rQkhWcEhtUllWNi9IaXhiTzZVQzQ3S09GSm5vTXJWeXI3d1l6K1NsVzZHVWFnaFliWTFJNmtreEEyVzFmU0pva1VkU2gyTFExR0FpbVJHbTBNVCt1dTU3SDVsN1FnT1d4RVJwTzltb0xSUGdUdHF1V0NmRmxHbElqUWFSbHk5b2Rtek1PV1krSUJPNXRCNHNXLzArVldHVWgzMnFZazc5RWlkV0tyald1aUxwaVZOR0ZXRlJKVmt0eWVYV21iZ0JCelZsOGFuUHVYeU5KbEJKT2xLTFRnQWJpL0VZSFZIeFdpRGFWUjA2R25IUU5wSmNXY0syakp0aUNmRzJzRUhMenVJNjZzR3JNSzQ3blBJSW5QbnU3OTk5MzVhT0syY3ZtdnVickUzOFp6WmpyRUxDbVhNMmhNN1VjcFhEMm9DMytFQ1ZwN3h0SXV4cHRKMGpVcjNzQm1CUzQ3VFZ4bHZKMVNxYi9FMHVMZHZMajBsTHIyOXlwZGQvZU1YM2Y2bHJ4R2xLd0tReEVHdncwcUhia2J3ckYzdUhLd1ZFTmJJVjJ3WjEza05FRjZ6RCt4MjRhTE5NZkRUQ2JEUG5FaWtaRnlUTnR0eFdCWERhQnVNOEt0STJybWFNZFVZN2NYY1VQc3RxVEd2QkdTckZXSXBOTWZiZGVhOTkwYnZBT0MxWVgwcWJjNnNtRFMxbVB4U0pvVzRmd0VYdmpNbWhsaWpEUnE2cWFsZTZhSkV1RkdvcHBZRG9CRUxRekxCdWgvbVpOeDdqa2ludjBFdG5VcDUwbE85aGJOSzU3bFphTUFXdVdSNVlvOS9rWXdjWUkwdDRnV000N1VtbmwzWW1wZUJQcVN5TnAzSzdzMkRTQVMvMzlLUnVFTjJiUzR4dm93VjNkRlJNeC9WRmNwMllwOHcyblRPOWhDWHRIRzFrRjFMNEtsckpyMndLZnlxNzdSN01LcEZLeldsWTlVa2hZeHlIV1c2bkJXUGF1ZHZFQWwzQ0djTnBTWFBaNlI5QmJCdElsNmNITDNnSUJpKzQyQ1lYcUN4MWdmR1dlN0FwMGgzbHV5WGR0MU1LeTRZVVQ5eFNGMDFHMTZZRWRXc291VzltZ0RIZDN2ZXlBOTdIK1lhNDdabUVicU1ZNzJvUHp0Q0d2SzBvbkw0NEF2Z0M0OXNhWktrV1J6NHZlV2xqRTFGSGpiUkphV3Y2WktLdGw4NzVoNEN6aUZDWmhHNXJ4N3RlZnNsMGFSVDFiTUhaam04ZHdMLzZ1N3dDUnlzYVFibFFvRzV5QVFONXpwYXRNTlkvK3lmOHorR0xjSC9RbjBpWDJXMm9FZlhQNEd2d1FIdUlMOUFZR25hTzN6cUFYNjk0Nm5rZ3FaTm5VaHg0M0RJZFF0TUZlT1ByZ3kveTNZZDg1SGxKV3dqTEZrVTNrRndxMjh4UG51UGhNV2VTK3RETFY5T3RsbHE3cFFDZjN1WEpETjl3RkRpVVRnZWZIYWlZYmRmaTNiM3U4K2lZNlRuemhnZWhJMUxUZThsY2Q3czF3SlN6S2JhaENSeEtLenRUTFhzdEdBaXUzYTZyUHVRczVwazlUV0FhbjVmMEJabUdmN1lseHp6ay9BN1BBczRRUFBQQUhlRlEyaGJGSHN6bGdadUtac0pjVW1iREM0MHNFVTQwM2NFamN6c3RPRXlwYStZeGV2TDRRQkM4b1JZcVdkSzZiN3NLMjV0ZkUrb0RaZ3RPUTJKZzhUNDFIR2NCRTZmVFdIbjRKdEhjdTlTN3VZZ1U1S1NDa2wvbWNucSs1L1lCWE9FcjZsQ1VDd09UT00xdGFPSThtU3h4MU5zQ1hCRW1MS2JNQWc1TWt3YkxtcEJhRk9Qck5TbE8ySG5MaUVxVzN0SEV3ZDhBZWlRTG1uKzJneGpDM2s2QXhSRXF2S2NKYlRFemxwTGl3NHJOWks2b0pkaWRiTU1HWDlGVUxLcjBBa1crMnFERVBCTk5tNVFBdDJJazJuZnROV0hldHVib3NITG8ybkc0dlFBN0drY1ZDZ1ZDZ2FEaXhIcW85VVVuMUE2T3NoYXBhTlIvTFBSWUZWOHNpVDFjQ3RKRTBrLzNXdGFOU3VVWllLUG5zVklXMHhYV25NVXhxNStFbjRLdncvTXFRbVZYbkFYajlaKzl6TTk4ek0vQWd5N0YvcXFqMk5oNjdiOEhqRm5QUDNpQm4vdGtwZHp3RUpYL3doSWNRVVhPYWlrZWxpQ1JHVWs3dGl3RjBySXR3TUVoamtaMzA5aGlrRm9SQW1MVHBFWFd1SFM2eSthbS9LQi9mTTUwYUxFaEduU013a3B4ek9vdjRIMEF2Z292d0oxaUd6REx0Sm4vOUJVK2ZBSU5md1VlNkZIU0xodTgzdmlWLysvSHJPZVBYK1NUVDJCOXVXR2JyTUhITGxkUkJsaFMvQ0pRbWNSeEpGcVppY2EwMVhpeEFac1lpSDF1b2xaeExyUi9TZ3hWSUpqa3BRUDRQRTlzRTU5TEtMcjdrbHRTQm9nUzV0eXN6ekg4RnZ3OC9BUzhyTk9nMHhVUzlmSWFId2IrNmV0OFEvZ3l2S1JqZjVPdXNPekd4OGV2QS9CUDRJUDExdU4vZ3JjYTVPMGxjc1BMSjVZandJNFFrSkJPSGEwV2RNWllHeFBiaDJXMm5SOXYzV3hFV3FncC9HMys2VlpiUkxTQUFaM0JoZGhBYVVMMzNWVVN3OXlqRXN2YmFROXU0QS9nR1h3WlhvRUhPdVUxR1NqMmNoZitNbytmOEljZmNBeGZJS1ZteXVuUmJZUVZub2V2d2dmdzNUWFhjdysreE51UDRmaHl1ZUVVTnR0RWR1UlZhRHR0ZGRvUDBlU3hMZTJMRU5rNml0WXhscnhCTkJZck5OS1NRbWVhTGNtOWM4VXNhQjVXeU82Njc1eXlRSUFXU0RwQlZvQS9neG1jd0V2d29EdjBtNThVRTdnSG4rZkpPYTgvWXdhbjhFS1JmanNvcEY4M2VDZ2xYL1NmcjdPZWFSb1FmdnQxQ0d2SURjY0g1QkN2dzFzV0l6UkdDLzY2dDBWVGNMWlFadG02UGxBYXNiT0o5aXdXdFVvN2Jpa3RUU0lQeG5SMjRqeFAxWkthcXErMlJjWE05T3JCQW0vQUFzN2hESjViTm1HYitLSWZ3Q3M4YTNqbmpCck9GZU1qSFNDZGJLcisydU9MZm5PZDllaUE4SHZ2d3dxNTRWYlAyT3F3a0I0OFl0YzRZRU9pSDJ2VFhxb2RhYmZXRU96c280cXhkYnFENUw2dGJ0TlBFQ3FiaG5BNzA4RFpINFFPSlVYcVNjbVVsa3M3T3Q2RkJ1WnczbjJtRWJhVVg3a0R6eEhPT1FrOG5LV016QXp1NlpaOHNPRnc0UksrNlBjdVhvOXRCNFNiTXo1OEFwZktEWGYzc3pqTklJYkdwRDVUS1RSeEdrRU1MakxsK0szd2xXWEJzQ1V4SURVK2piT2l5c0VTcUF5MU1HVUpwWGd3YlRXek5PVkV6aUlYWnJKK1ZJenRsMVBVQnhUU28wZHduMmJPbWZEUlBEM1RSVEdsZmJDSnZPOUt2dWhMMWhNSGhCOXdQdVBSTEdIY2RPV0cyeGMwVSs1YlF0QUpUMG5SVGV3WEwxcGdrMityWkFkZVdtejNqeEFxZk5RUWR6VGxiRjh1SjVlY0VJV3ZUa2V2QUhwd3o3dzc4UXVqbEQvTHI0OTFiRDgvMXZoTTJ5clVRUnJXWE5RWTRmR2lsZmN0TVdZakw3MlVML3FTOWVpQThFbU44OG5iTmRvdXIrUEJiYkFqT2pJYTRpQmhmRmc2cnhlS2RFR2NMNnAzRVdSMVFxMlFraHMyRHJua1JubU45dEcyRUFxbWdQdzZob0w3T3phN0IrM1NDclI5dFJmdGtvK0xzZjJGL21rVG5kTjJMbXp1TWNLVHVqL21YMis0VmEza2kxNitubkpZK1M3TWVmcGtpZHh3blYrNHdrWEg4VEtuWDB0c1l6WXAyOURPT29TVzFuZjduVGgyYWtZaVdtY0pPdVRpZFNhcUVTclRZcHdqSkpOVkdRcityTEk3V3NxZXJIVzZLcC9vTTJwS3VWN1QxUVk5Z2pxbFpwNDEvV2ZLcGw1NkZWLzBrdlhRRlJ5ZVE4M3hhVHU1RThwNWROUDNkVUYzNGloeUkzR1NwZUNzeXdTaDIyWkpkV3RvOXdpbmhxaWZiN1ZSdmdrdHhwMTN2eWpyUzBFanZyUmZaNjJ1eXFkZFNXYVdZbHdUUEF0Sloyb1ozai9TZ2kvbWkrNnZwemVzZkFjV05BMG44eFZ5dzkwR1ZGR3VaalRYRVF5KzZHZkxHTE1MTDUyM2Y1RTBPbXhWakRvT3VSaUg5MVJLVSt2dG9DdEg3VGdtdkJMdnRGWFdMVzE1SDlHVGRWdzhvdzRJbFJMZUhFQ045eW0xZTlLMEkrQ2JuaGd2NFl1K2FEMkhhUUo4MFhEcU96U0dBVjQrNHlDcUJ4cnNKQVg2WlRJb1gzNlFudnpoaHp6TWZGVzJkWlZMT0pmbzB6YmNlNU92d1hNRmFaODFtT25sVFZYcERac1FOdW9ZV3Zla2V0S2I1KzZKT09zZ1grTlRtN0g0OWZVVGx4K1dMdVdMN3F4bk9GaDRCeHBtSngwcDJnRHpBL0JVQVJ1UzZwaFIrcFVzWTdNTWJvQUh4NXhOc1NWZlZaY1lTd3FDS3Jxb243ek0rOGVjQ2tlUzRubTNySU51YVd2Vk5uTVJJMUlScHhUcXg4UFpVWjBCci9VRWR1bzNCM2hOdm1nWmZzOWdRUGo4dklPeGQya25kaXIzYXd2SjZCTHZvVXVPZkZXTllCMExSMU9RSm9VeVNLYjlJbE9CeDc0cTErQURDMkc2ck9kbUZkSmNEOEJrZnVhbEErQmRqT096UDl1VWhHVUVYL1R3aFpzVWR1d1JyOHdOdVhLdXJDaXhMQmdwUUkwbURiSnI5ZElxVXVWKzkybmdrSlo3eGR1Q2syeVpLYmZXckgxVkJpVGc5VmR6c2dSalczQ1ZYQ3ZBd0RkK2MxejlkV3c5K0IrOE1KTC9lWTE1WlEvSHF2VHdWZHNabjVXUXNnUlJuTWFXYWVjdTNqRnZNQkVtZ2crRkpGWnNuU2wwempCOU9xUFlhQkQ3cW1vVnlJbUZ2emk0MXVzZXNWMGp1bGFBUjlkZlIxNVh6djlzRXJ1UkR5azFuYitRYUxVNjdUODg1R1RsczZZZ2NZK1VpTWEyNU0vcHdHcmJDZnprdlIzZTBqanR1YUZ0bnd1YWdIVFNiNXk3Ym9CSDExOUhYaHZ3UDQ4N2pKTHNMSjRYblVrSFg1c0xiUzYxZHBpQVhSb1pTQ3JGSitFanBlVTNwdVZmaXRuZ1lObzZQSnJBaWdLa3Rtd2p5UWRacGZxMzBtbXR1bGFBeDlaZngxNVh6ditjeWV1aUJGVXM5enE4S3ErWEI5YTRQVnZwaDNHVjRFM3k4SEVOSnJONTVIMVgycDhWeXFTS3dWdXNKREt6WE9aenBsV2R6QlVGSzllK0I0K3V2NDY4eHZJL2I1eHRTQWtCSFFhUHZ0cVd6bGxWdkVPeFBidWlFNitqMnB2amNLc2J2STd0eG5SRXJnZkg3TGRYcWpxMElva0t6Z2ExNEd6UTIzU1NiQ1F2TzZyK09yN1NNSXIvZWZPa2txU2RNbmo5bUJ4MkRSc2lZMjlVajYrcUs5WnJzc0NLYXB0UjZIS1VSZHdVWWVVV0Eya1B6VktRTzhrdTJuVTNBbmhzL1hXa0J4M0YvN3dKdENUVFRJS2Z0dGh1ZTF0eTl4dk5ZTFkvem81S1NiSXVLYlhwYkVkU3llUnlZZEFJd0tZMm5leW9jMytrMVhVYXVmWWdhM1Q5ZGFNVXgvcjh6MXMxMElUa25JTzBrdW9NdCtUQjhqSzBscGF5cXFqc0oycXRYQVl3QlU5MzJ6aW5pbWdtZDZtVFJEblFmcjg4cTM2TkFJK3R2MjRFOFByOHp4dGFzQnF4MCt4SEg5SGhscndzeHhOVWZLT0hRYVpCSVROZjB1Y2NqOEdYaVZtWEF1UEVBS1NkTi80R0xIaHMvWFdqOTJkTi91ZXROdUJNblZSK1hXRGMyNUpMam81TWc1SVpJcTIyNnRtQ3NpcDJ6WmxpTDIxM1lyVGxMMmhjRmpwQ2R1eWltM003L2VCMTZxL2JsUXN2NVgvZXNEUmJ0SmVhYkxJb3NXeTN5Y2F2d0xodHhkV3piTW1IaUJUaVZqSm82bENMalhac2k3cDlQRVBuc3E2WDZ3ZDRiUDExaTByRDVmelBtLzBBNmJycklzbGxlblpzMGxDSmxVNGFiYWtSNTllblpLcktlM0JaaWhiVHhseVoyemwxK2cwd3ZnbUExNjYvYmh3RHJjbi83RGR6MGVXWnVKdmZTRVN1ZzZOelpzb3gzWjA0Rkl4ejBtVWpNd1ZPT1ZUcTFDUTBBaGRiQkdWZGpHL0Nnc2ZVWDdlc0psM0svN3l0V0hSdjY4M3ByYVcvOGlET0NxV0xMaHBsakRZMVpweks3NVFpYVpvT1RwTEtsNjBhdUhTLzk3b0JYcnYrdW1VOStGTCs1K050TEZnanFWTENkYm1qN3BZNXpQQ1BMT0hOQ3dYR09jTHF1T2hpOENtQ1d2YmN1TzczWG1NVVBhYit1ZzNBNi9BLzc4QndlMGJjUzIrdGdIbjRKNXB5UzJXYk9jazBGNTFWcTNMY2poTHZaNjdwMUFCYmFMMkg2N2JnNzhCZmpLaS9qcjMrVC9BQlYzaWxMbU5YVEkyU3B2eFdCdHQ2L1ovL0Qwei9GWGFHYlNCZ3lsemxzRUdwKzUvL3hyZDQvYWU0ZDhEVVVqbHNsZklZUzN0MDZIWnB2ZlF0dnYwTjdBSFdxdGpQMnBXMDhRRC9GTHkvL2RhMzh2bzhQTmxLSGY1eTM3RHhkZmUvb2o0a1ZJZ0ZxM2tvTFJlU1I3NlcvYngvL245azhqb25aeHpXVEFOVndFbmlEc2c4N3NPU2QvejcvL1B2TXAzalFpcHRHVldGWDJjYWV6ekFYd2ZndHpZVXZicjBpb3pzMzJjM1VnZTd2YXJIK0NORTZjdkVZbXpiUFo5aE1hWURkaks0VjJpZWNmNkVjRWJkVURWVUFSZGEyS3pPL0p0Q3VEYk5RQi9pVGVMMEVHMUpTTzFqYlhTK25MeHRQTURQdzFmaDUrRVByZ1NFS0UvOEdyeTVBNzN1aTg3QW14d2RhdHlNRUJDUE5PQ1NLVWVSWjJQNk15YjVNUnZnQ0htQTl5d3NNaWZVK0FZWGNCNlhhNUdpYlVDNVRTeWVyeHloMGo2UWdMVnBkeWhmQXJSVFRMcVFqd2U0SE9EOXM5MkQ0QXA1NG9kWEFQQldMQXdCMDJpZ0c1S2tjK3BpTjRsdk9ESUZHQVpnVCtFTzRTaTFzN2ZqU1I3dmNRRVRVa1JtOU8rTVh5bzlPWWhmZTR4dDlTVFEycGNaUkxheUNWOTBiNEQzalIwRFlBZnl4SitleXdnMklMN05UTVhuYTdTL1JwUTYzSmhXRU04VTQxWnlRR2p3c1ZTMFFCckVLTHU4eHdac2JpNHdMY0NUK09HaWRQSU9DZTFQaVNjOVF0K2dvK3ZZcUI3Y0crQjlkOGNBRCtXSlB6MEFtMmd4WGdVOUluZU9xRHBBQVhPc09sdFZ1TXpwZGFrSlhyZFBDelhpTlZVcENlT29zNWN4bnBRVDM5RytYVkxoczFvc1FWdkpLUFp5TnE4SER3ZDRkN3BORHVXSlB4Vlg3TVN6cVVEVTZnZmFkS2lObFVGVHpMZUZISERsek80a3BhN2FpS2hCUEdLd09xeHNCQW1Za09JcGlweVhjUVNQbFJUZitUaWkwVTNFSkdhWnNERVIycW9CM2gyaHUwcWUrTk53VW9vWVU4eTVtSUxiSmU2T3VYKzJGVEt5N2JpZVREQWVtYVF5UTBDUHRobGpTV08reG1GRElZaUVTak01eEtkNklrNWx2THE1R3JRM2FDTUx2bUNBOXdvd0x1V0piOXhGNTloVlZQNk8wQ3JCaTNaalpTTk92UnkrSTZrbE5WUkpZUkJhRXpkTitpbWlVWFE4aVZGOGZzcCtXNEpYdzdXSVNXN2ZEaDdscHRXa0N3WjRkN1FUWHlCUGZKTVlLN1NpampGcHBHbmxJVkpCSkJZajdlVXd0aVAxSUJYR0kxWENzak5wYmpFTlZwU0FKMmhxMkxUeXdFbHkzaFVZYXp0MzFKOHcyK2FpTHgzZzNmb2hYaXhQZk9NWW02ekNHczlMVm85TW9XM01DSkU3UjV1L1dzT0lqcnFCb0hVTzBiSkU5dnhCcGJoc2QzK05iNC92dFBDWjRvWllDaXROZVl1Qy84VUR2RHZ5MHF2a2lXL2NncU5xUnl6cVNaYS9zMG1xTkdqdEtPb1RtMTR6WnBVYXVpUWdWZnF0UWlaanE3UTI3Sk5hU0s1RXhSY3JHQ1hPMUZKWWg2alI2Q0ZxSzdiWmRRWjR0OGcwclNsUGZQMVJkQnRxYWE5ZGlxdHpKa1E5ZHVTcnlpMmJyUVhieER3YlJVcEZNQkhqUmo4K050N0dES2d2cGg5b2tXN0xYNDdndTBTcEdubkZRMVMxbFlsZE9zQzdoWXRlUjU3NFp1S3M3RWkxbEJzZmR6N0lab3h6ekNWbW1WcWFTeVN6UWJCVkFXRGVrK040amg5RS80VnFackpqUHdpdjlCQzFYY3ZPV2dPODI3NUNWeUJQdkF0VFZsREpmWmthWkdVN05wcUJvZ0FqL3hFSGtlQXVKaWhXWUN4R042ZTgrOUp0U2VnRlhGMVRyaGhMR1AxZmFrM3BlYmdQejE5Mi84Z0I0ZC82V1Q3K0dkWW5wSDdoSC9ESnp6RmlZUG4vdmpXMFNnTnBUTnVQSVpvQUVadjh0bEd3NCtSTHh5K1pqbkthNU5kRm9DN1VhVzBhZHVvWXNlNitiWGcxRExnNlVmUll3bWhHRWpxUHZGNzVVNTU4U0FOckVsSy8rTWRwWHZtcUJwYVhPYS9NVFphYTFET2NTaUxhdzlqME5OTnN0M2MrNjNjN0VLVHBrdktIenU2YlBiUDBSa3VIQVZjYlJZOGlqUDQ2TUliUWVlVDFtaEErNVBWL2lueURkUWlwZjhMVHZNWGJ3dm9EeTdJcnVETlZaS1RmVjRDVFNSVVlkeWJVQ25HVTdLVVREeExnQ2tucVVtNWFBVzYvMXA2ZU1zT1lzcGhMenNIckUwWS9QNWJRZWR4MUYvNHlQSG5NQjMvSU9vVFU5K0JMOFBodGp1RktCcFpYbllOSnhUdXYrMlhxb2xLUjJVUWdIaFM1bm92dXhWeVNKaEJOUkYzU29LSzFYWmJiWGpWd1dOeU9qbHFXSmpyV0pJeStQNWJRZWR5bGROU2NQK0haNjF4S1NLM2p5cnorTmlIRzFoY09MTC8rUCtQREYyZ09rZWtLR2lOV0tnSis4Wi94OEl2NERkUUh6Y3BaeUY0djE5STI3dzkveVBHREZRdm1FcEt0cXYvVExpV01mbjRzb2ZNbTllQUg4QW8wenpoN2g0c0pxWXR4WmQ1L0Q3aGtZUG5lRHpsNWlkbHpOSGNJQjBqVmxRKzhVTHp3L25jNS9vanpsMmp1RTBhcEQ3TFJuSnhlMDRkTXoyaU9DRk50R0ZwVHVYQTVBaGNUUm84bWRONGt6MzBuVmpFQzRZVFpReTRncEM3R2xUbHJlUEtoR3NLS2dlWHBDWWVPME1BZC9HSDd5S1FVbFhQTE9hc09IM0ZuU3Boakh1RHZFdTRnQjhnNjZvTmJ0cjZlTWJGSUE0ZklCSmtnYXlvWHJpdzJYRURRUEpyUWVST0FsWTZhZVlPY01mK0lWWVRVM1hGbFp1Zk1IaW5HeXdhVzNZTHBPYlZCQXNiakY0UUpNc1ZVU2F5ams0dm9Qc0hKT1FmUFdEaENnRG5tRGw2WElSZXJEMjRIc0d0dzg2Uk1IT0x2VlNIcktCZGVWRTI2Z0tCNU5LSHphSXdMT21ycUJXSllaRExoQVNHMTZjMFRuK0NkUmhXRGdXWG5xUlpVVG5QSUh1TUpUZkxWcGtvWXk1Q3p5bEhWVEdaTVR3a0dBbzJIQmxrUXBsckpYNlUrdUYxd1p6MnV3UzFTUTEySXFXYVB1TzRiYVphRUZCZHVra3NKbWtjVE9tK1lKU3ZvcVBGenhGQS9ZVWhJdld4Y21TZFBXVFd3YkFLVnA2cnhUdFBGVVpmS0l3cHptNElvTWZhWVFMV2dtbEc1Rk1FMmdkQmdtK0o3SitydFMvWEJiYVZMc1I3YnBQUW5wTUZsbzJkb1dhVmNlSGs5K01reWd1Wk5DSjFIZStrdUhUV3lRQXpOTTVZU1VnL0dsVGs5WnVuQXNnMXFFTFZPaFVTQUswTEFCSUpITEticWFFYkhaTEwxVkEzVmdxb2lPS1hZaVMrSFJ5YUVLZ3NmSXFYNjRIWVdiTFJYeS9xV295bElWOWd1ZEwxT1dCTmdCZ1RObXhBNmI0dHhEVDRnaTNSaTd4RlNMeHRYcG1tWW56QWNXRFpnWThkNTAzTEZvZ3o1c2JvbkRna0tjeEdzV3NFMU9JK3JjUXRsZ0JCQ1NPS0QxbXRxWXBJVThjVHZCbUFUMHlaZSt6VXplWTkyZllqVHRHaXBYTGh1UjBlUG9IazBvZk5XQlgrbG84WjdwQVpEazhtRXc1TDdkVnlaWm9FL3BUZXdiSTZTTmJpQUw1eGV5Z1c0eFBSdUxDR2JoY080UkllVE1GWUhFSmtZeUVPOUhtSmZYTURFai9MYUg3ODF3SEhaRXRxU1EvNjlVbkdwekg3TEtJQVpFRFNQSm5UZXNKVFVhK3J3VGVwSTlkTEpFYXdZVitaa1JuOWcrUWlyRDh2RjhNcTBqRlEyOWpzNmtDUzNFMStqWkloZ1BOYW5IZEhGcUZ2UEpMSHFGd1FxYklBNGpoRHhjTnNPQ0NRTERvbWFML2RyNWx5SmFKVTZGeFBGak8zSk9oM2tWTWNST284dStDK2pvMDVHak1GM1AzL0Z1RExuNXgyTTA0eFhVTFB3YVM2aEJZa2krTXJNZFpKU2dQSGxjQjduQ1I1Yko5S3I1QUNVbjlqazVraXZkZDh0azk1U09HcnRxdTlscjJJaEs2NVp0RWw3WktycDdEcnF3WmZSVVNOMWVsNys3Tkp4WmJ5d09DOG5lTktUY2g1dnNURU1Oc29DQ3FIQkNxSVBSaklQa20wQmp2Rk9ER3R0bzk5ckNsK2Qzd21Ia1cwRlBkcFp0QzdNTWNWdEdGUWpKTFg1YmRRMit4OXlwZGMzMTN1ajh4bHNyZnVMZ1dYejFjUmhadkpZWDBpTlZCUmNWY21DWFpzNmFFZjNSUUYyV0kvVGNDYkttR1UzSU9vREpHRGREdWIwK2hZY2t0NlBsR3UyQmN4bWhiVGRqL2tsaGNjTEdKTWNxUmpNSlAxalcyRVRxTFNXSi8yOU1Bb09SbHVKKzZMUGZmQlpiaTVncWk1aDZjYXRRcG1PVDcvT0ZmNVVvclJwTHpDcWNNbHRCTGh3ZDFhcmUza3p0clN6WE8wTFViWFJRY2RMaC9SZFNaK3N3Um04MTlSRURydHF6QzRlczZHdzRKQ0tsU25qWVZwbzB4ZXEzM1ByQURiRkxMM1J1Q21PYlZtUE4rMjRrZmErQW9qRHVNNHVtS2UyUXdDZjZFTjkwNkh3anVqYWl0RHM1bzBzMXkrazNsZ2JUMlcyaTdGSmRud2JMWGhKVUJxLzlsaVRjdFNtRkMvME9xVWluYjBRZGRUV2FtdGpiSFJGdVdKSjZOcHFaOHZPM2ZaSjM3RGIrMkdrYVBZTEdIczdYVFRkaUZRSjY4U2tWSkZWbVk2TWNSNVV5Y2ZsTkNzY2NIRmFWOUZOYlI0TnR0THh3NHBRN3dKZDA2Nlowb2hWYnppaGF4SFZFeGQvYXkwNG94VUtXdCtBc2RpUTlPVXlaMmtyek4xOUlaSXdhZlNURmdJQm5NVjczQURqN1YvSzh1MU1hWTJzSnAySFdtMGY0MXRxd2FqRXZkSFdPSnM1MTBNYUFxTjRhb1NpUENYdE4yS1NpNDZkVXhIZGFNcXVhcjgyTzF4NWpxaERHdnFtb0U5TGZ4Y1kzenFBNy94M0hBNjdyOVpHNE82Q3V4dTEyLytUUCtlTFArSStIRXJxRERDRFZtQkRPNGxhcnVqTmU3eDhvbTJyTXVnME1YMHJMMStJV3dkd2ZSK3AxVE5UeU5tVko4NWxqV3piV3VHdjgvQzdIRC9pemprSE5aTllsaFpjVU9LVnpLRlV4c3h4Ti9rYXgrOHpQV1BTRkt3ODBySnI5VGl6eWozbzFnRXNkd2dXR294UGV6RGRaMVRTRU5FMWRMZE52dUtMK0k4NG54S2VzWmd4WFZBMVZBMU9jTDQ5ZEZscEZWNXlKTWh6eUNtTlErYTRCcXVzUEoyYkIreG84Vjl1M3g0OFZWSUVQUy9tYzNEdkFiWHlvWXI2VmdEZmg1ZG81aGhIT0NYTXFCWlVQaFdZYldaRUN3VkpsakxnTVVXT0NCNE1VdU1heEdOVVFEVkk1MFRRK1Mza0ZnSWN1MnFLa05TSFZvTTBTSHNnb1p4UDJkNUhIOEI5d29PazR4NWJQa0t0QUh1Y1pzZHlranh1SXBiVXJTSUxnclQ4RzdHNW9DVytLMDk5MG83RTNUNkFkVzRUaWxINWtEamRzK0g2NGtTMG16MjRncnR3bHpESEJKcUk4WUpRRXhvdFB2b0M0SkJxMGxFampRa3lCWjhvSDJMblJzUTRIdTFRc2dEVEpiTzhmUURubGxpdGt4dVZza29pS2JSRjlWd3pNRHZ4SEFkd0I3bUQ5eUNwbGhIRkV5VVdIeDNXdHdDYlNNTVRDVUNjRW1TR2xnNGdUWGtIcFpYV1E3a3B6bkszRW1DSGlYSW5xbmRrUWp1bkc1a3hUS0VlR3llN2pXejljeU1SMm1HaUZRMTVFTlJCVGJDcCtHaDg2dkF5QVNkZ21KcTJNQzZob0FEUTNHb3NQMFFIYm5NSGp5QlF2UXFmaHkvQlViZUhkNVdZL0cvOUxLLzhLYThKZDdVRmVOV0VadnpQYjQ1OERuOERHTE9lMy93R0wvNHhQK0hYbFJ0K00xUEUyaUxoUjh0K2xmZ3hzdWg3QWZPMkFPZitvd1doU1pSWVFiZDYyMmhicEtXS3VVK1h1dk56UDBPc2VSRGErbU9iZ0RISlVTYy9wS3gzMVFkS2ZmUTVPSUpwdDhHV2psZ1R3TWMvdzVNUENSL3lsMVhDMmEyWXV0NTRTdk90TWV2NTVPZjQ1Qk9hdDlhV0cyN3AyWlZPUlJ2bkVrMWhxV01WVW1xYTdTMll0dmxJcHNwdUYxcHQwc3l1WlMyTlYxNG1VaWRDU2Z6UXpnK0txdklZQ01sakl4MllLMkFPMzRmWDRHV2R1NXhjSUFiOE16VHcrai9seVdNK0R3L2dqczRHRDZlaE5nQTQ4a1gvQUk3WFhNL1hBTjRXSHIrOW50eXdxb0Nha0NxbUtQMHJtUXJKSkVFckcyVXBnMUpPYnIwMWxLUXk0anNrV2FsS1lmSi9FRExNcGpOU0hGRVVBZGUyZmx0YURnbXJOYVdROStBQWI4STV2S2p6M0wxbjFMcmlCL0JYa0cvd3dSOXkvb1JYNExsaW9IQTRMelAyaW56UngvRFdtdXRSd2VGamVQM3ROZVNHbGFFMUZkZTBPUzExeU9wbWJJcDJ1L2pGMW4yUlJadmlKTTB5QlQzSVpsMkhXSW1LalFPeEl5ZVUzMjViL3FXeVU5TW9qMW8wN3RTMEc3cUpEb0dIZzVtOHllQ3hNb0VIOEdVNDV0bnJOTTg0RDJsMjk3RFE5dDFZUDdqa2kvN1JtdXRSd2VFQTc3L0hXWE9oM0hDeGtSZ2xkRFFrQWpOVE1sMklsb2MxcU41SmZKZWVUbHlUUnp4VVJUZG4xSXh2MnVLanMxMkFiZEVXbEJ0bVZkazJrN0ZGd2owN1BDWjlYQXdXM2RHKzh4S3pORnI0RW53QlpweTlRemhoM2pEWGViQnBZY3B1bzRmUTQ0dStmRDFkd2VFbkh6STd2MHh1dU9BTFJVVjhyWHBGeWZTVFFZa2hkN0lIbTA3anB5aGxrQ21JMEFMWXFQVHBVeFhTK3o0amdEajFQZmx2bXo1ZWN1SXRwSUJ4eVRIcFNUR1dkOWcxQXBmRC9idndVaEw0blQxRXpxZ1g3Y3hmQ2NObWIzbVBML3FpOVN3VEhKNDlvajVaTGpjY2JURzNwUm1sWWk2SkNHMG1RckF0MStpMlVYVFoyZHY5SWxRcE41bmFNWXR2aWFYbFRyRnBvTXNsM2JPQUZFYThzcVBqMldDTXJ4M1lqeDk5cUZ3TzU5QXcvd2d4K0hscU56OG9adkEzZXhSRHZ1aEwxak1RSFBhT0owK1h5QTNmcDFPZk0zcU9iRVZkaHhqdnlueE5NWFFWNCtHSnl2T0VGcWVRQmFJYmJPN2k2M3JweENsdGRaU2hQRnhrak0yRlBWa24zVEcrUnA5cE8zbDJSekZlZ0dmeEdESElBaDhTdGVSMEM0SG9wWHpSRjYxbmhlRHc2VEZOMDVFYnZxOE0zVktLcEdqak82cjduaHVkVEVHTXRZTTkySFREYVIxRkRNWEoxZVRoc2JLZnl3eW9Xd3J6UlNYa2M1MWZsRzN2SWlkNjJoMjliSWNGYlRHaGZWK2ZhYUIrb2hqN2RQTjBDMmUybEM5NitYb3VGQnllbjlBc3VuTERKWjl6N05FeGlVYzBPdW9ZVzZVWmtJeXgyWVVSMno2L1RpUmp5S014NUdiYmpMSHZIdWY3WW10S2doZjM0TEpmeDYzWWc4dnJ2TjJ6QzdsWTB4MHR2S2V6bzRIbUdZRFUrR2FiNmRGTCtLSTc2MWxEY05pZmNqTHJycjlMV1pKY3RHMUZmVTF1d2hvUUUyMk9iamRma1N6WTYzQ2JVNWh6czIxV2VUZGRIMkJhTDExR2k3bFZkbHhQMW5reHFobktoVlk2a25TM0VQZ1ZHZzFKcE41Y1AvaGl2dWpPZWxoWGNQajhIQy9MeUk2TWt0ZVZqbG9sQmRNbUYzYTNEYnN1QVloTDQ0ZHh6dGhXU04wNjV4eFVkNTVMbWYwd1JiT1lPcUgwOS9vOVdiTzJWdEZkYU1iNHFCZ3RGSm9UMVNxb044d1BYTW9YTGIzcDFQVUVoeGZubkx6R3pCSTBLdTdGeHJLc05Kai84Ym4vSDhmUElWT2QzcmZya2xVQi9ET2VPK25rZ2hnU1B6cmxQeGx1Q010T25ETDRZbWw2ZEsxcjN2c2dNeGd0UE9yTUZVWmJFVWJUZEl6aWk1YmVxNzJHNFBEMERLbndqbUJVTFVWRm15OHQrazdmWjNwS2MwUTRVQzZqcFZScVM5VW12OGJ4dzM1ZmxaVk9VMVg3cWtqbmhabHNNYmsyNHFRNkh6N1FjdUw2c0RDMGlISGtpOTZVaDJVZHZtZ1puakl2RXh5MlRlSmRNRFpOU2JkWnlBSGUvWWQxeHNRaEhpS3pqaDdHeFE0eXFNUGF5d1Brak1hbXZxcllwbU83S25hZCtaUUM1bXNDdUFQV1VveHJ4VmhyR3Y3YStLTFhGaHlPTmRUTXJaN2tlMjNxaU80MFpKVXl6Z1l5WDVYeUwwbVY3TmlVekVzOW1qdGJNTjBkRVJxd3lBSnBpZ2FkMEIzL3pSVjdzNFBJZlhTdTZZVi9NSzcrT3JZZS9KdmZHTW4vUEhKZTJmeVVkdG5GcktSTnBYVjBZMjU1OWFXUHQvRzRCbHZqVE10WGxWSVdDbk55QTNZUUJEbVlJb2RGejQxUHZYUFNhNnJxOWxXWmF3WjRkUDExNUhYVi9NL3RuRmtrckJPZHpnNmFQNHBJRCtNWm5USjFTdXVCNmlabHlpb3g0SFQyeTNZQnRrVUtXb29hY0JRVURUcGp3YUR0NXBvQkhsMS9IWGx0d1A4ODdsS0tYeE5VRXlQcXBHVHlBNjk5VXFZL2x0OXlHZGxVS3JhMGZGV1MrMzZpeWxWV3JBeWQ3VXcwQ1pNMHo3eEtUT2R1em5MSWpHMkh4OGNEUExiK092SzZCdjduMURZY2k0Q3hVdVJ4cmpCYzBiYjR2RDNyTjVaejM2bnRMYjgzZVZKSUI4TGlJekNtbjZTTVBqbFgreU5sVGp2SUdqcytRekhQZjYwQWo2Mi9qcnpHOGo5dllNRnRtMVZvUldDSmRtdzd6OU4wdCtjOGN4WnBQZUs0YVRSaWNTMjVRaHJWdFVwN1U1NzhjaGs0cTA0V3g0WW9RU2pGcnlVbHBjUTFBYnhaL1hWTWtuSVUvL09HbDdRNno5WnB4aTArM3lGaFNralVEcG5DSVVoTFdWWDIzS1ErTDl2S3ZGS0kwWldGUWdrREx2Qm95bHJITlZtYXcxMHp3Q1BycjV0bG9kZm5mOTRFV25RMGxGUld5OHBXOUxia0xzeVVWRGMyTlNUSEdEdG5EMXVNdGNoamJDZWIxbXB4RlAwWWJjQ2xoemRMdTZsZk84Qmo2cStiZFQyc3ovKzhTWkNWN1ZJeHR0MERVbjlMN3I0Y0xZV0RTWG5zZUVwT0dGdXR5MHFiT1ZsUzdOTnpzNUZPR0pVcVFwbDJRNjQveUJwWmY5MHN4YkUrLy9QR2RaMDJIU2lwQ2JtRDZOSXRtUTRMazVYVXJHcERNa2hiTW0yWlZoZU5ZVitWYlVXVGN2OTkrMk55WDFWb2FmU3VDK0FONnE5YkZJTXY1WC9lYWdOV1haeEVhOUpqbE13TldiMDBha0dVa1NvZXBwMS95UnV1cUhHYlVuM1VkQlNUeEJVNlNFVmtseldSVWtQbmRWdncyUHJycGp2eE92elBtd0hjMGhwbXE4Mm5waTdHUnJvOGRYcDBLWG5VUW1oWmJSTDdORVZwMXV1Wm1PNDV2dXpLc0hya3RTM0dMV1hPRFZqdyt2WFhMWXg0SGY3bmpSUGQwaTNhb0FHWDZXMjlHbmFWNVlkeURqOVRGa2FramU3R0hZekRvT2JmZGRIdE9TcG9pMlNtekpIckIzaE0vWFVEREVieFAyL29vc3N6Y1JsZWhXWFV2ekh2NFRwQlZrdEhxd2VuRm84dUxWbXk0REtMYTVkM1J0THJtck0zYU1GcjExODNFNHNld2YrODVWV2VnMWM1YWcyNzZOWnJNOUlKVk5jbUxFdkROYVY2MmFxKzE0SUFPR0ZzQnQ5NzNSYThYdjExWXpYd05mbWZ0N0pnMm9TK1hPeW9DOC9jd3ppNjZEaG1nazM4a1VtUDFDVWlZV09YMWJwRDJ6V1h0MkZDcDd1cTg3MDNBUEFhOWRmTmRzY1IvTS9iWkxJeW91VnhxSmZlV3ZHOUplK0pWY2tIUTkrQ0k5Tld4eitibFgvS1lZdk81bjJ0QVAvdnJsWjcrOC9oOXkrOXFlQi9IbnQ5NjdlNW1ldlgxMHJBTERXSy8vRmFBVDVNWGRCWGRQMEMvQkFlczc5MmM0MEgrQWlBcDFlMW9IOEhnSDk0Zy9MdHR4MWdwNjNvcDFleW9NL0J2dzUvRy83eEZicUpQY0NYbm1CaXdEUGIvWUtPNEZYNE9qeUNiMjg5ZGIyL05vcWljdzRpN042VFZ0b3o4dE53REgrOHgvaTZBZTdsbWFRVkVOekpGYjNEaS9CRmVBd3orSXM5U2plUXlTcFBxYkxGbE5teXo0N3o1YS9BRitBWUZ2RG1IcWliU1hURXpvVDRHYzNPQUxhcUFQNEtQRlVKNm4rMXgrckdBTTZaZDc4YmdKMGE4UU40R1U2MTR2eHdEOWUxQW15NkNjc2tOcmN6THgxSklwNkhFNVVaRC9EQkhyRnIyb05sZ0c0T2R2MjI2Qm9kb3J5akdKOXEyVC9BUjN2UXJzT0NTMGN0WFppM3J1TGxocEZESllsNEhtWXRqUUNQOXJoZG40c3V5U0xLRHQ2d0xjQzUyaDh4UGxjamp1MWZuK3lodXc0TFpzQUdVdW8yYjRGeDJVd1F1Nzd1cVJIWEd0ZzkyYU4zdFFDYkZleGMwdWs5M3ZoVFhiY3Q2eTdNdWxMeWNvVWxqeDhuZ0RNQmcxdHZKakFhenBFbU90eGx6Y2x2ajF2UWYxVHg3UWxQRHBHcHFndGRTS3ovZDkvaGR5MXZUZkZIU21DOWRHRFpiTGlleno3QWM4MDFIaXJHWnNXanlkZlp5UHZIWEwvWThNanpnOEJ4VFppdXdLejRFYjhzQkU5enpuc3ptanZGd0hLUElXVW53aHFmVlJjZDRDazBLNmF0ZTQ4bTFvT2ZyWDMveU90dkFzSjh6c1BBTTg5c2puZGRtdUx1RFBqWDlCdS9MN3g3eHBNekZrNm5XdHlRZlBnMjc4R240QWVrejJaZ09tVTllSjM3UjE0dndFL0JMOEczYWliQ2lXTVdXRFEwWnRrUE1ubGNHZUF1L0FnKzhaeWVjVTVCUHV5MklMRCtzUXF5WmhBS21uN1haZCtqSU1UTjllQkw3eDk1eFZMU1g0T244RWNObFhEcW1CbHFTMTNqRzRMcG1HYmtGLzBDbk9pM0g4RVRPSVh6bW5tdGIwYTE2VHp4ajFzVXZRQ0JpWFpHRHRtQjNLQWVmUEg5NHhjVWEvNnZ3Um44MEdPRnlqRVhGcGJhNEExZThLUWZGRisyNTl0eDVYUzRlZ1luOGZRc0xHcnFHckhienRyK3VCeVRhaFd1TDFOVUdiRHBzbnJ3QmZlUFB3SEhJZjlYNFJuTTRaMkFCV2R4VUJscVEyUHdodUR4b1MwdnZxQjFKelMwUDRoMm5BL1FnVHJzSkZuK1kzQU9qczlKRkMwN0NHV1gxb05YM1QveUhPemdEandQbjFQTTNnOUprOWxack1FcHhubFBtQmJqeW8yK0tGWFJVNTJUSk0vMkFMY1k1N1JVempPYmJqcXhWdysrNFA2UkFPZjU4cGNWc3c5RGFqZTNodHJpWXJwRE9vbnJlM0N1ZFNlNmJma1RFZ0hCSHVEaXl1NU1Dc2M3QkhoWUR4N2VQeExqcWlnWFpzdytpak1IRmh1d0JtdG9UUHRPeE9yVHZZSkRuQzc1ZG5VYmhmd3UvWlc5QWdZZCtwZUw2OEhEKzBlbUtxdWlYSGhXakpnL1Vya0pZenVpYUwzRTlhSS95dHJDdkFkNEdjWVpNQ2tTUXhmVWczdjNqOGM0ZTkwajVaVFBkdm1KSkdIbk9DSTJuSFM4MDgxWDAxM3BIdUJsVjFnQjJNWDFZTm1XTEhxcUdOL1RXbUcweTZjbEpXdGh4TlVsNDhxMzhCaTh2dE1LeXp6cEZkU0RoeFo1V0JBNVpMdDhKdjM4OTVEZHVCbGdiUFlBajhDNEI4aE82OEZEa29oNWx5ZEM0RmlXdkJPVnFqWWRxamlMdjkydDh5UERqckRhaUhkVUQxNXFrU1VSU0dtWEp3T01TeFdBWFl3cjN6YUF1Zko2NmwrOTR2djNBTyt2UGNEN2F3L3cvdG9EdkwvMkFPK3ZQY0Q3YXcvd0h1RDl0UWQ0ZiswQjNsOTdnUGZYSHVEOXRRZDRmKzBCM2w5N2dHOEx3UDhHL0FMOE8vQTVPQ3EwWXMyS0lkdi9xT0lYRy80bXZGQU1GMTZnWkQrMlh2dS9COGFzNSs4YmZsbFd5ZzB6YU5PNWJmWGo2dmZoaHdEODYvQXEzTmZSUzl0OVdQbmhmbnZDSXcvQ1Q4R0xjRlRNbnBudGRGL3o5VitQV2MvdldvSUgrRkwzWm52NTdQaXRjZEdQNFIvQzM0YXZ3NWZnUlZVSW5Dd2JzbjF5eUE4Qzh6bS9CSDhOWG9YblZFNndWUGpkZUNJMzhrWC8zK0N0OWRiejFwVG1IRlJ1K0htNE85Q2gzY2xyOTluZWd4ZndqK0VSL0RSOEVWNkI1K0R1UU9uVGdVdzVybmtZK0ZiTlUzZ05YaDBvL0pZVHVXT3Z5QmY5RnZ6WDY2M0hIL0hlak84THdBbDhIbDVZTFRkOHE3c3FBM3dianVFeGZBRmVnUWR3ZnlEb1NrV1k4c3d6RWY2bzRReWV3ZWZnK2NITmJxTVFydVNML3UvV1djK0U1Zzd2bm5FWGdEbWNEZVNHYi9GNGNCY0NnVCtHR1J6RFUzaFpZYnVyQXQ5VEV0SGdiTTZKb3hKKzZOTXp6VGNmNmMyYnljdjIrS0svZitsNkxCenc1SXdmcVpKaEEzTTQ3MnBXVC9hakt4bmp2NEFGbk1FcG5CVFBORDZzMko3cUhiUEFxY01LNzRUMm1aNFZHQjl1SkE0NjVJdCsvZUwxV0toWU9EN3hIT2tyMWFqSzdkMEM0K2tlNEh5OXFYWndwZ0xyK1pubS91TkZ3OHhRT1N5OEg5SXpqVXJkOStCSWZlbllheWxmOUZzWHI4ZkJBYWRuUElFRG5hOElCY3dseG51QTAvV3Y2R0FXUGQ3ZERJS2pNZFNXdWVBc0JqNE03VE9kMDZxQmJ3RHdLcjdvbGV1eE1PRWNUdUVaVEhXdkRZVU83YUhxQWUwQmJxK0hFRlJ6T3o3V1ZvVERRa1ZkczdBNHNJSXhmQ1FkQ2VmRlJvSU9GL05GTDFtUGFiL252T2FrU0wvUTFhRnROcFViL25GT1ZYNmd6eWcvMW5JU3lEZlVoc29rSXphQlI5S3htODBzNW1LKzZQNTZpbDFqWGljN25oUXhzeFNtM093QkhsNGZGZExxaTY0bkRRWnZxRTJhdDdjV0FwL0lWdnJONi9CRkwxbVBoWXJHTUJmT2k0UHlqdVNHZjZ3QkJoN3AvRlpUZ2hDTldHZ016bEJick5Kb1BKWDJtVzVtd1pmeVJmZlhvN09GaTVwWmNTNHFaVXJsVmlwdHJYdHcrR1FveWhEUFMrQU5qY0dCTlJpTENRRFBaUE1IdWlaZmRGcFBTVGNRd3dLWWRSTnFwa2ptN0FGZWVUMHBKekFMZ283ZzhZWUdyTUhTMGlvY3krWVRtMnZ5UlV2dnBYQ0lwUTVwZTY2NlRKcmN5Z25TY1VmL3AwTkRzL2lBSS9ucURIQzhUbVFUOHgzTkY5MWw3Nm9EZFFHd3U2MVo2RTBBQnY3dU8xZGJmLzM3Wmx2K1p3L1BiaDhmMXM0QXZ1cjY2NTcvK1lZQnZ1cjY2NTcvK1lZQnZ1cjY2NTcvK1lZQnZ1cjY2NTcvK2FZQnZ1TDY2NTcvK1ZNQThGWFdYL2Y4enpjTjhCWFhYL2Y4enpjTk1GZGJmOTN6UDM4S0xQaUs2Njk3L3VlYnR1QXJyci91K1o5dkdtQ3VzUDY2NTMvKzFGandWZFpmOS96UE43b0hYMzM5ZGMvL2ZOTXUraXJycjN2KzUwK0JpK1pxNjY5Ny91ZWJBL2p6OFB1ZGY5aHQvZld2NTE3Si9YVXpBUDhDL0JBZVg5V0NEclVwWjMvZEVNQnhnUGNmYnRUVnZzWVY1WW4zMnUwM0IzQWM0UDNiOEkrdnhOQktlZUw5ZFJNQWx3TzgzOTU5cUdPNzhzVDc2OW9CN2czdy92R1ZZRnpLRSsrdjZ3VjRPTUQ3Rjd0Y2tGa21UN3kvcmhIZ3BRTzhiKzRZNDZYeXhQdnJ1Z0JlTmNCN0JSaVg4c1Q3NjdvQXZtQ0E5d29BSHNvVDc2K3JCSmpMQm5oM3R4T3ZraWZlWDFkc3daY084RzZON3NYeXhQdnI2aTM0MGdIZTNUbnFWZkxFKyt1S0FiNTBnSGNYTG5yWDhzUjdnTmRQUnF3endMdTdZL0ZPNVluM0FLOWpYQ01HZUhkZ3hEdVZKNzVWQUk4bGpQN1BBYjMvUmZqY1pmZVBIQkIrNzlkcGZwSDFDYW5OMzBkK21UMWg5R3FBeHhKR001TFFlZVExK1RiK0VRSnJFbExiMzhWSFE5NFRScTkwMGFNSW84Y1NPbys4RHA4UWZzQjh6cHFFMU5PM09JOVpyajFoOUVWNzhQcUUwV01KblVkZVU2RStKanlrL2hickVGSWZlV2J2SWQ4SDlvVFJGd2RaYXhKR3Z6aVcwSG4wZ3FZQi93eVowUHdSbHhKU1QrQk93OW03N0FtajE0aWkxeUdNL3R4WVF1ZE4wcUR6R2U0RXFmQS81R0pDYWdzSGNQYUVQV0gwZXNla1N3bWpSeE02YjVKRWNaNHd3NTBpbHZBT0Z4QlN4NHlMVytBL1lVOFl2Zlk1K0FMQzZOR0V6aHRteVpvRlpvYXJ3QkxlWnhVaHRZNHJjM2JLbmpCNlRLSmpGVUh6Sm9UT296RjJZQnBzamN5eERnemhRMVlSVXNlOCtKNHdlbndtYXlsQjgyaEM1dzB6b1JYVU5YYVJCbVNNUVVxaVdTV2tMc2FWcWMvWkUwYVBURlV1SldnZVRlaThTZkxaUWVNeE5hWlNJemJJSTRhRTFObXIxM1AyaE5IamM5RTlndVlOQ1owMzJZbE53RVNNTGNaaUxRSGtFNGFFMUJGZzB5QVI0ejFoOUFpQUdSQTBqeVowM3R5SXhXTWFqTVBXQklzeFlKQ25sSVRVNVNoaUhZZFo5NFRSNHdDbVN4ZzlqdEI1S3lQR1l6eW1BWWV4V0VNd0FQSXNBZFlkVjZhT2JtTlBHRDBhWUxvRXphTUpuVGMwWWdzK1lEdzBHQXRxeEJqa3VQMzhiTVJXQ0huNzN4Tkdqejc1UDczV2VuQ0VKbmh3eVZlM0FFZThUdEtkSmNZaEJsOTd3dWhOQU9iSzY2bHZELzlKOU5TNzV2MTd3dWl0QU41ZmU0RDMxeDdnL2JVSGVIL3RBZDVmZTREM0FPK3ZQY0Q3YXcvdy90b0R2TC8yQU8rdlBjRDdhdy93L3RvRHZBZDRmLzI0QUJ6WjhvK0tMc1NMUytQdi9UcVRiM1A0aEtsUXJUR2grZmJJQlQwQXhxem5uYitML1YybWIzSGtONU1iL25FSGVLN2Q0SWNEbGQ2bG1EVy9pSDlFK0FIMU1kT3cvSmx1MlQxeE5tWTk4c3Y0d0huRDdEM3VOSHU1NFdVdU9zQlRiUXV2QnNQVC9VZnpOeEdZendrUDhjK1l6M0Mrci9pNkRjeVJML3JaK3V0UndXSDVQbWZ2Y3ZZRXQ5akxEUy9iZzAvQjY0RFdLclFNOEFMOEZQd1M5YmVRQ2U2RU1LTlpZSm9sMzdqQk15MzVvdGRhejBCdzJIL0MyU21jNytXR0IwSFdERUxCbU9CeUEzcjVRT05vNFYrRHB6Ui9oRlM0VTh3TVcxUFhOQjRUT3FZejl1cnhSVisrbnRXQ3cvVTU5VHk5ZWJkV2JyZ2ZSUzlBWUtLTjYzWm9rWlZ5Z3I4R1ovZ2ZJaFpYSVhQc0FsTmpQT0xCYnk1YzFlT0x2bVE5bHdrT3k1eDZRVjFqNVRZcXBTMDVKdFVnVUhVcDV0b0hHc1ZmbjROWDRSbk1DZStBeFRwd21BcFRZeHFNeHdmQ2VKR2pwWHpSRjYxbmJjSGhVQlBxV3plOXN2d2NISitTNk5Qc2NLckVqdWc3OER4OExqM1Q4RDRZeEdJZHhtSmN3aGkzNGZ6WlVyN29sZXZaQ3c1dmtPaG9DbHE1ekJQWkFueWdEL1RsOUV6RGg2a2wzVmhzSFljREViK2hDdEpTdnVpVjY5a0xEbStXeWNyT1RBckhtQjUvVll5UDZqT1Zqd2dHYXdrMnpRT2FUY2MxTCthTFhyS2V2ZUR3WnFsS3J3OFU5WTFwNjZ1SzhkRXpkWXdCZVVRQVk3RGJ5WU5lekJmZFdROTd3ZUV0QUtZUWcyeEpJa3V2ZUFUM2RZZUxHSCtTaHJXTndaZ04wYjJZTDdxem5yM2c4SllBbzViUUJ6aVBqeDdCUFowZDlSQ1FwNFVaYm5GZHpCZGRvcjRYSE40S1lNckIycUhGUkl6emNMQUhRWjV0aGU1b3Z1aTk0UENXQVBlZmFZbnhJZHpSd2RIQ2J1UjRCK3RiaXk5Nkx6aThFNEQ3ejdTMG1FUGQrZXFPM2NUNTNaMFk4U1Y4MFh2QjRaMEFESmkvZjdYMTEzZis3cDcvK1VZQnZ1cjY2NTcvK1lZQnZ1cjY2NTcvK2FZQnZ1TDY2NTcvK2FZQnZ1TDY2NTcvK2FZQnZ1TDY2NTcvK2FZQnZ1TDY2NTcvK1ZNQThGWFdYL2Y4ejU4T2dLK3kvcnJuZjc1UmdMbmErdXVlLy9sVEEvQ1YxVi8zL004MzdhS3Z2djY2NTMrK1VRdm1hdXV2ZS83blR3ZkFWMU4vM2ZNL2Z6cjI0Q3V1dis3NW56OEZGbnhsOWRjOS8vTU9yLzgvZ2xpeHdSdVVmTTRBQUFBQVNVVk9SSzVDWUlJPSc7XG5cblx0fVxuXG5cdGdldFNlYXJjaFRleHR1cmUoKSB7XG5cblx0XHRyZXR1cm4gJ2RhdGE6aW1hZ2UvcG5nO2Jhc2U2NCxpVkJPUncwS0dnb0FBQUFOU1VoRVVnQUFBRUlBQUFBaENBQUFBQUJJWHlMQUFBQUFPRWxFUVZSSXgyTmdHQVdqWUJTTWdsRXdFSUNSRVlSZ0ZCWkJxRENTTEEyTUdQVUlWUUVURTlpTlVBcUxSNWdJZW9RS1Jnd1hqd0FBR240QXRhRmVZTEVBQUFBQVNVVk9SSzVDWUlJPSc7XG5cblx0fVxuXG5cdGRpc3Bvc2UoKSB7XG5cblx0XHR0aGlzLmVkZ2VzUlQuZGlzcG9zZSgpO1xuXHRcdHRoaXMud2VpZ2h0c1JULmRpc3Bvc2UoKTtcblxuXHRcdHRoaXMuYXJlYVRleHR1cmUuZGlzcG9zZSgpO1xuXHRcdHRoaXMuc2VhcmNoVGV4dHVyZS5kaXNwb3NlKCk7XG5cblx0XHR0aGlzLm1hdGVyaWFsRWRnZXMuZGlzcG9zZSgpO1xuXHRcdHRoaXMubWF0ZXJpYWxXZWlnaHRzLmRpc3Bvc2UoKTtcblx0XHR0aGlzLm1hdGVyaWFsQmxlbmQuZGlzcG9zZSgpO1xuXG5cdFx0dGhpcy5mc1F1YWQuZGlzcG9zZSgpO1xuXG5cdH1cblxufVxuXG5leHBvcnQgeyBTTUFBUGFzcyB9O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///737\n")},45:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ p: () => (/* binding */ ShaderPass)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(753);\n/* harmony import */ var _Pass_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(844);\n\n\n\nclass ShaderPass extends _Pass_js__WEBPACK_IMPORTED_MODULE_0__/* .Pass */ .o {\n\n\tconstructor( shader, textureID ) {\n\n\t\tsuper();\n\n\t\tthis.textureID = ( textureID !== undefined ) ? textureID : 'tDiffuse';\n\n\t\tif ( shader instanceof three__WEBPACK_IMPORTED_MODULE_1__/* .ShaderMaterial */ .BKk ) {\n\n\t\t\tthis.uniforms = shader.uniforms;\n\n\t\t\tthis.material = shader;\n\n\t\t} else if ( shader ) {\n\n\t\t\tthis.uniforms = three__WEBPACK_IMPORTED_MODULE_1__/* .UniformsUtils */ .LlO.clone( shader.uniforms );\n\n\t\t\tthis.material = new three__WEBPACK_IMPORTED_MODULE_1__/* .ShaderMaterial */ .BKk( {\n\n\t\t\t\tname: ( shader.name !== undefined ) ? shader.name : 'unspecified',\n\t\t\t\tdefines: Object.assign( {}, shader.defines ),\n\t\t\t\tuniforms: this.uniforms,\n\t\t\t\tvertexShader: shader.vertexShader,\n\t\t\t\tfragmentShader: shader.fragmentShader\n\n\t\t\t} );\n\n\t\t}\n\n\t\tthis.fsQuad = new _Pass_js__WEBPACK_IMPORTED_MODULE_0__/* .FullScreenQuad */ .F( this.material );\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer /*, deltaTime, maskActive */ ) {\n\n\t\tif ( this.uniforms[ this.textureID ] ) {\n\n\t\t\tthis.uniforms[ this.textureID ].value = readBuffer.texture;\n\n\t\t}\n\n\t\tthis.fsQuad.material = this.material;\n\n\t\tif ( this.renderToScreen ) {\n\n\t\t\trenderer.setRenderTarget( null );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t} else {\n\n\t\t\trenderer.setRenderTarget( writeBuffer );\n\t\t\t// TODO: Avoid using autoClear properties, see https://github.com/mrdoob/three.js/pull/15571#issuecomment-465669600\n\t\t\tif ( this.clear ) renderer.clear( renderer.autoClearColor, renderer.autoClearDepth, renderer.autoClearStencil );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t}\n\n\t}\n\n\tdispose() {\n\n\t\tthis.material.dispose();\n\n\t\tthis.fsQuad.dispose();\n\n\t}\n\n}\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiNDUuanMiLCJtYXBwaW5ncyI6Ijs7Ozs7QUFHZTtBQUNrQzs7QUFFakQseUJBQXlCLG1EQUFJOztBQUU3Qjs7QUFFQTs7QUFFQTs7QUFFQSx5QkFBeUIsNERBQWM7O0FBRXZDOztBQUVBOztBQUVBLElBQUk7O0FBRUosbUJBQW1CLDJEQUFhOztBQUVoQyx1QkFBdUIsNERBQWM7O0FBRXJDO0FBQ0EsOEJBQThCO0FBQzlCO0FBQ0E7QUFDQTs7QUFFQSxLQUFLOztBQUVMOztBQUVBLG9CQUFvQiw2REFBYzs7QUFFbEM7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVzQiIsInNvdXJjZXMiOlsid2VicGFjazovL3RocmVlanMtcG9zdHByb2Nlc3MvLi9ub2RlX21vZHVsZXMvdGhyZWUvZXhhbXBsZXMvanNtL3Bvc3Rwcm9jZXNzaW5nL1NoYWRlclBhc3MuanM/ODM0MyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuXHRTaGFkZXJNYXRlcmlhbCxcblx0VW5pZm9ybXNVdGlsc1xufSBmcm9tICd0aHJlZSc7XG5pbXBvcnQgeyBQYXNzLCBGdWxsU2NyZWVuUXVhZCB9IGZyb20gJy4vUGFzcy5qcyc7XG5cbmNsYXNzIFNoYWRlclBhc3MgZXh0ZW5kcyBQYXNzIHtcblxuXHRjb25zdHJ1Y3Rvciggc2hhZGVyLCB0ZXh0dXJlSUQgKSB7XG5cblx0XHRzdXBlcigpO1xuXG5cdFx0dGhpcy50ZXh0dXJlSUQgPSAoIHRleHR1cmVJRCAhPT0gdW5kZWZpbmVkICkgPyB0ZXh0dXJlSUQgOiAndERpZmZ1c2UnO1xuXG5cdFx0aWYgKCBzaGFkZXIgaW5zdGFuY2VvZiBTaGFkZXJNYXRlcmlhbCApIHtcblxuXHRcdFx0dGhpcy51bmlmb3JtcyA9IHNoYWRlci51bmlmb3JtcztcblxuXHRcdFx0dGhpcy5tYXRlcmlhbCA9IHNoYWRlcjtcblxuXHRcdH0gZWxzZSBpZiAoIHNoYWRlciApIHtcblxuXHRcdFx0dGhpcy51bmlmb3JtcyA9IFVuaWZvcm1zVXRpbHMuY2xvbmUoIHNoYWRlci51bmlmb3JtcyApO1xuXG5cdFx0XHR0aGlzLm1hdGVyaWFsID0gbmV3IFNoYWRlck1hdGVyaWFsKCB7XG5cblx0XHRcdFx0bmFtZTogKCBzaGFkZXIubmFtZSAhPT0gdW5kZWZpbmVkICkgPyBzaGFkZXIubmFtZSA6ICd1bnNwZWNpZmllZCcsXG5cdFx0XHRcdGRlZmluZXM6IE9iamVjdC5hc3NpZ24oIHt9LCBzaGFkZXIuZGVmaW5lcyApLFxuXHRcdFx0XHR1bmlmb3JtczogdGhpcy51bmlmb3Jtcyxcblx0XHRcdFx0dmVydGV4U2hhZGVyOiBzaGFkZXIudmVydGV4U2hhZGVyLFxuXHRcdFx0XHRmcmFnbWVudFNoYWRlcjogc2hhZGVyLmZyYWdtZW50U2hhZGVyXG5cblx0XHRcdH0gKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuZnNRdWFkID0gbmV3IEZ1bGxTY3JlZW5RdWFkKCB0aGlzLm1hdGVyaWFsICk7XG5cblx0fVxuXG5cdHJlbmRlciggcmVuZGVyZXIsIHdyaXRlQnVmZmVyLCByZWFkQnVmZmVyIC8qLCBkZWx0YVRpbWUsIG1hc2tBY3RpdmUgKi8gKSB7XG5cblx0XHRpZiAoIHRoaXMudW5pZm9ybXNbIHRoaXMudGV4dHVyZUlEIF0gKSB7XG5cblx0XHRcdHRoaXMudW5pZm9ybXNbIHRoaXMudGV4dHVyZUlEIF0udmFsdWUgPSByZWFkQnVmZmVyLnRleHR1cmU7XG5cblx0XHR9XG5cblx0XHR0aGlzLmZzUXVhZC5tYXRlcmlhbCA9IHRoaXMubWF0ZXJpYWw7XG5cblx0XHRpZiAoIHRoaXMucmVuZGVyVG9TY3JlZW4gKSB7XG5cblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggbnVsbCApO1xuXHRcdFx0dGhpcy5mc1F1YWQucmVuZGVyKCByZW5kZXJlciApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCB3cml0ZUJ1ZmZlciApO1xuXHRcdFx0Ly8gVE9ETzogQXZvaWQgdXNpbmcgYXV0b0NsZWFyIHByb3BlcnRpZXMsIHNlZSBodHRwczovL2dpdGh1Yi5jb20vbXJkb29iL3RocmVlLmpzL3B1bGwvMTU1NzEjaXNzdWVjb21tZW50LTQ2NTY2OTYwMFxuXHRcdFx0aWYgKCB0aGlzLmNsZWFyICkgcmVuZGVyZXIuY2xlYXIoIHJlbmRlcmVyLmF1dG9DbGVhckNvbG9yLCByZW5kZXJlci5hdXRvQ2xlYXJEZXB0aCwgcmVuZGVyZXIuYXV0b0NsZWFyU3RlbmNpbCApO1xuXHRcdFx0dGhpcy5mc1F1YWQucmVuZGVyKCByZW5kZXJlciApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0dGhpcy5tYXRlcmlhbC5kaXNwb3NlKCk7XG5cblx0XHR0aGlzLmZzUXVhZC5kaXNwb3NlKCk7XG5cblx0fVxuXG59XG5cbmV4cG9ydCB7IFNoYWRlclBhc3MgfTtcbiJdLCJuYW1lcyI6W10sInNvdXJjZVJvb3QiOiIifQ==\n//# sourceURL=webpack-internal:///45\n")},208:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("\n// EXPORTS\n__webpack_require__.d(__webpack_exports__, {\n C: () => (/* binding */ UnrealBloomPass)\n});\n\n// EXTERNAL MODULE: ./node_modules/three/build/three.module.js\nvar three_module = __webpack_require__(753);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/postprocessing/Pass.js\nvar Pass = __webpack_require__(844);\n// EXTERNAL MODULE: ./node_modules/three/examples/jsm/shaders/CopyShader.js\nvar CopyShader = __webpack_require__(364);\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/shaders/LuminosityHighPassShader.js\n\n\n/**\n * Luminosity\n * http://en.wikipedia.org/wiki/Luminosity\n */\n\nconst LuminosityHighPassShader = {\n\n\tname: 'LuminosityHighPassShader',\n\n\tshaderID: 'luminosityHighPass',\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'luminosityThreshold': { value: 1.0 },\n\t\t'smoothWidth': { value: 1.0 },\n\t\t'defaultColor': { value: new three_module/* Color */.Q1f( 0x000000 ) },\n\t\t'defaultOpacity': { value: 0.0 }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\n\t\tuniform sampler2D tDiffuse;\n\t\tuniform vec3 defaultColor;\n\t\tuniform float defaultOpacity;\n\t\tuniform float luminosityThreshold;\n\t\tuniform float smoothWidth;\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvec4 texel = texture2D( tDiffuse, vUv );\n\n\t\t\tfloat v = luminance( texel.xyz );\n\n\t\t\tvec4 outputColor = vec4( defaultColor.rgb, defaultOpacity );\n\n\t\t\tfloat alpha = smoothstep( luminosityThreshold, luminosityThreshold + smoothWidth, v );\n\n\t\t\tgl_FragColor = mix( outputColor, texel, alpha );\n\n\t\t}`\n\n};\n\n\n\n;// CONCATENATED MODULE: ./node_modules/three/examples/jsm/postprocessing/UnrealBloomPass.js\n\n\n\n\n\n/**\n * UnrealBloomPass is inspired by the bloom pass of Unreal Engine. It creates a\n * mip map chain of bloom textures and blurs them with different radii. Because\n * of the weighted combination of mips, and because larger blurs are done on\n * higher mips, this effect provides good quality and performance.\n *\n * Reference:\n * - https://docs.unrealengine.com/latest/INT/Engine/Rendering/PostProcessEffects/Bloom/\n */\nclass UnrealBloomPass extends Pass/* Pass */.o {\n\n\tconstructor( resolution, strength, radius, threshold ) {\n\n\t\tsuper();\n\n\t\tthis.strength = ( strength !== undefined ) ? strength : 1;\n\t\tthis.radius = radius;\n\t\tthis.threshold = threshold;\n\t\tthis.resolution = ( resolution !== undefined ) ? new three_module/* Vector2 */.I9Y( resolution.x, resolution.y ) : new three_module/* Vector2 */.I9Y( 256, 256 );\n\n\t\t// create color only once here, reuse it later inside the render function\n\t\tthis.clearColor = new three_module/* Color */.Q1f( 0, 0, 0 );\n\n\t\t// render targets\n\t\tthis.renderTargetsHorizontal = [];\n\t\tthis.renderTargetsVertical = [];\n\t\tthis.nMips = 5;\n\t\tlet resx = Math.round( this.resolution.x / 2 );\n\t\tlet resy = Math.round( this.resolution.y / 2 );\n\n\t\tthis.renderTargetBright = new three_module/* WebGLRenderTarget */.nWS( resx, resy, { type: three_module/* HalfFloatType */.ix0 } );\n\t\tthis.renderTargetBright.texture.name = 'UnrealBloomPass.bright';\n\t\tthis.renderTargetBright.texture.generateMipmaps = false;\n\n\t\tfor ( let i = 0; i < this.nMips; i ++ ) {\n\n\t\t\tconst renderTargetHorizontal = new three_module/* WebGLRenderTarget */.nWS( resx, resy, { type: three_module/* HalfFloatType */.ix0 } );\n\n\t\t\trenderTargetHorizontal.texture.name = 'UnrealBloomPass.h' + i;\n\t\t\trenderTargetHorizontal.texture.generateMipmaps = false;\n\n\t\t\tthis.renderTargetsHorizontal.push( renderTargetHorizontal );\n\n\t\t\tconst renderTargetVertical = new three_module/* WebGLRenderTarget */.nWS( resx, resy, { type: three_module/* HalfFloatType */.ix0 } );\n\n\t\t\trenderTargetVertical.texture.name = 'UnrealBloomPass.v' + i;\n\t\t\trenderTargetVertical.texture.generateMipmaps = false;\n\n\t\t\tthis.renderTargetsVertical.push( renderTargetVertical );\n\n\t\t\tresx = Math.round( resx / 2 );\n\n\t\t\tresy = Math.round( resy / 2 );\n\n\t\t}\n\n\t\t// luminosity high pass material\n\n\t\tconst highPassShader = LuminosityHighPassShader;\n\t\tthis.highPassUniforms = three_module/* UniformsUtils */.LlO.clone( highPassShader.uniforms );\n\n\t\tthis.highPassUniforms[ 'luminosityThreshold' ].value = threshold;\n\t\tthis.highPassUniforms[ 'smoothWidth' ].value = 0.01;\n\n\t\tthis.materialHighPassFilter = new three_module/* ShaderMaterial */.BKk( {\n\t\t\tuniforms: this.highPassUniforms,\n\t\t\tvertexShader: highPassShader.vertexShader,\n\t\t\tfragmentShader: highPassShader.fragmentShader\n\t\t} );\n\n\t\t// gaussian blur materials\n\n\t\tthis.separableBlurMaterials = [];\n\t\tconst kernelSizeArray = [ 3, 5, 7, 9, 11 ];\n\t\tresx = Math.round( this.resolution.x / 2 );\n\t\tresy = Math.round( this.resolution.y / 2 );\n\n\t\tfor ( let i = 0; i < this.nMips; i ++ ) {\n\n\t\t\tthis.separableBlurMaterials.push( this.getSeperableBlurMaterial( kernelSizeArray[ i ] ) );\n\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'invSize' ].value = new three_module/* Vector2 */.I9Y( 1 / resx, 1 / resy );\n\n\t\t\tresx = Math.round( resx / 2 );\n\n\t\t\tresy = Math.round( resy / 2 );\n\n\t\t}\n\n\t\t// composite material\n\n\t\tthis.compositeMaterial = this.getCompositeMaterial( this.nMips );\n\t\tthis.compositeMaterial.uniforms[ 'blurTexture1' ].value = this.renderTargetsVertical[ 0 ].texture;\n\t\tthis.compositeMaterial.uniforms[ 'blurTexture2' ].value = this.renderTargetsVertical[ 1 ].texture;\n\t\tthis.compositeMaterial.uniforms[ 'blurTexture3' ].value = this.renderTargetsVertical[ 2 ].texture;\n\t\tthis.compositeMaterial.uniforms[ 'blurTexture4' ].value = this.renderTargetsVertical[ 3 ].texture;\n\t\tthis.compositeMaterial.uniforms[ 'blurTexture5' ].value = this.renderTargetsVertical[ 4 ].texture;\n\t\tthis.compositeMaterial.uniforms[ 'bloomStrength' ].value = strength;\n\t\tthis.compositeMaterial.uniforms[ 'bloomRadius' ].value = 0.1;\n\n\t\tconst bloomFactors = [ 1.0, 0.8, 0.6, 0.4, 0.2 ];\n\t\tthis.compositeMaterial.uniforms[ 'bloomFactors' ].value = bloomFactors;\n\t\tthis.bloomTintColors = [ new three_module/* Vector3 */.Pq0( 1, 1, 1 ), new three_module/* Vector3 */.Pq0( 1, 1, 1 ), new three_module/* Vector3 */.Pq0( 1, 1, 1 ), new three_module/* Vector3 */.Pq0( 1, 1, 1 ), new three_module/* Vector3 */.Pq0( 1, 1, 1 ) ];\n\t\tthis.compositeMaterial.uniforms[ 'bloomTintColors' ].value = this.bloomTintColors;\n\n\t\t// blend material\n\n\t\tconst copyShader = CopyShader/* CopyShader */.Z;\n\n\t\tthis.copyUniforms = three_module/* UniformsUtils */.LlO.clone( copyShader.uniforms );\n\n\t\tthis.blendMaterial = new three_module/* ShaderMaterial */.BKk( {\n\t\t\tuniforms: this.copyUniforms,\n\t\t\tvertexShader: copyShader.vertexShader,\n\t\t\tfragmentShader: copyShader.fragmentShader,\n\t\t\tblending: three_module/* AdditiveBlending */.EZo,\n\t\t\tdepthTest: false,\n\t\t\tdepthWrite: false,\n\t\t\ttransparent: true\n\t\t} );\n\n\t\tthis.enabled = true;\n\t\tthis.needsSwap = false;\n\n\t\tthis._oldClearColor = new three_module/* Color */.Q1f();\n\t\tthis.oldClearAlpha = 1;\n\n\t\tthis.basic = new three_module/* MeshBasicMaterial */.V9B();\n\n\t\tthis.fsQuad = new Pass/* FullScreenQuad */.F( null );\n\n\t}\n\n\tdispose() {\n\n\t\tfor ( let i = 0; i < this.renderTargetsHorizontal.length; i ++ ) {\n\n\t\t\tthis.renderTargetsHorizontal[ i ].dispose();\n\n\t\t}\n\n\t\tfor ( let i = 0; i < this.renderTargetsVertical.length; i ++ ) {\n\n\t\t\tthis.renderTargetsVertical[ i ].dispose();\n\n\t\t}\n\n\t\tthis.renderTargetBright.dispose();\n\n\t\t//\n\n\t\tfor ( let i = 0; i < this.separableBlurMaterials.length; i ++ ) {\n\n\t\t\tthis.separableBlurMaterials[ i ].dispose();\n\n\t\t}\n\n\t\tthis.compositeMaterial.dispose();\n\t\tthis.blendMaterial.dispose();\n\t\tthis.basic.dispose();\n\n\t\t//\n\n\t\tthis.fsQuad.dispose();\n\n\t}\n\n\tsetSize( width, height ) {\n\n\t\tlet resx = Math.round( width / 2 );\n\t\tlet resy = Math.round( height / 2 );\n\n\t\tthis.renderTargetBright.setSize( resx, resy );\n\n\t\tfor ( let i = 0; i < this.nMips; i ++ ) {\n\n\t\t\tthis.renderTargetsHorizontal[ i ].setSize( resx, resy );\n\t\t\tthis.renderTargetsVertical[ i ].setSize( resx, resy );\n\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'invSize' ].value = new three_module/* Vector2 */.I9Y( 1 / resx, 1 / resy );\n\n\t\t\tresx = Math.round( resx / 2 );\n\t\t\tresy = Math.round( resy / 2 );\n\n\t\t}\n\n\t}\n\n\trender( renderer, writeBuffer, readBuffer, deltaTime, maskActive ) {\n\n\t\trenderer.getClearColor( this._oldClearColor );\n\t\tthis.oldClearAlpha = renderer.getClearAlpha();\n\t\tconst oldAutoClear = renderer.autoClear;\n\t\trenderer.autoClear = false;\n\n\t\trenderer.setClearColor( this.clearColor, 0 );\n\n\t\tif ( maskActive ) renderer.state.buffers.stencil.setTest( false );\n\n\t\t// Render input to screen\n\n\t\tif ( this.renderToScreen ) {\n\n\t\t\tthis.fsQuad.material = this.basic;\n\t\t\tthis.basic.map = readBuffer.texture;\n\n\t\t\trenderer.setRenderTarget( null );\n\t\t\trenderer.clear();\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t}\n\n\t\t// 1. Extract Bright Areas\n\n\t\tthis.highPassUniforms[ 'tDiffuse' ].value = readBuffer.texture;\n\t\tthis.highPassUniforms[ 'luminosityThreshold' ].value = this.threshold;\n\t\tthis.fsQuad.material = this.materialHighPassFilter;\n\n\t\trenderer.setRenderTarget( this.renderTargetBright );\n\t\trenderer.clear();\n\t\tthis.fsQuad.render( renderer );\n\n\t\t// 2. Blur All the mips progressively\n\n\t\tlet inputRenderTarget = this.renderTargetBright;\n\n\t\tfor ( let i = 0; i < this.nMips; i ++ ) {\n\n\t\t\tthis.fsQuad.material = this.separableBlurMaterials[ i ];\n\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'colorTexture' ].value = inputRenderTarget.texture;\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'direction' ].value = UnrealBloomPass.BlurDirectionX;\n\t\t\trenderer.setRenderTarget( this.renderTargetsHorizontal[ i ] );\n\t\t\trenderer.clear();\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'colorTexture' ].value = this.renderTargetsHorizontal[ i ].texture;\n\t\t\tthis.separableBlurMaterials[ i ].uniforms[ 'direction' ].value = UnrealBloomPass.BlurDirectionY;\n\t\t\trenderer.setRenderTarget( this.renderTargetsVertical[ i ] );\n\t\t\trenderer.clear();\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t\tinputRenderTarget = this.renderTargetsVertical[ i ];\n\n\t\t}\n\n\t\t// Composite All the mips\n\n\t\tthis.fsQuad.material = this.compositeMaterial;\n\t\tthis.compositeMaterial.uniforms[ 'bloomStrength' ].value = this.strength;\n\t\tthis.compositeMaterial.uniforms[ 'bloomRadius' ].value = this.radius;\n\t\tthis.compositeMaterial.uniforms[ 'bloomTintColors' ].value = this.bloomTintColors;\n\n\t\trenderer.setRenderTarget( this.renderTargetsHorizontal[ 0 ] );\n\t\trenderer.clear();\n\t\tthis.fsQuad.render( renderer );\n\n\t\t// Blend it additively over the input texture\n\n\t\tthis.fsQuad.material = this.blendMaterial;\n\t\tthis.copyUniforms[ 'tDiffuse' ].value = this.renderTargetsHorizontal[ 0 ].texture;\n\n\t\tif ( maskActive ) renderer.state.buffers.stencil.setTest( true );\n\n\t\tif ( this.renderToScreen ) {\n\n\t\t\trenderer.setRenderTarget( null );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t} else {\n\n\t\t\trenderer.setRenderTarget( readBuffer );\n\t\t\tthis.fsQuad.render( renderer );\n\n\t\t}\n\n\t\t// Restore renderer settings\n\n\t\trenderer.setClearColor( this._oldClearColor, this.oldClearAlpha );\n\t\trenderer.autoClear = oldAutoClear;\n\n\t}\n\n\tgetSeperableBlurMaterial( kernelRadius ) {\n\n\t\tconst coefficients = [];\n\n\t\tfor ( let i = 0; i < kernelRadius; i ++ ) {\n\n\t\t\tcoefficients.push( 0.39894 * Math.exp( - 0.5 * i * i / ( kernelRadius * kernelRadius ) ) / kernelRadius );\n\n\t\t}\n\n\t\treturn new three_module/* ShaderMaterial */.BKk( {\n\n\t\t\tdefines: {\n\t\t\t\t'KERNEL_RADIUS': kernelRadius\n\t\t\t},\n\n\t\t\tuniforms: {\n\t\t\t\t'colorTexture': { value: null },\n\t\t\t\t'invSize': { value: new three_module/* Vector2 */.I9Y( 0.5, 0.5 ) }, // inverse texture size\n\t\t\t\t'direction': { value: new three_module/* Vector2 */.I9Y( 0.5, 0.5 ) },\n\t\t\t\t'gaussianCoefficients': { value: coefficients } // precomputed Gaussian coefficients\n\t\t\t},\n\n\t\t\tvertexShader:\n\t\t\t\t`varying vec2 vUv;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvUv = uv;\n\t\t\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\t\t\t\t}`,\n\n\t\t\tfragmentShader:\n\t\t\t\t`#include \n\t\t\t\tvarying vec2 vUv;\n\t\t\t\tuniform sampler2D colorTexture;\n\t\t\t\tuniform vec2 invSize;\n\t\t\t\tuniform vec2 direction;\n\t\t\t\tuniform float gaussianCoefficients[KERNEL_RADIUS];\n\n\t\t\t\tvoid main() {\n\t\t\t\t\tfloat weightSum = gaussianCoefficients[0];\n\t\t\t\t\tvec3 diffuseSum = texture2D( colorTexture, vUv ).rgb * weightSum;\n\t\t\t\t\tfor( int i = 1; i < KERNEL_RADIUS; i ++ ) {\n\t\t\t\t\t\tfloat x = float(i);\n\t\t\t\t\t\tfloat w = gaussianCoefficients[i];\n\t\t\t\t\t\tvec2 uvOffset = direction * invSize * x;\n\t\t\t\t\t\tvec3 sample1 = texture2D( colorTexture, vUv + uvOffset ).rgb;\n\t\t\t\t\t\tvec3 sample2 = texture2D( colorTexture, vUv - uvOffset ).rgb;\n\t\t\t\t\t\tdiffuseSum += (sample1 + sample2) * w;\n\t\t\t\t\t\tweightSum += 2.0 * w;\n\t\t\t\t\t}\n\t\t\t\t\tgl_FragColor = vec4(diffuseSum/weightSum, 1.0);\n\t\t\t\t}`\n\t\t} );\n\n\t}\n\n\tgetCompositeMaterial( nMips ) {\n\n\t\treturn new three_module/* ShaderMaterial */.BKk( {\n\n\t\t\tdefines: {\n\t\t\t\t'NUM_MIPS': nMips\n\t\t\t},\n\n\t\t\tuniforms: {\n\t\t\t\t'blurTexture1': { value: null },\n\t\t\t\t'blurTexture2': { value: null },\n\t\t\t\t'blurTexture3': { value: null },\n\t\t\t\t'blurTexture4': { value: null },\n\t\t\t\t'blurTexture5': { value: null },\n\t\t\t\t'bloomStrength': { value: 1.0 },\n\t\t\t\t'bloomFactors': { value: null },\n\t\t\t\t'bloomTintColors': { value: null },\n\t\t\t\t'bloomRadius': { value: 0.0 }\n\t\t\t},\n\n\t\t\tvertexShader:\n\t\t\t\t`varying vec2 vUv;\n\t\t\t\tvoid main() {\n\t\t\t\t\tvUv = uv;\n\t\t\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\t\t\t\t}`,\n\n\t\t\tfragmentShader:\n\t\t\t\t`varying vec2 vUv;\n\t\t\t\tuniform sampler2D blurTexture1;\n\t\t\t\tuniform sampler2D blurTexture2;\n\t\t\t\tuniform sampler2D blurTexture3;\n\t\t\t\tuniform sampler2D blurTexture4;\n\t\t\t\tuniform sampler2D blurTexture5;\n\t\t\t\tuniform float bloomStrength;\n\t\t\t\tuniform float bloomRadius;\n\t\t\t\tuniform float bloomFactors[NUM_MIPS];\n\t\t\t\tuniform vec3 bloomTintColors[NUM_MIPS];\n\n\t\t\t\tfloat lerpBloomFactor(const in float factor) {\n\t\t\t\t\tfloat mirrorFactor = 1.2 - factor;\n\t\t\t\t\treturn mix(factor, mirrorFactor, bloomRadius);\n\t\t\t\t}\n\n\t\t\t\tvoid main() {\n\t\t\t\t\tgl_FragColor = bloomStrength * ( lerpBloomFactor(bloomFactors[0]) * vec4(bloomTintColors[0], 1.0) * texture2D(blurTexture1, vUv) +\n\t\t\t\t\t\tlerpBloomFactor(bloomFactors[1]) * vec4(bloomTintColors[1], 1.0) * texture2D(blurTexture2, vUv) +\n\t\t\t\t\t\tlerpBloomFactor(bloomFactors[2]) * vec4(bloomTintColors[2], 1.0) * texture2D(blurTexture3, vUv) +\n\t\t\t\t\t\tlerpBloomFactor(bloomFactors[3]) * vec4(bloomTintColors[3], 1.0) * texture2D(blurTexture4, vUv) +\n\t\t\t\t\t\tlerpBloomFactor(bloomFactors[4]) * vec4(bloomTintColors[4], 1.0) * texture2D(blurTexture5, vUv) );\n\t\t\t\t}`\n\t\t} );\n\n\t}\n\n}\n\nUnrealBloomPass.BlurDirectionX = new three_module/* Vector2 */.I9Y( 1.0, 0.0 );\nUnrealBloomPass.BlurDirectionY = new three_module/* Vector2 */.I9Y( 0.0, 1.0 );\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMjA4LmpzIiwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7QUFFZTs7QUFFZjtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxnQkFBZ0IsYUFBYTtBQUM3QiwyQkFBMkIsWUFBWTtBQUN2QyxtQkFBbUIsWUFBWTtBQUMvQixvQkFBb0IsV0FBVywyQkFBSyxjQUFjO0FBQ2xELHNCQUFzQjs7QUFFdEIsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsR0FBRzs7QUFFSDs7QUFFb0M7OztBQ3JEckI7QUFDa0M7QUFDSztBQUM0Qjs7QUFFbEY7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsOEJBQThCLGdCQUFJOztBQUVsQzs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQSx1REFBdUQsNkJBQU8scUNBQXFDLDZCQUFPOztBQUUxRztBQUNBLHdCQUF3QiwyQkFBSzs7QUFFN0I7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBLGdDQUFnQyx1Q0FBaUIsZ0JBQWdCLE1BQU0sbUNBQWEsR0FBRztBQUN2RjtBQUNBOztBQUVBLG1CQUFtQixnQkFBZ0I7O0FBRW5DLHNDQUFzQyx1Q0FBaUIsZ0JBQWdCLE1BQU0sbUNBQWEsR0FBRzs7QUFFN0Y7QUFDQTs7QUFFQTs7QUFFQSxvQ0FBb0MsdUNBQWlCLGdCQUFnQixNQUFNLG1DQUFhLEdBQUc7O0FBRTNGO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEseUJBQXlCLHdCQUF3QjtBQUNqRCwwQkFBMEIsbUNBQWE7O0FBRXZDO0FBQ0E7O0FBRUEsb0NBQW9DLG9DQUFjO0FBQ2xEO0FBQ0E7QUFDQTtBQUNBLElBQUk7O0FBRUo7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUEsbUJBQW1CLGdCQUFnQjs7QUFFbkM7O0FBRUEsc0VBQXNFLDZCQUFPOztBQUU3RTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSwrQkFBK0IsNkJBQU8saUJBQWlCLDZCQUFPLGlCQUFpQiw2QkFBTyxpQkFBaUIsNkJBQU8saUJBQWlCLDZCQUFPO0FBQ3RJOztBQUVBOztBQUVBLHFCQUFxQiw0QkFBVTs7QUFFL0Isc0JBQXNCLG1DQUFhOztBQUVuQywyQkFBMkIsb0NBQWM7QUFDekM7QUFDQTtBQUNBO0FBQ0EsYUFBYSxzQ0FBZ0I7QUFDN0I7QUFDQTtBQUNBO0FBQ0EsSUFBSTs7QUFFSjtBQUNBOztBQUVBLDRCQUE0QiwyQkFBSztBQUNqQzs7QUFFQSxtQkFBbUIsdUNBQWlCOztBQUVwQyxvQkFBb0IsMEJBQWM7O0FBRWxDOztBQUVBOztBQUVBLG1CQUFtQix5Q0FBeUM7O0FBRTVEOztBQUVBOztBQUVBLG1CQUFtQix1Q0FBdUM7O0FBRTFEOztBQUVBOztBQUVBOztBQUVBOztBQUVBLG1CQUFtQix3Q0FBd0M7O0FBRTNEOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBLG1CQUFtQixnQkFBZ0I7O0FBRW5DO0FBQ0E7O0FBRUEsc0VBQXNFLDZCQUFPOztBQUU3RTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGdCQUFnQjs7QUFFbkM7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUEsSUFBSTs7QUFFSjtBQUNBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRUE7O0FBRUE7O0FBRUEsbUJBQW1CLGtCQUFrQjs7QUFFckM7O0FBRUE7O0FBRUEsYUFBYSxvQ0FBYzs7QUFFM0I7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQSxzQkFBc0IsYUFBYTtBQUNuQyxpQkFBaUIsV0FBVyw2QkFBTyxjQUFjO0FBQ2pELG1CQUFtQixXQUFXLDZCQUFPLGNBQWM7QUFDbkQsOEJBQThCLHNCQUFzQjtBQUNwRCxJQUFJOztBQUVKO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQSxLQUFLOztBQUVMO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBLHFCQUFxQixtQkFBbUI7QUFDeEM7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSztBQUNMLElBQUk7O0FBRUo7O0FBRUE7O0FBRUEsYUFBYSxvQ0FBYzs7QUFFM0I7QUFDQTtBQUNBLElBQUk7O0FBRUo7QUFDQSxzQkFBc0IsYUFBYTtBQUNuQyxzQkFBc0IsYUFBYTtBQUNuQyxzQkFBc0IsYUFBYTtBQUNuQyxzQkFBc0IsYUFBYTtBQUNuQyxzQkFBc0IsYUFBYTtBQUNuQyx1QkFBdUIsWUFBWTtBQUNuQyxzQkFBc0IsYUFBYTtBQUNuQyx5QkFBeUIsYUFBYTtBQUN0QyxxQkFBcUI7QUFDckIsSUFBSTs7QUFFSjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsS0FBSzs7QUFFTDtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBLEtBQUs7QUFDTCxJQUFJOztBQUVKOztBQUVBOztBQUVBLHFDQUFxQyw2QkFBTztBQUM1QyxxQ0FBcUMsNkJBQU87O0FBRWpCIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy90aHJlZS9leGFtcGxlcy9qc20vc2hhZGVycy9MdW1pbm9zaXR5SGlnaFBhc3NTaGFkZXIuanM/NzhiYSIsIndlYnBhY2s6Ly90aHJlZWpzLXBvc3Rwcm9jZXNzLy4vbm9kZV9tb2R1bGVzL3RocmVlL2V4YW1wbGVzL2pzbS9wb3N0cHJvY2Vzc2luZy9VbnJlYWxCbG9vbVBhc3MuanM/YTJiMSJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuXHRDb2xvclxufSBmcm9tICd0aHJlZSc7XG5cbi8qKlxuICogTHVtaW5vc2l0eVxuICogaHR0cDovL2VuLndpa2lwZWRpYS5vcmcvd2lraS9MdW1pbm9zaXR5XG4gKi9cblxuY29uc3QgTHVtaW5vc2l0eUhpZ2hQYXNzU2hhZGVyID0ge1xuXG5cdG5hbWU6ICdMdW1pbm9zaXR5SGlnaFBhc3NTaGFkZXInLFxuXG5cdHNoYWRlcklEOiAnbHVtaW5vc2l0eUhpZ2hQYXNzJyxcblxuXHR1bmlmb3Jtczoge1xuXG5cdFx0J3REaWZmdXNlJzogeyB2YWx1ZTogbnVsbCB9LFxuXHRcdCdsdW1pbm9zaXR5VGhyZXNob2xkJzogeyB2YWx1ZTogMS4wIH0sXG5cdFx0J3Ntb290aFdpZHRoJzogeyB2YWx1ZTogMS4wIH0sXG5cdFx0J2RlZmF1bHRDb2xvcic6IHsgdmFsdWU6IG5ldyBDb2xvciggMHgwMDAwMDAgKSB9LFxuXHRcdCdkZWZhdWx0T3BhY2l0eSc6IHsgdmFsdWU6IDAuMCB9XG5cblx0fSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR2YXJ5aW5nIHZlYzIgdlV2O1xuXG5cdFx0dm9pZCBtYWluKCkge1xuXG5cdFx0XHR2VXYgPSB1djtcblxuXHRcdFx0Z2xfUG9zaXRpb24gPSBwcm9qZWN0aW9uTWF0cml4ICogbW9kZWxWaWV3TWF0cml4ICogdmVjNCggcG9zaXRpb24sIDEuMCApO1xuXG5cdFx0fWAsXG5cblx0ZnJhZ21lbnRTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR1bmlmb3JtIHNhbXBsZXIyRCB0RGlmZnVzZTtcblx0XHR1bmlmb3JtIHZlYzMgZGVmYXVsdENvbG9yO1xuXHRcdHVuaWZvcm0gZmxvYXQgZGVmYXVsdE9wYWNpdHk7XG5cdFx0dW5pZm9ybSBmbG9hdCBsdW1pbm9zaXR5VGhyZXNob2xkO1xuXHRcdHVuaWZvcm0gZmxvYXQgc21vb3RoV2lkdGg7XG5cblx0XHR2YXJ5aW5nIHZlYzIgdlV2O1xuXG5cdFx0dm9pZCBtYWluKCkge1xuXG5cdFx0XHR2ZWM0IHRleGVsID0gdGV4dHVyZTJEKCB0RGlmZnVzZSwgdlV2ICk7XG5cblx0XHRcdGZsb2F0IHYgPSBsdW1pbmFuY2UoIHRleGVsLnh5eiApO1xuXG5cdFx0XHR2ZWM0IG91dHB1dENvbG9yID0gdmVjNCggZGVmYXVsdENvbG9yLnJnYiwgZGVmYXVsdE9wYWNpdHkgKTtcblxuXHRcdFx0ZmxvYXQgYWxwaGEgPSBzbW9vdGhzdGVwKCBsdW1pbm9zaXR5VGhyZXNob2xkLCBsdW1pbm9zaXR5VGhyZXNob2xkICsgc21vb3RoV2lkdGgsIHYgKTtcblxuXHRcdFx0Z2xfRnJhZ0NvbG9yID0gbWl4KCBvdXRwdXRDb2xvciwgdGV4ZWwsIGFscGhhICk7XG5cblx0XHR9YFxuXG59O1xuXG5leHBvcnQgeyBMdW1pbm9zaXR5SGlnaFBhc3NTaGFkZXIgfTtcbiIsImltcG9ydCB7XG5cdEFkZGl0aXZlQmxlbmRpbmcsXG5cdENvbG9yLFxuXHRIYWxmRmxvYXRUeXBlLFxuXHRNZXNoQmFzaWNNYXRlcmlhbCxcblx0U2hhZGVyTWF0ZXJpYWwsXG5cdFVuaWZvcm1zVXRpbHMsXG5cdFZlY3RvcjIsXG5cdFZlY3RvcjMsXG5cdFdlYkdMUmVuZGVyVGFyZ2V0XG59IGZyb20gJ3RocmVlJztcbmltcG9ydCB7IFBhc3MsIEZ1bGxTY3JlZW5RdWFkIH0gZnJvbSAnLi9QYXNzLmpzJztcbmltcG9ydCB7IENvcHlTaGFkZXIgfSBmcm9tICcuLi9zaGFkZXJzL0NvcHlTaGFkZXIuanMnO1xuaW1wb3J0IHsgTHVtaW5vc2l0eUhpZ2hQYXNzU2hhZGVyIH0gZnJvbSAnLi4vc2hhZGVycy9MdW1pbm9zaXR5SGlnaFBhc3NTaGFkZXIuanMnO1xuXG4vKipcbiAqIFVucmVhbEJsb29tUGFzcyBpcyBpbnNwaXJlZCBieSB0aGUgYmxvb20gcGFzcyBvZiBVbnJlYWwgRW5naW5lLiBJdCBjcmVhdGVzIGFcbiAqIG1pcCBtYXAgY2hhaW4gb2YgYmxvb20gdGV4dHVyZXMgYW5kIGJsdXJzIHRoZW0gd2l0aCBkaWZmZXJlbnQgcmFkaWkuIEJlY2F1c2VcbiAqIG9mIHRoZSB3ZWlnaHRlZCBjb21iaW5hdGlvbiBvZiBtaXBzLCBhbmQgYmVjYXVzZSBsYXJnZXIgYmx1cnMgYXJlIGRvbmUgb25cbiAqIGhpZ2hlciBtaXBzLCB0aGlzIGVmZmVjdCBwcm92aWRlcyBnb29kIHF1YWxpdHkgYW5kIHBlcmZvcm1hbmNlLlxuICpcbiAqIFJlZmVyZW5jZTpcbiAqIC0gaHR0cHM6Ly9kb2NzLnVucmVhbGVuZ2luZS5jb20vbGF0ZXN0L0lOVC9FbmdpbmUvUmVuZGVyaW5nL1Bvc3RQcm9jZXNzRWZmZWN0cy9CbG9vbS9cbiAqL1xuY2xhc3MgVW5yZWFsQmxvb21QYXNzIGV4dGVuZHMgUGFzcyB7XG5cblx0Y29uc3RydWN0b3IoIHJlc29sdXRpb24sIHN0cmVuZ3RoLCByYWRpdXMsIHRocmVzaG9sZCApIHtcblxuXHRcdHN1cGVyKCk7XG5cblx0XHR0aGlzLnN0cmVuZ3RoID0gKCBzdHJlbmd0aCAhPT0gdW5kZWZpbmVkICkgPyBzdHJlbmd0aCA6IDE7XG5cdFx0dGhpcy5yYWRpdXMgPSByYWRpdXM7XG5cdFx0dGhpcy50aHJlc2hvbGQgPSB0aHJlc2hvbGQ7XG5cdFx0dGhpcy5yZXNvbHV0aW9uID0gKCByZXNvbHV0aW9uICE9PSB1bmRlZmluZWQgKSA/IG5ldyBWZWN0b3IyKCByZXNvbHV0aW9uLngsIHJlc29sdXRpb24ueSApIDogbmV3IFZlY3RvcjIoIDI1NiwgMjU2ICk7XG5cblx0XHQvLyBjcmVhdGUgY29sb3Igb25seSBvbmNlIGhlcmUsIHJldXNlIGl0IGxhdGVyIGluc2lkZSB0aGUgcmVuZGVyIGZ1bmN0aW9uXG5cdFx0dGhpcy5jbGVhckNvbG9yID0gbmV3IENvbG9yKCAwLCAwLCAwICk7XG5cblx0XHQvLyByZW5kZXIgdGFyZ2V0c1xuXHRcdHRoaXMucmVuZGVyVGFyZ2V0c0hvcml6b250YWwgPSBbXTtcblx0XHR0aGlzLnJlbmRlclRhcmdldHNWZXJ0aWNhbCA9IFtdO1xuXHRcdHRoaXMubk1pcHMgPSA1O1xuXHRcdGxldCByZXN4ID0gTWF0aC5yb3VuZCggdGhpcy5yZXNvbHV0aW9uLnggLyAyICk7XG5cdFx0bGV0IHJlc3kgPSBNYXRoLnJvdW5kKCB0aGlzLnJlc29sdXRpb24ueSAvIDIgKTtcblxuXHRcdHRoaXMucmVuZGVyVGFyZ2V0QnJpZ2h0ID0gbmV3IFdlYkdMUmVuZGVyVGFyZ2V0KCByZXN4LCByZXN5LCB7IHR5cGU6IEhhbGZGbG9hdFR5cGUgfSApO1xuXHRcdHRoaXMucmVuZGVyVGFyZ2V0QnJpZ2h0LnRleHR1cmUubmFtZSA9ICdVbnJlYWxCbG9vbVBhc3MuYnJpZ2h0Jztcblx0XHR0aGlzLnJlbmRlclRhcmdldEJyaWdodC50ZXh0dXJlLmdlbmVyYXRlTWlwbWFwcyA9IGZhbHNlO1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy5uTWlwczsgaSArKyApIHtcblxuXHRcdFx0Y29uc3QgcmVuZGVyVGFyZ2V0SG9yaXpvbnRhbCA9IG5ldyBXZWJHTFJlbmRlclRhcmdldCggcmVzeCwgcmVzeSwgeyB0eXBlOiBIYWxmRmxvYXRUeXBlIH0gKTtcblxuXHRcdFx0cmVuZGVyVGFyZ2V0SG9yaXpvbnRhbC50ZXh0dXJlLm5hbWUgPSAnVW5yZWFsQmxvb21QYXNzLmgnICsgaTtcblx0XHRcdHJlbmRlclRhcmdldEhvcml6b250YWwudGV4dHVyZS5nZW5lcmF0ZU1pcG1hcHMgPSBmYWxzZTtcblxuXHRcdFx0dGhpcy5yZW5kZXJUYXJnZXRzSG9yaXpvbnRhbC5wdXNoKCByZW5kZXJUYXJnZXRIb3Jpem9udGFsICk7XG5cblx0XHRcdGNvbnN0IHJlbmRlclRhcmdldFZlcnRpY2FsID0gbmV3IFdlYkdMUmVuZGVyVGFyZ2V0KCByZXN4LCByZXN5LCB7IHR5cGU6IEhhbGZGbG9hdFR5cGUgfSApO1xuXG5cdFx0XHRyZW5kZXJUYXJnZXRWZXJ0aWNhbC50ZXh0dXJlLm5hbWUgPSAnVW5yZWFsQmxvb21QYXNzLnYnICsgaTtcblx0XHRcdHJlbmRlclRhcmdldFZlcnRpY2FsLnRleHR1cmUuZ2VuZXJhdGVNaXBtYXBzID0gZmFsc2U7XG5cblx0XHRcdHRoaXMucmVuZGVyVGFyZ2V0c1ZlcnRpY2FsLnB1c2goIHJlbmRlclRhcmdldFZlcnRpY2FsICk7XG5cblx0XHRcdHJlc3ggPSBNYXRoLnJvdW5kKCByZXN4IC8gMiApO1xuXG5cdFx0XHRyZXN5ID0gTWF0aC5yb3VuZCggcmVzeSAvIDIgKTtcblxuXHRcdH1cblxuXHRcdC8vIGx1bWlub3NpdHkgaGlnaCBwYXNzIG1hdGVyaWFsXG5cblx0XHRjb25zdCBoaWdoUGFzc1NoYWRlciA9IEx1bWlub3NpdHlIaWdoUGFzc1NoYWRlcjtcblx0XHR0aGlzLmhpZ2hQYXNzVW5pZm9ybXMgPSBVbmlmb3Jtc1V0aWxzLmNsb25lKCBoaWdoUGFzc1NoYWRlci51bmlmb3JtcyApO1xuXG5cdFx0dGhpcy5oaWdoUGFzc1VuaWZvcm1zWyAnbHVtaW5vc2l0eVRocmVzaG9sZCcgXS52YWx1ZSA9IHRocmVzaG9sZDtcblx0XHR0aGlzLmhpZ2hQYXNzVW5pZm9ybXNbICdzbW9vdGhXaWR0aCcgXS52YWx1ZSA9IDAuMDE7XG5cblx0XHR0aGlzLm1hdGVyaWFsSGlnaFBhc3NGaWx0ZXIgPSBuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcblx0XHRcdHVuaWZvcm1zOiB0aGlzLmhpZ2hQYXNzVW5pZm9ybXMsXG5cdFx0XHR2ZXJ0ZXhTaGFkZXI6IGhpZ2hQYXNzU2hhZGVyLnZlcnRleFNoYWRlcixcblx0XHRcdGZyYWdtZW50U2hhZGVyOiBoaWdoUGFzc1NoYWRlci5mcmFnbWVudFNoYWRlclxuXHRcdH0gKTtcblxuXHRcdC8vIGdhdXNzaWFuIGJsdXIgbWF0ZXJpYWxzXG5cblx0XHR0aGlzLnNlcGFyYWJsZUJsdXJNYXRlcmlhbHMgPSBbXTtcblx0XHRjb25zdCBrZXJuZWxTaXplQXJyYXkgPSBbIDMsIDUsIDcsIDksIDExIF07XG5cdFx0cmVzeCA9IE1hdGgucm91bmQoIHRoaXMucmVzb2x1dGlvbi54IC8gMiApO1xuXHRcdHJlc3kgPSBNYXRoLnJvdW5kKCB0aGlzLnJlc29sdXRpb24ueSAvIDIgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMubk1pcHM7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuc2VwYXJhYmxlQmx1ck1hdGVyaWFscy5wdXNoKCB0aGlzLmdldFNlcGVyYWJsZUJsdXJNYXRlcmlhbCgga2VybmVsU2l6ZUFycmF5WyBpIF0gKSApO1xuXG5cdFx0XHR0aGlzLnNlcGFyYWJsZUJsdXJNYXRlcmlhbHNbIGkgXS51bmlmb3Jtc1sgJ2ludlNpemUnIF0udmFsdWUgPSBuZXcgVmVjdG9yMiggMSAvIHJlc3gsIDEgLyByZXN5ICk7XG5cblx0XHRcdHJlc3ggPSBNYXRoLnJvdW5kKCByZXN4IC8gMiApO1xuXG5cdFx0XHRyZXN5ID0gTWF0aC5yb3VuZCggcmVzeSAvIDIgKTtcblxuXHRcdH1cblxuXHRcdC8vIGNvbXBvc2l0ZSBtYXRlcmlhbFxuXG5cdFx0dGhpcy5jb21wb3NpdGVNYXRlcmlhbCA9IHRoaXMuZ2V0Q29tcG9zaXRlTWF0ZXJpYWwoIHRoaXMubk1pcHMgKTtcblx0XHR0aGlzLmNvbXBvc2l0ZU1hdGVyaWFsLnVuaWZvcm1zWyAnYmx1clRleHR1cmUxJyBdLnZhbHVlID0gdGhpcy5yZW5kZXJUYXJnZXRzVmVydGljYWxbIDAgXS50ZXh0dXJlO1xuXHRcdHRoaXMuY29tcG9zaXRlTWF0ZXJpYWwudW5pZm9ybXNbICdibHVyVGV4dHVyZTInIF0udmFsdWUgPSB0aGlzLnJlbmRlclRhcmdldHNWZXJ0aWNhbFsgMSBdLnRleHR1cmU7XG5cdFx0dGhpcy5jb21wb3NpdGVNYXRlcmlhbC51bmlmb3Jtc1sgJ2JsdXJUZXh0dXJlMycgXS52YWx1ZSA9IHRoaXMucmVuZGVyVGFyZ2V0c1ZlcnRpY2FsWyAyIF0udGV4dHVyZTtcblx0XHR0aGlzLmNvbXBvc2l0ZU1hdGVyaWFsLnVuaWZvcm1zWyAnYmx1clRleHR1cmU0JyBdLnZhbHVlID0gdGhpcy5yZW5kZXJUYXJnZXRzVmVydGljYWxbIDMgXS50ZXh0dXJlO1xuXHRcdHRoaXMuY29tcG9zaXRlTWF0ZXJpYWwudW5pZm9ybXNbICdibHVyVGV4dHVyZTUnIF0udmFsdWUgPSB0aGlzLnJlbmRlclRhcmdldHNWZXJ0aWNhbFsgNCBdLnRleHR1cmU7XG5cdFx0dGhpcy5jb21wb3NpdGVNYXRlcmlhbC51bmlmb3Jtc1sgJ2Jsb29tU3RyZW5ndGgnIF0udmFsdWUgPSBzdHJlbmd0aDtcblx0XHR0aGlzLmNvbXBvc2l0ZU1hdGVyaWFsLnVuaWZvcm1zWyAnYmxvb21SYWRpdXMnIF0udmFsdWUgPSAwLjE7XG5cblx0XHRjb25zdCBibG9vbUZhY3RvcnMgPSBbIDEuMCwgMC44LCAwLjYsIDAuNCwgMC4yIF07XG5cdFx0dGhpcy5jb21wb3NpdGVNYXRlcmlhbC51bmlmb3Jtc1sgJ2Jsb29tRmFjdG9ycycgXS52YWx1ZSA9IGJsb29tRmFjdG9ycztcblx0XHR0aGlzLmJsb29tVGludENvbG9ycyA9IFsgbmV3IFZlY3RvcjMoIDEsIDEsIDEgKSwgbmV3IFZlY3RvcjMoIDEsIDEsIDEgKSwgbmV3IFZlY3RvcjMoIDEsIDEsIDEgKSwgbmV3IFZlY3RvcjMoIDEsIDEsIDEgKSwgbmV3IFZlY3RvcjMoIDEsIDEsIDEgKSBdO1xuXHRcdHRoaXMuY29tcG9zaXRlTWF0ZXJpYWwudW5pZm9ybXNbICdibG9vbVRpbnRDb2xvcnMnIF0udmFsdWUgPSB0aGlzLmJsb29tVGludENvbG9ycztcblxuXHRcdC8vIGJsZW5kIG1hdGVyaWFsXG5cblx0XHRjb25zdCBjb3B5U2hhZGVyID0gQ29weVNoYWRlcjtcblxuXHRcdHRoaXMuY29weVVuaWZvcm1zID0gVW5pZm9ybXNVdGlscy5jbG9uZSggY29weVNoYWRlci51bmlmb3JtcyApO1xuXG5cdFx0dGhpcy5ibGVuZE1hdGVyaWFsID0gbmV3IFNoYWRlck1hdGVyaWFsKCB7XG5cdFx0XHR1bmlmb3JtczogdGhpcy5jb3B5VW5pZm9ybXMsXG5cdFx0XHR2ZXJ0ZXhTaGFkZXI6IGNvcHlTaGFkZXIudmVydGV4U2hhZGVyLFxuXHRcdFx0ZnJhZ21lbnRTaGFkZXI6IGNvcHlTaGFkZXIuZnJhZ21lbnRTaGFkZXIsXG5cdFx0XHRibGVuZGluZzogQWRkaXRpdmVCbGVuZGluZyxcblx0XHRcdGRlcHRoVGVzdDogZmFsc2UsXG5cdFx0XHRkZXB0aFdyaXRlOiBmYWxzZSxcblx0XHRcdHRyYW5zcGFyZW50OiB0cnVlXG5cdFx0fSApO1xuXG5cdFx0dGhpcy5lbmFibGVkID0gdHJ1ZTtcblx0XHR0aGlzLm5lZWRzU3dhcCA9IGZhbHNlO1xuXG5cdFx0dGhpcy5fb2xkQ2xlYXJDb2xvciA9IG5ldyBDb2xvcigpO1xuXHRcdHRoaXMub2xkQ2xlYXJBbHBoYSA9IDE7XG5cblx0XHR0aGlzLmJhc2ljID0gbmV3IE1lc2hCYXNpY01hdGVyaWFsKCk7XG5cblx0XHR0aGlzLmZzUXVhZCA9IG5ldyBGdWxsU2NyZWVuUXVhZCggbnVsbCApO1xuXG5cdH1cblxuXHRkaXNwb3NlKCkge1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy5yZW5kZXJUYXJnZXRzSG9yaXpvbnRhbC5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMucmVuZGVyVGFyZ2V0c0hvcml6b250YWxbIGkgXS5kaXNwb3NlKCk7XG5cblx0XHR9XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCB0aGlzLnJlbmRlclRhcmdldHNWZXJ0aWNhbC5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMucmVuZGVyVGFyZ2V0c1ZlcnRpY2FsWyBpIF0uZGlzcG9zZSgpO1xuXG5cdFx0fVxuXG5cdFx0dGhpcy5yZW5kZXJUYXJnZXRCcmlnaHQuZGlzcG9zZSgpO1xuXG5cdFx0Ly9cblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMuc2VwYXJhYmxlQmx1ck1hdGVyaWFscy5sZW5ndGg7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMuc2VwYXJhYmxlQmx1ck1hdGVyaWFsc1sgaSBdLmRpc3Bvc2UoKTtcblxuXHRcdH1cblxuXHRcdHRoaXMuY29tcG9zaXRlTWF0ZXJpYWwuZGlzcG9zZSgpO1xuXHRcdHRoaXMuYmxlbmRNYXRlcmlhbC5kaXNwb3NlKCk7XG5cdFx0dGhpcy5iYXNpYy5kaXNwb3NlKCk7XG5cblx0XHQvL1xuXG5cdFx0dGhpcy5mc1F1YWQuZGlzcG9zZSgpO1xuXG5cdH1cblxuXHRzZXRTaXplKCB3aWR0aCwgaGVpZ2h0ICkge1xuXG5cdFx0bGV0IHJlc3ggPSBNYXRoLnJvdW5kKCB3aWR0aCAvIDIgKTtcblx0XHRsZXQgcmVzeSA9IE1hdGgucm91bmQoIGhlaWdodCAvIDIgKTtcblxuXHRcdHRoaXMucmVuZGVyVGFyZ2V0QnJpZ2h0LnNldFNpemUoIHJlc3gsIHJlc3kgKTtcblxuXHRcdGZvciAoIGxldCBpID0gMDsgaSA8IHRoaXMubk1pcHM7IGkgKysgKSB7XG5cblx0XHRcdHRoaXMucmVuZGVyVGFyZ2V0c0hvcml6b250YWxbIGkgXS5zZXRTaXplKCByZXN4LCByZXN5ICk7XG5cdFx0XHR0aGlzLnJlbmRlclRhcmdldHNWZXJ0aWNhbFsgaSBdLnNldFNpemUoIHJlc3gsIHJlc3kgKTtcblxuXHRcdFx0dGhpcy5zZXBhcmFibGVCbHVyTWF0ZXJpYWxzWyBpIF0udW5pZm9ybXNbICdpbnZTaXplJyBdLnZhbHVlID0gbmV3IFZlY3RvcjIoIDEgLyByZXN4LCAxIC8gcmVzeSApO1xuXG5cdFx0XHRyZXN4ID0gTWF0aC5yb3VuZCggcmVzeCAvIDIgKTtcblx0XHRcdHJlc3kgPSBNYXRoLnJvdW5kKCByZXN5IC8gMiApO1xuXG5cdFx0fVxuXG5cdH1cblxuXHRyZW5kZXIoIHJlbmRlcmVyLCB3cml0ZUJ1ZmZlciwgcmVhZEJ1ZmZlciwgZGVsdGFUaW1lLCBtYXNrQWN0aXZlICkge1xuXG5cdFx0cmVuZGVyZXIuZ2V0Q2xlYXJDb2xvciggdGhpcy5fb2xkQ2xlYXJDb2xvciApO1xuXHRcdHRoaXMub2xkQ2xlYXJBbHBoYSA9IHJlbmRlcmVyLmdldENsZWFyQWxwaGEoKTtcblx0XHRjb25zdCBvbGRBdXRvQ2xlYXIgPSByZW5kZXJlci5hdXRvQ2xlYXI7XG5cdFx0cmVuZGVyZXIuYXV0b0NsZWFyID0gZmFsc2U7XG5cblx0XHRyZW5kZXJlci5zZXRDbGVhckNvbG9yKCB0aGlzLmNsZWFyQ29sb3IsIDAgKTtcblxuXHRcdGlmICggbWFza0FjdGl2ZSApIHJlbmRlcmVyLnN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRUZXN0KCBmYWxzZSApO1xuXG5cdFx0Ly8gUmVuZGVyIGlucHV0IHRvIHNjcmVlblxuXG5cdFx0aWYgKCB0aGlzLnJlbmRlclRvU2NyZWVuICkge1xuXG5cdFx0XHR0aGlzLmZzUXVhZC5tYXRlcmlhbCA9IHRoaXMuYmFzaWM7XG5cdFx0XHR0aGlzLmJhc2ljLm1hcCA9IHJlYWRCdWZmZXIudGV4dHVyZTtcblxuXHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCBudWxsICk7XG5cdFx0XHRyZW5kZXJlci5jbGVhcigpO1xuXHRcdFx0dGhpcy5mc1F1YWQucmVuZGVyKCByZW5kZXJlciApO1xuXG5cdFx0fVxuXG5cdFx0Ly8gMS4gRXh0cmFjdCBCcmlnaHQgQXJlYXNcblxuXHRcdHRoaXMuaGlnaFBhc3NVbmlmb3Jtc1sgJ3REaWZmdXNlJyBdLnZhbHVlID0gcmVhZEJ1ZmZlci50ZXh0dXJlO1xuXHRcdHRoaXMuaGlnaFBhc3NVbmlmb3Jtc1sgJ2x1bWlub3NpdHlUaHJlc2hvbGQnIF0udmFsdWUgPSB0aGlzLnRocmVzaG9sZDtcblx0XHR0aGlzLmZzUXVhZC5tYXRlcmlhbCA9IHRoaXMubWF0ZXJpYWxIaWdoUGFzc0ZpbHRlcjtcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggdGhpcy5yZW5kZXJUYXJnZXRCcmlnaHQgKTtcblx0XHRyZW5kZXJlci5jbGVhcigpO1xuXHRcdHRoaXMuZnNRdWFkLnJlbmRlciggcmVuZGVyZXIgKTtcblxuXHRcdC8vIDIuIEJsdXIgQWxsIHRoZSBtaXBzIHByb2dyZXNzaXZlbHlcblxuXHRcdGxldCBpbnB1dFJlbmRlclRhcmdldCA9IHRoaXMucmVuZGVyVGFyZ2V0QnJpZ2h0O1xuXG5cdFx0Zm9yICggbGV0IGkgPSAwOyBpIDwgdGhpcy5uTWlwczsgaSArKyApIHtcblxuXHRcdFx0dGhpcy5mc1F1YWQubWF0ZXJpYWwgPSB0aGlzLnNlcGFyYWJsZUJsdXJNYXRlcmlhbHNbIGkgXTtcblxuXHRcdFx0dGhpcy5zZXBhcmFibGVCbHVyTWF0ZXJpYWxzWyBpIF0udW5pZm9ybXNbICdjb2xvclRleHR1cmUnIF0udmFsdWUgPSBpbnB1dFJlbmRlclRhcmdldC50ZXh0dXJlO1xuXHRcdFx0dGhpcy5zZXBhcmFibGVCbHVyTWF0ZXJpYWxzWyBpIF0udW5pZm9ybXNbICdkaXJlY3Rpb24nIF0udmFsdWUgPSBVbnJlYWxCbG9vbVBhc3MuQmx1ckRpcmVjdGlvblg7XG5cdFx0XHRyZW5kZXJlci5zZXRSZW5kZXJUYXJnZXQoIHRoaXMucmVuZGVyVGFyZ2V0c0hvcml6b250YWxbIGkgXSApO1xuXHRcdFx0cmVuZGVyZXIuY2xlYXIoKTtcblx0XHRcdHRoaXMuZnNRdWFkLnJlbmRlciggcmVuZGVyZXIgKTtcblxuXHRcdFx0dGhpcy5zZXBhcmFibGVCbHVyTWF0ZXJpYWxzWyBpIF0udW5pZm9ybXNbICdjb2xvclRleHR1cmUnIF0udmFsdWUgPSB0aGlzLnJlbmRlclRhcmdldHNIb3Jpem9udGFsWyBpIF0udGV4dHVyZTtcblx0XHRcdHRoaXMuc2VwYXJhYmxlQmx1ck1hdGVyaWFsc1sgaSBdLnVuaWZvcm1zWyAnZGlyZWN0aW9uJyBdLnZhbHVlID0gVW5yZWFsQmxvb21QYXNzLkJsdXJEaXJlY3Rpb25ZO1xuXHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCB0aGlzLnJlbmRlclRhcmdldHNWZXJ0aWNhbFsgaSBdICk7XG5cdFx0XHRyZW5kZXJlci5jbGVhcigpO1xuXHRcdFx0dGhpcy5mc1F1YWQucmVuZGVyKCByZW5kZXJlciApO1xuXG5cdFx0XHRpbnB1dFJlbmRlclRhcmdldCA9IHRoaXMucmVuZGVyVGFyZ2V0c1ZlcnRpY2FsWyBpIF07XG5cblx0XHR9XG5cblx0XHQvLyBDb21wb3NpdGUgQWxsIHRoZSBtaXBzXG5cblx0XHR0aGlzLmZzUXVhZC5tYXRlcmlhbCA9IHRoaXMuY29tcG9zaXRlTWF0ZXJpYWw7XG5cdFx0dGhpcy5jb21wb3NpdGVNYXRlcmlhbC51bmlmb3Jtc1sgJ2Jsb29tU3RyZW5ndGgnIF0udmFsdWUgPSB0aGlzLnN0cmVuZ3RoO1xuXHRcdHRoaXMuY29tcG9zaXRlTWF0ZXJpYWwudW5pZm9ybXNbICdibG9vbVJhZGl1cycgXS52YWx1ZSA9IHRoaXMucmFkaXVzO1xuXHRcdHRoaXMuY29tcG9zaXRlTWF0ZXJpYWwudW5pZm9ybXNbICdibG9vbVRpbnRDb2xvcnMnIF0udmFsdWUgPSB0aGlzLmJsb29tVGludENvbG9ycztcblxuXHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggdGhpcy5yZW5kZXJUYXJnZXRzSG9yaXpvbnRhbFsgMCBdICk7XG5cdFx0cmVuZGVyZXIuY2xlYXIoKTtcblx0XHR0aGlzLmZzUXVhZC5yZW5kZXIoIHJlbmRlcmVyICk7XG5cblx0XHQvLyBCbGVuZCBpdCBhZGRpdGl2ZWx5IG92ZXIgdGhlIGlucHV0IHRleHR1cmVcblxuXHRcdHRoaXMuZnNRdWFkLm1hdGVyaWFsID0gdGhpcy5ibGVuZE1hdGVyaWFsO1xuXHRcdHRoaXMuY29weVVuaWZvcm1zWyAndERpZmZ1c2UnIF0udmFsdWUgPSB0aGlzLnJlbmRlclRhcmdldHNIb3Jpem9udGFsWyAwIF0udGV4dHVyZTtcblxuXHRcdGlmICggbWFza0FjdGl2ZSApIHJlbmRlcmVyLnN0YXRlLmJ1ZmZlcnMuc3RlbmNpbC5zZXRUZXN0KCB0cnVlICk7XG5cblx0XHRpZiAoIHRoaXMucmVuZGVyVG9TY3JlZW4gKSB7XG5cblx0XHRcdHJlbmRlcmVyLnNldFJlbmRlclRhcmdldCggbnVsbCApO1xuXHRcdFx0dGhpcy5mc1F1YWQucmVuZGVyKCByZW5kZXJlciApO1xuXG5cdFx0fSBlbHNlIHtcblxuXHRcdFx0cmVuZGVyZXIuc2V0UmVuZGVyVGFyZ2V0KCByZWFkQnVmZmVyICk7XG5cdFx0XHR0aGlzLmZzUXVhZC5yZW5kZXIoIHJlbmRlcmVyICk7XG5cblx0XHR9XG5cblx0XHQvLyBSZXN0b3JlIHJlbmRlcmVyIHNldHRpbmdzXG5cblx0XHRyZW5kZXJlci5zZXRDbGVhckNvbG9yKCB0aGlzLl9vbGRDbGVhckNvbG9yLCB0aGlzLm9sZENsZWFyQWxwaGEgKTtcblx0XHRyZW5kZXJlci5hdXRvQ2xlYXIgPSBvbGRBdXRvQ2xlYXI7XG5cblx0fVxuXG5cdGdldFNlcGVyYWJsZUJsdXJNYXRlcmlhbCgga2VybmVsUmFkaXVzICkge1xuXG5cdFx0Y29uc3QgY29lZmZpY2llbnRzID0gW107XG5cblx0XHRmb3IgKCBsZXQgaSA9IDA7IGkgPCBrZXJuZWxSYWRpdXM7IGkgKysgKSB7XG5cblx0XHRcdGNvZWZmaWNpZW50cy5wdXNoKCAwLjM5ODk0ICogTWF0aC5leHAoIC0gMC41ICogaSAqIGkgLyAoIGtlcm5lbFJhZGl1cyAqIGtlcm5lbFJhZGl1cyApICkgLyBrZXJuZWxSYWRpdXMgKTtcblxuXHRcdH1cblxuXHRcdHJldHVybiBuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcblxuXHRcdFx0ZGVmaW5lczoge1xuXHRcdFx0XHQnS0VSTkVMX1JBRElVUyc6IGtlcm5lbFJhZGl1c1xuXHRcdFx0fSxcblxuXHRcdFx0dW5pZm9ybXM6IHtcblx0XHRcdFx0J2NvbG9yVGV4dHVyZSc6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdFx0J2ludlNpemUnOiB7IHZhbHVlOiBuZXcgVmVjdG9yMiggMC41LCAwLjUgKSB9LCAvLyBpbnZlcnNlIHRleHR1cmUgc2l6ZVxuXHRcdFx0XHQnZGlyZWN0aW9uJzogeyB2YWx1ZTogbmV3IFZlY3RvcjIoIDAuNSwgMC41ICkgfSxcblx0XHRcdFx0J2dhdXNzaWFuQ29lZmZpY2llbnRzJzogeyB2YWx1ZTogY29lZmZpY2llbnRzIH0gLy8gcHJlY29tcHV0ZWQgR2F1c3NpYW4gY29lZmZpY2llbnRzXG5cdFx0XHR9LFxuXG5cdFx0XHR2ZXJ0ZXhTaGFkZXI6XG5cdFx0XHRcdGB2YXJ5aW5nIHZlYzIgdlV2O1xuXHRcdFx0XHR2b2lkIG1haW4oKSB7XG5cdFx0XHRcdFx0dlV2ID0gdXY7XG5cdFx0XHRcdFx0Z2xfUG9zaXRpb24gPSBwcm9qZWN0aW9uTWF0cml4ICogbW9kZWxWaWV3TWF0cml4ICogdmVjNCggcG9zaXRpb24sIDEuMCApO1xuXHRcdFx0XHR9YCxcblxuXHRcdFx0ZnJhZ21lbnRTaGFkZXI6XG5cdFx0XHRcdGAjaW5jbHVkZSA8Y29tbW9uPlxuXHRcdFx0XHR2YXJ5aW5nIHZlYzIgdlV2O1xuXHRcdFx0XHR1bmlmb3JtIHNhbXBsZXIyRCBjb2xvclRleHR1cmU7XG5cdFx0XHRcdHVuaWZvcm0gdmVjMiBpbnZTaXplO1xuXHRcdFx0XHR1bmlmb3JtIHZlYzIgZGlyZWN0aW9uO1xuXHRcdFx0XHR1bmlmb3JtIGZsb2F0IGdhdXNzaWFuQ29lZmZpY2llbnRzW0tFUk5FTF9SQURJVVNdO1xuXG5cdFx0XHRcdHZvaWQgbWFpbigpIHtcblx0XHRcdFx0XHRmbG9hdCB3ZWlnaHRTdW0gPSBnYXVzc2lhbkNvZWZmaWNpZW50c1swXTtcblx0XHRcdFx0XHR2ZWMzIGRpZmZ1c2VTdW0gPSB0ZXh0dXJlMkQoIGNvbG9yVGV4dHVyZSwgdlV2ICkucmdiICogd2VpZ2h0U3VtO1xuXHRcdFx0XHRcdGZvciggaW50IGkgPSAxOyBpIDwgS0VSTkVMX1JBRElVUzsgaSArKyApIHtcblx0XHRcdFx0XHRcdGZsb2F0IHggPSBmbG9hdChpKTtcblx0XHRcdFx0XHRcdGZsb2F0IHcgPSBnYXVzc2lhbkNvZWZmaWNpZW50c1tpXTtcblx0XHRcdFx0XHRcdHZlYzIgdXZPZmZzZXQgPSBkaXJlY3Rpb24gKiBpbnZTaXplICogeDtcblx0XHRcdFx0XHRcdHZlYzMgc2FtcGxlMSA9IHRleHR1cmUyRCggY29sb3JUZXh0dXJlLCB2VXYgKyB1dk9mZnNldCApLnJnYjtcblx0XHRcdFx0XHRcdHZlYzMgc2FtcGxlMiA9IHRleHR1cmUyRCggY29sb3JUZXh0dXJlLCB2VXYgLSB1dk9mZnNldCApLnJnYjtcblx0XHRcdFx0XHRcdGRpZmZ1c2VTdW0gKz0gKHNhbXBsZTEgKyBzYW1wbGUyKSAqIHc7XG5cdFx0XHRcdFx0XHR3ZWlnaHRTdW0gKz0gMi4wICogdztcblx0XHRcdFx0XHR9XG5cdFx0XHRcdFx0Z2xfRnJhZ0NvbG9yID0gdmVjNChkaWZmdXNlU3VtL3dlaWdodFN1bSwgMS4wKTtcblx0XHRcdFx0fWBcblx0XHR9ICk7XG5cblx0fVxuXG5cdGdldENvbXBvc2l0ZU1hdGVyaWFsKCBuTWlwcyApIHtcblxuXHRcdHJldHVybiBuZXcgU2hhZGVyTWF0ZXJpYWwoIHtcblxuXHRcdFx0ZGVmaW5lczoge1xuXHRcdFx0XHQnTlVNX01JUFMnOiBuTWlwc1xuXHRcdFx0fSxcblxuXHRcdFx0dW5pZm9ybXM6IHtcblx0XHRcdFx0J2JsdXJUZXh0dXJlMSc6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdFx0J2JsdXJUZXh0dXJlMic6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdFx0J2JsdXJUZXh0dXJlMyc6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdFx0J2JsdXJUZXh0dXJlNCc6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdFx0J2JsdXJUZXh0dXJlNSc6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdFx0J2Jsb29tU3RyZW5ndGgnOiB7IHZhbHVlOiAxLjAgfSxcblx0XHRcdFx0J2Jsb29tRmFjdG9ycyc6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdFx0J2Jsb29tVGludENvbG9ycyc6IHsgdmFsdWU6IG51bGwgfSxcblx0XHRcdFx0J2Jsb29tUmFkaXVzJzogeyB2YWx1ZTogMC4wIH1cblx0XHRcdH0sXG5cblx0XHRcdHZlcnRleFNoYWRlcjpcblx0XHRcdFx0YHZhcnlpbmcgdmVjMiB2VXY7XG5cdFx0XHRcdHZvaWQgbWFpbigpIHtcblx0XHRcdFx0XHR2VXYgPSB1djtcblx0XHRcdFx0XHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XG5cdFx0XHRcdH1gLFxuXG5cdFx0XHRmcmFnbWVudFNoYWRlcjpcblx0XHRcdFx0YHZhcnlpbmcgdmVjMiB2VXY7XG5cdFx0XHRcdHVuaWZvcm0gc2FtcGxlcjJEIGJsdXJUZXh0dXJlMTtcblx0XHRcdFx0dW5pZm9ybSBzYW1wbGVyMkQgYmx1clRleHR1cmUyO1xuXHRcdFx0XHR1bmlmb3JtIHNhbXBsZXIyRCBibHVyVGV4dHVyZTM7XG5cdFx0XHRcdHVuaWZvcm0gc2FtcGxlcjJEIGJsdXJUZXh0dXJlNDtcblx0XHRcdFx0dW5pZm9ybSBzYW1wbGVyMkQgYmx1clRleHR1cmU1O1xuXHRcdFx0XHR1bmlmb3JtIGZsb2F0IGJsb29tU3RyZW5ndGg7XG5cdFx0XHRcdHVuaWZvcm0gZmxvYXQgYmxvb21SYWRpdXM7XG5cdFx0XHRcdHVuaWZvcm0gZmxvYXQgYmxvb21GYWN0b3JzW05VTV9NSVBTXTtcblx0XHRcdFx0dW5pZm9ybSB2ZWMzIGJsb29tVGludENvbG9yc1tOVU1fTUlQU107XG5cblx0XHRcdFx0ZmxvYXQgbGVycEJsb29tRmFjdG9yKGNvbnN0IGluIGZsb2F0IGZhY3Rvcikge1xuXHRcdFx0XHRcdGZsb2F0IG1pcnJvckZhY3RvciA9IDEuMiAtIGZhY3Rvcjtcblx0XHRcdFx0XHRyZXR1cm4gbWl4KGZhY3RvciwgbWlycm9yRmFjdG9yLCBibG9vbVJhZGl1cyk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHR2b2lkIG1haW4oKSB7XG5cdFx0XHRcdFx0Z2xfRnJhZ0NvbG9yID0gYmxvb21TdHJlbmd0aCAqICggbGVycEJsb29tRmFjdG9yKGJsb29tRmFjdG9yc1swXSkgKiB2ZWM0KGJsb29tVGludENvbG9yc1swXSwgMS4wKSAqIHRleHR1cmUyRChibHVyVGV4dHVyZTEsIHZVdikgK1xuXHRcdFx0XHRcdFx0bGVycEJsb29tRmFjdG9yKGJsb29tRmFjdG9yc1sxXSkgKiB2ZWM0KGJsb29tVGludENvbG9yc1sxXSwgMS4wKSAqIHRleHR1cmUyRChibHVyVGV4dHVyZTIsIHZVdikgK1xuXHRcdFx0XHRcdFx0bGVycEJsb29tRmFjdG9yKGJsb29tRmFjdG9yc1syXSkgKiB2ZWM0KGJsb29tVGludENvbG9yc1syXSwgMS4wKSAqIHRleHR1cmUyRChibHVyVGV4dHVyZTMsIHZVdikgK1xuXHRcdFx0XHRcdFx0bGVycEJsb29tRmFjdG9yKGJsb29tRmFjdG9yc1szXSkgKiB2ZWM0KGJsb29tVGludENvbG9yc1szXSwgMS4wKSAqIHRleHR1cmUyRChibHVyVGV4dHVyZTQsIHZVdikgK1xuXHRcdFx0XHRcdFx0bGVycEJsb29tRmFjdG9yKGJsb29tRmFjdG9yc1s0XSkgKiB2ZWM0KGJsb29tVGludENvbG9yc1s0XSwgMS4wKSAqIHRleHR1cmUyRChibHVyVGV4dHVyZTUsIHZVdikgKTtcblx0XHRcdFx0fWBcblx0XHR9ICk7XG5cblx0fVxuXG59XG5cblVucmVhbEJsb29tUGFzcy5CbHVyRGlyZWN0aW9uWCA9IG5ldyBWZWN0b3IyKCAxLjAsIDAuMCApO1xuVW5yZWFsQmxvb21QYXNzLkJsdXJEaXJlY3Rpb25ZID0gbmV3IFZlY3RvcjIoIDAuMCwgMS4wICk7XG5cbmV4cG9ydCB7IFVucmVhbEJsb29tUGFzcyB9O1xuIl0sIm5hbWVzIjpbXSwic291cmNlUm9vdCI6IiJ9\n//# sourceURL=webpack-internal:///208\n")},364:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ Z: () => (/* binding */ CopyShader)\n/* harmony export */ });\n/**\n * Full-screen textured quad shader\n */\n\nconst CopyShader = {\n\n\tname: 'CopyShader',\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'opacity': { value: 1.0 }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\n\t\tuniform float opacity;\n\n\t\tuniform sampler2D tDiffuse;\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvec4 texel = texture2D( tDiffuse, vUv );\n\t\t\tgl_FragColor = opacity * texel;\n\n\n\t\t}`\n\n};\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMzY0LmpzIiwibWFwcGluZ3MiOiI7OztBQUFBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxnQkFBZ0IsYUFBYTtBQUM3QixlQUFlOztBQUVmLEVBQUU7O0FBRUY7O0FBRUE7O0FBRUE7O0FBRUE7QUFDQTs7QUFFQSxHQUFHOztBQUVIOztBQUVBOztBQUVBOztBQUVBOztBQUVBOztBQUVBO0FBQ0E7OztBQUdBLEdBQUc7O0FBRUg7O0FBRXNCIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy90aHJlZS9leGFtcGxlcy9qc20vc2hhZGVycy9Db3B5U2hhZGVyLmpzPzE4ODciXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBGdWxsLXNjcmVlbiB0ZXh0dXJlZCBxdWFkIHNoYWRlclxuICovXG5cbmNvbnN0IENvcHlTaGFkZXIgPSB7XG5cblx0bmFtZTogJ0NvcHlTaGFkZXInLFxuXG5cdHVuaWZvcm1zOiB7XG5cblx0XHQndERpZmZ1c2UnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0J29wYWNpdHknOiB7IHZhbHVlOiAxLjAgfVxuXG5cdH0sXG5cblx0dmVydGV4U2hhZGVyOiAvKiBnbHNsICovYFxuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0dlV2ID0gdXY7XG5cdFx0XHRnbF9Qb3NpdGlvbiA9IHByb2plY3Rpb25NYXRyaXggKiBtb2RlbFZpZXdNYXRyaXggKiB2ZWM0KCBwb3NpdGlvbiwgMS4wICk7XG5cblx0XHR9YCxcblxuXHRmcmFnbWVudFNoYWRlcjogLyogZ2xzbCAqL2BcblxuXHRcdHVuaWZvcm0gZmxvYXQgb3BhY2l0eTtcblxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHREaWZmdXNlO1xuXG5cdFx0dmFyeWluZyB2ZWMyIHZVdjtcblxuXHRcdHZvaWQgbWFpbigpIHtcblxuXHRcdFx0dmVjNCB0ZXhlbCA9IHRleHR1cmUyRCggdERpZmZ1c2UsIHZVdiApO1xuXHRcdFx0Z2xfRnJhZ0NvbG9yID0gb3BhY2l0eSAqIHRleGVsO1xuXG5cblx0XHR9YFxuXG59O1xuXG5leHBvcnQgeyBDb3B5U2hhZGVyIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///364\n")},161:(__unused_webpack___webpack_module__,__webpack_exports__,__webpack_require__)=>{eval("/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ o: () => (/* binding */ FXAAShader)\n/* harmony export */ });\n/* harmony import */ var three__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(753);\n\n\n/**\n * NVIDIA FXAA by Timothy Lottes\n * https://developer.download.nvidia.com/assets/gamedev/files/sdk/11/FXAA_WhitePaper.pdf\n * - WebGL port by @supereggbert\n * http://www.glge.org/demos/fxaa/\n * Further improved by Daniel Sturk\n */\n\nconst FXAAShader = {\n\n\tname: 'FXAAShader',\n\n\tuniforms: {\n\n\t\t'tDiffuse': { value: null },\n\t\t'resolution': { value: new three__WEBPACK_IMPORTED_MODULE_0__/* .Vector2 */ .I9Y( 1 / 1024, 1 / 512 ) }\n\n\t},\n\n\tvertexShader: /* glsl */`\n\n\t\tvarying vec2 vUv;\n\n\t\tvoid main() {\n\n\t\t\tvUv = uv;\n\t\t\tgl_Position = projectionMatrix * modelViewMatrix * vec4( position, 1.0 );\n\n\t\t}`,\n\n\tfragmentShader: /* glsl */`\n\t\tprecision highp float;\n\n\t\tuniform sampler2D tDiffuse;\n\n\t\tuniform vec2 resolution;\n\n\t\tvarying vec2 vUv;\n\n\t\t// FXAA 3.11 implementation by NVIDIA, ported to WebGL by Agost Biro (biro@archilogic.com)\n\n\t\t//----------------------------------------------------------------------------------\n\t\t// File: es3-kepler\\FXAA\\assets\\shaders/FXAA_DefaultES.frag\n\t\t// SDK Version: v3.00\n\t\t// Email: gameworks@nvidia.com\n\t\t// Site: http://developer.nvidia.com/\n\t\t//\n\t\t// Copyright (c) 2014-2015, NVIDIA CORPORATION. All rights reserved.\n\t\t//\n\t\t// Redistribution and use in source and binary forms, with or without\n\t\t// modification, are permitted provided that the following conditions\n\t\t// are met:\n\t\t// * Redistributions of source code must retain the above copyright\n\t\t// notice, this list of conditions and the following disclaimer.\n\t\t// * Redistributions in binary form must reproduce the above copyright\n\t\t// notice, this list of conditions and the following disclaimer in the\n\t\t// documentation and/or other materials provided with the distribution.\n\t\t// * Neither the name of NVIDIA CORPORATION nor the names of its\n\t\t// contributors may be used to endorse or promote products derived\n\t\t// from this software without specific prior written permission.\n\t\t//\n\t\t// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ''AS IS'' AND ANY\n\t\t// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n\t\t// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n\t\t// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n\t\t// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n\t\t// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n\t\t// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n\t\t// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n\t\t// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n\t\t// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n\t\t// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n\t\t//\n\t\t//----------------------------------------------------------------------------------\n\n\t\t#ifndef FXAA_DISCARD\n\t\t\t//\n\t\t\t// Only valid for PC OpenGL currently.\n\t\t\t// Probably will not work when FXAA_GREEN_AS_LUMA = 1.\n\t\t\t//\n\t\t\t// 1 = Use discard on pixels which don't need AA.\n\t\t\t// For APIs which enable concurrent TEX+ROP from same surface.\n\t\t\t// 0 = Return unchanged color on pixels which don't need AA.\n\t\t\t//\n\t\t\t#define FXAA_DISCARD 0\n\t\t#endif\n\n\t\t/*--------------------------------------------------------------------------*/\n\t\t#define FxaaTexTop(t, p) texture2D(t, p, -100.0)\n\t\t#define FxaaTexOff(t, p, o, r) texture2D(t, p + (o * r), -100.0)\n\t\t/*--------------------------------------------------------------------------*/\n\n\t\t#define NUM_SAMPLES 5\n\n\t\t// assumes colors have premultipliedAlpha, so that the calculated color contrast is scaled by alpha\n\t\tfloat contrast( vec4 a, vec4 b ) {\n\t\t\tvec4 diff = abs( a - b );\n\t\t\treturn max( max( max( diff.r, diff.g ), diff.b ), diff.a );\n\t\t}\n\n\t\t/*============================================================================\n\n\t\t\t\t\t\t\t\t\tFXAA3 QUALITY - PC\n\n\t\t============================================================================*/\n\n\t\t/*--------------------------------------------------------------------------*/\n\t\tvec4 FxaaPixelShader(\n\t\t\tvec2 posM,\n\t\t\tsampler2D tex,\n\t\t\tvec2 fxaaQualityRcpFrame,\n\t\t\tfloat fxaaQualityEdgeThreshold,\n\t\t\tfloat fxaaQualityinvEdgeThreshold\n\t\t) {\n\t\t\tvec4 rgbaM = FxaaTexTop(tex, posM);\n\t\t\tvec4 rgbaS = FxaaTexOff(tex, posM, vec2( 0.0, 1.0), fxaaQualityRcpFrame.xy);\n\t\t\tvec4 rgbaE = FxaaTexOff(tex, posM, vec2( 1.0, 0.0), fxaaQualityRcpFrame.xy);\n\t\t\tvec4 rgbaN = FxaaTexOff(tex, posM, vec2( 0.0,-1.0), fxaaQualityRcpFrame.xy);\n\t\t\tvec4 rgbaW = FxaaTexOff(tex, posM, vec2(-1.0, 0.0), fxaaQualityRcpFrame.xy);\n\t\t\t// . S .\n\t\t\t// W M E\n\t\t\t// . N .\n\n\t\t\tbool earlyExit = max( max( max(\n\t\t\t\t\tcontrast( rgbaM, rgbaN ),\n\t\t\t\t\tcontrast( rgbaM, rgbaS ) ),\n\t\t\t\t\tcontrast( rgbaM, rgbaE ) ),\n\t\t\t\t\tcontrast( rgbaM, rgbaW ) )\n\t\t\t\t\t< fxaaQualityEdgeThreshold;\n\t\t\t// . 0 .\n\t\t\t// 0 0 0\n\t\t\t// . 0 .\n\n\t\t\t#if (FXAA_DISCARD == 1)\n\t\t\t\tif(earlyExit) FxaaDiscard;\n\t\t\t#else\n\t\t\t\tif(earlyExit) return rgbaM;\n\t\t\t#endif\n\n\t\t\tfloat contrastN = contrast( rgbaM, rgbaN );\n\t\t\tfloat contrastS = contrast( rgbaM, rgbaS );\n\t\t\tfloat contrastE = contrast( rgbaM, rgbaE );\n\t\t\tfloat contrastW = contrast( rgbaM, rgbaW );\n\n\t\t\tfloat relativeVContrast = ( contrastN + contrastS ) - ( contrastE + contrastW );\n\t\t\trelativeVContrast *= fxaaQualityinvEdgeThreshold;\n\n\t\t\tbool horzSpan = relativeVContrast > 0.;\n\t\t\t// . 1 .\n\t\t\t// 0 0 0\n\t\t\t// . 1 .\n\n\t\t\t// 45 deg edge detection and corners of objects, aka V/H contrast is too similar\n\t\t\tif( abs( relativeVContrast ) < .3 ) {\n\t\t\t\t// locate the edge\n\t\t\t\tvec2 dirToEdge;\n\t\t\t\tdirToEdge.x = contrastE > contrastW ? 1. : -1.;\n\t\t\t\tdirToEdge.y = contrastS > contrastN ? 1. : -1.;\n\t\t\t\t// . 2 . . 1 .\n\t\t\t\t// 1 0 2 ~= 0 0 1\n\t\t\t\t// . 1 . . 0 .\n\n\t\t\t\t// tap 2 pixels and see which ones are \"outside\" the edge, to\n\t\t\t\t// determine if the edge is vertical or horizontal\n\n\t\t\t\tvec4 rgbaAlongH = FxaaTexOff(tex, posM, vec2( dirToEdge.x, -dirToEdge.y ), fxaaQualityRcpFrame.xy);\n\t\t\t\tfloat matchAlongH = contrast( rgbaM, rgbaAlongH );\n\t\t\t\t// . 1 .\n\t\t\t\t// 0 0 1\n\t\t\t\t// . 0 H\n\n\t\t\t\tvec4 rgbaAlongV = FxaaTexOff(tex, posM, vec2( -dirToEdge.x, dirToEdge.y ), fxaaQualityRcpFrame.xy);\n\t\t\t\tfloat matchAlongV = contrast( rgbaM, rgbaAlongV );\n\t\t\t\t// V 1 .\n\t\t\t\t// 0 0 1\n\t\t\t\t// . 0 .\n\n\t\t\t\trelativeVContrast = matchAlongV - matchAlongH;\n\t\t\t\trelativeVContrast *= fxaaQualityinvEdgeThreshold;\n\n\t\t\t\tif( abs( relativeVContrast ) < .3 ) { // 45 deg edge\n\t\t\t\t\t// 1 1 .\n\t\t\t\t\t// 0 0 1\n\t\t\t\t\t// . 0 1\n\n\t\t\t\t\t// do a simple blur\n\t\t\t\t\treturn mix(\n\t\t\t\t\t\trgbaM,\n\t\t\t\t\t\t(rgbaN + rgbaS + rgbaE + rgbaW) * .25,\n\t\t\t\t\t\t.4\n\t\t\t\t\t);\n\t\t\t\t}\n\n\t\t\t\thorzSpan = relativeVContrast > 0.;\n\t\t\t}\n\n\t\t\tif(!horzSpan) rgbaN = rgbaW;\n\t\t\tif(!horzSpan) rgbaS = rgbaE;\n\t\t\t// . 0 . 1\n\t\t\t// 1 0 1 -> 0\n\t\t\t// . 0 . 1\n\n\t\t\tbool pairN = contrast( rgbaM, rgbaN ) > contrast( rgbaM, rgbaS );\n\t\t\tif(!pairN) rgbaN = rgbaS;\n\n\t\t\tvec2 offNP;\n\t\t\toffNP.x = (!horzSpan) ? 0.0 : fxaaQualityRcpFrame.x;\n\t\t\toffNP.y = ( horzSpan) ? 0.0 : fxaaQualityRcpFrame.y;\n\n\t\t\tbool doneN = false;\n\t\t\tbool doneP = false;\n\n\t\t\tfloat nDist = 0.;\n\t\t\tfloat pDist = 0.;\n\n\t\t\tvec2 posN = posM;\n\t\t\tvec2 posP = posM;\n\n\t\t\tint iterationsUsedN = 0;\n\t\t\tint iterationsUsedP = 0;\n\t\t\tfor( int i = 0; i < NUM_SAMPLES; i++ ) {\n\n\t\t\t\tfloat increment = float(i + 1);\n\n\t\t\t\tif(!doneN) {\n\t\t\t\t\tnDist += increment;\n\t\t\t\t\tposN = posM + offNP * nDist;\n\t\t\t\t\tvec4 rgbaEndN = FxaaTexTop(tex, posN.xy);\n\t\t\t\t\tdoneN = contrast( rgbaEndN, rgbaM ) > contrast( rgbaEndN, rgbaN );\n\t\t\t\t\titerationsUsedN = i;\n\t\t\t\t}\n\n\t\t\t\tif(!doneP) {\n\t\t\t\t\tpDist += increment;\n\t\t\t\t\tposP = posM - offNP * pDist;\n\t\t\t\t\tvec4 rgbaEndP = FxaaTexTop(tex, posP.xy);\n\t\t\t\t\tdoneP = contrast( rgbaEndP, rgbaM ) > contrast( rgbaEndP, rgbaN );\n\t\t\t\t\titerationsUsedP = i;\n\t\t\t\t}\n\n\t\t\t\tif(doneN || doneP) break;\n\t\t\t}\n\n\n\t\t\tif ( !doneP && !doneN ) return rgbaM; // failed to find end of edge\n\n\t\t\tfloat dist = min(\n\t\t\t\tdoneN ? float( iterationsUsedN ) / float( NUM_SAMPLES - 1 ) : 1.,\n\t\t\t\tdoneP ? float( iterationsUsedP ) / float( NUM_SAMPLES - 1 ) : 1.\n\t\t\t);\n\n\t\t\t// hacky way of reduces blurriness of mostly diagonal edges\n\t\t\t// but reduces AA quality\n\t\t\tdist = pow(dist, .5);\n\n\t\t\tdist = 1. - dist;\n\n\t\t\treturn mix(\n\t\t\t\trgbaM,\n\t\t\t\trgbaN,\n\t\t\t\tdist * .5\n\t\t\t);\n\t\t}\n\n\t\tvoid main() {\n\t\t\tconst float edgeDetectionQuality = .2;\n\t\t\tconst float invEdgeDetectionQuality = 1. / edgeDetectionQuality;\n\n\t\t\tgl_FragColor = FxaaPixelShader(\n\t\t\t\tvUv,\n\t\t\t\ttDiffuse,\n\t\t\t\tresolution,\n\t\t\t\tedgeDetectionQuality, // [0,1] contrast needed, otherwise early discard\n\t\t\t\tinvEdgeDetectionQuality\n\t\t\t);\n\n\t\t}\n\t`\n\n};\n\n\n//# sourceURL=[module]\n//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiMTYxLmpzIiwibWFwcGluZ3MiOiI7Ozs7QUFFZTs7QUFFZjtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQSxnQkFBZ0IsYUFBYTtBQUM3QixrQkFBa0IsV0FBVyxxREFBTzs7QUFFcEMsRUFBRTs7QUFFRjs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBOztBQUVBLEdBQUc7O0FBRUg7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0Esa0RBQWtEO0FBQ2xELGNBQWM7QUFDZDtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOztBQUVBLDBDQUEwQztBQUMxQztBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7QUFDQTs7QUFFQTtBQUNBOztBQUVBO0FBQ0E7QUFDQSxtQkFBbUIsaUJBQWlCOztBQUVwQzs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTs7QUFFQTtBQUNBOzs7QUFHQSx5Q0FBeUM7O0FBRXpDO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTs7QUFFQTs7QUFFQTtBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7O0FBRUE7QUFDQTtBQUNBOztBQUVBO0FBQ0E7QUFDQTtBQUNBO0FBQ0E7QUFDQTtBQUNBOztBQUVBO0FBQ0E7O0FBRUE7O0FBRXNCIiwic291cmNlcyI6WyJ3ZWJwYWNrOi8vdGhyZWVqcy1wb3N0cHJvY2Vzcy8uL25vZGVfbW9kdWxlcy90aHJlZS9leGFtcGxlcy9qc20vc2hhZGVycy9GWEFBU2hhZGVyLmpzPzVmMDgiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHtcblx0VmVjdG9yMlxufSBmcm9tICd0aHJlZSc7XG5cbi8qKlxuICogTlZJRElBIEZYQUEgYnkgVGltb3RoeSBMb3R0ZXNcbiAqIGh0dHBzOi8vZGV2ZWxvcGVyLmRvd25sb2FkLm52aWRpYS5jb20vYXNzZXRzL2dhbWVkZXYvZmlsZXMvc2RrLzExL0ZYQUFfV2hpdGVQYXBlci5wZGZcbiAqIC0gV2ViR0wgcG9ydCBieSBAc3VwZXJlZ2diZXJ0XG4gKiBodHRwOi8vd3d3LmdsZ2Uub3JnL2RlbW9zL2Z4YWEvXG4gKiBGdXJ0aGVyIGltcHJvdmVkIGJ5IERhbmllbCBTdHVya1xuICovXG5cbmNvbnN0IEZYQUFTaGFkZXIgPSB7XG5cblx0bmFtZTogJ0ZYQUFTaGFkZXInLFxuXG5cdHVuaWZvcm1zOiB7XG5cblx0XHQndERpZmZ1c2UnOiB7IHZhbHVlOiBudWxsIH0sXG5cdFx0J3Jlc29sdXRpb24nOiB7IHZhbHVlOiBuZXcgVmVjdG9yMiggMSAvIDEwMjQsIDEgLyA1MTIgKSB9XG5cblx0fSxcblxuXHR2ZXJ0ZXhTaGFkZXI6IC8qIGdsc2wgKi9gXG5cblx0XHR2YXJ5aW5nIHZlYzIgdlV2O1xuXG5cdFx0dm9pZCBtYWluKCkge1xuXG5cdFx0XHR2VXYgPSB1djtcblx0XHRcdGdsX1Bvc2l0aW9uID0gcHJvamVjdGlvbk1hdHJpeCAqIG1vZGVsVmlld01hdHJpeCAqIHZlYzQoIHBvc2l0aW9uLCAxLjAgKTtcblxuXHRcdH1gLFxuXG5cdGZyYWdtZW50U2hhZGVyOiAvKiBnbHNsICovYFxuXHRcdHByZWNpc2lvbiBoaWdocCBmbG9hdDtcblxuXHRcdHVuaWZvcm0gc2FtcGxlcjJEIHREaWZmdXNlO1xuXG5cdFx0dW5pZm9ybSB2ZWMyIHJlc29sdXRpb247XG5cblx0XHR2YXJ5aW5nIHZlYzIgdlV2O1xuXG5cdFx0Ly8gRlhBQSAzLjExIGltcGxlbWVudGF0aW9uIGJ5IE5WSURJQSwgcG9ydGVkIHRvIFdlYkdMIGJ5IEFnb3N0IEJpcm8gKGJpcm9AYXJjaGlsb2dpYy5jb20pXG5cblx0XHQvLy0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblx0XHQvLyBGaWxlOiAgICAgICAgZXMzLWtlcGxlclxcRlhBQVxcYXNzZXRzXFxzaGFkZXJzL0ZYQUFfRGVmYXVsdEVTLmZyYWdcblx0XHQvLyBTREsgVmVyc2lvbjogdjMuMDBcblx0XHQvLyBFbWFpbDogICAgICAgZ2FtZXdvcmtzQG52aWRpYS5jb21cblx0XHQvLyBTaXRlOiAgICAgICAgaHR0cDovL2RldmVsb3Blci5udmlkaWEuY29tL1xuXHRcdC8vXG5cdFx0Ly8gQ29weXJpZ2h0IChjKSAyMDE0LTIwMTUsIE5WSURJQSBDT1JQT1JBVElPTi4gQWxsIHJpZ2h0cyByZXNlcnZlZC5cblx0XHQvL1xuXHRcdC8vIFJlZGlzdHJpYnV0aW9uIGFuZCB1c2UgaW4gc291cmNlIGFuZCBiaW5hcnkgZm9ybXMsIHdpdGggb3Igd2l0aG91dFxuXHRcdC8vIG1vZGlmaWNhdGlvbiwgYXJlIHBlcm1pdHRlZCBwcm92aWRlZCB0aGF0IHRoZSBmb2xsb3dpbmcgY29uZGl0aW9uc1xuXHRcdC8vIGFyZSBtZXQ6XG5cdFx0Ly8gICogUmVkaXN0cmlidXRpb25zIG9mIHNvdXJjZSBjb2RlIG11c3QgcmV0YWluIHRoZSBhYm92ZSBjb3B5cmlnaHRcblx0XHQvLyAgICBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIuXG5cdFx0Ly8gICogUmVkaXN0cmlidXRpb25zIGluIGJpbmFyeSBmb3JtIG11c3QgcmVwcm9kdWNlIHRoZSBhYm92ZSBjb3B5cmlnaHRcblx0XHQvLyAgICBub3RpY2UsIHRoaXMgbGlzdCBvZiBjb25kaXRpb25zIGFuZCB0aGUgZm9sbG93aW5nIGRpc2NsYWltZXIgaW4gdGhlXG5cdFx0Ly8gICAgZG9jdW1lbnRhdGlvbiBhbmQvb3Igb3RoZXIgbWF0ZXJpYWxzIHByb3ZpZGVkIHdpdGggdGhlIGRpc3RyaWJ1dGlvbi5cblx0XHQvLyAgKiBOZWl0aGVyIHRoZSBuYW1lIG9mIE5WSURJQSBDT1JQT1JBVElPTiBub3IgdGhlIG5hbWVzIG9mIGl0c1xuXHRcdC8vICAgIGNvbnRyaWJ1dG9ycyBtYXkgYmUgdXNlZCB0byBlbmRvcnNlIG9yIHByb21vdGUgcHJvZHVjdHMgZGVyaXZlZFxuXHRcdC8vICAgIGZyb20gdGhpcyBzb2Z0d2FyZSB3aXRob3V0IHNwZWNpZmljIHByaW9yIHdyaXR0ZW4gcGVybWlzc2lvbi5cblx0XHQvL1xuXHRcdC8vIFRISVMgU09GVFdBUkUgSVMgUFJPVklERUQgQlkgVEhFIENPUFlSSUdIVCBIT0xERVJTICcnQVMgSVMnJyBBTkQgQU5ZXG5cdFx0Ly8gRVhQUkVTUyBPUiBJTVBMSUVEIFdBUlJBTlRJRVMsIElOQ0xVRElORywgQlVUIE5PVCBMSU1JVEVEIFRPLCBUSEVcblx0XHQvLyBJTVBMSUVEIFdBUlJBTlRJRVMgT0YgTUVSQ0hBTlRBQklMSVRZIEFORCBGSVRORVNTIEZPUiBBIFBBUlRJQ1VMQVJcblx0XHQvLyBQVVJQT1NFIEFSRSBESVNDTEFJTUVELiAgSU4gTk8gRVZFTlQgU0hBTEwgVEhFIENPUFlSSUdIVCBPV05FUiBPUlxuXHRcdC8vIENPTlRSSUJVVE9SUyBCRSBMSUFCTEUgRk9SIEFOWSBESVJFQ1QsIElORElSRUNULCBJTkNJREVOVEFMLCBTUEVDSUFMLFxuXHRcdC8vIEVYRU1QTEFSWSwgT1IgQ09OU0VRVUVOVElBTCBEQU1BR0VTIChJTkNMVURJTkcsIEJVVCBOT1QgTElNSVRFRCBUTyxcblx0XHQvLyBQUk9DVVJFTUVOVCBPRiBTVUJTVElUVVRFIEdPT0RTIE9SIFNFUlZJQ0VTOyBMT1NTIE9GIFVTRSwgREFUQSwgT1Jcblx0XHQvLyBQUk9GSVRTOyBPUiBCVVNJTkVTUyBJTlRFUlJVUFRJT04pIEhPV0VWRVIgQ0FVU0VEIEFORCBPTiBBTlkgVEhFT1JZXG5cdFx0Ly8gT0YgTElBQklMSVRZLCBXSEVUSEVSIElOIENPTlRSQUNULCBTVFJJQ1QgTElBQklMSVRZLCBPUiBUT1JUXG5cdFx0Ly8gKElOQ0xVRElORyBORUdMSUdFTkNFIE9SIE9USEVSV0lTRSkgQVJJU0lORyBJTiBBTlkgV0FZIE9VVCBPRiBUSEUgVVNFXG5cdFx0Ly8gT0YgVEhJUyBTT0ZUV0FSRSwgRVZFTiBJRiBBRFZJU0VEIE9GIFRIRSBQT1NTSUJJTElUWSBPRiBTVUNIIERBTUFHRS5cblx0XHQvL1xuXHRcdC8vLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5cdFx0I2lmbmRlZiBGWEFBX0RJU0NBUkRcblx0XHRcdC8vXG5cdFx0XHQvLyBPbmx5IHZhbGlkIGZvciBQQyBPcGVuR0wgY3VycmVudGx5LlxuXHRcdFx0Ly8gUHJvYmFibHkgd2lsbCBub3Qgd29yayB3aGVuIEZYQUFfR1JFRU5fQVNfTFVNQSA9IDEuXG5cdFx0XHQvL1xuXHRcdFx0Ly8gMSA9IFVzZSBkaXNjYXJkIG9uIHBpeGVscyB3aGljaCBkb24ndCBuZWVkIEFBLlxuXHRcdFx0Ly8gICAgIEZvciBBUElzIHdoaWNoIGVuYWJsZSBjb25jdXJyZW50IFRFWCtST1AgZnJvbSBzYW1lIHN1cmZhY2UuXG5cdFx0XHQvLyAwID0gUmV0dXJuIHVuY2hhbmdlZCBjb2xvciBvbiBwaXhlbHMgd2hpY2ggZG9uJ3QgbmVlZCBBQS5cblx0XHRcdC8vXG5cdFx0XHQjZGVmaW5lIEZYQUFfRElTQ0FSRCAwXG5cdFx0I2VuZGlmXG5cblx0XHQvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblx0XHQjZGVmaW5lIEZ4YWFUZXhUb3AodCwgcCkgdGV4dHVyZTJEKHQsIHAsIC0xMDAuMClcblx0XHQjZGVmaW5lIEZ4YWFUZXhPZmYodCwgcCwgbywgcikgdGV4dHVyZTJEKHQsIHAgKyAobyAqIHIpLCAtMTAwLjApXG5cdFx0LyotLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLSovXG5cblx0XHQjZGVmaW5lIE5VTV9TQU1QTEVTIDVcblxuXHRcdC8vIGFzc3VtZXMgY29sb3JzIGhhdmUgcHJlbXVsdGlwbGllZEFscGhhLCBzbyB0aGF0IHRoZSBjYWxjdWxhdGVkIGNvbG9yIGNvbnRyYXN0IGlzIHNjYWxlZCBieSBhbHBoYVxuXHRcdGZsb2F0IGNvbnRyYXN0KCB2ZWM0IGEsIHZlYzQgYiApIHtcblx0XHRcdHZlYzQgZGlmZiA9IGFicyggYSAtIGIgKTtcblx0XHRcdHJldHVybiBtYXgoIG1heCggbWF4KCBkaWZmLnIsIGRpZmYuZyApLCBkaWZmLmIgKSwgZGlmZi5hICk7XG5cdFx0fVxuXG5cdFx0Lyo9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cblx0XHRcdFx0XHRcdFx0XHRcdEZYQUEzIFFVQUxJVFkgLSBQQ1xuXG5cdFx0PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PSovXG5cblx0XHQvKi0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tKi9cblx0XHR2ZWM0IEZ4YWFQaXhlbFNoYWRlcihcblx0XHRcdHZlYzIgcG9zTSxcblx0XHRcdHNhbXBsZXIyRCB0ZXgsXG5cdFx0XHR2ZWMyIGZ4YWFRdWFsaXR5UmNwRnJhbWUsXG5cdFx0XHRmbG9hdCBmeGFhUXVhbGl0eUVkZ2VUaHJlc2hvbGQsXG5cdFx0XHRmbG9hdCBmeGFhUXVhbGl0eWludkVkZ2VUaHJlc2hvbGRcblx0XHQpIHtcblx0XHRcdHZlYzQgcmdiYU0gPSBGeGFhVGV4VG9wKHRleCwgcG9zTSk7XG5cdFx0XHR2ZWM0IHJnYmFTID0gRnhhYVRleE9mZih0ZXgsIHBvc00sIHZlYzIoIDAuMCwgMS4wKSwgZnhhYVF1YWxpdHlSY3BGcmFtZS54eSk7XG5cdFx0XHR2ZWM0IHJnYmFFID0gRnhhYVRleE9mZih0ZXgsIHBvc00sIHZlYzIoIDEuMCwgMC4wKSwgZnhhYVF1YWxpdHlSY3BGcmFtZS54eSk7XG5cdFx0XHR2ZWM0IHJnYmFOID0gRnhhYVRleE9mZih0ZXgsIHBvc00sIHZlYzIoIDAuMCwtMS4wKSwgZnhhYVF1YWxpdHlSY3BGcmFtZS54eSk7XG5cdFx0XHR2ZWM0IHJnYmFXID0gRnhhYVRleE9mZih0ZXgsIHBvc00sIHZlYzIoLTEuMCwgMC4wKSwgZnhhYVF1YWxpdHlSY3BGcmFtZS54eSk7XG5cdFx0XHQvLyAuIFMgLlxuXHRcdFx0Ly8gVyBNIEVcblx0XHRcdC8vIC4gTiAuXG5cblx0XHRcdGJvb2wgZWFybHlFeGl0ID0gbWF4KCBtYXgoIG1heChcblx0XHRcdFx0XHRjb250cmFzdCggcmdiYU0sIHJnYmFOICksXG5cdFx0XHRcdFx0Y29udHJhc3QoIHJnYmFNLCByZ2JhUyApICksXG5cdFx0XHRcdFx0Y29udHJhc3QoIHJnYmFNLCByZ2JhRSApICksXG5cdFx0XHRcdFx0Y29udHJhc3QoIHJnYmFNLCByZ2JhVyApIClcblx0XHRcdFx0XHQ8IGZ4YWFRdWFsaXR5RWRnZVRocmVzaG9sZDtcblx0XHRcdC8vIC4gMCAuXG5cdFx0XHQvLyAwIDAgMFxuXHRcdFx0Ly8gLiAwIC5cblxuXHRcdFx0I2lmIChGWEFBX0RJU0NBUkQgPT0gMSlcblx0XHRcdFx0aWYoZWFybHlFeGl0KSBGeGFhRGlzY2FyZDtcblx0XHRcdCNlbHNlXG5cdFx0XHRcdGlmKGVhcmx5RXhpdCkgcmV0dXJuIHJnYmFNO1xuXHRcdFx0I2VuZGlmXG5cblx0XHRcdGZsb2F0IGNvbnRyYXN0TiA9IGNvbnRyYXN0KCByZ2JhTSwgcmdiYU4gKTtcblx0XHRcdGZsb2F0IGNvbnRyYXN0UyA9IGNvbnRyYXN0KCByZ2JhTSwgcmdiYVMgKTtcblx0XHRcdGZsb2F0IGNvbnRyYXN0RSA9IGNvbnRyYXN0KCByZ2JhTSwgcmdiYUUgKTtcblx0XHRcdGZsb2F0IGNvbnRyYXN0VyA9IGNvbnRyYXN0KCByZ2JhTSwgcmdiYVcgKTtcblxuXHRcdFx0ZmxvYXQgcmVsYXRpdmVWQ29udHJhc3QgPSAoIGNvbnRyYXN0TiArIGNvbnRyYXN0UyApIC0gKCBjb250cmFzdEUgKyBjb250cmFzdFcgKTtcblx0XHRcdHJlbGF0aXZlVkNvbnRyYXN0ICo9IGZ4YWFRdWFsaXR5aW52RWRnZVRocmVzaG9sZDtcblxuXHRcdFx0Ym9vbCBob3J6U3BhbiA9IHJlbGF0aXZlVkNvbnRyYXN0ID4gMC47XG5cdFx0XHQvLyAuIDEgLlxuXHRcdFx0Ly8gMCAwIDBcblx0XHRcdC8vIC4gMSAuXG5cblx0XHRcdC8vIDQ1IGRlZyBlZGdlIGRldGVjdGlvbiBhbmQgY29ybmVycyBvZiBvYmplY3RzLCBha2EgVi9IIGNvbnRyYXN0IGlzIHRvbyBzaW1pbGFyXG5cdFx0XHRpZiggYWJzKCByZWxhdGl2ZVZDb250cmFzdCApIDwgLjMgKSB7XG5cdFx0XHRcdC8vIGxvY2F0ZSB0aGUgZWRnZVxuXHRcdFx0XHR2ZWMyIGRpclRvRWRnZTtcblx0XHRcdFx0ZGlyVG9FZGdlLnggPSBjb250cmFzdEUgPiBjb250cmFzdFcgPyAxLiA6IC0xLjtcblx0XHRcdFx0ZGlyVG9FZGdlLnkgPSBjb250cmFzdFMgPiBjb250cmFzdE4gPyAxLiA6IC0xLjtcblx0XHRcdFx0Ly8gLiAyIC4gICAgICAuIDEgLlxuXHRcdFx0XHQvLyAxIDAgMiAgfj0gIDAgMCAxXG5cdFx0XHRcdC8vIC4gMSAuICAgICAgLiAwIC5cblxuXHRcdFx0XHQvLyB0YXAgMiBwaXhlbHMgYW5kIHNlZSB3aGljaCBvbmVzIGFyZSBcIm91dHNpZGVcIiB0aGUgZWRnZSwgdG9cblx0XHRcdFx0Ly8gZGV0ZXJtaW5lIGlmIHRoZSBlZGdlIGlzIHZlcnRpY2FsIG9yIGhvcml6b250YWxcblxuXHRcdFx0XHR2ZWM0IHJnYmFBbG9uZ0ggPSBGeGFhVGV4T2ZmKHRleCwgcG9zTSwgdmVjMiggZGlyVG9FZGdlLngsIC1kaXJUb0VkZ2UueSApLCBmeGFhUXVhbGl0eVJjcEZyYW1lLnh5KTtcblx0XHRcdFx0ZmxvYXQgbWF0Y2hBbG9uZ0ggPSBjb250cmFzdCggcmdiYU0sIHJnYmFBbG9uZ0ggKTtcblx0XHRcdFx0Ly8gLiAxIC5cblx0XHRcdFx0Ly8gMCAwIDFcblx0XHRcdFx0Ly8gLiAwIEhcblxuXHRcdFx0XHR2ZWM0IHJnYmFBbG9uZ1YgPSBGeGFhVGV4T2ZmKHRleCwgcG9zTSwgdmVjMiggLWRpclRvRWRnZS54LCBkaXJUb0VkZ2UueSApLCBmeGFhUXVhbGl0eVJjcEZyYW1lLnh5KTtcblx0XHRcdFx0ZmxvYXQgbWF0Y2hBbG9uZ1YgPSBjb250cmFzdCggcmdiYU0sIHJnYmFBbG9uZ1YgKTtcblx0XHRcdFx0Ly8gViAxIC5cblx0XHRcdFx0Ly8gMCAwIDFcblx0XHRcdFx0Ly8gLiAwIC5cblxuXHRcdFx0XHRyZWxhdGl2ZVZDb250cmFzdCA9IG1hdGNoQWxvbmdWIC0gbWF0Y2hBbG9uZ0g7XG5cdFx0XHRcdHJlbGF0aXZlVkNvbnRyYXN0ICo9IGZ4YWFRdWFsaXR5aW52RWRnZVRocmVzaG9sZDtcblxuXHRcdFx0XHRpZiggYWJzKCByZWxhdGl2ZVZDb250cmFzdCApIDwgLjMgKSB7IC8vIDQ1IGRlZyBlZGdlXG5cdFx0XHRcdFx0Ly8gMSAxIC5cblx0XHRcdFx0XHQvLyAwIDAgMVxuXHRcdFx0XHRcdC8vIC4gMCAxXG5cblx0XHRcdFx0XHQvLyBkbyBhIHNpbXBsZSBibHVyXG5cdFx0XHRcdFx0cmV0dXJuIG1peChcblx0XHRcdFx0XHRcdHJnYmFNLFxuXHRcdFx0XHRcdFx0KHJnYmFOICsgcmdiYVMgKyByZ2JhRSArIHJnYmFXKSAqIC4yNSxcblx0XHRcdFx0XHRcdC40XG5cdFx0XHRcdFx0KTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGhvcnpTcGFuID0gcmVsYXRpdmVWQ29udHJhc3QgPiAwLjtcblx0XHRcdH1cblxuXHRcdFx0aWYoIWhvcnpTcGFuKSByZ2JhTiA9IHJnYmFXO1xuXHRcdFx0aWYoIWhvcnpTcGFuKSByZ2JhUyA9IHJnYmFFO1xuXHRcdFx0Ly8gLiAwIC4gICAgICAxXG5cdFx0XHQvLyAxIDAgMSAgLT4gIDBcblx0XHRcdC8vIC4gMCAuICAgICAgMVxuXG5cdFx0XHRib29sIHBhaXJOID0gY29udHJhc3QoIHJnYmFNLCByZ2JhTiApID4gY29udHJhc3QoIHJnYmFNLCByZ2JhUyApO1xuXHRcdFx0aWYoIXBhaXJOKSByZ2JhTiA9IHJnYmFTO1xuXG5cdFx0XHR2ZWMyIG9mZk5QO1xuXHRcdFx0b2ZmTlAueCA9ICghaG9yelNwYW4pID8gMC4wIDogZnhhYVF1YWxpdHlSY3BGcmFtZS54O1xuXHRcdFx0b2ZmTlAueSA9ICggaG9yelNwYW4pID8gMC4wIDogZnhhYVF1YWxpdHlSY3BGcmFtZS55O1xuXG5cdFx0XHRib29sIGRvbmVOID0gZmFsc2U7XG5cdFx0XHRib29sIGRvbmVQID0gZmFsc2U7XG5cblx0XHRcdGZsb2F0IG5EaXN0ID0gMC47XG5cdFx0XHRmbG9hdCBwRGlzdCA9IDAuO1xuXG5cdFx0XHR2ZWMyIHBvc04gPSBwb3NNO1xuXHRcdFx0dmVjMiBwb3NQID0gcG9zTTtcblxuXHRcdFx0aW50IGl0ZXJhdGlvbnNVc2VkTiA9IDA7XG5cdFx0XHRpbnQgaXRlcmF0aW9uc1VzZWRQID0gMDtcblx0XHRcdGZvciggaW50IGkgPSAwOyBpIDwgTlVNX1NBTVBMRVM7IGkrKyApIHtcblxuXHRcdFx0XHRmbG9hdCBpbmNyZW1lbnQgPSBmbG9hdChpICsgMSk7XG5cblx0XHRcdFx0aWYoIWRvbmVOKSB7XG5cdFx0XHRcdFx0bkRpc3QgKz0gaW5jcmVtZW50O1xuXHRcdFx0XHRcdHBvc04gPSBwb3NNICsgb2ZmTlAgKiBuRGlzdDtcblx0XHRcdFx0XHR2ZWM0IHJnYmFFbmROID0gRnhhYVRleFRvcCh0ZXgsIHBvc04ueHkpO1xuXHRcdFx0XHRcdGRvbmVOID0gY29udHJhc3QoIHJnYmFFbmROLCByZ2JhTSApID4gY29udHJhc3QoIHJnYmFFbmROLCByZ2JhTiApO1xuXHRcdFx0XHRcdGl0ZXJhdGlvbnNVc2VkTiA9IGk7XG5cdFx0XHRcdH1cblxuXHRcdFx0XHRpZighZG9uZVApIHtcblx0XHRcdFx0XHRwRGlzdCArPSBpbmNyZW1lbnQ7XG5cdFx0XHRcdFx0cG9zUCA9IHBvc00gLSBvZmZOUCAqIHBEaXN0O1xuXHRcdFx0XHRcdHZlYzQgcmdiYUVuZFAgPSBGeGFhVGV4VG9wKHRleCwgcG9zUC54eSk7XG5cdFx0XHRcdFx0ZG9uZVAgPSBjb250cmFzdCggcmdiYUVuZFAsIHJnYmFNICkgPiBjb250cmFzdCggcmdiYUVuZFAsIHJnYmFOICk7XG5cdFx0XHRcdFx0aXRlcmF0aW9uc1VzZWRQID0gaTtcblx0XHRcdFx0fVxuXG5cdFx0XHRcdGlmKGRvbmVOIHx8IGRvbmVQKSBicmVhaztcblx0XHRcdH1cblxuXG5cdFx0XHRpZiAoICFkb25lUCAmJiAhZG9uZU4gKSByZXR1cm4gcmdiYU07IC8vIGZhaWxlZCB0byBmaW5kIGVuZCBvZiBlZGdlXG5cblx0XHRcdGZsb2F0IGRpc3QgPSBtaW4oXG5cdFx0XHRcdGRvbmVOID8gZmxvYXQoIGl0ZXJhdGlvbnNVc2VkTiApIC8gZmxvYXQoIE5VTV9TQU1QTEVTIC0gMSApIDogMS4sXG5cdFx0XHRcdGRvbmVQID8gZmxvYXQoIGl0ZXJhdGlvbnNVc2VkUCApIC8gZmxvYXQoIE5VTV9TQU1QTEVTIC0gMSApIDogMS5cblx0XHRcdCk7XG5cblx0XHRcdC8vIGhhY2t5IHdheSBvZiByZWR1Y2VzIGJsdXJyaW5lc3Mgb2YgbW9zdGx5IGRpYWdvbmFsIGVkZ2VzXG5cdFx0XHQvLyBidXQgcmVkdWNlcyBBQSBxdWFsaXR5XG5cdFx0XHRkaXN0ID0gcG93KGRpc3QsIC41KTtcblxuXHRcdFx0ZGlzdCA9IDEuIC0gZGlzdDtcblxuXHRcdFx0cmV0dXJuIG1peChcblx0XHRcdFx0cmdiYU0sXG5cdFx0XHRcdHJnYmFOLFxuXHRcdFx0XHRkaXN0ICogLjVcblx0XHRcdCk7XG5cdFx0fVxuXG5cdFx0dm9pZCBtYWluKCkge1xuXHRcdFx0Y29uc3QgZmxvYXQgZWRnZURldGVjdGlvblF1YWxpdHkgPSAuMjtcblx0XHRcdGNvbnN0IGZsb2F0IGludkVkZ2VEZXRlY3Rpb25RdWFsaXR5ID0gMS4gLyBlZGdlRGV0ZWN0aW9uUXVhbGl0eTtcblxuXHRcdFx0Z2xfRnJhZ0NvbG9yID0gRnhhYVBpeGVsU2hhZGVyKFxuXHRcdFx0XHR2VXYsXG5cdFx0XHRcdHREaWZmdXNlLFxuXHRcdFx0XHRyZXNvbHV0aW9uLFxuXHRcdFx0XHRlZGdlRGV0ZWN0aW9uUXVhbGl0eSwgLy8gWzAsMV0gY29udHJhc3QgbmVlZGVkLCBvdGhlcndpc2UgZWFybHkgZGlzY2FyZFxuXHRcdFx0XHRpbnZFZGdlRGV0ZWN0aW9uUXVhbGl0eVxuXHRcdFx0KTtcblxuXHRcdH1cblx0YFxuXG59O1xuXG5leHBvcnQgeyBGWEFBU2hhZGVyIH07XG4iXSwibmFtZXMiOltdLCJzb3VyY2VSb290IjoiIn0=\n//# sourceURL=webpack-internal:///161\n")}}]); \ No newline at end of file